xref: /aosp_15_r20/external/crosvm/devices/src/pci/pci_configuration.rs (revision bb4ee6a4ae7042d18b07a98463b9c8b875e44b39)
1 // Copyright 2018 The ChromiumOS Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 use std::collections::BTreeMap;
6 use std::convert::TryFrom;
7 use std::convert::TryInto;
8 use std::sync::Arc;
9 
10 use anyhow::bail;
11 use anyhow::Context;
12 use base::custom_serde::deserialize_seq_to_arr;
13 use base::custom_serde::serialize_arr;
14 use base::error;
15 use base::warn;
16 use base::MemoryMapping;
17 use base::MemoryMappingBuilder;
18 use base::SharedMemory;
19 use downcast_rs::impl_downcast;
20 use downcast_rs::Downcast;
21 use remain::sorted;
22 use serde::Deserialize;
23 use serde::Serialize;
24 use sync::Mutex;
25 use thiserror::Error;
26 
27 use crate::pci::PciInterruptPin;
28 
29 // The number of 32bit registers in the config space, 256 bytes.
30 const NUM_CONFIGURATION_REGISTERS: usize = 64;
31 
32 pub const PCI_ID_REG: usize = 0;
33 pub const COMMAND_REG: usize = 1;
34 pub const COMMAND_REG_IO_SPACE_MASK: u32 = 0x0000_0001;
35 pub const COMMAND_REG_MEMORY_SPACE_MASK: u32 = 0x0000_0002;
36 const STATUS_REG: usize = 1;
37 pub const STATUS_REG_CAPABILITIES_USED_MASK: u32 = 0x0010_0000;
38 #[allow(dead_code)]
39 #[cfg(any(target_os = "android", target_os = "linux"))]
40 pub const CLASS_REG: usize = 2;
41 pub const HEADER_TYPE_REG: usize = 3;
42 pub const HEADER_TYPE_REG_OFFSET: usize = 2;
43 pub const HEADER_TYPE_MULTIFUNCTION_MASK: u8 = 0x80;
44 pub const BAR0_REG: usize = 4;
45 const BAR_IO_ADDR_MASK: u32 = 0xffff_fffc;
46 const BAR_IO_MIN_SIZE: u64 = 4;
47 const BAR_MEM_ADDR_MASK: u32 = 0xffff_fff0;
48 const BAR_MEM_MIN_SIZE: u64 = 16;
49 const BAR_ROM_MIN_SIZE: u64 = 2048;
50 pub const NUM_BAR_REGS: usize = 7; // 6 normal BARs + expansion ROM BAR.
51 pub const ROM_BAR_IDX: PciBarIndex = 6;
52 pub const ROM_BAR_REG: usize = 12;
53 pub const CAPABILITY_LIST_HEAD_OFFSET: usize = 0x34;
54 #[cfg(any(target_os = "android", target_os = "linux"))]
55 pub const PCI_CAP_NEXT_POINTER: usize = 0x1;
56 const FIRST_CAPABILITY_OFFSET: usize = 0x40;
57 pub const CAPABILITY_MAX_OFFSET: usize = 255;
58 
59 const INTERRUPT_LINE_PIN_REG: usize = 15;
60 
61 /// Represents the types of PCI headers allowed in the configuration registers.
62 #[allow(dead_code)]
63 #[derive(Copy, Clone)]
64 pub enum PciHeaderType {
65     Device,
66     Bridge,
67 }
68 
69 /// Classes of PCI nodes.
70 #[allow(dead_code)]
71 #[derive(Copy, Clone, Debug, enumn::N, Serialize, Deserialize, PartialEq, Eq)]
72 pub enum PciClassCode {
73     TooOld,
74     MassStorage,
75     NetworkController,
76     DisplayController,
77     MultimediaController,
78     MemoryController,
79     BridgeDevice,
80     SimpleCommunicationController,
81     BaseSystemPeripheral,
82     InputDevice,
83     DockingStation,
84     Processor,
85     SerialBusController,
86     WirelessController,
87     IntelligentIoController,
88     SatelliteCommunicationController,
89     EncryptionController,
90     DataAcquisitionSignalProcessing,
91     ProcessingAccelerator,
92     NonEssentialInstrumentation,
93     Other = 0xff,
94 }
95 
96 impl PciClassCode {
get_register_value(&self) -> u897     pub fn get_register_value(&self) -> u8 {
98         *self as u8
99     }
100 }
101 
102 #[sorted]
103 #[derive(Error, Debug)]
104 pub enum PciClassCodeParseError {
105     #[error("Unknown class code")]
106     Unknown,
107 }
108 
109 impl TryFrom<u8> for PciClassCode {
110     type Error = PciClassCodeParseError;
try_from(v: u8) -> std::result::Result<PciClassCode, PciClassCodeParseError>111     fn try_from(v: u8) -> std::result::Result<PciClassCode, PciClassCodeParseError> {
112         match PciClassCode::n(v) {
113             Some(class) => Ok(class),
114             None => Err(PciClassCodeParseError::Unknown),
115         }
116     }
117 }
118 
119 /// A PCI sublcass. Each class in `PciClassCode` can specify a unique set of subclasses. This trait
120 /// is implemented by each subclass. It allows use of a trait object to generate configurations.
121 pub trait PciSubclass {
122     /// Convert this subclass to the value used in the PCI specification.
get_register_value(&self) -> u8123     fn get_register_value(&self) -> u8;
124 }
125 
126 /// Subclasses of the MassStorage class.
127 #[allow(dead_code)]
128 #[derive(Copy, Clone)]
129 pub enum PciMassStorageSubclass {
130     Scsi = 0x00,
131     NonVolatileMemory = 0x08,
132     Other = 0x80,
133 }
134 
135 impl PciSubclass for PciMassStorageSubclass {
get_register_value(&self) -> u8136     fn get_register_value(&self) -> u8 {
137         *self as u8
138     }
139 }
140 
141 /// Subclasses of the NetworkController class.
142 #[allow(dead_code)]
143 #[derive(Copy, Clone)]
144 pub enum PciNetworkControllerSubclass {
145     Other = 0x80,
146 }
147 
148 impl PciSubclass for PciNetworkControllerSubclass {
get_register_value(&self) -> u8149     fn get_register_value(&self) -> u8 {
150         *self as u8
151     }
152 }
153 
154 /// Subclasses of the DisplayController class.
155 #[allow(dead_code)]
156 #[derive(Copy, Clone)]
157 pub enum PciDisplaySubclass {
158     VgaCompatibleController = 0x00,
159     XgaCompatibleController = 0x01,
160     ThreeDController = 0x02,
161     Other = 0x80,
162 }
163 
164 impl PciSubclass for PciDisplaySubclass {
get_register_value(&self) -> u8165     fn get_register_value(&self) -> u8 {
166         *self as u8
167     }
168 }
169 
170 /// Subclasses of the MultimediaController class.
171 #[allow(dead_code)]
172 #[derive(Copy, Clone)]
173 pub enum PciMultimediaSubclass {
174     VideoController = 0x00,
175     AudioController = 0x01,
176     TelephonyDevice = 0x02,
177     AudioDevice = 0x03,
178     Other = 0x80,
179 }
180 
181 impl PciSubclass for PciMultimediaSubclass {
get_register_value(&self) -> u8182     fn get_register_value(&self) -> u8 {
183         *self as u8
184     }
185 }
186 
187 /// Subclasses of the BridgeDevice
188 #[allow(dead_code)]
189 #[derive(Copy, Clone)]
190 pub enum PciBridgeSubclass {
191     HostBridge = 0x00,
192     IsaBridge = 0x01,
193     EisaBridge = 0x02,
194     McaBridge = 0x03,
195     PciToPciBridge = 0x04,
196     PcmciaBridge = 0x05,
197     NuBusBridge = 0x06,
198     CardBusBridge = 0x07,
199     RaceWayBridge = 0x08,
200     PciToPciSemiTransparentBridge = 0x09,
201     InfiniBrandToPciHostBridge = 0x0a,
202     OtherBridgeDevice = 0x80,
203 }
204 
205 impl PciSubclass for PciBridgeSubclass {
get_register_value(&self) -> u8206     fn get_register_value(&self) -> u8 {
207         *self as u8
208     }
209 }
210 
211 /// Subclasses of the SimpleCommunicationController class.
212 #[allow(dead_code)]
213 #[derive(Copy, Clone)]
214 pub enum PciSimpleCommunicationControllerSubclass {
215     Other = 0x80,
216 }
217 
218 impl PciSubclass for PciSimpleCommunicationControllerSubclass {
get_register_value(&self) -> u8219     fn get_register_value(&self) -> u8 {
220         *self as u8
221     }
222 }
223 
224 /// Subclasses of the BaseSystemPeripheral class.
225 #[allow(dead_code)]
226 #[derive(Copy, Clone)]
227 pub enum PciBaseSystemPeripheralSubclass {
228     Iommu = 0x06,
229     Other = 0x80,
230 }
231 
232 impl PciSubclass for PciBaseSystemPeripheralSubclass {
get_register_value(&self) -> u8233     fn get_register_value(&self) -> u8 {
234         *self as u8
235     }
236 }
237 
238 /// Subclasses of the InputDevice class.
239 #[allow(dead_code)]
240 #[derive(Copy, Clone)]
241 pub enum PciInputDeviceSubclass {
242     Other = 0x80,
243 }
244 
245 impl PciSubclass for PciInputDeviceSubclass {
get_register_value(&self) -> u8246     fn get_register_value(&self) -> u8 {
247         *self as u8
248     }
249 }
250 
251 /// Subclass of the SerialBus
252 #[allow(dead_code)]
253 #[derive(Copy, Clone)]
254 pub enum PciSerialBusSubClass {
255     Firewire = 0x00,
256     AccessBus = 0x01,
257     Ssa = 0x02,
258     Usb = 0x03,
259 }
260 
261 impl PciSubclass for PciSerialBusSubClass {
get_register_value(&self) -> u8262     fn get_register_value(&self) -> u8 {
263         *self as u8
264     }
265 }
266 
267 /// Subclasses of the WirelessController class.
268 #[allow(dead_code)]
269 #[derive(Copy, Clone)]
270 pub enum PciWirelessControllerSubclass {
271     Other = 0x80,
272 }
273 
274 impl PciSubclass for PciWirelessControllerSubclass {
get_register_value(&self) -> u8275     fn get_register_value(&self) -> u8 {
276         *self as u8
277     }
278 }
279 
280 /// Subclasses for PciClassCode Other.
281 #[allow(dead_code)]
282 #[derive(Copy, Clone)]
283 #[repr(u8)]
284 pub enum PciOtherSubclass {
285     Other = 0xff,
286 }
287 
288 impl PciSubclass for PciOtherSubclass {
get_register_value(&self) -> u8289     fn get_register_value(&self) -> u8 {
290         *self as u8
291     }
292 }
293 
294 /// A PCI class programming interface. Each combination of `PciClassCode` and
295 /// `PciSubclass` can specify a set of register-level programming interfaces.
296 /// This trait is implemented by each programming interface.
297 /// It allows use of a trait object to generate configurations.
298 pub trait PciProgrammingInterface {
299     /// Convert this programming interface to the value used in the PCI specification.
get_register_value(&self) -> u8300     fn get_register_value(&self) -> u8;
301 }
302 
303 /// Types of PCI capabilities.
304 pub enum PciCapabilityID {
305     ListID = 0,
306     PowerManagement = 0x01,
307     AcceleratedGraphicsPort = 0x02,
308     VitalProductData = 0x03,
309     SlotIdentification = 0x04,
310     MessageSignalledInterrupts = 0x05,
311     CompactPciHotSwap = 0x06,
312     Pcix = 0x07,
313     HyperTransport = 0x08,
314     VendorSpecific = 0x09,
315     Debugport = 0x0A,
316     CompactPciCentralResourceControl = 0x0B,
317     PciStandardHotPlugController = 0x0C,
318     BridgeSubsystemVendorDeviceID = 0x0D,
319     AgpTargetPciPciBridge = 0x0E,
320     SecureDevice = 0x0F,
321     PciExpress = 0x10,
322     Msix = 0x11,
323     SataDataIndexConf = 0x12,
324     PciAdvancedFeatures = 0x13,
325     PciEnhancedAllocation = 0x14,
326 }
327 
328 /// A PCI capability list. Devices can optionally specify capabilities in their configuration space.
329 pub trait PciCapability {
bytes(&self) -> &[u8]330     fn bytes(&self) -> &[u8];
id(&self) -> PciCapabilityID331     fn id(&self) -> PciCapabilityID;
writable_bits(&self) -> Vec<u32>332     fn writable_bits(&self) -> Vec<u32>;
333 }
334 
335 pub trait PciCapConfigWriteResult: Downcast {}
336 impl_downcast!(PciCapConfigWriteResult);
337 
338 /// A trait for implementing complex PCI capabilities.
339 pub trait PciCapConfig: Send {
340     /// Reads a 32bit register from the capability. Only the bits set in the
341     /// read mask will be used, while the rest of the bits will be taken from
342     /// the `PciConfiguration`'s register data.
343     /// `reg_idx` - index into the capability
read_reg(&self, reg_idx: usize) -> u32344     fn read_reg(&self, reg_idx: usize) -> u32;
345 
346     /// Returns the read mask used by `read_reg`.
read_mask(&self) -> &'static [u32]347     fn read_mask(&self) -> &'static [u32];
348 
349     /// Writes data to the capability.
350     /// `reg_idx` - index into PciConfiguration.registers.
351     /// `offset`  - PciConfiguration.registers is in unit of DWord, offset define byte
352     ///             offset in the DWord.
353     /// `data`    - The data to write.
write_reg( &mut self, reg_idx: usize, offset: u64, data: &[u8], ) -> Option<Box<dyn PciCapConfigWriteResult>>354     fn write_reg(
355         &mut self,
356         reg_idx: usize,
357         offset: u64,
358         data: &[u8],
359     ) -> Option<Box<dyn PciCapConfigWriteResult>>;
360 
361     /// Used to pass the mmio region for the capability to the implementation.
362     /// If any external events update the capability's registers, then
363     /// `PciCapMapping.set_reg` must be called to make the changes visible
364     /// to the guest.
set_cap_mapping(&mut self, _mapping: PciCapMapping)365     fn set_cap_mapping(&mut self, _mapping: PciCapMapping) {}
366 
num_regs(&self) -> usize367     fn num_regs(&self) -> usize {
368         self.read_mask().len()
369     }
370 }
371 
372 /// Contains the configuration space of a PCI node.
373 /// See the [specification](https://en.wikipedia.org/wiki/PCI_configuration_space).
374 /// The configuration space is accessed with DWORD reads and writes from the guest.
375 pub struct PciConfiguration {
376     registers: [u32; NUM_CONFIGURATION_REGISTERS],
377     writable_bits: [u32; NUM_CONFIGURATION_REGISTERS], // writable bits for each register.
378     bar_used: [bool; NUM_BAR_REGS],
379     bar_configs: [Option<PciBarConfiguration>; NUM_BAR_REGS],
380     // Contains the byte offset and size of the last capability.
381     last_capability: Option<(usize, usize)>,
382     capability_configs: BTreeMap<usize, Box<dyn PciCapConfig>>,
383     mmio_mapping: Option<(Arc<Mutex<MemoryMapping>>, usize)>,
384 }
385 
386 #[derive(Serialize, Deserialize)]
387 pub struct PciConfigurationSerialized {
388     #[serde(
389         serialize_with = "serialize_arr",
390         deserialize_with = "deserialize_seq_to_arr"
391     )]
392     registers: [u32; NUM_CONFIGURATION_REGISTERS],
393     #[serde(
394         serialize_with = "serialize_arr",
395         deserialize_with = "deserialize_seq_to_arr"
396     )]
397     writable_bits: [u32; NUM_CONFIGURATION_REGISTERS],
398     bar_used: [bool; NUM_BAR_REGS],
399     bar_configs: [Option<PciBarConfiguration>; NUM_BAR_REGS],
400     last_capability: Option<(usize, usize)>,
401 }
402 
403 /// See pci_regs.h in kernel
404 #[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
405 pub enum PciBarRegionType {
406     Memory32BitRegion = 0,
407     IoRegion = 0x01,
408     Memory64BitRegion = 0x04,
409 }
410 
411 #[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
412 pub enum PciBarPrefetchable {
413     NotPrefetchable = 0,
414     Prefetchable = 0x08,
415 }
416 
417 pub type PciBarIndex = usize;
418 
419 #[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
420 pub struct PciBarConfiguration {
421     addr: u64,
422     size: u64,
423     bar_idx: PciBarIndex,
424     region_type: PciBarRegionType,
425     prefetchable: PciBarPrefetchable,
426 }
427 
428 pub struct PciBarIter<'a> {
429     config: &'a PciConfiguration,
430     bar_num: PciBarIndex,
431 }
432 
433 impl<'a> Iterator for PciBarIter<'a> {
434     type Item = PciBarConfiguration;
435 
next(&mut self) -> Option<Self::Item>436     fn next(&mut self) -> Option<Self::Item> {
437         while self.bar_num < NUM_BAR_REGS {
438             let bar_config = self.config.get_bar_configuration(self.bar_num);
439             self.bar_num += 1;
440             if let Some(bar_config) = bar_config {
441                 return Some(bar_config);
442             }
443         }
444 
445         None
446     }
447 }
448 
449 #[sorted]
450 #[derive(Error, Debug, PartialEq, Eq)]
451 pub enum Error {
452     #[error("address {0} size {1} too big")]
453     BarAddressInvalid(u64, u64),
454     #[error("address {0} is not aligned to size {1}")]
455     BarAlignmentInvalid(u64, u64),
456     #[error("bar {0} already used")]
457     BarInUse(PciBarIndex),
458     #[error("64bit bar {0} already used (requires two regs)")]
459     BarInUse64(PciBarIndex),
460     #[error("bar {0} invalid, max {}", NUM_BAR_REGS - 1)]
461     BarInvalid(PciBarIndex),
462     #[error("64bitbar {0} invalid, requires two regs, max {}", ROM_BAR_IDX - 1)]
463     BarInvalid64(PciBarIndex),
464     #[error("expansion rom bar must be a memory region")]
465     BarInvalidRomType,
466     #[error("bar address {0} not a power of two")]
467     BarSizeInvalid(u64),
468     #[error("empty capabilities are invalid")]
469     CapabilityEmpty,
470     #[error("Invalid capability length {0}")]
471     CapabilityLengthInvalid(usize),
472     #[error("capability of size {0} doesn't fit")]
473     CapabilitySpaceFull(usize),
474 }
475 
476 pub type Result<T> = std::result::Result<T, Error>;
477 
478 impl PciConfiguration {
new( vendor_id: u16, device_id: u16, class_code: PciClassCode, subclass: &dyn PciSubclass, programming_interface: Option<&dyn PciProgrammingInterface>, header_type: PciHeaderType, subsystem_vendor_id: u16, subsystem_id: u16, revision_id: u8, ) -> Self479     pub fn new(
480         vendor_id: u16,
481         device_id: u16,
482         class_code: PciClassCode,
483         subclass: &dyn PciSubclass,
484         programming_interface: Option<&dyn PciProgrammingInterface>,
485         header_type: PciHeaderType,
486         subsystem_vendor_id: u16,
487         subsystem_id: u16,
488         revision_id: u8,
489     ) -> Self {
490         let mut registers = [0u32; NUM_CONFIGURATION_REGISTERS];
491         let mut writable_bits = [0u32; NUM_CONFIGURATION_REGISTERS];
492         registers[0] = u32::from(device_id) << 16 | u32::from(vendor_id);
493         // TODO(dverkamp): Status should be write-1-to-clear
494         writable_bits[1] = 0x0000_ffff; // Status (r/o), command (r/w)
495         let pi = if let Some(pi) = programming_interface {
496             pi.get_register_value()
497         } else {
498             0
499         };
500         registers[2] = u32::from(class_code.get_register_value()) << 24
501             | u32::from(subclass.get_register_value()) << 16
502             | u32::from(pi) << 8
503             | u32::from(revision_id);
504         writable_bits[3] = 0x0000_00ff; // Cacheline size (r/w)
505         match header_type {
506             PciHeaderType::Device => {
507                 registers[3] = 0x0000_0000; // Header type 0 (device)
508                 writable_bits[15] = 0x0000_00ff; // Interrupt line (r/w)
509                 registers[11] = u32::from(subsystem_id) << 16 | u32::from(subsystem_vendor_id);
510             }
511             PciHeaderType::Bridge => {
512                 registers[3] = 0x0001_0000; // Header type 1 (bridge)
513                 writable_bits[6] = 0x00ff_ffff; // Primary/secondary/subordinate bus number,
514                                                 // secondary latency timer
515                 registers[7] = 0x0000_00f0; // IO base > IO Limit, no IO address on secondary side at initialize
516                 writable_bits[7] = 0xf900_0000; // IO base and limit, secondary status,
517                 registers[8] = 0x0000_fff0; // mem base > mem Limit, no MMIO address on secondary side at initialize
518                 writable_bits[8] = 0xfff0_fff0; // Memory base and limit
519                 registers[9] = 0x0001_fff1; // pmem base > pmem Limit, no prefetch MMIO address on secondary side at initialize
520                 writable_bits[9] = 0xfff0_fff0; // Prefetchable base and limit
521                 writable_bits[10] = 0xffff_ffff; // Prefetchable base upper 32 bits
522                 writable_bits[11] = 0xffff_ffff; // Prefetchable limit upper 32 bits
523                 writable_bits[15] = 0xffff_00ff; // Bridge control (r/w), interrupt line (r/w)
524             }
525         };
526 
527         PciConfiguration {
528             registers,
529             writable_bits,
530             bar_used: [false; NUM_BAR_REGS],
531             bar_configs: [None; NUM_BAR_REGS],
532             last_capability: None,
533             capability_configs: BTreeMap::new(),
534             mmio_mapping: None,
535         }
536     }
537 
538     /// Reads a 32bit register from `reg_idx` in the register map.
read_reg(&self, reg_idx: usize) -> u32539     pub fn read_reg(&self, reg_idx: usize) -> u32 {
540         let mut data = *(self.registers.get(reg_idx).unwrap_or(&0xffff_ffff));
541         if let Some((idx, cfg)) = self.capability_configs.range(..=reg_idx).last() {
542             if reg_idx < idx + cfg.num_regs() {
543                 let cap_idx = reg_idx - idx;
544                 let mask = cfg.read_mask()[cap_idx];
545                 data = (data & !mask) | (cfg.read_reg(cap_idx) & mask);
546             }
547         }
548         data
549     }
550 
551     /// Writes data to PciConfiguration.registers.
552     /// `reg_idx` - index into PciConfiguration.registers.
553     /// `offset`  - PciConfiguration.registers is in unit of DWord, offset define byte
554     ///             offset in the DWord.
555     /// `data`    - The data to write.
write_reg( &mut self, reg_idx: usize, offset: u64, data: &[u8], ) -> Option<Box<dyn PciCapConfigWriteResult>>556     pub fn write_reg(
557         &mut self,
558         reg_idx: usize,
559         offset: u64,
560         data: &[u8],
561     ) -> Option<Box<dyn PciCapConfigWriteResult>> {
562         let reg_offset = reg_idx * 4 + offset as usize;
563         match data.len() {
564             1 => self.write_byte(reg_offset, data[0]),
565             2 => self.write_word(reg_offset, u16::from_le_bytes(data.try_into().unwrap())),
566             4 => self.write_dword(reg_offset, u32::from_le_bytes(data.try_into().unwrap())),
567             _ => (),
568         }
569         if let Some((idx, cfg)) = self.capability_configs.range_mut(..=reg_idx).last() {
570             if reg_idx < idx + cfg.num_regs() {
571                 let cap_idx = reg_idx - idx;
572                 let ret = cfg.write_reg(cap_idx, offset, data);
573                 let new_val = cfg.read_reg(cap_idx);
574                 let mask = cfg.read_mask()[cap_idx];
575                 self.set_reg(reg_idx, new_val, mask);
576                 return ret;
577             }
578         }
579         None
580     }
581 
582     /// Writes a 32bit dword to `offset`. `offset` must be 32bit aligned.
write_dword(&mut self, offset: usize, value: u32)583     fn write_dword(&mut self, offset: usize, value: u32) {
584         if offset % 4 != 0 {
585             warn!("bad PCI config dword write offset {}", offset);
586             return;
587         }
588         let reg_idx = offset / 4;
589         if reg_idx < NUM_CONFIGURATION_REGISTERS {
590             let old_value = self.registers[reg_idx];
591             let new_value =
592                 (old_value & !self.writable_bits[reg_idx]) | (value & self.writable_bits[reg_idx]);
593             self.do_write(reg_idx, new_value)
594         } else {
595             warn!("bad PCI dword write {}", offset);
596         }
597     }
598 
599     /// Writes a 16bit word to `offset`. `offset` must be 16bit aligned.
write_word(&mut self, offset: usize, value: u16)600     fn write_word(&mut self, offset: usize, value: u16) {
601         let shift = match offset % 4 {
602             0 => 0,
603             2 => 16,
604             _ => {
605                 warn!("bad PCI config word write offset {}", offset);
606                 return;
607             }
608         };
609         let reg_idx = offset / 4;
610 
611         if reg_idx < NUM_CONFIGURATION_REGISTERS {
612             let old_value = self.registers[reg_idx];
613             let writable_mask = self.writable_bits[reg_idx];
614             let mask = (0xffffu32 << shift) & writable_mask;
615             let shifted_value = (u32::from(value) << shift) & writable_mask;
616             let new_value = old_value & !mask | shifted_value;
617             self.do_write(reg_idx, new_value)
618         } else {
619             warn!("bad PCI config word write offset {}", offset);
620         }
621     }
622 
623     /// Writes a byte to `offset`.
write_byte(&mut self, offset: usize, value: u8)624     fn write_byte(&mut self, offset: usize, value: u8) {
625         self.write_byte_internal(offset, value, true);
626     }
627 
628     /// Writes a byte to `offset`, optionally enforcing read-only bits.
write_byte_internal(&mut self, offset: usize, value: u8, apply_writable_mask: bool)629     fn write_byte_internal(&mut self, offset: usize, value: u8, apply_writable_mask: bool) {
630         let shift = (offset % 4) * 8;
631         let reg_idx = offset / 4;
632 
633         if reg_idx < NUM_CONFIGURATION_REGISTERS {
634             let writable_mask = if apply_writable_mask {
635                 self.writable_bits[reg_idx]
636             } else {
637                 0xffff_ffff
638             };
639             let old_value = self.registers[reg_idx];
640             let mask = (0xffu32 << shift) & writable_mask;
641             let shifted_value = (u32::from(value) << shift) & writable_mask;
642             let new_value = old_value & !mask | shifted_value;
643             self.do_write(reg_idx, new_value)
644         } else {
645             warn!("bad PCI config byte write offset {}", offset);
646         }
647     }
648 
649     /// Sets the value of a PciConfiguration register. This should be used when
650     /// device-internal events require changing the configuration space - as such,
651     /// the writable bits masks do not apply.
652     /// `reg_idx` - index into PciConfiguration.registers.
653     /// `data`    - The data to write.
654     /// `mask`    - The mask of which bits to modify.
set_reg(&mut self, reg_idx: usize, data: u32, mask: u32)655     pub fn set_reg(&mut self, reg_idx: usize, data: u32, mask: u32) {
656         if reg_idx >= NUM_CONFIGURATION_REGISTERS {
657             return;
658         }
659         let new_val = (self.registers[reg_idx] & !mask) | (data & mask);
660         self.do_write(reg_idx, new_val);
661     }
662 
663     /// Adds a region specified by `config`.  Configures the specified BAR(s) to
664     /// report this region and size to the guest kernel.  Enforces a few constraints
665     /// (i.e, region size must be power of two, register not already used). Returns 'None' on
666     /// failure all, `Some(BarIndex)` on success.
add_pci_bar(&mut self, config: PciBarConfiguration) -> Result<PciBarIndex>667     pub fn add_pci_bar(&mut self, config: PciBarConfiguration) -> Result<PciBarIndex> {
668         if config.bar_idx >= NUM_BAR_REGS {
669             return Err(Error::BarInvalid(config.bar_idx));
670         }
671 
672         if self.bar_used[config.bar_idx] {
673             return Err(Error::BarInUse(config.bar_idx));
674         }
675 
676         if config.size.count_ones() != 1 {
677             return Err(Error::BarSizeInvalid(config.size));
678         }
679 
680         if config.is_expansion_rom() && config.region_type != PciBarRegionType::Memory32BitRegion {
681             return Err(Error::BarInvalidRomType);
682         }
683 
684         let min_size = if config.is_expansion_rom() {
685             BAR_ROM_MIN_SIZE
686         } else if config.region_type == PciBarRegionType::IoRegion {
687             BAR_IO_MIN_SIZE
688         } else {
689             BAR_MEM_MIN_SIZE
690         };
691 
692         if config.size < min_size {
693             return Err(Error::BarSizeInvalid(config.size));
694         }
695 
696         if config.addr % config.size != 0 {
697             return Err(Error::BarAlignmentInvalid(config.addr, config.size));
698         }
699 
700         let reg_idx = config.reg_index();
701         let end_addr = config
702             .addr
703             .checked_add(config.size)
704             .ok_or(Error::BarAddressInvalid(config.addr, config.size))?;
705         match config.region_type {
706             PciBarRegionType::Memory32BitRegion | PciBarRegionType::IoRegion => {
707                 if end_addr > u64::from(u32::MAX) {
708                     return Err(Error::BarAddressInvalid(config.addr, config.size));
709                 }
710             }
711             PciBarRegionType::Memory64BitRegion => {
712                 // The expansion ROM BAR cannot be used for part of a 64-bit BAR.
713                 if config.bar_idx + 1 >= ROM_BAR_IDX {
714                     return Err(Error::BarInvalid64(config.bar_idx));
715                 }
716 
717                 if self.bar_used[config.bar_idx + 1] {
718                     return Err(Error::BarInUse64(config.bar_idx));
719                 }
720 
721                 self.do_write(reg_idx + 1, (config.addr >> 32) as u32);
722                 self.writable_bits[reg_idx + 1] = !((config.size - 1) >> 32) as u32;
723                 self.bar_used[config.bar_idx + 1] = true;
724             }
725         }
726 
727         let (mask, lower_bits) = match config.region_type {
728             PciBarRegionType::Memory32BitRegion | PciBarRegionType::Memory64BitRegion => {
729                 self.registers[COMMAND_REG] |= COMMAND_REG_MEMORY_SPACE_MASK;
730                 (
731                     BAR_MEM_ADDR_MASK,
732                     config.prefetchable as u32 | config.region_type as u32,
733                 )
734             }
735             PciBarRegionType::IoRegion => {
736                 self.registers[COMMAND_REG] |= COMMAND_REG_IO_SPACE_MASK;
737                 (BAR_IO_ADDR_MASK, config.region_type as u32)
738             }
739         };
740 
741         self.do_write(reg_idx, ((config.addr as u32) & mask) | lower_bits);
742         self.writable_bits[reg_idx] = !(config.size - 1) as u32;
743         if config.is_expansion_rom() {
744             self.writable_bits[reg_idx] |= 1; // Expansion ROM enable bit.
745         }
746         self.bar_used[config.bar_idx] = true;
747         self.bar_configs[config.bar_idx] = Some(config);
748         Ok(config.bar_idx)
749     }
750 
751     /// Returns an iterator of the currently configured base address registers.
752     #[allow(dead_code)] // TODO(dverkamp): remove this once used
get_bars(&self) -> PciBarIter753     pub fn get_bars(&self) -> PciBarIter {
754         PciBarIter {
755             config: self,
756             bar_num: 0,
757         }
758     }
759 
760     /// Returns the configuration of a base address register, if present.
get_bar_configuration(&self, bar_num: usize) -> Option<PciBarConfiguration>761     pub fn get_bar_configuration(&self, bar_num: usize) -> Option<PciBarConfiguration> {
762         let config = self.bar_configs.get(bar_num)?;
763 
764         if let Some(mut config) = config {
765             let command = self.read_reg(COMMAND_REG);
766             if (config.is_memory() && (command & COMMAND_REG_MEMORY_SPACE_MASK == 0))
767                 || (config.is_io() && (command & COMMAND_REG_IO_SPACE_MASK == 0))
768             {
769                 return None;
770             }
771 
772             // The address may have been modified by the guest, so the value in bar_configs
773             // may be outdated. Replace it with the current value.
774             config.addr = self.get_bar_addr(bar_num);
775             Some(config)
776         } else {
777             None
778         }
779     }
780 
781     /// Returns the type of the given BAR region.
get_bar_type(&self, bar_num: PciBarIndex) -> Option<PciBarRegionType>782     pub fn get_bar_type(&self, bar_num: PciBarIndex) -> Option<PciBarRegionType> {
783         self.bar_configs.get(bar_num)?.map(|c| c.region_type)
784     }
785 
786     /// Returns the address of the given BAR region.
get_bar_addr(&self, bar_num: PciBarIndex) -> u64787     pub fn get_bar_addr(&self, bar_num: PciBarIndex) -> u64 {
788         let bar_idx = if bar_num == ROM_BAR_IDX {
789             ROM_BAR_REG
790         } else {
791             BAR0_REG + bar_num
792         };
793 
794         let bar_type = match self.get_bar_type(bar_num) {
795             Some(t) => t,
796             None => return 0,
797         };
798 
799         match bar_type {
800             PciBarRegionType::IoRegion => u64::from(self.registers[bar_idx] & BAR_IO_ADDR_MASK),
801             PciBarRegionType::Memory32BitRegion => {
802                 u64::from(self.registers[bar_idx] & BAR_MEM_ADDR_MASK)
803             }
804             PciBarRegionType::Memory64BitRegion => {
805                 u64::from(self.registers[bar_idx] & BAR_MEM_ADDR_MASK)
806                     | u64::from(self.registers[bar_idx + 1]) << 32
807             }
808         }
809     }
810 
811     /// Configures the IRQ line and pin used by this device.
set_irq(&mut self, line: u8, pin: PciInterruptPin)812     pub fn set_irq(&mut self, line: u8, pin: PciInterruptPin) {
813         // `pin` is 1-based in the pci config space.
814         let pin_idx = (pin as u32) + 1;
815         let new_val = (self.registers[INTERRUPT_LINE_PIN_REG] & 0xffff_0000)
816             | (pin_idx << 8)
817             | u32::from(line);
818         self.do_write(INTERRUPT_LINE_PIN_REG, new_val)
819     }
820 
821     /// Adds the capability `cap_data` to the list of capabilities.
822     /// `cap_data` should include the two-byte PCI capability header (type, next),
823     /// but not populate it. Correct values will be generated automatically based
824     /// on `cap_data.id()`.
add_capability( &mut self, cap_data: &dyn PciCapability, cap_config: Option<Box<dyn PciCapConfig>>, ) -> Result<()>825     pub fn add_capability(
826         &mut self,
827         cap_data: &dyn PciCapability,
828         cap_config: Option<Box<dyn PciCapConfig>>,
829     ) -> Result<()> {
830         let total_len = cap_data.bytes().len();
831         // Check that the length is valid.
832         if cap_data.bytes().is_empty() {
833             return Err(Error::CapabilityEmpty);
834         }
835         let (cap_offset, tail_offset) = match self.last_capability {
836             Some((offset, len)) => (Self::next_dword(offset, len), offset + 1),
837             None => (FIRST_CAPABILITY_OFFSET, CAPABILITY_LIST_HEAD_OFFSET),
838         };
839         let end_offset = cap_offset
840             .checked_add(total_len)
841             .ok_or(Error::CapabilitySpaceFull(total_len))?;
842         if end_offset > CAPABILITY_MAX_OFFSET {
843             return Err(Error::CapabilitySpaceFull(total_len));
844         }
845         self.do_write(
846             STATUS_REG,
847             self.registers[STATUS_REG] | STATUS_REG_CAPABILITIES_USED_MASK,
848         );
849         self.write_byte_internal(tail_offset, cap_offset as u8, false);
850         self.write_byte_internal(cap_offset, cap_data.id() as u8, false);
851         self.write_byte_internal(cap_offset + 1, 0, false); // Next pointer.
852         for (i, byte) in cap_data.bytes().iter().enumerate().skip(2) {
853             self.write_byte_internal(cap_offset + i, *byte, false);
854         }
855         let reg_idx = cap_offset / 4;
856         for (i, dword) in cap_data.writable_bits().iter().enumerate() {
857             self.writable_bits[reg_idx + i] = *dword;
858         }
859         self.last_capability = Some((cap_offset, total_len));
860         if let Some(mut cap_config) = cap_config {
861             if let Some((mapping, offset)) = &self.mmio_mapping {
862                 cap_config.set_cap_mapping(PciCapMapping {
863                     mapping: mapping.clone(),
864                     offset: reg_idx * 4 + offset,
865                     num_regs: total_len / 4,
866                 });
867             }
868             self.capability_configs.insert(cap_offset / 4, cap_config);
869         }
870         Ok(())
871     }
872 
873     // Find the next aligned offset after the one given.
next_dword(offset: usize, len: usize) -> usize874     fn next_dword(offset: usize, len: usize) -> usize {
875         let next = offset + len;
876         (next + 3) & !3
877     }
878 
do_write(&mut self, reg_idx: usize, value: u32)879     fn do_write(&mut self, reg_idx: usize, value: u32) {
880         self.registers[reg_idx] = value;
881         if let Some((mmio_mapping, offset)) = self.mmio_mapping.as_ref() {
882             let mmio_mapping = mmio_mapping.lock();
883             let reg_offset = offset + reg_idx * 4;
884             if reg_idx == HEADER_TYPE_REG {
885                 // Skip writing the header type byte (reg_idx=2/offset=3) as
886                 // per the requirements of PciDevice.setup_pci_config_mapping.
887                 mmio_mapping
888                     .write_obj_volatile((value & 0xffff) as u16, reg_offset)
889                     .expect("bad register offset");
890                 // Skip HEADER_TYPE_REG_OFFSET (i.e. header+mfd byte)
891                 mmio_mapping
892                     .write_obj_volatile(((value >> 24) & 0xff) as u8, reg_offset + 3)
893                     .expect("bad register offset");
894             } else {
895                 mmio_mapping
896                     .write_obj_volatile(value, reg_offset)
897                     .expect("bad register offset");
898             }
899             if let Err(err) = mmio_mapping.flush_region(reg_offset, 4) {
900                 error!(
901                     "failed to flush write to pci mmio register ({}): {}",
902                     reg_idx, err
903                 );
904             }
905         }
906     }
907 
snapshot(&mut self) -> anyhow::Result<serde_json::Value>908     pub fn snapshot(&mut self) -> anyhow::Result<serde_json::Value> {
909         serde_json::to_value(PciConfigurationSerialized {
910             registers: self.registers,
911             writable_bits: self.writable_bits,
912             bar_used: self.bar_used,
913             bar_configs: self.bar_configs,
914             last_capability: self.last_capability,
915         })
916         .context("failed to serialize PciConfiguration")
917     }
918 
restore(&mut self, data: serde_json::Value) -> anyhow::Result<()>919     pub fn restore(&mut self, data: serde_json::Value) -> anyhow::Result<()> {
920         let deser: PciConfigurationSerialized =
921             serde_json::from_value(data).context("failed to deserialize PciConfiguration")?;
922         self.registers = deser.registers;
923         self.writable_bits = deser.writable_bits;
924         self.bar_used = deser.bar_used;
925         self.bar_configs = deser.bar_configs;
926         self.last_capability = deser.last_capability;
927         // Restore everything via do_write to avoid writing to the header type register
928         // and clobbering the multi-function device bit, as that bit is managed by the
929         // PciRoot. Since restore doesn't change the types or layout of PCI devices, the
930         // header type bits in the register are already correct anyway.
931         for i in 0..NUM_CONFIGURATION_REGISTERS {
932             self.do_write(i, self.registers[i]);
933         }
934         Ok(())
935     }
936 
setup_mapping( &mut self, shmem: &SharedMemory, base: usize, len: usize, ) -> anyhow::Result<()>937     pub fn setup_mapping(
938         &mut self,
939         shmem: &SharedMemory,
940         base: usize,
941         len: usize,
942     ) -> anyhow::Result<()> {
943         if self.mmio_mapping.is_some() {
944             bail!("PCIe config mmio mapping already initialized");
945         }
946         let mapping = MemoryMappingBuilder::new(base::pagesize())
947             .from_shared_memory(shmem)
948             .build()
949             .context("Failed to create mapping")?;
950         for i in 0..(len / 4) {
951             let val = self.registers.get(i).unwrap_or(&0xffff_ffff);
952             mapping
953                 .write_obj_volatile(*val, base + i * 4)
954                 .expect("memcpy failed");
955         }
956         let mapping = Arc::new(Mutex::new(mapping));
957         for (idx, cap) in self.capability_configs.iter_mut() {
958             let mut cap_mapping = PciCapMapping {
959                 mapping: mapping.clone(),
960                 offset: idx * 4 + base,
961                 num_regs: cap.num_regs(),
962             };
963             for i in 0..cap.num_regs() {
964                 let val = cap.read_reg(i);
965                 let mask = cap.read_mask()[i];
966                 cap_mapping.set_reg(i, val, mask);
967             }
968             cap.set_cap_mapping(cap_mapping);
969         }
970         self.mmio_mapping = Some((mapping, base));
971         Ok(())
972     }
973 }
974 
975 impl PciBarConfiguration {
new( bar_idx: PciBarIndex, size: u64, region_type: PciBarRegionType, prefetchable: PciBarPrefetchable, ) -> Self976     pub fn new(
977         bar_idx: PciBarIndex,
978         size: u64,
979         region_type: PciBarRegionType,
980         prefetchable: PciBarPrefetchable,
981     ) -> Self {
982         PciBarConfiguration {
983             bar_idx,
984             addr: 0,
985             size,
986             region_type,
987             prefetchable,
988         }
989     }
990 
bar_index(&self) -> PciBarIndex991     pub fn bar_index(&self) -> PciBarIndex {
992         self.bar_idx
993     }
994 
reg_index(&self) -> usize995     pub fn reg_index(&self) -> usize {
996         if self.bar_idx == ROM_BAR_IDX {
997             ROM_BAR_REG
998         } else {
999             BAR0_REG + self.bar_idx
1000         }
1001     }
1002 
address(&self) -> u641003     pub fn address(&self) -> u64 {
1004         self.addr
1005     }
1006 
address_range(&self) -> std::ops::Range<u64>1007     pub fn address_range(&self) -> std::ops::Range<u64> {
1008         self.addr..self.addr + self.size
1009     }
1010 
set_address(mut self, addr: u64) -> Self1011     pub fn set_address(mut self, addr: u64) -> Self {
1012         self.addr = addr;
1013         self
1014     }
1015 
size(&self) -> u641016     pub fn size(&self) -> u64 {
1017         self.size
1018     }
1019 
is_expansion_rom(&self) -> bool1020     pub fn is_expansion_rom(&self) -> bool {
1021         self.bar_idx == ROM_BAR_IDX
1022     }
1023 
is_memory(&self) -> bool1024     pub fn is_memory(&self) -> bool {
1025         matches!(
1026             self.region_type,
1027             PciBarRegionType::Memory32BitRegion | PciBarRegionType::Memory64BitRegion
1028         )
1029     }
1030 
is_64bit_memory(&self) -> bool1031     pub fn is_64bit_memory(&self) -> bool {
1032         self.region_type == PciBarRegionType::Memory64BitRegion
1033     }
1034 
is_io(&self) -> bool1035     pub fn is_io(&self) -> bool {
1036         self.region_type == PciBarRegionType::IoRegion
1037     }
1038 
is_prefetchable(&self) -> bool1039     pub fn is_prefetchable(&self) -> bool {
1040         self.is_memory() && self.prefetchable == PciBarPrefetchable::Prefetchable
1041     }
1042 }
1043 
1044 impl<T: PciCapConfig + ?Sized> PciCapConfig for Arc<Mutex<T>> {
read_mask(&self) -> &'static [u32]1045     fn read_mask(&self) -> &'static [u32] {
1046         self.lock().read_mask()
1047     }
read_reg(&self, reg_idx: usize) -> u321048     fn read_reg(&self, reg_idx: usize) -> u32 {
1049         self.lock().read_reg(reg_idx)
1050     }
write_reg( &mut self, reg_idx: usize, offset: u64, data: &[u8], ) -> Option<Box<dyn PciCapConfigWriteResult>>1051     fn write_reg(
1052         &mut self,
1053         reg_idx: usize,
1054         offset: u64,
1055         data: &[u8],
1056     ) -> Option<Box<dyn PciCapConfigWriteResult>> {
1057         self.lock().write_reg(reg_idx, offset, data)
1058     }
set_cap_mapping(&mut self, mapping: PciCapMapping)1059     fn set_cap_mapping(&mut self, mapping: PciCapMapping) {
1060         self.lock().set_cap_mapping(mapping)
1061     }
1062 }
1063 
1064 /// Struct for updating a capabilitiy's mmio mapping.
1065 pub struct PciCapMapping {
1066     mapping: Arc<Mutex<MemoryMapping>>,
1067     offset: usize,
1068     num_regs: usize,
1069 }
1070 
1071 impl PciCapMapping {
1072     /// Set the bits of register `reg_idx` specified by `mask` to `data`.
set_reg(&mut self, reg_idx: usize, data: u32, mask: u32)1073     pub fn set_reg(&mut self, reg_idx: usize, data: u32, mask: u32) {
1074         if reg_idx >= self.num_regs {
1075             error!(
1076                 "out of bounds register write {} vs {}",
1077                 self.num_regs, reg_idx
1078             );
1079             return;
1080         }
1081         let mapping = self.mapping.lock();
1082         let offset = self.offset + reg_idx * 4;
1083         let cur_value = mapping.read_obj::<u32>(offset).expect("memcpy failed");
1084         let new_val = (cur_value & !mask) | (data & mask);
1085         mapping
1086             .write_obj_volatile(new_val, offset)
1087             .expect("memcpy failed");
1088         if let Err(err) = mapping.flush_region(offset, 4) {
1089             error!(
1090                 "failed to flush write to pci cap in mmio register ({}): {}",
1091                 reg_idx, err
1092             );
1093         }
1094     }
1095 }
1096 
1097 #[cfg(test)]
1098 mod tests {
1099     use zerocopy::AsBytes;
1100 
1101     use super::*;
1102 
1103     #[repr(C, packed)]
1104     #[derive(Clone, Copy, AsBytes)]
1105     #[allow(dead_code)]
1106     struct TestCap {
1107         _vndr: u8,
1108         _next: u8,
1109         len: u8,
1110         foo: u8,
1111     }
1112 
1113     impl PciCapability for TestCap {
bytes(&self) -> &[u8]1114         fn bytes(&self) -> &[u8] {
1115             self.as_bytes()
1116         }
1117 
id(&self) -> PciCapabilityID1118         fn id(&self) -> PciCapabilityID {
1119             PciCapabilityID::VendorSpecific
1120         }
1121 
writable_bits(&self) -> Vec<u32>1122         fn writable_bits(&self) -> Vec<u32> {
1123             vec![0u32; 1]
1124         }
1125     }
1126 
1127     #[test]
add_capability()1128     fn add_capability() {
1129         let mut cfg = PciConfiguration::new(
1130             0x1234,
1131             0x5678,
1132             PciClassCode::MultimediaController,
1133             &PciMultimediaSubclass::AudioController,
1134             None,
1135             PciHeaderType::Device,
1136             0xABCD,
1137             0x2468,
1138             0,
1139         );
1140 
1141         // Add two capabilities with different contents.
1142         let cap1 = TestCap {
1143             _vndr: 0,
1144             _next: 0,
1145             len: 4,
1146             foo: 0xAA,
1147         };
1148         let cap1_offset = 64;
1149         cfg.add_capability(&cap1, None).unwrap();
1150 
1151         let cap2 = TestCap {
1152             _vndr: 0,
1153             _next: 0,
1154             len: 0x04,
1155             foo: 0x55,
1156         };
1157         let cap2_offset = 68;
1158         cfg.add_capability(&cap2, None).unwrap();
1159 
1160         // The capability list head should be pointing to cap1.
1161         let cap_ptr = cfg.read_reg(CAPABILITY_LIST_HEAD_OFFSET / 4) & 0xFF;
1162         assert_eq!(cap1_offset, cap_ptr as usize);
1163 
1164         // Verify the contents of the capabilities.
1165         let cap1_data = cfg.read_reg(cap1_offset / 4);
1166         assert_eq!(cap1_data & 0xFF, 0x09); // capability ID
1167         assert_eq!((cap1_data >> 8) & 0xFF, cap2_offset as u32); // next capability pointer
1168         assert_eq!((cap1_data >> 16) & 0xFF, 0x04); // cap1.len
1169         assert_eq!((cap1_data >> 24) & 0xFF, 0xAA); // cap1.foo
1170 
1171         let cap2_data = cfg.read_reg(cap2_offset / 4);
1172         assert_eq!(cap2_data & 0xFF, 0x09); // capability ID
1173         assert_eq!((cap2_data >> 8) & 0xFF, 0x00); // next capability pointer
1174         assert_eq!((cap2_data >> 16) & 0xFF, 0x04); // cap2.len
1175         assert_eq!((cap2_data >> 24) & 0xFF, 0x55); // cap2.foo
1176     }
1177 
1178     #[derive(Copy, Clone)]
1179     enum TestPI {
1180         Test = 0x5a,
1181     }
1182 
1183     impl PciProgrammingInterface for TestPI {
get_register_value(&self) -> u81184         fn get_register_value(&self) -> u8 {
1185             *self as u8
1186         }
1187     }
1188 
1189     #[test]
class_code()1190     fn class_code() {
1191         let cfg = PciConfiguration::new(
1192             0x1234,
1193             0x5678,
1194             PciClassCode::MultimediaController,
1195             &PciMultimediaSubclass::AudioController,
1196             Some(&TestPI::Test),
1197             PciHeaderType::Device,
1198             0xABCD,
1199             0x2468,
1200             0,
1201         );
1202 
1203         let class_reg = cfg.read_reg(2);
1204         let class_code = (class_reg >> 24) & 0xFF;
1205         let subclass = (class_reg >> 16) & 0xFF;
1206         let prog_if = (class_reg >> 8) & 0xFF;
1207         assert_eq!(class_code, 0x04);
1208         assert_eq!(subclass, 0x01);
1209         assert_eq!(prog_if, 0x5a);
1210     }
1211 
1212     #[test]
read_only_bits()1213     fn read_only_bits() {
1214         let mut cfg = PciConfiguration::new(
1215             0x1234,
1216             0x5678,
1217             PciClassCode::MultimediaController,
1218             &PciMultimediaSubclass::AudioController,
1219             Some(&TestPI::Test),
1220             PciHeaderType::Device,
1221             0xABCD,
1222             0x2468,
1223             0,
1224         );
1225 
1226         // Attempt to overwrite vendor ID and device ID, which are read-only
1227         cfg.write_reg(0, 0, &[0xBA, 0xAD, 0xF0, 0x0D]);
1228         // The original vendor and device ID should remain.
1229         assert_eq!(cfg.read_reg(0), 0x56781234);
1230     }
1231 
1232     #[test]
query_unused_bar()1233     fn query_unused_bar() {
1234         let cfg = PciConfiguration::new(
1235             0x1234,
1236             0x5678,
1237             PciClassCode::MultimediaController,
1238             &PciMultimediaSubclass::AudioController,
1239             Some(&TestPI::Test),
1240             PciHeaderType::Device,
1241             0xABCD,
1242             0x2468,
1243             0,
1244         );
1245 
1246         // No BAR 0 has been configured, so these should return None or 0 as appropriate.
1247         assert_eq!(cfg.get_bar_type(0), None);
1248         assert_eq!(cfg.get_bar_addr(0), 0);
1249 
1250         let mut bar_iter = cfg.get_bars();
1251         assert_eq!(bar_iter.next(), None);
1252     }
1253 
1254     #[test]
add_pci_bar_mem_64bit()1255     fn add_pci_bar_mem_64bit() {
1256         let mut cfg = PciConfiguration::new(
1257             0x1234,
1258             0x5678,
1259             PciClassCode::MultimediaController,
1260             &PciMultimediaSubclass::AudioController,
1261             Some(&TestPI::Test),
1262             PciHeaderType::Device,
1263             0xABCD,
1264             0x2468,
1265             0,
1266         );
1267 
1268         cfg.add_pci_bar(
1269             PciBarConfiguration::new(
1270                 0,
1271                 0x10,
1272                 PciBarRegionType::Memory64BitRegion,
1273                 PciBarPrefetchable::NotPrefetchable,
1274             )
1275             .set_address(0x0123_4567_89AB_CDE0),
1276         )
1277         .expect("add_pci_bar failed");
1278 
1279         assert_eq!(
1280             cfg.get_bar_type(0),
1281             Some(PciBarRegionType::Memory64BitRegion)
1282         );
1283         assert_eq!(cfg.get_bar_addr(0), 0x0123_4567_89AB_CDE0);
1284         assert_eq!(cfg.writable_bits[BAR0_REG + 1], 0xFFFFFFFF);
1285         assert_eq!(cfg.writable_bits[BAR0_REG + 0], 0xFFFFFFF0);
1286 
1287         let mut bar_iter = cfg.get_bars();
1288         assert_eq!(
1289             bar_iter.next(),
1290             Some(PciBarConfiguration {
1291                 addr: 0x0123_4567_89AB_CDE0,
1292                 size: 0x10,
1293                 bar_idx: 0,
1294                 region_type: PciBarRegionType::Memory64BitRegion,
1295                 prefetchable: PciBarPrefetchable::NotPrefetchable
1296             })
1297         );
1298         assert_eq!(bar_iter.next(), None);
1299     }
1300 
1301     #[test]
add_pci_bar_mem_32bit()1302     fn add_pci_bar_mem_32bit() {
1303         let mut cfg = PciConfiguration::new(
1304             0x1234,
1305             0x5678,
1306             PciClassCode::MultimediaController,
1307             &PciMultimediaSubclass::AudioController,
1308             Some(&TestPI::Test),
1309             PciHeaderType::Device,
1310             0xABCD,
1311             0x2468,
1312             0,
1313         );
1314 
1315         cfg.add_pci_bar(
1316             PciBarConfiguration::new(
1317                 0,
1318                 0x10,
1319                 PciBarRegionType::Memory32BitRegion,
1320                 PciBarPrefetchable::NotPrefetchable,
1321             )
1322             .set_address(0x12345670),
1323         )
1324         .expect("add_pci_bar failed");
1325 
1326         assert_eq!(
1327             cfg.get_bar_type(0),
1328             Some(PciBarRegionType::Memory32BitRegion)
1329         );
1330         assert_eq!(cfg.get_bar_addr(0), 0x12345670);
1331         assert_eq!(cfg.writable_bits[BAR0_REG], 0xFFFFFFF0);
1332 
1333         let mut bar_iter = cfg.get_bars();
1334         assert_eq!(
1335             bar_iter.next(),
1336             Some(PciBarConfiguration {
1337                 addr: 0x12345670,
1338                 size: 0x10,
1339                 bar_idx: 0,
1340                 region_type: PciBarRegionType::Memory32BitRegion,
1341                 prefetchable: PciBarPrefetchable::NotPrefetchable
1342             })
1343         );
1344         assert_eq!(bar_iter.next(), None);
1345     }
1346 
1347     #[test]
add_pci_bar_io()1348     fn add_pci_bar_io() {
1349         let mut cfg = PciConfiguration::new(
1350             0x1234,
1351             0x5678,
1352             PciClassCode::MultimediaController,
1353             &PciMultimediaSubclass::AudioController,
1354             Some(&TestPI::Test),
1355             PciHeaderType::Device,
1356             0xABCD,
1357             0x2468,
1358             0,
1359         );
1360 
1361         cfg.add_pci_bar(
1362             PciBarConfiguration::new(
1363                 0,
1364                 0x4,
1365                 PciBarRegionType::IoRegion,
1366                 PciBarPrefetchable::NotPrefetchable,
1367             )
1368             .set_address(0x1230),
1369         )
1370         .expect("add_pci_bar failed");
1371 
1372         assert_eq!(cfg.get_bar_type(0), Some(PciBarRegionType::IoRegion));
1373         assert_eq!(cfg.get_bar_addr(0), 0x1230);
1374         assert_eq!(cfg.writable_bits[BAR0_REG], 0xFFFFFFFC);
1375 
1376         let mut bar_iter = cfg.get_bars();
1377         assert_eq!(
1378             bar_iter.next(),
1379             Some(PciBarConfiguration {
1380                 addr: 0x1230,
1381                 size: 0x4,
1382                 bar_idx: 0,
1383                 region_type: PciBarRegionType::IoRegion,
1384                 prefetchable: PciBarPrefetchable::NotPrefetchable
1385             })
1386         );
1387         assert_eq!(bar_iter.next(), None);
1388     }
1389 
1390     #[test]
add_pci_bar_multiple()1391     fn add_pci_bar_multiple() {
1392         let mut cfg = PciConfiguration::new(
1393             0x1234,
1394             0x5678,
1395             PciClassCode::MultimediaController,
1396             &PciMultimediaSubclass::AudioController,
1397             Some(&TestPI::Test),
1398             PciHeaderType::Device,
1399             0xABCD,
1400             0x2468,
1401             0,
1402         );
1403 
1404         // bar_num 0-1: 64-bit memory
1405         cfg.add_pci_bar(
1406             PciBarConfiguration::new(
1407                 0,
1408                 0x10,
1409                 PciBarRegionType::Memory64BitRegion,
1410                 PciBarPrefetchable::NotPrefetchable,
1411             )
1412             .set_address(0x0123_4567_89AB_CDE0),
1413         )
1414         .expect("add_pci_bar failed");
1415 
1416         // bar 2: 32-bit memory
1417         cfg.add_pci_bar(
1418             PciBarConfiguration::new(
1419                 2,
1420                 0x10,
1421                 PciBarRegionType::Memory32BitRegion,
1422                 PciBarPrefetchable::NotPrefetchable,
1423             )
1424             .set_address(0x12345670),
1425         )
1426         .expect("add_pci_bar failed");
1427 
1428         // bar 3: I/O
1429         cfg.add_pci_bar(
1430             PciBarConfiguration::new(
1431                 3,
1432                 0x4,
1433                 PciBarRegionType::IoRegion,
1434                 PciBarPrefetchable::NotPrefetchable,
1435             )
1436             .set_address(0x1230),
1437         )
1438         .expect("add_pci_bar failed");
1439 
1440         // Confirm default memory and I/O region configurations.
1441         let mut bar_iter = cfg.get_bars();
1442         assert_eq!(
1443             bar_iter.next(),
1444             Some(PciBarConfiguration {
1445                 addr: 0x0123_4567_89AB_CDE0,
1446                 size: 0x10,
1447                 bar_idx: 0,
1448                 region_type: PciBarRegionType::Memory64BitRegion,
1449                 prefetchable: PciBarPrefetchable::NotPrefetchable
1450             })
1451         );
1452         assert_eq!(
1453             bar_iter.next(),
1454             Some(PciBarConfiguration {
1455                 addr: 0x12345670,
1456                 size: 0x10,
1457                 bar_idx: 2,
1458                 region_type: PciBarRegionType::Memory32BitRegion,
1459                 prefetchable: PciBarPrefetchable::NotPrefetchable
1460             })
1461         );
1462         assert_eq!(
1463             bar_iter.next(),
1464             Some(PciBarConfiguration {
1465                 addr: 0x1230,
1466                 size: 0x4,
1467                 bar_idx: 3,
1468                 region_type: PciBarRegionType::IoRegion,
1469                 prefetchable: PciBarPrefetchable::NotPrefetchable
1470             })
1471         );
1472         assert_eq!(bar_iter.next(), None);
1473 
1474         // Reassign the address for BAR 0 and verify that get_memory_regions() matches.
1475         cfg.write_reg(4 + 0, 0, &0xBBAA9980u32.to_le_bytes());
1476         cfg.write_reg(4 + 1, 0, &0xFFEEDDCCu32.to_le_bytes());
1477 
1478         let mut bar_iter = cfg.get_bars();
1479         assert_eq!(
1480             bar_iter.next(),
1481             Some(PciBarConfiguration {
1482                 addr: 0xFFEE_DDCC_BBAA_9980,
1483                 size: 0x10,
1484                 bar_idx: 0,
1485                 region_type: PciBarRegionType::Memory64BitRegion,
1486                 prefetchable: PciBarPrefetchable::NotPrefetchable
1487             })
1488         );
1489         assert_eq!(
1490             bar_iter.next(),
1491             Some(PciBarConfiguration {
1492                 addr: 0x12345670,
1493                 size: 0x10,
1494                 bar_idx: 2,
1495                 region_type: PciBarRegionType::Memory32BitRegion,
1496                 prefetchable: PciBarPrefetchable::NotPrefetchable
1497             })
1498         );
1499         assert_eq!(
1500             bar_iter.next(),
1501             Some(PciBarConfiguration {
1502                 addr: 0x1230,
1503                 size: 0x4,
1504                 bar_idx: 3,
1505                 region_type: PciBarRegionType::IoRegion,
1506                 prefetchable: PciBarPrefetchable::NotPrefetchable
1507             })
1508         );
1509         assert_eq!(bar_iter.next(), None);
1510     }
1511 
1512     #[test]
add_pci_bar_invalid_size()1513     fn add_pci_bar_invalid_size() {
1514         let mut cfg = PciConfiguration::new(
1515             0x1234,
1516             0x5678,
1517             PciClassCode::MultimediaController,
1518             &PciMultimediaSubclass::AudioController,
1519             Some(&TestPI::Test),
1520             PciHeaderType::Device,
1521             0xABCD,
1522             0x2468,
1523             0,
1524         );
1525 
1526         // I/O BAR with size 2 (too small)
1527         assert_eq!(
1528             cfg.add_pci_bar(
1529                 PciBarConfiguration::new(
1530                     0,
1531                     0x2,
1532                     PciBarRegionType::IoRegion,
1533                     PciBarPrefetchable::NotPrefetchable,
1534                 )
1535                 .set_address(0x1230),
1536             ),
1537             Err(Error::BarSizeInvalid(0x2))
1538         );
1539 
1540         // I/O BAR with size 3 (not a power of 2)
1541         assert_eq!(
1542             cfg.add_pci_bar(
1543                 PciBarConfiguration::new(
1544                     0,
1545                     0x3,
1546                     PciBarRegionType::IoRegion,
1547                     PciBarPrefetchable::NotPrefetchable,
1548                 )
1549                 .set_address(0x1230),
1550             ),
1551             Err(Error::BarSizeInvalid(0x3))
1552         );
1553 
1554         // Memory BAR with size 8 (too small)
1555         assert_eq!(
1556             cfg.add_pci_bar(
1557                 PciBarConfiguration::new(
1558                     0,
1559                     0x8,
1560                     PciBarRegionType::Memory32BitRegion,
1561                     PciBarPrefetchable::NotPrefetchable,
1562                 )
1563                 .set_address(0x12345670),
1564             ),
1565             Err(Error::BarSizeInvalid(0x8))
1566         );
1567     }
1568 
1569     #[test]
add_rom_bar()1570     fn add_rom_bar() {
1571         let mut cfg = PciConfiguration::new(
1572             0x1234,
1573             0x5678,
1574             PciClassCode::MultimediaController,
1575             &PciMultimediaSubclass::AudioController,
1576             Some(&TestPI::Test),
1577             PciHeaderType::Device,
1578             0xABCD,
1579             0x2468,
1580             0,
1581         );
1582 
1583         // Attempt to add a 64-bit memory BAR as the expansion ROM (invalid).
1584         assert_eq!(
1585             cfg.add_pci_bar(PciBarConfiguration::new(
1586                 ROM_BAR_IDX,
1587                 0x1000,
1588                 PciBarRegionType::Memory64BitRegion,
1589                 PciBarPrefetchable::NotPrefetchable,
1590             ),),
1591             Err(Error::BarInvalidRomType)
1592         );
1593 
1594         // Attempt to add an I/O BAR as the expansion ROM (invalid).
1595         assert_eq!(
1596             cfg.add_pci_bar(PciBarConfiguration::new(
1597                 ROM_BAR_IDX,
1598                 0x1000,
1599                 PciBarRegionType::IoRegion,
1600                 PciBarPrefetchable::NotPrefetchable,
1601             ),),
1602             Err(Error::BarInvalidRomType)
1603         );
1604 
1605         // Attempt to add a 1KB memory region as the expansion ROM (too small).
1606         assert_eq!(
1607             cfg.add_pci_bar(PciBarConfiguration::new(
1608                 ROM_BAR_IDX,
1609                 1024,
1610                 PciBarRegionType::Memory32BitRegion,
1611                 PciBarPrefetchable::NotPrefetchable,
1612             ),),
1613             Err(Error::BarSizeInvalid(1024))
1614         );
1615 
1616         // Add a 32-bit memory BAR as the expansion ROM (valid).
1617         cfg.add_pci_bar(
1618             PciBarConfiguration::new(
1619                 ROM_BAR_IDX,
1620                 0x800,
1621                 PciBarRegionType::Memory32BitRegion,
1622                 PciBarPrefetchable::NotPrefetchable,
1623             )
1624             .set_address(0x12345000),
1625         )
1626         .expect("add_pci_bar failed");
1627 
1628         assert_eq!(
1629             cfg.get_bar_type(ROM_BAR_IDX),
1630             Some(PciBarRegionType::Memory32BitRegion)
1631         );
1632         assert_eq!(cfg.get_bar_addr(ROM_BAR_IDX), 0x12345000);
1633         assert_eq!(cfg.read_reg(ROM_BAR_REG), 0x12345000);
1634         assert_eq!(cfg.writable_bits[ROM_BAR_REG], 0xFFFFF801);
1635     }
1636 
1637     #[test]
pci_configuration_capability_snapshot_restore() -> anyhow::Result<()>1638     fn pci_configuration_capability_snapshot_restore() -> anyhow::Result<()> {
1639         let mut cfg = PciConfiguration::new(
1640             0x1234,
1641             0x5678,
1642             PciClassCode::MultimediaController,
1643             &PciMultimediaSubclass::AudioController,
1644             Some(&TestPI::Test),
1645             PciHeaderType::Device,
1646             0xABCD,
1647             0x2468,
1648             0,
1649         );
1650 
1651         let snap_init = cfg.snapshot().context("failed to snapshot")?;
1652 
1653         // Add a capability.
1654         let cap1 = TestCap {
1655             _vndr: 0,
1656             _next: 0,
1657             len: 4,
1658             foo: 0xAA,
1659         };
1660         cfg.add_capability(&cap1, None).unwrap();
1661 
1662         let snap_mod = cfg.snapshot().context("failed to snapshot mod")?;
1663         cfg.restore(snap_init.clone())
1664             .context("failed to restore snap_init")?;
1665         let snap_restore_init = cfg.snapshot().context("failed to snapshot restored_init")?;
1666         assert_eq!(snap_init, snap_restore_init);
1667         assert_ne!(snap_init, snap_mod);
1668         cfg.restore(snap_mod.clone())
1669             .context("failed to restore snap_init")?;
1670         let snap_restore_mod = cfg.snapshot().context("failed to snapshot restored_mod")?;
1671         assert_eq!(snap_mod, snap_restore_mod);
1672         Ok(())
1673     }
1674 
1675     #[test]
pci_configuration_pci_bar_snapshot_restore() -> anyhow::Result<()>1676     fn pci_configuration_pci_bar_snapshot_restore() -> anyhow::Result<()> {
1677         let mut cfg = PciConfiguration::new(
1678             0x1234,
1679             0x5678,
1680             PciClassCode::MultimediaController,
1681             &PciMultimediaSubclass::AudioController,
1682             Some(&TestPI::Test),
1683             PciHeaderType::Device,
1684             0xABCD,
1685             0x2468,
1686             0,
1687         );
1688 
1689         let snap_init = cfg.snapshot().context("failed to snapshot")?;
1690 
1691         // bar_num 0-1: 64-bit memory
1692         cfg.add_pci_bar(
1693             PciBarConfiguration::new(
1694                 0,
1695                 0x10,
1696                 PciBarRegionType::Memory64BitRegion,
1697                 PciBarPrefetchable::NotPrefetchable,
1698             )
1699             .set_address(0x0123_4567_89AB_CDE0),
1700         )
1701         .expect("add_pci_bar failed");
1702 
1703         let snap_mod = cfg.snapshot().context("failed to snapshot mod")?;
1704         cfg.restore(snap_init.clone())
1705             .context("failed to restore snap_init")?;
1706         let snap_restore_init = cfg.snapshot().context("failed to snapshot restored_init")?;
1707         assert_eq!(snap_init, snap_restore_init);
1708         assert_ne!(snap_init, snap_mod);
1709         cfg.restore(snap_mod.clone())
1710             .context("failed to restore snap_init")?;
1711         let snap_restore_mod = cfg.snapshot().context("failed to snapshot restored_mod")?;
1712         assert_eq!(snap_mod, snap_restore_mod);
1713         Ok(())
1714     }
1715 
1716     #[test]
pci_configuration_capability_pci_bar_snapshot_restore() -> anyhow::Result<()>1717     fn pci_configuration_capability_pci_bar_snapshot_restore() -> anyhow::Result<()> {
1718         let mut cfg = PciConfiguration::new(
1719             0x1234,
1720             0x5678,
1721             PciClassCode::MultimediaController,
1722             &PciMultimediaSubclass::AudioController,
1723             Some(&TestPI::Test),
1724             PciHeaderType::Device,
1725             0xABCD,
1726             0x2468,
1727             0,
1728         );
1729 
1730         let snap_init = cfg.snapshot().context("failed to snapshot")?;
1731 
1732         // Add a capability.
1733         let cap1 = TestCap {
1734             _vndr: 0,
1735             _next: 0,
1736             len: 4,
1737             foo: 0xAA,
1738         };
1739         cfg.add_capability(&cap1, None).unwrap();
1740 
1741         // bar_num 0-1: 64-bit memory
1742         cfg.add_pci_bar(
1743             PciBarConfiguration::new(
1744                 0,
1745                 0x10,
1746                 PciBarRegionType::Memory64BitRegion,
1747                 PciBarPrefetchable::NotPrefetchable,
1748             )
1749             .set_address(0x0123_4567_89AB_CDE0),
1750         )
1751         .expect("add_pci_bar failed");
1752 
1753         let snap_mod = cfg.snapshot().context("failed to snapshot mod")?;
1754         cfg.restore(snap_init.clone())
1755             .context("failed to restore snap_init")?;
1756         let snap_restore_init = cfg.snapshot().context("failed to snapshot restored_init")?;
1757         assert_eq!(snap_init, snap_restore_init);
1758         assert_ne!(snap_init, snap_mod);
1759         cfg.restore(snap_mod.clone())
1760             .context("failed to restore snap_init")?;
1761         let snap_restore_mod = cfg.snapshot().context("failed to snapshot restored_mod")?;
1762         assert_eq!(snap_mod, snap_restore_mod);
1763         Ok(())
1764     }
1765 }
1766