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 <cathy.zhang@intel.com>
Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
This commit is contained in:
Cathy Zhang 2020-02-16 21:42:42 +01:00 committed by Sebastien Boeuf
parent 13756490b5
commit 722f9b6628
3 changed files with 134 additions and 2 deletions

2
Cargo.lock generated
View File

@ -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",
]

View File

@ -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"

View File

@ -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<T> = result::Result<T, Error>;
@ -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<VcpuKvmState> {
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 {