1 /////////////////////////////////////////////////////////////////////////
2 // $Id: xsave.cc 14326 2021-07-27 15:36:11Z vruppert $
3 /////////////////////////////////////////////////////////////////////////
4 //
5 // Copyright (c) 2008-2019 Stanislav Shwartsman
6 // Written by Stanislav Shwartsman [sshwarts at sourceforge net]
7 //
8 // This library is free software; you can redistribute it and/or
9 // modify it under the terms of the GNU Lesser General Public
10 // License as published by the Free Software Foundation; either
11 // version 2 of the License, or (at your option) any later version.
12 //
13 // This library is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 // Lesser General Public License for more details.
17 //
18 // You should have received a copy of the GNU Lesser General Public
19 // License along with this library; if not, write to the Free Software
20 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA B 02110-1301 USA
21 //
22 /////////////////////////////////////////////////////////////////////////
23
24 #define NEED_CPU_REG_SHORTCUTS 1
25 #include "bochs.h"
26 #include "cpu.h"
27 #include "msr.h"
28 #define LOG_THIS BX_CPU_THIS_PTR
29
30 #include "decoder/ia_opcodes.h"
31
32 const Bit64u XSAVEC_COMPACTION_ENABLED = BX_CONST64(0x8000000000000000);
33
34 #if BX_CPU_LEVEL >= 6
35 extern XSaveRestoreStateHelper xsave_restore[];
36 #endif
37
38 #if BX_USE_CPU_SMF == 0
39 #define CALL_XSAVE_FN(ptrToFunc) (this->*(ptrToFunc))
40 #else
41 #define CALL_XSAVE_FN(ptrToFunc) (ptrToFunc)
42 #endif
43
44 /* 0F AE /4 */
XSAVE(bxInstruction_c * i)45 void BX_CPP_AttrRegparmN(1) BX_CPU_C::XSAVE(bxInstruction_c *i)
46 {
47 #if BX_CPU_LEVEL >= 6
48 BX_CPU_THIS_PTR prepareXSAVE();
49
50 bool xsaveopt = (i->getIaOpcode() == BX_IA_XSAVEOPT);
51
52 BX_DEBUG(("%s: save processor state XCR0=0x%08x", i->getIaOpcodeNameShort(), BX_CPU_THIS_PTR xcr0.get32()));
53
54 bx_address eaddr = BX_CPU_RESOLVE_ADDR(i);
55 bx_address laddr = get_laddr(i->seg(), eaddr);
56
57 #if BX_SUPPORT_ALIGNMENT_CHECK && BX_CPU_LEVEL >= 4
58 if (BX_CPU_THIS_PTR alignment_check()) {
59 if (laddr & 0x3) {
60 BX_ERROR(("%s: access not aligned to 4-byte cause model specific #AC(0)", i->getIaOpcodeNameShort()));
61 exception(BX_AC_EXCEPTION, 0);
62 }
63 }
64 #endif
65
66 if (laddr & 0x3f) {
67 BX_ERROR(("%s: access not aligned to 64-byte", i->getIaOpcodeNameShort()));
68 exception(BX_GP_EXCEPTION, 0);
69 }
70
71 bx_address asize_mask = i->asize_mask();
72
73 Bit64u xstate_bv = read_virtual_qword(i->seg(), (eaddr + 512) & asize_mask);
74
75 Bit32u requested_feature_bitmap = BX_CPU_THIS_PTR xcr0.get32() & EAX;
76 Bit32u xinuse = get_xinuse_vector(requested_feature_bitmap);
77
78 /////////////////////////////////////////////////////////////////////////////
79 if ((requested_feature_bitmap & BX_XCR0_FPU_MASK) != 0)
80 {
81 if (! xsaveopt || (xinuse & BX_XCR0_FPU_MASK) != 0)
82 xsave_x87_state(i, eaddr);
83
84 if (xinuse & BX_XCR0_FPU_MASK)
85 xstate_bv |= BX_XCR0_FPU_MASK;
86 else
87 xstate_bv &= ~BX_XCR0_FPU_MASK;
88 }
89
90 /////////////////////////////////////////////////////////////////////////////
91 if ((requested_feature_bitmap & (BX_XCR0_SSE_MASK | BX_XCR0_YMM_MASK)) != 0)
92 {
93 // store MXCSR - write cannot cause any boundary cross because XSAVE image is 64-byte aligned
94 write_virtual_dword(i->seg(), eaddr + 24, BX_MXCSR_REGISTER);
95 write_virtual_dword(i->seg(), eaddr + 28, MXCSR_MASK);
96 }
97
98 /////////////////////////////////////////////////////////////////////////////
99 for (unsigned feature = xcr0_t::BX_XCR0_SSE_BIT; feature < xcr0_t::BX_XCR0_LAST; feature++)
100 {
101 Bit32u feature_mask = (1 << feature);
102
103 if ((requested_feature_bitmap & feature_mask) != 0)
104 {
105 if (! xsave_restore[feature].len) {
106 BX_ERROR(("%s: feature #%d requested to save but not implemented !", i->getIaOpcodeNameShort(), feature));
107 continue;
108 }
109
110 if (! xsaveopt || (xinuse & feature_mask) != 0) {
111 BX_ASSERT(xsave_restore[feature].xsave_method);
112 CALL_XSAVE_FN(xsave_restore[feature].xsave_method)(i, eaddr+xsave_restore[feature].offset);
113 }
114
115 if (xinuse & feature_mask)
116 xstate_bv |= Bit64u(feature_mask);
117 else
118 xstate_bv &= ~Bit64u(feature_mask);
119 }
120 }
121
122 // always update header to 'dirty' state
123 write_virtual_qword(i->seg(), (eaddr + 512) & asize_mask, xstate_bv);
124 #endif
125
126 BX_NEXT_INSTR(i);
127 }
128
129 /* 0F C7 /4 */
XSAVEC(bxInstruction_c * i)130 void BX_CPP_AttrRegparmN(1) BX_CPU_C::XSAVEC(bxInstruction_c *i)
131 {
132 #if BX_CPU_LEVEL >= 6
133 BX_CPU_THIS_PTR prepareXSAVE();
134
135 bool xsaves = (i->getIaOpcode() == BX_IA_XSAVES);
136 if (xsaves) {
137 if (CPL != 0) {
138 BX_ERROR(("%s: with CPL != 0", i->getIaOpcodeNameShort()));
139 exception(BX_GP_EXCEPTION, 0);
140 }
141
142 #if BX_SUPPORT_VMX >= 2
143 if (BX_CPU_THIS_PTR in_vmx_guest) {
144 if (! SECONDARY_VMEXEC_CONTROL(VMX_VM_EXEC_CTRL3_XSAVES_XRSTORS)) {
145 BX_ERROR(("%s in VMX guest: not allowed to use instruction !", i->getIaOpcodeNameShort()));
146 exception(BX_UD_EXCEPTION, 0);
147 }
148
149 VMCS_CACHE *vm = &BX_CPU_THIS_PTR vmcs;
150 Bit64u requested_features = (((Bit64u) EDX) << 32) | EAX;
151 if (requested_features & BX_CPU_THIS_PTR msr.ia32_xss & vm->xss_exiting_bitmap)
152 VMexit_Instruction(i, VMX_VMEXIT_XSAVES);
153 }
154 #endif
155 }
156
157 BX_DEBUG(("%s: save processor state XCR0=0x%08x XSS=" FMT_LL "x", i->getIaOpcodeNameShort(), BX_CPU_THIS_PTR xcr0.get32(), BX_CPU_THIS_PTR msr.ia32_xss));
158
159 bx_address eaddr = BX_CPU_RESOLVE_ADDR(i);
160 bx_address laddr = get_laddr(i->seg(), eaddr);
161
162 #if BX_SUPPORT_ALIGNMENT_CHECK && BX_CPU_LEVEL >= 4
163 if (BX_CPU_THIS_PTR alignment_check()) {
164 if (laddr & 0x3) {
165 BX_ERROR(("%s: access not aligned to 4-byte cause model specific #AC(0)", i->getIaOpcodeNameShort()));
166 exception(BX_AC_EXCEPTION, 0);
167 }
168 }
169 #endif
170
171 if (laddr & 0x3f) {
172 BX_ERROR(("%s: access not aligned to 64-byte", i->getIaOpcodeNameShort()));
173 exception(BX_GP_EXCEPTION, 0);
174 }
175
176 bx_address asize_mask = i->asize_mask();
177
178 Bit64u xcr0 = (Bit64u) BX_CPU_THIS_PTR xcr0.get32();
179 if (xsaves)
180 xcr0 |= BX_CPU_THIS_PTR msr.ia32_xss;
181
182 Bit32u requested_feature_bitmap = xcr0 & EAX;
183 Bit32u xinuse = get_xinuse_vector(requested_feature_bitmap);
184 Bit64u xstate_bv = requested_feature_bitmap & xinuse;
185 Bit64u xcomp_bv = requested_feature_bitmap | XSAVEC_COMPACTION_ENABLED;
186
187 if ((requested_feature_bitmap & BX_XCR0_FPU_MASK) != 0)
188 {
189 if (xinuse & BX_XCR0_FPU_MASK) {
190 xsave_x87_state(i, eaddr);
191 }
192 }
193
194 if ((requested_feature_bitmap & BX_XCR0_SSE_MASK) != 0)
195 {
196 // write cannot cause any boundary cross because XSAVE image is 64-byte aligned
197 write_virtual_dword(i->seg(), eaddr + 24, BX_MXCSR_REGISTER);
198 write_virtual_dword(i->seg(), eaddr + 28, MXCSR_MASK);
199 }
200
201 Bit32u offset = XSAVE_SSE_STATE_OFFSET;
202
203 /////////////////////////////////////////////////////////////////////////////
204 for (unsigned feature = xcr0_t::BX_XCR0_SSE_BIT; feature < xcr0_t::BX_XCR0_LAST; feature++)
205 {
206 Bit32u feature_mask = (1 << feature);
207
208 if ((requested_feature_bitmap & feature_mask) != 0)
209 {
210 if (! xsave_restore[feature].len) {
211 BX_ERROR(("%s: feature #%d requested to save but not implemented !", i->getIaOpcodeNameShort(), feature));
212 continue;
213 }
214
215 if (xinuse & feature_mask) {
216 BX_ASSERT(xsave_restore[feature].xsave_method);
217 CALL_XSAVE_FN(xsave_restore[feature].xsave_method)(i, eaddr+offset);
218 }
219
220 offset += xsave_restore[feature].len;
221 }
222 }
223
224 // always update header to 'dirty' state
225 write_virtual_qword(i->seg(), (eaddr + 512) & asize_mask, xstate_bv);
226 write_virtual_qword(i->seg(), (eaddr + 520) & asize_mask, xcomp_bv);
227 #endif
228
229 BX_NEXT_INSTR(i);
230 }
231
232 /* 0F AE /5 */
XRSTOR(bxInstruction_c * i)233 void BX_CPP_AttrRegparmN(1) BX_CPU_C::XRSTOR(bxInstruction_c *i)
234 {
235 #if BX_CPU_LEVEL >= 6
236 BX_CPU_THIS_PTR prepareXSAVE();
237
238 bool xrstors = (i->getIaOpcode() == BX_IA_XRSTORS);
239 if (xrstors) {
240 if (CPL != 0) {
241 BX_ERROR(("%s: with CPL != 0", i->getIaOpcodeNameShort()));
242 exception(BX_GP_EXCEPTION, 0);
243 }
244
245 #if BX_SUPPORT_VMX >= 2
246 if (BX_CPU_THIS_PTR in_vmx_guest) {
247 if (! SECONDARY_VMEXEC_CONTROL(VMX_VM_EXEC_CTRL3_XSAVES_XRSTORS)) {
248 BX_ERROR(("%s in VMX guest: not allowed to use instruction !", i->getIaOpcodeNameShort()));
249 exception(BX_UD_EXCEPTION, 0);
250 }
251
252 VMCS_CACHE *vm = &BX_CPU_THIS_PTR vmcs;
253 Bit64u requested_features = (((Bit64u) EDX) << 32) | EAX;
254 if (requested_features & BX_CPU_THIS_PTR msr.ia32_xss & vm->xss_exiting_bitmap)
255 VMexit_Instruction(i, VMX_VMEXIT_XRSTORS);
256 }
257 #endif
258 }
259
260 BX_DEBUG(("%s: restore processor state XCR0=0x%08x XSS=" FMT_LL "x", i->getIaOpcodeNameShort(), BX_CPU_THIS_PTR xcr0.get32(), BX_CPU_THIS_PTR msr.ia32_xss));
261
262 bx_address eaddr = BX_CPU_RESOLVE_ADDR(i);
263 bx_address laddr = get_laddr(i->seg(), eaddr);
264
265 #if BX_SUPPORT_ALIGNMENT_CHECK && BX_CPU_LEVEL >= 4
266 if (BX_CPU_THIS_PTR alignment_check()) {
267 if (laddr & 0x3) {
268 BX_ERROR(("%s: access not aligned to 4-byte cause model specific #AC(0)", i->getIaOpcodeNameShort()));
269 exception(BX_AC_EXCEPTION, 0);
270 }
271 }
272 #endif
273
274 if (laddr & 0x3f) {
275 BX_ERROR(("%s: access not aligned to 64-byte", i->getIaOpcodeNameShort()));
276 exception(BX_GP_EXCEPTION, 0);
277 }
278
279 bx_address asize_mask = i->asize_mask();
280
281 Bit64u xstate_bv = read_virtual_qword(i->seg(), (eaddr + 512) & asize_mask);
282 Bit64u xcomp_bv = read_virtual_qword(i->seg(), (eaddr + 520) & asize_mask);
283 Bit64u header3 = read_virtual_qword(i->seg(), (eaddr + 528) & asize_mask);
284
285 if (header3 != 0) {
286 BX_ERROR(("%s: Reserved header3 state is not '0", i->getIaOpcodeNameShort()));
287 exception(BX_GP_EXCEPTION, 0);
288 }
289
290 bool compaction = (xcomp_bv & XSAVEC_COMPACTION_ENABLED) != 0;
291
292 if (! BX_CPUID_SUPPORT_ISA_EXTENSION(BX_ISA_XSAVEC) || ! compaction) {
293 if (xcomp_bv != 0) {
294 BX_ERROR(("%s: Reserved header2 state is not '0", i->getIaOpcodeNameShort()));
295 exception(BX_GP_EXCEPTION, 0);
296 }
297 }
298
299 Bit64u xcr0 = (Bit64u) BX_CPU_THIS_PTR xcr0.get32();
300 if (xrstors)
301 xcr0 |= BX_CPU_THIS_PTR msr.ia32_xss;
302
303 if (! compaction) {
304 if (xrstors) {
305 BX_ERROR(("XRSTORS require compaction XCOMP_BV[63] to be set"));
306 exception(BX_GP_EXCEPTION, 0);
307 }
308
309 if ((~xcr0 & xstate_bv) != 0) {
310 BX_ERROR(("%s: Invalid xsave_bv state", i->getIaOpcodeNameShort()));
311 exception(BX_GP_EXCEPTION, 0);
312 }
313 }
314 else {
315 if ((~xcr0 & xcomp_bv & ~XSAVEC_COMPACTION_ENABLED) != 0) {
316 BX_ERROR(("%s: Invalid xcomp_bv state", i->getIaOpcodeNameShort()));
317 exception(BX_GP_EXCEPTION, 0);
318 }
319
320 if (xstate_bv & ~xcomp_bv) {
321 BX_ERROR(("%s: xstate_bv set a bit which is not in xcomp_bv state", i->getIaOpcodeNameShort()));
322 exception(BX_GP_EXCEPTION, 0);
323 }
324
325 Bit64u header4 = read_virtual_qword(i->seg(), (eaddr + 536) & asize_mask);
326 Bit64u header5 = read_virtual_qword(i->seg(), (eaddr + 544) & asize_mask);
327 Bit64u header6 = read_virtual_qword(i->seg(), (eaddr + 552) & asize_mask);
328 Bit64u header7 = read_virtual_qword(i->seg(), (eaddr + 560) & asize_mask);
329 Bit64u header8 = read_virtual_qword(i->seg(), (eaddr + 568) & asize_mask);
330
331 if (header4 | header5 | header6 | header7 | header8) {
332 BX_ERROR(("%s: Reserved header4_header7 state is not '0", i->getIaOpcodeNameShort()));
333 exception(BX_GP_EXCEPTION, 0);
334 }
335 }
336
337 Bit32u requested_feature_bitmap = xcr0 & EAX;
338
339 /////////////////////////////////////////////////////////////////////////////
340 if ((requested_feature_bitmap & BX_XCR0_FPU_MASK) != 0)
341 {
342 if (xstate_bv & BX_XCR0_FPU_MASK)
343 xrstor_x87_state(i, eaddr);
344 else
345 xrstor_init_x87_state();
346 }
347
348 /////////////////////////////////////////////////////////////////////////////
349 if ((requested_feature_bitmap & BX_XCR0_SSE_MASK) != 0 ||
350 ((requested_feature_bitmap & BX_XCR0_YMM_MASK) != 0 && ! compaction))
351 {
352 // read cannot cause any boundary cross because XSAVE image is 64-byte aligned
353 Bit32u new_mxcsr = read_virtual_dword(i->seg(), eaddr + 24);
354 if(new_mxcsr & ~MXCSR_MASK)
355 exception(BX_GP_EXCEPTION, 0);
356 BX_MXCSR_REGISTER = new_mxcsr;
357 }
358
359 /////////////////////////////////////////////////////////////////////////////
360 if ((requested_feature_bitmap & BX_XCR0_SSE_MASK) != 0)
361 {
362 if (xstate_bv & BX_XCR0_SSE_MASK)
363 xrstor_sse_state(i, eaddr+XSAVE_SSE_STATE_OFFSET);
364 else
365 xrstor_init_sse_state();
366 }
367
368 if (compaction) {
369 Bit32u offset = XSAVE_YMM_STATE_OFFSET;
370
371 /////////////////////////////////////////////////////////////////////////////
372 for (unsigned feature = xcr0_t::BX_XCR0_YMM_BIT; feature < xcr0_t::BX_XCR0_LAST; feature++)
373 {
374 Bit32u feature_mask = (1 << feature);
375
376 if ((requested_feature_bitmap & feature_mask) != 0)
377 {
378 if (! xsave_restore[feature].len) {
379 BX_ERROR(("%s: feature #%d requested to restore but not implemented !", i->getIaOpcodeNameShort(), feature));
380 continue;
381 }
382
383 if (xstate_bv & feature_mask) {
384 BX_ASSERT(xsave_restore[feature].xrstor_method);
385 CALL_XSAVE_FN(xsave_restore[feature].xrstor_method)(i, eaddr+offset);
386 }
387 else {
388 BX_ASSERT(xsave_restore[feature].xrstor_init_method);
389 CALL_XSAVE_FN(xsave_restore[feature].xrstor_init_method)();
390 }
391
392 offset += xsave_restore[feature].len;
393 }
394 }
395 }
396 else {
397
398 /////////////////////////////////////////////////////////////////////////////
399 for (unsigned feature = xcr0_t::BX_XCR0_YMM_BIT; feature < xcr0_t::BX_XCR0_LAST; feature++)
400 {
401 Bit32u feature_mask = (1 << feature);
402
403 if ((requested_feature_bitmap & feature_mask) != 0)
404 {
405 if (! xsave_restore[feature].len) {
406 BX_ERROR(("%s: feature #%d requested to restore but not implemented !", i->getIaOpcodeNameShort(), feature));
407 continue;
408 }
409
410 if (xstate_bv & feature_mask) {
411 BX_ASSERT(xsave_restore[feature].xrstor_method);
412 CALL_XSAVE_FN(xsave_restore[feature].xrstor_method)(i, eaddr+xsave_restore[feature].offset);
413 }
414 else {
415 BX_ASSERT(xsave_restore[feature].xrstor_init_method);
416 CALL_XSAVE_FN(xsave_restore[feature].xrstor_init_method)();
417 }
418 }
419 }
420 }
421
422 #if BX_SUPPORT_PKEYS
423 // take effect of changing the PKRU state
424 if ((requested_feature_bitmap & BX_XCR0_PKRU_MASK) != 0) {
425 set_PKeys(TMP32, BX_CPU_THIS_PTR pkrs);
426 }
427 #endif
428
429 #endif // BX_CPU_LEVEL >= 6
430
431 BX_NEXT_INSTR(i);
432 }
433
434 #if BX_CPU_LEVEL >= 6
435
436 // x87 state management //
437
xsave_x87_state(bxInstruction_c * i,bx_address offset)438 void BX_CPU_C::xsave_x87_state(bxInstruction_c *i, bx_address offset)
439 {
440 BxPackedXmmRegister xmm;
441 bx_address asize_mask = i->asize_mask();
442
443 xmm.xmm16u(0) = BX_CPU_THIS_PTR the_i387.get_control_word();
444 xmm.xmm16u(1) = BX_CPU_THIS_PTR the_i387.get_status_word();
445 xmm.xmm16u(2) = pack_FPU_TW(BX_CPU_THIS_PTR the_i387.get_tag_word());
446
447 /* x87 FPU Opcode (16 bits) */
448 /* The lower 11 bits contain the FPU opcode, upper 5 bits are reserved */
449 xmm.xmm16u(3) = BX_CPU_THIS_PTR the_i387.foo;
450
451 /*
452 * x87 FPU IP Offset (32/64 bits)
453 * The contents of this field differ depending on the current
454 * addressing mode (16/32/64 bit) when the FXSAVE instruction was executed:
455 * + 64-bit mode - 64-bit IP offset
456 * + 32-bit mode - 32-bit IP offset
457 * + 16-bit mode - low 16 bits are IP offset; high 16 bits are reserved.
458 * x87 CS FPU IP Selector
459 * + 16 bit, in 16/32 bit mode only
460 */
461 #if BX_SUPPORT_X86_64
462 if (i->os64L()) {
463 xmm.xmm64u(1) = (BX_CPU_THIS_PTR the_i387.fip);
464 }
465 else
466 #endif
467 {
468 xmm.xmm32u(2) = (Bit32u)(BX_CPU_THIS_PTR the_i387.fip);
469 xmm.xmm32u(3) = x87_get_FCS();
470 }
471
472 write_virtual_xmmword(i->seg(), offset, &xmm);
473
474 /*
475 * x87 FPU Instruction Operand (Data) Pointer Offset (32/64 bits)
476 * The contents of this field differ depending on the current
477 * addressing mode (16/32 bit) when the FXSAVE instruction was executed:
478 * + 64-bit mode - 64-bit offset
479 * + 32-bit mode - 32-bit offset
480 * + 16-bit mode - low 16 bits are offset; high 16 bits are reserved.
481 * x87 DS FPU Instruction Operand (Data) Pointer Selector
482 * + 16 bit, in 16/32 bit mode only
483 */
484 #if BX_SUPPORT_X86_64
485 // write cannot cause any boundary cross because XSAVE image is 64-byte aligned
486 if (i->os64L()) {
487 write_virtual_qword(i->seg(), offset + 16, BX_CPU_THIS_PTR the_i387.fdp);
488 }
489 else
490 #endif
491 {
492 write_virtual_dword(i->seg(), offset + 16, (Bit32u) BX_CPU_THIS_PTR the_i387.fdp);
493 write_virtual_dword(i->seg(), offset + 20, x87_get_FDS());
494 }
495 /* do not touch MXCSR state */
496
497 /* store i387 register file */
498 for(unsigned index=0; index < 8; index++)
499 {
500 const floatx80 &fp = BX_READ_FPU_REG(index);
501
502 xmm.xmm64u(0) = fp.fraction;
503 xmm.xmm64u(1) = 0;
504 xmm.xmm16u(4) = fp.exp;
505
506 write_virtual_xmmword(i->seg(), (offset+index*16+32) & asize_mask, &xmm);
507 }
508 }
509
xrstor_x87_state(bxInstruction_c * i,bx_address offset)510 void BX_CPU_C::xrstor_x87_state(bxInstruction_c *i, bx_address offset)
511 {
512 BxPackedXmmRegister xmm;
513 bx_address asize_mask = i->asize_mask();
514
515 // load FPU state from XSAVE area
516 read_virtual_xmmword(i->seg(), offset, &xmm);
517
518 BX_CPU_THIS_PTR the_i387.cwd = xmm.xmm16u(0);
519 BX_CPU_THIS_PTR the_i387.swd = xmm.xmm16u(1);
520 BX_CPU_THIS_PTR the_i387.tos = (xmm.xmm16u(1) >> 11) & 0x07;
521
522 /* always set bit 6 as '1 */
523 BX_CPU_THIS_PTR the_i387.cwd =
524 (BX_CPU_THIS_PTR the_i387.cwd & ~FPU_CW_Reserved_Bits) | 0x0040;
525
526 /* Restore x87 FPU Opcode */
527 /* The lower 11 bits contain the FPU opcode, upper 5 bits are reserved */
528 BX_CPU_THIS_PTR the_i387.foo = xmm.xmm16u(3) & 0x7FF;
529
530 /* Restore x87 FPU IP */
531 #if BX_SUPPORT_X86_64
532 if (i->os64L()) {
533 BX_CPU_THIS_PTR the_i387.fip = xmm.xmm64u(1);
534 BX_CPU_THIS_PTR the_i387.fcs = 0;
535 }
536 else
537 #endif
538 {
539 BX_CPU_THIS_PTR the_i387.fip = xmm.xmm32u(2);
540 BX_CPU_THIS_PTR the_i387.fcs = xmm.xmm16u(6);
541 }
542
543 Bit32u tag_byte = xmm.xmmubyte(4);
544
545 /* Restore x87 FPU DP - read cannot cause any boundary cross because XSAVE image is 64-byte aligned */
546 read_virtual_xmmword(i->seg(), offset + 16, &xmm);
547
548 #if BX_SUPPORT_X86_64
549 if (i->os64L()) {
550 BX_CPU_THIS_PTR the_i387.fdp = xmm.xmm64u(0);
551 BX_CPU_THIS_PTR the_i387.fds = 0;
552 }
553 else
554 #endif
555 {
556 BX_CPU_THIS_PTR the_i387.fdp = xmm.xmm32u(0);
557 BX_CPU_THIS_PTR the_i387.fds = xmm.xmm16u(2);
558 }
559
560 /* load i387 register file */
561 for(unsigned index=0; index < 8; index++)
562 {
563 floatx80 reg;
564 reg.fraction = read_virtual_qword(i->seg(), (offset+index*16+32) & asize_mask);
565 reg.exp = read_virtual_word (i->seg(), (offset+index*16+40) & asize_mask);
566
567 // update tag only if it is not empty
568 BX_WRITE_FPU_REGISTER_AND_TAG(reg,
569 IS_TAG_EMPTY(index) ? FPU_Tag_Empty : FPU_tagof(reg), index);
570 }
571
572 /* Restore floating point tag word - see desription for FXRSTOR instruction */
573 BX_CPU_THIS_PTR the_i387.twd = unpack_FPU_TW(tag_byte);
574
575 /* check for unmasked exceptions */
576 if (FPU_PARTIAL_STATUS & ~FPU_CONTROL_WORD & FPU_CW_Exceptions_Mask) {
577 /* set the B and ES bits in the status-word */
578 FPU_PARTIAL_STATUS |= FPU_SW_Summary | FPU_SW_Backward;
579 }
580 else {
581 /* clear the B and ES bits in the status-word */
582 FPU_PARTIAL_STATUS &= ~(FPU_SW_Summary | FPU_SW_Backward);
583 }
584 }
585
xrstor_init_x87_state(void)586 void BX_CPU_C::xrstor_init_x87_state(void)
587 {
588 // initialize FPU with reset values
589 BX_CPU_THIS_PTR the_i387.init();
590
591 for (unsigned index=0;index<8;index++) {
592 static floatx80 reg = { 0, 0 };
593 BX_FPU_REG(index) = reg;
594 }
595 }
596
xsave_x87_state_xinuse(void)597 bool BX_CPU_C::xsave_x87_state_xinuse(void)
598 {
599 if (BX_CPU_THIS_PTR the_i387.get_control_word() != 0x037F ||
600 BX_CPU_THIS_PTR the_i387.get_status_word() != 0 ||
601 BX_CPU_THIS_PTR the_i387.get_tag_word() != 0xFFFF ||
602 BX_CPU_THIS_PTR the_i387.foo != 0 ||
603 BX_CPU_THIS_PTR the_i387.fip != 0 || BX_CPU_THIS_PTR the_i387.fcs != 0 ||
604 BX_CPU_THIS_PTR the_i387.fdp != 0 || BX_CPU_THIS_PTR the_i387.fds != 0) return true;
605
606 for (unsigned index=0;index<8;index++) {
607 floatx80 reg = BX_FPU_REG(index);
608 if (reg.exp != 0 || reg.fraction != 0) return true;
609 }
610
611 return false;
612 }
613
614 // SSE state management //
615
xsave_sse_state(bxInstruction_c * i,bx_address offset)616 void BX_CPU_C::xsave_sse_state(bxInstruction_c *i, bx_address offset)
617 {
618 bx_address asize_mask = i->asize_mask();
619
620 /* store XMM register file */
621 for(unsigned index=0; index < 16; index++) {
622 // save XMM8-XMM15 only in 64-bit mode
623 if (index < 8 || long64_mode()) {
624 write_virtual_xmmword(i->seg(), (offset + index*16) & asize_mask, &BX_READ_XMM_REG(index));
625 }
626 }
627 }
628
xrstor_sse_state(bxInstruction_c * i,bx_address offset)629 void BX_CPU_C::xrstor_sse_state(bxInstruction_c *i, bx_address offset)
630 {
631 bx_address asize_mask = i->asize_mask();
632
633 // load SSE state from XSAVE area
634 for(unsigned index=0; index < 16; index++) {
635 // restore XMM8-XMM15 only in 64-bit mode
636 if (index < 8 || long64_mode()) {
637 read_virtual_xmmword(i->seg(), (offset+index*16) & asize_mask, &BX_READ_XMM_REG(index));
638 }
639 }
640 }
641
xrstor_init_sse_state(void)642 void BX_CPU_C::xrstor_init_sse_state(void)
643 {
644 // initialize SSE with reset values
645 for(unsigned index=0; index < 16; index++) {
646 // set XMM8-XMM15 only in 64-bit mode
647 if (index < 8 || long64_mode()) BX_CLEAR_XMM_REG(index);
648 }
649 }
650
xsave_sse_state_xinuse(void)651 bool BX_CPU_C::xsave_sse_state_xinuse(void)
652 {
653 for(unsigned index=0; index < 16; index++) {
654 // set XMM8-XMM15 only in 64-bit mode
655 if (index < 8 || long64_mode()) {
656 const BxPackedXmmRegister *reg = &BX_XMM_REG(index);
657 if (! is_clear(reg)) return true;
658 }
659 }
660
661 return false;
662 }
663
664 #if BX_SUPPORT_AVX
665
666 // YMM state management //
667
xsave_ymm_state(bxInstruction_c * i,bx_address offset)668 void BX_CPU_C::xsave_ymm_state(bxInstruction_c *i, bx_address offset)
669 {
670 bx_address asize_mask = i->asize_mask();
671
672 /* store AVX state */
673 for(unsigned index=0; index < 16; index++) {
674 // save YMM8-YMM15 only in 64-bit mode
675 if (index < 8 || long64_mode()) {
676 write_virtual_xmmword(i->seg(), (offset + index*16) & asize_mask, &BX_READ_AVX_REG_LANE(index, 1));
677 }
678 }
679 }
680
xrstor_ymm_state(bxInstruction_c * i,bx_address offset)681 void BX_CPU_C::xrstor_ymm_state(bxInstruction_c *i, bx_address offset)
682 {
683 bx_address asize_mask = i->asize_mask();
684
685 // load AVX state from XSAVE area
686 for(unsigned index=0; index < 16; index++) {
687 // restore YMM8-YMM15 only in 64-bit mode
688 if (index < 8 || long64_mode()) {
689 read_virtual_xmmword(i->seg(), (offset + index*16) & asize_mask, &BX_READ_AVX_REG_LANE(index, 1));
690 }
691 }
692 }
693
xrstor_init_ymm_state(void)694 void BX_CPU_C::xrstor_init_ymm_state(void)
695 {
696 // initialize upper part of AVX registers with reset values
697 for(unsigned index=0; index < 16; index++) {
698 // set YMM8-YMM15 only in 64-bit mode
699 if (index < 8 || long64_mode()) BX_CLEAR_AVX_HIGH128(index);
700 }
701 }
702
xsave_ymm_state_xinuse(void)703 bool BX_CPU_C::xsave_ymm_state_xinuse(void)
704 {
705 for(unsigned index=0; index < 16; index++) {
706 // set YMM8-YMM15 only in 64-bit mode
707 if (index < 8 || long64_mode()) {
708 const BxPackedXmmRegister *reg = &BX_READ_AVX_REG_LANE(index, 1);
709 if (! is_clear(reg)) return true;
710 }
711 }
712
713 return false;
714 }
715
716 #if BX_SUPPORT_EVEX
717
718 // Opmask state management //
719
xsave_opmask_state(bxInstruction_c * i,bx_address offset)720 void BX_CPU_C::xsave_opmask_state(bxInstruction_c *i, bx_address offset)
721 {
722 bx_address asize_mask = i->asize_mask();
723
724 // save OPMASK state to XSAVE area
725 for(unsigned index=0; index < 8; index++) {
726 write_virtual_qword(i->seg(), (offset+index*8) & asize_mask, BX_READ_OPMASK(index));
727 }
728 }
729
xrstor_opmask_state(bxInstruction_c * i,bx_address offset)730 void BX_CPU_C::xrstor_opmask_state(bxInstruction_c *i, bx_address offset)
731 {
732 bx_address asize_mask = i->asize_mask();
733
734 // load opmask registers from XSAVE area
735 for(unsigned index=0; index < 8; index++) {
736 Bit64u opmask = read_virtual_qword(i->seg(), (offset+index*8) & asize_mask);
737 BX_WRITE_OPMASK(index, opmask);
738 }
739 }
740
xrstor_init_opmask_state(void)741 void BX_CPU_C::xrstor_init_opmask_state(void)
742 {
743 // initialize opmask registers with reset values
744 for(unsigned index=0; index < 8; index++) {
745 BX_WRITE_OPMASK(index, 0);
746 }
747 }
748
xsave_opmask_state_xinuse(void)749 bool BX_CPU_C::xsave_opmask_state_xinuse(void)
750 {
751 for(unsigned index=0; index < 8; index++) {
752 if (BX_READ_OPMASK(index)) return true;
753 }
754
755 return false;
756 }
757
758 // ZMM_HI256 (upper part of zmm0..zmm15 registers) state management //
759
760 // In 64-bit mode, ZMM_Hi256 state is in its initial configuration if each of ZMM0_H-ZMM15_H is 0.
761 // Outside 64-bit mode, ZMM_Hi256 state is in its initial configuration if each of ZMM0_H-ZMM7_H is 0.
762 // An execution of XRSTOR or XRSTORS outside 64-bit mode does not update ZMM8_H-ZMM15_H.
763
xsave_zmm_hi256_state(bxInstruction_c * i,bx_address offset)764 void BX_CPU_C::xsave_zmm_hi256_state(bxInstruction_c *i, bx_address offset)
765 {
766 unsigned num_regs = long64_mode() ? 16 : 8;
767
768 bx_address asize_mask = i->asize_mask();
769
770 // save upper part of ZMM registers to XSAVE area
771 for(unsigned index=0; index < num_regs; index++) {
772 write_virtual_ymmword(i->seg(), (offset+index*32) & asize_mask, &BX_READ_ZMM_REG_HI(index));
773 }
774 }
775
xrstor_zmm_hi256_state(bxInstruction_c * i,bx_address offset)776 void BX_CPU_C::xrstor_zmm_hi256_state(bxInstruction_c *i, bx_address offset)
777 {
778 unsigned num_regs = long64_mode() ? 16 : 8;
779
780 bx_address asize_mask = i->asize_mask();
781
782 // load upper part of ZMM registers from XSAVE area
783 for(unsigned index=0; index < num_regs; index++) {
784 read_virtual_ymmword(i->seg(), (offset+index*32) & asize_mask, &BX_READ_ZMM_REG_HI(index));
785 }
786 }
787
xrstor_init_zmm_hi256_state(void)788 void BX_CPU_C::xrstor_init_zmm_hi256_state(void)
789 {
790 unsigned num_regs = long64_mode() ? 16 : 8;
791
792 // initialize upper part of ZMM registers with reset values
793 for(unsigned index=0; index < num_regs; index++) {
794 BX_CLEAR_AVX_HIGH256(index);
795 }
796 }
797
xsave_zmm_hi256_state_xinuse(void)798 bool BX_CPU_C::xsave_zmm_hi256_state_xinuse(void)
799 {
800 unsigned num_regs = long64_mode() ? 16 : 8;
801
802 for(unsigned index=0; index < num_regs; index++) {
803 for (unsigned n=2; n < 4; n++) {
804 const BxPackedXmmRegister *reg = &BX_READ_AVX_REG_LANE(index, n);
805 if (! is_clear(reg)) return true;
806 }
807 }
808
809 return false;
810 }
811
812 // HI_ZMM (zmm15..zmm31) state management //
813
814 // In 64-bit mode, Hi16_ZMM state is in its initial configuration if each of ZMM16-ZMM31 is 0.
815 // Outside 64-bit mode, Hi16_ZMM state is always in its initial configuration.
816 // An execution of XRSTOR or XRSTORS outside 64-bit mode does not update ZMM16-ZMM31.
817
xsave_hi_zmm_state(bxInstruction_c * i,bx_address offset)818 void BX_CPU_C::xsave_hi_zmm_state(bxInstruction_c *i, bx_address offset)
819 {
820 if (!long64_mode()) return;
821
822 bx_address asize_mask = i->asize_mask();
823
824 // save high ZMM state to XSAVE area
825 for(unsigned index=0; index < 16; index++) {
826 write_virtual_zmmword(i->seg(), (offset+index*64) & asize_mask, &BX_READ_AVX_REG(index+16));
827 }
828 }
829
xrstor_hi_zmm_state(bxInstruction_c * i,bx_address offset)830 void BX_CPU_C::xrstor_hi_zmm_state(bxInstruction_c *i, bx_address offset)
831 {
832 if (!long64_mode()) return;
833
834 bx_address asize_mask = i->asize_mask();
835
836 // load high ZMM state from XSAVE area
837 for(unsigned index=0; index < 16; index++) {
838 read_virtual_zmmword(i->seg(), (offset+index*64) & asize_mask, &BX_READ_AVX_REG(index+16));
839 }
840 }
841
xrstor_init_hi_zmm_state(void)842 void BX_CPU_C::xrstor_init_hi_zmm_state(void)
843 {
844 if (!long64_mode()) return;
845
846 // initialize high ZMM registers with reset values
847 for(unsigned index=16; index < 32; index++) {
848 BX_CLEAR_AVX_REG(index);
849 }
850 }
851
xsave_hi_zmm_state_xinuse(void)852 bool BX_CPU_C::xsave_hi_zmm_state_xinuse(void)
853 {
854 if (!long64_mode()) return true;
855
856 for(unsigned index=16; index < 32; index++) {
857 for (unsigned n=0; n < 4; n++) {
858 const BxPackedXmmRegister *reg = &BX_READ_AVX_REG_LANE(index, n);
859 if (! is_clear(reg)) return true;
860 }
861 }
862
863 return false;
864 }
865 #endif // BX_SUPPORT_EVEX
866
867 #endif // BX_SUPPORT_AVX
868
869 #if BX_SUPPORT_PKEYS
870 // PKRU state management //
xsave_pkru_state(bxInstruction_c * i,bx_address offset)871 void BX_CPU_C::xsave_pkru_state(bxInstruction_c *i, bx_address offset)
872 {
873 write_virtual_qword(i->seg(), offset, (Bit64u) BX_CPU_THIS_PTR pkru);
874 }
875
xrstor_pkru_state(bxInstruction_c * i,bx_address offset)876 void BX_CPU_C::xrstor_pkru_state(bxInstruction_c *i, bx_address offset)
877 {
878 // just write the pkru to TMP register for now and don't call set_PKeys
879 // calling it will take immediate effect on all future memory accesses including load of other XRSTOR components
880 TMP32 = read_virtual_dword(i->seg(), offset);
881 }
882
xrstor_init_pkru_state(void)883 void BX_CPU_C::xrstor_init_pkru_state(void)
884 {
885 // just write the pkru to TMP register for now and don't call set_PKeys
886 // calling it will take immediate effect on all future memory accesses including load of other XRSTOR components
887 TMP32 = 0;
888 }
889
xsave_pkru_state_xinuse(void)890 bool BX_CPU_C::xsave_pkru_state_xinuse(void)
891 {
892 return (BX_CPU_THIS_PTR pkru != 0);
893 }
894 #endif
895
896 #if BX_SUPPORT_CET
897 // CET U state management //
xsave_cet_u_state(bxInstruction_c * i,bx_address offset)898 void BX_CPU_C::xsave_cet_u_state(bxInstruction_c *i, bx_address offset)
899 {
900 bx_address asize_mask = i->asize_mask();
901
902 write_virtual_qword(i->seg(), offset, BX_CPU_THIS_PTR msr.ia32_cet_control[1]);
903 write_virtual_qword(i->seg(), (offset + 8) & asize_mask, BX_CPU_THIS_PTR msr.ia32_pl_ssp[3]);
904 }
905
xrstor_cet_u_state(bxInstruction_c * i,bx_address offset)906 void BX_CPU_C::xrstor_cet_u_state(bxInstruction_c *i, bx_address offset)
907 {
908 bx_address asize_mask = i->asize_mask();
909
910 Bit64u ctrl = read_virtual_qword(i->seg(), offset);
911 Bit64u ia32_pl3_ssp = read_virtual_qword(i->seg(), (offset + 8) & asize_mask);
912
913 // XRSTOR on CET state does all reserved bits and canonicality check like WRMSR would do
914 wrmsr(BX_MSR_IA32_U_CET, ctrl);
915 wrmsr(BX_MSR_IA32_PL3_SSP, ia32_pl3_ssp);
916 }
917
xrstor_init_cet_u_state(void)918 void BX_CPU_C::xrstor_init_cet_u_state(void)
919 {
920 BX_CPU_THIS_PTR msr.ia32_cet_control[1] = 0;
921 BX_CPU_THIS_PTR msr.ia32_pl_ssp[3] = 0;
922 }
923
xsave_cet_u_state_xinuse(void)924 bool BX_CPU_C::xsave_cet_u_state_xinuse(void)
925 {
926 return BX_CPU_THIS_PTR msr.ia32_cet_control[1] == 0 &&
927 BX_CPU_THIS_PTR msr.ia32_pl_ssp[3] == 0;
928 }
929
930 // CET S state management //
xsave_cet_s_state(bxInstruction_c * i,bx_address offset)931 void BX_CPU_C::xsave_cet_s_state(bxInstruction_c *i, bx_address offset)
932 {
933 bx_address asize_mask = i->asize_mask();
934
935 write_virtual_qword(i->seg(), offset, BX_CPU_THIS_PTR msr.ia32_pl_ssp[0]);
936 write_virtual_qword(i->seg(), (offset + 8) & asize_mask, BX_CPU_THIS_PTR msr.ia32_pl_ssp[1]);
937 write_virtual_qword(i->seg(), (offset + 16) & asize_mask, BX_CPU_THIS_PTR msr.ia32_pl_ssp[2]);
938 }
939
xrstor_cet_s_state(bxInstruction_c * i,bx_address offset)940 void BX_CPU_C::xrstor_cet_s_state(bxInstruction_c *i, bx_address offset)
941 {
942 bx_address asize_mask = i->asize_mask();
943
944 Bit64u ia32_pl0_ssp = read_virtual_qword(i->seg(), offset);
945 Bit64u ia32_pl1_ssp = read_virtual_qword(i->seg(), (offset + 8) & asize_mask);
946 Bit64u ia32_pl2_ssp = read_virtual_qword(i->seg(), (offset + 16) & asize_mask);
947
948 // XRSTOR on CET state does all reserved bits and canonicality check like WRMSR would do
949 wrmsr(BX_MSR_IA32_PL0_SSP, ia32_pl0_ssp);
950 wrmsr(BX_MSR_IA32_PL1_SSP, ia32_pl1_ssp);
951 wrmsr(BX_MSR_IA32_PL2_SSP, ia32_pl2_ssp);
952 }
953
xrstor_init_cet_s_state(void)954 void BX_CPU_C::xrstor_init_cet_s_state(void)
955 {
956 for (unsigned n=0;n<3;n++)
957 BX_CPU_THIS_PTR msr.ia32_pl_ssp[n] = 0;
958 }
959
xsave_cet_s_state_xinuse(void)960 bool BX_CPU_C::xsave_cet_s_state_xinuse(void)
961 {
962 for (unsigned n=0;n<3;n++)
963 return BX_CPU_THIS_PTR msr.ia32_pl_ssp[n] != 0;
964
965 return false;
966 }
967 #endif
968
get_xinuse_vector(Bit32u requested_feature_bitmap)969 Bit32u BX_CPU_C::get_xinuse_vector(Bit32u requested_feature_bitmap)
970 {
971 Bit32u xinuse = 0;
972
973 /////////////////////////////////////////////////////////////////////////////
974 for (unsigned feature = xcr0_t::BX_XCR0_FPU_BIT; feature < xcr0_t::BX_XCR0_LAST; feature++)
975 {
976 Bit32u feature_mask = (1 << feature);
977
978 if ((requested_feature_bitmap & feature_mask) != 0)
979 {
980 if (! xsave_restore[feature].len) {
981 BX_ERROR(("get_xinuse_vector(0x%08x): feature #%d requested but not implemented !", requested_feature_bitmap, feature));
982 continue;
983 }
984
985 BX_ASSERT(xsave_restore[feature].xstate_in_use_method);
986 if (CALL_XSAVE_FN(xsave_restore[feature].xstate_in_use_method)())
987 xinuse |= feature_mask;
988 }
989 }
990
991 /////////////////////////////////////////////////////////////////////////////
992 if (requested_feature_bitmap & BX_XCR0_SSE_MASK) {
993 if (BX_MXCSR_REGISTER != MXCSR_RESET)
994 xinuse |= BX_XCR0_SSE_MASK;
995 }
996
997 return xinuse;
998 }
999
1000 #endif // BX_CPU_LEVEL >= 6
1001
1002 /* 0F 01 D0 */
XGETBV(bxInstruction_c * i)1003 void BX_CPP_AttrRegparmN(1) BX_CPU_C::XGETBV(bxInstruction_c *i)
1004 {
1005 #if BX_CPU_LEVEL >= 6
1006 if(! BX_CPU_THIS_PTR cr4.get_OSXSAVE()) {
1007 BX_ERROR(("XGETBV: OSXSAVE feature is not enabled in CR4!"));
1008 exception(BX_UD_EXCEPTION, 0);
1009 }
1010
1011 // For now hardcoded handle only XCR0 register, it should take a few
1012 // years until extension will be required
1013
1014 if (ECX != 0) {
1015 if (ECX == 1 && BX_CPUID_SUPPORT_ISA_EXTENSION(BX_ISA_XSAVEC)) {
1016 // Executing XGETBV with ECX = 1 returns in EDX:EAX the logical-AND of XCR0
1017 // and the current value of the XINUSE state-component bitmap.
1018 // If XINUSE[i]=0, state component [i] is in its initial configuration.
1019 RDX = 0;
1020 RAX = get_xinuse_vector(BX_CPU_THIS_PTR xcr0.get32());
1021 }
1022 else {
1023 BX_ERROR(("XGETBV: Invalid XCR%d register", ECX));
1024 exception(BX_GP_EXCEPTION, 0);
1025 }
1026 }
1027 else {
1028 RDX = 0;
1029 RAX = BX_CPU_THIS_PTR xcr0.get32();
1030 }
1031 #endif
1032
1033 BX_NEXT_INSTR(i);
1034 }
1035
1036 /* 0F 01 D1 */
XSETBV(bxInstruction_c * i)1037 void BX_CPP_AttrRegparmN(1) BX_CPU_C::XSETBV(bxInstruction_c *i)
1038 {
1039 #if BX_CPU_LEVEL >= 6
1040 if(! BX_CPU_THIS_PTR cr4.get_OSXSAVE()) {
1041 BX_ERROR(("XSETBV: OSXSAVE feature is not enabled in CR4!"));
1042 exception(BX_UD_EXCEPTION, 0);
1043 }
1044
1045 #if BX_SUPPORT_VMX
1046 if (BX_CPU_THIS_PTR in_vmx_guest) {
1047 VMexit(VMX_VMEXIT_XSETBV, 0);
1048 }
1049 #endif
1050
1051 #if BX_SUPPORT_SVM
1052 if (BX_CPU_THIS_PTR in_svm_guest) {
1053 if (SVM_INTERCEPT(SVM_INTERCEPT1_XSETBV)) Svm_Vmexit(SVM_VMEXIT_XSETBV);
1054 }
1055 #endif
1056
1057 // CPL is always 3 in vm8086 mode
1058 if (/* v8086_mode() || */ CPL != 0) {
1059 BX_ERROR(("XSETBV: The current priveledge level is not 0"));
1060 exception(BX_GP_EXCEPTION, 0);
1061 }
1062
1063 // For now hardcoded handle only XCR0 register, it should take a few
1064 // years until extension will be required
1065 if (ECX != 0) {
1066 BX_ERROR(("XSETBV: Invalid XCR%d register", ECX));
1067 exception(BX_GP_EXCEPTION, 0);
1068 }
1069
1070 if (EDX != 0 || (EAX & ~BX_CPU_THIS_PTR xcr0_suppmask) != 0 || (EAX & BX_XCR0_FPU_MASK) == 0) {
1071 BX_ERROR(("XSETBV: Attempt to change reserved bits"));
1072 exception(BX_GP_EXCEPTION, 0);
1073 }
1074
1075 #if BX_SUPPORT_AVX
1076 if ((EAX & (BX_XCR0_YMM_MASK | BX_XCR0_SSE_MASK)) == BX_XCR0_YMM_MASK) {
1077 BX_ERROR(("XSETBV: Attempt to enable AVX without SSE"));
1078 exception(BX_GP_EXCEPTION, 0);
1079 }
1080 #endif
1081
1082 #if BX_SUPPORT_EVEX
1083 if (EAX & (BX_XCR0_OPMASK_MASK | BX_XCR0_ZMM_HI256_MASK | BX_XCR0_HI_ZMM_MASK)) {
1084 Bit32u avx512_state_mask = (BX_XCR0_FPU_MASK | BX_XCR0_SSE_MASK | BX_XCR0_YMM_MASK | BX_XCR0_OPMASK_MASK | BX_XCR0_ZMM_HI256_MASK | BX_XCR0_HI_ZMM_MASK);
1085 if ((EAX & avx512_state_mask) != avx512_state_mask) {
1086 BX_ERROR(("XSETBV: Illegal attempt to enable AVX-512 state"));
1087 exception(BX_GP_EXCEPTION, 0);
1088 }
1089 }
1090 #endif
1091
1092 BX_CPU_THIS_PTR xcr0.set32(EAX);
1093
1094 #if BX_SUPPORT_AVX
1095 handleAvxModeChange();
1096 #endif
1097
1098 #endif // BX_CPU_LEVEL >= 6
1099
1100 BX_NEXT_TRACE(i);
1101 }
1102