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.


APIC and CR8 changes for vector priorization vs TPR
[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 #include <palacios/vmm_debug.h>
28
29 #include <palacios/vmx.h>
30 #include <palacios/vmm_ctrl_regs.h>
31 #include <palacios/vmm_lowlevel.h>
32 #include <palacios/vmx_ctrl_regs.h>
33 #include <palacios/vmx_assist.h>
34 #include <palacios/vmm_halt.h>
35 #include <palacios/vmx_ept.h>
36
37
38 #ifndef V3_CONFIG_DEBUG_VMX
39 #undef PrintDebug
40 #define PrintDebug(fmt, args...)
41 #endif
42
43 #ifdef V3_CONFIG_TELEMETRY
44 #include <palacios/vmm_telemetry.h>
45 #endif
46
47 /* At this point the GPRs are already copied into the guest_info state */
48 int v3_handle_vmx_exit(struct guest_info * info, struct vmx_exit_info * exit_info) {
49     struct vmx_basic_exit_info * basic_info = (struct vmx_basic_exit_info *)&(exit_info->exit_reason);
50
51     /*
52       PrintError("Handling VMX_EXIT: %s (%u), %lu (0x%lx)\n", 
53       v3_vmx_exit_code_to_str(exit_info->exit_reason),
54       exit_info->exit_reason, 
55       exit_info->exit_qual, exit_info->exit_qual);
56       
57       v3_print_vmcs();
58     */
59
60
61     if (basic_info->entry_error == 1) {
62         switch (basic_info->reason) {
63             case VMX_EXIT_INVALID_GUEST_STATE:
64                 PrintError("VM Entry failed due to invalid guest state\n");
65                 PrintError("Printing VMCS: (NOTE: This VMCS may not belong to the correct guest)\n");
66                 v3_print_vmcs();
67                 break;
68             case VMX_EXIT_INVALID_MSR_LOAD:
69                 PrintError("VM Entry failed due to error loading MSRs\n");
70                 break;
71             default:
72                 PrintError("Entry failed for unknown reason (%d)\n", basic_info->reason);
73                 break;
74         }
75         
76         return -1;
77     }
78
79
80
81 #ifdef V3_CONFIG_TELEMETRY
82     if (info->vm_info->enable_telemetry) {
83         v3_telemetry_start_exit(info);
84     }
85 #endif
86
87     switch (basic_info->reason) {
88         case VMX_EXIT_INFO_EXCEPTION_OR_NMI: {
89             pf_error_t error_code = *(pf_error_t *)&(exit_info->int_err);
90
91
92             // JRL: Change "0x0e" to a macro value
93             if ((uint8_t)exit_info->int_info == 14) {
94 #ifdef V3_CONFIG_DEBUG_SHADOW_PAGING
95                 PrintDebug("Page Fault at %p error_code=%x\n", (void *)exit_info->exit_qual, *(uint32_t *)&error_code);
96 #endif
97
98                 if (info->shdw_pg_mode == SHADOW_PAGING) {
99                     if (v3_handle_shadow_pagefault(info, (addr_t)exit_info->exit_qual, error_code) == -1) {
100                         PrintError("Error handling shadow page fault\n");
101                         return -1;
102                     }
103             
104                 } else {
105                     PrintError("Page fault in unimplemented paging mode\n");
106                     return -1;
107                 }
108             } else if ((uint8_t)exit_info->int_info == 2) {
109                 // NMI. Don't do anything
110                 V3_Print("NMI Exception Received\n");
111             } else {
112                 PrintError("Unknown exception: 0x%x\n", (uint8_t)exit_info->int_info);
113                 v3_print_GPRs(info);
114                 return -1;
115             }
116             break;
117         }
118
119         case VMX_EXIT_EPT_VIOLATION: {
120             struct ept_exit_qual * ept_qual = (struct ept_exit_qual *)&(exit_info->exit_qual);
121
122             if (v3_handle_ept_fault(info, exit_info->ept_fault_addr, ept_qual) == -1) {
123                 PrintError("Error handling EPT fault\n");
124                 return -1;
125             }
126
127             break;
128         }
129         case VMX_EXIT_INVLPG:
130             if (info->shdw_pg_mode == SHADOW_PAGING) {
131                 if (v3_handle_shadow_invlpg(info) == -1) {
132                     PrintError("Error handling INVLPG\n");
133                     return -1;
134                 }
135             }
136
137             break;
138
139         case VMX_EXIT_RDTSC:
140 #ifdef V3_CONFIG_DEBUG_TIME
141             PrintDebug("RDTSC\n");
142 #endif 
143             if (v3_handle_rdtsc(info) == -1) {
144                 PrintError("Error Handling RDTSC instruction\n");
145                 return -1;
146             }
147             
148             break;
149
150         case VMX_EXIT_CPUID:
151             if (v3_handle_cpuid(info) == -1) {
152                 PrintError("Error Handling CPUID instruction\n");
153                 return -1;
154             }
155
156             break;
157         case VMX_EXIT_RDMSR: 
158             if (v3_handle_msr_read(info) == -1) {
159                 PrintError("Error handling MSR Read\n");
160                 return -1;
161             }
162
163             break;
164         case VMX_EXIT_WRMSR:
165             if (v3_handle_msr_write(info) == -1) {
166                 PrintError("Error handling MSR Write\n");
167                 return -1;
168             }
169
170             break;
171         case VMX_EXIT_VMCALL:
172             /* 
173              * Hypercall 
174              */
175
176             // VMCALL is a 3 byte op
177             // We do this early because some hypercalls can change the rip...
178             info->rip += 3;         
179
180             if (v3_handle_hypercall(info) == -1) {
181                 return -1;
182             }
183             break;
184         case VMX_EXIT_IO_INSTR: {
185             struct vmx_exit_io_qual * io_qual = (struct vmx_exit_io_qual *)&(exit_info->exit_qual);
186
187             if (io_qual->dir == 0) {
188                 if (io_qual->string) {
189                     if (v3_handle_vmx_io_outs(info, exit_info) == -1) {
190                         PrintError("Error in outs IO handler\n");
191                         return -1;
192                     }
193                 } else {
194                     if (v3_handle_vmx_io_out(info, exit_info) == -1) {
195                         PrintError("Error in out IO handler\n");
196                         return -1;
197                     }
198                 }
199             } else {
200                 if (io_qual->string) {
201                     if(v3_handle_vmx_io_ins(info, exit_info) == -1) {
202                         PrintError("Error in ins IO handler\n");
203                         return -1;
204                     }
205                 } else {
206                     if (v3_handle_vmx_io_in(info, exit_info) == -1) {
207                         PrintError("Error in in IO handler\n");
208                         return -1;
209                     }
210                 }
211             }
212             break;
213         }
214         case VMX_EXIT_CR_REG_ACCESSES: {
215             struct vmx_exit_cr_qual * cr_qual = (struct vmx_exit_cr_qual *)&(exit_info->exit_qual);
216             
217             // PrintDebug("Control register: %d\n", cr_qual->access_type);
218             switch(cr_qual->cr_id) {
219                 case 0:
220                     //PrintDebug("Handling CR0 Access\n");
221                     if (v3_vmx_handle_cr0_access(info, cr_qual, exit_info) == -1) {
222                         PrintError("Error in CR0 access handler\n");
223                         return -1;
224                     }
225                     break;
226                 case 3:
227                     //PrintDebug("Handling CR3 Access\n");
228                     if (v3_vmx_handle_cr3_access(info, cr_qual) == -1) {
229                         PrintError("Error in CR3 access handler\n");
230                         return -1;
231                     }
232                     break;
233                 case 4:
234                     //PrintDebug("Handling CR4 Access\n");
235                     if (v3_vmx_handle_cr4_access(info, cr_qual) == -1) {
236                         PrintError("Error in CR4 access handler\n");
237                         return -1;
238                     }
239                     break;
240                 case 8:
241                     if (v3_vmx_handle_cr8_access(info, cr_qual) == -1) {
242                         PrintError("Error in CR8 access handler\n");
243                         return -1;
244                     }
245                     break;
246                 default:
247                     PrintError("Unhandled CR access: %d\n", cr_qual->cr_id);
248                     return -1;
249             }
250             
251             // TODO: move RIP increment into all of the above individual CR
252             //       handlers, not just v3_vmx_handle_cr4_access()
253             if (cr_qual->cr_id != 4)
254                 info->rip += exit_info->instr_len;
255
256             break;
257         }
258         case VMX_EXIT_HLT:
259             PrintDebug("Guest halted\n");
260
261             if (v3_handle_halt(info) == -1) {
262                 PrintError("Error handling halt instruction\n");
263                 return -1;
264             }
265
266             break;
267
268
269
270         case VMX_EXIT_PAUSE:
271             // Handled as NOP
272             info->rip += 2;
273
274             break;
275         case VMX_EXIT_EXTERNAL_INTR:
276             // Interrupts are handled outside switch
277             break;
278         case VMX_EXIT_INTR_WINDOW:
279             // This is handled in the atomic part of the vmx code,
280             // not in the generic (interruptable) vmx handler
281             break;
282         case VMX_EXIT_EXPIRED_PREEMPT_TIMER:
283             V3_Print("VMX Preempt Timer Expired.\n");
284             // This just forces an exit and is handled outside the switch
285             break;
286             
287         default:
288             PrintError("Unhandled VMX_EXIT: %s (%u), %lu (0x%lx)\n", 
289                        v3_vmx_exit_code_to_str(basic_info->reason),
290                        basic_info->reason, 
291                        exit_info->exit_qual, exit_info->exit_qual);
292             return -1;
293     }
294
295
296 #ifdef V3_CONFIG_TELEMETRY
297     if (info->vm_info->enable_telemetry) {
298         v3_telemetry_end_exit(info, exit_info->exit_reason);
299     }
300 #endif
301
302
303     return 0;
304 }
305
306 static const char VMX_EXIT_INFO_EXCEPTION_OR_NMI_STR[] = "VMX_EXIT_INFO_EXCEPTION_OR_NMI";
307 static const char VMX_EXIT_EXTERNAL_INTR_STR[] = "VMX_EXIT_EXTERNAL_INTR";
308 static const char VMX_EXIT_TRIPLE_FAULT_STR[] = "VMX_EXIT_TRIPLE_FAULT";
309 static const char VMX_EXIT_INIT_SIGNAL_STR[] = "VMX_EXIT_INIT_SIGNAL";
310 static const char VMX_EXIT_STARTUP_IPI_STR[] = "VMX_EXIT_STARTUP_IPI";
311 static const char VMX_EXIT_IO_SMI_STR[] = "VMX_EXIT_IO_SMI";
312 static const char VMX_EXIT_OTHER_SMI_STR[] = "VMX_EXIT_OTHER_SMI";
313 static const char VMX_EXIT_INTR_WINDOW_STR[] = "VMX_EXIT_INTR_WINDOW";
314 static const char VMX_EXIT_NMI_WINDOW_STR[] = "VMX_EXIT_NMI_WINDOW";
315 static const char VMX_EXIT_TASK_SWITCH_STR[] = "VMX_EXIT_TASK_SWITCH";
316 static const char VMX_EXIT_CPUID_STR[] = "VMX_EXIT_CPUID";
317 static const char VMX_EXIT_HLT_STR[] = "VMX_EXIT_HLT";
318 static const char VMX_EXIT_INVD_STR[] = "VMX_EXIT_INVD";
319 static const char VMX_EXIT_INVLPG_STR[] = "VMX_EXIT_INVLPG";
320 static const char VMX_EXIT_RDPMC_STR[] = "VMX_EXIT_RDPMC";
321 static const char VMX_EXIT_RDTSC_STR[] = "VMX_EXIT_RDTSC";
322 static const char VMX_EXIT_RSM_STR[] = "VMX_EXIT_RSM";
323 static const char VMX_EXIT_VMCALL_STR[] = "VMX_EXIT_VMCALL";
324 static const char VMX_EXIT_VMCLEAR_STR[] = "VMX_EXIT_VMCLEAR";
325 static const char VMX_EXIT_VMLAUNCH_STR[] = "VMX_EXIT_VMLAUNCH";
326 static const char VMX_EXIT_VMPTRLD_STR[] = "VMX_EXIT_VMPTRLD";
327 static const char VMX_EXIT_VMPTRST_STR[] = "VMX_EXIT_VMPTRST";
328 static const char VMX_EXIT_VMREAD_STR[] = "VMX_EXIT_VMREAD";
329 static const char VMX_EXIT_VMRESUME_STR[] = "VMX_EXIT_VMRESUME";
330 static const char VMX_EXIT_VMWRITE_STR[] = "VMX_EXIT_VMWRITE";
331 static const char VMX_EXIT_VMXOFF_STR[] = "VMX_EXIT_VMXOFF";
332 static const char VMX_EXIT_VMXON_STR[] = "VMX_EXIT_VMXON";
333 static const char VMX_EXIT_CR_REG_ACCESSES_STR[] = "VMX_EXIT_CR_REG_ACCESSES";
334 static const char VMX_EXIT_MOV_DR_STR[] = "VMX_EXIT_MOV_DR";
335 static const char VMX_EXIT_IO_INSTR_STR[] = "VMX_EXIT_IO_INSTR";
336 static const char VMX_EXIT_RDMSR_STR[] = "VMX_EXIT_RDMSR";
337 static const char VMX_EXIT_WRMSR_STR[] = "VMX_EXIT_WRMSR";
338 static const char VMX_EXIT_INVALID_GUEST_STATE_STR[] = "VMX_EXIT_INVALID_GUEST_STATE";
339 static const char VMX_EXIT_INVALID_MSR_LOAD_STR[] = "VMX_EXIT_INVALID_MSR_LOAD";
340 static const char VMX_EXIT_MWAIT_STR[] = "VMX_EXIT_MWAIT";
341 static const char VMX_EXIT_MONITOR_STR[] = "VMX_EXIT_MONITOR";
342 static const char VMX_EXIT_PAUSE_STR[] = "VMX_EXIT_PAUSE";
343 static const char VMX_EXIT_INVALID_MACHINE_CHECK_STR[] = "VMX_EXIT_INVALIDE_MACHINE_CHECK";
344 static const char VMX_EXIT_TPR_BELOW_THRESHOLD_STR[] = "VMX_EXIT_TPR_BELOW_THRESHOLD";
345 static const char VMX_EXIT_APIC_STR[] = "VMX_EXIT_APIC";
346 static const char VMX_EXIT_GDTR_IDTR_STR[] = "VMX_EXIT_GDTR_IDTR";
347 static const char VMX_EXIT_LDTR_TR_STR[] = "VMX_EXIT_LDTR_TR";
348 static const char VMX_EXIT_EPT_VIOLATION_STR[] = "VMX_EXIT_EPT_VIOLATION";
349 static const char VMX_EXIT_EPT_CONFIG_STR[] = "VMX_EXIT_EPT_CONFIG";
350 static const char VMX_EXIT_INVEPT_STR[] = "VMX_EXIT_INVEPT";
351 static const char VMX_EXIT_RDTSCP_STR[] = "VMX_EXIT_RDTSCP";
352 static const char VMX_EXIT_EXPIRED_PREEMPT_TIMER_STR[] = "VMX_EXIT_EXPIRED_PREEMPT_TIMER";
353 static const char VMX_EXIT_INVVPID_STR[] = "VMX_EXIT_INVVPID";
354 static const char VMX_EXIT_WBINVD_STR[] = "VMX_EXIT_WBINVD";
355 static const char VMX_EXIT_XSETBV_STR[] = "VMX_EXIT_XSETBV";
356
357 const char * v3_vmx_exit_code_to_str(vmx_exit_t exit)
358 {
359     switch (exit) {
360         case VMX_EXIT_INFO_EXCEPTION_OR_NMI:
361             return VMX_EXIT_INFO_EXCEPTION_OR_NMI_STR;
362         case VMX_EXIT_EXTERNAL_INTR:
363             return VMX_EXIT_EXTERNAL_INTR_STR;
364         case VMX_EXIT_TRIPLE_FAULT:
365             return VMX_EXIT_TRIPLE_FAULT_STR;
366         case VMX_EXIT_INIT_SIGNAL:
367             return VMX_EXIT_INIT_SIGNAL_STR;
368         case VMX_EXIT_STARTUP_IPI:
369             return VMX_EXIT_STARTUP_IPI_STR;
370         case VMX_EXIT_IO_SMI:
371             return VMX_EXIT_IO_SMI_STR;
372         case VMX_EXIT_OTHER_SMI:
373             return VMX_EXIT_OTHER_SMI_STR;
374         case VMX_EXIT_INTR_WINDOW:
375             return VMX_EXIT_INTR_WINDOW_STR;
376         case VMX_EXIT_NMI_WINDOW:
377             return VMX_EXIT_NMI_WINDOW_STR;
378         case VMX_EXIT_TASK_SWITCH:
379             return VMX_EXIT_TASK_SWITCH_STR;
380         case VMX_EXIT_CPUID:
381             return VMX_EXIT_CPUID_STR;
382         case VMX_EXIT_HLT:
383             return VMX_EXIT_HLT_STR;
384         case VMX_EXIT_INVD:
385             return VMX_EXIT_INVD_STR;
386         case VMX_EXIT_INVLPG:
387             return VMX_EXIT_INVLPG_STR;
388         case VMX_EXIT_RDPMC:
389             return VMX_EXIT_RDPMC_STR;
390         case VMX_EXIT_RDTSC:
391             return VMX_EXIT_RDTSC_STR;
392         case VMX_EXIT_RSM:
393             return VMX_EXIT_RSM_STR;
394         case VMX_EXIT_VMCALL:
395             return VMX_EXIT_VMCALL_STR;
396         case VMX_EXIT_VMCLEAR:
397             return VMX_EXIT_VMCLEAR_STR;
398         case VMX_EXIT_VMLAUNCH:
399             return VMX_EXIT_VMLAUNCH_STR;
400         case VMX_EXIT_VMPTRLD:
401             return VMX_EXIT_VMPTRLD_STR;
402         case VMX_EXIT_VMPTRST:
403             return VMX_EXIT_VMPTRST_STR;
404         case VMX_EXIT_VMREAD:
405             return VMX_EXIT_VMREAD_STR;
406         case VMX_EXIT_VMRESUME:
407             return VMX_EXIT_VMRESUME_STR;
408         case VMX_EXIT_VMWRITE:
409             return VMX_EXIT_VMWRITE_STR;
410         case VMX_EXIT_VMXOFF:
411             return VMX_EXIT_VMXOFF_STR;
412         case VMX_EXIT_VMXON:
413             return VMX_EXIT_VMXON_STR;
414         case VMX_EXIT_CR_REG_ACCESSES:
415             return VMX_EXIT_CR_REG_ACCESSES_STR;
416         case VMX_EXIT_MOV_DR:
417             return VMX_EXIT_MOV_DR_STR;
418         case VMX_EXIT_IO_INSTR:
419             return VMX_EXIT_IO_INSTR_STR;
420         case VMX_EXIT_RDMSR:
421             return VMX_EXIT_RDMSR_STR;
422         case VMX_EXIT_WRMSR:
423             return VMX_EXIT_WRMSR_STR;
424         case VMX_EXIT_INVALID_GUEST_STATE:
425             return VMX_EXIT_INVALID_GUEST_STATE_STR;
426         case VMX_EXIT_INVALID_MSR_LOAD:
427             return VMX_EXIT_INVALID_MSR_LOAD_STR;
428         case VMX_EXIT_MWAIT:
429             return VMX_EXIT_MWAIT_STR;
430         case VMX_EXIT_MONITOR:
431             return VMX_EXIT_MONITOR_STR;
432         case VMX_EXIT_PAUSE:
433             return VMX_EXIT_PAUSE_STR;
434         case VMX_EXIT_INVALID_MACHINE_CHECK:
435             return VMX_EXIT_INVALID_MACHINE_CHECK_STR;
436         case VMX_EXIT_TPR_BELOW_THRESHOLD:
437             return VMX_EXIT_TPR_BELOW_THRESHOLD_STR;
438         case VMX_EXIT_APIC:
439             return VMX_EXIT_APIC_STR;
440         case VMX_EXIT_GDTR_IDTR:
441             return VMX_EXIT_GDTR_IDTR_STR;
442         case VMX_EXIT_LDTR_TR:
443             return VMX_EXIT_LDTR_TR_STR;
444         case VMX_EXIT_EPT_VIOLATION:
445             return VMX_EXIT_EPT_VIOLATION_STR;
446         case VMX_EXIT_EPT_CONFIG:
447             return VMX_EXIT_EPT_CONFIG_STR;
448         case VMX_EXIT_INVEPT:
449             return VMX_EXIT_INVEPT_STR;
450         case VMX_EXIT_RDTSCP:
451             return VMX_EXIT_RDTSCP_STR;
452         case VMX_EXIT_EXPIRED_PREEMPT_TIMER:
453             return VMX_EXIT_EXPIRED_PREEMPT_TIMER_STR;
454         case VMX_EXIT_INVVPID:
455             return VMX_EXIT_INVVPID_STR;
456         case VMX_EXIT_WBINVD:
457             return VMX_EXIT_WBINVD_STR;
458         case VMX_EXIT_XSETBV:
459             return VMX_EXIT_XSETBV_STR;
460     }
461     return NULL;
462 }
463