Fixes for DR6 handling

This commit is contained in:
Stanislav Shwartsman 2009-02-01 20:47:06 +00:00
parent b7f10117a9
commit 2378d31998
7 changed files with 60 additions and 37 deletions

View File

@ -1,5 +1,5 @@
/////////////////////////////////////////////////////////////////////////
// $Id: cpu.cc,v 1.264 2009-01-31 11:53:57 sshwarts Exp $
// $Id: cpu.cc,v 1.265 2009-02-01 20:47:06 sshwarts Exp $
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2001 MandrakeSoft S.A.
@ -485,10 +485,8 @@ unsigned BX_CPU_C::handleAsyncEvent(void)
// Priority 2: Trap on Task Switch
// T flag in TSS is set
if (BX_CPU_THIS_PTR debug_trap & 0x00008000) {
BX_CPU_THIS_PTR dr6 |= BX_CPU_THIS_PTR debug_trap;
if (BX_CPU_THIS_PTR debug_trap & BX_DEBUG_TRAP_TASK_SWITCH_BIT)
exception(BX_DB_EXCEPTION, 0, 0); // no error, not interrupt
}
// Priority 3: External Hardware Interventions
// FLUSH
@ -514,7 +512,6 @@ unsigned BX_CPU_C::handleAsyncEvent(void)
// which loaded SS. If so we clear the inhibit_mask below
// and don't execute this code until the next boundary.
// Commit debug events to DR6
BX_CPU_THIS_PTR dr6 |= BX_CPU_THIS_PTR debug_trap;
exception(BX_DB_EXCEPTION, 0, 0); // no error, not interrupt
}
@ -614,7 +611,7 @@ unsigned BX_CPU_C::handleAsyncEvent(void)
// TF is set before execution of next instruction. Schedule
// a debug trap (#DB) after execution. After completion of
// next instruction, the code above will invoke the trap.
BX_CPU_THIS_PTR debug_trap |= 0x00004000; // BS flag in DR6
BX_CPU_THIS_PTR debug_trap |= BX_DEBUG_SINGLE_STEP_BIT;
}
// Now we can handle things which are synchronous to instruction
@ -628,27 +625,14 @@ unsigned BX_CPU_C::handleAsyncEvent(void)
if (BX_CPU_THIS_PTR dr7 & 0x000000ff) {
bx_address iaddr = get_laddr(BX_SEG_REG_CS, BX_CPU_THIS_PTR prev_rip);
Bit32u dr6_bits = hwdebug_compare(iaddr, 1, BX_HWDebugInstruction, BX_HWDebugInstruction);
if (dr6_bits)
{
if (dr6_bits) {
// Add to the list of debug events thus far.
BX_CPU_THIS_PTR async_event = 1;
BX_CPU_THIS_PTR debug_trap |= dr6_bits;
// If debug events are not inhibited on this boundary,
// fire off a debug fault. Otherwise handle it on the next
// boundary. (becomes a trap)
if (! (BX_CPU_THIS_PTR inhibit_mask & BX_INHIBIT_DEBUG)) {
// Commit debug events to DR6
#if BX_CPU_LEVEL <= 4
// On 386/486 bit12 is settable
BX_CPU_THIS_PTR dr6 = (BX_CPU_THIS_PTR dr6 & 0xffff0ff0) |
(BX_CPU_THIS_PTR debug_trap & 0x0000f00f);
#else
// On Pentium+, bit12 is always zero
BX_CPU_THIS_PTR dr6 = (BX_CPU_THIS_PTR dr6 & 0xffff0ff0) |
(BX_CPU_THIS_PTR debug_trap & 0x0000e00f);
#endif
if (! (BX_CPU_THIS_PTR inhibit_mask & BX_INHIBIT_DEBUG))
exception(BX_DB_EXCEPTION, 0, 0); // no error, not interrupt
}
}
}
}

View File

