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.


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