Note that this does not (yet?) enable use of the respective processor extensions by guests (needs white listing of the respective CPUID bits and dealing with IA32_BNDCFGS via the respective VM exit/entry controls [MPX can probably be enabled for HVM guests only anyway] and handling its save/restore). --- a/xen/arch/x86/xstate.c +++ b/xen/arch/x86/xstate.c @@ -253,7 +253,7 @@ void xstate_free_save_area(struct vcpu * /* Collect the information of processor's extended state */ void xstate_init(bool_t bsp) { - u32 eax, ebx, ecx, edx, min_size; + u32 eax, ebx, ecx, edx; u64 feature_mask; if ( boot_cpu_data.cpuid_level < XSTATE_CPUID ) @@ -269,12 +269,6 @@ void xstate_init(bool_t bsp) BUG_ON((eax & XSTATE_YMM) && !(eax & XSTATE_SSE)); feature_mask = (((u64)edx << 32) | eax) & XCNTXT_MASK; - /* FP/SSE, XSAVE.HEADER, YMM */ - min_size = XSTATE_AREA_MIN_SIZE; - if ( eax & XSTATE_YMM ) - min_size += XSTATE_YMM_SIZE; - BUG_ON(ecx < min_size); - /* * Set CR4_OSXSAVE and run "cpuid" to get xsave_cntxt_size. */ @@ -327,14 +321,33 @@ unsigned int xstate_ctxt_size(u64 xcr0) return ebx; } +static bool_t valid_xcr0(u64 xcr0) +{ + if ( !(xcr0 & XSTATE_FP) ) + return 0; + + if ( (xcr0 & XSTATE_YMM) && !(xcr0 & XSTATE_SSE) ) + return 0; + + if ( xcr0 & (XSTATE_OPMASK | XSTATE_ZMM | XSTATE_HI_ZMM) ) + { + if ( !(xcr0 & XSTATE_YMM) ) + return 0; + + if ( ~xcr0 & (XSTATE_OPMASK | XSTATE_ZMM | XSTATE_HI_ZMM) ) + return 0; + } + + return !(xcr0 & XSTATE_BNDREGS) == !(xcr0 & XSTATE_BNDCSR); +} + int validate_xstate(u64 xcr0, u64 xcr0_accum, u64 xstate_bv, u64 xfeat_mask) { if ( (xcr0_accum & ~xfeat_mask) || (xstate_bv & ~xcr0_accum) || (xcr0 & ~xcr0_accum) || - !(xcr0 & XSTATE_FP) || - ((xcr0 & XSTATE_YMM) && !(xcr0 & XSTATE_SSE)) || - ((xcr0_accum & XSTATE_YMM) && !(xcr0_accum & XSTATE_SSE)) ) + !valid_xcr0(xcr0) || + !valid_xcr0(xcr0_accum) ) return -EINVAL; if ( xcr0_accum & ~xfeature_mask ) @@ -351,10 +364,7 @@ int handle_xsetbv(u32 index, u64 new_bv) if ( index != XCR_XFEATURE_ENABLED_MASK ) return -EOPNOTSUPP; - if ( (new_bv & ~xfeature_mask) || !(new_bv & XSTATE_FP) ) - return -EINVAL; - - if ( (new_bv & XSTATE_YMM) && !(new_bv & XSTATE_SSE) ) + if ( (new_bv & ~xfeature_mask) || !valid_xcr0(new_bv) ) return -EINVAL; if ( !set_xcr0(new_bv) ) --- a/xen/include/asm-x86/xstate.h +++ b/xen/include/asm-x86/xstate.h @@ -20,18 +20,23 @@ #define XCR_XFEATURE_ENABLED_MASK 0x00000000 /* index of XCR0 */ #define XSTATE_YMM_SIZE 256 -#define XSTATE_YMM_OFFSET XSAVE_AREA_MIN_SIZE #define XSTATE_AREA_MIN_SIZE (512 + 64) /* FP/SSE + XSAVE.HEADER */ #define XSTATE_FP (1ULL << 0) #define XSTATE_SSE (1ULL << 1) #define XSTATE_YMM (1ULL << 2) +#define XSTATE_BNDREGS (1ULL << 3) +#define XSTATE_BNDCSR (1ULL << 4) +#define XSTATE_OPMASK (1ULL << 5) +#define XSTATE_ZMM (1ULL << 6) +#define XSTATE_HI_ZMM (1ULL << 7) #define XSTATE_LWP (1ULL << 62) /* AMD lightweight profiling */ #define XSTATE_FP_SSE (XSTATE_FP | XSTATE_SSE) -#define XCNTXT_MASK (XSTATE_FP | XSTATE_SSE | XSTATE_YMM | XSTATE_LWP) +#define XCNTXT_MASK (XSTATE_FP | XSTATE_SSE | XSTATE_YMM | XSTATE_OPMASK | \ + XSTATE_ZMM | XSTATE_HI_ZMM | XSTATE_NONLAZY) -#define XSTATE_ALL (~0) -#define XSTATE_NONLAZY (XSTATE_LWP) +#define XSTATE_ALL (~(1ULL << 63)) +#define XSTATE_NONLAZY (XSTATE_LWP | XSTATE_BNDREGS | XSTATE_BNDCSR) #define XSTATE_LAZY (XSTATE_ALL & ~XSTATE_NONLAZY) extern u64 xfeature_mask;