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