pci_core/capabilities/
pci_express.rs

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4//! PCI Express Capability with Function Level Reset (FLR) support.
5
6use super::PciCapability;
7use crate::spec::caps::CapabilityId;
8use crate::spec::caps::pci_express;
9use crate::spec::caps::pci_express::PciExpressCapabilityHeader;
10use inspect::Inspect;
11use parking_lot::Mutex;
12use std::sync::Arc;
13
14/// FLR bit is the 28th bit in the Device Capabilities register (0 indexed).
15pub const PCI_EXPRESS_DEVICE_CAPS_FLR_BIT_MASK: u32 = 1 << 28;
16
17/// Callback interface for handling Function Level Reset (FLR) events.
18pub trait FlrHandler: Send + Sync + Inspect {
19    /// Called when Function Level Reset is initiated.
20    fn initiate_flr(&self);
21}
22
23#[derive(Debug, Inspect)]
24struct PciExpressState {
25    device_control: pci_express::DeviceControl,
26    device_status: pci_express::DeviceStatus,
27}
28
29impl PciExpressState {
30    fn new() -> Self {
31        Self {
32            device_control: pci_express::DeviceControl::new(),
33            device_status: pci_express::DeviceStatus::new(),
34        }
35    }
36}
37
38#[derive(Inspect)]
39/// Configurable PCI Express capability.
40pub struct PciExpressCapability {
41    pcie_capabilites: pci_express::PciExpressCapabilities,
42    device_capabilities: pci_express::DeviceCapabilities,
43    state: Arc<Mutex<PciExpressState>>,
44    #[inspect(skip)]
45    flr_handler: Option<Arc<dyn FlrHandler>>,
46}
47
48impl PciExpressCapability {
49    /// Creates a new PCI Express capability with FLR support.
50    ///
51    /// # Arguments
52    /// * `typ` - The spec-defined device or port type.
53    /// * `flr_handler` - Optional handler to be called when FLR is initiated. This emulator will report that FLR is supported if flr_handler = Some(_)
54    pub fn new(typ: pci_express::DevicePortType, flr_handler: Option<Arc<dyn FlrHandler>>) -> Self {
55        Self {
56            pcie_capabilites: pci_express::PciExpressCapabilities::new()
57                .with_capability_version(2)
58                .with_device_port_type(typ),
59            device_capabilities: pci_express::DeviceCapabilities::new()
60                .with_function_level_reset(flr_handler.is_some()),
61            state: Arc::new(Mutex::new(PciExpressState::new())),
62            flr_handler,
63        }
64    }
65
66    fn handle_device_control_write(&mut self, new_control: pci_express::DeviceControl) {
67        let mut state = self.state.lock();
68
69        // Check if FLR was initiated
70        let old_flr = state.device_control.initiate_function_level_reset();
71        let new_flr = new_control.initiate_function_level_reset();
72
73        // DEVNOTE: It is "safe" to drop a new FLR request if there is still a previous
74        // FLR request in progress. The PCIe spec indicates that such behavior is undefined,
75        // so we choose to ignore the new FLR request.
76        if new_flr && !old_flr {
77            if let Some(handler) = &self.flr_handler {
78                handler.initiate_flr();
79            }
80        }
81
82        // Update the control register but clear the FLR bit as it's self-clearing
83        state.device_control = new_control.with_initiate_function_level_reset(false);
84    }
85}
86
87impl PciCapability for PciExpressCapability {
88    fn label(&self) -> &str {
89        "pci-express"
90    }
91
92    fn len(&self) -> usize {
93        // We only implement the basic PCIe capability structure:
94        // 0x00: PCIe Capabilities (2 bytes) + Next Pointer (1 byte) + Capability ID (1 byte)
95        // 0x04: Device Capabilities (4 bytes)
96        // 0x08: Device Control (2 bytes) + Device Status (2 bytes)
97        // Total: 12 bytes (0x0C)
98        0x0C
99    }
100
101    fn read_u32(&self, offset: u16) -> u32 {
102        let label = self.label();
103        match PciExpressCapabilityHeader(offset) {
104            PciExpressCapabilityHeader::PCIE_CAPS => {
105                // PCIe Capabilities Register (16 bits) + Next Pointer (8 bits) + Capability ID (8 bits)
106                (self.pcie_capabilites.into_bits() as u32) << 16
107                    | CapabilityId::PCI_EXPRESS.0 as u32
108            }
109            PciExpressCapabilityHeader::DEVICE_CAPS => self.device_capabilities.into_bits(),
110            PciExpressCapabilityHeader::DEVICE_CTL_STS => {
111                let state = self.state.lock();
112                let device_control = state.device_control.into_bits() as u32;
113                let device_status = state.device_status.into_bits() as u32;
114                device_control | (device_status << 16)
115            }
116            _ => {
117                tracelimit::warn_ratelimited!(
118                    ?label,
119                    offset,
120                    "unhandled pci express capability read"
121                );
122                0
123            }
124        }
125    }
126
127    fn write_u32(&mut self, offset: u16, val: u32) {
128        let label = self.label();
129        match PciExpressCapabilityHeader(offset) {
130            PciExpressCapabilityHeader::PCIE_CAPS => {
131                // PCIe Capabilities register is read-only
132                tracelimit::warn_ratelimited!(
133                    ?label,
134                    offset,
135                    val,
136                    "write to read-only pcie capabilities"
137                );
138            }
139            PciExpressCapabilityHeader::DEVICE_CAPS => {
140                // Device Capabilities register is read-only
141                tracelimit::warn_ratelimited!(
142                    ?label,
143                    offset,
144                    val,
145                    "write to read-only device capabilities"
146                );
147            }
148            PciExpressCapabilityHeader::DEVICE_CTL_STS => {
149                // Lower 16 bits are Device Control (read-write)
150                // Upper 16 bits are Device Status (read-write, but some bits are read-only)
151                let new_control = pci_express::DeviceControl::from_bits(val as u16);
152                self.handle_device_control_write(new_control);
153
154                // Handle Device Status - most bits are write-1-to-clear
155                let new_status = pci_express::DeviceStatus::from_bits((val >> 16) as u16);
156                let mut state = self.state.lock();
157                let mut current_status = state.device_status;
158
159                // Clear bits that were written as 1 (write-1-to-clear semantics)
160                if new_status.correctable_error_detected() {
161                    current_status.set_correctable_error_detected(false);
162                }
163                if new_status.non_fatal_error_detected() {
164                    current_status.set_non_fatal_error_detected(false);
165                }
166                if new_status.fatal_error_detected() {
167                    current_status.set_fatal_error_detected(false);
168                }
169                if new_status.unsupported_request_detected() {
170                    current_status.set_unsupported_request_detected(false);
171                }
172
173                state.device_status = current_status;
174            }
175            _ => {
176                tracelimit::warn_ratelimited!(
177                    ?label,
178                    offset,
179                    val,
180                    "unhandled pci express capability write"
181                );
182            }
183        }
184    }
185
186    fn reset(&mut self) {
187        let mut state = self.state.lock();
188        *state = PciExpressState::new();
189    }
190}
191
192mod save_restore {
193    use super::*;
194    use vmcore::save_restore::RestoreError;
195    use vmcore::save_restore::SaveError;
196    use vmcore::save_restore::SaveRestore;
197
198    mod state {
199        use mesh::payload::Protobuf;
200        use vmcore::save_restore::SavedStateRoot;
201
202        #[derive(Protobuf, SavedStateRoot)]
203        #[mesh(package = "pci.capabilities.pci_express")]
204        pub struct SavedState {
205            #[mesh(1)]
206            pub device_control: u16,
207            #[mesh(2)]
208            pub device_status: u16,
209            #[mesh(3)]
210            pub flr_handler: u16,
211        }
212    }
213
214    impl SaveRestore for PciExpressCapability {
215        type SavedState = state::SavedState;
216
217        fn save(&mut self) -> Result<Self::SavedState, SaveError> {
218            Err(SaveError::NotSupported)
219        }
220
221        fn restore(&mut self, _: Self::SavedState) -> Result<(), RestoreError> {
222            Err(RestoreError::SavedStateNotSupported)
223        }
224    }
225}
226
227#[cfg(test)]
228mod tests {
229    use super::*;
230    use crate::spec::caps::pci_express::DevicePortType;
231    use std::sync::atomic::{AtomicBool, Ordering};
232
233    #[derive(Debug)]
234    struct TestFlrHandler {
235        flr_initiated: AtomicBool,
236    }
237
238    impl TestFlrHandler {
239        fn new() -> Arc<Self> {
240            Arc::new(Self {
241                flr_initiated: AtomicBool::new(false),
242            })
243        }
244
245        fn was_flr_initiated(&self) -> bool {
246            self.flr_initiated.load(Ordering::Acquire)
247        }
248
249        fn reset(&self) {
250            self.flr_initiated.store(false, Ordering::Release);
251        }
252    }
253
254    impl FlrHandler for TestFlrHandler {
255        fn initiate_flr(&self) {
256            self.flr_initiated.store(true, Ordering::Release);
257        }
258    }
259
260    impl Inspect for TestFlrHandler {
261        fn inspect(&self, req: inspect::Request<'_>) {
262            req.respond()
263                .field("flr_initiated", self.flr_initiated.load(Ordering::Acquire));
264        }
265    }
266
267    #[test]
268    fn test_pci_express_capability_read_u32_endpoint() {
269        let flr_handler = TestFlrHandler::new();
270        let cap = PciExpressCapability::new(DevicePortType::Endpoint, Some(flr_handler));
271
272        // Test PCIe Capabilities Register (offset 0x00)
273        let caps_val = cap.read_u32(0x00);
274        assert_eq!(caps_val & 0xFF, 0x10); // Capability ID = 0x10
275        assert_eq!((caps_val >> 8) & 0xFF, 0x00); // Next Pointer = 0x00
276        assert_eq!((caps_val >> 16) & 0xFFFF, 0x0002); // PCIe Caps: Version 2, Device/Port Type 0
277
278        // Test Device Capabilities Register (offset 0x04)
279        let device_caps_val = cap.read_u32(0x04);
280        assert_eq!(
281            device_caps_val & PCI_EXPRESS_DEVICE_CAPS_FLR_BIT_MASK,
282            PCI_EXPRESS_DEVICE_CAPS_FLR_BIT_MASK
283        ); // FLR bit should be set
284
285        // Test Device Control/Status Register (offset 0x08) - should be zero initially
286        let device_ctl_sts_val = cap.read_u32(0x08);
287        assert_eq!(device_ctl_sts_val, 0); // Both control and status should be 0
288
289        // Test unhandled offset - should return 0 and not panic
290        let unhandled_val = cap.read_u32(0x10);
291        assert_eq!(unhandled_val, 0);
292    }
293
294    #[test]
295    fn test_pci_express_capability_read_u32_root_port() {
296        let cap = PciExpressCapability::new(DevicePortType::RootPort, None);
297
298        // Test PCIe Capabilities Register (offset 0x00)
299        let caps_val = cap.read_u32(0x00);
300        assert_eq!(caps_val & 0xFF, 0x10); // Capability ID = 0x10
301        assert_eq!((caps_val >> 8) & 0xFF, 0x00); // Next Pointer = 0x00
302        assert_eq!((caps_val >> 16) & 0xFFFF, 0x0042); // PCIe Caps: Version 2, Device/Port Type 4
303    }
304
305    #[test]
306    fn test_pci_express_capability_read_u32_no_flr() {
307        let cap = PciExpressCapability::new(DevicePortType::Endpoint, None);
308
309        // Test Device Capabilities Register (offset 0x04) - FLR should not be set
310        let device_caps_val = cap.read_u32(0x04);
311        assert_eq!(device_caps_val & PCI_EXPRESS_DEVICE_CAPS_FLR_BIT_MASK, 0);
312    }
313
314    #[test]
315    fn test_pci_express_capability_write_u32_readonly_registers() {
316        let mut cap = PciExpressCapability::new(DevicePortType::Endpoint, None);
317
318        // Try to write to read-only PCIe Capabilities Register (offset 0x00)
319        let original_caps = cap.read_u32(0x00);
320        cap.write_u32(0x00, 0xFFFFFFFF);
321        assert_eq!(cap.read_u32(0x00), original_caps); // Should be unchanged
322
323        // Try to write to read-only Device Capabilities Register (offset 0x04)
324        let original_device_caps = cap.read_u32(0x04);
325        cap.write_u32(0x04, 0xFFFFFFFF);
326        assert_eq!(cap.read_u32(0x04), original_device_caps); // Should be unchanged
327    }
328
329    #[test]
330    fn test_pci_express_capability_write_u32_device_control() {
331        let flr_handler = TestFlrHandler::new();
332        let mut cap =
333            PciExpressCapability::new(DevicePortType::Endpoint, Some(flr_handler.clone()));
334
335        // Initial state should have FLR bit clear
336        let initial_ctl_sts = cap.read_u32(0x08);
337        assert_eq!(initial_ctl_sts & 0xFFFF, 0); // Device Control should be 0
338
339        // Test writing to Device Control Register (lower 16 bits of offset 0x08)
340        // Set some control bits but not FLR initially
341        cap.write_u32(0x08, 0x0001); // Enable correctable error reporting (bit 0)
342        let device_ctl_sts = cap.read_u32(0x08);
343        assert_eq!(device_ctl_sts & 0xFFFF, 0x0001); // Device Control should be set
344        assert!(!flr_handler.was_flr_initiated()); // FLR should not be triggered
345
346        // Test FLR initiation (bit 15 of Device Control)
347        flr_handler.reset();
348        cap.write_u32(0x08, 0x8001); // Set FLR bit (bit 15) and other control bits
349        let device_ctl_sts_after_flr = cap.read_u32(0x08);
350        assert_eq!(device_ctl_sts_after_flr & 0xFFFF, 0x0001); // FLR bit should be cleared, others remain
351        assert!(flr_handler.was_flr_initiated()); // FLR should be triggered
352
353        // Test that writing FLR bit when it's already been triggered behaves correctly
354        flr_handler.reset();
355        // After the previous FLR, device_control should have bit 0 set but FLR clear
356        // So writing 0x8000 (only FLR bit) should trigger FLR again
357        cap.write_u32(0x08, 0x8000); // Set FLR bit only
358        let device_ctl_sts_final = cap.read_u32(0x08);
359        assert_eq!(device_ctl_sts_final & 0xFFFF, 0x0000); // All bits should be cleared (FLR self-clears, bit 0 was overwritten)
360        assert!(flr_handler.was_flr_initiated()); // Should trigger because FLR transitioned from 0 to 1
361    }
362
363    #[test]
364    fn test_pci_express_capability_write_u32_device_status() {
365        let mut cap = PciExpressCapability::new(DevicePortType::Endpoint, None);
366
367        // Manually set some status bits to test write-1-to-clear behavior
368        {
369            let mut state = cap.state.lock();
370            state.device_status.set_correctable_error_detected(true);
371            state.device_status.set_non_fatal_error_detected(true);
372            state.device_status.set_fatal_error_detected(true);
373            state.device_status.set_unsupported_request_detected(true);
374        }
375
376        // Check that status bits are set
377        let device_ctl_sts = cap.read_u32(0x08);
378        let status_bits = (device_ctl_sts >> 16) & 0xFFFF;
379        assert_ne!(status_bits & 0x0F, 0); // Some status bits should be set
380
381        // Write 1 to clear correctable error bit (bit 0 of status)
382        cap.write_u32(0x08, 0x00010000); // Write 1 to bit 16 (correctable error in upper 16 bits)
383        let device_ctl_sts_after = cap.read_u32(0x08);
384        let status_bits_after = (device_ctl_sts_after >> 16) & 0xFFFF;
385        assert_eq!(status_bits_after & 0x01, 0); // Correctable error bit should be cleared
386        assert_ne!(status_bits_after & 0x0E, 0); // Other error bits should still be set
387
388        // Clear all remaining error bits
389        cap.write_u32(0x08, 0x000E0000); // Write 1 to bits 17-19 (other error bits)
390        let final_status = (cap.read_u32(0x08) >> 16) & 0xFFFF;
391        assert_eq!(final_status & 0x0F, 0); // All error bits should be cleared
392    }
393
394    #[test]
395    fn test_pci_express_capability_write_u32_unhandled_offset() {
396        let mut cap = PciExpressCapability::new(DevicePortType::Endpoint, None);
397
398        // Writing to unhandled offset should not panic
399        cap.write_u32(0x10, 0xFFFFFFFF);
400        // Should not crash and should not affect other registers
401        assert_eq!(cap.read_u32(0x08), 0); // Device Control/Status should still be 0
402    }
403
404    #[test]
405    fn test_pci_express_capability_reset() {
406        let flr_handler = TestFlrHandler::new();
407        let mut cap =
408            PciExpressCapability::new(DevicePortType::Endpoint, Some(flr_handler.clone()));
409
410        // Set some state
411        cap.write_u32(0x08, 0x0001); // Set some device control bits
412
413        // Manually set some status bits
414        {
415            let mut state = cap.state.lock();
416            state.device_status.set_correctable_error_detected(true);
417        }
418
419        // Verify state is set
420        let device_ctl_sts = cap.read_u32(0x08);
421        assert_ne!(device_ctl_sts, 0);
422
423        // Reset the capability
424        cap.reset();
425
426        // Verify state is cleared
427        let device_ctl_sts_after_reset = cap.read_u32(0x08);
428        assert_eq!(device_ctl_sts_after_reset, 0);
429    }
430
431    #[test]
432    fn test_pci_express_capability_length() {
433        let cap = PciExpressCapability::new(DevicePortType::Endpoint, None);
434        assert_eq!(cap.len(), 0x0C); // Should be 12 bytes
435    }
436
437    #[test]
438    fn test_pci_express_capability_label() {
439        let cap = PciExpressCapability::new(DevicePortType::Endpoint, None);
440        assert_eq!(cap.label(), "pci-express");
441    }
442}