[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [PATCH 3/6] x86/cpuid: Move all xstate leaf handling into guest_cpuid()
The xstate union now contains sanitised values, so it can be handled fully in the non-legacy path. c/s 1c0bc709d "x86/cpuid: Perform max_leaf calculations in guest_cpuid()" accidentally introduced a boundary error for the subleaf check, although it was masked by the correct logic in the legacy path. Two dynamic adjustments need making, but a TODO and BUILD_BUG_ON() are left to cover a latent bug which will present itself when Xen starts supporting XSS states for guests. Signed-off-by: Andrew Cooper <andrew.cooper3@xxxxxxxxxx> --- CC: Jan Beulich <JBeulich@xxxxxxxx> --- xen/arch/x86/cpuid.c | 179 +++++++--------------------------------- xen/arch/x86/domctl.c | 4 +- xen/include/asm-x86/processor.h | 10 +++ 3 files changed, 45 insertions(+), 148 deletions(-) diff --git a/xen/arch/x86/cpuid.c b/xen/arch/x86/cpuid.c index 303568d..9f16502 100644 --- a/xen/arch/x86/cpuid.c +++ b/xen/arch/x86/cpuid.c @@ -484,8 +484,6 @@ static void pv_cpuid(uint32_t leaf, uint32_t subleaf, struct cpuid_leaf *res) switch ( leaf ) { - uint32_t tmp; - case 0x00000001: res->c = p->basic._1c; res->d = p->basic._1d; @@ -637,57 +635,6 @@ static void pv_cpuid(uint32_t leaf, uint32_t subleaf, struct cpuid_leaf *res) res->a = (res->a & ~0xff) | 3; break; - case XSTATE_CPUID: - if ( !p->basic.xsave || subleaf >= 63 ) - goto unsupported; - switch ( subleaf ) - { - case 0: - { - uint64_t xfeature_mask = XSTATE_FP_SSE; - uint32_t xstate_size = XSTATE_AREA_MIN_SIZE; - - if ( p->basic.avx ) - { - xfeature_mask |= XSTATE_YMM; - xstate_size = (xstate_offsets[_XSTATE_YMM] + - xstate_sizes[_XSTATE_YMM]); - } - - if ( p->feat.avx512f ) - { - xfeature_mask |= XSTATE_OPMASK | XSTATE_ZMM | XSTATE_HI_ZMM; - xstate_size = max(xstate_size, - xstate_offsets[_XSTATE_OPMASK] + - xstate_sizes[_XSTATE_OPMASK]); - xstate_size = max(xstate_size, - xstate_offsets[_XSTATE_ZMM] + - xstate_sizes[_XSTATE_ZMM]); - xstate_size = max(xstate_size, - xstate_offsets[_XSTATE_HI_ZMM] + - xstate_sizes[_XSTATE_HI_ZMM]); - } - - res->a = xfeature_mask; - res->d = xfeature_mask >> 32; - res->c = xstate_size; - - /* - * Always read CPUID.0xD[ECX=0].EBX from hardware, rather than - * domain policy. It varies with enabled xstate, and the correct - * xcr0 is in context. - */ - cpuid_count(leaf, subleaf, &tmp, &res->b, &tmp, &tmp); - break; - } - - case 1: - res->a = p->xstate.Da1; - res->b = res->c = res->d = 0; - break; - } - break; - case 0x80000001: res->c = p->extd.e1c; res->d = p->extd.e1d; @@ -730,6 +677,7 @@ static void pv_cpuid(uint32_t leaf, uint32_t subleaf, struct cpuid_leaf *res) break; case 0x7: + case XSTATE_CPUID: ASSERT_UNREACHABLE(); /* Now handled in guest_cpuid(). */ } @@ -797,98 +745,6 @@ static void hvm_cpuid(uint32_t leaf, uint32_t subleaf, struct cpuid_leaf *res) res->d = v->vcpu_id * 2; break; - case XSTATE_CPUID: - if ( !p->basic.xsave || subleaf >= 63 ) - { - *res = EMPTY_LEAF; - break; - } - switch ( subleaf ) - { - case 0: - { - uint64_t xfeature_mask = XSTATE_FP_SSE; - uint32_t xstate_size = XSTATE_AREA_MIN_SIZE; - - if ( p->basic.avx ) - { - xfeature_mask |= XSTATE_YMM; - xstate_size = max(xstate_size, - xstate_offsets[_XSTATE_YMM] + - xstate_sizes[_XSTATE_YMM]); - } - - if ( p->feat.mpx ) - { - xfeature_mask |= XSTATE_BNDREGS | XSTATE_BNDCSR; - xstate_size = max(xstate_size, - xstate_offsets[_XSTATE_BNDCSR] + - xstate_sizes[_XSTATE_BNDCSR]); - } - - if ( p->feat.avx512f ) - { - xfeature_mask |= XSTATE_OPMASK | XSTATE_ZMM | XSTATE_HI_ZMM; - xstate_size = max(xstate_size, - xstate_offsets[_XSTATE_OPMASK] + - xstate_sizes[_XSTATE_OPMASK]); - xstate_size = max(xstate_size, - xstate_offsets[_XSTATE_ZMM] + - xstate_sizes[_XSTATE_ZMM]); - xstate_size = max(xstate_size, - xstate_offsets[_XSTATE_HI_ZMM] + - xstate_sizes[_XSTATE_HI_ZMM]); - } - - if ( p->feat.pku ) - { - xfeature_mask |= XSTATE_PKRU; - xstate_size = max(xstate_size, - xstate_offsets[_XSTATE_PKRU] + - xstate_sizes[_XSTATE_PKRU]); - } - - if ( p->extd.lwp ) - { - xfeature_mask |= XSTATE_LWP; - xstate_size = max(xstate_size, - xstate_offsets[_XSTATE_LWP] + - xstate_sizes[_XSTATE_LWP]); - } - - res->a = xfeature_mask; - res->d = xfeature_mask >> 32; - res->c = xstate_size; - - /* - * Always read CPUID[0xD,0].EBX from hardware, rather than domain - * policy. It varies with enabled xstate, and the correct xcr0 is - * in context. - */ - cpuid_count(leaf, subleaf, &tmp, &res->b, &tmp, &tmp); - break; - } - - case 1: - res->a = p->xstate.Da1; - - if ( p->xstate.xsaves ) - { - /* - * Always read CPUID[0xD,1].EBX from hardware, rather than - * domain policy. It varies with enabled xstate, and the - * correct xcr0/xss are in context. - */ - cpuid_count(leaf, subleaf, &tmp, &res->b, &tmp, &tmp); - } - else - res->b = 0; - - res->c = res->d = 0; - break; - } - break; - case 0x0000000a: /* Architectural Performance Monitor Features (Intel) */ if ( boot_cpu_data.x86_vendor != X86_VENDOR_INTEL || !vpmu_enabled(v) ) { @@ -970,6 +826,7 @@ static void hvm_cpuid(uint32_t leaf, uint32_t subleaf, struct cpuid_leaf *res) break; case 0x7: + case XSTATE_CPUID: ASSERT_UNREACHABLE(); /* Now handled in guest_cpuid(). */ } @@ -1007,10 +864,13 @@ void guest_cpuid(const struct vcpu *v, uint32_t leaf, break; case XSTATE_CPUID: - if ( subleaf > ARRAY_SIZE(p->xstate.raw) ) + if ( !p->basic.xsave || subleaf >= ARRAY_SIZE(p->xstate.raw) ) return; - /* Fallthrough. */ + BUG_ON(subleaf >= ARRAY_SIZE(p->xstate.raw)); + *res = p->xstate.raw[subleaf]; + break; + default: goto legacy; } @@ -1067,6 +927,31 @@ void guest_cpuid(const struct vcpu *v, uint32_t leaf, break; } break; + + case XSTATE_CPUID: + switch ( subleaf ) + { + case 1: + if ( p->xstate.xsaves ) + { + /* + * TODO: Figure out what to do for XSS state. VT-x manages + * host vs guest MSR_XSS automatically, so as soon as we start + * supporting any XSS states, the wrong XSS will be in + * context. + */ + BUILD_BUG_ON(XSTATE_XSAVES_ONLY != 0); + + /* + * Read CPUID[0xD,0/1].EBX from hardware. They vary with + * enabled XSTATE, and appropraite XCR0|XSS are in context. + */ + case 0: + res->b = cpuid_count_ebx(leaf, subleaf); + } + break; + } + break; } /* Done. */ diff --git a/xen/arch/x86/domctl.c b/xen/arch/x86/domctl.c index 772c5d2..8e8437d 100644 --- a/xen/arch/x86/domctl.c +++ b/xen/arch/x86/domctl.c @@ -105,8 +105,10 @@ static int update_domain_cpuid_info(struct domain *d, if ( ctl->input[0] == 7 && ctl->input[1] >= ARRAY_SIZE(p->feat.raw) ) return 0; + + BUILD_BUG_ON(ARRAY_SIZE(p->xstate.raw) < 2); if ( ctl->input[0] == XSTATE_CPUID && - ctl->input[1] >= ARRAY_SIZE(p->xstate.raw) ) + ctl->input[1] != 1 ) /* Everything else automatically calculated. */ return 0; break; diff --git a/xen/include/asm-x86/processor.h b/xen/include/asm-x86/processor.h index b130f47..54d0a17 100644 --- a/xen/include/asm-x86/processor.h +++ b/xen/include/asm-x86/processor.h @@ -319,6 +319,16 @@ static always_inline unsigned int cpuid_edx(unsigned int op) return edx; } +static always_inline unsigned int cpuid_count_ebx( + unsigned int leaf, unsigned int subleaf) +{ + unsigned int ebx, tmp; + + cpuid_count(leaf, subleaf, &tmp, &ebx, &tmp, &tmp); + + return ebx; +} + static inline unsigned long read_cr0(void) { unsigned long cr0; -- 2.1.4 _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxx https://lists.xen.org/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |