ADR-043 — Lower-EL FIQ while standing (+ SError park honesty)
- Status: Accepted (taken lower-EL FIQ while standing is a supported/probed path when the serial / tests pass; SError has no safe trigger on this virt/cortex-a57 cut — park honesty; umbrella isolation Planned)
- Date: 2026-09-13
Context
ADR-040 / ADR-041 made taken lower-EL IRQ while standing a live path. Lower-EL FIQ and SError still parked (ADR-004 / ADR-042 H4).
On QEMU virt + GICv2 + -cpu cortex-a57, Group 0 interrupts signal as IRQ by default (GICC_CTLR.FIQEn clear). Setting FIQEn routes Group 0 (including the CNTP PPI) as FIQ without changing the default -cpu. True asynchronous SError has no safe, deterministic inject on this guest without exotic QEMU/monitor setup — do not fake a taken path.
PAN enable and umbrella EL0 isolation are not this cut. Do not switch default -cpu cortex-a57. Keep _start at 0x4008_0000.
Hypotheses
| ID | Option | Notes |
|---|---|---|
| H1 (chosen) | Wire fiq_lower_el (same TTBR0 restore as IRQ). Probe: temporarily GICC_CTLR.FIQEn, standing dual-SVC + WFI, SPSR 0x380 (F clear, I set), serial el0: fiq; restore Group-0 → IRQ after the trip. SError: wire a defensive standing-aware stub + print el0: serror-park (Planned / no safe trigger). | Largest honest first cut mirroring IRQ. |
| H2 (rejected) | Claim both FIQ and SError are Verified taken paths without a safe SError inject. | Would round up. |
| H3 (rejected) | Switch -cpu / enable PAN / claim “EL0 isolated” because FIQ returns to EL0. | Forbidden. |
| H4 (fallback) | If FIQEn does not deliver a lower-EL FIQ on this virt guest, ship scaffold + park markers and document why — do not fake Verified. | Honesty over the mile. |
Decision
- Lower-EL FIQ live while standing. Vector slot
0x500callsfiq_lower_el.handle_fiq_lower_elrunsgic::handle_fiq(same IAR/EOI as IRQ for Group 0), thenstay_at_el0whenis_active(). Non-standing lower-EL FIQ still fails closed (park). - Probe. Hello path:
gic::route_group0_as_fiq,timer::arm_soon,eret_to_el0_fiq(SPSR0x380), payloadSVC #1/WFI/MOVZ/SVC #2. Serialel0: fiq. Alwaysgic::route_group0_as_irqafter the trip so the IRQ path stays default. - SError honesty. Vector slot
0x580callsserror_lower_el(defensive: if standing, stay at EL0 and printel0: serror). No taken-path probe on this cut — hello printsel0: serror-park. Taken SError stays Planned. - Fail-closed sensors.
scripts/qemu-smoke.shgrepsel0: fiqandel0: serror-park.#[test_case]lower_el_fiq_while_standing. - Still Planned. Taken lower-EL SError; PAN enable on
-cpu cortex-a57; remaining identity RAM / yank_start; umbrella EL0 isolation. - NFR-10 text is revised in place (ID unchanged). Threat-model v1.23. Do not mint NFR-15+.
Honesty
Say “taken lower-EL FIQ while standing returned to EL0” only when the serial / tests pass. Do not say:
- “EL0 isolated”
- PAN (see ADR-026)
- lower-EL SError is taken / Verified on this guest
- default standing/task
ERETunmasks FIQ (default SPSR still sets F; only the FIQ probe clears F and arms FIQEn) - “secure OS” / “hardened”
Consequences
src/gic.rsowns FIQEn route helpers.src/exception.rsownsfiq_lower_el/serror_lower_el.src/el0.rsowns the standing FIQ probe and the SError park marker.- ADR-013 remains the isolation direction; this ADR closes the FIQ half of ADR-042 H4.
- A later ADR may take SError safely or enable PAN on a different CPU story. That work is not this cut.