Skip to content

sunxi-fel: auto-use SPL RAM FIT handoff#248

Open
jameshilliard wants to merge 1 commit into
linux-sunxi:masterfrom
jameshilliard:ramfit-handoff
Open

sunxi-fel: auto-use SPL RAM FIT handoff#248
jameshilliard wants to merge 1 commit into
linux-sunxi:masterfrom
jameshilliard:ramfit-handoff

Conversation

@jameshilliard

Copy link
Copy Markdown
Contributor

The normal "sunxi-fel uboot" FIT path parses and loads the U-Boot FIT on the host after SPL returns to FEL. That bypasses SPL's own FIT loader, which breaks flows that need SPL-side handling, such as encrypted U-Boot proper FITs.

Teach the uboot command to detect a live SPL v0.4 RAM FIT handoff after DRAM init. If the payload after SPL is a FIT and the SPL header publishes a FIT buffer and resume address, write the FIT to that buffer and start the published resume address so SPL continues its normal FIT load path.

Older SPL builds, non-FIT payloads and the spl command keep using the existing behavior.

This feature needs a uboot patch:

From 9de50bb0e9fae40949d41e02940b77f2301184b8 Mon Sep 17 00:00:00 2001
From: James Hilliard <james.hilliard1@gmail.com>
Date: Mon, 6 Jul 2026 13:30:21 -0600
Subject: [PATCH] sunxi: spl: support FEL RAM FIT handoff

The sunxi-fel uboot command normally asks SPL to initialize DRAM and
then loads a U-Boot FIT from the host side after SPL returns to FEL.
That bypasses SPL's own FIT loader, so flows that rely on SPL-side FIT
processing, such as encrypted U-Boot proper FITs, cannot be exercised
through FEL.

When SPL FIT loading uses a fixed FIT address, publish a RAM FIT
handoff in the live sunxi SPL header before returning to FEL. A
compatible sunxi-fel can write the FIT to that buffer and resume SPL
through the published entry point. The resumed SPL then uses the RAM
loader, preserving normal SPL FIT parsing, hash and signature checks,
and decryption.

Select the SPL RAM loader for sunxi SPL FIT builds and add sunxi
SPL_LOAD_FIT_ADDRESS defaults so this path is available without board
specific configuration. Bump the sunxi SPL header minor version to
v0.4 for the new handoff fields. Older sunxi-fel versions keep using
the existing host-side FIT loader path.

Signed-off-by: James Hilliard <james.hilliard1@gmail.com>
---
 arch/arm/mach-sunxi/board.c | 59 +++++++++++++++++++++++++++++++++++++
 boot/Kconfig                |  2 ++
 common/spl/spl_ram.c        |  4 +--
 include/spl.h               |  3 ++
 include/sunxi_image.h       |  1 +
 5 files changed, 67 insertions(+), 2 deletions(-)

diff --git a/arch/arm/mach-sunxi/board.c b/arch/arm/mach-sunxi/board.c
index 432b1c10f92..88b4a23b672 100644
--- a/arch/arm/mach-sunxi/board.c
+++ b/arch/arm/mach-sunxi/board.c
@@ -10,9 +10,12 @@
  */
 
 #include <cpu_func.h>
+#include <errno.h>
 #include <init.h>
+#include <limits.h>
 #include <log.h>
 #include <mmc.h>
+#include <setjmp.h>
 #include <i2c.h>
 #include <serial.h>
 #include <spl.h>
@@ -29,6 +32,8 @@
 
 #include <linux/compiler.h>
 
