vmcs.c

来自「xen虚拟机源代码安装包」· C语言 代码 · 共 1,066 行 · 第 1/3 页

C
1,066
字号
{    struct list_head *active_vmcs_list = &this_cpu(active_vmcs_list);    unsigned long flags;    local_irq_save(flags);    while ( !list_empty(active_vmcs_list) )        __vmx_clear_vmcs(list_entry(active_vmcs_list->next,                                    struct vcpu, arch.hvm_vmx.active_list));    BUG_ON(!(read_cr4() & X86_CR4_VMXE));    __vmxoff();    local_irq_restore(flags);}struct foreign_vmcs {    struct vcpu *v;    unsigned int count;};static DEFINE_PER_CPU(struct foreign_vmcs, foreign_vmcs);void vmx_vmcs_enter(struct vcpu *v){    struct foreign_vmcs *fv;    /*     * NB. We must *always* run an HVM VCPU on its own VMCS, except for     * vmx_vmcs_enter/exit critical regions.     */    if ( likely(v == current) )        return;    fv = &this_cpu(foreign_vmcs);    if ( fv->v == v )    {        BUG_ON(fv->count == 0);    }    else    {        BUG_ON(fv->v != NULL);        BUG_ON(fv->count != 0);        vcpu_pause(v);        spin_lock(&v->arch.hvm_vmx.vmcs_lock);        vmx_clear_vmcs(v);        vmx_load_vmcs(v);        fv->v = v;    }    fv->count++;}void vmx_vmcs_exit(struct vcpu *v){    struct foreign_vmcs *fv;    if ( likely(v == current) )        return;    fv = &this_cpu(foreign_vmcs);    BUG_ON(fv->v != v);    BUG_ON(fv->count == 0);    if ( --fv->count == 0 )    {        /* Don't confuse vmx_do_resume (for @v or @current!) */        vmx_clear_vmcs(v);        if ( is_hvm_vcpu(current) )            vmx_load_vmcs(current);        spin_unlock(&v->arch.hvm_vmx.vmcs_lock);        vcpu_unpause(v);        fv->v = NULL;    }}struct xgt_desc {    unsigned short size;    unsigned long address __attribute__((packed));};static void vmx_set_host_env(struct vcpu *v){    unsigned int cpu = smp_processor_id();    __vmwrite(HOST_IDTR_BASE, (unsigned long)idt_tables[cpu]);    __vmwrite(HOST_TR_SELECTOR, __TSS(cpu) << 3);    __vmwrite(HOST_TR_BASE, (unsigned long)&init_tss[cpu]);    __vmwrite(HOST_SYSENTER_ESP, get_stack_bottom());    /*     * Skip end of cpu_user_regs when entering the hypervisor because the     * CPU does not save context onto the stack. SS,RSP,CS,RIP,RFLAGS,etc     * all get saved into the VMCS instead.     */    __vmwrite(HOST_RSP,              (unsigned long)&get_cpu_info()->guest_cpu_user_regs.error_code);}void vmx_disable_intercept_for_msr(struct vcpu *v, u32 msr){    unsigned long *msr_bitmap = v->arch.hvm_vmx.msr_bitmap;    /* VMX MSR bitmap supported? */    if ( msr_bitmap == NULL )        return;    /*     * See Intel PRM Vol. 3, 20.6.9 (MSR-Bitmap Address). Early manuals     * have the write-low and read-high bitmap offsets the wrong way round.     * We can control MSRs 0x00000000-0x00001fff and 0xc0000000-0xc0001fff.     */    if ( msr <= 0x1fff )    {        __clear_bit(msr, msr_bitmap + 0x000/BYTES_PER_LONG); /* read-low */        __clear_bit(msr, msr_bitmap + 0x800/BYTES_PER_LONG); /* write-low */    }    else if ( (msr >= 0xc0000000) && (msr <= 0xc0001fff) )    {        msr &= 0x1fff;        __clear_bit(msr, msr_bitmap + 0x400/BYTES_PER_LONG); /* read-high */        __clear_bit(msr, msr_bitmap + 0xc00/BYTES_PER_LONG); /* write-high */    }}static int construct_vmcs(struct vcpu *v){    struct domain *d = v->domain;    uint16_t sysenter_cs;    unsigned long sysenter_eip;    vmx_vmcs_enter(v);    /* VMCS controls. */    __vmwrite(PIN_BASED_VM_EXEC_CONTROL, vmx_pin_based_exec_control);    __vmwrite(VM_EXIT_CONTROLS, vmx_vmexit_control);    __vmwrite(VM_ENTRY_CONTROLS, vmx_vmentry_control);    v->arch.hvm_vmx.exec_control = vmx_cpu_based_exec_control;    v->arch.hvm_vmx.secondary_exec_control = vmx_secondary_exec_control;    if ( paging_mode_hap(d) )    {        v->arch.hvm_vmx.exec_control &= ~(CPU_BASED_INVLPG_EXITING |                                          CPU_BASED_CR3_LOAD_EXITING |                                          CPU_BASED_CR3_STORE_EXITING);    }    else    {        v->arch.hvm_vmx.secondary_exec_control &= ~SECONDARY_EXEC_ENABLE_EPT;    }    __vmwrite(CPU_BASED_VM_EXEC_CONTROL, v->arch.hvm_vmx.exec_control);    if ( cpu_has_vmx_secondary_exec_control )        __vmwrite(SECONDARY_VM_EXEC_CONTROL,                  v->arch.hvm_vmx.secondary_exec_control);    /* MSR access bitmap. */    if ( cpu_has_vmx_msr_bitmap )    {        unsigned long *msr_bitmap = alloc_xenheap_page();        if ( msr_bitmap == NULL )            return -ENOMEM;        memset(msr_bitmap, ~0, PAGE_SIZE);        v->arch.hvm_vmx.msr_bitmap = msr_bitmap;        __vmwrite(MSR_BITMAP, virt_to_maddr(msr_bitmap));        vmx_disable_intercept_for_msr(v, MSR_FS_BASE);        vmx_disable_intercept_for_msr(v, MSR_GS_BASE);        vmx_disable_intercept_for_msr(v, MSR_IA32_SYSENTER_CS);        vmx_disable_intercept_for_msr(v, MSR_IA32_SYSENTER_ESP);        vmx_disable_intercept_for_msr(v, MSR_IA32_SYSENTER_EIP);    }    /* I/O access bitmap. */    __vmwrite(IO_BITMAP_A, virt_to_maddr((char *)hvm_io_bitmap + 0));    __vmwrite(IO_BITMAP_B, virt_to_maddr((char *)hvm_io_bitmap + PAGE_SIZE));    /* Host GDTR base. */    __vmwrite(HOST_GDTR_BASE, GDT_VIRT_START(v));    /* Host data selectors. */    __vmwrite(HOST_SS_SELECTOR, __HYPERVISOR_DS);    __vmwrite(HOST_DS_SELECTOR, __HYPERVISOR_DS);    __vmwrite(HOST_ES_SELECTOR, __HYPERVISOR_DS);    __vmwrite(HOST_FS_SELECTOR, 0);    __vmwrite(HOST_GS_SELECTOR, 0);    __vmwrite(HOST_FS_BASE, 0);    __vmwrite(HOST_GS_BASE, 0);    /* Host control registers. */    v->arch.hvm_vmx.host_cr0 = read_cr0() | X86_CR0_TS;    __vmwrite(HOST_CR0, v->arch.hvm_vmx.host_cr0);    __vmwrite(HOST_CR4, mmu_cr4_features);    /* Host CS:RIP. */    __vmwrite(HOST_CS_SELECTOR, __HYPERVISOR_CS);    __vmwrite(HOST_RIP, (unsigned long)vmx_asm_vmexit_handler);    /* Host SYSENTER CS:RIP. */    rdmsrl(MSR_IA32_SYSENTER_CS, sysenter_cs);    __vmwrite(HOST_SYSENTER_CS, sysenter_cs);    rdmsrl(MSR_IA32_SYSENTER_EIP, sysenter_eip);    __vmwrite(HOST_SYSENTER_EIP, sysenter_eip);    /* MSR intercepts. */    __vmwrite(VM_EXIT_MSR_LOAD_COUNT, 0);    __vmwrite(VM_EXIT_MSR_STORE_COUNT, 0);    __vmwrite(VM_ENTRY_MSR_LOAD_COUNT, 0);    __vmwrite(VM_ENTRY_INTR_INFO, 0);    __vmwrite(CR0_GUEST_HOST_MASK, ~0UL);    __vmwrite(CR4_GUEST_HOST_MASK, ~0UL);    __vmwrite(PAGE_FAULT_ERROR_CODE_MASK, 0);    __vmwrite(PAGE_FAULT_ERROR_CODE_MATCH, 0);    __vmwrite(CR3_TARGET_COUNT, 0);    __vmwrite(GUEST_ACTIVITY_STATE, 0);    /* Guest segment bases. */    __vmwrite(GUEST_ES_BASE, 0);    __vmwrite(GUEST_SS_BASE, 0);    __vmwrite(GUEST_DS_BASE, 0);    __vmwrite(GUEST_FS_BASE, 0);    __vmwrite(GUEST_GS_BASE, 0);    __vmwrite(GUEST_CS_BASE, 0);    /* Guest segment limits. */    __vmwrite(GUEST_ES_LIMIT, ~0u);    __vmwrite(GUEST_SS_LIMIT, ~0u);    __vmwrite(GUEST_DS_LIMIT, ~0u);    __vmwrite(GUEST_FS_LIMIT, ~0u);    __vmwrite(GUEST_GS_LIMIT, ~0u);    __vmwrite(GUEST_CS_LIMIT, ~0u);    /* Guest segment AR bytes. */    __vmwrite(GUEST_ES_AR_BYTES, 0xc093); /* read/write, accessed */    __vmwrite(GUEST_SS_AR_BYTES, 0xc093);    __vmwrite(GUEST_DS_AR_BYTES, 0xc093);    __vmwrite(GUEST_FS_AR_BYTES, 0xc093);    __vmwrite(GUEST_GS_AR_BYTES, 0xc093);    __vmwrite(GUEST_CS_AR_BYTES, 0xc09b); /* exec/read, accessed */    /* Guest IDT. */    __vmwrite(GUEST_IDTR_BASE, 0);    __vmwrite(GUEST_IDTR_LIMIT, 0);    /* Guest GDT. */    __vmwrite(GUEST_GDTR_BASE, 0);    __vmwrite(GUEST_GDTR_LIMIT, 0);    /* Guest LDT. */    __vmwrite(GUEST_LDTR_AR_BYTES, 0x0082); /* LDT */    __vmwrite(GUEST_LDTR_SELECTOR, 0);    __vmwrite(GUEST_LDTR_BASE, 0);    __vmwrite(GUEST_LDTR_LIMIT, 0);    /* Guest TSS. */    __vmwrite(GUEST_TR_AR_BYTES, 0x008b); /* 32-bit TSS (busy) */    __vmwrite(GUEST_TR_BASE, 0);    __vmwrite(GUEST_TR_LIMIT, 0xff);    __vmwrite(GUEST_INTERRUPTIBILITY_INFO, 0);    __vmwrite(GUEST_DR7, 0);    __vmwrite(VMCS_LINK_POINTER, ~0UL);#if defined(__i386__)    __vmwrite(VMCS_LINK_POINTER_HIGH, ~0UL);#endif    __vmwrite(EXCEPTION_BITMAP,              HVM_TRAP_MASK              | (paging_mode_hap(d) ? 0 : (1U << TRAP_page_fault))              | (1U << TRAP_no_device));    v->arch.hvm_vcpu.guest_cr[0] = X86_CR0_PE | X86_CR0_ET;    hvm_update_guest_cr(v, 0);    v->arch.hvm_vcpu.guest_cr[4] = 0;    hvm_update_guest_cr(v, 4);    if ( cpu_has_vmx_tpr_shadow )    {        __vmwrite(VIRTUAL_APIC_PAGE_ADDR,                  page_to_maddr(vcpu_vlapic(v)->regs_page));        __vmwrite(TPR_THRESHOLD, 0);    }    if ( paging_mode_hap(d) )    {        __vmwrite(EPT_POINTER, d->arch.hvm_domain.vmx.ept_control.eptp);#ifdef __i386__        __vmwrite(EPT_POINTER_HIGH,                  d->arch.hvm_domain.vmx.ept_control.eptp >> 32);#endif    }    if ( cpu_has_vmx_vpid )    {        v->arch.hvm_vmx.vpid =            v->domain->arch.hvm_domain.vmx.vpid_base + v->vcpu_id;        __vmwrite(VIRTUAL_PROCESSOR_ID, v->arch.hvm_vmx.vpid);    }    vmx_vmcs_exit(v);    paging_update_paging_modes(v); /* will update HOST & GUEST_CR3 as reqd */    vmx_vlapic_msr_changed(v);    return 0;}int vmx_read_guest_msr(u32 msr, u64 *val){    struct vcpu *curr = current;    unsigned int i, msr_count = curr->arch.hvm_vmx.msr_count;    const struct vmx_msr_entry *msr_area = curr->arch.hvm_vmx.msr_area;    for ( i = 0; i < msr_count; i++ )    {        if ( msr_area[i].index == msr )        {            *val = msr_area[i].data;            return 0;        }    }    return -ESRCH;}int vmx_write_guest_msr(u32 msr, u64 val){    struct vcpu *curr = current;    unsigned int i, msr_count = curr->arch.hvm_vmx.msr_count;    struct vmx_msr_entry *msr_area = curr->arch.hvm_vmx.msr_area;    for ( i = 0; i < msr_count; i++ )    {        if ( msr_area[i].index == msr )        {            msr_area[i].data = val;            return 0;        }    }

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?