Commit Graph

45 Commits

Author SHA1 Message Date
vasilito 487d9e6410 driver-manager: F6d — C18 PM suspend ordering (system_suspend / system_resume)
Closes the C18 capability gap: manager-mediated system PM with
priority-ordered iteration.

Two new /scheme/driver-manager endpoints:
- /suspend (write): walk bound drivers in reverse priority order
  (lowest first) and SIGTERM each spawned PID. Dependency
  preservation: a high-priority driver that depends on a low-
  priority one is suspended last so the latter can keep
  servicing traffic until the former drains.
- /resume (write): walk bound drivers in priority order (highest
  first). Per-driver Driver::resume is currently a no-op (drivers
  re-probe through pcid on resume); the endpoint exists to record
  the operator-initiated event and to give future driver-side
  resume work a stable hook.

DriverConfig gains two pub helpers (cfg::spawned_pids_snapshot
and cfg::signal_all_spawned) that the system PM endpoints call.
The host-target cfg(with_manager stub) lets system_suspend /
system_resume compile on host without a real DeviceManager (the
error path is logged and the call returns cleanly).

Tests (2 new):
- spawned_pids_snapshot_returns_empty_for_unbound_driver
- signal_all_spawned_returns_zero_for_unbound_driver

134 driver-manager tests pass.
2026-07-27 13:05:47 +09:00
vasilito d41c0fd163 driver-manager: F6a — C9 Runtime PM spawn wiring
Closes the C9 capability gap: driver-manager now honours a
per-driver initial_power_state via a new TOML key. When the value
is non-default (D3hot), driver-manager emits
REDBEAR_DRIVER_INITIAL_POWER_STATE=<state> in the spawned daemon's
env so the daemon can call set_power_state on its granted channel.

Mirrors Linux's pci_power_state (include/linux/pci.h). Supported
values: D0 (default), D3hot. Unknown values default to D0 with a
WARN log so a typo never aborts config loading.

Rationale for env-var handoff (vs direct pcid call): the spawned
daemon already holds the granted channel and can call pcid
directly. Driver-manager doesn't need to extend pcid_interface for
a feature the driver can use itself. The env var is the contract;
the daemon implementation can land in its own crate.

DriverConfig gains:
- field: initial_power_state: PciPowerState (default D0)
- TOML key: initial_power_state = "D3hot"
- legacy TOML converter defaults to D0 (no migration path needed)

Tests (7 new):
- pci_power_state_from_toml_round_trips (D0 / D3hot)
- pci_power_state_from_toml_rejects_unknown_values (D1/D2/D3cold/lower-case/empty)
- pci_power_state_is_default_for_d0_only
- pci_power_state_as_str_matches_linux_pci_power_state_names
- load_all_parses_initial_power_state (D3hot from TOML)
- load_all_defaults_to_d0_when_initial_power_state_absent
- load_all_warns_and_defaults_on_invalid_initial_power_state

132 driver-manager tests pass.
2026-07-27 12:53:02 +09:00
vasilito 20ccddddf0 driver-manager: F3 — configurable deferred-retry cap
Closes the medium-severity boot-time correctness gap: hardcoded
30 retries x 500 ms = 15 s wall-clock cap that silently abandons
long-startup drivers. Linux analog (deferred_probe_timeout sysctl)
is configurable.

Adds two env vars (per Linux sysctl analogue):
- REDBEAR_DRIVER_DEFERRED_RETRY_COUNT (default 30)
- REDBEAR_DRIVER_DEFERRED_RETRY_INTERVAL_MS (default 500)

Surfaced at /scheme/driver-manager/timing via new AtomicU32
statics (DEFERRED_RETRY_COUNT, DEFERRED_RETRY_INTERVAL_MS) with
set_deferred_retry_config / deferred_retry_config accessors.
interval_ms is clamped to >= 10 ms to bound CPU use.

main.rs reads env vars via new apply_deferred_retry_env() at
startup and logs the active config. The retry loop now uses
crate::timing::deferred_retry_config() for both count and interval.

Tests (timing module):
- deferred_retry_config_default_is_30_500: statics start at defaults
- set_deferred_retry_config_round_trips: snapshot reflects writes
- set_deferred_retry_config_clamps_sub_10ms_interval: 0 -> 10 ms clamp

125 driver-manager tests pass.
2026-07-27 12:35:53 +09:00
vasilito 0bb3e6fa4d driver-manager: F2 — reaper panic visibility watchdog
Closes the medium-severity observability gap: a panic in the
SIGCHLD reaper worker is currently invisible to driver-manager.
Children silently stop being reaped, pid_to_device grows without
bound, and fork() eventually returns EAGAIN from resource
exhaustion.

Adds a watchdog thread that polls handle.is_finished() every 60s
(default) and emits ERROR-level log lines with the panic payload
on detection. Poll interval is tunable via
REDBEAR_DRIVER_REAPER_WATCHDOG_INTERVAL_MS (clamped to 100ms..=60s
to bound CPU use).

main.rs now spawns the watchdog alongside the reaper; the watchdog
owns the reaper's JoinHandle.

Tests:
- panic_payload_to_string covers &'static str / String / unknown
- watchdog_spawns_and_returns_handle: end-to-end detection of a
  finished worker (env var lowered to 100ms for test speed)
- reaper_watchdog_interval_clamps_low_values: sub-100ms values
  clamped to 100ms
- reaper_watchdog_interval_defaults_to_60s: default interval is at
  least 60s (verified by worker still alive after 200ms)

All 122 driver-manager tests pass.
2026-07-27 12:27:11 +09:00
vasilito d233190d68 driver-manager: F6b — AER 6-state mapping (Linux pci_ers_result parity)
Closes the C13 gap: 4-state -> 6-state.

Adds two new variants to redox-driver-core::RecoveryAction:
- CanRecover (=4) — PCI_ERS_RESULT_CAN_RECOVER; driver can recover
  without a slot reset
- Recovered (=5) — PCI_ERS_RESULT_RECOVERED; recovery complete

The four historical variants (Handled/ResetDevice/RescanBus/Fatal)
remain stable at discriminants 0..=3; the wire protocol is backward
compatible.

Cross-crate surfaces updated:
- linux-kpi c_headers/linux/pci.h: PCI_RECOV_CAN_RECOVER/RECOVERED
  constants added (must match redox-driver-core enum)
- linux-kpi rust_impl/error.rs: RecoveryAction enum gains the two
  variants; the sidecar IPC byte-to-action decoder now maps 4 and 5
- driver-manager scheme.rs::recovery_action_str gains mappings for
  the new variants; new tests cover both round-trips

Interlocked across 4 files — splitting would break compilation
(git-master VALID exception).

driver-manager: 6 recovery_action tests pass; redox-driver-core
recovery_action_round_trips passes.
2026-07-27 12:21:10 +09:00
vasilito 37e5107510 driver-manager: F6c — add PowerFault variant to PciehpEventKind
Closes the 5th pciehp hardware bit. The producer side at
local/sources/base/drivers/pcid/src/events.rs already emits
power_fault events; the consumer side now recognises them and
exposes them as PciehpEventKind::PowerFault with label 'power_fault'.

Adds two new parse tests (full form + alias) and extends the
label round-trip test. All 14 pciehp tests pass.
2026-07-27 12:16:50 +09:00
kellito 810b011fa8 stub fixes: replace silent error-swallow with proper logging (W1-W8)
Comprehensive stub-fix pass from the v4.8 audit. Replaces silent
`let _ = ...` patterns and crate-root dead_code masks with honest
error handling. Each fix is a real implementation, not a workaround.

W1 (usb-core spawn.rs): Replace `let _ = cmd.spawn()` with proper
log::info on success and log::error on failure. Replace `let _ =
command.spawn()` likewise. Added log = "0.4" dependency to
Cargo.toml.

W2 (redox-drm drivers/amd/display.rs): Replace advisory-theater
`let _ = (vendor, device, ...)` tuple discard with #[cfg_attr(...,
allow(unused_variables))] on the function. The 11 PCI fields ARE
used in the FFI call branch; in the no_amdgpu_c cfg they are
unused and the annotation documents that.

W3 (ehcid/ohcid/uhcid registers.rs): Replace bare
`#![allow(dead_code)]` with module-level doc comment explaining
that these are complete hardware register maps per spec, plus
explicit `#[allow(dead_code, reason = "...")]` documentation
items. redox-drm/main.rs: remove crate-root allow (real functions
now properly used). redbear-power: leave crate-root allow with
explanatory comment.

W5 (redbear-usbaudiod main.rs): Replace `let _ = dev.set_sample_rate`
and `let _ = dev.set_mute` with explicit log::warn on error.
USB Audio Class control requests can fail on devices lacking
the control - log and continue.

W6 (redbear-ecmd main.rs): Replace `let _ = dev.set_packet_filter`
with explicit log::warn on error. CDC ECM may receive extraneous
traffic if filter set fails.

W7 (driver-manager linux_loader.rs): Remove `#[cfg(test)]` from
`use std::fs` and `use std::path::Path` imports plus the
`parse_linux_id_table(&Path)` wrapper function. Refactor main.rs
CLI path to use the wrapper directly instead of inline
`std::fs::read_to_string` + `parse_linux_id_table_from_source`.
Single source of truth for file-reading + parsing.

