# DF-5509 — ehci_pci.c arms ehci_interrupt before controller init: pre-init interrupts are mute (no acknowledge) → level-INTx IRQ storm

## What (root cause, one paragraph)

`ehci_pci_attach()` registers the interrupt handler at
`sys/bus/u4b/controller/ehci_pci.c:390-391` — **before**
`ehci_pci_take_controller()` (:398, whose BIOS-handoff wait can park the
attach for up to 5 s at :532-545) and before `ehci_init()` (:451) runs. In
that whole window the fresh `M_ZERO` softc still holds the pre-init values
`sc_offs == 0` and `sc_eintrs == 0` (set only at ehci.c:308/353; softc
zeroing confirmed at sys/kern/subr_bus.c:1953-1954). The armed handler
`ehci_interrupt()` then:

- reads "USBSTS" at `io_hdl + sc_offs(0) + 0x04` — the **HCSPARAMS
  capability register**, never the real status register (measured: reads 6),
- and because `status & sc->sc_eintrs == 0`, unconditionally exits via
  `goto done` at ehci.c:1509-1511 **without writing USBSTS to acknowledge**.

If the controller arrives with `(USBINTR & USBSTS) != 0` — classic
BIOS-ownership-handoff residue, or a malicious/compromised controller — the
level-triggered INTx re-fires for every instant of the window. Nothing
clears USBINTR/USBSTS until `ehci_hcreset()` at ehci.c:215 (first reached
via ehci.c:335, *after* the 5 s handoff park). On this 6-vCPU guest the
storm is bounded (~5 s, 311,162 interrupts measured in the window vs 55 in
the control); on fewer CPUs — or whenever the storming IRQ thread starves
the attaching thread — `ehci_hcreset` is never reached and the storm is
permanent (demonstrated: ~33K interrupts/s sustained indefinitely until the
softc was un-muted).

## Guest environment (env.txt)

DragonFly 6.5-DEVELOPMENT x86_64, QEMU 7.2.22 i440fx, `-device
usb-ehci,id=ehci0` cold-boot → ehci0@pci0:0:3:0 (8086:24cd), BAR
0xfebd1000/0x1000, IRQ 10, CAPLENGTH 0x20, 6 ports, HCCPARAMS=0x6880
(EECP=0x68 → QEMU-implemented writable LEGSUP semaphores at config 0x68).
ehci as /boot/kernel/ehci.ko.

## Build

    # in guest (needs /usr/src + /usr/obj/usr/src/sys/X86_64_GENERIC):
    mkdir -p /root/ehciarm && cp mutearm.c Makefile /root/ehciarm/
    cd /root/ehciarm && make KERNBUILDDIR=/usr/obj/usr/src/sys/X86_64_GENERIC

## Run

See run.sh (exact sequence) and VERDICT.md (measured results).

Expected decisive numbers (unpatched kernel):

- Phase 2 (park + one real port event, stock driver):
  ehci0 interrupts 393,106 → 704,268 = **311,162** in the attach window.
- Phase 3 control (park, no pending event): **55**.
- Phase 4 (pre-init `sc_eintrs=0` on live driver + one port event):
  sustained **~33K/s**, load 3.6 and climbing, never recovers until the
  softc is restored (then stops dead: 1,603,736 → 1,605,667 ≈ tail only).

## Fix (fix.diff, validated)

Quiesce the controller's interrupt state *before* `bus_setup_intr()`:
read CAPLENGTH (absolute, valid pre-init), write USBINTR=0 and
acknowledge-all (USBSTS=0xFFFFFFFF). Patched kernel: same Phase-2 trigger
produces a **control-sized** delta and USB still enumerates normally.

## Threat model

Malicious/compromised EHCI silicon or emulated controller, or BIOS/SMM
residue at ownership handoff. Not reachable by an unprivileged local user
through this file (boot/kldload-time state; /dev/usb nodes are
operator/root). Impact class matches the file's known findings DF-1092 /
DF-2335 (Low, hardware-preconditioned kernel DoS).
