xref: /openbmc/qemu/target/i386/xsave_helper.c (revision c0198c5f)
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 
9*c0198c5fSDavid 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;
1286a57621SSergio Andres Gomez Del Real     X86XSaveArea *xsave = buf;
1386a57621SSergio Andres Gomez Del Real     uint16_t cwd, swd, twd;
1486a57621SSergio Andres Gomez Del Real     int i;
15*c0198c5fSDavid Edmondson 
16*c0198c5fSDavid Edmondson     assert(buflen >= sizeof(*xsave));
17*c0198c5fSDavid Edmondson 
18*c0198c5fSDavid Edmondson     memset(xsave, 0, buflen);
1986a57621SSergio Andres Gomez Del Real     twd = 0;
2086a57621SSergio Andres Gomez Del Real     swd = env->fpus & ~(7 << 11);
2186a57621SSergio Andres Gomez Del Real     swd |= (env->fpstt & 7) << 11;
2286a57621SSergio Andres Gomez Del Real     cwd = env->fpuc;
2386a57621SSergio Andres Gomez Del Real     for (i = 0; i < 8; ++i) {
2486a57621SSergio Andres Gomez Del Real         twd |= (!env->fptags[i]) << i;
2586a57621SSergio Andres Gomez Del Real     }
2686a57621SSergio Andres Gomez Del Real     xsave->legacy.fcw = cwd;
2786a57621SSergio Andres Gomez Del Real     xsave->legacy.fsw = swd;
2886a57621SSergio Andres Gomez Del Real     xsave->legacy.ftw = twd;
2986a57621SSergio Andres Gomez Del Real     xsave->legacy.fpop = env->fpop;
3086a57621SSergio Andres Gomez Del Real     xsave->legacy.fpip = env->fpip;
3186a57621SSergio Andres Gomez Del Real     xsave->legacy.fpdp = env->fpdp;
3286a57621SSergio Andres Gomez Del Real     memcpy(&xsave->legacy.fpregs, env->fpregs,
3386a57621SSergio Andres Gomez Del Real             sizeof env->fpregs);
3486a57621SSergio Andres Gomez Del Real     xsave->legacy.mxcsr = env->mxcsr;
3586a57621SSergio Andres Gomez Del Real     xsave->header.xstate_bv = env->xstate_bv;
3686a57621SSergio Andres Gomez Del Real     memcpy(&xsave->bndreg_state.bnd_regs, env->bnd_regs,
3786a57621SSergio Andres Gomez Del Real             sizeof env->bnd_regs);
3886a57621SSergio Andres Gomez Del Real     xsave->bndcsr_state.bndcsr = env->bndcs_regs;
3986a57621SSergio Andres Gomez Del Real     memcpy(&xsave->opmask_state.opmask_regs, env->opmask_regs,
4086a57621SSergio Andres Gomez Del Real             sizeof env->opmask_regs);
4186a57621SSergio Andres Gomez Del Real 
4286a57621SSergio Andres Gomez Del Real     for (i = 0; i < CPU_NB_REGS; i++) {
4386a57621SSergio Andres Gomez Del Real         uint8_t *xmm = xsave->legacy.xmm_regs[i];
4486a57621SSergio Andres Gomez Del Real         uint8_t *ymmh = xsave->avx_state.ymmh[i];
4586a57621SSergio Andres Gomez Del Real         uint8_t *zmmh = xsave->zmm_hi256_state.zmm_hi256[i];
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));
4886a57621SSergio Andres Gomez Del Real         stq_p(ymmh,    env->xmm_regs[i].ZMM_Q(2));
4986a57621SSergio Andres Gomez Del Real         stq_p(ymmh+8,  env->xmm_regs[i].ZMM_Q(3));
5086a57621SSergio Andres Gomez Del Real         stq_p(zmmh,    env->xmm_regs[i].ZMM_Q(4));
5186a57621SSergio Andres Gomez Del Real         stq_p(zmmh+8,  env->xmm_regs[i].ZMM_Q(5));
5286a57621SSergio Andres Gomez Del Real         stq_p(zmmh+16, env->xmm_regs[i].ZMM_Q(6));
5386a57621SSergio Andres Gomez Del Real         stq_p(zmmh+24, env->xmm_regs[i].ZMM_Q(7));
5486a57621SSergio Andres Gomez Del Real     }
5586a57621SSergio Andres Gomez Del Real 
5686a57621SSergio Andres Gomez Del Real #ifdef TARGET_X86_64
5786a57621SSergio Andres Gomez Del Real     memcpy(&xsave->hi16_zmm_state.hi16_zmm, &env->xmm_regs[16],
5886a57621SSergio Andres Gomez Del Real             16 * sizeof env->xmm_regs[16]);
5986a57621SSergio Andres Gomez Del Real     memcpy(&xsave->pkru_state, &env->pkru, sizeof env->pkru);
6086a57621SSergio Andres Gomez Del Real #endif
6186a57621SSergio Andres Gomez Del Real }
6286a57621SSergio Andres Gomez Del Real 
63*c0198c5fSDavid Edmondson void x86_cpu_xrstor_all_areas(X86CPU *cpu, const void *buf, uint32_t buflen)
6486a57621SSergio Andres Gomez Del Real {
6586a57621SSergio Andres Gomez Del Real     CPUX86State *env = &cpu->env;
6686a57621SSergio Andres Gomez Del Real     const X86XSaveArea *xsave = buf;
6786a57621SSergio Andres Gomez Del Real     int i;
6886a57621SSergio Andres Gomez Del Real     uint16_t cwd, swd, twd;
69*c0198c5fSDavid Edmondson 
70*c0198c5fSDavid Edmondson     assert(buflen >= sizeof(*xsave));
71*c0198c5fSDavid Edmondson 
7286a57621SSergio Andres Gomez Del Real     cwd = xsave->legacy.fcw;
7386a57621SSergio Andres Gomez Del Real     swd = xsave->legacy.fsw;
7486a57621SSergio Andres Gomez Del Real     twd = xsave->legacy.ftw;
7586a57621SSergio Andres Gomez Del Real     env->fpop = xsave->legacy.fpop;
7686a57621SSergio Andres Gomez Del Real     env->fpstt = (swd >> 11) & 7;
7786a57621SSergio Andres Gomez Del Real     env->fpus = swd;
7886a57621SSergio Andres Gomez Del Real     env->fpuc = cwd;
7986a57621SSergio Andres Gomez Del Real     for (i = 0; i < 8; ++i) {
8086a57621SSergio Andres Gomez Del Real         env->fptags[i] = !((twd >> i) & 1);
8186a57621SSergio Andres Gomez Del Real     }
8286a57621SSergio Andres Gomez Del Real     env->fpip = xsave->legacy.fpip;
8386a57621SSergio Andres Gomez Del Real     env->fpdp = xsave->legacy.fpdp;
8486a57621SSergio Andres Gomez Del Real     env->mxcsr = xsave->legacy.mxcsr;
8586a57621SSergio Andres Gomez Del Real     memcpy(env->fpregs, &xsave->legacy.fpregs,
8686a57621SSergio Andres Gomez Del Real             sizeof env->fpregs);
8786a57621SSergio Andres Gomez Del Real     env->xstate_bv = xsave->header.xstate_bv;
8886a57621SSergio Andres Gomez Del Real     memcpy(env->bnd_regs, &xsave->bndreg_state.bnd_regs,
8986a57621SSergio Andres Gomez Del Real             sizeof env->bnd_regs);
9086a57621SSergio Andres Gomez Del Real     env->bndcs_regs = xsave->bndcsr_state.bndcsr;
9186a57621SSergio Andres Gomez Del Real     memcpy(env->opmask_regs, &xsave->opmask_state.opmask_regs,
9286a57621SSergio Andres Gomez Del Real             sizeof env->opmask_regs);
9386a57621SSergio Andres Gomez Del Real 
9486a57621SSergio Andres Gomez Del Real     for (i = 0; i < CPU_NB_REGS; i++) {
9586a57621SSergio Andres Gomez Del Real         const uint8_t *xmm = xsave->legacy.xmm_regs[i];
9686a57621SSergio Andres Gomez Del Real         const uint8_t *ymmh = xsave->avx_state.ymmh[i];
9786a57621SSergio Andres Gomez Del Real         const uint8_t *zmmh = xsave->zmm_hi256_state.zmm_hi256[i];
9886a57621SSergio Andres Gomez Del Real         env->xmm_regs[i].ZMM_Q(0) = ldq_p(xmm);
9986a57621SSergio Andres Gomez Del Real         env->xmm_regs[i].ZMM_Q(1) = ldq_p(xmm+8);
10086a57621SSergio Andres Gomez Del Real         env->xmm_regs[i].ZMM_Q(2) = ldq_p(ymmh);
10186a57621SSergio Andres Gomez Del Real         env->xmm_regs[i].ZMM_Q(3) = ldq_p(ymmh+8);
10286a57621SSergio Andres Gomez Del Real         env->xmm_regs[i].ZMM_Q(4) = ldq_p(zmmh);
10386a57621SSergio Andres Gomez Del Real         env->xmm_regs[i].ZMM_Q(5) = ldq_p(zmmh+8);
10486a57621SSergio Andres Gomez Del Real         env->xmm_regs[i].ZMM_Q(6) = ldq_p(zmmh+16);
10586a57621SSergio Andres Gomez Del Real         env->xmm_regs[i].ZMM_Q(7) = ldq_p(zmmh+24);
10686a57621SSergio Andres Gomez Del Real     }
10786a57621SSergio Andres Gomez Del Real 
10886a57621SSergio Andres Gomez Del Real #ifdef TARGET_X86_64
10986a57621SSergio Andres Gomez Del Real     memcpy(&env->xmm_regs[16], &xsave->hi16_zmm_state.hi16_zmm,
11086a57621SSergio Andres Gomez Del Real            16 * sizeof env->xmm_regs[16]);
11186a57621SSergio Andres Gomez Del Real     memcpy(&env->pkru, &xsave->pkru_state, sizeof env->pkru);
11286a57621SSergio Andres Gomez Del Real #endif
11386a57621SSergio Andres Gomez Del Real }
114