arch/aarch64: fix VBAR_EL2 stale comment + hardcode HVC PSCI conduit
FABRIC-3.md §IV.3 item 7's code audit found two more findings; fixed both
per direct instruction naming them specifically.
Comments only, no behavior change:
interrupts.c's arch_interrupts_init() doc comment (and its matching
runtime EL2 console message) claimed VBAR_EL2 was "a known gap... not yet
wired." Checked against isr.S's aarch64_install_vectors() and found that
claim stale: the assembly already branches on aarch64_current_el() and
writes vbar_el2/vbar_el1 correctly, threading the same answer through
el2_mode_flag for the IRQ trampoline's ELR/SPSR selection too. There was
no gap to close -- only the comment was wrong. Also fixed a same-vintage
one-word staleness in arch.c's aarch64_install_vectors extern comment
("installs VBAR_EL1" -> EL-aware), caught while touching this.
Real behavior change, gated to preserve existing QEMU behavior:
arch_cold_reset() hardcoded the PSCI conduit to HVC, a documented
QEMU-specific workaround (QEMU's AAVMF has no genuine EL3 to answer SMC).
Real Pi 5 hardware's ATF means EL3 exists there; confirmed further this
pass that bcm2712.dtsi's own /psci node declares method="smc" directly,
not just inferred from ATF's presence.
New aarch64_psci_conduit_init(dtb) in arch.c: fdt_valid(dtb) ->
fdt_find_node_by_compatible(dtb, "arm,psci-1.0") ->
fdt_find_prop_in_node(..., "method", ...) -- sets a module-static
s_psci_use_smc flag to 1 only when method reads exactly "smc"; every
other outcome (no DTB, no PSCI node, method="hvc", property absent)
leaves it at its default 0/HVC, preserving this system's existing QEMU
behavior exactly. arch_cold_reset() now branches on that flag between
smc #0/hvc #0. Called once from apic_init() (arch/aarch64/apic.c), the
one point in boot with boot_info->dtb already in hand -- collocated with
its consumer in arch.c rather than defined in apic.c, since
arch_cold_reset() has no boot_info of its own by the time it runs (called
from deep in VM execution, via BYE).
Three-arch QEMU acceptance run exercised both new guard branches: the
aarch64 boot log shows "PSCI: no DTB -- using HVC (QEMU virt-machine
default)" immediately before the existing GIC discovery lines, then
boots clean to zuse)ok> -- confirming the QEMU/UEFI path is unchanged.
The SMC success branch itself stays unverified until real Pi 5 hardware
runs BYE.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019YcT3H2PQeyujrzjqS3Var
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
dc9445abec
commit
350287850f
+46
-21
@@ -541,9 +541,12 @@ blocker for free.
|
||||
7. **Code audit pass — DONE, 2026-09-04.** Reviewed `arch/aarch64/apic.c`, `arch.c`,
|
||||
`timer.c`, `interrupts.c` for the same class of QEMU-virt-vs-real-hardware assumption
|
||||
§III item 6's amd64 audit looked for. Report-only by default, per this project's own
|
||||
"identify, don't fix unless asked" rule — three of the four findings below are report
|
||||
only, nothing changed for them. **The GIC base address finding was fixed in code**, per
|
||||
direct instruction naming it specifically after this audit landed — see that finding's
|
||||
"identify, don't fix unless asked" rule — **all three findings below were fixed in code
|
||||
across two follow-up rounds, each named specifically by direct instruction after this
|
||||
audit landed**: the GIC base address (severe), the stale VBAR_EL2 doc comment (doc-only),
|
||||
and the hardcoded HVC PSCI conduit. §V.3's own parallel audit found a fourth finding of
|
||||
this same class (riscv64's `satp`-clear reasoning, lowest severity of the whole set) that
|
||||
remains report-only, not asked for. See each finding's own
|
||||
own text for what changed.
|
||||
|
||||
**Finding — severe, confirmed live, blocked reaching `ok>` on real hardware as the code
|
||||
@@ -580,29 +583,51 @@ blocker for free.
|
||||
`"arm,gic-400"` node) — that needs a devicetree this build never has, so it stays
|
||||
unverified until real Pi 5 hardware, same caveat as every other native-path item in this
|
||||
list.
|
||||
**Finding — doc-only, not a functional gap**: `arch_interrupts_init()`'s own doc comment
|
||||
in `interrupts.c` claims "`VBAR_EL1` is written unconditionally regardless of the
|
||||
**Finding — doc-only, not a functional gap — FIXED (comment corrected) 2026-09-04, per
|
||||
direct instruction naming it specifically.** `arch_interrupts_init()`'s own doc comment
|
||||
in `interrupts.c` claimed "`VBAR_EL1` is written unconditionally regardless of the
|
||||
detected level... if EL2, this is a known gap" — checked against `isr.S`
|
||||
(`aarch64_install_vectors`, lines 124–146) and found **stale**: the actual implementation
|
||||
already branches on `aarch64_current_el()` and writes `vbar_el2`/`vbar_el1` correctly,
|
||||
with `el2_mode_flag` threading the same answer through the IRQ trampoline for
|
||||
`ELR_EL1`/`SPSR_EL1` vs `ELR_EL2`/`SPSR_EL2` selection. The comment describes a gap the
|
||||
code already closed; left as-is per report-only policy, but flagged so a future reader
|
||||
doesn't take the stale comment at face value. Which EL the Pi 5's ATF hands the kernel
|
||||
off at under the native path is itself unconfirmed (the `atf@0` reserved-memory region
|
||||
found during item 2's work only establishes that EL3 firmware exists, not which EL the
|
||||
kernel lands at) — moot for this specific gap now that both paths are actually wired, but
|
||||
worth knowing for other EL-dependent code.
|
||||
`ELR_EL1`/`SPSR_EL1` vs `ELR_EL2`/`SPSR_EL2` selection. Rewrote the doc comment and the
|
||||
matching runtime console message (which made the identical stale claim — "not yet
|
||||
wired, see item 0.5/0.7") to describe what `isr.S` actually does, and fixed a
|
||||
same-vintage one-word staleness in `arch.c`'s own `aarch64_install_vectors` extern
|
||||
comment ("installs `VBAR_EL1`" → EL-aware) caught while touching this. No behavior
|
||||
changed anywhere — this was purely three comments correcting themselves to match code
|
||||
that was already right. Which EL the Pi 5's ATF hands the kernel off at under the native
|
||||
path is itself still unconfirmed (the `atf@0` reserved-memory region found during item
|
||||
2's work only establishes that EL3 firmware exists, not which EL the kernel lands at) —
|
||||
moot for this specific fix now that both paths are correctly wired regardless of which EL
|
||||
is chosen, but worth knowing for other EL-dependent code.
|
||||
**Finding — same defect class as amd64's `arch_cold_reset()` finding, on the QEMU side of
|
||||
this arch specifically**: `arch/aarch64/arch.c`'s `arch_cold_reset()` issues PSCI
|
||||
`SYSTEM_RESET` via `HVC` — a fix already documented in-file as a QEMU-specific
|
||||
workaround, because QEMU's AAVMF firmware has no genuine EL3/TrustZone secure monitor to
|
||||
answer an `SMC`. The Pi 5's real ATF (confirmed present via the `atf@0` reservation) is
|
||||
exactly the kind of genuine EL3 firmware PSCI's `SMC` conduit assumes — the conventional
|
||||
real-hardware call, not `HVC`. No runtime conduit detection exists; this is hardcoded to
|
||||
the QEMU-only fix with no fallback. Riscv64's equivalent (`arch/riscv64/arch.c`, SBI SRST)
|
||||
is the portable pattern this and amd64's i8042-pulse version both lack — worth naming as
|
||||
the standard to bring the other two toward, not fixed here.
|
||||
this arch specifically — FIXED 2026-09-04, per direct instruction naming it
|
||||
specifically.** `arch/aarch64/arch.c`'s `arch_cold_reset()` issued PSCI `SYSTEM_RESET` via
|
||||
`HVC` unconditionally — a fix already documented in-file as a QEMU-specific workaround,
|
||||
because QEMU's AAVMF firmware has no genuine EL3/TrustZone secure monitor to answer an
|
||||
`SMC`. The Pi 5's real ATF (confirmed present via the `atf@0` reservation) is exactly the
|
||||
kind of genuine EL3 firmware PSCI's `SMC` conduit assumes — confirmed further this pass:
|
||||
`bcm2712.dtsi`'s own `/psci` node declares `method = "smc"` directly, not inferred from
|
||||
ATF's mere presence. **Fix**: new `aarch64_psci_conduit_init(dtb)` (`arch.c`) —
|
||||
`fdt_valid(dtb)` → `fdt_find_node_by_compatible(dtb, "arm,psci-1.0")` →
|
||||
`fdt_find_prop_in_node(..., "method", ...)` — sets a module-static `s_psci_use_smc` flag
|
||||
to 1 only when the DTB's own `method` property reads exactly `"smc"`; every other
|
||||
outcome (no DTB, no PSCI node, `method="hvc"`, property absent) leaves it at its default
|
||||
0, preserving the exact HVC behaviour this system's QEMU boot already relies on.
|
||||
`arch_cold_reset()` now branches on that flag between the `smc #0`/`hvc #0` trap
|
||||
instructions; the function ID and calling convention are identical either way, matching
|
||||
the file's own existing comment about that. Called once from `apic_init()`
|
||||
(`arch/aarch64/apic.c`), the one point in boot with `boot_info->dtb` already in hand —
|
||||
collocated in `arch.c`, not `apic.c`, because `arch_cold_reset()` is the actual consumer
|
||||
and has no `boot_info` of its own by the time it runs (called from deep in VM execution,
|
||||
via `BYE`). Riscv64's equivalent (`arch/riscv64/arch.c`, SBI SRST) remains the one cold-
|
||||
reset implementation across all three architectures that never needed this kind of fix —
|
||||
still worth naming as the standard the other two moved toward, one now fixed, amd64's
|
||||
i8042-pulse version still open. 3-arch acceptance exercised the guard (this system's QEMU
|
||||
AAVMF forwards no DTB, so `aarch64_psci_conduit_init()` hits its own "no DTB" branch and
|
||||
`arch_cold_reset()` keeps using HVC, unchanged) but not the `SMC` success branch itself —
|
||||
that stays unverified until real Pi 5 hardware runs `BYE`.
|
||||
|
||||
**Hardware-dependent, after 2026-09-17 (not started until then):**
|
||||
8. Build the boot media (SD card: `config.txt`, `bcm2712-rpi-5-b.dtb`, kernel image).
|
||||
|
||||
Reference in New Issue
Block a user