2001-10-03 17:10:38 +04:00
|
|
|
/////////////////////////////////////////////////////////////////////////
|
2006-02-14 22:00:08 +03:00
|
|
|
// $Id: proc_ctrl.cc,v 1.134 2006-02-14 19:00:08 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
|
|
|
|
|
|
|
|
|
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"
|
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 RBX EBX
|
|
|
|
#define RCX ECX
|
|
|
|
#define RDX EDX
|
|
|
|
#endif
|
|
|
|
|
2003-11-14 00:17:31 +03:00
|
|
|
void BX_CPU_C::UndefinedOpcode(bxInstruction_c *i)
|
2001-04-10 05:04:59 +04:00
|
|
|
{
|
2002-10-16 21:37:35 +04:00
|
|
|
BX_DEBUG(("UndefinedOpcode: %02x causes exception 6", (unsigned) i->b1()));
|
2002-04-11 05:19:24 +04:00
|
|
|
exception(BX_UD_EXCEPTION, 0, 0);
|
2001-04-10 05:04:59 +04:00
|
|
|
}
|
|
|
|
|
2003-11-14 00:17:31 +03:00
|
|
|
void 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
|
|
|
}
|
|
|
|
|
|
|
|
void BX_CPU_C::PREFETCH(bxInstruction_c *i)
|
|
|
|
{
|
2003-05-15 20:41:17 +04:00
|
|
|
#if BX_SUPPORT_3DNOW || BX_SUPPORT_SSE >= 1
|
2003-02-13 18:04:11 +03:00
|
|
|
BX_INSTR_PREFETCH_HINT(BX_CPU_ID, i->nnn(), i->seg(), RMAddr(i));
|
2002-10-16 21:37:35 +04:00
|
|
|
#else
|
|
|
|
UndefinedOpcode(i);
|
|
|
|
#endif
|
2001-04-10 05:04:59 +04:00
|
|
|
}
|
|
|
|
|
2003-11-14 00:17:31 +03:00
|
|
|
void BX_CPU_C::HLT(bxInstruction_c *i)
|
2001-04-10 05:04:59 +04:00
|
|
|
{
|
|
|
|
// hack to panic if HLT comes from BIOS
|
2003-11-14 00:17:31 +03:00
|
|
|
if (BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value == 0xf000)
|
2001-11-18 19:32:40 +03:00
|
|
|
BX_PANIC(("HALT instruction encountered in the BIOS ROM"));
|
2001-04-10 05:04:59 +04:00
|
|
|
|
2005-09-15 00:01:42 +04:00
|
|
|
if (!real_mode() && CPL!=0) {
|
2002-04-11 05:19:24 +04:00
|
|
|
exception(BX_GP_EXCEPTION, 0, 0);
|
2001-04-10 05:04:59 +04:00
|
|
|
return;
|
2005-02-03 21:25:10 +03:00
|
|
|
}
|
2001-04-10 05:04:59 +04:00
|
|
|
|
2003-11-14 00:17:31 +03: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.
|
|
|
|
BX_CPU_THIS_PTR debug_trap |= 0x80000000; // artificial trap
|
|
|
|
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);
|
|
|
|
|
2001-11-12 03:45:09 +03:00
|
|
|
#if BX_USE_IDLE_HACK
|
2002-10-28 01:26:34 +03:00
|
|
|
bx_gui->sim_is_idle ();
|
2001-11-12 03:45:09 +03:00
|
|
|
#endif /* BX_USE_IDLE_HACK */
|
2001-04-10 05:04:59 +04:00
|
|
|
}
|
|
|
|
|
2005-07-07 22:40:35 +04:00
|
|
|
void BX_CPU_C::CLTS(bxInstruction_c *i)
|
2001-04-10 05:04:59 +04:00
|
|
|
{
|
|
|
|
// #GP(0) if CPL is not 0
|
2005-09-15 00:01:42 +04:00
|
|
|
if (!real_mode() && CPL!=0) {
|
2003-11-14 00:57:13 +03:00
|
|
|
BX_INFO(("CLTS: #GP(0) if CPL is not 0"));
|
2002-04-11 05:19:24 +04:00
|
|
|
exception(BX_GP_EXCEPTION, 0, 0);
|
2001-04-10 05:04:59 +04:00
|
|
|
return;
|
2005-02-03 21:25:10 +03:00
|
|
|
}
|
2001-04-10 05:04:59 +04:00
|
|
|
|
|
|
|
BX_CPU_THIS_PTR cr0.ts = 0;
|
|
|
|
BX_CPU_THIS_PTR cr0.val32 &= ~0x08;
|
|
|
|
}
|
|
|
|
|
2003-11-14 00:17:31 +03:00
|
|
|
void BX_CPU_C::INVD(bxInstruction_c *i)
|
2001-04-10 05:04:59 +04:00
|
|
|
{
|
|
|
|
#if BX_CPU_LEVEL >= 4
|
|
|
|
invalidate_prefetch_q();
|
|
|
|
|
2003-11-14 00:17:31 +03:00
|
|
|
// protected or v8086 mode
|
2001-04-10 05:04:59 +04:00
|
|
|
if (BX_CPU_THIS_PTR cr0.pe) {
|
|
|
|
if (CPL!=0) {
|
2003-11-14 00:57:13 +03:00
|
|
|
BX_INFO(("INVD: #GP(0) if CPL is not 0"));
|
2002-04-11 05:19:24 +04:00
|
|
|
exception(BX_GP_EXCEPTION, 0, 0);
|
2001-04-10 05:04:59 +04:00
|
|
|
}
|
2005-02-03 21:25:10 +03:00
|
|
|
}
|
2005-10-18 22:07:52 +04:00
|
|
|
|
2005-11-27 21:36:19 +03:00
|
|
|
BX_DEBUG(("INVD: Flush caches and TLB !"));
|
2003-02-13 18:04:11 +03:00
|
|
|
BX_INSTR_CACHE_CNTRL(BX_CPU_ID, BX_INSTR_INVD);
|
2005-10-18 22:07:52 +04:00
|
|
|
TLB_flush(1); // 1 = Flush Global entries too
|
|
|
|
#if BX_SUPPORT_ICACHE
|
|
|
|
flushICaches();
|
|
|
|
#endif
|
|
|
|
|
2001-04-10 05:04:59 +04:00
|
|
|
#else
|
2005-10-18 22:07:52 +04:00
|
|
|
BX_INFO(("INVD: required 486 support, use --enable-cpu-level=4 option"));
|
2001-04-10 05:04:59 +04:00
|
|
|
UndefinedOpcode(i);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2003-11-14 00:17:31 +03:00
|
|
|
void BX_CPU_C::WBINVD(bxInstruction_c *i)
|
2001-04-10 05:04:59 +04:00
|
|
|
{
|
|
|
|
#if BX_CPU_LEVEL >= 4
|
|
|
|
invalidate_prefetch_q();
|
|
|
|
|
|
|
|
if (BX_CPU_THIS_PTR cr0.pe) {
|
|
|
|
if (CPL!=0) {
|
2003-11-14 00:57:13 +03:00
|
|
|
BX_INFO(("WBINVD: #GP(0) if CPL is not 0"));
|
2002-04-11 05:19:24 +04:00
|
|
|
exception(BX_GP_EXCEPTION, 0, 0);
|
2001-04-10 05:04:59 +04:00
|
|
|
}
|
2005-02-03 21:25:10 +03:00
|
|
|
}
|
2005-10-18 22:07:52 +04:00
|
|
|
|
2005-11-27 21:36:19 +03:00
|
|
|
BX_DEBUG(("WBINVD: Flush caches and TLB !"));
|
2003-02-13 18:04:11 +03:00
|
|
|
BX_INSTR_CACHE_CNTRL(BX_CPU_ID, BX_INSTR_WBINVD);
|
2005-10-18 22:07:52 +04:00
|
|
|
TLB_flush(1); // 1 = Flush Global entries too
|
|
|
|
#if BX_SUPPORT_ICACHE
|
|
|
|
flushICaches();
|
|
|
|
#endif
|
|
|
|
|
2001-04-10 05:04:59 +04:00
|
|
|
#else
|
2005-10-18 22:07:52 +04:00
|
|
|
BX_INFO(("WBINVD: required 486 support, use --enable-cpu-level=4 option"));
|
2001-04-10 05:04:59 +04:00
|
|
|
UndefinedOpcode(i);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2005-07-01 18:06:02 +04:00
|
|
|
#if BX_CPU_LEVEL >= 3
|
2003-11-14 00:17:31 +03:00
|
|
|
void BX_CPU_C::MOV_DdRd(bxInstruction_c *i)
|
2001-04-10 05:04:59 +04:00
|
|
|
{
|
|
|
|
Bit32u val_32;
|
|
|
|
|
2003-08-03 20:44:53 +04:00
|
|
|
if (v8086_mode()) {
|
2003-11-14 00:57:13 +03:00
|
|
|
BX_INFO(("MOV_DdRd: v8086 mode causes #GP(0)"));
|
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
|
|
|
|
*/
|
|
|
|
|
2003-11-14 00:17:31 +03:00
|
|
|
/* This instruction is always treated as a register-to-register,
|
|
|
|
* regardless of the encoding of the MOD field in the MODRM byte.
|
|
|
|
*/
|
|
|
|
if (!i->modC0())
|
2003-11-14 00:57:13 +03:00
|
|
|
BX_INFO(("MOV_DdRd(): rm field not a register!"));
|
2001-04-10 05:04:59 +04:00
|
|
|
|
|
|
|
invalidate_prefetch_q();
|
|
|
|
|
2003-11-14 00:57:13 +03:00
|
|
|
/* #GP(0) if CPL is not 0 */
|
2001-04-10 05:04:59 +04:00
|
|
|
if (protected_mode() && CPL!=0) {
|
2003-11-14 00:57:13 +03:00
|
|
|
BX_INFO(("MOV_DdRd: #GP(0) if CPL is not 0"));
|
2002-04-11 05:19:24 +04:00
|
|
|
exception(BX_GP_EXCEPTION, 0, 0);
|
2003-11-14 00:17:31 +03:00
|
|
|
}
|
2001-04-10 05:04:59 +04:00
|
|
|
|
2002-09-18 02:50:53 +04:00
|
|
|
val_32 = BX_READ_32BIT_REG(i->rm());
|
2001-04-10 05:04:59 +04:00
|
|
|
if (bx_dbg.dreg)
|
2001-05-30 22:56:02 +04:00
|
|
|
BX_INFO(("MOV_DdRd: DR[%u]=%08xh unhandled",
|
2002-09-18 02:50:53 +04:00
|
|
|
(unsigned) i->nnn(), (unsigned) val_32));
|
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
|
|
|
|
BX_CPU_THIS_PTR dr0 = val_32;
|
|
|
|
break;
|
|
|
|
case 1: // DR1
|
|
|
|
BX_CPU_THIS_PTR dr1 = val_32;
|
|
|
|
break;
|
|
|
|
case 2: // DR2
|
|
|
|
BX_CPU_THIS_PTR dr2 = val_32;
|
|
|
|
break;
|
|
|
|
case 3: // DR3
|
|
|
|
BX_CPU_THIS_PTR dr3 = val_32;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 4: // DR4
|
|
|
|
case 6: // DR6
|
|
|
|
// DR4 aliased to DR6 by default. With Debug Extensions on,
|
|
|
|
// access to DR4 causes #UD
|
|
|
|
#if BX_CPU_LEVEL >= 4
|
2003-11-14 00:17:31 +03:00
|
|
|
if ((i->nnn() == 4) && (BX_CPU_THIS_PTR cr4.get_DE())) {
|
2001-04-10 05:04:59 +04:00
|
|
|
// Debug extensions on
|
2001-05-30 22:56:02 +04:00
|
|
|
BX_INFO(("MOV_DdRd: access to DR4 causes #UD"));
|
2001-04-10 05:04:59 +04:00
|
|
|
UndefinedOpcode(i);
|
2005-02-03 21:25:10 +03:00
|
|
|
}
|
2001-04-10 05:04:59 +04:00
|
|
|
#endif
|
|
|
|
#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
|
|
|
|
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.
|
|
|
|
|
|
|
|
// DR5 aliased to DR7 by default. With Debug Extensions on,
|
|
|
|
// access to DR5 causes #UD
|
|
|
|
#if BX_CPU_LEVEL >= 4
|
2003-11-14 00:17:31 +03:00
|
|
|
if ((i->nnn() == 5) && (BX_CPU_THIS_PTR cr4.get_DE())) {
|
2001-04-10 05:04:59 +04:00
|
|
|
// Debug extensions (CR4.DE) on
|
2001-05-30 22:56:02 +04:00
|
|
|
BX_INFO(("MOV_DdRd: access to DR5 causes #UD"));
|
2001-04-10 05:04:59 +04:00
|
|
|
UndefinedOpcode(i);
|
2005-02-03 21:25:10 +03:00
|
|
|
}
|
2001-04-10 05:04:59 +04:00
|
|
|
#endif
|
|
|
|
// Some sanity checks...
|
|
|
|
if ( val_32 & 0x00002000 ) {
|
2005-02-17 00:27:21 +03:00
|
|
|
BX_INFO(("MOV_DdRd: GD bit not supported yet"));
|
2001-04-10 05:04:59 +04:00
|
|
|
// Note: processor clears GD upon entering debug exception
|
|
|
|
// handler, to allow access to the debug registers
|
2005-02-03 21:25:10 +03:00
|
|
|
}
|
2001-04-10 05:04:59 +04:00
|
|
|
if ( (((val_32>>16) & 3)==2) ||
|
|
|
|
(((val_32>>20) & 3)==2) ||
|
|
|
|
(((val_32>>24) & 3)==2) ||
|
|
|
|
(((val_32>>28) & 3)==2) ) {
|
|
|
|
// IO breakpoints (10b) are not yet supported.
|
2003-11-14 00:17:31 +03:00
|
|
|
BX_PANIC(("MOV_DdRd: write of %08x contains IO breakpoint", val_32));
|
2005-02-03 21:25:10 +03:00
|
|
|
}
|
2001-04-10 05:04:59 +04:00
|
|
|
if ( (((val_32>>18) & 3)==2) ||
|
|
|
|
(((val_32>>22) & 3)==2) ||
|
|
|
|
(((val_32>>26) & 3)==2) ||
|
|
|
|
(((val_32>>30) & 3)==2) ) {
|
|
|
|
// LEN0..3 contains undefined length specifier (10b)
|
2003-11-14 00:17:31 +03:00
|
|
|
BX_PANIC(("MOV_DdRd: write of %08x contains undefined LENx", val_32));
|
2005-02-03 21:25:10 +03:00
|
|
|
}
|
2001-04-10 05:04:59 +04: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)) ||
|
2005-02-03 21:25:10 +03:00
|
|
|
((((val_32>>28) & 3)==0) && (((val_32>>30) & 3)!=0)) )
|
|
|
|
{
|
2001-04-10 05:04:59 +04:00
|
|
|
// Instruction breakpoint with LENx not 00b (1-byte length)
|
2003-11-14 00:17:31 +03:00
|
|
|
BX_PANIC(("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)
|
|
|
|
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:
|
2001-05-30 22:56:02 +04:00
|
|
|
BX_PANIC(("MOV_DdRd: control register index out of range"));
|
2001-04-10 05:04:59 +04:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2003-11-14 00:17:31 +03:00
|
|
|
void BX_CPU_C::MOV_RdDd(bxInstruction_c *i)
|
2001-04-10 05:04:59 +04:00
|
|
|
{
|
|
|
|
Bit32u val_32;
|
|
|
|
|
|
|
|
if (v8086_mode()) {
|
2003-11-14 00:57:13 +03:00
|
|
|
BX_INFO(("MOV_RdDd: v8086 mode causes #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
|
|
|
|
2003-11-14 00:17:31 +03:00
|
|
|
/* This instruction is always treated as a register-to-register,
|
|
|
|
* regardless of the encoding of the MOD field in the MODRM byte.
|
|
|
|
*/
|
|
|
|
if (!i->modC0())
|
2003-11-14 00:57:13 +03:00
|
|
|
BX_INFO(("MOV_RdDd(): rm field not a register!"));
|
2001-04-10 05:04:59 +04:00
|
|
|
|
2003-11-14 00:57:13 +03:00
|
|
|
/* #GP(0) if CPL is not 0 */
|
2001-04-10 05:04:59 +04:00
|
|
|
if (protected_mode() && (CPL!=0)) {
|
2003-11-14 00:57:13 +03:00
|
|
|
BX_INFO(("MOV_RdDd: #GP(0) if CPL is not 0"));
|
2002-04-11 05:19:24 +04:00
|
|
|
exception(BX_GP_EXCEPTION, 0, 0);
|
2003-11-14 00:17:31 +03:00
|
|
|
}
|
2001-04-10 05:04:59 +04:00
|
|
|
|
|
|
|
if (bx_dbg.dreg)
|
2002-09-18 02:50:53 +04:00
|
|
|
BX_INFO(("MOV_RdDd: DR%u not implemented yet", i->nnn()));
|
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
|
|
|
|
val_32 = BX_CPU_THIS_PTR dr0;
|
|
|
|
break;
|
|
|
|
case 1: // DR1
|
|
|
|
val_32 = BX_CPU_THIS_PTR dr1;
|
|
|
|
break;
|
|
|
|
case 2: // DR2
|
|
|
|
val_32 = BX_CPU_THIS_PTR dr2;
|
|
|
|
break;
|
|
|
|
case 3: // DR3
|
|
|
|
val_32 = BX_CPU_THIS_PTR dr3;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 4: // DR4
|
|
|
|
case 6: // DR6
|
|
|
|
// DR4 aliased to DR6 by default. With Debug Extensions on,
|
|
|
|
// access to DR4 causes #UD
|
|
|
|
#if BX_CPU_LEVEL >= 4
|
2002-09-18 02:50:53 +04:00
|
|
|
if ( (i->nnn() == 4) && (BX_CPU_THIS_PTR cr4.get_DE()) ) {
|
2001-04-10 05:04:59 +04:00
|
|
|
// Debug extensions on
|
2001-05-30 22:56:02 +04:00
|
|
|
BX_INFO(("MOV_RdDd: access to DR4 causes #UD"));
|
2001-04-10 05:04:59 +04:00
|
|
|
UndefinedOpcode(i);
|
2005-02-03 21:25:10 +03:00
|
|
|
}
|
2001-04-10 05:04:59 +04:00
|
|
|
#endif
|
|
|
|
val_32 = BX_CPU_THIS_PTR dr6;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 5: // DR5
|
|
|
|
case 7: // DR7
|
|
|
|
// DR5 aliased to DR7 by default. With Debug Extensions on,
|
|
|
|
// access to DR5 causes #UD
|
|
|
|
#if BX_CPU_LEVEL >= 4
|
2002-09-18 02:50:53 +04:00
|
|
|
if ( (i->nnn() == 5) && (BX_CPU_THIS_PTR cr4.get_DE()) ) {
|
2001-04-10 05:04:59 +04:00
|
|
|
// Debug extensions on
|
2001-05-30 22:56:02 +04:00
|
|
|
BX_INFO(("MOV_RdDd: access to DR5 causes #UD"));
|
2001-04-10 05:04:59 +04:00
|
|
|
UndefinedOpcode(i);
|
2005-02-03 21:25:10 +03:00
|
|
|
}
|
2001-04-10 05:04:59 +04:00
|
|
|
#endif
|
|
|
|
val_32 = BX_CPU_THIS_PTR dr7;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
2001-05-30 22:56:02 +04:00
|
|
|
BX_PANIC(("MOV_RdDd: control register index out of range"));
|
2001-04-10 05:04:59 +04:00
|
|
|
val_32 = 0;
|
|
|
|
}
|
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
|
2003-11-14 00:17:31 +03:00
|
|
|
void BX_CPU_C::MOV_DqRq(bxInstruction_c *i)
|
2002-09-15 03:17:55 +04:00
|
|
|
{
|
|
|
|
Bit64u val_64;
|
|
|
|
|
2003-11-14 00:17:31 +03:00
|
|
|
if (v8086_mode()) {
|
2003-11-14 00:57:13 +03:00
|
|
|
BX_INFO(("MOV_DqRq: v8086 mode causes #GP(0)"));
|
2003-11-14 00:17:31 +03:00
|
|
|
exception(BX_GP_EXCEPTION, 0, 0);
|
2005-02-03 21:25:10 +03:00
|
|
|
}
|
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:17:31 +03:00
|
|
|
/* This instruction is always treated as a register-to-register,
|
|
|
|
* regardless of the encoding of the MOD field in the MODRM byte.
|
|
|
|
*/
|
|
|
|
if (!i->modC0())
|
2003-11-14 00:57:13 +03:00
|
|
|
BX_INFO(("MOV_DqRq(): rm field not a register!"));
|
2002-09-15 03:17:55 +04:00
|
|
|
|
|
|
|
invalidate_prefetch_q();
|
|
|
|
|
2003-11-14 00:57:13 +03:00
|
|
|
/* #GP(0) if CPL is not 0 */
|
2002-09-15 03:17:55 +04:00
|
|
|
if (protected_mode() && CPL!=0) {
|
2003-11-14 00:57:13 +03:00
|
|
|
BX_INFO(("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
|
|
|
|
2002-09-18 02:50:53 +04:00
|
|
|
val_64 = BX_READ_64BIT_REG(i->rm());
|
2002-09-15 03:17:55 +04:00
|
|
|
if (bx_dbg.dreg)
|
|
|
|
BX_INFO(("MOV_DqRq: DR[%u]=%08xh unhandled",
|
2002-09-18 02:50:53 +04:00
|
|
|
(unsigned) i->nnn(), (unsigned) val_64));
|
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
|
|
|
|
BX_CPU_THIS_PTR dr0 = val_64;
|
|
|
|
break;
|
|
|
|
case 1: // DR1
|
|
|
|
BX_CPU_THIS_PTR dr1 = val_64;
|
|
|
|
break;
|
|
|
|
case 2: // DR2
|
|
|
|
BX_CPU_THIS_PTR dr2 = val_64;
|
|
|
|
break;
|
|
|
|
case 3: // DR3
|
|
|
|
BX_CPU_THIS_PTR dr3 = val_64;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 4: // DR4
|
|
|
|
case 6: // DR6
|
|
|
|
// DR4 aliased to DR6 by default. With Debug Extensions on,
|
|
|
|
// access to DR4 causes #UD
|
2002-09-18 02:50:53 +04:00
|
|
|
if ( (i->nnn() == 4) && (BX_CPU_THIS_PTR cr4.get_DE()) ) {
|
2002-09-15 03:17:55 +04:00
|
|
|
// Debug extensions on
|
|
|
|
BX_INFO(("MOV_DqRq: access to DR4 causes #UD"));
|
|
|
|
UndefinedOpcode(i);
|
2003-11-14 00:17:31 +03:00
|
|
|
}
|
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
|
|
|
|
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.
|
|
|
|
|
|
|
|
// DR5 aliased to DR7 by default. With Debug Extensions on,
|
|
|
|
// access to DR5 causes #UD
|
2002-09-18 02:50:53 +04:00
|
|
|
if ( (i->nnn() == 5) && (BX_CPU_THIS_PTR cr4.get_DE()) ) {
|
2002-09-15 03:17:55 +04:00
|
|
|
// Debug extensions (CR4.DE) on
|
|
|
|
BX_INFO(("MOV_DqRq: access to DR5 causes #UD"));
|
|
|
|
UndefinedOpcode(i);
|
2003-11-14 00:17:31 +03:00
|
|
|
}
|
|
|
|
|
2002-09-15 03:17:55 +04:00
|
|
|
// Some sanity checks...
|
|
|
|
if ( val_64 & 0x00002000 ) {
|
|
|
|
BX_PANIC(("MOV_DqRq: GD bit not supported yet"));
|
|
|
|
// Note: processor clears GD upon entering debug exception
|
|
|
|
// handler, to allow access to the debug registers
|
2005-02-03 21:25:10 +03:00
|
|
|
}
|
2002-09-15 03:17:55 +04:00
|
|
|
if ( (((val_64>>16) & 3)==2) ||
|
|
|
|
(((val_64>>20) & 3)==2) ||
|
|
|
|
(((val_64>>24) & 3)==2) ||
|
2004-11-05 01:41:24 +03:00
|
|
|
(((val_64>>28) & 3)==2) )
|
|
|
|
{
|
2002-09-15 03:17:55 +04:00
|
|
|
// IO breakpoints (10b) are not yet supported.
|
2004-11-05 01:41:24 +03:00
|
|
|
BX_PANIC(("MOV_DqRq: write of %08x:%08x contains IO breakpoint",
|
|
|
|
(Bit32u)(val_64 >> 32), (Bit32u)(val_64 & 0xFFFFFFFF)));
|
2003-11-14 00:17:31 +03:00
|
|
|
}
|
2002-09-15 03:17:55 +04:00
|
|
|
if ( (((val_64>>18) & 3)==2) ||
|
|
|
|
(((val_64>>22) & 3)==2) ||
|
|
|
|
(((val_64>>26) & 3)==2) ||
|
2004-11-05 01:41:24 +03:00
|
|
|
(((val_64>>30) & 3)==2) )
|
|
|
|
{
|
2002-09-15 03:17:55 +04:00
|
|
|
// LEN0..3 contains undefined length specifier (10b)
|
2004-11-05 01:41:24 +03:00
|
|
|
BX_PANIC(("MOV_DqRq: write of %08x:%08x contains undefined LENx",
|
|
|
|
(Bit32u)(val_64 >> 32), (Bit32u)(val_64 & 0xFFFFFFFF)));
|
2003-11-14 00:17:31 +03:00
|
|
|
}
|
2002-09-15 03:17:55 +04: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)) ||
|
2004-11-05 01:41:24 +03:00
|
|
|
((((val_64>>28) & 3)==0) && (((val_64>>30) & 3)!=0)) )
|
|
|
|
{
|
2002-09-15 03:17:55 +04:00
|
|
|
// Instruction breakpoint with LENx not 00b (1-byte length)
|
2004-11-05 01:41:24 +03:00
|
|
|
BX_PANIC(("MOV_DqRq: write of %08x:%08x , R/W=00b LEN!=00b",
|
|
|
|
(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:
|
|
|
|
BX_PANIC(("MOV_DqRq: control register index out of range"));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2003-11-14 00:17:31 +03:00
|
|
|
void BX_CPU_C::MOV_RqDq(bxInstruction_c *i)
|
2002-09-15 03:17:55 +04:00
|
|
|
{
|
|
|
|
Bit64u val_64;
|
|
|
|
|
|
|
|
if (v8086_mode()) {
|
2003-11-14 00:57:13 +03:00
|
|
|
BX_INFO(("MOV_RqDq: v8086 mode causes #GP(0)"));
|
2002-09-15 03:17:55 +04:00
|
|
|
exception(BX_GP_EXCEPTION, 0, 0);
|
2005-02-03 21:25:10 +03:00
|
|
|
}
|
2002-09-15 03:17:55 +04:00
|
|
|
|
2003-11-14 00:17:31 +03:00
|
|
|
/* This instruction is always treated as a register-to-register,
|
|
|
|
* regardless of the encoding of the MOD field in the MODRM byte.
|
|
|
|
*/
|
|
|
|
if (!i->modC0())
|
2003-11-14 00:57:13 +03:00
|
|
|
BX_INFO(("MOV_RqDq(): rm field not a register!"));
|
2002-09-15 03:17:55 +04:00
|
|
|
|
2003-11-14 00:57:13 +03:00
|
|
|
/* #GP(0) if CPL is not 0 */
|
2002-09-15 03:17:55 +04:00
|
|
|
if (protected_mode() && (CPL!=0)) {
|
2003-11-14 00:57:13 +03:00
|
|
|
BX_INFO(("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
|
|
|
|
|
|
|
if (bx_dbg.dreg)
|
2002-09-18 02:50:53 +04:00
|
|
|
BX_INFO(("MOV_RqDq: DR%u not implemented yet", i->nnn()));
|
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
|
|
|
|
val_64 = BX_CPU_THIS_PTR dr0;
|
|
|
|
break;
|
|
|
|
case 1: // DR1
|
|
|
|
val_64 = BX_CPU_THIS_PTR dr1;
|
|
|
|
break;
|
|
|
|
case 2: // DR2
|
|
|
|
val_64 = BX_CPU_THIS_PTR dr2;
|
|
|
|
break;
|
|
|
|
case 3: // DR3
|
|
|
|
val_64 = BX_CPU_THIS_PTR dr3;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 4: // DR4
|
|
|
|
case 6: // DR6
|
|
|
|
// DR4 aliased to DR6 by default. With Debug Extensions on,
|
|
|
|
// access to DR4 causes #UD
|
2002-09-18 02:50:53 +04:00
|
|
|
if ( (i->nnn() == 4) && (BX_CPU_THIS_PTR cr4.get_DE()) ) {
|
2002-09-15 03:17:55 +04:00
|
|
|
// Debug extensions on
|
|
|
|
BX_INFO(("MOV_RqDq: access to DR4 causes #UD"));
|
|
|
|
UndefinedOpcode(i);
|
2003-11-14 00:17:31 +03:00
|
|
|
}
|
2002-09-15 03:17:55 +04:00
|
|
|
val_64 = BX_CPU_THIS_PTR dr6;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 5: // DR5
|
|
|
|
case 7: // DR7
|
|
|
|
// DR5 aliased to DR7 by default. With Debug Extensions on,
|
|
|
|
// access to DR5 causes #UD
|
2002-09-18 02:50:53 +04:00
|
|
|
if ( (i->nnn() == 5) && (BX_CPU_THIS_PTR cr4.get_DE()) ) {
|
2002-09-15 03:17:55 +04:00
|
|
|
// Debug extensions on
|
|
|
|
BX_INFO(("MOV_RqDq: access to DR5 causes #UD"));
|
|
|
|
UndefinedOpcode(i);
|
2003-11-14 00:17:31 +03:00
|
|
|
}
|
2002-09-15 03:17:55 +04:00
|
|
|
val_64 = BX_CPU_THIS_PTR dr7;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
BX_PANIC(("MOV_RqDq: control register index out of range"));
|
|
|
|
val_64 = 0;
|
2005-02-03 21:25:10 +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
|
|
|
|
|
2003-11-14 00:17:31 +03:00
|
|
|
void BX_CPU_C::MOV_CdRd(bxInstruction_c *i)
|
2001-04-10 05:04:59 +04:00
|
|
|
{
|
|
|
|
// mov general register data to control register
|
|
|
|
Bit32u val_32;
|
|
|
|
|
2003-11-14 00:17:31 +03:00
|
|
|
if (v8086_mode()) {
|
2003-11-14 00:57:13 +03:00
|
|
|
BX_INFO(("MOV_CdRd: v8086 mode causes #GP(0)"));
|
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,
|
|
|
|
* regardless of the encoding of the MOD field in the MODRM byte.
|
|
|
|
*/
|
|
|
|
if (!i->modC0())
|
2003-11-14 00:57:13 +03:00
|
|
|
BX_INFO(("MOV_CdRd(): rm field not a register!"));
|
2001-04-10 05:04:59 +04:00
|
|
|
|
|
|
|
invalidate_prefetch_q();
|
|
|
|
|
2003-11-14 00:57:13 +03:00
|
|
|
/* #GP(0) if CPL is not 0 */
|
2003-11-14 00:17:31 +03:00
|
|
|
if (protected_mode() && CPL!=0) {
|
2003-11-14 00:57:13 +03:00
|
|
|
BX_INFO(("MOV_CdRd: #GP(0) if CPL is not 0"));
|
2002-04-11 05:19:24 +04:00
|
|
|
exception(BX_GP_EXCEPTION, 0, 0);
|
2004-06-18 18:11:11 +04:00
|
|
|
}
|
2001-04-10 05:04:59 +04:00
|
|
|
|
2002-09-18 02:50:53 +04:00
|
|
|
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)
|
2002-09-15 03:17:55 +04:00
|
|
|
// BX_INFO(("MOV_CdRd:CR0: R32 = %08x @CS:EIP %04x:%04x ",
|
2001-04-10 05:04:59 +04:00
|
|
|
// (unsigned) val_32,
|
|
|
|
// (unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value,
|
2002-09-13 04:15:23 +04:00
|
|
|
// (unsigned) EIP));
|
2001-04-10 05:04:59 +04:00
|
|
|
SetCR0(val_32);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 1: /* CR1 */
|
2001-05-30 22:56:02 +04:00
|
|
|
BX_PANIC(("MOV_CdRd: CR1 not implemented yet"));
|
2001-04-10 05:04:59 +04:00
|
|
|
break;
|
|
|
|
case 2: /* CR2 */
|
2001-08-25 01:02:37 +04:00
|
|
|
BX_DEBUG(("MOV_CdRd: CR2 not implemented yet"));
|
2002-10-04 21:04:33 +04:00
|
|
|
BX_DEBUG(("MOV_CdRd: CR2 = reg"));
|
2001-04-10 05:04:59 +04:00
|
|
|
BX_CPU_THIS_PTR cr2 = val_32;
|
|
|
|
break;
|
|
|
|
case 3: // CR3
|
|
|
|
if (bx_dbg.creg)
|
2001-05-30 22:56:02 +04:00
|
|
|
BX_INFO(("MOV_CdRd:CR3 = %08x", (unsigned) val_32));
|
2001-04-10 05:04:59 +04:00
|
|
|
// Reserved bits take on value of MOV instruction
|
|
|
|
CR3_change(val_32);
|
2003-02-13 18:04:11 +03:00
|
|
|
BX_INSTR_TLB_CNTRL(BX_CPU_ID, BX_INSTR_MOV_CR3, val_32);
|
2002-09-07 09:21:28 +04:00
|
|
|
// Reload of CR3 always serializes.
|
|
|
|
// invalidate_prefetch_q(); // Already done.
|
2001-04-10 05:04:59 +04:00
|
|
|
break;
|
|
|
|
case 4: // CR4
|
|
|
|
#if BX_CPU_LEVEL == 3
|
2003-11-14 00:17:31 +03:00
|
|
|
BX_PANIC(("MOV_CdRd: write to CR4 of 0x%08x on 386", val_32));
|
2001-04-10 05:04:59 +04:00
|
|
|
UndefinedOpcode(i);
|
|
|
|
#else
|
|
|
|
// Protected mode: #GP(0) if attempt to write a 1 to
|
|
|
|
// any reserved bit of CR4
|
2002-09-15 03:17:55 +04:00
|
|
|
SetCR4(val_32);
|
2001-04-10 05:04:59 +04:00
|
|
|
#endif
|
|
|
|
break;
|
|
|
|
default:
|
2001-05-30 22:56:02 +04:00
|
|
|
BX_PANIC(("MOV_CdRd: control register index out of range"));
|
2001-04-10 05:04:59 +04:00
|
|
|
break;
|
2005-02-03 21:25:10 +03:00
|
|
|
}
|
2001-04-10 05:04:59 +04:00
|
|
|
}
|
|
|
|
|
2003-11-14 00:17:31 +03:00
|
|
|
void BX_CPU_C::MOV_RdCd(bxInstruction_c *i)
|
2001-04-10 05:04:59 +04:00
|
|
|
{
|
|
|
|
// mov control register data to register
|
|
|
|
Bit32u val_32;
|
|
|
|
|
2005-02-03 21:25:10 +03:00
|
|
|
if (v8086_mode()) {
|
2003-11-14 00:57:13 +03:00
|
|
|
BX_INFO(("MOV_RdCd: v8086 mode causes #GP(0)"));
|
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,
|
|
|
|
* regardless of the encoding of the MOD field in the MODRM byte.
|
|
|
|
*/
|
|
|
|
if (!i->modC0())
|
2003-11-14 00:57:13 +03:00
|
|
|
BX_INFO(("MOV_RdCd(): rm field not a register!"));
|
2001-04-10 05:04:59 +04:00
|
|
|
|
2003-11-14 00:57:13 +03:00
|
|
|
/* #GP(0) if CPL is not 0 */
|
2003-11-14 00:17:31 +03:00
|
|
|
if (protected_mode() && CPL!=0) {
|
2003-11-14 00:57:13 +03:00
|
|
|
BX_INFO(("MOV_RdCd: #GP(0) if CPL is not 0"));
|
2002-04-11 05:19:24 +04:00
|
|
|
exception(BX_GP_EXCEPTION, 0, 0);
|
2003-11-14 00:57:13 +03:00
|
|
|
}
|
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)
|
|
|
|
val_32 = BX_CPU_THIS_PTR cr0.val32;
|
|
|
|
#if 0
|
2002-09-15 03:17:55 +04:00
|
|
|
BX_INFO(("MOV_RdCd:CR0: R32 = %08x @CS:EIP %04x:%04x",
|
2001-04-10 05:04:59 +04:00
|
|
|
(unsigned) val_32,
|
|
|
|
(unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value,
|
2002-09-13 04:15:23 +04:00
|
|
|
(unsigned) EIP));
|
2001-04-10 05:04:59 +04:00
|
|
|
#endif
|
|
|
|
break;
|
|
|
|
case 1: /* CR1 */
|
2001-05-30 22:56:02 +04:00
|
|
|
BX_PANIC(("MOV_RdCd: CR1 not implemented yet"));
|
2001-04-10 05:04:59 +04:00
|
|
|
val_32 = 0;
|
|
|
|
break;
|
|
|
|
case 2: /* CR2 */
|
|
|
|
if (bx_dbg.creg)
|
2001-05-30 22:56:02 +04:00
|
|
|
BX_INFO(("MOV_RdCd: CR2"));
|
2001-04-10 05:04:59 +04:00
|
|
|
val_32 = BX_CPU_THIS_PTR cr2;
|
|
|
|
break;
|
|
|
|
case 3: // CR3
|
|
|
|
if (bx_dbg.creg)
|
2001-05-30 22:56:02 +04:00
|
|
|
BX_INFO(("MOV_RdCd: reading CR3"));
|
2001-04-10 05:04:59 +04:00
|
|
|
val_32 = BX_CPU_THIS_PTR cr3;
|
|
|
|
break;
|
|
|
|
case 4: // CR4
|
|
|
|
#if BX_CPU_LEVEL == 3
|
|
|
|
val_32 = 0;
|
2001-05-30 22:56:02 +04:00
|
|
|
BX_INFO(("MOV_RdCd: read of CR4 causes #UD"));
|
2001-04-10 05:04:59 +04:00
|
|
|
UndefinedOpcode(i);
|
|
|
|
#else
|
2005-10-24 01:11:32 +04:00
|
|
|
BX_DEBUG(("MOV_RdCd: read of CR4"));
|
2002-09-14 23:21:41 +04:00
|
|
|
val_32 = BX_CPU_THIS_PTR cr4.getRegister();
|
2001-04-10 05:04:59 +04:00
|
|
|
#endif
|
|
|
|
break;
|
|
|
|
default:
|
2001-05-30 22:56:02 +04:00
|
|
|
BX_PANIC(("MOV_RdCd: control register index out of range"));
|
2001-04-10 05:04:59 +04:00
|
|
|
val_32 = 0;
|
2004-10-14 00:58:16 +04: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
|
2003-11-14 00:17:31 +03:00
|
|
|
void BX_CPU_C::MOV_CqRq(bxInstruction_c *i)
|
2002-09-15 03:17:55 +04:00
|
|
|
{
|
|
|
|
// mov general register data to control register
|
|
|
|
Bit64u val_64;
|
|
|
|
|
2004-10-14 00:58:16 +04:00
|
|
|
if (v8086_mode())
|
|
|
|
{
|
2003-11-14 00:57:13 +03:00
|
|
|
BX_INFO(("MOV_CqRq: v8086 mode causes #GP(0)"));
|
2003-11-14 00:17:31 +03:00
|
|
|
exception(BX_GP_EXCEPTION, 0, 0);
|
|
|
|
}
|
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:17:31 +03:00
|
|
|
/* This instruction is always treated as a register-to-register,
|
|
|
|
* regardless of the encoding of the MOD field in the MODRM byte.
|
|
|
|
*/
|
|
|
|
if (!i->modC0())
|
2003-11-14 00:57:13 +03:00
|
|
|
BX_INFO(("MOV_CqRq(): rm field not a register!"));
|
2002-09-15 03:17:55 +04:00
|
|
|
|
|
|
|
invalidate_prefetch_q();
|
|
|
|
|
2003-11-14 00:57:13 +03:00
|
|
|
/* #GP(0) if CPL is not 0 */
|
2002-09-15 03:17:55 +04:00
|
|
|
if (protected_mode() && CPL!=0) {
|
2003-11-14 00:57:13 +03:00
|
|
|
BX_INFO(("MOV_CqRq: #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
|
|
|
|
2002-09-18 02:50:53 +04:00
|
|
|
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)
|
|
|
|
// BX_INFO(("MOV_CqRq:CR0: R64 = %08x @CS:EIP %04x:%04x ",
|
|
|
|
// (unsigned) val_64,
|
|
|
|
// (unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value,
|
|
|
|
// (unsigned) EIP));
|
|
|
|
SetCR0(val_64);
|
|
|
|
break;
|
|
|
|
case 1: /* CR1 */
|
|
|
|
BX_PANIC(("MOV_CqRq: CR1 not implemented yet"));
|
|
|
|
break;
|
|
|
|
case 2: /* CR2 */
|
|
|
|
BX_DEBUG(("MOV_CqRq: CR2 not implemented yet"));
|
|
|
|
BX_CPU_THIS_PTR cr2 = val_64;
|
|
|
|
break;
|
|
|
|
case 3: // CR3
|
|
|
|
if (bx_dbg.creg)
|
|
|
|
BX_INFO(("MOV_CqRq:CR3 = %08x", (unsigned) val_64));
|
|
|
|
// Reserved bits take on value of MOV instruction
|
|
|
|
CR3_change(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
|
|
|
|
// Protected mode: #GP(0) if attempt to write a 1 to
|
|
|
|
// any reserved bit of CR4
|
2004-11-05 01:41:24 +03:00
|
|
|
BX_INFO(("MOV_CqRq: write to CR4 of %08x:%08x",
|
|
|
|
(Bit32u)(val_64 >> 32), (Bit32u)(val_64 & 0xFFFFFFFF)));
|
2002-09-15 03:17:55 +04:00
|
|
|
SetCR4(val_64);
|
|
|
|
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]
|
|
|
|
BX_CPU_THIS_PTR local_apic.set_tpr((val_64 & 0xF) << 0x4);
|
|
|
|
break;
|
|
|
|
#endif
|
2002-09-15 03:17:55 +04:00
|
|
|
default:
|
|
|
|
BX_PANIC(("MOV_CqRq: control register index out of range"));
|
|
|
|
break;
|
2005-02-03 21:25:10 +03:00
|
|
|
}
|
2002-09-15 03:17:55 +04:00
|
|
|
}
|
|
|
|
|
2003-11-14 00:17:31 +03:00
|
|
|
void BX_CPU_C::MOV_RqCq(bxInstruction_c *i)
|
2002-09-15 03:17:55 +04:00
|
|
|
{
|
|
|
|
// mov control register data to register
|
|
|
|
Bit64u val_64;
|
|
|
|
|
2003-11-14 00:17:31 +03:00
|
|
|
if (v8086_mode()) {
|
2003-11-14 00:57:13 +03:00
|
|
|
BX_INFO(("MOV_RqCq: v8086 mode causes #GP(0)"));
|
2003-11-14 00:17:31 +03:00
|
|
|
exception(BX_GP_EXCEPTION, 0, 0);
|
|
|
|
}
|
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:17:31 +03:00
|
|
|
/* This instruction is always treated as a register-to-register,
|
|
|
|
* regardless of the encoding of the MOD field in the MODRM byte.
|
|
|
|
*/
|
|
|
|
if (!i->modC0())
|
2003-11-14 00:57:13 +03:00
|
|
|
BX_INFO(("MOV_RqCq(): rm field not a register!"));
|
2002-09-15 03:17:55 +04:00
|
|
|
|
2003-11-14 00:57:13 +03:00
|
|
|
/* #GP(0) if CPL is not 0 */
|
2002-09-15 03:17:55 +04:00
|
|
|
if (protected_mode() && CPL!=0) {
|
2003-11-14 00:57:13 +03:00
|
|
|
BX_INFO(("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
|
|
|
|
2002-09-18 02:50:53 +04:00
|
|
|
switch (i->nnn()) {
|
2002-09-15 03:17:55 +04:00
|
|
|
case 0: // CR0 (MSW)
|
|
|
|
val_64 = BX_CPU_THIS_PTR cr0.val32;
|
|
|
|
#if 0
|
|
|
|
BX_INFO(("MOV_RqCq:CR0: R64 = %08x @CS:EIP %04x:%04x",
|
|
|
|
(unsigned) val_64,
|
|
|
|
(unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value,
|
|
|
|
(unsigned) EIP));
|
|
|
|
#endif
|
|
|
|
break;
|
|
|
|
case 1: /* CR1 */
|
|
|
|
BX_PANIC(("MOV_RqCq: CR1 not implemented yet"));
|
|
|
|
val_64 = 0;
|
|
|
|
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"));
|
2002-09-15 03:17:55 +04:00
|
|
|
val_64 = BX_CPU_THIS_PTR cr4.getRegister();
|
|
|
|
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:
|
|
|
|
BX_PANIC(("MOV_RqCq: control register index out of range"));
|
|
|
|
val_64 = 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
|
|
|
|
void BX_CPU_C::LMSW_Ew(bxInstruction_c *i)
|
|
|
|
{
|
|
|
|
Bit16u msw;
|
|
|
|
Bit32u cr0;
|
|
|
|
|
|
|
|
invalidate_prefetch_q();
|
|
|
|
|
|
|
|
if (protected_mode() || v8086_mode()) {
|
|
|
|
if (CPL != 0) {
|
|
|
|
BX_INFO(("LMSW: CPL != 0, CPL=%u", (unsigned) CPL));
|
|
|
|
exception(BX_GP_EXCEPTION, 0, 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (i->modC0()) {
|
|
|
|
msw = BX_READ_16BIT_REG(i->rm());
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
read_virtual_word(i->seg(), RMAddr(i), &msw);
|
|
|
|
}
|
|
|
|
|
|
|
|
// LMSW does not affect PG,CD,NW,AM,WP,NE,ET bits, and cannot clear PE
|
|
|
|
|
|
|
|
// LMSW cannot clear PE
|
|
|
|
if (BX_CPU_THIS_PTR cr0.pe)
|
|
|
|
msw |= 0x0001; // adjust PE bit to current value of 1
|
|
|
|
|
|
|
|
msw &= 0x000f; // LMSW only affects last 4 flags
|
|
|
|
cr0 = (BX_CPU_THIS_PTR cr0.val32 & 0xfffffff0) | msw;
|
|
|
|
SetCR0(cr0);
|
|
|
|
}
|
|
|
|
|
|
|
|
void BX_CPU_C::SMSW_Ew(bxInstruction_c *i)
|
|
|
|
{
|
|
|
|
Bit16u msw;
|
|
|
|
|
|
|
|
#if BX_CPU_LEVEL == 2
|
|
|
|
msw = 0xfff0; /* 80286 init value */
|
|
|
|
msw |= (BX_CPU_THIS_PTR cr0.ts << 3) |
|
|
|
|
(BX_CPU_THIS_PTR cr0.em << 2) |
|
|
|
|
(BX_CPU_THIS_PTR cr0.mp << 1) |
|
|
|
|
(BX_CPU_THIS_PTR cr0.pe);
|
|
|
|
#else /* 386+ */
|
|
|
|
msw = BX_CPU_THIS_PTR cr0.val32 & 0xffff;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (i->modC0()) {
|
|
|
|
if (i->os32L()) {
|
|
|
|
BX_WRITE_32BIT_REGZ(i->rm(), msw); // zeros out high 16bits
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
BX_WRITE_16BIT_REG(i->rm(), msw);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
write_virtual_word(i->seg(), RMAddr(i), &msw);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2003-11-14 00:17:31 +03:00
|
|
|
void 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"));
|
2001-04-10 05:04:59 +04:00
|
|
|
UndefinedOpcode(i);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2003-11-14 00:17:31 +03:00
|
|
|
void 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"));
|
2001-04-10 05:04:59 +04:00
|
|
|
UndefinedOpcode(i);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2004-05-11 01:05:51 +04:00
|
|
|
#if BX_CPU_LEVEL == 2
|
2003-11-14 00:17:31 +03:00
|
|
|
void 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 di, si, bp, sp, bx, dx, cx, ax;
|
|
|
|
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
|
|
|
|
2004-05-11 01:05:51 +04:00
|
|
|
if (BX_CPU_THIS_PTR cr0.pe)
|
|
|
|
{
|
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 */
|
2004-11-15 00:25:42 +03:00
|
|
|
BX_CPU_THIS_PTR mem->readPhysicalPage(BX_CPU_THIS, 0x806, 2, &msw);
|
2001-04-10 05:04:59 +04:00
|
|
|
BX_CPU_THIS_PTR cr0.pe = (msw & 0x01); msw >>= 1;
|
|
|
|
BX_CPU_THIS_PTR cr0.mp = (msw & 0x01); msw >>= 1;
|
|
|
|
BX_CPU_THIS_PTR cr0.em = (msw & 0x01); msw >>= 1;
|
|
|
|
BX_CPU_THIS_PTR cr0.ts = (msw & 0x01);
|
|
|
|
|
2001-05-30 22:56:02 +04:00
|
|
|
//BX_INFO(("LOADALL: pe=%u, mp=%u, em=%u, ts=%u",
|
2001-04-10 05:04:59 +04:00
|
|
|
// (unsigned) BX_CPU_THIS_PTR cr0.pe, (unsigned) BX_CPU_THIS_PTR cr0.mp,
|
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
|
|
|
// (unsigned) BX_CPU_THIS_PTR cr0.em, (unsigned) BX_CPU_THIS_PTR cr0.ts));
|
2001-04-10 05:04:59 +04:00
|
|
|
|
|
|
|
if (BX_CPU_THIS_PTR cr0.pe || BX_CPU_THIS_PTR cr0.mp || BX_CPU_THIS_PTR cr0.em || BX_CPU_THIS_PTR cr0.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 */
|
2004-11-15 00:25:42 +03:00
|
|
|
BX_CPU_THIS_PTR mem->readPhysicalPage(BX_CPU_THIS, 0x816, 2, &tr);
|
2001-04-10 05:04:59 +04:00
|
|
|
BX_CPU_THIS_PTR tr.selector.value = tr;
|
|
|
|
BX_CPU_THIS_PTR tr.selector.rpl = (tr & 0x03); tr >>= 2;
|
|
|
|
BX_CPU_THIS_PTR tr.selector.ti = (tr & 0x01); tr >>= 1;
|
|
|
|
BX_CPU_THIS_PTR tr.selector.index = tr;
|
2004-11-15 00:25:42 +03:00
|
|
|
BX_CPU_THIS_PTR mem->readPhysicalPage(BX_CPU_THIS, 0x860, 2, &base_15_0);
|
|
|
|
BX_CPU_THIS_PTR mem->readPhysicalPage(BX_CPU_THIS, 0x862, 1, &base_23_16);
|
|
|
|
BX_CPU_THIS_PTR mem->readPhysicalPage(BX_CPU_THIS, 0x863, 1, &access);
|
|
|
|
BX_CPU_THIS_PTR mem->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);
|
2001-04-10 05:04:59 +04:00
|
|
|
BX_CPU_THIS_PTR tr.cache.u.tss286.base = (base_23_16 << 16) | base_15_0;
|
|
|
|
BX_CPU_THIS_PTR tr.cache.u.tss286.limit = limit;
|
|
|
|
|
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
|
|
|
}
|
|
|
|
if (BX_CPU_THIS_PTR tr.cache.valid == 0) {
|
|
|
|
}
|
|
|
|
if (BX_CPU_THIS_PTR tr.cache.u.tss286.limit < 43) {
|
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.type != 1) {
|
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.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)
|
|
|
|
{
|
2001-04-10 05:04:59 +04:00
|
|
|
BX_CPU_THIS_PTR tr.cache.u.tss286.base = 0;
|
|
|
|
BX_CPU_THIS_PTR tr.cache.u.tss286.limit = 0;
|
|
|
|
BX_CPU_THIS_PTR tr.cache.p = 0;
|
|
|
|
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;
|
2005-02-03 21:25:10 +03:00
|
|
|
}
|
2001-04-10 05:04:59 +04:00
|
|
|
|
|
|
|
/* FLAGS */
|
2004-11-15 00:25:42 +03:00
|
|
|
BX_CPU_THIS_PTR mem->readPhysicalPage(BX_CPU_THIS, 0x818, 2, &flags);
|
2001-04-10 05:04:59 +04:00
|
|
|
write_flags(flags, 1, 1);
|
|
|
|
|
|
|
|
/* IP */
|
2004-11-15 00:25:42 +03:00
|
|
|
BX_CPU_THIS_PTR mem->readPhysicalPage(BX_CPU_THIS, 0x81a, 2, &ip);
|
2001-04-10 05:04:59 +04:00
|
|
|
IP = ip;
|
|
|
|
|
|
|
|
/* LDTR */
|
2004-11-15 00:25:42 +03:00
|
|
|
BX_CPU_THIS_PTR mem->readPhysicalPage(BX_CPU_THIS, 0x81c, 2, &ldtr);
|
2001-04-10 05:04:59 +04:00
|
|
|
BX_CPU_THIS_PTR ldtr.selector.value = ldtr;
|
|
|
|
BX_CPU_THIS_PTR ldtr.selector.rpl = (ldtr & 0x03); ldtr >>= 2;
|
|
|
|
BX_CPU_THIS_PTR ldtr.selector.ti = (ldtr & 0x01); ldtr >>= 1;
|
|
|
|
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;
|
|
|
|
BX_CPU_THIS_PTR ldtr.cache.u.ldt.base = 0;
|
|
|
|
BX_CPU_THIS_PTR ldtr.cache.u.ldt.limit = 0;
|
|
|
|
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 {
|
2004-11-15 00:25:42 +03:00
|
|
|
BX_CPU_THIS_PTR mem->readPhysicalPage(BX_CPU_THIS, 0x854, 2, &base_15_0);
|
|
|
|
BX_CPU_THIS_PTR mem->readPhysicalPage(BX_CPU_THIS, 0x856, 1, &base_23_16);
|
|
|
|
BX_CPU_THIS_PTR mem->readPhysicalPage(BX_CPU_THIS, 0x857, 1, &access);
|
|
|
|
BX_CPU_THIS_PTR mem->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);
|
|
|
|
BX_CPU_THIS_PTR ldtr.cache.u.ldt.base = (base_23_16 << 16) | base_15_0;
|
|
|
|
BX_CPU_THIS_PTR ldtr.cache.u.ldt.limit = limit;
|
|
|
|
|
|
|
|
if (access == 0) {
|
2001-05-30 22:56:02 +04: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
|
|
|
}
|
|
|
|
if (BX_CPU_THIS_PTR ldtr.cache.type != 2) {
|
2001-05-30 22:56:02 +04:00
|
|
|
BX_PANIC(("loadall: LDTR.type(%u) != 2", (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 */
|
2004-11-15 00:25:42 +03:00
|
|
|
BX_CPU_THIS_PTR mem->readPhysicalPage(BX_CPU_THIS, 0x81e, 2, &ds_raw);
|
2001-04-10 05:04:59 +04:00
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS].selector.value = ds_raw;
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS].selector.rpl = (ds_raw & 0x03); ds_raw >>= 2;
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS].selector.ti = (ds_raw & 0x01); ds_raw >>= 1;
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS].selector.index = ds_raw;
|
2004-11-15 00:25:42 +03:00
|
|
|
BX_CPU_THIS_PTR mem->readPhysicalPage(BX_CPU_THIS, 0x848, 2, &base_15_0);
|
|
|
|
BX_CPU_THIS_PTR mem->readPhysicalPage(BX_CPU_THIS, 0x84a, 1, &base_23_16);
|
|
|
|
BX_CPU_THIS_PTR mem->readPhysicalPage(BX_CPU_THIS, 0x84b, 1, &access);
|
|
|
|
BX_CPU_THIS_PTR mem->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;
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS].cache.u.segment.a = (access & 0x01); access >>= 1;
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS].cache.u.segment.r_w = (access & 0x01); access >>= 1;
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS].cache.u.segment.c_ed = (access & 0x01); access >>= 1;
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS].cache.u.segment.executable = (access & 0x01); access >>= 1;
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS].cache.segment = (access & 0x01); access >>= 1;
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS].cache.dpl = (access & 0x03); access >>= 2;
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS].cache.valid =
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS].cache.p = (access & 0x01);
|
|
|
|
|
|
|
|
if ( (BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS].selector.value & 0xfffc) == 0 ) {
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS].cache.valid = 0;
|
2005-02-03 21:25:10 +03:00
|
|
|
}
|
2001-04-10 05:04:59 +04:00
|
|
|
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 */
|
2004-11-15 00:25:42 +03:00
|
|
|
BX_CPU_THIS_PTR mem->readPhysicalPage(BX_CPU_THIS, 0x820, 2, &ss_raw);
|
2001-04-10 05:04:59 +04:00
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].selector.value = ss_raw;
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].selector.rpl = (ss_raw & 0x03); ss_raw >>= 2;
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].selector.ti = (ss_raw & 0x01); ss_raw >>= 1;
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].selector.index = ss_raw;
|
2004-11-15 00:25:42 +03:00
|
|
|
BX_CPU_THIS_PTR mem->readPhysicalPage(BX_CPU_THIS, 0x842, 2, &base_15_0);
|
|
|
|
BX_CPU_THIS_PTR mem->readPhysicalPage(BX_CPU_THIS, 0x844, 1, &base_23_16);
|
|
|
|
BX_CPU_THIS_PTR mem->readPhysicalPage(BX_CPU_THIS, 0x845, 1, &access);
|
|
|
|
BX_CPU_THIS_PTR mem->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;
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.a = (access & 0x01); access >>= 1;
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.r_w = (access & 0x01); access >>= 1;
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.c_ed = (access & 0x01); access >>= 1;
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.executable = (access & 0x01); access >>= 1;
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.segment = (access & 0x01); access >>= 1;
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.dpl = (access & 0x03); access >>= 2;
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.p = (access & 0x01);
|
|
|
|
|
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
|
|
|
}
|
2001-04-10 05:04:59 +04:00
|
|
|
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
|
|
|
}
|
|
|
|
|
2001-04-10 05:04:59 +04:00
|
|
|
/* CS */
|
2004-11-15 00:25:42 +03:00
|
|
|
BX_CPU_THIS_PTR mem->readPhysicalPage(BX_CPU_THIS, 0x822, 2, &cs_raw);
|
2001-04-10 05:04:59 +04:00
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value = cs_raw;
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.rpl = (cs_raw & 0x03); cs_raw >>= 2;
|
|
|
|
|
2001-05-30 22:56:02 +04:00
|
|
|
//BX_INFO(("LOADALL: setting cs.selector.rpl to %u",
|
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
|
|
|
// (unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.rpl));
|
2001-04-10 05:04:59 +04:00
|
|
|
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.ti = (cs_raw & 0x01); cs_raw >>= 1;
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.index = cs_raw;
|
2004-11-15 00:25:42 +03:00
|
|
|
BX_CPU_THIS_PTR mem->readPhysicalPage(BX_CPU_THIS, 0x83c, 2, &base_15_0);
|
|
|
|
BX_CPU_THIS_PTR mem->readPhysicalPage(BX_CPU_THIS, 0x83e, 1, &base_23_16);
|
|
|
|
BX_CPU_THIS_PTR mem->readPhysicalPage(BX_CPU_THIS, 0x83f, 1, &access);
|
|
|
|
BX_CPU_THIS_PTR mem->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;
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.a = (access & 0x01); access >>= 1;
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.r_w = (access & 0x01); access >>= 1;
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.c_ed = (access & 0x01); access >>= 1;
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.executable = (access & 0x01); access >>= 1;
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.segment = (access & 0x01); access >>= 1;
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.dpl = (access & 0x03); access >>= 2;
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.p = (access & 0x01);
|
|
|
|
|
2005-02-03 21:25:10 +03:00
|
|
|
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
|
|
|
}
|
2001-04-10 05:04:59 +04:00
|
|
|
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
|
|
|
|
2006-01-16 22:22:28 +03:00
|
|
|
#if BX_SUPPORT_ICACHE
|
|
|
|
BX_CPU_THIS_PTR iCache.fetchModeMask = createFetchModeMask(BX_CPU_THIS);
|
|
|
|
#endif
|
|
|
|
|
2001-04-10 05:04:59 +04:00
|
|
|
/* ES */
|
2004-11-15 00:25:42 +03:00
|
|
|
BX_CPU_THIS_PTR mem->readPhysicalPage(BX_CPU_THIS, 0x824, 2, &es_raw);
|
2001-04-10 05:04:59 +04:00
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_ES].selector.value = es_raw;
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_ES].selector.rpl = (es_raw & 0x03); es_raw >>= 2;
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_ES].selector.ti = (es_raw & 0x01); es_raw >>= 1;
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_ES].selector.index = es_raw;
|
2004-11-15 00:25:42 +03:00
|
|
|
BX_CPU_THIS_PTR mem->readPhysicalPage(BX_CPU_THIS, 0x836, 2, &base_15_0);
|
|
|
|
BX_CPU_THIS_PTR mem->readPhysicalPage(BX_CPU_THIS, 0x838, 1, &base_23_16);
|
|
|
|
BX_CPU_THIS_PTR mem->readPhysicalPage(BX_CPU_THIS, 0x839, 1, &access);
|
|
|
|
BX_CPU_THIS_PTR mem->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;
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_ES].cache.u.segment.a = (access & 0x01); access >>= 1;
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_ES].cache.u.segment.r_w = (access & 0x01); access >>= 1;
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_ES].cache.u.segment.c_ed = (access & 0x01); access >>= 1;
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_ES].cache.u.segment.executable = (access & 0x01); access >>= 1;
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_ES].cache.segment = (access & 0x01); access >>= 1;
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_ES].cache.dpl = (access & 0x03); access >>= 2;
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_ES].cache.p = (access & 0x01);
|
|
|
|
|
|
|
|
#if 0
|
2001-05-30 22:56:02 +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 = %02x", (unsigned) BX_CPU_THIS_PTR ds.cache.dpl));
|
|
|
|
BX_INFO(("BX_CPU_THIS_PTR sregs[BX_SEG_REG_ES].dpl = %02x", (unsigned) BX_CPU_THIS_PTR es.cache.dpl));
|
|
|
|
BX_INFO(("LOADALL: setting cs.selector.rpl to %u",
|
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
|
|
|
(unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.rpl));
|
2001-05-30 22:56:02 +04:00
|
|
|
BX_INFO(("LOADALL: setting ss.selector.rpl to %u",
|
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
|
|
|
(unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].selector.rpl));
|
2001-05-30 22:56:02 +04:00
|
|
|
BX_INFO(("LOADALL: setting ds.selector.rpl to %u",
|
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
|
|
|
(unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS].selector.rpl));
|
2001-05-30 22:56:02 +04:00
|
|
|
BX_INFO(("LOADALL: setting es.selector.rpl to %u",
|
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
|
|
|
(unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_ES].selector.rpl));
|
2001-04-10 05:04:59 +04:00
|
|
|
#endif
|
|
|
|
|
2005-02-03 21:25:10 +03:00
|
|
|
if ((BX_CPU_THIS_PTR sregs[BX_SEG_REG_ES].selector.value & 0xfffc) == 0)
|
|
|
|
{
|
2001-04-10 05:04:59 +04:00
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_ES].cache.valid = 0;
|
2005-02-03 21:25:10 +03:00
|
|
|
}
|
2001-04-10 05:04:59 +04:00
|
|
|
if (BX_CPU_THIS_PTR sregs[BX_SEG_REG_ES].cache.valid==0 ||
|
2005-02-03 21:25:10 +03:00
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_ES].cache.segment==0)
|
|
|
|
{
|
2001-05-30 22:56:02 +04:00
|
|
|
BX_PANIC(("loadall: ES invalid"));
|
2005-02-03 21:25:10 +03:00
|
|
|
}
|
2001-04-10 05:04:59 +04:00
|
|
|
|
|
|
|
/* DI */
|
2004-11-15 00:25:42 +03:00
|
|
|
BX_CPU_THIS_PTR mem->readPhysicalPage(BX_CPU_THIS, 0x826, 2, &di);
|
2001-04-10 05:04:59 +04:00
|
|
|
DI = di;
|
|
|
|
|
|
|
|
/* SI */
|
2004-11-15 00:25:42 +03:00
|
|
|
BX_CPU_THIS_PTR mem->readPhysicalPage(BX_CPU_THIS, 0x828, 2, &si);
|
2001-04-10 05:04:59 +04:00
|
|
|
SI = si;
|
|
|
|
|
|
|
|
/* BP */
|
2004-11-15 00:25:42 +03:00
|
|
|
BX_CPU_THIS_PTR mem->readPhysicalPage(BX_CPU_THIS, 0x82a, 2, &bp);
|
2001-04-10 05:04:59 +04:00
|
|
|
BP = bp;
|
|
|
|
|
|
|
|
/* SP */
|
2004-11-15 00:25:42 +03:00
|
|
|
BX_CPU_THIS_PTR mem->readPhysicalPage(BX_CPU_THIS, 0x82c, 2, &sp);
|
2001-04-10 05:04:59 +04:00
|
|
|
SP = sp;
|
|
|
|
|
|
|
|
/* BX */
|
2004-11-15 00:25:42 +03:00
|
|
|
BX_CPU_THIS_PTR mem->readPhysicalPage(BX_CPU_THIS, 0x82e, 2, &bx);
|
2001-04-10 05:04:59 +04:00
|
|
|
BX = bx;
|
|
|
|
|
|
|
|
/* DX */
|
2004-11-15 00:25:42 +03:00
|
|
|
BX_CPU_THIS_PTR mem->readPhysicalPage(BX_CPU_THIS, 0x830, 2, &dx);
|
2001-04-10 05:04:59 +04:00
|
|
|
DX = dx;
|
|
|
|
|
|
|
|
/* CX */
|
2004-11-15 00:25:42 +03:00
|
|
|
BX_CPU_THIS_PTR mem->readPhysicalPage(BX_CPU_THIS, 0x832, 2, &cx);
|
2001-04-10 05:04:59 +04:00
|
|
|
CX = cx;
|
|
|
|
|
|
|
|
/* AX */
|
2004-11-15 00:25:42 +03:00
|
|
|
BX_CPU_THIS_PTR mem->readPhysicalPage(BX_CPU_THIS, 0x834, 2, &ax);
|
2001-04-10 05:04:59 +04:00
|
|
|
AX = ax;
|
|
|
|
|
|
|
|
/* GDTR */
|
2004-11-15 00:25:42 +03:00
|
|
|
BX_CPU_THIS_PTR mem->readPhysicalPage(BX_CPU_THIS, 0x84e, 2, &base_15_0);
|
|
|
|
BX_CPU_THIS_PTR mem->readPhysicalPage(BX_CPU_THIS, 0x850, 1, &base_23_16);
|
|
|
|
BX_CPU_THIS_PTR mem->readPhysicalPage(BX_CPU_THIS, 0x851, 1, &access);
|
|
|
|
BX_CPU_THIS_PTR mem->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;
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
if (access)
|
2001-05-30 22:56:02 +04:00
|
|
|
BX_INFO(("LOADALL: GDTR access bits not 0 (%02x).",
|
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
|
|
|
(unsigned) access));
|
2001-04-10 05:04:59 +04:00
|
|
|
#endif
|
|
|
|
|
|
|
|
/* IDTR */
|
2004-11-15 00:25:42 +03:00
|
|
|
BX_CPU_THIS_PTR mem->readPhysicalPage(BX_CPU_THIS, 0x85a, 2, &base_15_0);
|
|
|
|
BX_CPU_THIS_PTR mem->readPhysicalPage(BX_CPU_THIS, 0x85c, 1, &base_23_16);
|
|
|
|
BX_CPU_THIS_PTR mem->readPhysicalPage(BX_CPU_THIS, 0x85d, 1, &access);
|
|
|
|
BX_CPU_THIS_PTR mem->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
|
|
|
|
2003-11-14 00:17:31 +03:00
|
|
|
void 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) {
|
|
|
|
BX_INFO(("SetCR0: GP(0) when attempt to set CR0.PG with CR0.PE cleared !"));
|
|
|
|
exception(BX_GP_EXCEPTION, 0, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (nw && !cd) {
|
|
|
|
BX_INFO(("SetCR0: GP(0) when attempt to set CR0.NW with CR0.CD cleared !"));
|
|
|
|
exception(BX_GP_EXCEPTION, 0, 0);
|
|
|
|
}
|
|
|
|
|
2005-03-15 22:00:04 +03:00
|
|
|
if (pe && BX_CPU_THIS_PTR get_VM()) BX_PANIC(("EFLAGS.VM=1, enter_PM"));
|
|
|
|
|
2001-04-10 05:04:59 +04:00
|
|
|
// from either MOV_CdRd() or debug functions
|
|
|
|
// protection checks made already or forcing from debug
|
2002-09-07 09:21:28 +04:00
|
|
|
Bit32u oldCR0 = BX_CPU_THIS_PTR cr0.val32, newCR0;
|
2001-04-10 05:04:59 +04:00
|
|
|
|
2004-09-22 00:19:19 +04:00
|
|
|
bx_bool prev_pe = BX_CPU_THIS_PTR cr0.pe;
|
2005-02-03 21:43:23 +03:00
|
|
|
#if BX_SUPPORT_X86_64
|
2004-09-22 00:19:19 +04:00
|
|
|
bx_bool prev_pg = BX_CPU_THIS_PTR cr0.pg;
|
2005-02-03 21:43:23 +03:00
|
|
|
#endif
|
2001-04-10 05:04:59 +04:00
|
|
|
|
2004-09-22 00:19:19 +04:00
|
|
|
BX_CPU_THIS_PTR cr0.pe = pe;
|
2001-04-10 05:04:59 +04:00
|
|
|
BX_CPU_THIS_PTR cr0.mp = (val_32 >> 1) & 0x01;
|
|
|
|
BX_CPU_THIS_PTR cr0.em = (val_32 >> 2) & 0x01;
|
|
|
|
BX_CPU_THIS_PTR cr0.ts = (val_32 >> 3) & 0x01;
|
|
|
|
// cr0.et is hardwired to 1
|
|
|
|
#if BX_CPU_LEVEL >= 4
|
|
|
|
BX_CPU_THIS_PTR cr0.ne = (val_32 >> 5) & 0x01;
|
|
|
|
BX_CPU_THIS_PTR cr0.wp = (val_32 >> 16) & 0x01;
|
|
|
|
BX_CPU_THIS_PTR cr0.am = (val_32 >> 18) & 0x01;
|
2004-09-22 00:19:19 +04:00
|
|
|
BX_CPU_THIS_PTR cr0.nw = nw;
|
|
|
|
BX_CPU_THIS_PTR cr0.cd = cd;
|
2001-04-10 05:04:59 +04:00
|
|
|
#endif
|
2004-09-22 00:19:19 +04:00
|
|
|
BX_CPU_THIS_PTR cr0.pg = pg;
|
2001-04-10 05:04:59 +04:00
|
|
|
|
2005-11-22 00:10:59 +03:00
|
|
|
#if BX_CPU_LEVEL >= 4
|
|
|
|
if (BX_CPU_THIS_PTR cr0.am) {
|
2006-01-06 00:40:07 +03:00
|
|
|
BX_DEBUG(("WARNING: Alignment check enabled but not implemented !"));
|
2005-11-22 00:10:59 +03:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2001-04-10 05:04:59 +04:00
|
|
|
// handle reserved bits behaviour
|
|
|
|
#if BX_CPU_LEVEL == 3
|
2002-09-07 09:21:28 +04:00
|
|
|
newCR0 = val_32 | 0x7ffffff0;
|
2001-04-10 05:04:59 +04:00
|
|
|
#elif BX_CPU_LEVEL == 4
|
2002-09-07 09:21:28 +04:00
|
|
|
newCR0 = (val_32 | 0x00000010) & 0xe005003f;
|
2001-04-10 05:04:59 +04:00
|
|
|
#elif BX_CPU_LEVEL == 5
|
2002-09-07 09:21:28 +04:00
|
|
|
newCR0 = val_32 | 0x00000010;
|
2001-04-10 05:04:59 +04:00
|
|
|
#elif BX_CPU_LEVEL == 6
|
2002-09-07 09:21:28 +04:00
|
|
|
newCR0 = (val_32 | 0x00000010) & 0xe005003f;
|
2001-04-10 05:04:59 +04:00
|
|
|
#else
|
|
|
|
#error "MOV_CdRd: implement reserved bits behaviour for this CPU_LEVEL"
|
|
|
|
#endif
|
2002-09-07 09:21:28 +04:00
|
|
|
BX_CPU_THIS_PTR cr0.val32 = newCR0;
|
2001-04-10 05:04:59 +04:00
|
|
|
|
|
|
|
if (prev_pe==0 && BX_CPU_THIS_PTR cr0.pe) {
|
2005-03-31 00:53:04 +04:00
|
|
|
BX_DEBUG(("Enter Protected Mode"));
|
2005-03-15 22:00:04 +03:00
|
|
|
BX_CPU_THIS_PTR cpu_mode = BX_MODE_IA32_PROTECTED;
|
2005-02-03 21:25:10 +03:00
|
|
|
}
|
2001-04-10 05:04:59 +04:00
|
|
|
else if (prev_pe==1 && BX_CPU_THIS_PTR cr0.pe==0) {
|
2005-03-31 00:53:04 +04:00
|
|
|
BX_DEBUG(("Enter Real Mode"));
|
2005-03-15 22:00:04 +03:00
|
|
|
BX_CPU_THIS_PTR cpu_mode = BX_MODE_IA32_REAL;
|
2005-02-03 21:25:10 +03:00
|
|
|
}
|
2001-04-10 05:04:59 +04:00
|
|
|
|
2002-09-15 03:17:55 +04:00
|
|
|
#if BX_SUPPORT_X86_64
|
|
|
|
if (prev_pg==0 && BX_CPU_THIS_PTR cr0.pg) {
|
|
|
|
if (BX_CPU_THIS_PTR msr.lme) {
|
|
|
|
if (!BX_CPU_THIS_PTR cr4.get_PAE()) {
|
2005-07-29 10:29:57 +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
|
|
|
}
|
2002-09-15 03:17:55 +04:00
|
|
|
BX_CPU_THIS_PTR msr.lma = 1;
|
2005-03-31 00:53:04 +04:00
|
|
|
BX_DEBUG(("Enter Compatibility Mode"));
|
2002-09-15 03:17:55 +04:00
|
|
|
BX_CPU_THIS_PTR cpu_mode = BX_MODE_LONG_COMPAT;
|
2005-10-13 20:22:21 +04:00
|
|
|
//#if BX_EXTERNAL_DEBUGGER
|
2003-01-14 10:40:21 +03:00
|
|
|
//trap_debugger(0);
|
2005-10-13 20:22:21 +04:00
|
|
|
//#endif
|
2002-09-15 03:17:55 +04:00
|
|
|
}
|
2005-02-03 21:25:10 +03:00
|
|
|
}
|
2002-09-15 03:17:55 +04:00
|
|
|
else if (prev_pg==1 && BX_CPU_THIS_PTR cr0.pg==0) {
|
|
|
|
if (BX_CPU_THIS_PTR msr.lma) {
|
|
|
|
if (BX_CPU_THIS_PTR dword.rip_upper != 0) {
|
|
|
|
BX_PANIC(("SetCR0: attempt to leave x86-64 LONG mode with RIP upper != 0 !!!"));
|
2005-02-03 21:25:10 +03:00
|
|
|
}
|
2002-09-15 03:17:55 +04:00
|
|
|
BX_CPU_THIS_PTR msr.lma = 0;
|
2005-03-15 22:00:04 +03:00
|
|
|
if (BX_CPU_THIS_PTR cr0.pe) {
|
2005-03-31 00:53:04 +04:00
|
|
|
BX_DEBUG(("Enter Protected Mode"));
|
2005-03-15 22:00:04 +03:00
|
|
|
BX_CPU_THIS_PTR cpu_mode = BX_MODE_IA32_PROTECTED;
|
|
|
|
}
|
|
|
|
else {
|
2005-03-31 00:53:04 +04:00
|
|
|
BX_DEBUG(("Enter Real Mode"));
|
2005-03-15 22:00:04 +03:00
|
|
|
BX_CPU_THIS_PTR cpu_mode = BX_MODE_IA32_REAL;
|
|
|
|
}
|
2005-10-13 20:22:21 +04:00
|
|
|
//#if BX_EXTERNAL_DEBUGGER
|
2003-01-14 10:40:21 +03:00
|
|
|
//trap_debugger(0);
|
2005-10-13 20:22:21 +04:00
|
|
|
//#endif
|
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
|
|
|
|
|
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.
|
|
|
|
pagingCR0Changed(oldCR0, newCR0);
|
2001-04-10 05:04:59 +04:00
|
|
|
}
|
|
|
|
|
2002-09-18 02:14:33 +04:00
|
|
|
#if BX_CPU_LEVEL >= 4
|
2003-11-14 00:17:31 +03:00
|
|
|
void BX_CPU_C::SetCR4(Bit32u val_32)
|
2002-09-15 03:17:55 +04:00
|
|
|
{
|
2005-02-03 21:25:10 +03:00
|
|
|
Bit32u oldCR4 = BX_CPU_THIS_PTR cr4.getRegister();
|
|
|
|
Bit32u allowMask = 0;
|
|
|
|
|
2002-09-23 18:45:44 +04:00
|
|
|
// CR4 bit definitions from AMD Hammer manual:
|
|
|
|
// [63-11] Reserved, Must be Zero
|
|
|
|
// [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 */
|
|
|
|
|
2005-01-24 00:13:49 +03:00
|
|
|
#if BX_SUPPORT_4MEG_PAGES
|
|
|
|
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
|
|
|
|
// NOTE: exception 18 never appears in Bochs
|
|
|
|
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
|
|
|
|
|
|
|
#if BX_SUPPORT_X86_64
|
|
|
|
// need to GPF #0 if LME=1 and PAE=0
|
2003-05-15 20:41:17 +04:00
|
|
|
if ((BX_CPU_THIS_PTR msr.lme)
|
2002-09-15 03:17:55 +04:00
|
|
|
&& (!(val_32 >> 5) & 1)
|
2003-05-15 20:41:17 +04:00
|
|
|
&& (BX_CPU_THIS_PTR cr4.get_PAE()))
|
|
|
|
{
|
2002-09-15 03:17:55 +04:00
|
|
|
exception(BX_GP_EXCEPTION, 0, 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.
|
|
|
|
if (val_32 & ~allowMask) {
|
2003-05-15 20:41:17 +04:00
|
|
|
BX_INFO(("#GP(0): SetCR4: Write of 0x%08x not supported (allowMask=0x%x)",
|
2002-09-15 03:17:55 +04:00
|
|
|
val_32, allowMask));
|
|
|
|
exception(BX_GP_EXCEPTION, 0, 0);
|
2003-05-15 20:41:17 +04:00
|
|
|
}
|
2002-09-15 03:17:55 +04:00
|
|
|
val_32 &= allowMask; // Screen out unsupported bits. (not needed, for good measure)
|
|
|
|
BX_CPU_THIS_PTR cr4.setRegister(val_32);
|
|
|
|
pagingCR4Changed(oldCR4, BX_CPU_THIS_PTR cr4.getRegister());
|
|
|
|
}
|
2002-09-18 02:14:33 +04:00
|
|
|
#endif
|
2002-09-15 03:17:55 +04:00
|
|
|
|
2003-11-14 00:17:31 +03:00
|
|
|
void 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)
|
|
|
|
exception (BX_GP_EXCEPTION, 0, 0);
|
|
|
|
#else //
|
|
|
|
if ((ECX & 0xffffffff) >= 2)
|
|
|
|
exception (BX_GP_EXCEPTION, 0, 0);
|
|
|
|
#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.
|
|
|
|
|
|
|
|
EAX = 0;
|
|
|
|
EDX = 0; // if P4 and ECX & 0x10000000, then always 0 (short read 32 bits)
|
|
|
|
|
|
|
|
BX_ERROR(("RDPMC: Performance Counters Support not reasonably implemented yet"));
|
|
|
|
} else {
|
|
|
|
// not allowed to use RDPMC!
|
|
|
|
exception (BX_GP_EXCEPTION, 0, 0);
|
|
|
|
}
|
2003-10-24 22:34:16 +04:00
|
|
|
#else
|
|
|
|
UndefinedOpcode(i);
|
|
|
|
#endif
|
2001-04-10 05:04:59 +04:00
|
|
|
}
|
|
|
|
|
2006-01-21 15:06:03 +03:00
|
|
|
#if BX_CPU_LEVEL >= 5
|
|
|
|
Bit64u BX_CPU_C::get_TSC ()
|
|
|
|
{
|
|
|
|
return bx_pc_system.time_ticks() - BX_CPU_THIS_PTR msr.tsc_last_reset;
|
|
|
|
}
|
|
|
|
|
|
|
|
void BX_CPU_C::set_TSC (Bit32u newval)
|
|
|
|
{
|
|
|
|
// compute the correct setting of tsc_last_reset so that a get_TSC()
|
|
|
|
// will return newval
|
|
|
|
BX_CPU_THIS_PTR msr.tsc_last_reset =
|
|
|
|
bx_pc_system.time_ticks() - (Bit64u) newval;
|
|
|
|
|
|
|
|
// verify
|
|
|
|
BX_ASSERT (get_TSC() == (Bit64u) newval);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2003-11-14 00:17:31 +03:00
|
|
|
void BX_CPU_C::RDTSC(bxInstruction_c *i)
|
2001-04-10 05:04:59 +04:00
|
|
|
{
|
|
|
|
#if BX_CPU_LEVEL >= 5
|
2002-10-25 15:44:41 +04:00
|
|
|
bx_bool tsd = BX_CPU_THIS_PTR cr4.get_TSD();
|
2005-01-24 00:13:49 +03:00
|
|
|
if ((tsd==0) || (tsd==1 && 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 !"));
|
2002-04-11 05:19:24 +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"));
|
2001-04-10 05:04:59 +04:00
|
|
|
UndefinedOpcode(i);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2005-08-05 16:47:33 +04:00
|
|
|
#if BX_SUPPORT_X86_64
|
|
|
|
void BX_CPU_C::RDTSCP(bxInstruction_c *i)
|
|
|
|
{
|
|
|
|
RDTSC(i);
|
|
|
|
RCX = MSR_TSC_AUX;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2003-11-14 00:17:31 +03:00
|
|
|
void BX_CPU_C::RDMSR(bxInstruction_c *i)
|
2001-04-10 05:04:59 +04:00
|
|
|
{
|
|
|
|
#if BX_CPU_LEVEL >= 5
|
2002-10-04 21:04:33 +04:00
|
|
|
invalidate_prefetch_q();
|
2002-09-15 03:17:55 +04:00
|
|
|
|
2002-10-04 21:04:33 +04:00
|
|
|
if (v8086_mode()) {
|
2004-12-14 23:41:55 +03:00
|
|
|
BX_INFO(("RDMSR: Invalid in virtual 8086 mode"));
|
2005-08-05 16:47:33 +04:00
|
|
|
exception(BX_GP_EXCEPTION, 0, 0);
|
2005-02-03 21:25:10 +03:00
|
|
|
}
|
2002-03-27 19:04:05 +03:00
|
|
|
|
2005-08-05 16:47:33 +04:00
|
|
|
if (protected_mode() && CPL != 0) {
|
2005-02-03 21:25:10 +03:00
|
|
|
BX_INFO(("RDMSR: CPL != 0"));
|
2005-08-05 16:47:33 +04:00
|
|
|
exception(BX_GP_EXCEPTION, 0, 0);
|
2005-02-03 21:25:10 +03:00
|
|
|
}
|
2002-03-27 19:04:05 +03:00
|
|
|
|
2002-10-04 21:04:33 +04:00
|
|
|
/* We have the requested MSR register in ECX */
|
|
|
|
switch(ECX) {
|
2003-01-20 23:10:31 +03:00
|
|
|
|
|
|
|
#if BX_SUPPORT_SEP
|
2005-08-05 16:47:33 +04:00
|
|
|
case BX_MSR_SYSENTER_CS:
|
|
|
|
RAX = BX_CPU_THIS_PTR sysenter_cs_msr;
|
|
|
|
RDX = 0;
|
|
|
|
return;
|
|
|
|
|
|
|
|
case BX_MSR_SYSENTER_ESP:
|
|
|
|
RAX = BX_CPU_THIS_PTR sysenter_esp_msr;
|
|
|
|
RDX = 0;
|
|
|
|
return;
|
|
|
|
|
|
|
|
case BX_MSR_SYSENTER_EIP:
|
|
|
|
RAX = BX_CPU_THIS_PTR sysenter_eip_msr;
|
|
|
|
RDX = 0;
|
|
|
|
return;
|
2003-01-20 23:10:31 +03:00
|
|
|
#endif
|
|
|
|
|
2002-03-27 19:04:05 +03:00
|
|
|
#if BX_CPU_LEVEL == 5
|
2002-10-04 21:04:33 +04:00
|
|
|
/* The following registers are defined for Pentium only */
|
|
|
|
case BX_MSR_P5_MC_ADDR:
|
|
|
|
case BX_MSR_MC_TYPE:
|
|
|
|
/* TODO */
|
|
|
|
return;
|
|
|
|
|
|
|
|
case BX_MSR_CESR:
|
|
|
|
/* TODO */
|
|
|
|
return;
|
2001-04-10 05:04:59 +04:00
|
|
|
#else
|
2002-10-04 21:04:33 +04:00
|
|
|
/* These are noops on i686... */
|
|
|
|
case BX_MSR_P5_MC_ADDR:
|
|
|
|
case BX_MSR_MC_TYPE:
|
|
|
|
/* do nothing */
|
|
|
|
return;
|
|
|
|
|
|
|
|
/* ... And these cause an exception on i686 */
|
|
|
|
case BX_MSR_CESR:
|
|
|
|
case BX_MSR_CTR0:
|
|
|
|
case BX_MSR_CTR1:
|
|
|
|
goto do_exception;
|
|
|
|
#endif /* BX_CPU_LEVEL == 5 */
|
|
|
|
|
2006-01-21 15:06:03 +03:00
|
|
|
case BX_MSR_TSC:
|
|
|
|
RDTSC(i);
|
2005-04-18 21:21:34 +04:00
|
|
|
return;
|
|
|
|
|
2002-10-04 21:04:33 +04:00
|
|
|
/* MSR_APICBASE
|
|
|
|
0:7 Reserved
|
2005-04-26 23:19:58 +04:00
|
|
|
8 This is set if its the BSP
|
2002-10-04 21:04:33 +04:00
|
|
|
9:10 Reserved
|
|
|
|
11 APIC Global Enable bit (1=enabled 0=disabled)
|
|
|
|
12:35 APIC Base Address
|
|
|
|
36:63 Reserved
|
|
|
|
*/
|
|
|
|
case BX_MSR_APICBASE:
|
|
|
|
/* we return low 32 bits in EAX, and high in EDX */
|
|
|
|
RAX = Bit32u(BX_CPU_THIS_PTR msr.apicbase & 0xffffffff);
|
|
|
|
RDX = Bit32u(BX_CPU_THIS_PTR msr.apicbase >> 32);
|
|
|
|
BX_INFO(("RDMSR: Read %08x:%08x from MSR_APICBASE", EDX, EAX));
|
|
|
|
return;
|
2002-09-15 03:17:55 +04:00
|
|
|
|
|
|
|
#if BX_SUPPORT_X86_64
|
2005-08-05 16:47:33 +04:00
|
|
|
case BX_MSR_EFER:
|
2005-11-27 00:36:51 +03:00
|
|
|
RAX = (Bit64u) BX_CPU_THIS_PTR get_EFER();
|
2005-08-05 16:47:33 +04:00
|
|
|
RDX = 0;
|
|
|
|
return;
|
|
|
|
|
|
|
|
case BX_MSR_STAR:
|
|
|
|
RAX = MSR_STAR & 0xffffffff;
|
|
|
|
RDX = MSR_STAR >> 32;
|
|
|
|
return;
|
|
|
|
|
|
|
|
case BX_MSR_LSTAR:
|
|
|
|
RAX = MSR_LSTAR & 0xffffffff;
|
|
|
|
RDX = MSR_LSTAR >> 32;
|
|
|
|
return;
|
|
|
|
|
|
|
|
case BX_MSR_CSTAR:
|
|
|
|
RAX = MSR_CSTAR & 0xffffffff;
|
|
|
|
RDX = MSR_CSTAR >> 32;
|
|
|
|
return;
|
|
|
|
|
|
|
|
case BX_MSR_FMASK:
|
|
|
|
RAX = MSR_FMASK & 0xffffffff;
|
|
|
|
RDX = MSR_FMASK >> 32;
|
|
|
|
return;
|
|
|
|
|
|
|
|
case BX_MSR_FSBASE:
|
|
|
|
RAX = MSR_FSBASE & 0xffffffff;
|
|
|
|
RDX = MSR_FSBASE >> 32;
|
|
|
|
return;
|
|
|
|
|
|
|
|
case BX_MSR_GSBASE:
|
|
|
|
RAX = MSR_GSBASE & 0xffffffff;
|
|
|
|
RDX = MSR_GSBASE >> 32;
|
|
|
|
return;
|
|
|
|
|
|
|
|
case BX_MSR_KERNELGSBASE:
|
|
|
|
RAX = MSR_KERNELGSBASE & 0xffffffff;
|
|
|
|
RDX = MSR_KERNELGSBASE >> 32;
|
|
|
|
return;
|
|
|
|
|
|
|
|
case BX_MSR_TSC_AUX:
|
|
|
|
RAX = MSR_TSC_AUX; // 32 bit MSR
|
|
|
|
RDX = 0;
|
|
|
|
return;
|
2002-09-15 03:17:55 +04:00
|
|
|
#endif // #if BX_SUPPORT_X86_64
|
|
|
|
|
2002-10-04 21:04:33 +04:00
|
|
|
default:
|
2003-08-30 01:20:52 +04:00
|
|
|
BX_ERROR(("RDMSR: Unknown register %#x", ECX));
|
2004-11-02 19:10:02 +03:00
|
|
|
#if BX_IGNORE_BAD_MSR
|
2005-02-03 21:25:10 +03:00
|
|
|
RAX = 0;
|
|
|
|
RDX = 0;
|
2003-08-30 01:20:52 +04:00
|
|
|
return;
|
I integrated my hacks to get Linux/x86-64 booting. To keep
these from interfering from a normal compile here's what I did.
In config.h.in (which will generate config.h after a configure),
I added a #define called KPL64Hacks:
#define KPL64Hacks
*After* running configure, you must set this by hand. It will
default to off, so you won't get my hacks in a normal compile.
This will go away soon. There is also a macro just after that
called BailBigRSP(). You don't need to enabled that, but you
can. In many of the instructions which seemed like they could
be hit by the fetchdecode64() process, but which also touched
EIP/ESP, I inserted a macro. Usually this macro expands to nothing.
If you like, you can enabled it, and it will panic if it finds
the upper bits of RIP/RSP set. This helped me find bugs.
Also, I cleaned up the emulation in ctrl_xfer{8,16,32}.cc.
There were some really old legacy code snippets which directly
accessed operands on the stack with access_linear. Lots of
ugly code instead of just pop_32() etc. Cleaning those up,
minimized the number of instructions which directly manipulate
the stack pointer, which should help in refining 64-bit support.
2002-09-24 04:44:56 +04:00
|
|
|
#endif
|
2002-10-04 21:04:33 +04:00
|
|
|
}
|
2002-03-27 19:04:05 +03:00
|
|
|
|
|
|
|
do_exception:
|
2002-10-04 21:04:33 +04:00
|
|
|
exception(BX_GP_EXCEPTION, 0, 0);
|
2004-11-02 19:10:02 +03:00
|
|
|
|
|
|
|
#else /* BX_CPU_LEVEL >= 5 */
|
|
|
|
BX_INFO(("RDMSR: Pentium CPU required"));
|
|
|
|
UndefinedOpcode(i);
|
|
|
|
#endif
|
2001-04-10 05:04:59 +04:00
|
|
|
}
|
|
|
|
|
2003-11-14 00:17:31 +03:00
|
|
|
void BX_CPU_C::WRMSR(bxInstruction_c *i)
|
2001-04-10 05:04:59 +04:00
|
|
|
{
|
|
|
|
#if BX_CPU_LEVEL >= 5
|
2002-10-04 21:04:33 +04:00
|
|
|
invalidate_prefetch_q();
|
2002-03-27 19:04:05 +03:00
|
|
|
|
2002-10-04 21:04:33 +04:00
|
|
|
if (v8086_mode()) {
|
2004-12-14 23:41:55 +03:00
|
|
|
BX_INFO(("WRMSR: Invalid in virtual 8086 mode"));
|
2005-08-05 16:47:33 +04:00
|
|
|
exception(BX_GP_EXCEPTION, 0, 0);
|
2005-02-03 21:25:10 +03:00
|
|
|
}
|
2002-03-27 19:04:05 +03:00
|
|
|
|
2005-08-05 16:47:33 +04:00
|
|
|
if (protected_mode() && CPL != 0) {
|
2005-02-03 21:25:10 +03:00
|
|
|
BX_INFO(("WDMSR: CPL != 0"));
|
2005-08-05 16:47:33 +04:00
|
|
|
exception(BX_GP_EXCEPTION, 0, 0);
|
2005-02-03 21:25:10 +03:00
|
|
|
}
|
2002-03-27 19:04:05 +03:00
|
|
|
|
2005-03-17 23:50:57 +03:00
|
|
|
BX_INSTR_WRMSR(BX_CPU_ID, ECX, ((Bit64u) EDX << 32) + EAX);
|
|
|
|
|
2002-10-04 21:04:33 +04:00
|
|
|
/* ECX has the MSR to write to */
|
|
|
|
switch(ECX) {
|
2003-01-20 23:10:31 +03:00
|
|
|
|
|
|
|
#if BX_SUPPORT_SEP
|
2005-08-05 16:47:33 +04:00
|
|
|
case BX_MSR_SYSENTER_CS: {
|
|
|
|
// not a bug according to book ... but very stOOpid
|
|
|
|
if (EAX & 3) BX_PANIC(("writing sysenter_cs_msr with non-kernel mode selector %X", EAX));
|
|
|
|
BX_CPU_THIS_PTR sysenter_cs_msr = EAX;
|
2003-01-20 23:10:31 +03:00
|
|
|
return;
|
|
|
|
}
|
2005-08-05 16:47:33 +04:00
|
|
|
|
|
|
|
case BX_MSR_SYSENTER_ESP:
|
|
|
|
BX_CPU_THIS_PTR sysenter_esp_msr = EAX;
|
|
|
|
return;
|
|
|
|
|
|
|
|
case BX_MSR_SYSENTER_EIP:
|
|
|
|
BX_CPU_THIS_PTR sysenter_eip_msr = EAX;
|
|
|
|
return;
|
2003-01-20 23:10:31 +03:00
|
|
|
#endif
|
|
|
|
|
2002-03-27 19:04:05 +03:00
|
|
|
#if BX_CPU_LEVEL == 5
|
2002-10-04 21:04:33 +04:00
|
|
|
/* The following registers are defined for Pentium only */
|
|
|
|
case BX_MSR_P5_MC_ADDR:
|
|
|
|
case BX_MSR_MC_TYPE:
|
|
|
|
case BX_MSR_CESR:
|
|
|
|
/* TODO */
|
|
|
|
return;
|
2001-04-10 05:04:59 +04:00
|
|
|
#else
|
2002-10-04 21:04:33 +04:00
|
|
|
/* These are noops on i686... */
|
|
|
|
case BX_MSR_P5_MC_ADDR:
|
|
|
|
case BX_MSR_MC_TYPE:
|
|
|
|
/* do nothing */
|
|
|
|
return;
|
|
|
|
|
|
|
|
/* ... And these cause an exception on i686 */
|
|
|
|
case BX_MSR_CESR:
|
|
|
|
case BX_MSR_CTR0:
|
|
|
|
case BX_MSR_CTR1:
|
|
|
|
goto do_exception;
|
|
|
|
#endif /* BX_CPU_LEVEL == 5 */
|
|
|
|
|
2005-04-18 21:21:34 +04:00
|
|
|
case BX_MSR_TSC:
|
2006-01-21 15:06:03 +03:00
|
|
|
BX_CPU_THIS_PTR set_TSC(EAX); /* ignore the high 32bits */
|
|
|
|
BX_INFO(("WRMSR: wrote 0x%08x to MSR_TSC", EAX));
|
2005-04-18 21:21:34 +04:00
|
|
|
return;
|
|
|
|
|
2002-10-04 21:04:33 +04:00
|
|
|
/* MSR_APICBASE
|
|
|
|
0:7 Reserved
|
2005-04-18 21:21:34 +04:00
|
|
|
8 This is set if its the BSP
|
2002-10-04 21:04:33 +04:00
|
|
|
9:10 Reserved
|
|
|
|
11 APIC Global Enable bit (1=enabled 0=disabled)
|
|
|
|
12:35 APIC Base Address
|
|
|
|
36:63 Reserved
|
|
|
|
*/
|
2004-12-14 23:41:55 +03:00
|
|
|
#if BX_SUPPORT_APIC
|
2002-10-04 21:04:33 +04:00
|
|
|
case BX_MSR_APICBASE:
|
2004-12-14 23:41:55 +03:00
|
|
|
if (BX_CPU_THIS_PTR msr.apicbase & 0x800)
|
|
|
|
{
|
|
|
|
BX_CPU_THIS_PTR msr.apicbase = ((Bit64u) EDX << 32) + EAX;
|
|
|
|
BX_INFO(("WRMSR: wrote %08x:%08x to MSR_APICBASE", EDX, EAX));
|
2005-01-13 22:03:40 +03:00
|
|
|
BX_CPU_THIS_PTR local_apic.set_base(BX_CPU_THIS_PTR msr.apicbase);
|
2004-12-14 23:41:55 +03:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
BX_INFO(("WRMSR: MSR_APICBASE APIC global enable bit cleared !"));
|
|
|
|
}
|
2002-10-04 21:04:33 +04:00
|
|
|
return;
|
2004-12-14 23:41:55 +03:00
|
|
|
#endif
|
2002-09-15 03:17:55 +04:00
|
|
|
|
|
|
|
#if BX_SUPPORT_X86_64
|
2005-08-05 16:47:33 +04:00
|
|
|
case BX_MSR_EFER:
|
|
|
|
// GPF #0 if lme 0->1 and cr0.pg = 1
|
|
|
|
// GPF #0 if lme 1->0 and cr0.pg = 1
|
|
|
|
if ((BX_CPU_THIS_PTR msr.lme != ((EAX >> 8) & 1)) &&
|
|
|
|
(BX_CPU_THIS_PTR cr0.pg == 1))
|
|
|
|
{
|
|
|
|
exception(BX_GP_EXCEPTION, 0, 0);
|
|
|
|
}
|
|
|
|
BX_CPU_THIS_PTR msr.sce = (EAX >> 0) & 1;
|
|
|
|
BX_CPU_THIS_PTR msr.lme = (EAX >> 8) & 1;
|
|
|
|
BX_CPU_THIS_PTR msr.nxe = (EAX >> 11) & 1;
|
|
|
|
BX_CPU_THIS_PTR msr.ffxsr = (EAX >> 14) & 1;
|
|
|
|
return;
|
|
|
|
|
|
|
|
case BX_MSR_STAR:
|
|
|
|
MSR_STAR = ((Bit64u) EDX << 32) + EAX;
|
|
|
|
return;
|
|
|
|
|
|
|
|
case BX_MSR_LSTAR:
|
|
|
|
MSR_LSTAR = ((Bit64u) EDX << 32) + EAX;
|
|
|
|
return;
|
|
|
|
|
|
|
|
case BX_MSR_CSTAR:
|
|
|
|
MSR_CSTAR = ((Bit64u) EDX << 32) + EAX;
|
|
|
|
return;
|
|
|
|
|
|
|
|
case BX_MSR_FMASK:
|
|
|
|
MSR_FMASK = ((Bit64u) EDX << 32) + EAX;
|
|
|
|
return;
|
|
|
|
|
|
|
|
case BX_MSR_FSBASE:
|
|
|
|
MSR_FSBASE = ((Bit64u) EDX << 32) + EAX;
|
|
|
|
return;
|
|
|
|
|
|
|
|
case BX_MSR_GSBASE:
|
|
|
|
MSR_GSBASE = ((Bit64u) EDX << 32) + EAX;
|
|
|
|
return;
|
|
|
|
|
|
|
|
case BX_MSR_KERNELGSBASE:
|
|
|
|
MSR_KERNELGSBASE = ((Bit64u) EDX << 32) + EAX;
|
|
|
|
return;
|
|
|
|
|
|
|
|
case BX_MSR_TSC_AUX:
|
|
|
|
MSR_TSC_AUX = EAX;
|
|
|
|
return;
|
2002-09-15 03:17:55 +04:00
|
|
|
#endif // #if BX_SUPPORT_X86_64
|
|
|
|
|
2002-10-04 21:04:33 +04:00
|
|
|
default:
|
2004-11-02 19:10:02 +03:00
|
|
|
BX_ERROR(("WRMSR: Unknown register %#x", ECX));
|
2002-09-24 12:29:06 +04:00
|
|
|
#if BX_IGNORE_BAD_MSR
|
2004-11-02 19:10:02 +03:00
|
|
|
return;
|
I integrated my hacks to get Linux/x86-64 booting. To keep
these from interfering from a normal compile here's what I did.
In config.h.in (which will generate config.h after a configure),
I added a #define called KPL64Hacks:
#define KPL64Hacks
*After* running configure, you must set this by hand. It will
default to off, so you won't get my hacks in a normal compile.
This will go away soon. There is also a macro just after that
called BailBigRSP(). You don't need to enabled that, but you
can. In many of the instructions which seemed like they could
be hit by the fetchdecode64() process, but which also touched
EIP/ESP, I inserted a macro. Usually this macro expands to nothing.
If you like, you can enabled it, and it will panic if it finds
the upper bits of RIP/RSP set. This helped me find bugs.
Also, I cleaned up the emulation in ctrl_xfer{8,16,32}.cc.
There were some really old legacy code snippets which directly
accessed operands on the stack with access_linear. Lots of
ugly code instead of just pop_32() etc. Cleaning those up,
minimized the number of instructions which directly manipulate
the stack pointer, which should help in refining 64-bit support.
2002-09-24 04:44:56 +04:00
|
|
|
#endif
|
2002-10-04 21:04:33 +04:00
|
|
|
}
|
2002-03-27 19:04:05 +03:00
|
|
|
|
|
|
|
do_exception:
|
2002-10-04 21:04:33 +04:00
|
|
|
exception(BX_GP_EXCEPTION, 0, 0);
|
2004-11-02 19:10:02 +03:00
|
|
|
|
|
|
|
#else /* BX_CPU_LEVEL >= 5 */
|
|
|
|
BX_INFO(("RDMSR: Pentium CPU required"));
|
|
|
|
UndefinedOpcode(i);
|
|
|
|
#endif
|
2003-01-20 23:10:31 +03:00
|
|
|
}
|
|
|
|
|
2003-11-14 00:17:31 +03:00
|
|
|
void BX_CPU_C::SYSENTER (bxInstruction_c *i)
|
2003-01-20 23:10:31 +03:00
|
|
|
{
|
|
|
|
#if BX_SUPPORT_SEP
|
|
|
|
if (!protected_mode ()) {
|
|
|
|
BX_INFO (("sysenter not from protected mode"));
|
|
|
|
exception (BX_GP_EXCEPTION, 0, 0);
|
|
|
|
return;
|
|
|
|
}
|
2005-10-09 22:32:36 +04:00
|
|
|
if ((BX_CPU_THIS_PTR sysenter_cs_msr & BX_SELECTOR_RPL_MASK) == 0) {
|
2003-01-20 23:10:31 +03:00
|
|
|
BX_INFO (("sysenter with zero sysenter_cs_msr"));
|
|
|
|
exception (BX_GP_EXCEPTION, 0, 0);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
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
|
|
|
|
2005-02-27 20:41:45 +03:00
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value = BX_CPU_THIS_PTR sysenter_cs_msr & BX_SELECTOR_RPL_MASK;
|
2003-01-20 23:10:31 +03:00
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.index = BX_CPU_THIS_PTR sysenter_cs_msr >> 3;
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.ti = (BX_CPU_THIS_PTR sysenter_cs_msr >> 2) & 1;
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.rpl = 0;
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.executable = 1; // code segment
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.c_ed = 0; // non-conforming
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.r_w = 1; // readable
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.a = 1; // accessed
|
|
|
|
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; // 32-bit mode
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.avl = 0; // available for use by system
|
|
|
|
|
2006-01-16 22:22:28 +03:00
|
|
|
#if BX_SUPPORT_ICACHE
|
|
|
|
BX_CPU_THIS_PTR iCache.fetchModeMask = createFetchModeMask(BX_CPU_THIS);
|
|
|
|
#endif
|
|
|
|
|
2005-02-27 20:41:45 +03:00
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].selector.value = (BX_CPU_THIS_PTR sysenter_cs_msr + 8) & BX_SELECTOR_RPL_MASK;
|
2003-01-20 23:10:31 +03:00
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].selector.index = (BX_CPU_THIS_PTR sysenter_cs_msr + 8) >> 3;
|
2005-02-26 15:00:22 +03:00
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].selector.ti = ((BX_CPU_THIS_PTR sysenter_cs_msr + 8) >> 2) & 1;
|
2003-01-20 23:10:31 +03:00
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].selector.rpl = 0;
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.executable = 0; // data segment
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.c_ed = 0; // expand-up
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.r_w = 1; // writeable
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.a = 1; // accessed
|
|
|
|
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
|
|
|
|
|
|
|
|
ESP = BX_CPU_THIS_PTR sysenter_esp_msr;
|
|
|
|
EIP = BX_CPU_THIS_PTR sysenter_eip_msr;
|
|
|
|
#else
|
2003-06-20 12:58:12 +04:00
|
|
|
BX_INFO(("SYSENTER: use --enable-sep to enable SYSENTER/SYSEXIT support"));
|
2003-01-20 23:10:31 +03:00
|
|
|
UndefinedOpcode (i);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2003-11-14 00:17:31 +03:00
|
|
|
void BX_CPU_C::SYSEXIT (bxInstruction_c *i)
|
2003-01-20 23:10:31 +03:00
|
|
|
{
|
|
|
|
#if BX_SUPPORT_SEP
|
|
|
|
if (!protected_mode ()) {
|
|
|
|
BX_INFO (("sysexit not from protected mode"));
|
|
|
|
exception (BX_GP_EXCEPTION, 0, 0);
|
|
|
|
}
|
2005-10-09 22:32:36 +04:00
|
|
|
if ((BX_CPU_THIS_PTR sysenter_cs_msr & BX_SELECTOR_RPL_MASK) == 0) {
|
2003-01-20 23:10:31 +03:00
|
|
|
BX_INFO (("sysexit with zero sysenter_cs_msr"));
|
|
|
|
exception (BX_GP_EXCEPTION, 0, 0);
|
|
|
|
}
|
|
|
|
if (CPL != 0) {
|
|
|
|
BX_INFO (("sysexit at non-zero cpl %u", CPL));
|
|
|
|
exception (BX_GP_EXCEPTION, 0, 0);
|
|
|
|
}
|
|
|
|
|
2003-05-11 02:25:55 +04:00
|
|
|
invalidate_prefetch_q();
|
2003-01-20 23:10:31 +03:00
|
|
|
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value = (BX_CPU_THIS_PTR sysenter_cs_msr + 16) | 3;
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.index = (BX_CPU_THIS_PTR sysenter_cs_msr + 16) >> 3;
|
2005-02-26 15:00:22 +03:00
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.ti = ((BX_CPU_THIS_PTR sysenter_cs_msr + 16) >> 2) & 1;
|
2003-01-20 23:10:31 +03:00
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.rpl = 3;
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.executable = 1; // code segment
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.c_ed = 0; // non-conforming
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.r_w = 1; // readable
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.a = 1; // accessed
|
|
|
|
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; // 32-bit mode
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.avl = 0; // available for use by system
|
|
|
|
|
2006-01-16 22:22:28 +03:00
|
|
|
#if BX_SUPPORT_ICACHE
|
|
|
|
BX_CPU_THIS_PTR iCache.fetchModeMask = createFetchModeMask(BX_CPU_THIS);
|
|
|
|
#endif
|
|
|
|
|
2003-01-20 23:10:31 +03:00
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].selector.value = (BX_CPU_THIS_PTR sysenter_cs_msr + 24) | 3;
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].selector.index = (BX_CPU_THIS_PTR sysenter_cs_msr + 24) >> 3;
|
2005-02-26 15:00:22 +03:00
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].selector.ti = ((BX_CPU_THIS_PTR sysenter_cs_msr + 24) >> 2) & 1;
|
2003-01-20 23:10:31 +03:00
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].selector.rpl = 3;
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.executable = 0; // data segment
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.c_ed = 0; // expand-up
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.r_w = 1; // writeable
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.a = 1; // accessed
|
|
|
|
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
|
|
|
|
|
|
|
|
ESP = ECX;
|
|
|
|
EIP = EDX;
|
|
|
|
#else
|
2003-06-20 12:58:12 +04:00
|
|
|
BX_INFO(("SYSEXIT: use --enable-sep to enable SYSENTER/SYSEXIT support"));
|
2003-01-20 23:10:31 +03:00
|
|
|
UndefinedOpcode (i);
|
|
|
|
#endif
|
2001-04-10 05:04:59 +04:00
|
|
|
}
|
|
|
|
|
2002-09-25 18:09:08 +04:00
|
|
|
#if BX_SUPPORT_X86_64
|
2005-03-03 23:24:52 +03:00
|
|
|
void BX_CPU_C::SYSCALL(bxInstruction_c *i)
|
|
|
|
{
|
|
|
|
|
|
|
|
/* pseudo code from AMD manual.
|
|
|
|
|
|
|
|
SYSCALL_START:
|
|
|
|
|
|
|
|
IF (MSR_EFER.SCE = 0) // Check if syscall/sysret are enabled.
|
|
|
|
EXCEPTION [#UD]
|
|
|
|
|
|
|
|
IF (LONG_MODE)
|
|
|
|
SYSCALL_LONG_MODE
|
|
|
|
ELSE // (LEGACY_MODE)
|
|
|
|
SYSCALL_LEGACY_MODE
|
|
|
|
|
|
|
|
|
|
|
|
SYSCALL_LONG_MODE:
|
|
|
|
|
|
|
|
RCX.q = next_RIP
|
|
|
|
R11.q = RFLAGS // with rf cleared
|
|
|
|
|
|
|
|
IF (64BIT_MODE)
|
|
|
|
temp_RIP.q = MSR_LSTAR
|
|
|
|
ELSE // (COMPATIBILITY_MODE)
|
|
|
|
temp_RIP.q = MSR_CSTAR
|
|
|
|
|
|
|
|
CS.sel = MSR_STAR.SYSCALL_CS AND 0xFFFC
|
|
|
|
CS.attr = 64-bit code,dpl0 // Always switch to 64-bit mode in long mode.
|
|
|
|
CS.base = 0x00000000
|
|
|
|
CS.limit = 0xFFFFFFFF
|
|
|
|
|
|
|
|
SS.sel = MSR_STAR.SYSCALL_CS + 8
|
|
|
|
SS.attr = 64-bit stack,dpl0
|
|
|
|
SS.base = 0x00000000
|
|
|
|
SS.limit = 0xFFFFFFFF
|
|
|
|
|
|
|
|
RFLAGS = RFLAGS AND ~MSR_SFMASK
|
|
|
|
RFLAGS.RF = 0
|
|
|
|
|
|
|
|
CPL = 0
|
|
|
|
|
|
|
|
RIP = temp_RIP
|
|
|
|
EXIT
|
|
|
|
|
|
|
|
SYSCALL_LEGACY_MODE:
|
|
|
|
|
|
|
|
RCX.d = next_RIP
|
|
|
|
|
|
|
|
temp_RIP.d = MSR_STAR.EIP
|
|
|
|
|
|
|
|
CS.sel = MSR_STAR.SYSCALL_CS AND 0xFFFC
|
|
|
|
CS.attr = 32-bit code,dpl0 // Always switch to 32-bit mode in legacy mode.
|
|
|
|
CS.base = 0x00000000
|
|
|
|
CS.limit = 0xFFFFFFFF
|
|
|
|
|
|
|
|
SS.sel = MSR_STAR.SYSCALL_CS + 8
|
|
|
|
SS.attr = 32-bit stack,dpl0
|
|
|
|
SS.base = 0x00000000
|
|
|
|
SS.limit = 0xFFFFFFFF
|
|
|
|
|
|
|
|
RFLAGS.VM,IF,RF=0
|
|
|
|
|
|
|
|
CPL = 0
|
|
|
|
|
|
|
|
RIP = temp_RIP
|
|
|
|
EXIT
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
bx_address temp_RIP;
|
|
|
|
bx_descriptor_t cs_descriptor,ss_descriptor;
|
|
|
|
bx_selector_t cs_selector,ss_selector;
|
|
|
|
Bit32u dword1, dword2;
|
|
|
|
|
|
|
|
if (!BX_CPU_THIS_PTR msr.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();
|
|
|
|
|
|
|
|
if (BX_CPU_THIS_PTR msr.lma)
|
|
|
|
{
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
parse_selector((MSR_STAR >> 32) & 0xFFFC, &cs_selector);
|
|
|
|
fetch_raw_descriptor(&cs_selector, &dword1, &dword2, BX_GP_EXCEPTION);
|
|
|
|
parse_descriptor(dword1, dword2, &cs_descriptor);
|
|
|
|
load_cs(&cs_selector, &cs_descriptor, 0);
|
|
|
|
|
|
|
|
parse_selector((MSR_STAR >> 32) + 8, &ss_selector);
|
|
|
|
fetch_raw_descriptor(&ss_selector, &dword1, &dword2, BX_GP_EXCEPTION);
|
|
|
|
parse_descriptor(dword1, dword2, &ss_descriptor);
|
|
|
|
load_ss(&ss_selector, &ss_descriptor, 0);
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
parse_selector((MSR_STAR >> 32) & 0xFFFC, &cs_selector);
|
|
|
|
fetch_raw_descriptor(&cs_selector, &dword1, &dword2, BX_GP_EXCEPTION);
|
|
|
|
parse_descriptor(dword1, dword2, &cs_descriptor);
|
|
|
|
load_cs(&cs_selector, &cs_descriptor, 0);
|
|
|
|
|
|
|
|
parse_selector((MSR_STAR >> 32) + 8, &ss_selector);
|
|
|
|
fetch_raw_descriptor(&ss_selector, &dword1, &dword2, BX_GP_EXCEPTION);
|
|
|
|
parse_descriptor(dword1, dword2, &ss_descriptor);
|
|
|
|
load_ss(&ss_selector, &ss_descriptor, 0);
|
|
|
|
|
|
|
|
BX_CPU_THIS_PTR clear_VM ();
|
|
|
|
BX_CPU_THIS_PTR clear_IF ();
|
|
|
|
BX_CPU_THIS_PTR clear_RF ();
|
|
|
|
RIP = temp_RIP;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void BX_CPU_C::SYSRET(bxInstruction_c *i)
|
|
|
|
{
|
|
|
|
/* from AMD manual
|
|
|
|
|
|
|
|
SYSRET_START:
|
|
|
|
|
|
|
|
IF (MSR_EFER.SCE = 0) // Check if syscall/sysret are enabled.
|
|
|
|
EXCEPTION [#UD]
|
|
|
|
|
|
|
|
IF ((!PROTECTED_MODE) || (CPL != 0))
|
|
|
|
EXCEPTION [#GP(0)] // SYSRET requires protected mode, cpl0
|
|
|
|
|
|
|
|
IF (64BIT_MODE)
|
|
|
|
SYSRET_64BIT_MODE
|
|
|
|
ELSE // (!64BIT_MODE)
|
|
|
|
SYSRET_NON_64BIT_MODE
|
|
|
|
|
|
|
|
SYSRET_64BIT_MODE:
|
|
|
|
IF (OPERAND_SIZE = 64) // Return to 64-bit mode.
|
|
|
|
{
|
|
|
|
CS.sel = (MSR_STAR.SYSRET_CS + 16) OR 3
|
|
|
|
CS.base = 0x00000000
|
|
|
|
CS.limit = 0xFFFFFFFF
|
|
|
|
CS.attr = 64-bit code,dpl3
|
|
|
|
temp_RIP.q = RCX
|
|
|
|
}
|
|
|
|
ELSE // Return to 32-bit compatibility mode.
|
|
|
|
{
|
|
|
|
CS.sel = MSR_STAR.SYSRET_CS OR 3
|
|
|
|
CS.base = 0x00000000
|
|
|
|
CS.limit = 0xFFFFFFFF
|
|
|
|
CS.attr = 32-bit code,dpl3
|
|
|
|
temp_RIP.d = RCX
|
|
|
|
}
|
|
|
|
SS.sel = MSR_STAR.SYSRET_CS + 8 // SS selector is changed,
|
|
|
|
// SS base, limit, attributes unchanged.
|
|
|
|
RFLAGS.q = R11 // RF=0,VM=0
|
|
|
|
CPL = 3
|
|
|
|
RIP = temp_RIP
|
|
|
|
EXIT
|
|
|
|
|
|
|
|
SYSRET_NON_64BIT_MODE:
|
|
|
|
CS.sel = MSR_STAR.SYSRET_CS OR 3 // Return to 32-bit legacy protected mode.
|
|
|
|
CS.base = 0x00000000
|
|
|
|
CS.limit = 0xFFFFFFFF
|
|
|
|
CS.attr = 32-bit code,dpl3
|
|
|
|
temp_RIP.d = RCX
|
|
|
|
SS.sel = MSR_STAR.SYSRET_CS + 8 // SS selector is changed.
|
|
|
|
// SS base, limit, attributes unchanged.
|
|
|
|
RFLAGS.IF = 1
|
|
|
|
CPL = 3
|
|
|
|
RIP = temp_RIP
|
|
|
|
EXIT
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
bx_address temp_RIP;
|
|
|
|
bx_descriptor_t cs_descriptor,ss_descriptor;
|
|
|
|
bx_selector_t cs_selector,ss_selector;
|
|
|
|
Bit32u dword1, dword2;
|
|
|
|
|
|
|
|
if (!BX_CPU_THIS_PTR msr.sce) {
|
2005-10-17 17:06:09 +04:00
|
|
|
exception(BX_UD_EXCEPTION, 0, 0);
|
2005-03-03 23:24:52 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
if(real_mode() || CPL != 0) {
|
|
|
|
exception(BX_GP_EXCEPTION, 0, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
invalidate_prefetch_q();
|
|
|
|
|
|
|
|
if (BX_CPU_THIS_PTR cpu_mode == BX_MODE_LONG_64)
|
|
|
|
{
|
2006-02-02 20:55:48 +03:00
|
|
|
if (i->os64L()) { // Return to 64-bit mode
|
2005-03-03 23:24:52 +03:00
|
|
|
parse_selector(((MSR_STAR >> 48) + 16) | 3, &cs_selector);
|
|
|
|
fetch_raw_descriptor(&cs_selector, &dword1, &dword2, BX_GP_EXCEPTION);
|
|
|
|
parse_descriptor(dword1, dword2, &cs_descriptor);
|
|
|
|
load_cs(&cs_selector, &cs_descriptor, 3);
|
|
|
|
|
|
|
|
temp_RIP = RCX;
|
|
|
|
}
|
2006-02-02 20:55:48 +03:00
|
|
|
else { // Return to 32-bit compatibility mode
|
2005-03-03 23:24:52 +03:00
|
|
|
parse_selector((MSR_STAR >> 48) | 3, &cs_selector);
|
|
|
|
fetch_raw_descriptor(&cs_selector, &dword1, &dword2, BX_GP_EXCEPTION);
|
|
|
|
parse_descriptor(dword1, dword2, &cs_descriptor);
|
|
|
|
load_cs(&cs_selector, &cs_descriptor, 3);
|
|
|
|
|
|
|
|
temp_RIP = ECX;
|
|
|
|
}
|
|
|
|
|
|
|
|
parse_selector((MSR_STAR >> 48) + 8, &ss_selector);
|
|
|
|
fetch_raw_descriptor(&ss_selector, &dword1, &dword2, BX_GP_EXCEPTION);
|
|
|
|
parse_descriptor(dword1, dword2, &ss_descriptor);
|
2006-02-02 20:55:48 +03:00
|
|
|
// SS base, limit, attributes unchanged.
|
2005-03-03 23:24:52 +03:00
|
|
|
load_ss(&ss_selector, &ss_descriptor, 0);
|
|
|
|
|
2005-10-17 17:06:09 +04:00
|
|
|
writeEFlags(R11, EFlagsValidMask);
|
2005-03-03 23:24:52 +03:00
|
|
|
|
|
|
|
RIP = temp_RIP;
|
|
|
|
}
|
|
|
|
else { // (!64BIT_MODE)
|
2006-02-02 20:55:48 +03:00
|
|
|
parse_selector((MSR_STAR >> 48) | 3, &cs_selector);
|
2005-03-03 23:24:52 +03:00
|
|
|
fetch_raw_descriptor(&cs_selector, &dword1, &dword2, BX_GP_EXCEPTION);
|
|
|
|
parse_descriptor(dword1, dword2, &cs_descriptor);
|
|
|
|
load_cs(&cs_selector, &cs_descriptor, 3);
|
|
|
|
|
|
|
|
temp_RIP = ECX;
|
|
|
|
|
|
|
|
parse_selector((MSR_STAR >> 48) + 8, &ss_selector);
|
|
|
|
fetch_raw_descriptor(&ss_selector, &dword1, &dword2, BX_GP_EXCEPTION);
|
|
|
|
parse_descriptor(dword1, dword2, &ss_descriptor);
|
2006-02-02 20:55:48 +03:00
|
|
|
// SS base, limit, attributes unchanged.
|
2005-03-03 23:24:52 +03:00
|
|
|
load_ss(&ss_selector, &ss_descriptor, 0);
|
|
|
|
|
|
|
|
BX_CPU_THIS_PTR assert_IF ();
|
|
|
|
|
|
|
|
RIP = temp_RIP;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2003-08-30 01:20:52 +04:00
|
|
|
void BX_CPU_C::SWAPGS(bxInstruction_c *i)
|
2002-09-25 18:09:08 +04:00
|
|
|
{
|
|
|
|
Bit64u temp_GS_base;
|
|
|
|
|
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
|
2003-08-30 01:20:52 +04:00
|
|
|
Bit32u BX_CPU_C::hwdebug_compare(Bit32u 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;
|
|
|
|
|
2002-10-25 15:44:41 +04:00
|
|
|
bx_bool ibpoint_found = 0;
|
2001-04-10 05:04:59 +04:00
|
|
|
Bit32u laddr_n = laddr_0 + (size - 1);
|
|
|
|
Bit32u dr0, dr1, dr2, dr3;
|
|
|
|
Bit32u dr0_n, dr1_n, dr2_n, dr3_n;
|
|
|
|
Bit32u len0, len1, len2, len3;
|
|
|
|
static unsigned alignment_mask[4] =
|
|
|
|
// 00b=1 01b=2 10b=undef 11b=4
|
|
|
|
{ 0xffffffff, 0xfffffffe, 0xffffffff, 0xfffffffc };
|
|
|
|
Bit32u dr0_op, dr1_op, dr2_op, dr3_op;
|
|
|
|
|
|
|
|
len0 = (dr7>>18) & 3;
|
|
|
|
len1 = (dr7>>22) & 3;
|
|
|
|
len2 = (dr7>>26) & 3;
|
|
|
|
len3 = (dr7>>30) & 3;
|
|
|
|
|
|
|
|
dr0 = BX_CPU_THIS_PTR dr0 & alignment_mask[len0];
|
|
|
|
dr1 = BX_CPU_THIS_PTR dr1 & alignment_mask[len1];
|
|
|
|
dr2 = BX_CPU_THIS_PTR dr2 & alignment_mask[len2];
|
|
|
|
dr3 = BX_CPU_THIS_PTR dr3 & alignment_mask[len3];
|
|
|
|
|
|
|
|
dr0_n = dr0 + len0;
|
|
|
|
dr1_n = dr1 + len1;
|
|
|
|
dr2_n = dr2 + len2;
|
|
|
|
dr3_n = dr3 + len3;
|
|
|
|
|
|
|
|
dr0_op = (dr7>>16) & 3;
|
|
|
|
dr1_op = (dr7>>20) & 3;
|
|
|
|
dr2_op = (dr7>>24) & 3;
|
|
|
|
dr3_op = (dr7>>28) & 3;
|
|
|
|
|
|
|
|
// See if this instruction address matches any breakpoints
|
|
|
|
if ( (dr7 & 0x00000003) ) {
|
|
|
|
if ( (dr0_op==opa || dr0_op==opb) &&
|
|
|
|
(laddr_0 <= dr0_n) &&
|
|
|
|
(laddr_n >= dr0) )
|
|
|
|
ibpoint_found = 1;
|
2005-04-18 21:21:34 +04:00
|
|
|
}
|
2001-04-10 05:04:59 +04:00
|
|
|
if ( (dr7 & 0x0000000c) ) {
|
|
|
|
if ( (dr1_op==opa || dr1_op==opb) &&
|
|
|
|
(laddr_0 <= dr1_n) &&
|
|
|
|
(laddr_n >= dr1) )
|
|
|
|
ibpoint_found = 1;
|
2005-04-18 21:21:34 +04:00
|
|
|
}
|
2001-04-10 05:04:59 +04:00
|
|
|
if ( (dr7 & 0x00000030) ) {
|
|
|
|
if ( (dr2_op==opa || dr2_op==opb) &&
|
|
|
|
(laddr_0 <= dr2_n) &&
|
|
|
|
(laddr_n >= dr2) )
|
|
|
|
ibpoint_found = 1;
|
2005-04-18 21:21:34 +04:00
|
|
|
}
|
2001-04-10 05:04:59 +04:00
|
|
|
if ( (dr7 & 0x000000c0) ) {
|
|
|
|
if ( (dr3_op==opa || dr3_op==opb) &&
|
|
|
|
(laddr_0 <= dr3_n) &&
|
|
|
|
(laddr_n >= dr3) )
|
|
|
|
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.
|
|
|
|
// This code is similar to that above, only without the
|
|
|
|
// breakpoint enabled check. Seems weird to duplicate effort,
|
|
|
|
// but its more efficient to do it this way.
|
|
|
|
if (ibpoint_found) {
|
|
|
|
// 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;
|
|
|
|
if ( (dr0_op==opa || dr0_op==opb) &&
|
|
|
|
(laddr_0 <= dr0_n) &&
|
|
|
|
(laddr_n >= dr0) )
|
|
|
|
dr6_mask |= 0x01;
|
|
|
|
if ( (dr1_op==opa || dr1_op==opb) &&
|
|
|
|
(laddr_0 <= dr1_n) &&
|
|
|
|
(laddr_n >= dr1) )
|
|
|
|
dr6_mask |= 0x02;
|
|
|
|
if ( (dr2_op==opa || dr2_op==opb) &&
|
|
|
|
(laddr_0 <= dr2_n) &&
|
|
|
|
(laddr_n >= dr2) )
|
|
|
|
dr6_mask |= 0x04;
|
|
|
|
if ( (dr3_op==opa || dr3_op==opb) &&
|
|
|
|
(laddr_0 <= dr3_n) &&
|
|
|
|
(laddr_n >= dr3) )
|
|
|
|
dr6_mask |= 0x08;
|
|
|
|
return(dr6_mask);
|
2005-04-18 21:21:34 +04:00
|
|
|
}
|
2001-04-10 05:04:59 +04:00
|
|
|
return(0);
|
|
|
|
}
|
|
|
|
#endif
|
2005-05-18 02:22:35 +04:00
|
|
|
|
2005-05-18 09:05:40 +04:00
|
|
|
/*
|
2005-05-18 02:22:35 +04:00
|
|
|
void BX_CPU_C::LFENCE(bxInstruction_c *i) {}
|
|
|
|
void BX_CPU_C::MFENCE(bxInstruction_c *i) {}
|
|
|
|
void BX_CPU_C::SFENCE(bxInstruction_c *i) {}
|
2005-05-18 09:05:40 +04:00
|
|
|
*/
|