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:
Generated
-17
@@ -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"
|
||||
|
||||
@@ -26,7 +26,6 @@ members = [
|
||||
"drivers/acpid",
|
||||
"drivers/hwd",
|
||||
"drivers/pcid",
|
||||
"drivers/pcid-spawner",
|
||||
"drivers/rtcd",
|
||||
"drivers/vboxd",
|
||||
"drivers/inputd",
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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(®ion.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.
|
||||
|
||||
@@ -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
|
||||
@@ -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(())
|
||||
}
|
||||
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
Reference in New Issue
Block a user