From 8f1549e28412a7b26984c7f17d27fa021f0db711 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 22 Feb 2025 19:47:52 +0100 Subject: [PATCH 1/2] Introduce a pci scheme and move driver spawning to pcid-spawner This allows a single PCI daemon to run on the whole system, prevents multiple drivers from claiming the same PCI device and makes it possible for userspace to enumerate all available PCI devices. In the future this will enable an lspci tool, possibly PCIe hot plugging and more. Co-Authored-By: 4lDO2 <4lDO2@protonmail.com> --- Cargo.lock | 55 +++-- Cargo.toml | 1 + pcid-spawner/Cargo.toml | 17 ++ pcid-spawner/src/main.rs | 102 +++++++++ pcid/Cargo.toml | 3 +- pcid/src/driver_handler.rs | 131 +++--------- pcid/src/driver_interface/config.rs | 2 +- pcid/src/driver_interface/mod.rs | 70 ++++--- pcid/src/main.rs | 236 ++++++++++----------- pcid/src/scheme.rs | 313 ++++++++++++++++++++++++++++ 10 files changed, 663 insertions(+), 267 deletions(-) create mode 100644 pcid-spawner/Cargo.toml create mode 100644 pcid-spawner/src/main.rs create mode 100644 pcid/src/scheme.rs diff --git a/Cargo.lock b/Cargo.lock index 4c1f1c7833..484b372504 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -32,7 +32,7 @@ dependencies = [ "parking_lot 0.12.3", "plain", "redox-daemon", - "redox-scheme", + "redox-scheme 0.3.0", "redox_event", "redox_syscall", "ron", @@ -52,7 +52,7 @@ dependencies = [ "log", "pcid", "redox-daemon", - "redox-scheme", + "redox-scheme 0.3.0", "redox_event", "redox_syscall", ] @@ -180,7 +180,7 @@ dependencies = [ "fdt 0.2.0-alpha1", "libredox", "redox-daemon", - "redox-scheme", + "redox-scheme 0.3.0", "redox_event", "redox_syscall", ] @@ -405,7 +405,7 @@ dependencies = [ "inputd", "libredox", "log", - "redox-scheme", + "redox-scheme 0.3.0", "redox_syscall", ] @@ -414,7 +414,7 @@ name = "driver-network" version = "0.1.0" dependencies = [ "libredox", - "redox-scheme", + "redox-scheme 0.3.0", "redox_syscall", ] @@ -449,7 +449,7 @@ dependencies = [ "orbclient", "ransid", "redox-daemon", - "redox-scheme", + "redox-scheme 0.3.0", "redox_event", "redox_syscall", ] @@ -465,7 +465,7 @@ dependencies = [ "orbclient", "ransid", "redox-daemon", - "redox-scheme", + "redox-scheme 0.3.0", "redox_event", "redox_syscall", ] @@ -680,7 +680,7 @@ dependencies = [ "log", "pcid", "redox-daemon", - "redox-scheme", + "redox-scheme 0.3.0", "redox_event", "redox_syscall", ] @@ -720,7 +720,7 @@ dependencies = [ "log", "orbclient", "redox-daemon", - "redox-scheme", + "redox-scheme 0.3.0", "redox_syscall", ] @@ -783,7 +783,7 @@ dependencies = [ "anyhow", "libredox", "redox-daemon", - "redox-scheme", + "redox-scheme 0.3.0", "redox_event", "redox_syscall", ] @@ -857,7 +857,7 @@ dependencies = [ "partitionlib", "pcid", "redox-daemon", - "redox-scheme", + "redox-scheme 0.3.0", "redox_event", "redox_syscall", "smallvec 1.13.2", @@ -968,8 +968,23 @@ dependencies = [ "pico-args", "plain", "redox-daemon", + "redox-scheme 0.4.0", + "redox_syscall", "serde", "thiserror", +] + +[[package]] +name = "pcid-spawner" +version = "0.1.0" +dependencies = [ + "anyhow", + "common", + "log", + "pcid", + "pico-args", + "redox_syscall", + "serde", "toml 0.5.11", ] @@ -1123,6 +1138,16 @@ dependencies = [ "redox_syscall", ] +[[package]] +name = "redox-scheme" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a28d292981c8f3338cb772b6024b08bcc597d0dd81020de17080a9a7b470ebb2" +dependencies = [ + "libredox", + "redox_syscall", +] + [[package]] name = "redox_event" version = "0.4.1" @@ -1135,9 +1160,9 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.5.7" +version = "0.5.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b6dfecf2c74bce2466cabf93f6664d6998a69eb21e39f4207930065b27b771f" +checksum = "82b568323e98e49e2a0899dcee453dd679fae22d69adf9b11dd508d1549b7e2f" dependencies = [ "bitflags 2.6.0", ] @@ -1577,7 +1602,7 @@ dependencies = [ "libredox", "plain", "redox-daemon", - "redox-scheme", + "redox-scheme 0.3.0", "redox_syscall", "thiserror", "xhcid", @@ -1652,7 +1677,7 @@ dependencies = [ "partitionlib", "pcid", "redox-daemon", - "redox-scheme", + "redox-scheme 0.3.0", "redox_syscall", "spin", "static_assertions", diff --git a/Cargo.toml b/Cargo.toml index be9ace45b5..62d4865e02 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,6 +4,7 @@ members = [ "common", "hwd", "pcid", + "pcid-spawner", "vboxd", "xhcid", "usbctl", diff --git a/pcid-spawner/Cargo.toml b/pcid-spawner/Cargo.toml new file mode 100644 index 0000000000..77dd21063f --- /dev/null +++ b/pcid-spawner/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "pcid-spawner" +version = "0.1.0" +authors = ["4lDO2 <4lDO2@protonmail.com>"] +edition = "2021" +license = "MIT" + +[dependencies] +anyhow = "1" +log = "0.4" +pico-args = "0.5" +redox_syscall = "0.5.9" +serde = { version = "1", features = ["derive"] } +toml = "0.5" + +common = { path = "../common" } +pcid = { path = "../pcid" } diff --git a/pcid-spawner/src/main.rs b/pcid-spawner/src/main.rs new file mode 100644 index 0000000000..a8ac5d5e13 --- /dev/null +++ b/pcid-spawner/src/main.rs @@ -0,0 +1,102 @@ +use std::fs; +use std::process::Command; + +use anyhow::{anyhow, Context, Result}; + +use pcid_interface::config::Config; +use pcid_interface::PciFunctionHandle; + +fn main() -> Result<()> { + let mut args = pico_args::Arguments::from_env(); + let config_path = args + .free_from_str::() + .expect("failed to parse --config argument"); + + common::setup_logging( + "bus", + "pci", + "pci-spawner.log", + log::LevelFilter::Info, + log::LevelFilter::Trace, + ); + + let config_data = if fs::metadata(&config_path)?.is_file() { + fs::read_to_string(&config_path)? + } else { + let mut config_data = String::new(); + for path in fs::read_dir(&config_path)? { + if let Ok(tmp) = fs::read_to_string(path.unwrap().path()) { + config_data.push_str(&tmp); + } + } + config_data + }; + let config: Config = toml::from_str(&config_data)?; + + 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) => { + // Either the device is gone or it is already in-use by a driver. + log::debug!( + "pcid-spawner: {} already in use: {err}", + device_path.display(), + ); + continue; + } + }; + + let full_device_id = handle.config().func.full_device_id; + + log::debug!( + "pcid-spawner enumerated: PCI {} {}", + handle.config().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", handle.config().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()); + + match command.status() { + Ok(status) if !status.success() => { + log::error!("pcid-spawner: driver {command:?} failed with {status}"); + } + Ok(_) => {} + Err(err) => log::error!("pcid-spawner: failed to execute {command:?}: {err}"), + } + syscall::close(channel_fd as usize).unwrap(); + } + + Ok(()) +} diff --git a/pcid/Cargo.toml b/pcid/Cargo.toml index b78a994584..b2d6b51317 100644 --- a/pcid/Cargo.toml +++ b/pcid/Cargo.toml @@ -20,9 +20,10 @@ pci_types = "0.10" pico-args = { version = "0.5", features = ["combined-flags"] } plain = "0.2" redox-daemon = "0.1" +redox-scheme = "0.4" +redox_syscall = "0.5.9" serde = { version = "1", features = ["derive"] } thiserror = "1" -toml = "0.5" common = { path = "../common" } libredox = "0.1.3" diff --git a/pcid/src/driver_handler.rs b/pcid/src/driver_handler.rs index cbaf221e54..8537be5c65 100644 --- a/pcid/src/driver_handler.rs +++ b/pcid/src/driver_handler.rs @@ -1,109 +1,48 @@ -use std::fs::File; -use std::os::unix::io::{FromRawFd, RawFd}; -use std::process::Command; use std::sync::Arc; -use std::thread; -use log::{error, info}; use pci_types::capability::{MultipleMessageSupport, PciCapability}; -use pci_types::{ConfigRegionAccess, PciAddress}; +use pci_types::{ConfigRegionAccess, EndpointHeader}; +use pcid_interface::PciFunction; use crate::State; -pub struct DriverHandler { - addr: PciAddress, +pub struct DriverHandler<'a> { + func: PciFunction, + endpoint_header: &'a mut EndpointHeader, capabilities: Vec, state: Arc, } -impl DriverHandler { - pub fn spawn( - state: Arc, - func: pcid_interface::PciFunction, +impl<'a> DriverHandler<'a> { + pub fn new( + func: PciFunction, + endpoint_header: &'a mut EndpointHeader, capabilities: Vec, - args: &[String], - ) { - let subdriver_args = pcid_interface::SubdriverArguments { func }; - - let mut args = args.iter(); - if let Some(program) = args.next() { - let program = if program.starts_with('/') { - program.to_owned() - } else { - "/usr/lib/drivers/".to_owned() + program - }; - let mut command = Command::new(program); - for arg in args { - if arg.starts_with("$") { - panic!("support for $VARIABLE has been removed. use pcid_interface instead"); - } - command.arg(arg); - } - - info!("PCID SPAWN {:?}", command); - - // TODO: libc wrapper? - let [fds1, fds2] = unsafe { - let mut fds1 = [0 as libc::c_int; 2]; - let mut fds2 = [0 as libc::c_int; 2]; - - assert_eq!( - libc::pipe(fds1.as_mut_ptr()), - 0, - "pcid: failed to create pcid->client pipe" - ); - assert_eq!( - libc::pipe(fds2.as_mut_ptr()), - 0, - "pcid: failed to create client->pcid pipe" - ); - - [fds1.map(|c| c as usize), fds2.map(|c| c as usize)] - }; - - let [pcid_to_client_read, pcid_to_client_write] = fds1; - let [pcid_from_client_read, pcid_from_client_write] = fds2; - - let envs = vec![ - ("PCID_TO_CLIENT_FD", format!("{}", pcid_to_client_read)), - ("PCID_FROM_CLIENT_FD", format!("{}", pcid_from_client_write)), - ]; - - match command.envs(envs).spawn() { - Ok(mut child) => { - let driver_handler = DriverHandler { - addr: func.addr, - state: state.clone(), - capabilities, - }; - let handle = thread::spawn(move || { - driver_handler.handle_spawn( - pcid_to_client_write, - pcid_from_client_read, - subdriver_args, - ); - }); - state.threads.lock().unwrap().push(handle); - match child.wait() { - Ok(_status) => (), - Err(err) => error!("pcid: failed to wait for {:?}: {}", command, err), - } - } - Err(err) => error!("pcid: failed to execute {:?}: {}", command, err), - } + state: Arc, + ) -> Self { + DriverHandler { + func, + endpoint_header, + capabilities, + state, } } - fn respond( + pub fn respond( &mut self, request: pcid_interface::PcidClientRequest, - args: &pcid_interface::SubdriverArguments, ) -> pcid_interface::PcidClientResponse { use pcid_interface::*; #[forbid(non_exhaustive_omitted_patterns)] match request { + PcidClientRequest::EnableDevice => { + self.func.legacy_interrupt_line = + crate::enable_function(&self.state, &mut self.endpoint_header); + + PcidClientResponse::EnabledDevice + } PcidClientRequest::RequestVendorCapabilities => PcidClientResponse::VendorCapabilities( self.capabilities .iter() @@ -115,7 +54,9 @@ impl DriverHandler { }) .collect::>(), ), - PcidClientRequest::RequestConfig => PcidClientResponse::Config(args.clone()), + PcidClientRequest::RequestConfig => { + PcidClientResponse::Config(SubdriverArguments { func: self.func }) + } PcidClientRequest::RequestFeatures => PcidClientResponse::AllFeatures( self.capabilities .iter() @@ -327,32 +268,16 @@ impl DriverHandler { _ => unreachable!(), }, PcidClientRequest::ReadConfig(offset) => { - let value = unsafe { self.state.pcie.read(self.addr, offset) }; + let value = unsafe { self.state.pcie.read(self.func.addr, offset) }; return PcidClientResponse::ReadConfig(value); } PcidClientRequest::WriteConfig(offset, value) => { unsafe { - self.state.pcie.write(self.addr, offset, value); + self.state.pcie.write(self.func.addr, offset, value); } return PcidClientResponse::WriteConfig; } _ => unreachable!(), } } - fn handle_spawn( - mut self, - pcid_to_client_write: usize, - pcid_from_client_read: usize, - args: pcid_interface::SubdriverArguments, - ) { - use pcid_interface::*; - - let mut pcid_to_client = unsafe { File::from_raw_fd(pcid_to_client_write as RawFd) }; - let mut pcid_from_client = unsafe { File::from_raw_fd(pcid_from_client_read as RawFd) }; - - while let Ok(msg) = recv(&mut pcid_from_client) { - let response = self.respond(msg, &args); - send(&mut pcid_to_client, &response).unwrap(); - } - } } diff --git a/pcid/src/driver_interface/config.rs b/pcid/src/driver_interface/config.rs index 8278f33c3c..e148b26ce6 100644 --- a/pcid/src/driver_interface/config.rs +++ b/pcid/src/driver_interface/config.rs @@ -20,7 +20,7 @@ pub struct DriverConfig { pub vendor: Option, pub device: Option, pub device_id_range: Option>, - pub command: Option>, + pub command: Vec, } impl DriverConfig { diff --git a/pcid/src/driver_interface/mod.rs b/pcid/src/driver_interface/mod.rs index 2cf16e8bba..7365276dc9 100644 --- a/pcid/src/driver_interface/mod.rs +++ b/pcid/src/driver_interface/mod.rs @@ -1,11 +1,11 @@ use std::fmt; use std::fs::File; use std::io::prelude::*; +use std::os::fd::{FromRawFd, IntoRawFd, RawFd}; +use std::path::Path; use std::ptr::NonNull; use std::{env, io}; -use std::os::unix::io::{FromRawFd, RawFd}; - use serde::{de::DeserializeOwned, Deserialize, Serialize}; use thiserror::Error; @@ -240,6 +240,7 @@ pub enum SetFeatureInfo { #[derive(Debug, Serialize, Deserialize)] #[non_exhaustive] pub enum PcidClientRequest { + EnableDevice, RequestConfig, RequestFeatures, RequestVendorCapabilities, @@ -260,6 +261,7 @@ pub enum PcidServerResponseError { #[derive(Debug, Serialize, Deserialize)] #[non_exhaustive] pub enum PcidClientResponse { + EnabledDevice, Config(SubdriverArguments), AllFeatures(Vec), VendorCapabilities(Vec), @@ -277,14 +279,9 @@ pub struct MappedBar { pub bar_size: usize, } -// TODO: Ideally, pcid might have its own scheme, like lots of other Redox drivers, where this kind of IPC is done. Otherwise, instead of writing serde messages over -// a channel, the communication could potentially be done via mmap, using a channel -// very similar to crossbeam-channel or libstd's mpsc (except the cycle, enqueue and dequeue fields -// are stored in the same buffer as the actual data). /// A handle from a `pcid` client (e.g. `ahcid`) to `pcid`. pub struct PciFunctionHandle { - pcid_to_client: File, - pcid_from_client: File, + channel: File, config: SubdriverArguments, mapped_bars: [Option; 6], } @@ -293,9 +290,7 @@ pub struct PciFunctionHandle { pub fn send(w: &mut W, message: &T) -> Result<()> { let mut data = Vec::new(); bincode::serialize_into(&mut data, message)?; - let length_bytes = u64::to_le_bytes(data.len() as u64); - w.write_all(&length_bytes)?; - w.write_all(&data)?; + assert_eq!(w.write(&data)?, data.len()); Ok(()) } #[doc(hidden)] @@ -314,42 +309,69 @@ pub fn recv(r: &mut R) -> Result { impl PciFunctionHandle { pub fn connect_default() -> Result { - let pcid_to_client_fd = env::var("PCID_TO_CLIENT_FD")? - .parse::() - .map_err(PcidClientHandleError::EnvValidityError)?; - let pcid_from_client_fd = env::var("PCID_FROM_CLIENT_FD")? + let channel_fd = env::var("PCID_CLIENT_CHANNEL")? .parse::() .map_err(PcidClientHandleError::EnvValidityError)?; + Self::connect_common(channel_fd) + } - let mut pcid_to_client = unsafe { File::from_raw_fd(pcid_to_client_fd) }; - let mut pcid_from_client = unsafe { File::from_raw_fd(pcid_from_client_fd) }; + pub fn connect_by_path(device_path: &Path) -> Result { + let channel_fd = syscall::open( + device_path.join("channel").to_str().unwrap(), + syscall::O_RDWR, + ) + .map_err(|err| { + PcidClientHandleError::IoError(io::Error::other(format!( + "failed to open pcid channel: {}", + err + ))) + })?; + Self::connect_common(channel_fd as RawFd) + } - send(&mut pcid_from_client, &PcidClientRequest::RequestConfig)?; - let config = match recv(&mut pcid_to_client)? { + fn connect_common( + channel_fd: i32, + ) -> std::result::Result { + let mut channel = unsafe { File::from_raw_fd(channel_fd) }; + + send(&mut channel, &PcidClientRequest::RequestConfig)?; + let config = match recv(&mut channel)? { PcidClientResponse::Config(a) => a, other => return Err(PcidClientHandleError::InvalidResponse(other)), }; Ok(Self { - pcid_to_client, - pcid_from_client, + channel, config, mapped_bars: [const { None }; 6], }) } + + pub fn into_inner_fd(self) -> RawFd { + self.channel.into_raw_fd() + } + fn send(&mut self, req: &PcidClientRequest) -> Result<()> { - send(&mut self.pcid_from_client, req) + send(&mut self.channel, req) } fn recv(&mut self) -> Result { - recv(&mut self.pcid_to_client) + recv(&mut self.channel) } + pub fn config(&self) -> SubdriverArguments { self.config.clone() } + pub fn enable_device(&mut self) -> Result<()> { + self.send(&PcidClientRequest::EnableDevice)?; + match self.recv()? { + PcidClientResponse::EnabledDevice => Ok(()), + other => Err(PcidClientHandleError::InvalidResponse(other)), + } + } + pub fn get_vendor_capabilities(&mut self) -> Result> { self.send(&PcidClientRequest::RequestVendorCapabilities)?; - match self.recv()? { PcidClientResponse::VendorCapabilities(a) => Ok(a), other => Err(PcidClientHandleError::InvalidResponse(other)), diff --git a/pcid/src/main.rs b/pcid/src/main.rs index c432539fda..8723cac4b5 100644 --- a/pcid/src/main.rs +++ b/pcid/src/main.rs @@ -1,123 +1,120 @@ +#![feature(array_chunks)] #![feature(non_exhaustive_omitted_patterns_lint)] #![feature(iter_next_chunk)] #![feature(if_let_guard)] -use std::fs::{metadata, read_dir, File}; -use std::io::prelude::*; -use std::path::PathBuf; -use std::sync::{Arc, Mutex}; -use std::thread; +use std::collections::BTreeMap; +use std::sync::Arc; use log::{debug, info, trace, warn}; +use pci_types::capability::PciCapability; use pci_types::{ Bar as TyBar, CommandRegister, EndpointHeader, HeaderType, PciAddress, PciHeader as TyPciHeader, PciPciBridgeHeader, }; +use redox_scheme::{RequestKind, SignalBehavior}; use crate::cfg_access::Pcie; -use pcid_interface::{config::Config, FullDeviceId, LegacyInterruptLine, PciBar}; +use pcid_interface::{FullDeviceId, LegacyInterruptLine, PciBar, PciFunction}; mod cfg_access; mod driver_handler; +mod scheme; pub struct State { - threads: Mutex>>, pcie: Pcie, } +pub struct Func { + inner: PciFunction, + + capabilities: Vec, + endpoint_header: EndpointHeader, + enabled: bool, +} + fn handle_parsed_header( - state: Arc, - config: &Config, - mut endpoint_header: EndpointHeader, + state: &State, + tree: &mut BTreeMap, + endpoint_header: EndpointHeader, full_device_id: FullDeviceId, ) { - for driver in config.drivers.iter() { - if !driver.match_function(&full_device_id) { + let mut bars = [PciBar::None; 6]; + let mut skip = false; + for i in 0..6 { + if skip { + skip = false; continue; } - - let Some(ref args) = driver.command else { - continue; - }; - - let mut bars = [PciBar::None; 6]; - let mut skip = false; - for i in 0..6 { - if skip { - skip = false; - continue; - } - match endpoint_header.bar(i, &state.pcie) { - Some(TyBar::Io { port }) => { - bars[i as usize] = PciBar::Port(port.try_into().unwrap()) - } - Some(TyBar::Memory32 { - address, + match endpoint_header.bar(i, &state.pcie) { + Some(TyBar::Io { port }) => bars[i as usize] = PciBar::Port(port.try_into().unwrap()), + Some(TyBar::Memory32 { + address, + size, + prefetchable: _, + }) => { + bars[i as usize] = PciBar::Memory32 { + addr: address, size, - prefetchable: _, - }) => { - bars[i as usize] = PciBar::Memory32 { - addr: address, - size, - } } - Some(TyBar::Memory64 { - address, + } + Some(TyBar::Memory64 { + address, + size, + prefetchable: _, + }) => { + bars[i as usize] = PciBar::Memory64 { + addr: address, size, - prefetchable: _, - }) => { - bars[i as usize] = PciBar::Memory64 { - addr: address, - size, - }; - skip = true; // Each 64bit memory BAR occupies two slots - } - None => bars[i as usize] = PciBar::None, + }; + skip = true; // Each 64bit memory BAR occupies two slots } + None => bars[i as usize] = PciBar::None, } + } - let mut string = String::new(); - for (i, bar) in bars.iter().enumerate() { - if !bar.is_none() { - string.push_str(&format!(" {i}={}", bar.display())); - } + let mut string = String::new(); + for (i, bar) in bars.iter().enumerate() { + if !bar.is_none() { + string.push_str(&format!(" {i}={}", bar.display())); } + } - if !string.is_empty() { - info!(" BAR{}", string); - } + if !string.is_empty() { + info!(" BAR{}", string); + } - let legacy_interrupt_line = enable_function(&state, &mut endpoint_header); + let capabilities = if endpoint_header.status(&state.pcie).has_capability_list() { + endpoint_header + .capabilities(&state.pcie) + .collect::>() + } else { + Vec::new() + }; + debug!( + "PCI DEVICE CAPABILITIES for {}: {:?}", + endpoint_header.header().address(), + capabilities + ); - let capabilities = if endpoint_header.status(&state.pcie).has_capability_list() { - endpoint_header - .capabilities(&state.pcie) - .collect::>() - } else { - Vec::new() - }; - debug!( - "PCI DEVICE CAPABILITIES for {}: {:?}", - args.iter() - .map(|string| string.as_ref()) - .nth(0) - .unwrap_or("[unknown]"), - capabilities - ); - - let func = pcid_interface::PciFunction { + let func = Func { + inner: pcid_interface::PciFunction { bars, addr: endpoint_header.header().address(), - legacy_interrupt_line, + legacy_interrupt_line: None, // Will be filled in when enabling the device full_device_id: full_device_id.clone(), - }; + }, - driver_handler::DriverHandler::spawn(Arc::clone(&state), func, capabilities, args); - } + capabilities, + endpoint_header, + enabled: false, + }; + + tree.insert(func.inner.addr, func); } fn enable_function( - state: &Arc, + state: &State, endpoint_header: &mut EndpointHeader, ) -> Option { // Enable bus mastering, memory space, and I/O space @@ -187,34 +184,6 @@ fn enable_function( fn main() { let mut args = pico_args::Arguments::from_env(); - - let mut config = Config::default(); - - if let Ok(config_path) = args.free_from_str::() { - if metadata(&config_path).unwrap().is_file() { - if let Ok(mut config_file) = File::open(&config_path) { - let mut config_data = String::new(); - if let Ok(_) = config_file.read_to_string(&mut config_data) { - config = toml::from_str(&config_data).unwrap_or(Config::default()); - } - } - } else { - let paths = read_dir(&config_path).unwrap(); - - let mut config_data = String::new(); - - for path in paths { - if let Ok(mut config_file) = File::open(&path.unwrap().path()) { - let mut tmp = String::new(); - if let Ok(_) = config_file.read_to_string(&mut tmp) { - config_data.push_str(&tmp); - } - } - } - config = toml::from_str(&config_data).unwrap_or(Config::default()); - } - } - let verbosity = (0..).find(|_| !args.contains("-v")).unwrap_or(0); let log_level = match verbosity { 0 => log::LevelFilter::Info, @@ -224,14 +193,12 @@ fn main() { common::setup_logging("bus", "pci", "pcid", log_level, log::LevelFilter::Trace); - redox_daemon::Daemon::new(move |daemon| main_inner(config, daemon)).unwrap(); + redox_daemon::Daemon::new(move |daemon| main_inner(daemon)).unwrap(); } -fn main_inner(config: Config, daemon: redox_daemon::Daemon) -> ! { - let state = Arc::new(State { - pcie: Pcie::new(), - threads: Mutex::new(Vec::new()), - }); +fn main_inner(daemon: redox_daemon::Daemon) -> ! { + let state = Arc::new(State { pcie: Pcie::new() }); + let mut tree = BTreeMap::new(); info!("PCI SG-BS:DV.F VEND:DEVI CL.SC.IN.RV"); @@ -245,22 +212,45 @@ fn main_inner(config: Config, daemon: redox_daemon::Daemon) -> ! { bus_i += 1; for dev_num in 0..32 { - scan_device(&config, &state, &mut bus_nums, bus_num, dev_num); + scan_device(&mut tree, &state, &mut bus_nums, bus_num, dev_num); + } + } + info!("Enumeration complete, now starting pci scheme"); + + let mut scheme = scheme::PciScheme::new(state, tree); + let socket = redox_scheme::Socket::create("pci").expect("failed to open pci scheme socket"); + + let _ = daemon.ready(); + + loop { + let Some(request) = socket + .next_request(SignalBehavior::Restart) + .expect("pcid: failed to get next scheme request") + else { + break; + }; + match request.kind() { + RequestKind::Call(call) => { + let response = call.handle_scheme(&mut scheme); + + socket + .write_responses(&[response], SignalBehavior::Restart) + .expect("pcid: failed to write next scheme response"); + } + RequestKind::OnClose { id } => { + scheme.on_close(id); + } + _ => (), } } - daemon.ready().unwrap(); - - for thread in state.threads.lock().unwrap().drain(..) { - thread.join().unwrap(); - } - + println!("pcid: exit"); std::process::exit(0); } fn scan_device( - config: &Config, - state: &Arc, + tree: &mut BTreeMap, + state: &State, bus_nums: &mut Vec, bus_num: u8, dev_num: u8, @@ -295,8 +285,8 @@ fn scan_device( match header.header_type(&state.pcie) { HeaderType::Endpoint => { handle_parsed_header( - Arc::clone(state), - config, + state, + tree, EndpointHeader::from_header(header, &state.pcie).unwrap(), full_device_id, ); diff --git a/pcid/src/scheme.rs b/pcid/src/scheme.rs new file mode 100644 index 0000000000..d1c35166d7 --- /dev/null +++ b/pcid/src/scheme.rs @@ -0,0 +1,313 @@ +use std::collections::{BTreeMap, VecDeque}; +use std::sync::Arc; + +use pci_types::PciAddress; +use redox_scheme::{CallerCtx, OpenResult, Scheme}; +use syscall::dirent::{DirEntry, DirentBuf, DirentKind}; +use syscall::error::{Error, Result, EACCES, EBADF, EINVAL, EIO, EISDIR, ENOENT, ENOTDIR}; +use syscall::flag::{MODE_CHR, MODE_DIR, O_DIRECTORY, O_STAT}; +use syscall::schemev2::NewFdFlags; +use syscall::ENOLCK; + +use crate::State; + +pub struct PciScheme { + handles: BTreeMap, + next_id: usize, + state: Arc, + tree: BTreeMap, +} +enum Handle { + TopLevel { entries: Vec }, + Device, + Channel { addr: PciAddress, st: ChannelState }, +} +struct HandleWrapper { + inner: Handle, + stat: bool, +} +impl Handle { + fn is_file(&self) -> bool { + matches!(self, Self::Channel { .. }) + } + fn is_dir(&self) -> bool { + !self.is_file() + } + // TODO: capability rather than root + fn requires_root(&self) -> bool { + matches!(self, Self::Channel { .. }) + } +} + +enum ChannelState { + AwaitingData, + AwaitingResponseRead(VecDeque), +} + +const DEVICE_CONTENTS: &[&str] = &["channel"]; + +impl Scheme for PciScheme { + fn xopen(&mut self, path: &str, flags: usize, ctx: &CallerCtx) -> Result { + log::trace!("OPEN `{}` flags {}", path, flags); + + // TODO: Check flags are correct + let expects_dir = path.ends_with('/') || flags & O_DIRECTORY != 0; + + let path = path.trim_matches('/'); + + let handle = if path.is_empty() { + Handle::TopLevel { + entries: self + .tree + .iter() + // FIXME remove replacement of : once the old scheme format is no longer supported. + .map(|(addr, _)| format!("{}", addr).replace(':', "--")) + .collect::>(), + } + } else { + let idx = path.find('/').unwrap_or(path.len()); + let (addr_str, after) = path.split_at(idx); + let addr = parse_pci_addr(addr_str).ok_or(Error::new(ENOENT))?; + + self.parse_after_pci_addr(addr, after)? + }; + + let stat = flags & O_STAT != 0; + if expects_dir && handle.is_file() && !stat { + return Err(Error::new(ENOTDIR)); + } + if !expects_dir && handle.is_dir() && !stat { + return Err(Error::new(EISDIR)); + } + if ctx.uid != 0 && handle.requires_root() && !stat { + return Err(Error::new(EACCES)); + } + + let id = self.next_id; + self.next_id += 1; + + self.handles.insert( + id, + HandleWrapper { + inner: handle, + stat, + }, + ); + Ok(OpenResult::ThisScheme { + number: id, + flags: NewFdFlags::POSITIONED, + }) + } + fn fstat(&mut self, id: usize, stat: &mut syscall::Stat) -> Result { + let handle = self.handles.get_mut(&id).ok_or(Error::new(EBADF))?; + + let (len, mode) = match handle.inner { + Handle::TopLevel { ref entries } => (entries.len(), MODE_DIR | 0o755), + Handle::Device => (DEVICE_CONTENTS.len(), MODE_DIR | 0o755), + Handle::Channel { .. } => (0, MODE_CHR | 0o600), + }; + stat.st_size = len as u64; + stat.st_mode = mode; + Ok(0) + } + fn read( + &mut self, + id: usize, + buf: &mut [u8], + _offset: u64, + _fcntl_flags: u32, + ) -> Result { + let handle = self.handles.get_mut(&id).ok_or(Error::new(EBADF))?; + + if handle.stat { + return Err(Error::new(EBADF)); + } + + match handle.inner { + Handle::TopLevel { .. } => Err(Error::new(EISDIR)), + Handle::Device => Err(Error::new(EISDIR)), + Handle::Channel { + addr: _, + ref mut st, + } => Self::read_channel(st, buf), + } + } + fn getdents<'buf>( + &mut self, + id: usize, + mut buf: DirentBuf<&'buf mut [u8]>, + opaque_offset: u64, + ) -> Result> { + let Ok(offset) = usize::try_from(opaque_offset) else { + return Ok(buf); + }; + + let handle = self.handles.get_mut(&id).ok_or(Error::new(EBADF))?; + + if handle.stat { + return Err(Error::new(EBADF)); + } + + let entries = match handle.inner { + Handle::TopLevel { ref entries } => { + for (i, dent_name) in entries.iter().enumerate().skip(offset) { + buf.entry(DirEntry { + inode: 0, + name: dent_name, + kind: DirentKind::Unspecified, + next_opaque_id: i as u64 + 1, + })?; + } + return Ok(buf); + } + Handle::Device => DEVICE_CONTENTS, + Handle::Channel { .. } => return Err(Error::new(ENOTDIR)), + }; + + for (i, dent_name) in entries.iter().enumerate().skip(offset) { + buf.entry(DirEntry { + inode: 0, + name: dent_name, + kind: DirentKind::Unspecified, + next_opaque_id: i as u64 + 1, + })?; + } + Ok(buf) + } + + fn write(&mut self, id: usize, buf: &[u8], _offset: u64, _fcntl_flags: u32) -> Result { + let handle = self.handles.get_mut(&id).ok_or(Error::new(EBADF))?; + + if handle.stat { + return Err(Error::new(EBADF)); + } + + match handle.inner { + Handle::Channel { addr, ref mut st } => { + Self::write_channel(&self.state, &mut self.tree, addr, st, buf) + } + + _ => Err(Error::new(EBADF)), + } + } +} + +impl PciScheme { + pub fn on_close(&mut self, id: usize) { + match self.handles.remove(&id) { + Some(HandleWrapper { + inner: Handle::Channel { addr, .. }, + .. + }) => { + log::trace!("TODO: Support disabling device (called on {})", addr); + if let Some(func) = self.tree.get_mut(&addr) { + func.enabled = false; + } + } + _ => {} + } + } +} + +impl PciScheme { + pub fn new(state: Arc, tree: BTreeMap) -> Self { + Self { + handles: BTreeMap::new(), + next_id: 0, + state, + tree, + } + } + fn parse_after_pci_addr(&mut self, addr: PciAddress, after: &str) -> Result { + if after.chars().next().map_or(false, |c| c != '/') { + return Err(Error::new(ENOENT)); + } + let func = self.tree.get_mut(&addr).ok_or(Error::new(ENOENT))?; + + Ok(if after.is_empty() { + Handle::Device + } else { + let path = &after[1..]; + + match path { + "channel" => { + if func.enabled { + return Err(Error::new(ENOLCK)); + } + func.inner.legacy_interrupt_line = + crate::enable_function(&self.state, &mut func.endpoint_header); + func.enabled = true; + Handle::Channel { + addr, + st: ChannelState::AwaitingData, + } + } + _ => return Err(Error::new(ENOENT)), + } + }) + } + + fn read_channel(state: &mut ChannelState, buf: &mut [u8]) -> Result { + match *state { + ChannelState::AwaitingResponseRead(ref mut queue) => { + let byte_count = std::cmp::min(queue.len(), buf.len()); + // XXX: Why can't VecDeque support dequeueing into slices? + for (idx, byte) in queue.drain(..byte_count).enumerate() { + buf[idx] = byte; + } + if queue.is_empty() { + *state = ChannelState::AwaitingData; + } + Ok(byte_count) + } + ChannelState::AwaitingData => Err(Error::new(EINVAL)), + } + } + fn write_channel( + pci_state: &Arc, + tree: &mut BTreeMap, + addr: PciAddress, + state: &mut ChannelState, + buf: &[u8], + ) -> Result { + match *state { + ChannelState::AwaitingResponseRead(_) => return Err(Error::new(EINVAL)), + ChannelState::AwaitingData => { + let func = tree.get_mut(&addr).unwrap(); + + let request = bincode::deserialize_from(buf).map_err(|_| Error::new(EINVAL))?; + let response = crate::driver_handler::DriverHandler::new( + func.inner.clone(), + &mut func.endpoint_header, + func.capabilities.clone(), + Arc::clone(pci_state), + ) + .respond(request); + + let mut output_bytes = vec![0_u8; 8]; + bincode::serialize_into(&mut output_bytes, &response) + .map_err(|_| Error::new(EIO))?; + let len = output_bytes.len() - 8; + output_bytes[..8].copy_from_slice(&u64::to_le_bytes(len as u64)); + *state = ChannelState::AwaitingResponseRead(output_bytes.into()); + + Ok(buf.len()) + } + } + } +} + +fn parse_pci_addr(addr: &str) -> Option { + let (segment, rest) = addr.split_once('-')?; + let segment = u16::from_str_radix(segment, 16).ok()?; + + // FIXME use : instead of -- as separator once the old scheme format is no longer supported. + let (bus, rest) = rest.split_once("--")?; + let bus = u8::from_str_radix(bus, 16).ok()?; + + let (device, function) = rest.split_once('.')?; + let device = u8::from_str_radix(device, 16).ok()?; + let function = u8::from_str_radix(function, 16).ok()?; + + Some(PciAddress::new(segment, bus, device, function)) +} From 7dbce70d9551ace0fc74f1e6f31c14fb48412048 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 1 Mar 2025 17:09:52 +0100 Subject: [PATCH 2/2] Get rid of the State struct and the Arc wrapper around Pcie --- pcid/src/driver_handler.rs | 36 +++++++++++++------------- pcid/src/main.rs | 52 ++++++++++++++++---------------------- pcid/src/scheme.rs | 17 ++++++------- 3 files changed, 47 insertions(+), 58 deletions(-) diff --git a/pcid/src/driver_handler.rs b/pcid/src/driver_handler.rs index 8537be5c65..435c225937 100644 --- a/pcid/src/driver_handler.rs +++ b/pcid/src/driver_handler.rs @@ -1,17 +1,15 @@ -use std::sync::Arc; - use pci_types::capability::{MultipleMessageSupport, PciCapability}; use pci_types::{ConfigRegionAccess, EndpointHeader}; use pcid_interface::PciFunction; -use crate::State; +use crate::cfg_access::Pcie; pub struct DriverHandler<'a> { func: PciFunction, endpoint_header: &'a mut EndpointHeader, capabilities: Vec, - state: Arc, + pcie: &'a Pcie, } impl<'a> DriverHandler<'a> { @@ -19,13 +17,13 @@ impl<'a> DriverHandler<'a> { func: PciFunction, endpoint_header: &'a mut EndpointHeader, capabilities: Vec, - state: Arc, + pcie: &'a Pcie, ) -> Self { DriverHandler { func, endpoint_header, capabilities, - state, + pcie, } } @@ -39,7 +37,7 @@ impl<'a> DriverHandler<'a> { match request { PcidClientRequest::EnableDevice => { self.func.legacy_interrupt_line = - crate::enable_function(&self.state, &mut self.endpoint_header); + crate::enable_function(&self.pcie, &mut self.endpoint_header); PcidClientResponse::EnabledDevice } @@ -48,7 +46,7 @@ impl<'a> DriverHandler<'a> { .iter() .filter_map(|capability| match capability { PciCapability::Vendor(addr) => unsafe { - Some(VendorSpecificCapability::parse(*addr, &self.state.pcie)) + Some(VendorSpecificCapability::parse(*addr, self.pcie)) }, _ => None, }) @@ -80,7 +78,7 @@ impl<'a> DriverHandler<'a> { { // If MSI-X is supported disable it before enabling MSI as they can't be // active at the same time. - msix_capability.set_enabled(false, &self.state.pcie); + msix_capability.set_enabled(false, self.pcie); } let capability = match self.capabilities.iter_mut().find_map(|capability| { @@ -96,7 +94,7 @@ impl<'a> DriverHandler<'a> { ) } }; - capability.set_enabled(true, &self.state.pcie); + capability.set_enabled(true, self.pcie); PcidClientResponse::FeatureEnabled(feature) } PciFeature::MsiX => { @@ -110,7 +108,7 @@ impl<'a> DriverHandler<'a> { { // If MSI is supported disable it before enabling MSI-X as they can't be // active at the same time. - msi_capability.set_enabled(false, &self.state.pcie); + msi_capability.set_enabled(false, self.pcie); } let capability = match self.capabilities.iter_mut().find_map(|capability| { @@ -126,7 +124,7 @@ impl<'a> DriverHandler<'a> { ) } }; - capability.set_enabled(true, &self.state.pcie); + capability.set_enabled(true, self.pcie); PcidClientResponse::FeatureEnabled(feature) } } @@ -209,7 +207,7 @@ impl<'a> DriverHandler<'a> { ) } }, - &self.state.pcie, + self.pcie, ); } if let Some(message_addr_and_data) = info_to_set.message_address_and_data { @@ -220,7 +218,7 @@ impl<'a> DriverHandler<'a> { ); } if message_addr_and_data.data - & ((1 << info.multiple_message_enable(&self.state.pcie) as u8) - 1) + & ((1 << info.multiple_message_enable(self.pcie) as u8) - 1) != 0 { return PcidClientResponse::Error( @@ -233,11 +231,11 @@ impl<'a> DriverHandler<'a> { .data .try_into() .expect("pcid: MSI message data too big"), - &self.state.pcie, + self.pcie, ); } if let Some(mask_bits) = info_to_set.mask_bits { - info.set_message_mask(mask_bits, &self.state.pcie); + info.set_message_mask(mask_bits, self.pcie); } PcidClientResponse::SetFeatureInfo(PciFeature::Msi) } else { @@ -256,7 +254,7 @@ impl<'a> DriverHandler<'a> { }) { if let Some(mask) = function_mask { - info.set_function_mask(mask, &self.state.pcie); + info.set_function_mask(mask, self.pcie); } PcidClientResponse::SetFeatureInfo(PciFeature::MsiX) } else { @@ -268,12 +266,12 @@ impl<'a> DriverHandler<'a> { _ => unreachable!(), }, PcidClientRequest::ReadConfig(offset) => { - let value = unsafe { self.state.pcie.read(self.func.addr, offset) }; + let value = unsafe { self.pcie.read(self.func.addr, offset) }; return PcidClientResponse::ReadConfig(value); } PcidClientRequest::WriteConfig(offset, value) => { unsafe { - self.state.pcie.write(self.func.addr, offset, value); + self.pcie.write(self.func.addr, offset, value); } return PcidClientResponse::WriteConfig; } diff --git a/pcid/src/main.rs b/pcid/src/main.rs index 8723cac4b5..3545c800f9 100644 --- a/pcid/src/main.rs +++ b/pcid/src/main.rs @@ -4,7 +4,6 @@ #![feature(if_let_guard)] use std::collections::BTreeMap; -use std::sync::Arc; use log::{debug, info, trace, warn}; use pci_types::capability::PciCapability; @@ -21,10 +20,6 @@ mod cfg_access; mod driver_handler; mod scheme; -pub struct State { - pcie: Pcie, -} - pub struct Func { inner: PciFunction, @@ -34,7 +29,7 @@ pub struct Func { } fn handle_parsed_header( - state: &State, + pcie: &Pcie, tree: &mut BTreeMap, endpoint_header: EndpointHeader, full_device_id: FullDeviceId, @@ -46,7 +41,7 @@ fn handle_parsed_header( skip = false; continue; } - match endpoint_header.bar(i, &state.pcie) { + match endpoint_header.bar(i, pcie) { Some(TyBar::Io { port }) => bars[i as usize] = PciBar::Port(port.try_into().unwrap()), Some(TyBar::Memory32 { address, @@ -84,10 +79,8 @@ fn handle_parsed_header( info!(" BAR{}", string); } - let capabilities = if endpoint_header.status(&state.pcie).has_capability_list() { - endpoint_header - .capabilities(&state.pcie) - .collect::>() + let capabilities = if endpoint_header.status(pcie).has_capability_list() { + endpoint_header.capabilities(pcie).collect::>() } else { Vec::new() }; @@ -114,11 +107,11 @@ fn handle_parsed_header( } fn enable_function( - state: &State, + pcie: &Pcie, endpoint_header: &mut EndpointHeader, ) -> Option { // Enable bus mastering, memory space, and I/O space - endpoint_header.update_command(&state.pcie, |cmd| { + endpoint_header.update_command(pcie, |cmd| { cmd | CommandRegister::BUS_MASTER_ENABLE | CommandRegister::MEMORY_ENABLE | CommandRegister::IO_ENABLE @@ -128,7 +121,7 @@ fn enable_function( let mut irq = 0xFF; let mut interrupt_pin = 0xFF; - endpoint_header.update_interrupt(&state.pcie, |(pin, mut line)| { + endpoint_header.update_interrupt(pcie, |(pin, mut line)| { if line == 0xFF { line = 9; } @@ -153,13 +146,12 @@ fn enable_function( | ((pci_address.device() as u32) << 11) | ((pci_address.function() as u32) << 8); let addr = [ - dt_address & state.pcie.interrupt_map_mask[0], + dt_address & pcie.interrupt_map_mask[0], 0u32, 0u32, - interrupt_pin as u32 & state.pcie.interrupt_map_mask[3], + interrupt_pin as u32 & pcie.interrupt_map_mask[3], ]; - let mapping = state - .pcie + let mapping = pcie .interrupt_map .iter() .find(|x| x.addr == addr[0..3] && x.interrupt == addr[3]); @@ -197,7 +189,7 @@ fn main() { } fn main_inner(daemon: redox_daemon::Daemon) -> ! { - let state = Arc::new(State { pcie: Pcie::new() }); + let pcie = Pcie::new(); let mut tree = BTreeMap::new(); info!("PCI SG-BS:DV.F VEND:DEVI CL.SC.IN.RV"); @@ -212,12 +204,12 @@ fn main_inner(daemon: redox_daemon::Daemon) -> ! { bus_i += 1; for dev_num in 0..32 { - scan_device(&mut tree, &state, &mut bus_nums, bus_num, dev_num); + scan_device(&mut tree, &pcie, &mut bus_nums, bus_num, dev_num); } } info!("Enumeration complete, now starting pci scheme"); - let mut scheme = scheme::PciScheme::new(state, tree); + let mut scheme = scheme::PciScheme::new(pcie, tree); let socket = redox_scheme::Socket::create("pci").expect("failed to open pci scheme socket"); let _ = daemon.ready(); @@ -250,7 +242,7 @@ fn main_inner(daemon: redox_daemon::Daemon) -> ! { fn scan_device( tree: &mut BTreeMap, - state: &State, + pcie: &Pcie, bus_nums: &mut Vec, bus_num: u8, dev_num: u8, @@ -258,7 +250,7 @@ fn scan_device( for func_num in 0..8 { let header = TyPciHeader::new(PciAddress::new(0, bus_num, dev_num, func_num)); - let (vendor_id, device_id) = header.id(&state.pcie); + let (vendor_id, device_id) = header.id(pcie); if vendor_id == 0xffff && device_id == 0xffff { if func_num == 0 { trace!("PCI {:>02X}:{:>02X}: no dev", bus_num, dev_num); @@ -268,7 +260,7 @@ fn scan_device( continue; } - let (revision, class, subclass, interface) = header.revision_and_class(&state.pcie); + let (revision, class, subclass, interface) = header.revision_and_class(pcie); let full_device_id = FullDeviceId { vendor_id, device_id, @@ -280,20 +272,20 @@ fn scan_device( info!("PCI {} {}", header.address(), full_device_id.display()); - let has_multiple_functions = header.has_multiple_functions(&state.pcie); + let has_multiple_functions = header.has_multiple_functions(pcie); - match header.header_type(&state.pcie) { + match header.header_type(pcie) { HeaderType::Endpoint => { handle_parsed_header( - state, + pcie, tree, - EndpointHeader::from_header(header, &state.pcie).unwrap(), + EndpointHeader::from_header(header, pcie).unwrap(), full_device_id, ); } HeaderType::PciPciBridge => { - let bridge_header = PciPciBridgeHeader::from_header(header, &state.pcie).unwrap(); - bus_nums.push(bridge_header.secondary_bus_number(&state.pcie)); + let bridge_header = PciPciBridgeHeader::from_header(header, pcie).unwrap(); + bus_nums.push(bridge_header.secondary_bus_number(pcie)); } ty => { warn!("pcid: unknown header type: {ty:?}"); diff --git a/pcid/src/scheme.rs b/pcid/src/scheme.rs index d1c35166d7..cee1fc7a11 100644 --- a/pcid/src/scheme.rs +++ b/pcid/src/scheme.rs @@ -1,5 +1,4 @@ use std::collections::{BTreeMap, VecDeque}; -use std::sync::Arc; use pci_types::PciAddress; use redox_scheme::{CallerCtx, OpenResult, Scheme}; @@ -9,12 +8,12 @@ use syscall::flag::{MODE_CHR, MODE_DIR, O_DIRECTORY, O_STAT}; use syscall::schemev2::NewFdFlags; use syscall::ENOLCK; -use crate::State; +use crate::cfg_access::Pcie; pub struct PciScheme { handles: BTreeMap, next_id: usize, - state: Arc, + pcie: Pcie, tree: BTreeMap, } enum Handle { @@ -184,7 +183,7 @@ impl Scheme for PciScheme { match handle.inner { Handle::Channel { addr, ref mut st } => { - Self::write_channel(&self.state, &mut self.tree, addr, st, buf) + Self::write_channel(&self.pcie, &mut self.tree, addr, st, buf) } _ => Err(Error::new(EBADF)), @@ -210,11 +209,11 @@ impl PciScheme { } impl PciScheme { - pub fn new(state: Arc, tree: BTreeMap) -> Self { + pub fn new(pcie: Pcie, tree: BTreeMap) -> Self { Self { handles: BTreeMap::new(), next_id: 0, - state, + pcie, tree, } } @@ -235,7 +234,7 @@ impl PciScheme { return Err(Error::new(ENOLCK)); } func.inner.legacy_interrupt_line = - crate::enable_function(&self.state, &mut func.endpoint_header); + crate::enable_function(&self.pcie, &mut func.endpoint_header); func.enabled = true; Handle::Channel { addr, @@ -264,7 +263,7 @@ impl PciScheme { } } fn write_channel( - pci_state: &Arc, + pci_state: &Pcie, tree: &mut BTreeMap, addr: PciAddress, state: &mut ChannelState, @@ -280,7 +279,7 @@ impl PciScheme { func.inner.clone(), &mut func.endpoint_header, func.capabilities.clone(), - Arc::clone(pci_state), + &*pci_state, ) .respond(request);