diff options
author | Himbeer <himbeer@disroot.org> | 2024-05-14 21:18:00 +0200 |
---|---|---|
committer | Himbeer <himbeer@disroot.org> | 2024-05-14 21:18:00 +0200 |
commit | 0c023db4c0ca74664d384d01bf579bdffd84877a (patch) | |
tree | 7553986c7b3c2cdb67389b1b657ffc14f3bf3251 | |
parent | 7f52b689eb8aa964b929c708d366e80da249aa3f (diff) |
bootm: Support loading legacy (multi) ELF images
-rw-r--r-- | arch/riscv/lib/bootm.c | 55 | ||||
-rw-r--r-- | cmd/elf.c | 2 | ||||
-rw-r--r-- | common/bootm.c | 3 | ||||
-rw-r--r-- | common/bootm_os.c | 3 | ||||
-rw-r--r-- | include/bootm.h | 1 |
5 files changed, 62 insertions, 2 deletions
diff --git a/arch/riscv/lib/bootm.c b/arch/riscv/lib/bootm.c index 837154d6..4de67ab5 100644 --- a/arch/riscv/lib/bootm.c +++ b/arch/riscv/lib/bootm.c @@ -9,6 +9,7 @@ #include <common.h> #include <command.h> #include <dm.h> +#include <elf.h> #include <dm/root.h> #include <image.h> #include <opensbi.h> @@ -37,6 +38,8 @@ __weak void board_quiesce_devices(void) { } +static struct fw_dynamic_info opensbi_info; + int arch_fixup_fdt(void *blob) { return 0; @@ -193,6 +196,44 @@ static void boot_jump_linux(bootm_headers_t *images, int flag) } } +static int boot_jump_elf(struct bootm_headers *images, int flag) +{ + unsigned long addr = images->ep; + ulong (*entry)(int, char * const[]); + void (*sbi)(ulong hart, void *dtb, struct fw_dynamic_info *p); + unsigned long initrd_len = images->initrd_end - images->initrd_start; + + sbi = (void (*)(ulong, void *, struct fw_dynamic_info*))0x80000000; + + if (!images->legacy_hdr_valid) + return -1; + + if (!valid_elf_image(addr)) + return -1; + + addr = load_elf_image_shdr(addr); + entry = (void *)addr; + + bootstage_mark(BOOTSTAGE_ID_RUN_OS); + + if (images->initrd_start && images->ft_addr) { + opensbi_info.magic = FW_DYNAMIC_INFO_MAGIC_VALUE; + opensbi_info.version = 0x1; + opensbi_info.next_addr = addr; + opensbi_info.next_mode = FW_DYNAMIC_INFO_NEXT_MODE_S; + opensbi_info.options = 0; + opensbi_info.boot_hart = 0; + + memcpy(sbi, (const void *)images->initrd_start, initrd_len); + + sbi(gd->arch.boot_hart, images->ft_addr, &opensbi_info); + } else { + entry(0, NULL); + } + + return 0; +} + int do_bootm_linux(int flag, int argc, char * const argv[], bootm_headers_t *images) { @@ -220,3 +261,17 @@ int do_bootm_vxworks(int flag, int argc, char * const argv[], { return do_bootm_linux(flag, argc, argv, images); } + +int do_bootm_elf(int flag, int argc, char * const argv[], + bootm_headers_t *images) +{ + /* No need for those on RISC-V */ + if (flag & BOOTM_STATE_OS_BD_T || flag & BOOTM_STATE_OS_CMDLINE) + return -1; + + if (flag & (BOOTM_STATE_OS_GO | BOOTM_STATE_OS_FAKE_GO)) { + return boot_jump_elf(images, flag); + }; + + return 0; +} @@ -177,7 +177,7 @@ static unsigned long load_elf_image_phdr(unsigned long addr) return ehdr->e_entry; } -static unsigned long load_elf_image_shdr(unsigned long addr) +unsigned long load_elf_image_shdr(unsigned long addr) { Elf32_Ehdr *ehdr; /* Elf header structure pointer */ Elf32_Shdr *shdr; /* Section header structure pointer */ diff --git a/common/bootm.c b/common/bootm.c index 902c1388..22f842cf 100644 --- a/common/bootm.c +++ b/common/bootm.c @@ -290,7 +290,8 @@ static int bootm_find_other(cmd_tbl_t *cmdtp, int flag, int argc, (images.os.type == IH_TYPE_KERNEL_NOLOAD) || (images.os.type == IH_TYPE_MULTI)) && (images.os.os == IH_OS_LINUX || - images.os.os == IH_OS_VXWORKS)) + images.os.os == IH_OS_VXWORKS || + images.os.os == IH_OS_ELF)) return bootm_find_images(flag, argc, argv); return 0; diff --git a/common/bootm_os.c b/common/bootm_os.c index d89ddc32..2df7add5 100644 --- a/common/bootm_os.c +++ b/common/bootm_os.c @@ -534,6 +534,9 @@ static boot_os_fn *boot_os[] = { #ifdef CONFIG_BOOTM_OPTEE [IH_OS_TEE] = do_bootm_tee, #endif +#if defined(CONFIG_CMD_ELF) + [IH_OS_ELF] = do_bootm_elf, +#endif }; /* Allow for arch specific config before we boot */ diff --git a/include/bootm.h b/include/bootm.h index edeeacb0..19543a7e 100644 --- a/include/bootm.h +++ b/include/bootm.h @@ -36,6 +36,7 @@ typedef int boot_os_fn(int flag, int argc, char * const argv[], extern boot_os_fn do_bootm_linux; extern boot_os_fn do_bootm_vxworks; +extern boot_os_fn do_bootm_elf; int do_bootelf(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]); void lynxkdi_boot(image_header_t *hdr); |