Skip to content

Commit b7c3e83

Browse files
committed
x86_64 support for saving and restoring kvm vm state
Signed-off-by: Adrian Catangiu <[email protected]>
1 parent c465243 commit b7c3e83

File tree

1 file changed

+114
-1
lines changed

1 file changed

+114
-1
lines changed

src/vmm/src/vstate.rs

Lines changed: 114 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,11 @@ use arch::aarch64::gic::GICDevice;
2020
#[cfg(target_arch = "x86_64")]
2121
use cpuid::{c3, filter_cpuid, t2, VmSpec};
2222
#[cfg(target_arch = "x86_64")]
23-
use kvm_bindings::{kvm_pit_config, CpuId, KVM_MAX_CPUID_ENTRIES, KVM_PIT_SPEAKER_DUMMY};
23+
use kvm_bindings::{
24+
kvm_clock_data, kvm_irqchip, kvm_pit_config, kvm_pit_state2, CpuId, MsrList,
25+
KVM_CLOCK_TSC_STABLE, KVM_IRQCHIP_IOAPIC, KVM_IRQCHIP_PIC_MASTER, KVM_IRQCHIP_PIC_SLAVE,
26+
KVM_MAX_CPUID_ENTRIES, KVM_PIT_SPEAKER_DUMMY,
27+
};
2428
use kvm_bindings::{kvm_userspace_memory_region, KVM_API_VERSION};
2529
use kvm_ioctls::*;
2630
use logger::{Metric, METRICS};
@@ -110,6 +114,24 @@ pub enum Error {
110114
VcpuUnhandledKvmExit,
111115
/// Cannot open the VM file descriptor.
112116
VmFd(kvm_ioctls::Error),
117+
#[cfg(target_arch = "x86_64")]
118+
/// Failed to get KVM vm pit state.
119+
VmGetPit2(kvm_ioctls::Error),
120+
#[cfg(target_arch = "x86_64")]
121+
/// Failed to get KVM vm clock.
122+
VmGetClock(kvm_ioctls::Error),
123+
#[cfg(target_arch = "x86_64")]
124+
/// Failed to get KVM vm irqchip.
125+
VmGetIrqChip(kvm_ioctls::Error),
126+
#[cfg(target_arch = "x86_64")]
127+
/// Failed to set KVM vm pit state.
128+
VmSetPit2(kvm_ioctls::Error),
129+
#[cfg(target_arch = "x86_64")]
130+
/// Failed to set KVM vm clock.
131+
VmSetClock(kvm_ioctls::Error),
132+
#[cfg(target_arch = "x86_64")]
133+
/// Failed to set KVM vm irqchip.
134+
VmSetIrqChip(kvm_ioctls::Error),
113135
/// Cannot configure the microvm.
114136
VmSetup(kvm_ioctls::Error),
115137
}
@@ -280,6 +302,74 @@ impl Vm {
280302
pub fn fd(&self) -> &VmFd {
281303
&self.fd
282304
}
305+
306+
#[allow(unused)]
307+
#[cfg(target_arch = "x86_64")]
308+
/// Saves and returns the Kvm Vm state.
309+
pub fn save_state(&self) -> Result<VmState> {
310+
let pitstate = self.fd.get_pit2().map_err(Error::VmGetPit2)?;
311+
312+
let mut clock = self.fd.get_clock().map_err(Error::VmGetClock)?;
313+
// This bit is not accepted in SET_CLOCK, clear it.
314+
clock.flags &= !KVM_CLOCK_TSC_STABLE;
315+
316+
let mut pic_master = kvm_irqchip::default();
317+
pic_master.chip_id = KVM_IRQCHIP_PIC_MASTER;
318+
self.fd
319+
.get_irqchip(&mut pic_master)
320+
.map_err(Error::VmGetIrqChip)?;
321+
322+
let mut pic_slave = kvm_irqchip::default();
323+
pic_slave.chip_id = KVM_IRQCHIP_PIC_SLAVE;
324+
self.fd
325+
.get_irqchip(&mut pic_slave)
326+
.map_err(Error::VmGetIrqChip)?;
327+
328+
let mut ioapic = kvm_irqchip::default();
329+
ioapic.chip_id = KVM_IRQCHIP_IOAPIC;
330+
self.fd
331+
.get_irqchip(&mut ioapic)
332+
.map_err(Error::VmGetIrqChip)?;
333+
334+
Ok(VmState {
335+
pitstate,
336+
clock,
337+
pic_master,
338+
pic_slave,
339+
ioapic,
340+
})
341+
}
342+
343+
#[allow(unused)]
344+
#[cfg(target_arch = "x86_64")]
345+
/// Restores the Kvm Vm state.
346+
pub fn restore_state(&self, state: &VmState) -> Result<()> {
347+
self.fd
348+
.set_pit2(&state.pitstate)
349+
.map_err(Error::VmSetPit2)?;
350+
self.fd.set_clock(&state.clock).map_err(Error::VmSetClock)?;
351+
self.fd
352+
.set_irqchip(&state.pic_master)
353+
.map_err(Error::VmSetIrqChip)?;
354+
self.fd
355+
.set_irqchip(&state.pic_slave)
356+
.map_err(Error::VmSetIrqChip)?;
357+
self.fd
358+
.set_irqchip(&state.ioapic)
359+
.map_err(Error::VmSetIrqChip)?;
360+
Ok(())
361+
}
362+
}
363+
364+
#[allow(unused)]
365+
#[cfg(target_arch = "x86_64")]
366+
/// Structure holding VM kvm state.
367+
pub struct VmState {
368+
pitstate: kvm_pit_state2,
369+
clock: kvm_clock_data,
370+
pic_master: kvm_irqchip,
371+
pic_slave: kvm_irqchip,
372+
ioapic: kvm_irqchip,
283373
}
284374

285375
// Using this for easier explicit type-casting to help IDEs interpret the code.
@@ -1285,4 +1375,27 @@ mod tests {
12851375
fn test_vcpu_rtsig_offset() {
12861376
assert!(validate_signal_num(sigrtmin() + VCPU_RTSIG_OFFSET).is_ok());
12871377
}
1378+
1379+
#[cfg(target_arch = "x86_64")]
1380+
#[test]
1381+
fn test_vm_save_restore_state() {
1382+
let kvm_fd = Kvm::new().unwrap();
1383+
let vm = Vm::new(&kvm_fd).expect("new vm failed");
1384+
// Irqchips, clock and pitstate are not configured so trying to save state should fail.
1385+
assert!(vm.save_state().is_err());
1386+
1387+
let (vm, _) = setup_vcpu(0x1000);
1388+
let vm_state = vm.save_state().unwrap();
1389+
assert_eq!(
1390+
vm_state.pitstate.flags | KVM_PIT_SPEAKER_DUMMY,
1391+
KVM_PIT_SPEAKER_DUMMY
1392+
);
1393+
assert_eq!(vm_state.clock.flags & KVM_CLOCK_TSC_STABLE, 0);
1394+
assert_eq!(vm_state.pic_master.chip_id, KVM_IRQCHIP_PIC_MASTER);
1395+
assert_eq!(vm_state.pic_slave.chip_id, KVM_IRQCHIP_PIC_SLAVE);
1396+
assert_eq!(vm_state.ioapic.chip_id, KVM_IRQCHIP_IOAPIC);
1397+
1398+
let (vm, _) = setup_vcpu(0x1000);
1399+
assert!(vm.restore_state(&vm_state).is_ok());
1400+
}
12881401
}

0 commit comments

Comments
 (0)