target-i386: fix confusion in xcr0 bit position vs. mask

The xsave and xrstor helpers are accessing the x86_ext_save_areas array
using a bit mask instead of a bit position. Provide two sets of XSTATE_*
definitions and use XSTATE_*_BIT when a bit position is requested.

Backports commit cfc3b074de4b4ccee2540edbf8cfdb026dc19943 from qemu
This commit is contained in:
Paolo Bonzini 2018-02-20 20:59:22 -05:00 committed by Lioncash
parent 26951bf754
commit abb0408274
No known key found for this signature in database
GPG key ID: 4E3C3CC1031BA9C7
4 changed files with 35 additions and 34 deletions

View file

@ -2418,7 +2418,7 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
*ecx = MAX(*ecx, esa->offset + esa->size); *ecx = MAX(*ecx, esa->offset + esa->size);
} }
} }
*eax |= ena_mask & (XSTATE_FP | XSTATE_SSE); *eax |= ena_mask & (XSTATE_FP_MASK | XSTATE_SSE_MASK);
*ebx = *ecx; *ebx = *ecx;
} else if (count == 1) { } else if (count == 1) {
*eax = env->features[FEAT_XSAVE]; *eax = env->features[FEAT_XSAVE];
@ -2652,15 +2652,15 @@ static void x86_cpu_reset(CPUState *s)
cpu_watchpoint_remove_all(s, BP_CPU); cpu_watchpoint_remove_all(s, BP_CPU);
cr4 = 0; cr4 = 0;
xcr0 = XSTATE_FP; xcr0 = XSTATE_FP_MASK;
#ifdef CONFIG_USER_ONLY #ifdef CONFIG_USER_ONLY
/* Enable all the features for user-mode. */ /* Enable all the features for user-mode. */
if (env->features[FEAT_1_EDX] & CPUID_SSE) { if (env->features[FEAT_1_EDX] & CPUID_SSE) {
xcr0 |= XSTATE_SSE; xcr0 |= XSTATE_SSE_MASK;
} }
if (env->features[FEAT_7_0_EBX] & CPUID_7_0_EBX_MPX) { if (env->features[FEAT_7_0_EBX] & CPUID_7_0_EBX_MPX) {
xcr0 |= XSTATE_BNDREGS | XSTATE_BNDCSR; xcr0 |= XSTATE_BNDREGS_MASK | XSTATE_BNDCSR_MASK;
} }
if (env->features[FEAT_1_ECX] & CPUID_EXT_XSAVE) { if (env->features[FEAT_1_ECX] & CPUID_EXT_XSAVE) {
cr4 |= CR4_OSFXSR_MASK | CR4_OSXSAVE_MASK; cr4 |= CR4_OSFXSR_MASK | CR4_OSXSAVE_MASK;

View file

@ -412,15 +412,15 @@
#define XSTATE_Hi16_ZMM_BIT 7 #define XSTATE_Hi16_ZMM_BIT 7
#define XSTATE_PKRU_BIT 9 #define XSTATE_PKRU_BIT 9
#define XSTATE_FP (1ULL << 0) #define XSTATE_FP_MASK (1ULL << XSTATE_FP_BIT)
#define XSTATE_SSE (1ULL << 1) #define XSTATE_SSE_MASK (1ULL << XSTATE_SSE_BIT)
#define XSTATE_YMM (1ULL << 2) #define XSTATE_YMM_MASK (1ULL << XSTATE_YMM_BIT)
#define XSTATE_BNDREGS (1ULL << 3) #define XSTATE_BNDREGS_MASK (1ULL << XSTATE_BNDREGS_BIT)
#define XSTATE_BNDCSR (1ULL << 4) #define XSTATE_BNDCSR_MASK (1ULL << XSTATE_BNDCSR_BIT)
#define XSTATE_OPMASK (1ULL << 5) #define XSTATE_OPMASK_MASK (1ULL << XSTATE_OPMASK_BIT)
#define XSTATE_ZMM_Hi256 (1ULL << 6) #define XSTATE_ZMM_Hi256_MASK (1ULL << XSTATE_ZMM_Hi256_BIT)
#define XSTATE_Hi16_ZMM (1ULL << 7) #define XSTATE_Hi16_ZMM_MASK (1ULL << XSTATE_Hi16_ZMM_BIT)
#define XSTATE_PKRU (1ULL << 9) #define XSTATE_PKRU_MASK (1ULL << XSTATE_PKRU_BIT)
/* CPUID feature words */ /* CPUID feature words */

View file

@ -1244,7 +1244,7 @@ static uint64_t get_xinuse(CPUX86State *env)
indicate in use. That said, the state of BNDREGS is important indicate in use. That said, the state of BNDREGS is important
enough to track in HFLAGS, so we might as well use that here. */ enough to track in HFLAGS, so we might as well use that here. */
if ((env->hflags & HF_MPX_IU_MASK) == 0) { if ((env->hflags & HF_MPX_IU_MASK) == 0) {
inuse &= ~XSTATE_BNDREGS; inuse &= ~XSTATE_BNDREGS_MASK;
} }
return inuse; return inuse;
} }
@ -1268,22 +1268,22 @@ static void do_xsave(CPUX86State *env, target_ulong ptr, uint64_t rfbm,
rfbm &= env->xcr0; rfbm &= env->xcr0;
opt &= rfbm; opt &= rfbm;
if (opt & XSTATE_FP) { if (opt & XSTATE_FP_MASK) {
do_xsave_fpu(env, ptr, ra); do_xsave_fpu(env, ptr, ra);
} }
if (rfbm & XSTATE_SSE) { if (rfbm & XSTATE_SSE_MASK) {
/* Note that saving MXCSR is not suppressed by XSAVEOPT. */ /* Note that saving MXCSR is not suppressed by XSAVEOPT. */
do_xsave_mxcsr(env, ptr, ra); do_xsave_mxcsr(env, ptr, ra);
} }
if (opt & XSTATE_SSE) { if (opt & XSTATE_SSE_MASK) {
do_xsave_sse(env, ptr, ra); do_xsave_sse(env, ptr, ra);
} }
if (opt & XSTATE_BNDREGS) { if (opt & XSTATE_BNDREGS_MASK) {
target_ulong off = x86_ext_save_areas[XSTATE_BNDREGS].offset; target_ulong off = x86_ext_save_areas[XSTATE_BNDREGS_BIT].offset;
do_xsave_bndregs(env, ptr + off, ra); do_xsave_bndregs(env, ptr + off, ra);
} }
if (opt & XSTATE_BNDCSR) { if (opt & XSTATE_BNDCSR_MASK) {
target_ulong off = x86_ext_save_areas[XSTATE_BNDCSR].offset; target_ulong off = x86_ext_save_areas[XSTATE_BNDCSR_BIT].offset;
do_xsave_bndcsr(env, ptr + off, ra); do_xsave_bndcsr(env, ptr + off, ra);
} }
@ -1428,19 +1428,19 @@ void helper_xrstor(CPUX86State *env, target_ulong ptr, uint64_t rfbm)
raise_exception_ra(env, EXCP0D_GPF, ra); raise_exception_ra(env, EXCP0D_GPF, ra);
} }
if (rfbm & XSTATE_FP) { if (rfbm & XSTATE_FP_MASK) {
if (xstate_bv & XSTATE_FP) { if (xstate_bv & XSTATE_FP_MASK) {
do_xrstor_fpu(env, ptr, ra); do_xrstor_fpu(env, ptr, ra);
} else { } else {
helper_fninit(env); helper_fninit(env);
memset(env->fpregs, 0, sizeof(env->fpregs)); memset(env->fpregs, 0, sizeof(env->fpregs));
} }
} }
if (rfbm & XSTATE_SSE) { if (rfbm & XSTATE_SSE_MASK) {
/* Note that the standard form of XRSTOR loads MXCSR from memory /* Note that the standard form of XRSTOR loads MXCSR from memory
whether or not the XSTATE_BV bit is set. */ whether or not the XSTATE_BV bit is set. */
do_xrstor_mxcsr(env, ptr, ra); do_xrstor_mxcsr(env, ptr, ra);
if (xstate_bv & XSTATE_SSE) { if (xstate_bv & XSTATE_SSE_MASK) {
do_xrstor_sse(env, ptr, ra); do_xrstor_sse(env, ptr, ra);
} else { } else {
/* ??? When AVX is implemented, we may have to be more /* ??? When AVX is implemented, we may have to be more
@ -1448,9 +1448,9 @@ void helper_xrstor(CPUX86State *env, target_ulong ptr, uint64_t rfbm)
memset(env->xmm_regs, 0, sizeof(env->xmm_regs)); memset(env->xmm_regs, 0, sizeof(env->xmm_regs));
} }
} }
if (rfbm & XSTATE_BNDREGS) { if (rfbm & XSTATE_BNDREGS_MASK) {
if (xstate_bv & XSTATE_BNDREGS) { if (xstate_bv & XSTATE_BNDREGS_MASK) {
target_ulong off = x86_ext_save_areas[XSTATE_BNDREGS].offset; target_ulong off = x86_ext_save_areas[XSTATE_BNDREGS_BIT].offset;
do_xrstor_bndregs(env, ptr + off, ra); do_xrstor_bndregs(env, ptr + off, ra);
env->hflags |= HF_MPX_IU_MASK; env->hflags |= HF_MPX_IU_MASK;
} else { } else {
@ -1458,9 +1458,9 @@ void helper_xrstor(CPUX86State *env, target_ulong ptr, uint64_t rfbm)
env->hflags &= ~HF_MPX_IU_MASK; env->hflags &= ~HF_MPX_IU_MASK;
} }
} }
if (rfbm & XSTATE_BNDCSR) { if (rfbm & XSTATE_BNDCSR_MASK) {
if (xstate_bv & XSTATE_BNDCSR) { if (xstate_bv & XSTATE_BNDCSR_MASK) {
target_ulong off = x86_ext_save_areas[XSTATE_BNDCSR].offset; target_ulong off = x86_ext_save_areas[XSTATE_BNDCSR_BIT].offset;
do_xrstor_bndcsr(env, ptr + off, ra); do_xrstor_bndcsr(env, ptr + off, ra);
} else { } else {
memset(&env->bndcs_regs, 0, sizeof(env->bndcs_regs)); memset(&env->bndcs_regs, 0, sizeof(env->bndcs_regs));
@ -1499,7 +1499,7 @@ void helper_xsetbv(CPUX86State *env, uint32_t ecx, uint64_t mask)
} }
/* Only XCR0 is defined at present; the FPU may not be disabled. */ /* Only XCR0 is defined at present; the FPU may not be disabled. */
if (ecx != 0 || (mask & XSTATE_FP) == 0) { if (ecx != 0 || (mask & XSTATE_FP_MASK) == 0) {
goto do_gpf; goto do_gpf;
} }
@ -1511,7 +1511,8 @@ void helper_xsetbv(CPUX86State *env, uint32_t ecx, uint64_t mask)
} }
/* Disallow enabling only half of MPX. */ /* Disallow enabling only half of MPX. */
if ((mask ^ (mask * (XSTATE_BNDCSR / XSTATE_BNDREGS))) & XSTATE_BNDCSR) { if ((mask ^ (mask * (XSTATE_BNDCSR_MASK / XSTATE_BNDREGS_MASK)))
& XSTATE_BNDCSR_MASK) {
goto do_gpf; goto do_gpf;
} }

View file

@ -35,7 +35,7 @@ void cpu_sync_bndcs_hflags(CPUX86State *env)
} }
if ((env->cr[4] & CR4_OSXSAVE_MASK) if ((env->cr[4] & CR4_OSXSAVE_MASK)
&& (env->xcr0 & XSTATE_BNDCSR) && (env->xcr0 & XSTATE_BNDCSR_MASK)
&& (bndcsr & BNDCFG_ENABLE)) { && (bndcsr & BNDCFG_ENABLE)) {
hflags |= HF_MPX_EN_MASK; hflags |= HF_MPX_EN_MASK;
} else { } else {