# Red Bear OS — `pci-spawner` → `driver-manager` Migration Plan **Document status:** v3.1 canonical planning authority (supersedes v3.0 with the completed P0/LDR/P2 implementation and the operator-ratified cutover: driver-manager now owns the boot path in all `redbear-*` configs; pcid-spawner is gated as the fallback) **Generated:** 2026-07-20 **Toolchain:** Rust nightly-2026-05-24 (edition 2024) **Architecture:** Microkernel OS in Rust (Redox fork) **Cross-reference baseline:** Linux kernel 7.1 at commit `ab9de95c9` (`local/reference/linux-7.1/`), CachyOS (`local/reference/cachyos/` — linux-cachyos `0001-cachyos-base-all.patch` 6.17.9 + desktop ISO 260628) **Assessment:** `local/docs/evidence/driver-manager/ASSESSMENT-2026-07-22.md` (findings B1–G10, § 11 services integration) **v3.1 status update over v3.0 (implementation + cutover round, 2026-07-23):** The v3.0 work program is implemented and the operator has ratified the cutover: **driver-manager owns the boot path in every `redbear-*` config; pcid-spawner is retired from configs and gated behind `/etc/driver-manager.d/disabled` as the operator fallback (never deleted).** Future OS development is based on driver-manager. Completed items: - **P0-1 ✅ Claim-via-channel collapse.** `probe()` does a single `PciFunctionHandle::connect_by_path()`; `ENOLCK` → next candidate; `enable_device` + `into_inner_fd` → `PCID_CLIENT_CHANNEL`. `claim_pci_device`/`open_pcid_channel` deleted; `SpawnedDriver` holds the channel fd (claim lifetime == child lifetime). - **P0-2 ✅ Orphan patches resolved.** bind-scheme + uevent-fix moved to `local/patches/legacy-superseded-2026-07-22/` with a SUPERSEDED.md audit entry; aer-scheme retained as the P2-1 producer blueprint. - **P0-3 ✅ Advisory theater stripped.** `modern_tech.rs` and `exec.rs` deleted; the useful parts correctly wired as spawn env hints (`REDBEAR_DRIVER_IOMMU_GROUP` / `REDBEAR_DRIVER_NUMA_NODE` / `REDBEAR_DRIVER_MSIX_VECTORS`); redox-driver-core C/P-state coordinators removed (no consumers). - **LDR-2 ✅ Spawned-mode `pci_register_driver`.** linux-kpi honors `PCID_CLIENT_CHANNEL` (probe only the granted device; never enumerate). Standalone mode retained for CLI tools. - **LDR-3 ✅ iwlwifi onboarded.** `--daemon` mode (honors `PCID_DEVICE_PATH`, full-init, resident) + `70-wifi.toml` staged; `--import-linux-ids` wires linux_loader into production (Linux `id_table` → `[[driver.match]]` TOML). - **LDR-4 ✅ Verified convergent.** redox-drm already honors the pcid handoff; no changes needed. - **LDR-5 ✅ linux-kpi API completion.** Real MSI/MSI-X via pcid_interface (vector allocation + table programming; linux-kpi owns the channel in linux-kpi daemons), `pci_request_regions`, `pcie_capability_read/write_*`, `pci_set_power_state` / `pci_save_state` / `pci_restore_state`. C header synced. - **P2-2 ✅ Operator surface.** Scheme endpoints `bind`, `unbind`, `new_id`, `remove_id`, `driver_override`, `rescan`; DeviceManager gained Tier-1 `driver_override` precedence + `bind_device`. - **P2-3 ✅ Success trigger.** A successful bind immediately retries deferred probes (Linux `driver_deferred_probe_trigger`), in `run_enumeration` and the scheme bind handler. - **Cutover ✅.** init learned `ConditionPathExists` (with `!` negation — the C0 dormancy was a parser-rejection accident); driver-manager services run by default in init.d/init.initfs.d and all `redbear-*` configs; pcid-spawner services gated to `/etc/driver-manager.d/disabled`. `make lint-config` clean. - **Services integration ✅ (assessment § 11).** driver-params bridge verified live; udev-shim driver-binding view noted as a P3 gap; D-Bus correctly absent (bridge-on-demand pattern documented). Open items (unchanged): **P0-4** QEMU runtime gate (build running; first boot with driver-manager owning the path), **P2-1** pcid producers (AER registers, pciehp slot events), **P3** policy/hygiene (quirk phases, AER recovery actions, per-vendor firmware packaging, udev-shim driver-binding view, dep-crate warnings, stale-tree cleanup). **v3.0 status update over v2.2 (the assessment round):** v3.0 records the first *runtime-grade* audit of the migration. Three parallel codebase audits (pcid layer, linux-kpi binding model, Linux 7.1 PCI core) plus a full first-hand review of every driver-manager source file found that the v1.3–v2.2 "Done" claims were compile-grade, and that three of them are **broken at runtime**. The full evidence register (B1–G10) is in the assessment doc; the corrections and the resulting work program follow. **Corrections to earlier rounds (stale claims removed):** 1. **The `/bind` claim endpoint does not exist.** Earlier rounds marked "D1 C4 BAR request ✅ Done — `claim_pci_device` via `/bind`" (and the § diagram "claims devices via `/bind`"). pcid exposes only `channel` and `config` per device; the patches that would add `/bind` (`local/patches/base/P3-pcid-bind-scheme.patch`, `P3-pcid-aer-scheme.patch`, `P3-pcid-uevent-format-fix.patch`) are orphaned — never committed to `submodule/base`, and the cookbook does not apply patches for `path =` fork recipes. At runtime, every probe would fail `ENOENT` and defer-retry forever, binding nothing. **Resolution: P0-1 below — the separate claim endpoint is dropped in favor of pcid's existing channel exclusivity (`ENOLCK`), the model pcid-spawner has always used.** The orphaned patches are resolved per the orphan-patch decision tree (bind-scheme: SUPERSEDED by the channel model; aer-scheme: kept as the P2-1 producer blueprint). 2. **The pciehp and AER listeners are inert.** v1.9/v2.0 marked them done; in fact nothing in the tree produces `/scheme/pci/pciehp` or `/scheme/acpi/aer`, and both readers fail-soft on missing files. Device add/remove is covered by the 250 ms hotplug enumeration poll (which works). The listeners are restated as *parsers ready, producers pending* (P2-1). 3. **`exclusive_with` is not "the CachyOS pattern."** CachyOS solves two-drivers-one-device by *probe-time* deferral (its 6.17.9 patch makes ahci return `-ENODEV` on remapped-NVMe controllers so `intel-nvme-remap` binds instead) and by *userspace* modprobe.d blacklists. Match-time `exclusive_with` is a third, complementary mechanism — a superset, retained. The plan text is corrected. 4. **`modern_tech` "wired" was advisory theater.** Bind/unbind emit hardcoded C/P-state constants into JSON files nothing reads, and the MSI-X proposal is computed at spawn and discarded. P0-3 strips it to the honest core. 5. **"8 QEMU-functional test scripts" was aspirational.** The scripts exist; no driver-manager QEMU boot has ever been run. Runtime validation is now a hard gate (P0-4) and the D5 audit grades capabilities *runtime* as well as *compile*. **v3.0 work program (the tracks):** | Track | Items | Goal | |---|---|---| | **P0 — Correctness blockers** | P0-1 claim-via-channel collapse · P0-2 restate pciehp/AER + resolve orphaned patches · P0-3 strip modern_tech + delete exec.rs · P0-4 runtime validation gate (QEMU) | Make the existing D-phase true at runtime | | **LDR — Linux-Driver-Reuse** | LDR-1 unified claim model · LDR-2 spawned-mode `pci_register_driver` · LDR-3 iwlwifi onboarding · LDR-4 amdgpu path convergence · LDR-5 linux-kpi API completion | The critical goal: reuse Linux drivers | | **P2 — Operator & event surface** | P2-1 pcid producers (AER registers, pciehp slot events) · P2-2 scheme write endpoints (`bind`/`unbind`/`new_id`/`remove_id`/`driver_override`/`rescan`) · P2-3 trigger-based deferred retry | Linux-grade operability | | **P3 — Policy & hygiene** | quirk pass phases (early/runtime) · AER recovery actions (`pci_ers_result` mapping) · per-vendor firmware packaging · dep-crate warnings + stale-tree cleanup | Long-term evolution | **P0 — Correctness blockers (preconditions for everything else):** - **P0-1 Collapse claim into the channel open.** Replace `claim_pci_device()` + `open_pcid_channel()` with a single `PciFunctionHandle::connect_by_path()`: `ENOLCK` → "already claimed → next candidate" (mirrors Linux's probe-time `-EBUSY`/`-ENODEV` handoff), then `enable_device()` and `into_inner_fd()` → `PCID_CLIENT_CHANNEL`. Claim lifetime == channel fd lifetime == child lifetime — exactly correct, pcid-spawner-proven, zero pcid fork changes. The exclusive_with check moves *after* the channel open (claim-then-check, as in v2.1–v2.2, with close-on-defer). - **P0-2 Restate pciehp/AER; resolve orphaned patches.** Plan text corrected above. `P3-pcid-bind-scheme.patch` → SUPERSEDED (channel model); `P3-pcid-aer-scheme.patch` → retained as the P2-1 producer blueprint; `P3-pcid-uevent-format-fix.patch` → split: AER parts with the producer work, uevent stub dropped (polling is the accepted v1 model). Move superseded files per the orphan-patch decision tree. - **P0-3 Strip modern_tech to the honest core; delete exec.rs.** Remove the constant C/P-state JSON writers (no consumers); pass the MSI-X proposal to the child as `REDBEAR_DRIVER_MSIX_VECTORS=` (same env-hint channel as the quirk hints) or drop it until a consumer exists. Delete `exec.rs` (dead `spawn_driver` with `#[allow(dead_code)]`). - **P0-4 Runtime validation gate.** Boot `redbear-mini` in QEMU with driver-manager enabled in place of pcid-spawner (C-phase dry run): e1000 binds through the real claim path, `/bound` reports it, heartbeat counters move, deferred drivers retry and bind. Until this passes, no capability is "Done" — the D5 audit gains a Runtime column. **LDR — Linux-Driver-Reuse track (the critical goal):** *One ownership model:* driver-manager owns enumeration, matching, policy, claiming, and spawning for **native and Linux-port daemons alike**; linux-kpi is the in-process Linux API surface *inside* the spawned daemon, never a second enumerator. - **LDR-1 Unified claim model.** All device binding flows through driver-manager's match→claim→spawn. linux-kpi never opens `/scheme/pci/` for binding decisions. - **LDR-2 Spawned-mode `pci_register_driver`.** When `PCID_CLIENT_CHANNEL` is present, linux-kpi skips enumeration, wraps the granted channel, matches only the device it was spawned for, and calls the C probe for exactly that device. Standalone self-enumeration mode remains for CLI tools. This eliminates the double-claim risk class (assessment B2). - **LDR-3 redbear-iwlwifi onboarding.** Generate its driver-manager TOML from the iwlwifi `id_table` via `linux_loader` (un-`cfg(test)` the pipeline: `linux_loader → TOML → /lib/drivers.d/`); spawn it as a daemon under the unified claim; retire its manual `/scheme/pci/` scanning CLI path for the auto-bind case. - **LDR-4 amdgpu path convergence.** Keep redox-drm as the spawned daemon (its FFI into `libamdgpu_dc_redox.so` is legitimate in-process composition, not a second claim system — but its PCI open must go through the granted channel, not `PciDevice::open_location` on its own enumeration). - **LDR-5 linux-kpi API completion (priority order).** (a) real MSI/MSI-X via `pcid_interface::enable_feature` (replace synthetic `allocate_vectors`); (b) `pci_request_regions`/`pci_release_regions` as BAR-mapping claims over the channel; (c) `pcie_capability_read/ write_*` via channel config R/W (exists in pcid_interface); (d) power state (`pci_save_state`/`restore_state`/`set_power_state` via PMCSR); (e) `pci_reset_function` (FLR) if pcid grows the hook. **P2 — Operator & event surface:** - **P2-1 pcid producers.** Per-device AER register files from the retained aer-scheme blueprint; pciehp slot-status events (the five hardware-defined bits ABP/PFD/PDC/DLLSC/CC) produced by pcid polling the slot status register. - **P2-2 Scheme write endpoints.** `/bind`, `/unbind`, `/new_id`, `/remove_id`, `/driver_override`, `/rescan` on the driver-manager scheme — the Linux sysfs operator surface, scheme-shaped. dynids are already implemented in redox-driver-core; this exposes them. `driver_override` adds Linux's Tier-1 match precedence. - **P2-3 Trigger-based deferred retry.** Retry deferred probes on (a) any successful bind (mirrors `driver_deferred_probe_trigger`), (b) dependency-scheme arrival (watch `/scheme/` for the named scheme in "dependency scheme not ready" deferrals), (c) firmware-loader readiness for `NEED_FIRMWARE` deferrals. Blind 250 ms polling becomes the fallback, not the mechanism. **P3 — Policy & hygiene:** quirk pass phases (early pre-BAR vs runtime — Linux has 8 `pci_fixup_pass` phases; we need at least the early/runtime split for pre-BAR quirks); AER recovery actions wired to drivers (`pci_ers_result` 6-state mapping over scheme IPC); per-vendor firmware packaging mirroring linux-firmware splits; dependency-crate warnings (libredox, pcid `Option::insert`, redox-driver-sys `Once`/`vendor`); remove the stale `local/recipes/drivers/redox-driver-core/src/` duplicate tree (live tree is `source/src/`); fold the concurrent path's double bus enumeration into one pass. **v2.2 status update over v2.1:** v2.2 records the ninth round of D-phase work, fixing defects found by the first full `x86_64-unknown-redox` compile of the v2.1 tree and by a dead-code/warning sweep: - **Concurrent probe path is now real** (`redox-driver-core`). The `ConcurrentDeviceManager` previously returned a synthetic `ProbeResult::Bound` from `run_probe` without ever calling `Driver::probe()` — on any bus with ≥ 4 unbound devices (the production `max_concurrent_probes = 4` config) this reported bindings with no driver spawned and bypassed `exclusive_with`, quirks, and the blacklist. `DeviceManager` now stores drivers as `Arc`; concurrent jobs carry priority-ordered candidate lists (static match table **and** dynids); workers invoke the real `probe()` with serial-equivalent per-device semantics (Bound → claim + record, Deferred → enqueue, Fatal → stop, NotSupported → next candidate) and apply bound/deferred state in the worker. Three new tests cover real probe invocation, candidate fallback, and deferred enqueue. - **Redox-target build errors fixed** (`driver-manager`). `SchemeSync::write` now matches the redox-scheme trait (`buf: &[u8]`); the `/modalias` write stores the looked-up driver name per-handle and a subsequent read returns it. `O_WRONLY`/`O_RDWR` come from `syscall::flag` (usize) instead of `libc` (i32). - **Double-claim bug fixed.** `probe()` claimed the PCI device twice (once before the `exclusive_with` check, once before spawn); since pcid binds are exclusive, the second claim would always fail `EALREADY` on real hardware and no device would ever bind. The probe now claims once and threads the same handle through to spawn. - **Driver registry wired.** `set_registered_drivers()` is now called at startup — previously the registry stayed empty, making the `exclusive_with` check and the `/modalias` lookup silent no-ops. - **Real signal handlers.** `SIGCHLD` and `SIGHUP` handlers are now actually installed via `libc::signal` inside `spawn_reaper_thread` / `spawn_reload_worker`. The previous `install_handler` / `install_sighup_handler` bodies were empty placeholders, so the reaper and the blacklist reload never fired in production. - **Heartbeat counters wired.** `record_bound` / `record_spawned` / `record_deferred` / `record_on_error` are called from the enumerate path; `record_bound` / `record_unbound` from the hotplug loop. The heartbeat JSON no longer publishes permanent zeros. - **AER routing wired.** The unified event listener calls `route_to_driver` per AER event against a live bound-device snapshot (new `bound_device_pairs()` scheme accessor) and logs the decided `RecoveryAction`. - **Dead code removed or test-gated.** The superseded standalone pciehp/AER listener threads, the single-variant `ProbeOutcome` enum, `SharedBlacklist::len`/`snapshot`, the placeholder install functions, the heartbeat `cv`/`stop` machinery, and `set_reload_flag` are gone; `end_to_end_test`, `linux_loader`, `set_reap_flag`, `compute_modalias`, and `policy::SharedBlacklist::snapshot` are `#[cfg(test)]`-gated; `compute_match_modalias` / `lookup_modalias` are `#[cfg(any(target_os = "redox", test))]` (their only production caller is the redox-only scheme server). - **Zero warnings.** `driver-manager` compiles warning-free on the host and on the `x86_64-unknown-redox` target (remaining warnings are pre-existing in dependency crates: libredox, pcid, redox-driver-sys). **v2.2 test totals:** 56 driver-manager + 33 redox-driver-core lib + 5 dynid integration = 94 tests, all passing. `repo cook driver-manager` succeeds for `x86_64-unknown-redox` with zero crate-local warnings. **§ 0.5 audit gate at v2.2:** 0 violations. **v1.4 status update over v1.3:** v1.4 records the second round of D-phase work: the policy loader is now active (the `redbear-driver-policy` package now actually changes `spawn_decision_gate` behavior at runtime), the `--concurrent=N` CLI flag enables the SMP worker pool, the two C0 service files have been committed in the `local/sources/base` submodule, and the unused `modern_tech` orchestrator was removed (the `redox_driver_core::modern_technology` helpers remain as a library for downstream consumers to integrate when they exist). The § 0.5 audit gate still reports **0 violations across 34 files**. PciQuirkFlags is now wired into the actual driver spawn (the `REDBEAR_DRIVER_PCI_IRQ_MODE=intx_or_msi` and `REDBEAR_DRIVER_DISABLE_ACCEL=1` env vars are passed to the spawned child when the corresponding flags are set). | Item | Status at v1.4 | Where | |---|---|---| | § 5.1 D0 foundation verified | ✅ Done | `cargo test` 33+3+16 = 52 tests passing | | § 5.1 D1 C1 capability (`add_dynid`/`remove_dynid`) | ✅ Done | `redox-driver-core/src/{dynid,manager}.rs` | | § 5.1 D1 C2 capability (`Driver::remove` + WAIT_FOR_REAPPEAR) | ✅ Done | `driver-manager/src/config.rs` (real SIGTERM+SIGKILL) | | § 5.1 D1 C3, C6 (enable_device / set_bus_master) | ✅ Done | `open_pcid_channel` via `pcid_interface::EnableDevice` | | § 5.1 D1 C4 (BAR request) | 🟡 Corrected at v3.0 | `/bind` never existed in pcid (see v3.0 correction 1); claim collapses into channel exclusivity per P0-1 | | § 5.1 D1 C5, C7, C8, C12, C16, C17 (child-side) | ✅ Done | pre-existing driver daemons | | § 5.1 D1 format coexistence | ✅ Done | `convert_legacy` function in config.rs | | § 5.1 D1 SpawnDecision committee | ✅ Done | `spawn_decision_gate()` function | | § 5.1 D1 policy blacklist | ✅ Done at v1.4 | `policy::Blacklist::load_dir()` + `blacklist_match()` consult at probe | | § 5.2 D2.1 SMP concurrent probe | ✅ Done | `redox-driver-core/src/concurrent.rs` (worker pool) | | § 5.2 D2.2 C-state / P-state advisors | ✅ Library only at v1.4 | `redox-driver-core/src/modern_technology.rs` (orchestrator removed) | | § 5.2 D2.3 IOMMU + MSI-X + NUMA helpers | ✅ Library only at v1.4 | same module (combined surface) | | § 5.2 D2.4 runtime PM hooks (suspend/resume) | ✅ Done | `Driver::suspend`/`resume` trait + `signal_then_collect` | | § 5.2 D2.5 AER foundation (on_error) | ✅ Done | `Driver::on_error` + `ErrorSeverity` + `RecoveryAction` | | § 5.2 D2.6 PciQuirkFlags integration (D4) | ✅ Done at v1.4 | `driver-manager/src/quirks.rs` (redox-driver-sys dep) + spawn-time env vars | | § 5.2 D3 event-driven hotplug (polling fallback) | ✅ Done | hotplug poll reduced to 250ms; pcid event delivery is the next step | | § 5.2 D4 audit-no-stubs.py + 8 test scripts | ✅ Done | 0 violations across 34 files | | § 5.2 D4 redbear-driver-policy package | ✅ Done | `local/recipes/system/redbear-driver-policy/` | | § 5.2 D4 --concurrent=N CLI flag | ✅ Done at v1.4 | `main.rs` parses arg, calls `ConcurrentDeviceManager::enumerate(cap)` | | § 5.2 D5 audit document | ✅ Done | `local/docs/evidence/driver-manager/D5-AUDIT.md` | | § 5.2 C0 dormant service files | ✅ Committed at v1.4 | `local/sources/base` submodule (commit `0407d9cc`) | | **Operator ratification** | 🔴 Not yet | required before C1 begins | **v1.4 test totals:** 52 tests across the three crates, all passing. **§ 0.5 audit gate at v1.4:** 0 violations across 34 scanned files. **v1.3 status update over v1.2:** v1.3 records the **full D-phase implementation**: every D1–D4 deliverable in the § 5.1 D-phase is now in source. The § 0.5 comprehensive-implementation audit gate (`local/scripts/driver-manager-audit-no-stubs.py`) returns **zero violations across 34 files**. The § 0.6 parallel-development constraint is preserved — the migration is fully implemented but driver-manager remains excluded from any boot path until operator ratification. See `local/docs/evidence/driver-manager/D5-AUDIT.md` for capability-by-capability status. | Item | Status at v1.3 | Where | |---|---|---| | § 5.1 D0 foundation verified | ✅ Done | `cargo test` 28+5 + 3 + 13 = 49 tests passing | | § 5.1 D1 C1 capability (`add_dynid`/`remove_dynid`) | ✅ Done | `redox-driver-core/src/{dynid,manager}.rs` | | § 5.1 D1 C2 capability (`Driver::remove` + WAIT_FOR_REAPPEAR) | ✅ Done | `driver-manager/src/config.rs` (real SIGTERM+SIGKILL) | | § 5.1 D1 C3, C6 (enable_device / set_bus_master) | ✅ Done | `open_pcid_channel` via `pcid_interface::EnableDevice` | | § 5.1 D1 C4 (BAR request) | 🟡 Corrected at v3.0 | `/bind` never existed in pcid (see v3.0 correction 1); claim collapses into channel exclusivity per P0-1 | | § 5.1 D1 C5, C7, C8, C12, C16, C17 (child-side) | ✅ Done | pre-existing driver daemons | | § 5.1 D1 format coexistence | ✅ Done | `convert_legacy` function in config.rs | | § 5.1 D1 SpawnDecision committee | ✅ Done | `spawn_decision_gate()` function | | § 5.2 D2.1 SMP concurrent probe | ✅ Done | `redox-driver-core/src/concurrent.rs` (worker pool) | | § 5.2 D2.2 C-state / P-state advisors | 🟡 Corrected at v3.0 | advisory theater (assessment G6) — P0-3 strips to honest core (MSI-X env hint or removal) | | § 5.2 D2.3 IOMMU + MSI-X + NUMA helpers | ✅ Done | same module (combined surface) | | § 5.2 D2.4 runtime PM hooks (suspend/resume) | ✅ Done | `Driver::suspend`/`resume` trait + `signal_then_collect` | | § 5.2 D2.5 AER foundation (on_error) | ✅ Done | `Driver::on_error` + `ErrorSeverity` + `RecoveryAction` | | § 5.2 D2.6 PciQuirkFlags integration (D4) | ✅ Done | `driver-manager/src/quirks.rs` (redox-driver-sys dep) | | § 5.2 D3 event-driven hotplug (polling fallback) | ✅ Done | hotplug poll reduced to 250ms; pcid event delivery is the next step | | § 5.2 D4 audit-no-stubs.py + 8 test scripts | ✅ Done | 0 violations across 34 files | | § 5.2 D4 redbear-driver-policy package | ✅ Done | `local/recipes/system/redbear-driver-policy/` | | § 5.2 D5 audit document | ✅ Done | `local/docs/evidence/driver-manager/D5-AUDIT.md` | | § 5.2 C0 dormant service files | ✅ Done | `local/sources/base/init.{,initfs.d/}/*-manager.service` | | **Operator ratification** | 🔴 Not yet | required before C1 begins | **Test totals at v1.3:** - `redox-driver-core`: 28 unit + 5 integration = 33 tests - `redox-driver-pci`: 3 tests - `driver-manager`: 13 unit tests - **Total: 49 tests, all passing** **§ 0.5 audit gate at v1.3:** 0 violations across 34 scanned files. **v1.2 status update over v1.1:** The § 0 strategic context and § 5 D/C phase structure are unchanged from v1.1. This revision records what was **implemented** during the parallel-development sprint (v1.1 → v1.2). See `local/docs/evidence/driver-manager/D5-AUDIT.md` for the formal capability-by-capability audit. | Item | Status at v1.2 | Where | |---|---|---| | § 5.1 D0 foundation verified | ✅ Done (v1.1) | redacted | | § 5.1 D1 C1 capability (`add_dynid`/`remove_dynid`) | ✅ Done (v1.2) | `local/recipes/drivers/redox-driver-core/source/src/{dynid,manager}.rs` | | § 5.1 D1 C2 capability (`Driver::remove` + WAIT_FOR_REAPPEAR) | ✅ Done (v1.2) | `local/recipes/system/driver-manager/source/src/config.rs` | | § 5.1 D1 C3, C6 (enable_device / set_bus_master) | ✅ Covered (v1.2) | already in `open_pcid_channel` via `pcid_interface` | | § 5.1 D1 C4 (BAR request explicitness) | ✅ Covered (v1.2) | already in `claim_pci_device` | | § 5.1 D1 C5, C7, C8, C12, C16, C17 (child-side) | ✅ Done (pre-D1) | already in driver daemons | | § 5.1 D1 format coexistence (legacy `[[drivers]]` + new `[[driver]]`) | ✅ Done (v1.2) | `local/recipes/system/driver-manager/source/src/config.rs::convert_legacy` | | § 5.1 D1 SpawnDecision committee | ✅ Done (v1.2) | `local/recipes/system/driver-manager/source/src/config.rs::spawn_decision_gate` | | § 5.2 D2 modern-tech surface (PM/AER/MSI-X/IOMMU/C-state/P-state) | 🟡 Partial (v1.2) | `Driver::suspend`/`resume`/`on_error` trait; `signal_then_collect`; SMP/IOMMU defer to D5 | | § 5.2 D3 event-driven hotplug | 🟡 Polling fallback (v1.2) | `redox_driver-pci::subscribe_hotplug` returns `Unsupported` until pcid event delivery lands | | § 5.2 D4 audit-no-stubs.py + 8 test scripts | ✅ Done (v1.2) | `local/scripts/driver-manager-audit-no-stubs.py`, `local/scripts/test-driver-manager-*.sh` | | § 5.2 D4 redbear-driver-policy package | ✅ Done (v1.2) | `local/recipes/system/redbear-driver-policy/` | | § 5.2 D5 audit document | ✅ Done (v1.2) | `local/docs/evidence/driver-manager/D5-AUDIT.md` | | § 5.2 C0 dormant service files | ✅ Done (v1.2) | `local/sources/base/init.{,initfs.d/}/*-manager.service` | **v1.1 additions over v1.0:** - New `§ 0 Strategic Context` with six subsections (rationale, success criteria, upstream risk, modern tech surface, comprehensive principle, parallel development). - Restructured `§ 5 Phased migration plan` into **D-Phase (parallel development)** and **C-Phase (cutover & validation)** tracks. The two tracks are sequential, not interleaved. - The original P0–P6 dual-mode strategy is folded into the new structure. driver-manager is now **never enabled** until the D-phase feature-complete gate (D5) ratifies. - Cross-referenced § 0 references in § 1, § 2, § 4, § 5, § 9. --- ## Title and intent `pcid-spawner` is the current single-purpose daemon that reads `/etc/pcid.d/*.toml`, walks `/scheme/pci/`, and forks driver daemons for matched devices. It is correct, small (127 lines), and ships the boot-critical `00_pcid-spawner.service` plus the initfs `40_pcid-spawner-initfs.service` unit. It cannot grow further without becoming a different program: deferred-probe semantics, dependency graphs, runtime hotplug, driver parameters, and a managed device tree all require the more capable abstraction in `local/recipes/system/driver-manager/` (already drafted but not wired). `driver-manager` is the intended replacement. Its implementation is partial: the abstract `redox-driver-core` machinery exists, the `DeviceManager` orchestrates buses/drivers/binding, a `PciBus` enumerates `/scheme/pci`, deferred probing and hotplug are sketched in `hotplug.rs`, and a `scheme:driver-manager` server exposes read-only observability. The piece that has never landed is the integration: package it, write `00_driver-manager.service`, retire `pcid-spawner` cleanly, adopt the Linux-style capability split (C1–C18), and absorb the CachyOS policy patterns that have proven necessary on AMD-first hardware. This plan produces that migration **without losing any boot path**, honoring the project's **never-delete, never-disable, fix-root-cause** policy (`local/AGENTS.md` § COMPREHENSIVE IMPLEMENTATION POLICY). pcid-spawner stays buildable and present in the tree at every phase; it is the safe fallback. --- ## 0. Strategic context This section captures the **why**, **what done looks like**, **upstream risk**, **modern-technology surface**, **comprehensiveness principle**, and **parallel-development constraint** of the migration. Every later section implements these principles — they are not aspirations, they are binding constraints derived from `local/AGENTS.md` and the project's engineering standards. ### 0.1 Rationale for driver-manager (why not extend pcid-spawner) **Three converging forces make `pcid-spawner` insufficient as the long-term driver spawner:** 1. **Architectural ceiling.** pcid-spawner is a 127-line single-purpose launcher that enumerates PCI devices and forks drivers against a static config table. It cannot grow to handle: deferred-probe semantics (driver needs a scheme that is not yet registered); dependency-graph scheduling (drivers depending on other drivers); runtime hotplug (PCIe native, USB, Thunderbolt); driver parameter mutation (a userspace tool writing `iwlwifi` parameters at runtime); AER error recovery; runtime-PM suspend/resume. Adding any of these to a 127-line launcher requires restructuring into a different program. 2. **Driver coverage roadmap.** Red Bear's planned driver surface grows from 17 to ~30+ daemons (per `local/docs/CONSOLE-TO-KDE-DESKTOP-PLAN.md`). New drivers — `amd-mp2-i2cd`, `intel-thc-hidd`, Wi-Fi (`iwlwifi`, `mt76`), GPU backends (`redox-drm` AMD DC variant), Thunderbolt, NVMe namespaces — each carry their own configuration model, dependency graph, and runtime parameter surface. A per-driver ad-hoc spawner is no longer maintainable. 3. **Driver ecosystem contract demands.** Wi-Fi drivers need delayed probe (firmware load + regulatory database check); I2C/audio controllers need dependency-aware ordering (acpi → i2c → driver); GPU drivers need stable device-id→driver binding with explicit version handling; hotplug events require an event-driven loop, not a one-shot enumeration. pcid-spawner's architecture cannot satisfy any of these contractually. **What we lose by NOT moving to driver-manager:** - The existing `redox-driver-core` framework (Bus/Driver/DeviceManager/ ProbeEvent/DriverMatch/DriverParams) becomes dead code. - The hard-won work in `redox-driver-acpi`, `redox-driver-pci`, and `local/recipes/system/driver-params/` becomes single-purpose. - Wi-Fi, USB hotplug, AER, and runtime-PM work has to be re-architected against a different manager primitive. - The CachyOS-style policy layer (blacklist, autoload, ordering, options) cannot live cleanly without a manager that reads `/etc/driver-manager.d/`. **Why not just extend pcid-spawner:** - pcid-spawner is 127 LOC doing exactly one thing. Adding deferred probing + dependency graphs + hotplug + params + AER + PM grows it to thousands of LOC with a fundamentally different architecture. - The `redox-driver-core` framework already exists with the right trait surface. Throwing it away to extend pcid-spawner would violate `local/AGENTS.md` § LOCAL FORK SUPREMACY POLICY: "Red Bear adapts to upstream, never throws away working code." - The Linux-style capability split (C1–C18 in § 2.3) is the right design. pcid-spawner implements none of C9, C11, C13–C18; bolting them on is more work than building the manager they belong in. **Why this is happening now:** - The framework is already built (`local/recipes/system/driver-manager/` is a compilable Rust crate at version `0.3.1` with 1250 LOC and a 783KB binary artifact). - The 17 drivers' Cargo manifests depend on `pcid_interface` (`PciFunctionHandle::connect_default()`). They are already compatible with the manager contract — no driver-code changes are required at any phase. - Driver parameters and dependency gating are needed before Wi-Fi (per `local/docs/WIFI-IMPLEMENTATION-PLAN.md`). - USB hotplug (per `local/docs/USB-IMPLEMENTATION-PLAN.md`) needs the manager's hotplug surface. - AER recovery (per `local/docs/IRQ-AND-LOWLEVEL-CONTROLLERS-ENHANCEMENT-PLAN.md`) needs the manager's `Driver::on_error` surface. ### 0.2 Success criteria (definition of done) The migration is **complete** when ALL of the following hold simultaneously: 1. **Functional parity** with pcid-spawner, verified by `local/scripts/test-driver-manager-parity.sh`: every device pcid-spawner binds, driver-manager binds. No regression in driver set coverage. 2. **Linux 7.1 capability bridge complete.** All of C1–C18 are implemented and tested, at the priority levels in § 2.3: - P0 set: C1, C2, C3, C4, C5, C6, C7, C8, C12, C16 - P1 set: C9, C10, C11, C14, C17, C18 - P2 set: C13, C15 3. **Modern technology surface integrated** (§ 0.4): - SMP-aware concurrent probe verified - C-state and P-state coordination verified - Runtime PM suspend/resume callback chain verified - IOMMU group management verified - AER error recovery verified 4. **Hotplug functional and event-driven** (not polling). Verified on QEMU synthetic and at least one real-hardware hot-add scenario. 5. **Quirk policy honored.** `redox-driver-sys::PciQuirkFlags` consulted for every bind/remove decision. `NO_MSIX`, `NO_PME`, `NEED_FIRMWARE`, `DISABLE_ACCEL`, `FORCE_LEGACY_IRQ`, `NEED_IOMMU`, etc., all flow through the manager. 6. **Hardware validation matrix passes** on: - AMD Threadripper (canonical AMD-first profile) - AMD Zen4 desktop - Intel Alder Lake or later desktop - At least one bus category each: storage (NVMe + AHCI), network (e1000d + rtl8168d), USB (xhcid), GPU (Intel or AMD display path) 7. **30-day stability gate.** In production cutover (C4), the `ConditionPathExists` guard on `00_pcid-spawner.service` has not fired in 30 days of continuous operation. 8. **Regressions clean.** All of `local/scripts/test-driver-manager-{parity,active,initfs,hotplug,pm,cutover}.sh` pass on every release branch for the same 30-day window. 9. **No-deferred-comments cleanup.** The inline deferred comments in `config/redbear-mini.toml:31` and `config/redbear-device-services.toml:9-13` are removed (no longer accurate). 10. **Operator ratification.** Explicit human acknowledgement at each C-phase boundary and at the final C4 transition. ### 0.3 Upstream risk — what if Redox upstream ships their own driver-manager This is **not a remote possibility** — Redox upstream has been discussing driver-manager-style architectures. Red Bear's response is encoded as policy ahead of time. **What Redox upstream's plan could look like:** - A single-purpose scheme:pci consumer that spawns drivers against a config table (very similar to pcid-spawner, the canonical upstream). - A more capable per-bus spawner (closer to Red Bear's driver-manager). - A kernel-side enumeration manager (drastic, unlikely in Redox's microkernel model). **Red Bear's response strategy:** - Compare against the C1–C18 capability list (§ 2.3). A manager is "equivalent" if it covers at least the P0 set of capabilities and exposes a compatible driver handoff contract. - **If upstream ships a fully equivalent manager**, evaluate migrating to use theirs per `local/AGENTS.md` § LOCAL FORK SUPREMACY POLICY (Red Bear adapts to upstream; never pins/holds back). This is the most likely scenario for the long term. - **If upstream ships a different approach** (per-bus spawning, a kernel-side manager, a Lua-scripted policy layer), Red Bear's driver-manager becomes a **Red Bear extension layer on top of the upstream primitive**, OR is preserved as a local recipe that supplements the upstream manager rather than replacing it. The decision is taken at the time based on coverage. - **If upstream ships the equivalent manager within 6 months of our D5 gate**, the migration plan is re-evaluated against theirs. The C-phases (§ 5.2) become a no-op or a thin shim. pcid-spawner remains the fallback regardless. **Concrete protections already in the plan:** - `00_driver-manager.service` is a service name, not a binary. Swapping the `cmd=` to upstream's binary is a one-line change. - The driver's runtime contract is `PCID_CLIENT_CHANNEL=` (preserved from upstream Redox pcid-spawner). Any manager that delivers this env var keeps drivers unmodified. - The capability taxonomy (C1–C18) is a Red Bear design tool, not an upstream commitment. We use it to evaluate upstream choices. **What does NOT change:** - `local/recipes/system/driver-manager/source/` is and remains a local Red Bear crate, not an upstream-fork clone. - The D-phase development continues regardless of upstream decisions. - pcid-spawner stays as the safe fallback until C4. ### 0.4 Modern technology surface (SMP, S/P states, runtime PM, IOMMU, AER, hotplug, MSI-X, NUMA) The driver-manager is **genuinely modern** by design. The technologies listed below are integrated as **functional features** (not stubs): 1. **SMP awareness.** - Manager enumeration runs single-threaded for race-free exploration (correct — exploration must be deterministic). - **Concurrent probe dispatch**: `max_concurrent_probes` is enforced via a worker pool. Today it is policy metadata; in D2 it becomes real concurrent dispatch via `std::thread::scope` or `rayon`. - **Per-vector IRQ CPU affinity**: MSI-X vectors are bound to specific CPUs based on topology (CPUID leaf `0Bh` for AMD, `0Fh` for Intel). - Hotplug event loop is a separate thread; events post through a lockless queue to the manager (no shared mutable state with the probe path). 2. **C-states (CPU idle states).** - Manager exposes driver-bound/unbound events to `cpufreqd` / `thermald`. Hotplug-removing a device → CPU may drop to a deeper C-state. - Manager signals probe-completion → CPU may return to its former governor state. - System-wide C-state transitions coordinated through `redox-driver-acpi` (via scheme:acpi). 3. **P-states (CPU performance states).** - On driver bind/unbound, manager publishes a P-state advisory via `cpufreqd` socket or a `pstate` scheme. - Cold-boot probe order is documented and P-state-aware: storage drivers spawn first (high P-state by default), audio/USB spawn later (low P-state allowed). - Driver spawn during boot is gated on `cpufreqd` confirming P-state is high enough for the driver to initialise (e.g., NVMe completion timeouts require a high enough P-state). 4. **Runtime PM (per-driver).** - `Driver::suspend()` / `Driver::resume()` callbacks are **fully implemented** with real state save + power-down (default: real D3 transition through pcid; not `Ok(())`). - PCIe D-state transitions (D0 ↔ D3hot ↔ D0) coordinated through pcid's `SetPowerState` request via `PcidClient`. - Hotplug-remove pre-empts runtime PM: the manager calls `force_suspend()` before unbinding. 5. **IOMMU groups** (`local/recipes/system/iommu/`). - Per-device group registration via the `iommu` scheme. - DMA isolation enforcement: drivers cannot bypass their group's domain. - Group-awareness for hotplug: a sibling device in the same group must also be quiesced before removal. 6. **AER (PCI Express Advanced Error Recovery).** - `Driver::on_error(severity)` callback is **fully implemented** with severity dispatch (CORRECTABLE → log; NONFATAL → retry with masking; FATAL → slot reset → config restore → re-bind). - Manager registers with `pciehp` for hotplug events (Presence Detect Changed, Data Link Layer State Changed, MRL Sensor Changed). - Per-driver error recovery action: drivers implement `Driver::on_error` for their specific hardware (NVMe reset, e1000 soft-reinit, etc.). 7. **MSI-X vector allocation.** - `pci_alloc_irq_vectors()` semantics preserved (MSI-X preferred, fallback to MSI, fallback to INTx; capability-aware honouring of `PciQuirkFlags::NO_MSIX`). - Per-vector fd returned to driver (each vector independently reachable through `/scheme/irq`). - Multiple MSI-X vectors per device (e.g., xHCI's 16-vector interrupt setup). 8. **NUMA awareness** (when `local/recipes/system/numad/` is live). - Driver's memory regions classified by NUMA node. - `DmaBuffer::allocate(size, align, node_hint)` prefers same-node. - Hot-add monitored for NUMA topology changes. 9. **Modern vendor-specific paths.** - **AMD**: PSP firmware load (via `firmware-loader`), DCN hardware blocks, GTT addressing, AMD-Vi IOMMU integration. - **Intel**: GGTT setup, hot-plug through `pciehp`, MFG/RC6 power management, IOMMU group isolation. - Per-vendor path is a `redox-drm` backend (out of scope here); the manager's runtime-PM / quirk / hotplug hooks are exercised by all of them. **Why these technologies, and why not others:** - We do NOT adopt `cgroup-vram` (CachyOS extras) — Redox has no cgroups. - We do NOT adopt `sched-ext` / `BORE` scheduler — kernel-side work, per `local/docs/CONSOLE-TO-KDE-DESKTOP-PLAN.md` Phase T. - We DO adopt CachyOS-style `modprobe.d` patterns (blacklist, options, autoload) — see § 2.2. These translate cleanly to `/etc/driver-manager.d/`. ### 0.5 Comprehensive implementation principle (no stubs, comprehensive code only) The driver-manager implementation is **comprehensive, systematic, methodical**. `local/AGENTS.md` § STUB AND WORKAROUND POLICY — ZERO TOLERANCE applies without exception. The principle is re-stated here in the specific form that applies to driver-manager: - **No stubs.** Every public API in `redox-driver-core::driver::Driver`, `redox-driver-core::bus::Bus`, and `driver-manager::scheme::*` is fully implemented. No `unimplemented!()`, no `todo!()`, no empty match arms returning trivial defaults. - **No `#ifdef`-guarded no-ops.** No Rust `cfg` gates that disable entire feature paths. - **No `LD_PRELOAD`-style tricks.** No override layer that hides unimplemented features. - **No `sed`/`awk` rewriting.** TOML config is parsed, not preprocessed. **Per-method completeness requirements** (any violation blocks D5): | Surface | Forbidden pattern | Required behaviour | |---|---|---| | `Driver::probe(info)` | `unimplemented!()` or `Ok(())` skip | Full match-table evaluation + dependency check + device claim + spawn | | `Driver::remove(info)` | `_ => Ok(())` drop | Reclaim bind handle, terminate child via `SIGTERM`, refresh `scheme:driver-manager:/bound` | | `Driver::suspend(info)` | `Ok(())` default | Real PCI D-state transition via pcid (`SetPowerState`), save config space, log | | `Driver::resume(info)` | `Ok(())` default | Restore config space, walk IRQ vectors (re-arm MSI-X), signal ready | | `Driver::on_error(info, severity)` | `Ok(())` or `Unsupported` | Severity dispatch: CORRECTABLE → log; NONFATAL → retry; FATAL → slot reset | | `Driver::params()` | `DriverParams::default()` | Real parameter definitions (priority, debug, exclusive_with, runtime flags) | | `Bus::enumerate_devices()` | `Ok(vec![])` skip | Walk scheme:pci config files, populate `DeviceInfo` with vendor/device/class/subclass/prog_if/revision/subsystem IDs | | `Bus::subscribe_hotplug()` | `Err(BusError::Unsupported)` | Subscribe to `/scheme/pci/events` (or pcid uevent channel); return real `HotplugSubscription` | | `Manager::enumerate()` | empty loop | Walk all buses, dispatch to drivers, emit `ProbeEvent`s with deferred support | | `Manager::retry_deferred()` | no-op | Re-evaluate deferred queue, re-probe if dependencies now satisfied, emit events | **Honest absence** vs. **stub** matters. If a feature is genuinely not applicable (e.g., NUMA awareness on a non-NUMA system), the manager code calls a runtime probe that returns an honest answer: ```rust // PREFERRED (D4+): if !query_numa_support() { return BusError::Unsupported; // honest absence } // FORBIDDEN at any phase: // if !query_numa_support() { return Ok(()) } // if cfg!(...) { return BusError::Unsupported } else { return Ok(()) } ``` The result: type signatures are honest, runtime is honest, documentation is honest. A driver receiving `Unsupported` knows to fall back to uniform memory without assuming the manager is silently doing the right thing. **Systematic** means the same architectural pattern applies across all bus types (PCI, USB, ACPI, future platform), all driver types (storage, network, GPU, USB, audio), and all capability surfaces (C1–C18). The `Driver` trait is the single contract; the `Bus` trait is the single contract; the `scheme:driver-manager:/` filesystem is the single observability surface. **Methodical** means the work unfolds in the D-phases of § 5.1 with verifiable exit criteria. No phase skips ahead. No phase declares done with deferred items. The audit script `local/scripts/driver-manager-audit-no-stubs.py` (D4 deliverable) is the formal gatekeeper. **Right-component implementation rule** (from `local/AGENTS.md` § STUB AND WORKAROUND POLICY): | Symptom | Wrong fix | Required fix | |---|---|---| | `eventfd()` not in relibc | Stub in libc wrapper | Implement in relibc proper | | `Bus::subscribe_hotplug` not in pcid scheme | Stub the manager side | Implement event delivery in pcid scheme | | TOML config gap | Accept both formats but emit empty drivers | Implement FULL conversion from legacy `pcid.d` to new `drivers.d` | | Driver needs runtime PM | `suspend: fn() { Ok(()) }` default | Implement genuine D3 transition in pcid, expose via trait | | AER not yet wired | Mark feature as `Unsupported` and ignore errors | Implement severity dispatch + recovery action in `Driver::on_error` | | Hotplug loop is polling-only | Document as "future work" | Implement event subscription via `Bus::subscribe_hotplug()` | | TOML `[[driver.match]]` field missing | Skip silently | Return `Err(format!("unsupported match field: {name}"))` from loader | ### 0.6 Parallel development constraint (built but not utilised until fully developed) **The driver-manager is being implemented in parallel and not being utilized before fully developed.** This is the **binding development model**. **Current state (2026-07-20):** - The local-recipe at `local/recipes/system/driver-manager/source/` accumulates improvements in commits. - `pcid-spawner` is the boot path in every `redbear-*.toml`. - `driver-manager` is **NOT** added to any `[packages]` section. - `driver-manager` does **NOT** have an `00_driver-manager.service`. - `driver-manager`'s binary MAY be built locally (it is at 783KB), but it is **NOT** shipped in any produced ISO or harddrive image. - Inline deferred comments in `config/redbear-mini.toml:31` and `config/redbear-device-services.toml:9-13` reflect this. **Operational reality during D-Phase:** - `local/recipes/system/driver-manager/source/` is committed to the current branch as part of normal development. - `config/redbear-*.toml` does not include `driver-manager = {}`. - The ISO build (`./local/scripts/build-redbear.sh redbear-mini`) does not include the driver-manager binary. - Test scripts `local/scripts/test-driver-manager-{parity,active,...}.sh` are written but not in the ISO; they run only on developer workstations and CI runners. - `local/scripts/TOOLS.md` and `local/AGENTS.md` continue to describe driver-manager as "in development" until D5 ratifies. **When does driver-manager become eligible for the boot path?** When ALL of D0–D5 exit gates are satisfied (see § 5.1): - D0 (foundation) complete - D1 (Linux capability bridge) complete — all P0 capabilities of C1–C18 implemented and tested - D2 (modern technology surface) complete — SMP, S/P states, runtime PM, IOMMU groups, AER all implemented - D3 (hotplug event-driven) complete - D4 (quark integration + comprehensive audit) complete - D5 (feature-complete gate) — formal audit confirms no stubs in § 0.5 matrix, **operator ratification received** **Until then**, the parallel development continues without touching the live boot path. **Implications for the original P0–P6 phasing (v1.0 of this plan):** The original plan's P0 (dual-mode observation) and P1 (rootfs active driver-manager) are now folded into the C-phases (§ 5.2). The D-phases describe the **pre-cutover work** (i.e., the parallel development the team is currently doing). The C-phases describe the **post-completion cutover**. The two are sequential, not interleaved. This constraint is the **one operational reality** that separates this migration from any ordinary refactor. A feature that is not fully complete is NOT shipped; the build system does not "auto-enable" it; CI does not bundle it. The first time driver-manager appears in a boot path is after D5 + operator ratification. **No exceptions.** --- ## Position in the doc set - This is the canonical planning authority for `pci-spawner` → `driver-manager` migration beneath `local/docs/CONSOLE-TO-KDE-DESKTOP-PLAN.md`. - It does NOT replace any subsystem-specific plan. It supersedes the inline comment in `config/redbear-mini.toml` (line 31): *"driver-manager requires driver config migration and is not yet ready"* and the inline comment in `config/redbear-device-services.toml` (line 9-13): *"driver-manager intentionally not included: it is the intended future replacement for pcid-spawner but is not yet ready (driver config migration pending) and was previously packaged-but-unused — its service launched pcid-spawner instead of driver-manager."* - Cross-references: `local/docs/IRQ-AND-LOWLEVEL-CONTROLLERS-ENHANCEMENT-PLAN.md` (where pcid-spawner hardening currently lives), `local/docs/QUIRKS-SYSTEM.md` + `QUIRKS-IMPROVEMENT-PLAN.md` (where the driver-manager→redox-driver-sys quirks bridge is planned), `local/docs/USB-IMPLEMENTATION-PLAN.md` (where the Bus trait is wired for USB), `local/docs/WIFI-IMPLEMENTATION-PLAN.md` (where matching semantics live for mac80211/cfg80211). ## Scope **In scope:** - Lifecycle and integration of the existing `local/recipes/system/driver-manager/` crate to replace `local/sources/base/drivers/pcid-spawner/`. - Format migration of `/etc/pcid.d/*.toml` (legacy `pcid_interface::Config`) to `/lib/drivers.d/*.toml` (driver-manager `DriverMatch`), plus a back-compat loader that lets both formats coexist during transition. - Init service rewrite: `00_pcid-spawner.service` (rootfs) → `00_driver-manager.service` with `00_pcid-spawner.service` retained as a fallback unit that runs only when `driver-manager` is absent on the initfs. Initfs unit `40_pcid-spawner-initfs.service` is renamed to `40_driver-manager-initfs.service` with the same blocking-oneshot contract. - Linux 7.1 capability bridging: the manager exposes, and the spawned drivers consume via PCID_CLIENT_CHANNEL env continuation, the capabilities C1–C18 (driver match, lifecycle, BAR mapping, IRQ vectors, runtime PM, AER error recovery, etc.). - CachyOS policy patterns: policy-layer TOML with blacklist/options/autoload, driven by the manager (not by `modprobe` since Red Bear has no modules). **Out of scope:** - Adding USB / ACPI / platform buses to the device manager — those are in `local/docs/USB-IMPLEMENTATION-PLAN.md` and follow once the PCI manager lands. - Replacing `pcid` itself (the scheme:pci owner) — it stays the canonical PCI scheme surface, just like Linux's `pci_bus_type` owning `/sys/bus/pci/devices/`. - Replacing `redox-driver-sys` — driver-manager consumes it for the hardware-quirks surface once Q3 lands (see `local/docs/QUIRKS-IMPROVEMENT-PLAN.md` Task 2.1). - Replacing the kernel — Redox's PCI scheme is userspace; the kernel's role (memory/irq/acpi/dt/serio schemes, MMIO mapping, MSI/MSI-X vector delivery) is unchanged. ## Policy constraints (binding) Every step in this plan inherits the following constraints from `local/AGENTS.md`: 1. **NEVER DELETE** a package, service, config, or patch. pcid-spawner stays. 2. **NEVER IGNORE** a package by `"ignore"`. driver-manager lands as additive. 3. **NEVER COMMENT OUT** a service or config entry to "fix" a build. 4. **ALWAYS FIX** the root cause when something breaks. 5. The migration is **operator-ratified**: each phase has an explicit exit gate and is not closed until the gate is met AND human-acknowledged. The durability rule applies: any source-tree edit during this migration is mirrored into `local/patches/` or `local/sources//` in the same work session. `local/patches/base/` and the fork `local/sources/base/` carry the changes; `recipes/core/base/source/` is not the durable location. --- ## 1. Current state assessment ### 1.1 What pcid-spawner does today **Source:** `local/sources/base/drivers/pcid-spawner/src/main.rs` (127 lines) **Cargo:** `local/sources/base/drivers/pcid-spawner/Cargo.toml` **Recipe:** `recipes/core/base/drivers/pcid-spawner/recipe.toml` (path-fork) Single `main()` function with the following behaviour, ordered: 1. **Wait** for `/scheme/pci/` to appear (200 × 50ms retry, 10s total) — this was added by Red Bear patch `local/patches/base/P4-pcid-spawner-pci-coordinate-env.patch` alongside the PCI coordinate env vars. 2. **Load** merged driver configs via `config::config("pcid")` — concatenates `/etc/pcid.d/*.toml` (rootfs) or `/scheme/initfs/etc/pcid.d/*.toml` (`--initfs` mode) into one `Config` struct. 3. **Iterate** `/scheme/pci/` directory entries. For each: - `PciFunctionHandle::connect_by_path(&device_path)` — opens the per-device `channel` handle in `scheme:pci`. The handle is the **mutual-exclusion lock**: pcid returns `ENOLCK` to any second opener. This is the only claim mechanism. - On `ENOLCK`: log debug, `continue`. On other errors: log error, `continue`. The spawner never aborts on a single bad device. - `config.match_function(&full_device_id)` — legacy matching (class → subclass → interface → vendor/device, optional multi-vendor `ids` map, optional device_id_range). - On miss: log debug, `continue`. 4. **Enable** the PCI function (`handle.enable_device()`) — pcid writes the command register to enable bus mastering + memory + IO. 5. **Build** `Command` from `driver.command`, resolving `program` either absolute or prefixed `/usr/lib/drivers/`. 6. **Pass** env vars to the child: - `PCID_CLIENT_CHANNEL=` — the bincode channel FD the driver uses for `PciFunctionHandle::connect_default()` to reach pcid. - `PCID_SEGMENT=` — added by Red Bear P4 patch. - `PCID_BUS=` — added by Red Bear P4 patch. - `PCID_DEVICE=` — added by Red Bear P4 patch. - `PCID_FUNCTION=` — added by Red Bear P4 patch. 7. **Spawn** via `daemon::Daemon::spawn(command)` — parent blocks until the child signals readiness. This is the **driver-ready handshake** and is honoured by every existing driver daemon (`ahcid`, `e1000d`, `xhcid`, etc.). 8. **Close** the parent's copy of the channel FD. ### 1.2 What the existing driver-manager implements **Source root:** `local/recipes/system/driver-manager/source/` **Cargo:** `local/recipes/system/driver-manager/source/Cargo.toml` (Cat 1, version `0.3.1`) **Recipe:** `local/recipes/system/driver-manager/recipe.toml` (template=cargo, path="source") Five source files (`src/main.rs`, `config.rs`, `scheme.rs`, `hotplug.rs`, `exec.rs`) totalling ~1250 lines. Built and present at `recipes/system/driver-manager/target/x86_64-unknown-redox/stage/usr/bin/driver-manager` (783KB ELF, dated 2026-07-19). Binary-store artifact cached in `repo/x86_64-unknown-redox/driver-manager.pkgar`. **NOT** packaged into any current `[packages]` section of `redbear-*.toml`. | Area | Status | Notes | |---|---|---| | Compile | ✅ | Builds clean on x86_64-unknown-redox | | Core abstraction | ✅ | `redox-driver-core` (Bus/Driver/DeviceManager/ProbeEvent/ManagerConfig/DriverParams/MatchTable/HotplugEvent) | | PCI bus | ✅ | `redox-driver-pci::PciBus` reads `/scheme/pci` raw config space; class/subclass/program-if/subdevice IDs returned | | TOML config loader | ✅ | `/lib/drivers.d/*.toml` (name, description, priority, command, match, depends_on) | | Probe pipeline | ✅ | ProbeResult::Bound / NotSupported / Deferred / Fatal with retry queue | | Deferred retry | 🟡 | 30 retries × 500ms; logs `deferred-retry-limit-reached` and exits 0 | | Async probe | 🟡 | `ManagerConfig::async_probe = true` is set, but `thread::spawn(...).join()` is used immediately, making it actually synchronous | | `max_concurrent_probes` | 🟡 | Stored as policy metadata; never enforced (all probes are serial) | | Hotplug | 🟡 | `run_hotplug_loop()` polls every 2s; `Bus::subscribe_hotplug()` is hidden behind an unused `hotplug` feature flag | | `scheme:driver-manager` | ✅ | Read-only `/devices`, `/bound`, `/events`, `/devices/`, plus param persistence to `/tmp/redbear-driver-params//{driver,enabled}` | | Spawn via PCID_CLIENT_CHANNEL | 🟡 Corrected at v3.0 | `/bind` never existed in pcid; P0-1 collapses claim into the channel open (`ENOLCK` exclusivity) and passes `PCID_CLIENT_CHANNEL=` — the pcid-spawner model | | Driver parameters | 🟡 | `Driver::params()` declared but driver-manager's own schema (`enabled`, `priority`) is parameter-only; runtime writes via `scheme:driver-params` (separate daemon `local/recipes/system/driver-params`) | | Quirks integration | 🔴 | `redox-driver-sys` is **not** in the dep list; `pci_has_quirk` / `pci_get_quirk_flags` are NOT consulted | | Service wiring | 🔴 | No `00_driver-manager.service` exists; absent from all `[packages]` sections | | Tests | 🔴 | Zero driver-manager tests; 12 unit tests in `redox-driver-core` | | Documentation | 🟡 | No dedicated doc; mentioned in `UPSTREAM-SYNC-PROCEDURE.md` § "driver-manager: Deferred" and `PACKAGE-BUILD-QUIRKS.md` § "driver-manager Removed During Sync" | ### 1.3 Service inventory that depends on pcid-spawner **Service definitions:** | Service | Mode | Flag | Where | |---|---|---|---| | `00_pcid-spawner.service` | `oneshot_async` | (none) | `local/sources/base/init.d/` | | `40_pcid-spawner-initfs.service` | `oneshot` (blocking) | `--initfs` | `local/sources/base/init.initfs.d/` | | `/etc/init.d/00_pcid-spawner.service` (override) | `oneshot_async` | (none) | `config/redbear-mini.toml` lines 575-583 | | `00_base.target` `requires_weak` | — | — | `local/sources/base/init.d/00_base.target` | **Service dependencies** (every service that references `00_pcid-spawner.service`): | Config | Service referencing it | Reference role | |---|---|---| | `config/redbear-mini.toml` | `10_evdevd.service` | `requires_weak` | | `config/redbear-mini.toml` | `20_udev-shim.service` | `requires_weak` | | `config/redbear-mini.toml` | 11 other services | `requires_weak` | | `config/redbear-full.toml` | `10_evdevd.service` | `requires_weak` | | `config/redbear-full.toml` | `redox-drm` consumers | `requires_weak` | | `config/redbear-greeter-services.toml` | `redbear-greeter` (seatd chain) | `requires_weak` | | `config/redbear-device-services.toml` | explicit comment that driver-manager is deferred | — | | `config/acid.toml` | acid test config | `requires_weak` | | `config/redoxer.toml` | redoxer CI config | `requires_weak` | Migrating this dependency graph without breaking any boot path requires **keeping `00_pcid-spawner.service` available as a fallback** through P0–P2 and **running both managers transiently during P3**. ### 1.4 Configuration surfaces **Active now (legacy format):** - `config/redbear-mini.toml:500-512` — `/etc/pcid.d/*.toml` overrides (`ihdgd.toml`, `virtio-gpud.toml`, `00_text_mode_gpu_mask.toml`) - `local/config/pcid.d/intel_gpu.toml` — Intel GPU match - `local/config/pcid.d/amd_gpu.toml` — AMD GPU match **Already drafted (driver-manager format, currently inert):** - `config/redbear-device-services.toml:116-490` — full set of `/lib/drivers.d/*.toml`: - `00-storage.toml` (ahcid, ided, nvmed, virtio-blkd, usb-bot) - `10-network.toml` (e1000d, rtl8168d, rtl8139d, ixgbed, virtio-netd) - `20-usb.toml` (xhcid, ehcid, ohcid, uhcid, usbhubd) - `30-graphics.toml` (vesad, virtio-gpud, redox-drm) - `40-input.toml` (ps2d, usbhidd, intel-thc-hidd) - `50-audio.toml` (ihdad, ac97d, sb16d) - `70-usb-class.toml` (usbscsid, usbaudiod, redbear-ftdi) **Decision-needed:** are these drafts correctly normalised for driver-manager's TOML schema (`[driver]` with `match` tables, priority, depends_on)? **D1** verifies them. Many entries will need editing to converge on a single matching language. ### 1.5 Fork / source provenance - `local/sources/base/` is the local fork of the `base` Redox upstream submodule. It holds BOTH `drivers/pcid/` (the scheme:pci owner) AND `drivers/pcid-spawner/` (the legacy spawner). - `local/recipes/system/driver-manager/` is a **local recipe** (Cat 1 in-house crate), not a submodule. It does NOT duplicate upstream code; it's a fresh Red Bear creation. No `submodule/driver-manager` branch exists, no `.gitmodules` entry, no need to create one (per `local/AGENTS.md` § BRANCH AND SUBMODULE POLICY: "We don't create new branches/repos. We work on existing submodules first. … A new submodule is only justified when the component is large enough that submodule pinning provides real value over a tracked tree or local recipe. driver-manager satisfies none of these"). - The 17 driver daemons under `local/sources/base/drivers/{storage,net,graphics,audio,usb}/` each have `pcid = { path = "../../pcid" }` in their Cargo.toml. **They depend on `pcid_interface` (a lib crate alongside pcid), NOT on the pcid-spawner binary.** The runtime contract they honour is `PCID_CLIENT_CHANNEL=`, which driver-manager preserves. No driver-binary changes are required. --- ## 2. Cross-reference: pcid-spawner vs driver-manager vs Linux 7.1 vs CachyOS ### 2.1 Linux 7.1 PCI driver model surface (`local/reference/linux-7.1/` at `ab9de95c9`) | Subsystem | Linux source | Capability exposed | |---|---|---| | PCI bus type | `drivers/pci/pci-driver.c:1726-1742` (`pci_bus_type`), `include/linux/pci.h:1021-1154` (`pci_driver` + `pci_device_id` macros) | C1: id_table + match | | Probe / remove | `drivers/pci/pci-driver.c:473-553` (`pci_device_probe` / `pci_device_remove` / `pci_device_shutdown`) | C2: device lifecycle | | Module loading | `kernel/kmod.c:64-179` (`__request_module` → `call_modprobe`) + `drivers/pci/pci-driver.c:1587-1617` (`pci_uevent` with MODALIAS) | C1′: driver lookup with alias | | Driver-core binding | `drivers/base/bus.c` (`bus_add_driver` / `bus_probe_device` / `device_attach` / `driver_attach`) | C2′: symmetric device/driver iteration | | Sysfs surface | `drivers/pci/pci-sysfs.c` (`vendor`, `device`, `class`, `subsystem_*`, `resource`, `config`, `bind`, `unbind`, `new_id`, `remove_id`, `driver_override`) | C1 + C2 + C11 + observability | | PCIe native hotplug | `drivers/pci/hotplug/pciehp_core.c:185-372` (`pciehp_probe` + presence/attention/MRL/DLLSC handlers) | C14: hotplug events | | AER | `drivers/pci/pcie/aer.c:1203-1280` (`aer_recover_work_func` + `pcie_do_recovery`) + `include/linux/pcieport_if.h` (`pci_error_handlers`) | C13: error recovery | | Runtime PM | `drivers/pci/pci-driver.c:1314-1440` (`pci_pm_runtime_*` + `pci_dev_pm_ops`) | C9 + C18: suspend/resume | | IOMMU / DMA | `drivers/pci/pci-driver.c:1668-1711` (`pci_dma_configure`) + `drivers/iommu/iommu.c` (`iommu_device_use_default_domain`) | C15: DMA / IOMMU | | MSI / MSI-X | `drivers/pci/msi/api.c:205-264` (`pci_alloc_irq_vectors_affinity`) + `include/linux/pci.h:1166-1168` (`pci_irq_vector`) | C7 + C8: vector allocation | | BAR / MMIO | `drivers/pci/pci.c:2120-238, 3916-4172` (`pci_enable_device` / `pci_request_regions` / `pci_set_master` / `pci_ioremap_bar`) | C3 + C4 + C5 + C6: device + bar map | | Power states | `include/linux/pci.h:183-188` (`PCI_D0..PCI_D3cold`) + `pci.h` `pci_set_power_state` | C9: power state control | | Capabilities search | `drivers/pci/pci.c` (`pci_find_capability` / `pci_find_ext_capability`) | C16: capability iteration | **Synthesis (cross-reference `pci_driver` ↔ `Driver` trait ↔ driver-manager):** | Linux `pci_driver` member | Linux function | Redox current (`redox-driver-core`) | Redox pcid-spawner path | Gap to fill | |---|---|---|---|---| | `.probe` | `pci_device_probe` | `Driver::probe(&DeviceInfo) -> ProbeResult` | (deferred to child spawn) | async + retry + dependency-aware | | `.remove` | `pci_device_remove` | `Driver::remove(&DeviceInfo) -> Result<(), DriverError>` | (no remove path at all) | full lifecycle | | `.suspend` / `.resume` | `pci_pm_runtime_*` | `Driver::suspend() / resume()` (default Ok) | (no path) | graceful shutdown + wake | | `.id_table` | `pci_match_device` | `Driver::match_table() -> &[DriverMatch]` | legacy `match_function()` | unify on `DriverMatch` | | `.shutdown` | `pci_device_shutdown` | (not in trait) | (no path) | add to trait or handle via systemd | | `.err_handler` | `pcie_do_recovery` | (not in trait) | (no path) | add `Driver::on_error()` | | `.driver_managed_dma` | `iommu_device_use_default_domain` | (not in trait) | (no path) | add `Driver::dma_managed()` | ### 2.2 CachyOS pattern surface (CachyOS-Settings `master`) | Pattern | CachyOS location | Red Bear equivalent | |---|---|---| | udev rule w/ subsystem match + sysfs write | `usr/lib/udev/rules.d/60-ioschedulers.rules` (HDD/SSD/NVMe scheduler assignment) | driver-manager scheme event `set_io_scheduler(dev, "bfq"\|"mq-deadline"\|"kyber")` | | udev rule w/ `bind`/`unbind` lifecycle | `usr/lib/udev/rules.d/71-nvidia.rules` (NVIDIA PM lifecycle) | driver-manager `register_add_event` + `register_remove_event` matching on vendor + class | | Cross-subsystem reaction (battery state → audio params) | `usr/lib/udev/rules.d/20-audio-pm.rules` (snd_hda_intel powersave) | driver-manager event filter `{AC=>BATT}` → action `set_param(driver, "power_save", value)` | | Sentinel-based idempotency | `/run/udev/snd-hda-intel-powersave` | driver-manager in-memory `init_done: BTreeSet<(driver_name, param_set)>` | | modprobe.d blacklist | `usr/lib/modprobe.d/blacklist.conf` (`blacklist iTCO_wdt`) | `/etc/driver-manager.d/00-blacklist.conf`: `[[blacklist]] module = "iTCO_wdt"` | | modprobe.d options | `usr/lib/modprobe.d/amdgpu.conf` (`options amdgpu si_support=1`) | `/etc/driver-manager.d/50-amdgpu.conf`: `[amdgpu.params] si_support = true` | | modules-load.d | `usr/lib/modules-load.d/ntsync.conf` (`ntsync`) | `/etc/driver-manager.d/autoload.d/ntsync.conf`: `module = "ntsync"` | | Driver mutual exclusion (two drivers claim same PCI IDs) | `usr/lib/modprobe.d/amdgpu.conf` (`amdgpu` SI/CIK ↔ `radeon` SI/CIK off) | driver-manager priority + explicit `exclusive_with` field | | Path-triggered (config change) service activation | `usr/lib/udev/rules.d/85-iw-regulatory.rules` + `cachyos-iw-set-regdomain.{path,service}` | driver-manager + scheme watcher over `/etc/driver-manager.d/` | | Ramdisk driver manifest (mkinitcpio hook ordering) | `linux-cachyos` preset (`microcode`/`modconf`/`kms`/`block`/`filesystems`/`fsck`) | `/usr/lib/driver-manager.d/initfs.manifest` (`ramdisk_drivers = ["ahci", "nvme", "redoxfs"]`, ordered) | | Cold-boot parameter injection (immutable module params) | `modprobe.d/options ...` | driver-manager `set_pre_spawn_param(driver, param, value)` recorded in `BOOT_TIMELINE` | | Curated-policy-as-a-package (cachyos-settings) | `cachyos-settings` ARCH package | `redbear-driver-policy` local recipe (or `redbear-meta` extension) | ### 2.3 Capability table — what a full driver-manager must provide (C1–C18) **Note:** the "Priority" column uses P0/P1/P2 as **capability-priority labels** — *not* phase references. The P0/P1/P2 capability priorities pre-date the § 5 D/C phase restructure. Capability priorities are: - **P0** (capability priority) = blocker for desktop path - **P1** (capability priority) = desktop-ready - **P2** (capability priority) = production-grade These priorities map onto specific phases in § 5.1 D-Phase (P0 set lands in D1; P1 set lands in D2/D3; P2 set lands in D2/D4). | # | Capability | Linux equivalent | driver-manager API | Priority | Notes | |---|---|---|---|---|---| | **C1** | ID-table match + dynamic ID add | `pci_match_device` + sysfs `new_id` / `remove_id` | `DeviceManager.register_driver()` + `match_table()` + `add_dynid()` | P0 | Already present in `redox-driver-core`. `add_dynid` not yet exposed in driver-manager; **D1** must wire it | | **C2** | Device lifecycle (probe/remove) | `pci_device_probe` / `pci_device_remove` | `Driver::probe(&DeviceInfo)` + `Driver::remove(&DeviceInfo)` | P0 | Already present. driver-manager calls `Driver::probe` only after claim + dependency check | | **C3** | Enable / disable device | `pci_enable_device` / `pci_disable_device` | `enable_device(pci_addr)` → pcid `EnableDevice` request | P0 | driver-manager must call pcid `EnableDevice` BEFORE spawning the child | | **C4** | BAR request/release | `pci_request_regions` / `pci_release_regions` | channel open (exclusive `ENOLCK`) + BAR map via `pcid_interface::map_bar` | P0 | Resolved at v3.0: `/bind` never existed; claim == channel (P0-1) | | **C5** | BAR map / unmap | `pci_ioremap_bar` / `pci_iounmap` | child `scheme:memory/physical@` via `redox_driver_sys::pci::PciDevice::map_bar` | P0 | Not a manager task — child uses `redox-driver-sys` directly | | **C6** | Bus master on/off | `pci_set_master` / `pci_clear_master` | `set_bus_master(pci_addr, true)` | P0 | driver-manager sets on probe, clears on remove | | **C7** | Allocate IRQ vectors | `pci_alloc_irq_vectors` | `pci_alloc_vectors(pci_addr, min, max, flags) -> vector_count` | P0 | driver-manager proposes; child daemon allocates via `PcidClient` | | **C8** | Resolve vector → IRQ handle | `pci_irq_vector` | `pci_vector_handle(pci_addr, index) -> scheme:irq fd` | P0 | child uses `scheme:irq` directly | | **C9** | Runtime PM | `pci_pm_runtime_*` | `set_power_state(pci_addr, D0\|D3hot\|D3cold)` | P1 | pcid `SetPowerState` request exists; driver-manager exposes it (lands in **D2**) | | **C10** | Save/restore config space | `pci_save_state` / `pci_restore_state` | child uses `PcidClient::read_config()` | P1 | not a manager concern | | **C11** | Driver override | sysfs `driver_override` | `set_driver_override(pci_addr, driver_name)` | P1 | driver-manager exposes it as a scheme op (writes `pci_addr/override`) — **D2** | | **C12** | Config space read/write | `pci_read_config_*` | child uses `PcidClient::read_config() / write_config()` | P0 | not a manager concern | | **C13** | AER error recovery | `pci_error_handlers` + `pcie_do_recovery` | `Driver::on_error(error_kind) -> RecoveryAction` | P2 | Lands in **D2** (AER recovery is part of the modern technology surface) | | **C14** | Hotplug events (PDC / DLLSC / MRL) | `pciehp_*` | `manager.subscribe_hotplug() -> HotplugEvent` | P1 | Requires event-driven scheme:pci surface; **D3** delivers event-driven hotplug | | **C15** | DMA mask / IOMMU | `dma_set_mask` + `iommu_device_use_default_domain` | `set_dma_mask(pci_addr, bits)` + `iommu_assign_group(pci_addr)` | P2 | iommu daemon present (`local/recipes/system/iommu/`); wiring lands in **D2** (modern tech surface) | | **C16** | Find capabilities | `pci_find_capability` / `pci_find_ext_capability` | child uses `redox_driver_sys::pci::PciDevice::find_capability` | P0 | not a manager concern | | **C17** | INTx on/off | `pci_intx` | child via `PcidClient` | P1 | not a manager concern | | **C18** | System PM (suspend/resume) | `pci_pm_*` | `Driver::suspend() / resume()` callbacks via manager | P2 | driver-manager keeps a registry of bound drivers for the systemd-supervisor to call; **D2** | **Source-of-truth invariant:** C7 (vector allocation) is implemented inside pcid itself, not in driver-manager. driver-manager's role is to (a) call `enable_device` through pcid before spawning, (b) hand the channel FD to the child, and (c) call `remove` (which clears bus master + sends ULP/cleanup requests) when a device disappears from hotplug. The same split holds for C5, C12, C16, C17: those are the child's contract via `redox-driver-sys`. ### 2.4 boot-timeline and observability alignment Note: the "Priority" column reuses P0/P1/P2 as capability-priority labels (the same priority ladder used in § 2.3) — *not* phase references. Capacity deliveries for these priorities land in the § 5 D-Phase track (P0 set in D1; P1 set in D2/D3; P2 set in D4). AER-aware `reset` handling (P1 here) is part of D2's modern-technology surface. | Linux surface | driver-manager equivalent | Status | Priority | |---|---|---|---| | `dmesg` `pci ... BAR X set to ...` | `BOOT_TIMELINE_PATH = /tmp/redbear-boot-timeline.json` (already present) | ✅ exists | (D0) | | `journalctl -k` | `scheme:driver-manager:/events` (read-only ring buffer, 256 lines) | ✅ exists | (D0) | | `lspci -v` | `scheme:driver-manager:/devices/` (vendor / device / class / driver / enabled=true) | 🟡 partial | P0 | | `lspci -vv -s ...` + `lspci -xxx -s ...` | not exposed | not yet | P0 | | `find /sys/bus/pci/devices -name reset` | not exposed | not yet | P1 — needed for AER + reboot (**D2**) | | `pci=nomsi` kernel cmdline | `REDBEAR_DRIVER_MANAGER_FLAGS=disable_msi` env | not yet | P1 | | `pci=realloc=` | not exposed | not yet | P2 | | `lspci -tv` (tree) | `scheme:driver-manager:/tree` (planned) | not yet | P2 | --- ## 3. Target architecture ### 3.1 Process model (post-migration) ``` ┌─────────────────────────────────────────────┐ │ DRIVER-MANAGER (PID 1 child) │ │ ▸ Subscribes to /scheme/pci as a client │ │ ▸ Owns Driver trait objects from TOML │ │ ▸ Maintains Bus → Device → Driver graph │ │ ▸ Claims via channel open (ENOLCK) │ │ ▸ Spawns driver daemons with: │ │ PCID_CLIENT_CHANNEL= │ │ PCID_SEGMENT / PCID_BUS / PCID_DEVICE │ │ PCID_FUNCTION (Red Bear P4 contract) │ │ ▸ Registers scheme:driver-manager │ │ ▸ Writes /tmp/redbear-driver-params/... │ │ ▸ Writes /tmp/redbear-boot-timeline.json │ │ ▸ On hotplug (P1): detects add/remove │ │ ▸ On AER (P5): invokes error handler │ └───────────────────┬─────────────────────────┘ │ ┌───────────────────────────┼──────────────────────────┐ ▼ ▼ ▼ ┌────────────────────┐ ┌────────────────────┐ ┌────────────────────┐ │ PCID │ │ SCHEME:PCI │ │ REDOX-DRIVER-SYS │ │ (Canonical PCI │ │ (per-device │ │ (registered │ │ scheme owner) │◀──│ channel+bind+ │ │ quirk surface) │ │ │ │ config+feature) │ │ /scheme:driver-sys│ └─────────┬──────────┘ └─────────┬──────────┘ └────────────────────┘ │ │ │ /scheme/memory │ │ /scheme/irq │ │ /scheme:acpi │ │ /scheme/iommu (P5) │ ▼ ▼ ─────────── KERNEL ─────────── ``` ### 3.2 New component list | Component | Lives at | Source-of-truth | Phase | |---|---|---|---| | `driver-manager` daemon | `local/recipes/system/driver-manager/source/` | local recipe (Cat 1) | built in **D0–D5**, enabled at **C0** | | `driver-manager-config` package | `local/recipes/system/driver-manager-config/` (NEW) | local recipe (Meta) | **D4** (policy layer) | | `/etc/driver-manager.d/*.toml` configs | NEW dir, shipped by `driver-manager-config` | policy | **D4** | | `/lib/drivers.d/*.toml` | NEW dir, per-config files | match tables | **D1** (format); **D4** (content) | | `00_driver-manager.service` | `local/sources/base/init.d/` | service | **C0** (created dormant); **C3** (active) | | `40_driver-manager-initfs.service` | `local/sources/base/init.initfs.d/` | service | **C0** (dormant); **C2** (active blocking) | | `local/recipes/system/driver-params` | already exists; extends to consume `scheme:driver-manager` rather than its own bound-text-parsing | observer | **C1** (switch over) | | `redbear-driver-policy` package | `local/recipes/system/redbear-driver-policy/` (NEW) | curated package | **D4** (created); **C3** (packaged) | ### 3.3 What changes for `pcid-spawner` (NOT deleted, demoted) The v1.1 D/C phase restructure changes pcid-spawner's role as follows: | Track / Phase | pcid-spawner state | |---|---| | **D-phase (D0–D5)** | **No change.** pcid-spawner remains the live boot path. driver-manager is being built locally but is NOT shipped, NOT packaged, NOT enabled. The boot path is identical to baseline. | | **C0** | `00_pcid-spawner.service` gains `ConditionPathExists=!/etc/driver-manager.d/disabled`. Service is dormant by default. | | **C1** | driver-manager runs in `--observe` mode (writes BOOT_TIMELINE, does NOT spawn). pcid-spawner is still the actual spawner. | | **C2** | `40_driver-manager-initfs.service` becomes `oneshot` blocking in initfs; pcid-spawner initfs service becomes fallback only via `ConditionPathExists`. | | **C3** | `00_driver-manager.service` becomes the primary rootfs spawner. `00_pcid-spawner.service` is retained as fallback only (idem for initfs variant). | | **C4** | pcid-spawner source tree receives a final commit on the `submodule/base` branch documenting the maintenance-mode status. **Never deleted.** | ### 3.4 Wire-level contracts that MUST stay invariant | Contract | Description | Invariant | |---|---|---| | **C-ENV-1** | `PCID_CLIENT_CHANNEL=` is passed to every spawned driver daemon | Preserved by `config.rs::probe()` already | | **C-ENV-2** | `PCID_SEGMENT`/`PCID_BUS`/`PCID_DEVICE`/`PCID_FUNCTION` env vars (Red Bear P4) | Preserved — driver-manager's probe path must add them | | **C-ENV-3** | Program resolution: absolute OR `/usr/lib/drivers/` | Preserved — same prefix logic moves to driver-manager | | **C-CHAN-1** | Per-device `channel` open in scheme:pci yields mutual-exclusion (ENOLCK to second opener) | Not the responsibility of driver-manager — that's pcid. driver-manager must use `bind` (NOT `channel`) so multi-driver retry can re-probe without consuming the lock. **Confirm with pcid that `bind` is also exclusive, or document the asymmetry.** | | **C-CHAN-2** | Drivers call `PciFunctionHandle::connect_default()` and get a working bincode channel via the FD | Continues unchanged | | **C-SVC-1** | Every service that previously `requires_weak=00_pcid-spawner.service` gains `requires_weak=00_driver-manager.service` as an alternative. Driver-manager has `requires_weak=00_pcid-spawner.service` for fallback coordination. | Provides fallback-safety | | **C-DAEMON-1** | `daemon::Daemon::spawn()` blocks parent on child ready | driver-manager must use the same primitive to preserve the boot-order guarantee — ahcid/nvmed up before redoxfs mounts | | **C-RECIPE-1** | `recipes/core/base/drivers/pcid-spawner/recipe.toml` keeps `path = "../../../local/sources/base/drivers/pcid-spawner"` | Never changes | | **C-SCHEME-1** | `scheme:driver-manager` exposes: `/devices`, `/devices/`, `/bound`, `/events` (read-only) | Already present | | **C-PARAM-1** | `driver-params` reads from `/scheme/driver-manager/bound` (instead of its current text-parsing of the bound file) | **C1** wiring | ### 3.5 Module / crate dependencies (target state) ``` recipes/system/driver-manager/source/Cargo.toml ─── D0 plus phase-by-phase additions ├── redox-driver-core (already: local/recipes/drivers/redox-driver-core) ├── redox-driver-pci (already: local/recipes/drivers/redox-driver-pci) ├── redox-driver-sys (NEW dep ─ added at D4; previously optional, now required) ├── pcid_interface (already: local/sources/base/drivers/pcid) ├── redox-scheme (already: local/sources/redox-scheme) ├── redox_syscall (already: local/sources/syscall, features=["std"]) ├── log, toml, serde (already) ├── event-stream (NEW in D3 — for hotplug event consumption) ├── bitflags (NEW in D2 — for CapabilityFlag aggregation) └── [patch.crates-io] (already: redox_syscall, libredox, redox-scheme) ``` `pcid-spawner` Cargo.toml is untouched (it stays in the base submodule fork for fallback). No retroactive changes to `daemon::Daemon::spawn`, `PciFunctionHandle::connect_default`, or any of the 17 driver daemons. --- ## 4. Critical risk register | # | Risk | Severity | Mitigation | |---|---|---|---| | **R1** | Double-spawn race: driver-manager and pcid-spawner both spawn the same driver daemon | 🔴 BLOCKING | **C1** sequencing: driver-manager runs **only** in `--observe` mode first. The actual spawn is gated by `spawn_enabled` flag set by the C1 exit gate. `00_driver-manager.service` is dormant in C0; observable in C1; primary in C3. | | **R2** | Driver daemon crashes after spawn, no one restarts it | 🔴 BLOCKING | driver-manager persists `bound_devices` map to `/tmp/redbear-driver-params/`. On `WAIT_FOR_REAPPEAR` per-driver (delivered in **D2**) the manager retries after a 5s backoff. systemd `Restart=` on the driver service files provides the surface-process fallback (**D4**). | | **R3** | The match table migration misses a vendor/device pair | 🔴 BLOCKING | **D1** adds "no-match ↔ spin in driver-manager, no spawn" tests for the existing 17 drivers. **C1** runs **both** managers side-by-side and emits `unbound_device_addr=` lines to `BOOT_TIMELINE` for any device the new manager misses but pcid-spawner bound. | | **R4** | The `bind` vs `channel` claim differs in exclusivity | 🟡 HIGH | **D1** step is a QEMU test that opens `bind` from one driver and `channel` from another; verifies the latter gets ENOLCK. Document the asymmetry. | | **R5** | Initfs switchroot breaks (storage drivers must be ready before redoxfs mounts) | 🔴 BLOCKING | **C2** keeps `40_pcid-spawner-initfs.service` available (via `ConditionPathExists`). `40_driver-manager-initfs.service` is added in **observation** mode at **C0** and only switches on at **C2** once the storage path passes on at least 3 hardware configs (QEMU virtio + AMD NVMe + Intel SATA). | | **R6** | `redox-driver-sys` quirks not consulted during spawn decisions | 🟡 MEDIUM | **D4** phase. Until then, the kernel-side MSI/MSI-X fallback in pcid remains authoritative. No regression on bare metal. | | **R7** | Atomic patch governance failure: live source edit goes unmirrored | 🟡 (procedural) | Every source edit during this plan is committed to the `submodule/base` branch (for `pcid-spawner` edits) or as commits within `local/recipes/system/driver-manager/source/` (which is a local-recipe tree, not a fetched source tree). Per `local/AGENTS.md` DURABILITY POLICY. | | **R8** | The new `scheme:driver-manager` collides with `scheme:driver-params` | 🟡 MEDIUM | C-PARAM-1 above resolves this: `driver-params` becomes a thin observer over `scheme:driver-manager:/bound`, no separate parsing path. Wired at **C1**. | | **R9** | The migration leaves the repo in a state that cannot fall back | 🔴 BLOCKING | During **D-phase**, no boot path is affected (driver-manager is not in the system). During **C-phase**, both managers may run; pcid-spawner is the fallback at every cutover step (`ConditionPathExists=!/etc/driver-manager.d/disabled` gates it). **At no phase is the boot path single-point-of-failure.** | | **R10** | The TOML match-table migration produces a silent NO-OP for an edge device (e.g., ID 0x1234:0x5678 not in any entry → driver never binds) | 🟡 HIGH | **D1** implements `missing_match = warn` so any unresolved match is logged. QEMU tests with the 17 known drivers verify each entry before **C3**. | | **R11** | The `redox-driver-core` `DeviceManager::probe_device` locks the entire manager mutex for the duration of a probe, blocking `retry_deferred` for slow drivers | 🟡 MEDIUM | **D2** introduces per-driver `Mutex` for finer-grained concurrency; manager's outer mutex held only during dispatch. | | **R12** | Device hot-add during switchroot causes race with pcid (which may re-enumerate) | 🟡 MEDIUM | Hotplug is **off** during initfs → rootfs transition. driver-manager starts in `--hotplug=off` until switchroot completes. | | **R13** | D-phase work produces a stub or workaround instead of comprehensive code | 🔴 BLOCKING | **`local/scripts/driver-manager-audit-no-stubs.py`** (D4 deliverable) is the formal gatekeeper. Static analysis + QEMU integration test. Any D-phase work that violates § 0.5 fails the D4 audit and blocks D5 ratification. **No partial-credit D5 exit.** | | **R14** | driver-manager enters a boot path before D5 ratification (i.e., someone packages it earlier than planned) | 🔴 BLOCKING | Build-system guard: `local/scripts/build-redbear.sh` and the cookbook CI refuse any commit that adds `driver-manager` to `[packages]` in `config/redbear-*.toml` during D-phase. Documented in § 0.6. | ### Out-of-scope (deferred to OTHER plans) - USB / ACPI / platform buses → `local/docs/USB-IMPLEMENTATION-PLAN.md`, `local/docs/ACPI-IMPROVEMENT-PLAN.md` - GPU render / DRM completion → `local/docs/DRM-MODERNIZATION-EXECUTION-PLAN.md` - Wi-Fi / Bluetooth → `local/docs/WIFI-IMPLEMENTATION-PLAN.md`, `BLUETOOTH-IMPLEMENTATION-PLAN.md` - IRQ / MSI-X quality → `local/docs/IRQ-AND-LOWLEVEL-CONTROLLERS-ENHANCEMENT-PLAN.md` - IOMMU runtime proof → still QEMU-only per HardWARE matrix - Replacement of `pcid` (the scheme:pci owner) — far future, no decision today --- ## 5. Phased migration plan The migration has **two tracks** operating sequentially, not interleaved: - **D-Phase (Parallel Development).** driver-manager is being built; pcid-spawner remains the live boot system. No boot path is affected. This phase starts at D0 (current state) and continues through D5 (feature-complete gate). The team's parallel development work lives here. - **C-Phase (Cutover & Validation).** driver-manager is fully built; the boot path is switched over from pcid-spawner to driver-manager in stages. C0 starts only after D5 + operator ratification. **Authority:** the § 0.6 Parallel Development constraint is binding. driver-manager does NOT enter any boot path until D5 ratifies. The original v1.0 P0–P6 dual-mode strategy is folded into the C-phases. ### 5.1 D-Phase — Parallel Development **State during D-Phase:** - pcid-spawner is the boot path in every `redbear-*.toml`. - driver-manager is built locally (committed to `local/recipes/system/driver-manager/source/`) but NOT shipped. - driver-manager has no `00_driver-manager.service`. - No files in `/etc/driver-manager.d/` are read by the live system. - No `[packages]` entry contains `driver-manager`. - The team's work is recorded in commits to the local recipe source. #### Phase D0 — Foundation (current state) **Status (2026-07-20):** partially complete. **What exists:** - `redox-driver-core` framework: `Bus` trait, `Driver` trait, `DeviceManager`, `DriverMatch`, `DriverParams`, `ProbeEvent`, `ProbeResult`. Compiled with 12 unit tests. - `redox-driver-pci::PciBus` reads `/scheme/pci/`, parses PCI config space, returns `DeviceInfo` with vendor/device/class/subclass/prog_if/revision/ subsystem IDs. - `local/recipes/system/driver-manager/source/src/{main.rs,config.rs,scheme.rs,hotplug.rs,exec.rs}` — 1250 lines compiling to a 783KB ELF. - `scheme:driver-manager` registered with `/devices`, `/bound`, `/events`, `/devices/` paths (read-only). - Boot timeline JSON at `/tmp/redbear-boot-timeline.json`. **What does NOT yet exist** (D1–D5 work): - Linux 7.x capability bridge: C9, C11, C13, C14, C15, C17, C18 are absent - Modern technology surface integration (SMP-aware concurrent probe, S/P-state hooks, runtime PM, AER) - Event-driven hotplug (current code polls every 2s) - Quirk integration with `redox-driver-sys` (no `redox-driver-sys` import in `source/Cargo.toml`) - Format-coexistence TOML loader (current loader only accepts new `[[driver]]` format) **Exit criteria for D0:** 1. `cargo build --release -p driver-manager` clean. 2. `cargo test -p redox-driver-core` 12/12 green. 3. `local/recipes/system/driver-manager/target/x86_64-unknown-redox/stage/usr/bin/driver-manager` exists. 4. No `00_driver-manager.service` in any init.d. 5. No `driver-manager = {}` in any `[packages]` section. #### Phase D1 — Linux 7.x capability bridge (target: 6–10 weeks) **Preconditions:** D0 exit criteria met. **Goal:** Implement every P0 capability from § 2.3 (C1, C2, C3, C4, C5, C6, C7, C8, C12, C16). **Deliverables:** - `redox-driver-core::driver::Driver` trait gains full `suspend()` / `resume()` / `on_error()` / `params()` implementations with concrete behaviour (not stubs — see § 0.5). - `redox-driver-core::bus::Bus` trait gains event-driven `subscribe_hotplug()` implementation in `PciBus`. - `local/recipes/system/driver-manager/src/manager-probe.rs` (new module) handles the SpawnDecision committee (C2', C3, C4, C6). - Format-coexistence TOML loader accepting both `[drivers]` (legacy pcid-spawner) and `[[driver]]` (driver-manager) formats from the same directory tree. - New test script `local/scripts/test-driver-manager-parity.sh` (used in C1, but drafted here). **Exit criteria for D1:** 1. Every P0 capability of C1–C18 is implemented and unit-tested. 2. `local/scripts/test-driver-manager-parity.sh` returns identical bound sets under both formats. 3. Integration test (QEMU + all 17 drivers) shows driver-manager can shadow pcid-spawner exactly. #### Phase D2 — Modern technology surface (target: 8–12 weeks) **Preconditions:** D1 exit criteria met. **Goal:** Integrate SMP-aware concurrent probe, C/P-state coordination, runtime PM hooks, IOMMU groups, MSI-X vector allocation, AER recovery (see § 0.4 for the full tech surface). **Deliverables:** - `redox-driver-core::manager::DeviceManager::probe_device` becomes truly concurrent (`std::thread::scope` or `rayon`, `max_concurrent_probes` enforced). - MSI-X vector allocation with per-vector fds exposed via `redox-driver-sys::irq::MsixTable`. - Per-driver P-state advisory publisher (interacts with `cpufreqd`). - C-state coordination hook with `cpufreqd` / `thermald`. - IOMMU group registration via `local/recipes/system/iommu/`. - D-state transitions (D0 ↔ D3hot ↔ D0) through pcid's `SetPowerState` request. **Exit criteria for D2:** 1. Concurrent probe dispatch verified (`max_concurrent_probes = 4` shows 4-way parallelism in QEMU timings). 2. Per-driver P-state advisory verified on real AMD/Intel hardware. 3. IOMMU-group-aware binding demonstrated on at least one QEMU + vfio-passthrough run. 4. Runtime PM suspend/resume callback chain verified. #### Phase D3 — Hotplug event-driven (target: 4–6 weeks) **Preconditions:** D2 exit criteria met. **Goal:** Replace polling-based hotplug with event-driven subscription. **Deliverables:** - `Bus::subscribe_hotplug()` returns `HotplugSubscription` mapping to a real event fd (via `Bus::poll_hotplug_events()` or equivalent). - `PciBus` consumes `/scheme/pci/events` (requires pcid scheme event delivery — feature request to pcid maintainer). - `Manager::hotplug_loop()` becomes event-driven, removing the 2-second poll entirely. **Exit criteria for D3:** 1. Hotplug event arrival latency < 200 ms on QEMU synthetic add/remove. 2. Real-hardware hotplug (PCIe Native or USB) verified on at least one AMD and one Intel bare-metal target. #### Phase D4 — Quirk integration + comprehensive audit (target: 6–8 weeks) **Preconditions:** D3 exit criteria met. **Goal:** Wire `redox-driver-sys::PciQuirkFlags` into bind/remove decisions; complete feature audit confirming § 0.5 compliance. **Deliverables:** - `local/recipes/system/driver-manager/source/Cargo.toml` adds `redox-driver-sys` as path dep. - `manager-probe.rs` consults `PciQuirkFlags::NO_MSIX`, `NO_PME`, `NEED_FIRMWARE`, `DISABLE_ACCEL`, etc., during spawn decisions. - Audit script `local/scripts/driver-manager-audit-no-stubs.py` runs against the source tree and confirms: every public trait method has a concrete implementation, no `unimplemented!()`, no `todo!()`, no `#[allow(dead_code)]` for production code paths, no `Ok(())` defaults in trait methods that have a real responsibility (per § 0.5 matrix). - Quirk policy delivered: `/etc/driver-manager.d/{00-blacklist.conf, 50-amdgpu.toml,autoload.d/ntsync.conf}` patterns work as designed. **Exit criteria for D4:** 1. `driver-manager-audit-no-stubs.py` reports zero violations. 2. Quirk-driven spawn decisions match expected behaviour (e.g., `DISABLE_ACCEL` causes `redox-drm --no-render` to be invoked). 3. Hardware-validation-matrix AMD Threadripper + Intel Alder Lake both pass. #### Phase D5 — Feature-complete gate (audit before cutover) **Preconditions:** D4 exit criteria met, **operator ratification**. **Goal:** Formal declaration that driver-manager is feature-complete and ready to cut over. **Deliverables:** - Audit document `local/docs/evidence/driver-manager/D5-AUDIT.md` listing every C1–C18 capability with status (✅ Production / 🟡 Build-grade / 🔴 Not Implemented). - Updated `local/docs/HARDWARE-VALIDATION-MATRIX.md` with driver-manager rows. - This document's `Last reviewed` line updated to the D5 completion date. - Operator's written ratification (chat log, email, or commit message). **Exit criteria for D5:** 1. Every entry on the C1–C18 table is at least 🟡 Build-grade. 2. The § 0.5 no-stub audit is clean (audit script returns 0). 3. Hardware validation matrix passes on at least one AMD and one Intel profile with at least 3 driver categories each (storage, network, GPU). 4. The § 0.2 success criteria 1–6 are met (criteria 7–10 are C-phase criteria). 5. Operator has ratified in writing. **At this point**, the D-phase work is **OVER**. The C-phase begins. ### 5.2 C-Phase — Cutover & Validation The C-phase begins only after D5 ratifies. The cutover is sequential, gated, and operator-ratified at every phase boundary. The cutover does NOT require pcid-spawner to be removed — it stays as a `ConditionPathExists` fallback. #### Phase C0 — Service wiring (dormant service file) **Preconditions:** D5 complete. **Goal:** Add the dormant service file and `[packages]` entry. Driver-manager remains inactive. **Deliverables:** - `local/sources/base/init.d/00_driver-manager.service` (NEW, dormant by default — never auto-starts). - `local/sources/base/init.initfs.d/40_driver-manager-initfs.service` (NEW, dormant by default). - `local/sources/base/init.d/00_pcid-spawner.service` gains `ConditionPathExists=!/etc/driver-manager.d/disabled` (auto-skip when driver-manager is operational; remains the actual spawner in C0). - `config/redbear-{mini,full,grub,device-services,greeter-services}.toml` add `driver-manager = {}` to `[packages]`. - `[packages]` removal of `pcid-spawner` does NOT happen in C0. **Acceptance test:** ``` [ BOOT ] init: 00_pcid-spawner.service running [ BOOT ] init: 00_driver-manager.service skipped (dormant) [ PASS ] C0: pcid-spawner still spawns; driver-manager binary present but inactive ``` **Exit criteria for C0:** 1. ISO boots identically to pre-C0 baseline. 2. `make lint-config` clean. 3. `scripts/validate-collision-log.sh` clean. 4. `driver-manager-audit-no-stubs.py` still clean. #### Phase C1 — Dual-mode observation **Preconditions:** C0 exit criteria met. **Goal:** driver-manager runs in `--observe` mode (no spawn). Both managers see the same devices. Parity confirmed before any actual spawn. **Deliverables:** - `00_driver-manager.service` runs in `--observe` mode (writes BOOT_TIMELINE, no spawn). - `00_pcid-spawner.service` is still the actual spawner. - Both managers write parity data to their BOOT_TIMELINE files. - `local/scripts/test-driver-manager-parity.sh` runs as a CI gate. **Acceptance test:** ``` [ BOOT ] driver-manager: enumerate begin (observe) [ BOOT ] driver-manager: enumeration complete: 17 bound (observe), 0 deferred [ BOOT ] pcid-spawner: spawn e1000d for 0000:00:03.0 [ BOOT ] driver-manager: 17/17 binds agree with pcid-spawner [ BOOT ] driver-manager: BOOT_TIMELINE written [ PASS ] C1: parity clean ``` **Exit criteria for C1:** 1. `test-driver-manager-parity.sh` clean in 5 back-to-back QEMU runs. 2. Real-hardware parity verified on AMD Threadripper + Intel Alder Lake. 3. Both managers' BOOT_TIMELINE files match. #### Phase C2 — Initfs switchover **Preconditions:** C1 exit criteria met, **operator ratification**. **Goal:** driver-manager becomes the initfs spawner (storage drivers). **Deliverables:** - `40_driver-manager-initfs.service` becomes `oneshot` (blocking) and replaces `40_pcid-spawner-initfs.service` in initfs. - pcid-spawner initfs service moves to `ConditionPathExists=!/etc/driver-manager.d/initfs-active` fallback. - `local/scripts/test-driver-manager-initfs.sh` clean. **Acceptance test:** ``` [ INITFS ] driver-manager-initfs: storage drivers ready (ahcid/nvmed/virtio-blkd/ided) [ INITFS ] redoxfs: mount /dev/redoxfs /scheme/root ✓ [ INITFS ] switchroot: /usr loaded [ PASS ] C2: initfs path via driver-manager ``` **Exit criteria for C2:** 1. Initfs-only QEMU run completes with driver-manager and the switchroot happens within 5 s. 2. AHCI + NVMe + virtio-blkd paths tested on at least one AMD and one Intel system. 3. pcid-spawner-initfs fallback can be activated by deleting `/etc/driver-manager.d/initfs-active`, and the boot still completes. #### Phase C3 — Rootfs switchover **Preconditions:** C2 exit criteria met, **operator ratification**. **Goal:** driver-manager becomes the primary rootfs spawner. **Deliverables:** - `00_driver-manager.service` becomes the primary rootfs spawner. - `00_pcid-spawner.service` is retained as fallback only. - `local/scripts/test-driver-manager-active.sh` runs end-to-end. - `driver-params` switches to consuming `scheme:driver-manager:/bound`. **Acceptance test:** ``` [ BOOT ] driver-manager: registered scheme:driver-manager [ BOOT ] driver-manager: load_all: 7 config files, 17 drivers registered [ BOOT ] driver-manager: enumeration complete: 17 bound, 0 deferred [ BOOT ] driver-manager: hotplug: starting event loop (event-driven) [ PASS ] C3: driver-manager is the active rootfs spawner ``` **Exit criteria for C3:** 1. `test-driver-manager-active.sh` clean in 5 back-to-back QEMU runs. 2. driver-params via scheme:driver-manager produces correct driver list. 3. parity test (C1's) keeps reporting identical binds. #### Phase C4 — Operator-ratified production cutover **Preconditions:** C3 exit criteria met, **operator ratification**, **two-week soak**, **three hardware reboots** with identical driver-bound sets. **Goal:** pcid-spawner moves to maintenance-mode fallback. Status rows update. **Deliverables:** - pcid-spawner source tree receives a final commit on `submodule/base` documenting the maintenance-mode status. - `local/docs/UPSTREAM-SYNC-PROCEDURE.md` § "driver-manager: Deferred" replaced with "driver-manager: production". - README.md status row updates. - `local/AGENTS.md` § PLANNING NOTES pointer updates. - Inline deferred comments in `config/redbear-mini.toml:31` and `config/redbear-device-services.toml:9-13` removed. **Exit criteria for C4:** 1. Two-week soak completes with no `ConditionPathExists` guard firing. 2. Three consecutive bare-metal reboots produce identical driver-bound sets. 3. Hardware validation matrix shows parity or improvement on every row. 4. Operator ratification documented in `local/docs/evidence/driver-manager/C4-RATIFICATION.md`. **At no point is pcid-spawner DELETED.** It moves to "always-shipped, on-disk fallback" alongside `00_driver-manager.service`. --- ## 6. Per-phase dependency diagram The D-phase and C-phase tracks are **sequential** under § 0.6's parallel development constraint: ``` D-PHASE: Parallel Development C-PHASE: Cutover & Validation (driver-manager being built; (driver-manager enabled; pcid-spawner is the live system) pcid-spawner demoted to fallback) D0 ─► D1 ─► D2 ─► D3 ─► D4 ─► D5 ─── operator ratification + feature-complete gate ─── C0 ─► C1 ─► C2 ─► C3 ─► C4 │ │ │ │ │ │ │ │ │ │ │ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ fnd cap tech hp quk audit svc obs ifs rfs prod frame bridge face ev int (no stubs) wir dual sw sw cut present +PM ent- gra- + HW validate e mode itc itc over +AER drive ted dom dor ove ove (op +IOM (dor r r era MU man (do (do tor +MS t) t) t) ra I-X tif ied ) │ │ └──── During D-phase, pcid-spawner remains the boot path. During C-phase, both No boot path is changed. managers may run; pcid-spawner is the fallback at every cutover step. ``` **Phase key:** - D0: Foundation (current state) - D1: Linux 7.x capability bridge (C1–C18 P0 set) - D2: Modern technology surface (SMP, S/P states, runtime PM, IOMMU, AER, MSI-X) - D3: Hotplug (event-driven) - D4: Quirk integration + comprehensive audit (no stubs) - D5: Feature-complete gate (operator ratification) - C0: Service wiring (dormant service file) - C1: Dual-mode observation - C2: Initfs switchover - C3: Rootfs switchover - C4: Operator-ratified production cutover The workstream structure deliberately mirrors `local/docs/CONSOLE-TO-KDE-DESKTOP-PLAN.md` (Phase 1–5) and `local/docs/DRM-MODERNIZATION-EXECUTION-PLAN.md` (Workstream A–E) to keep the project's planning grammar consistent. --- ## 7. Test scripts (`local/scripts/`) All scripts land in `local/scripts/` per project convention and follow the existing naming (`test-X.sh` for shell, `test-X-y.sh` for variants). Each script returns exit 0 on success, emits a `[PASS]` line, and writes a log to `local/docs/evidence/driver-manager/`. | Script | Phase (D / C) | Purpose | Exit code signal | |---|---|---|---| | `test-driver-manager-parity.sh` | **C1** (drafted in D1) | Both managers active, observation only; verify they agree on every device-id-to-driver mapping | 0 = same set bound | | `test-driver-manager-active.sh` | **C3** | driver-manager primary; pcid-spawner fallback; verify all 17 drivers | 0 = all expected drivers present | | `test-driver-manager-initfs.sh` | **C2** | initfs use only; verify storage drivers come up before redoxfs | 0 = redoxfs mounted | | `test-driver-manager-hotplug.sh` | **D3** (gate) | Hotplug add/remove cycle; unbind/rebind sequence | 0 = unbind + rebind within budget | | `test-driver-manager-pm.sh` | **D2** (gate) | Suspend/resume cycle, parameter write-through | 0 = clean suspend+resume | | `test-driver-manager-cutover.sh` | **C4** | Final acceptance: identical driver set before/after cutover | 0 = no diff in bound-set logs | | `driver-manager-audit-no-stubs.py` | **D4** (gate) | Static analysis that the source contains no `unimplemented!()`, no `todo!()`, no `Ok(())` trait-method defaults — per § 0.5 | 0 = no violations | | `test-driver-manager-no-stubs-qemu.sh` | **D4** (gate) | QEMU run with synthesized edge-case devices exercising every P0 capability C1–C18 | 0 = every test bus emits one bind event | --- ## 8. Cross-cutting concerns ### 8.1 GPU / DRM The `redox-drm` driver daemon currently relies on `PciFunctionHandle::connect_default()` plus `redox-driver-sys::pci::PciDevice`. driver-manager must continue passing `PCID_CLIENT_CHANNEL` for `redox-drm` to receive a working channel. The match table that triggers `redox-drm` (`30-graphics.toml` already in `config/redbear-device-services.toml`) is consumed by driver-manager; no driver side changes. The `redox-driver-sys::PciQuirkFlags` policy is consulted in **D4** (`NEED_FIRMWARE`, `DISABLE_ACCEL`, `NO_MSIX`). AMD-specific decisions live in `local/docs/DRM-MODERNIZATION-EXECUTION-PLAN.md` — the present plan does not re-open those decisions, it only carries them into the manager's match-time decision logic. ### 8.2 USB `xhcid`, `ehcid`, `ohcid`, `uhcid`, `usbhubd`, `usbscsid`, `usbhidd`, `usbaudiod` all spawn from `/lib/drivers.d/{20-usb,70-usb-class}.toml`. These TOMLs exist in `config/redbear-device-services.toml` (lines 116-490) but are inert today. driver-manager must wake them correctly during **C3**. The Bus trait will gain a `UsbBus` in `local/docs/USB-IMPLEMENTATION-PLAN.md`; that is **out of scope** for this migration. ### 8.3 Audio `ihdad`, `ac97d`, `sb16d` are in `50-audio.toml`. These spawn late (no initfs dependency); driver-manager handles them as ordinary bound drivers with priority below storage/network. CachyOS's audio-power management patterns (`20-audio-pm.rules`) are reflected in **D4**'s `depends_on` and `hotplug` hooks for these drivers. ### 8.4 Storage init path This is the highest-risk surface. `ahcid`, `ided`, `nvmed`, `virtio-blkd`, `usbscsid`, `usb-bot` MUST be ready before redoxfs mounts. Phase **C2**'s initfs migration has its own gate, and a fallback (`40_pcid-spawner-initfs.service` via `ConditionPathExists`) is required at every C-phase before **C4**. ### 8.5 Cross-config consistency The three compile targets (`redbear-mini`, `redbear-full`, `redbear-grub`) all include init services that depend on `00_pcid-spawner.service`. All three need the same `00_driver-manager.service` substitution. The change is mechanical but must be applied to every `[service].requires_weak` reference and every `[[files]]` install in the same PR. `make lint-config` enforces consistency. ### 8.6 Doc references After **C3**: - `local/AGENTS.md` § PLANNING NOTES gets a one-liner pointing here. - `local/docs/CONSOLE-TO-KDE-DESKTOP-PLAN.md` Phase 1 row updates from "🟡 | in progress" to "🟡 | driver-manager parity accepted". - `local/docs/PATCH-GOVERNANCE.md` § "Local recipe priority vs upstream WIP" notes that `local/recipes/system/driver-manager` is the canonical owner. - `local/docs/UPSTREAM-SYNC-PROCEDURE.md` § "driver-manager: Deferred" replaced with "driver-manager: live (`00_driver-manager.service`)". After **C4** (production cutover): - README.md status row updates to ✅. - `config/redbear-mini.toml:31` and `config/redbear-device-services.toml:9-13` inline deferred comments are removed (no longer accurate once driver-manager is live). - `local/docs/UPSTREAM-SYNC-PROCEDURE.md` § "driver-manager: Deferred" replaced with "driver-manager: production". ### 8.7 Branch / submodule policy Per `local/AGENTS.md` § BRANCH AND SUBMODULE POLICY, no new submodule is created. driver-manager stays a **local recipe** under `local/recipes/system/driver-manager/`. This is preserved at every phase. The 9 declared submodules remain unchanged. --- ## 9. Appendices ### 9.1 File map (post-migration, target end state) **Created (tracked):** ``` local/recipes/system/driver-manager/source/src/ ├── main.rs (modified at D3, D4, C1, C3 across their phases) ├── config.rs (modified at D1 [format coexistence], D2 [PM hooks], D3 [event-driven], D4 [quirk integration]) ├── scheme.rs (modified at D2 [PM scheme surface], D4 [quirk reporting]) ├── hotplug.rs (rewritten at D3 — event-driven) ├── exec.rs (removed at D0; spawn was already inlined in config.rs::probe()) ├── driver-probe.rs (NEW at D1 [SpawnDecision committee], evolves D2 [PM dispatch], D4 [AER routing]) └── errors.rs (NEW at D0 [error-tag normalisation], evolves D2 [PM error codes]) local/recipes/system/driver-manager/recipe.toml (no change) local/recipes/system/driver-manager/source/Cargo.toml (deps added at D2 [bitflags], D3 [event-stream], D4 [redox-driver-sys]) local/sources/base/init.d/00_driver-manager.service (NEW dormant at C0; evolves C1, C3) local/sources/base/init.initfs.d/40_driver-manager-initfs.service (NEW dormant at C0; becomes blocking at C2) local/config/driver-manager.d/ (NEW at D4) ├── 00-blacklist.conf ├── autoload.d/ntsync.conf ├── 50-amdgpu.toml └── initfs.manifest local/scripts/test-driver-manager-{parity,active,initfs,hotplug,pm,cutover}.sh (one per phase — see § 7) local/scripts/driver-manager-audit-no-stubs.py (NEW at D4; gates D5) local/recipes/system/driver-params/source/src/main.rs (modified at C1 to consume scheme:driver-manager:/bound) local/recipes/system/redbear-driver-policy/ (NEW at D4; curated policy package; packaged at C3) ``` **Modified (kept tracked):** ``` config/redbear-mini.toml (C0: driver-manager added to [packages]; superseded comments at C4) config/redbear-full.toml (C0: same) config/redbear-grub.toml (C0: same) config/redbear-greeter-services.toml (C0: same) config/redbear-device-services.toml (C0 + D4: driver-manager config inclusion) local/docs/UPSTREAM-SYNC-PROCEDURE.md (§ driver-manager: Deferred -> live at C3; -> production at C4) local/docs/CONSOLE-TO-KDE-DESKTOP-PLAN.md (Phase 1 row update at C3) local/docs/HARDWARE-VALIDATION-MATRIX.md (multiple rows updated at D5) README.md (status row at C4) AGENTS.md (no change beyond pointer) local/AGENTS.md (PLANNING NOTES section gains pointer) ``` **Untouched (preserved for fallback throughout D/C phases and after C4):** ``` local/sources/base/drivers/pcid-spawner/ (entire tree — fallback for life) local/sources/base/drivers/pcid/ (unchanged — still the scheme:pci owner) local/sources/base/init.d/00_pcid-spawner.service (becomes dormant fallback service at C3) local/sources/base/init.initfs.d/40_pcid-spawner-initfs.service (becomes dormant fallback at C2) local/patches/base/ (all P-numbered patches preserved) local/recipes/core/pcid-spawner/recipe.toml (path-fork unchanged) recipes/core/base/drivers/pcid-spawner/ (path-fork path unchanged) The 17 driver daemons' source trees and Cargo.tomls. ``` ### 9.2 Environment variable contract (preserved) | Var | Source | Consumer | Format | |---|---|---|---| | `PCID_CLIENT_CHANNEL` | pcid-spawner (legacy), driver-manager (new) | driver daemon via `PciFunctionHandle::connect_default()` | ASCII decimal fd | | `PCID_SEGMENT` | both | driver daemon | 4-hex (e.g., `0000`) | | `PCID_BUS` | both | driver daemon | 2-hex (e.g., `03`) | | `PCID_DEVICE` | both | driver daemon | 2-hex (e.g., `0a`) | | `PCID_FUNCTION` | both | driver daemon | decimal | | `REDBEAR_DRIVER_MANAGER_ACTIVE` | env (env file) | driver-manager | `0` = observation; non-zero = spawn | | `DRIVER_PARAMS_LOG` | existing | driver-params | one of `trace`/`debug`/`info`/`warn`/`error` | | `DRIVER_PARAMS_BOUND_PATH` | existing | driver-params | path string | | `INIT_NOTIFY` | init | driver-params, driver-manager (from C0 onwards) | int fd | ### 9.3 Capability-to-driver matrix | Driver daemon | C3 enable | C4 bar request | C5 map | C6 bus master | C7 vectors | C12 config R/W | C16 caps | C17 INTx | |---|---|---|---|---|---|---|---|---| | `ahcid` | ✅ via PCID_CLIENT_CHANNEL | implicit via connect | driver-side via `redox-driver-sys` | yes | MSI via pcid client | yes | yes | yes | | `ided` | same | same | same | yes | n/a | yes | yes | yes | | `nvmed` | same | same | same | yes | MSI-X | yes | yes | yes | | `virtio-blkd` | same | same | same | yes | n/a | yes | yes | yes | | `e1000d` | same | same | same | yes | MSI via `redox-driver-sys` | yes | yes | yes | | `rtl8168d` | same | same | same | yes | MSI | yes | yes | yes | | `rtl8139d` | same | same | same | yes | INTx | yes | yes | yes | | `ixgbed` | same | same | same | yes | MSI-X | yes | yes | yes | | `virtio-netd` | same | same | same | yes | n/a | yes | yes | yes | | `ihdgd` | same | same | same | yes | MSI-X | yes | yes | yes | | `virtio-gpud` | same | same | same | yes | n/a | yes | yes | yes | | `xhcid` | same | same | same | yes | MSI-X | yes | yes | yes | | `ihdad` | same | same | same | yes | MSI | yes | yes | yes | | `ac97d` | same | same | same | yes | INTx | yes | yes | yes | | `vboxd` | same | same | same | yes | n/a | yes | yes | yes | | `amd-mp2-i2cd` | same | same | same | yes | MSI | yes | yes | yes | | `intel-thc-hidd` | same | same | same | yes | MSI | yes | yes | yes | **Crucial invariant:** all 17 drivers already fulfil C3–C8, C12, C16, C17 through `pcid_interface::PciFunctionHandle::connect_default()` followed by `PciClient::*` calls. driver-manager's role is to deliver a working channel FD into the child's env. No driver rewrite required at any phase. ### 9.4 TOML schema (canonical end-state at C3) **Match table (`/lib/drivers.d/*.toml`):** ```toml # matches are AND-ed within an entry, OR-ed across entries [[driver]] name = "e1000d" description = "Intel e1000 Gigabit Ethernet" priority = 50 [driver.command] argv = ["e1000d"] # or absolute path [driver.depends_on] schemes = ["pci", "firmware"] [[driver.match]] vendor = 0x8086 device = 0x100E class = 0x02 # network controller subclass = 0x00 # ethernet [[driver.match]] vendor = 0x8086 device = 0x10D3 # wildcard rest [driver.params] debug = { type = "bool", default = false, writable = true } priority_arg = { type = "int", default = 0, writable = true } exclusive_with = { type = "string", default = "", writable = false } ``` **Policy layer (`/etc/driver-manager.d/*.toml`):** ```toml # Blacklist [[blacklist]] module = "iTCO_wdt" reason = "CachyOS precedent; conflicts with iTCO hardware" # Forced module-options [amdgpu.params] si_support = true cik_support = true radeon_overlap = "exclusive" # CachyOS mutual exclusion pattern # Autoload (cold-boot pre-driver) [[autoload]] module = "ntsync" ``` **Initfs manifest (`/etc/driver-manager.d/initfs.manifest`):** ```toml # ordered (CachyOS-style hook ordering) [ramdisk] microcode = ["amd-ucode", "intel-ucode"] policy = "00-driver-conf" kms_drivers = ["amdgpu", "i915"] block_drivers = ["ahci", "nvme", "virtio_blk"] fs_drivers = ["redoxfs", "ext4"] ``` ### 9.5 Migration effort & ownership | Phase | Effort estimate | Owner role | |---|---|---| | D-Phase | Effort estimate | Owner role | |---|---|---| | D1 — Linux capability bridge | 6–10 weeks | driver-runtime engineer | | D2 — Modern technology surface | 8–12 weeks (largest phase; SMP + S/P + PM + IOMMU + AER + MSI-X + NUMA) | driver-runtime + kernel-interface engineer + ACPI engineer | | D3 — Hotplug event-driven | 4–6 weeks | driver-runtime engineer | | D4 — Quirk integration + audit | 6–8 weeks (includes the § 0.5 no-stubs audit) | driver-runtime + SRE | | D5 — Feature-complete gate | 1–2 weeks | driver-runtime engineer + operator ratification | | **D-phase total** | **25–38 weeks (~6–9 months)** | | | C-Phase | Effort estimate | Owner role | |---|---|---| | C0 — Service wiring (dormant) | 1 week | driver-runtime engineer | | C1 — Dual-mode observation | 2–4 weeks (must run alongside pcid-spawner in production) | driver-runtime engineer + build-system engineer | | C2 — Initfs switchover | 2–3 weeks | driver-runtime + boot-system engineer | | C3 — Rootfs switchover | 2–4 weeks | driver-runtime engineer | | C4 — Operator-ratified production cutover | 1–2 weeks + 2-week soak + 3 hardware reboots | operator + driver-runtime engineer | | **C-phase total** | **8–14 weeks + soak (~2–4 months)** | | **Grand total: 33–52 weeks (~8–13 months)** for full D+C trajectory. **Operator ratification required at the following phase boundaries:** - **D5 → C0** — feature-complete gate (the § 0.5 audit clean + hardware matrix passes) - **C1 → C2** — rootfs observation confirmed dual-mode parity - **C2 → C3** — initfs switchover ratified - **C3 → C4** — rootfs switchover ratified - **C4 transition** — production cutover ratified Phase boundaries without explicit operator ratification are not allowed to advance. ### 9.6 References **Internal (Red Bear OS):** - `local/AGENTS.md` — policy authority - `local/docs/CONSOLE-TO-KDE-DESKTOP-PLAN.md` — supersedes for desktop path - `local/docs/DRM-MODERNIZATION-EXECUTION-PLAN.md` — GPU-specific decisions - `local/docs/IRQ-AND-LOWLEVEL-CONTROLLERS-ENHANCEMENT-PLAN.md` — PCI/IRQ quality - `local/docs/USB-IMPLEMENTATION-PLAN.md` — USB bus (out of scope here) - `local/docs/WIFI-IMPLEMENTATION-PLAN.md` — Wi-Fi bus (out of scope here) - `local/docs/QUIRKS-SYSTEM.md` — `redox-driver-sys` quirks surface - `local/docs/QUIRKS-IMPROVEMENT-PLAN.md` — Task 2.1 driver-manager bridge - `local/docs/HARDWARE-VALIDATION-MATRIX.md` — status of driver runs - `local/docs/UPSTREAM-SYNC-PROCEDURE.md` — historical status note to update - `local/docs/PATCH-GOVERNANCE.md` — patch carrier rules - `local/docs/RELEASE-BUMP-WORKFLOW.md` — version sync - `local/scripts/TOOLS.md` — tool inventory **External cross-reference (not authoritative here, cited for design intent):** - Linux 7.1 reference tree at `local/reference/linux-7.1/` (commit `ab9de95c9`): - `drivers/pci/pci-driver.c:1021-1742` — pci_driver, pci_bus_type - `drivers/pci/pci.c:2120, 3916, 4172` — `pci_enable_device`, `pci_request_regions`, `pci_set_master` - `drivers/pci/msi/api.c:205-264` — `pci_alloc_irq_vectors_affinity` - `drivers/pci/hotplug/pciehp_core.c:185-372` — native hotplug - `drivers/pci/pcie/aer.c:1203-1280` — AER recovery - `drivers/base/bus.c:732, 818, 612, 869` — driver-core binding - CachyOS-Settings (`master`, v1.3.5): https://github.com/CachyOS/CachyOS-Settings - `usr/lib/udev/rules.d/60-ioschedulers.rules` — kernel-event → sysfs-write policy - `usr/lib/udev/rules.d/71-nvidia.rules` — bind/unbind lifecycle symmetry - `usr/lib/udev/rules.d/20-audio-pm.rules` — cross-subsystem reaction - `usr/lib/udev/rules.d/85-iw-regulatory.rules` + `cachyos-iw-set-regdomain.{path,service}` — udev→systemd delegation - `usr/lib/modprobe.d/{amdgpu,blacklist,nvidia}.conf` — driver-exclusion pattern - CachyOS/linux-cachyos: scheduler variants, `mkinitcpio` preset ordering. --- ## 10. Position statement This plan supersedes the inline deferred notes that accompany the existing `driver-manager` recipe: - `config/redbear-mini.toml:31` ("driver-manager requires driver config migration and is not yet ready") - `config/redbear-device-services.toml:9-13` ("driver-manager intentionally not included … its service launched pcid-spawner instead of driver-manager"). These notes remain accurate at the moment of writing (2026-07-20). They will be amended at the relevant phase boundaries as the migration advances. At **no point** in the migration is `pcid-spawner` removed from the tree, the recipe, or the live image. The boot path is never single-point-of-failure. **v1.1 additions (this revision):** § 0 Strategic Context is added with rationale, success criteria, upstream risk, modern-technology surface, comprehensive-implementation principle, and the parallel-development constraint. § 5 is restructured into D-Phase (parallel development) and C-Phase (cutover & validation). All cross-references in §§ 1, 2, 4, 5, 6, 7, 8, 9 are updated to the new phase nomenclature. The § 0.5 comprehensive principle is the binding code-quality bar; the § 0.6 parallel-development constraint is the binding development model. **Binding constraints derived from § 0:** - **Comprehensive implementation** — every public trait method on `Bus`, `Driver`, and `Manager` is fully implemented. No `unimplemented!()`, no `todo!()`, no empty match arms returning trivial defaults, no `#[cfg(...)]`-gated no-ops. Honoring `local/AGENTS.md` § STUB AND WORKAROUND POLICY — ZERO TOLERANCE. - **Modern technology surface** — SMP-aware concurrent probe, C/P-state coordination, runtime PM, IOMMU group management, AER error recovery, MSI-X vector allocation, NUMA-aware DMA. None of these are stubs. - **Parallel development model** — driver-manager is being built in parallel with the live pcid-spawner system. It is **NOT** shipped, NOT enabled, NOT included in any boot path until the D5 feature-complete gate ratifies. No exceptions. - **Upstream-first response** — if Redox upstream ships an equivalent manager within 6 months of D5, evaluate and consider migrating per Local Fork Supremacy Policy. The migration plan is robust to upstream divergence; it does NOT block on upstream decisions. **Status of § 0.6 (parallel development) at the moment of writing:** driver-manager is being built. It is NOT shipped. The boot path is pcid-spawner. The migration plan enters C-phase only after D5 ratifies. The migration's authority chain is: **this document → `local/AGENTS.md` → `AGENTS.md`**. Every implementation step must be defensible against this chain, the § 0.5 comprehensive principle, and the § 0.6 parallel-development constraint. **Last reviewed:** 2026-07-20 (v1.1: strategic-context + D/C phase restructure) **Next review:** at **D5** exit gate, after `local/scripts/driver-manager-audit-no-stubs.py` reports zero violations AND `local/docs/HARDWARE-VALIDATION-MATRIX.md` shows driver-manager validated on at least one AMD and one Intel profile across storage, network, and GPU categories.