# HG changeset patch
# User Jerone Young <[EMAIL PROTECTED]>
# Date 1205953012 18000
# Branch merge
# Node ID 8e9da5ddf159eb6cf5a292ccbf5f735103b493ef
# Parent  03925441312877b8350e4af68e475d5d746304d4
Add dynamic device tree manipulation & change uboot loader for PPC bamboo board 
model

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]>

diff --git a/qemu/Makefile.target b/qemu/Makefile.target
--- a/qemu/Makefile.target
+++ b/qemu/Makefile.target
@@ -617,7 +617,7 @@ OBJS+= unin_pci.o ppc_chrp.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
--- /dev/null
+++ b/qemu/hw/device_tree.c
@@ -0,0 +1,181 @@
+/*
+ * 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 = snprintf(buf, 0, "%s/%s", DT_PROC_INTERFACE_PATH,
+               path_in_device_tree);
+
+       buf = (char *)malloc(i);
+       if (buf == NULL) {
+               printf("%s: Unable to malloc string buffer buf\n",
+                       __func__);
+               exit(1);
+       }
+
+       i = snprintf(buf, i+1, "%s/%s",  DT_PROC_INTERFACE_PATH,
+               path_in_device_tree);
+
+       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);
+
+       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);
+       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
--- /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
--- 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"
+#include "qemu-kvm.h"
+#include "device_tree.h"
 
-#define KERNEL_LOAD_ADDR 0x400000 /* uboot loader puts kernel at 4MB */
-
-#include "qemu-kvm.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, in
                        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,18 +81,23 @@ void bamboo_init(ram_addr_t ram_size, in
 
        /* 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,
@@ -99,17 +107,64 @@ void bamboo_init(ram_addr_t ram_size, in
                }
        }
 
+#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 = snprintf(buf, 0, "%s/%s", bios_dir, 
+               BINARY_DEVICE_TREE_FILE);
+
+       buf = (char*) malloc(ret);
+       if (buf == NULL) {
+               printf("%s: Unable to malloc string buffer buf\n",
+                       __func__);
+               exit(1);
+       }       
+
+       snprintf(buf, ret+1, "%s/%s", bios_dir, 
+               BINARY_DEVICE_TREE_FILE);
+
+       /* 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);
+
+       /* 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-devel mailing list
kvm-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/kvm-devel

Reply via email to