Fixed a lot of code duplication and possible bug with oncorrect implementation of repeat speedup in 64-bit guest

This commit is contained in:
Stanislav Shwartsman 2007-12-17 21:13:55 +00:00
parent fe2e0525da
commit d032a30429
2 changed files with 159 additions and 193 deletions

View File

@ -1,5 +1,5 @@
///////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////
// $Id: io.cc,v 1.43 2007-12-16 21:03:45 sshwarts Exp $ // $Id: io.cc,v 1.44 2007-12-17 21:13:55 sshwarts Exp $
///////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////
// //
// Copyright (C) 2001 MandrakeSoft S.A. // Copyright (C) 2001 MandrakeSoft S.A.
@ -329,11 +329,9 @@ void BX_CPU_C::INSB_YbDX(bxInstruction_c *i)
{ {
Bit8u value8=0; Bit8u value8=0;
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 allow_io(DX, 1)) {
if (! BX_CPU_THIS_PTR allow_io(DX, 1)) { BX_DEBUG(("INSB_YbDX: I/O access not allowed !"));
BX_DEBUG(("INSB_YbDX: I/O access not allowed !")); exception(BX_GP_EXCEPTION, 0, 0);
exception(BX_GP_EXCEPTION, 0, 0);
}
} }
#if BX_SUPPORT_X86_64 #if BX_SUPPORT_X86_64
@ -391,140 +389,138 @@ void BX_CPU_C::INSB_YbDX(bxInstruction_c *i)
// input word from port to string // input word from port to string
void BX_CPU_C::INSW_YwDX(bxInstruction_c *i) void BX_CPU_C::INSW_YwDX(bxInstruction_c *i)
{ {
bx_address edi; bx_address rdi;
unsigned int incr = 2; Bit32u incr = 2;
#if BX_SUPPORT_X86_64
if (i->as64L())
edi = RDI;
else
#endif
if (i->as32L())
edi = EDI;
else
edi = DI;
Bit16u value16=0; Bit16u value16=0;
#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;
#if BX_SUPPORT_X86_64 #if BX_SUPPORT_X86_64
if (i->as64L()) if (i->as64L()) {
wordCount = RCX; // Truncated to 32bits. (we're only doing 1 page) rdi = RDI;
// Write a zero to memory, to trigger any segment or page
// faults before reading from IO port.
write_virtual_word(BX_SEG_REG_ES, rdi, &value16);
value16 = BX_INP(DX, 2);
/* no seg override allowed */
write_virtual_word(BX_SEG_REG_ES, rdi, &value16);
if (BX_CPU_THIS_PTR get_DF())
rdi -= 2;
else else
#endif rdi += 2;
if (i->as32L())
wordCount = ECX;
else
wordCount = CX;
BX_ASSERT(wordCount > 0); RDI = rdi;
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);
#if BX_SUPPORT_X86_64
if (i->as64L())
RCX -= (wordCount-1);
else
#endif
if (i->as32L())
RCX = ECX - (wordCount-1);
else
CX -= (wordCount-1);
incr = wordCount << 1; // count * 2.
goto doIncr;
}
} }
else
#endif
{
if (i->as32L())
rdi = EDI;
else
rdi = DI;
#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;
if (i->as32L())
wordCount = ECX;
else
wordCount = CX;
BX_ASSERT(wordCount > 0);
wordCount = FastRepINSW(i, rdi, 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);
if (i->as32L())
RCX = ECX - (wordCount-1);
else
CX -= (wordCount-1);
incr = wordCount << 1; // count * 2.
goto doIncr;
}
}
#endif #endif
// Write a zero to memory, to trigger any segment or page // Write a zero to memory, to trigger any segment or page
// faults before reading from IO port. // faults before reading from IO port.
write_virtual_word(BX_SEG_REG_ES, edi, &value16); write_virtual_word(BX_SEG_REG_ES, rdi, &value16);
value16 = BX_INP(DX, 2); value16 = BX_INP(DX, 2);
/* no seg override allowed */ /* no seg override allowed */
write_virtual_word(BX_SEG_REG_ES, edi, &value16); write_virtual_word(BX_SEG_REG_ES, rdi, &value16);
incr = 2;
#if (BX_SupportRepeatSpeedups) && (BX_DEBUGGER == 0) #if (BX_SupportRepeatSpeedups) && (BX_DEBUGGER == 0)
doIncr: doIncr:
#endif #endif
#if BX_SUPPORT_X86_64 if (i->as32L()) {
if (i->as64L()) { if (BX_CPU_THIS_PTR get_DF())
if (BX_CPU_THIS_PTR get_DF()) RDI = EDI - incr;
RDI = RDI - incr; else
else RDI = EDI + incr;
RDI = RDI + incr; }
} else {
else if (BX_CPU_THIS_PTR get_DF())
#endif DI -= incr;
if (i->as32L()) { else
if (BX_CPU_THIS_PTR get_DF()) DI += incr;
RDI = EDI - incr; }
else
RDI = EDI + incr;
}
else {
if (BX_CPU_THIS_PTR get_DF())
DI = DI - incr;
else
DI = DI + incr;
} }
} }
// input doubleword from port to string // input doubleword from port to string
void BX_CPU_C::INSD_YdDX(bxInstruction_c *i) void BX_CPU_C::INSD_YdDX(bxInstruction_c *i)
{ {
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 allow_io(DX, 4)) {
if (! BX_CPU_THIS_PTR allow_io(DX, 4)) { BX_DEBUG(("INSD_YdDX: I/O access not allowed !"));
BX_DEBUG(("INSD_YdDX: I/O access not allowed !")); exception(BX_GP_EXCEPTION, 0, 0);
exception(BX_GP_EXCEPTION, 0, 0);
}
} }
bx_address edi; bx_address rdi;
#if BX_SUPPORT_X86_64 #if BX_SUPPORT_X86_64
if (i->as64L()) if (i->as64L())
edi = RDI; rdi = RDI;
else else
#endif #endif
if (i->as32L()) if (i->as32L())
edi = EDI; rdi = EDI;
else else
edi = DI; rdi = DI;
Bit32u value32=0; Bit32u value32=0;
// Write a zero to memory, to trigger any segment or page // Write a zero to memory, to trigger any segment or page
// faults before reading from IO port. // faults before reading from IO port.
write_virtual_dword(BX_SEG_REG_ES, edi, &value32); write_virtual_dword(BX_SEG_REG_ES, rdi, &value32);
value32 = BX_INP(DX, 4); value32 = BX_INP(DX, 4);
/* no seg override allowed */ /* no seg override allowed */
write_virtual_dword(BX_SEG_REG_ES, edi, &value32); write_virtual_dword(BX_SEG_REG_ES, rdi, &value32);
#if BX_SUPPORT_X86_64 #if BX_SUPPORT_X86_64
if (i->as64L()) { if (i->as64L()) {
if (BX_CPU_THIS_PTR get_DF()) if (BX_CPU_THIS_PTR get_DF())
RDI = RDI - 4; RDI -= 4;
else else
RDI = RDI + 4; RDI += 4;
} }
else else
#endif #endif
@ -536,9 +532,9 @@ void BX_CPU_C::INSD_YdDX(bxInstruction_c *i)
} }
else { else {
if (BX_CPU_THIS_PTR get_DF()) if (BX_CPU_THIS_PTR get_DF())
DI = DI - 4; DI -= 4;
else else
DI = DI + 4; DI += 4;
} }
} }
@ -570,11 +566,9 @@ void BX_CPU_C::OUTSB_DXXb(bxInstruction_c *i)
Bit8u value8; Bit8u value8;
bx_address esi; bx_address esi;
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 allow_io(DX, 1)) {
if (! BX_CPU_THIS_PTR allow_io(DX, 1)) { BX_DEBUG(("OUTSB_DXXb: I/O access not allowed !"));
BX_DEBUG(("OUTSB_DXXb: I/O access not allowed !")); exception(BX_GP_EXCEPTION, 0, 0);
exception(BX_GP_EXCEPTION, 0, 0);
}
} }
#if BX_SUPPORT_X86_64 #if BX_SUPPORT_X86_64
@ -618,13 +612,11 @@ void BX_CPU_C::OUTSB_DXXb(bxInstruction_c *i)
void BX_CPU_C::OUTSW_DXXw(bxInstruction_c *i) void BX_CPU_C::OUTSW_DXXw(bxInstruction_c *i)
{ {
bx_address esi; bx_address esi;
unsigned incr = 2; Bit32u incr = 2;
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 allow_io(DX, 2)) {
if (! BX_CPU_THIS_PTR allow_io(DX, 2)) { BX_DEBUG(("OUTSW_DXXw: I/O access not allowed !"));
BX_DEBUG(("OUTSW_DXXw: I/O access not allowed !")); exception(BX_GP_EXCEPTION, 0, 0);
exception(BX_GP_EXCEPTION, 0, 0);
}
} }
#if BX_SUPPORT_X86_64 #if BX_SUPPORT_X86_64
@ -711,11 +703,9 @@ void BX_CPU_C::OUTSW_DXXw(bxInstruction_c *i)
// output doubleword string to port // output doubleword string to port
void BX_CPU_C::OUTSD_DXXd(bxInstruction_c *i) void BX_CPU_C::OUTSD_DXXd(bxInstruction_c *i)
{ {
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 allow_io(DX, 4)) {
if (! BX_CPU_THIS_PTR allow_io(DX, 4)) { BX_DEBUG(("OUTSD_DXXd: I/O access not allowed !"));
BX_DEBUG(("OUTSD_DXXd: I/O access not allowed !")); exception(BX_GP_EXCEPTION, 0, 0);
exception(BX_GP_EXCEPTION, 0, 0);
}
} }
bx_address esi; bx_address esi;

