diff --git a/Cargo.lock b/Cargo.lock index d93fb99f01..d36db5740f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -837,9 +837,11 @@ dependencies = [ "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", + "plain 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.56 (git+https://gitlab.redox-os.org/redox-os/syscall.git)", "serde 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.51 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "thiserror 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)", "toml 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", ] diff --git a/pcid/Cargo.toml b/pcid/Cargo.toml index 966d0ebff2..dae6e66cce 100644 --- a/pcid/Cargo.toml +++ b/pcid/Cargo.toml @@ -16,8 +16,10 @@ bincode = "1.2" bitflags = "1" byteorder = "1.2" libc = "0.2" +plain = "0.2" redox_syscall = { git = "https://gitlab.redox-os.org/redox-os/syscall.git" } serde = { version = "1", features = ["derive"] } serde_json = "1" +smallvec = "1" thiserror = "1" toml = "0.5" diff --git a/pcid/src/main.rs b/pcid/src/main.rs index daef5c699a..e0d1b76d19 100644 --- a/pcid/src/main.rs +++ b/pcid/src/main.rs @@ -21,6 +21,7 @@ use crate::pci::cap::Capability as PciCapability; mod config; mod driver_interface; mod pci; +mod pcie; pub struct DriverHandler { config: config::DriverConfig, diff --git a/pcid/src/pcie/mod.rs b/pcid/src/pcie/mod.rs new file mode 100644 index 0000000000..57c21a9275 --- /dev/null +++ b/pcid/src/pcie/mod.rs @@ -0,0 +1,91 @@ +use std::{fs, io, mem, slice}; +use smallvec::SmallVec; + +pub const MCFG_NAME: [u8; 4] = *b"MCFG"; + +#[repr(packed)] +#[derive(Clone, Copy, Debug)] +pub struct Mcfg { + // base sdt fields + name: [u8; 4], + length: u32, + revision: u8, + checksum: u8, + oem_id: [u8; 6], + oem_table_id: [u8; 8], + oem_revision: u32, + creator_id: [u8; 4], + _rsvd: [u8; 8], + + base_addrs: [PcieAlloc; 0], +} +unsafe impl plain::Plain for Mcfg {} + +/// The "Memory Mapped Enhanced Configuration Space Base Address Allocation Structure" (yes, it's +/// called that). + +#[repr(packed)] +#[derive(Clone, Copy, Debug)] +pub struct PcieAlloc { + pub base_addr: u64, + pub seg_group_num: u16, + pub start_bus: u8, + pub end_bus: u8, + _rsvd: [u8; 4], +} +unsafe impl plain::Plain for PcieAlloc {} + +impl Mcfg { + pub fn base_addr_structs(&self) -> &[PcieAlloc] { + let total_length = mem::size_of::(); + let len = total_length - 44; + // safe because the length cannot be changed arbitrarily + unsafe { slice::from_raw_parts(&self.base_addrs as *const PcieAlloc, len / mem::size_of::()) } + } +} + +pub struct Mcfgs { + tables: SmallVec<[Vec; 2]>, +} +impl Mcfgs { + pub fn tables<'a>(&'a self) -> impl Iterator + 'a { + self.tables.iter().filter_map(|bytes| { + let mcfg = plain::from_bytes::(bytes).ok()?; + if mcfg.length as usize > bytes.len() { + return None; + } + Some(mcfg) + }) + } + + pub fn fetch() -> io::Result { + let table_dir = fs::read_dir("acpi:tables")?; + + let tables = table_dir.map(|table_direntry| -> io::Result> { + let table_direntry = table_direntry?; + let table_path = table_direntry.path(); + + let table_filename = match table_path.file_name() { + Some(n) => n.to_str().ok_or(io::Error::new(io::ErrorKind::InvalidData, "Non-UTF-8 ACPI table filename"))?, + None => return Ok(None), + }; + + if table_filename.starts_with("MCFG") { + Ok(Some(fs::read(table_path)?)) + } else { + Ok(None) + } + }).filter_map(|result_option| result_option.transpose()).collect::, _>>()?; + + Ok(Self { + tables, + }) + } + pub fn at_bus(&self, bus: u8) -> Option<(&Mcfg, &PcieAlloc)> { + self.tables().find_map(|table| { + Some((table, table.base_addr_structs().iter().find(|addr_struct| { + (addr_struct.start_bus..addr_struct.end_bus).contains(&bus) + })?)) + }) + } +}