From d6f29071cce7c162df253a8fbfd6de691be5fff9 Mon Sep 17 00:00:00 2001
From: David Edmondson <david.edmondson@oracle.com>
Date: Mon, 5 Jul 2021 11:46:30 +0100
Subject: [PATCH 6/7] target/i386: Observe XSAVE state area offsets
RH-Author: Dr. David Alan Gilbert <dgilbert@redhat.com>
RH-MergeRequest: 113: non-av 8.5z: Fix XSAVE on newer CPUs
RH-Commit: [6/7] 3741a121957cd10e4d160da22c056ff81b6bc62f
RH-Bugzilla: 2065239
RH-Acked-by: Jon Maloy <jmaloy@redhat.com>
RH-Acked-by: Paolo Bonzini <pbonzini@redhat.com>
RH-Acked-by: Bandan Das <None>
Rather than relying on the X86XSaveArea structure definition directly,
the routines that manipulate the XSAVE state area should observe the
offsets declared in the x86_ext_save_areas array.
Currently the offsets declared in the array are derived from the
structure definition, resulting in no functional change.
Signed-off-by: David Edmondson <david.edmondson@oracle.com>
Message-Id: <20210705104632.2902400-7-david.edmondson@oracle.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
(cherry picked from commit 3568987f78faff90829ea6c885bbdd5b083dc86c)
---
target/i386/xsave_helper.c | 262 ++++++++++++++++++++++++++++---------
1 file changed, 200 insertions(+), 62 deletions(-)
diff --git a/target/i386/xsave_helper.c b/target/i386/xsave_helper.c
index b16c6ac0fe..ac61a96344 100644
--- a/target/i386/xsave_helper.c
+++ b/target/i386/xsave_helper.c
@@ -9,13 +9,20 @@
void x86_cpu_xsave_all_areas(X86CPU *cpu, void *buf, uint32_t buflen)
{
CPUX86State *env = &cpu->env;
- X86XSaveArea *xsave = buf;
- uint16_t cwd, swd, twd;
+ const ExtSaveArea *e, *f;
int i;
- assert(buflen >= sizeof(*xsave));
+ X86LegacyXSaveArea *legacy;
+ X86XSaveHeader *header;
+ uint16_t cwd, swd, twd;
+
+ memset(buf, 0, buflen);
+
+ e = &x86_ext_save_areas[XSTATE_FP_BIT];
+
+ legacy = buf + e->offset;
+ header = buf + e->offset + sizeof(*legacy);
- memset(xsave, 0, buflen);
twd = 0;
swd = env->fpus & ~(7 << 11);
swd |= (env->fpstt & 7) << 11;
@@ -23,91 +30,222 @@ void x86_cpu_xsave_all_areas(X86CPU *cpu, void *buf, uint32_t buflen)
for (i = 0; i < 8; ++i) {
twd |= (!env->fptags[i]) << i;
}
- xsave->legacy.fcw = cwd;
- xsave->legacy.fsw = swd;
- xsave->legacy.ftw = twd;
- xsave->legacy.fpop = env->fpop;
- xsave->legacy.fpip = env->fpip;
- xsave->legacy.fpdp = env->fpdp;
- memcpy(&xsave->legacy.fpregs, env->fpregs,
- sizeof env->fpregs);
- xsave->legacy.mxcsr = env->mxcsr;
- xsave->header.xstate_bv = env->xstate_bv;
- memcpy(&xsave->bndreg_state.bnd_regs, env->bnd_regs,
- sizeof env->bnd_regs);
- xsave->bndcsr_state.bndcsr = env->bndcs_regs;
- memcpy(&xsave->opmask_state.opmask_regs, env->opmask_regs,
- sizeof env->opmask_regs);
+ legacy->fcw = cwd;
+ legacy->fsw = swd;
+ legacy->ftw = twd;
+ legacy->fpop = env->fpop;
+ legacy->fpip = env->fpip;
+ legacy->fpdp = env->fpdp;
+ memcpy(&legacy->fpregs, env->fpregs,
+ sizeof(env->fpregs));
+ legacy->mxcsr = env->mxcsr;
for (i = 0; i < CPU_NB_REGS; i++) {
- uint8_t *xmm = xsave->legacy.xmm_regs[i];
- uint8_t *ymmh = xsave->avx_state.ymmh[i];
- uint8_t *zmmh = xsave->zmm_hi256_state.zmm_hi256[i];
+ uint8_t *xmm = legacy->xmm_regs[i];
+
stq_p(xmm, env->xmm_regs[i].ZMM_Q(0));
- stq_p(xmm+8, env->xmm_regs[i].ZMM_Q(1));
- stq_p(ymmh, env->xmm_regs[i].ZMM_Q(2));
- stq_p(ymmh+8, env->xmm_regs[i].ZMM_Q(3));
- stq_p(zmmh, env->xmm_regs[i].ZMM_Q(4));
- stq_p(zmmh+8, env->xmm_regs[i].ZMM_Q(5));
- stq_p(zmmh+16, env->xmm_regs[i].ZMM_Q(6));
- stq_p(zmmh+24, env->xmm_regs[i].ZMM_Q(7));
+ stq_p(xmm + 8, env->xmm_regs[i].ZMM_Q(1));
+ }
+
+ header->xstate_bv = env->xstate_bv;
+
+ e = &x86_ext_save_areas[XSTATE_YMM_BIT];
+ if (e->size && e->offset) {
+ XSaveAVX *avx;
+
+ avx = buf + e->offset;
+
+ for (i = 0; i < CPU_NB_REGS; i++) {
+ uint8_t *ymmh = avx->ymmh[i];
+
+ stq_p(ymmh, env->xmm_regs[i].ZMM_Q(2));
+ stq_p(ymmh + 8, env->xmm_regs[i].ZMM_Q(3));
+ }
+ }
+
+ e = &x86_ext_save_areas[XSTATE_BNDREGS_BIT];
+ if (e->size && e->offset) {
+ XSaveBNDREG *bndreg;
+ XSaveBNDCSR *bndcsr;
+
+ f = &x86_ext_save_areas[XSTATE_BNDCSR_BIT];
+ assert(f->size);
+ assert(f->offset);
+
+ bndreg = buf + e->offset;
+ bndcsr = buf + f->offset;
+
+ memcpy(&bndreg->bnd_regs, env->bnd_regs,
+ sizeof(env->bnd_regs));
+ bndcsr->bndcsr = env->bndcs_regs;
}
+ e = &x86_ext_save_areas[XSTATE_OPMASK_BIT];
+ if (e->size && e->offset) {
+ XSaveOpmask *opmask;
+ XSaveZMM_Hi256 *zmm_hi256;
+#ifdef TARGET_X86_64
+ XSaveHi16_ZMM *hi16_zmm;
+#endif
+
+ f = &x86_ext_save_areas[XSTATE_ZMM_Hi256_BIT];
+ assert(f->size);
+ assert(f->offset);
+
+ opmask = buf + e->offset;
+ zmm_hi256 = buf + f->offset;
+
+ memcpy(&opmask->opmask_regs, env->opmask_regs,
+ sizeof(env->opmask_regs));
+
+ for (i = 0; i < CPU_NB_REGS; i++) {
+ uint8_t *zmmh = zmm_hi256->zmm_hi256[i];
+
+ stq_p(zmmh, env->xmm_regs[i].ZMM_Q(4));
+ stq_p(zmmh + 8, env->xmm_regs[i].ZMM_Q(5));
+ stq_p(zmmh + 16, env->xmm_regs[i].ZMM_Q(6));
+ stq_p(zmmh + 24, env->xmm_regs[i].ZMM_Q(7));
+ }
+
#ifdef TARGET_X86_64
- memcpy(&xsave->hi16_zmm_state.hi16_zmm, &env->xmm_regs[16],
- 16 * sizeof env->xmm_regs[16]);
- memcpy(&xsave->pkru_state, &env->pkru, sizeof env->pkru);
+ f = &x86_ext_save_areas[XSTATE_Hi16_ZMM_BIT];
+ assert(f->size);
+ assert(f->offset);
+
+ hi16_zmm = buf + f->offset;
+
+ memcpy(&hi16_zmm->hi16_zmm, &env->xmm_regs[16],
+ 16 * sizeof(env->xmm_regs[16]));
+#endif
+ }
+
+#ifdef TARGET_X86_64
+ e = &x86_ext_save_areas[XSTATE_PKRU_BIT];
+ if (e->size && e->offset) {
+ XSavePKRU *pkru = buf + e->offset;
+
+ memcpy(pkru, &env->pkru, sizeof(env->pkru));
+ }
#endif
}
void x86_cpu_xrstor_all_areas(X86CPU *cpu, const void *buf, uint32_t buflen)
{
CPUX86State *env = &cpu->env;
- const X86XSaveArea *xsave = buf;
+ const ExtSaveArea *e, *f, *g;
int i;
+
+ const X86LegacyXSaveArea *legacy;
+ const X86XSaveHeader *header;
uint16_t cwd, swd, twd;
- assert(buflen >= sizeof(*xsave));
+ e = &x86_ext_save_areas[XSTATE_FP_BIT];
- cwd = xsave->legacy.fcw;
- swd = xsave->legacy.fsw;
- twd = xsave->legacy.ftw;
- env->fpop = xsave->legacy.fpop;
+ legacy = buf + e->offset;
+ header = buf + e->offset + sizeof(*legacy);
+
+ cwd = legacy->fcw;
+ swd = legacy->fsw;
+ twd = legacy->ftw;
+ env->fpop = legacy->fpop;
env->fpstt = (swd >> 11) & 7;
env->fpus = swd;
env->fpuc = cwd;
for (i = 0; i < 8; ++i) {
env->fptags[i] = !((twd >> i) & 1);
}
- env->fpip = xsave->legacy.fpip;
- env->fpdp = xsave->legacy.fpdp;
- env->mxcsr = xsave->legacy.mxcsr;
- memcpy(env->fpregs, &xsave->legacy.fpregs,
- sizeof env->fpregs);
- env->xstate_bv = xsave->header.xstate_bv;
- memcpy(env->bnd_regs, &xsave->bndreg_state.bnd_regs,
- sizeof env->bnd_regs);
- env->bndcs_regs = xsave->bndcsr_state.bndcsr;
- memcpy(env->opmask_regs, &xsave->opmask_state.opmask_regs,
- sizeof env->opmask_regs);
+ env->fpip = legacy->fpip;
+ env->fpdp = legacy->fpdp;
+ env->mxcsr = legacy->mxcsr;
+ memcpy(env->fpregs, &legacy->fpregs,
+ sizeof(env->fpregs));
for (i = 0; i < CPU_NB_REGS; i++) {
- const uint8_t *xmm = xsave->legacy.xmm_regs[i];
- const uint8_t *ymmh = xsave->avx_state.ymmh[i];
- const uint8_t *zmmh = xsave->zmm_hi256_state.zmm_hi256[i];
+ const uint8_t *xmm = legacy->xmm_regs[i];
+
env->xmm_regs[i].ZMM_Q(0) = ldq_p(xmm);
- env->xmm_regs[i].ZMM_Q(1) = ldq_p(xmm+8);
- env->xmm_regs[i].ZMM_Q(2) = ldq_p(ymmh);
- env->xmm_regs[i].ZMM_Q(3) = ldq_p(ymmh+8);
- env->xmm_regs[i].ZMM_Q(4) = ldq_p(zmmh);
- env->xmm_regs[i].ZMM_Q(5) = ldq_p(zmmh+8);
- env->xmm_regs[i].ZMM_Q(6) = ldq_p(zmmh+16);
- env->xmm_regs[i].ZMM_Q(7) = ldq_p(zmmh+24);
+ env->xmm_regs[i].ZMM_Q(1) = ldq_p(xmm + 8);
+ }
+
+ env->xstate_bv = header->xstate_bv;
+
+ e = &x86_ext_save_areas[XSTATE_YMM_BIT];
+ if (e->size && e->offset) {
+ const XSaveAVX *avx;
+
+ avx = buf + e->offset;
+ for (i = 0; i < CPU_NB_REGS; i++) {
+ const uint8_t *ymmh = avx->ymmh[i];
+
+ env->xmm_regs[i].ZMM_Q(2) = ldq_p(ymmh);
+ env->xmm_regs[i].ZMM_Q(3) = ldq_p(ymmh + 8);
+ }
+ }
+
+ e = &x86_ext_save_areas[XSTATE_BNDREGS_BIT];
+ if (e->size && e->offset) {
+ const XSaveBNDREG *bndreg;
+ const XSaveBNDCSR *bndcsr;
+
+ f = &x86_ext_save_areas[XSTATE_BNDCSR_BIT];
+ assert(f->size);
+ assert(f->offset);
+
+ bndreg = buf + e->offset;
+ bndcsr = buf + f->offset;
+
+ memcpy(env->bnd_regs, &bndreg->bnd_regs,
+ sizeof(env->bnd_regs));
+ env->bndcs_regs = bndcsr->bndcsr;
}
+ e = &x86_ext_save_areas[XSTATE_OPMASK_BIT];
+ if (e->size && e->offset) {
+ const XSaveOpmask *opmask;
+ const XSaveZMM_Hi256 *zmm_hi256;
#ifdef TARGET_X86_64
- memcpy(&env->xmm_regs[16], &xsave->hi16_zmm_state.hi16_zmm,
- 16 * sizeof env->xmm_regs[16]);
- memcpy(&env->pkru, &xsave->pkru_state, sizeof env->pkru);
+ const XSaveHi16_ZMM *hi16_zmm;
+#endif
+
+ f = &x86_ext_save_areas[XSTATE_ZMM_Hi256_BIT];
+ assert(f->size);
+ assert(f->offset);
+
+ g = &x86_ext_save_areas[XSTATE_Hi16_ZMM_BIT];
+ assert(g->size);
+ assert(g->offset);
+
+ opmask = buf + e->offset;
+ zmm_hi256 = buf + f->offset;
+#ifdef TARGET_X86_64
+ hi16_zmm = buf + g->offset;
+#endif
+
+ memcpy(env->opmask_regs, &opmask->opmask_regs,
+ sizeof(env->opmask_regs));
+
+ for (i = 0; i < CPU_NB_REGS; i++) {
+ const uint8_t *zmmh = zmm_hi256->zmm_hi256[i];
+
+ env->xmm_regs[i].ZMM_Q(4) = ldq_p(zmmh);
+ env->xmm_regs[i].ZMM_Q(5) = ldq_p(zmmh + 8);
+ env->xmm_regs[i].ZMM_Q(6) = ldq_p(zmmh + 16);
+ env->xmm_regs[i].ZMM_Q(7) = ldq_p(zmmh + 24);
+ }
+
+#ifdef TARGET_X86_64
+ memcpy(&env->xmm_regs[16], &hi16_zmm->hi16_zmm,
+ 16 * sizeof(env->xmm_regs[16]));
+#endif
+ }
+
+#ifdef TARGET_X86_64
+ e = &x86_ext_save_areas[XSTATE_PKRU_BIT];
+ if (e->size && e->offset) {
+ const XSavePKRU *pkru;
+
+ pkru = buf + e->offset;
+ memcpy(&env->pkru, pkru, sizeof(env->pkru));
+ }
#endif
}
--
2.27.0