diff --git a/bzImage b/bzImage index 12749d8..dbe5a00 100644 Binary files a/bzImage and b/bzImage differ diff --git a/src/vmm/cpuid.rs b/src/vmm/cpuid.rs index 114242a..382d6b7 100644 --- a/src/vmm/cpuid.rs +++ b/src/vmm/cpuid.rs @@ -1,4 +1,3 @@ -use crate::info; use raw_cpuid::cpuid; use super::{vcpu::VCpu, vmcs::VmxLeaf}; @@ -95,6 +94,9 @@ pub fn handle_cpuid_exit(vcpu: &mut VCpu) { regs.rax = 0x00000000; regs.rbx = 0x00000000; regs.rcx = signature.ecx as u64; + if vcpu.emulate_amd { + regs.rcx |= 1 << 2; // SVM + } regs.rdx = signature.edx as u64; } VmxLeaf::EXTENDED_FUNCTION => { diff --git a/src/vmm/emulation/opcode.rs b/src/vmm/emulation/opcode.rs index f259550..980ef91 100644 --- a/src/vmm/emulation/opcode.rs +++ b/src/vmm/emulation/opcode.rs @@ -7,7 +7,6 @@ use crate::{ }, }; use alloc::vec; -use alloc::vec::Vec; use x86::current::vmx::{vmread, vmwrite}; use x86::vmx::vmcs; @@ -31,7 +30,7 @@ pub struct OpcodeEmulator { pub saved_rsp: Option, } -enum VmcallControl { +pub enum VmcallControl { 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 { + 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(); if replace_len > 16 { return false; @@ -152,8 +155,6 @@ fn replace_opcode(vcpu: &mut VCpu, instruction_bytes: [u8; 16], replace: &[u8]) let mut original_opcode = [0u8; 16]; 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.replaced_address = Some(guest_phys_addr); 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); // Read current values for logging - let current_cs_val = vmread(vmcs::guest::CS_SELECTOR).unwrap(); - let current_cs_base = vmread(vmcs::guest::CS_BASE).unwrap(); - let current_cs_limit = vmread(vmcs::guest::CS_LIMIT).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_base = vmread(vmcs::guest::SS_BASE).unwrap(); - let current_ss_limit = vmread(vmcs::guest::SS_LIMIT).unwrap(); - let current_ss_rights = vmread(vmcs::guest::SS_ACCESS_RIGHTS).unwrap(); + let _current_cs_val = vmread(vmcs::guest::CS_SELECTOR).unwrap(); + let _current_cs_base = vmread(vmcs::guest::CS_BASE).unwrap(); + let _current_cs_limit = vmread(vmcs::guest::CS_LIMIT).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_base = vmread(vmcs::guest::SS_BASE).unwrap(); + let _current_ss_limit = vmread(vmcs::guest::SS_LIMIT).unwrap(); + let _current_ss_rights = vmread(vmcs::guest::SS_ACCESS_RIGHTS).unwrap(); // Set CS for 32-bit compatibility mode 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_base = vcpu.opcode_emulator.saved_gs_base.unwrap_or(0); - let current_gs_val = vmread(vmcs::guest::GS_SELECTOR).unwrap(); - let current_gs_base = vmread(vmcs::guest::GS_BASE).unwrap(); + let _current_gs_val = vmread(vmcs::guest::GS_SELECTOR).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_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() }; // Read all current segment values for logging - 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_rights = unsafe { vmread(vmcs::guest::CS_ACCESS_RIGHTS).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_rights = unsafe { vmread(vmcs::guest::SS_ACCESS_RIGHTS).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_cs_base = unsafe { vmread(vmcs::guest::CS_BASE).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_ss_base = unsafe { vmread(vmcs::guest::SS_BASE).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_gs_limit = unsafe { vmread(vmcs::guest::GS_LIMIT).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_ss_selector = Some(current_ss); diff --git a/src/vmm/ept.rs b/src/vmm/ept.rs index 8bf666b..9606414 100644 --- a/src/vmm/ept.rs +++ b/src/vmm/ept.rs @@ -6,7 +6,7 @@ use x86_64::{ PhysAddr, }; -use crate::{info, memory}; +use crate::memory; pub struct EPT { pub root_table: PhysFrame, diff --git a/src/vmm/fpu.rs b/src/vmm/fpu.rs index b5b1baf..a58c65b 100644 --- a/src/vmm/fpu.rs +++ b/src/vmm/fpu.rs @@ -1,6 +1,6 @@ use bitfield::bitfield; -use crate::{error, info}; +use crate::error; use super::vcpu::VCpu; diff --git a/src/vmm/invlpg.rs b/src/vmm/invlpg.rs index 93d9b82..416e04d 100644 --- a/src/vmm/invlpg.rs +++ b/src/vmm/invlpg.rs @@ -1,5 +1,4 @@ use core::arch::asm; -use x86_64::PhysAddr; #[repr(C, packed)] pub struct InveptDesc { diff --git a/src/vmm/msr.rs b/src/vmm/msr.rs index 79be6db..0394d9c 100644 --- a/src/vmm/msr.rs +++ b/src/vmm/msr.rs @@ -125,6 +125,28 @@ impl ShadowMsr { x86::msr::IA32_EFER => Self::set_ret_val(vcpu, unsafe { 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 => { 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() }) } 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), 0x8b => Self::set_ret_val(vcpu, 0x8701021), 0xc0011029 => Self::set_ret_val(vcpu, 0x3000310e08202), @@ -140,6 +175,14 @@ impl ShadowMsr { 0xc0010002 => Self::set_ret_val(vcpu, 0), 0xc0010003 => 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); } diff --git a/src/vmm/vcpu.rs b/src/vmm/vcpu.rs index 99eb8f8..8a3de8d 100644 --- a/src/vmm/vcpu.rs +++ b/src/vmm/vcpu.rs @@ -50,7 +50,7 @@ use super::{ 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; static EPT_FRAME_ALLOCATOR: AtomicPtr = @@ -252,7 +252,7 @@ impl VCpu { }; 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"; 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!( "Setting up guest memory with on-demand allocation (reported size: {}MB)", GUEST_MEMORY_SIZE / (1024 * 1024) @@ -1062,7 +1062,6 @@ impl VCpu { 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); @@ -1203,7 +1202,7 @@ impl VCpu { } } } - Err(e) => { + Err(_e) => { // Try reading directly as physical address if translation fails if rip < 0x100000000 { for i in 0..16 { @@ -1254,13 +1253,13 @@ impl VCpu { unsafe { vmread(vmcs::ro::GUEST_PHYSICAL_ADDR_FULL).unwrap() }; let exit_qualification = 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 write_access = (exit_qualification & 0x2) != 0; - let execute_access = (exit_qualification & 0x4) != 0; - let gpa_valid = (exit_qualification & 0x80) != 0; - let translation_valid = (exit_qualification & 0x100) != 0; + let _read_access = (exit_qualification & 0x1) != 0; + let _write_access = (exit_qualification & 0x2) != 0; + let _execute_access = (exit_qualification & 0x4) != 0; + let _gpa_valid = (exit_qualification & 0x80) != 0; + let _translation_valid = (exit_qualification & 0x100) != 0; let page_addr = guest_address & !0xFFF;