Skip to main content

pci_core/test_helpers/
mod.rs

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4//! Mock types for unit-testing various PCI behaviors.
5
6use crate::capabilities::PciCapability;
7use crate::capabilities::extended::PciExtendedCapability;
8use crate::cfg_space_emu::ConfigSpaceType0Emulator;
9use crate::cfg_space_emu::ConfigSpaceType1Emulator;
10use crate::msi::SignalMsi;
11use chipset_device::pci::ByteEnabledDwordRead;
12use chipset_device::pci::ByteEnabledDwordWrite;
13use chipset_device::pci::PciConfigAddress;
14use parking_lot::Mutex;
15use std::collections::VecDeque;
16use std::sync::Arc;
17
18/// A test-only interrupt controller that simply stashes incoming interrupt
19/// requests in a FIFO queue. Implements [`SignalMsi`].
20#[derive(Debug, Clone)]
21pub struct TestPciInterruptController {
22    inner: Arc<TestPciInterruptControllerInner>,
23}
24
25#[derive(Debug)]
26struct TestPciInterruptControllerInner {
27    // TODO: also support INTx interrupts
28    msi_requests: Mutex<VecDeque<(u64, u32)>>, // (addr, data)
29}
30
31impl TestPciInterruptController {
32    /// Return a new test PCI interrupt controller
33    pub fn new() -> Self {
34        Self {
35            inner: Arc::new(TestPciInterruptControllerInner {
36                msi_requests: Mutex::new(VecDeque::new()),
37            }),
38        }
39    }
40
41    /// Fetch the first (addr, data) MSI-X interrupt in the FIFO interrupt queue
42    pub fn get_next_interrupt(&self) -> Option<(u64, u32)> {
43        self.inner.msi_requests.lock().pop_front()
44    }
45
46    /// Returns an `Arc<dyn SignalMsi>` to this controller.
47    pub fn signal_msi(&self) -> Arc<dyn SignalMsi> {
48        self.inner.clone()
49    }
50}
51
52impl SignalMsi for TestPciInterruptControllerInner {
53    fn signal_msi(&self, _devid: Option<u32>, address: u64, data: u32) {
54        self.msi_requests.lock().push_back((address, data));
55    }
56}
57
58/// Test-only DWORD access helpers for config-space-like objects.
59pub trait TestCfgAccess {
60    /// Read a DWORD at the given object-relative offset.
61    fn read_u32(&self, offset: u16) -> u32;
62
63    /// Write a DWORD at the given object-relative offset.
64    fn write_u32(&mut self, offset: u16, value: u32);
65}
66
67impl TestCfgAccess for ConfigSpaceType0Emulator {
68    fn read_u32(&self, offset: u16) -> u32 {
69        assert!(offset.is_multiple_of(4));
70        let mut val = 0;
71        self.read(
72            PciConfigAddress::new(0, 0, offset / 4).unwrap(),
73            ByteEnabledDwordRead::with_all_bytes_enabled(&mut val),
74        )
75        .unwrap();
76        val
77    }
78
79    fn write_u32(&mut self, offset: u16, value: u32) {
80        assert!(offset.is_multiple_of(4));
81        self.write(
82            PciConfigAddress::new(0, 0, offset / 4).unwrap(),
83            ByteEnabledDwordWrite::with_all_bytes_enabled(value),
84        )
85        .unwrap();
86    }
87}
88
89impl TestCfgAccess for ConfigSpaceType1Emulator {
90    fn read_u32(&self, offset: u16) -> u32 {
91        assert!(offset.is_multiple_of(4));
92        let mut val = 0;
93        self.read(
94            PciConfigAddress::new(0, 0, offset / 4).unwrap(),
95            ByteEnabledDwordRead::with_all_bytes_enabled(&mut val),
96        )
97        .unwrap();
98        val
99    }
100
101    fn write_u32(&mut self, offset: u16, value: u32) {
102        assert!(offset.is_multiple_of(4));
103        self.write(
104            PciConfigAddress::new(0, 0, offset / 4).unwrap(),
105            ByteEnabledDwordWrite::with_all_bytes_enabled(value),
106        )
107        .unwrap();
108    }
109}
110
111/// Read a u32 from a `PciCapability`.
112pub fn read_cap_u32(cap: &impl PciCapability, offset: u16) -> u32 {
113    let mut value = 0;
114    cap.read(
115        offset,
116        ByteEnabledDwordRead::with_all_bytes_enabled(&mut value),
117    );
118    value
119}
120
121/// Write a u32 to a `PciCapability`.
122pub fn write_cap_u32(cap: &mut impl PciCapability, offset: u16, val: u32) {
123    cap.write(offset, ByteEnabledDwordWrite::with_all_bytes_enabled(val))
124}
125
126/// Read a u32 from a `PciExtendedCapability`.
127pub fn read_extended_cap_u32(cap: &impl PciExtendedCapability, offset: u16) -> u32 {
128    let mut value = 0;
129    cap.read(
130        offset,
131        ByteEnabledDwordRead::with_all_bytes_enabled(&mut value),
132    );
133    value
134}
135
136/// Write a u32 to a `PciExtendedCapability`.
137pub fn write_extended_cap_u32(cap: &mut impl PciExtendedCapability, offset: u16, val: u32) {
138    cap.write(offset, ByteEnabledDwordWrite::with_all_bytes_enabled(val))
139}