- apply patch.smp-sync-arb-ids. This patch adds a local APIC behavior

that was missing before, the special "INIT Level Deassert" synchronize
  arbitration ID trick.
This commit is contained in:
Bryce Denney 2002-03-25 01:58:34 +00:00
parent fcd6f99391
commit b8ecf5b118
3 changed files with 55 additions and 160 deletions

View File

@ -1,5 +1,5 @@
/////////////////////////////////////////////////////////////////////////
// $Id: apic.cc,v 1.11 2002-03-23 00:54:37 bdenney Exp $
// $Id: apic.cc,v 1.12 2002-03-25 01:58:34 bdenney Exp $
/////////////////////////////////////////////////////////////////////////
//
#define NEED_CPU_REG_SHORTCUTS 1
@ -22,6 +22,13 @@ bx_generic_apic_c::~bx_generic_apic_c ()
{
}
void
bx_generic_apic_c::set_arb_id (int new_arb_id)
{
// politely ignore it. This gets sent to every APIC, regardless of its
// type.
}
// init is called during RESET and when an INIT message is delivered.
void bx_generic_apic_c::init ()
{
@ -160,8 +167,7 @@ bx_generic_apic_c::deliver (Bit8u dest, Bit8u dest_mode, Bit8u delivery_mode, Bi
Bit32u deliver_bitmask = get_delivery_bitmask (dest, dest_mode);
// mask must include ONLY local APICs, or we will have problems.
if (!deliver_bitmask) {
if (bx_dbg.apic)
BX_INFO(("deliver failed: no APICs in destination bitmask"));
BX_PANIC(("deliver failed for vector %02x: no APICs in destination bitmask", vector));
return false;
}
switch (delivery_mode) {
@ -185,6 +191,10 @@ bx_generic_apic_c::deliver (Bit8u dest, Bit8u dest_mode, Bit8u delivery_mode, Bi
break;
case 5: // INIT
{
// NOTE: special behavior of local apics is handled in
// bx_local_apic_c::deliver.
// normal INIT. initialize the local apics in the delivery mask.
for (int bit=0; bit<APIC_MAX_ID; bit++) {
if (deliver_bitmask & (1<<bit))
apic_index[bit]->init ();
@ -221,6 +231,33 @@ bx_generic_apic_c::deliver (Bit8u dest, Bit8u dest_mode, Bit8u delivery_mode, Bi
return true;
}
Boolean
bx_local_apic_c::deliver (Bit8u dest, Bit8u dest_mode, Bit8u delivery_mode, Bit8u vector, Bit8u polarity, Bit8u trig_mode)
{
// In this function, implement only the behavior that is specific to
// the local apic. For general behavior of all apics, just send it to
// the base class.
if (delivery_mode == 5)
{
int trig_mode = (icr_low >> 15) & 1;
int level = (icr_low >> 14) & 1;
if (level == 0 && trig_mode == 1) {
// special mode in local apic. See "INIT Level Deassert" in the
// Intel Soft. Devel. Guide Vol 3, page 7-34. This magic code
// causes all APICs (regardless of dest address) to set their
// arbitration ID to their APIC ID.
BX_INFO (("INIT with Level&Deassert: synchronize arbitration IDs"));
for (int bit=0; bit<APIC_MAX_ID; bit++) {
if (apic_index[bit])
apic_index[bit]->set_arb_id (apic_index[bit]->get_id ());
}
return true;
}
}
// not any special case behavior, just use generic apic code.
return bx_generic_apic_c::deliver (dest, dest_mode, delivery_mode, vector, polarity, trig_mode);
}
bx_local_apic_c::bx_local_apic_c(BX_CPU_C *mycpu)
: bx_generic_apic_c ()
{
@ -229,6 +266,13 @@ bx_local_apic_c::bx_local_apic_c(BX_CPU_C *mycpu)
hwreset ();
}
void
bx_local_apic_c::set_arb_id (int new_arb_id)
{
BX_DEBUG (("set arbitration ID to %d", new_arb_id));
arb_id = new_arb_id;
}
void
bx_local_apic_c::hwreset ()
{
@ -334,9 +378,11 @@ void bx_local_apic_c::write (Bit32u addr, Bit32u *data, unsigned len)
break;
case 0xd0: // logical destination
log_dest = (*data >> 24) & 0xff;
BX_DEBUG (("set logical destiation to %02x", log_dest));
break;
case 0xe0: // destination format
dest_format = (*data >> 28) & 0xf;
BX_DEBUG (("set destination format to %02x", dest_format));
break;
case 0xf0: // spurious interrupt vector
spurious_vec = (spurious_vec & 0x0f) | (*data & 0x3f0);
@ -645,12 +691,9 @@ Bit8u bx_local_apic_c::get_ppr ()
Bit8u bx_local_apic_c::get_apr ()
{
BX_ERROR (("WARNING: Local APIC Arbitration Priority not implemented, returning 0"));
// should look at TPR, vector of highest priority isr, etc.
return 0;
return arb_id;
}
void
bx_local_apic_c::periodic (Bit32u usec_delta)
{

View File

@ -1,5 +1,5 @@
/////////////////////////////////////////////////////////////////////////
// $Id: cpu.h,v 1.15 2001-10-03 19:53:48 instinc Exp $
// $Id: cpu.h,v 1.16 2002-03-25 01:58:34 bdenney Exp $
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2001 MandrakeSoft S.A.
@ -548,9 +548,10 @@ public:
virtual void trigger_irq (unsigned num, unsigned from);
virtual void untrigger_irq (unsigned num, unsigned from);
virtual Bit32u get_delivery_bitmask (Bit8u dest, Bit8u dest_mode);
Boolean deliver (Bit8u destination, Bit8u dest_mode, Bit8u delivery_mode, Bit8u vector, Bit8u polarity, Bit8u trig_mode);
virtual Boolean deliver (Bit8u destination, Bit8u dest_mode, Bit8u delivery_mode, Bit8u vector, Bit8u polarity, Bit8u trig_mode);
virtual Boolean match_logical_addr (Bit8u address);
virtual bx_apic_type_t get_type ();
virtual void set_arb_id (int newid); // only implemented on local apics
};
class bx_local_apic_c : public bx_generic_apic_c {
@ -612,10 +613,12 @@ public:
virtual Boolean is_local_apic () { return true; }
virtual bx_apic_type_t get_type () { return APIC_TYPE_LOCAL_APIC; }
virtual Bit32u get_delivery_bitmask (Bit8u dest, Bit8u dest_mode);
virtual Boolean deliver (Bit8u destination, Bit8u dest_mode, Bit8u delivery_mode, Bit8u vector, Bit8u polarity, Bit8u trig_mode);
Bit8u get_ppr ();
Bit8u get_apr ();
void periodic (Bit32u usec_delta);
void set_divide_configuration (Bit32u value);
virtual void set_arb_id (int newid);
};
#define APIC_MAX_ID 16

View File

@ -1,151 +0,0 @@
? cpu/Makefile
? cpu/stSVOcJq
? cpu/apic-works.cc
Index: cpu/apic.cc
===================================================================
RCS file: /cvsroot/bochs/bochs/cpu/apic.cc,v
retrieving revision 1.8
diff -u -r1.8 apic.cc
--- cpu/apic.cc 3 Oct 2001 13:10:37 -0000 1.8
+++ cpu/apic.cc 24 Mar 2002 01:14:58 -0000
@@ -22,6 +22,13 @@
{
}
+void
+bx_generic_apic_c::set_arb_id (int new_arb_id)
+{
+ // politely ignore it. This gets sent to every APIC, regardless of its
+ // type.
+}
+
// init is called during RESET and when an INIT message is delivered.
void bx_generic_apic_c::init ()
{
@@ -160,8 +167,7 @@
Bit32u deliver_bitmask = get_delivery_bitmask (dest, dest_mode);
// mask must include ONLY local APICs, or we will have problems.
if (!deliver_bitmask) {
- if (bx_dbg.apic)
- BX_INFO(("deliver failed: no APICs in destination bitmask"));
+ BX_PANIC(("deliver failed for vector %02x: no APICs in destination bitmask", vector));
return false;
}
switch (delivery_mode) {
@@ -185,6 +191,10 @@
break;
case 5: // INIT
{
+ // NOTE: special behavior of local apics is handled in
+ // bx_local_apic_c::deliver.
+
+ // normal INIT. initialize the local apics in the delivery mask.
for (int bit=0; bit<APIC_MAX_ID; bit++) {
if (deliver_bitmask & (1<<bit))
apic_index[bit]->init ();
@@ -221,6 +231,33 @@
return true;
}
+Boolean
+bx_local_apic_c::deliver (Bit8u dest, Bit8u dest_mode, Bit8u delivery_mode, Bit8u vector, Bit8u polarity, Bit8u trig_mode)
+{
+ // In this function, implement only the behavior that is specific to
+ // the local apic. For general behavior of all apics, just send it to
+ // the base class.
+ if (delivery_mode == 5)
+ {
+ int trig_mode = (icr_low >> 15) & 1;
+ int level = (icr_low >> 14) & 1;
+ if (level == 0 && trig_mode == 1) {
+ // special mode in local apic. See "INIT Level Deassert" in the
+ // Intel Soft. Devel. Guide Vol 3, page 7-34. This magic code
+ // causes all APICs (regardless of dest address) to set their
+ // arbitration ID to their APIC ID.
+ BX_INFO (("INIT with Level&Deassert: synchronize arbitration IDs"));
+ for (int bit=0; bit<APIC_MAX_ID; bit++) {
+ if (apic_index[bit])
+ apic_index[bit]->set_arb_id (apic_index[bit]->get_id ());
+ }
+ return true;
+ }
+ }
+ // not any special case behavior, just use generic apic code.
+ return bx_generic_apic_c::deliver (dest, dest_mode, delivery_mode, vector, polarity, trig_mode);
+}
+
bx_local_apic_c::bx_local_apic_c(BX_CPU_C *mycpu)
: bx_generic_apic_c ()
{
@@ -230,6 +267,13 @@
}
void
+bx_local_apic_c::set_arb_id (int new_arb_id)
+{
+ BX_DEBUG (("set arbitration ID to %d", new_arb_id));
+ arb_id = new_arb_id;
+}
+
+void
bx_local_apic_c::hwreset ()
{
/* same as INIT but also sets arbitration ID and APIC ID */
@@ -338,9 +382,11 @@
break;
case 0xd0: // logical destination
log_dest = (*data >> 24) & 0xff;
+ BX_DEBUG (("set logical destiation to %02x", log_dest));
break;
case 0xe0: // destination format
dest_format = (*data >> 28) & 0xf;
+ BX_DEBUG (("set destination format to %02x", dest_format));
break;
case 0xf0: // spurious interrupt vector
spurious_vec = (spurious_vec & 0x0f) | (*data & 0x3f0);
@@ -653,11 +698,9 @@
Bit8u bx_local_apic_c::get_apr ()
{
- if (bx_dbg.apic)
- BX_INFO(("WARNING: Local APIC Arbitration Priority not implemented, returning 0"));
- // should look at TPR, vector of highest priority isr, etc.
- return 0;
+ return arb_id;
}
+
void
Index: cpu/cpu.h
===================================================================
RCS file: /cvsroot/bochs/bochs/cpu/cpu.h,v
retrieving revision 1.15
diff -u -r1.15 cpu.h
--- cpu/cpu.h 3 Oct 2001 19:53:48 -0000 1.15
+++ cpu/cpu.h 24 Mar 2002 01:15:01 -0000
@@ -548,9 +548,10 @@
virtual void trigger_irq (unsigned num, unsigned from);
virtual void untrigger_irq (unsigned num, unsigned from);
virtual Bit32u get_delivery_bitmask (Bit8u dest, Bit8u dest_mode);
- Boolean deliver (Bit8u destination, Bit8u dest_mode, Bit8u delivery_mode, Bit8u vector, Bit8u polarity, Bit8u trig_mode);
+ virtual Boolean deliver (Bit8u destination, Bit8u dest_mode, Bit8u delivery_mode, Bit8u vector, Bit8u polarity, Bit8u trig_mode);
virtual Boolean match_logical_addr (Bit8u address);
virtual bx_apic_type_t get_type ();
+ virtual void set_arb_id (int newid); // only implemented on local apics
};
class bx_local_apic_c : public bx_generic_apic_c {
@@ -612,10 +613,12 @@
virtual Boolean is_local_apic () { return true; }
virtual bx_apic_type_t get_type () { return APIC_TYPE_LOCAL_APIC; }
virtual Bit32u get_delivery_bitmask (Bit8u dest, Bit8u dest_mode);
+ virtual Boolean deliver (Bit8u destination, Bit8u dest_mode, Bit8u delivery_mode, Bit8u vector, Bit8u polarity, Bit8u trig_mode);
Bit8u get_ppr ();
Bit8u get_apr ();
void periodic (Bit32u usec_delta);
void set_divide_configuration (Bit32u value);
+ virtual void set_arb_id (int newid);
};
#define APIC_MAX_ID 16