From: Liu, Jinsong Date: Thu, 1 Dec 2011 11:24:06 +0000 (+0100) Subject: X86: implement PCID/INVPCID for hvm X-Git-Url: https://dgit.raspbian.org/?a=commitdiff_plain;h=7d3ada69de442c1a65f5f5686150f1ff1b6131bc;p=xen.git X86: implement PCID/INVPCID for hvm This patch handle PCID/INVPCID for hvm: For hap hvm, we enable PCID/INVPCID, since no need to intercept INVPCID, and we just set INVPCID non-root behavior as running natively; For shadow hvm, we disable PCID/INVPCID, otherwise we need to emulate INVPCID at vmm by setting INVPCID non-root behavior as vmexit. Signed-off-by: Liu, Jinsong Committed-by: Jan Beulich --- diff --git a/xen/arch/x86/hvm/hvm.c b/xen/arch/x86/hvm/hvm.c index 404dcca618..9ac42b52b6 100644 --- a/xen/arch/x86/hvm/hvm.c +++ b/xen/arch/x86/hvm/hvm.c @@ -1582,6 +1582,13 @@ int hvm_set_cr0(unsigned long value) } else if ( !(value & X86_CR0_PG) && (old_value & X86_CR0_PG) ) { + if ( hvm_pcid_enabled(v) ) + { + HVM_DBG_LOG(DBG_LEVEL_1, "Guest attempts to clear CR0.PG " + "while CR4.PCIDE=1"); + goto gpf; + } + /* When CR0.PG is cleared, LMA is cleared immediately. */ if ( hvm_long_mode_enabled(v) ) { @@ -1700,12 +1707,27 @@ int hvm_set_cr4(unsigned long value) } old_cr = v->arch.hvm_vcpu.guest_cr[4]; + + if ( (value & X86_CR4_PCIDE) && !(old_cr & X86_CR4_PCIDE) && + (!hvm_long_mode_enabled(v) || + (v->arch.hvm_vcpu.guest_cr[3] & 0xfff)) ) + { + HVM_DBG_LOG(DBG_LEVEL_1, "Guest attempts to change CR4.PCIDE from " + "0 to 1 while either EFER.LMA=0 or CR3[11:0]!=000H"); + goto gpf; + } + v->arch.hvm_vcpu.guest_cr[4] = value; hvm_update_guest_cr(v, 4); - /* Modifying CR4.{PSE,PAE,PGE,SMEP} invalidates all TLB entries. */ - if ( (old_cr ^ value) & (X86_CR4_PSE | X86_CR4_PGE | - X86_CR4_PAE | X86_CR4_SMEP) ) { + /* + * Modifying CR4.{PSE,PAE,PGE,SMEP}, or clearing CR4.PCIDE + * invalidate all TLB entries. + */ + if ( ((old_cr ^ value) & + (X86_CR4_PSE | X86_CR4_PGE | X86_CR4_PAE | X86_CR4_SMEP)) || + (!(value & X86_CR4_PCIDE) && (old_cr & X86_CR4_PCIDE)) ) + { if ( !nestedhvm_vmswitch_in_progress(v) && nestedhvm_vcpu_in_guestmode(v) ) paging_update_nestedmode(v); else @@ -2465,6 +2487,10 @@ void hvm_cpuid(unsigned int input, unsigned int *eax, unsigned int *ebx, *ecx |= (v->arch.hvm_vcpu.guest_cr[4] & X86_CR4_OSXSAVE) ? cpufeat_mask(X86_FEATURE_OSXSAVE) : 0; + /* Don't expose PCID to non-hap hvm. */ + if ( !hap_enabled(d) ) + *ecx &= ~cpufeat_mask(X86_FEATURE_PCID); + /* Only provide PSE36 when guest runs in 32bit PAE or in long mode */ if ( !(hvm_pae_enabled(v) || hvm_long_mode_enabled(v)) ) *edx &= ~cpufeat_mask(X86_FEATURE_PSE36); @@ -2472,6 +2498,10 @@ void hvm_cpuid(unsigned int input, unsigned int *eax, unsigned int *ebx, case 0x7: if ( (count == 0) && !cpu_has_smep ) *ebx &= ~cpufeat_mask(X86_FEATURE_SMEP); + + /* Don't expose INVPCID to non-hap hvm. */ + if ( (count == 0) && !hap_enabled(d) ) + *ebx &= ~cpufeat_mask(X86_FEATURE_INVPCID); break; case 0xb: /* Fix the x2APIC identifier. */ diff --git a/xen/arch/x86/hvm/vmx/vmcs.c b/xen/arch/x86/hvm/vmx/vmcs.c index c6ba622b98..f0af4c4603 100644 --- a/xen/arch/x86/hvm/vmx/vmcs.c +++ b/xen/arch/x86/hvm/vmx/vmcs.c @@ -184,7 +184,8 @@ static int vmx_init_vmcs_config(void) SECONDARY_EXEC_WBINVD_EXITING | SECONDARY_EXEC_ENABLE_EPT | SECONDARY_EXEC_ENABLE_RDTSCP | - SECONDARY_EXEC_PAUSE_LOOP_EXITING); + SECONDARY_EXEC_PAUSE_LOOP_EXITING | + SECONDARY_EXEC_ENABLE_INVPCID); if ( opt_vpid_enabled ) opt |= SECONDARY_EXEC_ENABLE_VPID; if ( opt_unrestricted_guest_enabled ) @@ -732,7 +733,8 @@ static int construct_vmcs(struct vcpu *v) { v->arch.hvm_vmx.secondary_exec_control &= ~(SECONDARY_EXEC_ENABLE_EPT | - SECONDARY_EXEC_UNRESTRICTED_GUEST); + SECONDARY_EXEC_UNRESTRICTED_GUEST | + SECONDARY_EXEC_ENABLE_INVPCID); vmexit_ctl &= ~(VM_EXIT_SAVE_GUEST_PAT | VM_EXIT_LOAD_HOST_PAT); vmentry_ctl &= ~VM_ENTRY_LOAD_GUEST_PAT; diff --git a/xen/arch/x86/hvm/vmx/vmx.c b/xen/arch/x86/hvm/vmx/vmx.c index 1c819e3274..414414f143 100644 --- a/xen/arch/x86/hvm/vmx/vmx.c +++ b/xen/arch/x86/hvm/vmx/vmx.c @@ -1007,7 +1007,7 @@ static void vmx_load_pdptrs(struct vcpu *v) if ( !hvm_pae_enabled(v) || (v->arch.hvm_vcpu.guest_efer & EFER_LMA) ) return; - if ( cr3 & 0x1fUL ) + if ( (cr3 & 0x1fUL) && !hvm_pcid_enabled(v) ) goto crash; mfn = mfn_x(get_gfn(v->domain, cr3 >> PAGE_SHIFT, &p2mt)); @@ -2704,6 +2704,7 @@ asmlinkage void vmx_vmexit_handler(struct cpu_user_regs *regs) case EXIT_REASON_ACCESS_GDTR_OR_IDTR: case EXIT_REASON_ACCESS_LDTR_OR_TR: case EXIT_REASON_VMX_PREEMPTION_TIMER_EXPIRED: + case EXIT_REASON_INVPCID: /* fall through */ default: exit_and_crash: diff --git a/xen/include/asm-x86/cpufeature.h b/xen/include/asm-x86/cpufeature.h index c98b7569bf..e24d5244b4 100644 --- a/xen/include/asm-x86/cpufeature.h +++ b/xen/include/asm-x86/cpufeature.h @@ -224,6 +224,8 @@ #define cpu_has_x2apic boot_cpu_has(X86_FEATURE_X2APIC) +#define cpu_has_pcid boot_cpu_has(X86_FEATURE_PCID) + #define cpu_has_xsave boot_cpu_has(X86_FEATURE_XSAVE) #define cpu_has_avx boot_cpu_has(X86_FEATURE_AVX) #define cpu_has_lwp boot_cpu_has(X86_FEATURE_LWP) diff --git a/xen/include/asm-x86/hvm/hvm.h b/xen/include/asm-x86/hvm/hvm.h index 07458afd32..5373dab51e 100644 --- a/xen/include/asm-x86/hvm/hvm.h +++ b/xen/include/asm-x86/hvm/hvm.h @@ -212,6 +212,8 @@ int hvm_girq_dest_2_vcpu_id(struct domain *d, uint8_t dest, uint8_t dest_mode); (!!((v)->arch.hvm_vcpu.guest_cr[0] & X86_CR0_PG)) #define hvm_wp_enabled(v) \ (!!((v)->arch.hvm_vcpu.guest_cr[0] & X86_CR0_WP)) +#define hvm_pcid_enabled(v) \ + (!!((v)->arch.hvm_vcpu.guest_cr[4] & X86_CR4_PCIDE)) #define hvm_pae_enabled(v) \ (hvm_paging_enabled(v) && ((v)->arch.hvm_vcpu.guest_cr[4] & X86_CR4_PAE)) #define hvm_smep_enabled(v) \ @@ -334,6 +336,7 @@ static inline int hvm_do_pmu_interrupt(struct cpu_user_regs *regs) (cpu_has_fsgsbase ? X86_CR4_FSGSBASE : 0) | \ ((nestedhvm_enabled((_v)->domain) && cpu_has_vmx)\ ? X86_CR4_VMXE : 0) | \ + (cpu_has_pcid ? X86_CR4_PCIDE : 0) | \ (xsave_enabled(_v) ? X86_CR4_OSXSAVE : 0)))) /* These exceptions must always be intercepted. */ diff --git a/xen/include/asm-x86/hvm/vmx/vmcs.h b/xen/include/asm-x86/hvm/vmx/vmcs.h index acd7765348..6d58c37ba9 100644 --- a/xen/include/asm-x86/hvm/vmx/vmcs.h +++ b/xen/include/asm-x86/hvm/vmx/vmcs.h @@ -184,6 +184,7 @@ extern u32 vmx_vmentry_control; #define SECONDARY_EXEC_WBINVD_EXITING 0x00000040 #define SECONDARY_EXEC_UNRESTRICTED_GUEST 0x00000080 #define SECONDARY_EXEC_PAUSE_LOOP_EXITING 0x00000400 +#define SECONDARY_EXEC_ENABLE_INVPCID 0x00001000 extern u32 vmx_secondary_exec_control; extern bool_t cpu_has_vmx_ins_outs_instr_info; diff --git a/xen/include/asm-x86/hvm/vmx/vmx.h b/xen/include/asm-x86/hvm/vmx/vmx.h index 03cb7d97b5..f003f84be1 100644 --- a/xen/include/asm-x86/hvm/vmx/vmx.h +++ b/xen/include/asm-x86/hvm/vmx/vmx.h @@ -129,6 +129,7 @@ void vmx_update_cpu_exec_control(struct vcpu *v); #define EXIT_REASON_INVVPID 53 #define EXIT_REASON_WBINVD 54 #define EXIT_REASON_XSETBV 55 +#define EXIT_REASON_INVPCID 58 /* * Interruption-information format diff --git a/xen/include/asm-x86/processor.h b/xen/include/asm-x86/processor.h index 5a4a5c4b47..cf10ad58db 100644 --- a/xen/include/asm-x86/processor.h +++ b/xen/include/asm-x86/processor.h @@ -84,6 +84,7 @@ #define X86_CR4_VMXE 0x2000 /* enable VMX */ #define X86_CR4_SMXE 0x4000 /* enable SMX */ #define X86_CR4_FSGSBASE 0x10000 /* enable {rd,wr}{fs,gs}base */ +#define X86_CR4_PCIDE 0x20000 /* enable PCID */ #define X86_CR4_OSXSAVE 0x40000 /* enable XSAVE/XRSTOR */ #define X86_CR4_SMEP 0x100000/* enable SMEP */