With it, add a new hidden flag that will be used to enable the REX2 prefix
and EVEX map4.
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
target/i386/cpu.h | 3 ++
target/i386/tcg/tcg-cpu.h | 16 +++++++---
target/i386/helper.c | 11 +++++++
target/i386/tcg/fpu_helper.c | 59 +++++++++++++++++++++++++++++++++---
target/i386/tcg/tcg-cpu.c | 5 +--
5 files changed, 83 insertions(+), 11 deletions(-)
diff --git a/target/i386/cpu.h b/target/i386/cpu.h
index da5161fc1a5..7586ea0ed8d 100644
--- a/target/i386/cpu.h
+++ b/target/i386/cpu.h
@@ -186,6 +186,7 @@ typedef enum X86Seg {
#define HF_MPX_IU_SHIFT 26 /* BND registers in-use */
#define HF_UMIP_SHIFT 27 /* CR4.UMIP */
#define HF_AVX_EN_SHIFT 28 /* AVX Enabled (CR4+XCR0) */
+#define HF_APX_EN_SHIFT 29 /* APX Enabled (CR4+XCR0) */
#define HF_CPL_MASK (3 << HF_CPL_SHIFT)
#define HF_INHIBIT_IRQ_MASK (1 << HF_INHIBIT_IRQ_SHIFT)
@@ -213,6 +214,7 @@ typedef enum X86Seg {
#define HF_MPX_IU_MASK (1 << HF_MPX_IU_SHIFT)
#define HF_UMIP_MASK (1 << HF_UMIP_SHIFT)
#define HF_AVX_EN_MASK (1 << HF_AVX_EN_SHIFT)
+#define HF_APX_EN_MASK (1 << HF_APX_EN_SHIFT)
/* hflags2 */
@@ -2729,6 +2731,7 @@ static inline bool x86_has_cpuid_0x1f(X86CPU *cpu)
/* helper.c */
void x86_cpu_set_a20(X86CPU *cpu, int a20_state);
void cpu_sync_avx_hflag(CPUX86State *env);
+void cpu_sync_apx_hflag(CPUX86State *env);
typedef enum X86ASIdx {
X86ASIdx_MEM = 0,
diff --git a/target/i386/tcg/tcg-cpu.h b/target/i386/tcg/tcg-cpu.h
index 85bcd61678f..451f61e2043 100644
--- a/target/i386/tcg/tcg-cpu.h
+++ b/target/i386/tcg/tcg-cpu.h
@@ -52,9 +52,15 @@ typedef struct X86XSaveArea {
- sizeof(X86XSaveHeader)
- sizeof(XSaveAVX)];
- /* MPX State: */
- XSaveBNDREG bndreg_state;
- XSaveBNDCSR bndcsr_state;
+ /* Overlapping MPX and APX States: */
+ union {
+ struct {
+ XSaveBNDREG bndreg;
+ XSaveBNDCSR bndcsr;
+ } mpx_state;
+ XSaveAPX apx_state;
+ };
+
/* AVX-512 State: */
XSaveOpmask opmask_state;
XSaveZMM_Hi256 zmm_hi256_state;
@@ -71,8 +77,8 @@ QEMU_BUILD_BUG_ON(offsetof(X86XSaveArea, legacy.mxcsr) != XSAVE_MXCSR_OFFSET);
QEMU_BUILD_BUG_ON(offsetof(X86XSaveArea, legacy.fpregs) != XSAVE_ST_SPACE_OFFSET);
QEMU_BUILD_BUG_ON(offsetof(X86XSaveArea, legacy.xmm_regs) != XSAVE_XMM_SPACE_OFFSET);
QEMU_BUILD_BUG_ON(offsetof(X86XSaveArea, avx_state) != XSAVE_AVX_OFFSET);
-QEMU_BUILD_BUG_ON(offsetof(X86XSaveArea, bndreg_state) != XSAVE_BNDREG_OFFSET);
-QEMU_BUILD_BUG_ON(offsetof(X86XSaveArea, bndcsr_state) != XSAVE_BNDCSR_OFFSET);
+QEMU_BUILD_BUG_ON(offsetof(X86XSaveArea, mpx_state.bndreg) != XSAVE_BNDREG_OFFSET);
+QEMU_BUILD_BUG_ON(offsetof(X86XSaveArea, mpx_state.bndcsr) != XSAVE_BNDCSR_OFFSET);
QEMU_BUILD_BUG_ON(offsetof(X86XSaveArea, opmask_state) != XSAVE_OPMASK_OFFSET);
QEMU_BUILD_BUG_ON(offsetof(X86XSaveArea, zmm_hi256_state) != XSAVE_ZMM_HI256_OFFSET);
QEMU_BUILD_BUG_ON(offsetof(X86XSaveArea, hi16_zmm_state) != XSAVE_HI16_ZMM_OFFSET);
diff --git a/target/i386/helper.c b/target/i386/helper.c
index f9f9488eb4d..d01b12f8af7 100644
--- a/target/i386/helper.c
+++ b/target/i386/helper.c
@@ -35,6 +35,16 @@
#include "tcg/insn-start-words.h"
#endif
+void cpu_sync_apx_hflag(CPUX86State *env)
+{
+ if ((env->cr[4] & CR4_OSXSAVE_MASK)
+ && (env->xcr0 & XSTATE_APX_MASK) == XSTATE_APX_MASK) {
+ env->hflags |= HF_APX_EN_MASK;
+ } else{
+ env->hflags &= ~HF_APX_EN_MASK;
+ }
+}
+
void cpu_sync_avx_hflag(CPUX86State *env)
{
if ((env->cr[4] & CR4_OSXSAVE_MASK)
@@ -249,6 +259,7 @@ void cpu_x86_update_cr4(CPUX86State *env, uint32_t new_cr4)
cpu_sync_bndcs_hflags(env);
cpu_sync_avx_hflag(env);
+ cpu_sync_apx_hflag(env);
}
#if !defined(CONFIG_USER_ONLY)
diff --git a/target/i386/tcg/fpu_helper.c b/target/i386/tcg/fpu_helper.c
index b3b23823fda..26fc9af7082 100644
--- a/target/i386/tcg/fpu_helper.c
+++ b/target/i386/tcg/fpu_helper.c
@@ -2691,6 +2691,19 @@ static void do_xsave_pkru(X86Access *ac, target_ulong ptr)
access_stq(ac, ptr, ac->env->pkru);
}
+#ifdef TARGET_X86_64
+static void do_xsave_apx(X86Access *ac, target_ulong ptr)
+{
+ CPUX86State *env = ac->env;
+ int i;
+
+ for (i = 16; i < 32; i++) {
+ access_stq(ac, ptr, env->regs[i]);
+ ptr += 8;
+ }
+}
+#endif
+
static void do_fxsave(X86Access *ac, target_ulong ptr)
{
CPUX86State *env = ac->env;
@@ -2755,14 +2768,19 @@ static void do_xsave_access(X86Access *ac, target_ulong ptr, uint64_t rfbm,
do_xsave_ymmh(ac, ptr + XO(avx_state));
}
if (opt & XSTATE_BNDREGS_MASK) {
- do_xsave_bndregs(ac, ptr + XO(bndreg_state));
+ do_xsave_bndregs(ac, ptr + XO(mpx_state.bndreg));
}
if (opt & XSTATE_BNDCSR_MASK) {
- do_xsave_bndcsr(ac, ptr + XO(bndcsr_state));
+ do_xsave_bndcsr(ac, ptr + XO(mpx_state.bndcsr));
}
if (opt & XSTATE_PKRU_MASK) {
do_xsave_pkru(ac, ptr + XO(pkru_state));
}
+#ifdef TARGET_X86_64
+ if (opt & XSTATE_APX_MASK) {
+ do_xsave_apx(ac, ptr + XO(apx_state));
+ }
+#endif
/* Update the XSTATE_BV field. */
old_bv = access_ldq(ac, ptr + XO(header.xstate_bv));
@@ -2956,6 +2974,29 @@ static void do_fxrstor(X86Access *ac, target_ulong ptr)
}
}
+#ifdef TARGET_X86_64
+static void do_xrstor_apx(X86Access *ac, target_ulong ptr)
+{
+ CPUX86State *env = ac->env;
+ int i;
+
+ for (i = 16; i < 32; i++) {
+ env->regs[i] = access_ldq(ac, ptr);
+ ptr += 8;
+ }
+}
+
+static void do_clear_apx(X86Access *ac)
+{
+ CPUX86State *env = ac->env;
+ int i;
+
+ for (i = 16; i < 32; i++) {
+ env->regs[i] = 0;
+ }
+}
+#endif
+
void helper_fxrstor(CPUX86State *env, target_ulong ptr)
{
uintptr_t ra = GETPC();
@@ -3027,7 +3068,7 @@ static void do_xrstor(X86Access *ac, target_ulong ptr,
}
if (rfbm & XSTATE_BNDREGS_MASK) {
if (xstate_bv & XSTATE_BNDREGS_MASK) {
- do_xrstor_bndregs(ac, ptr + XO(bndreg_state));
+ do_xrstor_bndregs(ac, ptr + XO(mpx_state.bndreg));
env->hflags |= HF_MPX_IU_MASK;
} else {
memset(env->bnd_regs, 0, sizeof(env->bnd_regs));
@@ -3036,7 +3077,7 @@ static void do_xrstor(X86Access *ac, target_ulong ptr,
}
if (rfbm & XSTATE_BNDCSR_MASK) {
if (xstate_bv & XSTATE_BNDCSR_MASK) {
- do_xrstor_bndcsr(ac, ptr + XO(bndcsr_state));
+ do_xrstor_bndcsr(ac, ptr + XO(mpx_state.bndcsr));
} else {
memset(&env->bndcs_regs, 0, sizeof(env->bndcs_regs));
}
@@ -3054,6 +3095,15 @@ static void do_xrstor(X86Access *ac, target_ulong ptr,
tlb_flush(cs);
}
}
+#ifdef TARGET_X86_64
+ if (rfbm & XSTATE_APX_MASK) {
+ if (xstate_bv & XSTATE_APX_MASK) {
+ do_xrstor_apx(ac, ptr + XO(apx_state));
+ } else {
+ do_clear_apx(ac);
+ }
+ }
+#endif
}
#undef XO
@@ -3229,6 +3279,7 @@ void helper_xsetbv(CPUX86State *env, uint32_t ecx, uint64_t mask)
env->xcr0 = mask;
cpu_sync_bndcs_hflags(env);
cpu_sync_avx_hflag(env);
+ cpu_sync_apx_hflag(env);
return;
do_gpf:
diff --git a/target/i386/tcg/tcg-cpu.c b/target/i386/tcg/tcg-cpu.c
index 6f5dc06b3b9..2965c304e57 100644
--- a/target/i386/tcg/tcg-cpu.c
+++ b/target/i386/tcg/tcg-cpu.c
@@ -198,12 +198,13 @@ static void x86_tcg_cpu_xsave_init(void)
XO(XSTATE_FP_BIT, legacy);
XO(XSTATE_SSE_BIT, legacy);
XO(XSTATE_YMM_BIT, avx_state);
- XO(XSTATE_BNDREGS_BIT, bndreg_state);
- XO(XSTATE_BNDCSR_BIT, bndcsr_state);
+ XO(XSTATE_BNDREGS_BIT, mpx_state.bndreg);
+ XO(XSTATE_BNDCSR_BIT, mpx_state.bndcsr);
XO(XSTATE_OPMASK_BIT, opmask_state);
XO(XSTATE_ZMM_Hi256_BIT, zmm_hi256_state);
XO(XSTATE_Hi16_ZMM_BIT, hi16_zmm_state);
XO(XSTATE_PKRU_BIT, pkru_state);
+ XO(XSTATE_APX_BIT, apx_state);
#undef XO
}
--
2.52.0