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