Skip to content

Commit aa00caf

Browse files
committed
hvf: Add API to verify Nested Virt is supported
Add an API to check if the current system supports Nested Virt on macOS. Signed-off-by: Jake Correnti <[email protected]>
1 parent 291a4e9 commit aa00caf

File tree

3 files changed

+57
-26
lines changed

3 files changed

+57
-26
lines changed

include/libkrun.h

+13
Original file line numberDiff line numberDiff line change
@@ -560,6 +560,19 @@ int32_t krun_setgid(uint32_t ctx_id, gid_t gid);
560560
*/
561561
int32_t krun_set_nested_virt(uint32_t ctx_id, bool enabled);
562562

563+
/**
564+
* Check the system if Nested Virtualization is supported
565+
*
566+
* Notes:
567+
* This feature is only supported on macOS.
568+
*
569+
* Returns:
570+
* - 1 : Success and Nested Virtualization is supported
571+
* - 0 : Success and Nested Virtualization is not supported
572+
* - <0: Failure
573+
*/
574+
int32_t krun_check_nested_virt(void);
575+
563576
/**
564577
* Specify whether to split IRQCHIP responsibilities between the host and the guest.
565578
*

src/hvf/src/lib.rs

+31-26
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@
99
#[allow(deref_nullptr)]
1010
pub mod bindings;
1111

12+
#[macro_use]
13+
extern crate log;
14+
1215
use bindings::*;
1316

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

209-
pub struct HvfNestedBindings {
210-
hv_vm_config_get_el2_supported:
211-
libloading::Symbol<'static, unsafe extern "C" fn(*mut bool) -> hv_return_t>,
212-
hv_vm_config_set_el2_enabled:
213-
libloading::Symbol<'static, unsafe extern "C" fn(hv_vm_config_t, bool) -> hv_return_t>,
212+
/// Checks if Nested Virtualization is supported on the current system. Only
213+
/// M3 or newer chips on macOS 15+ will satisfy the requirements.
214+
pub fn check_nested_virt() -> Result<bool, Error> {
215+
type GetEL2Supported =
216+
libloading::Symbol<'static, unsafe extern "C" fn(*mut bool) -> hv_return_t>;
217+
218+
let get_el2_supported: Result<GetEL2Supported, libloading::Error> =
219+
unsafe { HVF.get(b"hv_vm_config_get_el2_supported") };
220+
if get_el2_supported.is_err() {
221+
info!("cannot find hv_vm_config_get_el2_supported symbol");
222+
return Ok(false);
223+
}
224+
225+
let mut el2_supported: bool = false;
226+
let ret = unsafe { (get_el2_supported.unwrap())(&mut el2_supported) };
227+
if ret != HV_SUCCESS {
228+
error!("processor does not support the nested virtualization functionality");
229+
return Err(Error::NestedCheck);
230+
}
231+
232+
Ok(el2_supported)
214233
}
215234

216235
pub struct HvfVm {}
@@ -225,30 +244,16 @@ static HVF: LazyLock<libloading::Library> = LazyLock::new(|| unsafe {
225244
impl HvfVm {
226245
pub fn new(nested_enabled: bool) -> Result<Self, Error> {
227246
let config = unsafe { hv_vm_config_create() };
228-
229247
if nested_enabled {
230-
let bindings = unsafe {
231-
HvfNestedBindings {
232-
hv_vm_config_get_el2_supported: HVF
233-
.get(b"hv_vm_config_get_el2_supported")
234-
.map_err(Error::FindSymbol)?,
235-
hv_vm_config_set_el2_enabled: HVF
236-
.get(b"hv_vm_config_set_el2_enabled")
237-
.map_err(Error::FindSymbol)?,
238-
}
248+
let set_el2_enabled: libloading::Symbol<
249+
'static,
250+
unsafe extern "C" fn(hv_vm_config_t, bool) -> hv_return_t,
251+
> = unsafe {
252+
HVF.get(b"hv_vm_config_set_el2_enabled")
253+
.map_err(Error::FindSymbol)?
239254
};
240255

241-
let mut el2_supported: bool = false;
242-
let ret = unsafe { (bindings.hv_vm_config_get_el2_supported)(&mut el2_supported) };
243-
if ret != HV_SUCCESS {
244-
return Err(Error::NestedCheck);
245-
}
246-
247-
if !el2_supported {
248-
return Err(Error::NestedCheck);
249-
}
250-
251-
let ret = unsafe { (bindings.hv_vm_config_set_el2_enabled)(config, true) };
256+
let ret = unsafe { (set_el2_enabled)(config, true) };
252257
if ret != HV_SUCCESS {
253258
return Err(Error::EnableEL2);
254259
}

src/libkrun/src/lib.rs

+13
Original file line numberDiff line numberDiff line change
@@ -1062,6 +1062,19 @@ pub unsafe extern "C" fn krun_set_nested_virt(ctx_id: u32, enabled: bool) -> i32
10621062
}
10631063
}
10641064

1065+
#[allow(clippy::missing_safety_doc)]
1066+
#[no_mangle]
1067+
pub unsafe extern "C" fn krun_check_nested_virt() -> i32 {
1068+
#[cfg(target_os = "macos")]
1069+
match hvf::check_nested_virt() {
1070+
Ok(supp) => supp as i32,
1071+
Err(_) => -libc::EINVAL,
1072+
}
1073+
1074+
#[cfg(not(target_os = "macos"))]
1075+
-libc::EOPNOTSUPP
1076+
}
1077+
10651078
#[allow(clippy::missing_safety_doc)]
10661079
#[no_mangle]
10671080
pub extern "C" fn krun_split_irqchip(ctx_id: u32, enable: bool) -> i32 {

0 commit comments

Comments
 (0)