Palacios Public Git Repository

To checkout Palacios execute

  git clone http://v3vee.org/palacios/palacios.web/palacios.git
This will give you the master branch. You probably want the devel branch or one of the release branches. To switch to the devel branch, simply execute
  cd palacios
  git checkout --track -b devel origin/devel
The other branches are similar.


4066bf2b18a43c715dea822cf55c6d796a45d65b
[palacios.git] / palacios / src / palacios / vmx_handler.c
1 /* 
2  * This file is part of the Palacios Virtual Machine Monitor developed
3  * by the V3VEE Project with funding from the United States National 
4  * Science Foundation and the Department of Energy.  
5  *
6  * The V3VEE Project is a joint project between Northwestern University
7  * and the University of New Mexico.  You can find out more at 
8  * http://www.v3vee.org
9  *
10  * Copyright (c) 2008, Jack Lange <jarusl@cs.northwestern.edu> 
11  * Copyright (c) 2008, The V3VEE Project <http://www.v3vee.org> 
12  * All rights reserved.
13  *
14  * Author: Jack Lange <jarusl@cs.northwestern.edu>
15  *
16  * This is free software.  You are permitted to use,
17  * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
18  */
19
20 #include <palacios/vmx_handler.h>
21 #include <palacios/vmm_types.h>
22 #include <palacios/vmm.h>
23 #include <palacios/vmcs.h>
24 #include <palacios/vmx_lowlevel.h>
25 #include <palacios/vmx_io.h>
26 #include <palacios/vmm_cpuid.h>
27
28 #include <palacios/vmx.h>
29 #include <palacios/vmm_ctrl_regs.h>
30 #include <palacios/vmm_lowlevel.h>
31 #include <palacios/vmx_ctrl_regs.h>
32 #include <palacios/vmx_assist.h>
33 #include <palacios/vmm_halt.h>
34
35 #ifndef CONFIG_DEBUG_VMX
36 #undef PrintDebug
37 #define PrintDebug(fmt, args...)
38 #endif
39
40 #ifdef CONFIG_TELEMETRY
41 #include <palacios/vmm_telemetry.h>
42 #endif
43
44 /* At this point the GPRs are already copied into the guest_info state */
45 int v3_handle_atomic_vmx_exit(struct guest_info * info, struct vmx_exit_info * exit_info) {
46     struct vmx_data * vmx_info = (struct vmx_data *)(info->vmm_data);
47
48     switch (exit_info->exit_reason) {
49         case VMEXIT_INTR_WINDOW:
50             // This is here because we touch the VMCS 
51             vmcs_read(VMCS_PROC_CTRLS, &(vmx_info->pri_proc_ctrls.value));
52             vmx_info->pri_proc_ctrls.int_wndw_exit = 0;
53             vmcs_write(VMCS_PROC_CTRLS, vmx_info->pri_proc_ctrls.value);
54
55 #ifdef CONFIG_DEBUG_INTERRUPTS
56             PrintDebug("Interrupts available again! (RIP=%llx)\n", info->rip);
57 #endif
58             break;
59     }
60     return 0;
61 }
62
63 /* At this point the GPRs are already copied into the guest_info state */
64 int v3_handle_vmx_exit(struct guest_info * info, struct vmx_exit_info * exit_info) {
65     /*
66       PrintError("Handling VMEXIT: %s (%u), %lu (0x%lx)\n", 
67       v3_vmx_exit_code_to_str(exit_info->exit_reason),
68       exit_info->exit_reason, 
69       exit_info->exit_qual, exit_info->exit_qual);
70       
71       v3_print_vmcs();
72     */
73
74 #ifdef CONFIG_TELEMETRY
75     if (info->vm_info->enable_telemetry) {
76         v3_telemetry_start_exit(info);
77     }
78 #endif
79
80     switch (exit_info->exit_reason) {
81         case VMEXIT_INFO_EXCEPTION_OR_NMI: {
82             pf_error_t error_code = *(pf_error_t *)&(exit_info->int_err);
83
84
85             // JRL: Change "0x0e" to a macro value
86             if ((uint8_t)exit_info->int_info == 0x0e) {
87 #ifdef CONFIG_DEBUG_SHADOW_PAGING
88                 PrintDebug("Page Fault at %p error_code=%x\n", (void *)exit_info->exit_qual, *(uint32_t *)&error_code);
89 #endif
90
91                 if (info->shdw_pg_mode == SHADOW_PAGING) {
92                     if (v3_handle_shadow_pagefault(info, (addr_t)exit_info->exit_qual, error_code) == -1) {
93                         PrintError("Error handling shadow page fault\n");
94                         return -1;
95                     }
96                 } else {
97                     PrintError("Page fault in unimplemented paging mode\n");
98                     return -1;
99                 }
100             } else {
101                 PrintError("Unknown exception: 0x%x\n", (uint8_t)exit_info->int_info);
102                 v3_print_GPRs(info);
103                 return -1;
104             }
105             break;
106         }
107
108         case VMEXIT_INVLPG:
109             if (info->shdw_pg_mode == SHADOW_PAGING) {
110                 if (v3_handle_shadow_invlpg(info) == -1) {
111                     PrintError("Error handling INVLPG\n");
112                     return -1;
113                 }
114             }
115
116             break;
117
118         case VMEXIT_RDTSC:
119 #ifdef CONFIG_DEBUG_TIME
120             PrintDebug("RDTSC\n");
121 #endif 
122             if (v3_handle_rdtsc(info) == -1) {
123                 PrintError("Error Handling RDTSC instruction\n");
124                 return -1;
125             }
126             
127             break;
128
129         case VMEXIT_CPUID:
130             if (v3_handle_cpuid(info) == -1) {
131                 PrintError("Error Handling CPUID instruction\n");
132                 return -1;
133             }
134
135             break;
136         case VMEXIT_RDMSR: 
137             if (v3_handle_msr_read(info) == -1) {
138                 PrintError("Error handling MSR Read\n");
139                 return -1;
140             }
141
142             break;
143         case VMEXIT_WRMSR:
144             if (v3_handle_msr_write(info) == -1) {
145                 PrintError("Error handling MSR Write\n");
146                 return -1;
147             }
148
149             break;
150         case VMEXIT_VMCALL:
151             /* 
152              * Hypercall 
153              */
154
155             // VMCALL is a 3 byte op
156             // We do this early because some hypercalls can change the rip...
157             info->rip += 3;         
158
159             if (v3_handle_hypercall(info) == -1) {
160                 return -1;
161             }
162             break;
163         case VMEXIT_IO_INSTR: {
164             struct vmx_exit_io_qual * io_qual = (struct vmx_exit_io_qual *)&(exit_info->exit_qual);
165
166             if (io_qual->dir == 0) {
167                 if (io_qual->string) {
168                     if (v3_handle_vmx_io_outs(info, exit_info) == -1) {
169                         PrintError("Error in outs IO handler\n");
170                         return -1;
171                     }
172                 } else {
173                     if (v3_handle_vmx_io_out(info, exit_info) == -1) {
174                         PrintError("Error in out IO handler\n");
175                         return -1;
176                     }
177                 }
178             } else {
179                 if (io_qual->string) {
180                     if(v3_handle_vmx_io_ins(info, exit_info) == -1) {
181                         PrintError("Error in ins IO handler\n");
182                         return -1;
183                     }
184                 } else {
185                     if (v3_handle_vmx_io_in(info, exit_info) == -1) {
186                         PrintError("Error in in IO handler\n");
187                         return -1;
188                     }
189                 }
190             }
191             break;
192         }
193         case VMEXIT_CR_REG_ACCESSES: {
194             struct vmx_exit_cr_qual * cr_qual = (struct vmx_exit_cr_qual *)&(exit_info->exit_qual);
195             
196             // PrintDebug("Control register: %d\n", cr_qual->access_type);
197             switch(cr_qual->cr_id) {
198                 case 0:
199                     //PrintDebug("Handling CR0 Access\n");
200                     if (v3_vmx_handle_cr0_access(info, cr_qual, exit_info) == -1) {
201                         PrintError("Error in CR0 access handler\n");
202                         return -1;
203                     }
204                     break;
205                 case 3:
206                     //PrintDebug("Handling CR3 Access\n");
207                     if (v3_vmx_handle_cr3_access(info, cr_qual) == -1) {
208                         PrintError("Error in CR3 access handler\n");
209                         return -1;
210                     }
211                     break;
212                 default:
213                     PrintError("Unhandled CR access: %d\n", cr_qual->cr_id);
214                     return -1;
215             }
216             
217             info->rip += exit_info->instr_len;
218
219             break;
220         }
221         case VMEXIT_HLT:
222             PrintDebug("Guest halted\n");
223
224             if (v3_handle_halt(info) == -1) {
225                 PrintError("Error handling halt instruction\n");
226                 return -1;
227             }
228
229             break;
230         case VMEXIT_PAUSE:
231             // Handled as NOP
232             info->rip += 2;
233
234             break;
235         case VMEXIT_EXTERNAL_INTR:
236             // Interrupts are handled outside switch
237             break;
238         case VMEXIT_INTR_WINDOW:
239             // This is handled in the atomic part of the vmx code,
240             // not in the generic (interruptable) vmx handler
241             break;
242         default:
243             PrintError("Unhandled VMEXIT: %s (%u), %lu (0x%lx)\n", 
244                        v3_vmx_exit_code_to_str(exit_info->exit_reason),
245                        exit_info->exit_reason, 
246                        exit_info->exit_qual, exit_info->exit_qual);
247             return -1;
248     }
249
250
251 #ifdef CONFIG_TELEMETRY
252     if (info->vm_info->enable_telemetry) {
253         v3_telemetry_end_exit(info, exit_info->exit_reason);
254     }
255 #endif
256
257
258     return 0;
259 }
260
261 static const char VMEXIT_INFO_EXCEPTION_OR_NMI_STR[] = "VMEXIT_INFO_EXCEPTION_OR_NMI";
262 static const char VMEXIT_EXTERNAL_INTR_STR[] = "VMEXIT_EXTERNAL_INTR";
263 static const char VMEXIT_TRIPLE_FAULT_STR[] = "VMEXIT_TRIPLE_FAULT";
264 static const char VMEXIT_INIT_SIGNAL_STR[] = "VMEXIT_INIT_SIGNAL";
265 static const char VMEXIT_STARTUP_IPI_STR[] = "VMEXIT_STARTUP_IPI";
266 static const char VMEXIT_IO_SMI_STR[] = "VMEXIT_IO_SMI";
267 static const char VMEXIT_OTHER_SMI_STR[] = "VMEXIT_OTHER_SMI";
268 static const char VMEXIT_INTR_WINDOW_STR[] = "VMEXIT_INTR_WINDOW";
269 static const char VMEXIT_NMI_WINDOW_STR[] = "VMEXIT_NMI_WINDOW";
270 static const char VMEXIT_TASK_SWITCH_STR[] = "VMEXIT_TASK_SWITCH";
271 static const char VMEXIT_CPUID_STR[] = "VMEXIT_CPUID";
272 static const char VMEXIT_HLT_STR[] = "VMEXIT_HLT";
273 static const char VMEXIT_INVD_STR[] = "VMEXIT_INVD";
274 static const char VMEXIT_INVLPG_STR[] = "VMEXIT_INVLPG";
275 static const char VMEXIT_RDPMC_STR[] = "VMEXIT_RDPMC";
276 static const char VMEXIT_RDTSC_STR[] = "VMEXIT_RDTSC";
277 static const char VMEXIT_RSM_STR[] = "VMEXIT_RSM";
278 static const char VMEXIT_VMCALL_STR[] = "VMEXIT_VMCALL";
279 static const char VMEXIT_VMCLEAR_STR[] = "VMEXIT_VMCLEAR";
280 static const char VMEXIT_VMLAUNCH_STR[] = "VMEXIT_VMLAUNCH";
281 static const char VMEXIT_VMPTRLD_STR[] = "VMEXIT_VMPTRLD";
282 static const char VMEXIT_VMPTRST_STR[] = "VMEXIT_VMPTRST";
283 static const char VMEXIT_VMREAD_STR[] = "VMEXIT_VMREAD";
284 static const char VMEXIT_VMRESUME_STR[] = "VMEXIT_VMRESUME";
285 static const char VMEXIT_VMWRITE_STR[] = "VMEXIT_VMWRITE";
286 static const char VMEXIT_VMXOFF_STR[] = "VMEXIT_VMXOFF";
287 static const char VMEXIT_VMXON_STR[] = "VMEXIT_VMXON";
288 static const char VMEXIT_CR_REG_ACCESSES_STR[] = "VMEXIT_CR_REG_ACCESSES";
289 static const char VMEXIT_MOV_DR_STR[] = "VMEXIT_MOV_DR";
290 static const char VMEXIT_IO_INSTR_STR[] = "VMEXIT_IO_INSTR";
291 static const char VMEXIT_RDMSR_STR[] = "VMEXIT_RDMSR";
292 static const char VMEXIT_WRMSR_STR[] = "VMEXIT_WRMSR";
293 static const char VMEXIT_ENTRY_FAIL_INVALID_GUEST_STATE_STR[] = "VMEXIT_ENTRY_FAIL_INVALID_GUEST_STATE";
294 static const char VMEXIT_ENTRY_FAIL_MSR_LOAD_STR[] = "VMEXIT_ENTRY_FAIL_MSR_LOAD";
295 static const char VMEXIT_MWAIT_STR[] = "VMEXIT_MWAIT";
296 static const char VMEXIT_MONITOR_STR[] = "VMEXIT_MONITOR";
297 static const char VMEXIT_PAUSE_STR[] = "VMEXIT_PAUSE";
298 static const char VMEXIT_ENTRY_FAILURE_MACHINE_CHECK_STR[] = "VMEXIT_ENTRY_FAILURE_MACHINE_CHECK";
299 static const char VMEXIT_TPR_BELOW_THRESHOLD_STR[] = "VMEXIT_TPR_BELOW_THRESHOLD";
300 static const char VMEXIT_APIC_STR[] = "VMEXIT_APIC";
301 static const char VMEXIT_GDTR_IDTR_STR[] = "VMEXIT_GDTR_IDTR";
302 static const char VMEXIT_LDTR_TR_STR[] = "VMEXIT_LDTR_TR";
303 static const char VMEXIT_EPT_VIOLATION_STR[] = "VMEXIT_EPT_VIOLATION";
304 static const char VMEXIT_EPT_CONFIG_STR[] = "VMEXIT_EPT_CONFIG";
305 static const char VMEXIT_INVEPT_STR[] = "VMEXIT_INVEPT";
306 static const char VMEXIT_RDTSCP_STR[] = "VMEXIT_RDTSCP";
307 static const char VMEXIT_EXPIRED_PREEMPT_TIMER_STR[] = "VMEXIT_EXPIRED_PREEMPT_TIMER";
308 static const char VMEXIT_INVVPID_STR[] = "VMEXIT_INVVPID";
309 static const char VMEXIT_WBINVD_STR[] = "VMEXIT_WBINVD";
310 static const char VMEXIT_XSETBV_STR[] = "VMEXIT_XSETBV";
311
312 const char * v3_vmx_exit_code_to_str(vmx_exit_t exit)
313 {
314     switch(exit) {
315         case VMEXIT_INFO_EXCEPTION_OR_NMI:
316             return VMEXIT_INFO_EXCEPTION_OR_NMI_STR;
317         case VMEXIT_EXTERNAL_INTR:
318             return VMEXIT_EXTERNAL_INTR_STR;
319         case VMEXIT_TRIPLE_FAULT:
320             return VMEXIT_TRIPLE_FAULT_STR;
321         case VMEXIT_INIT_SIGNAL:
322             return VMEXIT_INIT_SIGNAL_STR;
323         case VMEXIT_STARTUP_IPI:
324             return VMEXIT_STARTUP_IPI_STR;
325         case VMEXIT_IO_SMI:
326             return VMEXIT_IO_SMI_STR;
327         case VMEXIT_OTHER_SMI:
328             return VMEXIT_OTHER_SMI_STR;
329         case VMEXIT_INTR_WINDOW:
330             return VMEXIT_INTR_WINDOW_STR;
331         case VMEXIT_NMI_WINDOW:
332             return VMEXIT_NMI_WINDOW_STR;
333         case VMEXIT_TASK_SWITCH:
334             return VMEXIT_TASK_SWITCH_STR;
335         case VMEXIT_CPUID:
336             return VMEXIT_CPUID_STR;
337         case VMEXIT_HLT:
338             return VMEXIT_HLT_STR;
339         case VMEXIT_INVD:
340             return VMEXIT_INVD_STR;
341         case VMEXIT_INVLPG:
342             return VMEXIT_INVLPG_STR;
343         case VMEXIT_RDPMC:
344             return VMEXIT_RDPMC_STR;
345         case VMEXIT_RDTSC:
346             return VMEXIT_RDTSC_STR;
347         case VMEXIT_RSM:
348             return VMEXIT_RSM_STR;
349         case VMEXIT_VMCALL:
350             return VMEXIT_VMCALL_STR;
351         case VMEXIT_VMCLEAR:
352             return VMEXIT_VMCLEAR_STR;
353         case VMEXIT_VMLAUNCH:
354             return VMEXIT_VMLAUNCH_STR;
355         case VMEXIT_VMPTRLD:
356             return VMEXIT_VMPTRLD_STR;
357         case VMEXIT_VMPTRST:
358             return VMEXIT_VMPTRST_STR;
359         case VMEXIT_VMREAD:
360             return VMEXIT_VMREAD_STR;
361         case VMEXIT_VMRESUME:
362             return VMEXIT_VMRESUME_STR;
363         case VMEXIT_VMWRITE:
364             return VMEXIT_VMWRITE_STR;
365         case VMEXIT_VMXOFF:
366             return VMEXIT_VMXOFF_STR;
367         case VMEXIT_VMXON:
368             return VMEXIT_VMXON_STR;
369         case VMEXIT_CR_REG_ACCESSES:
370             return VMEXIT_CR_REG_ACCESSES_STR;
371         case VMEXIT_MOV_DR:
372             return VMEXIT_MOV_DR_STR;
373         case VMEXIT_IO_INSTR:
374             return VMEXIT_IO_INSTR_STR;
375         case VMEXIT_RDMSR:
376             return VMEXIT_RDMSR_STR;
377         case VMEXIT_WRMSR:
378             return VMEXIT_WRMSR_STR;
379         case VMEXIT_ENTRY_FAIL_INVALID_GUEST_STATE:
380             return VMEXIT_ENTRY_FAIL_INVALID_GUEST_STATE_STR;
381         case VMEXIT_ENTRY_FAIL_MSR_LOAD:
382             return VMEXIT_ENTRY_FAIL_MSR_LOAD_STR;
383         case VMEXIT_MWAIT:
384             return VMEXIT_MWAIT_STR;
385         case VMEXIT_MONITOR:
386             return VMEXIT_MONITOR_STR;
387         case VMEXIT_PAUSE:
388             return VMEXIT_PAUSE_STR;
389         case VMEXIT_ENTRY_FAILURE_MACHINE_CHECK:
390             return VMEXIT_ENTRY_FAILURE_MACHINE_CHECK_STR;
391         case VMEXIT_TPR_BELOW_THRESHOLD:
392             return VMEXIT_TPR_BELOW_THRESHOLD_STR;
393         case VMEXIT_APIC:
394             return VMEXIT_APIC_STR;
395         case VMEXIT_GDTR_IDTR:
396             return VMEXIT_GDTR_IDTR_STR;
397         case VMEXIT_LDTR_TR:
398             return VMEXIT_LDTR_TR_STR;
399         case VMEXIT_EPT_VIOLATION:
400             return VMEXIT_EPT_VIOLATION_STR;
401         case VMEXIT_EPT_CONFIG:
402             return VMEXIT_EPT_CONFIG_STR;
403         case VMEXIT_INVEPT:
404             return VMEXIT_INVEPT_STR;
405         case VMEXIT_RDTSCP:
406             return VMEXIT_RDTSCP_STR;
407         case VMEXIT_EXPIRED_PREEMPT_TIMER:
408             return VMEXIT_EXPIRED_PREEMPT_TIMER_STR;
409         case VMEXIT_INVVPID:
410             return VMEXIT_INVVPID_STR;
411         case VMEXIT_WBINVD:
412             return VMEXIT_WBINVD_STR;
413         case VMEXIT_XSETBV:
414             return VMEXIT_XSETBV_STR;
415     }
416     return NULL;
417 }
418