docs: document the supervision hierarchy and driver discovery
drivers.md gains a "How a driver gets started" section — the doc explained what a running driver does but never who starts it. It lays out the three-level supervision hierarchy (kernel spawns init; init spawns the services; the device-manager discovers, matches, and spawns the drivers) and names the two user-space policies that "configure" drivers today: init's service list and the device-manager's match table. driver-model.md's "what exists today" adds system_spawn and the supervision model, and the drivers.md restart bullet is refreshed: a spawning supervisor now exists, a restarting one still doesn't.
This commit is contained in:
@@ -132,9 +132,15 @@ If a class driver needs `mmio`, it has become an HCD and should be one.
|
|||||||
- **M11** — `irq_bind` / `irq_ack`. IRQ delivered as an IPC notification; mask before
|
- **M11** — `irq_bind` / `irq_ack`. IRQ delivered as an IPC notification; mask before
|
||||||
EOI; `irq_ack` is the unmask.
|
EOI; `irq_ack` is the unmask.
|
||||||
- **M12** — `parent` in `DeviceDesc`, `device_register` with resource containment.
|
- **M12** — `parent` in `DeviceDesc`, `device_register` with resource containment.
|
||||||
|
- **`system_spawn`** — a user-space supervisor starts a driver: `system_spawn(name)`
|
||||||
|
loads a binary bundled in the initial-ramdisk as a fresh ring-3 process. This is what
|
||||||
|
turned the device manager from "log the match" into "run the driver": the kernel now
|
||||||
|
spawns only `init`, `init` spawns the services, and the **device-manager** discovers
|
||||||
|
the hardware and spawns each driver ([drivers.md](drivers.md)). Ungated for now — a
|
||||||
|
spawn capability is future work.
|
||||||
|
|
||||||
So: **bus drivers work now.** HCDs and class drivers do not. Here is exactly why, and
|
So: **bus drivers work now, and they're started by the device manager, not the kernel.**
|
||||||
exactly what would fix it.
|
HCDs and class drivers do not work yet. Here is exactly why, and exactly what would fix it.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
+49
-3
@@ -20,6 +20,49 @@ them for itself:
|
|||||||
A driver is, in one sentence, *a process that sleeps until its device has something to
|
A driver is, in one sentence, *a process that sleeps until its device has something to
|
||||||
say.*
|
say.*
|
||||||
|
|
||||||
|
## How a driver gets started: discover, match, spawn
|
||||||
|
|
||||||
|
Nothing in the kernel decides that the HPET needs the `hpet` driver — that is policy,
|
||||||
|
and policy lives in user space. Boot brings user space up as a three-level supervision
|
||||||
|
hierarchy, each level owning one job:
|
||||||
|
|
||||||
|
```
|
||||||
|
kernel ──spawns──► init (PID 1) ──spawns──► device-manager ──spawns──► hpet
|
||||||
|
| | |
|
||||||
|
spawns only init, the service supervisor: the driver supervisor: enumerates
|
||||||
|
publishes the starts the system /system/devices, matches each device
|
||||||
|
initial-ramdisk services (vfs, the to a driver, and system_spawn's it
|
||||||
|
so user space can device-manager). Its
|
||||||
|
system_spawn from it list is init policy.
|
||||||
|
```
|
||||||
|
|
||||||
|
The kernel launches exactly one process — `init` — and hands it nothing but the raw
|
||||||
|
ability to start more (`system_spawn(name)`, which loads a binary bundled in the
|
||||||
|
initial-ramdisk as a fresh ring-3 process). Everything else is a user-space decision:
|
||||||
|
|
||||||
|
- **init** ([system/services/init](system/services/init/init.zig)) is the **service
|
||||||
|
supervisor**. It spawns the system services danos brings up at boot — today `vfs` and
|
||||||
|
the `device-manager` — from a small list. Drivers are deliberately *not* its job.
|
||||||
|
- **device-manager** ([system/services/device-manager](system/services/device-manager/device-manager.zig))
|
||||||
|
is the **driver supervisor**. It does the three steps a monolithic kernel would do in
|
||||||
|
its probe path, entirely from ring 3:
|
||||||
|
1. **Discover** — `device_enumerate` snapshots the device table the kernel built from
|
||||||
|
ACPI/PCI ([discovery](discovery.md)).
|
||||||
|
2. **Match** — for each device it looks up a driver by `DeviceClass`. The match policy
|
||||||
|
is a table (`driverFor`): today a static `timer → hpet` map; a fuller system reads
|
||||||
|
what each driver *binds* (a manifest under `/system/drivers`, or the driver
|
||||||
|
describing its own match).
|
||||||
|
3. **Spawn** — `system_spawn(driver_name)` starts the matched driver, which then claims
|
||||||
|
its device and runs the event loop below.
|
||||||
|
|
||||||
|
So "how is a driver discovered and configured" has two halves: **discovery** is the
|
||||||
|
kernel's device table, read by anyone; **configuration** is two user-space policies —
|
||||||
|
init's service list and the device-manager's match table. Both are hardcoded in their
|
||||||
|
respective programs today; the natural next step is to move them into `/etc` (see the
|
||||||
|
milestone notes in [driver-model.md](driver-model.md)). `system_spawn` is currently
|
||||||
|
ungated — any process may spawn any bundled binary — because there is no spawn
|
||||||
|
capability yet.
|
||||||
|
|
||||||
## The capability: claim before touch
|
## The capability: claim before touch
|
||||||
|
|
||||||
The driver syscall numbers (`system/abi.zig`) with the device types they carry
|
The driver syscall numbers (`system/abi.zig`) with the device types they carry
|
||||||
@@ -312,9 +355,12 @@ controller drivers), and the IOMMU — have proposed signatures in
|
|||||||
- **Unregistering children.** `device_register` only appends. A USB device that is
|
- **Unregistering children.** `device_register` only appends. A USB device that is
|
||||||
unplugged cannot be removed, and a bus driver in a loop can exhaust the 64-entry
|
unplugged cannot be removed, and a bus driver in a loop can exhaust the 64-entry
|
||||||
table.
|
table.
|
||||||
- **Restart.** A driver that dies should release its claim, have its device quiesced,
|
- **Restart.** A supervisor that *spawns* drivers now exists — the device-manager starts
|
||||||
and be respawned by a supervisor. Some pieces (`releaseIrqs`, `device_grant`
|
them with `system_spawn` — but a supervisor that *restarts* them does not. A driver that
|
||||||
teardown, the claim table) exist; the policy doesn't.
|
dies should release its claim, have its device quiesced, and be respawned; today nothing
|
||||||
|
notices the death. Some pieces (`releaseIrqs`, `device_grant` teardown, the claim table)
|
||||||
|
exist, and `dev_release` (below) is the missing mechanism; the restart policy is the
|
||||||
|
resilience track ([resilience.md](resilience.md)).
|
||||||
- **Interrupt priority / threaded IRQ latency.** `notifyFromIsr` enqueues the woken
|
- **Interrupt priority / threaded IRQ latency.** `notifyFromIsr` enqueues the woken
|
||||||
driver but doesn't preempt (`wakeLocked` deliberately leaves that to the caller), so
|
driver but doesn't preempt (`wakeLocked` deliberately leaves that to the caller), so
|
||||||
a woken driver waits for the next scheduling point.
|
a woken driver waits for the next scheduling point.
|
||||||
|
|||||||
Reference in New Issue
Block a user