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