xref: /aosp_15_r20/external/crosvm/devices/src/pci/pci_address.rs (revision bb4ee6a4ae7042d18b07a98463b9c8b875e44b39)
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