diff --git a/Cargo.lock b/Cargo.lock index cd047b5..8f9d22c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,12 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "accessor" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd8b2abd55bf1f9cffbf00fd594566c51a9d31402553284920c1309ca8351086" + [[package]] name = "aho-corasick" version = "1.1.3" @@ -66,6 +72,12 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" +[[package]] +name = "bit_field" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc827186963e592360843fb5ba4b973e145841266c1357f7180c43526f2e5b61" + [[package]] name = "clap" version = "4.5.9" @@ -97,7 +109,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn", + "syn 2.0.71", ] [[package]] @@ -196,6 +208,18 @@ dependencies = [ "eyre", "log", "pci-driver", + "xhci", +] + +[[package]] +name = "num-derive" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "876a53fff98e03a936a674b29568b0e605f06b29372c2489ff4de23f1949743d" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", ] [[package]] @@ -213,6 +237,12 @@ version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + [[package]] name = "pci-driver" version = "0.1.4" @@ -276,6 +306,17 @@ version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + [[package]] name = "syn" version = "2.0.71" @@ -371,3 +412,16 @@ name = "windows_x86_64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "xhci" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09f3f0483969259f2adb6524054400d94ac352e59fa37da6c6ca3b9b3d83ff83" +dependencies = [ + "accessor", + "bit_field", + "num-derive", + "num-traits", + "paste", +] diff --git a/Cargo.toml b/Cargo.toml index bb828e2..1bf720d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,3 +9,4 @@ env_logger = "0.11.3" eyre = "0.6.12" log = "0.4.22" pci-driver = "0.1.4" +xhci = "0.9.2" diff --git a/src/main.rs b/src/main.rs index bd153fe..a3979b5 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,3 +1,7 @@ +mod pci; + +use std::sync::Arc; + use clap::Parser; use pci_driver::{backends::vfio::VfioPciDevice, device::PciDevice}; @@ -16,28 +20,17 @@ fn main() -> eyre::Result<()> { env_logger::init(); let args = Args::parse(); - let device = VfioPciDevice::open(&args.device)?; + let device = Arc::new(VfioPciDevice::open(&args.device)?); if args.reset { device.reset()?; } - let config = device.config(); - // This library got the order backwards... - let class = ( - config.class_code().programming_interface().read()?, - config.class_code().sub_class_code().read()?, - config.class_code().base_class_code().read()?, - ); - println!("{:?}", class); - if class != (0x0c, 0x03, 0x30) { - eyre::bail!("Device is not xHCI controller!"); - } + let registers = crate::pci::load_registers(device)?; log::info!( - "Found PCIe device {:04x}:{:04x}", - config.vendor_id().read()?, - config.device_id().read()? + "xHCI version: {:04x}", + registers.capability.hciversion.read_volatile().get() ); Ok(()) diff --git a/src/pci.rs b/src/pci.rs new file mode 100644 index 0000000..4e2ed3c --- /dev/null +++ b/src/pci.rs @@ -0,0 +1,74 @@ +use std::{num::NonZeroUsize, sync::Arc}; + +use eyre::OptionExt; +use pci_driver::{ + backends::vfio::VfioPciDevice, + device::PciDevice, + regions::{MappedOwningPciRegion, PciRegion}, +}; +use xhci::Registers; + +#[derive(Clone)] +pub struct PciMapper { + pub device: Arc, + pub mapped_region: Arc, + pub phys_base: usize, +} + +impl xhci::accessor::Mapper for PciMapper { + unsafe fn map(&mut self, phys_start: usize, bytes: usize) -> std::num::NonZeroUsize { + log::trace!("Map {:#018x}: {:#x} bytes", phys_start, bytes); + if phys_start < self.phys_base + || phys_start - self.phys_base + bytes > self.mapped_region.len() + { + panic!("Tried to access invalid address"); + } + + NonZeroUsize::try_from( + (self.mapped_region.as_ptr() as usize) + (phys_start - self.phys_base), + ) + .unwrap() + } + + fn unmap(&mut self, virt_start: usize, bytes: usize) { + log::trace!("Unmap {:#018x}: {:#x} bytes", virt_start, bytes); + // no-op, we mapped the entire BAR 0 anyway + } +} + +pub fn load_registers(device: Arc) -> eyre::Result> { + let config = device.config(); + let class = config.read_le_u32(0x08)? >> 8; + if class != 0x0c_03_30 { + eyre::bail!("Device is not xHCI controller!"); + } + + log::info!( + "Found xHCI controller device {:04x}:{:04x}", + config.vendor_id().read()?, + config.device_id().read()? + ); + + let mut bar = [0u8; 8]; + device.config().read_bytes(0x10, &mut bar)?; + let phys_base = u64::from_le_bytes(bar) & 0xffff_fff8; + + log::debug!("BAR physical base: {:#018x}", phys_base); + + let region = device.bar(0).ok_or_eyre("Device does not have BAR 0")?; + let mapped_region = + Arc::new(region.map(0..region.len(), pci_driver::regions::Permissions::ReadWrite)?); + + log::debug!( + "BAR virtual base: {:#018x}", + mapped_region.as_ptr() as usize + ); + + let mapper = PciMapper { + device, + mapped_region, + phys_base: phys_base.try_into()?, + }; + + unsafe { Ok(Registers::new(phys_base as usize, mapper)) } +}