Skip to content

Commit cc35fce

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 cc35fce

File tree

3 files changed

+69
-26
lines changed

3 files changed

+69
-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

+43-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,39 @@ 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+
pub fn check_nested_virt() -> Result<bool, Error> {
213+
// Only M3 and newer chips will support nested virtualization. Query the
214+
// system to verify if the chip has support.
215+
let get_el2_supported: libloading::Symbol<
216+
'static,
217+
unsafe extern "C" fn(*mut bool) -> hv_return_t,
218+
> = unsafe {
219+
HVF.get(b"hv_vm_config_get_el2_supported")
220+
.map_err(Error::FindSymbol)?
221+
};
222+
let mut el2_supported: bool = false;
223+
let ret = unsafe { (get_el2_supported)(&mut el2_supported) };
224+
if ret != HV_SUCCESS {
225+
error!("processor does not support the nested virtualization functionality");
226+
return Err(Error::NestedCheck);
227+
}
228+
229+
// nested virtualization requires macOS 15.0+
230+
match std::process::Command::new("sw_vers")
231+
.arg("--productVersion")
232+
.output()
233+
{
234+
Ok(cmd_output) => {
235+
let macos_version: u8 = String::from_utf8_lossy(&cmd_output.stdout)[..2]
236+
.parse()
237+
.unwrap();
238+
Ok(el2_supported && macos_version >= 15)
239+
}
240+
Err(e) => {
241+
error!("unable to check macOS version: {:?}", e);
242+
Err(Error::NestedCheck)
243+
}
244+
}
214245
}
215246

216247
pub struct HvfVm {}
@@ -225,30 +256,16 @@ static HVF: LazyLock<libloading::Library> = LazyLock::new(|| unsafe {
225256
impl HvfVm {
226257
pub fn new(nested_enabled: bool) -> Result<Self, Error> {
227258
let config = unsafe { hv_vm_config_create() };
228-
229259
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-
}
260+
let set_el2_enabled: libloading::Symbol<
261+
'static,
262+
unsafe extern "C" fn(hv_vm_config_t, bool) -> hv_return_t,
263+
> = unsafe {
264+
HVF.get(b"hv_vm_config_set_el2_enabled")
265+
.map_err(Error::FindSymbol)?
239266
};
240267

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) };
268+
let ret = unsafe { (set_el2_enabled)(config, true) };
252269
if ret != HV_SUCCESS {
253270
return Err(Error::EnableEL2);
254271
}

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::EINVAL
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)