summaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
Diffstat (limited to 'arch')
-rw-r--r--arch/arm/lib32/bootm.c50
-rw-r--r--arch/arm/lib64/armlinux.c12
-rw-r--r--arch/mips/Kconfig1
-rw-r--r--arch/mips/lib/bootm.c59
-rw-r--r--arch/ppc/lib/ppclinux.c52
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();