+#define SUNXI_FEL_RAMFIT_WAIT	0xf8
+
 struct fel_stash {
 	uint32_t sp;
 	uint32_t lr;
@@ -78,6 +83,18 @@ phys_addr_t board_get_usable_ram_top(phys_size_t total_size)
 #endif /* CONFIG_ARM64 */
 
 #ifdef CONFIG_XPL_BUILD
+static jmp_buf sunxi_fel_ramfit_jmp __section(".data");
+static gd_t *sunxi_fel_ramfit_gd __section(".data");
+
+void __noreturn sunxi_spl_fel_ramfit_resume(void)
+{
+	set_gd(sunxi_fel_ramfit_gd);
+	longjmp(sunxi_fel_ramfit_jmp, 1);
+
+	for (;;)
+		;
+}
+
 static int gpio_init(void)
 {
 	__maybe_unused uint val;
@@ -215,6 +232,48 @@ static int gpio_init(void)
 static int spl_board_load_image(struct spl_image_info *spl_image,
 				struct spl_boot_device *bootdev)
 {
+	struct boot_file_head *spl = (void *)SPL_ADDR;
+	unsigned long fit_addr;
+
+	sunxi_fel_ramfit_gd = gd;
+	if (setjmp(sunxi_fel_ramfit_jmp)) {
+		puts("Resuming FEL RAM FIT handoff\n");
+		bootdev->boot_device = BOOT_DEVICE_RAM;
+		CONFIG_IS_ENABLED(RAM_SUPPORT,
+				  (return spl_ram_load_image(spl_image,
+							     bootdev);))
+		return -EOPNOTSUPP;
+	}
+
+	fit_addr = CONFIG_IS_ENABLED(HAS_LOAD_FIT_ADDRESS,
+				     (CONFIG_VAL(LOAD_FIT_ADDRESS)), (0));
+	if (IS_ENABLED(CONFIG_SPL_LOAD_FIT) && fit_addr &&
+	    !memcmp(spl->spl_signature, SPL_SIGNATURE, 3)) {
+		unsigned long dram_start = PHYS_SDRAM_0;
+		unsigned long dram_size;
+		unsigned long dram_end;
+		unsigned long max_size;
+
+		dram_size = (unsigned long)readl(&spl->dram_size) << 20;
+		dram_end = dram_start + dram_size;
+		if (fit_addr >= dram_start && fit_addr < dram_end) {
+			max_size = dram_end - fit_addr;
+			if (max_size > UINT_MAX)
+				max_size = UINT_MAX;
+
+			writel(fit_addr, &spl->fel_script_address);
+			writel(max_size, &spl->fel_uEnv_length);
+			/* Reuse the DT-name field for this resume entry. */
+			writel((ulong)sunxi_spl_fel_ramfit_resume,
+			       &spl->dt_name_offset);
+			if (spl->spl_signature[3] <
+			    SPL_FEL_RAMFIT_HEADER_VERSION)
+				spl->spl_signature[3] =
+					SPL_FEL_RAMFIT_HEADER_VERSION;
+			writeb(SUNXI_FEL_RAMFIT_WAIT, &spl->boot_media);
+		}
+	}
+
 	debug("Returning to FEL sp=%x, lr=%x\n", fel_stash.sp, fel_stash.lr);
 	return_to_fel(fel_stash.sp, fel_stash.lr);
 
diff --git a/boot/Kconfig b/boot/Kconfig
index ae6f09a6ede..bd43c3a4386 100644
--- a/boot/Kconfig
+++ b/boot/Kconfig
@@ -228,6 +228,7 @@ config SPL_LOAD_FIT
 	bool "Enable SPL loading U-Boot as a FIT (basic fitImage features)"
 	depends on SPL
 	select SPL_FIT
+	select SPL_RAM_SUPPORT if ARCH_SUNXI
 	help
 	  Normally with the SPL framework a legacy image is generated as part
 	  of the build. This contains U-Boot along with information as to
@@ -261,6 +262,7 @@ config SPL_LOAD_FIT_ADDRESS
 	default 0x81000000 if ARCH_K3 && ARM64
 	default 0x80080000 if ARCH_K3 && CPU_V7R
 	default 0x44000000 if ARCH_IMX8M
+	default 0x42000000 if ARCH_SUNXI
 	default 0x60080000 if ARCH_ROCKCHIP && SPL_TEXT_BASE = 0x60000000
 	default 0x40200000 if ARCH_ROCKCHIP && SPL_TEXT_BASE = 0x40000000
 	default 0x00200000 if ARCH_ROCKCHIP && SPL_TEXT_BASE = 0x00000000
diff --git a/common/spl/spl_ram.c b/common/spl/spl_ram.c
index 0c501cf02f2..48319dd018e 100644
--- a/common/spl/spl_ram.c
+++ b/common/spl/spl_ram.c
@@ -42,8 +42,8 @@ static ulong spl_ram_load_read(struct spl_load_info *load, ulong sector,
 	return count;
 }
 
-static int spl_ram_load_image(struct spl_image_info *spl_image,
-			      struct spl_boot_device *bootdev)
+int spl_ram_load_image(struct spl_image_info *spl_image,
+		       struct spl_boot_device *bootdev)
 {
 	struct legacy_img_hdr *header;
 	ulong addr = 0;
diff --git a/include/spl.h b/include/spl.h
index 5078d7525ab..f7463d45ef8 100644
--- a/include/spl.h
+++ b/include/spl.h
@@ -806,6 +806,9 @@ struct spl_image_loader {
 			  struct spl_boot_device *bootdev);
 };
 
+int spl_ram_load_image(struct spl_image_info *spl_image,
+		       struct spl_boot_device *bootdev);
+
 /* Helper function for accessing the name */
 static inline const char *spl_loader_name(const struct spl_image_loader *loader)
 {
diff --git a/include/sunxi_image.h b/include/sunxi_image.h
index 379ca9196e0..05c2cf06539 100644
--- a/include/sunxi_image.h
+++ b/include/sunxi_image.h
@@ -30,6 +30,7 @@
 #define SPL_ENV_HEADER_VERSION	SPL_VERSION(0, 1)
 #define SPL_DT_HEADER_VERSION	SPL_VERSION(0, 2)
 #define SPL_DRAM_HEADER_VERSION	SPL_VERSION(0, 3)
+#define SPL_FEL_RAMFIT_HEADER_VERSION	SPL_VERSION(0, 4)
 
 /* boot head definition from sun4i boot code */
 struct boot_file_head {
-- 
2.53.0

The normal "sunxi-fel uboot" FIT path parses and loads the U-Boot
FIT on the host after SPL returns to FEL. That bypasses SPL's own FIT
loader, which breaks flows that need SPL-side handling, such as
encrypted U-Boot proper FITs.

Teach the uboot command to detect a live SPL v0.4 RAM FIT handoff
after DRAM init. If the payload after SPL is a FIT and the SPL header
publishes a FIT buffer and resume address, write the FIT to that
buffer and start the published resume address so SPL continues its
normal FIT load path.

Older SPL builds, non-FIT payloads and the spl command keep using the
existing behavior.

Signed-off-by: James Hilliard <james.hilliard1@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant