diff --git a/pcid/src/driver_handler.rs b/pcid/src/driver_handler.rs new file mode 100644 index 0000000000..60c893dd85 --- /dev/null +++ b/pcid/src/driver_handler.rs @@ -0,0 +1,331 @@ +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::PciAddress; + +use crate::driver_interface; +use crate::pci::cap::Capability as PciCapability; +use crate::pci::PciFunc; +use crate::State; + +pub struct DriverHandler { + addr: PciAddress, + capabilities: Vec<(u8, PciCapability)>, + + state: Arc, +} + +impl DriverHandler { + pub fn spawn( + state: Arc, + func: driver_interface::PciFunction, + capabilities: Vec<(u8, PciCapability)>, + args: &[String], + ) { + let subdriver_args = driver_interface::SubdriverArguments { func }; + + let mut args = args.iter(); + if let Some(program) = args.next() { + 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, + capabilities, + }; + let _handle = thread::spawn(move || { + driver_handler.handle_spawn( + pcid_to_client_write, + pcid_from_client_read, + subdriver_args, + ); + }); + // FIXME this currently deadlocks as pcid doesn't daemonize + //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), + } + } + } + + fn respond( + &mut self, + request: driver_interface::PcidClientRequest, + args: &driver_interface::SubdriverArguments, + ) -> driver_interface::PcidClientResponse { + use crate::pci::cap::{MsiCapability, MsixCapability}; + use driver_interface::*; + + let func = PciFunc { + pci: &self.state.pcie, + addr: self.addr, + }; + + match request { + PcidClientRequest::RequestCapabilities => PcidClientResponse::Capabilities( + self.capabilities + .iter() + .map(|(_, capability)| capability.clone()) + .collect::>(), + ), + PcidClientRequest::RequestConfig => PcidClientResponse::Config(args.clone()), + PcidClientRequest::RequestFeatures => PcidClientResponse::AllFeatures( + self.capabilities + .iter() + .filter_map(|(_, capability)| match capability { + PciCapability::Msi(msi) => { + Some((PciFeature::Msi, FeatureStatus::enabled(msi.enabled()))) + } + PciCapability::MsiX(msix) => Some(( + PciFeature::MsiX, + FeatureStatus::enabled(msix.msix_enabled()), + )), + _ => None, + }) + .collect(), + ), + PcidClientRequest::EnableFeature(feature) => match feature { + PciFeature::Msi => { + let (offset, capability): (u8, &mut MsiCapability) = match self + .capabilities + .iter_mut() + .find_map(|&mut (offset, ref mut capability)| { + capability.as_msi_mut().map(|cap| (offset, cap)) + }) { + Some(tuple) => tuple, + None => { + return PcidClientResponse::Error( + PcidServerResponseError::NonexistentFeature(feature), + ) + } + }; + unsafe { + capability.set_enabled(true); + capability.write_message_control(&func, offset); + } + PcidClientResponse::FeatureEnabled(feature) + } + PciFeature::MsiX => { + let (offset, capability): (u8, &mut MsixCapability) = match self + .capabilities + .iter_mut() + .find_map(|&mut (offset, ref mut capability)| { + capability.as_msix_mut().map(|cap| (offset, cap)) + }) { + Some(tuple) => tuple, + None => { + return PcidClientResponse::Error( + PcidServerResponseError::NonexistentFeature(feature), + ) + } + }; + unsafe { + capability.set_msix_enabled(true); + capability.write_a(&func, offset); + } + PcidClientResponse::FeatureEnabled(feature) + } + }, + PcidClientRequest::FeatureStatus(feature) => PcidClientResponse::FeatureStatus( + feature, + match feature { + PciFeature::Msi => self + .capabilities + .iter() + .find_map(|(_, capability)| { + if let PciCapability::Msi(msi) = capability { + Some(FeatureStatus::enabled(msi.enabled())) + } else { + None + } + }) + .unwrap_or(FeatureStatus::Disabled), + PciFeature::MsiX => self + .capabilities + .iter() + .find_map(|(_, capability)| { + if let PciCapability::MsiX(msix) = capability { + Some(FeatureStatus::enabled(msix.msix_enabled())) + } else { + None + } + }) + .unwrap_or(FeatureStatus::Disabled), + }, + ), + PcidClientRequest::FeatureInfo(feature) => PcidClientResponse::FeatureInfo( + feature, + match feature { + PciFeature::Msi => { + if let Some(info) = self + .capabilities + .iter() + .find_map(|(_, capability)| capability.as_msi()) + { + PciFeatureInfo::Msi(*info) + } else { + return PcidClientResponse::Error( + PcidServerResponseError::NonexistentFeature(feature), + ); + } + } + PciFeature::MsiX => { + if let Some(info) = self + .capabilities + .iter() + .find_map(|(_, capability)| capability.as_msix()) + { + PciFeatureInfo::MsiX(*info) + } else { + return PcidClientResponse::Error( + PcidServerResponseError::NonexistentFeature(feature), + ); + } + } + }, + ), + PcidClientRequest::SetFeatureInfo(info_to_set) => match info_to_set { + SetFeatureInfo::Msi(info_to_set) => { + if let Some((offset, info)) = self + .capabilities + .iter_mut() + .find_map(|(offset, capability)| Some((*offset, capability.as_msi_mut()?))) + { + if let Some(mme) = info_to_set.multi_message_enable { + if info.multi_message_capable() < mme || mme > 0b101 { + return PcidClientResponse::Error( + PcidServerResponseError::InvalidBitPattern, + ); + } + info.set_multi_message_enable(mme); + } + if let Some(message_addr_and_data) = info_to_set.message_address_and_data { + let message_addr = message_addr_and_data.addr; + if message_addr & 0b11 != 0 { + return PcidClientResponse::Error( + PcidServerResponseError::InvalidBitPattern, + ); + } + info.set_message_address(message_addr as u32); + info.set_message_upper_address((message_addr >> 32) as u32); + if message_addr_and_data.data & ((1 << info.multi_message_enable()) - 1) + != 0 + { + return PcidClientResponse::Error( + PcidServerResponseError::InvalidBitPattern, + ); + } + info.set_message_data( + message_addr_and_data + .data + .try_into() + .expect("pcid: MSI message data too big"), + ); + } + if let Some(mask_bits) = info_to_set.mask_bits { + info.set_mask_bits(mask_bits); + } + unsafe { + info.write_all(&func, offset); + } + PcidClientResponse::SetFeatureInfo(PciFeature::Msi) + } else { + return PcidClientResponse::Error( + PcidServerResponseError::NonexistentFeature(PciFeature::Msi), + ); + } + } + SetFeatureInfo::MsiX { function_mask } => { + if let Some((offset, info)) = self + .capabilities + .iter_mut() + .find_map(|(offset, capability)| Some((*offset, capability.as_msix_mut()?))) + { + if let Some(mask) = function_mask { + info.set_function_mask(mask); + unsafe { + info.write_a(&func, offset); + } + } + PcidClientResponse::SetFeatureInfo(PciFeature::MsiX) + } else { + return PcidClientResponse::Error( + PcidServerResponseError::NonexistentFeature(PciFeature::MsiX), + ); + } + } + }, + PcidClientRequest::ReadConfig(offset) => { + let value = unsafe { func.read_u32(offset) }; + return PcidClientResponse::ReadConfig(value); + } + PcidClientRequest::WriteConfig(offset, value) => { + unsafe { + func.write_u32(offset, value); + } + return PcidClientResponse::WriteConfig; + } + } + } + fn handle_spawn( + mut self, + pcid_to_client_write: usize, + pcid_from_client_read: usize, + args: driver_interface::SubdriverArguments, + ) { + use driver_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/main.rs b/pcid/src/main.rs index f5d146632f..5ee29bc3e3 100644 --- a/pcid/src/main.rs +++ b/pcid/src/main.rs @@ -1,24 +1,22 @@ use std::fs::{File, metadata, read_dir}; use std::io::prelude::*; -use std::os::unix::io::{FromRawFd, RawFd}; -use std::process::Command; use std::thread; use std::sync::{Arc, Mutex}; use pci_types::{CommandRegister, PciAddress}; use structopt::StructOpt; -use log::{debug, error, info, warn, trace}; +use log::{debug, info, warn, trace}; use redox_log::{OutputBuilder, RedoxLogger}; use crate::cfg_access::Pcie; use crate::config::Config; use crate::driver_interface::LegacyInterruptLine; use crate::pci::PciFunc; -use crate::pci::cap::Capability as PciCapability; use crate::pci_header::{PciEndpointHeader, PciHeader, PciHeaderError}; mod cfg_access; mod config; +mod driver_handler; mod driver_interface; mod pci; mod pci_header; @@ -35,158 +33,6 @@ struct Args { config_path: Option, } -pub struct DriverHandler { - addr: PciAddress, - capabilities: Vec<(u8, PciCapability)>, - - state: Arc, -} - -impl DriverHandler { - fn respond(&mut self, request: driver_interface::PcidClientRequest, args: &driver_interface::SubdriverArguments) -> driver_interface::PcidClientResponse { - use driver_interface::*; - use crate::pci::cap::{MsiCapability, MsixCapability}; - - let func = PciFunc { - pci: &self.state.pcie, - addr: self.addr, - }; - - match request { - PcidClientRequest::RequestCapabilities => { - PcidClientResponse::Capabilities(self.capabilities.iter().map(|(_, capability)| capability.clone()).collect::>()) - } - PcidClientRequest::RequestConfig => { - PcidClientResponse::Config(args.clone()) - } - PcidClientRequest::RequestFeatures => { - PcidClientResponse::AllFeatures(self.capabilities.iter().filter_map(|(_, capability)| match capability { - PciCapability::Msi(msi) => Some((PciFeature::Msi, FeatureStatus::enabled(msi.enabled()))), - PciCapability::MsiX(msix) => Some((PciFeature::MsiX, FeatureStatus::enabled(msix.msix_enabled()))), - _ => None, - }).collect()) - } - PcidClientRequest::EnableFeature(feature) => match feature { - PciFeature::Msi => { - let (offset, capability): (u8, &mut MsiCapability) = match self.capabilities.iter_mut().find_map(|&mut (offset, ref mut capability)| capability.as_msi_mut().map(|cap| (offset, cap))) { - Some(tuple) => tuple, - None => return PcidClientResponse::Error(PcidServerResponseError::NonexistentFeature(feature)), - }; - unsafe { - capability.set_enabled(true); - capability.write_message_control(&func, offset); - } - PcidClientResponse::FeatureEnabled(feature) - } - PciFeature::MsiX => { - let (offset, capability): (u8, &mut MsixCapability) = match self.capabilities.iter_mut().find_map(|&mut (offset, ref mut capability)| capability.as_msix_mut().map(|cap| (offset, cap))) { - Some(tuple) => tuple, - None => return PcidClientResponse::Error(PcidServerResponseError::NonexistentFeature(feature)), - }; - unsafe { - capability.set_msix_enabled(true); - capability.write_a(&func, offset); - } - PcidClientResponse::FeatureEnabled(feature) - } - } - PcidClientRequest::FeatureStatus(feature) => PcidClientResponse::FeatureStatus(feature, match feature { - PciFeature::Msi => self.capabilities.iter().find_map(|(_, capability)| if let PciCapability::Msi(msi) = capability { - Some(FeatureStatus::enabled(msi.enabled())) - } else { - None - }).unwrap_or(FeatureStatus::Disabled), - PciFeature::MsiX => self.capabilities.iter().find_map(|(_, capability)| if let PciCapability::MsiX(msix) = capability { - Some(FeatureStatus::enabled(msix.msix_enabled())) - } else { - None - }).unwrap_or(FeatureStatus::Disabled), - }), - PcidClientRequest::FeatureInfo(feature) => PcidClientResponse::FeatureInfo(feature, match feature { - PciFeature::Msi => if let Some(info) = self.capabilities.iter().find_map(|(_, capability)| capability.as_msi()) { - PciFeatureInfo::Msi(*info) - } else { - return PcidClientResponse::Error(PcidServerResponseError::NonexistentFeature(feature)); - } - PciFeature::MsiX => if let Some(info) = self.capabilities.iter().find_map(|(_, capability)| capability.as_msix()) { - PciFeatureInfo::MsiX(*info) - } else { - return PcidClientResponse::Error(PcidServerResponseError::NonexistentFeature(feature)); - } - }), - PcidClientRequest::SetFeatureInfo(info_to_set) => match info_to_set { - SetFeatureInfo::Msi(info_to_set) => if let Some((offset, info)) = self.capabilities.iter_mut().find_map(|(offset, capability)| Some((*offset, capability.as_msi_mut()?))) { - if let Some(mme) = info_to_set.multi_message_enable { - if info.multi_message_capable() < mme || mme > 0b101 { - return PcidClientResponse::Error(PcidServerResponseError::InvalidBitPattern); - } - info.set_multi_message_enable(mme); - - } - if let Some(message_addr_and_data) = info_to_set.message_address_and_data { - let message_addr = message_addr_and_data.addr; - if message_addr & 0b11 != 0 { - return PcidClientResponse::Error(PcidServerResponseError::InvalidBitPattern); - } - info.set_message_address(message_addr as u32); - info.set_message_upper_address((message_addr >> 32) as u32); - if message_addr_and_data.data & ((1 << info.multi_message_enable()) - 1) != 0 { - return PcidClientResponse::Error(PcidServerResponseError::InvalidBitPattern); - } - info.set_message_data( - message_addr_and_data - .data - .try_into() - .expect("pcid: MSI message data too big"), - ); - } - if let Some(mask_bits) = info_to_set.mask_bits { - info.set_mask_bits(mask_bits); - } - unsafe { - info.write_all(&func, offset); - } - PcidClientResponse::SetFeatureInfo(PciFeature::Msi) - } else { - return PcidClientResponse::Error(PcidServerResponseError::NonexistentFeature(PciFeature::Msi)); - } - SetFeatureInfo::MsiX { function_mask } => if let Some((offset, info)) = self.capabilities.iter_mut().find_map(|(offset, capability)| Some((*offset, capability.as_msix_mut()?))) { - if let Some(mask) = function_mask { - info.set_function_mask(mask); - unsafe { - info.write_a(&func, offset); - } - } - PcidClientResponse::SetFeatureInfo(PciFeature::MsiX) - } else { - return PcidClientResponse::Error(PcidServerResponseError::NonexistentFeature(PciFeature::MsiX)); - } - } - PcidClientRequest::ReadConfig(offset) => { - let value = unsafe { func.read_u32(offset) }; - return PcidClientResponse::ReadConfig(value); - }, - PcidClientRequest::WriteConfig(offset, value) => { - unsafe { - func.write_u32(offset, value); - } - return PcidClientResponse::WriteConfig; - } - } - } - fn handle_spawn(mut self, pcid_to_client_write: usize, pcid_from_client_read: usize, args: driver_interface::SubdriverArguments) { - use driver_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(); - } - } -} - pub struct State { threads: Mutex>>, pcie: Pcie, @@ -268,64 +114,7 @@ fn handle_parsed_header(state: Arc, config: &Config, header: PciEndpointH full_device_id: header.full_device_id().clone(), }; - let subdriver_args = driver_interface::SubdriverArguments { - func, - }; - - let mut args = args.iter(); - if let Some(program) = args.next() { - 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: header.address(), - state: Arc::clone(&state), - capabilities, - }; - let _handle = thread::spawn(move || { - driver_handler.handle_spawn(pcid_to_client_write, pcid_from_client_read, subdriver_args); - }); - // FIXME this currently deadlocks as pcid doesn't daemonize - //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) - } - } + driver_handler::DriverHandler::spawn(Arc::clone(&state), func, capabilities, args); } }