Bochs/bochs/patches/patch.apic-mrieker
2006-01-21 12:08:10 +00:00

364 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".
Status:
Most of changes introduced in the patch already committed to CVS.
The not committed parts are PPR and interprocessor NMI's, the
patch could be considered as example of implementation of these
features.
----------------------------------------------------------------------
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
@@ -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
}