---------------------------------------------------------------------- Patch name: patch.apic.zwane Author: Zwane Mwaikambo Date: Wed, 25 Sep 2002 07:59:37 -0400 (EDT) Detailed description: Hi this patch adds the following; o Define symbols for constants like o APIC arbitration o Processor priority o Various interrupt delivery fixes o Focus processor checking o ExtINT delivery I need to release this now so that i don't fall too far behind CVS, when it was part of the bochs-smp patch it could boot 2.4.18 4way. Apologies for the whitespace changes. Changes by Bryce: - moved cpu_online_map into the BX_CPU_C structure as a static member (there is only one per bochs, not one per CPU) - reduced the diffs in several places to make it more clear what had changed - removed lots of whitespace diffs Patch was created with: cvs diff -u Apply patch to what version: cvs checked out on DATE, release version VER Instructions: To patch, go to main bochs directory. Type "patch -p1 < THIS_PATCH_FILE". ---------------------------------------------------------------------- Index: cpu/apic.cc =================================================================== RCS file: /cvsroot/bochs/bochs/cpu/apic.cc,v retrieving revision 1.18 diff -u -r1.18 apic.cc --- cpu/apic.cc 25 Sep 2002 01:50:14 -0000 1.18 +++ cpu/apic.cc 25 Sep 2002 14:41:04 -0000 @@ -8,6 +8,7 @@ #define LOG_THIS this-> bx_generic_apic_c *apic_index[APIC_MAX_ID]; +bx_local_apic_c *local_apic_index[BX_LOCAL_APIC_NUM]; bx_generic_apic_c::bx_generic_apic_c () { @@ -139,6 +140,70 @@ return APIC_TYPE_NONE; } +/* apic_mask is the bitmask of apics allowed to arbitrate here */ +int bx_generic_apic_c::apic_bus_arbitrate(Bit32u apic_mask) +{ + int winning_apr = 0, winning_id = 0, __apr, i; + for (i = 0; i < BX_LOCAL_APIC_NUM; i++) { + if (apic_mask & (1<get_apr(); + if (__apr > winning_apr) { + winning_apr = __apr; + winning_id = i; + } + } + } + return winning_id; +} + +/* get the CPU with the lowest arbitration ID */ +int bx_generic_apic_c::apic_bus_arbitrate_lowpri(Bit32u apic_mask) +{ + // XXX initial winning_apr value, the datasheets say 15 + int winning_apr = APIC_MAX_ID, winning_id = 0 , __apr, i; + for (i = 0; i < BX_LOCAL_APIC_NUM; i++) { + if (apic_mask & (1<get_apr_lowpri(); + if (__apr < winning_apr) { + winning_apr = __apr; + winning_id = i; + } + } + } + return winning_id; +} + +void bx_generic_apic_c::arbitrate_and_trigger(Bit32u deliver_bitmask, Bit32u vector, Bit8u trigger_mode) +{ + int trigger_order[BX_LOCAL_APIC_NUM], winner, i, j; +#define TERMINATE_MAGIK 0x5a + + /* bus arbitrate ... */ + for (i = 0, j = 0; i < BX_LOCAL_APIC_NUM; i++) { + if (deliver_bitmask & (1<adjust_arb_id(winner); + trigger_order[j++] = winner; + } + } + + if (j < BX_LOCAL_APIC_NUM) + trigger_order[j] = TERMINATE_MAGIK; + + i = 0; + do { + local_apic_index[trigger_order[i]]->trigger_irq(vector, trigger_order[i], trigger_mode); + i++; + } while (trigger_order[i] != TERMINATE_MAGIK); +} + +void bx_generic_apic_c::arbitrate_and_trigger_one(Bit32u deliver_bitmask, Bit32u vector, Bit8u trigger_mode) +{ + int winner = apic_bus_arbitrate(deliver_bitmask); + local_apic_index[winner]->adjust_arb_id(winner); + local_apic_index[winner]->trigger_irq(vector, winner, trigger_mode); +} + Bit32u bx_generic_apic_c::get_delivery_bitmask (Bit8u dest, Bit8u dest_mode) { @@ -156,8 +221,8 @@ } else { // logical destination. call match_logical_addr for each APIC. if (dest == 0) return 0; - for (int i=0; imatch_logical_addr(dest)) + for (int i=0; imatch_logical_addr(dest)) mask |= (1<get_ppr () < lowest_priority) { - lowest_priority = apic->get_ppr (); lowest_mask = 1<= 0); + case APIC_DM_LOWPRI: + /* fall through, we've already done low priority arbitration */ + arbitrate = 0; + case APIC_DM_FIXED: + /* once = false */ + break; + case APIC_DM_INIT: + // normal INIT IPI sent to processors + int i; + for (i = 0; i < BX_LOCAL_APIC_NUM; i++) { + if (deliver_bitmask & (1<init(); } + // HACK!! We need to do some IOAPIC init after the CPUs + // are fired up + apic_index[i]->init(); + return true; + + case APIC_DM_EXTINT: + for (int i = 0; i < BX_LOCAL_APIC_NUM; i++) + if (deliver_bitmask & (1<bypass_irr_isr = true; 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; bitinit (); - } - } - return true; - case 6: // Start Up (local apic only) - BX_ASSERT (get_type () == APIC_TYPE_LOCAL_APIC); - for (int bit=0; bitstartup_msg (vector); - return true; - case 2: // SMI + case APIC_DM_SMI: + case APIC_DM_NMI: case 3: // reserved - case 4: // NMI - case 7: // ExtINT (I/O apic only) default: BX_PANIC(("APIC delivery mode %d not implemented", delivery_mode)); + return false; } - // Fixed delivery mode + if (bx_dbg.apic) - BX_INFO(("delivering vector=0x%02x to bitmask=%04x", (int)vector, deliver_bitmask)); - for (int bit=0; bittrigger_irq (vector, id); + for (int i = 0; i < BX_LOCAL_APIC_NUM; i++) { + if (deliver_bitmask & (1<trigger_irq(vector, i, trig_mode); + } + break; + } + } + } else { + if (arbitrate && !broadcast) + arbitrate_and_trigger(deliver_bitmask, vector, trig_mode); + else { + for (int i = 0; i < BX_LOCAL_APIC_NUM; i++) { + if (deliver_bitmask & (1<trigger_irq(vector, i, trig_mode); } } } return true; } -Boolean -bx_local_apic_c::deliver (Bit8u dest, Bit8u dest_mode, Bit8u delivery_mode, Bit8u vector, Bit8u polarity, Bit8u trig_mode) + +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) - { + Bit32u deliver_bitmask = get_delivery_bitmask (dest, dest_mode); + int found_focus = 0; + int broadcast = deliver_bitmask == BX_CPU_C::cpu_online_map; + + if (broadcast) + BX_INFO(("Broadcast IPI for vector %#x delivery_mode %#x", vector, delivery_mode)); + switch (delivery_mode) { + case APIC_DM_LOWPRI: // lowest priority of destinations + // if we're focus processor, handle it, otherwise + // look for the focus processor. + dest = is_focus(vector) ? get_id() : 0; + if (dest) + break; + + for (int i = 0; i < BX_LOCAL_APIC_NUM; i++) { + if (local_apic_index[i]->is_focus(vector) == true) { + found_focus = 1; + dest = i; + break; // stop scanning + } + } + + if (!found_focus) + dest = apic_bus_arbitrate_lowpri(0xff); + else + return false; + break; + case APIC_DM_INIT: { + int bit; int trig_mode = (icr_low >> 15) & 1; int level = (icr_low >> 14) & 1; if (level == 0 && trig_mode == 1) { @@ -254,13 +355,26 @@ // 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; bitset_arb_id (apic_index[bit]->get_id ()); - } + for (bit=0; bitset_arb_id(local_apic_index[bit]->get_id()); + + apic_index[bit]->set_arb_id(apic_index[bit]->get_id()); // HACK !!! return true; } + break; // we'll fall through to generic_deliver:case INIT + } + + case APIC_DM_SIPI: // Start Up (SIPI, local apic only) + for (int bit=0; bitstartup_msg(vector); + } + return true; + + default: + break; } + // 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); } @@ -289,6 +403,7 @@ object, do not mess around with it */ // id = APIC_UNKNOWN_ID; arb_id = id; + BX_CPU_C::cpu_online_map |= (1 << id); } void @@ -297,9 +412,12 @@ bx_generic_apic_c::init (); BX_INFO(("local apic in %s initializing", (cpu && cpu->name) ? cpu->name : "?")); + local_apic_index[id] = this; + // default address for a local APIC, can be moved base_addr = APIC_BASE_ADDR; update_msr_apicbase(base_addr); + bypass_irr_isr = false; err_status = 0; log_dest = 0; dest_format = 0xf; @@ -322,10 +440,13 @@ // nothing for now } -void bx_local_apic_c::set_id (Bit8u newid) { +void bx_local_apic_c::set_id (Bit8u newid) +{ bx_generic_apic_c::set_id (newid); + local_apic_index[id] = this; + sprintf (cpu->name, "CPU apicid=%02x", (Bit32u)id); - if (id <= 15) { + if (id < APIC_MAX_ID) { char buffer[16]; sprintf (buffer, "APIC%x", id); put(buffer); @@ -333,12 +454,8 @@ sprintf (buffer, "CPU%x", id); cpu->put (buffer); } else { - BX_INFO (("naming convention for apics requires id=0-15 only")); + BX_INFO (("naming convention for apics requires id=0-%d only", APIC_MAX_ID)); } - if(BX_CPU_LEVEL<2) - BX_INFO(( "8086" )); - else - BX_INFO(( "80%d86", BX_CPU_LEVEL )); } char * @@ -365,7 +482,7 @@ addr &= 0xff0; switch (addr) { case 0x20: // local APIC id - id = ((*data)>>24) & 0xf; + id = ((*data)>>24) & APIC_ID_MASK; break; case 0x80: // task priority task_priority = *data & 0xff; @@ -386,7 +503,7 @@ } break; case 0xd0: // logical destination - log_dest = (*data >> 24) & 0xff; + log_dest = (*data >> 24) & APIC_ID_MASK; BX_DEBUG (("set logical destiation to %02x", log_dest)); break; case 0xe0: // destination format @@ -522,21 +639,32 @@ */ break; case 0xd0: // logical destination - *data = (log_dest & 0xff) << 24; break; + *data = (log_dest & APIC_ID_MASK) << 24; break; case 0xe0: // destination format *data = ((dest_format & 0xf) << 24) | 0x0fffffff; break; case 0xf0: // spurious interrupt vector *data = spurious_vec; break; - // ISRs not writable - case 0x100: case 0x110: case 0x120: case 0x130: - case 0x140: case 0x150: case 0x160: case 0x170: - case 0x180: case 0x190: case 0x1a0: case 0x1b0: - case 0x1c0: case 0x1d0: case 0x1e0: case 0x1f0: - case 0x200: case 0x210: case 0x220: case 0x230: - case 0x240: case 0x250: case 0x260: case 0x270: - *data = 0; - BX_INFO(("reading ISR,TMR,IRR not implemented")); + + // XXX blearrchhaarghh!! + case 0x100: case 0x110: + case 0x120: case 0x130: + case 0x140: case 0x150: + case 0x160: case 0x170: + *data = isr[addr2-0x100]; + break; + case 0x180: case 0x190: + case 0x1a0: case 0x1b0: + case 0x1c0: case 0x1d0: + case 0x1e0: case 0x1f0: + *data = tmr[addr2-0x180]; + break; + case 0x200: case 0x210: + case 0x220: case 0x230: + case 0x240: case 0x250: + case 0x260: case 0x270: + *data = irr[addr2-0x200]; break; + case 0x280: // error status reg *data = err_status; break; case 0x300: // interrupt command reg 0-31 @@ -577,18 +705,28 @@ void bx_local_apic_c::service_local_apic () { + int first_irr, first_isr; + if (bx_dbg.apic) { BX_INFO(("service_local_apic()")); print_status (); } - if (cpu->INTR) return; // INTR already up; do nothing + + 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); - if (first_irr < 0) return; // no interrupts, leave INTR=0 + first_irr = highest_priority_int (irr); + first_isr = highest_priority_int (isr); + 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)); + BX_INFO(("not delivering int%02x because int%02x is in service", + cpu->name, first_irr, first_isr)); + err_status |= APIC_ERR_TX_ACCEPT_ERR; + return; } // interrupt has appeared in irr. raise INTR. When the CPU @@ -599,21 +737,45 @@ cpu->int_from_local_apic = 1; } -void bx_local_apic_c::trigger_irq (unsigned vector, unsigned from) +void bx_local_apic_c::trigger_irq (unsigned vector, unsigned from, unsigned trigger_mode) { - BX_DEBUG(("Local apic on %s: trigger interrupt vector=0x%x", cpu->name, vector)); + /* check for local/apic_index usage */ + BX_ASSERT(from == id); + + if (vector > BX_APIC_LAST_VECTOR) { + err_status |= APIC_ERR_RX_ILLEGAL_VEC; + BX_INFO(("bogus vector %#x, ignoring", vector)); + return; + } + + if (bx_dbg.apic) + BX_INFO(("triggered vector %#02x", vector)); + + if (bypass_irr_isr) { + bypass_irr_isr = false; + goto service_vector; + } + + if (irr[vector] != 0) { + err_status |= APIC_ERR_TX_ACCEPT_ERR; + return; + } + +service_vector: irr[vector] = 1; + tmr[vector] = trigger_mode; // set for level triggered service_local_apic (); } -void bx_local_apic_c::untrigger_irq (unsigned vector, unsigned from) +void bx_local_apic_c::untrigger_irq (unsigned vector, unsigned from, unsigned trigger_mode) { BX_DEBUG(("Local apic on %s: untrigger interrupt vector=0x%x", cpu->name, vector)); // hardware says "no more". clear the bit. If the CPU hasn't yet // acknowledged the interrupt, it will never be serviced. BX_ASSERT (irr[vector] == 1); irr[vector] = 0; - if (bx_dbg.apic) print_status (); + if (bx_dbg.apic) + print_status (); } Bit8u @@ -622,14 +784,21 @@ // 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); + /*XXX */ + if (irr[vector] != 1) { + BX_INFO(("IRR was not 1! irr[%d]=%#x", vector, irr[vector])); + irr[vector]=1; + } 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 (); @@ -643,26 +812,21 @@ void bx_local_apic_c::print_status () { BX_INFO(("%s local apic: status is {:", cpu->name)); for (int vec=0; vecname)); + BX_INFO(("}")); } Boolean bx_local_apic_c::match_logical_addr (Bit8u address) { - if (dest_format != 0xf) { - BX_PANIC(("bx_local_apic_c::match_logical_addr: cluster model addressing not implemented")); - } - // if all address bits are 1, send to all local APICs. SDG3:7-27. - if (address == 0xff) { - BX_DEBUG (("%s: MDA=0xff matches everybody", cpu->name)); - return true; - } + if (dest_format != 0xf) + BX_PANIC(("cluster model addressing not implemented")); + Boolean match = ((address & log_dest) != 0); BX_DEBUG (("%s: comparing MDA %02x to my LDR %02x -> %s", cpu->name, address, log_dest, match? "Match" : "Not a match")); + return match; } @@ -670,68 +834,121 @@ bx_local_apic_c::get_delivery_bitmask (Bit8u dest, Bit8u dest_mode) { int dest_shorthand = (icr_low >> 18) & 3; - Bit32u all_mask = (1<get_type () != APIC_TYPE_LOCAL_APIC)) - mask &= ~(1<>WARNING<< returning a mask of 0x0, dest=%#x dest_mode=%#x", dest, dest_mode)); + return mask; } Bit8u bx_local_apic_c::get_ppr () { - static int warned = 0; - if (warned < 10) { - BX_ERROR(("WARNING: Local APIC Processor Priority not implemented, returning 0")); - warned++; - } - // should look at TPR, vector of highest priority isr, etc. - return 0; -} + Bit32u tpr = (task_priority >> 4) & 0xf; /* we want 7:4 */ + Bit32u isrv = (highest_priority_int(isr) >> 4) & 0xf; /* ditto */ + + if (tpr >= isrv) + proc_priority = task_priority & 0xff; + else + proc_priority = isrv << 4; /* low 4 bits of PPR have to be cleared */ + if (bx_dbg.apic) + BX_DEBUG(("%s: get_ppr returning %#x", cpu->name, proc_priority)); + + return (Bit8u)proc_priority; +} Bit8u bx_local_apic_c::get_apr () { return arb_id; } +Bit8u bx_local_apic_c::get_apr_lowpri() +{ + Bit32u tpr = (task_priority >> 4) & 0xf; + Bit32u isrv = (highest_priority_int(isr) >> 4) & 0xf; + Bit32u irrv = (highest_priority_int(irr) >> 4) & 0xf; + + if ((tpr >= irrv) && (tpr > isrv)) + arb_id = task_priority & 0xff; + else + arb_id = ((tpr && isrv) > irrv) ? (tpr && isrv) : irrv; + + BX_INFO(("apr = %d\n", arb_id)); + return (Bit8u)arb_id; +} + +Boolean bx_local_apic_c::is_focus(Bit32u vector) +{ + return (irr[vector] || isr[vector]) ? true : false; +} + +void bx_local_apic_c::adjust_arb_id(int winning_id) +{ + int __apr, __win_apr; + + // adjust arbitration priorities + for (int i = 0; i < BX_LOCAL_APIC_NUM; i++) { + if (i != winning_id) { + __apr = local_apic_index[i]->get_apr(); + if (__apr == 15) { + __win_apr = local_apic_index[winning_id]->get_apr(); + local_apic_index[i]->set_arb_id(__win_apr+1); + } else + local_apic_index[i]->set_arb_id(__apr+1); + } else + local_apic_index[winning_id]->set_arb_id(0); // the winner drops to lowest + } +} + void bx_local_apic_c::periodic (Bit32u usec_delta) { - if (!timer_active) return; + if (!timer_active) + return; + BX_DEBUG(("%s: bx_local_apic_c::periodic called with %d usec", cpu->name, usec_delta)); + // unless usec_delta is guaranteed to be a multiple of 128, I can't // just divide usec_delta by the divide-down value. Instead, it will // have a similar effect to implement the divide-down by ignoring // some fraction of calls to this function. This can be improved if // more granularity is important. + timer_divide_counter = (timer_divide_counter + 1) % timer_divide_factor; - if (timer_divide_counter != 0) return; + if (timer_divide_counter != 0) + return; + if (timer_current > usec_delta) { timer_current -= usec_delta; - //BX_INFO(("%s: local apic timer is now 0x%08x", cpu->name, timer_current)); + BX_DEBUG(("%s: local apic timer is now 0x%08x", cpu->name, timer_current)); return; } + // timer reached zero since the last call to periodic. Bit32u timervec = lvt[APIC_LVT_TIMER]; if (timervec & 0x20000) { // periodic mode. Always trigger the interrupt when we reach zero. - trigger_irq (timervec & 0xff, id); + trigger_irq (timervec & 0xff, id, APIC_EDGE_TRIGGERED); if (timer_initial == 0) { usec_delta = 0; timer_current = 0; @@ -745,14 +962,17 @@ // negative timer_current. BX_ASSERT ((timer_current + timer_initial) >= usec_delta); } - BX_DEBUG(("%s: local apic timer (periodic) triggered int, reset counter to 0x%08x", cpu->name, timer_current)); + + BX_DEBUG(("%s: local apic timer (periodic) triggered int, reset counter to 0x%08x", + cpu->name, timer_current)); } else { // one-shot mode timer_current = 0; if (timer_active) { - trigger_irq (timervec & 0xff, id); + trigger_irq (timervec & 0xff, id, APIC_EDGE_TRIGGERED); timer_active = false; BX_DEBUG (("%s: local apic timer (one-shot) triggered int", cpu->name)); } } } + Index: cpu/cpu.cc =================================================================== RCS file: /cvsroot/bochs/bochs/cpu/cpu.cc,v retrieving revision 1.52 diff -u -r1.52 cpu.cc --- cpu/cpu.cc 24 Sep 2002 18:33:37 -0000 1.52 +++ cpu/cpu.cc 25 Sep 2002 14:41:05 -0000 @@ -65,6 +65,9 @@ }; #endif +#if BX_SUPPORT_APIC +Bit32u BX_CPU_C::cpu_online_map = 0; +#endif #if BX_SMP_PROCESSORS==1 // single processor simulation, so there's one of everything Index: cpu/cpu.h =================================================================== RCS file: /cvsroot/bochs/bochs/cpu/cpu.h,v retrieving revision 1.80 diff -u -r1.80 cpu.h --- cpu/cpu.h 25 Sep 2002 13:26:04 -0000 1.80 +++ cpu/cpu.h 25 Sep 2002 14:41:08 -0000 @@ -1153,13 +1153,21 @@ #define APIC_BASE_ADDR 0xfee00000 // default APIC address +#if BX_CPU_LEVEL == 5 +# define APIC_VERSION_ID 0x00340011 +#else +# define APIC_VERSION_ID 0x00040011 // P6 +#endif + +#define IOAPIC_VERSION_ID 0x00170011 // same version as 82093 IOAPIC + + #if BX_SUPPORT_APIC class bx_generic_apic_c : public logfunctions { protected: Bit32u base_addr; Bit8u id; #define APIC_UNKNOWN_ID 0xff -#define APIC_VERSION_ID 0x00170011 // same version as 82093 IOAPIC public: bx_generic_apic_c (); virtual ~bx_generic_apic_c (); @@ -1184,10 +1192,20 @@ 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 + int apic_bus_arbitrate(Bit32u apic_mask); + int apic_bus_arbitrate_lowpri(Bit32u apic_mask); + void arbitrate_and_trigger(Bit32u deliver_bitmask, Bit32u vector, Bit8u trigger_mode); + void arbitrate_and_trigger_one(Bit32u deliver_bitmask, Bit32u vector, Bit8u trigger_mode); }; class bx_local_apic_c : public bx_generic_apic_c { +#define BX_LOCAL_APIC_NUM BX_SMP_PROCESSORS +#define BX_APIC_FIRST_VECTOR 0x10 +#define BX_APIC_LAST_VECTOR 0xfe #define BX_LOCAL_APIC_MAX_INTS 256 + +#define APIC_LEVEL_TRIGGERED 1 +#define APIC_EDGE_TRIGGERED 0 // TMR=trigger mode register. Cleared for edge-triggered interrupts // and set for level-triggered interrupts. If set, local APIC must send // EOI message to all other APICs. EOI's are not implemented. @@ -1199,7 +1217,7 @@ // ISR=in-service register. When an IRR bit is cleared, the corresponding // 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 arb_id, arb_priority, task_priority, proc_priority, log_dest, dest_format, spurious_vec; Bit32u lvt[6]; #define APIC_LVT_TIMER 0 #define APIC_LVT_THERMAL 1 @@ -1207,6 +1225,17 @@ #define APIC_LVT_LINT0 3 #define APIC_LVT_LINT1 4 #define APIC_LVT_ERROR 5 + +/* APIC delivery modes */ +#define APIC_DM_FIXED 0 +#define APIC_DM_LOWPRI 1 +#define APIC_DM_SMI 2 +/* RESERVED 3 */ +#define APIC_DM_NMI 4 +#define APIC_DM_INIT 5 +#define APIC_DM_SIPI 6 +#define APIC_DM_EXTINT 7 + Bit32u timer_initial, timer_current, timer_divconf; Boolean timer_active; // internal state, not accessible from bus Bit32u timer_divide_counter, timer_divide_factor; @@ -1234,8 +1263,8 @@ // on local APIC, trigger means raise the CPU's INTR line. For now // I also have to raise pc_system.INTR but that should be replaced // with the cpu-specific INTR signals. - virtual void trigger_irq (unsigned num, unsigned from); - virtual void untrigger_irq (unsigned num, unsigned from); + virtual void trigger_irq (unsigned num, unsigned from, unsigned trigger_mode); + virtual void untrigger_irq (unsigned num, unsigned from, unsigned trigger_mode); Bit8u acknowledge_int (); // only the local CPU should call this int highest_priority_int (Bit8u *array); void service_local_apic (); @@ -1247,14 +1276,20 @@ virtual Boolean deliver (Bit8u destination, Bit8u dest_mode, Bit8u delivery_mode, Bit8u vector, Bit8u polarity, Bit8u trig_mode); Bit8u get_ppr (); Bit8u get_apr (); + Bit8u get_apr_lowpri(); + Boolean is_focus(Bit32u vector); + Boolean bypass_irr_isr; + void adjust_arb_id(int winning_id); // adjust the arbitration id after a bus arbitration void periodic (Bit32u usec_delta); void set_divide_configuration (Bit32u value); virtual void update_msr_apicbase(Bit32u newaddr); virtual void set_arb_id (int newid); }; -#define APIC_MAX_ID 16 +#define APIC_MAX_ID 0xff +#define APIC_ID_MASK 0xff extern bx_generic_apic_c *apic_index[APIC_MAX_ID]; +extern bx_local_apic_c *local_apic_index[BX_LOCAL_APIC_NUM]; #endif // if BX_SUPPORT_APIC @@ -2603,6 +2638,7 @@ #if BX_SUPPORT_APIC bx_local_apic_c local_apic; Boolean int_from_local_apic; + static Bit32u cpu_online_map; #endif }; Index: iodev/ioapic.cc =================================================================== RCS file: /cvsroot/bochs/bochs/iodev/ioapic.cc,v retrieving revision 1.9 diff -u -r1.9 ioapic.cc --- iodev/ioapic.cc 29 Aug 2002 16:52:47 -0000 1.9 +++ iodev/ioapic.cc 25 Sep 2002 14:41:10 -0000 @@ -11,16 +11,22 @@ void bx_io_redirect_entry_t::parse_value () { - dest = (value >> 56) & 0xff; + dest = (value >> 56) & APIC_ID_MASK; masked = (value >> 16) & 1; trig_mode = (value >> 15) & 1; remote_irr = (value >> 14) & 1; polarity = (value >> 13) & 1; //delivery_status = (value >> 12) & 1; - delivery_status = 0; // always say the message has gone through + delivery_status = 0; // we'll change this later... dest_mode = (value >> 11) & 1; +#if 0 + if (dest_mode == 1) + dest = (value >> 56) & APIC_ID_MAX; // processor mask + else + dest = (value >> 56) & APIC_ID_MASK; // APIC ID +#endif delivery_mode = (value >> 8) & 7; - vector = (value >> 0) & 0xff; + vector = value & 0xff; } void @@ -45,6 +51,7 @@ bx_generic_apic_c::init (); BX_DEBUG(("initializing I/O APIC")); base_addr = 0xfec00000; + set_id(BX_IOAPIC_DEFAULT_ID); ioregsel = 0; // all interrupts masked for (int i=0; i> 24) & 0xf; + Bit8u newid = (*value >> 24) & APIC_ID_MASK; BX_INFO(("IOAPIC: setting id to 0x%x", newid)); set_id (newid); return; @@ -140,14 +146,16 @@ void bx_ioapic_c::trigger_irq (unsigned vector, unsigned from) { - BX_DEBUG(("IOAPIC: received interrupt %d", vector)); - if (vector >= 0 && vector < BX_IOAPIC_NUM_PINS) { + BX_DEBUG(("IOAPIC: received vector %d", vector)); + if ((vector >= 0) && (vector <= BX_APIC_LAST_VECTOR)) { Bit32u bit = 1<parse_value(); if (!entry->masked) { - // clear irr bit and deliver - Boolean done = deliver (entry->dest, entry->dest_mode, entry->delivery_mode, entry->vector, entry->polarity, entry->trig_mode); - if (done) irr &= ~(1<dest, entry->dest_mode, + entry->delivery_mode, entry->vector, + entry->polarity, entry->trig_mode); + + if (done) { + irr &= ~(1<delivery_status = 0; + stuck = 0; + } else { + entry->delivery_status = 1; + stuck++; + if (stuck > 5) + BX_INFO(("vector %#x stuck?\n", entry->vector)); + } + } } } } +