diff --git a/nel_os_kernel/src/vmm/x86_64/intel/asm.rs b/nel_os_kernel/src/vmm/x86_64/intel/asm.rs index 77af7ca..8ad8448 100644 --- a/nel_os_kernel/src/vmm/x86_64/intel/asm.rs +++ b/nel_os_kernel/src/vmm/x86_64/intel/asm.rs @@ -43,7 +43,7 @@ global_asm!( "push rbx", // push *guest_regs "push rdi", // push *VCpu "lea rdi, [rsp + 8]", // rdi = rsp + 8 = *guest_regs -"call set_host_stack", +"call intel_set_host_stack", "pop rdi", // rdi = *VCpu "test byte ptr [rdi + {launch_done_offset}], 1", // flag = launch_done ? 1 : 0 /* diff --git a/nel_os_kernel/src/vmm/x86_64/intel/mod.rs b/nel_os_kernel/src/vmm/x86_64/intel/mod.rs index a9a0097..e7ddf7e 100644 --- a/nel_os_kernel/src/vmm/x86_64/intel/mod.rs +++ b/nel_os_kernel/src/vmm/x86_64/intel/mod.rs @@ -1,4 +1,4 @@ -mod asm; +pub mod asm; mod controls; mod register; pub mod vcpu; diff --git a/nel_os_kernel/src/vmm/x86_64/intel/vcpu.rs b/nel_os_kernel/src/vmm/x86_64/intel/vcpu.rs index 081ffcd..0bf8944 100644 --- a/nel_os_kernel/src/vmm/x86_64/intel/vcpu.rs +++ b/nel_os_kernel/src/vmm/x86_64/intel/vcpu.rs @@ -17,6 +17,8 @@ use crate::{ register::GuestRegisters, vmcs::{ self, + err::InstructionError, + exit_reason::VmxExitReason, segment::{DescriptorType, Granularity, SegmentRights}, }, vmread, vmwrite, vmxon, @@ -44,6 +46,66 @@ impl IntelVCpu { naked_asm!("2: hlt; jmp 2b"); } + #[unsafe(no_mangle)] + unsafe extern "C" fn intel_set_host_stack(rsp: u64) { + vmwrite(x86::vmx::vmcs::host::RSP, rsp).unwrap(); + } + + fn vmexit_handler(&mut self) -> Result<(), &'static str> { + use x86::vmx::vmcs; + let exit_reason_raw = vmread(vmcs::ro::EXIT_REASON)? as u32; + + if exit_reason_raw & (1 << 31) != 0 { + let reason = exit_reason_raw & 0xFF; + info!("VMEntry failure"); + match reason { + 33 => { + info!(" Reason: invalid guest state"); + } + _ => { + info!(" Reason: unknown ({})", reason); + } + } + } else { + let basic_reason = (exit_reason_raw & 0xFFFF) as u16; + let exit_reason: VmxExitReason = basic_reason.try_into().unwrap(); + + match exit_reason { + VmxExitReason::HLT => { + info!("VM hlt"); + } + _ => { + info!("VM exit reason: {:?}", exit_reason); + } + } + } + + Ok(()) + } + + fn vmentry(&mut self) -> Result<(), InstructionError> { + let success = { + let result: u16; + unsafe { + result = crate::vmm::x86_64::intel::asm::asm_vm_entry(self as *mut _); + }; + result == 0 + }; + + if !self.launch_done && success { + self.launch_done = true; + } + + if !success { + let error = InstructionError::read().unwrap(); + if error as u32 != 0 { + return Err(error); + } + } + + Ok(()) + } + fn activate(&mut self) -> Result<(), &'static str> { let revision_id = common::read_msr(0x480) as u32; self.vmcs.write_revision_id(revision_id); @@ -115,8 +177,9 @@ impl IntelVCpu { vmwrite(vmcs::guest::CR3, 0)?; vmwrite( vmcs::guest::CR4, - (vmread(vmcs::guest::CR4)? | Cr4Flags::VIRTUAL_MACHINE_EXTENSIONS.bits()) - & !Cr4Flags::PHYSICAL_ADDRESS_EXTENSION.bits(), + vmread(vmcs::guest::CR4)? + | Cr4Flags::VIRTUAL_MACHINE_EXTENSIONS.bits() + & !Cr4Flags::PHYSICAL_ADDRESS_EXTENSION.bits(), )?; vmwrite(vmcs::guest::CS_BASE, 0)?; @@ -211,8 +274,8 @@ impl IntelVCpu { vmwrite(vmcs::guest::RIP, Self::test_guest_code as u64)?; // TODO: Set linux kernel base // TODO: RSI - vmwrite(vmcs::control::CR0_READ_SHADOW, vmread(vmcs::guest::CR0)?)?; - vmwrite(vmcs::control::CR4_READ_SHADOW, vmread(vmcs::guest::CR4)?)?; + //vmwrite(vmcs::control::CR0_READ_SHADOW, vmread(vmcs::guest::CR0)?)?; + //vmwrite(vmcs::control::CR4_READ_SHADOW, vmread(vmcs::guest::CR4)?)?; Ok(()) } @@ -220,13 +283,14 @@ impl IntelVCpu { impl VCpu for IntelVCpu { fn run(&mut self) -> Result<(), &'static str> { - info!("VCpu on Intel"); - if !self.activated { self.activate()?; self.activated = true; } + self.vmentry().map_err(|e| e.to_str())?; + self.vmexit_handler()?; + Ok(()) } diff --git a/nel_os_kernel/src/vmm/x86_64/intel/vmcs/err.rs b/nel_os_kernel/src/vmm/x86_64/intel/vmcs/err.rs index acb7e56..80b067c 100644 --- a/nel_os_kernel/src/vmm/x86_64/intel/vmcs/err.rs +++ b/nel_os_kernel/src/vmm/x86_64/intel/vmcs/err.rs @@ -41,4 +41,37 @@ impl InstructionError { InstructionError::try_from(err).map_err(|_| "Unknown instruction error") } + + pub fn to_str(&self) -> &'static str { + match self { + InstructionError::NOT_AVAILABLE => "Instruction not available", + InstructionError::VMCALL_IN_VMXROOT => "VMCALL in VMX root operation", + InstructionError::VMCLEAR_INVALID_PHYS => "Invalid physical address for VMCLEAR", + InstructionError::VMCLEAR_VMXONPTR => "VMCLEAR with VMXON pointer", + InstructionError::VMLAUNCH_NONCLEAR_VMCS => "VMLAUNCH with non-cleared VMCS", + InstructionError::VMRESUME_NONLAUNCHED_VMCS => "VMRESUME with non-launched VMCS", + InstructionError::VMRESUME_AFTER_VMXOFF => "VMRESUME after VMXOFF", + InstructionError::VMENTRY_INVALID_CTRL => "Invalid control fields for VMENTRY", + InstructionError::VMENTRY_INVALID_HOST_STATE => "Invalid host state for VMENTRY", + InstructionError::VMPTRLD_INVALID_PHYS => "Invalid physical address for VMPTRLD", + InstructionError::VMPTRLD_VMXONP => "VMPTRLD with VMXON pointer", + InstructionError::VMPTRLD_INCORRECT_REV => "Incorrect revision identifier for VMPTRLD", + InstructionError::VMRW_UNSUPPORTED_COMPONENT => "Unsupported component in VMRW", + InstructionError::VMW_RO_COMPONENT => "Read-only component in VMWRITE", + InstructionError::VMXON_IN_VMXROOT => "VMXON in VMX root operation", + InstructionError::VMENTRY_INVALID_EXEC_CTRL => "Invalid execution controls for VMENTRY", + InstructionError::VMENTRY_NONLAUNCHED_EXEC_CTRL => { + "Non-launched execution controls for VMENTRY" + } + InstructionError::VMENTRY_EXEC_VMCSPTR => "Execution control VMCS pointer for VMENTRY", + InstructionError::VMCALL_NONCLEAR_VMCS => "VMCALL with non-cleared VMCS", + InstructionError::VMCALL_INVALID_EXITCTL => "Invalid exit control fields for VMCALL", + InstructionError::VMCALL_INCORRECT_MSGREV => "Incorrect message revision for VMCALL", + InstructionError::VMXOFF_DUALMONITOR => "VMXOFF in dual-monitor mode", + InstructionError::VMCALL_INVALID_SMM => "Invalid SMM state for VMCALL", + InstructionError::VMENTRY_INVALID_EXECCTRL => "Invalid execution controls for VMENTRY", + InstructionError::VMENTRY_EVENTS_BLOCKED => "Events blocked during VMENTRY", + InstructionError::INVALID_INVEPT => "Invalid INVEPT operation", + } + } }