#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct NestedVirtSupport {
pub supported: bool,
pub reason: &'static str,
}
#[must_use]
pub fn host_nested_virt() -> NestedVirtSupport {
let supported = cached_or_reprobed();
NestedVirtSupport {
supported,
reason: if supported { "" } else { UNSUPPORTED_REASON },
}
}
#[cfg(target_os = "macos")]
fn cached_or_reprobed() -> bool {
static SUPPORTED: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
*SUPPORTED.get_or_init(probe_nested_virt)
}
#[cfg(not(target_os = "macos"))]
fn cached_or_reprobed() -> bool {
probe_nested_virt()
}
#[cfg(target_os = "macos")]
const UNSUPPORTED_REASON: &str = concat!(
"nested virtualization requires Apple Silicon M3 or newer ",
"with macOS 15 or newer",
);
#[cfg(target_os = "macos")]
fn probe_nested_virt() -> bool {
arcbox_vz::GenericPlatform::is_nested_virt_supported()
}
#[cfg(target_os = "linux")]
const UNSUPPORTED_REASON: &str = concat!(
"the host kernel does not expose nested KVM ",
"(/sys/module/kvm_{intel,amd}/parameters/nested)",
);
#[cfg(target_os = "linux")]
fn probe_nested_virt() -> bool {
["kvm_intel", "kvm_amd"].iter().any(|module| {
std::fs::read_to_string(format!("/sys/module/{module}/parameters/nested"))
.is_ok_and(|content| matches!(content.trim(), "1" | "Y" | "y"))
})
}
#[cfg(not(any(target_os = "macos", target_os = "linux")))]
const UNSUPPORTED_REASON: &str = "nested virtualization is not supported on this platform";
#[cfg(not(any(target_os = "macos", target_os = "linux")))]
fn probe_nested_virt() -> bool {
false
}
#[cfg(test)]
mod tests {
use super::*;
#[cfg(target_os = "macos")]
#[test]
fn the_macos_reason_names_the_hardware_requirement() {
let reason = super::UNSUPPORTED_REASON;
assert!(reason.contains("M3"), "{reason}");
assert!(reason.contains("macOS 15"), "{reason}");
}
#[test]
fn an_unsupported_host_always_carries_a_reason() {
let support = host_nested_virt();
assert_eq!(support.supported, support.reason.is_empty());
}
#[test]
fn the_probe_is_stable_across_repeated_calls() {
assert_eq!(host_nested_virt(), host_nested_virt());
}
}