xref: /openbmc/qemu/target/i386/xsave_helper.c (revision 3568987f)
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 
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;
12*3568987fSDavid Edmondson     const ExtSaveArea *e, *f;
1386a57621SSergio Andres Gomez Del Real     int i;
14c0198c5fSDavid Edmondson 
15*3568987fSDavid Edmondson     X86LegacyXSaveArea *legacy;
16*3568987fSDavid Edmondson     X86XSaveHeader *header;
17*3568987fSDavid Edmondson     uint16_t cwd, swd, twd;
18c0198c5fSDavid Edmondson 
19*3568987fSDavid Edmondson     memset(buf, 0, buflen);
20*3568987fSDavid Edmondson 
21*3568987fSDavid Edmondson     e = &x86_ext_save_areas[XSTATE_FP_BIT];
22*3568987fSDavid Edmondson 
23*3568987fSDavid Edmondson     legacy = buf + e->offset;
24*3568987fSDavid Edmondson     header = buf + e->offset + sizeof(*legacy);
25*3568987fSDavid 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     }
33*3568987fSDavid Edmondson     legacy->fcw = cwd;
34*3568987fSDavid Edmondson     legacy->fsw = swd;
35*3568987fSDavid Edmondson     legacy->ftw = twd;
36*3568987fSDavid Edmondson     legacy->fpop = env->fpop;
37*3568987fSDavid Edmondson     legacy->fpip = env->fpip;
38*3568987fSDavid Edmondson     legacy->fpdp = env->fpdp;
39*3568987fSDavid Edmondson     memcpy(&legacy->fpregs, env->fpregs,
40*3568987fSDavid Edmondson            sizeof(env->fpregs));
41*3568987fSDavid Edmondson     legacy->mxcsr = env->mxcsr;
4286a57621SSergio Andres Gomez Del Real 
4386a57621SSergio Andres Gomez Del Real     for (i = 0; i < CPU_NB_REGS; i++) {
44*3568987fSDavid Edmondson         uint8_t *xmm = legacy->xmm_regs[i];
45*3568987fSDavid 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));
48*3568987fSDavid Edmondson     }
49*3568987fSDavid Edmondson 
50*3568987fSDavid Edmondson     header->xstate_bv = env->xstate_bv;
51*3568987fSDavid Edmondson 
52*3568987fSDavid Edmondson     e = &x86_ext_save_areas[XSTATE_YMM_BIT];
53*3568987fSDavid Edmondson     if (e->size && e->offset) {
54*3568987fSDavid Edmondson         XSaveAVX *avx;
55*3568987fSDavid Edmondson 
56*3568987fSDavid Edmondson         avx = buf + e->offset;
57*3568987fSDavid Edmondson 
58*3568987fSDavid Edmondson         for (i = 0; i < CPU_NB_REGS; i++) {
59*3568987fSDavid Edmondson             uint8_t *ymmh = avx->ymmh[i];
60*3568987fSDavid 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));
63*3568987fSDavid Edmondson         }
64*3568987fSDavid Edmondson     }
65*3568987fSDavid Edmondson 
66*3568987fSDavid Edmondson     e = &x86_ext_save_areas[XSTATE_BNDREGS_BIT];
67*3568987fSDavid Edmondson     if (e->size && e->offset) {
68*3568987fSDavid Edmondson         XSaveBNDREG *bndreg;
69*3568987fSDavid Edmondson         XSaveBNDCSR *bndcsr;
70*3568987fSDavid Edmondson 
71*3568987fSDavid Edmondson         f = &x86_ext_save_areas[XSTATE_BNDCSR_BIT];
72*3568987fSDavid Edmondson         assert(f->size);
73*3568987fSDavid Edmondson         assert(f->offset);
74*3568987fSDavid Edmondson 
75*3568987fSDavid Edmondson         bndreg = buf + e->offset;
76*3568987fSDavid Edmondson         bndcsr = buf + f->offset;
77*3568987fSDavid Edmondson 
78*3568987fSDavid Edmondson         memcpy(&bndreg->bnd_regs, env->bnd_regs,
79*3568987fSDavid Edmondson                sizeof(env->bnd_regs));
80*3568987fSDavid Edmondson         bndcsr->bndcsr = env->bndcs_regs;
81*3568987fSDavid Edmondson     }
82*3568987fSDavid Edmondson 
83*3568987fSDavid Edmondson     e = &x86_ext_save_areas[XSTATE_OPMASK_BIT];
84*3568987fSDavid Edmondson     if (e->size && e->offset) {
85*3568987fSDavid Edmondson         XSaveOpmask *opmask;
86*3568987fSDavid Edmondson         XSaveZMM_Hi256 *zmm_hi256;
87*3568987fSDavid Edmondson #ifdef TARGET_X86_64
88*3568987fSDavid Edmondson         XSaveHi16_ZMM *hi16_zmm;
89*3568987fSDavid Edmondson #endif
90*3568987fSDavid Edmondson 
91*3568987fSDavid Edmondson         f = &x86_ext_save_areas[XSTATE_ZMM_Hi256_BIT];
92*3568987fSDavid Edmondson         assert(f->size);
93*3568987fSDavid Edmondson         assert(f->offset);
94*3568987fSDavid Edmondson 
95*3568987fSDavid Edmondson         opmask = buf + e->offset;
96*3568987fSDavid Edmondson         zmm_hi256 = buf + f->offset;
97*3568987fSDavid Edmondson 
98*3568987fSDavid Edmondson         memcpy(&opmask->opmask_regs, env->opmask_regs,
99*3568987fSDavid Edmondson                sizeof(env->opmask_regs));
100*3568987fSDavid Edmondson 
101*3568987fSDavid Edmondson         for (i = 0; i < CPU_NB_REGS; i++) {
102*3568987fSDavid Edmondson             uint8_t *zmmh = zmm_hi256->zmm_hi256[i];
103*3568987fSDavid 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
111*3568987fSDavid Edmondson         f = &x86_ext_save_areas[XSTATE_Hi16_ZMM_BIT];
112*3568987fSDavid Edmondson         assert(f->size);
113*3568987fSDavid Edmondson         assert(f->offset);
114*3568987fSDavid Edmondson 
115*3568987fSDavid Edmondson         hi16_zmm = buf + f->offset;
116*3568987fSDavid Edmondson 
117*3568987fSDavid Edmondson         memcpy(&hi16_zmm->hi16_zmm, &env->xmm_regs[16],
118*3568987fSDavid Edmondson                16 * sizeof(env->xmm_regs[16]));
119*3568987fSDavid Edmondson #endif
120*3568987fSDavid Edmondson     }
121*3568987fSDavid Edmondson 
122*3568987fSDavid Edmondson #ifdef TARGET_X86_64
123*3568987fSDavid Edmondson     e = &x86_ext_save_areas[XSTATE_PKRU_BIT];
124*3568987fSDavid Edmondson     if (e->size && e->offset) {
125*3568987fSDavid Edmondson         XSavePKRU *pkru = buf + e->offset;
126*3568987fSDavid Edmondson 
127*3568987fSDavid Edmondson         memcpy(pkru, &env->pkru, sizeof(env->pkru));
128*3568987fSDavid Edmondson     }
12986a57621SSergio Andres Gomez Del Real #endif
13086a57621SSergio Andres Gomez Del Real }
13186a57621SSergio Andres Gomez Del Real 
132c0198c5fSDavid Edmondson void x86_cpu_xrstor_all_areas(X86CPU *cpu, const void *buf, uint32_t buflen)
13386a57621SSergio Andres Gomez Del Real {
13486a57621SSergio Andres Gomez Del Real     CPUX86State *env = &cpu->env;
135*3568987fSDavid Edmondson     const ExtSaveArea *e, *f, *g;
13686a57621SSergio Andres Gomez Del Real     int i;
137*3568987fSDavid Edmondson 
138*3568987fSDavid Edmondson     const X86LegacyXSaveArea *legacy;
139*3568987fSDavid Edmondson     const X86XSaveHeader *header;
14086a57621SSergio Andres Gomez Del Real     uint16_t cwd, swd, twd;
141c0198c5fSDavid Edmondson 
142*3568987fSDavid Edmondson     e = &x86_ext_save_areas[XSTATE_FP_BIT];
143c0198c5fSDavid Edmondson 
144*3568987fSDavid Edmondson     legacy = buf + e->offset;
145*3568987fSDavid Edmondson     header = buf + e->offset + sizeof(*legacy);
146*3568987fSDavid Edmondson 
147*3568987fSDavid Edmondson     cwd = legacy->fcw;
148*3568987fSDavid Edmondson     swd = legacy->fsw;
149*3568987fSDavid Edmondson     twd = legacy->ftw;
150*3568987fSDavid Edmondson     env->fpop = legacy->fpop;
15186a57621SSergio Andres Gomez Del Real     env->fpstt = (swd >> 11) & 7;
15286a57621SSergio Andres Gomez Del Real     env->fpus = swd;
15386a57621SSergio Andres Gomez Del Real     env->fpuc = cwd;
15486a57621SSergio Andres Gomez Del Real     for (i = 0; i < 8; ++i) {
15586a57621SSergio Andres Gomez Del Real         env->fptags[i] = !((twd >> i) & 1);
15686a57621SSergio Andres Gomez Del Real     }
157*3568987fSDavid Edmondson     env->fpip = legacy->fpip;
158*3568987fSDavid Edmondson     env->fpdp = legacy->fpdp;
159*3568987fSDavid Edmondson     env->mxcsr = legacy->mxcsr;
160*3568987fSDavid Edmondson     memcpy(env->fpregs, &legacy->fpregs,
161*3568987fSDavid Edmondson            sizeof(env->fpregs));
16286a57621SSergio Andres Gomez Del Real 
16386a57621SSergio Andres Gomez Del Real     for (i = 0; i < CPU_NB_REGS; i++) {
164*3568987fSDavid Edmondson         const uint8_t *xmm = legacy->xmm_regs[i];
165*3568987fSDavid Edmondson 
16686a57621SSergio Andres Gomez Del Real         env->xmm_regs[i].ZMM_Q(0) = ldq_p(xmm);
16786a57621SSergio Andres Gomez Del Real         env->xmm_regs[i].ZMM_Q(1) = ldq_p(xmm + 8);
168*3568987fSDavid Edmondson     }
169*3568987fSDavid Edmondson 
170*3568987fSDavid Edmondson     env->xstate_bv = header->xstate_bv;
171*3568987fSDavid Edmondson 
172*3568987fSDavid Edmondson     e = &x86_ext_save_areas[XSTATE_YMM_BIT];
173*3568987fSDavid Edmondson     if (e->size && e->offset) {
174*3568987fSDavid Edmondson         const XSaveAVX *avx;
175*3568987fSDavid Edmondson 
176*3568987fSDavid Edmondson         avx = buf + e->offset;
177*3568987fSDavid Edmondson         for (i = 0; i < CPU_NB_REGS; i++) {
178*3568987fSDavid Edmondson             const uint8_t *ymmh = avx->ymmh[i];
179*3568987fSDavid Edmondson 
18086a57621SSergio Andres Gomez Del Real             env->xmm_regs[i].ZMM_Q(2) = ldq_p(ymmh);
18186a57621SSergio Andres Gomez Del Real             env->xmm_regs[i].ZMM_Q(3) = ldq_p(ymmh + 8);
182*3568987fSDavid Edmondson         }
183*3568987fSDavid Edmondson     }
184*3568987fSDavid Edmondson 
185*3568987fSDavid Edmondson     e = &x86_ext_save_areas[XSTATE_BNDREGS_BIT];
186*3568987fSDavid Edmondson     if (e->size && e->offset) {
187*3568987fSDavid Edmondson         const XSaveBNDREG *bndreg;
188*3568987fSDavid Edmondson         const XSaveBNDCSR *bndcsr;
189*3568987fSDavid Edmondson 
190*3568987fSDavid Edmondson         f = &x86_ext_save_areas[XSTATE_BNDCSR_BIT];
191*3568987fSDavid Edmondson         assert(f->size);
192*3568987fSDavid Edmondson         assert(f->offset);
193*3568987fSDavid Edmondson 
194*3568987fSDavid Edmondson         bndreg = buf + e->offset;
195*3568987fSDavid Edmondson         bndcsr = buf + f->offset;
196*3568987fSDavid Edmondson 
197*3568987fSDavid Edmondson         memcpy(env->bnd_regs, &bndreg->bnd_regs,
198*3568987fSDavid Edmondson                sizeof(env->bnd_regs));
199*3568987fSDavid Edmondson         env->bndcs_regs = bndcsr->bndcsr;
200*3568987fSDavid Edmondson     }
201*3568987fSDavid Edmondson 
202*3568987fSDavid Edmondson     e = &x86_ext_save_areas[XSTATE_OPMASK_BIT];
203*3568987fSDavid Edmondson     if (e->size && e->offset) {
204*3568987fSDavid Edmondson         const XSaveOpmask *opmask;
205*3568987fSDavid Edmondson         const XSaveZMM_Hi256 *zmm_hi256;
206*3568987fSDavid Edmondson #ifdef TARGET_X86_64
207*3568987fSDavid Edmondson         const XSaveHi16_ZMM *hi16_zmm;
208*3568987fSDavid Edmondson #endif
209*3568987fSDavid Edmondson 
210*3568987fSDavid Edmondson         f = &x86_ext_save_areas[XSTATE_ZMM_Hi256_BIT];
211*3568987fSDavid Edmondson         assert(f->size);
212*3568987fSDavid Edmondson         assert(f->offset);
213*3568987fSDavid Edmondson 
214*3568987fSDavid Edmondson         g = &x86_ext_save_areas[XSTATE_Hi16_ZMM_BIT];
215*3568987fSDavid Edmondson         assert(g->size);
216*3568987fSDavid Edmondson         assert(g->offset);
217*3568987fSDavid Edmondson 
218*3568987fSDavid Edmondson         opmask = buf + e->offset;
219*3568987fSDavid Edmondson         zmm_hi256 = buf + f->offset;
220*3568987fSDavid Edmondson #ifdef TARGET_X86_64
221*3568987fSDavid Edmondson         hi16_zmm = buf + g->offset;
222*3568987fSDavid Edmondson #endif
223*3568987fSDavid Edmondson 
224*3568987fSDavid Edmondson         memcpy(env->opmask_regs, &opmask->opmask_regs,
225*3568987fSDavid Edmondson                sizeof(env->opmask_regs));
226*3568987fSDavid Edmondson 
227*3568987fSDavid Edmondson         for (i = 0; i < CPU_NB_REGS; i++) {
228*3568987fSDavid Edmondson             const uint8_t *zmmh = zmm_hi256->zmm_hi256[i];
229*3568987fSDavid Edmondson 
23086a57621SSergio Andres Gomez Del Real             env->xmm_regs[i].ZMM_Q(4) = ldq_p(zmmh);
23186a57621SSergio Andres Gomez Del Real             env->xmm_regs[i].ZMM_Q(5) = ldq_p(zmmh + 8);
23286a57621SSergio Andres Gomez Del Real             env->xmm_regs[i].ZMM_Q(6) = ldq_p(zmmh + 16);
23386a57621SSergio Andres Gomez Del Real             env->xmm_regs[i].ZMM_Q(7) = ldq_p(zmmh + 24);
23486a57621SSergio Andres Gomez Del Real         }
23586a57621SSergio Andres Gomez Del Real 
23686a57621SSergio Andres Gomez Del Real #ifdef TARGET_X86_64
237*3568987fSDavid Edmondson         memcpy(&env->xmm_regs[16], &hi16_zmm->hi16_zmm,
238*3568987fSDavid Edmondson                16 * sizeof(env->xmm_regs[16]));
239*3568987fSDavid Edmondson #endif
240*3568987fSDavid Edmondson     }
241*3568987fSDavid Edmondson 
242*3568987fSDavid Edmondson #ifdef TARGET_X86_64
243*3568987fSDavid Edmondson     e = &x86_ext_save_areas[XSTATE_PKRU_BIT];
244*3568987fSDavid Edmondson     if (e->size && e->offset) {
245*3568987fSDavid Edmondson         const XSavePKRU *pkru;
246*3568987fSDavid Edmondson 
247*3568987fSDavid Edmondson         pkru = buf + e->offset;
248*3568987fSDavid Edmondson         memcpy(&env->pkru, pkru, sizeof(env->pkru));
249*3568987fSDavid Edmondson     }
25086a57621SSergio Andres Gomez Del Real #endif
25186a57621SSergio Andres Gomez Del Real }
252