hypervisor: kvm/x86_64: get and set nested guest state
Since the functionality of [0] was backported to kvm-bindings@v0.12.1 and kvm-ioctls@v0.22.1 [1, 2], we can now save nested KVM state. This way, nesting works across state save/resume and live-migration. [0] https://github.com/rust-vmm/kvm/pull/322 [1] https://github.com/rust-vmm/kvm/pull/349 [2] https://github.com/rust-vmm/kvm/pull/350 Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de> On-behalf-of: SAP philipp.schuster@sap.com
This commit is contained in:
parent
4c16285dde
commit
690741de13
6 changed files with 57 additions and 6 deletions
8
Cargo.lock
generated
8
Cargo.lock
generated
|
|
@ -1073,9 +1073,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "kvm-bindings"
|
||||
version = "0.12.0"
|
||||
version = "0.12.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d4b153a59bb3ca930ff8148655b2ef68c34259a623ae08cf2fb9b570b2e45363"
|
||||
checksum = "9a537873e15e8daabb416667e606d9b0abc2a8fb9a45bd5853b888ae0ead82f9"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"vmm-sys-util",
|
||||
|
|
@ -1084,9 +1084,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "kvm-ioctls"
|
||||
version = "0.22.0"
|
||||
version = "0.22.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b702df98508cb63ad89dd9beb9f6409761b30edca10d48e57941d3f11513a006"
|
||||
checksum = "0c8f7370330b4f57981e300fa39b02088f2f2a5c2d0f1f994e8090589619c56d"
|
||||
dependencies = [
|
||||
"bitflags 2.9.4",
|
||||
"kvm-bindings",
|
||||
|
|
|
|||
|
|
@ -107,8 +107,8 @@ package.edition = "2024"
|
|||
[workspace.dependencies]
|
||||
# rust-vmm crates
|
||||
acpi_tables = { git = "https://github.com/rust-vmm/acpi_tables", branch = "main" }
|
||||
kvm-bindings = "0.12.0"
|
||||
kvm-ioctls = "0.22.0"
|
||||
kvm-bindings = "0.12.1"
|
||||
kvm-ioctls = "0.22.1"
|
||||
# TODO: update to 0.13.1+
|
||||
linux-loader = { git = "https://github.com/rust-vmm/linux-loader", branch = "main" }
|
||||
mshv-bindings = "0.6.0"
|
||||
|
|
|
|||
|
|
@ -334,6 +334,10 @@ pub enum HypervisorCpuError {
|
|||
///
|
||||
#[error("Failed to inject NMI")]
|
||||
Nmi(#[source] anyhow::Error),
|
||||
#[error("Failed to get nested guest state")]
|
||||
GetNestedState(#[source] anyhow::Error),
|
||||
#[error("Failed to set nested guest state")]
|
||||
SetNestedState(#[source] anyhow::Error),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
|
|
|||
|
|
@ -86,6 +86,8 @@ use std::mem;
|
|||
///
|
||||
#[cfg(any(target_arch = "x86_64", target_arch = "aarch64"))]
|
||||
pub use kvm_bindings::kvm_vcpu_events as VcpuEvents;
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
use kvm_bindings::nested::KvmNestedStateBuffer;
|
||||
pub use kvm_bindings::{
|
||||
KVM_GUESTDBG_ENABLE, KVM_GUESTDBG_SINGLESTEP, KVM_IRQ_ROUTING_IRQCHIP, KVM_IRQ_ROUTING_MSI,
|
||||
KVM_MEM_LOG_DIRTY_PAGES, KVM_MEM_READONLY, KVM_MSI_VALID_DEVID, kvm_clock_data,
|
||||
|
|
@ -2442,6 +2444,7 @@ impl cpu::Vcpu for KvmVcpu {
|
|||
let xcrs = self.get_xcrs()?;
|
||||
let lapic_state = self.get_lapic()?;
|
||||
let fpu = self.get_fpu()?;
|
||||
let nested_state = self.nested_state()?;
|
||||
|
||||
// Try to get all MSRs based on the list previously retrieved from KVM.
|
||||
// If the number of MSRs obtained from GET_MSRS is different from the
|
||||
|
|
@ -2516,6 +2519,7 @@ impl cpu::Vcpu for KvmVcpu {
|
|||
xcrs,
|
||||
mp_state,
|
||||
tsc_khz,
|
||||
nested_state,
|
||||
}
|
||||
.into())
|
||||
}
|
||||
|
|
@ -2683,6 +2687,9 @@ impl cpu::Vcpu for KvmVcpu {
|
|||
self.set_xcrs(&state.xcrs)?;
|
||||
self.set_lapic(&state.lapic_state)?;
|
||||
self.set_fpu(&state.fpu)?;
|
||||
if let Some(nested_state) = state.nested_state {
|
||||
self.set_nested_state(&nested_state)?;
|
||||
}
|
||||
|
||||
if let Some(freq) = state.tsc_khz {
|
||||
self.set_tsc_khz(freq)?;
|
||||
|
|
@ -3036,6 +3043,36 @@ impl KvmVcpu {
|
|||
.set_vcpu_events(events)
|
||||
.map_err(|e| cpu::HypervisorCpuError::SetVcpuEvents(e.into()))
|
||||
}
|
||||
|
||||
/// Get the state of the nested guest from the current vCPU,
|
||||
/// if there is any.
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
fn nested_state(&self) -> cpu::Result<Option<KvmNestedStateBuffer>> {
|
||||
let mut buffer = KvmNestedStateBuffer::empty();
|
||||
|
||||
let maybe_size = self
|
||||
.fd
|
||||
.lock()
|
||||
.unwrap()
|
||||
.get_nested_state(&mut buffer)
|
||||
.map_err(|e| cpu::HypervisorCpuError::GetNestedState(e.into()))?;
|
||||
|
||||
if let Some(_size) = maybe_size {
|
||||
Ok(Some(buffer))
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
||||
/// Sets the state of the nested guest for the current vCPU.
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
fn set_nested_state(&self, state: &KvmNestedStateBuffer) -> cpu::Result<()> {
|
||||
self.fd
|
||||
.lock()
|
||||
.unwrap()
|
||||
.set_nested_state(state)
|
||||
.map_err(|e| cpu::HypervisorCpuError::GetNestedState(e.into()))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ pub use {
|
|||
kvm_bindings::kvm_msr_entry, kvm_bindings::kvm_regs, kvm_bindings::kvm_segment,
|
||||
kvm_bindings::kvm_sregs, kvm_bindings::kvm_vcpu_events as VcpuEvents,
|
||||
kvm_bindings::kvm_xcrs as ExtendedControlRegisters, kvm_bindings::kvm_xsave,
|
||||
kvm_bindings::nested::KvmNestedStateBuffer,
|
||||
};
|
||||
|
||||
use crate::arch::x86::{
|
||||
|
|
@ -75,6 +76,9 @@ pub struct VcpuKvmState {
|
|||
pub xcrs: ExtendedControlRegisters,
|
||||
pub mp_state: MpState,
|
||||
pub tsc_khz: Option<u32>,
|
||||
// Option to prevent useless 8K (de)serialization when no nested
|
||||
// state exists.
|
||||
pub nested_state: Option<KvmNestedStateBuffer>,
|
||||
}
|
||||
|
||||
impl From<SegmentRegister> for kvm_segment {
|
||||
|
|
|
|||
|
|
@ -103,6 +103,8 @@ mod kvm {
|
|||
pub const KVM_GET_REG_LIST: u64 = 0xc008_aeb0;
|
||||
pub const KVM_MEMORY_ENCRYPT_OP: u64 = 0xc008_aeba;
|
||||
pub const KVM_NMI: u64 = 0xae9a;
|
||||
pub const KVM_GET_NESTED_STATE: u64 = 3229658814;
|
||||
pub const KVM_SET_NESTED_STATE: u64 = 1082175167;
|
||||
}
|
||||
|
||||
// MSHV IOCTL code. This is unstable until the kernel code has been declared stable.
|
||||
|
|
@ -232,6 +234,8 @@ fn create_vmm_ioctl_seccomp_rule_common_kvm() -> Result<Vec<SeccompRule>, Backen
|
|||
and![Cond::new(1, ArgLen::Dword, Eq, KVM_SET_USER_MEMORY_REGION,)?],
|
||||
and![Cond::new(1, ArgLen::Dword, Eq, KVM_SET_VCPU_EVENTS,)?],
|
||||
and![Cond::new(1, ArgLen::Dword, Eq, KVM_NMI)?],
|
||||
and![Cond::new(1, ArgLen::Dword, Eq, KVM_GET_NESTED_STATE)?],
|
||||
and![Cond::new(1, ArgLen::Dword, Eq, KVM_SET_NESTED_STATE)?],
|
||||
])
|
||||
}
|
||||
|
||||
|
|
@ -697,6 +701,8 @@ fn create_vcpu_ioctl_seccomp_rule_kvm() -> Result<Vec<SeccompRule>, BackendError
|
|||
and![Cond::new(1, ArgLen::Dword, Eq, KVM_SET_USER_MEMORY_REGION,)?],
|
||||
and![Cond::new(1, ArgLen::Dword, Eq, KVM_RUN,)?],
|
||||
and![Cond::new(1, ArgLen::Dword, Eq, KVM_NMI)?],
|
||||
and![Cond::new(1, ArgLen::Dword, Eq, KVM_GET_NESTED_STATE)?],
|
||||
and![Cond::new(1, ArgLen::Dword, Eq, KVM_SET_NESTED_STATE)?],
|
||||
])
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue