pci_core/capabilities/
msi_cap.rs

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4//! MSI Capability.
5
6use super::PciCapability;
7use crate::capabilities::msix::MsiInterrupt;
8use crate::msi::MsiTarget;
9use crate::spec::caps::CapabilityId;
10use crate::spec::caps::msi::MsiCapabilityHeader;
11use inspect::Inspect;
12use inspect::InspectMut;
13use parking_lot::Mutex;
14use std::fmt::Debug;
15use std::sync::Arc;
16use vmcore::interrupt::Interrupt;
17
18/// MSI capability implementation for PCI configuration space.
19#[derive(Debug, Inspect)]
20pub struct MsiCapability {
21    #[inspect(with = "|x| inspect::adhoc(|req| x.lock().inspect_mut(req))")]
22    state: Arc<Mutex<MsiCapabilityState>>,
23    addr_64bit: bool,
24    per_vector_masking: bool,
25}
26
27#[derive(Debug, InspectMut)]
28struct MsiCapabilityState {
29    enabled: bool,
30    multiple_message_enable: u8,  // 2^(MME) messages allocated
31    multiple_message_capable: u8, // 2^(MMC) maximum messages requestable
32    #[inspect(hex)]
33    address: u64,
34    #[inspect(hex)]
35    data: u16,
36    #[inspect(hex)]
37    mask_bits: u32,
38    #[inspect(hex)]
39    pending_bits: u32,
40    interrupt: Option<MsiInterrupt>,
41}
42
43impl MsiCapabilityState {
44    fn new(multiple_message_capable: u8, _addr_64bit: bool, per_vector_masking: bool) -> Self {
45        Self {
46            enabled: false,
47            multiple_message_enable: 0,
48            multiple_message_capable,
49            address: 0,
50            data: 0,
51            mask_bits: if per_vector_masking { 0xFFFFFFFF } else { 0 },
52            pending_bits: 0,
53            interrupt: None,
54        }
55    }
56
57    fn control_register(&self, addr_64bit: bool, per_vector_masking: bool) -> u32 {
58        let mut control = 0u32;
59        control |= (self.multiple_message_capable as u32) << 1; // MMC field (bits 1-3)
60        control |= (self.multiple_message_enable as u32) << 4; // MME field (bits 4-6)
61        if addr_64bit {
62            control |= 1 << 7; // 64-bit Address Capable (bit 7)
63        }
64        if per_vector_masking {
65            control |= 1 << 8; // Per-vector Masking Capable (bit 8)
66        }
67        if self.enabled {
68            control |= 1 << 0; // MSI Enable (bit 0)
69        }
70        control
71    }
72}
73
74impl MsiCapability {
75    /// Create a new MSI capability.
76    ///
77    /// # Arguments
78    /// * `multiple_message_capable` - log2 of maximum number of messages (0-5)
79    /// * `addr_64bit` - Whether 64-bit addressing is supported
80    /// * `per_vector_masking` - Whether per-vector masking is supported
81    /// * `msi_target` - MSI target
82    pub fn new(
83        multiple_message_capable: u8,
84        addr_64bit: bool,
85        per_vector_masking: bool,
86        msi_target: &MsiTarget,
87    ) -> Self {
88        assert!(multiple_message_capable <= 5, "MMC must be 0-5");
89
90        let interrupt = MsiInterrupt::new(msi_target.clone());
91        let state = MsiCapabilityState {
92            interrupt: Some(interrupt),
93            ..MsiCapabilityState::new(multiple_message_capable, addr_64bit, per_vector_masking)
94        };
95
96        Self {
97            state: Arc::new(Mutex::new(state)),
98            addr_64bit,
99            per_vector_masking,
100        }
101    }
102
103    /// Get the interrupt object for signaling MSI.
104    pub fn interrupt(&self) -> Option<Interrupt> {
105        self.state.lock().interrupt.as_mut().map(|i| i.interrupt())
106    }
107
108    fn len_bytes(&self) -> usize {
109        let mut len = 8; // Base: ID + Next + Control + Message Address Low
110        if self.addr_64bit {
111            len += 4; // Message Address High
112        }
113        len += 2; // Message Data (16-bit, but aligned to 4-byte boundary)
114        if self.per_vector_masking {
115            len += 8; // Mask Bits + Pending Bits
116        }
117        // Round up to next 4-byte boundary
118        (len + 3) & !3
119    }
120}
121
122impl PciCapability for MsiCapability {
123    fn label(&self) -> &str {
124        "msi"
125    }
126
127    fn capability_id(&self) -> CapabilityId {
128        CapabilityId::MSI
129    }
130
131    fn len(&self) -> usize {
132        self.len_bytes()
133    }
134
135    fn read_u32(&self, offset: u16) -> u32 {
136        let state = self.state.lock();
137
138        match MsiCapabilityHeader(offset) {
139            MsiCapabilityHeader::CONTROL_CAPS => {
140                let control_reg = state.control_register(self.addr_64bit, self.per_vector_masking);
141                CapabilityId::MSI.0 as u32 | (control_reg << 16)
142            }
143            MsiCapabilityHeader::MSG_ADDR_LO => state.address as u32,
144            MsiCapabilityHeader::MSG_ADDR_HI if self.addr_64bit => (state.address >> 32) as u32,
145            MsiCapabilityHeader::MSG_DATA_32 if !self.addr_64bit => state.data as u32,
146            MsiCapabilityHeader::MSG_DATA_64 if self.addr_64bit => state.data as u32,
147            MsiCapabilityHeader::MASK_BITS if self.addr_64bit && self.per_vector_masking => {
148                state.mask_bits
149            }
150            MsiCapabilityHeader::PENDING_BITS if self.addr_64bit && self.per_vector_masking => {
151                state.pending_bits
152            }
153            _ => {
154                tracelimit::warn_ratelimited!("Unexpected MSI read offset {:#x}", offset);
155                0
156            }
157        }
158    }
159
160    fn write_u32(&mut self, offset: u16, val: u32) {
161        let mut state = self.state.lock();
162
163        match MsiCapabilityHeader(offset) {
164            MsiCapabilityHeader::CONTROL_CAPS => {
165                let control_val = (val >> 16) & 0xFFFF;
166                let old_enabled = state.enabled;
167                let new_enabled = control_val & 1 != 0;
168                let mme = ((control_val >> 4) & 0x7) as u8;
169
170                // Update MME (Multiple Message Enable) - limited by MMC
171                state.multiple_message_enable = mme.min(state.multiple_message_capable);
172                state.enabled = new_enabled;
173
174                // Handle enable/disable state changes
175                let address = state.address;
176                let data = state.data as u32;
177                if let Some(ref mut interrupt) = state.interrupt {
178                    if new_enabled && !old_enabled {
179                        // Enable MSI
180                        interrupt.enable(address, data, false);
181                    } else if !new_enabled && old_enabled {
182                        // Disable MSI
183                        interrupt.disable();
184                    }
185                }
186            }
187            MsiCapabilityHeader::MSG_ADDR_LO => {
188                state.address = (state.address & 0xFFFFFFFF00000000) | (val as u64);
189
190                // Update interrupt if enabled
191                if state.enabled {
192                    let address = state.address;
193                    let data = state.data as u32;
194                    if let Some(ref mut interrupt) = state.interrupt {
195                        interrupt.enable(address, data, false);
196                    }
197                }
198            }
199            MsiCapabilityHeader::MSG_ADDR_HI if self.addr_64bit => {
200                state.address = (state.address & 0xFFFFFFFF) | ((val as u64) << 32);
201
202                // Update interrupt if enabled
203                if state.enabled {
204                    let address = state.address;
205                    let data = state.data as u32;
206                    if let Some(ref mut interrupt) = state.interrupt {
207                        interrupt.enable(address, data, false);
208                    }
209                }
210            }
211            MsiCapabilityHeader::MSG_DATA_32 if !self.addr_64bit => {
212                state.data = val as u16;
213
214                // Update interrupt if enabled
215                if state.enabled {
216                    let address = state.address;
217                    let data = state.data as u32;
218                    if let Some(ref mut interrupt) = state.interrupt {
219                        interrupt.enable(address, data, false);
220                    }
221                }
222            }
223            MsiCapabilityHeader::MSG_DATA_64 if self.addr_64bit => {
224                state.data = val as u16;
225
226                // Update interrupt if enabled
227                if state.enabled {
228                    let address = state.address;
229                    let data = state.data as u32;
230                    if let Some(ref mut interrupt) = state.interrupt {
231                        interrupt.enable(address, data, false);
232                    }
233                }
234            }
235            MsiCapabilityHeader::MASK_BITS if self.addr_64bit && self.per_vector_masking => {
236                state.mask_bits = val;
237            }
238            MsiCapabilityHeader::PENDING_BITS if self.addr_64bit && self.per_vector_masking => {
239                // Pending bits are typically read-only, but some implementations may allow clearing
240                tracelimit::warn_ratelimited!(
241                    "Write to MSI pending bits register (typically read-only)"
242                );
243            }
244            _ => {
245                tracelimit::warn_ratelimited!("Unexpected MSI write offset {:#x}", offset);
246            }
247        }
248    }
249
250    fn reset(&mut self) {
251        let mut state = self.state.lock();
252
253        // Disable MSI
254        if state.enabled {
255            if let Some(ref mut interrupt) = state.interrupt {
256                interrupt.disable();
257            }
258        }
259
260        // Reset to default values
261        state.enabled = false;
262        state.multiple_message_enable = 0;
263        state.address = 0;
264        state.data = 0;
265        if self.per_vector_masking {
266            state.mask_bits = 0;
267            state.pending_bits = 0;
268        }
269    }
270}
271
272mod save_restore {
273    use super::*;
274    use thiserror::Error;
275    use vmcore::save_restore::RestoreError;
276    use vmcore::save_restore::SaveError;
277    use vmcore::save_restore::SaveRestore;
278
279    mod state {
280        use mesh::payload::Protobuf;
281        use vmcore::save_restore::SavedStateRoot;
282
283        #[derive(Debug, Protobuf, SavedStateRoot)]
284        #[mesh(package = "pci.caps.msi")]
285        pub struct SavedState {
286            #[mesh(1)]
287            pub enabled: bool,
288            #[mesh(2)]
289            pub multiple_message_enable: u8,
290            #[mesh(3)]
291            pub address: u64,
292            #[mesh(4)]
293            pub data: u16,
294            #[mesh(5)]
295            pub mask_bits: u32,
296            #[mesh(6)]
297            pub pending_bits: u32,
298        }
299    }
300
301    #[derive(Debug, Error)]
302    enum MsiRestoreError {
303        #[error("invalid multiple message enable value: {0}")]
304        InvalidMultipleMessageEnable(u8),
305    }
306
307    impl SaveRestore for MsiCapability {
308        type SavedState = state::SavedState;
309
310        fn save(&mut self) -> Result<Self::SavedState, SaveError> {
311            let state = self.state.lock();
312            Ok(state::SavedState {
313                enabled: state.enabled,
314                multiple_message_enable: state.multiple_message_enable,
315                address: state.address,
316                data: state.data,
317                mask_bits: state.mask_bits,
318                pending_bits: state.pending_bits,
319            })
320        }
321
322        fn restore(&mut self, saved_state: Self::SavedState) -> Result<(), RestoreError> {
323            let state::SavedState {
324                enabled,
325                multiple_message_enable,
326                address,
327                data,
328                mask_bits,
329                pending_bits,
330            } = saved_state;
331
332            if multiple_message_enable > 5 {
333                return Err(RestoreError::InvalidSavedState(
334                    MsiRestoreError::InvalidMultipleMessageEnable(multiple_message_enable).into(),
335                ));
336            }
337
338            let mut state = self.state.lock();
339
340            // Disable current interrupt if needed
341            if state.enabled {
342                if let Some(ref mut interrupt) = state.interrupt {
343                    interrupt.disable();
344                }
345            }
346
347            // Restore state
348            state.enabled = enabled;
349            state.multiple_message_enable =
350                multiple_message_enable.min(state.multiple_message_capable);
351            state.address = address;
352            state.data = data;
353            state.mask_bits = mask_bits;
354            state.pending_bits = pending_bits;
355
356            // Re-enable interrupt if needed
357            if state.enabled {
358                let address = state.address;
359                let data = state.data as u32;
360                if let Some(ref mut interrupt) = state.interrupt {
361                    interrupt.enable(address, data, false);
362                }
363            }
364
365            Ok(())
366        }
367    }
368}
369
370#[cfg(test)]
371mod tests {
372    use super::*;
373    use crate::msi::MsiConnection;
374    use crate::test_helpers::TestPciInterruptController;
375
376    #[test]
377    fn msi_check() {
378        let msi_conn = MsiConnection::new();
379        let mut cap = MsiCapability::new(2, true, false, msi_conn.target()); // 4 messages max, 64-bit, no masking
380        let msi_controller = TestPciInterruptController::new();
381        msi_conn.connect(msi_controller.signal_msi());
382
383        // Check initial capabilities register
384        // Capability ID (0x05) + MMC=2 (4 messages) + 64-bit capable
385        assert_eq!(cap.read_u32(0), 0x00840005); // 0x05 (ID) | (0x84 << 16) where 0x84 = MMC=2(<<1) + 64bit(<<7)
386
387        // Check initial address registers
388        assert_eq!(cap.read_u32(4), 0); // Address low
389        assert_eq!(cap.read_u32(8), 0); // Address high
390        assert_eq!(cap.read_u32(12), 0); // Data
391
392        // Write address and data
393        cap.write_u32(4, 0x12345678);
394        cap.write_u32(8, 0x9abcdef0);
395        cap.write_u32(12, 0x1234);
396
397        assert_eq!(cap.read_u32(4), 0x12345678);
398        assert_eq!(cap.read_u32(8), 0x9abcdef0);
399        assert_eq!(cap.read_u32(12), 0x1234);
400
401        // Enable MSI with 2 messages (MME=1)
402        cap.write_u32(0, 0x00110005); // Enable + MME=1 (bits 0 and 4-6)
403        assert_eq!(cap.read_u32(0), 0x00950005); // Should show enabled with all capability bits
404
405        // Test reset
406        cap.reset();
407        assert_eq!(cap.read_u32(0), 0x00840005); // Back to disabled
408        assert_eq!(cap.read_u32(4), 0);
409        assert_eq!(cap.read_u32(8), 0);
410        assert_eq!(cap.read_u32(12), 0);
411    }
412
413    #[test]
414    fn msi_32bit_check() {
415        let msi_conn = MsiConnection::new();
416        let mut cap = MsiCapability::new(1, false, false, msi_conn.target()); // 2 messages max, 32-bit, no masking
417        let msi_controller = TestPciInterruptController::new();
418        msi_conn.connect(msi_controller.signal_msi());
419
420        // Check initial capabilities register (no 64-bit bit set)
421        assert_eq!(cap.read_u32(0), 0x00020005); // MMC=1 (2 messages) + Capability ID
422
423        // For 32-bit, data is at offset 8, not 12
424        cap.write_u32(4, 0x12345678); // Address
425        cap.write_u32(8, 0x1234); // Data
426
427        assert_eq!(cap.read_u32(4), 0x12345678);
428        assert_eq!(cap.read_u32(8), 0x1234);
429    }
430
431    #[test]
432    fn test_msi_save_restore() {
433        use vmcore::save_restore::SaveRestore;
434
435        let msi_conn = MsiConnection::new();
436        let mut cap = MsiCapability::new(2, true, false, msi_conn.target()); // 4 messages max, 64-bit, no masking
437        let msi_controller = TestPciInterruptController::new();
438        msi_conn.connect(msi_controller.signal_msi());
439
440        // Configure MSI capability with specific values
441        cap.write_u32(4, 0x12345678); // Address low
442        cap.write_u32(8, 0x9abcdef0); // Address high
443        cap.write_u32(12, 0x5678); // Data
444        cap.write_u32(0, 0x00110001); // Enable MSI with MME=1 (2 messages)
445
446        // Verify initial state
447        assert_eq!(cap.read_u32(0), 0x00950005); // Enabled with capabilities
448        assert_eq!(cap.read_u32(4), 0x12345678);
449        assert_eq!(cap.read_u32(8), 0x9abcdef0);
450        assert_eq!(cap.read_u32(12), 0x5678);
451
452        // Save the state
453        let saved_state = cap.save().expect("save should succeed");
454
455        // Reset the capability
456        cap.reset();
457        assert_eq!(cap.read_u32(0), 0x00840005); // Back to disabled
458        assert_eq!(cap.read_u32(4), 0);
459        assert_eq!(cap.read_u32(8), 0);
460        assert_eq!(cap.read_u32(12), 0);
461
462        // Restore the state
463        cap.restore(saved_state).expect("restore should succeed");
464
465        // Verify restored state
466        assert_eq!(cap.read_u32(0), 0x00950005); // Should be enabled again
467        assert_eq!(cap.read_u32(4), 0x12345678);
468        assert_eq!(cap.read_u32(8), 0x9abcdef0);
469        assert_eq!(cap.read_u32(12), 0x5678);
470    }
471
472    #[test]
473    fn test_msi_save_restore_32bit_with_masking() {
474        use vmcore::save_restore::SaveRestore;
475
476        let msi_conn = MsiConnection::new();
477        let mut cap = MsiCapability::new(3, false, true, msi_conn.target()); // 8 messages max, 32-bit, with masking
478        let msi_controller = TestPciInterruptController::new();
479        msi_conn.connect(msi_controller.signal_msi());
480
481        // Configure MSI capability with specific values
482        cap.write_u32(4, 0x87654321); // Address (32-bit)
483        cap.write_u32(8, 0x1234); // Data
484        cap.write_u32(12, 0xaaaabbbb); // Mask bits (for per-vector masking)
485        cap.write_u32(0, 0x00210001); // Enable MSI with MME=2 (4 messages)
486
487        // Verify initial state
488        let control_reg = cap.read_u32(0);
489        let control_val = (control_reg >> 16) & 0xFFFF;
490        assert!(control_val & 1 != 0); // MSI enabled
491        assert_eq!((control_val >> 4) & 0x7, 2); // MME = 2
492        assert_eq!(cap.read_u32(4), 0x87654321);
493        assert_eq!(cap.read_u32(8), 0x1234);
494
495        // Save the state
496        let saved_state = cap.save().expect("save should succeed");
497
498        // Modify state
499        cap.write_u32(4, 0x11111111);
500        cap.write_u32(8, 0x9999);
501        cap.write_u32(0, 0x00000005); // Disable MSI
502
503        // Verify changed state
504        let control_reg = cap.read_u32(0);
505        let control_val = (control_reg >> 16) & 0xFFFF;
506        assert_eq!(control_val & 1, 0); // MSI disabled
507        assert_eq!(cap.read_u32(4), 0x11111111);
508        assert_eq!(cap.read_u32(8), 0x9999);
509
510        // Restore the state
511        cap.restore(saved_state).expect("restore should succeed");
512
513        // Verify restored state
514        let control_reg = cap.read_u32(0);
515        let control_val = (control_reg >> 16) & 0xFFFF;
516        assert!(control_val & 1 != 0); // MSI enabled
517        assert_eq!((control_val >> 4) & 0x7, 2); // MME = 2
518        assert_eq!(cap.read_u32(4), 0x87654321);
519        assert_eq!(cap.read_u32(8), 0x1234);
520    }
521
522    #[test]
523    fn test_msi_save_restore_mme_clamping() {
524        use vmcore::save_restore::SaveRestore;
525
526        let msi_conn = MsiConnection::new();
527        let mut cap = MsiCapability::new(1, true, false, msi_conn.target()); // Only 2 messages max (MMC=1)
528        let msi_controller = TestPciInterruptController::new();
529        msi_conn.connect(msi_controller.signal_msi());
530
531        // Configure with MME=3 (8 messages), but device only supports MMC=1 (2 messages)
532        cap.write_u32(4, 0x12345678); // Address low
533        cap.write_u32(8, 0x9abcdef0); // Address high
534        cap.write_u32(12, 0x5678); // Data
535        cap.write_u32(0, 0x00310001); // Enable MSI with MME=3
536
537        // Verify MME was clamped to MMC (1)
538        let control_reg = cap.read_u32(0);
539        let control_val = (control_reg >> 16) & 0xFFFF;
540        let mme = (control_val >> 4) & 0x7;
541        assert_eq!(mme, 1); // Should be clamped to MMC=1
542
543        // Save the state (which should preserve the clamped MME)
544        let saved_state = cap.save().expect("save should succeed");
545
546        // Reset the capability
547        cap.reset();
548
549        // Restore the state
550        cap.restore(saved_state).expect("restore should succeed");
551
552        // Check that MME is still properly clamped after restore
553        let control_reg = cap.read_u32(0);
554        let control_val = (control_reg >> 16) & 0xFFFF;
555        let mme = (control_val >> 4) & 0x7;
556        let enabled = control_val & 1 != 0;
557        assert_eq!(mme, 1); // Should still be clamped to MMC=1
558        assert!(enabled); // Should be enabled
559        assert_eq!(cap.read_u32(4), 0x12345678);
560        assert_eq!(cap.read_u32(8), 0x9abcdef0);
561        assert_eq!(cap.read_u32(12), 0x5678);
562    }
563}