xref: /cloud-hypervisor/pci/src/configuration.rs (revision eea9bcea38e0c5649f444c829f3a4f9c22aa486c)
1 // Copyright 2018 The Chromium OS Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE-BSD-3-Clause file.
4 
5 use crate::device::BarReprogrammingParams;
6 use crate::{MsixConfig, PciInterruptPin};
7 use byteorder::{ByteOrder, LittleEndian};
8 use std::fmt::{self, Display};
9 use std::sync::{Arc, Mutex};
10 use versionize::{VersionMap, Versionize, VersionizeError, VersionizeResult};
11 use versionize_derive::Versionize;
12 use vm_device::PciBarType;
13 use vm_migration::{MigratableError, Pausable, Snapshot, Snapshottable, VersionMapped};
14 
15 // The number of 32bit registers in the config space, 4096 bytes.
16 const NUM_CONFIGURATION_REGISTERS: usize = 1024;
17 
18 const STATUS_REG: usize = 1;
19 const STATUS_REG_CAPABILITIES_USED_MASK: u32 = 0x0010_0000;
20 const BAR0_REG: usize = 4;
21 const ROM_BAR_REG: usize = 12;
22 const ROM_BAR_IDX: usize = 6;
23 const BAR_IO_ADDR_MASK: u32 = 0xffff_fffc;
24 const BAR_MEM_ADDR_MASK: u32 = 0xffff_fff0;
25 const ROM_BAR_ADDR_MASK: u32 = 0xffff_f800;
26 const MSI_CAPABILITY_REGISTER_MASK: u32 = 0x0071_0000;
27 const MSIX_CAPABILITY_REGISTER_MASK: u32 = 0xc000_0000;
28 const NUM_BAR_REGS: usize = 6;
29 const CAPABILITY_LIST_HEAD_OFFSET: usize = 0x34;
30 const FIRST_CAPABILITY_OFFSET: usize = 0x40;
31 const CAPABILITY_MAX_OFFSET: usize = 192;
32 
33 const INTERRUPT_LINE_PIN_REG: usize = 15;
34 
35 /// Represents the types of PCI headers allowed in the configuration registers.
36 #[derive(Copy, Clone)]
37 pub enum PciHeaderType {
38     Device,
39     Bridge,
40 }
41 
42 /// Classes of PCI nodes.
43 #[allow(dead_code)]
44 #[derive(Copy, Clone)]
45 pub enum PciClassCode {
46     TooOld,
47     MassStorage,
48     NetworkController,
49     DisplayController,
50     MultimediaController,
51     MemoryController,
52     BridgeDevice,
53     SimpleCommunicationController,
54     BaseSystemPeripheral,
55     InputDevice,
56     DockingStation,
57     Processor,
58     SerialBusController,
59     WirelessController,
60     IntelligentIoController,
61     EncryptionController,
62     DataAcquisitionSignalProcessing,
63     Other = 0xff,
64 }
65 
66 impl PciClassCode {
67     pub fn get_register_value(self) -> u8 {
68         self as u8
69     }
70 }
71 
72 /// A PCI subclass. Each class in `PciClassCode` can specify a unique set of subclasses. This trait
73 /// is implemented by each subclass. It allows use of a trait object to generate configurations.
74 pub trait PciSubclass {
75     /// Convert this subclass to the value used in the PCI specification.
76     fn get_register_value(&self) -> u8;
77 }
78 
79 /// Subclasses of the MultimediaController class.
80 #[allow(dead_code)]
81 #[derive(Copy, Clone)]
82 pub enum PciMultimediaSubclass {
83     VideoController = 0x00,
84     AudioController = 0x01,
85     TelephonyDevice = 0x02,
86     AudioDevice = 0x03,
87     Other = 0x80,
88 }
89 
90 impl PciSubclass for PciMultimediaSubclass {
91     fn get_register_value(&self) -> u8 {
92         *self as u8
93     }
94 }
95 
96 /// Subclasses of the BridgeDevice
97 #[allow(dead_code)]
98 #[derive(Copy, Clone)]
99 pub enum PciBridgeSubclass {
100     HostBridge = 0x00,
101     IsaBridge = 0x01,
102     EisaBridge = 0x02,
103     McaBridge = 0x03,
104     PciToPciBridge = 0x04,
105     PcmciaBridge = 0x05,
106     NuBusBridge = 0x06,
107     CardBusBridge = 0x07,
108     RacEwayBridge = 0x08,
109     PciToPciSemiTransparentBridge = 0x09,
110     InfiniBrandToPciHostBridge = 0x0a,
111     OtherBridgeDevice = 0x80,
112 }
113 
114 impl PciSubclass for PciBridgeSubclass {
115     fn get_register_value(&self) -> u8 {
116         *self as u8
117     }
118 }
119 
120 /// Subclass of the SerialBus
121 #[allow(dead_code)]
122 #[derive(Copy, Clone)]
123 pub enum PciSerialBusSubClass {
124     Firewire = 0x00,
125     Accessbus = 0x01,
126     Ssa = 0x02,
127     Usb = 0x03,
128 }
129 
130 impl PciSubclass for PciSerialBusSubClass {
131     fn get_register_value(&self) -> u8 {
132         *self as u8
133     }
134 }
135 
136 /// Mass Storage Sub Classes
137 #[allow(dead_code)]
138 #[derive(Copy, Clone)]
139 pub enum PciMassStorageSubclass {
140     ScsiStorage = 0x00,
141     IdeInterface = 0x01,
142     FloppyController = 0x02,
143     IpiController = 0x03,
144     RaidController = 0x04,
145     AtaController = 0x05,
146     SataController = 0x06,
147     SerialScsiController = 0x07,
148     NvmController = 0x08,
149     MassStorage = 0x80,
150 }
151 
152 impl PciSubclass for PciMassStorageSubclass {
153     fn get_register_value(&self) -> u8 {
154         *self as u8
155     }
156 }
157 
158 /// Network Controller Sub Classes
159 #[allow(dead_code)]
160 #[derive(Copy, Clone)]
161 pub enum PciNetworkControllerSubclass {
162     EthernetController = 0x00,
163     TokenRingController = 0x01,
164     FddiController = 0x02,
165     AtmController = 0x03,
166     IsdnController = 0x04,
167     WorldFipController = 0x05,
168     PicmgController = 0x06,
169     InfinibandController = 0x07,
170     FabricController = 0x08,
171     NetworkController = 0x80,
172 }
173 
174 impl PciSubclass for PciNetworkControllerSubclass {
175     fn get_register_value(&self) -> u8 {
176         *self as u8
177     }
178 }
179 
180 /// A PCI class programming interface. Each combination of `PciClassCode` and
181 /// `PciSubclass` can specify a set of register-level programming interfaces.
182 /// This trait is implemented by each programming interface.
183 /// It allows use of a trait object to generate configurations.
184 pub trait PciProgrammingInterface {
185     /// Convert this programming interface to the value used in the PCI specification.
186     fn get_register_value(&self) -> u8;
187 }
188 
189 /// Types of PCI capabilities.
190 #[derive(PartialEq, Eq, Copy, Clone)]
191 #[allow(dead_code)]
192 #[allow(non_camel_case_types)]
193 #[repr(u8)]
194 pub enum PciCapabilityId {
195     ListId = 0,
196     PowerManagement = 0x01,
197     AcceleratedGraphicsPort = 0x02,
198     VitalProductData = 0x03,
199     SlotIdentification = 0x04,
200     MessageSignalledInterrupts = 0x05,
201     CompactPciHotSwap = 0x06,
202     PciX = 0x07,
203     HyperTransport = 0x08,
204     VendorSpecific = 0x09,
205     Debugport = 0x0A,
206     CompactPciCentralResourceControl = 0x0B,
207     PciStandardHotPlugController = 0x0C,
208     BridgeSubsystemVendorDeviceId = 0x0D,
209     AgpTargetPciPcibridge = 0x0E,
210     SecureDevice = 0x0F,
211     PciExpress = 0x10,
212     MsiX = 0x11,
213     SataDataIndexConf = 0x12,
214     PciAdvancedFeatures = 0x13,
215     PciEnhancedAllocation = 0x14,
216 }
217 
218 impl From<u8> for PciCapabilityId {
219     fn from(c: u8) -> Self {
220         match c {
221             0 => PciCapabilityId::ListId,
222             0x01 => PciCapabilityId::PowerManagement,
223             0x02 => PciCapabilityId::AcceleratedGraphicsPort,
224             0x03 => PciCapabilityId::VitalProductData,
225             0x04 => PciCapabilityId::SlotIdentification,
226             0x05 => PciCapabilityId::MessageSignalledInterrupts,
227             0x06 => PciCapabilityId::CompactPciHotSwap,
228             0x07 => PciCapabilityId::PciX,
229             0x08 => PciCapabilityId::HyperTransport,
230             0x09 => PciCapabilityId::VendorSpecific,
231             0x0A => PciCapabilityId::Debugport,
232             0x0B => PciCapabilityId::CompactPciCentralResourceControl,
233             0x0C => PciCapabilityId::PciStandardHotPlugController,
234             0x0D => PciCapabilityId::BridgeSubsystemVendorDeviceId,
235             0x0E => PciCapabilityId::AgpTargetPciPcibridge,
236             0x0F => PciCapabilityId::SecureDevice,
237             0x10 => PciCapabilityId::PciExpress,
238             0x11 => PciCapabilityId::MsiX,
239             0x12 => PciCapabilityId::SataDataIndexConf,
240             0x13 => PciCapabilityId::PciAdvancedFeatures,
241             0x14 => PciCapabilityId::PciEnhancedAllocation,
242             _ => PciCapabilityId::ListId,
243         }
244     }
245 }
246 
247 /// Types of PCI Express capabilities.
248 #[derive(PartialEq, Eq, Copy, Clone, Debug)]
249 #[allow(dead_code)]
250 #[repr(u16)]
251 pub enum PciExpressCapabilityId {
252     NullCapability = 0x0000,
253     AdvancedErrorReporting = 0x0001,
254     VirtualChannelMultiFunctionVirtualChannelNotPresent = 0x0002,
255     DeviceSerialNumber = 0x0003,
256     PowerBudgeting = 0x0004,
257     RootComplexLinkDeclaration = 0x0005,
258     RootComplexInternalLinkControl = 0x0006,
259     RootComplexEventCollectorEndpointAssociation = 0x0007,
260     MultiFunctionVirtualChannel = 0x0008,
261     VirtualChannelMultiFunctionVirtualChannelPresent = 0x0009,
262     RootComplexRegisterBlock = 0x000a,
263     VendorSpecificExtendedCapability = 0x000b,
264     ConfigurationAccessCorrelation = 0x000c,
265     AccessControlServices = 0x000d,
266     AlternativeRoutingIdentificationIntepretation = 0x000e,
267     AddressTranslationServices = 0x000f,
268     SingleRootIoVirtualization = 0x0010,
269     DeprecatedMultiRootIoVirtualzation = 0x0011,
270     Multicast = 0x0012,
271     PageRequestInterface = 0x0013,
272     ReservedForAmd = 0x0014,
273     ResizeableBar = 0x0015,
274     DynamicPowerAllocation = 0x0016,
275     ThpRequester = 0x0017,
276     LatencyToleranceReporting = 0x0018,
277     SecondaryPciExpress = 0x0019,
278     ProtocolMultiplexing = 0x001a,
279     ProcessAddressSpaceId = 0x001b,
280     LnRequestor = 0x001c,
281     DownstreamPortContainment = 0x001d,
282     L1PmSubstates = 0x001e,
283     PrecisionTimeMeasurement = 0x001f,
284     PciExpressOverMphy = 0x0020,
285     FRSQueueing = 0x0021,
286     ReadinessTimeReporting = 0x0022,
287     DesignatedVendorSpecificExtendedCapability = 0x0023,
288     VfResizeableBar = 0x0024,
289     DataLinkFeature = 0x0025,
290     PhysicalLayerSixteenGts = 0x0026,
291     LaneMargeningAtTheReceiver = 0x0027,
292     HierarchyId = 0x0028,
293     NativePcieEnclosureManagement = 0x0029,
294     PhysicalLayerThirtyTwoGts = 0x002a,
295     AlternateProtocol = 0x002b,
296     SystemFirmwareIntermediary = 0x002c,
297     ShadowFunctions = 0x002d,
298     DataObjectExchange = 0x002e,
299     Reserved = 0x002f,
300     ExtendedCapabilitiesAbsence = 0xffff,
301 }
302 
303 impl From<u16> for PciExpressCapabilityId {
304     fn from(c: u16) -> Self {
305         match c {
306             0x0000 => PciExpressCapabilityId::NullCapability,
307             0x0001 => PciExpressCapabilityId::AdvancedErrorReporting,
308             0x0002 => PciExpressCapabilityId::VirtualChannelMultiFunctionVirtualChannelNotPresent,
309             0x0003 => PciExpressCapabilityId::DeviceSerialNumber,
310             0x0004 => PciExpressCapabilityId::PowerBudgeting,
311             0x0005 => PciExpressCapabilityId::RootComplexLinkDeclaration,
312             0x0006 => PciExpressCapabilityId::RootComplexInternalLinkControl,
313             0x0007 => PciExpressCapabilityId::RootComplexEventCollectorEndpointAssociation,
314             0x0008 => PciExpressCapabilityId::MultiFunctionVirtualChannel,
315             0x0009 => PciExpressCapabilityId::VirtualChannelMultiFunctionVirtualChannelPresent,
316             0x000a => PciExpressCapabilityId::RootComplexRegisterBlock,
317             0x000b => PciExpressCapabilityId::VendorSpecificExtendedCapability,
318             0x000c => PciExpressCapabilityId::ConfigurationAccessCorrelation,
319             0x000d => PciExpressCapabilityId::AccessControlServices,
320             0x000e => PciExpressCapabilityId::AlternativeRoutingIdentificationIntepretation,
321             0x000f => PciExpressCapabilityId::AddressTranslationServices,
322             0x0010 => PciExpressCapabilityId::SingleRootIoVirtualization,
323             0x0011 => PciExpressCapabilityId::DeprecatedMultiRootIoVirtualzation,
324             0x0012 => PciExpressCapabilityId::Multicast,
325             0x0013 => PciExpressCapabilityId::PageRequestInterface,
326             0x0014 => PciExpressCapabilityId::ReservedForAmd,
327             0x0015 => PciExpressCapabilityId::ResizeableBar,
328             0x0016 => PciExpressCapabilityId::DynamicPowerAllocation,
329             0x0017 => PciExpressCapabilityId::ThpRequester,
330             0x0018 => PciExpressCapabilityId::LatencyToleranceReporting,
331             0x0019 => PciExpressCapabilityId::SecondaryPciExpress,
332             0x001a => PciExpressCapabilityId::ProtocolMultiplexing,
333             0x001b => PciExpressCapabilityId::ProcessAddressSpaceId,
334             0x001c => PciExpressCapabilityId::LnRequestor,
335             0x001d => PciExpressCapabilityId::DownstreamPortContainment,
336             0x001e => PciExpressCapabilityId::L1PmSubstates,
337             0x001f => PciExpressCapabilityId::PrecisionTimeMeasurement,
338             0x0020 => PciExpressCapabilityId::PciExpressOverMphy,
339             0x0021 => PciExpressCapabilityId::FRSQueueing,
340             0x0022 => PciExpressCapabilityId::ReadinessTimeReporting,
341             0x0023 => PciExpressCapabilityId::DesignatedVendorSpecificExtendedCapability,
342             0x0024 => PciExpressCapabilityId::VfResizeableBar,
343             0x0025 => PciExpressCapabilityId::DataLinkFeature,
344             0x0026 => PciExpressCapabilityId::PhysicalLayerSixteenGts,
345             0x0027 => PciExpressCapabilityId::LaneMargeningAtTheReceiver,
346             0x0028 => PciExpressCapabilityId::HierarchyId,
347             0x0029 => PciExpressCapabilityId::NativePcieEnclosureManagement,
348             0x002a => PciExpressCapabilityId::PhysicalLayerThirtyTwoGts,
349             0x002b => PciExpressCapabilityId::AlternateProtocol,
350             0x002c => PciExpressCapabilityId::SystemFirmwareIntermediary,
351             0x002d => PciExpressCapabilityId::ShadowFunctions,
352             0x002e => PciExpressCapabilityId::DataObjectExchange,
353             0xffff => PciExpressCapabilityId::ExtendedCapabilitiesAbsence,
354             _ => PciExpressCapabilityId::Reserved,
355         }
356     }
357 }
358 
359 /// A PCI capability list. Devices can optionally specify capabilities in their configuration space.
360 pub trait PciCapability {
361     fn bytes(&self) -> &[u8];
362     fn id(&self) -> PciCapabilityId;
363 }
364 
365 fn encode_32_bits_bar_size(bar_size: u32) -> Option<u32> {
366     if bar_size > 0 {
367         return Some(!(bar_size - 1));
368     }
369     None
370 }
371 
372 fn decode_32_bits_bar_size(bar_size: u32) -> Option<u32> {
373     if bar_size > 0 {
374         return Some(!bar_size + 1);
375     }
376     None
377 }
378 
379 fn encode_64_bits_bar_size(bar_size: u64) -> Option<(u32, u32)> {
380     if bar_size > 0 {
381         let result = !(bar_size - 1);
382         let result_hi = (result >> 32) as u32;
383         let result_lo = (result & 0xffff_ffff) as u32;
384         return Some((result_hi, result_lo));
385     }
386     None
387 }
388 
389 fn decode_64_bits_bar_size(bar_size_hi: u32, bar_size_lo: u32) -> Option<u64> {
390     let bar_size: u64 = ((bar_size_hi as u64) << 32) | (bar_size_lo as u64);
391     if bar_size > 0 {
392         return Some(!bar_size + 1);
393     }
394     None
395 }
396 
397 #[derive(Default, Clone, Copy, Versionize)]
398 struct PciBar {
399     addr: u32,
400     size: u32,
401     used: bool,
402     r#type: Option<PciBarRegionType>,
403 }
404 
405 #[derive(Versionize)]
406 struct PciConfigurationState {
407     registers: Vec<u32>,
408     writable_bits: Vec<u32>,
409     bars: Vec<PciBar>,
410     rom_bar_addr: u32,
411     rom_bar_size: u32,
412     rom_bar_used: bool,
413     last_capability: Option<(usize, usize)>,
414     msix_cap_reg_idx: Option<usize>,
415 }
416 
417 impl VersionMapped for PciConfigurationState {}
418 
419 /// Contains the configuration space of a PCI node.
420 /// See the [specification](https://en.wikipedia.org/wiki/PCI_configuration_space).
421 /// The configuration space is accessed with DWORD reads and writes from the guest.
422 pub struct PciConfiguration {
423     registers: [u32; NUM_CONFIGURATION_REGISTERS],
424     writable_bits: [u32; NUM_CONFIGURATION_REGISTERS], // writable bits for each register.
425     bars: [PciBar; NUM_BAR_REGS],
426     rom_bar_addr: u32,
427     rom_bar_size: u32,
428     rom_bar_used: bool,
429     // Contains the byte offset and size of the last capability.
430     last_capability: Option<(usize, usize)>,
431     msix_cap_reg_idx: Option<usize>,
432     msix_config: Option<Arc<Mutex<MsixConfig>>>,
433 }
434 
435 /// See pci_regs.h in kernel
436 #[derive(Copy, Clone, PartialEq, Eq, Versionize, Debug)]
437 pub enum PciBarRegionType {
438     Memory32BitRegion = 0,
439     IoRegion = 0x01,
440     Memory64BitRegion = 0x04,
441 }
442 
443 impl From<PciBarType> for PciBarRegionType {
444     fn from(type_: PciBarType) -> Self {
445         match type_ {
446             PciBarType::Io => PciBarRegionType::IoRegion,
447             PciBarType::Mmio32 => PciBarRegionType::Memory32BitRegion,
448             PciBarType::Mmio64 => PciBarRegionType::Memory64BitRegion,
449         }
450     }
451 }
452 
453 #[allow(clippy::from_over_into)]
454 impl Into<PciBarType> for PciBarRegionType {
455     fn into(self) -> PciBarType {
456         match self {
457             PciBarRegionType::IoRegion => PciBarType::Io,
458             PciBarRegionType::Memory32BitRegion => PciBarType::Mmio32,
459             PciBarRegionType::Memory64BitRegion => PciBarType::Mmio64,
460         }
461     }
462 }
463 
464 #[derive(Copy, Clone)]
465 pub enum PciBarPrefetchable {
466     NotPrefetchable = 0,
467     Prefetchable = 0x08,
468 }
469 
470 #[allow(clippy::from_over_into)]
471 impl Into<bool> for PciBarPrefetchable {
472     fn into(self) -> bool {
473         match self {
474             PciBarPrefetchable::NotPrefetchable => false,
475             PciBarPrefetchable::Prefetchable => true,
476         }
477     }
478 }
479 
480 #[derive(Copy, Clone)]
481 pub struct PciBarConfiguration {
482     addr: u64,
483     size: u64,
484     idx: usize,
485     region_type: PciBarRegionType,
486     prefetchable: PciBarPrefetchable,
487 }
488 
489 #[derive(Debug)]
490 pub enum Error {
491     BarAddressInvalid(u64, u64),
492     BarInUse(usize),
493     BarInUse64(usize),
494     BarInvalid(usize),
495     BarInvalid64(usize),
496     BarSizeInvalid(u64),
497     CapabilityEmpty,
498     CapabilityLengthInvalid(usize),
499     CapabilitySpaceFull(usize),
500     Decode32BarSize,
501     Decode64BarSize,
502     Encode32BarSize,
503     Encode64BarSize,
504     RomBarAddressInvalid(u64, u64),
505     RomBarInUse(usize),
506     RomBarInvalid(usize),
507     RomBarSizeInvalid(u64),
508 }
509 pub type Result<T> = std::result::Result<T, Error>;
510 
511 impl std::error::Error for Error {}
512 
513 impl Display for Error {
514     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
515         use self::Error::*;
516         match self {
517             BarAddressInvalid(a, s) => write!(f, "address {} size {} too big", a, s),
518             BarInUse(b) => write!(f, "bar {} already used", b),
519             BarInUse64(b) => write!(f, "64bit bar {} already used(requires two regs)", b),
520             BarInvalid(b) => write!(f, "bar {} invalid, max {}", b, NUM_BAR_REGS - 1),
521             BarInvalid64(b) => write!(
522                 f,
523                 "64bitbar {} invalid, requires two regs, max {}",
524                 b,
525                 NUM_BAR_REGS - 1
526             ),
527             BarSizeInvalid(s) => write!(f, "bar address {} not a power of two", s),
528             CapabilityEmpty => write!(f, "empty capabilities are invalid"),
529             CapabilityLengthInvalid(l) => write!(f, "Invalid capability length {}", l),
530             CapabilitySpaceFull(s) => write!(f, "capability of size {} doesn't fit", s),
531             Decode32BarSize => write!(f, "failed to decode 32 bits BAR size"),
532             Decode64BarSize => write!(f, "failed to decode 64 bits BAR size"),
533             Encode32BarSize => write!(f, "failed to encode 32 bits BAR size"),
534             Encode64BarSize => write!(f, "failed to encode 64 bits BAR size"),
535             RomBarAddressInvalid(a, s) => write!(f, "address {} size {} too big", a, s),
536             RomBarInUse(b) => write!(f, "rom bar {} already used", b),
537             RomBarInvalid(b) => write!(f, "rom bar {} invalid, max {}", b, NUM_BAR_REGS - 1),
538             RomBarSizeInvalid(s) => write!(f, "rom bar address {} not a power of two", s),
539         }
540     }
541 }
542 
543 impl PciConfiguration {
544     #[allow(clippy::too_many_arguments)]
545     pub fn new(
546         vendor_id: u16,
547         device_id: u16,
548         revision_id: u8,
549         class_code: PciClassCode,
550         subclass: &dyn PciSubclass,
551         programming_interface: Option<&dyn PciProgrammingInterface>,
552         header_type: PciHeaderType,
553         subsystem_vendor_id: u16,
554         subsystem_id: u16,
555         msix_config: Option<Arc<Mutex<MsixConfig>>>,
556     ) -> Self {
557         let mut registers = [0u32; NUM_CONFIGURATION_REGISTERS];
558         let mut writable_bits = [0u32; NUM_CONFIGURATION_REGISTERS];
559         registers[0] = u32::from(device_id) << 16 | u32::from(vendor_id);
560         // TODO(dverkamp): Status should be write-1-to-clear
561         writable_bits[1] = 0x0000_ffff; // Status (r/o), command (r/w)
562         let pi = if let Some(pi) = programming_interface {
563             pi.get_register_value()
564         } else {
565             0
566         };
567         registers[2] = u32::from(class_code.get_register_value()) << 24
568             | u32::from(subclass.get_register_value()) << 16
569             | u32::from(pi) << 8
570             | u32::from(revision_id);
571         writable_bits[3] = 0x0000_00ff; // Cacheline size (r/w)
572         match header_type {
573             PciHeaderType::Device => {
574                 registers[3] = 0x0000_0000; // Header type 0 (device)
575                 writable_bits[15] = 0x0000_00ff; // Interrupt line (r/w)
576             }
577             PciHeaderType::Bridge => {
578                 registers[3] = 0x0001_0000; // Header type 1 (bridge)
579                 writable_bits[9] = 0xfff0_fff0; // Memory base and limit
580                 writable_bits[15] = 0xffff_00ff; // Bridge control (r/w), interrupt line (r/w)
581             }
582         };
583         registers[11] = u32::from(subsystem_id) << 16 | u32::from(subsystem_vendor_id);
584 
585         let bars = [PciBar::default(); NUM_BAR_REGS];
586 
587         PciConfiguration {
588             registers,
589             writable_bits,
590             bars,
591             rom_bar_addr: 0,
592             rom_bar_size: 0,
593             rom_bar_used: false,
594             last_capability: None,
595             msix_cap_reg_idx: None,
596             msix_config,
597         }
598     }
599 
600     fn state(&self) -> PciConfigurationState {
601         PciConfigurationState {
602             registers: self.registers.to_vec(),
603             writable_bits: self.writable_bits.to_vec(),
604             bars: self.bars.to_vec(),
605             rom_bar_addr: self.rom_bar_addr,
606             rom_bar_size: self.rom_bar_size,
607             rom_bar_used: self.rom_bar_used,
608             last_capability: self.last_capability,
609             msix_cap_reg_idx: self.msix_cap_reg_idx,
610         }
611     }
612 
613     fn set_state(&mut self, state: &PciConfigurationState) {
614         self.registers.clone_from_slice(state.registers.as_slice());
615         self.writable_bits
616             .clone_from_slice(state.writable_bits.as_slice());
617         self.bars.clone_from_slice(state.bars.as_slice());
618         self.rom_bar_addr = state.rom_bar_addr;
619         self.rom_bar_size = state.rom_bar_size;
620         self.rom_bar_used = state.rom_bar_used;
621         self.last_capability = state.last_capability;
622         self.msix_cap_reg_idx = state.msix_cap_reg_idx;
623     }
624 
625     /// Reads a 32bit register from `reg_idx` in the register map.
626     pub fn read_reg(&self, reg_idx: usize) -> u32 {
627         *(self.registers.get(reg_idx).unwrap_or(&0xffff_ffff))
628     }
629 
630     /// Writes a 32bit register to `reg_idx` in the register map.
631     pub fn write_reg(&mut self, reg_idx: usize, value: u32) {
632         let mut mask = self.writable_bits[reg_idx];
633 
634         if (BAR0_REG..BAR0_REG + NUM_BAR_REGS).contains(&reg_idx) {
635             // Handle very specific case where the BAR is being written with
636             // all 1's to retrieve the BAR size during next BAR reading.
637             if value == 0xffff_ffff {
638                 mask &= self.bars[reg_idx - 4].size;
639             }
640         } else if reg_idx == ROM_BAR_REG {
641             // Handle very specific case where the BAR is being written with
642             // all 1's on bits 31-11 to retrieve the BAR size during next BAR
643             // reading.
644             if value & ROM_BAR_ADDR_MASK == ROM_BAR_ADDR_MASK {
645                 mask &= self.rom_bar_size;
646             }
647         }
648 
649         if let Some(r) = self.registers.get_mut(reg_idx) {
650             *r = (*r & !self.writable_bits[reg_idx]) | (value & mask);
651         } else {
652             warn!("bad PCI register write {}", reg_idx);
653         }
654     }
655 
656     /// Writes a 16bit word to `offset`. `offset` must be 16bit aligned.
657     pub fn write_word(&mut self, offset: usize, value: u16) {
658         let shift = match offset % 4 {
659             0 => 0,
660             2 => 16,
661             _ => {
662                 warn!("bad PCI config write offset {}", offset);
663                 return;
664             }
665         };
666         let reg_idx = offset / 4;
667 
668         if let Some(r) = self.registers.get_mut(reg_idx) {
669             let writable_mask = self.writable_bits[reg_idx];
670             let mask = (0xffffu32 << shift) & writable_mask;
671             let shifted_value = (u32::from(value) << shift) & writable_mask;
672             *r = *r & !mask | shifted_value;
673         } else {
674             warn!("bad PCI config write offset {}", offset);
675         }
676     }
677 
678     /// Writes a byte to `offset`.
679     pub fn write_byte(&mut self, offset: usize, value: u8) {
680         self.write_byte_internal(offset, value, true);
681     }
682 
683     /// Writes a byte to `offset`, optionally enforcing read-only bits.
684     fn write_byte_internal(&mut self, offset: usize, value: u8, apply_writable_mask: bool) {
685         let shift = (offset % 4) * 8;
686         let reg_idx = offset / 4;
687 
688         if let Some(r) = self.registers.get_mut(reg_idx) {
689             let writable_mask = if apply_writable_mask {
690                 self.writable_bits[reg_idx]
691             } else {
692                 0xffff_ffff
693             };
694             let mask = (0xffu32 << shift) & writable_mask;
695             let shifted_value = (u32::from(value) << shift) & writable_mask;
696             *r = *r & !mask | shifted_value;
697         } else {
698             warn!("bad PCI config write offset {}", offset);
699         }
700     }
701 
702     /// Adds a region specified by `config`.  Configures the specified BAR(s) to
703     /// report this region and size to the guest kernel.  Enforces a few constraints
704     /// (i.e, region size must be power of two, register not already used).
705     pub fn add_pci_bar(&mut self, config: &PciBarConfiguration) -> Result<()> {
706         let bar_idx = config.idx;
707         let reg_idx = BAR0_REG + bar_idx;
708 
709         if self.bars[bar_idx].used {
710             return Err(Error::BarInUse(bar_idx));
711         }
712 
713         if config.size.count_ones() != 1 {
714             return Err(Error::BarSizeInvalid(config.size));
715         }
716 
717         if bar_idx >= NUM_BAR_REGS {
718             return Err(Error::BarInvalid(bar_idx));
719         }
720 
721         let end_addr = config
722             .addr
723             .checked_add(config.size - 1)
724             .ok_or(Error::BarAddressInvalid(config.addr, config.size))?;
725         match config.region_type {
726             PciBarRegionType::Memory32BitRegion | PciBarRegionType::IoRegion => {
727                 if end_addr > u64::from(u32::max_value()) {
728                     return Err(Error::BarAddressInvalid(config.addr, config.size));
729                 }
730 
731                 // Encode the BAR size as expected by the software running in
732                 // the guest.
733                 self.bars[bar_idx].size =
734                     encode_32_bits_bar_size(config.size as u32).ok_or(Error::Encode32BarSize)?;
735             }
736             PciBarRegionType::Memory64BitRegion => {
737                 if bar_idx + 1 >= NUM_BAR_REGS {
738                     return Err(Error::BarInvalid64(bar_idx));
739                 }
740 
741                 if end_addr > u64::max_value() {
742                     return Err(Error::BarAddressInvalid(config.addr, config.size));
743                 }
744 
745                 if self.bars[bar_idx + 1].used {
746                     return Err(Error::BarInUse64(bar_idx));
747                 }
748 
749                 // Encode the BAR size as expected by the software running in
750                 // the guest.
751                 let (bar_size_hi, bar_size_lo) =
752                     encode_64_bits_bar_size(config.size).ok_or(Error::Encode64BarSize)?;
753 
754                 self.registers[reg_idx + 1] = (config.addr >> 32) as u32;
755                 self.writable_bits[reg_idx + 1] = 0xffff_ffff;
756                 self.bars[bar_idx + 1].addr = self.registers[reg_idx + 1];
757                 self.bars[bar_idx].size = bar_size_lo;
758                 self.bars[bar_idx + 1].size = bar_size_hi;
759                 self.bars[bar_idx + 1].used = true;
760             }
761         }
762 
763         let (mask, lower_bits) = match config.region_type {
764             PciBarRegionType::Memory32BitRegion | PciBarRegionType::Memory64BitRegion => (
765                 BAR_MEM_ADDR_MASK,
766                 config.prefetchable as u32 | config.region_type as u32,
767             ),
768             PciBarRegionType::IoRegion => (BAR_IO_ADDR_MASK, config.region_type as u32),
769         };
770 
771         self.registers[reg_idx] = ((config.addr as u32) & mask) | lower_bits;
772         self.writable_bits[reg_idx] = mask;
773         self.bars[bar_idx].addr = self.registers[reg_idx];
774         self.bars[bar_idx].used = true;
775         self.bars[bar_idx].r#type = Some(config.region_type);
776 
777         Ok(())
778     }
779 
780     /// Adds rom expansion BAR.
781     pub fn add_pci_rom_bar(&mut self, config: &PciBarConfiguration, active: u32) -> Result<()> {
782         let bar_idx = config.idx;
783         let reg_idx = ROM_BAR_REG;
784 
785         if self.rom_bar_used {
786             return Err(Error::RomBarInUse(bar_idx));
787         }
788 
789         if config.size.count_ones() != 1 {
790             return Err(Error::RomBarSizeInvalid(config.size));
791         }
792 
793         if bar_idx != ROM_BAR_IDX {
794             return Err(Error::RomBarInvalid(bar_idx));
795         }
796 
797         let end_addr = config
798             .addr
799             .checked_add(config.size - 1)
800             .ok_or(Error::RomBarAddressInvalid(config.addr, config.size))?;
801 
802         if end_addr > u64::from(u32::max_value()) {
803             return Err(Error::RomBarAddressInvalid(config.addr, config.size));
804         }
805 
806         self.registers[reg_idx] = (config.addr as u32) | active;
807         self.writable_bits[reg_idx] = ROM_BAR_ADDR_MASK;
808         self.rom_bar_addr = self.registers[reg_idx];
809         self.rom_bar_size =
810             encode_32_bits_bar_size(config.size as u32).ok_or(Error::Encode32BarSize)?;
811         self.rom_bar_used = true;
812 
813         Ok(())
814     }
815 
816     /// Returns the address of the given BAR region.
817     pub fn get_bar_addr(&self, bar_num: usize) -> u64 {
818         let bar_idx = BAR0_REG + bar_num;
819 
820         let mut addr = u64::from(self.bars[bar_num].addr & self.writable_bits[bar_idx]);
821 
822         if let Some(bar_type) = self.bars[bar_num].r#type {
823             if bar_type == PciBarRegionType::Memory64BitRegion {
824                 addr |= u64::from(self.bars[bar_num + 1].addr) << 32;
825             }
826         }
827 
828         addr
829     }
830 
831     /// Configures the IRQ line and pin used by this device.
832     pub fn set_irq(&mut self, line: u8, pin: PciInterruptPin) {
833         // `pin` is 1-based in the pci config space.
834         let pin_idx = (pin as u32) + 1;
835         self.registers[INTERRUPT_LINE_PIN_REG] = (self.registers[INTERRUPT_LINE_PIN_REG]
836             & 0xffff_0000)
837             | (pin_idx << 8)
838             | u32::from(line);
839     }
840 
841     /// Adds the capability `cap_data` to the list of capabilities.
842     /// `cap_data` should include the two-byte PCI capability header (type, next),
843     /// but not populate it. Correct values will be generated automatically based
844     /// on `cap_data.id()`.
845     pub fn add_capability(&mut self, cap_data: &dyn PciCapability) -> Result<usize> {
846         let total_len = cap_data.bytes().len();
847         // Check that the length is valid.
848         if cap_data.bytes().is_empty() {
849             return Err(Error::CapabilityEmpty);
850         }
851         let (cap_offset, tail_offset) = match self.last_capability {
852             Some((offset, len)) => (Self::next_dword(offset, len), offset + 1),
853             None => (FIRST_CAPABILITY_OFFSET, CAPABILITY_LIST_HEAD_OFFSET),
854         };
855         let end_offset = cap_offset
856             .checked_add(total_len)
857             .ok_or(Error::CapabilitySpaceFull(total_len))?;
858         if end_offset > CAPABILITY_MAX_OFFSET {
859             return Err(Error::CapabilitySpaceFull(total_len));
860         }
861         self.registers[STATUS_REG] |= STATUS_REG_CAPABILITIES_USED_MASK;
862         self.write_byte_internal(tail_offset, cap_offset as u8, false);
863         self.write_byte_internal(cap_offset, cap_data.id() as u8, false);
864         self.write_byte_internal(cap_offset + 1, 0, false); // Next pointer.
865         for (i, byte) in cap_data.bytes().iter().enumerate() {
866             self.write_byte_internal(cap_offset + i + 2, *byte, false);
867         }
868         self.last_capability = Some((cap_offset, total_len));
869 
870         match cap_data.id() {
871             PciCapabilityId::MessageSignalledInterrupts => {
872                 self.writable_bits[cap_offset / 4] = MSI_CAPABILITY_REGISTER_MASK;
873             }
874             PciCapabilityId::MsiX => {
875                 self.msix_cap_reg_idx = Some(cap_offset / 4);
876                 self.writable_bits[self.msix_cap_reg_idx.unwrap()] = MSIX_CAPABILITY_REGISTER_MASK;
877             }
878             _ => {}
879         }
880 
881         Ok(cap_offset)
882     }
883 
884     // Find the next aligned offset after the one given.
885     fn next_dword(offset: usize, len: usize) -> usize {
886         let next = offset + len;
887         (next + 3) & !3
888     }
889 
890     pub fn write_config_register(&mut self, reg_idx: usize, offset: u64, data: &[u8]) {
891         if offset as usize + data.len() > 4 {
892             return;
893         }
894 
895         // Handle potential write to MSI-X message control register
896         if let Some(msix_cap_reg_idx) = self.msix_cap_reg_idx {
897             if let Some(msix_config) = &self.msix_config {
898                 if msix_cap_reg_idx == reg_idx && offset == 2 && data.len() == 2 {
899                     msix_config
900                         .lock()
901                         .unwrap()
902                         .set_msg_ctl(LittleEndian::read_u16(data));
903                 } else if msix_cap_reg_idx == reg_idx && offset == 0 && data.len() == 4 {
904                     msix_config
905                         .lock()
906                         .unwrap()
907                         .set_msg_ctl((LittleEndian::read_u32(data) >> 16) as u16);
908                 }
909             }
910         }
911 
912         match data.len() {
913             1 => self.write_byte(reg_idx * 4 + offset as usize, data[0]),
914             2 => self.write_word(
915                 reg_idx * 4 + offset as usize,
916                 u16::from(data[0]) | u16::from(data[1]) << 8,
917             ),
918             4 => self.write_reg(reg_idx, LittleEndian::read_u32(data)),
919             _ => (),
920         }
921     }
922 
923     pub fn read_config_register(&self, reg_idx: usize) -> u32 {
924         self.read_reg(reg_idx)
925     }
926 
927     pub fn detect_bar_reprogramming(
928         &mut self,
929         reg_idx: usize,
930         data: &[u8],
931     ) -> Option<BarReprogrammingParams> {
932         if data.len() != 4 {
933             return None;
934         }
935 
936         let value = LittleEndian::read_u32(data);
937 
938         let mask = self.writable_bits[reg_idx];
939         if (BAR0_REG..BAR0_REG + NUM_BAR_REGS).contains(&reg_idx) {
940             // Ignore the case where the BAR size is being asked for.
941             if value == 0xffff_ffff {
942                 return None;
943             }
944 
945             let bar_idx = reg_idx - 4;
946             // Handle special case where the address being written is
947             // different from the address initially provided. This is a
948             // BAR reprogramming case which needs to be properly caught.
949             if let Some(bar_type) = self.bars[bar_idx].r#type {
950                 // In case of 64 bits memory BAR, we don't do anything until
951                 // the upper BAR is modified, otherwise we would be moving the
952                 // BAR to a wrong location in memory.
953                 if bar_type == PciBarRegionType::Memory64BitRegion {
954                     return None;
955                 }
956 
957                 // Ignore the case where the value is unchanged.
958                 if (value & mask) == (self.bars[bar_idx].addr & mask) {
959                     return None;
960                 }
961 
962                 info!(
963                     "Detected BAR reprogramming: (BAR {}) 0x{:x}->0x{:x}",
964                     reg_idx, self.registers[reg_idx], value
965                 );
966                 let old_base = u64::from(self.bars[bar_idx].addr & mask);
967                 let new_base = u64::from(value & mask);
968                 let len = u64::from(
969                     decode_32_bits_bar_size(self.bars[bar_idx].size)
970                         .ok_or(Error::Decode32BarSize)
971                         .unwrap(),
972                 );
973                 let region_type = bar_type;
974 
975                 self.bars[bar_idx].addr = value;
976 
977                 return Some(BarReprogrammingParams {
978                     old_base,
979                     new_base,
980                     len,
981                     region_type,
982                 });
983             } else if (reg_idx > BAR0_REG)
984                 && ((self.registers[reg_idx - 1] & self.writable_bits[reg_idx - 1])
985                     != (self.bars[bar_idx - 1].addr & self.writable_bits[reg_idx - 1])
986                     || (value & mask) != (self.bars[bar_idx].addr & mask))
987             {
988                 info!(
989                     "Detected BAR reprogramming: (BAR {}) 0x{:x}->0x{:x}",
990                     reg_idx, self.registers[reg_idx], value
991                 );
992                 let old_base = u64::from(self.bars[bar_idx].addr & mask) << 32
993                     | u64::from(self.bars[bar_idx - 1].addr & self.writable_bits[reg_idx - 1]);
994                 let new_base = u64::from(value & mask) << 32
995                     | u64::from(self.registers[reg_idx - 1] & self.writable_bits[reg_idx - 1]);
996                 let len =
997                     decode_64_bits_bar_size(self.bars[bar_idx].size, self.bars[bar_idx - 1].size)
998                         .ok_or(Error::Decode64BarSize)
999                         .unwrap();
1000                 let region_type = PciBarRegionType::Memory64BitRegion;
1001 
1002                 self.bars[bar_idx].addr = value;
1003                 self.bars[bar_idx - 1].addr = self.registers[reg_idx - 1];
1004 
1005                 return Some(BarReprogrammingParams {
1006                     old_base,
1007                     new_base,
1008                     len,
1009                     region_type,
1010                 });
1011             }
1012         } else if reg_idx == ROM_BAR_REG && (value & mask) != (self.rom_bar_addr & mask) {
1013             // Ignore the case where the BAR size is being asked for.
1014             if value & ROM_BAR_ADDR_MASK == ROM_BAR_ADDR_MASK {
1015                 return None;
1016             }
1017 
1018             info!(
1019                 "Detected ROM BAR reprogramming: (BAR {}) 0x{:x}->0x{:x}",
1020                 reg_idx, self.registers[reg_idx], value
1021             );
1022             let old_base = u64::from(self.rom_bar_addr & mask);
1023             let new_base = u64::from(value & mask);
1024             let len = u64::from(
1025                 decode_32_bits_bar_size(self.rom_bar_size)
1026                     .ok_or(Error::Decode32BarSize)
1027                     .unwrap(),
1028             );
1029             let region_type = PciBarRegionType::Memory32BitRegion;
1030 
1031             self.rom_bar_addr = value;
1032 
1033             return Some(BarReprogrammingParams {
1034                 old_base,
1035                 new_base,
1036                 len,
1037                 region_type,
1038             });
1039         }
1040 
1041         None
1042     }
1043 }
1044 
1045 impl Pausable for PciConfiguration {}
1046 
1047 impl Snapshottable for PciConfiguration {
1048     fn id(&self) -> String {
1049         String::from("pci_configuration")
1050     }
1051 
1052     fn snapshot(&mut self) -> std::result::Result<Snapshot, MigratableError> {
1053         Snapshot::new_from_versioned_state(&self.id(), &self.state())
1054     }
1055 
1056     fn restore(&mut self, snapshot: Snapshot) -> std::result::Result<(), MigratableError> {
1057         self.set_state(&snapshot.to_versioned_state(&self.id())?);
1058         Ok(())
1059     }
1060 }
1061 
1062 impl Default for PciBarConfiguration {
1063     fn default() -> Self {
1064         PciBarConfiguration {
1065             idx: 0,
1066             addr: 0,
1067             size: 0,
1068             region_type: PciBarRegionType::Memory64BitRegion,
1069             prefetchable: PciBarPrefetchable::NotPrefetchable,
1070         }
1071     }
1072 }
1073 
1074 impl PciBarConfiguration {
1075     pub fn new(
1076         idx: usize,
1077         size: u64,
1078         region_type: PciBarRegionType,
1079         prefetchable: PciBarPrefetchable,
1080     ) -> Self {
1081         PciBarConfiguration {
1082             idx,
1083             addr: 0,
1084             size,
1085             region_type,
1086             prefetchable,
1087         }
1088     }
1089 
1090     #[must_use]
1091     pub fn set_index(mut self, idx: usize) -> Self {
1092         self.idx = idx;
1093         self
1094     }
1095 
1096     #[must_use]
1097     pub fn set_address(mut self, addr: u64) -> Self {
1098         self.addr = addr;
1099         self
1100     }
1101 
1102     #[must_use]
1103     pub fn set_size(mut self, size: u64) -> Self {
1104         self.size = size;
1105         self
1106     }
1107 
1108     #[must_use]
1109     pub fn set_region_type(mut self, region_type: PciBarRegionType) -> Self {
1110         self.region_type = region_type;
1111         self
1112     }
1113 
1114     #[must_use]
1115     pub fn set_prefetchable(mut self, prefetchable: PciBarPrefetchable) -> Self {
1116         self.prefetchable = prefetchable;
1117         self
1118     }
1119 
1120     pub fn idx(&self) -> usize {
1121         self.idx
1122     }
1123 
1124     pub fn addr(&self) -> u64 {
1125         self.addr
1126     }
1127 
1128     pub fn size(&self) -> u64 {
1129         self.size
1130     }
1131 
1132     pub fn region_type(&self) -> PciBarRegionType {
1133         self.region_type
1134     }
1135 
1136     pub fn prefetchable(&self) -> PciBarPrefetchable {
1137         self.prefetchable
1138     }
1139 }
1140 
1141 #[cfg(test)]
1142 mod tests {
1143     use vm_memory::ByteValued;
1144 
1145     use super::*;
1146 
1147     #[repr(packed)]
1148     #[derive(Clone, Copy, Default)]
1149     #[allow(dead_code)]
1150     struct TestCap {
1151         len: u8,
1152         foo: u8,
1153     }
1154 
1155     // SAFETY: All members are simple numbers and any value is valid.
1156     unsafe impl ByteValued for TestCap {}
1157 
1158     impl PciCapability for TestCap {
1159         fn bytes(&self) -> &[u8] {
1160             self.as_slice()
1161         }
1162 
1163         fn id(&self) -> PciCapabilityId {
1164             PciCapabilityId::VendorSpecific
1165         }
1166     }
1167 
1168     #[test]
1169     fn add_capability() {
1170         let mut cfg = PciConfiguration::new(
1171             0x1234,
1172             0x5678,
1173             0x1,
1174             PciClassCode::MultimediaController,
1175             &PciMultimediaSubclass::AudioController,
1176             None,
1177             PciHeaderType::Device,
1178             0xABCD,
1179             0x2468,
1180             None,
1181         );
1182 
1183         // Add two capabilities with different contents.
1184         let cap1 = TestCap { len: 4, foo: 0xAA };
1185         let cap1_offset = cfg.add_capability(&cap1).unwrap();
1186         assert_eq!(cap1_offset % 4, 0);
1187 
1188         let cap2 = TestCap {
1189             len: 0x04,
1190             foo: 0x55,
1191         };
1192         let cap2_offset = cfg.add_capability(&cap2).unwrap();
1193         assert_eq!(cap2_offset % 4, 0);
1194 
1195         // The capability list head should be pointing to cap1.
1196         let cap_ptr = cfg.read_reg(CAPABILITY_LIST_HEAD_OFFSET / 4) & 0xFF;
1197         assert_eq!(cap1_offset, cap_ptr as usize);
1198 
1199         // Verify the contents of the capabilities.
1200         let cap1_data = cfg.read_reg(cap1_offset / 4);
1201         assert_eq!(cap1_data & 0xFF, 0x09); // capability ID
1202         assert_eq!((cap1_data >> 8) & 0xFF, cap2_offset as u32); // next capability pointer
1203         assert_eq!((cap1_data >> 16) & 0xFF, 0x04); // cap1.len
1204         assert_eq!((cap1_data >> 24) & 0xFF, 0xAA); // cap1.foo
1205 
1206         let cap2_data = cfg.read_reg(cap2_offset / 4);
1207         assert_eq!(cap2_data & 0xFF, 0x09); // capability ID
1208         assert_eq!((cap2_data >> 8) & 0xFF, 0x00); // next capability pointer
1209         assert_eq!((cap2_data >> 16) & 0xFF, 0x04); // cap2.len
1210         assert_eq!((cap2_data >> 24) & 0xFF, 0x55); // cap2.foo
1211     }
1212 
1213     #[derive(Copy, Clone)]
1214     enum TestPi {
1215         Test = 0x5a,
1216     }
1217 
1218     impl PciProgrammingInterface for TestPi {
1219         fn get_register_value(&self) -> u8 {
1220             *self as u8
1221         }
1222     }
1223 
1224     #[test]
1225     fn class_code() {
1226         let cfg = PciConfiguration::new(
1227             0x1234,
1228             0x5678,
1229             0x1,
1230             PciClassCode::MultimediaController,
1231             &PciMultimediaSubclass::AudioController,
1232             Some(&TestPi::Test),
1233             PciHeaderType::Device,
1234             0xABCD,
1235             0x2468,
1236             None,
1237         );
1238 
1239         let class_reg = cfg.read_reg(2);
1240         let class_code = (class_reg >> 24) & 0xFF;
1241         let subclass = (class_reg >> 16) & 0xFF;
1242         let prog_if = (class_reg >> 8) & 0xFF;
1243         assert_eq!(class_code, 0x04);
1244         assert_eq!(subclass, 0x01);
1245         assert_eq!(prog_if, 0x5a);
1246     }
1247 }
1248