Skip to content

hvf: Add API to verify Nested Virt is supported #320

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Apr 29, 2025
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
13 changes: 13 additions & 0 deletions include/libkrun.h
Original file line number Diff line number Diff line change
Expand Up @@ -560,6 +560,19 @@ int32_t krun_setgid(uint32_t ctx_id, gid_t gid);
*/
int32_t krun_set_nested_virt(uint32_t ctx_id, bool enabled);

/**
* Check the system if Nested Virtualization is supported
*
* Notes:
* This feature is only supported on macOS.
*
* Returns:
* - 1 : Success and Nested Virtualization is supported
* - 0 : Success and Nested Virtualization is not supported
* - <0: Failure
*/
int32_t krun_check_nested_virt(void);

/**
* Specify whether to split IRQCHIP responsibilities between the host and the guest.
*
Expand Down
57 changes: 31 additions & 26 deletions src/hvf/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@
#[allow(deref_nullptr)]
pub mod bindings;

#[macro_use]
extern crate log;

use bindings::*;

#[cfg(target_arch = "aarch64")]
Expand Down Expand Up @@ -206,11 +209,27 @@ pub fn vcpu_set_vtimer_mask(vcpuid: u64, masked: bool) -> Result<(), Error> {
}
}

pub struct HvfNestedBindings {
hv_vm_config_get_el2_supported:
libloading::Symbol<'static, unsafe extern "C" fn(*mut bool) -> hv_return_t>,
hv_vm_config_set_el2_enabled:
libloading::Symbol<'static, unsafe extern "C" fn(hv_vm_config_t, bool) -> hv_return_t>,
/// Checks if Nested Virtualization is supported on the current system. Only
/// M3 or newer chips on macOS 15+ will satisfy the requirements.
pub fn check_nested_virt() -> Result<bool, Error> {
type GetEL2Supported =
libloading::Symbol<'static, unsafe extern "C" fn(*mut bool) -> hv_return_t>;

let get_el2_supported: Result<GetEL2Supported, libloading::Error> =
unsafe { HVF.get(b"hv_vm_config_get_el2_supported") };
if get_el2_supported.is_err() {
info!("cannot find hv_vm_config_get_el2_supported symbol");
return Ok(false);
}

let mut el2_supported: bool = false;
let ret = unsafe { (get_el2_supported.unwrap())(&mut el2_supported) };
if ret != HV_SUCCESS {
error!("hv_vm_config_get_el2_supported failed: {:?}", ret);
return Err(Error::NestedCheck);
}

Ok(el2_supported)
}

pub struct HvfVm {}
Expand All @@ -225,30 +244,16 @@ static HVF: LazyLock<libloading::Library> = LazyLock::new(|| unsafe {
impl HvfVm {
pub fn new(nested_enabled: bool) -> Result<Self, Error> {
let config = unsafe { hv_vm_config_create() };

if nested_enabled {
let bindings = unsafe {
HvfNestedBindings {
hv_vm_config_get_el2_supported: HVF
.get(b"hv_vm_config_get_el2_supported")
.map_err(Error::FindSymbol)?,
hv_vm_config_set_el2_enabled: HVF
.get(b"hv_vm_config_set_el2_enabled")
.map_err(Error::FindSymbol)?,
}
let set_el2_enabled: libloading::Symbol<
'static,
unsafe extern "C" fn(hv_vm_config_t, bool) -> hv_return_t,
> = unsafe {
HVF.get(b"hv_vm_config_set_el2_enabled")
.map_err(Error::FindSymbol)?
};

let mut el2_supported: bool = false;
let ret = unsafe { (bindings.hv_vm_config_get_el2_supported)(&mut el2_supported) };
if ret != HV_SUCCESS {
return Err(Error::NestedCheck);
}

if !el2_supported {
return Err(Error::NestedCheck);
}

let ret = unsafe { (bindings.hv_vm_config_set_el2_enabled)(config, true) };
let ret = unsafe { (set_el2_enabled)(config, true) };
if ret != HV_SUCCESS {
return Err(Error::EnableEL2);
}
Expand Down
13 changes: 13 additions & 0 deletions src/libkrun/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1075,6 +1075,19 @@ pub unsafe extern "C" fn krun_set_nested_virt(ctx_id: u32, enabled: bool) -> i32
}
}

#[allow(clippy::missing_safety_doc)]
#[no_mangle]
pub unsafe extern "C" fn krun_check_nested_virt() -> i32 {
#[cfg(target_os = "macos")]
match hvf::check_nested_virt() {
Ok(supp) => supp as i32,
Err(_) => -libc::EINVAL,
}

#[cfg(not(target_os = "macos"))]
-libc::EOPNOTSUPP
}

#[allow(clippy::missing_safety_doc)]
#[no_mangle]
pub extern "C" fn krun_split_irqchip(ctx_id: u32, enable: bool) -> i32 {
Expand Down
Loading