diff --git a/docs/os-development/device-authority.md b/docs/os-development/device-authority.md index f6f7c55..926b03d 100644 --- a/docs/os-development/device-authority.md +++ b/docs/os-development/device-authority.md @@ -64,27 +64,46 @@ The kernel therefore does not need to know about matching, `devices.csv`, driver or why a device was assigned. It needs to know that an authority it can verify granted this device to this task. -## The awkward fact that decides the mechanism +## Only drivers hold devices -Five of the six claimants are device-manager children, spawned with their device id in -`argv[1]`: `pci-bus`, `usb-xhci-bus`, `ps2-bus`, `virtio-gpu`, `acpi`. +The layering the rest of the system already follows: -**`display` is not.** It is spawned by `init` from `init.csv`, and it finds its device by -enumerating the table for a display-class node and claiming whatever it finds -([backend.zig](../../system/services/display/backend.zig)). There is no assignment to -enforce, because nobody assigned it anything. +- A **driver** talks to hardware. It is the only thing that holds a device. +- A **service** talks to no hardware at all. It receives device events and sends data + and commands over a **protocol**. +- A **protocol** is the abstraction between them — the OS layer, in the sense of + [communication.md](communication.md). -That rules out the cheapest design. "The kernel records the device named at spawn, and -`device_claim` checks it" closes the hole for five claimants and breaks the sixth. And -the sixth is not an oddity to special-case — it is the one that shows the model is -wrong: authority should be *delegable*, not welded to the moment of spawn. +So the question "which services need device grants" has the answer **none**. That +collapses the design: every holder of a device is a driver, and every driver is spawned +by the device manager, which is what grants it. -It is also what tempted an earlier draft of this document into giving `init` the root -grants, since `init` is what starts `display`. That was wrong for a plainer reason: -`init` has nothing to do with devices. It is the first process and it starts the rest of -the system; the device manager is what owns hardware. Under delegation `display` simply -asks the manager, like every other driver, and the exception disappears rather than -being accommodated. +`display` already demonstrates both halves, one right and one wrong +([backend.zig](../../system/services/display/backend.zig)): + +| Backend | How it reaches the panel | +|---|---| +| `VirtioGpu` | speaks `scanout-protocol` over an IPC handle; touches no device | +| `Gop` | `device.enumerate`, `device.claim`, `device.mmioMap` | + +The virtio-gpu path is the intended shape and it works today: the driver holds the +hardware, the service speaks a protocol to it. **The GOP path is the anomaly** — the +display service reaching into hardware itself, because the firmware framebuffer has no +driver for it to talk to. + +It is also the only anomaly. Every other claimant — `pci-bus`, `usb-xhci-bus`, +`ps2-bus`, `virtio-gpu`, `acpi` — is a device-manager child spawned with its device id +in `argv[1]`. + +**A firmware-framebuffer driver is therefore a prerequisite of this phase**, not a +consequence of it. It is small: it holds the display device, maps the framebuffer, and +serves `scanout-protocol` — the same interface `virtio-gpu` already serves, so the +compositor needs no new code path and stops caring which is behind it, which it was +designed for. + +An earlier draft of this document had `display` asking the device manager for a grant, +and before that had `init` minting grants because `init` starts `display`. Both were +accommodating an exception instead of removing it. ## The design @@ -115,10 +134,10 @@ device manager the same way it starts everything else, and knows nothing about d `init` attests the services it spawned for `/protocol` (`supervisorSatisfies`); it knows which task is which driver because it spawned them. -3. **`display` asks the manager too.** It is started by `init` as a service, but the - framebuffer is a device, so it receives that grant from the device manager like any - other driver. One authority for hardware, not two — which is what makes `display` - stop being the exception that broke the simpler design. +3. **Services receive nothing.** `display`, `input`, `fat` and `logger` hold no devices + and need no grants; they speak protocols to the drivers that do. The one place this + is not true today is the GOP backend above, which a firmware-framebuffer driver + removes. 4. **Use.** `mmio_map`, `irq_bind`, `msi_bind`, `io_read`/`io_write` and `dma_bind` check possession of the grant instead of consulting an ownership table. @@ -137,13 +156,16 @@ own comment says "Claim the bridge, map the ECAM, hello the manager, then scan." delegation the hello must come first, because that is where the grant arrives. Five drivers need that reordering, and it is the bulk of the work. -**`display` gains a dependency on the device manager.** It currently finds its -framebuffer by itself and needs nothing from anyone; afterwards it must ask. That is a -new ordering constraint at boot — `display` cannot bring up a screen until the manager -is up — and it is the honest price of there being one authority for hardware. Mitigating: -`display` already tolerates arriving before its backend (the virtio-gpu driver hands it -a scanout later, over `attach_scanout`), so the machinery for "wait, then attach" is -there. +**A firmware-framebuffer driver has to be written first**, and until it exists the +display service cannot stop claiming a device. It is the smallest new binary in the +tree — hold the display node, map the framebuffer, serve `scanout-protocol` — but it is +new code on the boot path, and the boot path is where a mistake costs a screen. + +It brings an ordering constraint with it: `display` cannot paint until that driver is +up, where today it maps the framebuffer itself and is independent. Mitigating, +`display` already tolerates a backend arriving late — `virtio-gpu` hands it a scanout +after the fact over `attach_scanout` — so "wait, then attach" is a path that already +works rather than one to invent. **The kernel gains one piece of knowledge about a specific binary.** Chain attestation means the kernel recognises `/system/services/device-manager` under PID 1 as the root