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 testing of new time handling on VMX, initial implementation of new
[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
103 #if 0
104         case VMEXIT_RDTSC:
105             if (v3_handle_rdtsc(info) == -1) {
106                 PrintError("Error Handling RDTSC instruction\n");
107                 return -1;
108             }
109             
110             break;
111 #endif
112
113         case VMEXIT_CPUID:
114             if (v3_handle_cpuid(info) == -1) {
115                 PrintError("Error Handling CPUID instruction\n");
116                 return -1;
117             }
118
119             break;
120         case VMEXIT_RDMSR: 
121             if (v3_handle_msr_read(info) == -1) {
122                 PrintError("Error handling MSR Read\n");
123                 return -1;
124             }
125
126             break;
127         case VMEXIT_WRMSR:
128             if (v3_handle_msr_write(info) == -1) {
129                 PrintError("Error handling MSR Write\n");
130                 return -1;
131             }
132
133             break;
134         case VMEXIT_VMCALL:
135             /* 
136              * Hypercall 
137              */
138
139             // VMCALL is a 3 byte op
140             // We do this early because some hypercalls can change the rip...
141             info->rip += 3;         
142
143             if (v3_handle_hypercall(info) == -1) {
144                 return -1;
145             }
146             break;
147         case VMEXIT_IO_INSTR: {
148             struct vmx_exit_io_qual * io_qual = (struct vmx_exit_io_qual *)&(exit_info->exit_qual);
149
150             if (io_qual->dir == 0) {
151                 if (io_qual->string) {
152                     if (v3_handle_vmx_io_outs(info, exit_info) == -1) {
153                         PrintError("Error in outs IO handler\n");
154                         return -1;
155                     }
156                 } else {
157                     if (v3_handle_vmx_io_out(info, exit_info) == -1) {
158                         PrintError("Error in out IO handler\n");
159                         return -1;
160                     }
161                 }
162             } else {
163                 if (io_qual->string) {
164                     if(v3_handle_vmx_io_ins(info, exit_info) == -1) {
165                         PrintError("Error in ins IO handler\n");
166                         return -1;
167                     }
168                 } else {
169                     if (v3_handle_vmx_io_in(info, exit_info) == -1) {
170                         PrintError("Error in in IO handler\n");
171                         return -1;
172                     }
173                 }
174             }
175             break;
176         }
177         case VMEXIT_CR_REG_ACCESSES: {
178             struct vmx_exit_cr_qual * cr_qual = (struct vmx_exit_cr_qual *)&(exit_info->exit_qual);
179             
180             // PrintDebug("Control register: %d\n", cr_qual->access_type);
181             switch(cr_qual->cr_id) {
182                 case 0:
183                     //PrintDebug("Handling CR0 Access\n");
184                     if (v3_vmx_handle_cr0_access(info, cr_qual, exit_info) == -1) {
185                         PrintError("Error in CR0 access handler\n");
186                         return -1;
187                     }
188                     break;
189                 case 3:
190                     //PrintDebug("Handling CR3 Access\n");
191                     if (v3_vmx_handle_cr3_access(info, cr_qual) == -1) {
192                         PrintError("Error in CR3 access handler\n");
193                         return -1;
194                     }
195                     break;
196                 default:
197                     PrintError("Unhandled CR access: %d\n", cr_qual->cr_id);
198                     return -1;
199             }
200             
201             info->rip += exit_info->instr_len;
202
203             break;
204         }
205         case VMEXIT_HLT:
206             PrintDebug("Guest halted\n");
207
208             if (v3_handle_halt(info) == -1) {
209                 PrintError("Error handling halt instruction\n");
210                 return -1;
211             }
212
213             break;
214         case VMEXIT_PAUSE:
215             // Handled as NOP
216             info->rip += 2;
217
218             break;
219         case VMEXIT_EXTERNAL_INTR:
220             // Interrupts are handled outside switch
221             break;
222         case VMEXIT_INTR_WINDOW:
223
224             vmcs_read(VMCS_PROC_CTRLS, &(vmx_info->pri_proc_ctrls.value));
225             vmx_info->pri_proc_ctrls.int_wndw_exit = 0;
226             vmcs_write(VMCS_PROC_CTRLS, vmx_info->pri_proc_ctrls.value);
227
228 #ifdef CONFIG_DEBUG_INTERRUPTS
229             PrintDebug("Interrupts available again! (RIP=%llx)\n", info->rip);
230 #endif
231
232             break;
233         default:
234             PrintError("Unhandled VMEXIT: %s (%u), %lu (0x%lx)\n", 
235                        v3_vmx_exit_code_to_str(exit_info->exit_reason),
236                        exit_info->exit_reason, 
237                        exit_info->exit_qual, exit_info->exit_qual);
238             return -1;
239     }
240
241
242 #ifdef CONFIG_TELEMETRY
243     if (info->vm_info->enable_telemetry) {
244         v3_telemetry_end_exit(info, exit_info->exit_reason);
245     }
246 #endif
247
248
249     return 0;
250 }
251
252 static const char VMEXIT_INFO_EXCEPTION_OR_NMI_STR[] = "VMEXIT_INFO_EXCEPTION_OR_NMI";
253 static const char VMEXIT_EXTERNAL_INTR_STR[] = "VMEXIT_EXTERNAL_INTR";
254 static const char VMEXIT_TRIPLE_FAULT_STR[] = "VMEXIT_TRIPLE_FAULT";
255 static const char VMEXIT_INIT_SIGNAL_STR[] = "VMEXIT_INIT_SIGNAL";
256 static const char VMEXIT_STARTUP_IPI_STR[] = "VMEXIT_STARTUP_IPI";
257 static const char VMEXIT_IO_SMI_STR[] = "VMEXIT_IO_SMI";
258 static const char VMEXIT_OTHER_SMI_STR[] = "VMEXIT_OTHER_SMI";
259 static const char VMEXIT_INTR_WINDOW_STR[] = "VMEXIT_INTR_WINDOW";
260 static const char VMEXIT_NMI_WINDOW_STR[] = "VMEXIT_NMI_WINDOW";
261 static const char VMEXIT_TASK_SWITCH_STR[] = "VMEXIT_TASK_SWITCH";
262 static const char VMEXIT_CPUID_STR[] = "VMEXIT_CPUID";
263 static const char VMEXIT_HLT_STR[] = "VMEXIT_HLT";
264 static const char VMEXIT_INVD_STR[] = "VMEXIT_INVD";
265 static const char VMEXIT_INVLPG_STR[] = "VMEXIT_INVLPG";
266 static const char VMEXIT_RDPMC_STR[] = "VMEXIT_RDPMC";
267 static const char VMEXIT_RDTSC_STR[] = "VMEXIT_RDTSC";
268 static const char VMEXIT_RSM_STR[] = "VMEXIT_RSM";
269 static const char VMEXIT_VMCALL_STR[] = "VMEXIT_VMCALL";
270 static const char VMEXIT_VMCLEAR_STR[] = "VMEXIT_VMCLEAR";
271 static const char VMEXIT_VMLAUNCH_STR[] = "VMEXIT_VMLAUNCH";
272 static const char VMEXIT_VMPTRLD_STR[] = "VMEXIT_VMPTRLD";
273 static const char VMEXIT_VMPTRST_STR[] = "VMEXIT_VMPTRST";
274 static const char VMEXIT_VMREAD_STR[] = "VMEXIT_VMREAD";
275 static const char VMEXIT_VMRESUME_STR[] = "VMEXIT_VMRESUME";
276 static const char VMEXIT_VMWRITE_STR[] = "VMEXIT_VMWRITE";
277 static const char VMEXIT_VMXOFF_STR[] = "VMEXIT_VMXOFF";
278 static const char VMEXIT_VMXON_STR[] = "VMEXIT_VMXON";
279 static const char VMEXIT_CR_REG_ACCESSES_STR[] = "VMEXIT_CR_REG_ACCESSES";
280 static const char VMEXIT_MOV_DR_STR[] = "VMEXIT_MOV_DR";
281 static const char VMEXIT_IO_INSTR_STR[] = "VMEXIT_IO_INSTR";
282 static const char VMEXIT_RDMSR_STR[] = "VMEXIT_RDMSR";
283 static const char VMEXIT_WRMSR_STR[] = "VMEXIT_WRMSR";
284 static const char VMEXIT_ENTRY_FAIL_INVALID_GUEST_STATE_STR[] = "VMEXIT_ENTRY_FAIL_INVALID_GUEST_STATE";
285 static const char VMEXIT_ENTRY_FAIL_MSR_LOAD_STR[] = "VMEXIT_ENTRY_FAIL_MSR_LOAD";
286 static const char VMEXIT_MWAIT_STR[] = "VMEXIT_MWAIT";
287 static const char VMEXIT_MONITOR_STR[] = "VMEXIT_MONITOR";
288 static const char VMEXIT_PAUSE_STR[] = "VMEXIT_PAUSE";
289 static const char VMEXIT_ENTRY_FAILURE_MACHINE_CHECK_STR[] = "VMEXIT_ENTRY_FAILURE_MACHINE_CHECK";
290 static const char VMEXIT_TPR_BELOW_THRESHOLD_STR[] = "VMEXIT_TPR_BELOW_THRESHOLD";
291 static const char VMEXIT_APIC_STR[] = "VMEXIT_APIC";
292 static const char VMEXIT_GDTR_IDTR_STR[] = "VMEXIT_GDTR_IDTR";
293 static const char VMEXIT_LDTR_TR_STR[] = "VMEXIT_LDTR_TR";
294 static const char VMEXIT_EPT_VIOLATION_STR[] = "VMEXIT_EPT_VIOLATION";
295 static const char VMEXIT_EPT_CONFIG_STR[] = "VMEXIT_EPT_CONFIG";
296 static const char VMEXIT_INVEPT_STR[] = "VMEXIT_INVEPT";
297 static const char VMEXIT_RDTSCP_STR[] = "VMEXIT_RDTSCP";
298 static const char VMEXIT_EXPIRED_PREEMPT_TIMER_STR[] = "VMEXIT_EXPIRED_PREEMPT_TIMER";
299 static const char VMEXIT_INVVPID_STR[] = "VMEXIT_INVVPID";
300 static const char VMEXIT_WBINVD_STR[] = "VMEXIT_WBINVD";
301 static const char VMEXIT_XSETBV_STR[] = "VMEXIT_XSETBV";
302
303 const char * v3_vmx_exit_code_to_str(vmx_exit_t exit)
304 {
305     switch(exit) {
306         case VMEXIT_INFO_EXCEPTION_OR_NMI:
307             return VMEXIT_INFO_EXCEPTION_OR_NMI_STR;
308         case VMEXIT_EXTERNAL_INTR:
309             return VMEXIT_EXTERNAL_INTR_STR;
310         case VMEXIT_TRIPLE_FAULT:
311             return VMEXIT_TRIPLE_FAULT_STR;
312         case VMEXIT_INIT_SIGNAL:
313             return VMEXIT_INIT_SIGNAL_STR;
314         case VMEXIT_STARTUP_IPI:
315             return VMEXIT_STARTUP_IPI_STR;
316         case VMEXIT_IO_SMI:
317             return VMEXIT_IO_SMI_STR;
318         case VMEXIT_OTHER_SMI:
319             return VMEXIT_OTHER_SMI_STR;
320         case VMEXIT_INTR_WINDOW:
321             return VMEXIT_INTR_WINDOW_STR;
322         case VMEXIT_NMI_WINDOW:
323             return VMEXIT_NMI_WINDOW_STR;
324         case VMEXIT_TASK_SWITCH:
325             return VMEXIT_TASK_SWITCH_STR;
326         case VMEXIT_CPUID:
327             return VMEXIT_CPUID_STR;
328         case VMEXIT_HLT:
329             return VMEXIT_HLT_STR;
330         case VMEXIT_INVD:
331             return VMEXIT_INVD_STR;
332         case VMEXIT_INVLPG:
333             return VMEXIT_INVLPG_STR;
334         case VMEXIT_RDPMC:
335             return VMEXIT_RDPMC_STR;
336         case VMEXIT_RDTSC:
337             return VMEXIT_RDTSC_STR;
338         case VMEXIT_RSM:
339             return VMEXIT_RSM_STR;
340         case VMEXIT_VMCALL:
341             return VMEXIT_VMCALL_STR;
342         case VMEXIT_VMCLEAR:
343             return VMEXIT_VMCLEAR_STR;
344         case VMEXIT_VMLAUNCH:
345             return VMEXIT_VMLAUNCH_STR;
346         case VMEXIT_VMPTRLD:
347             return VMEXIT_VMPTRLD_STR;
348         case VMEXIT_VMPTRST:
349             return VMEXIT_VMPTRST_STR;
350         case VMEXIT_VMREAD:
351             return VMEXIT_VMREAD_STR;
352         case VMEXIT_VMRESUME:
353             return VMEXIT_VMRESUME_STR;
354         case VMEXIT_VMWRITE:
355             return VMEXIT_VMWRITE_STR;
356         case VMEXIT_VMXOFF:
357             return VMEXIT_VMXOFF_STR;
358         case VMEXIT_VMXON:
359             return VMEXIT_VMXON_STR;
360         case VMEXIT_CR_REG_ACCESSES:
361             return VMEXIT_CR_REG_ACCESSES_STR;
362         case VMEXIT_MOV_DR:
363             return VMEXIT_MOV_DR_STR;
364         case VMEXIT_IO_INSTR:
365             return VMEXIT_IO_INSTR_STR;
366         case VMEXIT_RDMSR:
367             return VMEXIT_RDMSR_STR;
368         case VMEXIT_WRMSR:
369             return VMEXIT_WRMSR_STR;
370         case VMEXIT_ENTRY_FAIL_INVALID_GUEST_STATE:
371             return VMEXIT_ENTRY_FAIL_INVALID_GUEST_STATE_STR;
372         case VMEXIT_ENTRY_FAIL_MSR_LOAD:
373             return VMEXIT_ENTRY_FAIL_MSR_LOAD_STR;
374         case VMEXIT_MWAIT:
375             return VMEXIT_MWAIT_STR;
376         case VMEXIT_MONITOR:
377             return VMEXIT_MONITOR_STR;
378         case VMEXIT_PAUSE:
379             return VMEXIT_PAUSE_STR;
380         case VMEXIT_ENTRY_FAILURE_MACHINE_CHECK:
381             return VMEXIT_ENTRY_FAILURE_MACHINE_CHECK_STR;
382         case VMEXIT_TPR_BELOW_THRESHOLD:
383             return VMEXIT_TPR_BELOW_THRESHOLD_STR;
384         case VMEXIT_APIC:
385             return VMEXIT_APIC_STR;
386         case VMEXIT_GDTR_IDTR:
387             return VMEXIT_GDTR_IDTR_STR;
388         case VMEXIT_LDTR_TR:
389             return VMEXIT_LDTR_TR_STR;
390         case VMEXIT_EPT_VIOLATION:
391             return VMEXIT_EPT_VIOLATION_STR;
392         case VMEXIT_EPT_CONFIG:
393             return VMEXIT_EPT_CONFIG_STR;
394         case VMEXIT_INVEPT:
395             return VMEXIT_INVEPT_STR;
396         case VMEXIT_RDTSCP:
397             return VMEXIT_RDTSCP_STR;
398         case VMEXIT_EXPIRED_PREEMPT_TIMER:
399             return VMEXIT_EXPIRED_PREEMPT_TIMER_STR;
400         case VMEXIT_INVVPID:
401             return VMEXIT_INVVPID_STR;
402         case VMEXIT_WBINVD:
403             return VMEXIT_WBINVD_STR;
404         case VMEXIT_XSETBV:
405             return VMEXIT_XSETBV_STR;
406     }
407     return NULL;
408 }
409