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 dedicated debugging framework with associated interface
[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                 default:
241                     PrintError("Unhandled CR access: %d\n", cr_qual->cr_id);
242                     return -1;
243             }
244             
245             // TODO: move RIP increment into all of the above individual CR
246             //       handlers, not just v3_vmx_handle_cr4_access()
247             if (cr_qual->cr_id != 4)
248                 info->rip += exit_info->instr_len;
249
250             break;
251         }
252         case VMX_EXIT_HLT:
253             PrintDebug("Guest halted\n");
254
255             if (v3_handle_halt(info) == -1) {
256                 PrintError("Error handling halt instruction\n");
257                 return -1;
258             }
259
260             break;
261
262
263
264         case VMX_EXIT_PAUSE:
265             // Handled as NOP
266             info->rip += 2;
267
268             break;
269         case VMX_EXIT_EXTERNAL_INTR:
270             // Interrupts are handled outside switch
271             break;
272         case VMX_EXIT_INTR_WINDOW:
273             // This is handled in the atomic part of the vmx code,
274             // not in the generic (interruptable) vmx handler
275             break;
276         case VMX_EXIT_EXPIRED_PREEMPT_TIMER:
277             V3_Print("VMX Preempt Timer Expired.\n");
278             // This just forces an exit and is handled outside the switch
279             break;
280             
281         default:
282             PrintError("Unhandled VMX_EXIT: %s (%u), %lu (0x%lx)\n", 
283                        v3_vmx_exit_code_to_str(basic_info->reason),
284                        basic_info->reason, 
285                        exit_info->exit_qual, exit_info->exit_qual);
286             return -1;
287     }
288
289
290 #ifdef V3_CONFIG_TELEMETRY
291     if (info->vm_info->enable_telemetry) {
292         v3_telemetry_end_exit(info, exit_info->exit_reason);
293     }
294 #endif
295
296
297     return 0;
298 }
299
300 static const char VMX_EXIT_INFO_EXCEPTION_OR_NMI_STR[] = "VMX_EXIT_INFO_EXCEPTION_OR_NMI";
301 static const char VMX_EXIT_EXTERNAL_INTR_STR[] = "VMX_EXIT_EXTERNAL_INTR";
302 static const char VMX_EXIT_TRIPLE_FAULT_STR[] = "VMX_EXIT_TRIPLE_FAULT";
303 static const char VMX_EXIT_INIT_SIGNAL_STR[] = "VMX_EXIT_INIT_SIGNAL";
304 static const char VMX_EXIT_STARTUP_IPI_STR[] = "VMX_EXIT_STARTUP_IPI";
305 static const char VMX_EXIT_IO_SMI_STR[] = "VMX_EXIT_IO_SMI";
306 static const char VMX_EXIT_OTHER_SMI_STR[] = "VMX_EXIT_OTHER_SMI";
307 static const char VMX_EXIT_INTR_WINDOW_STR[] = "VMX_EXIT_INTR_WINDOW";
308 static const char VMX_EXIT_NMI_WINDOW_STR[] = "VMX_EXIT_NMI_WINDOW";
309 static const char VMX_EXIT_TASK_SWITCH_STR[] = "VMX_EXIT_TASK_SWITCH";
310 static const char VMX_EXIT_CPUID_STR[] = "VMX_EXIT_CPUID";
311 static const char VMX_EXIT_HLT_STR[] = "VMX_EXIT_HLT";
312 static const char VMX_EXIT_INVD_STR[] = "VMX_EXIT_INVD";
313 static const char VMX_EXIT_INVLPG_STR[] = "VMX_EXIT_INVLPG";
314 static const char VMX_EXIT_RDPMC_STR[] = "VMX_EXIT_RDPMC";
315 static const char VMX_EXIT_RDTSC_STR[] = "VMX_EXIT_RDTSC";
316 static const char VMX_EXIT_RSM_STR[] = "VMX_EXIT_RSM";
317 static const char VMX_EXIT_VMCALL_STR[] = "VMX_EXIT_VMCALL";
318 static const char VMX_EXIT_VMCLEAR_STR[] = "VMX_EXIT_VMCLEAR";
319 static const char VMX_EXIT_VMLAUNCH_STR[] = "VMX_EXIT_VMLAUNCH";
320 static const char VMX_EXIT_VMPTRLD_STR[] = "VMX_EXIT_VMPTRLD";
321 static const char VMX_EXIT_VMPTRST_STR[] = "VMX_EXIT_VMPTRST";
322 static const char VMX_EXIT_VMREAD_STR[] = "VMX_EXIT_VMREAD";
323 static const char VMX_EXIT_VMRESUME_STR[] = "VMX_EXIT_VMRESUME";
324 static const char VMX_EXIT_VMWRITE_STR[] = "VMX_EXIT_VMWRITE";
325 static const char VMX_EXIT_VMXOFF_STR[] = "VMX_EXIT_VMXOFF";
326 static const char VMX_EXIT_VMXON_STR[] = "VMX_EXIT_VMXON";
327 static const char VMX_EXIT_CR_REG_ACCESSES_STR[] = "VMX_EXIT_CR_REG_ACCESSES";
328 static const char VMX_EXIT_MOV_DR_STR[] = "VMX_EXIT_MOV_DR";
329 static const char VMX_EXIT_IO_INSTR_STR[] = "VMX_EXIT_IO_INSTR";
330 static const char VMX_EXIT_RDMSR_STR[] = "VMX_EXIT_RDMSR";
331 static const char VMX_EXIT_WRMSR_STR[] = "VMX_EXIT_WRMSR";
332 static const char VMX_EXIT_INVALID_GUEST_STATE_STR[] = "VMX_EXIT_INVALID_GUEST_STATE";
333 static const char VMX_EXIT_INVALID_MSR_LOAD_STR[] = "VMX_EXIT_INVALID_MSR_LOAD";
334 static const char VMX_EXIT_MWAIT_STR[] = "VMX_EXIT_MWAIT";
335 static const char VMX_EXIT_MONITOR_STR[] = "VMX_EXIT_MONITOR";
336 static const char VMX_EXIT_PAUSE_STR[] = "VMX_EXIT_PAUSE";
337 static const char VMX_EXIT_INVALID_MACHINE_CHECK_STR[] = "VMX_EXIT_INVALIDE_MACHINE_CHECK";
338 static const char VMX_EXIT_TPR_BELOW_THRESHOLD_STR[] = "VMX_EXIT_TPR_BELOW_THRESHOLD";
339 static const char VMX_EXIT_APIC_STR[] = "VMX_EXIT_APIC";
340 static const char VMX_EXIT_GDTR_IDTR_STR[] = "VMX_EXIT_GDTR_IDTR";
341 static const char VMX_EXIT_LDTR_TR_STR[] = "VMX_EXIT_LDTR_TR";
342 static const char VMX_EXIT_EPT_VIOLATION_STR[] = "VMX_EXIT_EPT_VIOLATION";
343 static const char VMX_EXIT_EPT_CONFIG_STR[] = "VMX_EXIT_EPT_CONFIG";
344 static const char VMX_EXIT_INVEPT_STR[] = "VMX_EXIT_INVEPT";
345 static const char VMX_EXIT_RDTSCP_STR[] = "VMX_EXIT_RDTSCP";
346 static const char VMX_EXIT_EXPIRED_PREEMPT_TIMER_STR[] = "VMX_EXIT_EXPIRED_PREEMPT_TIMER";
347 static const char VMX_EXIT_INVVPID_STR[] = "VMX_EXIT_INVVPID";
348 static const char VMX_EXIT_WBINVD_STR[] = "VMX_EXIT_WBINVD";
349 static const char VMX_EXIT_XSETBV_STR[] = "VMX_EXIT_XSETBV";
350
351 const char * v3_vmx_exit_code_to_str(vmx_exit_t exit)
352 {
353     switch (exit) {
354         case VMX_EXIT_INFO_EXCEPTION_OR_NMI:
355             return VMX_EXIT_INFO_EXCEPTION_OR_NMI_STR;
356         case VMX_EXIT_EXTERNAL_INTR:
357             return VMX_EXIT_EXTERNAL_INTR_STR;
358         case VMX_EXIT_TRIPLE_FAULT:
359             return VMX_EXIT_TRIPLE_FAULT_STR;
360         case VMX_EXIT_INIT_SIGNAL:
361             return VMX_EXIT_INIT_SIGNAL_STR;
362         case VMX_EXIT_STARTUP_IPI:
363             return VMX_EXIT_STARTUP_IPI_STR;
364         case VMX_EXIT_IO_SMI:
365             return VMX_EXIT_IO_SMI_STR;
366         case VMX_EXIT_OTHER_SMI:
367             return VMX_EXIT_OTHER_SMI_STR;
368         case VMX_EXIT_INTR_WINDOW:
369             return VMX_EXIT_INTR_WINDOW_STR;
370         case VMX_EXIT_NMI_WINDOW:
371             return VMX_EXIT_NMI_WINDOW_STR;
372         case VMX_EXIT_TASK_SWITCH:
373             return VMX_EXIT_TASK_SWITCH_STR;
374         case VMX_EXIT_CPUID:
375             return VMX_EXIT_CPUID_STR;
376         case VMX_EXIT_HLT:
377             return VMX_EXIT_HLT_STR;
378         case VMX_EXIT_INVD:
379             return VMX_EXIT_INVD_STR;
380         case VMX_EXIT_INVLPG:
381             return VMX_EXIT_INVLPG_STR;
382         case VMX_EXIT_RDPMC:
383             return VMX_EXIT_RDPMC_STR;
384         case VMX_EXIT_RDTSC:
385             return VMX_EXIT_RDTSC_STR;
386         case VMX_EXIT_RSM:
387             return VMX_EXIT_RSM_STR;
388         case VMX_EXIT_VMCALL:
389             return VMX_EXIT_VMCALL_STR;
390         case VMX_EXIT_VMCLEAR:
391             return VMX_EXIT_VMCLEAR_STR;
392         case VMX_EXIT_VMLAUNCH:
393             return VMX_EXIT_VMLAUNCH_STR;
394         case VMX_EXIT_VMPTRLD:
395             return VMX_EXIT_VMPTRLD_STR;
396         case VMX_EXIT_VMPTRST:
397             return VMX_EXIT_VMPTRST_STR;
398         case VMX_EXIT_VMREAD:
399             return VMX_EXIT_VMREAD_STR;
400         case VMX_EXIT_VMRESUME:
401             return VMX_EXIT_VMRESUME_STR;
402         case VMX_EXIT_VMWRITE:
403             return VMX_EXIT_VMWRITE_STR;
404         case VMX_EXIT_VMXOFF:
405             return VMX_EXIT_VMXOFF_STR;
406         case VMX_EXIT_VMXON:
407             return VMX_EXIT_VMXON_STR;
408         case VMX_EXIT_CR_REG_ACCESSES:
409             return VMX_EXIT_CR_REG_ACCESSES_STR;
410         case VMX_EXIT_MOV_DR:
411             return VMX_EXIT_MOV_DR_STR;
412         case VMX_EXIT_IO_INSTR:
413             return VMX_EXIT_IO_INSTR_STR;
414         case VMX_EXIT_RDMSR:
415             return VMX_EXIT_RDMSR_STR;
416         case VMX_EXIT_WRMSR:
417             return VMX_EXIT_WRMSR_STR;
418         case VMX_EXIT_INVALID_GUEST_STATE:
419             return VMX_EXIT_INVALID_GUEST_STATE_STR;
420         case VMX_EXIT_INVALID_MSR_LOAD:
421             return VMX_EXIT_INVALID_MSR_LOAD_STR;
422         case VMX_EXIT_MWAIT:
423             return VMX_EXIT_MWAIT_STR;
424         case VMX_EXIT_MONITOR:
425             return VMX_EXIT_MONITOR_STR;
426         case VMX_EXIT_PAUSE:
427             return VMX_EXIT_PAUSE_STR;
428         case VMX_EXIT_INVALID_MACHINE_CHECK:
429             return VMX_EXIT_INVALID_MACHINE_CHECK_STR;
430         case VMX_EXIT_TPR_BELOW_THRESHOLD:
431             return VMX_EXIT_TPR_BELOW_THRESHOLD_STR;
432         case VMX_EXIT_APIC:
433             return VMX_EXIT_APIC_STR;
434         case VMX_EXIT_GDTR_IDTR:
435             return VMX_EXIT_GDTR_IDTR_STR;
436         case VMX_EXIT_LDTR_TR:
437             return VMX_EXIT_LDTR_TR_STR;
438         case VMX_EXIT_EPT_VIOLATION:
439             return VMX_EXIT_EPT_VIOLATION_STR;
440         case VMX_EXIT_EPT_CONFIG:
441             return VMX_EXIT_EPT_CONFIG_STR;
442         case VMX_EXIT_INVEPT:
443             return VMX_EXIT_INVEPT_STR;
444         case VMX_EXIT_RDTSCP:
445             return VMX_EXIT_RDTSCP_STR;
446         case VMX_EXIT_EXPIRED_PREEMPT_TIMER:
447             return VMX_EXIT_EXPIRED_PREEMPT_TIMER_STR;
448         case VMX_EXIT_INVVPID:
449             return VMX_EXIT_INVVPID_STR;
450         case VMX_EXIT_WBINVD:
451             return VMX_EXIT_WBINVD_STR;
452         case VMX_EXIT_XSETBV:
453             return VMX_EXIT_XSETBV_STR;
454     }
455     return NULL;
456 }
457