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