Complete MONITOR/MWAIT implemntation (including monitoring of memory range)

Fixed PANIC in read/write Cr/Dr - should #UD with unkown register used
This commit is contained in:
Stanislav Shwartsman 2007-11-01 18:03:48 +00:00
parent 4c6836e383
commit e137560b14
16 changed files with 303 additions and 232 deletions

View File

@ -1,5 +1,5 @@
/////////////////////////////////////////////////////////////////////////
// $Id: bochs.h,v 1.213 2007-10-30 18:57:45 sshwarts Exp $
// $Id: bochs.h,v 1.214 2007-11-01 18:03:48 sshwarts Exp $
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2002 MandrakeSoft S.A.
@ -186,11 +186,7 @@ void print_tree(bx_param_c *node, int level = 0);
#define BX_CPU(x) (&bx_cpu)
#endif
#if BX_ADDRESS_SPACES==1
#define BX_MEM(x) (&bx_mem)
#else
#define BX_MEM(x) (&bx_mem_array[x])
#endif
#define BX_SET_ENABLE_A20(enabled) bx_pc_system.set_enable_a20(enabled)
#define BX_GET_ENABLE_A20() bx_pc_system.get_enable_a20()

View File

@ -56,14 +56,6 @@
#define BX_BOOTSTRAP_PROCESSOR 0
#define BX_MAX_SMP_THREADS_SUPPORTED 8
// Controls how many instances of BX_MEM_C are created. For
// SMP, use several processors with one shared memory space.
#define BX_ADDRESS_SPACES 1
#if BX_ADDRESS_SPACES != 1
#error "Support for several address spaces still not implemented"
#endif
// include in APIC models, required for a multiprocessor system.
#define BX_SUPPORT_APIC 0

View File

