From patchwork Wed Feb 8 05:41:40 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Peter Maydell X-Patchwork-Id: 6704 Return-Path: X-Original-To: patchwork@peony.canonical.com Delivered-To: patchwork@peony.canonical.com Received: from fiordland.canonical.com (fiordland.canonical.com [91.189.94.145]) by peony.canonical.com (Postfix) with ESMTP id A112623EAA for ; Wed, 8 Feb 2012 05:41:48 +0000 (UTC) Received: from mail-iy0-f180.google.com (mail-iy0-f180.google.com [209.85.210.180]) by fiordland.canonical.com (Postfix) with ESMTP id 45A49A180AD for ; Wed, 8 Feb 2012 05:41:48 +0000 (UTC) Received: by iabz7 with SMTP id z7so480239iab.11 for ; Tue, 07 Feb 2012 21:41:47 -0800 (PST) Received: by 10.42.74.195 with SMTP id x3mr14366326icj.41.1328679707722; Tue, 07 Feb 2012 21:41:47 -0800 (PST) X-Forwarded-To: linaro-patchwork@canonical.com X-Forwarded-For: patch@linaro.org linaro-patchwork@canonical.com Delivered-To: patches@linaro.org Received: by 10.231.169.210 with SMTP id a18cs5058ibz; Tue, 7 Feb 2012 21:41:46 -0800 (PST) Received: by 10.216.131.27 with SMTP id l27mr8013043wei.32.1328679705473; Tue, 07 Feb 2012 21:41:45 -0800 (PST) Received: from mnementh.archaic.org.uk (mnementh.archaic.org.uk. [81.2.115.146]) by mx.google.com with ESMTPS id i12si116223wiw.29.2012.02.07.21.41.44 (version=TLSv1/SSLv3 cipher=OTHER); Tue, 07 Feb 2012 21:41:45 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of pm215@archaic.org.uk designates 81.2.115.146 as permitted sender) client-ip=81.2.115.146; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of pm215@archaic.org.uk designates 81.2.115.146 as permitted sender) smtp.mail=pm215@archaic.org.uk Received: from pm215 by mnementh.archaic.org.uk with local (Exim 4.72) (envelope-from ) id 1Rv0Hl-00084o-0R; Wed, 08 Feb 2012 05:41:41 +0000 From: Peter Maydell To: qemu-devel@nongnu.org Cc: patches@linaro.org, Grant Likely , Anthony Liguori , Alexander Graf Subject: [PATCH 4/4] arm: add device tree support Date: Wed, 8 Feb 2012 05:41:40 +0000 Message-Id: <1328679700-31015-5-git-send-email-peter.maydell@linaro.org> X-Mailer: git-send-email 1.7.2.5 In-Reply-To: <1328679700-31015-1-git-send-email-peter.maydell@linaro.org> References: <1328679700-31015-1-git-send-email-peter.maydell@linaro.org> From: Grant Likely If compiled with CONFIG_FDT, allow user to specify a device tree file using the -dtb argument. If the machine supports it then the dtb will be loaded into memory and passed to the kernel on boot. Signed-off-by: Jeremy Kerr Signed-off-by: Grant Likely [Peter Maydell: Use machine opt rather than global to pass dtb filename] Signed-off-by: Peter Maydell --- Makefile.target | 1 + configure | 1 + hw/arm-misc.h | 1 + hw/arm_boot.c | 96 +++++++++++++++++++++++++++++++++++++++++++++++++++--- qemu-config.c | 4 ++ qemu-options.hx | 9 +++++ vl.c | 9 +++++ 7 files changed, 115 insertions(+), 6 deletions(-) diff --git a/Makefile.target b/Makefile.target index 68481a3..5e465ec 100644 --- a/Makefile.target +++ b/Makefile.target @@ -363,6 +363,7 @@ obj-arm-y += vexpress.o obj-arm-y += strongarm.o obj-arm-y += collie.o obj-arm-y += pl041.o lm4549.o +obj-arm-$(CONFIG_FDT) += device_tree.o obj-sh4-y = shix.o r2d.o sh7750.o sh7750_regnames.o tc58128.o obj-sh4-y += sh_timer.o sh_serial.o sh_intc.o sh_pci.o sm501.o diff --git a/configure b/configure index 763db24..1d8b3ac 100755 --- a/configure +++ b/configure @@ -3458,6 +3458,7 @@ case "$target_arch2" in gdb_xml_files="arm-core.xml arm-vfp.xml arm-vfp3.xml arm-neon.xml" target_phys_bits=32 target_llong_alignment=4 + target_libs_softmmu="$fdt_libs" ;; cris) target_nptl="yes" diff --git a/hw/arm-misc.h b/hw/arm-misc.h index 5e5204b..4b55fb8 100644 --- a/hw/arm-misc.h +++ b/hw/arm-misc.h @@ -29,6 +29,7 @@ struct arm_boot_info { const char *kernel_filename; const char *kernel_cmdline; const char *initrd_filename; + const char *dtb_filename; target_phys_addr_t loader_start; /* multicore boards that use the default secondary core boot functions * need to put the address of the secondary boot code, the boot reg, diff --git a/hw/arm_boot.c b/hw/arm_boot.c index 5f163fd..769fe2e 100644 --- a/hw/arm_boot.c +++ b/hw/arm_boot.c @@ -7,11 +7,14 @@ * This code is licensed under the GPL. */ +#include "config.h" #include "hw.h" #include "arm-misc.h" #include "sysemu.h" +#include "boards.h" #include "loader.h" #include "elf.h" +#include "device_tree.h" #define KERNEL_ARGS_ADDR 0x100 #define KERNEL_LOAD_ADDR 0x00010000 @@ -207,6 +210,67 @@ static void set_kernel_args_old(const struct arm_boot_info *info, } } +static int load_dtb(target_phys_addr_t addr, const struct arm_boot_info *binfo) +{ +#ifdef CONFIG_FDT + uint32_t mem_reg_property[] = { cpu_to_be32(binfo->loader_start), + cpu_to_be32(binfo->ram_size) }; + void *fdt = NULL; + char *filename; + int size, rc; + + filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, binfo->dtb_filename); + if (!filename) { + fprintf(stderr, "Couldn't open dtb file %s\n", binfo->dtb_filename); + return -1; + } + + fdt = load_device_tree(filename, &size); + if (!fdt) { + fprintf(stderr, "Couldn't open dtb file %s\n", filename); + g_free(filename); + return -1; + } + g_free(filename); + + rc = qemu_devtree_setprop(fdt, "/memory", "reg", mem_reg_property, + sizeof(mem_reg_property)); + if (rc < 0) { + fprintf(stderr, "couldn't set /memory/reg\n"); + } + + rc = qemu_devtree_setprop_string(fdt, "/chosen", "bootargs", + binfo->kernel_cmdline); + if (rc < 0) { + fprintf(stderr, "couldn't set /chosen/bootargs\n"); + } + + if (binfo->initrd_size) { + rc = qemu_devtree_setprop_cell(fdt, "/chosen", "linux,initrd-start", + binfo->loader_start + INITRD_LOAD_ADDR); + if (rc < 0) { + fprintf(stderr, "couldn't set /chosen/linux,initrd-start\n"); + } + + rc = qemu_devtree_setprop_cell(fdt, "/chosen", "linux,initrd-end", + binfo->loader_start + INITRD_LOAD_ADDR + + binfo->initrd_size); + if (rc < 0) { + fprintf(stderr, "couldn't set /chosen/linux,initrd-end\n"); + } + } + + cpu_physical_memory_write(addr, fdt, size); + + return 0; + +#else + fprintf(stderr, "Device tree requested, " + "but qemu was compiled without fdt support\n"); + return -1; +#endif +} + static void do_cpu_reset(void *opaque) { CPUState *env = opaque; @@ -221,12 +285,14 @@ static void do_cpu_reset(void *opaque) } else { if (env == first_cpu) { env->regs[15] = info->loader_start; - if (old_param) { - set_kernel_args_old(info, info->initrd_size, + if (!info->dtb_filename) { + if (old_param) { + set_kernel_args_old(info, info->initrd_size, + info->loader_start); + } else { + set_kernel_args(info, info->initrd_size, info->loader_start); - } else { - set_kernel_args(info, info->initrd_size, - info->loader_start); + } } } else { info->secondary_cpu_reset_hook(env, info); @@ -251,6 +317,9 @@ void arm_load_kernel(CPUState *env, struct arm_boot_info *info) exit(1); } + info->dtb_filename = qemu_opt_get(qemu_opts_find(qemu_find_opts("machine"), + 0), "dtb"); + if (!info->secondary_cpu_reset_hook) { info->secondary_cpu_reset_hook = default_reset_secondary; } @@ -302,7 +371,22 @@ void arm_load_kernel(CPUState *env, struct arm_boot_info *info) initrd_size = 0; } bootloader[4] = info->board_id; - bootloader[5] = info->loader_start + KERNEL_ARGS_ADDR; + + /* for device tree boot, we pass the DTB directly in r2. Otherwise + * we point to the kernel args. + */ + if (info->dtb_filename) { + /* Place the DTB after the initrd in memory */ + target_phys_addr_t dtb_start = TARGET_PAGE_ALIGN(info->loader_start + + INITRD_LOAD_ADDR + + initrd_size); + if (load_dtb(dtb_start, info)) { + exit(1); + } + bootloader[5] = dtb_start; + } else { + bootloader[5] = info->loader_start + KERNEL_ARGS_ADDR; + } bootloader[6] = entry; for (n = 0; n < sizeof(bootloader) / 4; n++) { bootloader[n] = tswap32(bootloader[n]); diff --git a/qemu-config.c b/qemu-config.c index 07480a4..151a61a 100644 --- a/qemu-config.c +++ b/qemu-config.c @@ -548,6 +548,10 @@ static QemuOptsList qemu_machine_opts = { .name = "append", .type = QEMU_OPT_STRING, .help = "Linux kernel command line", + }, { + .name = "dtb", + .type = QEMU_OPT_STRING, + .help = "Linux kernel device tree file", }, { /* End of list */ } }, diff --git a/qemu-options.hx b/qemu-options.hx index 19906e5..80316ed 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -2011,6 +2011,15 @@ Use @var{file1} and @var{file2} as modules and pass arg=foo as parameter to the first module. ETEXI +DEF("dtb", HAS_ARG, QEMU_OPTION_dtb, \ + "-dtb file use 'file' as device tree image\n", QEMU_ARCH_ARM) +STEXI +@item -dtb @var{file} +@findex -dtb +Use @var{file} as a device tree binary (dtb) image and pass it to the kernel +on boot. +ETEXI + STEXI @end table ETEXI diff --git a/vl.c b/vl.c index b8bb955..03c17d6 100644 --- a/vl.c +++ b/vl.c @@ -2453,6 +2453,9 @@ int main(int argc, char **argv, char **envp) case QEMU_OPTION_append: qemu_opts_set(qemu_find_opts("machine"), 0, "append", optarg); break; + case QEMU_OPTION_dtb: + qemu_opts_set(qemu_find_opts("machine"), 0, "dtb", optarg); + break; case QEMU_OPTION_cdrom: drive_add(IF_DEFAULT, 2, optarg, CDROM_OPTS); break; @@ -3261,6 +3264,12 @@ int main(int argc, char **argv, char **envp) exit(1); } + if (!linux_boot + && qemu_opt_get(qemu_opts_find(qemu_find_opts("machine"), 0), "dtb")) { + fprintf(stderr, "-dtb only allowed with -kernel option\n"); + exit(1); + } + os_set_line_buffering(); if (init_timer_alarm() < 0) {