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.


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