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