1#[cfg(feature = "alloc")]
7extern crate alloc;
8
9pub mod container;
10pub mod containers;
11pub mod devices;
12pub mod hotplug;
13pub mod hypervisor;
14pub mod kvm;
15pub mod memory;
16pub mod namespace;
17pub mod qemu_compat;
18pub mod sriov;
19pub mod vfio;
20pub mod vmx;
21
22use crate::error::KernelError;
23
24#[derive(Debug, Clone, Copy, PartialEq, Eq)]
26pub enum VmError {
27 VmxNotSupported,
28 VmxDisabled,
29 VmxonFailed,
30 VmxoffFailed,
31 VmclearFailed,
32 VmptrldFailed,
33 VmlaunchFailed,
34 VmresumeFailed,
35 VmwriteFailed,
36 VmreadFailed,
37 VmcsAllocationFailed,
38 EptMappingFailed,
39 GuestMemoryError,
40 InvalidVmState,
41 DeviceError,
42 VmxOperationFailed,
43 VmcsFieldError,
44 VmxAlreadyEnabled,
45 VmEntryFailed,
46 VmExitHandlerError,
47 InvalidGuestState,
48}
49
50impl core::fmt::Display for VmError {
51 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
52 match self {
53 Self::VmxNotSupported => write!(f, "VMX not supported"),
54 Self::VmxDisabled => write!(f, "VMX disabled in BIOS"),
55 Self::VmxonFailed => write!(f, "VMXON failed"),
56 Self::VmxoffFailed => write!(f, "VMXOFF failed"),
57 Self::VmclearFailed => write!(f, "VMCLEAR failed"),
58 Self::VmptrldFailed => write!(f, "VMPTRLD failed"),
59 Self::VmlaunchFailed => write!(f, "VMLAUNCH failed"),
60 Self::VmresumeFailed => write!(f, "VMRESUME failed"),
61 Self::VmwriteFailed => write!(f, "VMWRITE failed"),
62 Self::VmreadFailed => write!(f, "VMREAD failed"),
63 Self::VmcsAllocationFailed => write!(f, "VMCS allocation failed"),
64 Self::EptMappingFailed => write!(f, "EPT mapping failed"),
65 Self::GuestMemoryError => write!(f, "Guest memory error"),
66 Self::InvalidVmState => write!(f, "Invalid VM state"),
67 Self::DeviceError => write!(f, "Device emulation error"),
68 Self::VmxOperationFailed => write!(f, "VMX operation failed"),
69 Self::VmcsFieldError => write!(f, "VMCS field error"),
70 Self::VmxAlreadyEnabled => write!(f, "VMX already enabled"),
71 Self::VmEntryFailed => write!(f, "VM entry failed"),
72 Self::VmExitHandlerError => write!(f, "VM exit handler error"),
73 Self::InvalidGuestState => write!(f, "Invalid guest state"),
74 }
75 }
76}
77
78impl From<VmError> for KernelError {
79 fn from(e: VmError) -> Self {
80 KernelError::InvalidArgument {
81 name: "virt",
82 value: match e {
83 VmError::VmxNotSupported => "vmx_not_supported",
84 VmError::VmxDisabled => "vmx_disabled",
85 VmError::VmxonFailed => "vmxon_failed",
86 VmError::VmxoffFailed => "vmxoff_failed",
87 VmError::VmclearFailed => "vmclear_failed",
88 VmError::VmptrldFailed => "vmptrld_failed",
89 VmError::VmlaunchFailed => "vmlaunch_failed",
90 VmError::VmresumeFailed => "vmresume_failed",
91 VmError::VmwriteFailed => "vmwrite_failed",
92 VmError::VmreadFailed => "vmread_failed",
93 VmError::VmcsAllocationFailed => "vmcs_alloc_failed",
94 VmError::EptMappingFailed => "ept_mapping_failed",
95 VmError::GuestMemoryError => "guest_memory_error",
96 VmError::InvalidVmState => "invalid_vm_state",
97 VmError::DeviceError => "device_error",
98 VmError::VmxOperationFailed => "vmx_operation_failed",
99 VmError::VmcsFieldError => "vmcs_field_error",
100 VmError::VmxAlreadyEnabled => "vmx_already_enabled",
101 VmError::VmEntryFailed => "vm_entry_failed",
102 VmError::VmExitHandlerError => "vm_exit_handler_error",
103 VmError::InvalidGuestState => "invalid_guest_state",
104 },
105 }
106 }
107}
108
109#[derive(Debug, Clone, Copy, PartialEq, Eq)]
110#[repr(u32)]
111pub enum VmExitReason {
112 ExceptionOrNmi = 0,
113 ExternalInterrupt = 1,
114 TripleFault = 2,
115 InitSignal = 3,
116 StartupIpi = 4,
117 IoSmi = 5,
118 OtherSmi = 6,
119 InterruptWindow = 7,
120 NmiWindow = 8,
121 TaskSwitch = 9,
122 Cpuid = 10,
123 Getsec = 11,
124 Hlt = 12,
125 Invd = 13,
126 Invlpg = 14,
127 Rdpmc = 15,
128 Rdtsc = 16,
129 Rsm = 17,
130 Vmcall = 18,
131 Vmclear = 19,
132 Vmlaunch = 20,
133 Vmptrld = 21,
134 Vmptrst = 22,
135 Vmread = 23,
136 Vmresume = 24,
137 Vmwrite = 25,
138 Vmxoff = 26,
139 Vmxon = 27,
140 ControlRegisterAccess = 28,
141 MovDr = 29,
142 IoInstruction = 30,
143 Rdmsr = 31,
144 Wrmsr = 32,
145 EntryFailInvalidGuestState = 33,
146 EntryFailMsrLoading = 34,
147 Mwait = 36,
148 MonitorTrapFlag = 37,
149 Monitor = 39,
150 Pause = 40,
151 EntryFailMachineCheck = 41,
152 TprBelowThreshold = 43,
153 ApicAccess = 44,
154 VirtualizedEoi = 45,
155 GdtrIdtrAccess = 46,
156 LdtrTrAccess = 47,
157 EptViolation = 48,
158 EptMisconfiguration = 49,
159 Invept = 50,
160 Rdtscp = 51,
161 VmxPreemptionTimerExpired = 52,
162 Invvpid = 53,
163 WbinvdWbnoinvd = 54,
164 Xsetbv = 55,
165 ApicWrite = 56,
166 Rdrand = 57,
167 Invpcid = 58,
168 Vmfunc = 59,
169 Encls = 60,
170 Rdseed = 61,
171 PageModLogFull = 62,
172 Xsaves = 63,
173 Xrstors = 64,
174 Unknown = 0xFFFF,
175}
176
177impl VmExitReason {
178 pub fn from_raw(raw: u32) -> Self {
179 match raw & 0xFFFF {
180 0 => Self::ExceptionOrNmi,
181 1 => Self::ExternalInterrupt,
182 2 => Self::TripleFault,
183 3 => Self::InitSignal,
184 4 => Self::StartupIpi,
185 5 => Self::IoSmi,
186 6 => Self::OtherSmi,
187 7 => Self::InterruptWindow,
188 8 => Self::NmiWindow,
189 9 => Self::TaskSwitch,
190 10 => Self::Cpuid,
191 11 => Self::Getsec,
192 12 => Self::Hlt,
193 13 => Self::Invd,
194 14 => Self::Invlpg,
195 15 => Self::Rdpmc,
196 16 => Self::Rdtsc,
197 17 => Self::Rsm,
198 18 => Self::Vmcall,
199 19 => Self::Vmclear,
200 20 => Self::Vmlaunch,
201 21 => Self::Vmptrld,
202 22 => Self::Vmptrst,
203 23 => Self::Vmread,
204 24 => Self::Vmresume,
205 25 => Self::Vmwrite,
206 26 => Self::Vmxoff,
207 27 => Self::Vmxon,
208 28 => Self::ControlRegisterAccess,
209 29 => Self::MovDr,
210 30 => Self::IoInstruction,
211 31 => Self::Rdmsr,
212 32 => Self::Wrmsr,
213 33 => Self::EntryFailInvalidGuestState,
214 34 => Self::EntryFailMsrLoading,
215 36 => Self::Mwait,
216 37 => Self::MonitorTrapFlag,
217 39 => Self::Monitor,
218 40 => Self::Pause,
219 41 => Self::EntryFailMachineCheck,
220 43 => Self::TprBelowThreshold,
221 44 => Self::ApicAccess,
222 45 => Self::VirtualizedEoi,
223 46 => Self::GdtrIdtrAccess,
224 47 => Self::LdtrTrAccess,
225 48 => Self::EptViolation,
226 49 => Self::EptMisconfiguration,
227 50 => Self::Invept,
228 51 => Self::Rdtscp,
229 52 => Self::VmxPreemptionTimerExpired,
230 53 => Self::Invvpid,
231 54 => Self::WbinvdWbnoinvd,
232 55 => Self::Xsetbv,
233 56 => Self::ApicWrite,
234 57 => Self::Rdrand,
235 58 => Self::Invpcid,
236 59 => Self::Vmfunc,
237 60 => Self::Encls,
238 61 => Self::Rdseed,
239 62 => Self::PageModLogFull,
240 63 => Self::Xsaves,
241 64 => Self::Xrstors,
242 _ => Self::Unknown,
243 }
244 }
245}
246
247#[derive(Debug, Clone, Copy)]
248pub struct VmCapability {
249 pub vmx_supported: bool,
250 pub ept_supported: bool,
251 pub vpid_supported: bool,
252 pub unrestricted_guest: bool,
253}
254
255impl VmCapability {
256 pub fn detect() -> Self {
257 let vmx = cpu_supports_vmx();
258 Self {
259 vmx_supported: vmx,
260 ept_supported: vmx,
261 vpid_supported: vmx,
262 unrestricted_guest: vmx,
263 }
264 }
265}
266
267pub fn cpu_supports_vmx() -> bool {
268 #[cfg(target_arch = "x86_64")]
269 {
270 let ecx: u32;
271 unsafe {
272 core::arch::asm!(
273 "push rbx", "mov eax, 1", "cpuid", "pop rbx",
274 out("ecx") ecx, out("eax") _, out("edx") _, options(nomem),
275 );
276 }
277 ecx & (1 << 5) != 0
278 }
279 #[cfg(not(target_arch = "x86_64"))]
280 {
281 false
282 }
283}
284
285#[cfg(target_arch = "x86_64")]
286pub(crate) unsafe fn read_msr(msr: u32) -> u64 {
287 let low: u32;
288 let high: u32;
289 unsafe {
290 core::arch::asm!("rdmsr", in("ecx") msr, out("eax") low, out("edx") high, options(nomem, nostack));
291 }
292 ((high as u64) << 32) | (low as u64)
293}
294
295#[cfg(target_arch = "x86_64")]
296pub(crate) unsafe fn write_msr(msr: u32, value: u64) {
297 let low = value as u32;
298 let high = (value >> 32) as u32;
299 unsafe {
300 core::arch::asm!("wrmsr", in("ecx") msr, in("eax") low, in("edx") high, options(nomem, nostack));
301 }
302}
303
304pub fn init() {
305 let cap = VmCapability::detect();
306 crate::println!(" [virt] VMX supported: {}", cap.vmx_supported);
307 crate::println!(" [virt] EPT supported: {}", cap.ept_supported);
308 crate::println!(" [virt] VPID supported: {}", cap.vpid_supported);
309 container::init();
310 crate::println!(" [virt] Virtualization subsystem initialized");
311}
312
313#[cfg(test)]
314mod tests {
315 use super::*;
316
317 #[test]
318 fn test_vm_exit_reason_from_raw() {
319 assert_eq!(VmExitReason::from_raw(0), VmExitReason::ExceptionOrNmi);
320 assert_eq!(VmExitReason::from_raw(10), VmExitReason::Cpuid);
321 assert_eq!(VmExitReason::from_raw(48), VmExitReason::EptViolation);
322 assert_eq!(VmExitReason::from_raw(9999), VmExitReason::Unknown);
323 }
324
325 #[test]
326 fn test_vm_error_display() {
327 assert_eq!(
328 alloc::format!("{}", VmError::VmxNotSupported),
329 "VMX not supported"
330 );
331 }
332
333 #[test]
334 fn test_vm_capability_detect() {
335 let _ = VmCapability::detect().vmx_supported;
336 }
337
338 #[test]
339 fn test_vm_error_to_kernel_error() {
340 let e: KernelError = VmError::EptMappingFailed.into();
341 match e {
342 KernelError::InvalidArgument { name, value } => {
343 assert_eq!(name, "virt");
344 assert_eq!(value, "ept_mapping_failed");
345 }
346 _ => panic!("Wrong error variant"),
347 }
348 }
349}