aarch64: GIC SPI wiring for virtio-input (item 4.3.5d)

Punch list §25 item 4.3.5d complete.

New apic_spi_enable(intid) generalizes item 0.6's PPI-only sequence to one
explicit SPI (IPRIORITYR/ISENABLER/ITARGETSR, ICFGR read-checked not
written). Verified via a software-pended SPI (GICD_ISPENDR, no device
needed) through the existing generic IRQ dispatch, which needed no changes.
Found and fixed a real bug during verification: PSTATE.I is still set at
apic_init()'s point in boot, so the first self-test run correctly latched
but never took the interrupt. Self-test code reverted after capturing
evidence -- interrupts.c has zero net diff, only apic_spi_enable() remains,
unused until 4.3.5e. Three-arch acceptance boot clean.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Robert Allan James
2026-08-08 12:15:23 -04:00
co-authored by Claude Sonnet 5
parent 8251aebcf8
commit 2a2d7c5e5e
17 changed files with 90693 additions and 80 deletions
+39 -1
View File
@@ -4118,7 +4118,7 @@ document and committing that amendment as its own item.*
> aarch64 (`logs/20260808-114603/aarch64/`), riscv64 (`logs/20260808-114720/riscv64/`,
> `virtio-input: found device` / `driver ready` present, no fault).
- [ ] **4.3.5d — aarch64: GIC SPI wiring for virtio-input.** Item 0.6 scoped the GIC to
- [x] **4.3.5d — aarch64: GIC SPI wiring for virtio-input.** Item 0.6 scoped the GIC to
"one interrupt" (the timer PPI) on purpose and explicitly called a general GIC driver
out of scope. A PCI-attached `virtio-keyboard-pci` device signals via legacy INTx, which
is an SPI, not a PPI — a different GIC distributor path (SPI target-CPU and priority
@@ -4157,6 +4157,44 @@ document and committing that amendment as its own item.*
unaffected, log committed.
*Refs:* §27.5.
> **Done, 2026-08-08.** New `apic_spi_enable(uint32_t intid)` in `apic.c` — generalises
> item 0.6's PPI-only priority/enable/target sequence to one explicit SPI: `GICD_IPRIORITYR`
> (byte-indexed, same pattern as the timer PPI), `GICD_ISENABLER` at
> `0x100 + 4*(intid/32)`, `GICD_ITARGETSR` (byte-indexed, CPU 0 only — no `-smp` on this
> target), and `GICD_ICFGR` read-then-write-only-if-needed (kept item 0.6's "don't touch
> ICFGR unless forced to" posture — the readback already matched level-triggered on this
> board, so no write occurred in practice). New `GICD_ITARGETSR`/`GICD_ISPENDR` offset
> constants added alongside the existing `GICD_*` block.
>
> Verified with a temporary self-test (`aarch64_gic_spi_self_test()` in `interrupts.c`,
> called once from `apic_init()`): software-pended target INTID 38 (GIC SPI 6 — the slot
> 3/INTA formula from §27.5.1, matching 4.3.5c's riscv64 `addr=0x3` placement) via
> `GICD_ISPENDR`, confirmed taken and EOI'd through the existing generic
> `aarch64_irq_handler()` dispatch (which needed **no changes** — it already EOIs any
> non-spurious, non-timer INTID unconditionally, unlike riscv64's PLIC which needed an
> explicit per-source branch in 4.3.5c).
>
> **One real bug found and fixed, not scope creep:** first self-test run reported FAIL —
> `target_intid=0x26 last_intid=0x00`, no exception, boot continued normally past the
> bounded spin-wait (`logs/20260808-115636/aarch64/`). Root cause: `PSTATE.I` is still set
> at the point `apic_init()` (M4) runs — `arch_enable_interrupts()` (`msr daifclr, #2`)
> doesn't run until much later (M7 area, `kernel_main.c`), so the GIC correctly latched the
> pended SPI but the core never trapped to take it. Same class of fix riscv64's self-test
> needed for `sstatus.SIE`. Fixed by temporarily clearing `PSTATE.I` (`msr daifclr, #2`)
> around the pend-and-wait, restoring it after (`msr daifset, #2`) — matches the pre-test
> state exactly, `arch_enable_interrupts()`'s later call is unaffected. Rerun after the fix:
> `target_intid=0x26 last_intid=0x26`, PASS, zero exceptions
> (`logs/20260808-115821/aarch64/`).
>
> Self-test code (the function, its `g_gic_last_intid` capture in `interrupts.c`, and its
> call site in `apic_init()`) reverted after recording this result — `interrupts.c` has
> **zero net diff** from before this item; only `apic.c`'s permanent `apic_spi_enable()`
> remains, unused/uncalled until 4.3.5e wires a real device to it. Three-architecture
> acceptance boot clean, zero exceptions: amd64 (`logs/20260808-120048/amd64/`), aarch64
> (`logs/20260808-120155/aarch64/`), riscv64 (`logs/20260808-120258/riscv64/`) — riscv64
> reboot required by §25.0 rule 6 / `.claude/CLAUDE.md`'s acceptance rule even though this
> item touched only aarch64 files.
> **Scoping check, 2026-08-08 — no landmine found (unlike 4.3.5a).** Before starting this
> item, checked whether aarch64 carries the same class of gap that blocked riscv64:
> `arch_mmu_init()` (`arch/aarch64/arch.c:169`) is an identical stub — "page-table setup...