1 use super::vmcs::{VmcsFields, VmxExitReason}; 2 use super::vmx_asm_wrapper::{vmx_vmread, vmx_vmwrite}; 3 use crate::kdebug; 4 use crate::{syscall::SystemError, virt::kvm::vm}; 5 use core::arch::asm; 6 use x86::vmx::vmcs::ro::GUEST_PHYSICAL_ADDR_FULL; 7 8 #[derive(FromPrimitive)] 9 #[allow(non_camel_case_types)] 10 pub enum APICExceptionVectors { 11 EXCEPTION_DIVIDE_ERROR, 12 EXCEPTION_DEBUG_BREAKPOINT, 13 EXCEPTION_NMI, 14 EXCEPTION_BREAKPOINT, 15 EXCEPTION_OVERFLOW, 16 EXCEPTION_BOUND_RANGE_EXCEEDED, 17 EXCEPTION_UNDEFINED_OPCODE, 18 EXCEPTION_NO_MATH_COPROCESSOR, 19 EXCEPTION_DOUBLE_FAULT, 20 EXCEPTION_RESERVED0, 21 EXCEPTION_INVALID_TASK_SEGMENT_SELECTOR, 22 EXCEPTION_SEGMENT_NOT_PRESENT, 23 EXCEPTION_STACK_SEGMENT_FAULT, 24 EXCEPTION_GENERAL_PROTECTION_FAULT, 25 EXCEPTION_PAGE_FAULT, 26 EXCEPTION_RESERVED1, 27 EXCEPTION_MATH_FAULT, 28 EXCEPTION_ALIGNMENT_CHECK, 29 EXCEPTION_MACHINE_CHECK, 30 EXCEPTION_SIMD_FLOATING_POINT_NUMERIC_ERROR, 31 EXCEPTION_VIRTUAL_EXCEPTION, 32 EXCEPTION_RESERVED2, 33 EXCEPTION_RESERVED3, 34 EXCEPTION_RESERVED4, 35 EXCEPTION_RESERVED5, 36 EXCEPTION_RESERVED6, 37 EXCEPTION_RESERVED7, 38 EXCEPTION_RESERVED8, 39 EXCEPTION_RESERVED9, 40 EXCEPTION_RESERVED10, 41 EXCEPTION_RESERVED11, 42 EXCEPTION_RESERVED12, 43 } 44 45 #[derive(FromPrimitive)] 46 #[allow(non_camel_case_types)] 47 pub enum InterruptType { 48 INTERRUPT_TYPE_EXTERNAL_INTERRUPT = 0, 49 INTERRUPT_TYPE_RESERVED = 1, 50 INTERRUPT_TYPE_NMI = 2, 51 INTERRUPT_TYPE_HARDWARE_EXCEPTION = 3, 52 INTERRUPT_TYPE_SOFTWARE_INTERRUPT = 4, 53 INTERRUPT_TYPE_PRIVILEGED_SOFTWARE_INTERRUPT = 5, 54 INTERRUPT_TYPE_SOFTWARE_EXCEPTION = 6, 55 INTERRUPT_TYPE_OTHER_EVENT = 7, 56 } 57 58 pub fn vmexit_vmx_instruction_executed() -> Result<(), SystemError> { 59 let valid: u32 = 1; 60 let vector: u32 = APICExceptionVectors::EXCEPTION_UNDEFINED_OPCODE as u32; 61 let interrupt_type = InterruptType::INTERRUPT_TYPE_HARDWARE_EXCEPTION as u32; 62 let deliver_code: u32 = 0; 63 let interrupt_info = valid << 31 | interrupt_type << 8 | deliver_code << 11 | vector; 64 vmx_vmwrite( 65 VmcsFields::CTRL_VM_ENTRY_INTR_INFO_FIELD as u32, 66 interrupt_info as u64, 67 )?; 68 vmx_vmwrite(VmcsFields::CTRL_VM_ENTRY_INSTR_LEN as u32, 0)?; 69 let rflags: u64 = vmx_vmread(VmcsFields::GUEST_RFLAGS as u32).unwrap() | 0x0001_0000; // set RF flags 70 vmx_vmwrite(VmcsFields::GUEST_RFLAGS as u32, rflags)?; 71 Ok(()) 72 } 73 74 // pub fn vmexit_cpuid_handler(guest_cpu_context: &mut GuestCpuContext) -> Result<(), SystemError>{ 75 // let rax = guest_cpu_context.rax; 76 // let rcx = guest_cpu_context.rcx; 77 // // let rdx = guest_cpu_context.rdx; 78 // // let rbx = guest_cpu_context.rbx; 79 // cpuid!(rax, rcx); 80 // unsafe{asm!("mov {}, rax", out(reg) guest_cpu_context.rax)}; 81 // unsafe{asm!("mov {}, rcx", out(reg) guest_cpu_context.rcx)}; 82 // unsafe{asm!("mov {}, rdx", out(reg) guest_cpu_context.rdx)}; 83 // unsafe{asm!("mov {}, rbx", out(reg) guest_cpu_context.rbx)}; 84 // Ok(()) 85 // } 86 87 unsafe fn save_rpg() { 88 asm!( 89 "push rax", 90 "push rcx", 91 "push rdx", 92 "push rbx", 93 "push rbp", 94 "push rsi", 95 "push rdi", 96 "push r8", 97 "push r9", 98 "push r10", 99 "push r11", 100 "push r12", 101 "push r13", 102 "push r14", 103 "push r15", 104 ); 105 } 106 107 unsafe fn restore_rpg() { 108 asm!( 109 "pop r15", 110 "pop r14", 111 "pop r13", 112 "pop r12", 113 "pop r11", 114 "pop r10", 115 "pop r9", 116 "pop r8", 117 "pop rdi", 118 "pop rsi", 119 "pop rbp", 120 "pop rbx", 121 "pop rdx", 122 "pop rcx", 123 "pop rax", 124 ); 125 } 126 127 #[repr(C)] 128 #[allow(dead_code)] 129 pub struct GuestCpuContext { 130 pub r15: u64, 131 pub r14: u64, 132 pub r13: u64, 133 pub r12: u64, 134 pub r11: u64, 135 pub r10: u64, 136 pub r9: u64, 137 pub r8: u64, 138 pub rdi: u64, 139 pub rsi: u64, 140 pub rbp: u64, 141 pub rbx: u64, 142 pub rdx: u64, 143 pub rcx: u64, 144 pub rax: u64, 145 } 146 147 #[no_mangle] 148 pub extern "C" fn vmx_return() { 149 kdebug!("vmx_return!"); 150 unsafe { save_rpg() }; 151 vmexit_handler(); 152 // XMM registers are vector registers. They're renamed onto the FP/SIMD register file 153 // unsafe {asm!( 154 // "sub rsp, 60h", 155 // "movaps xmmword ptr [rsp + 0h], xmm0", 156 // "movaps xmmword ptr [rsp + 10h], xmm1", 157 // "movaps xmmword ptr [rsp + 20h], xmm2", 158 // "movaps xmmword ptr [rsp + 30h], xmm3", 159 // "movaps xmmword ptr [rsp + 40h], xmm4", 160 // "movaps xmmword ptr [rsp + 50h], xmm5", 161 162 // "mov rdi, rsp", 163 // "sub rsp, 20h", 164 // "call vmexit_handler", 165 // "add rsp, 20h", 166 167 // "movaps xmm0, xmmword ptr [rsp + 0h]", 168 // "movaps xmm1, xmmword ptr [rsp + 10h]", 169 // "movaps xmm2, xmmword ptr [rsp + 20h]", 170 // "movaps xmm3, xmmword ptr [rsp + 30h]", 171 // "movaps xmm4, xmmword ptr [rsp + 40h]", 172 // "movaps xmm5, xmmword ptr [rsp + 50h]", 173 // "add rsp, 60h", 174 // clobber_abi("C"), 175 // )}; 176 unsafe { restore_rpg() }; 177 unsafe { asm!("vmresume",) }; 178 } 179 180 #[no_mangle] 181 extern "C" fn vmexit_handler() { 182 // let guest_cpu_context = unsafe { guest_cpu_context_ptr.as_mut().unwrap() }; 183 // kdebug!("guest_cpu_context_ptr={:p}",guest_cpu_context_ptr); 184 kdebug!("vmexit handler!"); 185 186 let exit_reason = vmx_vmread(VmcsFields::VMEXIT_EXIT_REASON as u32).unwrap() as u32; 187 let exit_basic_reason = exit_reason & 0x0000_ffff; 188 let guest_rip = vmx_vmread(VmcsFields::GUEST_RIP as u32).unwrap(); 189 // let guest_rsp = vmx_vmread(VmcsFields::GUEST_RSP as u32).unwrap(); 190 kdebug!("guest_rip={:x}", guest_rip); 191 let _guest_rflags = vmx_vmread(VmcsFields::GUEST_RFLAGS as u32).unwrap(); 192 193 match VmxExitReason::from(exit_basic_reason as i32) { 194 VmxExitReason::VMCALL 195 | VmxExitReason::VMCLEAR 196 | VmxExitReason::VMLAUNCH 197 | VmxExitReason::VMPTRLD 198 | VmxExitReason::VMPTRST 199 | VmxExitReason::VMREAD 200 | VmxExitReason::VMRESUME 201 | VmxExitReason::VMWRITE 202 | VmxExitReason::VMXOFF 203 | VmxExitReason::VMXON 204 | VmxExitReason::VMFUNC 205 | VmxExitReason::INVEPT 206 | VmxExitReason::INVVPID => { 207 kdebug!("vmexit handler: vmx instruction!"); 208 vmexit_vmx_instruction_executed().expect("previledge instruction handle error"); 209 } 210 VmxExitReason::CPUID => { 211 kdebug!("vmexit handler: cpuid instruction!"); 212 // vmexit_cpuid_handler(guest_cpu_context); 213 adjust_rip(guest_rip).unwrap(); 214 } 215 VmxExitReason::RDMSR => { 216 kdebug!("vmexit handler: rdmsr instruction!"); 217 adjust_rip(guest_rip).unwrap(); 218 } 219 VmxExitReason::WRMSR => { 220 kdebug!("vmexit handler: wrmsr instruction!"); 221 adjust_rip(guest_rip).unwrap(); 222 } 223 VmxExitReason::TRIPLE_FAULT => { 224 kdebug!("vmexit handler: triple fault!"); 225 adjust_rip(guest_rip).unwrap(); 226 } 227 VmxExitReason::EPT_VIOLATION => { 228 kdebug!("vmexit handler: ept violation!"); 229 let gpa = vmx_vmread(GUEST_PHYSICAL_ADDR_FULL as u32).unwrap(); 230 let exit_qualification = vmx_vmread(VmcsFields::VMEXIT_QUALIFICATION as u32).unwrap(); 231 /* It is a write fault? */ 232 let mut error_code = exit_qualification & (1 << 1); 233 /* It is a fetch fault? */ 234 error_code |= (exit_qualification << 2) & (1 << 4); 235 /* ept page table is present? */ 236 error_code |= (exit_qualification >> 3) & (1 << 0); 237 238 let kvm = vm(0).unwrap(); 239 let vcpu = kvm.vcpu[0].clone(); 240 // Use the data 241 let kvm_ept_page_fault = vcpu.lock().mmu.page_fault.unwrap(); 242 kvm_ept_page_fault(&mut (*vcpu.lock()), gpa, error_code as u32, false) 243 .expect("ept page fault error"); 244 } 245 _ => { 246 kdebug!( 247 "vmexit handler: unhandled vmexit reason: {}!", 248 exit_basic_reason 249 ); 250 251 let info = vmx_vmread(VmcsFields::VMEXIT_INSTR_LEN as u32).unwrap() as u32; 252 kdebug!("vmexit handler: VMEXIT_INSTR_LEN: {}!", info); 253 let info = vmx_vmread(VmcsFields::VMEXIT_INSTR_INFO as u32).unwrap() as u32; 254 kdebug!("vmexit handler: VMEXIT_INSTR_INFO: {}!", info); 255 let info = vmx_vmread(VmcsFields::CTRL_EXPECTION_BITMAP as u32).unwrap() as u32; 256 kdebug!("vmexit handler: CTRL_EXPECTION_BITMAP: {}!", info); 257 258 adjust_rip(guest_rip).unwrap(); 259 // panic!(); 260 } 261 } 262 } 263 264 #[no_mangle] 265 fn adjust_rip(rip: u64) -> Result<(), SystemError> { 266 let instruction_length = vmx_vmread(VmcsFields::VMEXIT_INSTR_LEN as u32)?; 267 vmx_vmwrite(VmcsFields::GUEST_RIP as u32, rip + instruction_length)?; 268 Ok(()) 269 } 270