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.


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