2001-10-03 17:10:38 +04:00
|
|
|
/////////////////////////////////////////////////////////////////////////
|
2007-12-21 13:33:39 +03:00
|
|
|
// $Id: access.cc,v 1.86 2007-12-21 10:33:39 sshwarts Exp $
|
2001-10-03 17:10:38 +04:00
|
|
|
/////////////////////////////////////////////////////////////////////////
|
|
|
|
//
|
2001-04-10 06:20:02 +04:00
|
|
|
// Copyright (C) 2001 MandrakeSoft S.A.
|
2001-04-10 05:04:59 +04:00
|
|
|
//
|
|
|
|
// MandrakeSoft S.A.
|
|
|
|
// 43, rue d'Aboukir
|
|
|
|
// 75002 Paris - France
|
|
|
|
// http://www.linux-mandrake.com/
|
|
|
|
// http://www.mandrakesoft.com/
|
|
|
|
//
|
|
|
|
// 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
2007-10-11 01:48:46 +04:00
|
|
|
//
|
|
|
|
/////////////////////////////////////////////////////////////////////////
|
2001-04-10 05:04:59 +04:00
|
|
|
|
2001-05-24 22:46:34 +04:00
|
|
|
#define NEED_CPU_REG_SHORTCUTS 1
|
2001-04-10 05:04:59 +04:00
|
|
|
#include "bochs.h"
|
2006-03-07 01:03:16 +03:00
|
|
|
#include "cpu.h"
|
merge in BRANCH-io-cleanup.
To see the commit logs for this use either cvsweb or
cvs update -r BRANCH-io-cleanup and then 'cvs log' the various files.
In general this provides a generic interface for logging.
logfunctions:: is a class that is inherited by some classes, and also
. allocated as a standalone global called 'genlog'. All logging uses
. one of the ::info(), ::error(), ::ldebug(), ::panic() methods of this
. class through 'BX_INFO(), BX_ERROR(), BX_DEBUG(), BX_PANIC()' macros
. respectively.
.
. An example usage:
. BX_INFO(("Hello, World!\n"));
iofunctions:: is a class that is allocated once by default, and assigned
as the iofunction of each logfunctions instance. It is this class that
maintains the file descriptor and other output related code, at this
point using vfprintf(). At some future point, someone may choose to
write a gui 'console' for bochs to which messages would be redirected
simply by assigning a different iofunction class to the various logfunctions
objects.
More cleanup is coming, but this works for now. If you want to see alot
of debugging output, in main.cc, change onoff[LOGLEV_DEBUG]=0 to =1.
Comments, bugs, flames, to me: todd@fries.net
2001-05-15 18:49:57 +04:00
|
|
|
#define LOG_THIS BX_CPU_THIS_PTR
|
2001-04-10 05:04:59 +04:00
|
|
|
|
2003-03-03 02:59:12 +03:00
|
|
|
void BX_CPP_AttrRegparmN(3)
|
2007-10-19 14:14:33 +04:00
|
|
|
BX_CPU_C::write_virtual_checks(bx_segment_reg_t *seg, bx_address offset, unsigned length)
|
2001-04-10 05:04:59 +04:00
|
|
|
{
|
|
|
|
Bit32u upper_limit;
|
|
|
|
|
2002-09-13 08:33:42 +04:00
|
|
|
#if BX_SUPPORT_X86_64
|
|
|
|
if (BX_CPU_THIS_PTR cpu_mode == BX_MODE_LONG_64) {
|
2003-03-13 03:37:40 +03:00
|
|
|
// do canonical checks
|
|
|
|
if (!IsCanonical(offset)) {
|
2007-10-11 01:48:46 +04:00
|
|
|
BX_ERROR(("write_virtual_checks(): canonical failure 0x%08x:%08x", GET32H(offset), GET32L(offset)));
|
2007-07-15 23:03:39 +04:00
|
|
|
exception(int_number(seg), 0, 0);
|
2005-01-25 23:41:43 +03:00
|
|
|
}
|
2007-10-11 02:00:51 +04:00
|
|
|
// Mark cache as being OK type for succeeding reads/writes
|
2007-12-10 22:08:13 +03:00
|
|
|
seg->cache.valid |= SegAccessROK | SegAccessWOK | SegAccess4G;
|
2002-09-13 08:33:42 +04:00
|
|
|
return;
|
2005-01-25 23:41:43 +03:00
|
|
|
}
|
2002-09-13 08:33:42 +04:00
|
|
|
#endif
|
2003-10-24 22:34:16 +04:00
|
|
|
if (protected_mode()) {
|
|
|
|
if (seg->cache.valid==0) {
|
2006-06-10 02:29:07 +04:00
|
|
|
BX_DEBUG(("write_virtual_checks(): segment descriptor not valid"));
|
2007-08-01 00:25:52 +04:00
|
|
|
exception(int_number(seg), 0, 0);
|
2005-01-25 23:41:43 +03:00
|
|
|
}
|
2001-04-10 05:04:59 +04:00
|
|
|
|
|
|
|
if (seg->cache.p == 0) { /* not present */
|
2006-02-27 00:44:03 +03:00
|
|
|
BX_ERROR(("write_virtual_checks(): segment not present"));
|
2001-04-10 05:04:59 +04:00
|
|
|
exception(int_number(seg), 0, 0);
|
2005-01-25 23:41:43 +03:00
|
|
|
}
|
|
|
|
|
2003-10-24 22:34:16 +04:00
|
|
|
switch (seg->cache.type) {
|
2001-04-10 05:04:59 +04:00
|
|
|
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
|
2006-02-27 00:44:03 +03:00
|
|
|
BX_ERROR(("write_virtual_checks(): no write access to seg"));
|
2007-08-01 00:25:52 +04:00
|
|
|
exception(int_number(seg), 0, 0);
|
2001-04-10 05:04:59 +04:00
|
|
|
|
|
|
|
case 2: case 3: /* read/write */
|
2002-09-13 08:33:42 +04:00
|
|
|
if (offset > (seg->cache.u.segment.limit_scaled - length + 1)
|
2005-01-25 23:41:43 +03:00
|
|
|
|| (length-1 > seg->cache.u.segment.limit_scaled))
|
|
|
|
{
|
2006-02-27 00:44:03 +03:00
|
|
|
BX_ERROR(("write_virtual_checks(): write beyond limit, r/w"));
|
2001-04-10 05:04:59 +04:00
|
|
|
exception(int_number(seg), 0, 0);
|
2005-01-25 23:41:43 +03:00
|
|
|
}
|
2002-09-05 00:23:54 +04:00
|
|
|
if (seg->cache.u.segment.limit_scaled >= 7) {
|
2007-10-11 02:00:51 +04:00
|
|
|
// Mark cache as being OK type for succeeding read/writes. The limit
|
|
|
|
// checks still needs to be done though, but is more simple. We
|
Integrated patches for:
- Paging code rehash. You must now use --enable-4meg-pages to
use 4Meg pages, with the default of disabled, since we don't well
support 4Meg pages yet. Paging table walks model a real CPU
more closely now, and I fixed some bugs in the old logic.
- Segment check redundancy elimination. After a segment is loaded,
reads and writes are marked when a segment type check succeeds, and
they are skipped thereafter, when possible.
- Repeated IO and memory string copy acceleration. Only some variants
of instructions are available on all platforms, word and dword
variants only on x86 for the moment due to alignment and endian issues.
This is compiled in currently with no option - I should add a configure
option.
- Added a guest linear address to host TLB. Actually, I just stick
the host address (mem.vector[addr] address) in the upper 29 bits
of the field 'combined_access' since they are unused. Convenient
for now. I'm only storing page frame addresses. This was the
simplest for of such a TLB. We can likely enhance this. Also,
I only accelerated the normal read/write routines in access.cc.
Could also modify the read-modify-write versions too. You must
use --enable-guest2host-tlb, to try this out. Currently speeds
up Win95 boot time by about 3.5% for me. More ground to cover...
- Minor mods to CPUI/MOV_CdRd for CMOV.
- Integrated enhancements from Volker to getHostMemAddr() for PCI
being enabled.
2002-09-02 00:12:09 +04:00
|
|
|
// could probably also optimize that out with a flag for the case
|
2007-10-11 02:00:51 +04:00
|
|
|
// when limit is the maximum 32bit value. Limit should accomodate
|
Integrated patches for:
- Paging code rehash. You must now use --enable-4meg-pages to
use 4Meg pages, with the default of disabled, since we don't well
support 4Meg pages yet. Paging table walks model a real CPU
more closely now, and I fixed some bugs in the old logic.
- Segment check redundancy elimination. After a segment is loaded,
reads and writes are marked when a segment type check succeeds, and
they are skipped thereafter, when possible.
- Repeated IO and memory string copy acceleration. Only some variants
of instructions are available on all platforms, word and dword
variants only on x86 for the moment due to alignment and endian issues.
This is compiled in currently with no option - I should add a configure
option.
- Added a guest linear address to host TLB. Actually, I just stick
the host address (mem.vector[addr] address) in the upper 29 bits
of the field 'combined_access' since they are unused. Convenient
for now. I'm only storing page frame addresses. This was the
simplest for of such a TLB. We can likely enhance this. Also,
I only accelerated the normal read/write routines in access.cc.
Could also modify the read-modify-write versions too. You must
use --enable-guest2host-tlb, to try this out. Currently speeds
up Win95 boot time by about 3.5% for me. More ground to cover...
- Minor mods to CPUI/MOV_CdRd for CMOV.
- Integrated enhancements from Volker to getHostMemAddr() for PCI
being enabled.
2002-09-02 00:12:09 +04:00
|
|
|
// 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.
|
2007-10-11 02:00:51 +04:00
|
|
|
seg->cache.valid |= SegAccessROK | SegAccessWOK;
|
2007-12-10 22:08:13 +03:00
|
|
|
|
|
|
|
if (seg->cache.u.segment.limit_scaled == 0xffffffff)
|
|
|
|
seg->cache.valid |= SegAccess4G;
|
2005-01-25 23:41:43 +03:00
|
|
|
}
|
2001-04-10 05:04:59 +04:00
|
|
|
break;
|
|
|
|
|
2007-04-10 01:55:07 +04:00
|
|
|
case 6: case 7: /* read/write, expand down */
|
2001-04-10 05:04:59 +04:00
|
|
|
if (seg->cache.u.segment.d_b)
|
|
|
|
upper_limit = 0xffffffff;
|
|
|
|
else
|
|
|
|
upper_limit = 0x0000ffff;
|
2003-10-24 22:34:16 +04:00
|
|
|
if ((offset <= seg->cache.u.segment.limit_scaled) ||
|
2007-04-10 01:55:07 +04:00
|
|
|
(offset > upper_limit) || ((upper_limit - offset) < (length - 1)))
|
2005-01-25 23:41:43 +03:00
|
|
|
{
|
2006-02-27 00:44:03 +03:00
|
|
|
BX_ERROR(("write_virtual_checks(): write beyond limit, r/w ED"));
|
2001-04-10 05:04:59 +04:00
|
|
|
exception(int_number(seg), 0, 0);
|
2005-01-25 23:41:43 +03:00
|
|
|
}
|
2001-04-10 05:04:59 +04:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2005-01-25 23:41:43 +03:00
|
|
|
return;
|
|
|
|
}
|
2001-04-10 05:04:59 +04:00
|
|
|
else { /* real mode */
|
2005-01-25 23:41:43 +03:00
|
|
|
if (offset > (seg->cache.u.segment.limit_scaled - length + 1)
|
|
|
|
|| (length-1 > seg->cache.u.segment.limit_scaled))
|
|
|
|
{
|
2006-06-10 02:29:07 +04:00
|
|
|
BX_DEBUG(("write_virtual_checks(): write beyond limit (real mode)"));
|
2005-11-19 22:38:45 +03:00
|
|
|
exception(int_number(seg), 0, 0);
|
2005-01-25 23:41:43 +03:00
|
|
|
}
|
2002-09-05 00:23:54 +04:00
|
|
|
if (seg->cache.u.segment.limit_scaled >= 7) {
|
2007-10-11 02:00:51 +04:00
|
|
|
// Mark cache as being OK type for succeeding reads/writes.
|
|
|
|
// See notes above.
|
|
|
|
seg->cache.valid |= SegAccessROK | SegAccessWOK;
|
2007-12-10 22:08:13 +03:00
|
|
|
|
|
|
|
if (seg->cache.u.segment.limit_scaled == 0xffffffff)
|
|
|
|
seg->cache.valid |= SegAccess4G;
|
2001-04-10 05:04:59 +04:00
|
|
|
}
|
2005-01-25 23:41:43 +03:00
|
|
|
}
|
2001-04-10 05:04:59 +04:00
|
|
|
}
|
|
|
|
|
2003-03-03 02:59:12 +03:00
|
|
|
void BX_CPP_AttrRegparmN(3)
|
2007-10-19 14:14:33 +04:00
|
|
|
BX_CPU_C::read_virtual_checks(bx_segment_reg_t *seg, bx_address offset, unsigned length)
|
2001-04-10 05:04:59 +04:00
|
|
|
{
|
|
|
|
Bit32u upper_limit;
|
|
|
|
|
2002-09-13 08:33:42 +04:00
|
|
|
#if BX_SUPPORT_X86_64
|
|
|
|
if (BX_CPU_THIS_PTR cpu_mode == BX_MODE_LONG_64) {
|
2003-03-13 03:37:40 +03:00
|
|
|
// do canonical checks
|
|
|
|
if (!IsCanonical(offset)) {
|
2007-10-11 01:48:46 +04:00
|
|
|
BX_ERROR(("read_virtual_checks(): canonical failure 0x%08x:%08x", GET32H(offset), GET32L(offset)));
|
2007-07-15 23:03:39 +04:00
|
|
|
exception(int_number(seg), 0, 0);
|
2005-01-25 23:41:43 +03:00
|
|
|
}
|
2007-10-11 02:00:51 +04:00
|
|
|
// Mark cache as being OK type for succeeding reads/writes
|
2007-12-10 22:08:13 +03:00
|
|
|
seg->cache.valid |= SegAccessROK | SegAccessWOK | SegAccess4G;
|
2002-09-13 08:33:42 +04:00
|
|
|
return;
|
2005-01-25 23:41:43 +03:00
|
|
|
}
|
2002-09-13 08:33:42 +04:00
|
|
|
#endif
|
2003-10-24 22:34:16 +04:00
|
|
|
if (protected_mode()) {
|
|
|
|
if (seg->cache.valid==0) {
|
2006-06-10 02:29:07 +04:00
|
|
|
BX_DEBUG(("read_virtual_checks(): segment descriptor not valid"));
|
2007-08-01 00:25:52 +04:00
|
|
|
exception(int_number(seg), 0, 0);
|
2005-01-25 23:41:43 +03:00
|
|
|
}
|
2001-04-10 05:04:59 +04:00
|
|
|
|
|
|
|
if (seg->cache.p == 0) { /* not present */
|
2006-02-27 00:44:03 +03:00
|
|
|
BX_ERROR(("read_virtual_checks(): segment not present"));
|
2001-04-10 05:04:59 +04:00
|
|
|
exception(int_number(seg), 0, 0);
|
2005-01-25 23:41:43 +03:00
|
|
|
}
|
2001-04-10 05:04:59 +04:00
|
|
|
|
2003-10-24 22:34:16 +04:00
|
|
|
switch (seg->cache.type) {
|
2001-04-10 05:04:59 +04:00
|
|
|
case 0: case 1: /* read only */
|
2007-04-10 01:55:07 +04:00
|
|
|
case 2: case 3: /* read/write */
|
2001-04-10 05:04:59 +04:00
|
|
|
case 10: case 11: /* execute/read */
|
|
|
|
case 14: case 15: /* execute/read-only, conforming */
|
2002-09-13 08:33:42 +04:00
|
|
|
if (offset > (seg->cache.u.segment.limit_scaled - length + 1)
|
2005-01-25 23:41:43 +03:00
|
|
|
|| (length-1 > seg->cache.u.segment.limit_scaled))
|
|
|
|
{
|
2006-02-27 00:44:03 +03:00
|
|
|
BX_ERROR(("read_virtual_checks(): read beyond limit"));
|
2001-04-10 05:04:59 +04:00
|
|
|
exception(int_number(seg), 0, 0);
|
2005-01-25 23:41:43 +03:00
|
|
|
}
|
2002-09-05 00:23:54 +04:00
|
|
|
if (seg->cache.u.segment.limit_scaled >= 7) {
|
2005-03-30 23:56:02 +04:00
|
|
|
// Mark cache as being OK type for succeeding reads. See notes for
|
Integrated patches for:
- Paging code rehash. You must now use --enable-4meg-pages to
use 4Meg pages, with the default of disabled, since we don't well
support 4Meg pages yet. Paging table walks model a real CPU
more closely now, and I fixed some bugs in the old logic.
- Segment check redundancy elimination. After a segment is loaded,
reads and writes are marked when a segment type check succeeds, and
they are skipped thereafter, when possible.
- Repeated IO and memory string copy acceleration. Only some variants
of instructions are available on all platforms, word and dword
variants only on x86 for the moment due to alignment and endian issues.
This is compiled in currently with no option - I should add a configure
option.
- Added a guest linear address to host TLB. Actually, I just stick
the host address (mem.vector[addr] address) in the upper 29 bits
of the field 'combined_access' since they are unused. Convenient
for now. I'm only storing page frame addresses. This was the
simplest for of such a TLB. We can likely enhance this. Also,
I only accelerated the normal read/write routines in access.cc.
Could also modify the read-modify-write versions too. You must
use --enable-guest2host-tlb, to try this out. Currently speeds
up Win95 boot time by about 3.5% for me. More ground to cover...
- Minor mods to CPUI/MOV_CdRd for CMOV.
- Integrated enhancements from Volker to getHostMemAddr() for PCI
being enabled.
2002-09-02 00:12:09 +04:00
|
|
|
// write checks; similar code.
|
|
|
|
seg->cache.valid |= SegAccessROK;
|
2007-12-10 22:08:13 +03:00
|
|
|
if (seg->cache.u.segment.limit_scaled == 0xffffffff)
|
|
|
|
seg->cache.valid |= SegAccess4G;
|
2005-01-25 23:41:43 +03:00
|
|
|
}
|
2001-04-10 05:04:59 +04:00
|
|
|
break;
|
|
|
|
|
|
|
|
case 4: case 5: /* read only, expand down */
|
2007-04-10 01:55:07 +04:00
|
|
|
case 6: case 7: /* read/write, expand down */
|
2001-04-10 05:04:59 +04:00
|
|
|
if (seg->cache.u.segment.d_b)
|
|
|
|
upper_limit = 0xffffffff;
|
|
|
|
else
|
|
|
|
upper_limit = 0x0000ffff;
|
2003-10-24 22:34:16 +04:00
|
|
|
if ((offset <= seg->cache.u.segment.limit_scaled) ||
|
2005-01-25 23:41:43 +03:00
|
|
|
(offset > upper_limit) || ((upper_limit - offset) < (length - 1)))
|
|
|
|
{
|
2007-10-11 02:00:51 +04:00
|
|
|
BX_ERROR(("read_virtual_checks(): read beyond limit ED"));
|
2001-04-10 05:04:59 +04:00
|
|
|
exception(int_number(seg), 0, 0);
|
2005-01-25 23:41:43 +03:00
|
|
|
}
|
2001-04-10 05:04:59 +04:00
|
|
|
break;
|
|
|
|
|
|
|
|
case 8: case 9: /* execute only */
|
|
|
|
case 12: case 13: /* execute only, conforming */
|
|
|
|
/* can't read or write an execute-only segment */
|
2006-02-27 00:44:03 +03:00
|
|
|
BX_ERROR(("read_virtual_checks(): execute only"));
|
2007-08-01 00:25:52 +04:00
|
|
|
exception(int_number(seg), 0, 0);
|
2001-04-10 05:04:59 +04:00
|
|
|
}
|
2005-01-25 23:41:43 +03:00
|
|
|
return;
|
|
|
|
}
|
2001-04-10 05:04:59 +04:00
|
|
|
else { /* real mode */
|
2002-09-13 08:33:42 +04:00
|
|
|
if (offset > (seg->cache.u.segment.limit_scaled - length + 1)
|
2005-01-25 23:41:43 +03:00
|
|
|
|| (length-1 > seg->cache.u.segment.limit_scaled))
|
|
|
|
{
|
2006-06-10 02:29:07 +04:00
|
|
|
BX_DEBUG(("read_virtual_checks(): read beyond limit (real mode)"));
|
2005-11-19 22:38:45 +03:00
|
|
|
exception(int_number(seg), 0, 0);
|
2007-10-11 01:48:46 +04:00
|
|
|
}
|
|
|
|
if (seg->cache.u.segment.limit_scaled >= 7) {
|
2007-10-11 02:00:51 +04:00
|
|
|
// Mark cache as being OK type for succeeding reads/writes. See notes for
|
2007-10-11 01:48:46 +04:00
|
|
|
// write checks; similar code.
|
2007-10-11 02:00:51 +04:00
|
|
|
seg->cache.valid |= SegAccessROK | SegAccessWOK;
|
2007-12-10 22:08:13 +03:00
|
|
|
|
|
|
|
if (seg->cache.u.segment.limit_scaled == 0xffffffff)
|
|
|
|
seg->cache.valid |= SegAccess4G;
|
2007-10-11 01:48:46 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void BX_CPP_AttrRegparmN(3)
|
2007-10-19 14:14:33 +04:00
|
|
|
BX_CPU_C::execute_virtual_checks(bx_segment_reg_t *seg, bx_address offset, unsigned length)
|
2007-10-11 01:48:46 +04:00
|
|
|
{
|
|
|
|
Bit32u upper_limit;
|
|
|
|
|
|
|
|
#if BX_SUPPORT_X86_64
|
|
|
|
if (BX_CPU_THIS_PTR cpu_mode == BX_MODE_LONG_64) {
|
|
|
|
// do canonical checks
|
|
|
|
if (!IsCanonical(offset)) {
|
|
|
|
BX_ERROR(("execute_virtual_checks(): canonical failure 0x%08x:%08x", GET32H(offset), GET32L(offset)));
|
|
|
|
exception(int_number(seg), 0, 0);
|
|
|
|
}
|
2007-10-11 02:00:51 +04:00
|
|
|
// Mark cache as being OK type for succeeding reads/writes
|
2007-12-10 22:08:13 +03:00
|
|
|
seg->cache.valid |= SegAccessROK | SegAccessWOK | SegAccess4G;
|
2007-10-11 01:48:46 +04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
if (protected_mode()) {
|
|
|
|
if (seg->cache.valid==0) {
|
|
|
|
BX_DEBUG(("execute_virtual_checks(): segment descriptor not valid"));
|
|
|
|
exception(int_number(seg), 0, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (seg->cache.p == 0) { /* not present */
|
|
|
|
BX_ERROR(("execute_virtual_checks(): segment not present"));
|
|
|
|
exception(int_number(seg), 0, 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"));
|
|
|
|
exception(int_number(seg), 0, 0);
|
|
|
|
}
|
|
|
|
if (seg->cache.u.segment.limit_scaled >= 7) {
|
|
|
|
// Mark cache as being OK type for succeeding reads. See notes for
|
|
|
|
// write checks; similar code.
|
|
|
|
seg->cache.valid |= SegAccessROK;
|
2007-12-10 22:08:13 +03:00
|
|
|
if (seg->cache.u.segment.limit_scaled == 0xffffffff)
|
|
|
|
seg->cache.valid |= SegAccess4G;
|
2007-10-11 01:48:46 +04:00
|
|
|
}
|
|
|
|
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))
|
|
|
|
{
|
2007-10-11 02:00:51 +04:00
|
|
|
BX_ERROR(("execute_virtual_checks(): read beyond limit execute only"));
|
2007-10-11 01:48:46 +04:00
|
|
|
exception(int_number(seg), 0, 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)))
|
|
|
|
{
|
2007-10-19 14:14:33 +04:00
|
|
|
BX_ERROR(("execute_virtual_checks(): read beyond limit ED"));
|
2007-10-11 01:48:46 +04:00
|
|
|
exception(int_number(seg), 0, 0);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
else { /* real mode */
|
|
|
|
if (offset > (seg->cache.u.segment.limit_scaled - length + 1)
|
|
|
|
|| (length-1 > seg->cache.u.segment.limit_scaled))
|
|
|
|
{
|
|
|
|
BX_DEBUG(("execute_virtual_checks(): read beyond limit (real mode)"));
|
|
|
|
exception(int_number(seg), 0, 0);
|
2005-01-25 23:41:43 +03:00
|
|
|
}
|
2002-09-05 00:23:54 +04:00
|
|
|
if (seg->cache.u.segment.limit_scaled >= 7) {
|
2007-10-11 02:00:51 +04:00
|
|
|
// Mark cache as being OK type for succeeding reads/writes. See notes for
|
Integrated patches for:
- Paging code rehash. You must now use --enable-4meg-pages to
use 4Meg pages, with the default of disabled, since we don't well
support 4Meg pages yet. Paging table walks model a real CPU
more closely now, and I fixed some bugs in the old logic.
- Segment check redundancy elimination. After a segment is loaded,
reads and writes are marked when a segment type check succeeds, and
they are skipped thereafter, when possible.
- Repeated IO and memory string copy acceleration. Only some variants
of instructions are available on all platforms, word and dword
variants only on x86 for the moment due to alignment and endian issues.
This is compiled in currently with no option - I should add a configure
option.
- Added a guest linear address to host TLB. Actually, I just stick
the host address (mem.vector[addr] address) in the upper 29 bits
of the field 'combined_access' since they are unused. Convenient
for now. I'm only storing page frame addresses. This was the
simplest for of such a TLB. We can likely enhance this. Also,
I only accelerated the normal read/write routines in access.cc.
Could also modify the read-modify-write versions too. You must
use --enable-guest2host-tlb, to try this out. Currently speeds
up Win95 boot time by about 3.5% for me. More ground to cover...
- Minor mods to CPUI/MOV_CdRd for CMOV.
- Integrated enhancements from Volker to getHostMemAddr() for PCI
being enabled.
2002-09-02 00:12:09 +04:00
|
|
|
// write checks; similar code.
|
2007-10-11 02:00:51 +04:00
|
|
|
seg->cache.valid |= SegAccessROK | SegAccessWOK;
|
2007-12-10 22:08:13 +03:00
|
|
|
|
|
|
|
if (seg->cache.u.segment.limit_scaled == 0xffffffff)
|
|
|
|
seg->cache.valid |= SegAccess4G;
|
2001-04-10 05:04:59 +04:00
|
|
|
}
|
2005-01-25 23:41:43 +03:00
|
|
|
}
|
2001-04-10 05:04:59 +04:00
|
|
|
}
|
|
|
|
|
2007-10-25 03:02:09 +04:00
|
|
|
const char * BX_CPP_AttrRegparmN(1)
|
2001-04-10 05:04:59 +04:00
|
|
|
BX_CPU_C::strseg(bx_segment_reg_t *seg)
|
|
|
|
{
|
|
|
|
if (seg == &BX_CPU_THIS_PTR sregs[0]) return("ES");
|
2006-02-22 23:58:16 +03:00
|
|
|
else if (seg == &BX_CPU_THIS_PTR sregs[1]) return("CS");
|
|
|
|
else if (seg == &BX_CPU_THIS_PTR sregs[2]) return("SS");
|
2001-04-10 05:04:59 +04:00
|
|
|
else if (seg == &BX_CPU_THIS_PTR sregs[3]) return("DS");
|
|
|
|
else if (seg == &BX_CPU_THIS_PTR sregs[4]) return("FS");
|
|
|
|
else if (seg == &BX_CPU_THIS_PTR sregs[5]) return("GS");
|
|
|
|
else {
|
2006-02-27 00:44:03 +03:00
|
|
|
BX_PANIC(("undefined segment passed to strseg()!"));
|
2001-04-10 05:04:59 +04:00
|
|
|
return("??");
|
2005-01-25 23:41:43 +03:00
|
|
|
}
|
2001-04-10 05:04:59 +04:00
|
|
|
}
|
|
|
|
|
2005-03-03 23:24:52 +03:00
|
|
|
int BX_CPU_C::int_number(bx_segment_reg_t *seg)
|
|
|
|
{
|
2007-10-19 14:14:33 +04:00
|
|
|
if (seg == &BX_CPU_THIS_PTR sregs[0]) return BX_GP_EXCEPTION;
|
|
|
|
if (seg == &BX_CPU_THIS_PTR sregs[1]) return BX_GP_EXCEPTION;
|
|
|
|
if (seg == &BX_CPU_THIS_PTR sregs[2]) return BX_SS_EXCEPTION;
|
|
|
|
if (seg == &BX_CPU_THIS_PTR sregs[3]) return BX_GP_EXCEPTION;
|
|
|
|
if (seg == &BX_CPU_THIS_PTR sregs[4]) return BX_GP_EXCEPTION;
|
|
|
|
if (seg == &BX_CPU_THIS_PTR sregs[5]) return BX_GP_EXCEPTION;
|
|
|
|
|
|
|
|
// imdefined segment, this must be new stack segment
|
|
|
|
return BX_SS_EXCEPTION;
|
2005-03-03 23:24:52 +03:00
|
|
|
}
|
|
|
|
|
2005-08-24 00:01:54 +04:00
|
|
|
#if BX_SupportGuest2HostTLB
|
|
|
|
Bit8u* BX_CPP_AttrRegparmN(2)
|
2007-12-17 00:03:46 +03:00
|
|
|
BX_CPU_C::v2h_read_byte(bx_address laddr, unsigned curr_pl)
|
2005-08-24 00:01:54 +04:00
|
|
|
{
|
2007-12-21 13:33:39 +03:00
|
|
|
Bit32u tlbIndex = BX_TLB_INDEX_OF(laddr, 0);
|
2005-08-24 00:01:54 +04:00
|
|
|
bx_address lpf = LPFOf(laddr);
|
|
|
|
bx_TLB_entry *tlbEntry = &BX_CPU_THIS_PTR TLB.entry[tlbIndex];
|
2007-11-11 23:44:07 +03:00
|
|
|
if (tlbEntry->lpf == lpf) {
|
2005-08-24 00:01:54 +04:00
|
|
|
// See if the TLB entry privilege level allows us read access
|
|
|
|
// from this CPL.
|
2007-12-17 00:03:46 +03:00
|
|
|
if (tlbEntry->accessBits & (1<<curr_pl)) { // Read this pl OK.
|
2005-08-24 00:01:54 +04:00
|
|
|
bx_hostpageaddr_t hostPageAddr = tlbEntry->hostPageAddr;
|
|
|
|
Bit32u pageOffset = laddr & 0xfff;
|
|
|
|
Bit8u *hostAddr = (Bit8u*) (hostPageAddr | pageOffset);
|
|
|
|
return hostAddr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
Bit8u* BX_CPP_AttrRegparmN(2)
|
2007-12-17 00:03:46 +03:00
|
|
|
BX_CPU_C::v2h_write_byte(bx_address laddr, unsigned curr_pl)
|
2005-08-24 00:01:54 +04:00
|
|
|
{
|
2007-12-21 13:33:39 +03:00
|
|
|
Bit32u tlbIndex = BX_TLB_INDEX_OF(laddr, 0);
|
2005-08-24 00:01:54 +04:00
|
|
|
bx_address lpf = LPFOf(laddr);
|
|
|
|
bx_TLB_entry *tlbEntry = &BX_CPU_THIS_PTR TLB.entry[tlbIndex];
|
2007-11-11 23:44:07 +03:00
|
|
|
if (tlbEntry->lpf == lpf)
|
2005-08-24 00:01:54 +04:00
|
|
|
{
|
|
|
|
// See if the TLB entry privilege level allows us write access
|
|
|
|
// from this CPL.
|
2007-12-17 00:03:46 +03:00
|
|
|
if (tlbEntry->accessBits & (0x10 << curr_pl)) {
|
2005-08-24 00:01:54 +04:00
|
|
|
bx_hostpageaddr_t hostPageAddr = tlbEntry->hostPageAddr;
|
|
|
|
Bit32u pageOffset = laddr & 0xfff;
|
|
|
|
Bit8u *hostAddr = (Bit8u*) (hostPageAddr | pageOffset);
|
|
|
|
#if BX_SUPPORT_ICACHE
|
|
|
|
pageWriteStampTable.decWriteStamp(tlbEntry->ppf);
|
|
|
|
#endif
|
|
|
|
return hostAddr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2007-12-21 13:33:39 +03:00
|
|
|
Bit8u* BX_CPP_AttrRegparmN(3)
|
|
|
|
BX_CPU_C::v2h_read(bx_address laddr, unsigned curr_pl, unsigned len)
|
2005-08-24 00:01:54 +04:00
|
|
|
{
|
2007-12-21 13:33:39 +03:00
|
|
|
// Make sure access does not span 2 pages.
|
|
|
|
Bit32u tlbIndex = BX_TLB_INDEX_OF(laddr, len);
|
|
|
|
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 & (1<<curr_pl)) { // Read this pl OK.
|
|
|
|
bx_hostpageaddr_t hostPageAddr = tlbEntry->hostPageAddr;
|
|
|
|
Bit32u pageOffset = laddr & 0xfff;
|
|
|
|
Bit8u *hostAddr = (Bit8u*) (hostPageAddr | pageOffset);
|
|
|
|
return hostAddr;
|
2005-08-24 00:01:54 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2007-12-21 13:33:39 +03:00
|
|
|
Bit8u* BX_CPP_AttrRegparmN(3)
|
|
|
|
BX_CPU_C::v2h_write(bx_address laddr, unsigned curr_pl, unsigned len)
|
2005-08-24 00:01:54 +04:00
|
|
|
{
|
2007-12-21 13:33:39 +03:00
|
|
|
// Make sure access does not span 2 pages.
|
|
|
|
Bit32u tlbIndex = BX_TLB_INDEX_OF(laddr, len);
|
|
|
|
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 & (0x10 << curr_pl)) {
|
|
|
|
bx_hostpageaddr_t hostPageAddr = tlbEntry->hostPageAddr;
|
|
|
|
Bit32u pageOffset = laddr & 0xfff;
|
|
|
|
Bit8u *hostAddr = (Bit8u*) (hostPageAddr | pageOffset);
|
2005-08-24 00:01:54 +04:00
|
|
|
#if BX_SUPPORT_ICACHE
|
2007-12-21 13:33:39 +03:00
|
|
|
pageWriteStampTable.decWriteStamp(tlbEntry->ppf);
|
2005-08-24 00:01:54 +04:00
|
|
|
#endif
|
2007-12-21 13:33:39 +03:00
|
|
|
return hostAddr;
|
2005-08-24 00:01:54 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
#endif // BX_SupportGuest2HostTLB
|
|
|
|
|
2003-03-03 02:59:12 +03:00
|
|
|
void BX_CPP_AttrRegparmN(3)
|
2007-12-20 21:29:42 +03:00
|
|
|
BX_CPU_C::write_virtual_byte(unsigned s, bx_address offset, Bit8u data)
|
2001-04-10 05:04:59 +04:00
|
|
|
{
|
2002-09-13 08:33:42 +04:00
|
|
|
bx_address laddr;
|
2007-12-10 22:08:13 +03:00
|
|
|
bx_segment_reg_t *seg = &BX_CPU_THIS_PTR sregs[s];
|
2001-04-10 05:04:59 +04:00
|
|
|
|
2007-12-10 22:08:13 +03:00
|
|
|
if ((seg->cache.valid & SegAccessWOK4G) == SegAccessWOK4G) {
|
Integrated patches for:
- Paging code rehash. You must now use --enable-4meg-pages to
use 4Meg pages, with the default of disabled, since we don't well
support 4Meg pages yet. Paging table walks model a real CPU
more closely now, and I fixed some bugs in the old logic.
- Segment check redundancy elimination. After a segment is loaded,
reads and writes are marked when a segment type check succeeds, and
they are skipped thereafter, when possible.
- Repeated IO and memory string copy acceleration. Only some variants
of instructions are available on all platforms, word and dword
variants only on x86 for the moment due to alignment and endian issues.
This is compiled in currently with no option - I should add a configure
option.
- Added a guest linear address to host TLB. Actually, I just stick
the host address (mem.vector[addr] address) in the upper 29 bits
of the field 'combined_access' since they are unused. Convenient
for now. I'm only storing page frame addresses. This was the
simplest for of such a TLB. We can likely enhance this. Also,
I only accelerated the normal read/write routines in access.cc.
Could also modify the read-modify-write versions too. You must
use --enable-guest2host-tlb, to try this out. Currently speeds
up Win95 boot time by about 3.5% for me. More ground to cover...
- Minor mods to CPUI/MOV_CdRd for CMOV.
- Integrated enhancements from Volker to getHostMemAddr() for PCI
being enabled.
2002-09-02 00:12:09 +04:00
|
|
|
accessOK:
|
2007-12-10 22:08:13 +03:00
|
|
|
laddr = BX_CPU_THIS_PTR get_segment_base(s) + offset;
|
|
|
|
BX_INSTR_MEM_DATA(BX_CPU_ID, laddr, 1, BX_WRITE);
|
Integrated patches for:
- Paging code rehash. You must now use --enable-4meg-pages to
use 4Meg pages, with the default of disabled, since we don't well
support 4Meg pages yet. Paging table walks model a real CPU
more closely now, and I fixed some bugs in the old logic.
- Segment check redundancy elimination. After a segment is loaded,
reads and writes are marked when a segment type check succeeds, and
they are skipped thereafter, when possible.
- Repeated IO and memory string copy acceleration. Only some variants
of instructions are available on all platforms, word and dword
variants only on x86 for the moment due to alignment and endian issues.
This is compiled in currently with no option - I should add a configure
option.
- Added a guest linear address to host TLB. Actually, I just stick
the host address (mem.vector[addr] address) in the upper 29 bits
of the field 'combined_access' since they are unused. Convenient
for now. I'm only storing page frame addresses. This was the
simplest for of such a TLB. We can likely enhance this. Also,
I only accelerated the normal read/write routines in access.cc.
Could also modify the read-modify-write versions too. You must
use --enable-guest2host-tlb, to try this out. Currently speeds
up Win95 boot time by about 3.5% for me. More ground to cover...
- Minor mods to CPUI/MOV_CdRd for CMOV.
- Integrated enhancements from Volker to getHostMemAddr() for PCI
being enabled.
2002-09-02 00:12:09 +04:00
|
|
|
#if BX_SupportGuest2HostTLB
|
2007-12-21 13:33:39 +03:00
|
|
|
Bit32u tlbIndex = BX_TLB_INDEX_OF(laddr, 0);
|
2007-12-10 22:08:13 +03:00
|
|
|
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.
|
2007-12-17 00:03:46 +03:00
|
|
|
if (tlbEntry->accessBits & (0x10 << CPL)) {
|
2007-12-10 22:08:13 +03:00
|
|
|
bx_hostpageaddr_t hostPageAddr = tlbEntry->hostPageAddr;
|
|
|
|
Bit32u pageOffset = laddr & 0xfff;
|
2007-12-14 00:30:05 +03:00
|
|
|
BX_INSTR_LIN_ACCESS(BX_CPU_ID, laddr, tlbEntry->ppf | pageOffset, 1, BX_WRITE);
|
2007-12-10 22:08:13 +03:00
|
|
|
Bit8u *hostAddr = (Bit8u*) (hostPageAddr | pageOffset);
|
2007-10-17 22:09:42 +04:00
|
|
|
#if BX_SUPPORT_ICACHE
|
2007-12-10 22:08:13 +03:00
|
|
|
pageWriteStampTable.decWriteStamp(tlbEntry->ppf);
|
2007-10-17 22:09:42 +04:00
|
|
|
#endif
|
2007-12-20 21:29:42 +03:00
|
|
|
*hostAddr = data;
|
2007-12-10 22:08:13 +03:00
|
|
|
return;
|
Now, when you compile with --enable-guest2host-tlb, non-paged
mode uses the notion of the guest-to-host TLB. This has the
benefit of allowing more uniform and streamlined acceleration
code in access.cc which does not have to check if CR0.PG
is set, eliminating a few instructions per guest access.
Shaved just a little off execution time, as expected.
Also, access_linear now breaks accesses which span two pages,
into two calls the the physical memory routines, when paging
is off, just like it always has for paging on. Besides
being more uniform, this allows the physical memory access
routines to known the complete data item is contained
within a single physical page, and stop reapplying the
A20ADDR() macro to pointers as it increments them.
Perhaps things can be optimized a little more now there too...
I renamed the routines to {read,write}PhysicalPage() as
a reminder that these routines now operate on data
solely within one page.
I also added a little code so that the paging module is
notified when the A20 line is tweaked, so it can dump
whatever mappings it wants to.
2002-09-05 06:31:24 +04:00
|
|
|
}
|
2007-12-10 22:08:13 +03:00
|
|
|
}
|
2007-11-20 20:15:33 +03:00
|
|
|
#endif
|
|
|
|
#if BX_SUPPORT_X86_64
|
2007-12-10 22:08:13 +03:00
|
|
|
if (! IsCanonical(laddr)) {
|
|
|
|
BX_ERROR(("write_virtual_byte(): canonical failure"));
|
|
|
|
exception(int_number(seg), 0, 0);
|
Integrated patches for:
- Paging code rehash. You must now use --enable-4meg-pages to
use 4Meg pages, with the default of disabled, since we don't well
support 4Meg pages yet. Paging table walks model a real CPU
more closely now, and I fixed some bugs in the old logic.
- Segment check redundancy elimination. After a segment is loaded,
reads and writes are marked when a segment type check succeeds, and
they are skipped thereafter, when possible.
- Repeated IO and memory string copy acceleration. Only some variants
of instructions are available on all platforms, word and dword
variants only on x86 for the moment due to alignment and endian issues.
This is compiled in currently with no option - I should add a configure
option.
- Added a guest linear address to host TLB. Actually, I just stick
the host address (mem.vector[addr] address) in the upper 29 bits
of the field 'combined_access' since they are unused. Convenient
for now. I'm only storing page frame addresses. This was the
simplest for of such a TLB. We can likely enhance this. Also,
I only accelerated the normal read/write routines in access.cc.
Could also modify the read-modify-write versions too. You must
use --enable-guest2host-tlb, to try this out. Currently speeds
up Win95 boot time by about 3.5% for me. More ground to cover...
- Minor mods to CPUI/MOV_CdRd for CMOV.
- Integrated enhancements from Volker to getHostMemAddr() for PCI
being enabled.
2002-09-02 00:12:09 +04:00
|
|
|
}
|
2007-12-10 22:08:13 +03:00
|
|
|
#endif
|
2007-12-20 21:29:42 +03:00
|
|
|
access_linear(laddr, 1, CPL, BX_WRITE, (void *) &data);
|
2007-12-10 22:08:13 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (seg->cache.valid & SegAccessWOK) {
|
|
|
|
if (Is64BitMode() || (offset <= seg->cache.u.segment.limit_scaled))
|
|
|
|
goto accessOK;
|
2004-11-19 02:16:36 +03:00
|
|
|
}
|
Integrated patches for:
- Paging code rehash. You must now use --enable-4meg-pages to
use 4Meg pages, with the default of disabled, since we don't well
support 4Meg pages yet. Paging table walks model a real CPU
more closely now, and I fixed some bugs in the old logic.
- Segment check redundancy elimination. After a segment is loaded,
reads and writes are marked when a segment type check succeeds, and
they are skipped thereafter, when possible.
- Repeated IO and memory string copy acceleration. Only some variants
of instructions are available on all platforms, word and dword
variants only on x86 for the moment due to alignment and endian issues.
This is compiled in currently with no option - I should add a configure
option.
- Added a guest linear address to host TLB. Actually, I just stick
the host address (mem.vector[addr] address) in the upper 29 bits
of the field 'combined_access' since they are unused. Convenient
for now. I'm only storing page frame addresses. This was the
simplest for of such a TLB. We can likely enhance this. Also,
I only accelerated the normal read/write routines in access.cc.
Could also modify the read-modify-write versions too. You must
use --enable-guest2host-tlb, to try this out. Currently speeds
up Win95 boot time by about 3.5% for me. More ground to cover...
- Minor mods to CPUI/MOV_CdRd for CMOV.
- Integrated enhancements from Volker to getHostMemAddr() for PCI
being enabled.
2002-09-02 00:12:09 +04:00
|
|
|
write_virtual_checks(seg, offset, 1);
|
|
|
|
goto accessOK;
|
2001-04-10 05:04:59 +04:00
|
|
|
}
|
|
|
|
|
2003-03-03 02:59:12 +03:00
|
|
|
void BX_CPP_AttrRegparmN(3)
|
2007-12-20 21:29:42 +03:00
|
|
|
BX_CPU_C::write_virtual_word(unsigned s, bx_address offset, Bit16u data)
|
2001-04-10 05:04:59 +04:00
|
|
|
{
|
2002-09-13 08:33:42 +04:00
|
|
|
bx_address laddr;
|
2007-12-10 22:08:13 +03:00
|
|
|
bx_segment_reg_t *seg = &BX_CPU_THIS_PTR sregs[s];
|
2001-04-10 05:04:59 +04:00
|
|
|
|
2007-12-10 22:08:13 +03:00
|
|
|
if ((seg->cache.valid & SegAccessWOK4G) == SegAccessWOK4G) {
|
Integrated patches for:
- Paging code rehash. You must now use --enable-4meg-pages to
use 4Meg pages, with the default of disabled, since we don't well
support 4Meg pages yet. Paging table walks model a real CPU
more closely now, and I fixed some bugs in the old logic.
- Segment check redundancy elimination. After a segment is loaded,
reads and writes are marked when a segment type check succeeds, and
they are skipped thereafter, when possible.
- Repeated IO and memory string copy acceleration. Only some variants
of instructions are available on all platforms, word and dword
variants only on x86 for the moment due to alignment and endian issues.
This is compiled in currently with no option - I should add a configure
option.
- Added a guest linear address to host TLB. Actually, I just stick
the host address (mem.vector[addr] address) in the upper 29 bits
of the field 'combined_access' since they are unused. Convenient
for now. I'm only storing page frame addresses. This was the
simplest for of such a TLB. We can likely enhance this. Also,
I only accelerated the normal read/write routines in access.cc.
Could also modify the read-modify-write versions too. You must
use --enable-guest2host-tlb, to try this out. Currently speeds
up Win95 boot time by about 3.5% for me. More ground to cover...
- Minor mods to CPUI/MOV_CdRd for CMOV.
- Integrated enhancements from Volker to getHostMemAddr() for PCI
being enabled.
2002-09-02 00:12:09 +04:00
|
|
|
accessOK:
|
2007-12-10 22:08:13 +03:00
|
|
|
laddr = BX_CPU_THIS_PTR get_segment_base(s) + offset;
|
|
|
|
BX_INSTR_MEM_DATA(BX_CPU_ID, laddr, 2, BX_WRITE);
|
2007-08-01 00:25:52 +04:00
|
|
|
#if BX_CPU_LEVEL >= 4 && BX_SUPPORT_ALIGNMENT_CHECK
|
2007-12-10 22:08:13 +03:00
|
|
|
if (BX_CPU_THIS_PTR alignment_check) {
|
|
|
|
if (laddr & 1) {
|
|
|
|
BX_ERROR(("write_virtual_word(): #AC misaligned access"));
|
|
|
|
exception(BX_AC_EXCEPTION, 0, 0);
|
2007-08-01 00:25:52 +04:00
|
|
|
}
|
2007-12-10 22:08:13 +03:00
|
|
|
}
|
2007-08-01 00:25:52 +04:00
|
|
|
#endif
|
Integrated patches for:
- Paging code rehash. You must now use --enable-4meg-pages to
use 4Meg pages, with the default of disabled, since we don't well
support 4Meg pages yet. Paging table walks model a real CPU
more closely now, and I fixed some bugs in the old logic.
- Segment check redundancy elimination. After a segment is loaded,
reads and writes are marked when a segment type check succeeds, and
they are skipped thereafter, when possible.
- Repeated IO and memory string copy acceleration. Only some variants
of instructions are available on all platforms, word and dword
variants only on x86 for the moment due to alignment and endian issues.
This is compiled in currently with no option - I should add a configure
option.
- Added a guest linear address to host TLB. Actually, I just stick
the host address (mem.vector[addr] address) in the upper 29 bits
of the field 'combined_access' since they are unused. Convenient
for now. I'm only storing page frame addresses. This was the
simplest for of such a TLB. We can likely enhance this. Also,
I only accelerated the normal read/write routines in access.cc.
Could also modify the read-modify-write versions too. You must
use --enable-guest2host-tlb, to try this out. Currently speeds
up Win95 boot time by about 3.5% for me. More ground to cover...
- Minor mods to CPUI/MOV_CdRd for CMOV.
- Integrated enhancements from Volker to getHostMemAddr() for PCI
being enabled.
2002-09-02 00:12:09 +04:00
|
|
|
#if BX_SupportGuest2HostTLB
|
2007-12-21 13:33:39 +03:00
|
|
|
Bit32u 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) {
|
|
|
|
// See if the TLB entry privilege level allows us write access
|
|
|
|
// from this CPL.
|
|
|
|
if (tlbEntry->accessBits & (0x10 << CPL)) {
|
|
|
|
bx_hostpageaddr_t hostPageAddr = tlbEntry->hostPageAddr;
|
|
|
|
Bit32u pageOffset = laddr & 0xfff;
|
|
|
|
BX_INSTR_LIN_ACCESS(BX_CPU_ID, laddr, tlbEntry->ppf | pageOffset, 2, BX_WRITE);
|
|
|
|
Bit16u *hostAddr = (Bit16u*) (hostPageAddr | pageOffset);
|
2007-10-17 22:09:42 +04:00
|
|
|
#if BX_SUPPORT_ICACHE
|
2007-12-21 13:33:39 +03:00
|
|
|
pageWriteStampTable.decWriteStamp(tlbEntry->ppf);
|
2007-10-17 22:09:42 +04:00
|
|
|
#endif
|
2007-12-21 13:33:39 +03:00
|
|
|
WriteHostWordToLittleEndian(hostAddr, data);
|
|
|
|
return;
|
Now, when you compile with --enable-guest2host-tlb, non-paged
mode uses the notion of the guest-to-host TLB. This has the
benefit of allowing more uniform and streamlined acceleration
code in access.cc which does not have to check if CR0.PG
is set, eliminating a few instructions per guest access.
Shaved just a little off execution time, as expected.
Also, access_linear now breaks accesses which span two pages,
into two calls the the physical memory routines, when paging
is off, just like it always has for paging on. Besides
being more uniform, this allows the physical memory access
routines to known the complete data item is contained
within a single physical page, and stop reapplying the
A20ADDR() macro to pointers as it increments them.
Perhaps things can be optimized a little more now there too...
I renamed the routines to {read,write}PhysicalPage() as
a reminder that these routines now operate on data
solely within one page.
I also added a little code so that the paging module is
notified when the A20 line is tweaked, so it can dump
whatever mappings it wants to.
2002-09-05 06:31:24 +04:00
|
|
|
}
|
2007-12-10 22:08:13 +03:00
|
|
|
}
|
2007-11-20 20:15:33 +03:00
|
|
|
#endif
|
|
|
|
#if BX_SUPPORT_X86_64
|
2007-12-10 22:08:13 +03:00
|
|
|
if (! IsCanonical(laddr)) {
|
|
|
|
BX_ERROR(("write_virtual_word(): canonical failure"));
|
|
|
|
exception(int_number(seg), 0, 0);
|
Integrated patches for:
- Paging code rehash. You must now use --enable-4meg-pages to
use 4Meg pages, with the default of disabled, since we don't well
support 4Meg pages yet. Paging table walks model a real CPU
more closely now, and I fixed some bugs in the old logic.
- Segment check redundancy elimination. After a segment is loaded,
reads and writes are marked when a segment type check succeeds, and
they are skipped thereafter, when possible.
- Repeated IO and memory string copy acceleration. Only some variants
of instructions are available on all platforms, word and dword
variants only on x86 for the moment due to alignment and endian issues.
This is compiled in currently with no option - I should add a configure
option.
- Added a guest linear address to host TLB. Actually, I just stick
the host address (mem.vector[addr] address) in the upper 29 bits
of the field 'combined_access' since they are unused. Convenient
for now. I'm only storing page frame addresses. This was the
simplest for of such a TLB. We can likely enhance this. Also,
I only accelerated the normal read/write routines in access.cc.
Could also modify the read-modify-write versions too. You must
use --enable-guest2host-tlb, to try this out. Currently speeds
up Win95 boot time by about 3.5% for me. More ground to cover...
- Minor mods to CPUI/MOV_CdRd for CMOV.
- Integrated enhancements from Volker to getHostMemAddr() for PCI
being enabled.
2002-09-02 00:12:09 +04:00
|
|
|
}
|
2007-12-10 22:08:13 +03:00
|
|
|
#endif
|
2007-12-20 21:29:42 +03:00
|
|
|
access_linear(laddr, 2, CPL, BX_WRITE, (void *) &data);
|
2007-12-10 22:08:13 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (seg->cache.valid & SegAccessWOK) {
|
|
|
|
if (Is64BitMode() || (offset < seg->cache.u.segment.limit_scaled))
|
|
|
|
goto accessOK;
|
2004-11-19 02:16:36 +03:00
|
|
|
}
|
Integrated patches for:
- Paging code rehash. You must now use --enable-4meg-pages to
use 4Meg pages, with the default of disabled, since we don't well
support 4Meg pages yet. Paging table walks model a real CPU
more closely now, and I fixed some bugs in the old logic.
- Segment check redundancy elimination. After a segment is loaded,
reads and writes are marked when a segment type check succeeds, and
they are skipped thereafter, when possible.
- Repeated IO and memory string copy acceleration. Only some variants
of instructions are available on all platforms, word and dword
variants only on x86 for the moment due to alignment and endian issues.
This is compiled in currently with no option - I should add a configure
option.
- Added a guest linear address to host TLB. Actually, I just stick
the host address (mem.vector[addr] address) in the upper 29 bits
of the field 'combined_access' since they are unused. Convenient
for now. I'm only storing page frame addresses. This was the
simplest for of such a TLB. We can likely enhance this. Also,
I only accelerated the normal read/write routines in access.cc.
Could also modify the read-modify-write versions too. You must
use --enable-guest2host-tlb, to try this out. Currently speeds
up Win95 boot time by about 3.5% for me. More ground to cover...
- Minor mods to CPUI/MOV_CdRd for CMOV.
- Integrated enhancements from Volker to getHostMemAddr() for PCI
being enabled.
2002-09-02 00:12:09 +04:00
|
|
|
write_virtual_checks(seg, offset, 2);
|
|
|
|
goto accessOK;
|
2001-04-10 05:04:59 +04:00
|
|
|
}
|
|
|
|
|
2003-03-03 02:59:12 +03:00
|
|
|
void BX_CPP_AttrRegparmN(3)
|
2007-12-20 21:29:42 +03:00
|
|
|
BX_CPU_C::write_virtual_dword(unsigned s, bx_address offset, Bit32u data)
|
2001-04-10 05:04:59 +04:00
|
|
|
{
|
2002-09-13 08:33:42 +04:00
|
|
|
bx_address laddr;
|
2007-12-10 22:08:13 +03:00
|
|
|
bx_segment_reg_t *seg = &BX_CPU_THIS_PTR sregs[s];
|
2001-04-10 05:04:59 +04:00
|
|
|
|
2007-12-10 22:08:13 +03:00
|
|
|
if ((seg->cache.valid & SegAccessWOK4G) == SegAccessWOK4G) {
|
Integrated patches for:
- Paging code rehash. You must now use --enable-4meg-pages to
use 4Meg pages, with the default of disabled, since we don't well
support 4Meg pages yet. Paging table walks model a real CPU
more closely now, and I fixed some bugs in the old logic.
- Segment check redundancy elimination. After a segment is loaded,
reads and writes are marked when a segment type check succeeds, and
they are skipped thereafter, when possible.
- Repeated IO and memory string copy acceleration. Only some variants
of instructions are available on all platforms, word and dword
variants only on x86 for the moment due to alignment and endian issues.
This is compiled in currently with no option - I should add a configure
option.
- Added a guest linear address to host TLB. Actually, I just stick
the host address (mem.vector[addr] address) in the upper 29 bits
of the field 'combined_access' since they are unused. Convenient
for now. I'm only storing page frame addresses. This was the
simplest for of such a TLB. We can likely enhance this. Also,
I only accelerated the normal read/write routines in access.cc.
Could also modify the read-modify-write versions too. You must
use --enable-guest2host-tlb, to try this out. Currently speeds
up Win95 boot time by about 3.5% for me. More ground to cover...
- Minor mods to CPUI/MOV_CdRd for CMOV.
- Integrated enhancements from Volker to getHostMemAddr() for PCI
being enabled.
2002-09-02 00:12:09 +04:00
|
|
|
accessOK:
|
2007-12-10 22:08:13 +03:00
|
|
|
laddr = BX_CPU_THIS_PTR get_segment_base(s) + offset;
|
|
|
|
BX_INSTR_MEM_DATA(BX_CPU_ID, laddr, 4, BX_WRITE);
|
2007-08-01 00:25:52 +04:00
|
|
|
#if BX_CPU_LEVEL >= 4 && BX_SUPPORT_ALIGNMENT_CHECK
|
2007-12-10 22:08:13 +03:00
|
|
|
if (BX_CPU_THIS_PTR alignment_check) {
|
|
|
|
if (laddr & 3) {
|
|
|
|
BX_ERROR(("write_virtual_dword(): #AC misaligned access"));
|
|
|
|
exception(BX_AC_EXCEPTION, 0, 0);
|
2007-08-01 00:25:52 +04:00
|
|
|
}
|
2007-12-10 22:08:13 +03:00
|
|
|
}
|
2007-08-01 00:25:52 +04:00
|
|
|
#endif
|
Integrated patches for:
- Paging code rehash. You must now use --enable-4meg-pages to
use 4Meg pages, with the default of disabled, since we don't well
support 4Meg pages yet. Paging table walks model a real CPU
more closely now, and I fixed some bugs in the old logic.
- Segment check redundancy elimination. After a segment is loaded,
reads and writes are marked when a segment type check succeeds, and
they are skipped thereafter, when possible.
- Repeated IO and memory string copy acceleration. Only some variants
of instructions are available on all platforms, word and dword
variants only on x86 for the moment due to alignment and endian issues.
This is compiled in currently with no option - I should add a configure
option.
- Added a guest linear address to host TLB. Actually, I just stick
the host address (mem.vector[addr] address) in the upper 29 bits
of the field 'combined_access' since they are unused. Convenient
for now. I'm only storing page frame addresses. This was the
simplest for of such a TLB. We can likely enhance this. Also,
I only accelerated the normal read/write routines in access.cc.
Could also modify the read-modify-write versions too. You must
use --enable-guest2host-tlb, to try this out. Currently speeds
up Win95 boot time by about 3.5% for me. More ground to cover...
- Minor mods to CPUI/MOV_CdRd for CMOV.
- Integrated enhancements from Volker to getHostMemAddr() for PCI
being enabled.
2002-09-02 00:12:09 +04:00
|
|
|
#if BX_SupportGuest2HostTLB
|
2007-12-21 13:33:39 +03:00
|
|
|
Bit32u 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) {
|
|
|
|
// See if the TLB entry privilege level allows us write access
|
|
|
|
// from this CPL.
|
|
|
|
if (tlbEntry->accessBits & (0x10 << CPL)) {
|
|
|
|
bx_hostpageaddr_t hostPageAddr = tlbEntry->hostPageAddr;
|
|
|
|
Bit32u pageOffset = laddr & 0xfff;
|
|
|
|
BX_INSTR_LIN_ACCESS(BX_CPU_ID, laddr, tlbEntry->ppf | pageOffset, 4, BX_WRITE);
|
|
|
|
Bit32u *hostAddr = (Bit32u*) (hostPageAddr | pageOffset);
|
2007-10-17 22:09:42 +04:00
|
|
|
#if BX_SUPPORT_ICACHE
|
2007-12-21 13:33:39 +03:00
|
|
|
pageWriteStampTable.decWriteStamp(tlbEntry->ppf);
|
2007-10-17 22:09:42 +04:00
|
|
|
#endif
|
2007-12-21 13:33:39 +03:00
|
|
|
WriteHostDWordToLittleEndian(hostAddr, data);
|
|
|
|
return;
|
Now, when you compile with --enable-guest2host-tlb, non-paged
mode uses the notion of the guest-to-host TLB. This has the
benefit of allowing more uniform and streamlined acceleration
code in access.cc which does not have to check if CR0.PG
is set, eliminating a few instructions per guest access.
Shaved just a little off execution time, as expected.
Also, access_linear now breaks accesses which span two pages,
into two calls the the physical memory routines, when paging
is off, just like it always has for paging on. Besides
being more uniform, this allows the physical memory access
routines to known the complete data item is contained
within a single physical page, and stop reapplying the
A20ADDR() macro to pointers as it increments them.
Perhaps things can be optimized a little more now there too...
I renamed the routines to {read,write}PhysicalPage() as
a reminder that these routines now operate on data
solely within one page.
I also added a little code so that the paging module is
notified when the A20 line is tweaked, so it can dump
whatever mappings it wants to.
2002-09-05 06:31:24 +04:00
|
|
|
}
|
2007-12-10 22:08:13 +03:00
|
|
|
}
|
2007-11-20 20:15:33 +03:00
|
|
|
#endif
|
|
|
|
#if BX_SUPPORT_X86_64
|
2007-12-10 22:08:13 +03:00
|
|
|
if (! IsCanonical(laddr)) {
|
|
|
|
BX_ERROR(("write_virtual_dword(): canonical failure"));
|
|
|
|
exception(int_number(seg), 0, 0);
|
Integrated patches for:
- Paging code rehash. You must now use --enable-4meg-pages to
use 4Meg pages, with the default of disabled, since we don't well
support 4Meg pages yet. Paging table walks model a real CPU
more closely now, and I fixed some bugs in the old logic.
- Segment check redundancy elimination. After a segment is loaded,
reads and writes are marked when a segment type check succeeds, and
they are skipped thereafter, when possible.
- Repeated IO and memory string copy acceleration. Only some variants
of instructions are available on all platforms, word and dword
variants only on x86 for the moment due to alignment and endian issues.
This is compiled in currently with no option - I should add a configure
option.
- Added a guest linear address to host TLB. Actually, I just stick
the host address (mem.vector[addr] address) in the upper 29 bits
of the field 'combined_access' since they are unused. Convenient
for now. I'm only storing page frame addresses. This was the
simplest for of such a TLB. We can likely enhance this. Also,
I only accelerated the normal read/write routines in access.cc.
Could also modify the read-modify-write versions too. You must
use --enable-guest2host-tlb, to try this out. Currently speeds
up Win95 boot time by about 3.5% for me. More ground to cover...
- Minor mods to CPUI/MOV_CdRd for CMOV.
- Integrated enhancements from Volker to getHostMemAddr() for PCI
being enabled.
2002-09-02 00:12:09 +04:00
|
|
|
}
|
2007-12-10 22:08:13 +03:00
|
|
|
#endif
|
2007-12-20 21:29:42 +03:00
|
|
|
access_linear(laddr, 4, CPL, BX_WRITE, (void *) &data);
|
2007-12-10 22:08:13 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (seg->cache.valid & SegAccessWOK) {
|
|
|
|
if (Is64BitMode() || (offset < (seg->cache.u.segment.limit_scaled-2)))
|
|
|
|
goto accessOK;
|
2004-11-19 02:16:36 +03:00
|
|
|
}
|
Integrated patches for:
- Paging code rehash. You must now use --enable-4meg-pages to
use 4Meg pages, with the default of disabled, since we don't well
support 4Meg pages yet. Paging table walks model a real CPU
more closely now, and I fixed some bugs in the old logic.
- Segment check redundancy elimination. After a segment is loaded,
reads and writes are marked when a segment type check succeeds, and
they are skipped thereafter, when possible.
- Repeated IO and memory string copy acceleration. Only some variants
of instructions are available on all platforms, word and dword
variants only on x86 for the moment due to alignment and endian issues.
This is compiled in currently with no option - I should add a configure
option.
- Added a guest linear address to host TLB. Actually, I just stick
the host address (mem.vector[addr] address) in the upper 29 bits
of the field 'combined_access' since they are unused. Convenient
for now. I'm only storing page frame addresses. This was the
simplest for of such a TLB. We can likely enhance this. Also,
I only accelerated the normal read/write routines in access.cc.
Could also modify the read-modify-write versions too. You must
use --enable-guest2host-tlb, to try this out. Currently speeds
up Win95 boot time by about 3.5% for me. More ground to cover...
- Minor mods to CPUI/MOV_CdRd for CMOV.
- Integrated enhancements from Volker to getHostMemAddr() for PCI
being enabled.
2002-09-02 00:12:09 +04:00
|
|
|
write_virtual_checks(seg, offset, 4);
|
|
|
|
goto accessOK;
|
2001-04-10 05:04:59 +04:00
|
|
|
}
|
|
|
|
|
2004-11-19 02:16:36 +03:00
|
|
|
void BX_CPP_AttrRegparmN(3)
|
2007-12-20 21:29:42 +03:00
|
|
|
BX_CPU_C::write_virtual_qword(unsigned s, bx_address offset, Bit64u data)
|
2004-11-19 02:16:36 +03:00
|
|
|
{
|
|
|
|
bx_address laddr;
|
2007-12-10 22:08:13 +03:00
|
|
|
bx_segment_reg_t *seg = &BX_CPU_THIS_PTR sregs[s];
|
2004-11-19 02:16:36 +03:00
|
|
|
|
2007-12-10 22:08:13 +03:00
|
|
|
if ((seg->cache.valid & SegAccessWOK4G) == SegAccessWOK4G) {
|
2004-11-19 02:16:36 +03:00
|
|
|
accessOK:
|
2007-12-10 22:08:13 +03:00
|
|
|
laddr = BX_CPU_THIS_PTR get_segment_base(s) + offset;
|
|
|
|
BX_INSTR_MEM_DATA(BX_CPU_ID, laddr, 8, BX_WRITE);
|
2007-08-01 00:25:52 +04:00
|
|
|
#if BX_CPU_LEVEL >= 4 && BX_SUPPORT_ALIGNMENT_CHECK
|
2007-12-10 22:08:13 +03:00
|
|
|
if (BX_CPU_THIS_PTR alignment_check) {
|
|
|
|
if (laddr & 7) {
|
|
|
|
BX_ERROR(("write_virtual_qword(): #AC misaligned access"));
|
|
|
|
exception(BX_AC_EXCEPTION, 0, 0);
|
2007-08-01 00:25:52 +04:00
|
|
|
}
|
2007-12-10 22:08:13 +03:00
|
|
|
}
|
2007-08-01 00:25:52 +04:00
|
|
|
#endif
|
2004-11-19 02:16:36 +03:00
|
|
|
#if BX_SupportGuest2HostTLB
|
2007-12-21 13:33:39 +03:00
|
|
|
Bit32u 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) {
|
|
|
|
// See if the TLB entry privilege level allows us write access
|
|
|
|
// from this CPL.
|
|
|
|
if (tlbEntry->accessBits & (0x10 << CPL)) {
|
|
|
|
bx_hostpageaddr_t hostPageAddr = tlbEntry->hostPageAddr;
|
|
|
|
Bit32u pageOffset = laddr & 0xfff;
|
|
|
|
BX_INSTR_LIN_ACCESS(BX_CPU_ID, laddr, tlbEntry->ppf | pageOffset, 8, BX_WRITE);
|
|
|
|
Bit64u *hostAddr = (Bit64u*) (hostPageAddr | pageOffset);
|
2007-10-17 22:09:42 +04:00
|
|
|
#if BX_SUPPORT_ICACHE
|
2007-12-21 13:33:39 +03:00
|
|
|
pageWriteStampTable.decWriteStamp(tlbEntry->ppf);
|
2007-10-17 22:09:42 +04:00
|
|
|
#endif
|
2007-12-21 13:33:39 +03:00
|
|
|
WriteHostQWordToLittleEndian(hostAddr, data);
|
|
|
|
return;
|
2004-11-19 02:16:36 +03:00
|
|
|
}
|
2007-12-10 22:08:13 +03:00
|
|
|
}
|
2007-11-20 20:15:33 +03:00
|
|
|
#endif
|
|
|
|
#if BX_SUPPORT_X86_64
|
2007-12-10 22:08:13 +03:00
|
|
|
if (! IsCanonical(laddr)) {
|
|
|
|
BX_ERROR(("write_virtual_qword(): canonical failure"));
|
|
|
|
exception(int_number(seg), 0, 0);
|
2004-11-19 02:16:36 +03:00
|
|
|
}
|
2007-12-10 22:08:13 +03:00
|
|
|
#endif
|
2007-12-20 21:29:42 +03:00
|
|
|
access_linear(laddr, 8, CPL, BX_WRITE, (void *) &data);
|
2007-12-10 22:08:13 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (seg->cache.valid & SegAccessWOK) {
|
|
|
|
if (Is64BitMode() || (offset <= (seg->cache.u.segment.limit_scaled-7)))
|
|
|
|
goto accessOK;
|
2004-11-19 02:16:36 +03:00
|
|
|
}
|
|
|
|
write_virtual_checks(seg, offset, 8);
|
|
|
|
goto accessOK;
|
|
|
|
}
|
|
|
|
|
2007-12-20 23:58:38 +03:00
|
|
|
Bit8u BX_CPP_AttrRegparmN(2)
|
|
|
|
BX_CPU_C::read_virtual_byte(unsigned s, bx_address offset)
|
2001-04-10 05:04:59 +04:00
|
|
|
{
|
2002-09-13 08:33:42 +04:00
|
|
|
bx_address laddr;
|
2007-12-10 22:08:13 +03:00
|
|
|
bx_segment_reg_t *seg = &BX_CPU_THIS_PTR sregs[s];
|
2007-12-20 23:58:38 +03:00
|
|
|
Bit8u data;
|
2001-04-10 05:04:59 +04:00
|
|
|
|
2007-12-10 22:08:13 +03:00
|
|
|
if ((seg->cache.valid & SegAccessROK4G) == SegAccessROK4G) {
|
Integrated patches for:
- Paging code rehash. You must now use --enable-4meg-pages to
use 4Meg pages, with the default of disabled, since we don't well
support 4Meg pages yet. Paging table walks model a real CPU
more closely now, and I fixed some bugs in the old logic.
- Segment check redundancy elimination. After a segment is loaded,
reads and writes are marked when a segment type check succeeds, and
they are skipped thereafter, when possible.
- Repeated IO and memory string copy acceleration. Only some variants
of instructions are available on all platforms, word and dword
variants only on x86 for the moment due to alignment and endian issues.
This is compiled in currently with no option - I should add a configure
option.
- Added a guest linear address to host TLB. Actually, I just stick
the host address (mem.vector[addr] address) in the upper 29 bits
of the field 'combined_access' since they are unused. Convenient
for now. I'm only storing page frame addresses. This was the
simplest for of such a TLB. We can likely enhance this. Also,
I only accelerated the normal read/write routines in access.cc.
Could also modify the read-modify-write versions too. You must
use --enable-guest2host-tlb, to try this out. Currently speeds
up Win95 boot time by about 3.5% for me. More ground to cover...
- Minor mods to CPUI/MOV_CdRd for CMOV.
- Integrated enhancements from Volker to getHostMemAddr() for PCI
being enabled.
2002-09-02 00:12:09 +04:00
|
|
|
accessOK:
|
2007-12-10 22:08:13 +03:00
|
|
|
laddr = BX_CPU_THIS_PTR get_segment_base(s) + offset;
|
|
|
|
BX_INSTR_MEM_DATA(BX_CPU_ID, laddr, 1, BX_READ);
|
Integrated patches for:
- Paging code rehash. You must now use --enable-4meg-pages to
use 4Meg pages, with the default of disabled, since we don't well
support 4Meg pages yet. Paging table walks model a real CPU
more closely now, and I fixed some bugs in the old logic.
- Segment check redundancy elimination. After a segment is loaded,
reads and writes are marked when a segment type check succeeds, and
they are skipped thereafter, when possible.
- Repeated IO and memory string copy acceleration. Only some variants
of instructions are available on all platforms, word and dword
variants only on x86 for the moment due to alignment and endian issues.
This is compiled in currently with no option - I should add a configure
option.
- Added a guest linear address to host TLB. Actually, I just stick
the host address (mem.vector[addr] address) in the upper 29 bits
of the field 'combined_access' since they are unused. Convenient
for now. I'm only storing page frame addresses. This was the
simplest for of such a TLB. We can likely enhance this. Also,
I only accelerated the normal read/write routines in access.cc.
Could also modify the read-modify-write versions too. You must
use --enable-guest2host-tlb, to try this out. Currently speeds
up Win95 boot time by about 3.5% for me. More ground to cover...
- Minor mods to CPUI/MOV_CdRd for CMOV.
- Integrated enhancements from Volker to getHostMemAddr() for PCI
being enabled.
2002-09-02 00:12:09 +04:00
|
|
|
#if BX_SupportGuest2HostTLB
|
2007-12-21 13:33:39 +03:00
|
|
|
Bit32u tlbIndex = BX_TLB_INDEX_OF(laddr, 0);
|
2007-12-10 22:08:13 +03:00
|
|
|
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.
|
2007-12-17 00:03:46 +03:00
|
|
|
if (tlbEntry->accessBits & (1<<CPL)) { // Read this pl OK.
|
2007-12-10 22:08:13 +03:00
|
|
|
bx_hostpageaddr_t hostPageAddr = tlbEntry->hostPageAddr;
|
|
|
|
Bit32u pageOffset = laddr & 0xfff;
|
2007-12-14 00:30:05 +03:00
|
|
|
BX_INSTR_LIN_ACCESS(BX_CPU_ID, laddr, tlbEntry->ppf | pageOffset, 1, BX_READ);
|
2007-12-10 22:08:13 +03:00
|
|
|
Bit8u *hostAddr = (Bit8u*) (hostPageAddr | pageOffset);
|
2007-12-20 23:58:38 +03:00
|
|
|
data = *hostAddr;
|
|
|
|
return data;
|
Now, when you compile with --enable-guest2host-tlb, non-paged
mode uses the notion of the guest-to-host TLB. This has the
benefit of allowing more uniform and streamlined acceleration
code in access.cc which does not have to check if CR0.PG
is set, eliminating a few instructions per guest access.
Shaved just a little off execution time, as expected.
Also, access_linear now breaks accesses which span two pages,
into two calls the the physical memory routines, when paging
is off, just like it always has for paging on. Besides
being more uniform, this allows the physical memory access
routines to known the complete data item is contained
within a single physical page, and stop reapplying the
A20ADDR() macro to pointers as it increments them.
Perhaps things can be optimized a little more now there too...
I renamed the routines to {read,write}PhysicalPage() as
a reminder that these routines now operate on data
solely within one page.
I also added a little code so that the paging module is
notified when the A20 line is tweaked, so it can dump
whatever mappings it wants to.
2002-09-05 06:31:24 +04:00
|
|
|
}
|
2007-12-10 22:08:13 +03:00
|
|
|
}
|
2007-11-20 20:15:33 +03:00
|
|
|
#endif
|
|
|
|
#if BX_SUPPORT_X86_64
|
2007-12-10 22:08:13 +03:00
|
|
|
if (! IsCanonical(laddr)) {
|
|
|
|
BX_ERROR(("read_virtual_byte(): canonical failure"));
|
|
|
|
exception(int_number(seg), 0, 0);
|
Integrated patches for:
- Paging code rehash. You must now use --enable-4meg-pages to
use 4Meg pages, with the default of disabled, since we don't well
support 4Meg pages yet. Paging table walks model a real CPU
more closely now, and I fixed some bugs in the old logic.
- Segment check redundancy elimination. After a segment is loaded,
reads and writes are marked when a segment type check succeeds, and
they are skipped thereafter, when possible.
- Repeated IO and memory string copy acceleration. Only some variants
of instructions are available on all platforms, word and dword
variants only on x86 for the moment due to alignment and endian issues.
This is compiled in currently with no option - I should add a configure
option.
- Added a guest linear address to host TLB. Actually, I just stick
the host address (mem.vector[addr] address) in the upper 29 bits
of the field 'combined_access' since they are unused. Convenient
for now. I'm only storing page frame addresses. This was the
simplest for of such a TLB. We can likely enhance this. Also,
I only accelerated the normal read/write routines in access.cc.
Could also modify the read-modify-write versions too. You must
use --enable-guest2host-tlb, to try this out. Currently speeds
up Win95 boot time by about 3.5% for me. More ground to cover...
- Minor mods to CPUI/MOV_CdRd for CMOV.
- Integrated enhancements from Volker to getHostMemAddr() for PCI
being enabled.
2002-09-02 00:12:09 +04:00
|
|
|
}
|
2007-12-10 22:08:13 +03:00
|
|
|
#endif
|
2007-12-20 23:58:38 +03:00
|
|
|
access_linear(laddr, 1, CPL, BX_READ, (void *) &data);
|
|
|
|
return data;
|
2007-12-10 22:08:13 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
if (seg->cache.valid & SegAccessROK) {
|
|
|
|
if (Is64BitMode() || (offset <= seg->cache.u.segment.limit_scaled))
|
|
|
|
goto accessOK;
|
2005-01-25 23:41:43 +03:00
|
|
|
}
|
Integrated patches for:
- Paging code rehash. You must now use --enable-4meg-pages to
use 4Meg pages, with the default of disabled, since we don't well
support 4Meg pages yet. Paging table walks model a real CPU
more closely now, and I fixed some bugs in the old logic.
- Segment check redundancy elimination. After a segment is loaded,
reads and writes are marked when a segment type check succeeds, and
they are skipped thereafter, when possible.
- Repeated IO and memory string copy acceleration. Only some variants
of instructions are available on all platforms, word and dword
variants only on x86 for the moment due to alignment and endian issues.
This is compiled in currently with no option - I should add a configure
option.
- Added a guest linear address to host TLB. Actually, I just stick
the host address (mem.vector[addr] address) in the upper 29 bits
of the field 'combined_access' since they are unused. Convenient
for now. I'm only storing page frame addresses. This was the
simplest for of such a TLB. We can likely enhance this. Also,
I only accelerated the normal read/write routines in access.cc.
Could also modify the read-modify-write versions too. You must
use --enable-guest2host-tlb, to try this out. Currently speeds
up Win95 boot time by about 3.5% for me. More ground to cover...
- Minor mods to CPUI/MOV_CdRd for CMOV.
- Integrated enhancements from Volker to getHostMemAddr() for PCI
being enabled.
2002-09-02 00:12:09 +04:00
|
|
|
read_virtual_checks(seg, offset, 1);
|
|
|
|
goto accessOK;
|
2001-04-10 05:04:59 +04:00
|
|
|
}
|
|
|
|
|
2007-12-20 23:58:38 +03:00
|
|
|
Bit16u BX_CPP_AttrRegparmN(2)
|
|
|
|
BX_CPU_C::read_virtual_word(unsigned s, bx_address offset)
|
2001-04-10 05:04:59 +04:00
|
|
|
{
|
2002-09-13 08:33:42 +04:00
|
|
|
bx_address laddr;
|
2007-12-10 22:08:13 +03:00
|
|
|
bx_segment_reg_t *seg = &BX_CPU_THIS_PTR sregs[s];
|
2007-12-20 23:58:38 +03:00
|
|
|
Bit16u data;
|
2001-04-10 05:04:59 +04:00
|
|
|
|
2007-12-10 22:08:13 +03:00
|
|
|
if ((seg->cache.valid & SegAccessROK4G) == SegAccessROK4G) {
|
Integrated patches for:
- Paging code rehash. You must now use --enable-4meg-pages to
use 4Meg pages, with the default of disabled, since we don't well
support 4Meg pages yet. Paging table walks model a real CPU
more closely now, and I fixed some bugs in the old logic.
- Segment check redundancy elimination. After a segment is loaded,
reads and writes are marked when a segment type check succeeds, and
they are skipped thereafter, when possible.
- Repeated IO and memory string copy acceleration. Only some variants
of instructions are available on all platforms, word and dword
variants only on x86 for the moment due to alignment and endian issues.
This is compiled in currently with no option - I should add a configure
option.
- Added a guest linear address to host TLB. Actually, I just stick
the host address (mem.vector[addr] address) in the upper 29 bits
of the field 'combined_access' since they are unused. Convenient
for now. I'm only storing page frame addresses. This was the
simplest for of such a TLB. We can likely enhance this. Also,
I only accelerated the normal read/write routines in access.cc.
Could also modify the read-modify-write versions too. You must
use --enable-guest2host-tlb, to try this out. Currently speeds
up Win95 boot time by about 3.5% for me. More ground to cover...
- Minor mods to CPUI/MOV_CdRd for CMOV.
- Integrated enhancements from Volker to getHostMemAddr() for PCI
being enabled.
2002-09-02 00:12:09 +04:00
|
|
|
accessOK:
|
2007-12-10 22:08:13 +03:00
|
|
|
laddr = BX_CPU_THIS_PTR get_segment_base(s) + offset;
|
|
|
|
BX_INSTR_MEM_DATA(BX_CPU_ID, laddr, 2, BX_READ);
|
2007-08-01 00:25:52 +04:00
|
|
|
#if BX_CPU_LEVEL >= 4 && BX_SUPPORT_ALIGNMENT_CHECK
|
2007-12-10 22:08:13 +03:00
|
|
|
if (BX_CPU_THIS_PTR alignment_check) {
|
|
|
|
if (laddr & 1) {
|
|
|
|
BX_ERROR(("read_virtual_word(): #AC misaligned access"));
|
|
|
|
exception(BX_AC_EXCEPTION, 0, 0);
|
2007-08-01 00:25:52 +04:00
|
|
|
}
|
2007-12-10 22:08:13 +03:00
|
|
|
}
|
2007-08-01 00:25:52 +04:00
|
|
|
#endif
|
Integrated patches for:
- Paging code rehash. You must now use --enable-4meg-pages to
use 4Meg pages, with the default of disabled, since we don't well
support 4Meg pages yet. Paging table walks model a real CPU
more closely now, and I fixed some bugs in the old logic.
- Segment check redundancy elimination. After a segment is loaded,
reads and writes are marked when a segment type check succeeds, and
they are skipped thereafter, when possible.
- Repeated IO and memory string copy acceleration. Only some variants
of instructions are available on all platforms, word and dword
variants only on x86 for the moment due to alignment and endian issues.
This is compiled in currently with no option - I should add a configure
option.
- Added a guest linear address to host TLB. Actually, I just stick
the host address (mem.vector[addr] address) in the upper 29 bits
of the field 'combined_access' since they are unused. Convenient
for now. I'm only storing page frame addresses. This was the
simplest for of such a TLB. We can likely enhance this. Also,
I only accelerated the normal read/write routines in access.cc.
Could also modify the read-modify-write versions too. You must
use --enable-guest2host-tlb, to try this out. Currently speeds
up Win95 boot time by about 3.5% for me. More ground to cover...
- Minor mods to CPUI/MOV_CdRd for CMOV.
- Integrated enhancements from Volker to getHostMemAddr() for PCI
being enabled.
2002-09-02 00:12:09 +04:00
|
|
|
#if BX_SupportGuest2HostTLB
|
2007-12-21 13:33:39 +03:00
|
|
|
Bit32u 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) {
|
|
|
|
// See if the TLB entry privilege level allows us read access
|
|
|
|
// from this CPL.
|
|
|
|
if (tlbEntry->accessBits & (1<<CPL)) { // Read this pl OK.
|
|
|
|
bx_hostpageaddr_t hostPageAddr = tlbEntry->hostPageAddr;
|
|
|
|
Bit32u pageOffset = laddr & 0xfff;
|
|
|
|
BX_INSTR_LIN_ACCESS(BX_CPU_ID, laddr, tlbEntry->ppf | pageOffset, 2, BX_READ);
|
|
|
|
Bit16u *hostAddr = (Bit16u*) (hostPageAddr | pageOffset);
|
|
|
|
ReadHostWordFromLittleEndian(hostAddr, data);
|
|
|
|
return data;
|
Now, when you compile with --enable-guest2host-tlb, non-paged
mode uses the notion of the guest-to-host TLB. This has the
benefit of allowing more uniform and streamlined acceleration
code in access.cc which does not have to check if CR0.PG
is set, eliminating a few instructions per guest access.
Shaved just a little off execution time, as expected.
Also, access_linear now breaks accesses which span two pages,
into two calls the the physical memory routines, when paging
is off, just like it always has for paging on. Besides
being more uniform, this allows the physical memory access
routines to known the complete data item is contained
within a single physical page, and stop reapplying the
A20ADDR() macro to pointers as it increments them.
Perhaps things can be optimized a little more now there too...
I renamed the routines to {read,write}PhysicalPage() as
a reminder that these routines now operate on data
solely within one page.
I also added a little code so that the paging module is
notified when the A20 line is tweaked, so it can dump
whatever mappings it wants to.
2002-09-05 06:31:24 +04:00
|
|
|
}
|
2007-12-10 22:08:13 +03:00
|
|
|
}
|
2007-11-20 20:15:33 +03:00
|
|
|
#endif
|
|
|
|
#if BX_SUPPORT_X86_64
|
2007-12-10 22:08:13 +03:00
|
|
|
if (! IsCanonical(laddr)) {
|
|
|
|
BX_ERROR(("read_virtual_word(): canonical failure"));
|
|
|
|
exception(int_number(seg), 0, 0);
|
Integrated patches for:
- Paging code rehash. You must now use --enable-4meg-pages to
use 4Meg pages, with the default of disabled, since we don't well
support 4Meg pages yet. Paging table walks model a real CPU
more closely now, and I fixed some bugs in the old logic.
- Segment check redundancy elimination. After a segment is loaded,
reads and writes are marked when a segment type check succeeds, and
they are skipped thereafter, when possible.
- Repeated IO and memory string copy acceleration. Only some variants
of instructions are available on all platforms, word and dword
variants only on x86 for the moment due to alignment and endian issues.
This is compiled in currently with no option - I should add a configure
option.
- Added a guest linear address to host TLB. Actually, I just stick
the host address (mem.vector[addr] address) in the upper 29 bits
of the field 'combined_access' since they are unused. Convenient
for now. I'm only storing page frame addresses. This was the
simplest for of such a TLB. We can likely enhance this. Also,
I only accelerated the normal read/write routines in access.cc.
Could also modify the read-modify-write versions too. You must
use --enable-guest2host-tlb, to try this out. Currently speeds
up Win95 boot time by about 3.5% for me. More ground to cover...
- Minor mods to CPUI/MOV_CdRd for CMOV.
- Integrated enhancements from Volker to getHostMemAddr() for PCI
being enabled.
2002-09-02 00:12:09 +04:00
|
|
|
}
|
2007-12-10 22:08:13 +03:00
|
|
|
#endif
|
2007-12-20 23:58:38 +03:00
|
|
|
access_linear(laddr, 2, CPL, BX_READ, (void *) &data);
|
|
|
|
return data;
|
2007-12-10 22:08:13 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
if (seg->cache.valid & SegAccessROK) {
|
|
|
|
if (Is64BitMode() || (offset < seg->cache.u.segment.limit_scaled))
|
|
|
|
goto accessOK;
|
2005-01-25 23:41:43 +03:00
|
|
|
}
|
Integrated patches for:
- Paging code rehash. You must now use --enable-4meg-pages to
use 4Meg pages, with the default of disabled, since we don't well
support 4Meg pages yet. Paging table walks model a real CPU
more closely now, and I fixed some bugs in the old logic.
- Segment check redundancy elimination. After a segment is loaded,
reads and writes are marked when a segment type check succeeds, and
they are skipped thereafter, when possible.
- Repeated IO and memory string copy acceleration. Only some variants
of instructions are available on all platforms, word and dword
variants only on x86 for the moment due to alignment and endian issues.
This is compiled in currently with no option - I should add a configure
option.
- Added a guest linear address to host TLB. Actually, I just stick
the host address (mem.vector[addr] address) in the upper 29 bits
of the field 'combined_access' since they are unused. Convenient
for now. I'm only storing page frame addresses. This was the
simplest for of such a TLB. We can likely enhance this. Also,
I only accelerated the normal read/write routines in access.cc.
Could also modify the read-modify-write versions too. You must
use --enable-guest2host-tlb, to try this out. Currently speeds
up Win95 boot time by about 3.5% for me. More ground to cover...
- Minor mods to CPUI/MOV_CdRd for CMOV.
- Integrated enhancements from Volker to getHostMemAddr() for PCI
being enabled.
2002-09-02 00:12:09 +04:00
|
|
|
read_virtual_checks(seg, offset, 2);
|
|
|
|
goto accessOK;
|
2001-04-10 05:04:59 +04:00
|
|
|
}
|
|
|
|
|
2007-12-20 23:58:38 +03:00
|
|
|
Bit32u BX_CPP_AttrRegparmN(2)
|
|
|
|
BX_CPU_C::read_virtual_dword(unsigned s, bx_address offset)
|
2001-04-10 05:04:59 +04:00
|
|
|
{
|
2002-09-13 08:33:42 +04:00
|
|
|
bx_address laddr;
|
2007-12-10 22:08:13 +03:00
|
|
|
bx_segment_reg_t *seg = &BX_CPU_THIS_PTR sregs[s];
|
2007-12-20 23:58:38 +03:00
|
|
|
Bit32u data;
|
2001-04-10 05:04:59 +04:00
|
|
|
|
2007-12-10 22:08:13 +03:00
|
|
|
if ((seg->cache.valid & SegAccessROK4G) == SegAccessROK4G) {
|
Integrated patches for:
- Paging code rehash. You must now use --enable-4meg-pages to
use 4Meg pages, with the default of disabled, since we don't well
support 4Meg pages yet. Paging table walks model a real CPU
more closely now, and I fixed some bugs in the old logic.
- Segment check redundancy elimination. After a segment is loaded,
reads and writes are marked when a segment type check succeeds, and
they are skipped thereafter, when possible.
- Repeated IO and memory string copy acceleration. Only some variants
of instructions are available on all platforms, word and dword
variants only on x86 for the moment due to alignment and endian issues.
This is compiled in currently with no option - I should add a configure
option.
- Added a guest linear address to host TLB. Actually, I just stick
the host address (mem.vector[addr] address) in the upper 29 bits
of the field 'combined_access' since they are unused. Convenient
for now. I'm only storing page frame addresses. This was the
simplest for of such a TLB. We can likely enhance this. Also,
I only accelerated the normal read/write routines in access.cc.
Could also modify the read-modify-write versions too. You must
use --enable-guest2host-tlb, to try this out. Currently speeds
up Win95 boot time by about 3.5% for me. More ground to cover...
- Minor mods to CPUI/MOV_CdRd for CMOV.
- Integrated enhancements from Volker to getHostMemAddr() for PCI
being enabled.
2002-09-02 00:12:09 +04:00
|
|
|
accessOK:
|
2007-12-10 22:08:13 +03:00
|
|
|
laddr = BX_CPU_THIS_PTR get_segment_base(s) + offset;
|
|
|
|
BX_INSTR_MEM_DATA(BX_CPU_ID, laddr, 4, BX_READ);
|
2007-08-01 00:25:52 +04:00
|
|
|
#if BX_CPU_LEVEL >= 4 && BX_SUPPORT_ALIGNMENT_CHECK
|
2007-12-10 22:08:13 +03:00
|
|
|
if (BX_CPU_THIS_PTR alignment_check) {
|
|
|
|
if (laddr & 3) {
|
|
|
|
BX_ERROR(("read_virtual_dword(): #AC misaligned access"));
|
|
|
|
exception(BX_AC_EXCEPTION, 0, 0);
|
2007-08-01 00:25:52 +04:00
|
|
|
}
|
2007-12-10 22:08:13 +03:00
|
|
|
}
|
2007-08-01 00:25:52 +04:00
|
|
|
#endif
|
Integrated patches for:
- Paging code rehash. You must now use --enable-4meg-pages to
use 4Meg pages, with the default of disabled, since we don't well
support 4Meg pages yet. Paging table walks model a real CPU
more closely now, and I fixed some bugs in the old logic.
- Segment check redundancy elimination. After a segment is loaded,
reads and writes are marked when a segment type check succeeds, and
they are skipped thereafter, when possible.
- Repeated IO and memory string copy acceleration. Only some variants
of instructions are available on all platforms, word and dword
variants only on x86 for the moment due to alignment and endian issues.
This is compiled in currently with no option - I should add a configure
option.
- Added a guest linear address to host TLB. Actually, I just stick
the host address (mem.vector[addr] address) in the upper 29 bits
of the field 'combined_access' since they are unused. Convenient
for now. I'm only storing page frame addresses. This was the
simplest for of such a TLB. We can likely enhance this. Also,
I only accelerated the normal read/write routines in access.cc.
Could also modify the read-modify-write versions too. You must
use --enable-guest2host-tlb, to try this out. Currently speeds
up Win95 boot time by about 3.5% for me. More ground to cover...
- Minor mods to CPUI/MOV_CdRd for CMOV.
- Integrated enhancements from Volker to getHostMemAddr() for PCI
being enabled.
2002-09-02 00:12:09 +04:00
|
|
|
#if BX_SupportGuest2HostTLB
|
2007-12-21 13:33:39 +03:00
|
|
|
Bit32u 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) {
|
|
|
|
// See if the TLB entry privilege level allows us read access
|
|
|
|
// from this CPL.
|
|
|
|
if (tlbEntry->accessBits & (1<<CPL)) { // Read this pl OK.
|
|
|
|
bx_hostpageaddr_t hostPageAddr = tlbEntry->hostPageAddr;
|
|
|
|
Bit32u pageOffset = laddr & 0xfff;
|
|
|
|
BX_INSTR_LIN_ACCESS(BX_CPU_ID, laddr, tlbEntry->ppf | pageOffset, 4, BX_READ);
|
|
|
|
Bit32u *hostAddr = (Bit32u*) (hostPageAddr | pageOffset);
|
|
|
|
ReadHostDWordFromLittleEndian(hostAddr, data);
|
|
|
|
return data;
|
Now, when you compile with --enable-guest2host-tlb, non-paged
mode uses the notion of the guest-to-host TLB. This has the
benefit of allowing more uniform and streamlined acceleration
code in access.cc which does not have to check if CR0.PG
is set, eliminating a few instructions per guest access.
Shaved just a little off execution time, as expected.
Also, access_linear now breaks accesses which span two pages,
into two calls the the physical memory routines, when paging
is off, just like it always has for paging on. Besides
being more uniform, this allows the physical memory access
routines to known the complete data item is contained
within a single physical page, and stop reapplying the
A20ADDR() macro to pointers as it increments them.
Perhaps things can be optimized a little more now there too...
I renamed the routines to {read,write}PhysicalPage() as
a reminder that these routines now operate on data
solely within one page.
I also added a little code so that the paging module is
notified when the A20 line is tweaked, so it can dump
whatever mappings it wants to.
2002-09-05 06:31:24 +04:00
|
|
|
}
|
2007-12-10 22:08:13 +03:00
|
|
|
}
|
2007-11-20 20:15:33 +03:00
|
|
|
#endif
|
|
|
|
#if BX_SUPPORT_X86_64
|
2007-12-10 22:08:13 +03:00
|
|
|
if (! IsCanonical(laddr)) {
|
|
|
|
BX_ERROR(("read_virtual_dword(): canonical failure"));
|
|
|
|
exception(int_number(seg), 0, 0);
|
Integrated patches for:
- Paging code rehash. You must now use --enable-4meg-pages to
use 4Meg pages, with the default of disabled, since we don't well
support 4Meg pages yet. Paging table walks model a real CPU
more closely now, and I fixed some bugs in the old logic.
- Segment check redundancy elimination. After a segment is loaded,
reads and writes are marked when a segment type check succeeds, and
they are skipped thereafter, when possible.
- Repeated IO and memory string copy acceleration. Only some variants
of instructions are available on all platforms, word and dword
variants only on x86 for the moment due to alignment and endian issues.
This is compiled in currently with no option - I should add a configure
option.
- Added a guest linear address to host TLB. Actually, I just stick
the host address (mem.vector[addr] address) in the upper 29 bits
of the field 'combined_access' since they are unused. Convenient
for now. I'm only storing page frame addresses. This was the
simplest for of such a TLB. We can likely enhance this. Also,
I only accelerated the normal read/write routines in access.cc.
Could also modify the read-modify-write versions too. You must
use --enable-guest2host-tlb, to try this out. Currently speeds
up Win95 boot time by about 3.5% for me. More ground to cover...
- Minor mods to CPUI/MOV_CdRd for CMOV.
- Integrated enhancements from Volker to getHostMemAddr() for PCI
being enabled.
2002-09-02 00:12:09 +04:00
|
|
|
}
|
2007-12-10 22:08:13 +03:00
|
|
|
#endif
|
2007-12-20 23:58:38 +03:00
|
|
|
access_linear(laddr, 4, CPL, BX_READ, (void *) &data);
|
|
|
|
return data;
|
2007-12-10 22:08:13 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
if (seg->cache.valid & SegAccessROK) {
|
|
|
|
if (Is64BitMode() || (offset < (seg->cache.u.segment.limit_scaled-2)))
|
|
|
|
goto accessOK;
|
2005-01-25 23:41:43 +03:00
|
|
|
}
|
Integrated patches for:
- Paging code rehash. You must now use --enable-4meg-pages to
use 4Meg pages, with the default of disabled, since we don't well
support 4Meg pages yet. Paging table walks model a real CPU
more closely now, and I fixed some bugs in the old logic.
- Segment check redundancy elimination. After a segment is loaded,
reads and writes are marked when a segment type check succeeds, and
they are skipped thereafter, when possible.
- Repeated IO and memory string copy acceleration. Only some variants
of instructions are available on all platforms, word and dword
variants only on x86 for the moment due to alignment and endian issues.
This is compiled in currently with no option - I should add a configure
option.
- Added a guest linear address to host TLB. Actually, I just stick
the host address (mem.vector[addr] address) in the upper 29 bits
of the field 'combined_access' since they are unused. Convenient
for now. I'm only storing page frame addresses. This was the
simplest for of such a TLB. We can likely enhance this. Also,
I only accelerated the normal read/write routines in access.cc.
Could also modify the read-modify-write versions too. You must
use --enable-guest2host-tlb, to try this out. Currently speeds
up Win95 boot time by about 3.5% for me. More ground to cover...
- Minor mods to CPUI/MOV_CdRd for CMOV.
- Integrated enhancements from Volker to getHostMemAddr() for PCI
being enabled.
2002-09-02 00:12:09 +04:00
|
|
|
read_virtual_checks(seg, offset, 4);
|
|
|
|
goto accessOK;
|
2001-04-10 05:04:59 +04:00
|
|
|
}
|
|
|
|
|
2007-12-20 23:58:38 +03:00
|
|
|
Bit64u BX_CPP_AttrRegparmN(2)
|
|
|
|
BX_CPU_C::read_virtual_qword(unsigned s, bx_address offset)
|
2004-11-19 02:16:36 +03:00
|
|
|
{
|
|
|
|
bx_address laddr;
|
2007-12-10 22:08:13 +03:00
|
|
|
bx_segment_reg_t *seg = &BX_CPU_THIS_PTR sregs[s];
|
2007-12-20 23:58:38 +03:00
|
|
|
Bit64u data;
|
2004-11-19 02:16:36 +03:00
|
|
|
|
2007-12-10 22:08:13 +03:00
|
|
|
if ((seg->cache.valid & SegAccessROK4G) == SegAccessROK4G) {
|
2004-11-19 02:16:36 +03:00
|
|
|
accessOK:
|
2007-12-10 22:08:13 +03:00
|
|
|
laddr = BX_CPU_THIS_PTR get_segment_base(s) + offset;
|
|
|
|
BX_INSTR_MEM_DATA(BX_CPU_ID, laddr, 8, BX_READ);
|
2007-08-01 00:25:52 +04:00
|
|
|
#if BX_CPU_LEVEL >= 4 && BX_SUPPORT_ALIGNMENT_CHECK
|
2007-12-10 22:08:13 +03:00
|
|
|
if (BX_CPU_THIS_PTR alignment_check) {
|
|
|
|
if (laddr & 7) {
|
|
|
|
BX_ERROR(("read_virtual_qword(): #AC misaligned access"));
|
|
|
|
exception(BX_AC_EXCEPTION, 0, 0);
|
2007-08-01 00:25:52 +04:00
|
|
|
}
|
2007-12-10 22:08:13 +03:00
|
|
|
}
|
2007-08-01 00:25:52 +04:00
|
|
|
#endif
|
2004-11-19 02:16:36 +03:00
|
|
|
#if BX_SupportGuest2HostTLB
|
2007-12-21 13:33:39 +03:00
|
|
|
Bit32u 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) {
|
|
|
|
// See if the TLB entry privilege level allows us read access
|
|
|
|
// from this CPL.
|
|
|
|
if (tlbEntry->accessBits & (1<<CPL)) { // Read this pl OK.
|
|
|
|
bx_hostpageaddr_t hostPageAddr = tlbEntry->hostPageAddr;
|
|
|
|
Bit32u pageOffset = laddr & 0xfff;
|
|
|
|
BX_INSTR_LIN_ACCESS(BX_CPU_ID, laddr, tlbEntry->ppf | pageOffset, 8, BX_READ);
|
|
|
|
Bit64u *hostAddr = (Bit64u*) (hostPageAddr | pageOffset);
|
|
|
|
ReadHostQWordFromLittleEndian(hostAddr, data);
|
|
|
|
return data;
|
2004-11-19 02:16:36 +03:00
|
|
|
}
|
2007-12-10 22:08:13 +03:00
|
|
|
}
|
2007-11-20 20:15:33 +03:00
|
|
|
#endif
|
|
|
|
#if BX_SUPPORT_X86_64
|
2007-12-10 22:08:13 +03:00
|
|
|
if (! IsCanonical(laddr)) {
|
|
|
|
BX_ERROR(("read_virtual_qword(): canonical failure"));
|
|
|
|
exception(int_number(seg), 0, 0);
|
2004-11-19 02:16:36 +03:00
|
|
|
}
|
2007-12-10 22:08:13 +03:00
|
|
|
#endif
|
2007-12-20 23:58:38 +03:00
|
|
|
access_linear(laddr, 8, CPL, BX_READ, (void *) &data);
|
|
|
|
return data;
|
2007-12-10 22:08:13 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
if (seg->cache.valid & SegAccessROK) {
|
|
|
|
if (Is64BitMode() || (offset <= (seg->cache.u.segment.limit_scaled-7)))
|
|
|
|
goto accessOK;
|
2005-01-25 23:41:43 +03:00
|
|
|
}
|
2004-11-19 02:16:36 +03:00
|
|
|
read_virtual_checks(seg, offset, 8);
|
|
|
|
goto accessOK;
|
|
|
|
}
|
|
|
|
|
2001-04-10 05:04:59 +04:00
|
|
|
//////////////////////////////////////////////////////////////
|
|
|
|
// special Read-Modify-Write operations //
|
|
|
|
// address translation info is kept across read/write calls //
|
|
|
|
//////////////////////////////////////////////////////////////
|
|
|
|
|
2007-12-20 23:58:38 +03:00
|
|
|
Bit8u BX_CPP_AttrRegparmN(2)
|
|
|
|
BX_CPU_C::read_RMW_virtual_byte(unsigned s, bx_address offset)
|
2001-04-10 05:04:59 +04:00
|
|
|
{
|
2002-09-13 08:33:42 +04:00
|
|
|
bx_address laddr;
|
2007-12-10 22:08:13 +03:00
|
|
|
bx_segment_reg_t *seg = &BX_CPU_THIS_PTR sregs[s];
|
2007-12-20 23:58:38 +03:00
|
|
|
Bit8u data;
|
2001-04-10 05:04:59 +04:00
|
|
|
|
2007-12-10 22:08:13 +03:00
|
|
|
if ((seg->cache.valid & SegAccessWOK4G) == SegAccessWOK4G) {
|
Integrated patches for:
- Paging code rehash. You must now use --enable-4meg-pages to
use 4Meg pages, with the default of disabled, since we don't well
support 4Meg pages yet. Paging table walks model a real CPU
more closely now, and I fixed some bugs in the old logic.
- Segment check redundancy elimination. After a segment is loaded,
reads and writes are marked when a segment type check succeeds, and
they are skipped thereafter, when possible.
- Repeated IO and memory string copy acceleration. Only some variants
of instructions are available on all platforms, word and dword
variants only on x86 for the moment due to alignment and endian issues.
This is compiled in currently with no option - I should add a configure
option.
- Added a guest linear address to host TLB. Actually, I just stick
the host address (mem.vector[addr] address) in the upper 29 bits
of the field 'combined_access' since they are unused. Convenient
for now. I'm only storing page frame addresses. This was the
simplest for of such a TLB. We can likely enhance this. Also,
I only accelerated the normal read/write routines in access.cc.
Could also modify the read-modify-write versions too. You must
use --enable-guest2host-tlb, to try this out. Currently speeds
up Win95 boot time by about 3.5% for me. More ground to cover...
- Minor mods to CPUI/MOV_CdRd for CMOV.
- Integrated enhancements from Volker to getHostMemAddr() for PCI
being enabled.
2002-09-02 00:12:09 +04:00
|
|
|
accessOK:
|
2007-12-10 22:08:13 +03:00
|
|
|
laddr = BX_CPU_THIS_PTR get_segment_base(s) + offset;
|
|
|
|
BX_INSTR_MEM_DATA(BX_CPU_ID, laddr, 1, BX_RW);
|
2002-09-03 08:54:28 +04:00
|
|
|
#if BX_SupportGuest2HostTLB
|
2007-12-21 13:33:39 +03:00
|
|
|
Bit32u tlbIndex = BX_TLB_INDEX_OF(laddr, 0);
|
2007-12-10 22:08:13 +03:00
|
|
|
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.
|
2007-12-17 00:03:46 +03:00
|
|
|
if (tlbEntry->accessBits & (0x10 << CPL)) {
|
2007-12-10 22:08:13 +03:00
|
|
|
bx_hostpageaddr_t hostPageAddr = tlbEntry->hostPageAddr;
|
|
|
|
Bit32u pageOffset = laddr & 0xfff;
|
2007-12-14 00:30:05 +03:00
|
|
|
BX_INSTR_LIN_ACCESS(BX_CPU_ID, laddr, tlbEntry->ppf | pageOffset, 1, BX_RW);
|
2007-12-10 22:08:13 +03:00
|
|
|
Bit8u *hostAddr = (Bit8u*) (hostPageAddr | pageOffset);
|
2007-10-17 22:09:42 +04:00
|
|
|
#if BX_SUPPORT_ICACHE
|
2007-12-10 22:08:13 +03:00
|
|
|
pageWriteStampTable.decWriteStamp(tlbEntry->ppf);
|
2007-10-17 22:09:42 +04:00
|
|
|
#endif
|
2007-12-20 23:58:38 +03:00
|
|
|
data = *hostAddr;
|
2007-12-10 22:08:13 +03:00
|
|
|
BX_CPU_THIS_PTR address_xlation.pages = (bx_ptr_equiv_t) hostAddr;
|
2007-12-20 23:58:38 +03:00
|
|
|
return data;
|
Now, when you compile with --enable-guest2host-tlb, non-paged
mode uses the notion of the guest-to-host TLB. This has the
benefit of allowing more uniform and streamlined acceleration
code in access.cc which does not have to check if CR0.PG
is set, eliminating a few instructions per guest access.
Shaved just a little off execution time, as expected.
Also, access_linear now breaks accesses which span two pages,
into two calls the the physical memory routines, when paging
is off, just like it always has for paging on. Besides
being more uniform, this allows the physical memory access
routines to known the complete data item is contained
within a single physical page, and stop reapplying the
A20ADDR() macro to pointers as it increments them.
Perhaps things can be optimized a little more now there too...
I renamed the routines to {read,write}PhysicalPage() as
a reminder that these routines now operate on data
solely within one page.
I also added a little code so that the paging module is
notified when the A20 line is tweaked, so it can dump
whatever mappings it wants to.
2002-09-05 06:31:24 +04:00
|
|
|
}
|
2007-12-10 22:08:13 +03:00
|
|
|
}
|
2005-08-24 00:01:54 +04:00
|
|
|
#endif
|
2007-12-10 22:08:13 +03:00
|
|
|
// Accelerated attempt falls through to long path. Do it the
|
|
|
|
// old fashioned way...
|
2007-11-20 20:15:33 +03:00
|
|
|
#if BX_SUPPORT_X86_64
|
2007-12-10 22:08:13 +03:00
|
|
|
if (! IsCanonical(laddr)) {
|
|
|
|
BX_ERROR(("read_RMW_virtual_byte(): canonical failure"));
|
|
|
|
exception(int_number(seg), 0, 0);
|
2001-04-10 05:04:59 +04:00
|
|
|
}
|
2007-12-10 22:08:13 +03:00
|
|
|
#endif
|
2007-12-20 23:58:38 +03:00
|
|
|
access_linear(laddr, 1, CPL, BX_RW, (void *) &data);
|
|
|
|
return data;
|
2007-12-10 22:08:13 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
if (seg->cache.valid & SegAccessWOK) {
|
|
|
|
if (Is64BitMode() || (offset <= seg->cache.u.segment.limit_scaled))
|
|
|
|
goto accessOK;
|
2004-11-19 02:16:36 +03:00
|
|
|
}
|
Integrated patches for:
- Paging code rehash. You must now use --enable-4meg-pages to
use 4Meg pages, with the default of disabled, since we don't well
support 4Meg pages yet. Paging table walks model a real CPU
more closely now, and I fixed some bugs in the old logic.
- Segment check redundancy elimination. After a segment is loaded,
reads and writes are marked when a segment type check succeeds, and
they are skipped thereafter, when possible.
- Repeated IO and memory string copy acceleration. Only some variants
of instructions are available on all platforms, word and dword
variants only on x86 for the moment due to alignment and endian issues.
This is compiled in currently with no option - I should add a configure
option.
- Added a guest linear address to host TLB. Actually, I just stick
the host address (mem.vector[addr] address) in the upper 29 bits
of the field 'combined_access' since they are unused. Convenient
for now. I'm only storing page frame addresses. This was the
simplest for of such a TLB. We can likely enhance this. Also,
I only accelerated the normal read/write routines in access.cc.
Could also modify the read-modify-write versions too. You must
use --enable-guest2host-tlb, to try this out. Currently speeds
up Win95 boot time by about 3.5% for me. More ground to cover...
- Minor mods to CPUI/MOV_CdRd for CMOV.
- Integrated enhancements from Volker to getHostMemAddr() for PCI
being enabled.
2002-09-02 00:12:09 +04:00
|
|
|
write_virtual_checks(seg, offset, 1);
|
|
|
|
goto accessOK;
|
2001-04-10 05:04:59 +04:00
|
|
|
}
|
|
|
|
|
2007-12-20 23:58:38 +03:00
|
|
|
Bit16u BX_CPP_AttrRegparmN(2)
|
|
|
|
BX_CPU_C::read_RMW_virtual_word(unsigned s, bx_address offset)
|
2001-04-10 05:04:59 +04:00
|
|
|
{
|
2002-09-13 08:33:42 +04:00
|
|
|
bx_address laddr;
|
2007-12-10 22:08:13 +03:00
|
|
|
bx_segment_reg_t *seg = &BX_CPU_THIS_PTR sregs[s];
|
2007-12-20 23:58:38 +03:00
|
|
|
Bit16u data;
|
2001-04-10 05:04:59 +04:00
|
|
|
|
2007-12-10 22:08:13 +03:00
|
|
|
if ((seg->cache.valid & SegAccessWOK4G) == SegAccessWOK4G) {
|
Integrated patches for:
- Paging code rehash. You must now use --enable-4meg-pages to
use 4Meg pages, with the default of disabled, since we don't well
support 4Meg pages yet. Paging table walks model a real CPU
more closely now, and I fixed some bugs in the old logic.
- Segment check redundancy elimination. After a segment is loaded,
reads and writes are marked when a segment type check succeeds, and
they are skipped thereafter, when possible.
- Repeated IO and memory string copy acceleration. Only some variants
of instructions are available on all platforms, word and dword
variants only on x86 for the moment due to alignment and endian issues.
This is compiled in currently with no option - I should add a configure
option.
- Added a guest linear address to host TLB. Actually, I just stick
the host address (mem.vector[addr] address) in the upper 29 bits
of the field 'combined_access' since they are unused. Convenient
for now. I'm only storing page frame addresses. This was the
simplest for of such a TLB. We can likely enhance this. Also,
I only accelerated the normal read/write routines in access.cc.
Could also modify the read-modify-write versions too. You must
use --enable-guest2host-tlb, to try this out. Currently speeds
up Win95 boot time by about 3.5% for me. More ground to cover...
- Minor mods to CPUI/MOV_CdRd for CMOV.
- Integrated enhancements from Volker to getHostMemAddr() for PCI
being enabled.
2002-09-02 00:12:09 +04:00
|
|
|
accessOK:
|
2007-12-10 22:08:13 +03:00
|
|
|
laddr = BX_CPU_THIS_PTR get_segment_base(s) + offset;
|
|
|
|
BX_INSTR_MEM_DATA(BX_CPU_ID, laddr, 2, BX_RW);
|
2007-08-01 00:25:52 +04:00
|
|
|
#if BX_CPU_LEVEL >= 4 && BX_SUPPORT_ALIGNMENT_CHECK
|
2007-12-10 22:08:13 +03:00
|
|
|
if (BX_CPU_THIS_PTR alignment_check) {
|
|
|
|
if (laddr & 1) {
|
|
|
|
BX_ERROR(("read_RMW_virtual_word(): #AC misaligned access"));
|
|
|
|
exception(BX_AC_EXCEPTION, 0, 0);
|
2007-08-01 00:25:52 +04:00
|
|
|
}
|
2007-12-10 22:08:13 +03:00
|
|
|
}
|
2007-08-01 00:25:52 +04:00
|
|
|
#endif
|
2002-09-03 08:54:28 +04:00
|
|
|
#if BX_SupportGuest2HostTLB
|
2007-12-21 13:33:39 +03:00
|
|
|
Bit32u 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) {
|
|
|
|
// See if the TLB entry privilege level allows us write access
|
|
|
|
// from this CPL.
|
|
|
|
if (tlbEntry->accessBits & (0x10 << CPL)) {
|
|
|
|
bx_hostpageaddr_t hostPageAddr = tlbEntry->hostPageAddr;
|
|
|
|
Bit32u pageOffset = laddr & 0xfff;
|
|
|
|
BX_INSTR_LIN_ACCESS(BX_CPU_ID, laddr, tlbEntry->ppf | pageOffset, 2, BX_RW);
|
|
|
|
Bit16u *hostAddr = (Bit16u*) (hostPageAddr | pageOffset);
|
2007-10-17 22:09:42 +04:00
|
|
|
#if BX_SUPPORT_ICACHE
|
2007-12-21 13:33:39 +03:00
|
|
|
pageWriteStampTable.decWriteStamp(tlbEntry->ppf);
|
2007-10-17 22:09:42 +04:00
|
|
|
#endif
|
2007-12-21 13:33:39 +03:00
|
|
|
ReadHostWordFromLittleEndian(hostAddr, data);
|
|
|
|
BX_CPU_THIS_PTR address_xlation.pages = (bx_ptr_equiv_t) hostAddr;
|
|
|
|
return data;
|
Now, when you compile with --enable-guest2host-tlb, non-paged
mode uses the notion of the guest-to-host TLB. This has the
benefit of allowing more uniform and streamlined acceleration
code in access.cc which does not have to check if CR0.PG
is set, eliminating a few instructions per guest access.
Shaved just a little off execution time, as expected.
Also, access_linear now breaks accesses which span two pages,
into two calls the the physical memory routines, when paging
is off, just like it always has for paging on. Besides
being more uniform, this allows the physical memory access
routines to known the complete data item is contained
within a single physical page, and stop reapplying the
A20ADDR() macro to pointers as it increments them.
Perhaps things can be optimized a little more now there too...
I renamed the routines to {read,write}PhysicalPage() as
a reminder that these routines now operate on data
solely within one page.
I also added a little code so that the paging module is
notified when the A20 line is tweaked, so it can dump
whatever mappings it wants to.
2002-09-05 06:31:24 +04:00
|
|
|
}
|
2007-12-10 22:08:13 +03:00
|
|
|
}
|
2007-11-20 20:15:33 +03:00
|
|
|
#endif
|
|
|
|
#if BX_SUPPORT_X86_64
|
2007-12-10 22:08:13 +03:00
|
|
|
if (! IsCanonical(laddr)) {
|
|
|
|
BX_ERROR(("read_RMW_virtual_word(): canonical failure"));
|
|
|
|
exception(int_number(seg), 0, 0);
|
2001-04-10 05:04:59 +04:00
|
|
|
}
|
2007-12-10 22:08:13 +03:00
|
|
|
#endif
|
2007-12-20 23:58:38 +03:00
|
|
|
access_linear(laddr, 2, CPL, BX_RW, (void *) &data);
|
|
|
|
return data;
|
2007-12-10 22:08:13 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
if (seg->cache.valid & SegAccessWOK) {
|
|
|
|
if (Is64BitMode() || (offset < seg->cache.u.segment.limit_scaled))
|
|
|
|
goto accessOK;
|
2004-11-19 02:16:36 +03:00
|
|
|
}
|
Integrated patches for:
- Paging code rehash. You must now use --enable-4meg-pages to
use 4Meg pages, with the default of disabled, since we don't well
support 4Meg pages yet. Paging table walks model a real CPU
more closely now, and I fixed some bugs in the old logic.
- Segment check redundancy elimination. After a segment is loaded,
reads and writes are marked when a segment type check succeeds, and
they are skipped thereafter, when possible.
- Repeated IO and memory string copy acceleration. Only some variants
of instructions are available on all platforms, word and dword
variants only on x86 for the moment due to alignment and endian issues.
This is compiled in currently with no option - I should add a configure
option.
- Added a guest linear address to host TLB. Actually, I just stick
the host address (mem.vector[addr] address) in the upper 29 bits
of the field 'combined_access' since they are unused. Convenient
for now. I'm only storing page frame addresses. This was the
simplest for of such a TLB. We can likely enhance this. Also,
I only accelerated the normal read/write routines in access.cc.
Could also modify the read-modify-write versions too. You must
use --enable-guest2host-tlb, to try this out. Currently speeds
up Win95 boot time by about 3.5% for me. More ground to cover...
- Minor mods to CPUI/MOV_CdRd for CMOV.
- Integrated enhancements from Volker to getHostMemAddr() for PCI
being enabled.
2002-09-02 00:12:09 +04:00
|
|
|
write_virtual_checks(seg, offset, 2);
|
|
|
|
goto accessOK;
|
2001-04-10 05:04:59 +04:00
|
|
|
}
|
|
|
|
|
2007-12-20 23:58:38 +03:00
|
|
|
Bit32u BX_CPP_AttrRegparmN(2)
|
|
|
|
BX_CPU_C::read_RMW_virtual_dword(unsigned s, bx_address offset)
|
2001-04-10 05:04:59 +04:00
|
|
|
{
|
2002-09-13 08:33:42 +04:00
|
|
|
bx_address laddr;
|
2007-12-10 22:08:13 +03:00
|
|
|
bx_segment_reg_t *seg = &BX_CPU_THIS_PTR sregs[s];
|
2007-12-20 23:58:38 +03:00
|
|
|
Bit32u data;
|
2001-04-10 05:04:59 +04:00
|
|
|
|
2007-12-10 22:08:13 +03:00
|
|
|
if ((seg->cache.valid & SegAccessWOK4G) == SegAccessWOK4G) {
|
Integrated patches for:
- Paging code rehash. You must now use --enable-4meg-pages to
use 4Meg pages, with the default of disabled, since we don't well
support 4Meg pages yet. Paging table walks model a real CPU
more closely now, and I fixed some bugs in the old logic.
- Segment check redundancy elimination. After a segment is loaded,
reads and writes are marked when a segment type check succeeds, and
they are skipped thereafter, when possible.
- Repeated IO and memory string copy acceleration. Only some variants
of instructions are available on all platforms, word and dword
variants only on x86 for the moment due to alignment and endian issues.
This is compiled in currently with no option - I should add a configure
option.
- Added a guest linear address to host TLB. Actually, I just stick
the host address (mem.vector[addr] address) in the upper 29 bits
of the field 'combined_access' since they are unused. Convenient
for now. I'm only storing page frame addresses. This was the
simplest for of such a TLB. We can likely enhance this. Also,
I only accelerated the normal read/write routines in access.cc.
Could also modify the read-modify-write versions too. You must
use --enable-guest2host-tlb, to try this out. Currently speeds
up Win95 boot time by about 3.5% for me. More ground to cover...
- Minor mods to CPUI/MOV_CdRd for CMOV.
- Integrated enhancements from Volker to getHostMemAddr() for PCI
being enabled.
2002-09-02 00:12:09 +04:00
|
|
|
accessOK:
|
2007-12-10 22:08:13 +03:00
|
|
|
laddr = BX_CPU_THIS_PTR get_segment_base(s) + offset;
|
|
|
|
BX_INSTR_MEM_DATA(BX_CPU_ID, laddr, 4, BX_RW);
|
2007-08-01 00:25:52 +04:00
|
|
|
#if BX_CPU_LEVEL >= 4 && BX_SUPPORT_ALIGNMENT_CHECK
|
2007-12-10 22:08:13 +03:00
|
|
|
if (BX_CPU_THIS_PTR alignment_check) {
|
|
|
|
if (laddr & 3) {
|
|
|
|
BX_ERROR(("read_RMW_virtual_dword(): #AC misaligned access"));
|
|
|
|
exception(BX_AC_EXCEPTION, 0, 0);
|
2007-08-01 00:25:52 +04:00
|
|
|
}
|
2007-12-10 22:08:13 +03:00
|
|
|
}
|
2007-08-01 00:25:52 +04:00
|
|
|
#endif
|
2002-09-03 08:54:28 +04:00
|
|
|
#if BX_SupportGuest2HostTLB
|
2007-12-21 13:33:39 +03:00
|
|
|
Bit32u 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) {
|
|
|
|
// See if the TLB entry privilege level allows us write access
|
|
|
|
// from this CPL.
|
|
|
|
if (tlbEntry->accessBits & (0x10 << CPL)) {
|
|
|
|
bx_hostpageaddr_t hostPageAddr = tlbEntry->hostPageAddr;
|
|
|
|
Bit32u pageOffset = laddr & 0xfff;
|
|
|
|
BX_INSTR_LIN_ACCESS(BX_CPU_ID, laddr, tlbEntry->ppf | pageOffset, 4, BX_RW);
|
|
|
|
Bit32u *hostAddr = (Bit32u*) (hostPageAddr | pageOffset);
|
2007-10-17 22:09:42 +04:00
|
|
|
#if BX_SUPPORT_ICACHE
|
2007-12-21 13:33:39 +03:00
|
|
|
pageWriteStampTable.decWriteStamp(tlbEntry->ppf);
|
2007-10-17 22:09:42 +04:00
|
|
|
#endif
|
2007-12-21 13:33:39 +03:00
|
|
|
ReadHostDWordFromLittleEndian(hostAddr, data);
|
|
|
|
BX_CPU_THIS_PTR address_xlation.pages = (bx_ptr_equiv_t) hostAddr;
|
|
|
|
return data;
|
Now, when you compile with --enable-guest2host-tlb, non-paged
mode uses the notion of the guest-to-host TLB. This has the
benefit of allowing more uniform and streamlined acceleration
code in access.cc which does not have to check if CR0.PG
is set, eliminating a few instructions per guest access.
Shaved just a little off execution time, as expected.
Also, access_linear now breaks accesses which span two pages,
into two calls the the physical memory routines, when paging
is off, just like it always has for paging on. Besides
being more uniform, this allows the physical memory access
routines to known the complete data item is contained
within a single physical page, and stop reapplying the
A20ADDR() macro to pointers as it increments them.
Perhaps things can be optimized a little more now there too...
I renamed the routines to {read,write}PhysicalPage() as
a reminder that these routines now operate on data
solely within one page.
I also added a little code so that the paging module is
notified when the A20 line is tweaked, so it can dump
whatever mappings it wants to.
2002-09-05 06:31:24 +04:00
|
|
|
}
|
2007-12-10 22:08:13 +03:00
|
|
|
}
|
2007-11-20 20:15:33 +03:00
|
|
|
#endif
|
|
|
|
#if BX_SUPPORT_X86_64
|
2007-12-10 22:08:13 +03:00
|
|
|
if (! IsCanonical(laddr)) {
|
|
|
|
BX_ERROR(("read_RMW_virtual_dword(): canonical failure"));
|
|
|
|
exception(int_number(seg), 0, 0);
|
2001-04-10 05:04:59 +04:00
|
|
|
}
|
2007-12-10 22:08:13 +03:00
|
|
|
#endif
|
2007-12-20 23:58:38 +03:00
|
|
|
access_linear(laddr, 4, CPL, BX_RW, (void *) &data);
|
|
|
|
return data;
|
2007-12-10 22:08:13 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
if (seg->cache.valid & SegAccessWOK) {
|
|
|
|
if (Is64BitMode() || (offset < (seg->cache.u.segment.limit_scaled-2)))
|
|
|
|
goto accessOK;
|
2004-11-19 02:16:36 +03:00
|
|
|
}
|
Integrated patches for:
- Paging code rehash. You must now use --enable-4meg-pages to
use 4Meg pages, with the default of disabled, since we don't well
support 4Meg pages yet. Paging table walks model a real CPU
more closely now, and I fixed some bugs in the old logic.
- Segment check redundancy elimination. After a segment is loaded,
reads and writes are marked when a segment type check succeeds, and
they are skipped thereafter, when possible.
- Repeated IO and memory string copy acceleration. Only some variants
of instructions are available on all platforms, word and dword
variants only on x86 for the moment due to alignment and endian issues.
This is compiled in currently with no option - I should add a configure
option.
- Added a guest linear address to host TLB. Actually, I just stick
the host address (mem.vector[addr] address) in the upper 29 bits
of the field 'combined_access' since they are unused. Convenient
for now. I'm only storing page frame addresses. This was the
simplest for of such a TLB. We can likely enhance this. Also,
I only accelerated the normal read/write routines in access.cc.
Could also modify the read-modify-write versions too. You must
use --enable-guest2host-tlb, to try this out. Currently speeds
up Win95 boot time by about 3.5% for me. More ground to cover...
- Minor mods to CPUI/MOV_CdRd for CMOV.
- Integrated enhancements from Volker to getHostMemAddr() for PCI
being enabled.
2002-09-02 00:12:09 +04:00
|
|
|
write_virtual_checks(seg, offset, 4);
|
|
|
|
goto accessOK;
|
2001-04-10 05:04:59 +04:00
|
|
|
}
|
|
|
|
|
2007-12-20 23:58:38 +03:00
|
|
|
Bit64u BX_CPP_AttrRegparmN(2)
|
|
|
|
BX_CPU_C::read_RMW_virtual_qword(unsigned s, bx_address offset)
|
2004-11-19 02:16:36 +03:00
|
|
|
{
|
|
|
|
bx_address laddr;
|
2007-12-10 22:08:13 +03:00
|
|
|
bx_segment_reg_t *seg = &BX_CPU_THIS_PTR sregs[s];
|
2007-12-20 23:58:38 +03:00
|
|
|
Bit64u data;
|
2004-11-19 02:16:36 +03:00
|
|
|
|
2007-12-10 22:08:13 +03:00
|
|
|
if ((seg->cache.valid & SegAccessWOK4G) == SegAccessWOK4G) {
|
2004-11-19 02:16:36 +03:00
|
|
|
accessOK:
|
2007-12-10 22:08:13 +03:00
|
|
|
laddr = BX_CPU_THIS_PTR get_segment_base(s) + offset;
|
|
|
|
BX_INSTR_MEM_DATA(BX_CPU_ID, laddr, 8, BX_RW);
|
2007-08-01 00:25:52 +04:00
|
|
|
#if BX_CPU_LEVEL >= 4 && BX_SUPPORT_ALIGNMENT_CHECK
|
2007-12-10 22:08:13 +03:00
|
|
|
if (BX_CPU_THIS_PTR alignment_check) {
|
|
|
|
if (laddr & 7) {
|
|
|
|
BX_ERROR(("read_RMW_virtual_qword(): #AC misaligned access"));
|
|
|
|
exception(BX_AC_EXCEPTION, 0, 0);
|
2007-08-01 00:25:52 +04:00
|
|
|
}
|
2007-12-10 22:08:13 +03:00
|
|
|
}
|
2007-08-01 00:25:52 +04:00
|
|
|
#endif
|
2004-11-19 02:16:36 +03:00
|
|
|
#if BX_SupportGuest2HostTLB
|
2007-12-21 13:33:39 +03:00
|
|
|
Bit32u 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) {
|
|
|
|
// See if the TLB entry privilege level allows us write access
|
|
|
|
// from this CPL.
|
|
|
|
if (tlbEntry->accessBits & (0x10 << CPL)) {
|
|
|
|
bx_hostpageaddr_t hostPageAddr = tlbEntry->hostPageAddr;
|
|
|
|
Bit32u pageOffset = laddr & 0xfff;
|
|
|
|
BX_INSTR_LIN_ACCESS(BX_CPU_ID, laddr, tlbEntry->ppf | pageOffset, 8, BX_RW);
|
|
|
|
Bit64u *hostAddr = (Bit64u*) (hostPageAddr | pageOffset);
|
2007-10-17 22:09:42 +04:00
|
|
|
#if BX_SUPPORT_ICACHE
|
2007-12-21 13:33:39 +03:00
|
|
|
pageWriteStampTable.decWriteStamp(tlbEntry->ppf);
|
2007-10-17 22:09:42 +04:00
|
|
|
#endif
|
2007-12-21 13:33:39 +03:00
|
|
|
ReadHostQWordFromLittleEndian(hostAddr, data);
|
|
|
|
BX_CPU_THIS_PTR address_xlation.pages = (bx_ptr_equiv_t) hostAddr;
|
|
|
|
return data;
|
2004-11-19 02:16:36 +03:00
|
|
|
}
|
2007-12-10 22:08:13 +03:00
|
|
|
}
|
2007-11-20 20:15:33 +03:00
|
|
|
#endif
|
|
|
|
#if BX_SUPPORT_X86_64
|
2007-12-10 22:08:13 +03:00
|
|
|
if (! IsCanonical(laddr)) {
|
|
|
|
BX_ERROR(("read_RMW_virtual_qword(): canonical failure"));
|
|
|
|
exception(int_number(seg), 0, 0);
|
2004-11-19 02:16:36 +03:00
|
|
|
}
|
2007-12-10 22:08:13 +03:00
|
|
|
#endif
|
2007-12-20 23:58:38 +03:00
|
|
|
access_linear(laddr, 8, CPL, BX_RW, (void *) &data);
|
|
|
|
return data;
|
2007-12-10 22:08:13 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
if (seg->cache.valid & SegAccessWOK) {
|
|
|
|
if (Is64BitMode() || (offset <= (seg->cache.u.segment.limit_scaled-7)))
|
|
|
|
goto accessOK;
|
2004-11-19 02:16:36 +03:00
|
|
|
}
|
|
|
|
write_virtual_checks(seg, offset, 8);
|
|
|
|
goto accessOK;
|
|
|
|
}
|
|
|
|
|
2003-03-03 02:59:12 +03:00
|
|
|
void BX_CPP_AttrRegparmN(1)
|
2001-04-10 05:04:59 +04:00
|
|
|
BX_CPU_C::write_RMW_virtual_byte(Bit8u val8)
|
|
|
|
{
|
2002-09-07 01:54:58 +04:00
|
|
|
if (BX_CPU_THIS_PTR address_xlation.pages > 2) {
|
|
|
|
// Pages > 2 means it stores a host address for direct access.
|
2004-09-14 00:48:11 +04:00
|
|
|
Bit8u *hostAddr = (Bit8u *) BX_CPU_THIS_PTR address_xlation.pages;
|
|
|
|
*hostAddr = val8;
|
2005-01-25 23:41:43 +03:00
|
|
|
}
|
2002-09-07 01:54:58 +04:00
|
|
|
else {
|
|
|
|
// address_xlation.pages must be 1
|
2004-11-05 13:13:15 +03:00
|
|
|
BX_CPU_THIS_PTR mem->writePhysicalPage(BX_CPU_THIS,
|
2002-09-07 01:54:58 +04:00
|
|
|
BX_CPU_THIS_PTR address_xlation.paddress1, 1, &val8);
|
2005-01-25 23:41:43 +03:00
|
|
|
}
|
2001-04-10 05:04:59 +04:00
|
|
|
}
|
|
|
|
|
2003-03-03 02:59:12 +03:00
|
|
|
void BX_CPP_AttrRegparmN(1)
|
2001-04-10 05:04:59 +04:00
|
|
|
BX_CPU_C::write_RMW_virtual_word(Bit16u val16)
|
|
|
|
{
|
2002-09-07 01:54:58 +04:00
|
|
|
if (BX_CPU_THIS_PTR address_xlation.pages > 2) {
|
|
|
|
// Pages > 2 means it stores a host address for direct access.
|
|
|
|
Bit16u *hostAddr = (Bit16u *) BX_CPU_THIS_PTR address_xlation.pages;
|
|
|
|
WriteHostWordToLittleEndian(hostAddr, val16);
|
2005-01-25 23:41:43 +03:00
|
|
|
}
|
2002-09-07 01:54:58 +04:00
|
|
|
else if (BX_CPU_THIS_PTR address_xlation.pages == 1) {
|
2004-11-05 13:13:15 +03:00
|
|
|
BX_CPU_THIS_PTR mem->writePhysicalPage(BX_CPU_THIS,
|
Now, when you compile with --enable-guest2host-tlb, non-paged
mode uses the notion of the guest-to-host TLB. This has the
benefit of allowing more uniform and streamlined acceleration
code in access.cc which does not have to check if CR0.PG
is set, eliminating a few instructions per guest access.
Shaved just a little off execution time, as expected.
Also, access_linear now breaks accesses which span two pages,
into two calls the the physical memory routines, when paging
is off, just like it always has for paging on. Besides
being more uniform, this allows the physical memory access
routines to known the complete data item is contained
within a single physical page, and stop reapplying the
A20ADDR() macro to pointers as it increments them.
Perhaps things can be optimized a little more now there too...
I renamed the routines to {read,write}PhysicalPage() as
a reminder that these routines now operate on data
solely within one page.
I also added a little code so that the paging module is
notified when the A20 line is tweaked, so it can dump
whatever mappings it wants to.
2002-09-05 06:31:24 +04:00
|
|
|
BX_CPU_THIS_PTR address_xlation.paddress1, 2, &val16);
|
2005-01-25 23:41:43 +03:00
|
|
|
}
|
Now, when you compile with --enable-guest2host-tlb, non-paged
mode uses the notion of the guest-to-host TLB. This has the
benefit of allowing more uniform and streamlined acceleration
code in access.cc which does not have to check if CR0.PG
is set, eliminating a few instructions per guest access.
Shaved just a little off execution time, as expected.
Also, access_linear now breaks accesses which span two pages,
into two calls the the physical memory routines, when paging
is off, just like it always has for paging on. Besides
being more uniform, this allows the physical memory access
routines to known the complete data item is contained
within a single physical page, and stop reapplying the
A20ADDR() macro to pointers as it increments them.
Perhaps things can be optimized a little more now there too...
I renamed the routines to {read,write}PhysicalPage() as
a reminder that these routines now operate on data
solely within one page.
I also added a little code so that the paging module is
notified when the A20 line is tweaked, so it can dump
whatever mappings it wants to.
2002-09-05 06:31:24 +04:00
|
|
|
else {
|
2001-04-10 05:04:59 +04:00
|
|
|
#ifdef BX_LITTLE_ENDIAN
|
2004-11-05 13:13:15 +03:00
|
|
|
BX_CPU_THIS_PTR mem->writePhysicalPage(BX_CPU_THIS,
|
Now, when you compile with --enable-guest2host-tlb, non-paged
mode uses the notion of the guest-to-host TLB. This has the
benefit of allowing more uniform and streamlined acceleration
code in access.cc which does not have to check if CR0.PG
is set, eliminating a few instructions per guest access.
Shaved just a little off execution time, as expected.
Also, access_linear now breaks accesses which span two pages,
into two calls the the physical memory routines, when paging
is off, just like it always has for paging on. Besides
being more uniform, this allows the physical memory access
routines to known the complete data item is contained
within a single physical page, and stop reapplying the
A20ADDR() macro to pointers as it increments them.
Perhaps things can be optimized a little more now there too...
I renamed the routines to {read,write}PhysicalPage() as
a reminder that these routines now operate on data
solely within one page.
I also added a little code so that the paging module is
notified when the A20 line is tweaked, so it can dump
whatever mappings it wants to.
2002-09-05 06:31:24 +04:00
|
|
|
BX_CPU_THIS_PTR address_xlation.paddress1, 1, &val16);
|
2004-11-05 13:13:15 +03:00
|
|
|
BX_CPU_THIS_PTR mem->writePhysicalPage(BX_CPU_THIS,
|
Now, when you compile with --enable-guest2host-tlb, non-paged
mode uses the notion of the guest-to-host TLB. This has the
benefit of allowing more uniform and streamlined acceleration
code in access.cc which does not have to check if CR0.PG
is set, eliminating a few instructions per guest access.
Shaved just a little off execution time, as expected.
Also, access_linear now breaks accesses which span two pages,
into two calls the the physical memory routines, when paging
is off, just like it always has for paging on. Besides
being more uniform, this allows the physical memory access
routines to known the complete data item is contained
within a single physical page, and stop reapplying the
A20ADDR() macro to pointers as it increments them.
Perhaps things can be optimized a little more now there too...
I renamed the routines to {read,write}PhysicalPage() as
a reminder that these routines now operate on data
solely within one page.
I also added a little code so that the paging module is
notified when the A20 line is tweaked, so it can dump
whatever mappings it wants to.
2002-09-05 06:31:24 +04:00
|
|
|
BX_CPU_THIS_PTR address_xlation.paddress2, 1, ((Bit8u *) &val16) + 1);
|
2001-04-10 05:04:59 +04:00
|
|
|
#else
|
2004-11-05 13:13:15 +03:00
|
|
|
BX_CPU_THIS_PTR mem->writePhysicalPage(BX_CPU_THIS,
|
Now, when you compile with --enable-guest2host-tlb, non-paged
mode uses the notion of the guest-to-host TLB. This has the
benefit of allowing more uniform and streamlined acceleration
code in access.cc which does not have to check if CR0.PG
is set, eliminating a few instructions per guest access.
Shaved just a little off execution time, as expected.
Also, access_linear now breaks accesses which span two pages,
into two calls the the physical memory routines, when paging
is off, just like it always has for paging on. Besides
being more uniform, this allows the physical memory access
routines to known the complete data item is contained
within a single physical page, and stop reapplying the
A20ADDR() macro to pointers as it increments them.
Perhaps things can be optimized a little more now there too...
I renamed the routines to {read,write}PhysicalPage() as
a reminder that these routines now operate on data
solely within one page.
I also added a little code so that the paging module is
notified when the A20 line is tweaked, so it can dump
whatever mappings it wants to.
2002-09-05 06:31:24 +04:00
|
|
|
BX_CPU_THIS_PTR address_xlation.paddress1, 1, ((Bit8u *) &val16) + 1);
|
2004-11-05 13:13:15 +03:00
|
|
|
BX_CPU_THIS_PTR mem->writePhysicalPage(BX_CPU_THIS,
|
Now, when you compile with --enable-guest2host-tlb, non-paged
mode uses the notion of the guest-to-host TLB. This has the
benefit of allowing more uniform and streamlined acceleration
code in access.cc which does not have to check if CR0.PG
is set, eliminating a few instructions per guest access.
Shaved just a little off execution time, as expected.
Also, access_linear now breaks accesses which span two pages,
into two calls the the physical memory routines, when paging
is off, just like it always has for paging on. Besides
being more uniform, this allows the physical memory access
routines to known the complete data item is contained
within a single physical page, and stop reapplying the
A20ADDR() macro to pointers as it increments them.
Perhaps things can be optimized a little more now there too...
I renamed the routines to {read,write}PhysicalPage() as
a reminder that these routines now operate on data
solely within one page.
I also added a little code so that the paging module is
notified when the A20 line is tweaked, so it can dump
whatever mappings it wants to.
2002-09-05 06:31:24 +04:00
|
|
|
BX_CPU_THIS_PTR address_xlation.paddress2, 1, &val16);
|
2001-04-10 05:04:59 +04:00
|
|
|
#endif
|
2005-01-25 23:41:43 +03:00
|
|
|
}
|
2001-04-10 05:04:59 +04:00
|
|
|
}
|
|
|
|
|
2005-08-24 00:01:54 +04:00
|
|
|
void BX_CPP_AttrRegparmN(1)
|
2001-04-10 05:04:59 +04:00
|
|
|
BX_CPU_C::write_RMW_virtual_dword(Bit32u val32)
|
|
|
|
{
|
2002-09-07 01:54:58 +04:00
|
|
|
if (BX_CPU_THIS_PTR address_xlation.pages > 2) {
|
|
|
|
// Pages > 2 means it stores a host address for direct access.
|
|
|
|
Bit32u *hostAddr = (Bit32u *) BX_CPU_THIS_PTR address_xlation.pages;
|
|
|
|
WriteHostDWordToLittleEndian(hostAddr, val32);
|
2005-01-25 23:41:43 +03:00
|
|
|
}
|
2002-09-07 01:54:58 +04:00
|
|
|
else if (BX_CPU_THIS_PTR address_xlation.pages == 1) {
|
2004-11-05 13:13:15 +03:00
|
|
|
BX_CPU_THIS_PTR mem->writePhysicalPage(BX_CPU_THIS,
|
Now, when you compile with --enable-guest2host-tlb, non-paged
mode uses the notion of the guest-to-host TLB. This has the
benefit of allowing more uniform and streamlined acceleration
code in access.cc which does not have to check if CR0.PG
is set, eliminating a few instructions per guest access.
Shaved just a little off execution time, as expected.
Also, access_linear now breaks accesses which span two pages,
into two calls the the physical memory routines, when paging
is off, just like it always has for paging on. Besides
being more uniform, this allows the physical memory access
routines to known the complete data item is contained
within a single physical page, and stop reapplying the
A20ADDR() macro to pointers as it increments them.
Perhaps things can be optimized a little more now there too...
I renamed the routines to {read,write}PhysicalPage() as
a reminder that these routines now operate on data
solely within one page.
I also added a little code so that the paging module is
notified when the A20 line is tweaked, so it can dump
whatever mappings it wants to.
2002-09-05 06:31:24 +04:00
|
|
|
BX_CPU_THIS_PTR address_xlation.paddress1, 4, &val32);
|
2005-01-25 23:41:43 +03:00
|
|
|
}
|
Now, when you compile with --enable-guest2host-tlb, non-paged
mode uses the notion of the guest-to-host TLB. This has the
benefit of allowing more uniform and streamlined acceleration
code in access.cc which does not have to check if CR0.PG
is set, eliminating a few instructions per guest access.
Shaved just a little off execution time, as expected.
Also, access_linear now breaks accesses which span two pages,
into two calls the the physical memory routines, when paging
is off, just like it always has for paging on. Besides
being more uniform, this allows the physical memory access
routines to known the complete data item is contained
within a single physical page, and stop reapplying the
A20ADDR() macro to pointers as it increments them.
Perhaps things can be optimized a little more now there too...
I renamed the routines to {read,write}PhysicalPage() as
a reminder that these routines now operate on data
solely within one page.
I also added a little code so that the paging module is
notified when the A20 line is tweaked, so it can dump
whatever mappings it wants to.
2002-09-05 06:31:24 +04:00
|
|
|
else {
|
2001-04-10 05:04:59 +04:00
|
|
|
#ifdef BX_LITTLE_ENDIAN
|
2004-11-05 13:13:15 +03:00
|
|
|
BX_CPU_THIS_PTR mem->writePhysicalPage(BX_CPU_THIS,
|
Now, when you compile with --enable-guest2host-tlb, non-paged
mode uses the notion of the guest-to-host TLB. This has the
benefit of allowing more uniform and streamlined acceleration
code in access.cc which does not have to check if CR0.PG
is set, eliminating a few instructions per guest access.
Shaved just a little off execution time, as expected.
Also, access_linear now breaks accesses which span two pages,
into two calls the the physical memory routines, when paging
is off, just like it always has for paging on. Besides
being more uniform, this allows the physical memory access
routines to known the complete data item is contained
within a single physical page, and stop reapplying the
A20ADDR() macro to pointers as it increments them.
Perhaps things can be optimized a little more now there too...
I renamed the routines to {read,write}PhysicalPage() as
a reminder that these routines now operate on data
solely within one page.
I also added a little code so that the paging module is
notified when the A20 line is tweaked, so it can dump
whatever mappings it wants to.
2002-09-05 06:31:24 +04:00
|
|
|
BX_CPU_THIS_PTR address_xlation.paddress1,
|
|
|
|
BX_CPU_THIS_PTR address_xlation.len1,
|
|
|
|
&val32);
|
2004-11-05 13:13:15 +03:00
|
|
|
BX_CPU_THIS_PTR mem->writePhysicalPage(BX_CPU_THIS,
|
Now, when you compile with --enable-guest2host-tlb, non-paged
mode uses the notion of the guest-to-host TLB. This has the
benefit of allowing more uniform and streamlined acceleration
code in access.cc which does not have to check if CR0.PG
is set, eliminating a few instructions per guest access.
Shaved just a little off execution time, as expected.
Also, access_linear now breaks accesses which span two pages,
into two calls the the physical memory routines, when paging
is off, just like it always has for paging on. Besides
being more uniform, this allows the physical memory access
routines to known the complete data item is contained
within a single physical page, and stop reapplying the
A20ADDR() macro to pointers as it increments them.
Perhaps things can be optimized a little more now there too...
I renamed the routines to {read,write}PhysicalPage() as
a reminder that these routines now operate on data
solely within one page.
I also added a little code so that the paging module is
notified when the A20 line is tweaked, so it can dump
whatever mappings it wants to.
2002-09-05 06:31:24 +04:00
|
|
|
BX_CPU_THIS_PTR address_xlation.paddress2,
|
|
|
|
BX_CPU_THIS_PTR address_xlation.len2,
|
|
|
|
((Bit8u *) &val32) + BX_CPU_THIS_PTR address_xlation.len1);
|
2001-04-10 05:04:59 +04:00
|
|
|
#else
|
2004-11-05 13:13:15 +03:00
|
|
|
BX_CPU_THIS_PTR mem->writePhysicalPage(BX_CPU_THIS,
|
Now, when you compile with --enable-guest2host-tlb, non-paged
mode uses the notion of the guest-to-host TLB. This has the
benefit of allowing more uniform and streamlined acceleration
code in access.cc which does not have to check if CR0.PG
is set, eliminating a few instructions per guest access.
Shaved just a little off execution time, as expected.
Also, access_linear now breaks accesses which span two pages,
into two calls the the physical memory routines, when paging
is off, just like it always has for paging on. Besides
being more uniform, this allows the physical memory access
routines to known the complete data item is contained
within a single physical page, and stop reapplying the
A20ADDR() macro to pointers as it increments them.
Perhaps things can be optimized a little more now there too...
I renamed the routines to {read,write}PhysicalPage() as
a reminder that these routines now operate on data
solely within one page.
I also added a little code so that the paging module is
notified when the A20 line is tweaked, so it can dump
whatever mappings it wants to.
2002-09-05 06:31:24 +04:00
|
|
|
BX_CPU_THIS_PTR address_xlation.paddress1,
|
|
|
|
BX_CPU_THIS_PTR address_xlation.len1,
|
|
|
|
((Bit8u *) &val32) + (4 - BX_CPU_THIS_PTR address_xlation.len1));
|
2004-11-05 13:13:15 +03:00
|
|
|
BX_CPU_THIS_PTR mem->writePhysicalPage(BX_CPU_THIS,
|
Now, when you compile with --enable-guest2host-tlb, non-paged
mode uses the notion of the guest-to-host TLB. This has the
benefit of allowing more uniform and streamlined acceleration
code in access.cc which does not have to check if CR0.PG
is set, eliminating a few instructions per guest access.
Shaved just a little off execution time, as expected.
Also, access_linear now breaks accesses which span two pages,
into two calls the the physical memory routines, when paging
is off, just like it always has for paging on. Besides
being more uniform, this allows the physical memory access
routines to known the complete data item is contained
within a single physical page, and stop reapplying the
A20ADDR() macro to pointers as it increments them.
Perhaps things can be optimized a little more now there too...
I renamed the routines to {read,write}PhysicalPage() as
a reminder that these routines now operate on data
solely within one page.
I also added a little code so that the paging module is
notified when the A20 line is tweaked, so it can dump
whatever mappings it wants to.
2002-09-05 06:31:24 +04:00
|
|
|
BX_CPU_THIS_PTR address_xlation.paddress2,
|
|
|
|
BX_CPU_THIS_PTR address_xlation.len2,
|
|
|
|
&val32);
|
2001-04-10 05:04:59 +04:00
|
|
|
#endif
|
2005-01-25 23:41:43 +03:00
|
|
|
}
|
2001-04-10 05:04:59 +04:00
|
|
|
}
|
2002-09-05 00:23:54 +04:00
|
|
|
|
2005-08-24 00:01:54 +04:00
|
|
|
void BX_CPP_AttrRegparmN(1)
|
2002-09-13 08:33:42 +04:00
|
|
|
BX_CPU_C::write_RMW_virtual_qword(Bit64u val64)
|
|
|
|
{
|
|
|
|
if (BX_CPU_THIS_PTR address_xlation.pages > 2) {
|
|
|
|
// Pages > 2 means it stores a host address for direct access.
|
|
|
|
Bit64u *hostAddr = (Bit64u *) BX_CPU_THIS_PTR address_xlation.pages;
|
|
|
|
WriteHostQWordToLittleEndian(hostAddr, val64);
|
2005-01-25 23:41:43 +03:00
|
|
|
}
|
2002-09-13 08:33:42 +04:00
|
|
|
else if (BX_CPU_THIS_PTR address_xlation.pages == 1) {
|
2004-11-05 13:13:15 +03:00
|
|
|
BX_CPU_THIS_PTR mem->writePhysicalPage(BX_CPU_THIS,
|
2002-09-13 08:33:42 +04:00
|
|
|
BX_CPU_THIS_PTR address_xlation.paddress1, 8, &val64);
|
2005-01-25 23:41:43 +03:00
|
|
|
}
|
2002-09-13 08:33:42 +04:00
|
|
|
else {
|
|
|
|
#ifdef BX_LITTLE_ENDIAN
|
2004-11-05 13:13:15 +03:00
|
|
|
BX_CPU_THIS_PTR mem->writePhysicalPage(BX_CPU_THIS,
|
2002-09-13 08:33:42 +04:00
|
|
|
BX_CPU_THIS_PTR address_xlation.paddress1,
|
|
|
|
BX_CPU_THIS_PTR address_xlation.len1,
|
|
|
|
&val64);
|
2004-11-05 13:13:15 +03:00
|
|
|
BX_CPU_THIS_PTR mem->writePhysicalPage(BX_CPU_THIS,
|
2002-09-13 08:33:42 +04:00
|
|
|
BX_CPU_THIS_PTR address_xlation.paddress2,
|
|
|
|
BX_CPU_THIS_PTR address_xlation.len2,
|
|
|
|
((Bit8u *) &val64) + BX_CPU_THIS_PTR address_xlation.len1);
|
|
|
|
#else
|
2004-11-05 13:13:15 +03:00
|
|
|
BX_CPU_THIS_PTR mem->writePhysicalPage(BX_CPU_THIS,
|
2002-09-13 08:33:42 +04:00
|
|
|
BX_CPU_THIS_PTR address_xlation.paddress1,
|
|
|
|
BX_CPU_THIS_PTR address_xlation.len1,
|
|
|
|
((Bit8u *) &val64) + (8 - BX_CPU_THIS_PTR address_xlation.len1));
|
2004-11-05 13:13:15 +03:00
|
|
|
BX_CPU_THIS_PTR mem->writePhysicalPage(BX_CPU_THIS,
|
2002-09-13 08:33:42 +04:00
|
|
|
BX_CPU_THIS_PTR address_xlation.paddress2,
|
|
|
|
BX_CPU_THIS_PTR address_xlation.len2,
|
|
|
|
&val64);
|
|
|
|
#endif
|
2005-01-25 23:41:43 +03:00
|
|
|
}
|
2002-09-13 08:33:42 +04:00
|
|
|
}
|
|
|
|
|
2003-10-24 22:34:16 +04:00
|
|
|
//
|
2002-10-11 20:18:00 +04:00
|
|
|
// Some macro defs to make things cleaner for endian-ness issues.
|
|
|
|
// The following routines access a double qword, ie 16-bytes.
|
|
|
|
// For the moment, I redirect these to use the single qword routines
|
|
|
|
// by splitting one access into two.
|
|
|
|
//
|
|
|
|
// Endian Host byte order Guest (x86) byte order
|
|
|
|
// ======================================================
|
|
|
|
// Little 0..7 8..15 0..7 8..15
|
|
|
|
// Big 15..8 7...0 0..7 8..15
|
|
|
|
//
|
|
|
|
// Below are the host memory offsets to each of 2 single quadwords, which
|
|
|
|
// are different across big an little endian machines. The memory
|
|
|
|
// accessing routines take care of the access endian issues when accessing
|
|
|
|
// the physical memory image.
|
2003-10-24 22:34:16 +04:00
|
|
|
//
|
|
|
|
|
2002-10-11 20:18:00 +04:00
|
|
|
|
|
|
|
#ifdef BX_LITTLE_ENDIAN
|
|
|
|
# define Host1stDWordOffset 0
|
|
|
|
# define Host2ndDWordOffset 8
|
|
|
|
#else
|
|
|
|
# define Host1stDWordOffset 8
|
|
|
|
# define Host2ndDWordOffset 0
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
2003-10-24 22:34:16 +04:00
|
|
|
void BX_CPP_AttrRegparmN(3)
|
2003-10-25 00:06:12 +04:00
|
|
|
BX_CPU_C::read_virtual_dqword(unsigned s, bx_address offset, Bit8u *data)
|
2002-10-11 05:11:11 +04:00
|
|
|
{
|
2002-10-11 17:55:26 +04:00
|
|
|
// Read Double Quadword.
|
|
|
|
Bit64u *qwords = (Bit64u*) data;
|
|
|
|
|
2007-12-20 23:58:38 +03:00
|
|
|
qwords[0] = read_virtual_qword(s, offset+Host1stDWordOffset);
|
|
|
|
qwords[1] = read_virtual_qword(s, offset+Host2ndDWordOffset);
|
2002-10-11 05:11:11 +04:00
|
|
|
}
|
|
|
|
|
2003-10-24 22:34:16 +04:00
|
|
|
void BX_CPP_AttrRegparmN(3)
|
2003-10-25 00:06:12 +04:00
|
|
|
BX_CPU_C::read_virtual_dqword_aligned(unsigned s, bx_address offset, Bit8u *data)
|
2002-10-11 05:11:11 +04:00
|
|
|
{
|
2002-10-11 17:55:26 +04:00
|
|
|
// If double quadword access is unaligned, #GP(0).
|
2007-08-01 00:25:52 +04:00
|
|
|
bx_address laddr = BX_CPU_THIS_PTR get_segment_base(s) + offset;
|
|
|
|
if (laddr & 0xf) {
|
2006-06-10 02:29:07 +04:00
|
|
|
BX_DEBUG(("read_virtual_dqword_aligned: access not aligned to 16-byte"));
|
2002-10-11 17:55:26 +04:00
|
|
|
exception(BX_GP_EXCEPTION, 0, 0);
|
2003-10-24 22:34:16 +04:00
|
|
|
}
|
2002-10-11 17:55:26 +04:00
|
|
|
|
2003-10-25 00:06:12 +04:00
|
|
|
read_virtual_dqword(s, offset, data);
|
2002-10-11 05:11:11 +04:00
|
|
|
}
|
|
|
|
|
2003-10-24 22:34:16 +04:00
|
|
|
void BX_CPP_AttrRegparmN(3)
|
2003-10-25 00:06:12 +04:00
|
|
|
BX_CPU_C::write_virtual_dqword(unsigned s, bx_address offset, Bit8u *data)
|
2002-10-11 05:11:11 +04:00
|
|
|
{
|
2002-10-11 17:55:26 +04:00
|
|
|
// Write Double Quadword.
|
|
|
|
Bit64u *qwords = (Bit64u*) data;
|
|
|
|
|
2007-12-20 21:29:42 +03:00
|
|
|
write_virtual_qword(s, offset+Host1stDWordOffset, qwords[0]);
|
|
|
|
write_virtual_qword(s, offset+Host2ndDWordOffset, qwords[1]);
|
2002-10-11 05:11:11 +04:00
|
|
|
}
|
|
|
|
|
2003-10-24 22:34:16 +04:00
|
|
|
void BX_CPP_AttrRegparmN(3)
|
2003-10-25 00:06:12 +04:00
|
|
|
BX_CPU_C::write_virtual_dqword_aligned(unsigned s, bx_address offset, Bit8u *data)
|
2002-10-11 05:11:11 +04:00
|
|
|
{
|
2002-10-11 17:55:26 +04:00
|
|
|
// If double quadword access is unaligned, #GP(0).
|
2007-08-01 00:25:52 +04:00
|
|
|
bx_address laddr = BX_CPU_THIS_PTR get_segment_base(s) + offset;
|
|
|
|
if (laddr & 0xf) {
|
2006-06-10 02:29:07 +04:00
|
|
|
BX_DEBUG(("write_virtual_dqword_aligned: access not aligned to 16-byte"));
|
2002-10-11 17:55:26 +04:00
|
|
|
exception(BX_GP_EXCEPTION, 0, 0);
|
2003-10-24 22:34:16 +04:00
|
|
|
}
|
2002-10-11 17:55:26 +04:00
|
|
|
|
2003-10-25 00:06:12 +04:00
|
|
|
write_virtual_dqword(s, offset, data);
|
2002-10-11 05:11:11 +04:00
|
|
|
}
|
2004-06-18 18:11:11 +04:00
|
|
|
|
|
|
|
#if BX_SUPPORT_FPU
|
|
|
|
|
|
|
|
void BX_CPP_AttrRegparmN(3)
|
|
|
|
BX_CPU_C::read_virtual_tword(unsigned s, bx_address offset, floatx80 *data)
|
|
|
|
{
|
|
|
|
// read floating point register
|
2007-12-20 23:58:38 +03:00
|
|
|
data->fraction = read_virtual_qword(s, offset+0);
|
|
|
|
data->exp = read_virtual_word (s, offset+8);
|
2004-06-18 18:11:11 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
void BX_CPP_AttrRegparmN(3)
|
|
|
|
BX_CPU_C::write_virtual_tword(unsigned s, bx_address offset, floatx80 *data)
|
|
|
|
{
|
|
|
|
// store floating point register
|
2007-12-20 21:29:42 +03:00
|
|
|
write_virtual_qword(s, offset+0, data->fraction);
|
|
|
|
write_virtual_word (s, offset+8, data->exp);
|
2004-06-18 18:11:11 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|
2007-10-19 14:14:33 +04:00
|
|
|
|
|
|
|
//
|
|
|
|
// Write data to new stack, these methods are required for emulation
|
|
|
|
// correctness but not performance critical.
|
|
|
|
//
|
|
|
|
|
|
|
|
// assuming the write happens in legacy mode
|
2007-12-17 00:03:46 +03:00
|
|
|
void BX_CPU_C::write_new_stack_word(bx_segment_reg_t *seg, bx_address offset, unsigned curr_pl, Bit16u data)
|
2007-10-19 14:14:33 +04:00
|
|
|
{
|
|
|
|
bx_address laddr;
|
|
|
|
|
|
|
|
BX_ASSERT(BX_CPU_THIS_PTR cpu_mode != BX_MODE_LONG_64);
|
|
|
|
|
2007-12-10 22:08:13 +03:00
|
|
|
if ((seg->cache.valid & SegAccessWOK4G) == SegAccessWOK4G) {
|
2007-10-19 14:14:33 +04:00
|
|
|
accessOK:
|
2007-12-10 22:08:13 +03:00
|
|
|
laddr = seg->cache.u.segment.base + offset;
|
|
|
|
BX_INSTR_MEM_DATA(BX_CPU_ID, laddr, 2, BX_WRITE);
|
2007-10-19 14:14:33 +04:00
|
|
|
#if BX_CPU_LEVEL >= 4 && BX_SUPPORT_ALIGNMENT_CHECK
|
2007-12-16 23:47:10 +03:00
|
|
|
if (BX_CPU_THIS_PTR alignment_check) {
|
2007-12-10 22:08:13 +03:00
|
|
|
if (laddr & 1) {
|
|
|
|
BX_ERROR(("write_new_stack_word(): #AC misaligned access"));
|
|
|
|
exception(BX_AC_EXCEPTION, 0, 0);
|
2007-10-19 14:14:33 +04:00
|
|
|
}
|
2007-12-10 22:08:13 +03:00
|
|
|
}
|
2007-10-19 14:14:33 +04:00
|
|
|
#endif
|
|
|
|
#if BX_SupportGuest2HostTLB
|
2007-12-21 13:33:39 +03:00
|
|
|
Bit16u *hostAddr = (Bit16u*) v2h_write(laddr, curr_pl, 1);
|
2007-12-10 22:08:13 +03:00
|
|
|
if (hostAddr) {
|
2007-12-14 00:30:05 +03:00
|
|
|
BX_INSTR_LIN_ACCESS(BX_CPU_ID, laddr, tlbEntry->ppf | (laddr & 0xfff), 2, BX_WRITE);
|
2007-12-10 22:08:13 +03:00
|
|
|
WriteHostWordToLittleEndian(hostAddr, data);
|
2007-10-19 14:14:33 +04:00
|
|
|
return;
|
|
|
|
}
|
2007-12-10 22:08:13 +03:00
|
|
|
#endif
|
2007-12-17 00:03:46 +03:00
|
|
|
access_linear(laddr, 2, curr_pl, BX_WRITE, (void *) &data);
|
2007-12-10 22:08:13 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (seg->cache.valid & SegAccessWOK) {
|
|
|
|
if (offset < seg->cache.u.segment.limit_scaled)
|
|
|
|
goto accessOK;
|
2007-10-19 14:14:33 +04:00
|
|
|
}
|
|
|
|
write_virtual_checks(seg, offset, 2);
|
|
|
|
goto accessOK;
|
|
|
|
}
|
|
|
|
|
|
|
|
// assuming the write happens in legacy mode
|
2007-12-17 00:03:46 +03:00
|
|
|
void BX_CPU_C::write_new_stack_dword(bx_segment_reg_t *seg, bx_address offset, unsigned curr_pl, Bit32u data)
|
2007-10-19 14:14:33 +04:00
|
|
|
{
|
|
|
|
bx_address laddr;
|
|
|
|
|
|
|
|
BX_ASSERT(BX_CPU_THIS_PTR cpu_mode != BX_MODE_LONG_64);
|
|
|
|
|
2007-12-10 22:08:13 +03:00
|
|
|
if ((seg->cache.valid & SegAccessWOK4G) == SegAccessWOK4G) {
|
2007-10-19 14:14:33 +04:00
|
|
|
accessOK:
|
2007-12-10 22:08:13 +03:00
|
|
|
laddr = seg->cache.u.segment.base + offset;
|
|
|
|
BX_INSTR_MEM_DATA(BX_CPU_ID, laddr, 4, BX_WRITE);
|
2007-10-19 14:14:33 +04:00
|
|
|
#if BX_CPU_LEVEL >= 4 && BX_SUPPORT_ALIGNMENT_CHECK
|
2007-12-16 23:47:10 +03:00
|
|
|
if (BX_CPU_THIS_PTR alignment_check) {
|
2007-12-10 22:08:13 +03:00
|
|
|
if (laddr & 3) {
|
|
|
|
BX_ERROR(("write_new_stack_dword(): #AC misaligned access"));
|
|
|
|
exception(BX_AC_EXCEPTION, 0, 0);
|
2007-10-19 14:14:33 +04:00
|
|
|
}
|
2007-12-10 22:08:13 +03:00
|
|
|
}
|
2007-10-19 14:14:33 +04:00
|
|
|
#endif
|
|
|
|
#if BX_SupportGuest2HostTLB
|
2007-12-21 13:33:39 +03:00
|
|
|
Bit32u *hostAddr = (Bit32u*) v2h_write(laddr, curr_pl, 3);
|
2007-12-10 22:08:13 +03:00
|
|
|
if (hostAddr) {
|
2007-12-14 00:30:05 +03:00
|
|
|
BX_INSTR_LIN_ACCESS(BX_CPU_ID, laddr, tlbEntry->ppf | (laddr & 0xfff), 4, BX_WRITE);
|
2007-12-10 22:08:13 +03:00
|
|
|
WriteHostDWordToLittleEndian(hostAddr, data);
|
2007-10-19 14:14:33 +04:00
|
|
|
return;
|
|
|
|
}
|
2007-12-10 22:08:13 +03:00
|
|
|
#endif
|
2007-12-17 00:03:46 +03:00
|
|
|
access_linear(laddr, 4, curr_pl, BX_WRITE, (void *) &data);
|
2007-12-10 22:08:13 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (seg->cache.valid & SegAccessWOK) {
|
|
|
|
if (offset < (seg->cache.u.segment.limit_scaled-2))
|
|
|
|
goto accessOK;
|
2007-10-19 14:14:33 +04:00
|
|
|
}
|
|
|
|
write_virtual_checks(seg, offset, 4);
|
|
|
|
goto accessOK;
|
|
|
|
}
|
|
|
|
|
|
|
|
// assuming the write happens in 64-bit mode
|
2007-11-20 20:15:33 +03:00
|
|
|
#if BX_SUPPORT_X86_64
|
2007-12-17 00:03:46 +03:00
|
|
|
void BX_CPU_C::write_new_stack_qword(bx_address offset, unsigned curr_pl, Bit64u data)
|
2007-10-19 14:14:33 +04:00
|
|
|
{
|
|
|
|
bx_address laddr = offset;
|
|
|
|
|
|
|
|
if (IsCanonical(offset)) {
|
|
|
|
BX_INSTR_MEM_DATA(BX_CPU_ID, laddr, 8, BX_WRITE);
|
|
|
|
#if BX_CPU_LEVEL >= 4 && BX_SUPPORT_ALIGNMENT_CHECK
|
2007-12-16 23:47:10 +03:00
|
|
|
if (BX_CPU_THIS_PTR alignment_check) {
|
2007-10-19 14:14:33 +04:00
|
|
|
if (laddr & 7) {
|
2007-11-21 00:22:03 +03:00
|
|
|
BX_ERROR(("write_new_stack_qword(): #AC misaligned access"));
|
2007-10-19 14:14:33 +04:00
|
|
|
exception(BX_AC_EXCEPTION, 0, 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
#if BX_SupportGuest2HostTLB
|
2007-12-21 13:33:39 +03:00
|
|
|
Bit64u *hostAddr = (Bit64u*) v2h_write(laddr, curr_pl, 7);
|
2007-10-19 14:14:33 +04:00
|
|
|
if (hostAddr) {
|
2007-12-14 00:30:05 +03:00
|
|
|
BX_INSTR_LIN_ACCESS(BX_CPU_ID, laddr, tlbEntry->ppf | (laddr & 0xfff), 8, BX_WRITE);
|
2007-10-19 14:14:33 +04:00
|
|
|
WriteHostQWordToLittleEndian(hostAddr, data);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
#endif
|
2007-12-17 00:03:46 +03:00
|
|
|
access_linear(laddr, 8, curr_pl, BX_WRITE, (void *) &data);
|
2007-10-19 14:14:33 +04:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
BX_ERROR(("write_new_stack_qword(): canonical failure 0x%08x:%08x", GET32H(laddr), GET32L(laddr)));
|
|
|
|
exception(BX_SS_EXCEPTION, 0, 0);
|
|
|
|
}
|
|
|
|
}
|
2007-11-20 20:15:33 +03:00
|
|
|
#endif
|