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