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.


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