mirror of
https://github.com/AsahiLinux/u-boot
synced 2024-11-11 07:34:31 +00:00
mach-imx: bootaux: elf firmware support
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). ELF64 binaries isn't supported yet. 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>
This commit is contained in:
parent
ebabbf1169
commit
c0f037f6a2
3 changed files with 125 additions and 4 deletions
|
@ -106,6 +106,13 @@ void gpr_init(void);
|
||||||
|
|
||||||
#endif /* CONFIG_MX6 */
|
#endif /* CONFIG_MX6 */
|
||||||
|
|
||||||
|
/* address translation table */
|
||||||
|
struct rproc_att {
|
||||||
|
u32 da; /* device address (From Cortex M4 view) */
|
||||||
|
u32 sa; /* system bus address */
|
||||||
|
u32 size; /* size of reg range */
|
||||||
|
};
|
||||||
|
|
||||||
#ifdef CONFIG_IMX8M
|
#ifdef CONFIG_IMX8M
|
||||||
struct rom_api {
|
struct rom_api {
|
||||||
u16 ver;
|
u16 ver;
|
||||||
|
|
|
@ -7,20 +7,106 @@
|
||||||
#include <asm/io.h>
|
#include <asm/io.h>
|
||||||
#include <asm/mach-imx/sys_proto.h>
|
#include <asm/mach-imx/sys_proto.h>
|
||||||
#include <command.h>
|
#include <command.h>
|
||||||
|
#include <elf.h>
|
||||||
#include <imx_sip.h>
|
#include <imx_sip.h>
|
||||||
#include <linux/compiler.h>
|
#include <linux/compiler.h>
|
||||||
#include <cpu_func.h>
|
#include <cpu_func.h>
|
||||||
|
|
||||||
int arch_auxiliary_core_up(u32 core_id, ulong boot_private_data)
|
#ifndef CONFIG_IMX8M
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int arch_auxiliary_core_up(u32 core_id, ulong addr)
|
||||||
{
|
{
|
||||||
ulong stack, pc;
|
ulong stack, pc;
|
||||||
|
|
||||||
if (!boot_private_data)
|
if (!addr)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
stack = *(u32 *)boot_private_data;
|
#ifdef CONFIG_IMX8M
|
||||||
pc = *(u32 *)(boot_private_data + 4);
|
stack = *(u32 *)addr;
|
||||||
|
pc = *(u32 *)(addr + 4);
|
||||||
|
#else
|
||||||
|
/*
|
||||||
|
* handling ELF64 binaries
|
||||||
|
* isn't supported yet.
|
||||||
|
*/
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
printf("## Starting auxiliary core stack = 0x%08lX, pc = 0x%08lX...\n",
|
printf("## Starting auxiliary core stack = 0x%08lX, pc = 0x%08lX...\n",
|
||||||
stack, pc);
|
stack, pc);
|
||||||
|
|
||||||
|
|
|
@ -193,6 +193,34 @@ static void init_cpu_basic(void)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_IMX_BOOTAUX
|
||||||
|
/*
|
||||||
|
* Table of mappings of physical mem regions in both
|
||||||
|
* Cortex-A7 and Cortex-M4 address spaces.
|
||||||
|
*
|
||||||
|
* For additional details check sections 2.1.2 and 2.1.3 in
|
||||||
|
* i.MX7Dual Applications Processor Reference Manual
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
const struct rproc_att hostmap[] = {
|
||||||
|
/* aux core , host core, size */
|
||||||
|
{ 0x00000000, 0x00180000, 0x8000 }, /* OCRAM_S */
|
||||||
|
{ 0x00180000, 0x00180000, 0x8000 }, /* OCRAM_S */
|
||||||
|
{ 0x20180000, 0x00180000, 0x8000 }, /* OCRAM_S */
|
||||||
|
{ 0x1fff8000, 0x007f8000, 0x8000 }, /* TCML */
|
||||||
|
{ 0x20000000, 0x00800000, 0x8000 }, /* TCMU */
|
||||||
|
{ 0x00900000, 0x00900000, 0x20000 }, /* OCRAM_128KB */
|
||||||
|
{ 0x20200000, 0x00900000, 0x20000 }, /* OCRAM_128KB */
|
||||||
|
{ 0x00920000, 0x00920000, 0x20000 }, /* OCRAM_EPDC */
|
||||||
|
{ 0x20220000, 0x00920000, 0x20000 }, /* OCRAM_EPDC */
|
||||||
|
{ 0x00940000, 0x00940000, 0x20000 }, /* OCRAM_PXP */
|
||||||
|
{ 0x20240000, 0x00940000, 0x20000 }, /* OCRAM_PXP */
|
||||||
|
{ 0x10000000, 0x80000000, 0x0fff0000 }, /* DDR Code alias */
|
||||||
|
{ 0x80000000, 0x80000000, 0xe0000000 }, /* DDRC */
|
||||||
|
{ /* sentinel */ }
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef CONFIG_SKIP_LOWLEVEL_INIT
|
#ifndef CONFIG_SKIP_LOWLEVEL_INIT
|
||||||
/* enable all periherial can be accessed in nosec mode */
|
/* enable all periherial can be accessed in nosec mode */
|
||||||
static void init_csu(void)
|
static void init_csu(void)
|
||||||
|
|
Loading…
Reference in a new issue