// Copyright 2018 The Chromium OS Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE-BSD-3-Clause file. //! Implements pci devices and busses. #[macro_use] extern crate log; mod bus; mod configuration; mod device; mod msi; mod msix; mod vfio; mod vfio_user; pub use self::bus::{PciBus, PciConfigIo, PciConfigMmio, PciRoot, PciRootError}; pub use self::configuration::{ PciBarConfiguration, PciBarPrefetchable, PciBarRegionType, PciCapability, PciCapabilityId, PciClassCode, PciConfiguration, PciHeaderType, PciMassStorageSubclass, PciNetworkControllerSubclass, PciProgrammingInterface, PciSerialBusSubClass, PciSubclass, }; pub use self::device::{ BarReprogrammingParams, DeviceRelocation, Error as PciDeviceError, PciDevice, }; pub use self::msi::{msi_num_enabled_vectors, MsiCap, MsiConfig}; pub use self::msix::{MsixCap, MsixConfig, MsixTableEntry, MSIX_TABLE_ENTRY_SIZE}; pub use self::vfio::{VfioPciDevice, VfioPciError}; pub use self::vfio_user::{VfioUserDmaMapping, VfioUserPciDevice, VfioUserPciDeviceError}; use serde::de::Visitor; use std::fmt::{self, Display}; use std::num::ParseIntError; use std::str::FromStr; /// PCI has four interrupt pins A->D. #[derive(Copy, Clone)] pub enum PciInterruptPin { IntA, IntB, IntC, IntD, } impl PciInterruptPin { pub fn to_mask(self) -> u32 { self as u32 } } #[cfg(target_arch = "x86_64")] pub const PCI_CONFIG_IO_PORT: u64 = 0xcf8; #[cfg(target_arch = "x86_64")] pub const PCI_CONFIG_IO_PORT_SIZE: u64 = 0x8; #[derive(Clone, Copy, PartialEq, PartialOrd)] pub struct PciBdf(u32); struct PciBdfVisitor; impl<'de> Visitor<'de> for PciBdfVisitor { type Value = PciBdf; fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { formatter.write_str("struct PciBdf") } fn visit_str(self, v: &str) -> Result where E: serde::de::Error, { Ok(v.into()) } } impl<'de> serde::Deserialize<'de> for PciBdf { fn deserialize(deserializer: D) -> Result where D: serde::Deserializer<'de>, { deserializer.deserialize_str(PciBdfVisitor) } } impl serde::Serialize for PciBdf { fn serialize(&self, serializer: S) -> Result where S: serde::Serializer, { serializer.collect_str(&self.to_string()) } } impl PciBdf { pub fn segment(&self) -> u16 { ((self.0 >> 16) & 0xffff) as u16 } pub fn bus(&self) -> u8 { ((self.0 >> 8) & 0xff) as u8 } pub fn device(&self) -> u8 { ((self.0 >> 3) & 0x1f) as u8 } pub fn function(&self) -> u8 { (self.0 & 0x7) as u8 } pub fn new(segment: u16, bus: u8, device: u8, function: u8) -> Self { Self( (segment as u32) << 16 | (bus as u32) << 8 | ((device & 0x1f) as u32) << 3 | (function & 0x7) as u32, ) } } impl From for PciBdf { fn from(bdf: u32) -> Self { Self(bdf) } } impl From for u32 { fn from(bdf: PciBdf) -> Self { bdf.0 } } impl From<&PciBdf> for u32 { fn from(bdf: &PciBdf) -> Self { bdf.0 } } impl From for u16 { fn from(bdf: PciBdf) -> Self { (bdf.0 & 0xffff) as u16 } } impl From<&PciBdf> for u16 { fn from(bdf: &PciBdf) -> Self { (bdf.0 & 0xffff) as u16 } } impl Display for PciBdf { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!( f, "{:04x}:{:02x}:{:02x}.{:01x}", self.segment(), self.bus(), self.device(), self.function() ) } } impl FromStr for PciBdf { type Err = ParseIntError; fn from_str(s: &str) -> Result { let items: Vec<&str> = s.split('.').collect(); assert_eq!(items.len(), 2); let function = u8::from_str_radix(items[1], 16)?; let items: Vec<&str> = items[0].split(':').collect(); assert_eq!(items.len(), 3); let segment = u16::from_str_radix(items[0], 16)?; let bus = u8::from_str_radix(items[1], 16)?; let device = u8::from_str_radix(items[2], 16)?; Ok(PciBdf::new(segment, bus, device, function)) } } impl From<&str> for PciBdf { fn from(bdf: &str) -> Self { Self::from_str(bdf).unwrap() } }