Skip to main content

pci_core/capabilities/extended/
acs.rs

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4//! PCIe Access Control Services (ACS) extended capability.
5
6use super::PciExtendedCapability;
7use crate::spec::caps::ExtendedCapabilityId;
8use crate::spec::caps::acs::AcsCapabilities;
9use crate::spec::caps::acs::AcsControl;
10use crate::spec::caps::acs::AcsExtendedCapabilityHeader;
11use crate::spec::caps::acs::DEFAULT_ACS_CAP_MASK;
12use chipset_device::pci::ByteEnabledDwordRead;
13use chipset_device::pci::ByteEnabledDwordWrite;
14use inspect::Inspect;
15
16/// PCIe Access Control Services (ACS) extended capability emulator.
17#[derive(Debug, Inspect)]
18pub struct AcsExtendedCapability {
19    capabilities: AcsCapabilities,
20    control: AcsControl,
21}
22
23impl AcsExtendedCapability {
24    /// Creates an ACS capability with the default set of sub-capabilities enabled (SV, TB, RR, CR, UF, DT).
25    pub fn new() -> Self {
26        Self::with_capabilities(DEFAULT_ACS_CAP_MASK)
27    }
28
29    /// Creates an ACS capability with the sub-capabilities indicated by `capability_bits`.
30    pub fn with_capabilities(capability_bits: u16) -> Self {
31        let capabilities = AcsCapabilities::from_bits(capability_bits);
32
33        Self {
34            capabilities,
35            control: AcsControl::new(),
36        }
37    }
38}
39
40impl PciExtendedCapability for AcsExtendedCapability {
41    fn label(&self) -> &str {
42        "acs"
43    }
44
45    fn extended_capability_id(&self) -> u16 {
46        ExtendedCapabilityId::ACS.0
47    }
48
49    fn capability_version(&self) -> u8 {
50        1
51    }
52
53    fn len(&self) -> usize {
54        12
55    }
56
57    fn read(&self, offset: u16, mut value: ByteEnabledDwordRead<'_>) {
58        match AcsExtendedCapabilityHeader(offset) {
59            AcsExtendedCapabilityHeader::HEADER => {
60                value.set_low_high(
61                    self.extended_capability_id(),
62                    self.capability_version().into(),
63                );
64            }
65            AcsExtendedCapabilityHeader::CAPS_CONTROL => {
66                value.set_low_high(self.capabilities.into_bits(), self.control.into_bits());
67            }
68            AcsExtendedCapabilityHeader::EGRESS_CONTROL_VECTOR => value.set(0),
69            _ => value.set(!0),
70        }
71    }
72
73    fn write(&mut self, offset: u16, val: ByteEnabledDwordWrite) {
74        // Note that all ACS control only affect the emulated port, and do not reflect
75        // any underlying hardware capabilities.
76        match AcsExtendedCapabilityHeader(offset) {
77            AcsExtendedCapabilityHeader::HEADER => {
78                tracelimit::warn_ratelimited!(
79                    offset,
80                    ?val,
81                    "write to read-only ACS extended capability register"
82                );
83            }
84            AcsExtendedCapabilityHeader::CAPS_CONTROL => {
85                // Control bits are writable only if the matching capability bit is set.
86                self.control = AcsControl::from_bits(
87                    val.merge_high(self.control.into_bits()) & self.capabilities.into_bits(),
88                );
89            }
90            AcsExtendedCapabilityHeader::EGRESS_CONTROL_VECTOR => {
91                tracelimit::warn_ratelimited!(
92                    offset,
93                    ?val,
94                    "ACS egress control vector writes are currently not supported; dropping write"
95                );
96            }
97            _ => {
98                tracelimit::warn_ratelimited!(
99                    offset,
100                    ?val,
101                    "unexpected ACS extended capability write"
102                );
103            }
104        }
105    }
106
107    fn reset(&mut self) {
108        self.control = AcsControl::new();
109    }
110}
111
112mod save_restore {
113    use super::*;
114    use vmcore::save_restore::RestoreError;
115    use vmcore::save_restore::SaveError;
116    use vmcore::save_restore::SaveRestore;
117
118    mod state {
119        use mesh::payload::Protobuf;
120        use vmcore::save_restore::SavedStateRoot;
121
122        #[derive(Debug, Protobuf, SavedStateRoot)]
123        #[mesh(package = "pci.capabilities.extended.acs")]
124        pub struct SavedState {
125            #[mesh(1)]
126            pub control: u16,
127        }
128    }
129
130    impl SaveRestore for AcsExtendedCapability {
131        type SavedState = state::SavedState;
132
133        fn save(&mut self) -> Result<Self::SavedState, SaveError> {
134            Ok(state::SavedState {
135                control: self.control.into_bits(),
136            })
137        }
138
139        fn restore(&mut self, state: Self::SavedState) -> Result<(), RestoreError> {
140            self.control = AcsControl::from_bits(state.control & self.capabilities.into_bits());
141            Ok(())
142        }
143    }
144}
145
146#[cfg(test)]
147mod tests {
148    use super::*;
149    use crate::capabilities::extended::assert_extended_header_contract;
150    use crate::test_helpers::read_extended_cap_u32;
151    use crate::test_helpers::write_extended_cap_u32;
152    use vmcore::save_restore::SaveRestore;
153
154    #[test]
155    fn test_acs_defaults() {
156        let cap = AcsExtendedCapability::new();
157
158        assert_eq!(cap.label(), "acs");
159        assert_eq!(cap.extended_capability_id(), ExtendedCapabilityId::ACS.0);
160        assert_eq!(cap.capability_version(), 1);
161        assert_eq!(cap.len(), 12);
162        assert_extended_header_contract(&cap);
163
164        let caps_ctl = read_extended_cap_u32(&cap, AcsExtendedCapabilityHeader::CAPS_CONTROL.0);
165        assert_eq!(caps_ctl as u16, DEFAULT_ACS_CAP_MASK);
166        assert_eq!((caps_ctl >> 16) as u16, 0);
167    }
168
169    #[test]
170    fn test_acs_control_write_masks_unsupported_bits() {
171        let mut cap = AcsExtendedCapability::new();
172
173        write_extended_cap_u32(
174            &mut cap,
175            AcsExtendedCapabilityHeader::CAPS_CONTROL.0,
176            0xffff_0000,
177        );
178        let caps_ctl = read_extended_cap_u32(&cap, AcsExtendedCapabilityHeader::CAPS_CONTROL.0);
179
180        assert_eq!((caps_ctl >> 16) as u16, DEFAULT_ACS_CAP_MASK);
181    }
182
183    #[test]
184    fn test_acs_reset_clears_control() {
185        let mut cap = AcsExtendedCapability::new();
186
187        write_extended_cap_u32(
188            &mut cap,
189            AcsExtendedCapabilityHeader::CAPS_CONTROL.0,
190            0xffff_0000,
191        );
192        cap.reset();
193
194        let caps_ctl = read_extended_cap_u32(&cap, AcsExtendedCapabilityHeader::CAPS_CONTROL.0);
195        assert_eq!((caps_ctl >> 16) as u16, 0);
196    }
197
198    #[test]
199    fn test_acs_save_restore() {
200        let mut cap = AcsExtendedCapability::new();
201        write_extended_cap_u32(
202            &mut cap,
203            AcsExtendedCapabilityHeader::CAPS_CONTROL.0,
204            0xffff_0000,
205        );
206
207        let saved = cap.save().expect("save should succeed");
208
209        cap.reset();
210        assert_eq!(
211            (read_extended_cap_u32(&cap, AcsExtendedCapabilityHeader::CAPS_CONTROL.0) >> 16) as u16,
212            0
213        );
214
215        cap.restore(saved).expect("restore should succeed");
216        assert_eq!(
217            (read_extended_cap_u32(&cap, AcsExtendedCapabilityHeader::CAPS_CONTROL.0) >> 16) as u16,
218            DEFAULT_ACS_CAP_MASK
219        );
220    }
221}