step2 in XSAVE implementation

This commit is contained in:
Stanislav Shwartsman 2008-02-13 16:45:21 +00:00
parent c70d3e7d76
commit 457152334e
8 changed files with 436 additions and 89 deletions

View File

@ -1,5 +1,5 @@
/////////////////////////////////////////////////////////////////////////
// $Id: cpu.h,v 1.423 2008-02-12 22:41:39 sshwarts Exp $
// $Id: cpu.h,v 1.424 2008-02-13 16:45:20 sshwarts Exp $
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2001 MandrakeSoft S.A.
@ -859,6 +859,10 @@ public: // for now...
bx_efer_t efer;
#endif
#if BX_SUPPORT_XSAVE
xcr0_t xcr0;
#endif
/* SMM base register */
Bit32u smbase;
@ -3212,6 +3216,11 @@ public: // for now...
BX_SMF void prepareSSE(void);
BX_SMF void check_exceptionsSSE(int);
BX_SMF void print_state_SSE(void);
BX_SMF Bit16u unpack_FPU_TW(Bit16u tag_byte);
#endif
#if BX_SUPPORT_XSAVE
BX_SMF void prepareXSAVE(void);
#endif
#if BX_SUPPORT_MONITOR_MWAIT

View File

@ -1,5 +1,5 @@
/////////////////////////////////////////////////////////////////////////
// $Id: cpuid.cc,v 1.61 2008-02-02 21:46:50 sshwarts Exp $
// $Id: cpuid.cc,v 1.62 2008-02-13 16:45:20 sshwarts Exp $
/////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2007 Stanislav Shwartsman
@ -137,36 +137,44 @@ Bit32u BX_CPU_C::get_extended_cpuid_features()
// [18:15] reserved
// [19:19] SSE4.1: SSE4.1 Instructions
// [20:20] SSE4.2: SSE4.2 (SSE4E) Instructions
// [21:22] Reserved
// [23:23] POPCNT instruction support
// [31:21] reserved
// [21:22] X2APIC
// [22:22] Reserved
// [23:23] POPCNT instruction
// [25:24] reserved
// [26:26] XSAVE extensions support
// [27:27] OSXSAVE support
// [31:28] reserved
Bit32u features = 0;
#if BX_SUPPORT_SSE >= 3
features |= 0x1; // support SSE3
features |= 0x1; // support SSE3
#endif
#if BX_SUPPORT_MONITOR_MWAIT
features |= (1<<3); // support MONITOR/MWAIT
features |= (1<<3); // support MONITOR/MWAIT
#endif
#if (BX_SUPPORT_SSE >= 4) || (BX_SUPPORT_SSE >= 3 && BX_SUPPORT_SSE_EXTENSION > 0)
features |= (1<<9); // support SSE3E
features |= (1<<9); // support SSE3E
#endif
#if BX_SUPPORT_X86_64
features |= (1<<13); // support CMPXCHG16B
features |= (1<<13); // support CMPXCHG16B
#endif
#if BX_SUPPORT_SSE >= 4
features |= (1<<19); // support SSE4.1
features |= (1<<19); // support SSE4.1
#endif
#if (BX_SUPPORT_SSE >= 5) || (BX_SUPPORT_SSE >= 4 && BX_SUPPORT_SSE_EXTENSION > 0)
features |= (1<<20); // support SSE4.2 (SSE4E)
features |= (1<<20); // support SSE4.2 (SSE4E)
#endif
#if BX_SUPPORT_POPCNT || (BX_SUPPORT_SSE >= 5) || (BX_SUPPORT_SSE >= 4 && BX_SUPPORT_SSE_EXTENSION > 0)
features |= (1<<23); // support POPCNT instruction
features |= (1<<23); // support POPCNT instruction
#endif
#if BX_SUPPORT_XSAVE
features |= (1<<26) | (1<<27); // support XSAVE extensions
#endif
return features;

View File

