Fail* directories reorganized, Code-cleanup (-> coding-style), Typos+comments fixed.

git-svn-id: https://www4.informatik.uni-erlangen.de/i4svn/danceos/trunk/devel/fail@1321 8c4709b5-6ec9-48aa-a5cd-a96041d1645a
This commit is contained in:
adrian
2012-06-08 20:09:43 +00:00
parent d474a5b952
commit 2575604b41
866 changed files with 1848 additions and 1879 deletions

291
simulators/bochs/cpu/3dnow.cc Executable file
View File

@ -0,0 +1,291 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2002-2009 Stanislav Shwartsman
// 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
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA B 02110-1301 USA
//
/////////////////////////////////////////////////////////////////////////
#define NEED_CPU_REG_SHORTCUTS 1
#include "bochs.h"
#include "cpu.h"
#define LOG_THIS BX_CPU_THIS_PTR
#if BX_SUPPORT_3DNOW
BX_CPP_INLINE void prepare_softfloat_status_word(float_status_t &status, int rounding_mode)
{
status.float_exception_flags = 0; // clear exceptions before execution
status.float_nan_handling_mode = float_first_operand_nan;
status.float_rounding_mode = rounding_mode;
status.flush_underflow_to_zero = 0;
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::PFPNACC_PqQq(bxInstruction_c *i)
{
BX_PANIC(("PFPNACC_PqQq: 3DNow! instruction still not implemented"));
}
/* 0F 0F /r 0C */
void BX_CPP_AttrRegparmN(1) BX_CPU_C::PI2FW_PqQq(bxInstruction_c *i)
{
#if BX_CPU_LEVEL >= 5
BxPackedMmxRegister result, op;
BX_CPU_THIS_PTR prepareMMX();
/* op is a register or memory reference */
if (i->modC0()) {
op = BX_READ_MMX_REG(i->rm());
}
else {
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
/* pointer, segment address pair */
MMXUQ(op) = read_virtual_qword(i->seg(), eaddr);
}
BX_CPU_THIS_PTR prepareFPU2MMX(); /* FPU2MMX transition */
float_status_t status_word;
prepare_softfloat_status_word(status_word, float_round_to_zero);
MMXUD0(result) =
int32_to_float32((Bit32s)(MMXSW0(op)), status_word);
MMXUD1(result) =
int32_to_float32((Bit32s)(MMXSW2(op)), status_word);
/* now write result back to destination */
BX_WRITE_MMX_REG(i->nnn(), result);
#endif
}
/* 0F 0F /r 0D */
void BX_CPP_AttrRegparmN(1) BX_CPU_C::PI2FD_PqQq(bxInstruction_c *i)
{
#if BX_CPU_LEVEL >= 5
BxPackedMmxRegister result, op;
BX_CPU_THIS_PTR prepareMMX();
/* op is a register or memory reference */
if (i->modC0()) {
op = BX_READ_MMX_REG(i->rm());
}
else {
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
/* pointer, segment address pair */
MMXUQ(op) = read_virtual_qword(i->seg(), eaddr);
}
BX_CPU_THIS_PTR prepareFPU2MMX(); /* FPU2MMX transition */
float_status_t status_word;
prepare_softfloat_status_word(status_word, float_round_to_zero);
MMXUD0(result) =
int32_to_float32(MMXSD0(op), status_word);
MMXUD1(result) =
int32_to_float32(MMXSD1(op), status_word);
/* now write result back to destination */
BX_WRITE_MMX_REG(i->nnn(), result);
#endif
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::PF2IW_PqQq(bxInstruction_c *i)
{
BX_PANIC(("PF2IW_PqQq: 3DNow! instruction still not implemented"));
}
/* 0F 0F /r 1D */
void BX_CPP_AttrRegparmN(1) BX_CPU_C::PF2ID_PqQq(bxInstruction_c *i)
{
#if BX_CPU_LEVEL >= 5
BxPackedMmxRegister result, op;
BX_CPU_THIS_PTR prepareMMX();
/* op is a register or memory reference */
if (i->modC0()) {
op = BX_READ_MMX_REG(i->rm());
}
else {
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
/* pointer, segment address pair */
MMXUQ(op) = read_virtual_qword(i->seg(), eaddr);
}
BX_CPU_THIS_PTR prepareFPU2MMX(); /* FPU2MMX transition */
float_status_t status_word;
prepare_softfloat_status_word(status_word, float_round_to_zero);
MMXSD0(result) =
float32_to_int32_round_to_zero(MMXUD0(op), status_word);
MMXSD1(result) =
float32_to_int32_round_to_zero(MMXUD1(op), status_word);
/* now write result back to destination */
BX_WRITE_MMX_REG(i->nnn(), result);
#endif
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::PFNACC_PqQq(bxInstruction_c *i)
{
BX_PANIC(("PFNACC_PqQq: 3DNow! instruction still not implemented"));
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::PFCMPGE_PqQq(bxInstruction_c *i)
{
BX_PANIC(("PFCMPGE_PqQq: 3DNow! instruction still not implemented"));
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::PFMIN_PqQq(bxInstruction_c *i)
{
BX_PANIC(("PFMIN_PqQq: 3DNow! instruction still not implemented"));
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::PFRCP_PqQq(bxInstruction_c *i)
{
BX_PANIC(("PFRCP_PqQq: 3DNow! instruction still not implemented"));
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::PFRSQRT_PqQq(bxInstruction_c *i)
{
BX_PANIC(("PFRSQRT_PqQq: 3DNow! instruction still not implemented"));
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::PFSUB_PqQq(bxInstruction_c *i)
{
BX_PANIC(("PFSUB_PqQq: 3DNow! instruction still not implemented"));
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::PFADD_PqQq(bxInstruction_c *i)
{
BX_PANIC(("PFADD_PqQq: 3DNow! instruction still not implemented"));
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::PFCMPGT_PqQq(bxInstruction_c *i)
{
BX_PANIC(("PFCMPGT_PqQq: 3DNow! instruction still not implemented"));
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::PFMAX_PqQq(bxInstruction_c *i)
{
BX_PANIC(("PFMAX_PqQq: 3DNow! instruction still not implemented"));
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::PFRCPIT1_PqQq(bxInstruction_c *i)
{
BX_PANIC(("PFRCPIT1_PqQq: 3DNow! instruction still not implemented"));
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::PFRSQIT1_PqQq(bxInstruction_c *i)
{
BX_PANIC(("PFRSQIT1_PqQq: 3DNow! instruction still not implemented"));
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::PFSUBR_PqQq(bxInstruction_c *i)
{
BX_PANIC(("PFSUBR_PqQq: 3DNow! instruction still not implemented"));
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::PFACC_PqQq(bxInstruction_c *i)
{
BX_PANIC(("PFACC_PqQq: 3DNow! instruction still not implemented"));
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::PFCMPEQ_PqQq(bxInstruction_c *i)
{
BX_PANIC(("PFCMPEQ_PqQq: 3DNow! instruction still not implemented"));
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::PFMUL_PqQq(bxInstruction_c *i)
{
BX_PANIC(("PFMUL_PqQq: 3DNow! instruction still not implemented"));
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::PFRCPIT2_PqQq(bxInstruction_c *i)
{
BX_PANIC(("PFRCPIT2_PqQq: 3DNow! instruction still not implemented"));
}
/* 0F 0F /r B7 */
void BX_CPP_AttrRegparmN(1) BX_CPU_C::PMULHRW_PqQq(bxInstruction_c *i)
{
#if BX_CPU_LEVEL >= 5
BX_CPU_THIS_PTR prepareMMX();
BxPackedMmxRegister op1 = BX_READ_MMX_REG(i->nnn()), op2, result;
/* op2 is a register or memory reference */
if (i->modC0()) {
op2 = BX_READ_MMX_REG(i->rm());
}
else {
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
/* pointer, segment address pair */
MMXUQ(op2) = read_virtual_qword(i->seg(), eaddr);
}
BX_CPU_THIS_PTR prepareFPU2MMX(); /* FPU2MMX transition */
Bit32s product1 = Bit32s(MMXSW0(op1)) * Bit32s(MMXSW0(op2)) + 0x8000;
Bit32s product2 = Bit32s(MMXSW1(op1)) * Bit32s(MMXSW1(op2)) + 0x8000;
Bit32s product3 = Bit32s(MMXSW2(op1)) * Bit32s(MMXSW2(op2)) + 0x8000;
Bit32s product4 = Bit32s(MMXSW3(op1)) * Bit32s(MMXSW3(op2)) + 0x8000;
MMXUW0(result) = Bit16u(product1 >> 16);
MMXUW1(result) = Bit16u(product2 >> 16);
MMXUW2(result) = Bit16u(product3 >> 16);
MMXUW3(result) = Bit16u(product4 >> 16);
/* now write result back to destination */
BX_WRITE_MMX_REG(i->nnn(), result);
#endif
}
/* 0F 0F /r BB */
void BX_CPP_AttrRegparmN(1) BX_CPU_C::PSWAPD_PqQq(bxInstruction_c *i)
{
#if BX_CPU_LEVEL >= 5
BX_CPU_THIS_PTR prepareMMX();
BxPackedMmxRegister result, op;
/* op is a register or memory reference */
if (i->modC0()) {
op = BX_READ_MMX_REG(i->rm());
}
else {
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
/* pointer, segment address pair */
MMXUQ(op) = read_virtual_qword(i->seg(), eaddr);
}
BX_CPU_THIS_PTR prepareFPU2MMX(); /* FPU2MMX transition */
MMXUD0(result) = MMXUD1(op);
MMXUD1(result) = MMXUD0(op);
/* now write result back to destination */
BX_WRITE_MMX_REG(i->nnn(), result);
#endif
}
#endif

View File

@ -0,0 +1,773 @@
# Copyright (C) 2001-2009 The Bochs Project
#
# 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
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA B 02110-1301 USA
@SUFFIX_LINE@
srcdir = @srcdir@
VPATH = @srcdir@
top_builddir = ..
top_srcdir = @top_srcdir@
SHELL = /bin/sh
@SET_MAKE@
CXX = @CXX@
CXXFLAGS = @CXXFLAGS@ @GUI_CXXFLAGS@
LDFLAGS = @LDFLAGS@
LIBS = @LIBS@
X_LIBS = @X_LIBS@
X_PRE_LIBS = @X_PRE_LIBS@
RANLIB = @RANLIB@
BX_INCDIRS = -I.. -I$(srcdir)/.. -I../@INSTRUMENT_DIR@ -I$(srcdir)/../@INSTRUMENT_DIR@
# Objects which are synced between the cpu and cpu64 code and
# are used for either compile.
OBJS = \
init.o \
cpu.o \
icache.o \
resolver.o \
fetchdecode.o \
access.o \
access32.o \
shift16.o \
logical16.o \
ctrl_xfer32.o \
ctrl_xfer16.o \
mmx.o \
3dnow.o \
fpu_emu.o \
sse.o \
sse_move.o \
sse_pfp.o \
sse_rcp.o \
sse_string.o \
xsave.o \
aes.o \
vmx.o \
vmcs.o \
vmexit.o \
soft_int.o \
apic.o \
bcd.o \
mult16.o \
tasking.o \
shift32.o \
shift8.o \
arith8.o \
stack16.o \
protect_ctrl.o \
mult8.o \
load.o \
data_xfer8.o \
vm8086.o \
logical8.o \
logical32.o \
arith16.o \
segment_ctrl.o \
data_xfer16.o \
data_xfer32.o \
exception.o \
cpuid.o \
proc_ctrl.o \
crregs.o \
msr.o \
smm.o \
lazy_flags.o \
flag_ctrl_pro.o \
stack32.o \
debugstuff.o \
flag_ctrl.o \
mult32.o \
arith32.o \
jmp_far.o \
call_far.o \
ret_far.o \
iret.o \
ctrl_xfer_pro.o \
segment_ctrl_pro.o \
io.o \
crc32.o \
bit.o \
bit16.o \
bit32.o \
string.o \
paging.o
# Objects which are only used for x86-64 code
OBJS64 = \
access64.o \
arith64.o \
ctrl_xfer64.o \
data_xfer64.o \
fetchdecode64.o \
logical64.o \
mult64.o \
shift64.o \
bit64.o \
stack64.o
BX_INCLUDES = ../bochs.h ../config.h
all: libcpu.a
.@CPP_SUFFIX@.o:
$(CXX) @DASH@c $(BX_INCDIRS) $(CXXFLAGS) @CXXFP@$< @OFP@$@
libcpu.a: $(OBJS) @OBJS64@
@RMCOMMAND@ libcpu.a
@MAKELIB@ $(OBJS) @OBJS64@
$(RANLIB) libcpu.a
$(OBJS): $(BX_INCLUDES)
$(OBJS64): $(BX_INCLUDES)
clean:
@RMCOMMAND@ *.o
@RMCOMMAND@ *.a
dist-clean: clean
@RMCOMMAND@ Makefile
###########################################
# dependencies generated by
# gcc -MM -I.. -I../instrument/stubs *.cc | sed 's/\.cc/.@CPP_SUFFIX@/g'
###########################################
3dnow.o: 3dnow.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h ../bx_debug/debug.h \
../config.h ../osdep.h ../bxversion.h ../gui/siminterface.h \
../gui/paramtree.h ../memory/memory.h ../pc_system.h ../plugin.h \
../extplugin.h ../gui/gui.h ../instrument/stubs/instrument.h cpu.h \
model_specific.h crregs.h descriptor.h instr.h ia_opcodes.h lazy_flags.h \
icache.h apic.h ../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h \
../fpu/status_w.h ../fpu/control_w.h ../cpu/xmm.h vmx.h stack.h
access.o: access.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h ../bx_debug/debug.h \
../config.h ../osdep.h ../bxversion.h ../gui/siminterface.h \
../gui/paramtree.h ../memory/memory.h ../pc_system.h ../plugin.h \
../extplugin.h ../gui/gui.h ../instrument/stubs/instrument.h cpu.h \
model_specific.h crregs.h descriptor.h instr.h ia_opcodes.h lazy_flags.h \
icache.h apic.h ../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h \
../fpu/status_w.h ../fpu/control_w.h ../cpu/xmm.h vmx.h stack.h
access32.o: access32.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../gui/gui.h \
../instrument/stubs/instrument.h cpu.h model_specific.h crregs.h \
descriptor.h instr.h ia_opcodes.h lazy_flags.h icache.h apic.h \
../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h ../fpu/status_w.h \
../fpu/control_w.h ../cpu/xmm.h vmx.h stack.h
access64.o: access64.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../gui/gui.h \
../instrument/stubs/instrument.h cpu.h model_specific.h crregs.h \
descriptor.h instr.h ia_opcodes.h lazy_flags.h icache.h apic.h \
../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h ../fpu/status_w.h \
../fpu/control_w.h ../cpu/xmm.h vmx.h stack.h
aes.o: aes.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h ../bx_debug/debug.h \
../config.h ../osdep.h ../bxversion.h ../gui/siminterface.h \
../gui/paramtree.h ../memory/memory.h ../pc_system.h ../plugin.h \
../extplugin.h ../gui/gui.h ../instrument/stubs/instrument.h cpu.h \
model_specific.h crregs.h descriptor.h instr.h ia_opcodes.h lazy_flags.h \
icache.h apic.h ../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h \
../fpu/status_w.h ../fpu/control_w.h ../cpu/xmm.h vmx.h stack.h
apic.o: apic.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h ../bx_debug/debug.h \
../config.h ../osdep.h ../bxversion.h ../gui/siminterface.h \
../gui/paramtree.h ../memory/memory.h ../pc_system.h ../plugin.h \
../extplugin.h ../gui/gui.h ../instrument/stubs/instrument.h cpu.h \
model_specific.h crregs.h descriptor.h instr.h ia_opcodes.h lazy_flags.h \
icache.h apic.h ../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h \
../fpu/status_w.h ../fpu/control_w.h ../cpu/xmm.h vmx.h stack.h \
../iodev/iodev.h ../param_names.h
arith16.o: arith16.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../gui/gui.h \
../instrument/stubs/instrument.h cpu.h model_specific.h crregs.h \
descriptor.h instr.h ia_opcodes.h lazy_flags.h icache.h apic.h \
../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h ../fpu/status_w.h \
../fpu/control_w.h ../cpu/xmm.h vmx.h stack.h
arith32.o: arith32.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../gui/gui.h \
../instrument/stubs/instrument.h cpu.h model_specific.h crregs.h \
descriptor.h instr.h ia_opcodes.h lazy_flags.h icache.h apic.h \
../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h ../fpu/status_w.h \
../fpu/control_w.h ../cpu/xmm.h vmx.h stack.h
arith64.o: arith64.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../gui/gui.h \
../instrument/stubs/instrument.h cpu.h model_specific.h crregs.h \
descriptor.h instr.h ia_opcodes.h lazy_flags.h icache.h apic.h \
../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h ../fpu/status_w.h \
../fpu/control_w.h ../cpu/xmm.h vmx.h stack.h
arith8.o: arith8.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h ../bx_debug/debug.h \
../config.h ../osdep.h ../bxversion.h ../gui/siminterface.h \
../gui/paramtree.h ../memory/memory.h ../pc_system.h ../plugin.h \
../extplugin.h ../gui/gui.h ../instrument/stubs/instrument.h cpu.h \
model_specific.h crregs.h descriptor.h instr.h ia_opcodes.h lazy_flags.h \
icache.h apic.h ../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h \
../fpu/status_w.h ../fpu/control_w.h ../cpu/xmm.h vmx.h stack.h
bcd.o: bcd.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h ../bx_debug/debug.h \
../config.h ../osdep.h ../bxversion.h ../gui/siminterface.h \
../gui/paramtree.h ../memory/memory.h ../pc_system.h ../plugin.h \
../extplugin.h ../gui/gui.h ../instrument/stubs/instrument.h cpu.h \
model_specific.h crregs.h descriptor.h instr.h ia_opcodes.h lazy_flags.h \
icache.h apic.h ../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h \
../fpu/status_w.h ../fpu/control_w.h ../cpu/xmm.h vmx.h stack.h
bit.o: bit.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h ../bx_debug/debug.h \
../config.h ../osdep.h ../bxversion.h ../gui/siminterface.h \
../gui/paramtree.h ../memory/memory.h ../pc_system.h ../plugin.h \
../extplugin.h ../gui/gui.h ../instrument/stubs/instrument.h cpu.h \
model_specific.h crregs.h descriptor.h instr.h ia_opcodes.h lazy_flags.h \
icache.h apic.h ../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h \
../fpu/status_w.h ../fpu/control_w.h ../cpu/xmm.h vmx.h stack.h
bit16.o: bit16.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h ../bx_debug/debug.h \
../config.h ../osdep.h ../bxversion.h ../gui/siminterface.h \
../gui/paramtree.h ../memory/memory.h ../pc_system.h ../plugin.h \
../extplugin.h ../gui/gui.h ../instrument/stubs/instrument.h cpu.h \
model_specific.h crregs.h descriptor.h instr.h ia_opcodes.h lazy_flags.h \
icache.h apic.h ../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h \
../fpu/status_w.h ../fpu/control_w.h ../cpu/xmm.h vmx.h stack.h
bit32.o: bit32.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h ../bx_debug/debug.h \
../config.h ../osdep.h ../bxversion.h ../gui/siminterface.h \
../gui/paramtree.h ../memory/memory.h ../pc_system.h ../plugin.h \
../extplugin.h ../gui/gui.h ../instrument/stubs/instrument.h cpu.h \
model_specific.h crregs.h descriptor.h instr.h ia_opcodes.h lazy_flags.h \
icache.h apic.h ../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h \
../fpu/status_w.h ../fpu/control_w.h ../cpu/xmm.h vmx.h stack.h
bit64.o: bit64.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h ../bx_debug/debug.h \
../config.h ../osdep.h ../bxversion.h ../gui/siminterface.h \
../gui/paramtree.h ../memory/memory.h ../pc_system.h ../plugin.h \
../extplugin.h ../gui/gui.h ../instrument/stubs/instrument.h cpu.h \
model_specific.h crregs.h descriptor.h instr.h ia_opcodes.h lazy_flags.h \
icache.h apic.h ../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h \
../fpu/status_w.h ../fpu/control_w.h ../cpu/xmm.h vmx.h stack.h
call_far.o: call_far.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../gui/gui.h \
../instrument/stubs/instrument.h cpu.h model_specific.h crregs.h \
descriptor.h instr.h ia_opcodes.h lazy_flags.h icache.h apic.h \
../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h ../fpu/status_w.h \
../fpu/control_w.h ../cpu/xmm.h vmx.h stack.h
cpu.o: cpu.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h ../bx_debug/debug.h \
../config.h ../osdep.h ../bxversion.h ../gui/siminterface.h \
../gui/paramtree.h ../memory/memory.h ../pc_system.h ../plugin.h \
../extplugin.h ../gui/gui.h ../instrument/stubs/instrument.h cpu.h \
model_specific.h crregs.h descriptor.h instr.h ia_opcodes.h lazy_flags.h \
icache.h apic.h ../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h \
../fpu/status_w.h ../fpu/control_w.h ../cpu/xmm.h vmx.h stack.h \
../iodev/iodev.h ../param_names.h
cpuid.o: cpuid.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h ../bx_debug/debug.h \
../config.h ../osdep.h ../bxversion.h ../gui/siminterface.h \
../gui/paramtree.h ../memory/memory.h ../pc_system.h ../plugin.h \
../extplugin.h ../gui/gui.h ../instrument/stubs/instrument.h cpu.h \
model_specific.h crregs.h descriptor.h instr.h ia_opcodes.h lazy_flags.h \
icache.h apic.h ../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h \
../fpu/status_w.h ../fpu/control_w.h ../cpu/xmm.h vmx.h stack.h \
../param_names.h
crc32.o: crc32.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h ../bx_debug/debug.h \
../config.h ../osdep.h ../bxversion.h ../gui/siminterface.h \
../gui/paramtree.h ../memory/memory.h ../pc_system.h ../plugin.h \
../extplugin.h ../gui/gui.h ../instrument/stubs/instrument.h cpu.h \
model_specific.h crregs.h descriptor.h instr.h ia_opcodes.h lazy_flags.h \
icache.h apic.h ../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h \
../fpu/status_w.h ../fpu/control_w.h ../cpu/xmm.h vmx.h stack.h
crregs.o: crregs.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h ../bx_debug/debug.h \
../config.h ../osdep.h ../bxversion.h ../gui/siminterface.h \
../gui/paramtree.h ../memory/memory.h ../pc_system.h ../plugin.h \
../extplugin.h ../gui/gui.h ../instrument/stubs/instrument.h cpu.h \
model_specific.h crregs.h descriptor.h instr.h ia_opcodes.h lazy_flags.h \
icache.h apic.h ../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h \
../fpu/status_w.h ../fpu/control_w.h ../cpu/xmm.h vmx.h stack.h
ctrl_xfer16.o: ctrl_xfer16.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../gui/gui.h \
../instrument/stubs/instrument.h cpu.h model_specific.h crregs.h \
descriptor.h instr.h ia_opcodes.h lazy_flags.h icache.h apic.h \
../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h ../fpu/status_w.h \
../fpu/control_w.h ../cpu/xmm.h vmx.h stack.h
ctrl_xfer32.o: ctrl_xfer32.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../gui/gui.h \
../instrument/stubs/instrument.h cpu.h model_specific.h crregs.h \
descriptor.h instr.h ia_opcodes.h lazy_flags.h icache.h apic.h \
../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h ../fpu/status_w.h \
../fpu/control_w.h ../cpu/xmm.h vmx.h stack.h
ctrl_xfer64.o: ctrl_xfer64.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../gui/gui.h \
../instrument/stubs/instrument.h cpu.h model_specific.h crregs.h \
descriptor.h instr.h ia_opcodes.h lazy_flags.h icache.h apic.h \
../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h ../fpu/status_w.h \
../fpu/control_w.h ../cpu/xmm.h vmx.h stack.h
ctrl_xfer_pro.o: ctrl_xfer_pro.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../gui/gui.h \
../instrument/stubs/instrument.h cpu.h model_specific.h crregs.h \
descriptor.h instr.h ia_opcodes.h lazy_flags.h icache.h apic.h \
../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h ../fpu/status_w.h \
../fpu/control_w.h ../cpu/xmm.h vmx.h stack.h
data_xfer16.o: data_xfer16.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../gui/gui.h \
../instrument/stubs/instrument.h cpu.h model_specific.h crregs.h \
descriptor.h instr.h ia_opcodes.h lazy_flags.h icache.h apic.h \
../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h ../fpu/status_w.h \
../fpu/control_w.h ../cpu/xmm.h vmx.h stack.h
data_xfer32.o: data_xfer32.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../gui/gui.h \
../instrument/stubs/instrument.h cpu.h model_specific.h crregs.h \
descriptor.h instr.h ia_opcodes.h lazy_flags.h icache.h apic.h \
../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h ../fpu/status_w.h \
../fpu/control_w.h ../cpu/xmm.h vmx.h stack.h
data_xfer64.o: data_xfer64.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../gui/gui.h \
../instrument/stubs/instrument.h cpu.h model_specific.h crregs.h \
descriptor.h instr.h ia_opcodes.h lazy_flags.h icache.h apic.h \
../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h ../fpu/status_w.h \
../fpu/control_w.h ../cpu/xmm.h vmx.h stack.h
data_xfer8.o: data_xfer8.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../gui/gui.h \
../instrument/stubs/instrument.h cpu.h model_specific.h crregs.h \
descriptor.h instr.h ia_opcodes.h lazy_flags.h icache.h apic.h \
../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h ../fpu/status_w.h \
../fpu/control_w.h ../cpu/xmm.h vmx.h stack.h
debugstuff.o: debugstuff.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../gui/gui.h \
../instrument/stubs/instrument.h cpu.h model_specific.h crregs.h \
descriptor.h instr.h ia_opcodes.h lazy_flags.h icache.h apic.h \
../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h ../fpu/status_w.h \
../fpu/control_w.h ../cpu/xmm.h vmx.h stack.h ../disasm/disasm.h
exception.o: exception.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../gui/gui.h \
../instrument/stubs/instrument.h cpu.h model_specific.h crregs.h \
descriptor.h instr.h ia_opcodes.h lazy_flags.h icache.h apic.h \
../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h ../fpu/status_w.h \
../fpu/control_w.h ../cpu/xmm.h vmx.h stack.h ../param_names.h \
../iodev/iodev.h
fetchdecode.o: fetchdecode.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../gui/gui.h \
../instrument/stubs/instrument.h cpu.h model_specific.h crregs.h \
descriptor.h instr.h ia_opcodes.h lazy_flags.h icache.h apic.h \
../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h ../fpu/status_w.h \
../fpu/control_w.h ../cpu/xmm.h vmx.h stack.h fetchdecode.h \
fetchdecode_x87.h fetchdecode_sse.h
fetchdecode64.o: fetchdecode64.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../gui/gui.h \
../instrument/stubs/instrument.h cpu.h model_specific.h crregs.h \
descriptor.h instr.h ia_opcodes.h lazy_flags.h icache.h apic.h \
../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h ../fpu/status_w.h \
../fpu/control_w.h ../cpu/xmm.h vmx.h stack.h fetchdecode.h \
fetchdecode_x87.h fetchdecode_sse.h
flag_ctrl.o: flag_ctrl.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../gui/gui.h \
../instrument/stubs/instrument.h cpu.h model_specific.h crregs.h \
descriptor.h instr.h ia_opcodes.h lazy_flags.h icache.h apic.h \
../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h ../fpu/status_w.h \
../fpu/control_w.h ../cpu/xmm.h vmx.h stack.h
flag_ctrl_pro.o: flag_ctrl_pro.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../gui/gui.h \
../instrument/stubs/instrument.h cpu.h model_specific.h crregs.h \
descriptor.h instr.h ia_opcodes.h lazy_flags.h icache.h apic.h \
../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h ../fpu/status_w.h \
../fpu/control_w.h ../cpu/xmm.h vmx.h stack.h
fpu_emu.o: fpu_emu.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../gui/gui.h \
../instrument/stubs/instrument.h cpu.h model_specific.h crregs.h \
descriptor.h instr.h ia_opcodes.h lazy_flags.h icache.h apic.h \
../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h ../fpu/status_w.h \
../fpu/control_w.h ../cpu/xmm.h vmx.h stack.h
icache.o: icache.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h ../bx_debug/debug.h \
../config.h ../osdep.h ../bxversion.h ../gui/siminterface.h \
../gui/paramtree.h ../memory/memory.h ../pc_system.h ../plugin.h \
../extplugin.h ../gui/gui.h ../instrument/stubs/instrument.h cpu.h \
model_specific.h crregs.h descriptor.h instr.h ia_opcodes.h lazy_flags.h \
icache.h apic.h ../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h \
../fpu/status_w.h ../fpu/control_w.h ../cpu/xmm.h vmx.h stack.h
init.o: init.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h ../bx_debug/debug.h \
../config.h ../osdep.h ../bxversion.h ../gui/siminterface.h \
../gui/paramtree.h ../memory/memory.h ../pc_system.h ../plugin.h \
../extplugin.h ../gui/gui.h ../instrument/stubs/instrument.h cpu.h \
model_specific.h crregs.h descriptor.h instr.h ia_opcodes.h lazy_flags.h \
icache.h apic.h ../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h \
../fpu/status_w.h ../fpu/control_w.h ../cpu/xmm.h vmx.h stack.h \
../param_names.h
io.o: io.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h ../bx_debug/debug.h \
../config.h ../osdep.h ../bxversion.h ../gui/siminterface.h \
../gui/paramtree.h ../memory/memory.h ../pc_system.h ../plugin.h \
../extplugin.h ../gui/gui.h ../instrument/stubs/instrument.h cpu.h \
model_specific.h crregs.h descriptor.h instr.h ia_opcodes.h lazy_flags.h \
icache.h apic.h ../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h \
../fpu/status_w.h ../fpu/control_w.h ../cpu/xmm.h vmx.h stack.h \
../iodev/iodev.h ../param_names.h
iret.o: iret.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h ../bx_debug/debug.h \
../config.h ../osdep.h ../bxversion.h ../gui/siminterface.h \
../gui/paramtree.h ../memory/memory.h ../pc_system.h ../plugin.h \
../extplugin.h ../gui/gui.h ../instrument/stubs/instrument.h cpu.h \
model_specific.h crregs.h descriptor.h instr.h ia_opcodes.h lazy_flags.h \
icache.h apic.h ../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h \
../fpu/status_w.h ../fpu/control_w.h ../cpu/xmm.h vmx.h stack.h
jmp_far.o: jmp_far.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../gui/gui.h \
../instrument/stubs/instrument.h cpu.h model_specific.h crregs.h \
descriptor.h instr.h ia_opcodes.h lazy_flags.h icache.h apic.h \
../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h ../fpu/status_w.h \
../fpu/control_w.h ../cpu/xmm.h vmx.h stack.h
lazy_flags.o: lazy_flags.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../gui/gui.h \
../instrument/stubs/instrument.h cpu.h model_specific.h crregs.h \
descriptor.h instr.h ia_opcodes.h lazy_flags.h icache.h apic.h \
../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h ../fpu/status_w.h \
../fpu/control_w.h ../cpu/xmm.h vmx.h stack.h
load.o: load.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h ../bx_debug/debug.h \
../config.h ../osdep.h ../bxversion.h ../gui/siminterface.h \
../gui/paramtree.h ../memory/memory.h ../pc_system.h ../plugin.h \
../extplugin.h ../gui/gui.h ../instrument/stubs/instrument.h cpu.h \
model_specific.h crregs.h descriptor.h instr.h ia_opcodes.h lazy_flags.h \
icache.h apic.h ../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h \
../fpu/status_w.h ../fpu/control_w.h ../cpu/xmm.h vmx.h stack.h
logical16.o: logical16.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../gui/gui.h \
../instrument/stubs/instrument.h cpu.h model_specific.h crregs.h \
descriptor.h instr.h ia_opcodes.h lazy_flags.h icache.h apic.h \
../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h ../fpu/status_w.h \
../fpu/control_w.h ../cpu/xmm.h vmx.h stack.h
logical32.o: logical32.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../gui/gui.h \
../instrument/stubs/instrument.h cpu.h model_specific.h crregs.h \
descriptor.h instr.h ia_opcodes.h lazy_flags.h icache.h apic.h \
../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h ../fpu/status_w.h \
../fpu/control_w.h ../cpu/xmm.h vmx.h stack.h
logical64.o: logical64.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../gui/gui.h \
../instrument/stubs/instrument.h cpu.h model_specific.h crregs.h \
descriptor.h instr.h ia_opcodes.h lazy_flags.h icache.h apic.h \
../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h ../fpu/status_w.h \
../fpu/control_w.h ../cpu/xmm.h vmx.h stack.h
logical8.o: logical8.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../gui/gui.h \
../instrument/stubs/instrument.h cpu.h model_specific.h crregs.h \
descriptor.h instr.h ia_opcodes.h lazy_flags.h icache.h apic.h \
../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h ../fpu/status_w.h \
../fpu/control_w.h ../cpu/xmm.h vmx.h stack.h
mmx.o: mmx.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h ../bx_debug/debug.h \
../config.h ../osdep.h ../bxversion.h ../gui/siminterface.h \
../gui/paramtree.h ../memory/memory.h ../pc_system.h ../plugin.h \
../extplugin.h ../gui/gui.h ../instrument/stubs/instrument.h cpu.h \
model_specific.h crregs.h descriptor.h instr.h ia_opcodes.h lazy_flags.h \
icache.h apic.h ../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h \
../fpu/status_w.h ../fpu/control_w.h ../cpu/xmm.h vmx.h stack.h
msr.o: msr.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h ../bx_debug/debug.h \
../config.h ../osdep.h ../bxversion.h ../gui/siminterface.h \
../gui/paramtree.h ../memory/memory.h ../pc_system.h ../plugin.h \
../extplugin.h ../gui/gui.h ../instrument/stubs/instrument.h cpu.h \
model_specific.h crregs.h descriptor.h instr.h ia_opcodes.h lazy_flags.h \
icache.h apic.h ../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h \
../fpu/status_w.h ../fpu/control_w.h ../cpu/xmm.h vmx.h stack.h
mult16.o: mult16.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h ../bx_debug/debug.h \
../config.h ../osdep.h ../bxversion.h ../gui/siminterface.h \
../gui/paramtree.h ../memory/memory.h ../pc_system.h ../plugin.h \
../extplugin.h ../gui/gui.h ../instrument/stubs/instrument.h cpu.h \
model_specific.h crregs.h descriptor.h instr.h ia_opcodes.h lazy_flags.h \
icache.h apic.h ../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h \
../fpu/status_w.h ../fpu/control_w.h ../cpu/xmm.h vmx.h stack.h
mult32.o: mult32.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h ../bx_debug/debug.h \
../config.h ../osdep.h ../bxversion.h ../gui/siminterface.h \
../gui/paramtree.h ../memory/memory.h ../pc_system.h ../plugin.h \
../extplugin.h ../gui/gui.h ../instrument/stubs/instrument.h cpu.h \
model_specific.h crregs.h descriptor.h instr.h ia_opcodes.h lazy_flags.h \
icache.h apic.h ../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h \
../fpu/status_w.h ../fpu/control_w.h ../cpu/xmm.h vmx.h stack.h
mult64.o: mult64.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h ../bx_debug/debug.h \
../config.h ../osdep.h ../bxversion.h ../gui/siminterface.h \
../gui/paramtree.h ../memory/memory.h ../pc_system.h ../plugin.h \
../extplugin.h ../gui/gui.h ../instrument/stubs/instrument.h cpu.h \
model_specific.h crregs.h descriptor.h instr.h ia_opcodes.h lazy_flags.h \
icache.h apic.h ../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h \
../fpu/status_w.h ../fpu/control_w.h ../cpu/xmm.h vmx.h stack.h
mult8.o: mult8.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h ../bx_debug/debug.h \
../config.h ../osdep.h ../bxversion.h ../gui/siminterface.h \
../gui/paramtree.h ../memory/memory.h ../pc_system.h ../plugin.h \
../extplugin.h ../gui/gui.h ../instrument/stubs/instrument.h cpu.h \
model_specific.h crregs.h descriptor.h instr.h ia_opcodes.h lazy_flags.h \
icache.h apic.h ../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h \
../fpu/status_w.h ../fpu/control_w.h ../cpu/xmm.h vmx.h stack.h
paging.o: paging.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h ../bx_debug/debug.h \
../config.h ../osdep.h ../bxversion.h ../gui/siminterface.h \
../gui/paramtree.h ../memory/memory.h ../pc_system.h ../plugin.h \
../extplugin.h ../gui/gui.h ../instrument/stubs/instrument.h cpu.h \
model_specific.h crregs.h descriptor.h instr.h ia_opcodes.h lazy_flags.h \
icache.h apic.h ../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h \
../fpu/status_w.h ../fpu/control_w.h ../cpu/xmm.h vmx.h stack.h
proc_ctrl.o: proc_ctrl.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../gui/gui.h \
../instrument/stubs/instrument.h ../param_names.h cpu.h model_specific.h \
crregs.h descriptor.h instr.h ia_opcodes.h lazy_flags.h icache.h apic.h \
../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h ../fpu/status_w.h \
../fpu/control_w.h ../cpu/xmm.h vmx.h stack.h
protect_ctrl.o: protect_ctrl.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../gui/gui.h \
../instrument/stubs/instrument.h cpu.h model_specific.h crregs.h \
descriptor.h instr.h ia_opcodes.h lazy_flags.h icache.h apic.h \
../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h ../fpu/status_w.h \
../fpu/control_w.h ../cpu/xmm.h vmx.h stack.h
resolver.o: resolver.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../gui/gui.h \
../instrument/stubs/instrument.h cpu.h model_specific.h crregs.h \
descriptor.h instr.h ia_opcodes.h lazy_flags.h icache.h apic.h \
../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h ../fpu/status_w.h \
../fpu/control_w.h ../cpu/xmm.h vmx.h stack.h
ret_far.o: ret_far.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../gui/gui.h \
../instrument/stubs/instrument.h cpu.h model_specific.h crregs.h \
descriptor.h instr.h ia_opcodes.h lazy_flags.h icache.h apic.h \
../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h ../fpu/status_w.h \
../fpu/control_w.h ../cpu/xmm.h vmx.h stack.h
segment_ctrl.o: segment_ctrl.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../gui/gui.h \
../instrument/stubs/instrument.h cpu.h model_specific.h crregs.h \
descriptor.h instr.h ia_opcodes.h lazy_flags.h icache.h apic.h \
../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h ../fpu/status_w.h \
../fpu/control_w.h ../cpu/xmm.h vmx.h stack.h
segment_ctrl_pro.o: segment_ctrl_pro.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../gui/gui.h \
../instrument/stubs/instrument.h cpu.h model_specific.h crregs.h \
descriptor.h instr.h ia_opcodes.h lazy_flags.h icache.h apic.h \
../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h ../fpu/status_w.h \
../fpu/control_w.h ../cpu/xmm.h vmx.h stack.h
shift16.o: shift16.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../gui/gui.h \
../instrument/stubs/instrument.h cpu.h model_specific.h crregs.h \
descriptor.h instr.h ia_opcodes.h lazy_flags.h icache.h apic.h \
../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h ../fpu/status_w.h \
../fpu/control_w.h ../cpu/xmm.h vmx.h stack.h
shift32.o: shift32.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../gui/gui.h \
../instrument/stubs/instrument.h cpu.h model_specific.h crregs.h \
descriptor.h instr.h ia_opcodes.h lazy_flags.h icache.h apic.h \
../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h ../fpu/status_w.h \
../fpu/control_w.h ../cpu/xmm.h vmx.h stack.h
shift64.o: shift64.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../gui/gui.h \
../instrument/stubs/instrument.h cpu.h model_specific.h crregs.h \
descriptor.h instr.h ia_opcodes.h lazy_flags.h icache.h apic.h \
../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h ../fpu/status_w.h \
../fpu/control_w.h ../cpu/xmm.h vmx.h stack.h
shift8.o: shift8.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h ../bx_debug/debug.h \
../config.h ../osdep.h ../bxversion.h ../gui/siminterface.h \
../gui/paramtree.h ../memory/memory.h ../pc_system.h ../plugin.h \
../extplugin.h ../gui/gui.h ../instrument/stubs/instrument.h cpu.h \
model_specific.h crregs.h descriptor.h instr.h ia_opcodes.h lazy_flags.h \
icache.h apic.h ../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h \
../fpu/status_w.h ../fpu/control_w.h ../cpu/xmm.h vmx.h stack.h
smm.o: smm.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h ../bx_debug/debug.h \
../config.h ../osdep.h ../bxversion.h ../gui/siminterface.h \
../gui/paramtree.h ../memory/memory.h ../pc_system.h ../plugin.h \
../extplugin.h ../gui/gui.h ../instrument/stubs/instrument.h cpu.h \
model_specific.h crregs.h descriptor.h instr.h ia_opcodes.h lazy_flags.h \
icache.h apic.h ../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h \
../fpu/status_w.h ../fpu/control_w.h ../cpu/xmm.h vmx.h stack.h smm.h
soft_int.o: soft_int.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../gui/gui.h \
../instrument/stubs/instrument.h cpu.h model_specific.h crregs.h \
descriptor.h instr.h ia_opcodes.h lazy_flags.h icache.h apic.h \
../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h ../fpu/status_w.h \
../fpu/control_w.h ../cpu/xmm.h vmx.h stack.h
sse.o: sse.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h ../bx_debug/debug.h \
../config.h ../osdep.h ../bxversion.h ../gui/siminterface.h \
../gui/paramtree.h ../memory/memory.h ../pc_system.h ../plugin.h \
../extplugin.h ../gui/gui.h ../instrument/stubs/instrument.h cpu.h \
model_specific.h crregs.h descriptor.h instr.h ia_opcodes.h lazy_flags.h \
icache.h apic.h ../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h \
../fpu/status_w.h ../fpu/control_w.h ../cpu/xmm.h vmx.h stack.h
sse_move.o: sse_move.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../gui/gui.h \
../instrument/stubs/instrument.h cpu.h model_specific.h crregs.h \
descriptor.h instr.h ia_opcodes.h lazy_flags.h icache.h apic.h \
../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h ../fpu/status_w.h \
../fpu/control_w.h ../cpu/xmm.h vmx.h stack.h
sse_pfp.o: sse_pfp.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../gui/gui.h \
../instrument/stubs/instrument.h cpu.h model_specific.h crregs.h \
descriptor.h instr.h ia_opcodes.h lazy_flags.h icache.h apic.h \
../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h ../fpu/status_w.h \
../fpu/control_w.h ../cpu/xmm.h vmx.h stack.h ../fpu/softfloat-compare.h \
../fpu/softfloat.h ../fpu/softfloat-specialize.h
sse_rcp.o: sse_rcp.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../gui/gui.h \
../instrument/stubs/instrument.h cpu.h model_specific.h crregs.h \
descriptor.h instr.h ia_opcodes.h lazy_flags.h icache.h apic.h \
../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h ../fpu/status_w.h \
../fpu/control_w.h ../cpu/xmm.h vmx.h stack.h \
../fpu/softfloat-specialize.h ../fpu/softfloat.h
sse_string.o: sse_string.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../gui/gui.h \
../instrument/stubs/instrument.h cpu.h model_specific.h crregs.h \
descriptor.h instr.h ia_opcodes.h lazy_flags.h icache.h apic.h \
../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h ../fpu/status_w.h \
../fpu/control_w.h ../cpu/xmm.h vmx.h stack.h
stack16.o: stack16.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../gui/gui.h \
../instrument/stubs/instrument.h cpu.h model_specific.h crregs.h \
descriptor.h instr.h ia_opcodes.h lazy_flags.h icache.h apic.h \
../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h ../fpu/status_w.h \
../fpu/control_w.h ../cpu/xmm.h vmx.h stack.h
stack32.o: stack32.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../gui/gui.h \
../instrument/stubs/instrument.h cpu.h model_specific.h crregs.h \
descriptor.h instr.h ia_opcodes.h lazy_flags.h icache.h apic.h \
../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h ../fpu/status_w.h \
../fpu/control_w.h ../cpu/xmm.h vmx.h stack.h
stack64.o: stack64.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../gui/gui.h \
../instrument/stubs/instrument.h cpu.h model_specific.h crregs.h \
descriptor.h instr.h ia_opcodes.h lazy_flags.h icache.h apic.h \
../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h ../fpu/status_w.h \
../fpu/control_w.h ../cpu/xmm.h vmx.h stack.h
string.o: string.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h ../bx_debug/debug.h \
../config.h ../osdep.h ../bxversion.h ../gui/siminterface.h \
../gui/paramtree.h ../memory/memory.h ../pc_system.h ../plugin.h \
../extplugin.h ../gui/gui.h ../instrument/stubs/instrument.h cpu.h \
model_specific.h crregs.h descriptor.h instr.h ia_opcodes.h lazy_flags.h \
icache.h apic.h ../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h \
../fpu/status_w.h ../fpu/control_w.h ../cpu/xmm.h vmx.h stack.h
tasking.o: tasking.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../gui/gui.h \
../instrument/stubs/instrument.h cpu.h model_specific.h crregs.h \
descriptor.h instr.h ia_opcodes.h lazy_flags.h icache.h apic.h \
../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h ../fpu/status_w.h \
../fpu/control_w.h ../cpu/xmm.h vmx.h stack.h
vm8086.o: vm8086.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h ../bx_debug/debug.h \
../config.h ../osdep.h ../bxversion.h ../gui/siminterface.h \
../gui/paramtree.h ../memory/memory.h ../pc_system.h ../plugin.h \
../extplugin.h ../gui/gui.h ../instrument/stubs/instrument.h cpu.h \
model_specific.h crregs.h descriptor.h instr.h ia_opcodes.h lazy_flags.h \
icache.h apic.h ../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h \
../fpu/status_w.h ../fpu/control_w.h ../cpu/xmm.h vmx.h stack.h
vmcs.o: vmcs.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h ../bx_debug/debug.h \
../config.h ../osdep.h ../bxversion.h ../gui/siminterface.h \
../gui/paramtree.h ../memory/memory.h ../pc_system.h ../plugin.h \
../extplugin.h ../gui/gui.h ../instrument/stubs/instrument.h cpu.h \
model_specific.h crregs.h descriptor.h instr.h ia_opcodes.h lazy_flags.h \
icache.h apic.h ../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h \
../fpu/status_w.h ../fpu/control_w.h ../cpu/xmm.h vmx.h stack.h
vmexit.o: vmexit.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h ../bx_debug/debug.h \
../config.h ../osdep.h ../bxversion.h ../gui/siminterface.h \
../gui/paramtree.h ../memory/memory.h ../pc_system.h ../plugin.h \
../extplugin.h ../gui/gui.h ../instrument/stubs/instrument.h cpu.h \
model_specific.h crregs.h descriptor.h instr.h ia_opcodes.h lazy_flags.h \
icache.h apic.h ../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h \
../fpu/status_w.h ../fpu/control_w.h ../cpu/xmm.h vmx.h stack.h
vmx.o: vmx.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h ../bx_debug/debug.h \
../config.h ../osdep.h ../bxversion.h ../gui/siminterface.h \
../gui/paramtree.h ../memory/memory.h ../pc_system.h ../plugin.h \
../extplugin.h ../gui/gui.h ../instrument/stubs/instrument.h cpu.h \
model_specific.h crregs.h descriptor.h instr.h ia_opcodes.h lazy_flags.h \
icache.h apic.h ../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h \
../fpu/status_w.h ../fpu/control_w.h ../cpu/xmm.h vmx.h stack.h \
../iodev/iodev.h ../param_names.h
xsave.o: xsave.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h ../bx_debug/debug.h \
../config.h ../osdep.h ../bxversion.h ../gui/siminterface.h \
../gui/paramtree.h ../memory/memory.h ../pc_system.h ../plugin.h \
../extplugin.h ../gui/gui.h ../instrument/stubs/instrument.h cpu.h \
model_specific.h crregs.h descriptor.h instr.h ia_opcodes.h lazy_flags.h \
icache.h apic.h ../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h \
../fpu/status_w.h ../fpu/control_w.h ../cpu/xmm.h vmx.h stack.h

View File

@ -0,0 +1,503 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2005-2010 The Bochs Project
//
// 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
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA B 02110-1301 USA
//
/////////////////////////////////////////////////////////////////////////
#define NEED_CPU_REG_SHORTCUTS 1
#include "bochs.h"
#include "cpu.h"
#define LOG_THIS BX_CPU_THIS_PTR
bx_address bx_asize_mask[] = {
0xffff, // as16 (asize = '00)
0xffffffff, // as32 (asize = '01)
#if BX_SUPPORT_X86_64
BX_CONST64(0xffffffffffffffff), // as64 (asize = '10)
BX_CONST64(0xffffffffffffffff) // as64 (asize = '11)
#endif
};
bx_bool BX_CPP_AttrRegparmN(3)
BX_CPU_C::write_virtual_checks(bx_segment_reg_t *seg, Bit32u offset, unsigned length)
{
Bit32u upper_limit;
if (seg->cache.valid==0) {
BX_DEBUG(("write_virtual_checks(): segment descriptor not valid"));
return 0;
}
if (seg->cache.p == 0) { /* not present */
BX_ERROR(("write_virtual_checks(): segment not present"));
return 0;
}
switch (seg->cache.type) {
case 0: case 1: // read only
case 4: case 5: // read only, expand down
case 8: case 9: // execute only
case 10: case 11: // execute/read
case 12: case 13: // execute only, conforming
case 14: case 15: // execute/read-only, conforming
BX_ERROR(("write_virtual_checks(): no write access to seg"));
return 0;
case 2: case 3: /* read/write */
if (offset > (seg->cache.u.segment.limit_scaled - length + 1)
|| (length-1 > seg->cache.u.segment.limit_scaled))
{
BX_ERROR(("write_virtual_checks(): write beyond limit, r/w"));
return 0;
}
if (seg->cache.u.segment.limit_scaled >= 15) {
// Mark cache as being OK type for succeeding read/writes. The limit
// checks still needs to be done though, but is more simple. We
// could probably also optimize that out with a flag for the case
// when limit is the maximum 32bit value. Limit should accomodate
// at least a dword, since we subtract from it in the simple
// limit check in other functions, and we don't want the value to roll.
// Only normal segments (not expand down) are handled this way.
seg->cache.valid |= SegAccessROK | SegAccessWOK;
}
break;
case 6: case 7: /* read/write, expand down */
if (seg->cache.u.segment.d_b)
upper_limit = 0xffffffff;
else
upper_limit = 0x0000ffff;
if ((offset <= seg->cache.u.segment.limit_scaled) ||
(offset > upper_limit) || ((upper_limit - offset) < (length - 1)))
{
BX_ERROR(("write_virtual_checks(): write beyond limit, r/w ED"));
return 0;
}
break;
default:
BX_PANIC(("write_virtual_checks(): unknown descriptor type=%d", seg->cache.type));
}
return 1;
}
bx_bool BX_CPP_AttrRegparmN(3)
BX_CPU_C::read_virtual_checks(bx_segment_reg_t *seg, Bit32u offset, unsigned length)
{
Bit32u upper_limit;
if (seg->cache.valid==0) {
BX_DEBUG(("read_virtual_checks(): segment descriptor not valid"));
return 0;
}
if (seg->cache.p == 0) { /* not present */
BX_ERROR(("read_virtual_checks(): segment not present"));
return 0;
}
switch (seg->cache.type) {
case 0: case 1: /* read only */
case 2: case 3: /* read/write */
case 10: case 11: /* execute/read */
case 14: case 15: /* execute/read-only, conforming */
if (offset > (seg->cache.u.segment.limit_scaled - length + 1)
|| (length-1 > seg->cache.u.segment.limit_scaled))
{
BX_ERROR(("read_virtual_checks(): read beyond limit"));
return 0;
}
if (seg->cache.u.segment.limit_scaled >= 15) {
// Mark cache as being OK type for succeeding reads. See notes for
// write checks; similar code.
seg->cache.valid |= SegAccessROK;
}
break;
case 4: case 5: /* read only, expand down */
case 6: case 7: /* read/write, expand down */
if (seg->cache.u.segment.d_b)
upper_limit = 0xffffffff;
else
upper_limit = 0x0000ffff;
if ((offset <= seg->cache.u.segment.limit_scaled) ||
(offset > upper_limit) || ((upper_limit - offset) < (length - 1)))
{
BX_ERROR(("read_virtual_checks(): read beyond limit ED"));
return 0;
}
break;
case 8: case 9: /* execute only */
case 12: case 13: /* execute only, conforming */
/* can't read or write an execute-only segment */
BX_ERROR(("read_virtual_checks(): execute only"));
return 0;
default:
BX_PANIC(("read_virtual_checks(): unknown descriptor type=%d", seg->cache.type));
}
return 1;
}
bx_bool BX_CPP_AttrRegparmN(3)
BX_CPU_C::execute_virtual_checks(bx_segment_reg_t *seg, Bit32u offset, unsigned length)
{
Bit32u upper_limit;
if (seg->cache.valid==0) {
BX_DEBUG(("execute_virtual_checks(): segment descriptor not valid"));
return 0;
}
if (seg->cache.p == 0) { /* not present */
BX_ERROR(("execute_virtual_checks(): segment not present"));
return 0;
}
switch (seg->cache.type) {
case 0: case 1: /* read only */
case 2: case 3: /* read/write */
case 10: case 11: /* execute/read */
case 14: case 15: /* execute/read-only, conforming */
if (offset > (seg->cache.u.segment.limit_scaled - length + 1)
|| (length-1 > seg->cache.u.segment.limit_scaled))
{
BX_ERROR(("execute_virtual_checks(): read beyond limit"));
return 0;
}
if (seg->cache.u.segment.limit_scaled >= 15) {
// Mark cache as being OK type for succeeding reads. See notes for
// write checks; similar code.
seg->cache.valid |= SegAccessROK;
}
break;
case 8: case 9: /* execute only */
case 12: case 13: /* execute only, conforming */
if (offset > (seg->cache.u.segment.limit_scaled - length + 1)
|| (length-1 > seg->cache.u.segment.limit_scaled))
{
BX_ERROR(("execute_virtual_checks(): read beyond limit execute only"));
return 0;
}
break;
case 4: case 5: /* read only, expand down */
case 6: case 7: /* read/write, expand down */
if (seg->cache.u.segment.d_b)
upper_limit = 0xffffffff;
else
upper_limit = 0x0000ffff;
if ((offset <= seg->cache.u.segment.limit_scaled) ||
(offset > upper_limit) || ((upper_limit - offset) < (length - 1)))
{
BX_ERROR(("execute_virtual_checks(): read beyond limit ED"));
return 0;
}
break;
default:
BX_PANIC(("execute_virtual_checks(): unknown descriptor type=%d", seg->cache.type));
}
return 1;
}
const char *BX_CPU_C::strseg(bx_segment_reg_t *seg)
{
if (seg == &BX_CPU_THIS_PTR sregs[BX_SEG_REG_ES]) return("ES");
else if (seg == &BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS]) return("CS");
else if (seg == &BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS]) return("SS");
else if (seg == &BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS]) return("DS");
else if (seg == &BX_CPU_THIS_PTR sregs[BX_SEG_REG_FS]) return("FS");
else if (seg == &BX_CPU_THIS_PTR sregs[BX_SEG_REG_GS]) return("GS");
else {
BX_PANIC(("undefined segment passed to strseg()!"));
return("??");
}
}
int BX_CPU_C::int_number(unsigned s)
{
if (s == BX_SEG_REG_SS)
return BX_SS_EXCEPTION;
else
return BX_GP_EXCEPTION;
}
Bit8u BX_CPP_AttrRegparmN(1)
BX_CPU_C::system_read_byte(bx_address laddr)
{
Bit8u data;
unsigned tlbIndex = BX_TLB_INDEX_OF(laddr, 0);
bx_address lpf = LPFOf(laddr);
bx_TLB_entry *tlbEntry = &BX_CPU_THIS_PTR TLB.entry[tlbIndex];
if (tlbEntry->lpf == lpf) {
bx_hostpageaddr_t hostPageAddr = tlbEntry->hostPageAddr;
Bit32u pageOffset = PAGE_OFFSET(laddr);
BX_INSTR_LIN_ACCESS(BX_CPU_ID, laddr, tlbEntry->ppf | pageOffset, 1, BX_READ);
Bit8u *hostAddr = (Bit8u*) (hostPageAddr | pageOffset);
data = *hostAddr;
BX_DBG_LIN_MEMORY_ACCESS(BX_CPU_ID, laddr,
tlbEntry->ppf | pageOffset, 1, 0, BX_READ, (Bit8u*) &data);
return data;
}
#if BX_SUPPORT_X86_64
if (! IsCanonical(laddr)) {
BX_ERROR(("system_read_byte(): canonical failure"));
exception(BX_GP_EXCEPTION, 0);
}
#endif
access_read_linear(laddr, 1, 0, BX_READ, (void *) &data);
return data;
}
Bit16u BX_CPP_AttrRegparmN(1)
BX_CPU_C::system_read_word(bx_address laddr)
{
Bit16u data;
unsigned tlbIndex = BX_TLB_INDEX_OF(laddr, 1);
bx_address lpf = LPFOf(laddr);
bx_TLB_entry *tlbEntry = &BX_CPU_THIS_PTR TLB.entry[tlbIndex];
if (tlbEntry->lpf == lpf) {
bx_hostpageaddr_t hostPageAddr = tlbEntry->hostPageAddr;
Bit32u pageOffset = PAGE_OFFSET(laddr);
BX_INSTR_LIN_ACCESS(BX_CPU_ID, laddr, tlbEntry->ppf | pageOffset, 2, BX_READ);
Bit16u *hostAddr = (Bit16u*) (hostPageAddr | pageOffset);
ReadHostWordFromLittleEndian(hostAddr, data);
BX_DBG_LIN_MEMORY_ACCESS(BX_CPU_ID, laddr,
tlbEntry->ppf | pageOffset, 2, 0, BX_READ, (Bit8u*) &data);
return data;
}
#if BX_SUPPORT_X86_64
if (! IsCanonical(laddr) || ! IsCanonical(laddr+1)) {
BX_ERROR(("system_read_word(): canonical failure"));
exception(BX_GP_EXCEPTION, 0);
}
#endif
access_read_linear(laddr, 2, 0, BX_READ, (void *) &data);
return data;
}
Bit32u BX_CPP_AttrRegparmN(1)
BX_CPU_C::system_read_dword(bx_address laddr)
{
Bit32u data;
unsigned tlbIndex = BX_TLB_INDEX_OF(laddr, 3);
bx_address lpf = LPFOf(laddr);
bx_TLB_entry *tlbEntry = &BX_CPU_THIS_PTR TLB.entry[tlbIndex];
if (tlbEntry->lpf == lpf) {
bx_hostpageaddr_t hostPageAddr = tlbEntry->hostPageAddr;
Bit32u pageOffset = PAGE_OFFSET(laddr);
BX_INSTR_LIN_ACCESS(BX_CPU_ID, laddr, tlbEntry->ppf | pageOffset, 4, BX_READ);
Bit32u *hostAddr = (Bit32u*) (hostPageAddr | pageOffset);
ReadHostDWordFromLittleEndian(hostAddr, data);
BX_DBG_LIN_MEMORY_ACCESS(BX_CPU_ID, laddr,
tlbEntry->ppf | pageOffset, 4, 0, BX_READ, (Bit8u*) &data);
return data;
}
#if BX_SUPPORT_X86_64
if (! IsCanonical(laddr) || ! IsCanonical(laddr+3)) {
BX_ERROR(("system_read_dword(): canonical failure"));
exception(BX_GP_EXCEPTION, 0);
}
#endif
access_read_linear(laddr, 4, 0, BX_READ, (void *) &data);
return data;
}
Bit64u BX_CPP_AttrRegparmN(1)
BX_CPU_C::system_read_qword(bx_address laddr)
{
Bit64u data;
unsigned tlbIndex = BX_TLB_INDEX_OF(laddr, 7);
bx_address lpf = LPFOf(laddr);
bx_TLB_entry *tlbEntry = &BX_CPU_THIS_PTR TLB.entry[tlbIndex];
if (tlbEntry->lpf == lpf) {
bx_hostpageaddr_t hostPageAddr = tlbEntry->hostPageAddr;
Bit32u pageOffset = PAGE_OFFSET(laddr);
BX_INSTR_LIN_ACCESS(BX_CPU_ID, laddr, tlbEntry->ppf | pageOffset, 8, BX_READ);
Bit64u *hostAddr = (Bit64u*) (hostPageAddr | pageOffset);
ReadHostQWordFromLittleEndian(hostAddr, data);
BX_DBG_LIN_MEMORY_ACCESS(BX_CPU_ID, laddr,
tlbEntry->ppf | pageOffset, 8, 0, BX_READ, (Bit8u*) &data);
return data;
}
#if BX_SUPPORT_X86_64
if (! IsCanonical(laddr) || ! IsCanonical(laddr+7)) {
BX_ERROR(("system_read_qword(): canonical failure"));
exception(BX_GP_EXCEPTION, 0);
}
#endif
access_read_linear(laddr, 8, 0, BX_READ, (void *) &data);
return data;
}
void BX_CPP_AttrRegparmN(2)
BX_CPU_C::system_write_byte(bx_address laddr, Bit8u data)
{
unsigned tlbIndex = BX_TLB_INDEX_OF(laddr, 0);
Bit32u lpf = LPFOf(laddr);
bx_TLB_entry *tlbEntry = &BX_CPU_THIS_PTR TLB.entry[tlbIndex];
if (tlbEntry->lpf == lpf) {
// See if the TLB entry privilege level allows us write access
// from this CPL.
if (! (tlbEntry->accessBits & 0x2)) {
bx_hostpageaddr_t hostPageAddr = tlbEntry->hostPageAddr;
Bit32u pageOffset = PAGE_OFFSET(laddr);
bx_phy_address pAddr = tlbEntry->ppf | pageOffset;
BX_INSTR_LIN_ACCESS(BX_CPU_ID, laddr, pAddr, 1, BX_WRITE);
BX_DBG_LIN_MEMORY_ACCESS(BX_CPU_ID, laddr, pAddr, 1, 0, BX_WRITE, (Bit8u*) &data);
Bit8u *hostAddr = (Bit8u*) (hostPageAddr | pageOffset);
pageWriteStampTable.decWriteStamp(pAddr, 1);
*hostAddr = data;
return;
}
}
#if BX_SUPPORT_X86_64
if (! IsCanonical(laddr)) {
BX_ERROR(("system_write_byte(): canonical failure"));
exception(BX_GP_EXCEPTION, 0);
}
#endif
access_write_linear(laddr, 1, 0, (void *) &data);
}
void BX_CPP_AttrRegparmN(2)
BX_CPU_C::system_write_word(bx_address laddr, Bit16u data)
{
unsigned tlbIndex = BX_TLB_INDEX_OF(laddr, 1);
Bit32u lpf = LPFOf(laddr);
bx_TLB_entry *tlbEntry = &BX_CPU_THIS_PTR TLB.entry[tlbIndex];
if (tlbEntry->lpf == lpf) {
// See if the TLB entry privilege level allows us write access
// from this CPL.
if (! (tlbEntry->accessBits & 0x2)) {
bx_hostpageaddr_t hostPageAddr = tlbEntry->hostPageAddr;
Bit32u pageOffset = PAGE_OFFSET(laddr);
bx_phy_address pAddr = tlbEntry->ppf | pageOffset;
BX_INSTR_LIN_ACCESS(BX_CPU_ID, laddr, pAddr, 2, BX_WRITE);
BX_DBG_LIN_MEMORY_ACCESS(BX_CPU_ID, laddr, pAddr, 2, 0, BX_WRITE, (Bit8u*) &data);
Bit16u *hostAddr = (Bit16u*) (hostPageAddr | pageOffset);
pageWriteStampTable.decWriteStamp(pAddr, 2);
WriteHostWordToLittleEndian(hostAddr, data);
return;
}
}
#if BX_SUPPORT_X86_64
if (! IsCanonical(laddr) || ! IsCanonical(laddr+1)) {
BX_ERROR(("system_write_word(): canonical failure"));
exception(BX_GP_EXCEPTION, 0);
}
#endif
access_write_linear(laddr, 2, 0, (void *) &data);
}
void BX_CPP_AttrRegparmN(2)
BX_CPU_C::system_write_dword(bx_address laddr, Bit32u data)
{
unsigned tlbIndex = BX_TLB_INDEX_OF(laddr, 3);
Bit32u lpf = LPFOf(laddr);
bx_TLB_entry *tlbEntry = &BX_CPU_THIS_PTR TLB.entry[tlbIndex];
if (tlbEntry->lpf == lpf) {
// See if the TLB entry privilege level allows us write access
// from this CPL.
if (! (tlbEntry->accessBits & 0x2)) {
bx_hostpageaddr_t hostPageAddr = tlbEntry->hostPageAddr;
Bit32u pageOffset = PAGE_OFFSET(laddr);
bx_phy_address pAddr = tlbEntry->ppf | pageOffset;
BX_INSTR_LIN_ACCESS(BX_CPU_ID, laddr, pAddr, 4, BX_WRITE);
BX_DBG_LIN_MEMORY_ACCESS(BX_CPU_ID, laddr, pAddr, 4, 0, BX_WRITE, (Bit8u*) &data);
Bit32u *hostAddr = (Bit32u*) (hostPageAddr | pageOffset);
pageWriteStampTable.decWriteStamp(pAddr, 4);
WriteHostDWordToLittleEndian(hostAddr, data);
return;
}
}
#if BX_SUPPORT_X86_64
if (! IsCanonical(laddr) || ! IsCanonical(laddr+3)) {
BX_ERROR(("system_write_dword(): canonical failure"));
exception(BX_GP_EXCEPTION, 0);
}
#endif
access_write_linear(laddr, 4, 0, (void *) &data);
}
Bit8u* BX_CPP_AttrRegparmN(2)
BX_CPU_C::v2h_read_byte(bx_address laddr, bx_bool user)
{
unsigned tlbIndex = BX_TLB_INDEX_OF(laddr, 0);
bx_address lpf = LPFOf(laddr);
bx_TLB_entry *tlbEntry = &BX_CPU_THIS_PTR TLB.entry[tlbIndex];
if (tlbEntry->lpf == lpf) {
// See if the TLB entry privilege level allows us read access
// from this CPL.
if (! (tlbEntry->accessBits & user)) { // Read this pl OK.
bx_hostpageaddr_t hostPageAddr = tlbEntry->hostPageAddr;
Bit32u pageOffset = PAGE_OFFSET(laddr);
Bit8u *hostAddr = (Bit8u*) (hostPageAddr | pageOffset);
return hostAddr;
}
}
return 0;
}
Bit8u* BX_CPP_AttrRegparmN(2)
BX_CPU_C::v2h_write_byte(bx_address laddr, bx_bool user)
{
unsigned tlbIndex = BX_TLB_INDEX_OF(laddr, 0);
bx_address lpf = LPFOf(laddr);
bx_TLB_entry *tlbEntry = &BX_CPU_THIS_PTR TLB.entry[tlbIndex];
if (tlbEntry->lpf == lpf)
{
// See if the TLB entry privilege level allows us write access
// from this CPL.
if (! (tlbEntry->accessBits & (0x2 | user))) {
bx_hostpageaddr_t hostPageAddr = tlbEntry->hostPageAddr;
Bit32u pageOffset = PAGE_OFFSET(laddr);
Bit8u *hostAddr = (Bit8u*) (hostPageAddr | pageOffset);
pageWriteStampTable.decWriteStamp(tlbEntry->ppf);
return hostAddr;
}
}
return 0;
}

1234
simulators/bochs/cpu/access32.cc Executable file

File diff suppressed because it is too large Load Diff

920
simulators/bochs/cpu/access64.cc Executable file
View File

@ -0,0 +1,920 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2008-2010 Stanislav Shwartsman
// 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
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA B 02110-1301 USA
//
/////////////////////////////////////////////////////////////////////////
#define NEED_CPU_REG_SHORTCUTS 1
#include "bochs.h"
#include "cpu.h"
#define LOG_THIS BX_CPU_THIS_PTR
#if BX_SUPPORT_X86_64
void BX_CPP_AttrRegparmN(3)
BX_CPU_C::write_virtual_byte_64(unsigned s, Bit64u offset, Bit8u data)
{
BX_ASSERT(BX_CPU_THIS_PTR cpu_mode == BX_MODE_LONG_64);
BX_INSTR_MEM_DATA_ACCESS(BX_CPU_ID, s, offset, 1, BX_WRITE);
Bit64u laddr = BX_CPU_THIS_PTR get_laddr64(s, offset);
unsigned tlbIndex = BX_TLB_INDEX_OF(laddr, 0);
Bit64u lpf = LPFOf(laddr);
bx_TLB_entry *tlbEntry = &BX_CPU_THIS_PTR TLB.entry[tlbIndex];
if (tlbEntry->lpf == lpf) {
// See if the TLB entry privilege level allows us write access
// from this CPL.
if (! (tlbEntry->accessBits & (0x2 | USER_PL))) {
bx_hostpageaddr_t hostPageAddr = tlbEntry->hostPageAddr;
Bit32u pageOffset = PAGE_OFFSET(laddr);
bx_phy_address pAddr = tlbEntry->ppf | pageOffset;
BX_INSTR_LIN_ACCESS(BX_CPU_ID, laddr, pAddr, 1, BX_WRITE);
BX_DBG_LIN_MEMORY_ACCESS(BX_CPU_ID, laddr, pAddr, 1, CPL, BX_WRITE, (Bit8u*) &data);
Bit8u *hostAddr = (Bit8u*) (hostPageAddr | pageOffset);
pageWriteStampTable.decWriteStamp(pAddr, 1);
*hostAddr = data;
return;
}
}
if (! IsCanonical(laddr)) {
BX_ERROR(("write_virtual_byte_64(): canonical failure"));
exception(int_number(s), 0);
}
access_write_linear(laddr, 1, CPL, (void *) &data);
}
void BX_CPP_AttrRegparmN(3)
BX_CPU_C::write_virtual_word_64(unsigned s, Bit64u offset, Bit16u data)
{
BX_ASSERT(BX_CPU_THIS_PTR cpu_mode == BX_MODE_LONG_64);
BX_INSTR_MEM_DATA_ACCESS(BX_CPU_ID, s, offset, 2, BX_WRITE);
Bit64u laddr = BX_CPU_THIS_PTR get_laddr64(s, offset);
unsigned tlbIndex = BX_TLB_INDEX_OF(laddr, 1);
#if BX_SUPPORT_ALIGNMENT_CHECK && BX_CPU_LEVEL >= 4
Bit64u lpf = AlignedAccessLPFOf(laddr, (1 & BX_CPU_THIS_PTR alignment_check_mask));
#else
Bit64u lpf = LPFOf(laddr);
#endif
bx_TLB_entry *tlbEntry = &BX_CPU_THIS_PTR TLB.entry[tlbIndex];
if (tlbEntry->lpf == lpf) {
// See if the TLB entry privilege level allows us write access
// from this CPL.
if (! (tlbEntry->accessBits & (0x2 | USER_PL))) {
bx_hostpageaddr_t hostPageAddr = tlbEntry->hostPageAddr;
Bit32u pageOffset = PAGE_OFFSET(laddr);
bx_phy_address pAddr = tlbEntry->ppf | pageOffset;
BX_INSTR_LIN_ACCESS(BX_CPU_ID, laddr, pAddr, 2, BX_WRITE);
BX_DBG_LIN_MEMORY_ACCESS(BX_CPU_ID, laddr, pAddr, 2, CPL, BX_WRITE, (Bit8u*) &data);
Bit16u *hostAddr = (Bit16u*) (hostPageAddr | pageOffset);
pageWriteStampTable.decWriteStamp(pAddr, 2);
WriteHostWordToLittleEndian(hostAddr, data);
return;
}
}
if (! IsCanonical(laddr)) {
BX_ERROR(("write_virtual_word_64(): canonical failure"));
exception(int_number(s), 0);
}
#if BX_CPU_LEVEL >= 4 && BX_SUPPORT_ALIGNMENT_CHECK
if (BX_CPU_THIS_PTR alignment_check()) {
if (laddr & 1) {
BX_ERROR(("write_virtual_word_64(): #AC misaligned access"));
exception(BX_AC_EXCEPTION, 0);
}
}
#endif
if (! IsCanonical(laddr+1)) {
BX_ERROR(("write_virtual_word_64(): canonical failure"));
exception(int_number(s), 0);
}
access_write_linear(laddr, 2, CPL, (void *) &data);
}
void BX_CPP_AttrRegparmN(3)
BX_CPU_C::write_virtual_dword_64(unsigned s, Bit64u offset, Bit32u data)
{
BX_ASSERT(BX_CPU_THIS_PTR cpu_mode == BX_MODE_LONG_64);
BX_INSTR_MEM_DATA_ACCESS(BX_CPU_ID, s, offset, 4, BX_WRITE);
Bit64u laddr = BX_CPU_THIS_PTR get_laddr64(s, offset);
unsigned tlbIndex = BX_TLB_INDEX_OF(laddr, 3);
#if BX_SUPPORT_ALIGNMENT_CHECK && BX_CPU_LEVEL >= 4
Bit64u lpf = AlignedAccessLPFOf(laddr, (3 & BX_CPU_THIS_PTR alignment_check_mask));
#else
Bit64u lpf = LPFOf(laddr);
#endif
bx_TLB_entry *tlbEntry = &BX_CPU_THIS_PTR TLB.entry[tlbIndex];
if (tlbEntry->lpf == lpf) {
// See if the TLB entry privilege level allows us write access
// from this CPL.
if (! (tlbEntry->accessBits & (0x2 | USER_PL))) {
bx_hostpageaddr_t hostPageAddr = tlbEntry->hostPageAddr;
Bit32u pageOffset = PAGE_OFFSET(laddr);
bx_phy_address pAddr = tlbEntry->ppf | pageOffset;
BX_INSTR_LIN_ACCESS(BX_CPU_ID, laddr, pAddr, 4, BX_WRITE);
BX_DBG_LIN_MEMORY_ACCESS(BX_CPU_ID, laddr, pAddr, 4, CPL, BX_WRITE, (Bit8u*) &data);
Bit32u *hostAddr = (Bit32u*) (hostPageAddr | pageOffset);
pageWriteStampTable.decWriteStamp(pAddr, 4);
WriteHostDWordToLittleEndian(hostAddr, data);
return;
}
}
if (! IsCanonical(laddr)) {
BX_ERROR(("write_virtual_dword_64(): canonical failure"));
exception(int_number(s), 0);
}
#if BX_CPU_LEVEL >= 4 && BX_SUPPORT_ALIGNMENT_CHECK
if (BX_CPU_THIS_PTR alignment_check()) {
if (laddr & 3) {
BX_ERROR(("write_virtual_dword_64(): #AC misaligned access"));
exception(BX_AC_EXCEPTION, 0);
}
}
#endif
if (! IsCanonical(laddr+3)) {
BX_ERROR(("write_virtual_dword_64(): canonical failure"));
exception(int_number(s), 0);
}
access_write_linear(laddr, 4, CPL, (void *) &data);
}
void BX_CPP_AttrRegparmN(3)
BX_CPU_C::write_virtual_qword_64(unsigned s, Bit64u offset, Bit64u data)
{
BX_ASSERT(BX_CPU_THIS_PTR cpu_mode == BX_MODE_LONG_64);
BX_INSTR_MEM_DATA_ACCESS(BX_CPU_ID, s, offset, 8, BX_WRITE);
Bit64u laddr = BX_CPU_THIS_PTR get_laddr64(s, offset);
unsigned tlbIndex = BX_TLB_INDEX_OF(laddr, 7);
#if BX_SUPPORT_ALIGNMENT_CHECK && BX_CPU_LEVEL >= 4
Bit64u lpf = AlignedAccessLPFOf(laddr, (7 & BX_CPU_THIS_PTR alignment_check_mask));
#else
Bit64u lpf = LPFOf(laddr);
#endif
bx_TLB_entry *tlbEntry = &BX_CPU_THIS_PTR TLB.entry[tlbIndex];
if (tlbEntry->lpf == lpf) {
// See if the TLB entry privilege level allows us write access
// from this CPL.
if (! (tlbEntry->accessBits & (0x2 | USER_PL))) {
bx_hostpageaddr_t hostPageAddr = tlbEntry->hostPageAddr;
Bit32u pageOffset = PAGE_OFFSET(laddr);
bx_phy_address pAddr = tlbEntry->ppf | pageOffset;
BX_INSTR_LIN_ACCESS(BX_CPU_ID, laddr, pAddr, 8, BX_WRITE);
BX_DBG_LIN_MEMORY_ACCESS(BX_CPU_ID, laddr, pAddr, 8, CPL, BX_WRITE, (Bit8u*) &data);
Bit64u *hostAddr = (Bit64u*) (hostPageAddr | pageOffset);
pageWriteStampTable.decWriteStamp(pAddr, 8);
WriteHostQWordToLittleEndian(hostAddr, data);
return;
}
}
if (! IsCanonical(laddr)) {
BX_ERROR(("write_virtual_qword_64(): canonical failure"));
exception(int_number(s), 0);
}
#if BX_CPU_LEVEL >= 4 && BX_SUPPORT_ALIGNMENT_CHECK
if (BX_CPU_THIS_PTR alignment_check()) {
if (laddr & 7) {
BX_ERROR(("write_virtual_qword_64(): #AC misaligned access"));
exception(BX_AC_EXCEPTION, 0);
}
}
#endif
if (! IsCanonical(laddr+7)) {
BX_ERROR(("write_virtual_qword_64(): canonical failure"));
exception(int_number(s), 0);
}
access_write_linear(laddr, 8, CPL, (void *) &data);
}
void BX_CPP_AttrRegparmN(3)
BX_CPU_C::write_virtual_dqword_64(unsigned s, Bit64u offset, const BxPackedXmmRegister *data)
{
BX_ASSERT(BX_CPU_THIS_PTR cpu_mode == BX_MODE_LONG_64);
BX_INSTR_MEM_DATA_ACCESS(BX_CPU_ID, s, offset, 16, BX_WRITE);
Bit64u laddr = BX_CPU_THIS_PTR get_laddr64(s, offset);
unsigned tlbIndex = BX_TLB_INDEX_OF(laddr, 15);
Bit64u lpf = LPFOf(laddr);
bx_TLB_entry *tlbEntry = &BX_CPU_THIS_PTR TLB.entry[tlbIndex];
if (tlbEntry->lpf == lpf) {
// See if the TLB entry privilege level allows us write access
// from this CPL.
if (! (tlbEntry->accessBits & (0x2 | USER_PL))) {
bx_hostpageaddr_t hostPageAddr = tlbEntry->hostPageAddr;
Bit32u pageOffset = PAGE_OFFSET(laddr);
bx_phy_address pAddr = tlbEntry->ppf | pageOffset;
BX_INSTR_LIN_ACCESS(BX_CPU_ID, laddr, pAddr, 16, BX_WRITE);
BX_DBG_LIN_MEMORY_ACCESS(BX_CPU_ID, laddr, pAddr, 16, CPL, BX_WRITE, (Bit8u*) data);
Bit64u *hostAddr = (Bit64u*) (hostPageAddr | pageOffset);
pageWriteStampTable.decWriteStamp(pAddr, 16);
WriteHostQWordToLittleEndian(hostAddr, data->xmm64u(0));
WriteHostQWordToLittleEndian(hostAddr+1, data->xmm64u(1));
return;
}
}
if (! IsCanonical(laddr) || ! IsCanonical(laddr+15)) {
BX_ERROR(("write_virtual_dqword_64(): canonical failure"));
exception(int_number(s), 0);
}
access_write_linear(laddr, 16, CPL, (void *) data);
}
void BX_CPP_AttrRegparmN(3)
BX_CPU_C::write_virtual_dqword_aligned_64(unsigned s, Bit64u offset, const BxPackedXmmRegister *data)
{
BX_ASSERT(BX_CPU_THIS_PTR cpu_mode == BX_MODE_LONG_64);
BX_INSTR_MEM_DATA_ACCESS(BX_CPU_ID, s, offset, 16, BX_WRITE);
Bit64u laddr = BX_CPU_THIS_PTR get_laddr64(s, offset);
unsigned tlbIndex = BX_TLB_INDEX_OF(laddr, 0);
Bit64u lpf = AlignedAccessLPFOf(laddr, 15);
bx_TLB_entry *tlbEntry = &BX_CPU_THIS_PTR TLB.entry[tlbIndex];
if (tlbEntry->lpf == lpf) {
// See if the TLB entry privilege level allows us write access
// from this CPL.
if (! (tlbEntry->accessBits & (0x2 | USER_PL))) {
bx_hostpageaddr_t hostPageAddr = tlbEntry->hostPageAddr;
Bit32u pageOffset = PAGE_OFFSET(laddr);
bx_phy_address pAddr = tlbEntry->ppf | pageOffset;
BX_INSTR_LIN_ACCESS(BX_CPU_ID, laddr, pAddr, 16, BX_WRITE);
BX_DBG_LIN_MEMORY_ACCESS(BX_CPU_ID, laddr, pAddr, 16, CPL, BX_WRITE, (Bit8u*) data);
Bit64u *hostAddr = (Bit64u*) (hostPageAddr | pageOffset);
pageWriteStampTable.decWriteStamp(pAddr, 16);
WriteHostQWordToLittleEndian(hostAddr, data->xmm64u(0));
WriteHostQWordToLittleEndian(hostAddr+1, data->xmm64u(1));
return;
}
}
if (laddr & 15) {
BX_ERROR(("write_virtual_dqword_aligned_64(): #GP misaligned access"));
exception(BX_GP_EXCEPTION, 0);
}
if (! IsCanonical(laddr) || ! IsCanonical(laddr+15)) {
BX_ERROR(("write_virtual_dqword_aligned_64(): canonical failure"));
exception(int_number(s), 0);
}
access_write_linear(laddr, 16, CPL, (void *) data);
}
Bit8u BX_CPP_AttrRegparmN(2)
BX_CPU_C::read_virtual_byte_64(unsigned s, Bit64u offset)
{
BX_ASSERT(BX_CPU_THIS_PTR cpu_mode == BX_MODE_LONG_64);
Bit8u data;
BX_INSTR_MEM_DATA_ACCESS(BX_CPU_ID, s, offset, 1, BX_READ);
Bit64u laddr = BX_CPU_THIS_PTR get_laddr64(s, offset);
unsigned tlbIndex = BX_TLB_INDEX_OF(laddr, 0);
Bit64u lpf = LPFOf(laddr);
bx_TLB_entry *tlbEntry = &BX_CPU_THIS_PTR TLB.entry[tlbIndex];
if (tlbEntry->lpf == lpf) {
// See if the TLB entry privilege level allows us read access
// from this CPL.
if (! (tlbEntry->accessBits & USER_PL)) { // Read this pl OK.
bx_hostpageaddr_t hostPageAddr = tlbEntry->hostPageAddr;
Bit32u pageOffset = PAGE_OFFSET(laddr);
Bit8u *hostAddr = (Bit8u*) (hostPageAddr | pageOffset);
data = *hostAddr;
BX_INSTR_LIN_ACCESS(BX_CPU_ID, laddr, tlbEntry->ppf | pageOffset, 1, BX_READ);
BX_DBG_LIN_MEMORY_ACCESS(BX_CPU_ID, laddr,
tlbEntry->ppf | pageOffset, 1, CPL, BX_READ, (Bit8u*) &data);
return data;
}
}
if (! IsCanonical(laddr)) {
BX_ERROR(("read_virtual_byte_64(): canonical failure"));
exception(int_number(s), 0);
}
access_read_linear(laddr, 1, CPL, BX_READ, (void *) &data);
return data;
}
Bit16u BX_CPP_AttrRegparmN(2)
BX_CPU_C::read_virtual_word_64(unsigned s, Bit64u offset)
{
BX_ASSERT(BX_CPU_THIS_PTR cpu_mode == BX_MODE_LONG_64);
Bit16u data;
BX_INSTR_MEM_DATA_ACCESS(BX_CPU_ID, s, offset, 2, BX_READ);
Bit64u laddr = BX_CPU_THIS_PTR get_laddr64(s, offset);
unsigned tlbIndex = BX_TLB_INDEX_OF(laddr, 1);
#if BX_SUPPORT_ALIGNMENT_CHECK && BX_CPU_LEVEL >= 4
Bit64u lpf = AlignedAccessLPFOf(laddr, (1 & BX_CPU_THIS_PTR alignment_check_mask));
#else
Bit64u lpf = LPFOf(laddr);
#endif
bx_TLB_entry *tlbEntry = &BX_CPU_THIS_PTR TLB.entry[tlbIndex];
if (tlbEntry->lpf == lpf) {
// See if the TLB entry privilege level allows us read access
// from this CPL.
if (! (tlbEntry->accessBits & USER_PL)) { // Read this pl OK.
bx_hostpageaddr_t hostPageAddr = tlbEntry->hostPageAddr;
Bit32u pageOffset = PAGE_OFFSET(laddr);
Bit16u *hostAddr = (Bit16u*) (hostPageAddr | pageOffset);
ReadHostWordFromLittleEndian(hostAddr, data);
BX_INSTR_LIN_ACCESS(BX_CPU_ID, laddr, tlbEntry->ppf | pageOffset, 2, BX_READ);
BX_DBG_LIN_MEMORY_ACCESS(BX_CPU_ID, laddr,
tlbEntry->ppf | pageOffset, 2, CPL, BX_READ, (Bit8u*) &data);
return data;
}
}
if (! IsCanonical(laddr)) {
BX_ERROR(("read_virtual_word_64(): canonical failure"));
exception(int_number(s), 0);
}
#if BX_CPU_LEVEL >= 4 && BX_SUPPORT_ALIGNMENT_CHECK
if (BX_CPU_THIS_PTR alignment_check()) {
if (laddr & 1) {
BX_ERROR(("read_virtual_word_64(): #AC misaligned access"));
exception(BX_AC_EXCEPTION, 0);
}
}
#endif
if (! IsCanonical(laddr+1)) {
BX_ERROR(("read_virtual_word_64(): canonical failure"));
exception(int_number(s), 0);
}
access_read_linear(laddr, 2, CPL, BX_READ, (void *) &data);
return data;
}
Bit32u BX_CPP_AttrRegparmN(2)
BX_CPU_C::read_virtual_dword_64(unsigned s, Bit64u offset)
{
BX_ASSERT(BX_CPU_THIS_PTR cpu_mode == BX_MODE_LONG_64);
Bit32u data;
BX_INSTR_MEM_DATA_ACCESS(BX_CPU_ID, s, offset, 4, BX_READ);
Bit64u laddr = BX_CPU_THIS_PTR get_laddr64(s, offset);
unsigned tlbIndex = BX_TLB_INDEX_OF(laddr, 3);
#if BX_SUPPORT_ALIGNMENT_CHECK && BX_CPU_LEVEL >= 4
Bit64u lpf = AlignedAccessLPFOf(laddr, (3 & BX_CPU_THIS_PTR alignment_check_mask));
#else
Bit64u lpf = LPFOf(laddr);
#endif
bx_TLB_entry *tlbEntry = &BX_CPU_THIS_PTR TLB.entry[tlbIndex];
if (tlbEntry->lpf == lpf) {
// See if the TLB entry privilege level allows us read access
// from this CPL.
if (! (tlbEntry->accessBits & USER_PL)) { // Read this pl OK.
bx_hostpageaddr_t hostPageAddr = tlbEntry->hostPageAddr;
Bit32u pageOffset = PAGE_OFFSET(laddr);
Bit32u *hostAddr = (Bit32u*) (hostPageAddr | pageOffset);
ReadHostDWordFromLittleEndian(hostAddr, data);
BX_INSTR_LIN_ACCESS(BX_CPU_ID, laddr, tlbEntry->ppf | pageOffset, 4, BX_READ);
BX_DBG_LIN_MEMORY_ACCESS(BX_CPU_ID, laddr,
tlbEntry->ppf | pageOffset, 4, CPL, BX_READ, (Bit8u*) &data);
return data;
}
}
if (! IsCanonical(laddr)) {
BX_ERROR(("read_virtual_dword_64(): canonical failure"));
exception(int_number(s), 0);
}
#if BX_CPU_LEVEL >= 4 && BX_SUPPORT_ALIGNMENT_CHECK
if (BX_CPU_THIS_PTR alignment_check()) {
if (laddr & 3) {
BX_ERROR(("read_virtual_dword_64(): #AC misaligned access"));
exception(BX_AC_EXCEPTION, 0);
}
}
#endif
if (! IsCanonical(laddr+3)) {
BX_ERROR(("read_virtual_dword_64(): canonical failure"));
exception(int_number(s), 0);
}
access_read_linear(laddr, 4, CPL, BX_READ, (void *) &data);
return data;
}
Bit64u BX_CPP_AttrRegparmN(2)
BX_CPU_C::read_virtual_qword_64(unsigned s, Bit64u offset)
{
BX_ASSERT(BX_CPU_THIS_PTR cpu_mode == BX_MODE_LONG_64);
Bit64u data;
BX_INSTR_MEM_DATA_ACCESS(BX_CPU_ID, s, offset, 8, BX_READ);
Bit64u laddr = BX_CPU_THIS_PTR get_laddr64(s, offset);
unsigned tlbIndex = BX_TLB_INDEX_OF(laddr, 7);
#if BX_SUPPORT_ALIGNMENT_CHECK && BX_CPU_LEVEL >= 4
Bit64u lpf = AlignedAccessLPFOf(laddr, (7 & BX_CPU_THIS_PTR alignment_check_mask));
#else
Bit64u lpf = LPFOf(laddr);
#endif
bx_TLB_entry *tlbEntry = &BX_CPU_THIS_PTR TLB.entry[tlbIndex];
if (tlbEntry->lpf == lpf) {
// See if the TLB entry privilege level allows us read access
// from this CPL.
if (! (tlbEntry->accessBits & USER_PL)) { // Read this pl OK.
bx_hostpageaddr_t hostPageAddr = tlbEntry->hostPageAddr;
Bit32u pageOffset = PAGE_OFFSET(laddr);
Bit64u *hostAddr = (Bit64u*) (hostPageAddr | pageOffset);
ReadHostQWordFromLittleEndian(hostAddr, data);
BX_INSTR_LIN_ACCESS(BX_CPU_ID, laddr, tlbEntry->ppf | pageOffset, 8, BX_READ);
BX_DBG_LIN_MEMORY_ACCESS(BX_CPU_ID, laddr,
tlbEntry->ppf | pageOffset, 8, CPL, BX_READ, (Bit8u*) &data);
return data;
}
}
if (! IsCanonical(laddr)) {
BX_ERROR(("read_virtual_qword_64(): canonical failure"));
exception(int_number(s), 0);
}
#if BX_CPU_LEVEL >= 4 && BX_SUPPORT_ALIGNMENT_CHECK
if (BX_CPU_THIS_PTR alignment_check()) {
if (laddr & 7) {
BX_ERROR(("read_virtual_qword_64(): #AC misaligned access"));
exception(BX_AC_EXCEPTION, 0);
}
}
#endif
if (! IsCanonical(laddr+7)) {
BX_ERROR(("read_virtual_qword_64(): canonical failure"));
exception(int_number(s), 0);
}
access_read_linear(laddr, 8, CPL, BX_READ, (void *) &data);
return data;
}
void BX_CPP_AttrRegparmN(3)
BX_CPU_C::read_virtual_dqword_64(unsigned s, Bit64u offset, BxPackedXmmRegister *data)
{
BX_ASSERT(BX_CPU_THIS_PTR cpu_mode == BX_MODE_LONG_64);
BX_INSTR_MEM_DATA_ACCESS(BX_CPU_ID, s, offset, 16, BX_READ);
Bit64u laddr = BX_CPU_THIS_PTR get_laddr64(s, offset);
unsigned tlbIndex = BX_TLB_INDEX_OF(laddr, 15);
Bit64u lpf = LPFOf(laddr);
bx_TLB_entry *tlbEntry = &BX_CPU_THIS_PTR TLB.entry[tlbIndex];
if (tlbEntry->lpf == lpf) {
// See if the TLB entry privilege level allows us read access
// from this CPL.
if (! (tlbEntry->accessBits & USER_PL)) { // Read this pl OK.
bx_hostpageaddr_t hostPageAddr = tlbEntry->hostPageAddr;
Bit32u pageOffset = PAGE_OFFSET(laddr);
Bit64u *hostAddr = (Bit64u*) (hostPageAddr | pageOffset);
ReadHostQWordFromLittleEndian(hostAddr, data->xmm64u(0));
ReadHostQWordFromLittleEndian(hostAddr+1, data->xmm64u(1));
BX_INSTR_LIN_ACCESS(BX_CPU_ID, laddr, tlbEntry->ppf | pageOffset, 16, BX_READ);
BX_DBG_LIN_MEMORY_ACCESS(BX_CPU_ID, laddr,
tlbEntry->ppf | pageOffset, 16, CPL, BX_READ, (Bit8u*) data);
return;
}
}
if (! IsCanonical(laddr) || ! IsCanonical(laddr+15)) {
BX_ERROR(("read_virtual_dqword_64(): canonical failure"));
exception(int_number(s), 0);
}
access_read_linear(laddr, 16, CPL, BX_READ, (void *) data);
}
void BX_CPP_AttrRegparmN(3)
BX_CPU_C::read_virtual_dqword_aligned_64(unsigned s, Bit64u offset, BxPackedXmmRegister *data)
{
BX_ASSERT(BX_CPU_THIS_PTR cpu_mode == BX_MODE_LONG_64);
BX_INSTR_MEM_DATA_ACCESS(BX_CPU_ID, s, offset, 16, BX_READ);
Bit64u laddr = BX_CPU_THIS_PTR get_laddr64(s, offset);
unsigned tlbIndex = BX_TLB_INDEX_OF(laddr, 0);
Bit64u lpf = AlignedAccessLPFOf(laddr, 15);
bx_TLB_entry *tlbEntry = &BX_CPU_THIS_PTR TLB.entry[tlbIndex];
if (tlbEntry->lpf == lpf) {
// See if the TLB entry privilege level allows us read access
// from this CPL.
if (! (tlbEntry->accessBits & USER_PL)) { // Read this pl OK.
bx_hostpageaddr_t hostPageAddr = tlbEntry->hostPageAddr;
Bit32u pageOffset = PAGE_OFFSET(laddr);
Bit64u *hostAddr = (Bit64u*) (hostPageAddr | pageOffset);
ReadHostQWordFromLittleEndian(hostAddr, data->xmm64u(0));
ReadHostQWordFromLittleEndian(hostAddr+1, data->xmm64u(1));
BX_INSTR_LIN_ACCESS(BX_CPU_ID, laddr, tlbEntry->ppf | pageOffset, 16, BX_READ);
BX_DBG_LIN_MEMORY_ACCESS(BX_CPU_ID, laddr,
tlbEntry->ppf | pageOffset, 16, CPL, BX_READ, (Bit8u*) data);
return;
}
}
if (laddr & 15) {
BX_ERROR(("read_virtual_dqword_aligned_64(): #GP misaligned access"));
exception(BX_GP_EXCEPTION, 0);
}
if (! IsCanonical(laddr) || ! IsCanonical(laddr+15)) {
BX_ERROR(("read_virtual_dqword_aligned_64(): canonical failure"));
exception(int_number(s), 0);
}
access_read_linear(laddr, 16, CPL, BX_READ, (void *) data);
}
//////////////////////////////////////////////////////////////
// special Read-Modify-Write operations //
// address translation info is kept across read/write calls //
//////////////////////////////////////////////////////////////
Bit8u BX_CPP_AttrRegparmN(2)
BX_CPU_C::read_RMW_virtual_byte_64(unsigned s, Bit64u offset)
{
BX_ASSERT(BX_CPU_THIS_PTR cpu_mode == BX_MODE_LONG_64);
Bit8u data;
BX_INSTR_MEM_DATA_ACCESS(BX_CPU_ID, s, offset, 1, BX_RW);
Bit64u laddr = BX_CPU_THIS_PTR get_laddr64(s, offset);
unsigned tlbIndex = BX_TLB_INDEX_OF(laddr, 0);
Bit64u lpf = LPFOf(laddr);
bx_TLB_entry *tlbEntry = &BX_CPU_THIS_PTR TLB.entry[tlbIndex];
if (tlbEntry->lpf == lpf) {
// See if the TLB entry privilege level allows us write access
// from this CPL.
if (! (tlbEntry->accessBits & (0x2 | USER_PL))) {
bx_hostpageaddr_t hostPageAddr = tlbEntry->hostPageAddr;
Bit32u pageOffset = PAGE_OFFSET(laddr);
bx_phy_address pAddr = tlbEntry->ppf | pageOffset;
Bit8u *hostAddr = (Bit8u*) (hostPageAddr | pageOffset);
pageWriteStampTable.decWriteStamp(pAddr, 1);
data = *hostAddr;
BX_CPU_THIS_PTR address_xlation.pages = (bx_ptr_equiv_t) hostAddr;
BX_INSTR_LIN_ACCESS(BX_CPU_ID, laddr, pAddr, 1, BX_RW);
BX_DBG_LIN_MEMORY_ACCESS(BX_CPU_ID, laddr, pAddr, 1, CPL, BX_READ, (Bit8u*) &data);
return data;
}
}
if (! IsCanonical(laddr)) {
BX_ERROR(("read_RMW_virtual_byte_64(): canonical failure"));
exception(int_number(s), 0);
}
access_read_linear(laddr, 1, CPL, BX_RW, (void *) &data);
return data;
}
Bit16u BX_CPP_AttrRegparmN(2)
BX_CPU_C::read_RMW_virtual_word_64(unsigned s, Bit64u offset)
{
BX_ASSERT(BX_CPU_THIS_PTR cpu_mode == BX_MODE_LONG_64);
Bit16u data;
BX_INSTR_MEM_DATA_ACCESS(BX_CPU_ID, s, offset, 2, BX_RW);
Bit64u laddr = BX_CPU_THIS_PTR get_laddr64(s, offset);
unsigned tlbIndex = BX_TLB_INDEX_OF(laddr, 1);
#if BX_SUPPORT_ALIGNMENT_CHECK && BX_CPU_LEVEL >= 4
Bit64u lpf = AlignedAccessLPFOf(laddr, (1 & BX_CPU_THIS_PTR alignment_check_mask));
#else
Bit64u lpf = LPFOf(laddr);
#endif
bx_TLB_entry *tlbEntry = &BX_CPU_THIS_PTR TLB.entry[tlbIndex];
if (tlbEntry->lpf == lpf) {
// See if the TLB entry privilege level allows us write access
// from this CPL.
if (! (tlbEntry->accessBits & (0x2 | USER_PL))) {
bx_hostpageaddr_t hostPageAddr = tlbEntry->hostPageAddr;
Bit32u pageOffset = PAGE_OFFSET(laddr);
bx_phy_address pAddr = tlbEntry->ppf | pageOffset;
Bit16u *hostAddr = (Bit16u*) (hostPageAddr | pageOffset);
pageWriteStampTable.decWriteStamp(pAddr, 2);
ReadHostWordFromLittleEndian(hostAddr, data);
BX_CPU_THIS_PTR address_xlation.pages = (bx_ptr_equiv_t) hostAddr;
BX_INSTR_LIN_ACCESS(BX_CPU_ID, laddr, pAddr, 2, BX_RW);
BX_DBG_LIN_MEMORY_ACCESS(BX_CPU_ID, laddr, pAddr, 2, CPL, BX_READ, (Bit8u*) &data);
return data;
}
}
if (! IsCanonical(laddr)) {
BX_ERROR(("read_RMW_virtual_word_64(): canonical failure"));
exception(int_number(s), 0);
}
#if BX_CPU_LEVEL >= 4 && BX_SUPPORT_ALIGNMENT_CHECK
if (BX_CPU_THIS_PTR alignment_check()) {
if (laddr & 1) {
BX_ERROR(("read_RMW_virtual_word_64(): #AC misaligned access"));
exception(BX_AC_EXCEPTION, 0);
}
}
#endif
if (! IsCanonical(laddr+1)) {
BX_ERROR(("read_RMW_virtual_word_64(): canonical failure"));
exception(int_number(s), 0);
}
access_read_linear(laddr, 2, CPL, BX_RW, (void *) &data);
return data;
}
Bit32u BX_CPP_AttrRegparmN(2)
BX_CPU_C::read_RMW_virtual_dword_64(unsigned s, Bit64u offset)
{
BX_ASSERT(BX_CPU_THIS_PTR cpu_mode == BX_MODE_LONG_64);
Bit32u data;
BX_INSTR_MEM_DATA_ACCESS(BX_CPU_ID, s, offset, 4, BX_RW);
Bit64u laddr = BX_CPU_THIS_PTR get_laddr64(s, offset);
unsigned tlbIndex = BX_TLB_INDEX_OF(laddr, 3);
#if BX_SUPPORT_ALIGNMENT_CHECK && BX_CPU_LEVEL >= 4
Bit64u lpf = AlignedAccessLPFOf(laddr, (3 & BX_CPU_THIS_PTR alignment_check_mask));
#else
Bit64u lpf = LPFOf(laddr);
#endif
bx_TLB_entry *tlbEntry = &BX_CPU_THIS_PTR TLB.entry[tlbIndex];
if (tlbEntry->lpf == lpf) {
// See if the TLB entry privilege level allows us write access
// from this CPL.
if (! (tlbEntry->accessBits & (0x2 | USER_PL))) {
bx_hostpageaddr_t hostPageAddr = tlbEntry->hostPageAddr;
Bit32u pageOffset = PAGE_OFFSET(laddr);
bx_phy_address pAddr = tlbEntry->ppf | pageOffset;
Bit32u *hostAddr = (Bit32u*) (hostPageAddr | pageOffset);
pageWriteStampTable.decWriteStamp(pAddr, 4);
ReadHostDWordFromLittleEndian(hostAddr, data);
BX_CPU_THIS_PTR address_xlation.pages = (bx_ptr_equiv_t) hostAddr;
BX_INSTR_LIN_ACCESS(BX_CPU_ID, laddr, pAddr, 4, BX_RW);
BX_DBG_LIN_MEMORY_ACCESS(BX_CPU_ID, laddr, pAddr, 4, CPL, BX_READ, (Bit8u*) &data);
return data;
}
}
if (! IsCanonical(laddr)) {
BX_ERROR(("read_RMW_virtual_dword_64(): canonical failure"));
exception(int_number(s), 0);
}
#if BX_CPU_LEVEL >= 4 && BX_SUPPORT_ALIGNMENT_CHECK
if (BX_CPU_THIS_PTR alignment_check()) {
if (laddr & 3) {
BX_ERROR(("read_RMW_virtual_dword_64(): #AC misaligned access"));
exception(BX_AC_EXCEPTION, 0);
}
}
#endif
if (! IsCanonical(laddr+3)) {
BX_ERROR(("read_RMW_virtual_dword_64(): canonical failure"));
exception(int_number(s), 0);
}
access_read_linear(laddr, 4, CPL, BX_RW, (void *) &data);
return data;
}
Bit64u BX_CPP_AttrRegparmN(2)
BX_CPU_C::read_RMW_virtual_qword_64(unsigned s, Bit64u offset)
{
BX_ASSERT(BX_CPU_THIS_PTR cpu_mode == BX_MODE_LONG_64);
Bit64u data;
BX_INSTR_MEM_DATA_ACCESS(BX_CPU_ID, s, offset, 8, BX_RW);
Bit64u laddr = BX_CPU_THIS_PTR get_laddr64(s, offset);
unsigned tlbIndex = BX_TLB_INDEX_OF(laddr, 7);
#if BX_SUPPORT_ALIGNMENT_CHECK && BX_CPU_LEVEL >= 4
Bit64u lpf = AlignedAccessLPFOf(laddr, (7 & BX_CPU_THIS_PTR alignment_check_mask));
#else
Bit64u lpf = LPFOf(laddr);
#endif
bx_TLB_entry *tlbEntry = &BX_CPU_THIS_PTR TLB.entry[tlbIndex];
if (tlbEntry->lpf == lpf) {
// See if the TLB entry privilege level allows us write access
// from this CPL.
if (! (tlbEntry->accessBits & (0x2 | USER_PL))) {
bx_hostpageaddr_t hostPageAddr = tlbEntry->hostPageAddr;
Bit32u pageOffset = PAGE_OFFSET(laddr);
bx_phy_address pAddr = tlbEntry->ppf | pageOffset;
Bit64u *hostAddr = (Bit64u*) (hostPageAddr | pageOffset);
pageWriteStampTable.decWriteStamp(pAddr, 8);
ReadHostQWordFromLittleEndian(hostAddr, data);
BX_CPU_THIS_PTR address_xlation.pages = (bx_ptr_equiv_t) hostAddr;
BX_INSTR_LIN_ACCESS(BX_CPU_ID, laddr, pAddr, 8, BX_RW);
BX_DBG_LIN_MEMORY_ACCESS(BX_CPU_ID, laddr, pAddr, 8, CPL, BX_READ, (Bit8u*) &data);
return data;
}
}
if (! IsCanonical(laddr)) {
BX_ERROR(("read_RMW_virtual_qword_64(): canonical failure"));
exception(int_number(s), 0);
}
#if BX_CPU_LEVEL >= 4 && BX_SUPPORT_ALIGNMENT_CHECK
if (BX_CPU_THIS_PTR alignment_check()) {
if (laddr & 7) {
BX_ERROR(("read_RMW_virtual_qword_64(): #AC misaligned access"));
exception(BX_AC_EXCEPTION, 0);
}
}
#endif
if (! IsCanonical(laddr+7)) {
BX_ERROR(("read_RMW_virtual_qword_64(): canonical failure"));
exception(int_number(s), 0);
}
access_read_linear(laddr, 8, CPL, BX_RW, (void *) &data);
return data;
}
void BX_CPU_C::write_new_stack_word_64(Bit64u laddr, unsigned curr_pl, Bit16u data)
{
bx_bool user = (curr_pl == 3);
unsigned tlbIndex = BX_TLB_INDEX_OF(laddr, 1);
#if BX_SUPPORT_ALIGNMENT_CHECK && BX_CPU_LEVEL >= 4
Bit64u lpf = AlignedAccessLPFOf(laddr, (1 & BX_CPU_THIS_PTR alignment_check_mask));
#else
Bit64u lpf = LPFOf(laddr);
#endif
bx_TLB_entry *tlbEntry = &BX_CPU_THIS_PTR TLB.entry[tlbIndex];
if (tlbEntry->lpf == lpf) {
// See if the TLB entry privilege level allows us write access
// from this CPL.
if (! (tlbEntry->accessBits & (0x2 | user))) {
bx_hostpageaddr_t hostPageAddr = tlbEntry->hostPageAddr;
Bit32u pageOffset = PAGE_OFFSET(laddr);
bx_phy_address pAddr = tlbEntry->ppf | pageOffset;
BX_INSTR_LIN_ACCESS(BX_CPU_ID, laddr, pAddr, 2, BX_WRITE);
BX_DBG_LIN_MEMORY_ACCESS(BX_CPU_ID, laddr, pAddr, 2, curr_pl, BX_WRITE, (Bit8u*) &data);
Bit16u *hostAddr = (Bit16u*) (hostPageAddr | pageOffset);
pageWriteStampTable.decWriteStamp(pAddr, 2);
WriteHostWordToLittleEndian(hostAddr, data);
return;
}
}
if (! IsCanonical(laddr)) {
BX_ERROR(("write_new_stack_word_64(): canonical failure"));
exception(BX_SS_EXCEPTION, 0);
}
#if BX_CPU_LEVEL >= 4 && BX_SUPPORT_ALIGNMENT_CHECK
if (BX_CPU_THIS_PTR alignment_check() && user) {
if (laddr & 1) {
BX_ERROR(("write_new_stack_word_64(): #AC misaligned access"));
exception(BX_AC_EXCEPTION, 0);
}
}
#endif
if (! IsCanonical(laddr+1)) {
BX_ERROR(("write_new_stack_word_64(): canonical failure"));
exception(BX_SS_EXCEPTION, 0);
}
access_write_linear(laddr, 2, curr_pl, (void *) &data);
}
void BX_CPU_C::write_new_stack_dword_64(Bit64u laddr, unsigned curr_pl, Bit32u data)
{
bx_bool user = (curr_pl == 3);
unsigned tlbIndex = BX_TLB_INDEX_OF(laddr, 3);
#if BX_SUPPORT_ALIGNMENT_CHECK && BX_CPU_LEVEL >= 4
Bit64u lpf = AlignedAccessLPFOf(laddr, (3 & BX_CPU_THIS_PTR alignment_check_mask));
#else
Bit64u lpf = LPFOf(laddr);
#endif
bx_TLB_entry *tlbEntry = &BX_CPU_THIS_PTR TLB.entry[tlbIndex];
if (tlbEntry->lpf == lpf) {
// See if the TLB entry privilege level allows us write access
// from this CPL.
if (! (tlbEntry->accessBits & (0x2 | user))) {
bx_hostpageaddr_t hostPageAddr = tlbEntry->hostPageAddr;
Bit32u pageOffset = PAGE_OFFSET(laddr);
bx_phy_address pAddr = tlbEntry->ppf | pageOffset;
BX_INSTR_LIN_ACCESS(BX_CPU_ID, laddr, pAddr, 4, BX_WRITE);
BX_DBG_LIN_MEMORY_ACCESS(BX_CPU_ID, laddr, pAddr, 4, curr_pl, BX_WRITE, (Bit8u*) &data);
Bit32u *hostAddr = (Bit32u*) (hostPageAddr | pageOffset);
pageWriteStampTable.decWriteStamp(pAddr, 4);
WriteHostDWordToLittleEndian(hostAddr, data);
return;
}
}
if (! IsCanonical(laddr)) {
BX_ERROR(("write_new_stack_dword_64(): canonical failure"));
exception(BX_SS_EXCEPTION, 0);
}
#if BX_CPU_LEVEL >= 4 && BX_SUPPORT_ALIGNMENT_CHECK
if (BX_CPU_THIS_PTR alignment_check() && user) {
if (laddr & 3) {
BX_ERROR(("write_new_stack_dword_64(): #AC misaligned access"));
exception(BX_AC_EXCEPTION, 0);
}
}
#endif
if (! IsCanonical(laddr+3)) {
BX_ERROR(("write_new_stack_dword_64(): canonical failure"));
exception(BX_SS_EXCEPTION, 0);
}
access_write_linear(laddr, 4, curr_pl, (void *) &data);
}
void BX_CPU_C::write_new_stack_qword_64(Bit64u laddr, unsigned curr_pl, Bit64u data)
{
bx_bool user = (curr_pl == 3);
unsigned tlbIndex = BX_TLB_INDEX_OF(laddr, 7);
#if BX_SUPPORT_ALIGNMENT_CHECK && BX_CPU_LEVEL >= 4
Bit64u lpf = AlignedAccessLPFOf(laddr, (7 & BX_CPU_THIS_PTR alignment_check_mask));
#else
Bit64u lpf = LPFOf(laddr);
#endif
bx_TLB_entry *tlbEntry = &BX_CPU_THIS_PTR TLB.entry[tlbIndex];
if (tlbEntry->lpf == lpf) {
// See if the TLB entry privilege level allows us write access
// from this CPL.
if (! (tlbEntry->accessBits & (0x2 | user))) {
bx_hostpageaddr_t hostPageAddr = tlbEntry->hostPageAddr;
Bit32u pageOffset = PAGE_OFFSET(laddr);
bx_phy_address pAddr = tlbEntry->ppf | pageOffset;
BX_INSTR_LIN_ACCESS(BX_CPU_ID, laddr, pAddr, 8, BX_WRITE);
BX_DBG_LIN_MEMORY_ACCESS(BX_CPU_ID, laddr, pAddr, 8, curr_pl, BX_WRITE, (Bit8u*) &data);
Bit64u *hostAddr = (Bit64u*) (hostPageAddr | pageOffset);
pageWriteStampTable.decWriteStamp(pAddr, 8);
WriteHostQWordToLittleEndian(hostAddr, data);
return;
}
}
if (! IsCanonical(laddr)) {
BX_ERROR(("write_new_stack_qword_64(): canonical failure"));
exception(BX_SS_EXCEPTION, 0);
}
#if BX_CPU_LEVEL >= 4 && BX_SUPPORT_ALIGNMENT_CHECK
if (BX_CPU_THIS_PTR alignment_check() && user) {
if (laddr & 7) {
BX_ERROR(("write_new_stack_qword_64(): #AC misaligned access"));
exception(BX_AC_EXCEPTION, 0);
}
}
#endif
if (! IsCanonical(laddr+7)) {
BX_ERROR(("write_new_stack_qword_64(): canonical failure"));
exception(BX_SS_EXCEPTION, 0);
}
access_write_linear(laddr, 8, curr_pl, (void *) &data);
}
#endif

422
simulators/bochs/cpu/aes.cc Executable file
View File

@ -0,0 +1,422 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2008-2010 Stanislav Shwartsman
// 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
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA B 02110-1301 USA
//
/////////////////////////////////////////////////////////////////////////
#define NEED_CPU_REG_SHORTCUTS 1
#include "bochs.h"
#include "cpu.h"
#define LOG_THIS BX_CPU_THIS_PTR
#if BX_CPU_LEVEL >= 6
//
// XMM - Byte Representation of a 128-bit AES State
//
// F E D C B A
// 1 1 1 1 1 1
// 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
// --+-+-+-+-+-+-+-+-+-+-+-+-+-+-+--
// P O N M L K J I H G F E D C B A
//
//
// XMM - Matrix Representation of a 128-bit AES State
//
// | A E I M | | S(0,0) S(0,1) S(0,2) S(0,3) | | S(0) S(4) S(8) S(C) |
// | B F J N | = | S(1,0) S(1,1) S(1,2) S(1,3) | = | S(1) S(5) S(9) S(D) |
// | C G K O | | S(2,0) S(2,1) S(2,2) S(2,3) | | S(2) S(6) S(A) S(E) |
// | D H L P | | S(3,0) S(3,1) S(2,3) S(3,3) | | S(3) S(7) S(B) S(F) |
//
//
// AES ShiftRows transformation
//
// | A E I M | | A E I M |
// | B F J N | => | F J N B |
// | C G K O | | K O C G |
// | D H L P | | P D H L |
//
BX_CPP_INLINE void AES_ShiftRows(BxPackedXmmRegister &state)
{
BxPackedXmmRegister tmp = state;
state.xmmubyte(0x0) = tmp.xmmubyte(0x0); // A => A
state.xmmubyte(0x1) = tmp.xmmubyte(0x5);
state.xmmubyte(0x2) = tmp.xmmubyte(0xA);
state.xmmubyte(0x3) = tmp.xmmubyte(0xF);
state.xmmubyte(0x4) = tmp.xmmubyte(0x4); // E => E
state.xmmubyte(0x5) = tmp.xmmubyte(0x9);
state.xmmubyte(0x6) = tmp.xmmubyte(0xE);
state.xmmubyte(0x7) = tmp.xmmubyte(0x3);
state.xmmubyte(0x8) = tmp.xmmubyte(0x8); // I => I
state.xmmubyte(0x9) = tmp.xmmubyte(0xD);
state.xmmubyte(0xA) = tmp.xmmubyte(0x2);
state.xmmubyte(0xB) = tmp.xmmubyte(0x7);
state.xmmubyte(0xC) = tmp.xmmubyte(0xC); // M => M
state.xmmubyte(0xD) = tmp.xmmubyte(0x1);
state.xmmubyte(0xE) = tmp.xmmubyte(0x6);
state.xmmubyte(0xF) = tmp.xmmubyte(0xB);
}
//
// AES InverseShiftRows transformation
//
// | A E I M | | A E I M |
// | B F J N | => | N B F J |
// | C G K O | | K O C G |
// | D H L P | | H L P D |
//
BX_CPP_INLINE void AES_InverseShiftRows(BxPackedXmmRegister &state)
{
BxPackedXmmRegister tmp = state;
state.xmmubyte(0x0) = tmp.xmmubyte(0x0); // A => A
state.xmmubyte(0x1) = tmp.xmmubyte(0xD);
state.xmmubyte(0x2) = tmp.xmmubyte(0xA);
state.xmmubyte(0x3) = tmp.xmmubyte(0x7);
state.xmmubyte(0x4) = tmp.xmmubyte(0x4); // E => E
state.xmmubyte(0x5) = tmp.xmmubyte(0x1);
state.xmmubyte(0x6) = tmp.xmmubyte(0xE);
state.xmmubyte(0x7) = tmp.xmmubyte(0xB);
state.xmmubyte(0x8) = tmp.xmmubyte(0x8); // I => I
state.xmmubyte(0x9) = tmp.xmmubyte(0x5);
state.xmmubyte(0xA) = tmp.xmmubyte(0x2);
state.xmmubyte(0xB) = tmp.xmmubyte(0xF);
state.xmmubyte(0xC) = tmp.xmmubyte(0xC); // M => M
state.xmmubyte(0xD) = tmp.xmmubyte(0x9);
state.xmmubyte(0xE) = tmp.xmmubyte(0x6);
state.xmmubyte(0xF) = tmp.xmmubyte(0x3);
}
static Bit8u sbox_transformation[256] = {
0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5,
0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,
0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0,
0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,
0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc,
0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a,
0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75,
0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0,
0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84,
0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b,
0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,
0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85,
0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8,
0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5,
0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2,
0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17,
0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,
0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88,
0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb,
0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c,
0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79,
0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9,
0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,
0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6,
0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a,
0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e,
0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e,
0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94,
0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68,
0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16
};
static Bit8u inverse_sbox_transformation[256] = {
0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38,
0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb,
0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87,
0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb,
0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d,
0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e,
0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2,
0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25,
0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16,
0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92,
0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda,
0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84,
0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a,
0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06,
0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02,
0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b,
0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea,
0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73,
0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85,
0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e,
0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89,
0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b,
0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20,
0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4,
0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31,
0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f,
0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d,
0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef,
0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0,
0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61,
0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26,
0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d
};
BX_CPP_INLINE void AES_SubstituteBytes(BxPackedXmmRegister &state)
{
for (int i=0; i<16; i++)
state.xmmubyte(i) = sbox_transformation[state.xmmubyte(i)];
}
BX_CPP_INLINE void AES_InverseSubstituteBytes(BxPackedXmmRegister &state)
{
for (int i=0; i<16; i++)
state.xmmubyte(i) = inverse_sbox_transformation[state.xmmubyte(i)];
}
/*
* Galois Field multiplication of a by b, modulo m.
* Just like arithmetic multiplication, except that additions and
* subtractions are replaced by XOR.
* The code was taken from: http://www.darkside.com.au/ice/index.html
*/
BX_CPP_INLINE unsigned gf_mul(unsigned a, unsigned b)
{
unsigned res = 0, m = 0x11b;
while (b) {
if (b & 1)
res ^= a;
a <<= 1;
b >>= 1;
if (a >= 256)
a ^= m;
}
return res;
}
#define AES_STATE(s,a,b) (s.xmmubyte((b)*4+(a)))
static void AES_MixColumns(BxPackedXmmRegister &state)
{
BxPackedXmmRegister tmp = state;
for(int j=0; j<4; j++) {
AES_STATE(state, 0, j) = gf_mul(0x2, AES_STATE(tmp, 0, j)) ^
gf_mul(0x3, AES_STATE(tmp, 1, j)) ^
AES_STATE(tmp, 2, j) ^
AES_STATE(tmp, 3, j);
AES_STATE(state, 1, j) = AES_STATE(tmp, 0, j) ^
gf_mul(0x2, AES_STATE(tmp, 1, j)) ^
gf_mul(0x3, AES_STATE(tmp, 2, j)) ^
AES_STATE(tmp, 3, j);
AES_STATE(state, 2, j) = AES_STATE(tmp, 0, j) ^
AES_STATE(tmp, 1, j) ^
gf_mul(0x2, AES_STATE(tmp, 2, j)) ^
gf_mul(0x3, AES_STATE(tmp, 3, j));
AES_STATE(state, 3, j) = gf_mul(0x3, AES_STATE(tmp, 0, j)) ^
AES_STATE(tmp, 1, j) ^
AES_STATE(tmp, 2, j) ^
gf_mul(0x2, AES_STATE(tmp, 3, j));
}
}
static void AES_InverseMixColumns(BxPackedXmmRegister &state)
{
BxPackedXmmRegister tmp = state;
for(int j=0; j<4; j++) {
AES_STATE(state, 0, j) = gf_mul(0xE, AES_STATE(tmp, 0, j)) ^
gf_mul(0xB, AES_STATE(tmp, 1, j)) ^
gf_mul(0xD, AES_STATE(tmp, 2, j)) ^
gf_mul(0x9, AES_STATE(tmp, 3, j));
AES_STATE(state, 1, j) = gf_mul(0x9, AES_STATE(tmp, 0, j)) ^
gf_mul(0xE, AES_STATE(tmp, 1, j)) ^
gf_mul(0xB, AES_STATE(tmp, 2, j)) ^
gf_mul(0xD, AES_STATE(tmp, 3, j));
AES_STATE(state, 2, j) = gf_mul(0xD, AES_STATE(tmp, 0, j)) ^
gf_mul(0x9, AES_STATE(tmp, 1, j)) ^
gf_mul(0xE, AES_STATE(tmp, 2, j)) ^
gf_mul(0xB, AES_STATE(tmp, 3, j));
AES_STATE(state, 3, j) = gf_mul(0xB, AES_STATE(tmp, 0, j)) ^
gf_mul(0xD, AES_STATE(tmp, 1, j)) ^
gf_mul(0x9, AES_STATE(tmp, 2, j)) ^
gf_mul(0xE, AES_STATE(tmp, 3, j));
}
}
BX_CPP_INLINE Bit32u AES_SubWord(Bit32u x)
{
Bit8u b0 = sbox_transformation[(x) & 0xff];
Bit8u b1 = sbox_transformation[(x>>8) & 0xff];
Bit8u b2 = sbox_transformation[(x>>16) & 0xff];
Bit8u b3 = sbox_transformation[(x>>24) & 0xff];
return b0 | ((Bit32u)(b1) << 8) |
((Bit32u)(b2) << 16) | ((Bit32u)(b3) << 24);
}
BX_CPP_INLINE Bit32u AES_RotWord(Bit32u x)
{
return (x >> 8) | (x << 24);
}
#endif
/* 66 0F 38 DB */
void BX_CPP_AttrRegparmN(1) BX_CPU_C::AESIMC_VdqWdqR(bxInstruction_c *i)
{
#if BX_CPU_LEVEL >= 6
BxPackedXmmRegister op = BX_READ_XMM_REG(i->rm());
AES_InverseMixColumns(op);
BX_WRITE_XMM_REG(i->nnn(), op);
#endif
}
/* 66 0F 38 DC */
void BX_CPP_AttrRegparmN(1) BX_CPU_C::AESENC_VdqWdqR(bxInstruction_c *i)
{
#if BX_CPU_LEVEL >= 6
BxPackedXmmRegister op1 = BX_READ_XMM_REG(i->nnn()), op2 = BX_READ_XMM_REG(i->rm());
AES_ShiftRows(op1);
AES_SubstituteBytes(op1);
AES_MixColumns(op1);
op1.xmm64u(0) ^= op2.xmm64u(0);
op1.xmm64u(1) ^= op2.xmm64u(1);
BX_WRITE_XMM_REG(i->nnn(), op1);
#endif
}
/* 66 0F 38 DD */
void BX_CPP_AttrRegparmN(1) BX_CPU_C::AESENCLAST_VdqWdqR(bxInstruction_c *i)
{
#if BX_CPU_LEVEL >= 6
BxPackedXmmRegister op1 = BX_READ_XMM_REG(i->nnn()), op2 = BX_READ_XMM_REG(i->rm());
AES_ShiftRows(op1);
AES_SubstituteBytes(op1);
op1.xmm64u(0) ^= op2.xmm64u(0);
op1.xmm64u(1) ^= op2.xmm64u(1);
BX_WRITE_XMM_REG(i->nnn(), op1);
#endif
}
/* 66 0F 38 DE */
void BX_CPP_AttrRegparmN(1) BX_CPU_C::AESDEC_VdqWdqR(bxInstruction_c *i)
{
#if BX_CPU_LEVEL >= 6
BxPackedXmmRegister op1 = BX_READ_XMM_REG(i->nnn()), op2 = BX_READ_XMM_REG(i->rm());
AES_InverseShiftRows(op1);
AES_InverseSubstituteBytes(op1);
AES_InverseMixColumns(op1);
op1.xmm64u(0) ^= op2.xmm64u(0);
op1.xmm64u(1) ^= op2.xmm64u(1);
BX_WRITE_XMM_REG(i->nnn(), op1);
#endif
}
/* 66 0F 38 DF */
void BX_CPP_AttrRegparmN(1) BX_CPU_C::AESDECLAST_VdqWdqR(bxInstruction_c *i)
{
#if BX_CPU_LEVEL >= 6
BxPackedXmmRegister op1 = BX_READ_XMM_REG(i->nnn()), op2 = BX_READ_XMM_REG(i->rm());
AES_InverseShiftRows(op1);
AES_InverseSubstituteBytes(op1);
op1.xmm64u(0) ^= op2.xmm64u(0);
op1.xmm64u(1) ^= op2.xmm64u(1);
BX_WRITE_XMM_REG(i->nnn(), op1);
#endif
}
/* 66 0F 3A DF */
void BX_CPP_AttrRegparmN(1) BX_CPU_C::AESKEYGENASSIST_VdqWdqIbR(bxInstruction_c *i)
{
#if BX_CPU_LEVEL >= 6
BxPackedXmmRegister op = BX_READ_XMM_REG(i->rm()), result;
Bit32u rcon32 = i->Ib();
result.xmm32u(0) = AES_SubWord(op.xmm32u(1));
result.xmm32u(1) = AES_RotWord(result.xmm32u(0)) ^ rcon32;
result.xmm32u(2) = AES_SubWord(op.xmm32u(3));
result.xmm32u(3) = AES_RotWord(result.xmm32u(2)) ^ rcon32;
BX_WRITE_XMM_REG(i->nnn(), result);
#endif
}
/* 66 0F 3A 44 */
void BX_CPP_AttrRegparmN(1) BX_CPU_C::PCLMULQDQ_VdqWdqIbR(bxInstruction_c *i)
{
#if BX_CPU_LEVEL >= 6
BxPackedXmmRegister op1 = BX_READ_XMM_REG(i->nnn()), op2 = BX_READ_XMM_REG(i->rm());
BxPackedXmmRegister r, a;
Bit8u imm8 = i->Ib();
//
// Initialize sources for Carry Less Multiplication [R = A CLMUL B]
//
// A determined by imm8[0]
a.xmm64u(0) = op1.xmm64u(imm8 & 1);
a.xmm64u(1) = 0;
// B determined by imm8[4]
Bit64u b = op2.xmm64u((imm8 >> 4) & 1);
r.xmm64u(0) = 0;
r.xmm64u(1) = 0;
for (int n = 0; b && n < 64; n++) {
if (b & 1) {
r.xmm64u(0) ^= a.xmm64u(0);
r.xmm64u(1) ^= a.xmm64u(1);
}
a.xmm64u(1) = (a.xmm64u(1) << 1) | (a.xmm64u(0) >> 63);
a.xmm64u(0) <<= 1;
b >>= 1;
}
BX_WRITE_XMM_REG(i->nnn(), r);
#endif
}

1188
simulators/bochs/cpu/apic.cc Normal file

File diff suppressed because it is too large Load Diff

169
simulators/bochs/cpu/apic.h Normal file
View File

@ -0,0 +1,169 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2002-2009 Zwane Mwaikambo, Stanislav Shwartsman
//
// 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
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
//
/////////////////////////////////////////////////////////////////////////
#ifndef BX_CPU_APIC_H
#define BX_CPU_APIC_H 1
#if BX_SUPPORT_APIC
#define APIC_LEVEL_TRIGGERED 1
#define APIC_EDGE_TRIGGERED 0
#define BX_LAPIC_BASE_ADDR 0xfee00000 // default Local APIC address
#define BX_NUM_LOCAL_APICS BX_SMP_PROCESSORS
#define BX_LAPIC_MAX_INTS 256
#define BX_APIC_GLOBALLY_DISABLED 0
#define BX_APIC_STATE_INVALID 1
#define BX_APIC_XAPIC_MODE 2
#define BX_APIC_X2APIC_MODE 3
typedef Bit32u apic_dest_t; /* same definition in ioapic.h */
class BOCHSAPI bx_local_apic_c : public logfunctions
{
bx_phy_address base_addr;
unsigned mode;
bx_bool xapic;
Bit32u apic_id; // 4 bit in legacy mode, 8 bit in XAPIC mode
// 32 bit in X2APIC mode
Bit32u apic_version_id;
bx_bool software_enabled;
Bit8u spurious_vector;
bx_bool focus_disable;
Bit32u task_priority; // Task priority (TPR)
Bit32u ldr; // Logical destination (LDR)
Bit32u dest_format; // Destination format (DFR)
// ISR=in-service register. When an IRR bit is cleared, the corresponding
// bit in ISR is set.
Bit8u isr[BX_LAPIC_MAX_INTS];
// TMR=trigger mode register. Cleared for edge-triggered interrupts
// and set for level-triggered interrupts. If set, local APIC must send
// EOI message to all other APICs.
Bit8u tmr[BX_LAPIC_MAX_INTS];
// IRR=interrupt request register. When an interrupt is triggered by
// the I/O APIC or another processor, it sets a bit in irr. The bit is
// cleared when the interrupt is acknowledged by the processor.
Bit8u irr[BX_LAPIC_MAX_INTS];
#define APIC_ERR_ILLEGAL_ADDR 0x80
#define APIC_ERR_RX_ILLEGAL_VEC 0x40
#define APIC_ERR_TX_ILLEGAL_VEC 0x20
#define X2APIC_ERR_REDIRECTIBLE_IPI 0x08
#define APIC_ERR_RX_ACCEPT_ERR 0x08
#define APIC_ERR_TX_ACCEPT_ERR 0x04
#define APIC_ERR_RX_CHECKSUM 0x02
#define APIC_ERR_TX_CHECKSUM 0x01
// Error status Register (ESR)
Bit32u error_status, shadow_error_status;
Bit32u icr_hi; // Interrupt command register (ICR)
Bit32u icr_lo;
#define APIC_LVT_ENTRIES 6
Bit32u lvt[APIC_LVT_ENTRIES];
#define APIC_LVT_TIMER 0
#define APIC_LVT_THERMAL 1
#define APIC_LVT_PERFMON 2
#define APIC_LVT_LINT0 3
#define APIC_LVT_LINT1 4
#define APIC_LVT_ERROR 5
Bit32u timer_initial; // Initial timer count
Bit32u timer_current; // current timer count
Bit32u timer_divconf; // Timer divide configuration register
Bit32u timer_divide_factor;
// Internal timer state, not accessible from bus
bx_bool timer_active;
int timer_handle;
Bit64u ticksInitial;
/* APIC delivery modes */
#define APIC_DM_FIXED 0
#define APIC_DM_LOWPRI 1
#define APIC_DM_SMI 2
/* RESERVED 3 */
#define APIC_DM_NMI 4
#define APIC_DM_INIT 5
#define APIC_DM_SIPI 6
#define APIC_DM_EXTINT 7
BX_CPU_C *cpu;
public:
bx_bool INTR;
bx_local_apic_c(BX_CPU_C *cpu, unsigned id);
~bx_local_apic_c() { }
void reset(unsigned type);
bx_phy_address get_base(void) const { return base_addr; }
void set_base(bx_phy_address newbase);
Bit32u get_id() const { return apic_id; }
bx_bool is_xapic() const { return xapic; }
bx_bool is_selected(bx_phy_address addr);
void read(bx_phy_address addr, void *data, unsigned len);
void write(bx_phy_address addr, void *data, unsigned len);
void write_aligned(bx_phy_address addr, Bit32u data);
Bit32u read_aligned(bx_phy_address address);
#if BX_SUPPORT_X2APIC
bx_bool read_x2apic(unsigned index, Bit64u *msr);
bx_bool write_x2apic(unsigned index, Bit64u msr);
#endif
// on local APIC, trigger means raise the CPU's INTR line. For now
// I also have to raise pc_system.INTR but that should be replaced
// with the cpu-specific INTR signals.
void trigger_irq(Bit8u vector, unsigned trigger_mode, bx_bool bypass_irr_isr = 0);
void untrigger_irq(Bit8u vector, unsigned trigger_mode);
Bit8u acknowledge_int(void); // only the local CPU should call this
int highest_priority_int(Bit8u *array);
void receive_EOI(Bit32u value);
void send_ipi(apic_dest_t dest, Bit32u lo_cmd);
void write_spurious_interrupt_register(Bit32u value);
void service_local_apic(void);
void print_status(void);
bx_bool match_logical_addr(apic_dest_t address);
bx_bool deliver(Bit8u vector, Bit8u delivery_mode, Bit8u trig_mode);
Bit8u get_tpr(void) { return task_priority; }
void set_tpr(Bit8u tpr);
Bit8u get_ppr(void);
Bit8u get_apr(void);
bx_bool is_focus(Bit8u vector);
static void periodic_smf(void *);
void periodic(void);
void set_divide_configuration(Bit32u value);
void set_initial_timer_count(Bit32u value);
void startup_msg(Bit8u vector);
void register_state(bx_param_c *parent);
};
int apic_bus_deliver_lowest_priority(Bit8u vector, apic_dest_t dest, bx_bool trig_mode, bx_bool broadcast);
int apic_bus_deliver_interrupt(Bit8u vector, apic_dest_t dest, Bit8u delivery_mode, bx_bool logical_dest, bx_bool level, bx_bool trig_mode);
int apic_bus_broadcast_interrupt(Bit8u vector, Bit8u delivery_mode, bx_bool trig_mode, int exclude_cpu);
#endif // if BX_SUPPORT_APIC
#endif

View File

@ -0,0 +1,497 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2001-2009 The Bochs Project
//
// 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
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA B 02110-1301 USA
/////////////////////////////////////////////////////////////////////////
#define NEED_CPU_REG_SHORTCUTS 1
#include "bochs.h"
#include "cpu.h"
#define LOG_THIS BX_CPU_THIS_PTR
void BX_CPP_AttrRegparmN(1) BX_CPU_C::INC_RX(bxInstruction_c *i)
{
Bit16u rx = ++BX_READ_16BIT_REG(i->rm());
SET_FLAGS_OSZAPC_INC_16(rx);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::DEC_RX(bxInstruction_c *i)
{
Bit16u rx = --BX_READ_16BIT_REG(i->rm());
SET_FLAGS_OSZAPC_DEC_16(rx);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::ADD_EwGwM(bxInstruction_c *i)
{
Bit16u op1_16, op2_16, sum_16;
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
op1_16 = read_RMW_virtual_word(i->seg(), eaddr);
op2_16 = BX_READ_16BIT_REG(i->nnn());
sum_16 = op1_16 + op2_16;
write_RMW_virtual_word(sum_16);
SET_FLAGS_OSZAPC_ADD_16(op1_16, op2_16, sum_16);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::ADD_GwEwR(bxInstruction_c *i)
{
Bit16u op1_16, op2_16, sum_16;
op1_16 = BX_READ_16BIT_REG(i->nnn());
op2_16 = BX_READ_16BIT_REG(i->rm());
sum_16 = op1_16 + op2_16;
BX_WRITE_16BIT_REG(i->nnn(), sum_16);
SET_FLAGS_OSZAPC_ADD_16(op1_16, op2_16, sum_16);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::ADD_AXIw(bxInstruction_c *i)
{
Bit16u op1_16, op2_16, sum_16;
op1_16 = AX;
op2_16 = i->Iw();
sum_16 = op1_16 + op2_16;
AX = sum_16;
SET_FLAGS_OSZAPC_ADD_16(op1_16, op2_16, sum_16);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::ADC_EwGwM(bxInstruction_c *i)
{
Bit16u op1_16, op2_16, sum_16;
bx_bool temp_CF = getB_CF();
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
op1_16 = read_RMW_virtual_word(i->seg(), eaddr);
op2_16 = BX_READ_16BIT_REG(i->nnn());
sum_16 = op1_16 + op2_16 + temp_CF;
write_RMW_virtual_word(sum_16);
SET_FLAGS_OSZAPC_16(op1_16, op2_16, sum_16, BX_LF_INSTR_ADD_ADC16(temp_CF));
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::ADC_GwEwR(bxInstruction_c *i)
{
Bit16u op1_16, op2_16, sum_16;
bx_bool temp_CF = getB_CF();
op1_16 = BX_READ_16BIT_REG(i->nnn());
op2_16 = BX_READ_16BIT_REG(i->rm());
sum_16 = op1_16 + op2_16 + temp_CF;
BX_WRITE_16BIT_REG(i->nnn(), sum_16);
SET_FLAGS_OSZAPC_16(op1_16, op2_16, sum_16, BX_LF_INSTR_ADD_ADC16(temp_CF));
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::ADC_AXIw(bxInstruction_c *i)
{
Bit16u op1_16, op2_16, sum_16;
bx_bool temp_CF = getB_CF();
op1_16 = AX;
op2_16 = i->Iw();
sum_16 = op1_16 + op2_16 + temp_CF;
AX = sum_16;
SET_FLAGS_OSZAPC_16(op1_16, op2_16, sum_16, BX_LF_INSTR_ADD_ADC16(temp_CF));
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SBB_EwGwM(bxInstruction_c *i)
{
Bit16u op1_16, op2_16, diff_16;
bx_bool temp_CF = getB_CF();
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
op1_16 = read_RMW_virtual_word(i->seg(), eaddr);
op2_16 = BX_READ_16BIT_REG(i->nnn());
diff_16 = op1_16 - (op2_16 + temp_CF);
write_RMW_virtual_word(diff_16);
SET_FLAGS_OSZAPC_16(op1_16, op2_16, diff_16, BX_LF_INSTR_SUB_SBB16(temp_CF));
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SBB_GwEwR(bxInstruction_c *i)
{
Bit16u op1_16, op2_16, diff_16;
bx_bool temp_CF = getB_CF();
op1_16 = BX_READ_16BIT_REG(i->nnn());
op2_16 = BX_READ_16BIT_REG(i->rm());
diff_16 = op1_16 - (op2_16 + temp_CF);
BX_WRITE_16BIT_REG(i->nnn(), diff_16);
SET_FLAGS_OSZAPC_16(op1_16, op2_16, diff_16, BX_LF_INSTR_SUB_SBB16(temp_CF));
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SBB_AXIw(bxInstruction_c *i)
{
bx_bool temp_CF = getB_CF();
Bit16u op1_16, op2_16, diff_16;
op1_16 = AX;
op2_16 = i->Iw();
diff_16 = op1_16 - (op2_16 + temp_CF);
AX = diff_16;
SET_FLAGS_OSZAPC_16(op1_16, op2_16, diff_16, BX_LF_INSTR_SUB_SBB16(temp_CF));
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SBB_EwIwM(bxInstruction_c *i)
{
bx_bool temp_CF = getB_CF();
Bit16u op1_16, op2_16 = i->Iw(), diff_16;
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
op1_16 = read_RMW_virtual_word(i->seg(), eaddr);
diff_16 = op1_16 - (op2_16 + temp_CF);
write_RMW_virtual_word(diff_16);
SET_FLAGS_OSZAPC_16(op1_16, op2_16, diff_16, BX_LF_INSTR_SUB_SBB16(temp_CF));
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SBB_EwIwR(bxInstruction_c *i)
{
bx_bool temp_CF = getB_CF();
Bit16u op1_16, op2_16 = i->Iw(), diff_16;
op1_16 = BX_READ_16BIT_REG(i->rm());
diff_16 = op1_16 - (op2_16 + temp_CF);
BX_WRITE_16BIT_REG(i->rm(), diff_16);
SET_FLAGS_OSZAPC_16(op1_16, op2_16, diff_16, BX_LF_INSTR_SUB_SBB16(temp_CF));
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SUB_EwGwM(bxInstruction_c *i)
{
Bit16u op1_16, op2_16, diff_16;
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
op1_16 = read_RMW_virtual_word(i->seg(), eaddr);
op2_16 = BX_READ_16BIT_REG(i->nnn());
diff_16 = op1_16 - op2_16;
write_RMW_virtual_word(diff_16);
SET_FLAGS_OSZAPC_SUB_16(op1_16, op2_16, diff_16);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SUB_GwEwR(bxInstruction_c *i)
{
Bit16u op1_16, op2_16, diff_16;
op1_16 = BX_READ_16BIT_REG(i->nnn());
op2_16 = BX_READ_16BIT_REG(i->rm());
diff_16 = op1_16 - op2_16;
BX_WRITE_16BIT_REG(i->nnn(), diff_16);
SET_FLAGS_OSZAPC_SUB_16(op1_16, op2_16, diff_16);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SUB_AXIw(bxInstruction_c *i)
{
Bit16u op1_16, op2_16, diff_16;
op1_16 = AX;
op2_16 = i->Iw();
diff_16 = op1_16 - op2_16;
AX = diff_16;
SET_FLAGS_OSZAPC_SUB_16(op1_16, op2_16, diff_16);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMP_EwGwM(bxInstruction_c *i)
{
Bit16u op1_16, op2_16, diff_16;
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
op1_16 = read_virtual_word(i->seg(), eaddr);
op2_16 = BX_READ_16BIT_REG(i->nnn());
diff_16 = op1_16 - op2_16;
SET_FLAGS_OSZAPC_SUB_16(op1_16, op2_16, diff_16);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMP_GwEwR(bxInstruction_c *i)
{
Bit16u op1_16, op2_16, diff_16;
op1_16 = BX_READ_16BIT_REG(i->nnn());
op2_16 = BX_READ_16BIT_REG(i->rm());
diff_16 = op1_16 - op2_16;
SET_FLAGS_OSZAPC_SUB_16(op1_16, op2_16, diff_16);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMP_AXIw(bxInstruction_c *i)
{
Bit16u op1_16, op2_16, diff_16;
op1_16 = AX;
op2_16 = i->Iw();
diff_16 = op1_16 - op2_16;
SET_FLAGS_OSZAPC_SUB_16(op1_16, op2_16, diff_16);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CBW(bxInstruction_c *i)
{
/* CBW: no flags are effected */
AX = (Bit8s) AL;
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CWD(bxInstruction_c *i)
{
/* CWD: no flags are affected */
if (AX & 0x8000) {
DX = 0xFFFF;
}
else {
DX = 0x0000;
}
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::XADD_EwGwM(bxInstruction_c *i)
{
Bit16u op1_16, op2_16, sum_16;
/* XADD dst(r/m), src(r)
* temp <-- src + dst | sum = op2 + op1
* src <-- dst | op2 = op1
* dst <-- tmp | op1 = sum
*/
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
op1_16 = read_RMW_virtual_word(i->seg(), eaddr);
op2_16 = BX_READ_16BIT_REG(i->nnn());
sum_16 = op1_16 + op2_16;
write_RMW_virtual_word(sum_16);
/* and write destination into source */
BX_WRITE_16BIT_REG(i->nnn(), op1_16);
SET_FLAGS_OSZAPC_ADD_16(op1_16, op2_16, sum_16);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::XADD_EwGwR(bxInstruction_c *i)
{
Bit16u op1_16, op2_16, sum_16;
/* XADD dst(r/m), src(r)
* temp <-- src + dst | sum = op2 + op1
* src <-- dst | op2 = op1
* dst <-- tmp | op1 = sum
*/
op1_16 = BX_READ_16BIT_REG(i->rm());
op2_16 = BX_READ_16BIT_REG(i->nnn());
sum_16 = op1_16 + op2_16;
// and write destination into source
// Note: if both op1 & op2 are registers, the last one written
// should be the sum, as op1 & op2 may be the same register.
// For example: XADD AL, AL
BX_WRITE_16BIT_REG(i->nnn(), op1_16);
BX_WRITE_16BIT_REG(i->rm(), sum_16);
SET_FLAGS_OSZAPC_ADD_16(op1_16, op2_16, sum_16);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::ADD_EwIwM(bxInstruction_c *i)
{
Bit16u op1_16, op2_16 = i->Iw(), sum_16;
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
op1_16 = read_RMW_virtual_word(i->seg(), eaddr);
sum_16 = op1_16 + op2_16;
write_RMW_virtual_word(sum_16);
SET_FLAGS_OSZAPC_ADD_16(op1_16, op2_16, sum_16);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::ADD_EwIwR(bxInstruction_c *i)
{
Bit16u op1_16, op2_16 = i->Iw(), sum_16;
op1_16 = BX_READ_16BIT_REG(i->rm());
sum_16 = op1_16 + op2_16;
BX_WRITE_16BIT_REG(i->rm(), sum_16);
SET_FLAGS_OSZAPC_ADD_16(op1_16, op2_16, sum_16);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::ADC_EwIwM(bxInstruction_c *i)
{
bx_bool temp_CF = getB_CF();
Bit16u op1_16, op2_16 = i->Iw(), sum_16;
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
op1_16 = read_RMW_virtual_word(i->seg(), eaddr);
sum_16 = op1_16 + op2_16 + temp_CF;
write_RMW_virtual_word(sum_16);
SET_FLAGS_OSZAPC_16(op1_16, op2_16, sum_16, BX_LF_INSTR_ADD_ADC16(temp_CF));
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::ADC_EwIwR(bxInstruction_c *i)
{
bx_bool temp_CF = getB_CF();
Bit16u op1_16, op2_16 = i->Iw(), sum_16;
op1_16 = BX_READ_16BIT_REG(i->rm());
sum_16 = op1_16 + op2_16 + temp_CF;
BX_WRITE_16BIT_REG(i->rm(), sum_16);
SET_FLAGS_OSZAPC_16(op1_16, op2_16, sum_16, BX_LF_INSTR_ADD_ADC16(temp_CF));
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SUB_EwIwM(bxInstruction_c *i)
{
Bit16u op1_16, op2_16 = i->Iw(), diff_16;
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
op1_16 = read_RMW_virtual_word(i->seg(), eaddr);
diff_16 = op1_16 - op2_16;
write_RMW_virtual_word(diff_16);
SET_FLAGS_OSZAPC_SUB_16(op1_16, op2_16, diff_16);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SUB_EwIwR(bxInstruction_c *i)
{
Bit16u op1_16, op2_16 = i->Iw(), diff_16;
op1_16 = BX_READ_16BIT_REG(i->rm());
diff_16 = op1_16 - op2_16;
BX_WRITE_16BIT_REG(i->rm(), diff_16);
SET_FLAGS_OSZAPC_SUB_16(op1_16, op2_16, diff_16);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMP_EwIwM(bxInstruction_c *i)
{
Bit16u op1_16, op2_16 = i->Iw(), diff_16;
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
op1_16 = read_virtual_word(i->seg(), eaddr);
diff_16 = op1_16 - op2_16;
SET_FLAGS_OSZAPC_SUB_16(op1_16, op2_16, diff_16);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMP_EwIwR(bxInstruction_c *i)
{
Bit16u op1_16, op2_16 = i->Iw(), diff_16;
op1_16 = BX_READ_16BIT_REG(i->rm());
diff_16 = op1_16 - op2_16;
SET_FLAGS_OSZAPC_SUB_16(op1_16, op2_16, diff_16);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::NEG_EwM(bxInstruction_c *i)
{
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
Bit16u op1_16 = read_RMW_virtual_word(i->seg(), eaddr);
op1_16 = - (Bit16s)(op1_16);
write_RMW_virtual_word(op1_16);
SET_FLAGS_OSZAPC_RESULT_16(op1_16, BX_LF_INSTR_NEG16);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::NEG_EwR(bxInstruction_c *i)
{
Bit16u op1_16 = BX_READ_16BIT_REG(i->rm());
op1_16 = - (Bit16s)(op1_16);
BX_WRITE_16BIT_REG(i->rm(), op1_16);
SET_FLAGS_OSZAPC_RESULT_16(op1_16, BX_LF_INSTR_NEG16);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::INC_EwM(bxInstruction_c *i)
{
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
Bit16u op1_16 = read_RMW_virtual_word(i->seg(), eaddr);
op1_16++;
write_RMW_virtual_word(op1_16);
SET_FLAGS_OSZAPC_INC_16(op1_16);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::DEC_EwM(bxInstruction_c *i)
{
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
Bit16u op1_16 = read_RMW_virtual_word(i->seg(), eaddr);
op1_16--;
write_RMW_virtual_word(op1_16);
SET_FLAGS_OSZAPC_DEC_16(op1_16);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMPXCHG_EwGwM(bxInstruction_c *i)
{
Bit16u op1_16, op2_16, diff_16;
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
op1_16 = read_RMW_virtual_word(i->seg(), eaddr);
diff_16 = AX - op1_16;
SET_FLAGS_OSZAPC_SUB_16(AX, op1_16, diff_16);
if (diff_16 == 0) { // if accumulator == dest
// dest <-- src
op2_16 = BX_READ_16BIT_REG(i->nnn());
write_RMW_virtual_word(op2_16);
}
else {
// accumulator <-- dest
AX = op1_16;
}
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMPXCHG_EwGwR(bxInstruction_c *i)
{
Bit16u op1_16, op2_16, diff_16;
op1_16 = BX_READ_16BIT_REG(i->rm());
diff_16 = AX - op1_16;
SET_FLAGS_OSZAPC_SUB_16(AX, op1_16, diff_16);
if (diff_16 == 0) { // if accumulator == dest
// dest <-- src
op2_16 = BX_READ_16BIT_REG(i->nnn());
BX_WRITE_16BIT_REG(i->rm(), op2_16);
}
else {
// accumulator <-- dest
AX = op1_16;
}
}

View File

@ -0,0 +1,570 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2001-2009 The Bochs Project
//
// 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
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA B 02110-1301 USA
/////////////////////////////////////////////////////////////////////////
#define NEED_CPU_REG_SHORTCUTS 1
#include "bochs.h"
#include "cpu.h"
#define LOG_THIS BX_CPU_THIS_PTR
#if BX_SUPPORT_X86_64==0
// Make life easier for merging cpu64 and cpu code.
#define RAX EAX
#define RDX EDX
#endif
void BX_CPP_AttrRegparmN(1) BX_CPU_C::INC_ERX(bxInstruction_c *i)
{
Bit32u erx = ++BX_READ_32BIT_REG(i->rm());
SET_FLAGS_OSZAPC_INC_32(erx);
BX_CLEAR_64BIT_HIGH(i->rm());
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::DEC_ERX(bxInstruction_c *i)
{
Bit32u erx = --BX_READ_32BIT_REG(i->rm());
SET_FLAGS_OSZAPC_DEC_32(erx);
BX_CLEAR_64BIT_HIGH(i->rm());
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::ADD_EdGdM(bxInstruction_c *i)
{
Bit32u op1_32, op2_32, sum_32;
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
op1_32 = read_RMW_virtual_dword(i->seg(), eaddr);
op2_32 = BX_READ_32BIT_REG(i->nnn());
sum_32 = op1_32 + op2_32;
write_RMW_virtual_dword(sum_32);
SET_FLAGS_OSZAPC_ADD_32(op1_32, op2_32, sum_32);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::ADD_GdEdR(bxInstruction_c *i)
{
Bit32u op1_32, op2_32, sum_32;
op1_32 = BX_READ_32BIT_REG(i->nnn());
op2_32 = BX_READ_32BIT_REG(i->rm());
sum_32 = op1_32 + op2_32;
BX_WRITE_32BIT_REGZ(i->nnn(), sum_32);
SET_FLAGS_OSZAPC_ADD_32(op1_32, op2_32, sum_32);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::ADD_EAXId(bxInstruction_c *i)
{
Bit32u op1_32, op2_32 = i->Id(), sum_32;
op1_32 = EAX;
sum_32 = op1_32 + op2_32;
RAX = sum_32;
SET_FLAGS_OSZAPC_ADD_32(op1_32, op2_32, sum_32);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::ADC_EdGdM(bxInstruction_c *i)
{
bx_bool temp_CF = getB_CF();
Bit32u op1_32, op2_32, sum_32;
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
op1_32 = read_RMW_virtual_dword(i->seg(), eaddr);
op2_32 = BX_READ_32BIT_REG(i->nnn());
sum_32 = op1_32 + op2_32 + temp_CF;
write_RMW_virtual_dword(sum_32);
SET_FLAGS_OSZAPC_32(op1_32, op2_32, sum_32, BX_LF_INSTR_ADD_ADC32(temp_CF));
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::ADC_GdEdR(bxInstruction_c *i)
{
bx_bool temp_CF = getB_CF();
Bit32u op1_32, op2_32, sum_32;
op1_32 = BX_READ_32BIT_REG(i->nnn());
op2_32 = BX_READ_32BIT_REG(i->rm());
sum_32 = op1_32 + op2_32 + temp_CF;
BX_WRITE_32BIT_REGZ(i->nnn(), sum_32);
SET_FLAGS_OSZAPC_32(op1_32, op2_32, sum_32, BX_LF_INSTR_ADD_ADC32(temp_CF));
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::ADC_EAXId(bxInstruction_c *i)
{
bx_bool temp_CF = getB_CF();
Bit32u op1_32, op2_32 = i->Id(), sum_32;
op1_32 = EAX;
sum_32 = op1_32 + op2_32 + temp_CF;
RAX = sum_32;
SET_FLAGS_OSZAPC_32(op1_32, op2_32, sum_32, BX_LF_INSTR_ADD_ADC32(temp_CF));
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SBB_EdGdM(bxInstruction_c *i)
{
bx_bool temp_CF = getB_CF();
Bit32u op1_32, op2_32, diff_32;
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
op1_32 = read_RMW_virtual_dword(i->seg(), eaddr);
op2_32 = BX_READ_32BIT_REG(i->nnn());
diff_32 = op1_32 - (op2_32 + temp_CF);
write_RMW_virtual_dword(diff_32);
SET_FLAGS_OSZAPC_32(op1_32, op2_32, diff_32, BX_LF_INSTR_SUB_SBB32(temp_CF));
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SBB_GdEdR(bxInstruction_c *i)
{
bx_bool temp_CF = getB_CF();
Bit32u op1_32, op2_32, diff_32;
op1_32 = BX_READ_32BIT_REG(i->nnn());
op2_32 = BX_READ_32BIT_REG(i->rm());
diff_32 = op1_32 - (op2_32 + temp_CF);
BX_WRITE_32BIT_REGZ(i->nnn(), diff_32);
SET_FLAGS_OSZAPC_32(op1_32, op2_32, diff_32, BX_LF_INSTR_SUB_SBB32(temp_CF));
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SBB_EAXId(bxInstruction_c *i)
{
bx_bool temp_CF = getB_CF();
Bit32u op1_32, op2_32, diff_32;
op1_32 = EAX;
op2_32 = i->Id();
diff_32 = op1_32 - (op2_32 + temp_CF);
RAX = diff_32;
SET_FLAGS_OSZAPC_32(op1_32, op2_32, diff_32, BX_LF_INSTR_SUB_SBB32(temp_CF));
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SBB_EdIdM(bxInstruction_c *i)
{
bx_bool temp_CF = getB_CF();
Bit32u op1_32, op2_32 = i->Id(), diff_32;
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
op1_32 = read_RMW_virtual_dword(i->seg(), eaddr);
diff_32 = op1_32 - (op2_32 + temp_CF);
write_RMW_virtual_dword(diff_32);
SET_FLAGS_OSZAPC_32(op1_32, op2_32, diff_32, BX_LF_INSTR_SUB_SBB32(temp_CF));
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SBB_EdIdR(bxInstruction_c *i)
{
bx_bool temp_CF = getB_CF();
Bit32u op1_32, op2_32 = i->Id(), diff_32;
op1_32 = BX_READ_32BIT_REG(i->rm());
diff_32 = op1_32 - (op2_32 + temp_CF);
BX_WRITE_32BIT_REGZ(i->rm(), diff_32);
SET_FLAGS_OSZAPC_32(op1_32, op2_32, diff_32, BX_LF_INSTR_SUB_SBB32(temp_CF));
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SUB_EdGdM(bxInstruction_c *i)
{
Bit32u op1_32, op2_32, diff_32;
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
op1_32 = read_RMW_virtual_dword(i->seg(), eaddr);
op2_32 = BX_READ_32BIT_REG(i->nnn());
diff_32 = op1_32 - op2_32;
write_RMW_virtual_dword(diff_32);
SET_FLAGS_OSZAPC_SUB_32(op1_32, op2_32, diff_32);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SUB_GdEdR(bxInstruction_c *i)
{
Bit32u op1_32, op2_32, diff_32;
op1_32 = BX_READ_32BIT_REG(i->nnn());
op2_32 = BX_READ_32BIT_REG(i->rm());
diff_32 = op1_32 - op2_32;
BX_WRITE_32BIT_REGZ(i->nnn(), diff_32);
SET_FLAGS_OSZAPC_SUB_32(op1_32, op2_32, diff_32);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SUB_EAXId(bxInstruction_c *i)
{
Bit32u op1_32, op2_32, diff_32;
op1_32 = EAX;
op2_32 = i->Id();
diff_32 = op1_32 - op2_32;
RAX = diff_32;
SET_FLAGS_OSZAPC_SUB_32(op1_32, op2_32, diff_32);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMP_EdGdM(bxInstruction_c *i)
{
Bit32u op1_32, op2_32, diff_32;
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
op1_32 = read_virtual_dword(i->seg(), eaddr);
op2_32 = BX_READ_32BIT_REG(i->nnn());
diff_32 = op1_32 - op2_32;
SET_FLAGS_OSZAPC_SUB_32(op1_32, op2_32, diff_32);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMP_GdEdR(bxInstruction_c *i)
{
Bit32u op1_32, op2_32, diff_32;
op1_32 = BX_READ_32BIT_REG(i->nnn());
op2_32 = BX_READ_32BIT_REG(i->rm());
diff_32 = op1_32 - op2_32;
SET_FLAGS_OSZAPC_SUB_32(op1_32, op2_32, diff_32);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMP_EAXId(bxInstruction_c *i)
{
Bit32u op1_32, op2_32, diff_32;
op1_32 = EAX;
op2_32 = i->Id();
diff_32 = op1_32 - op2_32;
SET_FLAGS_OSZAPC_SUB_32(op1_32, op2_32, diff_32);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CWDE(bxInstruction_c *i)
{
/* CWDE: no flags are effected */
Bit32u tmp = (Bit16s) AX;
RAX = tmp;
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CDQ(bxInstruction_c *i)
{
/* CDQ: no flags are affected */
if (EAX & 0x80000000) {
RDX = 0xFFFFFFFF;
}
else {
RDX = 0x00000000;
}
}
// Some info on the opcodes at {0F,A6} and {0F,A7}
// On 386 steps A0-B0:
// {OF,A6} = XBTS
// {OF,A7} = IBTS
// On 486 steps A0-B0:
// {OF,A6} = CMPXCHG 8
// {OF,A7} = CMPXCHG 16|32
//
// On 486 >= B steps, and further processors, the
// CMPXCHG instructions were moved to opcodes:
// {OF,B0} = CMPXCHG 8
// {OF,B1} = CMPXCHG 16|32
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMPXCHG_XBTS(bxInstruction_c *i)
{
BX_INFO(("CMPXCHG_XBTS: Generate #UD exception"));
exception(BX_UD_EXCEPTION, 0);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMPXCHG_IBTS(bxInstruction_c *i)
{
BX_INFO(("CMPXCHG_IBTS: Generate #UD exception"));
exception(BX_UD_EXCEPTION, 0);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::XADD_EdGdM(bxInstruction_c *i)
{
Bit32u op1_32, op2_32, sum_32;
/* XADD dst(r/m), src(r)
* temp <-- src + dst | sum = op2 + op1
* src <-- dst | op2 = op1
* dst <-- tmp | op1 = sum
*/
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
op1_32 = read_RMW_virtual_dword(i->seg(), eaddr);
op2_32 = BX_READ_32BIT_REG(i->nnn());
sum_32 = op1_32 + op2_32;
write_RMW_virtual_dword(sum_32);
/* and write destination into source */
BX_WRITE_32BIT_REGZ(i->nnn(), op1_32);
SET_FLAGS_OSZAPC_ADD_32(op1_32, op2_32, sum_32);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::XADD_EdGdR(bxInstruction_c *i)
{
Bit32u op1_32, op2_32, sum_32;
/* XADD dst(r/m), src(r)
* temp <-- src + dst | sum = op2 + op1
* src <-- dst | op2 = op1
* dst <-- tmp | op1 = sum
*/
op1_32 = BX_READ_32BIT_REG(i->rm());
op2_32 = BX_READ_32BIT_REG(i->nnn());
sum_32 = op1_32 + op2_32;
// and write destination into source
// Note: if both op1 & op2 are registers, the last one written
// should be the sum, as op1 & op2 may be the same register.
// For example: XADD AL, AL
BX_WRITE_32BIT_REGZ(i->nnn(), op1_32);
BX_WRITE_32BIT_REGZ(i->rm(), sum_32);
SET_FLAGS_OSZAPC_ADD_32(op1_32, op2_32, sum_32);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::ADD_EdIdM(bxInstruction_c *i)
{
Bit32u op1_32, op2_32, sum_32;
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
op1_32 = read_RMW_virtual_dword(i->seg(), eaddr);
op2_32 = i->Id();
sum_32 = op1_32 + op2_32;
write_RMW_virtual_dword(sum_32);
SET_FLAGS_OSZAPC_ADD_32(op1_32, op2_32, sum_32);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::ADD_EdIdR(bxInstruction_c *i)
{
Bit32u op1_32, op2_32, sum_32;
op1_32 = BX_READ_32BIT_REG(i->rm());
op2_32 = i->Id();
sum_32 = op1_32 + op2_32;
BX_WRITE_32BIT_REGZ(i->rm(), sum_32);
SET_FLAGS_OSZAPC_ADD_32(op1_32, op2_32, sum_32);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::ADC_EdIdM(bxInstruction_c *i)
{
bx_bool temp_CF = getB_CF();
Bit32u op1_32, op2_32 = i->Id(), sum_32;
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
op1_32 = read_RMW_virtual_dword(i->seg(), eaddr);
sum_32 = op1_32 + op2_32 + temp_CF;
write_RMW_virtual_dword(sum_32);
SET_FLAGS_OSZAPC_32(op1_32, op2_32, sum_32, BX_LF_INSTR_ADD_ADC32(temp_CF));
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::ADC_EdIdR(bxInstruction_c *i)
{
bx_bool temp_CF = getB_CF();
Bit32u op1_32, op2_32 = i->Id(), sum_32;
op1_32 = BX_READ_32BIT_REG(i->rm());
sum_32 = op1_32 + op2_32 + temp_CF;
BX_WRITE_32BIT_REGZ(i->rm(), sum_32);
SET_FLAGS_OSZAPC_32(op1_32, op2_32, sum_32, BX_LF_INSTR_ADD_ADC32(temp_CF));
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SUB_EdIdM(bxInstruction_c *i)
{
Bit32u op1_32, op2_32 = i->Id(), diff_32;
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
op1_32 = read_RMW_virtual_dword(i->seg(), eaddr);
diff_32 = op1_32 - op2_32;
write_RMW_virtual_dword(diff_32);
SET_FLAGS_OSZAPC_SUB_32(op1_32, op2_32, diff_32);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SUB_EdIdR(bxInstruction_c *i)
{
Bit32u op1_32, op2_32 = i->Id(), diff_32;
op1_32 = BX_READ_32BIT_REG(i->rm());
diff_32 = op1_32 - op2_32;
BX_WRITE_32BIT_REGZ(i->rm(), diff_32);
SET_FLAGS_OSZAPC_SUB_32(op1_32, op2_32, diff_32);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMP_EdIdM(bxInstruction_c *i)
{
Bit32u op1_32, op2_32, diff_32;
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
op1_32 = read_virtual_dword(i->seg(), eaddr);
op2_32 = i->Id();
diff_32 = op1_32 - op2_32;
SET_FLAGS_OSZAPC_SUB_32(op1_32, op2_32, diff_32);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMP_EdIdR(bxInstruction_c *i)
{
Bit32u op1_32, op2_32, diff_32;
op1_32 = BX_READ_32BIT_REG(i->rm());
op2_32 = i->Id();
diff_32 = op1_32 - op2_32;
SET_FLAGS_OSZAPC_SUB_32(op1_32, op2_32, diff_32);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::NEG_EdM(bxInstruction_c *i)
{
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
Bit32u op1_32 = read_RMW_virtual_dword(i->seg(), eaddr);
op1_32 = - (Bit32s)(op1_32);
write_RMW_virtual_dword(op1_32);
SET_FLAGS_OSZAPC_RESULT_32(op1_32, BX_LF_INSTR_NEG32);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::NEG_EdR(bxInstruction_c *i)
{
Bit32u op1_32 = BX_READ_32BIT_REG(i->rm());
op1_32 = - (Bit32s)(op1_32);
BX_WRITE_32BIT_REGZ(i->rm(), op1_32);
SET_FLAGS_OSZAPC_RESULT_32(op1_32, BX_LF_INSTR_NEG32);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::INC_EdM(bxInstruction_c *i)
{
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
Bit32u op1_32 = read_RMW_virtual_dword(i->seg(), eaddr);
op1_32++;
write_RMW_virtual_dword(op1_32);
SET_FLAGS_OSZAPC_INC_32(op1_32);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::DEC_EdM(bxInstruction_c *i)
{
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
Bit32u op1_32 = read_RMW_virtual_dword(i->seg(), eaddr);
op1_32--;
write_RMW_virtual_dword(op1_32);
SET_FLAGS_OSZAPC_DEC_32(op1_32);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMPXCHG_EdGdM(bxInstruction_c *i)
{
Bit32u op1_32, op2_32, diff_32;
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
op1_32 = read_RMW_virtual_dword(i->seg(), eaddr);
diff_32 = EAX - op1_32;
SET_FLAGS_OSZAPC_SUB_32(EAX, op1_32, diff_32);
if (diff_32 == 0) { // if accumulator == dest
// dest <-- src
op2_32 = BX_READ_32BIT_REG(i->nnn());
write_RMW_virtual_dword(op2_32);
}
else {
// accumulator <-- dest
RAX = op1_32;
}
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMPXCHG_EdGdR(bxInstruction_c *i)
{
Bit32u op1_32, op2_32, diff_32;
op1_32 = BX_READ_32BIT_REG(i->rm());
diff_32 = EAX - op1_32;
SET_FLAGS_OSZAPC_SUB_32(EAX, op1_32, diff_32);
if (diff_32 == 0) { // if accumulator == dest
// dest <-- src
op2_32 = BX_READ_32BIT_REG(i->nnn());
BX_WRITE_32BIT_REGZ(i->rm(), op2_32);
}
else {
// accumulator <-- dest
RAX = op1_32;
}
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMPXCHG8B(bxInstruction_c *i)
{
Bit64u op1_64, op2_64;
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
// check write permission for following write
op1_64 = read_RMW_virtual_qword(i->seg(), eaddr);
op2_64 = ((Bit64u) EDX << 32) | EAX;
if (op1_64 == op2_64) { // if accumulator == dest
// dest <-- src (ECX:EBX)
op2_64 = ((Bit64u) ECX << 32) | EBX;
write_RMW_virtual_qword(op2_64);
assert_ZF();
}
else {
// accumulator <-- dest
RAX = GET32L(op1_64);
RDX = GET32H(op1_64);
clear_ZF();
}
}

View File

@ -0,0 +1,580 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2001-2009 The Bochs Project
//
// 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
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA B 02110-1301 USA
/////////////////////////////////////////////////////////////////////////
#define NEED_CPU_REG_SHORTCUTS 1
#include "bochs.h"
#include "cpu.h"
#define LOG_THIS BX_CPU_THIS_PTR
#if BX_SUPPORT_X86_64
void BX_CPP_AttrRegparmN(1) BX_CPU_C::ADD_EqGqM(bxInstruction_c *i)
{
Bit64u op1_64, op2_64, sum_64;
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
/* pointer, segment address pair */
op1_64 = read_RMW_virtual_qword_64(i->seg(), eaddr);
op2_64 = BX_READ_64BIT_REG(i->nnn());
sum_64 = op1_64 + op2_64;
write_RMW_virtual_qword(sum_64);
SET_FLAGS_OSZAPC_ADD_64(op1_64, op2_64, sum_64);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::ADD_GqEqR(bxInstruction_c *i)
{
Bit64u op1_64, op2_64, sum_64;
op1_64 = BX_READ_64BIT_REG(i->nnn());
op2_64 = BX_READ_64BIT_REG(i->rm());
sum_64 = op1_64 + op2_64;
BX_WRITE_64BIT_REG(i->nnn(), sum_64);
SET_FLAGS_OSZAPC_ADD_64(op1_64, op2_64, sum_64);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::ADD_RAXId(bxInstruction_c *i)
{
Bit64u op1_64, op2_64, sum_64;
op1_64 = RAX;
op2_64 = (Bit32s) i->Id();
sum_64 = op1_64 + op2_64;
/* now write sum back to destination */
RAX = sum_64;
SET_FLAGS_OSZAPC_ADD_64(op1_64, op2_64, sum_64);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::ADC_EqGqM(bxInstruction_c *i)
{
bx_bool temp_CF = getB_CF();
Bit64u op1_64, op2_64, sum_64;
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
/* pointer, segment address pair */
op1_64 = read_RMW_virtual_qword_64(i->seg(), eaddr);
op2_64 = BX_READ_64BIT_REG(i->nnn());
sum_64 = op1_64 + op2_64 + temp_CF;
write_RMW_virtual_qword(sum_64);
SET_FLAGS_OSZAPC_64(op1_64, op2_64, sum_64, BX_LF_INSTR_ADD_ADC64(temp_CF));
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::ADC_GqEqR(bxInstruction_c *i)
{
bx_bool temp_CF = getB_CF();
Bit64u op1_64, op2_64, sum_64;
op1_64 = BX_READ_64BIT_REG(i->nnn());
op2_64 = BX_READ_64BIT_REG(i->rm());
sum_64 = op1_64 + op2_64 + temp_CF;
/* now write sum back to destination */
BX_WRITE_64BIT_REG(i->nnn(), sum_64);
SET_FLAGS_OSZAPC_64(op1_64, op2_64, sum_64, BX_LF_INSTR_ADD_ADC64(temp_CF));
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::ADC_RAXId(bxInstruction_c *i)
{
bx_bool temp_CF = getB_CF();
Bit64u op1_64, op2_64, sum_64;
op1_64 = RAX;
op2_64 = (Bit32s) i->Id();
sum_64 = op1_64 + op2_64 + temp_CF;
/* now write sum back to destination */
RAX = sum_64;
SET_FLAGS_OSZAPC_64(op1_64, op2_64, sum_64, BX_LF_INSTR_ADD_ADC64(temp_CF));
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SBB_EqGqM(bxInstruction_c *i)
{
bx_bool temp_CF = getB_CF();
Bit64u op1_64, op2_64, diff_64;
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
/* pointer, segment address pair */
op1_64 = read_RMW_virtual_qword_64(i->seg(), eaddr);
op2_64 = BX_READ_64BIT_REG(i->nnn());
diff_64 = op1_64 - (op2_64 + temp_CF);
write_RMW_virtual_qword(diff_64);
SET_FLAGS_OSZAPC_64(op1_64, op2_64, diff_64, BX_LF_INSTR_SUB_SBB64(temp_CF));
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SBB_GqEqR(bxInstruction_c *i)
{
bx_bool temp_CF = getB_CF();
Bit64u op1_64, op2_64, diff_64;
op1_64 = BX_READ_64BIT_REG(i->nnn());
op2_64 = BX_READ_64BIT_REG(i->rm());
diff_64 = op1_64 - (op2_64 + temp_CF);
/* now write diff back to destination */
BX_WRITE_64BIT_REG(i->nnn(), diff_64);
SET_FLAGS_OSZAPC_64(op1_64, op2_64, diff_64, BX_LF_INSTR_SUB_SBB64(temp_CF));
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SBB_RAXId(bxInstruction_c *i)
{
bx_bool temp_CF = getB_CF();
Bit64u op1_64, op2_64, diff_64;
op1_64 = RAX;
op2_64 = (Bit32s) i->Id();
diff_64 = op1_64 - (op2_64 + temp_CF);
/* now write diff back to destination */
RAX = diff_64;
SET_FLAGS_OSZAPC_64(op1_64, op2_64, diff_64, BX_LF_INSTR_SUB_SBB64(temp_CF));
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SBB_EqIdM(bxInstruction_c *i)
{
bx_bool temp_CF = getB_CF();
Bit64u op1_64, op2_64, diff_64;
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
/* pointer, segment address pair */
op1_64 = read_RMW_virtual_qword_64(i->seg(), eaddr);
op2_64 = (Bit32s) i->Id();
diff_64 = op1_64 - (op2_64 + temp_CF);
write_RMW_virtual_qword(diff_64);
SET_FLAGS_OSZAPC_64(op1_64, op2_64, diff_64, BX_LF_INSTR_SUB_SBB64(temp_CF));
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SBB_EqIdR(bxInstruction_c *i)
{
bx_bool temp_CF = getB_CF();
Bit64u op1_64, op2_64, diff_64;
op1_64 = BX_READ_64BIT_REG(i->rm());
op2_64 = (Bit32s) i->Id();
diff_64 = op1_64 - (op2_64 + temp_CF);
BX_WRITE_64BIT_REG(i->rm(), diff_64);
SET_FLAGS_OSZAPC_64(op1_64, op2_64, diff_64, BX_LF_INSTR_SUB_SBB64(temp_CF));
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SUB_EqGqM(bxInstruction_c *i)
{
Bit64u op1_64, op2_64, diff_64;
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
/* pointer, segment address pair */
op1_64 = read_RMW_virtual_qword_64(i->seg(), eaddr);
op2_64 = BX_READ_64BIT_REG(i->nnn());
diff_64 = op1_64 - op2_64;
write_RMW_virtual_qword(diff_64);
SET_FLAGS_OSZAPC_SUB_64(op1_64, op2_64, diff_64);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SUB_GqEqR(bxInstruction_c *i)
{
Bit64u op1_64, op2_64, diff_64;
op1_64 = BX_READ_64BIT_REG(i->nnn());
op2_64 = BX_READ_64BIT_REG(i->rm());
diff_64 = op1_64 - op2_64;
/* now write diff back to destination */
BX_WRITE_64BIT_REG(i->nnn(), diff_64);
SET_FLAGS_OSZAPC_SUB_64(op1_64, op2_64, diff_64);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SUB_RAXId(bxInstruction_c *i)
{
Bit64u op1_64, op2_64, diff_64;
op1_64 = RAX;
op2_64 = (Bit32s) i->Id();
diff_64 = op1_64 - op2_64;
/* now write diff back to destination */
RAX = diff_64;
SET_FLAGS_OSZAPC_SUB_64(op1_64, op2_64, diff_64);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMP_EqGqM(bxInstruction_c *i)
{
Bit64u op1_64, op2_64, diff_64;
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
op1_64 = read_virtual_qword_64(i->seg(), eaddr);
op2_64 = BX_READ_64BIT_REG(i->nnn());
diff_64 = op1_64 - op2_64;
SET_FLAGS_OSZAPC_SUB_64(op1_64, op2_64, diff_64);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMP_GqEqR(bxInstruction_c *i)
{
Bit64u op1_64, op2_64, diff_64;
op1_64 = BX_READ_64BIT_REG(i->nnn());
op2_64 = BX_READ_64BIT_REG(i->rm());
diff_64 = op1_64 - op2_64;
SET_FLAGS_OSZAPC_SUB_64(op1_64, op2_64, diff_64);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMP_RAXId(bxInstruction_c *i)
{
Bit64u op1_64, op2_64, diff_64;
op1_64 = RAX;
op2_64 = (Bit32s) i->Id();
diff_64 = op1_64 - op2_64;
SET_FLAGS_OSZAPC_SUB_64(op1_64, op2_64, diff_64);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CDQE(bxInstruction_c *i)
{
/* CWDE: no flags are affected */
RAX = (Bit32s) EAX;
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CQO(bxInstruction_c *i)
{
/* CQO: no flags are affected */
if (RAX & BX_CONST64(0x8000000000000000))
RDX = BX_CONST64(0xffffffffffffffff);
else
RDX = 0;
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::XADD_EqGqM(bxInstruction_c *i)
{
Bit64u op1_64, op2_64, sum_64;
/* XADD dst(r/m), src(r)
* temp <-- src + dst | sum = op2 + op1
* src <-- dst | op2 = op1
* dst <-- tmp | op1 = sum
*/
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
/* pointer, segment address pair */
op1_64 = read_RMW_virtual_qword_64(i->seg(), eaddr);
op2_64 = BX_READ_64BIT_REG(i->nnn());
sum_64 = op1_64 + op2_64;
write_RMW_virtual_qword(sum_64);
/* and write destination into source */
BX_WRITE_64BIT_REG(i->nnn(), op1_64);
SET_FLAGS_OSZAPC_ADD_64(op1_64, op2_64, sum_64);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::XADD_EqGqR(bxInstruction_c *i)
{
Bit64u op1_64, op2_64, sum_64;
/* XADD dst(r/m), src(r)
* temp <-- src + dst | sum = op2 + op1
* src <-- dst | op2 = op1
* dst <-- tmp | op1 = sum
*/
op1_64 = BX_READ_64BIT_REG(i->rm());
op2_64 = BX_READ_64BIT_REG(i->nnn());
sum_64 = op1_64 + op2_64;
// and write destination into source
// Note: if both op1 & op2 are registers, the last one written
// should be the sum, as op1 & op2 may be the same register.
// For example: XADD AL, AL
BX_WRITE_64BIT_REG(i->nnn(), op1_64);
BX_WRITE_64BIT_REG(i->rm(), sum_64);
SET_FLAGS_OSZAPC_ADD_64(op1_64, op2_64, sum_64);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::ADD_EqIdM(bxInstruction_c *i)
{
Bit64u op1_64, op2_64, sum_64;
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
/* pointer, segment address pair */
op1_64 = read_RMW_virtual_qword_64(i->seg(), eaddr);
op2_64 = (Bit32s) i->Id();
sum_64 = op1_64 + op2_64;
write_RMW_virtual_qword(sum_64);
SET_FLAGS_OSZAPC_ADD_64(op1_64, op2_64, sum_64);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::ADD_EqIdR(bxInstruction_c *i)
{
Bit64u op1_64, op2_64, sum_64;
op1_64 = BX_READ_64BIT_REG(i->rm());
op2_64 = (Bit32s) i->Id();
sum_64 = op1_64 + op2_64;
BX_WRITE_64BIT_REG(i->rm(), sum_64);
SET_FLAGS_OSZAPC_ADD_64(op1_64, op2_64, sum_64);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::ADC_EqIdM(bxInstruction_c *i)
{
bx_bool temp_CF = getB_CF();
Bit64u op1_64, op2_64, sum_64;
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
/* pointer, segment address pair */
op1_64 = read_RMW_virtual_qword_64(i->seg(), eaddr);
op2_64 = (Bit32s) i->Id();
sum_64 = op1_64 + op2_64 + temp_CF;
write_RMW_virtual_qword(sum_64);
SET_FLAGS_OSZAPC_64(op1_64, op2_64, sum_64, BX_LF_INSTR_ADD_ADC64(temp_CF));
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::ADC_EqIdR(bxInstruction_c *i)
{
bx_bool temp_CF = getB_CF();
Bit64u op1_64, op2_64, sum_64;
op1_64 = BX_READ_64BIT_REG(i->rm());
op2_64 = (Bit32s) i->Id();
sum_64 = op1_64 + op2_64 + temp_CF;
BX_WRITE_64BIT_REG(i->rm(), sum_64);
SET_FLAGS_OSZAPC_64(op1_64, op2_64, sum_64, BX_LF_INSTR_ADD_ADC64(temp_CF));
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SUB_EqIdM(bxInstruction_c *i)
{
Bit64u op1_64, op2_64, diff_64;
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
/* pointer, segment address pair */
op1_64 = read_RMW_virtual_qword_64(i->seg(), eaddr);
op2_64 = (Bit32s) i->Id();
diff_64 = op1_64 - op2_64;
write_RMW_virtual_qword(diff_64);
SET_FLAGS_OSZAPC_SUB_64(op1_64, op2_64, diff_64);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SUB_EqIdR(bxInstruction_c *i)
{
Bit64u op1_64, op2_64, diff_64;
op1_64 = BX_READ_64BIT_REG(i->rm());
op2_64 = (Bit32s) i->Id();
diff_64 = op1_64 - op2_64;
BX_WRITE_64BIT_REG(i->rm(), diff_64);
SET_FLAGS_OSZAPC_SUB_64(op1_64, op2_64, diff_64);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMP_EqIdM(bxInstruction_c *i)
{
Bit64u op1_64, op2_64, diff_64;
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
op1_64 = read_virtual_qword_64(i->seg(), eaddr);
op2_64 = (Bit32s) i->Id();
diff_64 = op1_64 - op2_64;
SET_FLAGS_OSZAPC_SUB_64(op1_64, op2_64, diff_64);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMP_EqIdR(bxInstruction_c *i)
{
Bit64u op1_64, op2_64, diff_64;
op1_64 = BX_READ_64BIT_REG(i->rm());
op2_64 = (Bit32s) i->Id();
diff_64 = op1_64 - op2_64;
SET_FLAGS_OSZAPC_SUB_64(op1_64, op2_64, diff_64);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::NEG_EqM(bxInstruction_c *i)
{
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
Bit64u op1_64 = read_RMW_virtual_qword_64(i->seg(), eaddr);
op1_64 = - (Bit64s)(op1_64);
write_RMW_virtual_qword(op1_64);
SET_FLAGS_OSZAPC_RESULT_64(op1_64, BX_LF_INSTR_NEG64);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::NEG_EqR(bxInstruction_c *i)
{
Bit64u op1_64 = BX_READ_64BIT_REG(i->rm());
op1_64 = - (Bit64s)(op1_64);
BX_WRITE_64BIT_REG(i->rm(), op1_64);
SET_FLAGS_OSZAPC_RESULT_64(op1_64, BX_LF_INSTR_NEG64);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::INC_EqM(bxInstruction_c *i)
{
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
Bit64u op1_64 = read_RMW_virtual_qword_64(i->seg(), eaddr);
op1_64++;
write_RMW_virtual_qword(op1_64);
SET_FLAGS_OSZAPC_INC_64(op1_64);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::INC_EqR(bxInstruction_c *i)
{
Bit64u rrx = ++BX_READ_64BIT_REG(i->rm());
SET_FLAGS_OSZAPC_INC_64(rrx);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::DEC_EqM(bxInstruction_c *i)
{
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
Bit64u op1_64 = read_RMW_virtual_qword_64(i->seg(), eaddr);
op1_64--;
write_RMW_virtual_qword(op1_64);
SET_FLAGS_OSZAPC_DEC_64(op1_64);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::DEC_EqR(bxInstruction_c *i)
{
Bit64u rrx = --BX_READ_64BIT_REG(i->rm());
SET_FLAGS_OSZAPC_INC_64(rrx);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMPXCHG_EqGqM(bxInstruction_c *i)
{
Bit64u op1_64, op2_64, diff_64;
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
/* pointer, segment address pair */
op1_64 = read_RMW_virtual_qword_64(i->seg(), eaddr);
diff_64 = RAX - op1_64;
SET_FLAGS_OSZAPC_SUB_64(RAX, op1_64, diff_64);
if (diff_64 == 0) { // if accumulator == dest
// dest <-- src
op2_64 = BX_READ_64BIT_REG(i->nnn());
write_RMW_virtual_qword(op2_64);
}
else {
// accumulator <-- dest
RAX = op1_64;
}
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMPXCHG_EqGqR(bxInstruction_c *i)
{
Bit64u op1_64, op2_64, diff_64;
op1_64 = BX_READ_64BIT_REG(i->rm());
diff_64 = RAX - op1_64;
SET_FLAGS_OSZAPC_SUB_64(RAX, op1_64, diff_64);
if (diff_64 == 0) { // if accumulator == dest
// dest <-- src
op2_64 = BX_READ_64BIT_REG(i->nnn());
BX_WRITE_64BIT_REG(i->rm(), op2_64);
}
else {
// accumulator <-- dest
RAX = op1_64;
}
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMPXCHG16B(bxInstruction_c *i)
{
Bit64u op1_64_lo, op1_64_hi, diff;
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
bx_address laddr = get_laddr64(i->seg(), eaddr);
if (laddr & 0xf) {
BX_ERROR(("CMPXCHG16B: not aligned memory location (#GP)"));
exception(BX_GP_EXCEPTION, 0);
}
// check write permission for following write
op1_64_lo = read_RMW_virtual_qword_64(i->seg(), eaddr);
op1_64_hi = read_RMW_virtual_qword_64(i->seg(), (eaddr + 8) & i->asize_mask());
diff = RAX - op1_64_lo;
diff |= RDX - op1_64_hi;
if (diff == 0) { // if accumulator == dest
// dest <-- src (RCX:RBX)
write_RMW_virtual_qword(RCX);
// write permissions already checked by read_RMW_virtual_qword_64
write_virtual_qword_64(i->seg(), eaddr, RBX);
assert_ZF();
}
else {
clear_ZF();
// accumulator <-- dest
RAX = op1_64_lo;
RDX = op1_64_hi;
}
}
#endif /* if BX_SUPPORT_X86_64 */

View File

@ -0,0 +1,487 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2001-2009 The Bochs Project
//
// 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
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA B 02110-1301 USA
/////////////////////////////////////////////////////////////////////////
#define NEED_CPU_REG_SHORTCUTS 1
#include "bochs.h"
#include "cpu.h"
#define LOG_THIS BX_CPU_THIS_PTR
void BX_CPP_AttrRegparmN(1) BX_CPU_C::ADD_EbGbM(bxInstruction_c *i)
{
Bit8u op1, op2, sum;
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
op1 = read_RMW_virtual_byte(i->seg(), eaddr);
op2 = BX_READ_8BIT_REGx(i->nnn(), i->extend8bitL());
sum = op1 + op2;
write_RMW_virtual_byte(sum);
SET_FLAGS_OSZAPC_ADD_8(op1, op2, sum);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::ADD_GbEbR(bxInstruction_c *i)
{
Bit8u op1, op2, sum;
op1 = BX_READ_8BIT_REGx(i->nnn(), i->extend8bitL());
op2 = BX_READ_8BIT_REGx(i->rm(), i->extend8bitL());
sum = op1 + op2;
BX_WRITE_8BIT_REGx(i->nnn(), i->extend8bitL(), sum);
SET_FLAGS_OSZAPC_ADD_8(op1, op2, sum);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::ADD_ALIb(bxInstruction_c *i)
{
Bit8u op1, op2, sum;
op1 = AL;
op2 = i->Ib();
sum = op1 + op2;
AL = sum;
SET_FLAGS_OSZAPC_ADD_8(op1, op2, sum);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::ADC_EbGbM(bxInstruction_c *i)
{
Bit8u op1, op2, sum;
bx_bool temp_CF = getB_CF();
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
op1 = read_RMW_virtual_byte(i->seg(), eaddr);
op2 = BX_READ_8BIT_REGx(i->nnn(), i->extend8bitL());
sum = op1 + op2 + temp_CF;
write_RMW_virtual_byte(sum);
SET_FLAGS_OSZAPC_8(op1, op2, sum, BX_LF_INSTR_ADD_ADC8(temp_CF));
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::ADC_GbEbR(bxInstruction_c *i)
{
Bit8u op1, op2, sum;
bx_bool temp_CF = getB_CF();
op1 = BX_READ_8BIT_REGx(i->nnn(), i->extend8bitL());
op2 = BX_READ_8BIT_REGx(i->rm(), i->extend8bitL());
sum = op1 + op2 + temp_CF;
BX_WRITE_8BIT_REGx(i->nnn(), i->extend8bitL(), sum);
SET_FLAGS_OSZAPC_8(op1, op2, sum, BX_LF_INSTR_ADD_ADC8(temp_CF));
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::ADC_ALIb(bxInstruction_c *i)
{
Bit8u op1, op2, sum;
bx_bool temp_CF = getB_CF();
op1 = AL;
op2 = i->Ib();
sum = op1 + op2 + temp_CF;
AL = sum;
SET_FLAGS_OSZAPC_8(op1, op2, sum, BX_LF_INSTR_ADD_ADC8(temp_CF));
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SBB_EbGbM(bxInstruction_c *i)
{
Bit8u op1_8, op2_8, diff_8;
bx_bool temp_CF = getB_CF();
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
op1_8 = read_RMW_virtual_byte(i->seg(), eaddr);
op2_8 = BX_READ_8BIT_REGx(i->nnn(), i->extend8bitL());
diff_8 = op1_8 - (op2_8 + temp_CF);
write_RMW_virtual_byte(diff_8);
SET_FLAGS_OSZAPC_8(op1_8, op2_8, diff_8, BX_LF_INSTR_SUB_SBB8(temp_CF));
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SBB_GbEbR(bxInstruction_c *i)
{
Bit8u op1_8, op2_8, diff_8;
bx_bool temp_CF = getB_CF();
op1_8 = BX_READ_8BIT_REGx(i->nnn(), i->extend8bitL());
op2_8 = BX_READ_8BIT_REGx(i->rm(), i->extend8bitL());
diff_8 = op1_8 - (op2_8 + temp_CF);
BX_WRITE_8BIT_REGx(i->nnn(), i->extend8bitL(), diff_8);
SET_FLAGS_OSZAPC_8(op1_8, op2_8, diff_8, BX_LF_INSTR_SUB_SBB8(temp_CF));
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SBB_ALIb(bxInstruction_c *i)
{
Bit8u op1_8, op2_8, diff_8;
bx_bool temp_CF = getB_CF();
op1_8 = AL;
op2_8 = i->Ib();
diff_8 = op1_8 - (op2_8 + temp_CF);
AL = diff_8;
SET_FLAGS_OSZAPC_8(op1_8, op2_8, diff_8, BX_LF_INSTR_SUB_SBB8(temp_CF));
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SBB_EbIbM(bxInstruction_c *i)
{
Bit8u op1_8, op2_8 = i->Ib(), diff_8;
bx_bool temp_CF = getB_CF();
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
op1_8 = read_RMW_virtual_byte(i->seg(), eaddr);
diff_8 = op1_8 - (op2_8 + temp_CF);
write_RMW_virtual_byte(diff_8);
SET_FLAGS_OSZAPC_8(op1_8, op2_8, diff_8, BX_LF_INSTR_SUB_SBB8(temp_CF));
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SBB_EbIbR(bxInstruction_c *i)
{
Bit8u op1_8, op2_8 = i->Ib(), diff_8;
bx_bool temp_CF = getB_CF();
op1_8 = BX_READ_8BIT_REGx(i->rm(), i->extend8bitL());
diff_8 = op1_8 - (op2_8 + temp_CF);
BX_WRITE_8BIT_REGx(i->rm(), i->extend8bitL(), diff_8);
SET_FLAGS_OSZAPC_8(op1_8, op2_8, diff_8, BX_LF_INSTR_SUB_SBB8(temp_CF));
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SUB_EbGbM(bxInstruction_c *i)
{
Bit8u op1_8, op2_8, diff_8;
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
op1_8 = read_RMW_virtual_byte(i->seg(), eaddr);
op2_8 = BX_READ_8BIT_REGx(i->nnn(), i->extend8bitL());
diff_8 = op1_8 - op2_8;
write_RMW_virtual_byte(diff_8);
SET_FLAGS_OSZAPC_SUB_8(op1_8, op2_8, diff_8);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SUB_GbEbR(bxInstruction_c *i)
{
Bit8u op1_8, op2_8, diff_8;
op1_8 = BX_READ_8BIT_REGx(i->nnn(), i->extend8bitL());
op2_8 = BX_READ_8BIT_REGx(i->rm(), i->extend8bitL());
diff_8 = op1_8 - op2_8;
BX_WRITE_8BIT_REGx(i->nnn(), i->extend8bitL(), diff_8);
SET_FLAGS_OSZAPC_SUB_8(op1_8, op2_8, diff_8);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SUB_ALIb(bxInstruction_c *i)
{
Bit8u op1_8, op2_8, diff_8;
op1_8 = AL;
op2_8 = i->Ib();
diff_8 = op1_8 - op2_8;
AL = diff_8;
SET_FLAGS_OSZAPC_SUB_8(op1_8, op2_8, diff_8);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMP_EbGbM(bxInstruction_c *i)
{
Bit8u op1_8, op2_8, diff_8;
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
op1_8 = read_virtual_byte(i->seg(), eaddr);
op2_8 = BX_READ_8BIT_REGx(i->nnn(), i->extend8bitL());
diff_8 = op1_8 - op2_8;
SET_FLAGS_OSZAPC_SUB_8(op1_8, op2_8, diff_8);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMP_GbEbR(bxInstruction_c *i)
{
Bit8u op1_8, op2_8, diff_8;
op1_8 = BX_READ_8BIT_REGx(i->nnn(), i->extend8bitL());
op2_8 = BX_READ_8BIT_REGx(i->rm(), i->extend8bitL());
diff_8 = op1_8 - op2_8;
SET_FLAGS_OSZAPC_SUB_8(op1_8, op2_8, diff_8);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMP_ALIb(bxInstruction_c *i)
{
Bit8u op1_8, op2_8, diff_8;
op1_8 = AL;
op2_8 = i->Ib();
diff_8 = op1_8 - op2_8;
SET_FLAGS_OSZAPC_SUB_8(op1_8, op2_8, diff_8);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::XADD_EbGbM(bxInstruction_c *i)
{
Bit8u op1, op2, sum;
/* XADD dst(r/m8), src(r8)
* temp <-- src + dst | sum = op2 + op1
* src <-- dst | op2 = op1
* dst <-- tmp | op1 = sum
*/
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
op1 = read_RMW_virtual_byte(i->seg(), eaddr);
op2 = BX_READ_8BIT_REGx(i->nnn(), i->extend8bitL());
sum = op1 + op2;
write_RMW_virtual_byte(sum);
/* and write destination into source */
BX_WRITE_8BIT_REGx(i->nnn(), i->extend8bitL(), op1);
SET_FLAGS_OSZAPC_ADD_8(op1, op2, sum);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::XADD_EbGbR(bxInstruction_c *i)
{
Bit8u op1, op2, sum;
/* XADD dst(r/m8), src(r8)
* temp <-- src + dst | sum = op2 + op1
* src <-- dst | op2 = op1
* dst <-- tmp | op1 = sum
*/
op1 = BX_READ_8BIT_REGx(i->rm(), i->extend8bitL());
op2 = BX_READ_8BIT_REGx(i->nnn(), i->extend8bitL());
sum = op1 + op2;
// and write destination into source
// Note: if both op1 & op2 are registers, the last one written
// should be the sum, as op1 & op2 may be the same register.
// For example: XADD AL, AL
BX_WRITE_8BIT_REGx(i->nnn(), i->extend8bitL(), op1);
BX_WRITE_8BIT_REGx(i->rm(), i->extend8bitL(), sum);
SET_FLAGS_OSZAPC_ADD_8(op1, op2, sum);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::ADD_EbIbM(bxInstruction_c *i)
{
Bit8u op1, op2 = i->Ib(), sum;
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
op1 = read_RMW_virtual_byte(i->seg(), eaddr);
sum = op1 + op2;
write_RMW_virtual_byte(sum);
SET_FLAGS_OSZAPC_ADD_8(op1, op2, sum);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::ADD_EbIbR(bxInstruction_c *i)
{
Bit8u op1, op2 = i->Ib(), sum;
op1 = BX_READ_8BIT_REGx(i->rm(), i->extend8bitL());
sum = op1 + op2;
BX_WRITE_8BIT_REGx(i->rm(), i->extend8bitL(), sum);
SET_FLAGS_OSZAPC_ADD_8(op1, op2, sum);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::ADC_EbIbM(bxInstruction_c *i)
{
Bit8u op1, op2 = i->Ib(), sum;
bx_bool temp_CF = getB_CF();
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
op1 = read_RMW_virtual_byte(i->seg(), eaddr);
sum = op1 + op2 + temp_CF;
write_RMW_virtual_byte(sum);
SET_FLAGS_OSZAPC_8(op1, op2, sum, BX_LF_INSTR_ADD_ADC8(temp_CF));
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::ADC_EbIbR(bxInstruction_c *i)
{
Bit8u op1, op2 = i->Ib(), sum;
bx_bool temp_CF = getB_CF();
op1 = BX_READ_8BIT_REGx(i->rm(), i->extend8bitL());
sum = op1 + op2 + temp_CF;
BX_WRITE_8BIT_REGx(i->rm(), i->extend8bitL(), sum);
SET_FLAGS_OSZAPC_8(op1, op2, sum, BX_LF_INSTR_ADD_ADC8(temp_CF));
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SUB_EbIbM(bxInstruction_c *i)
{
Bit8u op1_8, op2_8 = i->Ib(), diff_8;
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
op1_8 = read_RMW_virtual_byte(i->seg(), eaddr);
diff_8 = op1_8 - op2_8;
write_RMW_virtual_byte(diff_8);
SET_FLAGS_OSZAPC_SUB_8(op1_8, op2_8, diff_8);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SUB_EbIbR(bxInstruction_c *i)
{
Bit8u op1_8, op2_8 = i->Ib(), diff_8;
op1_8 = BX_READ_8BIT_REGx(i->rm(), i->extend8bitL());
diff_8 = op1_8 - op2_8;
BX_WRITE_8BIT_REGx(i->rm(), i->extend8bitL(), diff_8);
SET_FLAGS_OSZAPC_SUB_8(op1_8, op2_8, diff_8);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMP_EbIbM(bxInstruction_c *i)
{
Bit8u op1_8, op2_8 = i->Ib(), diff_8;
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
op1_8 = read_virtual_byte(i->seg(), eaddr);
diff_8 = op1_8 - op2_8;
SET_FLAGS_OSZAPC_SUB_8(op1_8, op2_8, diff_8);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMP_EbIbR(bxInstruction_c *i)
{
Bit8u op1_8, op2_8 = i->Ib(), diff_8;
op1_8 = BX_READ_8BIT_REGx(i->rm(), i->extend8bitL());
diff_8 = op1_8 - op2_8;
SET_FLAGS_OSZAPC_SUB_8(op1_8, op2_8, diff_8);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::NEG_EbM(bxInstruction_c *i)
{
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
Bit8u op1_8 = read_RMW_virtual_byte(i->seg(), eaddr);
op1_8 = - (Bit8s)(op1_8);
write_RMW_virtual_byte(op1_8);
SET_FLAGS_OSZAPC_RESULT_8(op1_8, BX_LF_INSTR_NEG8);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::NEG_EbR(bxInstruction_c *i)
{
Bit8u op1_8 = BX_READ_8BIT_REGx(i->rm(), i->extend8bitL());
op1_8 = - (Bit8s)(op1_8);
BX_WRITE_8BIT_REGx(i->rm(), i->extend8bitL(), op1_8);
SET_FLAGS_OSZAPC_RESULT_8(op1_8, BX_LF_INSTR_NEG8);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::INC_EbM(bxInstruction_c *i)
{
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
Bit8u op1_8 = read_RMW_virtual_byte(i->seg(), eaddr);
op1_8++;
write_RMW_virtual_byte(op1_8);
SET_FLAGS_OSZAPC_INC_8(op1_8);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::INC_EbR(bxInstruction_c *i)
{
Bit8u op1_8 = BX_READ_8BIT_REGx(i->rm(), i->extend8bitL());
op1_8++;
BX_WRITE_8BIT_REGx(i->rm(), i->extend8bitL(), op1_8);
SET_FLAGS_OSZAPC_INC_8(op1_8);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::DEC_EbM(bxInstruction_c *i)
{
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
Bit8u op1_8 = read_RMW_virtual_byte(i->seg(), eaddr);
op1_8--;
write_RMW_virtual_byte(op1_8);
SET_FLAGS_OSZAPC_DEC_8(op1_8);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::DEC_EbR(bxInstruction_c *i)
{
Bit8u op1_8 = BX_READ_8BIT_REGx(i->rm(), i->extend8bitL());
op1_8--;
BX_WRITE_8BIT_REGx(i->rm(), i->extend8bitL(), op1_8);
SET_FLAGS_OSZAPC_DEC_8(op1_8);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMPXCHG_EbGbM(bxInstruction_c *i)
{
Bit8u op1_8, op2_8, diff_8;
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
op1_8 = read_RMW_virtual_byte(i->seg(), eaddr);
diff_8 = AL - op1_8;
SET_FLAGS_OSZAPC_SUB_8(AL, op1_8, diff_8);
if (diff_8 == 0) { // if accumulator == dest
// dest <-- src
op2_8 = BX_READ_8BIT_REGx(i->nnn(), i->extend8bitL());
write_RMW_virtual_byte(op2_8);
}
else {
// accumulator <-- dest
AL = op1_8;
}
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMPXCHG_EbGbR(bxInstruction_c *i)
{
Bit8u op1_8, op2_8, diff_8;
op1_8 = BX_READ_8BIT_REGx(i->rm(), i->extend8bitL());
diff_8 = AL - op1_8;
SET_FLAGS_OSZAPC_SUB_8(AL, op1_8, diff_8);
if (diff_8 == 0) { // if accumulator == dest
// dest <-- src
op2_8 = BX_READ_8BIT_REGx(i->nnn(), i->extend8bitL());
BX_WRITE_8BIT_REGx(i->rm(), i->extend8bitL(), op2_8);
}
else {
// accumulator <-- dest
AL = op1_8;
}
}

202
simulators/bochs/cpu/bcd.cc Normal file
View File

@ -0,0 +1,202 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2001-2009 The Bochs Project
//
// 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
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA B 02110-1301 USA
/////////////////////////////////////////////////////////////////////////
#define NEED_CPU_REG_SHORTCUTS 1
#include "bochs.h"
#include "cpu.h"
#define LOG_THIS BX_CPU_THIS_PTR
void BX_CPP_AttrRegparmN(1) BX_CPU_C::AAA(bxInstruction_c *i)
{
/*
* Note: This instruction incorrectly documented in Intel's materials.
* The right description is:
*
* IF (((AL and 0FH) > 9) or (AF==1)
* THEN
* IF CPU<286 THEN { AL <- AL+6 }
* ELSE { AX <- AX+6 }
* AH <- AH+1
* CF <- 1
* AF <- 1
* ELSE
* CF <- 0
* AF <- 0
* ENDIF
* AL <- AL and 0Fh
*/
/* Validated against Intel Pentium family hardware. */
/* AAA affects the following flags: A,C */
if (((AL & 0x0f) > 9) || get_AF())
{
AX = AX + 0x106;
assert_AF();
assert_CF();
}
else {
clear_AF();
clear_CF();
}
AL = AL & 0x0f;
/* AAA affects also the following flags: Z,S,O,P */
/* modification of the flags is undocumented */
/* The following behaviour seems to match the P6 and
its derived processors. */
clear_OF();
clear_SF(); /* sign is always 0 because bits 4-7 of AL are zeroed */
set_ZF(AL == 0);
set_PF_base(AL);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::AAS(bxInstruction_c *i)
{
/* AAS affects the following flags: A,C */
if (((AL & 0x0F) > 0x09) || get_AF())
{
AX = AX - 0x106;
assert_AF();
assert_CF();
}
else {
clear_CF();
clear_AF();
}
AL = AL & 0x0f;
/* AAS affects also the following flags: Z,S,O,P */
/* modification of the flags is undocumented */
/* The following behaviour seems to match the P6 and
its derived processors. */
clear_OF();
clear_SF(); /* sign is always 0 because bits 4-7 of AL are zeroed */
set_ZF(AL == 0);
set_PF_base(AL);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::AAM(bxInstruction_c *i)
{
Bit8u al, imm8 = i->Ib();
if (imm8 == 0)
exception(BX_DE_EXCEPTION, 0);
al = AL;
AH = al / imm8;
AL = al % imm8;
/* modification of flags A,C,O is undocumented */
/* The following behaviour seems to match the P6 and
its derived processors. */
SET_FLAGS_OSZAPC_LOGIC_8(AL);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::AAD(bxInstruction_c *i)
{
Bit16u tmp = AH;
tmp *= i->Ib();
tmp += AL;
AX = (tmp & 0xff);
/* modification of flags A,C,O is undocumented */
/* The following behaviour seems to match the P6 and
its derived processors. */
SET_FLAGS_OSZAPC_LOGIC_8(AL);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::DAA(bxInstruction_c *i)
{
Bit8u tmpAL = AL;
int tmpCF = 0;
/* Validated against Intel Pentium family hardware. */
// DAA affects the following flags: S,Z,A,P,C
if (((tmpAL & 0x0F) > 0x09) || get_AF())
{
tmpCF = ((AL > 0xF9) || get_CF());
AL = AL + 0x06;
assert_AF();
}
else
clear_AF();
if ((tmpAL > 0x99) || get_CF())
{
AL = AL + 0x60;
tmpCF = 1;
}
else
tmpCF = 0;
clear_OF(); /* undocumented flag modification */
set_SF(AL >= 0x80);
set_ZF(AL==0);
set_PF_base(AL);
set_CF(tmpCF);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::DAS(bxInstruction_c *i)
{
/* The algorithm for DAS is fashioned after the pseudo code in the
* Pentium Processor Family Developer's Manual, volume 3. It seems
* to have changed from earlier processor's manuals. I'm not sure
* if this is a correction in the algorithm printed, or Intel has
* changed the handling of instruction. Validated against Intel
* Pentium family hardware.
*/
Bit8u tmpAL = AL;
int tmpCF = 0;
/* DAS effect the following flags: A,C,S,Z,P */
if (((tmpAL & 0x0F) > 0x09) || get_AF())
{
tmpCF = (AL < 0x06) || get_CF();
AL = AL - 0x06;
assert_AF();
}
else
clear_AF();
if ((tmpAL > 0x99) || get_CF())
{
AL = AL - 0x60;
tmpCF = 1;
}
clear_OF(); /* undocumented flag modification */
set_SF(AL >= 0x80);
set_ZF(AL==0);
set_PF_base(AL);
set_CF(tmpCF);
}

337
simulators/bochs/cpu/bit.cc Normal file
View File

@ -0,0 +1,337 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2001-2009 The Bochs Project
//
// 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
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA B 02110-1301 USA
/////////////////////////////////////////////////////////////////////////
#define NEED_CPU_REG_SHORTCUTS 1
#include "bochs.h"
#include "cpu.h"
#define LOG_THIS BX_CPU_THIS_PTR
#if BX_CPU_LEVEL >= 3
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SETO_EbM(bxInstruction_c *i)
{
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
Bit8u result_8 = getB_OF();
write_virtual_byte(i->seg(), eaddr, result_8);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SETO_EbR(bxInstruction_c *i)
{
BX_WRITE_8BIT_REGx(i->rm(), i->extend8bitL(), getB_OF());
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SETNO_EbM(bxInstruction_c *i)
{
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
Bit8u result_8 = !getB_OF();
write_virtual_byte(i->seg(), eaddr, result_8);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SETNO_EbR(bxInstruction_c *i)
{
BX_WRITE_8BIT_REGx(i->rm(), i->extend8bitL(), !getB_OF());
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SETB_EbM(bxInstruction_c *i)
{
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
Bit8u result_8 = getB_CF();
write_virtual_byte(i->seg(), eaddr, result_8);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SETB_EbR(bxInstruction_c *i)
{
BX_WRITE_8BIT_REGx(i->rm(), i->extend8bitL(), getB_CF());
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SETNB_EbM(bxInstruction_c *i)
{
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
Bit8u result_8 = !getB_CF();
write_virtual_byte(i->seg(), eaddr, result_8);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SETNB_EbR(bxInstruction_c *i)
{
BX_WRITE_8BIT_REGx(i->rm(), i->extend8bitL(), !getB_CF());
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SETZ_EbM(bxInstruction_c *i)
{
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
Bit8u result_8 = getB_ZF();
write_virtual_byte(i->seg(), eaddr, result_8);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SETZ_EbR(bxInstruction_c *i)
{
BX_WRITE_8BIT_REGx(i->rm(), i->extend8bitL(), getB_ZF());
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SETNZ_EbM(bxInstruction_c *i)
{
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
Bit8u result_8 = !getB_ZF();
write_virtual_byte(i->seg(), eaddr, result_8);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SETNZ_EbR(bxInstruction_c *i)
{
BX_WRITE_8BIT_REGx(i->rm(), i->extend8bitL(), !getB_ZF());
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SETBE_EbM(bxInstruction_c *i)
{
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
Bit8u result_8 = (getB_CF() | getB_ZF());
write_virtual_byte(i->seg(), eaddr, result_8);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SETBE_EbR(bxInstruction_c *i)
{
BX_WRITE_8BIT_REGx(i->rm(), i->extend8bitL(), (getB_CF() | getB_ZF()));
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SETNBE_EbM(bxInstruction_c *i)
{
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
Bit8u result_8 = !(getB_CF() | getB_ZF());
write_virtual_byte(i->seg(), eaddr, result_8);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SETNBE_EbR(bxInstruction_c *i)
{
BX_WRITE_8BIT_REGx(i->rm(), i->extend8bitL(), !(getB_CF() | getB_ZF()));
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SETS_EbM(bxInstruction_c *i)
{
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
Bit8u result_8 = getB_SF();
write_virtual_byte(i->seg(), eaddr, result_8);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SETS_EbR(bxInstruction_c *i)
{
BX_WRITE_8BIT_REGx(i->rm(), i->extend8bitL(), getB_SF());
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SETNS_EbM(bxInstruction_c *i)
{
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
Bit8u result_8 = !getB_SF();
write_virtual_byte(i->seg(), eaddr, result_8);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SETNS_EbR(bxInstruction_c *i)
{
BX_WRITE_8BIT_REGx(i->rm(), i->extend8bitL(), !getB_SF());
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SETP_EbM(bxInstruction_c *i)
{
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
Bit8u result_8 = getB_PF();
write_virtual_byte(i->seg(), eaddr, result_8);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SETP_EbR(bxInstruction_c *i)
{
BX_WRITE_8BIT_REGx(i->rm(), i->extend8bitL(), getB_PF());
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SETNP_EbM(bxInstruction_c *i)
{
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
Bit8u result_8 = !getB_PF();
write_virtual_byte(i->seg(), eaddr, result_8);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SETNP_EbR(bxInstruction_c *i)
{
BX_WRITE_8BIT_REGx(i->rm(), i->extend8bitL(), !getB_PF());
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SETL_EbM(bxInstruction_c *i)
{
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
Bit8u result_8 = (getB_SF() ^ getB_OF());
write_virtual_byte(i->seg(), eaddr, result_8);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SETL_EbR(bxInstruction_c *i)
{
BX_WRITE_8BIT_REGx(i->rm(), i->extend8bitL(), (getB_SF() ^ getB_OF()));
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SETNL_EbM(bxInstruction_c *i)
{
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
Bit8u result_8 = !(getB_SF() ^ getB_OF());
write_virtual_byte(i->seg(), eaddr, result_8);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SETNL_EbR(bxInstruction_c *i)
{
BX_WRITE_8BIT_REGx(i->rm(), i->extend8bitL(), !(getB_SF() ^ getB_OF()));
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SETLE_EbM(bxInstruction_c *i)
{
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
Bit8u result_8 = getB_ZF() | (getB_SF() ^ getB_OF());
write_virtual_byte(i->seg(), eaddr, result_8);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SETLE_EbR(bxInstruction_c *i)
{
Bit8u result_8 = getB_ZF() | (getB_SF() ^ getB_OF());
BX_WRITE_8BIT_REGx(i->rm(), i->extend8bitL(), result_8);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SETNLE_EbM(bxInstruction_c *i)
{
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
Bit8u result_8 = !(getB_ZF() | (getB_SF() ^ getB_OF()));
write_virtual_byte(i->seg(), eaddr, result_8);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SETNLE_EbR(bxInstruction_c *i)
{
Bit8u result_8 = !(getB_ZF() | (getB_SF() ^ getB_OF()));
BX_WRITE_8BIT_REGx(i->rm(), i->extend8bitL(), result_8);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::BSWAP_RX(bxInstruction_c *i)
{
BX_ERROR(("BSWAP with 16-bit opsize: undefined behavior !"));
BX_WRITE_16BIT_REG(i->rm(), 0);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::BSWAP_ERX(bxInstruction_c *i)
{
Bit32u val32 = BX_READ_32BIT_REG(i->rm());
BX_WRITE_32BIT_REGZ(i->rm(), bx_bswap32(val32));
}
#if BX_SUPPORT_X86_64
void BX_CPP_AttrRegparmN(1) BX_CPU_C::BSWAP_RRX(bxInstruction_c *i)
{
Bit64u val64 = BX_READ_64BIT_REG(i->rm());
BX_WRITE_64BIT_REG(i->rm(), bx_bswap64(val64));
}
#endif
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOVBE_GwEwR(bxInstruction_c *i)
{
Bit16u val16 = BX_READ_16BIT_REG(i->rm()), b0, b1;
b0 = val16 & 0xff; val16 >>= 8;
b1 = val16;
val16 = (b0<<8) | b1;
BX_WRITE_16BIT_REG(i->nnn(), val16);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOVBE_EwGw(bxInstruction_c *i)
{
Bit16u val16 = BX_READ_16BIT_REG(i->nnn()), b0, b1;
b0 = val16 & 0xff; val16 >>= 8;
b1 = val16;
val16 = (b0<<8) | b1;
if (i->modC0()) {
BX_WRITE_16BIT_REG(i->rm(), val16);
}
else {
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
write_virtual_word(i->seg(), eaddr, val16);
}
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOVBE_GdEdR(bxInstruction_c *i)
{
Bit32u val32 = BX_READ_32BIT_REG(i->rm());
BX_WRITE_32BIT_REGZ(i->nnn(), bx_bswap32(val32));
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOVBE_EdGd(bxInstruction_c *i)
{
Bit32u val32 = BX_READ_32BIT_REG(i->nnn());
val32 = bx_bswap32(val32);
if (i->modC0()) {
BX_WRITE_32BIT_REGZ(i->rm(), val32);
}
else {
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
write_virtual_dword(i->seg(), eaddr, val32);
}
}
#if BX_SUPPORT_X86_64
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOVBE_GqEqR(bxInstruction_c *i)
{
Bit64u val64 = BX_READ_64BIT_REG(i->rm());
BX_WRITE_64BIT_REG(i->nnn(), bx_bswap64(val64));
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOVBE_EqGq(bxInstruction_c *i)
{
Bit64u val64 = BX_READ_64BIT_REG(i->nnn());
val64 = bx_bswap64(val64);
if (i->modC0()) {
BX_WRITE_64BIT_REG(i->rm(), val64);
}
else {
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
write_virtual_qword_64(i->seg(), eaddr, val64);
}
}
#endif // BX_SUPPORT_X86_64
#endif // BX_CPU_LEVEL >= 3

327
simulators/bochs/cpu/bit16.cc Executable file
View File

@ -0,0 +1,327 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2001-2009 The Bochs Project
//
// 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
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA B 02110-1301 USA
/////////////////////////////////////////////////////////////////////////
#define NEED_CPU_REG_SHORTCUTS 1
#include "bochs.h"
#include "cpu.h"
#define LOG_THIS BX_CPU_THIS_PTR
#if BX_CPU_LEVEL >= 3
void BX_CPP_AttrRegparmN(1) BX_CPU_C::BSF_GwEwR(bxInstruction_c *i)
{
Bit16u op2_16 = BX_READ_16BIT_REG(i->rm());
if (op2_16 == 0) {
assert_ZF(); /* op1_16 undefined */
}
else {
Bit16u op1_16 = 0;
while ((op2_16 & 0x01) == 0) {
op1_16++;
op2_16 >>= 1;
}
SET_FLAGS_OSZAPC_LOGIC_16(op1_16);
clear_ZF();
/* now write result back to destination */
BX_WRITE_16BIT_REG(i->nnn(), op1_16);
}
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::BSR_GwEwR(bxInstruction_c *i)
{
Bit16u op2_16 = BX_READ_16BIT_REG(i->rm());
if (op2_16 == 0) {
assert_ZF(); /* op1_16 undefined */
}
else {
Bit16u op1_16 = 15;
while ((op2_16 & 0x8000) == 0) {
op1_16--;
op2_16 <<= 1;
}
SET_FLAGS_OSZAPC_LOGIC_16(op1_16);
clear_ZF();
/* now write result back to destination */
BX_WRITE_16BIT_REG(i->nnn(), op1_16);
}
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::BT_EwGwM(bxInstruction_c *i)
{
bx_address op1_addr;
Bit16u op1_16, op2_16, index;
Bit32s displacement32;
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
op2_16 = BX_READ_16BIT_REG(i->nnn());
index = op2_16 & 0x0f;
displacement32 = ((Bit16s) (op2_16&0xfff0)) / 16;
op1_addr = eaddr + 2 * displacement32;
/* pointer, segment address pair */
op1_16 = read_virtual_word(i->seg(), op1_addr & i->asize_mask());
set_CF((op1_16 >> index) & 0x01);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::BT_EwGwR(bxInstruction_c *i)
{
Bit16u op1_16, op2_16;
op1_16 = BX_READ_16BIT_REG(i->rm());
op2_16 = BX_READ_16BIT_REG(i->nnn());
op2_16 &= 0x0f;
set_CF((op1_16 >> op2_16) & 0x01);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::BTS_EwGwM(bxInstruction_c *i)
{
bx_address op1_addr;
Bit16u op1_16, op2_16, index;
Bit32s displacement32;
bx_bool bit_i;
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
op2_16 = BX_READ_16BIT_REG(i->nnn());
index = op2_16 & 0x0f;
displacement32 = ((Bit16s) (op2_16 & 0xfff0)) / 16;
op1_addr = eaddr + 2 * displacement32;
/* pointer, segment address pair */
op1_16 = read_RMW_virtual_word(i->seg(), op1_addr & i->asize_mask());
bit_i = (op1_16 >> index) & 0x01;
op1_16 |= (((Bit16u) 1) << index);
write_RMW_virtual_word(op1_16);
set_CF(bit_i);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::BTS_EwGwR(bxInstruction_c *i)
{
Bit16u op1_16, op2_16;
op1_16 = BX_READ_16BIT_REG(i->rm());
op2_16 = BX_READ_16BIT_REG(i->nnn());
op2_16 &= 0x0f;
set_CF((op1_16 >> op2_16) & 0x01);
op1_16 |= (((Bit16u) 1) << op2_16);
/* now write result back to the destination */
BX_WRITE_16BIT_REG(i->rm(), op1_16);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::BTR_EwGwM(bxInstruction_c *i)
{
bx_address op1_addr;
Bit16u op1_16, op2_16, index;
Bit32s displacement32;
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
op2_16 = BX_READ_16BIT_REG(i->nnn());
index = op2_16 & 0x0f;
displacement32 = ((Bit16s) (op2_16&0xfff0)) / 16;
op1_addr = eaddr + 2 * displacement32;
/* pointer, segment address pair */
op1_16 = read_RMW_virtual_word(i->seg(), op1_addr & i->asize_mask());
bx_bool temp_cf = (op1_16 >> index) & 0x01;
op1_16 &= ~(((Bit16u) 1) << index);
/* now write back to destination */
write_RMW_virtual_word(op1_16);
set_CF(temp_cf);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::BTR_EwGwR(bxInstruction_c *i)
{
Bit16u op1_16, op2_16;
op1_16 = BX_READ_16BIT_REG(i->rm());
op2_16 = BX_READ_16BIT_REG(i->nnn());
op2_16 &= 0x0f;
set_CF((op1_16 >> op2_16) & 0x01);
op1_16 &= ~(((Bit16u) 1) << op2_16);
/* now write result back to the destination */
BX_WRITE_16BIT_REG(i->rm(), op1_16);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::BTC_EwGwM(bxInstruction_c *i)
{
bx_address op1_addr;
Bit16u op1_16, op2_16, index_16;
Bit16s displacement16;
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
op2_16 = BX_READ_16BIT_REG(i->nnn());
index_16 = op2_16 & 0x0f;
displacement16 = ((Bit16s) (op2_16 & 0xfff0)) / 16;
op1_addr = eaddr + 2 * displacement16;
op1_16 = read_RMW_virtual_word(i->seg(), op1_addr & i->asize_mask());
bx_bool temp_CF = (op1_16 >> index_16) & 0x01;
op1_16 ^= (((Bit16u) 1) << index_16); /* toggle bit */
write_RMW_virtual_word(op1_16);
set_CF(temp_CF);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::BTC_EwGwR(bxInstruction_c *i)
{
Bit16u op1_16, op2_16;
op1_16 = BX_READ_16BIT_REG(i->rm());
op2_16 = BX_READ_16BIT_REG(i->nnn());
op2_16 &= 0x0f;
bx_bool temp_CF = (op1_16 >> op2_16) & 0x01;
op1_16 ^= (((Bit16u) 1) << op2_16); /* toggle bit */
BX_WRITE_16BIT_REG(i->rm(), op1_16);
set_CF(temp_CF);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::BT_EwIbM(bxInstruction_c *i)
{
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
Bit16u op1_16 = read_virtual_word(i->seg(), eaddr);
Bit8u op2_8 = i->Ib() & 0xf;
set_CF((op1_16 >> op2_8) & 0x01);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::BT_EwIbR(bxInstruction_c *i)
{
Bit16u op1_16 = BX_READ_16BIT_REG(i->rm());
Bit8u op2_8 = i->Ib() & 0xf;
set_CF((op1_16 >> op2_8) & 0x01);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::BTS_EwIbM(bxInstruction_c *i)
{
Bit8u op2_8 = i->Ib() & 0xf;
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
Bit16u op1_16 = read_RMW_virtual_word(i->seg(), eaddr);
bx_bool temp_CF = (op1_16 >> op2_8) & 0x01;
op1_16 |= (((Bit16u) 1) << op2_8);
write_RMW_virtual_word(op1_16);
set_CF(temp_CF);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::BTS_EwIbR(bxInstruction_c *i)
{
Bit8u op2_8 = i->Ib() & 0xf;
Bit16u op1_16 = BX_READ_16BIT_REG(i->rm());
bx_bool temp_CF = (op1_16 >> op2_8) & 0x01;
op1_16 |= (((Bit16u) 1) << op2_8);
BX_WRITE_16BIT_REG(i->rm(), op1_16);
set_CF(temp_CF);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::BTC_EwIbM(bxInstruction_c *i)
{
Bit8u op2_8 = i->Ib() & 0xf;
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
Bit16u op1_16 = read_RMW_virtual_word(i->seg(), eaddr);
bx_bool temp_CF = (op1_16 >> op2_8) & 0x01;
op1_16 ^= (((Bit16u) 1) << op2_8); /* toggle bit */
write_RMW_virtual_word(op1_16);
set_CF(temp_CF);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::BTC_EwIbR(bxInstruction_c *i)
{
Bit8u op2_8 = i->Ib() & 0xf;
Bit16u op1_16 = BX_READ_16BIT_REG(i->rm());
bx_bool temp_CF = (op1_16 >> op2_8) & 0x01;
op1_16 ^= (((Bit16u) 1) << op2_8); /* toggle bit */
BX_WRITE_16BIT_REG(i->rm(), op1_16);
set_CF(temp_CF);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::BTR_EwIbM(bxInstruction_c *i)
{
Bit8u op2_8 = i->Ib() & 0xf;
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
Bit16u op1_16 = read_RMW_virtual_word(i->seg(), eaddr);
bx_bool temp_CF = (op1_16 >> op2_8) & 0x01;
op1_16 &= ~(((Bit16u) 1) << op2_8);
write_RMW_virtual_word(op1_16);
set_CF(temp_CF);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::BTR_EwIbR(bxInstruction_c *i)
{
Bit8u op2_8 = i->Ib() & 0xf;
Bit16u op1_16 = BX_READ_16BIT_REG(i->rm());
bx_bool temp_CF = (op1_16 >> op2_8) & 0x01;
op1_16 &= ~(((Bit16u) 1) << op2_8);
BX_WRITE_16BIT_REG(i->rm(), op1_16);
set_CF(temp_CF);
}
/* F3 0F B8 */
void BX_CPP_AttrRegparmN(1) BX_CPU_C::POPCNT_GwEwR(bxInstruction_c *i)
{
Bit16u op2_16 = BX_READ_16BIT_REG(i->rm());
Bit16u op1_16 = 0;
while (op2_16 != 0) {
if (op2_16 & 1) op1_16++;
op2_16 >>= 1;
}
Bit32u flags = op1_16 ? 0 : EFlagsZFMask;
setEFlagsOSZAPC(flags);
/* now write result back to destination */
BX_WRITE_16BIT_REG(i->nnn(), op1_16);
}
#endif // (BX_CPU_LEVEL >= 3)

332
simulators/bochs/cpu/bit32.cc Executable file
View File

@ -0,0 +1,332 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2001-2009 The Bochs Project
//
// 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
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA B 02110-1301 USA
/////////////////////////////////////////////////////////////////////////
#define NEED_CPU_REG_SHORTCUTS 1
#include "bochs.h"
#include "cpu.h"
#define LOG_THIS BX_CPU_THIS_PTR
#if BX_CPU_LEVEL >= 3
void BX_CPP_AttrRegparmN(1) BX_CPU_C::BSF_GdEdR(bxInstruction_c *i)
{
Bit32u op2_32 = BX_READ_32BIT_REG(i->rm());
if (op2_32 == 0) {
assert_ZF(); /* op1_32 undefined */
}
else {
Bit32u op1_32 = 0;
while ((op2_32 & 0x01) == 0) {
op1_32++;
op2_32 >>= 1;
}
SET_FLAGS_OSZAPC_LOGIC_32(op1_32);
clear_ZF();
/* now write result back to destination */
BX_WRITE_32BIT_REGZ(i->nnn(), op1_32);
}
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::BSR_GdEdR(bxInstruction_c *i)
{
Bit32u op2_32 = BX_READ_32BIT_REG(i->rm());
if (op2_32 == 0) {
assert_ZF(); /* op1_32 undefined */
}
else {
Bit32u op1_32 = 31;
while ((op2_32 & 0x80000000) == 0) {
op1_32--;
op2_32 <<= 1;
}
SET_FLAGS_OSZAPC_LOGIC_32(op1_32);
clear_ZF();
/* now write result back to destination */
BX_WRITE_32BIT_REGZ(i->nnn(), op1_32);
}
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::BT_EdGdM(bxInstruction_c *i)
{
bx_address op1_addr;
Bit32u op1_32, op2_32, index;
Bit32s displacement32;
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
op2_32 = BX_READ_32BIT_REG(i->nnn());
index = op2_32 & 0x1f;
displacement32 = ((Bit32s) (op2_32&0xffffffe0)) / 32;
op1_addr = eaddr + 4 * displacement32;
/* pointer, segment address pair */
op1_32 = read_virtual_dword(i->seg(), op1_addr & i->asize_mask());
set_CF((op1_32 >> index) & 0x01);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::BT_EdGdR(bxInstruction_c *i)
{
Bit32u op1_32, op2_32;
op1_32 = BX_READ_32BIT_REG(i->rm());
op2_32 = BX_READ_32BIT_REG(i->nnn());
op2_32 &= 0x1f;
set_CF((op1_32 >> op2_32) & 0x01);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::BTS_EdGdM(bxInstruction_c *i)
{
bx_address op1_addr;
Bit32u op1_32, op2_32, index;
Bit32s displacement32;
bx_bool bit_i;
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
op2_32 = BX_READ_32BIT_REG(i->nnn());
index = op2_32 & 0x1f;
displacement32 = ((Bit32s) (op2_32&0xffffffe0)) / 32;
op1_addr = eaddr + 4 * displacement32;
/* pointer, segment address pair */
op1_32 = read_RMW_virtual_dword(i->seg(), op1_addr & i->asize_mask());
bit_i = (op1_32 >> index) & 0x01;
op1_32 |= (((Bit32u) 1) << index);
write_RMW_virtual_dword(op1_32);
set_CF(bit_i);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::BTS_EdGdR(bxInstruction_c *i)
{
Bit32u op1_32, op2_32;
op1_32 = BX_READ_32BIT_REG(i->rm());
op2_32 = BX_READ_32BIT_REG(i->nnn());
op2_32 &= 0x1f;
set_CF((op1_32 >> op2_32) & 0x01);
op1_32 |= (((Bit32u) 1) << op2_32);
/* now write result back to the destination */
BX_WRITE_32BIT_REGZ(i->rm(), op1_32);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::BTR_EdGdM(bxInstruction_c *i)
{
bx_address op1_addr;
Bit32u op1_32, op2_32, index;
Bit32s displacement32;
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
op2_32 = BX_READ_32BIT_REG(i->nnn());
index = op2_32 & 0x1f;
displacement32 = ((Bit32s) (op2_32&0xffffffe0)) / 32;
op1_addr = eaddr + 4 * displacement32;
/* pointer, segment address pair */
op1_32 = read_RMW_virtual_dword(i->seg(), op1_addr & i->asize_mask());
bx_bool temp_cf = (op1_32 >> index) & 0x01;
op1_32 &= ~(((Bit32u) 1) << index);
/* now write back to destination */
write_RMW_virtual_dword(op1_32);
set_CF(temp_cf);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::BTR_EdGdR(bxInstruction_c *i)
{
Bit32u op1_32, op2_32;
op1_32 = BX_READ_32BIT_REG(i->rm());
op2_32 = BX_READ_32BIT_REG(i->nnn());
op2_32 &= 0x1f;
set_CF((op1_32 >> op2_32) & 0x01);
op1_32 &= ~(((Bit32u) 1) << op2_32);
/* now write result back to the destination */
BX_WRITE_32BIT_REGZ(i->rm(), op1_32);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::BTC_EdGdM(bxInstruction_c *i)
{
bx_address op1_addr;
Bit32u op1_32, op2_32, index_32;
Bit32s displacement32;
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
op2_32 = BX_READ_32BIT_REG(i->nnn());
index_32 = op2_32 & 0x1f;
displacement32 = ((Bit32s) (op2_32 & 0xffffffe0)) / 32;
op1_addr = eaddr + 4 * displacement32;
op1_32 = read_RMW_virtual_dword(i->seg(), op1_addr & i->asize_mask());
bx_bool temp_CF = (op1_32 >> index_32) & 0x01;
op1_32 ^= (((Bit32u) 1) << index_32); /* toggle bit */
set_CF(temp_CF);
write_RMW_virtual_dword(op1_32);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::BTC_EdGdR(bxInstruction_c *i)
{
Bit32u op1_32, op2_32;
op1_32 = BX_READ_32BIT_REG(i->rm());
op2_32 = BX_READ_32BIT_REG(i->nnn());
op2_32 &= 0x1f;
bx_bool temp_CF = (op1_32 >> op2_32) & 0x01;
op1_32 ^= (((Bit32u) 1) << op2_32); /* toggle bit */
set_CF(temp_CF);
BX_WRITE_32BIT_REGZ(i->rm(), op1_32);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::BT_EdIbM(bxInstruction_c *i)
{
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
Bit32u op1_32 = read_virtual_dword(i->seg(), eaddr);
Bit8u op2_8 = i->Ib() & 0x1f;
set_CF((op1_32 >> op2_8) & 0x01);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::BT_EdIbR(bxInstruction_c *i)
{
Bit32u op1_32 = BX_READ_32BIT_REG(i->rm());
Bit8u op2_8 = i->Ib() & 0x1f;
set_CF((op1_32 >> op2_8) & 0x01);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::BTS_EdIbM(bxInstruction_c *i)
{
Bit8u op2_8 = i->Ib() & 0x1f;
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
Bit32u op1_32 = read_RMW_virtual_dword(i->seg(), eaddr);
bx_bool temp_CF = (op1_32 >> op2_8) & 0x01;
op1_32 |= (((Bit32u) 1) << op2_8);
write_RMW_virtual_dword(op1_32);
set_CF(temp_CF);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::BTS_EdIbR(bxInstruction_c *i)
{
Bit8u op2_8 = i->Ib() & 0x1f;
Bit32u op1_32 = BX_READ_32BIT_REG(i->rm());
bx_bool temp_CF = (op1_32 >> op2_8) & 0x01;
op1_32 |= (((Bit32u) 1) << op2_8);
BX_WRITE_32BIT_REGZ(i->rm(), op1_32);
set_CF(temp_CF);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::BTC_EdIbM(bxInstruction_c *i)
{
Bit8u op2_8 = i->Ib() & 0x1f;
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
Bit32u op1_32 = read_RMW_virtual_dword(i->seg(), eaddr);
bx_bool temp_CF = (op1_32 >> op2_8) & 0x01;
op1_32 ^= (((Bit32u) 1) << op2_8); /* toggle bit */
write_RMW_virtual_dword(op1_32);
set_CF(temp_CF);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::BTC_EdIbR(bxInstruction_c *i)
{
Bit8u op2_8 = i->Ib() & 0x1f;
Bit32u op1_32 = BX_READ_32BIT_REG(i->rm());
bx_bool temp_CF = (op1_32 >> op2_8) & 0x01;
op1_32 ^= (((Bit32u) 1) << op2_8); /* toggle bit */
BX_WRITE_32BIT_REGZ(i->rm(), op1_32);
set_CF(temp_CF);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::BTR_EdIbM(bxInstruction_c *i)
{
Bit8u op2_8 = i->Ib() & 0x1f;
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
Bit32u op1_32 = read_RMW_virtual_dword(i->seg(), eaddr);
bx_bool temp_CF = (op1_32 >> op2_8) & 0x01;
op1_32 &= ~(((Bit32u) 1) << op2_8);
write_RMW_virtual_dword(op1_32);
set_CF(temp_CF);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::BTR_EdIbR(bxInstruction_c *i)
{
Bit8u op2_8 = i->Ib() & 0x1f;
Bit32u op1_32 = BX_READ_32BIT_REG(i->rm());
bx_bool temp_CF = (op1_32 >> op2_8) & 0x01;
op1_32 &= ~(((Bit32u) 1) << op2_8);
BX_WRITE_32BIT_REGZ(i->rm(), op1_32);
set_CF(temp_CF);
}
/* F3 0F B8 */
void BX_CPP_AttrRegparmN(1) BX_CPU_C::POPCNT_GdEdR(bxInstruction_c *i)
{
Bit32u op2_32 = BX_READ_32BIT_REG(i->rm());
Bit32u op1_32 = 0;
while (op2_32 != 0) {
if (op2_32 & 1) op1_32++;
op2_32 >>= 1;
}
Bit32u flags = op1_32 ? 0 : EFlagsZFMask;
setEFlagsOSZAPC(flags);
/* now write result back to destination */
BX_WRITE_32BIT_REGZ(i->nnn(), op1_32);
}
#endif // (BX_CPU_LEVEL >= 3)

336
simulators/bochs/cpu/bit64.cc Executable file
View File

@ -0,0 +1,336 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2001-2009 The Bochs Project
//
// 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
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA B 02110-1301 USA
/////////////////////////////////////////////////////////////////////////
#define NEED_CPU_REG_SHORTCUTS 1
#include "bochs.h"
#include "cpu.h"
#define LOG_THIS BX_CPU_THIS_PTR
#if BX_SUPPORT_X86_64
void BX_CPP_AttrRegparmN(1) BX_CPU_C::BSF_GqEqR(bxInstruction_c *i)
{
Bit64u op2_64 = BX_READ_64BIT_REG(i->rm());
if (op2_64 == 0) {
assert_ZF(); /* op1_64 undefined */
}
else {
Bit64u op1_64 = 0;
while ((op2_64 & 0x01) == 0) {
op1_64++;
op2_64 >>= 1;
}
SET_FLAGS_OSZAPC_LOGIC_64(op1_64);
clear_ZF();
/* now write result back to destination */
BX_WRITE_64BIT_REG(i->nnn(), op1_64);
}
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::BSR_GqEqR(bxInstruction_c *i)
{
Bit64u op2_64 = BX_READ_64BIT_REG(i->rm());
if (op2_64 == 0) {
assert_ZF(); /* op1_64 undefined */
}
else {
Bit64u op1_64 = 63;
while ((op2_64 & BX_CONST64(0x8000000000000000)) == 0) {
op1_64--;
op2_64 <<= 1;
}
SET_FLAGS_OSZAPC_LOGIC_64(op1_64);
clear_ZF();
/* now write result back to destination */
BX_WRITE_64BIT_REG(i->nnn(), op1_64);
}
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::BT_EqGqM(bxInstruction_c *i)
{
bx_address op1_addr;
Bit64u op1_64, op2_64;
Bit64s displacement64;
Bit64u index;
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
op2_64 = BX_READ_64BIT_REG(i->nnn());
index = op2_64 & 0x3f;
displacement64 = ((Bit64s) (op2_64 & BX_CONST64(0xffffffffffffffc0))) / 64;
op1_addr = eaddr + 8 * displacement64;
if (! i->as64L())
op1_addr = (Bit32u) op1_addr;
/* pointer, segment address pair */
op1_64 = read_virtual_qword_64(i->seg(), op1_addr);
set_CF((op1_64 >> index) & 0x01);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::BT_EqGqR(bxInstruction_c *i)
{
Bit64u op1_64, op2_64;
op1_64 = BX_READ_64BIT_REG(i->rm());
op2_64 = BX_READ_64BIT_REG(i->nnn());
op2_64 &= 0x3f;
set_CF((op1_64 >> op2_64) & 0x01);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::BTS_EqGqM(bxInstruction_c *i)
{
bx_address op1_addr;
Bit64u op1_64, op2_64, index;
Bit64s displacement64;
bx_bool bit_i;
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
op2_64 = BX_READ_64BIT_REG(i->nnn());
index = op2_64 & 0x3f;
displacement64 = ((Bit64s) (op2_64 & BX_CONST64(0xffffffffffffffc0))) / 64;
op1_addr = eaddr + 8 * displacement64;
if (! i->as64L())
op1_addr = (Bit32u) op1_addr;
/* pointer, segment address pair */
op1_64 = read_RMW_virtual_qword_64(i->seg(), op1_addr);
bit_i = (op1_64 >> index) & 0x01;
op1_64 |= (((Bit64u) 1) << index);
write_RMW_virtual_qword(op1_64);
set_CF(bit_i);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::BTS_EqGqR(bxInstruction_c *i)
{
Bit64u op1_64, op2_64;
op1_64 = BX_READ_64BIT_REG(i->rm());
op2_64 = BX_READ_64BIT_REG(i->nnn());
op2_64 &= 0x3f;
set_CF((op1_64 >> op2_64) & 0x01);
op1_64 |= (((Bit64u) 1) << op2_64);
/* now write result back to the destination */
BX_WRITE_64BIT_REG(i->rm(), op1_64);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::BTR_EqGqM(bxInstruction_c *i)
{
bx_address op1_addr;
Bit64u op1_64, op2_64, index;
Bit64s displacement64;
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
op2_64 = BX_READ_64BIT_REG(i->nnn());
index = op2_64 & 0x3f;
displacement64 = ((Bit64s) (op2_64 & BX_CONST64(0xffffffffffffffc0))) / 64;
op1_addr = eaddr + 8 * displacement64;
if (! i->as64L())
op1_addr = (Bit32u) op1_addr;
/* pointer, segment address pair */
op1_64 = read_RMW_virtual_qword_64(i->seg(), op1_addr);
bx_bool temp_cf = (op1_64 >> index) & 0x01;
op1_64 &= ~(((Bit64u) 1) << index);
/* now write back to destination */
write_RMW_virtual_qword(op1_64);
set_CF(temp_cf);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::BTR_EqGqR(bxInstruction_c *i)
{
Bit64u op1_64, op2_64;
op1_64 = BX_READ_64BIT_REG(i->rm());
op2_64 = BX_READ_64BIT_REG(i->nnn());
op2_64 &= 0x3f;
set_CF((op1_64 >> op2_64) & 0x01);
op1_64 &= ~(((Bit64u) 1) << op2_64);
/* now write result back to the destination */
BX_WRITE_64BIT_REG(i->rm(), op1_64);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::BTC_EqGqM(bxInstruction_c *i)
{
bx_address op1_addr;
Bit64u op1_64, op2_64;
Bit64s displacement64;
Bit64u index;
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
op2_64 = BX_READ_64BIT_REG(i->nnn());
index = op2_64 & 0x3f;
displacement64 = ((Bit64s) (op2_64 & BX_CONST64(0xffffffffffffffc0))) / 64;
op1_addr = eaddr + 8 * displacement64;
if (! i->as64L())
op1_addr = (Bit32u) op1_addr;
op1_64 = read_RMW_virtual_qword_64(i->seg(), op1_addr);
bx_bool temp_CF = (op1_64 >> index) & 0x01;
op1_64 ^= (((Bit64u) 1) << index); /* toggle bit */
set_CF(temp_CF);
write_RMW_virtual_qword(op1_64);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::BTC_EqGqR(bxInstruction_c *i)
{
Bit64u op1_64, op2_64;
op1_64 = BX_READ_64BIT_REG(i->rm());
op2_64 = BX_READ_64BIT_REG(i->nnn());
op2_64 &= 0x3f;
bx_bool temp_CF = (op1_64 >> op2_64) & 0x01;
op1_64 ^= (((Bit64u) 1) << op2_64); /* toggle bit */
set_CF(temp_CF);
BX_WRITE_64BIT_REG(i->rm(), op1_64);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::BT_EqIbM(bxInstruction_c *i)
{
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
Bit64u op1_64 = read_virtual_qword_64(i->seg(), eaddr);
Bit8u op2_8 = i->Ib() & 0x3f;
set_CF((op1_64 >> op2_8) & 0x01);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::BT_EqIbR(bxInstruction_c *i)
{
Bit64u op1_64 = BX_READ_64BIT_REG(i->rm());
Bit8u op2_8 = i->Ib() & 0x3f;
set_CF((op1_64 >> op2_8) & 0x01);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::BTS_EqIbM(bxInstruction_c *i)
{
Bit8u op2_8 = i->Ib() & 0x3f;
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
Bit64u op1_64 = read_RMW_virtual_qword_64(i->seg(), eaddr);
bx_bool temp_CF = (op1_64 >> op2_8) & 0x01;
op1_64 |= (((Bit64u) 1) << op2_8);
write_RMW_virtual_qword(op1_64);
set_CF(temp_CF);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::BTS_EqIbR(bxInstruction_c *i)
{
Bit8u op2_8 = i->Ib() & 0x3f;
Bit64u op1_64 = BX_READ_64BIT_REG(i->rm());
bx_bool temp_CF = (op1_64 >> op2_8) & 0x01;
op1_64 |= (((Bit64u) 1) << op2_8);
BX_WRITE_64BIT_REG(i->rm(), op1_64);
set_CF(temp_CF);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::BTC_EqIbM(bxInstruction_c *i)
{
Bit8u op2_8 = i->Ib() & 0x3f;
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
Bit64u op1_64 = read_RMW_virtual_qword_64(i->seg(), eaddr);
bx_bool temp_CF = (op1_64 >> op2_8) & 0x01;
op1_64 ^= (((Bit64u) 1) << op2_8); /* toggle bit */
write_RMW_virtual_qword(op1_64);
set_CF(temp_CF);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::BTC_EqIbR(bxInstruction_c *i)
{
Bit8u op2_8 = i->Ib() & 0x3f;
Bit64u op1_64 = BX_READ_64BIT_REG(i->rm());
bx_bool temp_CF = (op1_64 >> op2_8) & 0x01;
op1_64 ^= (((Bit64u) 1) << op2_8); /* toggle bit */
BX_WRITE_64BIT_REG(i->rm(), op1_64);
set_CF(temp_CF);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::BTR_EqIbM(bxInstruction_c *i)
{
Bit8u op2_8 = i->Ib() & 0x3f;
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
Bit64u op1_64 = read_RMW_virtual_qword_64(i->seg(), eaddr);
bx_bool temp_CF = (op1_64 >> op2_8) & 0x01;
op1_64 &= ~(((Bit64u) 1) << op2_8);
write_RMW_virtual_qword(op1_64);
set_CF(temp_CF);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::BTR_EqIbR(bxInstruction_c *i)
{
Bit8u op2_8 = i->Ib() & 0x3f;
Bit64u op1_64 = BX_READ_64BIT_REG(i->rm());
bx_bool temp_CF = (op1_64 >> op2_8) & 0x01;
op1_64 &= ~(((Bit64u) 1) << op2_8);
BX_WRITE_64BIT_REG(i->rm(), op1_64);
set_CF(temp_CF);
}
/* F3 0F B8 */
void BX_CPP_AttrRegparmN(1) BX_CPU_C::POPCNT_GqEqR(bxInstruction_c *i)
{
Bit64u op2_64 = BX_READ_64BIT_REG(i->rm());
Bit64u op1_64 = 0;
while (op2_64 != 0) {
if (op2_64 & 1) op1_64++;
op2_64 >>= 1;
}
Bit32u flags = op1_64 ? 0 : EFlagsZFMask;
setEFlagsOSZAPC(flags);
/* now write result back to destination */
BX_WRITE_64BIT_REG(i->nnn(), op1_64);
}
#endif // BX_SUPPORT_X86_64

570
simulators/bochs/cpu/call_far.cc Executable file
View File

@ -0,0 +1,570 @@
////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2005-2009 Stanislav Shwartsman
// 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
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA B 02110-1301 USA
//
/////////////////////////////////////////////////////////////////////////
#define NEED_CPU_REG_SHORTCUTS 1
#include "bochs.h"
#include "cpu.h"
#define LOG_THIS BX_CPU_THIS_PTR
#if BX_SUPPORT_X86_64==0
// Make life easier merging cpu64 & cpu code.
#define RIP EIP
#endif
void BX_CPP_AttrRegparmN(3)
BX_CPU_C::call_protected(bxInstruction_c *i, Bit16u cs_raw, bx_address disp)
{
bx_selector_t cs_selector;
Bit32u dword1, dword2;
bx_descriptor_t cs_descriptor;
/* new cs selector must not be null, else #GP(0) */
if ((cs_raw & 0xfffc) == 0) {
BX_ERROR(("call_protected: CS selector null"));
exception(BX_GP_EXCEPTION, 0);
}
parse_selector(cs_raw, &cs_selector);
// check new CS selector index within its descriptor limits,
// else #GP(new CS selector)
fetch_raw_descriptor(&cs_selector, &dword1, &dword2, BX_GP_EXCEPTION);
parse_descriptor(dword1, dword2, &cs_descriptor);
// examine AR byte of selected descriptor for various legal values
if (cs_descriptor.valid==0) {
BX_ERROR(("call_protected: invalid CS descriptor"));
exception(BX_GP_EXCEPTION, cs_raw & 0xfffc);
}
if (cs_descriptor.segment) // normal segment
{
check_cs(&cs_descriptor, cs_raw, BX_SELECTOR_RPL(cs_raw), CPL);
#if BX_SUPPORT_X86_64
if (long_mode() && cs_descriptor.u.segment.l) {
Bit64u temp_rsp = RSP;
// moving to long mode, push return address onto 64-bit stack
if (i->os64L()) {
write_new_stack_qword_64(temp_rsp - 8, cs_descriptor.dpl,
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value);
write_new_stack_qword_64(temp_rsp - 16, cs_descriptor.dpl, RIP);
temp_rsp -= 16;
}
else if (i->os32L()) {
write_new_stack_dword_64(temp_rsp - 4, cs_descriptor.dpl,
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value);
write_new_stack_dword_64(temp_rsp - 8, cs_descriptor.dpl, EIP);
temp_rsp -= 8;
}
else {
write_new_stack_word_64(temp_rsp - 2, cs_descriptor.dpl,
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value);
write_new_stack_word_64(temp_rsp - 4, cs_descriptor.dpl, IP);
temp_rsp -= 4;
}
// load code segment descriptor into CS cache
// load CS with new code segment selector
// set RPL of CS to CPL
branch_far64(&cs_selector, &cs_descriptor, disp, CPL);
RSP = temp_rsp;
}
else
#endif
{
Bit32u temp_RSP;
// moving to legacy mode, push return address onto 32-bit stack
if (BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.d_b)
temp_RSP = ESP;
else
temp_RSP = SP;
#if BX_SUPPORT_X86_64
if (i->os64L()) {
write_new_stack_qword_32(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS],
temp_RSP - 8, cs_descriptor.dpl,
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value);
write_new_stack_qword_32(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS],
temp_RSP - 16, cs_descriptor.dpl, RIP);
temp_RSP -= 16;
}
else
#endif
if (i->os32L()) {
write_new_stack_dword_32(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS],
temp_RSP - 4, cs_descriptor.dpl,
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value);
write_new_stack_dword_32(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS],
temp_RSP - 8, cs_descriptor.dpl, EIP);
temp_RSP -= 8;
}
else {
write_new_stack_word_32(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS],
temp_RSP - 2, cs_descriptor.dpl,
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value);
write_new_stack_word_32(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS],
temp_RSP - 4, cs_descriptor.dpl, IP);
temp_RSP -= 4;
}
// load code segment descriptor into CS cache
// load CS with new code segment selector
// set RPL of CS to CPL
branch_far64(&cs_selector, &cs_descriptor, disp, CPL);
if (BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.d_b)
ESP = (Bit32u) temp_RSP;
else
SP = (Bit16u) temp_RSP;
}
return;
}
else { // gate & special segment
bx_descriptor_t gate_descriptor = cs_descriptor;
bx_selector_t gate_selector = cs_selector;
// descriptor DPL must be >= CPL else #GP(gate selector)
if (gate_descriptor.dpl < CPL) {
BX_ERROR(("call_protected: descriptor.dpl < CPL"));
exception(BX_GP_EXCEPTION, cs_raw & 0xfffc);
}
// descriptor DPL must be >= gate selector RPL else #GP(gate selector)
if (gate_descriptor.dpl < gate_selector.rpl) {
BX_ERROR(("call_protected: descriptor.dpl < selector.rpl"));
exception(BX_GP_EXCEPTION, cs_raw & 0xfffc);
}
#if BX_SUPPORT_X86_64
if (long_mode()) {
// call gate type is higher priority than non-present bit check
if (gate_descriptor.type != BX_386_CALL_GATE) {
BX_ERROR(("call_protected: gate type %u unsupported in long mode", (unsigned) gate_descriptor.type));
exception(BX_GP_EXCEPTION, cs_raw & 0xfffc);
}
// gate descriptor must be present else #NP(gate selector)
if (! IS_PRESENT(gate_descriptor)) {
BX_ERROR(("call_protected: call gate not present"));
exception(BX_NP_EXCEPTION, cs_raw & 0xfffc);
}
call_gate64(&gate_selector);
return;
}
#endif
switch (gate_descriptor.type) {
case BX_SYS_SEGMENT_AVAIL_286_TSS:
case BX_SYS_SEGMENT_AVAIL_386_TSS:
if (gate_descriptor.type==BX_SYS_SEGMENT_AVAIL_286_TSS)
BX_DEBUG(("call_protected: 16bit available TSS"));
else
BX_DEBUG(("call_protected: 32bit available TSS"));
if (gate_descriptor.valid==0 || gate_selector.ti) {
BX_ERROR(("call_protected: call bad TSS selector !"));
exception(BX_GP_EXCEPTION, cs_raw & 0xfffc);
}
// TSS must be present, else #NP(TSS selector)
if (! IS_PRESENT(gate_descriptor)) {
BX_ERROR(("call_protected: call not present TSS !"));
exception(BX_NP_EXCEPTION, cs_raw & 0xfffc);
}
// SWITCH_TASKS _without_ nesting to TSS
task_switch(i, &gate_selector, &gate_descriptor,
BX_TASK_FROM_CALL, dword1, dword2);
// EIP must be in code seg limit, else #GP(0)
if (EIP > BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.limit_scaled) {
BX_ERROR(("call_protected: EIP not within CS limits"));
exception(BX_GP_EXCEPTION, 0);
}
return;
case BX_TASK_GATE:
task_gate(i, &gate_selector, &gate_descriptor, BX_TASK_FROM_CALL);
return;
case BX_286_CALL_GATE:
case BX_386_CALL_GATE:
// gate descriptor must be present else #NP(gate selector)
if (! IS_PRESENT(gate_descriptor)) {
BX_ERROR(("call_protected: gate not present"));
exception(BX_NP_EXCEPTION, cs_raw & 0xfffc);
}
call_gate(&gate_descriptor);
return;
default: // can't get here
BX_ERROR(("call_protected(): gate.type(%u) unsupported", (unsigned) gate_descriptor.type));
exception(BX_GP_EXCEPTION, cs_raw & 0xfffc);
}
}
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::call_gate(bx_descriptor_t *gate_descriptor)
{
bx_selector_t cs_selector;
Bit32u dword1, dword2;
bx_descriptor_t cs_descriptor;
// examine code segment selector in call gate descriptor
BX_DEBUG(("call_protected: call gate"));
Bit16u dest_selector = gate_descriptor->u.gate.dest_selector;
Bit32u new_EIP = gate_descriptor->u.gate.dest_offset;
// selector must not be null else #GP(0)
if ((dest_selector & 0xfffc) == 0) {
BX_ERROR(("call_protected: selector in gate null"));
exception(BX_GP_EXCEPTION, 0);
}
parse_selector(dest_selector, &cs_selector);
// selector must be within its descriptor table limits,
// else #GP(code segment selector)
fetch_raw_descriptor(&cs_selector, &dword1, &dword2, BX_GP_EXCEPTION);
parse_descriptor(dword1, dword2, &cs_descriptor);
// AR byte of selected descriptor must indicate code segment,
// else #GP(code segment selector)
// DPL of selected descriptor must be <= CPL,
// else #GP(code segment selector)
if (cs_descriptor.valid==0 || cs_descriptor.segment==0 ||
IS_DATA_SEGMENT(cs_descriptor.type) || cs_descriptor.dpl > CPL)
{
BX_ERROR(("call_protected: selected descriptor is not code"));
exception(BX_GP_EXCEPTION, dest_selector & 0xfffc);
}
// code segment must be present else #NP(selector)
if (! IS_PRESENT(cs_descriptor)) {
BX_ERROR(("call_protected: code segment not present !"));
exception(BX_NP_EXCEPTION, dest_selector & 0xfffc);
}
// CALL GATE TO MORE PRIVILEGE
// if non-conforming code segment and DPL < CPL then
if (IS_CODE_SEGMENT_NON_CONFORMING(cs_descriptor.type) && (cs_descriptor.dpl < CPL))
{
Bit16u SS_for_cpl_x;
Bit32u ESP_for_cpl_x;
bx_selector_t ss_selector;
bx_descriptor_t ss_descriptor;
Bit16u return_SS, return_CS;
Bit32u return_ESP, return_EIP;
BX_DEBUG(("CALL GATE TO MORE PRIVILEGE LEVEL"));
// get new SS selector for new privilege level from TSS
get_SS_ESP_from_TSS(cs_descriptor.dpl, &SS_for_cpl_x, &ESP_for_cpl_x);
// check selector & descriptor for new SS:
// selector must not be null, else #TS(0)
if ((SS_for_cpl_x & 0xfffc) == 0) {
BX_ERROR(("call_protected: new SS null"));
exception(BX_TS_EXCEPTION, 0);
}
// selector index must be within its descriptor table limits,
// else #TS(SS selector)
parse_selector(SS_for_cpl_x, &ss_selector);
fetch_raw_descriptor(&ss_selector, &dword1, &dword2, BX_TS_EXCEPTION);
parse_descriptor(dword1, dword2, &ss_descriptor);
// selector's RPL must equal DPL of code segment,
// else #TS(SS selector)
if (ss_selector.rpl != cs_descriptor.dpl) {
BX_ERROR(("call_protected: SS selector.rpl != CS descr.dpl"));
exception(BX_TS_EXCEPTION, SS_for_cpl_x & 0xfffc);
}
// stack segment DPL must equal DPL of code segment,
// else #TS(SS selector)
if (ss_descriptor.dpl != cs_descriptor.dpl) {
BX_ERROR(("call_protected: SS descr.rpl != CS descr.dpl"));
exception(BX_TS_EXCEPTION, SS_for_cpl_x & 0xfffc);
}
// descriptor must indicate writable data segment,
// else #TS(SS selector)
if (ss_descriptor.valid==0 || ss_descriptor.segment==0 ||
IS_CODE_SEGMENT(ss_descriptor.type) || !IS_DATA_SEGMENT_WRITEABLE(ss_descriptor.type))
{
BX_ERROR(("call_protected: ss descriptor is not writable data seg"));
exception(BX_TS_EXCEPTION, SS_for_cpl_x & 0xfffc);
}
// segment must be present, else #SS(SS selector)
if (! IS_PRESENT(ss_descriptor)) {
BX_ERROR(("call_protected: ss descriptor not present"));
exception(BX_SS_EXCEPTION, SS_for_cpl_x & 0xfffc);
}
// get word count from call gate, mask to 5 bits
unsigned param_count = gate_descriptor->u.gate.param_count & 0x1f;
// save return SS:eSP to be pushed on new stack
return_SS = BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].selector.value;
if (BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.d_b)
return_ESP = ESP;
else
return_ESP = SP;
// save return CS:eIP to be pushed on new stack
return_CS = BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value;
if (cs_descriptor.u.segment.d_b)
return_EIP = EIP;
else
return_EIP = IP;
// Prepare new stack segment
bx_segment_reg_t new_stack;
new_stack.selector = ss_selector;
new_stack.cache = ss_descriptor;
new_stack.selector.rpl = cs_descriptor.dpl;
// add cpl to the selector value
new_stack.selector.value = (0xfffc & new_stack.selector.value) |
new_stack.selector.rpl;
/* load new SS:SP value from TSS */
if (ss_descriptor.u.segment.d_b) {
Bit32u temp_ESP = ESP_for_cpl_x;
// push pointer of old stack onto new stack
if (gate_descriptor->type==BX_386_CALL_GATE) {
write_new_stack_dword_32(&new_stack, temp_ESP-4, cs_descriptor.dpl, return_SS);
write_new_stack_dword_32(&new_stack, temp_ESP-8, cs_descriptor.dpl, return_ESP);
temp_ESP -= 8;
for (unsigned n=param_count; n>0; n--) {
temp_ESP -= 4;
Bit32u param = read_virtual_dword_32(BX_SEG_REG_SS, return_ESP + (n-1)*4);
write_new_stack_dword_32(&new_stack, temp_ESP, cs_descriptor.dpl, param);
}
// push return address onto new stack
write_new_stack_dword_32(&new_stack, temp_ESP-4, cs_descriptor.dpl, return_CS);
write_new_stack_dword_32(&new_stack, temp_ESP-8, cs_descriptor.dpl, return_EIP);
temp_ESP -= 8;
}
else {
write_new_stack_word_32(&new_stack, temp_ESP-2, cs_descriptor.dpl, return_SS);
write_new_stack_word_32(&new_stack, temp_ESP-4, cs_descriptor.dpl, (Bit16u) return_ESP);
temp_ESP -= 4;
for (unsigned n=param_count; n>0; n--) {
temp_ESP -= 2;
Bit16u param = read_virtual_word_32(BX_SEG_REG_SS, return_ESP + (n-1)*2);
write_new_stack_word_32(&new_stack, temp_ESP, cs_descriptor.dpl, param);
}
// push return address onto new stack
write_new_stack_word_32(&new_stack, temp_ESP-2, cs_descriptor.dpl, return_CS);
write_new_stack_word_32(&new_stack, temp_ESP-4, cs_descriptor.dpl, (Bit16u) return_EIP);
temp_ESP -= 4;
}
ESP = temp_ESP;
}
else {
Bit16u temp_SP = (Bit16u) ESP_for_cpl_x;
// push pointer of old stack onto new stack
if (gate_descriptor->type==BX_386_CALL_GATE) {
write_new_stack_dword_32(&new_stack, (Bit16u)(temp_SP-4), cs_descriptor.dpl, return_SS);
write_new_stack_dword_32(&new_stack, (Bit16u)(temp_SP-8), cs_descriptor.dpl, return_ESP);
temp_SP -= 8;
for (unsigned n=param_count; n>0; n--) {
temp_SP -= 4;
Bit32u param = read_virtual_dword_32(BX_SEG_REG_SS, return_ESP + (n-1)*4);
write_new_stack_dword_32(&new_stack, temp_SP, cs_descriptor.dpl, param);
}
// push return address onto new stack
write_new_stack_dword_32(&new_stack, (Bit16u)(temp_SP-4), cs_descriptor.dpl, return_CS);
write_new_stack_dword_32(&new_stack, (Bit16u)(temp_SP-8), cs_descriptor.dpl, return_EIP);
temp_SP -= 8;
}
else {
write_new_stack_word_32(&new_stack, (Bit16u)(temp_SP-2), cs_descriptor.dpl, return_SS);
write_new_stack_word_32(&new_stack, (Bit16u)(temp_SP-4), cs_descriptor.dpl, (Bit16u) return_ESP);
temp_SP -= 4;
for (unsigned n=param_count; n>0; n--) {
temp_SP -= 2;
Bit16u param = read_virtual_word_32(BX_SEG_REG_SS, return_ESP + (n-1)*2);
write_new_stack_word_32(&new_stack, temp_SP, cs_descriptor.dpl, param);
}
// push return address onto new stack
write_new_stack_word_32(&new_stack, (Bit16u)(temp_SP-2), cs_descriptor.dpl, return_CS);
write_new_stack_word_32(&new_stack, (Bit16u)(temp_SP-4), cs_descriptor.dpl, (Bit16u) return_EIP);
temp_SP -= 4;
}
SP = temp_SP;
}
// new eIP must be in code segment limit else #GP(0)
if (new_EIP > cs_descriptor.u.segment.limit_scaled) {
BX_ERROR(("call_protected: EIP not within CS limits"));
exception(BX_GP_EXCEPTION, 0);
}
/* load SS descriptor */
load_ss(&ss_selector, &ss_descriptor, cs_descriptor.dpl);
/* load new CS:IP value from gate */
/* load CS descriptor */
/* set CPL to stack segment DPL */
/* set RPL of CS to CPL */
load_cs(&cs_selector, &cs_descriptor, cs_descriptor.dpl);
EIP = new_EIP;
}
else // CALL GATE TO SAME PRIVILEGE
{
BX_DEBUG(("CALL GATE TO SAME PRIVILEGE"));
if (gate_descriptor->type == BX_386_CALL_GATE) {
// call gate 32bit, push return address onto stack
push_32(BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value);
push_32(EIP);
}
else {
// call gate 16bit, push return address onto stack
push_16(BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value);
push_16(IP);
}
// load CS:EIP from gate
// load code segment descriptor into CS register
// set RPL of CS to CPL
branch_far32(&cs_selector, &cs_descriptor, new_EIP, CPL);
}
}
#if BX_SUPPORT_X86_64
void BX_CPP_AttrRegparmN(1) BX_CPU_C::call_gate64(bx_selector_t *gate_selector)
{
bx_selector_t cs_selector;
Bit32u dword1, dword2, dword3;
bx_descriptor_t cs_descriptor;
bx_descriptor_t gate_descriptor;
// examine code segment selector in call gate descriptor
BX_DEBUG(("call_gate64: CALL 64bit call gate"));
fetch_raw_descriptor_64(gate_selector, &dword1, &dword2, &dword3, BX_GP_EXCEPTION);
parse_descriptor(dword1, dword2, &gate_descriptor);
Bit16u dest_selector = gate_descriptor.u.gate.dest_selector;
// selector must not be null else #GP(0)
if ((dest_selector & 0xfffc) == 0) {
BX_ERROR(("call_gate64: selector in gate null"));
exception(BX_GP_EXCEPTION, 0);
}
parse_selector(dest_selector, &cs_selector);
// selector must be within its descriptor table limits,
// else #GP(code segment selector)
fetch_raw_descriptor(&cs_selector, &dword1, &dword2, BX_GP_EXCEPTION);
parse_descriptor(dword1, dword2, &cs_descriptor);
// find the RIP in the gate_descriptor
Bit64u new_RIP = gate_descriptor.u.gate.dest_offset;
new_RIP |= ((Bit64u)dword3 << 32);
// AR byte of selected descriptor must indicate code segment,
// else #GP(code segment selector)
// DPL of selected descriptor must be <= CPL,
// else #GP(code segment selector)
if (cs_descriptor.valid==0 || cs_descriptor.segment==0 ||
IS_DATA_SEGMENT(cs_descriptor.type) ||
cs_descriptor.dpl > CPL)
{
BX_ERROR(("call_gate64: selected descriptor is not code"));
exception(BX_GP_EXCEPTION, dest_selector & 0xfffc);
}
// In long mode, only 64-bit call gates are allowed, and they must point
// to 64-bit code segments, else #GP(selector)
if (! IS_LONG64_SEGMENT(cs_descriptor) || cs_descriptor.u.segment.d_b)
{
BX_ERROR(("call_gate64: not 64-bit code segment in call gate 64"));
exception(BX_GP_EXCEPTION, dest_selector & 0xfffc);
}
// code segment must be present else #NP(selector)
if (! IS_PRESENT(cs_descriptor)) {
BX_ERROR(("call_gate64: code segment not present !"));
exception(BX_NP_EXCEPTION, dest_selector & 0xfffc);
}
Bit64u old_CS = BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value;
Bit64u old_RIP = RIP;
// CALL GATE TO MORE PRIVILEGE
// if non-conforming code segment and DPL < CPL then
if (IS_CODE_SEGMENT_NON_CONFORMING(cs_descriptor.type) && (cs_descriptor.dpl < CPL))
{
BX_DEBUG(("CALL GATE TO MORE PRIVILEGE LEVEL"));
// get new RSP for new privilege level from TSS
Bit64u RSP_for_cpl_x = get_RSP_from_TSS(cs_descriptor.dpl);
Bit64u old_SS = BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].selector.value;
Bit64u old_RSP = RSP;
// push old stack long pointer onto new stack
write_new_stack_qword_64(RSP_for_cpl_x - 8, cs_descriptor.dpl, old_SS);
write_new_stack_qword_64(RSP_for_cpl_x - 16, cs_descriptor.dpl, old_RSP);
// push long pointer to return address onto new stack
write_new_stack_qword_64(RSP_for_cpl_x - 24, cs_descriptor.dpl, old_CS);
write_new_stack_qword_64(RSP_for_cpl_x - 32, cs_descriptor.dpl, old_RIP);
RSP_for_cpl_x -= 32;
// load CS:RIP (guaranteed to be in 64 bit mode)
branch_far64(&cs_selector, &cs_descriptor, new_RIP, cs_descriptor.dpl);
// set up null SS descriptor
load_null_selector(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS], cs_descriptor.dpl);
RSP = RSP_for_cpl_x;
}
else
{
BX_DEBUG(("CALL GATE TO SAME PRIVILEGE"));
// push to 64-bit stack, switch to long64 guaranteed
write_new_stack_qword_64(RSP - 8, CPL, old_CS);
write_new_stack_qword_64(RSP - 16, CPL, old_RIP);
// load CS:RIP (guaranteed to be in 64 bit mode)
branch_far64(&cs_selector, &cs_descriptor, new_RIP, CPL);
RSP -= 16;
}
}
#endif

1003
simulators/bochs/cpu/cpu.cc Normal file

File diff suppressed because it is too large Load Diff

3972
simulators/bochs/cpu/cpu.h Normal file

File diff suppressed because it is too large Load Diff

1133
simulators/bochs/cpu/cpuid.cc Executable file

File diff suppressed because it is too large Load Diff

140
simulators/bochs/cpu/crc32.cc Executable file
View File

@ -0,0 +1,140 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2008-2009 Stanislav Shwartsman
// 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
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA B 02110-1301 USA
//
/////////////////////////////////////////////////////////////////////////
#define NEED_CPU_REG_SHORTCUTS 1
#include "bochs.h"
#include "cpu.h"
#define LOG_THIS BX_CPU_THIS_PTR
// 3-byte opcodes
#define CRC32_POLYNOMIAL BX_CONST64(0x11edc6f41)
// primitives for CRC32 usage
BX_CPP_INLINE Bit8u BitReflect8(Bit8u val8)
{
return ((val8 & 0x80) >> 7) |
((val8 & 0x40) >> 5) |
((val8 & 0x20) >> 3) |
((val8 & 0x10) >> 1) |
((val8 & 0x08) << 1) |
((val8 & 0x04) << 3) |
((val8 & 0x02) << 5) |
((val8 & 0x01) << 7);
}
BX_CPP_INLINE Bit16u BitReflect16(Bit16u val16)
{
return ((Bit16u)(BitReflect8(val16 & 0xff)) << 8) | BitReflect8(val16 >> 8);
}
BX_CPP_INLINE Bit32u BitReflect32(Bit32u val32)
{
return ((Bit32u)(BitReflect16(val32 & 0xffff)) << 16) | BitReflect16(val32 >> 16);
}
static Bit32u mod2_64bit(Bit64u divisor, Bit64u dividend)
{
Bit64u remainder = dividend >> 32;
for (int bitpos=31; bitpos>=0; bitpos--) {
// copy one more bit from the dividend
remainder = (remainder << 1) | ((dividend >> bitpos) & 1);
// if MSB is set, then XOR divisor and get new remainder
if (((remainder >> 32) & 1) == 1) {
remainder ^= divisor;
}
}
return (Bit32u) remainder;
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CRC32_GdEbR(bxInstruction_c *i)
{
Bit8u op1 = BX_READ_8BIT_REGx(i->rm(), i->extend8bitL());
Bit32u op2 = BX_READ_32BIT_REG(i->nnn());
op2 = BitReflect32(op2);
Bit64u tmp1 = ((Bit64u) BitReflect8 (op1)) << 32;
Bit64u tmp2 = ((Bit64u) op2) << 8;
Bit64u tmp3 = tmp1 ^ tmp2;
op2 = mod2_64bit(CRC32_POLYNOMIAL, tmp3);
/* now write result back to destination */
BX_WRITE_32BIT_REGZ(i->nnn(), BitReflect32(op2));
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CRC32_GdEwR(bxInstruction_c *i)
{
Bit32u op2 = BX_READ_32BIT_REG(i->nnn());
op2 = BitReflect32(op2);
Bit16u op1 = BX_READ_16BIT_REG(i->rm());
Bit64u tmp1 = ((Bit64u) BitReflect16(op1)) << 32;
Bit64u tmp2 = ((Bit64u) op2) << 16;
Bit64u tmp3 = tmp1 ^ tmp2;
op2 = mod2_64bit(CRC32_POLYNOMIAL, tmp3);
/* now write result back to destination */
BX_WRITE_32BIT_REGZ(i->nnn(), BitReflect32(op2));
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CRC32_GdEdR(bxInstruction_c *i)
{
Bit32u op2 = BX_READ_32BIT_REG(i->nnn());
op2 = BitReflect32(op2);
Bit32u op1 = BX_READ_32BIT_REG(i->rm());
Bit64u tmp1 = ((Bit64u) BitReflect32(op1)) << 32;
Bit64u tmp2 = ((Bit64u) op2) << 32;
Bit64u tmp3 = tmp1 ^ tmp2;
op2 = mod2_64bit(CRC32_POLYNOMIAL, tmp3);
/* now write result back to destination */
BX_WRITE_32BIT_REGZ(i->nnn(), BitReflect32(op2));
}
#if BX_SUPPORT_X86_64
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CRC32_GdEqR(bxInstruction_c *i)
{
Bit32u op2 = BX_READ_32BIT_REG(i->nnn());
op2 = BitReflect32(op2);
Bit64u op1 = BX_READ_64BIT_REG(i->rm());
Bit64u tmp1 = ((Bit64u) BitReflect32(op1 & 0xffffffff)) << 32;
Bit64u tmp2 = ((Bit64u) op2) << 32;
Bit64u tmp3 = tmp1 ^ tmp2;
op2 = mod2_64bit(CRC32_POLYNOMIAL, tmp3);
tmp1 = ((Bit64u) BitReflect32(op1 >> 32)) << 32;
tmp2 = ((Bit64u) op2) << 32;
tmp3 = tmp1 ^ tmp2;
op2 = mod2_64bit(CRC32_POLYNOMIAL, tmp3);
/* now write result back to destination */
BX_WRITE_32BIT_REGZ(i->nnn(), BitReflect32(op2));
}
#endif // BX_SUPPORT_X86_64

1282
simulators/bochs/cpu/crregs.cc Executable file

File diff suppressed because it is too large Load Diff

222
simulators/bochs/cpu/crregs.h Executable file
View File

@ -0,0 +1,222 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2007-2009 Stanislav Shwartsman
// 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
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA B 02110-1301 USA
//
/////////////////////////////////////////////////////////////////////////
#ifndef BX_CRREGS
#define BX_CRREGS
struct bx_cr0_t {
Bit32u val32; // 32bit value of register
// Accessors for all cr0 bitfields.
#define IMPLEMENT_CRREG_ACCESSORS(name, bitnum) \
BX_CPP_INLINE bx_bool get_##name () { \
return 1 & (val32 >> bitnum); \
} \
BX_CPP_INLINE void set_##name (Bit8u val) { \
val32 = (val32 & ~(1<<bitnum)) | ((!!val) << bitnum); \
}
// CR0 notes:
// Each x86 level has its own quirks regarding how it handles
// reserved bits. I used DOS DEBUG.EXE in real mode on the
// following processors, tried to clear bits 1..30, then tried
// to set bits 1..30, to see how these bits are handled.
// I found the following:
//
// Processor try to clear bits 1..30 try to set bits 1..30
// 386 7FFFFFF0 7FFFFFFE
// 486DX2 00000010 6005003E
// Pentium 00000010 7FFFFFFE
// Pentium-II 00000010 6005003E
//
// My assumptions:
// All processors: bit 4 is hardwired to 1 (not true on all clones)
// 386: bits 5..30 of CR0 are also hardwired to 1
// Pentium: reserved bits retain value set using mov cr0, reg32
// 486DX2/Pentium-II: reserved bits are hardwired to 0
IMPLEMENT_CRREG_ACCESSORS(PE, 0);
IMPLEMENT_CRREG_ACCESSORS(MP, 1);
IMPLEMENT_CRREG_ACCESSORS(EM, 2);
IMPLEMENT_CRREG_ACCESSORS(TS, 3);
#if BX_CPU_LEVEL >= 4
IMPLEMENT_CRREG_ACCESSORS(ET, 4);
IMPLEMENT_CRREG_ACCESSORS(NE, 5);
IMPLEMENT_CRREG_ACCESSORS(WP, 16);
IMPLEMENT_CRREG_ACCESSORS(AM, 18);
IMPLEMENT_CRREG_ACCESSORS(NW, 29);
IMPLEMENT_CRREG_ACCESSORS(CD, 30);
#endif
IMPLEMENT_CRREG_ACCESSORS(PG, 31);
BX_CPP_INLINE Bit32u get32() { return val32; }
// ET is hardwired bit in CR0
BX_CPP_INLINE void set32(Bit32u val) { val32 = val | 0x10; }
};
#if BX_CPU_LEVEL >= 4
#define BX_CR4_VME_MASK (1 << 0)
#define BX_CR4_PVI_MASK (1 << 1)
#define BX_CR4_TSD_MASK (1 << 2)
#define BX_CR4_DE_MASK (1 << 3)
#define BX_CR4_PSE_MASK (1 << 4)
#define BX_CR4_PAE_MASK (1 << 5)
#define BX_CR4_MCE_MASK (1 << 6)
#define BX_CR4_PGE_MASK (1 << 7)
#define BX_CR4_PCE_MASK (1 << 8)
#define BX_CR4_OSFXSR_MASK (1 << 9)
#define BX_CR4_OSXMMEXCPT_MASK (1 << 10)
#define BX_CR4_VMXE_MASK (1 << 13)
#define BX_CR4_SMXE_MASK (1 << 14)
#define BX_CR4_FSGSBASE_MASK (1 << 16)
#define BX_CR4_PCIDE_MASK (1 << 17)
#define BX_CR4_OSXSAVE_MASK (1 << 18)
struct bx_cr4_t {
Bit32u val32; // 32bit value of register
IMPLEMENT_CRREG_ACCESSORS(VME, 0);
IMPLEMENT_CRREG_ACCESSORS(PVI, 1);
IMPLEMENT_CRREG_ACCESSORS(TSD, 2);
IMPLEMENT_CRREG_ACCESSORS(DE, 3);
IMPLEMENT_CRREG_ACCESSORS(PSE, 4);
IMPLEMENT_CRREG_ACCESSORS(PAE, 5);
IMPLEMENT_CRREG_ACCESSORS(MCE, 6);
IMPLEMENT_CRREG_ACCESSORS(PGE, 7);
IMPLEMENT_CRREG_ACCESSORS(PCE, 8);
IMPLEMENT_CRREG_ACCESSORS(OSFXSR, 9);
IMPLEMENT_CRREG_ACCESSORS(OSXMMEXCPT, 10);
#if BX_SUPPORT_VMX
IMPLEMENT_CRREG_ACCESSORS(VMXE, 13);
#endif
#if BX_SUPPORT_X86_64
IMPLEMENT_CRREG_ACCESSORS(FSGSBASE, 16);
IMPLEMENT_CRREG_ACCESSORS(PCIDE, 17);
#endif
IMPLEMENT_CRREG_ACCESSORS(OSXSAVE, 18);
BX_CPP_INLINE Bit32u get32() { return val32; }
BX_CPP_INLINE void set32(Bit32u val) { val32 = val; }
};
#define BX_CR4_FLUSH_TLB_MASK \
(BX_CR4_PSE_MASK | BX_CR4_PAE_MASK | BX_CR4_PGE_MASK | BX_CR4_PCIDE_MASK)
#endif // #if BX_CPU_LEVEL >= 4
#if BX_SUPPORT_X86_64
#define BX_EFER_SCE_MASK (1 << 0)
#define BX_EFER_LME_MASK (1 << 8)
#define BX_EFER_LMA_MASK (1 << 10)
#define BX_EFER_NXE_MASK (1 << 11)
#define BX_EFER_FFXSR_MASK (1 << 14)
struct bx_efer_t {
Bit32u val32; // 32bit value of register
IMPLEMENT_CRREG_ACCESSORS(SCE, 0);
IMPLEMENT_CRREG_ACCESSORS(LME, 8);
IMPLEMENT_CRREG_ACCESSORS(LMA, 10);
IMPLEMENT_CRREG_ACCESSORS(NXE, 11);
IMPLEMENT_CRREG_ACCESSORS(SVME, 12); /* AMD Secure Virtual Machine */
IMPLEMENT_CRREG_ACCESSORS(LMSLE, 13); /* AMD Long Mode Segment Limit */
IMPLEMENT_CRREG_ACCESSORS(FFXSR, 14);
BX_CPP_INLINE Bit32u get32() { return val32; }
BX_CPP_INLINE void set32(Bit32u val) { val32 = val; }
};
#define BX_EFER_SUPPORTED_BITS \
((Bit64u) (BX_EFER_SCE_MASK | BX_EFER_LME_MASK | \
BX_EFER_LMA_MASK | BX_EFER_NXE_MASK | BX_EFER_FFXSR_MASK))
#endif
#if BX_CPU_LEVEL >= 6
struct xcr0_t {
Bit32u val32; // 32bit value of register
#define BX_XCR0_SUPPORTED_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_SSE_MASK (1<<BX_XCR0_SSE_BIT)
IMPLEMENT_CRREG_ACCESSORS(FPU, BX_XCR0_FPU_BIT);
IMPLEMENT_CRREG_ACCESSORS(SSE, BX_XCR0_SSE_BIT);
BX_CPP_INLINE Bit32u get32() { return val32; }
BX_CPP_INLINE void set32(Bit32u val) { val32 = val; }
};
#endif
#undef IMPLEMENT_CRREG_ACCESSORS
typedef struct msr {
unsigned index; // MSR index
unsigned type; // MSR type: 1 - lin address, 2 - phy address
#define BX_LIN_ADDRESS_MSR 1
#define BX_PHY_ADDRESS_MSR 2
Bit64u val64; // current MSR value
Bit64u reset_value; // reset value
Bit64u reserved; // r/o bits - fault on write
Bit64u ignored; // hardwired bits - ignored on write
// workaround for an 'index(a,b)' macro definition clash in some system header in conjunction with AspectC++
#undef index
msr(unsigned idx, unsigned msr_type = 0, Bit64u reset_val = 0, Bit64u rsrv = 0, Bit64u ign = 0):
index(idx), type(msr_type), val64(reset_val), reset_value(reset_val),
reserved(rsrv), ignored(ign) {}
msr(unsigned idx, Bit64u reset_val = 0, Bit64u rsrv = 0, Bit64u ign = 0):
index(idx), type(0), val64(reset_val), reset_value(reset_val),
reserved(rsrv), ignored(ign) {}
BX_CPP_INLINE void reset() { val64 = reset_value; }
BX_CPP_INLINE Bit64u get64() { return val64; }
BX_CPP_INLINE bx_bool set64(Bit64u new_val) {
new_val = (new_val & ~ignored) | (val64 & ignored);
switch(type) {
#if BX_SUPPORT_X86_64
case BX_LIN_ADDRESS_MSR:
if (! IsCanonical(new_val)) return 0;
break;
#endif
case BX_PHY_ADDRESS_MSR:
if (! IsValidPhyAddr(new_val)) return 0;
break;
default:
if ((val64 ^ new_val) & reserved) return 0;
break;
}
val64 = new_val;
return 1;
}
} MSR;
#endif

View File

@ -0,0 +1,785 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2001-2009 The Bochs Project
//
// 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
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA B 02110-1301 USA
/////////////////////////////////////////////////////////////////////////
#define NEED_CPU_REG_SHORTCUTS 1
#include "bochs.h"
#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 RSP ESP
#define RIP EIP
#endif
BX_CPP_INLINE void BX_CPP_AttrRegparmN(1) BX_CPU_C::branch_near16(Bit16u new_IP)
{
BX_ASSERT(BX_CPU_THIS_PTR cpu_mode != BX_MODE_LONG_64);
// check always, not only in protected mode
if (new_IP > BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.limit_scaled)
{
BX_ERROR(("branch_near16: offset outside of CS limits"));
exception(BX_GP_EXCEPTION, 0);
}
EIP = new_IP;
#if BX_SUPPORT_TRACE_CACHE && !defined(BX_TRACE_CACHE_NO_SPECULATIVE_TRACING)
// assert magic async_event to stop trace execution
BX_CPU_THIS_PTR async_event |= BX_ASYNC_EVENT_STOP_TRACE;
#endif
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::RETnear16_Iw(bxInstruction_c *i)
{
BX_ASSERT(BX_CPU_THIS_PTR cpu_mode != BX_MODE_LONG_64);
#if BX_DEBUGGER
BX_CPU_THIS_PTR show_flag |= Flag_ret;
#endif
RSP_SPECULATIVE;
Bit16u return_IP = pop_16();
if (return_IP > BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.limit_scaled)
{
BX_ERROR(("RETnear16_Iw: IP > limit"));
exception(BX_GP_EXCEPTION, 0);
}
EIP = return_IP;
Bit16u imm16 = i->Iw();
if (BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.d_b) /* 32bit stack */
ESP += imm16;
else
SP += imm16;
RSP_COMMIT;
BX_INSTR_UCNEAR_BRANCH(BX_CPU_ID, BX_INSTR_IS_RET, EIP);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::RETnear16(bxInstruction_c *i)
{
BX_ASSERT(BX_CPU_THIS_PTR cpu_mode != BX_MODE_LONG_64);
#if BX_DEBUGGER
BX_CPU_THIS_PTR show_flag |= Flag_ret;
#endif
RSP_SPECULATIVE;
Bit16u return_IP = pop_16();
if (return_IP > BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.limit_scaled)
{
BX_ERROR(("RETnear16: IP > limit"));
exception(BX_GP_EXCEPTION, 0);
}
EIP = return_IP;
RSP_COMMIT;
BX_INSTR_UCNEAR_BRANCH(BX_CPU_ID, BX_INSTR_IS_RET, EIP);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::RETfar16_Iw(bxInstruction_c *i)
{
Bit16u ip, cs_raw;
invalidate_prefetch_q();
#if BX_DEBUGGER
BX_CPU_THIS_PTR show_flag |= Flag_ret;
#endif
Bit16s imm16 = (Bit16s) i->Iw();
if (protected_mode()) {
return_protected(i, imm16);
goto done;
}
RSP_SPECULATIVE;
ip = pop_16();
cs_raw = pop_16();
// CS.LIMIT can't change when in real/v8086 mode
if (ip > BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.limit_scaled) {
BX_ERROR(("RETfar16_Iw: instruction pointer not within code segment limits"));
exception(BX_GP_EXCEPTION, 0);
}
load_seg_reg(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS], cs_raw);
EIP = (Bit32u) ip;
if (BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.d_b)
ESP += imm16;
else
SP += imm16;
RSP_COMMIT;
done:
BX_INSTR_FAR_BRANCH(BX_CPU_ID, BX_INSTR_IS_RET,
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value, EIP);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::RETfar16(bxInstruction_c *i)
{
Bit16u ip, cs_raw;
invalidate_prefetch_q();
#if BX_DEBUGGER
BX_CPU_THIS_PTR show_flag |= Flag_ret;
#endif
if (protected_mode()) {
return_protected(i, 0);
goto done;
}
RSP_SPECULATIVE;
ip = pop_16();
cs_raw = pop_16();
// CS.LIMIT can't change when in real/v8086 mode
if (ip > BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.limit_scaled) {
BX_ERROR(("RETfar16: instruction pointer not within code segment limits"));
exception(BX_GP_EXCEPTION, 0);
}
load_seg_reg(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS], cs_raw);
EIP = (Bit32u) ip;
RSP_COMMIT;
done:
BX_INSTR_FAR_BRANCH(BX_CPU_ID, BX_INSTR_IS_RET,
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value, EIP);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CALL_Jw(bxInstruction_c *i)
{
#if BX_DEBUGGER
BX_CPU_THIS_PTR show_flag |= Flag_call;
#endif
RSP_SPECULATIVE;
/* push 16 bit EA of next instruction */
push_16(IP);
Bit16u new_IP = IP + i->Iw();
branch_near16(new_IP);
RSP_COMMIT;
BX_INSTR_UCNEAR_BRANCH(BX_CPU_ID, BX_INSTR_IS_CALL, EIP);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CALL16_Ap(bxInstruction_c *i)
{
BX_ASSERT(BX_CPU_THIS_PTR cpu_mode != BX_MODE_LONG_64);
invalidate_prefetch_q();
#if BX_DEBUGGER
BX_CPU_THIS_PTR show_flag |= Flag_call;
#endif
Bit16u disp16 = i->Iw();
Bit16u cs_raw = i->Iw2();
RSP_SPECULATIVE;
if (protected_mode()) {
call_protected(i, cs_raw, disp16);
goto done;
}
push_16(BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value);
push_16(IP);
// CS.LIMIT can't change when in real/v8086 mode
if (disp16 > BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.limit_scaled) {
BX_ERROR(("CALL16_Ap: instruction pointer not within code segment limits"));
exception(BX_GP_EXCEPTION, 0);
}
load_seg_reg(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS], cs_raw);
EIP = (Bit32u) disp16;
done:
RSP_COMMIT;
BX_INSTR_FAR_BRANCH(BX_CPU_ID, BX_INSTR_IS_CALL,
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value, EIP);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CALL_EwR(bxInstruction_c *i)
{
Bit16u new_IP = BX_READ_16BIT_REG(i->rm());
#if BX_DEBUGGER
BX_CPU_THIS_PTR show_flag |= Flag_call;
#endif
RSP_SPECULATIVE;
/* push 16 bit EA of next instruction */
push_16(IP);
branch_near16(new_IP);
RSP_COMMIT;
BX_INSTR_UCNEAR_BRANCH(BX_CPU_ID, BX_INSTR_IS_CALL, EIP);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CALL16_Ep(bxInstruction_c *i)
{
Bit16u cs_raw;
Bit16u op1_16;
invalidate_prefetch_q();
#if BX_DEBUGGER
BX_CPU_THIS_PTR show_flag |= Flag_call;
#endif
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
op1_16 = read_virtual_word(i->seg(), eaddr);
cs_raw = read_virtual_word(i->seg(), (eaddr+2) & i->asize_mask());
RSP_SPECULATIVE;
if (protected_mode()) {
call_protected(i, cs_raw, op1_16);
goto done;
}
push_16(BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value);
push_16(IP);
// CS.LIMIT can't change when in real/v8086 mode
if (op1_16 > BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.limit_scaled) {
BX_ERROR(("CALL16_Ep: instruction pointer not within code segment limits"));
exception(BX_GP_EXCEPTION, 0);
}
load_seg_reg(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS], cs_raw);
EIP = op1_16;
done:
RSP_COMMIT;
BX_INSTR_FAR_BRANCH(BX_CPU_ID, BX_INSTR_IS_CALL,
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value, EIP);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::JMP_Jw(bxInstruction_c *i)
{
Bit16u new_IP = IP + i->Iw();
branch_near16(new_IP);
BX_INSTR_UCNEAR_BRANCH(BX_CPU_ID, BX_INSTR_IS_JMP, new_IP);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::JO_Jw(bxInstruction_c *i)
{
if (get_OF()) {
Bit16u new_IP = IP + i->Iw();
branch_near16(new_IP);
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, new_IP);
}
#if BX_INSTRUMENTATION
else {
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
}
#endif
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::JNO_Jw(bxInstruction_c *i)
{
if (! get_OF()) {
Bit16u new_IP = IP + i->Iw();
branch_near16(new_IP);
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, new_IP);
}
#if BX_INSTRUMENTATION
else {
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
}
#endif
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::JB_Jw(bxInstruction_c *i)
{
if (get_CF()) {
Bit16u new_IP = IP + i->Iw();
branch_near16(new_IP);
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, new_IP);
}
#if BX_INSTRUMENTATION
else {
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
}
#endif
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::JNB_Jw(bxInstruction_c *i)
{
if (! get_CF()) {
Bit16u new_IP = IP + i->Iw();
branch_near16(new_IP);
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, new_IP);
}
#if BX_INSTRUMENTATION
else {
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
}
#endif
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::JZ_Jw(bxInstruction_c *i)
{
if (get_ZF()) {
Bit16u new_IP = IP + i->Iw();
branch_near16(new_IP);
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, new_IP);
}
#if BX_INSTRUMENTATION
else {
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
}
#endif
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::JNZ_Jw(bxInstruction_c *i)
{
if (! get_ZF()) {
Bit16u new_IP = IP + i->Iw();
branch_near16(new_IP);
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, new_IP);
}
#if BX_INSTRUMENTATION
else {
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
}
#endif
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::JBE_Jw(bxInstruction_c *i)
{
if (get_CF() || get_ZF()) {
Bit16u new_IP = IP + i->Iw();
branch_near16(new_IP);
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, new_IP);
}
#if BX_INSTRUMENTATION
else {
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
}
#endif
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::JNBE_Jw(bxInstruction_c *i)
{
if (! (get_CF() || get_ZF())) {
Bit16u new_IP = IP + i->Iw();
branch_near16(new_IP);
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, new_IP);
}
#if BX_INSTRUMENTATION
else {
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
}
#endif
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::JS_Jw(bxInstruction_c *i)
{
if (get_SF()) {
Bit16u new_IP = IP + i->Iw();
branch_near16(new_IP);
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, new_IP);
}
#if BX_INSTRUMENTATION
else {
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
}
#endif
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::JNS_Jw(bxInstruction_c *i)
{
if (! get_SF()) {
Bit16u new_IP = IP + i->Iw();
branch_near16(new_IP);
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, new_IP);
}
#if BX_INSTRUMENTATION
else {
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
}
#endif
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::JP_Jw(bxInstruction_c *i)
{
if (get_PF()) {
Bit16u new_IP = IP + i->Iw();
branch_near16(new_IP);
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, new_IP);
}
#if BX_INSTRUMENTATION
else {
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
}
#endif
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::JNP_Jw(bxInstruction_c *i)
{
if (! get_PF()) {
Bit16u new_IP = IP + i->Iw();
branch_near16(new_IP);
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, new_IP);
}
#if BX_INSTRUMENTATION
else {
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
}
#endif
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::JL_Jw(bxInstruction_c *i)
{
if (getB_SF() != getB_OF()) {
Bit16u new_IP = IP + i->Iw();
branch_near16(new_IP);
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, new_IP);
}
#if BX_INSTRUMENTATION
else {
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
}
#endif
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::JNL_Jw(bxInstruction_c *i)
{
if (getB_SF() == getB_OF()) {
Bit16u new_IP = IP + i->Iw();
branch_near16(new_IP);
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, new_IP);
}
#if BX_INSTRUMENTATION
else {
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
}
#endif
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::JLE_Jw(bxInstruction_c *i)
{
if (get_ZF() || (getB_SF() != getB_OF())) {
Bit16u new_IP = IP + i->Iw();
branch_near16(new_IP);
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, new_IP);
}
#if BX_INSTRUMENTATION
else {
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
}
#endif
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::JNLE_Jw(bxInstruction_c *i)
{
if (! get_ZF() && (getB_SF() == getB_OF())) {
Bit16u new_IP = IP + i->Iw();
branch_near16(new_IP);
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, new_IP);
}
#if BX_INSTRUMENTATION
else {
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
}
#endif
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::JMP_EwR(bxInstruction_c *i)
{
Bit16u new_IP = BX_READ_16BIT_REG(i->rm());
branch_near16(new_IP);
BX_INSTR_UCNEAR_BRANCH(BX_CPU_ID, BX_INSTR_IS_JMP, new_IP);
}
/* Far indirect jump */
void BX_CPP_AttrRegparmN(1) BX_CPU_C::JMP16_Ep(bxInstruction_c *i)
{
Bit16u cs_raw;
Bit16u op1_16;
invalidate_prefetch_q();
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
op1_16 = read_virtual_word(i->seg(), eaddr);
cs_raw = read_virtual_word(i->seg(), (eaddr+2) & i->asize_mask());
// jump_protected doesn't affect RSP so it is RSP safe
if (protected_mode()) {
jump_protected(i, cs_raw, op1_16);
goto done;
}
// CS.LIMIT can't change when in real/v8086 mode
if (op1_16 > BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.limit_scaled) {
BX_ERROR(("JMP16_Ep: instruction pointer not within code segment limits"));
exception(BX_GP_EXCEPTION, 0);
}
load_seg_reg(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS], cs_raw);
EIP = op1_16;
done:
BX_INSTR_FAR_BRANCH(BX_CPU_ID, BX_INSTR_IS_JMP,
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value, EIP);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::IRET16(bxInstruction_c *i)
{
invalidate_prefetch_q();
#if BX_SUPPORT_VMX
if (!BX_CPU_THIS_PTR in_vmx_guest || !VMEXIT(VMX_VM_EXEC_CTRL1_NMI_VMEXIT))
#endif
BX_CPU_THIS_PTR disable_NMI = 0;
#if BX_DEBUGGER
BX_CPU_THIS_PTR show_flag |= Flag_iret;
#endif
if (protected_mode()) {
iret_protected(i);
goto done;
}
RSP_SPECULATIVE;
if (v8086_mode()) {
// IOPL check in stack_return_from_v86()
iret16_stack_return_from_v86(i);
}
else {
Bit16u ip = pop_16();
Bit16u cs_raw = pop_16(); // #SS has higher priority
Bit16u flags = pop_16();
// CS.LIMIT can't change when in real/v8086 mode
if(ip > BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.limit_scaled) {
BX_ERROR(("IRET16: instruction pointer not within code segment limits"));
exception(BX_GP_EXCEPTION, 0);
}
load_seg_reg(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS], cs_raw);
EIP = (Bit32u) ip;
write_flags(flags, /* change IOPL? */ 1, /* change IF? */ 1);
}
RSP_COMMIT;
done:
BX_INSTR_FAR_BRANCH(BX_CPU_ID, BX_INSTR_IS_IRET,
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value, EIP);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::JCXZ_Jb(bxInstruction_c *i)
{
// it is impossible to get this instruction in long mode
BX_ASSERT(i->as64L() == 0);
Bit32u temp_ECX;
if (i->as32L())
temp_ECX = ECX;
else
temp_ECX = CX;
if (temp_ECX == 0) {
Bit16u new_IP = IP + i->Iw();
branch_near16(new_IP);
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, new_IP);
}
#if BX_INSTRUMENTATION
else {
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
}
#endif
}
//
// There is some weirdness in LOOP instructions definition. If an exception
// was generated during the instruction execution (for example #GP fault
// because EIP was beyond CS segment limits) CPU state should restore the
// state prior to instruction execution.
//
// The final point that we are not allowed to decrement ECX register before
// it is known that no exceptions can happen.
//
void BX_CPP_AttrRegparmN(1) BX_CPU_C::LOOPNE16_Jb(bxInstruction_c *i)
{
// it is impossible to get this instruction in long mode
BX_ASSERT(i->as64L() == 0);
if (i->as32L()) {
Bit32u count = ECX;
count--;
if (count != 0 && (get_ZF()==0)) {
Bit16u new_IP = IP + i->Iw();
branch_near16(new_IP);
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, new_IP);
}
#if BX_INSTRUMENTATION
else {
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
}
#endif
ECX = count;
}
else {
Bit16u count = CX;
count--;
if (count != 0 && (get_ZF()==0)) {
Bit16u new_IP = IP + i->Iw();
branch_near16(new_IP);
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, new_IP);
}
#if BX_INSTRUMENTATION
else {
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
}
#endif
CX = count;
}
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::LOOPE16_Jb(bxInstruction_c *i)
{
// it is impossible to get this instruction in long mode
BX_ASSERT(i->as64L() == 0);
if (i->as32L()) {
Bit32u count = ECX;
count--;
if (count != 0 && get_ZF()) {
Bit16u new_IP = IP + i->Iw();
branch_near16(new_IP);
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, new_IP);
}
#if BX_INSTRUMENTATION
else {
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
}
#endif
ECX = count;
}
else {
Bit16u count = CX;
count--;
if (count != 0 && get_ZF()) {
Bit16u new_IP = IP + i->Iw();
branch_near16(new_IP);
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, new_IP);
}
#if BX_INSTRUMENTATION
else {
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
}
#endif
CX = count;
}
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::LOOP16_Jb(bxInstruction_c *i)
{
// it is impossible to get this instruction in long mode
BX_ASSERT(i->as64L() == 0);
if (i->as32L()) {
Bit32u count = ECX;
count--;
if (count != 0) {
Bit16u new_IP = IP + i->Iw();
branch_near16(new_IP);
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, new_IP);
}
#if BX_INSTRUMENTATION
else {
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
}
#endif
ECX = count;
}
else {
Bit16u count = CX;
count--;
if (count != 0) {
Bit16u new_IP = IP + i->Iw();
branch_near16(new_IP);
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, new_IP);
}
#if BX_INSTRUMENTATION
else {
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
}
#endif
CX = count;
}
}

View File

@ -0,0 +1,829 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2001-2009 The Bochs Project
//
// 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
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA B 02110-1301 USA
/////////////////////////////////////////////////////////////////////////
#define NEED_CPU_REG_SHORTCUTS 1
#include "bochs.h"
#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 RSP ESP
#define RIP EIP
#endif
#if BX_CPU_LEVEL >= 3
BX_CPP_INLINE void BX_CPP_AttrRegparmN(1) BX_CPU_C::branch_near32(Bit32u new_EIP)
{
BX_ASSERT(BX_CPU_THIS_PTR cpu_mode != BX_MODE_LONG_64);
// check always, not only in protected mode
if (new_EIP > BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.limit_scaled)
{
BX_ERROR(("branch_near32: offset outside of CS limits"));
exception(BX_GP_EXCEPTION, 0);
}
EIP = new_EIP;
#if BX_SUPPORT_TRACE_CACHE && !defined(BX_TRACE_CACHE_NO_SPECULATIVE_TRACING)
// assert magic async_event to stop trace execution
BX_CPU_THIS_PTR async_event |= BX_ASYNC_EVENT_STOP_TRACE;
#endif
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::RETnear32_Iw(bxInstruction_c *i)
{
BX_ASSERT(BX_CPU_THIS_PTR cpu_mode != BX_MODE_LONG_64);
#if BX_DEBUGGER
BX_CPU_THIS_PTR show_flag |= Flag_ret;
#endif
RSP_SPECULATIVE;
Bit16u imm16 = i->Iw();
Bit32u return_EIP = pop_32();
if (return_EIP > BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.limit_scaled)
{
BX_ERROR(("RETnear32_Iw: offset outside of CS limits"));
exception(BX_GP_EXCEPTION, 0);
}
EIP = return_EIP;
if (BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.d_b)
ESP += imm16;
else
SP += imm16;
RSP_COMMIT;
BX_INSTR_UCNEAR_BRANCH(BX_CPU_ID, BX_INSTR_IS_RET, EIP);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::RETnear32(bxInstruction_c *i)
{
BX_ASSERT(BX_CPU_THIS_PTR cpu_mode != BX_MODE_LONG_64);
#if BX_DEBUGGER
BX_CPU_THIS_PTR show_flag |= Flag_ret;
#endif
RSP_SPECULATIVE;
Bit32u return_EIP = pop_32();
if (return_EIP > BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.limit_scaled)
{
BX_ERROR(("RETnear32: offset outside of CS limits"));
exception(BX_GP_EXCEPTION, 0);
}
EIP = return_EIP;
RSP_COMMIT;
BX_INSTR_UCNEAR_BRANCH(BX_CPU_ID, BX_INSTR_IS_RET, EIP);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::RETfar32_Iw(bxInstruction_c *i)
{
invalidate_prefetch_q();
#if BX_DEBUGGER
BX_CPU_THIS_PTR show_flag |= Flag_ret;
#endif
Bit16u imm16 = i->Iw();
Bit16u cs_raw;
Bit32u eip;
if (protected_mode()) {
return_protected(i, imm16);
goto done;
}
RSP_SPECULATIVE;
eip = pop_32();
cs_raw = (Bit16u) pop_32(); /* 32bit pop, MSW discarded */
// CS.LIMIT can't change when in real/v8086 mode
if (eip > BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.limit_scaled) {
BX_ERROR(("RETfar32_Iw: instruction pointer not within code segment limits"));
exception(BX_GP_EXCEPTION, 0);
}
load_seg_reg(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS], cs_raw);
EIP = eip;
if (BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.d_b)
ESP += imm16;
else
SP += imm16;
RSP_COMMIT;
done:
BX_INSTR_FAR_BRANCH(BX_CPU_ID, BX_INSTR_IS_RET,
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value, EIP);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::RETfar32(bxInstruction_c *i)
{
Bit32u eip;
Bit16u cs_raw;
invalidate_prefetch_q();
#if BX_DEBUGGER
BX_CPU_THIS_PTR show_flag |= Flag_ret;
#endif
if (protected_mode()) {
return_protected(i, 0);
goto done;
}
RSP_SPECULATIVE;
eip = pop_32();
cs_raw = (Bit16u) pop_32(); /* 32bit pop, MSW discarded */
// CS.LIMIT can't change when in real/v8086 mode
if (eip > BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.limit_scaled) {
BX_ERROR(("RETfar32: instruction pointer not within code segment limits"));
exception(BX_GP_EXCEPTION, 0);
}
load_seg_reg(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS], cs_raw);
EIP = eip;
RSP_COMMIT;
done:
BX_INSTR_FAR_BRANCH(BX_CPU_ID, BX_INSTR_IS_RET,
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value, EIP);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CALL_Jd(bxInstruction_c *i)
{
#if BX_DEBUGGER
BX_CPU_THIS_PTR show_flag |= Flag_call;
#endif
Bit32u new_EIP = EIP + i->Id();
RSP_SPECULATIVE;
/* push 32 bit EA of next instruction */
push_32(EIP);
branch_near32(new_EIP);
RSP_COMMIT;
BX_INSTR_UCNEAR_BRANCH(BX_CPU_ID, BX_INSTR_IS_CALL, EIP);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CALL32_Ap(bxInstruction_c *i)
{
BX_ASSERT(BX_CPU_THIS_PTR cpu_mode != BX_MODE_LONG_64);
Bit16u cs_raw;
Bit32u disp32;
invalidate_prefetch_q();
#if BX_DEBUGGER
BX_CPU_THIS_PTR show_flag |= Flag_call;
#endif
disp32 = i->Id();
cs_raw = i->Iw2();
RSP_SPECULATIVE;
if (protected_mode()) {
call_protected(i, cs_raw, disp32);
goto done;
}
// CS.LIMIT can't change when in real/v8086 mode
if (disp32 > BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.limit_scaled) {
BX_ERROR(("CALL32_Ap: instruction pointer not within code segment limits"));
exception(BX_GP_EXCEPTION, 0);
}
push_32(BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value);
push_32(EIP);
load_seg_reg(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS], cs_raw);
EIP = disp32;
done:
RSP_COMMIT;
BX_INSTR_FAR_BRANCH(BX_CPU_ID, BX_INSTR_IS_CALL,
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value, EIP);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CALL_EdR(bxInstruction_c *i)
{
#if BX_DEBUGGER
BX_CPU_THIS_PTR show_flag |= Flag_call;
#endif
Bit32u new_EIP = BX_READ_32BIT_REG(i->rm());
RSP_SPECULATIVE;
/* push 32 bit EA of next instruction */
push_32(EIP);
branch_near32(new_EIP);
RSP_COMMIT;
BX_INSTR_UCNEAR_BRANCH(BX_CPU_ID, BX_INSTR_IS_CALL, EIP);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CALL32_Ep(bxInstruction_c *i)
{
Bit16u cs_raw;
Bit32u op1_32;
invalidate_prefetch_q();
#if BX_DEBUGGER
BX_CPU_THIS_PTR show_flag |= Flag_call;
#endif
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
/* pointer, segment address pair */
op1_32 = read_virtual_dword(i->seg(), eaddr);
cs_raw = read_virtual_word (i->seg(), (eaddr+4) & i->asize_mask());
RSP_SPECULATIVE;
if (protected_mode()) {
call_protected(i, cs_raw, op1_32);
goto done;
}
// CS.LIMIT can't change when in real/v8086 mode
if (op1_32 > BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.limit_scaled) {
BX_ERROR(("CALL32_Ep: instruction pointer not within code segment limits"));
exception(BX_GP_EXCEPTION, 0);
}
push_32(BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value);
push_32(EIP);
load_seg_reg(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS], cs_raw);
EIP = op1_32;
done:
RSP_COMMIT;
BX_INSTR_FAR_BRANCH(BX_CPU_ID, BX_INSTR_IS_CALL,
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value, EIP);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::JMP_Jd(bxInstruction_c *i)
{
Bit32u new_EIP = EIP + (Bit32s) i->Id();
branch_near32(new_EIP);
BX_INSTR_UCNEAR_BRANCH(BX_CPU_ID, BX_INSTR_IS_JMP, new_EIP);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::JO_Jd(bxInstruction_c *i)
{
if (get_OF()) {
Bit32u new_EIP = EIP + (Bit32s) i->Id();
branch_near32(new_EIP);
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, new_EIP);
}
#if BX_INSTRUMENTATION
else {
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
}
#endif
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::JNO_Jd(bxInstruction_c *i)
{
if (! get_OF()) {
Bit32u new_EIP = EIP + (Bit32s) i->Id();
branch_near32(new_EIP);
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, new_EIP);
}
#if BX_INSTRUMENTATION
else {
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
}
#endif
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::JB_Jd(bxInstruction_c *i)
{
if (get_CF()) {
Bit32u new_EIP = EIP + (Bit32s) i->Id();
branch_near32(new_EIP);
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, new_EIP);
}
#if BX_INSTRUMENTATION
else {
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
}
#endif
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::JNB_Jd(bxInstruction_c *i)
{
if (! get_CF()) {
Bit32u new_EIP = EIP + (Bit32s) i->Id();
branch_near32(new_EIP);
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, new_EIP);
}
#if BX_INSTRUMENTATION
else {
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
}
#endif
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::JZ_Jd(bxInstruction_c *i)
{
if (get_ZF()) {
Bit32u new_EIP = EIP + (Bit32s) i->Id();
branch_near32(new_EIP);
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, new_EIP);
}
#if BX_INSTRUMENTATION
else {
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
}
#endif
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::JNZ_Jd(bxInstruction_c *i)
{
if (! get_ZF()) {
Bit32u new_EIP = EIP + (Bit32s) i->Id();
branch_near32(new_EIP);
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, new_EIP);
}
#if BX_INSTRUMENTATION
else {
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
}
#endif
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::JBE_Jd(bxInstruction_c *i)
{
if (get_CF() || get_ZF()) {
Bit32u new_EIP = EIP + (Bit32s) i->Id();
branch_near32(new_EIP);
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, new_EIP);
}
#if BX_INSTRUMENTATION
else {
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
}
#endif
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::JNBE_Jd(bxInstruction_c *i)
{
if (! (get_CF() || get_ZF())) {
Bit32u new_EIP = EIP + (Bit32s) i->Id();
branch_near32(new_EIP);
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, new_EIP);
}
#if BX_INSTRUMENTATION
else {
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
}
#endif
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::JS_Jd(bxInstruction_c *i)
{
if (get_SF()) {
Bit32u new_EIP = EIP + (Bit32s) i->Id();
branch_near32(new_EIP);
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, new_EIP);
}
#if BX_INSTRUMENTATION
else {
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
}
#endif
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::JNS_Jd(bxInstruction_c *i)
{
if (! get_SF()) {
Bit32u new_EIP = EIP + (Bit32s) i->Id();
branch_near32(new_EIP);
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, new_EIP);
}
#if BX_INSTRUMENTATION
else {
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
}
#endif
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::JP_Jd(bxInstruction_c *i)
{
if (get_PF()) {
Bit32u new_EIP = EIP + (Bit32s) i->Id();
branch_near32(new_EIP);
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, new_EIP);
}
#if BX_INSTRUMENTATION
else {
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
}
#endif
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::JNP_Jd(bxInstruction_c *i)
{
if (! get_PF()) {
Bit32u new_EIP = EIP + (Bit32s) i->Id();
branch_near32(new_EIP);
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, new_EIP);
}
#if BX_INSTRUMENTATION
else {
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
}
#endif
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::JL_Jd(bxInstruction_c *i)
{
if (getB_SF() != getB_OF()) {
Bit32u new_EIP = EIP + (Bit32s) i->Id();
branch_near32(new_EIP);
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, new_EIP);
}
#if BX_INSTRUMENTATION
else {
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
}
#endif
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::JNL_Jd(bxInstruction_c *i)
{
if (getB_SF() == getB_OF()) {
Bit32u new_EIP = EIP + (Bit32s) i->Id();
branch_near32(new_EIP);
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, new_EIP);
}
#if BX_INSTRUMENTATION
else {
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
}
#endif
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::JLE_Jd(bxInstruction_c *i)
{
if (get_ZF() || (getB_SF() != getB_OF())) {
Bit32u new_EIP = EIP + (Bit32s) i->Id();
branch_near32(new_EIP);
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, new_EIP);
}
#if BX_INSTRUMENTATION
else {
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
}
#endif
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::JNLE_Jd(bxInstruction_c *i)
{
if (! get_ZF() && (getB_SF() == getB_OF())) {
Bit32u new_EIP = EIP + (Bit32s) i->Id();
branch_near32(new_EIP);
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, new_EIP);
}
#if BX_INSTRUMENTATION
else {
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
}
#endif
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::JMP_Ap(bxInstruction_c *i)
{
BX_ASSERT(BX_CPU_THIS_PTR cpu_mode != BX_MODE_LONG_64);
Bit32u disp32;
Bit16u cs_raw;
invalidate_prefetch_q();
if (i->os32L()) {
disp32 = i->Id();
}
else {
disp32 = i->Iw();
}
cs_raw = i->Iw2();
// jump_protected doesn't affect ESP so it is ESP safe
if (protected_mode()) {
jump_protected(i, cs_raw, disp32);
goto done;
}
// CS.LIMIT can't change when in real/v8086 mode
if (disp32 > BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.limit_scaled) {
BX_ERROR(("JMP_Ap: instruction pointer not within code segment limits"));
exception(BX_GP_EXCEPTION, 0);
}
load_seg_reg(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS], cs_raw);
EIP = disp32;
done:
BX_INSTR_FAR_BRANCH(BX_CPU_ID, BX_INSTR_IS_JMP,
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value, EIP);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::JMP_EdR(bxInstruction_c *i)
{
Bit32u new_EIP = BX_READ_32BIT_REG(i->rm());
branch_near32(new_EIP);
BX_INSTR_UCNEAR_BRANCH(BX_CPU_ID, BX_INSTR_IS_JMP, new_EIP);
}
/* Far indirect jump */
void BX_CPP_AttrRegparmN(1) BX_CPU_C::JMP32_Ep(bxInstruction_c *i)
{
Bit16u cs_raw;
Bit32u op1_32;
invalidate_prefetch_q();
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
/* pointer, segment address pair */
op1_32 = read_virtual_dword(i->seg(), eaddr);
cs_raw = read_virtual_word (i->seg(), (eaddr+4) & i->asize_mask());
// jump_protected doesn't affect RSP so it is RSP safe
if (protected_mode()) {
jump_protected(i, cs_raw, op1_32);
goto done;
}
// CS.LIMIT can't change when in real/v8086 mode
if (op1_32 > BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.limit_scaled) {
BX_ERROR(("JMP32_Ep: instruction pointer not within code segment limits"));
exception(BX_GP_EXCEPTION, 0);
}
load_seg_reg(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS], cs_raw);
EIP = op1_32;
done:
BX_INSTR_FAR_BRANCH(BX_CPU_ID, BX_INSTR_IS_JMP,
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value, EIP);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::IRET32(bxInstruction_c *i)
{
BX_ASSERT(BX_CPU_THIS_PTR cpu_mode != BX_MODE_LONG_64);
invalidate_prefetch_q();
#if BX_SUPPORT_VMX
if (!BX_CPU_THIS_PTR in_vmx_guest || !VMEXIT(VMX_VM_EXEC_CTRL1_NMI_VMEXIT))
#endif
BX_CPU_THIS_PTR disable_NMI = 0;
#if BX_DEBUGGER
BX_CPU_THIS_PTR show_flag |= Flag_iret;
#endif
if (protected_mode()) {
iret_protected(i);
goto done;
}
RSP_SPECULATIVE;
if (v8086_mode()) {
// IOPL check in stack_return_from_v86()
iret32_stack_return_from_v86(i);
}
else {
Bit32u eip = pop_32();
Bit16u cs_raw = (Bit16u) pop_32(); // #SS has higher priority
Bit32u eflags32 = pop_32();
// CS.LIMIT can't change when in real/v8086 mode
if (eip > BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.limit_scaled) {
BX_ERROR(("IRET32: instruction pointer not within code segment limits"));
exception(BX_GP_EXCEPTION, 0);
}
load_seg_reg(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS], cs_raw);
EIP = eip;
writeEFlags(eflags32, 0x00257fd5); // VIF, VIP, VM unchanged
}
RSP_COMMIT;
done:
BX_INSTR_FAR_BRANCH(BX_CPU_ID, BX_INSTR_IS_IRET,
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value, EIP);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::JECXZ_Jb(bxInstruction_c *i)
{
// it is impossible to get this instruction in long mode
BX_ASSERT(i->as64L() == 0);
Bit32u temp_ECX;
if (i->as32L())
temp_ECX = ECX;
else
temp_ECX = CX;
if (temp_ECX == 0) {
Bit32u new_EIP = EIP + (Bit32s) i->Id();
branch_near32(new_EIP);
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, new_EIP);
}
#if BX_INSTRUMENTATION
else {
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
}
#endif
}
//
// There is some weirdness in LOOP instructions definition. If an exception
// was generated during the instruction execution (for example #GP fault
// because EIP was beyond CS segment limits) CPU state should restore the
// state prior to instruction execution.
//
// The final point that we are not allowed to decrement ECX register before
// it is known that no exceptions can happen.
//
void BX_CPP_AttrRegparmN(1) BX_CPU_C::LOOPNE32_Jb(bxInstruction_c *i)
{
// it is impossible to get this instruction in long mode
BX_ASSERT(i->as64L() == 0);
if (i->as32L()) {
Bit32u count = ECX;
count--;
if (count != 0 && (get_ZF()==0)) {
Bit32u new_EIP = EIP + (Bit32s) i->Id();
branch_near32(new_EIP);
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, new_EIP);
}
#if BX_INSTRUMENTATION
else {
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
}
#endif
ECX = count;
}
else {
Bit16u count = CX;
count--;
if (count != 0 && (get_ZF()==0)) {
Bit32u new_EIP = EIP + (Bit32s) i->Id();
branch_near32(new_EIP);
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, new_EIP);
}
#if BX_INSTRUMENTATION
else {
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
}
#endif
CX = count;
}
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::LOOPE32_Jb(bxInstruction_c *i)
{
// it is impossible to get this instruction in long mode
BX_ASSERT(i->as64L() == 0);
if (i->as32L()) {
Bit32u count = ECX;
count--;
if (count != 0 && get_ZF()) {
Bit32u new_EIP = EIP + (Bit32s) i->Id();
branch_near32(new_EIP);
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, new_EIP);
}
#if BX_INSTRUMENTATION
else {
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
}
#endif
ECX = count;
}
else {
Bit16u count = CX;
count--;
if (count != 0 && get_ZF()) {
Bit32u new_EIP = EIP + (Bit32s) i->Id();
branch_near32(new_EIP);
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, new_EIP);
}
#if BX_INSTRUMENTATION
else {
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
}
#endif
CX = count;
}
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::LOOP32_Jb(bxInstruction_c *i)
{
// it is impossible to get this instruction in long mode
BX_ASSERT(i->as64L() == 0);
if (i->as32L()) {
Bit32u count = ECX;
count--;
if (count != 0) {
Bit32u new_EIP = EIP + (Bit32s) i->Id();
branch_near32(new_EIP);
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, new_EIP);
}
#if BX_INSTRUMENTATION
else {
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
}
#endif
ECX = count;
}
else {
Bit16u count = CX;
count--;
if (count != 0) {
Bit32u new_EIP = EIP + (Bit32s) i->Id();
branch_near32(new_EIP);
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, new_EIP);
}
#if BX_INSTRUMENTATION
else {
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
}
#endif
CX = count;
}
}
#endif

View File

@ -0,0 +1,576 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2001-2009 The Bochs Project
//
// 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
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA B 02110-1301 USA
/////////////////////////////////////////////////////////////////////////
#define NEED_CPU_REG_SHORTCUTS 1
#include "bochs.h"
#include "cpu.h"
#define LOG_THIS BX_CPU_THIS_PTR
#if BX_SUPPORT_X86_64
BX_CPP_INLINE void BX_CPP_AttrRegparmN(1) BX_CPU_C::branch_near64(bxInstruction_c *i)
{
Bit64u new_RIP = RIP + (Bit32s) i->Id();
if (! IsCanonical(new_RIP)) {
BX_ERROR(("branch_near64: canonical RIP violation"));
exception(BX_GP_EXCEPTION, 0);
}
RIP = new_RIP;
#if BX_SUPPORT_TRACE_CACHE && !defined(BX_TRACE_CACHE_NO_SPECULATIVE_TRACING)
// assert magic async_event to stop trace execution
BX_CPU_THIS_PTR async_event |= BX_ASYNC_EVENT_STOP_TRACE;
#endif
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::RETnear64_Iw(bxInstruction_c *i)
{
#if BX_DEBUGGER
BX_CPU_THIS_PTR show_flag |= Flag_ret;
#endif
Bit64u return_RIP = read_virtual_qword_64(BX_SEG_REG_SS, RSP);
if (! IsCanonical(return_RIP)) {
BX_ERROR(("RETnear64_Iw: canonical RIP violation"));
exception(BX_GP_EXCEPTION, 0);
}
RIP = return_RIP;
RSP += 8 + i->Iw();
BX_INSTR_UCNEAR_BRANCH(BX_CPU_ID, BX_INSTR_IS_RET, RIP);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::RETnear64(bxInstruction_c *i)
{
#if BX_DEBUGGER
BX_CPU_THIS_PTR show_flag |= Flag_ret;
#endif
Bit64u return_RIP = read_virtual_qword_64(BX_SEG_REG_SS, RSP);
if (! IsCanonical(return_RIP)) {
BX_ERROR(("RETnear64: canonical RIP violation %08x%08x", GET32H(return_RIP), GET32L(return_RIP)));
exception(BX_GP_EXCEPTION, 0);
}
RIP = return_RIP;
RSP += 8;
BX_INSTR_UCNEAR_BRANCH(BX_CPU_ID, BX_INSTR_IS_RET, RIP);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::RETfar64_Iw(bxInstruction_c *i)
{
invalidate_prefetch_q();
#if BX_DEBUGGER
BX_CPU_THIS_PTR show_flag |= Flag_ret;
#endif
BX_ASSERT(protected_mode());
// return_protected is RSP safe
return_protected(i, i->Iw());
BX_INSTR_FAR_BRANCH(BX_CPU_ID, BX_INSTR_IS_RET,
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value, RIP);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CALL_Jq(bxInstruction_c *i)
{
Bit64u new_RIP = RIP + (Bit32s) i->Id();
#if BX_DEBUGGER
BX_CPU_THIS_PTR show_flag |= Flag_call;
#endif
/* push 64 bit EA of next instruction */
write_virtual_qword_64(BX_SEG_REG_SS, RSP-8, RIP);
if (! IsCanonical(new_RIP)) {
BX_ERROR(("CALL_Jq: canonical RIP violation"));
exception(BX_GP_EXCEPTION, 0);
}
RIP = new_RIP;
RSP -= 8;
BX_INSTR_UCNEAR_BRANCH(BX_CPU_ID, BX_INSTR_IS_CALL, RIP);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CALL_EqR(bxInstruction_c *i)
{
#if BX_DEBUGGER
BX_CPU_THIS_PTR show_flag |= Flag_call;
#endif
Bit64u new_RIP = BX_READ_64BIT_REG(i->rm());
/* push 64 bit EA of next instruction */
write_virtual_qword_64(BX_SEG_REG_SS, RSP-8, RIP);
if (! IsCanonical(new_RIP))
{
BX_ERROR(("CALL_Eq: canonical RIP violation"));
exception(BX_GP_EXCEPTION, 0);
}
RIP = new_RIP;
RSP -= 8;
BX_INSTR_UCNEAR_BRANCH(BX_CPU_ID, BX_INSTR_IS_CALL, RIP);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CALL64_Ep(bxInstruction_c *i)
{
invalidate_prefetch_q();
#if BX_DEBUGGER
BX_CPU_THIS_PTR show_flag |= Flag_call;
#endif
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
/* pointer, segment address pair */
Bit64u op1_64 = read_virtual_qword_64(i->seg(), eaddr);
Bit16u cs_raw = read_virtual_word_64(i->seg(), (eaddr+8) & i->asize_mask());
BX_ASSERT(protected_mode());
// call_protected is RSP safe for 64-bit mode
call_protected(i, cs_raw, op1_64);
BX_INSTR_FAR_BRANCH(BX_CPU_ID, BX_INSTR_IS_CALL,
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value, RIP);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::JMP_Jq(bxInstruction_c *i)
{
Bit64u new_RIP = RIP + (Bit32s) i->Id();
if (! IsCanonical(new_RIP)) {
BX_ERROR(("JMP_Jq: canonical RIP violation"));
exception(BX_GP_EXCEPTION, 0);
}
RIP = new_RIP;
BX_INSTR_UCNEAR_BRANCH(BX_CPU_ID, BX_INSTR_IS_JMP, RIP);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::JO_Jq(bxInstruction_c *i)
{
if (get_OF()) {
branch_near64(i);
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, RIP);
}
#if BX_INSTRUMENTATION
else {
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
}
#endif
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::JNO_Jq(bxInstruction_c *i)
{
if (! get_OF()) {
branch_near64(i);
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, RIP);
}
#if BX_INSTRUMENTATION
else {
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
}
#endif
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::JB_Jq(bxInstruction_c *i)
{
if (get_CF()) {
branch_near64(i);
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, RIP);
}
#if BX_INSTRUMENTATION
else {
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
}
#endif
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::JNB_Jq(bxInstruction_c *i)
{
if (! get_CF()) {
branch_near64(i);
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, RIP);
}
#if BX_INSTRUMENTATION
else {
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
}
#endif
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::JZ_Jq(bxInstruction_c *i)
{
if (get_ZF()) {
branch_near64(i);
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, RIP);
}
#if BX_INSTRUMENTATION
else {
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
}
#endif
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::JNZ_Jq(bxInstruction_c *i)
{
if (! get_ZF()) {
branch_near64(i);
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, RIP);
}
#if BX_INSTRUMENTATION
else {
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
}
#endif
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::JBE_Jq(bxInstruction_c *i)
{
if (get_CF() || get_ZF()) {
branch_near64(i);
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, RIP);
}
#if BX_INSTRUMENTATION
else {
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
}
#endif
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::JNBE_Jq(bxInstruction_c *i)
{
if (! (get_CF() || get_ZF())) {
branch_near64(i);
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, RIP);
}
#if BX_INSTRUMENTATION
else {
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
}
#endif
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::JS_Jq(bxInstruction_c *i)
{
if (get_SF()) {
branch_near64(i);
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, RIP);
}
#if BX_INSTRUMENTATION
else {
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
}
#endif
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::JNS_Jq(bxInstruction_c *i)
{
if (! get_SF()) {
branch_near64(i);
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, RIP);
}
#if BX_INSTRUMENTATION
else {
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
}
#endif
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::JP_Jq(bxInstruction_c *i)
{
if (get_PF()) {
branch_near64(i);
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, RIP);
}
#if BX_INSTRUMENTATION
else {
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
}
#endif
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::JNP_Jq(bxInstruction_c *i)
{
if (! get_PF()) {
branch_near64(i);
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, RIP);
}
#if BX_INSTRUMENTATION
else {
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
}
#endif
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::JL_Jq(bxInstruction_c *i)
{
if (getB_SF() != getB_OF()) {
branch_near64(i);
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, RIP);
}
#if BX_INSTRUMENTATION
else {
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
}
#endif
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::JNL_Jq(bxInstruction_c *i)
{
if (getB_SF() == getB_OF()) {
branch_near64(i);
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, RIP);
}
#if BX_INSTRUMENTATION
else {
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
}
#endif
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::JLE_Jq(bxInstruction_c *i)
{
if (get_ZF() || (getB_SF() != getB_OF())) {
branch_near64(i);
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, RIP);
}
#if BX_INSTRUMENTATION
else {
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
}
#endif
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::JNLE_Jq(bxInstruction_c *i)
{
if (! get_ZF() && (getB_SF() == getB_OF())) {
branch_near64(i);
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, RIP);
}
#if BX_INSTRUMENTATION
else {
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
}
#endif
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::JMP_EqR(bxInstruction_c *i)
{
Bit64u op1_64 = BX_READ_64BIT_REG(i->rm());
if (! IsCanonical(op1_64)) {
BX_ERROR(("JMP_Eq: canonical RIP violation"));
exception(BX_GP_EXCEPTION, 0);
}
RIP = op1_64;
BX_INSTR_UCNEAR_BRANCH(BX_CPU_ID, BX_INSTR_IS_JMP, RIP);
}
/* Far indirect jump */
void BX_CPP_AttrRegparmN(1) BX_CPU_C::JMP64_Ep(bxInstruction_c *i)
{
invalidate_prefetch_q();
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
Bit64u op1_64 = read_virtual_qword_64(i->seg(), eaddr);
Bit16u cs_raw = read_virtual_word_64(i->seg(), (eaddr+8) & i->asize_mask());
BX_ASSERT(protected_mode());
jump_protected(i, cs_raw, op1_64);
BX_INSTR_FAR_BRANCH(BX_CPU_ID, BX_INSTR_IS_JMP,
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value, RIP);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::IRET64(bxInstruction_c *i)
{
invalidate_prefetch_q();
#if BX_SUPPORT_VMX
if (!BX_CPU_THIS_PTR in_vmx_guest || !VMEXIT(VMX_VM_EXEC_CTRL1_NMI_VMEXIT))
#endif
BX_CPU_THIS_PTR disable_NMI = 0;
#if BX_DEBUGGER
BX_CPU_THIS_PTR show_flag |= Flag_iret;
#endif
BX_ASSERT(long_mode());
long_iret(i);
BX_INSTR_FAR_BRANCH(BX_CPU_ID, BX_INSTR_IS_IRET,
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value, RIP);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::JRCXZ_Jb(bxInstruction_c *i)
{
Bit64u temp_RCX;
if (i->as64L())
temp_RCX = RCX;
else
temp_RCX = ECX;
if (temp_RCX == 0) {
branch_near64(i);
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, RIP);
}
#if BX_INSTRUMENTATION
else {
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
}
#endif
}
//
// There is some weirdness in LOOP instructions definition. If an exception
// was generated during the instruction execution (for example #GP fault
// because EIP was beyond CS segment limits) CPU state should restore the
// state prior to instruction execution.
//
// The final point that we are not allowed to decrement RCX register before
// it is known that no exceptions can happen.
//
void BX_CPP_AttrRegparmN(1) BX_CPU_C::LOOPNE64_Jb(bxInstruction_c *i)
{
if (i->as64L()) {
Bit64u count = RCX;
if (((--count) != 0) && (get_ZF()==0)) {
branch_near64(i);
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, RIP);
}
#if BX_INSTRUMENTATION
else {
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
}
#endif
RCX = count;
}
else {
Bit32u count = ECX;
if (((--count) != 0) && (get_ZF()==0)) {
branch_near64(i);
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, RIP);
}
#if BX_INSTRUMENTATION
else {
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
}
#endif
RCX = count;
}
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::LOOPE64_Jb(bxInstruction_c *i)
{
if (i->as64L()) {
Bit64u count = RCX;
if (((--count) != 0) && get_ZF()) {
branch_near64(i);
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, RIP);
}
#if BX_INSTRUMENTATION
else {
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
}
#endif
RCX = count;
}
else {
Bit32u count = ECX;
if (((--count) != 0) && get_ZF()) {
branch_near64(i);
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, RIP);
}
#if BX_INSTRUMENTATION
else {
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
}
#endif
RCX = count;
}
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::LOOP64_Jb(bxInstruction_c *i)
{
if (i->as64L()) {
Bit64u count = RCX;
if ((--count) != 0) {
branch_near64(i);
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, RIP);
}
#if BX_INSTRUMENTATION
else {
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
}
#endif
RCX = count;
}
else {
Bit32u count = ECX;
if ((--count) != 0) {
branch_near64(i);
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, RIP);
}
#if BX_INSTRUMENTATION
else {
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
}
#endif
RCX = count;
}
}
#endif /* if BX_SUPPORT_X86_64 */

View File

@ -0,0 +1,165 @@
////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2001-2009 The Bochs Project
//
// 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
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA B 02110-1301 USA
/////////////////////////////////////////////////////////////////////////
#define NEED_CPU_REG_SHORTCUTS 1
#include "bochs.h"
#include "cpu.h"
#define LOG_THIS BX_CPU_THIS_PTR
#if BX_SUPPORT_X86_64==0
// Make life easier merging cpu64 & cpu code.
#define RIP EIP
#endif
/* pass zero in check_rpl if no needed selector RPL checking for
non-conforming segments */
void BX_CPU_C::check_cs(bx_descriptor_t *descriptor, Bit16u cs_raw, Bit8u check_rpl, Bit8u check_cpl)
{
// descriptor AR byte must indicate code segment else #GP(selector)
if (descriptor->valid==0 || descriptor->segment==0 ||
IS_DATA_SEGMENT(descriptor->type))
{
BX_ERROR(("check_cs(0x%04x): not a valid code segment !", cs_raw));
exception(BX_GP_EXCEPTION, cs_raw & 0xfffc);
}
#if BX_SUPPORT_X86_64
if (long_mode()) {
if (descriptor->u.segment.l && descriptor->u.segment.d_b) {
BX_ERROR(("check_cs(0x%04x): Both CS.L and CS.D_B bits enabled !", cs_raw));
exception(BX_GP_EXCEPTION, cs_raw & 0xfffc);
}
}
#endif
// if non-conforming, code segment descriptor DPL must = CPL else #GP(selector)
if (IS_CODE_SEGMENT_NON_CONFORMING(descriptor->type)) {
if (descriptor->dpl != check_cpl) {
BX_ERROR(("check_cs(0x%04x): non-conforming code seg descriptor dpl != cpl, dpl=%d, cpl=%d",
cs_raw, descriptor->dpl, check_cpl));
exception(BX_GP_EXCEPTION, cs_raw & 0xfffc);
}
/* RPL of destination selector must be <= CPL else #GP(selector) */
if (check_rpl > check_cpl) {
BX_ERROR(("check_cs(0x%04x): non-conforming code seg selector rpl > cpl, rpl=%d, cpl=%d",
cs_raw, check_rpl, check_cpl));
exception(BX_GP_EXCEPTION, cs_raw & 0xfffc);
}
}
// if conforming, then code segment descriptor DPL must <= CPL else #GP(selector)
else {
if (descriptor->dpl > check_cpl) {
BX_ERROR(("check_cs(0x%04x): conforming code seg descriptor dpl > cpl, dpl=%d, cpl=%d",
cs_raw, descriptor->dpl, check_cpl));
exception(BX_GP_EXCEPTION, cs_raw & 0xfffc);
}
}
// code segment must be present else #NP(selector)
if (! descriptor->p) {
BX_ERROR(("check_cs(0x%04x): code segment not present !", cs_raw));
exception(BX_NP_EXCEPTION, cs_raw & 0xfffc);
}
}
void BX_CPP_AttrRegparmN(3)
BX_CPU_C::load_cs(bx_selector_t *selector, bx_descriptor_t *descriptor, Bit8u cpl)
{
// Add cpl to the selector value.
selector->value = (0xfffc & selector->value) | cpl;
touch_segment(selector, descriptor);
#ifdef BX_SUPPORT_CS_LIMIT_DEMOTION
// Handle special case of CS.LIMIT demotion (new descriptor limit is
// smaller than current one)
if (BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.limit_scaled > descriptor->u.segment.limit_scaled)
BX_CPU_THIS_PTR iCache.flushICacheEntries();
#endif
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector = *selector;
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache = *descriptor;
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.rpl = cpl;
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.valid = 1;
#if BX_SUPPORT_X86_64
if (long_mode()) {
handleCpuModeChange();
}
#endif
updateFetchModeMask(/* CS reloaded */);
#if BX_CPU_LEVEL >= 4 && BX_SUPPORT_ALIGNMENT_CHECK
handleAlignmentCheck(/* CPL change */);
#endif
// Loading CS will invalidate the EIP fetch window.
invalidate_prefetch_q();
}
void BX_CPU_C::branch_far32(bx_selector_t *selector,
bx_descriptor_t *descriptor, Bit32u eip, Bit8u cpl)
{
/* instruction pointer must be in code segment limit else #GP(0) */
if (eip > descriptor->u.segment.limit_scaled) {
BX_ERROR(("branch_far32: EIP > limit"));
exception(BX_GP_EXCEPTION, 0);
}
/* Load CS:IP from destination pointer */
/* Load CS-cache with new segment descriptor */
load_cs(selector, descriptor, cpl);
/* Change the EIP value */
EIP = eip;
}
void BX_CPU_C::branch_far64(bx_selector_t *selector,
bx_descriptor_t *descriptor, bx_address rip, Bit8u cpl)
{
#if BX_SUPPORT_X86_64
if (long_mode() && descriptor->u.segment.l) {
if (! IsCanonical(rip)) {
BX_ERROR(("branch_far64: canonical RIP violation"));
exception(BX_GP_EXCEPTION, 0);
}
}
else
#endif
{
rip &= 0xffffffff;
/* instruction pointer must be in code segment limit else #GP(0) */
if (rip > descriptor->u.segment.limit_scaled) {
BX_ERROR(("branch_far64: RIP > limit"));
exception(BX_GP_EXCEPTION, 0);
}
}
/* Load CS:IP from destination pointer */
/* Load CS-cache with new segment descriptor */
load_cs(selector, descriptor, cpl);
/* Change the RIP value */
RIP = rip;
}

View File

@ -0,0 +1,313 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2001-2009 The Bochs Project
//
// 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
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA B 02110-1301 USA
/////////////////////////////////////////////////////////////////////////
#define NEED_CPU_REG_SHORTCUTS 1
#include "bochs.h"
#include "cpu.h"
#define LOG_THIS BX_CPU_THIS_PTR
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOV_RXIw(bxInstruction_c *i)
{
BX_WRITE_16BIT_REG(i->rm(), i->Iw());
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::XCHG_RXAX(bxInstruction_c *i)
{
Bit16u temp16 = AX;
AX = BX_READ_16BIT_REG(i->rm());
BX_WRITE_16BIT_REG(i->rm(), temp16);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOV_EwGwM(bxInstruction_c *i)
{
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
write_virtual_word(i->seg(), eaddr, BX_READ_16BIT_REG(i->nnn()));
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOV_GwEwR(bxInstruction_c *i)
{
BX_WRITE_16BIT_REG(i->nnn(), BX_READ_16BIT_REG(i->rm()));
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOV_GwEwM(bxInstruction_c *i)
{
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
Bit16u val16 = read_virtual_word(i->seg(), eaddr);
BX_WRITE_16BIT_REG(i->nnn(), val16);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOV_EwSwR(bxInstruction_c *i)
{
/* Illegal to use nonexisting segments */
if (i->nnn() >= 6) {
BX_INFO(("MOV_EwSw: using of nonexisting segment register %d", i->nnn()));
exception(BX_UD_EXCEPTION, 0);
}
Bit16u seg_reg = BX_CPU_THIS_PTR sregs[i->nnn()].selector.value;
if (i->os32L()) {
BX_WRITE_32BIT_REGZ(i->rm(), seg_reg);
}
else {
BX_WRITE_16BIT_REG(i->rm(), seg_reg);
}
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOV_EwSwM(bxInstruction_c *i)
{
/* Illegal to use nonexisting segments */
if (i->nnn() >= 6) {
BX_INFO(("MOV_EwSw: using of nonexisting segment register %d", i->nnn()));
exception(BX_UD_EXCEPTION, 0);
}
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
Bit16u seg_reg = BX_CPU_THIS_PTR sregs[i->nnn()].selector.value;
write_virtual_word(i->seg(), eaddr, seg_reg);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOV_SwEw(bxInstruction_c *i)
{
Bit16u op2_16;
/* Attempt to load CS or nonexisting segment register */
if (i->nnn() >= 6 || i->nnn() == BX_SEG_REG_CS) {
BX_INFO(("MOV_EwSw: can't use this segment register %d", i->nnn()));
exception(BX_UD_EXCEPTION, 0);
}
if (i->modC0()) {
op2_16 = BX_READ_16BIT_REG(i->rm());
}
else {
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
/* pointer, segment address pair */
op2_16 = read_virtual_word(i->seg(), eaddr);
}
load_seg_reg(&BX_CPU_THIS_PTR sregs[i->nnn()], op2_16);
if (i->nnn() == BX_SEG_REG_SS) {
// MOV SS inhibits interrupts, debug exceptions and single-step
// trap exceptions until the execution boundary following the
// next instruction is reached.
// Same code as POP_SS()
BX_CPU_THIS_PTR inhibit_mask |= BX_INHIBIT_INTERRUPTS_BY_MOVSS;
BX_CPU_THIS_PTR async_event = 1;
}
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::LEA_GwM(bxInstruction_c *i)
{
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
BX_WRITE_16BIT_REG(i->nnn(), (Bit16u) eaddr);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOV_AXOd(bxInstruction_c *i)
{
AX = read_virtual_word_32(i->seg(), i->Id());
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOV_OdAX(bxInstruction_c *i)
{
write_virtual_word_32(i->seg(), i->Id(), AX);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOV_EwIwM(bxInstruction_c *i)
{
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
write_virtual_word(i->seg(), eaddr, i->Iw());
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOVZX_GwEbM(bxInstruction_c *i)
{
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
Bit8u op2_8 = read_virtual_byte(i->seg(), eaddr);
/* zero extend byte op2 into word op1 */
BX_WRITE_16BIT_REG(i->nnn(), (Bit16u) op2_8);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOVZX_GwEbR(bxInstruction_c *i)
{
Bit8u op2_8 = BX_READ_8BIT_REGx(i->rm(), i->extend8bitL());
/* zero extend byte op2 into word op1 */
BX_WRITE_16BIT_REG(i->nnn(), (Bit16u) op2_8);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOVSX_GwEbM(bxInstruction_c *i)
{
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
Bit8u op2_8 = read_virtual_byte(i->seg(), eaddr);
/* sign extend byte op2 into word op1 */
BX_WRITE_16BIT_REG(i->nnn(), (Bit8s) op2_8);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOVSX_GwEbR(bxInstruction_c *i)
{
Bit8u op2_8 = BX_READ_8BIT_REGx(i->rm(),i->extend8bitL());
/* sign extend byte op2 into word op1 */
BX_WRITE_16BIT_REG(i->nnn(), (Bit8s) op2_8);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::XCHG_EwGwM(bxInstruction_c *i)
{
Bit16u op1_16, op2_16;
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
op1_16 = read_RMW_virtual_word(i->seg(), eaddr);
op2_16 = BX_READ_16BIT_REG(i->nnn());
write_RMW_virtual_word(op2_16);
BX_WRITE_16BIT_REG(i->nnn(), op1_16);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::XCHG_EwGwR(bxInstruction_c *i)
{
Bit16u op1_16, op2_16;
#if BX_DEBUGGER
// Note for mortals: the instruction to trigger this is "xchgw %bx,%bx"
if (bx_dbg.magic_break_enabled && (i->nnn() == 3) && (i->rm() == 3))
{
BX_CPU_THIS_PTR magic_break = 1;
return;
}
#endif
op1_16 = BX_READ_16BIT_REG(i->rm());
op2_16 = BX_READ_16BIT_REG(i->nnn());
BX_WRITE_16BIT_REG(i->nnn(), op1_16);
BX_WRITE_16BIT_REG(i->rm(), op2_16);
}
// Note: CMOV accesses a memory source operand (read), regardless
// of whether condition is true or not. Thus, exceptions may
// occur even if the MOV does not take place.
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMOVO_GwEwR(bxInstruction_c *i)
{
if (get_OF())
BX_WRITE_16BIT_REG(i->nnn(), BX_READ_16BIT_REG(i->rm()));
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMOVNO_GwEwR(bxInstruction_c *i)
{
if (!get_OF())
BX_WRITE_16BIT_REG(i->nnn(), BX_READ_16BIT_REG(i->rm()));
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMOVB_GwEwR(bxInstruction_c *i)
{
if (get_CF())
BX_WRITE_16BIT_REG(i->nnn(), BX_READ_16BIT_REG(i->rm()));
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMOVNB_GwEwR(bxInstruction_c *i)
{
if (!get_CF())
BX_WRITE_16BIT_REG(i->nnn(), BX_READ_16BIT_REG(i->rm()));
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMOVZ_GwEwR(bxInstruction_c *i)
{
if (get_ZF())
BX_WRITE_16BIT_REG(i->nnn(), BX_READ_16BIT_REG(i->rm()));
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMOVNZ_GwEwR(bxInstruction_c *i)
{
if (!get_ZF())
BX_WRITE_16BIT_REG(i->nnn(), BX_READ_16BIT_REG(i->rm()));
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMOVBE_GwEwR(bxInstruction_c *i)
{
if (get_CF() || get_ZF())
BX_WRITE_16BIT_REG(i->nnn(), BX_READ_16BIT_REG(i->rm()));
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMOVNBE_GwEwR(bxInstruction_c *i)
{
if (! (get_CF() || get_ZF()))
BX_WRITE_16BIT_REG(i->nnn(), BX_READ_16BIT_REG(i->rm()));
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMOVS_GwEwR(bxInstruction_c *i)
{
if (get_SF())
BX_WRITE_16BIT_REG(i->nnn(), BX_READ_16BIT_REG(i->rm()));
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMOVNS_GwEwR(bxInstruction_c *i)
{
if (!get_SF())
BX_WRITE_16BIT_REG(i->nnn(), BX_READ_16BIT_REG(i->rm()));
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMOVP_GwEwR(bxInstruction_c *i)
{
if (get_PF())
BX_WRITE_16BIT_REG(i->nnn(), BX_READ_16BIT_REG(i->rm()));
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMOVNP_GwEwR(bxInstruction_c *i)
{
if (!get_PF())
BX_WRITE_16BIT_REG(i->nnn(), BX_READ_16BIT_REG(i->rm()));
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMOVL_GwEwR(bxInstruction_c *i)
{
if (getB_SF() != getB_OF())
BX_WRITE_16BIT_REG(i->nnn(), BX_READ_16BIT_REG(i->rm()));
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMOVNL_GwEwR(bxInstruction_c *i)
{
if (getB_SF() == getB_OF())
BX_WRITE_16BIT_REG(i->nnn(), BX_READ_16BIT_REG(i->rm()));
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMOVLE_GwEwR(bxInstruction_c *i)
{
if (get_ZF() || (getB_SF() != getB_OF()))
BX_WRITE_16BIT_REG(i->nnn(), BX_READ_16BIT_REG(i->rm()));
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMOVNLE_GwEwR(bxInstruction_c *i)
{
if (! get_ZF() && (getB_SF() == getB_OF()))
BX_WRITE_16BIT_REG(i->nnn(), BX_READ_16BIT_REG(i->rm()));
}

View File

@ -0,0 +1,317 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2001-2009 The Bochs Project
//
// 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
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA B 02110-1301 USA
/////////////////////////////////////////////////////////////////////////
#define NEED_CPU_REG_SHORTCUTS 1
#include "bochs.h"
#include "cpu.h"
#define LOG_THIS BX_CPU_THIS_PTR
#if BX_SUPPORT_X86_64==0
// Make life easier for merging cpu64 and cpu32 code.
#define RAX EAX
#endif
void BX_CPP_AttrRegparmN(1) BX_CPU_C::XCHG_ERXEAX(bxInstruction_c *i)
{
#if BX_SUPPORT_X86_64
if (i->rm() == 0) // 'xchg eax, eax' is NOP even in 64-bit mode
return;
#endif
Bit32u temp32 = EAX;
RAX = BX_READ_32BIT_REG(i->rm());
BX_WRITE_32BIT_REGZ(i->rm(), temp32);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOV_ERXId(bxInstruction_c *i)
{
BX_WRITE_32BIT_REGZ(i->rm(), i->Id());
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOV32_EdGdM(bxInstruction_c *i)
{
Bit32u eaddr = (Bit32u) BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
write_virtual_dword_32(i->seg(), eaddr, BX_READ_32BIT_REG(i->nnn()));
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOV_GdEdR(bxInstruction_c *i)
{
BX_WRITE_32BIT_REGZ(i->nnn(), BX_READ_32BIT_REG(i->rm()));
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOV32_GdEdM(bxInstruction_c *i)
{
Bit32u eaddr = (Bit32u) BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
Bit32u val32 = read_virtual_dword_32(i->seg(), eaddr);
BX_WRITE_32BIT_REGZ(i->nnn(), val32);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::LEA_GdM(bxInstruction_c *i)
{
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
BX_WRITE_32BIT_REGZ(i->nnn(), eaddr);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOV_EAXOd(bxInstruction_c *i)
{
RAX = read_virtual_dword_32(i->seg(), i->Id());
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOV_OdEAX(bxInstruction_c *i)
{
write_virtual_dword_32(i->seg(), i->Id(), EAX);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOV_EdIdM(bxInstruction_c *i)
{
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
write_virtual_dword(i->seg(), eaddr, i->Id());
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOVZX_GdEbM(bxInstruction_c *i)
{
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
Bit8u op2_8 = read_virtual_byte(i->seg(), eaddr);
/* zero extend byte op2 into dword op1 */
BX_WRITE_32BIT_REGZ(i->nnn(), (Bit32u) op2_8);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOVZX_GdEbR(bxInstruction_c *i)
{
Bit8u op2_8 = BX_READ_8BIT_REGx(i->rm(), i->extend8bitL());
/* zero extend byte op2 into dword op1 */
BX_WRITE_32BIT_REGZ(i->nnn(), (Bit32u) op2_8);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOVZX_GdEwM(bxInstruction_c *i)
{
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
Bit16u op2_16 = read_virtual_word(i->seg(), eaddr);
/* zero extend word op2 into dword op1 */
BX_WRITE_32BIT_REGZ(i->nnn(), (Bit32u) op2_16);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOVZX_GdEwR(bxInstruction_c *i)
{
Bit16u op2_16 = BX_READ_16BIT_REG(i->rm());
/* zero extend word op2 into dword op1 */
BX_WRITE_32BIT_REGZ(i->nnn(), (Bit32u) op2_16);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOVSX_GdEbM(bxInstruction_c *i)
{
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
Bit8u op2_8 = read_virtual_byte(i->seg(), eaddr);
/* sign extend byte op2 into dword op1 */
BX_WRITE_32BIT_REGZ(i->nnn(), (Bit8s) op2_8);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOVSX_GdEbR(bxInstruction_c *i)
{
Bit8u op2_8 = BX_READ_8BIT_REGx(i->rm(), i->extend8bitL());
/* sign extend byte op2 into dword op1 */
BX_WRITE_32BIT_REGZ(i->nnn(), (Bit8s) op2_8);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOVSX_GdEwM(bxInstruction_c *i)
{
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
Bit16u op2_16 = read_virtual_word(i->seg(), eaddr);
/* sign extend word op2 into dword op1 */
BX_WRITE_32BIT_REGZ(i->nnn(), (Bit16s) op2_16);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOVSX_GdEwR(bxInstruction_c *i)
{
Bit16u op2_16 = BX_READ_16BIT_REG(i->rm());
/* sign extend word op2 into dword op1 */
BX_WRITE_32BIT_REGZ(i->nnn(), (Bit16s) op2_16);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::XCHG_EdGdM(bxInstruction_c *i)
{
Bit32u op2_32, op1_32;
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
op1_32 = read_RMW_virtual_dword(i->seg(), eaddr);
op2_32 = BX_READ_32BIT_REG(i->nnn());
write_RMW_virtual_dword(op2_32);
BX_WRITE_32BIT_REGZ(i->nnn(), op1_32);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::XCHG_EdGdR(bxInstruction_c *i)
{
Bit32u op1_32 = BX_READ_32BIT_REG(i->rm());
Bit32u op2_32 = BX_READ_32BIT_REG(i->nnn());
BX_WRITE_32BIT_REGZ(i->nnn(), op1_32);
BX_WRITE_32BIT_REGZ(i->rm(), op2_32);
}
// Note: CMOV accesses a memory source operand (read), regardless
// of whether condition is true or not. Thus, exceptions may
// occur even if the MOV does not take place.
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMOVO_GdEdR(bxInstruction_c *i)
{
if (get_OF())
BX_WRITE_32BIT_REGZ(i->nnn(), BX_READ_32BIT_REG(i->rm()));
BX_CLEAR_64BIT_HIGH(i->nnn()); // always clear upper part of the register
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMOVNO_GdEdR(bxInstruction_c *i)
{
if (!get_OF())
BX_WRITE_32BIT_REGZ(i->nnn(), BX_READ_32BIT_REG(i->rm()));
BX_CLEAR_64BIT_HIGH(i->nnn()); // always clear upper part of the register
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMOVB_GdEdR(bxInstruction_c *i)
{
if (get_CF())
BX_WRITE_32BIT_REGZ(i->nnn(), BX_READ_32BIT_REG(i->rm()));
BX_CLEAR_64BIT_HIGH(i->nnn()); // always clear upper part of the register
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMOVNB_GdEdR(bxInstruction_c *i)
{
if (!get_CF())
BX_WRITE_32BIT_REGZ(i->nnn(), BX_READ_32BIT_REG(i->rm()));
BX_CLEAR_64BIT_HIGH(i->nnn()); // always clear upper part of the register
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMOVZ_GdEdR(bxInstruction_c *i)
{
if (get_ZF())
BX_WRITE_32BIT_REGZ(i->nnn(), BX_READ_32BIT_REG(i->rm()));
BX_CLEAR_64BIT_HIGH(i->nnn()); // always clear upper part of the register
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMOVNZ_GdEdR(bxInstruction_c *i)
{
if (!get_ZF())
BX_WRITE_32BIT_REGZ(i->nnn(), BX_READ_32BIT_REG(i->rm()));
BX_CLEAR_64BIT_HIGH(i->nnn()); // always clear upper part of the register
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMOVBE_GdEdR(bxInstruction_c *i)
{
if (get_CF() || get_ZF())
BX_WRITE_32BIT_REGZ(i->nnn(), BX_READ_32BIT_REG(i->rm()));
BX_CLEAR_64BIT_HIGH(i->nnn()); // always clear upper part of the register
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMOVNBE_GdEdR(bxInstruction_c *i)
{
if (! (get_CF() || get_ZF()))
BX_WRITE_32BIT_REGZ(i->nnn(), BX_READ_32BIT_REG(i->rm()));
BX_CLEAR_64BIT_HIGH(i->nnn()); // always clear upper part of the register
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMOVS_GdEdR(bxInstruction_c *i)
{
if (get_SF())
BX_WRITE_32BIT_REGZ(i->nnn(), BX_READ_32BIT_REG(i->rm()));
BX_CLEAR_64BIT_HIGH(i->nnn()); // always clear upper part of the register
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMOVNS_GdEdR(bxInstruction_c *i)
{
if (!get_SF())
BX_WRITE_32BIT_REGZ(i->nnn(), BX_READ_32BIT_REG(i->rm()));
BX_CLEAR_64BIT_HIGH(i->nnn()); // always clear upper part of the register
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMOVP_GdEdR(bxInstruction_c *i)
{
if (get_PF())
BX_WRITE_32BIT_REGZ(i->nnn(), BX_READ_32BIT_REG(i->rm()));
BX_CLEAR_64BIT_HIGH(i->nnn()); // always clear upper part of the register
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMOVNP_GdEdR(bxInstruction_c *i)
{
if (!get_PF())
BX_WRITE_32BIT_REGZ(i->nnn(), BX_READ_32BIT_REG(i->rm()));
BX_CLEAR_64BIT_HIGH(i->nnn()); // always clear upper part of the register
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMOVL_GdEdR(bxInstruction_c *i)
{
if (getB_SF() != getB_OF())
BX_WRITE_32BIT_REGZ(i->nnn(), BX_READ_32BIT_REG(i->rm()));
BX_CLEAR_64BIT_HIGH(i->nnn()); // always clear upper part of the register
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMOVNL_GdEdR(bxInstruction_c *i)
{
if (getB_SF() == getB_OF())
BX_WRITE_32BIT_REGZ(i->nnn(), BX_READ_32BIT_REG(i->rm()));
BX_CLEAR_64BIT_HIGH(i->nnn()); // always clear upper part of the register
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMOVLE_GdEdR(bxInstruction_c *i)
{
if (get_ZF() || (getB_SF() != getB_OF()))
BX_WRITE_32BIT_REGZ(i->nnn(), BX_READ_32BIT_REG(i->rm()));
BX_CLEAR_64BIT_HIGH(i->nnn()); // always clear upper part of the register
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMOVNLE_GdEdR(bxInstruction_c *i)
{
if (! get_ZF() && (getB_SF() == getB_OF()))
BX_WRITE_32BIT_REGZ(i->nnn(), BX_READ_32BIT_REG(i->rm()));
BX_CLEAR_64BIT_HIGH(i->nnn()); // always clear upper part of the register
}

View File

@ -0,0 +1,350 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2001-2009 The Bochs Project
//
// 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
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA B 02110-1301 USA
/////////////////////////////////////////////////////////////////////////
#define NEED_CPU_REG_SHORTCUTS 1
#include "bochs.h"
#include "cpu.h"
#define LOG_THIS BX_CPU_THIS_PTR
#if BX_SUPPORT_X86_64
void BX_CPP_AttrRegparmN(1) BX_CPU_C::XCHG_RRXRAX(bxInstruction_c *i)
{
Bit64u temp64 = RAX;
RAX = BX_READ_64BIT_REG(i->rm());
BX_WRITE_64BIT_REG(i->rm(), temp64);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOV_RRXIq(bxInstruction_c *i)
{
BX_WRITE_64BIT_REG(i->rm(), i->Iq());
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOV64_GdEdM(bxInstruction_c *i)
{
Bit64u eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
Bit32u val32 = read_virtual_dword_64(i->seg(), eaddr);
BX_WRITE_32BIT_REGZ(i->nnn(), val32);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOV64_EdGdM(bxInstruction_c *i)
{
Bit64u eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
write_virtual_dword_64(i->seg(), eaddr, BX_READ_32BIT_REG(i->nnn()));
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOV_EqGqM(bxInstruction_c *i)
{
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
write_virtual_qword_64(i->seg(), eaddr, BX_READ_64BIT_REG(i->nnn()));
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOV_GqEqM(bxInstruction_c *i)
{
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
Bit64u val64 = read_virtual_qword_64(i->seg(), eaddr);
BX_WRITE_64BIT_REG(i->nnn(), val64);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOV_GqEqR(bxInstruction_c *i)
{
BX_WRITE_64BIT_REG(i->nnn(), BX_READ_64BIT_REG(i->rm()));
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::LEA_GqM(bxInstruction_c *i)
{
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
BX_WRITE_64BIT_REG(i->nnn(), eaddr);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOV_ALOq(bxInstruction_c *i)
{
AL = read_virtual_byte_64(i->seg(), i->Iq());
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOV_OqAL(bxInstruction_c *i)
{
write_virtual_byte_64(i->seg(), i->Iq(), AL);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOV_AXOq(bxInstruction_c *i)
{
AX = read_virtual_word_64(i->seg(), i->Iq());
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOV_OqAX(bxInstruction_c *i)
{
write_virtual_word_64(i->seg(), i->Iq(), AX);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOV_EAXOq(bxInstruction_c *i)
{
RAX = read_virtual_dword_64(i->seg(), i->Iq());
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOV_OqEAX(bxInstruction_c *i)
{
write_virtual_dword_64(i->seg(), i->Iq(), EAX);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOV_RAXOq(bxInstruction_c *i)
{
RAX = read_virtual_qword_64(i->seg(), i->Iq());
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOV_OqRAX(bxInstruction_c *i)
{
write_virtual_qword_64(i->seg(), i->Iq(), RAX);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOV_EqIdM(bxInstruction_c *i)
{
Bit64u op_64 = (Bit32s) i->Id();
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
write_virtual_qword_64(i->seg(), eaddr, op_64);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOV_EqIdR(bxInstruction_c *i)
{
Bit64u op_64 = (Bit32s) i->Id();
BX_WRITE_64BIT_REG(i->rm(), op_64);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOVZX_GqEbM(bxInstruction_c *i)
{
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
Bit8u op2_8 = read_virtual_byte_64(i->seg(), eaddr);
/* zero extend byte op2 into qword op1 */
BX_WRITE_64BIT_REG(i->nnn(), (Bit64u) op2_8);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOVZX_GqEbR(bxInstruction_c *i)
{
Bit8u op2_8 = BX_READ_8BIT_REGx(i->rm(), i->extend8bitL());
/* zero extend byte op2 into qword op1 */
BX_WRITE_64BIT_REG(i->nnn(), (Bit64u) op2_8);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOVZX_GqEwM(bxInstruction_c *i)
{
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
Bit16u op2_16 = read_virtual_word_64(i->seg(), eaddr);
/* zero extend word op2 into qword op1 */
BX_WRITE_64BIT_REG(i->nnn(), (Bit64u) op2_16);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOVZX_GqEwR(bxInstruction_c *i)
{
Bit16u op2_16 = BX_READ_16BIT_REG(i->rm());
/* zero extend word op2 into qword op1 */
BX_WRITE_64BIT_REG(i->nnn(), (Bit64u) op2_16);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOVSX_GqEbM(bxInstruction_c *i)
{
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
Bit8u op2_8 = read_virtual_byte_64(i->seg(), eaddr);
/* sign extend byte op2 into qword op1 */
BX_WRITE_64BIT_REG(i->nnn(), (Bit8s) op2_8);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOVSX_GqEbR(bxInstruction_c *i)
{
Bit8u op2_8 = BX_READ_8BIT_REGx(i->rm(), i->extend8bitL());
/* sign extend byte op2 into qword op1 */
BX_WRITE_64BIT_REG(i->nnn(), (Bit8s) op2_8);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOVSX_GqEwM(bxInstruction_c *i)
{
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
Bit16u op2_16 = read_virtual_word_64(i->seg(), eaddr);
/* sign extend word op2 into qword op1 */
BX_WRITE_64BIT_REG(i->nnn(), (Bit16s) op2_16);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOVSX_GqEwR(bxInstruction_c *i)
{
Bit16u op2_16 = BX_READ_16BIT_REG(i->rm());
/* sign extend word op2 into qword op1 */
BX_WRITE_64BIT_REG(i->nnn(), (Bit16s) op2_16);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOVSX_GqEdM(bxInstruction_c *i)
{
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
Bit32u op2_32 = read_virtual_dword_64(i->seg(), eaddr);
/* sign extend word op2 into qword op1 */
BX_WRITE_64BIT_REG(i->nnn(), (Bit32s) op2_32);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOVSX_GqEdR(bxInstruction_c *i)
{
Bit32u op2_32 = BX_READ_32BIT_REG(i->rm());
/* sign extend word op2 into qword op1 */
BX_WRITE_64BIT_REG(i->nnn(), (Bit32s) op2_32);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::XCHG_EqGqM(bxInstruction_c *i)
{
Bit64u op2_64, op1_64;
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
op1_64 = read_RMW_virtual_qword_64(i->seg(), eaddr);
op2_64 = BX_READ_64BIT_REG(i->nnn());
write_RMW_virtual_qword(op2_64);
BX_WRITE_64BIT_REG(i->nnn(), op1_64);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::XCHG_EqGqR(bxInstruction_c *i)
{
Bit64u op1_64 = BX_READ_64BIT_REG(i->rm());
Bit64u op2_64 = BX_READ_64BIT_REG(i->nnn());
BX_WRITE_64BIT_REG(i->nnn(), op1_64);
BX_WRITE_64BIT_REG(i->rm(), op2_64);
}
// Note: CMOV accesses a memory source operand (read), regardless
// of whether condition is true or not. Thus, exceptions may
// occur even if the MOV does not take place.
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMOVO_GqEqR(bxInstruction_c *i)
{
if (get_OF())
BX_WRITE_64BIT_REG(i->nnn(), BX_READ_64BIT_REG(i->rm()));
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMOVNO_GqEqR(bxInstruction_c *i)
{
if (!get_OF())
BX_WRITE_64BIT_REG(i->nnn(), BX_READ_64BIT_REG(i->rm()));
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMOVB_GqEqR(bxInstruction_c *i)
{
if (get_CF())
BX_WRITE_64BIT_REG(i->nnn(), BX_READ_64BIT_REG(i->rm()));
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMOVNB_GqEqR(bxInstruction_c *i)
{
if (!get_CF())
BX_WRITE_64BIT_REG(i->nnn(), BX_READ_64BIT_REG(i->rm()));
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMOVZ_GqEqR(bxInstruction_c *i)
{
if (get_ZF())
BX_WRITE_64BIT_REG(i->nnn(), BX_READ_64BIT_REG(i->rm()));
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMOVNZ_GqEqR(bxInstruction_c *i)
{
if (!get_ZF())
BX_WRITE_64BIT_REG(i->nnn(), BX_READ_64BIT_REG(i->rm()));
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMOVBE_GqEqR(bxInstruction_c *i)
{
if (get_CF() || get_ZF())
BX_WRITE_64BIT_REG(i->nnn(), BX_READ_64BIT_REG(i->rm()));
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMOVNBE_GqEqR(bxInstruction_c *i)
{
if (! (get_CF() || get_ZF()))
BX_WRITE_64BIT_REG(i->nnn(), BX_READ_64BIT_REG(i->rm()));
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMOVS_GqEqR(bxInstruction_c *i)
{
if (get_SF())
BX_WRITE_64BIT_REG(i->nnn(), BX_READ_64BIT_REG(i->rm()));
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMOVNS_GqEqR(bxInstruction_c *i)
{
if (!get_SF())
BX_WRITE_64BIT_REG(i->nnn(), BX_READ_64BIT_REG(i->rm()));
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMOVP_GqEqR(bxInstruction_c *i)
{
if (get_PF())
BX_WRITE_64BIT_REG(i->nnn(), BX_READ_64BIT_REG(i->rm()));
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMOVNP_GqEqR(bxInstruction_c *i)
{
if (!get_PF())
BX_WRITE_64BIT_REG(i->nnn(), BX_READ_64BIT_REG(i->rm()));
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMOVL_GqEqR(bxInstruction_c *i)
{
if (getB_SF() != getB_OF())
BX_WRITE_64BIT_REG(i->nnn(), BX_READ_64BIT_REG(i->rm()));
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMOVNL_GqEqR(bxInstruction_c *i)
{
if (getB_SF() == getB_OF())
BX_WRITE_64BIT_REG(i->nnn(), BX_READ_64BIT_REG(i->rm()));
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMOVLE_GqEqR(bxInstruction_c *i)
{
if (get_ZF() || (getB_SF() != getB_OF()))
BX_WRITE_64BIT_REG(i->nnn(), BX_READ_64BIT_REG(i->rm()));
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMOVNLE_GqEqR(bxInstruction_c *i)
{
if (! get_ZF() && (getB_SF() == getB_OF()))
BX_WRITE_64BIT_REG(i->nnn(), BX_READ_64BIT_REG(i->rm()));
}
#endif /* if BX_SUPPORT_X86_64 */

View File

@ -0,0 +1,112 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2001-2009 The Bochs Project
//
// 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
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA B 02110-1301 USA
/////////////////////////////////////////////////////////////////////////
#define NEED_CPU_REG_SHORTCUTS 1
#include "bochs.h"
#include "cpu.h"
#define LOG_THIS BX_CPU_THIS_PTR
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOV_RLIb(bxInstruction_c *i)
{
BX_WRITE_8BIT_REGx(i->rm(), i->extend8bitL(), i->Ib());
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOV_RHIb(bxInstruction_c *i)
{
BX_WRITE_8BIT_REGH(i->rm() & 0x03, i->Ib());
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOV_EbGbM(bxInstruction_c *i)
{
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
write_virtual_byte(i->seg(), eaddr, BX_READ_8BIT_REGx(i->nnn(), i->extend8bitL()));
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOV_GbEbM(bxInstruction_c *i)
{
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
Bit8u val8 = read_virtual_byte(i->seg(), eaddr);
BX_WRITE_8BIT_REGx(i->nnn(), i->extend8bitL(), val8);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOV_GbEbR(bxInstruction_c *i)
{
Bit8u op2 = BX_READ_8BIT_REGx(i->rm(), i->extend8bitL());
BX_WRITE_8BIT_REGx(i->nnn(), i->extend8bitL(), op2);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOV_ALOd(bxInstruction_c *i)
{
AL = read_virtual_byte_32(i->seg(), i->Id());
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOV_OdAL(bxInstruction_c *i)
{
write_virtual_byte_32(i->seg(), i->Id(), AL);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOV_EbIbM(bxInstruction_c *i)
{
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
write_virtual_byte(i->seg(), eaddr, i->Ib());
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::XLAT(bxInstruction_c *i)
{
#if BX_SUPPORT_X86_64
if (i->as64L()) {
AL = read_virtual_byte_64(i->seg(), RBX + AL);
}
else
#endif
if (i->as32L()) {
AL = read_virtual_byte(i->seg(), (Bit32u) (EBX + AL));
}
else {
AL = read_virtual_byte_32(i->seg(), (Bit16u) (BX + AL));
}
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::XCHG_EbGbM(bxInstruction_c *i)
{
Bit8u op1, op2;
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
/* pointer, segment address pair */
op1 = read_RMW_virtual_byte(i->seg(), eaddr);
op2 = BX_READ_8BIT_REGx(i->nnn(), i->extend8bitL());
write_RMW_virtual_byte(op2);
BX_WRITE_8BIT_REGx(i->nnn(), i->extend8bitL(), op1);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::XCHG_EbGbR(bxInstruction_c *i)
{
Bit8u op1 = BX_READ_8BIT_REGx(i->rm(), i->extend8bitL());
Bit8u op2 = BX_READ_8BIT_REGx(i->nnn(), i->extend8bitL());
BX_WRITE_8BIT_REGx(i->nnn(), i->extend8bitL(), op1);
BX_WRITE_8BIT_REGx(i->rm(), i->extend8bitL(), op2);
}

View File

@ -0,0 +1,392 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2001-2009 The Bochs Project
//
// 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
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA B 02110-1301 USA
//
/////////////////////////////////////////////////////////////////////////
#define NEED_CPU_REG_SHORTCUTS 1
#include "bochs.h"
#include "cpu.h"
#define LOG_THIS BX_CPU_THIS_PTR
#if BX_DISASM
#include "disasm/disasm.h"
void BX_CPU_C::debug_disasm_instruction(bx_address offset)
{
#if BX_DEBUGGER
bx_dbg_disassemble_current(BX_CPU_ID, 1); // only one cpu, print time stamp
#else
bx_phy_address phy_addr;
Bit8u instr_buf[16];
char char_buf[512];
size_t i=0;
static char letters[] = "0123456789ABCDEF";
static disassembler bx_disassemble;
unsigned remainsInPage = 0x1000 - PAGE_OFFSET(offset);
bx_bool valid = dbg_xlate_linear2phy(BX_CPU_THIS_PTR get_laddr(BX_SEG_REG_CS, offset), &phy_addr);
if (valid) {
BX_MEM(0)->dbg_fetch_mem(BX_CPU_THIS, phy_addr, 16, instr_buf);
unsigned isize = bx_disassemble.disasm(
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.d_b,
BX_CPU_THIS_PTR cpu_mode == BX_MODE_LONG_64,
BX_CPU_THIS_PTR get_segment_base(BX_SEG_REG_CS), offset,
instr_buf, char_buf+i);
if (isize <= remainsInPage) {
i=strlen(char_buf);
char_buf[i++] = ' ';
char_buf[i++] = ':';
char_buf[i++] = ' ';
for (unsigned j=0; j<isize; j++) {
char_buf[i++] = letters[(instr_buf[j] >> 4) & 0xf];
char_buf[i++] = letters[(instr_buf[j] >> 0) & 0xf];
}
char_buf[i] = 0;
BX_INFO(("0x" FMT_ADDRX ">> %s", offset, char_buf));
}
else {
BX_INFO(("0x" FMT_ADDRX ": (instruction unavailable) page split instruction", offset));
}
}
else {
BX_INFO(("0x" FMT_ADDRX ": (instruction unavailable) page not present", offset));
}
#endif // #if BX_DEBUGGER
}
#endif // #if BX_DISASM
const char* cpu_mode_string(unsigned cpu_mode)
{
static const char *cpu_mode_name[] = {
"real mode",
"v8086 mode",
"protected mode",
"compatibility mode",
"long mode",
"unknown mode"
};
if(cpu_mode >= 5) cpu_mode = 5;
return cpu_mode_name[cpu_mode];
}
const char* cpu_state_string(unsigned state)
{
static const char *cpu_state_name[] = {
"active",
"halted",
"in shutdown",
"waiting for SIPI",
"executing mwait",
"executing mwait inhibit interrups",
"unknown state"
};
if(state >= 6) state = 6;
return cpu_state_name[state];
}
void BX_CPU_C::debug(bx_address offset)
{
BX_INFO(("CPU is in %s (%s)", cpu_mode_string(BX_CPU_THIS_PTR get_cpu_mode()),
cpu_state_string(BX_CPU_THIS_PTR activity_state)));
BX_INFO(("CS.d_b = %u bit",
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.d_b ? 32 : 16));
BX_INFO(("SS.d_b = %u bit",
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.d_b ? 32 : 16));
#if BX_SUPPORT_X86_64
BX_INFO(("EFER = 0x%08x", BX_CPU_THIS_PTR efer.get32()));
BX_INFO(("| RAX=%08x%08x RBX=%08x%08x",
(unsigned) (RAX >> 32), (unsigned) EAX,
(unsigned) (RBX >> 32), (unsigned) EBX));
BX_INFO(("| RCX=%08x%08x RDX=%08x%08x",
(unsigned) (RCX >> 32), (unsigned) ECX,
(unsigned) (RDX >> 32), (unsigned) EDX));
BX_INFO(("| RSP=%08x%08x RBP=%08x%08x",
(unsigned) (RSP >> 32), (unsigned) ESP,
(unsigned) (RBP >> 32), (unsigned) EBP));
BX_INFO(("| RSI=%08x%08x RDI=%08x%08x",
(unsigned) (RSI >> 32), (unsigned) ESI,
(unsigned) (RDI >> 32), (unsigned) EDI));
BX_INFO(("| R8=%08x%08x R9=%08x%08x",
(unsigned) (R8 >> 32), (unsigned) (R8 & 0xFFFFFFFF),
(unsigned) (R9 >> 32), (unsigned) (R9 & 0xFFFFFFFF)));
BX_INFO(("| R10=%08x%08x R11=%08x%08x",
(unsigned) (R10 >> 32), (unsigned) (R10 & 0xFFFFFFFF),
(unsigned) (R11 >> 32), (unsigned) (R11 & 0xFFFFFFFF)));
BX_INFO(("| R12=%08x%08x R13=%08x%08x",
(unsigned) (R12 >> 32), (unsigned) (R12 & 0xFFFFFFFF),
(unsigned) (R13 >> 32), (unsigned) (R13 & 0xFFFFFFFF)));
BX_INFO(("| R14=%08x%08x R15=%08x%08x",
(unsigned) (R14 >> 32), (unsigned) (R14 & 0xFFFFFFFF),
(unsigned) (R15 >> 32), (unsigned) (R15 & 0xFFFFFFFF)));
#else
BX_INFO(("| EAX=%08x EBX=%08x ECX=%08x EDX=%08x",
(unsigned) EAX, (unsigned) EBX, (unsigned) ECX, (unsigned) EDX));
BX_INFO(("| ESP=%08x EBP=%08x ESI=%08x EDI=%08x",
(unsigned) ESP, (unsigned) EBP, (unsigned) ESI, (unsigned) EDI));
#endif
BX_INFO(("| IOPL=%1u %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s",
BX_CPU_THIS_PTR get_IOPL(),
BX_CPU_THIS_PTR get_ID() ? "ID" : "id",
BX_CPU_THIS_PTR get_VIP() ? "VIP" : "vip",
BX_CPU_THIS_PTR get_VIF() ? "VIF" : "vif",
BX_CPU_THIS_PTR get_AC() ? "AC" : "ac",
BX_CPU_THIS_PTR get_VM() ? "VM" : "vm",
BX_CPU_THIS_PTR get_RF() ? "RF" : "rf",
BX_CPU_THIS_PTR get_NT() ? "NT" : "nt",
BX_CPU_THIS_PTR get_OF() ? "OF" : "of",
BX_CPU_THIS_PTR get_DF() ? "DF" : "df",
BX_CPU_THIS_PTR get_IF() ? "IF" : "if",
BX_CPU_THIS_PTR get_TF() ? "TF" : "tf",
BX_CPU_THIS_PTR get_SF() ? "SF" : "sf",
BX_CPU_THIS_PTR get_ZF() ? "ZF" : "zf",
BX_CPU_THIS_PTR get_AF() ? "AF" : "af",
BX_CPU_THIS_PTR get_PF() ? "PF" : "pf",
BX_CPU_THIS_PTR get_CF() ? "CF" : "cf"));
BX_INFO(("| SEG selector base limit G D"));
BX_INFO(("| SEG sltr(index|ti|rpl) base limit G D"));
BX_INFO(("| CS:%04x( %04x| %01u| %1u) %08x %08x %1u %1u",
(unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value,
(unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.index,
(unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.ti,
(unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.rpl,
(unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.base,
(unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.limit_scaled,
(unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.g,
(unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.d_b));
BX_INFO(("| DS:%04x( %04x| %01u| %1u) %08x %08x %1u %1u",
(unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS].selector.value,
(unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS].selector.index,
(unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS].selector.ti,
(unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS].selector.rpl,
(unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS].cache.u.segment.base,
(unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS].cache.u.segment.limit_scaled,
(unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS].cache.u.segment.g,
(unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS].cache.u.segment.d_b));
BX_INFO(("| SS:%04x( %04x| %01u| %1u) %08x %08x %1u %1u",
(unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].selector.value,
(unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].selector.index,
(unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].selector.ti,
(unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].selector.rpl,
(unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.base,
(unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.limit_scaled,
(unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.g,
(unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.d_b));
BX_INFO(("| ES:%04x( %04x| %01u| %1u) %08x %08x %1u %1u",
(unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_ES].selector.value,
(unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_ES].selector.index,
(unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_ES].selector.ti,
(unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_ES].selector.rpl,
(unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_ES].cache.u.segment.base,
(unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_ES].cache.u.segment.limit_scaled,
(unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_ES].cache.u.segment.g,
(unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_ES].cache.u.segment.d_b));
BX_INFO(("| FS:%04x( %04x| %01u| %1u) %08x %08x %1u %1u",
(unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_FS].selector.value,
(unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_FS].selector.index,
(unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_FS].selector.ti,
(unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_FS].selector.rpl,
(unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_FS].cache.u.segment.base,
(unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_FS].cache.u.segment.limit_scaled,
(unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_FS].cache.u.segment.g,
(unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_FS].cache.u.segment.d_b));
BX_INFO(("| GS:%04x( %04x| %01u| %1u) %08x %08x %1u %1u",
(unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_GS].selector.value,
(unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_GS].selector.index,
(unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_GS].selector.ti,
(unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_GS].selector.rpl,
(unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_GS].cache.u.segment.base,
(unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_GS].cache.u.segment.limit_scaled,
(unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_GS].cache.u.segment.g,
(unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_GS].cache.u.segment.d_b));
#if BX_SUPPORT_X86_64
BX_INFO(("| MSR_FS_BASE:%08x%08x",
(unsigned) (MSR_FSBASE >> 32), (unsigned) (MSR_FSBASE & 0xFFFFFFFF)));
BX_INFO(("| MSR_GS_BASE:%08x%08x",
(unsigned) (MSR_GSBASE >> 32), (unsigned) (MSR_GSBASE & 0xFFFFFFFF)));
#endif
#if BX_SUPPORT_X86_64
BX_INFO(("| RIP=%08x%08x (%08x%08x)",
(unsigned) (BX_CPU_THIS_PTR gen_reg[BX_64BIT_REG_RIP].dword.hrx),
(unsigned) (EIP),
(unsigned) (BX_CPU_THIS_PTR prev_rip >> 32),
(unsigned) (BX_CPU_THIS_PTR prev_rip & 0xffffffff)));
BX_INFO(("| CR0=0x%08x CR2=0x%08x%08x",
(unsigned) (BX_CPU_THIS_PTR cr0.get32()),
(unsigned) (BX_CPU_THIS_PTR cr2 >> 32),
(unsigned) (BX_CPU_THIS_PTR cr2 & 0xffffffff)));
BX_INFO(("| CR3=0x%08x CR4=0x%08x",
(unsigned) BX_CPU_THIS_PTR cr3, BX_CPU_THIS_PTR cr4.get32()));
#else
BX_INFO(("| EIP=%08x (%08x)", (unsigned) EIP,
(unsigned) BX_CPU_THIS_PTR prev_rip));
#if BX_CPU_LEVEL >= 2 && BX_CPU_LEVEL < 4
BX_INFO(("| CR0=0x%08x CR2=0x%08x CR3=0x%08x",
BX_CPU_THIS_PTR cr0.get32(),
BX_CPU_THIS_PTR cr2,
BX_CPU_THIS_PTR cr3));
#elif BX_CPU_LEVEL >= 4
BX_INFO(("| CR0=0x%08x CR2=0x%08x",
BX_CPU_THIS_PTR cr0.get32(),
BX_CPU_THIS_PTR cr2));
BX_INFO(("| CR3=0x%08x CR4=0x%08x",
BX_CPU_THIS_PTR cr3,
BX_CPU_THIS_PTR cr4.get32()));
#endif
#endif // BX_SUPPORT_X86_64
#if BX_DISASM
debug_disasm_instruction(offset);
#endif // #if BX_DISASM
}
#if BX_DEBUGGER
bx_bool BX_CPU_C::dbg_set_reg(unsigned reg, Bit32u val)
{
// returns 1=OK, 0=can't change
Bit32u current_sys_bits;
switch (reg) {
case BX_DBG_REG_EIP:
EIP = val;
invalidate_prefetch_q();
return(1);
case BX_DBG_REG_EFLAGS:
if (val & 0xffff0000) {
BX_INFO(("dbg_set_reg: can not set upper 16 bits of eflags."));
return(0);
}
// make sure none of the system bits are being changed
current_sys_bits = ((BX_CPU_THIS_PTR getB_NT()) << 14) |
(BX_CPU_THIS_PTR get_IOPL () << 12) |
((BX_CPU_THIS_PTR getB_TF()) << 8);
if (current_sys_bits != (val & 0x0000f100)) {
BX_INFO(("dbg_set_reg: can not modify NT, IOPL, or TF."));
return(0);
}
BX_CPU_THIS_PTR set_CF(val & 0x01); val >>= 2;
BX_CPU_THIS_PTR set_PF(val & 0x01); val >>= 2;
BX_CPU_THIS_PTR set_AF(val & 0x01); val >>= 2;
BX_CPU_THIS_PTR set_ZF(val & 0x01); val >>= 1;
BX_CPU_THIS_PTR set_SF(val & 0x01); val >>= 2;
BX_CPU_THIS_PTR set_IF(val & 0x01); val >>= 1;
BX_CPU_THIS_PTR set_DF(val & 0x01); val >>= 1;
BX_CPU_THIS_PTR set_OF(val & 0x01);
return(1);
}
return(0);
}
unsigned BX_CPU_C::dbg_query_pending(void)
{
unsigned ret = 0;
if (BX_HRQ) { // DMA Hold Request
ret |= BX_DBG_PENDING_DMA;
}
if (BX_CPU_THIS_PTR INTR && BX_CPU_THIS_PTR get_IF()) {
ret |= BX_DBG_PENDING_IRQ;
}
return(ret);
}
bx_bool BX_CPU_C::dbg_get_sreg(bx_dbg_sreg_t *sreg, unsigned sreg_no)
{
if (sreg_no > 5)
return(0);
sreg->valid = BX_CPU_THIS_PTR sregs[sreg_no].cache.valid;
sreg->sel = BX_CPU_THIS_PTR sregs[sreg_no].selector.value;
sreg->des_l = get_descriptor_l(&BX_CPU_THIS_PTR sregs[sreg_no].cache);
sreg->des_h = get_descriptor_h(&BX_CPU_THIS_PTR sregs[sreg_no].cache);
#if BX_SUPPORT_X86_64
sreg->dword3 = BX_CPU_THIS_PTR sregs[sreg_no].cache.u.segment.base >> 32;
#endif
return(1);
}
bx_bool BX_CPU_C::dbg_set_sreg(unsigned sreg_no, bx_segment_reg_t *sreg)
{
if (sreg_no < 6) {
BX_CPU_THIS_PTR sregs[sreg_no] = *sreg;
if (sreg_no == BX_SEG_REG_CS) {
handleCpuModeChange();
#if BX_CPU_LEVEL >= 4 && BX_SUPPORT_ALIGNMENT_CHECK
handleAlignmentCheck(/* CPL change */);
#endif
invalidate_prefetch_q();
return 1;
}
}
return 0;
}
void BX_CPU_C::dbg_get_tr(bx_dbg_sreg_t *sreg)
{
sreg->valid = BX_CPU_THIS_PTR tr.cache.valid;
sreg->sel = BX_CPU_THIS_PTR tr.selector.value;
sreg->des_l = get_descriptor_l(&BX_CPU_THIS_PTR tr.cache);
sreg->des_h = get_descriptor_h(&BX_CPU_THIS_PTR tr.cache);
#if BX_SUPPORT_X86_64
sreg->dword3 = BX_CPU_THIS_PTR tr.cache.u.segment.base >> 32;
#endif
}
void BX_CPU_C::dbg_get_ldtr(bx_dbg_sreg_t *sreg)
{
sreg->valid = BX_CPU_THIS_PTR ldtr.cache.valid;
sreg->sel = BX_CPU_THIS_PTR ldtr.selector.value;
sreg->des_l = get_descriptor_l(&BX_CPU_THIS_PTR ldtr.cache);
sreg->des_h = get_descriptor_h(&BX_CPU_THIS_PTR ldtr.cache);
#if BX_SUPPORT_X86_64
sreg->dword3 = BX_CPU_THIS_PTR ldtr.cache.u.segment.base >> 32;
#endif
}
void BX_CPU_C::dbg_get_gdtr(bx_dbg_global_sreg_t *sreg)
{
sreg->base = BX_CPU_THIS_PTR gdtr.base;
sreg->limit = BX_CPU_THIS_PTR gdtr.limit;
}
void BX_CPU_C::dbg_get_idtr(bx_dbg_global_sreg_t *sreg)
{
sreg->base = BX_CPU_THIS_PTR idtr.base;
sreg->limit = BX_CPU_THIS_PTR idtr.limit;
}
#endif // #if BX_DEBUGGER
void BX_CPU_C::atexit(void)
{
debug(BX_CPU_THIS_PTR prev_rip);
}

192
simulators/bochs/cpu/descriptor.h Executable file
View File

@ -0,0 +1,192 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2007-2009 Stanislav Shwartsman
// 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
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA B 02110-1301 USA
/////////////////////////////////////////////////////////////////////////
#ifndef BX_DESCRIPTOR_H
#define BX_DESCRIPTOR_H
//
// |---------------------------------------------|
// | Segment Descriptor |
// |---------------------------------------------|
// |33222222|2|2|2|2| 11 11 |1|11|1|11 | |
// |10987654|3|2|1|0| 98 76 |5|43|2|1098|76543210|
// |--------|-|-|-|-|-------|-|--|-|----|--------|
// |Base |G|D|L|A|Limit |P|D |S|Type|Base |
// |[31-24] | |/| |V|[19-16]| |P | | |[23-16] |
// | | |B| |L| | |L | | | |
// |------------------------|--------------------|
// | Base [15-0] | Limit [15-0] |
// |------------------------|--------------------|
//
typedef struct { /* bx_selector_t */
Bit16u value; /* the 16bit value of the selector */
/* the following fields are extracted from the value field in protected
mode only. They're used for sake of efficiency */
Bit16u index; /* 13bit index extracted from value in protected mode */
Bit8u ti; /* table indicator bit extracted from value */
Bit8u rpl; /* RPL extracted from value */
} bx_selector_t;
#define BX_SELECTOR_RPL(selector) ((selector) & 0x03)
#define BX_SELECTOR_RPL_MASK (0xfffc)
typedef struct
{
// do not go above 4 bits !
#define SegValidCache (0x01)
#define SegAccessROK (0x02)
#define SegAccessWOK (0x04)
unsigned valid; // Holds above values, Or'd together. Used to
// hold only 0 or 1.
bx_bool p; /* present */
Bit8u dpl; /* descriptor privilege level 0..3 */
bx_bool segment; /* 0 = system/gate, 1 = data/code segment */
Bit8u type; /* For system & gate descriptors:
* 0 = invalid descriptor (reserved)
* 1 = 286 available Task State Segment (TSS)
* 2 = LDT descriptor
* 3 = 286 busy Task State Segment (TSS)
* 4 = 286 call gate
* 5 = task gate
* 6 = 286 interrupt gate
* 7 = 286 trap gate
* 8 = (reserved)
* 9 = 386 available TSS
* 10 = (reserved)
* 11 = 386 busy TSS
* 12 = 386 call gate
* 13 = (reserved)
* 14 = 386 interrupt gate
* 15 = 386 trap gate */
// For system & gate descriptors:
#define BX_GATE_TYPE_NONE (0x0)
#define BX_SYS_SEGMENT_AVAIL_286_TSS (0x1)
#define BX_SYS_SEGMENT_LDT (0x2)
#define BX_SYS_SEGMENT_BUSY_286_TSS (0x3)
#define BX_286_CALL_GATE (0x4)
#define BX_TASK_GATE (0x5)
#define BX_286_INTERRUPT_GATE (0x6)
#define BX_286_TRAP_GATE (0x7)
/* 0x8 reserved */
#define BX_SYS_SEGMENT_AVAIL_386_TSS (0x9)
/* 0xa reserved */
#define BX_SYS_SEGMENT_BUSY_386_TSS (0xb)
#define BX_386_CALL_GATE (0xc)
/* 0xd reserved */
#define BX_386_INTERRUPT_GATE (0xe)
#define BX_386_TRAP_GATE (0xf)
// For data/code descriptors:
#define BX_DATA_READ_ONLY (0x0)
#define BX_DATA_READ_ONLY_ACCESSED (0x1)
#define BX_DATA_READ_WRITE (0x2)
#define BX_DATA_READ_WRITE_ACCESSED (0x3)
#define BX_DATA_READ_ONLY_EXPAND_DOWN (0x4)
#define BX_DATA_READ_ONLY_EXPAND_DOWN_ACCESSED (0x5)
#define BX_DATA_READ_WRITE_EXPAND_DOWN (0x6)
#define BX_DATA_READ_WRITE_EXPAND_DOWN_ACCESSED (0x7)
#define BX_CODE_EXEC_ONLY (0x8)
#define BX_CODE_EXEC_ONLY_ACCESSED (0x9)
#define BX_CODE_EXEC_READ (0xa)
#define BX_CODE_EXEC_READ_ACCESSED (0xb)
#define BX_CODE_EXEC_ONLY_CONFORMING (0xc)
#define BX_CODE_EXEC_ONLY_CONFORMING_ACCESSED (0xd)
#define BX_CODE_EXEC_READ_CONFORMING (0xe)
#define BX_CODE_EXEC_READ_CONFORMING_ACCESSED (0xf)
union {
struct {
bx_address base; /* base address: 286=24bits, 386=32bits, long=64 */
Bit32u limit_scaled; /* for efficiency, this contrived field is set to
* limit for byte granular, and
* (limit << 12) | 0xfff for page granular seg's
*/
bx_bool g; /* granularity: 0=byte, 1=4K (page) */
bx_bool d_b; /* default size: 0=16bit, 1=32bit */
#if BX_SUPPORT_X86_64
bx_bool l; /* long mode: 0=compat, 1=64 bit */
#endif
bx_bool avl; /* available for use by system */
} segment;
struct {
Bit8u param_count; /* 5bits (0..31) #words/dword to copy from caller's
* stack to called procedure's stack. */
Bit16u dest_selector;
Bit32u dest_offset;
} gate;
struct { /* type 5: Task Gate Descriptor */
Bit16u tss_selector; /* TSS segment selector */
} taskgate;
} u;
} bx_descriptor_t;
#define IS_PRESENT(descriptor) (descriptor.p)
#if BX_SUPPORT_X86_64
#define IS_LONG64_SEGMENT(descriptor) (descriptor.u.segment.l)
#else
#define IS_LONG64_SEGMENT(descriptor) (0)
#endif
#define IS_CODE_SEGMENT(type) (((type) >> 3) & 0x1)
#define IS_CODE_SEGMENT_CONFORMING(type) (((type) >> 2) & 0x1)
#define IS_DATA_SEGMENT_EXPAND_DOWN(type) (((type) >> 2) & 0x1)
#define IS_CODE_SEGMENT_READABLE(type) (((type) >> 1) & 0x1)
#define IS_DATA_SEGMENT_WRITEABLE(type) (((type) >> 1) & 0x1)
#define IS_SEGMENT_ACCESSED(type) ((type) & 0x1)
#define BX_SEGMENT_CODE (0x8)
#define BX_SEGMENT_DATA_EXPAND_DOWN (0x4)
#define BX_SEGMENT_CODE_CONFORMING (0x4)
#define BX_SEGMENT_DATA_WRITE (0x2)
#define BX_SEGMENT_CODE_READ (0x2)
#define BX_SEGMENT_ACCESSED (0x1)
#define IS_DATA_SEGMENT(type) (! IS_CODE_SEGMENT(type))
#define IS_CODE_SEGMENT_NON_CONFORMING(type) \
(! IS_CODE_SEGMENT_CONFORMING(type))
typedef struct {
bx_selector_t selector;
bx_descriptor_t cache;
} bx_segment_reg_t;
typedef struct {
bx_address base; /* base address: 24bits=286,32bits=386,64bits=x86-64 */
Bit16u limit; /* limit, 16bits */
} bx_global_segment_reg_t;
void parse_selector(Bit16u raw_selector, bx_selector_t *selector);
Bit8u get_ar_byte(const bx_descriptor_t *d);
void set_ar_byte(bx_descriptor_t *d, Bit8u ar_byte);
void parse_descriptor(Bit32u dword1, Bit32u dword2, bx_descriptor_t *temp);
#endif

View File

@ -0,0 +1,941 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2001-2010 The Bochs Project
//
// 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
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA B 02110-1301 USA
//
/////////////////////////////////////////////////////////////////////////
#define NEED_CPU_REG_SHORTCUTS 1
#include "bochs.h"
#include "cpu.h"
#define LOG_THIS BX_CPU_THIS_PTR
#include "param_names.h"
#include "iodev/iodev.h"
#if BX_SUPPORT_X86_64==0
// Make life easier merging cpu64 & cpu code.
#define RIP EIP
#define RSP ESP
#endif
#if BX_SUPPORT_X86_64
void BX_CPU_C::long_mode_int(Bit8u vector, unsigned soft_int, bx_bool push_error, Bit16u error_code)
{
bx_descriptor_t gate_descriptor, cs_descriptor;
bx_selector_t cs_selector;
// interrupt vector must be within IDT table limits,
// else #GP(vector*8 + 2 + EXT)
if ((vector*16 + 15) > BX_CPU_THIS_PTR idtr.limit) {
BX_ERROR(("interrupt(long mode): vector must be within IDT table limits, IDT.limit = 0x%x", BX_CPU_THIS_PTR idtr.limit));
exception(BX_GP_EXCEPTION, vector*8 + 2);
}
Bit64u desctmp1 = system_read_qword(BX_CPU_THIS_PTR idtr.base + vector*16);
Bit64u desctmp2 = system_read_qword(BX_CPU_THIS_PTR idtr.base + vector*16 + 8);
if (desctmp2 & BX_CONST64(0x00001F0000000000)) {
BX_ERROR(("interrupt(long mode): IDT entry extended attributes DWORD4 TYPE != 0"));
exception(BX_GP_EXCEPTION, vector*8 + 2);
}
Bit32u dword1 = GET32L(desctmp1);
Bit32u dword2 = GET32H(desctmp1);
Bit32u dword3 = GET32L(desctmp2);
parse_descriptor(dword1, dword2, &gate_descriptor);
if ((gate_descriptor.valid==0) || gate_descriptor.segment)
{
BX_ERROR(("interrupt(long mode): gate descriptor is not valid sys seg"));
exception(BX_GP_EXCEPTION, vector*8 + 2);
}
// descriptor AR byte must indicate interrupt gate, trap gate,
// or task gate, else #GP(vector*8 + 2 + EXT)
if (gate_descriptor.type != BX_386_INTERRUPT_GATE &&
gate_descriptor.type != BX_386_TRAP_GATE)
{
BX_ERROR(("interrupt(long mode): unsupported gate type %u",
(unsigned) gate_descriptor.type));
exception(BX_GP_EXCEPTION, vector*8 + 2);
}
// if software interrupt, then gate descripor DPL must be >= CPL,
// else #GP(vector * 8 + 2 + EXT)
if (soft_int && gate_descriptor.dpl < CPL)
{
BX_ERROR(("interrupt(long mode): soft_int && gate.dpl < CPL"));
exception(BX_GP_EXCEPTION, vector*8 + 2);
}
// Gate must be present, else #NP(vector * 8 + 2 + EXT)
if (! IS_PRESENT(gate_descriptor)) {
BX_ERROR(("interrupt(long mode): gate.p == 0"));
exception(BX_NP_EXCEPTION, vector*8 + 2);
}
Bit16u gate_dest_selector = gate_descriptor.u.gate.dest_selector;
Bit64u gate_dest_offset = ((Bit64u)dword3 << 32) |
gate_descriptor.u.gate.dest_offset;
unsigned ist = gate_descriptor.u.gate.param_count & 0x7;
// examine CS selector and descriptor given in gate descriptor
// selector must be non-null else #GP(EXT)
if ((gate_dest_selector & 0xfffc) == 0) {
BX_ERROR(("int_trap_gate(long mode): selector null"));
exception(BX_GP_EXCEPTION, 0);
}
parse_selector(gate_dest_selector, &cs_selector);
// selector must be within its descriptor table limits
// else #GP(selector+EXT)
fetch_raw_descriptor(&cs_selector, &dword1, &dword2, BX_GP_EXCEPTION);
parse_descriptor(dword1, dword2, &cs_descriptor);
// descriptor AR byte must indicate code seg
// and code segment descriptor DPL<=CPL, else #GP(selector+EXT)
if (cs_descriptor.valid==0 || cs_descriptor.segment==0 ||
IS_DATA_SEGMENT(cs_descriptor.type) ||
cs_descriptor.dpl > CPL)
{
BX_ERROR(("interrupt(long mode): not accessible or not code segment"));
exception(BX_GP_EXCEPTION, cs_selector.value & 0xfffc);
}
// check that it's a 64 bit segment
if (! IS_LONG64_SEGMENT(cs_descriptor) || cs_descriptor.u.segment.d_b)
{
BX_ERROR(("interrupt(long mode): must be 64 bit segment"));
exception(BX_GP_EXCEPTION, cs_selector.value & 0xfffc);
}
// segment must be present, else #NP(selector + EXT)
if (! IS_PRESENT(cs_descriptor)) {
BX_ERROR(("interrupt(long mode): segment not present"));
exception(BX_NP_EXCEPTION, cs_selector.value & 0xfffc);
}
Bit64u RSP_for_cpl_x;
Bit64u old_CS = BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value;
Bit64u old_RIP = RIP;
Bit64u old_SS = BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].selector.value;
Bit64u old_RSP = RSP;
// if code segment is non-conforming and DPL < CPL then
// INTERRUPT TO INNER PRIVILEGE:
if (IS_CODE_SEGMENT_NON_CONFORMING(cs_descriptor.type) && cs_descriptor.dpl < CPL)
{
BX_DEBUG(("interrupt(long mode): INTERRUPT TO INNER PRIVILEGE"));
// check selector and descriptor for new stack in current TSS
if (ist > 0) {
BX_DEBUG(("interrupt(long mode): trap to IST, vector = %d", ist));
RSP_for_cpl_x = get_RSP_from_TSS(ist+3);
}
else {
RSP_for_cpl_x = get_RSP_from_TSS(cs_descriptor.dpl);
}
// align stack
RSP_for_cpl_x &= BX_CONST64(0xfffffffffffffff0);
// push old stack long pointer onto new stack
write_new_stack_qword_64(RSP_for_cpl_x - 8, cs_descriptor.dpl, old_SS);
write_new_stack_qword_64(RSP_for_cpl_x - 16, cs_descriptor.dpl, old_RSP);
write_new_stack_qword_64(RSP_for_cpl_x - 24, cs_descriptor.dpl, read_eflags());
// push long pointer to return address onto new stack
write_new_stack_qword_64(RSP_for_cpl_x - 32, cs_descriptor.dpl, old_CS);
write_new_stack_qword_64(RSP_for_cpl_x - 40, cs_descriptor.dpl, old_RIP);
RSP_for_cpl_x -= 40;
if (push_error) {
RSP_for_cpl_x -= 8;
write_new_stack_qword_64(RSP_for_cpl_x, cs_descriptor.dpl, error_code);
}
// load CS:RIP (guaranteed to be in 64 bit mode)
branch_far64(&cs_selector, &cs_descriptor, gate_dest_offset, cs_descriptor.dpl);
// set up null SS descriptor
load_null_selector(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS], cs_descriptor.dpl);
}
else if(IS_CODE_SEGMENT_CONFORMING(cs_descriptor.type) || cs_descriptor.dpl==CPL)
{
// if code segment is conforming OR code segment DPL = CPL then
// INTERRUPT TO SAME PRIVILEGE LEVEL:
BX_DEBUG(("interrupt(long mode): INTERRUPT TO SAME PRIVILEGE"));
// check selector and descriptor for new stack in current TSS
if (ist > 0) {
BX_DEBUG(("interrupt(long mode): trap to IST, vector = %d", ist));
RSP_for_cpl_x = get_RSP_from_TSS(ist+3);
}
else {
RSP_for_cpl_x = RSP;
}
// align stack
RSP_for_cpl_x &= BX_CONST64(0xfffffffffffffff0);
// push flags onto stack
// push current CS selector onto stack
// push return offset onto stack
write_new_stack_qword_64(RSP_for_cpl_x - 8, cs_descriptor.dpl, old_SS);
write_new_stack_qword_64(RSP_for_cpl_x - 16, cs_descriptor.dpl, old_RSP);
write_new_stack_qword_64(RSP_for_cpl_x - 24, cs_descriptor.dpl, read_eflags());
// push long pointer to return address onto new stack
write_new_stack_qword_64(RSP_for_cpl_x - 32, cs_descriptor.dpl, old_CS);
write_new_stack_qword_64(RSP_for_cpl_x - 40, cs_descriptor.dpl, old_RIP);
RSP_for_cpl_x -= 40;
if (push_error) {
RSP_for_cpl_x -= 8;
write_new_stack_qword_64(RSP_for_cpl_x, cs_descriptor.dpl, error_code);
}
// set the RPL field of CS to CPL
branch_far64(&cs_selector, &cs_descriptor, gate_dest_offset, CPL);
}
else {
BX_ERROR(("interrupt(long mode): bad descriptor type %u (CS.DPL=%u CPL=%u)",
(unsigned) cs_descriptor.type, (unsigned) cs_descriptor.dpl, (unsigned) CPL));
exception(BX_GP_EXCEPTION, cs_selector.value & 0xfffc);
}
RSP = RSP_for_cpl_x;
// if interrupt gate then set IF to 0
if (!(gate_descriptor.type & 1)) // even is int-gate
BX_CPU_THIS_PTR clear_IF();
BX_CPU_THIS_PTR clear_TF();
//BX_CPU_THIS_PTR clear_VM(); // VM is clear in long mode
BX_CPU_THIS_PTR clear_RF();
BX_CPU_THIS_PTR clear_NT();
}
#endif
void BX_CPU_C::protected_mode_int(Bit8u vector, unsigned soft_int, bx_bool push_error, Bit16u error_code)
{
bx_descriptor_t gate_descriptor, cs_descriptor;
bx_selector_t cs_selector;
Bit16u raw_tss_selector;
bx_selector_t tss_selector;
bx_descriptor_t tss_descriptor;
Bit16u gate_dest_selector;
Bit32u gate_dest_offset;
// interrupt vector must be within IDT table limits,
// else #GP(vector*8 + 2 + EXT)
if ((vector*8 + 7) > BX_CPU_THIS_PTR idtr.limit) {
BX_ERROR(("interrupt(): vector must be within IDT table limits, IDT.limit = 0x%x", BX_CPU_THIS_PTR idtr.limit));
exception(BX_GP_EXCEPTION, vector*8 + 2);
}
Bit64u desctmp = system_read_qword(BX_CPU_THIS_PTR idtr.base + vector*8);
Bit32u dword1 = GET32L(desctmp);
Bit32u dword2 = GET32H(desctmp);
parse_descriptor(dword1, dword2, &gate_descriptor);
if ((gate_descriptor.valid==0) || gate_descriptor.segment) {
BX_ERROR(("interrupt(): gate descriptor is not valid sys seg (vector=0x%02x)", vector));
exception(BX_GP_EXCEPTION, vector*8 + 2);
}
// descriptor AR byte must indicate interrupt gate, trap gate,
// or task gate, else #GP(vector*8 + 2 + EXT)
switch (gate_descriptor.type) {
case BX_TASK_GATE:
case BX_286_INTERRUPT_GATE:
case BX_286_TRAP_GATE:
case BX_386_INTERRUPT_GATE:
case BX_386_TRAP_GATE:
break;
default:
BX_ERROR(("interrupt(): gate.type(%u) != {5,6,7,14,15}",
(unsigned) gate_descriptor.type));
exception(BX_GP_EXCEPTION, vector*8 + 2);
}
// if software interrupt, then gate descripor DPL must be >= CPL,
// else #GP(vector * 8 + 2 + EXT)
if (soft_int && gate_descriptor.dpl < CPL) {
BX_ERROR(("interrupt(): soft_int && (gate.dpl < CPL)"));
exception(BX_GP_EXCEPTION, vector*8 + 2);
}
// Gate must be present, else #NP(vector * 8 + 2 + EXT)
if (! IS_PRESENT(gate_descriptor)) {
BX_ERROR(("interrupt(): gate not present"));
exception(BX_NP_EXCEPTION, vector*8 + 2);
}
switch (gate_descriptor.type) {
case BX_TASK_GATE:
// examine selector to TSS, given in task gate descriptor
raw_tss_selector = gate_descriptor.u.taskgate.tss_selector;
parse_selector(raw_tss_selector, &tss_selector);
// must specify global in the local/global bit,
// else #GP(TSS selector)
if (tss_selector.ti) {
BX_ERROR(("interrupt(): tss_selector.ti=1 from gate descriptor - #GP(tss_selector)"));
exception(BX_GP_EXCEPTION, raw_tss_selector & 0xfffc);
}
// index must be within GDT limits, else #TS(TSS selector)
fetch_raw_descriptor(&tss_selector, &dword1, &dword2, BX_GP_EXCEPTION);
parse_descriptor(dword1, dword2, &tss_descriptor);
// AR byte must specify available TSS,
// else #GP(TSS selector)
if (tss_descriptor.valid==0 || tss_descriptor.segment) {
BX_ERROR(("interrupt(): TSS selector points to invalid or bad TSS - #GP(tss_selector)"));
exception(BX_GP_EXCEPTION, raw_tss_selector & 0xfffc);
}
if (tss_descriptor.type!=BX_SYS_SEGMENT_AVAIL_286_TSS &&
tss_descriptor.type!=BX_SYS_SEGMENT_AVAIL_386_TSS)
{
BX_ERROR(("interrupt(): TSS selector points to bad TSS - #GP(tss_selector)"));
exception(BX_GP_EXCEPTION, raw_tss_selector & 0xfffc);
}
// TSS must be present, else #NP(TSS selector)
if (! IS_PRESENT(tss_descriptor)) {
BX_ERROR(("interrupt(): TSS descriptor.p == 0"));
exception(BX_NP_EXCEPTION, raw_tss_selector & 0xfffc);
}
// switch tasks with nesting to TSS
task_switch(0, &tss_selector, &tss_descriptor,
BX_TASK_FROM_INT, dword1, dword2);
RSP_SPECULATIVE;
// if interrupt was caused by fault with error code
// stack limits must allow push of 2 more bytes, else #SS(0)
// push error code onto stack
if (push_error) {
if (tss_descriptor.type >= 9) // TSS386
push_32(error_code);
else
push_16(error_code);
}
// instruction pointer must be in CS limit, else #GP(0)
if (EIP > BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.limit_scaled) {
BX_ERROR(("interrupt(): EIP > CS.limit"));
exception(BX_GP_EXCEPTION, 0);
}
RSP_COMMIT;
return;
case BX_286_INTERRUPT_GATE:
case BX_286_TRAP_GATE:
case BX_386_INTERRUPT_GATE:
case BX_386_TRAP_GATE:
gate_dest_selector = gate_descriptor.u.gate.dest_selector;
gate_dest_offset = gate_descriptor.u.gate.dest_offset;
// examine CS selector and descriptor given in gate descriptor
// selector must be non-null else #GP(EXT)
if ((gate_dest_selector & 0xfffc) == 0) {
BX_ERROR(("int_trap_gate(): selector null"));
exception(BX_GP_EXCEPTION, 0);
}
parse_selector(gate_dest_selector, &cs_selector);
// selector must be within its descriptor table limits
// else #GP(selector+EXT)
fetch_raw_descriptor(&cs_selector, &dword1, &dword2, BX_GP_EXCEPTION);
parse_descriptor(dword1, dword2, &cs_descriptor);
// descriptor AR byte must indicate code seg
// and code segment descriptor DPL<=CPL, else #GP(selector+EXT)
if (cs_descriptor.valid==0 || cs_descriptor.segment==0 ||
IS_DATA_SEGMENT(cs_descriptor.type) ||
cs_descriptor.dpl > CPL)
{
BX_ERROR(("interrupt(): not accessible or not code segment cs=0x%04x", cs_selector.value));
exception(BX_GP_EXCEPTION, cs_selector.value & 0xfffc);
}
// segment must be present, else #NP(selector + EXT)
if (! IS_PRESENT(cs_descriptor)) {
BX_ERROR(("interrupt(): segment not present"));
exception(BX_NP_EXCEPTION, cs_selector.value & 0xfffc);
}
// if code segment is non-conforming and DPL < CPL then
// INTERRUPT TO INNER PRIVILEGE
if(IS_CODE_SEGMENT_NON_CONFORMING(cs_descriptor.type) && cs_descriptor.dpl < CPL)
{
Bit16u old_SS, old_CS, SS_for_cpl_x;
Bit32u ESP_for_cpl_x, old_EIP, old_ESP;
bx_descriptor_t ss_descriptor;
bx_selector_t ss_selector;
int is_v8086_mode = v8086_mode();
BX_DEBUG(("interrupt(): INTERRUPT TO INNER PRIVILEGE"));
// check selector and descriptor for new stack in current TSS
get_SS_ESP_from_TSS(cs_descriptor.dpl,
&SS_for_cpl_x, &ESP_for_cpl_x);
if (is_v8086_mode && cs_descriptor.dpl != 0) {
// if code segment DPL != 0 then #GP(new code segment selector)
BX_ERROR(("interrupt(): code segment DPL(%d) != 0 in v8086 mode", cs_descriptor.dpl));
exception(BX_GP_EXCEPTION, cs_selector.value & 0xfffc);
}
// Selector must be non-null else #TS(EXT)
if ((SS_for_cpl_x & 0xfffc) == 0) {
BX_ERROR(("interrupt(): SS selector null"));
exception(BX_TS_EXCEPTION, 0); /* TS(ext) */
}
// selector index must be within its descriptor table limits
// else #TS(SS selector + EXT)
parse_selector(SS_for_cpl_x, &ss_selector);
// fetch 2 dwords of descriptor; call handles out of limits checks
fetch_raw_descriptor(&ss_selector, &dword1, &dword2, BX_TS_EXCEPTION);
parse_descriptor(dword1, dword2, &ss_descriptor);
// selector rpl must = dpl of code segment,
// else #TS(SS selector + ext)
if (ss_selector.rpl != cs_descriptor.dpl) {
BX_ERROR(("interrupt(): SS.rpl != CS.dpl"));
exception(BX_TS_EXCEPTION, SS_for_cpl_x & 0xfffc);
}
// stack seg DPL must = DPL of code segment,
// else #TS(SS selector + ext)
if (ss_descriptor.dpl != cs_descriptor.dpl) {
BX_ERROR(("interrupt(): SS.dpl != CS.dpl"));
exception(BX_TS_EXCEPTION, SS_for_cpl_x & 0xfffc);
}
// descriptor must indicate writable data segment,
// else #TS(SS selector + EXT)
if (ss_descriptor.valid==0 || ss_descriptor.segment==0 ||
IS_CODE_SEGMENT(ss_descriptor.type) ||
!IS_DATA_SEGMENT_WRITEABLE(ss_descriptor.type))
{
BX_ERROR(("interrupt(): SS is not writable data segment"));
exception(BX_TS_EXCEPTION, SS_for_cpl_x & 0xfffc);
}
// seg must be present, else #SS(SS selector + ext)
if (! IS_PRESENT(ss_descriptor)) {
BX_ERROR(("interrupt(): SS not present"));
exception(BX_SS_EXCEPTION, SS_for_cpl_x & 0xfffc);
}
// IP must be within CS segment boundaries, else #GP(0)
if (gate_dest_offset > cs_descriptor.u.segment.limit_scaled) {
BX_ERROR(("interrupt(): gate EIP > CS.limit"));
exception(BX_GP_EXCEPTION, 0);
}
old_ESP = ESP;
old_SS = BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].selector.value;
old_EIP = EIP;
old_CS = BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value;
// Prepare new stack segment
bx_segment_reg_t new_stack;
new_stack.selector = ss_selector;
new_stack.cache = ss_descriptor;
new_stack.selector.rpl = cs_descriptor.dpl;
// add cpl to the selector value
new_stack.selector.value = (0xfffc & new_stack.selector.value) |
new_stack.selector.rpl;
if (ss_descriptor.u.segment.d_b) {
Bit32u temp_ESP = ESP_for_cpl_x;
if (is_v8086_mode)
{
if (gate_descriptor.type>=14) { // 386 int/trap gate
write_new_stack_dword_32(&new_stack, temp_ESP-4, cs_descriptor.dpl,
BX_CPU_THIS_PTR sregs[BX_SEG_REG_GS].selector.value);
write_new_stack_dword_32(&new_stack, temp_ESP-8, cs_descriptor.dpl,
BX_CPU_THIS_PTR sregs[BX_SEG_REG_FS].selector.value);
write_new_stack_dword_32(&new_stack, temp_ESP-12, cs_descriptor.dpl,
BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS].selector.value);
write_new_stack_dword_32(&new_stack, temp_ESP-16, cs_descriptor.dpl,
BX_CPU_THIS_PTR sregs[BX_SEG_REG_ES].selector.value);
temp_ESP -= 16;
}
else {
write_new_stack_word_32(&new_stack, temp_ESP-2, cs_descriptor.dpl,
BX_CPU_THIS_PTR sregs[BX_SEG_REG_GS].selector.value);
write_new_stack_word_32(&new_stack, temp_ESP-4, cs_descriptor.dpl,
BX_CPU_THIS_PTR sregs[BX_SEG_REG_FS].selector.value);
write_new_stack_word_32(&new_stack, temp_ESP-6, cs_descriptor.dpl,
BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS].selector.value);
write_new_stack_word_32(&new_stack, temp_ESP-8, cs_descriptor.dpl,
BX_CPU_THIS_PTR sregs[BX_SEG_REG_ES].selector.value);
temp_ESP -= 8;
}
}
if (gate_descriptor.type>=14) { // 386 int/trap gate
// push long pointer to old stack onto new stack
write_new_stack_dword_32(&new_stack, temp_ESP-4, cs_descriptor.dpl, old_SS);
write_new_stack_dword_32(&new_stack, temp_ESP-8, cs_descriptor.dpl, old_ESP);
write_new_stack_dword_32(&new_stack, temp_ESP-12, cs_descriptor.dpl, read_eflags());
write_new_stack_dword_32(&new_stack, temp_ESP-16, cs_descriptor.dpl, old_CS);
write_new_stack_dword_32(&new_stack, temp_ESP-20, cs_descriptor.dpl, old_EIP);
temp_ESP -= 20;
if (push_error) {
temp_ESP -= 4;
write_new_stack_dword_32(&new_stack, temp_ESP, cs_descriptor.dpl, error_code);
}
}
else { // 286 int/trap gate
// push long pointer to old stack onto new stack
write_new_stack_word_32(&new_stack, temp_ESP-2, cs_descriptor.dpl, old_SS);
write_new_stack_word_32(&new_stack, temp_ESP-4, cs_descriptor.dpl, (Bit16u) old_ESP);
write_new_stack_word_32(&new_stack, temp_ESP-6, cs_descriptor.dpl, (Bit16u) read_eflags());
write_new_stack_word_32(&new_stack, temp_ESP-8, cs_descriptor.dpl, old_CS);
write_new_stack_word_32(&new_stack, temp_ESP-10, cs_descriptor.dpl, (Bit16u) old_EIP);
temp_ESP -= 10;
if (push_error) {
temp_ESP -= 2;
write_new_stack_word_32(&new_stack, temp_ESP, cs_descriptor.dpl, error_code);
}
}
ESP = temp_ESP;
}
else {
Bit16u temp_SP = (Bit16u) ESP_for_cpl_x;
if (is_v8086_mode)
{
if (gate_descriptor.type>=14) { // 386 int/trap gate
write_new_stack_dword_32(&new_stack, (Bit16u)(temp_SP-4), cs_descriptor.dpl,
BX_CPU_THIS_PTR sregs[BX_SEG_REG_GS].selector.value);
write_new_stack_dword_32(&new_stack, (Bit16u)(temp_SP-8), cs_descriptor.dpl,
BX_CPU_THIS_PTR sregs[BX_SEG_REG_FS].selector.value);
write_new_stack_dword_32(&new_stack, (Bit16u)(temp_SP-12), cs_descriptor.dpl,
BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS].selector.value);
write_new_stack_dword_32(&new_stack, (Bit16u)(temp_SP-16), cs_descriptor.dpl,
BX_CPU_THIS_PTR sregs[BX_SEG_REG_ES].selector.value);
temp_SP -= 16;
}
else {
write_new_stack_word_32(&new_stack, (Bit16u)(temp_SP-2), cs_descriptor.dpl,
BX_CPU_THIS_PTR sregs[BX_SEG_REG_GS].selector.value);
write_new_stack_word_32(&new_stack, (Bit16u)(temp_SP-4), cs_descriptor.dpl,
BX_CPU_THIS_PTR sregs[BX_SEG_REG_FS].selector.value);
write_new_stack_word_32(&new_stack, (Bit16u)(temp_SP-6), cs_descriptor.dpl,
BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS].selector.value);
write_new_stack_word_32(&new_stack, (Bit16u)(temp_SP-8), cs_descriptor.dpl,
BX_CPU_THIS_PTR sregs[BX_SEG_REG_ES].selector.value);
temp_SP -= 8;
}
}
if (gate_descriptor.type>=14) { // 386 int/trap gate
// push long pointer to old stack onto new stack
write_new_stack_dword_32(&new_stack, (Bit16u)(temp_SP-4), cs_descriptor.dpl, old_SS);
write_new_stack_dword_32(&new_stack, (Bit16u)(temp_SP-8), cs_descriptor.dpl, old_ESP);
write_new_stack_dword_32(&new_stack, (Bit16u)(temp_SP-12), cs_descriptor.dpl, read_eflags());
write_new_stack_dword_32(&new_stack, (Bit16u)(temp_SP-16), cs_descriptor.dpl, old_CS);
write_new_stack_dword_32(&new_stack, (Bit16u)(temp_SP-20), cs_descriptor.dpl, old_EIP);
temp_SP -= 20;
if (push_error) {
temp_SP -= 4;
write_new_stack_dword_32(&new_stack, temp_SP, cs_descriptor.dpl, error_code);
}
}
else { // 286 int/trap gate
// push long pointer to old stack onto new stack
write_new_stack_word_32(&new_stack, (Bit16u)(temp_SP-2), cs_descriptor.dpl, old_SS);
write_new_stack_word_32(&new_stack, (Bit16u)(temp_SP-4), cs_descriptor.dpl, (Bit16u) old_ESP);
write_new_stack_word_32(&new_stack, (Bit16u)(temp_SP-6), cs_descriptor.dpl, (Bit16u) read_eflags());
write_new_stack_word_32(&new_stack, (Bit16u)(temp_SP-8), cs_descriptor.dpl, old_CS);
write_new_stack_word_32(&new_stack, (Bit16u)(temp_SP-10), cs_descriptor.dpl, (Bit16u) old_EIP);
temp_SP -= 10;
if (push_error) {
temp_SP -= 2;
write_new_stack_word_32(&new_stack, temp_SP, cs_descriptor.dpl, error_code);
}
}
SP = temp_SP;
}
// load new CS:eIP values from gate
// set CPL to new code segment DPL
// set RPL of CS to CPL
load_cs(&cs_selector, &cs_descriptor, cs_descriptor.dpl);
// load new SS:eSP values from TSS
load_ss(&ss_selector, &ss_descriptor, cs_descriptor.dpl);
if (is_v8086_mode)
{
BX_CPU_THIS_PTR sregs[BX_SEG_REG_GS].cache.valid = 0;
BX_CPU_THIS_PTR sregs[BX_SEG_REG_GS].selector.value = 0;
BX_CPU_THIS_PTR sregs[BX_SEG_REG_FS].cache.valid = 0;
BX_CPU_THIS_PTR sregs[BX_SEG_REG_FS].selector.value = 0;
BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS].cache.valid = 0;
BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS].selector.value = 0;
BX_CPU_THIS_PTR sregs[BX_SEG_REG_ES].cache.valid = 0;
BX_CPU_THIS_PTR sregs[BX_SEG_REG_ES].selector.value = 0;
}
}
else
{
BX_DEBUG(("interrupt(): INTERRUPT TO SAME PRIVILEGE"));
if (v8086_mode() && (IS_CODE_SEGMENT_CONFORMING(cs_descriptor.type) || cs_descriptor.dpl != 0)) {
// if code segment DPL != 0 then #GP(new code segment selector)
BX_ERROR(("interrupt(): code segment conforming or DPL(%d) != 0 in v8086 mode", cs_descriptor.dpl));
exception(BX_GP_EXCEPTION, cs_selector.value & 0xfffc);
}
// EIP must be in CS limit else #GP(0)
if (gate_dest_offset > cs_descriptor.u.segment.limit_scaled) {
BX_ERROR(("interrupt(): IP > CS descriptor limit"));
exception(BX_GP_EXCEPTION, 0);
}
// push flags onto stack
// push current CS selector onto stack
// push return offset onto stack
if (gate_descriptor.type >= 14) { // 386 gate
push_32(read_eflags());
push_32(BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value);
push_32(EIP);
if (push_error)
push_32(error_code);
}
else { // 286 gate
push_16((Bit16u) read_eflags());
push_16(BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value);
push_16(IP);
if (push_error)
push_16(error_code);
}
// load CS:IP from gate
// load CS descriptor
// set the RPL field of CS to CPL
load_cs(&cs_selector, &cs_descriptor, CPL);
}
EIP = gate_dest_offset;
// if interrupt gate then set IF to 0
if (!(gate_descriptor.type & 1)) // even is int-gate
BX_CPU_THIS_PTR clear_IF();
BX_CPU_THIS_PTR clear_TF();
BX_CPU_THIS_PTR clear_NT();
BX_CPU_THIS_PTR clear_VM();
BX_CPU_THIS_PTR clear_RF();
return;
default:
BX_PANIC(("bad descriptor type in interrupt()!"));
break;
}
}
void BX_CPU_C::real_mode_int(Bit8u vector, bx_bool push_error, Bit16u error_code)
{
if ((vector*4+3) > BX_CPU_THIS_PTR idtr.limit) {
BX_ERROR(("interrupt(real mode) vector > idtr.limit"));
exception(BX_GP_EXCEPTION, 0);
}
push_16((Bit16u) read_eflags());
push_16(BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value);
push_16(IP);
Bit16u new_ip = system_read_word(BX_CPU_THIS_PTR idtr.base + 4 * vector);
// CS.LIMIT can't change when in real/v8086 mode
if (new_ip > BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.limit_scaled) {
BX_ERROR(("interrupt(real mode): instruction pointer not within code segment limits"));
exception(BX_GP_EXCEPTION, 0);
}
Bit16u cs_selector = system_read_word(BX_CPU_THIS_PTR idtr.base + 4 * vector + 2);
load_seg_reg(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS], cs_selector);
EIP = new_ip;
/* INT affects the following flags: I,T */
BX_CPU_THIS_PTR clear_IF();
BX_CPU_THIS_PTR clear_TF();
#if BX_CPU_LEVEL >= 4
BX_CPU_THIS_PTR clear_AC();
#endif
BX_CPU_THIS_PTR clear_RF();
}
void BX_CPU_C::interrupt(Bit8u vector, unsigned type, bx_bool push_error, Bit16u error_code)
{
#if BX_DEBUGGER
BX_CPU_THIS_PTR show_flag |= Flag_intsig;
#if BX_DEBUG_LINUX
if (bx_dbg.linux_syscall) {
if (vector == 0x80) bx_dbg_linux_syscall(BX_CPU_ID);
}
#endif
bx_dbg_interrupt(BX_CPU_ID, vector, error_code);
#endif
BX_INSTR_INTERRUPT(BX_CPU_ID, vector);
invalidate_prefetch_q();
bx_bool soft_int = 0;
switch(type) {
case BX_SOFTWARE_INTERRUPT:
case BX_SOFTWARE_EXCEPTION:
soft_int = 1;
break;
case BX_PRIVILEGED_SOFTWARE_INTERRUPT:
case BX_EXTERNAL_INTERRUPT:
case BX_NMI:
case BX_HARDWARE_EXCEPTION:
break;
default:
BX_PANIC(("interrupt(): unknown exception type %d", type));
}
BX_DEBUG(("interrupt(): vector = %02x, TYPE = %u, EXT = %u",
vector, type, (unsigned) BX_CPU_THIS_PTR EXT));
// Discard any traps and inhibits for new context; traps will
// resume upon return.
BX_CPU_THIS_PTR debug_trap = 0;
BX_CPU_THIS_PTR inhibit_mask = 0;
#if BX_SUPPORT_VMX
BX_CPU_THIS_PTR in_event = 1;
#endif
#if BX_SUPPORT_X86_64
if (long_mode()) {
long_mode_int(vector, soft_int, push_error, error_code);
}
else
#endif
{
RSP_SPECULATIVE;
if(real_mode()) {
real_mode_int(vector, push_error, error_code);
}
else {
protected_mode_int(vector, soft_int, push_error, error_code);
}
RSP_COMMIT;
}
#if BX_X86_DEBUGGER
BX_CPU_THIS_PTR in_repeat = 0;
#endif
#if BX_SUPPORT_VMX
BX_CPU_THIS_PTR in_event = 0;
#endif
}
/* Exception classes. These are used as indexes into the 'is_exception_OK'
* array below, and are stored in the 'exception' array also
*/
#define BX_ET_BENIGN 0
#define BX_ET_CONTRIBUTORY 1
#define BX_ET_PAGE_FAULT 2
#define BX_ET_DOUBLE_FAULT 10
static const bx_bool is_exception_OK[3][3] = {
{ 1, 1, 1 }, /* 1st exception is BENIGN */
{ 1, 0, 1 }, /* 1st exception is CONTRIBUTORY */
{ 1, 0, 0 } /* 1st exception is PAGE_FAULT */
};
#define BX_EXCEPTION_CLASS_TRAP 0
#define BX_EXCEPTION_CLASS_FAULT 1
#define BX_EXCEPTION_CLASS_ABORT 2
struct BxExceptionInfo exceptions_info[BX_CPU_HANDLED_EXCEPTIONS+1] = {
/* DE */ { BX_ET_CONTRIBUTORY, BX_EXCEPTION_CLASS_FAULT, 0 },
/* DB */ { BX_ET_BENIGN, BX_EXCEPTION_CLASS_FAULT, 0 },
/* -- */ { BX_ET_BENIGN, BX_EXCEPTION_CLASS_FAULT, 0 }, // NMI
/* BP */ { BX_ET_BENIGN, BX_EXCEPTION_CLASS_TRAP, 0 },
/* OF */ { BX_ET_BENIGN, BX_EXCEPTION_CLASS_TRAP, 0 },
/* BR */ { BX_ET_BENIGN, BX_EXCEPTION_CLASS_FAULT, 0 },
/* UD */ { BX_ET_BENIGN, BX_EXCEPTION_CLASS_FAULT, 0 },
/* NM */ { BX_ET_BENIGN, BX_EXCEPTION_CLASS_FAULT, 0 },
/* DF */ { BX_ET_DOUBLE_FAULT, BX_EXCEPTION_CLASS_FAULT, 1 },
// coprocessor segment overrun (286,386 only)
/* -- */ { BX_ET_BENIGN, BX_EXCEPTION_CLASS_FAULT, 0 },
/* TS */ { BX_ET_CONTRIBUTORY, BX_EXCEPTION_CLASS_FAULT, 1 },
/* NP */ { BX_ET_CONTRIBUTORY, BX_EXCEPTION_CLASS_FAULT, 1 },
/* SS */ { BX_ET_CONTRIBUTORY, BX_EXCEPTION_CLASS_FAULT, 1 },
/* GP */ { BX_ET_CONTRIBUTORY, BX_EXCEPTION_CLASS_FAULT, 1 },
/* PF */ { BX_ET_PAGE_FAULT, BX_EXCEPTION_CLASS_FAULT, 1 },
/* -- */ { BX_ET_BENIGN, BX_EXCEPTION_CLASS_FAULT, 0 }, // reserved
/* MF */ { BX_ET_BENIGN, BX_EXCEPTION_CLASS_FAULT, 0 },
/* AC */ { BX_ET_BENIGN, BX_EXCEPTION_CLASS_FAULT, 1 },
/* MC */ { BX_ET_BENIGN, BX_EXCEPTION_CLASS_ABORT, 0 },
/* XM */ { BX_ET_BENIGN, BX_EXCEPTION_CLASS_FAULT, 0 },
/* -- */ { BX_ET_BENIGN, BX_EXCEPTION_CLASS_FAULT, 0 } // default
};
// vector: 0..255: vector in IDT
// error_code: if exception generates and error, push this error code
// trap: override exception class to TRAP
void BX_CPU_C::exception(unsigned vector, Bit16u error_code)
{
BX_INSTR_EXCEPTION(BX_CPU_ID, vector, error_code);
#if BX_DEBUGGER
bx_dbg_exception(BX_CPU_ID, vector, error_code);
#endif
BX_DEBUG(("exception(0x%02x): error_code=%04x", vector, error_code));
unsigned exception_type = 0;
unsigned exception_class = BX_EXCEPTION_CLASS_FAULT;
bx_bool push_error = 0;
if (vector < BX_CPU_HANDLED_EXCEPTIONS) {
push_error = exceptions_info[vector].push_error;
exception_class = exceptions_info[vector].exception_class;
exception_type = exceptions_info[vector].exception_type;
}
else {
BX_PANIC(("exception(%u): bad vector", vector));
}
if (vector != BX_PF_EXCEPTION && vector != BX_DF_EXCEPTION) {
// Page faults have different format
error_code = (error_code & 0xfffe) | BX_CPU_THIS_PTR EXT;
}
#if BX_SUPPORT_VMX
VMexit_Event(0, BX_HARDWARE_EXCEPTION, vector, error_code, push_error);
#endif
if (BX_CPU_THIS_PTR errorno > 0) {
if (BX_CPU_THIS_PTR errorno > 2 || BX_CPU_THIS_PTR curr_exception == BX_ET_DOUBLE_FAULT) {
// restore RIP/RSP to value before error occurred
RIP = BX_CPU_THIS_PTR prev_rip;
if (BX_CPU_THIS_PTR speculative_rsp)
RSP = BX_CPU_THIS_PTR prev_rsp;
debug(BX_CPU_THIS_PTR prev_rip); // print debug information to the log
#if BX_SUPPORT_VMX
VMexit_TripleFault();
#endif
#if BX_DEBUGGER
// trap into debugger (similar as done when PANIC occured)
bx_debug_break();
#endif
if (SIM->get_param_bool(BXPN_RESET_ON_TRIPLE_FAULT)->get()) {
BX_ERROR(("exception(): 3rd (%d) exception with no resolution, shutdown status is %02xh, resetting", vector, DEV_cmos_get_reg(0x0f)));
bx_pc_system.Reset(BX_RESET_HARDWARE);
}
else {
BX_PANIC(("exception(): 3rd (%d) exception with no resolution", vector));
BX_ERROR(("WARNING: Any simulation after this point is completely bogus !"));
shutdown();
}
longjmp(BX_CPU_THIS_PTR jmp_buf_env, 1); // go back to main decode loop
}
}
// note: fault-class exceptions _except_ #DB set RF in
// eflags image.
if (exception_class == BX_EXCEPTION_CLASS_FAULT)
{
// restore RIP/RSP to value before error occurred
RIP = BX_CPU_THIS_PTR prev_rip;
if (BX_CPU_THIS_PTR speculative_rsp)
RSP = BX_CPU_THIS_PTR prev_rsp;
if (vector != BX_DB_EXCEPTION) BX_CPU_THIS_PTR assert_RF();
}
if (vector == BX_DB_EXCEPTION) {
// Commit debug events to DR6
#if BX_CPU_LEVEL <= 4
// On 386/486 bit12 is settable
BX_CPU_THIS_PTR dr6 = (BX_CPU_THIS_PTR dr6 & 0xffff0ff0) |
(BX_CPU_THIS_PTR debug_trap & 0x0000f00f);
#else
// On Pentium+, bit12 is always zero
BX_CPU_THIS_PTR dr6 = (BX_CPU_THIS_PTR dr6 & 0xffff0ff0) |
(BX_CPU_THIS_PTR debug_trap & 0x0000e00f);
#endif
// clear GD flag in the DR7 prior entering debug exception handler
BX_CPU_THIS_PTR dr7 &= ~0x00002000;
}
BX_CPU_THIS_PTR EXT = 1;
/* if we've already had 1st exception, see if 2nd causes a
* Double Fault instead. Otherwise, just record 1st exception
*/
if (BX_CPU_THIS_PTR errorno > 0 && exception_type != BX_ET_DOUBLE_FAULT) {
if (! is_exception_OK[BX_CPU_THIS_PTR curr_exception][exception_type]) {
exception(BX_DF_EXCEPTION, 0);
}
}
BX_CPU_THIS_PTR curr_exception = exception_type;
BX_CPU_THIS_PTR errorno++;
if (real_mode()) {
push_error = 0; // not INT, no error code pushed
error_code = 0;
}
interrupt(vector, BX_HARDWARE_EXCEPTION, push_error, error_code);
BX_CPU_THIS_PTR errorno = 0; // error resolved
longjmp(BX_CPU_THIS_PTR jmp_buf_env, 1); // go back to main decode loop
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,793 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2005-2011 Stanislav Shwartsman
// 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
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA B 02110-1301 USA
//
/////////////////////////////////////////////////////////////////////////
#ifndef BX_COMMON_FETCHDECODE_TABLES_H
#define BX_COMMON_FETCHDECODE_TABLES_H
typedef struct BxOpcodeInfo_t {
Bit16u Attr;
Bit16u IA;
const BxOpcodeInfo_t *AnotherArray;
} BxOpcodeInfo_t;
//
// This file contains common IA-32/X86-64 opcode tables, like FPU opcode
// table, 3DNow! opcode table or SSE opcode groups (choose the opcode
// according to instruction prefixes)
//
BX_CPP_INLINE Bit16u FetchWORD(const Bit8u *iptr)
{
Bit16u data;
ReadHostWordFromLittleEndian(iptr, data);
return data;
}
BX_CPP_INLINE Bit32u FetchDWORD(const Bit8u *iptr)
{
Bit32u data;
ReadHostDWordFromLittleEndian(iptr, data);
return data;
}
#if BX_SUPPORT_X86_64
BX_CPP_INLINE Bit64u FetchQWORD(const Bit8u *iptr)
{
Bit64u data;
ReadHostQWordFromLittleEndian(iptr, data);
return data;
}
#endif
#define BX_PREPARE_SSE (0x01)
#define BX_PREPARE_AVX (0x02)
#define BX_VEX_L128 (0x04) /* VEX.L128 allowed */
#define BX_VEX_L256 (0x08) /* VEX.L256 allowed */
struct bxIAOpcodeTable {
BxExecutePtr_tR execute1;
BxExecutePtr_tR execute2;
Bit32u flags;
};
//
// Common FetchDecode Opcode Tables
//
#include "fetchdecode_x87.h"
#include "fetchdecode_sse.h"
/* ************************************************************************ */
/* Opcode Groups */
/* ******* */
/* Group 1 */
/* ******* */
static const BxOpcodeInfo_t BxOpcodeInfoG1EbIb[8] = {
// attributes defined in main area
/* 0 */ { BxLockable, BX_IA_ADD_EbIb },
/* 1 */ { BxLockable, BX_IA_OR_EbIb },
/* 2 */ { BxLockable, BX_IA_ADC_EbIb },
/* 3 */ { BxLockable, BX_IA_SBB_EbIb },
/* 4 */ { BxLockable, BX_IA_AND_EbIb },
/* 5 */ { BxLockable, BX_IA_SUB_EbIb },
/* 6 */ { BxLockable, BX_IA_XOR_EbIb },
/* 7 */ { 0, BX_IA_CMP_EbIb }
};
static const BxOpcodeInfo_t BxOpcodeInfoG1Ew[8] = {
// attributes defined in main area
/* 0 */ { BxLockable, BX_IA_ADD_EwIw },
/* 1 */ { BxLockable, BX_IA_OR_EwIw },
/* 2 */ { BxLockable, BX_IA_ADC_EwIw },
/* 3 */ { BxLockable, BX_IA_SBB_EwIw },
/* 4 */ { BxLockable, BX_IA_AND_EwIw },
/* 5 */ { BxLockable, BX_IA_SUB_EwIw },
/* 6 */ { BxLockable, BX_IA_XOR_EwIw },
/* 7 */ { 0, BX_IA_CMP_EwIw }
};
static const BxOpcodeInfo_t BxOpcodeInfoG1Ed[8] = {
// attributes defined in main area
/* 0 */ { BxLockable, BX_IA_ADD_EdId },
/* 1 */ { BxLockable, BX_IA_OR_EdId },
/* 2 */ { BxLockable, BX_IA_ADC_EdId },
/* 3 */ { BxLockable, BX_IA_SBB_EdId },
/* 4 */ { BxLockable, BX_IA_AND_EdId },
/* 5 */ { BxLockable, BX_IA_SUB_EdId },
/* 6 */ { BxLockable, BX_IA_XOR_EdId },
/* 7 */ { 0, BX_IA_CMP_EdId }
};
#if BX_SUPPORT_X86_64
static const BxOpcodeInfo_t BxOpcodeInfo64G1Eq[8] = {
// attributes defined in main area
/* 0 */ { BxLockable, BX_IA_ADD_EqId },
/* 1 */ { BxLockable, BX_IA_OR_EqId },
/* 2 */ { BxLockable, BX_IA_ADC_EqId },
/* 3 */ { BxLockable, BX_IA_SBB_EqId },
/* 4 */ { BxLockable, BX_IA_AND_EqId },
/* 5 */ { BxLockable, BX_IA_SUB_EqId },
/* 6 */ { BxLockable, BX_IA_XOR_EqId },
/* 7 */ { 0, BX_IA_CMP_EqId }
};
#endif
/* ******** */
/* Group 1A */
/* ******** */
static const BxOpcodeInfo_t BxOpcodeInfoG1AEw[8] = {
/* 0 */ { 0, BX_IA_POP_Ew },
/* 1 */ { 0, BX_IA_ERROR },
/* 2 */ { 0, BX_IA_ERROR },
/* 3 */ { 0, BX_IA_ERROR },
/* 4 */ { 0, BX_IA_ERROR },
/* 5 */ { 0, BX_IA_ERROR },
/* 6 */ { 0, BX_IA_ERROR },
/* 7 */ { 0, BX_IA_ERROR }
};
static const BxOpcodeInfo_t BxOpcodeInfoG1AEd[8] = {
/* 0 */ { 0, BX_IA_POP_Ed },
/* 1 */ { 0, BX_IA_ERROR },
/* 2 */ { 0, BX_IA_ERROR },
/* 3 */ { 0, BX_IA_ERROR },
/* 4 */ { 0, BX_IA_ERROR },
/* 5 */ { 0, BX_IA_ERROR },
/* 6 */ { 0, BX_IA_ERROR },
/* 7 */ { 0, BX_IA_ERROR }
};
#if BX_SUPPORT_X86_64
static const BxOpcodeInfo_t BxOpcodeInfo64G1AEq[8] = {
/* 0 */ { 0, BX_IA_POP_Eq },
/* 1 */ { 0, BX_IA_ERROR },
/* 2 */ { 0, BX_IA_ERROR },
/* 3 */ { 0, BX_IA_ERROR },
/* 4 */ { 0, BX_IA_ERROR },
/* 5 */ { 0, BX_IA_ERROR },
/* 6 */ { 0, BX_IA_ERROR },
/* 7 */ { 0, BX_IA_ERROR }
};
#endif
/* ******* */
/* Group 2 */
/* ******* */
static const BxOpcodeInfo_t BxOpcodeInfoG2Eb[8] = {
// attributes defined in main area
/* 0 */ { 0, BX_IA_ROL_Eb },
/* 1 */ { 0, BX_IA_ROR_Eb },
/* 2 */ { 0, BX_IA_RCL_Eb },
/* 3 */ { 0, BX_IA_RCR_Eb },
/* 4 */ { 0, BX_IA_SHL_Eb },
/* 5 */ { 0, BX_IA_SHR_Eb },
/* 6 */ { 0, BX_IA_SHL_Eb },
/* 7 */ { 0, BX_IA_SAR_Eb }
};
static const BxOpcodeInfo_t BxOpcodeInfoG2Ew[8] = {
// attributes defined in main area
/* 0 */ { 0, BX_IA_ROL_Ew },
/* 1 */ { 0, BX_IA_ROR_Ew },
/* 2 */ { 0, BX_IA_RCL_Ew },
/* 3 */ { 0, BX_IA_RCR_Ew },
/* 4 */ { 0, BX_IA_SHL_Ew },
/* 5 */ { 0, BX_IA_SHR_Ew },
/* 6 */ { 0, BX_IA_SHL_Ew },
/* 7 */ { 0, BX_IA_SAR_Ew }
};
static const BxOpcodeInfo_t BxOpcodeInfoG2Ed[8] = {
// attributes defined in main area
/* 0 */ { 0, BX_IA_ROL_Ed },
/* 1 */ { 0, BX_IA_ROR_Ed },
/* 2 */ { 0, BX_IA_RCL_Ed },
/* 3 */ { 0, BX_IA_RCR_Ed },
/* 4 */ { 0, BX_IA_SHL_Ed },
/* 5 */ { 0, BX_IA_SHR_Ed },
/* 6 */ { 0, BX_IA_SHL_Ed },
/* 7 */ { 0, BX_IA_SAR_Ed }
};
#if BX_SUPPORT_X86_64
static const BxOpcodeInfo_t BxOpcodeInfo64G2Eq[8] = {
// attributes defined in main area
/* 0 */ { 0, BX_IA_ROL_Eq },
/* 1 */ { 0, BX_IA_ROR_Eq },
/* 2 */ { 0, BX_IA_RCL_Eq },
/* 3 */ { 0, BX_IA_RCR_Eq },
/* 4 */ { 0, BX_IA_SHL_Eq },
/* 5 */ { 0, BX_IA_SHR_Eq },
/* 6 */ { 0, BX_IA_SHL_Eq },
/* 7 */ { 0, BX_IA_SAR_Eq }
};
#endif
/* ******* */
/* Group 3 */
/* ******* */
static const BxOpcodeInfo_t BxOpcodeInfoG3Eb[8] = {
/* 0 */ { BxImmediate_Ib, BX_IA_TEST_EbIb },
/* 1 */ { BxImmediate_Ib, BX_IA_TEST_EbIb },
/* 2 */ { BxLockable, BX_IA_NOT_Eb },
/* 3 */ { BxLockable, BX_IA_NEG_Eb },
/* 4 */ { 0, BX_IA_MUL_ALEb },
/* 5 */ { 0, BX_IA_IMUL_ALEb },
/* 6 */ { 0, BX_IA_DIV_ALEb },
/* 7 */ { 0, BX_IA_IDIV_ALEb }
};
static const BxOpcodeInfo_t BxOpcodeInfoG3Ew[8] = {
/* 0 */ { BxImmediate_Iw, BX_IA_TEST_EwIw },
/* 1 */ { BxImmediate_Iw, BX_IA_TEST_EwIw },
/* 2 */ { BxLockable, BX_IA_NOT_Ew },
/* 3 */ { BxLockable, BX_IA_NEG_Ew },
/* 4 */ { 0, BX_IA_MUL_AXEw },
/* 5 */ { 0, BX_IA_IMUL_AXEw },
/* 6 */ { 0, BX_IA_DIV_AXEw },
/* 7 */ { 0, BX_IA_IDIV_AXEw }
};
static const BxOpcodeInfo_t BxOpcodeInfoG3Ed[8] = {
/* 0 */ { BxImmediate_Id, BX_IA_TEST_EdId },
/* 1 */ { BxImmediate_Id, BX_IA_TEST_EdId },
/* 2 */ { BxLockable, BX_IA_NOT_Ed },
/* 3 */ { BxLockable, BX_IA_NEG_Ed },
/* 4 */ { 0, BX_IA_MUL_EAXEd },
/* 5 */ { 0, BX_IA_IMUL_EAXEd },
/* 6 */ { 0, BX_IA_DIV_EAXEd },
/* 7 */ { 0, BX_IA_IDIV_EAXEd }
};
#if BX_SUPPORT_X86_64
static const BxOpcodeInfo_t BxOpcodeInfo64G3Eq[8] = {
/* 0 */ { BxImmediate_Id, BX_IA_TEST_EqId },
/* 1 */ { BxImmediate_Id, BX_IA_TEST_EqId },
/* 2 */ { BxLockable, BX_IA_NOT_Eq },
/* 3 */ { BxLockable, BX_IA_NEG_Eq },
/* 4 */ { 0, BX_IA_MUL_RAXEq },
/* 5 */ { 0, BX_IA_IMUL_RAXEq },
/* 6 */ { 0, BX_IA_DIV_RAXEq },
/* 7 */ { 0, BX_IA_IDIV_RAXEq }
};
#endif
/* ******* */
/* Group 4 */
/* ******* */
static const BxOpcodeInfo_t BxOpcodeInfoG4[8] = {
/* 0 */ { BxLockable, BX_IA_INC_Eb },
/* 1 */ { BxLockable, BX_IA_DEC_Eb },
/* 2 */ { 0, BX_IA_ERROR },
/* 3 */ { 0, BX_IA_ERROR },
/* 4 */ { 0, BX_IA_ERROR },
/* 5 */ { 0, BX_IA_ERROR },
/* 6 */ { 0, BX_IA_ERROR },
/* 7 */ { 0, BX_IA_ERROR }
};
/* ******* */
/* Group 5 */
/* ******* */
static const BxOpcodeInfo_t BxOpcodeInfoG5w[8] = {
// attributes defined in main area
/* 0 */ { BxLockable, BX_IA_INC_Ew },
/* 1 */ { BxLockable, BX_IA_DEC_Ew },
/* 2 */ { BxTraceEnd, BX_IA_CALL_Ew },
/* 3 */ { BxTraceEnd, BX_IA_CALL16_Ep },
/* 4 */ { BxTraceEnd, BX_IA_JMP_Ew },
/* 5 */ { BxTraceEnd, BX_IA_JMP16_Ep },
/* 6 */ { 0, BX_IA_PUSH_Ew },
/* 7 */ { 0, BX_IA_ERROR }
};
static const BxOpcodeInfo_t BxOpcodeInfoG5d[8] = {
// attributes defined in main area
/* 0 */ { BxLockable, BX_IA_INC_Ed },
/* 1 */ { BxLockable, BX_IA_DEC_Ed },
/* 2 */ { BxTraceEnd, BX_IA_CALL_Ed },
/* 3 */ { BxTraceEnd, BX_IA_CALL32_Ep },
/* 4 */ { BxTraceEnd, BX_IA_JMP_Ed },
/* 5 */ { BxTraceEnd, BX_IA_JMP32_Ep },
/* 6 */ { 0, BX_IA_PUSH_Ed },
/* 7 */ { 0, BX_IA_ERROR }
};
#if BX_SUPPORT_X86_64
static const BxOpcodeInfo_t BxOpcodeInfo64G5w[8] = {
/* 0 */ { BxLockable, BX_IA_INC_Ew },
/* 1 */ { BxLockable, BX_IA_DEC_Ew },
/* 2 */ { BxTraceEnd, BX_IA_CALL_Eq },
/* 3 */ { BxTraceEnd, BX_IA_CALL16_Ep },
/* 4 */ { BxTraceEnd, BX_IA_JMP_Eq },
/* 5 */ { BxTraceEnd, BX_IA_JMP16_Ep },
/* 6 */ { 0, BX_IA_PUSH_Ew },
/* 7 */ { 0, BX_IA_ERROR }
};
static const BxOpcodeInfo_t BxOpcodeInfo64G5d[8] = {
/* 0 */ { BxLockable, BX_IA_INC_Ed },
/* 1 */ { BxLockable, BX_IA_DEC_Ed },
/* 2 */ { BxTraceEnd, BX_IA_CALL_Eq },
/* 3 */ { BxTraceEnd, BX_IA_CALL32_Ep },
/* 4 */ { BxTraceEnd, BX_IA_JMP_Eq },
/* 5 */ { BxTraceEnd, BX_IA_JMP32_Ep },
/* 6 */ { 0, BX_IA_PUSH_Eq },
/* 7 */ { 0, BX_IA_ERROR }
};
static const BxOpcodeInfo_t BxOpcodeInfo64G5q[8] = {
/* 0 */ { BxLockable, BX_IA_INC_Eq },
/* 1 */ { BxLockable, BX_IA_DEC_Eq },
/* 2 */ { BxTraceEnd, BX_IA_CALL_Eq },
/* 3 */ { BxTraceEnd, BX_IA_CALL64_Ep }, // TODO: 64-bit offset for Intel
/* 4 */ { BxTraceEnd, BX_IA_JMP_Eq },
/* 5 */ { BxTraceEnd, BX_IA_JMP64_Ep }, // TODO: 64-bit offset for Intel
/* 6 */ { 0, BX_IA_PUSH_Eq },
/* 7 */ { 0, BX_IA_ERROR }
};
#endif
/* ******* */
/* Group 6 */
/* ******* */
static const BxOpcodeInfo_t BxOpcodeInfoG6[8] = {
/* 0 */ { 0, BX_IA_SLDT_Ew },
/* 1 */ { 0, BX_IA_STR_Ew },
/* 2 */ { 0, BX_IA_LLDT_Ew },
/* 3 */ { 0, BX_IA_LTR_Ew },
/* 4 */ { 0, BX_IA_VERR_Ew },
/* 5 */ { 0, BX_IA_VERW_Ew },
/* 6 */ { 0, BX_IA_ERROR },
/* 7 */ { 0, BX_IA_ERROR }
};
/* ******* */
/* Group 7 */
/* ******* */
static const BxOpcodeInfo_t BxOpcodeInfoG7[64+8] = {
/* /m form */
/* 0 */ { 0, BX_IA_SGDT_Ms },
/* 1 */ { 0, BX_IA_SIDT_Ms },
/* 2 */ { 0, BX_IA_LGDT_Ms },
/* 3 */ { 0, BX_IA_LIDT_Ms },
/* 4 */ { 0, BX_IA_SMSW_Ew },
/* 5 */ { 0, BX_IA_ERROR },
/* 6 */ { BxTraceEnd, BX_IA_LMSW_Ew },
/* 7 */ { BxTraceEnd, BX_IA_INVLPG },
/* /r form */
/* 0F 01 C0 */ { 0, BX_IA_ERROR },
/* 0F 01 C1 */ { BxTraceEnd | BxPrefixSSE, BX_IA_VMCALL, BxOpcodeGroupSSE_ERR },
/* 0F 01 C2 */ { BxTraceEnd | BxPrefixSSE, BX_IA_VMLAUNCH, BxOpcodeGroupSSE_ERR },
/* 0F 01 C3 */ { BxTraceEnd | BxPrefixSSE, BX_IA_VMRESUME, BxOpcodeGroupSSE_ERR },
/* 0F 01 C4 */ { BxTraceEnd | BxPrefixSSE, BX_IA_VMXOFF, BxOpcodeGroupSSE_ERR },
/* 0F 01 C5 */ { 0, BX_IA_ERROR },
/* 0F 01 C6 */ { 0, BX_IA_ERROR },
/* 0F 01 C7 */ { 0, BX_IA_ERROR },
/* 0F 01 C8 */ { BxPrefixSSE, BX_IA_MONITOR, BxOpcodeGroupSSE_ERR },
/* 0F 01 C9 */ { BxPrefixSSE | BxTraceEnd, BX_IA_MWAIT, BxOpcodeGroupSSE_ERR },
/* 0F 01 CA */ { 0, BX_IA_ERROR },
/* 0F 01 CB */ { 0, BX_IA_ERROR },
/* 0F 01 CC */ { 0, BX_IA_ERROR },
/* 0F 01 CD */ { 0, BX_IA_ERROR },
/* 0F 01 CE */ { 0, BX_IA_ERROR },
/* 0F 01 CF */ { 0, BX_IA_ERROR },
/* 0F 01 D0 */ { BxPrefixSSE, BX_IA_XGETBV, BxOpcodeGroupSSE_ERR },
/* 0F 01 D1 */ { BxPrefixSSE, BX_IA_XSETBV, BxOpcodeGroupSSE_ERR },
/* 0F 01 D2 */ { 0, BX_IA_ERROR },
/* 0F 01 D3 */ { 0, BX_IA_ERROR },
/* 0F 01 D4 */ { 0, BX_IA_ERROR },
/* 0F 01 D5 */ { 0, BX_IA_ERROR },
/* 0F 01 D6 */ { 0, BX_IA_ERROR },
/* 0F 01 D7 */ { 0, BX_IA_ERROR },
/* 0F 01 D8 */ { 0, BX_IA_ERROR },
/* 0F 01 D9 */ { 0, BX_IA_ERROR },
/* 0F 01 DA */ { 0, BX_IA_ERROR },
/* 0F 01 DB */ { 0, BX_IA_ERROR },
/* 0F 01 DC */ { 0, BX_IA_ERROR },
/* 0F 01 DD */ { 0, BX_IA_ERROR },
/* 0F 01 DE */ { 0, BX_IA_ERROR },
/* 0F 01 DF */ { 0, BX_IA_ERROR },
/* 0F 01 E0 */ { 0, BX_IA_SMSW_Ew },
/* 0F 01 E1 */ { 0, BX_IA_SMSW_Ew },
/* 0F 01 E2 */ { 0, BX_IA_SMSW_Ew },
/* 0F 01 E3 */ { 0, BX_IA_SMSW_Ew },
/* 0F 01 E4 */ { 0, BX_IA_SMSW_Ew },
/* 0F 01 E5 */ { 0, BX_IA_SMSW_Ew },
/* 0F 01 E6 */ { 0, BX_IA_SMSW_Ew },
/* 0F 01 E7 */ { 0, BX_IA_SMSW_Ew },
/* 0F 01 E8 */ { 0, BX_IA_ERROR },
/* 0F 01 E9 */ { 0, BX_IA_ERROR },
/* 0F 01 EA */ { 0, BX_IA_ERROR },
/* 0F 01 EB */ { 0, BX_IA_ERROR },
/* 0F 01 EC */ { 0, BX_IA_ERROR },
/* 0F 01 ED */ { 0, BX_IA_ERROR },
/* 0F 01 EE */ { 0, BX_IA_ERROR },
/* 0F 01 EF */ { 0, BX_IA_ERROR },
/* 0F 01 F0 */ { BxTraceEnd, BX_IA_LMSW_Ew },
/* 0F 01 F1 */ { BxTraceEnd, BX_IA_LMSW_Ew },
/* 0F 01 F2 */ { BxTraceEnd, BX_IA_LMSW_Ew },
/* 0F 01 F3 */ { BxTraceEnd, BX_IA_LMSW_Ew },
/* 0F 01 F4 */ { BxTraceEnd, BX_IA_LMSW_Ew },
/* 0F 01 F5 */ { BxTraceEnd, BX_IA_LMSW_Ew },
/* 0F 01 F6 */ { BxTraceEnd, BX_IA_LMSW_Ew },
/* 0F 01 F7 */ { BxTraceEnd, BX_IA_LMSW_Ew },
/* 0F 01 F8 */ { 0, BX_IA_ERROR },
/* 0F 01 F9 */ { 0, BX_IA_RDTSCP },
/* 0F 01 FA */ { 0, BX_IA_ERROR },
/* 0F 01 FB */ { 0, BX_IA_ERROR },
/* 0F 01 FC */ { 0, BX_IA_ERROR },
/* 0F 01 FD */ { 0, BX_IA_ERROR },
/* 0F 01 FE */ { 0, BX_IA_ERROR },
/* 0F 01 FF */ { 0, BX_IA_ERROR }
};
#if BX_SUPPORT_X86_64
static const BxOpcodeInfo_t BxOpcodeInfoG7q[64+8] = {
/* /m form */
/* 0 */ { 0, BX_IA_SGDT64_Ms },
/* 1 */ { 0, BX_IA_SIDT64_Ms },
/* 2 */ { 0, BX_IA_LGDT64_Ms },
/* 3 */ { 0, BX_IA_LIDT64_Ms },
/* 4 */ { 0, BX_IA_SMSW_Ew },
/* 5 */ { 0, BX_IA_ERROR },
/* 6 */ { BxTraceEnd, BX_IA_LMSW_Ew },
/* 7 */ { BxTraceEnd, BX_IA_INVLPG },
/* /r form */
/* 0F 01 C0 */ { 0, BX_IA_ERROR },
/* 0F 01 C1 */ { BxTraceEnd | BxPrefixSSE, BX_IA_VMCALL, BxOpcodeGroupSSE_ERR },
/* 0F 01 C2 */ { BxTraceEnd | BxPrefixSSE, BX_IA_VMLAUNCH, BxOpcodeGroupSSE_ERR },
/* 0F 01 C3 */ { BxTraceEnd | BxPrefixSSE, BX_IA_VMRESUME, BxOpcodeGroupSSE_ERR },
/* 0F 01 C4 */ { BxTraceEnd | BxPrefixSSE, BX_IA_VMXOFF, BxOpcodeGroupSSE_ERR },
/* 0F 01 C5 */ { 0, BX_IA_ERROR },
/* 0F 01 C6 */ { 0, BX_IA_ERROR },
/* 0F 01 C7 */ { 0, BX_IA_ERROR },
/* 0F 01 C8 */ { BxPrefixSSE, BX_IA_MONITOR, BxOpcodeGroupSSE_ERR },
/* 0F 01 C9 */ { BxPrefixSSE | BxTraceEnd, BX_IA_MWAIT, BxOpcodeGroupSSE_ERR },
/* 0F 01 CA */ { 0, BX_IA_ERROR },
/* 0F 01 CB */ { 0, BX_IA_ERROR },
/* 0F 01 CC */ { 0, BX_IA_ERROR },
/* 0F 01 CD */ { 0, BX_IA_ERROR },
/* 0F 01 CE */ { 0, BX_IA_ERROR },
/* 0F 01 CF */ { 0, BX_IA_ERROR },
/* 0F 01 D0 */ { BxPrefixSSE, BX_IA_XGETBV, BxOpcodeGroupSSE_ERR },
/* 0F 01 D1 */ { BxPrefixSSE, BX_IA_XSETBV, BxOpcodeGroupSSE_ERR },
/* 0F 01 D2 */ { 0, BX_IA_ERROR },
/* 0F 01 D3 */ { 0, BX_IA_ERROR },
/* 0F 01 D4 */ { 0, BX_IA_ERROR },
/* 0F 01 D5 */ { 0, BX_IA_ERROR },
/* 0F 01 D6 */ { 0, BX_IA_ERROR },
/* 0F 01 D7 */ { 0, BX_IA_ERROR },
/* 0F 01 D8 */ { 0, BX_IA_ERROR },
/* 0F 01 D9 */ { 0, BX_IA_ERROR },
/* 0F 01 DA */ { 0, BX_IA_ERROR },
/* 0F 01 DB */ { 0, BX_IA_ERROR },
/* 0F 01 DC */ { 0, BX_IA_ERROR },
/* 0F 01 DD */ { 0, BX_IA_ERROR },
/* 0F 01 DE */ { 0, BX_IA_ERROR },
/* 0F 01 DF */ { 0, BX_IA_ERROR },
/* 0F 01 E0 */ { 0, BX_IA_SMSW_Ew },
/* 0F 01 E1 */ { 0, BX_IA_SMSW_Ew },
/* 0F 01 E2 */ { 0, BX_IA_SMSW_Ew },
/* 0F 01 E3 */ { 0, BX_IA_SMSW_Ew },
/* 0F 01 E4 */ { 0, BX_IA_SMSW_Ew },
/* 0F 01 E5 */ { 0, BX_IA_SMSW_Ew },
/* 0F 01 E6 */ { 0, BX_IA_SMSW_Ew },
/* 0F 01 E7 */ { 0, BX_IA_SMSW_Ew },
/* 0F 01 E8 */ { 0, BX_IA_ERROR },
/* 0F 01 E9 */ { 0, BX_IA_ERROR },
/* 0F 01 EA */ { 0, BX_IA_ERROR },
/* 0F 01 EB */ { 0, BX_IA_ERROR },
/* 0F 01 EC */ { 0, BX_IA_ERROR },
/* 0F 01 ED */ { 0, BX_IA_ERROR },
/* 0F 01 EE */ { 0, BX_IA_ERROR },
/* 0F 01 EF */ { 0, BX_IA_ERROR },
/* 0F 01 F0 */ { BxTraceEnd, BX_IA_LMSW_Ew },
/* 0F 01 F1 */ { BxTraceEnd, BX_IA_LMSW_Ew },
/* 0F 01 F2 */ { BxTraceEnd, BX_IA_LMSW_Ew },
/* 0F 01 F3 */ { BxTraceEnd, BX_IA_LMSW_Ew },
/* 0F 01 F4 */ { BxTraceEnd, BX_IA_LMSW_Ew },
/* 0F 01 F5 */ { BxTraceEnd, BX_IA_LMSW_Ew },
/* 0F 01 F6 */ { BxTraceEnd, BX_IA_LMSW_Ew },
/* 0F 01 F7 */ { BxTraceEnd, BX_IA_LMSW_Ew },
/* 0F 01 F8 */ { 0, BX_IA_SWAPGS },
/* 0F 01 F9 */ { 0, BX_IA_RDTSCP },
/* 0F 01 FA */ { 0, BX_IA_ERROR },
/* 0F 01 FB */ { 0, BX_IA_ERROR },
/* 0F 01 FC */ { 0, BX_IA_ERROR },
/* 0F 01 FD */ { 0, BX_IA_ERROR },
/* 0F 01 FE */ { 0, BX_IA_ERROR },
/* 0F 01 FF */ { 0, BX_IA_ERROR }
};
#endif
/* ******* */
/* Group 8 */
/* ******* */
static const BxOpcodeInfo_t BxOpcodeInfoG8EwIb[8] = {
/* 0 */ { 0, BX_IA_ERROR },
/* 1 */ { 0, BX_IA_ERROR },
/* 2 */ { 0, BX_IA_ERROR },
/* 3 */ { 0, BX_IA_ERROR },
/* 4 */ { BxImmediate_Ib, BX_IA_BT_EwIb },
/* 5 */ { BxImmediate_Ib | BxLockable, BX_IA_BTS_EwIb },
/* 6 */ { BxImmediate_Ib | BxLockable, BX_IA_BTR_EwIb },
/* 7 */ { BxImmediate_Ib | BxLockable, BX_IA_BTC_EwIb }
};
static const BxOpcodeInfo_t BxOpcodeInfoG8EdIb[8] = {
/* 0 */ { 0, BX_IA_ERROR },
/* 1 */ { 0, BX_IA_ERROR },
/* 2 */ { 0, BX_IA_ERROR },
/* 3 */ { 0, BX_IA_ERROR },
/* 4 */ { BxImmediate_Ib, BX_IA_BT_EdIb },
/* 5 */ { BxImmediate_Ib | BxLockable, BX_IA_BTS_EdIb },
/* 6 */ { BxImmediate_Ib | BxLockable, BX_IA_BTR_EdIb },
/* 7 */ { BxImmediate_Ib | BxLockable, BX_IA_BTC_EdIb }
};
#if BX_SUPPORT_X86_64
static const BxOpcodeInfo_t BxOpcodeInfo64G8EqIb[8] = {
/* 0 */ { 0, BX_IA_ERROR },
/* 1 */ { 0, BX_IA_ERROR },
/* 2 */ { 0, BX_IA_ERROR },
/* 3 */ { 0, BX_IA_ERROR },
/* 4 */ { BxImmediate_Ib, BX_IA_BT_EqIb },
/* 5 */ { BxImmediate_Ib | BxLockable, BX_IA_BTS_EqIb },
/* 6 */ { BxImmediate_Ib | BxLockable, BX_IA_BTR_EqIb },
/* 7 */ { BxImmediate_Ib | BxLockable, BX_IA_BTC_EqIb }
};
#endif
/* ******* */
/* Group 9 */
/* ******* */
static const BxOpcodeInfo_t BxOpcodeInfoG9M[8] = {
/* 0 */ { 0, BX_IA_ERROR },
/* 1 */ { BxLockable, BX_IA_CMPXCHG8B },
/* 2 */ { 0, BX_IA_ERROR },
/* 3 */ { 0, BX_IA_ERROR },
/* 4 */ { 0, BX_IA_ERROR },
/* 5 */ { 0, BX_IA_ERROR },
/* 6 */ { BxPrefixSSE, BX_IA_VMPTRLD_Mq, BxOpcodeGroupSSE_G9VMX6 },
/* 7 */ { BxPrefixSSE, BX_IA_VMPTRST_Mq, BxOpcodeGroupSSE_ERR }
};
#if BX_SUPPORT_X86_64
static const BxOpcodeInfo_t BxOpcodeInfo64G9qM[8] = {
/* 0 */ { 0, BX_IA_ERROR },
/* 1 */ { BxLockable, BX_IA_CMPXCHG16B },
/* 2 */ { 0, BX_IA_ERROR },
/* 3 */ { 0, BX_IA_ERROR },
/* 4 */ { 0, BX_IA_ERROR },
/* 5 */ { 0, BX_IA_ERROR },
/* 6 */ { BxPrefixSSE, BX_IA_VMPTRLD_Mq, BxOpcodeGroupSSE_G9VMX6 },
/* 7 */ { BxPrefixSSE, BX_IA_VMPTRST_Mq, BxOpcodeGroupSSE_ERR }
};
#endif
/* ******** */
/* Group 11 */
/* ******** */
static const BxOpcodeInfo_t BxOpcodeInfoG11Eb[8] = {
/* 0 */ { BxImmediate_Ib, BX_IA_MOV_EbIb },
/* 1 */ { 0, BX_IA_ERROR },
/* 2 */ { 0, BX_IA_ERROR },
/* 3 */ { 0, BX_IA_ERROR },
/* 4 */ { 0, BX_IA_ERROR },
/* 5 */ { 0, BX_IA_ERROR },
/* 6 */ { 0, BX_IA_ERROR },
/* 7 */ { 0, BX_IA_ERROR }
};
static const BxOpcodeInfo_t BxOpcodeInfoG11Ew[8] = {
/* 0 */ { BxImmediate_Iw, BX_IA_MOV_EwIw },
/* 1 */ { 0, BX_IA_ERROR },
/* 2 */ { 0, BX_IA_ERROR },
/* 3 */ { 0, BX_IA_ERROR },
/* 4 */ { 0, BX_IA_ERROR },
/* 5 */ { 0, BX_IA_ERROR },
/* 6 */ { 0, BX_IA_ERROR },
/* 7 */ { 0, BX_IA_ERROR }
};
static const BxOpcodeInfo_t BxOpcodeInfoG11Ed[8] = {
/* 0 */ { BxImmediate_Id, BX_IA_MOV_EdId },
/* 1 */ { 0, BX_IA_ERROR },
/* 2 */ { 0, BX_IA_ERROR },
/* 3 */ { 0, BX_IA_ERROR },
/* 4 */ { 0, BX_IA_ERROR },
/* 5 */ { 0, BX_IA_ERROR },
/* 6 */ { 0, BX_IA_ERROR },
/* 7 */ { 0, BX_IA_ERROR }
};
#if BX_SUPPORT_X86_64
static const BxOpcodeInfo_t BxOpcodeInfo64G11Eq[8] = {
/* 0 */ { BxImmediate_Id, BX_IA_MOV_EqId },
/* 1 */ { 0, BX_IA_ERROR },
/* 2 */ { 0, BX_IA_ERROR },
/* 3 */ { 0, BX_IA_ERROR },
/* 4 */ { 0, BX_IA_ERROR },
/* 5 */ { 0, BX_IA_ERROR },
/* 6 */ { 0, BX_IA_ERROR },
/* 7 */ { 0, BX_IA_ERROR }
};
#endif
/* ******** */
/* Group 12 */
/* ******** */
static const BxOpcodeInfo_t BxOpcodeInfoG12R[8] = {
/* 0 */ { 0, BX_IA_ERROR },
/* 1 */ { 0, BX_IA_ERROR },
/* 2 */ { BxImmediate_Ib | BxPrefixSSE, BX_IA_PSRLW_PqIb, BxOpcodeGroupSSE_G1202 },
/* 3 */ { 0, BX_IA_ERROR },
/* 4 */ { BxImmediate_Ib | BxPrefixSSE, BX_IA_PSRAW_PqIb, BxOpcodeGroupSSE_G1204 },
/* 5 */ { 0, BX_IA_ERROR },
/* 6 */ { BxImmediate_Ib | BxPrefixSSE, BX_IA_PSLLW_PqIb, BxOpcodeGroupSSE_G1206 },
/* 7 */ { 0, BX_IA_ERROR }
};
/* ******** */
/* Group 13 */
/* ******** */
static const BxOpcodeInfo_t BxOpcodeInfoG13R[8] = {
/* 0 */ { 0, BX_IA_ERROR },
/* 1 */ { 0, BX_IA_ERROR },
/* 2 */ { BxImmediate_Ib | BxPrefixSSE, BX_IA_PSRLD_PqIb, BxOpcodeGroupSSE_G1302 },
/* 3 */ { 0, BX_IA_ERROR },
/* 4 */ { BxImmediate_Ib | BxPrefixSSE, BX_IA_PSRAD_PqIb, BxOpcodeGroupSSE_G1304 },
/* 5 */ { 0, BX_IA_ERROR },
/* 6 */ { BxImmediate_Ib | BxPrefixSSE, BX_IA_PSLLD_PqIb, BxOpcodeGroupSSE_G1306 },
/* 7 */ { 0, BX_IA_ERROR }
};
/* ******** */
/* Group 14 */
/* ******** */
static const BxOpcodeInfo_t BxOpcodeInfoG14R[8] = {
/* 0 */ { 0, BX_IA_ERROR },
/* 1 */ { 0, BX_IA_ERROR },
/* 2 */ { BxImmediate_Ib | BxPrefixSSE, BX_IA_PSRLQ_PqIb, BxOpcodeGroupSSE_G1402 },
/* 3 */ { BxImmediate_Ib | BxPrefixSSE66, BX_IA_PSRLDQ_UdqIb },
/* 4 */ { 0, BX_IA_ERROR },
/* 5 */ { 0, BX_IA_ERROR },
/* 6 */ { BxImmediate_Ib | BxPrefixSSE, BX_IA_PSLLQ_PqIb, BxOpcodeGroupSSE_G1406 },
/* 7 */ { BxImmediate_Ib | BxPrefixSSE66, BX_IA_PSLLDQ_UdqIb }
};
/* ******** */
/* Group 15 */
/* ******** */
static const BxOpcodeInfo_t BxOpcodeInfoG15[8*2] = {
/* /r form */
/* 0 */ { 0, BX_IA_ERROR },
/* 1 */ { 0, BX_IA_ERROR },
/* 2 */ { 0, BX_IA_ERROR },
/* 3 */ { 0, BX_IA_ERROR },
/* 4 */ { 0, BX_IA_ERROR },
/* 5 */ { BxPrefixSSE, BX_IA_LFENCE, BxOpcodeGroupSSE_ERR },
/* 6 */ { BxPrefixSSE, BX_IA_MFENCE, BxOpcodeGroupSSE_ERR },
/* 7 */ { BxPrefixSSE, BX_IA_SFENCE, BxOpcodeGroupSSE_ERR },
/* /m form */
/* 0 */ { BxPrefixSSE, BX_IA_FXSAVE, BxOpcodeGroupSSE_ERR },
/* 1 */ { BxPrefixSSE, BX_IA_FXRSTOR, BxOpcodeGroupSSE_ERR },
/* 2 */ { BxPrefixSSE, BX_IA_LDMXCSR, BxOpcodeGroupSSE_ERR },
/* 3 */ { BxPrefixSSE, BX_IA_STMXCSR, BxOpcodeGroupSSE_ERR },
/* 4 */ { BxPrefixSSE, BX_IA_XSAVE, BxOpcodeGroupSSE_ERR },
/* 5 */ { BxPrefixSSE, BX_IA_XRSTOR, BxOpcodeGroupSSE_ERR },
/* 6 */ { 0, BX_IA_ERROR },
/* 7 */ { BxPrefixSSE, BX_IA_CLFLUSH, BxOpcodeGroupSSE_ERR }
};
#if BX_SUPPORT_X86_64
static const BxOpcodeInfo_t BxOpcodeInfoG15q[8*2] = {
/* /r form */
/* 0 */ { BxPrefixSSEF3, BX_IA_RDFSBASE },
/* 1 */ { BxPrefixSSEF3, BX_IA_RDGSBASE },
/* 2 */ { BxPrefixSSEF3, BX_IA_WRFSBASE },
/* 3 */ { BxPrefixSSEF3, BX_IA_WRGSBASE },
/* 4 */ { 0, BX_IA_ERROR },
/* 5 */ { BxPrefixSSE, BX_IA_LFENCE, BxOpcodeGroupSSE_ERR },
/* 6 */ { BxPrefixSSE, BX_IA_MFENCE, BxOpcodeGroupSSE_ERR },
/* 7 */ { BxPrefixSSE, BX_IA_SFENCE, BxOpcodeGroupSSE_ERR },
/* /m form */
/* 0 */ { BxPrefixSSE, BX_IA_FXSAVE, BxOpcodeGroupSSE_ERR },
/* 1 */ { BxPrefixSSE, BX_IA_FXRSTOR, BxOpcodeGroupSSE_ERR },
/* 2 */ { BxPrefixSSE, BX_IA_LDMXCSR, BxOpcodeGroupSSE_ERR },
/* 3 */ { BxPrefixSSE, BX_IA_STMXCSR, BxOpcodeGroupSSE_ERR },
/* 4 */ { BxPrefixSSE, BX_IA_XSAVE, BxOpcodeGroupSSE_ERR },
/* 5 */ { BxPrefixSSE, BX_IA_XRSTOR, BxOpcodeGroupSSE_ERR },
/* 6 */ { 0, BX_IA_ERROR },
/* 7 */ { BxPrefixSSE, BX_IA_CLFLUSH, BxOpcodeGroupSSE_ERR }
};
#endif
static const BxOpcodeInfo_t BxOpcodeInfoMOV_RdCd[8] = {
/* 0 */ { 0, BX_IA_MOV_RdCR0 },
/* 1 */ { 0, BX_IA_ERROR },
/* 2 */ { 0, BX_IA_MOV_RdCR2 },
/* 3 */ { 0, BX_IA_MOV_RdCR3 },
/* 4 */ { 0, BX_IA_MOV_RdCR4 },
/* 5 */ { 0, BX_IA_ERROR },
/* 6 */ { 0, BX_IA_ERROR },
/* 7 */ { 0, BX_IA_ERROR }
};
static const BxOpcodeInfo_t BxOpcodeInfoMOV_CdRd[8] = {
/* 0 */ { BxTraceEnd, BX_IA_MOV_CR0Rd },
/* 1 */ { 0, BX_IA_ERROR },
/* 2 */ { 0, BX_IA_MOV_CR2Rd },
/* 3 */ { BxTraceEnd, BX_IA_MOV_CR3Rd },
/* 4 */ { BxTraceEnd, BX_IA_MOV_CR4Rd },
/* 5 */ { 0, BX_IA_ERROR },
/* 6 */ { 0, BX_IA_ERROR },
/* 7 */ { 0, BX_IA_ERROR }
};
#if BX_SUPPORT_X86_64
static const BxOpcodeInfo_t BxOpcodeInfoMOV_RqCq[8] = {
/* 0 */ { 0, BX_IA_MOV_RqCR0 },
/* 1 */ { 0, BX_IA_ERROR },
/* 2 */ { 0, BX_IA_MOV_RqCR2 },
/* 3 */ { 0, BX_IA_MOV_RqCR3 },
/* 4 */ { 0, BX_IA_MOV_RqCR4 },
/* 5 */ { 0, BX_IA_ERROR },
/* 6 */ { 0, BX_IA_ERROR },
/* 7 */ { 0, BX_IA_ERROR }
};
static const BxOpcodeInfo_t BxOpcodeInfoMOV_CqRq[8] = {
/* 0 */ { BxTraceEnd, BX_IA_MOV_CR0Rq },
/* 1 */ { 0, BX_IA_ERROR },
/* 2 */ { 0, BX_IA_MOV_CR2Rq },
/* 3 */ { BxTraceEnd, BX_IA_MOV_CR3Rq },
/* 4 */ { BxTraceEnd, BX_IA_MOV_CR4Rq },
/* 5 */ { 0, BX_IA_ERROR },
/* 6 */ { 0, BX_IA_ERROR },
/* 7 */ { 0, BX_IA_ERROR }
};
#endif
#endif // BX_COMMON_FETCHDECODE_TABLES_H

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,768 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2005-2010 Stanislav Shwartsman
// 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
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA B 02110-1301 USA
//
/////////////////////////////////////////////////////////////////////////
#ifndef BX_X87_FETCHDECODE_TABLES_H
#define BX_X87_FETCHDECODE_TABLES_H
//
// Common FetchDecode Opcode Tables - x87 and 3dnow!
//
#if BX_SUPPORT_FPU
/* ************************************************************************ */
/* FPU Opcodes */
// D8 (modrm is outside 00h - BFh)
static const BxOpcodeInfo_t BxOpcodeInfo_FPGroupD8[8*2] = {
/* /r form */
/* 0 */ { 0, BX_IA_FADD_ST0_STj },
/* 1 */ { 0, BX_IA_FMUL_ST0_STj },
/* 2 */ { 0, BX_IA_FCOM_STi },
/* 3 */ { 0, BX_IA_FCOMP_STi },
/* 4 */ { 0, BX_IA_FSUB_ST0_STj },
/* 5 */ { 0, BX_IA_FSUBR_ST0_STj },
/* 6 */ { 0, BX_IA_FDIV_ST0_STj },
/* 7 */ { 0, BX_IA_FDIVR_ST0_STj },
/* /m form */
/* 0 */ { 0, BX_IA_FADD_SINGLE_REAL },
/* 1 */ { 0, BX_IA_FMUL_SINGLE_REAL },
/* 2 */ { 0, BX_IA_FCOM_SINGLE_REAL },
/* 3 */ { 0, BX_IA_FCOMP_SINGLE_REAL },
/* 4 */ { 0, BX_IA_FSUB_SINGLE_REAL },
/* 5 */ { 0, BX_IA_FSUBR_SINGLE_REAL },
/* 6 */ { 0, BX_IA_FDIV_SINGLE_REAL },
/* 7 */ { 0, BX_IA_FDIVR_SINGLE_REAL }
};
// D9 (modrm is outside 00h - BFh)
static const BxOpcodeInfo_t BxOpcodeInfo_FloatingPointD9[64+8] = {
/* /m form */
/* 0 */ { 0, BX_IA_FLD_SINGLE_REAL },
/* 1 */ { 0, BX_IA_ERROR },
/* 2 */ { 0, BX_IA_FST_SINGLE_REAL },
/* 3 */ { 0, BX_IA_FSTP_SINGLE_REAL },
/* 4 */ { 0, BX_IA_FLDENV },
/* 5 */ { 0, BX_IA_FLDCW },
/* 6 */ { 0, BX_IA_FNSTENV },
/* 7 */ { 0, BX_IA_FNSTCW },
/* /r form */
/* D9 C0 */ { 0, BX_IA_FLD_STi },
/* D9 C1 */ { 0, BX_IA_FLD_STi },
/* D9 C2 */ { 0, BX_IA_FLD_STi },
/* D9 C3 */ { 0, BX_IA_FLD_STi },
/* D9 C4 */ { 0, BX_IA_FLD_STi },
/* D9 C5 */ { 0, BX_IA_FLD_STi },
/* D9 C6 */ { 0, BX_IA_FLD_STi },
/* D9 C7 */ { 0, BX_IA_FLD_STi },
/* D9 C8 */ { 0, BX_IA_FXCH_STi },
/* D9 C9 */ { 0, BX_IA_FXCH_STi },
/* D9 CA */ { 0, BX_IA_FXCH_STi },
/* D9 CB */ { 0, BX_IA_FXCH_STi },
/* D9 CC */ { 0, BX_IA_FXCH_STi },
/* D9 CD */ { 0, BX_IA_FXCH_STi },
/* D9 CE */ { 0, BX_IA_FXCH_STi },
/* D9 CF */ { 0, BX_IA_FXCH_STi },
/* D9 D0 */ { 0, BX_IA_FNOP },
/* D9 D1 */ { 0, BX_IA_ERROR },
/* D9 D2 */ { 0, BX_IA_ERROR },
/* D9 D3 */ { 0, BX_IA_ERROR },
/* D9 D4 */ { 0, BX_IA_ERROR },
/* D9 D5 */ { 0, BX_IA_ERROR },
/* D9 D6 */ { 0, BX_IA_ERROR },
/* D9 D7 */ { 0, BX_IA_ERROR },
/* D9 D8 */ { 0, BX_IA_FSTP_STi }, // undocumented
/* D9 D9 */ { 0, BX_IA_FSTP_STi }, // undocumented
/* D9 DA */ { 0, BX_IA_FSTP_STi }, // undocumented
/* D9 DB */ { 0, BX_IA_FSTP_STi }, // undocumented
/* D9 DC */ { 0, BX_IA_FSTP_STi }, // undocumented
/* D9 DD */ { 0, BX_IA_FSTP_STi }, // undocumented
/* D9 DE */ { 0, BX_IA_FSTP_STi }, // undocumented
/* D9 DF */ { 0, BX_IA_FSTP_STi }, // undocumented
/* D9 E0 */ { 0, BX_IA_FCHS },
/* D9 E1 */ { 0, BX_IA_FABS },
/* D9 E2 */ { 0, BX_IA_ERROR },
/* D9 E3 */ { 0, BX_IA_ERROR },
/* D9 E4 */ { 0, BX_IA_FTST },
/* D9 E5 */ { 0, BX_IA_FXAM },
/* D9 E6 */ { 0, BX_IA_ERROR },
/* D9 E7 */ { 0, BX_IA_ERROR },
/* D9 E8 */ { 0, BX_IA_FLD1 },
/* D9 E9 */ { 0, BX_IA_FLDL2T },
/* D9 EA */ { 0, BX_IA_FLDL2E },
/* D9 EB */ { 0, BX_IA_FLDPI },
/* D9 EC */ { 0, BX_IA_FLDLG2 },
/* D9 ED */ { 0, BX_IA_FLDLN2 },
/* D9 EE */ { 0, BX_IA_FLDZ },
/* D9 EF */ { 0, BX_IA_ERROR },
/* D9 F0 */ { 0, BX_IA_F2XM1 },
/* D9 F1 */ { 0, BX_IA_FYL2X },
/* D9 F2 */ { 0, BX_IA_FPTAN },
/* D9 F3 */ { 0, BX_IA_FPATAN },
/* D9 F4 */ { 0, BX_IA_FXTRACT },
/* D9 F5 */ { 0, BX_IA_FPREM1 },
/* D9 F6 */ { 0, BX_IA_FDECSTP },
/* D9 F7 */ { 0, BX_IA_FINCSTP },
/* D9 F8 */ { 0, BX_IA_FPREM },
/* D9 F9 */ { 0, BX_IA_FYL2XP1 },
/* D9 FA */ { 0, BX_IA_FSQRT },
/* D9 FB */ { 0, BX_IA_FSINCOS },
/* D9 FC */ { 0, BX_IA_FRNDINT },
/* D9 FD */ { 0, BX_IA_FSCALE },
/* D9 FE */ { 0, BX_IA_FSIN },
/* D9 FF */ { 0, BX_IA_FCOS }
};
// DA (modrm is outside 00h - BFh)
static const BxOpcodeInfo_t BxOpcodeInfo_FloatingPointDA[64+8] = {
/* /m form */
/* 0 */ { 0, BX_IA_FIADD_DWORD_INTEGER },
/* 1 */ { 0, BX_IA_FIMUL_DWORD_INTEGER },
/* 2 */ { 0, BX_IA_FICOM_DWORD_INTEGER },
/* 3 */ { 0, BX_IA_FICOMP_DWORD_INTEGER },
/* 4 */ { 0, BX_IA_FISUB_DWORD_INTEGER },
/* 5 */ { 0, BX_IA_FISUBR_DWORD_INTEGER },
/* 6 */ { 0, BX_IA_FIDIV_DWORD_INTEGER },
/* 7 */ { 0, BX_IA_FIDIVR_DWORD_INTEGER },
/* /r form */
/* DA C0 */ { 0, BX_IA_FCMOV_ST0_STj },
/* DA C1 */ { 0, BX_IA_FCMOV_ST0_STj },
/* DA C2 */ { 0, BX_IA_FCMOV_ST0_STj },
/* DA C3 */ { 0, BX_IA_FCMOV_ST0_STj },
/* DA C4 */ { 0, BX_IA_FCMOV_ST0_STj },
/* DA C5 */ { 0, BX_IA_FCMOV_ST0_STj },
/* DA C6 */ { 0, BX_IA_FCMOV_ST0_STj },
/* DA C7 */ { 0, BX_IA_FCMOV_ST0_STj },
/* DA C8 */ { 0, BX_IA_FCMOV_ST0_STj },
/* DA C9 */ { 0, BX_IA_FCMOV_ST0_STj },
/* DA CA */ { 0, BX_IA_FCMOV_ST0_STj },
/* DA CB */ { 0, BX_IA_FCMOV_ST0_STj },
/* DA CC */ { 0, BX_IA_FCMOV_ST0_STj },
/* DA CD */ { 0, BX_IA_FCMOV_ST0_STj },
/* DA CE */ { 0, BX_IA_FCMOV_ST0_STj },
/* DA CF */ { 0, BX_IA_FCMOV_ST0_STj },
/* DA D0 */ { 0, BX_IA_FCMOV_ST0_STj },
/* DA D1 */ { 0, BX_IA_FCMOV_ST0_STj },
/* DA D2 */ { 0, BX_IA_FCMOV_ST0_STj },
/* DA D3 */ { 0, BX_IA_FCMOV_ST0_STj },
/* DA D4 */ { 0, BX_IA_FCMOV_ST0_STj },
/* DA D5 */ { 0, BX_IA_FCMOV_ST0_STj },
/* DA D6 */ { 0, BX_IA_FCMOV_ST0_STj },
/* DA D7 */ { 0, BX_IA_FCMOV_ST0_STj },
/* DA D8 */ { 0, BX_IA_FCMOV_ST0_STj },
/* DA D9 */ { 0, BX_IA_FCMOV_ST0_STj },
/* DA DA */ { 0, BX_IA_FCMOV_ST0_STj },
/* DA DB */ { 0, BX_IA_FCMOV_ST0_STj },
/* DA DC */ { 0, BX_IA_FCMOV_ST0_STj },
/* DA DD */ { 0, BX_IA_FCMOV_ST0_STj },
/* DA DE */ { 0, BX_IA_FCMOV_ST0_STj },
/* DA DF */ { 0, BX_IA_FCMOV_ST0_STj },
/* DA E0 */ { 0, BX_IA_ERROR },
/* DA E1 */ { 0, BX_IA_ERROR },
/* DA E2 */ { 0, BX_IA_ERROR },
/* DA E3 */ { 0, BX_IA_ERROR },
/* DA E4 */ { 0, BX_IA_ERROR },
/* DA E5 */ { 0, BX_IA_ERROR },
/* DA E6 */ { 0, BX_IA_ERROR },
/* DA E7 */ { 0, BX_IA_ERROR },
/* DA E8 */ { 0, BX_IA_ERROR },
/* DA E9 */ { 0, BX_IA_FUCOMPP },
/* DA EA */ { 0, BX_IA_ERROR },
/* DA EB */ { 0, BX_IA_ERROR },
/* DA EC */ { 0, BX_IA_ERROR },
/* DA ED */ { 0, BX_IA_ERROR },
/* DA EE */ { 0, BX_IA_ERROR },
/* DA EF */ { 0, BX_IA_ERROR },
/* DA F0 */ { 0, BX_IA_ERROR },
/* DA F1 */ { 0, BX_IA_ERROR },
/* DA F2 */ { 0, BX_IA_ERROR },
/* DA F3 */ { 0, BX_IA_ERROR },
/* DA F4 */ { 0, BX_IA_ERROR },
/* DA F5 */ { 0, BX_IA_ERROR },
/* DA F6 */ { 0, BX_IA_ERROR },
/* DA F7 */ { 0, BX_IA_ERROR },
/* DA F8 */ { 0, BX_IA_ERROR },
/* DA F9 */ { 0, BX_IA_ERROR },
/* DA FA */ { 0, BX_IA_ERROR },
/* DA FB */ { 0, BX_IA_ERROR },
/* DA FC */ { 0, BX_IA_ERROR },
/* DA FD */ { 0, BX_IA_ERROR },
/* DA FE */ { 0, BX_IA_ERROR },
/* DA FF */ { 0, BX_IA_ERROR }
};
// DB (modrm is outside 00h - BFh)
static const BxOpcodeInfo_t BxOpcodeInfo_FloatingPointDB[64+8] = {
/* /m form */
/* 0 */ { 0, BX_IA_FILD_DWORD_INTEGER },
/* 1 */ { 0, BX_IA_FISTTP32 },
/* 2 */ { 0, BX_IA_FIST_DWORD_INTEGER },
/* 3 */ { 0, BX_IA_FISTP_DWORD_INTEGER },
/* 4 */ { 0, BX_IA_ERROR },
/* 5 */ { 0, BX_IA_FLD_EXTENDED_REAL },
/* 6 */ { 0, BX_IA_ERROR },
/* 7 */ { 0, BX_IA_FSTP_EXTENDED_REAL },
/* /r form */
/* DB C0 */ { 0, BX_IA_FCMOV_ST0_STj },
/* DB C1 */ { 0, BX_IA_FCMOV_ST0_STj },
/* DB C2 */ { 0, BX_IA_FCMOV_ST0_STj },
/* DB C3 */ { 0, BX_IA_FCMOV_ST0_STj },
/* DB C4 */ { 0, BX_IA_FCMOV_ST0_STj },
/* DB C5 */ { 0, BX_IA_FCMOV_ST0_STj },
/* DB C6 */ { 0, BX_IA_FCMOV_ST0_STj },
/* DB C7 */ { 0, BX_IA_FCMOV_ST0_STj },
/* DB C8 */ { 0, BX_IA_FCMOV_ST0_STj },
/* DB C9 */ { 0, BX_IA_FCMOV_ST0_STj },
/* DB CA */ { 0, BX_IA_FCMOV_ST0_STj },
/* DB CB */ { 0, BX_IA_FCMOV_ST0_STj },
/* DB CC */ { 0, BX_IA_FCMOV_ST0_STj },
/* DB CD */ { 0, BX_IA_FCMOV_ST0_STj },
/* DB CE */ { 0, BX_IA_FCMOV_ST0_STj },
/* DB CF */ { 0, BX_IA_FCMOV_ST0_STj },
/* DB D0 */ { 0, BX_IA_FCMOV_ST0_STj },
/* DB D1 */ { 0, BX_IA_FCMOV_ST0_STj },
/* DB D2 */ { 0, BX_IA_FCMOV_ST0_STj },
/* DB D3 */ { 0, BX_IA_FCMOV_ST0_STj },
/* DB D4 */ { 0, BX_IA_FCMOV_ST0_STj },
/* DB D5 */ { 0, BX_IA_FCMOV_ST0_STj },
/* DB D6 */ { 0, BX_IA_FCMOV_ST0_STj },
/* DB D7 */ { 0, BX_IA_FCMOV_ST0_STj },
/* DB D8 */ { 0, BX_IA_FCMOV_ST0_STj },
/* DB D9 */ { 0, BX_IA_FCMOV_ST0_STj },
/* DB DA */ { 0, BX_IA_FCMOV_ST0_STj },
/* DB DB */ { 0, BX_IA_FCMOV_ST0_STj },
/* DB DC */ { 0, BX_IA_FCMOV_ST0_STj },
/* DB DD */ { 0, BX_IA_FCMOV_ST0_STj },
/* DB DE */ { 0, BX_IA_FCMOV_ST0_STj },
/* DB DF */ { 0, BX_IA_FCMOV_ST0_STj },
/* DB E0 */ { 0, BX_IA_FPLEGACY }, // feni (287 only)
/* DB E1 */ { 0, BX_IA_FPLEGACY }, // fdisi (287 only)
/* DB E2 */ { 0, BX_IA_FNCLEX },
/* DB E3 */ { 0, BX_IA_FNINIT },
/* DB E4 */ { 0, BX_IA_FPLEGACY }, // fsetpm (287 only)
/* DB E5 */ { 0, BX_IA_ERROR },
/* DB E6 */ { 0, BX_IA_ERROR },
/* DB E7 */ { 0, BX_IA_ERROR },
/* DB E8 */ { 0, BX_IA_FUCOMI_ST0_STj },
/* DB E9 */ { 0, BX_IA_FUCOMI_ST0_STj },
/* DB EA */ { 0, BX_IA_FUCOMI_ST0_STj },
/* DB EB */ { 0, BX_IA_FUCOMI_ST0_STj },
/* DB EC */ { 0, BX_IA_FUCOMI_ST0_STj },
/* DB ED */ { 0, BX_IA_FUCOMI_ST0_STj },
/* DB EE */ { 0, BX_IA_FUCOMI_ST0_STj },
/* DB EF */ { 0, BX_IA_FUCOMI_ST0_STj },
/* DB F0 */ { 0, BX_IA_FCOMI_ST0_STj },
/* DB F1 */ { 0, BX_IA_FCOMI_ST0_STj },
/* DB F2 */ { 0, BX_IA_FCOMI_ST0_STj },
/* DB F3 */ { 0, BX_IA_FCOMI_ST0_STj },
/* DB F4 */ { 0, BX_IA_FCOMI_ST0_STj },
/* DB F5 */ { 0, BX_IA_FCOMI_ST0_STj },
/* DB F6 */ { 0, BX_IA_FCOMI_ST0_STj },
/* DB F7 */ { 0, BX_IA_FCOMI_ST0_STj },
/* DB F8 */ { 0, BX_IA_ERROR },
/* DB F9 */ { 0, BX_IA_ERROR },
/* DB FA */ { 0, BX_IA_ERROR },
/* DB FB */ { 0, BX_IA_ERROR },
/* DB FC */ { 0, BX_IA_ERROR },
/* DB FD */ { 0, BX_IA_ERROR },
/* DB FE */ { 0, BX_IA_ERROR },
/* DB FF */ { 0, BX_IA_ERROR }
};
// DC (modrm is outside 00h - BFh)
static const BxOpcodeInfo_t BxOpcodeInfo_FPGroupDC[8*2] = {
/* /r form */
/* 0 */ { 0, BX_IA_FADD_STi_ST0 },
/* 1 */ { 0, BX_IA_FMUL_STi_ST0 },
/* 2 */ { 0, BX_IA_FCOM_STi }, // undocumented
/* 3 */ { 0, BX_IA_FCOMP_STi }, // undocumented
/* 4 */ { 0, BX_IA_FSUBR_STi_ST0 },
/* 5 */ { 0, BX_IA_FSUB_STi_ST0 },
/* 6 */ { 0, BX_IA_FDIVR_STi_ST0 },
/* 7 */ { 0, BX_IA_FDIV_STi_ST0 },
/* /m form */
/* 0 */ { 0, BX_IA_FADD_DOUBLE_REAL },
/* 1 */ { 0, BX_IA_FMUL_DOUBLE_REAL },
/* 2 */ { 0, BX_IA_FCOM_DOUBLE_REAL },
/* 3 */ { 0, BX_IA_FCOMP_DOUBLE_REAL },
/* 4 */ { 0, BX_IA_FSUB_DOUBLE_REAL },
/* 5 */ { 0, BX_IA_FSUBR_DOUBLE_REAL },
/* 6 */ { 0, BX_IA_FDIV_DOUBLE_REAL },
/* 7 */ { 0, BX_IA_FDIVR_DOUBLE_REAL }
};
// DD (modrm is outside 00h - BFh)
static const BxOpcodeInfo_t BxOpcodeInfo_FPGroupDD[8*2] = {
/* /r form */
/* 0 */ { 0, BX_IA_FFREE_STi },
/* 1 */ { 0, BX_IA_FXCH_STi }, // undocumented
/* 2 */ { 0, BX_IA_FST_STi },
/* 3 */ { 0, BX_IA_FSTP_STi },
/* 4 */ { 0, BX_IA_FUCOM_STi },
/* 5 */ { 0, BX_IA_FUCOMP_STi },
/* 6 */ { 0, BX_IA_ERROR },
/* 7 */ { 0, BX_IA_ERROR },
/* /m form */
/* 0 */ { 0, BX_IA_FLD_DOUBLE_REAL },
/* 1 */ { 0, BX_IA_FISTTP64 },
/* 2 */ { 0, BX_IA_FST_DOUBLE_REAL },
/* 3 */ { 0, BX_IA_FSTP_DOUBLE_REAL },
/* 4 */ { 0, BX_IA_FRSTOR },
/* 5 */ { 0, BX_IA_ERROR },
/* 6 */ { 0, BX_IA_FNSAVE },
/* 7 */ { 0, BX_IA_FNSTSW }
};
// DE (modrm is outside 00h - BFh)
static const BxOpcodeInfo_t BxOpcodeInfo_FloatingPointDE[64+8] = {
/* /m form */
/* 0 */ { 0, BX_IA_FIADD_WORD_INTEGER },
/* 1 */ { 0, BX_IA_FIMUL_WORD_INTEGER },
/* 2 */ { 0, BX_IA_FICOM_WORD_INTEGER },
/* 3 */ { 0, BX_IA_FICOMP_WORD_INTEGER },
/* 4 */ { 0, BX_IA_FISUB_WORD_INTEGER },
/* 5 */ { 0, BX_IA_FISUBR_WORD_INTEGER },
/* 6 */ { 0, BX_IA_FIDIV_WORD_INTEGER },
/* 7 */ { 0, BX_IA_FIDIVR_WORD_INTEGER },
/* /r form */ // all instructions pop FPU stack
/* DE C0 */ { 0, BX_IA_FADD_STi_ST0 },
/* DE C1 */ { 0, BX_IA_FADD_STi_ST0 },
/* DE C2 */ { 0, BX_IA_FADD_STi_ST0 },
/* DE C3 */ { 0, BX_IA_FADD_STi_ST0 },
/* DE C4 */ { 0, BX_IA_FADD_STi_ST0 },
/* DE C5 */ { 0, BX_IA_FADD_STi_ST0 },
/* DE C6 */ { 0, BX_IA_FADD_STi_ST0 },
/* DE C7 */ { 0, BX_IA_FADD_STi_ST0 },
/* DE C8 */ { 0, BX_IA_FMUL_STi_ST0 },
/* DE C9 */ { 0, BX_IA_FMUL_STi_ST0 },
/* DE CA */ { 0, BX_IA_FMUL_STi_ST0 },
/* DE CB */ { 0, BX_IA_FMUL_STi_ST0 },
/* DE CC */ { 0, BX_IA_FMUL_STi_ST0 },
/* DE CD */ { 0, BX_IA_FMUL_STi_ST0 },
/* DE CE */ { 0, BX_IA_FMUL_STi_ST0 },
/* DE CF */ { 0, BX_IA_FMUL_STi_ST0 },
/* DE D0 */ { 0, BX_IA_FCOMP_STi }, // undocumented, special FPSTACK pop case
/* DE D1 */ { 0, BX_IA_FCOMP_STi }, // undocumented, special FPSTACK pop case
/* DE D2 */ { 0, BX_IA_FCOMP_STi }, // undocumented, special FPSTACK pop case
/* DE D3 */ { 0, BX_IA_FCOMP_STi }, // undocumented, special FPSTACK pop case
/* DE D4 */ { 0, BX_IA_FCOMP_STi }, // undocumented, special FPSTACK pop case
/* DE D5 */ { 0, BX_IA_FCOMP_STi }, // undocumented, special FPSTACK pop case
/* DE D6 */ { 0, BX_IA_FCOMP_STi }, // undocumented, special FPSTACK pop case
/* DE D7 */ { 0, BX_IA_FCOMP_STi }, // undocumented, special FPSTACK pop case
/* DE D8 */ { 0, BX_IA_ERROR },
/* DE D9 */ { 0, BX_IA_FCOMPP },
/* DE DA */ { 0, BX_IA_ERROR },
/* DE DB */ { 0, BX_IA_ERROR },
/* DE DC */ { 0, BX_IA_ERROR },
/* DE DD */ { 0, BX_IA_ERROR },
/* DE DE */ { 0, BX_IA_ERROR },
/* DE DF */ { 0, BX_IA_ERROR },
/* DE E0 */ { 0, BX_IA_FSUBR_STi_ST0 },
/* DE E1 */ { 0, BX_IA_FSUBR_STi_ST0 },
/* DE E2 */ { 0, BX_IA_FSUBR_STi_ST0 },
/* DE E3 */ { 0, BX_IA_FSUBR_STi_ST0 },
/* DE E4 */ { 0, BX_IA_FSUBR_STi_ST0 },
/* DE E5 */ { 0, BX_IA_FSUBR_STi_ST0 },
/* DE E6 */ { 0, BX_IA_FSUBR_STi_ST0 },
/* DE E7 */ { 0, BX_IA_FSUBR_STi_ST0 },
/* DE E8 */ { 0, BX_IA_FSUB_STi_ST0 },
/* DE E9 */ { 0, BX_IA_FSUB_STi_ST0 },
/* DE EA */ { 0, BX_IA_FSUB_STi_ST0 },
/* DE EB */ { 0, BX_IA_FSUB_STi_ST0 },
/* DE EC */ { 0, BX_IA_FSUB_STi_ST0 },
/* DE ED */ { 0, BX_IA_FSUB_STi_ST0 },
/* DE EE */ { 0, BX_IA_FSUB_STi_ST0 },
/* DE EF */ { 0, BX_IA_FSUB_STi_ST0 },
/* DE F0 */ { 0, BX_IA_FDIVR_STi_ST0 },
/* DE F1 */ { 0, BX_IA_FDIVR_STi_ST0 },
/* DE F2 */ { 0, BX_IA_FDIVR_STi_ST0 },
/* DE F3 */ { 0, BX_IA_FDIVR_STi_ST0 },
/* DE F4 */ { 0, BX_IA_FDIVR_STi_ST0 },
/* DE F5 */ { 0, BX_IA_FDIVR_STi_ST0 },
/* DE F6 */ { 0, BX_IA_FDIVR_STi_ST0 },
/* DE F7 */ { 0, BX_IA_FDIVR_STi_ST0 },
/* DE F8 */ { 0, BX_IA_FDIV_STi_ST0 },
/* DE F9 */ { 0, BX_IA_FDIV_STi_ST0 },
/* DE FA */ { 0, BX_IA_FDIV_STi_ST0 },
/* DE FB */ { 0, BX_IA_FDIV_STi_ST0 },
/* DE FC */ { 0, BX_IA_FDIV_STi_ST0 },
/* DE FD */ { 0, BX_IA_FDIV_STi_ST0 },
/* DE FE */ { 0, BX_IA_FDIV_STi_ST0 },
/* DE FF */ { 0, BX_IA_FDIV_STi_ST0 }
};
// DF (modrm is outside 00h - BFh)
static const BxOpcodeInfo_t BxOpcodeInfo_FloatingPointDF[64+8] = {
/* /m form */
/* 0 */ { 0, BX_IA_FILD_WORD_INTEGER },
/* 1 */ { 0, BX_IA_FISTTP16 },
/* 2 */ { 0, BX_IA_FIST_WORD_INTEGER },
/* 3 */ { 0, BX_IA_FISTP_WORD_INTEGER },
/* 4 */ { 0, BX_IA_FBLD_PACKED_BCD },
/* 5 */ { 0, BX_IA_FILD_QWORD_INTEGER },
/* 6 */ { 0, BX_IA_FBSTP_PACKED_BCD },
/* 7 */ { 0, BX_IA_FISTP_QWORD_INTEGER },
/* /r form */
/* DF C0 */ { 0, BX_IA_FFREEP_STi }, // 287+ compatibility opcode
/* DF C1 */ { 0, BX_IA_FFREEP_STi },
/* DF C2 */ { 0, BX_IA_FFREEP_STi },
/* DF C3 */ { 0, BX_IA_FFREEP_STi },
/* DF C4 */ { 0, BX_IA_FFREEP_STi },
/* DF C5 */ { 0, BX_IA_FFREEP_STi },
/* DF C6 */ { 0, BX_IA_FFREEP_STi },
/* DF C7 */ { 0, BX_IA_FFREEP_STi },
/* DF C8 */ { 0, BX_IA_FXCH_STi }, // undocumented
/* DF C9 */ { 0, BX_IA_FXCH_STi }, // undocumented
/* DF CA */ { 0, BX_IA_FXCH_STi }, // undocumented
/* DF CB */ { 0, BX_IA_FXCH_STi }, // undocumented
/* DF CC */ { 0, BX_IA_FXCH_STi }, // undocumented
/* DF CD */ { 0, BX_IA_FXCH_STi }, // undocumented
/* DF CE */ { 0, BX_IA_FXCH_STi }, // undocumented
/* DF CF */ { 0, BX_IA_FXCH_STi }, // undocumented
/* DF D0 */ { 0, BX_IA_FSTP_STi }, // undocumented, special FPSTACK pop case
/* DF D1 */ { 0, BX_IA_FSTP_STi }, // undocumented, special FPSTACK pop case
/* DF D2 */ { 0, BX_IA_FSTP_STi }, // undocumented, special FPSTACK pop case
/* DF D3 */ { 0, BX_IA_FSTP_STi }, // undocumented, special FPSTACK pop case
/* DF D4 */ { 0, BX_IA_FSTP_STi }, // undocumented, special FPSTACK pop case
/* DF D5 */ { 0, BX_IA_FSTP_STi }, // undocumented, special FPSTACK pop case
/* DF D6 */ { 0, BX_IA_FSTP_STi }, // undocumented, special FPSTACK pop case
/* DF D7 */ { 0, BX_IA_FSTP_STi }, // undocumented, special FPSTACK pop case
/* DF D8 */ { 0, BX_IA_FSTP_STi }, // undocumented
/* DF D9 */ { 0, BX_IA_FSTP_STi }, // undocumented
/* DF DA */ { 0, BX_IA_FSTP_STi }, // undocumented
/* DF DB */ { 0, BX_IA_FSTP_STi }, // undocumented
/* DF DC */ { 0, BX_IA_FSTP_STi }, // undocumented
/* DF DD */ { 0, BX_IA_FSTP_STi }, // undocumented
/* DF DE */ { 0, BX_IA_FSTP_STi }, // undocumented
/* DF DF */ { 0, BX_IA_FSTP_STi }, // undocumented
/* DF E0 */ { 0, BX_IA_FNSTSW_AX },
/* DF E1 */ { 0, BX_IA_ERROR },
/* DF E2 */ { 0, BX_IA_ERROR },
/* DF E3 */ { 0, BX_IA_ERROR },
/* DF E4 */ { 0, BX_IA_ERROR },
/* DF E5 */ { 0, BX_IA_ERROR },
/* DF E6 */ { 0, BX_IA_ERROR },
/* DF E7 */ { 0, BX_IA_ERROR },
/* DF E8 */ { 0, BX_IA_FUCOMIP_ST0_STj },
/* DF E9 */ { 0, BX_IA_FUCOMIP_ST0_STj },
/* DF EA */ { 0, BX_IA_FUCOMIP_ST0_STj },
/* DF EB */ { 0, BX_IA_FUCOMIP_ST0_STj },
/* DF EC */ { 0, BX_IA_FUCOMIP_ST0_STj },
/* DF ED */ { 0, BX_IA_FUCOMIP_ST0_STj },
/* DF EE */ { 0, BX_IA_FUCOMIP_ST0_STj },
/* DF EF */ { 0, BX_IA_FUCOMIP_ST0_STj },
/* DF F0 */ { 0, BX_IA_FCOMIP_ST0_STj },
/* DF F1 */ { 0, BX_IA_FCOMIP_ST0_STj },
/* DF F2 */ { 0, BX_IA_FCOMIP_ST0_STj },
/* DF F3 */ { 0, BX_IA_FCOMIP_ST0_STj },
/* DF F4 */ { 0, BX_IA_FCOMIP_ST0_STj },
/* DF F5 */ { 0, BX_IA_FCOMIP_ST0_STj },
/* DF F6 */ { 0, BX_IA_FCOMIP_ST0_STj },
/* DF F7 */ { 0, BX_IA_FCOMIP_ST0_STj },
/* DF F8 */ { 0, BX_IA_ERROR },
/* DF F9 */ { 0, BX_IA_ERROR },
/* DF FA */ { 0, BX_IA_ERROR },
/* DF FB */ { 0, BX_IA_ERROR },
/* DF FC */ { 0, BX_IA_ERROR },
/* DF FD */ { 0, BX_IA_ERROR },
/* DF FE */ { 0, BX_IA_ERROR },
/* DF FF */ { 0, BX_IA_ERROR },
};
#endif
/* ************************************************************************ */
/* 3DNow! Opcodes */
#if BX_SUPPORT_3DNOW
static Bit16u Bx3DNowOpcode[256] = {
// 256 entries for 3DNow opcodes, by suffix
/* 00 */ BX_IA_ERROR,
/* 01 */ BX_IA_ERROR,
/* 02 */ BX_IA_ERROR,
/* 03 */ BX_IA_ERROR,
/* 04 */ BX_IA_ERROR,
/* 05 */ BX_IA_ERROR,
/* 06 */ BX_IA_ERROR,
/* 07 */ BX_IA_ERROR,
/* 08 */ BX_IA_ERROR,
/* 09 */ BX_IA_ERROR,
/* 0A */ BX_IA_ERROR,
/* 0B */ BX_IA_ERROR,
/* 0C */ BX_IA_PI2FW_PqQq,
/* 0D */ BX_IA_PI2FD_PqQq,
/* 0E */ BX_IA_ERROR,
/* 0F */ BX_IA_ERROR,
/* 10 */ BX_IA_ERROR,
/* 11 */ BX_IA_ERROR,
/* 12 */ BX_IA_ERROR,
/* 13 */ BX_IA_ERROR,
/* 14 */ BX_IA_ERROR,
/* 15 */ BX_IA_ERROR,
/* 16 */ BX_IA_ERROR,
/* 17 */ BX_IA_ERROR,
/* 18 */ BX_IA_ERROR,
/* 19 */ BX_IA_ERROR,
/* 1A */ BX_IA_ERROR,
/* 1B */ BX_IA_ERROR,
/* 1C */ BX_IA_PF2IW_PqQq,
/* 1D */ BX_IA_PF2ID_PqQq,
/* 1E */ BX_IA_ERROR,
/* 1F */ BX_IA_ERROR,
/* 20 */ BX_IA_ERROR,
/* 21 */ BX_IA_ERROR,
/* 22 */ BX_IA_ERROR,
/* 23 */ BX_IA_ERROR,
/* 24 */ BX_IA_ERROR,
/* 25 */ BX_IA_ERROR,
/* 26 */ BX_IA_ERROR,
/* 27 */ BX_IA_ERROR,
/* 28 */ BX_IA_ERROR,
/* 29 */ BX_IA_ERROR,
/* 2A */ BX_IA_ERROR,
/* 2B */ BX_IA_ERROR,
/* 2C */ BX_IA_ERROR,
/* 2D */ BX_IA_ERROR,
/* 2E */ BX_IA_ERROR,
/* 2F */ BX_IA_ERROR,
/* 30 */ BX_IA_ERROR,
/* 31 */ BX_IA_ERROR,
/* 32 */ BX_IA_ERROR,
/* 33 */ BX_IA_ERROR,
/* 34 */ BX_IA_ERROR,
/* 35 */ BX_IA_ERROR,
/* 36 */ BX_IA_ERROR,
/* 37 */ BX_IA_ERROR,
/* 38 */ BX_IA_ERROR,
/* 39 */ BX_IA_ERROR,
/* 3A */ BX_IA_ERROR,
/* 3B */ BX_IA_ERROR,
/* 3C */ BX_IA_ERROR,
/* 3D */ BX_IA_ERROR,
/* 3E */ BX_IA_ERROR,
/* 3F */ BX_IA_ERROR,
/* 40 */ BX_IA_ERROR,
/* 41 */ BX_IA_ERROR,
/* 42 */ BX_IA_ERROR,
/* 43 */ BX_IA_ERROR,
/* 44 */ BX_IA_ERROR,
/* 45 */ BX_IA_ERROR,
/* 46 */ BX_IA_ERROR,
/* 47 */ BX_IA_ERROR,
/* 48 */ BX_IA_ERROR,
/* 49 */ BX_IA_ERROR,
/* 4A */ BX_IA_ERROR,
/* 4B */ BX_IA_ERROR,
/* 4C */ BX_IA_ERROR,
/* 4D */ BX_IA_ERROR,
/* 4E */ BX_IA_ERROR,
/* 4F */ BX_IA_ERROR,
/* 50 */ BX_IA_ERROR,
/* 51 */ BX_IA_ERROR,
/* 52 */ BX_IA_ERROR,
/* 53 */ BX_IA_ERROR,
/* 54 */ BX_IA_ERROR,
/* 55 */ BX_IA_ERROR,
/* 56 */ BX_IA_ERROR,
/* 57 */ BX_IA_ERROR,
/* 58 */ BX_IA_ERROR,
/* 59 */ BX_IA_ERROR,
/* 5A */ BX_IA_ERROR,
/* 5B */ BX_IA_ERROR,
/* 5C */ BX_IA_ERROR,
/* 5D */ BX_IA_ERROR,
/* 5E */ BX_IA_ERROR,
/* 5F */ BX_IA_ERROR,
/* 60 */ BX_IA_ERROR,
/* 61 */ BX_IA_ERROR,
/* 62 */ BX_IA_ERROR,
/* 63 */ BX_IA_ERROR,
/* 64 */ BX_IA_ERROR,
/* 65 */ BX_IA_ERROR,
/* 66 */ BX_IA_ERROR,
/* 67 */ BX_IA_ERROR,
/* 68 */ BX_IA_ERROR,
/* 69 */ BX_IA_ERROR,
/* 6A */ BX_IA_ERROR,
/* 6B */ BX_IA_ERROR,
/* 6C */ BX_IA_ERROR,
/* 6D */ BX_IA_ERROR,
/* 6E */ BX_IA_ERROR,
/* 6F */ BX_IA_ERROR,
/* 70 */ BX_IA_ERROR,
/* 71 */ BX_IA_ERROR,
/* 72 */ BX_IA_ERROR,
/* 73 */ BX_IA_ERROR,
/* 74 */ BX_IA_ERROR,
/* 75 */ BX_IA_ERROR,
/* 76 */ BX_IA_ERROR,
/* 77 */ BX_IA_ERROR,
/* 78 */ BX_IA_ERROR,
/* 79 */ BX_IA_ERROR,
/* 7A */ BX_IA_ERROR,
/* 7B */ BX_IA_ERROR,
/* 7C */ BX_IA_ERROR,
/* 7D */ BX_IA_ERROR,
/* 7E */ BX_IA_ERROR,
/* 7F */ BX_IA_ERROR,
/* 80 */ BX_IA_ERROR,
/* 81 */ BX_IA_ERROR,
/* 82 */ BX_IA_ERROR,
/* 83 */ BX_IA_ERROR,
/* 84 */ BX_IA_ERROR,
/* 85 */ BX_IA_ERROR,
/* 86 */ BX_IA_ERROR,
/* 87 */ BX_IA_ERROR,
/* 88 */ BX_IA_ERROR,
/* 89 */ BX_IA_ERROR,
/* 8A */ BX_IA_PFNACC_PqQq,
/* 8B */ BX_IA_ERROR,
/* 8C */ BX_IA_ERROR,
/* 8D */ BX_IA_ERROR,
/* 8E */ BX_IA_PFPNACC_PqQq,
/* 8F */ BX_IA_ERROR,
/* 90 */ BX_IA_PFCMPGE_PqQq,
/* 91 */ BX_IA_ERROR,
/* 92 */ BX_IA_ERROR,
/* 93 */ BX_IA_ERROR,
/* 94 */ BX_IA_PFMIN_PqQq,
/* 95 */ BX_IA_ERROR,
/* 96 */ BX_IA_PFRCP_PqQq,
/* 97 */ BX_IA_PFRSQRT_PqQq,
/* 98 */ BX_IA_ERROR,
/* 99 */ BX_IA_ERROR,
/* 9A */ BX_IA_PFSUB_PqQq,
/* 9B */ BX_IA_ERROR,
/* 9C */ BX_IA_ERROR,
/* 9D */ BX_IA_ERROR,
/* 9E */ BX_IA_PFADD_PqQq,
/* 9F */ BX_IA_ERROR,
/* A0 */ BX_IA_PFCMPGT_PqQq,
/* A1 */ BX_IA_ERROR,
/* A2 */ BX_IA_ERROR,
/* A3 */ BX_IA_ERROR,
/* A4 */ BX_IA_PFMAX_PqQq,
/* A5 */ BX_IA_ERROR,
/* A6 */ BX_IA_PFRCPIT1_PqQq,
/* A7 */ BX_IA_PFRSQIT1_PqQq,
/* A8 */ BX_IA_ERROR,
/* A9 */ BX_IA_ERROR,
/* AA */ BX_IA_PFSUBR_PqQq,
/* AB */ BX_IA_ERROR,
/* AC */ BX_IA_ERROR,
/* AD */ BX_IA_ERROR,
/* AE */ BX_IA_PFACC_PqQq,
/* AF */ BX_IA_ERROR,
/* B0 */ BX_IA_PFCMPEQ_PqQq,
/* B1 */ BX_IA_ERROR,
/* B2 */ BX_IA_ERROR,
/* B3 */ BX_IA_ERROR,
/* B4 */ BX_IA_PFMUL_PqQq,
/* B5 */ BX_IA_ERROR,
/* B6 */ BX_IA_PFRCPIT2_PqQq,
/* B7 */ BX_IA_PMULHRW_PqQq,
/* B8 */ BX_IA_ERROR,
/* B9 */ BX_IA_ERROR,
/* BA */ BX_IA_ERROR,
/* BB */ BX_IA_PSWAPD_PqQq,
/* BC */ BX_IA_ERROR,
/* BD */ BX_IA_ERROR,
/* BE */ BX_IA_ERROR,
/* BF */ BX_IA_PAVGB_PqQq,
/* C0 */ BX_IA_ERROR,
/* C1 */ BX_IA_ERROR,
/* C2 */ BX_IA_ERROR,
/* C3 */ BX_IA_ERROR,
/* C4 */ BX_IA_ERROR,
/* C5 */ BX_IA_ERROR,
/* C6 */ BX_IA_ERROR,
/* C7 */ BX_IA_ERROR,
/* C8 */ BX_IA_ERROR,
/* C9 */ BX_IA_ERROR,
/* CA */ BX_IA_ERROR,
/* CB */ BX_IA_ERROR,
/* CC */ BX_IA_ERROR,
/* CD */ BX_IA_ERROR,
/* CE */ BX_IA_ERROR,
/* CF */ BX_IA_ERROR,
/* D0 */ BX_IA_ERROR,
/* D1 */ BX_IA_ERROR,
/* D2 */ BX_IA_ERROR,
/* D3 */ BX_IA_ERROR,
/* D4 */ BX_IA_ERROR,
/* D5 */ BX_IA_ERROR,
/* D6 */ BX_IA_ERROR,
/* D7 */ BX_IA_ERROR,
/* D8 */ BX_IA_ERROR,
/* D9 */ BX_IA_ERROR,
/* DA */ BX_IA_ERROR,
/* DB */ BX_IA_ERROR,
/* DC */ BX_IA_ERROR,
/* DD */ BX_IA_ERROR,
/* DE */ BX_IA_ERROR,
/* DF */ BX_IA_ERROR,
/* E0 */ BX_IA_ERROR,
/* E1 */ BX_IA_ERROR,
/* E2 */ BX_IA_ERROR,
/* E3 */ BX_IA_ERROR,
/* E4 */ BX_IA_ERROR,
/* E5 */ BX_IA_ERROR,
/* E6 */ BX_IA_ERROR,
/* E7 */ BX_IA_ERROR,
/* E8 */ BX_IA_ERROR,
/* E9 */ BX_IA_ERROR,
/* EA */ BX_IA_ERROR,
/* EB */ BX_IA_ERROR,
/* EC */ BX_IA_ERROR,
/* ED */ BX_IA_ERROR,
/* EE */ BX_IA_ERROR,
/* EF */ BX_IA_ERROR,
/* F0 */ BX_IA_ERROR,
/* F1 */ BX_IA_ERROR,
/* F2 */ BX_IA_ERROR,
/* F3 */ BX_IA_ERROR,
/* F4 */ BX_IA_ERROR,
/* F5 */ BX_IA_ERROR,
/* F6 */ BX_IA_ERROR,
/* F7 */ BX_IA_ERROR,
/* F8 */ BX_IA_ERROR,
/* F9 */ BX_IA_ERROR,
/* FA */ BX_IA_ERROR,
/* FB */ BX_IA_ERROR,
/* FC */ BX_IA_ERROR,
/* FD */ BX_IA_ERROR,
/* FE */ BX_IA_ERROR,
/* FF */ BX_IA_ERROR
};
#endif
#endif // BX_X87_FETCHDECODE_TABLES_H

View File

@ -0,0 +1,331 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2002-2009 The Bochs Project
//
// 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
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA B 02110-1301 USA
/////////////////////////////////////////////////////////////////////////
#define NEED_CPU_REG_SHORTCUTS 1
#include "bochs.h"
#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 RSP ESP
#endif
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SAHF(bxInstruction_c *i)
{
set_SF((AH & 0x80) >> 7);
set_ZF((AH & 0x40) >> 6);
set_AF((AH & 0x10) >> 4);
set_CF (AH & 0x01);
set_PF((AH & 0x04) >> 2);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::LAHF(bxInstruction_c *i)
{
AH = read_eflags() & 0xFF;
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CLC(bxInstruction_c *i)
{
clear_CF();
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::STC(bxInstruction_c *i)
{
assert_CF();
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CLI(bxInstruction_c *i)
{
Bit32u IOPL = BX_CPU_THIS_PTR get_IOPL();
if (protected_mode())
{
#if BX_CPU_LEVEL >= 5
if (BX_CPU_THIS_PTR cr4.get_PVI() && (CPL == 3))
{
if (IOPL < 3) {
BX_CPU_THIS_PTR clear_VIF();
return;
}
}
else
#endif
{
if (IOPL < CPL) {
BX_DEBUG(("CLI: IOPL < CPL in protected mode"));
exception(BX_GP_EXCEPTION, 0);
}
}
}
else if (v8086_mode())
{
if (IOPL != 3) {
#if BX_CPU_LEVEL >= 5
if (BX_CPU_THIS_PTR cr4.get_VME()) {
BX_CPU_THIS_PTR clear_VIF();
return;
}
#endif
BX_DEBUG(("CLI: IOPL != 3 in v8086 mode"));
exception(BX_GP_EXCEPTION, 0);
}
}
BX_CPU_THIS_PTR clear_IF();
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::STI(bxInstruction_c *i)
{
Bit32u IOPL = BX_CPU_THIS_PTR get_IOPL();
if (protected_mode())
{
#if BX_CPU_LEVEL >= 5
if (BX_CPU_THIS_PTR cr4.get_PVI())
{
if (CPL == 3 && IOPL < 3) {
if (! BX_CPU_THIS_PTR get_VIP())
{
BX_CPU_THIS_PTR assert_VIF();
return;
}
BX_DEBUG(("STI: #GP(0) in VME mode"));
exception(BX_GP_EXCEPTION, 0);
}
}
#endif
if (CPL > IOPL) {
BX_DEBUG(("STI: CPL > IOPL in protected mode"));
exception(BX_GP_EXCEPTION, 0);
}
}
else if (v8086_mode())
{
if (IOPL != 3) {
#if BX_CPU_LEVEL >= 5
if (BX_CPU_THIS_PTR cr4.get_VME() && BX_CPU_THIS_PTR get_VIP() == 0)
{
BX_CPU_THIS_PTR assert_VIF();
return;
}
#endif
BX_DEBUG(("STI: IOPL != 3 in v8086 mode"));
exception(BX_GP_EXCEPTION, 0);
}
}
if (!BX_CPU_THIS_PTR get_IF()) {
BX_CPU_THIS_PTR assert_IF();
BX_CPU_THIS_PTR inhibit_mask |= BX_INHIBIT_INTERRUPTS;
BX_CPU_THIS_PTR async_event = 1;
}
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CLD(bxInstruction_c *i)
{
BX_CPU_THIS_PTR clear_DF();
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::STD(bxInstruction_c *i)
{
BX_CPU_THIS_PTR assert_DF();
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMC(bxInstruction_c *i)
{
set_CF(! get_CF());
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::PUSHF_Fw(bxInstruction_c *i)
{
Bit16u flags = (Bit16u) read_eflags();
if (v8086_mode()) {
if (BX_CPU_THIS_PTR get_IOPL() < 3) {
#if BX_CPU_LEVEL >= 5
if (BX_CPU_THIS_PTR cr4.get_VME()) {
flags |= EFlagsIOPLMask;
if (BX_CPU_THIS_PTR get_VIF())
flags |= EFlagsIFMask;
else
flags &= ~EFlagsIFMask;
}
else
#endif
{
BX_DEBUG(("PUSHFW: #GP(0) in v8086 (no VME) mode"));
exception(BX_GP_EXCEPTION, 0);
}
}
}
push_16(flags);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::POPF_Fw(bxInstruction_c *i)
{
// Build a mask of the following bits:
// x,NT,IOPL,OF,DF,IF,TF,SF,ZF,x,AF,x,PF,x,CF
Bit32u changeMask = EFlagsOSZAPCMask | EFlagsTFMask | EFlagsDFMask | EFlagsNTMask;
RSP_SPECULATIVE;
Bit16u flags16 = pop_16();
if (protected_mode()) {
if (CPL==0)
changeMask |= EFlagsIOPLMask;
if (CPL <= BX_CPU_THIS_PTR get_IOPL())
changeMask |= EFlagsIFMask;
}
else if (v8086_mode()) {
if (BX_CPU_THIS_PTR get_IOPL() < 3) {
#if BX_CPU_LEVEL >= 5
if (BX_CPU_THIS_PTR cr4.get_VME()) {
if (((flags16 & EFlagsIFMask) && BX_CPU_THIS_PTR get_VIP()) ||
(flags16 & EFlagsTFMask))
{
BX_ERROR(("POPFW: #GP(0) in VME mode"));
exception(BX_GP_EXCEPTION, 0);
}
// IF, IOPL unchanged, EFLAGS.VIF = TMP_FLAGS.IF
changeMask |= EFlagsVIFMask;
Bit32u flags32 = (Bit32u) flags16;
if (flags32 & EFlagsIFMask) flags32 |= EFlagsVIFMask;
writeEFlags(flags32, changeMask);
RSP_COMMIT;
return;
}
#endif
BX_DEBUG(("POPFW: #GP(0) in v8086 (no VME) mode"));
exception(BX_GP_EXCEPTION, 0);
}
changeMask |= EFlagsIFMask;
}
else {
// All non-reserved flags can be modified
changeMask |= (EFlagsIOPLMask | EFlagsIFMask);
}
writeEFlags((Bit32u) flags16, changeMask);
RSP_COMMIT;
}
#if BX_CPU_LEVEL >= 3
void BX_CPP_AttrRegparmN(1) BX_CPU_C::PUSHF_Fd(bxInstruction_c *i)
{
if (v8086_mode() && (BX_CPU_THIS_PTR get_IOPL()<3)) {
BX_DEBUG(("PUSHFD: #GP(0) in v8086 mode"));
exception(BX_GP_EXCEPTION, 0);
}
// VM & RF flags cleared in image stored on the stack
push_32(read_eflags() & 0x00fcffff);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::POPF_Fd(bxInstruction_c *i)
{
// Build a mask of the following bits:
// ID,VIP,VIF,AC,VM,RF,x,NT,IOPL,OF,DF,IF,TF,SF,ZF,x,AF,x,PF,x,CF
Bit32u changeMask = EFlagsOSZAPCMask | EFlagsTFMask |
EFlagsDFMask | EFlagsNTMask | EFlagsRFMask;
#if BX_CPU_LEVEL >= 4
changeMask |= (EFlagsIDMask | EFlagsACMask); // ID/AC
#endif
RSP_SPECULATIVE;
Bit32u flags32 = pop_32();
if (protected_mode()) {
// IOPL changed only if (CPL == 0),
// IF changed only if (CPL <= EFLAGS.IOPL),
// VIF, VIP, VM are unaffected
if (CPL==0)
changeMask |= EFlagsIOPLMask;
if (CPL <= BX_CPU_THIS_PTR get_IOPL())
changeMask |= EFlagsIFMask;
}
else if (v8086_mode()) {
if (BX_CPU_THIS_PTR get_IOPL() < 3) {
BX_ERROR(("POPFD: #GP(0) in v8086 mode"));
exception(BX_GP_EXCEPTION, 0);
}
// v8086-mode: VM, IOPL, VIP, VIF are unaffected
changeMask |= EFlagsIFMask;
}
else { // Real-mode
// VIF, VIP, VM are unaffected
changeMask |= (EFlagsIOPLMask | EFlagsIFMask);
}
writeEFlags(flags32, changeMask);
RSP_COMMIT;
}
#if BX_SUPPORT_X86_64
void BX_CPP_AttrRegparmN(1) BX_CPU_C::PUSHF_Fq(bxInstruction_c *i)
{
// VM & RF flags cleared in image stored on the stack
push_64(read_eflags() & 0x00fcffff);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::POPF_Fq(bxInstruction_c *i)
{
// Build a mask of the following bits:
// ID,VIP,VIF,AC,VM,RF,x,NT,IOPL,OF,DF,IF,TF,SF,ZF,x,AF,x,PF,x,CF
Bit32u changeMask = EFlagsOSZAPCMask | EFlagsTFMask | EFlagsDFMask
| EFlagsNTMask | EFlagsRFMask | EFlagsACMask
| EFlagsIDMask;
BX_ASSERT (protected_mode());
Bit32u eflags32 = (Bit32u) pop_64();
if (CPL==0)
changeMask |= EFlagsIOPLMask;
if (CPL <= BX_CPU_THIS_PTR get_IOPL())
changeMask |= EFlagsIFMask;
// VIF, VIP, VM are unaffected
writeEFlags(eflags32, changeMask);
}
#endif
#endif // BX_CPU_LEVEL >= 3
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SALC(bxInstruction_c *i)
{
if (get_CF()) {
AL = 0xff;
}
else {
AL = 0x00;
}
}

View File

@ -0,0 +1,114 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2001-2009 The Bochs Project
//
// 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
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA B 02110-1301 USA
//
/////////////////////////////////////////////////////////////////////////
#define NEED_CPU_REG_SHORTCUTS 1
#include "bochs.h"
#include "cpu.h"
#define LOG_THIS BX_CPU_THIS_PTR
void BX_CPP_AttrRegparmN(1) BX_CPU_C::setEFlags(Bit32u val)
{
// VM flag could not be set from long mode
#if BX_SUPPORT_X86_64
if (long_mode()) {
if (BX_CPU_THIS_PTR get_VM()) BX_PANIC(("VM is set in long mode !"));
val &= ~EFlagsVMMask;
}
#endif
if (val & (EFlagsTFMask|EFlagsRFMask)) {
BX_CPU_THIS_PTR async_event = 1; // TF == 1 || RF == 1
}
if (val & EFlagsIFMask) {
if (! BX_CPU_THIS_PTR get_IF())
BX_CPU_THIS_PTR async_event = 1; // IF bit was set
}
BX_CPU_THIS_PTR eflags = val;
BX_CPU_THIS_PTR lf_flags_status = 0; // OSZAPC flags are known.
#if BX_CPU_LEVEL >= 4 && BX_SUPPORT_ALIGNMENT_CHECK
handleAlignmentCheck(/* EFLAGS.AC reloaded */);
#endif
handleCpuModeChange(); // VM flag might be changed
}
void BX_CPP_AttrRegparmN(2)
BX_CPU_C::writeEFlags(Bit32u flags, Bit32u changeMask)
{
// Build a mask of the non-reserved bits:
// ID,VIP,VIF,AC,VM,RF,x,NT,IOPL,OF,DF,IF,TF,SF,ZF,x,AF,x,PF,x,CF
Bit32u supportMask = 0x00037fd5;
#if BX_CPU_LEVEL >= 4
supportMask |= (EFlagsIDMask | EFlagsACMask); // ID/AC
#endif
#if BX_CPU_LEVEL >= 5
supportMask |= (EFlagsVIPMask | EFlagsVIFMask); // VIP/VIF
#endif
// Screen out changing of any unsupported bits.
changeMask &= supportMask;
Bit32u newEFlags = (BX_CPU_THIS_PTR eflags & ~changeMask) |
(flags & changeMask);
setEFlags(newEFlags);
// OSZAPC flags are known - done in setEFlags(newEFlags)
}
void BX_CPP_AttrRegparmN(3)
BX_CPU_C::write_flags(Bit16u flags, bx_bool change_IOPL, bx_bool change_IF)
{
// Build a mask of the following bits:
// x,NT,IOPL,OF,DF,IF,TF,SF,ZF,x,AF,x,PF,x,CF
Bit32u changeMask = 0x0dd5;
#if BX_CPU_LEVEL >= 3
changeMask |= EFlagsNTMask; // NT is modified as requested.
if (change_IOPL)
changeMask |= EFlagsIOPLMask; // IOPL is modified as requested.
#endif
if (change_IF)
changeMask |= EFlagsIFMask;
writeEFlags(Bit32u(flags), changeMask);
}
// Cause arithmetic flags to be in known state and cached in val32.
Bit32u BX_CPU_C::force_flags(void)
{
if (BX_CPU_THIS_PTR lf_flags_status) {
Bit32u newflags;
newflags = get_CF() ? EFlagsCFMask : 0;
newflags |= get_PF() ? EFlagsPFMask : 0;
newflags |= get_AF() ? EFlagsAFMask : 0;
newflags |= get_ZF() ? EFlagsZFMask : 0;
newflags |= get_SF() ? EFlagsSFMask : 0;
newflags |= get_OF() ? EFlagsOFMask : 0;
setEFlagsOSZAPC(newflags);
}
return BX_CPU_THIS_PTR eflags;
}

View File

@ -0,0 +1,46 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2004-2009 Stanislav Shwartsman
// 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
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA B 02110-1301 USA
/////////////////////////////////////////////////////////////////////////
#define NEED_CPU_REG_SHORTCUTS 1
#include "bochs.h"
#include "cpu.h"
#define LOG_THIS BX_CPU_THIS_PTR
/* 9B */
void BX_CPP_AttrRegparmN(1) BX_CPU_C::FWAIT(bxInstruction_c *i)
{
#if BX_SUPPORT_FPU
if (BX_CPU_THIS_PTR cr0.get_TS() && BX_CPU_THIS_PTR cr0.get_MP())
exception(BX_NM_EXCEPTION, 0);
BX_CPU_THIS_PTR FPU_check_pending_exceptions();
#endif
}
/* relevant only when FPU support is disabled */
#if BX_SUPPORT_FPU == 0
void BX_CPP_AttrRegparmN(1) BX_CPU_C::FPU_ESC(bxInstruction_c *i)
{
if (BX_CPU_THIS_PTR cr0.get_EM() || BX_CPU_THIS_PTR cr0.get_TS())
exception(BX_NM_EXCEPTION, 0);
}
#endif

263
simulators/bochs/cpu/i387.h Normal file
View File

@ -0,0 +1,263 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2004-2009 Stanislav Shwartsman
// 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
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA B 02110-1301 USA
//
/////////////////////////////////////////////////////////////////////////
#ifndef _BX_I387_RELATED_EXTENSIONS_H_
#define _BX_I387_RELATED_EXTENSIONS_H_
#if BX_SUPPORT_FPU
#include "fpu/softfloat.h"
#define BX_FPU_REG(index) \
(BX_CPU_THIS_PTR the_i387.st_space[index & 0x7])
#if defined(NEED_CPU_REG_SHORTCUTS)
#define FPU_PARTIAL_STATUS (BX_CPU_THIS_PTR the_i387.swd)
#define FPU_CONTROL_WORD (BX_CPU_THIS_PTR the_i387.cwd)
#define FPU_TAG_WORD (BX_CPU_THIS_PTR the_i387.twd)
#define FPU_TOS (BX_CPU_THIS_PTR the_i387.tos)
#endif
#include "fpu/tag_w.h"
#include "fpu/status_w.h"
#include "fpu/control_w.h"
extern int FPU_tagof(const floatx80 &reg);
//
// Minimal i387 structure
//
struct BOCHSAPI_MSVCONLY i387_t
{
i387_t() {}
public:
void init(); // used by FINIT/FNINIT instructions
void reset(); // called on CPU reset
int is_IA_masked() const { return (cwd & FPU_CW_Invalid); }
Bit16u get_control_word() const { return cwd; }
Bit16u get_tag_word() const { return twd; }
Bit16u get_status_word() const { return (swd & ~FPU_SW_Top & 0xFFFF) | ((tos << 11) & FPU_SW_Top); }
Bit16u get_partial_status() const { return swd; }
void FPU_pop ();
void FPU_push();
void FPU_settagi(int tag, int stnr);
void FPU_settagi_valid(int stnr);
int FPU_gettagi(int stnr);
floatx80 FPU_read_regi(int stnr) { return st_space[(tos+stnr) & 7]; }
void FPU_save_regi(floatx80 reg, int stnr);
void FPU_save_regi(floatx80 reg, int tag, int stnr);
public:
Bit16u cwd; // control word
Bit16u swd; // status word
Bit16u twd; // tag word
Bit16u foo; // last instruction opcode
bx_address fip;
bx_address fdp;
Bit16u fcs;
Bit16u fds;
floatx80 st_space[8];
unsigned char tos;
unsigned char align1;
unsigned char align2;
unsigned char align3;
};
#define IS_TAG_EMPTY(i) \
((BX_CPU_THIS_PTR the_i387.FPU_gettagi(i)) == FPU_Tag_Empty)
#define BX_READ_FPU_REG(i) \
(BX_CPU_THIS_PTR the_i387.FPU_read_regi(i))
#define BX_WRITE_FPU_REG(value, i) \
BX_CPU_THIS_PTR the_i387.FPU_save_regi((value), (i));
#define BX_WRITE_FPU_REGISTER_AND_TAG(value, tag, i) \
BX_CPU_THIS_PTR the_i387.FPU_save_regi((value), (tag), (i));
BX_CPP_INLINE int i387_t::FPU_gettagi(int stnr)
{
return (twd >> (((stnr+tos) & 7)*2)) & 3;
}
BX_CPP_INLINE void i387_t::FPU_settagi_valid(int stnr)
{
int regnr = (stnr + tos) & 7;
twd &= ~(3 << (regnr*2)); // FPU_Tag_Valid == '00
}
BX_CPP_INLINE void i387_t::FPU_settagi(int tag, int stnr)
{
int regnr = (stnr + tos) & 7;
twd &= ~(3 << (regnr*2));
twd |= (tag & 3) << (regnr*2);
}
BX_CPP_INLINE void i387_t::FPU_push(void)
{
tos = (tos - 1) & 7;
}
BX_CPP_INLINE void i387_t::FPU_pop(void)
{
twd |= 3 << (tos*2);
tos = (tos + 1) & 7;
}
// it is only possisble to read FPU tag word through certain
// instructions like FNSAVE, and they update tag word to its
// real value anyway
BX_CPP_INLINE void i387_t::FPU_save_regi(floatx80 reg, int stnr)
{
st_space[(stnr+tos) & 7] = reg;
FPU_settagi_valid(stnr);
}
BX_CPP_INLINE void i387_t::FPU_save_regi(floatx80 reg, int tag, int stnr)
{
st_space[(stnr+tos) & 7] = reg;
FPU_settagi(tag, stnr);
}
#include <string.h>
BX_CPP_INLINE void i387_t::init()
{
cwd = 0x037F;
swd = 0;
tos = 0;
twd = 0xFFFF;
foo = 0;
fip = 0;
fcs = 0;
fds = 0;
fdp = 0;
}
BX_CPP_INLINE void i387_t::reset()
{
cwd = 0x0040;
swd = 0;
tos = 0;
twd = 0x5555;
foo = 0;
fip = 0;
fcs = 0;
fds = 0;
fdp = 0;
memset(st_space, 0, sizeof(floatx80)*8);
}
typedef union bx_packed_mmx_reg_t {
Bit8s mmx_sbyte[8];
Bit16s mmx_s16[4];
Bit32s mmx_s32[2];
Bit64s mmx_s64;
Bit8u mmx_ubyte[8];
Bit16u mmx_u16[4];
Bit32u mmx_u32[2];
Bit64u mmx_u64;
} BxPackedMmxRegister;
#ifdef BX_BIG_ENDIAN
#define mmx64s(i) mmx_s64
#define mmx32s(i) mmx_s32[1 - (i)]
#define mmx16s(i) mmx_s16[3 - (i)]
#define mmxsbyte(i) mmx_sbyte[7 - (i)]
#define mmxubyte(i) mmx_ubyte[7 - (i)]
#define mmx16u(i) mmx_u16[3 - (i)]
#define mmx32u(i) mmx_u32[1 - (i)]
#define mmx64u mmx_u64
#else
#define mmx64s(i) mmx_s64
#define mmx32s(i) mmx_s32[(i)]
#define mmx16s(i) mmx_s16[(i)]
#define mmxsbyte(i) mmx_sbyte[(i)]
#define mmxubyte(i) mmx_ubyte[(i)]
#define mmx16u(i) mmx_u16[(i)]
#define mmx32u(i) mmx_u32[(i)]
#define mmx64u mmx_u64
#endif
/* for compatability with already written code */
#define MMXSB0(reg) (reg.mmxsbyte(0))
#define MMXSB1(reg) (reg.mmxsbyte(1))
#define MMXSB2(reg) (reg.mmxsbyte(2))
#define MMXSB3(reg) (reg.mmxsbyte(3))
#define MMXSB4(reg) (reg.mmxsbyte(4))
#define MMXSB5(reg) (reg.mmxsbyte(5))
#define MMXSB6(reg) (reg.mmxsbyte(6))
#define MMXSB7(reg) (reg.mmxsbyte(7))
#define MMXSW0(reg) (reg.mmx16s(0))
#define MMXSW1(reg) (reg.mmx16s(1))
#define MMXSW2(reg) (reg.mmx16s(2))
#define MMXSW3(reg) (reg.mmx16s(3))
#define MMXSD0(reg) (reg.mmx32s(0))
#define MMXSD1(reg) (reg.mmx32s(1))
#define MMXSQ(reg) (reg.mmx64s)
#define MMXUQ(reg) (reg.mmx64u)
#define MMXUD0(reg) (reg.mmx32u(0))
#define MMXUD1(reg) (reg.mmx32u(1))
#define MMXUW0(reg) (reg.mmx16u(0))
#define MMXUW1(reg) (reg.mmx16u(1))
#define MMXUW2(reg) (reg.mmx16u(2))
#define MMXUW3(reg) (reg.mmx16u(3))
#define MMXUB0(reg) (reg.mmxubyte(0))
#define MMXUB1(reg) (reg.mmxubyte(1))
#define MMXUB2(reg) (reg.mmxubyte(2))
#define MMXUB3(reg) (reg.mmxubyte(3))
#define MMXUB4(reg) (reg.mmxubyte(4))
#define MMXUB5(reg) (reg.mmxubyte(5))
#define MMXUB6(reg) (reg.mmxubyte(6))
#define MMXUB7(reg) (reg.mmxubyte(7))
#define BX_MMX_REG(index) (BX_FPU_REG(index).fraction)
#define BX_READ_MMX_REG(index) \
(*((const BxPackedMmxRegister*)(&(BX_MMX_REG(index)))))
#define BX_WRITE_MMX_REG(index, value) \
{ \
(BX_FPU_REG(index)).fraction = MMXUQ(value); \
(BX_FPU_REG(index)).exp = 0xffff; \
}
#endif /* BX_SUPPORT_FPU */
#endif

File diff suppressed because it is too large Load Diff

269
simulators/bochs/cpu/icache.cc Executable file
View File

@ -0,0 +1,269 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2007-2011 Stanislav Shwartsman
// 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
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA B 02110-1301 USA
//
/////////////////////////////////////////////////////////////////////////
#define NEED_CPU_REG_SHORTCUTS 1
#include "bochs.h"
#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 RIP EIP
#endif
bxPageWriteStampTable pageWriteStampTable;
void flushICaches(void)
{
for (unsigned i=0; i<BX_SMP_PROCESSORS; i++) {
BX_CPU(i)->iCache.flushICacheEntries();
#if BX_SUPPORT_TRACE_CACHE
BX_CPU(i)->async_event |= BX_ASYNC_EVENT_STOP_TRACE;
#endif
}
pageWriteStampTable.resetWriteStamps();
}
void handleSMC(bx_phy_address pAddr, Bit32u mask)
{
for (unsigned i=0; i<BX_SMP_PROCESSORS; i++) {
#if BX_SUPPORT_TRACE_CACHE
BX_CPU(i)->async_event |= BX_ASYNC_EVENT_STOP_TRACE;
#endif
BX_CPU(i)->iCache.handleSMC(pAddr, mask);
}
}
#if BX_SUPPORT_TRACE_CACHE
void BX_CPU_C::serveICacheMiss(bxICacheEntry_c *entry, Bit32u eipBiased, bx_phy_address pAddr)
{
BX_CPU_THIS_PTR iCache.alloc_trace(entry);
// Cache miss. We weren't so lucky, but let's be optimistic - try to build
// trace from incoming instruction bytes stream !
entry->pAddr = pAddr;
entry->traceMask = 0;
unsigned remainingInPage = BX_CPU_THIS_PTR eipPageWindowSize - eipBiased;
const Bit8u *fetchPtr = BX_CPU_THIS_PTR eipFetchPtr + eipBiased;
int ret;
bxInstruction_c *i = entry->i;
Bit32u pageOffset = PAGE_OFFSET((Bit32u) pAddr);
Bit32u traceMask = 0;
for (unsigned n=0;n<BX_MAX_TRACE_LENGTH;n++)
{
#if BX_SUPPORT_X86_64
if (BX_CPU_THIS_PTR cpu_mode == BX_MODE_LONG_64)
ret = fetchDecode64(fetchPtr, i, remainingInPage);
else
#endif
ret = fetchDecode32(fetchPtr, i, remainingInPage);
if (ret < 0) {
// Fetching instruction on segment/page boundary
if (n > 0) {
// The trace is already valid, it has several instructions inside,
// in this case just drop the boundary instruction and stop
// tracing.
break;
}
// First instruction is boundary fetch, leave the trace cache entry
// invalid for now because boundaryFetch() can fault
entry->pAddr = ~entry->pAddr;
entry->tlen = 1;
boundaryFetch(fetchPtr, remainingInPage, i);
// Add the instruction to trace cache
entry->pAddr = ~entry->pAddr;
entry->traceMask = 0x80000000; /* last line in page */
pageWriteStampTable.markICacheMask(entry->pAddr, entry->traceMask);
pageWriteStampTable.markICacheMask(BX_CPU_THIS_PTR pAddrPage, 0x1);
BX_CPU_THIS_PTR iCache.commit_page_split_trace(BX_CPU_THIS_PTR pAddrPage, entry);
return;
}
// add instruction to the trace
unsigned iLen = i->ilen();
entry->tlen++;
BX_INSTR_OPCODE(BX_CPU_ID, fetchPtr, iLen,
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.d_b, long64_mode());
traceMask |= 1 << (pageOffset >> 7);
traceMask |= 1 << ((pageOffset + iLen - 1) >> 7);
// continue to the next instruction
remainingInPage -= iLen;
if (ret != 0 /* stop trace indication */ || remainingInPage == 0) break;
pAddr += iLen;
pageOffset += iLen;
fetchPtr += iLen;
i++;
// try to find a trace starting from current pAddr and merge
if (remainingInPage >= 15) // avoid merging with page split trace
if (mergeTraces(entry, i, pAddr)) break;
}
//BX_INFO(("commit trace %08x len=%d mask %08x", (Bit32u) entry->pAddr, entry->tlen, pageWriteStampTable.getFineGranularityMapping(entry->pAddr)));
entry->traceMask |= traceMask;
pageWriteStampTable.markICacheMask(pAddr, entry->traceMask);
BX_CPU_THIS_PTR iCache.commit_trace(entry->tlen);
}
bx_bool BX_CPU_C::mergeTraces(bxICacheEntry_c *entry, bxInstruction_c *i, bx_phy_address pAddr)
{
bxICacheEntry_c *e = BX_CPU_THIS_PTR iCache.get_entry(pAddr, BX_CPU_THIS_PTR fetchModeMask);
if (e->pAddr == pAddr)
{
// determine max amount of instruction to take from another entry
unsigned max_length = e->tlen;
if (max_length + entry->tlen > BX_MAX_TRACE_LENGTH)
max_length = BX_MAX_TRACE_LENGTH - entry->tlen;
if(max_length == 0) return 0;
memcpy(i, e->i, sizeof(bxInstruction_c)*max_length);
entry->tlen += max_length;
BX_ASSERT(entry->tlen <= BX_MAX_TRACE_LENGTH);
entry->traceMask |= e->traceMask;
return 1;
}
return 0;
}
#else // BX_SUPPORT_TRACE_CACHE == 0
bx_bool BX_CPU_C::fetchInstruction(bxInstruction_c *iStorage, Bit32u eipBiased)
{
unsigned remainingInPage = BX_CPU_THIS_PTR eipPageWindowSize - eipBiased;
const Bit8u *fetchPtr = BX_CPU_THIS_PTR eipFetchPtr + eipBiased;
int ret;
#if BX_SUPPORT_X86_64
if (BX_CPU_THIS_PTR cpu_mode == BX_MODE_LONG_64)
ret = fetchDecode64(fetchPtr, iStorage, remainingInPage);
else
#endif
ret = fetchDecode32(fetchPtr, iStorage, remainingInPage);
if (ret < 0) {
// handle instrumentation callback inside boundaryFetch
boundaryFetch(fetchPtr, remainingInPage, iStorage);
return 0;
}
#if BX_INSTRUMENTATION
BX_INSTR_OPCODE(BX_CPU_ID, fetchPtr, iStorage->ilen(),
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.d_b, long64_mode());
#endif
return 1;
}
void BX_CPU_C::serveICacheMiss(bxICacheEntry_c *entry, Bit32u eipBiased, bx_phy_address pAddr)
{
// The entry will be marked valid if fetchdecode will succeed
if (fetchInstruction(entry->i, eipBiased)) {
entry->pAddr = pAddr;
pageWriteStampTable.markICache(pAddr, entry->i->ilen());
}
else {
entry->pAddr = BX_ICACHE_INVALID_PHY_ADDRESS;
}
}
#endif
void BX_CPU_C::boundaryFetch(const Bit8u *fetchPtr, unsigned remainingInPage, bxInstruction_c *i)
{
unsigned j, k;
Bit8u fetchBuffer[32];
int ret;
if (remainingInPage >= 15) {
BX_ERROR(("boundaryFetch #GP(0): too many instruction prefixes"));
exception(BX_GP_EXCEPTION, 0);
}
// Read all leftover bytes in current page up to boundary.
for (j=0; j<remainingInPage; j++) {
fetchBuffer[j] = *fetchPtr++;
}
// The 2nd chunk of the instruction is on the next page.
// Set RIP to the 0th byte of the 2nd page, and force a
// prefetch so direct access of that physical page is possible, and
// all the associated info is updated.
RIP += remainingInPage;
prefetch();
unsigned fetchBufferLimit = 15;
if (BX_CPU_THIS_PTR eipPageWindowSize < 15) {
BX_DEBUG(("boundaryFetch: small window size after prefetch=%d bytes, remainingInPage=%d bytes", BX_CPU_THIS_PTR eipPageWindowSize, remainingInPage));
fetchBufferLimit = BX_CPU_THIS_PTR eipPageWindowSize;
}
// We can fetch straight from the 0th byte, which is eipFetchPtr;
fetchPtr = BX_CPU_THIS_PTR eipFetchPtr;
// read leftover bytes in next page
for (k=0; k<fetchBufferLimit; k++, j++) {
fetchBuffer[j] = *fetchPtr++;
}
#if BX_SUPPORT_X86_64
if (BX_CPU_THIS_PTR cpu_mode == BX_MODE_LONG_64)
ret = fetchDecode64(fetchBuffer, i, remainingInPage+fetchBufferLimit);
else
#endif
ret = fetchDecode32(fetchBuffer, i, remainingInPage+fetchBufferLimit);
if (ret < 0) {
BX_INFO(("boundaryFetch #GP(0): failed to complete instruction decoding"));
exception(BX_GP_EXCEPTION, 0);
}
// Restore EIP since we fudged it to start at the 2nd page boundary.
RIP = BX_CPU_THIS_PTR prev_rip;
// Since we cross an instruction boundary, note that we need a prefetch()
// again on the next instruction. Perhaps we can optimize this to
// eliminate the extra prefetch() since we do it above, but have to
// think about repeated instructions, etc.
// invalidate_prefetch_q();
BX_INSTR_OPCODE(BX_CPU_ID, fetchBuffer, i->ilen(),
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.d_b, long64_mode());
}

242
simulators/bochs/cpu/icache.h Executable file
View File

@ -0,0 +1,242 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2007-2011 Stanislav Shwartsman
// 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
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA B 02110-1301 USA
//
/////////////////////////////////////////////////////////////////////////
#ifndef BX_ICACHE_H
#define BX_ICACHE_H
extern void handleSMC(bx_phy_address pAddr, Bit32u mask);
class bxPageWriteStampTable
{
#define PHY_MEM_PAGES (1024*1024)
Bit32u *fineGranularityMapping;
public:
bxPageWriteStampTable() {
fineGranularityMapping = new Bit32u[PHY_MEM_PAGES];
resetWriteStamps();
}
~bxPageWriteStampTable() { delete [] fineGranularityMapping; }
BX_CPP_INLINE Bit32u hash(bx_phy_address pAddr) const {
// can share writeStamps between multiple pages if >32 bit phy address
return ((Bit32u) pAddr) >> 12;
}
BX_CPP_INLINE Bit32u getFineGranularityMapping(bx_phy_address pAddr) const
{
return fineGranularityMapping[hash(pAddr)];
}
BX_CPP_INLINE void markICache(bx_phy_address pAddr, unsigned len)
{
Bit32u mask = 1 << (PAGE_OFFSET((Bit32u) pAddr) >> 7);
mask |= 1 << (PAGE_OFFSET((Bit32u) pAddr + len - 1) >> 7);
fineGranularityMapping[hash(pAddr)] |= mask;
}
BX_CPP_INLINE void markICacheMask(bx_phy_address pAddr, Bit32u mask)
{
fineGranularityMapping[hash(pAddr)] |= mask;
}
// whole page is being altered
BX_CPP_INLINE void decWriteStamp(bx_phy_address pAddr)
{
Bit32u index = hash(pAddr);
if (fineGranularityMapping[index]) {
handleSMC(pAddr, 0xffffffff); // one of the CPUs might be running trace from this page
fineGranularityMapping[index] = 0;
}
}
// assumption: write does not split 4K page
BX_CPP_INLINE void decWriteStamp(bx_phy_address pAddr, unsigned len)
{
Bit32u index = hash(pAddr);
if (fineGranularityMapping[index]) {
Bit32u mask = 1 << (PAGE_OFFSET((Bit32u) pAddr) >> 7);
mask |= 1 << (PAGE_OFFSET((Bit32u) pAddr + len - 1) >> 7);
if (fineGranularityMapping[index] & mask) {
// one of the CPUs might be running trace from this page
handleSMC(pAddr, mask);
fineGranularityMapping[index] &= ~mask;
}
}
}
BX_CPP_INLINE void resetWriteStamps(void);
};
BX_CPP_INLINE void bxPageWriteStampTable::resetWriteStamps(void)
{
for (Bit32u i=0; i<PHY_MEM_PAGES; i++) {
fineGranularityMapping[i] = 0;
}
}
extern bxPageWriteStampTable pageWriteStampTable;
#define BxICacheEntries (64 * 1024) // Must be a power of 2.
#define BxICacheMemPool (384 * 1024)
#if BX_SUPPORT_TRACE_CACHE
#define BX_MAX_TRACE_LENGTH 32
#endif
struct bxICacheEntry_c
{
bx_phy_address pAddr; // Physical address of the instruction
Bit32u traceMask;
#if BX_SUPPORT_TRACE_CACHE
Bit32u tlen; // Trace length in instructions
bxInstruction_c *i;
#else
// ... define as array of 1 to simplify merge with trace cache code
bxInstruction_c i[1];
#endif
};
#define BX_ICACHE_INVALID_PHY_ADDRESS (bx_phy_address(-1))
class BOCHSAPI bxICache_c {
public:
bxICacheEntry_c entry[BxICacheEntries];
#if BX_SUPPORT_TRACE_CACHE
bxInstruction_c mpool[BxICacheMemPool];
unsigned mpindex;
#define BX_ICACHE_PAGE_SPLIT_ENTRIES 8 /* must be power of two */
struct pageSplitEntryIndex {
bx_phy_address ppf; // Physical address of 2nd page of the trace
bxICacheEntry_c *e; // Pointer to icache entry
} pageSplitIndex[BX_ICACHE_PAGE_SPLIT_ENTRIES];
int nextPageSplitIndex;
#endif
public:
bxICache_c() { flushICacheEntries(); }
BX_CPP_INLINE unsigned hash(bx_phy_address pAddr, unsigned fetchModeMask) const
{
// return ((pAddr + (pAddr << 2) + (pAddr>>6)) & (BxICacheEntries-1)) ^ fetchModeMask;
return ((pAddr) & (BxICacheEntries-1)) ^ fetchModeMask;
}
#if BX_SUPPORT_TRACE_CACHE
BX_CPP_INLINE void alloc_trace(bxICacheEntry_c *e)
{
if (mpindex + BX_MAX_TRACE_LENGTH > BxICacheMemPool) {
flushICacheEntries();
}
e->i = &mpool[mpindex];
e->tlen = 0;
}
BX_CPP_INLINE void commit_trace(unsigned len) { mpindex += len; }
BX_CPP_INLINE void commit_page_split_trace(bx_phy_address paddr, bxICacheEntry_c *entry)
{
mpindex++; // commit_trace(1)
// register page split entry
if (pageSplitIndex[nextPageSplitIndex].ppf != BX_ICACHE_INVALID_PHY_ADDRESS)
pageSplitIndex[nextPageSplitIndex].e->pAddr = BX_ICACHE_INVALID_PHY_ADDRESS;
pageSplitIndex[nextPageSplitIndex].ppf = paddr;
pageSplitIndex[nextPageSplitIndex].e = entry;
nextPageSplitIndex = (nextPageSplitIndex+1) & (BX_ICACHE_PAGE_SPLIT_ENTRIES-1);
}
#endif
BX_CPP_INLINE void handleSMC(bx_phy_address pAddr, Bit32u mask);
BX_CPP_INLINE void purgeICacheEntries(void);
BX_CPP_INLINE void flushICacheEntries(void);
BX_CPP_INLINE bxICacheEntry_c* get_entry(bx_phy_address pAddr, unsigned fetchModeMask)
{
return &(entry[hash(pAddr, fetchModeMask)]);
}
};
BX_CPP_INLINE void bxICache_c::flushICacheEntries(void)
{
bxICacheEntry_c* e = entry;
unsigned i;
for (i=0; i<BxICacheEntries; i++, e++) {
e->pAddr = BX_ICACHE_INVALID_PHY_ADDRESS;
e->traceMask = 0;
}
#if BX_SUPPORT_TRACE_CACHE
for (i=0;i<BX_ICACHE_PAGE_SPLIT_ENTRIES;i++)
pageSplitIndex[i].ppf = BX_ICACHE_INVALID_PHY_ADDRESS;
nextPageSplitIndex = 0;
mpindex = 0;
#endif
}
BX_CPP_INLINE void bxICache_c::handleSMC(bx_phy_address pAddr, Bit32u mask)
{
// TODO: invalidate only entries in same page as pAddr
pAddr = LPFOf(pAddr);
#if BX_SUPPORT_TRACE_CACHE
if (mask & 0x1) {
// the store touched 1st cache line in the page, check for
// page split traces to invalidate.
for (unsigned i=0;i<BX_ICACHE_PAGE_SPLIT_ENTRIES;i++) {
if (pAddr == pageSplitIndex[i].ppf) {
pageSplitIndex[i].ppf = BX_ICACHE_INVALID_PHY_ADDRESS;
}
}
}
#endif
bxICacheEntry_c *e = get_entry(pAddr, 0);
for (unsigned n=0; n < 32; n++) {
Bit32u line_mask = (1 << n);
if (line_mask > mask) break;
for (unsigned index=0; index < 128; index++, e++) {
if (pAddr == LPFOf(e->pAddr) && (e->traceMask & mask) != 0) {
e->pAddr = BX_ICACHE_INVALID_PHY_ADDRESS;
}
}
}
}
extern void flushICaches(void);
#endif

1239
simulators/bochs/cpu/init.cc Normal file

File diff suppressed because it is too large Load Diff

279
simulators/bochs/cpu/instr.h Executable file
View File

@ -0,0 +1,279 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2008-2010 Stanislav Shwartsman
// 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
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA B 02110-1301 USA
//
/////////////////////////////////////////////////////////////////////////
#ifndef BX_INSTR_H
#define BX_INSTR_H
class bxInstruction_c;
// <TAG-TYPE-EXECUTEPTR-START>
#if BX_USE_CPU_SMF
typedef void (BX_CPP_AttrRegparmN(1) *BxExecutePtr_tR)(bxInstruction_c *);
typedef bx_address (BX_CPP_AttrRegparmN(1) *BxResolvePtr_tR)(bxInstruction_c *);
#else
typedef void (BX_CPU_C::*BxExecutePtr_tR)(bxInstruction_c *) BX_CPP_AttrRegparmN(1);
typedef bx_address (BX_CPU_C::*BxResolvePtr_tR)(bxInstruction_c *) BX_CPP_AttrRegparmN(1);
#endif
// <TAG-TYPE-EXECUTEPTR-END>
extern bx_address bx_asize_mask[];
// <TAG-CLASS-INSTRUCTION-START>
class bxInstruction_c {
public:
// Function pointers; a function to resolve the modRM address
// given the current state of the CPU and the instruction data,
// and a function to execute the instruction after resolving
// the memory address (if any).
BxExecutePtr_tR execute;
BxExecutePtr_tR execute2;
BxResolvePtr_tR ResolveModrm;
struct {
// 15..0 opcode
Bit16u ia_opcode;
// 7...4 (unused)
// 3...0 ilen (0..15)
Bit8u ilen;
// 7...6 repUsed (0=none, 2=0xF2, 3=0xF3)
// 5...5 extend8bit
// 4...4 mod==c0 (modrm)
// 3...3 os64
// 2...2 os32
// 1...1 as64
// 0...0 as32
Bit8u metaInfo1;
} metaInfo;
#define BX_INSTR_METADATA_SEG 0
#define BX_INSTR_METADATA_B1 1
#define BX_INSTR_METADATA_NNN 2
#define BX_INSTR_METADATA_RM 3
#define BX_INSTR_METADATA_BASE 4
#define BX_INSTR_METADATA_INDEX 5
#define BX_INSTR_METADATA_SCALE 6
#define BX_INSTR_METADATA_MODRM 7
// using 5-bit field for registers (16 regs in 64-bit, RIP, NIL)
Bit8u metaData[8];
union {
// Form (longest case): [opcode+modrm+sib/displacement32/immediate32]
struct {
union {
Bit32u Id;
Bit16u Iw;
Bit8u Ib;
};
union {
Bit16u displ16u; // for 16-bit modrm forms
Bit32u displ32u; // for 32-bit modrm forms
Bit16u Iw2;
Bit8u Ib2;
};
} modRMForm;
#if BX_SUPPORT_X86_64
struct {
Bit64u Iq; // for MOV Rx,imm64
} IqForm;
#endif
};
BX_CPP_INLINE unsigned seg(void) const {
return metaData[BX_INSTR_METADATA_SEG];
}
BX_CPP_INLINE void setSeg(unsigned val) {
metaData[BX_INSTR_METADATA_SEG] = val;
}
BX_CPP_INLINE unsigned b1(void) const {
return metaData[BX_INSTR_METADATA_B1];
}
BX_CPP_INLINE void setB1(unsigned b1) {
metaData[BX_INSTR_METADATA_B1] = b1 & 0xff;
}
BX_CPP_INLINE void setModRM(unsigned modrm) {
metaData[BX_INSTR_METADATA_MODRM] = modrm;
}
BX_CPP_INLINE unsigned modrm() const {
return metaData[BX_INSTR_METADATA_MODRM];
}
BX_CPP_INLINE void setNnn(unsigned nnn) {
metaData[BX_INSTR_METADATA_NNN] = nnn;
}
BX_CPP_INLINE unsigned nnn() const {
return metaData[BX_INSTR_METADATA_NNN];
}
BX_CPP_INLINE void setRm(unsigned rm) {
metaData[BX_INSTR_METADATA_RM] = rm;
}
BX_CPP_INLINE unsigned rm() const {
return metaData[BX_INSTR_METADATA_RM];
}
BX_CPP_INLINE void setSibScale(unsigned scale) {
metaData[BX_INSTR_METADATA_SCALE] = scale;
}
BX_CPP_INLINE unsigned sibScale() const {
return metaData[BX_INSTR_METADATA_SCALE];
}
BX_CPP_INLINE void setSibIndex(unsigned index) {
metaData[BX_INSTR_METADATA_INDEX] = index;
}
BX_CPP_INLINE unsigned sibIndex() const {
return metaData[BX_INSTR_METADATA_INDEX];
}
BX_CPP_INLINE void setSibBase(unsigned base) {
metaData[BX_INSTR_METADATA_BASE] = base;
}
BX_CPP_INLINE unsigned sibBase() const {
return metaData[BX_INSTR_METADATA_BASE];
}
BX_CPP_INLINE Bit32s displ32s() const { return (Bit32s) modRMForm.displ32u; }
BX_CPP_INLINE Bit16s displ16s() const { return (Bit16s) modRMForm.displ16u; }
BX_CPP_INLINE Bit32u Id() const { return modRMForm.Id; }
BX_CPP_INLINE Bit16u Iw() const { return modRMForm.Iw; }
BX_CPP_INLINE Bit8u Ib() const { return modRMForm.Ib; }
BX_CPP_INLINE Bit16u Iw2() const { return modRMForm.Iw2; }
BX_CPP_INLINE Bit8u Ib2() const { return modRMForm.Ib2; }
#if BX_SUPPORT_X86_64
BX_CPP_INLINE Bit64u Iq() const { return IqForm.Iq; }
#endif
// Info in the metaInfo field.
// Note: the 'L' at the end of certain flags, means the value returned
// is for Logical comparisons, eg if (i->os32L() && i->as32L()). If you
// want a bx_bool value, use os32B() etc. This makes for smaller
// code, when a strict 0 or 1 is not necessary.
BX_CPP_INLINE void init(unsigned os32, unsigned as32, unsigned os64, unsigned as64)
{
metaInfo.metaInfo1 = (os32<<2) | (os64<<3) | (as32<<0) | (as64<<1);
}
BX_CPP_INLINE unsigned os32L(void) const {
return metaInfo.metaInfo1 & (1<<2);
}
BX_CPP_INLINE void setOs32B(unsigned bit) {
metaInfo.metaInfo1 = (metaInfo.metaInfo1 & ~(1<<2)) | (bit<<2);
}
BX_CPP_INLINE void assertOs32(void) {
metaInfo.metaInfo1 |= (1<<2);
}
#if BX_SUPPORT_X86_64
BX_CPP_INLINE unsigned os64L(void) const {
return metaInfo.metaInfo1 & (1<<3);
}
BX_CPP_INLINE void assertOs64(void) {
metaInfo.metaInfo1 |= (1<<3);
}
#else
BX_CPP_INLINE unsigned os64L(void) const { return 0; }
#endif
BX_CPP_INLINE unsigned as32L(void) const {
return metaInfo.metaInfo1 & 0x1;
}
BX_CPP_INLINE void setAs32B(unsigned bit) {
metaInfo.metaInfo1 = (metaInfo.metaInfo1 & ~0x1) | (bit);
}
#if BX_SUPPORT_X86_64
BX_CPP_INLINE unsigned as64L(void) const {
return metaInfo.metaInfo1 & (1<<1);
}
BX_CPP_INLINE void clearAs64(void) {
metaInfo.metaInfo1 &= ~(1<<1);
}
#else
BX_CPP_INLINE unsigned as64L(void) const { return 0; }
#endif
BX_CPP_INLINE unsigned asize(void) const {
return metaInfo.metaInfo1 & 0x3;
}
BX_CPP_INLINE bx_address asize_mask(void) const {
return bx_asize_mask[asize()];
}
#if BX_SUPPORT_X86_64
BX_CPP_INLINE unsigned extend8bitL(void) const {
return metaInfo.metaInfo1 & (1<<5);
}
BX_CPP_INLINE void assertExtend8bit(void) {
metaInfo.metaInfo1 |= (1<<5);
}
#endif
BX_CPP_INLINE unsigned ilen(void) const {
return metaInfo.ilen;
}
BX_CPP_INLINE void setILen(unsigned ilen) {
metaInfo.ilen = ilen;
}
BX_CPP_INLINE unsigned getIaOpcode(void) const {
return metaInfo.ia_opcode;
}
BX_CPP_INLINE void setIaOpcode(Bit16u op) {
metaInfo.ia_opcode = op;
}
BX_CPP_INLINE unsigned repUsedL(void) const {
return metaInfo.metaInfo1 >> 6;
}
BX_CPP_INLINE unsigned repUsedValue(void) const {
return metaInfo.metaInfo1 >> 6;
}
BX_CPP_INLINE void setRepUsed(unsigned value) {
metaInfo.metaInfo1 = (metaInfo.metaInfo1 & 0x3f) | (value << 6);
}
BX_CPP_INLINE unsigned modC0() const
{
// This is a cheaper way to test for modRM instructions where
// the mod field is 0xc0. FetchDecode flags this condition since
// it is quite common to be tested for.
return metaInfo.metaInfo1 & (1<<4);
}
BX_CPP_INLINE unsigned assertModC0()
{
return metaInfo.metaInfo1 |= (1<<4);
}
};
// <TAG-CLASS-INSTRUCTION-END>
const char *get_bx_opcode_name(Bit16u ia_opcode);
enum {
#define bx_define_opcode(a, b, c, d, e) a,
#include "ia_opcodes.h"
BX_IA_LAST
};
#undef bx_define_opcode
#endif

868
simulators/bochs/cpu/io.cc Normal file
View File

@ -0,0 +1,868 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2001-2009 The Bochs Project
//
// 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
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA B 02110-1301 USA
//
/////////////////////////////////////////////////////////////////////////
#define NEED_CPU_REG_SHORTCUTS 1
#include "bochs.h"
#include "cpu.h"
#define LOG_THIS BX_CPU_THIS_PTR
#include "iodev/iodev.h"
#if BX_SUPPORT_X86_64==0
// Make life easier for merging cpu64 and cpu32 code.
#define RDI EDI
#define RSI ESI
#define RAX EAX
#define RCX ECX
#endif
//
// Repeat Speedups methods
//
#if BX_SupportRepeatSpeedups
Bit32u BX_CPU_C::FastRepINSW(bxInstruction_c *i, bx_address dstOff, Bit16u port, Bit32u wordCount)
{
Bit32u wordsFitDst;
signed int pointerDelta;
Bit8u *hostAddrDst;
unsigned count;
BX_ASSERT(BX_CPU_THIS_PTR cpu_mode != BX_MODE_LONG_64);
bx_segment_reg_t *dstSegPtr = &BX_CPU_THIS_PTR sregs[BX_SEG_REG_ES];
if (!(dstSegPtr->cache.valid & SegAccessWOK))
return 0;
if ((dstOff | 0xfff) > dstSegPtr->cache.u.segment.limit_scaled)
return 0;
bx_address laddrDst = BX_CPU_THIS_PTR get_laddr(BX_SEG_REG_ES, dstOff);
// check that the address is word aligned
if (laddrDst & 1) return 0;
hostAddrDst = v2h_write_byte(laddrDst, BX_CPU_THIS_PTR user_pl);
// Check that native host access was not vetoed for that page
if (!hostAddrDst) return 0;
// See how many words can fit in the rest of this page.
if (BX_CPU_THIS_PTR get_DF()) {
// Counting downward
// 1st word must cannot cross page boundary because it is word aligned
wordsFitDst = (2 + (PAGE_OFFSET(laddrDst))) >> 1;
pointerDelta = -2;
}
else {
// Counting upward
wordsFitDst = (0x1000 - PAGE_OFFSET(laddrDst)) >> 1;
pointerDelta = 2;
}
// Restrict word count to the number that will fit in this page.
if (wordCount > wordsFitDst)
wordCount = wordsFitDst;
// If after all the restrictions, there is anything left to do...
if (wordCount) {
for (count=0; count<wordCount; ) {
bx_devices.bulkIOQuantumsTransferred = 0;
if (BX_CPU_THIS_PTR get_DF()==0) { // Only do accel for DF=0
bx_devices.bulkIOHostAddr = hostAddrDst;
bx_devices.bulkIOQuantumsRequested = (wordCount - count);
}
else
bx_devices.bulkIOQuantumsRequested = 0;
Bit16u temp16 = BX_INP(port, 2);
if (bx_devices.bulkIOQuantumsTransferred) {
hostAddrDst = bx_devices.bulkIOHostAddr;
count += bx_devices.bulkIOQuantumsTransferred;
}
else {
WriteHostWordToLittleEndian(hostAddrDst, temp16);
hostAddrDst += pointerDelta;
count++;
}
// Terminate early if there was an event.
if (BX_CPU_THIS_PTR async_event) break;
}
// Reset for next non-bulk IO
bx_devices.bulkIOQuantumsRequested = 0;
return count;
}
return 0;
}
Bit32u BX_CPU_C::FastRepOUTSW(bxInstruction_c *i, unsigned srcSeg, bx_address srcOff, Bit16u port, Bit32u wordCount)
{
Bit32u wordsFitSrc;
signed int pointerDelta;
Bit8u *hostAddrSrc;
unsigned count;
BX_ASSERT(BX_CPU_THIS_PTR cpu_mode != BX_MODE_LONG_64);
bx_segment_reg_t *srcSegPtr = &BX_CPU_THIS_PTR sregs[srcSeg];
if (!(srcSegPtr->cache.valid & SegAccessROK))
return 0;
if ((srcOff | 0xfff) > srcSegPtr->cache.u.segment.limit_scaled)
return 0;
bx_address laddrSrc = BX_CPU_THIS_PTR get_laddr(srcSeg, srcOff);
// check that the address is word aligned
if (laddrSrc & 1) return 0;
hostAddrSrc = v2h_read_byte(laddrSrc, BX_CPU_THIS_PTR user_pl);
// Check that native host access was not vetoed for that page
if (!hostAddrSrc) return 0;
// See how many words can fit in the rest of this page.
if (BX_CPU_THIS_PTR get_DF()) {
// Counting downward
// 1st word must cannot cross page boundary because it is word aligned
wordsFitSrc = (2 + (PAGE_OFFSET(laddrSrc))) >> 1;
pointerDelta = (unsigned) -2;
}
else {
// Counting upward
wordsFitSrc = (0x1000 - PAGE_OFFSET(laddrSrc)) >> 1;
pointerDelta = 2;
}
// Restrict word count to the number that will fit in this page.
if (wordCount > wordsFitSrc)
wordCount = wordsFitSrc;
// If after all the restrictions, there is anything left to do...
if (wordCount) {
for (count=0; count<wordCount; ) {
bx_devices.bulkIOQuantumsTransferred = 0;
if (BX_CPU_THIS_PTR get_DF()==0) { // Only do accel for DF=0
bx_devices.bulkIOHostAddr = hostAddrSrc;
bx_devices.bulkIOQuantumsRequested = (wordCount - count);
}
else
bx_devices.bulkIOQuantumsRequested = 0;
Bit16u temp16;
ReadHostWordFromLittleEndian(hostAddrSrc, temp16);
BX_OUTP(port, temp16, 2);
if (bx_devices.bulkIOQuantumsTransferred) {
hostAddrSrc = bx_devices.bulkIOHostAddr;
count += bx_devices.bulkIOQuantumsTransferred;
}
else {
hostAddrSrc += pointerDelta;
count++;
}
// Terminate early if there was an event.
if (BX_CPU_THIS_PTR async_event) break;
}
// Reset for next non-bulk IO
bx_devices.bulkIOQuantumsRequested = 0;
return count;
}
return 0;
}
#endif
//
// REP INS methods
//
void BX_CPP_AttrRegparmN(1) BX_CPU_C::REP_INSB_YbDX(bxInstruction_c *i)
{
if (! allow_io(i, DX, 1)) {
BX_DEBUG(("INSB_YbDX: I/O access not allowed !"));
exception(BX_GP_EXCEPTION, 0);
}
#if BX_SUPPORT_X86_64
if (i->as64L()) {
BX_CPU_THIS_PTR repeat(i, &BX_CPU_C::INSB64_YbDX);
}
else
#endif
if (i->as32L()) {
BX_CPU_THIS_PTR repeat(i, &BX_CPU_C::INSB32_YbDX);
BX_CLEAR_64BIT_HIGH(BX_64BIT_REG_RDI); // always clear upper part of RDI
}
else {
BX_CPU_THIS_PTR repeat(i, &BX_CPU_C::INSB16_YbDX);
}
}
// 16-bit address size
void BX_CPP_AttrRegparmN(1) BX_CPU_C::INSB16_YbDX(bxInstruction_c *i)
{
// trigger any segment or page faults before reading from IO port
Bit8u value8 = read_RMW_virtual_byte_32(BX_SEG_REG_ES, DI);
value8 = BX_INP(DX, 1);
write_RMW_virtual_byte(value8);
if (BX_CPU_THIS_PTR get_DF())
DI--;
else
DI++;
}
// 32-bit address size
void BX_CPP_AttrRegparmN(1) BX_CPU_C::INSB32_YbDX(bxInstruction_c *i)
{
// trigger any segment or page faults before reading from IO port
Bit8u value8 = read_RMW_virtual_byte(BX_SEG_REG_ES, EDI);
value8 = BX_INP(DX, 1);
/* no seg override possible */
write_RMW_virtual_byte(value8);
if (BX_CPU_THIS_PTR get_DF()) {
RDI = EDI - 1;
}
else {
RDI = EDI + 1;
}
}
#if BX_SUPPORT_X86_64
// 64-bit address size
void BX_CPP_AttrRegparmN(1) BX_CPU_C::INSB64_YbDX(bxInstruction_c *i)
{
// trigger any segment or page faults before reading from IO port
Bit8u value8 = read_RMW_virtual_byte_64(BX_SEG_REG_ES, RDI);
value8 = BX_INP(DX, 1);
write_RMW_virtual_byte(value8);
if (BX_CPU_THIS_PTR get_DF())
RDI--;
else
RDI++;
}
#endif
void BX_CPP_AttrRegparmN(1) BX_CPU_C::REP_INSW_YwDX(bxInstruction_c *i)
{
if (! allow_io(i, DX, 2)) {
BX_DEBUG(("INSW_YwDX: I/O access not allowed !"));
exception(BX_GP_EXCEPTION, 0);
}
#if BX_SUPPORT_X86_64
if (i->as64L()) {
BX_CPU_THIS_PTR repeat(i, &BX_CPU_C::INSW64_YwDX);
}
else
#endif
if (i->as32L()) {
BX_CPU_THIS_PTR repeat(i, &BX_CPU_C::INSW32_YwDX);
BX_CLEAR_64BIT_HIGH(BX_64BIT_REG_RDI); // always clear upper part of RDI
}
else {
BX_CPU_THIS_PTR repeat(i, &BX_CPU_C::INSW16_YwDX);
}
}
// 16-bit operand size, 16-bit address size
void BX_CPP_AttrRegparmN(1) BX_CPU_C::INSW16_YwDX(bxInstruction_c *i)
{
// trigger any segment or page faults before reading from IO port
Bit16u value16 = read_RMW_virtual_word_32(BX_SEG_REG_ES, DI);
value16 = BX_INP(DX, 2);
write_RMW_virtual_word(value16);
if (BX_CPU_THIS_PTR get_DF())
DI -= 2;
else
DI += 2;
}
// 16-bit operand size, 32-bit address size
void BX_CPP_AttrRegparmN(1) BX_CPU_C::INSW32_YwDX(bxInstruction_c *i)
{
Bit16u value16=0;
Bit32u edi = EDI;
unsigned incr = 2;
#if (BX_SupportRepeatSpeedups) && (BX_DEBUGGER == 0)
/* If conditions are right, we can transfer IO to physical memory
* in a batch, rather than one instruction at a time.
*/
if (i->repUsedL() && !BX_CPU_THIS_PTR async_event)
{
Bit32u wordCount = ECX;
BX_ASSERT(wordCount > 0);
wordCount = FastRepINSW(i, edi, DX, wordCount);
if (wordCount) {
// Decrement the ticks count by the number of iterations, minus
// one, since the main cpu loop will decrement one. Also,
// the count is predecremented before examined, so defintely
// don't roll it under zero.
BX_TICKN(wordCount-1);
RCX = ECX - (wordCount-1);
incr = wordCount << 1; // count * 2.
}
else {
// trigger any segment or page faults before reading from IO port
value16 = read_RMW_virtual_word(BX_SEG_REG_ES, edi);
value16 = BX_INP(DX, 2);
write_RMW_virtual_word(value16);
}
}
else
#endif
{
// trigger any segment or page faults before reading from IO port
value16 = read_RMW_virtual_word_32(BX_SEG_REG_ES, edi);
value16 = BX_INP(DX, 2);
write_RMW_virtual_word(value16);
}
if (BX_CPU_THIS_PTR get_DF())
RDI = EDI - incr;
else
RDI = EDI + incr;
}
#if BX_SUPPORT_X86_64
// 16-bit operand size, 64-bit address size
void BX_CPP_AttrRegparmN(1) BX_CPU_C::INSW64_YwDX(bxInstruction_c *i)
{
// trigger any segment or page faults before reading from IO port
Bit16u value16 = read_RMW_virtual_word_64(BX_SEG_REG_ES, RDI);
value16 = BX_INP(DX, 2);
write_RMW_virtual_word(value16);
if (BX_CPU_THIS_PTR get_DF())
RDI -= 2;
else
RDI += 2;
}
#endif
void BX_CPP_AttrRegparmN(1) BX_CPU_C::REP_INSD_YdDX(bxInstruction_c *i)
{
if (! allow_io(i, DX, 4)) {
BX_DEBUG(("INSD_YdDX: I/O access not allowed !"));
exception(BX_GP_EXCEPTION, 0);
}
#if BX_SUPPORT_X86_64
if (i->as64L()) {
BX_CPU_THIS_PTR repeat(i, &BX_CPU_C::INSD64_YdDX);
}
else
#endif
if (i->as32L()) {
BX_CPU_THIS_PTR repeat(i, &BX_CPU_C::INSD32_YdDX);
BX_CLEAR_64BIT_HIGH(BX_64BIT_REG_RDI); // always clear upper part of RDI
}
else {
BX_CPU_THIS_PTR repeat(i, &BX_CPU_C::INSD16_YdDX);
}
}
// 32-bit operand size, 16-bit address size
void BX_CPP_AttrRegparmN(1) BX_CPU_C::INSD16_YdDX(bxInstruction_c *i)
{
// trigger any segment or page faults before reading from IO port
Bit32u value32 = read_RMW_virtual_dword_32(BX_SEG_REG_ES, DI);
value32 = BX_INP(DX, 4);
write_RMW_virtual_dword(value32);
if (BX_CPU_THIS_PTR get_DF())
DI -= 4;
else
DI += 4;
}
// 32-bit operand size, 32-bit address size
void BX_CPP_AttrRegparmN(1) BX_CPU_C::INSD32_YdDX(bxInstruction_c *i)
{
// trigger any segment or page faults before reading from IO port
Bit32u value32 = read_RMW_virtual_dword(BX_SEG_REG_ES, EDI);
value32 = BX_INP(DX, 4);
write_RMW_virtual_dword(value32);
if (BX_CPU_THIS_PTR get_DF())
RDI = EDI - 4;
else
RDI = EDI + 4;
}
#if BX_SUPPORT_X86_64
// 32-bit operand size, 64-bit address size
void BX_CPP_AttrRegparmN(1) BX_CPU_C::INSD64_YdDX(bxInstruction_c *i)
{
// trigger any segment or page faults before reading from IO port
Bit32u value32 = read_RMW_virtual_dword_64(BX_SEG_REG_ES, RDI);
value32 = BX_INP(DX, 4);
write_RMW_virtual_dword(value32);
if (BX_CPU_THIS_PTR get_DF())
RDI -= 4;
else
RDI += 4;
}
#endif
//
// REP OUTS methods
//
void BX_CPP_AttrRegparmN(1) BX_CPU_C::REP_OUTSB_DXXb(bxInstruction_c *i)
{
if (! allow_io(i, DX, 1)) {
BX_DEBUG(("OUTSB_DXXb: I/O access not allowed !"));
exception(BX_GP_EXCEPTION, 0);
}
#if BX_SUPPORT_X86_64
if (i->as64L()) {
BX_CPU_THIS_PTR repeat(i, &BX_CPU_C::OUTSB64_DXXb);
}
else
#endif
if (i->as32L()) {
BX_CPU_THIS_PTR repeat(i, &BX_CPU_C::OUTSB32_DXXb);
BX_CLEAR_64BIT_HIGH(BX_64BIT_REG_RSI); // always clear upper part of RSI
}
else {
BX_CPU_THIS_PTR repeat(i, &BX_CPU_C::OUTSB16_DXXb);
}
}
// 16-bit address size
void BX_CPP_AttrRegparmN(1) BX_CPU_C::OUTSB16_DXXb(bxInstruction_c *i)
{
Bit8u value8 = read_virtual_byte_32(i->seg(), SI);
BX_OUTP(DX, value8, 1);
if (BX_CPU_THIS_PTR get_DF())
SI--;
else
SI++;
}
// 32-bit address size
void BX_CPP_AttrRegparmN(1) BX_CPU_C::OUTSB32_DXXb(bxInstruction_c *i)
{
Bit8u value8 = read_virtual_byte(i->seg(), ESI);
BX_OUTP(DX, value8, 1);
if (BX_CPU_THIS_PTR get_DF())
RSI = ESI - 1;
else
RSI = ESI + 1;
}
#if BX_SUPPORT_X86_64
// 64-bit address size
void BX_CPP_AttrRegparmN(1) BX_CPU_C::OUTSB64_DXXb(bxInstruction_c *i)
{
Bit8u value8 = read_virtual_byte_64(i->seg(), RSI);
BX_OUTP(DX, value8, 1);
if (BX_CPU_THIS_PTR get_DF())
RSI--;
else
RSI++;
}
#endif
void BX_CPP_AttrRegparmN(1) BX_CPU_C::REP_OUTSW_DXXw(bxInstruction_c *i)
{
if (! allow_io(i, DX, 2)) {
BX_DEBUG(("OUTSW_DXXw: I/O access not allowed !"));
exception(BX_GP_EXCEPTION, 0);
}
#if BX_SUPPORT_X86_64
if (i->as64L()) {
BX_CPU_THIS_PTR repeat(i, &BX_CPU_C::OUTSW64_DXXw);
}
else
#endif
if (i->as32L()) {
BX_CPU_THIS_PTR repeat(i, &BX_CPU_C::OUTSW32_DXXw);
BX_CLEAR_64BIT_HIGH(BX_64BIT_REG_RSI); // always clear upper part of RSI
}
else {
BX_CPU_THIS_PTR repeat(i, &BX_CPU_C::OUTSW16_DXXw);
}
}
// 16-bit operand size, 16-bit address size
void BX_CPP_AttrRegparmN(1) BX_CPU_C::OUTSW16_DXXw(bxInstruction_c *i)
{
Bit16u value16 = read_virtual_word_32(i->seg(), SI);
BX_OUTP(DX, value16, 2);
if (BX_CPU_THIS_PTR get_DF())
SI -= 2;
else
SI += 2;
}
// 16-bit operand size, 32-bit address size
void BX_CPP_AttrRegparmN(1) BX_CPU_C::OUTSW32_DXXw(bxInstruction_c *i)
{
Bit16u value16;
Bit32u esi = ESI;
unsigned incr = 2;
#if (BX_SupportRepeatSpeedups) && (BX_DEBUGGER == 0)
/* If conditions are right, we can transfer IO to physical memory
* in a batch, rather than one instruction at a time.
*/
if (i->repUsedL() && !BX_CPU_THIS_PTR async_event) {
Bit32u wordCount = ECX;
wordCount = FastRepOUTSW(i, i->seg(), esi, DX, wordCount);
if (wordCount) {
// Decrement eCX. Note, the main loop will decrement 1 also, so
// decrement by one less than expected, like the case above.
BX_TICKN(wordCount-1); // Main cpu loop also decrements one more.
RCX = ECX - (wordCount-1);
incr = wordCount << 1; // count * 2.
}
else {
value16 = read_virtual_word(i->seg(), esi);
BX_OUTP(DX, value16, 2);
}
}
else
#endif
{
value16 = read_virtual_word(i->seg(), esi);
BX_OUTP(DX, value16, 2);
}
if (BX_CPU_THIS_PTR get_DF())
RSI = ESI - incr;
else
RSI = ESI + incr;
}
#if BX_SUPPORT_X86_64
// 16-bit operand size, 64-bit address size
void BX_CPP_AttrRegparmN(1) BX_CPU_C::OUTSW64_DXXw(bxInstruction_c *i)
{
Bit16u value16 = read_virtual_word_64(i->seg(), RSI);
BX_OUTP(DX, value16, 2);
if (BX_CPU_THIS_PTR get_DF())
RSI -= 2;
else
RSI += 2;
}
#endif
void BX_CPP_AttrRegparmN(1) BX_CPU_C::REP_OUTSD_DXXd(bxInstruction_c *i)
{
if (! allow_io(i, DX, 4)) {
BX_DEBUG(("OUTSD_DXXd: I/O access not allowed !"));
exception(BX_GP_EXCEPTION, 0);
}
#if BX_SUPPORT_X86_64
if (i->as64L()) {
BX_CPU_THIS_PTR repeat(i, &BX_CPU_C::OUTSD64_DXXd);
}
else
#endif
if (i->as32L()) {
BX_CPU_THIS_PTR repeat(i, &BX_CPU_C::OUTSD32_DXXd);
BX_CLEAR_64BIT_HIGH(BX_64BIT_REG_RSI); // always clear upper part of RSI
}
else {
BX_CPU_THIS_PTR repeat(i, &BX_CPU_C::OUTSD16_DXXd);
}
}
// 32-bit operand size, 16-bit address size
void BX_CPP_AttrRegparmN(1) BX_CPU_C::OUTSD16_DXXd(bxInstruction_c *i)
{
Bit32u value32 = read_virtual_dword_32(i->seg(), SI);
BX_OUTP(DX, value32, 4);
if (BX_CPU_THIS_PTR get_DF())
SI -= 4;
else
SI += 4;
}
// 32-bit operand size, 32-bit address size
void BX_CPP_AttrRegparmN(1) BX_CPU_C::OUTSD32_DXXd(bxInstruction_c *i)
{
Bit32u value32 = read_virtual_dword(i->seg(), ESI);
BX_OUTP(DX, value32, 4);
if (BX_CPU_THIS_PTR get_DF())
RSI = ESI - 4;
else
RSI = ESI + 4;
}
#if BX_SUPPORT_X86_64
// 32-bit operand size, 64-bit address size
void BX_CPP_AttrRegparmN(1) BX_CPU_C::OUTSD64_DXXd(bxInstruction_c *i)
{
Bit32u value32 = read_virtual_dword_64(i->seg(), RSI);
BX_OUTP(DX, value32, 4);
if (BX_CPU_THIS_PTR get_DF())
RSI -= 4;
else
RSI += 4;
}
#endif
//
// non repeatable IN/OUT methods
//
void BX_CPP_AttrRegparmN(1) BX_CPU_C::IN_ALIb(bxInstruction_c *i)
{
unsigned port = i->Ib();
if (! allow_io(i, port, 1)) {
BX_DEBUG(("IN_ALIb: I/O access not allowed !"));
exception(BX_GP_EXCEPTION, 0);
}
AL = BX_INP(port, 1);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::IN_AXIb(bxInstruction_c *i)
{
unsigned port = i->Ib();
if (! allow_io(i, port, 2)) {
BX_DEBUG(("IN_AXIb: I/O access not allowed !"));
exception(BX_GP_EXCEPTION, 0);
}
AX = BX_INP(port, 2);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::IN_EAXIb(bxInstruction_c *i)
{
unsigned port = i->Ib();
if (! allow_io(i, port, 4)) {
BX_DEBUG(("IN_EAXIb: I/O access not allowed !"));
exception(BX_GP_EXCEPTION, 0);
}
RAX = BX_INP(port, 4);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::OUT_IbAL(bxInstruction_c *i)
{
unsigned port = i->Ib();
if (! allow_io(i, port, 1)) {
BX_DEBUG(("OUT_IbAL: I/O access not allowed !"));
exception(BX_GP_EXCEPTION, 0);
}
BX_OUTP(port, AL, 1);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::OUT_IbAX(bxInstruction_c *i)
{
unsigned port = i->Ib();
if (! allow_io(i, port, 2)) {
BX_DEBUG(("OUT_IbAX: I/O access not allowed !"));
exception(BX_GP_EXCEPTION, 0);
}
BX_OUTP(port, AX, 2);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::OUT_IbEAX(bxInstruction_c *i)
{
unsigned port = i->Ib();
if (! allow_io(i, port, 4)) {
BX_DEBUG(("OUT_IbEAX: I/O access not allowed !"));
exception(BX_GP_EXCEPTION, 0);
}
BX_OUTP(port, EAX, 4);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::IN_ALDX(bxInstruction_c *i)
{
unsigned port = DX;
if (! allow_io(i, port, 1)) {
BX_DEBUG(("IN_ALDX: I/O access not allowed !"));
exception(BX_GP_EXCEPTION, 0);
}
AL = BX_INP(port, 1);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::IN_AXDX(bxInstruction_c *i)
{
unsigned port = DX;
if (! allow_io(i, port, 2)) {
BX_DEBUG(("IN_AXDX: I/O access not allowed !"));
exception(BX_GP_EXCEPTION, 0);
}
AX = BX_INP(port, 2);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::IN_EAXDX(bxInstruction_c *i)
{
unsigned port = DX;
if (! allow_io(i, port, 4)) {
BX_DEBUG(("IN_EAXDX: I/O access not allowed !"));
exception(BX_GP_EXCEPTION, 0);
}
RAX = BX_INP(port, 4);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::OUT_DXAL(bxInstruction_c *i)
{
unsigned port = DX;
if (! allow_io(i, port, 1)) {
BX_DEBUG(("OUT_DXAL: I/O access not allowed !"));
exception(BX_GP_EXCEPTION, 0);
}
BX_OUTP(port, AL, 1);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::OUT_DXAX(bxInstruction_c *i)
{
unsigned port = DX;
if (! allow_io(i, port, 2)) {
BX_DEBUG(("OUT_DXAX: I/O access not allowed !"));
exception(BX_GP_EXCEPTION, 0);
}
BX_OUTP(port, AX, 2);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::OUT_DXEAX(bxInstruction_c *i)
{
unsigned port = DX;
if (! allow_io(i, port, 4)) {
BX_DEBUG(("OUT_DXEAX: I/O access not allowed !"));
exception(BX_GP_EXCEPTION, 0);
}
BX_OUTP(port, EAX, 4);
}
bx_bool BX_CPP_AttrRegparmN(3) BX_CPU_C::allow_io(bxInstruction_c *i, Bit16u port, unsigned len)
{
/* If CPL <= IOPL, then all IO portesses are accessible.
* Otherwise, must check the IO permission map on >286.
* On the 286, there is no IO permissions map */
if (BX_CPU_THIS_PTR cr0.get_PE() && (BX_CPU_THIS_PTR get_VM() || (CPL>BX_CPU_THIS_PTR get_IOPL())))
{
if (BX_CPU_THIS_PTR tr.cache.valid==0 ||
(BX_CPU_THIS_PTR tr.cache.type != BX_SYS_SEGMENT_AVAIL_386_TSS &&
BX_CPU_THIS_PTR tr.cache.type != BX_SYS_SEGMENT_BUSY_386_TSS))
{
BX_ERROR(("allow_io(): TR doesn't point to a valid 32bit TSS, TR.TYPE=%u", BX_CPU_THIS_PTR tr.cache.type));
return(0);
}
if (BX_CPU_THIS_PTR tr.cache.u.segment.limit_scaled < 103) {
BX_ERROR(("allow_io(): TR.limit < 103"));
return(0);
}
Bit32u io_base = system_read_word(BX_CPU_THIS_PTR tr.cache.u.segment.base + 102);
if ((io_base + port/8) >= BX_CPU_THIS_PTR tr.cache.u.segment.limit_scaled) {
BX_DEBUG(("allow_io(): IO port %x (len %d) outside TSS IO permission map (base=%x, limit=%x) #GP(0)",
port, len, io_base, BX_CPU_THIS_PTR tr.cache.u.segment.limit_scaled));
return(0);
}
Bit16u permission16 = system_read_word(BX_CPU_THIS_PTR tr.cache.u.segment.base + io_base + port/8);
unsigned bit_index = port & 0x7;
unsigned mask = (1 << len) - 1;
if ((permission16 >> bit_index) & mask)
return(0);
}
#if BX_SUPPORT_VMX
VMexit_IO(i, port, len);
#endif
#if BX_X86_DEBUGGER
iobreakpoint_match(port, len);
#endif
return(1);
}

564
simulators/bochs/cpu/iret.cc Executable file
View File

@ -0,0 +1,564 @@
////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2005-2009 Stanislav Shwartsman
// 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
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA B 02110-1301 USA
//
/////////////////////////////////////////////////////////////////////////
#define NEED_CPU_REG_SHORTCUTS 1
#include "bochs.h"
#include "cpu.h"
#define LOG_THIS BX_CPU_THIS_PTR
#if BX_SUPPORT_X86_64==0
// Make life easier merging cpu64 & cpu code.
#define RIP EIP
#endif
void BX_CPP_AttrRegparmN(1)
BX_CPU_C::iret_protected(bxInstruction_c *i)
{
Bit16u raw_cs_selector, raw_ss_selector;
bx_selector_t cs_selector, ss_selector;
Bit32u dword1, dword2;
bx_descriptor_t cs_descriptor, ss_descriptor;
#if BX_SUPPORT_X86_64
if (long_mode()) {
long_iret(i);
return;
}
#endif
if (BX_CPU_THIS_PTR get_NT()) /* NT = 1: RETURN FROM NESTED TASK */
{
/* what's the deal with NT & VM ? */
Bit16u raw_link_selector;
bx_selector_t link_selector;
bx_descriptor_t tss_descriptor;
if (BX_CPU_THIS_PTR get_VM())
BX_PANIC(("iret_protected: VM sholdn't be set here !"));
BX_DEBUG(("IRET: nested task return"));
if (BX_CPU_THIS_PTR tr.cache.valid==0)
BX_PANIC(("IRET: TR not valid"));
// examine back link selector in TSS addressed by current TR
raw_link_selector = system_read_word(BX_CPU_THIS_PTR tr.cache.u.segment.base);
// must specify global, else #TS(new TSS selector)
parse_selector(raw_link_selector, &link_selector);
if (link_selector.ti) {
BX_ERROR(("iret: link selector.ti=1"));
exception(BX_TS_EXCEPTION, raw_link_selector & 0xfffc);
}
// index must be within GDT limits, else #TS(new TSS selector)
fetch_raw_descriptor(&link_selector, &dword1, &dword2, BX_TS_EXCEPTION);
// AR byte must specify TSS, else #TS(new TSS selector)
// new TSS must be busy, else #TS(new TSS selector)
parse_descriptor(dword1, dword2, &tss_descriptor);
if (tss_descriptor.valid==0 || tss_descriptor.segment) {
BX_ERROR(("iret: TSS selector points to bad TSS"));
exception(BX_TS_EXCEPTION, raw_link_selector & 0xfffc);
}
if (tss_descriptor.type != BX_SYS_SEGMENT_BUSY_286_TSS &&
tss_descriptor.type != BX_SYS_SEGMENT_BUSY_386_TSS)
{
BX_ERROR(("iret: TSS selector points to bad TSS"));
exception(BX_TS_EXCEPTION, raw_link_selector & 0xfffc);
}
// TSS must be present, else #NP(new TSS selector)
if (! IS_PRESENT(tss_descriptor)) {
BX_ERROR(("iret: task descriptor.p == 0"));
exception(BX_NP_EXCEPTION, raw_link_selector & 0xfffc);
}
// switch tasks (without nesting) to TSS specified by back link selector
task_switch(i, &link_selector, &tss_descriptor,
BX_TASK_FROM_IRET, dword1, dword2);
// mark the task just abandoned as not busy
// EIP must be within code seg limit, else #GP(0)
if (EIP > BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.limit_scaled) {
BX_ERROR(("iret: EIP > CS.limit"));
exception(BX_GP_EXCEPTION, 0);
}
return;
}
/* NT = 0: INTERRUPT RETURN ON STACK -or STACK_RETURN_TO_V86 */
unsigned top_nbytes_same;
Bit32u new_eip = 0, new_esp, temp_ESP, new_eflags = 0;
Bit16u new_ip = 0, new_flags = 0;
/* 16bit opsize | 32bit opsize
* ==============================
* SS eSP+8 | SS eSP+16
* SP eSP+6 | ESP eSP+12
* -------------------------------
* FLAGS eSP+4 | EFLAGS eSP+8
* CS eSP+2 | CS eSP+4
* IP eSP+0 | EIP eSP+0
*/
if (i->os32L()) {
top_nbytes_same = 12;
}
else {
top_nbytes_same = 6;
}
if (BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.d_b)
temp_ESP = ESP;
else
temp_ESP = SP;
if (i->os32L()) {
new_eflags = read_virtual_dword_32(BX_SEG_REG_SS, temp_ESP + 8);
raw_cs_selector = (Bit16u) read_virtual_dword_32(BX_SEG_REG_SS, temp_ESP + 4);
new_eip = read_virtual_dword_32(BX_SEG_REG_SS, temp_ESP + 0);
// if VM=1 in flags image on stack then STACK_RETURN_TO_V86
if (new_eflags & EFlagsVMMask) {
if (CPL == 0) {
stack_return_to_v86(new_eip, raw_cs_selector, new_eflags);
return;
}
else BX_INFO(("iret: VM set on stack, CPL!=0"));
}
}
else {
new_flags = read_virtual_word_32(BX_SEG_REG_SS, temp_ESP + 4);
raw_cs_selector = read_virtual_word_32(BX_SEG_REG_SS, temp_ESP + 2);
new_ip = read_virtual_word_32(BX_SEG_REG_SS, temp_ESP + 0);
}
parse_selector(raw_cs_selector, &cs_selector);
// return CS selector must be non-null, else #GP(0)
if ((raw_cs_selector & 0xfffc) == 0) {
BX_ERROR(("iret: return CS selector null"));
exception(BX_GP_EXCEPTION, 0);
}
// selector index must be within descriptor table limits,
// else #GP(return selector)
fetch_raw_descriptor(&cs_selector, &dword1, &dword2, BX_GP_EXCEPTION);
parse_descriptor(dword1, dword2, &cs_descriptor);
// return CS selector RPL must be >= CPL, else #GP(return selector)
if (cs_selector.rpl < CPL) {
BX_ERROR(("iret: return selector RPL < CPL"));
exception(BX_GP_EXCEPTION, raw_cs_selector & 0xfffc);
}
// check code-segment descriptor
check_cs(&cs_descriptor, raw_cs_selector, 0, cs_selector.rpl);
if (cs_selector.rpl == CPL) { /* INTERRUPT RETURN TO SAME LEVEL */
/* top 6/12 bytes on stack must be within limits, else #SS(0) */
/* satisfied above */
if (i->os32L()) {
/* load CS-cache with new code segment descriptor */
branch_far32(&cs_selector, &cs_descriptor, new_eip, cs_selector.rpl);
// ID,VIP,VIF,AC,VM,RF,x,NT,IOPL,OF,DF,IF,TF,SF,ZF,x,AF,x,PF,x,CF
Bit32u changeMask = EFlagsOSZAPCMask | EFlagsTFMask |
EFlagsDFMask | EFlagsNTMask | EFlagsRFMask;
#if BX_CPU_LEVEL >= 4
changeMask |= (EFlagsIDMask | EFlagsACMask); // ID/AC
#endif
if (CPL <= BX_CPU_THIS_PTR get_IOPL())
changeMask |= EFlagsIFMask;
if (CPL == 0)
changeMask |= EFlagsVIPMask | EFlagsVIFMask | EFlagsIOPLMask;
// IF only changed if (CPL <= EFLAGS.IOPL)
// VIF, VIP, IOPL only changed if CPL == 0
// VM unaffected
writeEFlags(new_eflags, changeMask);
}
else {
/* load CS-cache with new code segment descriptor */
branch_far32(&cs_selector, &cs_descriptor, (Bit32u) new_ip, cs_selector.rpl);
/* load flags with third word on stack */
write_flags(new_flags, CPL==0, CPL<=BX_CPU_THIS_PTR get_IOPL());
}
/* increment stack by 6/12 */
if (BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.d_b)
ESP += top_nbytes_same;
else
SP += top_nbytes_same;
return;
}
else { /* INTERRUPT RETURN TO OUTER PRIVILEGE LEVEL */
/* 16bit opsize | 32bit opsize
* ==============================
* SS eSP+8 | SS eSP+16
* SP eSP+6 | ESP eSP+12
* FLAGS eSP+4 | EFLAGS eSP+8
* CS eSP+2 | CS eSP+4
* IP eSP+0 | EIP eSP+0
*/
/* examine return SS selector and associated descriptor */
if (i->os32L()) {
raw_ss_selector = read_virtual_word_32(BX_SEG_REG_SS, temp_ESP + 16);
}
else {
raw_ss_selector = read_virtual_word_32(BX_SEG_REG_SS, temp_ESP + 8);
}
/* selector must be non-null, else #GP(0) */
if ((raw_ss_selector & 0xfffc) == 0) {
BX_ERROR(("iret: SS selector null"));
exception(BX_GP_EXCEPTION, 0);
}
parse_selector(raw_ss_selector, &ss_selector);
/* selector RPL must = RPL of return CS selector,
* else #GP(SS selector) */
if (ss_selector.rpl != cs_selector.rpl) {
BX_ERROR(("iret: SS.rpl != CS.rpl"));
exception(BX_GP_EXCEPTION, raw_ss_selector & 0xfffc);
}
/* selector index must be within its descriptor table limits,
* else #GP(SS selector) */
fetch_raw_descriptor(&ss_selector, &dword1, &dword2, BX_GP_EXCEPTION);
parse_descriptor(dword1, dword2, &ss_descriptor);
/* AR byte must indicate a writable data segment,
* else #GP(SS selector) */
if (ss_descriptor.valid==0 || ss_descriptor.segment==0 ||
IS_CODE_SEGMENT(ss_descriptor.type) ||
!IS_DATA_SEGMENT_WRITEABLE(ss_descriptor.type))
{
BX_ERROR(("iret: SS AR byte not writable or code segment"));
exception(BX_GP_EXCEPTION, raw_ss_selector & 0xfffc);
}
/* stack segment DPL must equal the RPL of the return CS selector,
* else #GP(SS selector) */
if (ss_descriptor.dpl != cs_selector.rpl) {
BX_ERROR(("iret: SS.dpl != CS selector RPL"));
exception(BX_GP_EXCEPTION, raw_ss_selector & 0xfffc);
}
/* SS must be present, else #NP(SS selector) */
if (! IS_PRESENT(ss_descriptor)) {
BX_ERROR(("iret: SS not present!"));
exception(BX_NP_EXCEPTION, raw_ss_selector & 0xfffc);
}
if (i->os32L()) {
new_esp = read_virtual_dword_32(BX_SEG_REG_SS, temp_ESP + 12);
new_eflags = read_virtual_dword_32(BX_SEG_REG_SS, temp_ESP + 8);
new_eip = read_virtual_dword_32(BX_SEG_REG_SS, temp_ESP + 0);
}
else {
new_esp = read_virtual_word_32(BX_SEG_REG_SS, temp_ESP + 6);
new_eflags = read_virtual_word_32(BX_SEG_REG_SS, temp_ESP + 4);
new_eip = read_virtual_word_32(BX_SEG_REG_SS, temp_ESP + 0);
}
// ID,VIP,VIF,AC,VM,RF,x,NT,IOPL,OF,DF,IF,TF,SF,ZF,x,AF,x,PF,x,CF
Bit32u changeMask = EFlagsOSZAPCMask | EFlagsTFMask |
EFlagsDFMask | EFlagsNTMask | EFlagsRFMask;
#if BX_CPU_LEVEL >= 4
changeMask |= (EFlagsIDMask | EFlagsACMask); // ID/AC
#endif
if (CPL <= BX_CPU_THIS_PTR get_IOPL())
changeMask |= EFlagsIFMask;
if (CPL == 0)
changeMask |= EFlagsVIPMask | EFlagsVIFMask | EFlagsIOPLMask;
if (! i->os32L()) // 16 bit
changeMask &= 0xffff;
/* load CS:EIP from stack */
/* load the CS-cache with CS descriptor */
/* set CPL to the RPL of the return CS selector */
branch_far32(&cs_selector, &cs_descriptor, new_eip, cs_selector.rpl);
// IF only changed if (prev_CPL <= EFLAGS.IOPL)
// VIF, VIP, IOPL only changed if prev_CPL == 0
// VM unaffected
writeEFlags(new_eflags, changeMask);
// load SS:eSP from stack
// load the SS-cache with SS descriptor
load_ss(&ss_selector, &ss_descriptor, cs_selector.rpl);
if (ss_descriptor.u.segment.d_b)
ESP = new_esp;
else
SP = new_esp;
validate_seg_regs();
}
}
#if BX_SUPPORT_X86_64
void BX_CPP_AttrRegparmN(1)
BX_CPU_C::long_iret(bxInstruction_c *i)
{
Bit16u raw_cs_selector, raw_ss_selector;
bx_selector_t cs_selector, ss_selector;
Bit32u dword1, dword2;
bx_descriptor_t cs_descriptor, ss_descriptor;
Bit32u new_eflags;
Bit64u new_rip, new_rsp, temp_RSP;
BX_DEBUG (("LONG MODE IRET"));
if (BX_CPU_THIS_PTR get_NT()) {
BX_ERROR(("iret64: return from nested task in x86-64 mode !"));
exception(BX_GP_EXCEPTION, 0);
}
/* 64bit opsize
* ============
* SS eSP+32
* ESP eSP+24
* -------------
* EFLAGS eSP+16
* CS eSP+8
* EIP eSP+0
*/
if (StackAddrSize64()) temp_RSP = RSP;
else {
if (BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.d_b) temp_RSP = ESP;
else temp_RSP = SP;
}
unsigned top_nbytes_same = 0; /* stop compiler warnings */
#if BX_SUPPORT_X86_64
if (i->os64L()) {
new_eflags = (Bit32u) read_virtual_qword_64(BX_SEG_REG_SS, temp_RSP + 16);
raw_cs_selector = (Bit16u) read_virtual_qword_64(BX_SEG_REG_SS, temp_RSP + 8);
new_rip = read_virtual_qword_64(BX_SEG_REG_SS, temp_RSP + 0);
top_nbytes_same = 24;
}
else
#endif
if (i->os32L()) {
new_eflags = read_virtual_dword(BX_SEG_REG_SS, temp_RSP + 8);
raw_cs_selector = (Bit16u) read_virtual_dword(BX_SEG_REG_SS, temp_RSP + 4);
new_rip = (Bit64u) read_virtual_dword(BX_SEG_REG_SS, temp_RSP + 0);
top_nbytes_same = 12;
}
else {
new_eflags = read_virtual_word(BX_SEG_REG_SS, temp_RSP + 4);
raw_cs_selector = read_virtual_word(BX_SEG_REG_SS, temp_RSP + 2);
new_rip = (Bit64u) read_virtual_word(BX_SEG_REG_SS, temp_RSP + 0);
top_nbytes_same = 6;
}
// ignore VM flag in long mode
new_eflags &= ~EFlagsVMMask;
parse_selector(raw_cs_selector, &cs_selector);
// return CS selector must be non-null, else #GP(0)
if ((raw_cs_selector & 0xfffc) == 0) {
BX_ERROR(("iret64: return CS selector null"));
exception(BX_GP_EXCEPTION, 0);
}
// selector index must be within descriptor table limits,
// else #GP(return selector)
fetch_raw_descriptor(&cs_selector, &dword1, &dword2, BX_GP_EXCEPTION);
parse_descriptor(dword1, dword2, &cs_descriptor);
// return CS selector RPL must be >= CPL, else #GP(return selector)
if (cs_selector.rpl < CPL) {
BX_ERROR(("iret64: return selector RPL < CPL"));
exception(BX_GP_EXCEPTION, raw_cs_selector & 0xfffc);
}
// check code-segment descriptor
check_cs(&cs_descriptor, raw_cs_selector, 0, cs_selector.rpl);
/* INTERRUPT RETURN TO SAME PRIVILEGE LEVEL */
if (cs_selector.rpl == CPL && !i->os64L())
{
/* top 24 bytes on stack must be within limits, else #SS(0) */
/* satisfied above */
/* load CS:EIP from stack */
/* load CS-cache with new code segment descriptor */
if(cs_descriptor.u.segment.l) {
branch_far64(&cs_selector, &cs_descriptor, new_rip, CPL);
}
else {
branch_far32(&cs_selector, &cs_descriptor, (Bit32u) new_rip, CPL);
}
// ID,VIP,VIF,AC,VM,RF,x,NT,IOPL,OF,DF,IF,TF,SF,ZF,x,AF,x,PF,x,CF
Bit32u changeMask = EFlagsOSZAPCMask | EFlagsTFMask | EFlagsDFMask |
EFlagsNTMask | EFlagsRFMask | EFlagsIDMask | EFlagsACMask;
if (CPL <= BX_CPU_THIS_PTR get_IOPL())
changeMask |= EFlagsIFMask;
if (CPL == 0)
changeMask |= EFlagsVIPMask | EFlagsVIFMask | EFlagsIOPLMask;
if (! i->os32L()) // 16 bit
changeMask &= 0xffff;
// IF only changed if (CPL <= EFLAGS.IOPL)
// VIF, VIP, IOPL only changed if CPL == 0
// VM unaffected
writeEFlags(new_eflags, changeMask);
/* we are NOT in 64-bit mode */
if (BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.d_b)
ESP += top_nbytes_same;
else
SP += top_nbytes_same;
}
else { /* INTERRUPT RETURN TO OUTER PRIVILEGE LEVEL or 64 BIT MODE */
/* 64bit opsize
* ============
* SS eSP+32
* ESP eSP+24
* EFLAGS eSP+16
* CS eSP+8
* EIP eSP+0
*/
/* examine return SS selector and associated descriptor */
#if BX_SUPPORT_X86_64
if (i->os64L()) {
raw_ss_selector = (Bit16u) read_virtual_qword_64(BX_SEG_REG_SS, temp_RSP + 32);
new_rsp = read_virtual_qword_64(BX_SEG_REG_SS, temp_RSP + 24);
}
else
#endif
{
if (i->os32L()) {
raw_ss_selector = (Bit16u) read_virtual_dword(BX_SEG_REG_SS, temp_RSP + 16);
new_rsp = (Bit64u) read_virtual_dword(BX_SEG_REG_SS, temp_RSP + 12);
}
else {
raw_ss_selector = read_virtual_word(BX_SEG_REG_SS, temp_RSP + 8);
new_rsp = (Bit64u) read_virtual_word(BX_SEG_REG_SS, temp_RSP + 6);
}
}
if ((raw_ss_selector & 0xfffc) == 0) {
if (! IS_LONG64_SEGMENT(cs_descriptor) || cs_selector.rpl == 3) {
BX_ERROR(("iret64: SS selector null"));
exception(BX_GP_EXCEPTION, 0);
}
}
else {
parse_selector(raw_ss_selector, &ss_selector);
/* selector RPL must = RPL of return CS selector,
* else #GP(SS selector) */
if (ss_selector.rpl != cs_selector.rpl) {
BX_ERROR(("iret64: SS.rpl != CS.rpl"));
exception(BX_GP_EXCEPTION, raw_ss_selector & 0xfffc);
}
/* selector index must be within its descriptor table limits,
* else #GP(SS selector) */
fetch_raw_descriptor(&ss_selector, &dword1, &dword2, BX_GP_EXCEPTION);
parse_descriptor(dword1, dword2, &ss_descriptor);
/* AR byte must indicate a writable data segment,
* else #GP(SS selector) */
if (ss_descriptor.valid==0 || ss_descriptor.segment==0 ||
IS_CODE_SEGMENT(ss_descriptor.type) ||
!IS_DATA_SEGMENT_WRITEABLE(ss_descriptor.type))
{
BX_ERROR(("iret64: SS AR byte not writable or code segment"));
exception(BX_GP_EXCEPTION, raw_ss_selector & 0xfffc);
}
/* stack segment DPL must equal the RPL of the return CS selector,
* else #GP(SS selector) */
if (ss_descriptor.dpl != cs_selector.rpl) {
BX_ERROR(("iret64: SS.dpl != CS selector RPL"));
exception(BX_GP_EXCEPTION, raw_ss_selector & 0xfffc);
}
/* SS must be present, else #NP(SS selector) */
if (! IS_PRESENT(ss_descriptor)) {
BX_ERROR(("iret64: SS not present!"));
exception(BX_NP_EXCEPTION, raw_ss_selector & 0xfffc);
}
}
Bit8u prev_cpl = CPL; /* previous CPL */
// ID,VIP,VIF,AC,VM,RF,x,NT,IOPL,OF,DF,IF,TF,SF,ZF,x,AF,x,PF,x,CF
Bit32u changeMask = EFlagsOSZAPCMask | EFlagsTFMask | EFlagsDFMask |
EFlagsNTMask | EFlagsRFMask | EFlagsIDMask | EFlagsACMask;
if (prev_cpl <= BX_CPU_THIS_PTR get_IOPL())
changeMask |= EFlagsIFMask;
if (prev_cpl == 0)
changeMask |= EFlagsVIPMask | EFlagsVIFMask | EFlagsIOPLMask;
if (! i->os32L()) // 16 bit
changeMask &= 0xffff;
/* set CPL to the RPL of the return CS selector */
branch_far64(&cs_selector, &cs_descriptor, new_rip, cs_selector.rpl);
// IF only changed if (prev_CPL <= EFLAGS.IOPL)
// VIF, VIP, IOPL only changed if prev_CPL == 0
// VM unaffected
writeEFlags(new_eflags, changeMask);
if ((raw_ss_selector & 0xfffc) != 0) {
// load SS:RSP from stack
// load the SS-cache with SS descriptor
load_ss(&ss_selector, &ss_descriptor, cs_selector.rpl);
}
else {
// we are in 64-bit mode !
load_null_selector(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS], raw_ss_selector);
}
if (StackAddrSize64()) RSP = new_rsp;
else {
if (ss_descriptor.u.segment.d_b) ESP = (Bit32u) new_rsp;
else SP = (Bit16u) new_rsp;
}
if (prev_cpl != CPL) validate_seg_regs();
}
}
#endif

292
simulators/bochs/cpu/jmp_far.cc Executable file
View File

@ -0,0 +1,292 @@
////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2005-2009 Stanislav Shwartsman
// 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
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA B 02110-1301 USA
//
////////////////////////////////////////////////////////////////////////
#define NEED_CPU_REG_SHORTCUTS 1
#include "bochs.h"
#include "cpu.h"
#define LOG_THIS BX_CPU_THIS_PTR
#if BX_SUPPORT_X86_64==0
// Make life easier merging cpu64 & cpu code.
#define RIP EIP
#endif
void BX_CPP_AttrRegparmN(3)
BX_CPU_C::jump_protected(bxInstruction_c *i, Bit16u cs_raw, bx_address disp)
{
bx_descriptor_t descriptor;
bx_selector_t selector;
Bit32u dword1, dword2;
/* destination selector is not null else #GP(0) */
if ((cs_raw & 0xfffc) == 0) {
BX_ERROR(("jump_protected: cs == 0"));
exception(BX_GP_EXCEPTION, 0);
}
parse_selector(cs_raw, &selector);
/* destination selector index is within its descriptor table
limits else #GP(selector) */
fetch_raw_descriptor(&selector, &dword1, &dword2, BX_GP_EXCEPTION);
/* examine AR byte of destination selector for legal values: */
parse_descriptor(dword1, dword2, &descriptor);
if (descriptor.segment) {
check_cs(&descriptor, cs_raw, BX_SELECTOR_RPL(cs_raw), CPL);
branch_far64(&selector, &descriptor, disp, CPL);
return;
}
else {
// call gate DPL must be >= CPL else #GP(gate selector)
if (descriptor.dpl < CPL) {
BX_ERROR(("jump_protected: call gate.dpl < CPL"));
exception(BX_GP_EXCEPTION, cs_raw & 0xfffc);
}
// call gate DPL must be >= gate selector RPL else #GP(gate selector)
if (descriptor.dpl < selector.rpl) {
BX_ERROR(("jump_protected: call gate.dpl < selector.rpl"));
exception(BX_GP_EXCEPTION, cs_raw & 0xfffc);
}
#if BX_SUPPORT_X86_64
if (long_mode()) {
if (descriptor.type != BX_386_CALL_GATE) {
BX_ERROR(("jump_protected: gate type %u unsupported in long mode", (unsigned) descriptor.type));
exception(BX_GP_EXCEPTION, cs_raw & 0xfffc);
}
// gate must be present else #NP(gate selector)
if (! IS_PRESENT(descriptor)) {
BX_ERROR(("jump_protected: call gate not present!"));
exception(BX_NP_EXCEPTION, cs_raw & 0xfffc);
}
jmp_call_gate64(&selector);
return;
}
#endif
switch (descriptor.type) {
case BX_SYS_SEGMENT_AVAIL_286_TSS:
case BX_SYS_SEGMENT_AVAIL_386_TSS:
if (descriptor.type==BX_SYS_SEGMENT_AVAIL_286_TSS)
BX_DEBUG(("jump_protected: jump to 286 TSS"));
else
BX_DEBUG(("jump_protected: jump to 386 TSS"));
if (descriptor.valid==0 || selector.ti) {
BX_ERROR(("jump_protected: jump to bad TSS selector !"));
exception(BX_GP_EXCEPTION, cs_raw & 0xfffc);
}
// TSS must be present, else #NP(TSS selector)
if (! IS_PRESENT(descriptor)) {
BX_ERROR(("jump_protected: jump to not present TSS !"));
exception(BX_NP_EXCEPTION, cs_raw & 0xfffc);
}
// SWITCH_TASKS _without_ nesting to TSS
task_switch(i, &selector, &descriptor, BX_TASK_FROM_JUMP, dword1, dword2);
// EIP must be in code seg limit, else #GP(0)
if (EIP > BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.limit_scaled) {
BX_ERROR(("jump_protected: EIP not within CS limits"));
exception(BX_GP_EXCEPTION, 0);
}
return;
case BX_TASK_GATE:
task_gate(i, &selector, &descriptor, BX_TASK_FROM_JUMP);
return;
case BX_286_CALL_GATE:
case BX_386_CALL_GATE:
jmp_call_gate(&selector, &descriptor);
return;
default:
BX_ERROR(("jump_protected: gate type %u unsupported", (unsigned) descriptor.type));
exception(BX_GP_EXCEPTION, cs_raw & 0xfffc);
}
}
}
void BX_CPU_C::task_gate(bxInstruction_c *i, bx_selector_t *selector, bx_descriptor_t *gate_descriptor, unsigned source)
{
Bit16u raw_tss_selector;
bx_selector_t tss_selector;
bx_descriptor_t tss_descriptor;
Bit32u dword1, dword2;
Bit32u temp_eIP;
// task gate must be present else #NP(gate selector)
if (! gate_descriptor->p) {
BX_ERROR(("task_gate: task gate not present"));
exception(BX_NP_EXCEPTION, selector->value & 0xfffc);
}
// examine selector to TSS, given in Task Gate descriptor
// must specify global in the local/global bit else #GP(TSS selector)
raw_tss_selector = gate_descriptor->u.taskgate.tss_selector;
parse_selector(raw_tss_selector, &tss_selector);
if (tss_selector.ti) {
BX_ERROR(("task_gate: tss_selector.ti=1"));
exception(BX_GP_EXCEPTION, raw_tss_selector & 0xfffc);
}
// index must be within GDT limits else #GP(TSS selector)
fetch_raw_descriptor(&tss_selector, &dword1, &dword2, BX_GP_EXCEPTION);
// descriptor AR byte must specify available TSS
// else #GP(TSS selector)
parse_descriptor(dword1, dword2, &tss_descriptor);
if (tss_descriptor.valid==0 || tss_descriptor.segment) {
BX_ERROR(("task_gate: TSS selector points to bad TSS"));
exception(BX_GP_EXCEPTION, raw_tss_selector & 0xfffc);
}
if (tss_descriptor.type!=BX_SYS_SEGMENT_AVAIL_286_TSS &&
tss_descriptor.type!=BX_SYS_SEGMENT_AVAIL_386_TSS)
{
BX_ERROR(("task_gate: TSS selector points to bad TSS"));
exception(BX_GP_EXCEPTION, raw_tss_selector & 0xfffc);
}
// task state segment must be present, else #NP(tss selector)
if (! IS_PRESENT(tss_descriptor)) {
BX_ERROR(("task_gate: TSS descriptor.p == 0"));
exception(BX_NP_EXCEPTION, raw_tss_selector & 0xfffc);
}
// SWITCH_TASKS _without_ nesting to TSS
task_switch(i, &tss_selector, &tss_descriptor, source, dword1, dword2);
// EIP must be within code segment limit, else #GP(0)
if (BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.d_b)
temp_eIP = EIP;
else
temp_eIP = IP;
if (temp_eIP > BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.limit_scaled) {
BX_ERROR(("task_gate: EIP > CS.limit"));
exception(BX_GP_EXCEPTION, 0);
}
}
void BX_CPP_AttrRegparmN(2)
BX_CPU_C::jmp_call_gate(bx_selector_t *selector, bx_descriptor_t *gate_descriptor)
{
bx_selector_t gate_cs_selector;
bx_descriptor_t gate_cs_descriptor;
Bit32u dword1, dword2;
if (gate_descriptor->type==BX_286_CALL_GATE)
BX_DEBUG(("jmp_call_gate: jump to 286 CALL GATE"));
else
BX_DEBUG(("jmp_call_gate: jump to 386 CALL GATE"));
// task gate must be present else #NP(gate selector)
if (! gate_descriptor->p) {
BX_ERROR(("jmp_call_gate: call gate not present!"));
exception(BX_NP_EXCEPTION, selector->value & 0xfffc);
}
// examine selector to code segment given in call gate descriptor
// selector must not be null, else #GP(0)
Bit16u gate_cs_raw = gate_descriptor->u.gate.dest_selector;
if ((gate_cs_raw & 0xfffc) == 0) {
BX_ERROR(("jmp_call_gate: CS selector null"));
exception(BX_GP_EXCEPTION, 0);
}
parse_selector(gate_cs_raw, &gate_cs_selector);
// selector must be within its descriptor table limits else #GP(CS selector)
fetch_raw_descriptor(&gate_cs_selector, &dword1, &dword2, BX_GP_EXCEPTION);
parse_descriptor(dword1, dword2, &gate_cs_descriptor);
// check code-segment descriptor
check_cs(&gate_cs_descriptor, gate_cs_raw, 0, CPL);
Bit32u temp_EIP = gate_descriptor->u.gate.dest_offset;
branch_far32(&gate_cs_selector, &gate_cs_descriptor, temp_EIP, CPL);
}
#if BX_SUPPORT_X86_64
void BX_CPP_AttrRegparmN(1)
BX_CPU_C::jmp_call_gate64(bx_selector_t *gate_selector)
{
bx_selector_t cs_selector;
Bit32u dword1, dword2, dword3;
bx_descriptor_t cs_descriptor;
bx_descriptor_t gate_descriptor;
BX_DEBUG(("jmp_call_gate64: jump to CALL GATE 64"));
fetch_raw_descriptor_64(gate_selector, &dword1, &dword2, &dword3, BX_GP_EXCEPTION);
parse_descriptor(dword1, dword2, &gate_descriptor);
Bit16u dest_selector = gate_descriptor.u.gate.dest_selector;
// selector must not be null else #GP(0)
if ((dest_selector & 0xfffc) == 0) {
BX_ERROR(("jmp_call_gate64: selector in gate null"));
exception(BX_GP_EXCEPTION, 0);
}
parse_selector(dest_selector, &cs_selector);
// selector must be within its descriptor table limits,
// else #GP(code segment selector)
fetch_raw_descriptor(&cs_selector, &dword1, &dword2, BX_GP_EXCEPTION);
parse_descriptor(dword1, dword2, &cs_descriptor);
// find the RIP in the gate_descriptor
Bit64u new_RIP = gate_descriptor.u.gate.dest_offset;
new_RIP |= ((Bit64u)dword3 << 32);
// AR byte of selected descriptor must indicate code segment,
// else #GP(code segment selector)
if (cs_descriptor.valid==0 || cs_descriptor.segment==0 ||
IS_DATA_SEGMENT(cs_descriptor.type))
{
BX_ERROR(("jmp_call_gate64: not code segment in 64-bit call gate"));
exception(BX_GP_EXCEPTION, dest_selector & 0xfffc);
}
// In long mode, only 64-bit call gates are allowed, and they must point
// to 64-bit code segments, else #GP(selector)
if (! IS_LONG64_SEGMENT(cs_descriptor) || cs_descriptor.u.segment.d_b)
{
BX_ERROR(("jmp_call_gate64: not 64-bit code segment in 64-bit call gate"));
exception(BX_GP_EXCEPTION, dest_selector & 0xfffc);
}
// check code-segment descriptor
check_cs(&cs_descriptor, dest_selector, 0, CPL);
// and transfer the control
branch_far64(&cs_selector, &cs_descriptor, new_RIP, CPL);
}
#endif

View File

@ -0,0 +1,299 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2001-2009 The Bochs Project
//
// 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
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA B 02110-1301 USA
/////////////////////////////////////////////////////////////////////////
#define NEED_CPU_REG_SHORTCUTS 1
#include "bochs.h"
#include "cpu.h"
#define LOG_THIS BX_CPU_THIS_PTR
// This array defines a look-up table for the even parity-ness
// of an 8bit quantity, for optimal assignment of the parity bit
// in the EFLAGS register
const Bit8u bx_parity_lookup[256] = {
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1
};
#define op1_8 ((Bit8u)(BX_CPU_THIS_PTR oszapc.op1))
#define op2_8 ((Bit8u)(BX_CPU_THIS_PTR oszapc.op2))
#define result_8 ((Bit8u)(BX_CPU_THIS_PTR oszapc.result))
#define op1_16 ((Bit16u)(BX_CPU_THIS_PTR oszapc.op1))
#define op2_16 ((Bit16u)(BX_CPU_THIS_PTR oszapc.op2))
#define result_16 ((Bit16u)(BX_CPU_THIS_PTR oszapc.result))
#define op1_32 ((Bit32u)(BX_CPU_THIS_PTR oszapc.op1))
#define op2_32 ((Bit32u)(BX_CPU_THIS_PTR oszapc.op2))
#define result_32 ((Bit32u)(BX_CPU_THIS_PTR oszapc.result))
#if BX_SUPPORT_X86_64
#define op1_64 ((Bit64u)(BX_CPU_THIS_PTR oszapc.op1))
#define op2_64 ((Bit64u)(BX_CPU_THIS_PTR oszapc.op2))
#define result_64 ((Bit64u)(BX_CPU_THIS_PTR oszapc.result))
#endif
bx_bool BX_CPU_C::get_CFLazy(void)
{
unsigned cf;
switch (BX_CPU_THIS_PTR oszapc.instr) {
case BX_LF_INSTR_ADD8:
case BX_LF_INSTR_ADD16:
case BX_LF_INSTR_ADD32:
cf = (result_32 < op1_32);
break;
#if BX_SUPPORT_X86_64
case BX_LF_INSTR_ADD64:
cf = (result_64 < op1_64);
break;
#endif
// used only if CF = 1 when executing ADC instruction
case BX_LF_INSTR_ADC8:
case BX_LF_INSTR_ADC16:
case BX_LF_INSTR_ADC32:
cf = (result_32 <= op1_32);
break;
#if BX_SUPPORT_X86_64
// used only if CF = 1 when executing ADC instruction
case BX_LF_INSTR_ADC64:
cf = (result_64 <= op1_64);
break;
#endif
case BX_LF_INSTR_SUB8:
case BX_LF_INSTR_SUB16:
case BX_LF_INSTR_SUB32:
cf = (op1_32 < op2_32);
break;
#if BX_SUPPORT_X86_64
case BX_LF_INSTR_SUB64:
cf = (op1_64 < op2_64);
break;
#endif
// used only if CF = 1 when executing SBB instruction
case BX_LF_INSTR_SBB8:
cf = (op1_8 < result_8) || (op2_8==0xff);
break;
// used only if CF = 1 when executing SBB instruction
case BX_LF_INSTR_SBB16:
cf = (op1_16 < result_16) || (op2_16==0xffff);
break;
// used only if CF = 1 when executing SBB instruction
case BX_LF_INSTR_SBB32:
cf = (op1_32 < result_32) || (op2_32==0xffffffff);
break;
#if BX_SUPPORT_X86_64
// used only if CF = 1 when executing SBB instruction
case BX_LF_INSTR_SBB64:
cf = (op1_64 < result_64) || (op2_64==BX_CONST64(0xffffffffffffffff));
break;
#endif
case BX_LF_INSTR_NEG8:
case BX_LF_INSTR_NEG16:
case BX_LF_INSTR_NEG32:
cf = (result_32 != 0);
break;
#if BX_SUPPORT_X86_64
case BX_LF_INSTR_NEG64:
cf = (result_64 != 0);
break;
#endif
case BX_LF_INSTR_LOGIC8:
case BX_LF_INSTR_LOGIC16:
case BX_LF_INSTR_LOGIC32:
#if BX_SUPPORT_X86_64
case BX_LF_INSTR_LOGIC64:
#endif
cf = 0;
break;
default:
cf = 0; // Keep compiler quiet.
BX_PANIC(("get_CF: OSZAPC: unknown instr %u",
(unsigned) BX_CPU_THIS_PTR oszapc.instr));
}
return(cf);
}
bx_bool BX_CPU_C::get_AFLazy(void)
{
unsigned af;
switch (BX_CPU_THIS_PTR oszapc.instr) {
case BX_LF_INSTR_ADD8:
case BX_LF_INSTR_ADC8:
case BX_LF_INSTR_SUB8:
case BX_LF_INSTR_SBB8:
case BX_LF_INSTR_ADD16:
case BX_LF_INSTR_ADC16:
case BX_LF_INSTR_SUB16:
case BX_LF_INSTR_SBB16:
case BX_LF_INSTR_ADD32:
case BX_LF_INSTR_ADC32:
case BX_LF_INSTR_SUB32:
case BX_LF_INSTR_SBB32:
#if BX_SUPPORT_X86_64
case BX_LF_INSTR_ADD64:
case BX_LF_INSTR_ADC64:
case BX_LF_INSTR_SUB64:
case BX_LF_INSTR_SBB64:
#endif
af = ((op1_8 ^ op2_8) ^ result_8) & 0x10;
break;
case BX_LF_INSTR_NEG8:
case BX_LF_INSTR_NEG16:
case BX_LF_INSTR_NEG32:
#if BX_SUPPORT_X86_64
case BX_LF_INSTR_NEG64:
#endif
af = (result_8 & 0xf) != 0;
break;
case BX_LF_INSTR_INC8:
case BX_LF_INSTR_INC16:
case BX_LF_INSTR_INC32:
#if BX_SUPPORT_X86_64
case BX_LF_INSTR_INC64:
#endif
af = (result_8 & 0xf) == 0;
break;
case BX_LF_INSTR_DEC8:
case BX_LF_INSTR_DEC16:
case BX_LF_INSTR_DEC32:
#if BX_SUPPORT_X86_64
case BX_LF_INSTR_DEC64:
#endif
af = (result_8 & 0xf) == 0xf;
break;
case BX_LF_INSTR_LOGIC8:
case BX_LF_INSTR_LOGIC16:
case BX_LF_INSTR_LOGIC32:
#if BX_SUPPORT_X86_64
case BX_LF_INSTR_LOGIC64:
#endif
af = 0;
break;
default:
af = 0; // Keep compiler quiet.
BX_PANIC(("get_AF: OSZAPC: unknown instr %u", (unsigned) BX_CPU_THIS_PTR oszapc.instr));
}
return(af);
}
#define GET_ADD_OVERFLOW(op1, op2, result, mask) \
(((((op1) ^ (result)) & ((op2) ^ (result))) & (mask)) != 0)
#define GET_SUB_OVERFLOW(op1, op2, result, mask) \
(((((op1) ^ (op2)) & ((op1) ^ (result))) & (mask)) != 0)
bx_bool BX_CPU_C::get_OFLazy(void)
{
unsigned of;
switch (BX_CPU_THIS_PTR oszapc.instr) {
case BX_LF_INSTR_ADD8:
case BX_LF_INSTR_ADC8:
case BX_LF_INSTR_ADD16:
case BX_LF_INSTR_ADC16:
case BX_LF_INSTR_ADD32:
case BX_LF_INSTR_ADC32:
of = GET_ADD_OVERFLOW(op1_32, op2_32, result_32, 0x80000000);
break;
#if BX_SUPPORT_X86_64
case BX_LF_INSTR_ADD64:
case BX_LF_INSTR_ADC64:
of = GET_ADD_OVERFLOW(op1_64, op2_64, result_64, BX_CONST64(0x8000000000000000));
break;
#endif
case BX_LF_INSTR_SUB8:
case BX_LF_INSTR_SBB8:
case BX_LF_INSTR_SUB16:
case BX_LF_INSTR_SBB16:
case BX_LF_INSTR_SUB32:
case BX_LF_INSTR_SBB32:
of = GET_SUB_OVERFLOW(op1_32, op2_32, result_32, 0x80000000);
break;
#if BX_SUPPORT_X86_64
case BX_LF_INSTR_SUB64:
case BX_LF_INSTR_SBB64:
of = GET_SUB_OVERFLOW(op1_64, op2_64, result_64, BX_CONST64(0x8000000000000000));
break;
#endif
case BX_LF_INSTR_LOGIC8:
case BX_LF_INSTR_LOGIC16:
case BX_LF_INSTR_LOGIC32:
#if BX_SUPPORT_X86_64
case BX_LF_INSTR_LOGIC64:
#endif
of = 0;
break;
case BX_LF_INSTR_NEG8:
case BX_LF_INSTR_INC8:
of = (result_8 == 0x80);
break;
case BX_LF_INSTR_NEG16:
case BX_LF_INSTR_INC16:
of = (result_16 == 0x8000);
break;
case BX_LF_INSTR_NEG32:
case BX_LF_INSTR_INC32:
of = (result_32 == 0x80000000);
break;
#if BX_SUPPORT_X86_64
case BX_LF_INSTR_NEG64:
case BX_LF_INSTR_INC64:
of = (result_64 == BX_CONST64(0x8000000000000000));
break;
#endif
case BX_LF_INSTR_DEC8:
of = (result_8 == 0x7F);
break;
case BX_LF_INSTR_DEC16:
of = (result_16 == 0x7FFF);
break;
case BX_LF_INSTR_DEC32:
of = (result_32 == 0x7FFFFFFF);
break;
#if BX_SUPPORT_X86_64
case BX_LF_INSTR_DEC64:
of = (result_64 == BX_CONST64(0x7FFFFFFFFFFFFFFF));
break;
#endif
default:
of = 0; // Keep compiler happy.
BX_PANIC(("get_OF: OSZAPC: unknown instr"));
}
return(of);
}

View File

@ -0,0 +1,254 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2001-2009 The Bochs Project
//
// 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
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA B 02110-1301 USA
//
/////////////////////////////////////////////////////////////////////////
#ifndef BX_LAZY_FLAGS_DEF
#define BX_LAZY_FLAGS_DEF
#define BX_LF_INSTR_ADD8 1
#define BX_LF_INSTR_ADC8 2
#define BX_LF_INSTR_ADD16 3
#define BX_LF_INSTR_ADC16 4
#define BX_LF_INSTR_ADD32 5
#define BX_LF_INSTR_ADC32 6
#define BX_LF_INSTR_ADD64 7
#define BX_LF_INSTR_ADC64 8
#define BX_LF_INSTR_ADD_ADC8(cf) (1 + (cf))
#define BX_LF_INSTR_ADD_ADC16(cf) (3 + (cf))
#define BX_LF_INSTR_ADD_ADC32(cf) (5 + (cf))
#define BX_LF_INSTR_ADD_ADC64(cf) (7 + (cf))
#define BX_LF_INSTR_SUB8 9
#define BX_LF_INSTR_SBB8 10
#define BX_LF_INSTR_SUB16 11
#define BX_LF_INSTR_SBB16 12
#define BX_LF_INSTR_SUB32 13
#define BX_LF_INSTR_SBB32 14
#define BX_LF_INSTR_SUB64 15
#define BX_LF_INSTR_SBB64 16
#define BX_LF_INSTR_SUB_SBB8(cf) (9 + (cf))
#define BX_LF_INSTR_SUB_SBB16(cf) (11 + (cf))
#define BX_LF_INSTR_SUB_SBB32(cf) (13 + (cf))
#define BX_LF_INSTR_SUB_SBB64(cf) (15 + (cf))
#define BX_LF_INSTR_INC8 17
#define BX_LF_INSTR_INC16 18
#define BX_LF_INSTR_INC32 19
#define BX_LF_INSTR_INC64 20
#define BX_LF_INSTR_DEC8 21
#define BX_LF_INSTR_DEC16 22
#define BX_LF_INSTR_DEC32 23
#define BX_LF_INSTR_DEC64 24
#define BX_LF_INSTR_NEG8 25
#define BX_LF_INSTR_NEG16 26
#define BX_LF_INSTR_NEG32 27
#define BX_LF_INSTR_NEG64 28
#define BX_LF_INSTR_LOGIC8 29
#define BX_LF_INSTR_LOGIC16 30
#define BX_LF_INSTR_LOGIC32 31
#define BX_LF_INSTR_LOGIC64 32
#if BX_SUPPORT_X86_64
#define BX_LF_SIGN_BIT 63
#else
#define BX_LF_SIGN_BIT 31
#endif
typedef struct {
bx_address op1;
bx_address op2;
bx_address result;
unsigned instr;
} bx_lf_flags_entry;
// *******************
// OSZAPC
// *******************
/* op1, op2, result */
#define SET_FLAGS_OSZAPC_SIZE(size, lf_op1, lf_op2, lf_result, ins) { \
BX_CPU_THIS_PTR oszapc.op1 = (bx_address)(Bit##size##s)(lf_op1); \
BX_CPU_THIS_PTR oszapc.op2 = (bx_address)(Bit##size##s)(lf_op2); \
BX_CPU_THIS_PTR oszapc.result = (bx_address)(Bit##size##s)(lf_result); \
BX_CPU_THIS_PTR oszapc.instr = (ins); \
BX_CPU_THIS_PTR lf_flags_status = EFlagsOSZAPCMask; \
}
#define SET_FLAGS_OSZAPC_8(op1, op2, result, ins) \
SET_FLAGS_OSZAPC_SIZE(8, op1, op2, result, ins)
#define SET_FLAGS_OSZAPC_16(op1, op2, result, ins) \
SET_FLAGS_OSZAPC_SIZE(16, op1, op2, result, ins)
#define SET_FLAGS_OSZAPC_32(op1, op2, result, ins) \
SET_FLAGS_OSZAPC_SIZE(32, op1, op2, result, ins)
#if BX_SUPPORT_X86_64
#define SET_FLAGS_OSZAPC_64(op1, op2, result, ins) \
SET_FLAGS_OSZAPC_SIZE(64, op1, op2, result, ins)
#endif
/* op1 and result only */
#define SET_FLAGS_OSZAPC_S1_SIZE(size, lf_op1, lf_result, ins) { \
BX_CPU_THIS_PTR oszapc.op1 = (bx_address)(Bit##size##s)(lf_op1); \
BX_CPU_THIS_PTR oszapc.result = (Bit##size##s)(lf_result); \
BX_CPU_THIS_PTR oszapc.instr = (ins); \
BX_CPU_THIS_PTR lf_flags_status = EFlagsOSZAPCMask; \
}
#define SET_FLAGS_OSZAPC_S1_8(op1, result, ins) \
SET_FLAGS_OSZAPC_S1_SIZE(8, op1, result, ins)
#define SET_FLAGS_OSZAPC_S1_16(op1, result, ins) \
SET_FLAGS_OSZAPC_S1_SIZE(16, op1, result, ins)
#define SET_FLAGS_OSZAPC_S1_32(op1, result, ins) \
SET_FLAGS_OSZAPC_S1_SIZE(32, op1, result, ins)
#if BX_SUPPORT_X86_64
#define SET_FLAGS_OSZAPC_S1_64(op1, result, ins) \
SET_FLAGS_OSZAPC_S1_SIZE(64, op1, result, ins)
#endif
/* op2 and result only */
#define SET_FLAGS_OSZAPC_S2_SIZE(size, lf_op2, lf_result, ins) { \
BX_CPU_THIS_PTR oszapc.op2 = (bx_address)(Bit##size##s)(lf_op2); \
BX_CPU_THIS_PTR oszapc.result = (Bit##size##s)(lf_result); \
BX_CPU_THIS_PTR oszapc.instr = (ins); \
BX_CPU_THIS_PTR lf_flags_status = EFlagsOSZAPCMask; \
}
#define SET_FLAGS_OSZAPC_S2_8(op2, result, ins) \
SET_FLAGS_OSZAPC_S2_SIZE(8, op2, result, ins)
#define SET_FLAGS_OSZAPC_S2_16(op2, result, ins) \
SET_FLAGS_OSZAPC_S2_SIZE(16, op2, result, ins)
#define SET_FLAGS_OSZAPC_S2_32(op2, result, ins) \
SET_FLAGS_OSZAPC_S2_SIZE(32, op2, result, ins)
#if BX_SUPPORT_X86_64
#define SET_FLAGS_OSZAPC_S2_64(op2, result, ins) \
SET_FLAGS_OSZAPC_S2_SIZE(64, op2, result, ins)
#endif
/* result only */
#define SET_FLAGS_OSZAPC_RESULT_SIZE(size, lf_result, ins) { \
BX_CPU_THIS_PTR oszapc.result = (Bit##size##s)(lf_result); \
BX_CPU_THIS_PTR oszapc.instr = (ins); \
BX_CPU_THIS_PTR lf_flags_status = EFlagsOSZAPCMask; \
}
#define SET_FLAGS_OSZAPC_RESULT_8(result, ins) \
SET_FLAGS_OSZAPC_RESULT_SIZE(8, result, ins)
#define SET_FLAGS_OSZAPC_RESULT_16(result, ins) \
SET_FLAGS_OSZAPC_RESULT_SIZE(16, result, ins)
#define SET_FLAGS_OSZAPC_RESULT_32(result, ins) \
SET_FLAGS_OSZAPC_RESULT_SIZE(32, result, ins)
#if BX_SUPPORT_X86_64
#define SET_FLAGS_OSZAPC_RESULT_64(result, ins) \
SET_FLAGS_OSZAPC_RESULT_SIZE(64, result, ins)
#endif
// *******************
// OSZAP
// *******************
/* result only */
#define SET_FLAGS_OSZAP_RESULT_SIZE(size, lf_result, ins) { \
force_CF(); \
BX_CPU_THIS_PTR oszapc.result = (Bit##size##s)(lf_result); \
BX_CPU_THIS_PTR oszapc.instr = (ins); \
BX_CPU_THIS_PTR lf_flags_status = EFlagsOSZAPMask; \
}
#define SET_FLAGS_OSZAP_RESULT_8(result, ins) \
SET_FLAGS_OSZAP_RESULT_SIZE(8, result, ins)
#define SET_FLAGS_OSZAP_RESULT_16(result, ins) \
SET_FLAGS_OSZAP_RESULT_SIZE(16, result, ins)
#define SET_FLAGS_OSZAP_RESULT_32(result, ins) \
SET_FLAGS_OSZAP_RESULT_SIZE(32, result, ins)
#if BX_SUPPORT_X86_64
#define SET_FLAGS_OSZAP_RESULT_64(result, ins) \
SET_FLAGS_OSZAP_RESULT_SIZE(64, result, ins)
#endif
// transition to new lazy flags code
#define SET_FLAGS_OSZAPC_LOGIC_8(result_8) \
SET_FLAGS_OSZAPC_RESULT_8((result_8), BX_LF_INSTR_LOGIC8)
#define SET_FLAGS_OSZAPC_LOGIC_16(result_16) \
SET_FLAGS_OSZAPC_RESULT_16((result_16), BX_LF_INSTR_LOGIC16)
#define SET_FLAGS_OSZAPC_LOGIC_32(result_32) \
SET_FLAGS_OSZAPC_RESULT_32((result_32), BX_LF_INSTR_LOGIC32)
#if BX_SUPPORT_X86_64
#define SET_FLAGS_OSZAPC_LOGIC_64(result_64) \
SET_FLAGS_OSZAPC_RESULT_64((result_64), BX_LF_INSTR_LOGIC64)
#endif
#define SET_FLAGS_OSZAPC_ADD_8(op1_8, op2_8, sum_8) \
SET_FLAGS_OSZAPC_8((op1_8), (op2_8), (sum_8), BX_LF_INSTR_ADD8)
#define SET_FLAGS_OSZAPC_ADD_16(op1_16, op2_16, sum_16) \
SET_FLAGS_OSZAPC_16((op1_16), (op2_16), (sum_16), BX_LF_INSTR_ADD16)
#define SET_FLAGS_OSZAPC_ADD_32(op1_32, op2_32, sum_32) \
SET_FLAGS_OSZAPC_32((op1_32), (op2_32), (sum_32), BX_LF_INSTR_ADD32)
#if BX_SUPPORT_X86_64
#define SET_FLAGS_OSZAPC_ADD_64(op1_64, op2_64, sum_64) \
SET_FLAGS_OSZAPC_64((op1_64), (op2_64), (sum_64), BX_LF_INSTR_ADD64)
#endif
#define SET_FLAGS_OSZAPC_SUB_8(op1_8, op2_8, diff_8) \
SET_FLAGS_OSZAPC_8((op1_8), (op2_8), (diff_8), BX_LF_INSTR_SUB8)
#define SET_FLAGS_OSZAPC_SUB_16(op1_16, op2_16, diff_16) \
SET_FLAGS_OSZAPC_16((op1_16), (op2_16), (diff_16), BX_LF_INSTR_SUB16)
#define SET_FLAGS_OSZAPC_SUB_32(op1_32, op2_32, diff_32) \
SET_FLAGS_OSZAPC_32((op1_32), (op2_32), (diff_32), BX_LF_INSTR_SUB32)
#if BX_SUPPORT_X86_64
#define SET_FLAGS_OSZAPC_SUB_64(op1_64, op2_64, diff_64) \
SET_FLAGS_OSZAPC_64((op1_64), (op2_64), (diff_64), BX_LF_INSTR_SUB64)
#endif
#define SET_FLAGS_OSZAPC_INC_8(result) \
SET_FLAGS_OSZAP_RESULT_SIZE(8, (result), BX_LF_INSTR_INC8)
#define SET_FLAGS_OSZAPC_INC_16(result) \
SET_FLAGS_OSZAP_RESULT_SIZE(16, (result), BX_LF_INSTR_INC16)
#define SET_FLAGS_OSZAPC_INC_32(result) \
SET_FLAGS_OSZAP_RESULT_SIZE(32, (result), BX_LF_INSTR_INC32)
#if BX_SUPPORT_X86_64
#define SET_FLAGS_OSZAPC_INC_64(result) \
SET_FLAGS_OSZAP_RESULT_SIZE(64, (result), BX_LF_INSTR_INC64)
#endif
#define SET_FLAGS_OSZAPC_DEC_8(result) \
SET_FLAGS_OSZAP_RESULT_SIZE(8, (result), BX_LF_INSTR_DEC8)
#define SET_FLAGS_OSZAPC_DEC_16(result) \
SET_FLAGS_OSZAP_RESULT_SIZE(16, (result), BX_LF_INSTR_DEC16)
#define SET_FLAGS_OSZAPC_DEC_32(result) \
SET_FLAGS_OSZAP_RESULT_SIZE(32, (result), BX_LF_INSTR_DEC32)
#if BX_SUPPORT_X86_64
#define SET_FLAGS_OSZAPC_DEC_64(result) \
SET_FLAGS_OSZAP_RESULT_SIZE(64, (result), BX_LF_INSTR_DEC64)
#endif
BOCHSAPI extern const Bit8u bx_parity_lookup[256];
#endif // BX_LAZY_FLAGS_DEF

121
simulators/bochs/cpu/load.cc Executable file
View File

@ -0,0 +1,121 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2008-2011 Stanislav Shwartsman
// 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
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA B 02110-1301 USA
//
/////////////////////////////////////////////////////////////////////////
#define NEED_CPU_REG_SHORTCUTS 1
#include "bochs.h"
#include "cpu.h"
#define LOG_THIS BX_CPU_THIS_PTR
void BX_CPP_AttrRegparmN(1) BX_CPU_C::LOAD_Eb(bxInstruction_c *i)
{
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
TMP8L = read_virtual_byte(i->seg(), eaddr);
BX_CPU_CALL_METHOD(i->execute2, (i));
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::LOAD_Ew(bxInstruction_c *i)
{
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
TMP16 = read_virtual_word(i->seg(), eaddr);
BX_CPU_CALL_METHOD(i->execute2, (i));
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::LOAD_Ed(bxInstruction_c *i)
{
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
TMP32 = read_virtual_dword(i->seg(), eaddr);
BX_CPU_CALL_METHOD(i->execute2, (i));
}
#if BX_SUPPORT_X86_64
void BX_CPP_AttrRegparmN(1) BX_CPU_C::LOAD_Eq(bxInstruction_c *i)
{
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
TMP64 = read_virtual_qword_64(i->seg(), eaddr);
BX_CPU_CALL_METHOD(i->execute2, (i));
}
#endif
void BX_CPP_AttrRegparmN(1) BX_CPU_C::LOAD_Ww(bxInstruction_c *i)
{
#if BX_CPU_LEVEL >= 6
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
Bit16u val_16 = read_virtual_word(i->seg(), eaddr);
BX_WRITE_XMM_REG_LO_WORD(BX_TMP_REGISTER, val_16);
BX_CPU_CALL_METHOD(i->execute2, (i));
#endif
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::LOAD_Wss(bxInstruction_c *i)
{
#if BX_CPU_LEVEL >= 6
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
Bit32u val_32 = read_virtual_dword(i->seg(), eaddr);
BX_WRITE_XMM_REG_LO_DWORD(BX_TMP_REGISTER, val_32);
BX_CPU_CALL_METHOD(i->execute2, (i));
#endif
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::LOAD_Wsd(bxInstruction_c *i)
{
#if BX_CPU_LEVEL >= 6
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
Bit64u val_64 = read_virtual_qword(i->seg(), eaddr);
BX_WRITE_XMM_REG_LO_QWORD(BX_TMP_REGISTER, val_64);
BX_CPU_CALL_METHOD(i->execute2, (i));
#endif
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::LOAD_Wdq(bxInstruction_c *i)
{
#if BX_CPU_LEVEL >= 6
BxPackedXmmRegister op;
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
#if BX_SUPPORT_MISALIGNED_SSE
if (BX_CPU_THIS_PTR mxcsr.get_MM())
read_virtual_dqword(i->seg(), eaddr, &op);
else
#endif
read_virtual_dqword_aligned(i->seg(), eaddr, &op);
BX_WRITE_XMM_REG(BX_TMP_REGISTER, op);
BX_CPU_CALL_METHOD(i->execute2, (i));
#endif
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::LOADU_Wdq(bxInstruction_c *i)
{
#if BX_CPU_LEVEL >= 6
BxPackedXmmRegister op;
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
read_virtual_dqword(i->seg(), eaddr, &op);
BX_WRITE_XMM_REG(BX_TMP_REGISTER, op);
BX_CPU_CALL_METHOD(i->execute2, (i));
#endif
}

View File

@ -0,0 +1,248 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2001-2009 The Bochs Project
//
// 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
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA B 02110-1301 USA
/////////////////////////////////////////////////////////////////////////
#define NEED_CPU_REG_SHORTCUTS 1
#include "bochs.h"
#include "cpu.h"
#define LOG_THIS BX_CPU_THIS_PTR
void BX_CPP_AttrRegparmN(1) BX_CPU_C::XOR_EwGwM(bxInstruction_c *i)
{
Bit16u op1_16, op2_16;
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
op1_16 = read_RMW_virtual_word(i->seg(), eaddr);
op2_16 = BX_READ_16BIT_REG(i->nnn());
op1_16 ^= op2_16;
write_RMW_virtual_word(op1_16);
SET_FLAGS_OSZAPC_LOGIC_16(op1_16);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::XOR_GwEwR(bxInstruction_c *i)
{
Bit16u op1_16, op2_16;
op1_16 = BX_READ_16BIT_REG(i->nnn());
op2_16 = BX_READ_16BIT_REG(i->rm());
op1_16 ^= op2_16;
BX_WRITE_16BIT_REG(i->nnn(), op1_16);
SET_FLAGS_OSZAPC_LOGIC_16(op1_16);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::XOR_AXIw(bxInstruction_c *i)
{
Bit16u op1_16;
op1_16 = AX;
op1_16 ^= i->Iw();
AX = op1_16;
SET_FLAGS_OSZAPC_LOGIC_16(op1_16);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::XOR_EwIwM(bxInstruction_c *i)
{
Bit16u op1_16;
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
op1_16 = read_RMW_virtual_word(i->seg(), eaddr);
op1_16 ^= i->Iw();
write_RMW_virtual_word(op1_16);
SET_FLAGS_OSZAPC_LOGIC_16(op1_16);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::XOR_EwIwR(bxInstruction_c *i)
{
Bit16u op1_16 = BX_READ_16BIT_REG(i->rm());
op1_16 ^= i->Iw();
BX_WRITE_16BIT_REG(i->rm(), op1_16);
SET_FLAGS_OSZAPC_LOGIC_16(op1_16);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::OR_EwIwM(bxInstruction_c *i)
{
Bit16u op1_16;
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
op1_16 = read_RMW_virtual_word(i->seg(), eaddr);
op1_16 |= i->Iw();
write_RMW_virtual_word(op1_16);
SET_FLAGS_OSZAPC_LOGIC_16(op1_16);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::OR_EwIwR(bxInstruction_c *i)
{
Bit16u op1_16 = BX_READ_16BIT_REG(i->rm());
op1_16 |= i->Iw();
BX_WRITE_16BIT_REG(i->rm(), op1_16);
SET_FLAGS_OSZAPC_LOGIC_16(op1_16);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::NOT_EwM(bxInstruction_c *i)
{
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
Bit16u op1_16 = read_RMW_virtual_word(i->seg(), eaddr);
op1_16 = ~op1_16;
write_RMW_virtual_word(op1_16);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::NOT_EwR(bxInstruction_c *i)
{
Bit16u op1_16 = BX_READ_16BIT_REG(i->rm());
op1_16 = ~op1_16;
BX_WRITE_16BIT_REG(i->rm(), op1_16);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::OR_EwGwM(bxInstruction_c *i)
{
Bit16u op1_16, op2_16;
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
op1_16 = read_RMW_virtual_word(i->seg(), eaddr);
op2_16 = BX_READ_16BIT_REG(i->nnn());
op1_16 |= op2_16;
write_RMW_virtual_word(op1_16);
SET_FLAGS_OSZAPC_LOGIC_16(op1_16);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::OR_GwEwR(bxInstruction_c *i)
{
Bit16u op1_16, op2_16;
op1_16 = BX_READ_16BIT_REG(i->nnn());
op2_16 = BX_READ_16BIT_REG(i->rm());
op1_16 |= op2_16;
BX_WRITE_16BIT_REG(i->nnn(), op1_16);
SET_FLAGS_OSZAPC_LOGIC_16(op1_16);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::OR_AXIw(bxInstruction_c *i)
{
Bit16u op1_16, op2_16;
op1_16 = AX;
op2_16 = i->Iw();
op1_16 |= op2_16;
AX = op1_16;
SET_FLAGS_OSZAPC_LOGIC_16(op1_16);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::AND_EwGwM(bxInstruction_c *i)
{
Bit16u op1_16, op2_16;
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
op1_16 = read_RMW_virtual_word(i->seg(), eaddr);
op2_16 = BX_READ_16BIT_REG(i->nnn());
op1_16 &= op2_16;
write_RMW_virtual_word(op1_16);
SET_FLAGS_OSZAPC_LOGIC_16(op1_16);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::AND_GwEwR(bxInstruction_c *i)
{
Bit16u op1_16, op2_16;
op1_16 = BX_READ_16BIT_REG(i->nnn());
op2_16 = BX_READ_16BIT_REG(i->rm());
op1_16 &= op2_16;
BX_WRITE_16BIT_REG(i->nnn(), op1_16);
SET_FLAGS_OSZAPC_LOGIC_16(op1_16);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::AND_AXIw(bxInstruction_c *i)
{
Bit16u op1_16, op2_16;
op1_16 = AX;
op2_16 = i->Iw();
op1_16 &= op2_16;
AX = op1_16;
SET_FLAGS_OSZAPC_LOGIC_16(op1_16);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::AND_EwIwM(bxInstruction_c *i)
{
Bit16u op1_16;
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
op1_16 = read_RMW_virtual_word(i->seg(), eaddr);
op1_16 &= i->Iw();
write_RMW_virtual_word(op1_16);
SET_FLAGS_OSZAPC_LOGIC_16(op1_16);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::AND_EwIwR(bxInstruction_c *i)
{
Bit16u op1_16 = BX_READ_16BIT_REG(i->rm());
op1_16 &= i->Iw();
BX_WRITE_16BIT_REG(i->rm(), op1_16);
SET_FLAGS_OSZAPC_LOGIC_16(op1_16);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::TEST_EwGwR(bxInstruction_c *i)
{
Bit16u op1_16, op2_16;
op1_16 = BX_READ_16BIT_REG(i->rm());
op2_16 = BX_READ_16BIT_REG(i->nnn());
op1_16 &= op2_16;
SET_FLAGS_OSZAPC_LOGIC_16(op1_16);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::TEST_AXIw(bxInstruction_c *i)
{
Bit16u op1_16, op2_16;
op1_16 = AX;
op2_16 = i->Iw();
op1_16 &= op2_16;
SET_FLAGS_OSZAPC_LOGIC_16(op1_16);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::TEST_EwIwR(bxInstruction_c *i)
{
Bit16u op1_16 = BX_READ_16BIT_REG(i->rm());
op1_16 &= i->Iw();
SET_FLAGS_OSZAPC_LOGIC_16(op1_16);
}

View File

@ -0,0 +1,254 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2001-2009 The Bochs Project
//
// 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
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA B 02110-1301 USA
/////////////////////////////////////////////////////////////////////////
#define NEED_CPU_REG_SHORTCUTS 1
#include "bochs.h"
#include "cpu.h"
#define LOG_THIS BX_CPU_THIS_PTR
#if BX_SUPPORT_X86_64==0
// Make life easier for merging cpu64 and cpu32 code.
#define RAX EAX
#endif
void BX_CPP_AttrRegparmN(1) BX_CPU_C::XOR_EdGdM(bxInstruction_c *i)
{
Bit32u op1_32, op2_32;
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
op1_32 = read_RMW_virtual_dword(i->seg(), eaddr);
op2_32 = BX_READ_32BIT_REG(i->nnn());
op1_32 ^= op2_32;
write_RMW_virtual_dword(op1_32);
SET_FLAGS_OSZAPC_LOGIC_32(op1_32);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::XOR_GdEdR(bxInstruction_c *i)
{
Bit32u op1_32, op2_32;
op1_32 = BX_READ_32BIT_REG(i->nnn());
op2_32 = BX_READ_32BIT_REG(i->rm());
op1_32 ^= op2_32;
BX_WRITE_32BIT_REGZ(i->nnn(), op1_32);
SET_FLAGS_OSZAPC_LOGIC_32(op1_32);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::XOR_EAXId(bxInstruction_c *i)
{
Bit32u op1_32;
op1_32 = EAX;
op1_32 ^= i->Id();
RAX = op1_32;
SET_FLAGS_OSZAPC_LOGIC_32(op1_32);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::XOR_EdIdM(bxInstruction_c *i)
{
Bit32u op1_32;
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
op1_32 = read_RMW_virtual_dword(i->seg(), eaddr);
op1_32 ^= i->Id();
write_RMW_virtual_dword(op1_32);
SET_FLAGS_OSZAPC_LOGIC_32(op1_32);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::XOR_EdIdR(bxInstruction_c *i)
{
Bit32u op1_32 = BX_READ_32BIT_REG(i->rm());
op1_32 ^= i->Id();
BX_WRITE_32BIT_REGZ(i->rm(), op1_32);
SET_FLAGS_OSZAPC_LOGIC_32(op1_32);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::OR_EdIdM(bxInstruction_c *i)
{
Bit32u op1_32;
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
op1_32 = read_RMW_virtual_dword(i->seg(), eaddr);
op1_32 |= i->Id();
write_RMW_virtual_dword(op1_32);
SET_FLAGS_OSZAPC_LOGIC_32(op1_32);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::OR_EdIdR(bxInstruction_c *i)
{
Bit32u op1_32 = BX_READ_32BIT_REG(i->rm());
op1_32 |= i->Id();
BX_WRITE_32BIT_REGZ(i->rm(), op1_32);
SET_FLAGS_OSZAPC_LOGIC_32(op1_32);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::NOT_EdM(bxInstruction_c *i)
{
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
Bit32u op1_32 = read_RMW_virtual_dword(i->seg(), eaddr);
op1_32 = ~op1_32;
write_RMW_virtual_dword(op1_32);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::NOT_EdR(bxInstruction_c *i)
{
Bit32u op1_32 = BX_READ_32BIT_REG(i->rm());
op1_32 = ~op1_32;
BX_WRITE_32BIT_REGZ(i->rm(), op1_32);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::OR_EdGdM(bxInstruction_c *i)
{
Bit32u op1_32, op2_32;
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
op1_32 = read_RMW_virtual_dword(i->seg(), eaddr);
op2_32 = BX_READ_32BIT_REG(i->nnn());
op1_32 |= op2_32;
write_RMW_virtual_dword(op1_32);
SET_FLAGS_OSZAPC_LOGIC_32(op1_32);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::OR_GdEdR(bxInstruction_c *i)
{
Bit32u op1_32, op2_32;
op1_32 = BX_READ_32BIT_REG(i->nnn());
op2_32 = BX_READ_32BIT_REG(i->rm());
op1_32 |= op2_32;
BX_WRITE_32BIT_REGZ(i->nnn(), op1_32);
SET_FLAGS_OSZAPC_LOGIC_32(op1_32);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::OR_EAXId(bxInstruction_c *i)
{
Bit32u op1_32, op2_32;
op1_32 = EAX;
op2_32 = i->Id();
op1_32 |= op2_32;
RAX = op1_32;
SET_FLAGS_OSZAPC_LOGIC_32(op1_32);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::AND_EdGdM(bxInstruction_c *i)
{
Bit32u op1_32, op2_32;
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
op1_32 = read_RMW_virtual_dword(i->seg(), eaddr);
op2_32 = BX_READ_32BIT_REG(i->nnn());
op1_32 &= op2_32;
write_RMW_virtual_dword(op1_32);
SET_FLAGS_OSZAPC_LOGIC_32(op1_32);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::AND_GdEdR(bxInstruction_c *i)
{
Bit32u op1_32, op2_32;
op1_32 = BX_READ_32BIT_REG(i->nnn());
op2_32 = BX_READ_32BIT_REG(i->rm());
op1_32 &= op2_32;
BX_WRITE_32BIT_REGZ(i->nnn(), op1_32);
SET_FLAGS_OSZAPC_LOGIC_32(op1_32);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::AND_EAXId(bxInstruction_c *i)
{
Bit32u op1_32, op2_32;
op1_32 = EAX;
op2_32 = i->Id();
op1_32 &= op2_32;
RAX = op1_32;
SET_FLAGS_OSZAPC_LOGIC_32(op1_32);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::AND_EdIdM(bxInstruction_c *i)
{
Bit32u op1_32;
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
op1_32 = read_RMW_virtual_dword(i->seg(), eaddr);
op1_32 &= i->Id();
write_RMW_virtual_dword(op1_32);
SET_FLAGS_OSZAPC_LOGIC_32(op1_32);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::AND_EdIdR(bxInstruction_c *i)
{
Bit32u op1_32 = BX_READ_32BIT_REG(i->rm());
op1_32 &= i->Id();
BX_WRITE_32BIT_REGZ(i->rm(), op1_32);
SET_FLAGS_OSZAPC_LOGIC_32(op1_32);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::TEST_EdGdR(bxInstruction_c *i)
{
Bit32u op1_32, op2_32;
op1_32 = BX_READ_32BIT_REG(i->rm());
op2_32 = BX_READ_32BIT_REG(i->nnn());
op1_32 &= op2_32;
SET_FLAGS_OSZAPC_LOGIC_32(op1_32);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::TEST_EAXId(bxInstruction_c *i)
{
Bit32u op1_32, op2_32;
op1_32 = EAX;
op2_32 = i->Id();
op1_32 &= op2_32;
SET_FLAGS_OSZAPC_LOGIC_32(op1_32);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::TEST_EdIdR(bxInstruction_c *i)
{
Bit32u op1_32 = BX_READ_32BIT_REG(i->rm());
op1_32 &= i->Id();
SET_FLAGS_OSZAPC_LOGIC_32(op1_32);
}

View File

@ -0,0 +1,272 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2001-2009 The Bochs Project
//
// 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
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA B 02110-1301 USA
/////////////////////////////////////////////////////////////////////////
#define NEED_CPU_REG_SHORTCUTS 1
#include "bochs.h"
#include "cpu.h"
#define LOG_THIS BX_CPU_THIS_PTR
#if BX_SUPPORT_X86_64
void BX_CPP_AttrRegparmN(1) BX_CPU_C::XOR_EqGqM(bxInstruction_c *i)
{
Bit64u op1_64, op2_64;
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
op1_64 = read_RMW_virtual_qword_64(i->seg(), eaddr);
op2_64 = BX_READ_64BIT_REG(i->nnn());
op1_64 ^= op2_64;
write_RMW_virtual_qword(op1_64);
SET_FLAGS_OSZAPC_LOGIC_64(op1_64);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::XOR_GqEqR(bxInstruction_c *i)
{
Bit64u op1_64, op2_64;
op1_64 = BX_READ_64BIT_REG(i->nnn());
op2_64 = BX_READ_64BIT_REG(i->rm());
op1_64 ^= op2_64;
/* now write result back to destination */
BX_WRITE_64BIT_REG(i->nnn(), op1_64);
SET_FLAGS_OSZAPC_LOGIC_64(op1_64);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::XOR_RAXId(bxInstruction_c *i)
{
Bit64u op1_64, op2_64;
op1_64 = RAX;
op2_64 = (Bit32s) i->Id();
op1_64 ^= op2_64;
RAX = op1_64;
SET_FLAGS_OSZAPC_LOGIC_64(op1_64);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::XOR_EqIdM(bxInstruction_c *i)
{
Bit64u op1_64, op2_64 = (Bit32s) i->Id();
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
op1_64 = read_RMW_virtual_qword_64(i->seg(), eaddr);
op1_64 ^= op2_64;
write_RMW_virtual_qword(op1_64);
SET_FLAGS_OSZAPC_LOGIC_64(op1_64);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::XOR_EqIdR(bxInstruction_c *i)
{
Bit64u op1_64, op2_64 = (Bit32s) i->Id();
op1_64 = BX_READ_64BIT_REG(i->rm());
op1_64 ^= op2_64;
BX_WRITE_64BIT_REG(i->rm(), op1_64);
SET_FLAGS_OSZAPC_LOGIC_64(op1_64);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::OR_EqIdM(bxInstruction_c *i)
{
Bit64u op1_64, op2_64 = (Bit32s) i->Id();
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
op1_64 = read_RMW_virtual_qword_64(i->seg(), eaddr);
op1_64 |= op2_64;
write_RMW_virtual_qword(op1_64);
SET_FLAGS_OSZAPC_LOGIC_64(op1_64);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::OR_EqIdR(bxInstruction_c *i)
{
Bit64u op1_64, op2_64 = (Bit32s) i->Id();
op1_64 = BX_READ_64BIT_REG(i->rm());
op1_64 |= op2_64;
BX_WRITE_64BIT_REG(i->rm(), op1_64);
SET_FLAGS_OSZAPC_LOGIC_64(op1_64);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::NOT_EqM(bxInstruction_c *i)
{
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
Bit64u op1_64 = read_RMW_virtual_qword_64(i->seg(), eaddr);
op1_64 = ~op1_64;
write_RMW_virtual_qword(op1_64);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::NOT_EqR(bxInstruction_c *i)
{
Bit64u op1_64 = BX_READ_64BIT_REG(i->rm());
op1_64 = ~op1_64;
BX_WRITE_64BIT_REG(i->rm(), op1_64);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::OR_EqGqM(bxInstruction_c *i)
{
Bit64u op1_64, op2_64;
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
op1_64 = read_RMW_virtual_qword_64(i->seg(), eaddr);
op2_64 = BX_READ_64BIT_REG(i->nnn());
op1_64 |= op2_64;
write_RMW_virtual_qword(op1_64);
SET_FLAGS_OSZAPC_LOGIC_64(op1_64);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::OR_GqEqR(bxInstruction_c *i)
{
Bit64u op1_64, op2_64;
op1_64 = BX_READ_64BIT_REG(i->nnn());
op2_64 = BX_READ_64BIT_REG(i->rm());
op1_64 |= op2_64;
/* now write result back to destination */
BX_WRITE_64BIT_REG(i->nnn(), op1_64);
SET_FLAGS_OSZAPC_LOGIC_64(op1_64);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::OR_RAXId(bxInstruction_c *i)
{
Bit64u op1_64, op2_64;
op1_64 = RAX;
op2_64 = (Bit32s) i->Id();
op1_64 |= op2_64;
RAX = op1_64;
SET_FLAGS_OSZAPC_LOGIC_64(op1_64);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::AND_EqGqM(bxInstruction_c *i)
{
Bit64u op1_64, op2_64;
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
op1_64 = read_RMW_virtual_qword_64(i->seg(), eaddr);
op2_64 = BX_READ_64BIT_REG(i->nnn());
op1_64 &= op2_64;
write_RMW_virtual_qword(op1_64);
SET_FLAGS_OSZAPC_LOGIC_64(op1_64);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::AND_GqEqR(bxInstruction_c *i)
{
Bit64u op1_64, op2_64;
op1_64 = BX_READ_64BIT_REG(i->nnn());
op2_64 = BX_READ_64BIT_REG(i->rm());
op1_64 &= op2_64;
/* now write result back to destination */
BX_WRITE_64BIT_REG(i->nnn(), op1_64);
SET_FLAGS_OSZAPC_LOGIC_64(op1_64);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::AND_RAXId(bxInstruction_c *i)
{
Bit64u op1_64, op2_64;
op1_64 = RAX;
op2_64 = (Bit32s) i->Id();
op1_64 &= op2_64;
RAX = op1_64;
SET_FLAGS_OSZAPC_LOGIC_64(op1_64);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::AND_EqIdM(bxInstruction_c *i)
{
Bit64u op1_64, op2_64 = (Bit32s) i->Id();
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
op1_64 = read_RMW_virtual_qword_64(i->seg(), eaddr);
op1_64 &= op2_64;
write_RMW_virtual_qword(op1_64);
SET_FLAGS_OSZAPC_LOGIC_64(op1_64);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::AND_EqIdR(bxInstruction_c *i)
{
Bit64u op1_64, op2_64 = (Bit32s) i->Id();
op1_64 = BX_READ_64BIT_REG(i->rm());
op1_64 &= op2_64;
BX_WRITE_64BIT_REG(i->rm(), op1_64);
SET_FLAGS_OSZAPC_LOGIC_64(op1_64);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::TEST_EqGqR(bxInstruction_c *i)
{
Bit64u op1_64, op2_64;
op1_64 = BX_READ_64BIT_REG(i->rm());
op2_64 = BX_READ_64BIT_REG(i->nnn());
op1_64 &= op2_64;
SET_FLAGS_OSZAPC_LOGIC_64(op1_64);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::TEST_RAXId(bxInstruction_c *i)
{
Bit64u op1_64, op2_64;
op1_64 = RAX;
op2_64 = (Bit32s) i->Id();
op1_64 &= op2_64;
SET_FLAGS_OSZAPC_LOGIC_64(op1_64);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::TEST_EqIdR(bxInstruction_c *i)
{
Bit64u op1_64, op2_64;
op1_64 = BX_READ_64BIT_REG(i->rm());
op2_64 = (Bit32s) i->Id();
op1_64 &= op2_64;
SET_FLAGS_OSZAPC_LOGIC_64(op1_64);
}
#endif /* if BX_SUPPORT_X86_64 */

View File

@ -0,0 +1,253 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2001-2009 The Bochs Project
//
// 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
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA B 02110-1301 USA
/////////////////////////////////////////////////////////////////////////
#define NEED_CPU_REG_SHORTCUTS 1
#include "bochs.h"
#include "cpu.h"
#define LOG_THIS BX_CPU_THIS_PTR
void BX_CPP_AttrRegparmN(1) BX_CPU_C::XOR_EbGbM(bxInstruction_c *i)
{
Bit8u op1, op2;
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
op1 = read_RMW_virtual_byte(i->seg(), eaddr);
op2 = BX_READ_8BIT_REGx(i->nnn(), i->extend8bitL());
op1 ^= op2;
write_RMW_virtual_byte(op1);
SET_FLAGS_OSZAPC_LOGIC_8(op1);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::XOR_GbEbR(bxInstruction_c *i)
{
Bit8u op1, op2;
op1 = BX_READ_8BIT_REGx(i->nnn(), i->extend8bitL());
op2 = BX_READ_8BIT_REGx(i->rm(), i->extend8bitL());
op1 ^= op2;
BX_WRITE_8BIT_REGx(i->nnn(), i->extend8bitL(), op1);
SET_FLAGS_OSZAPC_LOGIC_8(op1);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::XOR_ALIb(bxInstruction_c *i)
{
Bit8u op1 = AL;
op1 ^= i->Ib();
AL = op1;
SET_FLAGS_OSZAPC_LOGIC_8(op1);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::XOR_EbIbM(bxInstruction_c *i)
{
Bit8u op1, op2 = i->Ib();
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
op1 = read_RMW_virtual_byte(i->seg(), eaddr);
op1 ^= op2;
write_RMW_virtual_byte(op1);
SET_FLAGS_OSZAPC_LOGIC_8(op1);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::XOR_EbIbR(bxInstruction_c *i)
{
Bit8u op1, op2 = i->Ib();
op1 = BX_READ_8BIT_REGx(i->rm(), i->extend8bitL());
op1 ^= op2;
BX_WRITE_8BIT_REGx(i->rm(), i->extend8bitL(), op1);
SET_FLAGS_OSZAPC_LOGIC_8(op1);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::OR_EbIbM(bxInstruction_c *i)
{
Bit8u op1, op2 = i->Ib();
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
op1 = read_RMW_virtual_byte(i->seg(), eaddr);
op1 |= op2;
write_RMW_virtual_byte(op1);
SET_FLAGS_OSZAPC_LOGIC_8(op1);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::OR_EbIbR(bxInstruction_c *i)
{
Bit8u op1, op2 = i->Ib();
op1 = BX_READ_8BIT_REGx(i->rm(), i->extend8bitL());
op1 |= op2;
BX_WRITE_8BIT_REGx(i->rm(), i->extend8bitL(), op1);
SET_FLAGS_OSZAPC_LOGIC_8(op1);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::NOT_EbM(bxInstruction_c *i)
{
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
Bit8u op1_8 = read_RMW_virtual_byte(i->seg(), eaddr);
op1_8 = ~op1_8;
write_RMW_virtual_byte(op1_8);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::NOT_EbR(bxInstruction_c *i)
{
Bit8u op1_8 = BX_READ_8BIT_REGx(i->rm(), i->extend8bitL());
op1_8 = ~op1_8;
BX_WRITE_8BIT_REGx(i->rm(), i->extend8bitL(), op1_8);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::OR_EbGbM(bxInstruction_c *i)
{
Bit8u op1, op2;
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
op1 = read_RMW_virtual_byte(i->seg(), eaddr);
op2 = BX_READ_8BIT_REGx(i->nnn(), i->extend8bitL());
op1 |= op2;
write_RMW_virtual_byte(op1);
SET_FLAGS_OSZAPC_LOGIC_8(op1);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::OR_GbEbR(bxInstruction_c *i)
{
Bit8u op1, op2;
op1 = BX_READ_8BIT_REGx(i->nnn(), i->extend8bitL());
op2 = BX_READ_8BIT_REGx(i->rm(), i->extend8bitL());
op1 |= op2;
BX_WRITE_8BIT_REGx(i->nnn(), i->extend8bitL(), op1);
SET_FLAGS_OSZAPC_LOGIC_8(op1);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::OR_ALIb(bxInstruction_c *i)
{
Bit8u op1, op2;
op1 = AL;
op2 = i->Ib();
op1 |= op2;
AL = op1;
SET_FLAGS_OSZAPC_LOGIC_8(op1);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::AND_EbGbM(bxInstruction_c *i)
{
Bit8u op1, op2;
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
op1 = read_RMW_virtual_byte(i->seg(), eaddr);
op2 = BX_READ_8BIT_REGx(i->nnn(), i->extend8bitL());
op1 &= op2;
write_RMW_virtual_byte(op1);
SET_FLAGS_OSZAPC_LOGIC_8(op1);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::AND_GbEbR(bxInstruction_c *i)
{
Bit8u op1, op2;
op1 = BX_READ_8BIT_REGx(i->nnn(), i->extend8bitL());
op2 = BX_READ_8BIT_REGx(i->rm(), i->extend8bitL());
op1 &= op2;
BX_WRITE_8BIT_REGx(i->nnn(), i->extend8bitL(), op1);
SET_FLAGS_OSZAPC_LOGIC_8(op1);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::AND_ALIb(bxInstruction_c *i)
{
Bit8u op1, op2;
op1 = AL;
op2 = i->Ib();
op1 &= op2;
AL = op1;
SET_FLAGS_OSZAPC_LOGIC_8(op1);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::AND_EbIbM(bxInstruction_c *i)
{
Bit8u op1, op2 = i->Ib();
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
op1 = read_RMW_virtual_byte(i->seg(), eaddr);
op1 &= op2;
write_RMW_virtual_byte(op1);
SET_FLAGS_OSZAPC_LOGIC_8(op1);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::AND_EbIbR(bxInstruction_c *i)
{
Bit8u op1, op2 = i->Ib();
op1 = BX_READ_8BIT_REGx(i->rm(), i->extend8bitL());
op1 &= op2;
BX_WRITE_8BIT_REGx(i->rm(), i->extend8bitL(), op1);
SET_FLAGS_OSZAPC_LOGIC_8(op1);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::TEST_EbGbR(bxInstruction_c *i)
{
Bit8u op1, op2;
op1 = BX_READ_8BIT_REGx(i->rm(), i->extend8bitL());
op2 = BX_READ_8BIT_REGx(i->nnn(), i->extend8bitL());
op1 &= op2;
SET_FLAGS_OSZAPC_LOGIC_8(op1);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::TEST_ALIb(bxInstruction_c *i)
{
Bit8u op1, op2;
op1 = AL;
op2 = i->Ib();
op1 &= op2;
SET_FLAGS_OSZAPC_LOGIC_8(op1);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::TEST_EbIbR(bxInstruction_c *i)
{
Bit8u op1 = BX_READ_8BIT_REGx(i->rm(), i->extend8bitL());
op1 &= i->Ib();
SET_FLAGS_OSZAPC_LOGIC_8(op1);
}

2768
simulators/bochs/cpu/mmx.cc Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,235 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2010 Stanislav Shwartsman
// 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
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA B 02110-1301 USA
//
/////////////////////////////////////////////////////////////////////////
#ifndef BX_CPU_MODEL_SPECIFIC
#define BX_CPU_MODEL_SPECIFIC
// CPUID defines - STD features CPUID[0x00000001].EDX
// ----------------------------
// [0:0] FPU on chip
// [1:1] VME: Virtual-8086 Mode enhancements
// [2:2] DE: Debug Extensions (I/O breakpoints)
// [3:3] PSE: Page Size Extensions
// [4:4] TSC: Time Stamp Counter
// [5:5] MSR: RDMSR and WRMSR support
// [6:6] PAE: Physical Address Extensions
// [7:7] MCE: Machine Check Exception
// [8:8] CXS: CMPXCHG8B instruction
// [9:9] APIC: APIC on Chip
// [10:10] Reserved
// [11:11] SYSENTER/SYSEXIT support
// [12:12] MTRR: Memory Type Range Reg
// [13:13] PGE/PTE Global Bit
// [14:14] MCA: Machine Check Architecture
// [15:15] CMOV: Cond Mov/Cmp Instructions
// [16:16] PAT: Page Attribute Table
// [17:17] PSE-36: Physical Address Extensions
// [18:18] PSN: Processor Serial Number
// [19:19] CLFLUSH: CLFLUSH Instruction support
// [20:20] Reserved
// [21:21] DS: Debug Store
// [22:22] ACPI: Thermal Monitor and Software Controlled Clock Facilities
// [23:23] MMX Technology
// [24:24] FXSR: FXSAVE/FXRSTOR (also indicates CR4.OSFXSR is available)
// [25:25] SSE: SSE Extensions
// [26:26] SSE2: SSE2 Extensions
// [27:27] Self Snoop
// [28:28] Hyper Threading Technology
// [29:29] TM: Thermal Monitor
// [30:30] Reserved
// [31:31] PBE: Pending Break Enable
#define BX_CPUID_STD_X87 (1 << 0)
#define BX_CPUID_STD_VME (1 << 1)
#define BX_CPUID_STD_DEBUG_EXTENSIONS (1 << 2)
#define BX_CPUID_STD_PSE (1 << 3)
#define BX_CPUID_STD_TSC (1 << 4)
#define BX_CPUID_STD_MSR (1 << 5)
#define BX_CPUID_STD_PAE (1 << 6)
#define BX_CPUID_STD_MCE (1 << 7)
#define BX_CPUID_STD_CMPXCHG8B (1 << 8)
#define BX_CPUID_STD_APIC (1 << 9)
#define BX_CPUID_STD_RESERVED10 (1 << 10)
#define BX_CPUID_STD_SYSENTER_SYSEXIT (1 << 11)
#define BX_CPUID_STD_MTRR (1 << 12)
#define BX_CPUID_STD_GLOBAL_PAGES (1 << 13)
#define BX_CPUID_STD_MCA (1 << 14)
#define BX_CPUID_STD_CMOV (1 << 15)
#define BX_CPUID_STD_PAT (1 << 16)
#define BX_CPUID_STD_PSE36 (1 << 17)
#define BX_CPUID_STD_PROCESSOR_SERIAL_NUMBER (1 << 18)
#define BX_CPUID_STD_CLFLUSH (1 << 19)
#define BX_CPUID_STD_RESERVED20 (1 << 20)
#define BX_CPUID_STD_DEBUG_STORE (1 << 21)
#define BX_CPUID_STD_ACPI (1 << 22)
#define BX_CPUID_STD_MMX (1 << 23)
#define BX_CPUID_STD_FXSAVE_FXRSTOR (1 << 24)
#define BX_CPUID_STD_SSE (1 << 25)
#define BX_CPUID_STD_SSE2 (1 << 26)
#define BX_CPUID_STD_SELF_SNOOP (1 << 27)
#define BX_CPUID_STD_HT (1 << 28)
#define BX_CPUID_STD_THERMAL_MONITOR (1 << 29)
#define BX_CPUID_STD_RESERVED30 (1 << 30)
#define BX_CPUID_STD_PBE (1 << 31)
// CPUID defines - EXT features CPUID[0x00000001].ECX
// ----------------------------
// [0:0] SSE3: SSE3 Instructions
// [1:1] PCLMULQDQ Instruction support
// [2:2] DTES64: 64-bit DS area
// [3:3] MONITOR/MWAIT support
// [4:4] DS-CPL: CPL qualified debug store
// [5:5] VMX: Virtual Machine Technology
// [6:6] SMX: Secure Virtual Machine Technology
// [7:7] EST: Enhanced Intel SpeedStep Technology
// [8:8] TM2: Thermal Monitor 2
// [9:9] SSSE3: SSSE3 Instructions
// [10:10] CNXT-ID: L1 context ID
// [11:11] reserved
// [12:12] FMA Instructions support
// [13:13] CMPXCHG16B: CMPXCHG16B instruction support
// [14:14] xTPR update control
// [15:15] PDCM - Perfon and Debug Capability MSR
// [16:16] reserved
// [17:17] PCID: Process Context Identifiers
// [18:18] DCA - Direct Cache Access
// [19:19] SSE4.1 Instructions
// [20:20] SSE4.2 Instructions
// [21:21] X2APIC
// [22:22] MOVBE instruction
// [23:23] POPCNT instruction
// [24:24] TSC Deadline
// [25:25] AES Instructions
// [26:26] XSAVE extensions support
// [27:27] OSXSAVE support
// [28:28] AVX extensions support
// [29:29] F16C - Float16 conversion support
// [30:30] RDRAND instruction
// [31:31] reserved
#define BX_CPUID_EXT_SSE3 (1 << 0)
#define BX_CPUID_EXT_PCLMULQDQ (1 << 1)
#define BX_CPUID_EXT_DTES64 (1 << 2)
#define BX_CPUID_EXT_MONITOR_MWAIT (1 << 3)
#define BX_CPUID_EXT_DS_CPL (1 << 4)
#define BX_CPUID_EXT_VMX (1 << 5)
#define BX_CPUID_EXT_SMX (1 << 6)
#define BX_CPUID_EXT_EST (1 << 7)
#define BX_CPUID_EXT_THERMAL_MONITOR2 (1 << 8)
#define BX_CPUID_EXT_SSSE3 (1 << 9)
#define BX_CPUID_EXT_CNXT_ID (1 << 10)
#define BX_CPUID_EXT_RESERVED11 (1 << 11)
#define BX_CPUID_EXT_FMA (1 << 12)
#define BX_CPUID_EXT_CMPXCHG16B (1 << 13)
#define BX_CPUID_EXT_xTPR (1 << 14)
#define BX_CPUID_EXT_PDCM (1 << 15)
#define BX_CPUID_EXT_RESERVED16 (1 << 16)
#define BX_CPUID_EXT_PCID (1 << 17)
#define BX_CPUID_EXT_DCA (1 << 18)
#define BX_CPUID_EXT_SSE4_1 (1 << 19)
#define BX_CPUID_EXT_SSE4_2 (1 << 20)
#define BX_CPUID_EXT_X2APIC (1 << 21)
#define BX_CPUID_EXT_MOVBE (1 << 22)
#define BX_CPUID_EXT_POPCNT (1 << 23)
#define BX_CPUID_EXT_TSC_DEADLINE (1 << 24)
#define BX_CPUID_EXT_AES (1 << 25)
#define BX_CPUID_EXT_XSAVE (1 << 26)
#define BX_CPUID_EXT_OSXSAVE (1 << 27)
#define BX_CPUID_EXT_AVX (1 << 28)
#define BX_CPUID_EXT_F16C (1 << 29)
#define BX_CPUID_EXT_RDRAND (1 << 30)
#define BX_CPUID_EXT_RESERVED31 (1 << 31)
// CPUID defines - STD2 features CPUID[0x80000001].EDX
// -----------------------------
// ...
#define BX_CPUID_STD2_SYSCALL_SYSRET (1 << 11)
// ...
#define BX_CPUID_STD2_NX (1 << 20)
#define BX_CPUID_STD2_RESERVED21 (1 << 21)
#define BX_CPUID_STD2_AMD_MMX_EXT (1 << 22)
#define BX_CPUID_STD2_RESERVED23 (1 << 23)
#define BX_CPUID_STD2_RESERVED24 (1 << 24)
#define BX_CPUID_STD2_FFXSR (1 << 25)
#define BX_CPUID_STD2_1G_PAGES (1 << 26)
#define BX_CPUID_STD2_RDTSCP (1 << 27)
#define BX_CPUID_STD2_RESERVED28 (1 << 28)
#define BX_CPUID_STD2_LONG_MODE (1 << 29)
#define BX_CPUID_STD2_3DNOW_EXT (1 << 30)
#define BX_CPUID_STD2_3DNOW (1 << 31)
// CPUID defines - EXT2 features CPUID[0x80000001].ECX
// -----------------------------
// [0:0] LAHF/SAHF instructions support in 64-bit mode
// [1:1] CMP_Legacy: Core multi-processing legacy mode (AMD)
// [2:2] SVM: Secure Virtual Machine (AMD)
// [3:3] Extended APIC Space
// [4:4] AltMovCR8: LOCK MOV CR0 means MOV CR8
// [5:5] LZCNT: LZCNT instruction support
// [6:6] SSE4A: SSE4A Instructions support
// [7:7] Misaligned SSE support
// [8:8] PREFETCHW: PREFETCHW instruction support
// [9:9] OSVW: OS visible workarounds (AMD)
// [10:10] IBS: Instruction based sampling
// [11:11] XOP: Extended Operations Support and XOP Prefix
// [12:12] SKINIT support
// [13:13] WDT: Watchdog timer support
// [14:14] reserved
// [15:15] LWP: Light weight profiling
// [16:16] FMA4: Four-operand FMA instructions support
// [18:17] reserved
// [19:19] NodeId: Indicates support for NodeId MSR (0xc001100c)
// [20:20] reserved
// [21:21] TBM: trailing bit manipulation instruction support
// [22:22] Topology extensions support
// [31:23] reserved
#define BX_CPUID_EXT2_LAHF_SAHF (1 << 0)
#define BX_CPUID_EXT2_CMP_LEGACY (1 << 1)
#define BX_CPUID_EXT2_SVM (1 << 2)
#define BX_CPUID_EXT2_EXT_APIC_SPACE (1 << 3)
#define BX_CPUID_EXT2_ALT_MOV_CR8 (1 << 4)
#define BX_CPUID_EXT2_LZCNT (1 << 5)
#define BX_CPUID_EXT2_SSE4A (1 << 6)
#define BX_CPUID_EXT2_MISALIGNED_SSE (1 << 7)
#define BX_CPUID_EXT2_PREFETCHW (1 << 8)
#define BX_CPUID_EXT2_OSVW (1 << 9)
#define BX_CPUID_EXT2_IBS (1 << 10)
#define BX_CPUID_EXT2_XOP (1 << 11)
#define BX_CPUID_EXT2_SKINIT (1 << 12)
#define BX_CPUID_EXT2_WDT (1 << 13)
#define BX_CPUID_EXT2_RESERVED14 (1 << 14)
#define BX_CPUID_EXT2_LWP (1 << 15)
#define BX_CPUID_EXT2_FMA4 (1 << 16)
#define BX_CPUID_EXT2_RESERVED17 (1 << 17)
#define BX_CPUID_EXT2_RESERVED18 (1 << 18)
#define BX_CPUID_EXT2_NODEID (1 << 19)
#define BX_CPUID_EXT2_RESERVED20 (1 << 20)
#define BX_CPUID_EXT2_TBM (1 << 21)
#define BX_CPUID_EXT2_TOPOLOGY_EXTENSIONS (1 << 22)
#endif

807
simulators/bochs/cpu/msr.cc Executable file
View File

@ -0,0 +1,807 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2008-2010 Stanislav Shwartsman
// 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
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA B 02110-1301 USA
//
/////////////////////////////////////////////////////////////////////////
#define NEED_CPU_REG_SHORTCUTS 1
#include "bochs.h"
#include "cpu.h"
#define LOG_THIS BX_CPU_THIS_PTR
#if BX_SUPPORT_X86_64==0
// Make life easier for merging code.
#define RAX EAX
#define RDX EDX
#endif
#if BX_CPU_LEVEL >= 5
bx_bool BX_CPP_AttrRegparmN(2) BX_CPU_C::rdmsr(Bit32u index, Bit64u *msr)
{
Bit64u val64 = 0;
if ((index & 0x3FFFFFFF) >= BX_MSR_MAX_INDEX)
return 0;
#if BX_SUPPORT_X2APIC
if (index >= 0x800 && index <= 0xBFF) {
if (BX_CPU_THIS_PTR msr.apicbase & 0x400) // X2APIC mode
return BX_CPU_THIS_PTR lapic.read_x2apic(index, msr);
else
return 0;
}
#endif
switch(index) {
#if BX_CPU_LEVEL >= 6
case BX_MSR_SYSENTER_CS:
if (! bx_cpuid_support_sep()) {
// failed to find the MSR, could #GP or ignore it silently
BX_ERROR(("RDMSR MSR_SYSENTER_CS: SYSENTER/SYSEXIT feature not enabled !"));
if (! BX_CPU_THIS_PTR ignore_bad_msrs)
return 0; // will result in #GP fault due to unknown MSR
}
val64 = BX_CPU_THIS_PTR msr.sysenter_cs_msr;
break;
case BX_MSR_SYSENTER_ESP:
if (! bx_cpuid_support_sep()) {
// failed to find the MSR, could #GP or ignore it silently
BX_ERROR(("RDMSR MSR_SYSENTER_ESP: SYSENTER/SYSEXIT feature not enabled !"));
if (! BX_CPU_THIS_PTR ignore_bad_msrs)
return 0; // will result in #GP fault due to unknown MSR
}
val64 = BX_CPU_THIS_PTR msr.sysenter_esp_msr;
break;
case BX_MSR_SYSENTER_EIP:
if (! bx_cpuid_support_sep()) {
// failed to find the MSR, could #GP or ignore it silently
BX_ERROR(("RDMSR MSR_SYSENTER_EIP: SYSENTER/SYSEXIT feature not enabled !"));
if (! BX_CPU_THIS_PTR ignore_bad_msrs)
return 0; // will result in #GP fault due to unknown MSR
}
val64 = BX_CPU_THIS_PTR msr.sysenter_eip_msr;
break;
#endif
#if BX_CPU_LEVEL >= 6
case BX_MSR_MTRRCAP: // read only MSR
val64 = BX_CONST64(0x0000000000000508);
break;
case BX_MSR_MTRRPHYSBASE0:
case BX_MSR_MTRRPHYSMASK0:
case BX_MSR_MTRRPHYSBASE1:
case BX_MSR_MTRRPHYSMASK1:
case BX_MSR_MTRRPHYSBASE2:
case BX_MSR_MTRRPHYSMASK2:
case BX_MSR_MTRRPHYSBASE3:
case BX_MSR_MTRRPHYSMASK3:
case BX_MSR_MTRRPHYSBASE4:
case BX_MSR_MTRRPHYSMASK4:
case BX_MSR_MTRRPHYSBASE5:
case BX_MSR_MTRRPHYSMASK5:
case BX_MSR_MTRRPHYSBASE6:
case BX_MSR_MTRRPHYSMASK6:
case BX_MSR_MTRRPHYSBASE7:
case BX_MSR_MTRRPHYSMASK7:
val64 = BX_CPU_THIS_PTR msr.mtrrphys[index - BX_MSR_MTRRPHYSBASE0];
break;
case BX_MSR_MTRRFIX64K_00000:
val64 = BX_CPU_THIS_PTR msr.mtrrfix64k_00000;
break;
case BX_MSR_MTRRFIX16K_80000:
case BX_MSR_MTRRFIX16K_A0000:
val64 = BX_CPU_THIS_PTR msr.mtrrfix16k[index - BX_MSR_MTRRFIX16K_80000];
break;
case BX_MSR_MTRRFIX4K_C0000:
case BX_MSR_MTRRFIX4K_C8000:
case BX_MSR_MTRRFIX4K_D0000:
case BX_MSR_MTRRFIX4K_D8000:
case BX_MSR_MTRRFIX4K_E0000:
case BX_MSR_MTRRFIX4K_E8000:
case BX_MSR_MTRRFIX4K_F0000:
case BX_MSR_MTRRFIX4K_F8000:
val64 = BX_CPU_THIS_PTR msr.mtrrfix4k[index - BX_MSR_MTRRFIX4K_C0000];
break;
case BX_MSR_PAT:
val64 = BX_CPU_THIS_PTR msr.pat;
break;
case BX_MSR_MTRR_DEFTYPE:
val64 = BX_CPU_THIS_PTR msr.mtrr_deftype;
break;
#endif
case BX_MSR_TSC:
val64 = BX_CPU_THIS_PTR get_TSC();
break;
#if BX_SUPPORT_APIC
case BX_MSR_APICBASE:
val64 = BX_CPU_THIS_PTR msr.apicbase;
BX_INFO(("RDMSR: Read %08x:%08x from MSR_APICBASE", GET32H(val64), GET32L(val64)));
break;
#endif
#if BX_SUPPORT_VMX
/*
case BX_MSR_IA32_SMM_MONITOR_CTL:
BX_PANIC(("Dual-monitor treatment of SMI and SMM is not implemented"));
break;
*/
case BX_MSR_IA32_FEATURE_CONTROL:
val64 = BX_CPU_THIS_PTR msr.ia32_feature_ctrl;
break;
case BX_MSR_VMX_BASIC:
val64 = VMX_MSR_VMX_BASIC;
break;
case BX_MSR_VMX_PINBASED_CTRLS:
val64 = VMX_MSR_VMX_PINBASED_CTRLS;
break;
case BX_MSR_VMX_PROCBASED_CTRLS:
val64 = VMX_MSR_VMX_PROCBASED_CTRLS;
break;
case BX_MSR_VMX_VMEXIT_CTRLS:
val64 = VMX_MSR_VMX_VMEXIT_CTRLS;
break;
case BX_MSR_VMX_VMENTRY_CTRLS:
val64 = VMX_MSR_VMX_VMENTRY_CTRLS;
break;
#if BX_SUPPORT_VMX >= 2
case BX_MSR_VMX_PROCBASED_CTRLS2:
val64 = VMX_MSR_VMX_PROCBASED_CTRLS2;
break;
case BX_MSR_VMX_TRUE_PINBASED_CTRLS:
val64 = VMX_MSR_VMX_TRUE_PINBASED_CTRLS;
break;
case BX_MSR_VMX_TRUE_PROCBASED_CTRLS:
val64 = VMX_MSR_VMX_TRUE_PROCBASED_CTRLS;
break;
case BX_MSR_VMX_TRUE_VMEXIT_CTRLS:
val64 = VMX_MSR_VMX_TRUE_VMEXIT_CTRLS;
break;
case BX_MSR_VMX_TRUE_VMENTRY_CTRLS:
val64 = VMX_MSR_VMX_TRUE_VMENTRY_CTRLS;
break;
case BX_MSR_VMX_MSR_VMX_EPT_VPID_CAP:
val64 = VMX_MSR_VMX_EPT_VPID_CAP;
break;
#endif
case BX_MSR_VMX_MISC:
val64 = VMX_MSR_MISC;
break;
case BX_MSR_VMX_CR0_FIXED0:
val64 = VMX_MSR_CR0_FIXED0;
break;
case BX_MSR_VMX_CR0_FIXED1:
val64 = VMX_MSR_CR0_FIXED1;
break;
case BX_MSR_VMX_CR4_FIXED0:
val64 = VMX_MSR_CR4_FIXED0;
break;
case BX_MSR_VMX_CR4_FIXED1:
val64 = VMX_MSR_CR4_FIXED1;
break;
case BX_MSR_VMX_VMCS_ENUM:
val64 = VMX_MSR_VMCS_ENUM;
break;
#endif
#if BX_SUPPORT_X86_64
case BX_MSR_EFER:
val64 = BX_CPU_THIS_PTR efer.get32();
break;
case BX_MSR_STAR:
val64 = MSR_STAR;
break;
case BX_MSR_LSTAR:
val64 = MSR_LSTAR;
break;
case BX_MSR_CSTAR:
val64 = MSR_CSTAR;
break;
case BX_MSR_FMASK:
val64 = MSR_FMASK;
break;
case BX_MSR_FSBASE:
val64 = MSR_FSBASE;
break;
case BX_MSR_GSBASE:
val64 = MSR_GSBASE;
break;
case BX_MSR_KERNELGSBASE:
val64 = MSR_KERNELGSBASE;
break;
case BX_MSR_TSC_AUX:
val64 = MSR_TSC_AUX; // 32 bit MSR
break;
#endif // #if BX_SUPPORT_X86_64
default:
#if BX_CONFIGURE_MSRS
if (index < BX_MSR_MAX_INDEX && BX_CPU_THIS_PTR msrs[index]) {
val64 = BX_CPU_THIS_PTR msrs[index]->get64();
break;
}
#endif
// failed to find the MSR, could #GP or ignore it silently
BX_ERROR(("RDMSR: Unknown register %#x", index));
if (! BX_CPU_THIS_PTR ignore_bad_msrs)
return 0; // will result in #GP fault due to unknown MSR
}
BX_DEBUG(("RDMSR: read %08x:%08x from MSR %x", GET32H(val64), GET32L(val64), index));
*msr = val64;
return 1;
}
#endif // BX_CPU_LEVEL >= 5
void BX_CPP_AttrRegparmN(1) BX_CPU_C::RDMSR(bxInstruction_c *i)
{
#if BX_CPU_LEVEL >= 5
if (!real_mode() && CPL != 0) {
BX_ERROR(("RDMSR: CPL != 0 not in real mode"));
exception(BX_GP_EXCEPTION, 0);
}
Bit32u index = ECX;
Bit64u val64 = 0;
#if BX_SUPPORT_VMX
VMexit_MSR(i, VMX_VMEXIT_RDMSR, index);
#endif
#if BX_SUPPORT_VMX >= 2
if (BX_CPU_THIS_PTR in_vmx_guest && index == 0x808) {
if (SECONDARY_VMEXEC_CONTROL(VMX_VM_EXEC_CTRL3_VIRTUALIZE_X2APIC_MODE)) {
RAX = VMX_Read_VTPR() & 0xff;
RDX = 0;
return;
}
}
#endif
if (!rdmsr(index, &val64))
exception(BX_GP_EXCEPTION, 0);
RAX = GET32L(val64);
RDX = GET32H(val64);
#endif
}
#if BX_CPU_LEVEL >= 6
bx_bool isMemTypeValidMTRR(unsigned memtype)
{
switch(memtype) {
case BX_MEMTYPE_UC:
case BX_MEMTYPE_WC:
case BX_MEMTYPE_WT:
case BX_MEMTYPE_WP:
case BX_MEMTYPE_WB:
return 1;
default:
return 0;
}
}
BX_CPP_INLINE bx_bool isMemTypeValidPAT(unsigned memtype)
{
return (memtype == 0x07) /* UC- */ || isMemTypeValidMTRR(memtype);
}
bx_bool isValidMSR_PAT(Bit64u pat_msr)
{
if (! isMemTypeValidPAT(pat_msr & 0xFF) ||
! isMemTypeValidPAT((pat_msr >> 8) & 0xFF) ||
! isMemTypeValidPAT((pat_msr >> 16) & 0xFF) ||
! isMemTypeValidPAT((pat_msr >> 24) & 0xFF) ||
! isMemTypeValidPAT((pat_msr >> 32) & 0xFF) ||
! isMemTypeValidPAT((pat_msr >> 40) & 0xFF) ||
! isMemTypeValidPAT((pat_msr >> 48) & 0xFF) ||
! isMemTypeValidPAT(pat_msr >> 56)) return 0;
return 1;
}
bx_bool isValidMSR_FixedMTRR(Bit64u fixed_mtrr_msr)
{
if (! isMemTypeValidMTRR(fixed_mtrr_msr & 0xFF) ||
! isMemTypeValidMTRR((fixed_mtrr_msr >> 8) & 0xFF) ||
! isMemTypeValidMTRR((fixed_mtrr_msr >> 16) & 0xFF) ||
! isMemTypeValidMTRR((fixed_mtrr_msr >> 24) & 0xFF) ||
! isMemTypeValidMTRR((fixed_mtrr_msr >> 32) & 0xFF) ||
! isMemTypeValidMTRR((fixed_mtrr_msr >> 40) & 0xFF) ||
! isMemTypeValidMTRR((fixed_mtrr_msr >> 48) & 0xFF) ||
! isMemTypeValidMTRR(fixed_mtrr_msr >> 56)) return 0;
return 1;
}
#endif
#if BX_CPU_LEVEL >= 5
bx_bool BX_CPP_AttrRegparmN(2) BX_CPU_C::wrmsr(Bit32u index, Bit64u val_64)
{
Bit32u val32_lo = GET32L(val_64);
Bit32u val32_hi = GET32H(val_64);
BX_INSTR_WRMSR(BX_CPU_ID, index, val_64);
BX_DEBUG(("WRMSR: write %08x:%08x to MSR %x", val32_hi, val32_lo, index));
if ((index & 0x3FFFFFFF) >= BX_MSR_MAX_INDEX)
return 0;
#if BX_SUPPORT_X2APIC
if (index >= 0x800 && index <= 0xBFF) {
if (BX_CPU_THIS_PTR msr.apicbase & 0x400) // X2APIC mode
return BX_CPU_THIS_PTR lapic.write_x2apic(index, val_64);
else
return 0;
}
#endif
switch(index) {
#if BX_CPU_LEVEL >= 6
case BX_MSR_SYSENTER_CS:
if (! bx_cpuid_support_sep()) {
// failed to find the MSR, could #GP or ignore it silently
BX_ERROR(("WRMSR MSR_SYSENTER_CS: SYSENTER/SYSEXIT feature not enabled !"));
if (! BX_CPU_THIS_PTR ignore_bad_msrs)
return 0; // will result in #GP fault due to unknown MSR
}
BX_CPU_THIS_PTR msr.sysenter_cs_msr = val32_lo;
break;
case BX_MSR_SYSENTER_ESP:
if (! bx_cpuid_support_sep()) {
// failed to find the MSR, could #GP or ignore it silently
BX_ERROR(("WRMSR MSR_SYSENTER_ESP: SYSENTER/SYSEXIT feature not enabled !"));
if (! BX_CPU_THIS_PTR ignore_bad_msrs)
return 0; // will result in #GP fault due to unknown MSR
}
#if BX_SUPPORT_X86_64
if (! IsCanonical(val_64)) {
BX_ERROR(("WRMSR: attempt to write non-canonical value to MSR_SYSENTER_ESP !"));
return 0;
}
#endif
BX_CPU_THIS_PTR msr.sysenter_esp_msr = val_64;
break;
case BX_MSR_SYSENTER_EIP:
if (! bx_cpuid_support_sep()) {
// failed to find the MSR, could #GP or ignore it silently
BX_ERROR(("WRMSR MSR_SYSENTER_EIP: SYSENTER/SYSEXIT feature not enabled !"));
if (! BX_CPU_THIS_PTR ignore_bad_msrs)
return 0; // will result in #GP fault due to unknown MSR
}
#if BX_SUPPORT_X86_64
if (! IsCanonical(val_64)) {
BX_ERROR(("WRMSR: attempt to write non-canonical value to MSR_SYSENTER_EIP !"));
return 0;
}
#endif
BX_CPU_THIS_PTR msr.sysenter_eip_msr = val_64;
break;
#endif
#if BX_CPU_LEVEL >= 6
case BX_MSR_MTRRCAP:
BX_ERROR(("WRMSR: MTRRCAP is read only MSR"));
return 0;
case BX_MSR_MTRRPHYSBASE0:
case BX_MSR_MTRRPHYSBASE1:
case BX_MSR_MTRRPHYSBASE2:
case BX_MSR_MTRRPHYSBASE3:
case BX_MSR_MTRRPHYSBASE4:
case BX_MSR_MTRRPHYSBASE5:
case BX_MSR_MTRRPHYSBASE6:
case BX_MSR_MTRRPHYSBASE7:
if (! IsValidPhyAddr(val_64)) {
BX_ERROR(("WRMSR[0x%08x]: attempt to write invalid phy addr to variable range MTRR %08x:%08x", index, val32_hi, val32_lo));
return 0;
}
// handle 8-11 reserved bits
if (! isMemTypeValidMTRR(val32_lo & 0xFFF)) {
BX_ERROR(("WRMSR: attempt to write invalid Memory Type to BX_MSR_MTRRPHYSBASE"));
return 0;
}
BX_CPU_THIS_PTR msr.mtrrphys[index - BX_MSR_MTRRPHYSBASE0] = val_64;
break;
case BX_MSR_MTRRPHYSMASK0:
case BX_MSR_MTRRPHYSMASK1:
case BX_MSR_MTRRPHYSMASK2:
case BX_MSR_MTRRPHYSMASK3:
case BX_MSR_MTRRPHYSMASK4:
case BX_MSR_MTRRPHYSMASK5:
case BX_MSR_MTRRPHYSMASK6:
case BX_MSR_MTRRPHYSMASK7:
if (! IsValidPhyAddr(val_64)) {
BX_ERROR(("WRMSR[0x%08x]: attempt to write invalid phy addr to variable range MTRR %08x:%08x", index, val32_hi, val32_lo));
return 0;
}
// handle 10-0 reserved bits
if (val32_lo & 0x7ff) {
BX_ERROR(("WRMSR[0x%08x]: variable range MTRR reserved bits violation %08x:%08x", index, val32_hi, val32_lo));
return 0;
}
BX_CPU_THIS_PTR msr.mtrrphys[index - BX_MSR_MTRRPHYSBASE0] = val_64;
break;
case BX_MSR_MTRRFIX64K_00000:
if (! isValidMSR_FixedMTRR(val_64)) {
BX_ERROR(("WRMSR: attempt to write invalid Memory Type to MSR_MTRRFIX64K_00000 !"));
return 0;
}
BX_CPU_THIS_PTR msr.mtrrfix64k_00000 = val_64;
break;
case BX_MSR_MTRRFIX16K_80000:
case BX_MSR_MTRRFIX16K_A0000:
if (! isValidMSR_FixedMTRR(val_64)) {
BX_ERROR(("WRMSR: attempt to write invalid Memory Type to MSR_MTRRFIX16K regsiter !"));
return 0;
}
BX_CPU_THIS_PTR msr.mtrrfix16k[index - BX_MSR_MTRRFIX16K_80000] = val_64;
break;
case BX_MSR_MTRRFIX4K_C0000:
case BX_MSR_MTRRFIX4K_C8000:
case BX_MSR_MTRRFIX4K_D0000:
case BX_MSR_MTRRFIX4K_D8000:
case BX_MSR_MTRRFIX4K_E0000:
case BX_MSR_MTRRFIX4K_E8000:
case BX_MSR_MTRRFIX4K_F0000:
case BX_MSR_MTRRFIX4K_F8000:
if (! isValidMSR_FixedMTRR(val_64)) {
BX_ERROR(("WRMSR: attempt to write invalid Memory Type to fixed memory range MTRR !"));
return 0;
}
BX_CPU_THIS_PTR msr.mtrrfix4k[index - BX_MSR_MTRRFIX4K_C0000] = val_64;
break;
case BX_MSR_PAT:
if (! isValidMSR_PAT(val_64)) {
BX_ERROR(("WRMSR: attempt to write invalid Memory Type to MSR_PAT"));
return 0;
}
BX_CPU_THIS_PTR msr.pat = val_64;
break;
case BX_MSR_MTRR_DEFTYPE:
if (! isMemTypeValidMTRR(val32_lo & 0xFF)) {
BX_ERROR(("WRMSR: attempt to write invalid Memory Type to MSR_MTRR_DEFTYPE"));
return 0;
}
if (val32_hi || (val32_lo & 0xfffff300)) {
BX_ERROR(("WRMSR: attempt to reserved bits in MSR_MTRR_DEFTYPE"));
return 0;
}
BX_CPU_THIS_PTR msr.mtrr_deftype = val32_lo;
break;
#endif
case BX_MSR_TSC:
BX_INFO(("WRMSR: write 0x%08x%08x to MSR_TSC", val32_hi, val32_lo));
BX_CPU_THIS_PTR set_TSC(val_64);
break;
#if BX_SUPPORT_APIC
case BX_MSR_APICBASE:
return relocate_apic(val_64);
#endif
#if BX_SUPPORT_VMX
// Support only two bits: lock bit (bit 0) and VMX enable (bit 2)
case BX_MSR_IA32_FEATURE_CONTROL:
if (BX_CPU_THIS_PTR msr.ia32_feature_ctrl & 0x1) {
BX_ERROR(("WRMSR: IA32_FEATURE_CONTROL_MSR VMX lock bit is set !"));
return 0;
}
/*
if (val_64 & ~((Bit64u)(BX_IA32_FEATURE_CONTROL_BITS))) {
BX_ERROR(("WRMSR: attempt to set reserved bits of IA32_FEATURE_CONTROL_MSR !"));
return 0;
}
*/
BX_CPU_THIS_PTR msr.ia32_feature_ctrl = val32_lo;
break;
case BX_MSR_VMX_BASIC:
case BX_MSR_VMX_PINBASED_CTRLS:
case BX_MSR_VMX_PROCBASED_CTRLS:
case BX_MSR_VMX_PROCBASED_CTRLS2:
case BX_MSR_VMX_VMEXIT_CTRLS:
case BX_MSR_VMX_VMENTRY_CTRLS:
case BX_MSR_VMX_MISC:
case BX_MSR_VMX_CR0_FIXED0:
case BX_MSR_VMX_CR0_FIXED1:
case BX_MSR_VMX_CR4_FIXED0:
case BX_MSR_VMX_CR4_FIXED1:
case BX_MSR_VMX_VMCS_ENUM:
case BX_MSR_VMX_MSR_VMX_EPT_VPID_CAP:
case BX_MSR_VMX_TRUE_PINBASED_CTRLS:
case BX_MSR_VMX_TRUE_PROCBASED_CTRLS:
case BX_MSR_VMX_TRUE_VMEXIT_CTRLS:
case BX_MSR_VMX_TRUE_VMENTRY_CTRLS:
BX_ERROR(("WRMSR: VMX read only MSR"));
return 0;
#endif
#if BX_SUPPORT_X86_64
case BX_MSR_EFER:
if (val_64 & ~BX_EFER_SUPPORTED_BITS) {
BX_ERROR(("WRMSR: attempt to set reserved bits of EFER MSR !"));
return 0;
}
/* #GP(0) if changing EFER.LME when cr0.pg = 1 */
if ((BX_CPU_THIS_PTR efer.get_LME() != ((val32_lo >> 8) & 1)) &&
BX_CPU_THIS_PTR cr0.get_PG())
{
BX_ERROR(("WRMSR: attempt to change LME when CR0.PG=1"));
return 0;
}
BX_CPU_THIS_PTR efer.set32((val32_lo & BX_EFER_SUPPORTED_BITS & ~BX_EFER_LMA_MASK)
| (BX_CPU_THIS_PTR efer.get32() & BX_EFER_LMA_MASK)); // keep LMA untouched
break;
case BX_MSR_STAR:
MSR_STAR = val_64;
break;
case BX_MSR_LSTAR:
if (! IsCanonical(val_64)) {
BX_ERROR(("WRMSR: attempt to write non-canonical value to MSR_LSTAR !"));
return 0;
}
MSR_LSTAR = val_64;
break;
case BX_MSR_CSTAR:
if (! IsCanonical(val_64)) {
BX_ERROR(("WRMSR: attempt to write non-canonical value to MSR_CSTAR !"));
return 0;
}
MSR_CSTAR = val_64;
break;
case BX_MSR_FMASK:
MSR_FMASK = (Bit32u) val_64;
break;
case BX_MSR_FSBASE:
if (! IsCanonical(val_64)) {
BX_ERROR(("WRMSR: attempt to write non-canonical value to MSR_FSBASE !"));
return 0;
}
MSR_FSBASE = val_64;
break;
case BX_MSR_GSBASE:
if (! IsCanonical(val_64)) {
BX_ERROR(("WRMSR: attempt to write non-canonical value to MSR_GSBASE !"));
return 0;
}
MSR_GSBASE = val_64;
break;
case BX_MSR_KERNELGSBASE:
if (! IsCanonical(val_64)) {
BX_ERROR(("WRMSR: attempt to write non-canonical value to MSR_KERNELGSBASE !"));
return 0;
}
MSR_KERNELGSBASE = val_64;
break;
case BX_MSR_TSC_AUX:
MSR_TSC_AUX = val32_lo;
break;
#endif // #if BX_SUPPORT_X86_64
default:
#if BX_CONFIGURE_MSRS
if (index < BX_MSR_MAX_INDEX && BX_CPU_THIS_PTR msrs[index]) {
if (! BX_CPU_THIS_PTR msrs[index]->set64(val_64)) {
BX_ERROR(("WRMSR: Write failed to MSR %#x - #GP fault", index));
return 0;
}
break;
}
#endif
// failed to find the MSR, could #GP or ignore it silently
BX_ERROR(("WRMSR: Unknown register %#x", index));
if (! BX_CPU_THIS_PTR ignore_bad_msrs)
return 0; // will result in #GP fault due to unknown MSR
}
return 1;
}
#endif // BX_CPU_LEVEL >= 5
#if BX_SUPPORT_APIC
bx_bool BX_CPU_C::relocate_apic(Bit64u val_64)
{
/* MSR_APICBASE
* [0:7] Reserved
* [8] This is set if CPU is BSP
* [9] Reserved
* [10] X2APIC mode bit (1=enabled 0=disabled)
* [11] APIC Global Enable bit (1=enabled 0=disabled)
* [12:M] APIC Base Address (physical)
* [M:63] Reserved
*/
#define BX_MSR_APICBASE_RESERVED_BITS (0x2ff | (BX_SUPPORT_X2APIC ? 0 : 0x400))
if (BX_CPU_THIS_PTR msr.apicbase & 0x800) {
Bit32u val32_hi = GET32H(val_64), val32_lo = GET32L(val_64);
BX_INFO(("WRMSR: wrote %08x:%08x to MSR_APICBASE", val32_hi, val32_lo));
#if BX_SUPPORT_X86_64
if (! IsValidPhyAddr(val_64)) {
BX_ERROR(("relocate_apic: invalid physical address"));
return 0;
}
#endif
if (val32_lo & BX_MSR_APICBASE_RESERVED_BITS) {
BX_ERROR(("relocate_apic: attempt to set reserved bits"));
return 0;
}
#if BX_SUPPORT_X2APIC
unsigned apic_state = (BX_CPU_THIS_PTR msr.apicbase >> 10) & 3;
unsigned new_state = (val32_lo >> 10) & 3;
if (new_state == BX_APIC_STATE_INVALID) {
BX_ERROR(("relocate_apic: attempt to set invalid apic state"));
return 0;
}
if (apic_state == BX_APIC_X2APIC_MODE && new_state != BX_APIC_GLOBALLY_DISABLED) {
BX_ERROR(("relocate_apic: attempt to switch from x2apic -> xapic"));
return 0;
}
#endif
BX_CPU_THIS_PTR msr.apicbase = (bx_phy_address) val_64;
BX_CPU_THIS_PTR lapic.set_base(BX_CPU_THIS_PTR msr.apicbase);
// TLB flush is required for emulation correctness
TLB_flush(); // don't care about performance of apic relocation
if ((val32_lo & 0x800) == 0) {
// APIC global enable bit cleared, clear APIC on chip CPUID feature flag
BX_CPU_THIS_PTR cpuid_std_function[0x1].edx &= ~(1<<9);
BX_CPU_THIS_PTR cpuid_ext_function[0x1].edx &= ~(1<<9);
}
}
else {
BX_INFO(("WRMSR: MSR_APICBASE APIC global enable bit cleared !"));
}
return 1;
}
#endif
void BX_CPP_AttrRegparmN(1) BX_CPU_C::WRMSR(bxInstruction_c *i)
{
#if BX_CPU_LEVEL >= 5
if (!real_mode() && CPL != 0) {
BX_ERROR(("WRMSR: CPL != 0 not in real mode"));
exception(BX_GP_EXCEPTION, 0);
}
Bit64u val_64 = ((Bit64u) EDX << 32) | EAX;
Bit32u index = ECX;
#if BX_SUPPORT_VMX
VMexit_MSR(i, VMX_VMEXIT_WRMSR, index);
#endif
#if BX_SUPPORT_VMX >= 2
if (BX_CPU_THIS_PTR in_vmx_guest && index == 0x808) {
if (SECONDARY_VMEXEC_CONTROL(VMX_VM_EXEC_CTRL3_VIRTUALIZE_X2APIC_MODE)) {
VMX_Write_VTPR(AL);
return;
}
}
#endif
if (! wrmsr(index, val_64))
exception(BX_GP_EXCEPTION, 0);
#endif
}
#if BX_CONFIGURE_MSRS
int BX_CPU_C::load_MSRs(const char *file)
{
char line[512];
unsigned linenum = 0;
Bit32u index, type;
Bit32u reset_hi, reset_lo;
Bit32u rsrv_hi, rsrv_lo;
Bit32u ignr_hi, ignr_lo;
FILE *fd = fopen (file, "r");
if (fd == NULL) return -1;
int retval = 0;
do {
linenum++;
char* ret = fgets(line, sizeof(line)-1, fd);
line[sizeof(line) - 1] = '\0';
size_t len = strlen(line);
if (len>0 && line[len-1] < ' ')
line[len-1] = '\0';
if (ret != NULL && strlen(line)) {
if (line[0] == '#') continue;
retval = sscanf(line, "%x %d %08x %08x %08x %08x %08x %08x",
&index, &type, &reset_hi, &reset_lo, &rsrv_hi, &rsrv_lo, &ignr_hi, &ignr_lo);
if (retval < 8) {
retval = -1;
BX_PANIC(("%s:%d > error parsing MSRs config file!", file, linenum));
break; // quit parsing after first error
}
if (index >= BX_MSR_MAX_INDEX) {
BX_PANIC(("%s:%d > MSR index is too big !", file, linenum));
continue;
}
if (BX_CPU_THIS_PTR msrs[index]) {
BX_PANIC(("%s:%d > MSR[0x%03x] is already defined!", file, linenum, index));
continue;
}
if (type > 2) {
BX_PANIC(("%s:%d > MSR[0x%03x] unknown type !", file, linenum, index));
continue;
}
BX_INFO(("loaded MSR[0x%03x] type=%d %08x:%08x %08x:%08x %08x:%08x", index, type,
reset_hi, reset_lo, rsrv_hi, rsrv_lo, ignr_hi, ignr_lo));
BX_CPU_THIS_PTR msrs[index] = new MSR(index, type,
((Bit64u)(reset_hi) << 32) | reset_lo,
((Bit64u) (rsrv_hi) << 32) | rsrv_lo,
((Bit64u) (ignr_hi) << 32) | ignr_lo);
}
} while (!feof(fd));
fclose(fd);
return retval;
}
#endif

View File

@ -0,0 +1,159 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2001-2009 The Bochs Project
//
// 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
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA B 02110-1301 USA
/////////////////////////////////////////////////////////////////////////
#define NEED_CPU_REG_SHORTCUTS 1
#include "bochs.h"
#include "cpu.h"
#define LOG_THIS BX_CPU_THIS_PTR
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MUL_AXEwR(bxInstruction_c *i)
{
Bit16u op1_16 = AX;
Bit16u op2_16 = BX_READ_16BIT_REG(i->rm());
Bit32u product_32 = ((Bit32u) op1_16) * ((Bit32u) op2_16);
Bit16u product_16l = (product_32 & 0xFFFF);
Bit16u product_16h = product_32 >> 16;
/* now write product back to destination */
AX = product_16l;
DX = product_16h;
/* set EFLAGS */
SET_FLAGS_OSZAPC_LOGIC_16(product_16l);
if(product_16h != 0)
{
ASSERT_FLAGS_OxxxxC();
}
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::IMUL_AXEwR(bxInstruction_c *i)
{
Bit16s op1_16 = AX;
Bit16s op2_16 = BX_READ_16BIT_REG(i->rm());
Bit32s product_32 = ((Bit32s) op1_16) * ((Bit32s) op2_16);
Bit16u product_16l = (product_32 & 0xFFFF);
Bit16u product_16h = product_32 >> 16;
/* now write product back to destination */
AX = product_16l;
DX = product_16h;
/* set eflags:
* IMUL r/m16: condition for clearing CF & OF:
* DX:AX = sign-extend of AX
*/
SET_FLAGS_OSZAPC_LOGIC_16(product_16l);
if(product_32 != (Bit16s)product_32)
{
ASSERT_FLAGS_OxxxxC();
}
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::DIV_AXEwR(bxInstruction_c *i)
{
Bit16u op2_16 = BX_READ_16BIT_REG(i->rm());
if (op2_16 == 0)
exception(BX_DE_EXCEPTION, 0);
Bit32u op1_32 = (((Bit32u) DX) << 16) | ((Bit32u) AX);
Bit32u quotient_32 = op1_32 / op2_16;
Bit16u remainder_16 = op1_32 % op2_16;
Bit16u quotient_16l = quotient_32 & 0xFFFF;
if (quotient_32 != quotient_16l)
exception(BX_DE_EXCEPTION, 0);
/* now write quotient back to destination */
AX = quotient_16l;
DX = remainder_16;
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::IDIV_AXEwR(bxInstruction_c *i)
{
Bit32s op1_32 = ((((Bit32u) DX) << 16) | ((Bit32u) AX));
/* check MIN_INT case */
if (op1_32 == ((Bit32s)0x80000000))
exception(BX_DE_EXCEPTION, 0);
Bit16s op2_16 = BX_READ_16BIT_REG(i->rm());
if (op2_16 == 0)
exception(BX_DE_EXCEPTION, 0);
Bit32s quotient_32 = op1_32 / op2_16;
Bit16s remainder_16 = op1_32 % op2_16;
Bit16s quotient_16l = quotient_32 & 0xFFFF;
if (quotient_32 != quotient_16l)
exception(BX_DE_EXCEPTION, 0);
/* now write quotient back to destination */
AX = quotient_16l;
DX = remainder_16;
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::IMUL_GwEwIwR(bxInstruction_c *i)
{
Bit16s op2_16 = BX_READ_16BIT_REG(i->rm());
Bit16s op3_16 = i->Iw();
Bit32s product_32 = op2_16 * op3_16;
Bit16u product_16 = (product_32 & 0xFFFF);
/* now write product back to destination */
BX_WRITE_16BIT_REG(i->nnn(), product_16);
/* set eflags:
* IMUL r16,r/m16,imm16: condition for clearing CF & OF:
* result exactly fits within r16
*/
SET_FLAGS_OSZAPC_LOGIC_16(product_16);
if(product_32 != (Bit16s) product_32)
{
ASSERT_FLAGS_OxxxxC();
}
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::IMUL_GwEwR(bxInstruction_c *i)
{
Bit16s op1_16 = BX_READ_16BIT_REG(i->nnn());
Bit16s op2_16 = BX_READ_16BIT_REG(i->rm());
Bit32s product_32 = op1_16 * op2_16;
Bit16u product_16 = (product_32 & 0xFFFF);
/* now write product back to destination */
BX_WRITE_16BIT_REG(i->nnn(), product_16);
/* set eflags:
* IMUL r16,r/m16: condition for clearing CF & OF:
* result exactly fits within r16
*/
SET_FLAGS_OSZAPC_LOGIC_16(product_16);
if(product_32 != (Bit16s) product_32)
{
ASSERT_FLAGS_OxxxxC();
}
}

View File

@ -0,0 +1,177 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2001-2009 The Bochs Project
//
// 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
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA B 02110-1301 USA
/////////////////////////////////////////////////////////////////////////
#define NEED_CPU_REG_SHORTCUTS 1
#include "bochs.h"
#include "cpu.h"
#define LOG_THIS BX_CPU_THIS_PTR
#if BX_SUPPORT_X86_64==0
#define RAX EAX
#define RDX EDX
#endif
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MUL_EAXEdR(bxInstruction_c *i)
{
Bit32u op1_32 = EAX;
Bit32u op2_32 = BX_READ_32BIT_REG(i->rm());
Bit64u product_64 = ((Bit64u) op1_32) * ((Bit64u) op2_32);
Bit32u product_32l = GET32L(product_64);
Bit32u product_32h = GET32H(product_64);
/* now write product back to destination */
RAX = product_32l;
RDX = product_32h;
/* set EFLAGS */
SET_FLAGS_OSZAPC_LOGIC_32(product_32l);
if(product_32h != 0)
{
ASSERT_FLAGS_OxxxxC();
}
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::IMUL_EAXEdR(bxInstruction_c *i)
{
Bit32s op1_32 = EAX;
Bit32s op2_32 = BX_READ_32BIT_REG(i->rm());
Bit64s product_64 = ((Bit64s) op1_32) * ((Bit64s) op2_32);
Bit32u product_32l = GET32L(product_64);
Bit32u product_32h = GET32H(product_64);
/* now write product back to destination */
RAX = product_32l;
RDX = product_32h;
/* set eflags:
* IMUL r/m32: condition for clearing CF & OF:
* EDX:EAX = sign-extend of EAX
*/
SET_FLAGS_OSZAPC_LOGIC_32(product_32l);
if(product_64 != (Bit32s)product_64)
{
ASSERT_FLAGS_OxxxxC();
}
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::DIV_EAXEdR(bxInstruction_c *i)
{
Bit32u op2_32 = BX_READ_32BIT_REG(i->rm());
if (op2_32 == 0) {
exception(BX_DE_EXCEPTION, 0);
}
Bit64u op1_64 = (((Bit64u) EDX) << 32) + ((Bit64u) EAX);
Bit64u quotient_64 = op1_64 / op2_32;
Bit32u remainder_32 = (Bit32u) (op1_64 % op2_32);
Bit32u quotient_32l = (Bit32u) (quotient_64 & 0xFFFFFFFF);
if (quotient_64 != quotient_32l)
{
exception(BX_DE_EXCEPTION, 0);
}
/* set EFLAGS:
* DIV affects the following flags: O,S,Z,A,P,C are undefined
*/
/* now write quotient back to destination */
RAX = quotient_32l;
RDX = remainder_32;
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::IDIV_EAXEdR(bxInstruction_c *i)
{
Bit64s op1_64 = (((Bit64u) EDX) << 32) | ((Bit64u) EAX);
/* check MIN_INT case */
if (op1_64 == ((Bit64s)BX_CONST64(0x8000000000000000)))
exception(BX_DE_EXCEPTION, 0);
Bit32s op2_32 = BX_READ_32BIT_REG(i->rm());
if (op2_32 == 0)
exception(BX_DE_EXCEPTION, 0);
Bit64s quotient_64 = op1_64 / op2_32;
Bit32s remainder_32 = (Bit32s) (op1_64 % op2_32);
Bit32s quotient_32l = (Bit32s) (quotient_64 & 0xFFFFFFFF);
if (quotient_64 != quotient_32l)
{
exception(BX_DE_EXCEPTION, 0);
}
/* set EFLAGS:
* IDIV affects the following flags: O,S,Z,A,P,C are undefined
*/
/* now write quotient back to destination */
RAX = (Bit32u) quotient_32l;
RDX = (Bit32u) remainder_32;
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::IMUL_GdEdIdR(bxInstruction_c *i)
{
Bit32s op2_32 = BX_READ_32BIT_REG(i->rm());
Bit32s op3_32 = i->Id();
Bit64s product_64 = ((Bit64s) op2_32) * ((Bit64s) op3_32);
Bit32u product_32 = (Bit32u)(product_64 & 0xFFFFFFFF);
/* now write product back to destination */
BX_WRITE_32BIT_REGZ(i->nnn(), product_32);
/* set eflags:
* IMUL r32,r/m32,imm32: condition for clearing CF & OF:
* result exactly fits within r32
*/
SET_FLAGS_OSZAPC_LOGIC_32(product_32);
if(product_64 != (Bit32s) product_64)
{
ASSERT_FLAGS_OxxxxC();
}
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::IMUL_GdEdR(bxInstruction_c *i)
{
Bit32s op1_32 = BX_READ_32BIT_REG(i->nnn());
Bit32s op2_32 = BX_READ_32BIT_REG(i->rm());
Bit64s product_64 = ((Bit64s) op1_32) * ((Bit64s) op2_32);
Bit32u product_32 = (Bit32u)(product_64 & 0xFFFFFFFF);
/* now write product back to destination */
BX_WRITE_32BIT_REGZ(i->nnn(), product_32);
/* set eflags:
* IMUL r32,r/m32: condition for clearing CF & OF:
* result exactly fits within r32
*/
SET_FLAGS_OSZAPC_LOGIC_32(product_32);
if(product_64 != (Bit32s) product_64)
{
ASSERT_FLAGS_OxxxxC();
}
}

View File

@ -0,0 +1,367 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2001-2009 The Bochs Project
//
// 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
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA B 02110-1301 USA
/////////////////////////////////////////////////////////////////////////
#define NEED_CPU_REG_SHORTCUTS 1
#include "bochs.h"
#include "cpu.h"
#define LOG_THIS BX_CPU_THIS_PTR
#if BX_SUPPORT_X86_64
static unsigned partial_add(Bit32u *sum,Bit32u b)
{
Bit32u t = *sum;
*sum += b;
return (*sum < t);
}
void long_mul(Bit128u *product, Bit64u op1, Bit64u op2)
{
Bit32u op_1[2],op_2[2];
Bit32u result[5];
Bit64u nn;
unsigned c;
int i,j,k;
op_1[0] = (Bit32u)(op1 & 0xffffffff);
op_1[1] = (Bit32u)(op1 >> 32);
op_2[0] = (Bit32u)(op2 & 0xffffffff);
op_2[1] = (Bit32u)(op2 >> 32);
for (i = 0; i < 4; i++) result[i] = 0;
for (i = 0; i < 2; i++) {
for (j = 0; j < 2; j++) {
nn = (Bit64u) op_1[i] * (Bit64u) op_2[j];
k = i + j;
c = partial_add(&result[k++], (Bit32u)(nn & 0xffffffff));
c = partial_add(&result[k++], (Bit32u)(nn >> 32) + c);
while (k < 4 && c != 0) {
c = partial_add(&result[k++], c);
}
}
}
product->lo = result[0] + ((Bit64u) result[1] << 32);
product->hi = result[2] + ((Bit64u) result[3] << 32);
}
void long_neg(Bit128s *n)
{
Bit64u t = n->lo;
n->lo = - (Bit64s)(n->lo);
if (t - 1 > t) --n->hi;
n->hi = ~n->hi;
}
void long_imul(Bit128s *product, Bit64s op1, Bit64s op2)
{
unsigned s1,s2;
if ((s1 = (op1 < 0))) op1 = -op1;
if ((s2 = (op2 < 0))) op2 = -op2;
long_mul((Bit128u*)product,(Bit64u)op1,(Bit64u)op2);
if (s1 ^ s2)
long_neg(product);
}
void long_shl(Bit128u *a)
{
Bit64u c = a->lo >> 63;
a->lo <<= 1;
a->hi <<= 1;
a->hi |= c;
}
void long_shr(Bit128u *a)
{
Bit64u c;
c = a->hi << 63;
a->hi >>= 1;
a->lo >>= 1;
a->lo |= c;
}
unsigned long_sub(Bit128u *a,Bit128u *b)
{
Bit64u t = a->lo;
a->lo -= b->lo;
int c = (a->lo > t);
t = a -> hi;
a->hi -= b->hi + c;
return(a->hi > t);
}
int long_le(Bit128u *a,Bit128u *b)
{
if (a->hi == b->hi) {
return(a->lo <= b->lo);
} else {
return(a->hi <= b->hi);
}
}
void long_div(Bit128u *quotient,Bit64u *remainder,const Bit128u *dividend,Bit64u divisor)
{
/*
n := 0;
while (divisor <= dividend) do
inc(n);
divisor := divisor * 2;
end;
quotient := 0;
while n > 0 do
divisor := divisor div 2;
quotient := quotient * 2;
temp := dividend;
dividend := dividend - divisor;
if temp > dividend then
dividend := temp;
else
inc(quotient);
end;
dec(n);
end;
remainder := dividend;
*/
Bit128u d,acc,q,temp;
int n,c;
d.lo = divisor;
d.hi = 0;
acc.lo = dividend->lo;
acc.hi = dividend->hi;
q.lo = 0;
q.hi = 0;
n = 0;
while (long_le(&d,&acc) && n < 128) {
long_shl(&d);
n++;
}
while (n > 0) {
long_shr(&d);
long_shl(&q);
temp.lo = acc.lo;
temp.hi = acc.hi;
c = long_sub(&acc,&d);
if (c) {
acc.lo = temp.lo;
acc.hi = temp.hi;
} else {
q.lo++;
}
n--;
}
*remainder = acc.lo;
quotient->lo = q.lo;
quotient->hi = q.hi;
}
void long_idiv(Bit128s *quotient,Bit64s *remainder,Bit128s *dividend,Bit64s divisor)
{
unsigned s1,s2;
Bit128s temp;
temp = *dividend;
if ((s1 = (temp.hi < 0))) {
long_neg(&temp);
}
if ((s2 = (divisor < 0))) divisor = -divisor;
long_div((Bit128u*)quotient,(Bit64u*)remainder,(Bit128u*)&temp,divisor);
if (s1 ^ s2) {
long_neg(quotient);
}
if (s1) {
*remainder = -*remainder;
}
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MUL_RAXEqR(bxInstruction_c *i)
{
Bit128u product_128;
Bit64u op1_64 = RAX;
Bit64u op2_64 = BX_READ_64BIT_REG(i->rm());
// product_128 = ((Bit128u) op1_64) * ((Bit128u) op2_64);
// product_64l = (Bit64u) (product_128 & 0xFFFFFFFFFFFFFFFF);
// product_64h = (Bit64u) (product_128 >> 64);
long_mul(&product_128,op1_64,op2_64);
/* now write product back to destination */
RAX = product_128.lo;
RDX = product_128.hi;
/* set EFLAGS */
SET_FLAGS_OSZAPC_LOGIC_64(product_128.lo);
if(product_128.hi != 0)
{
ASSERT_FLAGS_OxxxxC();
}
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::IMUL_RAXEqR(bxInstruction_c *i)
{
Bit128s product_128;
Bit64s op1_64 = RAX;
Bit64s op2_64 = BX_READ_64BIT_REG(i->rm());
// product_128 = ((Bit128s) op1_64) * ((Bit128s) op2_64);
// product_64l = (Bit64u) (product_128 & 0xFFFFFFFFFFFFFFFF);
// product_64h = (Bit64u) (product_128 >> 64);
long_imul(&product_128,op1_64,op2_64);
/* now write product back to destination */
RAX = product_128.lo;
RDX = product_128.hi;
/* set eflags:
* IMUL r/m64: condition for clearing CF & OF:
* RDX:RAX = sign-extend of RAX
*/
SET_FLAGS_OSZAPC_LOGIC_64(product_128.lo);
/* magic compare between RDX:RAX and sign extended RAX */
if (((Bit64u)(product_128.hi) + (product_128.lo >> 63)) != 0) {
ASSERT_FLAGS_OxxxxC();
}
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::DIV_RAXEqR(bxInstruction_c *i)
{
Bit64u remainder_64, quotient_64l;
Bit128u op1_128, quotient_128;
Bit64u op2_64 = BX_READ_64BIT_REG(i->rm());
if (op2_64 == 0) {
exception(BX_DE_EXCEPTION, 0);
}
op1_128.lo = RAX;
op1_128.hi = RDX;
// quotient_128 = op1_128 / op2_64;
// remainder_64 = (Bit64u) (op1_128 % op2_64);
// quotient_64l = (Bit64u) (quotient_128 & 0xFFFFFFFFFFFFFFFF);
long_div(&quotient_128,&remainder_64,&op1_128,op2_64);
quotient_64l = quotient_128.lo;
if (quotient_128.hi != 0)
exception(BX_DE_EXCEPTION, 0);
/* set EFLAGS:
* DIV affects the following flags: O,S,Z,A,P,C are undefined
*/
/* now write quotient back to destination */
RAX = quotient_64l;
RDX = remainder_64;
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::IDIV_RAXEqR(bxInstruction_c *i)
{
Bit64s remainder_64, quotient_64l;
Bit128s op1_128, quotient_128;
op1_128.lo = RAX;
op1_128.hi = RDX;
/* check MIN_INT case */
if ((op1_128.hi == (Bit64s) BX_CONST64(0x8000000000000000)) && (!op1_128.lo))
exception(BX_DE_EXCEPTION, 0);
Bit64s op2_64 = BX_READ_64BIT_REG(i->rm());
if (op2_64 == 0) {
exception(BX_DE_EXCEPTION, 0);
}
// quotient_128 = op1_128 / op2_64;
// remainder_64 = (Bit64s) (op1_128 % op2_64);
// quotient_64l = (Bit64s) (quotient_128 & 0xFFFFFFFFFFFFFFFF);
long_idiv(&quotient_128,&remainder_64,&op1_128,op2_64);
quotient_64l = quotient_128.lo;
if ((!(quotient_128.lo & BX_CONST64(0x8000000000000000)) && quotient_128.hi != (Bit64s) 0) ||
(quotient_128.lo & BX_CONST64(0x8000000000000000)) && quotient_128.hi != (Bit64s) BX_CONST64(0xffffffffffffffff))
{
exception(BX_DE_EXCEPTION, 0);
}
/* set EFLAGS:
* IDIV affects the following flags: O,S,Z,A,P,C are undefined
*/
/* now write quotient back to destination */
RAX = quotient_64l;
RDX = remainder_64;
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::IMUL_GqEqIdR(bxInstruction_c *i)
{
Bit128s product_128;
Bit64s op2_64 = BX_READ_64BIT_REG(i->rm());
Bit64s op3_64 = (Bit32s) i->Id();
long_imul(&product_128,op2_64,op3_64);
/* now write product back to destination */
BX_WRITE_64BIT_REG(i->nnn(), product_128.lo);
SET_FLAGS_OSZAPC_LOGIC_64(product_128.lo);
if (((Bit64u)(product_128.hi) + (product_128.lo >> 63)) != 0) {
ASSERT_FLAGS_OxxxxC();
}
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::IMUL_GqEqR(bxInstruction_c *i)
{
Bit128s product_128;
Bit64s op1_64 = BX_READ_64BIT_REG(i->nnn());
Bit64s op2_64 = BX_READ_64BIT_REG(i->rm());
long_imul(&product_128,op1_64,op2_64);
/* now write product back to destination */
BX_WRITE_64BIT_REG(i->nnn(), product_128.lo);
SET_FLAGS_OSZAPC_LOGIC_64(product_128.lo);
if (((Bit64u)(product_128.hi) + (product_128.lo >> 63)) != 0) {
ASSERT_FLAGS_OxxxxC();
}
}
#endif /* if BX_SUPPORT_X86_64 */

View File

@ -0,0 +1,117 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2001-2009 The Bochs Project
//
// 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
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA B 02110-1301 USA
/////////////////////////////////////////////////////////////////////////
#define NEED_CPU_REG_SHORTCUTS 1
#include "bochs.h"
#include "cpu.h"
#define LOG_THIS BX_CPU_THIS_PTR
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MUL_ALEbR(bxInstruction_c *i)
{
Bit8u op1 = AL;
Bit8u op2 = BX_READ_8BIT_REGx(i->rm(), i->extend8bitL());
Bit32u product_16 = ((Bit16u) op1) * ((Bit16u) op2);
Bit8u product_8l = (product_16 & 0xFF);
Bit8u product_8h = product_16 >> 8;
/* now write product back to destination */
AX = product_16;
/* set EFLAGS */
SET_FLAGS_OSZAPC_LOGIC_8(product_8l);
if(product_8h != 0)
{
ASSERT_FLAGS_OxxxxC();
}
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::IMUL_ALEbR(bxInstruction_c *i)
{
Bit8s op1 = AL;
Bit8s op2 = BX_READ_8BIT_REGx(i->rm(), i->extend8bitL());
Bit16s product_16 = op1 * op2;
Bit8u product_8 = (product_16 & 0xFF);
/* now write product back to destination */
AX = product_16;
/* set EFLAGS:
* IMUL r/m8: condition for clearing CF & OF:
* AX = sign-extend of AL to 16 bits
*/
SET_FLAGS_OSZAPC_LOGIC_8(product_8);
if(product_16 != (Bit8s) product_16)
{
ASSERT_FLAGS_OxxxxC();
}
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::DIV_ALEbR(bxInstruction_c *i)
{
Bit8u op2 = BX_READ_8BIT_REGx(i->rm(), i->extend8bitL());
if (op2 == 0) {
exception(BX_DE_EXCEPTION, 0);
}
Bit16u op1 = AX;
Bit16u quotient_16 = op1 / op2;
Bit8u remainder_8 = op1 % op2;
Bit8u quotient_8l = quotient_16 & 0xFF;
if (quotient_16 != quotient_8l)
{
exception(BX_DE_EXCEPTION, 0);
}
/* now write quotient back to destination */
AL = quotient_8l;
AH = remainder_8;
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::IDIV_ALEbR(bxInstruction_c *i)
{
Bit16s op1 = AX;
/* check MIN_INT case */
if (op1 == ((Bit16s)0x8000))
exception(BX_DE_EXCEPTION, 0);
Bit8s op2 = BX_READ_8BIT_REGx(i->rm(), i->extend8bitL());
if (op2 == 0)
exception(BX_DE_EXCEPTION, 0);
Bit16s quotient_16 = op1 / op2;
Bit8s remainder_8 = op1 % op2;
Bit8s quotient_8l = quotient_16 & 0xFF;
if (quotient_16 != quotient_8l)
exception(BX_DE_EXCEPTION, 0);
/* now write quotient back to destination */
AL = quotient_8l;
AH = remainder_8;
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,899 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2001-2010 The Bochs Project
//
// 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
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA B 02110-1301 USA
/////////////////////////////////////////////////////////////////////////
#define NEED_CPU_REG_SHORTCUTS 1
#include "bochs.h"
#include "cpu.h"
#define LOG_THIS BX_CPU_THIS_PTR
void BX_CPP_AttrRegparmN(1) BX_CPU_C::ARPL_EwGw(bxInstruction_c *i)
{
Bit16u op2_16, op1_16;
if (! protected_mode()) {
BX_DEBUG(("ARPL: not recognized in real or virtual-8086 mode"));
exception(BX_UD_EXCEPTION, 0);
}
/* op1_16 is a register or memory reference */
if (i->modC0()) {
op1_16 = BX_READ_16BIT_REG(i->rm());
}
else {
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
/* pointer, segment address pair */
op1_16 = read_RMW_virtual_word(i->seg(), eaddr);
}
op2_16 = BX_READ_16BIT_REG(i->nnn());
if ((op1_16 & 0x03) < (op2_16 & 0x03)) {
op1_16 = (op1_16 & 0xfffc) | (op2_16 & 0x03);
/* now write back to destination */
if (i->modC0()) {
BX_WRITE_16BIT_REG(i->rm(), op1_16);
}
else {
write_RMW_virtual_word(op1_16);
}
assert_ZF();
}
else {
clear_ZF();
}
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::LAR_GvEw(bxInstruction_c *i)
{
/* for 16 bit operand size mode */
Bit16u raw_selector;
bx_descriptor_t descriptor;
bx_selector_t selector;
Bit32u dword1, dword2;
#if BX_SUPPORT_X86_64
Bit32u dword3 = 0;
#endif
if (! protected_mode()) {
BX_ERROR(("LAR: not recognized in real or virtual-8086 mode"));
exception(BX_UD_EXCEPTION, 0);
}
if (i->modC0()) {
raw_selector = BX_READ_16BIT_REG(i->rm());
}
else {
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
/* pointer, segment address pair */
raw_selector = read_virtual_word(i->seg(), eaddr);
}
/* if selector null, clear ZF and done */
if ((raw_selector & 0xfffc) == 0) {
clear_ZF();
return;
}
parse_selector(raw_selector, &selector);
if (!fetch_raw_descriptor2(&selector, &dword1, &dword2)) {
BX_DEBUG(("LAR: failed to fetch descriptor"));
clear_ZF();
return;
}
parse_descriptor(dword1, dword2, &descriptor);
if (descriptor.valid==0) {
BX_DEBUG(("LAR: descriptor not valid"));
clear_ZF();
return;
}
/* if source selector is visible at CPL & RPL,
* within the descriptor table, and of type accepted by LAR instruction,
* then load register with segment limit and set ZF
*/
if (descriptor.segment) { /* normal segment */
if (IS_CODE_SEGMENT(descriptor.type) && IS_CODE_SEGMENT_CONFORMING(descriptor.type)) {
/* ignore DPL for conforming segments */
}
else {
if (descriptor.dpl < CPL || descriptor.dpl < selector.rpl) {
clear_ZF();
return;
}
}
}
else { /* system or gate segment */
switch (descriptor.type) {
case BX_SYS_SEGMENT_AVAIL_286_TSS:
case BX_SYS_SEGMENT_BUSY_286_TSS:
case BX_286_CALL_GATE:
case BX_TASK_GATE:
if (long_mode()) {
BX_DEBUG(("LAR: descriptor type in not accepted in long mode"));
clear_ZF();
return;
}
/* fall through */
case BX_SYS_SEGMENT_LDT:
case BX_SYS_SEGMENT_AVAIL_386_TSS:
case BX_SYS_SEGMENT_BUSY_386_TSS:
case BX_386_CALL_GATE:
#if BX_SUPPORT_X86_64
if (long64_mode() || (descriptor.type == BX_386_CALL_GATE && long_mode()) ) {
if (!fetch_raw_descriptor2_64(&selector, &dword1, &dword2, &dword3)) {
BX_ERROR(("LAR: failed to fetch 64-bit descriptor"));
clear_ZF();
return;
}
}
#endif
break;
default: /* rest not accepted types to LAR */
BX_DEBUG(("LAR: not accepted descriptor type"));
clear_ZF();
return;
}
if (descriptor.dpl < CPL || descriptor.dpl < selector.rpl) {
clear_ZF();
return;
}
}
assert_ZF();
if (i->os32L()) {
/* masked by 00FxFF00, where x is undefined */
BX_WRITE_32BIT_REGZ(i->nnn(), dword2 & 0x00ffff00);
}
else {
BX_WRITE_16BIT_REG(i->nnn(), dword2 & 0xff00);
}
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::LSL_GvEw(bxInstruction_c *i)
{
/* for 16 bit operand size mode */
Bit16u raw_selector;
Bit32u limit32;
bx_selector_t selector;
Bit32u dword1, dword2;
#if BX_SUPPORT_X86_64
Bit32u dword3 = 0;
#endif
if (! protected_mode()) {
BX_ERROR(("LSL: not recognized in real or virtual-8086 mode"));
exception(BX_UD_EXCEPTION, 0);
}
if (i->modC0()) {
raw_selector = BX_READ_16BIT_REG(i->rm());
}
else {
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
/* pointer, segment address pair */
raw_selector = read_virtual_word(i->seg(), eaddr);
}
/* if selector null, clear ZF and done */
if ((raw_selector & 0xfffc) == 0) {
clear_ZF();
return;
}
parse_selector(raw_selector, &selector);
if (!fetch_raw_descriptor2(&selector, &dword1, &dword2)) {
BX_DEBUG(("LSL: failed to fetch descriptor"));
clear_ZF();
return;
}
Bit32u descriptor_dpl = (dword2 >> 13) & 0x03;
if ((dword2 & 0x00001000) == 0) { // system segment
Bit32u type = (dword2 >> 8) & 0x0000000f;
switch (type) {
case BX_SYS_SEGMENT_AVAIL_286_TSS:
case BX_SYS_SEGMENT_BUSY_286_TSS:
if (long_mode()) {
clear_ZF();
return;
}
/* fall through */
case BX_SYS_SEGMENT_LDT:
case BX_SYS_SEGMENT_AVAIL_386_TSS:
case BX_SYS_SEGMENT_BUSY_386_TSS:
#if BX_SUPPORT_X86_64
if (long64_mode()) {
if (!fetch_raw_descriptor2_64(&selector, &dword1, &dword2, &dword3)) {
BX_ERROR(("LSL: failed to fetch 64-bit descriptor"));
clear_ZF();
return;
}
}
#endif
if (descriptor_dpl < CPL || descriptor_dpl < selector.rpl) {
clear_ZF();
return;
}
limit32 = (dword1 & 0x0000ffff) | (dword2 & 0x000f0000);
if (dword2 & 0x00800000)
limit32 = (limit32 << 12) | 0x00000fff;
break;
default: /* rest not accepted types to LSL */
clear_ZF();
return;
}
}
else { // data & code segment
limit32 = (dword1 & 0x0000ffff) | (dword2 & 0x000f0000);
if (dword2 & 0x00800000)
limit32 = (limit32 << 12) | 0x00000fff;
if ((dword2 & 0x00000c00) != 0x00000c00) {
// non-conforming code segment
if (descriptor_dpl < CPL || descriptor_dpl < selector.rpl) {
clear_ZF();
return;
}
}
}
/* all checks pass, limit32 is now byte granular, write to op1 */
assert_ZF();
if (i->os32L()) {
BX_WRITE_32BIT_REGZ(i->nnn(), limit32);
}
else {
// chop off upper 16 bits
BX_WRITE_16BIT_REG(i->nnn(), (Bit16u) limit32);
}
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SLDT_Ew(bxInstruction_c *i)
{
if (! protected_mode()) {
BX_ERROR(("SLDT: not recognized in real or virtual-8086 mode"));
exception(BX_UD_EXCEPTION, 0);
}
#if BX_SUPPORT_VMX >= 2
if (BX_CPU_THIS_PTR in_vmx_guest)
if (SECONDARY_VMEXEC_CONTROL(VMX_VM_EXEC_CTRL3_DESCRIPTOR_TABLE_VMEXIT))
VMexit_Instruction(i, VMX_VMEXIT_LDTR_TR_ACCESS);
#endif
Bit16u val16 = BX_CPU_THIS_PTR ldtr.selector.value;
if (i->modC0()) {
if (i->os32L()) {
BX_WRITE_32BIT_REGZ(i->rm(), val16);
}
else {
BX_WRITE_16BIT_REG(i->rm(), val16);
}
}
else {
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
/* pointer, segment address pair */
write_virtual_word(i->seg(), eaddr, val16);
}
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::STR_Ew(bxInstruction_c *i)
{
if (! protected_mode()) {
BX_ERROR(("STR: not recognized in real or virtual-8086 mode"));
exception(BX_UD_EXCEPTION, 0);
}
#if BX_SUPPORT_VMX >= 2
if (BX_CPU_THIS_PTR in_vmx_guest)
if (SECONDARY_VMEXEC_CONTROL(VMX_VM_EXEC_CTRL3_DESCRIPTOR_TABLE_VMEXIT))
VMexit_Instruction(i, VMX_VMEXIT_LDTR_TR_ACCESS);
#endif
Bit16u val16 = BX_CPU_THIS_PTR tr.selector.value;
if (i->modC0()) {
if (i->os32L()) {
BX_WRITE_32BIT_REGZ(i->rm(), val16);
}
else {
BX_WRITE_16BIT_REG(i->rm(), val16);
}
}
else {
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
/* pointer, segment address pair */
write_virtual_word(i->seg(), eaddr, val16);
}
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::LLDT_Ew(bxInstruction_c *i)
{
/* protected mode */
bx_descriptor_t descriptor;
bx_selector_t selector;
Bit16u raw_selector;
Bit32u dword1, dword2;
#if BX_SUPPORT_X86_64
Bit32u dword3 = 0;
#endif
if (! protected_mode()) {
BX_ERROR(("LLDT: not recognized in real or virtual-8086 mode"));
exception(BX_UD_EXCEPTION, 0);
}
if (CPL != 0) {
BX_ERROR(("LLDT: The current priveledge level is not 0"));
exception(BX_GP_EXCEPTION, 0);
}
#if BX_SUPPORT_VMX >= 2
if (BX_CPU_THIS_PTR in_vmx_guest)
if (SECONDARY_VMEXEC_CONTROL(VMX_VM_EXEC_CTRL3_DESCRIPTOR_TABLE_VMEXIT))
VMexit_Instruction(i, VMX_VMEXIT_LDTR_TR_ACCESS);
#endif
if (i->modC0()) {
raw_selector = BX_READ_16BIT_REG(i->rm());
}
else {
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
/* pointer, segment address pair */
raw_selector = read_virtual_word(i->seg(), eaddr);
}
/* if selector is NULL, invalidate and done */
if ((raw_selector & 0xfffc) == 0) {
BX_CPU_THIS_PTR ldtr.selector.value = raw_selector;
BX_CPU_THIS_PTR ldtr.cache.valid = 0;
return;
}
/* parse fields in selector */
parse_selector(raw_selector, &selector);
// #GP(selector) if the selector operand does not point into GDT
if (selector.ti != 0) {
BX_ERROR(("LLDT: selector.ti != 0"));
exception(BX_GP_EXCEPTION, raw_selector & 0xfffc);
}
/* fetch descriptor; call handles out of limits checks */
#if BX_SUPPORT_X86_64
if (BX_CPU_THIS_PTR cpu_mode == BX_MODE_LONG_64) {
fetch_raw_descriptor_64(&selector, &dword1, &dword2, &dword3, BX_GP_EXCEPTION);
}
else
#endif
{
fetch_raw_descriptor(&selector, &dword1, &dword2, BX_GP_EXCEPTION);
}
parse_descriptor(dword1, dword2, &descriptor);
/* if selector doesn't point to an LDT descriptor #GP(selector) */
if (descriptor.valid == 0 || descriptor.segment ||
descriptor.type != BX_SYS_SEGMENT_LDT)
{
BX_ERROR(("LLDT: doesn't point to an LDT descriptor!"));
exception(BX_GP_EXCEPTION, raw_selector & 0xfffc);
}
/* #NP(selector) if LDT descriptor is not present */
if (! IS_PRESENT(descriptor)) {
BX_ERROR(("LLDT: LDT descriptor not present!"));
exception(BX_NP_EXCEPTION, raw_selector & 0xfffc);
}
#if BX_SUPPORT_X86_64
if (BX_CPU_THIS_PTR cpu_mode == BX_MODE_LONG_64) {
descriptor.u.segment.base |= ((Bit64u)(dword3) << 32);
BX_DEBUG(("64 bit LDT base = 0x%08x%08x",
GET32H(descriptor.u.segment.base), GET32L(descriptor.u.segment.base)));
if (!IsCanonical(descriptor.u.segment.base)) {
BX_ERROR(("LLDT: non-canonical LDT descriptor base!"));
exception(BX_GP_EXCEPTION, raw_selector & 0xfffc);
}
}
#endif
BX_CPU_THIS_PTR ldtr.selector = selector;
BX_CPU_THIS_PTR ldtr.cache = descriptor;
BX_CPU_THIS_PTR ldtr.cache.valid = 1;
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::LTR_Ew(bxInstruction_c *i)
{
bx_descriptor_t descriptor;
bx_selector_t selector;
Bit16u raw_selector;
Bit32u dword1, dword2;
#if BX_SUPPORT_X86_64
Bit32u dword3 = 0;
#endif
if (! protected_mode()) {
BX_ERROR(("LTR: not recognized in real or virtual-8086 mode"));
exception(BX_UD_EXCEPTION, 0);
}
if (CPL != 0) {
BX_ERROR(("LTR: The current priveledge level is not 0"));
exception(BX_GP_EXCEPTION, 0);
}
#if BX_SUPPORT_VMX >= 2
if (BX_CPU_THIS_PTR in_vmx_guest)
if (SECONDARY_VMEXEC_CONTROL(VMX_VM_EXEC_CTRL3_DESCRIPTOR_TABLE_VMEXIT))
VMexit_Instruction(i, VMX_VMEXIT_LDTR_TR_ACCESS);
#endif
if (i->modC0()) {
raw_selector = BX_READ_16BIT_REG(i->rm());
}
else {
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
/* pointer, segment address pair */
raw_selector = read_virtual_word(i->seg(), eaddr);
}
/* if selector is NULL, invalidate and done */
if ((raw_selector & BX_SELECTOR_RPL_MASK) == 0) {
BX_ERROR(("LTR: loading with NULL selector!"));
exception(BX_GP_EXCEPTION, 0);
}
/* parse fields in selector, then check for null selector */
parse_selector(raw_selector, &selector);
if (selector.ti) {
BX_ERROR(("LTR: selector.ti != 0"));
exception(BX_GP_EXCEPTION, raw_selector & 0xfffc);
}
/* fetch descriptor; call handles out of limits checks */
#if BX_SUPPORT_X86_64
if (BX_CPU_THIS_PTR cpu_mode == BX_MODE_LONG_64) {
fetch_raw_descriptor_64(&selector, &dword1, &dword2, &dword3, BX_GP_EXCEPTION);
}
else
#endif
{
fetch_raw_descriptor(&selector, &dword1, &dword2, BX_GP_EXCEPTION);
}
parse_descriptor(dword1, dword2, &descriptor);
/* #GP(selector) if object is not a TSS or is already busy */
if (descriptor.valid==0 || descriptor.segment ||
(descriptor.type!=BX_SYS_SEGMENT_AVAIL_286_TSS &&
descriptor.type!=BX_SYS_SEGMENT_AVAIL_386_TSS))
{
BX_ERROR(("LTR: doesn't point to an available TSS descriptor!"));
exception(BX_GP_EXCEPTION, raw_selector & 0xfffc);
}
#if BX_SUPPORT_X86_64
if (long_mode() && descriptor.type!=BX_SYS_SEGMENT_AVAIL_386_TSS) {
BX_ERROR(("LTR: doesn't point to an available TSS386 descriptor in long mode!"));
exception(BX_GP_EXCEPTION, raw_selector & 0xfffc);
}
#endif
/* #NP(selector) if TSS descriptor is not present */
if (! IS_PRESENT(descriptor)) {
BX_ERROR(("LTR: TSS descriptor not present!"));
exception(BX_NP_EXCEPTION, raw_selector & 0xfffc);
}
#if BX_SUPPORT_X86_64
if (BX_CPU_THIS_PTR cpu_mode == BX_MODE_LONG_64) {
descriptor.u.segment.base |= ((Bit64u)(dword3) << 32);
BX_DEBUG(("64 bit TSS base = 0x%08x%08x",
GET32H(descriptor.u.segment.base), GET32L(descriptor.u.segment.base)));
if (!IsCanonical(descriptor.u.segment.base)) {
BX_ERROR(("LTR: non-canonical TSS descriptor base!"));
exception(BX_GP_EXCEPTION, raw_selector & 0xfffc);
}
}
#endif
BX_CPU_THIS_PTR tr.selector = selector;
BX_CPU_THIS_PTR tr.cache = descriptor;
BX_CPU_THIS_PTR tr.cache.valid = 1;
// tr.cache.type should not have busy bit, or it would not get
// through the conditions above.
BX_ASSERT((BX_CPU_THIS_PTR tr.cache.type & 2) == 0);
BX_CPU_THIS_PTR tr.cache.type |= 2; // mark as busy
/* mark as busy */
if (!(dword2 & 0x0200)) {
dword2 |= 0x0200; /* set busy bit */
access_write_linear(BX_CPU_THIS_PTR gdtr.base + selector.index*8 + 4, 4, 0, &dword2);
}
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::VERR_Ew(bxInstruction_c *i)
{
/* for 16 bit operand size mode */
Bit16u raw_selector;
bx_descriptor_t descriptor;
bx_selector_t selector;
Bit32u dword1, dword2;
if (! protected_mode()) {
BX_ERROR(("VERR: not recognized in real or virtual-8086 mode"));
exception(BX_UD_EXCEPTION, 0);
}
if (i->modC0()) {
raw_selector = BX_READ_16BIT_REG(i->rm());
}
else {
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
/* pointer, segment address pair */
raw_selector = read_virtual_word(i->seg(), eaddr);
}
/* if selector null, clear ZF and done */
if ((raw_selector & 0xfffc) == 0) {
BX_DEBUG(("VERR: null selector"));
clear_ZF();
return;
}
/* if source selector is visible at CPL & RPL,
* within the descriptor table, and of type accepted by VERR instruction,
* then load register with segment limit and set ZF */
parse_selector(raw_selector, &selector);
if (!fetch_raw_descriptor2(&selector, &dword1, &dword2)) {
/* not within descriptor table */
BX_DEBUG(("VERR: not within descriptor table"));
clear_ZF();
return;
}
parse_descriptor(dword1, dword2, &descriptor);
if (descriptor.segment==0) { /* system or gate descriptor */
BX_DEBUG(("VERR: system descriptor"));
clear_ZF(); /* inaccessible */
return;
}
if (descriptor.valid==0) {
BX_DEBUG(("VERR: valid bit cleared"));
clear_ZF(); /* inaccessible */
return;
}
/* normal data/code segment */
if (IS_CODE_SEGMENT(descriptor.type)) { /* code segment */
/* ignore DPL for readable conforming segments */
if (IS_CODE_SEGMENT_CONFORMING(descriptor.type) &&
IS_CODE_SEGMENT_READABLE(descriptor.type))
{
BX_DEBUG(("VERR: conforming code, OK"));
assert_ZF(); /* accessible */
return;
}
if (!IS_CODE_SEGMENT_READABLE(descriptor.type)) {
BX_DEBUG(("VERR: code not readable"));
clear_ZF(); /* inaccessible */
return;
}
/* readable, non-conforming code segment */
if ((descriptor.dpl<CPL) || (descriptor.dpl<selector.rpl)) {
BX_DEBUG(("VERR: non-conforming code not withing priv level"));
clear_ZF(); /* inaccessible */
}
else {
assert_ZF(); /* accessible */
}
}
else { /* data segment */
if ((descriptor.dpl<CPL) || (descriptor.dpl<selector.rpl)) {
BX_DEBUG(("VERR: data seg not withing priv level"));
clear_ZF(); /* not accessible */
}
else {
assert_ZF(); /* accessible */
}
}
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::VERW_Ew(bxInstruction_c *i)
{
/* for 16 bit operand size mode */
Bit16u raw_selector;
bx_descriptor_t descriptor;
bx_selector_t selector;
Bit32u dword1, dword2;
if (! protected_mode()) {
BX_ERROR(("VERW: not recognized in real or virtual-8086 mode"));
exception(BX_UD_EXCEPTION, 0);
}
if (i->modC0()) {
raw_selector = BX_READ_16BIT_REG(i->rm());
}
else {
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
/* pointer, segment address pair */
raw_selector = read_virtual_word(i->seg(), eaddr);
}
/* if selector null, clear ZF and done */
if ((raw_selector & 0xfffc) == 0) {
BX_DEBUG(("VERW: null selector"));
clear_ZF();
return;
}
/* if source selector is visible at CPL & RPL,
* within the descriptor table, and of type accepted by VERW instruction,
* then load register with segment limit and set ZF */
parse_selector(raw_selector, &selector);
if (!fetch_raw_descriptor2(&selector, &dword1, &dword2)) {
/* not within descriptor table */
BX_DEBUG(("VERW: not within descriptor table"));
clear_ZF();
return;
}
parse_descriptor(dword1, dword2, &descriptor);
/* rule out system segments & code segments */
if (descriptor.segment==0 || IS_CODE_SEGMENT(descriptor.type)) {
BX_DEBUG(("VERW: system seg or code"));
clear_ZF();
return;
}
if (descriptor.valid==0) {
BX_DEBUG(("VERW: valid bit cleared"));
clear_ZF();
return;
}
/* data segment */
if (IS_DATA_SEGMENT_WRITEABLE(descriptor.type)) { /* writable */
if ((descriptor.dpl<CPL) || (descriptor.dpl<selector.rpl)) {
BX_DEBUG(("VERW: writable data seg not within priv level"));
clear_ZF(); /* not accessible */
}
else {
assert_ZF(); /* accessible */
}
}
else {
BX_DEBUG(("VERW: data seg not writable"));
clear_ZF(); /* not accessible */
}
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SGDT_Ms(bxInstruction_c *i)
{
BX_ASSERT(BX_CPU_THIS_PTR cpu_mode != BX_MODE_LONG_64);
#if BX_SUPPORT_VMX >= 2
if (BX_CPU_THIS_PTR in_vmx_guest)
if (SECONDARY_VMEXEC_CONTROL(VMX_VM_EXEC_CTRL3_DESCRIPTOR_TABLE_VMEXIT))
VMexit_Instruction(i, VMX_VMEXIT_GDTR_IDTR_ACCESS);
#endif
Bit16u limit_16 = BX_CPU_THIS_PTR gdtr.limit;
Bit32u base_32 = (Bit32u) BX_CPU_THIS_PTR gdtr.base;
Bit32u eaddr = (Bit32u) BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
write_virtual_word_32(i->seg(), eaddr, limit_16);
write_virtual_dword_32(i->seg(), (eaddr+2) & i->asize_mask(), base_32);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SIDT_Ms(bxInstruction_c *i)
{
BX_ASSERT(BX_CPU_THIS_PTR cpu_mode != BX_MODE_LONG_64);
#if BX_SUPPORT_VMX >= 2
if (BX_CPU_THIS_PTR in_vmx_guest)
if (SECONDARY_VMEXEC_CONTROL(VMX_VM_EXEC_CTRL3_DESCRIPTOR_TABLE_VMEXIT))
VMexit_Instruction(i, VMX_VMEXIT_GDTR_IDTR_ACCESS);
#endif
Bit16u limit_16 = BX_CPU_THIS_PTR idtr.limit;
Bit32u base_32 = (Bit32u) BX_CPU_THIS_PTR idtr.base;
Bit32u eaddr = (Bit32u) BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
write_virtual_word_32(i->seg(), eaddr, limit_16);
write_virtual_dword_32(i->seg(), (eaddr+2) & i->asize_mask(), base_32);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::LGDT_Ms(bxInstruction_c *i)
{
BX_ASSERT(BX_CPU_THIS_PTR cpu_mode != BX_MODE_LONG_64);
if (v8086_mode()) {
BX_ERROR(("LGDT: not recognized in virtual-8086 mode"));
exception(BX_GP_EXCEPTION, 0);
}
if (!real_mode() && CPL!=0) {
BX_ERROR(("LGDT: CPL!=0 in protected mode"));
exception(BX_GP_EXCEPTION, 0);
}
#if BX_SUPPORT_VMX >= 2
if (BX_CPU_THIS_PTR in_vmx_guest)
if (SECONDARY_VMEXEC_CONTROL(VMX_VM_EXEC_CTRL3_DESCRIPTOR_TABLE_VMEXIT))
VMexit_Instruction(i, VMX_VMEXIT_GDTR_IDTR_ACCESS);
#endif
Bit32u eaddr = (Bit32u) BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
Bit16u limit_16 = read_virtual_word_32(i->seg(), eaddr);
Bit32u base_32 = read_virtual_dword_32(i->seg(), (eaddr + 2) & i->asize_mask());
if (i->os32L() == 0) base_32 &= 0x00ffffff; /* ignore upper 8 bits */
BX_CPU_THIS_PTR gdtr.limit = limit_16;
BX_CPU_THIS_PTR gdtr.base = base_32;
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::LIDT_Ms(bxInstruction_c *i)
{
BX_ASSERT(BX_CPU_THIS_PTR cpu_mode != BX_MODE_LONG_64);
if (v8086_mode()) {
BX_ERROR(("LIDT: not recognized in virtual-8086 mode"));
exception(BX_GP_EXCEPTION, 0);
}
if (!real_mode() && CPL!=0) {
BX_ERROR(("LIDT: CPL!=0 in protected mode"));
exception(BX_GP_EXCEPTION, 0);
}
#if BX_SUPPORT_VMX >= 2
if (BX_CPU_THIS_PTR in_vmx_guest)
if (SECONDARY_VMEXEC_CONTROL(VMX_VM_EXEC_CTRL3_DESCRIPTOR_TABLE_VMEXIT))
VMexit_Instruction(i, VMX_VMEXIT_GDTR_IDTR_ACCESS);
#endif
Bit32u eaddr = (Bit32u) BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
Bit16u limit_16 = read_virtual_word_32(i->seg(), eaddr);
Bit32u base_32 = read_virtual_dword_32(i->seg(), (eaddr + 2) & i->asize_mask());
if (i->os32L() == 0) base_32 &= 0x00ffffff; /* ignore upper 8 bits */
BX_CPU_THIS_PTR idtr.limit = limit_16;
BX_CPU_THIS_PTR idtr.base = base_32;
}
#if BX_SUPPORT_X86_64
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SGDT64_Ms(bxInstruction_c *i)
{
BX_ASSERT(BX_CPU_THIS_PTR cpu_mode == BX_MODE_LONG_64);
#if BX_SUPPORT_VMX >= 2
if (BX_CPU_THIS_PTR in_vmx_guest)
if (SECONDARY_VMEXEC_CONTROL(VMX_VM_EXEC_CTRL3_DESCRIPTOR_TABLE_VMEXIT))
VMexit_Instruction(i, VMX_VMEXIT_GDTR_IDTR_ACCESS);
#endif
Bit16u limit_16 = BX_CPU_THIS_PTR gdtr.limit;
Bit64u base_64 = BX_CPU_THIS_PTR gdtr.base;
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
write_virtual_word_64(i->seg(), eaddr, limit_16);
write_virtual_qword_64(i->seg(), (eaddr+2) & i->asize_mask(), base_64);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SIDT64_Ms(bxInstruction_c *i)
{
BX_ASSERT(BX_CPU_THIS_PTR cpu_mode == BX_MODE_LONG_64);
#if BX_SUPPORT_VMX >= 2
if (BX_CPU_THIS_PTR in_vmx_guest)
if (SECONDARY_VMEXEC_CONTROL(VMX_VM_EXEC_CTRL3_DESCRIPTOR_TABLE_VMEXIT))
VMexit_Instruction(i, VMX_VMEXIT_GDTR_IDTR_ACCESS);
#endif
Bit16u limit_16 = BX_CPU_THIS_PTR idtr.limit;
Bit64u base_64 = BX_CPU_THIS_PTR idtr.base;
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
write_virtual_word_64(i->seg(), eaddr, limit_16);
write_virtual_qword_64(i->seg(), (eaddr+2) & i->asize_mask(), base_64);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::LGDT64_Ms(bxInstruction_c *i)
{
BX_ASSERT(BX_CPU_THIS_PTR cpu_mode == BX_MODE_LONG_64);
if (CPL!=0) {
BX_ERROR(("LGDT64_Ms: CPL != 0 in long mode"));
exception(BX_GP_EXCEPTION, 0);
}
#if BX_SUPPORT_VMX >= 2
if (BX_CPU_THIS_PTR in_vmx_guest)
if (SECONDARY_VMEXEC_CONTROL(VMX_VM_EXEC_CTRL3_DESCRIPTOR_TABLE_VMEXIT))
VMexit_Instruction(i, VMX_VMEXIT_GDTR_IDTR_ACCESS);
#endif
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
Bit64u base_64 = read_virtual_qword_64(i->seg(), (eaddr + 2) & i->asize_mask());
if (! IsCanonical(base_64)) {
BX_ERROR(("LGDT64_Ms: loaded base64 address is not in canonical form!"));
exception(BX_GP_EXCEPTION, 0);
}
Bit16u limit_16 = read_virtual_word_64(i->seg(), eaddr);
BX_CPU_THIS_PTR gdtr.limit = limit_16;
BX_CPU_THIS_PTR gdtr.base = base_64;
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::LIDT64_Ms(bxInstruction_c *i)
{
BX_ASSERT(BX_CPU_THIS_PTR cpu_mode == BX_MODE_LONG_64);
if (CPL != 0) {
BX_ERROR(("LIDT64_Ms: CPL != 0 in long mode"));
exception(BX_GP_EXCEPTION, 0);
}
#if BX_SUPPORT_VMX >= 2
if (BX_CPU_THIS_PTR in_vmx_guest)
if (SECONDARY_VMEXEC_CONTROL(VMX_VM_EXEC_CTRL3_DESCRIPTOR_TABLE_VMEXIT))
VMexit_Instruction(i, VMX_VMEXIT_GDTR_IDTR_ACCESS);
#endif
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
Bit64u base_64 = read_virtual_qword_64(i->seg(), (eaddr + 2) & i->asize_mask());
if (! IsCanonical(base_64)) {
BX_ERROR(("LIDT64_Ms: loaded base64 address is not in canonical form!"));
exception(BX_GP_EXCEPTION, 0);
}
Bit16u limit_16 = read_virtual_word_64(i->seg(), eaddr);
BX_CPU_THIS_PTR idtr.limit = limit_16;
BX_CPU_THIS_PTR idtr.base = base_64;
}
#endif

View File

@ -0,0 +1,69 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2008-2009 Stanislav Shwartsman
// 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
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA B 02110-1301 USA
//
/////////////////////////////////////////////////////////////////////////
#define NEED_CPU_REG_SHORTCUTS 1
#include "bochs.h"
#include "cpu.h"
#define LOG_THIS BX_CPU_THIS_PTR
//
// 16 bit address size
//
bx_address BX_CPP_AttrRegparmN(1)
BX_CPU_C::BxResolve16BaseIndex(bxInstruction_c *i)
{
return (Bit16u) (BX_READ_16BIT_REG(i->sibBase()) + BX_READ_16BIT_REG(i->sibIndex()) + i->displ16s());
}
//
// 32 bit address size
//
bx_address BX_CPP_AttrRegparmN(1)
BX_CPU_C::BxResolve32Base(bxInstruction_c *i)
{
return (Bit32u) (BX_READ_32BIT_REG(i->sibBase()) + i->displ32s());
}
bx_address BX_CPP_AttrRegparmN(1)
BX_CPU_C::BxResolve32BaseIndex(bxInstruction_c *i)
{
return (Bit32u) (BX_READ_32BIT_REG(i->sibBase()) + (BX_READ_32BIT_REG(i->sibIndex()) << i->sibScale()) + i->displ32s());
}
//
// 64 bit address size
//
#if BX_SUPPORT_X86_64
bx_address BX_CPP_AttrRegparmN(1)
BX_CPU_C::BxResolve64Base(bxInstruction_c *i)
{
return BX_READ_64BIT_REG(i->sibBase()) + i->displ32s();
}
bx_address BX_CPP_AttrRegparmN(1)
BX_CPU_C::BxResolve64BaseIndex(bxInstruction_c *i)
{
return BX_READ_64BIT_REG(i->sibBase()) + (BX_READ_64BIT_REG(i->sibIndex()) << i->sibScale()) + i->displ32s();
}
#endif

236
simulators/bochs/cpu/ret_far.cc Executable file
View File

@ -0,0 +1,236 @@
////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2005-2009 Stanislav Shwartsman
// 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
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA B 02110-1301 USA
//
////////////////////////////////////////////////////////////////////////
#define NEED_CPU_REG_SHORTCUTS 1
#include "bochs.h"
#include "cpu.h"
#define LOG_THIS BX_CPU_THIS_PTR
#if BX_SUPPORT_X86_64==0
// Make life easier merging cpu64 & cpu code.
#define RIP EIP
#define RSP ESP
#endif
void BX_CPP_AttrRegparmN(2)
BX_CPU_C::return_protected(bxInstruction_c *i, Bit16u pop_bytes)
{
Bit16u raw_cs_selector, raw_ss_selector;
bx_selector_t cs_selector, ss_selector;
bx_descriptor_t cs_descriptor, ss_descriptor;
Bit32u stack_param_offset;
bx_address return_RIP, return_RSP, temp_RSP;
Bit32u dword1, dword2;
/* + 6+N*2: SS | +12+N*4: SS | +24+N*8 SS */
/* + 4+N*2: SP | + 8+N*4: ESP | +16+N*8 RSP */
/* parm N | + parm N | + parm N */
/* parm 3 | + parm 3 | + parm 3 */
/* parm 2 | + parm 2 | + parm 2 */
/* + 4: parm 1 | + 8: parm 1 | +16: parm 1 */
/* + 2: CS | + 4: CS | + 8: CS */
/* + 0: IP | + 0: EIP | + 0: RIP */
#if BX_SUPPORT_X86_64
if (StackAddrSize64()) temp_RSP = RSP;
else
#endif
{
if (BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.d_b) temp_RSP = ESP;
else temp_RSP = SP;
}
#if BX_SUPPORT_X86_64
if (i->os64L()) {
raw_cs_selector = (Bit16u) read_virtual_qword_64(BX_SEG_REG_SS, temp_RSP + 8);
return_RIP = read_virtual_qword_64(BX_SEG_REG_SS, temp_RSP);
stack_param_offset = 16;
}
else
#endif
if (i->os32L()) {
raw_cs_selector = (Bit16u) read_virtual_dword(BX_SEG_REG_SS, temp_RSP + 4);
return_RIP = read_virtual_dword(BX_SEG_REG_SS, temp_RSP);
stack_param_offset = 8;
}
else {
raw_cs_selector = read_virtual_word(BX_SEG_REG_SS, temp_RSP + 2);
return_RIP = read_virtual_word(BX_SEG_REG_SS, temp_RSP);
stack_param_offset = 4;
}
// selector must be non-null else #GP(0)
if ((raw_cs_selector & 0xfffc) == 0) {
BX_ERROR(("return_protected: CS selector null"));
exception(BX_GP_EXCEPTION, 0);
}
parse_selector(raw_cs_selector, &cs_selector);
// selector index must be within its descriptor table limits,
// else #GP(selector)
fetch_raw_descriptor(&cs_selector, &dword1, &dword2, BX_GP_EXCEPTION);
// descriptor AR byte must indicate code segment, else #GP(selector)
parse_descriptor(dword1, dword2, &cs_descriptor);
// return selector RPL must be >= CPL, else #GP(return selector)
if (cs_selector.rpl < CPL) {
BX_ERROR(("return_protected: CS.rpl < CPL"));
exception(BX_GP_EXCEPTION, raw_cs_selector & 0xfffc);
}
// check code-segment descriptor
check_cs(&cs_descriptor, raw_cs_selector, 0, cs_selector.rpl);
// if return selector RPL == CPL then
// RETURN TO SAME PRIVILEGE LEVEL
if (cs_selector.rpl == CPL)
{
BX_DEBUG(("return_protected: return to SAME PRIVILEGE LEVEL"));
branch_far64(&cs_selector, &cs_descriptor, return_RIP, CPL);
#if BX_SUPPORT_X86_64
if (StackAddrSize64())
RSP += stack_param_offset + pop_bytes;
else
#endif
{
if (BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.d_b)
RSP = ESP + stack_param_offset + pop_bytes;
else
SP += stack_param_offset + pop_bytes;
}
}
/* RETURN TO OUTER PRIVILEGE LEVEL */
else {
/* + 6+N*2: SS | +12+N*4: SS | +24+N*8 SS */
/* + 4+N*2: SP | + 8+N*4: ESP | +16+N*8 RSP */
/* parm N | + parm N | + parm N */
/* parm 3 | + parm 3 | + parm 3 */
/* parm 2 | + parm 2 | + parm 2 */
/* + 4: parm 1 | + 8: parm 1 | +16: parm 1 */
/* + 2: CS | + 4: CS | + 8: CS */
/* + 0: IP | + 0: EIP | + 0: RIP */
BX_DEBUG(("return_protected: return to OUTER PRIVILEGE LEVEL"));
#if BX_SUPPORT_X86_64
if (i->os64L()) {
raw_ss_selector = read_virtual_word_64(BX_SEG_REG_SS, temp_RSP + 24 + pop_bytes);
return_RSP = read_virtual_qword_64(BX_SEG_REG_SS, temp_RSP + 16 + pop_bytes);
}
else
#endif
if (i->os32L()) {
raw_ss_selector = read_virtual_word(BX_SEG_REG_SS, temp_RSP + 12 + pop_bytes);
return_RSP = read_virtual_dword(BX_SEG_REG_SS, temp_RSP + 8 + pop_bytes);
}
else {
raw_ss_selector = read_virtual_word(BX_SEG_REG_SS, temp_RSP + 6 + pop_bytes);
return_RSP = read_virtual_word(BX_SEG_REG_SS, temp_RSP + 4 + pop_bytes);
}
/* selector index must be within its descriptor table limits,
* else #GP(selector) */
parse_selector(raw_ss_selector, &ss_selector);
if ((raw_ss_selector & 0xfffc) == 0) {
#if BX_SUPPORT_X86_64
if (long_mode()) {
if (! IS_LONG64_SEGMENT(cs_descriptor) || (cs_selector.rpl == 3)) {
BX_ERROR(("return_protected: SS selector null"));
exception(BX_GP_EXCEPTION, 0);
}
}
else // not in long or compatibility mode
#endif
{
BX_ERROR(("return_protected: SS selector null"));
exception(BX_GP_EXCEPTION, 0);
}
}
else {
fetch_raw_descriptor(&ss_selector, &dword1, &dword2, BX_GP_EXCEPTION);
parse_descriptor(dword1, dword2, &ss_descriptor);
/* selector RPL must = RPL of the return CS selector,
* else #GP(selector) */
if (ss_selector.rpl != cs_selector.rpl) {
BX_ERROR(("return_protected: ss.rpl != cs.rpl"));
exception(BX_GP_EXCEPTION, raw_ss_selector & 0xfffc);
}
/* descriptor AR byte must indicate a writable data segment,
* else #GP(selector) */
if (ss_descriptor.valid==0 || ss_descriptor.segment==0 ||
IS_CODE_SEGMENT(ss_descriptor.type) ||
!IS_DATA_SEGMENT_WRITEABLE(ss_descriptor.type))
{
BX_ERROR(("return_protected: SS.AR byte not writable data"));
exception(BX_GP_EXCEPTION, raw_ss_selector & 0xfffc);
}
/* descriptor dpl must = RPL of the return CS selector,
* else #GP(selector) */
if (ss_descriptor.dpl != cs_selector.rpl) {
BX_ERROR(("return_protected: SS.dpl != cs.rpl"));
exception(BX_GP_EXCEPTION, raw_ss_selector & 0xfffc);
}
/* segment must be present else #SS(selector) */
if (! IS_PRESENT(ss_descriptor)) {
BX_ERROR(("return_protected: ss.present == 0"));
exception(BX_SS_EXCEPTION, raw_ss_selector & 0xfffc);
}
}
branch_far64(&cs_selector, &cs_descriptor, return_RIP, cs_selector.rpl);
if ((raw_ss_selector & 0xfffc) != 0) {
// load SS:RSP from stack
// load the SS-cache with SS descriptor
load_ss(&ss_selector, &ss_descriptor, cs_selector.rpl);
}
#if BX_SUPPORT_X86_64
else {
// we are in 64-bit mode (checked above)
load_null_selector(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS], raw_ss_selector);
}
if (StackAddrSize64())
RSP = return_RSP + pop_bytes;
else
#endif
{
if (ss_descriptor.u.segment.d_b)
RSP = (Bit32u)(return_RSP + pop_bytes);
else
SP = (Bit16u)(return_RSP + pop_bytes);
}
/* check ES, DS, FS, GS for validity */
validate_seg_regs();
}
}

View File

@ -0,0 +1,200 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2001-2009 The Bochs Project
//
// 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
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA B 02110-1301 USA
//
/////////////////////////////////////////////////////////////////////////
#define NEED_CPU_REG_SHORTCUTS 1
#include "bochs.h"
#include "cpu.h"
#define LOG_THIS BX_CPU_THIS_PTR
// LES/LDS can't be called from long64 mode
void BX_CPP_AttrRegparmN(1) BX_CPU_C::LES_GwMp(bxInstruction_c *i)
{
BX_ASSERT(BX_CPU_THIS_PTR cpu_mode != BX_MODE_LONG_64);
Bit32u eaddr = (Bit32u) BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
Bit16u reg_16 = read_virtual_word_32(i->seg(), eaddr);
Bit16u es = read_virtual_word_32(i->seg(), (eaddr + 2) & i->asize_mask());
load_seg_reg(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_ES], es);
BX_WRITE_16BIT_REG(i->nnn(), reg_16);
}
// LES/LDS can't be called from long64 mode
void BX_CPP_AttrRegparmN(1) BX_CPU_C::LES_GdMp(bxInstruction_c *i)
{
BX_ASSERT(BX_CPU_THIS_PTR cpu_mode != BX_MODE_LONG_64);
Bit32u eaddr = (Bit32u) BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
Bit16u es = read_virtual_word_32(i->seg(), (eaddr + 4) & i->asize_mask());
Bit32u reg_32 = read_virtual_dword_32(i->seg(), eaddr);
load_seg_reg(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_ES], es);
BX_WRITE_32BIT_REGZ(i->nnn(), reg_32);
}
// LES/LDS can't be called from long64 mode
void BX_CPP_AttrRegparmN(1) BX_CPU_C::LDS_GwMp(bxInstruction_c *i)
{
BX_ASSERT(BX_CPU_THIS_PTR cpu_mode != BX_MODE_LONG_64);
Bit32u eaddr = (Bit32u) BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
Bit16u reg_16 = read_virtual_word_32(i->seg(), eaddr);
Bit16u ds = read_virtual_word_32(i->seg(), (eaddr + 2) & i->asize_mask());
load_seg_reg(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS], ds);
BX_WRITE_16BIT_REG(i->nnn(), reg_16);
}
// LES/LDS can't be called from long64 mode
void BX_CPP_AttrRegparmN(1) BX_CPU_C::LDS_GdMp(bxInstruction_c *i)
{
BX_ASSERT(BX_CPU_THIS_PTR cpu_mode != BX_MODE_LONG_64);
Bit32u eaddr = (Bit32u) BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
Bit16u ds = read_virtual_word_32(i->seg(), (eaddr + 4) & i->asize_mask());
Bit32u reg_32 = read_virtual_dword_32(i->seg(), eaddr);
load_seg_reg(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS], ds);
BX_WRITE_32BIT_REGZ(i->nnn(), reg_32);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::LFS_GwMp(bxInstruction_c *i)
{
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
Bit16u reg_16 = read_virtual_word(i->seg(), eaddr);
Bit16u fs = read_virtual_word(i->seg(), (eaddr + 2) & i->asize_mask());
load_seg_reg(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_FS], fs);
BX_WRITE_16BIT_REG(i->nnn(), reg_16);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::LFS_GdMp(bxInstruction_c *i)
{
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
Bit16u fs = read_virtual_word(i->seg(), (eaddr + 4) & i->asize_mask());
Bit32u reg_32 = read_virtual_dword(i->seg(), eaddr);
load_seg_reg(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_FS], fs);
BX_WRITE_32BIT_REGZ(i->nnn(), reg_32);
}
#if BX_SUPPORT_X86_64
void BX_CPP_AttrRegparmN(1) BX_CPU_C::LFS_GqMp(bxInstruction_c *i)
{
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
Bit16u fs = read_virtual_word_64(i->seg(), (eaddr + 8) & i->asize_mask());
Bit64u reg_64 = read_virtual_qword_64(i->seg(), eaddr);
load_seg_reg(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_FS], fs);
BX_WRITE_64BIT_REG(i->nnn(), reg_64);
}
#endif
void BX_CPP_AttrRegparmN(1) BX_CPU_C::LGS_GwMp(bxInstruction_c *i)
{
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
Bit16u reg_16 = read_virtual_word(i->seg(), eaddr);
Bit16u gs = read_virtual_word(i->seg(), (eaddr + 2) & i->asize_mask());
load_seg_reg(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_GS], gs);
BX_WRITE_16BIT_REG(i->nnn(), reg_16);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::LGS_GdMp(bxInstruction_c *i)
{
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
Bit16u gs = read_virtual_word(i->seg(), (eaddr + 4) & i->asize_mask());
Bit32u reg_32 = read_virtual_dword(i->seg(), eaddr);
load_seg_reg(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_GS], gs);
BX_WRITE_32BIT_REGZ(i->nnn(), reg_32);
}
#if BX_SUPPORT_X86_64
void BX_CPP_AttrRegparmN(1) BX_CPU_C::LGS_GqMp(bxInstruction_c *i)
{
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
Bit16u gs = read_virtual_word_64(i->seg(), (eaddr + 8) & i->asize_mask());
Bit64u reg_64 = read_virtual_qword_64(i->seg(), eaddr);
load_seg_reg(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_GS], gs);
BX_WRITE_64BIT_REG(i->nnn(), reg_64);
}
#endif
void BX_CPP_AttrRegparmN(1) BX_CPU_C::LSS_GwMp(bxInstruction_c *i)
{
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
Bit16u reg_16 = read_virtual_word(i->seg(), eaddr);
Bit16u ss = read_virtual_word(i->seg(), (eaddr + 2) & i->asize_mask());
load_seg_reg(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS], ss);
BX_WRITE_16BIT_REG(i->nnn(), reg_16);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::LSS_GdMp(bxInstruction_c *i)
{
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
Bit16u ss = read_virtual_word(i->seg(), (eaddr + 4) & i->asize_mask());
Bit32u reg_32 = read_virtual_dword(i->seg(), eaddr);
load_seg_reg(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS], ss);
BX_WRITE_32BIT_REGZ(i->nnn(), reg_32);
}
#if BX_SUPPORT_X86_64
void BX_CPP_AttrRegparmN(1) BX_CPU_C::LSS_GqMp(bxInstruction_c *i)
{
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
Bit16u ss = read_virtual_word_64(i->seg(), (eaddr + 8) & i->asize_mask());
Bit64u reg_64 = read_virtual_qword_64(i->seg(), eaddr);
load_seg_reg(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS], ss);
BX_WRITE_64BIT_REG(i->nnn(), reg_64);
}
#endif

View File

@ -0,0 +1,679 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2001-2009 The Bochs Project
//
// 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
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA B 02110-1301 USA
/////////////////////////////////////////////////////////////////////////
#define NEED_CPU_REG_SHORTCUTS 1
#include "bochs.h"
#include "cpu.h"
#define LOG_THIS BX_CPU_THIS_PTR
void BX_CPP_AttrRegparmN(2)
BX_CPU_C::load_seg_reg(bx_segment_reg_t *seg, Bit16u new_value)
{
if (protected_mode())
{
if (seg == &BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS])
{
bx_selector_t ss_selector;
bx_descriptor_t descriptor;
Bit32u dword1, dword2;
parse_selector(new_value, &ss_selector);
if ((new_value & 0xfffc) == 0) { /* null selector */
#if BX_SUPPORT_X86_64
// allow SS = 0 in 64 bit mode only with cpl != 3 and rpl=cpl
if (long64_mode() && CPL != 3 && ss_selector.rpl == CPL) {
load_null_selector(seg, new_value);
return;
}
#endif
BX_ERROR(("load_seg_reg(SS): loading null selector"));
exception(BX_GP_EXCEPTION, new_value & 0xfffc);
}
fetch_raw_descriptor(&ss_selector, &dword1, &dword2, BX_GP_EXCEPTION);
/* selector's RPL must = CPL, else #GP(selector) */
if (ss_selector.rpl != CPL) {
BX_ERROR(("load_seg_reg(SS): rpl != CPL"));
exception(BX_GP_EXCEPTION, new_value & 0xfffc);
}
parse_descriptor(dword1, dword2, &descriptor);
if (descriptor.valid==0) {
BX_ERROR(("load_seg_reg(SS): valid bit cleared"));
exception(BX_GP_EXCEPTION, new_value & 0xfffc);
}
/* AR byte must indicate a writable data segment else #GP(selector) */
if (descriptor.segment==0 || IS_CODE_SEGMENT(descriptor.type) ||
IS_DATA_SEGMENT_WRITEABLE(descriptor.type) == 0)
{
BX_ERROR(("load_seg_reg(SS): not writable data segment"));
exception(BX_GP_EXCEPTION, new_value & 0xfffc);
}
/* DPL in the AR byte must equal CPL else #GP(selector) */
if (descriptor.dpl != CPL) {
BX_ERROR(("load_seg_reg(SS): dpl != CPL"));
exception(BX_GP_EXCEPTION, new_value & 0xfffc);
}
/* segment must be marked PRESENT else #SS(selector) */
if (! IS_PRESENT(descriptor)) {
BX_ERROR(("load_seg_reg(SS): not present"));
exception(BX_SS_EXCEPTION, new_value & 0xfffc);
}
touch_segment(&ss_selector, &descriptor);
/* load SS with selector, load SS cache with descriptor */
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].selector = ss_selector;
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache = descriptor;
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.valid = 1;
return;
}
else if ((seg==&BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS]) ||
(seg==&BX_CPU_THIS_PTR sregs[BX_SEG_REG_ES]) ||
(seg==&BX_CPU_THIS_PTR sregs[BX_SEG_REG_FS]) ||
(seg==&BX_CPU_THIS_PTR sregs[BX_SEG_REG_GS])
)
{
bx_descriptor_t descriptor;
bx_selector_t selector;
Bit32u dword1, dword2;
if ((new_value & 0xfffc) == 0) { /* null selector */
load_null_selector(seg, new_value);
return;
}
parse_selector(new_value, &selector);
fetch_raw_descriptor(&selector, &dword1, &dword2, BX_GP_EXCEPTION);
parse_descriptor(dword1, dword2, &descriptor);
if (descriptor.valid==0) {
BX_ERROR(("load_seg_reg(%s, 0x%04x): invalid segment", strseg(seg), new_value));
exception(BX_GP_EXCEPTION, new_value & 0xfffc);
}
/* AR byte must indicate data or readable code segment else #GP(selector) */
if (descriptor.segment==0 || (IS_CODE_SEGMENT(descriptor.type) &&
IS_CODE_SEGMENT_READABLE(descriptor.type) == 0))
{
BX_ERROR(("load_seg_reg(%s, 0x%04x): not data or readable code", strseg(seg), new_value));
exception(BX_GP_EXCEPTION, new_value & 0xfffc);
}
/* If data or non-conforming code, then both the RPL and the CPL
* must be less than or equal to DPL in AR byte else #GP(selector) */
if (IS_DATA_SEGMENT(descriptor.type) ||
IS_CODE_SEGMENT_NON_CONFORMING(descriptor.type))
{
if ((selector.rpl > descriptor.dpl) || (CPL > descriptor.dpl)) {
BX_ERROR(("load_seg_reg(%s, 0x%04x): RPL & CPL must be <= DPL", strseg(seg), new_value));
exception(BX_GP_EXCEPTION, new_value & 0xfffc);
}
}
/* segment must be marked PRESENT else #NP(selector) */
if (! IS_PRESENT(descriptor)) {
BX_ERROR(("load_seg_reg(%s, 0x%04x): segment not present", strseg(seg), new_value));
exception(BX_NP_EXCEPTION, new_value & 0xfffc);
}
touch_segment(&selector, &descriptor);
/* load segment register with selector */
/* load segment register-cache with descriptor */
seg->selector = selector;
seg->cache = descriptor;
seg->cache.valid = 1;
return;
}
else {
BX_PANIC(("load_seg_reg(): invalid segment register passed!"));
return;
}
}
/* real or v8086 mode */
/* www.x86.org:
According to Intel, each time any segment register is loaded in real
mode, the base address is calculated as 16 times the segment value,
while the access rights and size limit attributes are given fixed,
"real-mode compatible" values. This is not true. In fact, only the CS
descriptor caches for the 286, 386, and 486 get loaded with fixed
values each time the segment register is loaded. Loading CS, or any
other segment register in real mode, on later Intel processors doesn't
change the access rights or the segment size limit attributes stored
in the descriptor cache registers. For these segments, the access
rights and segment size limit attributes from any previous setting are
honored. */
seg->selector.value = new_value;
seg->selector.rpl = real_mode() ? 0 : 3;
seg->cache.valid = 1;
seg->cache.u.segment.base = new_value << 4;
seg->cache.segment = 1; /* regular segment */
seg->cache.p = 1; /* present */
/* Do not modify segment limit and AR bytes when in real mode */
/* Support for big real mode */
if (!real_mode()) {
seg->cache.type = BX_DATA_READ_WRITE_ACCESSED;
seg->cache.dpl = 3; /* we are in v8086 mode */
seg->cache.u.segment.limit_scaled = 0xffff;
seg->cache.u.segment.g = 0; /* byte granular */
seg->cache.u.segment.d_b = 0; /* default 16bit size */
#if BX_SUPPORT_X86_64
seg->cache.u.segment.l = 0; /* default 16bit size */
#endif
seg->cache.u.segment.avl = 0;
}
if (seg == &BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS]) {
invalidate_prefetch_q();
updateFetchModeMask(/* CS reloaded */);
#if BX_CPU_LEVEL >= 4 && BX_SUPPORT_ALIGNMENT_CHECK
handleAlignmentCheck(/* CPL change */);
#endif
}
}
void BX_CPP_AttrRegparmN(2)
BX_CPU_C::load_null_selector(bx_segment_reg_t *seg, unsigned value)
{
BX_ASSERT((value & 0xfffc) == 0);
seg->selector.index = 0;
seg->selector.ti = 0;
seg->selector.rpl = BX_SELECTOR_RPL(value);
seg->selector.value = value;
seg->cache.valid = 0; /* invalidate null selector */
seg->cache.p = 0;
seg->cache.dpl = 0;
seg->cache.segment = 1; /* data/code segment */
seg->cache.type = 0;
seg->cache.u.segment.base = 0;
seg->cache.u.segment.limit_scaled = 0;
seg->cache.u.segment.g = 0;
seg->cache.u.segment.d_b = 0;
seg->cache.u.segment.avl = 0;
#if BX_SUPPORT_X86_64
seg->cache.u.segment.l = 0;
#endif
}
BX_CPP_INLINE void BX_CPU_C::validate_seg_reg(unsigned seg)
{
/*
FOR (seg = ES, DS, FS, GS)
DO
IF ((seg.attr.dpl < CPL) && ((seg.attr.type = 'data')
|| (seg.attr.type = 'non-conforming-code')))
{
seg = NULL // can't use lower dpl data segment at higher cpl
}
END
*/
bx_segment_reg_t *segment = &BX_CPU_THIS_PTR sregs[seg];
if (segment->cache.dpl < CPL)
{
// invalidate if data or non-conforming code segment
if (segment->cache.valid==0 || segment->cache.segment==0 ||
IS_DATA_SEGMENT(segment->cache.type) ||
IS_CODE_SEGMENT_NON_CONFORMING(segment->cache.type))
{
segment->selector.value = 0;
segment->cache.valid = 0;
}
}
}
void BX_CPU_C::validate_seg_regs(void)
{
validate_seg_reg(BX_SEG_REG_ES);
validate_seg_reg(BX_SEG_REG_DS);
validate_seg_reg(BX_SEG_REG_FS);
validate_seg_reg(BX_SEG_REG_GS);
}
void parse_selector(Bit16u raw_selector, bx_selector_t *selector)
{
selector->value = raw_selector;
selector->index = raw_selector >> 3;
selector->ti = (raw_selector >> 2) & 0x01;
selector->rpl = raw_selector & 0x03;
}
Bit8u get_ar_byte(const bx_descriptor_t *d)
{
return (d->type) |
(d->segment << 4) |
(d->dpl << 5) |
(d->p << 7);
}
void set_ar_byte(bx_descriptor_t *d, Bit8u ar_byte)
{
d->p = (ar_byte >> 7) & 0x01;
d->dpl = (ar_byte >> 5) & 0x03;
d->segment = (ar_byte >> 4) & 0x01;
d->type = (ar_byte & 0x0f);
}
Bit32u BX_CPP_AttrRegparmN(1)
BX_CPU_C::get_descriptor_l(const bx_descriptor_t *d)
{
Bit32u limit = d->u.segment.limit_scaled;
if (d->u.segment.g)
limit >>= 12;
Bit32u val = ((d->u.segment.base & 0xffff) << 16) | (limit & 0xffff);
if (d->segment) {
return(val);
}
else {
switch (d->type) {
case BX_SYS_SEGMENT_LDT:
case BX_SYS_SEGMENT_AVAIL_286_TSS:
case BX_SYS_SEGMENT_BUSY_286_TSS:
case BX_SYS_SEGMENT_AVAIL_386_TSS:
case BX_SYS_SEGMENT_BUSY_386_TSS:
return(val);
default:
BX_ERROR(("#get_descriptor_l(): type %d not finished", d->type));
return(0);
}
}
}
Bit32u BX_CPP_AttrRegparmN(1)
BX_CPU_C::get_descriptor_h(const bx_descriptor_t *d)
{
Bit32u val;
Bit32u limit = d->u.segment.limit_scaled;
if (d->u.segment.g)
limit >>= 12;
if (d->segment) {
val = (d->u.segment.base & 0xff000000) |
((d->u.segment.base >> 16) & 0x000000ff) |
(d->type << 8) |
(d->segment << 12) |
(d->dpl << 13) |
(d->p << 15) | (limit & 0xf0000) |
(d->u.segment.avl << 20) |
#if BX_SUPPORT_X86_64
(d->u.segment.l << 21) |
#endif
(d->u.segment.d_b << 22) |
(d->u.segment.g << 23);
return(val);
}
else {
switch (d->type) {
case BX_SYS_SEGMENT_AVAIL_286_TSS:
case BX_SYS_SEGMENT_BUSY_286_TSS:
case BX_SYS_SEGMENT_LDT:
case BX_SYS_SEGMENT_AVAIL_386_TSS:
case BX_SYS_SEGMENT_BUSY_386_TSS:
val = ((d->u.segment.base >> 16) & 0xff) |
(d->type << 8) |
(d->dpl << 13) |
(d->p << 15) | (limit & 0xf0000) |
(d->u.segment.avl << 20) |
(d->u.segment.d_b << 22) |
(d->u.segment.g << 23) |
(d->u.segment.base & 0xff000000);
return(val);
default:
BX_ERROR(("#get_descriptor_h(): type %d not finished", d->type));
return(0);
}
}
}
bx_bool BX_CPU_C::set_segment_ar_data(bx_segment_reg_t *seg, bx_bool valid,
Bit16u raw_selector, bx_address base, Bit32u limit_scaled, Bit16u ar_data)
{
parse_selector(raw_selector, &seg->selector);
bx_descriptor_t *d = &seg->cache;
d->p = (ar_data >> 7) & 0x1;
d->dpl = (ar_data >> 5) & 0x3;
d->segment = (ar_data >> 4) & 0x1;
d->type = (ar_data & 0x0f);
d->valid = valid;
if (d->segment) { /* data/code segment descriptors */
d->u.segment.g = (ar_data >> 15) & 0x1;
d->u.segment.d_b = (ar_data >> 14) & 0x1;
#if BX_SUPPORT_X86_64
d->u.segment.l = (ar_data >> 13) & 0x1;
#endif
d->u.segment.avl = (ar_data >> 12) & 0x1;
d->u.segment.base = base;
d->u.segment.limit_scaled = limit_scaled;
}
else {
switch(d->type) {
case BX_SYS_SEGMENT_LDT:
case BX_SYS_SEGMENT_AVAIL_286_TSS:
case BX_SYS_SEGMENT_BUSY_286_TSS:
case BX_SYS_SEGMENT_AVAIL_386_TSS:
case BX_SYS_SEGMENT_BUSY_386_TSS:
d->u.segment.avl = (ar_data >> 12) & 0x1;
d->u.segment.d_b = (ar_data >> 14) & 0x1;
d->u.segment.g = (ar_data >> 15) & 0x1;
d->u.segment.base = base;
d->u.segment.limit_scaled = limit_scaled;
break;
default:
BX_ERROR(("set_segment_ar_data(): case %u unsupported, valid=%d", (unsigned) d->type, d->valid));
}
}
return d->valid;
}
void parse_descriptor(Bit32u dword1, Bit32u dword2, bx_descriptor_t *temp)
{
Bit8u AR_byte;
Bit32u limit;
AR_byte = dword2 >> 8;
temp->p = (AR_byte >> 7) & 0x1;
temp->dpl = (AR_byte >> 5) & 0x3;
temp->segment = (AR_byte >> 4) & 0x1;
temp->type = (AR_byte & 0xf);
temp->valid = 0; /* start out invalid */
if (temp->segment) { /* data/code segment descriptors */
limit = (dword1 & 0xffff) | (dword2 & 0x000F0000);
temp->u.segment.base = (dword1 >> 16) | ((dword2 & 0xFF) << 16);
temp->u.segment.g = (dword2 & 0x00800000) > 0;
temp->u.segment.d_b = (dword2 & 0x00400000) > 0;
#if BX_SUPPORT_X86_64
temp->u.segment.l = (dword2 & 0x00200000) > 0;
#endif
temp->u.segment.avl = (dword2 & 0x00100000) > 0;
temp->u.segment.base |= (dword2 & 0xFF000000);
if (temp->u.segment.g)
temp->u.segment.limit_scaled = (limit << 12) | 0xfff;
else
temp->u.segment.limit_scaled = limit;
temp->valid = 1;
}
else { // system & gate segment descriptors
switch (temp->type) {
case BX_286_CALL_GATE:
case BX_286_INTERRUPT_GATE:
case BX_286_TRAP_GATE:
// param count only used for call gate
temp->u.gate.param_count = dword2 & 0x1f;
temp->u.gate.dest_selector = dword1 >> 16;
temp->u.gate.dest_offset = dword1 & 0xffff;
temp->valid = 1;
break;
case BX_386_CALL_GATE:
case BX_386_INTERRUPT_GATE:
case BX_386_TRAP_GATE:
// param count only used for call gate
temp->u.gate.param_count = dword2 & 0x1f;
temp->u.gate.dest_selector = dword1 >> 16;
temp->u.gate.dest_offset = (dword2 & 0xffff0000) |
(dword1 & 0x0000ffff);
temp->valid = 1;
break;
case BX_TASK_GATE:
temp->u.taskgate.tss_selector = dword1 >> 16;
temp->valid = 1;
break;
case BX_SYS_SEGMENT_LDT:
case BX_SYS_SEGMENT_AVAIL_286_TSS:
case BX_SYS_SEGMENT_BUSY_286_TSS:
case BX_SYS_SEGMENT_AVAIL_386_TSS:
case BX_SYS_SEGMENT_BUSY_386_TSS:
limit = (dword1 & 0xffff) | (dword2 & 0x000F0000);
temp->u.segment.base = (dword1 >> 16) |
((dword2 & 0xff) << 16) | (dword2 & 0xff000000);
temp->u.segment.g = (dword2 & 0x00800000) > 0;
temp->u.segment.d_b = (dword2 & 0x00400000) > 0;
temp->u.segment.avl = (dword2 & 0x00100000) > 0;
if (temp->u.segment.g)
temp->u.segment.limit_scaled = (limit << 12) | 0xfff;
else
temp->u.segment.limit_scaled = limit;
temp->valid = 1;
break;
default: // reserved
temp->valid = 0;
break;
}
}
}
void BX_CPP_AttrRegparmN(2)
BX_CPU_C::touch_segment(bx_selector_t *selector, bx_descriptor_t *descriptor)
{
if (! IS_SEGMENT_ACCESSED(descriptor->type)) {
Bit8u AR_byte = get_ar_byte(descriptor);
AR_byte |= 1;
descriptor->type |= 1;
if (selector->ti == 0) { /* GDT */
access_write_linear(BX_CPU_THIS_PTR gdtr.base + selector->index*8 + 5, 1, 0, &AR_byte);
}
else { /* LDT */
access_write_linear(BX_CPU_THIS_PTR ldtr.cache.u.segment.base + selector->index*8 + 5, 1, 0, &AR_byte);
}
}
}
void BX_CPP_AttrRegparmN(3)
BX_CPU_C::load_ss(bx_selector_t *selector, bx_descriptor_t *descriptor, Bit8u cpl)
{
// Add cpl to the selector value.
selector->value = (BX_SELECTOR_RPL_MASK & selector->value) | cpl;
if ((selector->value & BX_SELECTOR_RPL_MASK) != 0)
touch_segment(selector, descriptor);
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].selector = *selector;
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache = *descriptor;
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].selector.rpl = cpl;
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.valid = 1;
}
void BX_CPU_C::fetch_raw_descriptor(const bx_selector_t *selector,
Bit32u *dword1, Bit32u *dword2, unsigned exception_no)
{
Bit32u index = selector->index;
bx_address offset;
Bit64u raw_descriptor;
if (selector->ti == 0) { /* GDT */
if ((index*8 + 7) > BX_CPU_THIS_PTR gdtr.limit) {
BX_ERROR(("fetch_raw_descriptor: GDT: index (%x) %x > limit (%x)",
index*8 + 7, index, BX_CPU_THIS_PTR gdtr.limit));
exception(exception_no, selector->value & 0xfffc);
}
offset = BX_CPU_THIS_PTR gdtr.base + index*8;
}
else { /* LDT */
if (BX_CPU_THIS_PTR ldtr.cache.valid==0) {
BX_ERROR(("fetch_raw_descriptor: LDTR.valid=0"));
exception(exception_no, selector->value & 0xfffc);
}
if ((index*8 + 7) > BX_CPU_THIS_PTR ldtr.cache.u.segment.limit_scaled) {
BX_ERROR(("fetch_raw_descriptor: LDT: index (%x) %x > limit (%x)",
index*8 + 7, index, BX_CPU_THIS_PTR ldtr.cache.u.segment.limit_scaled));
exception(exception_no, selector->value & 0xfffc);
}
offset = BX_CPU_THIS_PTR ldtr.cache.u.segment.base + index*8;
}
raw_descriptor = system_read_qword(offset);
*dword1 = GET32L(raw_descriptor);
*dword2 = GET32H(raw_descriptor);
}
bx_bool BX_CPP_AttrRegparmN(3)
BX_CPU_C::fetch_raw_descriptor2(const bx_selector_t *selector, Bit32u *dword1, Bit32u *dword2)
{
Bit32u index = selector->index;
bx_address offset;
Bit64u raw_descriptor;
if (selector->ti == 0) { /* GDT */
if ((index*8 + 7) > BX_CPU_THIS_PTR gdtr.limit)
return 0;
offset = BX_CPU_THIS_PTR gdtr.base + index*8;
}
else { /* LDT */
if (BX_CPU_THIS_PTR ldtr.cache.valid==0) {
BX_ERROR(("fetch_raw_descriptor2: LDTR.valid=0"));
return 0;
}
if ((index*8 + 7) > BX_CPU_THIS_PTR ldtr.cache.u.segment.limit_scaled)
return 0;
offset = BX_CPU_THIS_PTR ldtr.cache.u.segment.base + index*8;
}
raw_descriptor = system_read_qword(offset);
*dword1 = GET32L(raw_descriptor);
*dword2 = GET32H(raw_descriptor);
return 1;
}
#if BX_SUPPORT_X86_64
void BX_CPU_C::fetch_raw_descriptor_64(const bx_selector_t *selector,
Bit32u *dword1, Bit32u *dword2, Bit32u *dword3, unsigned exception_no)
{
Bit32u index = selector->index;
bx_address offset;
Bit64u raw_descriptor1, raw_descriptor2;
if (selector->ti == 0) { /* GDT */
if ((index*8 + 15) > BX_CPU_THIS_PTR gdtr.limit) {
BX_ERROR(("fetch_raw_descriptor64: GDT: index (%x) %x > limit (%x)",
index*8 + 15, index, BX_CPU_THIS_PTR gdtr.limit));
exception(exception_no, selector->value & 0xfffc);
}
offset = BX_CPU_THIS_PTR gdtr.base + index*8;
}
else { /* LDT */
if (BX_CPU_THIS_PTR ldtr.cache.valid==0) {
BX_ERROR(("fetch_raw_descriptor64: LDTR.valid=0"));
exception(exception_no, selector->value & 0xfffc);
}
if ((index*8 + 15) > BX_CPU_THIS_PTR ldtr.cache.u.segment.limit_scaled) {
BX_ERROR(("fetch_raw_descriptor64: LDT: index (%x) %x > limit (%x)",
index*8 + 15, index, BX_CPU_THIS_PTR ldtr.cache.u.segment.limit_scaled));
exception(exception_no, selector->value & 0xfffc);
}
offset = BX_CPU_THIS_PTR ldtr.cache.u.segment.base + index*8;
}
raw_descriptor1 = system_read_qword(offset);
raw_descriptor2 = system_read_qword(offset + 8);
if (raw_descriptor2 & BX_CONST64(0x00001F0000000000)) {
BX_ERROR(("fetch_raw_descriptor64: extended attributes DWORD4 TYPE != 0"));
exception(BX_GP_EXCEPTION, selector->value & 0xfffc);
}
*dword1 = GET32L(raw_descriptor1);
*dword2 = GET32H(raw_descriptor1);
*dword3 = GET32L(raw_descriptor2);
}
bx_bool BX_CPU_C::fetch_raw_descriptor2_64(const bx_selector_t *selector,
Bit32u *dword1, Bit32u *dword2, Bit32u *dword3)
{
Bit32u index = selector->index;
bx_address offset;
Bit64u raw_descriptor1, raw_descriptor2;
if (selector->ti == 0) { /* GDT */
if ((index*8 + 15) > BX_CPU_THIS_PTR gdtr.limit) {
BX_ERROR(("fetch_raw_descriptor2_64: GDT: index (%x) %x > limit (%x)",
index*8 + 15, index, BX_CPU_THIS_PTR gdtr.limit));
return 0;
}
offset = BX_CPU_THIS_PTR gdtr.base + index*8;
}
else { /* LDT */
if (BX_CPU_THIS_PTR ldtr.cache.valid==0) {
BX_ERROR(("fetch_raw_descriptor2_64: LDTR.valid=0"));
return 0;
}
if ((index*8 + 15) > BX_CPU_THIS_PTR ldtr.cache.u.segment.limit_scaled) {
BX_ERROR(("fetch_raw_descriptor2_64: LDT: index (%x) %x > limit (%x)",
index*8 + 15, index, BX_CPU_THIS_PTR ldtr.cache.u.segment.limit_scaled));
return 0;
}
offset = BX_CPU_THIS_PTR ldtr.cache.u.segment.base + index*8;
}
raw_descriptor1 = system_read_qword(offset);
raw_descriptor2 = system_read_qword(offset + 8);
if (raw_descriptor2 & BX_CONST64(0x00001F0000000000)) {
BX_ERROR(("fetch_raw_descriptor2_64: extended attributes DWORD4 TYPE != 0"));
return 0;
}
*dword1 = GET32L(raw_descriptor1);
*dword2 = GET32H(raw_descriptor1);
*dword3 = GET32L(raw_descriptor2);
return 1;
}
#endif

View File

@ -0,0 +1,641 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2001-2010 The Bochs Project
//
// 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
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA B 02110-1301 USA
/////////////////////////////////////////////////////////////////////////
#define NEED_CPU_REG_SHORTCUTS 1
#include "bochs.h"
#include "cpu.h"
#define LOG_THIS BX_CPU_THIS_PTR
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SHLD_EwGwM(bxInstruction_c *i)
{
Bit16u op1_16, op2_16, result_16;
Bit32u temp_32, result_32;
unsigned count;
unsigned of, cf;
/* op1:op2 << count. result stored in op1 */
if (i->b1() == 0xa4) // 0x1a4
count = i->Ib();
else // 0x1a5
count = CL;
count &= 0x1f; // use only 5 LSB's
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
/* pointer, segment address pair */
op1_16 = read_RMW_virtual_word(i->seg(), eaddr);
if (!count) return;
op2_16 = BX_READ_16BIT_REG(i->nnn());
/* count < 32, since only lower 5 bits used */
temp_32 = ((Bit32u)(op1_16) << 16) | (op2_16); // double formed by op1:op2
result_32 = temp_32 << count;
// hack to act like x86 SHLD when count > 16
if (count > 16) {
// when count > 16 actually shifting op1:op2:op2 << count,
// it is the same as shifting op2:op2 by count-16
result_32 |= (op1_16 << (count - 16));
}
result_16 = (Bit16u)(result_32 >> 16);
write_RMW_virtual_word(result_16);
SET_FLAGS_OSZAPC_LOGIC_16(result_16);
cf = (temp_32 >> (32 - count)) & 0x1;
of = cf ^ (result_16 >> 15); // of = cf ^ result15
SET_FLAGS_OxxxxC(of, cf);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SHLD_EwGwR(bxInstruction_c *i)
{
Bit16u op1_16, op2_16, result_16;
Bit32u temp_32, result_32;
unsigned count;
unsigned of, cf;
/* op1:op2 << count. result stored in op1 */
if (i->b1() == 0xa4) // 0x1a4
count = i->Ib();
else // 0x1a5
count = CL;
count &= 0x1f; // use only 5 LSB's
if (!count) return;
op1_16 = BX_READ_16BIT_REG(i->rm());
op2_16 = BX_READ_16BIT_REG(i->nnn());
/* count < 32, since only lower 5 bits used */
temp_32 = ((Bit32u)(op1_16) << 16) | (op2_16); // double formed by op1:op2
result_32 = temp_32 << count;
// hack to act like x86 SHLD when count > 16
if (count > 16) {
// when count > 16 actually shifting op1:op2:op2 << count,
// it is the same as shifting op2:op2 by count-16
result_32 |= (op1_16 << (count - 16));
}
result_16 = (Bit16u)(result_32 >> 16);
BX_WRITE_16BIT_REG(i->rm(), result_16);
SET_FLAGS_OSZAPC_LOGIC_16(result_16);
cf = (temp_32 >> (32 - count)) & 0x1;
of = cf ^ (result_16 >> 15); // of = cf ^ result15
SET_FLAGS_OxxxxC(of, cf);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SHRD_EwGwM(bxInstruction_c *i)
{
Bit16u op1_16, op2_16, result_16;
Bit32u temp_32, result_32;
unsigned count;
unsigned cf, of;
if (i->b1() == 0xac) // 0x1ac
count = i->Ib();
else // 0x1ad
count = CL;
count &= 0x1f; /* use only 5 LSB's */
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
/* pointer, segment address pair */
op1_16 = read_RMW_virtual_word(i->seg(), eaddr);
if (!count) return;
op2_16 = BX_READ_16BIT_REG(i->nnn());
/* count < 32, since only lower 5 bits used */
temp_32 = (op2_16 << 16) | op1_16; // double formed by op2:op1
result_32 = temp_32 >> count;
// hack to act like x86 SHRD when count > 16
if (count > 16) {
// when count > 16 actually shifting op2:op2:op1 >> count,
// it is the same as shifting op2:op2 by count-16
result_32 |= (op1_16 << (32 - count));
}
result_16 = (Bit16u) result_32;
write_RMW_virtual_word(result_16);
SET_FLAGS_OSZAPC_LOGIC_16(result_16);
cf = (op1_16 >> (count - 1)) & 0x1;
of = ((Bit16u)((result_16 << 1) ^ result_16) >> 15) & 0x1; // of = result14 ^ result15
SET_FLAGS_OxxxxC(of, cf);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SHRD_EwGwR(bxInstruction_c *i)
{
Bit16u op1_16, op2_16, result_16;
Bit32u temp_32, result_32;
unsigned count;
unsigned cf, of;
if (i->b1() == 0xac) // 0x1ac
count = i->Ib();
else // 0x1ad
count = CL;
count &= 0x1f; /* use only 5 LSB's */
if (!count) return;
op1_16 = BX_READ_16BIT_REG(i->rm());
op2_16 = BX_READ_16BIT_REG(i->nnn());
/* count < 32, since only lower 5 bits used */
temp_32 = (op2_16 << 16) | op1_16; // double formed by op2:op1
result_32 = temp_32 >> count;
// hack to act like x86 SHRD when count > 16
if (count > 16) {
// when count > 16 actually shifting op2:op2:op1 >> count,
// it is the same as shifting op2:op2 by count-16
result_32 |= (op1_16 << (32 - count));
}
result_16 = (Bit16u) result_32;
BX_WRITE_16BIT_REG(i->rm(), result_16);
SET_FLAGS_OSZAPC_LOGIC_16(result_16);
cf = (op1_16 >> (count - 1)) & 0x1;
of = ((Bit16u)((result_16 << 1) ^ result_16) >> 15) & 0x1; // of = result14 ^ result15
SET_FLAGS_OxxxxC(of, cf);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::ROL_EwM(bxInstruction_c *i)
{
unsigned count;
unsigned bit0, bit15;
if (i->b1() == 0xd3)
count = CL;
else // 0xc1 or 0xd1
count = i->Ib();
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
/* pointer, segment address pair */
Bit16u op1_16 = read_RMW_virtual_word(i->seg(), eaddr);
if ((count & 0x0f) == 0) {
if (count & 0x10) {
bit0 = (op1_16 & 0x1);
bit15 = (op1_16 >> 15);
// of = cf ^ result15
SET_FLAGS_OxxxxC(bit0 ^ bit15, bit0);
}
return;
}
count &= 0x0f; // only use bottom 4 bits
Bit16u result_16 = (op1_16 << count) | (op1_16 >> (16 - count));
write_RMW_virtual_word(result_16);
bit0 = (result_16 & 0x1);
bit15 = (result_16 >> 15);
// of = cf ^ result15
SET_FLAGS_OxxxxC(bit0 ^ bit15, bit0);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::ROL_EwR(bxInstruction_c *i)
{
unsigned count;
unsigned bit0, bit15;
if (i->b1() == 0xd3)
count = CL;
else // 0xc1 or 0xd1
count = i->Ib();
Bit16u op1_16 = BX_READ_16BIT_REG(i->rm());
if ((count & 0x0f) == 0) {
if (count & 0x10) {
bit0 = (op1_16 & 0x1);
bit15 = (op1_16 >> 15);
// of = cf ^ result15
SET_FLAGS_OxxxxC(bit0 ^ bit15, bit0);
}
return;
}
count &= 0x0f; // only use bottom 4 bits
Bit16u result_16 = (op1_16 << count) | (op1_16 >> (16 - count));
BX_WRITE_16BIT_REG(i->rm(), result_16);
bit0 = (result_16 & 0x1);
bit15 = (result_16 >> 15);
// of = cf ^ result15
SET_FLAGS_OxxxxC(bit0 ^ bit15, bit0);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::ROR_EwM(bxInstruction_c *i)
{
unsigned count;
unsigned bit14, bit15;
if (i->b1() == 0xd3)
count = CL;
else // 0xc1 or 0xd1
count = i->Ib();
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
/* pointer, segment address pair */
Bit16u op1_16 = read_RMW_virtual_word(i->seg(), eaddr);
if ((count & 0x0f) == 0) {
if (count & 0x10) {
bit14 = (op1_16 >> 14) & 1;
bit15 = (op1_16 >> 15) & 1;
// of = result14 ^ result15
SET_FLAGS_OxxxxC(bit14 ^ bit15, bit15);
}
return;
}
count &= 0x0f; // use only 4 LSB's
Bit16u result_16 = (op1_16 >> count) | (op1_16 << (16 - count));
write_RMW_virtual_word(result_16);
bit14 = (result_16 >> 14) & 1;
bit15 = (result_16 >> 15) & 1;
// of = result14 ^ result15
SET_FLAGS_OxxxxC(bit14 ^ bit15, bit15);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::ROR_EwR(bxInstruction_c *i)
{
unsigned count;
unsigned bit14, bit15;
if (i->b1() == 0xd3)
count = CL;
else // 0xc1 or 0xd1
count = i->Ib();
Bit16u op1_16 = BX_READ_16BIT_REG(i->rm());
if ((count & 0x0f) == 0) {
if (count & 0x10) {
bit14 = (op1_16 >> 14) & 1;
bit15 = (op1_16 >> 15) & 1;
// of = result14 ^ result15
SET_FLAGS_OxxxxC(bit14 ^ bit15, bit15);
}
return;
}
count &= 0x0f; // use only 4 LSB's
Bit16u result_16 = (op1_16 >> count) | (op1_16 << (16 - count));
BX_WRITE_16BIT_REG(i->rm(), result_16);
bit14 = (result_16 >> 14) & 1;
bit15 = (result_16 >> 15) & 1;
// of = result14 ^ result15
SET_FLAGS_OxxxxC(bit14 ^ bit15, bit15);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::RCL_EwM(bxInstruction_c *i)
{
Bit16u result_16;
unsigned count;
unsigned of, cf;
if (i->b1() == 0xd3)
count = CL;
else // 0xc1 or 0xd1
count = i->Ib();
count = (count & 0x1f) % 17;
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
/* pointer, segment address pair */
Bit16u op1_16 = read_RMW_virtual_word(i->seg(), eaddr);
if (!count) return;
if (count==1) {
result_16 = (op1_16 << 1) | getB_CF();
}
else if (count==16) {
result_16 = (getB_CF() << 15) | (op1_16 >> 1);
}
else { // 2..15
result_16 = (op1_16 << count) | (getB_CF() << (count - 1)) |
(op1_16 >> (17 - count));
}
write_RMW_virtual_word(result_16);
cf = (op1_16 >> (16 - count)) & 0x1;
of = cf ^ (result_16 >> 15); // of = cf ^ result15
SET_FLAGS_OxxxxC(of, cf);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::RCL_EwR(bxInstruction_c *i)
{
Bit16u result_16;
unsigned count;
unsigned of, cf;
if (i->b1() == 0xd3)
count = CL;
else // 0xc1 or 0xd1
count = i->Ib();
count = (count & 0x1f) % 17;
if (!count) return;
Bit16u op1_16 = BX_READ_16BIT_REG(i->rm());
if (count==1) {
result_16 = (op1_16 << 1) | getB_CF();
}
else if (count==16) {
result_16 = (getB_CF() << 15) | (op1_16 >> 1);
}
else { // 2..15
result_16 = (op1_16 << count) | (getB_CF() << (count - 1)) |
(op1_16 >> (17 - count));
}
BX_WRITE_16BIT_REG(i->rm(), result_16);
cf = (op1_16 >> (16 - count)) & 0x1;
of = cf ^ (result_16 >> 15); // of = cf ^ result15
SET_FLAGS_OxxxxC(of, cf);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::RCR_EwM(bxInstruction_c *i)
{
unsigned count;
unsigned of, cf;
if (i->b1() == 0xd3)
count = CL;
else // 0xc1 or 0xd1
count = i->Ib();
count = (count & 0x1f) % 17;
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
/* pointer, segment address pair */
Bit16u op1_16 = read_RMW_virtual_word(i->seg(), eaddr);
if (! count) return;
Bit16u result_16 = (op1_16 >> count) | (getB_CF() << (16 - count)) |
(op1_16 << (17 - count));
write_RMW_virtual_word(result_16);
cf = (op1_16 >> (count - 1)) & 0x1;
of = ((Bit16u)((result_16 << 1) ^ result_16) >> 15) & 0x1; // of = result15 ^ result14
SET_FLAGS_OxxxxC(of, cf);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::RCR_EwR(bxInstruction_c *i)
{
unsigned count;
unsigned of, cf;
if (i->b1() == 0xd3)
count = CL;
else // 0xc1 or 0xd1
count = i->Ib();
count = (count & 0x1f) % 17;
if (! count) return;
Bit16u op1_16 = BX_READ_16BIT_REG(i->rm());
Bit16u result_16 = (op1_16 >> count) | (getB_CF() << (16 - count)) |
(op1_16 << (17 - count));
BX_WRITE_16BIT_REG(i->rm(), result_16);
cf = (op1_16 >> (count - 1)) & 0x1;
of = ((Bit16u)((result_16 << 1) ^ result_16) >> 15) & 0x1; // of = result15 ^ result14
SET_FLAGS_OxxxxC(of, cf);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SHL_EwM(bxInstruction_c *i)
{
Bit16u result_16;
unsigned count;
unsigned of = 0, cf = 0;
if (i->b1() == 0xd3)
count = CL;
else // 0xc1 or 0xd1
count = i->Ib();
count &= 0x1f; /* use only 5 LSB's */
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
/* pointer, segment address pair */
Bit16u op1_16 = read_RMW_virtual_word(i->seg(), eaddr);
if (!count) return;
if (count <= 16) {
result_16 = (op1_16 << count);
cf = (op1_16 >> (16 - count)) & 0x1;
of = cf ^ (result_16 >> 15); // of = cf ^ result15
}
else {
result_16 = 0;
}
write_RMW_virtual_word(result_16);
SET_FLAGS_OSZAPC_LOGIC_16(result_16);
SET_FLAGS_OxxxxC(of, cf);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SHL_EwR(bxInstruction_c *i)
{
Bit16u result_16;
unsigned count;
unsigned of = 0, cf = 0;
if (i->b1() == 0xd3)
count = CL;
else // 0xc1 or 0xd1
count = i->Ib();
count &= 0x1f; /* use only 5 LSB's */
if (!count) return;
Bit16u op1_16 = BX_READ_16BIT_REG(i->rm());
if (count <= 16) {
result_16 = (op1_16 << count);
cf = (op1_16 >> (16 - count)) & 0x1;
of = cf ^ (result_16 >> 15); // of = cf ^ result15
}
else {
result_16 = 0;
}
BX_WRITE_16BIT_REG(i->rm(), result_16);
SET_FLAGS_OSZAPC_LOGIC_16(result_16);
SET_FLAGS_OxxxxC(of, cf);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SHR_EwM(bxInstruction_c *i)
{
unsigned count;
unsigned of, cf;
if (i->b1() == 0xd3)
count = CL;
else // 0xc1 or 0xd1
count = i->Ib();
count &= 0x1f; /* use only 5 LSB's */
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
/* pointer, segment address pair */
Bit16u op1_16 = read_RMW_virtual_word(i->seg(), eaddr);
if (!count) return;
Bit16u result_16 = (op1_16 >> count);
write_RMW_virtual_word(result_16);
cf = (op1_16 >> (count - 1)) & 0x1;
// note, that of == result15 if count == 1 and
// of == 0 if count >= 2
of = ((Bit16u)((result_16 << 1) ^ result_16) >> 15) & 0x1;
SET_FLAGS_OSZAPC_LOGIC_16(result_16);
SET_FLAGS_OxxxxC(of, cf);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SHR_EwR(bxInstruction_c *i)
{
unsigned count;
unsigned of, cf;
if (i->b1() == 0xd3)
count = CL;
else // 0xc1 or 0xd1
count = i->Ib();
count &= 0x1f; /* use only 5 LSB's */
if (!count) return;
Bit16u op1_16 = BX_READ_16BIT_REG(i->rm());
Bit16u result_16 = (op1_16 >> count);
BX_WRITE_16BIT_REG(i->rm(), result_16);
cf = (op1_16 >> (count - 1)) & 0x1;
// note, that of == result15 if count == 1 and
// of == 0 if count >= 2
of = ((Bit16u)((result_16 << 1) ^ result_16) >> 15) & 0x1;
SET_FLAGS_OSZAPC_LOGIC_16(result_16);
SET_FLAGS_OxxxxC(of, cf);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SAR_EwM(bxInstruction_c *i)
{
unsigned count, cf;
if (i->b1() == 0xd3)
count = CL;
else // 0xc1 or 0xd1
count = i->Ib();
count &= 0x1f; /* use only 5 LSB's */
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
/* pointer, segment address pair */
Bit16u op1_16 = read_RMW_virtual_word(i->seg(), eaddr);
if (!count) return;
Bit16u result_16 = ((Bit16s) op1_16) >> count;
cf = (((Bit16s) op1_16) >> (count - 1)) & 0x1;
SET_FLAGS_OSZAPC_LOGIC_16(result_16);
/* signed overflow cannot happen in SAR instruction */
SET_FLAGS_OxxxxC(0, cf);
write_RMW_virtual_word(result_16);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SAR_EwR(bxInstruction_c *i)
{
unsigned count, cf;
if (i->b1() == 0xd3)
count = CL;
else // 0xc1 or 0xd1
count = i->Ib();
count &= 0x1f; /* use only 5 LSB's */
if (!count) return;
Bit16u op1_16 = BX_READ_16BIT_REG(i->rm());
Bit16u result_16 = ((Bit16s) op1_16) >> count;
BX_WRITE_16BIT_REG(i->rm(), result_16);
cf = (((Bit16s) op1_16) >> (count - 1)) & 0x1;
SET_FLAGS_OSZAPC_LOGIC_16(result_16);
/* signed overflow cannot happen in SAR instruction */
SET_FLAGS_OxxxxC(0, cf);
}

View File

@ -0,0 +1,576 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2001-2010 The Bochs Project
//
// 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
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA B 02110-1301 USA
/////////////////////////////////////////////////////////////////////////
#define NEED_CPU_REG_SHORTCUTS 1
#include "bochs.h"
#include "cpu.h"
#define LOG_THIS BX_CPU_THIS_PTR
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SHLD_EdGdM(bxInstruction_c *i)
{
Bit32u op1_32, op2_32, result_32;
unsigned count;
unsigned of, cf;
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
/* pointer, segment address pair */
op1_32 = read_RMW_virtual_dword(i->seg(), eaddr);
if (i->b1() == 0xa4) // 0x1a4
count = i->Ib();
else // 0x1a5
count = CL;
count &= 0x1f; // use only 5 LSB's
if (!count) return;
op2_32 = BX_READ_32BIT_REG(i->nnn());
result_32 = (op1_32 << count) | (op2_32 >> (32 - count));
write_RMW_virtual_dword(result_32);
SET_FLAGS_OSZAPC_LOGIC_32(result_32);
cf = (op1_32 >> (32 - count)) & 0x1;
of = cf ^ (result_32 >> 31); // of = cf ^ result31
SET_FLAGS_OxxxxC(of, cf);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SHLD_EdGdR(bxInstruction_c *i)
{
Bit32u op1_32, op2_32, result_32;
unsigned count;
unsigned of, cf;
if (i->b1() == 0xa4) // 0x1a4
count = i->Ib();
else // 0x1a5
count = CL;
count &= 0x1f; // use only 5 LSB's
if (!count) {
BX_CLEAR_64BIT_HIGH(i->rm()); // always clear upper part of the register
return;
}
op1_32 = BX_READ_32BIT_REG(i->rm());
op2_32 = BX_READ_32BIT_REG(i->nnn());
result_32 = (op1_32 << count) | (op2_32 >> (32 - count));
BX_WRITE_32BIT_REGZ(i->rm(), result_32);
SET_FLAGS_OSZAPC_LOGIC_32(result_32);
cf = (op1_32 >> (32 - count)) & 0x1;
of = cf ^ (result_32 >> 31); // of = cf ^ result31
SET_FLAGS_OxxxxC(of, cf);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SHRD_EdGdM(bxInstruction_c *i)
{
Bit32u op1_32, op2_32, result_32;
unsigned count;
unsigned cf, of;
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
/* pointer, segment address pair */
op1_32 = read_RMW_virtual_dword(i->seg(), eaddr);
if (i->b1() == 0xac) // 0x1ac
count = i->Ib();
else // 0x1ad
count = CL;
count &= 0x1f; // use only 5 LSB's
if (!count) return;
op2_32 = BX_READ_32BIT_REG(i->nnn());
result_32 = (op2_32 << (32 - count)) | (op1_32 >> count);
write_RMW_virtual_dword(result_32);
SET_FLAGS_OSZAPC_LOGIC_32(result_32);
cf = (op1_32 >> (count - 1)) & 0x1;
of = ((result_32 << 1) ^ result_32) >> 31; // of = result30 ^ result31
SET_FLAGS_OxxxxC(of, cf);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SHRD_EdGdR(bxInstruction_c *i)
{
Bit32u op1_32, op2_32, result_32;
unsigned count;
unsigned cf, of;
if (i->b1() == 0xac) // 0x1ac
count = i->Ib();
else // 0x1ad
count = CL;
count &= 0x1f; // use only 5 LSB's
if (!count) {
BX_CLEAR_64BIT_HIGH(i->rm()); // always clear upper part of the register
return;
}
op1_32 = BX_READ_32BIT_REG(i->rm());
op2_32 = BX_READ_32BIT_REG(i->nnn());
result_32 = (op2_32 << (32 - count)) | (op1_32 >> count);
BX_WRITE_32BIT_REGZ(i->rm(), result_32);
SET_FLAGS_OSZAPC_LOGIC_32(result_32);
cf = (op1_32 >> (count - 1)) & 0x1;
of = ((result_32 << 1) ^ result_32) >> 31; // of = result30 ^ result31
SET_FLAGS_OxxxxC(of, cf);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::ROL_EdM(bxInstruction_c *i)
{
Bit32u op1_32, result_32;
unsigned count;
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
/* pointer, segment address pair */
op1_32 = read_RMW_virtual_dword(i->seg(), eaddr);
if (i->b1() == 0xd3)
count = CL;
else // 0xc1 or 0xd1
count = i->Ib();
count &= 0x1f;
if (! count) return;
result_32 = (op1_32 << count) | (op1_32 >> (32 - count));
write_RMW_virtual_dword(result_32);
unsigned bit0 = (result_32 & 0x1);
unsigned bit31 = (result_32 >> 31);
// of = cf ^ result31
SET_FLAGS_OxxxxC(bit0 ^ bit31, bit0);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::ROL_EdR(bxInstruction_c *i)
{
Bit32u op1_32, result_32;
unsigned count;
unsigned bit0, bit31;
if (i->b1() == 0xd3)
count = CL;
else // 0xc1 or 0xd1
count = i->Ib();
count &= 0x1f;
if (!count) {
BX_CLEAR_64BIT_HIGH(i->rm()); // always clear upper part of the register
return;
}
op1_32 = BX_READ_32BIT_REG(i->rm());
result_32 = (op1_32 << count) | (op1_32 >> (32 - count));
BX_WRITE_32BIT_REGZ(i->rm(), result_32);
bit0 = (result_32 & 0x1);
bit31 = (result_32 >> 31);
// of = cf ^ result31
SET_FLAGS_OxxxxC(bit0 ^ bit31, bit0);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::ROR_EdM(bxInstruction_c *i)
{
Bit32u op1_32, result_32;
unsigned count;
unsigned bit31, bit30;
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
/* pointer, segment address pair */
op1_32 = read_RMW_virtual_dword(i->seg(), eaddr);
if (i->b1() == 0xd3)
count = CL;
else // 0xc1 or 0xd1
count = i->Ib();
count &= 0x1f;
if (! count) return;
result_32 = (op1_32 >> count) | (op1_32 << (32 - count));
write_RMW_virtual_dword(result_32);
bit31 = (result_32 >> 31) & 1;
bit30 = (result_32 >> 30) & 1;
// of = result30 ^ result31
SET_FLAGS_OxxxxC(bit30 ^ bit31, bit31);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::ROR_EdR(bxInstruction_c *i)
{
Bit32u op1_32, result_32;
unsigned count;
unsigned bit31, bit30;
if (i->b1() == 0xd3)
count = CL;
else // 0xc1 or 0xd1
count = i->Ib();
count &= 0x1f;
if (!count) {
BX_CLEAR_64BIT_HIGH(i->rm()); // always clear upper part of the register
return;
}
op1_32 = BX_READ_32BIT_REG(i->rm());
result_32 = (op1_32 >> count) | (op1_32 << (32 - count));
BX_WRITE_32BIT_REGZ(i->rm(), result_32);
bit31 = (result_32 >> 31) & 1;
bit30 = (result_32 >> 30) & 1;
// of = result30 ^ result31
SET_FLAGS_OxxxxC(bit30 ^ bit31, bit31);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::RCL_EdM(bxInstruction_c *i)
{
Bit32u op1_32, result_32;
unsigned count;
unsigned cf, of;
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
/* pointer, segment address pair */
op1_32 = read_RMW_virtual_dword(i->seg(), eaddr);
if (i->b1() == 0xd3)
count = CL;
else // 0xc1 or 0xd1
count = i->Ib();
count &= 0x1f;
if (!count) return;
if (count==1) {
result_32 = (op1_32 << 1) | getB_CF();
}
else {
result_32 = (op1_32 << count) | (getB_CF() << (count - 1)) |
(op1_32 >> (33 - count));
}
write_RMW_virtual_dword(result_32);
cf = (op1_32 >> (32 - count)) & 0x1;
of = cf ^ (result_32 >> 31); // of = cf ^ result31
SET_FLAGS_OxxxxC(of, cf);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::RCL_EdR(bxInstruction_c *i)
{
Bit32u op1_32, result_32;
unsigned count;
unsigned cf, of;
if (i->b1() == 0xd3)
count = CL;
else // 0xc1 or 0xd1
count = i->Ib();
count &= 0x1f;
if (!count) {
BX_CLEAR_64BIT_HIGH(i->rm()); // always clear upper part of the register
return;
}
op1_32 = BX_READ_32BIT_REG(i->rm());
if (count==1) {
result_32 = (op1_32 << 1) | getB_CF();
}
else {
result_32 = (op1_32 << count) | (getB_CF() << (count - 1)) |
(op1_32 >> (33 - count));
}
BX_WRITE_32BIT_REGZ(i->rm(), result_32);
cf = (op1_32 >> (32 - count)) & 0x1;
of = cf ^ (result_32 >> 31); // of = cf ^ result31
SET_FLAGS_OxxxxC(of, cf);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::RCR_EdM(bxInstruction_c *i)
{
Bit32u op1_32, result_32;
unsigned count;
unsigned cf, of;
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
/* pointer, segment address pair */
op1_32 = read_RMW_virtual_dword(i->seg(), eaddr);
if (i->b1() == 0xd3)
count = CL;
else // 0xc1 or 0xd1
count = i->Ib();
count &= 0x1f;
if (!count) return;
if (count==1) {
result_32 = (op1_32 >> 1) | (getB_CF() << 31);
}
else {
result_32 = (op1_32 >> count) | (getB_CF() << (32 - count)) |
(op1_32 << (33 - count));
}
write_RMW_virtual_dword(result_32);
cf = (op1_32 >> (count - 1)) & 0x1;
of = ((result_32 << 1) ^ result_32) >> 31; // of = result30 ^ result31
SET_FLAGS_OxxxxC(of, cf);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::RCR_EdR(bxInstruction_c *i)
{
Bit32u op1_32, result_32;
unsigned count;
unsigned cf, of;
if (i->b1() == 0xd3)
count = CL;
else // 0xc1 or 0xd1
count = i->Ib();
count &= 0x1f;
if (!count) {
BX_CLEAR_64BIT_HIGH(i->rm()); // always clear upper part of the register
return;
}
op1_32 = BX_READ_32BIT_REG(i->rm());
if (count==1) {
result_32 = (op1_32 >> 1) | (getB_CF() << 31);
}
else {
result_32 = (op1_32 >> count) | (getB_CF() << (32 - count)) |
(op1_32 << (33 - count));
}
BX_WRITE_32BIT_REGZ(i->rm(), result_32);
cf = (op1_32 >> (count - 1)) & 0x1;
of = ((result_32 << 1) ^ result_32) >> 31; // of = result30 ^ result31
SET_FLAGS_OxxxxC(of, cf);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SHL_EdM(bxInstruction_c *i)
{
Bit32u op1_32, result_32;
unsigned count;
unsigned cf, of;
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
/* pointer, segment address pair */
op1_32 = read_RMW_virtual_dword(i->seg(), eaddr);
if (i->b1() == 0xd3)
count = CL;
else // 0xc1 or 0xd1
count = i->Ib();
count &= 0x1f;
if (!count) return;
/* count < 32, since only lower 5 bits used */
result_32 = (op1_32 << count);
write_RMW_virtual_dword(result_32);
cf = (op1_32 >> (32 - count)) & 0x1;
of = cf ^ (result_32 >> 31);
SET_FLAGS_OSZAPC_LOGIC_32(result_32);
SET_FLAGS_OxxxxC(of, cf);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SHL_EdR(bxInstruction_c *i)
{
Bit32u op1_32, result_32;
unsigned count;
unsigned cf, of;
if (i->b1() == 0xd3)
count = CL;
else // 0xc1 or 0xd1
count = i->Ib();
count &= 0x1f;
if (!count) {
BX_CLEAR_64BIT_HIGH(i->rm()); // always clear upper part of the register
return;
}
op1_32 = BX_READ_32BIT_REG(i->rm());
/* count < 32, since only lower 5 bits used */
result_32 = (op1_32 << count);
cf = (op1_32 >> (32 - count)) & 0x1;
of = cf ^ (result_32 >> 31);
BX_WRITE_32BIT_REGZ(i->rm(), result_32);
SET_FLAGS_OSZAPC_LOGIC_32(result_32);
SET_FLAGS_OxxxxC(of, cf);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SHR_EdM(bxInstruction_c *i)
{
Bit32u op1_32, result_32;
unsigned count;
unsigned of, cf;
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
/* pointer, segment address pair */
op1_32 = read_RMW_virtual_dword(i->seg(), eaddr);
if (i->b1() == 0xd3)
count = CL;
else // 0xc1 or 0xd1
count = i->Ib();
count &= 0x1f;
if (!count) return;
result_32 = (op1_32 >> count);
write_RMW_virtual_dword(result_32);
cf = (op1_32 >> (count - 1)) & 0x1;
// note, that of == result31 if count == 1 and
// of == 0 if count >= 2
of = ((result_32 << 1) ^ result_32) >> 31;
SET_FLAGS_OSZAPC_LOGIC_32(result_32);
SET_FLAGS_OxxxxC(of, cf);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SHR_EdR(bxInstruction_c *i)
{
Bit32u op1_32, result_32;
unsigned count;
unsigned of, cf;
if (i->b1() == 0xd3)
count = CL;
else // 0xc1 or 0xd1
count = i->Ib();
count &= 0x1f;
if (!count) {
BX_CLEAR_64BIT_HIGH(i->rm()); // always clear upper part of the register
return;
}
op1_32 = BX_READ_32BIT_REG(i->rm());
result_32 = (op1_32 >> count);
BX_WRITE_32BIT_REGZ(i->rm(), result_32);
cf = (op1_32 >> (count - 1)) & 0x1;
// note, that of == result31 if count == 1 and
// of == 0 if count >= 2
of = ((result_32 << 1) ^ result_32) >> 31;
SET_FLAGS_OSZAPC_LOGIC_32(result_32);
SET_FLAGS_OxxxxC(of, cf);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SAR_EdM(bxInstruction_c *i)
{
Bit32u op1_32, result_32;
unsigned count;
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
/* pointer, segment address pair */
op1_32 = read_RMW_virtual_dword(i->seg(), eaddr);
if (i->b1() == 0xd3)
count = CL;
else // 0xc1 or 0xd1
count = i->Ib();
count &= 0x1f;
if (!count) return;
/* count < 32, since only lower 5 bits used */
result_32 = ((Bit32s) op1_32) >> count;
write_RMW_virtual_dword(result_32);
SET_FLAGS_OSZAPC_LOGIC_32(result_32);
set_CF((op1_32 >> (count - 1)) & 1);
clear_OF(); /* signed overflow cannot happen in SAR instruction */
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SAR_EdR(bxInstruction_c *i)
{
Bit32u op1_32, result_32;
unsigned count;
if (i->b1() == 0xd3)
count = CL;
else // 0xc1 or 0xd1
count = i->Ib();
count &= 0x1f;
if (!count) {
BX_CLEAR_64BIT_HIGH(i->rm()); // always clear upper part of the register
return;
}
op1_32 = BX_READ_32BIT_REG(i->rm());
/* count < 32, since only lower 5 bits used */
result_32 = ((Bit32s) op1_32) >> count;
BX_WRITE_32BIT_REGZ(i->rm(), result_32);
SET_FLAGS_OSZAPC_LOGIC_32(result_32);
set_CF((op1_32 >> (count - 1)) & 1);
clear_OF(); /* signed overflow cannot happen in SAR instruction */
}

View File

@ -0,0 +1,552 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2001-2010 The Bochs Project
//
// 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
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA B 02110-1301 USA
/////////////////////////////////////////////////////////////////////////
#define NEED_CPU_REG_SHORTCUTS 1
#include "bochs.h"
#include "cpu.h"
#define LOG_THIS BX_CPU_THIS_PTR
#if BX_SUPPORT_X86_64
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SHLD_EqGqM(bxInstruction_c *i)
{
Bit64u op1_64, op2_64, result_64;
unsigned count;
unsigned cf, of;
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
/* pointer, segment address pair */
op1_64 = read_RMW_virtual_qword_64(i->seg(), eaddr);
if (i->b1() == 0xa4) // 0x1a4
count = i->Ib();
else // 0x1a5
count = CL;
count &= 0x3f; // use only 6 LSB's
if (!count) return;
op2_64 = BX_READ_64BIT_REG(i->nnn());
result_64 = (op1_64 << count) | (op2_64 >> (64 - count));
write_RMW_virtual_qword(result_64);
SET_FLAGS_OSZAPC_LOGIC_64(result_64);
cf = (op1_64 >> (64 - count)) & 0x1;
of = cf ^ (result_64 >> 63); // of = cf ^ result63
SET_FLAGS_OxxxxC(of, cf);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SHLD_EqGqR(bxInstruction_c *i)
{
Bit64u op1_64, op2_64, result_64;
unsigned count;
unsigned cf, of;
if (i->b1() == 0xa4) // 0x1a4
count = i->Ib();
else // 0x1a5
count = CL;
count &= 0x3f; // use only 6 LSB's
if (!count) return;
op1_64 = BX_READ_64BIT_REG(i->rm());
op2_64 = BX_READ_64BIT_REG(i->nnn());
result_64 = (op1_64 << count) | (op2_64 >> (64 - count));
BX_WRITE_64BIT_REG(i->rm(), result_64);
SET_FLAGS_OSZAPC_LOGIC_64(result_64);
cf = (op1_64 >> (64 - count)) & 0x1;
of = cf ^ (result_64 >> 63); // of = cf ^ result63
SET_FLAGS_OxxxxC(of, cf);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SHRD_EqGqM(bxInstruction_c *i)
{
Bit64u op1_64, op2_64, result_64;
unsigned count;
unsigned cf, of;
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
/* pointer, segment address pair */
op1_64 = read_RMW_virtual_qword_64(i->seg(), eaddr);
if (i->b1() == 0xac) // 0x1ac
count = i->Ib();
else // 0x1ad
count = CL;
count &= 0x3f; // use only 6 LSB's
if (!count) return;
op2_64 = BX_READ_64BIT_REG(i->nnn());
result_64 = (op2_64 << (64 - count)) | (op1_64 >> count);
write_RMW_virtual_qword(result_64);
SET_FLAGS_OSZAPC_LOGIC_64(result_64);
cf = (op1_64 >> (count - 1)) & 0x1;
of = ((result_64 << 1) ^ result_64) >> 63; // of = result62 ^ result63
SET_FLAGS_OxxxxC(of, cf);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SHRD_EqGqR(bxInstruction_c *i)
{
Bit64u op1_64, op2_64, result_64;
unsigned count;
unsigned cf, of;
if (i->b1() == 0xac) // 0x1ac
count = i->Ib();
else // 0x1ad
count = CL;
count &= 0x3f; // use only 6 LSB's
if (!count) return;
op1_64 = BX_READ_64BIT_REG(i->rm());
op2_64 = BX_READ_64BIT_REG(i->nnn());
result_64 = (op2_64 << (64 - count)) | (op1_64 >> count);
BX_WRITE_64BIT_REG(i->rm(), result_64);
SET_FLAGS_OSZAPC_LOGIC_64(result_64);
cf = (op1_64 >> (count - 1)) & 0x1;
of = ((result_64 << 1) ^ result_64) >> 63; // of = result62 ^ result63
SET_FLAGS_OxxxxC(of, cf);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::ROL_EqM(bxInstruction_c *i)
{
Bit64u op1_64, result_64;
unsigned count;
unsigned bit0, bit63;
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
/* pointer, segment address pair */
op1_64 = read_RMW_virtual_qword_64(i->seg(), eaddr);
if (i->b1() == 0xd3)
count = CL;
else // 0xc1 or 0xd1
count = i->Ib();
count &= 0x3f;
if (! count) return;
result_64 = (op1_64 << count) | (op1_64 >> (64 - count));
write_RMW_virtual_qword(result_64);
bit0 = (result_64 & 0x1);
bit63 = (result_64 >> 63);
// of = cf ^ result63
SET_FLAGS_OxxxxC(bit0 ^ bit63, bit0);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::ROL_EqR(bxInstruction_c *i)
{
Bit64u op1_64, result_64;
unsigned count;
unsigned bit0, bit63;
if (i->b1() == 0xd3)
count = CL;
else // 0xc1 or 0xd1
count = i->Ib();
count &= 0x3f;
if (! count) return;
op1_64 = BX_READ_64BIT_REG(i->rm());
result_64 = (op1_64 << count) | (op1_64 >> (64 - count));
BX_WRITE_64BIT_REG(i->rm(), result_64);
bit0 = (result_64 & 0x1);
bit63 = (result_64 >> 63);
// of = cf ^ result63
SET_FLAGS_OxxxxC(bit0 ^ bit63, bit0);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::ROR_EqM(bxInstruction_c *i)
{
Bit64u op1_64, result_64;
unsigned count;
unsigned bit62, bit63;
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
/* pointer, segment address pair */
op1_64 = read_RMW_virtual_qword_64(i->seg(), eaddr);
if (i->b1() == 0xd3)
count = CL;
else // 0xc1 or 0xd1
count = i->Ib();
count &= 0x3f;
if (! count) return;
result_64 = (op1_64 >> count) | (op1_64 << (64 - count));
write_RMW_virtual_qword(result_64);
bit63 = (result_64 >> 63) & 1;
bit62 = (result_64 >> 62) & 1;
// of = result62 ^ result63
SET_FLAGS_OxxxxC(bit62 ^ bit63, bit63);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::ROR_EqR(bxInstruction_c *i)
{
Bit64u op1_64, result_64;
unsigned count;
unsigned bit62, bit63;
if (i->b1() == 0xd3)
count = CL;
else // 0xc1 or 0xd1
count = i->Ib();
count &= 0x3f;
if (! count) return;
op1_64 = BX_READ_64BIT_REG(i->rm());
result_64 = (op1_64 >> count) | (op1_64 << (64 - count));
BX_WRITE_64BIT_REG(i->rm(), result_64);
bit63 = (result_64 >> 63) & 1;
bit62 = (result_64 >> 62) & 1;
// of = result62 ^ result63
SET_FLAGS_OxxxxC(bit62 ^ bit63, bit63);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::RCL_EqM(bxInstruction_c *i)
{
Bit64u op1_64, result_64;
unsigned count;
unsigned cf, of;
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
/* pointer, segment address pair */
op1_64 = read_RMW_virtual_qword_64(i->seg(), eaddr);
if (i->b1() == 0xd3)
count = CL;
else // 0xc1 or 0xd1
count = i->Ib();
count &= 0x3f;
if (!count) return;
if (count==1) {
result_64 = (op1_64 << 1) | getB_CF();
}
else {
result_64 = (op1_64 << count) | (getB_CF() << (count - 1)) |
(op1_64 >> (65 - count));
}
write_RMW_virtual_qword(result_64);
cf = (op1_64 >> (64 - count)) & 0x1;
of = cf ^ (result_64 >> 63); // of = cf ^ result63
SET_FLAGS_OxxxxC(of, cf);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::RCL_EqR(bxInstruction_c *i)
{
Bit64u op1_64, result_64;
unsigned count;
unsigned cf, of;
if (i->b1() == 0xd3)
count = CL;
else // 0xc1 or 0xd1
count = i->Ib();
count &= 0x3f;
if (!count) return;
op1_64 = BX_READ_64BIT_REG(i->rm());
if (count==1) {
result_64 = (op1_64 << 1) | getB_CF();
}
else {
result_64 = (op1_64 << count) | (getB_CF() << (count - 1)) |
(op1_64 >> (65 - count));
}
BX_WRITE_64BIT_REG(i->rm(), result_64);
cf = (op1_64 >> (64 - count)) & 0x1;
of = cf ^ (result_64 >> 63); // of = cf ^ result63
SET_FLAGS_OxxxxC(of, cf);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::RCR_EqM(bxInstruction_c *i)
{
Bit64u op1_64, result_64;
unsigned count;
unsigned of, cf;
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
/* pointer, segment address pair */
op1_64 = read_RMW_virtual_qword_64(i->seg(), eaddr);
if (i->b1() == 0xd3)
count = CL;
else // 0xc1 or 0xd1
count = i->Ib();
count &= 0x3f;
if (!count) return;
if (count==1) {
result_64 = (op1_64 >> 1) | (((Bit64u) getB_CF()) << 63);
}
else {
result_64 = (op1_64 >> count) | (getB_CF() << (64 - count)) |
(op1_64 << (65 - count));
}
write_RMW_virtual_qword(result_64);
cf = (op1_64 >> (count - 1)) & 0x1;
of = ((result_64 << 1) ^ result_64) >> 63;
SET_FLAGS_OxxxxC(of, cf);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::RCR_EqR(bxInstruction_c *i)
{
Bit64u op1_64, result_64;
unsigned count;
unsigned of, cf;
if (i->b1() == 0xd3)
count = CL;
else // 0xc1 or 0xd1
count = i->Ib();
count &= 0x3f;
if (!count) return;
op1_64 = BX_READ_64BIT_REG(i->rm());
if (count==1) {
result_64 = (op1_64 >> 1) | (((Bit64u) getB_CF()) << 63);
}
else {
result_64 = (op1_64 >> count) | (getB_CF() << (64 - count)) |
(op1_64 << (65 - count));
}
BX_WRITE_64BIT_REG(i->rm(), result_64);
cf = (op1_64 >> (count - 1)) & 0x1;
of = ((result_64 << 1) ^ result_64) >> 63;
SET_FLAGS_OxxxxC(of, cf);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SHL_EqM(bxInstruction_c *i)
{
Bit64u op1_64, result_64;
unsigned count;
unsigned cf, of;
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
/* pointer, segment address pair */
op1_64 = read_RMW_virtual_qword_64(i->seg(), eaddr);
if (i->b1() == 0xd3)
count = CL;
else // 0xc1 or 0xd1
count = i->Ib();
count &= 0x3f;
if (!count) return;
/* count < 64, since only lower 6 bits used */
result_64 = (op1_64 << count);
cf = (op1_64 >> (64 - count)) & 0x1;
of = cf ^ (result_64 >> 63);
write_RMW_virtual_qword(result_64);
SET_FLAGS_OSZAPC_LOGIC_64(result_64);
SET_FLAGS_OxxxxC(of, cf);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SHL_EqR(bxInstruction_c *i)
{
Bit64u op1_64, result_64;
unsigned count;
unsigned cf, of;
if (i->b1() == 0xd3)
count = CL;
else // 0xc1 or 0xd1
count = i->Ib();
count &= 0x3f;
if (!count) return;
op1_64 = BX_READ_64BIT_REG(i->rm());
/* count < 64, since only lower 6 bits used */
result_64 = (op1_64 << count);
BX_WRITE_64BIT_REG(i->rm(), result_64);
cf = (op1_64 >> (64 - count)) & 0x1;
of = cf ^ (result_64 >> 63);
SET_FLAGS_OSZAPC_LOGIC_64(result_64);
SET_FLAGS_OxxxxC(of, cf);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SHR_EqM(bxInstruction_c *i)
{
Bit64u op1_64, result_64;
unsigned count;
unsigned cf, of;
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
/* pointer, segment address pair */
op1_64 = read_RMW_virtual_qword_64(i->seg(), eaddr);
if (i->b1() == 0xd3)
count = CL;
else // 0xc1 or 0xd1
count = i->Ib();
count &= 0x3f;
if (!count) return;
result_64 = (op1_64 >> count);
write_RMW_virtual_qword(result_64);
cf = (op1_64 >> (count - 1)) & 0x1;
// note, that of == result63 if count == 1 and
// of == 0 if count >= 2
of = ((result_64 << 1) ^ result_64) >> 63;
SET_FLAGS_OSZAPC_LOGIC_64(result_64);
SET_FLAGS_OxxxxC(of, cf);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SHR_EqR(bxInstruction_c *i)
{
Bit64u op1_64, result_64;
unsigned count;
unsigned cf, of;
if (i->b1() == 0xd3)
count = CL;
else // 0xc1 or 0xd1
count = i->Ib();
count &= 0x3f;
if (!count) return;
op1_64 = BX_READ_64BIT_REG(i->rm());
result_64 = (op1_64 >> count);
BX_WRITE_64BIT_REG(i->rm(), result_64);
cf = (op1_64 >> (count - 1)) & 0x1;
// note, that of == result63 if count == 1 and
// of == 0 if count >= 2
of = ((result_64 << 1) ^ result_64) >> 63;
SET_FLAGS_OSZAPC_LOGIC_64(result_64);
SET_FLAGS_OxxxxC(of, cf);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SAR_EqM(bxInstruction_c *i)
{
Bit64u op1_64, result_64;
unsigned count;
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
/* pointer, segment address pair */
op1_64 = read_RMW_virtual_qword_64(i->seg(), eaddr);
if (i->b1() == 0xd3)
count = CL;
else // 0xc1 or 0xd1
count = i->Ib();
count &= 0x3f;
if (!count) return;
/* count < 64, since only lower 6 bits used */
result_64 = ((Bit64s) op1_64) >> count;
write_RMW_virtual_qword(result_64);
SET_FLAGS_OSZAPC_LOGIC_64(result_64);
set_CF((op1_64 >> (count - 1)) & 1);
clear_OF(); /* signed overflow cannot happen in SAR instruction */
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SAR_EqR(bxInstruction_c *i)
{
Bit64u op1_64, result_64;
unsigned count;
if (i->b1() == 0xd3)
count = CL;
else // 0xc1 or 0xd1
count = i->Ib();
count &= 0x3f;
if (!count) return;
op1_64 = BX_READ_64BIT_REG(i->rm());
/* count < 64, since only lower 6 bits used */
result_64 = ((Bit64s) op1_64) >> count;
BX_WRITE_64BIT_REG(i->rm(), result_64);
SET_FLAGS_OSZAPC_LOGIC_64(result_64);
set_CF((op1_64 >> (count - 1)) & 1);
clear_OF(); /* signed overflow cannot happen in SAR instruction */
}
#endif /* if BX_SUPPORT_X86_64 */

View File

@ -0,0 +1,469 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2001-2010 The Bochs Project
//
// 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
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA B 02110-1301 USA
/////////////////////////////////////////////////////////////////////////
#define NEED_CPU_REG_SHORTCUTS 1
#include "bochs.h"
#include "cpu.h"
#define LOG_THIS BX_CPU_THIS_PTR
void BX_CPP_AttrRegparmN(1) BX_CPU_C::ROL_EbR(bxInstruction_c *i)
{
unsigned count;
unsigned bit0, bit7;
if (i->b1() == 0xd2)
count = CL;
else // 0xc0 or 0xd0
count = i->Ib();
Bit8u op1_8 = BX_READ_8BIT_REGx(i->rm(), i->extend8bitL());
if ((count & 0x07) == 0) {
if (count & 0x18) {
bit0 = (op1_8 & 1);
bit7 = (op1_8 >> 7);
SET_FLAGS_OxxxxC(bit0 ^ bit7, bit0);
}
return;
}
count &= 0x7; // use only lowest 3 bits
Bit8u result_8 = (op1_8 << count) | (op1_8 >> (8 - count));
BX_WRITE_8BIT_REGx(i->rm(), i->extend8bitL(), result_8);
/* set eflags:
* ROL count affects the following flags: C, O
*/
bit0 = (result_8 & 1);
bit7 = (result_8 >> 7);
SET_FLAGS_OxxxxC(bit0 ^ bit7, bit0);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::ROL_EbM(bxInstruction_c *i)
{
unsigned count;
unsigned bit0, bit7;
if (i->b1() == 0xd2)
count = CL;
else // 0xc0 or 0xd0
count = i->Ib();
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
/* pointer, segment address pair */
Bit8u op1_8 = read_RMW_virtual_byte(i->seg(), eaddr);
if ((count & 0x07) == 0) {
if (count & 0x18) {
bit0 = (op1_8 & 1);
bit7 = (op1_8 >> 7);
SET_FLAGS_OxxxxC(bit0 ^ bit7, bit0);
}
return;
}
count &= 0x7; // use only lowest 3 bits
Bit8u result_8 = (op1_8 << count) | (op1_8 >> (8 - count));
write_RMW_virtual_byte(result_8);
/* set eflags:
* ROL count affects the following flags: C, O
*/
bit0 = (result_8 & 1);
bit7 = (result_8 >> 7);
SET_FLAGS_OxxxxC(bit0 ^ bit7, bit0);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::ROR_EbR(bxInstruction_c *i)
{
unsigned count;
unsigned bit6, bit7;
if (i->b1() == 0xd2)
count = CL;
else // 0xc0 or 0xd0
count = i->Ib();
Bit8u op1_8 = BX_READ_8BIT_REGx(i->rm(), i->extend8bitL());
if ((count & 0x07) == 0) {
if (count & 0x18) {
bit6 = (op1_8 >> 6) & 1;
bit7 = (op1_8 >> 7) & 1;
SET_FLAGS_OxxxxC(bit6 ^ bit7, bit7);
}
return;
}
count &= 0x7; /* use only bottom 3 bits */
Bit8u result_8 = (op1_8 >> count) | (op1_8 << (8 - count));
BX_WRITE_8BIT_REGx(i->rm(), i->extend8bitL(), result_8);
/* set eflags:
* ROR count affects the following flags: C, O
*/
bit6 = (result_8 >> 6) & 1;
bit7 = (result_8 >> 7) & 1;
SET_FLAGS_OxxxxC(bit6 ^ bit7, bit7);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::ROR_EbM(bxInstruction_c *i)
{
unsigned count;
unsigned bit6, bit7;
if (i->b1() == 0xd2)
count = CL;
else // 0xc0 or 0xd0
count = i->Ib();
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
/* pointer, segment address pair */
Bit8u op1_8 = read_RMW_virtual_byte(i->seg(), eaddr);
if ((count & 0x07) == 0) {
if (count & 0x18) {
bit6 = (op1_8 >> 6) & 1;
bit7 = (op1_8 >> 7) & 1;
SET_FLAGS_OxxxxC(bit6 ^ bit7, bit7);
}
return;
}
count &= 0x7; /* use only bottom 3 bits */
Bit8u result_8 = (op1_8 >> count) | (op1_8 << (8 - count));
write_RMW_virtual_byte(result_8);
/* set eflags:
* ROR count affects the following flags: C, O
*/
bit6 = (result_8 >> 6) & 1;
bit7 = (result_8 >> 7) & 1;
SET_FLAGS_OxxxxC(bit6 ^ bit7, bit7);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::RCL_EbR(bxInstruction_c *i)
{
Bit8u result_8;
unsigned count;
unsigned of, cf;
if (i->b1() == 0xd2)
count = CL;
else // 0xc0 or 0xd0
count = i->Ib();
count = (count & 0x1f) % 9;
if (! count) return;
Bit8u op1_8 = BX_READ_8BIT_REGx(i->rm(), i->extend8bitL());
if (count==1) {
result_8 = (op1_8 << 1) | getB_CF();
}
else {
result_8 = (op1_8 << count) | (getB_CF() << (count - 1)) |
(op1_8 >> (9 - count));
}
BX_WRITE_8BIT_REGx(i->rm(), i->extend8bitL(), result_8);
cf = (op1_8 >> (8 - count)) & 0x01;
of = cf ^ (result_8 >> 7); // of = cf ^ result7
SET_FLAGS_OxxxxC(of, cf);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::RCL_EbM(bxInstruction_c *i)
{
Bit8u result_8;
unsigned count;
unsigned of, cf;
if (i->b1() == 0xd2)
count = CL;
else // 0xc0 or 0xd0
count = i->Ib();
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
/* pointer, segment address pair */
Bit8u op1_8 = read_RMW_virtual_byte(i->seg(), eaddr);
count = (count & 0x1f) % 9;
if (! count) return;
if (count==1) {
result_8 = (op1_8 << 1) | getB_CF();
}
else {
result_8 = (op1_8 << count) | (getB_CF() << (count - 1)) |
(op1_8 >> (9 - count));
}
write_RMW_virtual_byte(result_8);
cf = (op1_8 >> (8 - count)) & 0x01;
of = cf ^ (result_8 >> 7); // of = cf ^ result7
SET_FLAGS_OxxxxC(of, cf);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::RCR_EbR(bxInstruction_c *i)
{
unsigned count;
unsigned cf, of;
if (i->b1() == 0xd2)
count = CL;
else // 0xc0 or 0xd0
count = i->Ib();
count = (count & 0x1f) % 9;
if (! count) return;
Bit8u op1_8 = BX_READ_8BIT_REGx(i->rm(), i->extend8bitL());
Bit8u result_8 = (op1_8 >> count) | (getB_CF() << (8 - count)) |
(op1_8 << (9 - count));
BX_WRITE_8BIT_REGx(i->rm(), i->extend8bitL(), result_8);
cf = (op1_8 >> (count - 1)) & 0x1;
of = (((result_8 << 1) ^ result_8) >> 7) & 0x1; // of = result6 ^ result7
SET_FLAGS_OxxxxC(of, cf);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::RCR_EbM(bxInstruction_c *i)
{
unsigned count;
unsigned cf, of;
if (i->b1() == 0xd2)
count = CL;
else // 0xc0 or 0xd0
count = i->Ib();
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
/* pointer, segment address pair */
Bit8u op1_8 = read_RMW_virtual_byte(i->seg(), eaddr);
count = (count & 0x1f) % 9;
if (! count) return;
Bit8u result_8 = (op1_8 >> count) | (getB_CF() << (8 - count)) |
(op1_8 << (9 - count));
write_RMW_virtual_byte(result_8);
cf = (op1_8 >> (count - 1)) & 0x1;
of = (((result_8 << 1) ^ result_8) >> 7) & 0x1; // of = result6 ^ result7
SET_FLAGS_OxxxxC(of, cf);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SHL_EbR(bxInstruction_c *i)
{
Bit8u result_8;
unsigned count;
unsigned of = 0, cf = 0;
if (i->b1() == 0xd2)
count = CL;
else // 0xc0 or 0xd0
count = i->Ib();
count &= 0x1f;
if (!count) return;
Bit8u op1_8 = BX_READ_8BIT_REGx(i->rm(), i->extend8bitL());
if (count <= 8) {
result_8 = (op1_8 << count);
cf = (op1_8 >> (8 - count)) & 0x1;
of = cf ^ (result_8 >> 7);
}
else {
result_8 = 0;
}
BX_WRITE_8BIT_REGx(i->rm(), i->extend8bitL(), result_8);
SET_FLAGS_OSZAPC_LOGIC_8(result_8);
SET_FLAGS_OxxxxC(of, cf);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SHL_EbM(bxInstruction_c *i)
{
Bit8u result_8;
unsigned count;
unsigned of = 0, cf = 0;
if (i->b1() == 0xd2)
count = CL;
else // 0xc0 or 0xd0
count = i->Ib();
count &= 0x1f;
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
/* pointer, segment address pair */
Bit8u op1_8 = read_RMW_virtual_byte(i->seg(), eaddr);
if (!count) return;
if (count <= 8) {
result_8 = (op1_8 << count);
cf = (op1_8 >> (8 - count)) & 0x1;
of = cf ^ (result_8 >> 7);
}
else {
result_8 = 0;
}
write_RMW_virtual_byte(result_8);
SET_FLAGS_OSZAPC_LOGIC_8(result_8);
SET_FLAGS_OxxxxC(of, cf);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SHR_EbR(bxInstruction_c *i)
{
unsigned count;
if (i->b1() == 0xd2)
count = CL;
else // 0xc0 or 0xd0
count = i->Ib();
count &= 0x1f;
if (!count) return;
Bit8u op1_8 = BX_READ_8BIT_REGx(i->rm(), i->extend8bitL());
Bit8u result_8 = (op1_8 >> count);
BX_WRITE_8BIT_REGx(i->rm(), i->extend8bitL(), result_8);
unsigned cf = (op1_8 >> (count - 1)) & 0x1;
// note, that of == result7 if count == 1 and
// of == 0 if count >= 2
unsigned of = (((result_8 << 1) ^ result_8) >> 7) & 0x1;
SET_FLAGS_OSZAPC_LOGIC_8(result_8);
SET_FLAGS_OxxxxC(of, cf);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SHR_EbM(bxInstruction_c *i)
{
unsigned count;
if (i->b1() == 0xd2)
count = CL;
else // 0xc0 or 0xd0
count = i->Ib();
count &= 0x1f;
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
/* pointer, segment address pair */
Bit8u op1_8 = read_RMW_virtual_byte(i->seg(), eaddr);
if (!count) return;
Bit8u result_8 = (op1_8 >> count);
write_RMW_virtual_byte(result_8);
unsigned cf = (op1_8 >> (count - 1)) & 0x1;
// note, that of == result7 if count == 1 and
// of == 0 if count >= 2
unsigned of = (((result_8 << 1) ^ result_8) >> 7) & 0x1;
SET_FLAGS_OSZAPC_LOGIC_8(result_8);
SET_FLAGS_OxxxxC(of, cf);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SAR_EbR(bxInstruction_c *i)
{
unsigned count;
if (i->b1() == 0xd2)
count = CL;
else // 0xc0 or 0xd0
count = i->Ib();
count &= 0x1f;
if (!count) return;
Bit8u op1_8 = BX_READ_8BIT_REGx(i->rm(), i->extend8bitL());
Bit8u result_8 = ((Bit8s) op1_8) >> count;
BX_WRITE_8BIT_REGx(i->rm(), i->extend8bitL(), result_8);
unsigned cf = (((Bit8s) op1_8) >> (count - 1)) & 0x1;
SET_FLAGS_OSZAPC_LOGIC_8(result_8);
/* signed overflow cannot happen in SAR instruction */
SET_FLAGS_OxxxxC(0, cf);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SAR_EbM(bxInstruction_c *i)
{
unsigned count;
if (i->b1() == 0xd2)
count = CL;
else // 0xc0 or 0xd0
count = i->Ib();
count &= 0x1f;
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
/* pointer, segment address pair */
Bit8u op1_8 = read_RMW_virtual_byte(i->seg(), eaddr);
if (!count) return;
Bit8u result_8 = ((Bit8s) op1_8) >> count;
write_RMW_virtual_byte(result_8);
unsigned cf = (((Bit8s) op1_8) >> (count - 1)) & 0x1;
SET_FLAGS_OSZAPC_LOGIC_8(result_8);
/* signed overflow cannot happen in SAR instruction */
SET_FLAGS_OxxxxC(0, cf);
}

874
simulators/bochs/cpu/smm.cc Executable file
View File

@ -0,0 +1,874 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2006-2009 Stanislav Shwartsman
// 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
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA B 02110-1301 USA
/////////////////////////////////////////////////////////////////////////
#define NEED_CPU_REG_SHORTCUTS 1
#include "bochs.h"
#include "cpu.h"
#include "smm.h"
#define LOG_THIS BX_CPU_THIS_PTR
#if BX_CPU_LEVEL >= 3
#if BX_SUPPORT_X86_64==0
#define RIP EIP
#endif
//
// Some of the CPU field must be saved and restored in order to continue the
// simulation correctly after the RSM instruction:
//
// ---------------------------------------------------------------
//
// 1. General purpose registers: EAX-EDI, R8-R15
// 2. EIP, RFLAGS
// 3. Segment registers CS, DS, SS, ES, FS, GS
// fields: valid - not required, initialized according to selector value
// p - must be saved/restored
// dpl - must be saved/restored
// segment - must be 1 for seg registers, not required to save
// type - must be saved/restored
// base - must be saved/restored
// limit - must be saved/restored
// g - must be saved/restored
// d_b - must be saved/restored
// l - must be saved/restored
// avl - must be saved/restored
// 4. GDTR, IDTR
// fields: base, limit
// 5. LDTR, TR
// fields: base, limit, anything else ?
// 6. Debug Registers DR0-DR7, only DR6 and DR7 are saved
// 7. Control Registers: CR0, CR1 is always 0, CR2 is NOT saved, CR3, CR4, EFER
// 8. SMBASE
// 9. MSR/FPU/XMM/APIC are NOT saved accoring to Intel docs
//
#define SMM_SAVE_STATE_MAP_SIZE 128
void BX_CPP_AttrRegparmN(1) BX_CPU_C::RSM(bxInstruction_c *i)
{
/* If we are not in System Management Mode, then #UD should be generated */
if (! BX_CPU_THIS_PTR smm_mode()) {
BX_INFO(("RSM not in System Management Mode !"));
exception(BX_UD_EXCEPTION, 0);
}
#if BX_SUPPORT_VMX
if (BX_CPU_THIS_PTR in_vmx) {
if (BX_CPU_THIS_PTR in_vmx_guest) {
BX_ERROR(("VMEXIT: RSM in VMX non-root operation"));
VMexit(i, VMX_VMEXIT_RSM, 0);
}
else {
BX_ERROR(("RSM in VMX root operation !"));
exception(BX_UD_EXCEPTION, 0);
}
}
#endif
invalidate_prefetch_q();
BX_INFO(("RSM: Resuming from System Management Mode"));
BX_CPU_THIS_PTR disable_NMI = 0;
Bit32u saved_state[SMM_SAVE_STATE_MAP_SIZE], n;
// reset reserved bits
for(n=0;n<SMM_SAVE_STATE_MAP_SIZE;n++) saved_state[n] = 0;
bx_phy_address base = BX_CPU_THIS_PTR smbase + 0x10000;
// could be optimized with reading of only non-reserved bytes
for(n=0;n<SMM_SAVE_STATE_MAP_SIZE;n++) {
base -= 4;
access_read_physical(base, 4, &saved_state[n]);
BX_DBG_PHY_MEMORY_ACCESS(BX_CPU_ID, base, 4, BX_SMRAM_ACCESS | BX_READ, (Bit8u*)(&saved_state[n]));
}
BX_CPU_THIS_PTR in_smm = 0;
// restore the CPU state from SMRAM
if (! smram_restore_state(saved_state)) {
BX_PANIC(("RSM: Incorrect state when restoring CPU state - shutdown !"));
shutdown();
}
// debug(RIP);
}
void BX_CPU_C::enter_system_management_mode(void)
{
invalidate_prefetch_q();
BX_INFO(("Enter to System Management Mode"));
// debug(BX_CPU_THIS_PTR prev_rip);
//
// Processors that support VMX operation perform SMI delivery as follows:
//
#if BX_SUPPORT_VMX
// Enter SMM
// save the following internal to the processor:
// * CR4.VMXE
// * an indication of whether the logical processor was in VMX operation (root or non-root)
// IF the logical processor is in VMX operation
// THEN
// leave VMX operation;
// save VMX-critical state defined below;
// preserve current VMCS pointer as noted below;
// FI;
// CR4.VMXE = 0;
BX_CPU_THIS_PTR cr4.set_VMXE(0);
BX_CPU_THIS_PTR in_smm_vmx = BX_CPU_THIS_PTR in_vmx;
BX_CPU_THIS_PTR in_smm_vmx_guest = BX_CPU_THIS_PTR in_vmx_guest;
BX_CPU_THIS_PTR in_vmx = 0;
BX_CPU_THIS_PTR in_vmx_guest = 0;
BX_INFO(("enter_system_management_mode: temporary disable VMX while in SMM mode"));
// perform ordinary SMI delivery:
// * save processor state in SMRAM;
// * set processor state to standard SMM values
#endif
BX_CPU_THIS_PTR in_smm = 1;
BX_CPU_THIS_PTR disable_NMI = 1;
Bit32u saved_state[SMM_SAVE_STATE_MAP_SIZE], n;
// reset reserved bits
for(n=0;n<SMM_SAVE_STATE_MAP_SIZE;n++) saved_state[n] = 0;
// prepare CPU state to be saved in the SMRAM
smram_save_state(saved_state);
bx_phy_address base = BX_CPU_THIS_PTR smbase + 0x10000;
// could be optimized with reading of only non-reserved bytes
for(n=0;n<SMM_SAVE_STATE_MAP_SIZE;n++) {
base -= 4;
access_write_physical(base, 4, &saved_state[n]);
BX_DBG_PHY_MEMORY_ACCESS(BX_CPU_ID, base, 4, BX_SMRAM_ACCESS | BX_WRITE, (Bit8u*)(&saved_state[n]));
}
BX_CPU_THIS_PTR setEFlags(0x2); // Bit1 is always set
BX_CPU_THIS_PTR prev_rip = RIP = 0x00008000;
BX_CPU_THIS_PTR dr7 = 0x00000400;
// CR0 - PE, EM, TS, and PG flags set to 0; others unmodified
BX_CPU_THIS_PTR cr0.set_PE(0); // real mode (bit 0)
BX_CPU_THIS_PTR cr0.set_EM(0); // emulate math coprocessor (bit 2)
BX_CPU_THIS_PTR cr0.set_TS(0); // no task switch (bit 3)
BX_CPU_THIS_PTR cr0.set_PG(0); // paging disabled (bit 31)
#if BX_CPU_LEVEL >= 4
BX_CPU_THIS_PTR cr4.set32(0);
#endif
// paging mode was changed - flush TLB
TLB_flush(); // Flush Global entries also
#if BX_SUPPORT_X86_64
BX_CPU_THIS_PTR efer.set32(0);
#endif
parse_selector(BX_CPU_THIS_PTR smbase >> 4,
&BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector);
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.valid = SegValidCache | SegAccessROK | SegAccessWOK;
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.p = 1;
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.dpl = 0;
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.segment = 1; /* data/code segment */
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.type = BX_DATA_READ_WRITE_ACCESSED;
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.base = BX_CPU_THIS_PTR smbase;
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.limit_scaled = 0xffffffff;
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.avl = 0;
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.g = 1; /* page granular */
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.d_b = 0; /* 16bit default size */
#if BX_SUPPORT_X86_64
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.l = 0; /* 16bit default size */
#endif
handleCpuModeChange();
#if BX_CPU_LEVEL >= 4 && BX_SUPPORT_ALIGNMENT_CHECK
handleAlignmentCheck();
#endif
#if BX_CPU_LEVEL >= 6
handleSseModeChange();
#endif
/* DS (Data Segment) and descriptor cache */
parse_selector(0x0000,
&BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS].selector);
BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS].cache.valid = SegValidCache | SegAccessROK | SegAccessWOK;
BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS].cache.p = 1;
BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS].cache.dpl = 0;
BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS].cache.segment = 1; /* data/code segment */
BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS].cache.type = BX_DATA_READ_WRITE_ACCESSED;
BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS].cache.u.segment.base = 0x00000000;
BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS].cache.u.segment.limit_scaled = 0xffffffff;
BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS].cache.u.segment.avl = 0;
BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS].cache.u.segment.g = 1; /* byte granular */
BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS].cache.u.segment.d_b = 0; /* 16bit default size */
#if BX_SUPPORT_X86_64
BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS].cache.u.segment.l = 0; /* 16bit default size */
#endif
// use DS segment as template for the others
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS] = BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS];
BX_CPU_THIS_PTR sregs[BX_SEG_REG_ES] = BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS];
BX_CPU_THIS_PTR sregs[BX_SEG_REG_FS] = BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS];
BX_CPU_THIS_PTR sregs[BX_SEG_REG_GS] = BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS];
}
#define SMRAM_TRANSLATE(addr) (((0x8000 - (addr)) >> 2) - 1)
// SMRAM SMM_SAVE_STATE_MAP_SIZE is 128 elements, find the element for each field
static unsigned smram_map[SMRAM_FIELD_LAST];
#if BX_SUPPORT_X86_64
void BX_CPU_C::init_SMRAM(void)
{
static bx_bool smram_map_ready = 0;
if (smram_map_ready) return;
smram_map_ready = 1;
smram_map[SMRAM_FIELD_SMBASE_OFFSET] = SMRAM_TRANSLATE(0x7f00);
smram_map[SMRAM_FIELD_SMM_REVISION_ID] = SMRAM_TRANSLATE(0x7efc);
smram_map[SMRAM_FIELD_RAX_HI32] = SMRAM_TRANSLATE(0x7ffc);
smram_map[SMRAM_FIELD_EAX] = SMRAM_TRANSLATE(0x7ff8);
smram_map[SMRAM_FIELD_RCX_HI32] = SMRAM_TRANSLATE(0x7ff4);
smram_map[SMRAM_FIELD_ECX] = SMRAM_TRANSLATE(0x7ff0);
smram_map[SMRAM_FIELD_RDX_HI32] = SMRAM_TRANSLATE(0x7fec);
smram_map[SMRAM_FIELD_EDX] = SMRAM_TRANSLATE(0x7fe8);
smram_map[SMRAM_FIELD_RBX_HI32] = SMRAM_TRANSLATE(0x7fe4);
smram_map[SMRAM_FIELD_EBX] = SMRAM_TRANSLATE(0x7fe0);
smram_map[SMRAM_FIELD_RSP_HI32] = SMRAM_TRANSLATE(0x7fdc);
smram_map[SMRAM_FIELD_ESP] = SMRAM_TRANSLATE(0x7fd8);
smram_map[SMRAM_FIELD_RBP_HI32] = SMRAM_TRANSLATE(0x7fd4);
smram_map[SMRAM_FIELD_EBP] = SMRAM_TRANSLATE(0x7fd0);
smram_map[SMRAM_FIELD_RSI_HI32] = SMRAM_TRANSLATE(0x7fcc);
smram_map[SMRAM_FIELD_ESI] = SMRAM_TRANSLATE(0x7fc8);
smram_map[SMRAM_FIELD_RDI_HI32] = SMRAM_TRANSLATE(0x7fc4);
smram_map[SMRAM_FIELD_EDI] = SMRAM_TRANSLATE(0x7fc0);
smram_map[SMRAM_FIELD_R8_HI32] = SMRAM_TRANSLATE(0x7fbc);
smram_map[SMRAM_FIELD_R8] = SMRAM_TRANSLATE(0x7fb8);
smram_map[SMRAM_FIELD_R9_HI32] = SMRAM_TRANSLATE(0x7fb4);
smram_map[SMRAM_FIELD_R9] = SMRAM_TRANSLATE(0x7fb0);
smram_map[SMRAM_FIELD_R10_HI32] = SMRAM_TRANSLATE(0x7fac);
smram_map[SMRAM_FIELD_R10] = SMRAM_TRANSLATE(0x7fa8);
smram_map[SMRAM_FIELD_R11_HI32] = SMRAM_TRANSLATE(0x7fa4);
smram_map[SMRAM_FIELD_R11] = SMRAM_TRANSLATE(0x7fa0);
smram_map[SMRAM_FIELD_R12_HI32] = SMRAM_TRANSLATE(0x7f9c);
smram_map[SMRAM_FIELD_R12] = SMRAM_TRANSLATE(0x7f98);
smram_map[SMRAM_FIELD_R13_HI32] = SMRAM_TRANSLATE(0x7f94);
smram_map[SMRAM_FIELD_R13] = SMRAM_TRANSLATE(0x7f90);
smram_map[SMRAM_FIELD_R14_HI32] = SMRAM_TRANSLATE(0x7f8c);
smram_map[SMRAM_FIELD_R14] = SMRAM_TRANSLATE(0x7f88);
smram_map[SMRAM_FIELD_R15_HI32] = SMRAM_TRANSLATE(0x7f84);
smram_map[SMRAM_FIELD_R15] = SMRAM_TRANSLATE(0x7f80);
smram_map[SMRAM_FIELD_RIP_HI32] = SMRAM_TRANSLATE(0x7f7c);
smram_map[SMRAM_FIELD_EIP] = SMRAM_TRANSLATE(0x7f78);
smram_map[SMRAM_FIELD_RFLAGS_HI32] = SMRAM_TRANSLATE(0x7f74); // always zero
smram_map[SMRAM_FIELD_EFLAGS] = SMRAM_TRANSLATE(0x7f70);
smram_map[SMRAM_FIELD_DR6_HI32] = SMRAM_TRANSLATE(0x7f6c); // always zero
smram_map[SMRAM_FIELD_DR6] = SMRAM_TRANSLATE(0x7f68);
smram_map[SMRAM_FIELD_DR7_HI32] = SMRAM_TRANSLATE(0x7f64); // always zero
smram_map[SMRAM_FIELD_DR7] = SMRAM_TRANSLATE(0x7f60);
smram_map[SMRAM_FIELD_CR0_HI32] = SMRAM_TRANSLATE(0x7f5c); // always zero
smram_map[SMRAM_FIELD_CR0] = SMRAM_TRANSLATE(0x7f58);
smram_map[SMRAM_FIELD_CR3_HI32] = SMRAM_TRANSLATE(0x7f54); // zero when physical address size 32-bit
smram_map[SMRAM_FIELD_CR3] = SMRAM_TRANSLATE(0x7f50);
smram_map[SMRAM_FIELD_CR4_HI32] = SMRAM_TRANSLATE(0x7f4c); // always zero
smram_map[SMRAM_FIELD_CR4] = SMRAM_TRANSLATE(0x7f48);
smram_map[SMRAM_FIELD_EFER_HI32] = SMRAM_TRANSLATE(0x7ed4); // always zero
smram_map[SMRAM_FIELD_EFER] = SMRAM_TRANSLATE(0x7ed0);
smram_map[SMRAM_FIELD_IO_INSTRUCTION_RESTART] = SMRAM_TRANSLATE(0x7ec8);
smram_map[SMRAM_FIELD_AUTOHALT_RESTART] = SMRAM_TRANSLATE(0x7ec8);
smram_map[SMRAM_FIELD_NMI_MASK] = SMRAM_TRANSLATE(0x7ec8);
smram_map[SMRAM_FIELD_TR_BASE_HI32] = SMRAM_TRANSLATE(0x7e9c);
smram_map[SMRAM_FIELD_TR_BASE] = SMRAM_TRANSLATE(0x7e98);
smram_map[SMRAM_FIELD_TR_LIMIT] = SMRAM_TRANSLATE(0x7e94);
smram_map[SMRAM_FIELD_TR_SELECTOR_AR] = SMRAM_TRANSLATE(0x7e90);
smram_map[SMRAM_FIELD_IDTR_BASE_HI32] = SMRAM_TRANSLATE(0x7e8c);
smram_map[SMRAM_FIELD_IDTR_BASE] = SMRAM_TRANSLATE(0x7e88);
smram_map[SMRAM_FIELD_IDTR_LIMIT] = SMRAM_TRANSLATE(0x7e84);
smram_map[SMRAM_FIELD_LDTR_BASE_HI32] = SMRAM_TRANSLATE(0x7e7c);
smram_map[SMRAM_FIELD_LDTR_BASE] = SMRAM_TRANSLATE(0x7e78);
smram_map[SMRAM_FIELD_LDTR_LIMIT] = SMRAM_TRANSLATE(0x7e74);
smram_map[SMRAM_FIELD_LDTR_SELECTOR_AR] = SMRAM_TRANSLATE(0x7e70);
smram_map[SMRAM_FIELD_GDTR_BASE_HI32] = SMRAM_TRANSLATE(0x7e6c);
smram_map[SMRAM_FIELD_GDTR_BASE] = SMRAM_TRANSLATE(0x7e68);
smram_map[SMRAM_FIELD_GDTR_LIMIT] = SMRAM_TRANSLATE(0x7e64);
smram_map[SMRAM_FIELD_ES_BASE_HI32] = SMRAM_TRANSLATE(0x7e0c);
smram_map[SMRAM_FIELD_ES_BASE] = SMRAM_TRANSLATE(0x7e08);
smram_map[SMRAM_FIELD_ES_LIMIT] = SMRAM_TRANSLATE(0x7e04);
smram_map[SMRAM_FIELD_ES_SELECTOR_AR] = SMRAM_TRANSLATE(0x7e00);
smram_map[SMRAM_FIELD_CS_BASE_HI32] = SMRAM_TRANSLATE(0x7e1c);
smram_map[SMRAM_FIELD_CS_BASE] = SMRAM_TRANSLATE(0x7e18);
smram_map[SMRAM_FIELD_CS_LIMIT] = SMRAM_TRANSLATE(0x7e14);
smram_map[SMRAM_FIELD_CS_SELECTOR_AR] = SMRAM_TRANSLATE(0x7e10);
smram_map[SMRAM_FIELD_SS_BASE_HI32] = SMRAM_TRANSLATE(0x7e2c);
smram_map[SMRAM_FIELD_SS_BASE] = SMRAM_TRANSLATE(0x7e28);
smram_map[SMRAM_FIELD_SS_LIMIT] = SMRAM_TRANSLATE(0x7e24);
smram_map[SMRAM_FIELD_SS_SELECTOR_AR] = SMRAM_TRANSLATE(0x7e20);
smram_map[SMRAM_FIELD_DS_BASE_HI32] = SMRAM_TRANSLATE(0x7e3c);
smram_map[SMRAM_FIELD_DS_BASE] = SMRAM_TRANSLATE(0x7e38);
smram_map[SMRAM_FIELD_DS_LIMIT] = SMRAM_TRANSLATE(0x7e34);
smram_map[SMRAM_FIELD_DS_SELECTOR_AR] = SMRAM_TRANSLATE(0x7e30);
smram_map[SMRAM_FIELD_FS_BASE_HI32] = SMRAM_TRANSLATE(0x7e4c);
smram_map[SMRAM_FIELD_FS_BASE] = SMRAM_TRANSLATE(0x7e48);
smram_map[SMRAM_FIELD_FS_LIMIT] = SMRAM_TRANSLATE(0x7e44);
smram_map[SMRAM_FIELD_FS_SELECTOR_AR] = SMRAM_TRANSLATE(0x7e40);
smram_map[SMRAM_FIELD_GS_BASE_HI32] = SMRAM_TRANSLATE(0x7e5c);
smram_map[SMRAM_FIELD_GS_BASE] = SMRAM_TRANSLATE(0x7e58);
smram_map[SMRAM_FIELD_GS_LIMIT] = SMRAM_TRANSLATE(0x7e54);
smram_map[SMRAM_FIELD_GS_SELECTOR_AR] = SMRAM_TRANSLATE(0x7e50);
for (unsigned n=0; n<SMRAM_FIELD_LAST;n++) {
if (smram_map[n] >= SMM_SAVE_STATE_MAP_SIZE) {
BX_PANIC(("smram map[%d] = %d", n, smram_map[n]));
}
}
}
#else
// source for Intel P6 SMM save state map used: www.sandpile.org
void BX_CPU_C::init_SMRAM(void)
{
smram_map[SMRAM_FIELD_SMBASE_OFFSET] = SMRAM_TRANSLATE(0x7ef8);
smram_map[SMRAM_FIELD_SMM_REVISION_ID] = SMRAM_TRANSLATE(0x7efc);
smram_map[SMRAM_FIELD_EAX] = SMRAM_TRANSLATE(0x7fd0);
smram_map[SMRAM_FIELD_ECX] = SMRAM_TRANSLATE(0x7fd4);
smram_map[SMRAM_FIELD_EDX] = SMRAM_TRANSLATE(0x7fd8);
smram_map[SMRAM_FIELD_EBX] = SMRAM_TRANSLATE(0x7fdc);
smram_map[SMRAM_FIELD_ESP] = SMRAM_TRANSLATE(0x7fe0);
smram_map[SMRAM_FIELD_EBP] = SMRAM_TRANSLATE(0x7fe4);
smram_map[SMRAM_FIELD_ESI] = SMRAM_TRANSLATE(0x7fe8);
smram_map[SMRAM_FIELD_EDI] = SMRAM_TRANSLATE(0x7fec);
smram_map[SMRAM_FIELD_EIP] = SMRAM_TRANSLATE(0x7ff0);
smram_map[SMRAM_FIELD_EFLAGS] = SMRAM_TRANSLATE(0x7ff4);
smram_map[SMRAM_FIELD_DR6] = SMRAM_TRANSLATE(0x7fcc);
smram_map[SMRAM_FIELD_DR7] = SMRAM_TRANSLATE(0x7fc8);
smram_map[SMRAM_FIELD_CR0] = SMRAM_TRANSLATE(0x7ffc);
smram_map[SMRAM_FIELD_CR3] = SMRAM_TRANSLATE(0x7ff8);
smram_map[SMRAM_FIELD_CR4] = SMRAM_TRANSLATE(0x7f14);
smram_map[SMRAM_FIELD_IO_INSTRUCTION_RESTART] = SMRAM_TRANSLATE(0x7f00);
smram_map[SMRAM_FIELD_AUTOHALT_RESTART] = SMRAM_TRANSLATE(0x7f00);
smram_map[SMRAM_FIELD_NMI_MASK] = SMRAM_TRANSLATE(0x7f00);
smram_map[SMRAM_FIELD_TR_SELECTOR] = SMRAM_TRANSLATE(0x7fc4);
smram_map[SMRAM_FIELD_TR_BASE] = SMRAM_TRANSLATE(0x7f64);
smram_map[SMRAM_FIELD_TR_LIMIT] = SMRAM_TRANSLATE(0x7f60);
smram_map[SMRAM_FIELD_TR_SELECTOR_AR] = SMRAM_TRANSLATE(0x7f5c);
smram_map[SMRAM_FIELD_LDTR_SELECTOR] = SMRAM_TRANSLATE(0x7fc0);
smram_map[SMRAM_FIELD_LDTR_BASE] = SMRAM_TRANSLATE(0x7f80);
smram_map[SMRAM_FIELD_LDTR_LIMIT] = SMRAM_TRANSLATE(0x7f7c);
smram_map[SMRAM_FIELD_LDTR_SELECTOR_AR] = SMRAM_TRANSLATE(0x7f78);
smram_map[SMRAM_FIELD_IDTR_BASE] = SMRAM_TRANSLATE(0x7f58);
smram_map[SMRAM_FIELD_IDTR_LIMIT] = SMRAM_TRANSLATE(0x7f54);
smram_map[SMRAM_FIELD_GDTR_BASE] = SMRAM_TRANSLATE(0x7f74);
smram_map[SMRAM_FIELD_GDTR_LIMIT] = SMRAM_TRANSLATE(0x7f70);
smram_map[SMRAM_FIELD_ES_SELECTOR] = SMRAM_TRANSLATE(0x7fa8);
smram_map[SMRAM_FIELD_ES_BASE] = SMRAM_TRANSLATE(0x7f8c);
smram_map[SMRAM_FIELD_ES_LIMIT] = SMRAM_TRANSLATE(0x7f88);
smram_map[SMRAM_FIELD_ES_SELECTOR_AR] = SMRAM_TRANSLATE(0x7f84);
smram_map[SMRAM_FIELD_CS_SELECTOR] = SMRAM_TRANSLATE(0x7fac);
smram_map[SMRAM_FIELD_CS_BASE] = SMRAM_TRANSLATE(0x7f98);
smram_map[SMRAM_FIELD_CS_LIMIT] = SMRAM_TRANSLATE(0x7f94);
smram_map[SMRAM_FIELD_CS_SELECTOR_AR] = SMRAM_TRANSLATE(0x7f90);
smram_map[SMRAM_FIELD_SS_SELECTOR] = SMRAM_TRANSLATE(0x7fb0);
smram_map[SMRAM_FIELD_SS_BASE] = SMRAM_TRANSLATE(0x7fa4);
smram_map[SMRAM_FIELD_SS_LIMIT] = SMRAM_TRANSLATE(0x7fa0);
smram_map[SMRAM_FIELD_SS_SELECTOR_AR] = SMRAM_TRANSLATE(0x7f9c);
smram_map[SMRAM_FIELD_DS_SELECTOR] = SMRAM_TRANSLATE(0x7fb4);
smram_map[SMRAM_FIELD_DS_BASE] = SMRAM_TRANSLATE(0x7f34);
smram_map[SMRAM_FIELD_DS_LIMIT] = SMRAM_TRANSLATE(0x7f30);
smram_map[SMRAM_FIELD_DS_SELECTOR_AR] = SMRAM_TRANSLATE(0x7f2c);
smram_map[SMRAM_FIELD_FS_SELECTOR] = SMRAM_TRANSLATE(0x7fb8);
smram_map[SMRAM_FIELD_FS_BASE] = SMRAM_TRANSLATE(0x7f40);
smram_map[SMRAM_FIELD_FS_LIMIT] = SMRAM_TRANSLATE(0x7f3c);
smram_map[SMRAM_FIELD_FS_SELECTOR_AR] = SMRAM_TRANSLATE(0x7f38);
smram_map[SMRAM_FIELD_GS_SELECTOR] = SMRAM_TRANSLATE(0x7fbc);
smram_map[SMRAM_FIELD_GS_BASE] = SMRAM_TRANSLATE(0x7f4c);
smram_map[SMRAM_FIELD_GS_LIMIT] = SMRAM_TRANSLATE(0x7f48);
smram_map[SMRAM_FIELD_GS_SELECTOR_AR] = SMRAM_TRANSLATE(0x7f44);
for (unsigned n=0; n<SMRAM_FIELD_LAST;n++) {
if (smram_map[n] >= SMM_SAVE_STATE_MAP_SIZE) {
BX_PANIC(("smram map[%d] = %d", n, smram_map[n]));
}
}
}
#endif
#define SMRAM_FIELD(state, field) (state[smram_map[field]])
#if BX_SUPPORT_X86_64
BX_CPP_INLINE Bit64u SMRAM_FIELD64(const Bit32u *saved_state, unsigned hi, unsigned lo)
{
Bit64u tmp = ((Bit64u) SMRAM_FIELD(saved_state, hi)) << 32;
tmp |= (Bit64u) SMRAM_FIELD(saved_state, lo);
return tmp;
}
void BX_CPU_C::smram_save_state(Bit32u *saved_state)
{
// --- General Purpose Registers --- //
for (int n=0; n<BX_GENERAL_REGISTERS; n++) {
Bit64u val_64 = BX_READ_64BIT_REG(n);
SMRAM_FIELD(saved_state, SMRAM_FIELD_RAX_HI32 + 2*n) = GET32H(val_64);
SMRAM_FIELD(saved_state, SMRAM_FIELD_EAX + 2*n) = GET32L(val_64);
}
SMRAM_FIELD(saved_state, SMRAM_FIELD_RIP_HI32) = GET32H(RIP);
SMRAM_FIELD(saved_state, SMRAM_FIELD_EIP) = EIP;
SMRAM_FIELD(saved_state, SMRAM_FIELD_EFLAGS) = read_eflags();
// --- Debug and Control Registers --- //
SMRAM_FIELD(saved_state, SMRAM_FIELD_DR6) = BX_CPU_THIS_PTR dr6;
SMRAM_FIELD(saved_state, SMRAM_FIELD_DR7) = BX_CPU_THIS_PTR dr7;
SMRAM_FIELD(saved_state, SMRAM_FIELD_CR0) = BX_CPU_THIS_PTR cr0.get32();
SMRAM_FIELD(saved_state, SMRAM_FIELD_CR3_HI32) = GET32H(BX_CPU_THIS_PTR cr3);
SMRAM_FIELD(saved_state, SMRAM_FIELD_CR3) = GET32L(BX_CPU_THIS_PTR cr3);
SMRAM_FIELD(saved_state, SMRAM_FIELD_CR4) = BX_CPU_THIS_PTR cr4.get32();
SMRAM_FIELD(saved_state, SMRAM_FIELD_EFER) = BX_CPU_THIS_PTR efer.get32();
SMRAM_FIELD(saved_state, SMRAM_FIELD_SMBASE_OFFSET) = BX_CPU_THIS_PTR smbase;
SMRAM_FIELD(saved_state, SMRAM_FIELD_SMM_REVISION_ID) = SMM_REVISION_ID;
// --- Task Register --- //
SMRAM_FIELD(saved_state, SMRAM_FIELD_TR_BASE_HI32) = GET32H(BX_CPU_THIS_PTR tr.cache.u.segment.base);
SMRAM_FIELD(saved_state, SMRAM_FIELD_TR_BASE) = GET32L(BX_CPU_THIS_PTR tr.cache.u.segment.base);
SMRAM_FIELD(saved_state, SMRAM_FIELD_TR_LIMIT) = BX_CPU_THIS_PTR tr.cache.u.segment.limit_scaled;
Bit32u tr_ar = ((get_descriptor_h(&BX_CPU_THIS_PTR tr.cache) >> 8) & 0xf0ff) | (BX_CPU_THIS_PTR tr.cache.valid << 8);
SMRAM_FIELD(saved_state, SMRAM_FIELD_TR_SELECTOR_AR) = BX_CPU_THIS_PTR tr.selector.value | (tr_ar << 16);
// --- LDTR --- //
SMRAM_FIELD(saved_state, SMRAM_FIELD_LDTR_BASE_HI32) = GET32H(BX_CPU_THIS_PTR ldtr.cache.u.segment.base);
SMRAM_FIELD(saved_state, SMRAM_FIELD_LDTR_BASE) = GET32L(BX_CPU_THIS_PTR ldtr.cache.u.segment.base);
SMRAM_FIELD(saved_state, SMRAM_FIELD_LDTR_LIMIT) = BX_CPU_THIS_PTR ldtr.cache.u.segment.limit_scaled;
Bit32u ldtr_ar = ((get_descriptor_h(&BX_CPU_THIS_PTR ldtr.cache) >> 8) & 0xf0ff) | (BX_CPU_THIS_PTR ldtr.cache.valid << 8);
SMRAM_FIELD(saved_state, SMRAM_FIELD_LDTR_SELECTOR_AR) = BX_CPU_THIS_PTR ldtr.selector.value | (ldtr_ar << 16);
// --- IDTR --- //
SMRAM_FIELD(saved_state, SMRAM_FIELD_IDTR_BASE_HI32) = GET32H(BX_CPU_THIS_PTR idtr.base);
SMRAM_FIELD(saved_state, SMRAM_FIELD_IDTR_BASE) = GET32L(BX_CPU_THIS_PTR idtr.base);
SMRAM_FIELD(saved_state, SMRAM_FIELD_IDTR_LIMIT) = BX_CPU_THIS_PTR idtr.limit;
// --- GDTR --- //
SMRAM_FIELD(saved_state, SMRAM_FIELD_GDTR_BASE_HI32) = GET32H(BX_CPU_THIS_PTR gdtr.base);
SMRAM_FIELD(saved_state, SMRAM_FIELD_GDTR_BASE) = GET32L(BX_CPU_THIS_PTR gdtr.base);
SMRAM_FIELD(saved_state, SMRAM_FIELD_GDTR_LIMIT) = BX_CPU_THIS_PTR gdtr.limit;
for (int segreg = 0; segreg < 6; segreg++) {
bx_segment_reg_t *seg = &(BX_CPU_THIS_PTR sregs[segreg]);
SMRAM_FIELD(saved_state, SMRAM_FIELD_ES_BASE_HI32 + 4*segreg) = GET32H(seg->cache.u.segment.base);
SMRAM_FIELD(saved_state, SMRAM_FIELD_ES_BASE + 4*segreg) = GET32L(seg->cache.u.segment.base);
SMRAM_FIELD(saved_state, SMRAM_FIELD_ES_LIMIT + 4*segreg) = seg->cache.u.segment.limit_scaled;
Bit32u seg_ar = ((get_descriptor_h(&seg->cache) >> 8) & 0xf0ff) | (seg->cache.valid << 8);
SMRAM_FIELD(saved_state, SMRAM_FIELD_ES_SELECTOR_AR + 4*segreg) = seg->selector.value | (seg_ar << 16);
}
}
bx_bool BX_CPU_C::smram_restore_state(const Bit32u *saved_state)
{
Bit32u temp_cr0 = SMRAM_FIELD(saved_state, SMRAM_FIELD_CR0);
Bit32u temp_eflags = SMRAM_FIELD(saved_state, SMRAM_FIELD_EFLAGS);
Bit32u temp_efer = SMRAM_FIELD(saved_state, SMRAM_FIELD_EFER);
Bit32u temp_cr4 = SMRAM_FIELD(saved_state, SMRAM_FIELD_CR4);
// Processors that support VMX operation perform RSM as follows:
#if BX_SUPPORT_VMX
// IF VMXE=1 in CR4 image in SMRAM
// THEN
// fail and enter shutdown state;
if (temp_cr4 & BX_CR4_VMXE_MASK) {
BX_PANIC(("SMM restore: CR4.VMXE is set in restore image !"));
return 0;
}
// restore state normally from SMRAM;
// CR4.VMXE = value stored internally;
// IF internal storage indicates that the logical processor had been in VMX operation (root or non-root)
// THEN
// enter VMX operation (root or non-root);
// restore VMX-critical state
// set CR0.PE, CR0.NE, and CR0.PG to 1;
// IF RFLAGS.VM = 0
// THEN
// CS.RPL = SS.DPL;
// SS.RPL = SS.DPL;
// FI;
// If necessary, restore current VMCS pointer;
// Leave SMM; Deassert SMMEM on subsequent bus transactions;
// IF logical processor will be in VMX operation after RSM
// THEN
// block A20M and leave A20M mode;
// FI;
if (BX_CPU_THIS_PTR in_smm_vmx) {
BX_CPU_THIS_PTR in_vmx = 1;
BX_CPU_THIS_PTR in_vmx_guest = BX_CPU_THIS_PTR in_smm_vmx_guest;
BX_INFO(("SMM Restore: enable VMX %s mode", BX_CPU_THIS_PTR in_vmx_guest ? "guest" : "host"));
temp_cr4 |= BX_CR4_VMXE_MASK; /* set VMXE */
temp_cr0 |= (1<<31) /* PG */ | (1 << 5) /* NE */ | 0x1 /* PE */;
// block and disable A20M;
}
#endif
bx_bool pe = (temp_cr0 & 0x1);
bx_bool pg = (temp_cr0 >> 31) & 0x1;
// check CR0 conditions for entering to shutdown state
if (!check_CR0(temp_cr0)) {
BX_PANIC(("SMM restore: CR0 consistency check failed !"));
return 0;
}
if (!check_CR4(temp_cr4)) {
BX_PANIC(("SMM restore: CR4 consistency check failed !"));
return 0;
}
// shutdown if write to reserved CR4 bits
if (!SetCR4(temp_cr4)) {
BX_PANIC(("SMM restore: incorrect CR4 state !"));
return 0;
}
if (temp_efer & ~BX_EFER_SUPPORTED_BITS) {
BX_PANIC(("SMM restore: Attemp to set EFER reserved bits: 0x%08x !", temp_efer));
return 0;
}
BX_CPU_THIS_PTR efer.set32(temp_efer & BX_EFER_SUPPORTED_BITS);
if (BX_CPU_THIS_PTR efer.get_LMA()) {
if (temp_eflags & EFlagsVMMask) {
BX_PANIC(("SMM restore: If EFER.LMA = 1 => RFLAGS.VM=0 !"));
return 0;
}
if (!BX_CPU_THIS_PTR cr4.get_PAE() || !pg || !pe || !BX_CPU_THIS_PTR efer.get_LME()) {
BX_PANIC(("SMM restore: If EFER.LMA = 1 <=> CR4.PAE, CR0.PG, CR0.PE, EFER.LME=1 !"));
return 0;
}
}
else {
if (BX_CPU_THIS_PTR cr4.get_PCIDE()) {
BX_PANIC(("SMM restore: CR4.PCIDE must be clear when not in long mode !"));
return 0;
}
}
if (BX_CPU_THIS_PTR cr4.get_PAE() && pg && pe && BX_CPU_THIS_PTR efer.get_LME()) {
if (! BX_CPU_THIS_PTR efer.get_LMA()) {
BX_PANIC(("SMM restore: If EFER.LMA = 1 <=> CR4.PAE, CR0.PG, CR0.PE, EFER.LME=1 !"));
return 0;
}
}
// hack CR0 to be able to back to long mode correctly
BX_CPU_THIS_PTR cr0.set_PE(0); // real mode (bit 0)
BX_CPU_THIS_PTR cr0.set_PG(0); // paging disabled (bit 31)
if (! SetCR0(temp_cr0)) {
BX_PANIC(("SMM restore: failed to restore CR0 !"));
return 0;
}
setEFlags(temp_eflags);
bx_phy_address temp_cr3 = (bx_phy_address) SMRAM_FIELD64(saved_state, SMRAM_FIELD_CR3_HI32, SMRAM_FIELD_CR3);
if (!SetCR3(temp_cr3)) {
BX_PANIC(("SMM restore: failed to restore CR3 !"));
return 0;
}
if (BX_CPU_THIS_PTR cr0.get_PG() && BX_CPU_THIS_PTR cr4.get_PAE() && !long_mode()) {
if (! CheckPDPTR(temp_cr3)) {
BX_ERROR(("SMM restore: PDPTR check failed !"));
return 0;
}
}
for (int n=0; n<BX_GENERAL_REGISTERS; n++) {
Bit64u val_64 = SMRAM_FIELD64(saved_state,
SMRAM_FIELD_RAX_HI32 + 2*n, SMRAM_FIELD_EAX + 2*n);
BX_WRITE_64BIT_REG(n, val_64);
}
RIP = SMRAM_FIELD64(saved_state, SMRAM_FIELD_RIP_HI32, SMRAM_FIELD_EIP);
BX_CPU_THIS_PTR dr6 = SMRAM_FIELD(saved_state, SMRAM_FIELD_DR6);
BX_CPU_THIS_PTR dr7 = SMRAM_FIELD(saved_state, SMRAM_FIELD_DR7);
BX_CPU_THIS_PTR gdtr.base = SMRAM_FIELD64(saved_state, SMRAM_FIELD_GDTR_BASE_HI32, SMRAM_FIELD_GDTR_BASE);
BX_CPU_THIS_PTR gdtr.limit = SMRAM_FIELD(saved_state, SMRAM_FIELD_GDTR_LIMIT);
BX_CPU_THIS_PTR idtr.base = SMRAM_FIELD64(saved_state, SMRAM_FIELD_IDTR_BASE_HI32, SMRAM_FIELD_IDTR_BASE);
BX_CPU_THIS_PTR idtr.limit = SMRAM_FIELD(saved_state, SMRAM_FIELD_IDTR_LIMIT);
for (int segreg = 0; segreg < 6; segreg++) {
Bit16u ar_data = SMRAM_FIELD(saved_state, SMRAM_FIELD_ES_SELECTOR_AR + 4*segreg) >> 16;
if (set_segment_ar_data(&BX_CPU_THIS_PTR sregs[segreg],
(ar_data >> 8) & 1,
SMRAM_FIELD(saved_state, SMRAM_FIELD_ES_SELECTOR_AR + 4*segreg) & 0xf0ff,
SMRAM_FIELD64(saved_state, SMRAM_FIELD_ES_BASE_HI32 + 4*segreg, SMRAM_FIELD_ES_BASE + 4*segreg),
SMRAM_FIELD(saved_state, SMRAM_FIELD_ES_LIMIT + 4*segreg), ar_data))
{
if (! BX_CPU_THIS_PTR sregs[segreg].cache.segment) {
BX_PANIC(("SMM restore: restored valid non segment %d !", segreg));
return 0;
}
}
}
handleCpuModeChange();
#if BX_CPU_LEVEL >= 6
handleSseModeChange();
#endif
Bit16u ar_data = SMRAM_FIELD(saved_state, SMRAM_FIELD_LDTR_SELECTOR_AR) >> 16;
if (set_segment_ar_data(&BX_CPU_THIS_PTR ldtr,
(ar_data >> 8) & 1,
SMRAM_FIELD(saved_state, SMRAM_FIELD_LDTR_SELECTOR_AR) & 0xf0ff,
SMRAM_FIELD64(saved_state, SMRAM_FIELD_LDTR_BASE_HI32, SMRAM_FIELD_LDTR_BASE),
SMRAM_FIELD(saved_state, SMRAM_FIELD_LDTR_LIMIT), ar_data))
{
if (BX_CPU_THIS_PTR ldtr.cache.type != BX_SYS_SEGMENT_LDT) {
BX_PANIC(("SMM restore: LDTR is not LDT descriptor type !"));
return 0;
}
}
ar_data = SMRAM_FIELD(saved_state, SMRAM_FIELD_TR_SELECTOR_AR) >> 16;
if (set_segment_ar_data(&BX_CPU_THIS_PTR tr,
(ar_data >> 8) & 1,
SMRAM_FIELD(saved_state, SMRAM_FIELD_TR_SELECTOR_AR) & 0xf0ff,
SMRAM_FIELD64(saved_state, SMRAM_FIELD_TR_BASE_HI32, SMRAM_FIELD_TR_BASE),
SMRAM_FIELD(saved_state, SMRAM_FIELD_TR_LIMIT), ar_data))
{
if (BX_CPU_THIS_PTR tr.cache.type != BX_SYS_SEGMENT_AVAIL_286_TSS &&
BX_CPU_THIS_PTR tr.cache.type != BX_SYS_SEGMENT_BUSY_286_TSS &&
BX_CPU_THIS_PTR tr.cache.type != BX_SYS_SEGMENT_AVAIL_386_TSS &&
BX_CPU_THIS_PTR tr.cache.type != BX_SYS_SEGMENT_BUSY_386_TSS)
{
BX_PANIC(("SMM restore: TR is not TSS descriptor type !"));
return 0;
}
}
if (SMM_REVISION_ID & SMM_SMBASE_RELOCATION)
BX_CPU_THIS_PTR smbase = SMRAM_FIELD(saved_state, SMRAM_FIELD_SMBASE_OFFSET);
return 1;
}
#else /* BX_SUPPORT_X86_64 == 0 */
void BX_CPU_C::smram_save_state(Bit32u *saved_state)
{
SMRAM_FIELD(saved_state, SMRAM_FIELD_SMM_REVISION_ID) = SMM_REVISION_ID;
SMRAM_FIELD(saved_state, SMRAM_FIELD_SMBASE_OFFSET) = BX_CPU_THIS_PTR smbase;
for (int n=0; n<BX_GENERAL_REGISTERS; n++) {
Bit32u val_32 = BX_READ_32BIT_REG(n);
SMRAM_FIELD(saved_state, SMRAM_FIELD_EAX + n) = val_32;
}
SMRAM_FIELD(saved_state, SMRAM_FIELD_EIP) = EIP;
SMRAM_FIELD(saved_state, SMRAM_FIELD_EFLAGS) = read_eflags();
SMRAM_FIELD(saved_state, SMRAM_FIELD_CR0) = BX_CPU_THIS_PTR cr0.get32();
SMRAM_FIELD(saved_state, SMRAM_FIELD_CR3) = BX_CPU_THIS_PTR cr3;
#if BX_CPU_LEVEL >= 4
SMRAM_FIELD(saved_state, SMRAM_FIELD_CR4) = BX_CPU_THIS_PTR cr4.get32();
#endif
SMRAM_FIELD(saved_state, SMRAM_FIELD_DR6) = BX_CPU_THIS_PTR dr6;
SMRAM_FIELD(saved_state, SMRAM_FIELD_DR7) = BX_CPU_THIS_PTR dr7;
// --- Task Register --- //
SMRAM_FIELD(saved_state, SMRAM_FIELD_TR_SELECTOR) = BX_CPU_THIS_PTR tr.selector.value;
SMRAM_FIELD(saved_state, SMRAM_FIELD_TR_BASE) = BX_CPU_THIS_PTR tr.cache.u.segment.base;
SMRAM_FIELD(saved_state, SMRAM_FIELD_TR_LIMIT) = BX_CPU_THIS_PTR tr.cache.u.segment.limit_scaled;
Bit32u tr_ar = ((get_descriptor_h(&BX_CPU_THIS_PTR tr.cache) >> 8) & 0xf0ff) | (BX_CPU_THIS_PTR tr.cache.valid << 8);
SMRAM_FIELD(saved_state, SMRAM_FIELD_TR_SELECTOR_AR) = BX_CPU_THIS_PTR tr.selector.value | (tr_ar << 16);
// --- LDTR --- //
SMRAM_FIELD(saved_state, SMRAM_FIELD_LDTR_SELECTOR) = BX_CPU_THIS_PTR ldtr.selector.value;
SMRAM_FIELD(saved_state, SMRAM_FIELD_LDTR_BASE) = BX_CPU_THIS_PTR ldtr.cache.u.segment.base;
SMRAM_FIELD(saved_state, SMRAM_FIELD_LDTR_LIMIT) = BX_CPU_THIS_PTR ldtr.cache.u.segment.limit_scaled;
Bit32u ldtr_ar = ((get_descriptor_h(&BX_CPU_THIS_PTR ldtr.cache) >> 8) & 0xf0ff) | (BX_CPU_THIS_PTR ldtr.cache.valid << 8);
SMRAM_FIELD(saved_state, SMRAM_FIELD_LDTR_SELECTOR_AR) = BX_CPU_THIS_PTR ldtr.selector.value | (ldtr_ar << 16);
// --- IDTR --- //
SMRAM_FIELD(saved_state, SMRAM_FIELD_IDTR_BASE) = BX_CPU_THIS_PTR idtr.base;
SMRAM_FIELD(saved_state, SMRAM_FIELD_IDTR_LIMIT) = BX_CPU_THIS_PTR idtr.limit;
// --- GDTR --- //
SMRAM_FIELD(saved_state, SMRAM_FIELD_GDTR_BASE) = BX_CPU_THIS_PTR gdtr.base;
SMRAM_FIELD(saved_state, SMRAM_FIELD_GDTR_LIMIT) = BX_CPU_THIS_PTR gdtr.limit;
for (int segreg = 0; segreg < 6; segreg++) {
bx_segment_reg_t *seg = &(BX_CPU_THIS_PTR sregs[segreg]);
SMRAM_FIELD(saved_state, SMRAM_FIELD_ES_SELECTOR + 4*segreg) = seg->selector.value;
SMRAM_FIELD(saved_state, SMRAM_FIELD_ES_BASE + 4*segreg) = seg->cache.u.segment.base;
SMRAM_FIELD(saved_state, SMRAM_FIELD_ES_LIMIT + 4*segreg) = seg->cache.u.segment.limit_scaled;
Bit32u seg_ar = ((get_descriptor_h(&seg->cache) >> 8) & 0xf0ff) | (seg->cache.valid << 8);
SMRAM_FIELD(saved_state, SMRAM_FIELD_ES_SELECTOR_AR + 4*segreg) = seg->selector.value | (seg_ar << 16);
}
}
bx_bool BX_CPU_C::smram_restore_state(const Bit32u *saved_state)
{
// check conditions for entering to shutdown state
Bit32u temp_cr0 = SMRAM_FIELD(saved_state, SMRAM_FIELD_CR0);
if (!check_CR0(temp_cr0)) {
BX_PANIC(("SMM restore: CR0 consistency check failed !"));
return 0;
}
#if BX_CPU_LEVEL >= 4
Bit32u temp_cr4 = SMRAM_FIELD(saved_state, SMRAM_FIELD_CR4);
if (! check_CR4(temp_cr4)) {
BX_PANIC(("SMM restore: CR4 consistency check failed !"));
return 0;
}
#endif
if (!SetCR0(temp_cr0)) {
BX_PANIC(("SMM restore: failed to restore CR0 !"));
return 0;
}
#if BX_CPU_LEVEL >= 4
if (!SetCR4(temp_cr4)) {
BX_PANIC(("SMM restore: incorrect CR4 state !"));
return 0;
}
#endif
Bit32u temp_cr3 = SMRAM_FIELD(saved_state, SMRAM_FIELD_CR3);
if (!SetCR3(temp_cr3)) {
BX_PANIC(("SMM restore: failed to restore CR3 !"));
return 0;
}
#if BX_CPU_LEVEL >= 6
if (BX_CPU_THIS_PTR cr0.get_PG() && BX_CPU_THIS_PTR cr4.get_PAE()) {
if (! CheckPDPTR(temp_cr3)) {
BX_ERROR(("SMM restore: PDPTR check failed !"));
return 0;
}
}
#endif
Bit32u temp_eflags = SMRAM_FIELD(saved_state, SMRAM_FIELD_EFLAGS);
setEFlags(temp_eflags);
for (int n=0; n<BX_GENERAL_REGISTERS; n++) {
Bit32u val_32 = SMRAM_FIELD(saved_state, SMRAM_FIELD_EAX + n);
BX_WRITE_32BIT_REGZ(n, val_32);
}
EIP = SMRAM_FIELD(saved_state, SMRAM_FIELD_EIP);
BX_CPU_THIS_PTR dr6 = SMRAM_FIELD(saved_state, SMRAM_FIELD_DR6);
BX_CPU_THIS_PTR dr7 = SMRAM_FIELD(saved_state, SMRAM_FIELD_DR7);
BX_CPU_THIS_PTR gdtr.base = SMRAM_FIELD(saved_state, SMRAM_FIELD_GDTR_BASE);
BX_CPU_THIS_PTR gdtr.limit = SMRAM_FIELD(saved_state, SMRAM_FIELD_GDTR_LIMIT);
BX_CPU_THIS_PTR idtr.base = SMRAM_FIELD(saved_state, SMRAM_FIELD_IDTR_BASE);
BX_CPU_THIS_PTR idtr.limit = SMRAM_FIELD(saved_state, SMRAM_FIELD_IDTR_LIMIT);
for (int segreg = 0; segreg < 6; segreg++) {
Bit32u ar_data = SMRAM_FIELD(saved_state, SMRAM_FIELD_ES_SELECTOR_AR + 4*segreg) >> 16;
if (set_segment_ar_data(&BX_CPU_THIS_PTR sregs[segreg],
(ar_data >> 8) & 1,
SMRAM_FIELD(saved_state, SMRAM_FIELD_ES_SELECTOR_AR + 4*segreg) & 0xf0ff,
SMRAM_FIELD(saved_state, SMRAM_FIELD_ES_BASE + 4*segreg),
SMRAM_FIELD(saved_state, SMRAM_FIELD_ES_LIMIT + 4*segreg), ar_data))
{
if (! BX_CPU_THIS_PTR sregs[segreg].cache.segment) {
BX_PANIC(("SMM restore: restored valid non segment %d !", segreg));
return 0;
}
}
}
Bit32u ar_data = SMRAM_FIELD(saved_state, SMRAM_FIELD_LDTR_SELECTOR_AR) >> 16;
if (set_segment_ar_data(&BX_CPU_THIS_PTR ldtr,
(ar_data >> 8) & 1,
SMRAM_FIELD(saved_state, SMRAM_FIELD_LDTR_SELECTOR_AR) & 0xf0ff,
SMRAM_FIELD(saved_state, SMRAM_FIELD_LDTR_BASE),
SMRAM_FIELD(saved_state, SMRAM_FIELD_LDTR_LIMIT), ar_data))
{
if (BX_CPU_THIS_PTR ldtr.cache.type != BX_SYS_SEGMENT_LDT) {
BX_PANIC(("SMM restore: LDTR is not LDT descriptor type !"));
return 0;
}
}
ar_data = SMRAM_FIELD(saved_state, SMRAM_FIELD_TR_SELECTOR_AR) >> 16;
if (set_segment_ar_data(&BX_CPU_THIS_PTR tr,
(ar_data >> 8) & 1,
SMRAM_FIELD(saved_state, SMRAM_FIELD_TR_SELECTOR_AR) & 0xf0ff,
SMRAM_FIELD(saved_state, SMRAM_FIELD_TR_BASE),
SMRAM_FIELD(saved_state, SMRAM_FIELD_TR_LIMIT), ar_data))
{
if (BX_CPU_THIS_PTR tr.cache.type != BX_SYS_SEGMENT_AVAIL_286_TSS &&
BX_CPU_THIS_PTR tr.cache.type != BX_SYS_SEGMENT_BUSY_286_TSS &&
BX_CPU_THIS_PTR tr.cache.type != BX_SYS_SEGMENT_AVAIL_386_TSS &&
BX_CPU_THIS_PTR tr.cache.type != BX_SYS_SEGMENT_BUSY_386_TSS)
{
BX_PANIC(("SMM restore: TR is not TSS descriptor type !"));
return 0;
}
}
if (SMM_REVISION_ID & SMM_SMBASE_RELOCATION) {
BX_CPU_THIS_PTR smbase = SMRAM_FIELD(saved_state, SMRAM_FIELD_SMBASE_OFFSET);
#if BX_CPU_LEVEL < 6
if (BX_CPU_THIS_PTR smbase & 0x7fff) {
BX_PANIC(("SMM restore: SMBASE must be aligned to 32K !"));
return 0;
}
#endif
}
return 1;
}
#endif /* BX_SUPPORT_X86_64 */
#endif /* BX_CPU_LEVEL >= 3 */

203
simulators/bochs/cpu/smm.h Executable file
View File

@ -0,0 +1,203 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2006-2009 Stanislav Shwartsman
// 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
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA B 02110-1301 USA
/////////////////////////////////////////////////////////////////////////
#ifndef BX_SMM_H
#define BX_SMM_H
/* SMM feature masks */
#define SMM_IO_INSTRUCTION_RESTART (0x00010000)
#define SMM_SMBASE_RELOCATION (0x00020000)
#define SMM_SAVE_STATE_MAP_SIZE 128
//
// - For x86-64 configuration using AMD Athlon 64 512-byte SMM save state map
// revision ID according to QEMU/Bochs BIOS
//
// - For x86-32 configuration using Intel P6 512-byte SMM save state map
//
#define SMM_REVISION_ID \
((BX_SUPPORT_X86_64 ? 0x00000064 : 0) | SMM_SMBASE_RELOCATION)
#if BX_SUPPORT_X86_64
enum SMMRAM_Fields {
SMRAM_FIELD_SMBASE_OFFSET = 0,
SMRAM_FIELD_SMM_REVISION_ID,
SMRAM_FIELD_RAX_HI32,
SMRAM_FIELD_EAX,
SMRAM_FIELD_RCX_HI32,
SMRAM_FIELD_ECX,
SMRAM_FIELD_RDX_HI32,
SMRAM_FIELD_EDX,
SMRAM_FIELD_RBX_HI32,
SMRAM_FIELD_EBX,
SMRAM_FIELD_RSP_HI32,
SMRAM_FIELD_ESP,
SMRAM_FIELD_RBP_HI32,
SMRAM_FIELD_EBP,
SMRAM_FIELD_RSI_HI32,
SMRAM_FIELD_ESI,
SMRAM_FIELD_RDI_HI32,
SMRAM_FIELD_EDI,
SMRAM_FIELD_R8_HI32,
SMRAM_FIELD_R8,
SMRAM_FIELD_R9_HI32,
SMRAM_FIELD_R9,
SMRAM_FIELD_R10_HI32,
SMRAM_FIELD_R10,
SMRAM_FIELD_R11_HI32,
SMRAM_FIELD_R11,
SMRAM_FIELD_R12_HI32,
SMRAM_FIELD_R12,
SMRAM_FIELD_R13_HI32,
SMRAM_FIELD_R13,
SMRAM_FIELD_R14_HI32,
SMRAM_FIELD_R14,
SMRAM_FIELD_R15_HI32,
SMRAM_FIELD_R15,
SMRAM_FIELD_RIP_HI32,
SMRAM_FIELD_EIP,
SMRAM_FIELD_RFLAGS_HI32, // always zero
SMRAM_FIELD_EFLAGS,
SMRAM_FIELD_DR6_HI32, // always zero
SMRAM_FIELD_DR6,
SMRAM_FIELD_DR7_HI32, // always zero
SMRAM_FIELD_DR7,
SMRAM_FIELD_CR0_HI32, // always zero
SMRAM_FIELD_CR0,
SMRAM_FIELD_CR3_HI32, // zero when physical address size 32-bit
SMRAM_FIELD_CR3,
SMRAM_FIELD_CR4_HI32, // always zero
SMRAM_FIELD_CR4,
SMRAM_FIELD_EFER_HI32, // always zero
SMRAM_FIELD_EFER,
SMRAM_FIELD_IO_INSTRUCTION_RESTART,
SMRAM_FIELD_AUTOHALT_RESTART,
SMRAM_FIELD_NMI_MASK,
SMRAM_FIELD_TR_BASE_HI32,
SMRAM_FIELD_TR_BASE,
SMRAM_FIELD_TR_LIMIT,
SMRAM_FIELD_TR_SELECTOR_AR,
SMRAM_FIELD_LDTR_BASE_HI32,
SMRAM_FIELD_LDTR_BASE,
SMRAM_FIELD_LDTR_LIMIT,
SMRAM_FIELD_LDTR_SELECTOR_AR,
SMRAM_FIELD_IDTR_BASE_HI32,
SMRAM_FIELD_IDTR_BASE,
SMRAM_FIELD_IDTR_LIMIT,
SMRAM_FIELD_GDTR_BASE_HI32,
SMRAM_FIELD_GDTR_BASE,
SMRAM_FIELD_GDTR_LIMIT,
SMRAM_FIELD_ES_BASE_HI32,
SMRAM_FIELD_ES_BASE,
SMRAM_FIELD_ES_LIMIT,
SMRAM_FIELD_ES_SELECTOR_AR,
SMRAM_FIELD_CS_BASE_HI32,
SMRAM_FIELD_CS_BASE,
SMRAM_FIELD_CS_LIMIT,
SMRAM_FIELD_CS_SELECTOR_AR,
SMRAM_FIELD_SS_BASE_HI32,
SMRAM_FIELD_SS_BASE,
SMRAM_FIELD_SS_LIMIT,
SMRAM_FIELD_SS_SELECTOR_AR,
SMRAM_FIELD_DS_BASE_HI32,
SMRAM_FIELD_DS_BASE,
SMRAM_FIELD_DS_LIMIT,
SMRAM_FIELD_DS_SELECTOR_AR,
SMRAM_FIELD_FS_BASE_HI32,
SMRAM_FIELD_FS_BASE,
SMRAM_FIELD_FS_LIMIT,
SMRAM_FIELD_FS_SELECTOR_AR,
SMRAM_FIELD_GS_BASE_HI32,
SMRAM_FIELD_GS_BASE,
SMRAM_FIELD_GS_LIMIT,
SMRAM_FIELD_GS_SELECTOR_AR,
SMRAM_FIELD_LAST
};
#else
enum SMMRAM_Fields {
SMRAM_FIELD_SMBASE_OFFSET = 0,
SMRAM_FIELD_SMM_REVISION_ID,
SMRAM_FIELD_EAX,
SMRAM_FIELD_ECX,
SMRAM_FIELD_EDX,
SMRAM_FIELD_EBX,
SMRAM_FIELD_ESP,
SMRAM_FIELD_EBP,
SMRAM_FIELD_ESI,
SMRAM_FIELD_EDI,
SMRAM_FIELD_EIP,
SMRAM_FIELD_EFLAGS,
SMRAM_FIELD_DR6,
SMRAM_FIELD_DR7,
SMRAM_FIELD_CR0,
SMRAM_FIELD_CR3,
SMRAM_FIELD_CR4,
SMRAM_FIELD_IO_INSTRUCTION_RESTART,
SMRAM_FIELD_AUTOHALT_RESTART,
SMRAM_FIELD_NMI_MASK,
SMRAM_FIELD_TR_SELECTOR,
SMRAM_FIELD_TR_BASE,
SMRAM_FIELD_TR_LIMIT,
SMRAM_FIELD_TR_SELECTOR_AR,
SMRAM_FIELD_LDTR_SELECTOR,
SMRAM_FIELD_LDTR_BASE,
SMRAM_FIELD_LDTR_LIMIT,
SMRAM_FIELD_LDTR_SELECTOR_AR,
SMRAM_FIELD_IDTR_BASE,
SMRAM_FIELD_IDTR_LIMIT,
SMRAM_FIELD_GDTR_BASE,
SMRAM_FIELD_GDTR_LIMIT,
SMRAM_FIELD_ES_SELECTOR,
SMRAM_FIELD_ES_BASE,
SMRAM_FIELD_ES_LIMIT,
SMRAM_FIELD_ES_SELECTOR_AR,
SMRAM_FIELD_CS_SELECTOR,
SMRAM_FIELD_CS_BASE,
SMRAM_FIELD_CS_LIMIT,
SMRAM_FIELD_CS_SELECTOR_AR,
SMRAM_FIELD_SS_SELECTOR,
SMRAM_FIELD_SS_BASE,
SMRAM_FIELD_SS_LIMIT,
SMRAM_FIELD_SS_SELECTOR_AR,
SMRAM_FIELD_DS_SELECTOR,
SMRAM_FIELD_DS_BASE,
SMRAM_FIELD_DS_LIMIT,
SMRAM_FIELD_DS_SELECTOR_AR,
SMRAM_FIELD_FS_SELECTOR,
SMRAM_FIELD_FS_BASE,
SMRAM_FIELD_FS_LIMIT,
SMRAM_FIELD_FS_SELECTOR_AR,
SMRAM_FIELD_GS_SELECTOR,
SMRAM_FIELD_GS_BASE,
SMRAM_FIELD_GS_LIMIT,
SMRAM_FIELD_GS_SELECTOR_AR,
SMRAM_FIELD_LAST
};
#endif // BX_SUPPORT_X86_64
#endif

View File

@ -0,0 +1,162 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2001-2009 The Bochs Project
//
// 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
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA B 02110-1301 USA
/////////////////////////////////////////////////////////////////////////
#define NEED_CPU_REG_SHORTCUTS 1
#include "bochs.h"
#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 RSP ESP
#endif
void BX_CPP_AttrRegparmN(1) BX_CPU_C::BOUND_GwMa(bxInstruction_c *i)
{
Bit16s op1_16 = BX_READ_16BIT_REG(i->nnn());
Bit32u eaddr = (Bit32u) BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
Bit16s bound_min = (Bit16s) read_virtual_word_32(i->seg(), eaddr);
Bit16s bound_max = (Bit16s) read_virtual_word_32(i->seg(), (eaddr+2) & i->asize_mask());
if (op1_16 < bound_min || op1_16 > bound_max) {
BX_INFO(("BOUND_GdMa: fails bounds test"));
exception(BX_BR_EXCEPTION, 0);
}
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::BOUND_GdMa(bxInstruction_c *i)
{
Bit32s op1_32 = BX_READ_32BIT_REG(i->nnn());
Bit32u eaddr = (Bit32u) BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
Bit32s bound_min = (Bit32s) read_virtual_dword_32(i->seg(), eaddr);
Bit32s bound_max = (Bit32s) read_virtual_dword_32(i->seg(), (eaddr+4) & i->asize_mask());
if (op1_32 < bound_min || op1_32 > bound_max) {
BX_INFO(("BOUND_GdMa: fails bounds test"));
exception(BX_BR_EXCEPTION, 0);
}
}
// This is an undocumented instrucion (opcode 0xf1) which
// is useful for an ICE system
void BX_CPP_AttrRegparmN(1) BX_CPU_C::INT1(bxInstruction_c *i)
{
#if BX_SUPPORT_VMX
VMexit_Event(i, BX_PRIVILEGED_SOFTWARE_INTERRUPT, 1, 0, 0);
#endif
#if BX_DEBUGGER
BX_CPU_THIS_PTR show_flag |= Flag_softint;
#endif
BX_CPU_THIS_PTR EXT = 1;
// interrupt is not RSP safe
interrupt(1, BX_PRIVILEGED_SOFTWARE_INTERRUPT, 0, 0);
BX_CPU_THIS_PTR EXT = 0;
BX_INSTR_FAR_BRANCH(BX_CPU_ID, BX_INSTR_IS_INT,
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value,
EIP);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::INT3(bxInstruction_c *i)
{
// INT 3 is not IOPL sensitive
#if BX_SUPPORT_VMX
VMexit_Event(i, BX_SOFTWARE_EXCEPTION, 3, 0, 0);
#endif
#if BX_DEBUGGER
BX_CPU_THIS_PTR show_flag |= Flag_softint;
#endif
// interrupt is not RSP safe
interrupt(3, BX_SOFTWARE_EXCEPTION, 0, 0);
BX_INSTR_FAR_BRANCH(BX_CPU_ID, BX_INSTR_IS_INT,
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value,
EIP);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::INT_Ib(bxInstruction_c *i)
{
#if BX_DEBUGGER
BX_CPU_THIS_PTR show_flag |= Flag_softint;
#endif
Bit8u vector = i->Ib();
#if BX_SUPPORT_VMX
VMexit_Event(i, BX_SOFTWARE_INTERRUPT, vector, 0, 0);
#endif
#ifdef SHOW_EXIT_STATUS
if ((vector == 0x21) && (AH == 0x4c)) {
BX_INFO(("INT 21/4C called AL=0x%02x, BX=0x%04x", (unsigned) AL, (unsigned) BX));
}
#endif
RSP_SPECULATIVE;
if (v8086_mode()) {
// redirect interrupt through virtual-mode idt
if (v86_redirect_interrupt(vector)) goto done;
}
interrupt(vector, BX_SOFTWARE_INTERRUPT, 0, 0);
done:
RSP_COMMIT;
BX_INSTR_FAR_BRANCH(BX_CPU_ID, BX_INSTR_IS_INT,
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value,
EIP);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::INTO(bxInstruction_c *i)
{
if (get_OF()) {
#if BX_SUPPORT_VMX
VMexit_Event(i, BX_SOFTWARE_EXCEPTION, 4, 0, 0);
#endif
#if BX_DEBUGGER
BX_CPU_THIS_PTR show_flag |= Flag_softint;
#endif
// interrupt is not RSP safe
interrupt(4, BX_SOFTWARE_EXCEPTION, 0, 0);
BX_INSTR_FAR_BRANCH(BX_CPU_ID, BX_INSTR_IS_INT,
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value,
EIP);
}
}

2438
simulators/bochs/cpu/sse.cc Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

727
simulators/bochs/cpu/sse_rcp.cc Executable file
View File

@ -0,0 +1,727 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2003-2010 Stanislav Shwartsman
// 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
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA B 02110-1301 USA
//
/////////////////////////////////////////////////////////////////////////
#define NEED_CPU_REG_SHORTCUTS 1
#include "bochs.h"
#include "cpu.h"
#define LOG_THIS BX_CPU_THIS_PTR
#if BX_CPU_LEVEL >= 6
#include "fpu/softfloat-specialize.h"
BX_CPP_INLINE float32 convert_to_QNaN(float32 op)
{
return op | 0x00400000;
}
static Bit16u rcp_table[2048] = {
0x7ff0, 0x7fd0, 0x7fb0, 0x7f90, 0x7f70, 0x7f50, 0x7f30, 0x7f10,
0x7ef0, 0x7ed0, 0x7eb0, 0x7e90, 0x7e70, 0x7e50, 0x7e30, 0x7e10,
0x7df8, 0x7dd8, 0x7db8, 0x7d98, 0x7d78, 0x7d58, 0x7d38, 0x7d18,
0x7cf8, 0x7cd8, 0x7cb8, 0x7c98, 0x7c80, 0x7c60, 0x7c40, 0x7c20,
0x7c00, 0x7be0, 0x7bc0, 0x7ba0, 0x7b88, 0x7b68, 0x7b48, 0x7b28,
0x7b08, 0x7ae8, 0x7ac8, 0x7ab0, 0x7a90, 0x7a70, 0x7a50, 0x7a30,
0x7a10, 0x79f8, 0x79d8, 0x79b8, 0x7998, 0x7978, 0x7960, 0x7940,
0x7920, 0x7900, 0x78e0, 0x78c8, 0x78a8, 0x7888, 0x7868, 0x7850,
0x7830, 0x7810, 0x77f0, 0x77d8, 0x77b8, 0x7798, 0x7778, 0x7760,
0x7740, 0x7720, 0x7700, 0x76e8, 0x76c8, 0x76a8, 0x7690, 0x7670,
0x7650, 0x7630, 0x7618, 0x75f8, 0x75d8, 0x75c0, 0x75a0, 0x7580,
0x7568, 0x7548, 0x7528, 0x7510, 0x74f0, 0x74d0, 0x74b8, 0x7498,
0x7478, 0x7460, 0x7440, 0x7420, 0x7408, 0x73e8, 0x73d0, 0x73b0,
0x7390, 0x7378, 0x7358, 0x7338, 0x7320, 0x7300, 0x72e8, 0x72c8,
0x72a8, 0x7290, 0x7270, 0x7258, 0x7238, 0x7220, 0x7200, 0x71e0,
0x71c8, 0x71a8, 0x7190, 0x7170, 0x7158, 0x7138, 0x7118, 0x7100,
0x70e0, 0x70c8, 0x70a8, 0x7090, 0x7070, 0x7058, 0x7038, 0x7020,
0x7000, 0x6fe8, 0x6fc8, 0x6fb0, 0x6f90, 0x6f78, 0x6f58, 0x6f40,
0x6f20, 0x6f08, 0x6ee8, 0x6ed0, 0x6eb0, 0x6e98, 0x6e78, 0x6e60,
0x6e40, 0x6e28, 0x6e08, 0x6df0, 0x6dd0, 0x6db8, 0x6da0, 0x6d80,
0x6d68, 0x6d48, 0x6d30, 0x6d10, 0x6cf8, 0x6cd8, 0x6cc0, 0x6ca8,
0x6c88, 0x6c70, 0x6c50, 0x6c38, 0x6c20, 0x6c00, 0x6be8, 0x6bc8,
0x6bb0, 0x6b98, 0x6b78, 0x6b60, 0x6b40, 0x6b28, 0x6b10, 0x6af0,
0x6ad8, 0x6ac0, 0x6aa0, 0x6a88, 0x6a70, 0x6a50, 0x6a38, 0x6a20,
0x6a00, 0x69e8, 0x69c8, 0x69b0, 0x6998, 0x6978, 0x6960, 0x6948,
0x6930, 0x6910, 0x68f8, 0x68e0, 0x68c0, 0x68a8, 0x6890, 0x6870,
0x6858, 0x6840, 0x6820, 0x6808, 0x67f0, 0x67d8, 0x67b8, 0x67a0,
0x6788, 0x6770, 0x6750, 0x6738, 0x6720, 0x6700, 0x66e8, 0x66d0,
0x66b8, 0x6698, 0x6680, 0x6668, 0x6650, 0x6638, 0x6618, 0x6600,
0x65e8, 0x65d0, 0x65b0, 0x6598, 0x6580, 0x6568, 0x6550, 0x6530,
0x6518, 0x6500, 0x64e8, 0x64c8, 0x64b0, 0x6498, 0x6480, 0x6468,
0x6450, 0x6430, 0x6418, 0x6400, 0x63e8, 0x63d0, 0x63b8, 0x6398,
0x6380, 0x6368, 0x6350, 0x6338, 0x6320, 0x6300, 0x62e8, 0x62d0,
0x62b8, 0x62a0, 0x6288, 0x6270, 0x6250, 0x6238, 0x6220, 0x6208,
0x61f0, 0x61d8, 0x61c0, 0x61a8, 0x6190, 0x6170, 0x6158, 0x6140,
0x6128, 0x6110, 0x60f8, 0x60e0, 0x60c8, 0x60b0, 0x6098, 0x6080,
0x6060, 0x6048, 0x6030, 0x6018, 0x6000, 0x5fe8, 0x5fd0, 0x5fb8,
0x5fa0, 0x5f88, 0x5f70, 0x5f58, 0x5f40, 0x5f28, 0x5f10, 0x5ef8,
0x5ee0, 0x5ec8, 0x5eb0, 0x5e98, 0x5e80, 0x5e68, 0x5e50, 0x5e30,
0x5e18, 0x5e00, 0x5de8, 0x5dd0, 0x5db8, 0x5da0, 0x5d88, 0x5d70,
0x5d58, 0x5d40, 0x5d30, 0x5d18, 0x5d00, 0x5ce8, 0x5cd0, 0x5cb8,
0x5ca0, 0x5c88, 0x5c70, 0x5c58, 0x5c40, 0x5c28, 0x5c10, 0x5bf8,
0x5be0, 0x5bc8, 0x5bb0, 0x5b98, 0x5b80, 0x5b68, 0x5b50, 0x5b38,
0x5b20, 0x5b08, 0x5af8, 0x5ae0, 0x5ac8, 0x5ab0, 0x5a98, 0x5a80,
0x5a68, 0x5a50, 0x5a38, 0x5a20, 0x5a08, 0x59f8, 0x59e0, 0x59c8,
0x59b0, 0x5998, 0x5980, 0x5968, 0x5950, 0x5938, 0x5928, 0x5910,
0x58f8, 0x58e0, 0x58c8, 0x58b0, 0x5898, 0x5880, 0x5870, 0x5858,
0x5840, 0x5828, 0x5810, 0x57f8, 0x57e0, 0x57d0, 0x57b8, 0x57a0,
0x5788, 0x5770, 0x5758, 0x5748, 0x5730, 0x5718, 0x5700, 0x56e8,
0x56d0, 0x56c0, 0x56a8, 0x5690, 0x5678, 0x5660, 0x5650, 0x5638,
0x5620, 0x5608, 0x55f0, 0x55e0, 0x55c8, 0x55b0, 0x5598, 0x5588,
0x5570, 0x5558, 0x5540, 0x5528, 0x5518, 0x5500, 0x54e8, 0x54d0,
0x54c0, 0x54a8, 0x5490, 0x5478, 0x5468, 0x5450, 0x5438, 0x5420,
0x5410, 0x53f8, 0x53e0, 0x53c8, 0x53b8, 0x53a0, 0x5388, 0x5370,
0x5360, 0x5348, 0x5330, 0x5318, 0x5308, 0x52f0, 0x52d8, 0x52c8,
0x52b0, 0x5298, 0x5280, 0x5270, 0x5258, 0x5240, 0x5230, 0x5218,
0x5200, 0x51f0, 0x51d8, 0x51c0, 0x51b0, 0x5198, 0x5180, 0x5170,
0x5158, 0x5140, 0x5128, 0x5118, 0x5100, 0x50e8, 0x50d8, 0x50c0,
0x50a8, 0x5098, 0x5080, 0x5070, 0x5058, 0x5040, 0x5030, 0x5018,
0x5000, 0x4ff0, 0x4fd8, 0x4fc0, 0x4fb0, 0x4f98, 0x4f80, 0x4f70,
0x4f58, 0x4f48, 0x4f30, 0x4f18, 0x4f08, 0x4ef0, 0x4ee0, 0x4ec8,
0x4eb0, 0x4ea0, 0x4e88, 0x4e78, 0x4e60, 0x4e48, 0x4e38, 0x4e20,
0x4e10, 0x4df8, 0x4de0, 0x4dd0, 0x4db8, 0x4da8, 0x4d90, 0x4d78,
0x4d68, 0x4d50, 0x4d40, 0x4d28, 0x4d18, 0x4d00, 0x4ce8, 0x4cd8,
0x4cc0, 0x4cb0, 0x4c98, 0x4c88, 0x4c70, 0x4c60, 0x4c48, 0x4c30,
0x4c20, 0x4c08, 0x4bf8, 0x4be0, 0x4bd0, 0x4bb8, 0x4ba8, 0x4b90,
0x4b80, 0x4b68, 0x4b58, 0x4b40, 0x4b30, 0x4b18, 0x4b08, 0x4af0,
0x4ad8, 0x4ac8, 0x4ab0, 0x4aa0, 0x4a88, 0x4a78, 0x4a60, 0x4a50,
0x4a38, 0x4a28, 0x4a10, 0x4a00, 0x49e8, 0x49d8, 0x49c8, 0x49b0,
0x49a0, 0x4988, 0x4978, 0x4960, 0x4950, 0x4938, 0x4928, 0x4910,
0x4900, 0x48e8, 0x48d8, 0x48c0, 0x48b0, 0x4898, 0x4888, 0x4878,
0x4860, 0x4850, 0x4838, 0x4828, 0x4810, 0x4800, 0x47e8, 0x47d8,
0x47c8, 0x47b0, 0x47a0, 0x4788, 0x4778, 0x4760, 0x4750, 0x4740,
0x4728, 0x4718, 0x4700, 0x46f0, 0x46d8, 0x46c8, 0x46b8, 0x46a0,
0x4690, 0x4678, 0x4668, 0x4658, 0x4640, 0x4630, 0x4618, 0x4608,
0x45f8, 0x45e0, 0x45d0, 0x45b8, 0x45a8, 0x4598, 0x4580, 0x4570,
0x4560, 0x4548, 0x4538, 0x4520, 0x4510, 0x4500, 0x44e8, 0x44d8,
0x44c8, 0x44b0, 0x44a0, 0x4488, 0x4478, 0x4468, 0x4450, 0x4440,
0x4430, 0x4418, 0x4408, 0x43f8, 0x43e0, 0x43d0, 0x43c0, 0x43a8,
0x4398, 0x4388, 0x4370, 0x4360, 0x4350, 0x4338, 0x4328, 0x4318,
0x4300, 0x42f0, 0x42e0, 0x42c8, 0x42b8, 0x42a8, 0x4290, 0x4280,
0x4270, 0x4260, 0x4248, 0x4238, 0x4228, 0x4210, 0x4200, 0x41f0,
0x41d8, 0x41c8, 0x41b8, 0x41a8, 0x4190, 0x4180, 0x4170, 0x4158,
0x4148, 0x4138, 0x4128, 0x4110, 0x4100, 0x40f0, 0x40d8, 0x40c8,
0x40b8, 0x40a8, 0x4090, 0x4080, 0x4070, 0x4060, 0x4048, 0x4038,
0x4028, 0x4018, 0x4000, 0x3ff0, 0x3fe0, 0x3fd0, 0x3fb8, 0x3fa8,
0x3f98, 0x3f88, 0x3f70, 0x3f60, 0x3f50, 0x3f40, 0x3f28, 0x3f18,
0x3f08, 0x3ef8, 0x3ee8, 0x3ed0, 0x3ec0, 0x3eb0, 0x3ea0, 0x3e88,
0x3e78, 0x3e68, 0x3e58, 0x3e48, 0x3e30, 0x3e20, 0x3e10, 0x3e00,
0x3df0, 0x3dd8, 0x3dc8, 0x3db8, 0x3da8, 0x3d98, 0x3d80, 0x3d70,
0x3d60, 0x3d50, 0x3d40, 0x3d28, 0x3d18, 0x3d08, 0x3cf8, 0x3ce8,
0x3cd8, 0x3cc0, 0x3cb0, 0x3ca0, 0x3c90, 0x3c80, 0x3c70, 0x3c58,
0x3c48, 0x3c38, 0x3c28, 0x3c18, 0x3c08, 0x3bf0, 0x3be0, 0x3bd0,
0x3bc0, 0x3bb0, 0x3ba0, 0x3b90, 0x3b78, 0x3b68, 0x3b58, 0x3b48,
0x3b38, 0x3b28, 0x3b18, 0x3b00, 0x3af0, 0x3ae0, 0x3ad0, 0x3ac0,
0x3ab0, 0x3aa0, 0x3a88, 0x3a78, 0x3a68, 0x3a58, 0x3a48, 0x3a38,
0x3a28, 0x3a18, 0x3a08, 0x39f0, 0x39e0, 0x39d0, 0x39c0, 0x39b0,
0x39a0, 0x3990, 0x3980, 0x3970, 0x3958, 0x3948, 0x3938, 0x3928,
0x3918, 0x3908, 0x38f8, 0x38e8, 0x38d8, 0x38c8, 0x38b8, 0x38a8,
0x3890, 0x3880, 0x3870, 0x3860, 0x3850, 0x3840, 0x3830, 0x3820,
0x3810, 0x3800, 0x37f0, 0x37e0, 0x37d0, 0x37c0, 0x37a8, 0x3798,
0x3788, 0x3778, 0x3768, 0x3758, 0x3748, 0x3738, 0x3728, 0x3718,
0x3708, 0x36f8, 0x36e8, 0x36d8, 0x36c8, 0x36b8, 0x36a8, 0x3698,
0x3688, 0x3678, 0x3668, 0x3658, 0x3648, 0x3630, 0x3620, 0x3610,
0x3600, 0x35f0, 0x35e0, 0x35d0, 0x35c0, 0x35b0, 0x35a0, 0x3590,
0x3580, 0x3570, 0x3560, 0x3550, 0x3540, 0x3530, 0x3520, 0x3510,
0x3500, 0x34f0, 0x34e0, 0x34d0, 0x34c0, 0x34b0, 0x34a0, 0x3490,
0x3480, 0x3470, 0x3460, 0x3450, 0x3440, 0x3430, 0x3420, 0x3410,
0x3400, 0x33f0, 0x33e0, 0x33d0, 0x33c8, 0x33b8, 0x33a8, 0x3398,
0x3388, 0x3378, 0x3368, 0x3358, 0x3348, 0x3338, 0x3328, 0x3318,
0x3308, 0x32f8, 0x32e8, 0x32d8, 0x32c8, 0x32b8, 0x32a8, 0x3298,
0x3288, 0x3278, 0x3268, 0x3260, 0x3250, 0x3240, 0x3230, 0x3220,
0x3210, 0x3200, 0x31f0, 0x31e0, 0x31d0, 0x31c0, 0x31b0, 0x31a0,
0x3190, 0x3180, 0x3178, 0x3168, 0x3158, 0x3148, 0x3138, 0x3128,
0x3118, 0x3108, 0x30f8, 0x30e8, 0x30d8, 0x30c8, 0x30c0, 0x30b0,
0x30a0, 0x3090, 0x3080, 0x3070, 0x3060, 0x3050, 0x3040, 0x3030,
0x3028, 0x3018, 0x3008, 0x2ff8, 0x2fe8, 0x2fd8, 0x2fc8, 0x2fb8,
0x2fa8, 0x2fa0, 0x2f90, 0x2f80, 0x2f70, 0x2f60, 0x2f50, 0x2f40,
0x2f30, 0x2f28, 0x2f18, 0x2f08, 0x2ef8, 0x2ee8, 0x2ed8, 0x2ec8,
0x2eb8, 0x2eb0, 0x2ea0, 0x2e90, 0x2e80, 0x2e70, 0x2e60, 0x2e50,
0x2e48, 0x2e38, 0x2e28, 0x2e18, 0x2e08, 0x2df8, 0x2df0, 0x2de0,
0x2dd0, 0x2dc0, 0x2db0, 0x2da0, 0x2d90, 0x2d88, 0x2d78, 0x2d68,
0x2d58, 0x2d48, 0x2d38, 0x2d30, 0x2d20, 0x2d10, 0x2d00, 0x2cf0,
0x2ce0, 0x2cd8, 0x2cc8, 0x2cb8, 0x2ca8, 0x2c98, 0x2c90, 0x2c80,
0x2c70, 0x2c60, 0x2c50, 0x2c40, 0x2c38, 0x2c28, 0x2c18, 0x2c08,
0x2bf8, 0x2bf0, 0x2be0, 0x2bd0, 0x2bc0, 0x2bb0, 0x2ba8, 0x2b98,
0x2b88, 0x2b78, 0x2b68, 0x2b60, 0x2b50, 0x2b40, 0x2b30, 0x2b20,
0x2b18, 0x2b08, 0x2af8, 0x2ae8, 0x2ae0, 0x2ad0, 0x2ac0, 0x2ab0,
0x2aa0, 0x2a98, 0x2a88, 0x2a78, 0x2a68, 0x2a60, 0x2a50, 0x2a40,
0x2a30, 0x2a20, 0x2a18, 0x2a08, 0x29f8, 0x29e8, 0x29e0, 0x29d0,
0x29c0, 0x29b0, 0x29a8, 0x2998, 0x2988, 0x2978, 0x2970, 0x2960,
0x2950, 0x2940, 0x2938, 0x2928, 0x2918, 0x2908, 0x2900, 0x28f0,
0x28e0, 0x28d0, 0x28c8, 0x28b8, 0x28a8, 0x2898, 0x2890, 0x2880,
0x2870, 0x2868, 0x2858, 0x2848, 0x2838, 0x2830, 0x2820, 0x2810,
0x2800, 0x27f8, 0x27e8, 0x27d8, 0x27d0, 0x27c0, 0x27b0, 0x27a0,
0x2798, 0x2788, 0x2778, 0x2770, 0x2760, 0x2750, 0x2740, 0x2738,
0x2728, 0x2718, 0x2710, 0x2700, 0x26f0, 0x26e8, 0x26d8, 0x26c8,
0x26b8, 0x26b0, 0x26a0, 0x2690, 0x2688, 0x2678, 0x2668, 0x2660,
0x2650, 0x2640, 0x2638, 0x2628, 0x2618, 0x2608, 0x2600, 0x25f0,
0x25e0, 0x25d8, 0x25c8, 0x25b8, 0x25b0, 0x25a0, 0x2590, 0x2588,
0x2578, 0x2568, 0x2560, 0x2550, 0x2540, 0x2538, 0x2528, 0x2518,
0x2510, 0x2500, 0x24f0, 0x24e8, 0x24d8, 0x24c8, 0x24c0, 0x24b0,
0x24a0, 0x2498, 0x2488, 0x2478, 0x2470, 0x2460, 0x2450, 0x2448,
0x2438, 0x2430, 0x2420, 0x2410, 0x2408, 0x23f8, 0x23e8, 0x23e0,
0x23d0, 0x23c0, 0x23b8, 0x23a8, 0x23a0, 0x2390, 0x2380, 0x2378,
0x2368, 0x2358, 0x2350, 0x2340, 0x2330, 0x2328, 0x2318, 0x2310,
0x2300, 0x22f0, 0x22e8, 0x22d8, 0x22d0, 0x22c0, 0x22b0, 0x22a8,
0x2298, 0x2288, 0x2280, 0x2270, 0x2268, 0x2258, 0x2248, 0x2240,
0x2230, 0x2228, 0x2218, 0x2208, 0x2200, 0x21f0, 0x21e8, 0x21d8,
0x21c8, 0x21c0, 0x21b0, 0x21a8, 0x2198, 0x2188, 0x2180, 0x2170,
0x2168, 0x2158, 0x2148, 0x2140, 0x2130, 0x2128, 0x2118, 0x2108,
0x2100, 0x20f0, 0x20e8, 0x20d8, 0x20d0, 0x20c0, 0x20b0, 0x20a8,
0x2098, 0x2090, 0x2080, 0x2078, 0x2068, 0x2058, 0x2050, 0x2040,
0x2038, 0x2028, 0x2020, 0x2010, 0x2000, 0x1ff8, 0x1fe8, 0x1fe0,
0x1fd0, 0x1fc8, 0x1fb8, 0x1fb0, 0x1fa0, 0x1f90, 0x1f88, 0x1f78,
0x1f70, 0x1f60, 0x1f58, 0x1f48, 0x1f40, 0x1f30, 0x1f20, 0x1f18,
0x1f08, 0x1f00, 0x1ef0, 0x1ee8, 0x1ed8, 0x1ed0, 0x1ec0, 0x1eb8,
0x1ea8, 0x1ea0, 0x1e90, 0x1e80, 0x1e78, 0x1e68, 0x1e60, 0x1e50,
0x1e48, 0x1e38, 0x1e30, 0x1e20, 0x1e18, 0x1e08, 0x1e00, 0x1df0,
0x1de8, 0x1dd8, 0x1dd0, 0x1dc0, 0x1db8, 0x1da8, 0x1da0, 0x1d90,
0x1d80, 0x1d78, 0x1d68, 0x1d60, 0x1d50, 0x1d48, 0x1d38, 0x1d30,
0x1d20, 0x1d18, 0x1d08, 0x1d00, 0x1cf0, 0x1ce8, 0x1cd8, 0x1cd0,
0x1cc0, 0x1cb8, 0x1ca8, 0x1ca0, 0x1c90, 0x1c88, 0x1c78, 0x1c70,
0x1c60, 0x1c58, 0x1c48, 0x1c40, 0x1c30, 0x1c28, 0x1c18, 0x1c10,
0x1c00, 0x1bf8, 0x1bf0, 0x1be0, 0x1bd8, 0x1bc8, 0x1bc0, 0x1bb0,
0x1ba8, 0x1b98, 0x1b90, 0x1b80, 0x1b78, 0x1b68, 0x1b60, 0x1b50,
0x1b48, 0x1b38, 0x1b30, 0x1b20, 0x1b18, 0x1b08, 0x1b00, 0x1af8,
0x1ae8, 0x1ae0, 0x1ad0, 0x1ac8, 0x1ab8, 0x1ab0, 0x1aa0, 0x1a98,
0x1a88, 0x1a80, 0x1a70, 0x1a68, 0x1a60, 0x1a50, 0x1a48, 0x1a38,
0x1a30, 0x1a20, 0x1a18, 0x1a08, 0x1a00, 0x19f8, 0x19e8, 0x19e0,
0x19d0, 0x19c8, 0x19b8, 0x19b0, 0x19a0, 0x1998, 0x1990, 0x1980,
0x1978, 0x1968, 0x1960, 0x1950, 0x1948, 0x1938, 0x1930, 0x1928,
0x1918, 0x1910, 0x1900, 0x18f8, 0x18e8, 0x18e0, 0x18d8, 0x18c8,
0x18c0, 0x18b0, 0x18a8, 0x1898, 0x1890, 0x1888, 0x1878, 0x1870,
0x1860, 0x1858, 0x1850, 0x1840, 0x1838, 0x1828, 0x1820, 0x1810,
0x1808, 0x1800, 0x17f0, 0x17e8, 0x17d8, 0x17d0, 0x17c8, 0x17b8,
0x17b0, 0x17a0, 0x1798, 0x1790, 0x1780, 0x1778, 0x1768, 0x1760,
0x1758, 0x1748, 0x1740, 0x1730, 0x1728, 0x1720, 0x1710, 0x1708,
0x16f8, 0x16f0, 0x16e8, 0x16d8, 0x16d0, 0x16c8, 0x16b8, 0x16b0,
0x16a0, 0x1698, 0x1690, 0x1680, 0x1678, 0x1668, 0x1660, 0x1658,
0x1648, 0x1640, 0x1638, 0x1628, 0x1620, 0x1610, 0x1608, 0x1600,
0x15f0, 0x15e8, 0x15e0, 0x15d0, 0x15c8, 0x15b8, 0x15b0, 0x15a8,
0x1598, 0x1590, 0x1588, 0x1578, 0x1570, 0x1568, 0x1558, 0x1550,
0x1540, 0x1538, 0x1530, 0x1520, 0x1518, 0x1510, 0x1500, 0x14f8,
0x14f0, 0x14e0, 0x14d8, 0x14d0, 0x14c0, 0x14b8, 0x14a8, 0x14a0,
0x1498, 0x1488, 0x1480, 0x1478, 0x1468, 0x1460, 0x1458, 0x1448,
0x1440, 0x1438, 0x1428, 0x1420, 0x1418, 0x1408, 0x1400, 0x13f8,
0x13e8, 0x13e0, 0x13d8, 0x13c8, 0x13c0, 0x13b8, 0x13a8, 0x13a0,
0x1398, 0x1388, 0x1380, 0x1378, 0x1368, 0x1360, 0x1358, 0x1348,
0x1340, 0x1338, 0x1328, 0x1320, 0x1318, 0x1308, 0x1300, 0x12f8,
0x12e8, 0x12e0, 0x12d8, 0x12d0, 0x12c0, 0x12b8, 0x12b0, 0x12a0,
0x1298, 0x1290, 0x1280, 0x1278, 0x1270, 0x1260, 0x1258, 0x1250,
0x1240, 0x1238, 0x1230, 0x1228, 0x1218, 0x1210, 0x1208, 0x11f8,
0x11f0, 0x11e8, 0x11d8, 0x11d0, 0x11c8, 0x11c0, 0x11b0, 0x11a8,
0x11a0, 0x1190, 0x1188, 0x1180, 0x1178, 0x1168, 0x1160, 0x1158,
0x1148, 0x1140, 0x1138, 0x1128, 0x1120, 0x1118, 0x1110, 0x1100,
0x10f8, 0x10f0, 0x10e8, 0x10d8, 0x10d0, 0x10c8, 0x10b8, 0x10b0,
0x10a8, 0x10a0, 0x1090, 0x1088, 0x1080, 0x1070, 0x1068, 0x1060,
0x1058, 0x1048, 0x1040, 0x1038, 0x1030, 0x1020, 0x1018, 0x1010,
0x1000, 0x0ff8, 0x0ff0, 0x0fe8, 0x0fd8, 0x0fd0, 0x0fc8, 0x0fc0,
0x0fb0, 0x0fa8, 0x0fa0, 0x0f98, 0x0f88, 0x0f80, 0x0f78, 0x0f70,
0x0f60, 0x0f58, 0x0f50, 0x0f48, 0x0f38, 0x0f30, 0x0f28, 0x0f20,
0x0f10, 0x0f08, 0x0f00, 0x0ef8, 0x0ee8, 0x0ee0, 0x0ed8, 0x0ed0,
0x0ec0, 0x0eb8, 0x0eb0, 0x0ea8, 0x0e98, 0x0e90, 0x0e88, 0x0e80,
0x0e70, 0x0e68, 0x0e60, 0x0e58, 0x0e48, 0x0e40, 0x0e38, 0x0e30,
0x0e28, 0x0e18, 0x0e10, 0x0e08, 0x0e00, 0x0df0, 0x0de8, 0x0de0,
0x0dd8, 0x0dc8, 0x0dc0, 0x0db8, 0x0db0, 0x0da8, 0x0d98, 0x0d90,
0x0d88, 0x0d80, 0x0d70, 0x0d68, 0x0d60, 0x0d58, 0x0d50, 0x0d40,
0x0d38, 0x0d30, 0x0d28, 0x0d18, 0x0d10, 0x0d08, 0x0d00, 0x0cf8,
0x0ce8, 0x0ce0, 0x0cd8, 0x0cd0, 0x0cc8, 0x0cb8, 0x0cb0, 0x0ca8,
0x0ca0, 0x0c98, 0x0c88, 0x0c80, 0x0c78, 0x0c70, 0x0c60, 0x0c58,
0x0c50, 0x0c48, 0x0c40, 0x0c30, 0x0c28, 0x0c20, 0x0c18, 0x0c10,
0x0c00, 0x0bf8, 0x0bf0, 0x0be8, 0x0be0, 0x0bd8, 0x0bc8, 0x0bc0,
0x0bb8, 0x0bb0, 0x0ba8, 0x0b98, 0x0b90, 0x0b88, 0x0b80, 0x0b78,
0x0b68, 0x0b60, 0x0b58, 0x0b50, 0x0b48, 0x0b40, 0x0b30, 0x0b28,
0x0b20, 0x0b18, 0x0b10, 0x0b00, 0x0af8, 0x0af0, 0x0ae8, 0x0ae0,
0x0ad8, 0x0ac8, 0x0ac0, 0x0ab8, 0x0ab0, 0x0aa8, 0x0a98, 0x0a90,
0x0a88, 0x0a80, 0x0a78, 0x0a70, 0x0a60, 0x0a58, 0x0a50, 0x0a48,
0x0a40, 0x0a38, 0x0a28, 0x0a20, 0x0a18, 0x0a10, 0x0a08, 0x0a00,
0x09f0, 0x09e8, 0x09e0, 0x09d8, 0x09d0, 0x09c8, 0x09c0, 0x09b0,
0x09a8, 0x09a0, 0x0998, 0x0990, 0x0988, 0x0978, 0x0970, 0x0968,
0x0960, 0x0958, 0x0950, 0x0948, 0x0938, 0x0930, 0x0928, 0x0920,
0x0918, 0x0910, 0x0900, 0x08f8, 0x08f0, 0x08e8, 0x08e0, 0x08d8,
0x08d0, 0x08c0, 0x08b8, 0x08b0, 0x08a8, 0x08a0, 0x0898, 0x0890,
0x0880, 0x0878, 0x0870, 0x0868, 0x0860, 0x0858, 0x0850, 0x0848,
0x0838, 0x0830, 0x0828, 0x0820, 0x0818, 0x0810, 0x0808, 0x0800,
0x07f0, 0x07e8, 0x07e0, 0x07d8, 0x07d0, 0x07c8, 0x07c0, 0x07b0,
0x07a8, 0x07a0, 0x0798, 0x0790, 0x0788, 0x0780, 0x0778, 0x0770,
0x0760, 0x0758, 0x0750, 0x0748, 0x0740, 0x0738, 0x0730, 0x0728,
0x0718, 0x0710, 0x0708, 0x0700, 0x06f8, 0x06f0, 0x06e8, 0x06e0,
0x06d8, 0x06c8, 0x06c0, 0x06b8, 0x06b0, 0x06a8, 0x06a0, 0x0698,
0x0690, 0x0688, 0x0680, 0x0670, 0x0668, 0x0660, 0x0658, 0x0650,
0x0648, 0x0640, 0x0638, 0x0630, 0x0620, 0x0618, 0x0610, 0x0608,
0x0600, 0x05f8, 0x05f0, 0x05e8, 0x05e0, 0x05d8, 0x05d0, 0x05c0,
0x05b8, 0x05b0, 0x05a8, 0x05a0, 0x0598, 0x0590, 0x0588, 0x0580,
0x0578, 0x0570, 0x0560, 0x0558, 0x0550, 0x0548, 0x0540, 0x0538,
0x0530, 0x0528, 0x0520, 0x0518, 0x0510, 0x0508, 0x04f8, 0x04f0,
0x04e8, 0x04e0, 0x04d8, 0x04d0, 0x04c8, 0x04c0, 0x04b8, 0x04b0,
0x04a8, 0x04a0, 0x0498, 0x0488, 0x0480, 0x0478, 0x0470, 0x0468,
0x0460, 0x0458, 0x0450, 0x0448, 0x0440, 0x0438, 0x0430, 0x0428,
0x0420, 0x0418, 0x0408, 0x0400, 0x03f8, 0x03f0, 0x03e8, 0x03e0,
0x03d8, 0x03d0, 0x03c8, 0x03c0, 0x03b8, 0x03b0, 0x03a8, 0x03a0,
0x0398, 0x0390, 0x0388, 0x0378, 0x0370, 0x0368, 0x0360, 0x0358,
0x0350, 0x0348, 0x0340, 0x0338, 0x0330, 0x0328, 0x0320, 0x0318,
0x0310, 0x0308, 0x0300, 0x02f8, 0x02f0, 0x02e8, 0x02d8, 0x02d0,
0x02c8, 0x02c0, 0x02b8, 0x02b0, 0x02a8, 0x02a0, 0x0298, 0x0290,
0x0288, 0x0280, 0x0278, 0x0270, 0x0268, 0x0260, 0x0258, 0x0250,
0x0248, 0x0240, 0x0238, 0x0230, 0x0228, 0x0220, 0x0218, 0x0210,
0x0200, 0x01f8, 0x01f0, 0x01e8, 0x01e0, 0x01d8, 0x01d0, 0x01c8,
0x01c0, 0x01b8, 0x01b0, 0x01a8, 0x01a0, 0x0198, 0x0190, 0x0188,
0x0180, 0x0178, 0x0170, 0x0168, 0x0160, 0x0158, 0x0150, 0x0148,
0x0140, 0x0138, 0x0130, 0x0128, 0x0120, 0x0118, 0x0110, 0x0108,
0x0100, 0x00f8, 0x00f0, 0x00e8, 0x00e0, 0x00d8, 0x00d0, 0x00c8,
0x00c0, 0x00b8, 0x00b0, 0x00a8, 0x00a0, 0x0098, 0x0090, 0x0088,
0x0080, 0x0078, 0x0070, 0x0068, 0x0060, 0x0058, 0x0050, 0x0048,
0x0040, 0x0038, 0x0030, 0x0028, 0x0020, 0x0018, 0x0010, 0x0008
};
// approximate reciprocal of scalar single precision FP
static float32 approximate_rcp(float32 op)
{
float_class_t op_class = float32_class(op);
int sign = float32_sign(op);
switch(op_class)
{
case float_zero:
case float_denormal:
return packFloat32(sign, 0xFF, 0);
case float_negative_inf:
case float_positive_inf:
return packFloat32(sign, 0x00, 0);
case float_NaN:
return convert_to_QNaN(op);
case float_normalized:
break;
}
Bit32u fraction = float32_fraction(op);
Bit16s exp = float32_exp(op);
/*
* Calculate (1/1.yyyyyyyyyyy1), the result is always rounded to the
* 12th bit after the decimal point by round-to-nearest, regardless
* of the current rounding mode.
*
* Using precalculated 2048-entry table.
*/
exp = 253 - exp;
/* check for underflow */
if (exp <= 0)
return packFloat32(sign, 0x00, 0);
return packFloat32(sign, exp, (Bit32u)(rcp_table[fraction >> 12]) << 8);
}
#endif
/*
* Opcode: 0F 53
* Approximate reciprocals of packed single precision FP values from XMM2/MEM.
* Possible floating point exceptions: -
*/
void BX_CPP_AttrRegparmN(1) BX_CPU_C::RCPPS_VpsWpsR(bxInstruction_c *i)
{
#if BX_CPU_LEVEL >= 6
BxPackedXmmRegister op = BX_READ_XMM_REG(i->rm());
op.xmm32u(0) = approximate_rcp(op.xmm32u(0));
op.xmm32u(1) = approximate_rcp(op.xmm32u(1));
op.xmm32u(2) = approximate_rcp(op.xmm32u(2));
op.xmm32u(3) = approximate_rcp(op.xmm32u(3));
BX_WRITE_XMM_REG(i->nnn(), op);
#endif
}
/*
* Opcode: F3 0F 53
* Approximate reciprocal of scalar single precision FP value from XMM2/MEM32.
* Possible floating point exceptions: -
*/
void BX_CPP_AttrRegparmN(1) BX_CPU_C::RCPSS_VssWssR(bxInstruction_c *i)
{
#if BX_CPU_LEVEL >= 6
float32 op = BX_READ_XMM_REG_LO_DWORD(i->rm());
op = approximate_rcp(op);
BX_WRITE_XMM_REG_LO_DWORD(i->nnn(), op);
#endif
}
#if BX_CPU_LEVEL >= 6
Bit16u rsqrt_table0[1024] =
{
0x34f8, 0x34e0, 0x34d0, 0x34b8, 0x34a0, 0x3488, 0x3470, 0x3460,
0x3448, 0x3430, 0x3418, 0x3400, 0x33f0, 0x33d8, 0x33c0, 0x33a8,
0x3398, 0x3380, 0x3368, 0x3350, 0x3338, 0x3328, 0x3310, 0x32f8,
0x32e8, 0x32d0, 0x32b8, 0x32a0, 0x3290, 0x3278, 0x3260, 0x3250,
0x3238, 0x3220, 0x3208, 0x31f8, 0x31e0, 0x31c8, 0x31b8, 0x31a0,
0x3188, 0x3178, 0x3160, 0x3148, 0x3138, 0x3120, 0x3108, 0x30f8,
0x30e0, 0x30c8, 0x30b8, 0x30a0, 0x3090, 0x3078, 0x3060, 0x3050,
0x3038, 0x3028, 0x3010, 0x2ff8, 0x2fe8, 0x2fd0, 0x2fc0, 0x2fa8,
0x2f90, 0x2f80, 0x2f68, 0x2f58, 0x2f40, 0x2f30, 0x2f18, 0x2f00,
0x2ef0, 0x2ed8, 0x2ec8, 0x2eb0, 0x2ea0, 0x2e88, 0x2e78, 0x2e60,
0x2e50, 0x2e38, 0x2e20, 0x2e10, 0x2df8, 0x2de8, 0x2dd0, 0x2dc0,
0x2da8, 0x2d98, 0x2d80, 0x2d70, 0x2d58, 0x2d48, 0x2d38, 0x2d20,
0x2d10, 0x2cf8, 0x2ce8, 0x2cd0, 0x2cc0, 0x2ca8, 0x2c98, 0x2c80,
0x2c70, 0x2c58, 0x2c48, 0x2c38, 0x2c20, 0x2c10, 0x2bf8, 0x2be8,
0x2bd0, 0x2bc0, 0x2bb0, 0x2b98, 0x2b88, 0x2b70, 0x2b60, 0x2b50,
0x2b38, 0x2b28, 0x2b10, 0x2b00, 0x2af0, 0x2ad8, 0x2ac8, 0x2ab8,
0x2aa0, 0x2a90, 0x2a78, 0x2a68, 0x2a58, 0x2a40, 0x2a30, 0x2a20,
0x2a08, 0x29f8, 0x29e8, 0x29d0, 0x29c0, 0x29b0, 0x2998, 0x2988,
0x2978, 0x2960, 0x2950, 0x2940, 0x2928, 0x2918, 0x2908, 0x28f0,
0x28e0, 0x28d0, 0x28c0, 0x28a8, 0x2898, 0x2888, 0x2870, 0x2860,
0x2850, 0x2840, 0x2828, 0x2818, 0x2808, 0x27f8, 0x27e0, 0x27d0,
0x27c0, 0x27b0, 0x2798, 0x2788, 0x2778, 0x2768, 0x2750, 0x2740,
0x2730, 0x2720, 0x2708, 0x26f8, 0x26e8, 0x26d8, 0x26c8, 0x26b0,
0x26a0, 0x2690, 0x2680, 0x2670, 0x2658, 0x2648, 0x2638, 0x2628,
0x2618, 0x2600, 0x25f0, 0x25e0, 0x25d0, 0x25c0, 0x25b0, 0x2598,
0x2588, 0x2578, 0x2568, 0x2558, 0x2548, 0x2530, 0x2520, 0x2510,
0x2500, 0x24f0, 0x24e0, 0x24d0, 0x24b8, 0x24a8, 0x2498, 0x2488,
0x2478, 0x2468, 0x2458, 0x2448, 0x2430, 0x2420, 0x2410, 0x2400,
0x23f0, 0x23e0, 0x23d0, 0x23c0, 0x23b0, 0x23a0, 0x2388, 0x2378,
0x2368, 0x2358, 0x2348, 0x2338, 0x2328, 0x2318, 0x2308, 0x22f8,
0x22e8, 0x22d8, 0x22c8, 0x22b8, 0x22a8, 0x2290, 0x2280, 0x2270,
0x2260, 0x2250, 0x2240, 0x2230, 0x2220, 0x2210, 0x2200, 0x21f0,
0x21e0, 0x21d0, 0x21c0, 0x21b0, 0x21a0, 0x2190, 0x2180, 0x2170,
0x2160, 0x2150, 0x2140, 0x2130, 0x2120, 0x2110, 0x2100, 0x20f0,
0x20e0, 0x20d0, 0x20c0, 0x20b0, 0x20a0, 0x2090, 0x2080, 0x2070,
0x2060, 0x2050, 0x2040, 0x2030, 0x2020, 0x2010, 0x2000, 0x1ff0,
0x1fe8, 0x1fd8, 0x1fc8, 0x1fb8, 0x1fa8, 0x1f98, 0x1f88, 0x1f78,
0x1f68, 0x1f58, 0x1f48, 0x1f38, 0x1f28, 0x1f18, 0x1f08, 0x1f00,
0x1ef0, 0x1ee0, 0x1ed0, 0x1ec0, 0x1eb0, 0x1ea0, 0x1e90, 0x1e80,
0x1e70, 0x1e60, 0x1e58, 0x1e48, 0x1e38, 0x1e28, 0x1e18, 0x1e08,
0x1df8, 0x1de8, 0x1de0, 0x1dd0, 0x1dc0, 0x1db0, 0x1da0, 0x1d90,
0x1d80, 0x1d70, 0x1d68, 0x1d58, 0x1d48, 0x1d38, 0x1d28, 0x1d18,
0x1d08, 0x1d00, 0x1cf0, 0x1ce0, 0x1cd0, 0x1cc0, 0x1cb0, 0x1ca8,
0x1c98, 0x1c88, 0x1c78, 0x1c68, 0x1c58, 0x1c50, 0x1c40, 0x1c30,
0x1c20, 0x1c10, 0x1c08, 0x1bf8, 0x1be8, 0x1bd8, 0x1bc8, 0x1bc0,
0x1bb0, 0x1ba0, 0x1b90, 0x1b80, 0x1b78, 0x1b68, 0x1b58, 0x1b48,
0x1b38, 0x1b30, 0x1b20, 0x1b10, 0x1b00, 0x1af0, 0x1ae8, 0x1ad8,
0x1ac8, 0x1ab8, 0x1ab0, 0x1aa0, 0x1a90, 0x1a80, 0x1a78, 0x1a68,
0x1a58, 0x1a48, 0x1a40, 0x1a30, 0x1a20, 0x1a10, 0x1a08, 0x19f8,
0x19e8, 0x19d8, 0x19d0, 0x19c0, 0x19b0, 0x19a0, 0x1998, 0x1988,
0x1978, 0x1970, 0x1960, 0x1950, 0x1940, 0x1938, 0x1928, 0x1918,
0x1910, 0x1900, 0x18f0, 0x18e0, 0x18d8, 0x18c8, 0x18b8, 0x18b0,
0x18a0, 0x1890, 0x1888, 0x1878, 0x1868, 0x1858, 0x1850, 0x1840,
0x1830, 0x1828, 0x1818, 0x1808, 0x1800, 0x17f0, 0x17e0, 0x17d8,
0x17c8, 0x17b8, 0x17b0, 0x17a0, 0x1790, 0x1788, 0x1778, 0x1768,
0x1760, 0x1750, 0x1740, 0x1738, 0x1728, 0x1718, 0x1710, 0x1700,
0x16f8, 0x16e8, 0x16d8, 0x16d0, 0x16c0, 0x16b0, 0x16a8, 0x1698,
0x1688, 0x1680, 0x1670, 0x1668, 0x1658, 0x1648, 0x1640, 0x1630,
0x1628, 0x1618, 0x1608, 0x1600, 0x15f0, 0x15e0, 0x15d8, 0x15c8,
0x15c0, 0x15b0, 0x15a0, 0x1598, 0x1588, 0x1580, 0x1570, 0x1560,
0x1558, 0x1548, 0x1540, 0x1530, 0x1528, 0x1518, 0x1508, 0x1500,
0x14f0, 0x14e8, 0x14d8, 0x14d0, 0x14c0, 0x14b0, 0x14a8, 0x1498,
0x1490, 0x1480, 0x1478, 0x1468, 0x1458, 0x1450, 0x1440, 0x1438,
0x1428, 0x1420, 0x1410, 0x1408, 0x13f8, 0x13f0, 0x13e0, 0x13d0,
0x13c8, 0x13b8, 0x13b0, 0x13a0, 0x1398, 0x1388, 0x1380, 0x1370,
0x1368, 0x1358, 0x1350, 0x1340, 0x1338, 0x1328, 0x1318, 0x1310,
0x1300, 0x12f8, 0x12e8, 0x12e0, 0x12d0, 0x12c8, 0x12b8, 0x12b0,
0x12a0, 0x1298, 0x1288, 0x1280, 0x1270, 0x1268, 0x1258, 0x1250,
0x1240, 0x1238, 0x1228, 0x1220, 0x1210, 0x1208, 0x11f8, 0x11f0,
0x11e8, 0x11d8, 0x11d0, 0x11c0, 0x11b8, 0x11a8, 0x11a0, 0x1190,
0x1188, 0x1178, 0x1170, 0x1160, 0x1158, 0x1148, 0x1140, 0x1130,
0x1128, 0x1120, 0x1110, 0x1108, 0x10f8, 0x10f0, 0x10e0, 0x10d8,
0x10c8, 0x10c0, 0x10b0, 0x10a8, 0x10a0, 0x1090, 0x1088, 0x1078,
0x1070, 0x1060, 0x1058, 0x1050, 0x1040, 0x1038, 0x1028, 0x1020,
0x1010, 0x1008, 0x1000, 0x0ff0, 0x0fe8, 0x0fd8, 0x0fd0, 0x0fc0,
0x0fb8, 0x0fb0, 0x0fa0, 0x0f98, 0x0f88, 0x0f80, 0x0f78, 0x0f68,
0x0f60, 0x0f50, 0x0f48, 0x0f40, 0x0f30, 0x0f28, 0x0f18, 0x0f10,
0x0f08, 0x0ef8, 0x0ef0, 0x0ee0, 0x0ed8, 0x0ed0, 0x0ec0, 0x0eb8,
0x0ea8, 0x0ea0, 0x0e98, 0x0e88, 0x0e80, 0x0e78, 0x0e68, 0x0e60,
0x0e50, 0x0e48, 0x0e40, 0x0e30, 0x0e28, 0x0e20, 0x0e10, 0x0e08,
0x0df8, 0x0df0, 0x0de8, 0x0dd8, 0x0dd0, 0x0dc8, 0x0db8, 0x0db0,
0x0da8, 0x0d98, 0x0d90, 0x0d80, 0x0d78, 0x0d70, 0x0d60, 0x0d58,
0x0d50, 0x0d40, 0x0d38, 0x0d30, 0x0d20, 0x0d18, 0x0d10, 0x0d00,
0x0cf8, 0x0cf0, 0x0ce0, 0x0cd8, 0x0cd0, 0x0cc0, 0x0cb8, 0x0cb0,
0x0ca0, 0x0c98, 0x0c90, 0x0c80, 0x0c78, 0x0c70, 0x0c60, 0x0c58,
0x0c50, 0x0c40, 0x0c38, 0x0c30, 0x0c28, 0x0c18, 0x0c10, 0x0c08,
0x0bf8, 0x0bf0, 0x0be8, 0x0bd8, 0x0bd0, 0x0bc8, 0x0bb8, 0x0bb0,
0x0ba8, 0x0ba0, 0x0b90, 0x0b88, 0x0b80, 0x0b70, 0x0b68, 0x0b60,
0x0b58, 0x0b48, 0x0b40, 0x0b38, 0x0b28, 0x0b20, 0x0b18, 0x0b10,
0x0b00, 0x0af8, 0x0af0, 0x0ae0, 0x0ad8, 0x0ad0, 0x0ac8, 0x0ab8,
0x0ab0, 0x0aa8, 0x0a98, 0x0a90, 0x0a88, 0x0a80, 0x0a70, 0x0a68,
0x0a60, 0x0a58, 0x0a48, 0x0a40, 0x0a38, 0x0a30, 0x0a20, 0x0a18,
0x0a10, 0x0a08, 0x09f8, 0x09f0, 0x09e8, 0x09e0, 0x09d0, 0x09c8,
0x09c0, 0x09b8, 0x09a8, 0x09a0, 0x0998, 0x0990, 0x0980, 0x0978,
0x0970, 0x0968, 0x0958, 0x0950, 0x0948, 0x0940, 0x0930, 0x0928,
0x0920, 0x0918, 0x0910, 0x0900, 0x08f8, 0x08f0, 0x08e8, 0x08d8,
0x08d0, 0x08c8, 0x08c0, 0x08b8, 0x08a8, 0x08a0, 0x0898, 0x0890,
0x0880, 0x0878, 0x0870, 0x0868, 0x0860, 0x0850, 0x0848, 0x0840,
0x0838, 0x0830, 0x0820, 0x0818, 0x0810, 0x0808, 0x0800, 0x07f0,
0x07e8, 0x07e0, 0x07d8, 0x07d0, 0x07c0, 0x07b8, 0x07b0, 0x07a8,
0x07a0, 0x0790, 0x0788, 0x0780, 0x0778, 0x0770, 0x0768, 0x0758,
0x0750, 0x0748, 0x0740, 0x0738, 0x0728, 0x0720, 0x0718, 0x0710,
0x0708, 0x0700, 0x06f0, 0x06e8, 0x06e0, 0x06d8, 0x06d0, 0x06c8,
0x06b8, 0x06b0, 0x06a8, 0x06a0, 0x0698, 0x0690, 0x0680, 0x0678,
0x0670, 0x0668, 0x0660, 0x0658, 0x0648, 0x0640, 0x0638, 0x0630,
0x0628, 0x0620, 0x0618, 0x0608, 0x0600, 0x05f8, 0x05f0, 0x05e8,
0x05e0, 0x05d8, 0x05c8, 0x05c0, 0x05b8, 0x05b0, 0x05a8, 0x05a0,
0x0598, 0x0588, 0x0580, 0x0578, 0x0570, 0x0568, 0x0560, 0x0558,
0x0548, 0x0540, 0x0538, 0x0530, 0x0528, 0x0520, 0x0518, 0x0510,
0x0500, 0x04f8, 0x04f0, 0x04e8, 0x04e0, 0x04d8, 0x04d0, 0x04c8,
0x04c0, 0x04b0, 0x04a8, 0x04a0, 0x0498, 0x0490, 0x0488, 0x0480,
0x0478, 0x0470, 0x0460, 0x0458, 0x0450, 0x0448, 0x0440, 0x0438,
0x0430, 0x0428, 0x0420, 0x0410, 0x0408, 0x0400, 0x03f8, 0x03f0,
0x03e8, 0x03e0, 0x03d8, 0x03d0, 0x03c8, 0x03c0, 0x03b0, 0x03a8,
0x03a0, 0x0398, 0x0390, 0x0388, 0x0380, 0x0378, 0x0370, 0x0368,
0x0360, 0x0358, 0x0348, 0x0340, 0x0338, 0x0330, 0x0328, 0x0320,
0x0318, 0x0310, 0x0308, 0x0300, 0x02f8, 0x02f0, 0x02e8, 0x02d8,
0x02d0, 0x02c8, 0x02c0, 0x02b8, 0x02b0, 0x02a8, 0x02a0, 0x0298,
0x0290, 0x0288, 0x0280, 0x0278, 0x0270, 0x0268, 0x0260, 0x0250,
0x0248, 0x0240, 0x0238, 0x0230, 0x0228, 0x0220, 0x0218, 0x0210,
0x0208, 0x0200, 0x01f8, 0x01f0, 0x01e8, 0x01e0, 0x01d8, 0x01d0,
0x01c8, 0x01c0, 0x01b8, 0x01b0, 0x01a0, 0x0198, 0x0190, 0x0188,
0x0180, 0x0178, 0x0170, 0x0168, 0x0160, 0x0158, 0x0150, 0x0148,
0x0140, 0x0138, 0x0130, 0x0128, 0x0120, 0x0118, 0x0110, 0x0108,
0x0100, 0x00f8, 0x00f0, 0x00e8, 0x00e0, 0x00d8, 0x00d0, 0x00c8,
0x00c0, 0x00b8, 0x00b0, 0x00a8, 0x00a0, 0x0098, 0x0090, 0x0088,
0x0080, 0x0078, 0x0070, 0x0068, 0x0060, 0x0058, 0x0050, 0x0048,
0x0040, 0x0038, 0x0030, 0x0028, 0x0020, 0x0018, 0x0010, 0x0008
};
Bit16u rsqrt_table1[1024] =
{
0x7ff0, 0x7fd0, 0x7fb0, 0x7f90, 0x7f70, 0x7f50, 0x7f30, 0x7f10,
0x7ef0, 0x7ed0, 0x7eb0, 0x7e90, 0x7e70, 0x7e58, 0x7e38, 0x7e18,
0x7df8, 0x7dd8, 0x7db8, 0x7d98, 0x7d78, 0x7d58, 0x7d38, 0x7d20,
0x7d00, 0x7ce0, 0x7cc0, 0x7ca0, 0x7c80, 0x7c60, 0x7c48, 0x7c28,
0x7c08, 0x7be8, 0x7bc8, 0x7bb0, 0x7b90, 0x7b70, 0x7b50, 0x7b30,
0x7b18, 0x7af8, 0x7ad8, 0x7ab8, 0x7aa0, 0x7a80, 0x7a60, 0x7a40,
0x7a28, 0x7a08, 0x79e8, 0x79c8, 0x79b0, 0x7990, 0x7970, 0x7958,
0x7938, 0x7918, 0x7900, 0x78e0, 0x78c0, 0x78a8, 0x7888, 0x7868,
0x7850, 0x7830, 0x7810, 0x77f8, 0x77d8, 0x77b8, 0x77a0, 0x7780,
0x7768, 0x7748, 0x7728, 0x7710, 0x76f0, 0x76d8, 0x76b8, 0x7698,
0x7680, 0x7660, 0x7648, 0x7628, 0x7610, 0x75f0, 0x75d0, 0x75b8,
0x7598, 0x7580, 0x7560, 0x7548, 0x7528, 0x7510, 0x74f0, 0x74d8,
0x74b8, 0x74a0, 0x7480, 0x7468, 0x7448, 0x7430, 0x7410, 0x73f8,
0x73d8, 0x73c0, 0x73a8, 0x7388, 0x7370, 0x7350, 0x7338, 0x7318,
0x7300, 0x72e8, 0x72c8, 0x72b0, 0x7290, 0x7278, 0x7260, 0x7240,
0x7228, 0x7208, 0x71f0, 0x71d8, 0x71b8, 0x71a0, 0x7188, 0x7168,
0x7150, 0x7130, 0x7118, 0x7100, 0x70e0, 0x70c8, 0x70b0, 0x7090,
0x7078, 0x7060, 0x7048, 0x7028, 0x7010, 0x6ff8, 0x6fd8, 0x6fc0,
0x6fa8, 0x6f88, 0x6f70, 0x6f58, 0x6f40, 0x6f20, 0x6f08, 0x6ef0,
0x6ed8, 0x6eb8, 0x6ea0, 0x6e88, 0x6e70, 0x6e50, 0x6e38, 0x6e20,
0x6e08, 0x6df0, 0x6dd0, 0x6db8, 0x6da0, 0x6d88, 0x6d70, 0x6d50,
0x6d38, 0x6d20, 0x6d08, 0x6cf0, 0x6cd8, 0x6cb8, 0x6ca0, 0x6c88,
0x6c70, 0x6c58, 0x6c40, 0x6c20, 0x6c08, 0x6bf0, 0x6bd8, 0x6bc0,
0x6ba8, 0x6b90, 0x6b78, 0x6b58, 0x6b40, 0x6b28, 0x6b10, 0x6af8,
0x6ae0, 0x6ac8, 0x6ab0, 0x6a98, 0x6a80, 0x6a68, 0x6a48, 0x6a30,
0x6a18, 0x6a00, 0x69e8, 0x69d0, 0x69b8, 0x69a0, 0x6988, 0x6970,
0x6958, 0x6940, 0x6928, 0x6910, 0x68f8, 0x68e0, 0x68c8, 0x68b0,
0x6898, 0x6880, 0x6868, 0x6850, 0x6838, 0x6820, 0x6808, 0x67f0,
0x67d8, 0x67c0, 0x67a8, 0x6790, 0x6778, 0x6760, 0x6748, 0x6730,
0x6718, 0x6700, 0x66e8, 0x66d8, 0x66c0, 0x66a8, 0x6690, 0x6678,
0x6660, 0x6648, 0x6630, 0x6618, 0x6600, 0x65e8, 0x65d0, 0x65c0,
0x65a8, 0x6590, 0x6578, 0x6560, 0x6548, 0x6530, 0x6518, 0x6508,
0x64f0, 0x64d8, 0x64c0, 0x64a8, 0x6490, 0x6478, 0x6468, 0x6450,
0x6438, 0x6420, 0x6408, 0x63f0, 0x63e0, 0x63c8, 0x63b0, 0x6398,
0x6380, 0x6370, 0x6358, 0x6340, 0x6328, 0x6310, 0x6300, 0x62e8,
0x62d0, 0x62b8, 0x62a0, 0x6290, 0x6278, 0x6260, 0x6248, 0x6238,
0x6220, 0x6208, 0x61f0, 0x61e0, 0x61c8, 0x61b0, 0x6198, 0x6188,
0x6170, 0x6158, 0x6140, 0x6130, 0x6118, 0x6100, 0x60f0, 0x60d8,
0x60c0, 0x60a8, 0x6098, 0x6080, 0x6068, 0x6058, 0x6040, 0x6028,
0x6018, 0x6000, 0x5fe8, 0x5fd8, 0x5fc0, 0x5fa8, 0x5f98, 0x5f80,
0x5f68, 0x5f58, 0x5f40, 0x5f28, 0x5f18, 0x5f00, 0x5ee8, 0x5ed8,
0x5ec0, 0x5ea8, 0x5e98, 0x5e80, 0x5e70, 0x5e58, 0x5e40, 0x5e30,
0x5e18, 0x5e00, 0x5df0, 0x5dd8, 0x5dc8, 0x5db0, 0x5d98, 0x5d88,
0x5d70, 0x5d60, 0x5d48, 0x5d38, 0x5d20, 0x5d08, 0x5cf8, 0x5ce0,
0x5cd0, 0x5cb8, 0x5ca8, 0x5c90, 0x5c78, 0x5c68, 0x5c50, 0x5c40,
0x5c28, 0x5c18, 0x5c00, 0x5bf0, 0x5bd8, 0x5bc8, 0x5bb0, 0x5b98,
0x5b88, 0x5b70, 0x5b60, 0x5b48, 0x5b38, 0x5b20, 0x5b10, 0x5af8,
0x5ae8, 0x5ad0, 0x5ac0, 0x5aa8, 0x5a98, 0x5a80, 0x5a70, 0x5a58,
0x5a48, 0x5a30, 0x5a20, 0x5a08, 0x59f8, 0x59e8, 0x59d0, 0x59c0,
0x59a8, 0x5998, 0x5980, 0x5970, 0x5958, 0x5948, 0x5930, 0x5920,
0x5910, 0x58f8, 0x58e8, 0x58d0, 0x58c0, 0x58a8, 0x5898, 0x5888,
0x5870, 0x5860, 0x5848, 0x5838, 0x5828, 0x5810, 0x5800, 0x57e8,
0x57d8, 0x57c8, 0x57b0, 0x57a0, 0x5788, 0x5778, 0x5768, 0x5750,
0x5740, 0x5728, 0x5718, 0x5708, 0x56f0, 0x56e0, 0x56d0, 0x56b8,
0x56a8, 0x5698, 0x5680, 0x5670, 0x5658, 0x5648, 0x5638, 0x5620,
0x5610, 0x5600, 0x55e8, 0x55d8, 0x55c8, 0x55b0, 0x55a0, 0x5590,
0x5578, 0x5568, 0x5558, 0x5540, 0x5530, 0x5520, 0x5510, 0x54f8,
0x54e8, 0x54d8, 0x54c0, 0x54b0, 0x54a0, 0x5488, 0x5478, 0x5468,
0x5458, 0x5440, 0x5430, 0x5420, 0x5410, 0x53f8, 0x53e8, 0x53d8,
0x53c0, 0x53b0, 0x53a0, 0x5390, 0x5378, 0x5368, 0x5358, 0x5348,
0x5330, 0x5320, 0x5310, 0x5300, 0x52e8, 0x52d8, 0x52c8, 0x52b8,
0x52a8, 0x5290, 0x5280, 0x5270, 0x5260, 0x5248, 0x5238, 0x5228,
0x5218, 0x5208, 0x51f0, 0x51e0, 0x51d0, 0x51c0, 0x51b0, 0x5198,
0x5188, 0x5178, 0x5168, 0x5158, 0x5140, 0x5130, 0x5120, 0x5110,
0x5100, 0x50e8, 0x50d8, 0x50c8, 0x50b8, 0x50a8, 0x5098, 0x5080,
0x5070, 0x5060, 0x5050, 0x5040, 0x5030, 0x5020, 0x5008, 0x4ff8,
0x4fe8, 0x4fd8, 0x4fc8, 0x4fb8, 0x4fa8, 0x4f90, 0x4f80, 0x4f70,
0x4f60, 0x4f50, 0x4f40, 0x4f30, 0x4f20, 0x4f08, 0x4ef8, 0x4ee8,
0x4ed8, 0x4ec8, 0x4eb8, 0x4ea8, 0x4e98, 0x4e88, 0x4e70, 0x4e60,
0x4e50, 0x4e40, 0x4e30, 0x4e20, 0x4e10, 0x4e00, 0x4df0, 0x4de0,
0x4dd0, 0x4db8, 0x4da8, 0x4d98, 0x4d88, 0x4d78, 0x4d68, 0x4d58,
0x4d48, 0x4d38, 0x4d28, 0x4d18, 0x4d08, 0x4cf8, 0x4ce8, 0x4cd8,
0x4cc8, 0x4cb8, 0x4ca0, 0x4c90, 0x4c80, 0x4c70, 0x4c60, 0x4c50,
0x4c40, 0x4c30, 0x4c20, 0x4c10, 0x4c00, 0x4bf0, 0x4be0, 0x4bd0,
0x4bc0, 0x4bb0, 0x4ba0, 0x4b90, 0x4b80, 0x4b70, 0x4b60, 0x4b50,
0x4b40, 0x4b30, 0x4b20, 0x4b10, 0x4b00, 0x4af0, 0x4ae0, 0x4ad0,
0x4ac0, 0x4ab0, 0x4aa0, 0x4a90, 0x4a80, 0x4a70, 0x4a60, 0x4a50,
0x4a40, 0x4a30, 0x4a20, 0x4a10, 0x4a00, 0x49f0, 0x49e0, 0x49d0,
0x49c0, 0x49b8, 0x49a8, 0x4998, 0x4988, 0x4978, 0x4968, 0x4958,
0x4948, 0x4938, 0x4928, 0x4918, 0x4908, 0x48f8, 0x48e8, 0x48d8,
0x48c8, 0x48b8, 0x48b0, 0x48a0, 0x4890, 0x4880, 0x4870, 0x4860,
0x4850, 0x4840, 0x4830, 0x4820, 0x4810, 0x4800, 0x47f8, 0x47e8,
0x47d8, 0x47c8, 0x47b8, 0x47a8, 0x4798, 0x4788, 0x4778, 0x4768,
0x4760, 0x4750, 0x4740, 0x4730, 0x4720, 0x4710, 0x4700, 0x46f0,
0x46e0, 0x46d8, 0x46c8, 0x46b8, 0x46a8, 0x4698, 0x4688, 0x4678,
0x4670, 0x4660, 0x4650, 0x4640, 0x4630, 0x4620, 0x4610, 0x4608,
0x45f8, 0x45e8, 0x45d8, 0x45c8, 0x45b8, 0x45a8, 0x45a0, 0x4590,
0x4580, 0x4570, 0x4560, 0x4550, 0x4548, 0x4538, 0x4528, 0x4518,
0x4508, 0x44f8, 0x44f0, 0x44e0, 0x44d0, 0x44c0, 0x44b0, 0x44a8,
0x4498, 0x4488, 0x4478, 0x4468, 0x4460, 0x4450, 0x4440, 0x4430,
0x4420, 0x4418, 0x4408, 0x43f8, 0x43e8, 0x43d8, 0x43d0, 0x43c0,
0x43b0, 0x43a0, 0x4390, 0x4388, 0x4378, 0x4368, 0x4358, 0x4350,
0x4340, 0x4330, 0x4320, 0x4310, 0x4308, 0x42f8, 0x42e8, 0x42d8,
0x42d0, 0x42c0, 0x42b0, 0x42a0, 0x4298, 0x4288, 0x4278, 0x4268,
0x4260, 0x4250, 0x4240, 0x4230, 0x4228, 0x4218, 0x4208, 0x41f8,
0x41f0, 0x41e0, 0x41d0, 0x41c0, 0x41b8, 0x41a8, 0x4198, 0x4188,
0x4180, 0x4170, 0x4160, 0x4158, 0x4148, 0x4138, 0x4128, 0x4120,
0x4110, 0x4100, 0x40f8, 0x40e8, 0x40d8, 0x40c8, 0x40c0, 0x40b0,
0x40a0, 0x4098, 0x4088, 0x4078, 0x4068, 0x4060, 0x4050, 0x4040,
0x4038, 0x4028, 0x4018, 0x4010, 0x4000, 0x3ff0, 0x3fe8, 0x3fd8,
0x3fc8, 0x3fb8, 0x3fb0, 0x3fa0, 0x3f90, 0x3f88, 0x3f78, 0x3f68,
0x3f60, 0x3f50, 0x3f40, 0x3f38, 0x3f28, 0x3f18, 0x3f10, 0x3f00,
0x3ef0, 0x3ee8, 0x3ed8, 0x3ec8, 0x3ec0, 0x3eb0, 0x3ea0, 0x3e98,
0x3e88, 0x3e80, 0x3e70, 0x3e60, 0x3e58, 0x3e48, 0x3e38, 0x3e30,
0x3e20, 0x3e10, 0x3e08, 0x3df8, 0x3df0, 0x3de0, 0x3dd0, 0x3dc8,
0x3db8, 0x3da8, 0x3da0, 0x3d90, 0x3d80, 0x3d78, 0x3d68, 0x3d60,
0x3d50, 0x3d40, 0x3d38, 0x3d28, 0x3d20, 0x3d10, 0x3d00, 0x3cf8,
0x3ce8, 0x3cd8, 0x3cd0, 0x3cc0, 0x3cb8, 0x3ca8, 0x3c98, 0x3c90,
0x3c80, 0x3c78, 0x3c68, 0x3c58, 0x3c50, 0x3c40, 0x3c38, 0x3c28,
0x3c20, 0x3c10, 0x3c00, 0x3bf8, 0x3be8, 0x3be0, 0x3bd0, 0x3bc0,
0x3bb8, 0x3ba8, 0x3ba0, 0x3b90, 0x3b88, 0x3b78, 0x3b68, 0x3b60,
0x3b50, 0x3b48, 0x3b38, 0x3b30, 0x3b20, 0x3b10, 0x3b08, 0x3af8,
0x3af0, 0x3ae0, 0x3ad8, 0x3ac8, 0x3ac0, 0x3ab0, 0x3aa0, 0x3a98,
0x3a88, 0x3a80, 0x3a70, 0x3a68, 0x3a58, 0x3a50, 0x3a40, 0x3a38,
0x3a28, 0x3a20, 0x3a10, 0x3a00, 0x39f8, 0x39e8, 0x39e0, 0x39d0,
0x39c8, 0x39b8, 0x39b0, 0x39a0, 0x3998, 0x3988, 0x3980, 0x3970,
0x3968, 0x3958, 0x3950, 0x3940, 0x3938, 0x3928, 0x3918, 0x3910,
0x3900, 0x38f8, 0x38e8, 0x38e0, 0x38d0, 0x38c8, 0x38b8, 0x38b0,
0x38a0, 0x3898, 0x3888, 0x3880, 0x3870, 0x3868, 0x3858, 0x3850,
0x3840, 0x3838, 0x3828, 0x3820, 0x3818, 0x3808, 0x3800, 0x37f0,
0x37e8, 0x37d8, 0x37d0, 0x37c0, 0x37b8, 0x37a8, 0x37a0, 0x3790,
0x3788, 0x3778, 0x3770, 0x3760, 0x3758, 0x3748, 0x3740, 0x3730,
0x3728, 0x3720, 0x3710, 0x3708, 0x36f8, 0x36f0, 0x36e0, 0x36d8,
0x36c8, 0x36c0, 0x36b0, 0x36a8, 0x3698, 0x3690, 0x3688, 0x3678,
0x3670, 0x3660, 0x3658, 0x3648, 0x3640, 0x3630, 0x3628, 0x3620,
0x3610, 0x3608, 0x35f8, 0x35f0, 0x35e0, 0x35d8, 0x35d0, 0x35c0,
0x35b8, 0x35a8, 0x35a0, 0x3590, 0x3588, 0x3580, 0x3570, 0x3568,
0x3558, 0x3550, 0x3540, 0x3538, 0x3530, 0x3520, 0x3518, 0x3508
};
// approximate reciprocal sqrt of scalar single precision FP
static float32 approximate_rsqrt(float32 op)
{
float_class_t op_class = float32_class(op);
int sign = float32_sign(op);
switch(op_class)
{
case float_zero:
case float_denormal:
return packFloat32(sign, 0xFF, 0);
case float_positive_inf:
return 0;
case float_negative_inf:
return float32_default_nan;
case float_NaN:
return convert_to_QNaN(op);
case float_normalized:
break;
};
if (sign == 1)
return float32_default_nan;
Bit32u fraction = float32_fraction(op);
Bit16s exp = float32_exp(op);
/*
* Calculate (1/1.yyyyyyyyyy1), the result is always rounded to the
* 11th bit after the decimal point by round-to-nearest, regardless
* of the current rounding mode.
*
* Using two precalculated 1024-entry tables.
*/
Bit16u *rsqrt_table = (exp & 1) ? rsqrt_table1 : rsqrt_table0;
exp = 126 - ((exp - 127) >> 1);
/* check for underflow */
if (exp <= 0)
return packFloat32(sign, 0x00, 0);
return packFloat32(sign, exp, (Bit32u)(rsqrt_table[fraction >> 13]) << 8);
}
#endif
/*
* Opcode: F3 0F 52
* Approximate reciprocal of square root of scalar single precision FP value
* from XMM2/MEM32.
* Possible floating point exceptions: -
*/
void BX_CPP_AttrRegparmN(1) BX_CPU_C::RSQRTSS_VssWssR(bxInstruction_c *i)
{
#if BX_CPU_LEVEL >= 6
float32 op = BX_READ_XMM_REG_LO_DWORD(i->rm());
op = approximate_rsqrt(op);
BX_WRITE_XMM_REG_LO_DWORD(i->nnn(), op);
#endif
}
/*
* Opcode: 0F 52
* Approximate reciprocal of square root of packed single precision FP values
* from XMM2/MEM.
* Possible floating point exceptions: -
*/
void BX_CPP_AttrRegparmN(1) BX_CPU_C::RSQRTPS_VpsWpsR(bxInstruction_c *i)
{
#if BX_CPU_LEVEL >= 6
BxPackedXmmRegister op = BX_READ_XMM_REG(i->rm());
op.xmm32u(0) = approximate_rsqrt(op.xmm32u(0));
op.xmm32u(1) = approximate_rsqrt(op.xmm32u(1));
op.xmm32u(2) = approximate_rsqrt(op.xmm32u(2));
op.xmm32u(3) = approximate_rsqrt(op.xmm32u(3));
BX_WRITE_XMM_REG(i->nnn(), op);
#endif
}

View File

@ -0,0 +1,485 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2007-2010 Stanislav Shwartsman
// 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
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA B 02110-1301 USA
//
/////////////////////////////////////////////////////////////////////////
#define NEED_CPU_REG_SHORTCUTS 1
#include "bochs.h"
#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 RCX ECX
#endif
#if BX_CPU_LEVEL >= 6
// Compare all pairs of Ai, Bj according to imm8 control
static void compare_strings(Bit8u BoolRes[16][16], BxPackedXmmRegister op1, BxPackedXmmRegister op2, Bit8u imm)
{
unsigned i, j;
unsigned aggregation_operation = (imm >> 2) & 3;
// All possible comparisons are performed, the individual boolean
// results of those comparisons are referred by
// BoolRes[op2 element index, op1 element index]
switch (imm & 3) {
case 0: /* unsigned bytes compare */
for (i=0;i<16;i++) {
for (j=0;j<16;j++) {
switch (aggregation_operation) {
case 0: /* 'equal' comparison */
case 2:
case 3:
BoolRes[j][i] = (op1.xmmubyte(i) == op2.xmmubyte(j));
break;
case 1: /* 'ranges' comparison */
if ((i % 2) == 0)
BoolRes[j][i] = (op1.xmmubyte(i) <= op2.xmmubyte(j));
else
BoolRes[j][i] = (op1.xmmubyte(i) >= op2.xmmubyte(j));
break;
}
}
}
break;
case 1: /* unsigned words compare */
for (i=0;i<8;i++) {
for (j=0;j<8;j++) {
switch (aggregation_operation) {
case 0: /* 'equal' comparison */
case 2:
case 3:
BoolRes[j][i] = (op1.xmm16u(i) == op2.xmm16u(j));
break;
case 1: /* 'ranges' comparison */
if ((i % 2) == 0)
BoolRes[j][i] = (op1.xmm16u(i) <= op2.xmm16u(j));
else
BoolRes[j][i] = (op1.xmm16u(i) >= op2.xmm16u(j));
break;
}
}
}
break;
case 2: /* signed bytes compare */
for (i=0;i<16;i++) {
for (j=0;j<16;j++) {
switch (aggregation_operation) {
case 0: /* 'equal' comparison */
case 2:
case 3:
BoolRes[j][i] = (op1.xmmsbyte(i) == op2.xmmsbyte(j));
break;
case 1: /* 'ranges' comparison */
if ((i % 2) == 0)
BoolRes[j][i] = (op1.xmmsbyte(i) <= op2.xmmsbyte(j));
else
BoolRes[j][i] = (op1.xmmsbyte(i) >= op2.xmmsbyte(j));
break;
}
}
}
break;
case 3: /* signed words compare */
for (i=0;i<8;i++) {
for (j=0;j<8;j++) {
switch (aggregation_operation) {
case 0: /* 'equal' comparison */
case 2:
case 3:
BoolRes[j][i] = (op1.xmm16s(i) == op2.xmm16s(j));
break;
case 1: /* 'ranges' comparison */
if ((i % 2) == 0)
BoolRes[j][i] = (op1.xmm16s(i) <= op2.xmm16s(j));
else
BoolRes[j][i] = (op1.xmm16s(i) >= op2.xmm16s(j));
break;
}
}
}
break;
}
}
static unsigned find_eos32(Bit32s reg32, Bit8u imm)
{
if (imm & 0x1) { // 8 elements
if (reg32 > 8 || reg32 < -8) return 8;
else return abs(reg32);
}
else { // 16 elements
if (reg32 > 16 || reg32 < -16) return 16;
else return abs(reg32);
}
}
#if BX_SUPPORT_X86_64
static unsigned find_eos64(Bit64s reg64, Bit8u imm)
{
if (imm & 0x1) { // 8 elements
if (reg64 > 8 || reg64 < -8) return 8;
else return (unsigned) abs(reg64);
}
else { // 16 elements
if (reg64 > 16 || reg64 < -16) return 16;
else return (unsigned) abs(reg64);
}
}
#endif
static unsigned find_eos(BxPackedXmmRegister op, Bit8u imm)
{
unsigned i = 0;
if (imm & 0x1) { // 8 elements
for(i=0;i<8;i++)
if (op.xmm16u(i) == 0) break;
}
else { // 16 elements
for(i=0;i<16;i++)
if (op.xmmubyte(i) == 0) break;
}
return i;
}
static bx_bool override_if_data_invalid(bx_bool val, bx_bool i_valid, bx_bool j_valid, Bit8u imm)
{
unsigned aggregation_operation = (imm >> 2) & 3;
switch(aggregation_operation) {
case 0: // 'equal any'
case 1: // 'ranges'
if (! i_valid || ! j_valid) // one of the elements is invalid
return 0;
break;
case 2: // 'equal each'
if (! i_valid) {
if (! j_valid) return 1; // both elements are invalid
else return 0; // only i is invalid
}
else {
if (! j_valid) return 0; // only j is invalid
}
break;
case 3: // 'equal ordered'
if (! i_valid) { // element i is invalid
return 1;
}
else {
if (! j_valid) { // only j is invalid
return 0;
}
}
break;
}
return val;
}
static Bit16u aggregate(Bit8u BoolRes[16][16], unsigned len1, unsigned len2, Bit8u imm)
{
unsigned aggregation_operation = (imm >> 2) & 3;
unsigned num_elements = (imm & 0x1) ? 8 : 16;
unsigned polarity = (imm >> 4) & 3;
unsigned i,j,k;
Bit16u result = 0;
switch(aggregation_operation) {
case 0: // 'equal any'
for(j=0; j<num_elements; j++) {
bx_bool res = 0;
for(i=0; i<num_elements; i++) {
if (override_if_data_invalid(BoolRes[j][i], (i < len1), (j < len2), imm)) {
res = 1;
break;
}
}
if (res)
result |= (1<<j);
}
break;
case 1: // 'ranges'
for(j=0; j<num_elements; j++) {
bx_bool res = 0;
for(i=0; i<num_elements; i+=2) {
if (override_if_data_invalid(BoolRes[j][i], (i < len1), (j < len2), imm) &&
override_if_data_invalid(BoolRes[j][i+1], (i+1 < len1), (j < len2), imm)) {
res = 1;
break;
}
}
if (res)
result |= (1<<j);
}
break;
case 2: // 'equal each'
for(j=0; j<num_elements; j++) {
if (override_if_data_invalid(BoolRes[j][j], (j < len1), (j < len2), imm))
result |= (1<<j);
}
break;
case 3: // 'equal ordered'
for(j=0; j<num_elements; j++) {
bx_bool res = 1;
for (i=0, k=j; (i < num_elements-j) && (k < num_elements); i++, k++) {
if (! override_if_data_invalid(BoolRes[k][i], (i < len1), (k < len2), imm)) {
res = 0;
break;
}
}
if (res)
result |= (1<<j);
}
break;
}
switch(polarity) {
case 0:
case 2:
break; // do nothing
case 1:
result ^= (num_elements == 8) ? 0xFF : 0xFFFF;
break;
case 3:
for (j=0;j<num_elements;j++)
if (j < len2) result ^= (1<<j); // flip the bit
break;
}
return result;
}
#endif // BX_CPU_LEVEL >= 6
/* 66 0F 3A 60 */
void BX_CPP_AttrRegparmN(1) BX_CPU_C::PCMPESTRM_VdqWdqIbR(bxInstruction_c *i)
{
#if BX_CPU_LEVEL >= 6
BxPackedXmmRegister op1 = BX_READ_XMM_REG(i->nnn());
BxPackedXmmRegister op2 = BX_READ_XMM_REG(i->rm()), result;
Bit8u imm8 = i->Ib();
// compare all pairs of Ai, Bj
Bit8u BoolRes[16][16];
compare_strings(BoolRes, op1, op2, imm8);
unsigned len1, len2, num_elements = (imm8 & 0x1) ? 8 : 16;
#if BX_SUPPORT_X86_64
if (i->os64L()) {
len1 = find_eos64(RAX, imm8);
len2 = find_eos64(RDX, imm8);
}
else
#endif
{
len1 = find_eos32(EAX, imm8);
len2 = find_eos32(EDX, imm8);
}
Bit16u result2 = aggregate(BoolRes, len1, len2, imm8);
// As defined by imm8[6], result2 is then either stored to the least
// significant bits of XMM0 (zero extended to 128 bits) or expanded
// into a byte/word-mask and then stored to XMM0
if (imm8 & 0x40) {
if (num_elements == 8) {
for (int index = 0; index < 8; index++)
result.xmm16u(index) = (result2 & (1<<index)) ? 0xffff : 0;
}
else { // num_elements = 16
for (int index = 0; index < 16; index++)
result.xmmubyte(index) = (result2 & (1<<index)) ? 0xff : 0;
}
}
else {
result.xmm64u(1) = 0;
result.xmm64u(0) = (Bit64u) result2;
}
Bit32u flags = 0;
if (result2 != 0) flags |= EFlagsCFMask;
if (len1 < num_elements) flags |= EFlagsSFMask;
if (len2 < num_elements) flags |= EFlagsZFMask;
if (result2 & 0x1)
flags |= EFlagsOFMask;
setEFlagsOSZAPC(flags);
BX_WRITE_XMM_REG(0, result); /* store result XMM0 */
#endif
}
/* 66 0F 3A 61 */
void BX_CPP_AttrRegparmN(1) BX_CPU_C::PCMPESTRI_VdqWdqIbR(bxInstruction_c *i)
{
#if BX_CPU_LEVEL >= 6
BxPackedXmmRegister op1 = BX_READ_XMM_REG(i->nnn()), op2 = BX_READ_XMM_REG(i->rm());
Bit8u imm8 = i->Ib();
// compare all pairs of Ai, Bj
Bit8u BoolRes[16][16];
compare_strings(BoolRes, op1, op2, imm8);
unsigned len1, len2, num_elements = (imm8 & 0x1) ? 8 : 16;
int index;
#if BX_SUPPORT_X86_64
if (i->os64L()) {
len1 = find_eos64(RAX, imm8);
len2 = find_eos64(RDX, imm8);
}
else
#endif
{
len1 = find_eos32(EAX, imm8);
len2 = find_eos32(EDX, imm8);
}
Bit16u result2 = aggregate(BoolRes, len1, len2, imm8);
// The index of the first (or last, according to imm8[6]) set bit of result2
// is returned to ECX. If no bits are set in IntRes2, ECX is set to 16 (8)
if (imm8 & 0x40) {
// The index returned to ECX is of the MSB in result2
for (index=num_elements-1; index>=0; index--)
if (result2 & (1<<index)) break;
if (index < 0) index = num_elements;
}
else {
// The index returned to ECX is of the LSB in result2
for (index=0; index<(int)num_elements; index++)
if (result2 & (1<<index)) break;
}
RCX = index;
Bit32u flags = 0;
if (result2 != 0) flags |= EFlagsCFMask;
if (len1 < num_elements) flags |= EFlagsSFMask;
if (len2 < num_elements) flags |= EFlagsZFMask;
if (result2 & 0x1)
flags |= EFlagsOFMask;
setEFlagsOSZAPC(flags);
#endif
}
/* 66 0F 3A 62 */
void BX_CPP_AttrRegparmN(1) BX_CPU_C::PCMPISTRM_VdqWdqIbR(bxInstruction_c *i)
{
#if BX_CPU_LEVEL >= 6
BxPackedXmmRegister op1 = BX_READ_XMM_REG(i->nnn());
BxPackedXmmRegister op2 = BX_READ_XMM_REG(i->rm()), result;
Bit8u imm8 = i->Ib();
// compare all pairs of Ai, Bj
Bit8u BoolRes[16][16];
compare_strings(BoolRes, op1, op2, imm8);
unsigned num_elements = (imm8 & 0x1) ? 8 : 16;
unsigned len1 = find_eos(op1, imm8);
unsigned len2 = find_eos(op2, imm8);
Bit16u result2 = aggregate(BoolRes, len1, len2, imm8);
// As defined by imm8[6], result2 is then either stored to the least
// significant bits of XMM0 (zero extended to 128 bits) or expanded
// into a byte/word-mask and then stored to XMM0
if (imm8 & 0x40) {
if (num_elements == 8) {
for (int index = 0; index < 8; index++)
result.xmm16u(index) = (result2 & (1<<index)) ? 0xffff : 0;
}
else { // num_elements = 16
for (int index = 0; index < 16; index++)
result.xmmubyte(index) = (result2 & (1<<index)) ? 0xff : 0;
}
}
else {
result.xmm64u(1) = 0;
result.xmm64u(0) = (Bit64u) result2;
}
Bit32u flags = 0;
if (result2 != 0) flags |= EFlagsCFMask;
if (len1 < num_elements) flags |= EFlagsSFMask;
if (len2 < num_elements) flags |= EFlagsZFMask;
if (result2 & 0x1)
flags |= EFlagsOFMask;
setEFlagsOSZAPC(flags);
BX_WRITE_XMM_REG(0, result); /* store result XMM0 */
#endif
}
/* 66 0F 3A 63 */
void BX_CPP_AttrRegparmN(1) BX_CPU_C::PCMPISTRI_VdqWdqIbR(bxInstruction_c *i)
{
#if BX_CPU_LEVEL >= 6
BxPackedXmmRegister op1 = BX_READ_XMM_REG(i->nnn()), op2 = BX_READ_XMM_REG(i->rm());
Bit8u imm8 = i->Ib();
// compare all pairs of Ai, Bj
Bit8u BoolRes[16][16];
compare_strings(BoolRes, op1, op2, imm8);
unsigned num_elements = (imm8 & 0x1) ? 8 : 16;
int index;
unsigned len1 = find_eos(op1, imm8);
unsigned len2 = find_eos(op2, imm8);
Bit16u result2 = aggregate(BoolRes, len1, len2, imm8);
// The index of the first (or last, according to imm8[6]) set bit of result2
// is returned to ECX. If no bits are set in IntRes2, ECX is set to 16 (8)
if (imm8 & 0x40) {
// The index returned to ECX is of the MSB in result2
for (index=num_elements-1; index>=0; index--)
if (result2 & (1<<index)) break;
if (index < 0) index = num_elements;
}
else {
// The index returned to ECX is of the LSB in result2
for (index=0; index<(int)num_elements; index++)
if (result2 & (1<<index)) break;
}
RCX = index;
Bit32u flags = 0;
if (result2 != 0) flags |= EFlagsCFMask;
if (len1 < num_elements) flags |= EFlagsSFMask;
if (len2 < num_elements) flags |= EFlagsZFMask;
if (result2 & 0x1)
flags |= EFlagsOFMask;
setEFlagsOSZAPC(flags);
#endif
}

140
simulators/bochs/cpu/stack.h Executable file
View File

@ -0,0 +1,140 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2007-2009 Stanislav Shwartsman
// 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
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA B 02110-1301 USA
//
/////////////////////////////////////////////////////////////////////////
#ifndef BX_PUSHPOP_H
#define BX_PUSHPOP_H
BX_CPP_INLINE void BX_CPP_AttrRegparmN(1)
BX_CPU_C::push_16(Bit16u value16)
{
/* must use StackAddrSize, and either RSP, ESP or SP accordingly */
#if BX_SUPPORT_X86_64
if (StackAddrSize64()) {
write_virtual_word_64(BX_SEG_REG_SS, RSP-2, value16);
RSP -= 2;
}
else
#endif
if (BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.d_b) { /* StackAddrSize = 32 */
write_virtual_word_32(BX_SEG_REG_SS, (Bit32u) (ESP-2), value16);
ESP -= 2;
}
else
{
write_virtual_word_32(BX_SEG_REG_SS, (Bit16u) (SP-2), value16);
SP -= 2;
}
}
BX_CPP_INLINE void BX_CPP_AttrRegparmN(1)
BX_CPU_C::push_32(Bit32u value32)
{
/* must use StackAddrSize, and either RSP, ESP or SP accordingly */
#if BX_SUPPORT_X86_64
if (StackAddrSize64()) {
write_virtual_dword_64(BX_SEG_REG_SS, RSP-4, value32);
RSP -= 4;
}
else
#endif
if (BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.d_b) { /* StackAddrSize = 32 */
write_virtual_dword_32(BX_SEG_REG_SS, (Bit32u) (ESP-4), value32);
ESP -= 4;
}
else
{
write_virtual_dword_32(BX_SEG_REG_SS, (Bit16u) (SP-4), value32);
SP -= 4;
}
}
/* push 64 bit operand */
#if BX_SUPPORT_X86_64
BX_CPP_INLINE void BX_CPP_AttrRegparmN(1)
BX_CPU_C::push_64(Bit64u value64)
{
write_virtual_qword_64(BX_SEG_REG_SS, RSP-8, value64);
RSP -= 8;
}
#endif
/* pop 16 bit operand from the stack */
BX_CPP_INLINE Bit16u BX_CPU_C::pop_16(void)
{
Bit16u value16;
#if BX_SUPPORT_X86_64
if (StackAddrSize64()) {
value16 = read_virtual_word_64(BX_SEG_REG_SS, RSP);
RSP += 2;
}
else
#endif
if (BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.d_b) {
value16 = read_virtual_word_32(BX_SEG_REG_SS, ESP);
ESP += 2;
}
else {
value16 = read_virtual_word_32(BX_SEG_REG_SS, SP);
SP += 2;
}
return value16;
}
/* pop 32 bit operand from the stack */
BX_CPP_INLINE Bit32u BX_CPU_C::pop_32(void)
{
Bit32u value32;
#if BX_SUPPORT_X86_64
if (StackAddrSize64()) {
value32 = read_virtual_dword_64(BX_SEG_REG_SS, RSP);
RSP += 4;
}
else
#endif
if (BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.d_b) {
value32 = read_virtual_dword_32(BX_SEG_REG_SS, ESP);
ESP += 4;
}
else {
value32 = read_virtual_dword_32(BX_SEG_REG_SS, SP);
SP += 4;
}
return value32;
}
/* pop 64 bit operand from the stack */
#if BX_SUPPORT_X86_64
BX_CPP_INLINE Bit64u BX_CPU_C::pop_64(void)
{
Bit64u value64 = read_virtual_qword_64(BX_SEG_REG_SS, RSP);
RSP += 8;
return value64;
}
#endif // BX_SUPPORT_X86_64
#endif

View File

@ -0,0 +1,309 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2001-2009 The Bochs Project
//
// 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
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA B 02110-1301 USA
/////////////////////////////////////////////////////////////////////////
#define NEED_CPU_REG_SHORTCUTS 1
#include "bochs.h"
#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 RSP ESP
#endif
void BX_CPP_AttrRegparmN(1) BX_CPU_C::PUSH_RX(bxInstruction_c *i)
{
push_16(BX_READ_16BIT_REG(i->rm()));
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::PUSH16_CS(bxInstruction_c *i)
{
push_16(BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::PUSH16_DS(bxInstruction_c *i)
{
push_16(BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS].selector.value);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::PUSH16_ES(bxInstruction_c *i)
{
push_16(BX_CPU_THIS_PTR sregs[BX_SEG_REG_ES].selector.value);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::PUSH16_FS(bxInstruction_c *i)
{
push_16(BX_CPU_THIS_PTR sregs[BX_SEG_REG_FS].selector.value);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::PUSH16_GS(bxInstruction_c *i)
{
push_16(BX_CPU_THIS_PTR sregs[BX_SEG_REG_GS].selector.value);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::PUSH16_SS(bxInstruction_c *i)
{
push_16(BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].selector.value);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::POP16_DS(bxInstruction_c *i)
{
RSP_SPECULATIVE;
Bit16u ds = pop_16();
load_seg_reg(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS], ds);
RSP_COMMIT;
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::POP16_ES(bxInstruction_c *i)
{
RSP_SPECULATIVE;
Bit16u es = pop_16();
load_seg_reg(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_ES], es);
RSP_COMMIT;
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::POP16_FS(bxInstruction_c *i)
{
RSP_SPECULATIVE;
Bit16u fs = pop_16();
load_seg_reg(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_FS], fs);
RSP_COMMIT;
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::POP16_GS(bxInstruction_c *i)
{
RSP_SPECULATIVE;
Bit16u gs = pop_16();
load_seg_reg(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_GS], gs);
RSP_COMMIT;
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::POP16_SS(bxInstruction_c *i)
{
RSP_SPECULATIVE;
Bit16u ss = pop_16();
load_seg_reg(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS], ss);
RSP_COMMIT;
// POP SS inhibits interrupts, debug exceptions and single-step
// trap exceptions until the execution boundary following the
// next instruction is reached.
// Same code as MOV_SwEw()
BX_CPU_THIS_PTR inhibit_mask |= BX_INHIBIT_INTERRUPTS_BY_MOVSS;
BX_CPU_THIS_PTR async_event = 1;
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::POP_RX(bxInstruction_c *i)
{
BX_WRITE_16BIT_REG(i->rm(), pop_16());
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::POP_EwM(bxInstruction_c *i)
{
RSP_SPECULATIVE;
Bit16u val16 = pop_16();
// Note: there is one little weirdism here. It is possible to use
// SP in the modrm addressing. If used, the value of SP after the
// pop is used to calculate the address.
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
write_virtual_word(i->seg(), eaddr, val16);
RSP_COMMIT;
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::PUSH_Iw(bxInstruction_c *i)
{
push_16(i->Iw());
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::PUSH_EwM(bxInstruction_c *i)
{
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
Bit16u op1_16 = read_virtual_word(i->seg(), eaddr);
push_16(op1_16);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::PUSHAD16(bxInstruction_c *i)
{
Bit32u temp_ESP = ESP;
Bit16u temp_SP = SP;
if (BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.d_b)
{
write_virtual_word_32(BX_SEG_REG_SS, (Bit32u)(temp_ESP - 2), AX);
write_virtual_word_32(BX_SEG_REG_SS, (Bit32u)(temp_ESP - 4), CX);
write_virtual_word_32(BX_SEG_REG_SS, (Bit32u)(temp_ESP - 6), DX);
write_virtual_word_32(BX_SEG_REG_SS, (Bit32u)(temp_ESP - 8), BX);
write_virtual_word_32(BX_SEG_REG_SS, (Bit32u)(temp_ESP - 10), temp_SP);
write_virtual_word_32(BX_SEG_REG_SS, (Bit32u)(temp_ESP - 12), BP);
write_virtual_word_32(BX_SEG_REG_SS, (Bit32u)(temp_ESP - 14), SI);
write_virtual_word_32(BX_SEG_REG_SS, (Bit32u)(temp_ESP - 16), DI);
ESP -= 16;
}
else
{
write_virtual_word_32(BX_SEG_REG_SS, (Bit16u)(temp_SP - 2), AX);
write_virtual_word_32(BX_SEG_REG_SS, (Bit16u)(temp_SP - 4), CX);
write_virtual_word_32(BX_SEG_REG_SS, (Bit16u)(temp_SP - 6), DX);
write_virtual_word_32(BX_SEG_REG_SS, (Bit16u)(temp_SP - 8), BX);
write_virtual_word_32(BX_SEG_REG_SS, (Bit16u)(temp_SP - 10), temp_SP);
write_virtual_word_32(BX_SEG_REG_SS, (Bit16u)(temp_SP - 12), BP);
write_virtual_word_32(BX_SEG_REG_SS, (Bit16u)(temp_SP - 14), SI);
write_virtual_word_32(BX_SEG_REG_SS, (Bit16u)(temp_SP - 16), DI);
SP -= 16;
}
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::POPAD16(bxInstruction_c *i)
{
Bit16u di, si, bp, bx, dx, cx, ax, dummy;
if (BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.d_b)
{
Bit32u temp_ESP = ESP;
di = read_virtual_word_32(BX_SEG_REG_SS, (Bit32u)(temp_ESP + 0));
si = read_virtual_word_32(BX_SEG_REG_SS, (Bit32u)(temp_ESP + 2));
bp = read_virtual_word_32(BX_SEG_REG_SS, (Bit32u)(temp_ESP + 4));
dummy = read_virtual_word_32(BX_SEG_REG_SS, (Bit32u)(temp_ESP + 6));
bx = read_virtual_word_32(BX_SEG_REG_SS, (Bit32u)(temp_ESP + 8));
dx = read_virtual_word_32(BX_SEG_REG_SS, (Bit32u)(temp_ESP + 10));
cx = read_virtual_word_32(BX_SEG_REG_SS, (Bit32u)(temp_ESP + 12));
ax = read_virtual_word_32(BX_SEG_REG_SS, (Bit32u)(temp_ESP + 14));
ESP += 16;
}
else
{
Bit16u temp_SP = SP;
di = read_virtual_word_32(BX_SEG_REG_SS, (Bit16u)(temp_SP + 0));
si = read_virtual_word_32(BX_SEG_REG_SS, (Bit16u)(temp_SP + 2));
bp = read_virtual_word_32(BX_SEG_REG_SS, (Bit16u)(temp_SP + 4));
dummy = read_virtual_word_32(BX_SEG_REG_SS, (Bit16u)(temp_SP + 6));
bx = read_virtual_word_32(BX_SEG_REG_SS, (Bit16u)(temp_SP + 8));
dx = read_virtual_word_32(BX_SEG_REG_SS, (Bit16u)(temp_SP + 10));
cx = read_virtual_word_32(BX_SEG_REG_SS, (Bit16u)(temp_SP + 12));
ax = read_virtual_word_32(BX_SEG_REG_SS, (Bit16u)(temp_SP + 14));
SP += 16;
}
DI = di;
SI = si;
BP = bp;
BX = bx;
DX = dx;
CX = cx;
AX = ax;
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::ENTER16_IwIb(bxInstruction_c *i)
{
Bit16u imm16 = i->Iw();
Bit8u level = i->Ib2();
level &= 0x1F;
RSP_SPECULATIVE;
push_16(BP);
Bit16u frame_ptr16 = SP;
if (BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.d_b) {
Bit32u ebp = EBP; // Use temp copy for case of exception.
if (level > 0) {
/* do level-1 times */
while (--level) {
ebp -= 2;
Bit16u temp16 = read_virtual_word_32(BX_SEG_REG_SS, ebp);
push_16(temp16);
}
/* push(frame pointer) */
push_16(frame_ptr16);
}
ESP -= imm16;
// ENTER finishes with memory write check on the final stack pointer
// the memory is touched but no write actually occurs
// emulate it by doing RMW read access from SS:ESP
read_RMW_virtual_word(BX_SEG_REG_SS, ESP);
BP = frame_ptr16;
}
else {
Bit16u bp = BP;
if (level > 0) {
/* do level-1 times */
while (--level) {
bp -= 2;
Bit16u temp16 = read_virtual_word_32(BX_SEG_REG_SS, bp);
push_16(temp16);
}
/* push(frame pointer) */
push_16(frame_ptr16);
}
SP -= imm16;
// ENTER finishes with memory write check on the final stack pointer
// the memory is touched but no write actually occurs
// emulate it by doing RMW read access from SS:SP
read_RMW_virtual_word_32(BX_SEG_REG_SS, SP);
}
BP = frame_ptr16;
RSP_COMMIT;
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::LEAVE16(bxInstruction_c *i)
{
BX_ASSERT(BX_CPU_THIS_PTR cpu_mode != BX_MODE_LONG_64);
Bit16u value16;
if (BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.d_b) {
value16 = read_virtual_word_32(BX_SEG_REG_SS, EBP);
ESP = EBP + 2;
}
else {
value16 = read_virtual_word_32(BX_SEG_REG_SS, BP);
SP = BP + 2;
}
BP = value16;
}

View File

@ -0,0 +1,397 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2001-2009 The Bochs Project
//
// 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
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA B 02110-1301 USA
/////////////////////////////////////////////////////////////////////////
#define NEED_CPU_REG_SHORTCUTS 1
#include "bochs.h"
#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 RSP ESP
#endif
void BX_CPP_AttrRegparmN(1) BX_CPU_C::POP_EdM(bxInstruction_c *i)
{
RSP_SPECULATIVE;
Bit32u val32 = pop_32();
// Note: there is one little weirdism here. It is possible to use
// ESP in the modrm addressing. If used, the value of ESP after the
// pop is used to calculate the address.
Bit32u eaddr = (Bit32u) BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
write_virtual_dword_32(i->seg(), eaddr, val32);
RSP_COMMIT;
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::PUSH_ERX(bxInstruction_c *i)
{
push_32(BX_READ_32BIT_REG(i->rm()));
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::POP_ERX(bxInstruction_c *i)
{
BX_WRITE_32BIT_REGZ(i->rm(), pop_32());
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::PUSH32_CS(bxInstruction_c *i)
{
Bit16u val_16 = BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value;
if (BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.d_b) {
write_virtual_word_32(BX_SEG_REG_SS, (Bit32u) (ESP-4), val_16);
ESP -= 4;
}
else
{
write_virtual_word_32(BX_SEG_REG_SS, (Bit16u) (SP-4), val_16);
SP -= 4;
}
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::PUSH32_DS(bxInstruction_c *i)
{
Bit16u val_16 = BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS].selector.value;
if (BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.d_b) {
write_virtual_word_32(BX_SEG_REG_SS, (Bit32u) (ESP-4), val_16);
ESP -= 4;
}
else
{
write_virtual_word_32(BX_SEG_REG_SS, (Bit16u) (SP-4), val_16);
SP -= 4;
}
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::PUSH32_ES(bxInstruction_c *i)
{
Bit16u val_16 = BX_CPU_THIS_PTR sregs[BX_SEG_REG_ES].selector.value;
if (BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.d_b) {
write_virtual_word_32(BX_SEG_REG_SS, (Bit32u) (ESP-4), val_16);
ESP -= 4;
}
else
{
write_virtual_word_32(BX_SEG_REG_SS, (Bit16u) (SP-4), val_16);
SP -= 4;
}
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::PUSH32_FS(bxInstruction_c *i)
{
Bit16u val_16 = BX_CPU_THIS_PTR sregs[BX_SEG_REG_FS].selector.value;
if (BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.d_b) {
write_virtual_word_32(BX_SEG_REG_SS, (Bit32u) (ESP-4), val_16);
ESP -= 4;
}
else
{
write_virtual_word_32(BX_SEG_REG_SS, (Bit16u) (SP-4), val_16);
SP -= 4;
}
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::PUSH32_GS(bxInstruction_c *i)
{
Bit16u val_16 = BX_CPU_THIS_PTR sregs[BX_SEG_REG_GS].selector.value;
if (BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.d_b) {
write_virtual_word_32(BX_SEG_REG_SS, (Bit32u) (ESP-4), val_16);
ESP -= 4;
}
else
{
write_virtual_word_32(BX_SEG_REG_SS, (Bit16u) (SP-4), val_16);
SP -= 4;
}
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::PUSH32_SS(bxInstruction_c *i)
{
Bit16u val_16 = BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].selector.value;
if (BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.d_b) {
write_virtual_word_32(BX_SEG_REG_SS, (Bit32u) (ESP-4), val_16);
ESP -= 4;
}
else
{
write_virtual_word_32(BX_SEG_REG_SS, (Bit16u) (SP-4), val_16);
SP -= 4;
}
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::POP32_DS(bxInstruction_c *i)
{
Bit16u ds;
if (BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.d_b) {
ds = read_virtual_word_32(BX_SEG_REG_SS, ESP);
load_seg_reg(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS], ds);
ESP += 4;
}
else {
ds = read_virtual_word_32(BX_SEG_REG_SS, SP);
load_seg_reg(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS], ds);
SP += 4;
}
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::POP32_ES(bxInstruction_c *i)
{
Bit16u es;
if (BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.d_b) {
es = read_virtual_word_32(BX_SEG_REG_SS, ESP);
load_seg_reg(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_ES], es);
ESP += 4;
}
else {
es = read_virtual_word_32(BX_SEG_REG_SS, SP);
load_seg_reg(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_ES], es);
SP += 4;
}
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::POP32_FS(bxInstruction_c *i)
{
Bit16u fs;
if (BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.d_b) {
fs = read_virtual_word_32(BX_SEG_REG_SS, ESP);
load_seg_reg(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_FS], fs);
ESP += 4;
}
else {
fs = read_virtual_word_32(BX_SEG_REG_SS, SP);
load_seg_reg(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_FS], fs);
SP += 4;
}
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::POP32_GS(bxInstruction_c *i)
{
Bit16u gs;
if (BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.d_b) {
gs = read_virtual_word_32(BX_SEG_REG_SS, ESP);
load_seg_reg(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_GS], gs);
ESP += 4;
}
else {
gs = read_virtual_word_32(BX_SEG_REG_SS, SP);
load_seg_reg(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_GS], gs);
SP += 4;
}
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::POP32_SS(bxInstruction_c *i)
{
Bit16u ss;
if (BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.d_b) {
ss = read_virtual_word_32(BX_SEG_REG_SS, ESP);
load_seg_reg(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS], ss);
ESP += 4;
}
else {
ss = read_virtual_word_32(BX_SEG_REG_SS, SP);
load_seg_reg(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS], ss);
SP += 4;
}
// POP SS inhibits interrupts, debug exceptions and single-step
// trap exceptions until the execution boundary following the
// next instruction is reached.
// Same code as MOV_SwEw()
BX_CPU_THIS_PTR inhibit_mask |= BX_INHIBIT_INTERRUPTS_BY_MOVSS;
BX_CPU_THIS_PTR async_event = 1;
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::PUSH_Id(bxInstruction_c *i)
{
push_32(i->Id());
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::PUSH_EdM(bxInstruction_c *i)
{
Bit32u eaddr = (Bit32u) BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
Bit32u op1_32 = read_virtual_dword_32(i->seg(), eaddr);
push_32(op1_32);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::PUSHAD32(bxInstruction_c *i)
{
Bit32u temp_ESP = ESP;
Bit16u temp_SP = SP;
if (BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.d_b)
{
write_virtual_dword_32(BX_SEG_REG_SS, (Bit32u) (temp_ESP - 4), EAX);
write_virtual_dword_32(BX_SEG_REG_SS, (Bit32u) (temp_ESP - 8), ECX);
write_virtual_dword_32(BX_SEG_REG_SS, (Bit32u) (temp_ESP - 12), EDX);
write_virtual_dword_32(BX_SEG_REG_SS, (Bit32u) (temp_ESP - 16), EBX);
write_virtual_dword_32(BX_SEG_REG_SS, (Bit32u) (temp_ESP - 20), temp_ESP);
write_virtual_dword_32(BX_SEG_REG_SS, (Bit32u) (temp_ESP - 24), EBP);
write_virtual_dword_32(BX_SEG_REG_SS, (Bit32u) (temp_ESP - 28), ESI);
write_virtual_dword_32(BX_SEG_REG_SS, (Bit32u) (temp_ESP - 32), EDI);
ESP -= 32;
}
else
{
write_virtual_dword_32(BX_SEG_REG_SS, (Bit16u) (temp_SP - 4), EAX);
write_virtual_dword_32(BX_SEG_REG_SS, (Bit16u) (temp_SP - 8), ECX);
write_virtual_dword_32(BX_SEG_REG_SS, (Bit16u) (temp_SP - 12), EDX);
write_virtual_dword_32(BX_SEG_REG_SS, (Bit16u) (temp_SP - 16), EBX);
write_virtual_dword_32(BX_SEG_REG_SS, (Bit16u) (temp_SP - 20), temp_ESP);
write_virtual_dword_32(BX_SEG_REG_SS, (Bit16u) (temp_SP - 24), EBP);
write_virtual_dword_32(BX_SEG_REG_SS, (Bit16u) (temp_SP - 28), ESI);
write_virtual_dword_32(BX_SEG_REG_SS, (Bit16u) (temp_SP - 32), EDI);
SP -= 32;
}
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::POPAD32(bxInstruction_c *i)
{
Bit32u edi, esi, ebp, ebx, edx, ecx, eax, dummy;
if (BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.d_b)
{
Bit32u temp_ESP = ESP;
edi = read_virtual_dword_32(BX_SEG_REG_SS, (Bit32u) (temp_ESP + 0));
esi = read_virtual_dword_32(BX_SEG_REG_SS, (Bit32u) (temp_ESP + 4));
ebp = read_virtual_dword_32(BX_SEG_REG_SS, (Bit32u) (temp_ESP + 8));
dummy = read_virtual_dword_32(BX_SEG_REG_SS, (Bit32u) (temp_ESP + 12));
ebx = read_virtual_dword_32(BX_SEG_REG_SS, (Bit32u) (temp_ESP + 16));
edx = read_virtual_dword_32(BX_SEG_REG_SS, (Bit32u) (temp_ESP + 20));
ecx = read_virtual_dword_32(BX_SEG_REG_SS, (Bit32u) (temp_ESP + 24));
eax = read_virtual_dword_32(BX_SEG_REG_SS, (Bit32u) (temp_ESP + 28));
ESP += 32;
}
else
{
Bit16u temp_SP = SP;
edi = read_virtual_dword_32(BX_SEG_REG_SS, (Bit16u) (temp_SP + 0));
esi = read_virtual_dword_32(BX_SEG_REG_SS, (Bit16u) (temp_SP + 4));
ebp = read_virtual_dword_32(BX_SEG_REG_SS, (Bit16u) (temp_SP + 8));
dummy = read_virtual_dword_32(BX_SEG_REG_SS, (Bit16u) (temp_SP + 12));
ebx = read_virtual_dword_32(BX_SEG_REG_SS, (Bit16u) (temp_SP + 16));
edx = read_virtual_dword_32(BX_SEG_REG_SS, (Bit16u) (temp_SP + 20));
ecx = read_virtual_dword_32(BX_SEG_REG_SS, (Bit16u) (temp_SP + 24));
eax = read_virtual_dword_32(BX_SEG_REG_SS, (Bit16u) (temp_SP + 28));
SP += 32;
}
EDI = edi;
ESI = esi;
EBP = ebp;
EBX = ebx;
EDX = edx;
ECX = ecx;
EAX = eax;
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::ENTER32_IwIb(bxInstruction_c *i)
{
Bit16u imm16 = i->Iw();
Bit8u level = i->Ib2();
level &= 0x1F;
RSP_SPECULATIVE;
push_32(EBP);
Bit32u frame_ptr32 = ESP;
if (BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.d_b) {
Bit32u ebp = EBP; // Use temp copy for case of exception.
if (level > 0) {
/* do level-1 times */
while (--level) {
ebp -= 4;
Bit32u temp32 = read_virtual_dword_32(BX_SEG_REG_SS, ebp);
push_32(temp32);
}
/* push(frame pointer) */
push_32(frame_ptr32);
}
ESP -= imm16;
// ENTER finishes with memory write check on the final stack pointer
// the memory is touched but no write actually occurs
// emulate it by doing RMW read access from SS:ESP
read_RMW_virtual_dword_32(BX_SEG_REG_SS, ESP);
}
else {
Bit16u bp = BP;
if (level > 0) {
/* do level-1 times */
while (--level) {
bp -= 4;
Bit32u temp32 = read_virtual_dword_32(BX_SEG_REG_SS, bp);
push_32(temp32);
}
/* push(frame pointer) */
push_32(frame_ptr32);
}
SP -= imm16;
// ENTER finishes with memory write check on the final stack pointer
// the memory is touched but no write actually occurs
// emulate it by doing RMW read access from SS:SP
read_RMW_virtual_dword_32(BX_SEG_REG_SS, SP);
}
EBP = frame_ptr32;
RSP_COMMIT;
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::LEAVE32(bxInstruction_c *i)
{
BX_ASSERT(BX_CPU_THIS_PTR cpu_mode != BX_MODE_LONG_64);
Bit32u value32;
if (BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.d_b) {
value32 = read_virtual_dword_32(BX_SEG_REG_SS, EBP);
ESP = EBP + 4;
}
else {
value32 = read_virtual_dword_32(BX_SEG_REG_SS, BP);
SP = BP + 4;
}
EBP = value32;
}

View File

@ -0,0 +1,139 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2001-2009 The Bochs Project
//
// 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
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA B 02110-1301 USA
/////////////////////////////////////////////////////////////////////////
#define NEED_CPU_REG_SHORTCUTS 1
#include "bochs.h"
#include "cpu.h"
#define LOG_THIS BX_CPU_THIS_PTR
#if BX_SUPPORT_X86_64
void BX_CPP_AttrRegparmN(1) BX_CPU_C::POP_EqM(bxInstruction_c *i)
{
RSP_SPECULATIVE;
Bit64u val64 = pop_64();
// Note: there is one little weirdism here. It is possible to use
// RSP in the modrm addressing. If used, the value of RSP after the
// pop is used to calculate the address.
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
write_virtual_qword_64(i->seg(), eaddr, val64);
RSP_COMMIT;
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::PUSH_RRX(bxInstruction_c *i)
{
push_64(BX_READ_64BIT_REG(i->rm()));
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::POP_RRX(bxInstruction_c *i)
{
BX_WRITE_64BIT_REG(i->rm(), pop_64());
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::PUSH64_FS(bxInstruction_c *i)
{
push_64(BX_CPU_THIS_PTR sregs[BX_SEG_REG_FS].selector.value);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::PUSH64_GS(bxInstruction_c *i)
{
push_64(BX_CPU_THIS_PTR sregs[BX_SEG_REG_GS].selector.value);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::POP64_FS(bxInstruction_c *i)
{
Bit64u fs = read_virtual_word_64(BX_SEG_REG_SS, RSP);
load_seg_reg(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_FS], (Bit16u) fs);
RSP += 8;
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::POP64_GS(bxInstruction_c *i)
{
Bit64u gs = read_virtual_word_64(BX_SEG_REG_SS, RSP);
load_seg_reg(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_GS], (Bit16u) gs);
RSP += 8;
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::PUSH64_Id(bxInstruction_c *i)
{
Bit64u imm64 = (Bit32s) i->Id();
push_64(imm64);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::PUSH_EqM(bxInstruction_c *i)
{
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
Bit64u op1_64 = read_virtual_qword_64(i->seg(), eaddr);
push_64(op1_64);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::ENTER64_IwIb(bxInstruction_c *i)
{
Bit8u level = i->Ib2();
level &= 0x1F;
Bit64u temp_RSP = RSP, temp_RBP = RBP;
temp_RSP -= 8;
write_virtual_qword_64(BX_SEG_REG_SS, temp_RSP, temp_RBP);
Bit64u frame_ptr64 = temp_RSP;
if (level > 0) {
/* do level-1 times */
while (--level) {
temp_RBP -= 8;
Bit64u temp64 = read_virtual_qword_64(BX_SEG_REG_SS, temp_RBP);
temp_RSP -= 8;
write_virtual_qword_64(BX_SEG_REG_SS, temp_RSP, temp64);
} /* while (--level) */
/* push(frame pointer) */
temp_RSP -= 8;
write_virtual_qword_64(BX_SEG_REG_SS, temp_RSP, frame_ptr64);
} /* if (level > 0) ... */
temp_RSP -= i->Iw();
// ENTER finishes with memory write check on the final stack pointer
// the memory is touched but no write actually occurs
// emulate it by doing RMW read access from SS:RSP
read_RMW_virtual_qword_64(BX_SEG_REG_SS, temp_RSP);
RBP = frame_ptr64;
RSP = temp_RSP;
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::LEAVE64(bxInstruction_c *i)
{
// restore frame pointer
Bit64u temp64 = read_virtual_qword_64(BX_SEG_REG_SS, RBP);
RSP = RBP + 8;
RBP = temp64;
}
#endif /* if BX_SUPPORT_X86_64 */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,798 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2001-2010 The Bochs Project
//
// 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
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA B 02110-1301 USA
/////////////////////////////////////////////////////////////////////////
#define NEED_CPU_REG_SHORTCUTS 1
#include "bochs.h"
#include "cpu.h"
#define LOG_THIS BX_CPU_THIS_PTR
// Notes:
// ======
// ======================
// 286 Task State Segment
// ======================
// dynamic item | hex dec offset
// 0 task LDT selector | 2a 42
// 1 DS selector | 28 40
// 1 SS selector | 26 38
// 1 CS selector | 24 36
// 1 ES selector | 22 34
// 1 DI | 20 32
// 1 SI | 1e 30
// 1 BP | 1c 28
// 1 SP | 1a 26
// 1 BX | 18 24
// 1 DX | 16 22
// 1 CX | 14 20
// 1 AX | 12 18
// 1 flag word | 10 16
// 1 IP (entry point) | 0e 14
// 0 SS for CPL 2 | 0c 12
// 0 SP for CPL 2 | 0a 10
// 0 SS for CPL 1 | 08 08
// 0 SP for CPL 1 | 06 06
// 0 SS for CPL 0 | 04 04
// 0 SP for CPL 0 | 02 02
// back link selector to TSS | 00 00
// ======================
// 386 Task State Segment
// ======================
// |31 16|15 0| hex dec
// |I/O Map Base |000000000000000000000|T| 64 100 static
// |0000000000000000| LDT | 60 96 static
// |0000000000000000| GS selector | 5c 92 dynamic
// |0000000000000000| FS selector | 58 88 dynamic
// |0000000000000000| DS selector | 54 84 dynamic
// |0000000000000000| SS selector | 50 80 dynamic
// |0000000000000000| CS selector | 4c 76 dynamic
// |0000000000000000| ES selector | 48 72 dynamic
// | EDI | 44 68 dynamic
// | ESI | 40 64 dynamic
// | EBP | 3c 60 dynamic
// | ESP | 38 56 dynamic
// | EBX | 34 52 dynamic
// | EDX | 30 48 dynamic
// | ECX | 2c 44 dynamic
// | EAX | 28 40 dynamic
// | EFLAGS | 24 36 dynamic
// | EIP (entry point) | 20 32 dynamic
// | CR3 (PDPR) | 1c 28 static
// |000000000000000 | SS for CPL 2 | 18 24 static
// | ESP for CPL 2 | 14 20 static
// |000000000000000 | SS for CPL 1 | 10 16 static
// | ESP for CPL 1 | 0c 12 static
// |000000000000000 | SS for CPL 0 | 08 08 static
// | ESP for CPL 0 | 04 04 static
// |000000000000000 | back link to prev TSS | 00 00 dynamic (updated only when return expected)
// ==================================================
// Effect of task switch on Busy, NT, and Link Fields
// ==================================================
// Field jump call/interrupt iret
// ------------------------------------------------------
// new busy bit Set Set No change
// old busy bit Cleared No change Cleared
// new NT flag No change Set No change
// old NT flag No change No change Cleared
// new link No change old TSS selector No change
// old link No change No change No change
// CR0.TS Set Set Set
// Note: I checked 386, 486, and Pentium, and they all exhibited
// exactly the same behaviour as above. There seems to
// be some misprints in the Intel docs.
void BX_CPU_C::task_switch(bxInstruction_c *i, bx_selector_t *tss_selector,
bx_descriptor_t *tss_descriptor, unsigned source,
Bit32u dword1, Bit32u dword2)
{
Bit32u obase32; // base address of old TSS
Bit32u nbase32; // base address of new TSS
Bit32u temp32, newCR3;
Bit16u raw_cs_selector, raw_ss_selector, raw_ds_selector, raw_es_selector,
raw_fs_selector, raw_gs_selector, raw_ldt_selector;
Bit16u trap_word;
bx_selector_t cs_selector, ss_selector, ds_selector, es_selector,
fs_selector, gs_selector, ldt_selector;
bx_descriptor_t cs_descriptor, ss_descriptor, ldt_descriptor;
Bit32u old_TSS_max, new_TSS_max, old_TSS_limit, new_TSS_limit;
Bit32u newEAX, newECX, newEDX, newEBX;
Bit32u newESP, newEBP, newESI, newEDI;
Bit32u newEFLAGS, newEIP;
BX_DEBUG(("TASKING: ENTER"));
invalidate_prefetch_q();
// Discard any traps and inhibits for new context; traps will
// resume upon return.
BX_CPU_THIS_PTR debug_trap = 0;
BX_CPU_THIS_PTR inhibit_mask = 0;
// STEP 1: The following checks are made before calling task_switch(),
// for JMP & CALL only. These checks are NOT made for exceptions,
// interrupts & IRET.
//
// 1) TSS DPL must be >= CPL
// 2) TSS DPL must be >= TSS selector RPL
// 3) TSS descriptor is not busy.
// STEP 2: The processor performs limit-checking on the target TSS
// to verify that the TSS limit is greater than or equal
// to 67h (2Bh for 16-bit TSS).
// Gather info about new TSS
if (tss_descriptor->type <= 3) { // {1,3}
new_TSS_max = 0x2B;
}
else { // tss_descriptor->type = {9,11}
new_TSS_max = 0x67;
}
nbase32 = (Bit32u) tss_descriptor->u.segment.base;
new_TSS_limit = tss_descriptor->u.segment.limit_scaled;
if (new_TSS_limit < new_TSS_max) {
BX_ERROR(("task_switch(): new TSS limit < %d", new_TSS_max));
exception(BX_TS_EXCEPTION, tss_selector->value & 0xfffc);
}
#if BX_SUPPORT_VMX
VMexit_TaskSwitch(i, tss_selector->value, source);
#endif
// Gather info about old TSS
if (BX_CPU_THIS_PTR tr.cache.type <= 3) {
old_TSS_max = 0x29;
}
else {
old_TSS_max = 0x5F;
}
obase32 = (Bit32u) BX_CPU_THIS_PTR tr.cache.u.segment.base; // old TSS.base
old_TSS_limit = BX_CPU_THIS_PTR tr.cache.u.segment.limit_scaled;
if (old_TSS_limit < old_TSS_max) {
BX_ERROR(("task_switch(): old TSS limit < %d", old_TSS_max));
exception(BX_TS_EXCEPTION, BX_CPU_THIS_PTR tr.selector.value & 0xfffc);
}
if (obase32 == nbase32) {
BX_INFO(("TASK SWITCH: switching to the same TSS !"));
}
// Check that old TSS, new TSS, and all segment descriptors
// used in the task switch are paged in.
if (BX_CPU_THIS_PTR cr0.get_PG())
{
dtranslate_linear(nbase32, 0, BX_READ); // old TSS
dtranslate_linear(nbase32 + new_TSS_max, 0, BX_READ);
// ??? Humm, we check the new TSS region with READ above,
// but sometimes we need to write the link field in that
// region. We also sometimes update other fields, perhaps
// we need to WRITE check them here also, so that we keep
// the written state consistent (ie, we don't encounter a
// page fault in the middle).
if (source == BX_TASK_FROM_CALL || source == BX_TASK_FROM_INT)
{
dtranslate_linear(nbase32, 0, BX_WRITE);
dtranslate_linear(nbase32 + 1, 0, BX_WRITE);
}
}
// Privilege and busy checks done in CALL, JUMP, INT, IRET
// Step 3: If JMP or IRET, clear busy bit in old task TSS descriptor,
// otherwise leave set.
// effect on Busy bit of old task
if (source == BX_TASK_FROM_JUMP || source == BX_TASK_FROM_IRET) {
// Bit is cleared
Bit32u laddr = (Bit32u) BX_CPU_THIS_PTR gdtr.base + (BX_CPU_THIS_PTR tr.selector.index<<3) + 4;
access_read_linear(laddr, 4, 0, BX_RW, &temp32);
temp32 &= ~0x200;
access_write_linear(laddr, 4, 0, &temp32);
}
// STEP 4: If the task switch was initiated with an IRET instruction,
// clears the NT flag in a temporarily saved EFLAGS image;
// if initiated with a CALL or JMP instruction, an exception, or
// an interrupt, the NT flag is left unchanged.
Bit32u oldEFLAGS = read_eflags();
/* if moving to busy task, clear NT bit */
if (tss_descriptor->type == BX_SYS_SEGMENT_BUSY_286_TSS ||
tss_descriptor->type == BX_SYS_SEGMENT_BUSY_386_TSS)
{
oldEFLAGS &= ~EFlagsNTMask;
}
// STEP 5: Save the current task state in the TSS. Up to this point,
// any exception that occurs aborts the task switch without
// changing the processor state.
/* save current machine state in old task's TSS */
if (BX_CPU_THIS_PTR tr.cache.type <= 3) {
// check that we won't page fault while writing
if (BX_CPU_THIS_PTR cr0.get_PG()) {
dtranslate_linear(Bit32u(obase32 + 14), 0, BX_WRITE);
dtranslate_linear(Bit32u(obase32 + 41), 0, BX_WRITE);
}
system_write_word(Bit32u(obase32 + 14), IP);
system_write_word(Bit32u(obase32 + 16), oldEFLAGS);
system_write_word(Bit32u(obase32 + 18), AX);
system_write_word(Bit32u(obase32 + 20), CX);
system_write_word(Bit32u(obase32 + 22), DX);
system_write_word(Bit32u(obase32 + 24), BX);
system_write_word(Bit32u(obase32 + 26), SP);
system_write_word(Bit32u(obase32 + 28), BP);
system_write_word(Bit32u(obase32 + 30), SI);
system_write_word(Bit32u(obase32 + 32), DI);
system_write_word(Bit32u(obase32 + 34),
BX_CPU_THIS_PTR sregs[BX_SEG_REG_ES].selector.value);
system_write_word(Bit32u(obase32 + 36),
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value);
system_write_word(Bit32u(obase32 + 38),
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].selector.value);
system_write_word(Bit32u(obase32 + 40),
BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS].selector.value);
}
else {
// check that we won't page fault while writing
if (BX_CPU_THIS_PTR cr0.get_PG()) {
dtranslate_linear(Bit32u(obase32 + 0x20), 0, BX_WRITE);
dtranslate_linear(Bit32u(obase32 + 0x5d), 0, BX_WRITE);
}
system_write_dword(Bit32u(obase32 + 0x20), EIP);
system_write_dword(Bit32u(obase32 + 0x24), oldEFLAGS);
system_write_dword(Bit32u(obase32 + 0x28), EAX);
system_write_dword(Bit32u(obase32 + 0x2c), ECX);
system_write_dword(Bit32u(obase32 + 0x30), EDX);
system_write_dword(Bit32u(obase32 + 0x34), EBX);
system_write_dword(Bit32u(obase32 + 0x38), ESP);
system_write_dword(Bit32u(obase32 + 0x3c), EBP);
system_write_dword(Bit32u(obase32 + 0x40), ESI);
system_write_dword(Bit32u(obase32 + 0x44), EDI);
system_write_word(Bit32u(obase32 + 0x48),
BX_CPU_THIS_PTR sregs[BX_SEG_REG_ES].selector.value);
system_write_word(Bit32u(obase32 + 0x4c),
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value);
system_write_word(Bit32u(obase32 + 0x50),
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].selector.value);
system_write_word(Bit32u(obase32 + 0x54),
BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS].selector.value);
system_write_word(Bit32u(obase32 + 0x58),
BX_CPU_THIS_PTR sregs[BX_SEG_REG_FS].selector.value);
system_write_word(Bit32u(obase32 + 0x5c),
BX_CPU_THIS_PTR sregs[BX_SEG_REG_GS].selector.value);
}
// effect on link field of new task
if (source == BX_TASK_FROM_CALL || source == BX_TASK_FROM_INT)
{
// set to selector of old task's TSS
system_write_word(nbase32, BX_CPU_THIS_PTR tr.selector.value);
}
// STEP 6: The new-task state is loaded from the TSS
if (tss_descriptor->type <= 3) {
newEIP = system_read_word(Bit32u(nbase32 + 14));
newEFLAGS = system_read_word(Bit32u(nbase32 + 16));
// incoming TSS is 16bit:
// - upper word of general registers is set to 0xFFFF
// - upper word of eflags is zero'd
// - FS, GS are zero'd
// - upper word of eIP is zero'd
Bit16u temp16 = system_read_word(Bit32u(nbase32 + 18));
newEAX = 0xffff0000 | temp16;
temp16 = system_read_word(Bit32u(nbase32 + 20));
newECX = 0xffff0000 | temp16;
temp16 = system_read_word(Bit32u(nbase32 + 22));
newEDX = 0xffff0000 | temp16;
temp16 = system_read_word(Bit32u(nbase32 + 24));
newEBX = 0xffff0000 | temp16;
temp16 = system_read_word(Bit32u(nbase32 + 26));
newESP = 0xffff0000 | temp16;
temp16 = system_read_word(Bit32u(nbase32 + 28));
newEBP = 0xffff0000 | temp16;
temp16 = system_read_word(Bit32u(nbase32 + 30));
newESI = 0xffff0000 | temp16;
temp16 = system_read_word(Bit32u(nbase32 + 32));
newEDI = 0xffff0000 | temp16;
raw_es_selector = system_read_word(Bit32u(nbase32 + 34));
raw_cs_selector = system_read_word(Bit32u(nbase32 + 36));
raw_ss_selector = system_read_word(Bit32u(nbase32 + 38));
raw_ds_selector = system_read_word(Bit32u(nbase32 + 40));
raw_ldt_selector = system_read_word(Bit32u(nbase32 + 42));
raw_fs_selector = 0; // use a NULL selector
raw_gs_selector = 0; // use a NULL selector
// No CR3 change for 286 task switch
newCR3 = 0; // keep compiler happy (not used)
trap_word = 0; // keep compiler happy (not used)
}
else {
if (BX_CPU_THIS_PTR cr0.get_PG())
newCR3 = system_read_dword(Bit32u(nbase32 + 0x1c));
else
newCR3 = 0; // keep compiler happy (not used)
newEIP = system_read_dword(Bit32u(nbase32 + 0x20));
newEFLAGS = system_read_dword(Bit32u(nbase32 + 0x24));
newEAX = system_read_dword(Bit32u(nbase32 + 0x28));
newECX = system_read_dword(Bit32u(nbase32 + 0x2c));
newEDX = system_read_dword(Bit32u(nbase32 + 0x30));
newEBX = system_read_dword(Bit32u(nbase32 + 0x34));
newESP = system_read_dword(Bit32u(nbase32 + 0x38));
newEBP = system_read_dword(Bit32u(nbase32 + 0x3c));
newESI = system_read_dword(Bit32u(nbase32 + 0x40));
newEDI = system_read_dword(Bit32u(nbase32 + 0x44));
raw_es_selector = system_read_word(Bit32u(nbase32 + 0x48));
raw_cs_selector = system_read_word(Bit32u(nbase32 + 0x4c));
raw_ss_selector = system_read_word(Bit32u(nbase32 + 0x50));
raw_ds_selector = system_read_word(Bit32u(nbase32 + 0x54));
raw_fs_selector = system_read_word(Bit32u(nbase32 + 0x58));
raw_gs_selector = system_read_word(Bit32u(nbase32 + 0x5c));
raw_ldt_selector = system_read_word(Bit32u(nbase32 + 0x60));
trap_word = system_read_word(Bit32u(nbase32 + 0x64));
}
// Step 7: If CALL, interrupt, or JMP, set busy flag in new task's
// TSS descriptor. If IRET, leave set.
if (source != BX_TASK_FROM_IRET)
{
// set the new task's busy bit
Bit32u laddr = (Bit32u)(BX_CPU_THIS_PTR gdtr.base) + (tss_selector->index<<3) + 4;
access_read_linear(laddr, 4, 0, BX_RW, &dword2);
dword2 |= 0x200;
access_write_linear(laddr, 4, 0, &dword2);
}
//
// Commit point. At this point, we commit to the new
// context. If an unrecoverable error occurs in further
// processing, we complete the task switch without performing
// additional access and segment availablility checks and
// generate the appropriate exception prior to beginning
// execution of the new task.
//
// Step 8: Load the task register with the segment selector and
// descriptor for the new task TSS.
BX_CPU_THIS_PTR tr.selector = *tss_selector;
BX_CPU_THIS_PTR tr.cache = *tss_descriptor;
BX_CPU_THIS_PTR tr.cache.type |= 2; // mark TSS in TR as busy
// Step 9: Set TS flag in the CR0 image stored in the new task TSS.
BX_CPU_THIS_PTR cr0.set_TS(1);
// Task switch clears LE/L3/L2/L1/L0 in DR7
BX_CPU_THIS_PTR dr7 &= ~0x00000155;
// Step 10: If call or interrupt, set the NT flag in the eflags
// image stored in new task's TSS. If IRET or JMP,
// NT is restored from new TSS eflags image. (no change)
// effect on NT flag of new task
if (source == BX_TASK_FROM_CALL || source == BX_TASK_FROM_INT) {
newEFLAGS |= EFlagsNTMask; // NT flag is set
}
// Step 11: Load the new task (dynamic) state from new TSS.
// Any errors associated with loading and qualification of
// segment descriptors in this step occur in the new task's
// context. State loaded here includes LDTR, CR3,
// EFLAGS, EIP, general purpose registers, and segment
// descriptor parts of the segment registers.
BX_CPU_THIS_PTR prev_rip = EIP = newEIP;
EAX = newEAX;
ECX = newECX;
EDX = newEDX;
EBX = newEBX;
ESP = newESP;
EBP = newEBP;
ESI = newESI;
EDI = newEDI;
BX_CPU_THIS_PTR speculative_rsp = 0;
writeEFlags(newEFLAGS, EFlagsValidMask);
// Fill in selectors for all segment registers. If errors
// occur later, the selectors will at least be loaded.
parse_selector(raw_cs_selector, &cs_selector);
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector = cs_selector;
parse_selector(raw_ss_selector, &ss_selector);
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].selector = ss_selector;
parse_selector(raw_ds_selector, &ds_selector);
BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS].selector = ds_selector;
parse_selector(raw_es_selector, &es_selector);
BX_CPU_THIS_PTR sregs[BX_SEG_REG_ES].selector = es_selector;
parse_selector(raw_fs_selector, &fs_selector);
BX_CPU_THIS_PTR sregs[BX_SEG_REG_FS].selector = fs_selector;
parse_selector(raw_gs_selector, &gs_selector);
BX_CPU_THIS_PTR sregs[BX_SEG_REG_GS].selector = gs_selector;
parse_selector(raw_ldt_selector, &ldt_selector);
BX_CPU_THIS_PTR ldtr.selector = ldt_selector;
// Start out with invalid descriptor caches, fill in with
// values only as they are validated
BX_CPU_THIS_PTR ldtr.cache.valid = 0;
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.valid = 0;
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.valid = 0;
BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS].cache.valid = 0;
BX_CPU_THIS_PTR sregs[BX_SEG_REG_ES].cache.valid = 0;
BX_CPU_THIS_PTR sregs[BX_SEG_REG_FS].cache.valid = 0;
BX_CPU_THIS_PTR sregs[BX_SEG_REG_GS].cache.valid = 0;
if ((tss_descriptor->type >= 9) && BX_CPU_THIS_PTR cr0.get_PG()) {
// change CR3 only if it actually modified
if (newCR3 != BX_CPU_THIS_PTR cr3) {
BX_DEBUG(("task_switch changing CR3 to 0x%08x", newCR3));
#if BX_CPU_LEVEL >= 6
if (BX_CPU_THIS_PTR cr0.get_PG() && BX_CPU_THIS_PTR cr4.get_PAE()) {
if (! CheckPDPTR(newCR3)) {
BX_ERROR(("task_switch(exception after commit point): PDPTR check failed !"));
exception(BX_GP_EXCEPTION, 0);
}
}
#endif
if (! SetCR3(newCR3)) // Tell paging unit about new cr3 value
exception(BX_GP_EXCEPTION, 0);
BX_INSTR_TLB_CNTRL(BX_CPU_ID, BX_INSTR_TASKSWITCH, newCR3);
}
}
unsigned save_CPL = CPL;
/* set CPL to 3 to force a privilege level change and stack switch if SS
is not properly loaded */
CPL = 3;
// LDTR
if (ldt_selector.ti) {
// LDT selector must be in GDT
BX_INFO(("task_switch(exception after commit point): bad LDT selector TI=1"));
exception(BX_TS_EXCEPTION, raw_ldt_selector & 0xfffc);
}
if ((raw_ldt_selector & 0xfffc) != 0) {
bx_bool good = fetch_raw_descriptor2(&ldt_selector, &dword1, &dword2);
if (!good) {
BX_ERROR(("task_switch(exception after commit point): bad LDT fetch"));
exception(BX_TS_EXCEPTION, raw_ldt_selector & 0xfffc);
}
parse_descriptor(dword1, dword2, &ldt_descriptor);
// LDT selector of new task is valid, else #TS(new task's LDT)
if (ldt_descriptor.valid==0 ||
ldt_descriptor.type!=BX_SYS_SEGMENT_LDT ||
ldt_descriptor.segment)
{
BX_ERROR(("task_switch(exception after commit point): bad LDT segment"));
exception(BX_TS_EXCEPTION, raw_ldt_selector & 0xfffc);
}
// LDT of new task is present in memory, else #TS(new tasks's LDT)
if (! IS_PRESENT(ldt_descriptor)) {
BX_ERROR(("task_switch(exception after commit point): LDT not present"));
exception(BX_TS_EXCEPTION, raw_ldt_selector & 0xfffc);
}
// All checks pass, fill in LDTR shadow cache
BX_CPU_THIS_PTR ldtr.cache = ldt_descriptor;
}
else {
// NULL LDT selector is OK, leave cache invalid
}
if (v8086_mode()) {
// load seg regs as 8086 registers
load_seg_reg(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS], raw_ss_selector);
load_seg_reg(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS], raw_ds_selector);
load_seg_reg(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_ES], raw_es_selector);
load_seg_reg(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_FS], raw_fs_selector);
load_seg_reg(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_GS], raw_gs_selector);
load_seg_reg(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS], raw_cs_selector);
// CPL is set from CS selector
}
else {
// SS
if ((raw_ss_selector & 0xfffc) != 0)
{
bx_bool good = fetch_raw_descriptor2(&ss_selector, &dword1, &dword2);
if (!good) {
BX_ERROR(("task_switch(exception after commit point): bad SS fetch"));
exception(BX_TS_EXCEPTION, raw_ss_selector & 0xfffc);
}
parse_descriptor(dword1, dword2, &ss_descriptor);
// SS selector must be within its descriptor table limits else #TS(SS)
// SS descriptor AR byte must must indicate writable data segment,
// else #TS(SS)
if (ss_descriptor.valid==0 || ss_descriptor.segment==0 ||
IS_CODE_SEGMENT(ss_descriptor.type) ||
!IS_DATA_SEGMENT_WRITEABLE(ss_descriptor.type))
{
BX_ERROR(("task_switch(exception after commit point): SS not valid or writeable segment"));
exception(BX_TS_EXCEPTION, raw_ss_selector & 0xfffc);
}
//
// Stack segment is present in memory, else #SS(new stack segment)
//
if (! IS_PRESENT(ss_descriptor)) {
BX_ERROR(("task_switch(exception after commit point): SS not present"));
exception(BX_SS_EXCEPTION, raw_ss_selector & 0xfffc);
}
// Stack segment DPL matches CS.RPL, else #TS(new stack segment)
if (ss_descriptor.dpl != cs_selector.rpl) {
BX_ERROR(("task_switch(exception after commit point): SS.rpl != CS.RPL"));
exception(BX_TS_EXCEPTION, raw_ss_selector & 0xfffc);
}
// Stack segment DPL matches selector RPL, else #TS(new stack segment)
if (ss_descriptor.dpl != ss_selector.rpl) {
BX_ERROR(("task_switch(exception after commit point): SS.dpl != SS.rpl"));
exception(BX_TS_EXCEPTION, raw_ss_selector & 0xfffc);
}
touch_segment(&ss_selector, &ss_descriptor);
// All checks pass, fill in shadow cache
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache = ss_descriptor;
}
else {
// SS selector is valid, else #TS(new stack segment)
BX_ERROR(("task_switch(exception after commit point): SS NULL"));
exception(BX_TS_EXCEPTION, raw_ss_selector & 0xfffc);
}
CPL = save_CPL;
task_switch_load_selector(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS],
&ds_selector, raw_ds_selector, cs_selector.rpl);
task_switch_load_selector(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_ES],
&es_selector, raw_es_selector, cs_selector.rpl);
task_switch_load_selector(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_FS],
&fs_selector, raw_fs_selector, cs_selector.rpl);
task_switch_load_selector(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_GS],
&gs_selector, raw_gs_selector, cs_selector.rpl);
// if new selector is not null then perform following checks:
// index must be within its descriptor table limits else #TS(selector)
// AR byte must indicate data or readable code else #TS(selector)
// if data or non-conforming code then:
// DPL must be >= CPL else #TS(selector)
// DPL must be >= RPL else #TS(selector)
// AR byte must indicate PRESENT else #NP(selector)
// load cache with new segment descriptor and set valid bit
// CS
if ((raw_cs_selector & 0xfffc) != 0) {
bx_bool good = fetch_raw_descriptor2(&cs_selector, &dword1, &dword2);
if (!good) {
BX_ERROR(("task_switch(exception after commit point): bad CS fetch"));
exception(BX_TS_EXCEPTION, raw_cs_selector & 0xfffc);
}
parse_descriptor(dword1, dword2, &cs_descriptor);
// CS descriptor AR byte must indicate code segment else #TS(CS)
if (cs_descriptor.valid==0 || cs_descriptor.segment==0 ||
IS_DATA_SEGMENT(cs_descriptor.type))
{
BX_ERROR(("task_switch(exception after commit point): CS not valid executable seg"));
exception(BX_TS_EXCEPTION, raw_cs_selector & 0xfffc);
}
// if non-conforming then DPL must equal selector RPL else #TS(CS)
if (IS_CODE_SEGMENT_NON_CONFORMING(cs_descriptor.type) &&
cs_descriptor.dpl != cs_selector.rpl)
{
BX_ERROR(("task_switch(exception after commit point): non-conforming: CS.dpl!=CS.RPL"));
exception(BX_TS_EXCEPTION, raw_cs_selector & 0xfffc);
}
// if conforming then DPL must be <= selector RPL else #TS(CS)
if (IS_CODE_SEGMENT_CONFORMING(cs_descriptor.type) &&
cs_descriptor.dpl > cs_selector.rpl)
{
BX_ERROR(("task_switch(exception after commit point): conforming: CS.dpl>RPL"));
exception(BX_TS_EXCEPTION, raw_cs_selector & 0xfffc);
}
// Code segment is present in memory, else #NP(new code segment)
if (! IS_PRESENT(cs_descriptor)) {
BX_ERROR(("task_switch(exception after commit point): CS.p==0"));
exception(BX_NP_EXCEPTION, raw_cs_selector & 0xfffc);
}
touch_segment(&cs_selector, &cs_descriptor);
#ifdef BX_SUPPORT_CS_LIMIT_DEMOTION
// Handle special case of CS.LIMIT demotion (new descriptor limit is
// smaller than current one)
if (BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.limit_scaled > cs_descriptor.u.segment.limit_scaled)
BX_CPU_THIS_PTR iCache.flushICacheEntries();
#endif
// All checks pass, fill in shadow cache
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache = cs_descriptor;
}
else {
// If new cs selector is null #TS(CS)
BX_ERROR(("task_switch(exception after commit point): CS NULL"));
exception(BX_TS_EXCEPTION, raw_cs_selector & 0xfffc);
}
updateFetchModeMask(/* CS reloaded */);
#if BX_CPU_LEVEL >= 4 && BX_SUPPORT_ALIGNMENT_CHECK
handleAlignmentCheck(); // task switch, CPL was modified
#endif
}
if (tss_descriptor->type >= 9 && (trap_word & 0x1)) {
BX_CPU_THIS_PTR debug_trap |= BX_DEBUG_TRAP_TASK_SWITCH_BIT; // BT flag
BX_CPU_THIS_PTR async_event = 1; // so processor knows to check
BX_INFO(("task_switch: T bit set in new TSS"));
}
#if BX_CPU_LEVEL >= 6
handleSseModeChange(); /* CR0.TS changes */
#endif
//
// Step 12: Begin execution of new task.
//
BX_DEBUG(("TASKING: LEAVE"));
}
void BX_CPU_C::task_switch_load_selector(bx_segment_reg_t *seg,
bx_selector_t *selector, Bit16u raw_selector, Bit8u cs_rpl)
{
bx_descriptor_t descriptor;
Bit32u dword1, dword2;
// NULL selector is OK, will leave cache invalid
if ((raw_selector & 0xfffc) != 0)
{
bx_bool good = fetch_raw_descriptor2(selector, &dword1, &dword2);
if (!good) {
BX_ERROR(("task_switch(%s): bad selector fetch !", strseg(seg)));
exception(BX_TS_EXCEPTION, raw_selector & 0xfffc);
}
parse_descriptor(dword1, dword2, &descriptor);
/* AR byte must indicate data or readable code segment else #TS(selector) */
if (descriptor.segment==0 || (IS_CODE_SEGMENT(descriptor.type) &&
IS_CODE_SEGMENT_READABLE(descriptor.type) == 0))
{
BX_ERROR(("task_switch(%s): not data or readable code !", strseg(seg)));
exception(BX_TS_EXCEPTION, raw_selector & 0xfffc);
}
/* If data or non-conforming code, then both the RPL and the CPL
* must be less than or equal to DPL in AR byte else #GP(selector) */
if (IS_DATA_SEGMENT(descriptor.type) ||
IS_CODE_SEGMENT_NON_CONFORMING(descriptor.type))
{
if ((selector->rpl > descriptor.dpl) || (cs_rpl > descriptor.dpl)) {
BX_ERROR(("load_seg_reg(%s): RPL & CPL must be <= DPL", strseg(seg)));
exception(BX_TS_EXCEPTION, raw_selector & 0xfffc);
}
}
if (! IS_PRESENT(descriptor)) {
BX_ERROR(("task_switch(%s): descriptor not present !", strseg(seg)));
exception(BX_NP_EXCEPTION, raw_selector & 0xfffc);
}
touch_segment(selector, &descriptor);
// All checks pass, fill in shadow cache
seg->cache = descriptor;
}
}
void BX_CPU_C::get_SS_ESP_from_TSS(unsigned pl, Bit16u *ss, Bit32u *esp)
{
if (BX_CPU_THIS_PTR tr.cache.valid==0)
BX_PANIC(("get_SS_ESP_from_TSS: TR.cache invalid"));
if (BX_CPU_THIS_PTR tr.cache.type==BX_SYS_SEGMENT_AVAIL_386_TSS ||
BX_CPU_THIS_PTR tr.cache.type==BX_SYS_SEGMENT_BUSY_386_TSS)
{
// 32-bit TSS
Bit32u TSSstackaddr = 8*pl + 4;
if ((TSSstackaddr+7) > BX_CPU_THIS_PTR tr.cache.u.segment.limit_scaled) {
BX_DEBUG(("get_SS_ESP_from_TSS(386): TSSstackaddr > TSS.LIMIT"));
exception(BX_TS_EXCEPTION, BX_CPU_THIS_PTR tr.selector.value & 0xfffc);
}
*ss = system_read_word (BX_CPU_THIS_PTR tr.cache.u.segment.base + TSSstackaddr + 4);
*esp = system_read_dword(BX_CPU_THIS_PTR tr.cache.u.segment.base + TSSstackaddr);
}
else if (BX_CPU_THIS_PTR tr.cache.type==BX_SYS_SEGMENT_AVAIL_286_TSS ||
BX_CPU_THIS_PTR tr.cache.type==BX_SYS_SEGMENT_BUSY_286_TSS)
{
// 16-bit TSS
Bit32u TSSstackaddr = 4*pl + 2;
if ((TSSstackaddr+3) > BX_CPU_THIS_PTR tr.cache.u.segment.limit_scaled) {
BX_DEBUG(("get_SS_ESP_from_TSS(286): TSSstackaddr > TSS.LIMIT"));
exception(BX_TS_EXCEPTION, BX_CPU_THIS_PTR tr.selector.value & 0xfffc);
}
*ss = system_read_word(BX_CPU_THIS_PTR tr.cache.u.segment.base + TSSstackaddr + 2);
*esp = (Bit32u) system_read_word(BX_CPU_THIS_PTR tr.cache.u.segment.base + TSSstackaddr);
}
else {
BX_PANIC(("get_SS_ESP_from_TSS: TR is bogus type (%u)", (unsigned) BX_CPU_THIS_PTR tr.cache.type));
}
}
#if BX_SUPPORT_X86_64
Bit64u BX_CPU_C::get_RSP_from_TSS(unsigned pl)
{
if (BX_CPU_THIS_PTR tr.cache.valid==0)
BX_PANIC(("get_RSP_from_TSS: TR.cache invalid"));
// 32-bit TSS
Bit32u TSSstackaddr = 8*pl + 4;
if ((TSSstackaddr+7) > BX_CPU_THIS_PTR tr.cache.u.segment.limit_scaled) {
BX_DEBUG(("get_RSP_from_TSS(): TSSstackaddr > TSS.LIMIT"));
exception(BX_TS_EXCEPTION, BX_CPU_THIS_PTR tr.selector.value & 0xfffc);
}
Bit64u rsp = system_read_qword(BX_CPU_THIS_PTR tr.cache.u.segment.base + TSSstackaddr);
if (! IsCanonical(rsp)) {
BX_ERROR(("get_RSP_from_TSS: canonical address failure 0x%08x%08x", GET32H(rsp), GET32L(rsp)));
exception(BX_SS_EXCEPTION, BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].selector.value & 0xfffc);
}
return rsp;
}
#endif // #if BX_SUPPORT_X86_64

52
simulators/bochs/cpu/todo Executable file
View File

@ -0,0 +1,52 @@
TODO (know issues in CPU model):
-------------------------------
[!] The following 3DNow! instructions still not implemented:
PF2IW_PqQq
PFNACC_PqQq
PFPNACC_PqQq
PFCMPGE_PqQq
PFCMPGT_PqQq
PFCMPEQ_PqQq
PFMIN_PqQq
PFMAX_PqQq
PFRCP_PqQq
PFRSQRT_PqQq
PFSUB_PqQq
PFSUBR_PqQq
PFADD_PqQq
PFACC_PqQq,
PFMUL_PqQq
PFRCPIT1_PqQq
PFRSQIT1_PqQq
PFRCPIT2_PqQq
[!] CPUID does not report 3DNow! instruction set
[!] Some of APIC functionality still not implemented, for example
- LVT pins handling
- Filter interrupts according processor priority (PPR)
[!] REP NOP is PAUSE (on P4/XEON)
When running in SMP mode, this means that we are in a spin loop.
This processor should yield to the other one, as we are anyhow waiting
for a lock, and any other processor is responsible for this.
[!] 32-bit linear address wrap when executing in legacy mode might be
not implemented correctly for system memory accesses (like descriptor
tables and etc)
[!] AMD and Intel x86_64 implementations are different.
Currently Bochs emulation is according to Intel version.
Do we need to support both ?
[!] More flexible CPUID - vendor and etc
[!] VMX:
- Dual-monitor treatment of SMIs and SMM not implemented yet
- VMENTER to not-active state not supported yet
[!] SSE4A, SMX, SVM, AVX

View File

@ -0,0 +1,263 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2001-2009 The Bochs Project
//
// 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
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA B 02110-1301 USA
/////////////////////////////////////////////////////////////////////////
#define NEED_CPU_REG_SHORTCUTS 1
#include "bochs.h"
#include "cpu.h"
#define LOG_THIS BX_CPU_THIS_PTR
//
// Notes:
//
// The high bits of the 32bit eip image are ignored by
// the IRET to VM. The high bits of the 32bit esp image
// are loaded into ESP. A subsequent push uses
// only the low 16bits since it's in VM. In neither case
// did a protection fault occur during actual tests. This
// is contrary to the Intel docs which claim a #GP for
// eIP out of code limits.
//
// IRET to VM does affect IOPL, IF, VM, and RF
//
#if BX_CPU_LEVEL >= 3
void BX_CPU_C::stack_return_to_v86(Bit32u new_eip, Bit32u raw_cs_selector, Bit32u flags32)
{
Bit32u temp_ESP, new_esp;
Bit16u raw_es_selector, raw_ds_selector, raw_fs_selector,
raw_gs_selector, raw_ss_selector;
// Must be 32bit effective opsize, VM is set in upper 16bits of eFLAGS
// and CPL = 0 to get here
// ----------------
// | | OLD GS | eSP+32
// | | OLD FS | eSP+28
// | | OLD DS | eSP+24
// | | OLD ES | eSP+20
// | | OLD SS | eSP+16
// | OLD ESP | eSP+12
// | OLD EFLAGS | eSP+8
// | | OLD CS | eSP+4
// | OLD EIP | eSP+0
// ----------------
if (BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.d_b)
temp_ESP = ESP;
else
temp_ESP = SP;
// load SS:ESP from stack
new_esp = read_virtual_dword_32(BX_SEG_REG_SS, temp_ESP+12);
raw_ss_selector = (Bit16u) read_virtual_dword_32(BX_SEG_REG_SS, temp_ESP+16);
// load ES,DS,FS,GS from stack
raw_es_selector = (Bit16u) read_virtual_dword_32(BX_SEG_REG_SS, temp_ESP+20);
raw_ds_selector = (Bit16u) read_virtual_dword_32(BX_SEG_REG_SS, temp_ESP+24);
raw_fs_selector = (Bit16u) read_virtual_dword_32(BX_SEG_REG_SS, temp_ESP+28);
raw_gs_selector = (Bit16u) read_virtual_dword_32(BX_SEG_REG_SS, temp_ESP+32);
writeEFlags(flags32, EFlagsValidMask);
// load CS:IP from stack; already read and passed as args
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value = raw_cs_selector;
EIP = new_eip & 0xffff;
BX_CPU_THIS_PTR sregs[BX_SEG_REG_ES].selector.value = raw_es_selector;
BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS].selector.value = raw_ds_selector;
BX_CPU_THIS_PTR sregs[BX_SEG_REG_FS].selector.value = raw_fs_selector;
BX_CPU_THIS_PTR sregs[BX_SEG_REG_GS].selector.value = raw_gs_selector;
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].selector.value = raw_ss_selector;
ESP = new_esp; // full 32 bit are loaded
init_v8086_mode();
}
#if BX_CPU_LEVEL >= 5
#define BX_CR4_VME_ENABLED (BX_CPU_THIS_PTR cr4.get_VME())
#else
#define BX_CR4_VME_ENABLED (0)
#endif
void BX_CPU_C::iret16_stack_return_from_v86(bxInstruction_c *i)
{
if ((BX_CPU_THIS_PTR get_IOPL() < 3) && (BX_CR4_VME_ENABLED == 0)) {
// trap to virtual 8086 monitor
BX_DEBUG(("IRET in vm86 with IOPL != 3, VME = 0"));
exception(BX_GP_EXCEPTION, 0);
}
Bit16u ip, cs_raw, flags16;
ip = pop_16();
cs_raw = pop_16();
flags16 = pop_16();
#if BX_CPU_LEVEL >= 5
if (BX_CPU_THIS_PTR cr4.get_VME() && BX_CPU_THIS_PTR get_IOPL() < 3)
{
if (((flags16 & EFlagsIFMask) && BX_CPU_THIS_PTR get_VIP()) ||
(flags16 & EFlagsTFMask))
{
BX_DEBUG(("iret16_stack_return_from_v86(): #GP(0) in VME mode"));
exception(BX_GP_EXCEPTION, 0);
}
load_seg_reg(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS], cs_raw);
EIP = (Bit32u) ip;
// IF, IOPL unchanged, EFLAGS.VIF = TMP_FLAGS.IF
Bit32u changeMask = EFlagsOSZAPCMask | EFlagsTFMask |
EFlagsDFMask | EFlagsNTMask | EFlagsVIFMask;
Bit32u flags32 = (Bit32u) flags16;
if (flags16 & EFlagsIFMask) flags32 |= EFlagsVIFMask;
writeEFlags(flags32, changeMask);
return;
}
#endif
load_seg_reg(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS], cs_raw);
EIP = (Bit32u) ip;
write_flags(flags16, /*IOPL*/ 0, /*IF*/ 1);
}
void BX_CPU_C::iret32_stack_return_from_v86(bxInstruction_c *i)
{
if (BX_CPU_THIS_PTR get_IOPL() < 3) {
// trap to virtual 8086 monitor
BX_DEBUG(("IRET in vm86 with IOPL != 3, VME = 0"));
exception(BX_GP_EXCEPTION, 0);
}
Bit32u eip, cs_raw, flags32;
// Build a mask of the following bits:
// ID,VIP,VIF,AC,VM,RF,x,NT,IOPL,OF,DF,IF,TF,SF,ZF,x,AF,x,PF,x,CF
Bit32u change_mask = EFlagsOSZAPCMask | EFlagsTFMask | EFlagsIFMask
| EFlagsDFMask | EFlagsNTMask | EFlagsRFMask;
#if BX_CPU_LEVEL >= 4
change_mask |= (EFlagsIDMask | EFlagsACMask); // ID/AC
#endif
eip = pop_32();
cs_raw = pop_32();
flags32 = pop_32();
load_seg_reg(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS], (Bit16u) cs_raw);
EIP = eip;
// VIF, VIP, VM, IOPL unchanged
writeEFlags(flags32, change_mask);
}
int BX_CPU_C::v86_redirect_interrupt(Bit8u vector)
{
#if BX_CPU_LEVEL >= 5
if (BX_CPU_THIS_PTR cr4.get_VME())
{
bx_address tr_base = BX_CPU_THIS_PTR tr.cache.u.segment.base;
if (BX_CPU_THIS_PTR tr.cache.u.segment.limit_scaled < 103) {
BX_ERROR(("INT_Ib(): TR.limit < 103 in VME"));
exception(BX_GP_EXCEPTION, 0);
}
Bit32u io_base = system_read_word(tr_base + 102), offset = io_base - 32 + (vector >> 3);
if (offset > BX_CPU_THIS_PTR tr.cache.u.segment.limit_scaled) {
BX_ERROR(("INT_Ib(): failed to fetch VME redirection bitmap"));
exception(BX_GP_EXCEPTION, 0);
}
Bit8u vme_redirection_bitmap = system_read_byte(tr_base + offset);
if (!(vme_redirection_bitmap & (1 << (vector & 7))))
{
// redirect interrupt through virtual-mode idt
Bit16u temp_flags = (Bit16u) read_eflags();
Bit16u temp_CS = system_read_word(vector*4 + 2);
Bit16u temp_IP = system_read_word(vector*4);
if (BX_CPU_THIS_PTR get_IOPL() < 3) {
temp_flags |= EFlagsIOPLMask;
if (BX_CPU_THIS_PTR get_VIF())
temp_flags |= EFlagsIFMask;
else
temp_flags &= ~EFlagsIFMask;
}
Bit16u old_IP = IP;
Bit16u old_CS = BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value;
push_16(temp_flags);
// push return address onto new stack
push_16(old_CS);
push_16(old_IP);
load_seg_reg(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS], (Bit16u) temp_CS);
EIP = temp_IP;
BX_CPU_THIS_PTR clear_TF();
BX_CPU_THIS_PTR clear_RF();
if (BX_CPU_THIS_PTR get_IOPL() == 3)
BX_CPU_THIS_PTR clear_IF();
else
BX_CPU_THIS_PTR clear_VIF();
return 1;
}
}
#endif
// interrupt is not redirected or VME is OFF
if (BX_CPU_THIS_PTR get_IOPL() < 3)
{
BX_DEBUG(("INT_Ib(): Interrupt cannot be redirected, generate #GP(0)"));
exception(BX_GP_EXCEPTION, 0);
}
return 0;
}
void BX_CPU_C::init_v8086_mode(void)
{
for(unsigned sreg = 0; sreg < 6; sreg++) {
BX_CPU_THIS_PTR sregs[sreg].cache.valid = SegValidCache | SegAccessROK | SegAccessWOK;
BX_CPU_THIS_PTR sregs[sreg].cache.p = 1;
BX_CPU_THIS_PTR sregs[sreg].cache.dpl = 3;
BX_CPU_THIS_PTR sregs[sreg].cache.segment = 1;
BX_CPU_THIS_PTR sregs[sreg].cache.type = BX_DATA_READ_WRITE_ACCESSED;
BX_CPU_THIS_PTR sregs[sreg].cache.u.segment.base =
BX_CPU_THIS_PTR sregs[sreg].selector.value << 4;
BX_CPU_THIS_PTR sregs[sreg].cache.u.segment.limit_scaled = 0xffff;
BX_CPU_THIS_PTR sregs[sreg].cache.u.segment.g = 0;
BX_CPU_THIS_PTR sregs[sreg].cache.u.segment.d_b = 0;
BX_CPU_THIS_PTR sregs[sreg].cache.u.segment.avl = 0;
BX_CPU_THIS_PTR sregs[sreg].selector.rpl = 3;
}
handleCpuModeChange();
#if BX_CPU_LEVEL >= 4 && BX_SUPPORT_ALIGNMENT_CHECK
handleAlignmentCheck(/* CPL change */);
#endif
}
#endif /* BX_CPU_LEVEL >= 3 */

324
simulators/bochs/cpu/vmcs.cc Executable file
View File

@ -0,0 +1,324 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2009-2010 Stanislav Shwartsman
// 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
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA B 02110-1301 USA
//
/////////////////////////////////////////////////////////////////////////
#define NEED_CPU_REG_SHORTCUTS 1
#include "bochs.h"
#include "cpu.h"
#define LOG_THIS BX_CPU_THIS_PTR
#if BX_SUPPORT_VMX
static unsigned vmcs_map[16][1+VMX_HIGHEST_VMCS_ENCODING];
void BX_CPU_C::init_VMCS(void)
{
static bx_bool vmcs_map_ready = 0;
unsigned type, field;
if (vmcs_map_ready) return;
vmcs_map_ready = 1;
for (type=0; type<16; type++) {
for (field=0; field <= VMX_HIGHEST_VMCS_ENCODING; field++) {
vmcs_map[type][field] = 0xffffffff;
}
}
#if 1
// try to build generic VMCS map
for (type=0; type<16; type++) {
for (field=0; field <= VMX_HIGHEST_VMCS_ENCODING; field++) {
unsigned encoding = ((type & 0xc) << 11) + ((type & 3) << 10) + field;
if (vmcs_map[type][field] != 0xffffffff) {
BX_PANIC(("VMCS type %d field %d (encoding = 0x%08x) is already initialized", type, field, encoding));
}
if (vmcs_field_supported(encoding)) {
// allocate 64 fields (4 byte each) per type
vmcs_map[type][field] = VMCS_DATA_OFFSET + (type*64 + field) * 4;
if(vmcs_map[type][field] >= VMX_VMCS_AREA_SIZE) {
BX_PANIC(("VMCS type %d field %d (encoding = 0x%08x) is out of VMCS boundaries", type, field, encoding));
}
}
}
}
#else
// define your own VMCS format
#include "vmcs.h"
#endif
}
#define VMCS_ENCODING_RESERVED_BITS (0xffff9000)
unsigned vmcs_field_offset(Bit32u encoding)
{
if (encoding & VMCS_ENCODING_RESERVED_BITS)
return 0xffffffff;
unsigned field = VMCS_FIELD(encoding);
if (field >= VMX_HIGHEST_VMCS_ENCODING)
return 0xffffffff;
return vmcs_map[VMCS_FIELD_INDEX(encoding)][field];
}
bx_bool BX_CPU_C::vmcs_field_supported(Bit32u encoding)
{
switch(encoding)
{
#if BX_SUPPORT_VMX >= 2
/* VMCS 16-bit control fields */
/* binary 0000_00xx_xxxx_xxx0 */
case VMCS_16BIT_CONTROL_VPID:
return 1;
#endif
/* VMCS 16-bit guest-state fields */
/* binary 0000_10xx_xxxx_xxx0 */
case VMCS_16BIT_GUEST_ES_SELECTOR:
case VMCS_16BIT_GUEST_CS_SELECTOR:
case VMCS_16BIT_GUEST_SS_SELECTOR:
case VMCS_16BIT_GUEST_DS_SELECTOR:
case VMCS_16BIT_GUEST_FS_SELECTOR:
case VMCS_16BIT_GUEST_GS_SELECTOR:
case VMCS_16BIT_GUEST_LDTR_SELECTOR:
case VMCS_16BIT_GUEST_TR_SELECTOR:
return 1;
/* VMCS 16-bit host-state fields */
/* binary 0000_11xx_xxxx_xxx0 */
case VMCS_16BIT_HOST_ES_SELECTOR:
case VMCS_16BIT_HOST_CS_SELECTOR:
case VMCS_16BIT_HOST_SS_SELECTOR:
case VMCS_16BIT_HOST_DS_SELECTOR:
case VMCS_16BIT_HOST_FS_SELECTOR:
case VMCS_16BIT_HOST_GS_SELECTOR:
case VMCS_16BIT_HOST_TR_SELECTOR:
return 1;
/* VMCS 32_bit control fields */
/* binary 0100_00xx_xxxx_xxx0 */
case VMCS_32BIT_CONTROL_PIN_BASED_EXEC_CONTROLS:
case VMCS_32BIT_CONTROL_PROCESSOR_BASED_VMEXEC_CONTROLS:
case VMCS_32BIT_CONTROL_EXECUTION_BITMAP:
case VMCS_32BIT_CONTROL_PAGE_FAULT_ERR_CODE_MASK:
case VMCS_32BIT_CONTROL_PAGE_FAULT_ERR_CODE_MATCH:
case VMCS_32BIT_CONTROL_CR3_TARGET_COUNT:
case VMCS_32BIT_CONTROL_VMEXIT_CONTROLS:
case VMCS_32BIT_CONTROL_VMEXIT_MSR_STORE_COUNT:
case VMCS_32BIT_CONTROL_VMEXIT_MSR_LOAD_COUNT:
case VMCS_32BIT_CONTROL_VMENTRY_CONTROLS:
case VMCS_32BIT_CONTROL_VMENTRY_MSR_LOAD_COUNT:
case VMCS_32BIT_CONTROL_VMENTRY_INTERRUPTION_INFO:
case VMCS_32BIT_CONTROL_VMENTRY_EXCEPTION_ERR_CODE:
case VMCS_32BIT_CONTROL_VMENTRY_INSTRUCTION_LENGTH:
#if BX_SUPPORT_X86_64
case VMCS_32BIT_CONTROL_TPR_THRESHOLD:
#endif
#if BX_SUPPORT_VMX >= 2
case VMCS_32BIT_CONTROL_SECONDARY_VMEXEC_CONTROLS:
#endif
return 1;
/* VMCS 32-bit read only data fields */
/* binary 0100_01xx_xxxx_xxx0 */
case VMCS_32BIT_INSTRUCTION_ERROR:
case VMCS_32BIT_VMEXIT_REASON:
case VMCS_32BIT_VMEXIT_INTERRUPTION_INFO:
case VMCS_32BIT_VMEXIT_INTERRUPTION_ERR_CODE:
case VMCS_32BIT_IDT_VECTORING_INFO:
case VMCS_32BIT_IDT_VECTORING_ERR_CODE:
case VMCS_32BIT_VMEXIT_INSTRUCTION_LENGTH:
case VMCS_32BIT_VMEXIT_INSTRUCTION_INFO:
return 1;
/* VMCS 32-bit guest-state fields */
/* binary 0100_10xx_xxxx_xxx0 */
case VMCS_32BIT_GUEST_ES_LIMIT:
case VMCS_32BIT_GUEST_CS_LIMIT:
case VMCS_32BIT_GUEST_SS_LIMIT:
case VMCS_32BIT_GUEST_DS_LIMIT:
case VMCS_32BIT_GUEST_FS_LIMIT:
case VMCS_32BIT_GUEST_GS_LIMIT:
case VMCS_32BIT_GUEST_LDTR_LIMIT:
case VMCS_32BIT_GUEST_TR_LIMIT:
case VMCS_32BIT_GUEST_GDTR_LIMIT:
case VMCS_32BIT_GUEST_IDTR_LIMIT:
case VMCS_32BIT_GUEST_ES_ACCESS_RIGHTS:
case VMCS_32BIT_GUEST_CS_ACCESS_RIGHTS:
case VMCS_32BIT_GUEST_SS_ACCESS_RIGHTS:
case VMCS_32BIT_GUEST_DS_ACCESS_RIGHTS:
case VMCS_32BIT_GUEST_FS_ACCESS_RIGHTS:
case VMCS_32BIT_GUEST_GS_ACCESS_RIGHTS:
case VMCS_32BIT_GUEST_LDTR_ACCESS_RIGHTS:
case VMCS_32BIT_GUEST_TR_ACCESS_RIGHTS:
case VMCS_32BIT_GUEST_INTERRUPTIBILITY_STATE:
case VMCS_32BIT_GUEST_ACTIVITY_STATE:
case VMCS_32BIT_GUEST_SMBASE:
case VMCS_32BIT_GUEST_IA32_SYSENTER_CS_MSR:
return 1;
/* VMCS 32-bit host-state fields */
/* binary 0100_11xx_xxxx_xxx0 */
case VMCS_32BIT_HOST_IA32_SYSENTER_CS_MSR:
return 1;
/* VMCS 64-bit control fields */
/* binary 0010_00xx_xxxx_xxx0 */
case VMCS_64BIT_CONTROL_IO_BITMAP_A:
case VMCS_64BIT_CONTROL_IO_BITMAP_A_HI:
case VMCS_64BIT_CONTROL_IO_BITMAP_B:
case VMCS_64BIT_CONTROL_IO_BITMAP_B_HI:
case VMCS_64BIT_CONTROL_MSR_BITMAPS:
case VMCS_64BIT_CONTROL_MSR_BITMAPS_HI:
case VMCS_64BIT_CONTROL_VMEXIT_MSR_STORE_ADDR:
case VMCS_64BIT_CONTROL_VMEXIT_MSR_STORE_ADDR_HI:
case VMCS_64BIT_CONTROL_VMEXIT_MSR_LOAD_ADDR:
case VMCS_64BIT_CONTROL_VMEXIT_MSR_LOAD_ADDR_HI:
case VMCS_64BIT_CONTROL_VMENTRY_MSR_LOAD_ADDR:
case VMCS_64BIT_CONTROL_VMENTRY_MSR_LOAD_ADDR_HI:
case VMCS_64BIT_CONTROL_EXECUTIVE_VMCS_PTR:
case VMCS_64BIT_CONTROL_EXECUTIVE_VMCS_PTR_HI:
case VMCS_64BIT_CONTROL_TSC_OFFSET:
case VMCS_64BIT_CONTROL_TSC_OFFSET_HI:
#if BX_SUPPORT_X86_64
case VMCS_64BIT_CONTROL_VIRTUAL_APIC_PAGE_ADDR:
case VMCS_64BIT_CONTROL_VIRTUAL_APIC_PAGE_ADDR_HI:
#endif
#if BX_SUPPORT_VMX >= 2
case VMCS_64BIT_CONTROL_APIC_ACCESS_ADDR:
case VMCS_64BIT_CONTROL_APIC_ACCESS_ADDR_HI:
case VMCS_64BIT_CONTROL_EPTPTR:
case VMCS_64BIT_CONTROL_EPTPTR_HI:
#endif
return 1;
#if BX_SUPPORT_VMX >= 2
/* VMCS 64-bit read only data fields */
/* binary 0010_01xx_xxxx_xxx0 */
case VMCS_64BIT_GUEST_PHYSICAL_ADDR:
case VMCS_64BIT_GUEST_PHYSICAL_ADDR_HI:
return 1;
#endif
/* VMCS 64-bit guest state fields */
/* binary 0010_10xx_xxxx_xxx0 */
case VMCS_64BIT_GUEST_LINK_POINTER:
case VMCS_64BIT_GUEST_LINK_POINTER_HI:
case VMCS_64BIT_GUEST_IA32_DEBUGCTL:
case VMCS_64BIT_GUEST_IA32_DEBUGCTL_HI:
#if BX_SUPPORT_VMX >= 2
case VMCS_64BIT_GUEST_IA32_PAT:
case VMCS_64BIT_GUEST_IA32_PAT_HI:
case VMCS_64BIT_GUEST_IA32_EFER:
case VMCS_64BIT_GUEST_IA32_EFER_HI:
case VMCS_64BIT_GUEST_IA32_PDPTE0:
case VMCS_64BIT_GUEST_IA32_PDPTE0_HI:
case VMCS_64BIT_GUEST_IA32_PDPTE1:
case VMCS_64BIT_GUEST_IA32_PDPTE1_HI:
case VMCS_64BIT_GUEST_IA32_PDPTE2:
case VMCS_64BIT_GUEST_IA32_PDPTE2_HI:
case VMCS_64BIT_GUEST_IA32_PDPTE3:
case VMCS_64BIT_GUEST_IA32_PDPTE3_HI:
#endif
return 1;
#if BX_SUPPORT_VMX >= 2
/* VMCS 64-bit host state fields */
/* binary 0010_11xx_xxxx_xxx0 */
case VMCS_64BIT_HOST_IA32_PAT:
case VMCS_64BIT_HOST_IA32_PAT_HI:
case VMCS_64BIT_HOST_IA32_EFER:
case VMCS_64BIT_HOST_IA32_EFER_HI:
return 1;
#endif
/* VMCS natural width control fields */
/* binary 0110_00xx_xxxx_xxx0 */
case VMCS_CONTROL_CR0_GUEST_HOST_MASK:
case VMCS_CONTROL_CR4_GUEST_HOST_MASK:
case VMCS_CONTROL_CR0_READ_SHADOW:
case VMCS_CONTROL_CR4_READ_SHADOW:
case VMCS_CR3_TARGET0:
case VMCS_CR3_TARGET1:
case VMCS_CR3_TARGET2:
case VMCS_CR3_TARGET3:
return 1;
/* VMCS natural width read only data fields */
/* binary 0110_01xx_xxxx_xxx0 */
case VMCS_VMEXIT_QUALIFICATION:
case VMCS_IO_RCX:
case VMCS_IO_RSI:
case VMCS_IO_RDI:
case VMCS_IO_RIP:
case VMCS_GUEST_LINEAR_ADDR:
return 1;
/* VMCS natural width guest state fields */
/* binary 0110_10xx_xxxx_xxx0 */
case VMCS_GUEST_CR0:
case VMCS_GUEST_CR3:
case VMCS_GUEST_CR4:
case VMCS_GUEST_ES_BASE:
case VMCS_GUEST_CS_BASE:
case VMCS_GUEST_SS_BASE:
case VMCS_GUEST_DS_BASE:
case VMCS_GUEST_FS_BASE:
case VMCS_GUEST_GS_BASE:
case VMCS_GUEST_LDTR_BASE:
case VMCS_GUEST_TR_BASE:
case VMCS_GUEST_GDTR_BASE:
case VMCS_GUEST_IDTR_BASE:
case VMCS_GUEST_DR7:
case VMCS_GUEST_RSP:
case VMCS_GUEST_RIP:
case VMCS_GUEST_RFLAGS:
case VMCS_GUEST_PENDING_DBG_EXCEPTIONS:
case VMCS_GUEST_IA32_SYSENTER_ESP_MSR:
case VMCS_GUEST_IA32_SYSENTER_EIP_MSR:
return 1;
/* VMCS natural width host state fields */
/* binary 0110_11xx_xxxx_xxx0 */
case VMCS_HOST_CR0:
case VMCS_HOST_CR3:
case VMCS_HOST_CR4:
case VMCS_HOST_FS_BASE:
case VMCS_HOST_GS_BASE:
case VMCS_HOST_TR_BASE:
case VMCS_HOST_GDTR_BASE:
case VMCS_HOST_IDTR_BASE:
case VMCS_HOST_IA32_SYSENTER_ESP_MSR:
case VMCS_HOST_IA32_SYSENTER_EIP_MSR:
case VMCS_HOST_RSP:
case VMCS_HOST_RIP:
return 1;
default:
return 0;
}
return 0;
}
#endif

792
simulators/bochs/cpu/vmexit.cc Executable file
View File

@ -0,0 +1,792 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2009-2010 Stanislav Shwartsman
// 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
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA B 02110-1301 USA
//
/////////////////////////////////////////////////////////////////////////
#define NEED_CPU_REG_SHORTCUTS 1
#include "bochs.h"
#include "cpu.h"
#define LOG_THIS BX_CPU_THIS_PTR
#if BX_SUPPORT_X86_64==0
// Make life easier for merging cpu64 and cpu32 code.
#define RIP EIP
#define RDI EDI
#define RSI ESI
#endif
#if BX_SUPPORT_VMX
Bit32u gen_instruction_info(bxInstruction_c *i, Bit32u reason)
{
Bit32u instr_info = 0;
switch(reason) {
case VMX_VMEXIT_VMREAD:
case VMX_VMEXIT_VMWRITE:
#if BX_SUPPORT_VMX >= 2
case VMX_VMEXIT_GDTR_IDTR_ACCESS:
case VMX_VMEXIT_LDTR_TR_ACCESS:
case VMX_VMEXIT_INVEPT:
case VMX_VMEXIT_INVVPID:
#endif
instr_info |= i->nnn() << 28;
break;
default:
break;
}
// --------------------------------------
// instruction information field format
// --------------------------------------
//
// [.2:.0] | Memory operand scale field (encoded)
// [.6:.3] | Reg1, undefined when memory operand
// [.9:.7] | Memory operand address size
// [10:10] | Memory/Register format (0 - mem, 1 - reg)
// [14:11] | Reserved
// [17:15] | Memory operand segment register field
// [21:18] | Memory operand index field
// [22:22] | Memory operand index field invalid
// [26:23] | Memory operand base field
// [27:27] | Memory operand base field invalid
// [31:28] | Reg2, if exists
//
if (i->modC0()) {
// reg/reg format
instr_info |= (1 << 10) | (i->rm() << 3);
}
else {
// memory format
if (i->as64L())
instr_info |= 1 << 8;
else if (i->as32L())
instr_info |= 1 << 7;
instr_info |= i->seg() << 15;
if (i->sibIndex() != BX_NIL_REGISTER)
instr_info |= i->sibScale() | (i->sibIndex() << 18);
else
instr_info |= 1 << 22; // index invalid
if (i->sibBase() != BX_NIL_REGISTER)
instr_info |= i->sibBase() << 23;
else
instr_info |= 1 << 27; // base invalid
}
return instr_info;
}
void BX_CPP_AttrRegparmN(2) BX_CPU_C::VMexit_Instruction(bxInstruction_c *i, Bit32u reason)
{
Bit64u qualification = 0;
Bit32u instr_info = 0;
switch(reason) {
case VMX_VMEXIT_VMCALL:
case VMX_VMEXIT_VMLAUNCH:
case VMX_VMEXIT_VMRESUME:
case VMX_VMEXIT_VMXOFF:
// do not have VMEXIT instruction info
break;
case VMX_VMEXIT_VMREAD:
case VMX_VMEXIT_VMWRITE:
case VMX_VMEXIT_VMPTRLD:
case VMX_VMEXIT_VMPTRST:
case VMX_VMEXIT_VMCLEAR:
case VMX_VMEXIT_VMXON:
#if BX_SUPPORT_VMX >= 2
case VMX_VMEXIT_GDTR_IDTR_ACCESS:
case VMX_VMEXIT_LDTR_TR_ACCESS:
case VMX_VMEXIT_INVEPT:
case VMX_VMEXIT_INVVPID:
#endif
#if BX_SUPPORT_X86_64
if (long64_mode()) {
qualification = (Bit64u) i->displ32s();
if (i->sibBase() == BX_64BIT_REG_RIP)
qualification += RIP;
}
else
#endif
qualification = (Bit64u) ((Bit32u) i->displ32s());
instr_info = gen_instruction_info(i, reason);
VMwrite32(VMCS_32BIT_VMEXIT_INSTRUCTION_INFO, instr_info);
break;
default:
BX_PANIC(("VMexit_Instruction reason %d", reason));
}
VMexit(i, reason, qualification);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::VMexit_HLT(bxInstruction_c *i)
{
if (! BX_CPU_THIS_PTR in_vmx_guest) return;
if (VMEXIT(VMX_VM_EXEC_CTRL2_HLT_VMEXIT)) {
BX_ERROR(("VMEXIT: HLT"));
VMexit(i, VMX_VMEXIT_HLT, 0);
}
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::VMexit_PAUSE(bxInstruction_c *i)
{
if (! BX_CPU_THIS_PTR in_vmx_guest) return;
if (VMEXIT(VMX_VM_EXEC_CTRL2_PAUSE_VMEXIT)) {
BX_ERROR(("VMEXIT: PAUSE"));
VMexit(i, VMX_VMEXIT_PAUSE, 0);
}
}
void BX_CPP_AttrRegparmN(2) BX_CPU_C::VMexit_INVLPG(bxInstruction_c *i, bx_address laddr)
{
if (! BX_CPU_THIS_PTR in_vmx_guest) return;
if (VMEXIT(VMX_VM_EXEC_CTRL2_INVLPG_VMEXIT)) {
BX_ERROR(("VMEXIT: INVLPG 0x" FMT_ADDRX, laddr));
VMexit(i, VMX_VMEXIT_INVLPG, laddr);
}
}
Bit64s BX_CPU_C::VMX_TSC_Offset(void)
{
if (! BX_CPU_THIS_PTR in_vmx_guest) return 0;
if (VMEXIT(VMX_VM_EXEC_CTRL2_TSC_OFFSET))
return (Bit64s) BX_CPU_THIS_PTR vmcs.tsc_offset;
else
return 0;
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::VMexit_RDTSC(bxInstruction_c *i)
{
if (! BX_CPU_THIS_PTR in_vmx_guest) return;
if (VMEXIT(VMX_VM_EXEC_CTRL2_RDTSC_VMEXIT)) {
BX_ERROR(("VMEXIT: RDTSC"));
VMexit(i, (i->getIaOpcode() == BX_IA_RDTSC) ? VMX_VMEXIT_RDTSC : VMX_VMEXIT_RDTSCP, 0);
}
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::VMexit_RDPMC(bxInstruction_c *i)
{
if (! BX_CPU_THIS_PTR in_vmx_guest) return;
if (VMEXIT(VMX_VM_EXEC_CTRL2_RDPMC_VMEXIT)) {
BX_ERROR(("VMEXIT: RDPMC"));
VMexit(i, VMX_VMEXIT_RDPMC, 0);
}
}
#if BX_SUPPORT_MONITOR_MWAIT
void BX_CPP_AttrRegparmN(1) BX_CPU_C::VMexit_MONITOR(bxInstruction_c *i)
{
if (! BX_CPU_THIS_PTR in_vmx_guest) return;
if (VMEXIT(VMX_VM_EXEC_CTRL2_MONITOR_VMEXIT)) {
BX_ERROR(("VMEXIT: MONITOR"));
VMexit(i, VMX_VMEXIT_MONITOR, 0);
}
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::VMexit_MWAIT(bxInstruction_c *i)
{
if (! BX_CPU_THIS_PTR in_vmx_guest) return;
if (VMEXIT(VMX_VM_EXEC_CTRL2_MWAIT_VMEXIT)) {
BX_ERROR(("VMEXIT: MWAIT"));
VMexit(i, VMX_VMEXIT_MWAIT, BX_CPU_THIS_PTR monitor.armed);
}
}
#endif
void BX_CPU_C::VMexit_ExtInterrupt(void)
{
if (! BX_CPU_THIS_PTR in_vmx_guest) return;
if (PIN_VMEXIT(VMX_VM_EXEC_CTRL1_EXTERNAL_INTERRUPT_VMEXIT)) {
VMCS_CACHE *vm = &BX_CPU_THIS_PTR vmcs;
if (! (vm->vmexit_ctrls & VMX_VMEXIT_CTRL1_INTA_ON_VMEXIT)) {
// interrupt wasn't acknowledged and still pending, interruption info is invalid
VMwrite32(VMCS_32BIT_VMEXIT_INTERRUPTION_INFO, 0);
VMexit(0, VMX_VMEXIT_EXTERNAL_INTERRUPT, 0);
}
}
}
void BX_CPU_C::VMexit_Event(bxInstruction_c *i, unsigned type, unsigned vector, Bit16u errcode, bx_bool errcode_valid, Bit64u qualification)
{
if (! BX_CPU_THIS_PTR in_vmx_guest) return;
VMCS_CACHE *vm = &BX_CPU_THIS_PTR vmcs;
bx_bool vmexit = 0;
VMX_vmexit_reason reason = VMX_VMEXIT_EXCEPTION_NMI;
switch(type) {
case BX_EXTERNAL_INTERRUPT:
reason = VMX_VMEXIT_EXTERNAL_INTERRUPT;
if (PIN_VMEXIT(VMX_VM_EXEC_CTRL1_EXTERNAL_INTERRUPT_VMEXIT))
vmexit = 1;
break;
case BX_NMI:
if (PIN_VMEXIT(VMX_VM_EXEC_CTRL1_NMI_VMEXIT))
vmexit = 1;
break;
case BX_PRIVILEGED_SOFTWARE_INTERRUPT:
case BX_SOFTWARE_EXCEPTION:
case BX_HARDWARE_EXCEPTION:
BX_ASSERT((vector < BX_CPU_HANDLED_EXCEPTIONS));
if (vector == BX_PF_EXCEPTION) {
// page faults are specially treated
bx_bool err_match = ((errcode & vm->vm_pf_mask) == vm->vm_pf_match);
bx_bool bitmap = (vm->vm_exceptions_bitmap >> BX_PF_EXCEPTION) & 1;
vmexit = (err_match == bitmap);
}
else {
vmexit = (vm->vm_exceptions_bitmap >> vector) & 1;
}
break;
case BX_SOFTWARE_INTERRUPT:
break; // no VMEXIT on software interrupt
default:
BX_ERROR(("VMexit_Event: unknown event type %d", type));
}
// ----------------------------------------------------
// VMExit interruption info
// ----------------------------------------------------
// [.7:.0] | Interrupt/Exception vector
// [10:.8] | Interrupt/Exception type
// [11:11] | error code pushed to the stack
// [12:12] | NMI unblocking due to IRET
// [30:13] | reserved
// [31:31] | interruption info valid
//
if (i) {
VMwrite32(VMCS_32BIT_VMEXIT_INSTRUCTION_LENGTH, i->ilen());
}
if (! vmexit) {
// record IDT vectoring information
vm->idt_vector_error_code = errcode;
vm->idt_vector_info = vector | (type << 8);
if (errcode_valid)
vm->idt_vector_info |= (1 << 11); // error code delivered
return;
}
BX_ERROR(("VMEXIT: event vector 0x%02x type %d error code=0x%04x", vector, type, errcode));
// VMEXIT is not considered to occur during event delivery if it results
// in a double fault exception that causes VMEXIT directly
if (vector == BX_DF_EXCEPTION)
BX_CPU_THIS_PTR in_event = 0; // clear in_event indication on #DF
if (vector == BX_DB_EXCEPTION) {
// qualifcation for debug exceptions similar to debug_trap field
qualification = BX_CPU_THIS_PTR debug_trap & 0x0000600f;
}
// clear debug_trap field
BX_CPU_THIS_PTR debug_trap = 0;
BX_CPU_THIS_PTR inhibit_mask = 0;
Bit32u interruption_info = vector | (type << 8);
if (errcode_valid)
interruption_info |= (1 << 11); // error code delivered
interruption_info |= (1 << 31); // valid
VMwrite32(VMCS_32BIT_VMEXIT_INTERRUPTION_INFO, interruption_info);
VMwrite32(VMCS_32BIT_VMEXIT_INTERRUPTION_ERR_CODE, errcode);
VMexit(0, reason, qualification);
}
void BX_CPU_C::VMexit_TripleFault(void)
{
if (! BX_CPU_THIS_PTR in_vmx_guest) return;
BX_ERROR(("VMEXIT: triple fault"));
// VMEXIT is not considered to occur during event delivery if it results
// in a triple fault exception (that causes VMEXIT directly)
BX_CPU_THIS_PTR in_event = 0;
VMexit(0, VMX_VMEXIT_TRIPLE_FAULT, 0);
}
void BX_CPP_AttrRegparmN(3) BX_CPU_C::VMexit_TaskSwitch(bxInstruction_c *i, Bit16u tss_selector, unsigned source)
{
if (! BX_CPU_THIS_PTR in_vmx_guest) return;
BX_ERROR(("VMEXIT: task switch"));
VMexit(i, VMX_VMEXIT_TASK_SWITCH, tss_selector | (source << 30));
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::VMexit_SoftwareInterrupt(bxInstruction_c *i)
{
if (! BX_CPU_THIS_PTR in_vmx_guest) return;
}
void BX_CPP_AttrRegparmN(3) BX_CPU_C::VMexit_MSR(bxInstruction_c *i, unsigned op, Bit32u msr)
{
if (! BX_CPU_THIS_PTR in_vmx_guest) return;
bx_bool vmexit = 0;
if (! VMEXIT(VMX_VM_EXEC_CTRL2_MSR_BITMAPS)) vmexit = 1;
else {
VMCS_CACHE *vm = &BX_CPU_THIS_PTR vmcs;
Bit8u field;
if (msr & 0xC0000000) {
if (msr > 0xC0001FFF) vmexit = 1;
else {
// check MSR-HI bitmaps
bx_phy_address pAddr = vm->msr_bitmap_addr + (msr >> 3) + 1024 + ((op == VMX_VMEXIT_RDMSR) ? 0 : 2048);
access_read_physical(pAddr, 1, &field);
BX_DBG_PHY_MEMORY_ACCESS(BX_CPU_ID, pAddr, 1, BX_VMX_MSR_BITMAP_ACCESS | BX_READ, &field);
if (field & (1 << (msr & 7)))
vmexit = 1;
}
}
else {
if (msr > 0x00001FFF) vmexit = 1;
else {
// check MSR-LO bitmaps
bx_phy_address pAddr = vm->msr_bitmap_addr + (msr >> 3) + ((op == VMX_VMEXIT_RDMSR) ? 0 : 2048);
access_read_physical(pAddr, 1, &field);
BX_DBG_PHY_MEMORY_ACCESS(BX_CPU_ID, pAddr, 1, BX_VMX_MSR_BITMAP_ACCESS | BX_READ, &field);
if (field & (1 << (msr & 7)))
vmexit = 1;
}
}
}
if (vmexit) {
BX_ERROR(("VMEXIT: %sMSR 0x%08x", (op == VMX_VMEXIT_RDMSR) ? "RD" : "WR", msr));
VMexit(i, op, 0);
}
}
#define VMX_VMEXIT_IO_PORTIN (1 << 3)
#define VMX_VMEXIT_IO_INSTR_STRING (1 << 4)
#define VMX_VMEXIT_IO_INSTR_REP (1 << 5)
#define VMX_VMEXIT_IO_INSTR_IMM (1 << 6)
void BX_CPP_AttrRegparmN(3) BX_CPU_C::VMexit_IO(bxInstruction_c *i, unsigned port, unsigned len)
{
if (! BX_CPU_THIS_PTR in_vmx_guest) return;
BX_ASSERT((port <= 0xFFFF));
bool vmexit = 0;
if (VMEXIT(VMX_VM_EXEC_CTRL2_IO_BITMAPS)) {
// always VMEXIT on port "wrap around" case
if ((port + len) > 0x10000) vmexit = 1;
else {
bx_phy_address pAddr = BX_CPU_THIS_PTR vmcs.io_bitmap_addr[(port >> 15) & 1] + ((port & 0x7fff) >> 3);
Bit16u bitmap;
access_read_physical(pAddr, 2, (Bit8u*) &bitmap);
BX_DBG_PHY_MEMORY_ACCESS(BX_CPU_ID, pAddr, 2, BX_VMX_IO_BITMAP_ACCESS | BX_READ, (Bit8u*) &bitmap);
unsigned mask = ((1 << len) - 1) << (port & 7);
if (bitmap & mask) vmexit = 1;
}
}
else if (VMEXIT(VMX_VM_EXEC_CTRL2_IO_VMEXIT)) vmexit = 1;
if (vmexit) {
BX_ERROR(("VMEXIT: I/O port 0x%04x", port));
Bit32u qualification = 0;
switch(i->getIaOpcode()) {
case BX_IA_IN_ALIb:
case BX_IA_IN_AXIb:
case BX_IA_IN_EAXIb:
qualification = VMX_VMEXIT_IO_PORTIN | VMX_VMEXIT_IO_INSTR_IMM;
break;
case BX_IA_OUT_IbAL:
case BX_IA_OUT_IbAX:
case BX_IA_OUT_IbEAX:
qualification = VMX_VMEXIT_IO_INSTR_IMM;
break;
case BX_IA_IN_ALDX:
case BX_IA_IN_AXDX:
case BX_IA_IN_EAXDX:
qualification = VMX_VMEXIT_IO_PORTIN; // no immediate
break;
case BX_IA_OUT_DXAL:
case BX_IA_OUT_DXAX:
case BX_IA_OUT_DXEAX:
qualification = 0; // PORTOUT, no immediate
break;
case BX_IA_REP_INSB_YbDX:
case BX_IA_REP_INSW_YwDX:
case BX_IA_REP_INSD_YdDX:
qualification = VMX_VMEXIT_IO_PORTIN | VMX_VMEXIT_IO_INSTR_STRING;
if (i->repUsedL())
qualification |= VMX_VMEXIT_IO_INSTR_REP;
break;
case BX_IA_REP_OUTSB_DXXb:
case BX_IA_REP_OUTSW_DXXw:
case BX_IA_REP_OUTSD_DXXd:
qualification = VMX_VMEXIT_IO_INSTR_STRING; // PORTOUT
if (i->repUsedL())
qualification |= VMX_VMEXIT_IO_INSTR_REP;
break;
default:
BX_PANIC(("VMexit_IO: I/O instruction %s unknown", get_bx_opcode_name(i->getIaOpcode())));
}
if (qualification & VMX_VMEXIT_IO_INSTR_STRING) {
bx_address asize_mask = BX_CONST64(0xffffffffffffffff), laddr;
if (! i->as64L()) {
if (i->as32L()) asize_mask = 0xffffffff;
else asize_mask = 0xffff;
}
if (qualification & VMX_VMEXIT_IO_PORTIN)
laddr = BX_CPU_THIS_PTR get_laddr(BX_SEG_REG_ES, RDI & asize_mask);
else // PORTOUT
laddr = BX_CPU_THIS_PTR get_laddr(i->seg(), RSI & asize_mask);
VMwrite64(VMCS_GUEST_LINEAR_ADDR, laddr);
Bit32u instruction_info = i->seg() << 15;
if (i->as64L())
instruction_info |= (1 << 8);
else if (i->as32L())
instruction_info |= (1 << 7);
VMwrite32(VMCS_32BIT_VMEXIT_INSTRUCTION_INFO, instruction_info);
}
VMexit(i, VMX_VMEXIT_IO_INSTRUCTION, qualification | (len-1) | (port << 16));
}
}
//
// ----------------------------------------------------------------
// Exit qualification for CR access
// ----------------------------------------------------------------
// [.3:.0] | Number of CR register (CR0, CR3, CR4, CR8)
// [.5:.4] | CR access type (0 - MOV to CR, 1 - MOV from CR, 2 - CLTS, 3 - LMSW)
// [.6:.6] | LMSW operand reg/mem (cleared for CR access and CLTS)
// [.7:.7] | reserved
// [11:.8] | Source Operand Register for CR access (cleared for CLTS and LMSW)
// [15:12] | reserved
// [31:16] | LMSW source data (cleared for CR access and CLTS)
// [63:32] | reserved
//
bx_bool BX_CPP_AttrRegparmN(1) BX_CPU_C::VMexit_CLTS(bxInstruction_c *i)
{
if (! BX_CPU_THIS_PTR in_vmx_guest) return 0;
VMCS_CACHE *vm = &BX_CPU_THIS_PTR vmcs;
if (vm->vm_cr0_mask & vm->vm_cr0_read_shadow & 0x8)
{
BX_ERROR(("VMEXIT: CLTS"));
// all rest of the fields cleared to zero
Bit64u qualification = VMX_VMEXIT_CR_ACCESS_CLTS << 4;
VMexit(i, VMX_VMEXIT_CR_ACCESS, qualification);
}
if ((vm->vm_cr0_mask & 0x8) != 0 && (vm->vm_cr0_read_shadow & 0x8) == 0)
return 1; /* do not clear CR0.TS */
else
return 0;
}
Bit32u BX_CPP_AttrRegparmN(2) BX_CPU_C::VMexit_LMSW(bxInstruction_c *i, Bit32u msw)
{
if (! BX_CPU_THIS_PTR in_vmx_guest) return msw;
VMCS_CACHE *vm = &BX_CPU_THIS_PTR vmcs;
Bit32u mask = vm->vm_cr0_mask & 0xF; /* LMSW affects only low 4 bits */
bx_bool vmexit = 0;
if ((mask & msw & 0x1) != 0 && (vm->vm_cr0_read_shadow & 0x1) == 0)
vmexit = 1;
if ((mask & vm->vm_cr0_read_shadow & 0xE) != (mask & msw & 0xE))
vmexit = 1;
if (vmexit) {
BX_ERROR(("VMEXIT: CR0 write by LMSW of value 0x%04x", msw));
Bit64u qualification = VMX_VMEXIT_CR_ACCESS_LMSW << 4;
qualification |= msw << 16;
if (! i->modC0()) {
qualification |= (1 << 6); // memory operand
VMwrite64(VMCS_GUEST_LINEAR_ADDR, BX_CPU_THIS_PTR get_laddr(i->seg(), RMAddr(i)));
}
VMexit(i, VMX_VMEXIT_CR_ACCESS, qualification);
}
// keep untouched all the bits set in CR0 mask
return (BX_CPU_THIS_PTR cr0.get32() & mask) | (msw & ~mask);
}
bx_address BX_CPP_AttrRegparmN(2) BX_CPU_C::VMexit_CR0_Write(bxInstruction_c *i, bx_address val)
{
if (! BX_CPU_THIS_PTR in_vmx_guest) return val;
VMCS_CACHE *vm = &BX_CPU_THIS_PTR vmcs;
if ((vm->vm_cr0_mask & vm->vm_cr0_read_shadow) != (vm->vm_cr0_mask & val))
{
BX_ERROR(("VMEXIT: CR0 write"));
Bit64u qualification = i->rm() << 8;
VMexit(i, VMX_VMEXIT_CR_ACCESS, qualification);
}
// keep untouched all the bits set in CR0 mask
return (BX_CPU_THIS_PTR cr0.get32() & vm->vm_cr0_mask) | (val & ~vm->vm_cr0_mask);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::VMexit_CR3_Read(bxInstruction_c *i)
{
if (! BX_CPU_THIS_PTR in_vmx_guest) return;
if (VMEXIT(VMX_VM_EXEC_CTRL2_CR3_READ_VMEXIT)) {
BX_ERROR(("VMEXIT: CR3 read"));
Bit64u qualification = 3 | (VMX_VMEXIT_CR_ACCESS_CR_READ << 4);
qualification |= (i->rm() << 8);
VMexit(i, VMX_VMEXIT_CR_ACCESS, qualification);
}
}
void BX_CPP_AttrRegparmN(2) BX_CPU_C::VMexit_CR3_Write(bxInstruction_c *i, bx_address val)
{
if (! BX_CPU_THIS_PTR in_vmx_guest) return;
VMCS_CACHE *vm = &BX_CPU_THIS_PTR vmcs;
if (VMEXIT(VMX_VM_EXEC_CTRL2_CR3_WRITE_VMEXIT)) {
for (unsigned n=0; n < vm->vm_cr3_target_cnt; n++) {
if (vm->vm_cr3_target_value[n] == val) return;
}
BX_ERROR(("VMEXIT: CR3 write"));
Bit64u qualification = 3 | (i->rm() << 8);
VMexit(i, VMX_VMEXIT_CR_ACCESS, qualification);
}
}
bx_address BX_CPP_AttrRegparmN(2) BX_CPU_C::VMexit_CR4_Write(bxInstruction_c *i, bx_address val)
{
if (! BX_CPU_THIS_PTR in_vmx_guest) return val;
VMCS_CACHE *vm = &BX_CPU_THIS_PTR vmcs;
if ((vm->vm_cr4_mask & vm->vm_cr4_read_shadow) != (vm->vm_cr4_mask & val))
{
BX_ERROR(("VMEXIT: CR4 write"));
Bit64u qualification = 4 | (i->rm() << 8);
VMexit(i, VMX_VMEXIT_CR_ACCESS, qualification);
}
// keep untouched all the bits set in CR4 mask
return (BX_CPU_THIS_PTR cr4.get32() & vm->vm_cr4_mask) | (val & ~vm->vm_cr4_mask);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::VMexit_CR8_Read(bxInstruction_c *i)
{
if (! BX_CPU_THIS_PTR in_vmx_guest) return;
if (VMEXIT(VMX_VM_EXEC_CTRL2_CR8_READ_VMEXIT)) {
BX_ERROR(("VMEXIT: CR8 read"));
Bit64u qualification = 8 | (VMX_VMEXIT_CR_ACCESS_CR_READ << 4);
qualification |= (i->rm() << 8);
VMexit(i, VMX_VMEXIT_CR_ACCESS, qualification);
}
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::VMexit_CR8_Write(bxInstruction_c *i)
{
if (! BX_CPU_THIS_PTR in_vmx_guest) return;
if (VMEXIT(VMX_VM_EXEC_CTRL2_CR8_WRITE_VMEXIT)) {
BX_ERROR(("VMEXIT: CR8 write"));
Bit64u qualification = 8 | (i->rm() << 8);
VMexit(i, VMX_VMEXIT_CR_ACCESS, qualification);
}
}
//
// ----------------------------------------------------------------
// Exit qualification for DR access
// ----------------------------------------------------------------
// [.3:.0] | Number of DR register
// [.4:.4] | DR access type (0 - MOV to DR, 1 - MOV from DR)
// [.7:.5] | reserved
// [11:.8] | Source Operand Register
// [63:12] | reserved
//
void BX_CPP_AttrRegparmN(2) BX_CPU_C::VMexit_DR_Access(bxInstruction_c *i, unsigned read)
{
if (! BX_CPU_THIS_PTR in_vmx_guest) return;
if (VMEXIT(VMX_VM_EXEC_CTRL2_DRx_ACCESS_VMEXIT))
{
BX_ERROR(("VMEXIT: DR%d %s access", i->nnn(), read ? "READ" : "WRITE"));
Bit64u qualification = i->nnn() | (i->rm() << 8);
if (read)
qualification |= (1 << 4);
VMexit(i, VMX_VMEXIT_DR_ACCESS, qualification);
}
}
Bit32u BX_CPU_C::VMX_Read_VTPR(void)
{
bx_phy_address pAddr = BX_CPU_THIS_PTR vmcs.virtual_apic_page_addr + 0x80;
Bit32u vtpr;
access_read_physical(pAddr, 4, (Bit8u*)(&vtpr));
BX_DBG_PHY_MEMORY_ACCESS(BX_CPU_ID, pAddr, 4, BX_VMX_VTPR_ACCESS | BX_READ, (Bit8u*)(&vtpr));
return vtpr;
}
void BX_CPU_C::VMX_Write_VTPR(Bit8u vtpr)
{
VMCS_CACHE *vm = &BX_CPU_THIS_PTR vmcs;
bx_phy_address pAddr = vm->virtual_apic_page_addr + 0x80;
Bit32u field32 = vtpr;
access_write_physical(pAddr, 4, (Bit8u*)(&field32));
BX_DBG_PHY_MEMORY_ACCESS(BX_CPU_ID, pAddr, 4, BX_VMX_VTPR_ACCESS | BX_WRITE, (Bit8u*)(&field32));
Bit8u tpr_shadow = vtpr >> 4;
if (tpr_shadow < vm->vm_tpr_threshold) {
// commit current instruction to produce trap-like VMexit
BX_CPU_THIS_PTR prev_rip = RIP; // commit new RIP
VMexit(0, VMX_VMEXIT_TPR_THRESHOLD, 0);
}
}
#if BX_SUPPORT_VMX >= 2
bx_bool BX_CPP_AttrRegparmN(1) BX_CPU_C::is_virtual_apic_page(bx_phy_address paddr)
{
VMCS_CACHE *vm = &BX_CPU_THIS_PTR vmcs;
if (BX_CPU_THIS_PTR in_vmx_guest) {
if (SECONDARY_VMEXEC_CONTROL(VMX_VM_EXEC_CTRL3_VIRTUALIZE_APIC_ACCESSES))
if (PPFOf(paddr) == PPFOf(vm->apic_access_page)) return 1;
}
return 0;
}
void BX_CPU_C::VMX_Virtual_Apic_Read(bx_phy_address paddr, unsigned len, void *data)
{
BX_ASSERT(SECONDARY_VMEXEC_CONTROL(VMX_VM_EXEC_CTRL3_VIRTUALIZE_APIC_ACCESSES));
Bit32u offset = PAGE_OFFSET(paddr);
// access is not instruction fetch because cpu::prefetch will crash them
if (VMEXIT(VMX_VM_EXEC_CTRL2_TPR_SHADOW) && offset == 0x80 && len <= 4) {
// VTPR access
Bit32u vtpr = VMX_Read_VTPR();
if (len == 1)
*((Bit8u *) data) = vtpr & 0xff;
else if (len == 2)
*((Bit16u *) data) = vtpr & 0xffff;
else if (len == 4)
*((Bit32u *) data) = vtpr;
else
BX_PANIC(("PANIC: Unsupported Virtual APIC access len = 3 !"));
return;
}
Bit32u qualification = offset |
(BX_CPU_THIS_PTR in_event) ? VMX_APIC_ACCESS_DURING_EVENT_DELIVERY : VMX_APIC_READ_INSTRUCTION_EXECUTION;
VMexit(0, VMX_VMEXIT_APIC_ACCESS, qualification);
}
void BX_CPU_C::VMX_Virtual_Apic_Write(bx_phy_address paddr, unsigned len, void *data)
{
BX_ASSERT(SECONDARY_VMEXEC_CONTROL(VMX_VM_EXEC_CTRL3_VIRTUALIZE_APIC_ACCESSES));
Bit32u offset = PAGE_OFFSET(paddr);
if (VMEXIT(VMX_VM_EXEC_CTRL2_TPR_SHADOW) && offset == 0x80 && len <= 4) {
// VTPR access
VMX_Write_VTPR(*((Bit8u *) data));
return;
}
Bit32u qualification = offset |
(BX_CPU_THIS_PTR in_event) ? VMX_APIC_ACCESS_DURING_EVENT_DELIVERY : VMX_APIC_WRITE_INSTRUCTION_EXECUTION;
VMexit(0, VMX_VMEXIT_APIC_ACCESS, qualification);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::VMexit_WBINVD(bxInstruction_c *i)
{
if (! BX_CPU_THIS_PTR in_vmx_guest) return;
if (SECONDARY_VMEXEC_CONTROL(VMX_VM_EXEC_CTRL3_WBINVD_VMEXIT)) {
BX_ERROR(("VMEXIT: WBINVD in VMX non-root operation"));
VMexit(i, VMX_VMEXIT_WBINVD, 0);
}
}
Bit16u BX_CPU_C::VMX_Get_Current_VPID(void)
{
if (! BX_CPU_THIS_PTR in_vmx_guest || !SECONDARY_VMEXEC_CONTROL(VMX_VM_EXEC_CTRL3_VPID_ENABLE))
return 0;
return BX_CPU_THIS_PTR vmcs.vpid;
}
#endif
#endif // BX_SUPPORT_VMX

3050
simulators/bochs/cpu/vmx.cc Executable file

File diff suppressed because it is too large Load Diff

1038
simulators/bochs/cpu/vmx.h Executable file

File diff suppressed because it is too large Load Diff

267
simulators/bochs/cpu/xmm.h Normal file
View File

@ -0,0 +1,267 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2003-2010 Stanislav Shwartsman
// 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
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA B 02110-1301 USA
//
/////////////////////////////////////////////////////////////////////////
#ifndef BX_SSE_EXTENSIONS_H
#define BX_SSE_EXTENSIONS_H
/* XMM REGISTER */
typedef union bx_xmm_reg_t {
Bit8s xmm_sbyte[16];
Bit16s xmm_s16[8];
Bit32s xmm_s32[4];
Bit64s xmm_s64[2];
Bit8u xmm_ubyte[16];
Bit16u xmm_u16[8];
Bit32u xmm_u32[4];
Bit64u xmm_u64[2];
} BxPackedXmmRegister;
#ifdef BX_BIG_ENDIAN
#define xmm64s(i) xmm_s64[1 - (i)]
#define xmm32s(i) xmm_s32[3 - (i)]
#define xmm16s(i) xmm_s16[7 - (i)]
#define xmmsbyte(i) xmm_sbyte[15 - (i)]
#define xmmubyte(i) xmm_ubyte[15 - (i)]
#define xmm16u(i) xmm_u16[7 - (i)]
#define xmm32u(i) xmm_u32[3 - (i)]
#define xmm64u(i) xmm_u64[1 - (i)]
#else
#define xmm64s(i) xmm_s64[(i)]
#define xmm32s(i) xmm_s32[(i)]
#define xmm16s(i) xmm_s16[(i)]
#define xmmsbyte(i) xmm_sbyte[(i)]
#define xmmubyte(i) xmm_ubyte[(i)]
#define xmm16u(i) xmm_u16[(i)]
#define xmm32u(i) xmm_u32[(i)]
#define xmm64u(i) xmm_u64[(i)]
#endif
#if BX_SUPPORT_X86_64
# define BX_XMM_REGISTERS 16
#else
# define BX_XMM_REGISTERS 8
#endif
/* read XMM register */
#define BX_READ_XMM_REG(index) (BX_CPU_THIS_PTR xmm[index])
/* read only high 64 bit of the register */
#define BX_READ_XMM_REG_HI_QWORD(index) \
((BX_CPU_THIS_PTR xmm[index]).xmm64u(1))
/* read only low 64 bit of the register */
#define BX_READ_XMM_REG_LO_QWORD(index) \
((BX_CPU_THIS_PTR xmm[index]).xmm64u(0))
/* read only low 32 bit of the register */
#define BX_READ_XMM_REG_LO_DWORD(index) \
((BX_CPU_THIS_PTR xmm[index]).xmm32u(0))
/* read only low 16 bit of the register */
#define BX_READ_XMM_REG_LO_WORD(index) \
((BX_CPU_THIS_PTR xmm[index]).xmm16u(0))
/* short names for above macroses */
#define BX_XMM_REG_HI_QWORD BX_READ_XMM_REG_HI_QWORD
#define BX_XMM_REG_LO_QWORD BX_READ_XMM_REG_LO_QWORD
#define BX_XMM_REG_LO_DWORD BX_READ_XMM_REG_LO_DWORD
#define BX_XMM_REG BX_READ_XMM_REG
/* store XMM register */
#define BX_WRITE_XMM_REG(index, reg) \
{ BX_CPU_THIS_PTR xmm[index] = (reg); }
/* store only high 64 bit of the register, rest of the register unchanged */
#define BX_WRITE_XMM_REG_HI_QWORD(index, reg64) \
{ (BX_CPU_THIS_PTR xmm[index]).xmm64u(1) = (reg64); }
/* store only low 64 bit of the register, rest of the register unchanged */
#define BX_WRITE_XMM_REG_LO_QWORD(index, reg64) \
{ (BX_CPU_THIS_PTR xmm[index]).xmm64u(0) = (reg64); }
/* store only low 32 bit of the register, rest of the register unchanged */
#define BX_WRITE_XMM_REG_LO_DWORD(index, reg32) \
{ (BX_CPU_THIS_PTR xmm[index]).xmm32u(0) = (reg32); }
/* store only low 16 bit of the register, rest of the register unchanged */
#define BX_WRITE_XMM_REG_LO_WORD(index, reg16) \
{ (BX_CPU_THIS_PTR xmm[index]).xmm16u(0) = (reg16); }
/* MXCSR REGISTER */
/* 31|30|29|28|27|26|25|24|23|22|21|20|19|18|17|16
* ==|==|=====|==|==|==|==|==|==|==|==|==|==|==|== (reserved)
* 0| 0| 0| 0| 0| 0| 0| 0| 0| 0| 0| 0| 0| 0|MM| 0
*
* 15|14|13|12|11|10| 9| 8| 7| 6| 5| 4| 3| 2| 1| 0
* ==|==|=====|==|==|==|==|==|==|==|==|==|==|==|==
* FZ| R C |PM|UM|OM|ZM|DM|IM|DZ|PE|UE|OE|ZE|DE|IE
*/
/* MXCSR REGISTER FIELDS DESCRIPTION */
/*
* IE 0 Invalid-Operation Exception 0
* DE 1 Denormalized-Operand Exception 0
* ZE 2 Zero-Divide Exception 0
* OE 3 Overflow Exception 0
* UE 4 Underflow Exception 0
* PE 5 Precision Exception 0
* DZ 6 Denormals are Zeros 0
* IM 7 Invalid-Operation Exception Mask 1
* DM 8 Denormalized-Operand Exception Mask 1
* ZM 9 Zero-Divide Exception Mask 1
* OM 10 Overflow Exception Mask 1
* UM 11 Underflow Exception Mask 1
* PM 12 Precision Exception Mask 1
* RC 13-14 Floating-Point Rounding Control 00
* FZ 15 Flush-to-Zero for Masked Underflow 0
* RZ 16 Reserved 0
* MM 17 Misaligned Exception Mask 0
*/
#define MXCSR_EXCEPTIONS 0x0000003F
#define MXCSR_DAZ 0x00000040
#define MXCSR_MASKED_EXCEPTIONS 0x00001F80
#define MXCSR_ROUNDING_CONTROL 0x00006000
#define MXCSR_FLUSH_MASKED_UNDERFLOW 0x00008000
#define MXCSR_MISALIGNED_EXCEPTION_MASK 0x00020000
#define MXCSR_IE 0x00000001
#define MXCSR_DE 0x00000002
#define MXCSR_ZE 0x00000004
#define MXCSR_OE 0x00000008
#define MXCSR_UE 0x00000010
#define MXCSR_PE 0x00000020
#define MXCSR_IM 0x00000080
#define MXCSR_DM 0x00000100
#define MXCSR_ZM 0x00000200
#define MXCSR_OM 0x00000400
#define MXCSR_UM 0x00000800
#define MXCSR_PM 0x00001000
#define MXCSR_RESET 0x00001F80 /* reset value of the MXCSR register */
struct BOCHSAPI bx_mxcsr_t
{
Bit32u mxcsr;
bx_mxcsr_t (Bit32u val = MXCSR_RESET)
: mxcsr(val) {}
#define IMPLEMENT_MXCSR_ACCESSOR(name, bitmask, bitnum) \
int get_##name () const { \
return (mxcsr & (bitmask)) >> (bitnum); \
}
IMPLEMENT_MXCSR_ACCESSOR(exceptions_masks, MXCSR_MASKED_EXCEPTIONS, 7);
IMPLEMENT_MXCSR_ACCESSOR(DAZ, MXCSR_DAZ, 6);
IMPLEMENT_MXCSR_ACCESSOR(rounding_mode, MXCSR_ROUNDING_CONTROL, 13);
IMPLEMENT_MXCSR_ACCESSOR(flush_masked_underflow, MXCSR_FLUSH_MASKED_UNDERFLOW, 15);
IMPLEMENT_MXCSR_ACCESSOR(MM, MXCSR_MISALIGNED_EXCEPTION_MASK, 17);
IMPLEMENT_MXCSR_ACCESSOR(IE, MXCSR_IE, 0);
IMPLEMENT_MXCSR_ACCESSOR(DE, MXCSR_DE, 1);
IMPLEMENT_MXCSR_ACCESSOR(ZE, MXCSR_ZE, 2);
IMPLEMENT_MXCSR_ACCESSOR(OE, MXCSR_OE, 3);
IMPLEMENT_MXCSR_ACCESSOR(UE, MXCSR_UE, 4);
IMPLEMENT_MXCSR_ACCESSOR(PE, MXCSR_PE, 5);
IMPLEMENT_MXCSR_ACCESSOR(IM, MXCSR_IM, 7);
IMPLEMENT_MXCSR_ACCESSOR(DM, MXCSR_DM, 8);
IMPLEMENT_MXCSR_ACCESSOR(ZM, MXCSR_ZM, 9);
IMPLEMENT_MXCSR_ACCESSOR(OM, MXCSR_OM, 10);
IMPLEMENT_MXCSR_ACCESSOR(UM, MXCSR_UM, 11);
IMPLEMENT_MXCSR_ACCESSOR(PM, MXCSR_PM, 12);
void set_exceptions(int status) {
mxcsr |= (status & MXCSR_EXCEPTIONS);
}
};
#if defined(NEED_CPU_REG_SHORTCUTS)
#define MXCSR (BX_CPU_THIS_PTR mxcsr)
#define BX_MXCSR_REGISTER (BX_CPU_THIS_PTR mxcsr.mxcsr)
#define MXCSR_MASK (BX_CPU_THIS_PTR mxcsr_mask)
#endif
/* INTEGER SATURATION */
/*
* SaturateWordSToByteS converts a signed 16-bit value to a signed
* 8-bit value. If the signed 16-bit value is less than -128, it is
* represented by the saturated value -128 (0x80). If it is greater
* than 127, it is represented by the saturated value 127 (0x7F).
*/
BX_CPP_INLINE Bit8s BX_CPP_AttrRegparmN(1) SaturateWordSToByteS(Bit16s value)
{
if(value < -128) return -128;
if(value > 127) return 127;
return (Bit8s) value;
}
/*
* SaturateDwordSToWordS converts a signed 32-bit value to a signed
* 16-bit value. If the signed 32-bit value is less than -32768, it is
* represented by the saturated value -32768 (0x8000). If it is greater
* than 32767, it is represented by the saturated value 32767 (0x7FFF).
*/
BX_CPP_INLINE Bit16s BX_CPP_AttrRegparmN(1) SaturateDwordSToWordS(Bit32s value)
{
if(value < -32768) return -32768;
if(value > 32767) return 32767;
return (Bit16s) value;
}
/*
* SaturateWordSToByteU converts a signed 16-bit value to an unsigned
* 8-bit value. If the signed 16-bit value is less than zero it is
* represented by the saturated value zero (0x00).If it is greater than
* 255 it is represented by the saturated value 255 (0xFF).
*/
BX_CPP_INLINE Bit8u BX_CPP_AttrRegparmN(1) SaturateWordSToByteU(Bit16s value)
{
if(value < 0) return 0;
if(value > 255) return 255;
return (Bit8u) value;
}
/*
* SaturateDwordSToWordU converts a signed 32-bit value to an unsigned
* 16-bit value. If the signed 32-bit value is less than zero, it is
* represented by the saturated value zero (0x0000). If it is greater
* than 65535, it is represented by the saturated value 65535 (0xFFFF).
*/
BX_CPP_INLINE Bit16u BX_CPP_AttrRegparmN(1) SaturateDwordSToWordU(Bit32s value)
{
if(value < 0) return 0;
if(value > 65535) return 65535;
return (Bit16u) value;
}
#endif

359
simulators/bochs/cpu/xsave.cc Executable file
View File

@ -0,0 +1,359 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2008-2009 Stanislav Shwartsman
// 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
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA B 02110-1301 USA
//
/////////////////////////////////////////////////////////////////////////
#define NEED_CPU_REG_SHORTCUTS 1
#include "bochs.h"
#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
/* 0F AE /4 */
void BX_CPP_AttrRegparmN(1) BX_CPU_C::XSAVE(bxInstruction_c *i)
{
#if BX_CPU_LEVEL >= 6
unsigned index;
BxPackedXmmRegister xmm;
BX_CPU_THIS_PTR prepareXSAVE();
BX_DEBUG(("XSAVE: save processor state XCR0=0x%08x", BX_CPU_THIS_PTR xcr0.get32()));
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
bx_address laddr = get_laddr(i->seg(), eaddr);
if (laddr & 0x3f) {
BX_ERROR(("XSAVE: access not aligned to 64-byte"));
exception(BX_GP_EXCEPTION, 0);
}
bx_address asize_mask = i->asize_mask();
//
// We will go feature-by-feature and not run over all XCR0 bits
//
Bit64u header1 = read_virtual_qword(i->seg(), (eaddr + 512) & asize_mask);
/////////////////////////////////////////////////////////////////////////////
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();
xmm.xmm16u(2) = pack_FPU_TW(BX_CPU_THIS_PTR the_i387.get_tag_word());
/* 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);
xmm.xmm32u(3) = (BX_CPU_THIS_PTR the_i387.fcs);
}
write_virtual_dqword(i->seg(), eaddr, (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(), (eaddr + 16) & asize_mask, BX_CPU_THIS_PTR the_i387.fdp);
}
else
#endif
{
write_virtual_dword(i->seg(), (eaddr + 16) & asize_mask, (Bit32u) BX_CPU_THIS_PTR the_i387.fdp);
write_virtual_dword(i->seg(), (eaddr + 20) & asize_mask, (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_READ_FPU_REG(index);
xmm.xmm64u(0) = fp.fraction;
xmm.xmm64u(1) = 0;
xmm.xmm16u(4) = fp.exp;
write_virtual_dqword(i->seg(), (eaddr+index*16+32) & asize_mask, (Bit8u *) &xmm);
}
header1 |= BX_XCR0_FPU_MASK;
}
/////////////////////////////////////////////////////////////////////////////
if (BX_CPU_THIS_PTR xcr0.get_SSE() && (EAX & BX_XCR0_SSE_MASK) != 0)
{
write_virtual_dword(i->seg(), (eaddr + 24) & asize_mask, BX_MXCSR_REGISTER);
write_virtual_dword(i->seg(), (eaddr + 28) & asize_mask, 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 || long64_mode()) {
write_virtual_dqword(i->seg(),
(eaddr+index*16+160) & asize_mask, (Bit8u *)(&BX_READ_XMM_REG(index)));
}
}
header1 |= BX_XCR0_SSE_MASK;
}
// always update header to 'dirty' state
write_virtual_qword(i->seg(), (eaddr + 512) & asize_mask, header1);
#endif
}
/* 0F AE /5 */
void BX_CPP_AttrRegparmN(1) BX_CPU_C::XRSTOR(bxInstruction_c *i)
{
#if BX_CPU_LEVEL >= 6
unsigned index;
BxPackedXmmRegister xmm;
BX_CPU_THIS_PTR prepareXSAVE();
BX_DEBUG(("XRSTOR: restore processor state XCR0=0x%08x", BX_CPU_THIS_PTR xcr0.get32()));
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
bx_address laddr = get_laddr(i->seg(), eaddr);
if (laddr & 0x3f) {
BX_ERROR(("XRSTOR: access not aligned to 64-byte"));
exception(BX_GP_EXCEPTION, 0);
}
bx_address asize_mask = i->asize_mask();
Bit64u header1 = read_virtual_qword(i->seg(), (eaddr + 512) & asize_mask);
Bit64u header2 = read_virtual_qword(i->seg(), (eaddr + 520) & asize_mask);
Bit64u header3 = read_virtual_qword(i->seg(), (eaddr + 528) & asize_mask);
if ((~BX_CPU_THIS_PTR xcr0.get32() & header1) != 0) {
BX_ERROR(("XRSTOR: Broken header state"));
exception(BX_GP_EXCEPTION, 0);
}
if (header2 != 0 || header3 != 0) {
BX_ERROR(("XRSTOR: Reserved header state is not '0"));
exception(BX_GP_EXCEPTION, 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(i->seg(), eaddr, (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(6);
}
Bit32u tag_byte = xmm.xmmubyte(4);
/* Restore x87 FPU DP */
read_virtual_dqword(i->seg(), (eaddr + 16) & asize_mask, (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++)
{
floatx80 reg;
reg.fraction = read_virtual_qword(i->seg(), (eaddr+index*16+32) & asize_mask);
reg.exp = read_virtual_word (i->seg(), (eaddr+index*16+40) & asize_mask);
// update tag only if it is not empty
BX_WRITE_FPU_REGISTER_AND_TAG(reg,
IS_TAG_EMPTY(index) ? FPU_Tag_Empty : FPU_tagof(reg), index);
}
/* Restore floating point tag word - see desription for FXRSTOR instruction */
BX_CPU_THIS_PTR the_i387.twd = unpack_FPU_TW(tag_byte);
/* check for unmasked exceptions */
if (FPU_PARTIAL_STATUS & ~FPU_CONTROL_WORD & FPU_CW_Exceptions_Mask) {
/* set the B and ES bits in the status-word */
FPU_PARTIAL_STATUS |= FPU_SW_Summary | FPU_SW_Backward;
}
else {
/* clear the B and ES bits in the status-word */
FPU_PARTIAL_STATUS &= ~(FPU_SW_Summary | FPU_SW_Backward);
}
}
else {
// initialize FPU with reset values
BX_CPU_THIS_PTR the_i387.init();
for (index=0;index<8;index++) {
floatx80 reg = { 0, 0 };
BX_FPU_REG(index) = reg;
}
}
}
/////////////////////////////////////////////////////////////////////////////
if (BX_CPU_THIS_PTR xcr0.get_SSE() && (EAX & BX_XCR0_SSE_MASK) != 0)
{
Bit32u new_mxcsr = read_virtual_dword(i->seg(), (eaddr + 24) & asize_mask);
if(new_mxcsr & ~MXCSR_MASK)
exception(BX_GP_EXCEPTION, 0);
BX_MXCSR_REGISTER = new_mxcsr;
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 || long64_mode()) {
read_virtual_dqword(i->seg(),
(eaddr+index*16+160) & asize_mask, (Bit8u *)(&BX_READ_XMM_REG(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 || long64_mode()) {
BX_CPU_THIS_PTR xmm[index].xmm64u(0) = 0;
BX_CPU_THIS_PTR xmm[index].xmm64u(1) = 0;
}
}
}
}
#endif
}
/* 0F 01 D0 */
void BX_CPP_AttrRegparmN(1) BX_CPU_C::XGETBV(bxInstruction_c *i)
{
#if BX_CPU_LEVEL >= 6
if(! BX_CPU_THIS_PTR cr4.get_OSXSAVE()) {
BX_ERROR(("XGETBV: OSXSAVE feature is not enabled in CR4!"));
exception(BX_UD_EXCEPTION, 0);
}
// 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);
}
RDX = 0;
RAX = BX_CPU_THIS_PTR xcr0.get32();
#endif
}
/* 0F 01 D1 */
void BX_CPP_AttrRegparmN(1) BX_CPU_C::XSETBV(bxInstruction_c *i)
{
#if BX_CPU_LEVEL >= 6
if(! BX_CPU_THIS_PTR cr4.get_OSXSAVE()) {
BX_ERROR(("XSETBV: OSXSAVE feature is not enabled in CR4!"));
exception(BX_UD_EXCEPTION, 0);
}
if (v8086_mode() || CPL != 0) {
BX_ERROR(("XSETBV: The current priveledge level is not 0"));
exception(BX_GP_EXCEPTION, 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);
}
if (EDX != 0 || (EAX & ~BX_XCR0_SUPPORTED_BITS) != 0 || (EAX & 1) == 0) {
BX_ERROR(("XSETBV: Attempting to change reserved bits!"));
exception(BX_GP_EXCEPTION, 0);
}
BX_CPU_THIS_PTR xcr0.set32(EAX);
#endif
}