Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
4 changes: 4 additions & 0 deletions hypervisor/src/cpu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)]
Expand Down
37 changes: 37 additions & 0 deletions hypervisor/src/kvm/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -2542,6 +2545,7 @@ impl cpu::Vcpu for KvmVcpu {
xcrs,
mp_state,
tsc_khz,
nested_state,
}
.into())
}
Expand Down Expand Up @@ -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)?;
Expand Down Expand Up @@ -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<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)]
Expand Down
4 changes: 4 additions & 0 deletions hypervisor/src/kvm/x86_64/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::{
Expand Down Expand Up @@ -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 {
Expand Down
6 changes: 6 additions & 0 deletions vmm/src/seccomp_filters.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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)?],
])
}

Expand Down Expand Up @@ -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)?],
])
}

Expand Down
Loading