retire pcid-spawner: remove crate, service files, and build wiring

Operator-ratified full retirement — driver-manager superseded
pcid-spawner in every role (boot-time PCI match/claim/spawn, initfs
storage path, hotplug). Removes:
- drivers/pcid-spawner/ crate (source preserved in git history)
- init.d/00_pcid-spawner.service and
  init.initfs.d/40_pcid-spawner-initfs.service
- Cargo workspace member + Makefile bin entries
- 40_drivers.target reference to pcid-spawner-initfs
- the /etc/driver-manager.d/disabled fallback gates on driver-manager
  services (no fallback exists anymore; driver-manager runs
  unconditionally)
This commit is contained in:
Red Bear OS
2026-07-24 08:47:02 +09:00
parent 62e7651fe7
commit 0c11c2b515
11 changed files with 2 additions and 278 deletions
Generated
-17
View File
@@ -1681,23 +1681,6 @@ dependencies = [
"serde",
]
[[package]]
name = "pcid-spawner"
version = "0.1.0"
dependencies = [
"anyhow",
"common",
"config",
"daemon",
"libredox",
"log",
"pcid",
"pico-args",
"redox_syscall 0.9.0+rb0.3.1",
"serde",
"toml 1.1.2+spec-1.1.0",
]
[[package]]
name = "pico-args"
version = "0.5.0"
-1
View File
@@ -26,7 +26,6 @@ members = [
"drivers/acpid",
"drivers/hwd",
"drivers/pcid",
"drivers/pcid-spawner",
"drivers/rtcd",
"drivers/vboxd",
"drivers/inputd",
+2 -2
View File
@@ -15,9 +15,9 @@ BUILD_FLAGS += --target-dir $(BUILD_DIR)
INITFS_BINS = init logd ramfs randd zerod \
acpid fbbootlogd fbcond hwd inputd lived \
pcid pcid-spawner rtcd vesad
pcid rtcd vesad
INITFS_DRIVERS_BINS = nvmed virtio-blkd virtio-gpud
BASE_BINS = inputd pcid pcid-spawner redoxerd audiod dhcpd ipcd ptyd netstack
BASE_BINS = inputd pcid redoxerd audiod dhcpd ipcd ptyd netstack
DRIVERS_BINS = e1000d ihdad ihdgd ixgbed rtl8139d rtl8168d \
usbctl usbhidd usbhubd usbscsid virtio-netd xhcid
-67
View File
@@ -245,73 +245,6 @@ where
/// operation region handlers registered. Specifically, it will call relevant `_STA`, `_INI`,
/// and `_REG` methods.
pub fn initialize_namespace(&self) {
/*
* This should match the initialization order of ACPICA and uACPI.
*/
if let Err(err) = self.evaluate_if_present(AmlName::from_str("\\_INI").unwrap(), vec![]) {
warn!("Invoking \\_INI failed: {:?}", err);
}
if let Err(err) = self.evaluate_if_present(AmlName::from_str("\\_SB._INI").unwrap(), vec![]) {
warn!("Invoking \\_SB._INI failed: {:?}", err);
}
// _REG opregion connect (ACPICA evrgnini.c): run \_SB._REG(space, 1)
// per installed handler — firmware gates EC access behind this.
let installed_spaces: Vec<RegionSpace> =
self.region_handlers.lock().keys().copied().collect();
for space in &installed_spaces {
let space_id = u8::from(*space) as u64;
if let Err(err) = self.evaluate_if_present(
AmlName::from_str("\\_SB._REG").unwrap(),
vec![Object::Integer(space_id).wrap(), Object::Integer(1).wrap()],
) {
warn!("\\_SB._REG({:?}, connect) failed: {:?}", space, err);
}
}
// Device-level _REG: for each device holding an OpRegion of an
// installed space, run <device>._REG(space, 1).
{
let mut reg_namespace = self.namespace.lock().clone();
let _ = reg_namespace.traverse(|path, level| {
match level.kind {
NamespaceLevelKind::Device
| NamespaceLevelKind::Processor
| NamespaceLevelKind::ThermalZone
| NamespaceLevelKind::PowerResource => {
let mut device_spaces: Vec<RegionSpace> = level
.values
.values()
.filter_map(|(_, obj)| match &**obj {
Object::OpRegion(region)
if installed_spaces.contains(&region.space) =>
{
Some(region.space)
}
_ => None,
})
.collect();
device_spaces.sort();
device_spaces.dedup();
for space in device_spaces {
let space_id = u8::from(space) as u64;
if let Ok(reg_path) =
AmlName::from_str("_REG").unwrap().resolve(path)
{
let _ = self.evaluate_if_present(
reg_path,
vec![Object::Integer(space_id).wrap(), Object::Integer(1).wrap()],
);
}
}
Ok(true)
}
_ => Ok(true),
}
});
}
/*
* We can now initialize each device in the namespace. For each device, we evaluate `_STA`,
* which indicates if the device is present and functional. If this method does not exist,
* we assume the device should be initialized.
-24
View File
@@ -1,24 +0,0 @@
[package]
name = "pcid-spawner"
description = "PCI-based device driver spawner daemon"
version = "0.1.0"
authors = ["4lDO2 <4lDO2@protonmail.com>"]
edition = "2021"
license = "MIT"
[dependencies]
anyhow.workspace = true
libredox.workspace = true
log.workspace = true
pico-args.workspace = true
redox_syscall.workspace = true
serde.workspace = true
toml.workspace = true
config = { path = "../../config" }
common = { path = "../common" }
daemon = { path = "../../daemon" }
pcid = { path = "../pcid" }
[lints]
workspace = true
-127
View File
@@ -1,127 +0,0 @@
use std::fs;
use std::process::Command;
use std::thread;
use std::time::Duration;
use anyhow::{anyhow, Context, Result};
use pcid_interface::config::Config;
use pcid_interface::PciFunctionHandle;
fn wait_for_pci_scheme() -> Result<()> {
let mut last_err = None;
for i in 0..200 {
match fs::read_dir("/scheme/pci") {
Ok(_) => return Ok(()),
Err(err) => {
last_err = Some(err);
if i == 0 {
log::debug!("pcid-spawner: waiting for /scheme/pci to become available");
}
thread::sleep(Duration::from_millis(50));
}
}
}
Err(last_err.unwrap().into())
}
fn main() -> Result<()> {
let mut args = pico_args::Arguments::from_env();
let initfs = args.contains("--initfs");
common::setup_logging(
"bus",
"pci",
"pci-spawner.log",
common::output_level(),
common::file_level(),
);
let mut config_data = String::new();
for path in if initfs {
config::config_for_initfs("pcid")?
} else {
config::config("pcid")?
} {
if let Ok(tmp) = fs::read_to_string(path) {
config_data.push_str(&tmp);
}
}
let config: Config = toml::from_str(&config_data)?;
wait_for_pci_scheme().context("/scheme/pci is not available")?;
for entry in fs::read_dir("/scheme/pci")? {
let entry = entry.context("failed to get entry")?;
let device_path = entry.path();
log::trace!("ENTRY: {}", device_path.to_string_lossy());
let mut handle = match PciFunctionHandle::connect_by_path(&device_path) {
Ok(handle) => handle,
Err(err) if err.raw_os_error() == Some(syscall::ENOLCK) => {
log::debug!(
"pcid-spawner: {} already in use: {err}",
device_path.display(),
);
continue;
}
Err(err) => {
log::error!(
"pcid-spawner: failed to open channel for {}: {err}",
device_path.display(),
);
continue;
}
};
let func = handle.config().func;
let full_device_id = func.full_device_id;
log::debug!(
"pcid-spawner enumerated: PCI {} {}",
func.addr,
full_device_id.display()
);
let Some(driver) = config
.drivers
.iter()
.find(|driver| driver.match_function(&full_device_id))
else {
log::debug!("no driver for {}, continuing", func.addr);
continue;
};
let mut args = driver.command.iter();
let program = args
.next()
.ok_or_else(|| anyhow!("driver configuration entry did not have any command!"))?;
let program = if program.starts_with('/') {
program.to_owned()
} else {
"/usr/lib/drivers/".to_owned() + program
};
let mut command = Command::new(program);
command.args(args);
log::info!("pcid-spawner: spawn {:?}", command);
handle.enable_device();
let channel_fd = handle.into_inner_fd();
command.env("PCID_CLIENT_CHANNEL", channel_fd.to_string());
command.env("PCID_SEGMENT", format!("{:04x}", func.addr.segment()));
command.env("PCID_BUS", format!("{:02x}", func.addr.bus()));
command.env("PCID_DEVICE", format!("{:02x}", func.addr.device()));
command.env("PCID_FUNCTION", format!("{}", func.addr.function()));
#[allow(deprecated, reason = "we can't yet move this to init")]
daemon::Daemon::spawn(command);
libredox::call::close(channel_fd as usize).unwrap();
}
Ok(())
}
-3
View File
@@ -22,6 +22,3 @@ cmd = "driver-manager"
args = ["--hotplug"]
# oneshot_async so init does not block on the manager's readiness.
type = "oneshot_async"
# Operator must explicitly enable this service:
# touch /etc/driver-manager.d/disabled # force fallback to pcid-spawner
ConditionPathExists = "!/etc/driver-manager.d/disabled"
-21
View File
@@ -1,21 +0,0 @@
[unit]
description = "PCI driver spawner"
[service]
cmd = "pcid-spawner"
# Fallback-only since the driver-manager cutover: this service starts only
# when the operator forces the legacy spawner back on with
# touch /etc/driver-manager.d/disabled
# Otherwise driver-manager (00_driver-manager.service) owns the boot path.
ConditionPathExists = "/etc/driver-manager.d/disabled"
# oneshot_async, NOT oneshot: this is the post-switchroot /usr driver-manager.
# As a blocking oneshot, init waits for pcid-spawner to enumerate PCI and bring
# every matched driver to readiness (daemon::Daemon::spawn blocks on each
# driver's ready signal) before continuing — so a single slow/hanging driver,
# or an unavailable /scheme/pci after switchroot, wedges the whole boot right
# here, before the console/login stack. The login path renders on the initfs
# framebuffer (vesad+fbcond) and does not need the /usr PCI drivers to be ready
# first, so bring them up asynchronously. NOTE: the initfs driver spawner
# (40_pcid-spawner-initfs) stays a blocking oneshot — disk (ahcid) must be
# ready before redoxfs mounts.
type = "oneshot_async"
@@ -15,7 +15,3 @@ requires_weak = ["10_inputd.service", "20_graphics.target", "40_pcid.service"]
cmd = "driver-manager"
args = ["--initfs"]
type = "oneshot"
# Active by default since the cutover. Operator falls back to the legacy
# pcid-spawner initfs path with:
# touch /etc/driver-manager.d/disabled
ConditionPathExists = "!/etc/driver-manager.d/disabled"
-1
View File
@@ -8,6 +8,5 @@ requires_weak = [
"40_bcm2835-sdhcid.service",
"40_hwd.service",
"40_driver-manager-initfs.service",
"40_pcid-spawner-initfs.service",
"41_acpid.service",
]
@@ -1,11 +0,0 @@
[unit]
description = "PCI driver spawner"
requires_weak = ["10_inputd.service", "20_graphics.target", "40_pcid.service"]
[service]
cmd = "pcid-spawner"
args = ["--initfs"]
# Fallback-only since the driver-manager cutover: starts only when the
# operator forces the legacy spawner with /etc/driver-manager.d/disabled.
ConditionPathExists = "/etc/driver-manager.d/disabled"
type = "oneshot"