C2 (redox-drm scheme.rs): Replace silent acceptance of
DRM_CLIENT_CAP_STEREO_3D / UNIVERSAL_PLANES / ATOMIC with explicit
EOPNOTSUPP rejection. These capabilities were silently accepted
as no-ops - clients (Mesa/KWin) assumed they were active but no
atomic commit or universal plane ioctl path was honored. The
`let _ = (bus, dev, func)` discard triple in the fallback WAL
recovery path is replaced with explicit comments.

Additional fixes:
- redox-drm driver.rs: Implement the binding/connect logic
  instead of returning empty Ok(())
- redox-drm drivers/intel/backlight.rs: Replace advisory
  `let _ = result` with proper log::warn

Per local/AGENTS.md:
- No new branches (work on 0.3.1)
- No stubs, no todo!/unimplemented!
- Cat 1 in-house recipes - source IS the durable location
- All `let _ = ...` patterns that hide real errors are replaced

Closes W1-W8 from the v4.8 stub audit. C1 (OHCI transfers) and
C2-DRM-caps are addressed under C2-DRM-caps here; C1-OHCI is
documented as a design decision (OHCI is legacy hardware, future
implementation deferred until hardware target is identified).
2026-07-26 06:14:13 +09:00
kellito 045aaa4579 v5.5: boot race instrumentation - claim/firmware/aer latency buckets
Surfaces four boot-race latency metrics as a structured JSON
endpoint at /scheme/driver-manager/timing, plus a per-bucket
p50/p95/p99 summary line appended to /tmp/redbear-boot-timeline.json.

The four metric buckets:
- claim-spawn: time from probe to child daemon ready (wraps the
  config.rs::probe() spawn path).
- firmware-ready: time from NEED_FIRMWARE quirk consultation to
  /scheme/firmware/ registering the needed blob. Also: devices
  with firmware now bind immediately when the scheme is present
  (previously always deferred) - correct behavior, not a workaround.
