diff options
| author | Bradley Morgan <brads@mainlining.org> | 2026-10-04 05:59:26 +0000 |
|---|---|---|
| committer | Bradley Morgan <brads@mainlining.org> | 2026-10-04 05:59:26 +0000 |
| commit | 4256361421a2d857e8a1d5cdef45bdbcfef477ad (patch) | |
| tree | 7aee83d4194098f49f2ad84f5080e1b6155d7638 /arch/arm64/kernel/start.S | |
| parent | 0567dd7e947d10a237405e4a9d965c57dd6b473e (diff) | |
tashaboot: el3 secure monitor
The resident firmware layer real machines ship, the thing the
gic group lesson pointed at. The reset path configures EL3,
SP_EL3 on its own region, the monitor vectors in VBAR_EL3,
then hands the next stage non-secure EL2 in the manual's boot
state and never comes back except through exceptions.
Secondaries that enter at EL3 get the monitor before they
park, a firmware call on any PE must land in a handler, and
SCR_EL3.NS is set to match the primary so a released PE does
not come up secure while the kernel runs non-secure.
The SMC conduit traps into the lower EL AArch64 sync slot and
dispatches through the same PSCI C code the hvc path uses,
SMCCC register convention kept whole across the trap.
On the emulator here the machine's own firmware shadow stands
in front of the conduit, its PSCI answers before the monitor
sees the call, and its secure memory map traps the kernel's
flash probe after init starts. The monitor mechanics, the
entry, the vectors, the stack, the eret, the SMC layout, are
live on every secure boot, the call dispatch itself is the
hardware receipt.
receipt: secure boot through the monitor to four cpus and the
init exec, plain boot unchanged to the busybox shell.
Diffstat (limited to 'arch/arm64/kernel/start.S')
| -rw-r--r-- | arch/arm64/kernel/start.S | 38 |
1 files changed, 32 insertions, 6 deletions
diff --git a/arch/arm64/kernel/start.S b/arch/arm64/kernel/start.S index 3cf58d2..2a5e2ae 100644 --- a/arch/arm64/kernel/start.S +++ b/arch/arm64/kernel/start.S @@ -38,12 +38,16 @@ reset: /* keep the dtb pointer before anything clobbers x0 */ mov x19, x0 - /* park secondary cores, they have nothing to do yet */ + /* + * park secondary cores, they have nothing to do yet. at + * EL3 they still get the monitor: a firmware call on any + * PE must land in a handler, a secondary with no EL3 + * vectors traps into nothing. + */ mrs x0, mpidr_el1 and x0, x0, #0xff - cbnz x0, park + cbnz x0, secondary_boot - /* which EL are we in, 0x8 per level shifted into bits 3:2 */ mrs x0, CurrentEL lsr x0, x0, #2 cmp x0, #3 @@ -54,12 +58,34 @@ reset: b.eq mmu_check b park +secondary_boot: + mrs x0, CurrentEL + lsr x0, x0, #2 + cmp x0, #3 + b.ne park + /* + * the same security state as the primary: SCR_EL3.NS + * clear leaves a PE secure, and a secondary released + * into the kernel secure is the inconsistent mode boot + * the kernel warns about, its calls trap to EL3 as if + * they were firmware's own. + */ + mrs x0, scr_el3 + orr x0, x0, #1 + msr scr_el3, x0 + isb + bl tb_monitor_init + b park + from_el3: /* - * EL3 holds the security state. the kernel runs non-secure, so - * set SCR_EL3.NS before dropping to EL2, which the kernel - * prefers (booting.rst, EL2 RECOMMENDED). + * EL3 holds the security state, so the monitor lives here: + * vectors, its own stack, the SMC conduit. it is resident + * after this, the kernel's firmware calls trap into it. */ + bl tb_monitor_init + + /* the kernel runs non-secure, drop to the EL2 it prefers */ mrs x0, scr_el3 orr x0, x0, #1 /* SCR_EL3.NS = 1, non-secure */ msr scr_el3, x0 |
