1use std::fmt;
6use std::fmt::Display;
7use std::path::Path;
8use std::str::FromStr;
9
10use remain::sorted;
11use serde::Deserialize;
12use serde::Deserializer;
13use serde::Serialize;
14use serde::Serializer;
15use thiserror::Error as ThisError;
16
17#[derive(Debug, PartialEq, Eq)]
19pub enum PciAddressComponent {
20 Domain,
21 Bus,
22 Device,
23 Function,
24}
25
26#[derive(ThisError, Debug, PartialEq, Eq)]
28#[sorted]
29pub enum Error {
30 #[error("{0:?} out of range")]
32 ComponentOutOfRange(PciAddressComponent),
33 #[error("{0:?} failed to parse as hex")]
35 InvalidHex(PciAddressComponent),
36 #[error("Invalid PCI device path")]
38 InvalidHostPath,
39 #[error("Missing delimiter between {0:?} and {1:?}")]
41 MissingDelimiter(PciAddressComponent, PciAddressComponent),
42 #[error("Too many components in PCI address")]
44 TooManyComponents,
45}
46
47pub type Result<T> = std::result::Result<T, Error>;
48
49#[derive(Default, Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
51pub struct PciAddress {
52 pub bus: u8,
54 pub dev: u8,
56 pub func: u8,
58}
59
60impl Serialize for PciAddress {
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
69impl<'de> Deserialize<'de> for PciAddress {
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
79impl Display for PciAddress {
93 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
103impl FromStr for PciAddress {
119 type Err = Error;
120
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 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
155impl 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 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 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 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 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 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 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 pub fn devfn(&self) -> u8 {
311 (self.dev << Self::FUNCTION_BITS_NUM) | self.func
312 }
313
314 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 pub fn pme_requester_id(&self) -> u16 {
329 self.to_u32() as u16
330 }
331
332 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)]
348mod tests {
349 use super::*;
350
351 #[test]
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]
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]
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]
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]
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]
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]
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]
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]
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]
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]
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]
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]
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]
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]
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]
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}