[U-Boot] [RFC PATCH v1] imx: bootaux: PoC for elf firmware support

Igor Opaniuk igor.opaniuk at gmail.com
Tue Nov 5 14:16:18 UTC 2019


From: Igor Opaniuk <igor.opaniuk at toradex.com>

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}

Questions:
1. I really doubt that hardcoding the memory map for
Cortex-A7/Cortex-M4 is a good idea. Does it make sense to move this
table to <board>-u-boot.dtsi instead?
2. How does similar "firmware loading" work is done on iMX8/iMX8M,
where U-boot is used only as non-secure bootloader.
I assume that this is responsibility of TF-A, who does all Cortex-M
initialization and firmware "deploying"?

Signed-off-by: Igor Opaniuk <igor.opaniuk at toradex.com>
Signed-off-by: Stefan Agner <stefan.agner at toradex.com>
---

 arch/arm/include/asm/mach-imx/sys_proto.h |  6 ++
 arch/arm/mach-imx/imx_bootaux.c           | 84 +++++++++++++++++++++--
 arch/arm/mach-imx/mx7/soc.c               | 26 +++++++
 3 files changed, 112 insertions(+), 4 deletions(-)

diff --git a/arch/arm/include/asm/mach-imx/sys_proto.h b/arch/arm/include/asm/mach-imx/sys_proto.h
index 1e627c8fc3..fa05fda716 100644
--- a/arch/arm/include/asm/mach-imx/sys_proto.h
+++ b/arch/arm/include/asm/mach-imx/sys_proto.h
@@ -104,6 +104,12 @@ void gpr_init(void);
 
 #endif /* CONFIG_MX6 */
 
+struct memorymap {
+	unsigned long auxcore;
+	unsigned long host;
+	unsigned long size;
+};
+
 u32 get_nr_cpus(void);
 u32 get_cpu_rev(void);
 u32 get_cpu_speed_grade_hz(void);
diff --git a/arch/arm/mach-imx/imx_bootaux.c b/arch/arm/mach-imx/imx_bootaux.c
index 3d9422d5a2..91d9272c51 100644
--- a/arch/arm/mach-imx/imx_bootaux.c
+++ b/arch/arm/mach-imx/imx_bootaux.c
@@ -7,18 +7,91 @@
 #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 memorymap hostmap[] = { };
+
+static const struct memorymap *get_host_mapping(unsigned long auxcore)
+{
+	const struct memorymap *mmap = hostmap;
+
+	while (mmap) {
+		if (mmap->auxcore <= auxcore &&
+		    mmap->auxcore + 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 memorymap *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->auxcore) + mmap->host;
+		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);
+	}
 
 	/* Set the stack and pc to M4 bootROM */
 	writel(stack, M4_BOOTROM_BASE_ADDR);
@@ -80,6 +153,9 @@ static int do_bootaux(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 
 	addr = simple_strtoul(argv[1], NULL, 16);
 
+	if (!addr)
+		return CMD_RET_FAILURE;
+
 	printf("## Starting auxiliary core at 0x%08lX ...\n", addr);
 
 	ret = arch_auxiliary_core_up(0, addr);
diff --git a/arch/arm/mach-imx/mx7/soc.c b/arch/arm/mach-imx/mx7/soc.c
index 35160f4b37..bc7d5e74ff 100644
--- a/arch/arm/mach-imx/mx7/soc.c
+++ b/arch/arm/mach-imx/mx7/soc.c
@@ -193,6 +193,32 @@ static void init_cpu_basic(void)
 #endif
 }
 
+#ifdef CONFIG_IMX_BOOTAUX
+/*
+ * Table of mappings of 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 memorymap hostmap[] = {
+	{ .auxcore = 0x00000000, .host = 0x00180000, .size = 0x8000 }, /* OCRAM_S */
+	{ .auxcore = 0x00180000, .host = 0x00180000, .size = 0x8000 }, /* OCRAM_S */
+	{ .auxcore = 0x20180000, .host = 0x00180000, .size = 0x8000 }, /* OCRAM_S */
+	{ .auxcore = 0x1fff8000, .host = 0x007f8000, .size = 0x8000 }, /* TCML */
+	{ .auxcore = 0x20000000, .host = 0x00800000, .size = 0x8000 }, /* TCMU */
+	{ .auxcore = 0x00900000, .host = 0x00900000, .size = 0x20000 }, /* OCRAM_128KB */
+	{ .auxcore = 0x20200000, .host = 0x00900000, .size = 0x20000 }, /* OCRAM_128KB */
+	{ .auxcore = 0x00920000, .host = 0x00920000, .size = 0x20000 }, /* OCRAM_EPDC */
+	{ .auxcore = 0x20220000, .host = 0x00920000, .size = 0x20000 }, /* OCRAM_EPDC */
+	{ .auxcore = 0x00940000, .host = 0x00940000, .size = 0x20000 }, /* OCRAM_PXP */
+	{ .auxcore = 0x20240000, .host = 0x00940000, .size = 0x20000 }, /* OCRAM_PXP */
+	{ .auxcore = 0x10000000, .host = 0x80000000, .size = 0x0fff0000 }, /* DDR Code alias */
+	{ .auxcore = 0x80000000, .host = 0x80000000, .size = 0xe0000000 }, /* DDRC */
+	{ /* sentinel */ }
+};
+#endif
+
 #ifndef CONFIG_SKIP_LOWLEVEL_INIT
 /* enable all periherial can be accessed in nosec mode */
 static void init_csu(void)
-- 
2.17.1



More information about the U-Boot mailing list