2008-02-13 01:42:47 +03:00
|
|
|
/////////////////////////////////////////////////////////////////////////
|
2009-10-18 21:16:08 +04:00
|
|
|
// $Id: xsave.cc,v 1.19 2009-10-18 17:16:08 sshwarts Exp $
|
2008-02-13 01:42:47 +03:00
|
|
|
/////////////////////////////////////////////////////////////////////////
|
|
|
|
//
|
2009-10-15 00:45:29 +04:00
|
|
|
// Copyright (c) 2008-2009 Stanislav Shwartsman
|
2008-02-13 01:42:47 +03:00
|
|
|
// Written by Stanislav Shwartsman [sshwarts at sourceforge net]
|
|
|
|
//
|
|
|
|
// This library is free software; you can redistribute it and/or
|
|
|
|
// modify it under the terms of the GNU Lesser General Public
|
|
|
|
// License as published by the Free Software Foundation; either
|
|
|
|
// version 2 of the License, or (at your option) any later version.
|
|
|
|
//
|
|
|
|
// This library is distributed in the hope that it will be useful,
|
|
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
// Lesser General Public License for more details.
|
|
|
|
//
|
|
|
|
// You should have received a copy of the GNU Lesser General Public
|
|
|
|
// License along with this library; if not, write to the Free Software
|
2009-01-16 21:18:59 +03:00
|
|
|
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA B 02110-1301 USA
|
2008-02-13 01:42:47 +03:00
|
|
|
//
|
|
|
|
/////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
#define NEED_CPU_REG_SHORTCUTS 1
|
|
|
|
#include "bochs.h"
|
|
|
|
#include "cpu.h"
|
|
|
|
#define LOG_THIS BX_CPU_THIS_PTR
|
|
|
|
|
2008-02-13 19:45:21 +03:00
|
|
|
// Make code more tidy with a few macros.
|
|
|
|
#if BX_SUPPORT_X86_64==0
|
|
|
|
#define RAX EAX
|
|
|
|
#define RDX EDX
|
|
|
|
#endif
|
|
|
|
|
2008-02-13 01:42:47 +03:00
|
|
|
/* 0F AE /4 */
|
2008-03-23 00:29:41 +03:00
|
|
|
void BX_CPP_AttrRegparmN(1) BX_CPU_C::XSAVE(bxInstruction_c *i)
|
2008-02-13 01:42:47 +03:00
|
|
|
{
|
|
|
|
#if BX_SUPPORT_XSAVE
|
2008-02-13 19:45:21 +03:00
|
|
|
unsigned index;
|
|
|
|
BxPackedXmmRegister xmm;
|
|
|
|
|
|
|
|
BX_CPU_THIS_PTR prepareXSAVE();
|
|
|
|
|
2008-12-06 13:21:55 +03:00
|
|
|
BX_DEBUG(("XSAVE: save processor state XCR0=0x%08x", BX_CPU_THIS_PTR xcr0.get32()));
|
2008-02-13 19:45:21 +03:00
|
|
|
|
2008-08-08 13:22:49 +04:00
|
|
|
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
2008-02-13 19:45:21 +03:00
|
|
|
|
2008-08-08 13:22:49 +04:00
|
|
|
bx_address laddr = get_laddr(i->seg(), eaddr);
|
2008-02-13 19:45:21 +03:00
|
|
|
|
|
|
|
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();
|
2008-05-10 17:34:47 +04:00
|
|
|
xmm.xmm16u(1) = BX_CPU_THIS_PTR the_i387.get_status_word();
|
|
|
|
xmm.xmm16u(2) = pack_FPU_TW(BX_CPU_THIS_PTR the_i387.get_tag_word());
|
2008-02-13 19:45:21 +03:00
|
|
|
|
|
|
|
/* 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
|
|
|
|
{
|
2008-08-16 16:19:30 +04:00
|
|
|
xmm.xmm32u(2) = (Bit32u)(BX_CPU_THIS_PTR the_i387.fip);
|
2008-02-13 19:45:21 +03:00
|
|
|
xmm.xmm32u(3) = (BX_CPU_THIS_PTR the_i387.fcs);
|
|
|
|
}
|
|
|
|
|
2008-08-08 13:22:49 +04:00
|
|
|
write_virtual_dqword(i->seg(), eaddr, (Bit8u *) &xmm);
|
2008-02-13 19:45:21 +03:00
|
|
|
|
|
|
|
/*
|
|
|
|
* 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()) {
|
2008-08-08 13:22:49 +04:00
|
|
|
write_virtual_qword(i->seg(), eaddr + 16, BX_CPU_THIS_PTR the_i387.fdp);
|
2008-02-13 19:45:21 +03:00
|
|
|
}
|
|
|
|
else
|
|
|
|
#endif
|
|
|
|
{
|
2008-08-16 16:19:30 +04:00
|
|
|
write_virtual_dword(i->seg(), eaddr + 16, (Bit32u) BX_CPU_THIS_PTR the_i387.fdp);
|
|
|
|
write_virtual_dword(i->seg(), eaddr + 20, (Bit32u) BX_CPU_THIS_PTR the_i387.fds);
|
2008-02-13 19:45:21 +03:00
|
|
|
}
|
|
|
|
/* 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;
|
2008-02-13 01:42:47 +03:00
|
|
|
|
2008-08-08 13:22:49 +04:00
|
|
|
write_virtual_dqword(i->seg(), eaddr+index*16+32, (Bit8u *) &xmm);
|
2008-02-13 19:45:21 +03:00
|
|
|
}
|
|
|
|
}
|
2008-02-13 01:42:47 +03:00
|
|
|
|
2008-02-13 19:45:21 +03:00
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
if (BX_CPU_THIS_PTR xcr0.get_SSE() && (EAX & BX_XCR0_SSE_MASK) != 0)
|
|
|
|
{
|
2008-08-08 13:22:49 +04:00
|
|
|
write_virtual_dword(i->seg(), eaddr + 24, BX_MXCSR_REGISTER);
|
|
|
|
write_virtual_dword(i->seg(), eaddr + 28, MXCSR_MASK);
|
2008-02-13 19:45:21 +03:00
|
|
|
|
|
|
|
/* store XMM register file */
|
|
|
|
for(index=0; index < BX_XMM_REGISTERS; index++)
|
|
|
|
{
|
|
|
|
// save XMM8-XMM15 only in 64-bit mode
|
|
|
|
if (index < 8 || Is64BitMode()) {
|
2008-02-13 20:06:44 +03:00
|
|
|
write_virtual_dqword(i->seg(),
|
2008-08-08 13:22:49 +04:00
|
|
|
eaddr+index*16+160, (Bit8u *) &(BX_CPU_THIS_PTR xmm[index]));
|
2008-02-13 19:45:21 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-02-13 20:06:44 +03:00
|
|
|
// skip header update for now, required to know if a CPU feature is in its initial state
|
2008-02-13 01:42:47 +03:00
|
|
|
#else
|
|
|
|
BX_INFO(("XSAVE: required XSAVE support, use --enable-xsave option"));
|
2008-07-13 19:35:10 +04:00
|
|
|
exception(BX_UD_EXCEPTION, 0, 0);
|
2008-02-13 01:42:47 +03:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
/* 0F AE /5 */
|
2008-03-23 00:29:41 +03:00
|
|
|
void BX_CPP_AttrRegparmN(1) BX_CPU_C::XRSTOR(bxInstruction_c *i)
|
2008-02-13 01:42:47 +03:00
|
|
|
{
|
|
|
|
#if BX_SUPPORT_XSAVE
|
2008-02-13 19:45:21 +03:00
|
|
|
unsigned index;
|
|
|
|
BxPackedXmmRegister xmm;
|
|
|
|
|
|
|
|
BX_CPU_THIS_PTR prepareXSAVE();
|
|
|
|
|
2008-12-06 13:21:55 +03:00
|
|
|
BX_DEBUG(("XRSTOR: restore processor state XCR0=0x%08x", BX_CPU_THIS_PTR xcr0.get32()));
|
2008-02-13 19:45:21 +03:00
|
|
|
|
2008-08-08 13:22:49 +04:00
|
|
|
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
|
|
|
bx_address laddr = get_laddr(i->seg(), eaddr);
|
2008-02-13 19:45:21 +03:00
|
|
|
|
|
|
|
if (laddr & 0x3f) {
|
|
|
|
BX_ERROR(("XRSTOR: access not aligned to 64-byte"));
|
|
|
|
exception(BX_GP_EXCEPTION, 0, 0);
|
|
|
|
}
|
|
|
|
|
2008-08-08 13:22:49 +04:00
|
|
|
Bit64u header1 = read_virtual_qword(i->seg(), eaddr + 512);
|
|
|
|
Bit64u header2 = read_virtual_qword(i->seg(), eaddr + 520);
|
|
|
|
Bit64u header3 = read_virtual_qword(i->seg(), eaddr + 528);
|
2008-02-13 19:45:21 +03:00
|
|
|
|
2008-12-06 13:21:55 +03:00
|
|
|
if ((~BX_CPU_THIS_PTR xcr0.get32() & header1) != 0) {
|
2008-02-13 19:45:21 +03:00
|
|
|
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
|
2008-08-08 13:22:49 +04:00
|
|
|
read_virtual_dqword(i->seg(), eaddr, (Bit8u *) &xmm);
|
2008-02-13 19:45:21 +03:00
|
|
|
|
|
|
|
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;
|
2008-02-13 01:42:47 +03:00
|
|
|
|
2008-02-13 19:45:21 +03:00
|
|
|
/* 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;
|
2008-02-13 01:42:47 +03:00
|
|
|
|
2008-02-13 19:45:21 +03:00
|
|
|
/* 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);
|
2008-08-16 16:19:30 +04:00
|
|
|
BX_CPU_THIS_PTR the_i387.fcs = xmm.xmm16u(6);
|
2008-02-13 19:45:21 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
Bit32u tag_byte = xmm.xmmubyte(4);
|
|
|
|
|
|
|
|
/* Restore x87 FPU DP */
|
2008-08-08 13:22:49 +04:00
|
|
|
read_virtual_dqword(i->seg(), eaddr + 16, (Bit8u *) &xmm);
|
2008-02-13 19:45:21 +03:00
|
|
|
|
|
|
|
#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++)
|
|
|
|
{
|
2008-06-12 23:14:40 +04:00
|
|
|
floatx80 reg;
|
2008-08-08 13:22:49 +04:00
|
|
|
reg.fraction = read_virtual_qword(i->seg(), eaddr+index*16+32);
|
|
|
|
reg.exp = read_virtual_word (i->seg(), eaddr+index*16+40);
|
2008-06-12 23:14:40 +04:00
|
|
|
BX_FPU_REG(index) = reg;
|
2008-02-13 19:45:21 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Restore floating point tag word - see desription for FXRSTOR instruction */
|
|
|
|
BX_CPU_THIS_PTR the_i387.twd = unpack_FPU_TW(tag_byte);
|
|
|
|
}
|
|
|
|
else {
|
2008-06-12 23:14:40 +04:00
|
|
|
// initialize FPU with reset values
|
|
|
|
BX_CPU_THIS_PTR the_i387.init();
|
2008-02-13 19:45:21 +03:00
|
|
|
|
2008-06-12 23:14:40 +04:00
|
|
|
for (index=0;index<8;index++) {
|
|
|
|
floatx80 reg = { 0, 0 };
|
|
|
|
BX_FPU_REG(index) = reg;
|
|
|
|
}
|
2008-02-13 19:45:21 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
if (BX_CPU_THIS_PTR xcr0.get_SSE() && (EAX & BX_XCR0_SSE_MASK) != 0)
|
|
|
|
{
|
2008-08-08 13:22:49 +04:00
|
|
|
Bit32u new_mxcsr = read_virtual_dword(i->seg(), eaddr + 24);
|
2008-02-13 19:45:21 +03:00
|
|
|
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()) {
|
2008-02-13 20:06:44 +03:00
|
|
|
read_virtual_dqword(i->seg(),
|
2008-08-08 13:22:49 +04:00
|
|
|
eaddr+index*16+160, (Bit8u *) &(BX_CPU_THIS_PTR xmm[index]));
|
2008-02-13 19:45:21 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// initialize SSE with reset values
|
|
|
|
for(index=0; index < BX_XMM_REGISTERS; index++) {
|
|
|
|
// set XMM8-XMM15 only in 64-bit mode
|
2008-02-13 20:06:44 +03:00
|
|
|
if (index < 8 || Is64BitMode()) {
|
|
|
|
BX_CPU_THIS_PTR xmm[index].xmm64u(0) = 0;
|
|
|
|
BX_CPU_THIS_PTR xmm[index].xmm64u(1) = 0;
|
|
|
|
}
|
2008-02-13 19:45:21 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2008-02-13 01:42:47 +03:00
|
|
|
#else
|
|
|
|
BX_INFO(("XRSTOR: required XSAVE support, use --enable-xsave option"));
|
2008-07-13 19:35:10 +04:00
|
|
|
exception(BX_UD_EXCEPTION, 0, 0);
|
2008-02-13 01:42:47 +03:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
/* 0F 01 D0 */
|
2008-03-23 00:29:41 +03:00
|
|
|
void BX_CPP_AttrRegparmN(1) BX_CPU_C::XGETBV(bxInstruction_c *i)
|
2008-02-13 01:42:47 +03:00
|
|
|
{
|
|
|
|
#if BX_SUPPORT_XSAVE
|
2008-02-13 19:45:21 +03:00
|
|
|
if(! (BX_CPU_THIS_PTR cr4.get_OSXSAVE())) {
|
|
|
|
BX_ERROR(("XGETBV: OSXSAVE feature is not enabled in CR4!"));
|
|
|
|
exception(BX_UD_EXCEPTION, 0, 0);
|
|
|
|
}
|
2008-02-13 01:42:47 +03:00
|
|
|
|
2008-02-13 19:45:21 +03:00
|
|
|
// 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);
|
|
|
|
}
|
2008-02-13 01:42:47 +03:00
|
|
|
|
2008-02-13 19:45:21 +03:00
|
|
|
RDX = 0;
|
2008-12-06 13:21:55 +03:00
|
|
|
RAX = BX_CPU_THIS_PTR xcr0.get32();
|
2008-02-13 01:42:47 +03:00
|
|
|
#else
|
|
|
|
BX_INFO(("XGETBV: required XSAVE support, use --enable-xsave option"));
|
2008-07-13 19:35:10 +04:00
|
|
|
exception(BX_UD_EXCEPTION, 0, 0);
|
2008-02-13 01:42:47 +03:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
/* 0F 01 D1 */
|
2008-03-23 00:29:41 +03:00
|
|
|
void BX_CPP_AttrRegparmN(1) BX_CPU_C::XSETBV(bxInstruction_c *i)
|
2008-02-13 01:42:47 +03:00
|
|
|
{
|
|
|
|
#if BX_SUPPORT_XSAVE
|
2009-10-18 21:16:08 +04:00
|
|
|
if (v8086_mode()) {
|
2008-02-13 19:45:21 +03:00
|
|
|
BX_ERROR(("XSETBV: not recognized in real or virtual-8086 mode"));
|
|
|
|
exception(BX_UD_EXCEPTION, 0, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
2008-02-13 01:42:47 +03:00
|
|
|
|
2008-04-01 00:56:27 +04:00
|
|
|
if (EDX != 0 || (EAX & ~BX_XCR0_SUPPORTED_BITS) != 0 || (EAX & 1) == 0) {
|
2008-02-13 19:45:21 +03:00
|
|
|
BX_ERROR(("XSETBV: Attempting to change reserved bits!"));
|
|
|
|
exception(BX_GP_EXCEPTION, 0, 0);
|
|
|
|
}
|
2008-02-13 01:42:47 +03:00
|
|
|
|
2008-12-06 13:21:55 +03:00
|
|
|
BX_CPU_THIS_PTR xcr0.set32(EAX);
|
2008-02-13 01:42:47 +03:00
|
|
|
#else
|
|
|
|
BX_INFO(("XSETBV: required XSAVE support, use --enable-xsave option"));
|
2008-07-13 19:35:10 +04:00
|
|
|
exception(BX_UD_EXCEPTION, 0, 0);
|
2008-02-13 01:42:47 +03:00
|
|
|
#endif
|
|
|
|
}
|