]>
Commit | Line | Data |
---|---|---|
58caa3dc | 1 | /* i387-specific utility functions, for the remote server for GDB. |
1d506c26 | 2 | Copyright (C) 2000-2024 Free Software Foundation, Inc. |
58caa3dc DJ |
3 | |
4 | This file is part of GDB. | |
5 | ||
6 | This program is free software; you can redistribute it and/or modify | |
7 | it under the terms of the GNU General Public License as published by | |
a9762ec7 | 8 | the Free Software Foundation; either version 3 of the License, or |
58caa3dc DJ |
9 | (at your option) any later version. |
10 | ||
11 | This program is distributed in the hope that it will be useful, | |
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 | GNU General Public License for more details. | |
15 | ||
16 | You should have received a copy of the GNU General Public License | |
a9762ec7 | 17 | along with this program. If not, see <http://www.gnu.org/licenses/>. */ |
58caa3dc | 18 | |
0d62e5e8 | 19 | #include "i387-fp.h" |
268a13a5 | 20 | #include "gdbsupport/x86-xstate.h" |
03e6fe7e JB |
21 | #include "nat/x86-xstate.h" |
22 | ||
23 | /* Default to SSE. */ | |
24 | static unsigned long long x86_xcr0 = X86_XSTATE_SSE_MASK; | |
58caa3dc | 25 | |
a196ebeb WT |
26 | static const int num_mpx_bnd_registers = 4; |
27 | static const int num_mpx_cfg_registers = 2; | |
01f9f808 | 28 | static const int num_avx512_k_registers = 8; |
51547df6 | 29 | static const int num_pkeys_registers = 1; |
a196ebeb | 30 | |
03e6fe7e JB |
31 | static x86_xsave_layout xsave_layout; |
32 | ||
58caa3dc DJ |
33 | /* Note: These functions preserve the reserved bits in control registers. |
34 | However, gdbserver promptly throws away that information. */ | |
35 | ||
36 | /* These structs should have the proper sizes and alignment on both | |
37 | i386 and x86-64 machines. */ | |
38 | ||
b3e17448 JB |
39 | struct i387_fsave |
40 | { | |
58caa3dc DJ |
41 | /* All these are only sixteen bits, plus padding, except for fop (which |
42 | is only eleven bits), and fooff / fioff (which are 32 bits each). */ | |
0c2ead7e DJ |
43 | unsigned short fctrl; |
44 | unsigned short pad1; | |
45 | unsigned short fstat; | |
46 | unsigned short pad2; | |
47 | unsigned short ftag; | |
48 | unsigned short pad3; | |
58caa3dc DJ |
49 | unsigned int fioff; |
50 | unsigned short fiseg; | |
51 | unsigned short fop; | |
52 | unsigned int fooff; | |
0c2ead7e DJ |
53 | unsigned short foseg; |
54 | unsigned short pad4; | |
58caa3dc DJ |
55 | |
56 | /* Space for eight 80-bit FP values. */ | |
f450004a | 57 | unsigned char st_space[80]; |
58caa3dc DJ |
58 | }; |
59 | ||
b3e17448 JB |
60 | struct i387_fxsave |
61 | { | |
58caa3dc DJ |
62 | /* All these are only sixteen bits, plus padding, except for fop (which |
63 | is only eleven bits), and fooff / fioff (which are 32 bits each). */ | |
64 | unsigned short fctrl; | |
65 | unsigned short fstat; | |
66 | unsigned short ftag; | |
67 | unsigned short fop; | |
68 | unsigned int fioff; | |
0c2ead7e DJ |
69 | unsigned short fiseg; |
70 | unsigned short pad1; | |
58caa3dc | 71 | unsigned int fooff; |
0c2ead7e DJ |
72 | unsigned short foseg; |
73 | unsigned short pad12; | |
58caa3dc DJ |
74 | |
75 | unsigned int mxcsr; | |
0c2ead7e | 76 | unsigned int pad3; |
58caa3dc DJ |
77 | |
78 | /* Space for eight 80-bit FP values in 128-bit spaces. */ | |
f450004a | 79 | unsigned char st_space[128]; |
58caa3dc DJ |
80 | |
81 | /* Space for eight 128-bit XMM values, or 16 on x86-64. */ | |
f450004a | 82 | unsigned char xmm_space[256]; |
58caa3dc DJ |
83 | }; |
84 | ||
69f6730d | 85 | static_assert (sizeof(i387_fxsave) == 416); |
1f14ecbe | 86 | |
b3e17448 JB |
87 | struct i387_xsave : public i387_fxsave |
88 | { | |
1570b33e L |
89 | unsigned char reserved1[48]; |
90 | ||
91 | /* The extended control register 0 (the XFEATURE_ENABLED_MASK | |
92 | register). */ | |
93 | unsigned long long xcr0; | |
94 | ||
95 | unsigned char reserved2[40]; | |
96 | ||
97 | /* The XSTATE_BV bit vector. */ | |
98 | unsigned long long xstate_bv; | |
99 | ||
1f14ecbe AP |
100 | /* The XCOMP_BV bit vector. */ |
101 | unsigned long long xcomp_bv; | |
a196ebeb | 102 | |
1f14ecbe | 103 | unsigned char reserved3[48]; |
a196ebeb | 104 | |
1f14ecbe AP |
105 | /* Byte 576. End of registers with fixed position in XSAVE. |
106 | The position of other XSAVE registers will be calculated | |
107 | from the appropriate CPUID calls. */ | |
01f9f808 | 108 | |
1f14ecbe AP |
109 | private: |
110 | /* Base address of XSAVE data as an unsigned char *. Used to derive | |
111 | pointers to XSAVE state components in the extended state | |
112 | area. */ | |
113 | unsigned char *xsave () | |
114 | { return reinterpret_cast<unsigned char *> (this); } | |
01f9f808 | 115 | |
1f14ecbe AP |
116 | public: |
117 | /* Memory address of eight upper 128-bit YMM values, or 16 on x86-64. */ | |
118 | unsigned char *ymmh_space () | |
119 | { return xsave () + xsave_layout.avx_offset; } | |
01f9f808 | 120 | |
1f14ecbe AP |
121 | /* Memory address of 4 bound registers values of 128 bits. */ |
122 | unsigned char *bndregs_space () | |
123 | { return xsave () + xsave_layout.bndregs_offset; } | |
01f9f808 | 124 | |
1f14ecbe AP |
125 | /* Memory address of 2 MPX configuration registers of 64 bits |
126 | plus reserved space. */ | |
127 | unsigned char *bndcfg_space () | |
128 | { return xsave () + xsave_layout.bndcfg_offset; } | |
129 | ||
130 | /* Memory address of 8 OpMask register values of 64 bits. */ | |
131 | unsigned char *k_space () | |
132 | { return xsave () + xsave_layout.k_offset; } | |
133 | ||
134 | /* Memory address of 16 256-bit zmm0-15. */ | |
135 | unsigned char *zmmh_space () | |
136 | { return xsave () + xsave_layout.zmm_h_offset; } | |
137 | ||
138 | /* Memory address of 16 512-bit zmm16-31 values. */ | |
139 | unsigned char *zmm16_space () | |
140 | { return xsave () + xsave_layout.zmm_offset; } | |
141 | ||
142 | /* Memory address of 1 32-bit PKRU register. The HW XSTATE size for this | |
143 | feature is actually 64 bits, but WRPKRU/RDPKRU instructions ignore upper | |
144 | 32 bits. */ | |
145 | unsigned char *pkru_space () | |
146 | { return xsave () + xsave_layout.pkru_offset; } | |
1570b33e L |
147 | }; |
148 | ||
69f6730d | 149 | static_assert (sizeof(i387_xsave) == 576); |
1f14ecbe | 150 | |
58caa3dc | 151 | void |
442ea881 | 152 | i387_cache_to_fsave (struct regcache *regcache, void *buf) |
58caa3dc DJ |
153 | { |
154 | struct i387_fsave *fp = (struct i387_fsave *) buf; | |
155 | int i; | |
3aee8918 | 156 | int st0_regnum = find_regno (regcache->tdesc, "st0"); |
cb197132 | 157 | unsigned long val2; |
58caa3dc DJ |
158 | |
159 | for (i = 0; i < 8; i++) | |
442ea881 PA |
160 | collect_register (regcache, i + st0_regnum, |
161 | ((char *) &fp->st_space[0]) + i * 10); | |
58caa3dc | 162 | |
cb197132 PA |
163 | fp->fioff = regcache_raw_get_unsigned_by_name (regcache, "fioff"); |
164 | fp->fooff = regcache_raw_get_unsigned_by_name (regcache, "fooff"); | |
165 | ||
58caa3dc | 166 | /* This one's 11 bits... */ |
cb197132 | 167 | val2 = regcache_raw_get_unsigned_by_name (regcache, "fop"); |
58caa3dc DJ |
168 | fp->fop = (val2 & 0x7FF) | (fp->fop & 0xF800); |
169 | ||
170 | /* Some registers are 16-bit. */ | |
cb197132 PA |
171 | fp->fctrl = regcache_raw_get_unsigned_by_name (regcache, "fctrl"); |
172 | fp->fstat = regcache_raw_get_unsigned_by_name (regcache, "fstat"); | |
173 | fp->ftag = regcache_raw_get_unsigned_by_name (regcache, "ftag"); | |
174 | fp->fiseg = regcache_raw_get_unsigned_by_name (regcache, "fiseg"); | |
175 | fp->foseg = regcache_raw_get_unsigned_by_name (regcache, "foseg"); | |
58caa3dc DJ |
176 | } |
177 | ||
178 | void | |
442ea881 | 179 | i387_fsave_to_cache (struct regcache *regcache, const void *buf) |
58caa3dc DJ |
180 | { |
181 | struct i387_fsave *fp = (struct i387_fsave *) buf; | |
182 | int i; | |
3aee8918 | 183 | int st0_regnum = find_regno (regcache->tdesc, "st0"); |
58caa3dc DJ |
184 | unsigned long val; |
185 | ||
186 | for (i = 0; i < 8; i++) | |
442ea881 PA |
187 | supply_register (regcache, i + st0_regnum, |
188 | ((char *) &fp->st_space[0]) + i * 10); | |
58caa3dc | 189 | |
442ea881 PA |
190 | supply_register_by_name (regcache, "fioff", &fp->fioff); |
191 | supply_register_by_name (regcache, "fooff", &fp->fooff); | |
1b3f6016 | 192 | |
58caa3dc DJ |
193 | /* Some registers are 16-bit. */ |
194 | val = fp->fctrl & 0xFFFF; | |
442ea881 | 195 | supply_register_by_name (regcache, "fctrl", &val); |
58caa3dc DJ |
196 | |
197 | val = fp->fstat & 0xFFFF; | |
442ea881 | 198 | supply_register_by_name (regcache, "fstat", &val); |
58caa3dc DJ |
199 | |
200 | val = fp->ftag & 0xFFFF; | |
442ea881 | 201 | supply_register_by_name (regcache, "ftag", &val); |
58caa3dc DJ |
202 | |
203 | val = fp->fiseg & 0xFFFF; | |
442ea881 | 204 | supply_register_by_name (regcache, "fiseg", &val); |
58caa3dc DJ |
205 | |
206 | val = fp->foseg & 0xFFFF; | |
442ea881 | 207 | supply_register_by_name (regcache, "foseg", &val); |
58caa3dc | 208 | |
0c2ead7e | 209 | /* fop has only 11 valid bits. */ |
58caa3dc | 210 | val = (fp->fop) & 0x7FF; |
442ea881 | 211 | supply_register_by_name (regcache, "fop", &val); |
58caa3dc DJ |
212 | } |
213 | ||
214 | void | |
442ea881 | 215 | i387_cache_to_fxsave (struct regcache *regcache, void *buf) |
58caa3dc DJ |
216 | { |
217 | struct i387_fxsave *fp = (struct i387_fxsave *) buf; | |
218 | int i; | |
3aee8918 PA |
219 | int st0_regnum = find_regno (regcache->tdesc, "st0"); |
220 | int xmm0_regnum = find_regno (regcache->tdesc, "xmm0"); | |
58caa3dc | 221 | unsigned long val, val2; |
3aee8918 PA |
222 | /* Amd64 has 16 xmm regs; I386 has 8 xmm regs. */ |
223 | int num_xmm_registers = register_size (regcache->tdesc, 0) == 8 ? 16 : 8; | |
58caa3dc DJ |
224 | |
225 | for (i = 0; i < 8; i++) | |
442ea881 PA |
226 | collect_register (regcache, i + st0_regnum, |
227 | ((char *) &fp->st_space[0]) + i * 16); | |
58caa3dc | 228 | for (i = 0; i < num_xmm_registers; i++) |
442ea881 PA |
229 | collect_register (regcache, i + xmm0_regnum, |
230 | ((char *) &fp->xmm_space[0]) + i * 16); | |
58caa3dc | 231 | |
cb197132 PA |
232 | fp->fioff = regcache_raw_get_unsigned_by_name (regcache, "fioff"); |
233 | fp->fooff = regcache_raw_get_unsigned_by_name (regcache, "fooff"); | |
234 | fp->mxcsr = regcache_raw_get_unsigned_by_name (regcache, "mxcsr"); | |
1b3f6016 | 235 | |
58caa3dc | 236 | /* This one's 11 bits... */ |
cb197132 | 237 | val2 = regcache_raw_get_unsigned_by_name (regcache, "fop"); |
58caa3dc DJ |
238 | fp->fop = (val2 & 0x7FF) | (fp->fop & 0xF800); |
239 | ||
240 | /* Some registers are 16-bit. */ | |
cb197132 PA |
241 | fp->fctrl = regcache_raw_get_unsigned_by_name (regcache, "fctrl"); |
242 | fp->fstat = regcache_raw_get_unsigned_by_name (regcache, "fstat"); | |
58caa3dc DJ |
243 | |
244 | /* Convert to the simplifed tag form stored in fxsave data. */ | |
cb197132 | 245 | val = regcache_raw_get_unsigned_by_name (regcache, "ftag"); |
73725ff3 | 246 | val2 = 0; |
58caa3dc DJ |
247 | for (i = 7; i >= 0; i--) |
248 | { | |
249 | int tag = (val >> (i * 2)) & 3; | |
250 | ||
251 | if (tag != 3) | |
252 | val2 |= (1 << i); | |
253 | } | |
0c2ead7e | 254 | fp->ftag = val2; |
58caa3dc | 255 | |
cb197132 PA |
256 | fp->fiseg = regcache_raw_get_unsigned_by_name (regcache, "fiseg"); |
257 | fp->foseg = regcache_raw_get_unsigned_by_name (regcache, "foseg"); | |
58caa3dc DJ |
258 | } |
259 | ||
1570b33e L |
260 | void |
261 | i387_cache_to_xsave (struct regcache *regcache, void *buf) | |
262 | { | |
263 | struct i387_xsave *fp = (struct i387_xsave *) buf; | |
2e187550 | 264 | bool amd64 = register_size (regcache->tdesc, 0) == 8; |
1570b33e L |
265 | int i; |
266 | unsigned long val, val2; | |
1570b33e | 267 | unsigned long long xstate_bv = 0; |
ff6527bb | 268 | unsigned long long clear_bv = 0; |
01f9f808 | 269 | char raw[64]; |
1f14ecbe | 270 | unsigned char *p; |
2e187550 | 271 | |
3aee8918 | 272 | /* Amd64 has 16 xmm regs; I386 has 8 xmm regs. */ |
2e187550 | 273 | int num_xmm_registers = amd64 ? 16 : 8; |
2e7b61ed JB |
274 | /* AVX512 adds 16 extra ZMM regs in Amd64 mode, but none in I386 mode.*/ |
275 | int num_zmm_high_registers = amd64 ? 16 : 0; | |
1570b33e | 276 | |
ff6527bb | 277 | /* The supported bits in `xstat_bv' are 8 bytes. Clear part in |
1570b33e L |
278 | vector registers if its bit in xstat_bv is zero. */ |
279 | clear_bv = (~fp->xstate_bv) & x86_xcr0; | |
280 | ||
281 | /* Clear part in x87 and vector registers if its bit in xstat_bv is | |
282 | zero. */ | |
283 | if (clear_bv) | |
284 | { | |
df7e5265 | 285 | if ((clear_bv & X86_XSTATE_X87)) |
8ee22052 AB |
286 | { |
287 | for (i = 0; i < 8; i++) | |
288 | memset (((char *) &fp->st_space[0]) + i * 16, 0, 10); | |
289 | ||
290 | fp->fioff = 0; | |
291 | fp->fooff = 0; | |
292 | fp->fctrl = I387_FCTRL_INIT_VAL; | |
293 | fp->fstat = 0; | |
294 | fp->ftag = 0; | |
295 | fp->fiseg = 0; | |
296 | fp->foseg = 0; | |
297 | fp->fop = 0; | |
298 | } | |
1570b33e | 299 | |
df7e5265 | 300 | if ((clear_bv & X86_XSTATE_SSE)) |
8ee22052 | 301 | for (i = 0; i < num_xmm_registers; i++) |
1570b33e L |
302 | memset (((char *) &fp->xmm_space[0]) + i * 16, 0, 16); |
303 | ||
df7e5265 | 304 | if ((clear_bv & X86_XSTATE_AVX)) |
8ee22052 | 305 | for (i = 0; i < num_xmm_registers; i++) |
1f14ecbe | 306 | memset (fp->ymmh_space () + i * 16, 0, 16); |
a196ebeb | 307 | |
8ee22052 AB |
308 | if ((clear_bv & X86_XSTATE_SSE) && (clear_bv & X86_XSTATE_AVX)) |
309 | memset (((char *) &fp->mxcsr), 0, 4); | |
310 | ||
df7e5265 | 311 | if ((clear_bv & X86_XSTATE_BNDREGS)) |
a196ebeb | 312 | for (i = 0; i < num_mpx_bnd_registers; i++) |
1f14ecbe | 313 | memset (fp->bndregs_space () + i * 16, 0, 16); |
a196ebeb | 314 | |
df7e5265 | 315 | if ((clear_bv & X86_XSTATE_BNDCFG)) |
a196ebeb | 316 | for (i = 0; i < num_mpx_cfg_registers; i++) |
1f14ecbe | 317 | memset (fp->bndcfg_space () + i * 8, 0, 8); |
01f9f808 | 318 | |
df7e5265 | 319 | if ((clear_bv & X86_XSTATE_K)) |
01f9f808 | 320 | for (i = 0; i < num_avx512_k_registers; i++) |
1f14ecbe | 321 | memset (fp->k_space () + i * 8, 0, 8); |
01f9f808 | 322 | |
df7e5265 | 323 | if ((clear_bv & X86_XSTATE_ZMM_H)) |
2e7b61ed | 324 | for (i = 0; i < num_xmm_registers; i++) |
1f14ecbe | 325 | memset (fp->zmmh_space () + i * 32, 0, 32); |
01f9f808 | 326 | |
df7e5265 | 327 | if ((clear_bv & X86_XSTATE_ZMM)) |
2e7b61ed JB |
328 | for (i = 0; i < num_zmm_high_registers; i++) |
329 | memset (fp->zmm16_space () + i * 64, 0, 64); | |
51547df6 MS |
330 | |
331 | if ((clear_bv & X86_XSTATE_PKRU)) | |
332 | for (i = 0; i < num_pkeys_registers; i++) | |
1f14ecbe | 333 | memset (fp->pkru_space () + i * 4, 0, 4); |
1570b33e L |
334 | } |
335 | ||
336 | /* Check if any x87 registers are changed. */ | |
df7e5265 | 337 | if ((x86_xcr0 & X86_XSTATE_X87)) |
1570b33e | 338 | { |
3aee8918 | 339 | int st0_regnum = find_regno (regcache->tdesc, "st0"); |
1570b33e L |
340 | |
341 | for (i = 0; i < 8; i++) | |
342 | { | |
343 | collect_register (regcache, i + st0_regnum, raw); | |
1f14ecbe | 344 | p = fp->st_space + i * 16; |
1570b33e L |
345 | if (memcmp (raw, p, 10)) |
346 | { | |
df7e5265 | 347 | xstate_bv |= X86_XSTATE_X87; |
1570b33e L |
348 | memcpy (p, raw, 10); |
349 | } | |
350 | } | |
351 | } | |
352 | ||
353 | /* Check if any SSE registers are changed. */ | |
df7e5265 | 354 | if ((x86_xcr0 & X86_XSTATE_SSE)) |
1570b33e | 355 | { |
3aee8918 | 356 | int xmm0_regnum = find_regno (regcache->tdesc, "xmm0"); |
1570b33e L |
357 | |
358 | for (i = 0; i < num_xmm_registers; i++) | |
359 | { | |
360 | collect_register (regcache, i + xmm0_regnum, raw); | |
1f14ecbe | 361 | p = fp->xmm_space + i * 16; |
1570b33e L |
362 | if (memcmp (raw, p, 16)) |
363 | { | |
df7e5265 | 364 | xstate_bv |= X86_XSTATE_SSE; |
1570b33e L |
365 | memcpy (p, raw, 16); |
366 | } | |
367 | } | |
368 | } | |
369 | ||
370 | /* Check if any AVX registers are changed. */ | |
df7e5265 | 371 | if ((x86_xcr0 & X86_XSTATE_AVX)) |
1570b33e | 372 | { |
3aee8918 | 373 | int ymm0h_regnum = find_regno (regcache->tdesc, "ymm0h"); |
1570b33e L |
374 | |
375 | for (i = 0; i < num_xmm_registers; i++) | |
376 | { | |
377 | collect_register (regcache, i + ymm0h_regnum, raw); | |
1f14ecbe | 378 | p = fp->ymmh_space () + i * 16; |
1570b33e L |
379 | if (memcmp (raw, p, 16)) |
380 | { | |
df7e5265 | 381 | xstate_bv |= X86_XSTATE_AVX; |
1570b33e L |
382 | memcpy (p, raw, 16); |
383 | } | |
384 | } | |
385 | } | |
386 | ||
a196ebeb | 387 | /* Check if any bound register has changed. */ |
df7e5265 | 388 | if ((x86_xcr0 & X86_XSTATE_BNDREGS)) |
a196ebeb WT |
389 | { |
390 | int bnd0r_regnum = find_regno (regcache->tdesc, "bnd0raw"); | |
391 | ||
392 | for (i = 0; i < num_mpx_bnd_registers; i++) | |
393 | { | |
394 | collect_register (regcache, i + bnd0r_regnum, raw); | |
1f14ecbe | 395 | p = fp->bndregs_space () + i * 16; |
a196ebeb WT |
396 | if (memcmp (raw, p, 16)) |
397 | { | |
df7e5265 | 398 | xstate_bv |= X86_XSTATE_BNDREGS; |
a196ebeb WT |
399 | memcpy (p, raw, 16); |
400 | } | |
401 | } | |
402 | } | |
403 | ||
404 | /* Check if any status register has changed. */ | |
df7e5265 | 405 | if ((x86_xcr0 & X86_XSTATE_BNDCFG)) |
a196ebeb WT |
406 | { |
407 | int bndcfg_regnum = find_regno (regcache->tdesc, "bndcfgu"); | |
408 | ||
409 | for (i = 0; i < num_mpx_cfg_registers; i++) | |
410 | { | |
411 | collect_register (regcache, i + bndcfg_regnum, raw); | |
1f14ecbe | 412 | p = fp->bndcfg_space () + i * 8; |
a196ebeb WT |
413 | if (memcmp (raw, p, 8)) |
414 | { | |
df7e5265 | 415 | xstate_bv |= X86_XSTATE_BNDCFG; |
a196ebeb WT |
416 | memcpy (p, raw, 8); |
417 | } | |
418 | } | |
419 | } | |
420 | ||
01f9f808 | 421 | /* Check if any K registers are changed. */ |
df7e5265 | 422 | if ((x86_xcr0 & X86_XSTATE_K)) |
01f9f808 MS |
423 | { |
424 | int k0_regnum = find_regno (regcache->tdesc, "k0"); | |
425 | ||
426 | for (i = 0; i < num_avx512_k_registers; i++) | |
427 | { | |
428 | collect_register (regcache, i + k0_regnum, raw); | |
1f14ecbe | 429 | p = fp->k_space () + i * 8; |
01f9f808 MS |
430 | if (memcmp (raw, p, 8) != 0) |
431 | { | |
df7e5265 | 432 | xstate_bv |= X86_XSTATE_K; |
01f9f808 MS |
433 | memcpy (p, raw, 8); |
434 | } | |
435 | } | |
436 | } | |
437 | ||
438 | /* Check if any of ZMM0H-ZMM15H registers are changed. */ | |
df7e5265 | 439 | if ((x86_xcr0 & X86_XSTATE_ZMM_H)) |
01f9f808 MS |
440 | { |
441 | int zmm0h_regnum = find_regno (regcache->tdesc, "zmm0h"); | |
442 | ||
2e7b61ed | 443 | for (i = 0; i < num_xmm_registers; i++) |
01f9f808 MS |
444 | { |
445 | collect_register (regcache, i + zmm0h_regnum, raw); | |
1f14ecbe | 446 | p = fp->zmmh_space () + i * 32; |
01f9f808 MS |
447 | if (memcmp (raw, p, 32) != 0) |
448 | { | |
df7e5265 | 449 | xstate_bv |= X86_XSTATE_ZMM_H; |
01f9f808 MS |
450 | memcpy (p, raw, 32); |
451 | } | |
452 | } | |
453 | } | |
454 | ||
2e7b61ed JB |
455 | /* Check if any of ZMM16-ZMM31 registers are changed. */ |
456 | if ((x86_xcr0 & X86_XSTATE_ZMM) && num_zmm_high_registers != 0) | |
01f9f808 | 457 | { |
2e7b61ed JB |
458 | int zmm16h_regnum = find_regno (regcache->tdesc, "zmm16h"); |
459 | int ymm16h_regnum = find_regno (regcache->tdesc, "ymm16h"); | |
460 | int xmm16_regnum = find_regno (regcache->tdesc, "xmm16"); | |
01f9f808 | 461 | |
2e7b61ed | 462 | for (i = 0; i < num_zmm_high_registers; i++) |
01f9f808 | 463 | { |
2e7b61ed JB |
464 | p = fp->zmm16_space () + i * 64; |
465 | ||
466 | /* ZMMH sub-register. */ | |
01f9f808 | 467 | collect_register (regcache, i + zmm16h_regnum, raw); |
2e7b61ed | 468 | if (memcmp (raw, p + 32, 32) != 0) |
01f9f808 | 469 | { |
df7e5265 | 470 | xstate_bv |= X86_XSTATE_ZMM; |
41770089 | 471 | memcpy (p + 32, raw, 32); |
01f9f808 | 472 | } |
01f9f808 | 473 | |
2e7b61ed JB |
474 | /* YMMH sub-register. */ |
475 | collect_register (regcache, i + ymm16h_regnum, raw); | |
476 | if (memcmp (raw, p + 16, 16) != 0) | |
01f9f808 | 477 | { |
df7e5265 | 478 | xstate_bv |= X86_XSTATE_ZMM; |
41770089 | 479 | memcpy (p + 16, raw, 16); |
01f9f808 | 480 | } |
01f9f808 | 481 | |
2e7b61ed JB |
482 | /* XMM sub-register. */ |
483 | collect_register (regcache, i + xmm16_regnum, raw); | |
01f9f808 MS |
484 | if (memcmp (raw, p, 16) != 0) |
485 | { | |
df7e5265 | 486 | xstate_bv |= X86_XSTATE_ZMM; |
01f9f808 MS |
487 | memcpy (p, raw, 16); |
488 | } | |
489 | } | |
490 | } | |
491 | ||
51547df6 MS |
492 | /* Check if any PKEYS registers are changed. */ |
493 | if ((x86_xcr0 & X86_XSTATE_PKRU)) | |
494 | { | |
495 | int pkru_regnum = find_regno (regcache->tdesc, "pkru"); | |
496 | ||
497 | for (i = 0; i < num_pkeys_registers; i++) | |
498 | { | |
499 | collect_register (regcache, i + pkru_regnum, raw); | |
1f14ecbe | 500 | p = fp->pkru_space () + i * 4; |
51547df6 MS |
501 | if (memcmp (raw, p, 4) != 0) |
502 | { | |
503 | xstate_bv |= X86_XSTATE_PKRU; | |
504 | memcpy (p, raw, 4); | |
505 | } | |
506 | } | |
507 | } | |
508 | ||
8ee22052 AB |
509 | if ((x86_xcr0 & X86_XSTATE_SSE) || (x86_xcr0 & X86_XSTATE_AVX)) |
510 | { | |
511 | collect_register_by_name (regcache, "mxcsr", raw); | |
512 | if (memcmp (raw, &fp->mxcsr, 4) != 0) | |
513 | { | |
514 | if (((fp->xstate_bv | xstate_bv) | |
515 | & (X86_XSTATE_SSE | X86_XSTATE_AVX)) == 0) | |
516 | xstate_bv |= X86_XSTATE_SSE; | |
517 | memcpy (&fp->mxcsr, raw, 4); | |
518 | } | |
519 | } | |
1570b33e | 520 | |
8ee22052 AB |
521 | if (x86_xcr0 & X86_XSTATE_X87) |
522 | { | |
523 | collect_register_by_name (regcache, "fioff", raw); | |
524 | if (memcmp (raw, &fp->fioff, 4) != 0) | |
525 | { | |
526 | xstate_bv |= X86_XSTATE_X87; | |
527 | memcpy (&fp->fioff, raw, 4); | |
528 | } | |
1570b33e | 529 | |
8ee22052 AB |
530 | collect_register_by_name (regcache, "fooff", raw); |
531 | if (memcmp (raw, &fp->fooff, 4) != 0) | |
532 | { | |
533 | xstate_bv |= X86_XSTATE_X87; | |
534 | memcpy (&fp->fooff, raw, 4); | |
535 | } | |
1570b33e | 536 | |
8ee22052 | 537 | /* This one's 11 bits... */ |
cb197132 | 538 | val2 = regcache_raw_get_unsigned_by_name (regcache, "fop"); |
8ee22052 AB |
539 | val2 = (val2 & 0x7FF) | (fp->fop & 0xF800); |
540 | if (fp->fop != val2) | |
541 | { | |
542 | xstate_bv |= X86_XSTATE_X87; | |
543 | fp->fop = val2; | |
544 | } | |
1570b33e | 545 | |
8ee22052 | 546 | /* Some registers are 16-bit. */ |
cb197132 | 547 | val = regcache_raw_get_unsigned_by_name (regcache, "fctrl"); |
8ee22052 AB |
548 | if (fp->fctrl != val) |
549 | { | |
550 | xstate_bv |= X86_XSTATE_X87; | |
551 | fp->fctrl = val; | |
552 | } | |
1570b33e | 553 | |
cb197132 | 554 | val = regcache_raw_get_unsigned_by_name (regcache, "fstat"); |
8ee22052 AB |
555 | if (fp->fstat != val) |
556 | { | |
557 | xstate_bv |= X86_XSTATE_X87; | |
558 | fp->fstat = val; | |
559 | } | |
1570b33e | 560 | |
8ee22052 | 561 | /* Convert to the simplifed tag form stored in fxsave data. */ |
cb197132 | 562 | val = regcache_raw_get_unsigned_by_name (regcache, "ftag"); |
8ee22052 AB |
563 | val2 = 0; |
564 | for (i = 7; i >= 0; i--) | |
565 | { | |
566 | int tag = (val >> (i * 2)) & 3; | |
1570b33e | 567 | |
8ee22052 AB |
568 | if (tag != 3) |
569 | val2 |= (1 << i); | |
570 | } | |
571 | if (fp->ftag != val2) | |
572 | { | |
573 | xstate_bv |= X86_XSTATE_X87; | |
574 | fp->ftag = val2; | |
575 | } | |
1570b33e | 576 | |
cb197132 | 577 | val = regcache_raw_get_unsigned_by_name (regcache, "fiseg"); |
8ee22052 AB |
578 | if (fp->fiseg != val) |
579 | { | |
580 | xstate_bv |= X86_XSTATE_X87; | |
581 | fp->fiseg = val; | |
582 | } | |
583 | ||
cb197132 | 584 | val = regcache_raw_get_unsigned_by_name (regcache, "foseg"); |
8ee22052 AB |
585 | if (fp->foseg != val) |
586 | { | |
587 | xstate_bv |= X86_XSTATE_X87; | |
588 | fp->foseg = val; | |
589 | } | |
590 | } | |
591 | ||
592 | /* Update the corresponding bits in xstate_bv if any SSE/AVX | |
593 | registers are changed. */ | |
594 | fp->xstate_bv |= xstate_bv; | |
1570b33e L |
595 | } |
596 | ||
58caa3dc DJ |
597 | static int |
598 | i387_ftag (struct i387_fxsave *fp, int regno) | |
599 | { | |
600 | unsigned char *raw = &fp->st_space[regno * 16]; | |
601 | unsigned int exponent; | |
602 | unsigned long fraction[2]; | |
603 | int integer; | |
604 | ||
605 | integer = raw[7] & 0x80; | |
606 | exponent = (((raw[9] & 0x7f) << 8) | raw[8]); | |
607 | fraction[0] = ((raw[3] << 24) | (raw[2] << 16) | (raw[1] << 8) | raw[0]); | |
608 | fraction[1] = (((raw[7] & 0x7f) << 24) | (raw[6] << 16) | |
1b3f6016 | 609 | | (raw[5] << 8) | raw[4]); |
58caa3dc DJ |
610 | |
611 | if (exponent == 0x7fff) | |
612 | { | |
613 | /* Special. */ | |
614 | return (2); | |
615 | } | |
616 | else if (exponent == 0x0000) | |
617 | { | |
618 | if (fraction[0] == 0x0000 && fraction[1] == 0x0000 && !integer) | |
1b3f6016 PA |
619 | { |
620 | /* Zero. */ | |
621 | return (1); | |
622 | } | |
58caa3dc | 623 | else |
1b3f6016 PA |
624 | { |
625 | /* Special. */ | |
626 | return (2); | |
627 | } | |
58caa3dc DJ |
628 | } |
629 | else | |
630 | { | |
631 | if (integer) | |
1b3f6016 PA |
632 | { |
633 | /* Valid. */ | |
634 | return (0); | |
635 | } | |
58caa3dc | 636 | else |
1b3f6016 PA |
637 | { |
638 | /* Special. */ | |
639 | return (2); | |
640 | } | |
58caa3dc DJ |
641 | } |
642 | } | |
643 | ||
644 | void | |
442ea881 | 645 | i387_fxsave_to_cache (struct regcache *regcache, const void *buf) |
58caa3dc DJ |
646 | { |
647 | struct i387_fxsave *fp = (struct i387_fxsave *) buf; | |
648 | int i, top; | |
3aee8918 PA |
649 | int st0_regnum = find_regno (regcache->tdesc, "st0"); |
650 | int xmm0_regnum = find_regno (regcache->tdesc, "xmm0"); | |
58caa3dc | 651 | unsigned long val; |
3aee8918 PA |
652 | /* Amd64 has 16 xmm regs; I386 has 8 xmm regs. */ |
653 | int num_xmm_registers = register_size (regcache->tdesc, 0) == 8 ? 16 : 8; | |
58caa3dc DJ |
654 | |
655 | for (i = 0; i < 8; i++) | |
442ea881 PA |
656 | supply_register (regcache, i + st0_regnum, |
657 | ((char *) &fp->st_space[0]) + i * 16); | |
58caa3dc | 658 | for (i = 0; i < num_xmm_registers; i++) |
442ea881 PA |
659 | supply_register (regcache, i + xmm0_regnum, |
660 | ((char *) &fp->xmm_space[0]) + i * 16); | |
58caa3dc | 661 | |
442ea881 PA |
662 | supply_register_by_name (regcache, "fioff", &fp->fioff); |
663 | supply_register_by_name (regcache, "fooff", &fp->fooff); | |
664 | supply_register_by_name (regcache, "mxcsr", &fp->mxcsr); | |
1b3f6016 | 665 | |
58caa3dc DJ |
666 | /* Some registers are 16-bit. */ |
667 | val = fp->fctrl & 0xFFFF; | |
442ea881 | 668 | supply_register_by_name (regcache, "fctrl", &val); |
58caa3dc DJ |
669 | |
670 | val = fp->fstat & 0xFFFF; | |
442ea881 | 671 | supply_register_by_name (regcache, "fstat", &val); |
58caa3dc DJ |
672 | |
673 | /* Generate the form of ftag data that GDB expects. */ | |
674 | top = (fp->fstat >> 11) & 0x7; | |
675 | val = 0; | |
676 | for (i = 7; i >= 0; i--) | |
677 | { | |
678 | int tag; | |
73725ff3 | 679 | if (fp->ftag & (1 << i)) |
58caa3dc DJ |
680 | tag = i387_ftag (fp, (i + 8 - top) % 8); |
681 | else | |
682 | tag = 3; | |
683 | val |= tag << (2 * i); | |
684 | } | |
442ea881 | 685 | supply_register_by_name (regcache, "ftag", &val); |
58caa3dc DJ |
686 | |
687 | val = fp->fiseg & 0xFFFF; | |
442ea881 | 688 | supply_register_by_name (regcache, "fiseg", &val); |
58caa3dc DJ |
689 | |
690 | val = fp->foseg & 0xFFFF; | |
442ea881 | 691 | supply_register_by_name (regcache, "foseg", &val); |
58caa3dc DJ |
692 | |
693 | val = (fp->fop) & 0x7FF; | |
442ea881 | 694 | supply_register_by_name (regcache, "fop", &val); |
58caa3dc | 695 | } |
1570b33e L |
696 | |
697 | void | |
698 | i387_xsave_to_cache (struct regcache *regcache, const void *buf) | |
699 | { | |
700 | struct i387_xsave *fp = (struct i387_xsave *) buf; | |
2e187550 | 701 | bool amd64 = register_size (regcache->tdesc, 0) == 8; |
1570b33e L |
702 | int i, top; |
703 | unsigned long val; | |
ff6527bb | 704 | unsigned long long clear_bv; |
1f14ecbe | 705 | unsigned char *p; |
2e187550 TV |
706 | |
707 | /* Amd64 has 16 xmm regs; I386 has 8 xmm regs. */ | |
708 | int num_xmm_registers = amd64 ? 16 : 8; | |
2e7b61ed JB |
709 | /* AVX512 adds 16 extra ZMM regs in Amd64 mode, but none in I386 mode.*/ |
710 | int num_zmm_high_registers = amd64 ? 16 : 0; | |
1570b33e | 711 | |
ff6527bb | 712 | /* The supported bits in `xstat_bv' are 8 bytes. Clear part in |
1570b33e L |
713 | vector registers if its bit in xstat_bv is zero. */ |
714 | clear_bv = (~fp->xstate_bv) & x86_xcr0; | |
715 | ||
716 | /* Check if any x87 registers are changed. */ | |
df7e5265 | 717 | if ((x86_xcr0 & X86_XSTATE_X87) != 0) |
1570b33e | 718 | { |
3aee8918 | 719 | int st0_regnum = find_regno (regcache->tdesc, "st0"); |
1570b33e | 720 | |
df7e5265 | 721 | if ((clear_bv & X86_XSTATE_X87) != 0) |
85724a0e PA |
722 | { |
723 | for (i = 0; i < 8; i++) | |
1c79eb8a | 724 | supply_register_zeroed (regcache, i + st0_regnum); |
85724a0e | 725 | } |
1570b33e | 726 | else |
1570b33e | 727 | { |
85724a0e PA |
728 | p = (gdb_byte *) &fp->st_space[0]; |
729 | for (i = 0; i < 8; i++) | |
730 | supply_register (regcache, i + st0_regnum, p + i * 16); | |
1570b33e L |
731 | } |
732 | } | |
733 | ||
df7e5265 | 734 | if ((x86_xcr0 & X86_XSTATE_SSE) != 0) |
1570b33e | 735 | { |
3aee8918 | 736 | int xmm0_regnum = find_regno (regcache->tdesc, "xmm0"); |
1570b33e | 737 | |
df7e5265 | 738 | if ((clear_bv & X86_XSTATE_SSE)) |
85724a0e PA |
739 | { |
740 | for (i = 0; i < num_xmm_registers; i++) | |
1c79eb8a | 741 | supply_register_zeroed (regcache, i + xmm0_regnum); |
85724a0e | 742 | } |
1570b33e | 743 | else |
1570b33e | 744 | { |
85724a0e PA |
745 | p = (gdb_byte *) &fp->xmm_space[0]; |
746 | for (i = 0; i < num_xmm_registers; i++) | |
747 | supply_register (regcache, i + xmm0_regnum, p + i * 16); | |
1570b33e L |
748 | } |
749 | } | |
750 | ||
df7e5265 | 751 | if ((x86_xcr0 & X86_XSTATE_AVX) != 0) |
1570b33e | 752 | { |
3aee8918 | 753 | int ymm0h_regnum = find_regno (regcache->tdesc, "ymm0h"); |
1570b33e | 754 | |
df7e5265 | 755 | if ((clear_bv & X86_XSTATE_AVX) != 0) |
85724a0e PA |
756 | { |
757 | for (i = 0; i < num_xmm_registers; i++) | |
1c79eb8a | 758 | supply_register_zeroed (regcache, i + ymm0h_regnum); |
85724a0e | 759 | } |
1570b33e | 760 | else |
1570b33e | 761 | { |
1f14ecbe | 762 | p = fp->ymmh_space (); |
85724a0e PA |
763 | for (i = 0; i < num_xmm_registers; i++) |
764 | supply_register (regcache, i + ymm0h_regnum, p + i * 16); | |
1570b33e L |
765 | } |
766 | } | |
767 | ||
df7e5265 | 768 | if ((x86_xcr0 & X86_XSTATE_BNDREGS)) |
a196ebeb WT |
769 | { |
770 | int bnd0r_regnum = find_regno (regcache->tdesc, "bnd0raw"); | |
771 | ||
772 | ||
df7e5265 | 773 | if ((clear_bv & X86_XSTATE_BNDREGS) != 0) |
a196ebeb WT |
774 | { |
775 | for (i = 0; i < num_mpx_bnd_registers; i++) | |
776 | supply_register_zeroed (regcache, i + bnd0r_regnum); | |
777 | } | |
778 | else | |
779 | { | |
1f14ecbe | 780 | p = fp->bndregs_space (); |
a196ebeb WT |
781 | for (i = 0; i < num_mpx_bnd_registers; i++) |
782 | supply_register (regcache, i + bnd0r_regnum, p + i * 16); | |
783 | } | |
784 | ||
785 | } | |
786 | ||
df7e5265 | 787 | if ((x86_xcr0 & X86_XSTATE_BNDCFG)) |
a196ebeb WT |
788 | { |
789 | int bndcfg_regnum = find_regno (regcache->tdesc, "bndcfgu"); | |
790 | ||
df7e5265 | 791 | if ((clear_bv & X86_XSTATE_BNDCFG) != 0) |
a196ebeb WT |
792 | { |
793 | for (i = 0; i < num_mpx_cfg_registers; i++) | |
794 | supply_register_zeroed (regcache, i + bndcfg_regnum); | |
795 | } | |
796 | else | |
797 | { | |
1f14ecbe | 798 | p = fp->bndcfg_space (); |
a196ebeb WT |
799 | for (i = 0; i < num_mpx_cfg_registers; i++) |
800 | supply_register (regcache, i + bndcfg_regnum, p + i * 8); | |
801 | } | |
802 | } | |
803 | ||
df7e5265 | 804 | if ((x86_xcr0 & X86_XSTATE_K) != 0) |
01f9f808 MS |
805 | { |
806 | int k0_regnum = find_regno (regcache->tdesc, "k0"); | |
807 | ||
df7e5265 | 808 | if ((clear_bv & X86_XSTATE_K) != 0) |
01f9f808 MS |
809 | { |
810 | for (i = 0; i < num_avx512_k_registers; i++) | |
811 | supply_register_zeroed (regcache, i + k0_regnum); | |
812 | } | |
813 | else | |
814 | { | |
1f14ecbe | 815 | p = fp->k_space (); |
01f9f808 MS |
816 | for (i = 0; i < num_avx512_k_registers; i++) |
817 | supply_register (regcache, i + k0_regnum, p + i * 8); | |
818 | } | |
819 | } | |
820 | ||
df7e5265 | 821 | if ((x86_xcr0 & X86_XSTATE_ZMM_H) != 0) |
01f9f808 MS |
822 | { |
823 | int zmm0h_regnum = find_regno (regcache->tdesc, "zmm0h"); | |
824 | ||
df7e5265 | 825 | if ((clear_bv & X86_XSTATE_ZMM_H) != 0) |
01f9f808 | 826 | { |
2e7b61ed | 827 | for (i = 0; i < num_xmm_registers; i++) |
01f9f808 MS |
828 | supply_register_zeroed (regcache, i + zmm0h_regnum); |
829 | } | |
830 | else | |
831 | { | |
1f14ecbe | 832 | p = fp->zmmh_space (); |
2e7b61ed | 833 | for (i = 0; i < num_xmm_registers; i++) |
01f9f808 MS |
834 | supply_register (regcache, i + zmm0h_regnum, p + i * 32); |
835 | } | |
836 | } | |
837 | ||
2e7b61ed | 838 | if ((x86_xcr0 & X86_XSTATE_ZMM) != 0 && num_zmm_high_registers != 0) |
01f9f808 | 839 | { |
2e7b61ed JB |
840 | int zmm16h_regnum = find_regno (regcache->tdesc, "zmm16h"); |
841 | int ymm16h_regnum = find_regno (regcache->tdesc, "ymm16h"); | |
842 | int xmm16_regnum = find_regno (regcache->tdesc, "xmm16"); | |
01f9f808 | 843 | |
df7e5265 | 844 | if ((clear_bv & X86_XSTATE_ZMM) != 0) |
01f9f808 | 845 | { |
2e7b61ed JB |
846 | for (i = 0; i < num_zmm_high_registers; i++) |
847 | { | |
848 | supply_register_zeroed (regcache, i + zmm16h_regnum); | |
849 | supply_register_zeroed (regcache, i + ymm16h_regnum); | |
850 | supply_register_zeroed (regcache, i + xmm16_regnum); | |
851 | } | |
01f9f808 MS |
852 | } |
853 | else | |
854 | { | |
1f14ecbe | 855 | p = fp->zmm16_space (); |
2e7b61ed JB |
856 | for (i = 0; i < num_zmm_high_registers; i++) |
857 | { | |
858 | supply_register (regcache, i + zmm16h_regnum, p + 32 + i * 64); | |
859 | supply_register (regcache, i + ymm16h_regnum, p + 16 + i * 64); | |
860 | supply_register (regcache, i + xmm16_regnum, p + i * 64); | |
861 | } | |
01f9f808 MS |
862 | } |
863 | } | |
864 | ||
51547df6 MS |
865 | if ((x86_xcr0 & X86_XSTATE_PKRU) != 0) |
866 | { | |
867 | int pkru_regnum = find_regno (regcache->tdesc, "pkru"); | |
868 | ||
869 | if ((clear_bv & X86_XSTATE_PKRU) != 0) | |
870 | { | |
871 | for (i = 0; i < num_pkeys_registers; i++) | |
872 | supply_register_zeroed (regcache, i + pkru_regnum); | |
873 | } | |
874 | else | |
875 | { | |
1f14ecbe | 876 | p = fp->pkru_space (); |
51547df6 MS |
877 | for (i = 0; i < num_pkeys_registers; i++) |
878 | supply_register (regcache, i + pkru_regnum, p + i * 4); | |
879 | } | |
880 | } | |
881 | ||
8ee22052 AB |
882 | if ((clear_bv & (X86_XSTATE_SSE | X86_XSTATE_AVX)) |
883 | == (X86_XSTATE_SSE | X86_XSTATE_AVX)) | |
884 | { | |
885 | unsigned int default_mxcsr = I387_MXCSR_INIT_VAL; | |
886 | supply_register_by_name (regcache, "mxcsr", &default_mxcsr); | |
887 | } | |
888 | else | |
889 | supply_register_by_name (regcache, "mxcsr", &fp->mxcsr); | |
1570b33e | 890 | |
8ee22052 AB |
891 | if ((clear_bv & X86_XSTATE_X87) != 0) |
892 | { | |
893 | supply_register_by_name_zeroed (regcache, "fioff"); | |
894 | supply_register_by_name_zeroed (regcache, "fooff"); | |
1570b33e | 895 | |
8ee22052 AB |
896 | val = I387_FCTRL_INIT_VAL; |
897 | supply_register_by_name (regcache, "fctrl", &val); | |
1570b33e | 898 | |
8ee22052 AB |
899 | supply_register_by_name_zeroed (regcache, "fstat"); |
900 | ||
901 | val = 0xFFFF; | |
902 | supply_register_by_name (regcache, "ftag", &val); | |
903 | ||
904 | supply_register_by_name_zeroed (regcache, "fiseg"); | |
905 | supply_register_by_name_zeroed (regcache, "foseg"); | |
906 | supply_register_by_name_zeroed (regcache, "fop"); | |
1570b33e | 907 | } |
8ee22052 AB |
908 | else |
909 | { | |
910 | supply_register_by_name (regcache, "fioff", &fp->fioff); | |
911 | supply_register_by_name (regcache, "fooff", &fp->fooff); | |
1570b33e | 912 | |
8ee22052 AB |
913 | /* Some registers are 16-bit. */ |
914 | val = fp->fctrl & 0xFFFF; | |
915 | supply_register_by_name (regcache, "fctrl", &val); | |
1570b33e | 916 | |
8ee22052 AB |
917 | val = fp->fstat & 0xFFFF; |
918 | supply_register_by_name (regcache, "fstat", &val); | |
1570b33e | 919 | |
8ee22052 AB |
920 | /* Generate the form of ftag data that GDB expects. */ |
921 | top = (fp->fstat >> 11) & 0x7; | |
922 | val = 0; | |
923 | for (i = 7; i >= 0; i--) | |
924 | { | |
925 | int tag; | |
926 | if (fp->ftag & (1 << i)) | |
c0c43317 | 927 | tag = i387_ftag (fp, (i + 8 - top) % 8); |
8ee22052 AB |
928 | else |
929 | tag = 3; | |
930 | val |= tag << (2 * i); | |
931 | } | |
932 | supply_register_by_name (regcache, "ftag", &val); | |
933 | ||
934 | val = fp->fiseg & 0xFFFF; | |
935 | supply_register_by_name (regcache, "fiseg", &val); | |
936 | ||
937 | val = fp->foseg & 0xFFFF; | |
938 | supply_register_by_name (regcache, "foseg", &val); | |
939 | ||
940 | val = (fp->fop) & 0x7FF; | |
941 | supply_register_by_name (regcache, "fop", &val); | |
942 | } | |
1570b33e L |
943 | } |
944 | ||
03e6fe7e JB |
945 | /* See i387-fp.h. */ |
946 | ||
947 | void | |
948 | i387_set_xsave_mask (uint64_t xcr0, int len) | |
949 | { | |
950 | x86_xcr0 = xcr0; | |
951 | xsave_layout = x86_fetch_xsave_layout (xcr0, len); | |
952 | } |