From: Jerone Young <[EMAIL PROTECTED]>

This patch adds code to dynamically manipulate the device tree when
loaded into memory. This allows us to finally have the ability to
manipulate the kernel command line & initrd from the qemu command
line. This will also let us setup different settings for the board.

This patch also now uses new uboot loader load_uimage() to load kernel image.

Signed-off-by: Jerone Young <[EMAIL PROTECTED]>
Signed-off-by: Avi Kivity <[EMAIL PROTECTED]>

diff --git a/qemu/Makefile.target b/qemu/Makefile.target
index 9c87eac..f282fa3 100644
--- a/qemu/Makefile.target
+++ b/qemu/Makefile.target
@@ -617,7 +617,7 @@ OBJS+= heathrow_pic.o grackle_pci.o ppc_oldworld.o
 OBJS+= unin_pci.o ppc_chrp.o
 # PowerPC 4xx boards
 OBJS+= pflash_cfi02.o ppc4xx_devs.o ppc405_uc.o ppc405_boards.o
-OBJS+= ppc440.o ppc440_bamboo.o
+OBJS+= ppc440.o ppc440_bamboo.o device_tree.o
 endif
 ifeq ($(TARGET_BASE_ARCH), mips)
 OBJS+= mips_r4k.o mips_malta.o mips_pica61.o mips_mipssim.o
