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 symbiotic interface and a number of other small changes
[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_VMCALL:
205             /* 
206              * Hypercall 
207              */
208
209             // VMCALL is a 3 byte op
210             // We do this early because some hypercalls can change the rip...
211             info->rip += 3;         
212
213             if (v3_handle_hypercall(info) == -1) {
214                 return -1;
215             }
216             break;
217         case VMEXIT_IO_INSTR: {
218             struct vmx_exit_io_qual * io_qual = (struct vmx_exit_io_qual *)&exit_qual;
219
220             if (io_qual->dir == 0) {
221                 if (io_qual->string) {
222                     if (v3_handle_vmx_io_outs(info) == -1) {
223                         PrintError("Error in outs IO handler\n");
224                         return -1;
225                     }
226                 } else {
227                     if (v3_handle_vmx_io_out(info) == -1) {
228                         PrintError("Error in out IO handler\n");
229                         return -1;
230                     }
231                 }
232             } else {
233                 if (io_qual->string) {
234                     if(v3_handle_vmx_io_ins(info) == -1) {
235                         PrintError("Error in ins IO handler\n");
236                         return -1;
237                     }
238                 } else {
239                     if (v3_handle_vmx_io_in(info) == -1) {
240                         PrintError("Error in in IO handler\n");
241                         return -1;
242                     }
243                 }
244             }
245             break;
246         }
247         case VMEXIT_CR_REG_ACCESSES:
248             if (handle_cr_access(info, exit_qual) != 0) {
249                 PrintError("Error handling CR access\n");
250                 return -1;
251             }
252
253             break;
254         case VMEXIT_HLT:
255             PrintDebug("Guest halted\n");
256
257             if (v3_handle_halt(info) == -1) {
258                 PrintError("Error handling halt instruction\n");
259                 return -1;
260             }
261
262             break;
263         case VMEXIT_PAUSE:
264             // Handled as NOP
265             info->rip += 2;
266
267             break;
268         case VMEXIT_EXTERNAL_INTR:
269             // Interrupts are handled outside switch
270             break;
271         case VMEXIT_INTR_WINDOW:
272
273             vmx_info->pri_proc_ctrls.int_wndw_exit = 0;
274             check_vmcs_write(VMCS_PROC_CTRLS, vmx_info->pri_proc_ctrls.value);
275
276 #ifdef CONFIG_DEBUG_INTERRUPTS
277             PrintDebug("Interrupts available again! (RIP=%llx)\n", info->rip);
278 #endif
279
280             break;
281         default:
282             PrintError("Unhandled VMEXIT: %s (%u), %lu (0x%lx)\n", 
283                        v3_vmx_exit_code_to_str(exit_reason),
284                        exit_reason, exit_qual, exit_qual);
285             return -1;
286     }
287
288 #ifdef CONFIG_TELEMETRY
289     if (info->enable_telemetry) {
290         v3_telemetry_end_exit(info, exit_reason);
291     }
292 #endif
293
294
295     /* Check for pending exceptions to inject */
296     if (v3_excp_pending(info)) {
297         struct vmx_entry_int_info int_info;
298         int_info.value = 0;
299
300         // In VMX, almost every exception is hardware
301         // Software exceptions are pretty much only for breakpoint or overflow
302         int_info.type = 3;
303         int_info.vector = v3_get_excp_number(info);
304
305         if (info->excp_state.excp_error_code_valid) {
306             check_vmcs_write(VMCS_ENTRY_EXCP_ERR, info->excp_state.excp_error_code);
307             int_info.error_code = 1;
308
309 #ifdef CONFIG_DEBUG_INTERRUPTS
310             PrintDebug("Injecting exception %d with error code %x\n", 
311                     int_info.vector, info->excp_state.excp_error_code);
312 #endif
313         }
314
315         int_info.valid = 1;
316 #ifdef CONFIG_DEBUG_INTERRUPTS
317         PrintDebug("Injecting exception %d (EIP=%p)\n", int_info.vector, (void *)info->rip);
318 #endif
319         check_vmcs_write(VMCS_ENTRY_INT_INFO, int_info.value);
320
321         v3_injecting_excp(info, int_info.vector);
322
323     } else if (((struct rflags *)&(info->ctrl_regs.rflags))->intr == 1) {
324        
325         if ((info->intr_state.irq_started == 1) && (idt_vec_info.valid == 1)) {
326
327 #ifdef CONFIG_DEBUG_INTERRUPTS
328             PrintDebug("IRQ pending from previous injection\n");
329 #endif
330
331             // Copy the IDT vectoring info over to reinject the old interrupt
332             if (idt_vec_info.error_code == 1) {
333                 uint32_t err_code = 0;
334
335                 check_vmcs_read(VMCS_IDT_VECTOR_ERR, &err_code);
336                 check_vmcs_write(VMCS_ENTRY_EXCP_ERR, err_code);
337             }
338
339             idt_vec_info.undef = 0;
340             check_vmcs_write(VMCS_ENTRY_INT_INFO, idt_vec_info.value);
341
342         } else {
343             struct vmx_entry_int_info ent_int;
344             ent_int.value = 0;
345
346             switch (v3_intr_pending(info)) {
347                 case V3_EXTERNAL_IRQ: {
348                     info->intr_state.irq_vector = v3_get_intr(info); 
349                     ent_int.vector = info->intr_state.irq_vector;
350                     ent_int.type = 0;
351                     ent_int.error_code = 0;
352                     ent_int.valid = 1;
353
354 #ifdef CONFIG_DEBUG_INTERRUPTS
355                     PrintDebug("Injecting Interrupt %d at exit %u(EIP=%p)\n", 
356                                info->intr_state.irq_vector, 
357                                (uint32_t)info->num_exits, 
358                                (void *)info->rip);
359 #endif
360
361                     check_vmcs_write(VMCS_ENTRY_INT_INFO, ent_int.value);
362                     info->intr_state.irq_started = 1;
363
364                     break;
365                 }
366                 case V3_NMI:
367                     PrintDebug("Injecting NMI\n");
368
369                     ent_int.type = 2;
370                     ent_int.vector = 2;
371                     ent_int.valid = 1;
372                     check_vmcs_write(VMCS_ENTRY_INT_INFO, ent_int.value);
373
374                     break;
375                 case V3_SOFTWARE_INTR:
376                     PrintDebug("Injecting software interrupt\n");
377                     ent_int.type = 4;
378
379                     ent_int.valid = 1;
380                     check_vmcs_write(VMCS_ENTRY_INT_INFO, ent_int.value);
381
382                     break;
383                 case V3_VIRTUAL_IRQ:
384                     // Not sure what to do here, Intel doesn't have virtual IRQs
385                     // May be the same as external interrupts/IRQs
386
387                     break;
388                 case V3_INVALID_INTR:
389                 default:
390                     break;
391             }
392         }
393     } else if ((v3_intr_pending(info)) && (vmx_info->pri_proc_ctrls.int_wndw_exit == 0)) {
394         // Enable INTR window exiting so we know when IF=1
395         uint32_t instr_len;
396
397         check_vmcs_read(VMCS_EXIT_INSTR_LEN, &instr_len);
398
399 #ifdef CONFIG_DEBUG_INTERRUPTS
400         PrintDebug("Enabling Interrupt-Window exiting: %d\n", instr_len);
401 #endif
402
403         vmx_info->pri_proc_ctrls.int_wndw_exit = 1;
404         check_vmcs_write(VMCS_PROC_CTRLS, vmx_info->pri_proc_ctrls.value);
405     }
406
407     check_vmcs_write(VMCS_GUEST_CR0, info->ctrl_regs.cr0);
408     check_vmcs_write(VMCS_GUEST_CR3, info->ctrl_regs.cr3);
409     check_vmcs_write(VMCS_GUEST_CR4, info->ctrl_regs.cr4);
410     check_vmcs_write(VMCS_GUEST_RIP, info->rip);
411     check_vmcs_write(VMCS_GUEST_RSP, info->vm_regs.rsp);
412
413     check_vmcs_write(VMCS_CR0_READ_SHDW, info->shdw_pg_state.guest_cr0);
414
415     v3_disable_ints();
416
417     rdtscll(info->time_state.cached_host_tsc);
418
419     return 0;
420 }
421
422 static const char VMEXIT_INFO_EXCEPTION_OR_NMI_STR[] = "VMEXIT_INFO_EXCEPTION_OR_NMI";
423 static const char VMEXIT_EXTERNAL_INTR_STR[] = "VMEXIT_EXTERNAL_INTR";
424 static const char VMEXIT_TRIPLE_FAULT_STR[] = "VMEXIT_TRIPLE_FAULT";
425 static const char VMEXIT_INIT_SIGNAL_STR[] = "VMEXIT_INIT_SIGNAL";
426 static const char VMEXIT_STARTUP_IPI_STR[] = "VMEXIT_STARTUP_IPI";
427 static const char VMEXIT_IO_SMI_STR[] = "VMEXIT_IO_SMI";
428 static const char VMEXIT_OTHER_SMI_STR[] = "VMEXIT_OTHER_SMI";
429 static const char VMEXIT_INTR_WINDOW_STR[] = "VMEXIT_INTR_WINDOW";
430 static const char VMEXIT_NMI_WINDOW_STR[] = "VMEXIT_NMI_WINDOW";
431 static const char VMEXIT_TASK_SWITCH_STR[] = "VMEXIT_TASK_SWITCH";
432 static const char VMEXIT_CPUID_STR[] = "VMEXIT_CPUID";
433 static const char VMEXIT_HLT_STR[] = "VMEXIT_HLT";
434 static const char VMEXIT_INVD_STR[] = "VMEXIT_INVD";
435 static const char VMEXIT_INVLPG_STR[] = "VMEXIT_INVLPG";
436 static const char VMEXIT_RDPMC_STR[] = "VMEXIT_RDPMC";
437 static const char VMEXIT_RDTSC_STR[] = "VMEXIT_RDTSC";
438 static const char VMEXIT_RSM_STR[] = "VMEXIT_RSM";
439 static const char VMEXIT_VMCALL_STR[] = "VMEXIT_VMCALL";
440 static const char VMEXIT_VMCLEAR_STR[] = "VMEXIT_VMCLEAR";
441 static const char VMEXIT_VMLAUNCH_STR[] = "VMEXIT_VMLAUNCH";
442 static const char VMEXIT_VMPTRLD_STR[] = "VMEXIT_VMPTRLD";
443 static const char VMEXIT_VMPTRST_STR[] = "VMEXIT_VMPTRST";
444 static const char VMEXIT_VMREAD_STR[] = "VMEXIT_VMREAD";
445 static const char VMEXIT_VMRESUME_STR[] = "VMEXIT_VMRESUME";
446 static const char VMEXIT_VMWRITE_STR[] = "VMEXIT_VMWRITE";
447 static const char VMEXIT_VMXOFF_STR[] = "VMEXIT_VMXOFF";
448 static const char VMEXIT_VMXON_STR[] = "VMEXIT_VMXON";
449 static const char VMEXIT_CR_REG_ACCESSES_STR[] = "VMEXIT_CR_REG_ACCESSES";
450 static const char VMEXIT_MOV_DR_STR[] = "VMEXIT_MOV_DR";
451 static const char VMEXIT_IO_INSTR_STR[] = "VMEXIT_IO_INSTR";
452 static const char VMEXIT_RDMSR_STR[] = "VMEXIT_RDMSR";
453 static const char VMEXIT_WRMSR_STR[] = "VMEXIT_WRMSR";
454 static const char VMEXIT_ENTRY_FAIL_INVALID_GUEST_STATE_STR[] = "VMEXIT_ENTRY_FAIL_INVALID_GUEST_STATE";
455 static const char VMEXIT_ENTRY_FAIL_MSR_LOAD_STR[] = "VMEXIT_ENTRY_FAIL_MSR_LOAD";
456 static const char VMEXIT_MWAIT_STR[] = "VMEXIT_MWAIT";
457 static const char VMEXIT_MONITOR_STR[] = "VMEXIT_MONITOR";
458 static const char VMEXIT_PAUSE_STR[] = "VMEXIT_PAUSE";
459 static const char VMEXIT_ENTRY_FAILURE_MACHINE_CHECK_STR[] = "VMEXIT_ENTRY_FAILURE_MACHINE_CHECK";
460 static const char VMEXIT_TPR_BELOW_THRESHOLD_STR[] = "VMEXIT_TPR_BELOW_THRESHOLD";
461 static const char VMEXIT_APIC_STR[] = "VMEXIT_APIC";
462 static const char VMEXIT_GDTR_IDTR_STR[] = "VMEXIT_GDTR_IDTR";
463 static const char VMEXIT_LDTR_TR_STR[] = "VMEXIT_LDTR_TR";
464 static const char VMEXIT_EPT_VIOLATION_STR[] = "VMEXIT_EPT_VIOLATION";
465 static const char VMEXIT_EPT_CONFIG_STR[] = "VMEXIT_EPT_CONFIG";
466 static const char VMEXIT_INVEPT_STR[] = "VMEXIT_INVEPT";
467 static const char VMEXIT_RDTSCP_STR[] = "VMEXIT_RDTSCP";
468 static const char VMEXIT_EXPIRED_PREEMPT_TIMER_STR[] = "VMEXIT_EXPIRED_PREEMPT_TIMER";
469 static const char VMEXIT_INVVPID_STR[] = "VMEXIT_INVVPID";
470 static const char VMEXIT_WBINVD_STR[] = "VMEXIT_WBINVD";
471 static const char VMEXIT_XSETBV_STR[] = "VMEXIT_XSETBV";
472
473 const char * v3_vmx_exit_code_to_str(vmx_exit_t exit)
474 {
475     switch(exit) {
476         case VMEXIT_INFO_EXCEPTION_OR_NMI:
477             return VMEXIT_INFO_EXCEPTION_OR_NMI_STR;
478         case VMEXIT_EXTERNAL_INTR:
479             return VMEXIT_EXTERNAL_INTR_STR;
480         case VMEXIT_TRIPLE_FAULT:
481             return VMEXIT_TRIPLE_FAULT_STR;
482         case VMEXIT_INIT_SIGNAL:
483             return VMEXIT_INIT_SIGNAL_STR;
484         case VMEXIT_STARTUP_IPI:
485             return VMEXIT_STARTUP_IPI_STR;
486         case VMEXIT_IO_SMI:
487             return VMEXIT_IO_SMI_STR;
488         case VMEXIT_OTHER_SMI:
489             return VMEXIT_OTHER_SMI_STR;
490         case VMEXIT_INTR_WINDOW:
491             return VMEXIT_INTR_WINDOW_STR;
492         case VMEXIT_NMI_WINDOW:
493             return VMEXIT_NMI_WINDOW_STR;
494         case VMEXIT_TASK_SWITCH:
495             return VMEXIT_TASK_SWITCH_STR;
496         case VMEXIT_CPUID:
497             return VMEXIT_CPUID_STR;
498         case VMEXIT_HLT:
499             return VMEXIT_HLT_STR;
500         case VMEXIT_INVD:
501             return VMEXIT_INVD_STR;
502         case VMEXIT_INVLPG:
503             return VMEXIT_INVLPG_STR;
504         case VMEXIT_RDPMC:
505             return VMEXIT_RDPMC_STR;
506         case VMEXIT_RDTSC:
507             return VMEXIT_RDTSC_STR;
508         case VMEXIT_RSM:
509             return VMEXIT_RSM_STR;
510         case VMEXIT_VMCALL:
511             return VMEXIT_VMCALL_STR;
512         case VMEXIT_VMCLEAR:
513             return VMEXIT_VMCLEAR_STR;
514         case VMEXIT_VMLAUNCH:
515             return VMEXIT_VMLAUNCH_STR;
516         case VMEXIT_VMPTRLD:
517             return VMEXIT_VMPTRLD_STR;
518         case VMEXIT_VMPTRST:
519             return VMEXIT_VMPTRST_STR;
520         case VMEXIT_VMREAD:
521             return VMEXIT_VMREAD_STR;
522         case VMEXIT_VMRESUME:
523             return VMEXIT_VMRESUME_STR;
524         case VMEXIT_VMWRITE:
525             return VMEXIT_VMWRITE_STR;
526         case VMEXIT_VMXOFF:
527             return VMEXIT_VMXOFF_STR;
528         case VMEXIT_VMXON:
529             return VMEXIT_VMXON_STR;
530         case VMEXIT_CR_REG_ACCESSES:
531             return VMEXIT_CR_REG_ACCESSES_STR;
532         case VMEXIT_MOV_DR:
533             return VMEXIT_MOV_DR_STR;
534         case VMEXIT_IO_INSTR:
535             return VMEXIT_IO_INSTR_STR;
536         case VMEXIT_RDMSR:
537             return VMEXIT_RDMSR_STR;
538         case VMEXIT_WRMSR:
539             return VMEXIT_WRMSR_STR;
540         case VMEXIT_ENTRY_FAIL_INVALID_GUEST_STATE:
541             return VMEXIT_ENTRY_FAIL_INVALID_GUEST_STATE_STR;
542         case VMEXIT_ENTRY_FAIL_MSR_LOAD:
543             return VMEXIT_ENTRY_FAIL_MSR_LOAD_STR;
544         case VMEXIT_MWAIT:
545             return VMEXIT_MWAIT_STR;
546         case VMEXIT_MONITOR:
547             return VMEXIT_MONITOR_STR;
548         case VMEXIT_PAUSE:
549             return VMEXIT_PAUSE_STR;
550         case VMEXIT_ENTRY_FAILURE_MACHINE_CHECK:
551             return VMEXIT_ENTRY_FAILURE_MACHINE_CHECK_STR;
552         case VMEXIT_TPR_BELOW_THRESHOLD:
553             return VMEXIT_TPR_BELOW_THRESHOLD_STR;
554         case VMEXIT_APIC:
555             return VMEXIT_APIC_STR;
556         case VMEXIT_GDTR_IDTR:
557             return VMEXIT_GDTR_IDTR_STR;
558         case VMEXIT_LDTR_TR:
559             return VMEXIT_LDTR_TR_STR;
560         case VMEXIT_EPT_VIOLATION:
561             return VMEXIT_EPT_VIOLATION_STR;
562         case VMEXIT_EPT_CONFIG:
563             return VMEXIT_EPT_CONFIG_STR;
564         case VMEXIT_INVEPT:
565             return VMEXIT_INVEPT_STR;
566         case VMEXIT_RDTSCP:
567             return VMEXIT_RDTSCP_STR;
568         case VMEXIT_EXPIRED_PREEMPT_TIMER:
569             return VMEXIT_EXPIRED_PREEMPT_TIMER_STR;
570         case VMEXIT_INVVPID:
571             return VMEXIT_INVVPID_STR;
572         case VMEXIT_WBINVD:
573             return VMEXIT_WBINVD_STR;
574         case VMEXIT_XSETBV:
575             return VMEXIT_XSETBV_STR;
576     }
577     return NULL;
578 }
579