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 at initialize
515                writable_bits[7] = 0xf900_0000; // IO base and limit, secondary status,
516                registers[8] = 0x0000_fff0; // mem base > mem Limit, no MMIO address on secondary side at initialize
517                writable_bits[8] = 0xfff0_fff0; // Memory base and limit
518                registers[9] = 0x0001_fff1; // pmem base > pmem Limit, no prefetch MMIO address on secondary side at initialize
519                writable_bits[9] = 0xfff0_fff0; // Prefetchable base and limit
520                writable_bits[10] = 0xffff_ffff; // Prefetchable base upper 32 bits
521                writable_bits[11] = 0xffff_ffff; // Prefetchable limit upper 32 bits
522                writable_bits[15] = 0xffff_00ff; // Bridge control (r/w), interrupt line (r/w)
523            }
524        };
525
526        PciConfiguration {
527            registers,
528            writable_bits,
529            bar_used: [false; NUM_BAR_REGS],
530            bar_configs: [None; NUM_BAR_REGS],
531            last_capability: None,
532            capability_configs: BTreeMap::new(),
533            mmio_mapping: None,
534        }
535    }
536
537    /// Reads a 32bit register from `reg_idx` in the register map.
538    pub fn read_reg(&self, reg_idx: usize) -> u32 {
539        let mut data = *(self.registers.get(reg_idx).unwrap_or(&0xffff_ffff));
540        if let Some((idx, cfg)) = self.capability_configs.range(..=reg_idx).last() {
541            if reg_idx < idx + cfg.num_regs() {
542                let cap_idx = reg_idx - idx;
543                let mask = cfg.read_mask()[cap_idx];
544                data = (data & !mask) | (cfg.read_reg(cap_idx) & mask);
545            }
546        }
547        data
548    }
549
550    /// Writes data to PciConfiguration.registers.
551    /// `reg_idx` - index into PciConfiguration.registers.
552    /// `offset`  - PciConfiguration.registers is in unit of DWord, offset define byte
553    ///             offset in the DWord.
554    /// `data`    - The data to write.
555    pub fn write_reg(
556        &mut self,
557        reg_idx: usize,
558        offset: u64,
559        data: &[u8],
560    ) -> Option<Box<dyn PciCapConfigWriteResult>> {
561        let reg_offset = reg_idx * 4 + offset as usize;
562        match data.len() {
563            1 => self.write_byte(reg_offset, data[0]),
564            2 => self.write_word(reg_offset, u16::from_le_bytes(data.try_into().unwrap())),
565            4 => self.write_dword(reg_offset, u32::from_le_bytes(data.try_into().unwrap())),
566            _ => (),
567        }
568        if let Some((idx, cfg)) = self.capability_configs.range_mut(..=reg_idx).last() {
569            if reg_idx < idx + cfg.num_regs() {
570                let cap_idx = reg_idx - idx;
571                let ret = cfg.write_reg(cap_idx, offset, data);
572                let new_val = cfg.read_reg(cap_idx);
573                let mask = cfg.read_mask()[cap_idx];
574                self.set_reg(reg_idx, new_val, mask);
575                return ret;
576            }
577        }
578        None
579    }
580
581    /// Writes a 32bit dword to `offset`. `offset` must be 32bit aligned.
582    fn write_dword(&mut self, offset: usize, value: u32) {
583        if offset % 4 != 0 {
584            warn!("bad PCI config dword write offset {}", offset);
585            return;
586        }
587        let reg_idx = offset / 4;
588        if reg_idx < NUM_CONFIGURATION_REGISTERS {
589            let old_value = self.registers[reg_idx];
590            let new_value =
591                (old_value & !self.writable_bits[reg_idx]) | (value & self.writable_bits[reg_idx]);
592            self.do_write(reg_idx, new_value)
593        } else {
594            warn!("bad PCI dword write {}", offset);
595        }
596    }
597
598    /// Writes a 16bit word to `offset`. `offset` must be 16bit aligned.
599    fn write_word(&mut self, offset: usize, value: u16) {
600        let shift = match offset % 4 {
601            0 => 0,
602            2 => 16,
603            _ => {
604                warn!("bad PCI config word write offset {}", offset);
605                return;
606            }
607        };
608        let reg_idx = offset / 4;
609
610        if reg_idx < NUM_CONFIGURATION_REGISTERS {
611            let old_value = self.registers[reg_idx];
612            let writable_mask = self.writable_bits[reg_idx];
613            let mask = (0xffffu32 << shift) & writable_mask;
614            let shifted_value = (u32::from(value) << shift) & writable_mask;
615            let new_value = old_value & !mask | shifted_value;
616            self.do_write(reg_idx, new_value)
617        } else {
618            warn!("bad PCI config word write offset {}", offset);
619        }
620    }
621
622    /// Writes a byte to `offset`.
623    fn write_byte(&mut self, offset: usize, value: u8) {
624        self.write_byte_internal(offset, value, true);
625    }
626
627    /// Writes a byte to `offset`, optionally enforcing read-only bits.
628    fn write_byte_internal(&mut self, offset: usize, value: u8, apply_writable_mask: bool) {
629        let shift = (offset % 4) * 8;
630        let reg_idx = offset / 4;
631
632        if reg_idx < NUM_CONFIGURATION_REGISTERS {
633            let writable_mask = if apply_writable_mask {
634                self.writable_bits[reg_idx]
635            } else {
636                0xffff_ffff
637            };
638            let old_value = self.registers[reg_idx];
639            let mask = (0xffu32 << shift) & writable_mask;
640            let shifted_value = (u32::from(value) << shift) & writable_mask;
641            let new_value = old_value & !mask | shifted_value;
642            self.do_write(reg_idx, new_value)
643        } else {
644            warn!("bad PCI config byte write offset {}", offset);
645        }
646    }
647
648    /// Sets the value of a PciConfiguration register. This should be used when
649    /// device-internal events require changing the configuration space - as such,
650    /// the writable bits masks do not apply.
651    /// `reg_idx` - index into PciConfiguration.registers.
652    /// `data`    - The data to write.
653    /// `mask`    - The mask of which bits to modify.
654    pub fn set_reg(&mut self, reg_idx: usize, data: u32, mask: u32) {
655        if reg_idx >= NUM_CONFIGURATION_REGISTERS {
656            return;
657        }
658        let new_val = (self.registers[reg_idx] & !mask) | (data & mask);
659        self.do_write(reg_idx, new_val);
660    }
661
662    /// Adds a region specified by `config`.  Configures the specified BAR(s) to
663    /// report this region and size to the guest kernel.  Enforces a few constraints
664    /// (i.e, region size must be power of two, register not already used). Returns 'None' on
665    /// failure all, `Some(BarIndex)` on success.
666    pub fn add_pci_bar(&mut self, config: PciBarConfiguration) -> Result<PciBarIndex> {
667        if config.bar_idx >= NUM_BAR_REGS {
668            return Err(Error::BarInvalid(config.bar_idx));
669        }
670
671        if self.bar_used[config.bar_idx] {
672            return Err(Error::BarInUse(config.bar_idx));
673        }
674
675        if config.size.count_ones() != 1 {
676            return Err(Error::BarSizeInvalid(config.size));
677        }
678
679        if config.is_expansion_rom() && config.region_type != PciBarRegionType::Memory32BitRegion {
680            return Err(Error::BarInvalidRomType);
681        }
682
683        let min_size = if config.is_expansion_rom() {
684            BAR_ROM_MIN_SIZE
685        } else if config.region_type == PciBarRegionType::IoRegion {
686            BAR_IO_MIN_SIZE
687        } else {
688            BAR_MEM_MIN_SIZE
689        };
690
691        if config.size < min_size {
692            return Err(Error::BarSizeInvalid(config.size));
693        }
694
695        if config.addr % config.size != 0 {
696            return Err(Error::BarAlignmentInvalid(config.addr, config.size));
697        }
698
699        let reg_idx = config.reg_index();
700        let end_addr = config
701            .addr
702            .checked_add(config.size)
703            .ok_or(Error::BarAddressInvalid(config.addr, config.size))?;
704        match config.region_type {
705            PciBarRegionType::Memory32BitRegion | PciBarRegionType::IoRegion => {
706                if end_addr > u64::from(u32::MAX) {
707                    return Err(Error::BarAddressInvalid(config.addr, config.size));
708                }
709            }
710            PciBarRegionType::Memory64BitRegion => {
711                // The expansion ROM BAR cannot be used for part of a 64-bit BAR.
712                if config.bar_idx + 1 >= ROM_BAR_IDX {
713                    return Err(Error::BarInvalid64(config.bar_idx));
714                }
715
716                if self.bar_used[config.bar_idx + 1] {
717                    return Err(Error::BarInUse64(config.bar_idx));
718                }
719
720                self.do_write(reg_idx + 1, (config.addr >> 32) as u32);
721                self.writable_bits[reg_idx + 1] = !((config.size - 1) >> 32) as u32;
722                self.bar_used[config.bar_idx + 1] = true;
723            }
724        }
725
726        let (mask, lower_bits) = match config.region_type {
727            PciBarRegionType::Memory32BitRegion | PciBarRegionType::Memory64BitRegion => {
728                self.registers[COMMAND_REG] |= COMMAND_REG_MEMORY_SPACE_MASK;
729                (
730                    BAR_MEM_ADDR_MASK,
731                    config.prefetchable as u32 | config.region_type as u32,
732                )
733            }
734            PciBarRegionType::IoRegion => {
735                self.registers[COMMAND_REG] |= COMMAND_REG_IO_SPACE_MASK;
736                (BAR_IO_ADDR_MASK, config.region_type as u32)
737            }
738        };
739
740        self.do_write(reg_idx, ((config.addr as u32) & mask) | lower_bits);
741        self.writable_bits[reg_idx] = !(config.size - 1) as u32;
742        if config.is_expansion_rom() {
743            self.writable_bits[reg_idx] |= 1; // Expansion ROM enable bit.
744        }
745        self.bar_used[config.bar_idx] = true;
746        self.bar_configs[config.bar_idx] = Some(config);
747        Ok(config.bar_idx)
748    }
749
750    /// Returns an iterator of the currently configured base address registers.
751    #[allow(dead_code)] // TODO(dverkamp): remove this once used
752    pub fn get_bars(&self) -> PciBarIter {
753        PciBarIter {
754            config: self,
755            bar_num: 0,
756        }
757    }
758
759    /// Returns the configuration of a base address register, if present.
760    pub fn get_bar_configuration(&self, bar_num: usize) -> Option<PciBarConfiguration> {
761        let config = self.bar_configs.get(bar_num)?;
762
763        if let Some(mut config) = config {
764            let command = self.read_reg(COMMAND_REG);
765            if (config.is_memory() && (command & COMMAND_REG_MEMORY_SPACE_MASK == 0))
766                || (config.is_io() && (command & COMMAND_REG_IO_SPACE_MASK == 0))
767            {
768                return None;
769            }
770
771            // The address may have been modified by the guest, so the value in bar_configs
772            // may be outdated. Replace it with the current value.
773            config.addr = self.get_bar_addr(bar_num);
774            Some(config)
775        } else {
776            None
777        }
778    }
779
780    /// Returns the type of the given BAR region.
781    pub fn get_bar_type(&self, bar_num: PciBarIndex) -> Option<PciBarRegionType> {
782        self.bar_configs.get(bar_num)?.map(|c| c.region_type)
783    }
784
785    /// Returns the address of the given BAR region.
786    pub fn get_bar_addr(&self, bar_num: PciBarIndex) -> u64 {
787        let bar_idx = if bar_num == ROM_BAR_IDX {
788            ROM_BAR_REG
789        } else {
790            BAR0_REG + bar_num
791        };
792
793        let bar_type = match self.get_bar_type(bar_num) {
794            Some(t) => t,
795            None => return 0,
796        };
797
798        match bar_type {
799            PciBarRegionType::IoRegion => u64::from(self.registers[bar_idx] & BAR_IO_ADDR_MASK),
800            PciBarRegionType::Memory32BitRegion => {
801                u64::from(self.registers[bar_idx] & BAR_MEM_ADDR_MASK)
802            }
803            PciBarRegionType::Memory64BitRegion => {
804                u64::from(self.registers[bar_idx] & BAR_MEM_ADDR_MASK)
805                    | u64::from(self.registers[bar_idx + 1]) << 32
806            }
807        }
808    }
809
810    /// Configures the IRQ line and pin used by this device.
811    pub fn set_irq(&mut self, line: u8, pin: PciInterruptPin) {
812        // `pin` is 1-based in the pci config space.
813        let pin_idx = (pin as u32) + 1;
814        let new_val = (self.registers[INTERRUPT_LINE_PIN_REG] & 0xffff_0000)
815            | (pin_idx << 8)
816            | u32::from(line);
817        self.do_write(INTERRUPT_LINE_PIN_REG, new_val)
818    }
819
820    /// Adds the capability `cap_data` to the list of capabilities.
821    /// `cap_data` should include the two-byte PCI capability header (type, next),
822    /// but not populate it. Correct values will be generated automatically based
823    /// on `cap_data.id()`.
824    pub fn add_capability(
825        &mut self,
826        cap_data: &dyn PciCapability,
827        cap_config: Option<Box<dyn PciCapConfig>>,
828    ) -> Result<()> {
829        let total_len = cap_data.bytes().len();
830        // Check that the length is valid.
831        if cap_data.bytes().is_empty() {
832            return Err(Error::CapabilityEmpty);
833        }
834        let (cap_offset, tail_offset) = match self.last_capability {
835            Some((offset, len)) => (Self::next_dword(offset, len), offset + 1),
836            None => (FIRST_CAPABILITY_OFFSET, CAPABILITY_LIST_HEAD_OFFSET),
837        };
838        let end_offset = cap_offset
839            .checked_add(total_len)
840            .ok_or(Error::CapabilitySpaceFull(total_len))?;
841        if end_offset > CAPABILITY_MAX_OFFSET {
842            return Err(Error::CapabilitySpaceFull(total_len));
843        }
844        self.do_write(
845            STATUS_REG,
846            self.registers[STATUS_REG] | STATUS_REG_CAPABILITIES_USED_MASK,
847        );
848        self.write_byte_internal(tail_offset, cap_offset as u8, false);
849        self.write_byte_internal(cap_offset, cap_data.id() as u8, false);
850        self.write_byte_internal(cap_offset + 1, 0, false); // Next pointer.
851        for (i, byte) in cap_data.bytes().iter().enumerate().skip(2) {
852            self.write_byte_internal(cap_offset + i, *byte, false);
853        }
854        let reg_idx = cap_offset / 4;
855        for (i, dword) in cap_data.writable_bits().iter().enumerate() {
856            self.writable_bits[reg_idx + i] = *dword;
857        }
858        self.last_capability = Some((cap_offset, total_len));
859        if let Some(mut cap_config) = cap_config {
860            if let Some((mapping, offset)) = &self.mmio_mapping {
861                cap_config.set_cap_mapping(PciCapMapping {
862                    mapping: mapping.clone(),
863                    offset: reg_idx * 4 + offset,
864                    num_regs: total_len / 4,
865                });
866            }
867            self.capability_configs.insert(cap_offset / 4, cap_config);
868        }
869        Ok(())
870    }
871
872    // Find the next aligned offset after the one given.
873    fn next_dword(offset: usize, len: usize) -> usize {
874        let next = offset + len;
875        (next + 3) & !3
876    }
877
878    fn do_write(&mut self, reg_idx: usize, value: u32) {
879        self.registers[reg_idx] = value;
880        if let Some((mmio_mapping, offset)) = self.mmio_mapping.as_ref() {
881            let mmio_mapping = mmio_mapping.lock();
882            let reg_offset = offset + reg_idx * 4;
883            if reg_idx == HEADER_TYPE_REG {
884                // Skip writing the header type byte (reg_idx=2/offset=3) as
885                // per the requirements of PciDevice.setup_pci_config_mapping.
886                mmio_mapping
887                    .write_obj_volatile((value & 0xffff) as u16, reg_offset)
888                    .expect("bad register offset");
889                // Skip HEADER_TYPE_REG_OFFSET (i.e. header+mfd byte)
890                mmio_mapping
891                    .write_obj_volatile(((value >> 24) & 0xff) as u8, reg_offset + 3)
892                    .expect("bad register offset");
893            } else {
894                mmio_mapping
895                    .write_obj_volatile(value, reg_offset)
896                    .expect("bad register offset");
897            }
898            if let Err(err) = mmio_mapping.flush_region(reg_offset, 4) {
899                error!(
900                    "failed to flush write to pci mmio register ({}): {}",
901                    reg_idx, err
902                );
903            }
904        }
905    }
906
907    pub fn snapshot(&mut self) -> anyhow::Result<AnySnapshot> {
908        AnySnapshot::to_any(PciConfigurationSerialized {
909            registers: self.registers,
910            writable_bits: self.writable_bits,
911            bar_used: self.bar_used,
912            bar_configs: self.bar_configs,
913            last_capability: self.last_capability,
914        })
915        .context("failed to serialize PciConfiguration")
916    }
917
918    pub fn restore(&mut self, data: AnySnapshot) -> anyhow::Result<()> {
919        let deser: PciConfigurationSerialized =
920            AnySnapshot::from_any(data).context("failed to deserialize PciConfiguration")?;
921        self.registers = deser.registers;
922        self.writable_bits = deser.writable_bits;
923        self.bar_used = deser.bar_used;
924        self.bar_configs = deser.bar_configs;
925        self.last_capability = deser.last_capability;
926        // Restore everything via do_write to avoid writing to the header type register
927        // and clobbering the multi-function device bit, as that bit is managed by the
928        // PciRoot. Since restore doesn't change the types or layout of PCI devices, the
929        // header type bits in the register are already correct anyway.
930        for i in 0..NUM_CONFIGURATION_REGISTERS {
931            self.do_write(i, self.registers[i]);
932        }
933        Ok(())
934    }
935
936    pub fn setup_mapping(
937        &mut self,
938        shmem: &SharedMemory,
939        base: usize,
940        len: usize,
941    ) -> anyhow::Result<()> {
942        if self.mmio_mapping.is_some() {
943            bail!("PCIe config mmio mapping already initialized");
944        }
945        let mapping = MemoryMappingBuilder::new(base::pagesize())
946            .from_shared_memory(shmem)
947            .build()
948            .context("Failed to create mapping")?;
949        for i in 0..(len / 4) {
950            let val = self.registers.get(i).unwrap_or(&0xffff_ffff);
951            mapping
952                .write_obj_volatile(*val, base + i * 4)
953                .expect("memcpy failed");
954        }
955        let mapping = Arc::new(Mutex::new(mapping));
956        for (idx, cap) in self.capability_configs.iter_mut() {
957            let mut cap_mapping = PciCapMapping {
958                mapping: mapping.clone(),
959                offset: idx * 4 + base,
960                num_regs: cap.num_regs(),
961            };
962            for i in 0..cap.num_regs() {
963                let val = cap.read_reg(i);
964                let mask = cap.read_mask()[i];
965                cap_mapping.set_reg(i, val, mask);
966            }
967            cap.set_cap_mapping(cap_mapping);
968        }
969        self.mmio_mapping = Some((mapping, base));
970        Ok(())
971    }
972}
973
974impl PciBarConfiguration {
975    pub fn new(
976        bar_idx: PciBarIndex,
977        size: u64,
978        region_type: PciBarRegionType,
979        prefetchable: PciBarPrefetchable,
980    ) -> Self {
981        PciBarConfiguration {
982            bar_idx,
983            addr: 0,
984            size,
985            region_type,
986            prefetchable,
987        }
988    }
989
990    pub fn bar_index(&self) -> PciBarIndex {
991        self.bar_idx
992    }
993
994    pub fn reg_index(&self) -> usize {
995        if self.bar_idx == ROM_BAR_IDX {
996            ROM_BAR_REG
997        } else {
998            BAR0_REG + self.bar_idx
999        }
1000    }
1001
1002    pub fn address(&self) -> u64 {
1003        self.addr
1004    }
1005
1006    pub fn address_range(&self) -> std::ops::Range<u64> {
1007        self.addr..self.addr + self.size
1008    }
1009
1010    pub fn set_address(mut self, addr: u64) -> Self {
1011        self.addr = addr;
1012        self
1013    }
1014
1015    pub fn size(&self) -> u64 {
1016        self.size
1017    }
1018
1019    pub fn is_expansion_rom(&self) -> bool {
1020        self.bar_idx == ROM_BAR_IDX
1021    }
1022
1023    pub fn is_memory(&self) -> bool {
1024        matches!(
1025            self.region_type,
1026            PciBarRegionType::Memory32BitRegion | PciBarRegionType::Memory64BitRegion
1027        )
1028    }
1029
1030    pub fn is_64bit_memory(&self) -> bool {
1031        self.region_type == PciBarRegionType::Memory64BitRegion
1032    }
1033
1034    pub fn is_io(&self) -> bool {
1035        self.region_type == PciBarRegionType::IoRegion
1036    }
1037
1038    pub fn is_prefetchable(&self) -> bool {
1039        self.is_memory() && self.prefetchable == PciBarPrefetchable::Prefetchable
1040    }
1041}
1042
1043impl<T: PciCapConfig + ?Sized> PciCapConfig for Arc<Mutex<T>> {
1044    fn read_mask(&self) -> &'static [u32] {
1045        self.lock().read_mask()
1046    }
1047    fn read_reg(&self, reg_idx: usize) -> u32 {
1048        self.lock().read_reg(reg_idx)
1049    }
1050    fn write_reg(
1051        &mut self,
1052        reg_idx: usize,
1053        offset: u64,
1054        data: &[u8],
1055    ) -> Option<Box<dyn PciCapConfigWriteResult>> {
1056        self.lock().write_reg(reg_idx, offset, data)
1057    }
1058    fn set_cap_mapping(&mut self, mapping: PciCapMapping) {
1059        self.lock().set_cap_mapping(mapping)
1060    }
1061}
1062
1063/// Struct for updating a capabilitiy's mmio mapping.
1064pub struct PciCapMapping {
1065    mapping: Arc<Mutex<MemoryMapping>>,
1066    offset: usize,
1067    num_regs: usize,
1068}
1069
1070impl PciCapMapping {
1071    /// Set the bits of register `reg_idx` specified by `mask` to `data`.
1072    pub fn set_reg(&mut self, reg_idx: usize, data: u32, mask: u32) {
1073        if reg_idx >= self.num_regs {
1074            error!(
1075                "out of bounds register write {} vs {}",
1076                self.num_regs, reg_idx
1077            );
1078            return;
1079        }
1080        let mapping = self.mapping.lock();
1081        let offset = self.offset + reg_idx * 4;
1082        let cur_value = mapping.read_obj::<u32>(offset).expect("memcpy failed");
1083        let new_val = (cur_value & !mask) | (data & mask);
1084        mapping
1085            .write_obj_volatile(new_val, offset)
1086            .expect("memcpy failed");
1087        if let Err(err) = mapping.flush_region(offset, 4) {
1088            error!(
1089                "failed to flush write to pci cap in mmio register ({}): {}",
1090                reg_idx, err
1091            );
1092        }
1093    }
1094}
1095
1096#[cfg(test)]
1097mod tests {
1098    use zerocopy::FromBytes;
1099    use zerocopy::Immutable;
1100    use zerocopy::IntoBytes;
1101    use zerocopy::KnownLayout;
1102
1103    use super::*;
1104
1105    #[repr(C, packed)]
1106    #[derive(Clone, Copy, FromBytes, Immutable, IntoBytes, KnownLayout)]
1107    #[allow(dead_code)]
1108    struct TestCap {
1109        _vndr: u8,
1110        _next: u8,
1111        len: u8,
1112        foo: u8,
1113    }
1114
1115    impl PciCapability for TestCap {
1116        fn bytes(&self) -> &[u8] {
1117            self.as_bytes()
1118        }
1119
1120        fn id(&self) -> PciCapabilityID {
1121            PciCapabilityID::VendorSpecific
1122        }
1123
1124        fn writable_bits(&self) -> Vec<u32> {
1125            vec![0u32; 1]
1126        }
1127    }
1128
1129    #[test]
1130    fn add_capability() {
1131        let mut cfg = PciConfiguration::new(
1132            0x1234,
1133            0x5678,
1134            PciClassCode::MultimediaController,
1135            &PciMultimediaSubclass::AudioController,
1136            None,
1137            PciHeaderType::Device,
1138            0xABCD,
1139            0x2468,
1140            0,
1141        );
1142
1143        // Add two capabilities with different contents.
1144        let cap1 = TestCap {
1145            _vndr: 0,
1146            _next: 0,
1147            len: 4,
1148            foo: 0xAA,
1149        };
1150        let cap1_offset = 64;
1151        cfg.add_capability(&cap1, None).unwrap();
1152
1153        let cap2 = TestCap {
1154            _vndr: 0,
1155            _next: 0,
1156            len: 0x04,
1157            foo: 0x55,
1158        };
1159        let cap2_offset = 68;
1160        cfg.add_capability(&cap2, None).unwrap();
1161
1162        // The capability list head should be pointing to cap1.
1163        let cap_ptr = cfg.read_reg(CAPABILITY_LIST_HEAD_OFFSET / 4) & 0xFF;
1164        assert_eq!(cap1_offset, cap_ptr as usize);
1165
1166        // Verify the contents of the capabilities.
1167        let cap1_data = cfg.read_reg(cap1_offset / 4);
1168        assert_eq!(cap1_data & 0xFF, 0x09); // capability ID
1169        assert_eq!((cap1_data >> 8) & 0xFF, cap2_offset as u32); // next capability pointer
1170        assert_eq!((cap1_data >> 16) & 0xFF, 0x04); // cap1.len
1171        assert_eq!((cap1_data >> 24) & 0xFF, 0xAA); // cap1.foo
1172
1173        let cap2_data = cfg.read_reg(cap2_offset / 4);
1174        assert_eq!(cap2_data & 0xFF, 0x09); // capability ID
1175        assert_eq!((cap2_data >> 8) & 0xFF, 0x00); // next capability pointer
1176        assert_eq!((cap2_data >> 16) & 0xFF, 0x04); // cap2.len
1177        assert_eq!((cap2_data >> 24) & 0xFF, 0x55); // cap2.foo
1178    }
1179
1180    #[derive(Copy, Clone)]
1181    enum TestPI {
1182        Test = 0x5a,
1183    }
1184
1185    impl PciProgrammingInterface for TestPI {
1186        fn get_register_value(&self) -> u8 {
1187            *self as u8
1188        }
1189    }
1190
1191    #[test]
1192    fn class_code() {
1193        let cfg = PciConfiguration::new(
1194            0x1234,
1195            0x5678,
1196            PciClassCode::MultimediaController,
1197            &PciMultimediaSubclass::AudioController,
1198            Some(&TestPI::Test),
1199            PciHeaderType::Device,
1200            0xABCD,
1201            0x2468,
1202            0,
1203        );
1204
1205        let class_reg = cfg.read_reg(2);
1206        let class_code = (class_reg >> 24) & 0xFF;
1207        let subclass = (class_reg >> 16) & 0xFF;
1208        let prog_if = (class_reg >> 8) & 0xFF;
1209        assert_eq!(class_code, 0x04);
1210        assert_eq!(subclass, 0x01);
1211        assert_eq!(prog_if, 0x5a);
1212    }
1213
1214    #[test]
1215    fn read_only_bits() {
1216        let mut cfg = PciConfiguration::new(
1217            0x1234,
1218            0x5678,
1219            PciClassCode::MultimediaController,
1220            &PciMultimediaSubclass::AudioController,
1221            Some(&TestPI::Test),
1222            PciHeaderType::Device,
1223            0xABCD,
1224            0x2468,
1225            0,
1226        );
1227
1228        // Attempt to overwrite vendor ID and device ID, which are read-only
1229        cfg.write_reg(0, 0, &[0xBA, 0xAD, 0xF0, 0x0D]);
1230        // The original vendor and device ID should remain.
1231        assert_eq!(cfg.read_reg(0), 0x56781234);
1232    }
1233
1234    #[test]
1235    fn query_unused_bar() {
1236        let cfg = PciConfiguration::new(
1237            0x1234,
1238            0x5678,
1239            PciClassCode::MultimediaController,
1240            &PciMultimediaSubclass::AudioController,
1241            Some(&TestPI::Test),
1242            PciHeaderType::Device,
1243            0xABCD,
1244            0x2468,
1245            0,
1246        );
1247
1248        // No BAR 0 has been configured, so these should return None or 0 as appropriate.
1249        assert_eq!(cfg.get_bar_type(0), None);
1250        assert_eq!(cfg.get_bar_addr(0), 0);
1251
1252        let mut bar_iter = cfg.get_bars();
1253        assert_eq!(bar_iter.next(), None);
1254    }
1255
1256    #[test]
1257    fn add_pci_bar_mem_64bit() {
1258        let mut cfg = PciConfiguration::new(
1259            0x1234,
1260            0x5678,
1261            PciClassCode::MultimediaController,
1262            &PciMultimediaSubclass::AudioController,
1263            Some(&TestPI::Test),
1264            PciHeaderType::Device,
1265            0xABCD,
1266            0x2468,
1267            0,
1268        );
1269
1270        cfg.add_pci_bar(
1271            PciBarConfiguration::new(
1272                0,
1273                0x10,
1274                PciBarRegionType::Memory64BitRegion,
1275                PciBarPrefetchable::NotPrefetchable,
1276            )
1277            .set_address(0x0123_4567_89AB_CDE0),
1278        )
1279        .expect("add_pci_bar failed");
1280
1281        assert_eq!(
1282            cfg.get_bar_type(0),
1283            Some(PciBarRegionType::Memory64BitRegion)
1284        );
1285        assert_eq!(cfg.get_bar_addr(0), 0x0123_4567_89AB_CDE0);
1286        assert_eq!(cfg.writable_bits[BAR0_REG + 1], 0xFFFFFFFF);
1287        assert_eq!(cfg.writable_bits[BAR0_REG + 0], 0xFFFFFFF0);
1288
1289        let mut bar_iter = cfg.get_bars();
1290        assert_eq!(
1291            bar_iter.next(),
1292            Some(PciBarConfiguration {
1293                addr: 0x0123_4567_89AB_CDE0,
1294                size: 0x10,
1295                bar_idx: 0,
1296                region_type: PciBarRegionType::Memory64BitRegion,
1297                prefetchable: PciBarPrefetchable::NotPrefetchable
1298            })
1299        );
1300        assert_eq!(bar_iter.next(), None);
1301    }
1302
1303    #[test]
1304    fn add_pci_bar_mem_32bit() {
1305        let mut cfg = PciConfiguration::new(
1306            0x1234,
1307            0x5678,
1308            PciClassCode::MultimediaController,
1309            &PciMultimediaSubclass::AudioController,
1310            Some(&TestPI::Test),
1311            PciHeaderType::Device,
1312            0xABCD,
1313            0x2468,
1314            0,
1315        );
1316
1317        cfg.add_pci_bar(
1318            PciBarConfiguration::new(
1319                0,
1320                0x10,
1321                PciBarRegionType::Memory32BitRegion,
1322                PciBarPrefetchable::NotPrefetchable,
1323            )
1324            .set_address(0x12345670),
1325        )
1326        .expect("add_pci_bar failed");
1327
1328        assert_eq!(
1329            cfg.get_bar_type(0),
1330            Some(PciBarRegionType::Memory32BitRegion)
1331        );
1332        assert_eq!(cfg.get_bar_addr(0), 0x12345670);
1333        assert_eq!(cfg.writable_bits[BAR0_REG], 0xFFFFFFF0);
1334
1335        let mut bar_iter = cfg.get_bars();
1336        assert_eq!(
1337            bar_iter.next(),
1338            Some(PciBarConfiguration {
1339                addr: 0x12345670,
1340                size: 0x10,
1341                bar_idx: 0,
1342                region_type: PciBarRegionType::Memory32BitRegion,
1343                prefetchable: PciBarPrefetchable::NotPrefetchable
1344            })
1345        );
1346        assert_eq!(bar_iter.next(), None);
1347    }
1348
1349    #[test]
1350    fn add_pci_bar_io() {
1351        let mut cfg = PciConfiguration::new(
1352            0x1234,
1353            0x5678,
1354            PciClassCode::MultimediaController,
1355            &PciMultimediaSubclass::AudioController,
1356            Some(&TestPI::Test),
1357            PciHeaderType::Device,
1358            0xABCD,
1359            0x2468,
1360            0,
1361        );
1362
1363        cfg.add_pci_bar(
1364            PciBarConfiguration::new(
1365                0,
1366                0x4,
1367                PciBarRegionType::IoRegion,
1368                PciBarPrefetchable::NotPrefetchable,
1369            )
1370            .set_address(0x1230),
1371        )
1372        .expect("add_pci_bar failed");
1373
1374        assert_eq!(cfg.get_bar_type(0), Some(PciBarRegionType::IoRegion));
1375        assert_eq!(cfg.get_bar_addr(0), 0x1230);
1376        assert_eq!(cfg.writable_bits[BAR0_REG], 0xFFFFFFFC);
1377
1378        let mut bar_iter = cfg.get_bars();
1379        assert_eq!(
1380            bar_iter.next(),
1381            Some(PciBarConfiguration {
1382                addr: 0x1230,
1383                size: 0x4,
1384                bar_idx: 0,
1385                region_type: PciBarRegionType::IoRegion,
1386                prefetchable: PciBarPrefetchable::NotPrefetchable
1387            })
1388        );
1389        assert_eq!(bar_iter.next(), None);
1390    }
1391
1392    #[test]
1393    fn add_pci_bar_multiple() {
1394        let mut cfg = PciConfiguration::new(
1395            0x1234,
1396            0x5678,
1397            PciClassCode::MultimediaController,
1398            &PciMultimediaSubclass::AudioController,
1399            Some(&TestPI::Test),
1400            PciHeaderType::Device,
1401            0xABCD,
1402            0x2468,
1403            0,
1404        );
1405
1406        // bar_num 0-1: 64-bit memory
1407        cfg.add_pci_bar(
1408            PciBarConfiguration::new(
1409                0,
1410                0x10,
1411                PciBarRegionType::Memory64BitRegion,
1412                PciBarPrefetchable::NotPrefetchable,
1413            )
1414            .set_address(0x0123_4567_89AB_CDE0),
1415        )
1416        .expect("add_pci_bar failed");
1417
1418        // bar 2: 32-bit memory
1419        cfg.add_pci_bar(
1420            PciBarConfiguration::new(
1421                2,
1422                0x10,
1423                PciBarRegionType::Memory32BitRegion,
1424                PciBarPrefetchable::NotPrefetchable,
1425            )
1426            .set_address(0x12345670),
1427        )
1428        .expect("add_pci_bar failed");
1429
1430        // bar 3: I/O
1431        cfg.add_pci_bar(
1432            PciBarConfiguration::new(
1433                3,
1434                0x4,
1435                PciBarRegionType::IoRegion,
1436                PciBarPrefetchable::NotPrefetchable,
1437            )
1438            .set_address(0x1230),
1439        )
1440        .expect("add_pci_bar failed");
1441
1442        // Confirm default memory and I/O region configurations.
1443        let mut bar_iter = cfg.get_bars();
1444        assert_eq!(
1445            bar_iter.next(),
1446            Some(PciBarConfiguration {
1447                addr: 0x0123_4567_89AB_CDE0,
1448                size: 0x10,
1449                bar_idx: 0,
1450                region_type: PciBarRegionType::Memory64BitRegion,
1451                prefetchable: PciBarPrefetchable::NotPrefetchable
1452            })
1453        );
1454        assert_eq!(
1455            bar_iter.next(),
1456            Some(PciBarConfiguration {
1457                addr: 0x12345670,
1458                size: 0x10,
1459                bar_idx: 2,
1460                region_type: PciBarRegionType::Memory32BitRegion,
1461                prefetchable: PciBarPrefetchable::NotPrefetchable
1462            })
1463        );
1464        assert_eq!(
1465            bar_iter.next(),
1466            Some(PciBarConfiguration {
1467                addr: 0x1230,
1468                size: 0x4,
1469                bar_idx: 3,
1470                region_type: PciBarRegionType::IoRegion,
1471                prefetchable: PciBarPrefetchable::NotPrefetchable
1472            })
1473        );
1474        assert_eq!(bar_iter.next(), None);
1475
1476        // Reassign the address for BAR 0 and verify that get_memory_regions() matches.
1477        cfg.write_reg(4 + 0, 0, &0xBBAA9980u32.to_le_bytes());
1478        cfg.write_reg(4 + 1, 0, &0xFFEEDDCCu32.to_le_bytes());
1479
1480        let mut bar_iter = cfg.get_bars();
1481        assert_eq!(
1482            bar_iter.next(),
1483            Some(PciBarConfiguration {
1484                addr: 0xFFEE_DDCC_BBAA_9980,
1485                size: 0x10,
1486                bar_idx: 0,
1487                region_type: PciBarRegionType::Memory64BitRegion,
1488                prefetchable: PciBarPrefetchable::NotPrefetchable
1489            })
1490        );
1491        assert_eq!(
1492            bar_iter.next(),
1493            Some(PciBarConfiguration {
1494                addr: 0x12345670,
1495                size: 0x10,
1496                bar_idx: 2,
1497                region_type: PciBarRegionType::Memory32BitRegion,
1498                prefetchable: PciBarPrefetchable::NotPrefetchable
1499            })
1500        );
1501        assert_eq!(
1502            bar_iter.next(),
1503            Some(PciBarConfiguration {
1504                addr: 0x1230,
1505                size: 0x4,
1506                bar_idx: 3,
1507                region_type: PciBarRegionType::IoRegion,
1508                prefetchable: PciBarPrefetchable::NotPrefetchable
1509            })
1510        );
1511        assert_eq!(bar_iter.next(), None);
1512    }
1513
1514    #[test]
1515    fn add_pci_bar_invalid_size() {
1516        let mut cfg = PciConfiguration::new(
1517            0x1234,
1518            0x5678,
1519            PciClassCode::MultimediaController,
1520            &PciMultimediaSubclass::AudioController,
1521            Some(&TestPI::Test),
1522            PciHeaderType::Device,
1523            0xABCD,
1524            0x2468,
1525            0,
1526        );
1527
1528        // I/O BAR with size 2 (too small)
1529        assert_eq!(
1530            cfg.add_pci_bar(
1531                PciBarConfiguration::new(
1532                    0,
1533                    0x2,
1534                    PciBarRegionType::IoRegion,
1535                    PciBarPrefetchable::NotPrefetchable,
1536                )
1537                .set_address(0x1230),
1538            ),
1539            Err(Error::BarSizeInvalid(0x2))
1540        );
1541
1542        // I/O BAR with size 3 (not a power of 2)
1543        assert_eq!(
1544            cfg.add_pci_bar(
1545                PciBarConfiguration::new(
1546                    0,
1547                    0x3,
1548                    PciBarRegionType::IoRegion,
1549                    PciBarPrefetchable::NotPrefetchable,
1550                )
1551                .set_address(0x1230),
1552            ),
1553            Err(Error::BarSizeInvalid(0x3))
1554        );
1555
1556        // Memory BAR with size 8 (too small)
1557        assert_eq!(
1558            cfg.add_pci_bar(
1559                PciBarConfiguration::new(
1560                    0,
1561                    0x8,
1562                    PciBarRegionType::Memory32BitRegion,
1563                    PciBarPrefetchable::NotPrefetchable,
1564                )
1565                .set_address(0x12345670),
1566            ),
1567            Err(Error::BarSizeInvalid(0x8))
1568        );
1569    }
1570
1571    #[test]
1572    fn add_rom_bar() {
1573        let mut cfg = PciConfiguration::new(
1574            0x1234,
1575            0x5678,
1576            PciClassCode::MultimediaController,
1577            &PciMultimediaSubclass::AudioController,
1578            Some(&TestPI::Test),
1579            PciHeaderType::Device,
1580            0xABCD,
1581            0x2468,
1582            0,
1583        );
1584
1585        // Attempt to add a 64-bit memory BAR as the expansion ROM (invalid).
1586        assert_eq!(
1587            cfg.add_pci_bar(PciBarConfiguration::new(
1588                ROM_BAR_IDX,
1589                0x1000,
1590                PciBarRegionType::Memory64BitRegion,
1591                PciBarPrefetchable::NotPrefetchable,
1592            ),),
1593            Err(Error::BarInvalidRomType)
1594        );
1595
1596        // Attempt to add an I/O BAR as the expansion ROM (invalid).
1597        assert_eq!(
1598            cfg.add_pci_bar(PciBarConfiguration::new(
1599                ROM_BAR_IDX,
1600                0x1000,
1601                PciBarRegionType::IoRegion,
1602                PciBarPrefetchable::NotPrefetchable,
1603            ),),
1604            Err(Error::BarInvalidRomType)
1605        );
1606
1607        // Attempt to add a 1KB memory region as the expansion ROM (too small).
1608        assert_eq!(
1609            cfg.add_pci_bar(PciBarConfiguration::new(
1610                ROM_BAR_IDX,
1611                1024,
1612                PciBarRegionType::Memory32BitRegion,
1613                PciBarPrefetchable::NotPrefetchable,
1614            ),),
1615            Err(Error::BarSizeInvalid(1024))
1616        );
1617
1618        // Add a 32-bit memory BAR as the expansion ROM (valid).
1619        cfg.add_pci_bar(
1620            PciBarConfiguration::new(
1621                ROM_BAR_IDX,
1622                0x800,
1623                PciBarRegionType::Memory32BitRegion,
1624                PciBarPrefetchable::NotPrefetchable,
1625            )
1626            .set_address(0x12345000),
1627        )
1628        .expect("add_pci_bar failed");
1629
1630        assert_eq!(
1631            cfg.get_bar_type(ROM_BAR_IDX),
1632            Some(PciBarRegionType::Memory32BitRegion)
1633        );
1634        assert_eq!(cfg.get_bar_addr(ROM_BAR_IDX), 0x12345000);
1635        assert_eq!(cfg.read_reg(ROM_BAR_REG), 0x12345000);
1636        assert_eq!(cfg.writable_bits[ROM_BAR_REG], 0xFFFFF801);
1637    }
1638
1639    #[test]
1640    fn pci_configuration_capability_snapshot_restore() -> anyhow::Result<()> {
1641        let mut cfg = PciConfiguration::new(
1642            0x1234,
1643            0x5678,
1644            PciClassCode::MultimediaController,
1645            &PciMultimediaSubclass::AudioController,
1646            Some(&TestPI::Test),
1647            PciHeaderType::Device,
1648            0xABCD,
1649            0x2468,
1650            0,
1651        );
1652
1653        let snap_init = cfg.snapshot().context("failed to snapshot")?;
1654
1655        // Add a capability.
1656        let cap1 = TestCap {
1657            _vndr: 0,
1658            _next: 0,
1659            len: 4,
1660            foo: 0xAA,
1661        };
1662        cfg.add_capability(&cap1, None).unwrap();
1663
1664        let snap_mod = cfg.snapshot().context("failed to snapshot mod")?;
1665        cfg.restore(snap_init.clone())
1666            .context("failed to restore snap_init")?;
1667        let snap_restore_init = cfg.snapshot().context("failed to snapshot restored_init")?;
1668        assert_eq!(snap_init, snap_restore_init);
1669        assert_ne!(snap_init, snap_mod);
1670        cfg.restore(snap_mod.clone())
1671            .context("failed to restore snap_init")?;
1672        let snap_restore_mod = cfg.snapshot().context("failed to snapshot restored_mod")?;
1673        assert_eq!(snap_mod, snap_restore_mod);
1674        Ok(())
1675    }
1676
1677    #[test]
1678    fn pci_configuration_pci_bar_snapshot_restore() -> anyhow::Result<()> {
1679        let mut cfg = PciConfiguration::new(
1680            0x1234,
1681            0x5678,
1682            PciClassCode::MultimediaController,
1683            &PciMultimediaSubclass::AudioController,
1684            Some(&TestPI::Test),
1685            PciHeaderType::Device,
1686            0xABCD,
1687            0x2468,
1688            0,
1689        );
1690
1691        let snap_init = cfg.snapshot().context("failed to snapshot")?;
1692
1693        // bar_num 0-1: 64-bit memory
1694        cfg.add_pci_bar(
1695            PciBarConfiguration::new(
1696                0,
1697                0x10,
1698                PciBarRegionType::Memory64BitRegion,
1699                PciBarPrefetchable::NotPrefetchable,
1700            )
1701            .set_address(0x0123_4567_89AB_CDE0),
1702        )
1703        .expect("add_pci_bar failed");
1704
1705        let snap_mod = cfg.snapshot().context("failed to snapshot mod")?;
1706        cfg.restore(snap_init.clone())
1707            .context("failed to restore snap_init")?;
1708        let snap_restore_init = cfg.snapshot().context("failed to snapshot restored_init")?;
1709        assert_eq!(snap_init, snap_restore_init);
1710        assert_ne!(snap_init, snap_mod);
1711        cfg.restore(snap_mod.clone())
1712            .context("failed to restore snap_init")?;
1713        let snap_restore_mod = cfg.snapshot().context("failed to snapshot restored_mod")?;
1714        assert_eq!(snap_mod, snap_restore_mod);
1715        Ok(())
1716    }
1717
1718    #[test]
1719    fn pci_configuration_capability_pci_bar_snapshot_restore() -> anyhow::Result<()> {
1720        let mut cfg = PciConfiguration::new(
1721            0x1234,
1722            0x5678,
1723            PciClassCode::MultimediaController,
1724            &PciMultimediaSubclass::AudioController,
1725            Some(&TestPI::Test),
1726            PciHeaderType::Device,
1727            0xABCD,
1728            0x2468,
1729            0,
1730        );
1731
1732        let snap_init = cfg.snapshot().context("failed to snapshot")?;
1733
1734        // Add a capability.
1735        let cap1 = TestCap {
1736            _vndr: 0,
1737            _next: 0,
1738            len: 4,
1739            foo: 0xAA,
1740        };
1741        cfg.add_capability(&cap1, None).unwrap();
1742
1743        // bar_num 0-1: 64-bit memory
1744        cfg.add_pci_bar(
1745            PciBarConfiguration::new(
1746                0,
1747                0x10,
1748                PciBarRegionType::Memory64BitRegion,
1749                PciBarPrefetchable::NotPrefetchable,
1750            )
1751            .set_address(0x0123_4567_89AB_CDE0),
1752        )
1753        .expect("add_pci_bar failed");
1754
1755        let snap_mod = cfg.snapshot().context("failed to snapshot mod")?;
1756        cfg.restore(snap_init.clone())
1757            .context("failed to restore snap_init")?;
1758        let snap_restore_init = cfg.snapshot().context("failed to snapshot restored_init")?;
1759        assert_eq!(snap_init, snap_restore_init);
1760        assert_ne!(snap_init, snap_mod);
1761        cfg.restore(snap_mod.clone())
1762            .context("failed to restore snap_init")?;
1763        let snap_restore_mod = cfg.snapshot().context("failed to snapshot restored_mod")?;
1764        assert_eq!(snap_mod, snap_restore_mod);
1765        Ok(())
1766    }
1767}