aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHimbeer <himbeer@disroot.org>2024-05-14 21:18:00 +0200
committerHimbeer <himbeer@disroot.org>2024-05-14 21:18:00 +0200
commit0c023db4c0ca74664d384d01bf579bdffd84877a (patch)
tree7553986c7b3c2cdb67389b1b657ffc14f3bf3251
parent7f52b689eb8aa964b929c708d366e80da249aa3f (diff)
bootm: Support loading legacy (multi) ELF images
-rw-r--r--arch/riscv/lib/bootm.c55
-rw-r--r--cmd/elf.c2
-rw-r--r--common/bootm.c3
-rw-r--r--common/bootm_os.c3
-rw-r--r--include/bootm.h1
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;
+}
diff --git a/cmd/elf.c b/cmd/elf.c
index 32f12a72..71e2b348 100644
--- a/cmd/elf.c
+++ b/cmd/elf.c
@@ -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);