1 /////////////////////////////////////////////////////////////////////////
2 // $Id: xsave.cc,v 1.14 2008/08/16 12:19:30 sshwarts Exp $
3 /////////////////////////////////////////////////////////////////////////
5 // Copyright (c) 2008 Stanislav Shwartsman
6 // Written by Stanislav Shwartsman [sshwarts at sourceforge net]
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.
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.
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 /////////////////////////////////////////////////////////////////////////
24 #define NEED_CPU_REG_SHORTCUTS 1
27 #define LOG_THIS BX_CPU_THIS_PTR
29 // Make code more tidy with a few macros.
30 #if BX_SUPPORT_X86_64==0
36 void BX_CPP_AttrRegparmN(1) BX_CPU_C::XSAVE(bxInstruction_c
*i
)
40 BxPackedXmmRegister xmm
;
42 BX_CPU_THIS_PTR
prepareXSAVE();
44 BX_DEBUG(("XSAVE: save processor state XCR0=0x%08x", BX_CPU_THIS_PTR xcr0
.getRegister()));
46 bx_address eaddr
= BX_CPU_CALL_METHODR(i
->ResolveModrm
, (i
));
48 bx_address laddr
= get_laddr(i
->seg(), eaddr
);
51 BX_ERROR(("XSAVE: access not aligned to 64-byte"));
52 exception(BX_GP_EXCEPTION
, 0, 0);
56 // We will go feature-by-feature and not run over all XCR0 bits
59 /////////////////////////////////////////////////////////////////////////////
60 if (BX_CPU_THIS_PTR xcr0
.get_FPU() && (EAX
& BX_XCR0_FPU_MASK
) != 0)
62 xmm
.xmm16u(0) = BX_CPU_THIS_PTR the_i387
.get_control_word();
63 xmm
.xmm16u(1) = BX_CPU_THIS_PTR the_i387
.get_status_word();
64 xmm
.xmm16u(2) = pack_FPU_TW(BX_CPU_THIS_PTR the_i387
.get_tag_word());
66 /* x87 FPU Opcode (16 bits) */
67 /* The lower 11 bits contain the FPU opcode, upper 5 bits are reserved */
68 xmm
.xmm16u(3) = BX_CPU_THIS_PTR the_i387
.foo
;
71 * x87 FPU IP Offset (32/64 bits)
72 * The contents of this field differ depending on the current
73 * addressing mode (16/32/64 bit) when the FXSAVE instruction was executed:
74 * + 64-bit mode - 64-bit IP offset
75 * + 32-bit mode - 32-bit IP offset
76 * + 16-bit mode - low 16 bits are IP offset; high 16 bits are reserved.
77 * x87 CS FPU IP Selector
78 * + 16 bit, in 16/32 bit mode only
82 xmm
.xmm64u(1) = (BX_CPU_THIS_PTR the_i387
.fip
);
87 xmm
.xmm32u(2) = (Bit32u
)(BX_CPU_THIS_PTR the_i387
.fip
);
88 xmm
.xmm32u(3) = (BX_CPU_THIS_PTR the_i387
.fcs
);
91 write_virtual_dqword(i
->seg(), eaddr
, (Bit8u
*) &xmm
);
94 * x87 FPU Instruction Operand (Data) Pointer Offset (32/64 bits)
95 * The contents of this field differ depending on the current
96 * addressing mode (16/32 bit) when the FXSAVE instruction was executed:
97 * + 64-bit mode - 64-bit offset
98 * + 32-bit mode - 32-bit offset
99 * + 16-bit mode - low 16 bits are offset; high 16 bits are reserved.
100 * x87 DS FPU Instruction Operand (Data) Pointer Selector
101 * + 16 bit, in 16/32 bit mode only
103 #if BX_SUPPORT_X86_64
105 write_virtual_qword(i
->seg(), eaddr
+ 16, BX_CPU_THIS_PTR the_i387
.fdp
);
110 write_virtual_dword(i
->seg(), eaddr
+ 16, (Bit32u
) BX_CPU_THIS_PTR the_i387
.fdp
);
111 write_virtual_dword(i
->seg(), eaddr
+ 20, (Bit32u
) BX_CPU_THIS_PTR the_i387
.fds
);
113 /* do not touch MXCSR state */
115 /* store i387 register file */
116 for(index
=0; index
< 8; index
++)
118 const floatx80
&fp
= BX_FPU_REG(index
);
120 xmm
.xmm64u(0) = fp
.fraction
;
122 xmm
.xmm16u(4) = fp
.exp
;
124 write_virtual_dqword(i
->seg(), eaddr
+index
*16+32, (Bit8u
*) &xmm
);
128 /////////////////////////////////////////////////////////////////////////////
129 if (BX_CPU_THIS_PTR xcr0
.get_SSE() && (EAX
& BX_XCR0_SSE_MASK
) != 0)
131 write_virtual_dword(i
->seg(), eaddr
+ 24, BX_MXCSR_REGISTER
);
132 write_virtual_dword(i
->seg(), eaddr
+ 28, MXCSR_MASK
);
134 /* store XMM register file */
135 for(index
=0; index
< BX_XMM_REGISTERS
; index
++)
137 // save XMM8-XMM15 only in 64-bit mode
138 if (index
< 8 || Is64BitMode()) {
139 write_virtual_dqword(i
->seg(),
140 eaddr
+index
*16+160, (Bit8u
*) &(BX_CPU_THIS_PTR xmm
[index
]));
145 // skip header update for now, required to know if a CPU feature is in its initial state
147 BX_INFO(("XSAVE: required XSAVE support, use --enable-xsave option"));
148 exception(BX_UD_EXCEPTION
, 0, 0);
153 void BX_CPP_AttrRegparmN(1) BX_CPU_C::XRSTOR(bxInstruction_c
*i
)
157 BxPackedXmmRegister xmm
;
159 BX_CPU_THIS_PTR
prepareXSAVE();
161 BX_DEBUG(("XRSTOR: restore processor state XCR0=0x%08x", BX_CPU_THIS_PTR xcr0
.getRegister()));
163 bx_address eaddr
= BX_CPU_CALL_METHODR(i
->ResolveModrm
, (i
));
164 bx_address laddr
= get_laddr(i
->seg(), eaddr
);
167 BX_ERROR(("XRSTOR: access not aligned to 64-byte"));
168 exception(BX_GP_EXCEPTION
, 0, 0);
171 Bit64u header1
= read_virtual_qword(i
->seg(), eaddr
+ 512);
172 Bit64u header2
= read_virtual_qword(i
->seg(), eaddr
+ 520);
173 Bit64u header3
= read_virtual_qword(i
->seg(), eaddr
+ 528);
175 if ((~BX_CPU_THIS_PTR xcr0
.getRegister() & header1
) != 0) {
176 BX_ERROR(("XRSTOR: Broken header state"));
177 exception(BX_GP_EXCEPTION
, 0, 0);
180 if (header2
!= 0 || header3
!= 0) {
181 BX_ERROR(("XRSTOR: Reserved header state is not '0"));
182 exception(BX_GP_EXCEPTION
, 0, 0);
186 // We will go feature-by-feature and not run over all XCR0 bits
189 /////////////////////////////////////////////////////////////////////////////
190 if (BX_CPU_THIS_PTR xcr0
.get_FPU() && (EAX
& BX_XCR0_FPU_MASK
) != 0)
192 if (header1
& BX_XCR0_FPU_MASK
) {
193 // load FPU state from XSAVE area
194 read_virtual_dqword(i
->seg(), eaddr
, (Bit8u
*) &xmm
);
196 BX_CPU_THIS_PTR the_i387
.cwd
= xmm
.xmm16u(0);
197 BX_CPU_THIS_PTR the_i387
.swd
= xmm
.xmm16u(1);
198 BX_CPU_THIS_PTR the_i387
.tos
= (xmm
.xmm16u(1) >> 11) & 0x07;
200 /* Restore x87 FPU Opcode */
201 /* The lower 11 bits contain the FPU opcode, upper 5 bits are reserved */
202 BX_CPU_THIS_PTR the_i387
.foo
= xmm
.xmm16u(3) & 0x7FF;
204 /* Restore x87 FPU IP */
205 #if BX_SUPPORT_X86_64
207 BX_CPU_THIS_PTR the_i387
.fip
= xmm
.xmm64u(1);
208 BX_CPU_THIS_PTR the_i387
.fcs
= 0;
213 BX_CPU_THIS_PTR the_i387
.fip
= xmm
.xmm32u(2);
214 BX_CPU_THIS_PTR the_i387
.fcs
= xmm
.xmm16u(6);
217 Bit32u tag_byte
= xmm
.xmmubyte(4);
219 /* Restore x87 FPU DP */
220 read_virtual_dqword(i
->seg(), eaddr
+ 16, (Bit8u
*) &xmm
);
222 #if BX_SUPPORT_X86_64
224 BX_CPU_THIS_PTR the_i387
.fdp
= xmm
.xmm64u(0);
225 BX_CPU_THIS_PTR the_i387
.fds
= 0;
230 BX_CPU_THIS_PTR the_i387
.fdp
= xmm
.xmm32u(0);
231 BX_CPU_THIS_PTR the_i387
.fds
= xmm
.xmm16u(2);
234 /* load i387 register file */
235 for(index
=0; index
< 8; index
++)
238 reg
.fraction
= read_virtual_qword(i
->seg(), eaddr
+index
*16+32);
239 reg
.exp
= read_virtual_word (i
->seg(), eaddr
+index
*16+40);
240 BX_FPU_REG(index
) = reg
;
243 /* Restore floating point tag word - see desription for FXRSTOR instruction */
244 BX_CPU_THIS_PTR the_i387
.twd
= unpack_FPU_TW(tag_byte
);
247 // initialize FPU with reset values
248 BX_CPU_THIS_PTR the_i387
.init();
250 for (index
=0;index
<8;index
++) {
251 floatx80 reg
= { 0, 0 };
252 BX_FPU_REG(index
) = reg
;
257 /////////////////////////////////////////////////////////////////////////////
258 if (BX_CPU_THIS_PTR xcr0
.get_SSE() && (EAX
& BX_XCR0_SSE_MASK
) != 0)
260 Bit32u new_mxcsr
= read_virtual_dword(i
->seg(), eaddr
+ 24);
261 if(new_mxcsr
& ~MXCSR_MASK
)
262 exception(BX_GP_EXCEPTION
, 0, 0);
264 if (header1
& BX_XCR0_SSE_MASK
) {
265 // load SSE state from XSAVE area
266 for(index
=0; index
< BX_XMM_REGISTERS
; index
++)
268 // restore XMM8-XMM15 only in 64-bit mode
269 if (index
< 8 || Is64BitMode()) {
270 read_virtual_dqword(i
->seg(),
271 eaddr
+index
*16+160, (Bit8u
*) &(BX_CPU_THIS_PTR xmm
[index
]));
276 // initialize SSE with reset values
277 for(index
=0; index
< BX_XMM_REGISTERS
; index
++) {
278 // set XMM8-XMM15 only in 64-bit mode
279 if (index
< 8 || Is64BitMode()) {
280 BX_CPU_THIS_PTR xmm
[index
].xmm64u(0) = 0;
281 BX_CPU_THIS_PTR xmm
[index
].xmm64u(1) = 0;
287 BX_INFO(("XRSTOR: required XSAVE support, use --enable-xsave option"));
288 exception(BX_UD_EXCEPTION
, 0, 0);
293 void BX_CPP_AttrRegparmN(1) BX_CPU_C::XGETBV(bxInstruction_c
*i
)
296 if(! (BX_CPU_THIS_PTR cr4
.get_OSXSAVE())) {
297 BX_ERROR(("XGETBV: OSXSAVE feature is not enabled in CR4!"));
298 exception(BX_UD_EXCEPTION
, 0, 0);
301 // For now hardcoded handle only XCR0 register, it should take a few
302 // years until extension will be required
304 BX_ERROR(("XGETBV: Invalid XCR register %d", ECX
));
305 exception(BX_GP_EXCEPTION
, 0, 0);
309 RAX
= BX_CPU_THIS_PTR xcr0
.getRegister();
311 BX_INFO(("XGETBV: required XSAVE support, use --enable-xsave option"));
312 exception(BX_UD_EXCEPTION
, 0, 0);
317 void BX_CPP_AttrRegparmN(1) BX_CPU_C::XSETBV(bxInstruction_c
*i
)
320 if (real_mode() || v8086_mode()) {
321 BX_ERROR(("XSETBV: not recognized in real or virtual-8086 mode"));
322 exception(BX_UD_EXCEPTION
, 0, 0);
325 if(! (BX_CPU_THIS_PTR cr4
.get_OSXSAVE())) {
326 BX_ERROR(("XSETBV: OSXSAVE feature is not enabled in CR4!"));
327 exception(BX_UD_EXCEPTION
, 0, 0);
331 BX_ERROR(("XSETBV: The current priveledge level is not 0"));
332 exception(BX_GP_EXCEPTION
, 0, 0);
335 // For now hardcoded handle only XCR0 register, it should take a few
336 // years until extension will be required
338 BX_ERROR(("XSETBV: Invalid XCR register %d", ECX
));
339 exception(BX_GP_EXCEPTION
, 0, 0);
342 if (EDX
!= 0 || (EAX
& ~BX_XCR0_SUPPORTED_BITS
) != 0 || (EAX
& 1) == 0) {
343 BX_ERROR(("XSETBV: Attempting to change reserved bits!"));
344 exception(BX_GP_EXCEPTION
, 0, 0);
347 BX_CPU_THIS_PTR xcr0
.setRegister(EAX
);
349 BX_INFO(("XSETBV: required XSAVE support, use --enable-xsave option"));
350 exception(BX_UD_EXCEPTION
, 0, 0);