driver-manager: fix scheme collision and scheme availability check; redox-driver-sys: CPU affinity logging; redbear-hwutils: timer characterization

This commit is contained in:
2026-05-19 23:50:32 +03:00
parent a9051ebb91
commit 861e6f88d2
6 changed files with 97 additions and 19 deletions
@@ -291,12 +291,21 @@ fn read_cpu_count() -> Result<u8> {
#[cfg(target_os = "redox")]
fn alloc_cpu_id() -> u8 {
match read_cpu_count() {
Ok(n) if n > 0 => {
Ok(0) => {
log::warn!("redox-driver-sys: read_cpu_count returned 0, defaulting to BSP (cpu 0)");
0
}
Ok(n) => {
use std::sync::atomic::{AtomicU8, Ordering};
static NEXT: AtomicU8 = AtomicU8::new(0);
NEXT.fetch_add(1, Ordering::Relaxed) % n
let cpu_id = NEXT.fetch_add(1, Ordering::Relaxed) % n;
log::debug!("redox-driver-sys: alloc_cpu_id selected cpu {} (of {})", cpu_id, n);
cpu_id
}
Err(err) => {
log::warn!("redox-driver-sys: read_cpu_count failed ({}), defaulting to BSP (cpu 0)", err);
0
}
_ => 0,
}
}
@@ -2,7 +2,18 @@
path = "source"
[build]
template = "cargo"
template = "custom"
script = """
# driver-manager runs in both rootfs and initfs; initfs has no dynamic linker,
# so we must build a statically linked binary.
export RUSTFLAGS="${RUSTFLAGS} -Ctarget-feature=+crt-static -L native=${COOKBOOK_SYSROOT}/lib"
"${COOKBOOK_CARGO}" build \
--manifest-path "${COOKBOOK_SOURCE}/Cargo.toml" \
--target "${TARGET}" \
${build_flags}
mkdir -pv "${COOKBOOK_STAGE}/usr/bin"
cp -v "target/${TARGET}/${build_type}/driver-manager" "${COOKBOOK_STAGE}/usr/bin/driver-manager"
"""
[dependencies]
redox-driver-core = {}
@@ -176,10 +176,24 @@ fn open_pcid_channel(device_path: &str) -> Result<OwnedFd, ProbeResult> {
}
fn check_scheme_available(name: &str) -> bool {
if std::path::Path::new(&format!("/scheme/{}", name)).exists() {
return true;
let path = format!("/scheme/{}", name);
// Use read_dir instead of Path::exists() because Redox scheme paths
// may not respond correctly to exists()/metadata() while still being
// fully functional for directory enumeration and file open.
// This was the root cause of "dependency scheme not ready: pci" even
// though PciBus::enumerate_devices (which uses read_dir) succeeded.
match fs::read_dir(&path) {
Ok(_) => true,
Err(err) => {
log::debug!(
"driver-manager: scheme availability check failed for {}: {} (exists={})",
path,
err,
std::path::Path::new(&path).exists()
);
false
}
}
false
}
impl Driver for DriverConfig {
@@ -52,6 +52,7 @@ impl log::Log for StderrLogger {
fn run_enumeration(
manager: &Arc<Mutex<DeviceManager>>,
scheme: &DriverManagerScheme,
initfs: bool,
) -> (usize, usize) {
let enum_start = Instant::now();
let events = match manager.lock() {
@@ -92,7 +93,11 @@ fn run_enumeration(
log::info!("bus {} enumerated {} device(s)", bus, device_count);
}
ProbeEvent::BusEnumerationFailed { bus, error } => {
log::error!("bus {} enumeration failed: {:?}", bus, error);
if initfs && *bus == "pci" {
log::warn!("bus {} enumeration not yet ready (initfs, pcid may still be starting): {:?}", bus, error);
} else {
log::error!("bus {} enumeration failed: {:?}", bus, error);
}
}
ProbeEvent::AlreadyBound {
device,
@@ -418,7 +423,7 @@ fn main() {
if manager_config.async_probe {
let handle = thread::spawn(move || {
let (bound, deferred) = run_enumeration(&mgr_clone, scheme_clone.as_ref());
let (bound, deferred) = run_enumeration(&mgr_clone, scheme_clone.as_ref(), initfs);
log::info!("async enum: {} bound, {} deferred", bound, deferred);
});
if handle.join().is_err() {
@@ -426,13 +431,21 @@ fn main() {
process::exit(1);
}
} else {
let (bound, deferred) = run_enumeration(&manager, scheme.as_ref());
let (bound, deferred) = run_enumeration(&manager, scheme.as_ref(), initfs);
log::info!("enum complete: {} bound, {} deferred", bound, deferred);
}
if let Err(err) = scheme::start_scheme_server(Arc::clone(&scheme)) {
log::error!("{err}");
process::exit(1);
match scheme::start_scheme_server(Arc::clone(&scheme)) {
Ok(true) => {
log::info!("driver-manager: scheme server started successfully");
}
Ok(false) => {
log::warn!("driver-manager: scheme already registered — another instance is active, continuing without scheme server");
}
Err(err) => {
log::error!("{err}");
process::exit(1);
}
}
if hotplug_mode {
@@ -425,13 +425,19 @@ pub fn notify_unbind(scheme: &DriverManagerScheme, pci_addr: &str) {
}
#[cfg(target_os = "redox")]
pub fn start_scheme_server(scheme: Arc<DriverManagerScheme>) -> std::result::Result<(), String> {
pub fn start_scheme_server(scheme: Arc<DriverManagerScheme>) -> std::result::Result<bool, String> {
let socket = Socket::create()
.map_err(|err| format!("driver-manager: failed to create scheme socket: {err}"))?;
let mut server = SchemeServer::new(scheme);
register_sync_scheme(&socket, SCHEME_NAME, &mut server)
.map_err(|err| format!("driver-manager: failed to register scheme:{SCHEME_NAME}: {err}"))?;
if let Err(err) = register_sync_scheme(&socket, SCHEME_NAME, &mut server) {
let msg = format!("{err}");
if msg.contains("File exists") {
log::warn!("driver-manager: scheme:{SCHEME_NAME} already registered (initfs instance active), returning gracefully");
return Ok(false);
}
return Err(format!("driver-manager: failed to register scheme:{SCHEME_NAME}: {err}"));
}
log::info!("driver-manager: registered scheme:{SCHEME_NAME}");
@@ -464,10 +470,10 @@ pub fn start_scheme_server(scheme: Arc<DriverManagerScheme>) -> std::result::Res
})
.map_err(|err| format!("driver-manager: failed to spawn scheme server thread: {err}"))?;
Ok(())
Ok(true)
}
#[cfg(not(target_os = "redox"))]
pub fn start_scheme_server(_scheme: Arc<DriverManagerScheme>) -> std::result::Result<(), String> {
Ok(())
pub fn start_scheme_server(_scheme: Arc<DriverManagerScheme>) -> std::result::Result<bool, String> {
Ok(true)
}
@@ -47,6 +47,16 @@ fn timespec_to_nanos(time: &TimeSpec) -> i128 {
i128::from(time.tv_sec) * 1_000_000_000i128 + i128::from(time.tv_nsec)
}
fn check_timer_source(name: &str, path: &str) -> &'static str {
if Path::new(path).exists() {
println!("timer_source={} path={} present=1", name, path);
"present"
} else {
println!("timer_source={} path={} present=0", name, path);
"missing"
}
}
fn run() -> Result<(), String> {
parse_args(PROGRAM, USAGE, std::env::args()).map_err(|err| {
if err.is_empty() {
@@ -57,6 +67,10 @@ fn run() -> Result<(), String> {
println!("=== Red Bear OS Timer Runtime Check ===");
check_timer_source("hpet", "/scheme/sys/hpet");
check_timer_source("pit", "/scheme/sys/pit");
check_timer_source("lapic", "/scheme/sys/lapic");
let time_path = monotonic_path()?;
let time_fd = Fd::open(&time_path, flag::O_RDWR, 0)
@@ -78,6 +92,17 @@ fn run() -> Result<(), String> {
return Err("monotonic timer did not advance".to_string());
}
let expected_ns: i128 = 50_000_000;
let deviation_ns = (delta_ns - expected_ns).abs();
println!("monotonic_expected_ns={expected_ns}");
println!("monotonic_deviation_ns={deviation_ns}");
if deviation_ns > 20_000_000 {
println!("timer_precision=coarse deviation_ns={deviation_ns} (threshold=20000000)");
} else {
println!("timer_precision=ok deviation_ns={deviation_ns} (threshold=20000000)");
}
println!("monotonic_progress=ok");
Ok(())
}