diff options
Diffstat (limited to 'arch')
-rw-r--r-- | arch/arm/lib32/bootm.c | 50 | ||||
-rw-r--r-- | arch/arm/lib64/armlinux.c | 12 | ||||
-rw-r--r-- | arch/mips/Kconfig | 1 | ||||
-rw-r--r-- | arch/mips/lib/bootm.c | 59 | ||||
-rw-r--r-- | arch/ppc/lib/ppclinux.c | 52 |
5 files changed, 128 insertions, 46 deletions
diff --git a/arch/arm/lib32/bootm.c b/arch/arm/lib32/bootm.c index c8bf72f0e0..b1ac2df731 100644 --- a/arch/arm/lib32/bootm.c +++ b/arch/arm/lib32/bootm.c @@ -130,11 +130,13 @@ static int get_kernel_addresses(size_t image_size, return 0; } -static int __do_bootm_linux(struct image_data *data, unsigned long free_mem, int swap) +static int __do_bootm_linux(struct image_data *data, unsigned long free_mem, + int swap, void *fdt) { unsigned long kernel; unsigned long initrd_start = 0, initrd_size = 0, initrd_end = 0; enum arm_security_state state = bootm_arm_security_state(); + void *fdt_load_address = NULL; int ret; kernel = data->os_res->start + data->os_entry; @@ -163,16 +165,28 @@ static int __do_bootm_linux(struct image_data *data, unsigned long free_mem, int free_mem = PAGE_ALIGN(initrd_end + 1); } - ret = bootm_load_devicetree(data, free_mem); - if (ret) - return ret; + if (!fdt) { + fdt = bootm_get_devicetree(data); + if (IS_ERR(fdt)) + return PTR_ERR(fdt); + } + + if (fdt) { + fdt_load_address = (void *)free_mem; + ret = bootm_load_devicetree(data, fdt, free_mem); + + free(fdt); + + if (ret) + return ret; + } if (bootm_verbose(data)) { printf("\nStarting kernel at 0x%08lx", kernel); if (initrd_size) printf(", initrd at 0x%08lx", initrd_start); - if (data->oftree) - printf(", oftree at 0x%p", data->oftree); + if (fdt_load_address) + printf(", oftree at 0x%p", fdt_load_address); printf("...\n"); } @@ -188,8 +202,8 @@ static int __do_bootm_linux(struct image_data *data, unsigned long free_mem, int if (data->dryrun) return 0; - start_linux((void *)kernel, swap, initrd_start, initrd_size, data->oftree, - state); + start_linux((void *)kernel, swap, initrd_start, initrd_size, + fdt_load_address, state); restart_machine(); @@ -212,7 +226,7 @@ static int do_bootm_linux(struct image_data *data) if (ret) return ret; - return __do_bootm_linux(data, mem_free, 0); + return __do_bootm_linux(data, mem_free, 0, NULL); } static struct image_handler uimage_handler = { @@ -237,7 +251,7 @@ struct zimage_header { #define ZIMAGE_MAGIC 0x016F2818 -static int do_bootz_linux_fdt(int fd, struct image_data *data) +static int do_bootz_linux_fdt(int fd, struct image_data *data, void **outfdt) { struct fdt_header __header, *header; void *oftree; @@ -245,9 +259,6 @@ static int do_bootz_linux_fdt(int fd, struct image_data *data) u32 end; - if (data->oftree) - return -ENXIO; - header = &__header; ret = read(fd, header, sizeof(*header)); if (ret < 0) @@ -287,8 +298,8 @@ static int do_bootz_linux_fdt(int fd, struct image_data *data) pr_err("unable to unflatten devicetree\n"); goto err_free; } - data->oftree = of_get_fixed_tree(root); - if (!data->oftree) { + *outfdt = of_get_fixed_tree(root); + if (!*outfdt) { pr_err("Unable to get fixed tree\n"); ret = -EINVAL; goto err_free; @@ -296,7 +307,7 @@ static int do_bootz_linux_fdt(int fd, struct image_data *data) free(oftree); } else { - data->oftree = oftree; + *outfdt = oftree; } pr_info("zImage: concatenated oftree detected\n"); @@ -318,6 +329,7 @@ static int do_bootz_linux(struct image_data *data) size_t image_size; unsigned long load_address = data->os_address; unsigned long mem_free; + void *fdt = NULL; fd = open(data->os_file, O_RDONLY); if (fd < 0) { @@ -388,13 +400,13 @@ static int do_bootz_linux(struct image_data *data) *(u32 *)ptr = swab32(*(u32 *)ptr); } - ret = do_bootz_linux_fdt(fd, data); + ret = do_bootz_linux_fdt(fd, data, &fdt); if (ret && ret != -ENXIO) goto err_out; close(fd); - return __do_bootm_linux(data, mem_free, swap); + return __do_bootm_linux(data, mem_free, swap, fdt); err_out: close(fd); @@ -559,7 +571,7 @@ static int do_bootm_aimage(struct image_data *data) else mem_free = PAGE_ALIGN(data->os_res->end + SZ_1M); - return __do_bootm_linux(data, mem_free, 0); + return __do_bootm_linux(data, mem_free, 0, NULL); err_out: linux_bootargs_overwrite(NULL); diff --git a/arch/arm/lib64/armlinux.c b/arch/arm/lib64/armlinux.c index 238e8b67a4..afa56792fb 100644 --- a/arch/arm/lib64/armlinux.c +++ b/arch/arm/lib64/armlinux.c @@ -38,6 +38,7 @@ static int do_bootm_linux(struct image_data *data) resource_size_t start, end; unsigned long text_offset, image_size, devicetree, kernel; int ret; + void *fdt; text_offset = le64_to_cpup(data->os_header + 8); image_size = le64_to_cpup(data->os_header + 16); @@ -54,7 +55,16 @@ static int do_bootm_linux(struct image_data *data) devicetree = ALIGN(kernel + image_size, PAGE_SIZE); - ret = bootm_load_devicetree(data, devicetree); + fdt = bootm_get_devicetree(data); + if (IS_ERR(fdt)) { + ret = PTR_ERR(fdt); + goto out; + } + + ret = bootm_load_devicetree(data, fdt, devicetree); + + free(fdt); + if (ret) goto out; diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index 359f67883c..9aedf9a77b 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -7,6 +7,7 @@ config MIPS select HAVE_CONFIGURABLE_MEMORY_LAYOUT select HAVE_CONFIGURABLE_TEXT_BASE select HAS_DMA + select ELF default y config SYS_SUPPORTS_BIG_ENDIAN diff --git a/arch/mips/lib/bootm.c b/arch/mips/lib/bootm.c index 91e7e1c68a..f14540a4c4 100644 --- a/arch/mips/lib/bootm.c +++ b/arch/mips/lib/bootm.c @@ -10,6 +10,7 @@ #include <restart.h> #include <asm/byteorder.h> +#include <asm/io.h> static int do_bootm_barebox(struct image_data *data) { @@ -42,11 +43,69 @@ static struct binfmt_hook binfmt_barebox_hook = { .exec = "bootm", }; +static int do_bootm_elf(struct image_data *data) +{ + void (*entry)(int, void *); + struct elf_image *elf; + void *fdt, *buf; + int ret = 0; + + buf = read_file(data->os_file, NULL); + if (!buf) + return -EINVAL; + + elf = elf_load_image(buf); + if (IS_ERR(elf)) + return PTR_ERR(elf); + + fdt = bootm_get_devicetree(data); + if (IS_ERR(fdt)) { + ret = PTR_ERR(fdt); + goto bootm_elf_done; + } + + pr_info("Starting application at 0x%08lx, dts 0x%08lx...\n", + phys_to_virt(elf->entry), data->of_root_node); + + if (data->dryrun) + goto bootm_elf_done; + + shutdown_barebox(); + + entry = (void *)elf->entry; + + entry(-2, phys_to_virt((unsigned long)fdt)); + + pr_err("ELF application terminated\n"); + ret = -EINVAL; + +bootm_elf_done: + elf_release_image(elf); + free(fdt); + free(buf); + + return ret; +} + +static struct image_handler elf_handler = { + .name = "ELF", + .bootm = do_bootm_elf, + .filetype = filetype_elf, +}; + +static struct binfmt_hook binfmt_elf_hook = { + .type = filetype_elf, + .exec = "bootm", +}; + static int mips_register_image_handler(void) { register_image_handler(&barebox_handler); binfmt_register(&binfmt_barebox_hook); + register_image_handler(&elf_handler); + binfmt_register(&binfmt_elf_hook); + return 0; } late_initcall(mips_register_image_handler); diff --git a/arch/ppc/lib/ppclinux.c b/arch/ppc/lib/ppclinux.c index 3fca6b2720..05c29be7da 100644 --- a/arch/ppc/lib/ppclinux.c +++ b/arch/ppc/lib/ppclinux.c @@ -14,35 +14,37 @@ #include <restart.h> #include <fs.h> -static int bootm_relocate_fdt(void *addr, struct image_data *data) +static struct fdt_header *bootm_relocate_fdt(struct image_data *data, + struct fdt_header *fdt) { - if (addr < LINUX_TLB1_MAX_ADDR) { + void *os = (void *)data->os_address; + void *newfdt; + + if (os < LINUX_TLB1_MAX_ADDR) { /* The kernel is within the boot TLB mapping. * Put the DTB above if there is no space * below. */ - if (addr < (void *)data->oftree->totalsize) { - addr = (void *)PAGE_ALIGN((phys_addr_t)addr + + if (os < (void *)fdt->totalsize) { + os = (void *)PAGE_ALIGN((phys_addr_t)os + data->os->header.ih_size); - addr += data->oftree->totalsize; - if (addr < LINUX_TLB1_MAX_ADDR) - addr = LINUX_TLB1_MAX_ADDR; + os += fdt->totalsize; + if (os < LINUX_TLB1_MAX_ADDR) + os = LINUX_TLB1_MAX_ADDR; } } - if (addr > LINUX_TLB1_MAX_ADDR) { + if (os > LINUX_TLB1_MAX_ADDR) { pr_crit("Unable to relocate DTB to Linux TLB\n"); - return 1; + return NULL; } - addr = (void *)PAGE_ALIGN_DOWN((phys_addr_t)addr - - data->oftree->totalsize); - memcpy(addr, data->oftree, data->oftree->totalsize); - free(data->oftree); - data->oftree = addr; + newfdt = (void *)PAGE_ALIGN_DOWN((phys_addr_t)os - fdt->totalsize); + memcpy(newfdt, fdt, fdt->totalsize); + free(fdt); - pr_info("Relocating device tree to 0x%p\n", addr); - return 0; + pr_info("Relocating device tree to 0x%p\n", newfdt); + return newfdt; } static int do_bootm_linux(struct image_data *data) @@ -50,13 +52,14 @@ static int do_bootm_linux(struct image_data *data) void (*kernel)(void *, void *, unsigned long, unsigned long, unsigned long); int ret; + struct fdt_header *fdt; ret = bootm_load_os(data, data->os_address); if (ret) return ret; - data->oftree = of_get_fixed_tree(data->of_root_node); - if (!data->oftree) { + fdt = of_get_fixed_tree(data->of_root_node); + if (!fdt) { pr_err("bootm: No devicetree given.\n"); return -EINVAL; } @@ -68,17 +71,14 @@ static int do_bootm_linux(struct image_data *data) * Linux mapped TLB. */ if (IS_ENABLED(CONFIG_MPC85xx)) { - void *addr = data->oftree; - - if ((addr + data->oftree->totalsize) > LINUX_TLB1_MAX_ADDR) { - addr = (void *)data->os_address; - - if (bootm_relocate_fdt(addr, data)) + if (((void *)fdt + fdt->totalsize) > LINUX_TLB1_MAX_ADDR) { + fdt = bootm_relocate_fdt(data, fdt); + if (!fdt) goto error; } } - fdt_add_reserve_map(data->oftree); + fdt_add_reserve_map(fdt); kernel = (void *)(data->os_address + data->os_entry); @@ -90,7 +90,7 @@ static int do_bootm_linux(struct image_data *data) * r6: NULL * r7: NULL */ - kernel(data->oftree, kernel, 0, 0, 0); + kernel(fdt, kernel, 0, 0, 0); restart_machine(); |