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