From 722f9b6628015bbbb91f23816f37babe7d54c4a5 Mon Sep 17 00:00:00 2001 From: Cathy Zhang Date: Sun, 16 Feb 2020 21:42:42 +0100 Subject: [PATCH] vmm: cpu: Get and set KVM vCPU state These two new helpers will be useful to capture a vCPU state and being able to restore it at a later time. Signed-off-by: Cathy Zhang Signed-off-by: Samuel Ortiz --- Cargo.lock | 2 + vmm/Cargo.toml | 2 +- vmm/src/cpu.rs | 132 ++++++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 134 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 555cef41b..abdce585b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -466,6 +466,8 @@ name = "kvm-bindings" version = "0.2.0" source = "git+https://github.com/cloud-hypervisor/kvm-bindings?branch=ch#3a6780089e0e2d69aaf77666524e81801c814bdd" dependencies = [ + "serde", + "serde_derive", "vmm-sys-util", ] diff --git a/vmm/Cargo.toml b/vmm/Cargo.toml index 3fd5ede2f..b77d3e610 100644 --- a/vmm/Cargo.toml +++ b/vmm/Cargo.toml @@ -19,7 +19,7 @@ anyhow = "1.0" arch = { path = "../arch" } devices = { path = "../devices" } epoll = ">=4.0.1" -kvm-bindings = { git = "https://github.com/cloud-hypervisor/kvm-bindings", branch = "ch" } +kvm-bindings = { git = "https://github.com/cloud-hypervisor/kvm-bindings", branch = "ch", features = ["with-serde", "fam-wrappers"] } kvm-ioctls = { git = "https://github.com/cloud-hypervisor/kvm-ioctls", branch = "ch" } lazy_static = "1.4.0" libc = "0.2.68" diff --git a/vmm/src/cpu.rs b/vmm/src/cpu.rs index 0ca996bae..fd9baf033 100644 --- a/vmm/src/cpu.rs +++ b/vmm/src/cpu.rs @@ -19,9 +19,13 @@ use acpi_tables::{aml, aml::Aml, sdt::SDT}; use arch::layout; use arch::EntryPoint; use devices::{ioapic, BusDevice}; -use kvm_bindings::CpuId; +use kvm_bindings::{ + kvm_fpu, kvm_lapic_state, kvm_mp_state, kvm_regs, kvm_sregs, kvm_vcpu_events, kvm_xcrs, + kvm_xsave, CpuId, Msrs, +}; use kvm_ioctls::*; use libc::{c_void, siginfo_t}; +use serde_derive::{Deserialize, Serialize}; use std::cmp; use std::os::unix::thread::JoinHandleExt; use std::sync::atomic::{AtomicBool, Ordering}; @@ -130,6 +134,60 @@ pub enum Error { /// Asking for more vCPUs that we can have DesiredVCPUCountExceedsMax, + + /// Failed to get KVM vcpu lapic. + VcpuGetLapic(kvm_ioctls::Error), + + /// Failed to set KVM vcpu lapic. + VcpuSetLapic(kvm_ioctls::Error), + + /// Failed to get KVM vcpu MP state. + VcpuGetMpState(kvm_ioctls::Error), + + /// Failed to set KVM vcpu MP state. + VcpuSetMpState(kvm_ioctls::Error), + + /// Failed to get KVM vcpu msrs. + VcpuGetMsrs(kvm_ioctls::Error), + + /// Failed to set KVM vcpu msrs. + VcpuSetMsrs(kvm_ioctls::Error), + + /// Failed to get KVM vcpu regs. + VcpuGetRegs(kvm_ioctls::Error), + + /// Failed to set KVM vcpu regs. + VcpuSetRegs(kvm_ioctls::Error), + + /// Failed to get KVM vcpu sregs. + VcpuGetSregs(kvm_ioctls::Error), + + /// Failed to set KVM vcpu sregs. + VcpuSetSregs(kvm_ioctls::Error), + + /// Failed to get KVM vcpu events. + VcpuGetVcpuEvents(kvm_ioctls::Error), + + /// Failed to set KVM vcpu events. + VcpuSetVcpuEvents(kvm_ioctls::Error), + + /// Failed to get KVM vcpu FPU. + VcpuGetFpu(kvm_ioctls::Error), + + /// Failed to set KVM vcpu FPU. + VcpuSetFpu(kvm_ioctls::Error), + + /// Failed to get KVM vcpu XSAVE. + VcpuGetXsave(kvm_ioctls::Error), + + /// Failed to set KVM vcpu XSAVE. + VcpuSetXsave(kvm_ioctls::Error), + + /// Failed to get KVM vcpu XCRS. + VcpuGetXcrs(kvm_ioctls::Error), + + /// Failed to set KVM vcpu XCRS. + VcpuSetXcrs(kvm_ioctls::Error), } pub type Result = result::Result; @@ -251,6 +309,19 @@ pub struct Vcpu { vm_ts: std::time::Instant, } +#[derive(Clone, Serialize, Deserialize)] +pub struct VcpuKvmState { + msrs: Msrs, + vcpu_events: kvm_vcpu_events, + regs: kvm_regs, + sregs: kvm_sregs, + fpu: kvm_fpu, + lapic_state: kvm_lapic_state, + xsave: kvm_xsave, + xcrs: kvm_xcrs, + mp_state: kvm_mp_state, +} + impl Vcpu { /// Constructs a new VCPU for `vm`. /// @@ -384,6 +455,65 @@ impl Vcpu { ts.as_micros() ); } + + #[allow(unused)] + fn kvm_state(&self) -> Result { + let mut msrs = arch::x86_64::regs::boot_msr_entries(); + self.fd.get_msrs(&mut msrs).map_err(Error::VcpuGetMsrs)?; + + let vcpu_events = self + .fd + .get_vcpu_events() + .map_err(Error::VcpuGetVcpuEvents)?; + let regs = self.fd.get_regs().map_err(Error::VcpuGetRegs)?; + let sregs = self.fd.get_sregs().map_err(Error::VcpuGetSregs)?; + let lapic_state = self.fd.get_lapic().map_err(Error::VcpuGetLapic)?; + let fpu = self.fd.get_fpu().map_err(Error::VcpuGetFpu)?; + let xsave = self.fd.get_xsave().map_err(Error::VcpuGetXsave)?; + let xcrs = self.fd.get_xcrs().map_err(Error::VcpuGetXsave)?; + let mp_state = self.fd.get_mp_state().map_err(Error::VcpuGetMpState)?; + + Ok(VcpuKvmState { + msrs, + vcpu_events, + regs, + sregs, + fpu, + lapic_state, + xsave, + xcrs, + mp_state, + }) + } + + #[allow(unused)] + fn set_kvm_state(&mut self, state: &VcpuKvmState) -> Result<()> { + self.fd.set_regs(&state.regs).map_err(Error::VcpuSetRegs)?; + + self.fd.set_fpu(&state.fpu).map_err(Error::VcpuSetFpu)?; + + self.fd + .set_xsave(&state.xsave) + .map_err(Error::VcpuSetXsave)?; + + self.fd + .set_sregs(&state.sregs) + .map_err(Error::VcpuSetSregs)?; + + self.fd.set_xcrs(&state.xcrs).map_err(Error::VcpuSetXcrs)?; + + self.fd.set_msrs(&state.msrs).map_err(Error::VcpuSetMsrs)?; + + self.fd + .set_lapic(&state.lapic_state) + .map_err(Error::VcpuSetLapic)?; + + self.fd + .set_mp_state(state.mp_state) + .map_err(Error::VcpuSetMpState)?; + + Ok(()) + } } pub struct CpuManager {