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.
6 * The V3VEE Project is a joint project between Northwestern University
7 * and the University of New Mexico. You can find out more at
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.
15 * Author: Peter Dinda <pdinda@northwestern.edu>
16 * Jack Lange <jarusl@cs.northwestern.edu>
18 * This is free software. You are permitted to use,
19 * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
23 #include <palacios/vmx.h>
24 #include <palacios/vmm.h>
25 #include <palacios/vmx_lowlevel.h>
26 #include <palacios/vmm_lowlevel.h>
27 #include <palacios/vmm_ctrl_regs.h>
28 #include <palacios/vmm_config.h>
29 #include <palacios/vm_guest_mem.h>
30 #include <palacios/vmm_direct_paging.h>
31 #include <palacios/vmx_io.h>
32 #include <palacios/vmx_msr.h>
34 static addr_t vmxon_ptr_phys;
35 extern int v3_vmx_exit_handler();
36 extern int v3_vmx_vmlaunch(struct v3_gprs * vm_regs, struct guest_info * info);
38 static int inline check_vmcs_write(vmcs_field_t field, addr_t val)
41 ret = vmcs_write(field,val);
43 if (ret != VMX_SUCCESS) {
44 PrintError("VMWRITE error on %s!: %d\n", v3_vmcs_field_to_str(field), ret);
51 static void inline translate_segment_access(struct v3_segment * v3_seg,
52 struct vmcs_segment_access * access)
54 access->type = v3_seg->type;
55 access->desc_type = v3_seg->system;
56 access->dpl = v3_seg->dpl;
57 access->present = v3_seg->present;
58 access->avail = v3_seg->avail;
59 access->long_mode = v3_seg->long_mode;
60 access->db = v3_seg->db;
61 access->granularity = v3_seg->granularity;
64 int v3_update_vmcs_ctrl_fields(struct guest_info * info) {
66 struct vmx_data * arch_data = (struct vmx_data *)(info->vmm_data);
68 vmx_ret |= check_vmcs_write(VMCS_PIN_CTRLS, arch_data->pinbased_ctrls);
69 vmx_ret |= check_vmcs_write(VMCS_PROC_CTRLS, arch_data->pri_procbased_ctrls);
71 if(arch_data->pri_procbased_ctrls & ACTIVE_SEC_CTRLS) {
72 vmx_ret |= check_vmcs_write(VMCS_SEC_PROC_CTRLS, arch_data->sec_procbased_ctrls);
75 vmx_ret |= check_vmcs_write(VMCS_EXIT_CTRLS, arch_data->exit_ctrls);
76 vmx_ret |= check_vmcs_write(VMCS_ENTRY_CTRLS, arch_data->entry_ctrls);
81 int v3_update_vmcs_host_state(struct guest_info * info) {
84 struct vmx_data * arch_data = (struct vmx_data *)(info->vmm_data);
85 struct v3_msr tmp_msr;
87 __asm__ __volatile__ ( "movq %%cr0, %0; "
91 vmx_ret |= check_vmcs_write(VMCS_HOST_CR0, tmp);
94 __asm__ __volatile__ ( "movq %%cr3, %0; "
98 vmx_ret |= check_vmcs_write(VMCS_HOST_CR3, tmp);
101 __asm__ __volatile__ ( "movq %%cr4, %0; "
105 vmx_ret |= check_vmcs_write(VMCS_HOST_CR4, tmp);
109 vmx_ret |= check_vmcs_write(VMCS_HOST_GDTR_BASE, arch_data->host_state.gdtr.base);
110 vmx_ret |= check_vmcs_write(VMCS_HOST_IDTR_BASE, arch_data->host_state.idtr.base);
111 vmx_ret |= check_vmcs_write(VMCS_HOST_TR_BASE, arch_data->host_state.tr.base);
113 #define FS_BASE_MSR 0xc0000100
114 #define GS_BASE_MSR 0xc0000101
117 v3_get_msr(FS_BASE_MSR, &(tmp_msr.hi), &(tmp_msr.lo));
118 vmx_ret |= check_vmcs_write(VMCS_HOST_FS_BASE, tmp_msr.value);
121 v3_get_msr(GS_BASE_MSR, &(tmp_msr.hi), &(tmp_msr.lo));
122 vmx_ret |= check_vmcs_write(VMCS_HOST_GS_BASE, tmp_msr.value);
126 __asm__ __volatile__ ( "movq %%cs, %0; "
130 vmx_ret |= check_vmcs_write(VMCS_HOST_CS_SELECTOR, tmp);
132 __asm__ __volatile__ ( "movq %%ss, %0; "
136 vmx_ret |= check_vmcs_write(VMCS_HOST_SS_SELECTOR, tmp);
138 __asm__ __volatile__ ( "movq %%ds, %0; "
142 vmx_ret |= check_vmcs_write(VMCS_HOST_DS_SELECTOR, tmp);
144 __asm__ __volatile__ ( "movq %%es, %0; "
148 vmx_ret |= check_vmcs_write(VMCS_HOST_ES_SELECTOR, tmp);
150 __asm__ __volatile__ ( "movq %%fs, %0; "
154 vmx_ret |= check_vmcs_write(VMCS_HOST_FS_SELECTOR, tmp);
156 __asm__ __volatile__ ( "movq %%gs, %0; "
160 vmx_ret |= check_vmcs_write(VMCS_HOST_GS_SELECTOR, tmp);
162 vmx_ret |= check_vmcs_write(VMCS_HOST_TR_SELECTOR, arch_data->host_state.tr.selector);
165 #define SYSENTER_CS_MSR 0x00000174
166 #define SYSENTER_ESP_MSR 0x00000175
167 #define SYSENTER_EIP_MSR 0x00000176
170 v3_get_msr(SYSENTER_CS_MSR, &(tmp_msr.hi), &(tmp_msr.lo));
171 vmx_ret |= check_vmcs_write(VMCS_HOST_SYSENTER_CS, tmp_msr.lo);
174 v3_get_msr(SYSENTER_ESP_MSR, &(tmp_msr.hi), &(tmp_msr.lo));
175 vmx_ret |= check_vmcs_write(VMCS_HOST_SYSENTER_ESP, tmp_msr.value);
178 v3_get_msr(SYSENTER_EIP_MSR, &(tmp_msr.hi), &(tmp_msr.lo));
179 vmx_ret |= check_vmcs_write(VMCS_HOST_SYSENTER_EIP, tmp_msr.value);
185 int v3_update_vmcs_guest_state(struct guest_info * info)
189 vmx_ret |= check_vmcs_write(VMCS_GUEST_RIP, info->rip);
190 vmx_ret |= check_vmcs_write(VMCS_GUEST_RSP, info->vm_regs.rsp);
193 vmx_ret |= check_vmcs_write(VMCS_GUEST_CR0, info->ctrl_regs.cr0);
194 vmx_ret |= check_vmcs_write(VMCS_GUEST_CR3, info->ctrl_regs.cr3);
195 vmx_ret |= check_vmcs_write(VMCS_GUEST_CR4, info->ctrl_regs.cr4);
197 vmx_ret |= check_vmcs_write(VMCS_GUEST_RFLAGS, info->ctrl_regs.rflags);
201 /*** Write VMCS Segments ***/
202 struct vmcs_segment_access access;
204 memset(&access, 0, sizeof(access));
207 translate_segment_access(&(info->segments.cs), &access);
209 vmx_ret |= check_vmcs_write(VMCS_GUEST_CS_BASE, info->segments.cs.base);
210 vmx_ret |= check_vmcs_write(VMCS_GUEST_CS_SELECTOR, info->segments.cs.selector);
211 vmx_ret |= check_vmcs_write(VMCS_GUEST_CS_LIMIT, info->segments.cs.limit);
212 vmx_ret |= check_vmcs_write(VMCS_GUEST_CS_ACCESS, access.value);
215 memset(&access, 0, sizeof(access));
216 translate_segment_access(&(info->segments.ss), &access);
218 vmx_ret |= check_vmcs_write(VMCS_GUEST_SS_BASE, info->segments.ss.base);
219 vmx_ret |= check_vmcs_write(VMCS_GUEST_SS_SELECTOR, info->segments.ss.selector);
220 vmx_ret |= check_vmcs_write(VMCS_GUEST_SS_LIMIT, info->segments.ss.limit);
221 vmx_ret |= check_vmcs_write(VMCS_GUEST_SS_ACCESS, access.value);
224 memset(&access, 0, sizeof(access));
225 translate_segment_access(&(info->segments.ds), &access);
227 vmx_ret |= check_vmcs_write(VMCS_GUEST_DS_BASE, info->segments.ds.base);
228 vmx_ret |= check_vmcs_write(VMCS_GUEST_DS_SELECTOR, info->segments.ds.selector);
229 vmx_ret |= check_vmcs_write(VMCS_GUEST_DS_LIMIT, info->segments.ds.limit);
230 vmx_ret |= check_vmcs_write(VMCS_GUEST_DS_ACCESS, access.value);
234 memset(&access, 0, sizeof(access));
235 translate_segment_access(&(info->segments.es), &access);
237 vmx_ret |= check_vmcs_write(VMCS_GUEST_ES_BASE, info->segments.es.base);
238 vmx_ret |= check_vmcs_write(VMCS_GUEST_ES_SELECTOR, info->segments.es.selector);
239 vmx_ret |= check_vmcs_write(VMCS_GUEST_ES_LIMIT, info->segments.es.limit);
240 vmx_ret |= check_vmcs_write(VMCS_GUEST_ES_ACCESS, access.value);
243 memset(&access, 0, sizeof(access));
244 translate_segment_access(&(info->segments.fs), &access);
246 vmx_ret |= check_vmcs_write(VMCS_GUEST_FS_BASE, info->segments.fs.base);
247 vmx_ret |= check_vmcs_write(VMCS_GUEST_FS_SELECTOR, info->segments.fs.selector);
248 vmx_ret |= check_vmcs_write(VMCS_GUEST_FS_LIMIT, info->segments.fs.limit);
249 vmx_ret |= check_vmcs_write(VMCS_GUEST_FS_ACCESS, access.value);
252 memset(&access, 0, sizeof(access));
253 translate_segment_access(&(info->segments.gs), &access);
255 vmx_ret |= check_vmcs_write(VMCS_GUEST_GS_BASE, info->segments.gs.base);
256 vmx_ret |= check_vmcs_write(VMCS_GUEST_GS_SELECTOR, info->segments.gs.selector);
257 vmx_ret |= check_vmcs_write(VMCS_GUEST_GS_LIMIT, info->segments.gs.limit);
258 vmx_ret |= check_vmcs_write(VMCS_GUEST_GS_ACCESS, access.value);
261 memset(&access, 0, sizeof(access));
262 translate_segment_access(&(info->segments.ldtr), &access);
264 vmx_ret |= check_vmcs_write(VMCS_GUEST_LDTR_BASE, info->segments.ldtr.base);
265 vmx_ret |= check_vmcs_write(VMCS_GUEST_LDTR_SELECTOR, info->segments.ldtr.selector);
266 vmx_ret |= check_vmcs_write(VMCS_GUEST_LDTR_LIMIT, info->segments.ldtr.limit);
267 vmx_ret |= check_vmcs_write(VMCS_GUEST_LDTR_ACCESS, access.value);
270 memset(&access, 0, sizeof(access));
271 translate_segment_access(&(info->segments.tr), &access);
273 vmx_ret |= check_vmcs_write(VMCS_GUEST_TR_BASE, info->segments.tr.base);
274 vmx_ret |= check_vmcs_write(VMCS_GUEST_TR_SELECTOR, info->segments.tr.selector);
275 vmx_ret |= check_vmcs_write(VMCS_GUEST_TR_LIMIT, info->segments.tr.limit);
276 vmx_ret |= check_vmcs_write(VMCS_GUEST_TR_ACCESS, access.value);
280 vmx_ret |= check_vmcs_write(VMCS_GUEST_GDTR_BASE, info->segments.gdtr.base);
281 vmx_ret |= check_vmcs_write(VMCS_GUEST_GDTR_LIMIT, info->segments.gdtr.limit);
284 vmx_ret |= check_vmcs_write(VMCS_GUEST_IDTR_BASE, info->segments.idtr.base);
285 vmx_ret |= check_vmcs_write(VMCS_GUEST_IDTR_LIMIT, info->segments.idtr.limit);
295 // For the 32 bit reserved bit fields
296 // MB1s are in the low 32 bits, MBZs are in the high 32 bits of the MSR
297 static uint32_t sanitize_bits1(uint32_t msr_num, uint32_t val) {
300 PrintDebug("sanitize_bits1 (MSR:%x)\n", msr_num);
302 v3_get_msr(msr_num, &mask_msr.hi, &mask_msr.lo);
304 PrintDebug("MSR %x = %x : %x \n", msr_num, mask_msr.hi, mask_msr.lo);
314 static addr_t sanitize_bits2(uint32_t msr_num0, uint32_t msr_num1, addr_t val) {
316 addr_t msr0_val, msr1_val;
318 PrintDebug("sanitize_bits2 (MSR0=%x, MSR1=%x)\n", msr_num0, msr_num1);
320 v3_get_msr(msr_num0, &msr0.hi, &msr0.lo);
321 v3_get_msr(msr_num1, &msr1.hi, &msr1.lo);
323 // This generates a mask that is the natural bit width of the CPU
324 msr0_val = msr0.value;
325 msr1_val = msr1.value;
327 PrintDebug("MSR %x = %p, %x = %p \n", msr_num0, (void*)msr0_val, msr_num1, (void*)msr1_val);
340 static addr_t allocate_vmcs()
343 PrintDebug("Allocating page\n");
344 struct vmcs_data * vmcs_page = (struct vmcs_data *)V3_VAddr(V3_AllocPages(1));
347 memset(vmcs_page, 0, 4096);
349 v3_get_msr(VMX_BASIC_MSR, &(msr.e_reg.high), &(msr.e_reg.low));
351 vmcs_page->revision = ((struct vmx_basic_msr*)&msr)->revision;
352 PrintDebug("VMX Revision: 0x%x\n",vmcs_page->revision);
354 return (addr_t)V3_PAddr((void *)vmcs_page);
358 static int init_vmx_guest(struct guest_info * info, struct v3_vm_config * config_ptr) {
359 v3_pre_config_guest(info, config_ptr);
361 struct vmx_data * vmx_data = NULL;
363 vmx_data = (struct vmx_data *)V3_Malloc(sizeof(struct vmx_data));
365 PrintDebug("vmx_data pointer: %p\n", (void *)vmx_data);
367 PrintDebug("Allocating VMCS\n");
368 vmx_data->vmcs_ptr_phys = allocate_vmcs();
370 PrintDebug("VMCS pointer: %p\n", (void *)(vmx_data->vmcs_ptr_phys));
372 info->vmm_data = vmx_data;
374 PrintDebug("Initializing VMCS (addr=%p)\n", info->vmm_data);
376 // TODO: Fix vmcs fields so they're 32-bit
379 PrintDebug("Clearing VMCS: %p\n",(void*)vmx_data->vmcs_ptr_phys);
380 vmx_ret = vmcs_clear(vmx_data->vmcs_ptr_phys);
382 if (vmx_ret != VMX_SUCCESS) {
383 PrintError("VMCLEAR failed\n");
387 PrintDebug("Loading VMCS\n");
388 vmx_ret = vmcs_load(vmx_data->vmcs_ptr_phys);
390 if (vmx_ret != VMX_SUCCESS) {
391 PrintError("VMPTRLD failed\n");
397 /******* Setup Host State **********/
399 /* Cache GDTR, IDTR, and TR in host struct */
404 } __attribute__((packed)) tmp_seg;
407 __asm__ __volatile__(
413 gdtr_base = tmp_seg.base;
414 vmx_data->host_state.gdtr.base = gdtr_base;
416 __asm__ __volatile__(
422 vmx_data->host_state.idtr.base = tmp_seg.base;
424 __asm__ __volatile__(
430 vmx_data->host_state.tr.selector = tmp_seg.selector;
432 /* The GDTR *index* is bits 3-15 of the selector. */
433 struct tss_descriptor * desc = (struct tss_descriptor *)
434 (gdtr_base + 8*(tmp_seg.selector>>3));
438 (desc->base2 << 16) |
439 (desc->base3 << 24) |
441 ((uint64_t)desc->base4 << 32)
447 vmx_data->host_state.tr.base = tmp_seg.base;
451 /********** Setup and VMX Control Fields from MSR ***********/
453 (void) v3_init_vmx_io_map(info);
454 (void) v3_init_vmx_msr_map(info);
456 struct v3_msr tmp_msr;
458 v3_get_msr(VMX_PINBASED_CTLS_MSR,&(tmp_msr.hi),&(tmp_msr.lo));
459 /* Add NMI exiting */
460 vmx_data->pinbased_ctrls = tmp_msr.lo | NMI_EXIT;
462 v3_get_msr(VMX_PROCBASED_CTLS_MSR, &(tmp_msr.hi), &(tmp_msr.lo));
464 PrintDebug("MSR High: 0x%x\n", tmp_msr.hi);
465 vmx_data->pri_procbased_ctrls = tmp_msr.lo | USE_IO_BITMAPS ;
467 vmx_ret |= check_vmcs_write(VMCS_IO_BITMAP_A_ADDR, (addr_t)V3_PAddr(info->io_map.arch_data));
468 vmx_ret |= check_vmcs_write(VMCS_IO_BITMAP_B_ADDR,
469 (addr_t)V3_PAddr(info->io_map.arch_data) + PAGE_SIZE_4KB);
471 vmx_ret |= check_vmcs_write(VMCS_MSR_BITMAP, (addr_t)V3_PAddr(info->msr_map.arch_data));
473 v3_get_msr(VMX_EXIT_CTLS_MSR, &(tmp_msr.hi), &(tmp_msr.lo));
474 vmx_data->exit_ctrls = tmp_msr.lo ;
476 v3_get_msr(VMX_ENTRY_CTLS_MSR, &(tmp_msr.hi), &(tmp_msr.lo));
477 vmx_data->entry_ctrls = tmp_msr.lo;
479 struct vmx_exception_bitmap excp_bmap;
480 excp_bmap.value = 0xffffffff;
482 vmx_ret |= check_vmcs_write(VMCS_EXCP_BITMAP, excp_bmap.value);
485 /******* Setup VMXAssist guest state ***********/
488 info->vm_regs.rsp = 0x80000;
490 struct rflags * flags = (struct rflags *)&(info->ctrl_regs.rflags);
493 /* Print Control MSRs */
494 v3_get_msr(VMX_CR0_FIXED0_MSR, &(tmp_msr.hi), &(tmp_msr.lo));
495 PrintDebug("CR0 MSR: %p\n", (void *)(addr_t)tmp_msr.value);
496 v3_get_msr(VMX_CR4_FIXED0_MSR, &(tmp_msr.hi), &(tmp_msr.lo));
497 PrintDebug("CR4 MSR: %p\n", (void *)(addr_t)tmp_msr.value);
500 #define GUEST_CR0 0x80000031
501 #define GUEST_CR4 0x00002000
502 info->ctrl_regs.cr0 = GUEST_CR0;
503 info->ctrl_regs.cr4 = GUEST_CR4;
506 if(info->shdw_pg_mode == SHADOW_PAGING) {
507 PrintDebug("Creating initial shadow page table\n");
509 if(v3_init_passthrough_pts(info) == -1) {
510 PrintError("Could not initialize passthrough page tables\n");
514 info->shdw_pg_state.guest_cr0 = CR0_PE;
515 PrintDebug("Created\n");
517 vmx_ret |= check_vmcs_write(VMCS_CR0_MASK, (CR0_PE | CR0_PG) );
518 vmx_ret |= check_vmcs_write(VMCS_CR0_READ_SHDW, info->shdw_pg_state.guest_cr0);
519 vmx_ret |= check_vmcs_write(VMCS_CR4_MASK, CR4_VMXE);
521 info->ctrl_regs.cr3 = info->direct_map_pt;
523 // vmx_data->pinbased_ctrls |= NMI_EXIT;
526 vmx_data->pri_procbased_ctrls |= CR3_LOAD_EXIT
529 vmx_data->exit_ctrls |= HOST_ADDR_SPACE_SIZE;
532 struct v3_segment * seg_reg = (struct v3_segment *)&(info->segments);
535 for(i=0; i < 10; i++)
537 seg_reg[i].selector = 3<<3;
538 seg_reg[i].limit = 0xffff;
539 seg_reg[i].base = 0x0;
541 info->segments.cs.selector = 2<<3;
543 /* Set only the segment registers */
544 for(i=0; i < 6; i++) {
545 seg_reg[i].limit = 0xfffff;
546 seg_reg[i].granularity = 1;
548 seg_reg[i].system = 1;
550 seg_reg[i].present = 1;
553 info->segments.cs.type = 0xb;
555 info->segments.ldtr.selector = 0x20;
556 info->segments.ldtr.type = 2;
557 info->segments.ldtr.system = 0;
558 info->segments.ldtr.present = 1;
559 info->segments.ldtr.granularity = 0;
562 /************* Map in GDT and vmxassist *************/
564 uint64_t gdt[] __attribute__ ((aligned(32))) = {
565 0x0000000000000000ULL, /* 0x00: reserved */
566 0x0000830000000000ULL, /* 0x08: 32-bit TSS */
567 //0x0000890000000000ULL, /* 0x08: 32-bit TSS */
568 0x00CF9b000000FFFFULL, /* 0x10: CS 32-bit */
569 0x00CF93000000FFFFULL, /* 0x18: DS 32-bit */
570 0x000082000000FFFFULL, /* 0x20: LDTR 32-bit */
573 #define VMXASSIST_GDT 0x10000
574 addr_t vmxassist_gdt = 0;
575 if(guest_pa_to_host_va(info, VMXASSIST_GDT, &vmxassist_gdt) == -1) {
576 PrintError("Could not find VMXASSIST GDT destination\n");
579 memcpy((void*)vmxassist_gdt, gdt, sizeof(uint64_t) * 5);
581 info->segments.gdtr.base = VMXASSIST_GDT;
583 #define VMXASSIST_TSS 0x40000
584 uint64_t vmxassist_tss = VMXASSIST_TSS;
585 gdt[0x08 / sizeof(gdt[0])] |=
586 ((vmxassist_tss & 0xFF000000) << (56 - 24)) |
587 ((vmxassist_tss & 0x00FF0000) << (32 - 16)) |
588 ((vmxassist_tss & 0x0000FFFF) << (16)) |
591 info->segments.tr.selector = 0x08;
592 info->segments.tr.base = vmxassist_tss;
594 //info->segments.tr.type = 0x9;
595 info->segments.tr.type = 0x3;
596 info->segments.tr.system = 0;
597 info->segments.tr.present = 1;
598 info->segments.tr.granularity = 0;
601 #define VMXASSIST_START 0x000d0000
602 extern uint8_t v3_vmxassist_start[];
603 extern uint8_t v3_vmxassist_end[];
605 addr_t vmxassist_dst = 0;
606 if(guest_pa_to_host_va(info, VMXASSIST_START, &vmxassist_dst) == -1) {
607 PrintError("Could not find VMXASSIST destination\n");
610 memcpy((void*)vmxassist_dst, v3_vmxassist_start, v3_vmxassist_end - v3_vmxassist_start);
612 /*** Write all the info to the VMCS ***/
614 #define DEBUGCTL_MSR 0x1d9
615 v3_get_msr(DEBUGCTL_MSR, &(tmp_msr.hi), &(tmp_msr.lo));
616 vmx_ret |= check_vmcs_write(VMCS_GUEST_DBG_CTL, tmp_msr.value);
618 vmx_ret |= check_vmcs_write(VMCS_GUEST_DR7, 0x400);
620 vmx_ret |= check_vmcs_write(VMCS_LINK_PTR, (addr_t)0xffffffffffffffffULL);
622 if(v3_update_vmcs_ctrl_fields(info)) {
623 PrintError("Could not write control fields!\n");
627 if(v3_update_vmcs_host_state(info)) {
628 PrintError("Could not write host state\n");
633 if(v3_update_vmcs_guest_state(info) != VMX_SUCCESS) {
634 PrintError("Writing guest state failed!\n");
640 vmx_data->state = VMXASSIST_DISABLED;
642 v3_post_config_guest(info, config_ptr);
648 static int start_vmx_guest(struct guest_info* info) {
652 PrintDebug("Attempting VMLAUNCH\n");
654 ret = v3_vmx_vmlaunch(&(info->vm_regs), info);
655 if (ret != VMX_SUCCESS) {
656 vmcs_read(VMCS_INSTR_ERR, &error);
657 PrintError("VMLAUNCH failed: %d\n", error);
662 PrintDebug("Returned from VMLAUNCH ret=%d(0x%x)\n", ret, ret);
668 int v3_is_vmx_capable() {
669 v3_msr_t feature_msr;
670 addr_t eax = 0, ebx = 0, ecx = 0, edx = 0;
672 v3_cpuid(0x1, &eax, &ebx, &ecx, &edx);
674 PrintDebug("ECX: %p\n", (void*)ecx);
676 if (ecx & CPUID_1_ECX_VTXFLAG) {
677 v3_get_msr(VMX_FEATURE_CONTROL_MSR, &(feature_msr.hi), &(feature_msr.lo));
679 PrintDebug("MSRREGlow: 0x%.8x\n", feature_msr.lo);
681 if ((feature_msr.lo & FEATURE_CONTROL_VALID) != FEATURE_CONTROL_VALID) {
682 PrintDebug("VMX is locked -- enable in the BIOS\n");
687 PrintDebug("VMX not supported on this cpu\n");
694 static int has_vmx_nested_paging() {
700 void v3_init_vmx(struct v3_ctrl_ops * vm_ops) {
701 extern v3_cpu_arch_t v3_cpu_type;
703 struct v3_msr tmp_msr;
706 v3_get_msr(VMX_CR4_FIXED0_MSR,&(tmp_msr.hi),&(tmp_msr.lo));
708 __asm__ __volatile__ (
710 "orq $0x00002000, %%rbx;"
717 if((~ret & tmp_msr.value) == 0) {
718 __asm__ __volatile__ (
724 PrintError("Invalid CR4 Settings!\n");
727 __asm__ __volatile__ (
728 "movq %%cr0, %%rbx; "
729 "orq $0x00000020,%%rbx; "
736 // Should check and return Error here....
739 // Setup VMXON Region
740 vmxon_ptr_phys = allocate_vmcs();
741 PrintDebug("VMXON pointer: 0x%p\n", (void*)vmxon_ptr_phys);
743 if (v3_enable_vmx(vmxon_ptr_phys) == VMX_SUCCESS) {
744 PrintDebug("VMX Enabled\n");
746 PrintError("VMX initialization failure\n");
751 if (has_vmx_nested_paging() == 1) {
752 v3_cpu_type = V3_VMX_EPT_CPU;
754 v3_cpu_type = V3_VMX_CPU;
757 // Setup the VMX specific vmm operations
758 vm_ops->init_guest = &init_vmx_guest;
759 vm_ops->start_guest = &start_vmx_guest;
760 vm_ops->has_nested_paging = &has_vmx_nested_paging;