Skip to content

Commit f6f9256

Browse files
committed
vstate: support serializing interrupts to snapshots
Vm object is now maintaining information about the interrupts (both traditional IRQs and MSI-X vectors) that are being used by microVM devices. Derive Serialize/Deserialize add logic for recreating objects for relevant types. Signed-off-by: Babis Chalios <[email protected]>
1 parent b88f536 commit f6f9256

File tree

1 file changed

+57
-1
lines changed

1 file changed

+57
-1
lines changed

src/vmm/src/vstate/vm.rs

Lines changed: 57 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ use kvm_bindings::{
2020
};
2121
use kvm_ioctls::VmFd;
2222
use log::debug;
23+
use serde::{Deserialize, Serialize};
2324
use vm_device::interrupt::{InterruptSourceGroup, MsiIrqSourceConfig};
2425
use vmm_sys_util::errno;
2526
use vmm_sys_util::eventfd::EventFd;
@@ -28,6 +29,7 @@ pub use crate::arch::{ArchVm as Vm, ArchVmError, VmState};
2829
use crate::device_manager::resources::ResourceAllocator;
2930
use crate::logger::info;
3031
use crate::persist::CreateSnapshotError;
32+
use crate::snapshot::Persist;
3133
use crate::utils::u64_to_usize;
3234
use crate::vmm_config::snapshot::SnapshotType;
3335
use 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
5456
pub 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+
117151
impl InterruptSourceGroup for MsiVectorGroup {
118152
fn enable(&self) -> vm_device::interrupt::Result<()> {
119153
for (_, route) in self.irq_routes.iter() {
@@ -899,4 +933,26 @@ pub(crate) mod tests {
899933

900934
msix_group.set_gsi().unwrap();
901935
}
936+
937+
#[test]
938+
fn test_msi_vector_group_persistence() {
939+
let (_, mut vm) = setup_vm_with_memory(mib_to_bytes(128));
940+
enable_irqchip(&mut vm);
941+
let vm = Arc::new(vm);
942+
let msix_group = create_msix_group(&vm);
943+
944+
msix_group.enable().unwrap();
945+
let state = msix_group.save();
946+
let restored_group = MsiVectorGroup::restore(vm, &state).unwrap();
947+
948+
assert_eq!(msix_group.num_vectors(), restored_group.num_vectors());
949+
// Even if an MSI group is enabled, we don't save it as such. During restoration, the PCI
950+
// transport will make sure the correct config is set for the vectors and enable them
951+
// accordingly.
952+
for (id, vector) in msix_group.irq_routes {
953+
let new_vector = restored_group.irq_routes.get(&id).unwrap();
954+
assert_eq!(vector.gsi, new_vector.gsi);
955+
assert!(!new_vector.enabled.load(Ordering::Acquire));
956+
}
957+
}
902958
}

0 commit comments

Comments
 (0)