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
x86_cpu_xsave_all_areas(X86CPU * cpu,void * buf,uint32_t buflen)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
x86_cpu_xrstor_all_areas(X86CPU * cpu,const void * buf,uint32_t buflen)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