From: Andrew Cooper Date: Wed, 4 Jan 2017 15:00:23 +0000 (+0000) Subject: x86/cpuid: Introduce recalculate_xstate() X-Git-Tag: archive/raspbian/4.11.1-1+rpi1~1^2~66^2~2965 X-Git-Url: https://dgit.raspbian.org/?a=commitdiff_plain;h=af109224109abb9648ea9720505daeeb06f76e4b;p=xen.git x86/cpuid: Introduce recalculate_xstate() All data in the xstate union, other than the Da1 feature word, is derived from other state; either feature bits from other words, or layout information which has already been collected by Xen's xstate driver. Recalculate the xstate information for each policy object when the feature bits may have changed. Signed-off-by: Andrew Cooper Reviewed-by: Jan Beulich --- diff --git a/xen/arch/x86/cpuid.c b/xen/arch/x86/cpuid.c index bcdac03dca..619ead8795 100644 --- a/xen/arch/x86/cpuid.c +++ b/xen/arch/x86/cpuid.c @@ -80,6 +80,88 @@ static void sanitise_featureset(uint32_t *fs) (fs[FEATURESET_e1d] & ~CPUID_COMMON_1D_FEATURES)); } +static void recalculate_xstate(struct cpuid_policy *p) +{ + uint64_t xstates = XSTATE_FP_SSE; + uint32_t xstate_size = XSTATE_AREA_MIN_SIZE; + unsigned int i, Da1 = p->xstate.Da1; + + /* + * The Da1 leaf is the only piece of information preserved in the common + * case. Everything else is derived from other feature state. + */ + memset(&p->xstate, 0, sizeof(p->xstate)); + + if ( !p->basic.xsave ) + return; + + if ( p->basic.avx ) + { + xstates |= XSTATE_YMM; + xstate_size = max(xstate_size, + xstate_offsets[_XSTATE_YMM] + + xstate_sizes[_XSTATE_YMM]); + } + + if ( p->feat.mpx ) + { + xstates |= XSTATE_BNDREGS | XSTATE_BNDCSR; + xstate_size = max(xstate_size, + xstate_offsets[_XSTATE_BNDCSR] + + xstate_sizes[_XSTATE_BNDCSR]); + } + + if ( p->feat.avx512f ) + { + xstates |= XSTATE_OPMASK | XSTATE_ZMM | XSTATE_HI_ZMM; + xstate_size = max(xstate_size, + xstate_offsets[_XSTATE_HI_ZMM] + + xstate_sizes[_XSTATE_HI_ZMM]); + } + + if ( p->feat.pku ) + { + xstates |= XSTATE_PKRU; + xstate_size = max(xstate_size, + xstate_offsets[_XSTATE_PKRU] + + xstate_sizes[_XSTATE_PKRU]); + } + + if ( p->extd.lwp ) + { + xstates |= XSTATE_LWP; + xstate_size = max(xstate_size, + xstate_offsets[_XSTATE_LWP] + + xstate_sizes[_XSTATE_LWP]); + } + + p->xstate.max_size = xstate_size; + p->xstate.xcr0_low = xstates & ~XSTATE_XSAVES_ONLY; + p->xstate.xcr0_high = (xstates & ~XSTATE_XSAVES_ONLY) >> 32; + + p->xstate.Da1 = Da1; + if ( p->xstate.xsaves ) + { + p->xstate.xss_low = xstates & XSTATE_XSAVES_ONLY; + p->xstate.xss_high = (xstates & XSTATE_XSAVES_ONLY) >> 32; + } + else + xstates &= ~XSTATE_XSAVES_ONLY; + + for ( i = 2; i < min(63ul, ARRAY_SIZE(p->xstate.comp)); ++i ) + { + uint64_t curr_xstate = 1ul << i; + + if ( !(xstates & curr_xstate) ) + continue; + + p->xstate.comp[i].size = xstate_sizes[i]; + p->xstate.comp[i].offset = xstate_offsets[i]; + p->xstate.comp[i].xss = curr_xstate & XSTATE_XSAVES_ONLY; + p->xstate.comp[i].align = curr_xstate & xstate_align; + } +} + static void __init calculate_raw_policy(void) { struct cpuid_policy *p = &raw_policy; @@ -149,6 +231,7 @@ static void __init calculate_host_policy(void) 0x80000000u + ARRAY_SIZE(p->extd.raw) - 1); cpuid_featureset_to_policy(boot_cpu_data.x86_capability, p); + recalculate_xstate(p); } static void __init calculate_pv_max_policy(void) @@ -168,6 +251,7 @@ static void __init calculate_pv_max_policy(void) sanitise_featureset(pv_featureset); cpuid_featureset_to_policy(pv_featureset, p); + recalculate_xstate(p); } static void __init calculate_hvm_max_policy(void) @@ -221,6 +305,7 @@ static void __init calculate_hvm_max_policy(void) sanitise_featureset(hvm_featureset); cpuid_featureset_to_policy(hvm_featureset, p); + recalculate_xstate(p); } void __init init_guest_cpuid(void) @@ -328,6 +413,7 @@ void recalculate_cpuid_policy(struct domain *d) special_features[FEATURESET_7b0]); cpuid_featureset_to_policy(fs, p); + recalculate_xstate(p); } int init_domain_cpuid_policy(struct domain *d) diff --git a/xen/include/asm-x86/cpuid.h b/xen/include/asm-x86/cpuid.h index 24ad3e0b86..e5140cac71 100644 --- a/xen/include/asm-x86/cpuid.h +++ b/xen/include/asm-x86/cpuid.h @@ -77,18 +77,15 @@ struct cpuid_policy * * Global *_policy objects: * - * - Host accurate: - * - {xcr0,xss}_{high,low} - * * - Guest accurate: - * - All of the feat union + * - All of the feat and xstate unions * - max_{,sub}leaf * - All FEATURESET_* words * * Per-domain objects: * * - Guest accurate: - * - All of the feat union + * - All of the feat and xstate unions * - max_{,sub}leaf * - All FEATURESET_* words * @@ -143,9 +140,10 @@ struct cpuid_policy /* Xstate feature leaf: 0x0000000D[xx] */ union { struct cpuid_leaf raw[CPUID_GUEST_NR_XSTATE]; + struct { /* Subleaf 0. */ - uint32_t xcr0_low, /* b */:32, /* c */:32, xcr0_high; + uint32_t xcr0_low, /* b */:32, max_size, xcr0_high; /* Subleaf 1. */ union { @@ -154,6 +152,13 @@ struct cpuid_policy }; uint32_t /* b */:32, xss_low, xss_high; }; + + /* Per-component common state. Valid for i >= 2. */ + struct { + uint32_t size, offset; + bool xss:1, align:1; + uint32_t _res_d; + } comp[CPUID_GUEST_NR_XSTATE]; } xstate; /* Extended leaves: 0x800000xx */