mirror of
https://github.com/mii443/nel_os.git
synced 2025-08-22 16:15:38 +00:00
HLT VMExit
This commit is contained in:
7
Cargo.lock
generated
7
Cargo.lock
generated
@ -88,6 +88,7 @@ dependencies = [
|
|||||||
"bootloader",
|
"bootloader",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
"linked_list_allocator",
|
"linked_list_allocator",
|
||||||
|
"numeric-enum-macro",
|
||||||
"pc-keyboard",
|
"pc-keyboard",
|
||||||
"pic8259",
|
"pic8259",
|
||||||
"spin 0.5.2",
|
"spin 0.5.2",
|
||||||
@ -97,6 +98,12 @@ dependencies = [
|
|||||||
"x86_64 0.14.13",
|
"x86_64 0.14.13",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "numeric-enum-macro"
|
||||||
|
version = "0.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "300e4bdb6b46b592948e700ea1ef24a4296491f6a0ee722b258040abd15a3714"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pc-keyboard"
|
name = "pc-keyboard"
|
||||||
version = "0.8.0"
|
version = "0.8.0"
|
||||||
|
@ -14,6 +14,7 @@ pc-keyboard = "0.8.0"
|
|||||||
linked_list_allocator = "0.9.0"
|
linked_list_allocator = "0.9.0"
|
||||||
x86 = "0.52.0"
|
x86 = "0.52.0"
|
||||||
bitfield = "0.19.0"
|
bitfield = "0.19.0"
|
||||||
|
numeric-enum-macro = "0.2.0"
|
||||||
|
|
||||||
[dependencies.lazy_static]
|
[dependencies.lazy_static]
|
||||||
version = "1.0"
|
version = "1.0"
|
||||||
|
@ -21,7 +21,10 @@ use nel_os::{
|
|||||||
vmcs::InstructionError,
|
vmcs::InstructionError,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
use x86::bits64::vmx;
|
use x86::{
|
||||||
|
bits64::vmx::{self, vmread},
|
||||||
|
vmx::vmcs,
|
||||||
|
};
|
||||||
use x86_64::VirtAddr;
|
use x86_64::VirtAddr;
|
||||||
|
|
||||||
#[cfg(not(test))]
|
#[cfg(not(test))]
|
||||||
@ -62,6 +65,8 @@ fn kernel_main(boot_info: &'static BootInfo) -> ! {
|
|||||||
info!("Starting the Virtual Machine...");
|
info!("Starting the Virtual Machine...");
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
|
asm!("cli");
|
||||||
|
|
||||||
let vmlaunch = vmx::vmlaunch();
|
let vmlaunch = vmx::vmlaunch();
|
||||||
|
|
||||||
info!("VMLaunch: {:?}", vmlaunch);
|
info!("VMLaunch: {:?}", vmlaunch);
|
||||||
|
107
src/vmm/vcpu.rs
107
src/vmm/vcpu.rs
@ -1,20 +1,21 @@
|
|||||||
use x86::{
|
use x86::{
|
||||||
bits64::vmx::vmwrite,
|
bits64::vmx::{vmread, vmwrite},
|
||||||
controlregs::{cr0, cr3, cr4},
|
controlregs::{cr0, cr3, cr4},
|
||||||
dtables::{self, DescriptorTablePointer},
|
dtables::{self, DescriptorTablePointer},
|
||||||
halt,
|
halt,
|
||||||
msr::{rdmsr, IA32_EFER, IA32_FS_BASE},
|
msr::{rdmsr, IA32_EFER, IA32_FS_BASE},
|
||||||
vmx::{vmcs, VmFail},
|
vmx::{vmcs, VmFail},
|
||||||
};
|
};
|
||||||
|
use x86_64::VirtAddr;
|
||||||
|
|
||||||
use core::arch::naked_asm;
|
use core::arch::{asm, naked_asm};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
info,
|
info,
|
||||||
memory::BootInfoFrameAllocator,
|
memory::BootInfoFrameAllocator,
|
||||||
vmm::vmcs::{
|
vmm::vmcs::{
|
||||||
DescriptorType, EntryControls, Granularity, PrimaryExitControls,
|
DescriptorType, EntryControls, Granularity, PrimaryExitControls,
|
||||||
PrimaryProcessorBasedVmExecutionControls, SegmentRights,
|
PrimaryProcessorBasedVmExecutionControls, SegmentRights, VmxExitInfo,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -29,6 +30,9 @@ pub struct VCpu {
|
|||||||
pub phys_mem_offset: u64,
|
pub phys_mem_offset: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const TEMP_STACK_SIZE: usize = 4096;
|
||||||
|
static mut TEMP_STACK: [u8; TEMP_STACK_SIZE + 0x10] = [0; TEMP_STACK_SIZE + 0x10];
|
||||||
|
|
||||||
impl VCpu {
|
impl VCpu {
|
||||||
pub fn new(phys_mem_offset: u64, frame_allocator: &mut BootInfoFrameAllocator) -> Self {
|
pub fn new(phys_mem_offset: u64, frame_allocator: &mut BootInfoFrameAllocator) -> Self {
|
||||||
let mut vmxon = Vmxon::new(frame_allocator);
|
let mut vmxon = Vmxon::new(frame_allocator);
|
||||||
@ -81,7 +85,7 @@ impl VCpu {
|
|||||||
|
|
||||||
primary_exec_ctrl.0 |= (reserved_bits & 0xFFFFFFFF) as u32;
|
primary_exec_ctrl.0 |= (reserved_bits & 0xFFFFFFFF) as u32;
|
||||||
primary_exec_ctrl.0 &= (reserved_bits >> 32) as u32;
|
primary_exec_ctrl.0 &= (reserved_bits >> 32) as u32;
|
||||||
primary_exec_ctrl.set_hlt(true);
|
primary_exec_ctrl.set_hlt(false);
|
||||||
primary_exec_ctrl.set_activate_secondary_controls(false);
|
primary_exec_ctrl.set_activate_secondary_controls(false);
|
||||||
|
|
||||||
primary_exec_ctrl.write();
|
primary_exec_ctrl.write();
|
||||||
@ -142,6 +146,10 @@ impl VCpu {
|
|||||||
vmwrite(vmcs::host::CR4, cr4().bits() as u64)?;
|
vmwrite(vmcs::host::CR4, cr4().bits() as u64)?;
|
||||||
|
|
||||||
vmwrite(vmcs::host::RIP, Self::vmexit as u64)?;
|
vmwrite(vmcs::host::RIP, Self::vmexit as u64)?;
|
||||||
|
vmwrite(
|
||||||
|
vmcs::host::RSP,
|
||||||
|
VirtAddr::from_ptr(&raw mut TEMP_STACK).as_u64() + TEMP_STACK_SIZE as u64,
|
||||||
|
)?;
|
||||||
|
|
||||||
vmwrite(
|
vmwrite(
|
||||||
vmcs::host::ES_SELECTOR,
|
vmcs::host::ES_SELECTOR,
|
||||||
@ -204,16 +212,16 @@ impl VCpu {
|
|||||||
vmwrite(vmcs::guest::IDTR_BASE, 0)?;
|
vmwrite(vmcs::guest::IDTR_BASE, 0)?;
|
||||||
vmwrite(vmcs::guest::LDTR_BASE, 0xDEAD00)?;
|
vmwrite(vmcs::guest::LDTR_BASE, 0xDEAD00)?;
|
||||||
|
|
||||||
vmwrite(vmcs::guest::CS_LIMIT, u32::MAX as u64)?;
|
vmwrite(vmcs::guest::CS_LIMIT, 0xffff)?;
|
||||||
vmwrite(vmcs::guest::SS_LIMIT, u32::MAX as u64)?;
|
vmwrite(vmcs::guest::SS_LIMIT, 0xffff)?;
|
||||||
vmwrite(vmcs::guest::DS_LIMIT, u32::MAX as u64)?;
|
vmwrite(vmcs::guest::DS_LIMIT, 0xffff)?;
|
||||||
vmwrite(vmcs::guest::ES_LIMIT, u32::MAX as u64)?;
|
vmwrite(vmcs::guest::ES_LIMIT, 0xffff)?;
|
||||||
vmwrite(vmcs::guest::FS_LIMIT, u32::MAX as u64)?;
|
vmwrite(vmcs::guest::FS_LIMIT, 0xffff)?;
|
||||||
vmwrite(vmcs::guest::GS_LIMIT, u32::MAX as u64)?;
|
vmwrite(vmcs::guest::GS_LIMIT, 0xffff)?;
|
||||||
vmwrite(vmcs::guest::TR_LIMIT, u32::MAX as u64)?;
|
vmwrite(vmcs::guest::TR_LIMIT, 0)?;
|
||||||
vmwrite(vmcs::guest::GDTR_LIMIT, u32::MAX as u64)?;
|
vmwrite(vmcs::guest::GDTR_LIMIT, 0)?;
|
||||||
vmwrite(vmcs::guest::IDTR_LIMIT, u32::MAX as u64)?;
|
vmwrite(vmcs::guest::IDTR_LIMIT, 0)?;
|
||||||
vmwrite(vmcs::guest::LDTR_LIMIT, u32::MAX as u64)?;
|
vmwrite(vmcs::guest::LDTR_LIMIT, 0)?;
|
||||||
|
|
||||||
vmwrite(
|
vmwrite(
|
||||||
vmcs::guest::CS_SELECTOR,
|
vmcs::guest::CS_SELECTOR,
|
||||||
@ -227,8 +235,8 @@ impl VCpu {
|
|||||||
vmwrite(vmcs::guest::TR_SELECTOR, 0)?;
|
vmwrite(vmcs::guest::TR_SELECTOR, 0)?;
|
||||||
vmwrite(vmcs::guest::LDTR_SELECTOR, 0)?;
|
vmwrite(vmcs::guest::LDTR_SELECTOR, 0)?;
|
||||||
|
|
||||||
let cs_rights = {
|
let cs_right = {
|
||||||
let mut rights = SegmentRights(0);
|
let mut rights = SegmentRights::default();
|
||||||
rights.set_rw(true);
|
rights.set_rw(true);
|
||||||
rights.set_dc(false);
|
rights.set_dc(false);
|
||||||
rights.set_executable(true);
|
rights.set_executable(true);
|
||||||
@ -237,12 +245,12 @@ impl VCpu {
|
|||||||
rights.set_granularity_raw(Granularity::KByte as u8);
|
rights.set_granularity_raw(Granularity::KByte as u8);
|
||||||
rights.set_long(true);
|
rights.set_long(true);
|
||||||
rights.set_db(false);
|
rights.set_db(false);
|
||||||
|
|
||||||
rights
|
rights
|
||||||
};
|
};
|
||||||
vmwrite(vmcs::guest::CS_ACCESS_RIGHTS, cs_rights.0 as u64)?;
|
|
||||||
|
|
||||||
let ds_rights = {
|
let ds_right = {
|
||||||
let mut rights = SegmentRights(0);
|
let mut rights = SegmentRights::default();
|
||||||
rights.set_rw(true);
|
rights.set_rw(true);
|
||||||
rights.set_dc(false);
|
rights.set_dc(false);
|
||||||
rights.set_executable(false);
|
rights.set_executable(false);
|
||||||
@ -251,12 +259,12 @@ impl VCpu {
|
|||||||
rights.set_granularity_raw(Granularity::KByte as u8);
|
rights.set_granularity_raw(Granularity::KByte as u8);
|
||||||
rights.set_long(false);
|
rights.set_long(false);
|
||||||
rights.set_db(true);
|
rights.set_db(true);
|
||||||
|
|
||||||
rights
|
rights
|
||||||
};
|
};
|
||||||
vmwrite(vmcs::guest::DS_ACCESS_RIGHTS, ds_rights.0 as u64)?;
|
|
||||||
|
|
||||||
let tr_rights = {
|
let tr_right = {
|
||||||
let mut rights = SegmentRights(0);
|
let mut rights = SegmentRights::default();
|
||||||
rights.set_rw(true);
|
rights.set_rw(true);
|
||||||
rights.set_dc(false);
|
rights.set_dc(false);
|
||||||
rights.set_executable(true);
|
rights.set_executable(true);
|
||||||
@ -265,12 +273,12 @@ impl VCpu {
|
|||||||
rights.set_granularity_raw(Granularity::Byte as u8);
|
rights.set_granularity_raw(Granularity::Byte as u8);
|
||||||
rights.set_long(false);
|
rights.set_long(false);
|
||||||
rights.set_db(false);
|
rights.set_db(false);
|
||||||
|
|
||||||
rights
|
rights
|
||||||
};
|
};
|
||||||
vmwrite(vmcs::guest::TR_ACCESS_RIGHTS, tr_rights.0 as u64)?;
|
|
||||||
|
|
||||||
let ldtr_rights = {
|
let ldtr_right = {
|
||||||
let mut rights = SegmentRights(0);
|
let mut rights = SegmentRights::default();
|
||||||
rights.set_accessed(false);
|
rights.set_accessed(false);
|
||||||
rights.set_rw(true);
|
rights.set_rw(true);
|
||||||
rights.set_dc(false);
|
rights.set_dc(false);
|
||||||
@ -280,9 +288,18 @@ impl VCpu {
|
|||||||
rights.set_granularity_raw(Granularity::Byte as u8);
|
rights.set_granularity_raw(Granularity::Byte as u8);
|
||||||
rights.set_long(false);
|
rights.set_long(false);
|
||||||
rights.set_db(false);
|
rights.set_db(false);
|
||||||
|
|
||||||
rights
|
rights
|
||||||
};
|
};
|
||||||
vmwrite(vmcs::guest::LDTR_ACCESS_RIGHTS, ldtr_rights.0 as u64)?;
|
|
||||||
|
vmwrite(vmcs::guest::CS_ACCESS_RIGHTS, cs_right.0 as u64)?;
|
||||||
|
vmwrite(vmcs::guest::SS_ACCESS_RIGHTS, ds_right.0 as u64)?;
|
||||||
|
vmwrite(vmcs::guest::DS_ACCESS_RIGHTS, ds_right.0 as u64)?;
|
||||||
|
vmwrite(vmcs::guest::ES_ACCESS_RIGHTS, ds_right.0 as u64)?;
|
||||||
|
vmwrite(vmcs::guest::FS_ACCESS_RIGHTS, ds_right.0 as u64)?;
|
||||||
|
vmwrite(vmcs::guest::GS_ACCESS_RIGHTS, ds_right.0 as u64)?;
|
||||||
|
vmwrite(vmcs::guest::TR_ACCESS_RIGHTS, tr_right.0 as u64)?;
|
||||||
|
vmwrite(vmcs::guest::LDTR_ACCESS_RIGHTS, ldtr_right.0 as u64)?;
|
||||||
|
|
||||||
info!("RIP: {:#x}", Self::guest as u64);
|
info!("RIP: {:#x}", Self::guest as u64);
|
||||||
vmwrite(vmcs::guest::RIP, Self::guest as u64)?;
|
vmwrite(vmcs::guest::RIP, Self::guest as u64)?;
|
||||||
@ -299,23 +316,41 @@ impl VCpu {
|
|||||||
self.vmcs.reset()
|
self.vmcs.reset()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn guest_fn() -> ! {
|
|
||||||
loop {
|
|
||||||
unsafe {
|
|
||||||
halt();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[naked]
|
#[naked]
|
||||||
unsafe extern "C" fn guest() -> ! {
|
unsafe extern "C" fn guest() -> ! {
|
||||||
naked_asm!("hlt");
|
naked_asm!("2: hlt; jmp 2b");
|
||||||
//naked_asm!("call {guest_fn}", guest_fn = sym Self::guest_fn);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn vmexit_handler(&mut self) -> ! {
|
fn vmexit_handler(&mut self) -> ! {
|
||||||
info!("VMExit occurred");
|
info!("VMExit occurred");
|
||||||
|
|
||||||
|
let raw_info = unsafe { vmread(vmcs::ro::EXIT_REASON) }.unwrap();
|
||||||
|
info!("VMExit reason: {:#b}", raw_info);
|
||||||
|
|
||||||
|
let info = VmxExitInfo::read();
|
||||||
|
|
||||||
|
if info.entry_failure() {
|
||||||
|
let reason = info.0 & 0xFF;
|
||||||
|
match reason {
|
||||||
|
33 => {
|
||||||
|
info!(" Reason: VM-entry failure due to invalid guest state");
|
||||||
|
}
|
||||||
|
34 => {
|
||||||
|
info!(" Reason: VM-entry failure due to MSR loading");
|
||||||
|
}
|
||||||
|
41 => {
|
||||||
|
info!(" Reason: VM-entry failure due to machine-check event");
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
info!(
|
||||||
|
" Reason: {:?} ({})",
|
||||||
|
info.get_reason().as_str(),
|
||||||
|
info.basic_reason()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
unsafe { halt() };
|
unsafe { halt() };
|
||||||
}
|
}
|
||||||
|
218
src/vmm/vmcs.rs
218
src/vmm/vmcs.rs
@ -1,6 +1,9 @@
|
|||||||
#![allow(non_camel_case_types)]
|
#![allow(non_camel_case_types)]
|
||||||
|
|
||||||
|
use core::convert::TryInto;
|
||||||
|
|
||||||
use bitfield::{bitfield, BitMut};
|
use bitfield::{bitfield, BitMut};
|
||||||
|
use numeric_enum_macro::numeric_enum;
|
||||||
use x86::{bits64::vmx, vmx::VmFail};
|
use x86::{bits64::vmx, vmx::VmFail};
|
||||||
use x86_64::structures::paging::{FrameAllocator, PhysFrame};
|
use x86_64::structures::paging::{FrameAllocator, PhysFrame};
|
||||||
|
|
||||||
@ -244,6 +247,19 @@ bitfield! {
|
|||||||
pub unusable, set_unusable: 16;
|
pub unusable, set_unusable: 16;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Default for SegmentRights {
|
||||||
|
fn default() -> Self {
|
||||||
|
let mut rights = SegmentRights(0);
|
||||||
|
rights.set_accessed(true);
|
||||||
|
rights.set_present(true);
|
||||||
|
rights.set_avl(false);
|
||||||
|
rights.set_long(false);
|
||||||
|
rights.set_unusable(false);
|
||||||
|
|
||||||
|
rights
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bitfield! {
|
bitfield! {
|
||||||
pub struct EntryControls(u32);
|
pub struct EntryControls(u32);
|
||||||
impl Debug;
|
impl Debug;
|
||||||
@ -357,3 +373,205 @@ pub enum VmcsReadOnlyData32 {
|
|||||||
VM_EXIT_INSTRUCTION_INFO = 0x0000440E,
|
VM_EXIT_INSTRUCTION_INFO = 0x0000440E,
|
||||||
}
|
}
|
||||||
vmcs_read!(VmcsReadOnlyData32, u32);
|
vmcs_read!(VmcsReadOnlyData32, u32);
|
||||||
|
|
||||||
|
numeric_enum! {
|
||||||
|
#[repr(u16)]
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
|
pub enum VmxExitReason {
|
||||||
|
EXCEPTION = 0,
|
||||||
|
EXTERNAL_INTERRUPT = 1,
|
||||||
|
TRIPLE_FAULT = 2,
|
||||||
|
INIT = 3,
|
||||||
|
SIPI = 4,
|
||||||
|
IO_SMI = 5,
|
||||||
|
OTHER_SMI = 6,
|
||||||
|
INTERRUPT_WINDOW = 7,
|
||||||
|
NMI_WINDOW = 8,
|
||||||
|
TASK_SWITCH = 9,
|
||||||
|
CPUID = 10,
|
||||||
|
GETSEC = 11,
|
||||||
|
HLT = 12,
|
||||||
|
INVD = 13,
|
||||||
|
INVLPG = 14,
|
||||||
|
RDPMC = 15,
|
||||||
|
RDTSC = 16,
|
||||||
|
RSM = 17,
|
||||||
|
VMCALL = 18,
|
||||||
|
VMCLEAR = 19,
|
||||||
|
VMLAUNCH = 20,
|
||||||
|
VMPTRLD = 21,
|
||||||
|
VMPTRST = 22,
|
||||||
|
VMREAD = 23,
|
||||||
|
VMRESUME = 24,
|
||||||
|
VMWRITE = 25,
|
||||||
|
VMXOFF = 26,
|
||||||
|
VMXON = 27,
|
||||||
|
CONTROL_REGISTER_ACCESSES = 28,
|
||||||
|
MOV_DR = 29,
|
||||||
|
IO_INSTRUCTION = 30,
|
||||||
|
RDMSR = 31,
|
||||||
|
WRMSR = 32,
|
||||||
|
VM_ENTRY_FAILURE_INVALID_GUEST_STATE = 33,
|
||||||
|
VM_ENTRY_FAILURE_MSR_LOADING = 34,
|
||||||
|
MWAIT = 36,
|
||||||
|
MONITOR_TRAP_FLAG = 37,
|
||||||
|
MONITOR = 39,
|
||||||
|
PAUSE = 40,
|
||||||
|
VM_ENTRY_FAILURE_MACHINE_CHECK_EVENT = 41,
|
||||||
|
TPR_BELOW_THRESHOLD = 43,
|
||||||
|
APIC_ACCESS = 44,
|
||||||
|
VIRTUALIZED_EOI = 45,
|
||||||
|
ACCESS_TO_GDTR_OR_IDTR = 46,
|
||||||
|
ACCESS_TO_LDTR_OR_TR = 47,
|
||||||
|
EPT_VIOLATION = 48,
|
||||||
|
EPT_MISCONFIGURATION = 49,
|
||||||
|
INVEPT = 50,
|
||||||
|
RDTSCP = 51,
|
||||||
|
VMX_PREEMPTION_TIMER_EXPIRED = 52,
|
||||||
|
INVVPID = 53,
|
||||||
|
WBINVD = 54,
|
||||||
|
XSETBV = 55,
|
||||||
|
APIC_WRITE = 56,
|
||||||
|
RDRAND = 57,
|
||||||
|
INVPCID = 58,
|
||||||
|
VMFUNC = 59,
|
||||||
|
ENCLS = 60,
|
||||||
|
RDSEED = 61,
|
||||||
|
PAGE_MODIFICATION_LOG_FULL = 62,
|
||||||
|
XSAVES = 63,
|
||||||
|
XRSTORS = 64,
|
||||||
|
PCONFIG = 65,
|
||||||
|
SPP_RELATED_EVENT = 66,
|
||||||
|
UMWAIT = 67,
|
||||||
|
TPAUSE = 68,
|
||||||
|
LOADIWKEY = 69,
|
||||||
|
ENCLV = 70,
|
||||||
|
ENQCMD_PASID_TRANSLATION_FAILURE = 72,
|
||||||
|
ENQCMDS_PASID_TRANSLATION_FAILURE = 73,
|
||||||
|
BUS_LOCK = 74,
|
||||||
|
INSTRUCTION_TIMEOUT = 75,
|
||||||
|
SEAMCALL = 76,
|
||||||
|
TDCALL = 77,
|
||||||
|
RDMSRLIST = 78,
|
||||||
|
WRMSRLIST = 79,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VmxExitReason {
|
||||||
|
pub fn read() -> Self {
|
||||||
|
let reason = VmcsReadOnlyData32::VM_EXIT_REASON.read();
|
||||||
|
if reason.is_err() {
|
||||||
|
panic!("Failed to read VM exit reason");
|
||||||
|
}
|
||||||
|
|
||||||
|
(reason.unwrap() as u16).try_into().unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_str(&self) -> &'static str {
|
||||||
|
use VmxExitReason::*;
|
||||||
|
match self {
|
||||||
|
EXCEPTION => "Exception or non-maskable interrupt (NMI)",
|
||||||
|
EXTERNAL_INTERRUPT => "External interrupt",
|
||||||
|
TRIPLE_FAULT => "Triple fault",
|
||||||
|
INIT => "INIT signal",
|
||||||
|
SIPI => "Start-up IPI (SIPI)",
|
||||||
|
IO_SMI => "I/O system-management interrupt (SMI)",
|
||||||
|
OTHER_SMI => "Other SMI",
|
||||||
|
INTERRUPT_WINDOW => "Interrupt window",
|
||||||
|
NMI_WINDOW => "NMI window",
|
||||||
|
TASK_SWITCH => "Task switch",
|
||||||
|
CPUID => "CPUID instruction execution",
|
||||||
|
GETSEC => "GETSEC instruction execution",
|
||||||
|
HLT => "HLT instruction execution",
|
||||||
|
INVD => "INVD instruction execution",
|
||||||
|
INVLPG => "INVLPG instruction execution",
|
||||||
|
RDPMC => "RDPMC instruction execution",
|
||||||
|
RDTSC => "RDTSC instruction execution",
|
||||||
|
RSM => "RSM instruction execution in SMM",
|
||||||
|
VMCALL => "VMCALL instruction execution",
|
||||||
|
VMCLEAR => "VMCLEAR instruction execution",
|
||||||
|
VMLAUNCH => "VMLAUNCH instruction execution",
|
||||||
|
VMPTRLD => "VMPTRLD instruction execution",
|
||||||
|
VMPTRST => "VMPTRST instruction execution",
|
||||||
|
VMREAD => "VMREAD instruction execution",
|
||||||
|
VMRESUME => "VMRESUME instruction execution",
|
||||||
|
VMWRITE => "VMWRITE instruction execution",
|
||||||
|
VMXOFF => "VMXOFF instruction execution",
|
||||||
|
VMXON => "VMXON instruction execution",
|
||||||
|
CONTROL_REGISTER_ACCESSES => "Control-register accesses",
|
||||||
|
MOV_DR => "MOV to or from debug registers",
|
||||||
|
IO_INSTRUCTION => "I/O instruction execution",
|
||||||
|
RDMSR => "RDMSR instruction execution",
|
||||||
|
WRMSR => "WRMSR or WRMSRNS instruction execution",
|
||||||
|
VM_ENTRY_FAILURE_INVALID_GUEST_STATE => "VM-entry failure due to invalid guest state",
|
||||||
|
VM_ENTRY_FAILURE_MSR_LOADING => "VM-entry failure due to MSR loading",
|
||||||
|
MWAIT => "MWAIT instruction execution",
|
||||||
|
MONITOR_TRAP_FLAG => "Monitor trap flag",
|
||||||
|
MONITOR => "MONITOR instruction execution",
|
||||||
|
PAUSE => "PAUSE instruction execution",
|
||||||
|
VM_ENTRY_FAILURE_MACHINE_CHECK_EVENT => "VM-entry failure due to machine-check event",
|
||||||
|
TPR_BELOW_THRESHOLD => "TPR below threshold",
|
||||||
|
APIC_ACCESS => "APIC access",
|
||||||
|
VIRTUALIZED_EOI => "Virtualized EOI",
|
||||||
|
ACCESS_TO_GDTR_OR_IDTR => "Access to GDTR or IDTR",
|
||||||
|
ACCESS_TO_LDTR_OR_TR => "Access to LDTR or TR",
|
||||||
|
EPT_VIOLATION => "EPT violation",
|
||||||
|
EPT_MISCONFIGURATION => "EPT misconfiguration",
|
||||||
|
INVEPT => "INVEPT instruction execution",
|
||||||
|
RDTSCP => "RDTSCP instruction execution",
|
||||||
|
VMX_PREEMPTION_TIMER_EXPIRED => "VMX-preemption timer expired",
|
||||||
|
INVVPID => "INVVPID instruction execution",
|
||||||
|
WBINVD => "WBINVD or WBNOINVD instruction execution",
|
||||||
|
XSETBV => "XSETBV instruction execution",
|
||||||
|
APIC_WRITE => "APIC write",
|
||||||
|
RDRAND => "RDRAND instruction execution",
|
||||||
|
INVPCID => "INVPCID instruction execution",
|
||||||
|
VMFUNC => "VMFUNC instruction execution",
|
||||||
|
ENCLS => "ENCLS instruction execution",
|
||||||
|
RDSEED => "RDSEED instruction execution",
|
||||||
|
PAGE_MODIFICATION_LOG_FULL => "Page-modification log full",
|
||||||
|
XSAVES => "XSAVES instruction execution",
|
||||||
|
XRSTORS => "XRSTORS instruction execution",
|
||||||
|
PCONFIG => "PCONFIG instruction execution",
|
||||||
|
SPP_RELATED_EVENT => "SPP-related event",
|
||||||
|
UMWAIT => "UMWAIT instruction execution",
|
||||||
|
TPAUSE => "TPAUSE instruction execution",
|
||||||
|
LOADIWKEY => "LOADIWKEY instruction execution",
|
||||||
|
ENCLV => "ENCLV instruction execution",
|
||||||
|
ENQCMD_PASID_TRANSLATION_FAILURE => "ENQCMD PASID translation failure",
|
||||||
|
ENQCMDS_PASID_TRANSLATION_FAILURE => "ENQCMDS PASID translation failure",
|
||||||
|
BUS_LOCK => "Bus lock",
|
||||||
|
INSTRUCTION_TIMEOUT => "Instruction timeout",
|
||||||
|
SEAMCALL => "SEAMCALL instruction execution",
|
||||||
|
TDCALL => "TDCALL instruction execution",
|
||||||
|
RDMSRLIST => "RDMSRLIST instruction execution",
|
||||||
|
WRMSRLIST => "WRMSRLIST instruction execution",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bitfield! {
|
||||||
|
pub struct VmxExitInfo(u32);
|
||||||
|
impl Debug;
|
||||||
|
|
||||||
|
pub u16, basic_reason, set_basic_reason: 15, 0;
|
||||||
|
pub pending_mtf, set_pending_mtf: 26;
|
||||||
|
pub exit_vmxroot, set_exit_vmxroot: 27;
|
||||||
|
pub entry_failure, set_entry_failure: 31;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VmxExitInfo {
|
||||||
|
pub fn read() -> Self {
|
||||||
|
let info = VmcsReadOnlyData32::VM_EXIT_REASON.read();
|
||||||
|
if info.is_err() {
|
||||||
|
panic!("Failed to read VM exit reason");
|
||||||
|
}
|
||||||
|
let info = info.unwrap();
|
||||||
|
Self(info)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_reason(&self) -> VmxExitReason {
|
||||||
|
let reason = self.basic_reason() as u16;
|
||||||
|
reason.try_into().unwrap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user