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.


Refactoring and additions to direct paging (nested and passthrough)
[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 #include <palacios/vmm_debug.h>
28
29 #include <palacios/vmx.h>
30 #include <palacios/vmm_ctrl_regs.h>
31 #include <palacios/vmm_lowlevel.h>
32 #include <palacios/vmx_ctrl_regs.h>
33 #include <palacios/vmx_assist.h>
34 #include <palacios/vmm_halt.h>
35 #include <palacios/vmm_mwait.h>
36 #include <palacios/vmx_ept.h>
37
38
39 #ifndef V3_CONFIG_DEBUG_VMX
40 #undef PrintDebug
41 #define PrintDebug(fmt, args...)
42 #endif
43
44 #ifdef V3_CONFIG_TELEMETRY
45 #include <palacios/vmm_telemetry.h>
46 #endif
47
48 /* At this point the GPRs are already copied into the guest_info state */
49 int v3_handle_vmx_exit(struct guest_info * info, struct vmx_exit_info * exit_info) {
50     struct vmx_basic_exit_info * basic_info = (struct vmx_basic_exit_info *)&(exit_info->exit_reason);
51
52     /*
53       PrintError(info->vm_info, info, "Handling VMX_EXIT: %s (%u), %lu (0x%lx)\n", 
54       v3_vmx_exit_code_to_str(exit_info->exit_reason),
55       exit_info->exit_reason, 
56       exit_info->exit_qual, exit_info->exit_qual);
57       
58       v3_print_vmcs();
59     */
60
61
62     if (basic_info->entry_error == 1) {
63         switch (basic_info->reason) {
64             case VMX_EXIT_INVALID_GUEST_STATE:
65                 PrintError(info->vm_info, info, "VM Entry failed due to invalid guest state\n");
66                 PrintError(info->vm_info, info, "Printing VMCS: (NOTE: This VMCS may not belong to the correct guest)\n");
67                 v3_print_vmcs();
68                 break;
69             case VMX_EXIT_INVALID_MSR_LOAD:
70                 PrintError(info->vm_info, info, "VM Entry failed due to error loading MSRs\n");
71                 break;
72             default:
73                 PrintError(info->vm_info, info, "Entry failed for unknown reason (%d)\n", basic_info->reason);
74                 break;
75         }
76         
77         return -1;
78     }
79
80
81
82 #ifdef V3_CONFIG_TELEMETRY
83     if (info->vm_info->enable_telemetry) {
84         v3_telemetry_start_exit(info);
85     }
86 #endif
87
88     switch (basic_info->reason) {
89         case VMX_EXIT_INFO_EXCEPTION_OR_NMI: {
90             pf_error_t error_code = *(pf_error_t *)&(exit_info->int_err);
91
92
93             // JRL: Change "0x0e" to a macro value
94             if ((uint8_t)exit_info->int_info == 14) {
95 #ifdef V3_CONFIG_DEBUG_SHADOW_PAGING
96                 PrintDebug(info->vm_info, info, "Page Fault at %p error_code=%x\n", (void *)exit_info->exit_qual, *(uint32_t *)&error_code);
97 #endif
98
99                 if (info->shdw_pg_mode == SHADOW_PAGING) {
100                     if (v3_handle_shadow_pagefault(info, (addr_t)exit_info->exit_qual, error_code) == -1) {
101                         PrintError(info->vm_info, info, "Error handling shadow page fault\n");
102                         return -1;
103                     }
104             
105                 } else {
106                     PrintError(info->vm_info, info, "Page fault in unimplemented paging mode\n");
107                     return -1;
108                 }
109             } else if ((uint8_t)exit_info->int_info == 2) {
110                 // NMI. Don't do anything
111             } else {
112                 PrintError(info->vm_info, info, "Unknown exception: 0x%x\n", (uint8_t)exit_info->int_info);
113                 v3_print_GPRs(info);
114                 return -1;
115             }
116             break;
117         }
118
119         case VMX_EXIT_EPT_VIOLATION: {
120             struct ept_exit_qual * ept_qual = (struct ept_exit_qual *)&(exit_info->exit_qual);
121
122             if (v3_handle_nested_pagefault(info, exit_info->ept_fault_addr, ept_qual,NULL,NULL) == -1) {
123                 PrintError(info->vm_info, info, "Error handling EPT fault\n");
124                 return -1;
125             }
126
127             break;
128         }
129         case VMX_EXIT_INVLPG:
130             if (info->shdw_pg_mode == SHADOW_PAGING) {
131                 if (v3_handle_shadow_invlpg(info) == -1) {
132                     PrintError(info->vm_info, info, "Error handling INVLPG\n");
133                     return -1;
134                 }
135             }
136
137             break;
138
139         case VMX_EXIT_RDTSC:
140 #ifdef V3_CONFIG_DEBUG_TIME
141             PrintDebug(info->vm_info, info, "RDTSC\n");
142 #endif 
143             if (v3_handle_rdtsc(info) == -1) {
144                 PrintError(info->vm_info, info, "Error Handling RDTSC instruction\n");
145                 return -1;
146             }
147             
148             break;
149
150         case VMX_EXIT_CPUID:
151             if (v3_handle_cpuid(info) == -1) {
152                 PrintError(info->vm_info, info, "Error Handling CPUID instruction\n");
153                 return -1;
154             }
155
156             break;
157         case VMX_EXIT_RDMSR: 
158             if (v3_handle_msr_read(info) == -1) {
159                 PrintError(info->vm_info, info, "Error handling MSR Read\n");
160                 return -1;
161             }
162
163             break;
164         case VMX_EXIT_WRMSR:
165             if (v3_handle_msr_write(info) == -1) {
166                 PrintError(info->vm_info, info, "Error handling MSR Write\n");
167                 return -1;
168             }
169
170             break;
171         case VMX_EXIT_VMCALL:
172             /* 
173              * Hypercall 
174              */
175
176             // VMCALL is a 3 byte op
177             // We do this early because some hypercalls can change the rip...
178             info->rip += 3;         
179
180             if (v3_handle_hypercall(info) == -1) {
181                 return -1;
182             }
183             break;
184         case VMX_EXIT_IO_INSTR: {
185             struct vmx_exit_io_qual * io_qual = (struct vmx_exit_io_qual *)&(exit_info->exit_qual);
186
187             if (io_qual->dir == 0) {
188                 if (io_qual->string) {
189                     if (v3_handle_vmx_io_outs(info, exit_info) == -1) {
190                         PrintError(info->vm_info, info, "Error in outs IO handler\n");
191                         return -1;
192                     }
193                 } else {
194                     if (v3_handle_vmx_io_out(info, exit_info) == -1) {
195                         PrintError(info->vm_info, info, "Error in out IO handler\n");
196                         return -1;
197                     }
198                 }
199             } else {
200                 if (io_qual->string) {
201                     if(v3_handle_vmx_io_ins(info, exit_info) == -1) {
202                         PrintError(info->vm_info, info, "Error in ins IO handler\n");
203                         return -1;
204                     }
205                 } else {
206                     if (v3_handle_vmx_io_in(info, exit_info) == -1) {
207                         PrintError(info->vm_info, info, "Error in in IO handler\n");
208                         return -1;
209                     }
210                 }
211             }
212             break;
213         }
214         case VMX_EXIT_CR_REG_ACCESSES: {
215             struct vmx_exit_cr_qual * cr_qual = (struct vmx_exit_cr_qual *)&(exit_info->exit_qual);
216             
217             // PrintDebug(info->vm_info, info, "Control register: %d\n", cr_qual->access_type);
218             switch(cr_qual->cr_id) {
219                 case 0:
220                     //PrintDebug(info->vm_info, info, "Handling CR0 Access\n");
221                     if (v3_vmx_handle_cr0_access(info, cr_qual, exit_info) == -1) {
222                         PrintError(info->vm_info, info, "Error in CR0 access handler\n");
223                         return -1;
224                     }
225                     break;
226                 case 3:
227                     //PrintDebug(info->vm_info, info, "Handling CR3 Access\n");
228                     if (v3_vmx_handle_cr3_access(info, cr_qual) == -1) {
229                         PrintError(info->vm_info, info, "Error in CR3 access handler\n");
230                         return -1;
231                     }
232                     break;
233                 case 4:
234                     //PrintDebug(info->vm_info, info, "Handling CR4 Access\n");
235                     if (v3_vmx_handle_cr4_access(info, cr_qual) == -1) {
236                         PrintError(info->vm_info, info, "Error in CR4 access handler\n");
237                         return -1;
238                     }
239                     break;
240                 case 8:
241                     if (v3_vmx_handle_cr8_access(info, cr_qual) == -1) {
242                         PrintError(info->vm_info, info, "Error in CR8 access handler\n");
243                         return -1;
244                     }
245                     break;
246                 default:
247                     PrintError(info->vm_info, info, "Unhandled CR access: %d\n", cr_qual->cr_id);
248                     return -1;
249             }
250             
251             // TODO: move RIP increment into all of the above individual CR
252             //       handlers, not just v3_vmx_handle_cr4_access()
253             if (cr_qual->cr_id != 4)
254                 info->rip += exit_info->instr_len;
255
256             break;
257         }
258         case VMX_EXIT_HLT:
259             PrintDebug(info->vm_info, info, "Guest halted\n");
260
261             if (v3_handle_halt(info) == -1) {
262                 PrintError(info->vm_info, info, "Error handling halt instruction\n");
263                 return -1;
264             }
265
266             break;
267
268         case VMX_EXIT_MONITOR:
269             PrintDebug(info->vm_info, info, "Guest Executing monitor\n");
270
271             if (v3_handle_monitor(info) == -1) {
272                 PrintError(info->vm_info, info, "Error handling monitor instruction\n");
273                 return -1;
274             }
275
276             break;
277
278         case VMX_EXIT_MWAIT:
279             PrintDebug(info->vm_info, info, "Guest Executing mwait\n");
280
281             if (v3_handle_mwait(info) == -1) {
282                 PrintError(info->vm_info, info, "Error handling mwait instruction\n");
283                 return -1;
284             }
285
286             break;
287
288
289         case VMX_EXIT_PAUSE:
290             // Handled as NOP
291             info->rip += 2;
292
293             break;
294         case VMX_EXIT_EXTERNAL_INTR:
295             // Interrupts are handled outside switch
296             break;
297         case VMX_EXIT_INTR_WINDOW:
298             // This is handled in the atomic part of the vmx code,
299             // not in the generic (interruptable) vmx handler
300             break;
301         case VMX_EXIT_EXPIRED_PREEMPT_TIMER:
302             V3_Print(info->vm_info, info, "VMX Preempt Timer Expired.\n");
303             // This just forces an exit and is handled outside the switch
304             break;
305             
306         default:
307             PrintError(info->vm_info, info, "Unhandled VMX_EXIT: %s (%u), %lu (0x%lx)\n", 
308                        v3_vmx_exit_code_to_str(basic_info->reason),
309                        basic_info->reason, 
310                        exit_info->exit_qual, exit_info->exit_qual);
311             return -1;
312     }
313
314
315 #ifdef V3_CONFIG_TELEMETRY
316     if (info->vm_info->enable_telemetry) {
317         v3_telemetry_end_exit(info, exit_info->exit_reason);
318     }
319 #endif
320
321
322     return 0;
323 }
324
325 static const char VMX_EXIT_INFO_EXCEPTION_OR_NMI_STR[] = "VMX_EXIT_INFO_EXCEPTION_OR_NMI";
326 static const char VMX_EXIT_EXTERNAL_INTR_STR[] = "VMX_EXIT_EXTERNAL_INTR";
327 static const char VMX_EXIT_TRIPLE_FAULT_STR[] = "VMX_EXIT_TRIPLE_FAULT";
328 static const char VMX_EXIT_INIT_SIGNAL_STR[] = "VMX_EXIT_INIT_SIGNAL";
329 static const char VMX_EXIT_STARTUP_IPI_STR[] = "VMX_EXIT_STARTUP_IPI";
330 static const char VMX_EXIT_IO_SMI_STR[] = "VMX_EXIT_IO_SMI";
331 static const char VMX_EXIT_OTHER_SMI_STR[] = "VMX_EXIT_OTHER_SMI";
332 static const char VMX_EXIT_INTR_WINDOW_STR[] = "VMX_EXIT_INTR_WINDOW";
333 static const char VMX_EXIT_NMI_WINDOW_STR[] = "VMX_EXIT_NMI_WINDOW";
334 static const char VMX_EXIT_TASK_SWITCH_STR[] = "VMX_EXIT_TASK_SWITCH";
335 static const char VMX_EXIT_CPUID_STR[] = "VMX_EXIT_CPUID";
336 static const char VMX_EXIT_HLT_STR[] = "VMX_EXIT_HLT";
337 static const char VMX_EXIT_INVD_STR[] = "VMX_EXIT_INVD";
338 static const char VMX_EXIT_INVLPG_STR[] = "VMX_EXIT_INVLPG";
339 static const char VMX_EXIT_RDPMC_STR[] = "VMX_EXIT_RDPMC";
340 static const char VMX_EXIT_RDTSC_STR[] = "VMX_EXIT_RDTSC";
341 static const char VMX_EXIT_RSM_STR[] = "VMX_EXIT_RSM";
342 static const char VMX_EXIT_VMCALL_STR[] = "VMX_EXIT_VMCALL";
343 static const char VMX_EXIT_VMCLEAR_STR[] = "VMX_EXIT_VMCLEAR";
344 static const char VMX_EXIT_VMLAUNCH_STR[] = "VMX_EXIT_VMLAUNCH";
345 static const char VMX_EXIT_VMPTRLD_STR[] = "VMX_EXIT_VMPTRLD";
346 static const char VMX_EXIT_VMPTRST_STR[] = "VMX_EXIT_VMPTRST";
347 static const char VMX_EXIT_VMREAD_STR[] = "VMX_EXIT_VMREAD";
348 static const char VMX_EXIT_VMRESUME_STR[] = "VMX_EXIT_VMRESUME";
349 static const char VMX_EXIT_VMWRITE_STR[] = "VMX_EXIT_VMWRITE";
350 static const char VMX_EXIT_VMXOFF_STR[] = "VMX_EXIT_VMXOFF";
351 static const char VMX_EXIT_VMXON_STR[] = "VMX_EXIT_VMXON";
352 static const char VMX_EXIT_CR_REG_ACCESSES_STR[] = "VMX_EXIT_CR_REG_ACCESSES";
353 static const char VMX_EXIT_MOV_DR_STR[] = "VMX_EXIT_MOV_DR";
354 static const char VMX_EXIT_IO_INSTR_STR[] = "VMX_EXIT_IO_INSTR";
355 static const char VMX_EXIT_RDMSR_STR[] = "VMX_EXIT_RDMSR";
356 static const char VMX_EXIT_WRMSR_STR[] = "VMX_EXIT_WRMSR";
357 static const char VMX_EXIT_INVALID_GUEST_STATE_STR[] = "VMX_EXIT_INVALID_GUEST_STATE";
358 static const char VMX_EXIT_INVALID_MSR_LOAD_STR[] = "VMX_EXIT_INVALID_MSR_LOAD";
359 static const char VMX_EXIT_MWAIT_STR[] = "VMX_EXIT_MWAIT";
360 static const char VMX_EXIT_MONITOR_STR[] = "VMX_EXIT_MONITOR";
361 static const char VMX_EXIT_PAUSE_STR[] = "VMX_EXIT_PAUSE";
362 static const char VMX_EXIT_INVALID_MACHINE_CHECK_STR[] = "VMX_EXIT_INVALIDE_MACHINE_CHECK";
363 static const char VMX_EXIT_TPR_BELOW_THRESHOLD_STR[] = "VMX_EXIT_TPR_BELOW_THRESHOLD";
364 static const char VMX_EXIT_APIC_STR[] = "VMX_EXIT_APIC";
365 static const char VMX_EXIT_GDTR_IDTR_STR[] = "VMX_EXIT_GDTR_IDTR";
366 static const char VMX_EXIT_LDTR_TR_STR[] = "VMX_EXIT_LDTR_TR";
367 static const char VMX_EXIT_EPT_VIOLATION_STR[] = "VMX_EXIT_EPT_VIOLATION";
368 static const char VMX_EXIT_EPT_CONFIG_STR[] = "VMX_EXIT_EPT_CONFIG";
369 static const char VMX_EXIT_INVEPT_STR[] = "VMX_EXIT_INVEPT";
370 static const char VMX_EXIT_RDTSCP_STR[] = "VMX_EXIT_RDTSCP";
371 static const char VMX_EXIT_EXPIRED_PREEMPT_TIMER_STR[] = "VMX_EXIT_EXPIRED_PREEMPT_TIMER";
372 static const char VMX_EXIT_INVVPID_STR[] = "VMX_EXIT_INVVPID";
373 static const char VMX_EXIT_WBINVD_STR[] = "VMX_EXIT_WBINVD";
374 static const char VMX_EXIT_XSETBV_STR[] = "VMX_EXIT_XSETBV";
375
376 const char * v3_vmx_exit_code_to_str(vmx_exit_t exit)
377 {
378     switch (exit) {
379         case VMX_EXIT_INFO_EXCEPTION_OR_NMI:
380             return VMX_EXIT_INFO_EXCEPTION_OR_NMI_STR;
381         case VMX_EXIT_EXTERNAL_INTR:
382             return VMX_EXIT_EXTERNAL_INTR_STR;
383         case VMX_EXIT_TRIPLE_FAULT:
384             return VMX_EXIT_TRIPLE_FAULT_STR;
385         case VMX_EXIT_INIT_SIGNAL:
386             return VMX_EXIT_INIT_SIGNAL_STR;
387         case VMX_EXIT_STARTUP_IPI:
388             return VMX_EXIT_STARTUP_IPI_STR;
389         case VMX_EXIT_IO_SMI:
390             return VMX_EXIT_IO_SMI_STR;
391         case VMX_EXIT_OTHER_SMI:
392             return VMX_EXIT_OTHER_SMI_STR;
393         case VMX_EXIT_INTR_WINDOW:
394             return VMX_EXIT_INTR_WINDOW_STR;
395         case VMX_EXIT_NMI_WINDOW:
396             return VMX_EXIT_NMI_WINDOW_STR;
397         case VMX_EXIT_TASK_SWITCH:
398             return VMX_EXIT_TASK_SWITCH_STR;
399         case VMX_EXIT_CPUID:
400             return VMX_EXIT_CPUID_STR;
401         case VMX_EXIT_HLT:
402             return VMX_EXIT_HLT_STR;
403         case VMX_EXIT_INVD:
404             return VMX_EXIT_INVD_STR;
405         case VMX_EXIT_INVLPG:
406             return VMX_EXIT_INVLPG_STR;
407         case VMX_EXIT_RDPMC:
408             return VMX_EXIT_RDPMC_STR;
409         case VMX_EXIT_RDTSC:
410             return VMX_EXIT_RDTSC_STR;
411         case VMX_EXIT_RSM:
412             return VMX_EXIT_RSM_STR;
413         case VMX_EXIT_VMCALL:
414             return VMX_EXIT_VMCALL_STR;
415         case VMX_EXIT_VMCLEAR:
416             return VMX_EXIT_VMCLEAR_STR;
417         case VMX_EXIT_VMLAUNCH:
418             return VMX_EXIT_VMLAUNCH_STR;
419         case VMX_EXIT_VMPTRLD:
420             return VMX_EXIT_VMPTRLD_STR;
421         case VMX_EXIT_VMPTRST:
422             return VMX_EXIT_VMPTRST_STR;
423         case VMX_EXIT_VMREAD:
424             return VMX_EXIT_VMREAD_STR;
425         case VMX_EXIT_VMRESUME:
426             return VMX_EXIT_VMRESUME_STR;
427         case VMX_EXIT_VMWRITE:
428             return VMX_EXIT_VMWRITE_STR;
429         case VMX_EXIT_VMXOFF:
430             return VMX_EXIT_VMXOFF_STR;
431         case VMX_EXIT_VMXON:
432             return VMX_EXIT_VMXON_STR;
433         case VMX_EXIT_CR_REG_ACCESSES:
434             return VMX_EXIT_CR_REG_ACCESSES_STR;
435         case VMX_EXIT_MOV_DR:
436             return VMX_EXIT_MOV_DR_STR;
437         case VMX_EXIT_IO_INSTR:
438             return VMX_EXIT_IO_INSTR_STR;
439         case VMX_EXIT_RDMSR:
440             return VMX_EXIT_RDMSR_STR;
441         case VMX_EXIT_WRMSR:
442             return VMX_EXIT_WRMSR_STR;
443         case VMX_EXIT_INVALID_GUEST_STATE:
444             return VMX_EXIT_INVALID_GUEST_STATE_STR;
445         case VMX_EXIT_INVALID_MSR_LOAD:
446             return VMX_EXIT_INVALID_MSR_LOAD_STR;
447         case VMX_EXIT_MWAIT:
448             return VMX_EXIT_MWAIT_STR;
449         case VMX_EXIT_MONITOR:
450             return VMX_EXIT_MONITOR_STR;
451         case VMX_EXIT_PAUSE:
452             return VMX_EXIT_PAUSE_STR;
453         case VMX_EXIT_INVALID_MACHINE_CHECK:
454             return VMX_EXIT_INVALID_MACHINE_CHECK_STR;
455         case VMX_EXIT_TPR_BELOW_THRESHOLD:
456             return VMX_EXIT_TPR_BELOW_THRESHOLD_STR;
457         case VMX_EXIT_APIC:
458             return VMX_EXIT_APIC_STR;
459         case VMX_EXIT_GDTR_IDTR:
460             return VMX_EXIT_GDTR_IDTR_STR;
461         case VMX_EXIT_LDTR_TR:
462             return VMX_EXIT_LDTR_TR_STR;
463         case VMX_EXIT_EPT_VIOLATION:
464             return VMX_EXIT_EPT_VIOLATION_STR;
465         case VMX_EXIT_EPT_CONFIG:
466             return VMX_EXIT_EPT_CONFIG_STR;
467         case VMX_EXIT_INVEPT:
468             return VMX_EXIT_INVEPT_STR;
469         case VMX_EXIT_RDTSCP:
470             return VMX_EXIT_RDTSCP_STR;
471         case VMX_EXIT_EXPIRED_PREEMPT_TIMER:
472             return VMX_EXIT_EXPIRED_PREEMPT_TIMER_STR;
473         case VMX_EXIT_INVVPID:
474             return VMX_EXIT_INVVPID_STR;
475         case VMX_EXIT_WBINVD:
476             return VMX_EXIT_WBINVD_STR;
477         case VMX_EXIT_XSETBV:
478             return VMX_EXIT_XSETBV_STR;
479     }
480     return NULL;
481 }
482