a3s_box_runtime/
host_check.rs1use a3s_box_core::error::{BoxError, Result};
9
10#[derive(Debug, Clone)]
12pub struct VirtualizationSupport {
13 pub backend: String,
15 pub details: String,
17}
18
19pub fn check_virtualization_support() -> Result<VirtualizationSupport> {
23 #[cfg(target_os = "macos")]
24 {
25 check_macos_hypervisor()
26 }
27
28 #[cfg(target_os = "linux")]
29 {
30 check_linux_kvm()
31 }
32
33 #[cfg(target_os = "windows")]
34 {
35 check_windows_whpx()
36 }
37
38 #[cfg(not(any(target_os = "macos", target_os = "linux", target_os = "windows")))]
39 {
40 Err(BoxError::ConfigError(
41 "Unsupported platform: A3S Box requires macOS (Apple Silicon), Linux with KVM, or Windows with WHPX"
42 .to_string(),
43 ))
44 }
45}
46
47#[cfg(target_os = "macos")]
49fn check_macos_hypervisor() -> Result<VirtualizationSupport> {
50 #[cfg(target_arch = "aarch64")]
51 {
52 let output = std::process::Command::new("sysctl")
54 .arg("kern.hv_support")
55 .output()
56 .map_err(|e| BoxError::ExecError(format!("Failed to run sysctl: {}", e)))?;
57
58 if !output.status.success() {
59 return Err(BoxError::ConfigError(
60 "Failed to query Hypervisor.framework support via sysctl".to_string(),
61 ));
62 }
63
64 let stdout = String::from_utf8_lossy(&output.stdout);
65 let value = stdout.split(':').nth(1).map(|s| s.trim()).unwrap_or("0");
67
68 if value == "1" {
69 Ok(VirtualizationSupport {
70 backend: "Hypervisor.framework".to_string(),
71 details: "Apple Silicon hardware virtualization is available".to_string(),
72 })
73 } else {
74 Err(BoxError::ConfigError(
75 "Hypervisor.framework is not available on this system. \
76 Ensure you are running on Apple Silicon and have the necessary entitlements."
77 .to_string(),
78 ))
79 }
80 }
81
82 #[cfg(not(target_arch = "aarch64"))]
83 {
84 Err(BoxError::ConfigError(
85 "A3S Box on macOS requires Apple Silicon (ARM64). Intel Macs are not supported."
86 .to_string(),
87 ))
88 }
89}
90
91#[cfg(target_os = "linux")]
93fn check_linux_kvm() -> Result<VirtualizationSupport> {
94 use std::path::Path;
95
96 let kvm_path = Path::new("/dev/kvm");
97
98 if !kvm_path.exists() {
99 return Err(BoxError::ConfigError(
100 "KVM is not available: /dev/kvm not found. \
101 Ensure KVM kernel modules are loaded (modprobe kvm kvm_intel or kvm_amd)."
102 .to_string(),
103 ));
104 }
105
106 match std::fs::OpenOptions::new()
108 .read(true)
109 .write(true)
110 .open(kvm_path)
111 {
112 Ok(_) => Ok(VirtualizationSupport {
113 backend: "KVM".to_string(),
114 details: "Linux KVM hardware virtualization is available".to_string(),
115 }),
116 Err(e) => {
117 if e.kind() == std::io::ErrorKind::PermissionDenied {
118 Err(BoxError::ConfigError(format!(
119 "KVM access denied: {}. Add your user to the 'kvm' group: \
120 sudo usermod -aG kvm $USER",
121 e
122 )))
123 } else {
124 Err(BoxError::ConfigError(format!(
125 "Failed to access /dev/kvm: {}",
126 e
127 )))
128 }
129 }
130 }
131}
132
133#[cfg(target_os = "windows")]
135fn check_windows_whpx() -> Result<VirtualizationSupport> {
136 #[cfg(not(target_arch = "x86_64"))]
137 {
138 return Err(BoxError::ConfigError(
139 "A3S Box on Windows currently requires x86_64 for the WHPX backend.".to_string(),
140 ));
141 }
142
143 use windows_sys::Win32::Foundation::BOOL;
144 use windows_sys::Win32::System::Hypervisor::{
145 WHvCapabilityCodeHypervisorPresent, WHvGetCapability,
146 };
147
148 let mut present: BOOL = 0;
149 let mut written = 0_u32;
150 let status = unsafe {
153 WHvGetCapability(
154 WHvCapabilityCodeHypervisorPresent,
155 (&mut present as *mut BOOL).cast(),
156 std::mem::size_of::<BOOL>() as u32,
157 &mut written,
158 )
159 };
160 if status < 0 {
161 return Err(BoxError::ConfigError(format!(
162 "Failed to query Windows Hypervisor Platform capability (HRESULT 0x{:08X})",
163 status as u32
164 )));
165 }
166 if written == std::mem::size_of::<BOOL>() as u32 && present != 0 {
167 Ok(VirtualizationSupport {
168 backend: "WHPX".to_string(),
169 details: "Windows Hypervisor Platform is available".to_string(),
170 })
171 } else {
172 Err(BoxError::ConfigError(
173 "Windows Hypervisor Platform is not available. Enable the 'Windows Hypervisor Platform' optional feature, verify firmware virtualization, and reboot."
174 .to_string(),
175 ))
176 }
177}
178
179#[cfg(test)]
180mod tests {
181 use super::*;
182
183 #[test]
184 fn test_check_virtualization_support() {
185 match check_virtualization_support() {
188 Ok(support) => {
189 println!("Virtualization supported:");
190 println!(" Backend: {}", support.backend);
191 println!(" Details: {}", support.details);
192 }
193 Err(e) => {
194 println!("Virtualization not supported: {}", e);
195 }
196 }
197 }
198}