@ -1,5 +1,5 @@
/////////////////////////////////////////////////////////////////////////
// $Id: crregs.h,v 1.6 2008-02-12 22:41:39 sshwarts Exp $
// $Id: crregs.h,v 1.7 2008-02-13 16:45:20 sshwarts Exp $
/////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2007 Stanislav Shwartsman
@ -116,6 +116,27 @@ typedef struct bx_efer_t {
} bx_efer_t;
#endif
#if BX_SUPPORT_XSAVE
typedef struct xcr0_reg_t {
Bit32u val32; // 32bit value of register
#define BX_XR0_SUPPORT_BITS 0x3
#define BX_XCR0_FPU_BIT 0
#define BX_XCR0_FPU_MASK (1<<BX_XCR0_FPU_BIT)
#define BX_XCR0_SSE_BIT 1
#define BX_XCR0_FPU_MASK (1<<BX_XCR0_SSE_BIT)
IMPLEMENT_CRREG_ACCESSORS(FPU, BX_XCR0_FPU_BIT);
#if BX_SUPPORT_SSE
IMPLEMENT_CRREG_ACCESSORS(SSE, BX_XCR0_SSE_BIT);
#endif
BX_CPP_INLINE Bit32u getRegister() { return val32; }
BX_CPP_INLINE void setRegister(Bit32u val) { val32 = val; }
} xcr0_t;
#endif
#undef IMPLEMENT_CRREG_ACCESSORS
#endif

View File

