From 4c4bf654746eae5a042bde6c150d534d8849b762 Mon Sep 17 00:00:00 2001 From: Ard Biesheuvel Date: Fri, 12 Sep 2014 14:06:50 +0100 Subject: hw/arm/boot: load DTB as a ROM image In order to make the device tree blob (DTB) available in memory not only at first boot, but also after system reset, use rom_blob_add_fixed() to install it into memory. Reviewed-by: Peter Maydell Signed-off-by: Ard Biesheuvel Message-id: 1410453915-9344-2-git-send-email-ard.biesheuvel@linaro.org Signed-off-by: Peter Maydell --- hw/arm/boot.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'hw/arm/boot.c') diff --git a/hw/arm/boot.c b/hw/arm/boot.c index e32f2f4158..50eca931e1 100644 --- a/hw/arm/boot.c +++ b/hw/arm/boot.c @@ -396,7 +396,10 @@ static int load_dtb(hwaddr addr, const struct arm_boot_info *binfo) qemu_fdt_dumpdtb(fdt, size); - cpu_physical_memory_write(addr, fdt, size); + /* Put the DTB into the memory map as a ROM image: this will ensure + * the DTB is copied again upon reset, even if addr points into RAM. + */ + rom_add_blob_fixed("dtb", fdt, size, addr); g_free(fdt); -- cgit v1.2.3-55-g7522 From fee8ea12eba366db5ef8f72478cb746bda375d6f Mon Sep 17 00:00:00 2001 From: Ard Biesheuvel Date: Fri, 12 Sep 2014 14:06:50 +0100 Subject: hw/arm/boot: pass an address limit to and return size from load_dtb() Add an address limit input parameter to load_dtb() so that we can tell load_dtb() how much memory the dtb is allowed to consume. If the dtb doesn't fit, return 0, otherwise return the actual size of the loaded dtb. Reviewed-by: Peter Maydell Signed-off-by: Ard Biesheuvel Message-id: 1410453915-9344-3-git-send-email-ard.biesheuvel@linaro.org Signed-off-by: Peter Maydell --- hw/arm/boot.c | 34 +++++++++++++++++++++++++++++++--- 1 file changed, 31 insertions(+), 3 deletions(-) (limited to 'hw/arm/boot.c') diff --git a/hw/arm/boot.c b/hw/arm/boot.c index 50eca931e1..2083aeb95d 100644 --- a/hw/arm/boot.c +++ b/hw/arm/boot.c @@ -312,7 +312,26 @@ static void set_kernel_args_old(const struct arm_boot_info *info) } } -static int load_dtb(hwaddr addr, const struct arm_boot_info *binfo) +/** + * load_dtb() - load a device tree binary image into memory + * @addr: the address to load the image at + * @binfo: struct describing the boot environment + * @addr_limit: upper limit of the available memory area at @addr + * + * Load a device tree supplied by the machine or by the user with the + * '-dtb' command line option, and put it at offset @addr in target + * memory. + * + * If @addr_limit contains a meaningful value (i.e., it is strictly greater + * than @addr), the device tree is only loaded if its size does not exceed + * the limit. + * + * Returns: the size of the device tree image on success, + * 0 if the image size exceeds the limit, + * -1 on errors. + */ +static int load_dtb(hwaddr addr, const struct arm_boot_info *binfo, + hwaddr addr_limit) { void *fdt = NULL; int size, rc; @@ -341,6 +360,15 @@ static int load_dtb(hwaddr addr, const struct arm_boot_info *binfo) } } + if (addr_limit > addr && size > (addr_limit - addr)) { + /* Installing the device tree blob at addr would exceed addr_limit. + * Whether this constitutes failure is up to the caller to decide, + * so just return 0 as size, i.e., no error. + */ + g_free(fdt); + return 0; + } + acells = qemu_fdt_getprop_cell(fdt, "/", "#address-cells"); scells = qemu_fdt_getprop_cell(fdt, "/", "#size-cells"); if (acells == 0 || scells == 0) { @@ -403,7 +431,7 @@ static int load_dtb(hwaddr addr, const struct arm_boot_info *binfo) g_free(fdt); - return 0; + return size; fail: g_free(fdt); @@ -572,7 +600,7 @@ void arm_load_kernel(ARMCPU *cpu, struct arm_boot_info *info) */ hwaddr dtb_start = QEMU_ALIGN_UP(info->initrd_start + initrd_size, 4096); - if (load_dtb(dtb_start, info)) { + if (load_dtb(dtb_start, info, 0) < 0) { exit(1); } fixupcontext[FIXUP_ARGPTR] = dtb_start; -- cgit v1.2.3-55-g7522 From 69e7f76f6a1ed8fe13602c8b5f51cdb6ce3a3981 Mon Sep 17 00:00:00 2001 From: Ard Biesheuvel Date: Fri, 12 Sep 2014 14:06:50 +0100 Subject: hw/arm/boot: load device tree to base of DRAM if no -kernel option was passed If we are running the 'virt' machine, we may have a device tree blob but no kernel to supply it to if no -kernel option was passed. In that case, copy it to the base of RAM where it can be picked up by a bootloader. Signed-off-by: Ard Biesheuvel Message-id: 1410453915-9344-4-git-send-email-ard.biesheuvel@linaro.org Signed-off-by: Peter Maydell --- hw/arm/boot.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'hw/arm/boot.c') diff --git a/hw/arm/boot.c b/hw/arm/boot.c index 2083aeb95d..1bed02db6f 100644 --- a/hw/arm/boot.c +++ b/hw/arm/boot.c @@ -490,6 +490,16 @@ void arm_load_kernel(ARMCPU *cpu, struct arm_boot_info *info) /* Load the kernel. */ if (!info->kernel_filename) { + + if (have_dtb(info)) { + /* If we have a device tree blob, but no kernel to supply it to, + * copy it to the base of RAM for a bootloader to pick up. + */ + if (load_dtb(info->loader_start, info, 0) < 0) { + exit(1); + } + } + /* If no kernel specified, do nothing; we will start from address 0 * (typically a boot ROM image) in the same way as hardware. */ -- cgit v1.2.3-55-g7522 From 92df845070290236d1b28b03453deec1ae9c4263 Mon Sep 17 00:00:00 2001 From: Ard Biesheuvel Date: Fri, 12 Sep 2014 14:06:50 +0100 Subject: hw/arm/boot: enable DTB support when booting ELF images Add support for loading DTB images when booting ELF images using -kernel. If there are no conflicts with the placement of the ELF segments, the DTB image is loaded at the base of RAM. Signed-off-by: Ard Biesheuvel Message-id: 1410453915-9344-5-git-send-email-ard.biesheuvel@linaro.org Signed-off-by: Peter Maydell --- hw/arm/boot.c | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) (limited to 'hw/arm/boot.c') diff --git a/hw/arm/boot.c b/hw/arm/boot.c index 1bed02db6f..c8dc34f086 100644 --- a/hw/arm/boot.c +++ b/hw/arm/boot.c @@ -482,7 +482,7 @@ void arm_load_kernel(ARMCPU *cpu, struct arm_boot_info *info) int kernel_size; int initrd_size; int is_linux = 0; - uint64_t elf_entry; + uint64_t elf_entry, elf_low_addr, elf_high_addr; int elf_machine; hwaddr entry, kernel_load_offset; int big_endian; @@ -549,7 +549,25 @@ void arm_load_kernel(ARMCPU *cpu, struct arm_boot_info *info) /* Assume that raw images are linux kernels, and ELF images are not. */ kernel_size = load_elf(info->kernel_filename, NULL, NULL, &elf_entry, - NULL, NULL, big_endian, elf_machine, 1); + &elf_low_addr, &elf_high_addr, big_endian, + elf_machine, 1); + if (kernel_size > 0 && have_dtb(info)) { + /* If there is still some room left at the base of RAM, try and put + * the DTB there like we do for images loaded with -bios or -pflash. + */ + if (elf_low_addr > info->loader_start + || elf_high_addr < info->loader_start) { + /* Pass elf_low_addr as address limit to load_dtb if it may be + * pointing into RAM, otherwise pass '0' (no limit) + */ + if (elf_low_addr < info->loader_start) { + elf_low_addr = 0; + } + if (load_dtb(info->loader_start, info, elf_low_addr) < 0) { + exit(1); + } + } + } entry = elf_entry; if (kernel_size < 0) { kernel_size = load_uimage(info->kernel_filename, &entry, NULL, -- cgit v1.2.3-55-g7522