Sixty-five headers sat side by side in include/, so `#include "irq.h"` said nothing about where irq.h was or what it belonged to, and errno.h, stat.h and fcntl.h at the top shadowed the system's for any host tool built with -I./include. They are in folders now -- arch/ core/ fs/ dev/ gfx/ net/ uapi/ (and ldls/ for the Linux driver layer) -- and every include names the folder, as Linux's do: "core/proc.h". Done mechanically and checked the hard way: the kernel built from this tree disassembles identically to the one built from the tree before it. The full image boots, and userland is the same set of programs. Paths in docs and comments follow; docs/guides/layout.md has a table of what is where, and tools/fix-includes.py rewrites old-style includes from the folders in the tree, for code written before this. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01S1giNvrHTrPMPw7V6x1kQ4
3.5 KiB
3.5 KiB
| name | description | metadata | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|
| schunix-driver-infrastructure | Dynamic IRQ registration, a DMA arena and PCI capabilities exist now; PCI interrupts are level/active-low and the old ioapicenable only did edge/high |
|
Built 2026-08-04, before USB, because xHCI, any NIC and virtio-gpu all need the same three things and none of them existed.
kernel/dev/irq.c+include/core/irq.h—irq_register(irq, fn, arg, name, level_low).trap.cused to be a switch listing every interrupt by name, which cannot work for a PCI device: its line comes out of config space at probe time, so there is no constant to write acaselabel for. Chains of up to 4 handlers per line, because PCI INTx pins are shared and a handler must recognise that its own device is idle and return. Registration publishes an entry then bumpsnwith a barrier, so dispatch needs no lock./proc/interrupts(minor 12) shows counts and trigger mode.kernel/core/dma.c+include/core/dma.h—dma_alloc(size, align)/dma_free(p, size)(Linux's contract: caller remembers the size). Carved off the top of physical memory inmain.cbeforekinit1, because kalloc's free list makes no contiguity promise. x86 PCI is cache coherent so no PAT games are needed — but ordering is still your problem.pci_find_cap()andpci_msi_enable()inkernel/dev/pci.c.
Four traps worth remembering:
- PCI interrupts are level-triggered, active low.
ioapicenable()hardcoded edge/active-high, which is right for every ISA-era device and wrong for every PCI one — and it fails silently: you get exactly one interrupt, then the device holds the line asserted, no further edge ever comes, and it is never heard from again.ioapicroute(irq, cpu, level_low)is the real call now. IRQ_ERROR(19) andIRQ_SPURIOUS(31) are LAPIC vectors that xv6 numbered as if they were IOAPIC pins, soT_IRQ0+19is already taken. A PCI device routed to pin 19 would collide.irq_registerrefuses them.cprintfhas no field widths.%04xis not a directive to it: it prints%and0literally, consumes no argument, and every argument after it lands in the wrong place. It understands only%d %u %l %x %p %b %s %%.- Unaligned MMIO reads return garbage. Reading a uint32 at BAR offset 2 to get xHCI's HCIVERSION returned zero. Read the aligned dword and shift.
- Never let a device raise an interrupt before its line is claimed. This
one cost real time. xHCI transfers completed, completion events sat in the
event ring,
USBSTS.EINTandIMAN.IPwere both set -- and the interrupt count stayed at zero. Cause: the controller asserted INTx during enumeration, while the IOAPIC entry was still masked. An interrupt that arrives at a masked pin is dropped, not deferred (the 82093AA manual says so, and QEMU implements it), and INTx is a level -- so the line then sits high forever with no further transition for anyone to notice. Unmasking afterwards finds nothing pending. The fix is ordering: enumerate with controller interrupts off, thenirq_register, then clear the device's pending status so it drives the line low, and only then enable. The next event is a genuine low-to-high transition.
Verify with pwsh -File tools/bootcheck.ps1 -Usb. See schunix-usb-xhci,
schunix-pci-drivers.