@ -1,5 +1,5 @@
/////////////////////////////////////////////////////////////////////////
// $Id: cpu.h,v 1.565 2009-01-31 10:43:23 sshwarts Exp $
// $Id: cpu.h,v 1.566 2009-02-01 20:47:06 sshwarts Exp $
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2001 MandrakeSoft S.A.
@ -942,7 +942,11 @@ public: // for now...
#define BX_ACTIVITY_STATE_MWAIT_IF (5)
unsigned activity_state;
#define BX_DEBUG_DR_ACCESS_BIT (1 << 13)
#define BX_DEBUG_SINGLE_STEP_BIT (1 << 14)
#define BX_DEBUG_TRAP_TASK_SWITCH_BIT (1 << 15)
Bit32u debug_trap; // holds DR6 value (16bit) to be set as well
volatile Bit32u async_event;
#if BX_SUPPORT_TRACE_CACHE

View File

@ -1,5 +1,5 @@
/////////////////////////////////////////////////////////////////////////
// $Id: exception.cc,v 1.134 2009-01-31 10:43:23 sshwarts Exp $
// $Id: exception.cc,v 1.135 2009-02-01 20:47:06 sshwarts Exp $
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2001 MandrakeSoft S.A.
@ -942,9 +942,20 @@ void BX_CPU_C::exception(unsigned vector, Bit16u error_code, unsigned unused)
if (vector != BX_DB_EXCEPTION) BX_CPU_THIS_PTR assert_RF();
}
// clear GD flag in the DR7 prior entering debug exception handler
if (vector == BX_DB_EXCEPTION)
if (vector == BX_DB_EXCEPTION) {
// Commit debug events to DR6
#if BX_CPU_LEVEL <= 4
// On 386/486 bit12 is settable
BX_CPU_THIS_PTR dr6 = (BX_CPU_THIS_PTR dr6 & 0xffff0ff0) |
(BX_CPU_THIS_PTR debug_trap & 0x0000f00f);
#else
// On Pentium+, bit12 is always zero
BX_CPU_THIS_PTR dr6 = (BX_CPU_THIS_PTR dr6 & 0xffff0ff0) |
(BX_CPU_THIS_PTR debug_trap & 0x0000e00f);
#endif
// clear GD flag in the DR7 prior entering debug exception handler
BX_CPU_THIS_PTR dr7 &= ~0x00002000;
}
BX_CPU_THIS_PTR EXT = 1;

View File

