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; 123568987fSDavid Edmondson const ExtSaveArea *e, *f; 1386a57621SSergio Andres Gomez Del Real int i; 14c0198c5fSDavid Edmondson 153568987fSDavid Edmondson X86LegacyXSaveArea *legacy; 163568987fSDavid Edmondson X86XSaveHeader *header; 173568987fSDavid Edmondson uint16_t cwd, swd, twd; 18c0198c5fSDavid Edmondson 193568987fSDavid Edmondson memset(buf, 0, buflen); 203568987fSDavid Edmondson 213568987fSDavid Edmondson e = &x86_ext_save_areas[XSTATE_FP_BIT]; 223568987fSDavid Edmondson 233568987fSDavid Edmondson legacy = buf + e->offset; 243568987fSDavid Edmondson header = buf + e->offset + sizeof(*legacy); 253568987fSDavid 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 } 333568987fSDavid Edmondson legacy->fcw = cwd; 343568987fSDavid Edmondson legacy->fsw = swd; 353568987fSDavid Edmondson legacy->ftw = twd; 363568987fSDavid Edmondson legacy->fpop = env->fpop; 373568987fSDavid Edmondson legacy->fpip = env->fpip; 383568987fSDavid Edmondson legacy->fpdp = env->fpdp; 393568987fSDavid Edmondson memcpy(&legacy->fpregs, env->fpregs, 403568987fSDavid Edmondson sizeof(env->fpregs)); 413568987fSDavid Edmondson legacy->mxcsr = env->mxcsr; 4286a57621SSergio Andres Gomez Del Real 4386a57621SSergio Andres Gomez Del Real for (i = 0; i < CPU_NB_REGS; i++) { 443568987fSDavid Edmondson uint8_t *xmm = legacy->xmm_regs[i]; 453568987fSDavid 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)); 483568987fSDavid Edmondson } 493568987fSDavid Edmondson 503568987fSDavid Edmondson header->xstate_bv = env->xstate_bv; 513568987fSDavid Edmondson 523568987fSDavid Edmondson e = &x86_ext_save_areas[XSTATE_YMM_BIT]; 533568987fSDavid Edmondson if (e->size && e->offset) { 543568987fSDavid Edmondson XSaveAVX *avx; 553568987fSDavid Edmondson 563568987fSDavid Edmondson avx = buf + e->offset; 573568987fSDavid Edmondson 583568987fSDavid Edmondson for (i = 0; i < CPU_NB_REGS; i++) { 593568987fSDavid Edmondson uint8_t *ymmh = avx->ymmh[i]; 603568987fSDavid 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)); 633568987fSDavid Edmondson } 643568987fSDavid Edmondson } 653568987fSDavid Edmondson 663568987fSDavid Edmondson e = &x86_ext_save_areas[XSTATE_BNDREGS_BIT]; 673568987fSDavid Edmondson if (e->size && e->offset) { 683568987fSDavid Edmondson XSaveBNDREG *bndreg; 693568987fSDavid Edmondson XSaveBNDCSR *bndcsr; 703568987fSDavid Edmondson 713568987fSDavid Edmondson f = &x86_ext_save_areas[XSTATE_BNDCSR_BIT]; 723568987fSDavid Edmondson assert(f->size); 733568987fSDavid Edmondson assert(f->offset); 743568987fSDavid Edmondson 753568987fSDavid Edmondson bndreg = buf + e->offset; 763568987fSDavid Edmondson bndcsr = buf + f->offset; 773568987fSDavid Edmondson 783568987fSDavid Edmondson memcpy(&bndreg->bnd_regs, env->bnd_regs, 793568987fSDavid Edmondson sizeof(env->bnd_regs)); 803568987fSDavid Edmondson bndcsr->bndcsr = env->bndcs_regs; 813568987fSDavid Edmondson } 823568987fSDavid Edmondson 833568987fSDavid Edmondson e = &x86_ext_save_areas[XSTATE_OPMASK_BIT]; 843568987fSDavid Edmondson if (e->size && e->offset) { 853568987fSDavid Edmondson XSaveOpmask *opmask; 863568987fSDavid Edmondson XSaveZMM_Hi256 *zmm_hi256; 873568987fSDavid Edmondson #ifdef TARGET_X86_64 883568987fSDavid Edmondson XSaveHi16_ZMM *hi16_zmm; 893568987fSDavid Edmondson #endif 903568987fSDavid Edmondson 913568987fSDavid Edmondson f = &x86_ext_save_areas[XSTATE_ZMM_Hi256_BIT]; 923568987fSDavid Edmondson assert(f->size); 933568987fSDavid Edmondson assert(f->offset); 943568987fSDavid Edmondson 953568987fSDavid Edmondson opmask = buf + e->offset; 963568987fSDavid Edmondson zmm_hi256 = buf + f->offset; 973568987fSDavid Edmondson 983568987fSDavid Edmondson memcpy(&opmask->opmask_regs, env->opmask_regs, 993568987fSDavid Edmondson sizeof(env->opmask_regs)); 1003568987fSDavid Edmondson 1013568987fSDavid Edmondson for (i = 0; i < CPU_NB_REGS; i++) { 1023568987fSDavid Edmondson uint8_t *zmmh = zmm_hi256->zmm_hi256[i]; 1033568987fSDavid 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 1113568987fSDavid Edmondson f = &x86_ext_save_areas[XSTATE_Hi16_ZMM_BIT]; 1123568987fSDavid Edmondson assert(f->size); 1133568987fSDavid Edmondson assert(f->offset); 1143568987fSDavid Edmondson 1153568987fSDavid Edmondson hi16_zmm = buf + f->offset; 1163568987fSDavid Edmondson 1173568987fSDavid Edmondson memcpy(&hi16_zmm->hi16_zmm, &env->xmm_regs[16], 1183568987fSDavid Edmondson 16 * sizeof(env->xmm_regs[16])); 1193568987fSDavid Edmondson #endif 1203568987fSDavid Edmondson } 1213568987fSDavid Edmondson 1223568987fSDavid Edmondson #ifdef TARGET_X86_64 1233568987fSDavid Edmondson e = &x86_ext_save_areas[XSTATE_PKRU_BIT]; 1243568987fSDavid Edmondson if (e->size && e->offset) { 1253568987fSDavid Edmondson XSavePKRU *pkru = buf + e->offset; 1263568987fSDavid Edmondson 1273568987fSDavid Edmondson memcpy(pkru, &env->pkru, sizeof(env->pkru)); 1283568987fSDavid Edmondson } 129*e56dd3c7SJing Liu 130*e56dd3c7SJing Liu e = &x86_ext_save_areas[XSTATE_XTILE_CFG_BIT]; 131*e56dd3c7SJing Liu if (e->size && e->offset) { 132*e56dd3c7SJing Liu XSaveXTILECFG *tilecfg = buf + e->offset; 133*e56dd3c7SJing Liu 134*e56dd3c7SJing Liu memcpy(tilecfg, &env->xtilecfg, sizeof(env->xtilecfg)); 135*e56dd3c7SJing Liu } 136*e56dd3c7SJing Liu 137*e56dd3c7SJing Liu e = &x86_ext_save_areas[XSTATE_XTILE_DATA_BIT]; 138*e56dd3c7SJing Liu if (e->size && e->offset && buflen >= e->size + e->offset) { 139*e56dd3c7SJing Liu XSaveXTILEDATA *tiledata = buf + e->offset; 140*e56dd3c7SJing Liu 141*e56dd3c7SJing Liu memcpy(tiledata, &env->xtiledata, sizeof(env->xtiledata)); 142*e56dd3c7SJing Liu } 14386a57621SSergio Andres Gomez Del Real #endif 14486a57621SSergio Andres Gomez Del Real } 14586a57621SSergio Andres Gomez Del Real 146c0198c5fSDavid Edmondson void x86_cpu_xrstor_all_areas(X86CPU *cpu, const void *buf, uint32_t buflen) 14786a57621SSergio Andres Gomez Del Real { 14886a57621SSergio Andres Gomez Del Real CPUX86State *env = &cpu->env; 1493568987fSDavid Edmondson const ExtSaveArea *e, *f, *g; 15086a57621SSergio Andres Gomez Del Real int i; 1513568987fSDavid Edmondson 1523568987fSDavid Edmondson const X86LegacyXSaveArea *legacy; 1533568987fSDavid Edmondson const X86XSaveHeader *header; 15486a57621SSergio Andres Gomez Del Real uint16_t cwd, swd, twd; 155c0198c5fSDavid Edmondson 1563568987fSDavid Edmondson e = &x86_ext_save_areas[XSTATE_FP_BIT]; 157c0198c5fSDavid Edmondson 1583568987fSDavid Edmondson legacy = buf + e->offset; 1593568987fSDavid Edmondson header = buf + e->offset + sizeof(*legacy); 1603568987fSDavid Edmondson 1613568987fSDavid Edmondson cwd = legacy->fcw; 1623568987fSDavid Edmondson swd = legacy->fsw; 1633568987fSDavid Edmondson twd = legacy->ftw; 1643568987fSDavid Edmondson env->fpop = legacy->fpop; 16586a57621SSergio Andres Gomez Del Real env->fpstt = (swd >> 11) & 7; 16686a57621SSergio Andres Gomez Del Real env->fpus = swd; 16786a57621SSergio Andres Gomez Del Real env->fpuc = cwd; 16886a57621SSergio Andres Gomez Del Real for (i = 0; i < 8; ++i) { 16986a57621SSergio Andres Gomez Del Real env->fptags[i] = !((twd >> i) & 1); 17086a57621SSergio Andres Gomez Del Real } 1713568987fSDavid Edmondson env->fpip = legacy->fpip; 1723568987fSDavid Edmondson env->fpdp = legacy->fpdp; 1733568987fSDavid Edmondson env->mxcsr = legacy->mxcsr; 1743568987fSDavid Edmondson memcpy(env->fpregs, &legacy->fpregs, 1753568987fSDavid Edmondson sizeof(env->fpregs)); 17686a57621SSergio Andres Gomez Del Real 17786a57621SSergio Andres Gomez Del Real for (i = 0; i < CPU_NB_REGS; i++) { 1783568987fSDavid Edmondson const uint8_t *xmm = legacy->xmm_regs[i]; 1793568987fSDavid Edmondson 18086a57621SSergio Andres Gomez Del Real env->xmm_regs[i].ZMM_Q(0) = ldq_p(xmm); 18186a57621SSergio Andres Gomez Del Real env->xmm_regs[i].ZMM_Q(1) = ldq_p(xmm + 8); 1823568987fSDavid Edmondson } 1833568987fSDavid Edmondson 1843568987fSDavid Edmondson env->xstate_bv = header->xstate_bv; 1853568987fSDavid Edmondson 1863568987fSDavid Edmondson e = &x86_ext_save_areas[XSTATE_YMM_BIT]; 1873568987fSDavid Edmondson if (e->size && e->offset) { 1883568987fSDavid Edmondson const XSaveAVX *avx; 1893568987fSDavid Edmondson 1903568987fSDavid Edmondson avx = buf + e->offset; 1913568987fSDavid Edmondson for (i = 0; i < CPU_NB_REGS; i++) { 1923568987fSDavid Edmondson const uint8_t *ymmh = avx->ymmh[i]; 1933568987fSDavid Edmondson 19486a57621SSergio Andres Gomez Del Real env->xmm_regs[i].ZMM_Q(2) = ldq_p(ymmh); 19586a57621SSergio Andres Gomez Del Real env->xmm_regs[i].ZMM_Q(3) = ldq_p(ymmh + 8); 1963568987fSDavid Edmondson } 1973568987fSDavid Edmondson } 1983568987fSDavid Edmondson 1993568987fSDavid Edmondson e = &x86_ext_save_areas[XSTATE_BNDREGS_BIT]; 2003568987fSDavid Edmondson if (e->size && e->offset) { 2013568987fSDavid Edmondson const XSaveBNDREG *bndreg; 2023568987fSDavid Edmondson const XSaveBNDCSR *bndcsr; 2033568987fSDavid Edmondson 2043568987fSDavid Edmondson f = &x86_ext_save_areas[XSTATE_BNDCSR_BIT]; 2053568987fSDavid Edmondson assert(f->size); 2063568987fSDavid Edmondson assert(f->offset); 2073568987fSDavid Edmondson 2083568987fSDavid Edmondson bndreg = buf + e->offset; 2093568987fSDavid Edmondson bndcsr = buf + f->offset; 2103568987fSDavid Edmondson 2113568987fSDavid Edmondson memcpy(env->bnd_regs, &bndreg->bnd_regs, 2123568987fSDavid Edmondson sizeof(env->bnd_regs)); 2133568987fSDavid Edmondson env->bndcs_regs = bndcsr->bndcsr; 2143568987fSDavid Edmondson } 2153568987fSDavid Edmondson 2163568987fSDavid Edmondson e = &x86_ext_save_areas[XSTATE_OPMASK_BIT]; 2173568987fSDavid Edmondson if (e->size && e->offset) { 2183568987fSDavid Edmondson const XSaveOpmask *opmask; 2193568987fSDavid Edmondson const XSaveZMM_Hi256 *zmm_hi256; 2203568987fSDavid Edmondson #ifdef TARGET_X86_64 2213568987fSDavid Edmondson const XSaveHi16_ZMM *hi16_zmm; 2223568987fSDavid Edmondson #endif 2233568987fSDavid Edmondson 2243568987fSDavid Edmondson f = &x86_ext_save_areas[XSTATE_ZMM_Hi256_BIT]; 2253568987fSDavid Edmondson assert(f->size); 2263568987fSDavid Edmondson assert(f->offset); 2273568987fSDavid Edmondson 2283568987fSDavid Edmondson g = &x86_ext_save_areas[XSTATE_Hi16_ZMM_BIT]; 2293568987fSDavid Edmondson assert(g->size); 2303568987fSDavid Edmondson assert(g->offset); 2313568987fSDavid Edmondson 2323568987fSDavid Edmondson opmask = buf + e->offset; 2333568987fSDavid Edmondson zmm_hi256 = buf + f->offset; 2343568987fSDavid Edmondson #ifdef TARGET_X86_64 2353568987fSDavid Edmondson hi16_zmm = buf + g->offset; 2363568987fSDavid Edmondson #endif 2373568987fSDavid Edmondson 2383568987fSDavid Edmondson memcpy(env->opmask_regs, &opmask->opmask_regs, 2393568987fSDavid Edmondson sizeof(env->opmask_regs)); 2403568987fSDavid Edmondson 2413568987fSDavid Edmondson for (i = 0; i < CPU_NB_REGS; i++) { 2423568987fSDavid Edmondson const uint8_t *zmmh = zmm_hi256->zmm_hi256[i]; 2433568987fSDavid Edmondson 24486a57621SSergio Andres Gomez Del Real env->xmm_regs[i].ZMM_Q(4) = ldq_p(zmmh); 24586a57621SSergio Andres Gomez Del Real env->xmm_regs[i].ZMM_Q(5) = ldq_p(zmmh + 8); 24686a57621SSergio Andres Gomez Del Real env->xmm_regs[i].ZMM_Q(6) = ldq_p(zmmh + 16); 24786a57621SSergio Andres Gomez Del Real env->xmm_regs[i].ZMM_Q(7) = ldq_p(zmmh + 24); 24886a57621SSergio Andres Gomez Del Real } 24986a57621SSergio Andres Gomez Del Real 25086a57621SSergio Andres Gomez Del Real #ifdef TARGET_X86_64 2513568987fSDavid Edmondson memcpy(&env->xmm_regs[16], &hi16_zmm->hi16_zmm, 2523568987fSDavid Edmondson 16 * sizeof(env->xmm_regs[16])); 2533568987fSDavid Edmondson #endif 2543568987fSDavid Edmondson } 2553568987fSDavid Edmondson 2563568987fSDavid Edmondson #ifdef TARGET_X86_64 2573568987fSDavid Edmondson e = &x86_ext_save_areas[XSTATE_PKRU_BIT]; 2583568987fSDavid Edmondson if (e->size && e->offset) { 2593568987fSDavid Edmondson const XSavePKRU *pkru; 2603568987fSDavid Edmondson 2613568987fSDavid Edmondson pkru = buf + e->offset; 2623568987fSDavid Edmondson memcpy(&env->pkru, pkru, sizeof(env->pkru)); 2633568987fSDavid Edmondson } 264*e56dd3c7SJing Liu 265*e56dd3c7SJing Liu e = &x86_ext_save_areas[XSTATE_XTILE_CFG_BIT]; 266*e56dd3c7SJing Liu if (e->size && e->offset) { 267*e56dd3c7SJing Liu const XSaveXTILECFG *tilecfg = buf + e->offset; 268*e56dd3c7SJing Liu 269*e56dd3c7SJing Liu memcpy(&env->xtilecfg, tilecfg, sizeof(env->xtilecfg)); 270*e56dd3c7SJing Liu } 271*e56dd3c7SJing Liu 272*e56dd3c7SJing Liu e = &x86_ext_save_areas[XSTATE_XTILE_DATA_BIT]; 273*e56dd3c7SJing Liu if (e->size && e->offset && buflen >= e->size + e->offset) { 274*e56dd3c7SJing Liu const XSaveXTILEDATA *tiledata = buf + e->offset; 275*e56dd3c7SJing Liu 276*e56dd3c7SJing Liu memcpy(&env->xtiledata, tiledata, sizeof(env->xtiledata)); 277*e56dd3c7SJing Liu } 27886a57621SSergio Andres Gomez Del Real #endif 27986a57621SSergio Andres Gomez Del Real } 280