diff --git a/xen/arch/x86/cpu/amd.c b/xen/arch/x86/cpu/amd.c index 784fa40c1d..2317546999 100644 --- a/xen/arch/x86/cpu/amd.c +++ b/xen/arch/x86/cpu/amd.c @@ -211,6 +211,24 @@ static void amd_ctxt_switch_levelling(const struct vcpu *next) (nextd && is_pv_domain(nextd) && nextd->arch.pv_domain.cpuidmasks) ? nextd->arch.pv_domain.cpuidmasks : &cpuidmask_defaults; + if ((levelling_caps & LCAP_1cd) == LCAP_1cd) { + uint64_t val = masks->_1cd; + + /* + * OSXSAVE defaults to 1, which causes fast-forwarding of + * Xen's real setting. Clobber it if disabled by the guest + * kernel. + */ + if (next && is_pv_vcpu(next) && !is_idle_vcpu(next) && + !(next->arch.pv_vcpu.ctrlreg[4] & X86_CR4_OSXSAVE)) + val &= ~((uint64_t)cpufeat_mask(X86_FEATURE_OSXSAVE) << 32); + + if (unlikely(these_masks->_1cd != val)) { + wrmsr_amd(MSR_K8_FEATURE_MASK, val); + these_masks->_1cd = val; + } + } + #define LAZY(cap, msr, field) \ ({ \ if (unlikely(these_masks->field != masks->field) && \ @@ -221,7 +239,6 @@ static void amd_ctxt_switch_levelling(const struct vcpu *next) } \ }) - LAZY(LCAP_1cd, MSR_K8_FEATURE_MASK, _1cd); LAZY(LCAP_e1cd, MSR_K8_EXT_FEATURE_MASK, e1cd); LAZY(LCAP_7ab0, MSR_AMD_L7S0_FEATURE_MASK, _7ab0); LAZY(LCAP_6c, MSR_AMD_THRM_FEATURE_MASK, _6c); diff --git a/xen/arch/x86/cpu/intel.c b/xen/arch/x86/cpu/intel.c index 3491638931..a9355cbfa1 100644 --- a/xen/arch/x86/cpu/intel.c +++ b/xen/arch/x86/cpu/intel.c @@ -182,6 +182,24 @@ static void intel_ctxt_switch_levelling(const struct vcpu *next) masks = (nextd && is_pv_domain(nextd) && nextd->arch.pv_domain.cpuidmasks) ? nextd->arch.pv_domain.cpuidmasks : &cpuidmask_defaults; + if (msr_basic) { + uint64_t val = masks->_1cd; + + /* + * OSXSAVE defaults to 1, which causes fast-forwarding of + * Xen's real setting. Clobber it if disabled by the guest + * kernel. + */ + if (next && is_pv_vcpu(next) && !is_idle_vcpu(next) && + !(next->arch.pv_vcpu.ctrlreg[4] & X86_CR4_OSXSAVE)) + val &= ~cpufeat_mask(X86_FEATURE_OSXSAVE); + + if (unlikely(these_masks->_1cd != val)) { + wrmsrl(msr_basic, val); + these_masks->_1cd = val; + } + } + #define LAZY(msr, field) \ ({ \ if (unlikely(these_masks->field != masks->field) && \ @@ -192,7 +210,6 @@ static void intel_ctxt_switch_levelling(const struct vcpu *next) } \ }) - LAZY(msr_basic, _1cd); LAZY(msr_ext, e1cd); LAZY(msr_xsave, Da1); @@ -218,6 +235,11 @@ static void __init noinline intel_init_levelling(void) ecx &= opt_cpuid_mask_ecx; edx &= opt_cpuid_mask_edx; + /* Fast-forward bits - Must be set. */ + if (ecx & cpufeat_mask(X86_FEATURE_XSAVE)) + ecx |= cpufeat_mask(X86_FEATURE_OSXSAVE); + edx |= cpufeat_mask(X86_FEATURE_APIC); + cpuidmask_defaults._1cd &= ((u64)edx << 32) | ecx; } diff --git a/xen/arch/x86/domctl.c b/xen/arch/x86/domctl.c index bed70aad66..a904fd6130 100644 --- a/xen/arch/x86/domctl.c +++ b/xen/arch/x86/domctl.c @@ -110,10 +110,18 @@ static void update_domain_cpuid_info(struct domain *d, case X86_VENDOR_INTEL: /* * Intel masking MSRs are documented as AND masks. - * Experimentally, they are applied before OSXSAVE and APIC + * Experimentally, they are applied after OSXSAVE and APIC * are fast-forwarded from real hardware state. */ mask &= ((uint64_t)edx << 32) | ecx; + + if ( ecx & cpufeat_mask(X86_FEATURE_XSAVE) ) + ecx = cpufeat_mask(X86_FEATURE_OSXSAVE); + else + ecx = 0; + edx = cpufeat_mask(X86_FEATURE_APIC); + + mask |= ((uint64_t)edx << 32) | ecx; break; case X86_VENDOR_AMD: diff --git a/xen/arch/x86/traps.c b/xen/arch/x86/traps.c index ce924d8a5d..bab374dd36 100644 --- a/xen/arch/x86/traps.c +++ b/xen/arch/x86/traps.c @@ -2737,6 +2737,7 @@ static int emulate_privileged_op(struct cpu_user_regs *regs) case 4: /* Write CR4 */ v->arch.pv_vcpu.ctrlreg[4] = pv_guest_cr4_fixup(v, *reg); write_cr4(pv_guest_cr4_to_real_cr4(v)); + ctxt_switch_levelling(v); break; default: