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 support for Intel EPT with(?) and without unrestricted guest support
[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 #include <palacios/vmx_ept.h>
35
36 #ifndef CONFIG_DEBUG_VMX
37 #undef PrintDebug
38 #define PrintDebug(fmt, args...)
39 #endif
40
41 #ifdef CONFIG_TELEMETRY
42 #include <palacios/vmm_telemetry.h>
43 #endif
44
45 /* At this point the GPRs are already copied into the guest_info state */
46 int v3_handle_vmx_exit(struct guest_info * info, struct vmx_exit_info * exit_info) {
47     struct vmx_basic_exit_info * basic_info = (struct vmx_basic_exit_info *)&(exit_info->exit_reason);
48
49     /*
50       PrintError("Handling VMEXIT: %s (%u), %lu (0x%lx)\n", 
51       v3_vmx_exit_code_to_str(exit_info->exit_reason),
52       exit_info->exit_reason, 
53       exit_info->exit_qual, exit_info->exit_qual);
54       
55       v3_print_vmcs();
56     */
57
58
59     if (basic_info->entry_error == 1) {
60         switch (basic_info->reason) {
61             case VMEXIT_INVALID_GUEST_STATE:
62                 PrintError("VM Entry failed due to invalid guest state\n");
63                 PrintError("Printing VMCS: (NOTE: This VMCS may not belong to the correct guest)\n");
64                 v3_print_vmcs();
65                 break;
66             case VMEXIT_INVALID_MSR_LOAD:
67                 PrintError("VM Entry failed due to error loading MSRs\n");
68                 break;
69             default:
70                 PrintError("Entry failed for unknown reason (%d)\n", basic_info->reason);
71                 break;
72         }
73         
74         return -1;
75     }
76
77
78 #ifdef CONFIG_TELEMETRY
79     if (info->vm_info->enable_telemetry) {
80         v3_telemetry_start_exit(info);
81     }
82 #endif
83
84     switch (basic_info->reason) {
85         case VMEXIT_INFO_EXCEPTION_OR_NMI: {
86             pf_error_t error_code = *(pf_error_t *)&(exit_info->int_err);
87
88
89             // JRL: Change "0x0e" to a macro value
90             if ((uint8_t)exit_info->int_info == 14) {
91 #ifdef CONFIG_DEBUG_SHADOW_PAGING
92                 PrintDebug("Page Fault at %p error_code=%x\n", (void *)exit_info->exit_qual, *(uint32_t *)&error_code);
93 #endif
94
95                 if (info->shdw_pg_mode == SHADOW_PAGING) {
96                     if (v3_handle_shadow_pagefault(info, (addr_t)exit_info->exit_qual, error_code) == -1) {
97                         PrintError("Error handling shadow page fault\n");
98                         return -1;
99                     }
100             
101                 } else {
102                     PrintError("Page fault in unimplemented paging mode\n");
103                     return -1;
104                 }
105             } else {
106                 PrintError("Unknown exception: 0x%x\n", (uint8_t)exit_info->int_info);
107                 v3_print_GPRs(info);
108                 return -1;
109             }
110             break;
111         }
112
113         case VMEXIT_EPT_VIOLATION: {
114             struct ept_exit_qual * ept_qual = (struct ept_exit_qual *)&(exit_info->exit_qual);
115
116             if (v3_handle_ept_fault(info, exit_info->ept_fault_addr, ept_qual) == -1) {
117                 PrintError("Error handling EPT fault\n");
118                 return -1;
119             }
120
121             break;
122         }
123         case VMEXIT_INVLPG:
124             if (info->shdw_pg_mode == SHADOW_PAGING) {
125                 if (v3_handle_shadow_invlpg(info) == -1) {
126                     PrintError("Error handling INVLPG\n");
127                     return -1;
128                 }
129             }
130
131             break;
132
133         case VMEXIT_RDTSC:
134 #ifdef CONFIG_DEBUG_TIME
135             PrintDebug("RDTSC\n");
136 #endif 
137             if (v3_handle_rdtsc(info) == -1) {
138                 PrintError("Error Handling RDTSC instruction\n");
139                 return -1;
140             }
141             
142             break;
143
144         case VMEXIT_CPUID:
145             if (v3_handle_cpuid(info) == -1) {
146                 PrintError("Error Handling CPUID instruction\n");
147                 return -1;
148             }
149
150             break;
151         case VMEXIT_RDMSR: 
152             if (v3_handle_msr_read(info) == -1) {
153                 PrintError("Error handling MSR Read\n");
154                 return -1;
155             }
156
157             break;
158         case VMEXIT_WRMSR:
159             if (v3_handle_msr_write(info) == -1) {
160                 PrintError("Error handling MSR Write\n");
161                 return -1;
162             }
163
164             break;
165         case VMEXIT_VMCALL:
166             /* 
167              * Hypercall 
168              */
169
170             // VMCALL is a 3 byte op
171             // We do this early because some hypercalls can change the rip...
172             info->rip += 3;         
173
174             if (v3_handle_hypercall(info) == -1) {
175                 return -1;
176             }
177             break;
178         case VMEXIT_IO_INSTR: {
179             struct vmx_exit_io_qual * io_qual = (struct vmx_exit_io_qual *)&(exit_info->exit_qual);
180
181             if (io_qual->dir == 0) {
182                 if (io_qual->string) {
183                     if (v3_handle_vmx_io_outs(info, exit_info) == -1) {
184                         PrintError("Error in outs IO handler\n");
185                         return -1;
186                     }
187                 } else {
188                     if (v3_handle_vmx_io_out(info, exit_info) == -1) {
189                         PrintError("Error in out IO handler\n");
190                         return -1;
191                     }
192                 }
193             } else {
194                 if (io_qual->string) {
195                     if(v3_handle_vmx_io_ins(info, exit_info) == -1) {
196                         PrintError("Error in ins IO handler\n");
197                         return -1;
198                     }
199                 } else {
200                     if (v3_handle_vmx_io_in(info, exit_info) == -1) {
201                         PrintError("Error in in IO handler\n");
202                         return -1;
203                     }
204                 }
205             }
206             break;
207         }
208         case VMEXIT_CR_REG_ACCESSES: {
209             struct vmx_exit_cr_qual * cr_qual = (struct vmx_exit_cr_qual *)&(exit_info->exit_qual);
210             
211             // PrintDebug("Control register: %d\n", cr_qual->access_type);
212             switch(cr_qual->cr_id) {
213                 case 0:
214                     //PrintDebug("Handling CR0 Access\n");
215                     if (v3_vmx_handle_cr0_access(info, cr_qual, exit_info) == -1) {
216                         PrintError("Error in CR0 access handler\n");
217                         return -1;
218                     }
219                     break;
220                 case 3:
221                     //PrintDebug("Handling CR3 Access\n");
222                     if (v3_vmx_handle_cr3_access(info, cr_qual) == -1) {
223                         PrintError("Error in CR3 access handler\n");
224                         return -1;
225                     }
226                     break;
227                 default:
228                     PrintError("Unhandled CR access: %d\n", cr_qual->cr_id);
229                     return -1;
230             }
231             
232             info->rip += exit_info->instr_len;
233
234             break;
235         }
236         case VMEXIT_HLT:
237             PrintDebug("Guest halted\n");
238
239             if (v3_handle_halt(info) == -1) {
240                 PrintError("Error handling halt instruction\n");
241                 return -1;
242             }
243
244             break;
245
246
247
248         case VMEXIT_PAUSE:
249             // Handled as NOP
250             info->rip += 2;
251
252             break;
253         case VMEXIT_EXTERNAL_INTR:
254             // Interrupts are handled outside switch
255             break;
256         case VMEXIT_INTR_WINDOW:
257             // This is handled in the atomic part of the vmx code,
258             // not in the generic (interruptable) vmx handler
259             break;
260
261             
262         default:
263             PrintError("Unhandled VMEXIT: %s (%u), %lu (0x%lx)\n", 
264                        v3_vmx_exit_code_to_str(basic_info->reason),
265                        basic_info->reason, 
266                        exit_info->exit_qual, exit_info->exit_qual);
267             return -1;
268     }
269
270
271 #ifdef CONFIG_TELEMETRY
272     if (info->vm_info->enable_telemetry) {
273         v3_telemetry_end_exit(info, exit_info->exit_reason);
274     }
275 #endif
276
277
278     return 0;
279 }
280
281 static const char VMEXIT_INFO_EXCEPTION_OR_NMI_STR[] = "VMEXIT_INFO_EXCEPTION_OR_NMI";
282 static const char VMEXIT_EXTERNAL_INTR_STR[] = "VMEXIT_EXTERNAL_INTR";
283 static const char VMEXIT_TRIPLE_FAULT_STR[] = "VMEXIT_TRIPLE_FAULT";
284 static const char VMEXIT_INIT_SIGNAL_STR[] = "VMEXIT_INIT_SIGNAL";
285 static const char VMEXIT_STARTUP_IPI_STR[] = "VMEXIT_STARTUP_IPI";
286 static const char VMEXIT_IO_SMI_STR[] = "VMEXIT_IO_SMI";
287 static const char VMEXIT_OTHER_SMI_STR[] = "VMEXIT_OTHER_SMI";
288 static const char VMEXIT_INTR_WINDOW_STR[] = "VMEXIT_INTR_WINDOW";
289 static const char VMEXIT_NMI_WINDOW_STR[] = "VMEXIT_NMI_WINDOW";
290 static const char VMEXIT_TASK_SWITCH_STR[] = "VMEXIT_TASK_SWITCH";
291 static const char VMEXIT_CPUID_STR[] = "VMEXIT_CPUID";
292 static const char VMEXIT_HLT_STR[] = "VMEXIT_HLT";
293 static const char VMEXIT_INVD_STR[] = "VMEXIT_INVD";
294 static const char VMEXIT_INVLPG_STR[] = "VMEXIT_INVLPG";
295 static const char VMEXIT_RDPMC_STR[] = "VMEXIT_RDPMC";
296 static const char VMEXIT_RDTSC_STR[] = "VMEXIT_RDTSC";
297 static const char VMEXIT_RSM_STR[] = "VMEXIT_RSM";
298 static const char VMEXIT_VMCALL_STR[] = "VMEXIT_VMCALL";
299 static const char VMEXIT_VMCLEAR_STR[] = "VMEXIT_VMCLEAR";
300 static const char VMEXIT_VMLAUNCH_STR[] = "VMEXIT_VMLAUNCH";
301 static const char VMEXIT_VMPTRLD_STR[] = "VMEXIT_VMPTRLD";
302 static const char VMEXIT_VMPTRST_STR[] = "VMEXIT_VMPTRST";
303 static const char VMEXIT_VMREAD_STR[] = "VMEXIT_VMREAD";
304 static const char VMEXIT_VMRESUME_STR[] = "VMEXIT_VMRESUME";
305 static const char VMEXIT_VMWRITE_STR[] = "VMEXIT_VMWRITE";
306 static const char VMEXIT_VMXOFF_STR[] = "VMEXIT_VMXOFF";
307 static const char VMEXIT_VMXON_STR[] = "VMEXIT_VMXON";
308 static const char VMEXIT_CR_REG_ACCESSES_STR[] = "VMEXIT_CR_REG_ACCESSES";
309 static const char VMEXIT_MOV_DR_STR[] = "VMEXIT_MOV_DR";
310 static const char VMEXIT_IO_INSTR_STR[] = "VMEXIT_IO_INSTR";
311 static const char VMEXIT_RDMSR_STR[] = "VMEXIT_RDMSR";
312 static const char VMEXIT_WRMSR_STR[] = "VMEXIT_WRMSR";
313 static const char VMEXIT_INVALID_GUEST_STATE_STR[] = "VMEXIT_INVALID_GUEST_STATE";
314 static const char VMEXIT_INVALID_MSR_LOAD_STR[] = "VMEXIT_INVALID_MSR_LOAD";
315 static const char VMEXIT_MWAIT_STR[] = "VMEXIT_MWAIT";
316 static const char VMEXIT_MONITOR_STR[] = "VMEXIT_MONITOR";
317 static const char VMEXIT_PAUSE_STR[] = "VMEXIT_PAUSE";
318 static const char VMEXIT_INVALID_MACHINE_CHECK_STR[] = "VMEXIT_INVALIDE_MACHINE_CHECK";
319 static const char VMEXIT_TPR_BELOW_THRESHOLD_STR[] = "VMEXIT_TPR_BELOW_THRESHOLD";
320 static const char VMEXIT_APIC_STR[] = "VMEXIT_APIC";
321 static const char VMEXIT_GDTR_IDTR_STR[] = "VMEXIT_GDTR_IDTR";
322 static const char VMEXIT_LDTR_TR_STR[] = "VMEXIT_LDTR_TR";
323 static const char VMEXIT_EPT_VIOLATION_STR[] = "VMEXIT_EPT_VIOLATION";
324 static const char VMEXIT_EPT_CONFIG_STR[] = "VMEXIT_EPT_CONFIG";
325 static const char VMEXIT_INVEPT_STR[] = "VMEXIT_INVEPT";
326 static const char VMEXIT_RDTSCP_STR[] = "VMEXIT_RDTSCP";
327 static const char VMEXIT_EXPIRED_PREEMPT_TIMER_STR[] = "VMEXIT_EXPIRED_PREEMPT_TIMER";
328 static const char VMEXIT_INVVPID_STR[] = "VMEXIT_INVVPID";
329 static const char VMEXIT_WBINVD_STR[] = "VMEXIT_WBINVD";
330 static const char VMEXIT_XSETBV_STR[] = "VMEXIT_XSETBV";
331
332 const char * v3_vmx_exit_code_to_str(vmx_exit_t exit)
333 {
334     switch(exit) {
335         case VMEXIT_INFO_EXCEPTION_OR_NMI:
336             return VMEXIT_INFO_EXCEPTION_OR_NMI_STR;
337         case VMEXIT_EXTERNAL_INTR:
338             return VMEXIT_EXTERNAL_INTR_STR;
339         case VMEXIT_TRIPLE_FAULT:
340             return VMEXIT_TRIPLE_FAULT_STR;
341         case VMEXIT_INIT_SIGNAL:
342             return VMEXIT_INIT_SIGNAL_STR;
343         case VMEXIT_STARTUP_IPI:
344             return VMEXIT_STARTUP_IPI_STR;
345         case VMEXIT_IO_SMI:
346             return VMEXIT_IO_SMI_STR;
347         case VMEXIT_OTHER_SMI:
348             return VMEXIT_OTHER_SMI_STR;
349         case VMEXIT_INTR_WINDOW:
350             return VMEXIT_INTR_WINDOW_STR;
351         case VMEXIT_NMI_WINDOW:
352             return VMEXIT_NMI_WINDOW_STR;
353         case VMEXIT_TASK_SWITCH:
354             return VMEXIT_TASK_SWITCH_STR;
355         case VMEXIT_CPUID:
356             return VMEXIT_CPUID_STR;
357         case VMEXIT_HLT:
358             return VMEXIT_HLT_STR;
359         case VMEXIT_INVD:
360             return VMEXIT_INVD_STR;
361         case VMEXIT_INVLPG:
362             return VMEXIT_INVLPG_STR;
363         case VMEXIT_RDPMC:
364             return VMEXIT_RDPMC_STR;
365         case VMEXIT_RDTSC:
366             return VMEXIT_RDTSC_STR;
367         case VMEXIT_RSM:
368             return VMEXIT_RSM_STR;
369         case VMEXIT_VMCALL:
370             return VMEXIT_VMCALL_STR;
371         case VMEXIT_VMCLEAR:
372             return VMEXIT_VMCLEAR_STR;
373         case VMEXIT_VMLAUNCH:
374             return VMEXIT_VMLAUNCH_STR;
375         case VMEXIT_VMPTRLD:
376             return VMEXIT_VMPTRLD_STR;
377         case VMEXIT_VMPTRST:
378             return VMEXIT_VMPTRST_STR;
379         case VMEXIT_VMREAD:
380             return VMEXIT_VMREAD_STR;
381         case VMEXIT_VMRESUME:
382             return VMEXIT_VMRESUME_STR;
383         case VMEXIT_VMWRITE:
384             return VMEXIT_VMWRITE_STR;
385         case VMEXIT_VMXOFF:
386             return VMEXIT_VMXOFF_STR;
387         case VMEXIT_VMXON:
388             return VMEXIT_VMXON_STR;
389         case VMEXIT_CR_REG_ACCESSES:
390             return VMEXIT_CR_REG_ACCESSES_STR;
391         case VMEXIT_MOV_DR:
392             return VMEXIT_MOV_DR_STR;
393         case VMEXIT_IO_INSTR:
394             return VMEXIT_IO_INSTR_STR;
395         case VMEXIT_RDMSR:
396             return VMEXIT_RDMSR_STR;
397         case VMEXIT_WRMSR:
398             return VMEXIT_WRMSR_STR;
399         case VMEXIT_INVALID_GUEST_STATE:
400             return VMEXIT_INVALID_GUEST_STATE_STR;
401         case VMEXIT_INVALID_MSR_LOAD:
402             return VMEXIT_INVALID_MSR_LOAD_STR;
403         case VMEXIT_MWAIT:
404             return VMEXIT_MWAIT_STR;
405         case VMEXIT_MONITOR:
406             return VMEXIT_MONITOR_STR;
407         case VMEXIT_PAUSE:
408             return VMEXIT_PAUSE_STR;
409         case VMEXIT_INVALID_MACHINE_CHECK:
410             return VMEXIT_INVALID_MACHINE_CHECK_STR;
411         case VMEXIT_TPR_BELOW_THRESHOLD:
412             return VMEXIT_TPR_BELOW_THRESHOLD_STR;
413         case VMEXIT_APIC:
414             return VMEXIT_APIC_STR;
415         case VMEXIT_GDTR_IDTR:
416             return VMEXIT_GDTR_IDTR_STR;
417         case VMEXIT_LDTR_TR:
418             return VMEXIT_LDTR_TR_STR;
419         case VMEXIT_EPT_VIOLATION:
420             return VMEXIT_EPT_VIOLATION_STR;
421         case VMEXIT_EPT_CONFIG:
422             return VMEXIT_EPT_CONFIG_STR;
423         case VMEXIT_INVEPT:
424             return VMEXIT_INVEPT_STR;
425         case VMEXIT_RDTSCP:
426             return VMEXIT_RDTSCP_STR;
427         case VMEXIT_EXPIRED_PREEMPT_TIMER:
428             return VMEXIT_EXPIRED_PREEMPT_TIMER_STR;
429         case VMEXIT_INVVPID:
430             return VMEXIT_INVVPID_STR;
431         case VMEXIT_WBINVD:
432             return VMEXIT_WBINVD_STR;
433         case VMEXIT_XSETBV:
434             return VMEXIT_XSETBV_STR;
435     }
436     return NULL;
437 }
438