@ -1,5 +1,5 @@
/////////////////////////////////////////////////////////////////////////
// $Id: init.cc,v 1.153 2008-02-11 20:52:10 sshwarts Exp $
// $Id: init.cc,v 1.154 2008-02-13 16:45:20 sshwarts Exp $
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2001 MandrakeSoft S.A.
@ -358,6 +358,9 @@ void BX_CPU_C::register_state(void)
#if BX_CPU_LEVEL >= 4
BXRS_HEX_PARAM_FIELD(cpu, CR4, cr4.val32);
#endif
#if BX_SUPPORT_XSAVE
BXRS_HEX_PARAM_FIELD(cpu, XCR0, xcr0.val32);
#endif
for(i=0; i<6; i++) {
bx_segment_reg_t *segment = &BX_CPU_THIS_PTR sregs[i];
@ -892,6 +895,10 @@ void BX_CPU_C::reset(unsigned source)
BX_CPU_THIS_PTR cr4.setRegister(0);
#endif
#if BX_SUPPORT_XSAVE
BX_CPU_THIS_PTR xcr0.setRegister(0x1);
#endif
// CR0/CR4 paging might be modified
TLB_flush(1);

View File

@ -1,5 +1,5 @@
/////////////////////////////////////////////////////////////////////////
// $Id: mmx.cc,v 1.73 2008-02-02 21:46:52 sshwarts Exp $
// $Id: mmx.cc,v 1.74 2008-02-13 16:45:20 sshwarts Exp $
/////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2002 Stanislav Shwartsman
@ -92,12 +92,12 @@ void BX_CPU_C::print_state_MMX(void)
void BX_CPU_C::prepareMMX(void)
{
if(BX_CPU_THIS_PTR cr0.get_TS())
exception(BX_NM_EXCEPTION, 0, 0);
if(BX_CPU_THIS_PTR cr0.get_EM())
exception(BX_UD_EXCEPTION, 0, 0);
if(BX_CPU_THIS_PTR cr0.get_TS())
exception(BX_NM_EXCEPTION, 0, 0);
/* cause transition from FPU to MMX technology state */
BX_CPU_THIS_PTR prepareFPU2MMX();
}

View File

@ -1,5 +1,5 @@
/////////////////////////////////////////////////////////////////////////
// $Id: protect_ctrl.cc,v 1.74 2008-02-02 21:46:53 sshwarts Exp $
// $Id: protect_ctrl.cc,v 1.75 2008-02-13 16:45:20 sshwarts Exp $
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2001 MandrakeSoft S.A.
@ -317,7 +317,6 @@ void BX_CPU_C::LLDT_Ew(bxInstruction_c *i)
UndefinedOpcode(i);
}
/* #GP(0) if the current privilege level is not 0 */
if (CPL != 0) {
BX_ERROR(("LLDT: The current priveledge level is not 0"));
exception(BX_GP_EXCEPTION, 0, 0);
@ -396,7 +395,6 @@ void BX_CPU_C::LTR_Ew(bxInstruction_c *i)
UndefinedOpcode(i);
}
/* #GP(0) if the current privilege level is not 0 */
if (CPL != 0) {
BX_ERROR(("LTR: The current priveledge level is not 0"));
exception(BX_GP_EXCEPTION, 0, 0);

View File

@ -1,5 +1,5 @@
/////////////////////////////////////////////////////////////////////////
// $Id: sse_move.cc,v 1.77 2008-02-02 21:46:53 sshwarts Exp $
// $Id: sse_move.cc,v 1.78 2008-02-13 16:45:21 sshwarts Exp $
/////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2003 Stanislav Shwartsman
@ -30,14 +30,14 @@
void BX_CPU_C::prepareSSE(void)
{
if(BX_CPU_THIS_PTR cr0.get_TS())
exception(BX_NM_EXCEPTION, 0, 0);
if(BX_CPU_THIS_PTR cr0.get_EM())
exception(BX_UD_EXCEPTION, 0, 0);
if(! (BX_CPU_THIS_PTR cr4.get_OSFXSR()))
exception(BX_UD_EXCEPTION, 0, 0);
if(BX_CPU_THIS_PTR cr0.get_TS())
exception(BX_NM_EXCEPTION, 0, 0);
}
#define BX_MXCSR_REGISTER (BX_CPU_THIS_PTR mxcsr.mxcsr)
@ -52,6 +52,64 @@ void BX_CPU_C::print_state_SSE(void)
}
}
Bit16u BX_CPU_C::unpack_FPU_TW(Bit16u tag_byte)
{
Bit32u twd = 0;
/* FTW
*
* Note that the original format for FTW can be recreated from the stored
* FTW valid bits and the stored 80-bit FP data (assuming the stored data
* was not the contents of MMX registers) using the following table:
| Exponent | Exponent | Fraction | J,M bits | FTW valid | x87 FTW |
| all 1s | all 0s | all 0s | | | |
-------------------------------------------------------------------
| 0 | 0 | 0 | 0x | 1 | S 10 |
| 0 | 0 | 0 | 1x | 1 | V 00 |
-------------------------------------------------------------------
| 0 | 0 | 1 | 00 | 1 | S 10 |
| 0 | 0 | 1 | 10 | 1 | V 00 |
-------------------------------------------------------------------
| 0 | 1 | 0 | 0x | 1 | S 10 |
| 0 | 1 | 0 | 1x | 1 | S 10 |
-------------------------------------------------------------------
| 0 | 1 | 1 | 00 | 1 | Z 01 |
| 0 | 1 | 1 | 10 | 1 | S 10 |
-------------------------------------------------------------------
| 1 | 0 | 0 | 1x | 1 | S 10 |
| 1 | 0 | 0 | 1x | 1 | S 10 |
-------------------------------------------------------------------
| 1 | 0 | 1 | 00 | 1 | S 10 |
| 1 | 0 | 1 | 10 | 1 | S 10 |
-------------------------------------------------------------------
| all combinations above | 0 | E 11 |
*
* The J-bit is defined to be the 1-bit binary integer to the left of
* the decimal place in the significand.
*
* The M-bit is defined to be the most significant bit of the fractional
* portion of the significand (i.e., the bit immediately to the right of
* the decimal place). When the M-bit is the most significant bit of the
* fractional portion of the significand, it must be 0 if the fraction
* is all 0's.
*/
for(unsigned index = 7;index >= 0; index--, twd <<= 2, tag_byte <<= 1)
{
if(tag_byte & 0x80) {
const floatx80 &fpu_reg = BX_FPU_REG(index);
twd |= FPU_tagof(fpu_reg);
}
else {
twd |= FPU_Tag_Empty;
}
}
return (twd >> 2);
}
#endif
/* ************************************ */
@ -246,8 +304,8 @@ void BX_CPU_C::FXRSTOR(bxInstruction_c *i)
read_virtual_dqword_aligned(i->seg(), RMAddr(i), (Bit8u *) &xmm);
BX_CPU_THIS_PTR the_i387.cwd = xmm.xmm16u(0);
BX_CPU_THIS_PTR the_i387.swd = xmm.xmm16u(1);
BX_CPU_THIS_PTR the_i387.cwd = xmm.xmm16u(0);
BX_CPU_THIS_PTR the_i387.swd = xmm.xmm16u(1);
BX_CPU_THIS_PTR the_i387.tos = (xmm.xmm16u(1) >> 11) & 0x07;
/* Restore x87 FPU Opcode */
@ -256,9 +314,9 @@ void BX_CPU_C::FXRSTOR(bxInstruction_c *i)
/* Restore x87 FPU IP */
#if BX_SUPPORT_X86_64
if (i->os64L()) /* 64 bit operand size mode */
{
if (i->os64L()) {
BX_CPU_THIS_PTR the_i387.fip = xmm.xmm64u(1);
BX_CPU_THIS_PTR the_i387.fcs = 0;
}
else
#endif
@ -267,15 +325,15 @@ void BX_CPU_C::FXRSTOR(bxInstruction_c *i)
BX_CPU_THIS_PTR the_i387.fcs = xmm.xmm16u(5);
}
Bit32u twd = 0, tag_byte = xmm.xmm16u(2);
Bit32u tag_byte = xmm.xmmubyte(4);
/* Restore x87 FPU DP */
read_virtual_dqword_aligned(i->seg(), RMAddr(i) + 16, (Bit8u *) &xmm);
#if BX_SUPPORT_X86_64
if (i->os64L()) /* 64 bit operand size mode */
{
if (i->os64L()) {
BX_CPU_THIS_PTR the_i387.fdp = xmm.xmm64u(0);
BX_CPU_THIS_PTR the_i387.fds = 0;
}
else
#endif
@ -303,58 +361,7 @@ void BX_CPU_C::FXRSTOR(bxInstruction_c *i)
read_virtual_tword(i->seg(), RMAddr(i)+index*16+32, &(BX_FPU_REG(index)));
}
/* FTW
*
* Note that the original format for FTW can be recreated from the stored
* FTW valid bits and the stored 80-bit FP data (assuming the stored data
* was not the contents of MMX registers) using the following table:
| Exponent | Exponent | Fraction | J,M bits | FTW valid | x87 FTW |
| all 1s | all 0s | all 0s | | | |
-------------------------------------------------------------------
| 0 | 0 | 0 | 0x | 1 | S 10 |
| 0 | 0 | 0 | 1x | 1 | V 00 |
-------------------------------------------------------------------
| 0 | 0 | 1 | 00 | 1 | S 10 |
| 0 | 0 | 1 | 10 | 1 | V 00 |
-------------------------------------------------------------------
| 0 | 1 | 0 | 0x | 1 | S 10 |
| 0 | 1 | 0 | 1x | 1 | S 10 |
-------------------------------------------------------------------
| 0 | 1 | 1 | 00 | 1 | Z 01 |
| 0 | 1 | 1 | 10 | 1 | S 10 |
-------------------------------------------------------------------
| 1 | 0 | 0 | 1x | 1 | S 10 |
| 1 | 0 | 0 | 1x | 1 | S 10 |
-------------------------------------------------------------------
| 1 | 0 | 1 | 00 | 1 | S 10 |
| 1 | 0 | 1 | 10 | 1 | S 10 |
-------------------------------------------------------------------
| all combinations above | 0 | E 11 |
*
* The J-bit is defined to be the 1-bit binary integer to the left of
* the decimal place in the significand.
*
* The M-bit is defined to be the most significant bit of the fractional
* portion of the significand (i.e., the bit immediately to the right of
* the decimal place). When the M-bit is the most significant bit of the
* fractional portion of the significand, it must be 0 if the fraction
* is all 0's.
*/
for(index = 7;index >= 0; index--, twd <<= 2, tag_byte <<= 1)
{
if(tag_byte & 0x80) {
const floatx80 &fpu_reg = BX_FPU_REG(index);
twd |= FPU_tagof(fpu_reg);
}
else {
twd |= FPU_Tag_Empty;
}
}
BX_CPU_THIS_PTR the_i387.twd = (twd >> 2);
BX_CPU_THIS_PTR the_i387.twd = unpack_FPU_TW(tag_byte);
#if BX_SUPPORT_X86_64
if (BX_CPU_THIS_PTR efer.ffxsr && CPL == 0 && Is64BitMode())

