⚠️ VeridianOS Kernel Documentation - This is low-level kernel code. All functions are unsafe unless explicitly marked otherwise. no_std

veridian_kernel/virt/
mod.rs

1//! Virtualization subsystem - VMX hypervisor, EPT memory, containers
2//!
3//! Provides hardware-assisted virtualization (Intel VT-x) and
4//! OS-level container isolation with Linux-compatible namespaces.
5
6#[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/// Virtualization error types
25#[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}