Turn acpi-ids.zig's flat name table into a HardwareId enum modeled on
ps2-library's Port: one entry() switch holds the registry (variant ->
_HID string + human-readable name), with hid(), description(), and
fromHid() methods. The free description(hid) lookup the kernel's
device-tree dump uses survives, implemented over the enum, and a new
test round-trips every variant through fromHid.
Callers now name the device instead of quoting its id:
- ps2-library's DeviceType.hid() and ps2-bus's descriptor lookups use
HardwareId.ps2_keyboard / .ps2_mouse.
- device-manager's driverFor parses the HID once with fromHid and
switches on named values.
- acpi.zig's isPciRootNode carried the same ids twice, as strings and
as packed-EISA integers (0x030AD041/0x080AD041); both branches now
decode to the string form and answer through one isPciRootHid helper
using .pci_bus / .pci_express_root_bridge.
- build.zig threads the acpi-ids module (previously kernel-only) into
every user binary, like xkeyboard-config.
process_enumerate snapshots the task table (the device_enumerate shape, so
ps is a user program); system_spawn returns the child id, records the caller
as supervisor, and takes an exit endpoint; process_kill is allowed only for
the supervisor. Every death — exit, fault, or kill — posts a child-exit badge
to that endpoint (the IRQ-as-IPC pattern as SIGCHLD). A target caught off-CPU
is reaped in place; a running one is condemned and finished at its next
system call or tick, guarded so teardown never lands mid-kernel-operation.
Tested by process-list, process-kill, and supervision (a ring-3 supervisor
exercising the whole surface); design notes in docs/process-management.md.
Add a `system_spawn(name)` system call: the kernel loads a binary bundled in the
initial-ramdisk, by name, as a fresh ring-3 process. It's the mechanism a user-space
supervisor needs — discovery and policy stay in user space, the kernel only spawns.
The kernel already holds the initial-ramdisk image from the boot handoff; it now
stashes it (process.setInitialRamdisk) so the handler can resolve names, bounds-checks
the name into the user half like debug_write, and returns -1 for an unknown name or a
load failure. Ungated for now (any process may spawn any bundled binary); a spawn
capability belongs here once the model grows one.
The device manager stops logging "would spawn it" and calls runtime.system.spawn on
its matched driver. On QEMU it discovers the HPET, matches `hpet`, and spawns it — and
the driver comes all the way up (claims the timer, maps its MMIO, binds and services
its IRQ, prints "hpet: ok"). The device-manager test now keys on that final marker:
since only the manager is spawned, `hpet: ok` appearing proves the whole
discover -> match -> system_spawn -> driver-up chain end to end.
Transitional: the kernel still auto-spawns the whole initial-ramdisk at boot, so a
real boot briefly double-spawns hpet (the second claim fails harmlessly). Increment 3
removes that redundancy so the manager is the sole owner of driver spawning. Suite
36/36 plus host tests.
The device manager is the ring-3 process that turns the device tree into a running
system — the udev-analog. It is mechanism-vs-policy done right: the kernel
enumerates the hardware and enforces the claim capability; this decides which
driver serves which device, using no special privilege (the same device_enumerate
any process could call).
This first increment does the discovery + matching half: system/services/
device-manager enumerates /system/devices, matches each device to a driver by
class (a small static policy table), and logs the decision — finding the HPET
(a timer) and deciding `hpet` serves it. It does not spawn yet: spawning needs a
`system_spawn` system call (the kernel spawns every initial-ramdisk binary in a
loop today), which is the next increment. New `device-manager` test; suite 36/36
plus host tests.