View File

@ -1,5 +1,5 @@
/////////////////////////////////////////////////////////////////////////
// $Id: xsave.cc,v 1.1 2008-02-12 22:42:47 sshwarts Exp $
// $Id: xsave.cc,v 1.2 2008-02-13 16:45:21 sshwarts Exp $
/////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2008 Stanislav Shwartsman
@ -26,13 +26,152 @@
#include "cpu.h"
#define LOG_THIS BX_CPU_THIS_PTR
// Make code more tidy with a few macros.
#if BX_SUPPORT_X86_64==0
#define RAX EAX
#define RDX EDX
#endif
// TODO:
// 1. CPUID leaf, CPU function ECX[26], ECX[27]
// 2. SSE #UD generation new way
#if BX_SUPPORT_XSAVE
void BX_CPU_C::prepareXSAVE(void)
{
if(! (BX_CPU_THIS_PTR cr4.get_OSXSAVE()))
exception(BX_UD_EXCEPTION, 0, 0);
if(BX_CPU_THIS_PTR cr0.get_TS())
exception(BX_NM_EXCEPTION, 0, 0);
}
#endif
/* 0F AE /4 */
void BX_CPU_C::XSAVE(bxInstruction_c *i)
{
#if BX_SUPPORT_XSAVE
unsigned index;
BxPackedXmmRegister xmm;
BX_PANIC(("XSAVE still not implemented !"));
BX_CPU_THIS_PTR prepareXSAVE();
BX_DEBUG(("XSAVE: save processor state XCR0=0x%08x", BX_CPU_THIS_PTR xcr.getRegister()));
BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
bx_address laddr = BX_CPU_THIS_PTR get_segment_base(i->seg()) + RMAddr(i);
if (laddr & 0x3f) {
BX_ERROR(("XSAVE: access not aligned to 64-byte"));
exception(BX_GP_EXCEPTION, 0, 0);
}
//
// We will go feature-by-feature and not run over all XCR0 bits
//
/////////////////////////////////////////////////////////////////////////////
if (BX_CPU_THIS_PTR xcr0.get_FPU() && (EAX & BX_XCR0_FPU_MASK) != 0)
{
xmm.xmm16u(0) = BX_CPU_THIS_PTR the_i387.get_control_word();
xmm.xmm16u(1) = BX_CPU_THIS_PTR the_i387.get_status_word ();
Bit16u twd = BX_CPU_THIS_PTR the_i387.get_tag_word(), tag_byte = 0;
if((twd & 0x0003) != 0x0003) tag_byte |= 0x01;
if((twd & 0x000c) != 0x000c) tag_byte |= 0x02;
if((twd & 0x0030) != 0x0030) tag_byte |= 0x04;
if((twd & 0x00c0) != 0x00c0) tag_byte |= 0x08;
if((twd & 0x0300) != 0x0300) tag_byte |= 0x10;
if((twd & 0x0c00) != 0x0c00) tag_byte |= 0x20;
if((twd & 0x3000) != 0x3000) tag_byte |= 0x40;
if((twd & 0xc000) != 0xc000) tag_byte |= 0x80;
xmm.xmm16u(2) = tag_byte;
/* x87 FPU Opcode (16 bits) */
/* The lower 11 bits contain the FPU opcode, upper 5 bits are reserved */
xmm.xmm16u(3) = BX_CPU_THIS_PTR the_i387.foo;
/*
* x87 FPU IP Offset (32/64 bits)
* The contents of this field differ depending on the current
* addressing mode (16/32/64 bit) when the FXSAVE instruction was executed:
* + 64-bit mode - 64-bit IP offset
* + 32-bit mode - 32-bit IP offset
* + 16-bit mode - low 16 bits are IP offset; high 16 bits are reserved.
* x87 CS FPU IP Selector
* + 16 bit, in 16/32 bit mode only
*/
#if BX_SUPPORT_X86_64
if (i->os64L()) {
xmm.xmm64u(1) = (BX_CPU_THIS_PTR the_i387.fip);
}
else
#endif
{
xmm.xmm32u(2) = (Bit32u)(BX_CPU_THIS_PTR the_i387.fip) & 0xffffffff;
xmm.xmm32u(3) = (BX_CPU_THIS_PTR the_i387.fcs);
}
write_virtual_dqword_aligned(i->seg(), RMAddr(i), (Bit8u *) &xmm);
/*
* x87 FPU Instruction Operand (Data) Pointer Offset (32/64 bits)
* The contents of this field differ depending on the current
* addressing mode (16/32 bit) when the FXSAVE instruction was executed:
* + 64-bit mode - 64-bit offset
* + 32-bit mode - 32-bit offset
* + 16-bit mode - low 16 bits are offset; high 16 bits are reserved.
* x87 DS FPU Instruction Operand (Data) Pointer Selector
* + 16 bit, in 16/32 bit mode only
*/
#if BX_SUPPORT_X86_64
if (i->os64L()) {
write_virtual_qword(i->seg(), RMAddr(i) + 16, BX_CPU_THIS_PTR the_i387.fdp);
}
else
#endif
{
write_virtual_dword(i->seg(), RMAddr(i) + 16,
(Bit32u)(BX_CPU_THIS_PTR the_i387.fdp & 0xffffffff));
write_virtual_dword(i->seg(), RMAddr(i) + 20,
(Bit32u)(BX_CPU_THIS_PTR the_i387.fds));
}
/* do not touch MXCSR state */
/* store i387 register file */
for(index=0; index < 8; index++)
{
const floatx80 &fp = BX_FPU_REG(index);
xmm.xmm64u(0) = fp.fraction;
xmm.xmm64u(1) = 0;
xmm.xmm16u(4) = fp.exp;
write_virtual_dqword_aligned(i->seg(), RMAddr(i)+index*16+32, (Bit8u *) &xmm);
}
}
/////////////////////////////////////////////////////////////////////////////
if (BX_CPU_THIS_PTR xcr0.get_SSE() && (EAX & BX_XCR0_SSE_MASK) != 0)
{
write_virtual_dword(i->seg(), RMAddr(i) + 24, BX_MXCSR_REGISTER);
write_virtual_dword(i->seg(), RMAddr(i) + 28, MXCSR_MASK);
/* store XMM register file */
for(index=0; index < BX_XMM_REGISTERS; index++)
{
// save XMM8-XMM15 only in 64-bit mode
if (index < 8 || Is64BitMode()) {
write_virtual_dqword_aligned(i->seg(),
RMAddr(i)+index*16+160, (Bit8u *) &(BX_CPU_THIS_PTR xmm[index]));
}
}
}
// skip header state update for now, required to know if the CPU feature is in its initial state
#else
BX_INFO(("XSAVE: required XSAVE support, use --enable-xsave option"));
UndefinedOpcode(i);
@ -43,9 +182,131 @@ void BX_CPU_C::XSAVE(bxInstruction_c *i)
void BX_CPU_C::XRSTOR(bxInstruction_c *i)
{
#if BX_SUPPORT_XSAVE
unsigned index;
BxPackedXmmRegister xmm;
BX_PANIC(("XRSTOR still not implemented !"));
BX_CPU_THIS_PTR prepareXSAVE();
BX_DEBUG(("XRSTOR: restore processor state XCR0=0x%08x", BX_CPU_THIS_PTR xcr.getRegister()));
BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
bx_address laddr = BX_CPU_THIS_PTR get_segment_base(i->seg()) + RMAddr(i);
if (laddr & 0x3f) {
BX_ERROR(("XRSTOR: access not aligned to 64-byte"));
exception(BX_GP_EXCEPTION, 0, 0);
}
Bit64u header1 = read_virtual_qword(i->seg(), RMAddr(i) + 512);
Bit64u header2 = read_virtual_qword(i->seg(), RMAddr(i) + 520);
Bit64u header3 = read_virtual_qword(i->seg(), RMAddr(i) + 528);
if ((~BX_CPU_THIS_PTR xr0.getRegister() & header1) != 0) {
BX_ERROR(("XRSTOR: Broken header state"));
exception(BX_GP_EXCEPTION, 0, 0);
}
if (header2 != 0 || header3 != 0) {
BX_ERROR(("XRSTOR: Reserved header state is not '0"));
exception(BX_GP_EXCEPTION, 0, 0);
}
//
// We will go feature-by-feature and not run over all XCR0 bits
//
/////////////////////////////////////////////////////////////////////////////
if (BX_CPU_THIS_PTR xcr0.get_FPU() && (EAX & BX_XCR0_FPU_MASK) != 0)
{
if (header1 & BX_XCR0_FPU_MASK) {
// load FPU state from XSAVE area
read_virtual_dqword_aligned(i->seg(), RMAddr(i), (Bit8u *) &xmm);
BX_CPU_THIS_PTR the_i387.cwd = xmm.xmm16u(0);
BX_CPU_THIS_PTR the_i387.swd = xmm.xmm16u(1);
BX_CPU_THIS_PTR the_i387.tos = (xmm.xmm16u(1) >> 11) & 0x07;
/* Restore x87 FPU Opcode */
/* The lower 11 bits contain the FPU opcode, upper 5 bits are reserved */
BX_CPU_THIS_PTR the_i387.foo = xmm.xmm16u(3) & 0x7FF;
/* Restore x87 FPU IP */
#if BX_SUPPORT_X86_64
if (i->os64L()) {
BX_CPU_THIS_PTR the_i387.fip = xmm.xmm64u(1);
BX_CPU_THIS_PTR the_i387.fcs = 0;
}
else
#endif
{
BX_CPU_THIS_PTR the_i387.fip = xmm.xmm32u(2);
BX_CPU_THIS_PTR the_i387.fcs = xmm.xmm16u(5);
}
Bit32u tag_byte = xmm.xmmubyte(4);
/* Restore x87 FPU DP */
read_virtual_dqword_aligned(i->seg(), RMAddr(i) + 16, (Bit8u *) &xmm);
#if BX_SUPPORT_X86_64
if (i->os64L()) {
BX_CPU_THIS_PTR the_i387.fdp = xmm.xmm64u(0);
BX_CPU_THIS_PTR the_i387.fds = 0;
}
else
#endif
{
BX_CPU_THIS_PTR the_i387.fdp = xmm.xmm32u(0);
BX_CPU_THIS_PTR the_i387.fds = xmm.xmm16u(2);
}
/* load i387 register file */
for(index=0; index < 8; index++)
{
read_virtual_tword(i->seg(), RMAddr(i)+index*16+32, &(BX_FPU_REG(index)));
}
/* Restore floating point tag word - see desription for FXRSTOR instruction */
BX_CPU_THIS_PTR the_i387.twd = unpack_FPU_TW(tag_byte);
}
else {
// initialize FPU with reset values
BX_CPU_THIS_PTR the_i387.init();
for (index=0;index<8;index++) {
BX_CPU_THIS_PTR the_i387.st_space[index].exp = 0;
BX_CPU_THIS_PTR the_i387.st_space[index].fraction = 0;
}
}
}
/////////////////////////////////////////////////////////////////////////////
if (BX_CPU_THIS_PTR xcr0.get_SSE() && (EAX & BX_XCR0_SSE_MASK) != 0)
{
Bit32u new_mxcsr = read_virtual_dword(i->seg(), RMAddr(i) + 24);
if(new_mxcsr & ~MXCSR_MASK)
exception(BX_GP_EXCEPTION, 0, 0);
if (header1 & BX_XCR0_SSE_MASK) {
// load SSE state from XSAVE area
for(index=0; index < BX_XMM_REGISTERS; index++)
{
// restore XMM8-XMM15 only in 64-bit mode
if (index < 8 || Is64BitMode()) {
read_virtual_dqword_aligned(i->seg(),
RMAddr(i)+index*16+160, (Bit8u *) &(BX_CPU_THIS_PTR xmm[index]));
}
}
}
else {
// initialize SSE with reset values
for(index=0; index < BX_XMM_REGISTERS; index++) {
// set XMM8-XMM15 only in 64-bit mode
if (index < 8 || Is64BitMode()) BX_CPU_THIS_PTR xmm[index] = 0;
}
}
}
#else
BX_INFO(("XRSTOR: required XSAVE support, use --enable-xsave option"));
UndefinedOpcode(i);
@ -56,9 +317,20 @@ void BX_CPU_C::XRSTOR(bxInstruction_c *i)
void BX_CPU_C::XGETBV(bxInstruction_c *i)
{
#if BX_SUPPORT_XSAVE
if(! (BX_CPU_THIS_PTR cr4.get_OSXSAVE())) {
BX_ERROR(("XGETBV: OSXSAVE feature is not enabled in CR4!"));
exception(BX_UD_EXCEPTION, 0, 0);
}
BX_PANIC(("XGETBV still not implemented !"));
// For now hardcoded handle only XCR0 register, it should take a few
// years until extension will be required
if (ECX != 0) {
BX_ERROR(("XGETBV: Invalid XCR register %d", ECX));
exception(BX_GP_EXCEPTION, 0, 0);
}
RDX = 0;
RAX = BX_CPU_THIS_PTR xrc0.setRegister();
#else
BX_INFO(("XGETBV: required XSAVE support, use --enable-xsave option"));
UndefinedOpcode(i);
@ -69,9 +341,34 @@ void BX_CPU_C::XGETBV(bxInstruction_c *i)
void BX_CPU_C::XSETBV(bxInstruction_c *i)
{
#if BX_SUPPORT_XSAVE
if (real_mode() || v8086_mode()) {
BX_ERROR(("XSETBV: not recognized in real or virtual-8086 mode"));
exception(BX_UD_EXCEPTION, 0, 0);
}
BX_PANIC(("XSETBV still not implemented !"));
if(! (BX_CPU_THIS_PTR cr4.get_OSXSAVE())) {
BX_ERROR(("XSETBV: OSXSAVE feature is not enabled in CR4!"));
exception(BX_UD_EXCEPTION, 0, 0);
}
if (CPL != 0) {
BX_ERROR(("XSETBV: The current priveledge level is not 0"));
exception(BX_GP_EXCEPTION, 0, 0);
}
// For now hardcoded handle only XCR0 register, it should take a few
// years until extension will be required
if (ECX != 0) {
BX_ERROR(("XSETBV: Invalid XCR register %d", ECX));
exception(BX_GP_EXCEPTION, 0, 0);
}
if (EDX != 0 || (EAX & ~BX_XR0_SUPPORT_BITS) != 0 || (EAX & 1) == 0) {
BX_ERROR(("XSETBV: Attempting to change reserved bits!"));
exception(BX_GP_EXCEPTION, 0, 0);
}
BX_CPU_THIS_PTR xrc0.setRegister(EAX);
#else
BX_INFO(("XSETBV: required XSAVE support, use --enable-xsave option"));
UndefinedOpcode(i);