@ -1,5 +1,5 @@
/////////////////////////////////////////////////////////////////////////
// $Id: proc_ctrl.cc,v 1.279 2009-01-31 10:43:23 sshwarts Exp $
// $Id: proc_ctrl.cc,v 1.280 2009-02-01 20:47:06 sshwarts Exp $
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2001 MandrakeSoft S.A.
@ -276,7 +276,7 @@ void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOV_DdRd(bxInstruction_c *i)
// handler, to allow access to the debug registers
if (BX_CPU_THIS_PTR dr7 & 0x2000) { // GD bit set
BX_ERROR(("MOV_DdRd: DR7 GD bit is set"));
BX_CPU_THIS_PTR dr6 |= 0x2000;
BX_CPU_THIS_PTR debug_trap |= BX_DEBUG_DR_ACCESS_BIT;
exception(BX_DB_EXCEPTION, 0, 0);
}
@ -383,7 +383,7 @@ void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOV_RdDd(bxInstruction_c *i)
// handler, to allow access to the debug registers
if (BX_CPU_THIS_PTR dr7 & 0x2000) { // GD bit set
BX_ERROR(("MOV_RdDd: DR7 GD bit is set"));
BX_CPU_THIS_PTR dr6 |= 0x2000;
BX_CPU_THIS_PTR debug_trap |= BX_DEBUG_DR_ACCESS_BIT;
exception(BX_DB_EXCEPTION, 0, 0);
}
@ -452,7 +452,7 @@ void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOV_DqRq(bxInstruction_c *i)
// handler, to allow access to the debug registers
if (BX_CPU_THIS_PTR dr7 & 0x2000) { // GD bit set
BX_ERROR(("MOV_DqRq: DR7 GD bit is set"));
BX_CPU_THIS_PTR dr6 |= 0x2000;
BX_CPU_THIS_PTR debug_trap |= BX_DEBUG_DR_ACCESS_BIT;
exception(BX_DB_EXCEPTION, 0, 0);
}
@ -485,6 +485,10 @@ void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOV_DqRq(bxInstruction_c *i)
// DR4 aliased to DR6 by default. With Debug Extensions ON,
// access to DR4 causes #UD
case 6: // DR6
if (GET32H(val_64)) {
BX_ERROR(("MOV_DqRq: attempt to set upper part of DR6"));
exception(BX_GP_EXCEPTION, 0, 0);
}
// On Pentium+, bit12 is always zero
BX_CPU_THIS_PTR dr6 = (BX_CPU_THIS_PTR dr6 & 0xffff0ff0) |
(val_64 & 0x0000e00f);
@ -498,6 +502,11 @@ void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOV_DqRq(bxInstruction_c *i)
// data breakpoint matching does not occur unless it is enabled
// by setting the LE and/or GE flags.
if (GET32H(val_64)) {
BX_ERROR(("MOV_DqRq: attempt to set upper part of DR7"));
exception(BX_GP_EXCEPTION, 0, 0);
}
// Some sanity checks...
if (((((val_64>>16) & 3)==0) && (((val_64>>18) & 3)!=0)) ||
((((val_64>>20) & 3)==0) && (((val_64>>22) & 3)!=0)) ||
@ -539,7 +548,7 @@ void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOV_RqDq(bxInstruction_c *i)
// handler, to allow access to the debug registers
if (BX_CPU_THIS_PTR dr7 & 0x2000) { // GD bit set
BX_ERROR(("MOV_RqDq: DR7 GD bit is set"));
BX_CPU_THIS_PTR dr6 |= 0x2000;
BX_CPU_THIS_PTR debug_trap |= BX_DEBUG_DR_ACCESS_BIT;
exception(BX_DB_EXCEPTION, 0, 0);
}

View File

@ -1,5 +1,5 @@
/////////////////////////////////////////////////////////////////////////
// $Id: tasking.cc,v 1.67 2009-01-31 10:43:23 sshwarts Exp $
// $Id: tasking.cc,v 1.68 2009-02-01 20:47:06 sshwarts Exp $
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2001 MandrakeSoft S.A.
@ -653,7 +653,7 @@ void BX_CPU_C::task_switch(bxInstruction_c *i, bx_selector_t *tss_selector,
if ((tss_descriptor->type>=9) && (trap_word & 0x1)) {
BX_CPU_THIS_PTR debug_trap |= 0x00008000; // BT flag in DR6
BX_CPU_THIS_PTR debug_trap |= BX_DEBUG_TRAP_TASK_SWITCH_BIT; // BT flag
BX_CPU_THIS_PTR async_event = 1; // so processor knows to check
BX_INFO(("task_switch: T bit set in new TSS"));
}

View File

@ -1,5 +1,5 @@
/////////////////////////////////////////////////////////////////////////
// $Id: vmx.cc,v 1.1 2009-01-31 10:43:24 sshwarts Exp $
// $Id: vmx.cc,v 1.2 2009-02-01 20:47:06 sshwarts Exp $
/////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2009 Stanislav Shwartsman
@ -1046,10 +1046,15 @@ Bit32u BX_CPU_C::VMenterLoadCheckGuestState(Bit64u *qualification)
}
}
guest.activity_state = VMread32(VMCS_32BIT_GUEST_ACTIVITY_STATE);
guest.interruptibility_state = VMread32(VMCS_32BIT_GUEST_INTERRUPTIBILITY_STATE);
guest.tmpDR6 = VMread64(VMCS_GUEST_PENDING_DBG_EXCEPTIONS);
if (guest.tmpDR6 & BX_CONST64(0xFFFFFFFFFFFF5FF0)) {
BX_ERROR(("VMENTER FAIL: VMCS guest tmpDR6 reserved bits"));
return VMX_VMEXIT_VMENTRY_FAILURE_GUEST_STATE;
}
guest.activity_state = VMread32(VMCS_32BIT_GUEST_ACTIVITY_STATE);
if (guest.activity_state >= BX_VMX_LAST_ACTIVITY_STATE) {
BX_ERROR(("VMENTER FAIL: VMCS guest activity state %d", guest.activity_state));
return VMX_VMEXIT_VMENTRY_FAILURE_GUEST_STATE;
@ -1062,6 +1067,8 @@ Bit32u BX_CPU_C::VMenterLoadCheckGuestState(Bit64u *qualification)
}
}
guest.interruptibility_state = VMread32(VMCS_32BIT_GUEST_INTERRUPTIBILITY_STATE);
if (guest.interruptibility_state & ~BX_VMX_INTERRUPTIBILITY_STATE_MASK) {
BX_ERROR(("VMENTER FAIL: VMCS guest interruptibility state broken"));
return VMX_VMEXIT_VMENTRY_FAILURE_GUEST_STATE;
@ -1314,10 +1321,13 @@ Bit32u BX_CPU_C::StoreMSRs(Bit32u msr_cnt, bx_phy_address pAddr)
void BX_CPU_C::VMexitSaveGuestState(void)
{
VMCS_CACHE *vm = &BX_CPU_THIS_PTR vmcs;
VMwrite64(VMCS_GUEST_CR0, BX_CPU_THIS_PTR cr0.get32());
VMwrite64(VMCS_GUEST_CR3, BX_CPU_THIS_PTR cr3);
VMwrite64(VMCS_GUEST_CR4, BX_CPU_THIS_PTR cr4.get32());
VMwrite64(VMCS_GUEST_DR7, BX_CPU_THIS_PTR dr7);
if (vm->vmexit_ctrls & VMX_VMEXIT_CTRL1_SAVE_DBG_CTRLS)
VMwrite64(VMCS_GUEST_DR7, BX_CPU_THIS_PTR dr7);
VMwrite64(VMCS_GUEST_RIP, RIP);
VMwrite64(VMCS_GUEST_RSP, RSP);
VMwrite64(VMCS_GUEST_RFLAGS, BX_CPU_THIS_PTR read_eflags());
@ -1368,6 +1378,10 @@ void BX_CPU_C::VMexitSaveGuestState(void)
VMwrite64(VMCS_GUEST_IA32_SYSENTER_EIP_MSR, BX_CPU_THIS_PTR msr.sysenter_eip_msr);
VMwrite32(VMCS_32BIT_GUEST_IA32_SYSENTER_CS_MSR, BX_CPU_THIS_PTR msr.sysenter_cs_msr);
Bit32u tmpDR6 = BX_CPU_THIS_PTR debug_trap;
if (tmpDR6 & 0xf) tmpDR6 |= (1 << 12);
VMwrite64(VMCS_GUEST_PENDING_DBG_EXCEPTIONS, tmpDR6 & 0x0000500f);
Bit32u interruptibility_state = 0;
if (BX_CPU_THIS_PTR inhibit_mask & BX_INHIBIT_INTERRUPTS) {
if (BX_CPU_THIS_PTR inhibit_mask & BX_INHIBIT_DEBUG)

View File

@ -1,5 +1,5 @@
/////////////////////////////////////////////////////////////////////////
// $Id: main.cc,v 1.391 2009-01-16 18:18:57 sshwarts Exp $
// $Id: main.cc,v 1.392 2009-02-01 20:47:06 sshwarts Exp $
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2002 MandrakeSoft S.A.
@ -1024,6 +1024,7 @@ void bx_init_hardware()
BX_INFO((" MWAIT support: %s",BX_SUPPORT_MONITOR_MWAIT?"yes":"no"));
BX_INFO((" XSAVE support: %s",BX_SUPPORT_XSAVE?"yes":"no"));
BX_INFO((" AES support: %s",BX_SUPPORT_AES?"yes":"no"));
BX_INFO((" VMX support: %s",BX_SUPPORT_VMX?"yes":"no"));
BX_INFO(("Optimization configuration"));
BX_INFO((" RepeatSpeedups support: %s",BX_SupportRepeatSpeedups?"yes":"no"));
BX_INFO((" Icache support: %s",BX_SUPPORT_ICACHE?"yes":"no"));