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 VMX handler for the preempt timer so that we don't just crash if we get it.
[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 V3_CONFIG_DEBUG_VMX
37 #undef PrintDebug
38 #define PrintDebug(fmt, args...)
39 #endif
40
41 #ifdef V3_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 V3_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 V3_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 if ((uint8_t)exit_info->int_info == 2) {
106                 // NMI. Don't do anything
107                 V3_Print("NMI Exception Received\n");
108             } else {
109                 PrintError("Unknown exception: 0x%x\n", (uint8_t)exit_info->int_info);
110                 v3_print_GPRs(info);
111                 return -1;
112             }
113             break;
114         }
115
116         case VMEXIT_EPT_VIOLATION: {
117             struct ept_exit_qual * ept_qual = (struct ept_exit_qual *)&(exit_info->exit_qual);
118
119             if (v3_handle_ept_fault(info, exit_info->ept_fault_addr, ept_qual) == -1) {
120                 PrintError("Error handling EPT fault\n");
121                 return -1;
122             }
123
124             break;
125         }
126         case VMEXIT_INVLPG:
127             if (info->shdw_pg_mode == SHADOW_PAGING) {
128                 if (v3_handle_shadow_invlpg(info) == -1) {
129                     PrintError("Error handling INVLPG\n");
130                     return -1;
131                 }
132             }
133
134             break;
135
136         case VMEXIT_RDTSC:
137 #ifdef V3_CONFIG_DEBUG_TIME
138             PrintDebug("RDTSC\n");
139 #endif 
140             if (v3_handle_rdtsc(info) == -1) {
141                 PrintError("Error Handling RDTSC instruction\n");
142                 return -1;
143             }
144             
145             break;
146
147         case VMEXIT_CPUID:
148             if (v3_handle_cpuid(info) == -1) {
149                 PrintError("Error Handling CPUID instruction\n");
150                 return -1;
151             }
152
153             break;
154         case VMEXIT_RDMSR: 
155             if (v3_handle_msr_read(info) == -1) {
156                 PrintError("Error handling MSR Read\n");
157                 return -1;
158             }
159
160             break;
161         case VMEXIT_WRMSR:
162             if (v3_handle_msr_write(info) == -1) {
163                 PrintError("Error handling MSR Write\n");
164                 return -1;
165             }
166
167             break;
168         case VMEXIT_VMCALL:
169             /* 
170              * Hypercall 
171              */
172
173             // VMCALL is a 3 byte op
174             // We do this early because some hypercalls can change the rip...
175             info->rip += 3;         
176
177             if (v3_handle_hypercall(info) == -1) {
178                 return -1;
179             }
180             break;
181         case VMEXIT_IO_INSTR: {
182             struct vmx_exit_io_qual * io_qual = (struct vmx_exit_io_qual *)&(exit_info->exit_qual);
183
184             if (io_qual->dir == 0) {
185                 if (io_qual->string) {
186                     if (v3_handle_vmx_io_outs(info, exit_info) == -1) {
187                         PrintError("Error in outs IO handler\n");
188                         return -1;
189                     }
190                 } else {
191                     if (v3_handle_vmx_io_out(info, exit_info) == -1) {
192                         PrintError("Error in out IO handler\n");
193                         return -1;
194                     }
195                 }
196             } else {
197                 if (io_qual->string) {
198                     if(v3_handle_vmx_io_ins(info, exit_info) == -1) {
199                         PrintError("Error in ins IO handler\n");
200                         return -1;
201                     }
202                 } else {
203                     if (v3_handle_vmx_io_in(info, exit_info) == -1) {
204                         PrintError("Error in in IO handler\n");
205                         return -1;
206                     }
207                 }
208             }
209             break;
210         }
211         case VMEXIT_CR_REG_ACCESSES: {
212             struct vmx_exit_cr_qual * cr_qual = (struct vmx_exit_cr_qual *)&(exit_info->exit_qual);
213             
214             // PrintDebug("Control register: %d\n", cr_qual->access_type);
215             switch(cr_qual->cr_id) {
216                 case 0:
217                     //PrintDebug("Handling CR0 Access\n");
218                     if (v3_vmx_handle_cr0_access(info, cr_qual, exit_info) == -1) {
219                         PrintError("Error in CR0 access handler\n");
220                         return -1;
221                     }
222                     break;
223                 case 3:
224                     //PrintDebug("Handling CR3 Access\n");
225                     if (v3_vmx_handle_cr3_access(info, cr_qual) == -1) {
226                         PrintError("Error in CR3 access handler\n");
227                         return -1;
228                     }
229                     break;
230                 case 4:
231                     //PrintDebug("Handling CR4 Access\n");
232                     if (v3_vmx_handle_cr4_access(info, cr_qual) == -1) {
233                         PrintError("Error in CR4 access handler\n");
234                         return -1;
235                     }
236                     break;
237                 default:
238                     PrintError("Unhandled CR access: %d\n", cr_qual->cr_id);
239                     return -1;
240             }
241             
242             // TODO: move RIP increment into all of the above individual CR
243             //       handlers, not just v3_vmx_handle_cr4_access()
244             if (cr_qual->cr_id != 4)
245                 info->rip += exit_info->instr_len;
246
247             break;
248         }
249         case VMEXIT_HLT:
250             PrintDebug("Guest halted\n");
251
252             if (v3_handle_halt(info) == -1) {
253                 PrintError("Error handling halt instruction\n");
254                 return -1;
255             }
256
257             break;
258
259
260
261         case VMEXIT_PAUSE:
262             // Handled as NOP
263             info->rip += 2;
264
265             break;
266         case VMEXIT_EXTERNAL_INTR:
267             // Interrupts are handled outside switch
268             break;
269         case VMEXIT_INTR_WINDOW:
270             // This is handled in the atomic part of the vmx code,
271             // not in the generic (interruptable) vmx handler
272             break;
273         case VMEXIT_EXPIRED_PREEMPT_TIMER:
274             V3_Print("VMX Preempt Timer Expired.\n");
275             // This just forces an exit and is handled outside the switch
276             break;
277             
278         default:
279             PrintError("Unhandled VMEXIT: %s (%u), %lu (0x%lx)\n", 
280                        v3_vmx_exit_code_to_str(basic_info->reason),
281                        basic_info->reason, 
282                        exit_info->exit_qual, exit_info->exit_qual);
283             return -1;
284     }
285
286
287 #ifdef V3_CONFIG_TELEMETRY
288     if (info->vm_info->enable_telemetry) {
289         v3_telemetry_end_exit(info, exit_info->exit_reason);
290     }
291 #endif
292
293
294     return 0;
295 }
296
297 static const char VMEXIT_INFO_EXCEPTION_OR_NMI_STR[] = "VMEXIT_INFO_EXCEPTION_OR_NMI";
298 static const char VMEXIT_EXTERNAL_INTR_STR[] = "VMEXIT_EXTERNAL_INTR";
299 static const char VMEXIT_TRIPLE_FAULT_STR[] = "VMEXIT_TRIPLE_FAULT";
300 static const char VMEXIT_INIT_SIGNAL_STR[] = "VMEXIT_INIT_SIGNAL";
301 static const char VMEXIT_STARTUP_IPI_STR[] = "VMEXIT_STARTUP_IPI";
302 static const char VMEXIT_IO_SMI_STR[] = "VMEXIT_IO_SMI";
303 static const char VMEXIT_OTHER_SMI_STR[] = "VMEXIT_OTHER_SMI";
304 static const char VMEXIT_INTR_WINDOW_STR[] = "VMEXIT_INTR_WINDOW";
305 static const char VMEXIT_NMI_WINDOW_STR[] = "VMEXIT_NMI_WINDOW";
306 static const char VMEXIT_TASK_SWITCH_STR[] = "VMEXIT_TASK_SWITCH";
307 static const char VMEXIT_CPUID_STR[] = "VMEXIT_CPUID";
308 static const char VMEXIT_HLT_STR[] = "VMEXIT_HLT";
309 static const char VMEXIT_INVD_STR[] = "VMEXIT_INVD";
310 static const char VMEXIT_INVLPG_STR[] = "VMEXIT_INVLPG";
311 static const char VMEXIT_RDPMC_STR[] = "VMEXIT_RDPMC";
312 static const char VMEXIT_RDTSC_STR[] = "VMEXIT_RDTSC";
313 static const char VMEXIT_RSM_STR[] = "VMEXIT_RSM";
314 static const char VMEXIT_VMCALL_STR[] = "VMEXIT_VMCALL";
315 static const char VMEXIT_VMCLEAR_STR[] = "VMEXIT_VMCLEAR";
316 static const char VMEXIT_VMLAUNCH_STR[] = "VMEXIT_VMLAUNCH";
317 static const char VMEXIT_VMPTRLD_STR[] = "VMEXIT_VMPTRLD";
318 static const char VMEXIT_VMPTRST_STR[] = "VMEXIT_VMPTRST";
319 static const char VMEXIT_VMREAD_STR[] = "VMEXIT_VMREAD";
320 static const char VMEXIT_VMRESUME_STR[] = "VMEXIT_VMRESUME";
321 static const char VMEXIT_VMWRITE_STR[] = "VMEXIT_VMWRITE";
322 static const char VMEXIT_VMXOFF_STR[] = "VMEXIT_VMXOFF";
323 static const char VMEXIT_VMXON_STR[] = "VMEXIT_VMXON";
324 static const char VMEXIT_CR_REG_ACCESSES_STR[] = "VMEXIT_CR_REG_ACCESSES";
325 static const char VMEXIT_MOV_DR_STR[] = "VMEXIT_MOV_DR";
326 static const char VMEXIT_IO_INSTR_STR[] = "VMEXIT_IO_INSTR";
327 static const char VMEXIT_RDMSR_STR[] = "VMEXIT_RDMSR";
328 static const char VMEXIT_WRMSR_STR[] = "VMEXIT_WRMSR";
329 static const char VMEXIT_INVALID_GUEST_STATE_STR[] = "VMEXIT_INVALID_GUEST_STATE";
330 static const char VMEXIT_INVALID_MSR_LOAD_STR[] = "VMEXIT_INVALID_MSR_LOAD";
331 static const char VMEXIT_MWAIT_STR[] = "VMEXIT_MWAIT";
332 static const char VMEXIT_MONITOR_STR[] = "VMEXIT_MONITOR";
333 static const char VMEXIT_PAUSE_STR[] = "VMEXIT_PAUSE";
334 static const char VMEXIT_INVALID_MACHINE_CHECK_STR[] = "VMEXIT_INVALIDE_MACHINE_CHECK";
335 static const char VMEXIT_TPR_BELOW_THRESHOLD_STR[] = "VMEXIT_TPR_BELOW_THRESHOLD";
336 static const char VMEXIT_APIC_STR[] = "VMEXIT_APIC";
337 static const char VMEXIT_GDTR_IDTR_STR[] = "VMEXIT_GDTR_IDTR";
338 static const char VMEXIT_LDTR_TR_STR[] = "VMEXIT_LDTR_TR";
339 static const char VMEXIT_EPT_VIOLATION_STR[] = "VMEXIT_EPT_VIOLATION";
340 static const char VMEXIT_EPT_CONFIG_STR[] = "VMEXIT_EPT_CONFIG";
341 static const char VMEXIT_INVEPT_STR[] = "VMEXIT_INVEPT";
342 static const char VMEXIT_RDTSCP_STR[] = "VMEXIT_RDTSCP";
343 static const char VMEXIT_EXPIRED_PREEMPT_TIMER_STR[] = "VMEXIT_EXPIRED_PREEMPT_TIMER";
344 static const char VMEXIT_INVVPID_STR[] = "VMEXIT_INVVPID";
345 static const char VMEXIT_WBINVD_STR[] = "VMEXIT_WBINVD";
346 static const char VMEXIT_XSETBV_STR[] = "VMEXIT_XSETBV";
347
348 const char * v3_vmx_exit_code_to_str(vmx_exit_t exit)
349 {
350     switch(exit) {
351         case VMEXIT_INFO_EXCEPTION_OR_NMI:
352             return VMEXIT_INFO_EXCEPTION_OR_NMI_STR;
353         case VMEXIT_EXTERNAL_INTR:
354             return VMEXIT_EXTERNAL_INTR_STR;
355         case VMEXIT_TRIPLE_FAULT:
356             return VMEXIT_TRIPLE_FAULT_STR;
357         case VMEXIT_INIT_SIGNAL:
358             return VMEXIT_INIT_SIGNAL_STR;
359         case VMEXIT_STARTUP_IPI:
360             return VMEXIT_STARTUP_IPI_STR;
361         case VMEXIT_IO_SMI:
362             return VMEXIT_IO_SMI_STR;
363         case VMEXIT_OTHER_SMI:
364             return VMEXIT_OTHER_SMI_STR;
365         case VMEXIT_INTR_WINDOW:
366             return VMEXIT_INTR_WINDOW_STR;
367         case VMEXIT_NMI_WINDOW:
368             return VMEXIT_NMI_WINDOW_STR;
369         case VMEXIT_TASK_SWITCH:
370             return VMEXIT_TASK_SWITCH_STR;
371         case VMEXIT_CPUID:
372             return VMEXIT_CPUID_STR;
373         case VMEXIT_HLT:
374             return VMEXIT_HLT_STR;
375         case VMEXIT_INVD:
376             return VMEXIT_INVD_STR;
377         case VMEXIT_INVLPG:
378             return VMEXIT_INVLPG_STR;
379         case VMEXIT_RDPMC:
380             return VMEXIT_RDPMC_STR;
381         case VMEXIT_RDTSC:
382             return VMEXIT_RDTSC_STR;
383         case VMEXIT_RSM:
384             return VMEXIT_RSM_STR;
385         case VMEXIT_VMCALL:
386             return VMEXIT_VMCALL_STR;
387         case VMEXIT_VMCLEAR:
388             return VMEXIT_VMCLEAR_STR;
389         case VMEXIT_VMLAUNCH:
390             return VMEXIT_VMLAUNCH_STR;
391         case VMEXIT_VMPTRLD:
392             return VMEXIT_VMPTRLD_STR;
393         case VMEXIT_VMPTRST:
394             return VMEXIT_VMPTRST_STR;
395         case VMEXIT_VMREAD:
396             return VMEXIT_VMREAD_STR;
397         case VMEXIT_VMRESUME:
398             return VMEXIT_VMRESUME_STR;
399         case VMEXIT_VMWRITE:
400             return VMEXIT_VMWRITE_STR;
401         case VMEXIT_VMXOFF:
402             return VMEXIT_VMXOFF_STR;
403         case VMEXIT_VMXON:
404             return VMEXIT_VMXON_STR;
405         case VMEXIT_CR_REG_ACCESSES:
406             return VMEXIT_CR_REG_ACCESSES_STR;
407         case VMEXIT_MOV_DR:
408             return VMEXIT_MOV_DR_STR;
409         case VMEXIT_IO_INSTR:
410             return VMEXIT_IO_INSTR_STR;
411         case VMEXIT_RDMSR:
412             return VMEXIT_RDMSR_STR;
413         case VMEXIT_WRMSR:
414             return VMEXIT_WRMSR_STR;
415         case VMEXIT_INVALID_GUEST_STATE:
416             return VMEXIT_INVALID_GUEST_STATE_STR;
417         case VMEXIT_INVALID_MSR_LOAD:
418             return VMEXIT_INVALID_MSR_LOAD_STR;
419         case VMEXIT_MWAIT:
420             return VMEXIT_MWAIT_STR;
421         case VMEXIT_MONITOR:
422             return VMEXIT_MONITOR_STR;
423         case VMEXIT_PAUSE:
424             return VMEXIT_PAUSE_STR;
425         case VMEXIT_INVALID_MACHINE_CHECK:
426             return VMEXIT_INVALID_MACHINE_CHECK_STR;
427         case VMEXIT_TPR_BELOW_THRESHOLD:
428             return VMEXIT_TPR_BELOW_THRESHOLD_STR;
429         case VMEXIT_APIC:
430             return VMEXIT_APIC_STR;
431         case VMEXIT_GDTR_IDTR:
432             return VMEXIT_GDTR_IDTR_STR;
433         case VMEXIT_LDTR_TR:
434             return VMEXIT_LDTR_TR_STR;
435         case VMEXIT_EPT_VIOLATION:
436             return VMEXIT_EPT_VIOLATION_STR;
437         case VMEXIT_EPT_CONFIG:
438             return VMEXIT_EPT_CONFIG_STR;
439         case VMEXIT_INVEPT:
440             return VMEXIT_INVEPT_STR;
441         case VMEXIT_RDTSCP:
442             return VMEXIT_RDTSCP_STR;
443         case VMEXIT_EXPIRED_PREEMPT_TIMER:
444             return VMEXIT_EXPIRED_PREEMPT_TIMER_STR;
445         case VMEXIT_INVVPID:
446             return VMEXIT_INVVPID_STR;
447         case VMEXIT_WBINVD:
448             return VMEXIT_WBINVD_STR;
449         case VMEXIT_XSETBV:
450             return VMEXIT_XSETBV_STR;
451     }
452     return NULL;
453 }
454