devices/pci/
pci_configuration.rs

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