Fixed all JUMP near, CALL near and RET near cases

for problem EIP>CS.limit was not checked in real mode
This commit is contained in:
Stanislav Shwartsman 2004-11-02 18:05:19 +00:00
parent 2ed7e4eed5
commit 4e3bc367b6
4 changed files with 70 additions and 160 deletions

View File

@ -17,6 +17,8 @@ Changes to next release:
- fetchdecode fixes for AMD64 and 3DNow!
- change BX_PANIC messages to BX_INFO when behaviour exactly
matches Intel docs
- EIP > CS.limit case should always cause #GP(0), even in real mode.
Fixed all jump, call and ret instructions for 16/32 modes
- fixed using invalid segment register for MOV instruction (h.johansson)
- fixed ET bit mismatch between CR0 and SMSW instruction
- fixed possible simulator #DIVZERO fault when executing IDIV instruction

View File

@ -1,5 +1,5 @@
/////////////////////////////////////////////////////////////////////////
// $Id: ctrl_xfer16.cc,v 1.24 2004-11-02 17:31:14 sshwarts Exp $
// $Id: ctrl_xfer16.cc,v 1.25 2004-11-02 18:05:18 sshwarts Exp $
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2001 MandrakeSoft S.A.
@ -32,31 +32,24 @@
void
BX_CPU_C::RETnear16_Iw(bxInstruction_c *i)
void BX_CPU_C::RETnear16_Iw(bxInstruction_c *i)
{
Bit16u imm16;
Bit16u return_IP;
//invalidate_prefetch_q();
#if BX_DEBUGGER
BX_CPU_THIS_PTR show_flag |= Flag_ret;
#endif
pop_16(&return_IP);
if (protected_mode()) {
if (return_IP >
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.limit_scaled)
{
BX_ERROR(("retnear_iw: IP > limit"));
exception(BX_GP_EXCEPTION, 0, 0);
}
if (return_IP > BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.limit_scaled)
{
BX_ERROR(("retnear_iw: IP > limit"));
exception(BX_GP_EXCEPTION, 0, 0);
}
EIP = return_IP;
EIP = return_IP;
imm16 = i->Iw();
if (BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.d_b) /* 32bit stack */
@ -67,33 +60,28 @@ BX_CPU_C::RETnear16_Iw(bxInstruction_c *i)
BX_INSTR_UCNEAR_BRANCH(BX_CPU_ID, BX_INSTR_IS_RET, EIP);
}
void
BX_CPU_C::RETnear16(bxInstruction_c *i)
void BX_CPU_C::RETnear16(bxInstruction_c *i)
{
Bit16u return_IP;
//invalidate_prefetch_q();
#if BX_DEBUGGER
BX_CPU_THIS_PTR show_flag |= Flag_ret;
#endif
pop_16(&return_IP);
if (protected_mode()) {
if (return_IP >
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.limit_scaled)
{
BX_ERROR(("retnear: IP > limit"));
exception(BX_GP_EXCEPTION, 0, 0);
}
if (return_IP > BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.limit_scaled)
{
BX_ERROR(("retnear: IP > limit"));
exception(BX_GP_EXCEPTION, 0, 0);
}
EIP = return_IP;
BX_INSTR_UCNEAR_BRANCH(BX_CPU_ID, BX_INSTR_IS_RET, EIP);
}
void
BX_CPU_C::RETfar16_Iw(bxInstruction_c *i)
void BX_CPU_C::RETfar16_Iw(bxInstruction_c *i)
{
BailBigRSP("RETfar16_Iw");
Bit16s imm16;
@ -130,10 +118,8 @@ done:
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value, EIP);
}
void
BX_CPU_C::RETfar16(bxInstruction_c *i)
void BX_CPU_C::RETfar16(bxInstruction_c *i)
{
BailBigRSP("RETfar16");
Bit16u ip, cs_raw;
invalidate_prefetch_q();
@ -159,25 +145,19 @@ done:
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value, EIP);
}
void
BX_CPU_C::CALL_Aw(bxInstruction_c *i)
void BX_CPU_C::CALL_Aw(bxInstruction_c *i)
{
BailBigRSP("CALL_Aw");
Bit32u new_EIP;
//invalidate_prefetch_q();
#if BX_DEBUGGER
BX_CPU_THIS_PTR show_flag |= Flag_call;
#endif
new_EIP = EIP + (Bit32s) i->Id();
new_EIP &= 0x0000ffff;
#if BX_CPU_LEVEL >= 2
if (protected_mode() &&
(new_EIP > BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.limit_scaled))
if (new_EIP > BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.limit_scaled)
{
BX_ERROR(("call_aw: new_IP > BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].limit"));
exception(BX_GP_EXCEPTION, 0, 0);
@ -191,10 +171,8 @@ BailBigRSP("CALL_Aw");
BX_INSTR_UCNEAR_BRANCH(BX_CPU_ID, BX_INSTR_IS_CALL, EIP);
}
void
BX_CPU_C::CALL16_Ap(bxInstruction_c *i)
void BX_CPU_C::CALL16_Ap(bxInstruction_c *i)
{
BailBigRSP("CALL16_Ap");
Bit16u cs_raw;
Bit16u disp16;
@ -224,14 +202,10 @@ done:
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value, EIP);
}
void
BX_CPU_C::CALL_Ew(bxInstruction_c *i)
void BX_CPU_C::CALL_Ew(bxInstruction_c *i)
{
BailBigRSP("CALL_Ew");
Bit16u op1_16;
//invalidate_prefetch_q();
#if BX_DEBUGGER
BX_CPU_THIS_PTR show_flag |= Flag_call;
#endif
@ -244,13 +218,10 @@ BailBigRSP("CALL_Ew");
}
#if BX_CPU_LEVEL >= 2
if (protected_mode()) {
if (op1_16 >
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.limit_scaled)
{
BX_ERROR(("call_ew: IP out of CS limits!"));
exception(BX_GP_EXCEPTION, 0, 0);
}
if (op1_16 > BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.limit_scaled)
{
BX_ERROR(("call_ew: IP out of CS limits!"));
exception(BX_GP_EXCEPTION, 0, 0);
}
#endif
@ -260,10 +231,8 @@ BailBigRSP("CALL_Ew");
BX_INSTR_UCNEAR_BRANCH(BX_CPU_ID, BX_INSTR_IS_CALL, EIP);
}
void
BX_CPU_C::CALL16_Ep(bxInstruction_c *i)
void BX_CPU_C::CALL16_Ep(bxInstruction_c *i)
{
BailBigRSP("CALL_16_Ep");
Bit16u cs_raw;
Bit16u op1_16;
@ -297,9 +266,7 @@ done:
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value, EIP);
}
void
BX_CPU_C::JMP_Jw(bxInstruction_c *i)
void BX_CPU_C::JMP_Jw(bxInstruction_c *i)
{
Bit32u new_EIP = EIP + (Bit32s) i->Id();
new_EIP &= 0x0000ffff;
@ -307,8 +274,7 @@ BX_CPU_C::JMP_Jw(bxInstruction_c *i)
BX_INSTR_UCNEAR_BRANCH(BX_CPU_ID, BX_INSTR_IS_JMP, new_EIP);
}
void
BX_CPU_C::JCC_Jw(bxInstruction_c *i)
void BX_CPU_C::JCC_Jw(bxInstruction_c *i)
{
bx_bool condition;
@ -350,8 +316,7 @@ BX_CPU_C::JCC_Jw(bxInstruction_c *i)
#endif
}
void
BX_CPU_C::JZ_Jw(bxInstruction_c *i)
void BX_CPU_C::JZ_Jw(bxInstruction_c *i)
{
if (get_ZF()) {
Bit32u new_EIP = EIP + (Bit32s) i->Id();
@ -366,8 +331,7 @@ BX_CPU_C::JZ_Jw(bxInstruction_c *i)
#endif
}
void
BX_CPU_C::JNZ_Jw(bxInstruction_c *i)
void BX_CPU_C::JNZ_Jw(bxInstruction_c *i)
{
if (!get_ZF()) {
Bit32u new_EIP = EIP + (Bit32s) i->Id();
@ -382,9 +346,7 @@ BX_CPU_C::JNZ_Jw(bxInstruction_c *i)
#endif
}
void
BX_CPU_C::JMP_Ew(bxInstruction_c *i)
void BX_CPU_C::JMP_Ew(bxInstruction_c *i)
{
Bit16u op1_16;
@ -402,8 +364,7 @@ BX_CPU_C::JMP_Ew(bxInstruction_c *i)
/* Far indirect jump */
void
BX_CPU_C::JMP16_Ep(bxInstruction_c *i)
void BX_CPU_C::JMP16_Ep(bxInstruction_c *i)
{
BailBigRSP("JMP16_Ep");
Bit16u cs_raw;
@ -435,8 +396,7 @@ done:
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value, EIP);
}
void
BX_CPU_C::IRET16(bxInstruction_c *i)
void BX_CPU_C::IRET16(bxInstruction_c *i)
{
BailBigRSP("IRET16");
Bit16u ip, cs_raw, flags;

View File

@ -1,5 +1,5 @@
/////////////////////////////////////////////////////////////////////////
// $Id: ctrl_xfer32.cc,v 1.34 2004-11-02 17:31:14 sshwarts Exp $
// $Id: ctrl_xfer32.cc,v 1.35 2004-11-02 18:05:19 sshwarts Exp $
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2001 MandrakeSoft S.A.
@ -34,13 +34,10 @@
void BX_CPU_C::RETnear32_Iw(bxInstruction_c *i)
{
BailBigRSP("RETnear32_Iw");
Bit16u imm16;
Bit32u temp_ESP;
Bit32u return_EIP;
//invalidate_prefetch_q();
#if BX_DEBUGGER
BX_CPU_THIS_PTR show_flag |= Flag_ret;
#endif
@ -77,15 +74,15 @@ BailBigRSP("RETnear32_Iw");
EIP = return_EIP;
if (BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.d_b) /* 32bit stack */
ESP += 4 + imm16; /* ??? should it be 2*imm16 ? */
ESP += 4 + imm16;
else
SP += 4 + imm16;
}
else {
pop_32(&return_EIP);
EIP = return_EIP;
branch_near32(return_EIP);
if (BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.d_b) /* 32bit stack */
ESP += imm16; /* ??? should it be 2*imm16 ? */
ESP += imm16;
else
SP += imm16;
}
@ -95,12 +92,9 @@ BailBigRSP("RETnear32_Iw");
void BX_CPU_C::RETnear32(bxInstruction_c *i)
{
BailBigRSP("RETnear32");
Bit32u temp_ESP;
Bit32u return_EIP;
//invalidate_prefetch_q();
#if BX_DEBUGGER
BX_CPU_THIS_PTR show_flag |= Flag_ret;
#endif
@ -134,7 +128,7 @@ BailBigRSP("RETnear32");
}
else {
pop_32(&return_EIP);
EIP = return_EIP;
branch_near32(return_EIP);
}
BX_INSTR_UCNEAR_BRANCH(BX_CPU_ID, BX_INSTR_IS_RET, EIP);
@ -210,12 +204,10 @@ BailBigRSP("CALL_Ad");
Bit32u new_EIP = EIP + i->Id();
if ( protected_mode() ) {
if ( new_EIP > BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.limit_scaled ) {
BX_ERROR(("call_ad: offset outside of CS limits"));
exception(BX_GP_EXCEPTION, 0, 0);
}
}
if ( new_EIP > BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.limit_scaled ) {
BX_ERROR(("call_ad: offset outside of CS limits"));
exception(BX_GP_EXCEPTION, 0, 0);
}
/* push 32 bit EA of next instruction */
push_32(EIP);
@ -243,6 +235,7 @@ BailBigRSP("CALL32_Ap");
BX_CPU_THIS_PTR call_protected(i, cs_raw, disp32);
goto done;
}
push_32(BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value);
push_32(EIP);
EIP = disp32;
@ -255,11 +248,8 @@ done:
void BX_CPU_C::CALL_Ed(bxInstruction_c *i)
{
BailBigRSP("CALL_Ed");
Bit32u op1_32;
//invalidate_prefetch_q();
#if BX_DEBUGGER
BX_CPU_THIS_PTR show_flag |= Flag_call;
#endif
@ -271,13 +261,10 @@ BailBigRSP("CALL_Ed");
read_virtual_dword(i->seg(), RMAddr(i), &op1_32);
}
if (protected_mode()) {
if (op1_32 >
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.limit_scaled)
{
BX_ERROR(("call_ed: IP out of CS limits!"));
exception(BX_GP_EXCEPTION, 0, 0);
}
if (op1_32 > BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.limit_scaled)
{
BX_ERROR(("call_ed: IP out of CS limits!"));
exception(BX_GP_EXCEPTION, 0, 0);
}
push_32(EIP);

View File

@ -1,5 +1,5 @@
/////////////////////////////////////////////////////////////////////////
// $Id: ctrl_xfer8.cc,v 1.16 2004-11-02 16:10:01 sshwarts Exp $
// $Id: ctrl_xfer8.cc,v 1.17 2004-11-02 18:05:19 sshwarts Exp $
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2001 MandrakeSoft S.A.
@ -67,22 +67,10 @@ BailBigRSP("JCXZ_Jb");
temp_ECX = CX;
if ( temp_ECX == 0 ) {
Bit32u new_EIP;
new_EIP = EIP + (Bit32s) i->Id();
if (i->os32L()==0)
new_EIP &= 0x0000ffff;
#if BX_CPU_LEVEL >= 2
if (protected_mode()) {
if ( new_EIP > BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.limit_scaled ) {
BX_ERROR(("jcxz_jb: offset outside of CS limits"));
exception(BX_GP_EXCEPTION, 0, 0);
}
}
#endif
EIP = new_EIP;
Bit32u new_EIP = EIP + (Bit32s) i->Id();
if (i->os32L()==0) new_EIP &= 0x0000ffff;
branch_near32(new_EIP);
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, new_EIP);
revalidate_prefetch_q();
}
#if BX_INSTRUMENTATION
else {
@ -100,7 +88,6 @@ BailBigRSP("loopne_jb");
if (i->as64L()) {
if ( ((--RCX)!=0) && (get_ZF()==0) ) {
RIP += (Bit32s) i->Id();
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, RIP);
revalidate_prefetch_q();
@ -114,7 +101,7 @@ BailBigRSP("loopne_jb");
else
#endif
{
Bit32u count, new_EIP;
Bit32u count;
#if BX_CPU_LEVEL >= 3
if (i->as32L())
@ -125,20 +112,11 @@ BailBigRSP("loopne_jb");
count--;
if ( (count!=0) && (get_ZF()==0) ) {
new_EIP = EIP + (Bit32s) i->Id();
if (i->os32L()==0)
new_EIP &= 0x0000ffff;
if (protected_mode()) {
if (new_EIP > BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.limit_scaled) {
BX_ERROR(("loopne_jb: offset outside of CS limits"));
exception(BX_GP_EXCEPTION, 0, 0);
}
}
EIP = new_EIP;
Bit32u new_EIP = EIP + (Bit32s) i->Id();
if (i->os32L()==0) new_EIP &= 0x0000ffff;
branch_near32(new_EIP);
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, new_EIP);
revalidate_prefetch_q();
}
}
#if BX_INSTRUMENTATION
else {
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
@ -171,8 +149,8 @@ BailBigRSP("loope_jb");
}
else
#endif
{
Bit32u count, new_EIP;
{
Bit32u count;
#if BX_CPU_LEVEL >= 3
if (i->as32L())
@ -183,20 +161,11 @@ BailBigRSP("loope_jb");
count--;
if ( (count!=0) && get_ZF()) {
new_EIP = EIP + (Bit32s) i->Id();
if (i->os32L()==0)
new_EIP &= 0x0000ffff;
if (protected_mode()) {
if (new_EIP > BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.limit_scaled) {
BX_ERROR(("loope_jb: offset outside of CS limits"));
exception(BX_GP_EXCEPTION, 0, 0);
}
}
EIP = new_EIP;
Bit32u new_EIP = EIP + (Bit32s) i->Id();
if (i->os32L()==0) new_EIP &= 0x0000ffff;
branch_near32(new_EIP);
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, new_EIP);
revalidate_prefetch_q();
}
}
#if BX_INSTRUMENTATION
else {
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
@ -229,8 +198,8 @@ BailBigRSP("loop_jb");
}
else
#endif
{
Bit32u count, new_EIP;
{
Bit32u count;
#if BX_CPU_LEVEL >= 3
if (i->as32L())
@ -241,19 +210,11 @@ BailBigRSP("loop_jb");
count--;
if (count != 0) {
new_EIP = EIP + (Bit32s) i->Id();
if (i->os32L()==0)
new_EIP &= 0x0000ffff;
if (protected_mode()) {
if (new_EIP > BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.limit_scaled) {
BX_ERROR(("loop_jb: offset outside of CS limits"));
exception(BX_GP_EXCEPTION, 0, 0);
}
}
EIP = new_EIP;
Bit32u new_EIP = EIP + (Bit32s) i->Id();
if (i->os32L()==0) new_EIP &= 0x0000ffff;
branch_near32(new_EIP);
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, new_EIP);
revalidate_prefetch_q();
}
}
#if BX_INSTRUMENTATION
else {
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);