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