VMX: clean up capability checks VMCS size validation on APs should check against BP's size. No need for a separate cpu_has_vmx_ins_outs_instr_info variable anymore. Use proper symbolics. Signed-off-by: Jan Beulich --- a/xen/arch/x86/hvm/vmx/vmcs.c +++ b/xen/arch/x86/hvm/vmx/vmcs.c @@ -70,7 +70,6 @@ u32 vmx_secondary_exec_control __read_mo u32 vmx_vmexit_control __read_mostly; u32 vmx_vmentry_control __read_mostly; u64 vmx_ept_vpid_cap __read_mostly; -bool_t cpu_has_vmx_ins_outs_instr_info __read_mostly; static DEFINE_PER_CPU_READ_MOSTLY(struct vmcs_struct *, vmxon_region); static DEFINE_PER_CPU(struct vmcs_struct *, current_vmcs); @@ -294,24 +293,33 @@ static int vmx_init_vmcs_config(void) if ( !vmx_pin_based_exec_control ) { /* First time through. */ - vmcs_revision_id = vmx_basic_msr_low; + vmcs_revision_id = vmx_basic_msr_low & VMX_BASIC_REVISION_MASK; 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_ept_vpid_cap = _vmx_ept_vpid_cap; 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)); vmx_basic_msr = ((u64)vmx_basic_msr_high << 32) | vmx_basic_msr_low; vmx_display_features(); + + /* IA-32 SDM Vol 3B: VMCS size is never greater than 4kB. */ + if ( (vmx_basic_msr_high & (VMX_BASIC_VMCS_SIZE_MASK >> 32)) > + PAGE_SIZE ) + { + printk("VMX: CPU%d VMCS size is too big (%Lu bytes)\n", + smp_processor_id(), + vmx_basic_msr_high & (VMX_BASIC_VMCS_SIZE_MASK >> 32)); + return -EINVAL; + } } else { /* Globals are already initialised: re-check them. */ mismatch |= cap_check( "VMCS revision ID", - vmcs_revision_id, vmx_basic_msr_low); + vmcs_revision_id, vmx_basic_msr_low & VMX_BASIC_REVISION_MASK); mismatch |= cap_check( "Pin-Based Exec Control", vmx_pin_based_exec_control, _vmx_pin_based_exec_control); @@ -331,13 +339,21 @@ static int vmx_init_vmcs_config(void) "EPT and VPID Capability", vmx_ept_vpid_cap, _vmx_ept_vpid_cap); if ( cpu_has_vmx_ins_outs_instr_info != - !!(vmx_basic_msr_high & (1U<<22)) ) + !!(vmx_basic_msr_high & (VMX_BASIC_INS_OUT_INFO >> 32)) ) { printk("VMX INS/OUTS Instruction Info: saw %d expected %d\n", - !!(vmx_basic_msr_high & (1U<<22)), + !!(vmx_basic_msr_high & (VMX_BASIC_INS_OUT_INFO >> 32)), cpu_has_vmx_ins_outs_instr_info); mismatch = 1; } + if ( (vmx_basic_msr_high & (VMX_BASIC_VMCS_SIZE_MASK >> 32)) != + ((vmx_basic_msr & VMX_BASIC_VMCS_SIZE_MASK) >> 32) ) + { + printk("VMX: CPU%d unexpected VMCS size %Lu\n", + smp_processor_id(), + vmx_basic_msr_high & (VMX_BASIC_VMCS_SIZE_MASK >> 32)); + mismatch = 1; + } if ( mismatch ) { printk("VMX: Capabilities fatally differ between CPU%d and CPU0\n", @@ -346,16 +362,8 @@ static int vmx_init_vmcs_config(void) } } - /* IA-32 SDM Vol 3B: VMCS size is never greater than 4kB. */ - if ( (vmx_basic_msr_high & 0x1fff) > PAGE_SIZE ) - { - printk("VMX: CPU%d VMCS size is too big (%u bytes)\n", - smp_processor_id(), vmx_basic_msr_high & 0x1fff); - return -EINVAL; - } - /* IA-32 SDM Vol 3B: 64-bit CPUs always have VMX_BASIC_MSR[48]==0. */ - if ( vmx_basic_msr_high & (1u<<16) ) + if ( vmx_basic_msr_high & (VMX_BASIC_32BIT_ADDRESSES >> 32) ) { printk("VMX: CPU%d limits VMX structure pointers to 32 bits\n", smp_processor_id()); @@ -363,10 +371,12 @@ static int vmx_init_vmcs_config(void) } /* Require Write-Back (WB) memory type for VMCS accesses. */ - if ( ((vmx_basic_msr_high >> 18) & 15) != 6 ) + opt = (vmx_basic_msr_high & (VMX_BASIC_MEMORY_TYPE_MASK >> 32)) / + ((VMX_BASIC_MEMORY_TYPE_MASK & -VMX_BASIC_MEMORY_TYPE_MASK) >> 32); + if ( opt != MTRR_TYPE_WRBACK ) { printk("VMX: CPU%d has unexpected VMCS access type %u\n", - smp_processor_id(), (vmx_basic_msr_high >> 18) & 15); + smp_processor_id(), opt); return -EINVAL; } --- a/xen/include/asm-x86/hvm/vmx/vmcs.h +++ b/xen/include/asm-x86/hvm/vmx/vmcs.h @@ -210,8 +210,6 @@ extern u32 vmx_vmentry_control; #define SECONDARY_EXEC_ENABLE_VMCS_SHADOWING 0x00004000 extern u32 vmx_secondary_exec_control; -extern bool_t cpu_has_vmx_ins_outs_instr_info; - #define VMX_EPT_EXEC_ONLY_SUPPORTED 0x00000001 #define VMX_EPT_WALK_LENGTH_4_SUPPORTED 0x00000040 #define VMX_EPT_MEMORY_TYPE_UC 0x00000100 @@ -278,6 +276,12 @@ extern bool_t cpu_has_vmx_ins_outs_instr #define VMX_INTR_SHADOW_SMI 0x00000004 #define VMX_INTR_SHADOW_NMI 0x00000008 +#define VMX_BASIC_REVISION_MASK 0x7fffffff +#define VMX_BASIC_VMCS_SIZE_MASK (0x1fffULL << 32) +#define VMX_BASIC_32BIT_ADDRESSES (1ULL << 48) +#define VMX_BASIC_DUAL_MONITOR (1ULL << 49) +#define VMX_BASIC_MEMORY_TYPE_MASK (0xfULL << 50) +#define VMX_BASIC_INS_OUT_INFO (1ULL << 54) /* * bit 55 of IA32_VMX_BASIC MSR, indicating whether any VMX controls that * default to 1 may be cleared to 0. @@ -285,6 +289,8 @@ extern bool_t cpu_has_vmx_ins_outs_instr #define VMX_BASIC_DEFAULT1_ZERO (1ULL << 55) extern u64 vmx_basic_msr; +#define cpu_has_vmx_ins_outs_instr_info \ + (!!(vmx_basic_msr & VMX_BASIC_INS_OUT_INFO)) /* Guest interrupt status */ #define VMX_GUEST_INTR_STATUS_SUBFIELD_BITMASK 0x0FF