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"
8*4533af18SPierrick Bouvier #include "exec/tswap.h"
986a57621SSergio Andres Gomez Del Real
x86_cpu_xsave_all_areas(X86CPU * cpu,void * buf,uint32_t buflen)10c0198c5fSDavid Edmondson void x86_cpu_xsave_all_areas(X86CPU *cpu, void *buf, uint32_t buflen)
1186a57621SSergio Andres Gomez Del Real {
1286a57621SSergio Andres Gomez Del Real CPUX86State *env = &cpu->env;
133568987fSDavid Edmondson const ExtSaveArea *e, *f;
1486a57621SSergio Andres Gomez Del Real int i;
15c0198c5fSDavid Edmondson
163568987fSDavid Edmondson X86LegacyXSaveArea *legacy;
173568987fSDavid Edmondson X86XSaveHeader *header;
183568987fSDavid Edmondson uint16_t cwd, swd, twd;
19c0198c5fSDavid Edmondson
203568987fSDavid Edmondson memset(buf, 0, buflen);
213568987fSDavid Edmondson
223568987fSDavid Edmondson e = &x86_ext_save_areas[XSTATE_FP_BIT];
233568987fSDavid Edmondson
243568987fSDavid Edmondson legacy = buf + e->offset;
253568987fSDavid Edmondson header = buf + e->offset + sizeof(*legacy);
263568987fSDavid Edmondson
2786a57621SSergio Andres Gomez Del Real twd = 0;
2886a57621SSergio Andres Gomez Del Real swd = env->fpus & ~(7 << 11);
2986a57621SSergio Andres Gomez Del Real swd |= (env->fpstt & 7) << 11;
3086a57621SSergio Andres Gomez Del Real cwd = env->fpuc;
3186a57621SSergio Andres Gomez Del Real for (i = 0; i < 8; ++i) {
3286a57621SSergio Andres Gomez Del Real twd |= (!env->fptags[i]) << i;
3386a57621SSergio Andres Gomez Del Real }
343568987fSDavid Edmondson legacy->fcw = cwd;
353568987fSDavid Edmondson legacy->fsw = swd;
363568987fSDavid Edmondson legacy->ftw = twd;
373568987fSDavid Edmondson legacy->fpop = env->fpop;
383568987fSDavid Edmondson legacy->fpip = env->fpip;
393568987fSDavid Edmondson legacy->fpdp = env->fpdp;
403568987fSDavid Edmondson memcpy(&legacy->fpregs, env->fpregs,
413568987fSDavid Edmondson sizeof(env->fpregs));
423568987fSDavid Edmondson legacy->mxcsr = env->mxcsr;
4386a57621SSergio Andres Gomez Del Real
4486a57621SSergio Andres Gomez Del Real for (i = 0; i < CPU_NB_REGS; i++) {
453568987fSDavid Edmondson uint8_t *xmm = legacy->xmm_regs[i];
463568987fSDavid Edmondson
4786a57621SSergio Andres Gomez Del Real stq_p(xmm, env->xmm_regs[i].ZMM_Q(0));
4886a57621SSergio Andres Gomez Del Real stq_p(xmm + 8, env->xmm_regs[i].ZMM_Q(1));
493568987fSDavid Edmondson }
503568987fSDavid Edmondson
513568987fSDavid Edmondson header->xstate_bv = env->xstate_bv;
523568987fSDavid Edmondson
533568987fSDavid Edmondson e = &x86_ext_save_areas[XSTATE_YMM_BIT];
543568987fSDavid Edmondson if (e->size && e->offset) {
553568987fSDavid Edmondson XSaveAVX *avx;
563568987fSDavid Edmondson
573568987fSDavid Edmondson avx = buf + e->offset;
583568987fSDavid Edmondson
593568987fSDavid Edmondson for (i = 0; i < CPU_NB_REGS; i++) {
603568987fSDavid Edmondson uint8_t *ymmh = avx->ymmh[i];
613568987fSDavid Edmondson
6286a57621SSergio Andres Gomez Del Real stq_p(ymmh, env->xmm_regs[i].ZMM_Q(2));
6386a57621SSergio Andres Gomez Del Real stq_p(ymmh + 8, env->xmm_regs[i].ZMM_Q(3));
643568987fSDavid Edmondson }
653568987fSDavid Edmondson }
663568987fSDavid Edmondson
673568987fSDavid Edmondson e = &x86_ext_save_areas[XSTATE_BNDREGS_BIT];
683568987fSDavid Edmondson if (e->size && e->offset) {
693568987fSDavid Edmondson XSaveBNDREG *bndreg;
703568987fSDavid Edmondson XSaveBNDCSR *bndcsr;
713568987fSDavid Edmondson
723568987fSDavid Edmondson f = &x86_ext_save_areas[XSTATE_BNDCSR_BIT];
733568987fSDavid Edmondson assert(f->size);
743568987fSDavid Edmondson assert(f->offset);
753568987fSDavid Edmondson
763568987fSDavid Edmondson bndreg = buf + e->offset;
773568987fSDavid Edmondson bndcsr = buf + f->offset;
783568987fSDavid Edmondson
793568987fSDavid Edmondson memcpy(&bndreg->bnd_regs, env->bnd_regs,
803568987fSDavid Edmondson sizeof(env->bnd_regs));
813568987fSDavid Edmondson bndcsr->bndcsr = env->bndcs_regs;
823568987fSDavid Edmondson }
833568987fSDavid Edmondson
843568987fSDavid Edmondson e = &x86_ext_save_areas[XSTATE_OPMASK_BIT];
853568987fSDavid Edmondson if (e->size && e->offset) {
863568987fSDavid Edmondson XSaveOpmask *opmask;
873568987fSDavid Edmondson XSaveZMM_Hi256 *zmm_hi256;
883568987fSDavid Edmondson #ifdef TARGET_X86_64
893568987fSDavid Edmondson XSaveHi16_ZMM *hi16_zmm;
903568987fSDavid Edmondson #endif
913568987fSDavid Edmondson
923568987fSDavid Edmondson f = &x86_ext_save_areas[XSTATE_ZMM_Hi256_BIT];
933568987fSDavid Edmondson assert(f->size);
943568987fSDavid Edmondson assert(f->offset);
953568987fSDavid Edmondson
963568987fSDavid Edmondson opmask = buf + e->offset;
973568987fSDavid Edmondson zmm_hi256 = buf + f->offset;
983568987fSDavid Edmondson
993568987fSDavid Edmondson memcpy(&opmask->opmask_regs, env->opmask_regs,
1003568987fSDavid Edmondson sizeof(env->opmask_regs));
1013568987fSDavid Edmondson
1023568987fSDavid Edmondson for (i = 0; i < CPU_NB_REGS; i++) {
1033568987fSDavid Edmondson uint8_t *zmmh = zmm_hi256->zmm_hi256[i];
1043568987fSDavid Edmondson
10586a57621SSergio Andres Gomez Del Real stq_p(zmmh, env->xmm_regs[i].ZMM_Q(4));
10686a57621SSergio Andres Gomez Del Real stq_p(zmmh + 8, env->xmm_regs[i].ZMM_Q(5));
10786a57621SSergio Andres Gomez Del Real stq_p(zmmh + 16, env->xmm_regs[i].ZMM_Q(6));
10886a57621SSergio Andres Gomez Del Real stq_p(zmmh + 24, env->xmm_regs[i].ZMM_Q(7));
10986a57621SSergio Andres Gomez Del Real }
11086a57621SSergio Andres Gomez Del Real
11186a57621SSergio Andres Gomez Del Real #ifdef TARGET_X86_64
1123568987fSDavid Edmondson f = &x86_ext_save_areas[XSTATE_Hi16_ZMM_BIT];
1133568987fSDavid Edmondson assert(f->size);
1143568987fSDavid Edmondson assert(f->offset);
1153568987fSDavid Edmondson
1163568987fSDavid Edmondson hi16_zmm = buf + f->offset;
1173568987fSDavid Edmondson
1183568987fSDavid Edmondson memcpy(&hi16_zmm->hi16_zmm, &env->xmm_regs[16],
1193568987fSDavid Edmondson 16 * sizeof(env->xmm_regs[16]));
1203568987fSDavid Edmondson #endif
1213568987fSDavid Edmondson }
1223568987fSDavid Edmondson
1233568987fSDavid Edmondson #ifdef TARGET_X86_64
1243568987fSDavid Edmondson e = &x86_ext_save_areas[XSTATE_PKRU_BIT];
1253568987fSDavid Edmondson if (e->size && e->offset) {
1263568987fSDavid Edmondson XSavePKRU *pkru = buf + e->offset;
1273568987fSDavid Edmondson
1283568987fSDavid Edmondson memcpy(pkru, &env->pkru, sizeof(env->pkru));
1293568987fSDavid Edmondson }
130e56dd3c7SJing Liu
131e56dd3c7SJing Liu e = &x86_ext_save_areas[XSTATE_XTILE_CFG_BIT];
132e56dd3c7SJing Liu if (e->size && e->offset) {
133e56dd3c7SJing Liu XSaveXTILECFG *tilecfg = buf + e->offset;
134e56dd3c7SJing Liu
135e56dd3c7SJing Liu memcpy(tilecfg, &env->xtilecfg, sizeof(env->xtilecfg));
136e56dd3c7SJing Liu }
137e56dd3c7SJing Liu
138e56dd3c7SJing Liu e = &x86_ext_save_areas[XSTATE_XTILE_DATA_BIT];
139e56dd3c7SJing Liu if (e->size && e->offset && buflen >= e->size + e->offset) {
140e56dd3c7SJing Liu XSaveXTILEDATA *tiledata = buf + e->offset;
141e56dd3c7SJing Liu
142e56dd3c7SJing Liu memcpy(tiledata, &env->xtiledata, sizeof(env->xtiledata));
143e56dd3c7SJing Liu }
14486a57621SSergio Andres Gomez Del Real #endif
14586a57621SSergio Andres Gomez Del Real }
14686a57621SSergio Andres Gomez Del Real
x86_cpu_xrstor_all_areas(X86CPU * cpu,const void * buf,uint32_t buflen)147c0198c5fSDavid Edmondson void x86_cpu_xrstor_all_areas(X86CPU *cpu, const void *buf, uint32_t buflen)
14886a57621SSergio Andres Gomez Del Real {
14986a57621SSergio Andres Gomez Del Real CPUX86State *env = &cpu->env;
1503568987fSDavid Edmondson const ExtSaveArea *e, *f, *g;
15186a57621SSergio Andres Gomez Del Real int i;
1523568987fSDavid Edmondson
1533568987fSDavid Edmondson const X86LegacyXSaveArea *legacy;
1543568987fSDavid Edmondson const X86XSaveHeader *header;
15586a57621SSergio Andres Gomez Del Real uint16_t cwd, swd, twd;
156c0198c5fSDavid Edmondson
1573568987fSDavid Edmondson e = &x86_ext_save_areas[XSTATE_FP_BIT];
158c0198c5fSDavid Edmondson
1593568987fSDavid Edmondson legacy = buf + e->offset;
1603568987fSDavid Edmondson header = buf + e->offset + sizeof(*legacy);
1613568987fSDavid Edmondson
1623568987fSDavid Edmondson cwd = legacy->fcw;
1633568987fSDavid Edmondson swd = legacy->fsw;
1643568987fSDavid Edmondson twd = legacy->ftw;
1653568987fSDavid Edmondson env->fpop = legacy->fpop;
16686a57621SSergio Andres Gomez Del Real env->fpstt = (swd >> 11) & 7;
16786a57621SSergio Andres Gomez Del Real env->fpus = swd;
16886a57621SSergio Andres Gomez Del Real env->fpuc = cwd;
16986a57621SSergio Andres Gomez Del Real for (i = 0; i < 8; ++i) {
17086a57621SSergio Andres Gomez Del Real env->fptags[i] = !((twd >> i) & 1);
17186a57621SSergio Andres Gomez Del Real }
1723568987fSDavid Edmondson env->fpip = legacy->fpip;
1733568987fSDavid Edmondson env->fpdp = legacy->fpdp;
1743568987fSDavid Edmondson env->mxcsr = legacy->mxcsr;
1753568987fSDavid Edmondson memcpy(env->fpregs, &legacy->fpregs,
1763568987fSDavid Edmondson sizeof(env->fpregs));
17786a57621SSergio Andres Gomez Del Real
17886a57621SSergio Andres Gomez Del Real for (i = 0; i < CPU_NB_REGS; i++) {
1793568987fSDavid Edmondson const uint8_t *xmm = legacy->xmm_regs[i];
1803568987fSDavid Edmondson
18186a57621SSergio Andres Gomez Del Real env->xmm_regs[i].ZMM_Q(0) = ldq_p(xmm);
18286a57621SSergio Andres Gomez Del Real env->xmm_regs[i].ZMM_Q(1) = ldq_p(xmm + 8);
1833568987fSDavid Edmondson }
1843568987fSDavid Edmondson
1853568987fSDavid Edmondson env->xstate_bv = header->xstate_bv;
1863568987fSDavid Edmondson
1873568987fSDavid Edmondson e = &x86_ext_save_areas[XSTATE_YMM_BIT];
1883568987fSDavid Edmondson if (e->size && e->offset) {
1893568987fSDavid Edmondson const XSaveAVX *avx;
1903568987fSDavid Edmondson
1913568987fSDavid Edmondson avx = buf + e->offset;
1923568987fSDavid Edmondson for (i = 0; i < CPU_NB_REGS; i++) {
1933568987fSDavid Edmondson const uint8_t *ymmh = avx->ymmh[i];
1943568987fSDavid Edmondson
19586a57621SSergio Andres Gomez Del Real env->xmm_regs[i].ZMM_Q(2) = ldq_p(ymmh);
19686a57621SSergio Andres Gomez Del Real env->xmm_regs[i].ZMM_Q(3) = ldq_p(ymmh + 8);
1973568987fSDavid Edmondson }
1983568987fSDavid Edmondson }
1993568987fSDavid Edmondson
2003568987fSDavid Edmondson e = &x86_ext_save_areas[XSTATE_BNDREGS_BIT];
2013568987fSDavid Edmondson if (e->size && e->offset) {
2023568987fSDavid Edmondson const XSaveBNDREG *bndreg;
2033568987fSDavid Edmondson const XSaveBNDCSR *bndcsr;
2043568987fSDavid Edmondson
2053568987fSDavid Edmondson f = &x86_ext_save_areas[XSTATE_BNDCSR_BIT];
2063568987fSDavid Edmondson assert(f->size);
2073568987fSDavid Edmondson assert(f->offset);
2083568987fSDavid Edmondson
2093568987fSDavid Edmondson bndreg = buf + e->offset;
2103568987fSDavid Edmondson bndcsr = buf + f->offset;
2113568987fSDavid Edmondson
2123568987fSDavid Edmondson memcpy(env->bnd_regs, &bndreg->bnd_regs,
2133568987fSDavid Edmondson sizeof(env->bnd_regs));
2143568987fSDavid Edmondson env->bndcs_regs = bndcsr->bndcsr;
2153568987fSDavid Edmondson }
2163568987fSDavid Edmondson
2173568987fSDavid Edmondson e = &x86_ext_save_areas[XSTATE_OPMASK_BIT];
2183568987fSDavid Edmondson if (e->size && e->offset) {
2193568987fSDavid Edmondson const XSaveOpmask *opmask;
2203568987fSDavid Edmondson const XSaveZMM_Hi256 *zmm_hi256;
2213568987fSDavid Edmondson #ifdef TARGET_X86_64
2223568987fSDavid Edmondson const XSaveHi16_ZMM *hi16_zmm;
2233568987fSDavid Edmondson #endif
2243568987fSDavid Edmondson
2253568987fSDavid Edmondson f = &x86_ext_save_areas[XSTATE_ZMM_Hi256_BIT];
2263568987fSDavid Edmondson assert(f->size);
2273568987fSDavid Edmondson assert(f->offset);
2283568987fSDavid Edmondson
2293568987fSDavid Edmondson g = &x86_ext_save_areas[XSTATE_Hi16_ZMM_BIT];
2303568987fSDavid Edmondson assert(g->size);
2313568987fSDavid Edmondson assert(g->offset);
2323568987fSDavid Edmondson
2333568987fSDavid Edmondson opmask = buf + e->offset;
2343568987fSDavid Edmondson zmm_hi256 = buf + f->offset;
2353568987fSDavid Edmondson #ifdef TARGET_X86_64
2363568987fSDavid Edmondson hi16_zmm = buf + g->offset;
2373568987fSDavid Edmondson #endif
2383568987fSDavid Edmondson
2393568987fSDavid Edmondson memcpy(env->opmask_regs, &opmask->opmask_regs,
2403568987fSDavid Edmondson sizeof(env->opmask_regs));
2413568987fSDavid Edmondson
2423568987fSDavid Edmondson for (i = 0; i < CPU_NB_REGS; i++) {
2433568987fSDavid Edmondson const uint8_t *zmmh = zmm_hi256->zmm_hi256[i];
2443568987fSDavid Edmondson
24586a57621SSergio Andres Gomez Del Real env->xmm_regs[i].ZMM_Q(4) = ldq_p(zmmh);
24686a57621SSergio Andres Gomez Del Real env->xmm_regs[i].ZMM_Q(5) = ldq_p(zmmh + 8);
24786a57621SSergio Andres Gomez Del Real env->xmm_regs[i].ZMM_Q(6) = ldq_p(zmmh + 16);
24886a57621SSergio Andres Gomez Del Real env->xmm_regs[i].ZMM_Q(7) = ldq_p(zmmh + 24);
24986a57621SSergio Andres Gomez Del Real }
25086a57621SSergio Andres Gomez Del Real
25186a57621SSergio Andres Gomez Del Real #ifdef TARGET_X86_64
2523568987fSDavid Edmondson memcpy(&env->xmm_regs[16], &hi16_zmm->hi16_zmm,
2533568987fSDavid Edmondson 16 * sizeof(env->xmm_regs[16]));
2543568987fSDavid Edmondson #endif
2553568987fSDavid Edmondson }
2563568987fSDavid Edmondson
2573568987fSDavid Edmondson #ifdef TARGET_X86_64
2583568987fSDavid Edmondson e = &x86_ext_save_areas[XSTATE_PKRU_BIT];
2593568987fSDavid Edmondson if (e->size && e->offset) {
2603568987fSDavid Edmondson const XSavePKRU *pkru;
2613568987fSDavid Edmondson
2623568987fSDavid Edmondson pkru = buf + e->offset;
2633568987fSDavid Edmondson memcpy(&env->pkru, pkru, sizeof(env->pkru));
2643568987fSDavid Edmondson }
265e56dd3c7SJing Liu
266e56dd3c7SJing Liu e = &x86_ext_save_areas[XSTATE_XTILE_CFG_BIT];
267e56dd3c7SJing Liu if (e->size && e->offset) {
268e56dd3c7SJing Liu const XSaveXTILECFG *tilecfg = buf + e->offset;
269e56dd3c7SJing Liu
270e56dd3c7SJing Liu memcpy(&env->xtilecfg, tilecfg, sizeof(env->xtilecfg));
271e56dd3c7SJing Liu }
272e56dd3c7SJing Liu
273e56dd3c7SJing Liu e = &x86_ext_save_areas[XSTATE_XTILE_DATA_BIT];
274e56dd3c7SJing Liu if (e->size && e->offset && buflen >= e->size + e->offset) {
275e56dd3c7SJing Liu const XSaveXTILEDATA *tiledata = buf + e->offset;
276e56dd3c7SJing Liu
277e56dd3c7SJing Liu memcpy(&env->xtiledata, tiledata, sizeof(env->xtiledata));
278e56dd3c7SJing Liu }
27986a57621SSergio Andres Gomez Del Real #endif
28086a57621SSergio Andres Gomez Del Real }
281