Skip to content
Closed
Show file tree
Hide file tree
Changes from 3 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
38 changes: 29 additions & 9 deletions src/hyperlight_host/src/hypervisor/hyperv_linux.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ extern crate mshv_bindings3 as mshv_bindings;
extern crate mshv_ioctls3 as mshv_ioctls;

use std::fmt::{Debug, Formatter};
use std::sync::OnceLock;

use log::{error, LevelFilter};
#[cfg(mshv2)]
Expand Down Expand Up @@ -271,23 +272,38 @@ mod debug {
}
}

/// Static global MSHV handle to avoid reopening /dev/mshv for every sandbox
static MSHV_HANDLE: OnceLock<Mshv> = OnceLock::new();

/// Get the global MSHV handle, initializing it if needed
#[instrument(skip_all, parent = Span::current(), level = "Trace")]
pub(crate) fn get_mshv_handle() -> Option<&'static Mshv> {
match MSHV_HANDLE.get() {
Some(mshv) => Some(mshv),
None => match Mshv::new() {
Ok(mshv) => {
let _ = MSHV_HANDLE.set(mshv);
MSHV_HANDLE.get()
}
Err(e) => {
log::info!("MSHV is not available on this system: {}", e);
None
}
},
}
}

/// Determine whether the HyperV for Linux hypervisor API is present
/// and functional.
#[instrument(skip_all, parent = Span::current(), level = "Trace")]
pub(crate) fn is_hypervisor_present() -> bool {
match Mshv::new() {
Ok(_) => true,
Err(_) => {
log::info!("MSHV is not available on this system");
false
}
}
get_mshv_handle().is_some()
}

/// A Hypervisor driver for HyperV-on-Linux. This hypervisor is often
/// called the Microsoft Hypervisor (MSHV)
pub(super) struct HypervLinuxDriver {
_mshv: Mshv,
_mshv: &'static Mshv,
vm_fd: VmFd,
vcpu_fd: VcpuFd,
entrypoint: u64,
Expand Down Expand Up @@ -317,7 +333,11 @@ impl HypervLinuxDriver {
pml4_ptr: GuestPtr,
#[cfg(gdb)] gdb_conn: Option<DebugCommChannel<DebugResponse, DebugMsg>>,
) -> Result<Self> {
let mshv = Mshv::new()?;
let mshv = match get_mshv_handle() {
Some(mshv) => mshv,
None => return Err(new_error!("MSHV is not available on this system")),
};

let pr = Default::default();
#[cfg(mshv2)]
let vm_fd = mshv.create_vm_with_config(&pr)?;
Expand Down
58 changes: 40 additions & 18 deletions src/hyperlight_host/src/hypervisor/kvm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ limitations under the License.

use std::convert::TryFrom;
use std::fmt::Debug;
use std::sync::OnceLock;
#[cfg(gdb)]
use std::sync::{Arc, Mutex};

Expand All @@ -42,28 +43,46 @@ use crate::mem::ptr::{GuestPtr, RawPtr};
use crate::HyperlightError;
use crate::{log_then_return, new_error, Result};

/// Return `true` if the KVM API is available, version 12, and has UserMemory capability, or `false` otherwise
/// Static global KVM handle to avoid reopening /dev/kvm for every sandbox
static KVM_HANDLE: OnceLock<Kvm> = OnceLock::new();

/// Get the global KVM handle, initializing it if needed
#[instrument(skip_all, parent = Span::current(), level = "Trace")]
pub(crate) fn is_hypervisor_present() -> bool {
if let Ok(kvm) = Kvm::new() {
let api_version = kvm.get_api_version();
match api_version {
version if version == 12 && kvm.check_extension(UserMemory) => true,
12 => {
log::info!("KVM does not have KVM_CAP_USER_MEMORY capability");
false
pub(crate) fn get_kvm_handle() -> Option<&'static Kvm> {
match KVM_HANDLE.get() {
Some(kvm) => Some(kvm),
None => match Kvm::new() {
Ok(kvm) => {
let api_version = kvm.get_api_version();
match api_version {
version if version == 12 && kvm.check_extension(UserMemory) => {
let _ = KVM_HANDLE.set(kvm);
KVM_HANDLE.get()
}
12 => {
log::info!("KVM does not have KVM_CAP_USER_MEMORY capability");
None
}
version => {
log::info!("KVM GET_API_VERSION returned {}, expected 12", version);
None
}
}
}
version => {
log::info!("KVM GET_API_VERSION returned {}, expected 12", version);
false
Err(e) => {
log::info!("KVM is not available on this system: {}", e);
None
}
}
} else {
log::info!("KVM is not available on this system");
false
},
}
}

/// Return `true` if the KVM API is available, version 12, and has UserMemory capability, or `false` otherwise
#[instrument(skip_all, parent = Span::current(), level = "Trace")]
pub(crate) fn is_hypervisor_present() -> bool {
get_kvm_handle().is_some()
}

#[cfg(gdb)]
mod debug {
use std::sync::{Arc, Mutex};
Expand Down Expand Up @@ -275,7 +294,7 @@ mod debug {

/// A Hypervisor driver for KVM on Linux
pub(super) struct KVMDriver {
_kvm: Kvm,
_kvm: &'static Kvm,
_vm_fd: VmFd,
vcpu_fd: VcpuFd,
entrypoint: u64,
Expand All @@ -300,7 +319,10 @@ impl KVMDriver {
rsp: u64,
#[cfg(gdb)] gdb_conn: Option<DebugCommChannel<DebugResponse, DebugMsg>>,
) -> Result<Self> {
let kvm = Kvm::new()?;
let kvm = match get_kvm_handle() {
Some(kvm) => kvm,
None => return Err(new_error!("KVM is not available on this system")),
};

let vm_fd = kvm.create_vm_with_type(0)?;

Expand Down