vmcore/
vpci_msi.rs

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4//! Trait to model host-assisted MSI/MSI-X configuration (when using VPCI).
5
6#![forbid(unsafe_code)]
7#![expect(missing_docs)]
8
9use async_trait::async_trait;
10use inspect::Inspect;
11use std::future::Future;
12use std::sync::Arc;
13use thiserror::Error;
14
15/// An MSI address/data pair.
16#[derive(Debug, Copy, Clone, PartialEq, Eq, Inspect)]
17pub struct MsiAddressData {
18    /// The MSI address.
19    #[inspect(hex)]
20    pub address: u64,
21    /// The data payload.
22    #[inspect(hex)]
23    pub data: u32,
24}
25
26pub struct VpciInterruptParameters<'a> {
27    pub vector: u32,
28    pub multicast: bool,
29    pub target_processors: &'a [u32],
30}
31
32/// Trait to model host-assisted MSI/MSI-X configuration when using VPCI.
33///
34/// The VPCI model allows the guest to register interrupts with the host, and
35/// have the host return an MSI (address, data) value to use to program the
36/// MSI/MSI-X configuration within the device.
37pub trait MapVpciInterrupt: Send + Sync {
38    fn register_interrupt(
39        &self,
40        vector_count: u32,
41        params: &VpciInterruptParameters<'_>,
42    ) -> impl Future<Output = Result<MsiAddressData, RegisterInterruptError>> + Send;
43
44    fn unregister_interrupt(&self, address: u64, data: u32) -> impl Future<Output = ()> + Send;
45}
46
47#[async_trait]
48trait DynMapVpciInterrupt: Send + Sync {
49    async fn register_interrupt(
50        &self,
51        vector_count: u32,
52        params: &VpciInterruptParameters<'_>,
53    ) -> Result<MsiAddressData, RegisterInterruptError>;
54
55    async fn unregister_interrupt(&self, address: u64, data: u32);
56}
57
58#[async_trait]
59impl<T: MapVpciInterrupt> DynMapVpciInterrupt for T {
60    async fn register_interrupt(
61        &self,
62        vector_count: u32,
63        params: &VpciInterruptParameters<'_>,
64    ) -> Result<MsiAddressData, RegisterInterruptError> {
65        self.register_interrupt(vector_count, params).await
66    }
67
68    async fn unregister_interrupt(&self, address: u64, data: u32) {
69        self.unregister_interrupt(address, data).await
70    }
71}
72
73/// A type-erased [`MapVpciInterrupt`] trait object.
74#[derive(Clone)]
75pub struct VpciInterruptMapper(Arc<dyn DynMapVpciInterrupt>);
76
77impl VpciInterruptMapper {
78    /// Creates a new instance from `mapper`.
79    pub fn new<T: 'static + MapVpciInterrupt>(mapper: Arc<T>) -> Self {
80        Self(mapper)
81    }
82}
83
84impl MapVpciInterrupt for VpciInterruptMapper {
85    async fn register_interrupt(
86        &self,
87        vector_count: u32,
88        params: &VpciInterruptParameters<'_>,
89    ) -> Result<MsiAddressData, RegisterInterruptError> {
90        self.0.register_interrupt(vector_count, params).await
91    }
92
93    async fn unregister_interrupt(&self, address: u64, data: u32) {
94        self.0.unregister_interrupt(address, data).await
95    }
96}
97
98#[derive(Debug, Error)]
99#[error("failed to register an interrupt")]
100pub struct RegisterInterruptError(#[source] Box<dyn std::error::Error + Send + Sync>);
101
102impl RegisterInterruptError {
103    pub fn new(err: impl Into<Box<dyn std::error::Error + Send + Sync>>) -> Self {
104        Self(err.into())
105    }
106}