iap10@3290: /* iap10@3290: * vmx_vmcs.c: VMCS management iap10@3290: * Copyright (c) 2004, Intel Corporation. iap10@3290: * iap10@3290: * This program is free software; you can redistribute it and/or modify it iap10@3290: * under the terms and conditions of the GNU General Public License, iap10@3290: * version 2, as published by the Free Software Foundation. iap10@3290: * iap10@3290: * This program is distributed in the hope it will be useful, but WITHOUT iap10@3290: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or iap10@3290: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for iap10@3290: * more details. iap10@3290: * iap10@3290: * You should have received a copy of the GNU General Public License along with iap10@3290: * this program; if not, write to the Free Software Foundation, Inc., 59 Temple iap10@3290: * Place - Suite 330, Boston, MA 02111-1307 USA. iap10@3290: * iap10@3290: */ iap10@3290: iap10@3290: #include iap10@3290: #include iap10@3290: #include iap10@3290: #include iap10@3290: #include kaf24@5356: #include cl349@5291: #include iap10@3290: #include iap10@3290: #include iap10@3290: #include iap10@3290: #include kaf24@5722: #include iap10@3290: #include iap10@3290: #include iap10@3290: #include kaf24@5722: #if CONFIG_PAGING_LEVELS >= 4 kaf24@5722: #include kaf24@5722: #endif mafetter@3717: #ifdef CONFIG_VMX mafetter@3717: iap10@3290: struct vmcs_struct *alloc_vmcs(void) iap10@3290: { iap10@3290: struct vmcs_struct *vmcs; kaf24@5059: u32 vmx_msr_low, vmx_msr_high; iap10@3290: kaf24@5059: rdmsr(MSR_IA32_VMX_BASIC_MSR, vmx_msr_low, vmx_msr_high); kaf24@5059: vmcs_size = vmx_msr_high & 0x1fff; kaf24@6684: vmcs = alloc_xenheap_pages(get_order_from_bytes(vmcs_size)); kaf24@5398: memset((char *)vmcs, 0, vmcs_size); /* don't remove this */ iap10@3290: kaf24@5059: vmcs->vmcs_revision_id = vmx_msr_low; iap10@3290: return vmcs; iap10@3290: } iap10@3290: iap10@3290: void free_vmcs(struct vmcs_struct *vmcs) iap10@3290: { iap10@3290: int order; iap10@3290: kaf24@6684: order = get_order_from_bytes(vmcs_size); kaf24@5398: free_xenheap_pages(vmcs, order); iap10@3290: } iap10@3290: kaf24@5836: static inline int construct_vmcs_controls(struct arch_vmx_struct *arch_vmx) iap10@3290: { iap10@3290: int error = 0; kaf24@5836: void *io_bitmap_a; kaf24@5836: void *io_bitmap_b; kaf24@5775: iap10@3290: error |= __vmwrite(PIN_BASED_VM_EXEC_CONTROL, iap10@3290: MONITOR_PIN_BASED_EXEC_CONTROLS); iap10@3290: iap10@3290: error |= __vmwrite(CPU_BASED_VM_EXEC_CONTROL, iap10@3290: MONITOR_CPU_BASED_EXEC_CONTROLS); kaf24@5775: iap10@3290: error |= __vmwrite(VM_EXIT_CONTROLS, MONITOR_VM_EXIT_CONTROLS); kaf24@5775: iap10@3290: error |= __vmwrite(VM_ENTRY_CONTROLS, MONITOR_VM_ENTRY_CONTROLS); iap10@3290: kaf24@5836: /* need to use 0x1000 instead of PAGE_SIZE */ kaf24@6684: io_bitmap_a = (void*) alloc_xenheap_pages(get_order_from_bytes(0x1000)); kaf24@6684: io_bitmap_b = (void*) alloc_xenheap_pages(get_order_from_bytes(0x1000)); kaf24@5836: memset(io_bitmap_a, 0xff, 0x1000); kaf24@5836: /* don't bother debug port access */ kaf24@5836: clear_bit(PC_DEBUG_PORT, io_bitmap_a); kaf24@5836: memset(io_bitmap_b, 0xff, 0x1000); kaf24@5836: kaf24@5836: error |= __vmwrite(IO_BITMAP_A, (u64) virt_to_phys(io_bitmap_a)); kaf24@5836: error |= __vmwrite(IO_BITMAP_B, (u64) virt_to_phys(io_bitmap_b)); kaf24@5836: kaf24@5836: arch_vmx->io_bitmap_a = io_bitmap_a; kaf24@5836: arch_vmx->io_bitmap_b = io_bitmap_b; kaf24@5836: iap10@3290: return error; iap10@3290: } iap10@3290: iap10@3290: #define GUEST_SEGMENT_LIMIT 0xffffffff iap10@3290: #define HOST_SEGMENT_LIMIT 0xffffffff iap10@3290: iap10@3290: struct host_execution_env { iap10@3290: /* selectors */ iap10@3290: unsigned short ldtr_selector; iap10@3290: unsigned short tr_selector; iap10@3290: unsigned short ds_selector; iap10@3290: unsigned short cs_selector; iap10@3290: /* limits */ iap10@3290: unsigned short gdtr_limit; iap10@3290: unsigned short ldtr_limit; iap10@3290: unsigned short idtr_limit; iap10@3290: unsigned short tr_limit; iap10@3290: /* base */ iap10@3290: unsigned long gdtr_base; iap10@3290: unsigned long ldtr_base; iap10@3290: unsigned long idtr_base; iap10@3290: unsigned long tr_base; iap10@3290: unsigned long ds_base; iap10@3290: unsigned long cs_base; kaf24@5658: #ifdef __x86_64__ kaf24@5658: unsigned long fs_base; kaf24@5658: unsigned long gs_base; kaf24@5658: #endif kaf24@5658: iap10@3290: /* control registers */ iap10@3290: unsigned long cr3; iap10@3290: unsigned long cr0; iap10@3290: unsigned long cr4; iap10@3290: unsigned long dr7; iap10@3290: }; iap10@3290: iap10@3290: #define round_pgdown(_p) ((_p)&PAGE_MASK) /* coped from domain.c */ iap10@3290: kaf24@5289: int vmx_setup_platform(struct vcpu *d, struct cpu_user_regs *regs) iap10@3290: { iap10@3290: int i; iap10@3290: unsigned int n; iap10@3290: unsigned long *p, mpfn, offset, addr; iap10@3290: struct e820entry *e820p; iap10@3290: unsigned long gpfn = 0; iap10@3290: kaf24@5727: local_flush_tlb_pge(); kaf24@4683: regs->ebx = 0; /* Linux expects ebx to be 0 for boot proc */ iap10@3290: kaf24@4683: n = regs->ecx; iap10@3290: if (n > 32) { maf46@3855: VMX_DBG_LOG(DBG_LEVEL_1, "Too many e820 entries: %d", n); iap10@3290: return -1; iap10@3290: } iap10@3290: kaf24@4683: addr = regs->edi; iap10@3290: offset = (addr & ~PAGE_MASK); iap10@3290: addr = round_pgdown(addr); kaf24@5356: kaf24@6481: mpfn = get_mfn_from_pfn(addr >> PAGE_SHIFT); kaf24@5356: p = map_domain_page(mpfn); iap10@3290: iap10@3290: e820p = (struct e820entry *) ((unsigned long) p + offset); iap10@3290: maf46@3880: #ifndef NDEBUG maf46@3880: print_e820_memory_map(e820p, n); maf46@3880: #endif maf46@3880: kaf24@5356: for ( i = 0; i < n; i++ ) kaf24@5356: { kaf24@5356: if ( e820p[i].type == E820_SHARED_PAGE ) kaf24@5356: { iap10@3290: gpfn = (e820p[i].addr >> PAGE_SHIFT); iap10@3290: break; iap10@3290: } iap10@3290: } iap10@3290: kaf24@5356: if ( gpfn == 0 ) kaf24@5356: { kaf24@5356: unmap_domain_page(p); iap10@3290: return -1; iap10@3290: } iap10@3290: kaf24@5356: unmap_domain_page(p); iap10@3748: iap10@3748: /* Initialise shared page */ kaf24@6481: mpfn = get_mfn_from_pfn(gpfn); kaf24@5356: p = map_domain_page(mpfn); arun@5608: d->domain->arch.vmx_platform.shared_page_va = (unsigned long)p; arun@5608: kaf24@6730: VMX_DBG_LOG(DBG_LEVEL_1, "eport: %x\n", iopacket_port(d->domain)); arun@5615: kaf24@6730: clear_bit(iopacket_port(d->domain), kaf24@6730: &d->domain->shared_info->evtchn_mask[0]); iap10@3290: iap10@3290: return 0; iap10@3290: } iap10@3290: kaf24@6100: void vmx_set_host_env(struct vcpu *v) iap10@3290: { iap10@3290: unsigned int tr, cpu, error = 0; iap10@3290: struct host_execution_env host_env; iap10@3290: struct Xgt_desc_struct desc; cl349@4856: kaf24@4633: cpu = smp_processor_id(); kaf24@5820: __asm__ __volatile__ ("sidt (%0) \n" :: "a"(&desc) : "memory"); kaf24@5820: host_env.idtr_limit = desc.size; kaf24@5820: host_env.idtr_base = desc.address; kaf24@5820: error |= __vmwrite(HOST_IDTR_BASE, host_env.idtr_base); kaf24@6113: arun@4585: __asm__ __volatile__ ("sgdt (%0) \n" :: "a"(&desc) : "memory"); iap10@3290: host_env.gdtr_limit = desc.size; iap10@3290: host_env.gdtr_base = desc.address; iap10@3290: error |= __vmwrite(HOST_GDTR_BASE, host_env.gdtr_base); iap10@3290: kaf24@6100: __asm__ __volatile__ ("str (%0) \n" :: "a"(&tr) : "memory"); kaf24@6100: host_env.tr_selector = tr; kaf24@6100: host_env.tr_limit = sizeof(struct tss_struct); kaf24@6100: host_env.tr_base = (unsigned long) &init_tss[cpu]; kaf24@6100: error |= __vmwrite(HOST_TR_SELECTOR, host_env.tr_selector); kaf24@6100: error |= __vmwrite(HOST_TR_BASE, host_env.tr_base); kaf24@6100: } kaf24@6100: kaf24@6100: void vmx_do_launch(struct vcpu *v) kaf24@6100: { kaf24@6100: /* Update CR3, GDT, LDT, TR */ kaf24@6100: unsigned int error = 0; kaf24@6100: unsigned long pfn = 0; kaf24@6100: struct pfn_info *page; kaf24@6100: struct cpu_user_regs *regs = guest_cpu_user_regs(); kaf24@6100: kaf24@6100: vmx_stts(); kaf24@6100: kaf24@6100: page = (struct pfn_info *) alloc_domheap_page(NULL); kaf24@6100: pfn = (unsigned long) (page - frame_table); kaf24@6100: kaf24@6100: vmx_setup_platform(v, regs); kaf24@6100: kaf24@6100: vmx_set_host_env(v); kaf24@6100: iap10@3290: error |= __vmwrite(GUEST_LDTR_SELECTOR, 0); iap10@3290: error |= __vmwrite(GUEST_LDTR_BASE, 0); iap10@3290: error |= __vmwrite(GUEST_LDTR_LIMIT, 0); iap10@3290: iap10@3290: error |= __vmwrite(GUEST_TR_BASE, 0); iap10@3290: error |= __vmwrite(GUEST_TR_LIMIT, 0xff); iap10@3290: kaf24@5289: __vmwrite(GUEST_CR3, pagetable_get_paddr(v->arch.guest_table)); kaf24@5289: __vmwrite(HOST_CR3, pagetable_get_paddr(v->arch.monitor_table)); kaf24@5414: __vmwrite(HOST_RSP, (unsigned long)get_stack_bottom()); iap10@3290: kaf24@5289: v->arch.schedule_tail = arch_vmx_do_resume; iap10@3290: } iap10@3290: iap10@3290: /* iap10@3290: * Initially set the same environement as host. iap10@3290: */ iap10@3290: static inline int kaf24@4683: construct_init_vmcs_guest(struct cpu_user_regs *regs, kaf24@4683: struct vcpu_guest_context *ctxt, iap10@3290: struct host_execution_env *host_env) iap10@3290: { iap10@3290: int error = 0; iap10@3290: union vmcs_arbytes arbytes; iap10@3290: unsigned long dr7; iap10@3290: unsigned long eflags, shadow_cr; iap10@3290: iap10@3290: /* MSR */ iap10@3290: error |= __vmwrite(VM_EXIT_MSR_LOAD_ADDR, 0); iap10@3290: error |= __vmwrite(VM_EXIT_MSR_STORE_ADDR, 0); iap10@3290: iap10@3290: error |= __vmwrite(VM_EXIT_MSR_STORE_COUNT, 0); iap10@3290: error |= __vmwrite(VM_EXIT_MSR_LOAD_COUNT, 0); iap10@3290: error |= __vmwrite(VM_ENTRY_MSR_LOAD_COUNT, 0); iap10@3290: /* interrupt */ iap10@3290: error |= __vmwrite(VM_ENTRY_INTR_INFO_FIELD, 0); iap10@3290: /* mask */ kaf24@5658: error |= __vmwrite(CR0_GUEST_HOST_MASK, -1UL); kaf24@5658: error |= __vmwrite(CR4_GUEST_HOST_MASK, -1UL); iap10@3290: iap10@3290: error |= __vmwrite(PAGE_FAULT_ERROR_CODE_MASK, 0); iap10@3290: error |= __vmwrite(PAGE_FAULT_ERROR_CODE_MATCH, 0); iap10@3290: iap10@3290: /* TSC */ iap10@3290: error |= __vmwrite(TSC_OFFSET, 0); iap10@3290: error |= __vmwrite(CR3_TARGET_COUNT, 0); iap10@3290: iap10@3290: /* Guest Selectors */ kaf24@4683: error |= __vmwrite(GUEST_CS_SELECTOR, regs->cs); kaf24@4683: error |= __vmwrite(GUEST_ES_SELECTOR, regs->es); kaf24@4683: error |= __vmwrite(GUEST_SS_SELECTOR, regs->ss); kaf24@4683: error |= __vmwrite(GUEST_DS_SELECTOR, regs->ds); kaf24@4683: error |= __vmwrite(GUEST_FS_SELECTOR, regs->fs); kaf24@4683: error |= __vmwrite(GUEST_GS_SELECTOR, regs->gs); iap10@3290: iap10@3290: /* Guest segment Limits */ iap10@3290: error |= __vmwrite(GUEST_CS_LIMIT, GUEST_SEGMENT_LIMIT); iap10@3290: error |= __vmwrite(GUEST_ES_LIMIT, GUEST_SEGMENT_LIMIT); iap10@3290: error |= __vmwrite(GUEST_SS_LIMIT, GUEST_SEGMENT_LIMIT); iap10@3290: error |= __vmwrite(GUEST_DS_LIMIT, GUEST_SEGMENT_LIMIT); iap10@3290: error |= __vmwrite(GUEST_FS_LIMIT, GUEST_SEGMENT_LIMIT); iap10@3290: error |= __vmwrite(GUEST_GS_LIMIT, GUEST_SEGMENT_LIMIT); iap10@3290: iap10@3290: error |= __vmwrite(GUEST_IDTR_LIMIT, host_env->idtr_limit); iap10@3290: iap10@3290: /* AR bytes */ iap10@3290: arbytes.bytes = 0; iap10@3290: arbytes.fields.seg_type = 0x3; /* type = 3 */ iap10@3290: arbytes.fields.s = 1; /* code or data, i.e. not system */ iap10@3290: arbytes.fields.dpl = 0; /* DPL = 3 */ iap10@3290: arbytes.fields.p = 1; /* segment present */ iap10@3290: arbytes.fields.default_ops_size = 1; /* 32-bit */ iap10@3290: arbytes.fields.g = 1; iap10@3290: arbytes.fields.null_bit = 0; /* not null */ iap10@3290: iap10@3290: error |= __vmwrite(GUEST_ES_AR_BYTES, arbytes.bytes); iap10@3290: error |= __vmwrite(GUEST_SS_AR_BYTES, arbytes.bytes); iap10@3290: error |= __vmwrite(GUEST_DS_AR_BYTES, arbytes.bytes); iap10@3290: error |= __vmwrite(GUEST_FS_AR_BYTES, arbytes.bytes); iap10@3290: error |= __vmwrite(GUEST_GS_AR_BYTES, arbytes.bytes); iap10@3290: iap10@3290: arbytes.fields.seg_type = 0xb; /* type = 0xb */ iap10@3290: error |= __vmwrite(GUEST_CS_AR_BYTES, arbytes.bytes); iap10@3290: kaf24@4683: error |= __vmwrite(GUEST_GDTR_BASE, regs->edx); kaf24@4683: regs->edx = 0; kaf24@4683: error |= __vmwrite(GUEST_GDTR_LIMIT, regs->eax); kaf24@4683: regs->eax = 0; iap10@3290: iap10@3290: arbytes.fields.s = 0; /* not code or data segement */ iap10@3290: arbytes.fields.seg_type = 0x2; /* LTD */ iap10@3290: arbytes.fields.default_ops_size = 0; /* 16-bit */ iap10@3290: arbytes.fields.g = 0; iap10@3290: error |= __vmwrite(GUEST_LDTR_AR_BYTES, arbytes.bytes); iap10@3290: iap10@3290: arbytes.fields.seg_type = 0xb; /* 32-bit TSS (busy) */ iap10@3290: error |= __vmwrite(GUEST_TR_AR_BYTES, arbytes.bytes); iap10@3290: iap10@3290: error |= __vmwrite(GUEST_CR0, host_env->cr0); /* same CR0 */ iap10@3290: iap10@3290: /* Initally PG, PE are not set*/ iap10@3290: shadow_cr = host_env->cr0; arun@5186: shadow_cr &= ~X86_CR0_PG; iap10@3290: error |= __vmwrite(CR0_READ_SHADOW, shadow_cr); kaf24@3755: /* CR3 is set in vmx_final_setup_guest */ kaf24@5658: #ifdef __x86_64__ kaf24@5727: error |= __vmwrite(GUEST_CR4, host_env->cr4 & ~X86_CR4_PSE); kaf24@5658: #else iap10@3290: error |= __vmwrite(GUEST_CR4, host_env->cr4); kaf24@5658: #endif iap10@3290: shadow_cr = host_env->cr4; kaf24@5658: kaf24@5658: #ifdef __x86_64__ kaf24@5658: shadow_cr &= ~(X86_CR4_PGE | X86_CR4_VMXE | X86_CR4_PAE); kaf24@5658: #else iap10@3290: shadow_cr &= ~(X86_CR4_PGE | X86_CR4_VMXE); kaf24@5658: #endif iap10@3290: error |= __vmwrite(CR4_READ_SHADOW, shadow_cr); iap10@3290: iap10@3290: error |= __vmwrite(GUEST_ES_BASE, host_env->ds_base); iap10@3290: error |= __vmwrite(GUEST_CS_BASE, host_env->cs_base); iap10@3290: error |= __vmwrite(GUEST_SS_BASE, host_env->ds_base); iap10@3290: error |= __vmwrite(GUEST_DS_BASE, host_env->ds_base); iap10@3290: error |= __vmwrite(GUEST_FS_BASE, host_env->ds_base); iap10@3290: error |= __vmwrite(GUEST_GS_BASE, host_env->ds_base); iap10@3290: error |= __vmwrite(GUEST_IDTR_BASE, host_env->idtr_base); iap10@3290: kaf24@5414: error |= __vmwrite(GUEST_RSP, regs->esp); kaf24@5414: error |= __vmwrite(GUEST_RIP, regs->eip); iap10@3290: kaf24@4683: eflags = regs->eflags & ~VMCS_EFLAGS_RESERVED_0; /* clear 0s */ iap10@3290: eflags |= VMCS_EFLAGS_RESERVED_1; /* set 1s */ iap10@3290: kaf24@5414: error |= __vmwrite(GUEST_RFLAGS, eflags); iap10@3290: iap10@3290: error |= __vmwrite(GUEST_INTERRUPTIBILITY_INFO, 0); iap10@3290: __asm__ __volatile__ ("mov %%dr7, %0\n" : "=r" (dr7)); iap10@3290: error |= __vmwrite(GUEST_DR7, dr7); kaf24@5414: error |= __vmwrite(VMCS_LINK_POINTER, 0xffffffff); kaf24@5414: error |= __vmwrite(VMCS_LINK_POINTER_HIGH, 0xffffffff); iap10@3290: iap10@3290: return error; iap10@3290: } iap10@3290: iap10@3290: static inline int construct_vmcs_host(struct host_execution_env *host_env) iap10@3290: { iap10@3290: int error = 0; iap10@3290: unsigned long crn; iap10@3290: iap10@3290: /* Host Selectors */ iap10@3290: host_env->ds_selector = __HYPERVISOR_DS; iap10@3290: error |= __vmwrite(HOST_ES_SELECTOR, host_env->ds_selector); iap10@3290: error |= __vmwrite(HOST_SS_SELECTOR, host_env->ds_selector); iap10@3290: error |= __vmwrite(HOST_DS_SELECTOR, host_env->ds_selector); kaf24@5658: #if defined (__i386__) iap10@3290: error |= __vmwrite(HOST_FS_SELECTOR, host_env->ds_selector); iap10@3290: error |= __vmwrite(HOST_GS_SELECTOR, host_env->ds_selector); kaf24@5658: error |= __vmwrite(HOST_FS_BASE, host_env->ds_base); kaf24@5658: error |= __vmwrite(HOST_GS_BASE, host_env->ds_base); iap10@3290: kaf24@5658: #else kaf24@5658: rdmsrl(MSR_FS_BASE, host_env->fs_base); kaf24@5658: rdmsrl(MSR_GS_BASE, host_env->gs_base); kaf24@5658: error |= __vmwrite(HOST_FS_BASE, host_env->fs_base); kaf24@5658: error |= __vmwrite(HOST_GS_BASE, host_env->gs_base); kaf24@5658: kaf24@5658: #endif iap10@3290: host_env->cs_selector = __HYPERVISOR_CS; iap10@3290: error |= __vmwrite(HOST_CS_SELECTOR, host_env->cs_selector); iap10@3290: iap10@3290: host_env->ds_base = 0; iap10@3290: host_env->cs_base = 0; iap10@3290: kaf24@5193: __asm__ __volatile__ ("mov %%cr0,%0" : "=r" (crn) : ); iap10@3290: host_env->cr0 = crn; iap10@3290: error |= __vmwrite(HOST_CR0, crn); /* same CR0 */ iap10@3290: iap10@3290: /* CR3 is set in vmx_final_setup_hostos */ kaf24@5193: __asm__ __volatile__ ("mov %%cr4,%0" : "=r" (crn) : ); iap10@3290: host_env->cr4 = crn; iap10@3290: error |= __vmwrite(HOST_CR4, crn); kaf24@5820: kaf24@5414: error |= __vmwrite(HOST_RIP, (unsigned long) vmx_asm_vmexit_handler); kaf24@5658: #ifdef __x86_64__ kaf24@5658: /* TBD: support cr8 for 64-bit guest */ kaf24@5658: __vmwrite(VIRTUAL_APIC_PAGE_ADDR, 0); kaf24@5658: __vmwrite(TPR_THRESHOLD, 0); kaf24@5658: __vmwrite(SECONDARY_VM_EXEC_CONTROL, 0); kaf24@5658: #endif iap10@3290: iap10@3290: return error; iap10@3290: } iap10@3290: iap10@3290: /* iap10@3290: * Need to extend to support full virtualization. iap10@3290: * The variable use_host_env indicates if the new VMCS needs to use iap10@3290: * the same setups as the host has (xenolinux). iap10@3290: */ iap10@3290: iap10@3290: int construct_vmcs(struct arch_vmx_struct *arch_vmx, kaf24@4683: struct cpu_user_regs *regs, kaf24@4683: struct vcpu_guest_context *ctxt, iap10@3290: int use_host_env) iap10@3290: { iap10@3290: int error; iap10@3290: u64 vmcs_phys_ptr; iap10@3290: iap10@3290: struct host_execution_env host_env; iap10@3290: iap10@3290: if (use_host_env != VMCS_USE_HOST_ENV) iap10@3290: return -EINVAL; iap10@3290: iap10@3290: memset(&host_env, 0, sizeof(struct host_execution_env)); iap10@3290: iap10@3290: vmcs_phys_ptr = (u64) virt_to_phys(arch_vmx->vmcs); iap10@3290: iap10@3290: if ((error = __vmpclear (vmcs_phys_ptr))) { iap10@3290: printk("construct_vmcs: VMCLEAR failed\n"); iap10@3290: return -EINVAL; iap10@3290: } iap10@3290: if ((error = load_vmcs(arch_vmx, vmcs_phys_ptr))) { iap10@3290: printk("construct_vmcs: load_vmcs failed: VMCS = %lx\n", iap10@3290: (unsigned long) vmcs_phys_ptr); iap10@3290: return -EINVAL; iap10@3290: } kaf24@5836: if ((error = construct_vmcs_controls(arch_vmx))) { iap10@3290: printk("construct_vmcs: construct_vmcs_controls failed\n"); iap10@3290: return -EINVAL; iap10@3290: } iap10@3290: /* host selectors */ iap10@3290: if ((error = construct_vmcs_host(&host_env))) { iap10@3290: printk("construct_vmcs: construct_vmcs_host failed\n"); iap10@3290: return -EINVAL; iap10@3290: } iap10@3290: /* guest selectors */ kaf24@4683: if ((error = construct_init_vmcs_guest(regs, ctxt, &host_env))) { iap10@3290: printk("construct_vmcs: construct_vmcs_guest failed\n"); iap10@3290: return -EINVAL; iap10@3290: } iap10@3290: iap10@3290: if ((error |= __vmwrite(EXCEPTION_BITMAP, iap10@3290: MONITOR_DEFAULT_EXCEPTION_BITMAP))) { iap10@3290: printk("construct_vmcs: setting Exception bitmap failed\n"); iap10@3290: return -EINVAL; iap10@3290: } iap10@3290: kaf24@5821: if (regs->eflags & EF_TF) kaf24@5821: __vm_set_bit(EXCEPTION_BITMAP, EXCEPTION_BITMAP_DB); kaf24@5821: else kaf24@5821: __vm_clear_bit(EXCEPTION_BITMAP, EXCEPTION_BITMAP_DB); kaf24@5821: kaf24@5821: return 0; kaf24@5821: } kaf24@5821: kaf24@5821: /* kaf24@5821: * modify guest eflags and execption bitmap for gdb kaf24@5821: */ kaf24@5821: int modify_vmcs(struct arch_vmx_struct *arch_vmx, kaf24@5821: struct cpu_user_regs *regs) kaf24@5821: { kaf24@5821: int error; kaf24@5821: u64 vmcs_phys_ptr, old, old_phys_ptr; kaf24@5821: vmcs_phys_ptr = (u64) virt_to_phys(arch_vmx->vmcs); kaf24@5821: kaf24@5821: old_phys_ptr = virt_to_phys(&old); kaf24@5821: __vmptrst(old_phys_ptr); kaf24@5821: if ((error = load_vmcs(arch_vmx, vmcs_phys_ptr))) { kaf24@5821: printk("modify_vmcs: load_vmcs failed: VMCS = %lx\n", kaf24@6730: (unsigned long) vmcs_phys_ptr); kaf24@5821: return -EINVAL; kaf24@5821: } kaf24@5821: load_cpu_user_regs(regs); kaf24@5821: kaf24@5821: __vmptrld(old_phys_ptr); kaf24@5821: iap10@3290: return 0; iap10@3290: } iap10@3290: iap10@3290: int load_vmcs(struct arch_vmx_struct *arch_vmx, u64 phys_ptr) iap10@3290: { iap10@3290: int error; iap10@3290: iap10@3290: if ((error = __vmptrld(phys_ptr))) { iap10@3290: clear_bit(ARCH_VMX_VMCS_LOADED, &arch_vmx->flags); iap10@3290: return error; iap10@3290: } iap10@3290: set_bit(ARCH_VMX_VMCS_LOADED, &arch_vmx->flags); iap10@3290: return 0; iap10@3290: } iap10@3290: iap10@3290: int store_vmcs(struct arch_vmx_struct *arch_vmx, u64 phys_ptr) iap10@3290: { iap10@3290: /* take the current VMCS */ iap10@3290: __vmptrst(phys_ptr); iap10@3290: clear_bit(ARCH_VMX_VMCS_LOADED, &arch_vmx->flags); iap10@3290: return 0; iap10@3290: } iap10@3290: iap10@3290: void vm_launch_fail(unsigned long eflags) iap10@3290: { kaf24@6099: unsigned long error; kaf24@6099: __vmread(VM_INSTRUCTION_ERROR, &error); kaf24@6099: printk(" error code %lx\n", error); arun@5382: __vmx_bug(guest_cpu_user_regs()); iap10@3290: } iap10@3290: iap10@3290: void vm_resume_fail(unsigned long eflags) iap10@3290: { kaf24@6099: unsigned long error; kaf24@6099: __vmread(VM_INSTRUCTION_ERROR, &error); kaf24@6099: printk(" error code %lx\n", error); arun@5382: __vmx_bug(guest_cpu_user_regs()); iap10@3290: } iap10@3290: kaf24@6113: void arch_vmx_do_resume(struct vcpu *v) kaf24@6113: { kaf24@6113: u64 vmcs_phys_ptr = (u64) virt_to_phys(v->arch.arch_vmx.vmcs); kaf24@6113: kaf24@6113: load_vmcs(&v->arch.arch_vmx, vmcs_phys_ptr); kaf24@6113: vmx_do_resume(v); kaf24@6113: reset_stack_and_jump(vmx_asm_do_resume); kaf24@6113: } kaf24@6113: kaf24@6113: void arch_vmx_do_launch(struct vcpu *v) kaf24@6113: { kaf24@6113: u64 vmcs_phys_ptr = (u64) virt_to_phys(v->arch.arch_vmx.vmcs); kaf24@6113: kaf24@6113: load_vmcs(&v->arch.arch_vmx, vmcs_phys_ptr); kaf24@6113: vmx_do_launch(v); kaf24@6113: reset_stack_and_jump(vmx_asm_do_launch); kaf24@6113: } kaf24@6113: kaf24@6113: void arch_vmx_do_relaunch(struct vcpu *v) kaf24@6113: { kaf24@6113: u64 vmcs_phys_ptr = (u64) virt_to_phys(v->arch.arch_vmx.vmcs); kaf24@6113: kaf24@6113: load_vmcs(&v->arch.arch_vmx, vmcs_phys_ptr); kaf24@6113: vmx_do_resume(v); kaf24@6113: vmx_set_host_env(v); kaf24@6113: v->arch.schedule_tail = arch_vmx_do_resume; kaf24@6113: kaf24@6113: reset_stack_and_jump(vmx_asm_do_relaunch); kaf24@6113: } kaf24@6113: mafetter@3717: #endif /* CONFIG_VMX */ kaf24@3914: kaf24@3914: /* kaf24@3914: * Local variables: kaf24@3914: * mode: C kaf24@3914: * c-set-style: "BSD" kaf24@3914: * c-basic-offset: 4 kaf24@3914: * tab-width: 4 kaf24@3914: * indent-tabs-mode: nil kaf24@3988: * End: kaf24@3914: */