# DF-5431 — MADT IOAPIC topology never validated at probe → deterministic `ioapic_add` boot panic

## What

`madt_ioapic_probe()` (acpi_madt.c:638-666) validates only: ≥1 IOAPIC entry,
some entry with `GlobalIrqBase == 0`, non-zero addresses, `Id != 255`.
It never checks that the described GSI ranges are disjoint, that addresses
are unique, or that there are ≤16 IOAPICs. `madt_ioapic_enum_callback`
(acpi_madt.c:722-739) then feeds the raw entries to `ioapic_add()`, which
`panic()`s unconditionally on overlap (ioapic.c:240), duplicate address
(ioapic.c:245), and ioapic_config panics on >16 IOAPICs (ioapic.c:137-138).

## Rig

Identical to ../DF-5430: `hint.acpi.0.rsdp=0x40000000` + QEMU
`-device loader` blob with crafted RSDP→RSDT→MADT.

## Build

    python3 gen_madt.py ioapic_overlap /tmp/madt_ioapic_overlap.bin

## Run

    vm.sh run_root 'printf "hint.acpi.0.rsdp=0x40000000\nboot_verbose=YES\n" >> /boot/loader.conf; sync'
    vm.sh down
    QEMU_EXTRA="-device loader,file=/tmp/madt_ioapic_overlap.bin,addr=0x40000000,force-raw=on" vm.sh up
    vm.sh log

## Expected output (run.log:87-89)

    ACPI MADT: IOAPIC addr 0xfec00000, apic id 0, gsi base 0
    ACPI MADT: IOAPIC addr 0xfec88000, apic id 1, gsi base 0
    panic: ioapic_add: overlapped gsi, base 0 npin 1, hit base 0, npin 24

Trigger table: valid BSP+AP LAPIC entries plus two IO_APIC entries both
declaring GSI base 0 (first at the real QEMU IOAPIC 0xFEC00000, second on
unmapped MMIO whose VER read yields npin=1 — any overlap works).

Sibling findings: DF-1034 (mptable INT panic, Low), DF-5339 family
(probe/enumerate asymmetry). Same firmware-fed boot-time-DoS class.
