ADR-041 — IRQ-unmasked default standing/task ERET
- Status: Accepted (default
ERETto EL0 clears SPSR.I when the serial / tests pass; short non-standing trampoline probes stay masked; FIQ/SError lower-EL still park; umbrella isolation Planned) - Date: 2026-09-13
Context
ADR-040 made taken lower-EL IRQ while standing a live path, but only via a dedicated probe SPSR (eret_to_el0_irq_enabled, I clear). Default eret_to_el0 still used SPSR 0x3c0 (I set), so standing/task entry remained IRQ-masked unless that special trampoline was used.
This cut makes standing EL0 and the loaded-task / standing-payload paths enter with IRQ unmasked by default, and proves a timer tick can arrive without the special probe helper. 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) | Default eret_to_el0 uses SPSR 0x340 (EL0t, I clear). Short non-standing trampoline probes (SVC / IABORT / DABORT without is_active()) use eret_to_el0_masked. Standing IRQ probe uses default eret_to_el0 + WFI + arm_soon (no special SPSR helper). Serial el0: irq + el0: irq-default. Task/loader/syscall/libctos standing paths inherit the default. FIQ/SError stay parked. | Largest honest cut that matches the deferred ADR-040 item. |
| H2 (rejected) | Unmask every ERET including short non-standing probes and claim “IRQ mid-SVC is always fine.” | Non-standing lower-EL IRQ still parks (handle_irq_lower_el); a mid-probe tick would fail-closed. |
| H3 (rejected) | Claim “EL0 isolated” / PAN / “secure OS” because default SPSR clears I. | Isolation umbrella stays Planned. |
| H4 (fallback) | If H1 regresses smoke, keep default masked and document the park — do not regress smoke. | Honesty over the mile. |
Decision
- Default
ERETIRQ-unmasked.eret_to_el0writes SPSR0x340.eret_to_el0_irq_enabledbecomes an alias (or is removed).eret_to_el0_maskedkeeps SPSR0x3c0for short non-standing probes. - Probe. Hello path: same standing dual-SVC +
WFIas ADR-040, but enter via defaulteret_to_el0. Serial stillel0: irq; also printel0: irq-defaultafter that trip succeeds. Existingel0: standing/el0: restoredstill print. - Task path. Loaded standing task / A1–A3 standing payloads use
eret_to_el0and therefore inherit I-clear. No separate task WFI probe required for this cut; IRQ whileis_active()already returns viastay_at_el0. - Fail-closed sensors.
scripts/qemu-smoke.shgrepsel0: irq-default.#[test_case]lower_el_irq_default_eret(or extendlower_el_irq_while_standingto assert default path). - Still Planned. Lower-EL FIQ/SError; PAN enable on
-cpu cortex-a57; remaining identity RAM /_startteardown; umbrella EL0 isolation. - NFR-10 text is revised in place (ID unchanged). Threat-model v1.21. Do not mint NFR-15+.
Honesty
Say “default standing/task ERET enters with IRQ unmasked” only when the serial / tests pass. Do not say:
- “EL0 isolated”
- PAN (see ADR-026)
- lower-EL FIQ/SError are handled
- short non-standing trampoline probes take IRQs (those stay masked)
- “secure OS” / “hardened”
Consequences
src/exception.rsowns SPSR defaults.src/el0.rsowns the default-path IRQ probe. Short probes inel0/ttbr1/teardowncall the masked helper.- ADR-013 remains the isolation direction; this ADR closes the ADR-040 “default ERET still masks I” park.
- A later ADR may take FIQ/SError or enable PAN. That work is not this cut.