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    fn as_msi_cap(&self) -> Option<&MsiCapability> {
272        Some(self)
273    }
274
275    fn as_msi_cap_mut(&mut self) -> Option<&mut MsiCapability> {
276        Some(self)
277    }
278}
279
280mod save_restore {
281    use super::*;
282    use thiserror::Error;
283    use vmcore::save_restore::RestoreError;
284    use vmcore::save_restore::SaveError;
285    use vmcore::save_restore::SaveRestore;
286
287    mod state {
288        use mesh::payload::Protobuf;
289        use vmcore::save_restore::SavedStateRoot;
290
291        #[derive(Debug, Protobuf, SavedStateRoot)]
292        #[mesh(package = "pci.caps.msi")]
293        pub struct SavedState {
294            #[mesh(1)]
295            pub enabled: bool,
296            #[mesh(2)]
297            pub multiple_message_enable: u8,
298            #[mesh(3)]
299            pub address: u64,
300            #[mesh(4)]
301            pub data: u16,
302            #[mesh(5)]
303            pub mask_bits: u32,
304            #[mesh(6)]
305            pub pending_bits: u32,
306        }
307    }
308
309    #[derive(Debug, Error)]
310    enum MsiRestoreError {
311        #[error("invalid multiple message enable value: {0}")]
312        InvalidMultipleMessageEnable(u8),
313    }
314
315    impl SaveRestore for MsiCapability {
316        type SavedState = state::SavedState;
317
318        fn save(&mut self) -> Result<Self::SavedState, SaveError> {
319            let state = self.state.lock();
320            Ok(state::SavedState {
321                enabled: state.enabled,
322                multiple_message_enable: state.multiple_message_enable,
323                address: state.address,
324                data: state.data,
325                mask_bits: state.mask_bits,
326                pending_bits: state.pending_bits,
327            })
328        }
329
330        fn restore(&mut self, saved_state: Self::SavedState) -> Result<(), RestoreError> {
331            let state::SavedState {
332                enabled,
333                multiple_message_enable,
334                address,
335                data,
336                mask_bits,
337                pending_bits,
338            } = saved_state;
339
340            if multiple_message_enable > 5 {
341                return Err(RestoreError::InvalidSavedState(
342                    MsiRestoreError::InvalidMultipleMessageEnable(multiple_message_enable).into(),
343                ));
344            }
345
346            let mut state = self.state.lock();
347
348            // Disable current interrupt if needed
349            if state.enabled {
350                if let Some(ref mut interrupt) = state.interrupt {
351                    interrupt.disable();
352                }
353            }
354
355            // Restore state
356            state.enabled = enabled;
357            state.multiple_message_enable =
358                multiple_message_enable.min(state.multiple_message_capable);
359            state.address = address;
360            state.data = data;
361            state.mask_bits = mask_bits;
362            state.pending_bits = pending_bits;
363
364            // Re-enable interrupt if needed
365            if state.enabled {
366                let address = state.address;
367                let data = state.data as u32;
368                if let Some(ref mut interrupt) = state.interrupt {
369                    interrupt.enable(address, data, false);
370                }
371            }
372
373            Ok(())
374        }
375    }
376}
377
378#[cfg(test)]
379mod tests {
380    use super::*;
381    use crate::msi::MsiConnection;
382    use crate::test_helpers::TestPciInterruptController;
383
384    #[test]
385    fn msi_check() {
386        let msi_conn = MsiConnection::new();
387        let mut cap = MsiCapability::new(2, true, false, msi_conn.target()); // 4 messages max, 64-bit, no masking
388        let msi_controller = TestPciInterruptController::new();
389        msi_conn.connect(msi_controller.signal_msi());
390
391        // Check initial capabilities register
392        // Capability ID (0x05) + MMC=2 (4 messages) + 64-bit capable
393        assert_eq!(cap.read_u32(0), 0x00840005); // 0x05 (ID) | (0x84 << 16) where 0x84 = MMC=2(<<1) + 64bit(<<7)
394
395        // Check initial address registers
396        assert_eq!(cap.read_u32(4), 0); // Address low
397        assert_eq!(cap.read_u32(8), 0); // Address high
398        assert_eq!(cap.read_u32(12), 0); // Data
399
400        // Write address and data
401        cap.write_u32(4, 0x12345678);
402        cap.write_u32(8, 0x9abcdef0);
403        cap.write_u32(12, 0x1234);
404
405        assert_eq!(cap.read_u32(4), 0x12345678);
406        assert_eq!(cap.read_u32(8), 0x9abcdef0);
407        assert_eq!(cap.read_u32(12), 0x1234);
408
409        // Enable MSI with 2 messages (MME=1)
410        cap.write_u32(0, 0x00110005); // Enable + MME=1 (bits 0 and 4-6)
411        assert_eq!(cap.read_u32(0), 0x00950005); // Should show enabled with all capability bits
412
413        // Test reset
414        cap.reset();
415        assert_eq!(cap.read_u32(0), 0x00840005); // Back to disabled
416        assert_eq!(cap.read_u32(4), 0);
417        assert_eq!(cap.read_u32(8), 0);
418        assert_eq!(cap.read_u32(12), 0);
419    }
420
421    #[test]
422    fn msi_32bit_check() {
423        let msi_conn = MsiConnection::new();
424        let mut cap = MsiCapability::new(1, false, false, msi_conn.target()); // 2 messages max, 32-bit, no masking
425        let msi_controller = TestPciInterruptController::new();
426        msi_conn.connect(msi_controller.signal_msi());
427
428        // Check initial capabilities register (no 64-bit bit set)
429        assert_eq!(cap.read_u32(0), 0x00020005); // MMC=1 (2 messages) + Capability ID
430
431        // For 32-bit, data is at offset 8, not 12
432        cap.write_u32(4, 0x12345678); // Address
433        cap.write_u32(8, 0x1234); // Data
434
435        assert_eq!(cap.read_u32(4), 0x12345678);
436        assert_eq!(cap.read_u32(8), 0x1234);
437    }
438
439    #[test]
440    fn test_msi_save_restore() {
441        use vmcore::save_restore::SaveRestore;
442
443        let msi_conn = MsiConnection::new();
444        let mut cap = MsiCapability::new(2, true, false, msi_conn.target()); // 4 messages max, 64-bit, no masking
445        let msi_controller = TestPciInterruptController::new();
446        msi_conn.connect(msi_controller.signal_msi());
447
448        // Configure MSI capability with specific values
449        cap.write_u32(4, 0x12345678); // Address low
450        cap.write_u32(8, 0x9abcdef0); // Address high
451        cap.write_u32(12, 0x5678); // Data
452        cap.write_u32(0, 0x00110001); // Enable MSI with MME=1 (2 messages)
453
454        // Verify initial state
455        assert_eq!(cap.read_u32(0), 0x00950005); // Enabled with capabilities
456        assert_eq!(cap.read_u32(4), 0x12345678);
457        assert_eq!(cap.read_u32(8), 0x9abcdef0);
458        assert_eq!(cap.read_u32(12), 0x5678);
459
460        // Save the state
461        let saved_state = cap.save().expect("save should succeed");
462
463        // Reset the capability
464        cap.reset();
465        assert_eq!(cap.read_u32(0), 0x00840005); // Back to disabled
466        assert_eq!(cap.read_u32(4), 0);
467        assert_eq!(cap.read_u32(8), 0);
468        assert_eq!(cap.read_u32(12), 0);
469
470        // Restore the state
471        cap.restore(saved_state).expect("restore should succeed");
472
473        // Verify restored state
474        assert_eq!(cap.read_u32(0), 0x00950005); // Should be enabled again
475        assert_eq!(cap.read_u32(4), 0x12345678);
476        assert_eq!(cap.read_u32(8), 0x9abcdef0);
477        assert_eq!(cap.read_u32(12), 0x5678);
478    }
479
480    #[test]
481    fn test_msi_save_restore_32bit_with_masking() {
482        use vmcore::save_restore::SaveRestore;
483
484        let msi_conn = MsiConnection::new();
485        let mut cap = MsiCapability::new(3, false, true, msi_conn.target()); // 8 messages max, 32-bit, with masking
486        let msi_controller = TestPciInterruptController::new();
487        msi_conn.connect(msi_controller.signal_msi());
488
489        // Configure MSI capability with specific values
490        cap.write_u32(4, 0x87654321); // Address (32-bit)
491        cap.write_u32(8, 0x1234); // Data
492        cap.write_u32(12, 0xaaaabbbb); // Mask bits (for per-vector masking)
493        cap.write_u32(0, 0x00210001); // Enable MSI with MME=2 (4 messages)
494
495        // Verify initial state
496        let control_reg = cap.read_u32(0);
497        let control_val = (control_reg >> 16) & 0xFFFF;
498        assert!(control_val & 1 != 0); // MSI enabled
499        assert_eq!((control_val >> 4) & 0x7, 2); // MME = 2
500        assert_eq!(cap.read_u32(4), 0x87654321);
501        assert_eq!(cap.read_u32(8), 0x1234);
502
503        // Save the state
504        let saved_state = cap.save().expect("save should succeed");
505
506        // Modify state
507        cap.write_u32(4, 0x11111111);
508        cap.write_u32(8, 0x9999);
509        cap.write_u32(0, 0x00000005); // Disable MSI
510
511        // Verify changed state
512        let control_reg = cap.read_u32(0);
513        let control_val = (control_reg >> 16) & 0xFFFF;
514        assert_eq!(control_val & 1, 0); // MSI disabled
515        assert_eq!(cap.read_u32(4), 0x11111111);
516        assert_eq!(cap.read_u32(8), 0x9999);
517
518        // Restore the state
519        cap.restore(saved_state).expect("restore should succeed");
520
521        // Verify restored state
522        let control_reg = cap.read_u32(0);
523        let control_val = (control_reg >> 16) & 0xFFFF;
524        assert!(control_val & 1 != 0); // MSI enabled
525        assert_eq!((control_val >> 4) & 0x7, 2); // MME = 2
526        assert_eq!(cap.read_u32(4), 0x87654321);
527        assert_eq!(cap.read_u32(8), 0x1234);
528    }
529
530    #[test]
531    fn test_msi_save_restore_mme_clamping() {
532        use vmcore::save_restore::SaveRestore;
533
534        let msi_conn = MsiConnection::new();
535        let mut cap = MsiCapability::new(1, true, false, msi_conn.target()); // Only 2 messages max (MMC=1)
536        let msi_controller = TestPciInterruptController::new();
537        msi_conn.connect(msi_controller.signal_msi());
538
539        // Configure with MME=3 (8 messages), but device only supports MMC=1 (2 messages)
540        cap.write_u32(4, 0x12345678); // Address low
541        cap.write_u32(8, 0x9abcdef0); // Address high
542        cap.write_u32(12, 0x5678); // Data
543        cap.write_u32(0, 0x00310001); // Enable MSI with MME=3
544
545        // Verify MME was clamped to MMC (1)
546        let control_reg = cap.read_u32(0);
547        let control_val = (control_reg >> 16) & 0xFFFF;
548        let mme = (control_val >> 4) & 0x7;
549        assert_eq!(mme, 1); // Should be clamped to MMC=1
550
551        // Save the state (which should preserve the clamped MME)
552        let saved_state = cap.save().expect("save should succeed");
553
554        // Reset the capability
555        cap.reset();
556
557        // Restore the state
558        cap.restore(saved_state).expect("restore should succeed");
559
560        // Check that MME is still properly clamped after restore
561        let control_reg = cap.read_u32(0);
562        let control_val = (control_reg >> 16) & 0xFFFF;
563        let mme = (control_val >> 4) & 0x7;
564        let enabled = control_val & 1 != 0;
565        assert_eq!(mme, 1); // Should still be clamped to MMC=1
566        assert!(enabled); // Should be enabled
567        assert_eq!(cap.read_u32(4), 0x12345678);
568        assert_eq!(cap.read_u32(8), 0x9abcdef0);
569        assert_eq!(cap.read_u32(12), 0x5678);
570    }
571}