xref: /cloud-hypervisor/pci/src/configuration.rs (revision 6f8bd27cf7629733582d930519e98d19e90afb16)
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 {} size {} too big", a, s),
520             BarInUse(b) => write!(f, "bar {} already used", b),
521             BarInUse64(b) => write!(f, "64bit bar {} already used(requires two regs)", b),
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 {} not a power of two", s),
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 {} doesn't fit", s),
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 {} size {} too big", a, s),
538             RomBarInUse(b) => write!(f, "rom bar {} already used", b),
539             RomBarInvalid(b) => write!(f, "rom bar {} invalid, max {}", b, NUM_BAR_REGS - 1),
540             RomBarSizeInvalid(s) => write!(f, "rom bar address {} not a power of two", s),
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     fn set_state(&mut self, state: &PciConfigurationState) {
648         self.registers.clone_from_slice(state.registers.as_slice());
649         self.writable_bits
650             .clone_from_slice(state.writable_bits.as_slice());
651         self.bars.clone_from_slice(state.bars.as_slice());
652         self.rom_bar_addr = state.rom_bar_addr;
653         self.rom_bar_size = state.rom_bar_size;
654         self.rom_bar_used = state.rom_bar_used;
655         self.last_capability = state.last_capability;
656         self.msix_cap_reg_idx = state.msix_cap_reg_idx;
657     }
658 
659     /// Reads a 32bit register from `reg_idx` in the register map.
660     pub fn read_reg(&self, reg_idx: usize) -> u32 {
661         *(self.registers.get(reg_idx).unwrap_or(&0xffff_ffff))
662     }
663 
664     /// Writes a 32bit register to `reg_idx` in the register map.
665     pub fn write_reg(&mut self, reg_idx: usize, value: u32) {
666         let mut mask = self.writable_bits[reg_idx];
667 
668         if (BAR0_REG..BAR0_REG + NUM_BAR_REGS).contains(&reg_idx) {
669             // Handle very specific case where the BAR is being written with
670             // all 1's to retrieve the BAR size during next BAR reading.
671             if value == 0xffff_ffff {
672                 mask &= self.bars[reg_idx - 4].size;
673             }
674         } else if reg_idx == ROM_BAR_REG {
675             // Handle very specific case where the BAR is being written with
676             // all 1's on bits 31-11 to retrieve the BAR size during next BAR
677             // reading.
678             if value & ROM_BAR_ADDR_MASK == ROM_BAR_ADDR_MASK {
679                 mask &= self.rom_bar_size;
680             }
681         }
682 
683         if let Some(r) = self.registers.get_mut(reg_idx) {
684             *r = (*r & !self.writable_bits[reg_idx]) | (value & mask);
685         } else {
686             warn!("bad PCI register write {}", reg_idx);
687         }
688     }
689 
690     /// Writes a 16bit word to `offset`. `offset` must be 16bit aligned.
691     pub fn write_word(&mut self, offset: usize, value: u16) {
692         let shift = match offset % 4 {
693             0 => 0,
694             2 => 16,
695             _ => {
696                 warn!("bad PCI config write offset {}", offset);
697                 return;
698             }
699         };
700         let reg_idx = offset / 4;
701 
702         if let Some(r) = self.registers.get_mut(reg_idx) {
703             let writable_mask = self.writable_bits[reg_idx];
704             let mask = (0xffffu32 << shift) & writable_mask;
705             let shifted_value = (u32::from(value) << shift) & writable_mask;
706             *r = *r & !mask | shifted_value;
707         } else {
708             warn!("bad PCI config write offset {}", offset);
709         }
710     }
711 
712     /// Writes a byte to `offset`.
713     pub fn write_byte(&mut self, offset: usize, value: u8) {
714         self.write_byte_internal(offset, value, true);
715     }
716 
717     /// Writes a byte to `offset`, optionally enforcing read-only bits.
718     fn write_byte_internal(&mut self, offset: usize, value: u8, apply_writable_mask: bool) {
719         let shift = (offset % 4) * 8;
720         let reg_idx = offset / 4;
721 
722         if let Some(r) = self.registers.get_mut(reg_idx) {
723             let writable_mask = if apply_writable_mask {
724                 self.writable_bits[reg_idx]
725             } else {
726                 0xffff_ffff
727             };
728             let mask = (0xffu32 << shift) & writable_mask;
729             let shifted_value = (u32::from(value) << shift) & writable_mask;
730             *r = *r & !mask | shifted_value;
731         } else {
732             warn!("bad PCI config write offset {}", offset);
733         }
734     }
735 
736     /// Adds a region specified by `config`.  Configures the specified BAR(s) to
737     /// report this region and size to the guest kernel.  Enforces a few constraints
738     /// (i.e, region size must be power of two, register not already used).
739     pub fn add_pci_bar(&mut self, config: &PciBarConfiguration) -> Result<()> {
740         let bar_idx = config.idx;
741         let reg_idx = BAR0_REG + bar_idx;
742 
743         if self.bars[bar_idx].used {
744             return Err(Error::BarInUse(bar_idx));
745         }
746 
747         if config.size.count_ones() != 1 {
748             return Err(Error::BarSizeInvalid(config.size));
749         }
750 
751         if bar_idx >= NUM_BAR_REGS {
752             return Err(Error::BarInvalid(bar_idx));
753         }
754 
755         let end_addr = config
756             .addr
757             .checked_add(config.size - 1)
758             .ok_or(Error::BarAddressInvalid(config.addr, config.size))?;
759         match config.region_type {
760             PciBarRegionType::Memory32BitRegion | PciBarRegionType::IoRegion => {
761                 if end_addr > u64::from(u32::max_value()) {
762                     return Err(Error::BarAddressInvalid(config.addr, config.size));
763                 }
764 
765                 // Encode the BAR size as expected by the software running in
766                 // the guest.
767                 self.bars[bar_idx].size =
768                     encode_32_bits_bar_size(config.size as u32).ok_or(Error::Encode32BarSize)?;
769             }
770             PciBarRegionType::Memory64BitRegion => {
771                 if bar_idx + 1 >= NUM_BAR_REGS {
772                     return Err(Error::BarInvalid64(bar_idx));
773                 }
774 
775                 if end_addr > u64::max_value() {
776                     return Err(Error::BarAddressInvalid(config.addr, config.size));
777                 }
778 
779                 if self.bars[bar_idx + 1].used {
780                     return Err(Error::BarInUse64(bar_idx));
781                 }
782 
783                 // Encode the BAR size as expected by the software running in
784                 // the guest.
785                 let (bar_size_hi, bar_size_lo) =
786                     encode_64_bits_bar_size(config.size).ok_or(Error::Encode64BarSize)?;
787 
788                 self.registers[reg_idx + 1] = (config.addr >> 32) as u32;
789                 self.writable_bits[reg_idx + 1] = 0xffff_ffff;
790                 self.bars[bar_idx + 1].addr = self.registers[reg_idx + 1];
791                 self.bars[bar_idx].size = bar_size_lo;
792                 self.bars[bar_idx + 1].size = bar_size_hi;
793                 self.bars[bar_idx + 1].used = true;
794             }
795         }
796 
797         let (mask, lower_bits) = match config.region_type {
798             PciBarRegionType::Memory32BitRegion | PciBarRegionType::Memory64BitRegion => (
799                 BAR_MEM_ADDR_MASK,
800                 config.prefetchable as u32 | config.region_type as u32,
801             ),
802             PciBarRegionType::IoRegion => (BAR_IO_ADDR_MASK, config.region_type as u32),
803         };
804 
805         self.registers[reg_idx] = ((config.addr as u32) & mask) | lower_bits;
806         self.writable_bits[reg_idx] = mask;
807         self.bars[bar_idx].addr = self.registers[reg_idx];
808         self.bars[bar_idx].used = true;
809         self.bars[bar_idx].r#type = Some(config.region_type);
810 
811         Ok(())
812     }
813 
814     /// Adds rom expansion BAR.
815     pub fn add_pci_rom_bar(&mut self, config: &PciBarConfiguration, active: u32) -> Result<()> {
816         let bar_idx = config.idx;
817         let reg_idx = ROM_BAR_REG;
818 
819         if self.rom_bar_used {
820             return Err(Error::RomBarInUse(bar_idx));
821         }
822 
823         if config.size.count_ones() != 1 {
824             return Err(Error::RomBarSizeInvalid(config.size));
825         }
826 
827         if bar_idx != ROM_BAR_IDX {
828             return Err(Error::RomBarInvalid(bar_idx));
829         }
830 
831         let end_addr = config
832             .addr
833             .checked_add(config.size - 1)
834             .ok_or(Error::RomBarAddressInvalid(config.addr, config.size))?;
835 
836         if end_addr > u64::from(u32::max_value()) {
837             return Err(Error::RomBarAddressInvalid(config.addr, config.size));
838         }
839 
840         self.registers[reg_idx] = (config.addr as u32) | active;
841         self.writable_bits[reg_idx] = ROM_BAR_ADDR_MASK;
842         self.rom_bar_addr = self.registers[reg_idx];
843         self.rom_bar_size =
844             encode_32_bits_bar_size(config.size as u32).ok_or(Error::Encode32BarSize)?;
845         self.rom_bar_used = true;
846 
847         Ok(())
848     }
849 
850     /// Returns the address of the given BAR region.
851     pub fn get_bar_addr(&self, bar_num: usize) -> u64 {
852         let bar_idx = BAR0_REG + bar_num;
853 
854         let mut addr = u64::from(self.bars[bar_num].addr & self.writable_bits[bar_idx]);
855 
856         if let Some(bar_type) = self.bars[bar_num].r#type {
857             if bar_type == PciBarRegionType::Memory64BitRegion {
858                 addr |= u64::from(self.bars[bar_num + 1].addr) << 32;
859             }
860         }
861 
862         addr
863     }
864 
865     /// Configures the IRQ line and pin used by this device.
866     pub fn set_irq(&mut self, line: u8, pin: PciInterruptPin) {
867         // `pin` is 1-based in the pci config space.
868         let pin_idx = (pin as u32) + 1;
869         self.registers[INTERRUPT_LINE_PIN_REG] = (self.registers[INTERRUPT_LINE_PIN_REG]
870             & 0xffff_0000)
871             | (pin_idx << 8)
872             | u32::from(line);
873     }
874 
875     /// Adds the capability `cap_data` to the list of capabilities.
876     /// `cap_data` should include the two-byte PCI capability header (type, next),
877     /// but not populate it. Correct values will be generated automatically based
878     /// on `cap_data.id()`.
879     pub fn add_capability(&mut self, cap_data: &dyn PciCapability) -> Result<usize> {
880         let total_len = cap_data.bytes().len();
881         // Check that the length is valid.
882         if cap_data.bytes().is_empty() {
883             return Err(Error::CapabilityEmpty);
884         }
885         let (cap_offset, tail_offset) = match self.last_capability {
886             Some((offset, len)) => (Self::next_dword(offset, len), offset + 1),
887             None => (FIRST_CAPABILITY_OFFSET, CAPABILITY_LIST_HEAD_OFFSET),
888         };
889         let end_offset = cap_offset
890             .checked_add(total_len)
891             .ok_or(Error::CapabilitySpaceFull(total_len))?;
892         if end_offset > CAPABILITY_MAX_OFFSET {
893             return Err(Error::CapabilitySpaceFull(total_len));
894         }
895         self.registers[STATUS_REG] |= STATUS_REG_CAPABILITIES_USED_MASK;
896         self.write_byte_internal(tail_offset, cap_offset as u8, false);
897         self.write_byte_internal(cap_offset, cap_data.id() as u8, false);
898         self.write_byte_internal(cap_offset + 1, 0, false); // Next pointer.
899         for (i, byte) in cap_data.bytes().iter().enumerate() {
900             self.write_byte_internal(cap_offset + i + 2, *byte, false);
901         }
902         self.last_capability = Some((cap_offset, total_len));
903 
904         match cap_data.id() {
905             PciCapabilityId::MessageSignalledInterrupts => {
906                 self.writable_bits[cap_offset / 4] = MSI_CAPABILITY_REGISTER_MASK;
907             }
908             PciCapabilityId::MsiX => {
909                 self.msix_cap_reg_idx = Some(cap_offset / 4);
910                 self.writable_bits[self.msix_cap_reg_idx.unwrap()] = MSIX_CAPABILITY_REGISTER_MASK;
911             }
912             _ => {}
913         }
914 
915         Ok(cap_offset)
916     }
917 
918     // Find the next aligned offset after the one given.
919     fn next_dword(offset: usize, len: usize) -> usize {
920         let next = offset + len;
921         (next + 3) & !3
922     }
923 
924     pub fn write_config_register(&mut self, reg_idx: usize, offset: u64, data: &[u8]) {
925         if offset as usize + data.len() > 4 {
926             return;
927         }
928 
929         // Handle potential write to MSI-X message control register
930         if let Some(msix_cap_reg_idx) = self.msix_cap_reg_idx {
931             if let Some(msix_config) = &self.msix_config {
932                 if msix_cap_reg_idx == reg_idx && offset == 2 && data.len() == 2 {
933                     msix_config
934                         .lock()
935                         .unwrap()
936                         .set_msg_ctl(LittleEndian::read_u16(data));
937                 } else if msix_cap_reg_idx == reg_idx && offset == 0 && data.len() == 4 {
938                     msix_config
939                         .lock()
940                         .unwrap()
941                         .set_msg_ctl((LittleEndian::read_u32(data) >> 16) as u16);
942                 }
943             }
944         }
945 
946         match data.len() {
947             1 => self.write_byte(reg_idx * 4 + offset as usize, data[0]),
948             2 => self.write_word(
949                 reg_idx * 4 + offset as usize,
950                 u16::from(data[0]) | u16::from(data[1]) << 8,
951             ),
952             4 => self.write_reg(reg_idx, LittleEndian::read_u32(data)),
953             _ => (),
954         }
955     }
956 
957     pub fn read_config_register(&self, reg_idx: usize) -> u32 {
958         self.read_reg(reg_idx)
959     }
960 
961     pub fn detect_bar_reprogramming(
962         &mut self,
963         reg_idx: usize,
964         data: &[u8],
965     ) -> Option<BarReprogrammingParams> {
966         if data.len() != 4 {
967             return None;
968         }
969 
970         let value = LittleEndian::read_u32(data);
971 
972         let mask = self.writable_bits[reg_idx];
973         if (BAR0_REG..BAR0_REG + NUM_BAR_REGS).contains(&reg_idx) {
974             // Ignore the case where the BAR size is being asked for.
975             if value == 0xffff_ffff {
976                 return None;
977             }
978 
979             let bar_idx = reg_idx - 4;
980             // Handle special case where the address being written is
981             // different from the address initially provided. This is a
982             // BAR reprogramming case which needs to be properly caught.
983             if let Some(bar_type) = self.bars[bar_idx].r#type {
984                 // In case of 64 bits memory BAR, we don't do anything until
985                 // the upper BAR is modified, otherwise we would be moving the
986                 // BAR to a wrong location in memory.
987                 if bar_type == PciBarRegionType::Memory64BitRegion {
988                     return None;
989                 }
990 
991                 // Ignore the case where the value is unchanged.
992                 if (value & mask) == (self.bars[bar_idx].addr & mask) {
993                     return None;
994                 }
995 
996                 info!(
997                     "Detected BAR reprogramming: (BAR {}) 0x{:x}->0x{:x}",
998                     reg_idx, self.registers[reg_idx], value
999                 );
1000                 let old_base = u64::from(self.bars[bar_idx].addr & mask);
1001                 let new_base = u64::from(value & mask);
1002                 let len = u64::from(
1003                     decode_32_bits_bar_size(self.bars[bar_idx].size)
1004                         .ok_or(Error::Decode32BarSize)
1005                         .unwrap(),
1006                 );
1007                 let region_type = bar_type;
1008 
1009                 self.bars[bar_idx].addr = value;
1010 
1011                 return Some(BarReprogrammingParams {
1012                     old_base,
1013                     new_base,
1014                     len,
1015                     region_type,
1016                 });
1017             } else if (reg_idx > BAR0_REG)
1018                 && ((self.registers[reg_idx - 1] & self.writable_bits[reg_idx - 1])
1019                     != (self.bars[bar_idx - 1].addr & self.writable_bits[reg_idx - 1])
1020                     || (value & mask) != (self.bars[bar_idx].addr & mask))
1021             {
1022                 info!(
1023                     "Detected BAR reprogramming: (BAR {}) 0x{:x}->0x{:x}",
1024                     reg_idx, self.registers[reg_idx], value
1025                 );
1026                 let old_base = u64::from(self.bars[bar_idx].addr & mask) << 32
1027                     | u64::from(self.bars[bar_idx - 1].addr & self.writable_bits[reg_idx - 1]);
1028                 let new_base = u64::from(value & mask) << 32
1029                     | u64::from(self.registers[reg_idx - 1] & self.writable_bits[reg_idx - 1]);
1030                 let len =
1031                     decode_64_bits_bar_size(self.bars[bar_idx].size, self.bars[bar_idx - 1].size)
1032                         .ok_or(Error::Decode64BarSize)
1033                         .unwrap();
1034                 let region_type = PciBarRegionType::Memory64BitRegion;
1035 
1036                 self.bars[bar_idx].addr = value;
1037                 self.bars[bar_idx - 1].addr = self.registers[reg_idx - 1];
1038 
1039                 return Some(BarReprogrammingParams {
1040                     old_base,
1041                     new_base,
1042                     len,
1043                     region_type,
1044                 });
1045             }
1046         } else if reg_idx == ROM_BAR_REG && (value & mask) != (self.rom_bar_addr & mask) {
1047             // Ignore the case where the BAR size is being asked for.
1048             if value & ROM_BAR_ADDR_MASK == ROM_BAR_ADDR_MASK {
1049                 return None;
1050             }
1051 
1052             info!(
1053                 "Detected ROM BAR reprogramming: (BAR {}) 0x{:x}->0x{:x}",
1054                 reg_idx, self.registers[reg_idx], value
1055             );
1056             let old_base = u64::from(self.rom_bar_addr & mask);
1057             let new_base = u64::from(value & mask);
1058             let len = u64::from(
1059                 decode_32_bits_bar_size(self.rom_bar_size)
1060                     .ok_or(Error::Decode32BarSize)
1061                     .unwrap(),
1062             );
1063             let region_type = PciBarRegionType::Memory32BitRegion;
1064 
1065             self.rom_bar_addr = value;
1066 
1067             return Some(BarReprogrammingParams {
1068                 old_base,
1069                 new_base,
1070                 len,
1071                 region_type,
1072             });
1073         }
1074 
1075         None
1076     }
1077 }
1078 
1079 impl Pausable for PciConfiguration {}
1080 
1081 impl Snapshottable for PciConfiguration {
1082     fn id(&self) -> String {
1083         String::from(PCI_CONFIGURATION_ID)
1084     }
1085 
1086     fn snapshot(&mut self) -> std::result::Result<Snapshot, MigratableError> {
1087         Snapshot::new_from_versioned_state(&self.id(), &self.state())
1088     }
1089 
1090     fn restore(&mut self, snapshot: Snapshot) -> std::result::Result<(), MigratableError> {
1091         self.set_state(&snapshot.to_versioned_state(&self.id())?);
1092         Ok(())
1093     }
1094 }
1095 
1096 impl Default for PciBarConfiguration {
1097     fn default() -> Self {
1098         PciBarConfiguration {
1099             idx: 0,
1100             addr: 0,
1101             size: 0,
1102             region_type: PciBarRegionType::Memory64BitRegion,
1103             prefetchable: PciBarPrefetchable::NotPrefetchable,
1104         }
1105     }
1106 }
1107 
1108 impl PciBarConfiguration {
1109     pub fn new(
1110         idx: usize,
1111         size: u64,
1112         region_type: PciBarRegionType,
1113         prefetchable: PciBarPrefetchable,
1114     ) -> Self {
1115         PciBarConfiguration {
1116             idx,
1117             addr: 0,
1118             size,
1119             region_type,
1120             prefetchable,
1121         }
1122     }
1123 
1124     #[must_use]
1125     pub fn set_index(mut self, idx: usize) -> Self {
1126         self.idx = idx;
1127         self
1128     }
1129 
1130     #[must_use]
1131     pub fn set_address(mut self, addr: u64) -> Self {
1132         self.addr = addr;
1133         self
1134     }
1135 
1136     #[must_use]
1137     pub fn set_size(mut self, size: u64) -> Self {
1138         self.size = size;
1139         self
1140     }
1141 
1142     #[must_use]
1143     pub fn set_region_type(mut self, region_type: PciBarRegionType) -> Self {
1144         self.region_type = region_type;
1145         self
1146     }
1147 
1148     #[must_use]
1149     pub fn set_prefetchable(mut self, prefetchable: PciBarPrefetchable) -> Self {
1150         self.prefetchable = prefetchable;
1151         self
1152     }
1153 
1154     pub fn idx(&self) -> usize {
1155         self.idx
1156     }
1157 
1158     pub fn addr(&self) -> u64 {
1159         self.addr
1160     }
1161 
1162     pub fn size(&self) -> u64 {
1163         self.size
1164     }
1165 
1166     pub fn region_type(&self) -> PciBarRegionType {
1167         self.region_type
1168     }
1169 
1170     pub fn prefetchable(&self) -> PciBarPrefetchable {
1171         self.prefetchable
1172     }
1173 }
1174 
1175 #[cfg(test)]
1176 mod tests {
1177     use vm_memory::ByteValued;
1178 
1179     use super::*;
1180 
1181     #[repr(packed)]
1182     #[derive(Clone, Copy, Default)]
1183     #[allow(dead_code)]
1184     struct TestCap {
1185         len: u8,
1186         foo: u8,
1187     }
1188 
1189     // SAFETY: All members are simple numbers and any value is valid.
1190     unsafe impl ByteValued for TestCap {}
1191 
1192     impl PciCapability for TestCap {
1193         fn bytes(&self) -> &[u8] {
1194             self.as_slice()
1195         }
1196 
1197         fn id(&self) -> PciCapabilityId {
1198             PciCapabilityId::VendorSpecific
1199         }
1200     }
1201 
1202     #[test]
1203     fn add_capability() {
1204         let mut cfg = PciConfiguration::new(
1205             0x1234,
1206             0x5678,
1207             0x1,
1208             PciClassCode::MultimediaController,
1209             &PciMultimediaSubclass::AudioController,
1210             None,
1211             PciHeaderType::Device,
1212             0xABCD,
1213             0x2468,
1214             None,
1215             None,
1216         );
1217 
1218         // Add two capabilities with different contents.
1219         let cap1 = TestCap { len: 4, foo: 0xAA };
1220         let cap1_offset = cfg.add_capability(&cap1).unwrap();
1221         assert_eq!(cap1_offset % 4, 0);
1222 
1223         let cap2 = TestCap {
1224             len: 0x04,
1225             foo: 0x55,
1226         };
1227         let cap2_offset = cfg.add_capability(&cap2).unwrap();
1228         assert_eq!(cap2_offset % 4, 0);
1229 
1230         // The capability list head should be pointing to cap1.
1231         let cap_ptr = cfg.read_reg(CAPABILITY_LIST_HEAD_OFFSET / 4) & 0xFF;
1232         assert_eq!(cap1_offset, cap_ptr as usize);
1233 
1234         // Verify the contents of the capabilities.
1235         let cap1_data = cfg.read_reg(cap1_offset / 4);
1236         assert_eq!(cap1_data & 0xFF, 0x09); // capability ID
1237         assert_eq!((cap1_data >> 8) & 0xFF, cap2_offset as u32); // next capability pointer
1238         assert_eq!((cap1_data >> 16) & 0xFF, 0x04); // cap1.len
1239         assert_eq!((cap1_data >> 24) & 0xFF, 0xAA); // cap1.foo
1240 
1241         let cap2_data = cfg.read_reg(cap2_offset / 4);
1242         assert_eq!(cap2_data & 0xFF, 0x09); // capability ID
1243         assert_eq!((cap2_data >> 8) & 0xFF, 0x00); // next capability pointer
1244         assert_eq!((cap2_data >> 16) & 0xFF, 0x04); // cap2.len
1245         assert_eq!((cap2_data >> 24) & 0xFF, 0x55); // cap2.foo
1246     }
1247 
1248     #[derive(Copy, Clone)]
1249     enum TestPi {
1250         Test = 0x5a,
1251     }
1252 
1253     impl PciProgrammingInterface for TestPi {
1254         fn get_register_value(&self) -> u8 {
1255             *self as u8
1256         }
1257     }
1258 
1259     #[test]
1260     fn class_code() {
1261         let cfg = PciConfiguration::new(
1262             0x1234,
1263             0x5678,
1264             0x1,
1265             PciClassCode::MultimediaController,
1266             &PciMultimediaSubclass::AudioController,
1267             Some(&TestPi::Test),
1268             PciHeaderType::Device,
1269             0xABCD,
1270             0x2468,
1271             None,
1272             None,
1273         );
1274 
1275         let class_reg = cfg.read_reg(2);
1276         let class_code = (class_reg >> 24) & 0xFF;
1277         let subclass = (class_reg >> 16) & 0xFF;
1278         let prog_if = (class_reg >> 8) & 0xFF;
1279         assert_eq!(class_code, 0x04);
1280         assert_eq!(subclass, 0x01);
1281         assert_eq!(prog_if, 0x5a);
1282     }
1283 }
1284