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