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.


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