xref: /DragonOS/kernel/src/arch/x86_64/kvm/vmx/vmexit.rs (revision f9fe30be89e89499aad4ef52b4648986bef5a7d8)
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