From 378fd8866580acc8001e6e8e4476c8a8815b5965 Mon Sep 17 00:00:00 2001 From: Keir Fraser Date: Tue, 1 Jun 2010 14:25:59 +0100 Subject: [PATCH] VMX: does EPT capabilities detection strictly according to Intel SDM. Signed-off-by: Xin Li --- xen/arch/x86/hvm/svm/svm.c | 4 ++-- xen/arch/x86/hvm/vmx/vmcs.c | 37 ++++++++++++------------------ xen/arch/x86/hvm/vmx/vmx.c | 10 ++++++-- xen/arch/x86/mm/hap/p2m-ept.c | 11 ++++++--- xen/arch/x86/mm/p2m.c | 7 +++--- xen/include/asm-x86/hvm/hvm.h | 20 ++++++++++++---- xen/include/asm-x86/hvm/vmx/vmcs.h | 12 ++++++---- 7 files changed, 58 insertions(+), 43 deletions(-) diff --git a/xen/arch/x86/hvm/svm/svm.c b/xen/arch/x86/hvm/svm/svm.c index d897b43c7d..f52f4e0452 100644 --- a/xen/arch/x86/hvm/svm/svm.c +++ b/xen/arch/x86/hvm/svm/svm.c @@ -935,9 +935,9 @@ struct hvm_function_table * __init start_svm(void) cpuid_edx(0x8000000A) : 0); svm_function_table.hap_supported = cpu_has_svm_npt; - svm_function_table.hap_superpage_level = + svm_function_table.hap_capabilities = HVM_HAP_SUPERPAGE_2MB | ((CONFIG_PAGING_LEVELS == 4) && (cpuid_edx(0x80000001) & 0x04000000)) ? - 2 : 1; + HVM_HAP_SUPERPAGE_1GB : 0; return &svm_function_table; } diff --git a/xen/arch/x86/hvm/vmx/vmcs.c b/xen/arch/x86/hvm/vmx/vmcs.c index 39f5cb51ea..e1de38cc94 100644 --- a/xen/arch/x86/hvm/vmx/vmcs.c +++ b/xen/arch/x86/hvm/vmx/vmcs.c @@ -64,7 +64,7 @@ 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; -u8 vmx_ept_super_page_level_limit __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 *, host_vmcs); @@ -92,10 +92,10 @@ static void __init vmx_display_features(void) if ( !printed ) printk(" - none\n"); - if ( vmx_ept_super_page_level_limit ) - printk("EPT supports %s super page.\n", - (vmx_ept_super_page_level_limit == 2) ? "1G" : - ((vmx_ept_super_page_level_limit == 1) ? "2M" : "4K")); + if ( cpu_has_vmx_ept_1gb ) + printk("EPT supports 1GB super page.\n"); + if ( cpu_has_vmx_ept_2mb ) + printk("EPT supports 2MB super page.\n"); } static u32 adjust_vmx_controls( @@ -132,7 +132,7 @@ static int vmx_init_vmcs_config(void) u32 _vmx_pin_based_exec_control; u32 _vmx_cpu_based_exec_control; u32 _vmx_secondary_exec_control = 0; - u8 ept_super_page_level_limit = 0; + u64 _vmx_ept_vpid_cap = 0; u32 _vmx_vmexit_control; u32 _vmx_vmentry_control; bool_t mismatch = 0; @@ -208,17 +208,13 @@ static int vmx_init_vmcs_config(void) _vmx_secondary_exec_control &= ~(SECONDARY_EXEC_ENABLE_EPT | SECONDARY_EXEC_UNRESTRICTED_GUEST); - if ( _vmx_secondary_exec_control & SECONDARY_EXEC_ENABLE_EPT ) - { - uint64_t cap; - rdmsrl(MSR_IA32_VMX_EPT_VPID_CAP, cap); - if ( cap & VMX_EPT_SUPER_PAGE_1G ) - ept_super_page_level_limit = 2; - else if ( cap & VMX_EPT_SUPER_PAGE_2M ) - ept_super_page_level_limit = 1; - } } + /* The IA32_VMX_EPT_VPID_CAP MSR exists only when EPT or VPID available */ + if ( _vmx_secondary_exec_control & + (SECONDARY_EXEC_ENABLE_EPT | SECONDARY_EXEC_ENABLE_VPID) ) + rdmsrl(MSR_IA32_VMX_EPT_VPID_CAP, _vmx_ept_vpid_cap); + if ( (_vmx_secondary_exec_control & SECONDARY_EXEC_PAUSE_LOOP_EXITING) && ple_gap == 0 ) { @@ -256,7 +252,7 @@ static int vmx_init_vmcs_config(void) 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_super_page_level_limit = ept_super_page_level_limit; + 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)); @@ -283,12 +279,9 @@ static int vmx_init_vmcs_config(void) mismatch |= cap_check( "VMEntry Control", vmx_vmentry_control, _vmx_vmentry_control); - if ( vmx_ept_super_page_level_limit > ept_super_page_level_limit ) - { - printk("EPT Super Page Limit: saw %u expected >= %u\n", - ept_super_page_level_limit, vmx_ept_super_page_level_limit); - mismatch = 1; - } + mismatch |= cap_check( + "EPT Super Page Capability", + vmx_ept_vpid_cap, _vmx_ept_vpid_cap); if ( cpu_has_vmx_ins_outs_instr_info != !!(vmx_basic_msr_high & (1U<<22)) ) { diff --git a/xen/arch/x86/hvm/vmx/vmx.c b/xen/arch/x86/hvm/vmx/vmx.c index 3432e927d5..1c07be6f51 100644 --- a/xen/arch/x86/hvm/vmx/vmx.c +++ b/xen/arch/x86/hvm/vmx/vmx.c @@ -1432,10 +1432,16 @@ struct hvm_function_table * __init start_vmx(void) if ( cpu_has_vmx_ept ) { vmx_function_table.hap_supported = 1; + + vmx_function_table.hap_capabilities = 0; + + if ( cpu_has_vmx_ept_2mb ) + vmx_function_table.hap_capabilities |= HVM_HAP_SUPERPAGE_2MB; + if ( cpu_has_vmx_ept_1gb ) + vmx_function_table.hap_capabilities |= HVM_HAP_SUPERPAGE_1GB; + setup_ept_dump(); } - - vmx_function_table.hap_superpage_level = vmx_ept_super_page_level_limit; setup_vmcs_dump(); diff --git a/xen/arch/x86/mm/hap/p2m-ept.c b/xen/arch/x86/mm/hap/p2m-ept.c index 7f67a6725a..0fb306b7c3 100644 --- a/xen/arch/x86/mm/hap/p2m-ept.c +++ b/xen/arch/x86/mm/hap/p2m-ept.c @@ -308,9 +308,14 @@ ept_set_entry(struct domain *d, unsigned long gfn, mfn_t mfn, int num = order / EPT_TABLE_ORDER; int level; ept_entry_t *split_ept_entry; - - if ( num >= cpu_vmx_ept_super_page_level_limit ) - num = cpu_vmx_ept_super_page_level_limit; + + if ( (num >= 2) && hvm_hap_has_1gb(d) ) + num = 2; + else if ( (num >= 1) && hvm_hap_has_2mb(d) ) + num = 1; + else + num = 0; + for ( level = split_level; level > num ; level-- ) { rv = ept_split_large_page(d, &table, &index, gfn, level); diff --git a/xen/arch/x86/mm/p2m.c b/xen/arch/x86/mm/p2m.c index 29e15741f8..79ae915711 100644 --- a/xen/arch/x86/mm/p2m.c +++ b/xen/arch/x86/mm/p2m.c @@ -1758,10 +1758,9 @@ int set_p2m_entry(struct domain *d, unsigned long gfn, mfn_t mfn, { if ( is_hvm_domain(d) && paging_mode_hap(d) ) order = ( (((gfn | mfn_x(mfn) | todo) & ((1ul << 18) - 1)) == 0) && - (hvm_funcs.hap_superpage_level == 2) && - opt_hap_1gb ) ? 18 : - ((((gfn | mfn_x(mfn) | todo) & ((1ul << 9) - 1)) == 0) && - (hvm_funcs.hap_superpage_level >= 1)) ? 9 : 0; + hvm_hap_has_1gb(d) && opt_hap_1gb ) ? 18 : + ((((gfn | mfn_x(mfn) | todo) & ((1ul << 9) - 1)) == 0) && + hvm_hap_has_2mb(d)) ? 9 : 0; else order = 0; diff --git a/xen/include/asm-x86/hvm/hvm.h b/xen/include/asm-x86/hvm/hvm.h index 40719bb2cf..0bb4710b82 100644 --- a/xen/include/asm-x86/hvm/hvm.h +++ b/xen/include/asm-x86/hvm/hvm.h @@ -61,6 +61,14 @@ enum hvm_intblk { #define HVM_INTR_SHADOW_SMI 0x00000004 #define HVM_INTR_SHADOW_NMI 0x00000008 +/* + * HAP super page capabilities: + * bit0: if 2MB super page is allowed? + * bit1: if 1GB super page is allowed? + */ +#define HVM_HAP_SUPERPAGE_2MB 0x00000001 +#define HVM_HAP_SUPERPAGE_1GB 0x00000002 + /* * The hardware virtual machine (HVM) interface abstracts away from the * x86/x86_64 CPU virtualization assist specifics. Currently this interface @@ -72,11 +80,8 @@ struct hvm_function_table { /* Support Hardware-Assisted Paging? */ int hap_supported; - /* - * Indicate HAP super page level. - * 0 -- 4KB, 1 -- 2MB, 2 -- 1GB. - */ - int hap_superpage_level; + /* Indicate HAP capabilities. */ + int hap_capabilities; /* @@ -176,6 +181,11 @@ int hvm_girq_dest_2_vcpu_id(struct domain *d, uint8_t dest, uint8_t dest_mode); #define hvm_nx_enabled(v) \ (!!((v)->arch.hvm_vcpu.guest_efer & EFER_NX)) +#define hvm_hap_has_1gb(d) \ + (hvm_funcs.hap_capabilities & HVM_HAP_SUPERPAGE_1GB) +#define hvm_hap_has_2mb(d) \ + (hvm_funcs.hap_capabilities & HVM_HAP_SUPERPAGE_2MB) + #ifdef __x86_64__ #define hvm_long_mode_enabled(v) \ ((v)->arch.hvm_vcpu.guest_efer & EFER_LMA) diff --git a/xen/include/asm-x86/hvm/vmx/vmcs.h b/xen/include/asm-x86/hvm/vmx/vmcs.h index 535830f7d3..b49479b173 100644 --- a/xen/include/asm-x86/hvm/vmx/vmcs.h +++ b/xen/include/asm-x86/hvm/vmx/vmcs.h @@ -174,10 +174,10 @@ extern u32 vmx_secondary_exec_control; extern bool_t cpu_has_vmx_ins_outs_instr_info; -extern u8 vmx_ept_super_page_level_limit; +extern u64 vmx_ept_vpid_cap; -#define VMX_EPT_SUPER_PAGE_2M 0x00010000 -#define VMX_EPT_SUPER_PAGE_1G 0x00020000 +#define VMX_EPT_SUPERPAGE_2MB 0x00010000 +#define VMX_EPT_SUPERPAGE_1GB 0x00020000 #define cpu_has_wbinvd_exiting \ (vmx_secondary_exec_control & SECONDARY_EXEC_WBINVD_EXITING) @@ -193,6 +193,10 @@ extern u8 vmx_ept_super_page_level_limit; (vmx_cpu_based_exec_control & CPU_BASED_ACTIVATE_SECONDARY_CONTROLS) #define cpu_has_vmx_ept \ (vmx_secondary_exec_control & SECONDARY_EXEC_ENABLE_EPT) +#define cpu_has_vmx_ept_1gb \ + (vmx_ept_vpid_cap & VMX_EPT_SUPERPAGE_1GB) +#define cpu_has_vmx_ept_2mb \ + (vmx_ept_vpid_cap & VMX_EPT_SUPERPAGE_2MB) #define cpu_has_vmx_vpid \ (vmx_secondary_exec_control & SECONDARY_EXEC_ENABLE_VPID) #define cpu_has_monitor_trap_flag \ @@ -206,8 +210,6 @@ extern u8 vmx_ept_super_page_level_limit; SECONDARY_EXEC_UNRESTRICTED_GUEST) #define cpu_has_vmx_ple \ (vmx_secondary_exec_control & SECONDARY_EXEC_PAUSE_LOOP_EXITING) -#define cpu_vmx_ept_super_page_level_limit \ - vmx_ept_super_page_level_limit /* GUEST_INTERRUPTIBILITY_INFO flags. */ #define VMX_INTR_SHADOW_STI 0x00000001 -- 2.30.2