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