diff --git a/Cargo.lock b/Cargo.lock index ed015d1ce7..a56f90cad2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1053,9 +1053,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", @@ -1064,9 +1064,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", diff --git a/Cargo.toml b/Cargo.toml index ed4c5225f8..1ce6d53ba3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -121,8 +121,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" diff --git a/hypervisor/src/cpu.rs b/hypervisor/src/cpu.rs index e138cb745b..519b99f567 100644 --- a/hypervisor/src/cpu.rs +++ b/hypervisor/src/cpu.rs @@ -336,6 +336,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)] diff --git a/hypervisor/src/kvm/mod.rs b/hypervisor/src/kvm/mod.rs index 961b62810a..8d1bc228f1 100644 --- a/hypervisor/src/kvm/mod.rs +++ b/hypervisor/src/kvm/mod.rs @@ -84,6 +84,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, @@ -2468,6 +2470,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 @@ -2542,6 +2545,7 @@ impl cpu::Vcpu for KvmVcpu { xcrs, mp_state, tsc_khz, + nested_state, } .into()) } @@ -2708,6 +2712,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)?; @@ -3068,6 +3075,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> { + 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)] diff --git a/hypervisor/src/kvm/x86_64/mod.rs b/hypervisor/src/kvm/x86_64/mod.rs index a01fb9d727..c1bda9d9be 100644 --- a/hypervisor/src/kvm/x86_64/mod.rs +++ b/hypervisor/src/kvm/x86_64/mod.rs @@ -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, + // Option to prevent useless 8K (de)serialization when no nested + // state exists. + pub nested_state: Option, } impl From for kvm_segment { diff --git a/vmm/src/seccomp_filters.rs b/vmm/src/seccomp_filters.rs index b3175ffe15..2d7d3ca11e 100644 --- a/vmm/src/seccomp_filters.rs +++ b/vmm/src/seccomp_filters.rs @@ -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, 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, 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)?], ]) }