diff --git a/qemu/hw/device_tree.c b/qemu/hw/device_tree.c
new file mode 100644
index 0000000..e22d04b
--- /dev/null
+++ b/qemu/hw/device_tree.c
@@ -0,0 +1,178 @@
+/*
+ * Functions to help device tree manipulation using libfdt.
+ * It also provides functions to read entries from device tree proc
+ * interface.
+ *
+ * Copyright 2008 IBM Corporation.
+ * Authors: Jerone Young <[EMAIL PROTECTED]>
+ *
+ * This work is licensed under the GNU GPL license version 2 or later.
+ *
+ */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+#include "config.h"
+#include "ppc440.h"
+
+#ifdef CONFIG_LIBFDT
+#include "libfdt.h"
+#endif
+
+#define DT_PROC_INTERFACE_PATH "/proc/device-tree"
+
+/* FUNCTIONS FOR READING FROM DEVICE TREE OF HOST IN /PROC */
+
+/* This function reads device-tree property files that are of
+ * a single cell size
+ */
+uint32_t read_proc_dt_prop_cell(char *path_in_device_tree)
+{
+       char *buf = NULL;
+       int i;
+       uint32_t num;
+       FILE *stream;
+
+       i = asprintf(&buf, "%s/%s", DT_PROC_INTERFACE_PATH,
+               path_in_device_tree);
+
+       if (i < 0) {
+               printf("%s: Unable to malloc string buffer buf\n",
+                       __func__);
+               exit(1);
+       }
+
+       stream = fopen(buf, "rb");
+
+       if (stream == NULL) {
+               printf("%s: Unable to open '%s'\n", __func__, buf);
+               exit(1);
+       }
+
+       fread(&num, sizeof(num), 1, stream);
+       fclose(stream);
+       free(buf);
+
+       return num;
+}
+
+/* FUNCTIONS FOR LOADING & MANIPULATION OF DEVICE TREE IN GUEST */
+
+#ifdef CONFIG_LIBFDT
+/* support functions */
+static int get_offset_of_node(void *fdt, char *node_path)
+{
+       int node_offset;
+       node_offset = fdt_path_offset(fdt, node_path);
+       if (node_offset < 0) {
+               printf("Unable to find node in device tree '%s'\n",
+                       node_path);
+               exit(1);
+       }
+       return node_offset;
+}
+
+/* public functions */
+void *load_device_tree(char *filename_path, unsigned long load_addr)
+{
+       int dt_file_size;
+       int dt_file_load_size;
+       int new_dt_size;
+       int ret;
+       void *dt_file = NULL;
+       void *fdt;
+
+       dt_file_size = get_image_size(filename_path);
+       if (dt_file_size < 0) {
+               printf("Unable to get size of device tree file '%s'\n",
+                       filename_path);
+               goto fail;
+       }
+
+       /* First allocate space in qemu for device tree */
+       dt_file = qemu_malloc(dt_file_size);
+       if (dt_file == NULL) {
+               printf("Unable to allocate memory in qemu for device tree\n");
+               goto fail;
+       }
+       memset(dt_file, 0, dt_file_size);
+
+       dt_file_load_size = load_image(filename_path, dt_file);
+
+
+       /* XXX Second we place new copy of 2x size in guest memory
+        *  This give us enough room for manipulation.
+        */
+       new_dt_size = dt_file_size * 2;
+
+       fdt = (void *)load_addr;
+
+       ret = fdt_open_into(dt_file, fdt, new_dt_size);
+       if (ret) {
+               printf("Unable to copy device tree in memory\n");
+               goto fail;
+       }
+
+       /* Check sanity of device tree */
+       if (fdt_check_header(fdt)) {
+               printf ("Device tree file loaded into memory is invalid: %s\n",
+                       filename_path);
+               goto fail;
+       }
+       /* free qemu memory with old device tree */
+       qemu_free(dt_file);
+       return fdt;
+
+fail:
+       if (dt_file)
+               qemu_free(dt_file);
+       return NULL;
+}
+
+void dump_device_tree_to_file(void *fdt, char *filename)
+{
+       int fd;
+       fd = open(filename, O_RDWR|O_CREAT, O_RDWR);
+       if (fd < 0) {
+               printf("Failed to open file %s\n Cannot dum device-tree\n",
+                       filename);
+               return;
+       }
+
+       write(fd, fdt, fdt_totalsize(fdt));
+       close(fd);
+}
+
+void dt_cell(void *fdt, char *node_path, char *property,
+               uint32_t val)
+{
+       int offset;
+       int ret;
+       offset = get_offset_of_node(fdt, node_path);
+       ret = fdt_setprop_cell(fdt, offset, property, val);
+       if (ret < 0) {
+               printf("Unable to set device tree property '%s'\n",
+                       property);
+               exit(1);
+       }
+}
+
+void dt_string(void *fdt, char *node_path, char *property,
+               char *string)
+{
+       int offset;
+       int ret;
+       offset = get_offset_of_node(fdt, node_path);
+       ret = fdt_setprop_string(fdt, offset, property, string);
+       if (ret < 0) {
+               printf("Unable to set device tree property '%s'\n",
+                       property);
+               exit(1);
+       }
+}
+#endif
diff --git a/qemu/hw/device_tree.h b/qemu/hw/device_tree.h
new file mode 100644
index 0000000..c966491
--- /dev/null
+++ b/qemu/hw/device_tree.h
@@ -0,0 +1,24 @@
+/*
+ * Header with function prototypes to help device tree manipulation using
+ * libfdt. It also provides functions to read entries from device tree proc
+ * interface.
+ *
+ * Copyright 2008 IBM Corporation.
+ * Authors: Jerone Young <[EMAIL PROTECTED]>
+ *
+ * This work is licensed under the GNU GPL license version 2 or later.
+ *
+ */
+
+/* device-tree proc support functions */
+uint32_t read_proc_dt_prop_cell(char *path_in_device_tree);
+
+#ifdef CONFIG_LIBFDT
+/* device tree functions */
+void *load_device_tree(char *filename_path, target_ulong load_addr);
+void dump_device_tree_to_file(void *fdt, char *filename);
+void dt_cell(void *fdt, char *node_path, char *property,
+               uint32_t val);
+void dt_string(void *fdt, char *node_path, char *property,
+               char *string);
+#endif
diff --git a/qemu/hw/ppc440_bamboo.c b/qemu/hw/ppc440_bamboo.c
index f1cd408..d582276 100644
--- a/qemu/hw/ppc440_bamboo.c
+++ b/qemu/hw/ppc440_bamboo.c
@@ -4,20 +4,16 @@
  * Copyright 2007 IBM Corporation.
  * Authors: Jerone Young <[EMAIL PROTECTED]>
  *
- * This work is licensed under the GNU GPL licence version 2 or later.
+ * This work is licensed under the GNU GPL license version 2 or later.
  *
  */
 
+#include "config.h"
 #include "ppc440.h"
-
-#define KERNEL_LOAD_ADDR 0x400000 /* uboot loader puts kernel at 4MB */
-
 #include "qemu-kvm.h"
+#include "device_tree.h"
 
