docs: only drivers hold devices; services speak protocols
The design still had the display service receiving a device grant, which keeps the wrong layering and just moves who hands it over. Drivers talk hardware. Services talk to no hardware at all — they receive device events and send data and commands over a protocol, which is the OS abstraction between them. So the answer to "which services need device grants" is none, and the design collapses: every holder of a device is a driver, and every driver is spawned by the device manager, which is what grants it. No exceptions to accommodate. display already shows both halves. Its VirtioGpu backend speaks scanout-protocol over an IPC handle and touches no device — the driver holds the hardware, the service speaks to it, and it works today. Its Gop backend calls device.enumerate, device.claim and device.mmioMap: the service reaching into hardware itself, because the firmware framebuffer has no driver to talk to. That is the only such case in the tree; every other claimant is a device-manager child spawned with its device id. A firmware-framebuffer driver is therefore a prerequisite of this phase rather than a consequence. It is small — hold the display node, map the framebuffer, serve the same scanout-protocol virtio-gpu already serves — and the compositor needs no new path, since not caring which backend is behind it is what it was designed for. Two earlier drafts are recorded as wrong in the document: display asking the device manager for a grant, and before that init minting grants because init starts display. Both accommodated an exception instead of removing it.
This commit is contained in:
@@ -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
|
or why a device was assigned. It needs to know that an authority it can verify granted
|
||||||
this device to this task.
|
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
|
The layering the rest of the system already follows:
|
||||||
`argv[1]`: `pci-bus`, `usb-xhci-bus`, `ps2-bus`, `virtio-gpu`, `acpi`.
|
|
||||||
|
|
||||||
**`display` is not.** It is spawned by `init` from `init.csv`, and it finds its device by
|
- A **driver** talks to hardware. It is the only thing that holds a device.
|
||||||
enumerating the table for a display-class node and claiming whatever it finds
|
- A **service** talks to no hardware at all. It receives device events and sends data
|
||||||
([backend.zig](../../system/services/display/backend.zig)). There is no assignment to
|
and commands over a **protocol**.
|
||||||
enforce, because nobody assigned it anything.
|
- 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
|
So the question "which services need device grants" has the answer **none**. That
|
||||||
`device_claim` checks it" closes the hole for five claimants and breaks the sixth. And
|
collapses the design: every holder of a device is a driver, and every driver is spawned
|
||||||
the sixth is not an oddity to special-case — it is the one that shows the model is
|
by the device manager, which is what grants it.
|
||||||
wrong: authority should be *delegable*, not welded to the moment of spawn.
|
|
||||||
|
|
||||||
It is also what tempted an earlier draft of this document into giving `init` the root
|
`display` already demonstrates both halves, one right and one wrong
|
||||||
grants, since `init` is what starts `display`. That was wrong for a plainer reason:
|
([backend.zig](../../system/services/display/backend.zig)):
|
||||||
`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
|
| Backend | How it reaches the panel |
|
||||||
asks the manager, like every other driver, and the exception disappears rather than
|
|---|---|
|
||||||
being accommodated.
|
| `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
|
## 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
|
`init` attests the services it spawned for `/protocol` (`supervisorSatisfies`); it
|
||||||
knows which task is which driver because it spawned them.
|
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
|
3. **Services receive nothing.** `display`, `input`, `fat` and `logger` hold no devices
|
||||||
framebuffer is a device, so it receives that grant from the device manager like any
|
and need no grants; they speak protocols to the drivers that do. The one place this
|
||||||
other driver. One authority for hardware, not two — which is what makes `display`
|
is not true today is the GOP backend above, which a firmware-framebuffer driver
|
||||||
stop being the exception that broke the simpler design.
|
removes.
|
||||||
|
|
||||||
4. **Use.** `mmio_map`, `irq_bind`, `msi_bind`, `io_read`/`io_write` and `dma_bind`
|
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.
|
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
|
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.
|
drivers need that reordering, and it is the bulk of the work.
|
||||||
|
|
||||||
**`display` gains a dependency on the device manager.** It currently finds its
|
**A firmware-framebuffer driver has to be written first**, and until it exists the
|
||||||
framebuffer by itself and needs nothing from anyone; afterwards it must ask. That is a
|
display service cannot stop claiming a device. It is the smallest new binary in the
|
||||||
new ordering constraint at boot — `display` cannot bring up a screen until the manager
|
tree — hold the display node, map the framebuffer, serve `scanout-protocol` — but it is
|
||||||
is up — and it is the honest price of there being one authority for hardware. Mitigating:
|
new code on the boot path, and the boot path is where a mistake costs a screen.
|
||||||
`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
|
It brings an ordering constraint with it: `display` cannot paint until that driver is
|
||||||
there.
|
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
|
**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
|
means the kernel recognises `/system/services/device-manager` under PID 1 as the root
|
||||||
|
|||||||
Reference in New Issue
Block a user