Skip to content

sunxi-fel: handle H616 secure-FEL SPL handoff#236

Open
jameshilliard wants to merge 2 commits into
linux-sunxi:masterfrom
jameshilliard:h616-secure-fel
Open

sunxi-fel: handle H616 secure-FEL SPL handoff#236
jameshilliard wants to merge 2 commits into
linux-sunxi:masterfrom
jameshilliard:h616-secure-fel

Conversation

@jameshilliard

Copy link
Copy Markdown
Contributor

Newer secure-boot SoCs such as H616 enter FEL in non-secure SVC, so SPL cannot switch to AArch64 unless it first reaches secure state.

Add a secure-SVC SPL thunk variant for SoCs that need this transition. The thunk executes the ROM SMC path, clears SCR.NS, installs the secure-SVC SP/LR and the secure GIC view expected by the ROM, then enters SPL from secure-SVC mode. When SPL returns, it restores the secure GIC view before resuming BROM FEL.

Also add a small secure-SVC return thunk for command paths that need secure SID/register access but should return to FEL instead of entering SPL. Use the H616 SID shadow word at 0x03006240 to detect whether the SMC workaround is needed, so non-secure-boot boards skip it.

@apritzel apritzel left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This patch is massive (aka barely reviewable) and apparently combines code movement/refactoring and new features, which is not a good idea.
Please split this up to refactor the code first, then apply the changes required for the H616.
Also the detection doesn't work: on my non-secure boards, 0x03006240 also reads as zero, which triggers the secure code and hangs. Can you try to read the secure fuse word, and maybe filter for that bit?
And why does the secure workaround now only triggers for the SID read? And what does it have to do with the SPL? The smc #0 before was just triggered once, on the first sunxi-fel command, then the rest just fell in place. I am still hopeful something similar is possible on the newer SoCs, without having explicit entry and exit code.
At the very least this should be explained in detail in the commit message or in comments.
That's just what I found after 5 minutes into the patch, but as mentioned, it's very hard to comprehend. Please tell your LLM to make this understandable and reviewable by human beings.

@jameshilliard jameshilliard force-pushed the h616-secure-fel branch 2 times, most recently from ab40817 to ebd5305 Compare May 16, 2026 19:34
@jameshilliard

jameshilliard commented May 16, 2026

Copy link
Copy Markdown
Contributor Author

The patch is now a single commit:

sunxi-fel: handle H616 secure-FEL handoff

The generic SPL path is left alone. thunks/fel-to-spl-thunk.S and the
generated thunks/fel-to-spl-thunk.h are unchanged from master, and SPL
loading continues through the existing SPL code path.

The H616-specific part is limited to the secure-FEL startup transition and
the SoC data used to select it. H616 now checks both:

  • the secure boot status word at SID + 0xa0 (0x030060a0) with mask 0xf
  • the existing zero-word probe at 0x03006240

That avoids triggering the secure path on non-secure H616 boards where the
zero-word probe can also read as zero.

The SMC workaround method is explicit in SoC data:

  • existing secure-FEL users select SMC_WORKAROUND_DIRECT_SMC
  • H616 selects SMC_WORKAROUND_SECURE_SVC_THUNK

H616 still follows the global startup model: sunxi-fel applies the
workaround after opening the FEL device and before processing commands. It is
not tied to SID or SPL. The SID path is only one validation case because the
protected SID words are not readable until the transition succeeds.

The difference from older SoCs is the transition mechanism. Older SoCs can
execute smc #0; bx lr directly. On H616, smc #0 returns through monitor
mode, so the direct sequence does not leave the BROM FEL command loop in the
secure-SVC state it expects.

The H616 thunk issues the SMC, switches from monitor mode to secure SVC with
the banked SP/LR restored, restores the secure GIC view expected by the BROM,
and returns to the FEL command loop. It uses the same SRAM swap-table
convention as the SPL thunk to preserve the H616 BROM SRAM workspace while
the uploaded code runs and returns to FEL. After the transition, the normal
runtime probe sees secure state and suppresses repeat application in that
sunxi-fel process, so normal SID reads and SPL execution use the existing
code paths.

The new thunk header is added to the top-level sunxi-fel dependencies, and
thunks/Makefile can regenerate it with the same old-style header format used
by fel-to-spl-thunk.h.

Validation on the H616 board:

./sunxi-fel -v sid sid-dump ver

That applied the secure-SVC return thunk once in the sunxi-fel process,
printed the protected SID words, and then ver still worked.

I also tested SPL loading with the separate TOC0 loader changes in my working
tree:

./sunxi-fel -v -p uboot u-boot-sunxi-with-spl.bin

That applied the secure-SVC return thunk before TOC0 parsing, wrapped the TOC0
SPL item, executed the normal SPL thunk, returned from SPL to FEL, loaded
ATF/U-Boot/DTB, and started U-Boot. The TOC0 loader itself remains separate
from this secure-FEL patch.

@jameshilliard jameshilliard force-pushed the h616-secure-fel branch 2 times, most recently from 7dae1f5 to 486caf2 Compare May 17, 2026 02:08
@jameshilliard jameshilliard requested a review from apritzel May 17, 2026 18:13
@jameshilliard jameshilliard force-pushed the h616-secure-fel branch 5 times, most recently from ced88c1 to 681257a Compare May 24, 2026 04:12
Comment thread soc_info.c Outdated
.rvbar_reg_alt= 0x08100040,
.ver_reg = 0x03000024,
.needs_smc_workaround_if_zero_word_at_addr = 0x03006240,
.secure_boot_fuse_addr = 0x030060a0,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be an offset from .sid_base (or even always sid_base + 0xa0).

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed. This is now encoded as an offset from sid_base; H616 uses secure_boot_fuse_offset = 0xa0.

