This commit is contained in:
Masato Imai
2025-08-05 19:12:20 +00:00
parent 0dc45fc4ef
commit fc25077217
4 changed files with 105 additions and 8 deletions

View File

@ -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
/*

View File

@ -1,4 +1,4 @@
mod asm;
pub mod asm;
mod controls;
mod register;
pub mod vcpu;

View File

@ -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,7 +177,8 @@ impl IntelVCpu {
vmwrite(vmcs::guest::CR3, 0)?;
vmwrite(
vmcs::guest::CR4,
(vmread(vmcs::guest::CR4)? | Cr4Flags::VIRTUAL_MACHINE_EXTENSIONS.bits())
vmread(vmcs::guest::CR4)?
| Cr4Flags::VIRTUAL_MACHINE_EXTENSIONS.bits()
& !Cr4Flags::PHYSICAL_ADDRESS_EXTENSION.bits(),
)?;
@ -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(())
}

View File

@ -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",
}
}
}