diff --git a/pcid/src/main.rs b/pcid/src/main.rs index 65c3e1b4ad..0477d361a8 100644 --- a/pcid/src/main.rs +++ b/pcid/src/main.rs @@ -10,7 +10,7 @@ use log::{debug, error, info, warn, trace}; use redox_log::{OutputBuilder, RedoxLogger}; use crate::config::Config; -use crate::pci::{CfgAccess, Pci, PciAddress, PciBar, PciClass, PciFunc, PciHeader, PciHeaderError, PciHeaderType}; +use crate::pci::{CfgAccess, PciAddress, PciBar, PciClass, PciFunc, PciHeader, PciHeaderError, PciHeaderType}; use crate::pci::cap::Capability as PciCapability; use crate::pci::func::{ConfigReader, ConfigWriter}; use crate::pcie::Pcie; @@ -206,12 +206,11 @@ impl DriverHandler { pub struct State { threads: Mutex>>, - pci: Arc, - pcie: Option, + pcie: Pcie, } impl State { fn preferred_cfg_access(&self) -> &dyn CfgAccess { - self.pcie.as_ref().map(|pcie| pcie as &dyn CfgAccess).unwrap_or(&*self.pci as &dyn CfgAccess) + &self.pcie } } @@ -565,17 +564,8 @@ fn main(args: Args) { let _logger_ref = setup_logging(args.verbose); - let pci = Arc::new(Pci::new()); - let state = Arc::new(State { - pci: Arc::clone(&pci), - pcie: match Pcie::new(Arc::clone(&pci)) { - Ok(pcie) => Some(pcie), - Err(error) => { - info!("Couldn't retrieve PCIe info, perhaps the kernel is not compiled with acpi? Using the PCI 3.0 configuration space instead. Error: {:?}", error); - None - } - }, + pcie: Pcie::new(), threads: Mutex::new(Vec::new()), }); diff --git a/pcid/src/pci/mod.rs b/pcid/src/pci/mod.rs index 6fe191ea09..6d39cbdb8f 100644 --- a/pcid/src/pci/mod.rs +++ b/pcid/src/pci/mod.rs @@ -1,19 +1,13 @@ -use std::convert::TryFrom; use std::fmt; -use std::sync::{Mutex, Once}; use bit_field::BitField; use serde::{Deserialize, Serialize}; -#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] -use syscall::io::{Io as _, Pio}; pub use self::bar::PciBar; pub use self::class::PciClass; pub use self::func::PciFunc; pub use self::header::{PciHeader, PciHeaderError, PciHeaderType}; -use log::info; - mod bar; pub mod cap; mod class; @@ -86,85 +80,3 @@ impl fmt::Debug for PciAddress { write!(f, "{}", self) } } - -pub struct Pci { - lock: Mutex<()>, - iopl_once: Once, -} - -impl Pci { - pub fn new() -> Self { - Self { - lock: Mutex::new(()), - iopl_once: Once::new(), - } - } - - fn set_iopl() { - // make sure that pcid is not granted io port permission unless pcie memory-mapped - // configuration space is not available. - info!("PCI: couldn't find or access PCIe extended configuration, and thus falling back to PCI 3.0 io ports"); - unsafe { - syscall::iopl(3).expect("pcid: failed to set iopl to 3"); - } - } - fn address(address: PciAddress, offset: u8) -> u32 { - // TODO: Find the part of pcid that uses an unaligned offset! - // - // assert_eq!(offset & 0xFC, offset, "pci offset is not aligned"); - // - let offset = offset & 0xFC; - - assert_eq!( - address.segment(), - 0, - "usage of multiple segments requires PCIe extended configuration" - ); - - 0x80000000 - | (u32::from(address.bus()) << 16) - | (u32::from(address.device()) << 11) - | (u32::from(address.function()) << 8) - | u32::from(offset) - } -} -#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] -impl CfgAccess for Pci { - unsafe fn read(&self, address: PciAddress, offset: u16) -> u32 { - let _guard = self.lock.lock().unwrap(); - - self.iopl_once.call_once(Self::set_iopl); - - let offset = - u8::try_from(offset).expect("offset too large for PCI 3.0 configuration space"); - let address = Self::address(address, offset); - - Pio::::new(0xCF8).write(address); - Pio::::new(0xCFC).read() - } - - unsafe fn write(&self, address: PciAddress, offset: u16, value: u32) { - let _guard = self.lock.lock().unwrap(); - - self.iopl_once.call_once(Self::set_iopl); - - let offset = - u8::try_from(offset).expect("offset too large for PCI 3.0 configuration space"); - let address = Self::address(address, offset); - - Pio::::new(0xCF8).write(address); - Pio::::new(0xCFC).write(value); - } -} -#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] -impl CfgAccess for Pci { - unsafe fn read(&self, addr: PciAddress, offset: u16) -> u32 { - let _guard = self.lock.lock().unwrap(); - todo!("Pci::CfgAccess::read on this architecture") - } - - unsafe fn write(&self, addr: PciAddress, offset: u16, value: u32) { - let _guard = self.lock.lock().unwrap(); - todo!("Pci::CfgAccess::write on this architecture") - } -} diff --git a/pcid/src/pcie/fallback.rs b/pcid/src/pcie/fallback.rs new file mode 100644 index 0000000000..f9c874ee0a --- /dev/null +++ b/pcid/src/pcie/fallback.rs @@ -0,0 +1,91 @@ +use std::convert::TryFrom; +use std::sync::{Mutex, Once}; + +#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] +use syscall::io::{Io as _, Pio}; + +use log::info; + +use crate::pci::{CfgAccess, PciAddress}; + +pub(crate) struct Pci { + lock: Mutex<()>, + iopl_once: Once, +} + +impl Pci { + pub(crate) fn new() -> Self { + Self { + lock: Mutex::new(()), + iopl_once: Once::new(), + } + } + + fn set_iopl() { + // make sure that pcid is not granted io port permission unless pcie memory-mapped + // configuration space is not available. + info!("PCI: couldn't find or access PCIe extended configuration, and thus falling back to PCI 3.0 io ports"); + unsafe { + syscall::iopl(3).expect("pcid: failed to set iopl to 3"); + } + } + fn address(address: PciAddress, offset: u8) -> u32 { + // TODO: Find the part of pcid that uses an unaligned offset! + // + // assert_eq!(offset & 0xFC, offset, "pci offset is not aligned"); + // + let offset = offset & 0xFC; + + assert_eq!( + address.segment(), + 0, + "usage of multiple segments requires PCIe extended configuration" + ); + + 0x80000000 + | (u32::from(address.bus()) << 16) + | (u32::from(address.device()) << 11) + | (u32::from(address.function()) << 8) + | u32::from(offset) + } +} +#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] +impl CfgAccess for Pci { + unsafe fn read(&self, address: PciAddress, offset: u16) -> u32 { + let _guard = self.lock.lock().unwrap(); + + self.iopl_once.call_once(Self::set_iopl); + + let offset = + u8::try_from(offset).expect("offset too large for PCI 3.0 configuration space"); + let address = Self::address(address, offset); + + Pio::::new(0xCF8).write(address); + Pio::::new(0xCFC).read() + } + + unsafe fn write(&self, address: PciAddress, offset: u16, value: u32) { + let _guard = self.lock.lock().unwrap(); + + self.iopl_once.call_once(Self::set_iopl); + + let offset = + u8::try_from(offset).expect("offset too large for PCI 3.0 configuration space"); + let address = Self::address(address, offset); + + Pio::::new(0xCF8).write(address); + Pio::::new(0xCFC).write(value); + } +} +#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] +impl CfgAccess for Pci { + unsafe fn read(&self, addr: PciAddress, offset: u16) -> u32 { + let _guard = self.lock.lock().unwrap(); + todo!("Pci::CfgAccess::read on this architecture") + } + + unsafe fn write(&self, addr: PciAddress, offset: u16, value: u32) { + let _guard = self.lock.lock().unwrap(); + todo!("Pci::CfgAccess::write on this architecture") + } +} diff --git a/pcid/src/pcie/mod.rs b/pcid/src/pcie/mod.rs index a5f41014ad..3efb019d93 100644 --- a/pcid/src/pcie/mod.rs +++ b/pcid/src/pcie/mod.rs @@ -1,7 +1,12 @@ -use std::sync::{Arc, Mutex}; +use std::sync::Mutex; use std::{fmt, fs, io, mem, ptr, slice}; -use crate::pci::{CfgAccess, Pci, PciAddress}; +use log::info; + +use crate::pci::{CfgAccess, PciAddress}; +use fallback::Pci; + +mod fallback; pub const MCFG_NAME: [u8; 4] = *b"MCFG"; @@ -120,14 +125,14 @@ impl fmt::Debug for Mcfg { pub struct Pcie { lock: Mutex<()>, bus_maps: Vec>, - fallback: Arc, + fallback: Pci, } unsafe impl Send for Pcie {} unsafe impl Sync for Pcie {} impl Pcie { - pub fn new(fallback: Arc) -> io::Result { - Mcfg::with(|mcfg| { + pub fn new() -> Self { + match Mcfg::with(|mcfg| { let alloc_maps = (0..=255) .map(|bus| { if let Some(alloc) = mcfg.at_bus(bus) { @@ -141,9 +146,19 @@ impl Pcie { Ok(Self { lock: Mutex::new(()), bus_maps: alloc_maps, - fallback, + fallback: Pci::new(), }) - }) + }) { + Ok(pcie) => pcie, + Err(error) => { + info!("Couldn't retrieve PCIe info, perhaps the kernel is not compiled with acpi? Using the PCI 3.0 configuration space instead. Error: {:?}", error); + Self { + lock: Mutex::new(()), + bus_maps: vec![], + fallback: Pci::new(), + } + } + } } unsafe fn physmap_pcie_bus(alloc: &PcieAlloc, bus: u8) -> (*mut u32, usize) { @@ -190,9 +205,9 @@ impl Pcie { "multiple segments not yet implemented" ); - let bus_addr = match self.bus_maps[address.bus() as usize] { - Some(bus_addr) => bus_addr, - None => return f(None), + let bus_addr = match self.bus_maps.get(address.bus() as usize) { + Some(Some(bus_addr)) => bus_addr, + Some(None) | None => return f(None), }; let virt_pointer = unsafe { // FIXME use byte_add once stable