/* * 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 "cpu.h" void x86_cpu_xsave_all_areas(X86CPU *cpu, void *buf, uint32_t buflen) { CPUX86State *env = &cpu->env; const ExtSaveArea *e, *f; int i; 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); 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; } 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 = 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)); } 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 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 ExtSaveArea *e, *f, *g; int i; const X86LegacyXSaveArea *legacy; const X86XSaveHeader *header; uint16_t cwd, swd, twd; e = &x86_ext_save_areas[XSTATE_FP_BIT]; 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 = 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 = 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->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 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 }