wip
This commit is contained in:
@ -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
|
||||
/*
|
||||
|
@ -1,4 +1,4 @@
|
||||
mod asm;
|
||||
pub mod asm;
|
||||
mod controls;
|
||||
mod register;
|
||||
pub mod vcpu;
|
||||
|
@ -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(())
|
||||
}
|
||||
|
||||
|
@ -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",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user