Files
danos/docs/device-driver-development/devices-csv.md
T
Daniel Samson bf0595763e docs: flip stale status markers across the tracks (audit found 23)
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.
2026-08-09 22:04:17 +01:00

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.)

  1. Create system/drivers/<name>/ with the driver source plus a ~15-line package build.zig + build.zig.zon (copy an existing driver package, e.g. system/drivers/pci-bus/; per-driver extras go through build_support.programModule). Then bundle it at /system/drivers/<name>: one dependency + one bundled entry in the root build.zig, one line in the root build.zig.zon.
  2. Add a row to system/configuration/devices.csv naming the identity it binds and its full path.

No device-manager change is required — the registry is the seam.