@ -1,5 +1,5 @@
/////////////////////////////////////////////////////////////////////////
// $Id: apic.cc,v 1.100 2007-10-18 22:44:38 sshwarts Exp $
// $Id: apic.cc,v 1.101 2007-11-01 18:03:48 sshwarts Exp $
/////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2002 Zwane Mwaikambo, Stanislav Shwartsman
@ -507,9 +507,8 @@ void bx_local_apic_c::receive_EOI(Bit32u value)
void bx_local_apic_c::startup_msg(Bit32u vector)
{
if(cpu->debug_trap & BX_DEBUG_TRAP_HALT_STATE) {
cpu->debug_trap &= ~BX_DEBUG_TRAP_HALT_STATE;
cpu->cpu_state = BX_CPU_STATE_ACTIVE;
if(cpu->debug_trap & BX_DEBUG_TRAP_SPECIAL) {
cpu->debug_trap &= ~BX_DEBUG_TRAP_SPECIAL;
cpu->eip_reg.dword.eip = 0;
cpu->load_seg_reg(&cpu->sregs[BX_SEG_REG_CS], vector*0x100);
BX_INFO(("%s started up at %04X:%08X by APIC", cpu->name, vector*0x100, cpu->eip_reg.dword.eip));

View File

@ -1,5 +1,5 @@
/////////////////////////////////////////////////////////////////////////
// $Id: cpu.cc,v 1.177 2007-10-30 22:15:42 sshwarts Exp $
// $Id: cpu.cc,v 1.178 2007-11-01 18:03:48 sshwarts Exp $
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2001 MandrakeSoft S.A.
@ -36,14 +36,6 @@
#include "extdb.h"
#endif
#if BX_PROVIDE_CPU_MEMORY
#if BX_ADDRESS_SPACES==1
BOCHSAPI BX_MEM_C bx_mem;
#else
BOCHSAPI BX_MEM_C bx_mem_array[BX_ADDRESS_SPACES];
#endif
#endif
#if BX_SUPPORT_ICACHE
bxPageWriteStampTable pageWriteStampTable;
@ -443,7 +435,7 @@ unsigned BX_CPU_C::handleAsyncEvent(void)
//
// This area is where we process special conditions and events.
//
if (BX_CPU_THIS_PTR debug_trap & BX_DEBUG_TRAP_HALT_STATE) {
if (BX_CPU_THIS_PTR debug_trap & BX_DEBUG_TRAP_SPECIAL) {
// I made up the bitmask above to mean HALT state.
#if BX_SUPPORT_SMP == 0
// for one processor, pass the time as quickly as possible until
@ -454,15 +446,19 @@ unsigned BX_CPU_C::handleAsyncEvent(void)
while (1)
#endif
{
if ((BX_CPU_INTR && BX_CPU_THIS_PTR get_IF()) ||
if ((BX_CPU_INTR && (BX_CPU_THIS_PTR get_IF() || (BX_CPU_THIS_PTR debug_trap & BX_DEBUG_TRAP_MWAIT_IF))) ||
BX_CPU_THIS_PTR nmi_pending || BX_CPU_THIS_PTR smi_pending)
{
// interrupt ends the HALT condition
#if BX_SUPPORT_MONITOR_MWAIT
if (BX_CPU_THIS_PTR debug_trap & BX_DEBUG_TRAP_MWAIT)
BX_MEM(0)->clear_monitor(BX_CPU_THIS_PTR bx_cpuid);
#endif
BX_CPU_THIS_PTR debug_trap = 0; // clear traps for after resume
BX_CPU_THIS_PTR inhibit_mask = 0; // clear inhibits for after resume
break;
}
if ((BX_CPU_THIS_PTR debug_trap & BX_DEBUG_TRAP_HALT_STATE) == 0) {
if ((BX_CPU_THIS_PTR debug_trap & BX_DEBUG_TRAP_SPECIAL) == 0) {
BX_INFO(("handleAsyncEvent: reset detected in HLT state"));
break;
}
@ -473,10 +469,14 @@ unsigned BX_CPU_C::handleAsyncEvent(void)
// must give the others a chance to simulate. If an interrupt has
// arrived, then clear the HALT condition; otherwise just return from
// the CPU loop with stop_reason STOP_CPU_HALTED.
if ((BX_CPU_INTR && BX_CPU_THIS_PTR get_IF()) ||
if ((BX_CPU_INTR && (BX_CPU_THIS_PTR get_IF() || (BX_CPU_THIS_PTR debug_trap & BX_DEBUG_TRAP_MWAIT_IF))) ||
BX_CPU_THIS_PTR nmi_pending || BX_CPU_THIS_PTR smi_pending)
{
// interrupt ends the HALT condition
#if BX_SUPPORT_MONITOR_MWAIT
if (BX_CPU_THIS_PTR debug_trap & BX_DEBUG_TRAP_MWAIT)
BX_MEM(0)->clear_monitor(BX_CPU_THIS_PTR bx_cpuid);
#endif
BX_CPU_THIS_PTR debug_trap = 0; // clear traps for after resume
BX_CPU_THIS_PTR inhibit_mask = 0; // clear inhibits for after resume
} else {

View File

@ -1,5 +1,5 @@
/////////////////////////////////////////////////////////////////////////
// $Id: cpu.h,v 1.344 2007-10-30 22:15:42 sshwarts Exp $
// $Id: cpu.h,v 1.345 2007-11-01 18:03:48 sshwarts Exp $
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2001 MandrakeSoft S.A.
@ -339,13 +339,6 @@
#define BX_MODE_LONG_64 0x4 // EFER.LMA = 1, CR0.PE=1, CS.L=1
extern const char* cpu_mode_string(unsigned cpu_mode);
#define BX_CPU_STATE_ACTIVE 0x0
#define BX_CPU_STATE_HLT 0x1
#define BX_CPU_STATE_SHUTDOWN 0x2
#define BX_CPU_STATE_WAIT_FOR_SIPI 0x3
#define BX_CPU_STATE_MWAIT 0x4
extern const char* cpu_state_string(unsigned cpu_state);
#if BX_SUPPORT_X86_64
@ -368,6 +361,8 @@ extern const char* cpu_state_string(unsigned cpu_state);
#define BX_CPU_INTR (BX_CPU_THIS_PTR INTR)
#endif
#define CACHE_LINE_SIZE 64
class BX_CPU_C;
class BX_MEM_C;
@ -1041,6 +1036,19 @@ class BX_MEM_C;
#include "cpu/xmm.h"
#endif
#if BX_SUPPORT_MONITOR_MWAIT
struct monitor_addr_t {
bx_phy_address monitor_begin;
bx_phy_address monitor_end;
// avoid false trigger when MONITOR was not set up properly
monitor_addr_t():
monitor_begin(0xffffffff), monitor_end(0xffffffff) {}
monitor_addr_t(bx_phy_address addr, unsigned len):
monitor_begin(addr), monitor_end(addr+len) {}
};
#endif
class BOCHSAPI BX_CPU_C : public logfunctions {
public: // for now...
@ -1140,6 +1148,10 @@ public: // for now...
bx_mxcsr_t mxcsr;
#endif
#if BX_SUPPORT_MONITOR_MWAIT
monitor_addr_t monitor;
#endif
// pointer to the address space that this processor uses.
BX_MEM_C *mem;
@ -1152,8 +1164,15 @@ public: // for now...
* 0 if current CS:IP caused exception */
unsigned errorno; /* signal exception during instruction emulation */
#define BX_DEBUG_TRAP_HALT_STATE (0x80000000)
Bit32u debug_trap; // holds DR6 value to be set as well
#define BX_DEBUG_TRAP_HALT (0x80000000)
#define BX_DEBUG_TRAP_SHUTDOWN (0x40000000)
#define BX_DEBUG_TRAP_WAIT_FOR_SIPI (0x20000000)
#define BX_DEBUG_TRAP_MWAIT (0x10000000)
#define BX_DEBUG_TRAP_MWAIT_IF (0x18000000)
// combine all possible states
#define BX_DEBUG_TRAP_SPECIAL (0xf8000000)
Bit32u debug_trap; // holds DR6 value (16bit) to be set as well
volatile bx_bool async_event;
volatile bx_bool INTR;
volatile bx_bool smi_pending;
@ -1192,7 +1211,7 @@ public: // for now...
#if BX_SUPPORT_ICACHE
const Bit32u *currPageWriteStampPtr;
#endif
unsigned cpu_mode, cpu_state;
unsigned cpu_mode;
bx_bool in_smm;
bx_bool nmi_disable;
#if BX_CPU_LEVEL >= 4 && BX_SUPPORT_ALIGNMENT_CHECK
@ -3108,6 +3127,7 @@ public: // for now...
BX_SMF BX_CPP_INLINE bx_bool v8086_mode(void);
BX_SMF BX_CPP_INLINE bx_bool long_mode(void);
BX_SMF BX_CPP_INLINE unsigned get_cpu_mode(void);
BX_SMF BX_CPP_INLINE unsigned get_cpu_state(void);
#if BX_CPU_LEVEL >= 5
BX_SMF Bit64u get_TSC();
@ -3136,6 +3156,11 @@ public: // for now...
BX_SMF void check_exceptionsSSE(int);
BX_SMF void print_state_SSE(void);
#endif
#if BX_SUPPORT_MONITOR_MWAIT
BX_SMF bx_bool is_monitor(bx_phy_address addr, unsigned len);
BX_SMF void check_monitor(bx_phy_address addr, unsigned len);
#endif
};
#if BX_SUPPORT_ICACHE
@ -3300,6 +3325,11 @@ BX_CPP_INLINE unsigned BX_CPU_C::get_cpu_mode(void)
return (BX_CPU_THIS_PTR cpu_mode);
}
BX_CPP_INLINE unsigned BX_CPU_C::get_cpu_state(void)
{
return (BX_CPU_THIS_PTR debug_trap >> 28); // 4 upper state bits in 32-bit debug_trap
}
BOCHSAPI extern const bx_bool bx_parity_lookup[256];
BX_CPP_INLINE void BX_CPU_C::set_PF_base(Bit8u val)

View File

@ -1,5 +1,5 @@
/////////////////////////////////////////////////////////////////////////
// $Id: cpuid.cc,v 1.54 2007-10-15 22:07:52 sshwarts Exp $
// $Id: cpuid.cc,v 1.55 2007-11-01 18:03:48 sshwarts Exp $
/////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2007 Stanislav Shwartsman
@ -36,8 +36,6 @@
#define RDX EDX
#endif
#define CACHE_LINE_SIZE 64
#if BX_SUPPORT_3DNOW
#define BX_CPU_VENDOR_INTEL 0
#else

View File

@ -1,5 +1,5 @@
/////////////////////////////////////////////////////////////////////////
// $Id: debugstuff.cc,v 1.81 2007-10-23 21:51:44 sshwarts Exp $
// $Id: debugstuff.cc,v 1.82 2007-11-01 18:03:48 sshwarts Exp $
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2001 MandrakeSoft S.A.
@ -95,10 +95,10 @@ const char* cpu_state_string(unsigned cpu_state)
{
static const char *cpu_state_name[] = {
"active",
"halted",
"in shutdown",
"waiting for SIPI",
"executing mwait",
"waiting for SIPI",
"in shutdown",
"halted",
"unknown state"
};
@ -108,8 +108,8 @@ const char* cpu_state_string(unsigned cpu_state)
void BX_CPU_C::debug(bx_address offset)
{
BX_INFO(("CPU is in %s (%s)", cpu_mode_string(BX_CPU_THIS_PTR cpu_mode),
cpu_state_string(BX_CPU_THIS_PTR cpu_state)));
BX_INFO(("CPU is in %s (%s)", cpu_mode_string(BX_CPU_THIS_PTR get_cpu_mode()),
cpu_state_string(BX_CPU_THIS_PTR get_cpu_state())));
BX_INFO(("CS.d_b = %u bit",
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.d_b ? 32 : 16));
BX_INFO(("SS.d_b = %u bit",

View File

@ -1,5 +1,5 @@
/////////////////////////////////////////////////////////////////////////
// $Id: init.cc,v 1.140 2007-10-14 21:42:50 sshwarts Exp $
// $Id: init.cc,v 1.141 2007-11-01 18:03:48 sshwarts Exp $
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2001 MandrakeSoft S.A.
@ -400,7 +400,6 @@ void BX_CPU_C::register_state(void)
BXRS_PARAM_SPECIAL32(cpu, cpuid_std, param_save_handler, param_restore_handler);
BXRS_PARAM_SPECIAL32(cpu, cpuid_ext, param_save_handler, param_restore_handler);
BXRS_DEC_PARAM_SIMPLE(cpu, cpu_mode);
BXRS_DEC_PARAM_SIMPLE(cpu, cpu_state);
BXRS_HEX_PARAM_SIMPLE(cpu, inhibit_mask);
BXRS_HEX_PARAM_SIMPLE(cpu, debug_trap);
#if BX_SUPPORT_X86_64
@ -468,10 +467,10 @@ void BX_CPU_C::register_state(void)
}
#if BX_CPU_LEVEL >= 2
BXRS_HEX_PARAM_FIELD(cpu, gdtr_base, BX_CPU_THIS_PTR gdtr.base);
BXRS_HEX_PARAM_FIELD(cpu, gdtr_limit, BX_CPU_THIS_PTR gdtr.limit);
BXRS_HEX_PARAM_FIELD(cpu, idtr_base, BX_CPU_THIS_PTR idtr.base);
BXRS_HEX_PARAM_FIELD(cpu, idtr_limit, BX_CPU_THIS_PTR idtr.limit);
BXRS_HEX_PARAM_FIELD(cpu, gdtr_base, gdtr.base);
BXRS_HEX_PARAM_FIELD(cpu, gdtr_limit, gdtr.limit);
BXRS_HEX_PARAM_FIELD(cpu, idtr_base, idtr.base);
BXRS_HEX_PARAM_FIELD(cpu, idtr_limit, idtr.limit);
#endif
bx_list_c *LDTR = new bx_list_c (cpu, "LDTR", 7);
@ -575,12 +574,18 @@ void BX_CPU_C::register_state(void)
BXRS_HEX_PARAM_FIELD(sse, mxcsr, mxcsr.mxcsr);
for (i=0; i<BX_XMM_REGISTERS; i++) {
sprintf(name, "xmm%02d_hi", i);
new bx_shadow_num_c(sse, name, &BX_CPU_THIS_PTR xmm[i].xmm64u(1), BASE_HEX);
new bx_shadow_num_c(sse, name, &xmm[i].xmm64u(1), BASE_HEX);
sprintf(name, "xmm%02d_lo", i);
new bx_shadow_num_c(sse, name, &BX_CPU_THIS_PTR xmm[i].xmm64u(0), BASE_HEX);
new bx_shadow_num_c(sse, name, &xmm[i].xmm64u(0), BASE_HEX);
}
#endif
#if BX_SUPPORT_MONITOR_MWAIT
bx_list_c *monitor_list = new bx_list_c(cpu, "MONITOR", 2);
BXRS_HEX_PARAM_FIELD(monitor_list, begin_addr, monitor.monitor_begin);
BXRS_HEX_PARAM_FIELD(monitor_list, end_addr, monitor.monitor_end);
#endif
#if BX_SUPPORT_APIC
local_apic.register_state(cpu);
#endif
@ -948,7 +953,6 @@ void BX_CPU_C::reset(unsigned source)
#endif
BX_CPU_THIS_PTR cpu_mode = BX_MODE_IA32_REAL;
BX_CPU_THIS_PTR cpu_state = BX_CPU_STATE_ACTIVE;
BX_CPU_THIS_PTR smi_pending = 0;
BX_CPU_THIS_PTR nmi_pending = 0;
@ -1079,8 +1083,7 @@ void BX_CPU_C::reset(unsigned source)
// it's an application processor, halt until IPI is heard.
BX_CPU_THIS_PTR msr.apicbase &= ~0x0100; /* clear bit 8 BSP */
BX_INFO(("CPU[%d] is an application processor. Halting until IPI.", apic_id));
BX_CPU_THIS_PTR cpu_state = BX_CPU_STATE_WAIT_FOR_SIPI;
debug_trap |= BX_DEBUG_TRAP_HALT_STATE;
debug_trap |= BX_DEBUG_TRAP_WAIT_FOR_SIPI;
async_event = 1;
}
#endif
@ -1255,6 +1258,11 @@ void BX_CPU_C::assert_checks(void)
BX_PANIC(("assert_checks: TR is not TSS type !"));
}
}
#if BX_SUPPORT_MONITOR_MWAIT
if (BX_CPU_THIS_PTR monitor.monitor_end < BX_CPU_THIS_PTR monitor.monitor_begin)
BX_PANIC(("assert_checks: MONITOR range is not set correctly !"));
#endif
}
void BX_CPU_C::set_INTR(bx_bool value)

View File

@ -1,5 +1,5 @@
/////////////////////////////////////////////////////////////////////////
// $Id: paging.cc,v 1.88 2007-10-30 22:15:42 sshwarts Exp $
// $Id: paging.cc,v 1.89 2007-11-01 18:03:48 sshwarts Exp $
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2001 MandrakeSoft S.A.
@ -550,9 +550,11 @@ void BX_CPU_C::TLB_flush(bx_bool invalidateGlobal)
void BX_CPU_C::TLB_invlpg(bx_address laddr)
{
#if BX_USE_TLB
Bit32u TLB_index = BX_TLB_INDEX_OF(laddr);
BX_CPU_THIS_PTR TLB.entry[TLB_index].lpf = BX_INVALID_TLB_ENTRY;
InstrTLB_Increment(tlbEntryFlushes); // A TLB entry flush occurred.
#endif
}
void BX_CPU_C::INVLPG(bxInstruction_c* i)

View File

@ -1,5 +1,5 @@
/////////////////////////////////////////////////////////////////////////
// $Id: proc_ctrl.cc,v 1.176 2007-10-18 22:44:39 sshwarts Exp $
// $Id: proc_ctrl.cc,v 1.177 2007-11-01 18:03:48 sshwarts Exp $
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2001 MandrakeSoft S.A.
@ -77,8 +77,7 @@ void BX_CPU_C::shutdown(void)
BX_CPU_THIS_PTR clear_IF();
// artificial trap bit, why use another variable.
BX_CPU_THIS_PTR cpu_state = BX_CPU_STATE_SHUTDOWN;
BX_CPU_THIS_PTR debug_trap |= BX_DEBUG_TRAP_HALT_STATE; // artificial trap
BX_CPU_THIS_PTR debug_trap |= BX_DEBUG_TRAP_SHUTDOWN; // 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
@ -112,8 +111,7 @@ void BX_CPU_C::HLT(bxInstruction_c *i)
// following HLT.
// artificial trap bit, why use another variable.
BX_CPU_THIS_PTR cpu_state = BX_CPU_STATE_HLT;
BX_CPU_THIS_PTR debug_trap |= BX_DEBUG_TRAP_HALT_STATE; // artificial trap
BX_CPU_THIS_PTR debug_trap |= BX_DEBUG_TRAP_HALT; // 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
@ -319,8 +317,8 @@ void BX_CPU_C::MOV_DdRd(bxInstruction_c *i)
break;
default:
BX_PANIC(("MOV_DdRd: control register index out of range"));
break;
BX_ERROR(("MOV_DdRd: #UD - control register index out of range"));
UndefinedOpcode(i);
}
}
@ -336,8 +334,6 @@ void BX_CPU_C::MOV_RdDd(bxInstruction_c *i)
/* 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())
BX_PANIC(("MOV_RdDd(): rm field not a register!"));
switch (i->nnn()) {
case 0: // DR0
@ -384,9 +380,10 @@ void BX_CPU_C::MOV_RdDd(bxInstruction_c *i)
break;
default:
BX_PANIC(("MOV_RdDd: control register index out of range"));
val_32 = 0;
BX_ERROR(("MOV_RdDd: #UD - control register index out of range"));
UndefinedOpcode(i);
}
BX_WRITE_32BIT_REGZ(i->rm(), val_32);
}
@ -404,8 +401,6 @@ void BX_CPU_C::MOV_DqRq(bxInstruction_c *i)
/* 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())
BX_PANIC(("MOV_DqRq(): rm field not a register!"));
invalidate_prefetch_q();
@ -500,8 +495,8 @@ void BX_CPU_C::MOV_DqRq(bxInstruction_c *i)
break;
default:
BX_PANIC(("MOV_DqRq: control register index out of range"));
break;
BX_ERROR(("MOV_DqRq: #UD - control register index out of range"));
UndefinedOpcode(i);
}
}
@ -514,8 +509,6 @@ void BX_CPU_C::MOV_RqDq(bxInstruction_c *i)
/* 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())
BX_PANIC(("MOV_RqDq(): rm field not a register!"));
/* #GP(0) if CPL is not 0 */
if (CPL != 0) {
@ -564,9 +557,10 @@ void BX_CPU_C::MOV_RqDq(bxInstruction_c *i)
break;
default:
BX_PANIC(("MOV_RqDq: control register index out of range"));
val_64 = 0;
BX_ERROR(("MOV_DqRq: #UD - control register index out of range"));
UndefinedOpcode(i);
}
BX_WRITE_64BIT_REG(i->rm(), val_64);
}
#endif // #if BX_SUPPORT_X86_64
@ -590,8 +584,6 @@ void BX_CPU_C::MOV_CdRd(bxInstruction_c *i)
/* 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())
BX_PANIC(("MOV_CdRd(): rm field not a register!"));
invalidate_prefetch_q();
@ -627,8 +619,8 @@ void BX_CPU_C::MOV_CdRd(bxInstruction_c *i)
#endif
break;
default:
BX_PANIC(("MOV_CdRd: control register index out of range"));
break;
BX_ERROR(("MOV_CdRd: #UD - control register index out of range"));
UndefinedOpcode(i);
}
}
@ -681,9 +673,10 @@ void BX_CPU_C::MOV_RdCd(bxInstruction_c *i)
#endif
break;
default:
BX_PANIC(("MOV_RdCd: control register index out of range"));
val_32 = 0;
BX_ERROR(("MOV_RdCd: #UD - control register index out of range"));
UndefinedOpcode(i);
}
BX_WRITE_32BIT_REGZ(i->rm(), val_32);
}
@ -758,8 +751,8 @@ void BX_CPU_C::MOV_CqRq(bxInstruction_c *i)
break;
#endif
default:
BX_PANIC(("MOV_CqRq: control register index out of range"));
break;
BX_ERROR(("MOV_CqRq: #UD - control register index out of range"));
UndefinedOpcode(i);
}
}
@ -819,8 +812,8 @@ void BX_CPU_C::MOV_RqCq(bxInstruction_c *i)
break;
#endif
default:
BX_PANIC(("MOV_RqCq: control register index out of range"));
val_64 = 0;
BX_ERROR(("MOV_RqCq: #UD - control register index out of range"));
UndefinedOpcode(i);
}
BX_WRITE_64BIT_REG(i->rm(), val_64);
@ -1894,6 +1887,28 @@ void BX_CPU_C::WRMSR(bxInstruction_c *i)
#endif
}
#if BX_SUPPORT_MONITOR_MWAIT
bx_bool BX_CPU_C::is_monitor(bx_phy_address begin_addr, unsigned len)
{
bx_phy_address end_addr = begin_addr + len;
if (begin_addr >= BX_CPU_THIS_PTR monitor.monitor_end || end_addr <= BX_CPU_THIS_PTR monitor.monitor_begin)
return 0;
else
return 1;
}
void BX_CPU_C::check_monitor(bx_phy_address begin_addr, unsigned len)
{
if (is_monitor(begin_addr, len)) {
// wakeup from MWAIT state
BX_ASSERT(BX_CPU_THIS_PTR debug_trap & BX_DEBUG_TRAP_MWAIT);
BX_CPU_THIS_PTR debug_trap &= ~BX_DEBUG_TRAP_SPECIAL;
// clear monitor
BX_MEM(0)->clear_monitor(BX_CPU_THIS_PTR bx_cpuid);
}
}
#endif
void BX_CPU_C::MONITOR(bxInstruction_c *i)
{
#if BX_SUPPORT_MONITOR_MWAIT
@ -1907,7 +1922,8 @@ void BX_CPU_C::MONITOR(bxInstruction_c *i)
exception(BX_GP_EXCEPTION, 0, 0);
}
bx_address addr;
bx_address addr, laddr;
bx_phy_address paddr;
#if BX_SUPPORT_X86_64
if (i->as64L()) {
@ -1916,7 +1932,7 @@ void BX_CPU_C::MONITOR(bxInstruction_c *i)
else
#endif
if (i->as32L()) {
addr = EAX;
laddr = EAX;
}
else {
addr = AX;
@ -1924,7 +1940,20 @@ void BX_CPU_C::MONITOR(bxInstruction_c *i)
read_virtual_checks(&BX_CPU_THIS_PTR sregs[i->seg()], addr, 1);
// TODO: Implemented actual MONITOR functionality
// set MONITOR
laddr = BX_CPU_THIS_PTR get_segment_base(i->seg()) + addr;
if (BX_CPU_THIS_PTR cr0.get_PG()) {
paddr = dtranslate_linear(laddr, CPL==3, BX_READ);
paddr = A20ADDR(paddr);
}
else
{
paddr = A20ADDR(laddr);
}
BX_CPU_THIS_PTR monitor.monitor_begin = paddr;
BX_CPU_THIS_PTR monitor.monitor_end = paddr + CACHE_LINE_SIZE;
#else
BX_INFO(("MONITOR: use --enable-monitor-mwait to enable MONITOR/MWAIT support"));
@ -1941,12 +1970,43 @@ void BX_CPU_C::MWAIT(bxInstruction_c *i)
// only one extension is supported
// ECX[0] - interrupt MWAIT even if EFLAGS.IF = 0
if (RCX & ~((Bit64u)(1))) {
if (RCX & ~(BX_CONST64(1))) {
BX_ERROR(("MWAIT: incorrect optional extensions in RCX"));
exception(BX_GP_EXCEPTION, 0, 0);
}
// TODO: Implemented actual MWAIT functionality
// Do not enter optimized state if MONITOR wasn't properly set
if (BX_CPU_THIS_PTR monitor.monitor_begin == BX_CPU_THIS_PTR monitor.monitor_end) {
BX_ERROR(("MWAIT: incorrect MONITOR settings"));
return;
}
bx_pc_system.invlpg(BX_CPU_THIS_PTR monitor.monitor_begin);
if ((BX_CPU_THIS_PTR monitor.monitor_end & ~0xfff) != (BX_CPU_THIS_PTR monitor.monitor_begin & ~0xfff))
bx_pc_system.invlpg(BX_CPU_THIS_PTR monitor.monitor_end);
BX_DEBUG(("MWAIT for phys_addr=%08x", BX_CPU_THIS_PTR monitor.monitor_begin));
BX_MEM(0)->set_monitor(BX_CPU_THIS_PTR bx_cpuid);
// stops instruction execution and places the processor in a optimized
// state. Events that cause exit from MWAIT state are:
// A store from another processor to monitored range, any unmasked
// interrupt, including INTR, NMI, SMI, INIT or reset will resume
// the execution. Any far control transfer between MONITOR and MWAIT
// resets the monitoring logic.
// artificial trap bit, why use another variable.
BX_CPU_THIS_PTR debug_trap |= BX_DEBUG_TRAP_MWAIT; // artificial trap
if (ECX & 1)
BX_CPU_THIS_PTR debug_trap |= BX_DEBUG_TRAP_MWAIT_IF;
BX_CPU_THIS_PTR async_event = 1; // so processor knows to check
// Execution of this instruction completes. The processor
// will remain in a optimized state until one of the above
// conditions is met.
#if BX_USE_IDLE_HACK
bx_gui->sim_is_idle();
#endif
#else
BX_INFO(("MWAIT: use --enable-monitor-mwait to enable MONITOR/MWAIT support"));
UndefinedOpcode (i);

View File

@ -1,5 +1,5 @@
/////////////////////////////////////////////////////////////////////////
// $Id: main.cc,v 1.361 2007-10-24 23:28:11 sshwarts Exp $
// $Id: main.cc,v 1.362 2007-11-01 18:03:48 sshwarts Exp $
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2002 MandrakeSoft S.A.
@ -107,6 +107,10 @@ BOCHSAPI BX_CPU_C_PTR *bx_cpu_array = NULL;
BOCHSAPI BX_CPU_C bx_cpu;
#endif
#if BX_PROVIDE_CPU_MEMORY==1
BOCHSAPI BX_MEM_C bx_mem;
#endif
char *bochsrc_filename = NULL;
void bx_print_header ()

View File

@ -1,5 +1,5 @@
/////////////////////////////////////////////////////////////////////////
// $Id: memory.cc,v 1.61 2007-10-09 20:23:01 sshwarts Exp $
// $Id: memory.cc,v 1.62 2007-11-01 18:03:48 sshwarts Exp $
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2001 MandrakeSoft S.A.
@ -87,6 +87,10 @@ BX_MEM_C::writePhysicalPage(BX_CPU_C *cpu, bx_phy_address addr, unsigned len, vo
}
}
#if BX_SUPPORT_MONITOR_MWAIT
BX_MEM_THIS check_monitor(a20addr, len);
#endif
memory_handler = BX_MEM_THIS memory_handlers[a20addr >> 20];
while (memory_handler) {
if (memory_handler->begin <= a20addr &&

View File

@ -1,5 +1,5 @@
/////////////////////////////////////////////////////////////////////////
// $Id: memory.h,v 1.42 2007-09-28 19:52:08 sshwarts Exp $
// $Id: memory.h,v 1.43 2007-11-01 18:03:48 sshwarts Exp $
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2001 MandrakeSoft S.A.
@ -69,6 +69,11 @@ private:
bx_bool smram_available;
bx_bool smram_enable;
bx_bool smram_restricted;
#if BX_SUPPORT_MONITOR_MWAIT
bx_bool *monitor_active;
Bit32u n_monitors;
#endif
public:
Bit8u *actual_vector;
@ -105,18 +110,20 @@ public:
BX_MEM_SMF bx_bool unregisterMemoryHandlers(memory_handler_t read_handler, memory_handler_t write_handler,
bx_phy_address begin_addr, bx_phy_address end_addr);
BX_MEM_SMF Bit32u get_num_allocated_pages(void);
BX_MEM_SMF void register_state(void);
#if BX_SUPPORT_MONITOR_MWAIT
void set_monitor(unsigned cpu);
void clear_monitor(unsigned cpu);
bx_bool is_monitor(bx_phy_address begin_addr, unsigned len);
void check_monitor(bx_phy_address addr, unsigned len);
#endif
BX_MEM_SMF void register_state(void);
};
#if BX_PROVIDE_CPU_MEMORY==1
#if BX_ADDRESS_SPACES==1
BOCHSAPI extern BX_MEM_C bx_mem;
#else
BOCHSAPI extern BX_MEM_C bx_mem_array[BX_ADDRESS_SPACES];
#endif /* BX_ADDRESS_SPACES */
#endif /* BX_PROVIDE_CPU_MEMORY==1 */
#endif
#if BX_DEBUGGER
# define BX_DBG_DIRTY_PAGE(page) BX_MEM(0)->dbg_dirty_pages[page] = 1;

View File

@ -1,5 +1,5 @@
/////////////////////////////////////////////////////////////////////////
// $Id: misc_mem.cc,v 1.103 2007-10-24 23:00:01 sshwarts Exp $
// $Id: misc_mem.cc,v 1.104 2007-11-01 18:03:48 sshwarts Exp $
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2002 MandrakeSoft S.A.
@ -90,7 +90,7 @@ void BX_MEM_C::init_memory(int memsize)
{
unsigned idx;
BX_DEBUG(("Init $Id: misc_mem.cc,v 1.103 2007-10-24 23:00:01 sshwarts Exp $"));
BX_DEBUG(("Init $Id: misc_mem.cc,v 1.104 2007-11-01 18:03:48 sshwarts Exp $"));
alloc_vector_aligned(memsize+ BIOSROMSZ + EXROMSIZE + 4096, BX_MEM_VECTOR_ALIGN);
BX_MEM_THIS len = memsize;
@ -118,13 +118,31 @@ void BX_MEM_C::init_memory(int memsize)
BX_ASSERT((BX_MEM_THIS len & 0xfffff) == 0);
BX_INFO(("%.2fMB", (float)(BX_MEM_THIS megabytes)));
#if BX_SUPPORT_MONITOR_MWAIT
BX_MEM_THIS monitor_active = new bx_bool[BX_SMP_PROCESSORS];
for (int i=0; i<BX_SMP_PROCESSORS;i++) {
BX_MEM_THIS monitor_active[i] = 0;
}
BX_MEM_THIS n_monitors = 0;
#endif
register_state();
}
void BX_MEM_C::register_state()
{
bx_list_c *list = new bx_list_c(SIM->get_bochs_root(), "memory", "Memory State", 1);
bx_list_c *list = new bx_list_c(SIM->get_bochs_root(), "memory", "Memory State", 3);
new bx_shadow_data_c(list, "ram", BX_MEM_THIS vector, BX_MEM_THIS len);
BXRS_DEC_PARAM_FIELD(list, len, BX_MEM_THIS len);
#if BX_SUPPORT_MONITOR_MWAIT
bx_list_c *monitors = new bx_list_c(list, "monitors", BX_SMP_PROCESSORS+1);
BXRS_PARAM_BOOL(monitors, n_monitors, BX_MEM_THIS n_monitors);
for (int i=0;i<BX_SMP_PROCESSORS;i++) {
char param_name[15];
sprintf(param_name, "cpu%d_monitor", i);
new bx_shadow_bool_c(monitors, param_name, &BX_MEM_THIS monitor_active[i]);
}
#endif
}
void BX_MEM_C::cleanup_memory()
@ -154,49 +172,6 @@ void BX_MEM_C::cleanup_memory()
}
}
#if 0
void put_8bit(Bit8u **pp, Bit8u value)
{
Bit8u *p = *pp;
*p++ = value;
*pp = p;
}
void put_16bit(Bit8u **pp, Bit16u value)
{
Bit8u *p = *pp;
*p++ = value & 0xff;
*p++ = (value >> 8) & 0xff;
*pp = p;
}
void put_32bit(Bit8u **pp, Bit32u value)
{
Bit8u *p = *pp;
*p++ = value & 0xff;
*p++ = (value >> 8) & 0xff;
*p++ = (value >> 16) & 0xff;
*p++ = (value >> 24) & 0xff;
*pp = p;
}
void put_string(Bit8u **pp, const char *str)
{
Bit8u *p = *pp;
while (*str)
*p++ = *str++;
*pp = p;
}
Bit8u mp_checksum(const Bit8u *p, int len)
{
Bit8u sum = 0;
for (int i = 0; i < len; i++)
sum += p[i];
return (Bit8u)(-sum);
}
#endif
//
// Values for type:
// 0 : System Bios
@ -335,77 +310,6 @@ void BX_MEM_C::load_ROM(const char *path, bx_phy_address romaddress, Bit8u type)
}
}
}
#if 0
if (is_bochs_bios) {
Bit8u* pcmp_ptr = &BX_MEM_THIS rom[0xFB000 & BIOS_MASK];
Bit8u* p = pcmp_ptr;
put_string(&p, "PCMP"); // signature
put_16bit(&p, 0); // table length
put_8bit(&p, 4); // version
put_8bit(&p, 0); // checksum
put_string(&p, "BOCHSCPU"); // OEM ID
put_string(&p, "0.1 "); // vendor ID
put_32bit(&p, 0); // OEM table pointer
put_16bit(&p, 0); // OEM table size
put_16bit(&p, 20); // entry count
put_32bit(&p, 0xfee00000); // local APIC addr
put_16bit(&p, 0); // ext table length
put_8bit(&p, 0); // ext table checksum
put_8bit(&p, 0); // reserved
for (i = 0; i < BX_SMP_PROCESSORS; i++) {
put_8bit(&p, 0); // entry type = processor
put_8bit(&p, (Bit8u)i); // APIC id
put_8bit(&p, BX_LAPIC_VERSION_ID & 0xff); // local APIC version number
put_8bit(&p, (i==0)?3:1); // cpu flags: enabled, cpu0 = bootstrap cpu
put_8bit(&p, 0); // cpu signature
put_8bit(&p, 0);
put_8bit(&p, 0);
put_8bit(&p, 0);
put_16bit(&p, 0x301); // feature flags: FPU, CX8, APIC
put_16bit(&p, 0);
put_16bit(&p, 0); // reserved
put_16bit(&p, 0);
put_16bit(&p, 0);
put_16bit(&p, 0);
}
put_8bit(&p, 1); // entry type = bus
put_8bit(&p, 0); // bus ID
put_string(&p, "ISA ");
Bit8u ioapic_id = BX_SMP_PROCESSORS;
put_8bit(&p, 2); // entry type = I/O APIC
put_8bit(&p, ioapic_id); // apic id
put_8bit(&p, BX_IOAPIC_VERSION_ID & 0xff); // I/O APIC version number
put_8bit(&p, 1); // enabled
put_32bit(&p, 0xfec00000); // I/O APIC addr
for (i = 0; i < 16; i++) {
put_8bit(&p, 3); // entry type = I/O interrupt
put_8bit(&p, 0); // interrupt type = vectored interrupt
put_8bit(&p, 0); // flags: po=0, el=0
put_8bit(&p, 0);
put_8bit(&p, 0); // source bus ID = ISA
put_8bit(&p, i); // source bus IRQ
put_8bit(&p, ioapic_id); // dest I/O APIC ID
put_8bit(&p, i); // dest I/O APIC interrupt in
}
Bit16u len = (Bit16u)(p - pcmp_ptr);
pcmp_ptr[4] = (Bit8u)len;
pcmp_ptr[5] = (Bit8u)(len >> 8);
pcmp_ptr[7] = mp_checksum(pcmp_ptr, len);
Bit8u *fl_mp_ptr = &BX_MEM_THIS rom[0xFB000 & BIOS_MASK] + ((len + 15) & ~15);
p = fl_mp_ptr;
put_string(&p, "_MP_");
put_32bit(&p, 0xFB000); // pointer to MP config table
put_8bit(&p, 1); // length in 16 byte units
put_8bit(&p, 4); // MP spec revision
put_8bit(&p, 0); // checksum
put_8bit(&p, 0); // MP feature bytes 1-5
put_8bit(&p, 0);
put_8bit(&p, 0);
put_8bit(&p, 0);
put_8bit(&p, 0);
fl_mp_ptr[10] = mp_checksum(fl_mp_ptr, (int)(p - fl_mp_ptr));
}
#endif
BX_INFO(("rom at 0x%05x/%u ('%s')",
(unsigned) romaddress,
(unsigned) stat_buf.st_size,
@ -620,6 +524,13 @@ Bit8u *BX_MEM_C::getHostMemAddr(BX_CPU_C *cpu, bx_phy_address a20Addr, unsigned
}
}
#if BX_SUPPORT_MONITOR_MWAIT
if (BX_MEM_THIS is_monitor(a20Addr & ~0xfff, 0x1000)) {
// Vetoed! Write monitored page !
if (op != BX_READ) return(NULL);
}
#endif
struct memory_handler_struct *memory_handler = BX_MEM_THIS memory_handlers[a20Addr >> 20];
while (memory_handler) {
if (memory_handler->begin <= a20Addr &&
@ -724,9 +635,9 @@ BX_MEM_C::registerMemoryHandlers(void *param, memory_handler_t read_handler,
memory_handler_t write_handler, bx_phy_address begin_addr, bx_phy_address end_addr)
{
if (end_addr < begin_addr)
return false;
return 0;
if (!read_handler || !write_handler)
return false;
return 0;
BX_INFO(("Register memory access handlers: %08x-%08x", begin_addr, end_addr));
for (unsigned page_idx = begin_addr >> 20; page_idx <= end_addr >> 20; page_idx++) {
struct memory_handler_struct *memory_handler = new struct memory_handler_struct;
@ -738,14 +649,14 @@ BX_MEM_C::registerMemoryHandlers(void *param, memory_handler_t read_handler,
memory_handler->begin = begin_addr;
memory_handler->end = end_addr;
}
return true;
return 1;
}
bx_bool
BX_MEM_C::unregisterMemoryHandlers(memory_handler_t read_handler, memory_handler_t write_handler,
bx_phy_address begin_addr, bx_phy_address end_addr)
{
bx_bool ret = true;
bx_bool ret = 1;
BX_INFO(("Memory access handlers unregistered: %08x-%08x", begin_addr, end_addr));
for (unsigned page_idx = begin_addr >> 20; page_idx <= end_addr >> 20; page_idx++) {
struct memory_handler_struct *memory_handler = BX_MEM_THIS memory_handlers[page_idx];
@ -760,7 +671,7 @@ BX_MEM_C::unregisterMemoryHandlers(memory_handler_t read_handler, memory_handler
memory_handler = memory_handler->next;
}
if (!memory_handler) {
ret = false; // we should have found it
ret = 0; // we should have found it
continue; // anyway, try the other pages
}
if (prev)
@ -792,3 +703,57 @@ bx_bool BX_MEM_C::is_smram_accessible(void)
return(BX_MEM_THIS smram_available) &&
(BX_MEM_THIS smram_enable || !BX_MEM_THIS smram_restricted);
}
#if BX_SUPPORT_MONITOR_MWAIT
//
// MONITOR/MWAIT - x86arch way to optimize idle loops in CPU
//
void BX_MEM_C::set_monitor(unsigned cpu)
{
BX_ASSERT(cpu < BX_SMP_PROCESSORS);
if (! BX_MEM_THIS monitor_active[cpu]) {
BX_MEM_THIS monitor_active[cpu] = 1;
BX_MEM_THIS n_monitors++;
BX_DEBUG(("activate monitor for cpu=%d", cpu));
}
else {
BX_DEBUG(("monitor for cpu=%d already active !", cpu));
}
}
void BX_MEM_C::clear_monitor(unsigned cpu)
{
BX_ASSERT(cpu < BX_SMP_PROCESSORS);
BX_MEM_THIS monitor_active[cpu] = 0;
BX_MEM_THIS n_monitors--;
BX_DEBUG(("deactivate monitor for cpu=%d", cpu));
}
bx_bool BX_MEM_C::is_monitor(bx_phy_address begin_addr, unsigned len)
{
if (BX_MEM_THIS n_monitors == 0) return 0;
for (int i=0; i<BX_SMP_PROCESSORS;i++) {
if (BX_MEM_THIS monitor_active[i]) {
if (BX_CPU(i)->is_monitor(begin_addr, len))
return 1;
}
}
return 0; // // this is NOT monitored page
}
void BX_MEM_C::check_monitor(bx_phy_address begin_addr, unsigned len)
{
if (BX_MEM_THIS n_monitors == 0) return;
for (int i=0; i<BX_SMP_PROCESSORS;i++) {
if (BX_MEM_THIS monitor_active[i]) {
BX_CPU(i)->check_monitor(begin_addr, len);
}
}
}
#endif

View File

@ -1,5 +1,5 @@
/////////////////////////////////////////////////////////////////////////
// $Id: pc_system.cc,v 1.67 2007-09-28 19:51:42 sshwarts Exp $
// $Id: pc_system.cc,v 1.68 2007-11-01 18:03:48 sshwarts Exp $
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2002 MandrakeSoft S.A.
@ -187,6 +187,12 @@ void bx_pc_system_c::MemoryMappingChanged(void)
BX_CPU(i)->TLB_flush(1);
}
void bx_pc_system_c::invlpg(bx_address addr)
{
for (unsigned i=0; i<BX_SMP_PROCESSORS; i++)
BX_CPU(i)->TLB_invlpg(addr);
}
int bx_pc_system_c::Reset(unsigned type)
{
// type is BX_RESET_HARDWARE or BX_RESET_SOFTWARE

View File

@ -1,5 +1,5 @@
/////////////////////////////////////////////////////////////////////////
// $Id: pc_system.h,v 1.41 2007-09-28 19:51:42 sshwarts Exp $
// $Id: pc_system.h,v 1.42 2007-11-01 18:03:48 sshwarts Exp $
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2004 MandrakeSoft S.A.
@ -156,7 +156,6 @@ public:
// when A20 line is disabled, mask physical memory addresses to:
// 286: 20 bits
// 386: 20 bits
//
Bit32u a20_mask;
volatile bx_bool kill_bochs_request;
@ -175,6 +174,7 @@ public:
void set_enable_a20(bx_bool value);
bx_bool get_enable_a20(void);
void MemoryMappingChanged(void); // flush TLB in all CPUs
void invlpg(bx_address addr); // flush TLB page in all CPUs
void exit(void);
void register_state(void);
};