diff options
author | Igor Opaniuk <igor.opaniuk@toradex.com> | 2019-11-28 15:56:21 +0200 |
---|---|---|
committer | Marcel Ziswiler <marcel.ziswiler@toradex.com> | 2019-12-23 10:30:21 +0100 |
commit | 694e2136eefc2d110f44b26218c03e44a1e88235 (patch) | |
tree | 29dac6daec4e02040793bdb85ee52ae830fd659f /arch/arm/mach-imx/imx_bootaux.c | |
parent | bc138ed0a86f0ca8f870c419955f07f3f21b7dfa (diff) |
mach-imx: bootaux: elf firmware supportVerdin-iMX8MM_Console-Image_3.0b3.118-20200101Colibri-iMX8X_Console-Image_3.0b3.118-20200101Colibri-iMX7_Console-Image_3.0b3.118-20200101Colibri-iMX7-eMMC_Console-Image_3.0b3.118-20200101Colibri-iMX6_Console-Image_3.0b3.118-20200101Colibri-iMX6ULL_Console-Image_3.0b3.118-20200101Apalis-iMX8_Console-Image_3.0b3.118-20200101Apalis-iMX8X_Console-Image_3.0b3.118-20191231Apalis-iMX6_Console-Image_3.0b3.118-20191231Apalis-TK1_Console-Image_3.0b3.118-20191231Apalis-TK1-Mainline_Console-Image_3.0b3.118-20200101
Currently imx-specific bootaux command doesn't support ELF format
firmware for Cortex-M4 core.
This patches introduces a PoC implementation of handling elf firmware
(load_elf_image_phdr() was copy-pasted from elf.c just for PoC).
This has the advantage that the user does not need to know to which
address the binary has been linked to. However, in order to handle
and load the elf sections to the right address, we need to translate the
Cortex-M4 core memory addresses to primary/host CPU memory
addresses (Cortex A7/A9 cores).
This allows to boot firmwares from any location with just using
bootaux, e.g.:
> tftp ${loadaddr} hello_world.elf && bootaux ${loadaddr}
Similar translation table can be found in the Linux remoteproc
driver [1].
[1] https://elixir.bootlin.com/linux/latest/source/drivers/remoteproc/imx_rproc.c
Signed-off-by: Igor Opaniuk <igor.opaniuk@toradex.com>
Signed-off-by: Stefan Agner <stefan.agner@toradex.com>
Reviewed-by: Oleksandr Suvorov <oleksandr.suvorov@toradex.com>
(submitted upstream https://patchwork.ozlabs.org/patch/1202074/)
Diffstat (limited to 'arch/arm/mach-imx/imx_bootaux.c')
-rw-r--r-- | arch/arm/mach-imx/imx_bootaux.c | 84 |
1 files changed, 80 insertions, 4 deletions
diff --git a/arch/arm/mach-imx/imx_bootaux.c b/arch/arm/mach-imx/imx_bootaux.c index 425b12a421f..633072bcd12 100644 --- a/arch/arm/mach-imx/imx_bootaux.c +++ b/arch/arm/mach-imx/imx_bootaux.c @@ -7,18 +7,94 @@ #include <asm/io.h> #include <asm/mach-imx/sys_proto.h> #include <command.h> +#include <elf.h> #include <imx_sip.h> #include <linux/compiler.h> -int arch_auxiliary_core_up(u32 core_id, ulong boot_private_data) +const __weak struct rproc_att hostmap[] = { }; + +static const struct rproc_att *get_host_mapping(unsigned long auxcore) +{ + const struct rproc_att *mmap = hostmap; + + while (mmap && mmap->size) { + if (mmap->da <= auxcore && + mmap->da + mmap->size > auxcore) + return mmap; + mmap++; + } + + return NULL; +} + +/* + * A very simple elf loader, assumes the image is valid, returns the + * entry point address. + */ +static unsigned long load_elf_image_phdr(unsigned long addr) +{ + Elf32_Ehdr *ehdr; /* ELF header structure pointer */ + Elf32_Phdr *phdr; /* Program header structure pointer */ + int i; + + ehdr = (Elf32_Ehdr *)addr; + phdr = (Elf32_Phdr *)(addr + ehdr->e_phoff); + + /* Load each program header */ + for (i = 0; i < ehdr->e_phnum; ++i, ++phdr) { + const struct rproc_att *mmap = get_host_mapping(phdr->p_paddr); + void *dst, *src; + + if (phdr->p_type != PT_LOAD) + continue; + + if (!mmap) { + printf("Invalid aux core address: %08x", + phdr->p_paddr); + return 0; + } + + dst = (void *)(phdr->p_paddr - mmap->da) + mmap->sa; + src = (void *)addr + phdr->p_offset; + + debug("Loading phdr %i to 0x%p (%i bytes)\n", + i, dst, phdr->p_filesz); + + if (phdr->p_filesz) + memcpy(dst, src, phdr->p_filesz); + if (phdr->p_filesz != phdr->p_memsz) + memset(dst + phdr->p_filesz, 0x00, + phdr->p_memsz - phdr->p_filesz); + flush_cache((unsigned long)dst & + ~(CONFIG_SYS_CACHELINE_SIZE - 1), + ALIGN(phdr->p_filesz, CONFIG_SYS_CACHELINE_SIZE)); + } + + return ehdr->e_entry; +} + +int arch_auxiliary_core_up(u32 core_id, ulong addr) { ulong stack, pc; - if (!boot_private_data) + if (!addr) return -EINVAL; - stack = *(u32 *)boot_private_data; - pc = *(u32 *)(boot_private_data + 4); + if (valid_elf_image(addr)) { + stack = 0x0; + pc = load_elf_image_phdr(addr); + if (!pc) + return CMD_RET_FAILURE; + + } else { + /* + * Assume binary file with vector table at the beginning. + * Cortex-M4 vector tables start with the stack pointer (SP) + * and reset vector (initial PC). + */ + stack = *(u32 *)addr; + pc = *(u32 *)(addr + 4); + } printf("## Starting auxiliary core stack = 0x%08lX, pc = 0x%08lX...\n", stack, pc); |