xref: /openbmc/qemu/target/i386/xsave_helper.c (revision 096b778f)
1 /*
2  * This work is licensed under the terms of the GNU GPL, version 2 or later.
3  * See the COPYING file in the top-level directory.
4  */
5 #include "qemu/osdep.h"
6 
7 #include "cpu.h"
8 
9 void x86_cpu_xsave_all_areas(X86CPU *cpu, void *buf, uint32_t buflen)
10 {
11     CPUX86State *env = &cpu->env;
12     const ExtSaveArea *e, *f;
13     int i;
14 
15     X86LegacyXSaveArea *legacy;
16     X86XSaveHeader *header;
17     uint16_t cwd, swd, twd;
18 
19     memset(buf, 0, buflen);
20 
21     e = &x86_ext_save_areas[XSTATE_FP_BIT];
22 
23     legacy = buf + e->offset;
24     header = buf + e->offset + sizeof(*legacy);
25 
26     twd = 0;
27     swd = env->fpus & ~(7 << 11);
28     swd |= (env->fpstt & 7) << 11;
29     cwd = env->fpuc;
30     for (i = 0; i < 8; ++i) {
31         twd |= (!env->fptags[i]) << i;
32     }
33     legacy->fcw = cwd;
34     legacy->fsw = swd;
35     legacy->ftw = twd;
36     legacy->fpop = env->fpop;
37     legacy->fpip = env->fpip;
38     legacy->fpdp = env->fpdp;
39     memcpy(&legacy->fpregs, env->fpregs,
40            sizeof(env->fpregs));
41     legacy->mxcsr = env->mxcsr;
42 
43     for (i = 0; i < CPU_NB_REGS; i++) {
44         uint8_t *xmm = legacy->xmm_regs[i];
45 
46         stq_p(xmm,     env->xmm_regs[i].ZMM_Q(0));
47         stq_p(xmm + 8, env->xmm_regs[i].ZMM_Q(1));
48     }
49 
50     header->xstate_bv = env->xstate_bv;
51 
52     e = &x86_ext_save_areas[XSTATE_YMM_BIT];
53     if (e->size && e->offset) {
54         XSaveAVX *avx;
55 
56         avx = buf + e->offset;
57 
58         for (i = 0; i < CPU_NB_REGS; i++) {
59             uint8_t *ymmh = avx->ymmh[i];
60 
61             stq_p(ymmh,     env->xmm_regs[i].ZMM_Q(2));
62             stq_p(ymmh + 8, env->xmm_regs[i].ZMM_Q(3));
63         }
64     }
65 
66     e = &x86_ext_save_areas[XSTATE_BNDREGS_BIT];
67     if (e->size && e->offset) {
68         XSaveBNDREG *bndreg;
69         XSaveBNDCSR *bndcsr;
70 
71         f = &x86_ext_save_areas[XSTATE_BNDCSR_BIT];
72         assert(f->size);
73         assert(f->offset);
74 
75         bndreg = buf + e->offset;
76         bndcsr = buf + f->offset;
77 
78         memcpy(&bndreg->bnd_regs, env->bnd_regs,
79                sizeof(env->bnd_regs));
80         bndcsr->bndcsr = env->bndcs_regs;
81     }
82 
83     e = &x86_ext_save_areas[XSTATE_OPMASK_BIT];
84     if (e->size && e->offset) {
85         XSaveOpmask *opmask;
86         XSaveZMM_Hi256 *zmm_hi256;
87 #ifdef TARGET_X86_64
88         XSaveHi16_ZMM *hi16_zmm;
89 #endif
90 
91         f = &x86_ext_save_areas[XSTATE_ZMM_Hi256_BIT];
92         assert(f->size);
93         assert(f->offset);
94 
95         opmask = buf + e->offset;
96         zmm_hi256 = buf + f->offset;
97 
98         memcpy(&opmask->opmask_regs, env->opmask_regs,
99                sizeof(env->opmask_regs));
100 
101         for (i = 0; i < CPU_NB_REGS; i++) {
102             uint8_t *zmmh = zmm_hi256->zmm_hi256[i];
103 
104             stq_p(zmmh,      env->xmm_regs[i].ZMM_Q(4));
105             stq_p(zmmh + 8,  env->xmm_regs[i].ZMM_Q(5));
106             stq_p(zmmh + 16, env->xmm_regs[i].ZMM_Q(6));
107             stq_p(zmmh + 24, env->xmm_regs[i].ZMM_Q(7));
108         }
109 
110 #ifdef TARGET_X86_64
111         f = &x86_ext_save_areas[XSTATE_Hi16_ZMM_BIT];
112         assert(f->size);
113         assert(f->offset);
114 
115         hi16_zmm = buf + f->offset;
116 
117         memcpy(&hi16_zmm->hi16_zmm, &env->xmm_regs[16],
118                16 * sizeof(env->xmm_regs[16]));
119 #endif
120     }
121 
122 #ifdef TARGET_X86_64
123     e = &x86_ext_save_areas[XSTATE_PKRU_BIT];
124     if (e->size && e->offset) {
125         XSavePKRU *pkru = buf + e->offset;
126 
127         memcpy(pkru, &env->pkru, sizeof(env->pkru));
128     }
129 
130     e = &x86_ext_save_areas[XSTATE_XTILE_CFG_BIT];
131     if (e->size && e->offset) {
132         XSaveXTILECFG *tilecfg = buf + e->offset;
133 
134         memcpy(tilecfg, &env->xtilecfg, sizeof(env->xtilecfg));
135     }
136 
137     e = &x86_ext_save_areas[XSTATE_XTILE_DATA_BIT];
138     if (e->size && e->offset && buflen >= e->size + e->offset) {
139         XSaveXTILEDATA *tiledata = buf + e->offset;
140 
141         memcpy(tiledata, &env->xtiledata, sizeof(env->xtiledata));
142     }
143 #endif
144 }
145 
146 void x86_cpu_xrstor_all_areas(X86CPU *cpu, const void *buf, uint32_t buflen)
147 {
148     CPUX86State *env = &cpu->env;
149     const ExtSaveArea *e, *f, *g;
150     int i;
151 
152     const X86LegacyXSaveArea *legacy;
153     const X86XSaveHeader *header;
154     uint16_t cwd, swd, twd;
155 
156     e = &x86_ext_save_areas[XSTATE_FP_BIT];
157 
158     legacy = buf + e->offset;
159     header = buf + e->offset + sizeof(*legacy);
160 
161     cwd = legacy->fcw;
162     swd = legacy->fsw;
163     twd = legacy->ftw;
164     env->fpop = legacy->fpop;
165     env->fpstt = (swd >> 11) & 7;
166     env->fpus = swd;
167     env->fpuc = cwd;
168     for (i = 0; i < 8; ++i) {
169         env->fptags[i] = !((twd >> i) & 1);
170     }
171     env->fpip = legacy->fpip;
172     env->fpdp = legacy->fpdp;
173     env->mxcsr = legacy->mxcsr;
174     memcpy(env->fpregs, &legacy->fpregs,
175            sizeof(env->fpregs));
176 
177     for (i = 0; i < CPU_NB_REGS; i++) {
178         const uint8_t *xmm = legacy->xmm_regs[i];
179 
180         env->xmm_regs[i].ZMM_Q(0) = ldq_p(xmm);
181         env->xmm_regs[i].ZMM_Q(1) = ldq_p(xmm + 8);
182     }
183 
184     env->xstate_bv = header->xstate_bv;
185 
186     e = &x86_ext_save_areas[XSTATE_YMM_BIT];
187     if (e->size && e->offset) {
188         const XSaveAVX *avx;
189 
190         avx = buf + e->offset;
191         for (i = 0; i < CPU_NB_REGS; i++) {
192             const uint8_t *ymmh = avx->ymmh[i];
193 
194             env->xmm_regs[i].ZMM_Q(2) = ldq_p(ymmh);
195             env->xmm_regs[i].ZMM_Q(3) = ldq_p(ymmh + 8);
196         }
197     }
198 
199     e = &x86_ext_save_areas[XSTATE_BNDREGS_BIT];
200     if (e->size && e->offset) {
201         const XSaveBNDREG *bndreg;
202         const XSaveBNDCSR *bndcsr;
203 
204         f = &x86_ext_save_areas[XSTATE_BNDCSR_BIT];
205         assert(f->size);
206         assert(f->offset);
207 
208         bndreg = buf + e->offset;
209         bndcsr = buf + f->offset;
210 
211         memcpy(env->bnd_regs, &bndreg->bnd_regs,
212                sizeof(env->bnd_regs));
213         env->bndcs_regs = bndcsr->bndcsr;
214     }
215 
216     e = &x86_ext_save_areas[XSTATE_OPMASK_BIT];
217     if (e->size && e->offset) {
218         const XSaveOpmask *opmask;
219         const XSaveZMM_Hi256 *zmm_hi256;
220 #ifdef TARGET_X86_64
221         const XSaveHi16_ZMM *hi16_zmm;
222 #endif
223 
224         f = &x86_ext_save_areas[XSTATE_ZMM_Hi256_BIT];
225         assert(f->size);
226         assert(f->offset);
227 
228         g = &x86_ext_save_areas[XSTATE_Hi16_ZMM_BIT];
229         assert(g->size);
230         assert(g->offset);
231 
232         opmask = buf + e->offset;
233         zmm_hi256 = buf + f->offset;
234 #ifdef TARGET_X86_64
235         hi16_zmm = buf + g->offset;
236 #endif
237 
238         memcpy(env->opmask_regs, &opmask->opmask_regs,
239                sizeof(env->opmask_regs));
240 
241         for (i = 0; i < CPU_NB_REGS; i++) {
242             const uint8_t *zmmh = zmm_hi256->zmm_hi256[i];
243 
244             env->xmm_regs[i].ZMM_Q(4) = ldq_p(zmmh);
245             env->xmm_regs[i].ZMM_Q(5) = ldq_p(zmmh + 8);
246             env->xmm_regs[i].ZMM_Q(6) = ldq_p(zmmh + 16);
247             env->xmm_regs[i].ZMM_Q(7) = ldq_p(zmmh + 24);
248         }
249 
250 #ifdef TARGET_X86_64
251         memcpy(&env->xmm_regs[16], &hi16_zmm->hi16_zmm,
252                16 * sizeof(env->xmm_regs[16]));
253 #endif
254     }
255 
256 #ifdef TARGET_X86_64
257     e = &x86_ext_save_areas[XSTATE_PKRU_BIT];
258     if (e->size && e->offset) {
259         const XSavePKRU *pkru;
260 
261         pkru = buf + e->offset;
262         memcpy(&env->pkru, pkru, sizeof(env->pkru));
263     }
264 
265     e = &x86_ext_save_areas[XSTATE_XTILE_CFG_BIT];
266     if (e->size && e->offset) {
267         const XSaveXTILECFG *tilecfg = buf + e->offset;
268 
269         memcpy(&env->xtilecfg, tilecfg, sizeof(env->xtilecfg));
270     }
271 
272     e = &x86_ext_save_areas[XSTATE_XTILE_DATA_BIT];
273     if (e->size && e->offset && buflen >= e->size + e->offset) {
274         const XSaveXTILEDATA *tiledata = buf + e->offset;
275 
276         memcpy(&env->xtiledata, tiledata, sizeof(env->xtiledata));
277     }
278 #endif
279 }
280