Skip to content

Commit 1498fee

Browse files
committed
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] rust-vmm/kvm#322 [1] rust-vmm/kvm#349 [2] rust-vmm/kvm#350 Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de> On-behalf-of: SAP philipp.schuster@sap.com
1 parent fd140ac commit 1498fee

File tree

6 files changed

+57
-6
lines changed

6 files changed

+57
-6
lines changed

Cargo.lock

Lines changed: 4 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -121,8 +121,8 @@ package.edition = "2024"
121121
[workspace.dependencies]
122122
# rust-vmm crates
123123
acpi_tables = { git = "https://github.com/rust-vmm/acpi_tables", branch = "main" }
124-
kvm-bindings = "0.12.0"
125-
kvm-ioctls = "0.22.0"
124+
kvm-bindings = "0.12.1"
125+
kvm-ioctls = "0.22.1"
126126
# TODO: update to 0.13.1+
127127
linux-loader = { git = "https://github.com/rust-vmm/linux-loader", branch = "main" }
128128
mshv-bindings = "0.6.0"

hypervisor/src/cpu.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -336,6 +336,10 @@ pub enum HypervisorCpuError {
336336
///
337337
#[error("Failed to inject NMI")]
338338
Nmi(#[source] anyhow::Error),
339+
#[error("Failed to get nested guest state")]
340+
GetNestedState(#[source] anyhow::Error),
341+
#[error("Failed to set nested guest state")]
342+
SetNestedState(#[source] anyhow::Error),
339343
}
340344

341345
#[derive(Debug)]

hypervisor/src/kvm/mod.rs

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,8 @@ use std::mem;
8484
///
8585
#[cfg(any(target_arch = "x86_64", target_arch = "aarch64"))]
8686
pub use kvm_bindings::kvm_vcpu_events as VcpuEvents;
87+
#[cfg(target_arch = "x86_64")]
88+
use kvm_bindings::nested::KvmNestedStateBuffer;
8789
pub use kvm_bindings::{
8890
KVM_GUESTDBG_ENABLE, KVM_GUESTDBG_SINGLESTEP, KVM_IRQ_ROUTING_IRQCHIP, KVM_IRQ_ROUTING_MSI,
8991
KVM_MEM_LOG_DIRTY_PAGES, KVM_MEM_READONLY, KVM_MSI_VALID_DEVID, kvm_clock_data,
@@ -2468,6 +2470,7 @@ impl cpu::Vcpu for KvmVcpu {
24682470
let xcrs = self.get_xcrs()?;
24692471
let lapic_state = self.get_lapic()?;
24702472
let fpu = self.get_fpu()?;
2473+
let nested_state = self.nested_state()?;
24712474

24722475
// Try to get all MSRs based on the list previously retrieved from KVM.
24732476
// If the number of MSRs obtained from GET_MSRS is different from the
@@ -2542,6 +2545,7 @@ impl cpu::Vcpu for KvmVcpu {
25422545
xcrs,
25432546
mp_state,
25442547
tsc_khz,
2548+
nested_state,
25452549
}
25462550
.into())
25472551
}
@@ -2708,6 +2712,9 @@ impl cpu::Vcpu for KvmVcpu {
27082712
self.set_xcrs(&state.xcrs)?;
27092713
self.set_lapic(&state.lapic_state)?;
27102714
self.set_fpu(&state.fpu)?;
2715+
if let Some(nested_state) = state.nested_state {
2716+
self.set_nested_state(&nested_state)?;
2717+
}
27112718

27122719
if let Some(freq) = state.tsc_khz {
27132720
self.set_tsc_khz(freq)?;
@@ -3068,6 +3075,36 @@ impl KvmVcpu {
30683075
.set_vcpu_events(events)
30693076
.map_err(|e| cpu::HypervisorCpuError::SetVcpuEvents(e.into()))
30703077
}
3078+
3079+
/// Get the state of the nested guest from the current vCPU,
3080+
/// if there is any.
3081+
#[cfg(target_arch = "x86_64")]
3082+
fn nested_state(&self) -> cpu::Result<Option<KvmNestedStateBuffer>> {
3083+
let mut buffer = KvmNestedStateBuffer::empty();
3084+
3085+
let maybe_size = self
3086+
.fd
3087+
.lock()
3088+
.unwrap()
3089+
.get_nested_state(&mut buffer)
3090+
.map_err(|e| cpu::HypervisorCpuError::GetNestedState(e.into()))?;
3091+
3092+
if let Some(_size) = maybe_size {
3093+
Ok(Some(buffer))
3094+
} else {
3095+
Ok(None)
3096+
}
3097+
}
3098+
3099+
/// Sets the state of the nested guest for the current vCPU.
3100+
#[cfg(target_arch = "x86_64")]
3101+
fn set_nested_state(&self, state: &KvmNestedStateBuffer) -> cpu::Result<()> {
3102+
self.fd
3103+
.lock()
3104+
.unwrap()
3105+
.set_nested_state(state)
3106+
.map_err(|e| cpu::HypervisorCpuError::GetNestedState(e.into()))
3107+
}
30713108
}
30723109

30733110
#[cfg(test)]

hypervisor/src/kvm/x86_64/mod.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ pub use {
1919
kvm_bindings::kvm_msr_entry, kvm_bindings::kvm_regs, kvm_bindings::kvm_segment,
2020
kvm_bindings::kvm_sregs, kvm_bindings::kvm_vcpu_events as VcpuEvents,
2121
kvm_bindings::kvm_xcrs as ExtendedControlRegisters, kvm_bindings::kvm_xsave,
22+
kvm_bindings::nested::KvmNestedStateBuffer,
2223
};
2324

2425
use crate::arch::x86::{
@@ -75,6 +76,9 @@ pub struct VcpuKvmState {
7576
pub xcrs: ExtendedControlRegisters,
7677
pub mp_state: MpState,
7778
pub tsc_khz: Option<u32>,
79+
// Option to prevent useless 8K (de)serialization when no nested
80+
// state exists.
81+
pub nested_state: Option<KvmNestedStateBuffer>,
7882
}
7983

8084
impl From<SegmentRegister> for kvm_segment {

vmm/src/seccomp_filters.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,8 @@ mod kvm {
103103
pub const KVM_GET_REG_LIST: u64 = 0xc008_aeb0;
104104
pub const KVM_MEMORY_ENCRYPT_OP: u64 = 0xc008_aeba;
105105
pub const KVM_NMI: u64 = 0xae9a;
106+
pub const KVM_GET_NESTED_STATE: u64 = 3229658814;
107+
pub const KVM_SET_NESTED_STATE: u64 = 1082175167;
106108
}
107109

108110
// 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
232234
and![Cond::new(1, ArgLen::Dword, Eq, KVM_SET_USER_MEMORY_REGION,)?],
233235
and![Cond::new(1, ArgLen::Dword, Eq, KVM_SET_VCPU_EVENTS,)?],
234236
and![Cond::new(1, ArgLen::Dword, Eq, KVM_NMI)?],
237+
and![Cond::new(1, ArgLen::Dword, Eq, KVM_GET_NESTED_STATE)?],
238+
and![Cond::new(1, ArgLen::Dword, Eq, KVM_SET_NESTED_STATE)?],
235239
])
236240
}
237241

@@ -697,6 +701,8 @@ fn create_vcpu_ioctl_seccomp_rule_kvm() -> Result<Vec<SeccompRule>, BackendError
697701
and![Cond::new(1, ArgLen::Dword, Eq, KVM_SET_USER_MEMORY_REGION,)?],
698702
and![Cond::new(1, ArgLen::Dword, Eq, KVM_RUN,)?],
699703
and![Cond::new(1, ArgLen::Dword, Eq, KVM_NMI)?],
704+
and![Cond::new(1, ArgLen::Dword, Eq, KVM_GET_NESTED_STATE)?],
705+
and![Cond::new(1, ArgLen::Dword, Eq, KVM_SET_NESTED_STATE)?],
700706
])
701707
}
702708

0 commit comments

Comments
 (0)