xref: /openbmc/qemu/target/i386/xsave_helper.c (revision e56dd3c7)
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