xref: /cloud-hypervisor/pci/src/configuration.rs (revision 7bf0cc1ed518c9d854caeec24f30715c1414fc56)
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     AlternativeRoutingIdentificationInterpretation = 0x000e,
269     AddressTranslationServices = 0x000f,
270     SingleRootIoVirtualization = 0x0010,
271     DeprecatedMultiRootIoVirtualization = 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     LnRequester = 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::AlternativeRoutingIdentificationInterpretation,
323             0x000f => PciExpressCapabilityId::AddressTranslationServices,
324             0x0010 => PciExpressCapabilityId::SingleRootIoVirtualization,
325             0x0011 => PciExpressCapabilityId::DeprecatedMultiRootIoVirtualization,
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::LnRequester,
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 impl From<PciBarRegionType> for PciBarType {
456     fn from(val: PciBarRegionType) -> Self {
457         match val {
458             PciBarRegionType::IoRegion => PciBarType::Io,
459             PciBarRegionType::Memory32BitRegion => PciBarType::Mmio32,
460             PciBarRegionType::Memory64BitRegion => PciBarType::Mmio64,
461         }
462     }
463 }
464 
465 #[derive(Copy, Clone)]
466 pub enum PciBarPrefetchable {
467     NotPrefetchable = 0,
468     Prefetchable = 0x08,
469 }
470 
471 impl From<PciBarPrefetchable> for bool {
472     fn from(val: PciBarPrefetchable) -> Self {
473         match val {
474             PciBarPrefetchable::NotPrefetchable => false,
475             PciBarPrefetchable::Prefetchable => true,
476         }
477     }
478 }
479 
480 #[derive(Copy, Clone)]
481 pub struct PciBarConfiguration {
482     addr: u64,
483     size: u64,
484     idx: usize,
485     region_type: PciBarRegionType,
486     prefetchable: PciBarPrefetchable,
487 }
488 
489 #[derive(Debug)]
490 pub enum Error {
491     BarAddressInvalid(u64, u64),
492     BarInUse(usize),
493     BarInUse64(usize),
494     BarInvalid(usize),
495     BarInvalid64(usize),
496     BarSizeInvalid(u64),
497     CapabilityEmpty,
498     CapabilityLengthInvalid(usize),
499     CapabilitySpaceFull(usize),
500     Decode32BarSize,
501     Decode64BarSize,
502     Encode32BarSize,
503     Encode64BarSize,
504     RomBarAddressInvalid(u64, u64),
505     RomBarInUse(usize),
506     RomBarInvalid(usize),
507     RomBarSizeInvalid(u64),
508 }
509 pub type Result<T> = std::result::Result<T, Error>;
510 
511 impl std::error::Error for Error {}
512 
513 impl Display for Error {
514     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
515         use self::Error::*;
516         match self {
517             BarAddressInvalid(a, s) => write!(f, "address {a} size {s} too big"),
518             BarInUse(b) => write!(f, "bar {b} already used"),
519             BarInUse64(b) => write!(f, "64bit bar {b} already used(requires two regs)"),
520             BarInvalid(b) => write!(f, "bar {} invalid, max {}", b, NUM_BAR_REGS - 1),
521             BarInvalid64(b) => write!(
522                 f,
523                 "64bitbar {} invalid, requires two regs, max {}",
524                 b,
525                 NUM_BAR_REGS - 1
526             ),
527             BarSizeInvalid(s) => write!(f, "bar address {s} not a power of two"),
528             CapabilityEmpty => write!(f, "empty capabilities are invalid"),
529             CapabilityLengthInvalid(l) => write!(f, "Invalid capability length {l}"),
530             CapabilitySpaceFull(s) => write!(f, "capability of size {s} doesn't fit"),
531             Decode32BarSize => write!(f, "failed to decode 32 bits BAR size"),
532             Decode64BarSize => write!(f, "failed to decode 64 bits BAR size"),
533             Encode32BarSize => write!(f, "failed to encode 32 bits BAR size"),
534             Encode64BarSize => write!(f, "failed to encode 64 bits BAR size"),
535             RomBarAddressInvalid(a, s) => write!(f, "address {a} size {s} too big"),
536             RomBarInUse(b) => write!(f, "rom bar {b} already used"),
537             RomBarInvalid(b) => write!(f, "rom bar {} invalid, max {}", b, NUM_BAR_REGS - 1),
538             RomBarSizeInvalid(s) => write!(f, "rom bar address {s} not a power of two"),
539         }
540     }
541 }
542 
543 impl PciConfiguration {
544     #[allow(clippy::too_many_arguments)]
545     pub fn new(
546         vendor_id: u16,
547         device_id: u16,
548         revision_id: u8,
549         class_code: PciClassCode,
550         subclass: &dyn PciSubclass,
551         programming_interface: Option<&dyn PciProgrammingInterface>,
552         header_type: PciHeaderType,
553         subsystem_vendor_id: u16,
554         subsystem_id: u16,
555         msix_config: Option<Arc<Mutex<MsixConfig>>>,
556         state: Option<PciConfigurationState>,
557     ) -> Self {
558         let (
559             registers,
560             writable_bits,
561             bars,
562             rom_bar_addr,
563             rom_bar_size,
564             rom_bar_used,
565             last_capability,
566             msix_cap_reg_idx,
567         ) = if let Some(state) = state {
568             (
569                 state.registers.try_into().unwrap(),
570                 state.writable_bits.try_into().unwrap(),
571                 state.bars.try_into().unwrap(),
572                 state.rom_bar_addr,
573                 state.rom_bar_size,
574                 state.rom_bar_used,
575                 state.last_capability,
576                 state.msix_cap_reg_idx,
577             )
578         } else {
579             let mut registers = [0u32; NUM_CONFIGURATION_REGISTERS];
580             let mut writable_bits = [0u32; NUM_CONFIGURATION_REGISTERS];
581             registers[0] = u32::from(device_id) << 16 | u32::from(vendor_id);
582             // TODO(dverkamp): Status should be write-1-to-clear
583             writable_bits[1] = 0x0000_ffff; // Status (r/o), command (r/w)
584             let pi = if let Some(pi) = programming_interface {
585                 pi.get_register_value()
586             } else {
587                 0
588             };
589             registers[2] = u32::from(class_code.get_register_value()) << 24
590                 | u32::from(subclass.get_register_value()) << 16
591                 | u32::from(pi) << 8
592                 | u32::from(revision_id);
593             writable_bits[3] = 0x0000_00ff; // Cacheline size (r/w)
594             match header_type {
595                 PciHeaderType::Device => {
596                     registers[3] = 0x0000_0000; // Header type 0 (device)
597                     writable_bits[15] = 0x0000_00ff; // Interrupt line (r/w)
598                 }
599                 PciHeaderType::Bridge => {
600                     registers[3] = 0x0001_0000; // Header type 1 (bridge)
601                     writable_bits[9] = 0xfff0_fff0; // Memory base and limit
602                     writable_bits[15] = 0xffff_00ff; // Bridge control (r/w), interrupt line (r/w)
603                 }
604             };
605             registers[11] = u32::from(subsystem_id) << 16 | u32::from(subsystem_vendor_id);
606 
607             (
608                 registers,
609                 writable_bits,
610                 [PciBar::default(); NUM_BAR_REGS],
611                 0,
612                 0,
613                 false,
614                 None,
615                 None,
616             )
617         };
618 
619         PciConfiguration {
620             registers,
621             writable_bits,
622             bars,
623             rom_bar_addr,
624             rom_bar_size,
625             rom_bar_used,
626             last_capability,
627             msix_cap_reg_idx,
628             msix_config,
629         }
630     }
631 
632     fn state(&self) -> PciConfigurationState {
633         PciConfigurationState {
634             registers: self.registers.to_vec(),
635             writable_bits: self.writable_bits.to_vec(),
636             bars: self.bars.to_vec(),
637             rom_bar_addr: self.rom_bar_addr,
638             rom_bar_size: self.rom_bar_size,
639             rom_bar_used: self.rom_bar_used,
640             last_capability: self.last_capability,
641             msix_cap_reg_idx: self.msix_cap_reg_idx,
642         }
643     }
644 
645     /// Reads a 32bit register from `reg_idx` in the register map.
646     pub fn read_reg(&self, reg_idx: usize) -> u32 {
647         *(self.registers.get(reg_idx).unwrap_or(&0xffff_ffff))
648     }
649 
650     /// Writes a 32bit register to `reg_idx` in the register map.
651     pub fn write_reg(&mut self, reg_idx: usize, value: u32) {
652         let mut mask = self.writable_bits[reg_idx];
653 
654         if (BAR0_REG..BAR0_REG + NUM_BAR_REGS).contains(&reg_idx) {
655             // Handle very specific case where the BAR is being written with
656             // all 1's to retrieve the BAR size during next BAR reading.
657             if value == 0xffff_ffff {
658                 mask &= self.bars[reg_idx - 4].size;
659             }
660         } else if reg_idx == ROM_BAR_REG {
661             // Handle very specific case where the BAR is being written with
662             // all 1's on bits 31-11 to retrieve the BAR size during next BAR
663             // reading.
664             if value & ROM_BAR_ADDR_MASK == ROM_BAR_ADDR_MASK {
665                 mask &= self.rom_bar_size;
666             }
667         }
668 
669         if let Some(r) = self.registers.get_mut(reg_idx) {
670             *r = (*r & !self.writable_bits[reg_idx]) | (value & mask);
671         } else {
672             warn!("bad PCI register write {}", reg_idx);
673         }
674     }
675 
676     /// Writes a 16bit word to `offset`. `offset` must be 16bit aligned.
677     pub fn write_word(&mut self, offset: usize, value: u16) {
678         let shift = match offset % 4 {
679             0 => 0,
680             2 => 16,
681             _ => {
682                 warn!("bad PCI config write offset {}", offset);
683                 return;
684             }
685         };
686         let reg_idx = offset / 4;
687 
688         if let Some(r) = self.registers.get_mut(reg_idx) {
689             let writable_mask = self.writable_bits[reg_idx];
690             let mask = (0xffffu32 << shift) & writable_mask;
691             let shifted_value = (u32::from(value) << shift) & writable_mask;
692             *r = *r & !mask | shifted_value;
693         } else {
694             warn!("bad PCI config write offset {}", offset);
695         }
696     }
697 
698     /// Writes a byte to `offset`.
699     pub fn write_byte(&mut self, offset: usize, value: u8) {
700         self.write_byte_internal(offset, value, true);
701     }
702 
703     /// Writes a byte to `offset`, optionally enforcing read-only bits.
704     fn write_byte_internal(&mut self, offset: usize, value: u8, apply_writable_mask: bool) {
705         let shift = (offset % 4) * 8;
706         let reg_idx = offset / 4;
707 
708         if let Some(r) = self.registers.get_mut(reg_idx) {
709             let writable_mask = if apply_writable_mask {
710                 self.writable_bits[reg_idx]
711             } else {
712                 0xffff_ffff
713             };
714             let mask = (0xffu32 << shift) & writable_mask;
715             let shifted_value = (u32::from(value) << shift) & writable_mask;
716             *r = *r & !mask | shifted_value;
717         } else {
718             warn!("bad PCI config write offset {}", offset);
719         }
720     }
721 
722     /// Adds a region specified by `config`.  Configures the specified BAR(s) to
723     /// report this region and size to the guest kernel.  Enforces a few constraints
724     /// (i.e, region size must be power of two, register not already used).
725     pub fn add_pci_bar(&mut self, config: &PciBarConfiguration) -> Result<()> {
726         let bar_idx = config.idx;
727         let reg_idx = BAR0_REG + bar_idx;
728 
729         if self.bars[bar_idx].used {
730             return Err(Error::BarInUse(bar_idx));
731         }
732 
733         if config.size.count_ones() != 1 {
734             return Err(Error::BarSizeInvalid(config.size));
735         }
736 
737         if bar_idx >= NUM_BAR_REGS {
738             return Err(Error::BarInvalid(bar_idx));
739         }
740 
741         let end_addr = config
742             .addr
743             .checked_add(config.size - 1)
744             .ok_or(Error::BarAddressInvalid(config.addr, config.size))?;
745         match config.region_type {
746             PciBarRegionType::Memory32BitRegion | PciBarRegionType::IoRegion => {
747                 if end_addr > u64::from(u32::max_value()) {
748                     return Err(Error::BarAddressInvalid(config.addr, config.size));
749                 }
750 
751                 // Encode the BAR size as expected by the software running in
752                 // the guest.
753                 self.bars[bar_idx].size =
754                     encode_32_bits_bar_size(config.size as u32).ok_or(Error::Encode32BarSize)?;
755             }
756             PciBarRegionType::Memory64BitRegion => {
757                 if bar_idx + 1 >= NUM_BAR_REGS {
758                     return Err(Error::BarInvalid64(bar_idx));
759                 }
760 
761                 if end_addr > u64::max_value() {
762                     return Err(Error::BarAddressInvalid(config.addr, config.size));
763                 }
764 
765                 if self.bars[bar_idx + 1].used {
766                     return Err(Error::BarInUse64(bar_idx));
767                 }
768 
769                 // Encode the BAR size as expected by the software running in
770                 // the guest.
771                 let (bar_size_hi, bar_size_lo) =
772                     encode_64_bits_bar_size(config.size).ok_or(Error::Encode64BarSize)?;
773 
774                 self.registers[reg_idx + 1] = (config.addr >> 32) as u32;
775                 self.writable_bits[reg_idx + 1] = 0xffff_ffff;
776                 self.bars[bar_idx + 1].addr = self.registers[reg_idx + 1];
777                 self.bars[bar_idx].size = bar_size_lo;
778                 self.bars[bar_idx + 1].size = bar_size_hi;
779                 self.bars[bar_idx + 1].used = true;
780             }
781         }
782 
783         let (mask, lower_bits) = match config.region_type {
784             PciBarRegionType::Memory32BitRegion | PciBarRegionType::Memory64BitRegion => (
785                 BAR_MEM_ADDR_MASK,
786                 config.prefetchable as u32 | config.region_type as u32,
787             ),
788             PciBarRegionType::IoRegion => (BAR_IO_ADDR_MASK, config.region_type as u32),
789         };
790 
791         self.registers[reg_idx] = ((config.addr as u32) & mask) | lower_bits;
792         self.writable_bits[reg_idx] = mask;
793         self.bars[bar_idx].addr = self.registers[reg_idx];
794         self.bars[bar_idx].used = true;
795         self.bars[bar_idx].r#type = Some(config.region_type);
796 
797         Ok(())
798     }
799 
800     /// Adds rom expansion BAR.
801     pub fn add_pci_rom_bar(&mut self, config: &PciBarConfiguration, active: u32) -> Result<()> {
802         let bar_idx = config.idx;
803         let reg_idx = ROM_BAR_REG;
804 
805         if self.rom_bar_used {
806             return Err(Error::RomBarInUse(bar_idx));
807         }
808 
809         if config.size.count_ones() != 1 {
810             return Err(Error::RomBarSizeInvalid(config.size));
811         }
812 
813         if bar_idx != ROM_BAR_IDX {
814             return Err(Error::RomBarInvalid(bar_idx));
815         }
816 
817         let end_addr = config
818             .addr
819             .checked_add(config.size - 1)
820             .ok_or(Error::RomBarAddressInvalid(config.addr, config.size))?;
821 
822         if end_addr > u64::from(u32::max_value()) {
823             return Err(Error::RomBarAddressInvalid(config.addr, config.size));
824         }
825 
826         self.registers[reg_idx] = (config.addr as u32) | active;
827         self.writable_bits[reg_idx] = ROM_BAR_ADDR_MASK;
828         self.rom_bar_addr = self.registers[reg_idx];
829         self.rom_bar_size =
830             encode_32_bits_bar_size(config.size as u32).ok_or(Error::Encode32BarSize)?;
831         self.rom_bar_used = true;
832 
833         Ok(())
834     }
835 
836     /// Returns the address of the given BAR region.
837     pub fn get_bar_addr(&self, bar_num: usize) -> u64 {
838         let bar_idx = BAR0_REG + bar_num;
839 
840         let mut addr = u64::from(self.bars[bar_num].addr & self.writable_bits[bar_idx]);
841 
842         if let Some(bar_type) = self.bars[bar_num].r#type {
843             if bar_type == PciBarRegionType::Memory64BitRegion {
844                 addr |= u64::from(self.bars[bar_num + 1].addr) << 32;
845             }
846         }
847 
848         addr
849     }
850 
851     /// Configures the IRQ line and pin used by this device.
852     pub fn set_irq(&mut self, line: u8, pin: PciInterruptPin) {
853         // `pin` is 1-based in the pci config space.
854         let pin_idx = (pin as u32) + 1;
855         self.registers[INTERRUPT_LINE_PIN_REG] = (self.registers[INTERRUPT_LINE_PIN_REG]
856             & 0xffff_0000)
857             | (pin_idx << 8)
858             | u32::from(line);
859     }
860 
861     /// Adds the capability `cap_data` to the list of capabilities.
862     /// `cap_data` should include the two-byte PCI capability header (type, next),
863     /// but not populate it. Correct values will be generated automatically based
864     /// on `cap_data.id()`.
865     pub fn add_capability(&mut self, cap_data: &dyn PciCapability) -> Result<usize> {
866         let total_len = cap_data.bytes().len();
867         // Check that the length is valid.
868         if cap_data.bytes().is_empty() {
869             return Err(Error::CapabilityEmpty);
870         }
871         let (cap_offset, tail_offset) = match self.last_capability {
872             Some((offset, len)) => (Self::next_dword(offset, len), offset + 1),
873             None => (FIRST_CAPABILITY_OFFSET, CAPABILITY_LIST_HEAD_OFFSET),
874         };
875         let end_offset = cap_offset
876             .checked_add(total_len)
877             .ok_or(Error::CapabilitySpaceFull(total_len))?;
878         if end_offset > CAPABILITY_MAX_OFFSET {
879             return Err(Error::CapabilitySpaceFull(total_len));
880         }
881         self.registers[STATUS_REG] |= STATUS_REG_CAPABILITIES_USED_MASK;
882         self.write_byte_internal(tail_offset, cap_offset as u8, false);
883         self.write_byte_internal(cap_offset, cap_data.id() as u8, false);
884         self.write_byte_internal(cap_offset + 1, 0, false); // Next pointer.
885         for (i, byte) in cap_data.bytes().iter().enumerate() {
886             self.write_byte_internal(cap_offset + i + 2, *byte, false);
887         }
888         self.last_capability = Some((cap_offset, total_len));
889 
890         match cap_data.id() {
891             PciCapabilityId::MessageSignalledInterrupts => {
892                 self.writable_bits[cap_offset / 4] = MSI_CAPABILITY_REGISTER_MASK;
893             }
894             PciCapabilityId::MsiX => {
895                 self.msix_cap_reg_idx = Some(cap_offset / 4);
896                 self.writable_bits[self.msix_cap_reg_idx.unwrap()] = MSIX_CAPABILITY_REGISTER_MASK;
897             }
898             _ => {}
899         }
900 
901         Ok(cap_offset)
902     }
903 
904     // Find the next aligned offset after the one given.
905     fn next_dword(offset: usize, len: usize) -> usize {
906         let next = offset + len;
907         (next + 3) & !3
908     }
909 
910     pub fn write_config_register(&mut self, reg_idx: usize, offset: u64, data: &[u8]) {
911         if offset as usize + data.len() > 4 {
912             return;
913         }
914 
915         // Handle potential write to MSI-X message control register
916         if let Some(msix_cap_reg_idx) = self.msix_cap_reg_idx {
917             if let Some(msix_config) = &self.msix_config {
918                 if msix_cap_reg_idx == reg_idx && offset == 2 && data.len() == 2 {
919                     msix_config
920                         .lock()
921                         .unwrap()
922                         .set_msg_ctl(LittleEndian::read_u16(data));
923                 } else if msix_cap_reg_idx == reg_idx && offset == 0 && data.len() == 4 {
924                     msix_config
925                         .lock()
926                         .unwrap()
927                         .set_msg_ctl((LittleEndian::read_u32(data) >> 16) as u16);
928                 }
929             }
930         }
931 
932         match data.len() {
933             1 => self.write_byte(reg_idx * 4 + offset as usize, data[0]),
934             2 => self.write_word(
935                 reg_idx * 4 + offset as usize,
936                 u16::from(data[0]) | u16::from(data[1]) << 8,
937             ),
938             4 => self.write_reg(reg_idx, LittleEndian::read_u32(data)),
939             _ => (),
940         }
941     }
942 
943     pub fn read_config_register(&self, reg_idx: usize) -> u32 {
944         self.read_reg(reg_idx)
945     }
946 
947     pub fn detect_bar_reprogramming(
948         &mut self,
949         reg_idx: usize,
950         data: &[u8],
951     ) -> Option<BarReprogrammingParams> {
952         if data.len() != 4 {
953             return None;
954         }
955 
956         let value = LittleEndian::read_u32(data);
957 
958         let mask = self.writable_bits[reg_idx];
959         if (BAR0_REG..BAR0_REG + NUM_BAR_REGS).contains(&reg_idx) {
960             // Ignore the case where the BAR size is being asked for.
961             if value == 0xffff_ffff {
962                 return None;
963             }
964 
965             let bar_idx = reg_idx - 4;
966             // Handle special case where the address being written is
967             // different from the address initially provided. This is a
968             // BAR reprogramming case which needs to be properly caught.
969             if let Some(bar_type) = self.bars[bar_idx].r#type {
970                 // In case of 64 bits memory BAR, we don't do anything until
971                 // the upper BAR is modified, otherwise we would be moving the
972                 // BAR to a wrong location in memory.
973                 if bar_type == PciBarRegionType::Memory64BitRegion {
974                     return None;
975                 }
976 
977                 // Ignore the case where the value is unchanged.
978                 if (value & mask) == (self.bars[bar_idx].addr & mask) {
979                     return None;
980                 }
981 
982                 info!(
983                     "Detected BAR reprogramming: (BAR {}) 0x{:x}->0x{:x}",
984                     reg_idx, self.registers[reg_idx], value
985                 );
986                 let old_base = u64::from(self.bars[bar_idx].addr & mask);
987                 let new_base = u64::from(value & mask);
988                 let len = u64::from(
989                     decode_32_bits_bar_size(self.bars[bar_idx].size)
990                         .ok_or(Error::Decode32BarSize)
991                         .unwrap(),
992                 );
993                 let region_type = bar_type;
994 
995                 self.bars[bar_idx].addr = value;
996 
997                 return Some(BarReprogrammingParams {
998                     old_base,
999                     new_base,
1000                     len,
1001                     region_type,
1002                 });
1003             } else if (reg_idx > BAR0_REG)
1004                 && ((self.registers[reg_idx - 1] & self.writable_bits[reg_idx - 1])
1005                     != (self.bars[bar_idx - 1].addr & self.writable_bits[reg_idx - 1])
1006                     || (value & mask) != (self.bars[bar_idx].addr & mask))
1007             {
1008                 info!(
1009                     "Detected BAR reprogramming: (BAR {}) 0x{:x}->0x{:x}",
1010                     reg_idx, self.registers[reg_idx], value
1011                 );
1012                 let old_base = u64::from(self.bars[bar_idx].addr & mask) << 32
1013                     | u64::from(self.bars[bar_idx - 1].addr & self.writable_bits[reg_idx - 1]);
1014                 let new_base = u64::from(value & mask) << 32
1015                     | u64::from(self.registers[reg_idx - 1] & self.writable_bits[reg_idx - 1]);
1016                 let len =
1017                     decode_64_bits_bar_size(self.bars[bar_idx].size, self.bars[bar_idx - 1].size)
1018                         .ok_or(Error::Decode64BarSize)
1019                         .unwrap();
1020                 let region_type = PciBarRegionType::Memory64BitRegion;
1021 
1022                 self.bars[bar_idx].addr = value;
1023                 self.bars[bar_idx - 1].addr = self.registers[reg_idx - 1];
1024 
1025                 return Some(BarReprogrammingParams {
1026                     old_base,
1027                     new_base,
1028                     len,
1029                     region_type,
1030                 });
1031             }
1032         } else if reg_idx == ROM_BAR_REG && (value & mask) != (self.rom_bar_addr & mask) {
1033             // Ignore the case where the BAR size is being asked for.
1034             if value & ROM_BAR_ADDR_MASK == ROM_BAR_ADDR_MASK {
1035                 return None;
1036             }
1037 
1038             info!(
1039                 "Detected ROM BAR reprogramming: (BAR {}) 0x{:x}->0x{:x}",
1040                 reg_idx, self.registers[reg_idx], value
1041             );
1042             let old_base = u64::from(self.rom_bar_addr & mask);
1043             let new_base = u64::from(value & mask);
1044             let len = u64::from(
1045                 decode_32_bits_bar_size(self.rom_bar_size)
1046                     .ok_or(Error::Decode32BarSize)
1047                     .unwrap(),
1048             );
1049             let region_type = PciBarRegionType::Memory32BitRegion;
1050 
1051             self.rom_bar_addr = value;
1052 
1053             return Some(BarReprogrammingParams {
1054                 old_base,
1055                 new_base,
1056                 len,
1057                 region_type,
1058             });
1059         }
1060 
1061         None
1062     }
1063 }
1064 
1065 impl Pausable for PciConfiguration {}
1066 
1067 impl Snapshottable for PciConfiguration {
1068     fn id(&self) -> String {
1069         String::from(PCI_CONFIGURATION_ID)
1070     }
1071 
1072     fn snapshot(&mut self) -> std::result::Result<Snapshot, MigratableError> {
1073         Snapshot::new_from_versioned_state(&self.state())
1074     }
1075 }
1076 
1077 impl Default for PciBarConfiguration {
1078     fn default() -> Self {
1079         PciBarConfiguration {
1080             idx: 0,
1081             addr: 0,
1082             size: 0,
1083             region_type: PciBarRegionType::Memory64BitRegion,
1084             prefetchable: PciBarPrefetchable::NotPrefetchable,
1085         }
1086     }
1087 }
1088 
1089 impl PciBarConfiguration {
1090     pub fn new(
1091         idx: usize,
1092         size: u64,
1093         region_type: PciBarRegionType,
1094         prefetchable: PciBarPrefetchable,
1095     ) -> Self {
1096         PciBarConfiguration {
1097             idx,
1098             addr: 0,
1099             size,
1100             region_type,
1101             prefetchable,
1102         }
1103     }
1104 
1105     #[must_use]
1106     pub fn set_index(mut self, idx: usize) -> Self {
1107         self.idx = idx;
1108         self
1109     }
1110 
1111     #[must_use]
1112     pub fn set_address(mut self, addr: u64) -> Self {
1113         self.addr = addr;
1114         self
1115     }
1116 
1117     #[must_use]
1118     pub fn set_size(mut self, size: u64) -> Self {
1119         self.size = size;
1120         self
1121     }
1122 
1123     #[must_use]
1124     pub fn set_region_type(mut self, region_type: PciBarRegionType) -> Self {
1125         self.region_type = region_type;
1126         self
1127     }
1128 
1129     #[must_use]
1130     pub fn set_prefetchable(mut self, prefetchable: PciBarPrefetchable) -> Self {
1131         self.prefetchable = prefetchable;
1132         self
1133     }
1134 
1135     pub fn idx(&self) -> usize {
1136         self.idx
1137     }
1138 
1139     pub fn addr(&self) -> u64 {
1140         self.addr
1141     }
1142 
1143     pub fn size(&self) -> u64 {
1144         self.size
1145     }
1146 
1147     pub fn region_type(&self) -> PciBarRegionType {
1148         self.region_type
1149     }
1150 
1151     pub fn prefetchable(&self) -> PciBarPrefetchable {
1152         self.prefetchable
1153     }
1154 }
1155 
1156 #[cfg(test)]
1157 mod tests {
1158     use vm_memory::ByteValued;
1159 
1160     use super::*;
1161 
1162     #[repr(packed)]
1163     #[derive(Clone, Copy, Default)]
1164     #[allow(dead_code)]
1165     struct TestCap {
1166         len: u8,
1167         foo: u8,
1168     }
1169 
1170     // SAFETY: All members are simple numbers and any value is valid.
1171     unsafe impl ByteValued for TestCap {}
1172 
1173     impl PciCapability for TestCap {
1174         fn bytes(&self) -> &[u8] {
1175             self.as_slice()
1176         }
1177 
1178         fn id(&self) -> PciCapabilityId {
1179             PciCapabilityId::VendorSpecific
1180         }
1181     }
1182 
1183     #[test]
1184     fn add_capability() {
1185         let mut cfg = PciConfiguration::new(
1186             0x1234,
1187             0x5678,
1188             0x1,
1189             PciClassCode::MultimediaController,
1190             &PciMultimediaSubclass::AudioController,
1191             None,
1192             PciHeaderType::Device,
1193             0xABCD,
1194             0x2468,
1195             None,
1196             None,
1197         );
1198 
1199         // Add two capabilities with different contents.
1200         let cap1 = TestCap { len: 4, foo: 0xAA };
1201         let cap1_offset = cfg.add_capability(&cap1).unwrap();
1202         assert_eq!(cap1_offset % 4, 0);
1203 
1204         let cap2 = TestCap {
1205             len: 0x04,
1206             foo: 0x55,
1207         };
1208         let cap2_offset = cfg.add_capability(&cap2).unwrap();
1209         assert_eq!(cap2_offset % 4, 0);
1210 
1211         // The capability list head should be pointing to cap1.
1212         let cap_ptr = cfg.read_reg(CAPABILITY_LIST_HEAD_OFFSET / 4) & 0xFF;
1213         assert_eq!(cap1_offset, cap_ptr as usize);
1214 
1215         // Verify the contents of the capabilities.
1216         let cap1_data = cfg.read_reg(cap1_offset / 4);
1217         assert_eq!(cap1_data & 0xFF, 0x09); // capability ID
1218         assert_eq!((cap1_data >> 8) & 0xFF, cap2_offset as u32); // next capability pointer
1219         assert_eq!((cap1_data >> 16) & 0xFF, 0x04); // cap1.len
1220         assert_eq!((cap1_data >> 24) & 0xFF, 0xAA); // cap1.foo
1221 
1222         let cap2_data = cfg.read_reg(cap2_offset / 4);
1223         assert_eq!(cap2_data & 0xFF, 0x09); // capability ID
1224         assert_eq!((cap2_data >> 8) & 0xFF, 0x00); // next capability pointer
1225         assert_eq!((cap2_data >> 16) & 0xFF, 0x04); // cap2.len
1226         assert_eq!((cap2_data >> 24) & 0xFF, 0x55); // cap2.foo
1227     }
1228 
1229     #[derive(Copy, Clone)]
1230     enum TestPi {
1231         Test = 0x5a,
1232     }
1233 
1234     impl PciProgrammingInterface for TestPi {
1235         fn get_register_value(&self) -> u8 {
1236             *self as u8
1237         }
1238     }
1239 
1240     #[test]
1241     fn class_code() {
1242         let cfg = PciConfiguration::new(
1243             0x1234,
1244             0x5678,
1245             0x1,
1246             PciClassCode::MultimediaController,
1247             &PciMultimediaSubclass::AudioController,
1248             Some(&TestPi::Test),
1249             PciHeaderType::Device,
1250             0xABCD,
1251             0x2468,
1252             None,
1253             None,
1254         );
1255 
1256         let class_reg = cfg.read_reg(2);
1257         let class_code = (class_reg >> 24) & 0xFF;
1258         let subclass = (class_reg >> 16) & 0xFF;
1259         let prog_if = (class_reg >> 8) & 0xFF;
1260         assert_eq!(class_code, 0x04);
1261         assert_eq!(subclass, 0x01);
1262         assert_eq!(prog_if, 0x5a);
1263     }
1264 }
1265