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
@ -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;
}

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.
@ -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

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.
@ -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
};