Bochs/bochs/patches/patch.apic-mrieker
Stanislav Shwartsman 3074078297 Added CVS version header to all the files.
One more small change in APIC
2005-03-19 20:44:01 +00:00

371 lines
13 KiB
Plaintext

----------------------------------------------------------------------
Patch name: patch.apic-mrieker
Author: mrieker
Date: 27 June 2002
1st detailed description:
This a patch found on sf bug list from apparently mrieker :
fixed some stuff in apic code:
- interprocessor nmi's
- lowest priority
- fixed ppr
- can write task_priority
- scan priorities from high to low
2nd detailed description:
more complete apic stuff
fixed a couple things:
- it works on win32 vc 6. vc 6 apparently doesn't
zero mem on a 'new bx_cpu_c' and apic init
functions depended on that
- don't consider apic on a cpu that hasn't been
started yet for a destination bitmask bit
- fix some compile errors in vc 6 complaining
about 'int bit=0'
- implement reading IRR,TMR,ISR registers
Patch was created with:
cvs diff -u
Apply patch to what version:
cvs checked out on 27 June 2002
Instructions:
To patch, go to main bochs directory.
Type "patch -p0 < THIS_PATCH_FILE".
----------------------------------------------------------------------
Index: cpu/apic.cc
===================================================================
RCS file: /cvsroot/bochs/bochs/cpu/apic.cc,v
retrieving revision 1.14
diff -u -r1.14 apic.cc
--- cpu/apic.cc 27 Mar 2002 16:04:04 -0000 1.14
+++ cpu/apic.cc 27 Jun 2002 19:36:17 -0000
@@ -6,6 +6,9 @@
#include "bochs.h"
#include <assert.h>
+#ifdef LOG_THIS
+#undef LOG_THIS
+#endif
#define LOG_THIS this->
bx_generic_apic_c *apic_index[APIC_MAX_ID];
@@ -169,32 +178,51 @@
bx_bool bx_generic_apic_c::deliver (Bit8u dest, Bit8u dest_mode, Bit8u delivery_mode, Bit8u vector, Bit8u polarity, Bit8u trig_mode)
{
// return false if we can't deliver for any reason, so that the caller
// knows not to clear its IRR.
Bit32u deliver_bitmask = get_delivery_bitmask (dest, dest_mode);
// mask must include ONLY local APICs, or we will have problems.
if (!deliver_bitmask) {
BX_PANIC(("deliver failed for vector %02x: no APICs in destination bitmask", vector));
return false;
}
+
switch (delivery_mode) {
case 0: // fixed
break;
case 1: // lowest priority of destinations
{
// find lowest priority of apics in the mask
- int lowest_priority = 0x100, lowest_mask = -1;
- for (int bit=0; bit<APIC_MAX_ID; bit++) {
- if (deliver_bitmask & (1<<bit)) {
- bx_local_apic_c *apic = (bx_local_apic_c *)apic_index[bit];
- if (apic->get_ppr () < lowest_priority) {
- lowest_priority = apic->get_ppr (); lowest_mask = 1<<bit;
+
+ bx_local_apic_c *apic;
+ int bit, bitidx, itsppr, lowest_bit, lowest_mask, lowest_priority;
+ static int lowest_rotate = 0; // hw probably doesn't do this but mix it up for simulation
+
+ lowest_priority = 0x100; // any priority is lower than this
+ lowest_mask = -1; // set all mask bits
+
+ for (bitidx = 0; bitidx < APIC_MAX_ID; bitidx ++) { // loop through all apic's
+ bit = (bitidx + lowest_rotate) % APIC_MAX_ID; // get absolute apic number
+ if (deliver_bitmask & (1 << bit)) { // see if delivery is enabled
+ apic = (bx_local_apic_c *)apic_index[bit]; // ok, point to the apic object
+ if ((apic -> cpu -> eflags.if_) || !(apic -> cpu -> debug_trap & 0x80000000)) { // see if that cpu has been started
+ itsppr = apic -> get_ppr (); // ok, get its process priority
+ itsppr &= 0xF0; // ... ignore lower 4 bits
+ if (itsppr < lowest_priority) { // if it's the lowest so far ...
+ lowest_priority = itsppr; // ... save info
+ lowest_mask = 1 << bit;
+ lowest_bit = bit;
+ }
}
}
}
- deliver_bitmask = lowest_mask;
- BX_ASSERT (deliver_bitmask >= 0);
+ deliver_bitmask = lowest_mask; // save mask bit for lowest found
+ lowest_rotate = (lowest_bit + 1) % APIC_MAX_ID; // remember this for next scan
+ BX_ASSERT (deliver_bitmask >= 0); // we must have found something
}
break;
case 5: // INIT
@@ -210,32 +238,51 @@
}
return true;
case 6: // Start Up (local apic only)
BX_ASSERT (get_type () == APIC_TYPE_LOCAL_APIC);
for (int bit=0; bit<APIC_MAX_ID; bit++)
if (deliver_bitmask & (1<<bit))
apic_index[bit]->startup_msg (vector);
return true;
+ case 4: // NMI
+ {
+ BX_INFO (("APIC NMI deliver_bitmask %X", deliver_bitmask));
+ for (int bit=0; bit<APIC_MAX_ID; bit++) { // loop through all possible APIC's
+ if (deliver_bitmask & (1<<bit)) { // see if this one is to be NMI'd
+ BX_CPU_C *itscpu;
+ itscpu = apic_index[bit] -> get_cpu (); // if so, point to its CPU struct
+ if (itscpu -> eflags.if_ || !(itscpu -> debug_trap & 0x80000000)) { // make sure it's apic has been IPI'd
+ BX_INFO (("APIC NMI bit %u, cpu %s", bit, itscpu -> name)); // ok, NMI its ass
+ itscpu -> nmi_queued = 1;
+ itscpu -> async_event = 1;
+ }
+ }
+ }
+ return true;
+ }
case 2: // SMI
case 3: // reserved
- case 4: // NMI
case 7: // ExtINT (I/O apic only)
default:
BX_PANIC(("APIC delivery mode %d not implemented", delivery_mode));
}
@@ -269,9 +316,9 @@
bx_local_apic_c::bx_local_apic_c(BX_CPU_C *mycpu)
: bx_generic_apic_c ()
{
- char buffer[16];
cpu = mycpu;
- hwreset ();
+ // hwreset (); moved to be called after the 'new' - as on vc++, the struct doesn't
+ // get zeroed so we end up outputting a page of garbage characters
}
void
@@ -369,16 +415,19 @@
break;
case 0x80: // task priority
task_priority = *data & 0xff;
+ service_local_apic ();
+ //print_status ();
break;
case 0xb0: // EOI
{
BX_DEBUG(("%s: Wrote 0x%04x to EOI", cpu->name, *data));
int vec = highest_priority_int (isr);
if (vec < 0) {
- BX_INFO(("EOI written without any bit in ISR"));
+ BX_INFO (("apic write*: %s: EOI written without any bit in ISR", cpu -> name));
} else {
- BX_DEBUG(("%s: local apic received EOI, hopefully for vector 0x%02x", cpu->name, vec));
- isr[vec] = 0;
+ //BX_INFO (("apic write*: %s: EOI %d", cpu -> name, vec));
+ isr[vec] = 0;
+ //print_status ();
service_local_apic ();
}
if (bx_dbg.apic)
@@ -568,30 +628,38 @@
int
bx_local_apic_c::highest_priority_int (Bit8u *array)
{
- for (int i=0; i<BX_LOCAL_APIC_MAX_INTS; i++)
- if (array[i]) return i;
- return -1;
+ int i;
+
+ if (array[2]) return (2); // if NMI, that is the highest priority
+ for (i = 0x100; -- i >= 0;) if (array[i]) break; // all others, scan bits from highest to lowest
+ return (i);
}
void bx_local_apic_c::service_local_apic ()
{
+ int first_irr, ppr;
+
if (bx_dbg.apic) {
BX_INFO(("service_local_apic()"));
print_status ();
}
if (cpu->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);
+
+ first_irr = highest_priority_int (irr); // find highest vector being requested
+ ppr = get_ppr (); // get current priorities being blocked
+
if (first_irr < 0) return; // no interrupts, leave INTR=0
- if (first_isr >= 0 && first_irr >= first_isr) {
- if (bx_dbg.apic)
- BX_INFO(("local apic (%s): not delivering int%02x because int%02x is in service", cpu->name, first_irr, first_isr));
+ if ((first_irr & 0xF0) <= (ppr & 0xF0)) {
+ if (bx_dbg.apic) BX_INFO(("local apic (%s): not delivering int %02X because int %02X is in service/blocked", cpu->name, first_irr, ppr));
return;
}
+
// interrupt has appeared in irr. raise INTR. When the CPU
// 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;
@@ -617,20 +686,34 @@
Bit8u
bx_local_apic_c::acknowledge_int ()
{
+ int vector, ppr;
+
// CPU calls this when it is ready to service one interrupt
if (!cpu->INTR)
BX_PANIC(("%s: acknowledged an interrupt, but INTR=0", cpu->name));
+
BX_ASSERT (cpu->int_from_local_apic);
- int vector = highest_priority_int (irr);
- BX_ASSERT (irr[vector] == 1);
- BX_DEBUG(("%s: acknowledge_int returning vector 0x%x", cpu->name, vector));
- // currently isr never gets cleared, so no point
- //BX_ASSERT (isr[vector] == 0);
- irr[vector] = 0;
- isr[vector] = 1;
- if (bx_dbg.apic) {
- BX_INFO(("Status after setting isr:"));
- print_status ();
+ vector = highest_priority_int (irr);
+ if (vector < 0) {
+ BX_INFO (("%s: acknowledge_int w/ no interrupt requested", cpu -> name));
+ vector = spurious_vec;
+ } else {
+ ppr = get_ppr ();
+ if ((vector & 0xF0) <= (ppr & 0xF0)) {
+ BX_INFO (("%s: acknowledge_int irr 0x%02X while ppr 0x%02X", cpu -> name, vector, ppr));
+ vector = spurious_vec;
+ } else {
+ BX_ASSERT (irr[vector] == 1);
+ BX_DEBUG(("%s: acknowledge_int returning vector 0x%x", cpu->name, vector));
+
+ irr[vector] = 0;
+ isr[vector] = 1;
+ //print_status ();
+ if (bx_dbg.apic) {
+ BX_INFO(("Status after setting isr:"));
+ print_status ();
+ }
+ }
}
cpu->INTR = 0;
cpu->int_from_local_apic = 0;
@@ -639,10 +722,10 @@
}
void bx_local_apic_c::print_status () {
- BX_INFO(("%s local apic: status is {:", cpu->name));
+ BX_INFO(("%s local apic: tpr 0x%02X, ppr 0x%02X, status is {:", cpu->name, task_priority, get_ppr ()));
for (int vec=0; vec<BX_LOCAL_APIC_MAX_INTS; vec++) {
if (irr[vec] || isr[vec]) {
- BX_INFO(("vec 0x%x: irr=%d, isr=%d", vec, (int)irr[vec], (int)isr[vec]));
+ BX_INFO((" vec 0x%02X: irr=%d, isr=%d", vec, (int)irr[vec], (int)isr[vec]));
}
}
BX_INFO(("}", cpu->name));
Index: cpu/cpu.cc
===================================================================
RCS file: /cvsroot/bochs/bochs/cpu/cpu.cc,v
retrieving revision 1.32
diff -u -r1.32 cpu.cc
--- cpu/cpu.cc 6 Jun 2002 23:03:09 -0000 1.32
+++ cpu/cpu.cc 27 Jun 2002 19:36:18 -0000
@@ -539,7 +539,7 @@
#else
while (1) {
#endif
- if (BX_CPU_INTR && BX_CPU_THIS_PTR get_IF ()) {
+ if ((BX_CPU_INTR && BX_CPU_THIS_PTR get_IF()) || BX_CPU_THIS_PTR nmi_queued) {
break;
}
BX_TICK1();
@@ -549,7 +549,7 @@
// 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_INTR && BX_CPU_THIS_PTR get_IF ()) {
+ if ((BX_CPU_INTR && BX_CPU_THIS_PTR get_IF()) || BX_CPU_THIS_PTR nmi_queued) {
// 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
@@ -610,6 +611,16 @@
// an opportunity to check interrupts on the next instruction
// boundary.
}
+
+ else if (BX_CPU_THIS_PTR nmi_queued) {
+ BX_CPU_THIS_PTR nmi_queued = 0;
+
+ BX_CPU_THIS_PTR errorno = 0;
+ BX_CPU_THIS_PTR EXT = 1; /* external event */
+ interrupt (2, 0, 0, 0);
+ BX_INSTR_HWINTERRUPT (2, BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value, EIP);
+ }
+
else if (BX_CPU_THIS_PTR INTR && BX_CPU_THIS_PTR get_IF() && BX_DBG_ASYNC_INTR) {
Bit8u vector;
Index: cpu/cpu.h
===================================================================
RCS file: /cvsroot/bochs/bochs/cpu/cpu.h,v
retrieving revision 1.22
diff -u -r1.22 cpu.h
--- cpu/cpu.h 5 Jun 2002 21:51:30 -0000 1.22
+++ cpu/cpu.h 27 Jun 2002 19:36:19 -0000
@@ -820,6 +820,7 @@
volatile bx_bool async_event;
volatile bx_bool INTR;
volatile bx_bool kill_bochs_request;
+ volatile bx_bool nmi_queued;
/* wether this CPU is the BSP always set for UP */
bx_bool bsp;
Index: cpu/init.cc
===================================================================
RCS file: /cvsroot/bochs/bochs/cpu/init.cc,v
retrieving revision 1.16
diff -u -r1.16 init.cc
--- cpu/init.cc 5 Jun 2002 21:51:30 -0000 1.16
+++ cpu/init.cc 27 Jun 2002 19:36:19 -0000
@@ -603,6 +603,10 @@
dynamic_init();
#endif
+ // No NMI queued to the processor
+
+ BX_CPU_THIS_PTR nmi_queued = 0;
+
#if (BX_SMP_PROCESSORS > 1)
// notice if I'm the bootstrap processor. If not, do the equivalent of
// a HALT instruction.
@@ -620,6 +624,8 @@
BX_INFO(("CPU[%d] is an application processor. Halting until IPI.", apic_id));
debug_trap |= 0x80000000;
async_event = 1;
+ BX_CPU_THIS_PTR clear_IF(); // apic code uses this to distinguish from a normal HLT instruction
+ // ... normal HLT's should not be executed with interrupts inhibited
}
#endif
}