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