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:
Peter Tattam 2002-10-05 10:25:31 +00:00
parent 4bdd5acaeb
commit db0a37824c
3 changed files with 27 additions and 20 deletions

View File

@ -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 #define NEED_CPU_REG_SHORTCUTS 1
@ -280,6 +280,7 @@ bx_local_apic_c::bx_local_apic_c(BX_CPU_C *mycpu)
{ {
cpu = mycpu; cpu = mycpu;
hwreset (); hwreset ();
INTR = 0;
} }
void void
@ -626,7 +627,7 @@ void bx_local_apic_c::service_local_apic ()
BX_INFO(("service_local_apic()")); BX_INFO(("service_local_apic()"));
print_status (); print_status ();
} }
if (cpu->INTR) return; // INTR already up; do nothing if (INTR) return; // INTR already up; do nothing
// find first interrupt in irr. // find first interrupt in irr.
int first_irr = highest_priority_int (irr); int first_irr = highest_priority_int (irr);
int first_isr = highest_priority_int (isr); 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 // acknowledges, we will run highest_priority_int again and
// return it. // return it.
BX_DEBUG(("service_local_apic(): setting INTR=1 for vector 0x%02x", first_irr)); BX_DEBUG(("service_local_apic(): setting INTR=1 for vector 0x%02x", first_irr));
cpu->set_INTR (1); INTR = 1;
cpu->int_from_local_apic = 1; cpu->async_event = 1;
} }
void bx_local_apic_c::trigger_irq (unsigned vector, unsigned from) void bx_local_apic_c::trigger_irq (unsigned vector, unsigned from)
@ -665,9 +666,9 @@ Bit8u
bx_local_apic_c::acknowledge_int () bx_local_apic_c::acknowledge_int ()
{ {
// CPU calls this when it is ready to service one interrupt // 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_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); int vector = highest_priority_int (irr);
BX_ASSERT (irr[vector] == 1); BX_ASSERT (irr[vector] == 1);
BX_DEBUG(("%s: acknowledge_int returning vector 0x%x", cpu->name, vector)); 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:")); BX_INFO(("Status after setting isr:"));
print_status (); print_status ();
} }
cpu->set_INTR (0); INTR = 0;
cpu->int_from_local_apic = 0; cpu->async_event = 1;
service_local_apic (); // will set INTR again if another is ready service_local_apic (); // will set INTR again if another is ready
return vector; return vector;
} }

View File

@ -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. // Copyright (C) 2001 MandrakeSoft S.A.
@ -500,7 +500,7 @@ BX_CPU_C::handleAsyncEvent(void)
while (1) while (1)
#endif #endif
{ {
if (BX_CPU_THIS_PTR INTR && BX_CPU_THIS_PTR get_IF ()) { if (BX_CPU_INTR && BX_CPU_THIS_PTR get_IF ()) {
break; break;
} }
if (BX_CPU_THIS_PTR async_event == 0) { 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 // must give the others a chance to simulate. If an interrupt has
// arrived, then clear the HALT condition; otherwise just return from // arrived, then clear the HALT condition; otherwise just return from
// the CPU loop with stop_reason STOP_CPU_HALTED. // 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 // interrupt ends the HALT condition
BX_CPU_THIS_PTR debug_trap = 0; // clear traps for after resume BX_CPU_THIS_PTR debug_trap = 0; // clear traps for after resume
BX_CPU_THIS_PTR inhibit_mask = 0; // clear inhibits 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 // an opportunity to check interrupts on the next instruction
// boundary. // 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) { BX_DBG_ASYNC_INTR) {
Bit8u vector; Bit8u vector;
// NOTE: similar code in ::take_irq() // NOTE: similar code in ::take_irq()
#if BX_SUPPORT_APIC #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 (); vector = BX_CPU_THIS_PTR local_apic.acknowledge_int ();
else else
vector = BX_IAC(); // may set INTR with next interrupt 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. // will be processed on the next boundary.
BX_CPU_THIS_PTR inhibit_mask = 0; BX_CPU_THIS_PTR inhibit_mask = 0;
if ( !(BX_CPU_THIS_PTR INTR || if ( !(BX_CPU_INTR ||
BX_CPU_THIS_PTR debug_trap || BX_CPU_THIS_PTR debug_trap ||
BX_HRQ || BX_HRQ ||
BX_CPU_THIS_PTR get_TF ()) ) BX_CPU_THIS_PTR get_TF ()) )
@ -1015,7 +1015,7 @@ BX_CPU_C::dbg_take_irq(void)
// NOTE: similar code in ::cpu_loop() // 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 ) { if ( setjmp(BX_CPU_THIS_PTR jmp_buf_env) == 0 ) {
// normal return from setjmp setup // normal return from setjmp setup
vector = BX_IAC(); // may set INTR with next interrupt vector = BX_IAC(); // may set INTR with next interrupt

View File

@ -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. // Copyright (C) 2001 MandrakeSoft S.A.
@ -328,6 +328,12 @@ typedef Bit32u bx_address;
#define BX_MODE_LONG_COMPAT 0x1 #define BX_MODE_LONG_COMPAT 0x1
#define BX_MODE_LONG_64 0x2 #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; class BX_CPU_C;
#if BX_USE_CPU_SMF == 0 #if BX_USE_CPU_SMF == 0
@ -1236,6 +1242,7 @@ class bx_local_apic_c : public bx_generic_apic_c {
Bit64u ticksInitial; // System ticks count when APIC timer is started. Bit64u ticksInitial; // System ticks count when APIC timer is started.
public: public:
Boolean INTR;
bx_local_apic_c(BX_CPU_C *mycpu); bx_local_apic_c(BX_CPU_C *mycpu);
virtual ~bx_local_apic_c(void); virtual ~bx_local_apic_c(void);
BX_CPU_C *cpu; BX_CPU_C *cpu;
@ -2654,7 +2661,6 @@ union {
BX_SMF BX_CPP_INLINE Boolean v8086_mode(void); BX_SMF BX_CPP_INLINE Boolean v8086_mode(void);
#if BX_SUPPORT_APIC #if BX_SUPPORT_APIC
bx_local_apic_c local_apic; bx_local_apic_c local_apic;
Boolean int_from_local_apic;
#endif #endif
}; };