diff --git a/pcid/src/main.rs b/pcid/src/main.rs index 3f126f7e3d..87280eda73 100644 --- a/pcid/src/main.rs +++ b/pcid/src/main.rs @@ -4,21 +4,23 @@ use std::sync::{Arc, Mutex}; use std::thread; use log::{debug, info, trace, warn}; -use pci_types::{CommandRegister, PciAddress}; +use pci_types::{ + Bar as TyBar, CommandRegister, EndpointHeader, HeaderType, PciAddress, + PciHeader as TyPciHeader, PciPciBridgeHeader, +}; use redox_log::{OutputBuilder, RedoxLogger}; use structopt::StructOpt; use crate::cfg_access::Pcie; use crate::config::Config; use crate::driver_interface::LegacyInterruptLine; -use crate::pci_header::{PciEndpointHeader, PciHeader, PciHeaderError}; +use crate::pci::{FullDeviceId, PciBar}; mod cfg_access; mod config; mod driver_handler; mod driver_interface; mod pci; -mod pci_header; #[derive(StructOpt)] #[structopt(about)] @@ -42,9 +44,14 @@ pub struct State { pcie: Pcie, } -fn handle_parsed_header(state: Arc, config: &Config, header: PciEndpointHeader) { +fn handle_parsed_header( + state: Arc, + config: &Config, + mut endpoint_header: EndpointHeader, + full_device_id: FullDeviceId, +) { for driver in config.drivers.iter() { - if !driver.match_function(header.full_device_id()) { + if !driver.match_function(&full_device_id) { continue; } @@ -52,8 +59,43 @@ fn handle_parsed_header(state: Arc, config: &Config, header: PciEndpointH 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, + size, + prefetchable: _, + }) => { + bars[i as usize] = PciBar::Memory32 { + addr: address, + size, + } + } + Some(TyBar::Memory64 { + 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, + } + } + let mut string = String::new(); - let bars = header.bars(&state.pcie); for (i, bar) in bars.iter().enumerate() { if !bar.is_none() { string.push_str(&format!(" {i}={}", bar.display())); @@ -64,8 +106,6 @@ fn handle_parsed_header(state: Arc, config: &Config, header: PciEndpointH info!(" BAR{}", string); } - let mut endpoint_header = header.endpoint_header(&state.pcie); - // Enable bus mastering, memory space, and I/O space endpoint_header.update_command(&state.pcie, |cmd| { cmd | CommandRegister::BUS_MASTER_ENABLE @@ -114,13 +154,13 @@ fn handle_parsed_header(state: Arc, config: &Config, header: PciEndpointH let func = driver_interface::PciFunction { bars, - addr: header.address(), + addr: endpoint_header.header().address(), legacy_interrupt_line: if legacy_interrupt_enabled { Some(LegacyInterruptLine(irq)) } else { None }, - full_device_id: header.full_device_id().clone(), + full_device_id: full_device_id.clone(), }; driver_handler::DriverHandler::spawn(Arc::clone(&state), func, capabilities, args); @@ -227,29 +267,46 @@ fn main(args: Args) { 'dev: for dev_num in 0..32 { for func_num in 0..8 { - let func_addr = PciAddress::new(0, bus_num, dev_num, func_num); - match PciHeader::from_reader(&state.pcie, func_addr) { - Ok(header) => { - info!("{}", header.display()); - match header { - PciHeader::General(endpoint_header) => { - handle_parsed_header(Arc::clone(&state), &config, endpoint_header); - } - PciHeader::PciToPci { - secondary_bus_num, .. - } => { - bus_nums.push(secondary_bus_num); - } - } + let header = TyPciHeader::new(PciAddress::new(0, bus_num, dev_num, func_num)); + + let (vendor_id, device_id) = header.id(&state.pcie); + if vendor_id == 0xffff && device_id == 0xffff { + if func_num == 0 { + trace!("PCI {:>02X}:{:>02X}: no dev", bus_num, dev_num); + continue 'dev; } - Err(PciHeaderError::NoDevice) => { - if func_addr.function() == 0 { - trace!("PCI {:>02X}:{:>02X}: no dev", bus_num, dev_num); - continue 'dev; - } + + continue; + } + + let (revision, class, subclass, interface) = header.revision_and_class(&state.pcie); + let full_device_id = FullDeviceId { + vendor_id, + device_id, + class, + subclass, + interface, + revision, + }; + + info!("PCI {} {}", header.address(), full_device_id.display()); + + match header.header_type(&state.pcie) { + HeaderType::Endpoint => { + handle_parsed_header( + Arc::clone(&state), + &config, + EndpointHeader::from_header(header, &state.pcie).unwrap(), + full_device_id, + ); } - Err(PciHeaderError::UnknownHeaderType(id)) => { - warn!("pcid: unknown header type: {id:?}"); + HeaderType::PciPciBridge => { + let bridge_header = + PciPciBridgeHeader::from_header(header, &state.pcie).unwrap(); + bus_nums.push(bridge_header.secondary_bus_number(&state.pcie)); + } + ty => { + warn!("pcid: unknown header type: {ty:?}"); } } } diff --git a/pcid/src/pci/id.rs b/pcid/src/pci/id.rs index 9a59d660f6..307efc955a 100644 --- a/pcid/src/pci/id.rs +++ b/pcid/src/pci/id.rs @@ -1,3 +1,4 @@ +use pci_types::device_type::DeviceType; use serde::{Deserialize, Serialize}; /// All identifying information of a PCI function. @@ -10,3 +11,38 @@ pub struct FullDeviceId { pub interface: u8, pub revision: u8, } + +impl FullDeviceId { + pub(crate) fn display(&self) -> String { + let mut string = format!( + "{:>04X}:{:>04X} {:>02X}.{:>02X}.{:>02X}.{:>02X} {:?}", + self.vendor_id, + self.device_id, + self.class, + self.subclass, + self.interface, + self.revision, + self.class, + ); + let device_type = DeviceType::from((self.class, self.subclass)); + match device_type { + DeviceType::LegacyVgaCompatible => string.push_str(" VGA CTL"), + DeviceType::IdeController => string.push_str(" IDE"), + DeviceType::SataController => match self.interface { + 0 => string.push_str(" SATA VND"), + 1 => string.push_str(" SATA AHCI"), + _ => (), + }, + DeviceType::UsbController => match self.interface { + 0x00 => string.push_str(" UHCI"), + 0x10 => string.push_str(" OHCI"), + 0x20 => string.push_str(" EHCI"), + 0x30 => string.push_str(" XHCI"), + _ => (), + }, + DeviceType::NvmeController => string.push_str(" NVME"), + _ => (), + } + string + } +} diff --git a/pcid/src/pci_header.rs b/pcid/src/pci_header.rs deleted file mode 100644 index 8bde8369c8..0000000000 --- a/pcid/src/pci_header.rs +++ /dev/null @@ -1,324 +0,0 @@ -use pci_types::device_type::DeviceType; -use pci_types::{ - Bar as TyBar, ConfigRegionAccess, EndpointHeader, HeaderType, PciAddress, - PciHeader as TyPciHeader, PciPciBridgeHeader, -}; - -use crate::pci::{FullDeviceId, PciBar}; - -#[derive(Debug, PartialEq)] -pub enum PciHeaderError { - NoDevice, - UnknownHeaderType(HeaderType), -} - -#[derive(Clone, Copy, Debug, PartialEq)] -pub struct SharedPciHeader { - full_device_id: FullDeviceId, - addr: PciAddress, -} - -#[derive(Clone, Copy, Debug, PartialEq)] -pub struct PciEndpointHeader { - shared: SharedPciHeader, - subsystem_vendor_id: u16, - subsystem_id: u16, -} - -#[derive(Clone, Copy, Debug, PartialEq)] -pub enum PciHeader { - General(PciEndpointHeader), - PciToPci { - shared: SharedPciHeader, - secondary_bus_num: u8, - }, -} - -impl PciHeader { - /// Parse the bytes found in the Configuration Space of the PCI device into - /// a more usable PciHeader. - pub fn from_reader( - access: &impl ConfigRegionAccess, - addr: PciAddress, - ) -> Result { - let header = TyPciHeader::new(addr); - let (vendor_id, device_id) = header.id(access); - - if vendor_id == 0xffff && device_id == 0xffff { - return Err(PciHeaderError::NoDevice); - } - - let (revision, class, subclass, interface) = header.revision_and_class(access); - let header_type = header.header_type(access); - let shared = SharedPciHeader { - full_device_id: FullDeviceId { - vendor_id, - device_id, - class, - subclass, - interface, - revision, - }, - addr, - }; - - match header_type { - HeaderType::Endpoint => { - let endpoint_header = EndpointHeader::from_header(header, access).unwrap(); - let (subsystem_id, subsystem_vendor_id) = endpoint_header.subsystem(access); - Ok(PciHeader::General(PciEndpointHeader { - shared, - subsystem_vendor_id, - subsystem_id, - })) - } - HeaderType::PciPciBridge => { - let bridge_header = PciPciBridgeHeader::from_header(header, access).unwrap(); - let secondary_bus_num = bridge_header.secondary_bus_number(access); - Ok(PciHeader::PciToPci { - shared, - secondary_bus_num, - }) - } - ty => Err(PciHeaderError::UnknownHeaderType(ty)), - } - } - - /// Return all identifying information of the PCI function. - pub fn full_device_id(&self) -> &FullDeviceId { - match self { - PciHeader::General(PciEndpointHeader { - shared: - SharedPciHeader { - full_device_id: device_id, - .. - }, - .. - }) - | PciHeader::PciToPci { - shared: - SharedPciHeader { - full_device_id: device_id, - .. - }, - .. - } => device_id, - } - } - - /// Return the PCI address. - pub fn address(&self) -> PciAddress { - match self { - PciHeader::General(header) => header.address(), - PciHeader::PciToPci { shared, .. } => shared.addr, - } - } - - /// Return the Vendor ID field. - pub fn vendor_id(&self) -> u16 { - self.full_device_id().vendor_id - } - - /// Return the Device ID field. - pub fn device_id(&self) -> u16 { - self.full_device_id().device_id - } - - /// Return the Revision field. - pub fn revision(&self) -> u8 { - self.full_device_id().revision - } - - /// Return the Interface field. - pub fn interface(&self) -> u8 { - self.full_device_id().interface - } - - /// Return the Subclass field. - pub fn subclass(&self) -> u8 { - self.full_device_id().subclass - } - - /// Return the Class field. - pub fn class(&self) -> u8 { - self.full_device_id().class - } - - /// Format a human readable string indicating the address and type of PCI device. - pub fn display(&self) -> String { - let mut string = format!( - "PCI {} {:>04X}:{:>04X} {:>02X}.{:>02X}.{:>02X}.{:>02X} {:?}", - self.address(), - self.vendor_id(), - self.device_id(), - self.class(), - self.subclass(), - self.interface(), - self.revision(), - self.class() - ); - let device_type = DeviceType::from((self.class(), self.subclass())); - match device_type { - DeviceType::LegacyVgaCompatible => string.push_str(" VGA CTL"), - DeviceType::IdeController => string.push_str(" IDE"), - DeviceType::SataController => match self.interface() { - 0 => string.push_str(" SATA VND"), - 1 => string.push_str(" SATA AHCI"), - _ => (), - }, - DeviceType::UsbController => match self.interface() { - 0x00 => string.push_str(" UHCI"), - 0x10 => string.push_str(" OHCI"), - 0x20 => string.push_str(" EHCI"), - 0x30 => string.push_str(" XHCI"), - _ => (), - }, - _ => (), - } - string - } -} - -impl PciEndpointHeader { - pub fn address(&self) -> PciAddress { - self.shared.addr - } - - pub fn endpoint_header(&self, access: &impl ConfigRegionAccess) -> EndpointHeader { - EndpointHeader::from_header(TyPciHeader::new(self.shared.addr), access).unwrap() - } - - pub fn full_device_id(&self) -> &FullDeviceId { - &self.shared.full_device_id - } - - /// Return the Headers BARs. - pub fn bars(&self, access: &impl ConfigRegionAccess) -> [PciBar; 6] { - let endpoint_header = self.endpoint_header(access); - - 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, access) { - 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, - } - } - Some(TyBar::Memory64 { - 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, - } - } - bars - } -} - -#[cfg(test)] -mod test { - use std::convert::TryInto; - - use pci_types::device_type::DeviceType; - use pci_types::{ConfigRegionAccess, PciAddress}; - - use super::{PciHeader, PciHeaderError}; - - struct TestCfgAccess<'a> { - addr: PciAddress, - bytes: &'a [u8], - } - - impl ConfigRegionAccess for TestCfgAccess<'_> { - unsafe fn read(&self, addr: PciAddress, offset: u16) -> u32 { - assert_eq!(addr, self.addr); - let offset = offset as usize; - assert!(offset < self.bytes.len()); - u32::from_le_bytes(self.bytes[offset..offset + 4].try_into().unwrap()) - } - - unsafe fn write(&self, _addr: PciAddress, _offset: u16, _value: u32) { - unreachable!("should not write during tests"); - } - } - - #[rustfmt::skip] - const IGB_DEV_BYTES: [u8; 256] = [ - 0x86, 0x80, 0x33, 0x15, 0x07, 0x04, 0x10, 0x00, 0x03, 0x00, 0x00, 0x02, 0x10, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x50, 0xf7, 0x00, 0x00, 0x00, 0x00, 0x01, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x58, 0xf7, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd9, 0x15, 0x33, 0x15, - 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x01, 0x00, 0x00, - 0x01, 0x50, 0x23, 0xc8, 0x08, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x05, 0x70, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x11, 0xa0, 0x04, 0x80, 0x03, 0x00, 0x00, 0x00, 0x03, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, - 0x10, 0x00, 0x02, 0x00, 0xc2, 0x8c, 0x00, 0x10, 0x0f, 0x28, 0x19, 0x00, 0x11, 0x5c, 0x42, 0x00, - 0x42, 0x00, 0x11, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 - ]; - - #[test] - fn tset_parse_igb_dev() { - let header = PciHeader::from_reader( - &TestCfgAccess { - addr: PciAddress::new(0, 2, 4, 0), - bytes: &IGB_DEV_BYTES, - }, - PciAddress::new(0, 2, 4, 0), - ) - .unwrap(); - match header { - PciHeader::General { .. } => {} - _ => panic!("wrong header type"), - } - assert_eq!(header.device_id(), 0x1533); - assert_eq!(header.vendor_id(), 0x8086); - assert_eq!(header.revision(), 3); - assert_eq!(header.interface(), 0); - assert_eq!( - DeviceType::from((header.class(), header.subclass())), - DeviceType::EthernetController - ); - assert_eq!(header.subclass(), 0); - } - - #[test] - fn test_parse_nonexistent() { - let bytes = &[0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff]; - assert_eq!( - PciHeader::from_reader( - &TestCfgAccess { - addr: PciAddress::new(0, 2, 4, 0), - bytes, - }, - PciAddress::new(0, 2, 4, 0), - ), - Err(PciHeaderError::NoDevice) - ); - } -}