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.
@ -329,11 +329,9 @@ void BX_CPU_C::INSB_YbDX(bxInstruction_c *i)
{
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)) {
BX_DEBUG(("INSB_YbDX: I/O access not allowed !"));
exception(BX_GP_EXCEPTION, 0, 0);
}
if (! BX_CPU_THIS_PTR allow_io(DX, 1)) {
BX_DEBUG(("INSB_YbDX: I/O access not allowed !"));
exception(BX_GP_EXCEPTION, 0, 0);
}
#if BX_SUPPORT_X86_64
@ -391,140 +389,138 @@ void BX_CPU_C::INSB_YbDX(bxInstruction_c *i)
// input word from port to string
void BX_CPU_C::INSW_YwDX(bxInstruction_c *i)
{
bx_address edi;
unsigned int incr = 2;
#if BX_SUPPORT_X86_64
if (i->as64L())
edi = RDI;
else
#endif
if (i->as32L())
edi = EDI;
else
edi = DI;
bx_address rdi;
Bit32u incr = 2;
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 (i->as64L())
wordCount = RCX; // Truncated to 32bits. (we're only doing 1 page)
if (i->as64L()) {
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
#endif
if (i->as32L())
wordCount = ECX;
else
wordCount = CX;
rdi += 2;
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);
#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;
}
RDI = rdi;
}
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
// Write a zero to memory, to trigger any segment or page
// faults before reading from IO port.
write_virtual_word(BX_SEG_REG_ES, edi, &value16);
// 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);
value16 = BX_INP(DX, 2);
/* no seg override allowed */
write_virtual_word(BX_SEG_REG_ES, edi, &value16);
incr = 2;
/* no seg override allowed */
write_virtual_word(BX_SEG_REG_ES, rdi, &value16);
#if (BX_SupportRepeatSpeedups) && (BX_DEBUGGER == 0)
doIncr:
#endif
#if BX_SUPPORT_X86_64
if (i->as64L()) {
if (BX_CPU_THIS_PTR get_DF())
RDI = RDI - incr;
else
RDI = RDI + incr;
}
else
#endif
if (i->as32L()) {
if (BX_CPU_THIS_PTR get_DF())
RDI = EDI - incr;
else
RDI = EDI + incr;
}
else {
if (BX_CPU_THIS_PTR get_DF())
DI = DI - incr;
else
DI = DI + incr;
if (i->as32L()) {
if (BX_CPU_THIS_PTR get_DF())
RDI = EDI - incr;
else
RDI = EDI + incr;
}
else {
if (BX_CPU_THIS_PTR get_DF())
DI -= incr;
else
DI += incr;
}
}
}
// input doubleword from port to string
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)) {
BX_DEBUG(("INSD_YdDX: I/O access not allowed !"));
exception(BX_GP_EXCEPTION, 0, 0);
}
if (! BX_CPU_THIS_PTR allow_io(DX, 4)) {
BX_DEBUG(("INSD_YdDX: I/O access not allowed !"));
exception(BX_GP_EXCEPTION, 0, 0);
}
bx_address edi;
bx_address rdi;
#if BX_SUPPORT_X86_64
if (i->as64L())
edi = RDI;
rdi = RDI;
else
#endif
if (i->as32L())
edi = EDI;
rdi = EDI;
else
edi = DI;
rdi = DI;
Bit32u value32=0;
// Write a zero to memory, to trigger any segment or page
// 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);
/* 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 (i->as64L()) {
if (BX_CPU_THIS_PTR get_DF())
RDI = RDI - 4;
RDI -= 4;
else
RDI = RDI + 4;
RDI += 4;
}
else
#endif
@ -536,9 +532,9 @@ void BX_CPU_C::INSD_YdDX(bxInstruction_c *i)
}
else {
if (BX_CPU_THIS_PTR get_DF())
DI = DI - 4;
DI -= 4;
else
DI = DI + 4;
DI += 4;
}
}
@ -570,11 +566,9 @@ void BX_CPU_C::OUTSB_DXXb(bxInstruction_c *i)
Bit8u value8;
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)) {
BX_DEBUG(("OUTSB_DXXb: I/O access not allowed !"));
exception(BX_GP_EXCEPTION, 0, 0);
}
if (! BX_CPU_THIS_PTR allow_io(DX, 1)) {
BX_DEBUG(("OUTSB_DXXb: I/O access not allowed !"));
exception(BX_GP_EXCEPTION, 0, 0);
}
#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)
{
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)) {
BX_DEBUG(("OUTSW_DXXw: I/O access not allowed !"));
exception(BX_GP_EXCEPTION, 0, 0);
}
if (! BX_CPU_THIS_PTR allow_io(DX, 2)) {
BX_DEBUG(("OUTSW_DXXw: I/O access not allowed !"));
exception(BX_GP_EXCEPTION, 0, 0);
}
#if BX_SUPPORT_X86_64
@ -711,11 +703,9 @@ void BX_CPU_C::OUTSW_DXXw(bxInstruction_c *i)
// output doubleword string to port
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)) {
BX_DEBUG(("OUTSD_DXXd: I/O access not allowed !"));
exception(BX_GP_EXCEPTION, 0, 0);
}
if (! BX_CPU_THIS_PTR allow_io(DX, 4)) {
BX_DEBUG(("OUTSD_DXXd: I/O access not allowed !"));
exception(BX_GP_EXCEPTION, 0, 0);
}
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.
@ -35,31 +35,21 @@
Bit16u BX_CPP_AttrRegparmN(1)
BX_CPU_C::inp16(Bit16u addr)
{
Bit16u ret16;
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(("inp16(): I/O access not allowed !"));
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;
}
void BX_CPP_AttrRegparmN(2)
BX_CPU_C::outp16(Bit16u addr, Bit16u value)
{
/* If CPL <= IOPL, then all IO addresses 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 allow_io(addr, 2)) {
BX_DEBUG(("outp16(): I/O access not allowed !"));
exception(BX_GP_EXCEPTION, 0, 0);
}
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);
@ -68,31 +58,21 @@ BX_CPU_C::outp16(Bit16u addr, Bit16u value)
Bit32u BX_CPP_AttrRegparmN(1)
BX_CPU_C::inp32(Bit16u addr)
{
Bit32u ret32;
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(("inp32(): I/O access not allowed !"));
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;
}
void BX_CPP_AttrRegparmN(2)
BX_CPU_C::outp32(Bit16u addr, Bit32u value)
{
/* If CPL <= IOPL, then all IO addresses 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 allow_io(addr, 4)) {
BX_DEBUG(("outp32(): I/O access not allowed !"));
exception(BX_GP_EXCEPTION, 0, 0);
}
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);
@ -101,32 +81,21 @@ BX_CPU_C::outp32(Bit16u addr, Bit32u value)
Bit8u BX_CPP_AttrRegparmN(1)
BX_CPU_C::inp8(Bit16u addr)
{
Bit8u ret8;
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(("inp8(): I/O access not allowed !"));
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;
}
void BX_CPP_AttrRegparmN(2)
BX_CPU_C::outp8(Bit16u addr, Bit8u value)
{
/* If CPL <= IOPL, then all IO addresses 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 allow_io(addr, 1)) {
BX_DEBUG(("outp8(): I/O access not allowed !"));
exception(BX_GP_EXCEPTION, 0, 0);
}
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);
@ -136,41 +105,48 @@ bx_bool BX_CPU_C::allow_io(Bit16u addr, unsigned len)
{
Bit16u io_base, permission16;
if (BX_CPU_THIS_PTR tr.cache.valid==0 ||
BX_CPU_THIS_PTR tr.cache.type != BX_SYS_SEGMENT_AVAIL_386_TSS)
/* If CPL <= IOPL, then all IO addresses 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())))
{
BX_ERROR(("allow_io(): TR doesn't point to a valid 32bit TSS"));
return(0);
}
if (BX_CPU_THIS_PTR tr.cache.valid==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) {
BX_ERROR(("allow_io(): TR.limit < 103"));
return(0);
}
if (BX_CPU_THIS_PTR tr.cache.u.system.limit_scaled < 103) {
BX_ERROR(("allow_io(): TR.limit < 103"));
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);
if (io_base <= 103) {
BX_ERROR(("allow_io(): TR:io_base (%u) <= 103", io_base));
return(0);
}
if (io_base <= 103) {
BX_ERROR(("allow_io(): TR:io_base (%u) <= 103", io_base));
return(0);
}
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)",
addr, len, io_base, BX_CPU_THIS_PTR tr.cache.u.system.limit_scaled));
return(0);
}
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)",
addr, len, io_base, BX_CPU_THIS_PTR tr.cache.u.system.limit_scaled));
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);
unsigned bit_index = addr & 0x07;
permission16 >>= bit_index;
for (unsigned i=0; i<len; i++) {
if (permission16 & 0x01)
return(0);
permission16 >>= 1;
unsigned bit_index = addr & 0x07;
permission16 >>= bit_index;
for (unsigned i=0; i<len; i++) {
if (permission16 & 0x01)
return(0);
permission16 >>= 1;
}
}
return(1);