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