wip
This commit is contained in:
@ -43,7 +43,7 @@ global_asm!(
|
|||||||
"push rbx", // push *guest_regs
|
"push rbx", // push *guest_regs
|
||||||
"push rdi", // push *VCpu
|
"push rdi", // push *VCpu
|
||||||
"lea rdi, [rsp + 8]", // rdi = rsp + 8 = *guest_regs
|
"lea rdi, [rsp + 8]", // rdi = rsp + 8 = *guest_regs
|
||||||
"call set_host_stack",
|
"call intel_set_host_stack",
|
||||||
"pop rdi", // rdi = *VCpu
|
"pop rdi", // rdi = *VCpu
|
||||||
"test byte ptr [rdi + {launch_done_offset}], 1", // flag = launch_done ? 1 : 0
|
"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 controls;
|
||||||
mod register;
|
mod register;
|
||||||
pub mod vcpu;
|
pub mod vcpu;
|
||||||
|
@ -17,6 +17,8 @@ use crate::{
|
|||||||
register::GuestRegisters,
|
register::GuestRegisters,
|
||||||
vmcs::{
|
vmcs::{
|
||||||
self,
|
self,
|
||||||
|
err::InstructionError,
|
||||||
|
exit_reason::VmxExitReason,
|
||||||
segment::{DescriptorType, Granularity, SegmentRights},
|
segment::{DescriptorType, Granularity, SegmentRights},
|
||||||
},
|
},
|
||||||
vmread, vmwrite, vmxon,
|
vmread, vmwrite, vmxon,
|
||||||
@ -44,6 +46,66 @@ impl IntelVCpu {
|
|||||||
naked_asm!("2: hlt; jmp 2b");
|
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> {
|
fn activate(&mut self) -> Result<(), &'static str> {
|
||||||
let revision_id = common::read_msr(0x480) as u32;
|
let revision_id = common::read_msr(0x480) as u32;
|
||||||
self.vmcs.write_revision_id(revision_id);
|
self.vmcs.write_revision_id(revision_id);
|
||||||
@ -115,8 +177,9 @@ impl IntelVCpu {
|
|||||||
vmwrite(vmcs::guest::CR3, 0)?;
|
vmwrite(vmcs::guest::CR3, 0)?;
|
||||||
vmwrite(
|
vmwrite(
|
||||||
vmcs::guest::CR4,
|
vmcs::guest::CR4,
|
||||||
(vmread(vmcs::guest::CR4)? | Cr4Flags::VIRTUAL_MACHINE_EXTENSIONS.bits())
|
vmread(vmcs::guest::CR4)?
|
||||||
& !Cr4Flags::PHYSICAL_ADDRESS_EXTENSION.bits(),
|
| Cr4Flags::VIRTUAL_MACHINE_EXTENSIONS.bits()
|
||||||
|
& !Cr4Flags::PHYSICAL_ADDRESS_EXTENSION.bits(),
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
vmwrite(vmcs::guest::CS_BASE, 0)?;
|
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
|
vmwrite(vmcs::guest::RIP, Self::test_guest_code as u64)?; // TODO: Set linux kernel base
|
||||||
// TODO: RSI
|
// TODO: RSI
|
||||||
|
|
||||||
vmwrite(vmcs::control::CR0_READ_SHADOW, vmread(vmcs::guest::CR0)?)?;
|
//vmwrite(vmcs::control::CR0_READ_SHADOW, vmread(vmcs::guest::CR0)?)?;
|
||||||
vmwrite(vmcs::control::CR4_READ_SHADOW, vmread(vmcs::guest::CR4)?)?;
|
//vmwrite(vmcs::control::CR4_READ_SHADOW, vmread(vmcs::guest::CR4)?)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -220,13 +283,14 @@ impl IntelVCpu {
|
|||||||
|
|
||||||
impl VCpu for IntelVCpu {
|
impl VCpu for IntelVCpu {
|
||||||
fn run(&mut self) -> Result<(), &'static str> {
|
fn run(&mut self) -> Result<(), &'static str> {
|
||||||
info!("VCpu on Intel");
|
|
||||||
|
|
||||||
if !self.activated {
|
if !self.activated {
|
||||||
self.activate()?;
|
self.activate()?;
|
||||||
self.activated = true;
|
self.activated = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.vmentry().map_err(|e| e.to_str())?;
|
||||||
|
self.vmexit_handler()?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -41,4 +41,37 @@ impl InstructionError {
|
|||||||
|
|
||||||
InstructionError::try_from(err).map_err(|_| "Unknown instruction error")
|
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