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.


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