ADR-045 — Taken lower-EL SError via QMP/nmi (honest partial)
- Status: Accepted as implementation attempt — guest A-clear standing path is wired; host QMP
inject-nmion QEMU 10virt+-cpu cortex-a57does not deliver SError (machine does not provide NMIs). Taken lower-EL SError while standing stays Planned.el0: serror-parkremains the Verified honesty marker (ADR-043 / ADR-044). - Date: 2026-09-13
Context
ADR-044 recommended H1: host QMP/inject-nmi while standing with PSTATE.A clear, expecting virt → ARM_CPU_SERROR. That recommendation tracked a 2020 qemu-devel series; upstream QEMU 10 does not implement that path on this smoke machine:
inject-nmi/ HMPnmi→machine does not provide NMIs(noTYPE_NMIon virt for cortex-a57 + default GICv2).- Modern virt “NMI” support is FEAT_NMI (GICv3 + a CPU with
aa64_nmi), not async SError, and requires switching-cpu/ GIC — forbidden here. - TCG has virtual SError (
HCR_EL2.VSE/EXCP_VSERR) for EL2→EL1, not a host inject into our EL1/EL0 standing guest. - Guest-only RAS inject remains rejected for Verified (ADR-044 H2).
Do not switch default -cpu cortex-a57. Do not claim “EL0 isolated.” Keep _start at 0x4008_0000. Do not unmask A on default standing/task ERET (SPSR 0x340 keeps A set).
Decision
- Guest plumbing (shipped).
eret_to_el0_serroruses SPSR0x2c0(D+I+F set, A clear). Hello armsEXPECT_EL0_SERROR, prints UART cueel0: serror-arm, enters standing dual-SVC with a bounded spin (notWFI— I/F stay masked, so a failed inject must not hang). Handlerserror_lower_elprintsel0: serroronly when EXPECT is armed, thenstay_at_el0. - Host smoke (attempted).
scripts/qemu-serial-inject.pyopens-qmp unix:…,server,nowaitand, afterel0: serror-arm, issues{"execute":"inject-nmi"}, logging the result. On this QEMU it errors; guest printsel0: serror-park.qemu-smoke.shstill requiresel0: serror-parkand must not requireel0: serror. - No
#[test_case]for the taken path — it needs a host inject. Smoke-only honesty. - Taken path stays Planned. Do not mark Verified. Park marker stays Verified.
- Still Planned (unchanged honesty): PAN enable on
-cpu cortex-a57(ADR-026); yank_start/ leftover identity RAM (ADR-042); umbrella “EL0 isolated.” - NFR-10 text revised in place (ID unchanged). Threat-model v1.25. Do not mint NFR-15+.
Honesty
Say “guest A-clear standing SError path is wired; QMP inject-nmi does not take SError on virt/cortex-a57.” Do not say:
- taken lower-EL SError is Verified on this guest
- “EL0 isolated” / PAN / “secure OS”
- default standing
ERETunmasks SError - ADR-044 H1 landed as a working inject on QEMU 10
- guest-only RAS inject works on cortex-a57 TCG
Follow-on
ADR-083 (2026-09-19): pinned QEMU opt-in Verifies taken el0: serror; stock park path unchanged.
Consequences
src/exception.rs/src/el0.rsown the A-clear probe + EXPECT.scripts/qemu-serial-inject.pyowns the QMP attempt.el0: serror-parkstays the fail-closed serial when inject does not land.- ADR-047 records the sponsor decision: taken path is deferred / non-goal on this smoke machine until an honest inject exists; park stays Verified; A-clear plumbing stays as dormant prep.
- A later ADR may find a different honest inject (new QEMU feature, or a constrained CPU story with sponsor approval). That work is not this cut.
- Hard-stop lock: ADR-053 (2026-09-14) re-probed
inject-nmi/ HMPnmion QEMU 10.0.13 virt+cortex-a57 — samemachine does not provide NMIs. Taken path is locked deferred/non-goal, not a fuzzy Planned mile. - Reopen re-probe: ADR-081 / ADR-082 (2026-09-19) on default
-cpu cortex-a76+ GICv3/virtualization=on/max— stillmachine does not provide NMIs. Dormant prep unchanged. - Docker/(amd64 workstation) re-probe is optional; agent-box smoke must show park + QMP error log, not a fake
el0: serror.