mirror of
https://github.com/mii443/nel_os.git
synced 2025-08-22 16:15:38 +00:00
AMD emulation
This commit is contained in:
@ -12,7 +12,11 @@ pub fn handle_cpuid_exit(vcpu: &mut VCpu) {
|
|||||||
b"miHypervisor"
|
b"miHypervisor"
|
||||||
};
|
};
|
||||||
|
|
||||||
let brand_string: &[u8; 48] = b"mii Hypervisor CPU on Intel VT-x \0";
|
let brand_string: &[u8; 48] = if vcpu.emulate_amd {
|
||||||
|
b"AMD EPYC 9965 192-Core Processor \0"
|
||||||
|
} else {
|
||||||
|
b"mii Hypervisor CPU on Intel VT-x \0"
|
||||||
|
};
|
||||||
|
|
||||||
let vendor = unsafe { core::mem::transmute::<&[u8; 12], &[u32; 3]>(vendor) };
|
let vendor = unsafe { core::mem::transmute::<&[u8; 12], &[u32; 3]>(vendor) };
|
||||||
let brand_string = unsafe { core::mem::transmute::<&[u8; 48], &[u32; 12]>(brand_string) };
|
let brand_string = unsafe { core::mem::transmute::<&[u8; 48], &[u32; 12]>(brand_string) };
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
info,
|
info,
|
||||||
vmm::{
|
vmm::{
|
||||||
|
invlpg::{invept_single_context, invvpid_individual_address},
|
||||||
vcpu::VCpu,
|
vcpu::VCpu,
|
||||||
vmcs::{DescriptorType, EntryControls, Granularity, SegmentRights},
|
vmcs::{DescriptorType, EntryControls, Granularity, SegmentRights},
|
||||||
},
|
},
|
||||||
@ -72,13 +73,9 @@ pub fn emulate_opcode(vcpu: &mut VCpu, instruction_bytes: [u8; 16], valid_bytes:
|
|||||||
pub fn handle_vmcall(vcpu: &mut VCpu, guest_phys_addr: u64) -> bool {
|
pub fn handle_vmcall(vcpu: &mut VCpu, guest_phys_addr: u64) -> bool {
|
||||||
if let Some(replaced_addr) = vcpu.opcode_emulator.replaced_address {
|
if let Some(replaced_addr) = vcpu.opcode_emulator.replaced_address {
|
||||||
if replaced_addr == guest_phys_addr {
|
if replaced_addr == guest_phys_addr {
|
||||||
info!("Handling VMCall at {:#x}", guest_phys_addr);
|
|
||||||
|
|
||||||
match vcpu.opcode_emulator.vmcall_control {
|
match vcpu.opcode_emulator.vmcall_control {
|
||||||
Some(VmcallControl::ReturnTo32Bit) => {
|
Some(VmcallControl::ReturnTo32Bit) => {
|
||||||
if return_to_32_bit(vcpu) {
|
if !return_to_32_bit(vcpu) {
|
||||||
info!("Successfully returned to 32-bit mode.");
|
|
||||||
} else {
|
|
||||||
info!("Failed to return to 32-bit mode.");
|
info!("Failed to return to 32-bit mode.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -87,9 +84,7 @@ pub fn handle_vmcall(vcpu: &mut VCpu, guest_phys_addr: u64) -> bool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if restore_replaced_opcode(vcpu) {
|
if !restore_replaced_opcode(vcpu) {
|
||||||
info!("VMCall handled successfully, original opcode restored.");
|
|
||||||
} else {
|
|
||||||
info!("Failed to restore original opcode.");
|
info!("Failed to restore original opcode.");
|
||||||
}
|
}
|
||||||
// Clear saved selectors after handling
|
// Clear saved selectors after handling
|
||||||
@ -124,10 +119,24 @@ fn restore_replaced_opcode(vcpu: &mut VCpu) -> bool {
|
|||||||
}
|
}
|
||||||
vcpu.opcode_emulator.original_opcode = None;
|
vcpu.opcode_emulator.original_opcode = None;
|
||||||
vcpu.opcode_emulator.replaced_address = None;
|
vcpu.opcode_emulator.replaced_address = None;
|
||||||
info!(
|
|
||||||
"Restoring original opcode at {:#x}: {:?}",
|
// Invalidate TLB and EPT after modifying code
|
||||||
guest_phys_addr, original_opcode
|
unsafe {
|
||||||
);
|
// Get EPTP for EPT invalidation
|
||||||
|
let eptp = vmread(vmcs::control::EPTP_FULL).unwrap();
|
||||||
|
let _ = invept_single_context(eptp); // Ignore errors
|
||||||
|
|
||||||
|
// Get VPID for TLB invalidation (if VPID is enabled)
|
||||||
|
let secondary_controls =
|
||||||
|
vmread(vmcs::control::SECONDARY_PROCBASED_EXEC_CONTROLS).unwrap();
|
||||||
|
if secondary_controls & (1 << 5) != 0 {
|
||||||
|
// VPID enabled
|
||||||
|
let vpid = vmread(vmcs::control::VPID).unwrap() as u16;
|
||||||
|
let rip = vmread(vmcs::guest::RIP).unwrap();
|
||||||
|
let _ = invvpid_individual_address(vpid, rip); // Ignore errors
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -153,17 +162,25 @@ fn replace_opcode(vcpu: &mut VCpu, instruction_bytes: [u8; 16], replace: &[u8])
|
|||||||
vcpu.ept.set(guest_phys_addr + i as u64, byte).unwrap();
|
vcpu.ept.set(guest_phys_addr + i as u64, byte).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
info!(
|
// Invalidate TLB and EPT after modifying code
|
||||||
"Replacing opcode with: {:?} at {:#x}",
|
unsafe {
|
||||||
replace, guest_phys_addr
|
// Get EPTP for EPT invalidation
|
||||||
);
|
let eptp = vmread(vmcs::control::EPTP_FULL).unwrap();
|
||||||
|
let _ = invept_single_context(eptp); // Ignore errors
|
||||||
|
|
||||||
|
// Get VPID for TLB invalidation (if VPID is enabled)
|
||||||
|
let secondary_controls = vmread(vmcs::control::SECONDARY_PROCBASED_EXEC_CONTROLS).unwrap();
|
||||||
|
if secondary_controls & (1 << 5) != 0 {
|
||||||
|
// VPID enabled
|
||||||
|
let vpid = vmread(vmcs::control::VPID).unwrap() as u16;
|
||||||
|
let _ = invvpid_individual_address(vpid, rip); // Ignore errors
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
fn return_to_32_bit(vcpu: &mut VCpu) -> bool {
|
fn return_to_32_bit(vcpu: &mut VCpu) -> bool {
|
||||||
// 32bitモードへ戻す処理
|
|
||||||
info!("Returning to 32-bit mode");
|
|
||||||
if !vcpu.emulate_amd {
|
if !vcpu.emulate_amd {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -229,9 +246,9 @@ fn return_to_32_bit(vcpu: &mut VCpu) -> bool {
|
|||||||
};
|
};
|
||||||
vmwrite(vmcs::guest::SS_ACCESS_RIGHTS, ss_rights.0 as u64).unwrap();
|
vmwrite(vmcs::guest::SS_ACCESS_RIGHTS, ss_rights.0 as u64).unwrap();
|
||||||
|
|
||||||
// Set 32-bit data segment selectors
|
// Set 32-bit data segment selectors - use same as SS for compatibility mode
|
||||||
vmwrite(vmcs::guest::DS_SELECTOR, 0).unwrap();
|
vmwrite(vmcs::guest::DS_SELECTOR, user_ss_selector as u64).unwrap();
|
||||||
vmwrite(vmcs::guest::ES_SELECTOR, 0).unwrap();
|
vmwrite(vmcs::guest::ES_SELECTOR, user_ss_selector as u64).unwrap();
|
||||||
vmwrite(vmcs::guest::FS_SELECTOR, 0).unwrap();
|
vmwrite(vmcs::guest::FS_SELECTOR, 0).unwrap();
|
||||||
|
|
||||||
// Restore GS selector and base
|
// Restore GS selector and base
|
||||||
@ -249,16 +266,16 @@ fn return_to_32_bit(vcpu: &mut VCpu) -> bool {
|
|||||||
vmwrite(vmcs::guest::ES_BASE, 0).unwrap();
|
vmwrite(vmcs::guest::ES_BASE, 0).unwrap();
|
||||||
vmwrite(vmcs::guest::FS_BASE, 0).unwrap();
|
vmwrite(vmcs::guest::FS_BASE, 0).unwrap();
|
||||||
|
|
||||||
// Set segment limits
|
// Set segment limits - 32-bit segments need proper limits
|
||||||
vmwrite(vmcs::guest::DS_LIMIT, 0).unwrap();
|
vmwrite(vmcs::guest::DS_LIMIT, 0xFFFFFFFF).unwrap();
|
||||||
vmwrite(vmcs::guest::ES_LIMIT, 0).unwrap();
|
vmwrite(vmcs::guest::ES_LIMIT, 0xFFFFFFFF).unwrap();
|
||||||
vmwrite(vmcs::guest::FS_LIMIT, 0).unwrap();
|
vmwrite(vmcs::guest::FS_LIMIT, 0).unwrap();
|
||||||
vmwrite(vmcs::guest::GS_LIMIT, 0xFFFFFFFF).unwrap();
|
vmwrite(vmcs::guest::GS_LIMIT, 0xFFFFFFFF).unwrap();
|
||||||
|
|
||||||
// Set segment access rights for null segments (unusable)
|
// Set segment access rights for data segments (same as SS)
|
||||||
|
vmwrite(vmcs::guest::DS_ACCESS_RIGHTS, ss_rights.0 as u64).unwrap();
|
||||||
|
vmwrite(vmcs::guest::ES_ACCESS_RIGHTS, ss_rights.0 as u64).unwrap();
|
||||||
let null_rights = 0x10000; // Unusable bit set
|
let null_rights = 0x10000; // Unusable bit set
|
||||||
vmwrite(vmcs::guest::DS_ACCESS_RIGHTS, null_rights).unwrap();
|
|
||||||
vmwrite(vmcs::guest::ES_ACCESS_RIGHTS, null_rights).unwrap();
|
|
||||||
vmwrite(vmcs::guest::FS_ACCESS_RIGHTS, null_rights).unwrap();
|
vmwrite(vmcs::guest::FS_ACCESS_RIGHTS, null_rights).unwrap();
|
||||||
|
|
||||||
// Set GS access rights for 32-bit data segment
|
// Set GS access rights for 32-bit data segment
|
||||||
@ -278,16 +295,6 @@ fn return_to_32_bit(vcpu: &mut VCpu) -> bool {
|
|||||||
};
|
};
|
||||||
vmwrite(vmcs::guest::GS_ACCESS_RIGHTS, gs_rights).unwrap();
|
vmwrite(vmcs::guest::GS_ACCESS_RIGHTS, gs_rights).unwrap();
|
||||||
|
|
||||||
info!("Restoring user mode segments:");
|
|
||||||
info!(" CS: selector={:#x} -> {:#x}, base={:#x} -> {:#x}, limit={:#x} -> {:#x}, rights={:#x} -> {:#x}",
|
|
||||||
current_cs_val, user_cs_selector, current_cs_base, 0, current_cs_limit, 0xFFFFFFFFu64, current_cs_rights, cs_rights.0);
|
|
||||||
info!(" SS: selector={:#x} -> {:#x}, base={:#x} -> {:#x}, limit={:#x} -> {:#x}, rights={:#x} -> {:#x}",
|
|
||||||
current_ss_val, user_ss_selector, current_ss_base, 0, current_ss_limit, 0xFFFFFFFFu64, current_ss_rights, ss_rights.0);
|
|
||||||
info!(
|
|
||||||
" GS: selector={:#x} -> {:#x}, base={:#x} -> {:#x}",
|
|
||||||
current_gs_val, gs_selector, current_gs_base, gs_base
|
|
||||||
);
|
|
||||||
|
|
||||||
// Ensure CR0, CR4, and EFER are properly set for compatibility mode
|
// Ensure CR0, CR4, and EFER are properly set for compatibility mode
|
||||||
let mut cr0 = vmread(vmcs::guest::CR0).unwrap();
|
let mut cr0 = vmread(vmcs::guest::CR0).unwrap();
|
||||||
cr0 |= (1 << 31) | (1 << 0); // PG and PE bits
|
cr0 |= (1 << 31) | (1 << 0); // PG and PE bits
|
||||||
@ -305,28 +312,12 @@ fn return_to_32_bit(vcpu: &mut VCpu) -> bool {
|
|||||||
// Only the CS.L bit determines if we're in compatibility mode
|
// Only the CS.L bit determines if we're in compatibility mode
|
||||||
|
|
||||||
// Log guest registers that might be important
|
// Log guest registers that might be important
|
||||||
info!(
|
|
||||||
"Restored to user mode: RIP={:#x}, RFLAGS={:#x}, CS={:#x}, SS={:#x}, GS={:#x}, GS_BASE={:#x}",
|
|
||||||
return_rip + 2,
|
|
||||||
return_rflags,
|
|
||||||
user_cs_selector,
|
|
||||||
user_ss_selector,
|
|
||||||
gs_selector,
|
|
||||||
gs_base
|
|
||||||
);
|
|
||||||
info!("Guest registers: RAX={:#x}, RCX={:#x}, RDX={:#x}, RSI={:#x}, RDI={:#x}",
|
|
||||||
vcpu.guest_registers.rax,
|
|
||||||
vcpu.guest_registers.rcx,
|
|
||||||
vcpu.guest_registers.rdx,
|
|
||||||
vcpu.guest_registers.rsi,
|
|
||||||
vcpu.guest_registers.rdi);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
fn emulate_syscall(vcpu: &mut VCpu, instruction_bytes: [u8; 16]) -> bool {
|
fn emulate_syscall(vcpu: &mut VCpu, instruction_bytes: [u8; 16]) -> bool {
|
||||||
info!("Emulating SYSCALL instruction");
|
|
||||||
if !vcpu.emulate_amd {
|
if !vcpu.emulate_amd {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -355,20 +346,6 @@ fn emulate_syscall(vcpu: &mut VCpu, instruction_bytes: [u8; 16]) -> bool {
|
|||||||
let current_gs_limit = unsafe { vmread(vmcs::guest::GS_LIMIT).unwrap() };
|
let current_gs_limit = unsafe { vmread(vmcs::guest::GS_LIMIT).unwrap() };
|
||||||
let current_gs_rights = unsafe { vmread(vmcs::guest::GS_ACCESS_RIGHTS).unwrap() };
|
let current_gs_rights = unsafe { vmread(vmcs::guest::GS_ACCESS_RIGHTS).unwrap() };
|
||||||
|
|
||||||
info!("Current segments before SYSCALL:");
|
|
||||||
info!(
|
|
||||||
" CS: selector={:#x}, base={:#x}, limit={:#x}, rights={:#x}",
|
|
||||||
current_cs, current_cs_base, current_cs_limit, current_cs_rights
|
|
||||||
);
|
|
||||||
info!(
|
|
||||||
" SS: selector={:#x}, base={:#x}, limit={:#x}, rights={:#x}",
|
|
||||||
current_ss, current_ss_base, current_ss_limit, current_ss_rights
|
|
||||||
);
|
|
||||||
info!(
|
|
||||||
" GS: selector={:#x}, base={:#x}, limit={:#x}, rights={:#x}",
|
|
||||||
current_gs, current_gs_base, current_gs_limit, current_gs_rights
|
|
||||||
);
|
|
||||||
|
|
||||||
vcpu.opcode_emulator.saved_cs_selector = Some(current_cs);
|
vcpu.opcode_emulator.saved_cs_selector = Some(current_cs);
|
||||||
vcpu.opcode_emulator.saved_ss_selector = Some(current_ss);
|
vcpu.opcode_emulator.saved_ss_selector = Some(current_ss);
|
||||||
vcpu.opcode_emulator.saved_gs_selector = Some(current_gs);
|
vcpu.opcode_emulator.saved_gs_selector = Some(current_gs);
|
||||||
@ -407,17 +384,6 @@ fn emulate_syscall(vcpu: &mut VCpu, instruction_bytes: [u8; 16]) -> bool {
|
|||||||
rights
|
rights
|
||||||
};
|
};
|
||||||
|
|
||||||
info!("Setting RIP:{:x} to {:x}", current_rip, lstar);
|
|
||||||
info!("Setting kernel segments for SYSCALL:");
|
|
||||||
info!(
|
|
||||||
" CS: selector={:#x} -> {:#x}, base=0 -> 0, limit={:#x} -> {:#x}, rights={:#x} -> {:#x}",
|
|
||||||
current_cs, cs_selector, current_cs_limit, 0xFFFFFFFFu64, current_cs_rights, cs_rights.0
|
|
||||||
);
|
|
||||||
info!(
|
|
||||||
" SS: selector={:#x} -> {:#x}, base=0 -> 0, limit={:#x} -> {:#x}, rights={:#x} -> {:#x}",
|
|
||||||
current_ss, ss_selector, current_ss_limit, 0xFFFFFFFFu64, current_ss_rights, ss_rights.0
|
|
||||||
);
|
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
// Set segment registers for kernel mode
|
// Set segment registers for kernel mode
|
||||||
vmwrite(vmcs::guest::RIP, lstar).unwrap();
|
vmwrite(vmcs::guest::RIP, lstar).unwrap();
|
||||||
|
105
src/vmm/invlpg.rs
Normal file
105
src/vmm/invlpg.rs
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
use core::arch::asm;
|
||||||
|
use x86_64::PhysAddr;
|
||||||
|
|
||||||
|
#[repr(C, packed)]
|
||||||
|
pub struct InveptDesc {
|
||||||
|
eptp: u64,
|
||||||
|
reserved: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C, packed)]
|
||||||
|
pub struct InvvpidDesc {
|
||||||
|
vpid: u16,
|
||||||
|
reserved1: u16,
|
||||||
|
reserved2: u32,
|
||||||
|
linear_address: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const INVEPT_TYPE_SINGLE_CONTEXT: u64 = 1;
|
||||||
|
pub const INVEPT_TYPE_ALL_CONTEXT: u64 = 2;
|
||||||
|
|
||||||
|
pub const INVVPID_TYPE_INDIVIDUAL_ADDRESS: u64 = 0;
|
||||||
|
pub const INVVPID_TYPE_SINGLE_CONTEXT: u64 = 1;
|
||||||
|
pub const INVVPID_TYPE_ALL_CONTEXT: u64 = 2;
|
||||||
|
pub const INVVPID_TYPE_SINGLE_CONTEXT_RETAINING_GLOBALS: u64 = 3;
|
||||||
|
|
||||||
|
/// Invalidate EPT entries
|
||||||
|
pub unsafe fn invept(invept_type: u64, eptp: u64) -> Result<(), &'static str> {
|
||||||
|
let desc = InveptDesc {
|
||||||
|
eptp,
|
||||||
|
reserved: 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut error: u64;
|
||||||
|
asm!(
|
||||||
|
"xor {0}, {0}",
|
||||||
|
"invept {1}, [{2}]",
|
||||||
|
"jnc 2f",
|
||||||
|
"mov {0}, 1",
|
||||||
|
"2:",
|
||||||
|
inout(reg) 0u64 => error,
|
||||||
|
in(reg) invept_type,
|
||||||
|
in(reg) &desc as *const _ as u64,
|
||||||
|
options(nostack)
|
||||||
|
);
|
||||||
|
|
||||||
|
if error == 0 {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err("INVEPT failed")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Invalidate VPID entries
|
||||||
|
pub unsafe fn invvpid(invvpid_type: u64, vpid: u16, linear_address: u64) -> Result<(), &'static str> {
|
||||||
|
let desc = InvvpidDesc {
|
||||||
|
vpid,
|
||||||
|
reserved1: 0,
|
||||||
|
reserved2: 0,
|
||||||
|
linear_address,
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut error: u64;
|
||||||
|
asm!(
|
||||||
|
"xor {0}, {0}",
|
||||||
|
"invvpid {1}, [{2}]",
|
||||||
|
"jnc 2f",
|
||||||
|
"mov {0}, 1",
|
||||||
|
"2:",
|
||||||
|
inout(reg) 0u64 => error,
|
||||||
|
in(reg) invvpid_type,
|
||||||
|
in(reg) &desc as *const _ as u64,
|
||||||
|
options(nostack)
|
||||||
|
);
|
||||||
|
|
||||||
|
if error == 0 {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err("INVVPID failed")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Invalidate all EPT entries for a specific EPTP
|
||||||
|
pub unsafe fn invept_single_context(eptp: u64) -> Result<(), &'static str> {
|
||||||
|
invept(INVEPT_TYPE_SINGLE_CONTEXT, eptp)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Invalidate all EPT entries for all contexts
|
||||||
|
pub unsafe fn invept_all_contexts() -> Result<(), &'static str> {
|
||||||
|
invept(INVEPT_TYPE_ALL_CONTEXT, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Invalidate all TLB entries for a specific VPID
|
||||||
|
pub unsafe fn invvpid_single_context(vpid: u16) -> Result<(), &'static str> {
|
||||||
|
invvpid(INVVPID_TYPE_SINGLE_CONTEXT, vpid, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Invalidate all TLB entries for all VPIDs
|
||||||
|
pub unsafe fn invvpid_all_contexts() -> Result<(), &'static str> {
|
||||||
|
invvpid(INVVPID_TYPE_ALL_CONTEXT, 0, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Invalidate a specific linear address for a specific VPID
|
||||||
|
pub unsafe fn invvpid_individual_address(vpid: u16, linear_address: u64) -> Result<(), &'static str> {
|
||||||
|
invvpid(INVVPID_TYPE_INDIVIDUAL_ADDRESS, vpid, linear_address)
|
||||||
|
}
|
@ -5,6 +5,7 @@ pub mod emulation;
|
|||||||
pub mod ept;
|
pub mod ept;
|
||||||
pub mod error;
|
pub mod error;
|
||||||
pub mod fpu;
|
pub mod fpu;
|
||||||
|
pub mod invlpg;
|
||||||
pub mod io;
|
pub mod io;
|
||||||
pub mod linux;
|
pub mod linux;
|
||||||
pub mod msr;
|
pub mod msr;
|
||||||
|
@ -1017,6 +1017,12 @@ impl VCpu {
|
|||||||
if let Err(e) = self.ept.map_4k(gpa, hpa, frame_allocator) {
|
if let Err(e) = self.ept.map_4k(gpa, hpa, frame_allocator) {
|
||||||
panic!("Failed to map page at GPA {:#x}: {}", gpa, e);
|
panic!("Failed to map page at GPA {:#x}: {}", gpa, e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Invalidate EPT after mapping new page
|
||||||
|
// Note: INVEPT might not be available on all processors
|
||||||
|
use crate::vmm::invlpg::invept_single_context;
|
||||||
|
let eptp = vmread(vmcs::control::EPTP_FULL).unwrap();
|
||||||
|
let _ = invept_single_context(eptp); // Ignore errors as INVEPT might not be supported
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
panic!(
|
panic!(
|
||||||
@ -1054,6 +1060,48 @@ impl VCpu {
|
|||||||
match reason {
|
match reason {
|
||||||
33 => {
|
33 => {
|
||||||
info!(" Reason: VM-entry failure due to invalid guest state");
|
info!(" Reason: VM-entry failure due to invalid guest state");
|
||||||
|
// Read VM-instruction error for more details
|
||||||
|
let vm_instruction_error = unsafe {
|
||||||
|
use x86::msr::rdmsr;
|
||||||
|
vmread(vmcs::ro::VM_INSTRUCTION_ERROR).unwrap_or(0)
|
||||||
|
};
|
||||||
|
info!(" VM-instruction error: {}", vm_instruction_error);
|
||||||
|
|
||||||
|
// Dump guest state for debugging
|
||||||
|
unsafe {
|
||||||
|
info!(" Guest state dump:");
|
||||||
|
info!(" CS: selector={:#x}, base={:#x}, limit={:#x}, rights={:#x}",
|
||||||
|
vmread(vmcs::guest::CS_SELECTOR).unwrap(),
|
||||||
|
vmread(vmcs::guest::CS_BASE).unwrap(),
|
||||||
|
vmread(vmcs::guest::CS_LIMIT).unwrap(),
|
||||||
|
vmread(vmcs::guest::CS_ACCESS_RIGHTS).unwrap());
|
||||||
|
info!(" SS: selector={:#x}, base={:#x}, limit={:#x}, rights={:#x}",
|
||||||
|
vmread(vmcs::guest::SS_SELECTOR).unwrap(),
|
||||||
|
vmread(vmcs::guest::SS_BASE).unwrap(),
|
||||||
|
vmread(vmcs::guest::SS_LIMIT).unwrap(),
|
||||||
|
vmread(vmcs::guest::SS_ACCESS_RIGHTS).unwrap());
|
||||||
|
info!(" DS: selector={:#x}, base={:#x}, limit={:#x}, rights={:#x}",
|
||||||
|
vmread(vmcs::guest::DS_SELECTOR).unwrap(),
|
||||||
|
vmread(vmcs::guest::DS_BASE).unwrap(),
|
||||||
|
vmread(vmcs::guest::DS_LIMIT).unwrap(),
|
||||||
|
vmread(vmcs::guest::DS_ACCESS_RIGHTS).unwrap());
|
||||||
|
info!(" ES: selector={:#x}, base={:#x}, limit={:#x}, rights={:#x}",
|
||||||
|
vmread(vmcs::guest::ES_SELECTOR).unwrap(),
|
||||||
|
vmread(vmcs::guest::ES_BASE).unwrap(),
|
||||||
|
vmread(vmcs::guest::ES_LIMIT).unwrap(),
|
||||||
|
vmread(vmcs::guest::ES_ACCESS_RIGHTS).unwrap());
|
||||||
|
info!(" RIP={:#x}, RSP={:#x}, RFLAGS={:#x}",
|
||||||
|
vmread(vmcs::guest::RIP).unwrap(),
|
||||||
|
vmread(vmcs::guest::RSP).unwrap(),
|
||||||
|
vmread(vmcs::guest::RFLAGS).unwrap());
|
||||||
|
info!(" CR0={:#x}, CR3={:#x}, CR4={:#x}",
|
||||||
|
vmread(vmcs::guest::CR0).unwrap(),
|
||||||
|
vmread(vmcs::guest::CR3).unwrap(),
|
||||||
|
vmread(vmcs::guest::CR4).unwrap());
|
||||||
|
info!(" EFER={:#x}",
|
||||||
|
vmread(vmcs::guest::IA32_EFER_FULL).unwrap());
|
||||||
|
}
|
||||||
|
panic!("VM-entry failure due to invalid guest state");
|
||||||
}
|
}
|
||||||
34 => {
|
34 => {
|
||||||
info!(" Reason: VM-entry failure due to MSR loading");
|
info!(" Reason: VM-entry failure due to MSR loading");
|
||||||
|
Reference in New Issue
Block a user