CLFLUSH do not fault when checking execute only segment

This commit is contained in:
Stanislav Shwartsman 2007-10-10 21:48:46 +00:00
parent ed3fdad74d
commit 82b7eaabd5
4 changed files with 96 additions and 9 deletions

View File

@ -1,5 +1,5 @@
/////////////////////////////////////////////////////////////////////////
// $Id: access.cc,v 1.69 2007-07-31 20:25:52 sshwarts Exp $
// $Id: access.cc,v 1.70 2007-10-10 21:48:46 sshwarts Exp $
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2001 MandrakeSoft S.A.
@ -23,6 +23,8 @@
// 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
//
/////////////////////////////////////////////////////////////////////////
#define NEED_CPU_REG_SHORTCUTS 1
#include "bochs.h"
@ -45,7 +47,7 @@ BX_CPU_C::write_virtual_checks(bx_segment_reg_t *seg, bx_address offset,
if (BX_CPU_THIS_PTR cpu_mode == BX_MODE_LONG_64) {
// do canonical checks
if (!IsCanonical(offset)) {
BX_ERROR(("write_virtual_checks(): canonical Failure 0x%08x:%08x", GET32H(offset), GET32L(offset)));
BX_ERROR(("write_virtual_checks(): canonical failure 0x%08x:%08x", GET32H(offset), GET32L(offset)));
exception(int_number(seg), 0, 0);
}
seg->cache.valid |= SegAccessWOK;
@ -132,7 +134,7 @@ BX_CPU_C::read_virtual_checks(bx_segment_reg_t *seg, bx_address offset,
if (BX_CPU_THIS_PTR cpu_mode == BX_MODE_LONG_64) {
// do canonical checks
if (!IsCanonical(offset)) {
BX_ERROR(("read_virtual_checks(): canonical Failure 0x%08x:%08x", GET32H(offset), GET32L(offset)));
BX_ERROR(("read_virtual_checks(): canonical failure 0x%08x:%08x", GET32H(offset), GET32L(offset)));
exception(int_number(seg), 0, 0);
}
seg->cache.valid |= SegAccessROK;
@ -205,6 +207,93 @@ BX_CPU_C::read_virtual_checks(bx_segment_reg_t *seg, bx_address offset,
}
}
void BX_CPP_AttrRegparmN(3)
BX_CPU_C::execute_virtual_checks(bx_segment_reg_t *seg, bx_address offset,
unsigned length)
{
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);
}
seg->cache.valid |= SegAccessROK;
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;
}
break;
case 8: case 9: /* execute only */
case 12: case 13: /* execute only, conforming */
if (offset > (seg->cache.u.segment.limit_scaled - length + 1)
|| (length-1 > seg->cache.u.segment.limit_scaled))
{
BX_ERROR(("execute_virtual_checks(): read beyond limit"));
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)))
{
BX_ERROR(("read_virtual_checks(): read beyond limit"));
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);
}
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;
}
}
}
char * BX_CPP_AttrRegparmN(1)
BX_CPU_C::strseg(bx_segment_reg_t *seg)
{

View File

@ -1,5 +1,5 @@
/////////////////////////////////////////////////////////////////////////
// $Id: cpu.h,v 1.330 2007-10-09 19:49:23 sshwarts Exp $
// $Id: cpu.h,v 1.331 2007-10-10 21:48:46 sshwarts Exp $
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2001 MandrakeSoft S.A.
@ -2745,6 +2745,7 @@ public: // for now...
BX_SMF void write_virtual_checks(bx_segment_reg_t *seg, bx_address offset, unsigned length) BX_CPP_AttrRegparmN(3);
BX_SMF void read_virtual_checks(bx_segment_reg_t *seg, bx_address offset, unsigned length) BX_CPP_AttrRegparmN(3);
BX_SMF void execute_virtual_checks(bx_segment_reg_t *seg, bx_address offset, unsigned length) BX_CPP_AttrRegparmN(3);
BX_SMF void write_virtual_byte(unsigned seg, bx_address offset, Bit8u *data) BX_CPP_AttrRegparmN(3);
BX_SMF void write_virtual_word(unsigned seg, bx_address offset, Bit16u *data) BX_CPP_AttrRegparmN(3);
BX_SMF void write_virtual_dword(unsigned seg, bx_address offset, Bit32u *data) BX_CPP_AttrRegparmN(3);

View File

@ -1,5 +1,5 @@
/////////////////////////////////////////////////////////////////////////
// $Id: proc_ctrl.cc,v 1.171 2007-09-28 19:51:44 sshwarts Exp $
// $Id: proc_ctrl.cc,v 1.172 2007-10-10 21:48:46 sshwarts Exp $
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2001 MandrakeSoft S.A.
@ -190,7 +190,7 @@ void BX_CPU_C::CLFLUSH(bxInstruction_c *i)
#if BX_SUPPORT_CLFLUSH
// check if we could access the memory
read_virtual_checks(&BX_CPU_THIS_PTR sregs[i->seg()], RMAddr(i), 1);
execute_virtual_checks(&BX_CPU_THIS_PTR sregs[i->seg()], RMAddr(i), 1);
#else
BX_INFO(("CLFLUSH: not supported, enable with SSE2"));
UndefinedOpcode(i);

View File

@ -35,9 +35,6 @@ TODO (know issues in CPU model):
This processor should yield to the other one, as we are anyhow waiting
for a lock, and any other processor is responsible for this.
[!] CLFLUSH instructin should not crash in case of EXECUTE-ONLY segment
access (according to AMD manuals)
[!] AMD and Intel x86_64 implementations are different.
Currently Bochs emulation is according to Intel version.
Do we need to support both ?