Skip to main content

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