• 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::convert::TryFrom;
6 use std::convert::TryInto;
7 
8 use anyhow::Context;
9 use base::custom_serde::deserialize_seq_to_arr;
10 use base::custom_serde::serialize_arr;
11 use base::warn;
12 use remain::sorted;
13 use serde::Deserialize;
14 use serde::Serialize;
15 use thiserror::Error;
16 
17 use crate::pci::PciInterruptPin;
18 
19 // The number of 32bit registers in the config space, 256 bytes.
20 const NUM_CONFIGURATION_REGISTERS: usize = 64;
21 
22 pub const PCI_ID_REG: usize = 0;
23 pub const COMMAND_REG: usize = 1;
24 pub const COMMAND_REG_IO_SPACE_MASK: u32 = 0x0000_0001;
25 pub const COMMAND_REG_MEMORY_SPACE_MASK: u32 = 0x0000_0002;
26 const STATUS_REG: usize = 1;
27 pub const STATUS_REG_CAPABILITIES_USED_MASK: u32 = 0x0010_0000;
28 #[allow(dead_code)]
29 #[cfg(unix)]
30 pub const CLASS_REG: usize = 2;
31 #[cfg(feature = "direct")]
32 pub const CLASS_REG_REVISION_ID_OFFSET: usize = 0;
33 pub const HEADER_TYPE_REG: usize = 3;
34 pub const HEADER_TYPE_MULTIFUNCTION_MASK: u32 = 0x0080_0000;
35 pub const BAR0_REG: usize = 4;
36 const BAR_IO_ADDR_MASK: u32 = 0xffff_fffc;
37 const BAR_IO_MIN_SIZE: u64 = 4;
38 const BAR_MEM_ADDR_MASK: u32 = 0xffff_fff0;
39 const BAR_MEM_MIN_SIZE: u64 = 16;
40 const BAR_ROM_MIN_SIZE: u64 = 2048;
41 pub const NUM_BAR_REGS: usize = 7; // 6 normal BARs + expansion ROM BAR.
42 pub const ROM_BAR_IDX: PciBarIndex = 6;
43 pub const ROM_BAR_REG: usize = 12;
44 pub const CAPABILITY_LIST_HEAD_OFFSET: usize = 0x34;
45 #[cfg(unix)]
46 pub const PCI_CAP_NEXT_POINTER: usize = 0x1;
47 const FIRST_CAPABILITY_OFFSET: usize = 0x40;
48 pub const CAPABILITY_MAX_OFFSET: usize = 255;
49 
50 const INTERRUPT_LINE_PIN_REG: usize = 15;
51 
52 /// Represents the types of PCI headers allowed in the configuration registers.
53 #[allow(dead_code)]
54 #[derive(Copy, Clone)]
55 pub enum PciHeaderType {
56     Device,
57     Bridge,
58 }
59 
60 /// Classes of PCI nodes.
61 #[allow(dead_code)]
62 #[derive(Copy, Clone, Debug, enumn::N, Serialize, Deserialize, PartialEq, Eq)]
63 pub enum PciClassCode {
64     TooOld,
65     MassStorage,
66     NetworkController,
67     DisplayController,
68     MultimediaController,
69     MemoryController,
70     BridgeDevice,
71     SimpleCommunicationController,
72     BaseSystemPeripheral,
73     InputDevice,
74     DockingStation,
75     Processor,
76     SerialBusController,
77     WirelessController,
78     IntelligentIoController,
79     SatelliteCommunicationController,
80     EncryptionController,
81     DataAcquisitionSignalProcessing,
82     ProcessingAccelerator,
83     NonEssentialInstrumentation,
84     Other = 0xff,
85 }
86 
87 impl PciClassCode {
get_register_value(&self) -> u888     pub fn get_register_value(&self) -> u8 {
89         *self as u8
90     }
91 }
92 
93 #[sorted]
94 #[derive(Error, Debug)]
95 pub enum PciClassCodeParseError {
96     #[error("Unknown class code")]
97     Unknown,
98 }
99 
100 impl TryFrom<u8> for PciClassCode {
101     type Error = PciClassCodeParseError;
try_from(v: u8) -> std::result::Result<PciClassCode, PciClassCodeParseError>102     fn try_from(v: u8) -> std::result::Result<PciClassCode, PciClassCodeParseError> {
103         match PciClassCode::n(v) {
104             Some(class) => Ok(class),
105             None => Err(PciClassCodeParseError::Unknown),
106         }
107     }
108 }
109 
110 /// A PCI sublcass. Each class in `PciClassCode` can specify a unique set of subclasses. This trait
111 /// is implemented by each subclass. It allows use of a trait object to generate configurations.
112 pub trait PciSubclass {
113     /// Convert this subclass to the value used in the PCI specification.
get_register_value(&self) -> u8114     fn get_register_value(&self) -> u8;
115 }
116 
117 /// Subclasses of the DisplayController class.
118 #[allow(dead_code)]
119 #[derive(Copy, Clone)]
120 pub enum PciDisplaySubclass {
121     VgaCompatibleController = 0x00,
122     XgaCompatibleController = 0x01,
123     ThreeDController = 0x02,
124     Other = 0x80,
125 }
126 
127 impl PciSubclass for PciDisplaySubclass {
get_register_value(&self) -> u8128     fn get_register_value(&self) -> u8 {
129         *self as u8
130     }
131 }
132 
133 /// Subclasses of the MultimediaController class.
134 #[allow(dead_code)]
135 #[derive(Copy, Clone)]
136 pub enum PciMultimediaSubclass {
137     VideoController = 0x00,
138     AudioController = 0x01,
139     TelephonyDevice = 0x02,
140     AudioDevice = 0x03,
141     Other = 0x80,
142 }
143 
144 impl PciSubclass for PciMultimediaSubclass {
get_register_value(&self) -> u8145     fn get_register_value(&self) -> u8 {
146         *self as u8
147     }
148 }
149 
150 /// Subclasses of the BridgeDevice
151 #[allow(dead_code)]
152 #[derive(Copy, Clone)]
153 pub enum PciBridgeSubclass {
154     HostBridge = 0x00,
155     IsaBridge = 0x01,
156     EisaBridge = 0x02,
157     McaBridge = 0x03,
158     PciToPciBridge = 0x04,
159     PcmciaBridge = 0x05,
160     NuBusBridge = 0x06,
161     CardBusBridge = 0x07,
162     RaceWayBridge = 0x08,
163     PciToPciSemiTransparentBridge = 0x09,
164     InfiniBrandToPciHostBridge = 0x0a,
165     OtherBridgeDevice = 0x80,
166 }
167 
168 impl PciSubclass for PciBridgeSubclass {
get_register_value(&self) -> u8169     fn get_register_value(&self) -> u8 {
170         *self as u8
171     }
172 }
173 
174 /// Subclass of the SerialBus
175 #[allow(dead_code)]
176 #[derive(Copy, Clone)]
177 pub enum PciSerialBusSubClass {
178     Firewire = 0x00,
179     AccessBus = 0x01,
180     Ssa = 0x02,
181     Usb = 0x03,
182 }
183 
184 impl PciSubclass for PciSerialBusSubClass {
get_register_value(&self) -> u8185     fn get_register_value(&self) -> u8 {
186         *self as u8
187     }
188 }
189 
190 /// Subclasses for PciClassCode Other.
191 #[allow(dead_code)]
192 #[derive(Copy, Clone)]
193 #[repr(u8)]
194 pub enum PciOtherSubclass {
195     Other = 0xff,
196 }
197 
198 impl PciSubclass for PciOtherSubclass {
get_register_value(&self) -> u8199     fn get_register_value(&self) -> u8 {
200         *self as u8
201     }
202 }
203 
204 /// A PCI class programming interface. Each combination of `PciClassCode` and
205 /// `PciSubclass` can specify a set of register-level programming interfaces.
206 /// This trait is implemented by each programming interface.
207 /// It allows use of a trait object to generate configurations.
208 pub trait PciProgrammingInterface {
209     /// Convert this programming interface to the value used in the PCI specification.
get_register_value(&self) -> u8210     fn get_register_value(&self) -> u8;
211 }
212 
213 /// Types of PCI capabilities.
214 pub enum PciCapabilityID {
215     ListID = 0,
216     PowerManagement = 0x01,
217     AcceleratedGraphicsPort = 0x02,
218     VitalProductData = 0x03,
219     SlotIdentification = 0x04,
220     MessageSignalledInterrupts = 0x05,
221     CompactPciHotSwap = 0x06,
222     Pcix = 0x07,
223     HyperTransport = 0x08,
224     VendorSpecific = 0x09,
225     Debugport = 0x0A,
226     CompactPciCentralResourceControl = 0x0B,
227     PciStandardHotPlugController = 0x0C,
228     BridgeSubsystemVendorDeviceID = 0x0D,
229     AgpTargetPciPciBridge = 0x0E,
230     SecureDevice = 0x0F,
231     PciExpress = 0x10,
232     Msix = 0x11,
233     SataDataIndexConf = 0x12,
234     PciAdvancedFeatures = 0x13,
235     PciEnhancedAllocation = 0x14,
236 }
237 
238 /// A PCI capability list. Devices can optionally specify capabilities in their configuration space.
239 pub trait PciCapability {
bytes(&self) -> &[u8]240     fn bytes(&self) -> &[u8];
id(&self) -> PciCapabilityID241     fn id(&self) -> PciCapabilityID;
writable_bits(&self) -> Vec<u32>242     fn writable_bits(&self) -> Vec<u32>;
243 }
244 
245 /// Contains the configuration space of a PCI node.
246 /// See the [specification](https://en.wikipedia.org/wiki/PCI_configuration_space).
247 /// The configuration space is accessed with DWORD reads and writes from the guest.
248 #[derive(Serialize, Deserialize)]
249 pub struct PciConfiguration {
250     #[serde(
251         serialize_with = "serialize_arr",
252         deserialize_with = "deserialize_seq_to_arr"
253     )]
254     registers: [u32; NUM_CONFIGURATION_REGISTERS],
255     #[serde(
256         serialize_with = "serialize_arr",
257         deserialize_with = "deserialize_seq_to_arr"
258     )]
259     writable_bits: [u32; NUM_CONFIGURATION_REGISTERS], // writable bits for each register.
260     bar_used: [bool; NUM_BAR_REGS],
261     bar_configs: [Option<PciBarConfiguration>; NUM_BAR_REGS],
262     // Contains the byte offset and size of the last capability.
263     last_capability: Option<(usize, usize)>,
264 }
265 
266 /// See pci_regs.h in kernel
267 #[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
268 pub enum PciBarRegionType {
269     Memory32BitRegion = 0,
270     IoRegion = 0x01,
271     Memory64BitRegion = 0x04,
272 }
273 
274 #[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
275 pub enum PciBarPrefetchable {
276     NotPrefetchable = 0,
277     Prefetchable = 0x08,
278 }
279 
280 pub type PciBarIndex = usize;
281 
282 #[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
283 pub struct PciBarConfiguration {
284     addr: u64,
285     size: u64,
286     bar_idx: PciBarIndex,
287     region_type: PciBarRegionType,
288     prefetchable: PciBarPrefetchable,
289 }
290 
291 pub struct PciBarIter<'a> {
292     config: &'a PciConfiguration,
293     bar_num: PciBarIndex,
294 }
295 
296 impl<'a> Iterator for PciBarIter<'a> {
297     type Item = PciBarConfiguration;
298 
next(&mut self) -> Option<Self::Item>299     fn next(&mut self) -> Option<Self::Item> {
300         while self.bar_num < NUM_BAR_REGS {
301             let bar_config = self.config.get_bar_configuration(self.bar_num);
302             self.bar_num += 1;
303             if let Some(bar_config) = bar_config {
304                 return Some(bar_config);
305             }
306         }
307 
308         None
309     }
310 }
311 
312 #[sorted]
313 #[derive(Error, Debug, PartialEq, Eq)]
314 pub enum Error {
315     #[error("address {0} size {1} too big")]
316     BarAddressInvalid(u64, u64),
317     #[error("address {0} is not aligned to size {1}")]
318     BarAlignmentInvalid(u64, u64),
319     #[error("bar {0} already used")]
320     BarInUse(PciBarIndex),
321     #[error("64bit bar {0} already used (requires two regs)")]
322     BarInUse64(PciBarIndex),
323     #[error("bar {0} invalid, max {}", NUM_BAR_REGS - 1)]
324     BarInvalid(PciBarIndex),
325     #[error("64bitbar {0} invalid, requires two regs, max {}", ROM_BAR_IDX - 1)]
326     BarInvalid64(PciBarIndex),
327     #[error("expansion rom bar must be a memory region")]
328     BarInvalidRomType,
329     #[error("bar address {0} not a power of two")]
330     BarSizeInvalid(u64),
331     #[error("empty capabilities are invalid")]
332     CapabilityEmpty,
333     #[error("Invalid capability length {0}")]
334     CapabilityLengthInvalid(usize),
335     #[error("capability of size {0} doesn't fit")]
336     CapabilitySpaceFull(usize),
337 }
338 
339 pub type Result<T> = std::result::Result<T, Error>;
340 
341 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, ) -> Self342     pub fn new(
343         vendor_id: u16,
344         device_id: u16,
345         class_code: PciClassCode,
346         subclass: &dyn PciSubclass,
347         programming_interface: Option<&dyn PciProgrammingInterface>,
348         header_type: PciHeaderType,
349         subsystem_vendor_id: u16,
350         subsystem_id: u16,
351         revision_id: u8,
352     ) -> Self {
353         let mut registers = [0u32; NUM_CONFIGURATION_REGISTERS];
354         let mut writable_bits = [0u32; NUM_CONFIGURATION_REGISTERS];
355         registers[0] = u32::from(device_id) << 16 | u32::from(vendor_id);
356         // TODO(dverkamp): Status should be write-1-to-clear
357         writable_bits[1] = 0x0000_ffff; // Status (r/o), command (r/w)
358         let pi = if let Some(pi) = programming_interface {
359             pi.get_register_value()
360         } else {
361             0
362         };
363         registers[2] = u32::from(class_code.get_register_value()) << 24
364             | u32::from(subclass.get_register_value()) << 16
365             | u32::from(pi) << 8
366             | u32::from(revision_id);
367         writable_bits[3] = 0x0000_00ff; // Cacheline size (r/w)
368         match header_type {
369             PciHeaderType::Device => {
370                 registers[3] = 0x0000_0000; // Header type 0 (device)
371                 writable_bits[15] = 0x0000_00ff; // Interrupt line (r/w)
372                 registers[11] = u32::from(subsystem_id) << 16 | u32::from(subsystem_vendor_id);
373             }
374             PciHeaderType::Bridge => {
375                 registers[3] = 0x0001_0000; // Header type 1 (bridge)
376                 writable_bits[6] = 0x00ff_ffff; // Primary/secondary/subordinate bus number,
377                                                 // secondary latency timer
378                 registers[7] = 0x0000_00f0; // IO base > IO Limit, no IO address on secondary side at initialize
379                 writable_bits[7] = 0xf900_0000; // IO base and limit, secondary status,
380                 registers[8] = 0x0000_fff0; // mem base > mem Limit, no MMIO address on secondary side at initialize
381                 writable_bits[8] = 0xfff0_fff0; // Memory base and limit
382                 registers[9] = 0x0001_fff1; // pmem base > pmem Limit, no prefetch MMIO address on secondary side at initialize
383                 writable_bits[9] = 0xfff0_fff0; // Prefetchable base and limit
384                 writable_bits[10] = 0xffff_ffff; // Prefetchable base upper 32 bits
385                 writable_bits[11] = 0xffff_ffff; // Prefetchable limit upper 32 bits
386                 writable_bits[15] = 0xffff_00ff; // Bridge control (r/w), interrupt line (r/w)
387             }
388         };
389 
390         PciConfiguration {
391             registers,
392             writable_bits,
393             bar_used: [false; NUM_BAR_REGS],
394             bar_configs: [None; NUM_BAR_REGS],
395             last_capability: None,
396         }
397     }
398 
399     /// Reads a 32bit register from `reg_idx` in the register map.
read_reg(&self, reg_idx: usize) -> u32400     pub fn read_reg(&self, reg_idx: usize) -> u32 {
401         *(self.registers.get(reg_idx).unwrap_or(&0xffff_ffff))
402     }
403 
404     /// Writes data to PciConfiguration.registers.
405     /// `reg_idx` - index into PciConfiguration.registers.
406     /// `offset`  - PciConfiguration.registers is in unit of DWord, offset define byte
407     ///             offset in the DWrod.
408     /// `data`    - The data to write.
write_reg(&mut self, reg_idx: usize, offset: u64, data: &[u8])409     pub fn write_reg(&mut self, reg_idx: usize, offset: u64, data: &[u8]) {
410         let reg_offset = reg_idx * 4 + offset as usize;
411         match data.len() {
412             1 => self.write_byte(reg_offset, data[0]),
413             2 => self.write_word(reg_offset, u16::from_le_bytes(data.try_into().unwrap())),
414             4 => self.write_dword(reg_offset, u32::from_le_bytes(data.try_into().unwrap())),
415             _ => (),
416         }
417     }
418 
419     /// Writes a 32bit dword to `offset`. `offset` must be 32bit aligned.
write_dword(&mut self, offset: usize, value: u32)420     fn write_dword(&mut self, offset: usize, value: u32) {
421         if offset % 4 != 0 {
422             warn!("bad PCI config dword write offset {}", offset);
423             return;
424         }
425         let reg_idx = offset / 4;
426         if let Some(r) = self.registers.get_mut(reg_idx) {
427             *r = (*r & !self.writable_bits[reg_idx]) | (value & self.writable_bits[reg_idx]);
428         } else {
429             warn!("bad PCI dword write {}", offset);
430         }
431     }
432 
433     /// Writes a 16bit word to `offset`. `offset` must be 16bit aligned.
write_word(&mut self, offset: usize, value: u16)434     fn write_word(&mut self, offset: usize, value: u16) {
435         let shift = match offset % 4 {
436             0 => 0,
437             2 => 16,
438             _ => {
439                 warn!("bad PCI config word write offset {}", offset);
440                 return;
441             }
442         };
443         let reg_idx = offset / 4;
444 
445         if let Some(r) = self.registers.get_mut(reg_idx) {
446             let writable_mask = self.writable_bits[reg_idx];
447             let mask = (0xffffu32 << shift) & writable_mask;
448             let shifted_value = (u32::from(value) << shift) & writable_mask;
449             *r = *r & !mask | shifted_value;
450         } else {
451             warn!("bad PCI config word write offset {}", offset);
452         }
453     }
454 
455     /// Writes a byte to `offset`.
write_byte(&mut self, offset: usize, value: u8)456     fn write_byte(&mut self, offset: usize, value: u8) {
457         self.write_byte_internal(offset, value, true);
458     }
459 
460     /// Writes a byte to `offset`, optionally enforcing read-only bits.
write_byte_internal(&mut self, offset: usize, value: u8, apply_writable_mask: bool)461     fn write_byte_internal(&mut self, offset: usize, value: u8, apply_writable_mask: bool) {
462         let shift = (offset % 4) * 8;
463         let reg_idx = offset / 4;
464 
465         if let Some(r) = self.registers.get_mut(reg_idx) {
466             let writable_mask = if apply_writable_mask {
467                 self.writable_bits[reg_idx]
468             } else {
469                 0xffff_ffff
470             };
471             let mask = (0xffu32 << shift) & writable_mask;
472             let shifted_value = (u32::from(value) << shift) & writable_mask;
473             *r = *r & !mask | shifted_value;
474         } else {
475             warn!("bad PCI config byte write offset {}", offset);
476         }
477     }
478 
479     /// Adds a region specified by `config`.  Configures the specified BAR(s) to
480     /// report this region and size to the guest kernel.  Enforces a few constraints
481     /// (i.e, region size must be power of two, register not already used). Returns 'None' on
482     /// failure all, `Some(BarIndex)` on success.
add_pci_bar(&mut self, config: PciBarConfiguration) -> Result<PciBarIndex>483     pub fn add_pci_bar(&mut self, config: PciBarConfiguration) -> Result<PciBarIndex> {
484         if config.bar_idx >= NUM_BAR_REGS {
485             return Err(Error::BarInvalid(config.bar_idx));
486         }
487 
488         if self.bar_used[config.bar_idx] {
489             return Err(Error::BarInUse(config.bar_idx));
490         }
491 
492         if config.size.count_ones() != 1 {
493             return Err(Error::BarSizeInvalid(config.size));
494         }
495 
496         if config.is_expansion_rom() && config.region_type != PciBarRegionType::Memory32BitRegion {
497             return Err(Error::BarInvalidRomType);
498         }
499 
500         let min_size = if config.is_expansion_rom() {
501             BAR_ROM_MIN_SIZE
502         } else if config.region_type == PciBarRegionType::IoRegion {
503             BAR_IO_MIN_SIZE
504         } else {
505             BAR_MEM_MIN_SIZE
506         };
507 
508         if config.size < min_size {
509             return Err(Error::BarSizeInvalid(config.size));
510         }
511 
512         if config.addr % config.size != 0 {
513             return Err(Error::BarAlignmentInvalid(config.addr, config.size));
514         }
515 
516         let reg_idx = config.reg_index();
517         let end_addr = config
518             .addr
519             .checked_add(config.size)
520             .ok_or(Error::BarAddressInvalid(config.addr, config.size))?;
521         match config.region_type {
522             PciBarRegionType::Memory32BitRegion | PciBarRegionType::IoRegion => {
523                 if end_addr > u64::from(u32::max_value()) {
524                     return Err(Error::BarAddressInvalid(config.addr, config.size));
525                 }
526             }
527             PciBarRegionType::Memory64BitRegion => {
528                 // The expansion ROM BAR cannot be used for part of a 64-bit BAR.
529                 if config.bar_idx + 1 >= ROM_BAR_IDX {
530                     return Err(Error::BarInvalid64(config.bar_idx));
531                 }
532 
533                 if end_addr > u64::max_value() {
534                     return Err(Error::BarAddressInvalid(config.addr, config.size));
535                 }
536 
537                 if self.bar_used[config.bar_idx + 1] {
538                     return Err(Error::BarInUse64(config.bar_idx));
539                 }
540 
541                 self.registers[reg_idx + 1] = (config.addr >> 32) as u32;
542                 self.writable_bits[reg_idx + 1] = !((config.size - 1) >> 32) as u32;
543                 self.bar_used[config.bar_idx + 1] = true;
544             }
545         }
546 
547         let (mask, lower_bits) = match config.region_type {
548             PciBarRegionType::Memory32BitRegion | PciBarRegionType::Memory64BitRegion => {
549                 self.registers[COMMAND_REG] |= COMMAND_REG_MEMORY_SPACE_MASK;
550                 (
551                     BAR_MEM_ADDR_MASK,
552                     config.prefetchable as u32 | config.region_type as u32,
553                 )
554             }
555             PciBarRegionType::IoRegion => {
556                 self.registers[COMMAND_REG] |= COMMAND_REG_IO_SPACE_MASK;
557                 (BAR_IO_ADDR_MASK, config.region_type as u32)
558             }
559         };
560 
561         self.registers[reg_idx] = ((config.addr as u32) & mask) | lower_bits;
562         self.writable_bits[reg_idx] = !(config.size - 1) as u32;
563         if config.is_expansion_rom() {
564             self.writable_bits[reg_idx] |= 1; // Expansion ROM enable bit.
565         }
566         self.bar_used[config.bar_idx] = true;
567         self.bar_configs[config.bar_idx] = Some(config);
568         Ok(config.bar_idx)
569     }
570 
571     /// Returns an iterator of the currently configured base address registers.
572     #[allow(dead_code)] // TODO(dverkamp): remove this once used
get_bars(&self) -> PciBarIter573     pub fn get_bars(&self) -> PciBarIter {
574         PciBarIter {
575             config: self,
576             bar_num: 0,
577         }
578     }
579 
580     /// Returns the configuration of a base address register, if present.
get_bar_configuration(&self, bar_num: usize) -> Option<PciBarConfiguration>581     pub fn get_bar_configuration(&self, bar_num: usize) -> Option<PciBarConfiguration> {
582         let config = self.bar_configs.get(bar_num)?;
583 
584         if let Some(mut config) = config {
585             let command = self.read_reg(COMMAND_REG);
586             if (config.is_memory() && (command & COMMAND_REG_MEMORY_SPACE_MASK == 0))
587                 || (config.is_io() && (command & COMMAND_REG_IO_SPACE_MASK == 0))
588             {
589                 return None;
590             }
591 
592             // The address may have been modified by the guest, so the value in bar_configs
593             // may be outdated. Replace it with the current value.
594             config.addr = self.get_bar_addr(bar_num);
595             Some(config)
596         } else {
597             None
598         }
599     }
600 
601     /// Returns the type of the given BAR region.
get_bar_type(&self, bar_num: PciBarIndex) -> Option<PciBarRegionType>602     pub fn get_bar_type(&self, bar_num: PciBarIndex) -> Option<PciBarRegionType> {
603         self.bar_configs.get(bar_num)?.map(|c| c.region_type)
604     }
605 
606     /// Returns the address of the given BAR region.
get_bar_addr(&self, bar_num: PciBarIndex) -> u64607     pub fn get_bar_addr(&self, bar_num: PciBarIndex) -> u64 {
608         let bar_idx = if bar_num == ROM_BAR_IDX {
609             ROM_BAR_REG
610         } else {
611             BAR0_REG + bar_num
612         };
613 
614         let bar_type = match self.get_bar_type(bar_num) {
615             Some(t) => t,
616             None => return 0,
617         };
618 
619         match bar_type {
620             PciBarRegionType::IoRegion => u64::from(self.registers[bar_idx] & BAR_IO_ADDR_MASK),
621             PciBarRegionType::Memory32BitRegion => {
622                 u64::from(self.registers[bar_idx] & BAR_MEM_ADDR_MASK)
623             }
624             PciBarRegionType::Memory64BitRegion => {
625                 u64::from(self.registers[bar_idx] & BAR_MEM_ADDR_MASK)
626                     | u64::from(self.registers[bar_idx + 1]) << 32
627             }
628         }
629     }
630 
631     /// Configures the IRQ line and pin used by this device.
set_irq(&mut self, line: u8, pin: PciInterruptPin)632     pub fn set_irq(&mut self, line: u8, pin: PciInterruptPin) {
633         // `pin` is 1-based in the pci config space.
634         let pin_idx = (pin as u32) + 1;
635         self.registers[INTERRUPT_LINE_PIN_REG] = (self.registers[INTERRUPT_LINE_PIN_REG]
636             & 0xffff_0000)
637             | (pin_idx << 8)
638             | u32::from(line);
639     }
640 
641     /// Adds the capability `cap_data` to the list of capabilities.
642     /// `cap_data` should include the two-byte PCI capability header (type, next),
643     /// but not populate it. Correct values will be generated automatically based
644     /// on `cap_data.id()`.
add_capability(&mut self, cap_data: &dyn PciCapability) -> Result<usize>645     pub fn add_capability(&mut self, cap_data: &dyn PciCapability) -> Result<usize> {
646         let total_len = cap_data.bytes().len();
647         // Check that the length is valid.
648         if cap_data.bytes().is_empty() {
649             return Err(Error::CapabilityEmpty);
650         }
651         let (cap_offset, tail_offset) = match self.last_capability {
652             Some((offset, len)) => (Self::next_dword(offset, len), offset + 1),
653             None => (FIRST_CAPABILITY_OFFSET, CAPABILITY_LIST_HEAD_OFFSET),
654         };
655         let end_offset = cap_offset
656             .checked_add(total_len)
657             .ok_or(Error::CapabilitySpaceFull(total_len))?;
658         if end_offset > CAPABILITY_MAX_OFFSET {
659             return Err(Error::CapabilitySpaceFull(total_len));
660         }
661         self.registers[STATUS_REG] |= STATUS_REG_CAPABILITIES_USED_MASK;
662         self.write_byte_internal(tail_offset, cap_offset as u8, false);
663         self.write_byte_internal(cap_offset, cap_data.id() as u8, false);
664         self.write_byte_internal(cap_offset + 1, 0, false); // Next pointer.
665         for (i, byte) in cap_data.bytes().iter().enumerate().skip(2) {
666             self.write_byte_internal(cap_offset + i, *byte, false);
667         }
668         let reg_idx = cap_offset / 4;
669         for (i, dword) in cap_data.writable_bits().iter().enumerate() {
670             self.writable_bits[reg_idx + i] = *dword;
671         }
672         self.last_capability = Some((cap_offset, total_len));
673         Ok(cap_offset)
674     }
675 
676     // Find the next aligned offset after the one given.
next_dword(offset: usize, len: usize) -> usize677     fn next_dword(offset: usize, len: usize) -> usize {
678         let next = offset + len;
679         (next + 3) & !3
680     }
681 
restore(&mut self, data: serde_json::Value) -> anyhow::Result<()>682     pub fn restore(&mut self, data: serde_json::Value) -> anyhow::Result<()> {
683         let deser: PciConfiguration =
684             serde_json::from_value(data).context("failed to deserialize PciConfiguration")?;
685         *self = deser;
686         Ok(())
687     }
688 }
689 
690 impl PciBarConfiguration {
new( bar_idx: PciBarIndex, size: u64, region_type: PciBarRegionType, prefetchable: PciBarPrefetchable, ) -> Self691     pub fn new(
692         bar_idx: PciBarIndex,
693         size: u64,
694         region_type: PciBarRegionType,
695         prefetchable: PciBarPrefetchable,
696     ) -> Self {
697         PciBarConfiguration {
698             bar_idx,
699             addr: 0,
700             size,
701             region_type,
702             prefetchable,
703         }
704     }
705 
bar_index(&self) -> PciBarIndex706     pub fn bar_index(&self) -> PciBarIndex {
707         self.bar_idx
708     }
709 
reg_index(&self) -> usize710     pub fn reg_index(&self) -> usize {
711         if self.bar_idx == ROM_BAR_IDX {
712             ROM_BAR_REG
713         } else {
714             BAR0_REG + self.bar_idx
715         }
716     }
717 
address(&self) -> u64718     pub fn address(&self) -> u64 {
719         self.addr
720     }
721 
address_range(&self) -> std::ops::Range<u64>722     pub fn address_range(&self) -> std::ops::Range<u64> {
723         self.addr..self.addr + self.size
724     }
725 
set_address(mut self, addr: u64) -> Self726     pub fn set_address(mut self, addr: u64) -> Self {
727         self.addr = addr;
728         self
729     }
730 
size(&self) -> u64731     pub fn size(&self) -> u64 {
732         self.size
733     }
734 
is_expansion_rom(&self) -> bool735     pub fn is_expansion_rom(&self) -> bool {
736         self.bar_idx == ROM_BAR_IDX
737     }
738 
is_memory(&self) -> bool739     pub fn is_memory(&self) -> bool {
740         matches!(
741             self.region_type,
742             PciBarRegionType::Memory32BitRegion | PciBarRegionType::Memory64BitRegion
743         )
744     }
745 
is_64bit_memory(&self) -> bool746     pub fn is_64bit_memory(&self) -> bool {
747         self.region_type == PciBarRegionType::Memory64BitRegion
748     }
749 
is_io(&self) -> bool750     pub fn is_io(&self) -> bool {
751         self.region_type == PciBarRegionType::IoRegion
752     }
753 
is_prefetchable(&self) -> bool754     pub fn is_prefetchable(&self) -> bool {
755         self.is_memory() && self.prefetchable == PciBarPrefetchable::Prefetchable
756     }
757 }
758 
759 #[cfg(test)]
760 mod tests {
761     use zerocopy::AsBytes;
762 
763     use super::*;
764 
765     #[repr(packed)]
766     #[derive(Clone, Copy, AsBytes)]
767     #[allow(dead_code)]
768     struct TestCap {
769         _vndr: u8,
770         _next: u8,
771         len: u8,
772         foo: u8,
773     }
774 
775     impl PciCapability for TestCap {
bytes(&self) -> &[u8]776         fn bytes(&self) -> &[u8] {
777             self.as_bytes()
778         }
779 
id(&self) -> PciCapabilityID780         fn id(&self) -> PciCapabilityID {
781             PciCapabilityID::VendorSpecific
782         }
783 
writable_bits(&self) -> Vec<u32>784         fn writable_bits(&self) -> Vec<u32> {
785             vec![0u32; 1]
786         }
787     }
788 
789     #[test]
add_capability()790     fn add_capability() {
791         let mut cfg = PciConfiguration::new(
792             0x1234,
793             0x5678,
794             PciClassCode::MultimediaController,
795             &PciMultimediaSubclass::AudioController,
796             None,
797             PciHeaderType::Device,
798             0xABCD,
799             0x2468,
800             0,
801         );
802 
803         // Add two capabilities with different contents.
804         let cap1 = TestCap {
805             _vndr: 0,
806             _next: 0,
807             len: 4,
808             foo: 0xAA,
809         };
810         let cap1_offset = cfg.add_capability(&cap1).unwrap();
811         assert_eq!(cap1_offset % 4, 0);
812 
813         let cap2 = TestCap {
814             _vndr: 0,
815             _next: 0,
816             len: 0x04,
817             foo: 0x55,
818         };
819         let cap2_offset = cfg.add_capability(&cap2).unwrap();
820         assert_eq!(cap2_offset % 4, 0);
821 
822         // The capability list head should be pointing to cap1.
823         let cap_ptr = cfg.read_reg(CAPABILITY_LIST_HEAD_OFFSET / 4) & 0xFF;
824         assert_eq!(cap1_offset, cap_ptr as usize);
825 
826         // Verify the contents of the capabilities.
827         let cap1_data = cfg.read_reg(cap1_offset / 4);
828         assert_eq!(cap1_data & 0xFF, 0x09); // capability ID
829         assert_eq!((cap1_data >> 8) & 0xFF, cap2_offset as u32); // next capability pointer
830         assert_eq!((cap1_data >> 16) & 0xFF, 0x04); // cap1.len
831         assert_eq!((cap1_data >> 24) & 0xFF, 0xAA); // cap1.foo
832 
833         let cap2_data = cfg.read_reg(cap2_offset / 4);
834         assert_eq!(cap2_data & 0xFF, 0x09); // capability ID
835         assert_eq!((cap2_data >> 8) & 0xFF, 0x00); // next capability pointer
836         assert_eq!((cap2_data >> 16) & 0xFF, 0x04); // cap2.len
837         assert_eq!((cap2_data >> 24) & 0xFF, 0x55); // cap2.foo
838     }
839 
840     #[derive(Copy, Clone)]
841     enum TestPI {
842         Test = 0x5a,
843     }
844 
845     impl PciProgrammingInterface for TestPI {
get_register_value(&self) -> u8846         fn get_register_value(&self) -> u8 {
847             *self as u8
848         }
849     }
850 
851     #[test]
class_code()852     fn class_code() {
853         let cfg = PciConfiguration::new(
854             0x1234,
855             0x5678,
856             PciClassCode::MultimediaController,
857             &PciMultimediaSubclass::AudioController,
858             Some(&TestPI::Test),
859             PciHeaderType::Device,
860             0xABCD,
861             0x2468,
862             0,
863         );
864 
865         let class_reg = cfg.read_reg(2);
866         let class_code = (class_reg >> 24) & 0xFF;
867         let subclass = (class_reg >> 16) & 0xFF;
868         let prog_if = (class_reg >> 8) & 0xFF;
869         assert_eq!(class_code, 0x04);
870         assert_eq!(subclass, 0x01);
871         assert_eq!(prog_if, 0x5a);
872     }
873 
874     #[test]
read_only_bits()875     fn read_only_bits() {
876         let mut cfg = PciConfiguration::new(
877             0x1234,
878             0x5678,
879             PciClassCode::MultimediaController,
880             &PciMultimediaSubclass::AudioController,
881             Some(&TestPI::Test),
882             PciHeaderType::Device,
883             0xABCD,
884             0x2468,
885             0,
886         );
887 
888         // Attempt to overwrite vendor ID and device ID, which are read-only
889         cfg.write_reg(0, 0, &[0xBA, 0xAD, 0xF0, 0x0D]);
890         // The original vendor and device ID should remain.
891         assert_eq!(cfg.read_reg(0), 0x56781234);
892     }
893 
894     #[test]
query_unused_bar()895     fn query_unused_bar() {
896         let cfg = PciConfiguration::new(
897             0x1234,
898             0x5678,
899             PciClassCode::MultimediaController,
900             &PciMultimediaSubclass::AudioController,
901             Some(&TestPI::Test),
902             PciHeaderType::Device,
903             0xABCD,
904             0x2468,
905             0,
906         );
907 
908         // No BAR 0 has been configured, so these should return None or 0 as appropriate.
909         assert_eq!(cfg.get_bar_type(0), None);
910         assert_eq!(cfg.get_bar_addr(0), 0);
911 
912         let mut bar_iter = cfg.get_bars();
913         assert_eq!(bar_iter.next(), None);
914     }
915 
916     #[test]
add_pci_bar_mem_64bit()917     fn add_pci_bar_mem_64bit() {
918         let mut cfg = PciConfiguration::new(
919             0x1234,
920             0x5678,
921             PciClassCode::MultimediaController,
922             &PciMultimediaSubclass::AudioController,
923             Some(&TestPI::Test),
924             PciHeaderType::Device,
925             0xABCD,
926             0x2468,
927             0,
928         );
929 
930         cfg.add_pci_bar(
931             PciBarConfiguration::new(
932                 0,
933                 0x10,
934                 PciBarRegionType::Memory64BitRegion,
935                 PciBarPrefetchable::NotPrefetchable,
936             )
937             .set_address(0x0123_4567_89AB_CDE0),
938         )
939         .expect("add_pci_bar failed");
940 
941         assert_eq!(
942             cfg.get_bar_type(0),
943             Some(PciBarRegionType::Memory64BitRegion)
944         );
945         assert_eq!(cfg.get_bar_addr(0), 0x0123_4567_89AB_CDE0);
946         assert_eq!(cfg.writable_bits[BAR0_REG + 1], 0xFFFFFFFF);
947         assert_eq!(cfg.writable_bits[BAR0_REG + 0], 0xFFFFFFF0);
948 
949         let mut bar_iter = cfg.get_bars();
950         assert_eq!(
951             bar_iter.next(),
952             Some(PciBarConfiguration {
953                 addr: 0x0123_4567_89AB_CDE0,
954                 size: 0x10,
955                 bar_idx: 0,
956                 region_type: PciBarRegionType::Memory64BitRegion,
957                 prefetchable: PciBarPrefetchable::NotPrefetchable
958             })
959         );
960         assert_eq!(bar_iter.next(), None);
961     }
962 
963     #[test]
add_pci_bar_mem_32bit()964     fn add_pci_bar_mem_32bit() {
965         let mut cfg = PciConfiguration::new(
966             0x1234,
967             0x5678,
968             PciClassCode::MultimediaController,
969             &PciMultimediaSubclass::AudioController,
970             Some(&TestPI::Test),
971             PciHeaderType::Device,
972             0xABCD,
973             0x2468,
974             0,
975         );
976 
977         cfg.add_pci_bar(
978             PciBarConfiguration::new(
979                 0,
980                 0x10,
981                 PciBarRegionType::Memory32BitRegion,
982                 PciBarPrefetchable::NotPrefetchable,
983             )
984             .set_address(0x12345670),
985         )
986         .expect("add_pci_bar failed");
987 
988         assert_eq!(
989             cfg.get_bar_type(0),
990             Some(PciBarRegionType::Memory32BitRegion)
991         );
992         assert_eq!(cfg.get_bar_addr(0), 0x12345670);
993         assert_eq!(cfg.writable_bits[BAR0_REG], 0xFFFFFFF0);
994 
995         let mut bar_iter = cfg.get_bars();
996         assert_eq!(
997             bar_iter.next(),
998             Some(PciBarConfiguration {
999                 addr: 0x12345670,
1000                 size: 0x10,
1001                 bar_idx: 0,
1002                 region_type: PciBarRegionType::Memory32BitRegion,
1003                 prefetchable: PciBarPrefetchable::NotPrefetchable
1004             })
1005         );
1006         assert_eq!(bar_iter.next(), None);
1007     }
1008 
1009     #[test]
add_pci_bar_io()1010     fn add_pci_bar_io() {
1011         let mut cfg = PciConfiguration::new(
1012             0x1234,
1013             0x5678,
1014             PciClassCode::MultimediaController,
1015             &PciMultimediaSubclass::AudioController,
1016             Some(&TestPI::Test),
1017             PciHeaderType::Device,
1018             0xABCD,
1019             0x2468,
1020             0,
1021         );
1022 
1023         cfg.add_pci_bar(
1024             PciBarConfiguration::new(
1025                 0,
1026                 0x4,
1027                 PciBarRegionType::IoRegion,
1028                 PciBarPrefetchable::NotPrefetchable,
1029             )
1030             .set_address(0x1230),
1031         )
1032         .expect("add_pci_bar failed");
1033 
1034         assert_eq!(cfg.get_bar_type(0), Some(PciBarRegionType::IoRegion));
1035         assert_eq!(cfg.get_bar_addr(0), 0x1230);
1036         assert_eq!(cfg.writable_bits[BAR0_REG], 0xFFFFFFFC);
1037 
1038         let mut bar_iter = cfg.get_bars();
1039         assert_eq!(
1040             bar_iter.next(),
1041             Some(PciBarConfiguration {
1042                 addr: 0x1230,
1043                 size: 0x4,
1044                 bar_idx: 0,
1045                 region_type: PciBarRegionType::IoRegion,
1046                 prefetchable: PciBarPrefetchable::NotPrefetchable
1047             })
1048         );
1049         assert_eq!(bar_iter.next(), None);
1050     }
1051 
1052     #[test]
add_pci_bar_multiple()1053     fn add_pci_bar_multiple() {
1054         let mut cfg = PciConfiguration::new(
1055             0x1234,
1056             0x5678,
1057             PciClassCode::MultimediaController,
1058             &PciMultimediaSubclass::AudioController,
1059             Some(&TestPI::Test),
1060             PciHeaderType::Device,
1061             0xABCD,
1062             0x2468,
1063             0,
1064         );
1065 
1066         // bar_num 0-1: 64-bit memory
1067         cfg.add_pci_bar(
1068             PciBarConfiguration::new(
1069                 0,
1070                 0x10,
1071                 PciBarRegionType::Memory64BitRegion,
1072                 PciBarPrefetchable::NotPrefetchable,
1073             )
1074             .set_address(0x0123_4567_89AB_CDE0),
1075         )
1076         .expect("add_pci_bar failed");
1077 
1078         // bar 2: 32-bit memory
1079         cfg.add_pci_bar(
1080             PciBarConfiguration::new(
1081                 2,
1082                 0x10,
1083                 PciBarRegionType::Memory32BitRegion,
1084                 PciBarPrefetchable::NotPrefetchable,
1085             )
1086             .set_address(0x12345670),
1087         )
1088         .expect("add_pci_bar failed");
1089 
1090         // bar 3: I/O
1091         cfg.add_pci_bar(
1092             PciBarConfiguration::new(
1093                 3,
1094                 0x4,
1095                 PciBarRegionType::IoRegion,
1096                 PciBarPrefetchable::NotPrefetchable,
1097             )
1098             .set_address(0x1230),
1099         )
1100         .expect("add_pci_bar failed");
1101 
1102         // Confirm default memory and I/O region configurations.
1103         let mut bar_iter = cfg.get_bars();
1104         assert_eq!(
1105             bar_iter.next(),
1106             Some(PciBarConfiguration {
1107                 addr: 0x0123_4567_89AB_CDE0,
1108                 size: 0x10,
1109                 bar_idx: 0,
1110                 region_type: PciBarRegionType::Memory64BitRegion,
1111                 prefetchable: PciBarPrefetchable::NotPrefetchable
1112             })
1113         );
1114         assert_eq!(
1115             bar_iter.next(),
1116             Some(PciBarConfiguration {
1117                 addr: 0x12345670,
1118                 size: 0x10,
1119                 bar_idx: 2,
1120                 region_type: PciBarRegionType::Memory32BitRegion,
1121                 prefetchable: PciBarPrefetchable::NotPrefetchable
1122             })
1123         );
1124         assert_eq!(
1125             bar_iter.next(),
1126             Some(PciBarConfiguration {
1127                 addr: 0x1230,
1128                 size: 0x4,
1129                 bar_idx: 3,
1130                 region_type: PciBarRegionType::IoRegion,
1131                 prefetchable: PciBarPrefetchable::NotPrefetchable
1132             })
1133         );
1134         assert_eq!(bar_iter.next(), None);
1135 
1136         // Reassign the address for BAR 0 and verify that get_memory_regions() matches.
1137         cfg.write_reg(4 + 0, 0, &0xBBAA9980u32.to_le_bytes());
1138         cfg.write_reg(4 + 1, 0, &0xFFEEDDCCu32.to_le_bytes());
1139 
1140         let mut bar_iter = cfg.get_bars();
1141         assert_eq!(
1142             bar_iter.next(),
1143             Some(PciBarConfiguration {
1144                 addr: 0xFFEE_DDCC_BBAA_9980,
1145                 size: 0x10,
1146                 bar_idx: 0,
1147                 region_type: PciBarRegionType::Memory64BitRegion,
1148                 prefetchable: PciBarPrefetchable::NotPrefetchable
1149             })
1150         );
1151         assert_eq!(
1152             bar_iter.next(),
1153             Some(PciBarConfiguration {
1154                 addr: 0x12345670,
1155                 size: 0x10,
1156                 bar_idx: 2,
1157                 region_type: PciBarRegionType::Memory32BitRegion,
1158                 prefetchable: PciBarPrefetchable::NotPrefetchable
1159             })
1160         );
1161         assert_eq!(
1162             bar_iter.next(),
1163             Some(PciBarConfiguration {
1164                 addr: 0x1230,
1165                 size: 0x4,
1166                 bar_idx: 3,
1167                 region_type: PciBarRegionType::IoRegion,
1168                 prefetchable: PciBarPrefetchable::NotPrefetchable
1169             })
1170         );
1171         assert_eq!(bar_iter.next(), None);
1172     }
1173 
1174     #[test]
add_pci_bar_invalid_size()1175     fn add_pci_bar_invalid_size() {
1176         let mut cfg = PciConfiguration::new(
1177             0x1234,
1178             0x5678,
1179             PciClassCode::MultimediaController,
1180             &PciMultimediaSubclass::AudioController,
1181             Some(&TestPI::Test),
1182             PciHeaderType::Device,
1183             0xABCD,
1184             0x2468,
1185             0,
1186         );
1187 
1188         // I/O BAR with size 2 (too small)
1189         assert_eq!(
1190             cfg.add_pci_bar(
1191                 PciBarConfiguration::new(
1192                     0,
1193                     0x2,
1194                     PciBarRegionType::IoRegion,
1195                     PciBarPrefetchable::NotPrefetchable,
1196                 )
1197                 .set_address(0x1230),
1198             ),
1199             Err(Error::BarSizeInvalid(0x2))
1200         );
1201 
1202         // I/O BAR with size 3 (not a power of 2)
1203         assert_eq!(
1204             cfg.add_pci_bar(
1205                 PciBarConfiguration::new(
1206                     0,
1207                     0x3,
1208                     PciBarRegionType::IoRegion,
1209                     PciBarPrefetchable::NotPrefetchable,
1210                 )
1211                 .set_address(0x1230),
1212             ),
1213             Err(Error::BarSizeInvalid(0x3))
1214         );
1215 
1216         // Memory BAR with size 8 (too small)
1217         assert_eq!(
1218             cfg.add_pci_bar(
1219                 PciBarConfiguration::new(
1220                     0,
1221                     0x8,
1222                     PciBarRegionType::Memory32BitRegion,
1223                     PciBarPrefetchable::NotPrefetchable,
1224                 )
1225                 .set_address(0x12345670),
1226             ),
1227             Err(Error::BarSizeInvalid(0x8))
1228         );
1229     }
1230 
1231     #[test]
add_rom_bar()1232     fn add_rom_bar() {
1233         let mut cfg = PciConfiguration::new(
1234             0x1234,
1235             0x5678,
1236             PciClassCode::MultimediaController,
1237             &PciMultimediaSubclass::AudioController,
1238             Some(&TestPI::Test),
1239             PciHeaderType::Device,
1240             0xABCD,
1241             0x2468,
1242             0,
1243         );
1244 
1245         // Attempt to add a 64-bit memory BAR as the expansion ROM (invalid).
1246         assert_eq!(
1247             cfg.add_pci_bar(PciBarConfiguration::new(
1248                 ROM_BAR_IDX,
1249                 0x1000,
1250                 PciBarRegionType::Memory64BitRegion,
1251                 PciBarPrefetchable::NotPrefetchable,
1252             ),),
1253             Err(Error::BarInvalidRomType)
1254         );
1255 
1256         // Attempt to add an I/O BAR as the expansion ROM (invalid).
1257         assert_eq!(
1258             cfg.add_pci_bar(PciBarConfiguration::new(
1259                 ROM_BAR_IDX,
1260                 0x1000,
1261                 PciBarRegionType::IoRegion,
1262                 PciBarPrefetchable::NotPrefetchable,
1263             ),),
1264             Err(Error::BarInvalidRomType)
1265         );
1266 
1267         // Attempt to add a 1KB memory region as the expansion ROM (too small).
1268         assert_eq!(
1269             cfg.add_pci_bar(PciBarConfiguration::new(
1270                 ROM_BAR_IDX,
1271                 1024,
1272                 PciBarRegionType::Memory32BitRegion,
1273                 PciBarPrefetchable::NotPrefetchable,
1274             ),),
1275             Err(Error::BarSizeInvalid(1024))
1276         );
1277 
1278         // Add a 32-bit memory BAR as the expansion ROM (valid).
1279         cfg.add_pci_bar(
1280             PciBarConfiguration::new(
1281                 ROM_BAR_IDX,
1282                 0x800,
1283                 PciBarRegionType::Memory32BitRegion,
1284                 PciBarPrefetchable::NotPrefetchable,
1285             )
1286             .set_address(0x12345000),
1287         )
1288         .expect("add_pci_bar failed");
1289 
1290         assert_eq!(
1291             cfg.get_bar_type(ROM_BAR_IDX),
1292             Some(PciBarRegionType::Memory32BitRegion)
1293         );
1294         assert_eq!(cfg.get_bar_addr(ROM_BAR_IDX), 0x12345000);
1295         assert_eq!(cfg.read_reg(ROM_BAR_REG), 0x12345000);
1296         assert_eq!(cfg.writable_bits[ROM_BAR_REG], 0xFFFFF801);
1297     }
1298 
1299     #[test]
pci_configuration_capability_snapshot_restore() -> anyhow::Result<()>1300     fn pci_configuration_capability_snapshot_restore() -> anyhow::Result<()> {
1301         let mut cfg = PciConfiguration::new(
1302             0x1234,
1303             0x5678,
1304             PciClassCode::MultimediaController,
1305             &PciMultimediaSubclass::AudioController,
1306             Some(&TestPI::Test),
1307             PciHeaderType::Device,
1308             0xABCD,
1309             0x2468,
1310             0,
1311         );
1312 
1313         let snap_init = serde_json::to_value(&cfg).context("failed to snapshot")?;
1314 
1315         // Add a capability.
1316         let cap1 = TestCap {
1317             _vndr: 0,
1318             _next: 0,
1319             len: 4,
1320             foo: 0xAA,
1321         };
1322         cfg.add_capability(&cap1).unwrap();
1323 
1324         let snap_mod = serde_json::to_value(&cfg).context("failed to snapshot mod")?;
1325         cfg.restore(snap_init.clone())
1326             .context("failed to restore snap_init")?;
1327         let snap_restore_init =
1328             serde_json::to_value(&cfg).context("failed to snapshot restored_init")?;
1329         assert_eq!(snap_init, snap_restore_init);
1330         assert_ne!(snap_init, snap_mod);
1331         cfg.restore(snap_mod.clone())
1332             .context("failed to restore snap_init")?;
1333         let snap_restore_mod =
1334             serde_json::to_value(&cfg).context("failed to snapshot restored_mod")?;
1335         assert_eq!(snap_mod, snap_restore_mod);
1336         Ok(())
1337     }
1338 
1339     #[test]
pci_configuration_pci_bar_snapshot_restore() -> anyhow::Result<()>1340     fn pci_configuration_pci_bar_snapshot_restore() -> anyhow::Result<()> {
1341         let mut cfg = PciConfiguration::new(
1342             0x1234,
1343             0x5678,
1344             PciClassCode::MultimediaController,
1345             &PciMultimediaSubclass::AudioController,
1346             Some(&TestPI::Test),
1347             PciHeaderType::Device,
1348             0xABCD,
1349             0x2468,
1350             0,
1351         );
1352 
1353         let snap_init = serde_json::to_value(&cfg).context("failed to snapshot")?;
1354 
1355         // bar_num 0-1: 64-bit memory
1356         cfg.add_pci_bar(
1357             PciBarConfiguration::new(
1358                 0,
1359                 0x10,
1360                 PciBarRegionType::Memory64BitRegion,
1361                 PciBarPrefetchable::NotPrefetchable,
1362             )
1363             .set_address(0x0123_4567_89AB_CDE0),
1364         )
1365         .expect("add_pci_bar failed");
1366 
1367         let snap_mod = serde_json::to_value(&cfg).context("failed to snapshot mod")?;
1368         cfg.restore(snap_init.clone())
1369             .context("failed to restore snap_init")?;
1370         let snap_restore_init =
1371             serde_json::to_value(&cfg).context("failed to snapshot restored_init")?;
1372         assert_eq!(snap_init, snap_restore_init);
1373         assert_ne!(snap_init, snap_mod);
1374         cfg.restore(snap_mod.clone())
1375             .context("failed to restore snap_init")?;
1376         let snap_restore_mod =
1377             serde_json::to_value(&cfg).context("failed to snapshot restored_mod")?;
1378         assert_eq!(snap_mod, snap_restore_mod);
1379         Ok(())
1380     }
1381 
1382     #[test]
pci_configuration_capability_pci_bar_snapshot_restore() -> anyhow::Result<()>1383     fn pci_configuration_capability_pci_bar_snapshot_restore() -> anyhow::Result<()> {
1384         let mut cfg = PciConfiguration::new(
1385             0x1234,
1386             0x5678,
1387             PciClassCode::MultimediaController,
1388             &PciMultimediaSubclass::AudioController,
1389             Some(&TestPI::Test),
1390             PciHeaderType::Device,
1391             0xABCD,
1392             0x2468,
1393             0,
1394         );
1395 
1396         let snap_init = serde_json::to_value(&cfg).context("failed to snapshot")?;
1397 
1398         // Add a capability.
1399         let cap1 = TestCap {
1400             _vndr: 0,
1401             _next: 0,
1402             len: 4,
1403             foo: 0xAA,
1404         };
1405         cfg.add_capability(&cap1).unwrap();
1406 
1407         // bar_num 0-1: 64-bit memory
1408         cfg.add_pci_bar(
1409             PciBarConfiguration::new(
1410                 0,
1411                 0x10,
1412                 PciBarRegionType::Memory64BitRegion,
1413                 PciBarPrefetchable::NotPrefetchable,
1414             )
1415             .set_address(0x0123_4567_89AB_CDE0),
1416         )
1417         .expect("add_pci_bar failed");
1418 
1419         let snap_mod = serde_json::to_value(&cfg).context("failed to snapshot mod")?;
1420         cfg.restore(snap_init.clone())
1421             .context("failed to restore snap_init")?;
1422         let snap_restore_init =
1423             serde_json::to_value(&cfg).context("failed to snapshot restored_init")?;
1424         assert_eq!(snap_init, snap_restore_init);
1425         assert_ne!(snap_init, snap_mod);
1426         cfg.restore(snap_mod.clone())
1427             .context("failed to restore snap_init")?;
1428         let snap_restore_mod =
1429             serde_json::to_value(&cfg).context("failed to snapshot restored_mod")?;
1430         assert_eq!(snap_mod, snap_restore_mod);
1431         Ok(())
1432     }
1433 }
1434