⬢ DragonFlyBSD Kernel Audit
DF-4806 / panic.txt
← back to finding ↓ download raw
DF-4806 — clean evidence run (NO diagnostic probes; module = stock ppi.c +
arming.diff = the one-line `RF_ACTIVE` -> `RF_SHAREABLE` irq allocation fix
mirroring lpt.c:385; guest DragonFly 6.5-DEVELOPMENT X86_64_GENERIC, QEMU
PC-style LPT at 0x378 irq 7).

Trigger (root): ./ppi_intr_panic  =  open("/dev/ppi0") [registers ppiintr
with arg=cdev_t], open("/dev/io"), outb(0x37a,0x1c), outb(0x378,0x41),
strobe pulse -- the same sequence QEMU's emulated printer ACKs (8 strobes
=> 8 irq7 deliveries, cf. vmstat -i ppc0 counts in the stock run).

QEMU serial console (dfbsd-qemu/boot.log, 2026-09-24 02:09 UTC):

  ppc0: <Standard parallel printer port> port 0x378-0x37f irq 7 on acpi0
  ppc0: Generic chipset (NIBBLE-only) in COMPATIBLE mode
  ppbus0: <Parallel port bus> on ppc0
  ppi0: <Parallel I/O> on ppbus0
  interrupt uses mplock: ppc0
  sio2: can't drain, serial port might not exist, disabling
  interrupt uses mplock: ppi0

  Fatal trap 12: page fault while in kernel mode
  cpuid = 1; lapic id = 1
  fault virtual address	= 0x0
  fault code		= supervisor read data, page not present
  instruction pointer	= 0x8:0xffffffff82604651
  stack pointer	        = 0x10:0xfffff801187719a0
  frame pointer	        = 0x10:0xfffff801187719d0
  code segment		= base 0x0, limit 0xfffff, type 0x1b
			= DPL 0, pres 1, long 0, def32 0, gran 1
  processor eflags	= interrupt enabled, resume, IOPL = 0
  current process		= Idle
  current thread          = pri 28 (CRIT)
  kernel: type 12 trap, code=0

  CPU1 stopping CPUs: 0x0000003d
   stopped
  Stopped at      ppiintr+0x41:   movq    (%rax),%rsi
  db>

Interpretation:
- "interrupt uses mplock: ppi0": BUS_SETUP_INTR succeeded at ppiopen()
  (ppi.c:266-269) with the shareable resource, registering ppiintr with
  arg = the /dev/ppi0 cdev_t (the only `dev` in scope there, ppi.c:245).
- The first strobe's irq7 invoked ppiintr(cdev); the handler's first use
  of its argument -- ppi_disable_intr(ppidev=(device_t)cdev) ->
  device_get_parent(cdev) reads cdev+0x28 (struct cdev link.tqe_prev) ->
  ppb_rctr(bogus) -> PPBUS_IO(device_get_parent(bogus)) -> movq (%rax)
  with rax=0 -> supervisor read fault at 0x0.
- Trap 12 at interrupt context (current process Idle, pri CRIT) is fatal:
  all CPUs stopped, DDB, guest dead. Instant unrecoverable kernel panic
  from a single open() + one parallel-port interrupt.

Contrast: identical run against the STOCK module (RF_ACTIVE) survives all
strobes (stock_run.log) because the allocation fails -> no handler; and the
FIXED module (RF_SHAREABLE + ppidev arg) survives with interrupts delivered
(fix run logs in this pack).