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 cpuid hooking
[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 #ifdef CONFIG_TELEMETRY
36 #include <palacios/vmm_telemetry.h>
37 #endif
38
39
40 static int inline check_vmcs_write(vmcs_field_t field, addr_t val) {
41     int ret = 0;
42
43     ret = vmcs_write(field, val);
44
45     if (ret != VMX_SUCCESS) {
46         PrintError("VMWRITE error on %s!: %d\n", v3_vmcs_field_to_str(field), ret);
47     }
48
49     return ret;
50 }
51
52 static int inline check_vmcs_read(vmcs_field_t field, void * val) {
53     int ret = 0;
54
55     ret = vmcs_read(field, val);
56
57     if (ret != VMX_SUCCESS) {
58         PrintError("VMREAD error on %s!: %d\n", v3_vmcs_field_to_str(field), ret);
59     }
60
61     return ret;
62 }
63
64 static int inline handle_cr_access(struct guest_info * info, ulong_t exit_qual) {
65     struct vmx_exit_cr_qual * cr_qual = (struct vmx_exit_cr_qual *)&exit_qual;
66
67     // PrintDebug("Control register: %d\n", cr_qual->access_type);
68     switch(cr_qual->cr_id) {
69         case 0:
70             PrintDebug("Handling CR0 Access\n");
71             return v3_vmx_handle_cr0_access(info);
72         case 3:
73             PrintDebug("Handling CR3 Access\n");
74             return v3_vmx_handle_cr3_access(info);
75         default:
76             PrintError("Unhandled CR access: %d\n", cr_qual->cr_id);
77             return -1;
78     }
79     
80     return -1;
81 }
82
83
84 /* At this point the GPRs are already copied into the guest_info state */
85 int v3_handle_vmx_exit(struct v3_gprs * gprs, struct guest_info * info, struct v3_ctrl_regs * ctrl_regs) {
86     uint64_t tmp_tsc = 0;
87     uint32_t exit_reason = 0;
88     addr_t exit_qual = 0;
89     struct vmx_data * vmx_info = (struct vmx_data *)(info->vmm_data);
90     struct vmx_exit_idt_vec_info idt_vec_info;
91
92     rdtscll(tmp_tsc);
93     v3_update_time(info, tmp_tsc - info->time_state.cached_host_tsc);
94
95     v3_enable_ints();
96
97     check_vmcs_read(VMCS_EXIT_REASON, &exit_reason);
98     check_vmcs_read(VMCS_EXIT_QUAL, &exit_qual);
99
100     //PrintDebug("VMX Exit taken, id-qual: %u-%lu\n", exit_reason, exit_qual);
101
102     /* Update guest state */
103     v3_load_vmcs_guest_state(info);
104
105     // Load execution controls
106     check_vmcs_read(VMCS_PIN_CTRLS, &(vmx_info->pin_ctrls.value));
107     check_vmcs_read(VMCS_PROC_CTRLS, &(vmx_info->pri_proc_ctrls.value));
108
109     if (vmx_info->pri_proc_ctrls.sec_ctrls) {
110         check_vmcs_read(VMCS_SEC_PROC_CTRLS, &(vmx_info->sec_proc_ctrls.value));
111     }
112
113     info->mem_mode = v3_get_vm_mem_mode(info);
114     info->cpu_mode = v3_get_vm_cpu_mode(info);
115
116     // Check if we got interrupted while delivering interrupt
117     // Variable will be used later if this is true
118
119     check_vmcs_read(VMCS_IDT_VECTOR_INFO, &(idt_vec_info.value));
120
121     if ((info->intr_state.irq_started == 1) && (idt_vec_info.valid == 0)) {
122 #ifdef CONFIG_DEBUG_INTERRUPTS
123         PrintDebug("Calling v3_injecting_intr\n");
124 #endif
125         info->intr_state.irq_started = 0;
126         v3_injecting_intr(info, info->intr_state.irq_vector, V3_EXTERNAL_IRQ);
127     }
128
129     info->num_exits++;
130
131
132
133     if ((info->num_exits % 5000) == 0) {
134         PrintDebug("VMX Exit %d\n", (uint32_t)info->num_exits);
135     }
136
137 #ifdef CONFIG_TELEMETRY
138     if (info->enable_telemetry) {
139         v3_telemetry_start_exit(info);
140     }
141 #endif
142
143     switch (exit_reason) {
144         case VMEXIT_INFO_EXCEPTION_OR_NMI: {
145             uint32_t int_info;
146             pf_error_t error_code;
147
148             check_vmcs_read(VMCS_EXIT_INT_INFO, &int_info);
149             check_vmcs_read(VMCS_EXIT_INT_ERR, &error_code);
150
151             // JRL: Change "0x0e" to a macro value
152             if ((uint8_t)int_info == 0x0e) {
153 #ifdef CONFIG_DEBUG_SHADOW_PAGING
154                 PrintDebug("Page Fault at %p error_code=%x\n", (void *)exit_qual, *(uint32_t *)&error_code);
155 #endif
156
157                 if (info->shdw_pg_mode == SHADOW_PAGING) {
158                     if (v3_handle_shadow_pagefault(info, (addr_t)exit_qual, error_code) == -1) {
159                         PrintError("Error handling shadow page fault\n");
160                         return -1;
161                     }
162                 } else {
163                     PrintError("Page fault in unimplemented paging mode\n");
164                     return -1;
165                 }
166             } else {
167                 PrintError("Unknown exception: 0x%x\n", (uint8_t)int_info);
168                 v3_print_GPRs(info);
169                 return -1;
170             }
171             break;
172         }
173
174         case VMEXIT_INVLPG:
175             if (info->shdw_pg_mode == SHADOW_PAGING) {
176                 if (v3_handle_shadow_invlpg(info) == -1) {
177                     PrintError("Error handling INVLPG\n");
178                     return -1;
179                 }
180             }
181
182             break;
183         case VMEXIT_CPUID:
184             if (v3_handle_cpuid(info) == -1) {
185                 PrintError("Error Handling CPUID instruction\n");
186                 return -1;
187             }
188
189             break;
190         case VMEXIT_RDMSR: 
191             if (v3_handle_msr_read(info) == -1) {
192                 PrintError("Error handling MSR Read\n");
193                 return -1;
194             }
195
196             break;
197         case VMEXIT_WRMSR:
198             if (v3_handle_msr_write(info) == -1) {
199                 PrintError("Error handling MSR Write\n");
200                 return -1;
201             }
202
203             break;
204         case VMEXIT_IO_INSTR: {
205             struct vmx_exit_io_qual * io_qual = (struct vmx_exit_io_qual *)&exit_qual;
206
207             if (io_qual->dir == 0) {
208                 if (io_qual->string) {
209                     if (v3_handle_vmx_io_outs(info) == -1) {
210                         PrintError("Error in outs IO handler\n");
211                         return -1;
212                     }
213                 } else {
214                     if (v3_handle_vmx_io_out(info) == -1) {
215                         PrintError("Error in out IO handler\n");
216                         return -1;
217                     }
218                 }
219             } else {
220                 if (io_qual->string) {
221                     if(v3_handle_vmx_io_ins(info) == -1) {
222                         PrintError("Error in ins IO handler\n");
223                         return -1;
224                     }
225                 } else {
226                     if (v3_handle_vmx_io_in(info) == -1) {
227                         PrintError("Error in in IO handler\n");
228                         return -1;
229                     }
230                 }
231             }
232             break;
233         }
234         case VMEXIT_CR_REG_ACCESSES:
235             if (handle_cr_access(info, exit_qual) != 0) {
236                 PrintError("Error handling CR access\n");
237                 return -1;
238             }
239
240             break;
241         case VMEXIT_HLT:
242             PrintDebug("Guest halted\n");
243
244             if (v3_handle_halt(info) == -1) {
245                 PrintError("Error handling halt instruction\n");
246                 return -1;
247             }
248
249             break;
250         case VMEXIT_PAUSE:
251             // Handled as NOP
252             info->rip += 2;
253
254             break;
255         case VMEXIT_EXTERNAL_INTR:
256             // Interrupts are handled outside switch
257             break;
258         case VMEXIT_INTR_WINDOW:
259
260             vmx_info->pri_proc_ctrls.int_wndw_exit = 0;
261             check_vmcs_write(VMCS_PROC_CTRLS, vmx_info->pri_proc_ctrls.value);
262
263 #ifdef CONFIG_DEBUG_INTERRUPTS
264             PrintDebug("Interrupts available again! (RIP=%llx)\n", info->rip);
265 #endif
266
267             break;
268         default:
269             PrintError("Unhandled VMEXIT: %s (%u), %lu (0x%lx)\n", 
270                        v3_vmx_exit_code_to_str(exit_reason),
271                        exit_reason, exit_qual, exit_qual);
272             return -1;
273     }
274
275 #ifdef CONFIG_TELEMETRY
276     if (info->enable_telemetry) {
277         v3_telemetry_end_exit(info, exit_reason);
278     }
279 #endif
280
281
282     /* Check for pending exceptions to inject */
283     if (v3_excp_pending(info)) {
284         struct vmx_entry_int_info int_info;
285         int_info.value = 0;
286
287         // In VMX, almost every exception is hardware
288         // Software exceptions are pretty much only for breakpoint or overflow
289         int_info.type = 3;
290         int_info.vector = v3_get_excp_number(info);
291
292         if (info->excp_state.excp_error_code_valid) {
293             check_vmcs_write(VMCS_ENTRY_EXCP_ERR, info->excp_state.excp_error_code);
294             int_info.error_code = 1;
295
296             PrintDebug("Injecting exception %d with error code %x\n", 
297                     int_info.vector, info->excp_state.excp_error_code);
298         }
299
300         int_info.valid = 1;
301         PrintDebug("Injecting exception %d (EIP=%p)\n", int_info.vector, (void *)info->rip);
302         check_vmcs_write(VMCS_ENTRY_INT_INFO, int_info.value);
303
304         v3_injecting_excp(info, int_info.vector);
305
306     } else if (((struct rflags *)&(info->ctrl_regs.rflags))->intr == 1) {
307        
308         if ((info->intr_state.irq_started == 1) && (idt_vec_info.valid == 1)) {
309
310 #ifdef CONFIG_DEBUG_INTERRUPTS
311             PrintDebug("IRQ pending from previous injection\n");
312 #endif
313
314             // Copy the IDT vectoring info over to reinject the old interrupt
315             if (idt_vec_info.error_code == 1) {
316                 uint32_t err_code = 0;
317
318                 check_vmcs_read(VMCS_IDT_VECTOR_ERR, &err_code);
319                 check_vmcs_write(VMCS_ENTRY_EXCP_ERR, err_code);
320             }
321
322             idt_vec_info.undef = 0;
323             check_vmcs_write(VMCS_ENTRY_INT_INFO, idt_vec_info.value);
324
325         } else {
326             struct vmx_entry_int_info ent_int;
327             ent_int.value = 0;
328
329             switch (v3_intr_pending(info)) {
330                 case V3_EXTERNAL_IRQ: {
331                     info->intr_state.irq_vector = v3_get_intr(info); 
332                     ent_int.vector = info->intr_state.irq_vector;
333                     ent_int.type = 0;
334                     ent_int.error_code = 0;
335                     ent_int.valid = 1;
336
337 #ifdef CONFIG_DEBUG_INTERRUPTS
338                     PrintDebug("Injecting Interrupt %d at exit %u(EIP=%p)\n", 
339                                info->intr_state.irq_vector, 
340                                (uint32_t)info->num_exits, 
341                                (void *)info->rip);
342 #endif
343
344                     check_vmcs_write(VMCS_ENTRY_INT_INFO, ent_int.value);
345                     info->intr_state.irq_started = 1;
346
347                     break;
348                 }
349                 case V3_NMI:
350                     PrintDebug("Injecting NMI\n");
351
352                     ent_int.type = 2;
353                     ent_int.vector = 2;
354                     ent_int.valid = 1;
355                     check_vmcs_write(VMCS_ENTRY_INT_INFO, ent_int.value);
356
357                     break;
358                 case V3_SOFTWARE_INTR:
359                     PrintDebug("Injecting software interrupt\n");
360                     ent_int.type = 4;
361
362                     ent_int.valid = 1;
363                     check_vmcs_write(VMCS_ENTRY_INT_INFO, ent_int.value);
364
365                     break;
366                 case V3_VIRTUAL_IRQ:
367                     // Not sure what to do here, Intel doesn't have virtual IRQs
368                     // May be the same as external interrupts/IRQs
369
370                     break;
371                 case V3_INVALID_INTR:
372                 default:
373                     break;
374             }
375         }
376     } else if ((v3_intr_pending(info)) && (vmx_info->pri_proc_ctrls.int_wndw_exit == 0)) {
377         // Enable INTR window exiting so we know when IF=1
378         uint32_t instr_len;
379
380         check_vmcs_read(VMCS_EXIT_INSTR_LEN, &instr_len);
381
382 #ifdef CONFIG_DEBUG_INTERRUPTS
383         PrintDebug("Enabling Interrupt-Window exiting: %d\n", instr_len);
384 #endif
385
386         vmx_info->pri_proc_ctrls.int_wndw_exit = 1;
387         check_vmcs_write(VMCS_PROC_CTRLS, vmx_info->pri_proc_ctrls.value);
388     }
389
390     check_vmcs_write(VMCS_GUEST_CR0, info->ctrl_regs.cr0);
391     check_vmcs_write(VMCS_GUEST_CR3, info->ctrl_regs.cr3);
392     check_vmcs_write(VMCS_GUEST_CR4, info->ctrl_regs.cr4);
393     check_vmcs_write(VMCS_GUEST_RIP, info->rip);
394     check_vmcs_write(VMCS_GUEST_RSP, info->vm_regs.rsp);
395
396     check_vmcs_write(VMCS_CR0_READ_SHDW, info->shdw_pg_state.guest_cr0);
397
398     v3_disable_ints();
399
400     rdtscll(info->time_state.cached_host_tsc);
401
402     return 0;
403 }
404
405 static const char VMEXIT_INFO_EXCEPTION_OR_NMI_STR[] = "VMEXIT_INFO_EXCEPTION_OR_NMI";
406 static const char VMEXIT_EXTERNAL_INTR_STR[] = "VMEXIT_EXTERNAL_INTR";
407 static const char VMEXIT_TRIPLE_FAULT_STR[] = "VMEXIT_TRIPLE_FAULT";
408 static const char VMEXIT_INIT_SIGNAL_STR[] = "VMEXIT_INIT_SIGNAL";
409 static const char VMEXIT_STARTUP_IPI_STR[] = "VMEXIT_STARTUP_IPI";
410 static const char VMEXIT_IO_SMI_STR[] = "VMEXIT_IO_SMI";
411 static const char VMEXIT_OTHER_SMI_STR[] = "VMEXIT_OTHER_SMI";
412 static const char VMEXIT_INTR_WINDOW_STR[] = "VMEXIT_INTR_WINDOW";
413 static const char VMEXIT_NMI_WINDOW_STR[] = "VMEXIT_NMI_WINDOW";
414 static const char VMEXIT_TASK_SWITCH_STR[] = "VMEXIT_TASK_SWITCH";
415 static const char VMEXIT_CPUID_STR[] = "VMEXIT_CPUID";
416 static const char VMEXIT_HLT_STR[] = "VMEXIT_HLT";
417 static const char VMEXIT_INVD_STR[] = "VMEXIT_INVD";
418 static const char VMEXIT_INVLPG_STR[] = "VMEXIT_INVLPG";
419 static const char VMEXIT_RDPMC_STR[] = "VMEXIT_RDPMC";
420 static const char VMEXIT_RDTSC_STR[] = "VMEXIT_RDTSC";
421 static const char VMEXIT_RSM_STR[] = "VMEXIT_RSM";
422 static const char VMEXIT_VMCALL_STR[] = "VMEXIT_VMCALL";
423 static const char VMEXIT_VMCLEAR_STR[] = "VMEXIT_VMCLEAR";
424 static const char VMEXIT_VMLAUNCH_STR[] = "VMEXIT_VMLAUNCH";
425 static const char VMEXIT_VMPTRLD_STR[] = "VMEXIT_VMPTRLD";
426 static const char VMEXIT_VMPTRST_STR[] = "VMEXIT_VMPTRST";
427 static const char VMEXIT_VMREAD_STR[] = "VMEXIT_VMREAD";
428 static const char VMEXIT_VMRESUME_STR[] = "VMEXIT_VMRESUME";
429 static const char VMEXIT_VMWRITE_STR[] = "VMEXIT_VMWRITE";
430 static const char VMEXIT_VMXOFF_STR[] = "VMEXIT_VMXOFF";
431 static const char VMEXIT_VMXON_STR[] = "VMEXIT_VMXON";
432 static const char VMEXIT_CR_REG_ACCESSES_STR[] = "VMEXIT_CR_REG_ACCESSES";
433 static const char VMEXIT_MOV_DR_STR[] = "VMEXIT_MOV_DR";
434 static const char VMEXIT_IO_INSTR_STR[] = "VMEXIT_IO_INSTR";
435 static const char VMEXIT_RDMSR_STR[] = "VMEXIT_RDMSR";
436 static const char VMEXIT_WRMSR_STR[] = "VMEXIT_WRMSR";
437 static const char VMEXIT_ENTRY_FAIL_INVALID_GUEST_STATE_STR[] = "VMEXIT_ENTRY_FAIL_INVALID_GUEST_STATE";
438 static const char VMEXIT_ENTRY_FAIL_MSR_LOAD_STR[] = "VMEXIT_ENTRY_FAIL_MSR_LOAD";
439 static const char VMEXIT_MWAIT_STR[] = "VMEXIT_MWAIT";
440 static const char VMEXIT_MONITOR_STR[] = "VMEXIT_MONITOR";
441 static const char VMEXIT_PAUSE_STR[] = "VMEXIT_PAUSE";
442 static const char VMEXIT_ENTRY_FAILURE_MACHINE_CHECK_STR[] = "VMEXIT_ENTRY_FAILURE_MACHINE_CHECK";
443 static const char VMEXIT_TPR_BELOW_THRESHOLD_STR[] = "VMEXIT_TPR_BELOW_THRESHOLD";
444 static const char VMEXIT_APIC_STR[] = "VMEXIT_APIC";
445 static const char VMEXIT_GDTR_IDTR_STR[] = "VMEXIT_GDTR_IDTR";
446 static const char VMEXIT_LDTR_TR_STR[] = "VMEXIT_LDTR_TR";
447 static const char VMEXIT_EPT_VIOLATION_STR[] = "VMEXIT_EPT_VIOLATION";
448 static const char VMEXIT_EPT_CONFIG_STR[] = "VMEXIT_EPT_CONFIG";
449 static const char VMEXIT_INVEPT_STR[] = "VMEXIT_INVEPT";
450 static const char VMEXIT_RDTSCP_STR[] = "VMEXIT_RDTSCP";
451 static const char VMEXIT_EXPIRED_PREEMPT_TIMER_STR[] = "VMEXIT_EXPIRED_PREEMPT_TIMER";
452 static const char VMEXIT_INVVPID_STR[] = "VMEXIT_INVVPID";
453 static const char VMEXIT_WBINVD_STR[] = "VMEXIT_WBINVD";
454 static const char VMEXIT_XSETBV_STR[] = "VMEXIT_XSETBV";
455
456 const char * v3_vmx_exit_code_to_str(vmx_exit_t exit)
457 {
458     switch(exit) {
459         case VMEXIT_INFO_EXCEPTION_OR_NMI:
460             return VMEXIT_INFO_EXCEPTION_OR_NMI_STR;
461         case VMEXIT_EXTERNAL_INTR:
462             return VMEXIT_EXTERNAL_INTR_STR;
463         case VMEXIT_TRIPLE_FAULT:
464             return VMEXIT_TRIPLE_FAULT_STR;
465         case VMEXIT_INIT_SIGNAL:
466             return VMEXIT_INIT_SIGNAL_STR;
467         case VMEXIT_STARTUP_IPI:
468             return VMEXIT_STARTUP_IPI_STR;
469         case VMEXIT_IO_SMI:
470             return VMEXIT_IO_SMI_STR;
471         case VMEXIT_OTHER_SMI:
472             return VMEXIT_OTHER_SMI_STR;
473         case VMEXIT_INTR_WINDOW:
474             return VMEXIT_INTR_WINDOW_STR;
475         case VMEXIT_NMI_WINDOW:
476             return VMEXIT_NMI_WINDOW_STR;
477         case VMEXIT_TASK_SWITCH:
478             return VMEXIT_TASK_SWITCH_STR;
479         case VMEXIT_CPUID:
480             return VMEXIT_CPUID_STR;
481         case VMEXIT_HLT:
482             return VMEXIT_HLT_STR;
483         case VMEXIT_INVD:
484             return VMEXIT_INVD_STR;
485         case VMEXIT_INVLPG:
486             return VMEXIT_INVLPG_STR;
487         case VMEXIT_RDPMC:
488             return VMEXIT_RDPMC_STR;
489         case VMEXIT_RDTSC:
490             return VMEXIT_RDTSC_STR;
491         case VMEXIT_RSM:
492             return VMEXIT_RSM_STR;
493         case VMEXIT_VMCALL:
494             return VMEXIT_VMCALL_STR;
495         case VMEXIT_VMCLEAR:
496             return VMEXIT_VMCLEAR_STR;
497         case VMEXIT_VMLAUNCH:
498             return VMEXIT_VMLAUNCH_STR;
499         case VMEXIT_VMPTRLD:
500             return VMEXIT_VMPTRLD_STR;
501         case VMEXIT_VMPTRST:
502             return VMEXIT_VMPTRST_STR;
503         case VMEXIT_VMREAD:
504             return VMEXIT_VMREAD_STR;
505         case VMEXIT_VMRESUME:
506             return VMEXIT_VMRESUME_STR;
507         case VMEXIT_VMWRITE:
508             return VMEXIT_VMWRITE_STR;
509         case VMEXIT_VMXOFF:
510             return VMEXIT_VMXOFF_STR;
511         case VMEXIT_VMXON:
512             return VMEXIT_VMXON_STR;
513         case VMEXIT_CR_REG_ACCESSES:
514             return VMEXIT_CR_REG_ACCESSES_STR;
515         case VMEXIT_MOV_DR:
516             return VMEXIT_MOV_DR_STR;
517         case VMEXIT_IO_INSTR:
518             return VMEXIT_IO_INSTR_STR;
519         case VMEXIT_RDMSR:
520             return VMEXIT_RDMSR_STR;
521         case VMEXIT_WRMSR:
522             return VMEXIT_WRMSR_STR;
523         case VMEXIT_ENTRY_FAIL_INVALID_GUEST_STATE:
524             return VMEXIT_ENTRY_FAIL_INVALID_GUEST_STATE_STR;
525         case VMEXIT_ENTRY_FAIL_MSR_LOAD:
526             return VMEXIT_ENTRY_FAIL_MSR_LOAD_STR;
527         case VMEXIT_MWAIT:
528             return VMEXIT_MWAIT_STR;
529         case VMEXIT_MONITOR:
530             return VMEXIT_MONITOR_STR;
531         case VMEXIT_PAUSE:
532             return VMEXIT_PAUSE_STR;
533         case VMEXIT_ENTRY_FAILURE_MACHINE_CHECK:
534             return VMEXIT_ENTRY_FAILURE_MACHINE_CHECK_STR;
535         case VMEXIT_TPR_BELOW_THRESHOLD:
536             return VMEXIT_TPR_BELOW_THRESHOLD_STR;
537         case VMEXIT_APIC:
538             return VMEXIT_APIC_STR;
539         case VMEXIT_GDTR_IDTR:
540             return VMEXIT_GDTR_IDTR_STR;
541         case VMEXIT_LDTR_TR:
542             return VMEXIT_LDTR_TR_STR;
543         case VMEXIT_EPT_VIOLATION:
544             return VMEXIT_EPT_VIOLATION_STR;
545         case VMEXIT_EPT_CONFIG:
546             return VMEXIT_EPT_CONFIG_STR;
547         case VMEXIT_INVEPT:
548             return VMEXIT_INVEPT_STR;
549         case VMEXIT_RDTSCP:
550             return VMEXIT_RDTSCP_STR;
551         case VMEXIT_EXPIRED_PREEMPT_TIMER:
552             return VMEXIT_EXPIRED_PREEMPT_TIMER_STR;
553         case VMEXIT_INVVPID:
554             return VMEXIT_INVVPID_STR;
555         case VMEXIT_WBINVD:
556             return VMEXIT_WBINVD_STR;
557         case VMEXIT_XSETBV:
558             return VMEXIT_XSETBV_STR;
559     }
560     return NULL;
561 }
562