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