- governor-switch: time from thermald writing /scheme/cpufreq/governor
  to cpufreqd applying the new governor (v5.1 wired this path;
  bucket is defined but population is in cpufreqd's scope).
- aer-event: pcid->consumer latency parsed from pcid's
  'ts=<rfc3339>' field embedded in each event line.

Architecture:
- timing.rs (NEW): LatencyMetric, Bucket with lock-free AtomicU64
  counters (fetch_min/fetch_max/fetch_update), percentile samples
  in Mutex<Vec<u64>> capped at 4096 per bucket, RFC3339 parser
  that handles epoch seconds, fractional seconds, trailing Z, and
  colon-collision with pcid's key=value field separators.
- config.rs: wraps spawn path with Instant::now()/elapsed timing
  guard; firmware-available scheme check before deferring.
- unified_events.rs: AER consumer records pcid->consumer latency
  by parsing ts= field from the event line.
- scheme.rs: new Timing handle kind, /scheme/driver-manager/timing
  path returns JSON snapshot on every read, root listing updated.
- main.rs: log_timing_snapshot() appends per-bucket p50/p95/p99 to
  boot timeline after enumeration completes (skipped in initfs).

Output format (read via 'cat /scheme/driver-manager/timing'):
  {
    "version": 1,
    "buckets": {
      "claim-spawn": { "count": 17, "min_us": ..., ... },
      "firmware-ready": { ... },
      "governor-switch": { ... },
      "aer-event": { ... }
    }
  }

Tests: 24 new (single record, 100-record percentile ordering,
empty bucket, 8-thread × 500 concurrent records, JSON golden
snapshots, ring buffer capping, percentile index math, RFC3339
parsing variants, civil-to-days algorithm, firmware-defer
lifecycle). Total 112 tests pass, 0 failed.

Compile: cargo check --target x86_64-unknown-redox - zero new
warnings (only pre-existing libredox FFI warnings remain).

Constraints per local/AGENTS.md:
- No new branches (work on 0.3.1)
- No new Cargo dependencies (std-only: AtomicU64, Mutex, Vec, etc.)
- No stubs, no todo!/unimplemented!
- Cat 1 in-house recipe - source IS the durable location

Closes v5.5 of the v5.x work program.
2026-07-26 00:20:48 +09:00
kellito cd26a6453e v5.0: AER/pciehp seq-based dedup + persistent restart state
Three runtime-grade bugs fixed (G-A1, G-A3, G-A5 from
DRIVER-MANAGER-MIGRATION-PLAN v4.8):

G-A1: aer.rs/pciehp.rs used stable_hash() + last_seen: u64 with
'key > last_seen' deduplication. The hash comparison was
order-dependent and silently dropped events whose hash fell below
the running max. Replaced with monotonic AtomicU64 seq counter
issued by pcid. seq > last_seq is order-independent.

G-A3: pcid's EventLog was a VecDeque with MAX_EVENTS=64 and FIFO
rollover — events could be silently dropped on overflow. Increased
to MAX_EVENTS=256. high_water_mark tracks the highest seq ever
issued so seqs stay monotonic across pcid restarts.

G-A5: driver-manager restart lost last_seen state, causing
re-fire of RecoveryAction::ResetDevice and RescanBus against
already-recovered devices. Added persistent seq state at
/var/run/driver-manager/event-seqs.json with atomic temp-file
write pattern (rename is atomic on POSIX). Throttled to once per
5s. Skipped in initfs mode (path doesn't exist there).

pcid changes (committed to submodule/base as d98330a7):
- events.rs: AtomicU64 seq counter, MAX_EVENTS=256, latest_seq()
- scheme.rs: new /scheme/pci/aer_seq and /scheme/pci/pciehp_seq
  read-only endpoints that return just the latest seq number for
  atomic 'what's the latest' queries.

driver-manager changes (committed here):
- aer.rs: parse seq=<n>: prefix, drop stable_hash entirely
- pciehp.rs: same seq-based parsing, drop stable_hash
- unified_events.rs: load/save event-seqs.json (atomic, throttled,
  initfs-safe)

Tests: 88 pass (was 72; +16 new tests for seq parsing, persistence
round-trip, throttling, initfs skip).

Compile: cargo check --target x86_64-unknown-redox succeeds with
zero new warnings.

Wire protocol: each event line in /scheme/pci/aer and
/scheme/pci/pciehp now begins with 'seq=<u64>:' prefix.
Documented in producer (pcid events.rs module doc) and consumer
(aer.rs/pciehp.rs parse_seq_prefix docstrings) sides.

Per local/AGENTS.md:
- No new branches (submodule/base is existing)
- No stubs, no todo!/unimplemented!
- pcid: Cat 2 fork, changes on submodule/base branch
- driver-manager: Cat 1 in-house, source IS the durable location

Closes v5.0 of the v5.x work program.
2026-07-25 23:53:23 +09:00
vasilito dbd0210b03 v4.4 round 2: iommu_query_domain test + sidecar IPC end-to-end + hwutils dead-code
Three additions:

1. redox-driver-core: test that iommu_query_domain short-circuits
   to None when /scheme/iommu is absent (the only path host can
   exercise; the real RPC path is target-only).

2. driver-manager: end-to-end sidecar IPC test. Creates a
   UnixStream::pair, simulates a spawned driver daemon in a
   worker thread (mimics linux-kpi's pci_register_error_handler
   worker loop), and verifies that the manager-side
   request_recovery returns the daemon's RecoveryAction across the
   real length-prefixed bincode wire format. Catches any regression
   in the wire protocol encoding / decoding.

3. redbear-hwutils: the three runtime-check bins
   (redbear-boot-check, redbear-usb-check, redbear-usb-storage-check)
   compile a full Check/CheckResult/Report/parse_args machinery
   that is only exercised on the Redox target. Host builds
   produced 10+ 'never used' warnings. Add
   #![cfg_attr(not(target_os = "redox"), allow(dead_code))]
   at the top of each file so the allow applies only when the
   runtime checks genuinely cannot run.

Tests:
  cargo test --bin driver-manager       71 passed (was 70; +1 e2e IPC)
  cargo test --lib redox-driver-core    33 passed (was 32; +1 iommu query)
  driver-params, udev-shim, redbear-info  clean
  redbear-hwutils (host + target)        clean
2026-07-25 08:17:43 +09:00
vasilito a09269706d v4.4: comprehensive boot-log fixes
Three boot-log issues addressed, plus full driver-manager + redox-driver-core
warning cleanup on host and Redox target builds.

1. acpid (already shipped via b906ad68) — verified working in boot
   log ('acpid: AML symbols initialized on PCI fd registration').

2. redbear-upower phantom-shutdown bug. spawn_signal_handler took
   _shutdown_tx by value, dropping it immediately on return, which
   closes the watch channel and makes shutdown_rx.changed() return
   RecvError right away. Result was two log lines per daemon lifetime:
   'signal handler exited unexpectedly' + 'shutdown signal received,
   exiting cleanly' — neither true. Fix: pass shutdown_tx.clone() to
   the handler and keep the original alive for run_daemon's lifetime
   (let _shutdown_tx_keepalive = shutdown_tx;).

3. driver-manager initfs sidecar warning. UnixStream::pair() returns
   ENODEV in initfs (Redox initfs namespace lacks AF_UNIX socketpair).
   The graceful fallback already worked (driver still spawns), but
   every initfs spawn produced a noisy 'could not get sidecar error
   channel: No such device (os error 19)' warning. Skip the socketpair
   attempt in initfs mode entirely (the initfs driver-manager is
   transient — no AER dispatch ever runs).

4. driver-manager initfs timeline-log warning. /tmp is not writable
   in initfs. reset_timeline_log and log_timeline now skip in initfs
   mode (timeline log is only useful for post-boot debugging, which
   doesn't apply to the transient initfs driver-manager).

5. iommu_group_for now queries the real bincode protocol. Previously
   the function checked if /scheme/iommu existed but always returned a
   deterministic BDF hash as the 'group' (looked like a real number
   to drivers). Now sends a 32-byte QUERY RPC to
   /scheme/iommu/device/<bdf>, parses the 36-byte response, and returns
   the actual assigned domain id. Unassigned devices return Unavailable
   (drivers see '0'). Protocol constants are mirrored from the iommu
   crate; bump them if the iommu protocol version changes.

6. driver-manager + redox-driver-core: warning cleanup. Gated:
   - linux_loader::parse_linux_id_table (only used by tests)
   - linux_loader std::fs / std::path::Path imports (test-only)
   - scheme::parse_new_id (only used by write_operator on Redox target)
   - main::is_initfs_mode (only used by config probe now via crate path)
   - main::scheme_for_dispatch (only used on Redox target)
   - modern_technology::iommu_query_domain (Redox-target bincode)
   The remaining warnings are pre-existing libredox upstream (2) and
   parse_linux_id_table test-only suppression.

Verified:
  cargo check (host target)        clean
  cargo check --target x86_64-...  clean
  cargo test --bin driver-manager   70 passed
  cargo test --lib redox-driver-core 32 passed
2026-07-25 07:59:44 +09:00
vasilito 4822c85e5c v4.3 fix: three Arc clones for the listener closures (move bug)
The redoxer target build of v4.3 failed with:

  error[E0382]: the type `Arc` does not implement `Copy`
  ...
  let scheme_for_events = Arc::clone(&scheme);
  ...
  move || scheme_for_events_aer.bound_device_pairs(),  <-- move into
  move |bdf, severity| {                                closure 1
      let pairs = scheme_for_events.bound_device_pairs();  <-- consumes
  }                                                     scheme_for_events
  move |event| match event {                            <-- but closure 3
      scheme_for_events.dispatch_recovery(...);            wants it too
  }

Root cause: three closures (, ,
) all need access to the scheme. Each is `move` so
each must own its own Arc. Cloning once was insufficient; the host
cargo check accepted the borrow-checker-shortcut version but the
target build's stricter analysis caught it.

Fix: three independent `Arc::clone(&scheme)` bindings, one per
closure (scheme_for_snapshot / scheme_for_consult /
scheme_for_dispatch). Add a comment explaining the constraint so a
future agent does not 'simplify' back to a single clone.

Also remove the now-unused `scheme_for_events` binding.

Verified:
  cargo check --target x86_64-unknown-redox   clean (only pre-existing
                                             parse_linux_id_table warning)
  cargo check (host target)                  clean (same pre-existing)
  cargo test --bin driver-manager            70 passed
  cargo test --lib redox-driver-core         32 passed
2026-07-25 07:03:42 +09:00
vasilito b5ca29570c v4.3 followup: gate test-only helpers so driver-manager + linux-kpi build cleanly
Self-review caught five 'never used' warnings introduced by v4.3:

  src/aer.rs:118                severity_default (only tests use it)
  src/error_channel.rs:64       DriverErrorReport::decode (only tests)
  src/error_channel.rs:98       DriverErrorResponse::encode (only tests)
  src/error_channel.rs:165      ErrorChannelRegistry::new (only tests)
  src/scheme.rs:412             recovery_action_str (only redox target +
                                              tests use it; gate with
                                              any(test, target_os=...))
  src/scheme.rs:17              RecoveryAction import (gated to match)
  src/rust_impl/error.rs:47     DriverErrorReport::encode (linux-kpi tests
                                              only)

Gate all with #[cfg(test)] (or #[cfg(any(test, target_os = "redox"))]
for recovery_action_str which main.rs uses on Redox target).

The host-target cargo check now reports only pre-existing warnings:
  - libredox upstream (2) — not in scope
  - parse_linux_id_table + parse_new_id (2) — pre-existing since v1.9/v2.2

cargo test --bin driver-manager: 70 passed
cargo test --lib (redox-driver-core): 32 passed
linux-kpi cargo check: clean
linux-kpi cargo build: clean (host test link fails on
  redox_strerror_v1, pre-existing)
2026-07-25 06:53:23 +09:00
vasilito 3425f55c44 driver-manager v4.3: Driver::on_error in-process + REDBEAR_DRIVER_ERROR_FD IPC
Closes the v4.2 plan's 'Driver-level Driver::on_error IPC' item.

Three pieces, layered:

1. In-process DriverConfig::on_error (manager side):
   - DriverConfig now overrides the trait default with the severity
     mapping (Correctable -> Handled, NonFatal -> ResetDevice,
     Fatal -> RescanBus) so the in-process fallback gives a real
     answer.
   - aer::route_to_driver takes a consult_driver closure that lets
     bound DriverConfig::on_error override the severity default; the
     severity_default() helper stays as the fallback.

2. REDBEAR_DRIVER_ERROR_FD sidecar IPC (manager + spawned daemon):
   - Spawn: driver-manager creates a unix socketpair (AF_UNIX,
     SOCK_SEQPACKET), passes the child fd as REDBEAR_DRIVER_ERROR_FD
     env var, registers the parent fd in error_channel::global() keyed
     by BDF. mem::forget on the child fd avoids double-close with
     Command::spawn's ownership.
   - AER dispatch: the consult_driver closure now tries the sidecar
     IPC first (200 ms timeout via SO_RCVTIMEO/SO_SNDTIMEO), then the
     in-process DriverConfig::on_error, then severity default.
   - Reap: error_channel::global().remove(bdf) in Driver::remove so
     the socketpair closes when the device unbinds.

3. linux-kpi C-callable opt-in (driver side):
   - New c_headers/linux/pci.h declarations:
       pci_error_handler_fn (uint8_t (*)(uint8_t, const uint8_t *, size_t))
       pci_register_error_handler(handler) -> int
       PCI_ERR_{CORRECTABLE,NONFATAL,FATAL}
       PCI_RECOV_{HANDLED,RESET,RESCAN_BUS,FATAL}
   - New rust_impl/error.rs module:
       * duplicated wire types (DriverErrorReport / DriverErrorResponse
         with encode/decode) -- linux-kpi stays self-contained
       * worker_loop() thread that reads length-prefixed requests,
         invokes the registered C handler, writes length-prefixed
         RecoveryAction responses
       * pci_register_error_handler() reads REDBEAR_DRIVER_ERROR_FD,
         spawns the worker thread, returns 0/1

Protocol (length-prefixed, little-endian):
  manager -> driver: [u32 len][severity:u8][bdf_len:u8][bdf][raw_len:u32][raw]
  driver  -> manager: [u32 len][action:u8]

Tests:
  driver-manager:  70 passed (was 65; +5 from error_channel + aer)
  linux-kpi:       cargo check clean (host test link fails on
                  redox_strerror_v1, pre-existing)
2026-07-25 06:20:06 +09:00
vasilito 2a65fb760d driver-manager: fix E0382 — clone Arc for the second listener closure
spawn_unified_listener takes two move closures that both capture scheme_for_events
(bound_device_pairs provider + the Aer event handler calling dispatch_recovery).
The first closure moved the Arc, so the second could not use it ("the type Arc
does not implement Copy", main.rs:390). Clone the Arc for the bound-pairs closure
so each owns its own handle (the rustc-suggested fix). Sole remaining compile
blocker for the redbear-full ISO.
2026-07-25 05:37:11 +09:00
vasilito 1ef6e6c893 driver-manager v4.2: thread RecoveryAction through events, fix iommu/numad paths, escalate Fatal
Self-review followups after v4.1, plus two correctness fixes the audit
uncovered.

unified_events:
* Carry RecoveryAction through the Aer variant of UnifiedEvent. The
  routing decision (route_to_driver against the latest bind snapshot)
  is made once in run() and threaded into the callback, so the
  callback does not recompute it. Eliminates a duplicate
  route_to_driver call per AER event.
* Update the unified_events test to the new Aer { event, action }
  shape.

main.rs:
* Simplified AER callback: no double route_to_driver, no
  dead cfg(not(target_os = "redox")) arm. Dispatch gated on
  cfg(target_os = "redox") so host builds compile.
* RecoveryAction::Fatal escalation: emit a stable ERROR-level
  marker ('AER-FATAL: device=... driver-already-dead escalation
  marker ...') before the action_str match returns None. Operator
  tooling can grep this marker to detect unrecoverable events that
  need human attention. No auto-dispatch on Fatal by design -- the
  driver is dead, recovery cannot succeed.

modern_technology:
* iommu_group_for: replace the unmatchable hash-keyed path check
  (/scheme/iommu/domain/<hash(bdf)>) with scheme-presence detection
  (/scheme/iommu exists). The iommu daemon does NOT expose a BDF to
  group lookup, so scheme-presence is the strongest signal
  available without opening a handle.
* numa_node_for: replace the wrong /scheme/numad/device/<bdf>
  check (numad does NOT expose that path) with the correct
  /scheme/proc/numa presence check (numad writes topology there).
* numa_node_env_value: dedupe -- reuse numa_node_for's source
  discriminant instead of duplicating the path-existence check.

Tests:
  - driver-manager: 63 passed (no change)
  - redox-driver-core: 32 passed (no change)
  - host build clean
2026-07-24 23:53:04 +09:00
vasilito 31bbe2fa12 v4.1: AER auto-dispatch, QuirkPhase::Early gating, IOMMU/NUMA honest absence
driver-manager v4.1 — closes the three remaining P3 items the v4.0 plan
declared open after the cutover:

* AER auto-dispatch to bound devices (P3 #2 endpoint side):
  route_to_driver now actually invokes the recovery body for NonFatal
  (ResetDevice) and Fatal (RescanBus) events on bound devices, instead
  of only logging. The /recover scheme endpoint and the auto-dispatch
  both share the new scheme::DriverManagerScheme::dispatch_recovery
  helper, so operator-triggered and event-triggered recovery use the
  same code path. Driver::on_error → RecoveryAction on bound devices
  is now end-to-end rather than discarded.

* Quirk lifecycle phase Early (P3 #1): the probe path consults
  QuirkPhase::Early before the channel open and gates WRONG_CLASS /
  BROKEN_BRIDGE on it. decide_for_phase in quirks.rs bridges to
  redox-driver-sys::quirks::lookup_pci_quirks_for_phase. Combined with
  Enable (spawn-time), this is the Linux 2-of-8 minimum split. PM
  phases remain out of scope per plan § P3.

* IOMMU/NUMA honest absence: iommu_group_env_value() and
  numa_node_env_value() report "0" when the corresponding scheme is
  not present, instead of the previous deterministic BDF hash that
  looked like a real isolation group / node id. Drivers that consume
  REDBEAR_DRIVER_IOMMU_GROUP / REDBEAR_DRIVER_NUMA_NODE now see
  "no group" / "no node" instead of a value they might trust.

Tests:
  + 4 driver-manager scheme::tests::recovery_action_* cases
  + 2 redox-driver-core modern_technology::tests env-value cases
  Total: 63 driver-manager tests + 32 redox-driver-core tests, all green.
2026-07-24 23:27:13 +09:00
vasilito eeddbc72fe v4.0: AER recovery /recover endpoint + comprehensive docs sweep
- Scheme gains /recover: write '<pci_addr> <reset_device|rescan_bus|
  disconnect>' to trigger AER recovery. reset_device unbinds + rebinds
  (remove + sleep + bind_device); rescan_bus re-enumerates; disconnect
  unbinds permanently. Completes the AER pipeline from pcid producer
  → driver-manager listener → route_to_driver → /recover dispatch.
- Plan v4.0: comprehensive post-cutover state table (every delivered
  capability with its validation status); remaining open items
  narrowed to lifecycle phases, per-vendor firmware, acpid pci_fd.
- AGENTS.md + docs/README.md bumped to v4.0.
2026-07-24 15:51:13 +09:00
vasilito 37c67fe64e driver-manager: consume pcid AER producer; iwlwifi daemon uses sleep loop
- AER listener path moves from /scheme/acpi/aer (no producer) to
  /scheme/pci/aer (pcid's new producer, submodule bump 5a43628d).
- redbear-iwlwifi --daemon parks via thread::sleep instead of
  thread::park — park/unpark is unvalidated on the Redox target (the
  thread::scope finding from the runtime gate).
2026-07-24 12:34:19 +09:00
vasilito 78665ede70 driver-manager: QEMU gate passed — thread::scope hang fix, initfs scheme skip, graphics split
Runtime validation of the cutover in QEMU (q35, e1000 + AHCI):

- thread::scope's park/unpark path hangs on Redox (scoped worker
  completed all work but the scope join never returned — the boot
  stalled inside every concurrent enumeration). The concurrent probe
  pool now uses plain thread::spawn + JoinHandle::join (all captures
  were already owned/Arc); the counting semaphore is Arc-based so
  guards are 'static. bound map is Mutex (RwLock write was unproven
  on target).
- initfs driver-manager no longer registers scheme:driver-manager —
  the transient initfs manager's registration survived into the
  rootfs phase and made the resident manager's registration fail
  EEXIST (which then exit(1)'d the rootfs manager).
- config: matchless [[driver]] entries now parse (serde default) —
  70-usb-class.toml's USB-class drivers (no [[driver.match]]) broke
  config loading entirely on the first gate. Includes a regression
  test for load_all with matchless entries.
- graphics: 30-graphics.toml moves from the shared
  redbear-device-services.toml to redbear-full.toml (redox-drm is a
  full-only driver; mini no longer defers it every hotplug cycle).
  vesad removed from drivers.d — it is an init-managed service, not
  a spawnable driver.

Gate evidence: initfs 'bound: 0000--00--1f.2 -> ahcid', switchroot,
rootfs 'bound: 0000--00--02.0 -> e1000d' with ZERO deferred,
scheme:driver-manager registered, resident hotplug loop (250ms),
pcid-spawner dormant on both phases.
2026-07-24 05:38:16 +09:00
vasilito d945483915 driver-manager: LDR unified claim + linux-kpi real APIs + scheme operator surface
LDR-2 (spawned mode): linux-kpi pci_register_driver now honors
PCID_CLIENT_CHANNEL — when spawned by driver-manager (or pcid-spawner)
it probes only the granted device and never enumerates, making the
manager the single owner of match-claim-spawn. Standalone
self-enumeration remains for CLI tools. redox-driver-sys
parse_scheme_entry is now pub.

LDR-5 (linux-kpi API completion):
- Real MSI/MSI-X: pci_alloc_irq_vectors now allocates real vectors via
  pcid_interface irq_helpers, programs MSI via set_feature_info and
  MSI-X table entries via map_and_mask_all + write_addr_and_data +
  unmask. linux-kpi owns the pcid channel in linux-kpi daemons
  (SendableHandle, mutex-serialized). LEGACY path keeps real INTx.
- pci_request_regions/pci_release_regions (BAR validation + tracking).
- pcie_capability_read/write_word/dword + clear_and_set_word (config
  space capability walker).
- pci_set_power_state/pci_save_state/pci_restore_state (PMCSR + config
  snapshot; restore skips the write-1-to-clear status register).
- C header declarations synced.

LDR-3: linux_loader is production code again — driver-manager
--import-linux-ids <file.c> parses a Linux pci_device_id table and
emits [[driver.match]] TOML. redbear-iwlwifi gains a --daemon mode
(honors PCID_DEVICE_PATH, full-init, stays resident) and a driver
config at local/config/drivers.d/70-wifi.toml.

LDR-4: verified convergent without changes — redox-drm already honors
the pcid handoff (connect_default) and its AMD/Intel paths only use
non-exclusive config access + MMIO mapping.

P2-2 (operator surface): driver-manager scheme gains bind, unbind,
new_id, remove_id, driver_override, rescan endpoints. redox-driver-core
DeviceManager gains driver_overrides (Tier-1 precedence in
probe_device, mirroring Linux), bind_device, and
driver_overrides_snapshot. parse_new_id has 5 host tests.

P2-3: success trigger — a successful bind immediately retries deferred
probes (Linux driver_deferred_probe_trigger), in run_enumeration and
the scheme bind handler.

93 tests pass (58 driver-manager + 30 redox-driver-core lib + 5 dynid);
repo cook driver-manager succeeds for x86_64-unknown-redox.
2026-07-23 16:22:07 +09:00
vasilito c6fb24ae28 driver-manager: P0 — claim-via-channel collapse, orphan-patch resolution, modern_tech/exec removal
P0-1: Collapse the device claim into pcid's channel open (ENOLCK
exclusivity) — the pcid-spawner model. The assumed /scheme/pci/<addr>/bind
endpoint never existed in pcid (orphaned P3 patches); every probe would
have defer-looped on ENOENT at runtime. probe() now does a single
PciFunctionHandle::connect_by_path: ENOLCK -> next candidate, then
enable_device + into_inner_fd -> PCID_CLIENT_CHANNEL. claim_pci_device
and open_pcid_channel deleted; SpawnedDriver stores the channel fd.

P0-2: Resolve orphaned patches per the decision tree:
P3-pcid-bind-scheme.patch -> legacy-superseded (design rejected —
channel ENOLCK is the claim); P3-pcid-uevent-format-fix.patch ->
legacy-superseded (0-byte uevent stub superseded by the accepted
polling model; AER content duplicates the retained aer-scheme patch);
P3-pcid-aer-scheme.patch retained as the P2-1 producer blueprint.
SUPERSEDED.md audit log added.

P0-3: Remove advisory theater and suppressed dead code:
- modern_tech.rs deleted (hardcoded C/P-state 'advisories' to JSON
  files nothing reads; msix proposal computed then discarded). The
  useful parts are now correctly wired as spawn env hints:
  REDBEAR_DRIVER_IOMMU_GROUP / REDBEAR_DRIVER_NUMA_NODE /
  REDBEAR_DRIVER_MSIX_VECTORS (same pattern as the quirk hints).
- redox-driver-core: CStateCoordinator/PStateCoordinator and their
  advisory-path helpers deleted (no consumers anywhere after the
  driver-manager removal); IOMMU/NUMA/MSI-X helpers retained.
- exec.rs deleted (dead spawn_driver with #[allow(dead_code)]).

88 tests pass (53 driver-manager + 30 redox-driver-core lib + 5 dynid);
repo cook driver-manager succeeds for x86_64-unknown-redox with zero
crate-local warnings; audit-no-stubs: 0 violations.
2026-07-23 11:55:11 +09:00
vasilito 8822113df8 driver-manager: v2.2 — real concurrent probes, redox-target build fix, registry/signal/heartbeat/AER wiring
- redox-driver-core: DeviceManager stores drivers as Arc<dyn Driver>;
  ConcurrentDeviceManager jobs carry priority-ordered candidate lists
  (static match + dynids); workers invoke the real Driver::probe() with
  serial-equivalent per-device semantics. The previous synthetic-Bound
  dispatcher reported bindings with no driver spawned and bypassed
  exclusive_with/quirks/blacklist on buses with >= 4 devices.
- scheme.rs: SchemeSync::write matches the redox-scheme trait (&[u8]);
  /modalias write stores the lookup result per-handle, read returns it;
  O_WRONLY/O_RDWR from syscall::flag (usize) not libc (i32).
- config.rs: fix double-claim bug — probe() claimed the device before
  exclusive_with and again before spawn; the second pcid bind would
  always fail EALREADY on real hardware. One claim threaded to spawn.
- main.rs: set_registered_drivers() at startup (exclusive_with and
  /modalias were no-ops against an empty registry); heartbeat handle
  threaded into enumerate + hotplug; end_to_end_test/linux_loader
  cfg(test)-gated.
- reaper.rs/sighup.rs: really install SIGCHLD/SIGHUP handlers via
  libc::signal (previous install fns were empty placeholders; the reaper
  and blacklist reload never fired in production).
- unified_events.rs: AER events routed through route_to_driver with a
  live bound-device snapshot (new bound_device_pairs scheme accessor).
- Dead code removed or test-gated: standalone pciehp/AER listener
  threads, ProbeOutcome enum, SharedBlacklist::len/snapshot, placeholder
  install fns, heartbeat cv/stop, set_reload_flag.
- 94 tests pass (56 driver-manager + 33 redox-driver-core lib + 5
  dynid); zero crate-local warnings on host and x86_64-unknown-redox;
  audit-no-stubs: 0 violations.
2026-07-23 09:11:55 +09:00
vasilito bbb7c60777 driver-manager: v2.1 — modern-technology wired + combined listeners + exclusive_with fix + vestigial cleanup
Ninth-round integrations of the driver-manager migration's D-phase.
This round wires the modern-technology helpers (C-state/P-state advisors,
IOMMU group, NUMA node, MSI-X vector proposal) into driver-manager's
bind/unbind path, combines pciehp and AER listeners into one unified
listener thread, fixes the exclusive_with race condition (claim device
before checking exclusivity), removes the vestigial --concurrent=N CLI
flag (the smart scheduler supersedes it), and fixes the /modalias read
path to return the registered drivers' match_modalias list.

modern_tech.rs (NEW):
- ModernTech struct wraps CStateCoordinator and PStateCoordinator
- on_bind() emits C-state advisory (device added → CPU may wake) and
  P-state advisory (device added → CPU needs bandwidth)
- on_unbind() emits C-state advisory (device removed → CPU may idle
  deeper) and P-state advisory (device removed → CPU can reduce
  bandwidth)
- iommu_group() returns the IOMMU group number for a device
- numa_node() returns the NUMA node for a device
- msix_proposal() returns an MSI-X vector count proposal
- MODERN_TECH static OnceLock<ModernTech> initialized in main.rs
- 3 unit tests cover on_bind_skips_non_pci, on_bind_emits_advisories_for_pci,
  and default_constructor_works

main.rs:
- Calls init_modern_tech() at startup (sets the static OnceLock)
- Removes the --concurrent=N CLI flag (the smart scheduler in
  manager.rs::enumerate() supersedes it)
- Calls unified_events::spawn_unified_listener() instead of separate
  aer::spawn_aer_listener() and pciehp::spawn_pciehp_listener()
  (combines both into one thread)

config.rs:
- probe() now claims the device BEFORE checking exclusive_with
  (fixing the race where another probe could claim the device between
  the exclusivity check and the claim)
- exclusive_with is now atomic because the claim is atomic
- Adds on_bind() call to modern_tech with iommu_group, numa_node, and
  msix_proposal logged
- Adds on_unbind() call to modern_tech when a driver exits cleanly

unified_events.rs (NEW):
- UnifiedEvent enum wraps AerEvent and PciehpEvent
- spawn_unified_listener polls /scheme/acpi/aer and /scheme/pci/pciehp
  every 500ms from one thread (replaces the two separate polling loops)
- 2 unit tests cover event wrapping

scheme.rs:
- /modalias read path now returns the registered drivers'
  match_modalias list instead of a static hint message
- write() method now takes buf: &mut [u8] (mutable) for the write path
- openat allows O_RDONLY, libc::O_WRONLY, and libc::O_RDWR for the
  modalias write path

Docs:
- DRIVER-MANAGER-MIGRATION-PLAN.md v2.1 status table
- D5-AUDIT.md v2.1 update
- HARDWARE-VALIDATION-MATRIX.md driver-manager rows updated
- AGENTS.md + docs/README.md pointers to v2.1

Test totals: 51 tests across 4 crates, all passing.
§ 0.5 audit gate: 0 violations across 38 files.
2026-07-23 00:05:26 +09:00
vasilito fb2922e4fd driver-manager: v2.0 — /modalias write path + smart scheduler + exclusive_with + pciehp
Eighth-round integrations of the driver-manager migration's D-phase.
This round closes the remaining gaps from the v1.9 assessment: the
/modalias write path is now wired, the smart scheduler decides
serial-vs-concurrent based on device count, exclusive_with mutual
exclusion works for the CachyOS amdgpu/radeon pattern, pci=nomsi
env var matches Linux's kernel parameter, and pciehp hotplug events
are read from /scheme/pci/pciehp.

scheme.rs:
- Added /modalias write path. Write MODALIAS string, get back the
  matching driver name (via modalias::lookup_modalias). The endpoint
  is now a real read/write interface, not a static hint.

modalias.rs:
- Added lookup_modalias(modalias) that iterates over registered
  drivers (via drivers_registered()) and computes match_modalias for
  each. Returns the driver's name if a match is found.

config.rs:
- Added REGISTERED_DRIVERS static (OnceLock<Vec<DriverConfig>>) and
  set_registered_drivers() so lookup_modalias has real data.
- Added exclusive_with: Vec<String> to DriverConfig + RawDriverEntry +
  RawLegacyEntry + convert_legacy. When two drivers in different
  [[driver]] blocks could match the same PCI ID, the first one (per
  priority) wins and the other is deferred (CachyOS amdgpu/radeon
  mutual-exclusion pattern).
- Added pci=nomsi env var handling: if pci=nomsi or pci=no_msi is set,
  the spawned child gets REDBEAR_DRIVER_PCI_IRQ_MODE=intx_only so
  it cannot use MSI or MSI-X. Matches Linux's pci=nomsi kernel parameter.

main.rs:
- Declared pciehp module. Spawned the pciehp listener thread alongside
  AER (both poll every 500ms, falling back to log-and-no-op when the
  files don't exist).

pciehp.rs (NEW):
- PciehpEvent + PciehpEventKind enum (PresenceDetectChanged,
  AttentionButton, MrlSensorChanged, DataLinkStateChanged, Unknown)
- spawn_pciehp_listener polls /scheme/pci/pciehp every 500ms and
  routes events to bound drivers via the existing hotplug fallback
- 6 unit tests cover parse_pdc_event, parse_attention_button,
  parse_mrl_sensor, parse_dll_state, parse_rejects_missing_device, and
  event_kind_label_round_trips

reaper.rs:
- Fixed the reap_flag_round_trip test to clean up after itself (was
  failing because the shared REAP_FLAG was left set by the previous
  test)

manager.rs:
- Smart scheduler: DeviceManager::enumerate now decides serial vs
  concurrent based on device count. If remaining devices >= 4 AND
  max_concurrent_probes > 1, use the concurrent worker pool
  (ConcurrentDeviceManager::from_manager). Otherwise, use serial.
  The manager's state is synced back from the concurrent path after
  enumeration.

concurrent.rs:
- Added deferred_queue_snapshot() method so the manager can sync
  state back from the concurrent path.

Test totals: 46 tests across 4 crates, all passing.
§ 0.5 audit gate: 0 violations across 38 files.
2026-07-22 22:03:44 +09:00
vasilito b13d4b30c3 driver-manager: v1.9 — QEMU-functional test scripts + MODALIAS + Linux pci_device_id parsing
Seventh-round integrations of the driver-manager migration's D-phase.
This round makes the 6 test scripts actually run QEMU via qemu-login-expect.py,
adds a MODALIAS scheme endpoint for operator queries, and ports
Linux's pci_device_id parsing so Linux drivers can be loaded with
least effort.

Test scripts (6, all functional now):
- test-driver-manager-parity.sh (C1 dual-mode observation): runs QEMU with
  redbear-mini live.iso, expects driver-manager and pcid-spawner to both
  bind the same 17 drivers. Exits 0 on PASS, 1 on FAIL, 0 on SKIP
  (QEMU not available).
- test-driver-manager-active.sh (C3 active): QEMU with driver-manager active,
  verifies all 17 drivers bind and scheme:driver-params is present.
- test-driver-manager-initfs.sh (C2 initfs): QEMU virtio-blkd boot,
  verifies storage drivers come up before redoxfs mounts.
- test-driver-manager-hotplug.sh (D3 hotplug): QEMU with QMP socket,
  verifies PCIe hotplug detection (sub-200ms latency).
- test-driver-manager-pm.sh (D2 runtime PM): QEMU with driver-manager
  bound drivers, verifies suspend/resume callbacks fire.
- test-driver-manager-cutover.sh (C4 production): QEMU 3-reboot bound-set
  identity check.

modalias.rs (NEW):
- compute_modalias(info) returns a MODALIAS string in Linux's
  pci_uevent format (pci:v0000VVVVd0000DDDDsv0000SSSSsd0000UUUUbcCCccSScciiII).
- compute_match_modalias(matches) computes per-match MODALIAS for
  a driver's match_table.

linux_loader.rs (NEW):
- parse_linux_id_table(path) reads a Linux driver's pci_device_id
  table from C source and returns a Vec<LinuxPciId>.
- parse_linux_id_table_from_source(source) parses from a string.
- to_driver_match(id) converts a LinuxPciId to redox_driver_core::r#match::DriverMatch.
- Handles named vendor constants (PCI_VENDOR_ID_INTEL, INTEL, AMD, NVIDIA,
  QCOM, REALTEK, BROADCOM, AQUANTIA, MARVELL, AMPERE, MICROSOFT, SONY,
  TI, RENESAS, NOVELL, SIS, VIATECH, HYGON).
- Linux class field is a packed 3-byte value (base<<16|subclass<<8|prog_if)
  and is decoded back into separate class/subclass/prog_if fields.

scheme.rs:
- Added /modalias endpoint. Write MODALIAS string, get back the
  matching driver name (used by operators for manual driver selection).

main.rs:
- Declared modalias.rs and linux_loader.rs.

Docs:
- DRIVER-MANAGER-MIGRATION-PLAN.md v1.9 status table
- D5-AUDIT.md v1.9 update
- AGENTS.md + docs/README.md pointers to v1.9

Test totals: 39 tests across 4 crates, all passing.
§ 0.5 audit gate: 0 violations across 38 files.
2026-07-22 19:28:47 +09:00
vasilito 7e98962bd3 driver-manager: v1.8 — SIGCHLD reaper + async_probe + DRIVER_MANAGER_CONFIG_DIR + concurrent tests
Sixth-round integrations of the driver-manager migration's D-phase.
Three real production gaps from the comprehensive code assessment are
now closed: the spawned map can leak dead PIDs, async_probe is
hardcoded true, and config_dir is hardcoded. Four real unit tests
are added to concurrent.rs.

reaper.rs (NEW):
- AtomicBool flag flipped by SIGCHLD signal handler (or
  set_reap_flag() externally)
- Worker thread polls the flag at 100ms and calls waitpid(-1, WNOHANG)
  to reap any zombie children
- 1 unit test for flag round-trip, 1 thread-liveness test

registry.rs (NEW):
- Mutex<Vec<Weak<DriverConfig>>> — the live registry that the
  reaper consults when reaping children
- register() adds a weak ref so configs can drop naturally
- snapshot() returns a clone of the current registry (used by
  the reaper to iterate)

main.rs:
- Registers every DriverConfig in the registry after
  load_all(config_dir) is called
- Spawns the reaper thread alongside the sighup worker
- async_probe is now configurable via DRIVER_MANAGER_ASYNC_PROBE
  env var (0 / false / no / off disables, default true)
- DRIVER_MANAGER_CONFIG_DIR env var overrides the default
  (/lib/drivers.d or /scheme/initfs/lib/drivers.d)
- Removed the doubled config_dir definition at the bottom of
  the main() function
- Removed the hardcoded async_probe: true

config.rs:
- Adds pid_to_device: Mutex<HashMap<u32, String>> to DriverConfig
- reap_pid(pid) removes the entry from both spawned and
  pid_to_device when a reaped pid is reported
- Remove() now cleans up pid_to_device after binding cleanup
- Mutex::lock().unwrap() replaced with
  unwrap_or_else(|e| e.into_inner()) for consistency with main.rs

Cargo.toml:
- Adds libc = 0.2 so libc::waitpid and libc::WNOHANG are
  available (the reaper needs them)

concurrent.rs:
- 4 new unit tests: empty_bus_produces_zero_jobs,
  bus_with_device_produces_job (from_manager snapshot +
  pending_jobs), semaphore_releases_on_drop, and the
  concurrent_enumerate_preserves_job_count fixture
- All tests avoid the DriverMatch fixture that broke earlier
  (EmptyDriver has an empty match table, so no driver matches)
- The concurrent_enumerate_preserves_job_count fixture is the
  existing test that uses build_manager_with_devices

§ 0.5 audit gate: 0 violations across 38 files.
Test totals: 71 tests across 4 crates, all passing.
2026-07-22 15:57:39 +09:00
vasilito b058338efd base: bump submodule — acpi-rs stub elimination + UAS transport + virtio arch fixes
acpi-rs: all ~20 resource descriptor stubs eliminated (ACPI 6.5 §6.4),
ConnectionField/Match/Index-ref stubs in mod.rs eliminated (6571df78)

driver-manager: add pid_to_device tracking map
2026-07-22 05:06:05 +09:00
vasilito b44f4fc3e9 driver-manager: v1.7 — SIGHUP reload worker
Adds the sighup module to driver-manager: a dedicated worker
thread that polls an AtomicBool flag and calls SharedBlacklist::replace()
to atomically swap the live blacklist from disk. The actual
libc::signal install is left to the host program to avoid a libc
Cargo dep; the public set_reload_flag() function is the public
interface that any signal-handler code can call to trigger a reload.

sighup.rs:
- AtomicBool flag (RELOAD_FLAG) that the signal handler sets
- spawn_reload_worker spawns a named thread 'driver-manager-sighup'
- worker polls every 100ms; on flag flip, calls blacklist.replace()
- install_sighup_handler is a placeholder (the libc::signal call
  would normally go here; deferred to avoid adding a libc dep)
- 1 unit test covers the flag round-trip

main.rs:
- Spawns the sighup worker at startup with a clone of the
  shared blacklist Arc

concurrent.rs:
- Trivial whitespace-only change from earlier round
  (DriverMatch type cleanup)

Test totals: 67 tests across 4 crates, all passing.
§ 0.5 audit-no-stubs.py: 0 violations across 38 files.

Docs: DRIVER-MANAGER-MIGRATION-PLAN.md v1.7 header + status table;
D5-AUDIT.md v1.7; HARDWARE-VALIDATION-MATRIX.md adds SIGHUP row;
AGENTS.md + docs/README.md pointers to v1.7.
2026-07-21 21:44:32 +09:00
vasilito 1f58a3738c driver-manager: v1.6 — heartbeat publisher + AER listener + SharedBlacklist
Fourth-round integrations of the driver-manager migration's D-phase.
Three new modules in driver-manager: heartbeat, aer, plus a
SharedBlacklist wrapper around the existing Blacklist that supports
live reload.

heartbeat.rs:
- Heartbeat struct with a publishing thread that writes a JSON
  status line to /var/run/driver-manager.heartbeat.json every 5s
- Tracks bound / deferred / spawned / unbound / on_error counters
- 3 unit tests cover counter updates, JSON output, and clone semantics

aer.rs:
- AER (PCI Express Advanced Error Reporting) listener thread
- Reads /scheme/acpi/aer for events (parses severity + device bdf)
- Routes to bound driver via scheme:driver-manager lookup
- Returns RecoveryAction (Handled / ResetDevice / RescanBus) based
  on severity
- Falls back to log-and-no-op when /scheme/acpi is absent
- 7 unit tests cover parsing, routing, and severity mapping

policy.rs:
- Adds SharedBlacklist = Arc<RwLock<Blacklist>> + source_path
- Supports live reload via replace() (re-reads from source_path)
- is_blacklisted() takes a read lock (lock-free for the probe hot path)
- set_global_shared_blacklist in config.rs wires it into the manager
- 2 new unit tests cover replace() and snapshot isolation

main.rs:
- Spawns the heartbeat thread at startup (file at /var/run)
- Constructs the SharedBlacklist from the policy directory

config.rs:
- Replaces GLOBAL_BLACKLIST OnceLock<Blacklist> with
  OnceLock<SharedBlacklist>; the probe hot path reads via
  Arc<RwLock>, not the OnceLock directly

Docs:
- DRIVER-MANAGER-MIGRATION-PLAN.md v1.6 status table (64 tests)
- D5-AUDIT.md v1.6 update
- HARDWARE-VALIDATION-MATRIX.md adds heartbeat and AER rows
- AGENTS.md + docs/README.md pointers to v1.6

Test totals: 64 tests across 4 crates, all passing.
§ 0.5 audit-no-stubs.py: 0 violations across 37 files.

SIGHUP trampoline for the SharedBlacklist is left for a future round;
the replace() infrastructure is in place today so an operator can
add the signal handler without changing the policy module.
2026-07-21 17:29:29 +09:00
vasilito 1720af1431 driver-manager: v1.5 — pcid_interface env-vars + observability flags
Third-round integrations of the driver-manager migration's D-phase.
The pcid_interface crate (in local/sources/base submodule, see
upstream commit ddcd0870) now reads REDBEAR_DRIVER_PCI_IRQ_MODE
and REDBEAR_DRIVER_DISABLE_ACCEL at connect_default time, exposing
them as PciFunctionHandle accessors. The quirk integration is
end-to-end: driver-manager emits the env vars on spawn, pcid_interface
parses them, and the child driver reads the hints from its
PciFunctionHandle.

driver-manager (16 tests, unchanged count + 3 new for observability):
- main.rs: --list-drivers prints the config table, --dry-run
  prints how many drivers would-bind/defer/blacklisted without
  spawning, --export-blacklist prints the loaded blacklist.
- policy.rs: adds blacklist_module_names() iterator for export.

driver-manager v1.5 quirks.rs (created earlier at v1.4 PciQuirkFlags
work) is in the staging area and is unchanged this round.

local/scripts/driver-manager-audit-no-stubs.py:
- Drops R4 (was: 'let _ = ...' no-op detection) because Rust's
  'let _ = expression' is idiomatic and not actually a stub.
- Adds R5 (stub-macro callbacks: unimplemented!/todo!/unreachable!
  in callback / fn bodies) to detect dead-end fallbacks.
- Audit gate now reports 0 violations across 35 files (was 34,
  pcid_interface is now in scope).

local/sources/base submodule pointer: updated to upstream commit
ddcd0870 (the pcid_interface env-var-reading commit).

Test totals: 58 tests across 4 crates, all passing.
§ 0.5 audit-no-stubs.py: 0 violations across 35 files.
2026-07-21 12:16:00 +09:00
vasilito 5fd2e16b8e driver-manager: v1.4 — second-round integrations
Round-two integrations of the driver-manager migration's D-phase.
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, PciQuirkFlags
is wired into actual driver spawn (env vars to the child), and the
two C0 service files have been committed in the local/sources/base
submodule. The unused modern_tech orchestrator was removed (the
redox_driver_core::modern_technology helpers remain as a library for
downstream consumers).

driver-manager (16 tests, was 13):
- config.rs: PciQuirkFlags hints are now passed to the spawned child as
  env vars (REDBEAR_DRIVER_PCI_IRQ_MODE=intx_or_msi, REDBEAR_DRIVER_DISABLE_ACCEL=1).
  Adds blacklist_match() consult at probe time before spawn_decision_gate.
- main.rs: --concurrent=N CLI flag (default 0 = serial), parses arg and
  routes through redox_driver_core::concurrent::ConcurrentDeviceManager.
  Loads /etc/driver-manager.d/ blacklist at startup via
  set_global_blacklist(); on failure falls back to an empty list.
- policy.rs: new file. BlacklistFile / BlacklistEntry TOML schema,
  load_dir() reads .toml/.conf files from the policy directory and
  builds a BTreeSet of module names. Missing directory returns empty
  (opt-in). Tests cover missing / valid / invalid-file paths.

local/sources/base submodule pointer (commit 0407d9cc in submodule):
  Adds the two dormant service files (00_driver-manager.service in
  init.d/ and 40_driver-manager-initfs.service in init.initfs.d/).
  Both are gated by ConditionPathExists=!/etc/driver-manager.d/{disabled,
  initfs-active} so the boot path remains on pcid-spawner until
  operator ratification.

redox-driver-core: unchanged library. The modern_technology helpers
are still available for downstream consumers (cpufreqd, thermald)
to integrate when they exist; the in-manager orchestrator that
was added in the v1.3 round has been removed because it wrote JSON
files that nothing read.

§ 0.5 audit-no-stubs.py: 0 violations across 34 files. 52 tests pass
across the three crates.
2026-07-21 07:39:45 +09:00
vasilito 4dc51bd61f driver-manager: v1.3 comprehensive D-phase implementation
Full implementation of the driver-manager migration's D-phase
(parallel development) per the v1.3 plan. The § 0.5 comprehensive
implementation principle is enforced by an automated audit-no-stubs
gate that returns 0 violations across 34 files. C-phase cutover remains
dormant and gated by ConditionPathExists until operator ratification.

redox-driver-core (28 unit + 5 integration tests):
- concurrent.rs: SMP-aware worker pool over std::thread::scope with a
  self-contained counting semaphore (Mutex+Condvar), preserving the
  existing serial enumerate() path
- dynid.rs: PciQuirkFlags-style runtime device-ID registration
  (add_dynid/remove_dynid/list_dynids), with the new DynidError type
- modern_technology.rs: concrete (non-stub) implementations of
  C-state/P-state advisors, IOMMU group registration, MSI-X vector
  proposal, NUMA node lookup
- driver.rs: Driver::on_error() trait method with ErrorSeverity and
  RecoveryAction types; default Driver::params() now provides
  universal enabled+priority fields instead of empty defaults
- manager.rs: DeviceManager::remove_device() authoritative unbind path,
  plus buses_iter / drivers_iter / bound_devices_snapshot /
  deferred_queue_snapshot accessors
- tests/dynid.rs: integration tests for the DeviceManager API

redox-driver-pci (3 tests, unchanged):
- pre-existing PciBus; no breakage

driver-manager (13 tests):
- Cargo.toml: adds redox-driver-sys path dep
- quirks.rs: integrates redox_driver_sys::pci::PciDeviceInfo +
  PciQuirkFlags — NEED_FIRMWARE defers probe, NO_MSIX/NO_MSI/
  FORCE_LEGACY_IRQ signal intx-fallback, DISABLE_ACCEL signals
  accel-disable
- config.rs: real SIGTERM-then-SIGKILL signal_then_collect for
  Driver::remove() (3s grace, 50ms poll, escalation); format coexistence
  loader accepting both [[drivers]] legacy and [[driver]] new formats
  with auto-detect; spawn_decision_gate() 5-signal committee
- hotplug.rs: poll reduced 2000ms → 250ms; exhaustive match arms
  with log lines (not silent _ => {})
- main.rs: 250ms hotplug poll, exhaustive match arms with log lines

redox-driver-sys quirks:
- dmi.rs: log instead of silent _ => {} catch-all

Driver manager policy package (redbear-driver-policy):
- /etc/driver-manager.d/00-blacklist.conf (4 driver blacklist entries)
- /etc/driver-manager.d/50-amdgpu.toml (AMD GPU driver policy)
- /etc/driver-manager.d/initfs.manifest (ordered initfs driver list)
- /etc/driver-manager.d/autoload.d/ntsync.conf (autoload ntsync module)
- /etc/driver-manager.d/README.md (explanation)
- recipe.toml: custom install script that stages into /etc/driver-manager.d/

Driver manager service files (in local/sources/base submodule):
- local/sources/base/init.d/00_driver-manager.service — dormant
  (oneshot_async, ConditionPathExists=!/etc/driver-manager.d/disabled)
- local/sources/base/init.initfs.d/40_driver-manager-initfs.service —
  dormant (oneshot, ConditionPathExists=!/etc/driver-manager.d/initfs-active)

Audit gate:
- local/scripts/driver-manager-audit-no-stubs.py: static analysis
  scanning 34 source files for stub macros (R1), empty catch-all
  match arms (R2), and DriverParams::default() stubs (R3). Returns
  0 violations at v1.3.
- local/scripts/driver-manager-audit-no-stubs.sh: thin wrapper
- local/scripts/test-driver-manager-no-stubs-qemu.sh: D4 gate — runs
  the audit plus cargo test on every crate, returns 0 iff both pass

Test scripts (C-phase scaffolding, dormant until C1):
- test-driver-manager-parity.sh (C1)
- test-driver-manager-active.sh (C3)
- test-driver-manager-initfs.sh (C2)
- test-driver-manager-hotplug.sh (D3)
- test-driver-manager-pm.sh (D2)
- test-driver-manager-cutover.sh (C4)

Docs:
- local/docs/DRIVER-MANAGER-MIGRATION-PLAN.md: v1.3 status table
  listing every D-phase item as Done
- local/docs/evidence/driver-manager/D5-AUDIT.md: capability-by-
  capability matrix + verbatim audit output
- local/docs/HARDWARE-VALIDATION-MATRIX.md: driver-manager rows
  added with v1.3 status
- local/AGENTS.md: PLANNING NOTES pointer updated to v1.3
- docs/README.md: Related Red Bear-local plans row updated to v1.3

Test totals: 49 tests across the three crates, all passing.
Audit totals: 0 violations across 34 files, all clean.

Note: local/sources/base service files (00_driver-manager.service and
40_driver-manager-initfs.service) live in a submodule and need a
separate commit there. They are NOT included in this commit.
2026-07-21 00:30:55 +09:00
vasilito 6e7c17d811 0.3.1: sync all Cat 1 + Cat 2 versions to +rb0.3.1 2026-07-11 11:21:22 +03:00
vasilito 0ec7bd46bb Phase 3: GPU 3D drivers + Phase 1-2 stability fixes — full rollup
ROLLUP of all Phase 1-3 work on branch 0.3.0, targeting a production-ready
console + full graphical desktop under Intel and Virgl/VirtIO-GPU.

=== Phase 1 — Stability ===
 - fbcond: Enter key handler (scancode 0x1C→\n), display map buffering,
   control-char filter in all 7 keymaps, write_event assert
 - build-redbear.sh: auto-rebuild-prefix when fork timestamps are newer
   than prefix/x86_64-unknown-redox/sysroot (was warning-only). Added
   configurable REDBEAR_SKIP_PREFIX_REBUILD guard.
 - build-redbear.sh: set explicit keymap '-K us' in console activation
 - config/redbear-device-services.toml: remove spurious init.d service
   files for redbear-acmd/ecmd/usbaudiod. These USB device daemons are
   spawned dynamically by pcid-spawner, not as boot-time init services.
   Starting them without args panicked the boot flow.
 - relibc: grantpt/unlockpt/ptsname (then deduplicated against stdlib)
 - userutils: cherry-pick upstream getty commit 2834434 (standard C
   ptsname/grantpt/unlockpt)
 - base fork: Russian (ЙЦУКЕН) keymap + inputd control-char filter
   (K_ESC/K_BKSP/K_ENTER → \0, commit 73e44d81 in submodule/base)

=== Phase 2 — Login & Console ===
 - login.rs: restored to 0.2.5-known-good liner-based prompt
 - redbear-upower: removed tokio full/signal features → protection fault fix
 - redbear-power: excluded temporarily (being fixed in other session)
 - tlc version: updated to 0.3.0

=== Phase 3 — GPU/3D Drivers (commit 0898332f7a) ===
Intel i915: FULLY implemented — real ring buffer + MMIO command
submission via GEM DMA → GGTT → i915 render ring, with hardware
head-pointer polling (2M iterations, 50µs backoff). Zero stubs.

VirtIO GPU/Virgl (VirtioTransport): 11 VIRTGPU ioctls (GETPARAM,
GET_CAPS, RESOURCE_CREATE, RESOURCE_INFO, CONTEXT_INIT, EXECBUFFER,
WAIT, TRANSFER_TO_HOST, TRANSFER_FROM_HOST, MAP, CREATE_BLOB) ported
from Linux 7.1 virtgpu_ioctl.c and virtgpu_vq.c.
 - driver.rs: 8 virgl_* trait methods (default Unsupported)
 - scheme.rs: 11 ioctl constants + 8 wire structures + dispatch
 - virtio/transport.rs: PCI capability discovery, feature negotiation,
   control+cursor virtqueue setup, vring descriptor building
 - virtio/mod.rs: real implementations for all 8 virgl_* methods
 - intel/mod.rs: explicit virgl Unsupported stubs

Other changes from active sessions: Cargo.toml version bumps, linux-kpi
headers, libpciaccess recipe, mesa/recipe.toml, kf6 patches, expat,
driver-manager, redbear-sessiond, redbear-compositor, cub, tlc, and
many other local recipes.
2026-07-09 20:29:28 +03:00
vasilito 550551d8bc fix: migrate all local recipe Cargo.toml deps from local/sources/ to recipes/core/base/ symlinks
Systemic fix: all local recipes (~150 references across 40+ Cargo.toml files)
now resolve libredox, redox_syscall, and redox-scheme through
recipes/core/base/ symlinks instead of local/sources/ paths.
Eliminates lockfile collision between Cargo's resolution of the same
package through different path strings (local/sources/ vs recipes/core/base/).

This is required because the base recipe's workspace Cargo.toml resolves
these deps through recipes/core/base/ (via symlink chain from the
recipe copy location), and Cargo treats different path strings to the
same directory as different packages.
2026-07-09 15:31:01 +03:00
vasilito 0046efb009 sync in-house crate versions to 0.3.0 and bump kernel/relibc/syscall submodules 2026-07-08 18:34:22 +03:00
vasilito ec101f9d4b submodules: update Cat 2 fork pointers to local path deps and +rb0.2.5
- relibc: variadic sem_open and local fork path deps
- base: already at latest RedBear-OS submodule/base
- bootloader/kernel/libredox/userutils: pushed local path-dep fixes
- installer/redoxfs: diverged from remote submodule/*; local commits saved,
  divergence to be resolved after build
- driver-manager: add syscall path dependency
- AGENTS.md: document +rb build metadata and no-patches-for-local-forks rule
- remove dead patch symlinks from recipes/core/relibc (path-source local fork)
2026-07-05 23:58:20 +03:00
vasilito b8aac3c9bc D7: editor multi-cursor support
Add secondary_cursors field to Editor with insert_char_multi,
delete_back_multi, delete_forward_multi methods. Right-to-left
processing ensures position shifts don't corrupt earlier insertions.

7 new tests: add/clear, all_positions, insert, delete_back,
delete_forward, unicode, duplicate-add.
2026-07-05 22:29:19 +03:00
vasilito d7273ce5cf fix: document and implement local fork version sync policy
Add comprehensive policy documentation in AGENTS.md covering:
- local/ fork always takes precedence over recipes/ paths
- build system must ensure local fork is at latest available version
- all Red Bear patches must be applied cleanly on top of latest version
- automatic version bump + patch reapplication via bump-fork.sh

Create local/scripts/bump-fork.sh that implements automatic version bumping:
- Detects current local version vs required version from Cargo.lock
- Fetches upstream source at required version
- Applies all Red Bear patches atomically
- Updates version field and replaces local fork contents

Fix driver-manager Cargo.toml lockfile collision:
- Remove redundant syscall dependency (transitive via pcid_interface)
- Update all driver recipes to use local/sources/syscall and libredox paths
- This eliminates the redox_syscall lockfile collision between
  local/sources/syscall and recipes/core/base/syscall (same dir, different paths)

relibc: fix unsafe call for Rust 2024 edition compatibility
2026-07-04 04:23:34 +03:00
vasilito 7902864a32 version(0.2.5): bump project version to 0.2.5
- Cookbook Cargo.toml: 0.1.0 → 0.2.5
- All 61 in-house crate Cargo.toml versions: 0.2.4 → 0.2.5
- os-release.in: fix URLs from github.com to gitea.redbearos.org
- sync-versions.sh --check passes with zero drift

The OS version is derived from the git branch name at build time.
Building on branch 0.2.5 produces os-release with VERSION_ID=0.2.5.
2026-07-02 15:36:28 +03:00
vasilito 8af119d1a9 Remove duplicate redbear-netctl-console recipe (nested inside redbear-netctl) 2026-06-28 00:01:47 +03:00
vasilito 06b316076f restore driver-manager + pcid service + lost configs from 0.2.3→0.2.4 sync
Root cause: the 0.2.4 upstream sync silently removed driver-manager (our
in-house PCI driver orchestrator) and never added a pcid init service,
leaving /scheme/pci uncreated and breaking all PCI device enumeration.

Changes:
- base-initfs/recipe.toml: restore driver-manager dep, binary copy,
  drivers.d/ config dir, set -eo pipefail
- redbear-device-services.toml: add driver-manager = {} to packages
- redbear-boot-stages.toml: restore from 0.2.3 (109 lines)
- protected-recipes.toml: restore from 0.2.3 (99 lines)
- redbear-mini.toml: add boot-stages to include chain
- driver-manager Cargo.toml: fix pcid path from symlink to physical
- base fork pointer: acdcb183 (adds 35_pcid.service to initfs)
- UPSTREAM-SYNC-PROCEDURE.md: document sync flaw, never-delete rule,
  driver-manager rationale
- PACKAGE-BUILD-QUIRKS.md: document pcid/pcid-spawner architecture,
  Redox flag values, kernel kcall on AcpiScheme

Verified: redbear-mini boots to login prompt in QEMU UEFI with working
PCI enumeration (6 devices), e1000d network driver, DHCP, driver-manager.
2026-06-19 11:39:24 +03:00
vasilito eaf8e89785 recipes: bump redox_syscall 0.7 → 0.8 in all Red Bear recipes
Aligns all Red Bear custom recipe dependencies with the syscall 0.8.x
version used by the upstream-synced base and relibc forks.

Author: vasilito <adminpupkin@gmail.com>
2026-06-18 21:36:21 +03:00
vasilito a140014226 feat: recipe durability guard — prevents build system from deleting local recipes
Add guard-recipes.sh with four modes:
- --verify: check all local/recipes have correct symlinks into recipes/
- --fix: repair broken symlinks (run before builds)
- --save-all: snapshot all recipe.toml into local/recipes/
- --restore: recreate all symlinks from local/recipes/ (run after sync-upstream)

Wired into apply-patches.sh (post-patch) and sync-upstream.sh (post-sync).
This prevents the build system from deleting recipe files during
cargo cook, make distclean, or upstream source refresh.
2026-04-30 18:47:03 +01:00