-/* PPC 440 refrence demo board
- *
- * 440 PowerPC CPU
- */
+#define BINARY_DEVICE_TREE_FILE "bamboo.dtb"
 
 void bamboo_init(ram_addr_t ram_size, int vga_ram_size,
                        const char *boot_device, DisplayState *ds,
@@ -26,14 +22,21 @@ void bamboo_init(ram_addr_t ram_size, int vga_ram_size,
                        const char *initrd_filename,
                        const char *cpu_model)
 {
+       char *buf=NULL;
        target_phys_addr_t ram_bases[2], ram_sizes[2];
        qemu_irq *pic;
        CPUState *env;
-       target_ulong ep;
+       target_ulong ep=0;
+       target_ulong la=0;
        int is_linux=1; /* Will assume allways is Linux for now */
-       long kernel_size=0;
+       target_long kernel_size=0;
        target_ulong initrd_base=0;
-       target_ulong initrd_size=0;
+       target_long initrd_size=0;
+       target_ulong dt_base=0;
+       void *fdt;
+       int ret;
+       uint32_t cpu_freq;
+       uint32_t timebase_freq;
 
        printf("%s: START\n", __func__);
 
@@ -78,19 +81,24 @@ void bamboo_init(ram_addr_t ram_size, int vga_ram_size,
 
        /* load kernel with uboot loader */
        printf("%s: load kernel\n", __func__);
-       kernel_size = load_uboot(kernel_filename, &ep, &is_linux);
-       if (kernel_size < 0) {
+       ret = load_uimage(kernel_filename, &ep, &la, &kernel_size, &is_linux);
+       if (ret < 0) {
                fprintf(stderr, "qemu: could not load kernel '%s'\n",
                        kernel_filename);
                exit(1);
        }
+       printf("kernel is at guest address: 0x%lx\n", (unsigned long)la);
 
        /* load initrd */
        if (initrd_filename) {
-               initrd_base = kernel_size + KERNEL_LOAD_ADDR;
+               initrd_base = kernel_size + la;
+               printf("%s: load initrd\n", __func__);
                initrd_size = load_image(initrd_filename,
                                phys_ram_base + initrd_base);
 
+               printf("initrd is at guest address: 0x%lx\n",
+                                       (unsigned long) initrd_base);
+
                if (initrd_size < 0) {
                        fprintf(stderr,
                                "qemu: could not load initial ram disk '%s'\n",
@@ -99,17 +107,62 @@ void bamboo_init(ram_addr_t ram_size, int vga_ram_size,
                }
        }
 
+#ifdef CONFIG_LIBFDT
+       /* get variable for device tree */
+       cpu_freq = read_proc_dt_prop_cell("cpus/[EMAIL 
PROTECTED]/clock-frequency");
+       timebase_freq = read_proc_dt_prop_cell("cpus/[EMAIL 
PROTECTED]/timebase-frequency");
+
+       /* load binary device tree into qemu (not guest memory) */
+       printf("%s: load device tree file\n", __func__);
+
+       /* get string size */
+       ret = asprintf(&buf, "%s/%s", bios_dir,
+               BINARY_DEVICE_TREE_FILE);
+
+       if (ret < 0) {
+               printf("%s: Unable to malloc string buffer buf\n",
+                       __func__);
+               exit(1);
+       }
+
+       /* set base for device tree that will be in guest memory */
+       if (initrd_base)
+               dt_base = initrd_base + initrd_size;
+       else
+               dt_base = kernel_size + la;
+
+       fdt = load_device_tree(buf, (unsigned long)(phys_ram_base + dt_base));
+       if (fdt == NULL) {
+               printf("Loading device tree failed!\n");
+               exit(1);
+       }
+
+       printf("device tree address is at guest address: 0x%lx\n",
+               (unsigned long) dt_base);
+
+       free(buf);
+
+       /* manipulate device tree in memory */
+       dt_cell(fdt, "/cpus/[EMAIL PROTECTED]", "clock-frequency", cpu_freq);
+       dt_cell(fdt, "/cpus/[EMAIL PROTECTED]", "timebase-frequency", 
timebase_freq);
+       dt_cell(fdt, "/chosen", "linux,initrd-start", initrd_base);
+       dt_cell(fdt, "/chosen", "linux,initrd-end",
+                               (initrd_base + initrd_size));
+       dt_string(fdt, "/chosen", "bootargs", (char *)kernel_cmdline);
+#endif
+
        if (kvm_enabled()) {
-           /* XXX insert TLB entries */
-           env->gpr[1] = (16<<20) - 8;
-           env->gpr[4] = initrd_base;
-           env->gpr[5] = initrd_size;
+               /* XXX insert TLB entries */
+               env->gpr[1] = (16<<20) - 8;
 
-           env->nip = ep;
+#ifdef CONFIG_LIBFDT
+               /* location of device tree in register */
+               env->gpr[3] = dt_base;
+#endif
+               env->nip = ep;
 
-           env->cpu_index = 0;
-           printf("%s: loading kvm registers\n", __func__);
-           kvm_load_registers(env);
+               printf("%s: loading kvm registers\n", __func__);
+               kvm_load_registers(env);
        }
 
        printf("%s: DONE\n", __func__);

-------------------------------------------------------------------------
This SF.net email is sponsored by: Microsoft
Defy all challenges. Microsoft(R) Visual Studio 2008.
http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/
_______________________________________________
kvm-commits mailing list
kvm-commits@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/kvm-commits

Reply via email to