diff options
Diffstat (limited to 'target/i386/xsave_helper.c')
-rw-r--r-- | target/i386/xsave_helper.c | 114 |
1 files changed, 114 insertions, 0 deletions
diff --git a/target/i386/xsave_helper.c b/target/i386/xsave_helper.c new file mode 100644 index 0000000000..ca735eee77 --- /dev/null +++ b/target/i386/xsave_helper.c @@ -0,0 +1,114 @@ +/* + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ +#include "qemu/osdep.h" +#include "qapi/error.h" + +#include "qemu-common.h" +#include "cpu.h" + +void x86_cpu_xsave_all_areas(X86CPU *cpu, X86XSaveArea *buf) +{ + CPUX86State *env = &cpu->env; + X86XSaveArea *xsave = buf; + + uint16_t cwd, swd, twd; + int i; + memset(xsave, 0, sizeof(X86XSaveArea)); + twd = 0; + swd = env->fpus & ~(7 << 11); + swd |= (env->fpstt & 7) << 11; + cwd = env->fpuc; + 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); + + 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]; + 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)); + } + +#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); +#endif + +} + +void x86_cpu_xrstor_all_areas(X86CPU *cpu, const X86XSaveArea *buf) +{ + + CPUX86State *env = &cpu->env; + const X86XSaveArea *xsave = buf; + + int i; + uint16_t cwd, swd, twd; + cwd = xsave->legacy.fcw; + swd = xsave->legacy.fsw; + twd = xsave->legacy.ftw; + env->fpop = xsave->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); + + 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]; + 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); + } + +#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); +#endif + +} |