Fixed elusive APIC interrupt problems when bochs compiled for P6 or later.
Symptom: Linux kernel 2.4.19 would hang in random places. CPU still running, but in dle loop. Cause: if APIC interrupt occurred while a PIC interrupt was pending, the PIC interrupt would be lost. This is because either an APIC or PIC interrupt would trash any pending interrupt event because INTR is only a state, not an event queue. Temporary fix: reworked apic.cc to have it's own copy of INTR state. cpu.cc now checks for both cpu.INTR and local_apic.INTR. Need to do further research to see if local_apic and pic can be integrated in such a way as properly manage the combined effects of both devices accessing INTR state.
This commit is contained in:
parent
4bdd5acaeb
commit
db0a37824c
@ -1,5 +1,5 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id: apic.cc,v 1.22 2002-10-04 17:04:31 kevinlawton Exp $
|
||||
// $Id: apic.cc,v 1.23 2002-10-05 10:25:30 ptrumpet Exp $
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
#define NEED_CPU_REG_SHORTCUTS 1
|
||||
@ -10,7 +10,7 @@
|
||||
bx_generic_apic_c *apic_index[APIC_MAX_ID];
|
||||
|
||||
|
||||
bx_generic_apic_c::bx_generic_apic_c ()
|
||||
bx_generic_apic_c::bx_generic_apic_c ()
|
||||
{
|
||||
id = APIC_UNKNOWN_ID;
|
||||
put("APIC?");
|
||||
@ -280,6 +280,7 @@ bx_local_apic_c::bx_local_apic_c(BX_CPU_C *mycpu)
|
||||
{
|
||||
cpu = mycpu;
|
||||
hwreset ();
|
||||
INTR = 0;
|
||||
}
|
||||
|
||||
void
|
||||
@ -626,7 +627,7 @@ void bx_local_apic_c::service_local_apic ()
|
||||
BX_INFO(("service_local_apic()"));
|
||||
print_status ();
|
||||
}
|
||||
if (cpu->INTR) return; // INTR already up; do nothing
|
||||
if (INTR) return; // INTR already up; do nothing
|
||||
// find first interrupt in irr.
|
||||
int first_irr = highest_priority_int (irr);
|
||||
int first_isr = highest_priority_int (isr);
|
||||
@ -640,8 +641,8 @@ void bx_local_apic_c::service_local_apic ()
|
||||
// acknowledges, we will run highest_priority_int again and
|
||||
// return it.
|
||||
BX_DEBUG(("service_local_apic(): setting INTR=1 for vector 0x%02x", first_irr));
|
||||
cpu->set_INTR (1);
|
||||
cpu->int_from_local_apic = 1;
|
||||
INTR = 1;
|
||||
cpu->async_event = 1;
|
||||
}
|
||||
|
||||
void bx_local_apic_c::trigger_irq (unsigned vector, unsigned from)
|
||||
@ -665,9 +666,9 @@ Bit8u
|
||||
bx_local_apic_c::acknowledge_int ()
|
||||
{
|
||||
// CPU calls this when it is ready to service one interrupt
|
||||
if (!cpu->INTR)
|
||||
if (!INTR)
|
||||
BX_PANIC(("%s: acknowledged an interrupt, but INTR=0", cpu->name));
|
||||
BX_ASSERT (cpu->int_from_local_apic);
|
||||
BX_ASSERT (INTR);
|
||||
int vector = highest_priority_int (irr);
|
||||
BX_ASSERT (irr[vector] == 1);
|
||||
BX_DEBUG(("%s: acknowledge_int returning vector 0x%x", cpu->name, vector));
|
||||
@ -679,8 +680,8 @@ bx_local_apic_c::acknowledge_int ()
|
||||
BX_INFO(("Status after setting isr:"));
|
||||
print_status ();
|
||||
}
|
||||
cpu->set_INTR (0);
|
||||
cpu->int_from_local_apic = 0;
|
||||
INTR = 0;
|
||||
cpu->async_event = 1;
|
||||
service_local_apic (); // will set INTR again if another is ready
|
||||
return vector;
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id: cpu.cc,v 1.61 2002-10-04 17:04:31 kevinlawton Exp $
|
||||
// $Id: cpu.cc,v 1.62 2002-10-05 10:25:30 ptrumpet Exp $
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2001 MandrakeSoft S.A.
|
||||
@ -500,7 +500,7 @@ BX_CPU_C::handleAsyncEvent(void)
|
||||
while (1)
|
||||
#endif
|
||||
{
|
||||
if (BX_CPU_THIS_PTR INTR && BX_CPU_THIS_PTR get_IF ()) {
|
||||
if (BX_CPU_INTR && BX_CPU_THIS_PTR get_IF ()) {
|
||||
break;
|
||||
}
|
||||
if (BX_CPU_THIS_PTR async_event == 0) {
|
||||
@ -514,7 +514,7 @@ 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_THIS_PTR INTR && BX_CPU_THIS_PTR get_IF ()) {
|
||||
if (BX_CPU_INTR && BX_CPU_THIS_PTR get_IF ()) {
|
||||
// interrupt ends the HALT condition
|
||||
BX_CPU_THIS_PTR debug_trap = 0; // clear traps for after resume
|
||||
BX_CPU_THIS_PTR inhibit_mask = 0; // clear inhibits for after resume
|
||||
@ -575,13 +575,13 @@ BX_CPU_C::handleAsyncEvent(void)
|
||||
// an opportunity to check interrupts on the next instruction
|
||||
// boundary.
|
||||
}
|
||||
else if (BX_CPU_THIS_PTR INTR && BX_CPU_THIS_PTR get_IF () &&
|
||||
else if (BX_CPU_INTR && BX_CPU_THIS_PTR get_IF () &&
|
||||
BX_DBG_ASYNC_INTR) {
|
||||
Bit8u vector;
|
||||
|
||||
// NOTE: similar code in ::take_irq()
|
||||
#if BX_SUPPORT_APIC
|
||||
if (BX_CPU_THIS_PTR int_from_local_apic)
|
||||
if (BX_CPU_THIS_PTR local_apic.INTR)
|
||||
vector = BX_CPU_THIS_PTR local_apic.acknowledge_int ();
|
||||
else
|
||||
vector = BX_IAC(); // may set INTR with next interrupt
|
||||
@ -680,7 +680,7 @@ BX_CPU_C::handleAsyncEvent(void)
|
||||
// will be processed on the next boundary.
|
||||
BX_CPU_THIS_PTR inhibit_mask = 0;
|
||||
|
||||
if ( !(BX_CPU_THIS_PTR INTR ||
|
||||
if ( !(BX_CPU_INTR ||
|
||||
BX_CPU_THIS_PTR debug_trap ||
|
||||
BX_HRQ ||
|
||||
BX_CPU_THIS_PTR get_TF ()) )
|
||||
@ -1015,7 +1015,7 @@ BX_CPU_C::dbg_take_irq(void)
|
||||
|
||||
// NOTE: similar code in ::cpu_loop()
|
||||
|
||||
if ( BX_CPU_THIS_PTR INTR && BX_CPU_THIS_PTR get_IF () ) {
|
||||
if ( BX_CPU_INTR && BX_CPU_THIS_PTR get_IF () ) {
|
||||
if ( setjmp(BX_CPU_THIS_PTR jmp_buf_env) == 0 ) {
|
||||
// normal return from setjmp setup
|
||||
vector = BX_IAC(); // may set INTR with next interrupt
|
||||
|
@ -1,5 +1,5 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id: cpu.h,v 1.96 2002-10-05 06:33:10 kevinlawton Exp $
|
||||
// $Id: cpu.h,v 1.97 2002-10-05 10:25:31 ptrumpet Exp $
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2001 MandrakeSoft S.A.
|
||||
@ -328,11 +328,17 @@ typedef Bit32u bx_address;
|
||||
#define BX_MODE_LONG_COMPAT 0x1
|
||||
#define BX_MODE_LONG_64 0x2
|
||||
|
||||
#if BX_SUPPORT_APIC
|
||||
#define BX_CPU_INTR (BX_CPU_THIS_PTR INTR || BX_CPU_THIS_PTR local_apic.INTR)
|
||||
#else
|
||||
#define BX_CPU_INTR BX_CPU_THIS_PTR INTR
|
||||
#endif
|
||||
|
||||
class BX_CPU_C;
|
||||
|
||||
#if BX_USE_CPU_SMF == 0
|
||||
// normal member functions. This can ONLY be used within BX_CPU_C classes.
|
||||
// Anyone on the outside should use the BX_CPU macro (defined in bochs.h)
|
||||
// Anyone on the outside should use the BX_CPU macro (defined in bochs.h)
|
||||
// instead.
|
||||
# define BX_CPU_THIS_PTR this->
|
||||
# define BX_CPU_THIS this
|
||||
@ -1209,7 +1215,7 @@ class bx_local_apic_c : public bx_generic_apic_c {
|
||||
// cleared when the interrupt is acknowledged by the processor.
|
||||
Bit8u irr[BX_LOCAL_APIC_MAX_INTS];
|
||||
// ISR=in-service register. When an IRR bit is cleared, the corresponding
|
||||
// bit in ISR is set. The ISR bit is cleared when
|
||||
// bit in ISR is set. The ISR bit is cleared when
|
||||
Bit8u isr[BX_LOCAL_APIC_MAX_INTS];
|
||||
Bit32u arb_id, arb_priority, task_priority, log_dest, dest_format, spurious_vec;
|
||||
Bit32u lvt[6];
|
||||
@ -1236,6 +1242,7 @@ class bx_local_apic_c : public bx_generic_apic_c {
|
||||
Bit64u ticksInitial; // System ticks count when APIC timer is started.
|
||||
|
||||
public:
|
||||
Boolean INTR;
|
||||
bx_local_apic_c(BX_CPU_C *mycpu);
|
||||
virtual ~bx_local_apic_c(void);
|
||||
BX_CPU_C *cpu;
|
||||
@ -2654,7 +2661,6 @@ union {
|
||||
BX_SMF BX_CPP_INLINE Boolean v8086_mode(void);
|
||||
#if BX_SUPPORT_APIC
|
||||
bx_local_apic_c local_apic;
|
||||
Boolean int_from_local_apic;
|
||||
#endif
|
||||
};
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user