Comment thread fel.c Outdated
return false;

if (!soc_info->needs_smc_workaround_if_zero_word_at_addr)
return true;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we want to assume the workaround is needed if we don't have a way of distinguishing secure SVC from NS SVC, as we would apply the workaround on every sunxi-fel invocation.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed. The secure boot fuse is now only a guard. The runtime zero-word probe still has to match before the workaround is applied, so a secure fuse alone cannot make every sunxi-fel invocation run the thunk.

Comment thread fel.c
aw_fel_read(dev, soc_info->secure_boot_fuse_addr,
&val, sizeof(val));
if (!(le32toh(val) & soc_info->secure_boot_fuse_mask))
return false;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Have you ever seen a value other than 0 or 1 in 0x030060a0? I don't think this needs a mask; any nonzero value is secure.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed. The mask is gone; any nonzero value in the secure boot status word is treated as secure boot.

@smaeul

smaeul commented Jun 5, 2026

Copy link
Copy Markdown

A133 puts the monitor vector table at 0x300c0 (in SRAM C), and then wipes SRAM A1 and SRAM C at the beginning of NBROM, so you have to copy the monitor mode code back to SRAM before you can do smc. If I copy the stock SMC handler from the SBROM, A133 will also need something similar to this for GIC setup (smc works on A133 if I do it a second time to toggle back to NS before returning to FEL). But we could also make a smarter SMC handler that does all of the setup at once. Since the whole SRAM should be writable on H616, we should be able to overwrite the SMC handler before calling it on H616 as well.

@jameshilliard jameshilliard force-pushed the h616-secure-fel branch 2 times, most recently from 14eeace to e2f9995 Compare June 5, 2026 18:41
@jameshilliard

Copy link
Copy Markdown
Contributor Author

The updated version uses that smarter-handler approach for H616.

Instead of copying the stock SBROM SMC handler, the thunk installs a
temporary monitor-mode SMC handler by patching only the SMC vector word at
MVBAR + 8. The handler lives in the uploaded thunk, restores the original
vector word immediately, clears SCR.NS, clears MVBAR, sets up the secure
GIC view, copies the saved SVC SP/LR into the secure bank, switches to secure
SVC, and returns to the FEL command loop.

So this avoids replacing the whole monitor vector table on H616. The handler
parameters are in SoC data, so the same mechanism can be reused for A133-style
support later, but this patch only enables it for H616.

@smaeul

smaeul commented Jun 10, 2026

Copy link
Copy Markdown

Thanks for the updates! I can confirm this works on A133 as well, with the same settings, so the following change:

diff --git a/soc_info.c b/soc_info.c
index fa7b7e2..03b8dd6 100644
--- a/soc_info.c
+++ b/soc_info.c
@@ -766,8 +766,10 @@ soc_info_t soc_info_table[] = {
                        .brom_hook_shadow_addr = 0x0003c000,
                        .dma_max_len = FEL_RX_DMA_MAX_LEN,
                },
-               .needs_smc_workaround_if_zero_word_at_addr = 0x100004,
-               .smc_workaround = SMC_WORKAROUND_DIRECT_SMC,
+               .needs_smc_workaround_if_zero_word_at_addr = 0x03006240,
+               .secure_boot_fuse_offset = 0xa0,
+               .smc_workaround = SMC_WORKAROUND_SECURE_SVC_SMC_THUNK,
+               .monitor_smc_handler = &h616_monitor_smc_handler,
                .watchdog     = &wd_h6_compat,
        },{
                .swap_buffers = NULL /* End of the table */

Separate the runtime SMC-workaround probe from the code that executes
the workaround so later SoCs can choose a different implementation
without mixing that change into the existing direct-SMC path.

Describe the workaround method in SoC data and make every existing
secure-FEL user select the direct-SMC method explicitly. This preserves
the current behaviour because direct SMC remains the only implementation
in this patch.

Also make the old-format thunk header rule pattern-based while it still
only builds the existing SPL thunk header.

Signed-off-by: James Hilliard <james.hilliard1@gmail.com>
On H616 and A133 with the secure boot fuse set, FEL starts in
non-secure state. The older direct SMC workaround is not sufficient
there because SMC enters monitor mode instead of directly leaving the
BROM FEL command loop in secure SVC state.

Add a secure-SVC SMC thunk for this case and keep the existing global
startup workaround model. The thunk preserves the BROM SRAM workspace
using the same swap-table convention as the SPL thunk, installs a
temporary monitor-mode SMC handler by patching only the SMC vector word,
then issues SMC. The temporary handler restores the original vector word,
clears SCR.NS, clears MVBAR, restores the secure GIC view expected by
the BROM, copies the saved SVC SP/LR into the secure bank, switches to
secure SVC, and returns to the FEL command loop.

After the transition, the normal runtime probe sees secure state and
suppresses repeat application in that sunxi-fel process, so normal SID
reads and SPL execution use the existing code paths.

H616 and A133 select the secure-SVC SMC thunk path and gate the
workaround on a non-zero secure boot status word at SID base + 0xa0.
The zero-word runtime probe still has to match before the thunk is
applied, so non-secure boards and already-transitioned secure-FEL
sessions do not enter the secure path just because one of those checks
matches.

Signed-off-by: James Hilliard <james.hilliard1@gmail.com>
@jameshilliard

Copy link
Copy Markdown
Contributor Author

Thanks for the updates! I can confirm this works on A133 as well, with the same settings, so the following change:

I re-based an applied this change.

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.

3 participants