1extern crate log;
11
12use std::fmt::{self, Debug, Display};
13use std::num::ParseIntError;
14use std::str::FromStr;
15
16use serde::de::Visitor;
17use serde::{Deserialize, Serialize};
18
19#[derive(Copy, Clone)]
21pub enum PciInterruptPin {
22 IntA,
23 IntB,
24 IntC,
25 IntD,
26}
27
28impl PciInterruptPin {
29 pub fn to_mask(self) -> u32 {
30 self as u32
31 }
32}
33
34#[derive(Clone, Copy, PartialEq, Eq, PartialOrd)]
35pub struct PciBdf(u32);
36
37struct PciBdfVisitor;
38
39impl Visitor<'_> for PciBdfVisitor {
40 type Value = PciBdf;
41
42 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
43 formatter.write_str("struct PciBdf")
44 }
45
46 fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
47 where
48 E: serde::de::Error,
49 {
50 PciBdf::from_str(v).map_err(serde::de::Error::custom)
51 }
52}
53
54impl<'de> serde::Deserialize<'de> for PciBdf {
55 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
56 where
57 D: serde::Deserializer<'de>,
58 {
59 deserializer.deserialize_str(PciBdfVisitor)
60 }
61}
62
63impl serde::Serialize for PciBdf {
64 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
65 where
66 S: serde::Serializer,
67 {
68 serializer.collect_str(&self.to_string())
69 }
70}
71
72impl PciBdf {
73 pub fn segment(&self) -> u16 {
74 ((self.0 >> 16) & 0xffff) as u16
75 }
76
77 pub fn bus(&self) -> u8 {
78 ((self.0 >> 8) & 0xff) as u8
79 }
80
81 pub fn device(&self) -> u8 {
82 ((self.0 >> 3) & 0x1f) as u8
83 }
84
85 pub fn function(&self) -> u8 {
86 (self.0 & 0x7) as u8
87 }
88
89 pub fn new(segment: u16, bus: u8, device: u8, function: u8) -> Self {
90 Self(
91 ((segment as u32) << 16)
92 | ((bus as u32) << 8)
93 | (((device & 0x1f) as u32) << 3)
94 | (function & 0x7) as u32,
95 )
96 }
97}
98
99impl From<u32> for PciBdf {
100 fn from(bdf: u32) -> Self {
101 Self(bdf)
102 }
103}
104
105impl From<PciBdf> for u32 {
106 fn from(bdf: PciBdf) -> Self {
107 bdf.0
108 }
109}
110
111impl From<&PciBdf> for u32 {
112 fn from(bdf: &PciBdf) -> Self {
113 bdf.0
114 }
115}
116
117impl From<PciBdf> for u16 {
118 fn from(bdf: PciBdf) -> Self {
119 (bdf.0 & 0xffff) as u16
120 }
121}
122
123impl From<&PciBdf> for u16 {
124 fn from(bdf: &PciBdf) -> Self {
125 (bdf.0 & 0xffff) as u16
126 }
127}
128
129impl Debug for PciBdf {
130 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
131 write!(
132 f,
133 "{:04x}:{:02x}:{:02x}.{:01x}",
134 self.segment(),
135 self.bus(),
136 self.device(),
137 self.function()
138 )
139 }
140}
141
142impl Display for PciBdf {
143 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
144 write!(
145 f,
146 "{:04x}:{:02x}:{:02x}.{:01x}",
147 self.segment(),
148 self.bus(),
149 self.device(),
150 self.function()
151 )
152 }
153}
154
155#[derive(Debug, thiserror::Error, displaydoc::Display)]
157pub enum PciBdfParseError {
158 InvalidHex(#[from] ParseIntError),
160 InvalidFormat(String),
162}
163
164impl FromStr for PciBdf {
165 type Err = PciBdfParseError;
166
167 fn from_str(s: &str) -> Result<Self, Self::Err> {
168 let items: Vec<&str> = s.split('.').collect();
169 if items.len() != 2 {
170 return Err(PciBdfParseError::InvalidFormat(s.to_string()));
171 }
172 let function = u8::from_str_radix(items[1], 16)?;
173 let items: Vec<&str> = items[0].split(':').collect();
174 if items.len() != 3 {
175 return Err(PciBdfParseError::InvalidFormat(s.to_string()));
176 }
177 let segment = u16::from_str_radix(items[0], 16)?;
178 let bus = u8::from_str_radix(items[1], 16)?;
179 let device = u8::from_str_radix(items[2], 16)?;
180 Ok(PciBdf::new(segment, bus, device, function))
181 }
182}
183
184#[derive(Debug, Copy, Clone, Eq, PartialEq)]
186pub enum PciHeaderType {
187 Device,
188 Bridge,
189}
190
191#[allow(dead_code)]
193#[derive(Copy, Clone)]
194pub enum PciClassCode {
195 TooOld,
196 MassStorage,
197 NetworkController,
198 DisplayController,
199 MultimediaController,
200 MemoryController,
201 BridgeDevice,
202 SimpleCommunicationController,
203 BaseSystemPeripheral,
204 InputDevice,
205 DockingStation,
206 Processor,
207 SerialBusController,
208 WirelessController,
209 IntelligentIoController,
210 EncryptionController,
211 DataAcquisitionSignalProcessing,
212 Other = 0xff,
213}
214
215impl PciClassCode {
216 pub fn get_register_value(self) -> u8 {
217 self as u8
218 }
219}
220
221pub trait PciSubclass {
224 fn get_register_value(&self) -> u8;
226}
227
228#[allow(dead_code)]
230#[derive(Copy, Clone)]
231pub enum PciMultimediaSubclass {
232 VideoController = 0x00,
233 AudioController = 0x01,
234 TelephonyDevice = 0x02,
235 AudioDevice = 0x03,
236 Other = 0x80,
237}
238
239impl PciSubclass for PciMultimediaSubclass {
240 fn get_register_value(&self) -> u8 {
241 *self as u8
242 }
243}
244
245#[allow(dead_code)]
247#[derive(Copy, Clone)]
248pub enum PciBridgeSubclass {
249 HostBridge = 0x00,
250 IsaBridge = 0x01,
251 EisaBridge = 0x02,
252 McaBridge = 0x03,
253 PciToPciBridge = 0x04,
254 PcmciaBridge = 0x05,
255 NuBusBridge = 0x06,
256 CardBusBridge = 0x07,
257 RacEwayBridge = 0x08,
258 PciToPciSemiTransparentBridge = 0x09,
259 InfiniBrandToPciHostBridge = 0x0a,
260 OtherBridgeDevice = 0x80,
261}
262
263impl PciSubclass for PciBridgeSubclass {
264 fn get_register_value(&self) -> u8 {
265 *self as u8
266 }
267}
268
269#[allow(dead_code)]
271#[derive(Copy, Clone)]
272pub enum PciSerialBusSubClass {
273 Firewire = 0x00,
274 Accessbus = 0x01,
275 Ssa = 0x02,
276 Usb = 0x03,
277}
278
279impl PciSubclass for PciSerialBusSubClass {
280 fn get_register_value(&self) -> u8 {
281 *self as u8
282 }
283}
284
285#[allow(dead_code)]
287#[derive(Copy, Clone)]
288pub enum PciMassStorageSubclass {
289 ScsiStorage = 0x00,
290 IdeInterface = 0x01,
291 FloppyController = 0x02,
292 IpiController = 0x03,
293 RaidController = 0x04,
294 AtaController = 0x05,
295 SataController = 0x06,
296 SerialScsiController = 0x07,
297 NvmController = 0x08,
298 MassStorage = 0x80,
299}
300
301impl PciSubclass for PciMassStorageSubclass {
302 fn get_register_value(&self) -> u8 {
303 *self as u8
304 }
305}
306
307#[allow(dead_code)]
309#[derive(Copy, Clone)]
310pub enum PciNetworkControllerSubclass {
311 EthernetController = 0x00,
312 TokenRingController = 0x01,
313 FddiController = 0x02,
314 AtmController = 0x03,
315 IsdnController = 0x04,
316 WorldFipController = 0x05,
317 PicmgController = 0x06,
318 InfinibandController = 0x07,
319 FabricController = 0x08,
320 NetworkController = 0x80,
321}
322
323impl PciSubclass for PciNetworkControllerSubclass {
324 fn get_register_value(&self) -> u8 {
325 *self as u8
326 }
327}
328
329#[derive(Debug, PartialEq, Eq, Copy, Clone)]
331#[allow(dead_code)]
332#[allow(non_camel_case_types)]
333#[repr(u8)]
334pub enum PciCapabilityId {
335 ListId = 0,
336 PowerManagement = 0x01,
337 AcceleratedGraphicsPort = 0x02,
338 VitalProductData = 0x03,
339 SlotIdentification = 0x04,
340 MessageSignalledInterrupts = 0x05,
341 CompactPciHotSwap = 0x06,
342 PciX = 0x07,
343 HyperTransport = 0x08,
344 VendorSpecific = 0x09,
345 Debugport = 0x0A,
346 CompactPciCentralResourceControl = 0x0B,
347 PciStandardHotPlugController = 0x0C,
348 BridgeSubsystemVendorDeviceId = 0x0D,
349 AgpTargetPciPcibridge = 0x0E,
350 SecureDevice = 0x0F,
351 PciExpress = 0x10,
352 MsiX = 0x11,
353 SataDataIndexConf = 0x12,
354 PciAdvancedFeatures = 0x13,
355 PciEnhancedAllocation = 0x14,
356}
357
358impl From<u8> for PciCapabilityId {
359 fn from(c: u8) -> Self {
360 match c {
361 0 => PciCapabilityId::ListId,
362 0x01 => PciCapabilityId::PowerManagement,
363 0x02 => PciCapabilityId::AcceleratedGraphicsPort,
364 0x03 => PciCapabilityId::VitalProductData,
365 0x04 => PciCapabilityId::SlotIdentification,
366 0x05 => PciCapabilityId::MessageSignalledInterrupts,
367 0x06 => PciCapabilityId::CompactPciHotSwap,
368 0x07 => PciCapabilityId::PciX,
369 0x08 => PciCapabilityId::HyperTransport,
370 0x09 => PciCapabilityId::VendorSpecific,
371 0x0A => PciCapabilityId::Debugport,
372 0x0B => PciCapabilityId::CompactPciCentralResourceControl,
373 0x0C => PciCapabilityId::PciStandardHotPlugController,
374 0x0D => PciCapabilityId::BridgeSubsystemVendorDeviceId,
375 0x0E => PciCapabilityId::AgpTargetPciPcibridge,
376 0x0F => PciCapabilityId::SecureDevice,
377 0x10 => PciCapabilityId::PciExpress,
378 0x11 => PciCapabilityId::MsiX,
379 0x12 => PciCapabilityId::SataDataIndexConf,
380 0x13 => PciCapabilityId::PciAdvancedFeatures,
381 0x14 => PciCapabilityId::PciEnhancedAllocation,
382 _ => PciCapabilityId::ListId,
383 }
384 }
385}
386
387#[derive(PartialEq, Eq, Copy, Clone, Debug)]
389#[allow(dead_code)]
390#[repr(u16)]
391pub enum PciExpressCapabilityId {
392 NullCapability = 0x0000,
393 AdvancedErrorReporting = 0x0001,
394 VirtualChannelMultiFunctionVirtualChannelNotPresent = 0x0002,
395 DeviceSerialNumber = 0x0003,
396 PowerBudgeting = 0x0004,
397 RootComplexLinkDeclaration = 0x0005,
398 RootComplexInternalLinkControl = 0x0006,
399 RootComplexEventCollectorEndpointAssociation = 0x0007,
400 MultiFunctionVirtualChannel = 0x0008,
401 VirtualChannelMultiFunctionVirtualChannelPresent = 0x0009,
402 RootComplexRegisterBlock = 0x000a,
403 VendorSpecificExtendedCapability = 0x000b,
404 ConfigurationAccessCorrelation = 0x000c,
405 AccessControlServices = 0x000d,
406 AlternativeRoutingIdentificationInterpretation = 0x000e,
407 AddressTranslationServices = 0x000f,
408 SingleRootIoVirtualization = 0x0010,
409 DeprecatedMultiRootIoVirtualization = 0x0011,
410 Multicast = 0x0012,
411 PageRequestInterface = 0x0013,
412 ReservedForAmd = 0x0014,
413 ResizeableBar = 0x0015,
414 DynamicPowerAllocation = 0x0016,
415 ThpRequester = 0x0017,
416 LatencyToleranceReporting = 0x0018,
417 SecondaryPciExpress = 0x0019,
418 ProtocolMultiplexing = 0x001a,
419 ProcessAddressSpaceId = 0x001b,
420 LnRequester = 0x001c,
421 DownstreamPortContainment = 0x001d,
422 L1PmSubstates = 0x001e,
423 PrecisionTimeMeasurement = 0x001f,
424 PciExpressOverMphy = 0x0020,
425 FRSQueueing = 0x0021,
426 ReadinessTimeReporting = 0x0022,
427 DesignatedVendorSpecificExtendedCapability = 0x0023,
428 VfResizeableBar = 0x0024,
429 DataLinkFeature = 0x0025,
430 PhysicalLayerSixteenGts = 0x0026,
431 LaneMarginingAtTheReceiver = 0x0027,
432 HierarchyId = 0x0028,
433 NativePcieEnclosureManagement = 0x0029,
434 PhysicalLayerThirtyTwoGts = 0x002a,
435 AlternateProtocol = 0x002b,
436 SystemFirmwareIntermediary = 0x002c,
437 ShadowFunctions = 0x002d,
438 DataObjectExchange = 0x002e,
439 Reserved = 0x002f,
440 ExtendedCapabilitiesAbsence = 0xffff,
441}
442
443impl From<u16> for PciExpressCapabilityId {
444 fn from(c: u16) -> Self {
445 match c {
446 0x0000 => PciExpressCapabilityId::NullCapability,
447 0x0001 => PciExpressCapabilityId::AdvancedErrorReporting,
448 0x0002 => PciExpressCapabilityId::VirtualChannelMultiFunctionVirtualChannelNotPresent,
449 0x0003 => PciExpressCapabilityId::DeviceSerialNumber,
450 0x0004 => PciExpressCapabilityId::PowerBudgeting,
451 0x0005 => PciExpressCapabilityId::RootComplexLinkDeclaration,
452 0x0006 => PciExpressCapabilityId::RootComplexInternalLinkControl,
453 0x0007 => PciExpressCapabilityId::RootComplexEventCollectorEndpointAssociation,
454 0x0008 => PciExpressCapabilityId::MultiFunctionVirtualChannel,
455 0x0009 => PciExpressCapabilityId::VirtualChannelMultiFunctionVirtualChannelPresent,
456 0x000a => PciExpressCapabilityId::RootComplexRegisterBlock,
457 0x000b => PciExpressCapabilityId::VendorSpecificExtendedCapability,
458 0x000c => PciExpressCapabilityId::ConfigurationAccessCorrelation,
459 0x000d => PciExpressCapabilityId::AccessControlServices,
460 0x000e => PciExpressCapabilityId::AlternativeRoutingIdentificationInterpretation,
461 0x000f => PciExpressCapabilityId::AddressTranslationServices,
462 0x0010 => PciExpressCapabilityId::SingleRootIoVirtualization,
463 0x0011 => PciExpressCapabilityId::DeprecatedMultiRootIoVirtualization,
464 0x0012 => PciExpressCapabilityId::Multicast,
465 0x0013 => PciExpressCapabilityId::PageRequestInterface,
466 0x0014 => PciExpressCapabilityId::ReservedForAmd,
467 0x0015 => PciExpressCapabilityId::ResizeableBar,
468 0x0016 => PciExpressCapabilityId::DynamicPowerAllocation,
469 0x0017 => PciExpressCapabilityId::ThpRequester,
470 0x0018 => PciExpressCapabilityId::LatencyToleranceReporting,
471 0x0019 => PciExpressCapabilityId::SecondaryPciExpress,
472 0x001a => PciExpressCapabilityId::ProtocolMultiplexing,
473 0x001b => PciExpressCapabilityId::ProcessAddressSpaceId,
474 0x001c => PciExpressCapabilityId::LnRequester,
475 0x001d => PciExpressCapabilityId::DownstreamPortContainment,
476 0x001e => PciExpressCapabilityId::L1PmSubstates,
477 0x001f => PciExpressCapabilityId::PrecisionTimeMeasurement,
478 0x0020 => PciExpressCapabilityId::PciExpressOverMphy,
479 0x0021 => PciExpressCapabilityId::FRSQueueing,
480 0x0022 => PciExpressCapabilityId::ReadinessTimeReporting,
481 0x0023 => PciExpressCapabilityId::DesignatedVendorSpecificExtendedCapability,
482 0x0024 => PciExpressCapabilityId::VfResizeableBar,
483 0x0025 => PciExpressCapabilityId::DataLinkFeature,
484 0x0026 => PciExpressCapabilityId::PhysicalLayerSixteenGts,
485 0x0027 => PciExpressCapabilityId::LaneMarginingAtTheReceiver,
486 0x0028 => PciExpressCapabilityId::HierarchyId,
487 0x0029 => PciExpressCapabilityId::NativePcieEnclosureManagement,
488 0x002a => PciExpressCapabilityId::PhysicalLayerThirtyTwoGts,
489 0x002b => PciExpressCapabilityId::AlternateProtocol,
490 0x002c => PciExpressCapabilityId::SystemFirmwareIntermediary,
491 0x002d => PciExpressCapabilityId::ShadowFunctions,
492 0x002e => PciExpressCapabilityId::DataObjectExchange,
493 0xffff => PciExpressCapabilityId::ExtendedCapabilitiesAbsence,
494 _ => PciExpressCapabilityId::Reserved,
495 }
496 }
497}
498
499#[derive(Copy, Clone, PartialEq, Eq, Serialize, Deserialize, Debug)]
501pub enum PciBarRegionType {
502 Memory32BitRegion = 0,
503 IoRegion = 0x01,
504 Memory64BitRegion = 0x04,
505}
506
507#[derive(Debug, Copy, Clone, Serialize, Deserialize)]
508pub enum PciBarPrefetchable {
509 NotPrefetchable = 0,
510 Prefetchable = 0x08,
511}
512
513impl From<PciBarPrefetchable> for bool {
514 fn from(val: PciBarPrefetchable) -> Self {
515 match val {
516 PciBarPrefetchable::NotPrefetchable => false,
517 PciBarPrefetchable::Prefetchable => true,
518 }
519 }
520}
521
522#[cfg(test)]
523mod tests {
524 use super::*;
525
526 #[test]
527 fn test_pci_bdf_new() {
528 let bdf = PciBdf::new(0x1234, 0x56, 0x1f, 0x7);
529 assert_eq!(bdf.segment(), 0x1234);
530 assert_eq!(bdf.bus(), 0x56);
531 assert_eq!(bdf.device(), 0x1f);
532 assert_eq!(bdf.function(), 0x7);
533 }
534
535 #[test]
536 fn test_pci_bdf_from_u32() {
537 let bdf = PciBdf::from(0x12345678);
538 assert_eq!(bdf.segment(), 0x1234);
539 assert_eq!(bdf.bus(), 0x56);
540 assert_eq!(bdf.device(), 0x0f);
541 assert_eq!(bdf.function(), 0x0);
542 }
543
544 #[test]
545 fn test_pci_bdf_to_u32() {
546 let bdf = PciBdf::new(0x1234, 0x56, 0x1f, 0x7);
547 let val: u32 = bdf.into();
548 assert_eq!(val, 0x123456ff);
549 }
550
551 #[test]
552 fn test_pci_bdf_to_u16() {
553 let bdf = PciBdf::new(0x1234, 0x56, 0x1f, 0x7);
554 let val: u16 = bdf.into();
555 assert_eq!(val, 0x56ff);
556 }
557
558 #[test]
559 fn test_pci_bdf_from_str_valid() {
560 let bdf = PciBdf::from_str("1234:56:1f.7").unwrap();
561 assert_eq!(bdf.segment(), 0x1234);
562 assert_eq!(bdf.bus(), 0x56);
563 assert_eq!(bdf.device(), 0x1f);
564 assert_eq!(bdf.function(), 0x7);
565 }
566
567 #[test]
568 fn test_pci_bdf_from_str_zero() {
569 let bdf = PciBdf::from_str("0000:00:00.0").unwrap();
570 assert_eq!(bdf.segment(), 0);
571 assert_eq!(bdf.bus(), 0);
572 assert_eq!(bdf.device(), 0);
573 assert_eq!(bdf.function(), 0);
574 }
575
576 #[test]
577 fn test_pci_bdf_from_str_invalid_format() {
578 assert!(matches!(
579 PciBdf::from_str("invalid"),
580 Err(PciBdfParseError::InvalidFormat(_))
581 ));
582 assert!(matches!(
583 PciBdf::from_str("1234:56"),
584 Err(PciBdfParseError::InvalidFormat(_))
585 ));
586 assert!(matches!(
587 PciBdf::from_str("1234:56:78:9a.b"),
588 Err(PciBdfParseError::InvalidFormat(_))
589 ));
590 }
591
592 #[test]
593 fn test_pci_bdf_from_str_invalid_hex() {
594 assert!(matches!(
595 PciBdf::from_str("xxxx:00:00.0"),
596 Err(PciBdfParseError::InvalidHex(_))
597 ));
598 assert!(matches!(
599 PciBdf::from_str("0000:xx:00.0"),
600 Err(PciBdfParseError::InvalidHex(_))
601 ));
602 assert!(matches!(
603 PciBdf::from_str("0000:00:xx.0"),
604 Err(PciBdfParseError::InvalidHex(_))
605 ));
606 assert!(matches!(
607 PciBdf::from_str("0000:00:00.x"),
608 Err(PciBdfParseError::InvalidHex(_))
609 ));
610 }
611
612 #[test]
613 fn test_pci_bdf_display() {
614 let bdf = PciBdf::new(0x1234, 0x56, 0x1f, 0x7);
615 assert_eq!(format!("{}", bdf), "1234:56:1f.7");
616 }
617
618 #[test]
619 fn test_pci_bdf_debug() {
620 let bdf = PciBdf::new(0x1234, 0x56, 0x1f, 0x7);
621 assert_eq!(format!("{:?}", bdf), "1234:56:1f.7");
622 }
623
624 #[test]
625 fn test_pci_bdf_partial_eq() {
626 let bdf1 = PciBdf::new(0x1234, 0x56, 0x1f, 0x7);
627 let bdf2 = PciBdf::new(0x1234, 0x56, 0x1f, 0x7);
628 let bdf3 = PciBdf::new(0x1234, 0x56, 0x1f, 0x6);
629 assert_eq!(bdf1, bdf2);
630 assert_ne!(bdf1, bdf3);
631 }
632
633 #[test]
634 fn test_pci_bdf_partial_ord() {
635 let bdf1 = PciBdf::new(0x1234, 0x56, 0x1f, 0x6);
636 let bdf2 = PciBdf::new(0x1234, 0x56, 0x1f, 0x7);
637 assert!(bdf1 < bdf2);
638 }
639
640 #[test]
641 fn test_pci_bdf_deserialize_ok() {
642 let visitor = PciBdfVisitor;
644 let result = visitor
645 .visit_str::<serde::de::value::Error>("1234:56:1f.7")
646 .unwrap();
647 assert_eq!(result, PciBdf::new(0x1234, 0x56, 0x1f, 0x7));
648 }
649
650 #[test]
651 fn test_pci_bdf_deserialize_invalid() {
652 let visitor = PciBdfVisitor;
654 assert!(visitor
655 .visit_str::<serde::de::value::Error>("invalid")
656 .is_err());
657 }
658
659 #[test]
660 fn test_pci_bdf_serialize() {
661 let bdf = PciBdf::new(0x1234, 0x56, 0x1f, 0x7);
663 serde_test::assert_tokens(&bdf, &[serde_test::Token::Str("1234:56:1f.7")]);
664 }
665}