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.


Time configuration parameters added. More time control code prototyped,
[palacios.git] / palacios / src / palacios / vmx.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, Peter Dinda <pdinda@northwestern.edu> 
11  * Copyright (c) 2008, Jack Lange <jarusl@cs.northwestern.edu>
12  * Copyright (c) 2008, The V3VEE Project <http://www.v3vee.org> 
13  * All rights reserved.
14  *
15  * Author: Peter Dinda <pdinda@northwestern.edu>
16  *         Jack Lange <jarusl@cs.northwestern.edu>
17  *
18  * This is free software.  You are permitted to use,
19  * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
20  */
21
22
23 #include <palacios/vmx.h>
24 #include <palacios/vmm.h>
25 #include <palacios/vmx_handler.h>
26 #include <palacios/vmcs.h>
27 #include <palacios/vmx_lowlevel.h>
28 #include <palacios/vmm_lowlevel.h>
29 #include <palacios/vmm_ctrl_regs.h>
30 #include <palacios/vmm_config.h>
31 #include <palacios/vm_guest_mem.h>
32 #include <palacios/vmm_direct_paging.h>
33 #include <palacios/vmx_io.h>
34 #include <palacios/vmx_msr.h>
35
36
37 #ifndef CONFIG_DEBUG_VMX
38 #undef PrintDebug
39 #define PrintDebug(fmt, args...)
40 #endif
41
42
43 static addr_t host_vmcs_ptrs[CONFIG_MAX_CPUS] = { [0 ... CONFIG_MAX_CPUS - 1] = 0};
44
45
46
47 extern int v3_vmx_launch(struct v3_gprs * vm_regs, struct guest_info * info, struct v3_ctrl_regs * ctrl_regs);
48 extern int v3_vmx_resume(struct v3_gprs * vm_regs, struct guest_info * info, struct v3_ctrl_regs * ctrl_regs);
49
50 static int inline check_vmcs_write(vmcs_field_t field, addr_t val) {
51     int ret = 0;
52
53     ret = vmcs_write(field,val);
54
55     if (ret != VMX_SUCCESS) {
56         PrintError("VMWRITE error on %s!: %d\n", v3_vmcs_field_to_str(field), ret);
57         return 1;
58     }
59
60     return 0;
61 }
62
63 static int inline check_vmcs_read(vmcs_field_t field, void * val) {
64     int ret = 0;
65
66     ret = vmcs_read(field, val);
67
68     if (ret != VMX_SUCCESS) {
69         PrintError("VMREAD error on %s!: %d\n", v3_vmcs_field_to_str(field), ret);
70     }
71
72     return ret;
73 }
74
75 #if 0
76 // For the 32 bit reserved bit fields 
77 // MB1s are in the low 32 bits, MBZs are in the high 32 bits of the MSR
78 static uint32_t sanitize_bits1(uint32_t msr_num, uint32_t val) {
79     v3_msr_t mask_msr;
80
81     PrintDebug("sanitize_bits1 (MSR:%x)\n", msr_num);
82
83     v3_get_msr(msr_num, &mask_msr.hi, &mask_msr.lo);
84
85     PrintDebug("MSR %x = %x : %x \n", msr_num, mask_msr.hi, mask_msr.lo);
86
87     val |= mask_msr.lo;
88     val |= mask_msr.hi;
89   
90     return val;
91 }
92
93
94
95 static addr_t sanitize_bits2(uint32_t msr_num0, uint32_t msr_num1, addr_t val) {
96     v3_msr_t msr0, msr1;
97     addr_t msr0_val, msr1_val;
98
99     PrintDebug("sanitize_bits2 (MSR0=%x, MSR1=%x)\n", msr_num0, msr_num1);
100
101     v3_get_msr(msr_num0, &msr0.hi, &msr0.lo);
102     v3_get_msr(msr_num1, &msr1.hi, &msr1.lo);
103   
104     // This generates a mask that is the natural bit width of the CPU
105     msr0_val = msr0.value;
106     msr1_val = msr1.value;
107
108     PrintDebug("MSR %x = %p, %x = %p \n", msr_num0, (void*)msr0_val, msr_num1, (void*)msr1_val);
109
110     val |= msr0_val;
111     val |= msr1_val;
112
113     return val;
114 }
115
116
117
118 #endif
119
120
121 static addr_t allocate_vmcs() {
122     reg_ex_t msr;
123     struct vmcs_data * vmcs_page = NULL;
124
125     PrintDebug("Allocating page\n");
126
127     vmcs_page = (struct vmcs_data *)V3_VAddr(V3_AllocPages(1));
128     memset(vmcs_page, 0, 4096);
129
130     v3_get_msr(VMX_BASIC_MSR, &(msr.e_reg.high), &(msr.e_reg.low));
131     
132     vmcs_page->revision = ((struct vmx_basic_msr*)&msr)->revision;
133     PrintDebug("VMX Revision: 0x%x\n",vmcs_page->revision);
134
135     return (addr_t)V3_PAddr((void *)vmcs_page);
136 }
137
138
139
140
141 static int init_vmcs_bios(struct guest_info * info, struct vmx_data * vmx_state) {
142     int vmx_ret = 0;
143
144     PrintDebug("Loading VMCS\n");
145     vmx_ret = vmcs_load(vmx_state->vmcs_ptr_phys);
146
147     if (vmx_ret != VMX_SUCCESS) {
148         PrintError("VMPTRLD failed\n");
149         return -1;
150     }
151
152
153
154     /******* Setup Host State **********/
155
156     /* Cache GDTR, IDTR, and TR in host struct */
157     addr_t gdtr_base;
158     struct {
159         uint16_t selector;
160         addr_t   base;
161     } __attribute__((packed)) tmp_seg;
162     
163
164     __asm__ __volatile__(
165                          "sgdt (%0);"
166                          :
167                          : "q"(&tmp_seg)
168                          : "memory"
169                          );
170     gdtr_base = tmp_seg.base;
171     vmx_state->host_state.gdtr.base = gdtr_base;
172
173     __asm__ __volatile__(
174                          "sidt (%0);"
175                          :
176                          : "q"(&tmp_seg)
177                          : "memory"
178                          );
179     vmx_state->host_state.idtr.base = tmp_seg.base;
180
181     __asm__ __volatile__(
182                          "str (%0);"
183                          :
184                          : "q"(&tmp_seg)
185                          : "memory"
186                          );
187     vmx_state->host_state.tr.selector = tmp_seg.selector;
188
189     /* The GDTR *index* is bits 3-15 of the selector. */
190     struct tss_descriptor * desc = NULL;
191     desc = (struct tss_descriptor *)(gdtr_base + (8 * (tmp_seg.selector >> 3)));
192
193     tmp_seg.base = ((desc->base1) |
194                     (desc->base2 << 16) |
195                     (desc->base3 << 24) |
196 #ifdef __V3_64BIT__
197                     ((uint64_t)desc->base4 << 32)
198 #else 
199                     (0)
200 #endif
201                     );
202
203     vmx_state->host_state.tr.base = tmp_seg.base;
204
205   
206
207     /********** Setup and VMX Control Fields from MSR ***********/
208     /* Setup IO map */
209
210
211     struct v3_msr tmp_msr;
212
213     v3_get_msr(VMX_PINBASED_CTLS_MSR, &(tmp_msr.hi), &(tmp_msr.lo));
214
215     /* Add external interrupts, NMI exiting, and virtual NMI */
216     vmx_state->pin_ctrls.value =  tmp_msr.lo;
217     vmx_state->pin_ctrls.nmi_exit = 1;
218     vmx_state->pin_ctrls.ext_int_exit = 1;
219
220     v3_get_msr(VMX_PROCBASED_CTLS_MSR, &(tmp_msr.hi), &(tmp_msr.lo));
221
222     vmx_state->pri_proc_ctrls.value = tmp_msr.lo;
223     vmx_state->pri_proc_ctrls.use_io_bitmap = 1;
224     vmx_state->pri_proc_ctrls.hlt_exit = 1;
225     vmx_state->pri_proc_ctrls.invlpg_exit = 1;
226     vmx_state->pri_proc_ctrls.use_msr_bitmap = 1;
227     vmx_state->pri_proc_ctrls.pause_exit = 1;
228 #ifdef CONFIG_TIME_TSC_OFFSET
229     vmx_state->pri_proc_ctrls.tsc_offset = 1;
230 #endif
231
232     vmx_ret |= check_vmcs_write(VMCS_IO_BITMAP_A_ADDR, (addr_t)V3_PAddr(info->vm_info->io_map.arch_data));
233     vmx_ret |= check_vmcs_write(VMCS_IO_BITMAP_B_ADDR, 
234             (addr_t)V3_PAddr(info->vm_info->io_map.arch_data) + PAGE_SIZE_4KB);
235
236
237     vmx_ret |= check_vmcs_write(VMCS_MSR_BITMAP, (addr_t)V3_PAddr(info->vm_info->msr_map.arch_data));
238
239     v3_get_msr(VMX_EXIT_CTLS_MSR, &(tmp_msr.hi), &(tmp_msr.lo));
240     vmx_state->exit_ctrls.value = tmp_msr.lo;
241     vmx_state->exit_ctrls.host_64_on = 1;
242
243     if ((vmx_state->exit_ctrls.save_efer == 1) || (vmx_state->exit_ctrls.ld_efer == 1)) {
244         vmx_state->ia32e_avail = 1;
245     }
246
247     v3_get_msr(VMX_ENTRY_CTLS_MSR, &(tmp_msr.hi), &(tmp_msr.lo));
248     vmx_state->entry_ctrls.value = tmp_msr.lo;
249
250     {
251         struct vmx_exception_bitmap excp_bmap;
252         excp_bmap.value = 0;
253         
254         excp_bmap.pf = 1;
255     
256         vmx_ret |= check_vmcs_write(VMCS_EXCP_BITMAP, excp_bmap.value);
257     }
258     /******* Setup VMXAssist guest state ***********/
259
260     info->rip = 0xd0000;
261     info->vm_regs.rsp = 0x80000;
262
263     struct rflags * flags = (struct rflags *)&(info->ctrl_regs.rflags);
264     flags->rsvd1 = 1;
265
266     /* Print Control MSRs */
267     v3_get_msr(VMX_CR0_FIXED0_MSR, &(tmp_msr.hi), &(tmp_msr.lo));
268     PrintDebug("CR0 MSR: %p\n", (void *)(addr_t)tmp_msr.value);
269
270     v3_get_msr(VMX_CR4_FIXED0_MSR, &(tmp_msr.hi), &(tmp_msr.lo));
271     PrintDebug("CR4 MSR: %p\n", (void *)(addr_t)tmp_msr.value);
272
273
274 #define GUEST_CR0 0x80000031
275 #define GUEST_CR4 0x00002000
276     info->ctrl_regs.cr0 = GUEST_CR0;
277     info->ctrl_regs.cr4 = GUEST_CR4;
278
279     ((struct cr0_32 *)&(info->shdw_pg_state.guest_cr0))->pe = 1;
280    
281     /* Setup paging */
282     if (info->shdw_pg_mode == SHADOW_PAGING) {
283         PrintDebug("Creating initial shadow page table\n");
284
285         if (v3_init_passthrough_pts(info) == -1) {
286             PrintError("Could not initialize passthrough page tables\n");
287             return -1;
288         }
289         
290 #define CR0_PE 0x00000001
291 #define CR0_PG 0x80000000
292
293
294         vmx_ret |= check_vmcs_write(VMCS_CR0_MASK, (CR0_PE | CR0_PG) );
295         vmx_ret |= check_vmcs_write(VMCS_CR4_MASK, CR4_VMXE);
296
297         info->ctrl_regs.cr3 = info->direct_map_pt;
298
299         // vmx_state->pinbased_ctrls |= NMI_EXIT;
300
301         /* Add CR exits */
302         vmx_state->pri_proc_ctrls.cr3_ld_exit = 1;
303         vmx_state->pri_proc_ctrls.cr3_str_exit = 1;
304     }
305
306     // Setup segment registers
307     {
308         struct v3_segment * seg_reg = (struct v3_segment *)&(info->segments);
309
310         int i;
311
312         for (i = 0; i < 10; i++) {
313             seg_reg[i].selector = 3 << 3;
314             seg_reg[i].limit = 0xffff;
315             seg_reg[i].base = 0x0;
316         }
317
318         info->segments.cs.selector = 2<<3;
319
320         /* Set only the segment registers */
321         for (i = 0; i < 6; i++) {
322             seg_reg[i].limit = 0xfffff;
323             seg_reg[i].granularity = 1;
324             seg_reg[i].type = 3;
325             seg_reg[i].system = 1;
326             seg_reg[i].dpl = 0;
327             seg_reg[i].present = 1;
328             seg_reg[i].db = 1;
329         }
330
331         info->segments.cs.type = 0xb;
332
333         info->segments.ldtr.selector = 0x20;
334         info->segments.ldtr.type = 2;
335         info->segments.ldtr.system = 0;
336         info->segments.ldtr.present = 1;
337         info->segments.ldtr.granularity = 0;
338
339     
340         /************* Map in GDT and vmxassist *************/
341
342         uint64_t  gdt[] __attribute__ ((aligned(32))) = {
343             0x0000000000000000ULL,              /* 0x00: reserved */
344             0x0000830000000000ULL,              /* 0x08: 32-bit TSS */
345             //0x0000890000000000ULL,            /* 0x08: 32-bit TSS */
346             0x00CF9b000000FFFFULL,              /* 0x10: CS 32-bit */
347             0x00CF93000000FFFFULL,              /* 0x18: DS 32-bit */
348             0x000082000000FFFFULL,              /* 0x20: LDTR 32-bit */
349         };
350
351 #define VMXASSIST_GDT   0x10000
352         addr_t vmxassist_gdt = 0;
353
354         if (v3_gpa_to_hva(info, VMXASSIST_GDT, &vmxassist_gdt) == -1) {
355             PrintError("Could not find VMXASSIST GDT destination\n");
356             return -1;
357         }
358
359         memcpy((void *)vmxassist_gdt, gdt, sizeof(uint64_t) * 5);
360         
361         info->segments.gdtr.base = VMXASSIST_GDT;
362
363 #define VMXASSIST_TSS   0x40000
364         uint64_t vmxassist_tss = VMXASSIST_TSS;
365         gdt[0x08 / sizeof(gdt[0])] |=
366             ((vmxassist_tss & 0xFF000000) << (56 - 24)) |
367             ((vmxassist_tss & 0x00FF0000) << (32 - 16)) |
368             ((vmxassist_tss & 0x0000FFFF) << (16)) |
369             (8392 - 1);
370
371         info->segments.tr.selector = 0x08;
372         info->segments.tr.base = vmxassist_tss;
373
374         //info->segments.tr.type = 0x9; 
375         info->segments.tr.type = 0x3;
376         info->segments.tr.system = 0;
377         info->segments.tr.present = 1;
378         info->segments.tr.granularity = 0;
379     }
380  
381     // setup VMXASSIST
382     { 
383 #define VMXASSIST_START 0x000d0000
384         extern uint8_t v3_vmxassist_start[];
385         extern uint8_t v3_vmxassist_end[];
386         addr_t vmxassist_dst = 0;
387
388         if (v3_gpa_to_hva(info, VMXASSIST_START, &vmxassist_dst) == -1) {
389             PrintError("Could not find VMXASSIST destination\n");
390             return -1;
391         }
392
393         memcpy((void *)vmxassist_dst, v3_vmxassist_start, v3_vmxassist_end - v3_vmxassist_start);
394     }    
395
396     /*** Write all the info to the VMCS ***/
397
398 #define DEBUGCTL_MSR 0x1d9
399     v3_get_msr(DEBUGCTL_MSR, &(tmp_msr.hi), &(tmp_msr.lo));
400     vmx_ret |= check_vmcs_write(VMCS_GUEST_DBG_CTL, tmp_msr.value);
401
402     info->dbg_regs.dr7 = 0x400;
403
404     vmx_ret |= check_vmcs_write(VMCS_LINK_PTR, (addr_t)0xffffffffffffffffULL);
405     
406
407     if (v3_update_vmcs_ctrl_fields(info)) {
408         PrintError("Could not write control fields!\n");
409         return -1;
410     }
411     
412     if (v3_update_vmcs_host_state(info)) {
413         PrintError("Could not write host state\n");
414         return -1;
415     }
416
417
418     vmx_state->state = VMXASSIST_DISABLED;
419
420     return 0;
421 }
422
423 int v3_init_vmx_vmcs(struct guest_info * info, v3_vm_class_t vm_class) {
424     struct vmx_data * vmx_state = NULL;
425     int vmx_ret = 0;
426     
427     vmx_state = (struct vmx_data *)V3_Malloc(sizeof(struct vmx_data));
428
429     PrintDebug("vmx_data pointer: %p\n", (void *)vmx_state);
430
431     PrintDebug("Allocating VMCS\n");
432     vmx_state->vmcs_ptr_phys = allocate_vmcs();
433
434     PrintDebug("VMCS pointer: %p\n", (void *)(vmx_state->vmcs_ptr_phys));
435
436     info->vmm_data = vmx_state;
437
438     PrintDebug("Initializing VMCS (addr=%p)\n", info->vmm_data);
439     
440     // TODO: Fix vmcs fields so they're 32-bit
441
442     PrintDebug("Clearing VMCS: %p\n", (void *)vmx_state->vmcs_ptr_phys);
443     vmx_ret = vmcs_clear(vmx_state->vmcs_ptr_phys);
444
445     if (vmx_ret != VMX_SUCCESS) {
446         PrintError("VMCLEAR failed\n");
447         return -1; 
448     }
449
450     if (vm_class == V3_PC_VM) {
451         PrintDebug("Initializing VMCS\n");
452         init_vmcs_bios(info, vmx_state);
453     } else {
454         PrintError("Invalid VM Class\n");
455         return -1;
456     }
457
458     return 0;
459 }
460
461 static int update_irq_exit_state(struct guest_info * info) {
462     struct vmx_exit_idt_vec_info idt_vec_info;
463
464     check_vmcs_read(VMCS_IDT_VECTOR_INFO, &(idt_vec_info.value));
465
466     if ((info->intr_core_state.irq_started == 1) && (idt_vec_info.valid == 0)) {
467 #ifdef CONFIG_DEBUG_INTERRUPTS
468         PrintDebug("Calling v3_injecting_intr\n");
469 #endif
470         info->intr_core_state.irq_started = 0;
471         v3_injecting_intr(info, info->intr_core_state.irq_vector, V3_EXTERNAL_IRQ);
472     }
473
474     return 0;
475 }
476
477 static int update_irq_entry_state(struct guest_info * info) {
478     struct vmx_exit_idt_vec_info idt_vec_info;
479     struct vmcs_interrupt_state intr_core_state;
480     struct vmx_data * vmx_info = (struct vmx_data *)(info->vmm_data);
481
482     check_vmcs_read(VMCS_IDT_VECTOR_INFO, &(idt_vec_info.value));
483     check_vmcs_read(VMCS_GUEST_INT_STATE, &(intr_core_state));
484
485     /* Check for pending exceptions to inject */
486     if (v3_excp_pending(info)) {
487         struct vmx_entry_int_info int_info;
488         int_info.value = 0;
489
490         // In VMX, almost every exception is hardware
491         // Software exceptions are pretty much only for breakpoint or overflow
492         int_info.type = 3;
493         int_info.vector = v3_get_excp_number(info);
494
495         if (info->excp_state.excp_error_code_valid) {
496             check_vmcs_write(VMCS_ENTRY_EXCP_ERR, info->excp_state.excp_error_code);
497             int_info.error_code = 1;
498
499 #ifdef CONFIG_DEBUG_INTERRUPTS
500             PrintDebug("Injecting exception %d with error code %x\n", 
501                     int_info.vector, info->excp_state.excp_error_code);
502 #endif
503         }
504
505         int_info.valid = 1;
506 #ifdef CONFIG_DEBUG_INTERRUPTS
507         PrintDebug("Injecting exception %d (EIP=%p)\n", int_info.vector, (void *)(addr_t)info->rip);
508 #endif
509         check_vmcs_write(VMCS_ENTRY_INT_INFO, int_info.value);
510
511         v3_injecting_excp(info, int_info.vector);
512
513     } else if ((((struct rflags *)&(info->ctrl_regs.rflags))->intr == 1) && 
514                (intr_core_state.val == 0)) {
515        
516         if ((info->intr_core_state.irq_started == 1) && (idt_vec_info.valid == 1)) {
517
518 #ifdef CONFIG_DEBUG_INTERRUPTS
519             PrintDebug("IRQ pending from previous injection\n");
520 #endif
521
522             // Copy the IDT vectoring info over to reinject the old interrupt
523             if (idt_vec_info.error_code == 1) {
524                 uint32_t err_code = 0;
525
526                 check_vmcs_read(VMCS_IDT_VECTOR_ERR, &err_code);
527                 check_vmcs_write(VMCS_ENTRY_EXCP_ERR, err_code);
528             }
529
530             idt_vec_info.undef = 0;
531             check_vmcs_write(VMCS_ENTRY_INT_INFO, idt_vec_info.value);
532
533         } else {
534             struct vmx_entry_int_info ent_int;
535             ent_int.value = 0;
536
537             switch (v3_intr_pending(info)) {
538                 case V3_EXTERNAL_IRQ: {
539                     info->intr_core_state.irq_vector = v3_get_intr(info); 
540                     ent_int.vector = info->intr_core_state.irq_vector;
541                     ent_int.type = 0;
542                     ent_int.error_code = 0;
543                     ent_int.valid = 1;
544
545 #ifdef CONFIG_DEBUG_INTERRUPTS
546                     PrintDebug("Injecting Interrupt %d at exit %u(EIP=%p)\n", 
547                                info->intr_core_state.irq_vector, 
548                                (uint32_t)info->num_exits, 
549                                (void *)(addr_t)info->rip);
550 #endif
551
552                     check_vmcs_write(VMCS_ENTRY_INT_INFO, ent_int.value);
553                     info->intr_core_state.irq_started = 1;
554
555                     break;
556                 }
557                 case V3_NMI:
558                     PrintDebug("Injecting NMI\n");
559
560                     ent_int.type = 2;
561                     ent_int.vector = 2;
562                     ent_int.valid = 1;
563                     check_vmcs_write(VMCS_ENTRY_INT_INFO, ent_int.value);
564
565                     break;
566                 case V3_SOFTWARE_INTR:
567                     PrintDebug("Injecting software interrupt\n");
568                     ent_int.type = 4;
569
570                     ent_int.valid = 1;
571                     check_vmcs_write(VMCS_ENTRY_INT_INFO, ent_int.value);
572
573                     break;
574                 case V3_VIRTUAL_IRQ:
575                     // Not sure what to do here, Intel doesn't have virtual IRQs
576                     // May be the same as external interrupts/IRQs
577
578                     break;
579                 case V3_INVALID_INTR:
580                 default:
581                     break;
582             }
583         }
584     } else if ((v3_intr_pending(info)) && (vmx_info->pri_proc_ctrls.int_wndw_exit == 0)) {
585         // Enable INTR window exiting so we know when IF=1
586         uint32_t instr_len;
587
588         check_vmcs_read(VMCS_EXIT_INSTR_LEN, &instr_len);
589
590 #ifdef CONFIG_DEBUG_INTERRUPTS
591         PrintDebug("Enabling Interrupt-Window exiting: %d\n", instr_len);
592 #endif
593
594         vmx_info->pri_proc_ctrls.int_wndw_exit = 1;
595         check_vmcs_write(VMCS_PROC_CTRLS, vmx_info->pri_proc_ctrls.value);
596     }
597
598
599     return 0;
600 }
601
602
603
604 static struct vmx_exit_info exit_log[10];
605
606 static void print_exit_log(struct guest_info * info) {
607     int cnt = info->num_exits % 10;
608     int i = 0;
609     
610
611     V3_Print("\nExit Log (%d total exits):\n", (uint32_t)info->num_exits);
612
613     for (i = 0; i < 10; i++) {
614         struct vmx_exit_info * tmp = &exit_log[cnt];
615
616         V3_Print("%d:\texit_reason = %p\n", i, (void *)(addr_t)tmp->exit_reason);
617         V3_Print("\texit_qual = %p\n", (void *)tmp->exit_qual);
618         V3_Print("\tint_info = %p\n", (void *)(addr_t)tmp->int_info);
619         V3_Print("\tint_err = %p\n", (void *)(addr_t)tmp->int_err);
620         V3_Print("\tinstr_info = %p\n", (void *)(addr_t)tmp->instr_info);
621
622         cnt--;
623
624         if (cnt == -1) {
625             cnt = 9;
626         }
627
628     }
629
630 }
631
632 /* 
633  * CAUTION and DANGER!!! 
634  * 
635  * The VMCS CANNOT(!!) be accessed outside of the cli/sti calls inside this function
636  * When exectuing a symbiotic call, the VMCS WILL be overwritten, so any dependencies 
637  * on its contents will cause things to break. The contents at the time of the exit WILL 
638  * change before the exit handler is executed.
639  */
640 int v3_vmx_enter(struct guest_info * info) {
641     int ret = 0;
642     uint32_t tsc_offset_low, tsc_offset_high;
643     struct vmx_exit_info exit_info;
644
645     // Conditionally yield the CPU if the timeslice has expired
646     v3_yield_cond(info);
647
648     // v3_print_guest_state(info);
649
650     // disable global interrupts for vm state transition
651     v3_disable_ints();
652
653     v3_vmx_restore_vmcs(info);
654
655
656 #ifdef CONFIG_SYMCALL
657     if (info->sym_core_state.symcall_state.sym_call_active == 0) {
658         update_irq_entry_state(info);
659     }
660 #else 
661     update_irq_entry_state(info);
662 #endif
663
664     {
665         addr_t guest_cr3;
666         vmcs_read(VMCS_GUEST_CR3, &guest_cr3);
667         vmcs_write(VMCS_GUEST_CR3, guest_cr3);
668     }
669
670     v3_update_timers(info);
671     v3_resume_time(info);
672
673     tsc_offset_high = 
674         (uint32_t)((info->time_state.host_offset >> 32) & 0xffffffff);
675     tsc_offset_low = (uint32_t)(info->time_state.host_offset & 0xffffffff);
676 #ifdef CONFIG_TIME_TSC_OFFSET
677     check_vmcs_write(VMCS_TSC_OFFSET_HIGH, tsc_offset_high);
678     check_vmcs_write(VMCS_TSC_OFFSET, tsc_offset_low);
679 #endif
680
681     PrintDebug("Stored 0x %x %x into vmcs TSC offset.\n", 
682                tsc_offset_high, tsc_offset_low);
683     if (info->vm_info->run_state == VM_STOPPED) {
684         info->vm_info->run_state = VM_RUNNING;
685         ret = v3_vmx_launch(&(info->vm_regs), info, &(info->ctrl_regs));
686     } else {
687         ret = v3_vmx_resume(&(info->vm_regs), info, &(info->ctrl_regs));
688     }
689
690     //  PrintDebug("VMX Exit: ret=%d\n", ret);
691
692     if (ret != VMX_SUCCESS) {
693         uint32_t error = 0;
694
695         vmcs_read(VMCS_INSTR_ERR, &error);
696         PrintError("VMENTRY Error: %d\n", error);
697
698         return -1;
699     }
700
701     v3_pause_time(info);
702 #ifdef CONFIG_TIME_MASK_OVERHEAD
703     v3_offset_time(info, -VMX_ENTRY_OVERHEAD);
704 #endif
705
706     info->num_exits++;
707
708     /* Update guest state */
709     v3_vmx_save_vmcs(info);
710
711     // info->cpl = info->segments.cs.selector & 0x3;
712
713     info->mem_mode = v3_get_vm_mem_mode(info);
714     info->cpu_mode = v3_get_vm_cpu_mode(info);
715
716
717     check_vmcs_read(VMCS_EXIT_INSTR_LEN, &(exit_info.instr_len));
718     check_vmcs_read(VMCS_EXIT_INSTR_INFO, &(exit_info.instr_info));
719     check_vmcs_read(VMCS_EXIT_REASON, &(exit_info.exit_reason));
720     check_vmcs_read(VMCS_EXIT_QUAL, &(exit_info.exit_qual));
721     check_vmcs_read(VMCS_EXIT_INT_INFO, &(exit_info.int_info));
722     check_vmcs_read(VMCS_EXIT_INT_ERR, &(exit_info.int_err));
723     check_vmcs_read(VMCS_GUEST_LINEAR_ADDR, &(exit_info.guest_linear_addr));
724
725     //PrintDebug("VMX Exit taken, id-qual: %u-%lu\n", exit_info.exit_reason, exit_info.exit_qual);
726
727     exit_log[info->num_exits % 10] = exit_info;
728
729
730 #ifdef CONFIG_SYMCALL
731     if (info->sym_core_state.symcall_state.sym_call_active == 0) {
732         update_irq_exit_state(info);
733     }
734 #else
735     update_irq_exit_state(info);
736 #endif
737
738     // reenable global interrupts after vm exit
739     v3_enable_ints();
740
741     // Conditionally yield the CPU if the timeslice has expired
742     v3_yield_cond(info);
743
744     if (v3_handle_vmx_exit(info, &exit_info) == -1) {
745         PrintError("Error in VMX exit handler\n");
746         return -1;
747     }
748
749     return 0;
750 }
751
752
753 int v3_start_vmx_guest(struct guest_info* info) {
754
755
756     PrintDebug("Launching VMX guest\n");
757
758     v3_start_time(info);
759
760     while (1) {
761         if (v3_vmx_enter(info) == -1) {
762             v3_print_vmcs();
763             print_exit_log(info);
764             return -1;
765         }
766
767 /*
768         if ((info->num_exits % 5000) == 0) {
769             V3_Print("VMX Exit number %d\n", (uint32_t)info->num_exits);
770         }
771 */
772
773     }
774
775     return 0;
776 }
777
778
779 int v3_is_vmx_capable() {
780     v3_msr_t feature_msr;
781     uint32_t eax = 0, ebx = 0, ecx = 0, edx = 0;
782
783     v3_cpuid(0x1, &eax, &ebx, &ecx, &edx);
784
785     PrintDebug("ECX: 0x%x\n", ecx);
786
787     if (ecx & CPUID_1_ECX_VTXFLAG) {
788         v3_get_msr(VMX_FEATURE_CONTROL_MSR, &(feature_msr.hi), &(feature_msr.lo));
789         
790         PrintDebug("MSRREGlow: 0x%.8x\n", feature_msr.lo);
791
792         if ((feature_msr.lo & FEATURE_CONTROL_VALID) != FEATURE_CONTROL_VALID) {
793             PrintDebug("VMX is locked -- enable in the BIOS\n");
794             return 0;
795         }
796
797     } else {
798         PrintDebug("VMX not supported on this cpu\n");
799         return 0;
800     }
801
802     return 1;
803 }
804
805 static int has_vmx_nested_paging() {
806     return 0;
807 }
808
809
810
811 void v3_init_vmx_cpu(int cpu_id) {
812     extern v3_cpu_arch_t v3_cpu_types[];
813     struct v3_msr tmp_msr;
814     uint64_t ret = 0;
815
816     v3_get_msr(VMX_CR4_FIXED0_MSR,&(tmp_msr.hi),&(tmp_msr.lo));
817 #ifdef __V3_64BIT__
818     __asm__ __volatile__ (
819                           "movq %%cr4, %%rbx;"
820                           "orq  $0x00002000, %%rbx;"
821                           "movq %%rbx, %0;"
822                           : "=m"(ret) 
823                           :
824                           : "%rbx"
825                           );
826
827     if ((~ret & tmp_msr.value) == 0) {
828         __asm__ __volatile__ (
829                               "movq %0, %%cr4;"
830                               :
831                               : "q"(ret)
832                               );
833     } else {
834         PrintError("Invalid CR4 Settings!\n");
835         return;
836     }
837
838     __asm__ __volatile__ (
839                           "movq %%cr0, %%rbx; "
840                           "orq  $0x00000020,%%rbx; "
841                           "movq %%rbx, %%cr0;"
842                           :
843                           :
844                           : "%rbx"
845                           );
846 #elif __V3_32BIT__
847     __asm__ __volatile__ (
848                           "movl %%cr4, %%ecx;"
849                           "orl  $0x00002000, %%ecx;"
850                           "movl %%ecx, %0;"
851                           : "=m"(ret) 
852                           :
853                           : "%ecx"
854                           );
855
856     if ((~ret & tmp_msr.value) == 0) {
857         __asm__ __volatile__ (
858                               "movl %0, %%cr4;"
859                               :
860                               : "q"(ret)
861                               );
862     } else {
863         PrintError("Invalid CR4 Settings!\n");
864         return;
865     }
866
867     __asm__ __volatile__ (
868                           "movl %%cr0, %%ecx; "
869                           "orl  $0x00000020,%%ecx; "
870                           "movl %%ecx, %%cr0;"
871                           :
872                           :
873                           : "%ecx"
874                           );
875
876 #endif
877
878     //
879     // Should check and return Error here.... 
880
881
882     // Setup VMXON Region
883     host_vmcs_ptrs[cpu_id] = allocate_vmcs();
884
885     PrintDebug("VMXON pointer: 0x%p\n", (void *)host_vmcs_ptrs[cpu_id]);
886
887     if (v3_enable_vmx(host_vmcs_ptrs[cpu_id]) == VMX_SUCCESS) {
888         PrintDebug("VMX Enabled\n");
889     } else {
890         PrintError("VMX initialization failure\n");
891         return;
892     }
893     
894
895     if (has_vmx_nested_paging() == 1) {
896         v3_cpu_types[cpu_id] = V3_VMX_EPT_CPU;
897     } else {
898         v3_cpu_types[cpu_id] = V3_VMX_CPU;
899     }
900
901 }
902