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