1 // Copyright 2018 The ChromiumOS Authors 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 use std::fmt; 6 use std::fmt::Display; 7 use std::path::Path; 8 use std::str::FromStr; 9 10 use remain::sorted; 11 use serde::Deserialize; 12 use serde::Deserializer; 13 use serde::Serialize; 14 use serde::Serializer; 15 use thiserror::Error as ThisError; 16 17 /// Identifies a single component of a [`PciAddress`]. 18 #[derive(Debug, PartialEq, Eq)] 19 pub enum PciAddressComponent { 20 Domain, 21 Bus, 22 Device, 23 Function, 24 } 25 26 /// PCI address parsing and conversion errors. 27 #[derive(ThisError, Debug, PartialEq, Eq)] 28 #[sorted] 29 pub enum Error { 30 /// The specified component was outside the valid range. 31 #[error("{0:?} out of range")] 32 ComponentOutOfRange(PciAddressComponent), 33 /// The specified component could not be parsed as a hexadecimal number. 34 #[error("{0:?} failed to parse as hex")] 35 InvalidHex(PciAddressComponent), 36 /// The given PCI device path is invalid 37 #[error("Invalid PCI device path")] 38 InvalidHostPath, 39 /// A delimiter (`:` or `.`) between the two specified components was missing or incorrect. 40 #[error("Missing delimiter between {0:?} and {1:?}")] 41 MissingDelimiter(PciAddressComponent, PciAddressComponent), 42 /// The PCI address contained more than the expected number of components. 43 #[error("Too many components in PCI address")] 44 TooManyComponents, 45 } 46 47 pub type Result<T> = std::result::Result<T, Error>; 48 49 /// PCI Device Address, AKA Bus:Device.Function 50 #[derive(Default, Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] 51 pub struct PciAddress { 52 /// Bus number, in the range `0..=255`. 53 pub bus: u8, 54 /// Device number, in the range `0..=31`. 55 pub dev: u8, 56 /// Function number, in the range `0..=7`. 57 pub func: u8, 58 } 59 60 impl Serialize for PciAddress { serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error> where S: Serializer,61 fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error> 62 where 63 S: Serializer, 64 { 65 serializer.serialize_str(&self.to_string()) 66 } 67 } 68 69 impl<'de> Deserialize<'de> for PciAddress { deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error> where D: Deserializer<'de>,70 fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error> 71 where 72 D: Deserializer<'de>, 73 { 74 let s = String::deserialize(deserializer)?; 75 FromStr::from_str(&s).map_err(serde::de::Error::custom) 76 } 77 } 78 79 /// Convert `PciAddress` to a human-readable string format. 80 /// 81 /// The display format will always include the domain component, even if it is zero. 82 /// 83 /// # Example 84 /// 85 /// ``` 86 /// use devices::PciAddress; 87 /// 88 /// let pci_address = PciAddress::new(0x0000, 0x03, 0x14, 0x1)?; 89 /// assert_eq!(pci_address.to_string(), "0000:03:14.1"); 90 /// # Ok::<(), devices::PciAddressError>(()) 91 /// ``` 92 impl Display for PciAddress { fmt(&self, f: &mut fmt::Formatter) -> fmt::Result93 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 94 let domain = 0; 95 write!( 96 f, 97 "{:04x}:{:02x}:{:02x}.{:0x}", 98 domain, self.bus, self.dev, self.func, 99 ) 100 } 101 } 102 103 /// Construct `PciAddress` from string "\[domain:\]bus:device.function". 104 /// Each component of the address is unprefixed hexadecimal. 105 /// 106 /// # Example 107 /// 108 /// ``` 109 /// use std::str::FromStr; 110 /// use devices::PciAddress; 111 /// 112 /// let pci_address = PciAddress::from_str("d7:15.4")?; 113 /// assert_eq!(pci_address.bus, 0xd7); 114 /// assert_eq!(pci_address.dev, 0x15); 115 /// assert_eq!(pci_address.func, 0x4); 116 /// # Ok::<(), devices::PciAddressError>(()) 117 /// ``` 118 impl FromStr for PciAddress { 119 type Err = Error; 120 from_str(address: &str) -> std::result::Result<Self, Self::Err>121 fn from_str(address: &str) -> std::result::Result<Self, Self::Err> { 122 let (dev_bus_domain, func) = address.rsplit_once('.').ok_or(Error::MissingDelimiter( 123 PciAddressComponent::Device, 124 PciAddressComponent::Function, 125 ))?; 126 let func = u32::from_str_radix(func, 16) 127 .map_err(|_| Error::InvalidHex(PciAddressComponent::Function))?; 128 129 let (bus_domain, dev) = dev_bus_domain 130 .rsplit_once(':') 131 .ok_or(Error::MissingDelimiter( 132 PciAddressComponent::Bus, 133 PciAddressComponent::Device, 134 ))?; 135 let dev = u32::from_str_radix(dev, 16) 136 .map_err(|_| Error::InvalidHex(PciAddressComponent::Device))?; 137 138 // Domain is optional; if unspecified, the rest of the string is the bus, and domain 139 // defaults to 0. 140 let (domain, bus) = bus_domain.rsplit_once(':').unwrap_or(("0", bus_domain)); 141 let bus = u32::from_str_radix(bus, 16) 142 .map_err(|_| Error::InvalidHex(PciAddressComponent::Bus))?; 143 144 if domain.contains(':') { 145 return Err(Error::TooManyComponents); 146 } 147 148 let domain = u32::from_str_radix(domain, 16) 149 .map_err(|_| Error::InvalidHex(PciAddressComponent::Domain))?; 150 151 Self::new(domain, bus, dev, func) 152 } 153 } 154 155 impl PciAddress { 156 #[doc(hidden)] 157 const BUS_MASK: u32 = 0x00ff; 158 #[doc(hidden)] 159 const DEVICE_BITS_NUM: usize = 5; 160 #[doc(hidden)] 161 const DEVICE_MASK: u32 = 0x1f; 162 #[doc(hidden)] 163 const FUNCTION_BITS_NUM: usize = 3; 164 #[doc(hidden)] 165 const FUNCTION_MASK: u32 = 0x07; 166 #[doc(hidden)] 167 const REGISTER_OFFSET: usize = 2; 168 169 /// Construct [`PciAddress`] from separate domain, bus, device, and function numbers. 170 /// 171 /// # Arguments 172 /// 173 /// * `domain` - The PCI domain number. Must be `0` in the current implementation. 174 /// * `bus` - The PCI bus number. Must be in the range `0..=255`. 175 /// * `dev` - The PCI device number. Must be in the range `0..=31`. 176 /// * `func` - The PCI function number. Must be in the range `0..=7`. 177 /// 178 /// # Errors 179 /// 180 /// If any component is out of the valid range, this function will return 181 /// [`Error::ComponentOutOfRange`]. new(domain: u32, bus: u32, dev: u32, func: u32) -> Result<Self>182 pub fn new(domain: u32, bus: u32, dev: u32, func: u32) -> Result<Self> { 183 if bus > Self::BUS_MASK { 184 return Err(Error::ComponentOutOfRange(PciAddressComponent::Bus)); 185 } 186 187 if dev > Self::DEVICE_MASK { 188 return Err(Error::ComponentOutOfRange(PciAddressComponent::Device)); 189 } 190 191 if func > Self::FUNCTION_MASK { 192 return Err(Error::ComponentOutOfRange(PciAddressComponent::Function)); 193 } 194 195 // PciAddress does not store domain for now, so disallow anything other than domain 0. 196 if domain > 0 { 197 return Err(Error::ComponentOutOfRange(PciAddressComponent::Domain)); 198 } 199 200 Ok(PciAddress { 201 bus: bus as u8, 202 dev: dev as u8, 203 func: func as u8, 204 }) 205 } 206 207 /// Decode a [`PciAddress`] and register index from a CONFIG_ADDRESS value. 208 /// 209 /// The configuration address should be in the format used with the PCI CAM or ECAM 210 /// configuration space access mechanisms, with the lowest bits encoding a register index and 211 /// the bits above that encoding the PCI function (3 bits), device (5 bits), and bus (8 bits). 212 /// The low two bits of the configuration address, which are technically part of the register 213 /// number, are ignored, since PCI configuration space accesses must be DWORD (4-byte) aligned. 214 /// 215 /// On success, returns a [`PciAddress`] and the extracted register index in DWORDs. 216 /// 217 /// # Arguments 218 /// 219 /// * `config_address` - The PCI configuration address. 220 /// * `register_bits_num` - The size of the register value in bits. 221 /// 222 /// # Example 223 /// 224 /// ``` 225 /// use devices::PciAddress; 226 /// 227 /// let (pci_address, register_index) = PciAddress::from_config_address(0x32a354, 8); 228 /// assert_eq!(pci_address.bus, 0x32); 229 /// assert_eq!(pci_address.dev, 0x14); 230 /// assert_eq!(pci_address.func, 0x3); 231 /// assert_eq!(register_index, 0x15); 232 /// ``` from_config_address(config_address: u32, register_bits_num: usize) -> (Self, usize)233 pub fn from_config_address(config_address: u32, register_bits_num: usize) -> (Self, usize) { 234 let bus_offset = register_bits_num + Self::FUNCTION_BITS_NUM + Self::DEVICE_BITS_NUM; 235 let bus = ((config_address >> bus_offset) & Self::BUS_MASK) as u8; 236 let dev_offset = register_bits_num + Self::FUNCTION_BITS_NUM; 237 let dev = ((config_address >> dev_offset) & Self::DEVICE_MASK) as u8; 238 let func = ((config_address >> register_bits_num) & Self::FUNCTION_MASK) as u8; 239 let register_mask: u32 = (1_u32 << (register_bits_num - Self::REGISTER_OFFSET)) - 1; 240 let register = ((config_address >> Self::REGISTER_OFFSET) & register_mask) as usize; 241 242 (PciAddress { bus, dev, func }, register) 243 } 244 245 /// Construct [`PciAddress`] from a system PCI path 246 /// 247 /// # Arguments 248 /// 249 /// * `path` - The system PCI path. The file name of this path must be a valid PCI address. 250 /// 251 /// # Errors 252 /// 253 /// If the path given is invalid or filename is an invalid PCI address, this function will 254 /// return error. from_path(path: &Path) -> Result<Self>255 pub fn from_path(path: &Path) -> Result<Self> { 256 let os_str = path.file_name().ok_or(Error::InvalidHostPath)?; 257 let pci_str = os_str.to_str().ok_or(Error::InvalidHostPath)?; 258 PciAddress::from_str(pci_str) 259 } 260 261 /// Encode [`PciAddress`] into CONFIG_ADDRESS value. 262 /// 263 /// See [`PciAddress::from_config_address()`] for details of the encoding. 264 /// 265 /// # Arguments 266 /// 267 /// * `register` - The register index in DWORDs. 268 /// * `register_bits_num` - The width of the register field, not including the two lowest bits. 269 /// 270 /// # Example 271 /// 272 /// ``` 273 /// use devices::PciAddress; 274 /// 275 /// let pci_address = PciAddress::new(0x0000, 0x32, 0x14, 0x3)?; 276 /// let config_address = pci_address.to_config_address(0x15, 8); 277 /// assert_eq!(config_address, 0x32a354); 278 /// # Ok::<(), devices::PciAddressError>(()) 279 /// ``` to_config_address(&self, register: usize, register_bits_num: usize) -> u32280 pub fn to_config_address(&self, register: usize, register_bits_num: usize) -> u32 { 281 let bus_offset = register_bits_num + Self::FUNCTION_BITS_NUM + Self::DEVICE_BITS_NUM; 282 let dev_offset = register_bits_num + Self::FUNCTION_BITS_NUM; 283 let register_mask: u32 = (1_u32 << (register_bits_num - Self::REGISTER_OFFSET)) - 1; 284 ((Self::BUS_MASK & self.bus as u32) << bus_offset) 285 | ((Self::DEVICE_MASK & self.dev as u32) << dev_offset) 286 | ((Self::FUNCTION_MASK & self.func as u32) << register_bits_num) 287 | ((register_mask & register as u32) << Self::REGISTER_OFFSET) 288 } 289 290 /// Convert B:D:F PCI address to unsigned 32 bit integer. 291 /// 292 /// The bus, device, and function numbers are packed into an integer as follows: 293 /// 294 /// | Bits 15-8 | Bits 7-3 | Bits 2-0 | 295 /// |-----------|----------|----------| 296 /// | Bus | Device | Function | to_u32(&self) -> u32297 pub fn to_u32(&self) -> u32 { 298 ((Self::BUS_MASK & self.bus as u32) << (Self::FUNCTION_BITS_NUM + Self::DEVICE_BITS_NUM)) 299 | ((Self::DEVICE_MASK & self.dev as u32) << Self::FUNCTION_BITS_NUM) 300 | (Self::FUNCTION_MASK & self.func as u32) 301 } 302 303 /// Convert D:F PCI address to a linux style devfn. 304 /// 305 /// The device and function numbers are packed into an u8 as follows: 306 /// 307 /// | Bits 7-3 | Bits 2-0 | 308 /// |----------|----------| 309 /// | Device | Function | devfn(&self) -> u8310 pub fn devfn(&self) -> u8 { 311 (self.dev << Self::FUNCTION_BITS_NUM) | self.func 312 } 313 314 /// Convert D:F PCI address to an ACPI _ADR. 315 /// 316 /// The device and function numbers are packed into an u32 as follows: 317 /// 318 /// | Bits 31-16 | Bits 15-0 | 319 /// |------------|-----------| 320 /// | Device | Function | acpi_adr(&self) -> u32321 pub fn acpi_adr(&self) -> u32 { 322 ((Self::DEVICE_MASK & self.dev as u32) << 16) | (Self::FUNCTION_MASK & self.func as u32) 323 } 324 325 /// Convert B:D:F PCI address to a PCI PME Requester ID. 326 /// 327 /// The output is identical to `to_u32()` except that only the lower 16 bits are needed pme_requester_id(&self) -> u16328 pub fn pme_requester_id(&self) -> u16 { 329 self.to_u32() as u16 330 } 331 332 /// Returns true if the address points to PCI root host-bridge. 333 /// 334 /// This is true if and only if this is the all-zero address (`00:0.0`). is_root(&self) -> bool335 pub fn is_root(&self) -> bool { 336 matches!( 337 &self, 338 PciAddress { 339 bus: 0, 340 dev: 0, 341 func: 0 342 } 343 ) 344 } 345 } 346 347 #[cfg(test)] 348 mod tests { 349 use super::*; 350 351 #[test] from_string()352 fn from_string() { 353 assert_eq!( 354 PciAddress::from_str("0000:00:00.0").unwrap(), 355 PciAddress { 356 bus: 0, 357 dev: 0, 358 func: 0 359 } 360 ); 361 assert_eq!( 362 PciAddress::from_str("00:00.0").unwrap(), 363 PciAddress { 364 bus: 0, 365 dev: 0, 366 func: 0 367 } 368 ); 369 assert_eq!( 370 PciAddress::from_str("01:02.3").unwrap(), 371 PciAddress { 372 bus: 1, 373 dev: 2, 374 func: 3 375 } 376 ); 377 assert_eq!( 378 PciAddress::from_str("ff:1f.7").unwrap(), 379 PciAddress { 380 bus: 0xff, 381 dev: 0x1f, 382 func: 7, 383 } 384 ); 385 } 386 387 #[test] from_string_missing_func_delim()388 fn from_string_missing_func_delim() { 389 assert_eq!( 390 PciAddress::from_str("1").expect_err("parse should fail"), 391 Error::MissingDelimiter(PciAddressComponent::Device, PciAddressComponent::Function) 392 ); 393 } 394 395 #[test] from_string_missing_dev_delim()396 fn from_string_missing_dev_delim() { 397 assert_eq!( 398 PciAddress::from_str("2.1").expect_err("parse should fail"), 399 Error::MissingDelimiter(PciAddressComponent::Bus, PciAddressComponent::Device) 400 ); 401 } 402 403 #[test] from_string_extra_components()404 fn from_string_extra_components() { 405 assert_eq!( 406 PciAddress::from_str("0:0:0:0.0").expect_err("parse should fail"), 407 Error::TooManyComponents 408 ); 409 } 410 411 #[test] from_string_invalid_func_hex()412 fn from_string_invalid_func_hex() { 413 assert_eq!( 414 PciAddress::from_str("0000:00:00.g").expect_err("parse should fail"), 415 Error::InvalidHex(PciAddressComponent::Function) 416 ); 417 } 418 419 #[test] from_string_invalid_func_range()420 fn from_string_invalid_func_range() { 421 assert_eq!( 422 PciAddress::from_str("0000:00:00.8").expect_err("parse should fail"), 423 Error::ComponentOutOfRange(PciAddressComponent::Function) 424 ); 425 } 426 427 #[test] from_string_invalid_dev_hex()428 fn from_string_invalid_dev_hex() { 429 assert_eq!( 430 PciAddress::from_str("0000:00:gg.0").expect_err("parse should fail"), 431 Error::InvalidHex(PciAddressComponent::Device) 432 ); 433 } 434 435 #[test] from_string_invalid_dev_range()436 fn from_string_invalid_dev_range() { 437 assert_eq!( 438 PciAddress::from_str("0000:00:20.0").expect_err("parse should fail"), 439 Error::ComponentOutOfRange(PciAddressComponent::Device) 440 ); 441 } 442 443 #[test] from_string_invalid_bus_hex()444 fn from_string_invalid_bus_hex() { 445 assert_eq!( 446 PciAddress::from_str("0000:gg:00.0").expect_err("parse should fail"), 447 Error::InvalidHex(PciAddressComponent::Bus) 448 ); 449 } 450 451 #[test] from_string_invalid_bus_range()452 fn from_string_invalid_bus_range() { 453 assert_eq!( 454 PciAddress::from_str("0000:100:00.0").expect_err("parse should fail"), 455 Error::ComponentOutOfRange(PciAddressComponent::Bus) 456 ); 457 } 458 459 #[test] from_string_invalid_domain_hex()460 fn from_string_invalid_domain_hex() { 461 assert_eq!( 462 PciAddress::from_str("gggg:00:00.0").expect_err("parse should fail"), 463 Error::InvalidHex(PciAddressComponent::Domain) 464 ); 465 } 466 467 #[test] from_string_invalid_domain_range()468 fn from_string_invalid_domain_range() { 469 assert_eq!( 470 PciAddress::from_str("0001:00:00.0").expect_err("parse should fail"), 471 Error::ComponentOutOfRange(PciAddressComponent::Domain) 472 ); 473 } 474 475 #[test] format_simple()476 fn format_simple() { 477 assert_eq!( 478 PciAddress::new(0, 1, 2, 3).unwrap().to_string(), 479 "0000:01:02.3" 480 ); 481 } 482 483 #[test] format_max()484 fn format_max() { 485 assert_eq!( 486 PciAddress::new(0, 0xff, 0x1f, 7).unwrap().to_string(), 487 "0000:ff:1f.7" 488 ); 489 } 490 491 #[test] serialize_json()492 fn serialize_json() { 493 assert_eq!( 494 serde_json::to_string(&PciAddress::new(0, 0xa5, 0x1f, 3).unwrap()).unwrap(), 495 "\"0000:a5:1f.3\"" 496 ); 497 } 498 499 #[test] deserialize_json()500 fn deserialize_json() { 501 assert_eq!( 502 serde_json::from_str::<PciAddress>("\"0000:a5:1f.3\"").unwrap(), 503 PciAddress { 504 bus: 0xa5, 505 dev: 0x1f, 506 func: 3, 507 } 508 ); 509 } 510 } 511