An all-tracks docs-vs-code audit (the same method that caught the storage drift) found 23 confirmed inaccuracies where a doc's build-status claim no longer matches the source — status markers that were never flipped after a track landed, and a few paths left over from completed flag-days. All verified against the code before editing; docs only, no behavior change. The systemic ones: - IOMMU enforcement (driver-model.md, drivers.md): docs said enforcement was not built and "device_claim = ring 0" / "memory-safe is not true yet". It is built (per-device VT-d/AMD-Vi domains programmed at device_claim, -ECONFINE rollback, dma_alloc buffers bound and torn down at death; fail-open only with no IOMMU). Restated; M16 marker flipped to done. - The FHS flag-day paths: /etc/devices.csv -> /system/configuration/devices.csv (devices-csv.md, new-driver-checklist.md, device-manager.md), /var/log -> /system/logs (logging.md, new-driver-checklist.md), /mnt/usb -> /volumes/usb (process-management.md). Following the old paths silently breaks driver match. - protocol-namespace P4 "remaining" -> landed (only P5 remains); shared-fate fan-out "not yet enforced" -> enforced; wall_clock "not built" -> built; SMP affinity + fault-recovery "left" -> built; process_enumerate raw-pointer trust model -> checked copyToUser/EFAULT; bounds.md maximum_devices static hole -> dynamic per-registrar quota; init spawns fat -> volume-manager; config "hardcoded, move to /etc" -> already CSV data files; vdso.md three- value call; zig-self-hosting library/ layout; python argv "new" -> built. Found and fixed by a multi-agent audit across 12 doc clusters, each finding adversarially verified against the source.
5.6 KiB
/system/configuration/devices.csv — the device registry
Status: built (2026-07-26). The device manager reads /system/configuration/devices.csv at
boot and binds every device a bus driver reports to the driver the registry
names. It replaces the three hand-written switch tables that used to live in
the manager (pciDriverForIdentity, hidDriverFor, usbDriverForIdentity) —
the "manifest" device-manager.md anticipated once code
matching started to hurt. The parser and matcher are the pure, unit-tested
device-registry module (library/device/registry/device-registry.zig).
Why a registry
The switch tables keyed PCI matches on the 24-bit class/subclass/prog-IF triple
alone. That is too coarse: a virtio-gpu is just "display / other" by class, so it
could only be class-matched and the driver had to re-confirm its real
1AF4:1050 identity from config space after the manager had already spawned
it. The registry lets a rule bind on the full identity — down to vendor, device,
and subsystem — so the manager makes the precise decision itself, and the driver
comes up already knowing it is the right one.
It is also data, not code: teaching the system new hardware is a line in a
file, not an edit-and-recompile of the manager. And it is greppable — one
place to read "what binds what," the same idea as Linux's modules.alias.
The file
One rule per line, nine comma-separated fields; # starts a comment (whole-line
or trailing); blank lines are ignored. Whitespace around a field is trimmed, so
columns may be padded for readability.
# bus base class prog_if vendor device subsystem hid driver
pci, 0C, 03, 30, *, *, *, *, /system/drivers/usb-xhci-bus
pci, 03, 00, 00, *, *, *, *, /system/drivers/display
pci, 03, 80, *, 1AF4, 1050, *, *, /system/drivers/virtio-gpu
usb, 03, 01, 01, *, *, *, *, /system/drivers/usb-hid-keyboard
acpi, *, *, *, *, *, *, PNP0303, /system/drivers/ps2-bus
| Field | Meaning | Notes |
|---|---|---|
bus |
pci | usb | acpi |
which bus reported the device; picks the namespace for the id columns |
base |
PCI base class / USB class | hex |
class |
PCI subclass / USB subclass | hex |
prog_if |
PCI prog-IF / USB protocol | hex |
vendor |
PCI vendor / USB idVendor | hex |
device |
PCI device / USB idProduct | hex |
subsystem |
PCI subsystem, (ssvid<<16)|ssid |
hex; blank for usb/acpi |
hid |
ACPI _HID (e.g. PNP0303) |
blank for pci/usb |
driver |
full ramdisk path to spawn | e.g. /system/drivers/virtio-gpu |
* or an empty field is a wildcard — it matches anything and adds nothing to
a rule's specificity.
Levels of detection: most-specific-wins
Several rows may match one device. The manager picks the most specific — the one that pins the finest-grained fields. Specificity weights double from the coarsest level so each outweighs all coarser levels combined:
base(1) < class(2) < prog_if(4) < vendor(8) < subsystem(16) < device(32) ≈ hid(32)
So the generic pci, 03, 00, 00, …/display rule and the precise
pci, 03, 80, *, 1AF4, 1050, …/virtio-gpu rule coexist: the virtio card
(vendor 1AF4, device 1050) takes the specific rule; a plain VGA adapter still
falls to the generic one. Two rules that match a device with the same
specificity are a registry authoring error — the manager logs it loudly and binds
the first, so the shadowed rule is visible rather than silently dropped.
Authoritative — no code fallback
There is no compiled-in default table behind the registry. A device that no row
matches goes unbound and is logged; the manager never guesses. A missing or
empty /system/configuration/devices.csv therefore means nothing matches — which is loud at boot,
not a silent half-working system.
How the manager reads it
/system/configuration/devices.csv is bundled into the initial ramdisk (build.zig's bundled
list). The kernel serves the initrd's /system/configuration tree directly — the fat service is
spawned after the device manager and is irrelevant to /system/configuration — so the manager
reads the file with a plain fs.open("/system/configuration/devices.csv") + read, with no
filesystem service running and no boot-ordering dependency. It parses the bytes
once in initialise, before any bus driver can report a device to match.
Feeding the matcher: the widened report
Finer-grained matching needs identity the old ABI threw away. Two things carry it
now: child_added (and DeviceDescriptor) grew vendor / device /
subsystem fields, filled by the PCI bus driver from config space (offsets
0x00 and 0x2C); and each bus driver states its bus in the report (a BusKind),
so the manager reads a PCI class triple and a USB class triple — the same 24 bits
in different namespaces — against the right bus column.
Adding a driver
(The step-by-step walkthrough with a worked example is new-driver-checklist.md.)
- Create
system/drivers/<name>/with the driver source plus a ~15-line packagebuild.zig+build.zig.zon(copy an existing driver package, e.g.system/drivers/pci-bus/; per-driver extras go throughbuild_support.programModule). Then bundle it at/system/drivers/<name>: one dependency + one bundled entry in the rootbuild.zig, one line in the rootbuild.zig.zon. - Add a row to
system/configuration/devices.csvnaming the identity it binds and its full path.
No device-manager change is required — the registry is the seam.