@@ -20,6 +20,7 @@ use kvm_bindings::{
2020} ;
2121use kvm_ioctls:: VmFd ;
2222use log:: debug;
23+ use serde:: { Deserialize , Serialize } ;
2324use vm_device:: interrupt:: { InterruptSourceGroup , MsiIrqSourceConfig } ;
2425use vmm_sys_util:: errno;
2526use vmm_sys_util:: eventfd:: EventFd ;
@@ -28,6 +29,7 @@ pub use crate::arch::{ArchVm as Vm, ArchVmError, VmState};
2829use crate :: device_manager:: resources:: ResourceAllocator ;
2930use crate :: logger:: info;
3031use crate :: persist:: CreateSnapshotError ;
32+ use crate :: snapshot:: Persist ;
3133use crate :: utils:: u64_to_usize;
3234use crate :: vmm_config:: snapshot:: SnapshotType ;
3335use crate :: vstate:: memory:: {
@@ -49,7 +51,7 @@ pub enum InterruptError {
4951 Kvm ( #[ from] kvm_ioctls:: Error ) ,
5052}
5153
52- #[ derive( Debug ) ]
54+ #[ derive( Debug , Serialize , Deserialize ) ]
5355/// A struct representing an interrupt line used by some device of the microVM
5456pub struct RoutingEntry {
5557 entry : kvm_irq_routing_entry ,
@@ -114,6 +116,38 @@ impl MsiVectorGroup {
114116 }
115117}
116118
119+ impl < ' a > Persist < ' a > for MsiVectorGroup {
120+ type State = HashMap < u32 , u32 > ;
121+ type ConstructorArgs = Arc < Vm > ;
122+ type Error = InterruptError ;
123+
124+ fn save ( & self ) -> Self :: State {
125+ // We don't save the "enabled" state of the MSI interrupt. PCI devices store the MSI-X
126+ // configuration and make sure that the vector is enabled during the restore path if it was
127+ // initially enabled
128+ self . irq_routes
129+ . iter ( )
130+ . map ( |( id, route) | ( * id, route. gsi ) )
131+ . collect ( )
132+ }
133+
134+ fn restore (
135+ constructor_args : Self :: ConstructorArgs ,
136+ state : & Self :: State ,
137+ ) -> std:: result:: Result < Self , Self :: Error > {
138+ let mut irq_routes = HashMap :: new ( ) ;
139+
140+ for ( id, gsi) in state {
141+ irq_routes. insert ( * id, MsiVector :: new ( * gsi, false ) ?) ;
142+ }
143+
144+ Ok ( MsiVectorGroup {
145+ vm : constructor_args,
146+ irq_routes,
147+ } )
148+ }
149+ }
150+
117151impl InterruptSourceGroup for MsiVectorGroup {
118152 fn enable ( & self ) -> vm_device:: interrupt:: Result < ( ) > {
119153 for ( _, route) in self . irq_routes . iter ( ) {
@@ -210,7 +244,7 @@ pub struct VmCommon {
210244 /// The guest memory of this Vm.
211245 pub guest_memory : GuestMemoryMmap ,
212246 /// Interrupts used by Vm's devices
213- interrupts : Arc < Mutex < HashMap < u32 , RoutingEntry > > > ,
247+ pub interrupts : Arc < Mutex < HashMap < u32 , RoutingEntry > > > ,
214248}
215249
216250/// Errors associated with the wrappers over KVM ioctls.
@@ -891,4 +925,26 @@ pub(crate) mod tests {
891925
892926 msix_group. set_gsi ( ) . unwrap ( ) ;
893927 }
928+
929+ #[ test]
930+ fn test_msi_vector_group_persistence ( ) {
931+ let ( _, mut vm) = setup_vm_with_memory ( mib_to_bytes ( 128 ) ) ;
932+ enable_irqchip ( & mut vm) ;
933+ let vm = Arc :: new ( vm) ;
934+ let msix_group = create_msix_group ( & vm) ;
935+
936+ msix_group. enable ( ) . unwrap ( ) ;
937+ let state = msix_group. save ( ) ;
938+ let restored_group = MsiVectorGroup :: restore ( vm, & state) . unwrap ( ) ;
939+
940+ assert_eq ! ( msix_group. num_vectors( ) , restored_group. num_vectors( ) ) ;
941+ // Even if an MSI group is enabled, we don't save it as such. During restoration, the PCI
942+ // transport will make sure the correct config is set for the vectors and enable them
943+ // accordingly.
944+ for ( id, vector) in msix_group. irq_routes {
945+ let new_vector = restored_group. irq_routes . get ( & id) . unwrap ( ) ;
946+ assert_eq ! ( vector. gsi, new_vector. gsi) ;
947+ assert ! ( !new_vector. enabled. load( Ordering :: Acquire ) ) ;
948+ }
949+ }
894950}
0 commit comments