- compilation fixes for MSVC toolkit 2003
[bochs-mirror.git] / cpu / xsave.cc
blob28d0e281d6315dccf86a8f4405ae08a57fa5e3b1
1 /////////////////////////////////////////////////////////////////////////
2 // $Id: xsave.cc,v 1.14 2008/08/16 12:19:30 sshwarts Exp $
3 /////////////////////////////////////////////////////////////////////////
4 //
5 // Copyright (c) 2008 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.
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
25 #include "bochs.h"
26 #include "cpu.h"
27 #define LOG_THIS BX_CPU_THIS_PTR
29 // Make code more tidy with a few macros.
30 #if BX_SUPPORT_X86_64==0
31 #define RAX EAX
32 #define RDX EDX
33 #endif
35 /* 0F AE /4 */
36 void BX_CPP_AttrRegparmN(1) BX_CPU_C::XSAVE(bxInstruction_c *i)
38 #if BX_SUPPORT_XSAVE
39 unsigned index;
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);
50 if (laddr & 0x3f) {
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
80 #if BX_SUPPORT_X86_64
81 if (i->os64L()) {
82 xmm.xmm64u(1) = (BX_CPU_THIS_PTR the_i387.fip);
84 else
85 #endif
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
104 if (i->os64L()) {
105 write_virtual_qword(i->seg(), eaddr + 16, BX_CPU_THIS_PTR the_i387.fdp);
107 else
108 #endif
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;
121 xmm.xmm64u(1) = 0;
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
146 #else
147 BX_INFO(("XSAVE: required XSAVE support, use --enable-xsave option"));
148 exception(BX_UD_EXCEPTION, 0, 0);
149 #endif
152 /* 0F AE /5 */
153 void BX_CPP_AttrRegparmN(1) BX_CPU_C::XRSTOR(bxInstruction_c *i)
155 #if BX_SUPPORT_XSAVE
156 unsigned index;
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);
166 if (laddr & 0x3f) {
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
206 if (i->os64L()) {
207 BX_CPU_THIS_PTR the_i387.fip = xmm.xmm64u(1);
208 BX_CPU_THIS_PTR the_i387.fcs = 0;
210 else
211 #endif
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
223 if (i->os64L()) {
224 BX_CPU_THIS_PTR the_i387.fdp = xmm.xmm64u(0);
225 BX_CPU_THIS_PTR the_i387.fds = 0;
227 else
228 #endif
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++)
237 floatx80 reg;
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);
246 else {
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]));
275 else {
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;
286 #else
287 BX_INFO(("XRSTOR: required XSAVE support, use --enable-xsave option"));
288 exception(BX_UD_EXCEPTION, 0, 0);
289 #endif
292 /* 0F 01 D0 */
293 void BX_CPP_AttrRegparmN(1) BX_CPU_C::XGETBV(bxInstruction_c *i)
295 #if BX_SUPPORT_XSAVE
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
303 if (ECX != 0) {
304 BX_ERROR(("XGETBV: Invalid XCR register %d", ECX));
305 exception(BX_GP_EXCEPTION, 0, 0);
308 RDX = 0;
309 RAX = BX_CPU_THIS_PTR xcr0.getRegister();
310 #else
311 BX_INFO(("XGETBV: required XSAVE support, use --enable-xsave option"));
312 exception(BX_UD_EXCEPTION, 0, 0);
313 #endif
316 /* 0F 01 D1 */
317 void BX_CPP_AttrRegparmN(1) BX_CPU_C::XSETBV(bxInstruction_c *i)
319 #if BX_SUPPORT_XSAVE
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);
330 if (CPL != 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
337 if (ECX != 0) {
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);
348 #else
349 BX_INFO(("XSETBV: required XSAVE support, use --enable-xsave option"));
350 exception(BX_UD_EXCEPTION, 0, 0);
351 #endif