vmcs.c
来自「xen虚拟机源代码安装包」· C语言 代码 · 共 1,066 行 · 第 1/3 页
C
1,066 行
/* * vmcs.c: VMCS management * Copyright (c) 2004, Intel Corporation. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., 59 Temple * Place - Suite 330, Boston, MA 02111-1307 USA. */#include <xen/config.h>#include <xen/init.h>#include <xen/mm.h>#include <xen/lib.h>#include <xen/errno.h>#include <xen/domain_page.h>#include <asm/current.h>#include <asm/cpufeature.h>#include <asm/processor.h>#include <asm/msr.h>#include <asm/hvm/hvm.h>#include <asm/hvm/io.h>#include <asm/hvm/support.h>#include <asm/hvm/vmx/vmx.h>#include <asm/hvm/vmx/vmcs.h>#include <asm/flushtlb.h>#include <xen/event.h>#include <xen/kernel.h>#include <xen/keyhandler.h>#include <asm/shadow.h>#include <asm/tboot.h>static int opt_vpid_enabled = 1;boolean_param("vpid", opt_vpid_enabled);/* Dynamic (run-time adjusted) execution control flags. */u32 vmx_pin_based_exec_control __read_mostly;u32 vmx_cpu_based_exec_control __read_mostly;u32 vmx_secondary_exec_control __read_mostly;u32 vmx_vmexit_control __read_mostly;u32 vmx_vmentry_control __read_mostly;bool_t cpu_has_vmx_ins_outs_instr_info __read_mostly;static DEFINE_PER_CPU(struct vmcs_struct *, host_vmcs);static DEFINE_PER_CPU(struct vmcs_struct *, current_vmcs);static DEFINE_PER_CPU(struct list_head, active_vmcs_list);static u32 vmcs_revision_id __read_mostly;static u32 adjust_vmx_controls(u32 ctl_min, u32 ctl_opt, u32 msr){ u32 vmx_msr_low, vmx_msr_high, ctl = ctl_min | ctl_opt; rdmsr(msr, vmx_msr_low, vmx_msr_high); ctl &= vmx_msr_high; /* bit == 0 in high word ==> must be zero */ ctl |= vmx_msr_low; /* bit == 1 in low word ==> must be one */ /* Ensure minimum (required) set of control bits are supported. */ BUG_ON(ctl_min & ~ctl); return ctl;}static void vmx_init_vmcs_config(void){ u32 vmx_basic_msr_low, vmx_basic_msr_high, min, opt; u32 _vmx_pin_based_exec_control; u32 _vmx_cpu_based_exec_control; u32 _vmx_secondary_exec_control = 0; u32 _vmx_vmexit_control; u32 _vmx_vmentry_control; rdmsr(MSR_IA32_VMX_BASIC, vmx_basic_msr_low, vmx_basic_msr_high); min = (PIN_BASED_EXT_INTR_MASK | PIN_BASED_NMI_EXITING); opt = PIN_BASED_VIRTUAL_NMIS; _vmx_pin_based_exec_control = adjust_vmx_controls( min, opt, MSR_IA32_VMX_PINBASED_CTLS); min = (CPU_BASED_HLT_EXITING | CPU_BASED_INVLPG_EXITING | CPU_BASED_CR3_LOAD_EXITING | CPU_BASED_CR3_STORE_EXITING | CPU_BASED_MONITOR_EXITING | CPU_BASED_MWAIT_EXITING | CPU_BASED_MOV_DR_EXITING | CPU_BASED_ACTIVATE_IO_BITMAP | CPU_BASED_USE_TSC_OFFSETING | (opt_softtsc ? CPU_BASED_RDTSC_EXITING : 0)); opt = (CPU_BASED_ACTIVATE_MSR_BITMAP | CPU_BASED_TPR_SHADOW | CPU_BASED_ACTIVATE_SECONDARY_CONTROLS); _vmx_cpu_based_exec_control = adjust_vmx_controls( min, opt, MSR_IA32_VMX_PROCBASED_CTLS);#ifdef __x86_64__ if ( !(_vmx_cpu_based_exec_control & CPU_BASED_TPR_SHADOW) ) { min |= CPU_BASED_CR8_LOAD_EXITING | CPU_BASED_CR8_STORE_EXITING; _vmx_cpu_based_exec_control = adjust_vmx_controls( min, opt, MSR_IA32_VMX_PROCBASED_CTLS); }#endif if ( _vmx_cpu_based_exec_control & CPU_BASED_ACTIVATE_SECONDARY_CONTROLS ) { min = 0; opt = (SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES | SECONDARY_EXEC_WBINVD_EXITING | SECONDARY_EXEC_ENABLE_EPT); if ( opt_vpid_enabled ) opt |= SECONDARY_EXEC_ENABLE_VPID; _vmx_secondary_exec_control = adjust_vmx_controls( min, opt, MSR_IA32_VMX_PROCBASED_CTLS2); } if ( _vmx_secondary_exec_control & SECONDARY_EXEC_ENABLE_EPT ) { /* * To use EPT we expect to be able to clear certain intercepts. * We check VMX_BASIC_MSR[55] to correctly handle default1 controls. */ uint32_t must_be_one, must_be_zero, msr = MSR_IA32_VMX_PROCBASED_CTLS; if ( vmx_basic_msr_high & (1u << 23) ) msr = MSR_IA32_VMX_TRUE_PROCBASED_CTLS; rdmsr(msr, must_be_one, must_be_zero); if ( must_be_one & (CPU_BASED_INVLPG_EXITING | CPU_BASED_CR3_LOAD_EXITING | CPU_BASED_CR3_STORE_EXITING) ) _vmx_secondary_exec_control &= ~SECONDARY_EXEC_ENABLE_EPT; }#if defined(__i386__) /* If we can't virtualise APIC accesses, the TPR shadow is pointless. */ if ( !(_vmx_secondary_exec_control & SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES) ) _vmx_cpu_based_exec_control &= ~CPU_BASED_TPR_SHADOW;#endif min = VM_EXIT_ACK_INTR_ON_EXIT; opt = 0;#ifdef __x86_64__ min |= VM_EXIT_IA32E_MODE;#endif _vmx_vmexit_control = adjust_vmx_controls( min, opt, MSR_IA32_VMX_EXIT_CTLS); min = opt = 0; _vmx_vmentry_control = adjust_vmx_controls( min, opt, MSR_IA32_VMX_ENTRY_CTLS); if ( !vmx_pin_based_exec_control ) { /* First time through. */ vmcs_revision_id = vmx_basic_msr_low; vmx_pin_based_exec_control = _vmx_pin_based_exec_control; vmx_cpu_based_exec_control = _vmx_cpu_based_exec_control; vmx_secondary_exec_control = _vmx_secondary_exec_control; vmx_vmexit_control = _vmx_vmexit_control; vmx_vmentry_control = _vmx_vmentry_control; cpu_has_vmx_ins_outs_instr_info = !!(vmx_basic_msr_high & (1U<<22)); } else { /* Globals are already initialised: re-check them. */ BUG_ON(vmcs_revision_id != vmx_basic_msr_low); BUG_ON(vmx_pin_based_exec_control != _vmx_pin_based_exec_control); BUG_ON(vmx_cpu_based_exec_control != _vmx_cpu_based_exec_control); BUG_ON(vmx_secondary_exec_control != _vmx_secondary_exec_control); BUG_ON(vmx_vmexit_control != _vmx_vmexit_control); BUG_ON(vmx_vmentry_control != _vmx_vmentry_control); BUG_ON(cpu_has_vmx_ins_outs_instr_info != !!(vmx_basic_msr_high & (1U<<22))); } /* IA-32 SDM Vol 3B: VMCS size is never greater than 4kB. */ BUG_ON((vmx_basic_msr_high & 0x1fff) > PAGE_SIZE);#ifdef __x86_64__ /* IA-32 SDM Vol 3B: 64-bit CPUs always have VMX_BASIC_MSR[48]==0. */ BUG_ON(vmx_basic_msr_high & (1u<<16));#endif /* Require Write-Back (WB) memory type for VMCS accesses. */ BUG_ON(((vmx_basic_msr_high >> 18) & 15) != 6);}static struct vmcs_struct *vmx_alloc_vmcs(void){ struct vmcs_struct *vmcs; if ( (vmcs = alloc_xenheap_page()) == NULL ) { gdprintk(XENLOG_WARNING, "Failed to allocate VMCS.\n"); return NULL; } clear_page(vmcs); vmcs->vmcs_revision_id = vmcs_revision_id; return vmcs;}static void vmx_free_vmcs(struct vmcs_struct *vmcs){ free_xenheap_page(vmcs);}static void __vmx_clear_vmcs(void *info){ struct vcpu *v = info; struct arch_vmx_struct *arch_vmx = &v->arch.hvm_vmx; /* Otherwise we can nest (vmx_cpu_down() vs. vmx_clear_vmcs()). */ ASSERT(!local_irq_is_enabled()); if ( arch_vmx->active_cpu == smp_processor_id() ) { __vmpclear(virt_to_maddr(arch_vmx->vmcs)); arch_vmx->active_cpu = -1; arch_vmx->launched = 0; list_del(&arch_vmx->active_list); if ( arch_vmx->vmcs == this_cpu(current_vmcs) ) this_cpu(current_vmcs) = NULL; }}static void vmx_clear_vmcs(struct vcpu *v){ int cpu = v->arch.hvm_vmx.active_cpu; if ( cpu != -1 ) on_selected_cpus(cpumask_of_cpu(cpu), __vmx_clear_vmcs, v, 1, 1);}static void vmx_load_vmcs(struct vcpu *v){ unsigned long flags; local_irq_save(flags); if ( v->arch.hvm_vmx.active_cpu == -1 ) { list_add(&v->arch.hvm_vmx.active_list, &this_cpu(active_vmcs_list)); v->arch.hvm_vmx.active_cpu = smp_processor_id(); } ASSERT(v->arch.hvm_vmx.active_cpu == smp_processor_id()); __vmptrld(virt_to_maddr(v->arch.hvm_vmx.vmcs)); this_cpu(current_vmcs) = v->arch.hvm_vmx.vmcs; local_irq_restore(flags);}int vmx_cpu_up(void){ u32 eax, edx; int bios_locked, cpu = smp_processor_id(); u64 cr0, vmx_cr0_fixed0, vmx_cr0_fixed1; BUG_ON(!(read_cr4() & X86_CR4_VMXE)); /* * Ensure the current processor operating mode meets * the requred CRO fixed bits in VMX operation. */ cr0 = read_cr0(); rdmsrl(MSR_IA32_VMX_CR0_FIXED0, vmx_cr0_fixed0); rdmsrl(MSR_IA32_VMX_CR0_FIXED1, vmx_cr0_fixed1); if ( (~cr0 & vmx_cr0_fixed0) || (cr0 & ~vmx_cr0_fixed1) ) { printk("CPU%d: some settings of host CR0 are " "not allowed in VMX operation.\n", cpu); return 0; } rdmsr(IA32_FEATURE_CONTROL_MSR, eax, edx); bios_locked = !!(eax & IA32_FEATURE_CONTROL_MSR_LOCK); if ( bios_locked ) { if ( !(eax & (IA32_FEATURE_CONTROL_MSR_ENABLE_VMXON_OUTSIDE_SMX | IA32_FEATURE_CONTROL_MSR_ENABLE_VMXON_INSIDE_SMX)) ) { printk("CPU%d: VMX disabled by BIOS.\n", cpu); return 0; } } else { eax = IA32_FEATURE_CONTROL_MSR_LOCK; eax |= IA32_FEATURE_CONTROL_MSR_ENABLE_VMXON_OUTSIDE_SMX; if ( test_bit(X86_FEATURE_SMXE, &boot_cpu_data.x86_capability) ) eax |= IA32_FEATURE_CONTROL_MSR_ENABLE_VMXON_INSIDE_SMX; wrmsr(IA32_FEATURE_CONTROL_MSR, eax, 0); } vmx_init_vmcs_config(); INIT_LIST_HEAD(&this_cpu(active_vmcs_list)); if ( this_cpu(host_vmcs) == NULL ) { this_cpu(host_vmcs) = vmx_alloc_vmcs(); if ( this_cpu(host_vmcs) == NULL ) { printk("CPU%d: Could not allocate host VMCS\n", cpu); return 0; } } switch ( __vmxon(virt_to_maddr(this_cpu(host_vmcs))) ) { case -2: /* #UD or #GP */ if ( bios_locked && test_bit(X86_FEATURE_SMXE, &boot_cpu_data.x86_capability) && (!(eax & IA32_FEATURE_CONTROL_MSR_ENABLE_VMXON_OUTSIDE_SMX) || !(eax & IA32_FEATURE_CONTROL_MSR_ENABLE_VMXON_INSIDE_SMX)) ) { printk("CPU%d: VMXON failed: perhaps because of TXT settings " "in your BIOS configuration?\n", cpu); printk(" --> Disable TXT in your BIOS unless using a secure " "bootloader.\n"); return 0; } /* fall through */ case -1: /* CF==1 or ZF==1 */ printk("CPU%d: unexpected VMXON failure\n", cpu); return 0; case 0: /* success */ break; default: BUG(); } ept_sync_all(); vpid_sync_all(); return 1;}void vmx_cpu_down(void)
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?