This commit is contained in:
Masato Imai
2025-07-14 09:02:03 +00:00
parent f47315cda8
commit f67b0b7477
8 changed files with 81 additions and 37 deletions

BIN
bzImage

Binary file not shown.

View File

@ -1,4 +1,3 @@
use crate::info;
use raw_cpuid::cpuid; use raw_cpuid::cpuid;
use super::{vcpu::VCpu, vmcs::VmxLeaf}; use super::{vcpu::VCpu, vmcs::VmxLeaf};
@ -95,6 +94,9 @@ pub fn handle_cpuid_exit(vcpu: &mut VCpu) {
regs.rax = 0x00000000; regs.rax = 0x00000000;
regs.rbx = 0x00000000; regs.rbx = 0x00000000;
regs.rcx = signature.ecx as u64; regs.rcx = signature.ecx as u64;
if vcpu.emulate_amd {
regs.rcx |= 1 << 2; // SVM
}
regs.rdx = signature.edx as u64; regs.rdx = signature.edx as u64;
} }
VmxLeaf::EXTENDED_FUNCTION => { VmxLeaf::EXTENDED_FUNCTION => {

View File

@ -7,7 +7,6 @@ use crate::{
}, },
}; };
use alloc::vec; use alloc::vec;
use alloc::vec::Vec;
use x86::current::vmx::{vmread, vmwrite}; use x86::current::vmx::{vmread, vmwrite};
use x86::vmx::vmcs; use x86::vmx::vmcs;
@ -31,7 +30,7 @@ pub struct OpcodeEmulator {
pub saved_rsp: Option<u64>, pub saved_rsp: Option<u64>,
} }
enum VmcallControl { pub enum VmcallControl {
ReturnTo32Bit, ReturnTo32Bit,
} }
@ -144,6 +143,10 @@ fn restore_replaced_opcode(vcpu: &mut VCpu) -> bool {
} }
fn replace_opcode(vcpu: &mut VCpu, instruction_bytes: [u8; 16], replace: &[u8]) -> bool { fn replace_opcode(vcpu: &mut VCpu, instruction_bytes: [u8; 16], replace: &[u8]) -> bool {
let rip = unsafe { vmread(vmcs::guest::RIP).unwrap() };
let guest_phys_addr = vcpu.translate_guest_address(rip).unwrap();
info!("Replacing opcode at address: {:#x}", guest_phys_addr);
let replace_len = replace.len(); let replace_len = replace.len();
if replace_len > 16 { if replace_len > 16 {
return false; return false;
@ -152,8 +155,6 @@ fn replace_opcode(vcpu: &mut VCpu, instruction_bytes: [u8; 16], replace: &[u8])
let mut original_opcode = [0u8; 16]; let mut original_opcode = [0u8; 16];
original_opcode[..replace_len].copy_from_slice(&instruction_bytes[..replace_len]); original_opcode[..replace_len].copy_from_slice(&instruction_bytes[..replace_len]);
let rip = unsafe { vmread(vmcs::guest::RIP).unwrap() };
let guest_phys_addr = vcpu.translate_guest_address(rip).unwrap();
vcpu.opcode_emulator.original_opcode = Some(original_opcode); vcpu.opcode_emulator.original_opcode = Some(original_opcode);
vcpu.opcode_emulator.replaced_address = Some(guest_phys_addr); vcpu.opcode_emulator.replaced_address = Some(guest_phys_addr);
vcpu.opcode_emulator.replaced_size = Some(replace_len as u64); vcpu.opcode_emulator.replaced_size = Some(replace_len as u64);
@ -199,14 +200,14 @@ fn return_to_32_bit(vcpu: &mut VCpu) -> bool {
let user_ss_selector = vcpu.opcode_emulator.saved_ss_selector.unwrap_or(0x2b); let user_ss_selector = vcpu.opcode_emulator.saved_ss_selector.unwrap_or(0x2b);
// Read current values for logging // Read current values for logging
let current_cs_val = vmread(vmcs::guest::CS_SELECTOR).unwrap(); let _current_cs_val = vmread(vmcs::guest::CS_SELECTOR).unwrap();
let current_cs_base = vmread(vmcs::guest::CS_BASE).unwrap(); let _current_cs_base = vmread(vmcs::guest::CS_BASE).unwrap();
let current_cs_limit = vmread(vmcs::guest::CS_LIMIT).unwrap(); let _current_cs_limit = vmread(vmcs::guest::CS_LIMIT).unwrap();
let current_cs_rights = vmread(vmcs::guest::CS_ACCESS_RIGHTS).unwrap(); let _current_cs_rights = vmread(vmcs::guest::CS_ACCESS_RIGHTS).unwrap();
let current_ss_val = vmread(vmcs::guest::SS_SELECTOR).unwrap(); let _current_ss_val = vmread(vmcs::guest::SS_SELECTOR).unwrap();
let current_ss_base = vmread(vmcs::guest::SS_BASE).unwrap(); let _current_ss_base = vmread(vmcs::guest::SS_BASE).unwrap();
let current_ss_limit = vmread(vmcs::guest::SS_LIMIT).unwrap(); let _current_ss_limit = vmread(vmcs::guest::SS_LIMIT).unwrap();
let current_ss_rights = vmread(vmcs::guest::SS_ACCESS_RIGHTS).unwrap(); let _current_ss_rights = vmread(vmcs::guest::SS_ACCESS_RIGHTS).unwrap();
// Set CS for 32-bit compatibility mode // Set CS for 32-bit compatibility mode
vmwrite(vmcs::guest::CS_SELECTOR, user_cs_selector as u64).unwrap(); vmwrite(vmcs::guest::CS_SELECTOR, user_cs_selector as u64).unwrap();
@ -255,8 +256,8 @@ fn return_to_32_bit(vcpu: &mut VCpu) -> bool {
let gs_selector = vcpu.opcode_emulator.saved_gs_selector.unwrap_or(0); let gs_selector = vcpu.opcode_emulator.saved_gs_selector.unwrap_or(0);
let gs_base = vcpu.opcode_emulator.saved_gs_base.unwrap_or(0); let gs_base = vcpu.opcode_emulator.saved_gs_base.unwrap_or(0);
let current_gs_val = vmread(vmcs::guest::GS_SELECTOR).unwrap(); let _current_gs_val = vmread(vmcs::guest::GS_SELECTOR).unwrap();
let current_gs_base = vmread(vmcs::guest::GS_BASE).unwrap(); let _current_gs_base = vmread(vmcs::guest::GS_BASE).unwrap();
vmwrite(vmcs::guest::GS_SELECTOR, gs_selector as u64).unwrap(); vmwrite(vmcs::guest::GS_SELECTOR, gs_selector as u64).unwrap();
vmwrite(vmcs::guest::GS_BASE, gs_base).unwrap(); vmwrite(vmcs::guest::GS_BASE, gs_base).unwrap();
@ -337,14 +338,14 @@ fn emulate_syscall(vcpu: &mut VCpu, instruction_bytes: [u8; 16]) -> bool {
let current_gs_base = unsafe { vmread(vmcs::guest::GS_BASE).unwrap() }; let current_gs_base = unsafe { vmread(vmcs::guest::GS_BASE).unwrap() };
// Read all current segment values for logging // Read all current segment values for logging
let current_cs_base = unsafe { vmread(vmcs::guest::CS_BASE).unwrap() }; let _current_cs_base = unsafe { vmread(vmcs::guest::CS_BASE).unwrap() };
let current_cs_limit = unsafe { vmread(vmcs::guest::CS_LIMIT).unwrap() }; let _current_cs_limit = unsafe { vmread(vmcs::guest::CS_LIMIT).unwrap() };
let current_cs_rights = unsafe { vmread(vmcs::guest::CS_ACCESS_RIGHTS).unwrap() }; let _current_cs_rights = unsafe { vmread(vmcs::guest::CS_ACCESS_RIGHTS).unwrap() };
let current_ss_base = unsafe { vmread(vmcs::guest::SS_BASE).unwrap() }; let _current_ss_base = unsafe { vmread(vmcs::guest::SS_BASE).unwrap() };
let current_ss_limit = unsafe { vmread(vmcs::guest::SS_LIMIT).unwrap() }; let _current_ss_limit = unsafe { vmread(vmcs::guest::SS_LIMIT).unwrap() };
let current_ss_rights = unsafe { vmread(vmcs::guest::SS_ACCESS_RIGHTS).unwrap() }; let _current_ss_rights = unsafe { vmread(vmcs::guest::SS_ACCESS_RIGHTS).unwrap() };
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() };
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);

View File

@ -6,7 +6,7 @@ use x86_64::{
PhysAddr, PhysAddr,
}; };
use crate::{info, memory}; use crate::memory;
pub struct EPT { pub struct EPT {
pub root_table: PhysFrame, pub root_table: PhysFrame,

View File

@ -1,6 +1,6 @@
use bitfield::bitfield; use bitfield::bitfield;
use crate::{error, info}; use crate::error;
use super::vcpu::VCpu; use super::vcpu::VCpu;

View File

@ -1,5 +1,4 @@
use core::arch::asm; use core::arch::asm;
use x86_64::PhysAddr;
#[repr(C, packed)] #[repr(C, packed)]
pub struct InveptDesc { pub struct InveptDesc {

View File

@ -125,6 +125,28 @@ impl ShadowMsr {
x86::msr::IA32_EFER => Self::set_ret_val(vcpu, unsafe { x86::msr::IA32_EFER => Self::set_ret_val(vcpu, unsafe {
vmread(vmcs::guest::IA32_EFER_FULL).unwrap() vmread(vmcs::guest::IA32_EFER_FULL).unwrap()
}), }),
x86::msr::IA32_TIME_STAMP_COUNTER => {
Self::set_ret_val(vcpu, unsafe { x86::time::rdtsc() })
}
x86::msr::IA32_FEATURE_CONTROL => {
// Lock bit (0) | Enable VMX inside SMX (1) | Enable VMX outside SMX (2)
Self::set_ret_val(vcpu, 0x5)
}
0x48 => Self::set_ret_val(vcpu, 0), // IA32_SPEC_CTRL
0x122 => Self::set_ret_val(vcpu, 0), // IA32_TSX_CTRL
0x560 => Self::set_ret_val(vcpu, 0), // IA32_RTIT_OUTPUT_BASE
0x561 => Self::set_ret_val(vcpu, 0), // IA32_RTIT_OUTPUT_MASK_PTRS
0x570 => Self::set_ret_val(vcpu, 0), // IA32_RTIT_CTL
0x571 => Self::set_ret_val(vcpu, 0), // IA32_RTIT_STATUS
0x572 => Self::set_ret_val(vcpu, 0), // IA32_CR3_MATCH
0x580 => Self::set_ret_val(vcpu, 0), // IA32_ADDR0_START
0x581 => Self::set_ret_val(vcpu, 0), // IA32_ADDR0_END
0x582 => Self::set_ret_val(vcpu, 0), // IA32_ADDR1_START
0x583 => Self::set_ret_val(vcpu, 0), // IA32_ADDR1_END
0x584 => Self::set_ret_val(vcpu, 0), // IA32_ADDR2_START
0x585 => Self::set_ret_val(vcpu, 0), // IA32_ADDR2_END
0x586 => Self::set_ret_val(vcpu, 0), // IA32_ADDR3_START
0x587 => Self::set_ret_val(vcpu, 0), // IA32_ADDR3_END
x86::msr::IA32_FS_BASE => { x86::msr::IA32_FS_BASE => {
Self::set_ret_val(vcpu, unsafe { vmread(vmcs::guest::FS_BASE).unwrap() }) Self::set_ret_val(vcpu, unsafe { vmread(vmcs::guest::FS_BASE).unwrap() })
} }
@ -132,6 +154,19 @@ impl ShadowMsr {
Self::set_ret_val(vcpu, unsafe { vmread(vmcs::guest::GS_BASE).unwrap() }) Self::set_ret_val(vcpu, unsafe { vmread(vmcs::guest::GS_BASE).unwrap() })
} }
x86::msr::IA32_KERNEL_GSBASE => Self::shadow_read(vcpu, msr_kind), x86::msr::IA32_KERNEL_GSBASE => Self::shadow_read(vcpu, msr_kind),
x86::msr::IA32_STAR => Self::shadow_read(vcpu, msr_kind),
x86::msr::IA32_LSTAR => Self::shadow_read(vcpu, msr_kind),
x86::msr::IA32_CSTAR => Self::shadow_read(vcpu, msr_kind),
x86::msr::IA32_FMASK => Self::shadow_read(vcpu, msr_kind),
x86::msr::SYSENTER_CS_MSR => {
Self::set_ret_val(vcpu, unsafe { vmread(vmcs::guest::IA32_SYSENTER_CS).unwrap() })
}
x86::msr::SYSENTER_ESP_MSR => {
Self::set_ret_val(vcpu, unsafe { vmread(vmcs::guest::IA32_SYSENTER_ESP).unwrap() })
}
x86::msr::SYSENTER_EIP_MSR => {
Self::set_ret_val(vcpu, unsafe { vmread(vmcs::guest::IA32_SYSENTER_EIP).unwrap() })
}
0x1b => Self::shadow_read(vcpu, msr_kind), 0x1b => Self::shadow_read(vcpu, msr_kind),
0x8b => Self::set_ret_val(vcpu, 0x8701021), 0x8b => Self::set_ret_val(vcpu, 0x8701021),
0xc0011029 => Self::set_ret_val(vcpu, 0x3000310e08202), 0xc0011029 => Self::set_ret_val(vcpu, 0x3000310e08202),
@ -140,6 +175,14 @@ impl ShadowMsr {
0xc0010002 => Self::set_ret_val(vcpu, 0), 0xc0010002 => Self::set_ret_val(vcpu, 0),
0xc0010003 => Self::set_ret_val(vcpu, 0), 0xc0010003 => Self::set_ret_val(vcpu, 0),
0xc0010007 => Self::set_ret_val(vcpu, 0), 0xc0010007 => Self::set_ret_val(vcpu, 0),
0xc0010114 => Self::set_ret_val(vcpu, 0),
0xc0010117 => Self::set_ret_val(vcpu, 0), // MSR_VM_HSAVE_PA
0x277 => Self::set_ret_val(vcpu, 0x0007040600070406),
0xc0000103 => Self::shadow_read(vcpu, msr_kind), // TSC_AUX
0xd90 => Self::set_ret_val(vcpu, 0), // MSR_C1_PMON_EVNT_SEL0
0xe1 => Self::set_ret_val(vcpu, 0), // IA32_UMWAIT_CONTROL
0x1c4 => Self::set_ret_val(vcpu, 0), // Unknown MSR
0x1c5 => Self::set_ret_val(vcpu, 0), // Unknown MSR
_ => { _ => {
panic!("Unhandled RDMSR: {:#x}", msr_kind); panic!("Unhandled RDMSR: {:#x}", msr_kind);
} }

View File

@ -50,7 +50,7 @@ use super::{
vmxon::Vmxon, vmxon::Vmxon,
}; };
const SIZE_2MIB: u64 = 2 * 1024 * 1024; const _SIZE_2MIB: u64 = 2 * 1024 * 1024;
const GUEST_MEMORY_SIZE: u64 = 2 * 1024 * 1024 * 1024; const GUEST_MEMORY_SIZE: u64 = 2 * 1024 * 1024 * 1024;
static EPT_FRAME_ALLOCATOR: AtomicPtr<BootInfoFrameAllocator> = static EPT_FRAME_ALLOCATOR: AtomicPtr<BootInfoFrameAllocator> =
@ -252,7 +252,7 @@ impl VCpu {
}; };
let cmdline_start = linux::LAYOUT_CMDLINE as u64; let cmdline_start = linux::LAYOUT_CMDLINE as u64;
let cmdline_end = cmdline_start + cmdline_max_size as u64; let _cmdline_end = cmdline_start + cmdline_max_size as u64;
let cmdline_bytes = b"console=ttyS0 earlyprintk=serial nokaslr\0"; let cmdline_bytes = b"console=ttyS0 earlyprintk=serial nokaslr\0";
self.load_image(cmdline_bytes, cmdline_start as usize); self.load_image(cmdline_bytes, cmdline_start as usize);
@ -316,7 +316,7 @@ impl VCpu {
} }
} }
pub fn setup_guest_memory(&mut self, frame_allocator: &mut BootInfoFrameAllocator) -> u64 { pub fn setup_guest_memory(&mut self, _frame_allocator: &mut BootInfoFrameAllocator) -> u64 {
info!( info!(
"Setting up guest memory with on-demand allocation (reported size: {}MB)", "Setting up guest memory with on-demand allocation (reported size: {}MB)",
GUEST_MEMORY_SIZE / (1024 * 1024) GUEST_MEMORY_SIZE / (1024 * 1024)
@ -1062,7 +1062,6 @@ impl VCpu {
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 // Read VM-instruction error for more details
let vm_instruction_error = unsafe { let vm_instruction_error = unsafe {
use x86::msr::rdmsr;
vmread(vmcs::ro::VM_INSTRUCTION_ERROR).unwrap_or(0) vmread(vmcs::ro::VM_INSTRUCTION_ERROR).unwrap_or(0)
}; };
info!(" VM-instruction error: {}", vm_instruction_error); info!(" VM-instruction error: {}", vm_instruction_error);
@ -1203,7 +1202,7 @@ impl VCpu {
} }
} }
} }
Err(e) => { Err(_e) => {
// Try reading directly as physical address if translation fails // Try reading directly as physical address if translation fails
if rip < 0x100000000 { if rip < 0x100000000 {
for i in 0..16 { for i in 0..16 {
@ -1254,13 +1253,13 @@ impl VCpu {
unsafe { vmread(vmcs::ro::GUEST_PHYSICAL_ADDR_FULL).unwrap() }; unsafe { vmread(vmcs::ro::GUEST_PHYSICAL_ADDR_FULL).unwrap() };
let exit_qualification = let exit_qualification =
unsafe { vmread(vmcs::ro::EXIT_QUALIFICATION).unwrap() }; unsafe { vmread(vmcs::ro::EXIT_QUALIFICATION).unwrap() };
let guest_rip = unsafe { vmread(vmcs::guest::RIP).unwrap() }; let _guest_rip = unsafe { vmread(vmcs::guest::RIP).unwrap() };
let read_access = (exit_qualification & 0x1) != 0; let _read_access = (exit_qualification & 0x1) != 0;
let write_access = (exit_qualification & 0x2) != 0; let _write_access = (exit_qualification & 0x2) != 0;
let execute_access = (exit_qualification & 0x4) != 0; let _execute_access = (exit_qualification & 0x4) != 0;
let gpa_valid = (exit_qualification & 0x80) != 0; let _gpa_valid = (exit_qualification & 0x80) != 0;
let translation_valid = (exit_qualification & 0x100) != 0; let _translation_valid = (exit_qualification & 0x100) != 0;
let page_addr = guest_address & !0xFFF; let page_addr = guest_address & !0xFFF;