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