View File

@ -1,5 +1,5 @@
///////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////
// $Id: io_pro.cc,v 1.25 2007-11-29 21:45:10 sshwarts Exp $ // $Id: io_pro.cc,v 1.26 2007-12-17 21:13:55 sshwarts Exp $
///////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////
// //
// Copyright (C) 2001 MandrakeSoft S.A. // Copyright (C) 2001 MandrakeSoft S.A.
@ -35,31 +35,21 @@
Bit16u BX_CPP_AttrRegparmN(1) Bit16u BX_CPP_AttrRegparmN(1)
BX_CPU_C::inp16(Bit16u addr) BX_CPU_C::inp16(Bit16u addr)
{ {
Bit16u ret16; if (! BX_CPU_THIS_PTR allow_io(addr, 2)) {
BX_DEBUG(("inp16(): I/O access not allowed !"));
if (BX_CPU_THIS_PTR cr0.get_PE() && (BX_CPU_THIS_PTR get_VM() || (CPL>BX_CPU_THIS_PTR get_IOPL()))) { exception(BX_GP_EXCEPTION, 0, 0);
if (! BX_CPU_THIS_PTR allow_io(addr, 2)) {
BX_DEBUG(("inp16(): I/O access not allowed !"));
exception(BX_GP_EXCEPTION, 0, 0);
}
} }
ret16 = BX_INP(addr, 2); Bit16u ret16 = BX_INP(addr, 2);
return ret16; return ret16;
} }
void BX_CPP_AttrRegparmN(2) void BX_CPP_AttrRegparmN(2)
BX_CPU_C::outp16(Bit16u addr, Bit16u value) BX_CPU_C::outp16(Bit16u addr, Bit16u value)
{ {
/* If CPL <= IOPL, then all IO addresses are accessible. if (! BX_CPU_THIS_PTR allow_io(addr, 2)) {
* Otherwise, must check the IO permission map on >286. BX_DEBUG(("outp16(): I/O access not allowed !"));
* On the 286, there is no IO permissions map */ exception(BX_GP_EXCEPTION, 0, 0);
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 allow_io(addr, 2)) {
BX_DEBUG(("outp16(): I/O access not allowed !"));
exception(BX_GP_EXCEPTION, 0, 0);
}
} }
BX_OUTP(addr, value, 2); BX_OUTP(addr, value, 2);
@ -68,31 +58,21 @@ BX_CPU_C::outp16(Bit16u addr, Bit16u value)
Bit32u BX_CPP_AttrRegparmN(1) Bit32u BX_CPP_AttrRegparmN(1)
BX_CPU_C::inp32(Bit16u addr) BX_CPU_C::inp32(Bit16u addr)
{ {
Bit32u ret32; if (! BX_CPU_THIS_PTR allow_io(addr, 4)) {
BX_DEBUG(("inp32(): I/O access not allowed !"));
if (BX_CPU_THIS_PTR cr0.get_PE() && (BX_CPU_THIS_PTR get_VM() || (CPL>BX_CPU_THIS_PTR get_IOPL()))) { exception(BX_GP_EXCEPTION, 0, 0);
if (! BX_CPU_THIS_PTR allow_io(addr, 4)) {
BX_DEBUG(("inp32(): I/O access not allowed !"));
exception(BX_GP_EXCEPTION, 0, 0);
}
} }
ret32 = BX_INP(addr, 4); Bit32u ret32 = BX_INP(addr, 4);
return ret32; return ret32;
} }
void BX_CPP_AttrRegparmN(2) void BX_CPP_AttrRegparmN(2)
BX_CPU_C::outp32(Bit16u addr, Bit32u value) BX_CPU_C::outp32(Bit16u addr, Bit32u value)
{ {
/* If CPL <= IOPL, then all IO addresses are accessible. if (! BX_CPU_THIS_PTR allow_io(addr, 4)) {
* Otherwise, must check the IO permission map on >286. BX_DEBUG(("outp32(): I/O access not allowed !"));
* On the 286, there is no IO permissions map */ exception(BX_GP_EXCEPTION, 0, 0);
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 allow_io(addr, 4)) {
BX_DEBUG(("outp32(): I/O access not allowed !"));
exception(BX_GP_EXCEPTION, 0, 0);
}
} }
BX_OUTP(addr, value, 4); BX_OUTP(addr, value, 4);
@ -101,32 +81,21 @@ BX_CPU_C::outp32(Bit16u addr, Bit32u value)
Bit8u BX_CPP_AttrRegparmN(1) Bit8u BX_CPP_AttrRegparmN(1)
BX_CPU_C::inp8(Bit16u addr) BX_CPU_C::inp8(Bit16u addr)
{ {
Bit8u ret8; if (! BX_CPU_THIS_PTR allow_io(addr, 1)) {
BX_DEBUG(("inp8(): I/O access not allowed !"));
if (BX_CPU_THIS_PTR cr0.get_PE() && (BX_CPU_THIS_PTR get_VM() || (CPL>BX_CPU_THIS_PTR get_IOPL()))) { exception(BX_GP_EXCEPTION, 0, 0);
if (! BX_CPU_THIS_PTR allow_io(addr, 1)) {
BX_DEBUG(("inp8(): I/O access not allowed !"));
exception(BX_GP_EXCEPTION, 0, 0);
}
} }
ret8 = BX_INP(addr, 1); Bit8u ret8 = BX_INP(addr, 1);
return ret8; return ret8;
} }
void BX_CPP_AttrRegparmN(2) void BX_CPP_AttrRegparmN(2)
BX_CPU_C::outp8(Bit16u addr, Bit8u value) BX_CPU_C::outp8(Bit16u addr, Bit8u value)
{ {
/* If CPL <= IOPL, then all IO addresses are accessible. if (! BX_CPU_THIS_PTR allow_io(addr, 1)) {
* Otherwise, must check the IO permission map on >286. BX_DEBUG(("outp8(): I/O access not allowed !"));
* On the 286, there is no IO permissions map */ exception(BX_GP_EXCEPTION, 0, 0);
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 allow_io(addr, 1)) {
BX_DEBUG(("outp8(): I/O access not allowed !"));
exception(BX_GP_EXCEPTION, 0, 0);
}
} }
BX_OUTP(addr, value, 1); BX_OUTP(addr, value, 1);
@ -136,41 +105,48 @@ bx_bool BX_CPU_C::allow_io(Bit16u addr, unsigned len)
{ {
Bit16u io_base, permission16; Bit16u io_base, permission16;
if (BX_CPU_THIS_PTR tr.cache.valid==0 || /* If CPL <= IOPL, then all IO addresses are accessible.
BX_CPU_THIS_PTR tr.cache.type != BX_SYS_SEGMENT_AVAIL_386_TSS) * 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())))
{ {
BX_ERROR(("allow_io(): TR doesn't point to a valid 32bit TSS")); if (BX_CPU_THIS_PTR tr.cache.valid==0 ||
return(0); BX_CPU_THIS_PTR tr.cache.type != BX_SYS_SEGMENT_AVAIL_386_TSS)
} {
BX_ERROR(("allow_io(): TR doesn't point to a valid 32bit TSS"));
return(0);
}
if (BX_CPU_THIS_PTR tr.cache.u.system.limit_scaled < 103) { if (BX_CPU_THIS_PTR tr.cache.u.system.limit_scaled < 103) {
BX_ERROR(("allow_io(): TR.limit < 103")); BX_ERROR(("allow_io(): TR.limit < 103"));
return(0); return(0);
} }
access_linear(BX_CPU_THIS_PTR tr.cache.u.system.base + 102, access_linear(BX_CPU_THIS_PTR tr.cache.u.system.base + 102,
2, 0, BX_READ, &io_base); 2, 0, BX_READ, &io_base);
if (io_base <= 103) { if (io_base <= 103) {
BX_ERROR(("allow_io(): TR:io_base (%u) <= 103", io_base)); BX_ERROR(("allow_io(): TR:io_base (%u) <= 103", io_base));
return(0); return(0);
} }
if ( (Bit32s) (addr/8) >= (Bit32s) (BX_CPU_THIS_PTR tr.cache.u.system.limit_scaled - io_base)) { if ( (Bit32s) (addr/8) >= (Bit32s) (BX_CPU_THIS_PTR tr.cache.u.system.limit_scaled - io_base)) {
BX_ERROR(("allow_io(): IO addr %x (len %d) outside TSS IO permission map (base=%x, limit=%x) #GP(0)", BX_ERROR(("allow_io(): IO addr %x (len %d) outside TSS IO permission map (base=%x, limit=%x) #GP(0)",
addr, len, io_base, BX_CPU_THIS_PTR tr.cache.u.system.limit_scaled)); addr, len, io_base, BX_CPU_THIS_PTR tr.cache.u.system.limit_scaled));
return(0); return(0);
} }
access_linear(BX_CPU_THIS_PTR tr.cache.u.system.base + io_base + addr/8, access_linear(BX_CPU_THIS_PTR tr.cache.u.system.base + io_base + addr/8,
2, 0, BX_READ, &permission16); 2, 0, BX_READ, &permission16);
unsigned bit_index = addr & 0x07; unsigned bit_index = addr & 0x07;
permission16 >>= bit_index; permission16 >>= bit_index;
for (unsigned i=0; i<len; i++) { for (unsigned i=0; i<len; i++) {
if (permission16 & 0x01) if (permission16 & 0x01)
return(0); return(0);
permission16 >>= 1; permission16 >>= 1;
}
} }
return(1); return(1);