186a57621SSergio Andres Gomez Del Real /* 286a57621SSergio Andres Gomez Del Real * This work is licensed under the terms of the GNU GPL, version 2 or later. 386a57621SSergio Andres Gomez Del Real * See the COPYING file in the top-level directory. 486a57621SSergio Andres Gomez Del Real */ 586a57621SSergio Andres Gomez Del Real #include "qemu/osdep.h" 686a57621SSergio Andres Gomez Del Real 786a57621SSergio Andres Gomez Del Real #include "cpu.h" 886a57621SSergio Andres Gomez Del Real 9c0198c5fSDavid Edmondson void x86_cpu_xsave_all_areas(X86CPU *cpu, void *buf, uint32_t buflen) 1086a57621SSergio Andres Gomez Del Real { 1186a57621SSergio Andres Gomez Del Real CPUX86State *env = &cpu->env; 12*3568987fSDavid Edmondson const ExtSaveArea *e, *f; 1386a57621SSergio Andres Gomez Del Real int i; 14c0198c5fSDavid Edmondson 15*3568987fSDavid Edmondson X86LegacyXSaveArea *legacy; 16*3568987fSDavid Edmondson X86XSaveHeader *header; 17*3568987fSDavid Edmondson uint16_t cwd, swd, twd; 18c0198c5fSDavid Edmondson 19*3568987fSDavid Edmondson memset(buf, 0, buflen); 20*3568987fSDavid Edmondson 21*3568987fSDavid Edmondson e = &x86_ext_save_areas[XSTATE_FP_BIT]; 22*3568987fSDavid Edmondson 23*3568987fSDavid Edmondson legacy = buf + e->offset; 24*3568987fSDavid Edmondson header = buf + e->offset + sizeof(*legacy); 25*3568987fSDavid Edmondson 2686a57621SSergio Andres Gomez Del Real twd = 0; 2786a57621SSergio Andres Gomez Del Real swd = env->fpus & ~(7 << 11); 2886a57621SSergio Andres Gomez Del Real swd |= (env->fpstt & 7) << 11; 2986a57621SSergio Andres Gomez Del Real cwd = env->fpuc; 3086a57621SSergio Andres Gomez Del Real for (i = 0; i < 8; ++i) { 3186a57621SSergio Andres Gomez Del Real twd |= (!env->fptags[i]) << i; 3286a57621SSergio Andres Gomez Del Real } 33*3568987fSDavid Edmondson legacy->fcw = cwd; 34*3568987fSDavid Edmondson legacy->fsw = swd; 35*3568987fSDavid Edmondson legacy->ftw = twd; 36*3568987fSDavid Edmondson legacy->fpop = env->fpop; 37*3568987fSDavid Edmondson legacy->fpip = env->fpip; 38*3568987fSDavid Edmondson legacy->fpdp = env->fpdp; 39*3568987fSDavid Edmondson memcpy(&legacy->fpregs, env->fpregs, 40*3568987fSDavid Edmondson sizeof(env->fpregs)); 41*3568987fSDavid Edmondson legacy->mxcsr = env->mxcsr; 4286a57621SSergio Andres Gomez Del Real 4386a57621SSergio Andres Gomez Del Real for (i = 0; i < CPU_NB_REGS; i++) { 44*3568987fSDavid Edmondson uint8_t *xmm = legacy->xmm_regs[i]; 45*3568987fSDavid Edmondson 4686a57621SSergio Andres Gomez Del Real stq_p(xmm, env->xmm_regs[i].ZMM_Q(0)); 4786a57621SSergio Andres Gomez Del Real stq_p(xmm + 8, env->xmm_regs[i].ZMM_Q(1)); 48*3568987fSDavid Edmondson } 49*3568987fSDavid Edmondson 50*3568987fSDavid Edmondson header->xstate_bv = env->xstate_bv; 51*3568987fSDavid Edmondson 52*3568987fSDavid Edmondson e = &x86_ext_save_areas[XSTATE_YMM_BIT]; 53*3568987fSDavid Edmondson if (e->size && e->offset) { 54*3568987fSDavid Edmondson XSaveAVX *avx; 55*3568987fSDavid Edmondson 56*3568987fSDavid Edmondson avx = buf + e->offset; 57*3568987fSDavid Edmondson 58*3568987fSDavid Edmondson for (i = 0; i < CPU_NB_REGS; i++) { 59*3568987fSDavid Edmondson uint8_t *ymmh = avx->ymmh[i]; 60*3568987fSDavid Edmondson 6186a57621SSergio Andres Gomez Del Real stq_p(ymmh, env->xmm_regs[i].ZMM_Q(2)); 6286a57621SSergio Andres Gomez Del Real stq_p(ymmh + 8, env->xmm_regs[i].ZMM_Q(3)); 63*3568987fSDavid Edmondson } 64*3568987fSDavid Edmondson } 65*3568987fSDavid Edmondson 66*3568987fSDavid Edmondson e = &x86_ext_save_areas[XSTATE_BNDREGS_BIT]; 67*3568987fSDavid Edmondson if (e->size && e->offset) { 68*3568987fSDavid Edmondson XSaveBNDREG *bndreg; 69*3568987fSDavid Edmondson XSaveBNDCSR *bndcsr; 70*3568987fSDavid Edmondson 71*3568987fSDavid Edmondson f = &x86_ext_save_areas[XSTATE_BNDCSR_BIT]; 72*3568987fSDavid Edmondson assert(f->size); 73*3568987fSDavid Edmondson assert(f->offset); 74*3568987fSDavid Edmondson 75*3568987fSDavid Edmondson bndreg = buf + e->offset; 76*3568987fSDavid Edmondson bndcsr = buf + f->offset; 77*3568987fSDavid Edmondson 78*3568987fSDavid Edmondson memcpy(&bndreg->bnd_regs, env->bnd_regs, 79*3568987fSDavid Edmondson sizeof(env->bnd_regs)); 80*3568987fSDavid Edmondson bndcsr->bndcsr = env->bndcs_regs; 81*3568987fSDavid Edmondson } 82*3568987fSDavid Edmondson 83*3568987fSDavid Edmondson e = &x86_ext_save_areas[XSTATE_OPMASK_BIT]; 84*3568987fSDavid Edmondson if (e->size && e->offset) { 85*3568987fSDavid Edmondson XSaveOpmask *opmask; 86*3568987fSDavid Edmondson XSaveZMM_Hi256 *zmm_hi256; 87*3568987fSDavid Edmondson #ifdef TARGET_X86_64 88*3568987fSDavid Edmondson XSaveHi16_ZMM *hi16_zmm; 89*3568987fSDavid Edmondson #endif 90*3568987fSDavid Edmondson 91*3568987fSDavid Edmondson f = &x86_ext_save_areas[XSTATE_ZMM_Hi256_BIT]; 92*3568987fSDavid Edmondson assert(f->size); 93*3568987fSDavid Edmondson assert(f->offset); 94*3568987fSDavid Edmondson 95*3568987fSDavid Edmondson opmask = buf + e->offset; 96*3568987fSDavid Edmondson zmm_hi256 = buf + f->offset; 97*3568987fSDavid Edmondson 98*3568987fSDavid Edmondson memcpy(&opmask->opmask_regs, env->opmask_regs, 99*3568987fSDavid Edmondson sizeof(env->opmask_regs)); 100*3568987fSDavid Edmondson 101*3568987fSDavid Edmondson for (i = 0; i < CPU_NB_REGS; i++) { 102*3568987fSDavid Edmondson uint8_t *zmmh = zmm_hi256->zmm_hi256[i]; 103*3568987fSDavid Edmondson 10486a57621SSergio Andres Gomez Del Real stq_p(zmmh, env->xmm_regs[i].ZMM_Q(4)); 10586a57621SSergio Andres Gomez Del Real stq_p(zmmh + 8, env->xmm_regs[i].ZMM_Q(5)); 10686a57621SSergio Andres Gomez Del Real stq_p(zmmh + 16, env->xmm_regs[i].ZMM_Q(6)); 10786a57621SSergio Andres Gomez Del Real stq_p(zmmh + 24, env->xmm_regs[i].ZMM_Q(7)); 10886a57621SSergio Andres Gomez Del Real } 10986a57621SSergio Andres Gomez Del Real 11086a57621SSergio Andres Gomez Del Real #ifdef TARGET_X86_64 111*3568987fSDavid Edmondson f = &x86_ext_save_areas[XSTATE_Hi16_ZMM_BIT]; 112*3568987fSDavid Edmondson assert(f->size); 113*3568987fSDavid Edmondson assert(f->offset); 114*3568987fSDavid Edmondson 115*3568987fSDavid Edmondson hi16_zmm = buf + f->offset; 116*3568987fSDavid Edmondson 117*3568987fSDavid Edmondson memcpy(&hi16_zmm->hi16_zmm, &env->xmm_regs[16], 118*3568987fSDavid Edmondson 16 * sizeof(env->xmm_regs[16])); 119*3568987fSDavid Edmondson #endif 120*3568987fSDavid Edmondson } 121*3568987fSDavid Edmondson 122*3568987fSDavid Edmondson #ifdef TARGET_X86_64 123*3568987fSDavid Edmondson e = &x86_ext_save_areas[XSTATE_PKRU_BIT]; 124*3568987fSDavid Edmondson if (e->size && e->offset) { 125*3568987fSDavid Edmondson XSavePKRU *pkru = buf + e->offset; 126*3568987fSDavid Edmondson 127*3568987fSDavid Edmondson memcpy(pkru, &env->pkru, sizeof(env->pkru)); 128*3568987fSDavid Edmondson } 12986a57621SSergio Andres Gomez Del Real #endif 13086a57621SSergio Andres Gomez Del Real } 13186a57621SSergio Andres Gomez Del Real 132c0198c5fSDavid Edmondson void x86_cpu_xrstor_all_areas(X86CPU *cpu, const void *buf, uint32_t buflen) 13386a57621SSergio Andres Gomez Del Real { 13486a57621SSergio Andres Gomez Del Real CPUX86State *env = &cpu->env; 135*3568987fSDavid Edmondson const ExtSaveArea *e, *f, *g; 13686a57621SSergio Andres Gomez Del Real int i; 137*3568987fSDavid Edmondson 138*3568987fSDavid Edmondson const X86LegacyXSaveArea *legacy; 139*3568987fSDavid Edmondson const X86XSaveHeader *header; 14086a57621SSergio Andres Gomez Del Real uint16_t cwd, swd, twd; 141c0198c5fSDavid Edmondson 142*3568987fSDavid Edmondson e = &x86_ext_save_areas[XSTATE_FP_BIT]; 143c0198c5fSDavid Edmondson 144*3568987fSDavid Edmondson legacy = buf + e->offset; 145*3568987fSDavid Edmondson header = buf + e->offset + sizeof(*legacy); 146*3568987fSDavid Edmondson 147*3568987fSDavid Edmondson cwd = legacy->fcw; 148*3568987fSDavid Edmondson swd = legacy->fsw; 149*3568987fSDavid Edmondson twd = legacy->ftw; 150*3568987fSDavid Edmondson env->fpop = legacy->fpop; 15186a57621SSergio Andres Gomez Del Real env->fpstt = (swd >> 11) & 7; 15286a57621SSergio Andres Gomez Del Real env->fpus = swd; 15386a57621SSergio Andres Gomez Del Real env->fpuc = cwd; 15486a57621SSergio Andres Gomez Del Real for (i = 0; i < 8; ++i) { 15586a57621SSergio Andres Gomez Del Real env->fptags[i] = !((twd >> i) & 1); 15686a57621SSergio Andres Gomez Del Real } 157*3568987fSDavid Edmondson env->fpip = legacy->fpip; 158*3568987fSDavid Edmondson env->fpdp = legacy->fpdp; 159*3568987fSDavid Edmondson env->mxcsr = legacy->mxcsr; 160*3568987fSDavid Edmondson memcpy(env->fpregs, &legacy->fpregs, 161*3568987fSDavid Edmondson sizeof(env->fpregs)); 16286a57621SSergio Andres Gomez Del Real 16386a57621SSergio Andres Gomez Del Real for (i = 0; i < CPU_NB_REGS; i++) { 164*3568987fSDavid Edmondson const uint8_t *xmm = legacy->xmm_regs[i]; 165*3568987fSDavid Edmondson 16686a57621SSergio Andres Gomez Del Real env->xmm_regs[i].ZMM_Q(0) = ldq_p(xmm); 16786a57621SSergio Andres Gomez Del Real env->xmm_regs[i].ZMM_Q(1) = ldq_p(xmm + 8); 168*3568987fSDavid Edmondson } 169*3568987fSDavid Edmondson 170*3568987fSDavid Edmondson env->xstate_bv = header->xstate_bv; 171*3568987fSDavid Edmondson 172*3568987fSDavid Edmondson e = &x86_ext_save_areas[XSTATE_YMM_BIT]; 173*3568987fSDavid Edmondson if (e->size && e->offset) { 174*3568987fSDavid Edmondson const XSaveAVX *avx; 175*3568987fSDavid Edmondson 176*3568987fSDavid Edmondson avx = buf + e->offset; 177*3568987fSDavid Edmondson for (i = 0; i < CPU_NB_REGS; i++) { 178*3568987fSDavid Edmondson const uint8_t *ymmh = avx->ymmh[i]; 179*3568987fSDavid Edmondson 18086a57621SSergio Andres Gomez Del Real env->xmm_regs[i].ZMM_Q(2) = ldq_p(ymmh); 18186a57621SSergio Andres Gomez Del Real env->xmm_regs[i].ZMM_Q(3) = ldq_p(ymmh + 8); 182*3568987fSDavid Edmondson } 183*3568987fSDavid Edmondson } 184*3568987fSDavid Edmondson 185*3568987fSDavid Edmondson e = &x86_ext_save_areas[XSTATE_BNDREGS_BIT]; 186*3568987fSDavid Edmondson if (e->size && e->offset) { 187*3568987fSDavid Edmondson const XSaveBNDREG *bndreg; 188*3568987fSDavid Edmondson const XSaveBNDCSR *bndcsr; 189*3568987fSDavid Edmondson 190*3568987fSDavid Edmondson f = &x86_ext_save_areas[XSTATE_BNDCSR_BIT]; 191*3568987fSDavid Edmondson assert(f->size); 192*3568987fSDavid Edmondson assert(f->offset); 193*3568987fSDavid Edmondson 194*3568987fSDavid Edmondson bndreg = buf + e->offset; 195*3568987fSDavid Edmondson bndcsr = buf + f->offset; 196*3568987fSDavid Edmondson 197*3568987fSDavid Edmondson memcpy(env->bnd_regs, &bndreg->bnd_regs, 198*3568987fSDavid Edmondson sizeof(env->bnd_regs)); 199*3568987fSDavid Edmondson env->bndcs_regs = bndcsr->bndcsr; 200*3568987fSDavid Edmondson } 201*3568987fSDavid Edmondson 202*3568987fSDavid Edmondson e = &x86_ext_save_areas[XSTATE_OPMASK_BIT]; 203*3568987fSDavid Edmondson if (e->size && e->offset) { 204*3568987fSDavid Edmondson const XSaveOpmask *opmask; 205*3568987fSDavid Edmondson const XSaveZMM_Hi256 *zmm_hi256; 206*3568987fSDavid Edmondson #ifdef TARGET_X86_64 207*3568987fSDavid Edmondson const XSaveHi16_ZMM *hi16_zmm; 208*3568987fSDavid Edmondson #endif 209*3568987fSDavid Edmondson 210*3568987fSDavid Edmondson f = &x86_ext_save_areas[XSTATE_ZMM_Hi256_BIT]; 211*3568987fSDavid Edmondson assert(f->size); 212*3568987fSDavid Edmondson assert(f->offset); 213*3568987fSDavid Edmondson 214*3568987fSDavid Edmondson g = &x86_ext_save_areas[XSTATE_Hi16_ZMM_BIT]; 215*3568987fSDavid Edmondson assert(g->size); 216*3568987fSDavid Edmondson assert(g->offset); 217*3568987fSDavid Edmondson 218*3568987fSDavid Edmondson opmask = buf + e->offset; 219*3568987fSDavid Edmondson zmm_hi256 = buf + f->offset; 220*3568987fSDavid Edmondson #ifdef TARGET_X86_64 221*3568987fSDavid Edmondson hi16_zmm = buf + g->offset; 222*3568987fSDavid Edmondson #endif 223*3568987fSDavid Edmondson 224*3568987fSDavid Edmondson memcpy(env->opmask_regs, &opmask->opmask_regs, 225*3568987fSDavid Edmondson sizeof(env->opmask_regs)); 226*3568987fSDavid Edmondson 227*3568987fSDavid Edmondson for (i = 0; i < CPU_NB_REGS; i++) { 228*3568987fSDavid Edmondson const uint8_t *zmmh = zmm_hi256->zmm_hi256[i]; 229*3568987fSDavid Edmondson 23086a57621SSergio Andres Gomez Del Real env->xmm_regs[i].ZMM_Q(4) = ldq_p(zmmh); 23186a57621SSergio Andres Gomez Del Real env->xmm_regs[i].ZMM_Q(5) = ldq_p(zmmh + 8); 23286a57621SSergio Andres Gomez Del Real env->xmm_regs[i].ZMM_Q(6) = ldq_p(zmmh + 16); 23386a57621SSergio Andres Gomez Del Real env->xmm_regs[i].ZMM_Q(7) = ldq_p(zmmh + 24); 23486a57621SSergio Andres Gomez Del Real } 23586a57621SSergio Andres Gomez Del Real 23686a57621SSergio Andres Gomez Del Real #ifdef TARGET_X86_64 237*3568987fSDavid Edmondson memcpy(&env->xmm_regs[16], &hi16_zmm->hi16_zmm, 238*3568987fSDavid Edmondson 16 * sizeof(env->xmm_regs[16])); 239*3568987fSDavid Edmondson #endif 240*3568987fSDavid Edmondson } 241*3568987fSDavid Edmondson 242*3568987fSDavid Edmondson #ifdef TARGET_X86_64 243*3568987fSDavid Edmondson e = &x86_ext_save_areas[XSTATE_PKRU_BIT]; 244*3568987fSDavid Edmondson if (e->size && e->offset) { 245*3568987fSDavid Edmondson const XSavePKRU *pkru; 246*3568987fSDavid Edmondson 247*3568987fSDavid Edmondson pkru = buf + e->offset; 248*3568987fSDavid Edmondson memcpy(&env->pkru, pkru, sizeof(env->pkru)); 249*3568987fSDavid Edmondson } 25086a57621SSergio Andres Gomez Del Real #endif 25186a57621SSergio Andres Gomez Del Real } 252