2001-10-03 17:10:38 +04:00
|
|
|
/////////////////////////////////////////////////////////////////////////
|
2008-12-13 21:40:39 +03:00
|
|
|
// $Id: proc_ctrl.cc,v 1.267 2008-12-13 18:40: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 22:12:00 +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
|
|
|
|
2002-09-15 03:17:55 +04:00
|
|
|
#if BX_SUPPORT_X86_64==0
|
|
|
|
// Make life easier for merging code.
|
|
|
|
#define RAX EAX
|
|
|
|
#define RCX ECX
|
|
|
|
#define RDX EDX
|
2008-04-15 18:41:50 +04:00
|
|
|
#define RIP EIP
|
2002-09-15 03:17:55 +04:00
|
|
|
#endif
|
|
|
|
|
2008-03-23 00:29:41 +03:00
|
|
|
void BX_CPP_AttrRegparmN(1) BX_CPU_C::UndefinedOpcode(bxInstruction_c *i)
|
2001-04-10 05:04:59 +04:00
|
|
|
{
|
2008-08-09 23:18:09 +04:00
|
|
|
BX_DEBUG(("UndefinedOpcode: b1 = 0x%02x causes #UD exception", i->b1()));
|
2002-04-11 05:19:24 +04:00
|
|
|
exception(BX_UD_EXCEPTION, 0, 0);
|
2001-04-10 05:04:59 +04:00
|
|
|
}
|
|
|
|
|
2008-03-23 00:29:41 +03:00
|
|
|
void BX_CPP_AttrRegparmN(1) BX_CPU_C::NOP(bxInstruction_c *i)
|
2001-04-10 05:04:59 +04:00
|
|
|
{
|
2003-11-14 00:17:31 +03:00
|
|
|
// No operation.
|
2002-10-16 21:37:35 +04:00
|
|
|
}
|
|
|
|
|
2008-03-23 00:29:41 +03:00
|
|
|
void BX_CPP_AttrRegparmN(1) BX_CPU_C::PREFETCH(bxInstruction_c *i)
|
2002-10-16 21:37:35 +04:00
|
|
|
{
|
2008-01-10 22:37:56 +03:00
|
|
|
#if BX_INSTRUMENTATION
|
2008-08-08 13:22:49 +04:00
|
|
|
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
|
|
|
BX_INSTR_PREFETCH_HINT(BX_CPU_ID, i->nnn(), i->seg(), eaddr);
|
2008-01-10 22:37:56 +03:00
|
|
|
#endif
|
2001-04-10 05:04:59 +04:00
|
|
|
}
|
|
|
|
|
2006-04-08 00:47:32 +04:00
|
|
|
//
|
2008-02-03 00:46:54 +03:00
|
|
|
// The shutdown state is very similar to the state following the exection
|
|
|
|
// if HLT instruction. In this mode the processor stops executing
|
|
|
|
// instructions until #NMI, #SMI, #RESET or #INIT is received. If
|
|
|
|
// shutdown occurs why in NMI interrupt handler or in SMM, a hardware
|
2006-04-08 00:47:32 +04:00
|
|
|
// reset must be used to restart the processor execution.
|
|
|
|
//
|
2006-04-05 21:31:35 +04:00
|
|
|
void BX_CPU_C::shutdown(void)
|
|
|
|
{
|
|
|
|
BX_PANIC(("Entering to shutdown state still not implemented"));
|
2006-04-08 00:47:32 +04:00
|
|
|
|
|
|
|
BX_CPU_THIS_PTR clear_IF();
|
|
|
|
|
|
|
|
// artificial trap bit, why use another variable.
|
2007-11-01 21:03:48 +03:00
|
|
|
BX_CPU_THIS_PTR debug_trap |= BX_DEBUG_TRAP_SHUTDOWN; // artificial trap
|
2006-04-08 00:47:32 +04:00
|
|
|
BX_CPU_THIS_PTR async_event = 1; // so processor knows to check
|
|
|
|
// Execution of this instruction completes. The processor
|
|
|
|
// will remain in a halt state until one of the above conditions
|
|
|
|
// is met.
|
|
|
|
|
|
|
|
BX_INSTR_HLT(BX_CPU_ID);
|
|
|
|
|
2008-04-16 01:29:18 +04:00
|
|
|
#if BX_DEBUGGER
|
|
|
|
bx_dbg_halt(BX_CPU_ID);
|
|
|
|
#endif
|
|
|
|
|
2008-02-03 00:46:54 +03:00
|
|
|
#if BX_USE_IDLE_HACK
|
2007-10-11 22:12:00 +04:00
|
|
|
bx_gui->sim_is_idle();
|
|
|
|
#endif
|
2006-04-08 00:47:32 +04:00
|
|
|
|
|
|
|
longjmp(BX_CPU_THIS_PTR jmp_buf_env, 1); // go back to main decode loop
|
2006-04-05 21:31:35 +04:00
|
|
|
}
|
|
|
|
|
2008-03-23 00:29:41 +03:00
|
|
|
void BX_CPP_AttrRegparmN(1) BX_CPU_C::HLT(bxInstruction_c *i)
|
2001-04-10 05:04:59 +04:00
|
|
|
{
|
2005-09-15 00:01:42 +04:00
|
|
|
if (!real_mode() && CPL!=0) {
|
2007-04-26 00:14:15 +04:00
|
|
|
BX_DEBUG(("HLT: %s priveledge check failed, CPL=%d, generate #GP(0)",
|
2006-08-11 21:23:36 +04:00
|
|
|
cpu_mode_string(BX_CPU_THIS_PTR cpu_mode), CPL));
|
2002-04-11 05:19:24 +04:00
|
|
|
exception(BX_GP_EXCEPTION, 0, 0);
|
2005-02-03 21:25:10 +03:00
|
|
|
}
|
2001-04-10 05:04:59 +04:00
|
|
|
|
2006-04-08 00:47:32 +04:00
|
|
|
if (! BX_CPU_THIS_PTR get_IF()) {
|
2005-11-04 18:15:02 +03:00
|
|
|
BX_INFO(("WARNING: HLT instruction with IF=0!"));
|
2003-11-14 00:17:31 +03:00
|
|
|
}
|
2001-04-10 05:04:59 +04:00
|
|
|
|
|
|
|
// stops instruction execution and places the processor in a
|
|
|
|
// HALT state. An enabled interrupt, NMI, or reset will resume
|
|
|
|
// execution. If interrupt (including NMI) is used to resume
|
|
|
|
// execution after HLT, the saved CS:eIP points to instruction
|
|
|
|
// following HLT.
|
|
|
|
|
|
|
|
// artificial trap bit, why use another variable.
|
2007-11-01 21:03:48 +03:00
|
|
|
BX_CPU_THIS_PTR debug_trap |= BX_DEBUG_TRAP_HALT; // artificial trap
|
2001-04-10 05:04:59 +04:00
|
|
|
BX_CPU_THIS_PTR async_event = 1; // so processor knows to check
|
|
|
|
// Execution of this instruction completes. The processor
|
|
|
|
// will remain in a halt state until one of the above conditions
|
|
|
|
// is met.
|
2001-11-12 03:45:09 +03:00
|
|
|
|
2005-07-07 22:40:35 +04:00
|
|
|
BX_INSTR_HLT(BX_CPU_ID);
|
|
|
|
|
2008-03-24 00:39:01 +03:00
|
|
|
#if BX_DEBUGGER
|
|
|
|
bx_dbg_halt(BX_CPU_ID);
|
|
|
|
#endif
|
|
|
|
|
2008-02-03 00:46:54 +03:00
|
|
|
#if BX_USE_IDLE_HACK
|
2007-10-11 22:12:00 +04:00
|
|
|
bx_gui->sim_is_idle();
|
|
|
|
#endif
|
2001-04-10 05:04:59 +04:00
|
|
|
}
|
|
|
|
|
2008-03-23 00:29:41 +03:00
|
|
|
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CLTS(bxInstruction_c *i)
|
2001-04-10 05:04:59 +04:00
|
|
|
{
|
2005-09-15 00:01:42 +04:00
|
|
|
if (!real_mode() && CPL!=0) {
|
2006-06-10 02:29:07 +04:00
|
|
|
BX_ERROR(("CLTS: priveledge check failed, generate #GP(0)"));
|
2002-04-11 05:19:24 +04:00
|
|
|
exception(BX_GP_EXCEPTION, 0, 0);
|
2005-02-03 21:25:10 +03:00
|
|
|
}
|
2001-04-10 05:04:59 +04:00
|
|
|
|
2007-07-09 19:16:14 +04:00
|
|
|
BX_CPU_THIS_PTR cr0.set_TS(0);
|
2001-04-10 05:04:59 +04:00
|
|
|
}
|
|
|
|
|
2008-09-19 23:18:57 +04:00
|
|
|
/* 0F 08 INVD */
|
|
|
|
/* 0F 09 WBINVD */
|
2008-03-23 00:29:41 +03:00
|
|
|
void BX_CPP_AttrRegparmN(1) BX_CPU_C::WBINVD(bxInstruction_c *i)
|
2001-04-10 05:04:59 +04:00
|
|
|
{
|
|
|
|
#if BX_CPU_LEVEL >= 4
|
2006-10-04 23:08:40 +04:00
|
|
|
if (!real_mode() && CPL!=0) {
|
2008-09-19 23:18:57 +04:00
|
|
|
BX_ERROR(("INVD/WBINVD: priveledge check failed, generate #GP(0)"));
|
2006-10-04 23:08:40 +04:00
|
|
|
exception(BX_GP_EXCEPTION, 0, 0);
|
2005-02-03 21:25:10 +03:00
|
|
|
}
|
2005-10-18 22:07:52 +04:00
|
|
|
|
2007-12-14 23:41:09 +03:00
|
|
|
invalidate_prefetch_q();
|
|
|
|
|
2008-09-19 23:18:57 +04:00
|
|
|
BX_DEBUG(("INVD/WBINVD: Flush internal caches !"));
|
|
|
|
#if BX_INSTRUMENTATION
|
|
|
|
if (i->b1() == 0x08)
|
|
|
|
BX_INSTR_CACHE_CNTRL(BX_CPU_ID, BX_INSTR_INVD);
|
|
|
|
else
|
|
|
|
BX_INSTR_CACHE_CNTRL(BX_CPU_ID, BX_INSTR_WBINVD);
|
|
|
|
#endif
|
2007-12-14 23:41:09 +03:00
|
|
|
|
2005-10-18 22:07:52 +04:00
|
|
|
#if BX_SUPPORT_ICACHE
|
|
|
|
flushICaches();
|
|
|
|
#endif
|
|
|
|
|
2001-04-10 05:04:59 +04:00
|
|
|
#else
|
2008-09-19 23:18:57 +04:00
|
|
|
BX_INFO(("INVD/WBINVD: required 486 support, use --enable-cpu-level=4 option"));
|
2008-07-13 19:35:10 +04:00
|
|
|
exception(BX_UD_EXCEPTION, 0, 0);
|
2001-04-10 05:04:59 +04:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2008-03-23 00:29:41 +03:00
|
|
|
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CLFLUSH(bxInstruction_c *i)
|
2007-01-29 00:27:31 +03:00
|
|
|
{
|
|
|
|
#if BX_SUPPORT_CLFLUSH
|
2007-12-14 23:41:09 +03:00
|
|
|
bx_segment_reg_t *seg = &BX_CPU_THIS_PTR sregs[i->seg()];
|
2008-01-17 01:56:17 +03:00
|
|
|
|
2008-08-08 13:22:49 +04:00
|
|
|
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
|
|
|
bx_address laddr = BX_CPU_THIS_PTR get_laddr(i->seg(), eaddr);
|
2008-09-09 00:47:33 +04:00
|
|
|
|
2008-05-27 01:46:39 +04:00
|
|
|
#if BX_SUPPORT_X86_64
|
2008-09-09 00:47:33 +04:00
|
|
|
if (BX_CPU_THIS_PTR cpu_mode == BX_MODE_LONG_64) {
|
|
|
|
if (! IsCanonical(laddr)) {
|
|
|
|
BX_ERROR(("CLFLUSH: non-canonical access !"));
|
|
|
|
exception(int_number(i->seg()), 0, 0);
|
|
|
|
}
|
2008-05-27 01:46:39 +04:00
|
|
|
}
|
2008-09-09 00:47:33 +04:00
|
|
|
else
|
2008-05-27 01:46:39 +04:00
|
|
|
#endif
|
2008-09-09 00:47:33 +04:00
|
|
|
{
|
|
|
|
// check if we could access the memory segment
|
|
|
|
if (!(seg->cache.valid & SegAccessROK)) {
|
|
|
|
if (! execute_virtual_checks(seg, eaddr, 1))
|
|
|
|
exception(int_number(i->seg()), 0, 0);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
if (eaddr > seg->cache.u.segment.limit_scaled) {
|
|
|
|
BX_ERROR(("CLFLUSH: segment limit violation"));
|
|
|
|
exception(int_number(i->seg()), 0, 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2008-05-27 01:46:39 +04:00
|
|
|
|
2008-01-17 01:56:17 +03:00
|
|
|
bx_phy_address paddr;
|
|
|
|
|
|
|
|
if (BX_CPU_THIS_PTR cr0.get_PG()) {
|
|
|
|
paddr = dtranslate_linear(laddr, CPL, BX_READ);
|
|
|
|
paddr = A20ADDR(paddr);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
paddr = A20ADDR(laddr);
|
|
|
|
}
|
|
|
|
|
|
|
|
BX_INSTR_CLFLUSH(BX_CPU_ID, laddr, paddr);
|
|
|
|
|
2007-01-29 00:27:31 +03:00
|
|
|
#else
|
|
|
|
BX_INFO(("CLFLUSH: not supported, enable with SSE2"));
|
2008-07-13 19:35:10 +04:00
|
|
|
exception(BX_UD_EXCEPTION, 0, 0);
|
2007-01-29 00:27:31 +03:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2005-07-01 18:06:02 +04:00
|
|
|
#if BX_CPU_LEVEL >= 3
|
2008-03-23 00:29:41 +03:00
|
|
|
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOV_DdRd(bxInstruction_c *i)
|
2001-04-10 05:04:59 +04:00
|
|
|
{
|
2008-05-19 23:59:29 +04:00
|
|
|
#if BX_CPU_LEVEL >= 4
|
|
|
|
if (BX_CPU_THIS_PTR cr4.get_DE()) {
|
|
|
|
if ((i->nnn() & 0xE) == 4) {
|
|
|
|
BX_ERROR(("MOV_DdRd: access to DR4/DR5 causes #UD"));
|
2008-07-13 19:35:10 +04:00
|
|
|
exception(BX_UD_EXCEPTION, 0, 0);
|
2008-05-19 23:59:29 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2008-06-02 23:50:40 +04:00
|
|
|
// Note: processor clears GD upon entering debug exception
|
|
|
|
// handler, to allow access to the debug registers
|
|
|
|
if (BX_CPU_THIS_PTR dr7 & 0x2000) { // GD bit set
|
|
|
|
BX_ERROR(("MOV_DdRd: DR7 GD bit is set"));
|
|
|
|
BX_CPU_THIS_PTR dr6 |= 0x2000;
|
|
|
|
exception(BX_DB_EXCEPTION, 0, 0);
|
|
|
|
}
|
|
|
|
|
2006-09-10 20:56:55 +04:00
|
|
|
if (!real_mode() && CPL!=0) {
|
|
|
|
BX_ERROR(("MOV_DdRd: CPL!=0 not in real mode"));
|
2003-08-03 20:44:53 +04:00
|
|
|
exception(BX_GP_EXCEPTION, 0, 0);
|
|
|
|
}
|
2003-11-14 00:17:31 +03:00
|
|
|
|
2001-04-10 05:04:59 +04:00
|
|
|
/* NOTES:
|
|
|
|
* 32bit operands always used
|
|
|
|
* r/m field specifies general register
|
|
|
|
* reg field specifies which special register
|
|
|
|
*/
|
|
|
|
|
2007-12-14 14:27:44 +03:00
|
|
|
invalidate_prefetch_q();
|
|
|
|
|
2003-11-14 00:17:31 +03:00
|
|
|
/* This instruction is always treated as a register-to-register,
|
2008-02-03 00:46:54 +03:00
|
|
|
* regardless of the encoding of the MOD field in the MODRM byte.
|
2003-11-14 00:17:31 +03:00
|
|
|
*/
|
|
|
|
if (!i->modC0())
|
2006-06-27 01:07:44 +04:00
|
|
|
BX_PANIC(("MOV_DdRd(): rm field not a register!"));
|
2001-04-10 05:04:59 +04:00
|
|
|
|
2007-12-14 14:27:44 +03:00
|
|
|
Bit32u val_32 = BX_READ_32BIT_REG(i->rm());
|
2001-04-10 05:04:59 +04:00
|
|
|
|
2002-09-18 02:50:53 +04:00
|
|
|
switch (i->nnn()) {
|
2001-04-10 05:04:59 +04:00
|
|
|
case 0: // DR0
|
|
|
|
case 1: // DR1
|
|
|
|
case 2: // DR2
|
|
|
|
case 3: // DR3
|
2008-05-23 21:49:46 +04:00
|
|
|
TLB_invlpg(val_32);
|
|
|
|
BX_CPU_THIS_PTR dr[i->nnn()] = val_32;
|
2001-04-10 05:04:59 +04:00
|
|
|
break;
|
|
|
|
|
|
|
|
case 4: // DR4
|
2008-05-19 23:59:29 +04:00
|
|
|
// DR4 aliased to DR6 by default. With Debug Extensions on,
|
2001-04-10 05:04:59 +04:00
|
|
|
// access to DR4 causes #UD
|
2006-05-13 16:29:12 +04:00
|
|
|
case 6: // DR6
|
2001-04-10 05:04:59 +04:00
|
|
|
#if BX_CPU_LEVEL <= 4
|
|
|
|
// On 386/486 bit12 is settable
|
|
|
|
BX_CPU_THIS_PTR dr6 = (BX_CPU_THIS_PTR dr6 & 0xffff0ff0) |
|
|
|
|
(val_32 & 0x0000f00f);
|
|
|
|
#else
|
|
|
|
// On Pentium+, bit12 is always zero
|
|
|
|
BX_CPU_THIS_PTR dr6 = (BX_CPU_THIS_PTR dr6 & 0xffff0ff0) |
|
|
|
|
(val_32 & 0x0000e00f);
|
|
|
|
#endif
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 5: // DR5
|
2008-05-19 23:59:29 +04:00
|
|
|
// DR5 aliased to DR7 by default. With Debug Extensions on,
|
2001-04-10 05:04:59 +04:00
|
|
|
// access to DR5 causes #UD
|
2006-05-13 16:29:12 +04:00
|
|
|
case 7: // DR7
|
|
|
|
// Note: 486+ ignore GE and LE flags. On the 386, exact
|
|
|
|
// data breakpoint matching does not occur unless it is enabled
|
|
|
|
// by setting the LE and/or GE flags.
|
|
|
|
|
2001-04-10 05:04:59 +04:00
|
|
|
// Some sanity checks...
|
2008-02-16 01:05:43 +03:00
|
|
|
if (((((val_32>>16) & 3)==0) && (((val_32>>18) & 3)!=0)) ||
|
|
|
|
((((val_32>>20) & 3)==0) && (((val_32>>22) & 3)!=0)) ||
|
|
|
|
((((val_32>>24) & 3)==0) && (((val_32>>26) & 3)!=0)) ||
|
|
|
|
((((val_32>>28) & 3)==0) && (((val_32>>30) & 3)!=0)))
|
2005-02-03 21:25:10 +03:00
|
|
|
{
|
2001-04-10 05:04:59 +04:00
|
|
|
// Instruction breakpoint with LENx not 00b (1-byte length)
|
2008-12-13 21:40:39 +03:00
|
|
|
BX_ERROR(("MOV_DdRd: write of %08x, R/W=00b LEN!=00b", val_32));
|
2005-02-03 21:25:10 +03:00
|
|
|
}
|
2001-04-10 05:04:59 +04:00
|
|
|
#if BX_CPU_LEVEL <= 4
|
|
|
|
// 386/486: you can play with all the bits except b10 is always 1
|
|
|
|
BX_CPU_THIS_PTR dr7 = val_32 | 0x00000400;
|
|
|
|
#else
|
|
|
|
// Pentium+: bits15,14,12 are hardwired to 0, rest are settable.
|
|
|
|
// Even bits 11,10 are changeable though reserved.
|
|
|
|
BX_CPU_THIS_PTR dr7 = (val_32 & 0xffff2fff) | 0x00000400;
|
|
|
|
#endif
|
2003-08-03 20:44:53 +04:00
|
|
|
// if we have breakpoints enabled then we must check
|
|
|
|
// breakpoints condition in cpu loop
|
|
|
|
if(BX_CPU_THIS_PTR dr7 & 0xff)
|
2006-05-13 16:29:12 +04:00
|
|
|
BX_CPU_THIS_PTR async_event = 1;
|
2001-04-10 05:04:59 +04:00
|
|
|
break;
|
2003-11-14 00:17:31 +03:00
|
|
|
|
2001-04-10 05:04:59 +04:00
|
|
|
default:
|
2008-06-02 23:50:40 +04:00
|
|
|
BX_ERROR(("MOV_DdRd: #UD - register index out of range"));
|
2008-07-13 19:35:10 +04:00
|
|
|
exception(BX_UD_EXCEPTION, 0, 0);
|
2006-05-13 16:29:12 +04:00
|
|
|
}
|
2001-04-10 05:04:59 +04:00
|
|
|
}
|
|
|
|
|
2008-03-23 00:29:41 +03:00
|
|
|
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOV_RdDd(bxInstruction_c *i)
|
2001-04-10 05:04:59 +04:00
|
|
|
{
|
|
|
|
Bit32u val_32;
|
|
|
|
|
2008-05-19 23:59:29 +04:00
|
|
|
#if BX_CPU_LEVEL >= 4
|
|
|
|
if (BX_CPU_THIS_PTR cr4.get_DE()) {
|
|
|
|
if ((i->nnn() & 0xE) == 4) {
|
|
|
|
BX_ERROR(("MOV_RdDd: access to DR4/DR5 causes #UD"));
|
2008-07-13 19:35:10 +04:00
|
|
|
exception(BX_UD_EXCEPTION, 0, 0);
|
2008-05-19 23:59:29 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2008-06-02 23:50:40 +04:00
|
|
|
// Note: processor clears GD upon entering debug exception
|
|
|
|
// handler, to allow access to the debug registers
|
|
|
|
if (BX_CPU_THIS_PTR dr7 & 0x2000) { // GD bit set
|
|
|
|
BX_ERROR(("MOV_RdDd: DR7 GD bit is set"));
|
|
|
|
BX_CPU_THIS_PTR dr6 |= 0x2000;
|
|
|
|
exception(BX_DB_EXCEPTION, 0, 0);
|
|
|
|
}
|
|
|
|
|
2006-09-10 20:56:55 +04:00
|
|
|
if (!real_mode() && CPL!=0) {
|
|
|
|
BX_ERROR(("MOV_RdDd: CPL!=0 not in real mode"));
|
2002-04-11 05:19:24 +04:00
|
|
|
exception(BX_GP_EXCEPTION, 0, 0);
|
2005-02-03 21:25:10 +03:00
|
|
|
}
|
2001-04-10 05:04:59 +04:00
|
|
|
|
2003-11-14 00:17:31 +03:00
|
|
|
/* This instruction is always treated as a register-to-register,
|
2008-02-03 00:46:54 +03:00
|
|
|
* regardless of the encoding of the MOD field in the MODRM byte.
|
2003-11-14 00:17:31 +03:00
|
|
|
*/
|
2007-12-14 14:27:44 +03:00
|
|
|
if (!i->modC0())
|
|
|
|
BX_PANIC(("MOV_RdDd(): rm field not a register!"));
|
2001-04-10 05:04:59 +04:00
|
|
|
|
2002-09-18 02:50:53 +04:00
|
|
|
switch (i->nnn()) {
|
2001-04-10 05:04:59 +04:00
|
|
|
case 0: // DR0
|
|
|
|
case 1: // DR1
|
|
|
|
case 2: // DR2
|
|
|
|
case 3: // DR3
|
2008-05-23 21:49:46 +04:00
|
|
|
val_32 = BX_CPU_THIS_PTR dr[i->nnn()];
|
2001-04-10 05:04:59 +04:00
|
|
|
break;
|
|
|
|
|
|
|
|
case 4: // DR4
|
2008-05-19 23:59:29 +04:00
|
|
|
// DR4 aliased to DR6 by default. With Debug Extensions ON,
|
2001-04-10 05:04:59 +04:00
|
|
|
// access to DR4 causes #UD
|
2006-05-13 16:29:12 +04:00
|
|
|
case 6: // DR6
|
2001-04-10 05:04:59 +04:00
|
|
|
val_32 = BX_CPU_THIS_PTR dr6;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 5: // DR5
|
2008-05-19 23:59:29 +04:00
|
|
|
// DR5 aliased to DR7 by default. With Debug Extensions ON,
|
2001-04-10 05:04:59 +04:00
|
|
|
// access to DR5 causes #UD
|
2006-05-13 16:29:12 +04:00
|
|
|
case 7: // DR7
|
2001-04-10 05:04:59 +04:00
|
|
|
val_32 = BX_CPU_THIS_PTR dr7;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
2008-06-02 23:50:40 +04:00
|
|
|
BX_ERROR(("MOV_RdDd: #UD - register index out of range"));
|
2008-07-13 19:35:10 +04:00
|
|
|
exception(BX_UD_EXCEPTION, 0, 0);
|
2006-05-13 16:29:12 +04:00
|
|
|
}
|
2007-11-01 21:03:48 +03:00
|
|
|
|
2002-09-18 02:50:53 +04:00
|
|
|
BX_WRITE_32BIT_REGZ(i->rm(), val_32);
|
2001-04-10 05:04:59 +04:00
|
|
|
}
|
|
|
|
|
2002-09-15 03:17:55 +04:00
|
|
|
#if BX_SUPPORT_X86_64
|
2008-03-23 00:29:41 +03:00
|
|
|
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOV_DqRq(bxInstruction_c *i)
|
2002-09-15 03:17:55 +04:00
|
|
|
{
|
|
|
|
/* NOTES:
|
|
|
|
* 64bit operands always used
|
|
|
|
* r/m field specifies general register
|
|
|
|
* reg field specifies which special register
|
|
|
|
*/
|
|
|
|
|
2008-05-19 23:59:29 +04:00
|
|
|
if (BX_CPU_THIS_PTR cr4.get_DE()) {
|
|
|
|
if ((i->nnn() & 0xE) == 4) {
|
|
|
|
BX_ERROR(("MOV_DqRq: access to DR4/DR5 causes #UD"));
|
2008-07-13 19:35:10 +04:00
|
|
|
exception(BX_UD_EXCEPTION, 0, 0);
|
2008-05-19 23:59:29 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-06-02 23:50:40 +04:00
|
|
|
// Note: processor clears GD upon entering debug exception
|
|
|
|
// handler, to allow access to the debug registers
|
|
|
|
if (BX_CPU_THIS_PTR dr7 & 0x2000) { // GD bit set
|
|
|
|
BX_ERROR(("MOV_DqRq: DR7 GD bit is set"));
|
|
|
|
BX_CPU_THIS_PTR dr6 |= 0x2000;
|
|
|
|
exception(BX_DB_EXCEPTION, 0, 0);
|
|
|
|
}
|
|
|
|
|
2003-11-14 00:57:13 +03:00
|
|
|
/* #GP(0) if CPL is not 0 */
|
2006-06-27 01:07:44 +04:00
|
|
|
if (CPL != 0) {
|
|
|
|
BX_ERROR(("MOV_DqRq: #GP(0) if CPL is not 0"));
|
2002-09-15 03:17:55 +04:00
|
|
|
exception(BX_GP_EXCEPTION, 0, 0);
|
2003-11-14 00:17:31 +03:00
|
|
|
}
|
2002-09-15 03:17:55 +04:00
|
|
|
|
2007-12-14 14:27:44 +03:00
|
|
|
invalidate_prefetch_q();
|
|
|
|
|
|
|
|
/* This instruction is always treated as a register-to-register,
|
2008-02-03 00:46:54 +03:00
|
|
|
* regardless of the encoding of the MOD field in the MODRM byte.
|
2007-12-14 14:27:44 +03:00
|
|
|
*/
|
|
|
|
if (!i->modC0())
|
|
|
|
BX_PANIC(("MOV_DqRq(): rm field not a register!"));
|
|
|
|
|
2006-06-27 01:07:44 +04:00
|
|
|
Bit64u val_64 = BX_READ_64BIT_REG(i->rm());
|
2002-09-15 03:17:55 +04:00
|
|
|
|
2002-09-18 02:50:53 +04:00
|
|
|
switch (i->nnn()) {
|
2002-09-15 03:17:55 +04:00
|
|
|
case 0: // DR0
|
|
|
|
case 1: // DR1
|
|
|
|
case 2: // DR2
|
|
|
|
case 3: // DR3
|
2008-05-23 21:49:46 +04:00
|
|
|
TLB_invlpg(val_64);
|
|
|
|
BX_CPU_THIS_PTR dr[i->nnn()] = val_64;
|
2002-09-15 03:17:55 +04:00
|
|
|
break;
|
|
|
|
|
|
|
|
case 4: // DR4
|
2008-05-19 23:59:29 +04:00
|
|
|
// DR4 aliased to DR6 by default. With Debug Extensions ON,
|
2002-09-15 03:17:55 +04:00
|
|
|
// access to DR4 causes #UD
|
2006-05-13 16:29:12 +04:00
|
|
|
case 6: // DR6
|
2002-09-15 03:17:55 +04:00
|
|
|
// On Pentium+, bit12 is always zero
|
|
|
|
BX_CPU_THIS_PTR dr6 = (BX_CPU_THIS_PTR dr6 & 0xffff0ff0) |
|
|
|
|
(val_64 & 0x0000e00f);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 5: // DR5
|
2008-05-19 23:59:29 +04:00
|
|
|
// DR5 aliased to DR7 by default. With Debug Extensions ON,
|
2002-09-15 03:17:55 +04:00
|
|
|
// access to DR5 causes #UD
|
2006-05-13 16:29:12 +04:00
|
|
|
case 7: // DR7
|
|
|
|
// Note: 486+ ignore GE and LE flags. On the 386, exact
|
|
|
|
// data breakpoint matching does not occur unless it is enabled
|
|
|
|
// by setting the LE and/or GE flags.
|
2003-11-14 00:17:31 +03:00
|
|
|
|
2002-09-15 03:17:55 +04:00
|
|
|
// Some sanity checks...
|
2008-02-16 01:05:43 +03:00
|
|
|
if (((((val_64>>16) & 3)==0) && (((val_64>>18) & 3)!=0)) ||
|
|
|
|
((((val_64>>20) & 3)==0) && (((val_64>>22) & 3)!=0)) ||
|
|
|
|
((((val_64>>24) & 3)==0) && (((val_64>>26) & 3)!=0)) ||
|
|
|
|
((((val_64>>28) & 3)==0) && (((val_64>>30) & 3)!=0)))
|
2004-11-05 01:41:24 +03:00
|
|
|
{
|
2002-09-15 03:17:55 +04:00
|
|
|
// Instruction breakpoint with LENx not 00b (1-byte length)
|
2008-12-13 21:40:39 +03:00
|
|
|
BX_ERROR(("MOV_DqRq: write of %08x:%08x, R/W=00b LEN!=00b",
|
2004-11-05 01:41:24 +03:00
|
|
|
(Bit32u)(val_64 >> 32), (Bit32u)(val_64 & 0xFFFFFFFF)));
|
2003-11-14 00:17:31 +03:00
|
|
|
}
|
|
|
|
|
2002-09-15 03:17:55 +04:00
|
|
|
// Pentium+: bits15,14,12 are hardwired to 0, rest are settable.
|
|
|
|
// Even bits 11,10 are changeable though reserved.
|
|
|
|
BX_CPU_THIS_PTR dr7 = (val_64 & 0xffff2fff) | 0x00000400;
|
|
|
|
break;
|
2003-11-14 00:17:31 +03:00
|
|
|
|
2002-09-15 03:17:55 +04:00
|
|
|
default:
|
2008-06-02 23:50:40 +04:00
|
|
|
BX_ERROR(("MOV_DqRq: #UD - register index out of range"));
|
2008-07-13 19:35:10 +04:00
|
|
|
exception(BX_UD_EXCEPTION, 0, 0);
|
2006-05-13 16:29:12 +04:00
|
|
|
}
|
2002-09-15 03:17:55 +04:00
|
|
|
}
|
|
|
|
|
2008-03-23 00:29:41 +03:00
|
|
|
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOV_RqDq(bxInstruction_c *i)
|
2002-09-15 03:17:55 +04:00
|
|
|
{
|
|
|
|
Bit64u val_64;
|
|
|
|
|
2008-05-19 23:59:29 +04:00
|
|
|
if (BX_CPU_THIS_PTR cr4.get_DE()) {
|
|
|
|
if ((i->nnn() & 0xE) == 4) {
|
2008-06-02 23:50:40 +04:00
|
|
|
BX_ERROR(("MOV_RqDq: access to DR4/DR5 causes #UD"));
|
2008-07-13 19:35:10 +04:00
|
|
|
exception(BX_UD_EXCEPTION, 0, 0);
|
2008-05-19 23:59:29 +04:00
|
|
|
}
|
|
|
|
}
|
2002-09-15 03:17:55 +04:00
|
|
|
|
2008-06-02 23:50:40 +04:00
|
|
|
// Note: processor clears GD upon entering debug exception
|
|
|
|
// handler, to allow access to the debug registers
|
|
|
|
if (BX_CPU_THIS_PTR dr7 & 0x2000) { // GD bit set
|
|
|
|
BX_ERROR(("MOV_RqDq: DR7 GD bit is set"));
|
|
|
|
BX_CPU_THIS_PTR dr6 |= 0x2000;
|
|
|
|
exception(BX_DB_EXCEPTION, 0, 0);
|
|
|
|
}
|
|
|
|
|
2003-11-14 00:57:13 +03:00
|
|
|
/* #GP(0) if CPL is not 0 */
|
2006-06-27 01:07:44 +04:00
|
|
|
if (CPL != 0) {
|
|
|
|
BX_ERROR(("MOV_RqDq: #GP(0) if CPL is not 0"));
|
2002-09-15 03:17:55 +04:00
|
|
|
exception(BX_GP_EXCEPTION, 0, 0);
|
2003-11-14 00:17:31 +03:00
|
|
|
}
|
2002-09-15 03:17:55 +04:00
|
|
|
|
2007-12-14 14:27:44 +03:00
|
|
|
/* This instruction is always treated as a register-to-register,
|
2008-02-03 00:46:54 +03:00
|
|
|
* regardless of the encoding of the MOD field in the MODRM byte.
|
2007-12-14 14:27:44 +03:00
|
|
|
*/
|
|
|
|
if (!i->modC0())
|
|
|
|
BX_PANIC(("MOV_RqDq(): rm field not a register!"));
|
|
|
|
|
2002-09-18 02:50:53 +04:00
|
|
|
switch (i->nnn()) {
|
2002-09-15 03:17:55 +04:00
|
|
|
case 0: // DR0
|
|
|
|
case 1: // DR1
|
|
|
|
case 2: // DR2
|
|
|
|
case 3: // DR3
|
2008-05-23 21:49:46 +04:00
|
|
|
val_64 = BX_CPU_THIS_PTR dr[i->nnn()];
|
2002-09-15 03:17:55 +04:00
|
|
|
break;
|
|
|
|
|
|
|
|
case 4: // DR4
|
2008-05-19 23:59:29 +04:00
|
|
|
// DR4 aliased to DR6 by default. With Debug Extensions ON,
|
2002-09-15 03:17:55 +04:00
|
|
|
// access to DR4 causes #UD
|
2006-05-13 16:29:12 +04:00
|
|
|
case 6: // DR6
|
2002-09-15 03:17:55 +04:00
|
|
|
val_64 = BX_CPU_THIS_PTR dr6;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 5: // DR5
|
2008-05-19 23:59:29 +04:00
|
|
|
// DR5 aliased to DR7 by default. With Debug Extensions ON,
|
2002-09-15 03:17:55 +04:00
|
|
|
// access to DR5 causes #UD
|
2006-05-13 16:29:12 +04:00
|
|
|
case 7: // DR7
|
2002-09-15 03:17:55 +04:00
|
|
|
val_64 = BX_CPU_THIS_PTR dr7;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
2008-06-02 23:50:40 +04:00
|
|
|
BX_ERROR(("MOV_RqDq: #UD - register index out of range"));
|
2008-07-13 19:35:10 +04:00
|
|
|
exception(BX_UD_EXCEPTION, 0, 0);
|
2005-02-03 21:25:10 +03:00
|
|
|
}
|
2007-11-01 21:03:48 +03:00
|
|
|
|
2002-09-18 02:50:53 +04:00
|
|
|
BX_WRITE_64BIT_REG(i->rm(), val_64);
|
2002-09-15 03:17:55 +04:00
|
|
|
}
|
2005-07-01 18:06:02 +04:00
|
|
|
#endif // #if BX_SUPPORT_X86_64
|
|
|
|
|
2008-03-23 00:29:41 +03:00
|
|
|
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOV_CdRd(bxInstruction_c *i)
|
2001-04-10 05:04:59 +04:00
|
|
|
{
|
2006-09-10 20:56:55 +04:00
|
|
|
if (!real_mode() && CPL!=0) {
|
|
|
|
BX_ERROR(("MOV_CdRd: CPL!=0 not in real mode"));
|
2003-11-14 00:17:31 +03:00
|
|
|
exception(BX_GP_EXCEPTION, 0, 0);
|
|
|
|
}
|
2001-04-10 05:04:59 +04:00
|
|
|
|
|
|
|
/* NOTES:
|
|
|
|
* 32bit operands always used
|
|
|
|
* r/m field specifies general register
|
|
|
|
* reg field specifies which special register
|
|
|
|
*/
|
|
|
|
|
2003-11-14 00:17:31 +03:00
|
|
|
/* This instruction is always treated as a register-to-register,
|
2008-02-03 00:46:54 +03:00
|
|
|
* regardless of the encoding of the MOD field in the MODRM byte.
|
2003-11-14 00:17:31 +03:00
|
|
|
*/
|
2007-12-14 14:27:44 +03:00
|
|
|
if (!i->modC0())
|
|
|
|
BX_PANIC(("MOV_CdRd(): rm field not a register!"));
|
2001-04-10 05:04:59 +04:00
|
|
|
|
2007-12-14 14:27:44 +03:00
|
|
|
Bit32u val_32 = BX_READ_32BIT_REG(i->rm());
|
2001-04-10 05:04:59 +04:00
|
|
|
|
2002-09-18 02:50:53 +04:00
|
|
|
switch (i->nnn()) {
|
2001-04-10 05:04:59 +04:00
|
|
|
case 0: // CR0 (MSW)
|
|
|
|
SetCR0(val_32);
|
|
|
|
break;
|
|
|
|
case 2: /* CR2 */
|
2008-05-10 02:33:37 +04:00
|
|
|
BX_DEBUG(("MOV_CdRd:CR2 = %08x", val_32));
|
2001-04-10 05:04:59 +04:00
|
|
|
BX_CPU_THIS_PTR cr2 = val_32;
|
|
|
|
break;
|
|
|
|
case 3: // CR3
|
2008-05-10 02:33:37 +04:00
|
|
|
BX_DEBUG(("MOV_CdRd:CR3 = %08x", val_32));
|
2001-04-10 05:04:59 +04:00
|
|
|
// Reserved bits take on value of MOV instruction
|
2008-05-11 23:36:06 +04:00
|
|
|
SetCR3(val_32);
|
2003-02-13 18:04:11 +03:00
|
|
|
BX_INSTR_TLB_CNTRL(BX_CPU_ID, BX_INSTR_MOV_CR3, val_32);
|
2001-04-10 05:04:59 +04:00
|
|
|
break;
|
2008-06-23 06:56:31 +04:00
|
|
|
#if BX_CPU_LEVEL > 3
|
2001-04-10 05:04:59 +04:00
|
|
|
case 4: // CR4
|
2006-03-27 22:02:07 +04:00
|
|
|
// Protected mode: #GP(0) if attempt to write a 1 to
|
|
|
|
// any reserved bit of CR4
|
|
|
|
if (! SetCR4(val_32))
|
|
|
|
exception(BX_GP_EXCEPTION, 0, 0);
|
2001-04-10 05:04:59 +04:00
|
|
|
break;
|
2008-06-23 06:56:31 +04:00
|
|
|
#endif
|
2001-04-10 05:04:59 +04:00
|
|
|
default:
|
2008-06-23 06:56:31 +04:00
|
|
|
BX_ERROR(("MOV_CdRd: #UD - control register %d index out of range", i->nnn()));
|
2008-07-13 19:35:10 +04:00
|
|
|
exception(BX_UD_EXCEPTION, 0, 0);
|
2005-02-03 21:25:10 +03:00
|
|
|
}
|
2001-04-10 05:04:59 +04:00
|
|
|
}
|
|
|
|
|
2008-03-23 00:29:41 +03:00
|
|
|
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOV_RdCd(bxInstruction_c *i)
|
2001-04-10 05:04:59 +04:00
|
|
|
{
|
|
|
|
// mov control register data to register
|
2008-06-23 06:56:31 +04:00
|
|
|
Bit32u val_32 = 0;
|
2001-04-10 05:04:59 +04:00
|
|
|
|
2006-09-10 20:56:55 +04:00
|
|
|
if (!real_mode() && CPL!=0) {
|
|
|
|
BX_ERROR(("MOV_RdCd: CPL!=0 not in real mode"));
|
2003-11-14 00:17:31 +03:00
|
|
|
exception(BX_GP_EXCEPTION, 0, 0);
|
|
|
|
}
|
2001-04-10 05:04:59 +04:00
|
|
|
|
|
|
|
/* NOTES:
|
|
|
|
* 32bit operands always used
|
|
|
|
* r/m field specifies general register
|
|
|
|
* reg field specifies which special register
|
|
|
|
*/
|
|
|
|
|
2003-11-14 00:17:31 +03:00
|
|
|
/* This instruction is always treated as a register-to-register,
|
2008-02-03 00:46:54 +03:00
|
|
|
* regardless of the encoding of the MOD field in the MODRM byte.
|
2003-11-14 00:17:31 +03:00
|
|
|
*/
|
|
|
|
if (!i->modC0())
|
2006-06-27 01:07:44 +04:00
|
|
|
BX_PANIC(("MOV_RdCd(): rm field not a register!"));
|
2001-04-10 05:04:59 +04:00
|
|
|
|
2002-09-18 02:50:53 +04:00
|
|
|
switch (i->nnn()) {
|
2001-04-10 05:04:59 +04:00
|
|
|
case 0: // CR0 (MSW)
|
2008-12-06 13:21:55 +03:00
|
|
|
val_32 = BX_CPU_THIS_PTR cr0.get32();
|
2001-04-10 05:04:59 +04:00
|
|
|
break;
|
|
|
|
case 2: /* CR2 */
|
2006-06-14 20:44:33 +04:00
|
|
|
BX_DEBUG(("MOV_RdCd: reading CR2"));
|
2007-12-23 20:21:28 +03:00
|
|
|
val_32 = (Bit32u) BX_CPU_THIS_PTR cr2;
|
2001-04-10 05:04:59 +04:00
|
|
|
break;
|
|
|
|
case 3: // CR3
|
2006-03-04 12:22:55 +03:00
|
|
|
BX_DEBUG(("MOV_RdCd: reading CR3"));
|
2008-05-11 23:36:06 +04:00
|
|
|
val_32 = (Bit32u) BX_CPU_THIS_PTR cr3;
|
2001-04-10 05:04:59 +04:00
|
|
|
break;
|
|
|
|
case 4: // CR4
|
2008-06-23 19:58:22 +04:00
|
|
|
#if BX_CPU_LEVEL > 3
|
2005-10-24 01:11:32 +04:00
|
|
|
BX_DEBUG(("MOV_RdCd: read of CR4"));
|
2008-12-06 13:21:55 +03:00
|
|
|
val_32 = BX_CPU_THIS_PTR cr4.get32();
|
2001-04-10 05:04:59 +04:00
|
|
|
#endif
|
|
|
|
break;
|
|
|
|
default:
|
2008-06-23 06:56:31 +04:00
|
|
|
BX_ERROR(("MOV_RdCd: #UD - control register %d index out of range", i->nnn()));
|
2008-07-13 19:35:10 +04:00
|
|
|
exception(BX_UD_EXCEPTION, 0, 0);
|
2004-10-14 00:58:16 +04:00
|
|
|
}
|
2007-11-01 21:03:48 +03:00
|
|
|
|
2002-09-18 02:50:53 +04:00
|
|
|
BX_WRITE_32BIT_REGZ(i->rm(), val_32);
|
2002-09-15 03:17:55 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
#if BX_SUPPORT_X86_64
|
2008-03-23 00:29:41 +03:00
|
|
|
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOV_CqRq(bxInstruction_c *i)
|
2002-09-15 03:17:55 +04:00
|
|
|
{
|
2006-06-27 01:07:44 +04:00
|
|
|
BX_ASSERT(protected_mode());
|
2002-09-15 03:17:55 +04:00
|
|
|
|
|
|
|
/* NOTES:
|
|
|
|
* 64bit operands always used
|
|
|
|
* r/m field specifies general register
|
|
|
|
* reg field specifies which special register
|
|
|
|
*/
|
|
|
|
|
2007-12-14 14:27:44 +03:00
|
|
|
/* #GP(0) if CPL is not 0 */
|
|
|
|
if (CPL!=0) {
|
|
|
|
BX_ERROR(("MOV_CqRq: #GP(0) if CPL is not 0"));
|
|
|
|
exception(BX_GP_EXCEPTION, 0, 0);
|
|
|
|
}
|
|
|
|
|
2003-11-14 00:17:31 +03:00
|
|
|
/* This instruction is always treated as a register-to-register,
|
2008-02-03 00:46:54 +03:00
|
|
|
* regardless of the encoding of the MOD field in the MODRM byte.
|
2003-11-14 00:17:31 +03:00
|
|
|
*/
|
|
|
|
if (!i->modC0())
|
2006-06-27 01:07:44 +04:00
|
|
|
BX_PANIC(("MOV_CqRq(): rm field not a register!"));
|
2002-09-15 03:17:55 +04:00
|
|
|
|
2007-12-14 14:27:44 +03:00
|
|
|
Bit64u val_64 = BX_READ_64BIT_REG(i->rm());
|
2002-09-15 03:17:55 +04:00
|
|
|
|
2002-09-18 02:50:53 +04:00
|
|
|
switch (i->nnn()) {
|
2002-09-15 03:17:55 +04:00
|
|
|
case 0: // CR0 (MSW)
|
2007-12-23 20:21:28 +03:00
|
|
|
SetCR0((Bit32u) val_64);
|
2002-09-15 03:17:55 +04:00
|
|
|
break;
|
|
|
|
case 2: /* CR2 */
|
2008-05-10 02:33:37 +04:00
|
|
|
BX_DEBUG(("MOV_CqRq: write to CR2 of %08x:%08x", GET32H(val_64), GET32L(val_64)));
|
2002-09-15 03:17:55 +04:00
|
|
|
BX_CPU_THIS_PTR cr2 = val_64;
|
|
|
|
break;
|
|
|
|
case 3: // CR3
|
2008-05-10 02:33:37 +04:00
|
|
|
BX_DEBUG(("MOV_CqRq: write to CR3 of %08x:%08x", GET32H(val_64), GET32L(val_64)));
|
2002-09-15 03:17:55 +04:00
|
|
|
// Reserved bits take on value of MOV instruction
|
2008-05-11 23:36:06 +04:00
|
|
|
SetCR3(val_64);
|
2003-02-13 18:04:11 +03:00
|
|
|
BX_INSTR_TLB_CNTRL(BX_CPU_ID, BX_INSTR_MOV_CR3, val_64);
|
2002-09-15 03:17:55 +04:00
|
|
|
break;
|
|
|
|
case 4: // CR4
|
2008-05-11 23:36:06 +04:00
|
|
|
// Protected mode: #GP(0) if attempt to write a 1 to
|
|
|
|
// any reserved bit of CR4
|
2008-05-10 02:33:37 +04:00
|
|
|
BX_DEBUG(("MOV_CqRq: write to CR4 of %08x:%08x", GET32H(val_64), GET32L(val_64)));
|
2008-04-16 20:44:06 +04:00
|
|
|
if (! SetCR4(val_64))
|
2006-03-27 22:02:07 +04:00
|
|
|
exception(BX_GP_EXCEPTION, 0, 0);
|
2002-09-15 03:17:55 +04:00
|
|
|
break;
|
2004-10-14 00:58:16 +04:00
|
|
|
#if BX_SUPPORT_APIC
|
2005-05-18 02:22:35 +04:00
|
|
|
case 8: // CR8
|
2004-10-14 00:58:16 +04:00
|
|
|
// CR8 is aliased to APIC->TASK PRIORITY register
|
|
|
|
// APIC.TPR[7:4] = CR8[3:0]
|
|
|
|
// APIC.TPR[3:0] = 0
|
|
|
|
// Reads of CR8 return zero extended APIC.TPR[7:4]
|
|
|
|
// Write to CR8 update APIC.TPR[7:4]
|
2008-05-31 13:26:28 +04:00
|
|
|
if (val_64 & BX_CONST64(0xfffffffffffffff0)) {
|
|
|
|
BX_ERROR(("MOV_CqRq: Attempt to set reserved bits of CR8"));
|
|
|
|
exception(BX_GP_EXCEPTION, 0, 0);
|
|
|
|
}
|
2004-10-14 00:58:16 +04:00
|
|
|
BX_CPU_THIS_PTR local_apic.set_tpr((val_64 & 0xF) << 0x4);
|
|
|
|
break;
|
|
|
|
#endif
|
2002-09-15 03:17:55 +04:00
|
|
|
default:
|
2008-06-23 06:56:31 +04:00
|
|
|
BX_ERROR(("MOV_CqRq: #UD - control register %d index out of range", i->nnn()));
|
2008-07-13 19:35:10 +04:00
|
|
|
exception(BX_UD_EXCEPTION, 0, 0);
|
2005-02-03 21:25:10 +03:00
|
|
|
}
|
2002-09-15 03:17:55 +04:00
|
|
|
}
|
|
|
|
|
2008-03-23 00:29:41 +03:00
|
|
|
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOV_RqCq(bxInstruction_c *i)
|
2002-09-15 03:17:55 +04:00
|
|
|
{
|
|
|
|
// mov control register data to register
|
2008-06-23 06:56:31 +04:00
|
|
|
Bit64u val_64 = 0;
|
2002-09-15 03:17:55 +04:00
|
|
|
|
2006-06-27 01:07:44 +04:00
|
|
|
BX_ASSERT(protected_mode());
|
2002-09-15 03:17:55 +04:00
|
|
|
|
|
|
|
/* NOTES:
|
|
|
|
* 64bit operands always used
|
|
|
|
* r/m field specifies general register
|
|
|
|
* reg field specifies which special register
|
|
|
|
*/
|
|
|
|
|
2003-11-14 00:57:13 +03:00
|
|
|
/* #GP(0) if CPL is not 0 */
|
2006-06-27 01:07:44 +04:00
|
|
|
if (CPL!=0) {
|
|
|
|
BX_ERROR(("MOV_RqCq: #GP(0) if CPL is not 0"));
|
2002-09-15 03:17:55 +04:00
|
|
|
exception(BX_GP_EXCEPTION, 0, 0);
|
2003-11-14 00:57:13 +03:00
|
|
|
}
|
2002-09-15 03:17:55 +04:00
|
|
|
|
2007-12-14 14:27:44 +03:00
|
|
|
/* This instruction is always treated as a register-to-register,
|
2008-02-03 00:46:54 +03:00
|
|
|
* regardless of the encoding of the MOD field in the MODRM byte.
|
2007-12-14 14:27:44 +03:00
|
|
|
*/
|
|
|
|
if (!i->modC0())
|
|
|
|
BX_PANIC(("MOV_RqCq(): rm field not a register!"));
|
|
|
|
|
2002-09-18 02:50:53 +04:00
|
|
|
switch (i->nnn()) {
|
2002-09-15 03:17:55 +04:00
|
|
|
case 0: // CR0 (MSW)
|
2008-12-06 13:21:55 +03:00
|
|
|
val_64 = BX_CPU_THIS_PTR cr0.get32();
|
2002-09-15 03:17:55 +04:00
|
|
|
break;
|
|
|
|
case 2: /* CR2 */
|
2006-02-11 12:08:02 +03:00
|
|
|
BX_DEBUG(("MOV_RqCq: read of CR2"));
|
2002-09-15 03:17:55 +04:00
|
|
|
val_64 = BX_CPU_THIS_PTR cr2;
|
|
|
|
break;
|
|
|
|
case 3: // CR3
|
2006-02-11 12:08:02 +03:00
|
|
|
BX_DEBUG(("MOV_RqCq: read of CR3"));
|
2002-09-15 03:17:55 +04:00
|
|
|
val_64 = BX_CPU_THIS_PTR cr3;
|
|
|
|
break;
|
|
|
|
case 4: // CR4
|
2005-10-24 01:11:32 +04:00
|
|
|
BX_DEBUG(("MOV_RqCq: read of CR4"));
|
2008-12-06 13:21:55 +03:00
|
|
|
val_64 = BX_CPU_THIS_PTR cr4.get32();
|
2002-09-15 03:17:55 +04:00
|
|
|
break;
|
2004-10-14 00:58:16 +04:00
|
|
|
#if BX_SUPPORT_APIC
|
2005-05-18 02:22:35 +04:00
|
|
|
case 8: // CR8
|
2004-10-14 00:58:16 +04:00
|
|
|
// CR8 is aliased to APIC->TASK PRIORITY register
|
|
|
|
// APIC.TPR[7:4] = CR8[3:0]
|
|
|
|
// APIC.TPR[3:0] = 0
|
|
|
|
// Reads of CR8 return zero extended APIC.TPR[7:4]
|
|
|
|
// Write to CR8 update APIC.TPR[7:4]
|
|
|
|
val_64 = (BX_CPU_THIS_PTR local_apic.get_tpr() & 0xF) >> 4;
|
|
|
|
break;
|
|
|
|
#endif
|
2002-09-15 03:17:55 +04:00
|
|
|
default:
|
2008-06-23 06:56:31 +04:00
|
|
|
BX_ERROR(("MOV_RqCq: #UD - control register %d index out of range", i->nnn()));
|
2008-07-13 19:35:10 +04:00
|
|
|
exception(BX_UD_EXCEPTION, 0, 0);
|
2004-10-14 00:58:16 +04:00
|
|
|
}
|
2003-11-14 00:17:31 +03:00
|
|
|
|
2002-09-18 02:50:53 +04:00
|
|
|
BX_WRITE_64BIT_REG(i->rm(), val_64);
|
2001-04-10 05:04:59 +04:00
|
|
|
}
|
2005-07-01 18:06:02 +04:00
|
|
|
#endif // #if BX_SUPPORT_X86_64
|
|
|
|
|
|
|
|
#endif // #if BX_CPU_LEVEL >= 3
|
2001-04-10 05:04:59 +04:00
|
|
|
|
2005-07-31 21:57:27 +04:00
|
|
|
#if BX_CPU_LEVEL >= 2
|
2008-03-23 00:29:41 +03:00
|
|
|
void BX_CPP_AttrRegparmN(1) BX_CPU_C::LMSW_Ew(bxInstruction_c *i)
|
2005-07-31 21:57:27 +04:00
|
|
|
{
|
|
|
|
Bit16u msw;
|
|
|
|
|
2006-09-10 20:56:55 +04:00
|
|
|
if (!real_mode() && CPL!=0) {
|
|
|
|
BX_ERROR(("LMSW: CPL!=0 not in real mode"));
|
|
|
|
exception(BX_GP_EXCEPTION, 0, 0);
|
2005-07-31 21:57:27 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
if (i->modC0()) {
|
|
|
|
msw = BX_READ_16BIT_REG(i->rm());
|
|
|
|
}
|
|
|
|
else {
|
2008-08-08 13:22:49 +04:00
|
|
|
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
2008-01-10 22:37:56 +03:00
|
|
|
/* pointer, segment address pair */
|
2008-08-08 13:22:49 +04:00
|
|
|
msw = read_virtual_word(i->seg(), eaddr);
|
2005-07-31 21:57:27 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
// LMSW does not affect PG,CD,NW,AM,WP,NE,ET bits, and cannot clear PE
|
|
|
|
|
|
|
|
// LMSW cannot clear PE
|
2007-07-09 19:16:14 +04:00
|
|
|
if (BX_CPU_THIS_PTR cr0.get_PE())
|
2005-07-31 21:57:27 +04:00
|
|
|
msw |= 0x0001; // adjust PE bit to current value of 1
|
|
|
|
|
2008-05-19 23:59:29 +04:00
|
|
|
msw &= 0xf; // LMSW only affects last 4 flags
|
2008-12-06 13:21:55 +03:00
|
|
|
Bit32u cr0 = (BX_CPU_THIS_PTR cr0.get32() & 0xfffffff0) | msw;
|
2005-07-31 21:57:27 +04:00
|
|
|
SetCR0(cr0);
|
|
|
|
}
|
|
|
|
|
2008-04-28 22:18:08 +04:00
|
|
|
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SMSW_EwR(bxInstruction_c *i)
|
2005-07-31 21:57:27 +04:00
|
|
|
{
|
2008-04-28 22:18:08 +04:00
|
|
|
if (i->os32L()) {
|
2008-12-06 13:21:55 +03:00
|
|
|
BX_WRITE_32BIT_REGZ(i->rm(), BX_CPU_THIS_PTR cr0.get32());
|
2005-07-31 21:57:27 +04:00
|
|
|
}
|
|
|
|
else {
|
2008-12-06 13:21:55 +03:00
|
|
|
BX_WRITE_16BIT_REG(i->rm(), BX_CPU_THIS_PTR cr0.get32() & 0xffff);
|
2005-07-31 21:57:27 +04:00
|
|
|
}
|
|
|
|
}
|
2008-04-28 22:18:08 +04:00
|
|
|
|
|
|
|
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SMSW_EwM(bxInstruction_c *i)
|
|
|
|
{
|
2008-12-06 13:21:55 +03:00
|
|
|
Bit16u msw = BX_CPU_THIS_PTR cr0.get32() & 0xffff;
|
2008-08-08 13:22:49 +04:00
|
|
|
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
2008-04-28 22:18:08 +04:00
|
|
|
/* pointer, segment address pair */
|
2008-08-08 13:22:49 +04:00
|
|
|
write_virtual_word(i->seg(), eaddr, msw);
|
2008-04-28 22:18:08 +04:00
|
|
|
}
|
2005-07-31 21:57:27 +04:00
|
|
|
#endif
|
|
|
|
|
2008-03-23 00:29:41 +03:00
|
|
|
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOV_TdRd(bxInstruction_c *i)
|
2001-04-10 05:04:59 +04:00
|
|
|
{
|
2003-11-14 00:17:31 +03:00
|
|
|
#if BX_CPU_LEVEL <= 4
|
|
|
|
BX_PANIC(("MOV_TdRd: Still not implemented"));
|
2001-04-10 05:04:59 +04:00
|
|
|
#else
|
|
|
|
// Pentium+ does not have TRx. They were redesigned using the MSRs.
|
2001-05-30 22:56:02 +04:00
|
|
|
BX_INFO(("MOV_TdRd: causes #UD"));
|
2008-07-13 19:35:10 +04:00
|
|
|
exception(BX_UD_EXCEPTION, 0, 0);
|
2001-04-10 05:04:59 +04:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2008-03-23 00:29:41 +03:00
|
|
|
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOV_RdTd(bxInstruction_c *i)
|
2001-04-10 05:04:59 +04:00
|
|
|
{
|
2003-11-14 00:17:31 +03:00
|
|
|
#if BX_CPU_LEVEL <= 4
|
|
|
|
BX_PANIC(("MOV_RdTd: Still not implemented"));
|
2001-04-10 05:04:59 +04:00
|
|
|
#else
|
|
|
|
// Pentium+ does not have TRx. They were redesigned using the MSRs.
|
2001-05-30 22:56:02 +04:00
|
|
|
BX_INFO(("MOV_RdTd: causes #UD"));
|
2008-07-13 19:35:10 +04:00
|
|
|
exception(BX_UD_EXCEPTION, 0, 0);
|
2001-04-10 05:04:59 +04:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2004-05-11 01:05:51 +04:00
|
|
|
#if BX_CPU_LEVEL == 2
|
2008-03-23 00:29:41 +03:00
|
|
|
void BX_CPP_AttrRegparmN(1) BX_CPU_C::LOADALL(bxInstruction_c *i)
|
2001-04-10 05:04:59 +04:00
|
|
|
{
|
|
|
|
Bit16u msw, tr, flags, ip, ldtr;
|
|
|
|
Bit16u ds_raw, ss_raw, cs_raw, es_raw;
|
|
|
|
Bit16u base_15_0, limit;
|
|
|
|
Bit8u base_23_16, access;
|
|
|
|
|
2002-08-10 16:06:26 +04:00
|
|
|
if (v8086_mode()) BX_PANIC(("proc_ctrl: LOADALL in v8086 mode unsupported"));
|
2001-04-10 05:04:59 +04:00
|
|
|
|
2008-02-03 00:46:54 +03:00
|
|
|
if (BX_CPU_THIS_PTR cr0.get_PE())
|
2004-05-11 01:05:51 +04:00
|
|
|
{
|
2003-11-14 00:17:31 +03:00
|
|
|
BX_PANIC(("LOADALL not yet supported for protected mode"));
|
|
|
|
}
|
2001-04-10 05:04:59 +04:00
|
|
|
|
2003-11-14 00:17:31 +03:00
|
|
|
BX_PANIC(("LOADALL: handle CR0.val32"));
|
2001-04-10 05:04:59 +04:00
|
|
|
/* MSW */
|
2008-04-27 23:49:02 +04:00
|
|
|
BX_MEM(0)->readPhysicalPage(BX_CPU_THIS, 0x806, 2, &msw);
|
2007-07-09 19:16:14 +04:00
|
|
|
BX_CPU_THIS_PTR cr0.set_PE(msw & 0x01); msw >>= 1;
|
|
|
|
BX_CPU_THIS_PTR cr0.set_MP(msw & 0x01); msw >>= 1;
|
|
|
|
BX_CPU_THIS_PTR cr0.set_EM(msw & 0x01); msw >>= 1;
|
|
|
|
BX_CPU_THIS_PTR cr0.set_TS(msw & 0x01);
|
2001-04-10 05:04:59 +04:00
|
|
|
|
2007-07-09 19:16:14 +04:00
|
|
|
if (BX_CPU_THIS_PTR cr0.get_PE() || BX_CPU_THIS_PTR cr0.get_MP() || BX_CPU_THIS_PTR cr0.get_EM() || BX_CPU_THIS_PTR cr0.get_TS())
|
2001-05-30 22:56:02 +04:00
|
|
|
BX_PANIC(("LOADALL set PE, MP, EM or TS bits in MSW!"));
|
2001-04-10 05:04:59 +04:00
|
|
|
|
|
|
|
/* TR */
|
2008-04-27 23:49:02 +04:00
|
|
|
BX_MEM(0)->readPhysicalPage(BX_CPU_THIS, 0x816, 2, &tr);
|
2001-04-10 05:04:59 +04:00
|
|
|
BX_CPU_THIS_PTR tr.selector.value = tr;
|
2006-04-08 00:47:32 +04:00
|
|
|
BX_CPU_THIS_PTR tr.selector.rpl = (tr & 0x03); tr >>= 2;
|
|
|
|
BX_CPU_THIS_PTR tr.selector.ti = (tr & 0x01); tr >>= 1;
|
2001-04-10 05:04:59 +04:00
|
|
|
BX_CPU_THIS_PTR tr.selector.index = tr;
|
2008-04-27 23:49:02 +04:00
|
|
|
BX_MEM(0)->readPhysicalPage(BX_CPU_THIS, 0x860, 2, &base_15_0);
|
|
|
|
BX_MEM(0)->readPhysicalPage(BX_CPU_THIS, 0x862, 1, &base_23_16);
|
|
|
|
BX_MEM(0)->readPhysicalPage(BX_CPU_THIS, 0x863, 1, &access);
|
|
|
|
BX_MEM(0)->readPhysicalPage(BX_CPU_THIS, 0x864, 2, &limit);
|
2001-04-10 05:04:59 +04:00
|
|
|
|
|
|
|
BX_CPU_THIS_PTR tr.cache.valid =
|
|
|
|
BX_CPU_THIS_PTR tr.cache.p = (access & 0x80) >> 7;
|
|
|
|
BX_CPU_THIS_PTR tr.cache.dpl = (access & 0x60) >> 5;
|
|
|
|
BX_CPU_THIS_PTR tr.cache.segment = (access & 0x10) >> 4;
|
2001-10-10 01:15:14 +04:00
|
|
|
// don't allow busy bit in tr.cache.type, so bit 2 is masked away too.
|
|
|
|
BX_CPU_THIS_PTR tr.cache.type = (access & 0x0d);
|
2006-08-31 22:18:17 +04:00
|
|
|
BX_CPU_THIS_PTR tr.cache.u.system.base = (base_23_16 << 16) | base_15_0;
|
|
|
|
BX_CPU_THIS_PTR tr.cache.u.system.limit = limit;
|
2001-04-10 05:04:59 +04:00
|
|
|
|
2005-02-03 21:25:10 +03:00
|
|
|
if ((BX_CPU_THIS_PTR tr.selector.value & 0xfffc) == 0) {
|
2001-04-10 05:04:59 +04:00
|
|
|
BX_CPU_THIS_PTR tr.cache.valid = 0;
|
2005-02-03 21:25:10 +03:00
|
|
|
}
|
2006-08-31 22:18:17 +04:00
|
|
|
if (BX_CPU_THIS_PTR tr.cache.u.system.limit < 43 ||
|
2006-04-08 00:47:32 +04:00
|
|
|
BX_CPU_THIS_PTR tr.cache.type != BX_SYS_SEGMENT_AVAIL_286_TSS ||
|
|
|
|
BX_CPU_THIS_PTR tr.cache.segment)
|
|
|
|
{
|
2001-04-10 05:04:59 +04:00
|
|
|
BX_CPU_THIS_PTR tr.cache.valid = 0;
|
2005-02-03 21:25:10 +03:00
|
|
|
}
|
|
|
|
if (BX_CPU_THIS_PTR tr.cache.valid==0)
|
|
|
|
{
|
2006-05-22 00:41:48 +04:00
|
|
|
BX_CPU_THIS_PTR tr.selector.value = 0;
|
|
|
|
BX_CPU_THIS_PTR tr.selector.index = 0;
|
|
|
|
BX_CPU_THIS_PTR tr.selector.ti = 0;
|
|
|
|
BX_CPU_THIS_PTR tr.selector.rpl = 0;
|
2006-08-31 22:18:17 +04:00
|
|
|
BX_CPU_THIS_PTR tr.cache.u.system.base = 0;
|
|
|
|
BX_CPU_THIS_PTR tr.cache.u.system.limit = 0;
|
2006-05-22 00:41:48 +04:00
|
|
|
BX_CPU_THIS_PTR tr.cache.p = 0;
|
2005-02-03 21:25:10 +03:00
|
|
|
}
|
2001-04-10 05:04:59 +04:00
|
|
|
|
|
|
|
/* FLAGS */
|
2008-04-27 23:49:02 +04:00
|
|
|
BX_MEM(0)->readPhysicalPage(BX_CPU_THIS, 0x818, 2, &flags);
|
2001-04-10 05:04:59 +04:00
|
|
|
write_flags(flags, 1, 1);
|
|
|
|
|
|
|
|
/* IP */
|
2008-04-27 23:49:02 +04:00
|
|
|
BX_MEM(0)->readPhysicalPage(BX_CPU_THIS, 0x81a, 2, &IP);
|
2001-04-10 05:04:59 +04:00
|
|
|
|
|
|
|
/* LDTR */
|
2008-04-27 23:49:02 +04:00
|
|
|
BX_MEM(0)->readPhysicalPage(BX_CPU_THIS, 0x81c, 2, &ldtr);
|
2001-04-10 05:04:59 +04:00
|
|
|
BX_CPU_THIS_PTR ldtr.selector.value = ldtr;
|
2006-04-08 00:47:32 +04:00
|
|
|
BX_CPU_THIS_PTR ldtr.selector.rpl = (ldtr & 0x03); ldtr >>= 2;
|
|
|
|
BX_CPU_THIS_PTR ldtr.selector.ti = (ldtr & 0x01); ldtr >>= 1;
|
2001-04-10 05:04:59 +04:00
|
|
|
BX_CPU_THIS_PTR ldtr.selector.index = ldtr;
|
2005-02-03 21:25:10 +03:00
|
|
|
if ((BX_CPU_THIS_PTR ldtr.selector.value & 0xfffc) == 0)
|
|
|
|
{
|
2001-04-10 05:04:59 +04:00
|
|
|
BX_CPU_THIS_PTR ldtr.cache.valid = 0;
|
|
|
|
BX_CPU_THIS_PTR ldtr.cache.p = 0;
|
|
|
|
BX_CPU_THIS_PTR ldtr.cache.segment = 0;
|
|
|
|
BX_CPU_THIS_PTR ldtr.cache.type = 0;
|
2006-08-31 22:18:17 +04:00
|
|
|
BX_CPU_THIS_PTR ldtr.cache.u.system.base = 0;
|
|
|
|
BX_CPU_THIS_PTR ldtr.cache.u.system.limit = 0;
|
2001-04-10 05:04:59 +04:00
|
|
|
BX_CPU_THIS_PTR ldtr.selector.value = 0;
|
|
|
|
BX_CPU_THIS_PTR ldtr.selector.index = 0;
|
|
|
|
BX_CPU_THIS_PTR ldtr.selector.ti = 0;
|
2005-02-03 21:25:10 +03:00
|
|
|
}
|
2001-04-10 05:04:59 +04:00
|
|
|
else {
|
2008-04-27 23:49:02 +04:00
|
|
|
BX_MEM(0)->readPhysicalPage(BX_CPU_THIS, 0x854, 2, &base_15_0);
|
|
|
|
BX_MEM(0)->readPhysicalPage(BX_CPU_THIS, 0x856, 1, &base_23_16);
|
|
|
|
BX_MEM(0)->readPhysicalPage(BX_CPU_THIS, 0x857, 1, &access);
|
|
|
|
BX_MEM(0)->readPhysicalPage(BX_CPU_THIS, 0x858, 2, &limit);
|
2001-04-10 05:04:59 +04:00
|
|
|
BX_CPU_THIS_PTR ldtr.cache.valid =
|
|
|
|
BX_CPU_THIS_PTR ldtr.cache.p = access >> 7;
|
|
|
|
BX_CPU_THIS_PTR ldtr.cache.dpl = (access >> 5) & 0x03;
|
|
|
|
BX_CPU_THIS_PTR ldtr.cache.segment = (access >> 4) & 0x01;
|
|
|
|
BX_CPU_THIS_PTR ldtr.cache.type = (access & 0x0f);
|
2006-08-31 22:18:17 +04:00
|
|
|
BX_CPU_THIS_PTR ldtr.cache.u.system.base = (base_23_16 << 16) | base_15_0;
|
|
|
|
BX_CPU_THIS_PTR ldtr.cache.u.system.limit = limit;
|
2001-04-10 05:04:59 +04:00
|
|
|
|
|
|
|
if (access == 0) {
|
2008-02-07 21:28:50 +03:00
|
|
|
BX_PANIC(("loadall: LDTR case access byte=0"));
|
2005-02-03 21:25:10 +03:00
|
|
|
}
|
|
|
|
if (BX_CPU_THIS_PTR ldtr.cache.valid==0) {
|
2001-05-30 22:56:02 +04:00
|
|
|
BX_PANIC(("loadall: ldtr.valid=0"));
|
2005-02-03 21:25:10 +03:00
|
|
|
}
|
2001-04-10 05:04:59 +04:00
|
|
|
if (BX_CPU_THIS_PTR ldtr.cache.segment) { /* not a system segment */
|
2001-05-30 22:56:02 +04:00
|
|
|
BX_INFO((" AR byte = %02x", (unsigned) access));
|
|
|
|
BX_PANIC(("loadall: LDTR descriptor cache loaded with non system segment"));
|
2005-02-03 21:25:10 +03:00
|
|
|
}
|
2006-08-25 23:56:03 +04:00
|
|
|
if (BX_CPU_THIS_PTR ldtr.cache.type != BX_SYS_SEGMENT_LDT) {
|
|
|
|
BX_PANIC(("loadall: LDTR.type(%u) != LDT", (unsigned) (access & 0x0f)));
|
2001-04-10 05:04:59 +04:00
|
|
|
}
|
2005-02-03 21:25:10 +03:00
|
|
|
}
|
2001-04-10 05:04:59 +04:00
|
|
|
|
|
|
|
/* DS */
|
2008-04-27 23:49:02 +04:00
|
|
|
BX_MEM(0)->readPhysicalPage(BX_CPU_THIS, 0x81e, 2, &ds_raw);
|
2008-06-23 06:56:31 +04:00
|
|
|
parse_selector(ds_raw, &BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS].selector);
|
2008-04-27 23:49:02 +04:00
|
|
|
BX_MEM(0)->readPhysicalPage(BX_CPU_THIS, 0x848, 2, &base_15_0);
|
|
|
|
BX_MEM(0)->readPhysicalPage(BX_CPU_THIS, 0x84a, 1, &base_23_16);
|
|
|
|
BX_MEM(0)->readPhysicalPage(BX_CPU_THIS, 0x84b, 1, &access);
|
|
|
|
BX_MEM(0)->readPhysicalPage(BX_CPU_THIS, 0x84c, 2, &limit);
|
2001-04-10 05:04:59 +04:00
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS].cache.u.segment.base = (base_23_16 << 16) | base_15_0;
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS].cache.u.segment.limit = limit;
|
2006-06-12 20:58:27 +04:00
|
|
|
set_ar_byte(BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS].cache, access);
|
|
|
|
|
|
|
|
if ((BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS].selector.value & 0xfffc) == 0) {
|
2001-04-10 05:04:59 +04:00
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS].cache.valid = 0;
|
2005-02-03 21:25:10 +03:00
|
|
|
}
|
2006-06-12 20:58:27 +04:00
|
|
|
else {
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS].cache.valid = 1;
|
|
|
|
}
|
|
|
|
if (BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS].cache.valid==0 ||
|
2005-02-03 21:25:10 +03:00
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS].cache.segment==0)
|
|
|
|
{
|
2001-05-30 22:56:02 +04:00
|
|
|
BX_PANIC(("loadall: DS invalid"));
|
2005-02-03 21:25:10 +03:00
|
|
|
}
|
2001-04-10 05:04:59 +04:00
|
|
|
|
|
|
|
/* SS */
|
2008-04-27 23:49:02 +04:00
|
|
|
BX_MEM(0)->readPhysicalPage(BX_CPU_THIS, 0x820, 2, &ss_raw);
|
2008-06-23 06:56:31 +04:00
|
|
|
parse_selector(ss_raw, &BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].selector);
|
2008-04-27 23:49:02 +04:00
|
|
|
BX_MEM(0)->readPhysicalPage(BX_CPU_THIS, 0x842, 2, &base_15_0);
|
|
|
|
BX_MEM(0)->readPhysicalPage(BX_CPU_THIS, 0x844, 1, &base_23_16);
|
|
|
|
BX_MEM(0)->readPhysicalPage(BX_CPU_THIS, 0x845, 1, &access);
|
|
|
|
BX_MEM(0)->readPhysicalPage(BX_CPU_THIS, 0x846, 2, &limit);
|
2001-04-10 05:04:59 +04:00
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.base = (base_23_16 << 16) | base_15_0;
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.limit = limit;
|
2006-06-12 20:58:27 +04:00
|
|
|
set_ar_byte(BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache, access);
|
2001-04-10 05:04:59 +04:00
|
|
|
|
2005-02-03 21:25:10 +03:00
|
|
|
if ((BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].selector.value & 0xfffc) == 0) {
|
2001-04-10 05:04:59 +04:00
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.valid = 0;
|
2005-02-03 21:25:10 +03:00
|
|
|
}
|
2006-06-12 20:58:27 +04:00
|
|
|
else {
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.valid = 1;
|
|
|
|
}
|
|
|
|
if (BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.valid==0 ||
|
2005-02-03 21:25:10 +03:00
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.segment==0)
|
|
|
|
{
|
2001-05-30 22:56:02 +04:00
|
|
|
BX_PANIC(("loadall: SS invalid"));
|
2005-02-03 21:25:10 +03:00
|
|
|
}
|
2008-02-03 00:46:54 +03:00
|
|
|
|
2001-04-10 05:04:59 +04:00
|
|
|
/* CS */
|
2008-04-27 23:49:02 +04:00
|
|
|
BX_MEM(0)->readPhysicalPage(BX_CPU_THIS, 0x822, 2, &cs_raw);
|
2008-06-23 06:56:31 +04:00
|
|
|
parse_selector(cs_raw, &BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector);
|
2008-04-27 23:49:02 +04:00
|
|
|
BX_MEM(0)->readPhysicalPage(BX_CPU_THIS, 0x83c, 2, &base_15_0);
|
|
|
|
BX_MEM(0)->readPhysicalPage(BX_CPU_THIS, 0x83e, 1, &base_23_16);
|
|
|
|
BX_MEM(0)->readPhysicalPage(BX_CPU_THIS, 0x83f, 1, &access);
|
|
|
|
BX_MEM(0)->readPhysicalPage(BX_CPU_THIS, 0x840, 2, &limit);
|
2001-04-10 05:04:59 +04:00
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.base = (base_23_16 << 16) | base_15_0;
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.limit = limit;
|
2006-06-12 20:58:27 +04:00
|
|
|
set_ar_byte(BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache, access);
|
|
|
|
|
|
|
|
if ((BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value & 0xfffc) == 0) {
|
2001-04-10 05:04:59 +04:00
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.valid = 0;
|
2005-02-03 21:25:10 +03:00
|
|
|
}
|
2006-06-12 20:58:27 +04:00
|
|
|
else {
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.valid = 1;
|
|
|
|
}
|
|
|
|
if (BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.valid==0 ||
|
2005-02-03 21:25:10 +03:00
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.segment==0)
|
|
|
|
{
|
2001-05-30 22:56:02 +04:00
|
|
|
BX_PANIC(("loadall: CS invalid"));
|
2005-02-03 21:25:10 +03:00
|
|
|
}
|
2001-04-10 05:04:59 +04:00
|
|
|
|
2008-08-03 23:53:09 +04:00
|
|
|
updateFetchModeMask();
|
2008-04-07 22:39:17 +04:00
|
|
|
handleCpuModeChange();
|
|
|
|
|
2001-04-10 05:04:59 +04:00
|
|
|
/* ES */
|
2008-04-27 23:49:02 +04:00
|
|
|
BX_MEM(0)->readPhysicalPage(BX_CPU_THIS, 0x824, 2, &es_raw);
|
2008-06-23 06:56:31 +04:00
|
|
|
parse_selector(es_raw, &BX_CPU_THIS_PTR sregs[BX_SEG_REG_ES].selector);
|
2008-04-27 23:49:02 +04:00
|
|
|
BX_MEM(0)->readPhysicalPage(BX_CPU_THIS, 0x836, 2, &base_15_0);
|
|
|
|
BX_MEM(0)->readPhysicalPage(BX_CPU_THIS, 0x838, 1, &base_23_16);
|
|
|
|
BX_MEM(0)->readPhysicalPage(BX_CPU_THIS, 0x839, 1, &access);
|
|
|
|
BX_MEM(0)->readPhysicalPage(BX_CPU_THIS, 0x83a, 2, &limit);
|
2001-04-10 05:04:59 +04:00
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_ES].cache.u.segment.base = (base_23_16 << 16) | base_15_0;
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_ES].cache.u.segment.limit = limit;
|
2006-06-12 20:58:27 +04:00
|
|
|
set_ar_byte(BX_CPU_THIS_PTR sregs[BX_SEG_REG_ES].cache, access);
|
|
|
|
|
|
|
|
if ((BX_CPU_THIS_PTR sregs[BX_SEG_REG_ES].selector.value & 0xfffc) == 0) {
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_ES].cache.valid = 0;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_ES].cache.valid = 1;
|
|
|
|
}
|
|
|
|
if (BX_CPU_THIS_PTR sregs[BX_SEG_REG_ES].cache.valid==0 ||
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_ES].cache.segment==0)
|
|
|
|
{
|
|
|
|
BX_PANIC(("loadall: ES invalid"));
|
|
|
|
}
|
2001-04-10 05:04:59 +04:00
|
|
|
|
|
|
|
#if 0
|
2008-04-07 22:39:17 +04:00
|
|
|
BX_INFO(("cs.dpl = %02x", (unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.dpl));
|
|
|
|
BX_INFO(("ss.dpl = %02x", (unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.dpl));
|
|
|
|
BX_INFO(("BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS].dpl = 0x%02x", (unsigned) BX_CPU_THIS_PTR ds.cache.dpl));
|
|
|
|
BX_INFO(("BX_CPU_THIS_PTR sregs[BX_SEG_REG_ES].dpl = 0x%02x", (unsigned) BX_CPU_THIS_PTR es.cache.dpl));
|
|
|
|
BX_INFO(("LOADALL: setting cs.selector.rpl to %u",
|
|
|
|
(unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.rpl));
|
|
|
|
BX_INFO(("LOADALL: setting ss.selector.rpl to %u",
|
|
|
|
(unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].selector.rpl));
|
|
|
|
BX_INFO(("LOADALL: setting ds.selector.rpl to %u",
|
|
|
|
(unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS].selector.rpl));
|
|
|
|
BX_INFO(("LOADALL: setting es.selector.rpl to %u",
|
|
|
|
(unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_ES].selector.rpl));
|
2001-04-10 05:04:59 +04:00
|
|
|
#endif
|
|
|
|
|
2008-04-27 23:49:02 +04:00
|
|
|
BX_MEM(0)->readPhysicalPage(BX_CPU_THIS, 0x826, 2, &DI);
|
|
|
|
BX_MEM(0)->readPhysicalPage(BX_CPU_THIS, 0x828, 2, &SI);
|
|
|
|
BX_MEM(0)->readPhysicalPage(BX_CPU_THIS, 0x82a, 2, &BP);
|
|
|
|
BX_MEM(0)->readPhysicalPage(BX_CPU_THIS, 0x82c, 2, &SP);
|
|
|
|
BX_MEM(0)->readPhysicalPage(BX_CPU_THIS, 0x82e, 2, &BX);
|
|
|
|
BX_MEM(0)->readPhysicalPage(BX_CPU_THIS, 0x830, 2, &DX);
|
|
|
|
BX_MEM(0)->readPhysicalPage(BX_CPU_THIS, 0x832, 2, &CX);
|
|
|
|
BX_MEM(0)->readPhysicalPage(BX_CPU_THIS, 0x834, 2, &AX);
|
2001-04-10 05:04:59 +04:00
|
|
|
|
|
|
|
/* GDTR */
|
2008-04-27 23:49:02 +04:00
|
|
|
BX_MEM(0)->readPhysicalPage(BX_CPU_THIS, 0x84e, 2, &base_15_0);
|
|
|
|
BX_MEM(0)->readPhysicalPage(BX_CPU_THIS, 0x850, 1, &base_23_16);
|
|
|
|
BX_MEM(0)->readPhysicalPage(BX_CPU_THIS, 0x851, 1, &access);
|
|
|
|
BX_MEM(0)->readPhysicalPage(BX_CPU_THIS, 0x852, 2, &limit);
|
2001-04-10 05:04:59 +04:00
|
|
|
BX_CPU_THIS_PTR gdtr.base = (base_23_16 << 16) | base_15_0;
|
|
|
|
BX_CPU_THIS_PTR gdtr.limit = limit;
|
|
|
|
|
|
|
|
/* IDTR */
|
2008-04-27 23:49:02 +04:00
|
|
|
BX_MEM(0)->readPhysicalPage(BX_CPU_THIS, 0x85a, 2, &base_15_0);
|
|
|
|
BX_MEM(0)->readPhysicalPage(BX_CPU_THIS, 0x85c, 1, &base_23_16);
|
|
|
|
BX_MEM(0)->readPhysicalPage(BX_CPU_THIS, 0x85d, 1, &access);
|
|
|
|
BX_MEM(0)->readPhysicalPage(BX_CPU_THIS, 0x85e, 2, &limit);
|
2001-04-10 05:04:59 +04:00
|
|
|
BX_CPU_THIS_PTR idtr.base = (base_23_16 << 16) | base_15_0;
|
|
|
|
BX_CPU_THIS_PTR idtr.limit = limit;
|
|
|
|
}
|
2004-05-11 01:05:51 +04:00
|
|
|
#endif
|
2001-04-10 05:04:59 +04:00
|
|
|
|
2006-04-05 21:31:35 +04:00
|
|
|
void BX_CPU_C::handleCpuModeChange(void)
|
|
|
|
{
|
2008-02-01 16:25:23 +03:00
|
|
|
unsigned mode = BX_CPU_THIS_PTR cpu_mode;
|
|
|
|
|
2006-04-05 21:31:35 +04:00
|
|
|
#if BX_SUPPORT_X86_64
|
2008-04-01 00:56:27 +04:00
|
|
|
if (BX_CPU_THIS_PTR efer.get_LMA()) {
|
2007-07-09 19:16:14 +04:00
|
|
|
if (! BX_CPU_THIS_PTR cr0.get_PE()) {
|
2006-04-05 21:31:35 +04:00
|
|
|
BX_PANIC(("change_cpu_mode: EFER.LMA is set when CR0.PE=0 !"));
|
|
|
|
}
|
|
|
|
if (BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.l) {
|
|
|
|
BX_CPU_THIS_PTR cpu_mode = BX_MODE_LONG_64;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
BX_CPU_THIS_PTR cpu_mode = BX_MODE_LONG_COMPAT;
|
2008-05-12 00:46:11 +04:00
|
|
|
// clear upper part of RIP/RSP when leaving 64-bit long mode
|
|
|
|
BX_CLEAR_64BIT_HIGH(BX_64BIT_REG_RIP);
|
|
|
|
BX_CLEAR_64BIT_HIGH(BX_64BIT_REG_RSP);
|
2006-04-05 21:31:35 +04:00
|
|
|
}
|
|
|
|
}
|
2008-02-03 00:46:54 +03:00
|
|
|
else
|
2006-04-05 21:31:35 +04:00
|
|
|
#endif
|
|
|
|
{
|
2007-07-09 19:16:14 +04:00
|
|
|
if (BX_CPU_THIS_PTR cr0.get_PE()) {
|
2008-06-16 00:41:34 +04:00
|
|
|
if (BX_CPU_THIS_PTR get_VM()) {
|
2006-04-05 21:31:35 +04:00
|
|
|
BX_CPU_THIS_PTR cpu_mode = BX_MODE_IA32_V8086;
|
2008-06-16 00:41:34 +04:00
|
|
|
}
|
2008-02-01 16:25:23 +03:00
|
|
|
else
|
2006-04-05 21:31:35 +04:00
|
|
|
BX_CPU_THIS_PTR cpu_mode = BX_MODE_IA32_PROTECTED;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
BX_CPU_THIS_PTR cpu_mode = BX_MODE_IA32_REAL;
|
2008-06-16 00:41:34 +04:00
|
|
|
BX_ASSERT(CPL == 0);
|
2006-04-05 21:31:35 +04:00
|
|
|
}
|
|
|
|
}
|
2008-02-01 16:25:23 +03:00
|
|
|
|
2008-04-07 23:59:53 +04:00
|
|
|
if (mode != BX_CPU_THIS_PTR cpu_mode) {
|
2008-02-01 16:25:23 +03:00
|
|
|
BX_DEBUG(("%s activated", cpu_mode_string(BX_CPU_THIS_PTR cpu_mode)));
|
2008-04-07 23:59:53 +04:00
|
|
|
#if BX_DEBUGGER
|
|
|
|
if (BX_CPU_THIS_PTR mode_break) {
|
|
|
|
BX_CPU_THIS_PTR stop_reason = STOP_MODE_BREAK_POINT;
|
|
|
|
bx_debug_break(); // trap into debugger
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
2006-04-05 21:31:35 +04:00
|
|
|
}
|
|
|
|
|
2007-11-21 00:22:03 +03:00
|
|
|
#if BX_CPU_LEVEL >= 4 && BX_SUPPORT_ALIGNMENT_CHECK
|
|
|
|
void BX_CPU_C::handleAlignmentCheck(void)
|
|
|
|
{
|
|
|
|
if (CPL == 3 && BX_CPU_THIS_PTR cr0.get_AM() && BX_CPU_THIS_PTR get_AC()) {
|
2008-09-16 23:20:03 +04:00
|
|
|
if (BX_CPU_THIS_PTR alignment_check_mask == 0) {
|
|
|
|
BX_CPU_THIS_PTR alignment_check_mask = 0xF;
|
|
|
|
BX_INFO(("Enable alignment check (#AC exception)"));
|
|
|
|
#if BX_SUPPORT_ICACHE
|
|
|
|
BX_CPU_THIS_PTR iCache.flushICacheEntries();
|
|
|
|
#endif
|
|
|
|
}
|
2007-11-21 00:22:03 +03:00
|
|
|
}
|
|
|
|
else {
|
2008-09-16 23:20:03 +04:00
|
|
|
if (BX_CPU_THIS_PTR alignment_check_mask != 0) {
|
|
|
|
BX_CPU_THIS_PTR alignment_check_mask = 0;
|
|
|
|
BX_INFO(("Disable alignment check (#AC exception)"));
|
|
|
|
#if BX_SUPPORT_ICACHE
|
|
|
|
BX_CPU_THIS_PTR iCache.flushICacheEntries();
|
|
|
|
#endif
|
|
|
|
}
|
2007-11-21 00:22:03 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2008-04-20 02:29:44 +04:00
|
|
|
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SetCR0(Bit32u val_32)
|
2001-04-10 05:04:59 +04:00
|
|
|
{
|
2004-09-22 00:19:19 +04:00
|
|
|
bx_bool pe = val_32 & 0x01;
|
|
|
|
bx_bool nw = (val_32 >> 29) & 0x01;
|
|
|
|
bx_bool cd = (val_32 >> 30) & 0x01;
|
|
|
|
bx_bool pg = (val_32 >> 31) & 0x01;
|
|
|
|
|
|
|
|
if (pg && !pe) {
|
2007-01-29 00:27:31 +03:00
|
|
|
BX_ERROR(("SetCR0: GP(0) when attempt to set CR0.PG with CR0.PE cleared !"));
|
2004-09-22 00:19:19 +04:00
|
|
|
exception(BX_GP_EXCEPTION, 0, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (nw && !cd) {
|
2007-01-29 00:27:31 +03:00
|
|
|
BX_ERROR(("SetCR0: GP(0) when attempt to set CR0.NW with CR0.CD cleared !"));
|
2004-09-22 00:19:19 +04:00
|
|
|
exception(BX_GP_EXCEPTION, 0, 0);
|
|
|
|
}
|
|
|
|
|
2007-08-01 00:25:52 +04:00
|
|
|
if (pe && BX_CPU_THIS_PTR get_VM()) BX_PANIC(("EFLAGS.VM=1, enter_PM"));
|
2005-03-15 22:00:04 +03:00
|
|
|
|
2001-04-10 05:04:59 +04:00
|
|
|
// from either MOV_CdRd() or debug functions
|
|
|
|
// protection checks made already or forcing from debug
|
2008-12-06 13:21:55 +03:00
|
|
|
Bit32u oldCR0 = BX_CPU_THIS_PTR cr0.get32();
|
2001-04-10 05:04:59 +04:00
|
|
|
|
2005-02-03 21:43:23 +03:00
|
|
|
#if BX_SUPPORT_X86_64
|
2007-07-09 19:16:14 +04:00
|
|
|
bx_bool prev_pg = BX_CPU_THIS_PTR cr0.get_PG();
|
2001-04-10 05:04:59 +04:00
|
|
|
|
2007-11-21 00:22:03 +03:00
|
|
|
if (prev_pg==0 && pg) {
|
2008-04-01 00:56:27 +04:00
|
|
|
if (BX_CPU_THIS_PTR efer.get_LME()) {
|
2002-09-15 03:17:55 +04:00
|
|
|
if (!BX_CPU_THIS_PTR cr4.get_PAE()) {
|
2007-09-11 00:47:08 +04:00
|
|
|
BX_ERROR(("SetCR0: attempt to enter x86-64 long mode without enabling CR4.PAE !"));
|
2002-09-15 03:17:55 +04:00
|
|
|
exception(BX_GP_EXCEPTION, 0, 0);
|
2005-02-03 21:25:10 +03:00
|
|
|
}
|
2007-09-11 00:47:08 +04:00
|
|
|
if (BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.l) {
|
|
|
|
BX_ERROR(("SetCR0: attempt to enter x86-64 long mode with CS.L !"));
|
|
|
|
exception(BX_GP_EXCEPTION, 0, 0);
|
|
|
|
}
|
2008-04-20 22:10:32 +04:00
|
|
|
if (BX_CPU_THIS_PTR tr.cache.type <= 3) {
|
|
|
|
BX_ERROR(("SetCR0: attempt to enter x86-64 long mode with TSS286 in TR !"));
|
|
|
|
exception(BX_GP_EXCEPTION, 0, 0);
|
|
|
|
}
|
2008-04-01 00:56:27 +04:00
|
|
|
BX_CPU_THIS_PTR efer.set_LMA(1);
|
2002-09-15 03:17:55 +04:00
|
|
|
}
|
2005-02-03 21:25:10 +03:00
|
|
|
}
|
2007-11-21 00:22:03 +03:00
|
|
|
else if (prev_pg==1 && ! pg) {
|
2007-09-25 20:11:32 +04:00
|
|
|
if (BX_CPU_THIS_PTR cpu_mode == BX_MODE_LONG_64) {
|
|
|
|
BX_ERROR(("SetCR0: attempt to leave 64 bit mode directly to legacy mode !"));
|
|
|
|
exception(BX_GP_EXCEPTION, 0, 0);
|
|
|
|
}
|
2008-04-01 00:56:27 +04:00
|
|
|
if (BX_CPU_THIS_PTR efer.get_LMA()) {
|
2008-02-15 22:03:54 +03:00
|
|
|
if (BX_CPU_THIS_PTR gen_reg[BX_64BIT_REG_RIP].dword.hrx != 0) {
|
2002-09-15 03:17:55 +04:00
|
|
|
BX_PANIC(("SetCR0: attempt to leave x86-64 LONG mode with RIP upper != 0 !!!"));
|
2005-02-03 21:25:10 +03:00
|
|
|
}
|
2008-04-01 00:56:27 +04:00
|
|
|
BX_CPU_THIS_PTR efer.set_LMA(0);
|
2002-09-15 03:17:55 +04:00
|
|
|
}
|
2005-02-03 21:25:10 +03:00
|
|
|
}
|
2002-09-15 03:17:55 +04:00
|
|
|
#endif // #if BX_SUPPORT_X86_64
|
|
|
|
|
2007-11-21 00:22:03 +03:00
|
|
|
// handle reserved bits behaviour
|
|
|
|
#if BX_CPU_LEVEL == 3
|
|
|
|
val_32 = val_32 | 0x7ffffff0;
|
|
|
|
#elif BX_CPU_LEVEL == 4
|
|
|
|
val_32 = (val_32 | 0x00000010) & 0xe005003f;
|
|
|
|
#elif BX_CPU_LEVEL == 5
|
|
|
|
val_32 = val_32 | 0x00000010;
|
|
|
|
#elif BX_CPU_LEVEL == 6
|
|
|
|
val_32 = (val_32 | 0x00000010) & 0xe005003f;
|
|
|
|
#else
|
|
|
|
#error "SetCR0: implement reserved bits behaviour for this CPU_LEVEL"
|
|
|
|
#endif
|
2008-12-06 13:21:55 +03:00
|
|
|
BX_CPU_THIS_PTR cr0.set32(val_32);
|
2007-11-21 00:22:03 +03:00
|
|
|
|
|
|
|
#if BX_CPU_LEVEL >= 4 && BX_SUPPORT_ALIGNMENT_CHECK
|
|
|
|
handleAlignmentCheck();
|
|
|
|
#endif
|
|
|
|
|
2006-04-05 21:31:35 +04:00
|
|
|
handleCpuModeChange();
|
|
|
|
|
2002-09-07 09:21:28 +04:00
|
|
|
// Give the paging unit a chance to look for changes in bits
|
|
|
|
// it cares about, like {PG,PE}, so it can flush cache entries etc.
|
2007-07-09 19:16:14 +04:00
|
|
|
pagingCR0Changed(oldCR0, val_32);
|
2001-04-10 05:04:59 +04:00
|
|
|
}
|
|
|
|
|
2002-09-18 02:14:33 +04:00
|
|
|
#if BX_CPU_LEVEL >= 4
|
2008-04-20 02:29:44 +04:00
|
|
|
bx_bool BX_CPP_AttrRegparmN(1) BX_CPU_C::SetCR4(bx_address val)
|
2002-09-15 03:17:55 +04:00
|
|
|
{
|
2008-12-06 13:21:55 +03:00
|
|
|
Bit32u oldCR4 = BX_CPU_THIS_PTR cr4.get32();
|
2008-04-18 22:32:40 +04:00
|
|
|
bx_address allowMask = 0;
|
2005-02-03 21:25:10 +03:00
|
|
|
|
2008-02-13 01:41:39 +03:00
|
|
|
// CR4 bits definitions:
|
|
|
|
// [31-19] Reserved, Must be Zero
|
|
|
|
// [18] OSXSAVE: Operating System XSAVE Support R/W
|
|
|
|
// [17-15] Reserved, Must be Zero
|
|
|
|
// [14] SMXE: SMX Extensions R/W
|
|
|
|
// [13] VMXE: VMX Extensions R/W
|
|
|
|
// [12-11] Reserved, Must be Zero
|
2002-09-23 18:45:44 +04:00
|
|
|
// [10] OSXMMEXCPT: Operating System Unmasked Exception Support R/W
|
|
|
|
// [9] OSFXSR: Operating System FXSAVE/FXRSTOR Support R/W
|
|
|
|
// [8] PCE: Performance-Monitoring Counter Enable R/W
|
|
|
|
// [7] PGE: Page-Global Enable R/W
|
|
|
|
// [6] MCE: Machine Check Enable R/W
|
|
|
|
// [5] PAE: Physical-Address Extension R/W
|
|
|
|
// [4] PSE: Page Size Extensions R/W
|
|
|
|
// [3] DE: Debugging Extensions R/W
|
|
|
|
// [2] TSD: Time Stamp Disable R/W
|
|
|
|
// [1] PVI: Protected-Mode Virtual Interrupts R/W
|
|
|
|
// [0] VME: Virtual-8086 Mode Extensions R/W
|
|
|
|
|
2005-10-17 03:13:19 +04:00
|
|
|
#if BX_SUPPORT_VME
|
|
|
|
allowMask |= (1<<0) | (1<<1); /* VME */
|
|
|
|
#endif
|
|
|
|
|
2005-01-24 00:13:49 +03:00
|
|
|
#if BX_CPU_LEVEL >= 5
|
|
|
|
allowMask |= (1<<2); /* TSD */
|
2002-09-15 03:17:55 +04:00
|
|
|
#endif
|
|
|
|
|
2005-02-03 21:43:23 +03:00
|
|
|
allowMask |= (1<<3); /* DE */
|
|
|
|
|
2007-09-20 21:33:35 +04:00
|
|
|
#if BX_SUPPORT_LARGE_PAGES
|
2005-01-24 00:13:49 +03:00
|
|
|
allowMask |= (1<<4);
|
2002-09-15 03:17:55 +04:00
|
|
|
#endif
|
|
|
|
|
2005-11-27 00:36:51 +03:00
|
|
|
#if BX_SUPPORT_PAE
|
2002-09-15 03:17:55 +04:00
|
|
|
allowMask |= (1<<5);
|
|
|
|
#endif
|
2005-01-09 11:14:15 +03:00
|
|
|
|
|
|
|
#if BX_CPU_LEVEL >= 5
|
2008-02-13 01:41:39 +03:00
|
|
|
// NOTE: exception 18 (#MC) never appears in Bochs
|
2005-01-09 11:14:15 +03:00
|
|
|
allowMask |= (1<<6); /* MCE */
|
|
|
|
#endif
|
2002-09-15 03:17:55 +04:00
|
|
|
|
2005-11-27 00:36:51 +03:00
|
|
|
#if BX_SUPPORT_GLOBAL_PAGES
|
2005-01-24 00:13:49 +03:00
|
|
|
allowMask |= (1<<7);
|
|
|
|
#endif
|
|
|
|
|
2003-10-24 22:34:16 +04:00
|
|
|
#if BX_CPU_LEVEL >= 6
|
2006-01-13 14:11:29 +03:00
|
|
|
allowMask |= (1<<8); /* PCE */
|
2002-11-08 23:26:12 +03:00
|
|
|
allowMask |= (1<<9); /* OSFXSR */
|
2003-10-24 22:34:16 +04:00
|
|
|
#endif
|
|
|
|
|
|
|
|
#if BX_SUPPORT_SSE
|
2003-05-15 20:41:17 +04:00
|
|
|
allowMask |= (1<<10); /* OSXMMECPT */
|
2002-11-08 23:26:12 +03:00
|
|
|
#endif
|
2002-09-15 03:17:55 +04:00
|
|
|
|
2008-02-13 01:41:39 +03:00
|
|
|
#if BX_SUPPORT_XSAVE
|
|
|
|
allowMask |= (1<<18); /* OSXSAVE */
|
|
|
|
#endif
|
|
|
|
|
2002-09-15 03:17:55 +04:00
|
|
|
#if BX_SUPPORT_X86_64
|
2006-04-23 20:11:16 +04:00
|
|
|
// need to GP(0) if LMA=1 and PAE=1->0
|
2008-04-16 20:44:06 +04:00
|
|
|
if (BX_CPU_THIS_PTR efer.get_LMA()) {
|
|
|
|
if(!(val & (1<<5)) && BX_CPU_THIS_PTR cr4.get_PAE()) {
|
|
|
|
BX_ERROR(("SetCR4: attempt to change PAE when EFER.LMA=1"));
|
|
|
|
return 0;
|
|
|
|
}
|
2003-05-15 20:41:17 +04:00
|
|
|
}
|
2002-09-15 03:17:55 +04:00
|
|
|
#endif
|
|
|
|
|
|
|
|
// Need to GPF if trying to set undefined bits.
|
2008-04-16 20:44:06 +04:00
|
|
|
if (val & ~allowMask) {
|
|
|
|
BX_ERROR(("#GP(0): SetCR4: Write of 0x%08x not supported (allowMask=0x%x)", val, allowMask));
|
2006-03-27 22:02:07 +04:00
|
|
|
return 0;
|
2003-05-15 20:41:17 +04:00
|
|
|
}
|
2006-03-27 22:02:07 +04:00
|
|
|
|
2008-12-06 13:21:55 +03:00
|
|
|
BX_CPU_THIS_PTR cr4.set32(val);
|
|
|
|
pagingCR4Changed(oldCR4, BX_CPU_THIS_PTR cr4.get32());
|
2006-03-27 22:02:07 +04:00
|
|
|
return 1;
|
2002-09-15 03:17:55 +04:00
|
|
|
}
|
2002-09-18 02:14:33 +04:00
|
|
|
#endif
|
2002-09-15 03:17:55 +04:00
|
|
|
|
2008-03-23 00:29:41 +03:00
|
|
|
void BX_CPP_AttrRegparmN(1) BX_CPU_C::RDPMC(bxInstruction_c *i)
|
2003-10-24 22:34:16 +04:00
|
|
|
{
|
2004-05-11 01:05:51 +04:00
|
|
|
/* We need to be Pentium with MMX or later */
|
|
|
|
#if ((BX_CPU_LEVEL >= 6) || (BX_SUPPORT_MMX && BX_CPU_LEVEL == 5))
|
|
|
|
bx_bool pce = BX_CPU_THIS_PTR cr4.get_PCE();
|
|
|
|
|
|
|
|
if ((pce==1) || (CPL==0) || real_mode())
|
|
|
|
{
|
|
|
|
/* According to manual, Pentium 4 has 18 counters,
|
|
|
|
* previous versions have two. And the P4 also can do
|
|
|
|
* short read-out (EDX always 0). Otherwise it is
|
|
|
|
* limited to 40 bits.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#if (BX_CPU_LEVEL == 6 && BX_SUPPORT_SSE >= 2) // Pentium 4 processor (see cpuid.cc)
|
|
|
|
if ((ECX & 0x7fffffff) >= 18)
|
2006-06-10 02:29:07 +04:00
|
|
|
exception(BX_GP_EXCEPTION, 0, 0);
|
2004-05-11 01:05:51 +04:00
|
|
|
#else //
|
|
|
|
if ((ECX & 0xffffffff) >= 2)
|
2006-06-10 02:29:07 +04:00
|
|
|
exception(BX_GP_EXCEPTION, 0, 0);
|
2004-05-11 01:05:51 +04:00
|
|
|
#endif
|
|
|
|
// Most counters are for hardware specific details, which
|
|
|
|
// we anyhow do not emulate (like pipeline stalls etc)
|
|
|
|
|
|
|
|
// Could be interesting to count number of memory reads,
|
|
|
|
// writes. Misaligned etc... But to monitor bochs, this
|
|
|
|
// is easier done from the host.
|
|
|
|
|
2007-09-25 20:11:32 +04:00
|
|
|
RAX = 0;
|
|
|
|
RDX = 0; // if P4 and ECX & 0x10000000, then always 0 (short read 32 bits)
|
2004-05-11 01:05:51 +04:00
|
|
|
|
|
|
|
BX_ERROR(("RDPMC: Performance Counters Support not reasonably implemented yet"));
|
|
|
|
} else {
|
|
|
|
// not allowed to use RDPMC!
|
2006-06-10 02:29:07 +04:00
|
|
|
exception(BX_GP_EXCEPTION, 0, 0);
|
2004-05-11 01:05:51 +04:00
|
|
|
}
|
2003-10-24 22:34:16 +04:00
|
|
|
#else
|
2008-07-13 19:35:10 +04:00
|
|
|
exception(BX_UD_EXCEPTION, 0, 0);
|
2003-10-24 22:34:16 +04:00
|
|
|
#endif
|
2001-04-10 05:04:59 +04:00
|
|
|
}
|
|
|
|
|
2006-01-21 15:06:03 +03:00
|
|
|
#if BX_CPU_LEVEL >= 5
|
2008-04-18 22:32:40 +04:00
|
|
|
BX_CPP_INLINE Bit64u BX_CPU_C::get_TSC(void)
|
2006-01-21 15:06:03 +03:00
|
|
|
{
|
|
|
|
return bx_pc_system.time_ticks() - BX_CPU_THIS_PTR msr.tsc_last_reset;
|
|
|
|
}
|
|
|
|
|
2008-04-18 22:32:40 +04:00
|
|
|
void BX_CPU_C::set_TSC(Bit64u newval)
|
2006-01-21 15:06:03 +03:00
|
|
|
{
|
|
|
|
// compute the correct setting of tsc_last_reset so that a get_TSC()
|
|
|
|
// will return newval
|
2008-04-18 22:32:40 +04:00
|
|
|
BX_CPU_THIS_PTR msr.tsc_last_reset = bx_pc_system.time_ticks() - newval;
|
2006-01-21 15:06:03 +03:00
|
|
|
|
|
|
|
// verify
|
2008-04-18 22:32:40 +04:00
|
|
|
BX_ASSERT (get_TSC() == newval);
|
2006-01-21 15:06:03 +03:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2008-03-23 00:29:41 +03:00
|
|
|
void BX_CPP_AttrRegparmN(1) BX_CPU_C::RDTSC(bxInstruction_c *i)
|
2001-04-10 05:04:59 +04:00
|
|
|
{
|
|
|
|
#if BX_CPU_LEVEL >= 5
|
2008-04-18 22:32:40 +04:00
|
|
|
if (! BX_CPU_THIS_PTR cr4.get_TSD() || CPL==0) {
|
2001-05-23 12:16:07 +04:00
|
|
|
// return ticks
|
2006-01-21 15:06:03 +03:00
|
|
|
Bit64u ticks = BX_CPU_THIS_PTR get_TSC();
|
2002-09-15 03:17:55 +04:00
|
|
|
RAX = (Bit32u) (ticks & 0xffffffff);
|
|
|
|
RDX = (Bit32u) ((ticks >> 32) & 0xffffffff);
|
2001-05-23 12:16:07 +04:00
|
|
|
} else {
|
|
|
|
// not allowed to use RDTSC!
|
2005-08-05 16:47:33 +04:00
|
|
|
BX_ERROR(("RDTSC: incorrect usage of RDTSC instruction !"));
|
2006-06-10 02:29:07 +04:00
|
|
|
exception(BX_GP_EXCEPTION, 0, 0);
|
2001-05-23 12:16:07 +04:00
|
|
|
}
|
2001-04-10 05:04:59 +04:00
|
|
|
#else
|
2005-08-05 16:47:33 +04:00
|
|
|
BX_INFO(("RDTSC: Pentium CPU required, use --enable-cpu=5"));
|
2008-07-13 19:35:10 +04:00
|
|
|
exception(BX_UD_EXCEPTION, 0, 0);
|
2001-04-10 05:04:59 +04:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2005-08-05 16:47:33 +04:00
|
|
|
#if BX_SUPPORT_X86_64
|
2008-03-23 00:29:41 +03:00
|
|
|
void BX_CPP_AttrRegparmN(1) BX_CPU_C::RDTSCP(bxInstruction_c *i)
|
2005-08-05 16:47:33 +04:00
|
|
|
{
|
|
|
|
RDTSC(i);
|
|
|
|
RCX = MSR_TSC_AUX;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2007-11-01 21:03:48 +03:00
|
|
|
#if BX_SUPPORT_MONITOR_MWAIT
|
|
|
|
bx_bool BX_CPU_C::is_monitor(bx_phy_address begin_addr, unsigned len)
|
|
|
|
{
|
|
|
|
bx_phy_address end_addr = begin_addr + len;
|
|
|
|
if (begin_addr >= BX_CPU_THIS_PTR monitor.monitor_end || end_addr <= BX_CPU_THIS_PTR monitor.monitor_begin)
|
|
|
|
return 0;
|
|
|
|
else
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
void BX_CPU_C::check_monitor(bx_phy_address begin_addr, unsigned len)
|
|
|
|
{
|
|
|
|
if (is_monitor(begin_addr, len)) {
|
|
|
|
// wakeup from MWAIT state
|
|
|
|
BX_ASSERT(BX_CPU_THIS_PTR debug_trap & BX_DEBUG_TRAP_MWAIT);
|
|
|
|
BX_CPU_THIS_PTR debug_trap &= ~BX_DEBUG_TRAP_SPECIAL;
|
|
|
|
// clear monitor
|
2008-04-27 23:49:02 +04:00
|
|
|
BX_MEM(0)->clear_monitor(BX_CPU_THIS_PTR bx_cpuid);
|
2008-10-03 21:00:46 +04:00
|
|
|
BX_CPU_THIS_PTR monitor.reset_monitor();
|
2007-11-01 21:03:48 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2008-03-23 00:29:41 +03:00
|
|
|
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MONITOR(bxInstruction_c *i)
|
2007-10-12 01:29:01 +04:00
|
|
|
{
|
|
|
|
#if BX_SUPPORT_MONITOR_MWAIT
|
2008-02-03 00:46:54 +03:00
|
|
|
// TODO: #UD when CPL > 0 and
|
2007-10-12 01:29:01 +04:00
|
|
|
// MSR 0xC0010015[MONITOR_MWAIT_USER_UNABLE] = 1
|
2007-11-09 15:06:34 +03:00
|
|
|
BX_DEBUG(("MONITOR instruction executed EAX = 0x08x", (unsigned) EAX));
|
2007-10-12 01:29:01 +04:00
|
|
|
|
|
|
|
if (RCX != 0) {
|
|
|
|
BX_ERROR(("MONITOR: no optional extensions supported"));
|
|
|
|
exception(BX_GP_EXCEPTION, 0, 0);
|
|
|
|
}
|
|
|
|
|
2008-09-09 00:47:33 +04:00
|
|
|
bx_segment_reg_t *seg = &BX_CPU_THIS_PTR sregs[i->seg()];
|
|
|
|
|
|
|
|
bx_address offset;
|
2007-10-12 01:29:01 +04:00
|
|
|
|
|
|
|
#if BX_SUPPORT_X86_64
|
|
|
|
if (i->as64L()) {
|
2008-04-07 22:39:17 +04:00
|
|
|
offset = RAX;
|
2007-10-12 01:29:01 +04:00
|
|
|
}
|
|
|
|
else
|
|
|
|
#endif
|
|
|
|
if (i->as32L()) {
|
2008-04-07 22:39:17 +04:00
|
|
|
offset = EAX;
|
2007-10-12 01:29:01 +04:00
|
|
|
}
|
|
|
|
else {
|
2008-04-07 22:39:17 +04:00
|
|
|
offset = AX;
|
2007-10-12 01:29:01 +04:00
|
|
|
}
|
|
|
|
|
2008-09-09 00:47:33 +04:00
|
|
|
// set MONITOR
|
|
|
|
bx_address laddr = BX_CPU_THIS_PTR get_laddr(i->seg(), offset);
|
|
|
|
|
|
|
|
#if BX_SUPPORT_X86_64
|
|
|
|
if (BX_CPU_THIS_PTR cpu_mode == BX_MODE_LONG_64) {
|
|
|
|
if (! IsCanonical(laddr)) {
|
|
|
|
BX_ERROR(("MONITOR: non-canonical access !"));
|
2008-06-25 14:34:21 +04:00
|
|
|
exception(int_number(i->seg()), 0, 0);
|
2008-09-09 00:47:33 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
#endif
|
|
|
|
{
|
|
|
|
// check if we could access the memory segment
|
|
|
|
if (!(seg->cache.valid & SegAccessROK)) {
|
|
|
|
if (! read_virtual_checks(seg, offset, 1))
|
|
|
|
exception(int_number(i->seg()), 0, 0);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
if (offset > seg->cache.u.segment.limit_scaled) {
|
|
|
|
BX_ERROR(("MONITOR: segment limit violation"));
|
|
|
|
exception(int_number(i->seg()), 0, 0);
|
|
|
|
}
|
|
|
|
}
|
2008-06-12 23:14:40 +04:00
|
|
|
}
|
2007-10-12 01:29:01 +04:00
|
|
|
|
2008-09-09 00:47:33 +04:00
|
|
|
bx_phy_address paddr;
|
2007-11-01 21:03:48 +03:00
|
|
|
|
|
|
|
if (BX_CPU_THIS_PTR cr0.get_PG()) {
|
2007-12-17 00:03:46 +03:00
|
|
|
paddr = dtranslate_linear(laddr, CPL, BX_READ);
|
2007-11-01 21:03:48 +03:00
|
|
|
paddr = A20ADDR(paddr);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
paddr = A20ADDR(laddr);
|
|
|
|
}
|
|
|
|
|
|
|
|
BX_CPU_THIS_PTR monitor.monitor_begin = paddr;
|
|
|
|
BX_CPU_THIS_PTR monitor.monitor_end = paddr + CACHE_LINE_SIZE;
|
2007-10-12 01:29:01 +04:00
|
|
|
|
2008-10-03 20:53:08 +04:00
|
|
|
// Set the monitor immediately. If monitor is still armed when we MWAIT,
|
|
|
|
// the processor will stall.
|
|
|
|
bx_pc_system.invlpg(BX_CPU_THIS_PTR monitor.monitor_begin);
|
|
|
|
if ((BX_CPU_THIS_PTR monitor.monitor_end & ~0xfff) != (BX_CPU_THIS_PTR monitor.monitor_begin & ~0xfff))
|
|
|
|
bx_pc_system.invlpg(BX_CPU_THIS_PTR monitor.monitor_end);
|
|
|
|
BX_DEBUG(("MONITOR for phys_addr=0x" FMT_PHY_ADDRX, BX_CPU_THIS_PTR monitor.monitor_begin));
|
|
|
|
BX_MEM(0)->set_monitor(BX_CPU_THIS_PTR bx_cpuid);
|
2007-10-12 01:29:01 +04:00
|
|
|
#else
|
|
|
|
BX_INFO(("MONITOR: use --enable-monitor-mwait to enable MONITOR/MWAIT support"));
|
2008-07-13 19:35:10 +04:00
|
|
|
exception(BX_UD_EXCEPTION, 0, 0);
|
2007-10-12 01:29:01 +04:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2008-03-23 00:29:41 +03:00
|
|
|
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MWAIT(bxInstruction_c *i)
|
2007-10-12 01:29:01 +04:00
|
|
|
{
|
|
|
|
#if BX_SUPPORT_MONITOR_MWAIT
|
2008-02-03 00:46:54 +03:00
|
|
|
// TODO: #UD when CPL > 0 and
|
2007-10-12 01:29:01 +04:00
|
|
|
// MSR 0xC0010015[MONITOR_MWAIT_USER_UNABLE] = 1
|
2007-10-12 23:30:51 +04:00
|
|
|
BX_DEBUG(("MWAIT instruction executed ECX = 0x%08x", ECX));
|
2007-10-12 01:29:01 +04:00
|
|
|
|
|
|
|
// only one extension is supported
|
|
|
|
// ECX[0] - interrupt MWAIT even if EFLAGS.IF = 0
|
2007-11-01 21:03:48 +03:00
|
|
|
if (RCX & ~(BX_CONST64(1))) {
|
2007-10-12 01:29:01 +04:00
|
|
|
BX_ERROR(("MWAIT: incorrect optional extensions in RCX"));
|
|
|
|
exception(BX_GP_EXCEPTION, 0, 0);
|
|
|
|
}
|
|
|
|
|
2007-11-01 21:03:48 +03:00
|
|
|
// Do not enter optimized state if MONITOR wasn't properly set
|
|
|
|
if (BX_CPU_THIS_PTR monitor.monitor_begin == BX_CPU_THIS_PTR monitor.monitor_end) {
|
2008-04-26 00:08:23 +04:00
|
|
|
BX_DEBUG(("MWAIT: incorrect MONITOR settings"));
|
2007-11-01 21:03:48 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2008-10-03 20:53:08 +04:00
|
|
|
// If monitor has already triggered, we just return.
|
|
|
|
if (!BX_CPU_THIS_PTR monitor.armed) {
|
|
|
|
BX_DEBUG(("MWAIT: the MONITOR was already triggered"));
|
|
|
|
return;
|
|
|
|
}
|
2007-11-01 21:03:48 +03:00
|
|
|
|
|
|
|
// stops instruction execution and places the processor in a optimized
|
|
|
|
// state. Events that cause exit from MWAIT state are:
|
|
|
|
// A store from another processor to monitored range, any unmasked
|
|
|
|
// interrupt, including INTR, NMI, SMI, INIT or reset will resume
|
|
|
|
// the execution. Any far control transfer between MONITOR and MWAIT
|
|
|
|
// resets the monitoring logic.
|
|
|
|
|
|
|
|
// artificial trap bit, why use another variable.
|
|
|
|
BX_CPU_THIS_PTR debug_trap |= BX_DEBUG_TRAP_MWAIT; // artificial trap
|
|
|
|
if (ECX & 1)
|
|
|
|
BX_CPU_THIS_PTR debug_trap |= BX_DEBUG_TRAP_MWAIT_IF;
|
|
|
|
BX_CPU_THIS_PTR async_event = 1; // so processor knows to check
|
|
|
|
// Execution of this instruction completes. The processor
|
2008-02-03 00:46:54 +03:00
|
|
|
// will remain in a optimized state until one of the above
|
2007-11-01 21:03:48 +03:00
|
|
|
// conditions is met.
|
|
|
|
|
2007-12-14 00:41:32 +03:00
|
|
|
BX_INSTR_MWAIT(BX_CPU_ID, BX_CPU_THIS_PTR monitor.monitor_begin, CACHE_LINE_SIZE, ECX);
|
|
|
|
|
2008-02-03 00:46:54 +03:00
|
|
|
#if BX_USE_IDLE_HACK
|
2007-11-01 21:03:48 +03:00
|
|
|
bx_gui->sim_is_idle();
|
|
|
|
#endif
|
|
|
|
|
2007-10-12 01:29:01 +04:00
|
|
|
#else
|
|
|
|
BX_INFO(("MWAIT: use --enable-monitor-mwait to enable MONITOR/MWAIT support"));
|
2008-07-13 19:35:10 +04:00
|
|
|
exception(BX_UD_EXCEPTION, 0, 0);
|
2007-10-12 01:29:01 +04:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2008-03-23 00:29:41 +03:00
|
|
|
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SYSENTER(bxInstruction_c *i)
|
2003-01-20 23:10:31 +03:00
|
|
|
{
|
|
|
|
#if BX_SUPPORT_SEP
|
2008-04-21 01:44:13 +04:00
|
|
|
if (real_mode()) {
|
|
|
|
BX_ERROR(("SYSENTER not recognized in real mode !"));
|
2006-06-10 02:29:07 +04:00
|
|
|
exception(BX_GP_EXCEPTION, 0, 0);
|
2003-01-20 23:10:31 +03:00
|
|
|
}
|
2006-02-28 22:50:08 +03:00
|
|
|
if ((BX_CPU_THIS_PTR msr.sysenter_cs_msr & BX_SELECTOR_RPL_MASK) == 0) {
|
2007-10-12 01:29:01 +04:00
|
|
|
BX_ERROR(("SYSENTER with zero sysenter_cs_msr !"));
|
2006-06-10 02:29:07 +04:00
|
|
|
exception(BX_GP_EXCEPTION, 0, 0);
|
2003-01-20 23:10:31 +03:00
|
|
|
}
|
|
|
|
|
2003-05-11 02:25:55 +04:00
|
|
|
invalidate_prefetch_q();
|
2003-01-20 23:10:31 +03:00
|
|
|
|
2005-09-29 21:32:32 +04:00
|
|
|
BX_CPU_THIS_PTR clear_VM(); // do this just like the book says to do
|
|
|
|
BX_CPU_THIS_PTR clear_IF();
|
|
|
|
BX_CPU_THIS_PTR clear_RF();
|
2003-01-20 23:10:31 +03:00
|
|
|
|
2008-04-15 18:41:50 +04:00
|
|
|
#if BX_SUPPORT_X86_64
|
|
|
|
if (long_mode()) {
|
|
|
|
if (!IsCanonical(BX_CPU_THIS_PTR msr.sysenter_eip_msr)) {
|
|
|
|
BX_ERROR(("SYSENTER with non-canonical SYSENTER_EIP_MSR !"));
|
|
|
|
exception(BX_GP_EXCEPTION, 0, 0);
|
|
|
|
}
|
|
|
|
if (!IsCanonical(BX_CPU_THIS_PTR msr.sysenter_esp_msr)) {
|
|
|
|
BX_ERROR(("SYSENTER with non-canonical SYSENTER_ESP_MSR !"));
|
|
|
|
exception(BX_SS_EXCEPTION, 0, 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2006-06-12 01:37:22 +04:00
|
|
|
parse_selector(BX_CPU_THIS_PTR msr.sysenter_cs_msr & BX_SELECTOR_RPL_MASK,
|
|
|
|
&BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector);
|
|
|
|
|
2008-09-09 00:47:33 +04:00
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.valid = SegValidCache | SegAccessROK | SegAccessWOK;
|
2006-06-12 20:58:27 +04:00
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.p = 1;
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.dpl = 0;
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.segment = 1; /* data/code segment */
|
2008-05-27 01:46:39 +04:00
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.type = BX_DATA_READ_WRITE_ACCESSED;
|
2003-01-20 23:10:31 +03:00
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.base = 0; // base address
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.limit = 0xFFFF; // segment limit
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.limit_scaled = 0xFFFFFFFF; // scaled segment limit
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.g = 1; // 4k granularity
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.avl = 0; // available for use by system
|
2008-04-15 18:41:50 +04:00
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.d_b = !long_mode();
|
|
|
|
#if BX_SUPPORT_X86_64
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.l = long_mode();
|
|
|
|
#endif
|
2003-01-20 23:10:31 +03:00
|
|
|
|
2008-08-03 23:53:09 +04:00
|
|
|
updateFetchModeMask();
|
2006-01-16 22:22:28 +03:00
|
|
|
|
2008-04-20 22:17:14 +04:00
|
|
|
#if BX_SUPPORT_X86_64
|
|
|
|
handleCpuModeChange(); // mode change could happen only when in long_mode()
|
|
|
|
#endif
|
|
|
|
|
2007-11-21 00:22:03 +03:00
|
|
|
#if BX_CPU_LEVEL >= 4 && BX_SUPPORT_ALIGNMENT_CHECK
|
2008-09-08 19:45:57 +04:00
|
|
|
BX_CPU_THIS_PTR alignment_check_mask = 0; // CPL=0
|
2007-11-21 00:22:03 +03:00
|
|
|
#endif
|
|
|
|
|
2006-06-12 01:37:22 +04:00
|
|
|
parse_selector((BX_CPU_THIS_PTR msr.sysenter_cs_msr + 8) & BX_SELECTOR_RPL_MASK,
|
|
|
|
&BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].selector);
|
|
|
|
|
2008-09-09 00:47:33 +04:00
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.valid = SegValidCache | SegAccessROK | SegAccessWOK;
|
2006-06-12 20:58:27 +04:00
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.p = 1;
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.dpl = 0;
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.segment = 1; /* data/code segment */
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.type = BX_DATA_READ_WRITE_ACCESSED;
|
2003-01-20 23:10:31 +03:00
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.base = 0; // base address
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.limit = 0xFFFF; // segment limit
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.limit_scaled = 0xFFFFFFFF; // scaled segment limit
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.g = 1; // 4k granularity
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.d_b = 1; // 32-bit mode
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.avl = 0; // available for use by system
|
2008-04-15 18:41:50 +04:00
|
|
|
#if BX_SUPPORT_X86_64
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.l = 0;
|
|
|
|
#endif
|
2003-01-20 23:10:31 +03:00
|
|
|
|
2008-04-15 18:41:50 +04:00
|
|
|
#if BX_SUPPORT_X86_64
|
|
|
|
if (long_mode()) {
|
|
|
|
RSP = BX_CPU_THIS_PTR msr.sysenter_esp_msr;
|
|
|
|
RIP = BX_CPU_THIS_PTR msr.sysenter_eip_msr;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
#endif
|
|
|
|
{
|
|
|
|
ESP = (Bit32u) BX_CPU_THIS_PTR msr.sysenter_esp_msr;
|
|
|
|
EIP = (Bit32u) BX_CPU_THIS_PTR msr.sysenter_eip_msr;
|
|
|
|
}
|
2008-01-18 11:57:35 +03:00
|
|
|
|
|
|
|
BX_INSTR_FAR_BRANCH(BX_CPU_ID, BX_INSTR_IS_SYSENTER,
|
2008-04-15 18:41:50 +04:00
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value, RIP);
|
2003-01-20 23:10:31 +03:00
|
|
|
#else
|
2003-06-20 12:58:12 +04:00
|
|
|
BX_INFO(("SYSENTER: use --enable-sep to enable SYSENTER/SYSEXIT support"));
|
2008-07-13 19:35:10 +04:00
|
|
|
exception(BX_UD_EXCEPTION, 0, 0);
|
2003-01-20 23:10:31 +03:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2008-03-23 00:29:41 +03:00
|
|
|
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SYSEXIT(bxInstruction_c *i)
|
2003-01-20 23:10:31 +03:00
|
|
|
{
|
|
|
|
#if BX_SUPPORT_SEP
|
2008-04-21 01:44:13 +04:00
|
|
|
if (real_mode() || CPL != 0) {
|
|
|
|
BX_ERROR(("SYSEXIT from real mode or with CPL<>0 !"));
|
2006-06-10 02:29:07 +04:00
|
|
|
exception(BX_GP_EXCEPTION, 0, 0);
|
2003-01-20 23:10:31 +03:00
|
|
|
}
|
2006-02-28 22:50:08 +03:00
|
|
|
if ((BX_CPU_THIS_PTR msr.sysenter_cs_msr & BX_SELECTOR_RPL_MASK) == 0) {
|
2007-10-12 01:29:01 +04:00
|
|
|
BX_ERROR(("SYSEXIT with zero sysenter_cs_msr !"));
|
2006-06-10 02:29:07 +04:00
|
|
|
exception(BX_GP_EXCEPTION, 0, 0);
|
2003-01-20 23:10:31 +03:00
|
|
|
}
|
2008-04-15 18:41:50 +04:00
|
|
|
|
|
|
|
#if BX_SUPPORT_X86_64
|
|
|
|
if (i->os64L()) {
|
|
|
|
if (!IsCanonical(RDX)) {
|
|
|
|
BX_ERROR(("SYSEXIT with non-canonical RDX (RIP) pointer !"));
|
|
|
|
exception(BX_GP_EXCEPTION, 0, 0);
|
|
|
|
}
|
|
|
|
if (!IsCanonical(RCX)) {
|
|
|
|
BX_ERROR(("SYSEXIT with non-canonical RCX (RSP) pointer !"));
|
|
|
|
exception(BX_SS_EXCEPTION, 0, 0);
|
|
|
|
}
|
2003-01-20 23:10:31 +03:00
|
|
|
}
|
2008-04-15 18:41:50 +04:00
|
|
|
#endif
|
2003-01-20 23:10:31 +03:00
|
|
|
|
2003-05-11 02:25:55 +04:00
|
|
|
invalidate_prefetch_q();
|
2003-01-20 23:10:31 +03:00
|
|
|
|
2008-04-15 18:41:50 +04:00
|
|
|
#if BX_SUPPORT_X86_64
|
|
|
|
if (i->os64L()) {
|
|
|
|
parse_selector(((BX_CPU_THIS_PTR msr.sysenter_cs_msr + 32) & BX_SELECTOR_RPL_MASK) | 3,
|
|
|
|
&BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector);
|
2006-06-12 01:37:22 +04:00
|
|
|
|
2008-09-09 00:47:33 +04:00
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.valid = SegValidCache | SegAccessROK | SegAccessWOK;
|
2008-04-15 18:41:50 +04:00
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.p = 1;
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.dpl = 3;
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.segment = 1; /* data/code segment */
|
2008-05-27 01:46:39 +04:00
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.type = BX_DATA_READ_WRITE_ACCESSED;
|
2008-04-15 18:41:50 +04:00
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.base = 0; // base address
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.limit = 0xFFFF; // segment limit
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.limit_scaled = 0xFFFFFFFF; // scaled segment limit
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.g = 1; // 4k granularity
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.avl = 0; // available for use by system
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.d_b = 0;
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.l = 1;
|
|
|
|
|
|
|
|
RSP = RCX;
|
|
|
|
RIP = RDX;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
#endif
|
|
|
|
{
|
|
|
|
parse_selector(((BX_CPU_THIS_PTR msr.sysenter_cs_msr + 16) & BX_SELECTOR_RPL_MASK) | 3,
|
|
|
|
&BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector);
|
|
|
|
|
2008-09-09 00:47:33 +04:00
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.valid = SegValidCache | SegAccessROK | SegAccessWOK;
|
2008-04-15 18:41:50 +04:00
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.p = 1;
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.dpl = 3;
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.segment = 1; /* data/code segment */
|
2008-05-27 01:46:39 +04:00
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.type = BX_DATA_READ_WRITE_ACCESSED;
|
2008-04-15 18:41:50 +04:00
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.base = 0; // base address
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.limit = 0xFFFF; // segment limit
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.limit_scaled = 0xFFFFFFFF; // scaled segment limit
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.g = 1; // 4k granularity
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.avl = 0; // available for use by system
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.d_b = 1;
|
|
|
|
#if BX_SUPPORT_X86_64
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.l = 0;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
ESP = ECX;
|
|
|
|
EIP = EDX;
|
|
|
|
}
|
2003-01-20 23:10:31 +03:00
|
|
|
|
2008-08-03 23:53:09 +04:00
|
|
|
updateFetchModeMask();
|
2006-01-16 22:22:28 +03:00
|
|
|
|
2008-04-20 22:17:14 +04:00
|
|
|
#if BX_SUPPORT_X86_64
|
|
|
|
handleCpuModeChange(); // mode change could happen only when in long_mode()
|
|
|
|
#endif
|
|
|
|
|
2007-11-21 00:22:03 +03:00
|
|
|
#if BX_CPU_LEVEL >= 4 && BX_SUPPORT_ALIGNMENT_CHECK
|
|
|
|
handleAlignmentCheck(); // CPL was modified
|
|
|
|
#endif
|
|
|
|
|
2008-04-15 18:41:50 +04:00
|
|
|
parse_selector(((BX_CPU_THIS_PTR msr.sysenter_cs_msr + (i->os64L() ? 40:24)) & BX_SELECTOR_RPL_MASK) | 3,
|
|
|
|
&BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].selector);
|
2006-06-12 01:37:22 +04:00
|
|
|
|
2008-09-09 00:47:33 +04:00
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.valid = SegValidCache | SegAccessROK | SegAccessWOK;
|
2006-06-12 20:58:27 +04:00
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.p = 1;
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.dpl = 3;
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.segment = 1; /* data/code segment */
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.type = BX_DATA_READ_WRITE_ACCESSED;
|
2003-01-20 23:10:31 +03:00
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.base = 0; // base address
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.limit = 0xFFFF; // segment limit
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.limit_scaled = 0xFFFFFFFF; // scaled segment limit
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.g = 1; // 4k granularity
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.d_b = 1; // 32-bit mode
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.avl = 0; // available for use by system
|
2008-04-15 18:41:50 +04:00
|
|
|
#if BX_SUPPORT_X86_64
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.l = 0;
|
|
|
|
#endif
|
2008-01-18 11:57:35 +03:00
|
|
|
|
|
|
|
BX_INSTR_FAR_BRANCH(BX_CPU_ID, BX_INSTR_IS_SYSEXIT,
|
2008-04-15 18:41:50 +04:00
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value, RIP);
|
2003-01-20 23:10:31 +03:00
|
|
|
#else
|
2003-06-20 12:58:12 +04:00
|
|
|
BX_INFO(("SYSEXIT: use --enable-sep to enable SYSENTER/SYSEXIT support"));
|
2008-07-13 19:35:10 +04:00
|
|
|
exception(BX_UD_EXCEPTION, 0, 0);
|
2003-01-20 23:10:31 +03:00
|
|
|
#endif
|
2001-04-10 05:04:59 +04:00
|
|
|
}
|
|
|
|
|
2002-09-25 18:09:08 +04:00
|
|
|
#if BX_SUPPORT_X86_64
|
2008-03-23 00:29:41 +03:00
|
|
|
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SYSCALL(bxInstruction_c *i)
|
2005-03-03 23:24:52 +03:00
|
|
|
{
|
|
|
|
bx_address temp_RIP;
|
|
|
|
|
2006-06-10 02:29:07 +04:00
|
|
|
BX_DEBUG(("Execute SYSCALL instruction"));
|
|
|
|
|
2008-04-01 00:56:27 +04:00
|
|
|
if (!BX_CPU_THIS_PTR efer.get_SCE()) {
|
2005-10-17 17:06:09 +04:00
|
|
|
exception(BX_UD_EXCEPTION, 0, 0);
|
2005-03-03 23:24:52 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
invalidate_prefetch_q();
|
|
|
|
|
2008-04-15 18:41:50 +04:00
|
|
|
if (long_mode())
|
2005-03-03 23:24:52 +03:00
|
|
|
{
|
|
|
|
RCX = RIP;
|
2005-10-17 17:06:09 +04:00
|
|
|
R11 = read_eflags() & ~(EFlagsRFMask);
|
2005-03-03 23:24:52 +03:00
|
|
|
|
|
|
|
if (BX_CPU_THIS_PTR cpu_mode == BX_MODE_LONG_64) {
|
|
|
|
temp_RIP = MSR_LSTAR;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
temp_RIP = MSR_CSTAR;
|
|
|
|
}
|
|
|
|
|
2006-06-12 01:37:22 +04:00
|
|
|
// set up CS segment, flat, 64-bit DPL=0
|
|
|
|
parse_selector((MSR_STAR >> 32) & BX_SELECTOR_RPL_MASK,
|
|
|
|
&BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector);
|
|
|
|
|
2008-09-09 00:47:33 +04:00
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.valid = SegValidCache | SegAccessROK | SegAccessWOK;
|
2006-06-12 20:58:27 +04:00
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.p = 1;
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.dpl = 0;
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.segment = 1; /* data/code segment */
|
2008-05-27 01:46:39 +04:00
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.type = BX_DATA_READ_WRITE_ACCESSED;
|
2006-06-12 01:37:22 +04:00
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.base = 0; /* base address */
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.limit = 0xFFFF; /* segment limit */
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.limit_scaled = 0xFFFFFFFF; /* scaled segment limit */
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.g = 1; /* 4k granularity */
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.d_b = 0;
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.l = 1; /* 64-bit code */
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.avl = 0; /* available for use by system */
|
2005-03-03 23:24:52 +03:00
|
|
|
|
2008-08-03 23:53:09 +04:00
|
|
|
updateFetchModeMask();
|
2008-04-20 22:17:14 +04:00
|
|
|
handleCpuModeChange(); // mode change could only happen when in long_mode()
|
|
|
|
|
2007-11-21 00:22:03 +03:00
|
|
|
#if BX_CPU_LEVEL >= 4 && BX_SUPPORT_ALIGNMENT_CHECK
|
2008-09-08 19:45:57 +04:00
|
|
|
BX_CPU_THIS_PTR alignment_check_mask = 0; // CPL=0
|
2007-11-21 00:22:03 +03:00
|
|
|
#endif
|
|
|
|
|
2006-06-12 01:37:22 +04:00
|
|
|
// set up SS segment, flat, 64-bit DPL=0
|
|
|
|
parse_selector(((MSR_STAR >> 32) + 8) & BX_SELECTOR_RPL_MASK,
|
|
|
|
&BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].selector);
|
|
|
|
|
2008-09-09 00:47:33 +04:00
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.valid = SegValidCache | SegAccessROK | SegAccessWOK;
|
2006-06-12 20:58:27 +04:00
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.p = 1;
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.dpl = 0;
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.segment = 1; /* data/code segment */
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.type = BX_DATA_READ_WRITE_ACCESSED;
|
2006-06-12 01:37:22 +04:00
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.base = 0; /* base address */
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.limit = 0xFFFF; /* segment limit */
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.limit_scaled = 0xFFFFFFFF; /* scaled segment limit */
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.g = 1; /* 4k granularity */
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.d_b = 1; /* 32 bit stack */
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.l = 0;
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.avl = 0; /* available for use by system */
|
2005-03-03 23:24:52 +03:00
|
|
|
|
2005-10-17 17:06:09 +04:00
|
|
|
writeEFlags(read_eflags() & (~MSR_FMASK), EFlagsValidMask);
|
|
|
|
BX_CPU_THIS_PTR clear_RF();
|
2005-03-03 23:24:52 +03:00
|
|
|
RIP = temp_RIP;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// legacy mode
|
|
|
|
|
|
|
|
ECX = EIP;
|
|
|
|
temp_RIP = MSR_STAR & 0xFFFFFFFF;
|
|
|
|
|
2006-06-12 01:37:22 +04:00
|
|
|
// set up CS segment, flat, 32-bit DPL=0
|
|
|
|
parse_selector((MSR_STAR >> 32) & BX_SELECTOR_RPL_MASK,
|
|
|
|
&BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector);
|
|
|
|
|
2008-09-09 00:47:33 +04:00
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.valid = SegValidCache | SegAccessROK | SegAccessWOK;
|
2006-06-12 20:58:27 +04:00
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.p = 1;
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.dpl = 0;
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.segment = 1; /* data/code segment */
|
2008-05-27 01:46:39 +04:00
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.type = BX_DATA_READ_WRITE_ACCESSED;
|
2006-06-12 01:37:22 +04:00
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.base = 0; /* base address */
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.limit = 0xFFFF; /* segment limit */
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.limit_scaled = 0xFFFFFFFF; /* scaled segment limit */
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.g = 1; /* 4k granularity */
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.d_b = 1;
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.l = 0; /* 32-bit code */
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.avl = 0; /* available for use by system */
|
2005-03-03 23:24:52 +03:00
|
|
|
|
2008-08-03 23:53:09 +04:00
|
|
|
updateFetchModeMask();
|
2005-03-03 23:24:52 +03:00
|
|
|
|
2007-11-21 00:22:03 +03:00
|
|
|
#if BX_CPU_LEVEL >= 4 && BX_SUPPORT_ALIGNMENT_CHECK
|
2008-09-08 19:45:57 +04:00
|
|
|
BX_CPU_THIS_PTR alignment_check_mask = 0; // CPL=0
|
2007-11-21 00:22:03 +03:00
|
|
|
#endif
|
|
|
|
|
2006-06-12 01:37:22 +04:00
|
|
|
// set up SS segment, flat, 32-bit DPL=0
|
|
|
|
parse_selector(((MSR_STAR >> 32) + 8) & BX_SELECTOR_RPL_MASK,
|
|
|
|
&BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].selector);
|
|
|
|
|
2008-09-09 00:47:33 +04:00
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.valid = SegValidCache | SegAccessROK | SegAccessWOK;
|
2006-06-12 20:58:27 +04:00
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.p = 1;
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.dpl = 0;
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.segment = 1; /* data/code segment */
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.type = BX_DATA_READ_WRITE_ACCESSED;
|
2006-06-12 01:37:22 +04:00
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.base = 0; /* base address */
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.limit = 0xFFFF; /* segment limit */
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.limit_scaled = 0xFFFFFFFF; /* scaled segment limit */
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.g = 1; /* 4k granularity */
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.d_b = 1; /* 32 bit stack */
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.l = 0;
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.avl = 0; /* available for use by system */
|
|
|
|
|
|
|
|
BX_CPU_THIS_PTR clear_VM();
|
|
|
|
BX_CPU_THIS_PTR clear_IF();
|
|
|
|
BX_CPU_THIS_PTR clear_RF();
|
2005-03-03 23:24:52 +03:00
|
|
|
RIP = temp_RIP;
|
|
|
|
}
|
2008-01-18 11:57:35 +03:00
|
|
|
|
|
|
|
BX_INSTR_FAR_BRANCH(BX_CPU_ID, BX_INSTR_IS_SYSCALL,
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value, RIP);
|
2005-03-03 23:24:52 +03:00
|
|
|
}
|
|
|
|
|
2008-03-23 00:29:41 +03:00
|
|
|
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SYSRET(bxInstruction_c *i)
|
2005-03-03 23:24:52 +03:00
|
|
|
{
|
|
|
|
bx_address temp_RIP;
|
|
|
|
|
2006-06-10 02:29:07 +04:00
|
|
|
BX_DEBUG(("Execute SYSRET instruction"));
|
|
|
|
|
2008-04-01 00:56:27 +04:00
|
|
|
if (!BX_CPU_THIS_PTR efer.get_SCE()) {
|
2005-10-17 17:06:09 +04:00
|
|
|
exception(BX_UD_EXCEPTION, 0, 0);
|
2005-03-03 23:24:52 +03:00
|
|
|
}
|
|
|
|
|
2008-04-15 18:41:50 +04:00
|
|
|
if(!protected_mode() || CPL != 0) {
|
2006-06-10 02:29:07 +04:00
|
|
|
BX_ERROR(("SYSRET: priveledge check failed, generate #GP(0)"));
|
2005-03-03 23:24:52 +03:00
|
|
|
exception(BX_GP_EXCEPTION, 0, 0);
|
|
|
|
}
|
|
|
|
|
2008-04-15 18:41:50 +04:00
|
|
|
#if BX_SUPPORT_X86_64
|
|
|
|
if (!IsCanonical(RCX)) {
|
|
|
|
BX_ERROR(("SYSRET: canonical failure for RCX (RIP)"));
|
|
|
|
exception(BX_GP_EXCEPTION, 0, 0);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2005-03-03 23:24:52 +03:00
|
|
|
invalidate_prefetch_q();
|
2008-02-03 00:46:54 +03:00
|
|
|
|
2005-03-03 23:24:52 +03:00
|
|
|
if (BX_CPU_THIS_PTR cpu_mode == BX_MODE_LONG_64)
|
|
|
|
{
|
2006-06-12 01:37:22 +04:00
|
|
|
if (i->os64L()) {
|
|
|
|
// Return to 64-bit mode, set up CS segment, flat, 64-bit DPL=3
|
2008-04-15 18:41:50 +04:00
|
|
|
parse_selector((((MSR_STAR >> 48) + 16) & BX_SELECTOR_RPL_MASK) | 3,
|
2006-06-12 01:37:22 +04:00
|
|
|
&BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector);
|
|
|
|
|
2008-09-09 00:47:33 +04:00
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.valid = SegValidCache | SegAccessROK | SegAccessWOK;
|
2006-06-12 20:58:27 +04:00
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.p = 1;
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.dpl = 3;
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.segment = 1; /* data/code segment */
|
2008-05-27 01:46:39 +04:00
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.type = BX_DATA_READ_WRITE_ACCESSED;
|
2006-06-12 01:37:22 +04:00
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.base = 0; /* base address */
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.limit = 0xFFFF; /* segment limit */
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.limit_scaled = 0xFFFFFFFF; /* scaled segment limit */
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.g = 1; /* 4k granularity */
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.d_b = 0;
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.l = 1; /* 64-bit code */
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.avl = 0; /* available for use by system */
|
2005-03-03 23:24:52 +03:00
|
|
|
|
|
|
|
temp_RIP = RCX;
|
|
|
|
}
|
2006-06-12 01:37:22 +04:00
|
|
|
else {
|
|
|
|
// Return to 32-bit compatibility mode, set up CS segment, flat, 32-bit DPL=3
|
|
|
|
parse_selector((MSR_STAR >> 48) | 3,
|
|
|
|
&BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector);
|
|
|
|
|
2008-09-09 00:47:33 +04:00
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.valid = SegValidCache | SegAccessROK | SegAccessWOK;
|
2006-06-12 20:58:27 +04:00
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.p = 1;
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.dpl = 3;
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.segment = 1; /* data/code segment */
|
2008-05-27 01:46:39 +04:00
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.type = BX_DATA_READ_WRITE_ACCESSED;
|
2006-06-12 01:37:22 +04:00
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.base = 0; /* base address */
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.limit = 0xFFFF; /* segment limit */
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.limit_scaled = 0xFFFFFFFF; /* scaled segment limit */
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.g = 1; /* 4k granularity */
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.d_b = 1;
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.l = 0; /* 32-bit code */
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.avl = 0; /* available for use by system */
|
2005-03-03 23:24:52 +03:00
|
|
|
|
|
|
|
temp_RIP = ECX;
|
|
|
|
}
|
|
|
|
|
2008-08-03 23:53:09 +04:00
|
|
|
updateFetchModeMask();
|
2008-04-20 22:17:14 +04:00
|
|
|
handleCpuModeChange(); // mode change could only happen when in long64 mode
|
|
|
|
|
2007-11-21 00:22:03 +03:00
|
|
|
#if BX_CPU_LEVEL >= 4 && BX_SUPPORT_ALIGNMENT_CHECK
|
|
|
|
handleAlignmentCheck(); // CPL was modified
|
|
|
|
#endif
|
|
|
|
|
2006-06-12 01:37:22 +04:00
|
|
|
// SS base, limit, attributes unchanged
|
2008-04-15 18:41:50 +04:00
|
|
|
parse_selector((Bit16u)((MSR_STAR >> 48) + 8),
|
2006-06-12 01:37:22 +04:00
|
|
|
&BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].selector);
|
|
|
|
|
2008-09-09 00:47:33 +04:00
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.valid = SegValidCache | SegAccessROK | SegAccessWOK;
|
2006-06-12 20:58:27 +04:00
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.p = 1;
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.dpl = 3;
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.segment = 1; /* data/code segment */
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.type = BX_DATA_READ_WRITE_ACCESSED;
|
2005-03-03 23:24:52 +03:00
|
|
|
|
2007-12-23 20:21:28 +03:00
|
|
|
writeEFlags((Bit32u) R11, EFlagsValidMask);
|
2005-03-03 23:24:52 +03:00
|
|
|
}
|
|
|
|
else { // (!64BIT_MODE)
|
2006-06-12 01:37:22 +04:00
|
|
|
// Return to 32-bit legacy mode, set up CS segment, flat, 32-bit DPL=3
|
|
|
|
parse_selector((MSR_STAR >> 48) | 3,
|
|
|
|
&BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector);
|
|
|
|
|
2008-09-09 00:47:33 +04:00
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.valid = SegValidCache | SegAccessROK | SegAccessWOK;
|
2006-06-12 20:58:27 +04:00
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.p = 1;
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.dpl = 3;
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.segment = 1; /* data/code segment */
|
2008-05-27 01:46:39 +04:00
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.type = BX_DATA_READ_WRITE_ACCESSED;
|
2006-06-12 01:37:22 +04:00
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.base = 0; /* base address */
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.limit = 0xFFFF; /* segment limit */
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.limit_scaled = 0xFFFFFFFF; /* scaled segment limit */
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.g = 1; /* 4k granularity */
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.d_b = 1;
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.l = 0; /* 32-bit code */
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.avl = 0; /* available for use by system */
|
2005-03-03 23:24:52 +03:00
|
|
|
|
2008-08-03 23:53:09 +04:00
|
|
|
updateFetchModeMask();
|
2005-03-03 23:24:52 +03:00
|
|
|
|
2007-11-21 00:22:03 +03:00
|
|
|
#if BX_CPU_LEVEL >= 4 && BX_SUPPORT_ALIGNMENT_CHECK
|
|
|
|
handleAlignmentCheck(); // CPL was modified
|
|
|
|
#endif
|
|
|
|
|
2006-06-12 01:37:22 +04:00
|
|
|
// SS base, limit, attributes unchanged
|
2008-04-15 18:41:50 +04:00
|
|
|
parse_selector((Bit16u)((MSR_STAR >> 48) + 8),
|
2006-06-12 01:37:22 +04:00
|
|
|
&BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].selector);
|
2005-03-03 23:24:52 +03:00
|
|
|
|
2008-09-09 00:47:33 +04:00
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.valid = SegValidCache | SegAccessROK | SegAccessWOK;
|
2006-06-12 20:58:27 +04:00
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.p = 1;
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.dpl = 3;
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.segment = 1; /* data/code segment */
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.type = BX_DATA_READ_WRITE_ACCESSED;
|
2005-03-03 23:24:52 +03:00
|
|
|
|
2006-06-12 01:37:22 +04:00
|
|
|
BX_CPU_THIS_PTR assert_IF();
|
|
|
|
temp_RIP = ECX;
|
2005-03-03 23:24:52 +03:00
|
|
|
}
|
2006-06-12 01:37:22 +04:00
|
|
|
|
2008-04-20 22:10:32 +04:00
|
|
|
handleCpuModeChange();
|
|
|
|
|
2006-06-12 01:37:22 +04:00
|
|
|
RIP = temp_RIP;
|
2008-01-18 11:57:35 +03:00
|
|
|
|
|
|
|
BX_INSTR_FAR_BRANCH(BX_CPU_ID, BX_INSTR_IS_SYSRET,
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value, RIP);
|
2005-03-03 23:24:52 +03:00
|
|
|
}
|
|
|
|
|
2008-03-23 00:29:41 +03:00
|
|
|
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SWAPGS(bxInstruction_c *i)
|
2002-09-25 18:09:08 +04:00
|
|
|
{
|
|
|
|
Bit64u temp_GS_base;
|
|
|
|
|
2006-09-10 20:56:55 +04:00
|
|
|
BX_ASSERT(protected_mode());
|
|
|
|
|
2003-08-30 01:20:52 +04:00
|
|
|
if(CPL != 0)
|
2002-09-25 18:09:08 +04:00
|
|
|
exception(BX_GP_EXCEPTION, 0, 0);
|
2003-08-30 01:20:52 +04:00
|
|
|
|
2002-09-25 18:09:08 +04:00
|
|
|
temp_GS_base = MSR_GSBASE;
|
|
|
|
MSR_GSBASE = MSR_KERNELGSBASE;
|
2002-10-08 18:43:18 +04:00
|
|
|
MSR_KERNELGSBASE = temp_GS_base;
|
2002-09-25 18:09:08 +04:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2001-04-10 05:04:59 +04:00
|
|
|
#if BX_X86_DEBUGGER
|
2008-05-23 21:49:46 +04:00
|
|
|
bx_bool BX_CPU_C::hwbreakpoint_check(bx_address laddr)
|
|
|
|
{
|
|
|
|
laddr = LPFOf(laddr);
|
|
|
|
|
|
|
|
for (int i=0;i<4;i++) {
|
|
|
|
if (laddr == LPFOf(BX_CPU_THIS_PTR dr[i]))
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2007-12-03 23:49:24 +03:00
|
|
|
void BX_CPU_C::hwbreakpoint_match(bx_address laddr, unsigned len, unsigned rw)
|
|
|
|
{
|
|
|
|
if (BX_CPU_THIS_PTR dr7 & 0x000000ff) {
|
|
|
|
// Only compare debug registers if any breakpoints are enabled
|
2008-12-08 23:01:26 +03:00
|
|
|
unsigned opa, opb, write = rw & 1;
|
2007-12-03 23:49:24 +03:00
|
|
|
opa = BX_HWDebugMemRW; // Read or Write always compares vs 11b
|
2008-12-08 23:01:26 +03:00
|
|
|
if (! write) // only compares vs 11b
|
2007-12-03 23:49:24 +03:00
|
|
|
opb = opa;
|
|
|
|
else // BX_WRITE or BX_RW; also compare vs 01b
|
|
|
|
opb = BX_HWDebugMemW;
|
|
|
|
Bit32u dr6_bits = hwdebug_compare(laddr, len, opa, opb);
|
|
|
|
if (dr6_bits) {
|
|
|
|
BX_CPU_THIS_PTR debug_trap |= dr6_bits;
|
|
|
|
BX_CPU_THIS_PTR async_event = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-05-13 16:49:45 +04:00
|
|
|
Bit32u BX_CPU_C::hwdebug_compare(bx_address laddr_0, unsigned size,
|
2001-04-10 05:04:59 +04:00
|
|
|
unsigned opa, unsigned opb)
|
|
|
|
{
|
|
|
|
// Support x86 hardware debug facilities (DR0..DR7)
|
|
|
|
Bit32u dr7 = BX_CPU_THIS_PTR dr7;
|
|
|
|
|
2006-05-13 16:49:45 +04:00
|
|
|
static bx_address alignment_mask[4] =
|
2008-06-01 01:17:02 +04:00
|
|
|
// 00b=1 01b=2 10b=undef(8) 11b=4
|
|
|
|
{ 0x0, 0x1, 0x7, 0x3 };
|
2006-05-13 16:49:45 +04:00
|
|
|
|
2008-06-02 22:41:08 +04:00
|
|
|
bx_address laddr_n = laddr_0 + (size - 1);
|
|
|
|
bx_address dr[4], dr_n[4];
|
|
|
|
Bit32u dr_op[4], len[4];
|
|
|
|
bx_bool ibpoint_found_n[4], ibpoint_found = 0;
|
|
|
|
|
|
|
|
len[0] = (dr7>>18) & 3;
|
|
|
|
len[1] = (dr7>>22) & 3;
|
|
|
|
len[2] = (dr7>>26) & 3;
|
|
|
|
len[3] = (dr7>>30) & 3;
|
|
|
|
|
|
|
|
dr_op[0] = (dr7>>16) & 3;
|
|
|
|
dr_op[1] = (dr7>>20) & 3;
|
|
|
|
dr_op[2] = (dr7>>24) & 3;
|
|
|
|
dr_op[3] = (dr7>>28) & 3;
|
|
|
|
|
2008-06-14 20:55:45 +04:00
|
|
|
for (unsigned n=0;n<4;n++) {
|
|
|
|
dr[n] = BX_CPU_THIS_PTR dr[n] & ~alignment_mask[len[n]];
|
|
|
|
dr_n[n] = dr[n] + alignment_mask[len[n]];
|
|
|
|
ibpoint_found_n[n] = 0;
|
2008-06-02 22:41:08 +04:00
|
|
|
|
|
|
|
// See if this instruction address matches any breakpoints
|
2008-06-14 20:55:45 +04:00
|
|
|
if (dr7 & (3 << n*2)) {
|
|
|
|
if ((dr_op[n]==opa || dr_op[n]==opb) &&
|
|
|
|
(laddr_0 <= dr_n[n]) &&
|
|
|
|
(laddr_n >= dr[n])) {
|
|
|
|
ibpoint_found_n[n] = 1;
|
2008-06-02 22:41:08 +04:00
|
|
|
ibpoint_found = 1;
|
|
|
|
}
|
|
|
|
}
|
2005-04-18 21:21:34 +04:00
|
|
|
}
|
2001-04-10 05:04:59 +04:00
|
|
|
|
|
|
|
// If *any* enabled breakpoints matched, then we need to
|
|
|
|
// set status bits for *all* breakpoints, even disabled ones,
|
|
|
|
// as long as they meet the other breakpoint criteria.
|
2008-06-02 22:41:08 +04:00
|
|
|
// dr6_mask is the return value. These bits represent the bits
|
|
|
|
// to be OR'd into DR6 as a result of the debug event.
|
|
|
|
Bit32u dr6_mask = 0;
|
|
|
|
|
2001-04-10 05:04:59 +04:00
|
|
|
if (ibpoint_found) {
|
2008-06-02 22:41:08 +04:00
|
|
|
if (ibpoint_found_n[0]) dr6_mask |= 0x1;
|
|
|
|
if (ibpoint_found_n[1]) dr6_mask |= 0x2;
|
|
|
|
if (ibpoint_found_n[2]) dr6_mask |= 0x4;
|
|
|
|
if (ibpoint_found_n[3]) dr6_mask |= 0x8;
|
|
|
|
}
|
|
|
|
|
|
|
|
return dr6_mask;
|
2001-04-10 05:04:59 +04:00
|
|
|
}
|
2008-08-30 12:14:46 +04:00
|
|
|
|
|
|
|
void BX_CPU_C::iobreakpoint_match(unsigned port, unsigned len)
|
|
|
|
{
|
|
|
|
// Only compare debug registers if any breakpoints are enabled
|
|
|
|
if (BX_CPU_THIS_PTR cr4.get_DE() && (BX_CPU_THIS_PTR dr7 & 0x000000ff))
|
|
|
|
{
|
|
|
|
Bit32u dr_op[4], dr_len[4];
|
|
|
|
Bit32u dr7 = BX_CPU_THIS_PTR dr7;
|
|
|
|
|
|
|
|
dr_len[0] = 1 + (dr7>>18) & 3;
|
|
|
|
dr_len[1] = 1 + (dr7>>22) & 3;
|
|
|
|
dr_len[2] = 1 + (dr7>>26) & 3;
|
|
|
|
dr_len[3] = 1 + (dr7>>30) & 3;
|
|
|
|
|
|
|
|
dr_op[0] = (dr7>>16) & 3;
|
|
|
|
dr_op[1] = (dr7>>20) & 3;
|
|
|
|
dr_op[2] = (dr7>>24) & 3;
|
|
|
|
dr_op[3] = (dr7>>28) & 3;
|
|
|
|
|
|
|
|
for (unsigned n=0;n<4;n++) {
|
|
|
|
if (dr_op[n] == 2 && dr_len[n] == len && BX_CPU_THIS_PTR dr[n] == port) {
|
|
|
|
BX_CPU_THIS_PTR debug_trap |= (1<<n);
|
|
|
|
BX_CPU_THIS_PTR async_event = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2001-04-10 05:04:59 +04:00
|
|
|
#endif
|