Cleanup APIC code

Fixed APIC timer problem (too many registered timers) reported by Brendan
This commit is contained in:
Stanislav Shwartsman 2005-12-26 19:42:09 +00:00
parent ed577ee22e
commit 9e4a3675d3
3 changed files with 87 additions and 76 deletions

View File

@ -1,5 +1,5 @@
/////////////////////////////////////////////////////////////////////////
// $Id: apic.cc,v 1.69 2005-12-13 20:42:22 sshwarts Exp $
// $Id: apic.cc,v 1.70 2005-12-26 19:42:09 sshwarts Exp $
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2001 MandrakeSoft S.A.
@ -32,9 +32,9 @@
#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_local_apic_c *local_apic_index[BX_NUM_LOCAL_APICS];
#define LOCAL_APIC_ALL_MASK ((1<<BX_LOCAL_APIC_NUM) - 1)
#define LOCAL_APIC_ALL_MASK ((1<<BX_NUM_LOCAL_APICS) - 1)
bx_generic_apic_c::bx_generic_apic_c()
{
@ -43,9 +43,6 @@ bx_generic_apic_c::bx_generic_apic_c()
settype(APICLOG);
}
// init is called during RESET and when an INIT message is delivered.
void bx_generic_apic_c::init(void) { }
void bx_generic_apic_c::set_base (bx_address newbase)
{
newbase &= (~0xfff);
@ -118,7 +115,7 @@ void bx_generic_apic_c::read (Bit32u addr, void *data, unsigned len)
int bx_generic_apic_c::apic_bus_arbitrate(Bit32u apic_mask)
{
int winning_arb_id = -1, winning_id = -1, __arb_id, i;
for (i = 0; i < BX_LOCAL_APIC_NUM; i++) {
for (i = 0; i < BX_NUM_LOCAL_APICS; i++) {
if (apic_mask & (1<<i)) {
__arb_id = local_apic_index[i]->get_arb_id();
if (__arb_id > winning_arb_id) {
@ -136,7 +133,7 @@ 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++) {
for (i = 0; i < BX_NUM_LOCAL_APICS; i++) {
if (apic_mask & (1<<i)) {
__apr = local_apic_index[i]->get_apr();
if (__apr < winning_apr) {
@ -150,10 +147,10 @@ int bx_generic_apic_c::apic_bus_arbitrate_lowpri(Bit32u apic_mask)
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 = 0;
int trigger_order[BX_NUM_LOCAL_APICS], winner, i, j = 0;
/* bus arbitrate ... */
for (i = 0; i < BX_LOCAL_APIC_NUM; i++) {
for (i = 0; i < BX_NUM_LOCAL_APICS; i++) {
if (deliver_bitmask & (1<<i)) {
winner = apic_bus_arbitrate(deliver_bitmask);
local_apic_index[winner]->adjust_arb_id(winner);
@ -200,7 +197,7 @@ Bit32u bx_generic_apic_c::get_delivery_bitmask (Bit8u dest, Bit8u dest_mode)
} else {
// logical destination. call match_logical_addr for each local APIC.
if (dest == 0) return 0;
for (int i=0; i<BX_LOCAL_APIC_NUM; i++) {
for (int i=0; i<BX_NUM_LOCAL_APICS; i++) {
if (local_apic_index[i] && local_apic_index[i]->match_logical_addr(dest))
mask |= (1<<i);
}
@ -223,7 +220,7 @@ bx_bool bx_generic_apic_c::deliver (Bit8u dest, Bit8u dest_mode, Bit8u delivery_
int i;
// prune nonexistents apics from list
for (int bit=0; bit<BX_LOCAL_APIC_NUM; bit++)
for (int bit=0; bit<BX_NUM_LOCAL_APICS; bit++)
{
if (!local_apic_index[bit]) deliver_bitmask &= ~(1<<bit);
}
@ -249,13 +246,13 @@ bx_bool bx_generic_apic_c::deliver (Bit8u dest, Bit8u dest_mode, Bit8u delivery_
// bx_local_apic_c::deliver
// normal INIT IPI sent to processors
for (i = 0; i < BX_LOCAL_APIC_NUM; i++) {
for (i = 0; i < BX_NUM_LOCAL_APICS; i++) {
if (deliver_bitmask & (1<<i)) local_apic_index[i]->init();
}
return 1;
case APIC_DM_EXTINT:
for (i = 0; i < BX_LOCAL_APIC_NUM; i++)
for (i = 0; i < BX_NUM_LOCAL_APICS; i++)
if (deliver_bitmask & (1<<i))
local_apic_index[i]->bypass_irr_isr = 1;
break;
@ -280,7 +277,7 @@ bx_bool bx_generic_apic_c::deliver (Bit8u dest, Bit8u dest_mode, Bit8u delivery_
if (arbitrate)
arbitrate_and_trigger_one(deliver_bitmask, vector, trig_mode);
else {
for (int i = 0; i < BX_LOCAL_APIC_NUM; i++) {
for (int i = 0; i < BX_NUM_LOCAL_APICS; i++) {
if (deliver_bitmask & (1<<i)) {
local_apic_index[i]->trigger_irq(vector, i, trig_mode);
break;
@ -291,7 +288,7 @@ bx_bool bx_generic_apic_c::deliver (Bit8u dest, Bit8u dest_mode, Bit8u delivery_
if (arbitrate && !broadcast)
arbitrate_and_trigger(deliver_bitmask, vector, trig_mode);
else {
for (int i = 0; i < BX_LOCAL_APIC_NUM; i++) {
for (int i = 0; i < BX_NUM_LOCAL_APICS; i++) {
if (deliver_bitmask & (1<<i))
local_apic_index[i]->trigger_irq(vector, i, trig_mode);
}
@ -325,7 +322,7 @@ Bit32u bx_local_apic_c::get_delivery_bitmask (Bit8u dest, Bit8u dest_mode)
}
// prune nonexistents apics from list
for (int bit=0; bit<BX_LOCAL_APIC_NUM; bit++)
for (int bit=0; bit<BX_NUM_LOCAL_APICS; bit++)
{
if (!local_apic_index[bit]) mask &= ~(1<<bit);
}
@ -353,7 +350,7 @@ bx_bool bx_local_apic_c::deliver (Bit8u dest, Bit8u dest_mode, Bit8u delivery_mo
// 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++) {
for (int i = 0; i < BX_NUM_LOCAL_APICS; i++) {
if (local_apic_index[i]) {
if (local_apic_index[i]->is_focus(vector)) {
found_focus = 1;
@ -375,7 +372,7 @@ bx_bool bx_local_apic_c::deliver (Bit8u dest, Bit8u dest_mode, Bit8u delivery_mo
// arbitration ID to their APIC ID. Not supported by Pentium 4
// and Intel Xeon processors.
BX_INFO (("INIT with Level&Deassert: synchronize arbitration IDs"));
for (bit=0; bit<BX_LOCAL_APIC_NUM; bit++)
for (bit=0; bit<BX_NUM_LOCAL_APICS; bit++)
if (local_apic_index[bit])
local_apic_index[bit]->set_arb_id(local_apic_index[bit]->get_id());
return 1;
@ -383,7 +380,7 @@ bx_bool bx_local_apic_c::deliver (Bit8u dest, Bit8u dest_mode, Bit8u delivery_mo
break; // we'll fall through to generic_deliver:case INIT
case APIC_DM_SIPI: // Start Up (SIPI, local apic only)
for (bit=0; bit<BX_LOCAL_APIC_NUM; bit++) {
for (bit=0; bit<BX_NUM_LOCAL_APICS; bit++) {
if (deliver_bitmask & (1<<bit))
local_apic_index[bit]->startup_msg(vector);
}
@ -401,6 +398,11 @@ bx_local_apic_c::bx_local_apic_c(BX_CPU_C *mycpu)
: bx_generic_apic_c(), cpu(mycpu), cpu_id(cpu->which_cpu())
{
reset();
// KPL: Register a non-active timer for use when the timer is started.
timer_handle = bx_pc_system.register_timer_ticks(this,
BX_CPU(0)->local_apic.periodic_smf, 0, 0, 0, "lapic");
INTR = 0;
}
@ -453,7 +455,11 @@ void bx_local_apic_c::init()
timer_divide_factor = 1;
timer_initial = 0;
timer_current = 0;
timer_active = 0;
if (timer_active) {
bx_pc_system.deactivate_timer(timer_handle);
timer_active = 0;
}
for (i=0; i<APIC_LVT_ENTRIES; i++) {
lvt[i] = 0x10000; // all LVT are masked
@ -462,10 +468,6 @@ void bx_local_apic_c::init()
spurious_vector = 0xff; // software disabled (bit 8)
software_enabled = 0;
focus_disable = 0;
// KPL: Register a non-active timer for use when the timer is started.
timer_handle = bx_pc_system.register_timer_ticks(this,
BX_CPU(0)->local_apic.periodic_smf, 0, 0, 0, "lapic");
}
void bx_local_apic_c::set_id (Bit8u newid)
@ -585,28 +587,7 @@ void bx_local_apic_c::write (Bit32u addr, Bit32u *data, unsigned len)
if (! software_enabled) lvt[APIC_LVT_ERROR] |= 0x10000;
break;
case 0x380: // initial count for timer
{
// If active before, deactive the current timer before changing it.
if (timer_active) {
bx_pc_system.deactivate_timer(timer_handle);
timer_active = 0;
}
timer_initial = value;
timer_current = 0;
if (timer_initial != 0) // terminate the counting if timer_initial = 0
{
// This should trigger the counter to start. If already started,
// restart from the new start value.
BX_DEBUG(("APIC: Initial Timer Count Register = %u\n", value));
timer_current = timer_initial;
timer_active = 1;
Bit32u timervec = lvt[APIC_LVT_TIMER];
bx_bool continuous = (timervec & 0x20000) > 0;
ticksInitial = bx_pc_system.time_ticks(); // Take a reading.
bx_pc_system.activate_timer_ticks(timer_handle,
Bit64u(timer_initial) * Bit64u(timer_divide_factor), continuous);
}
}
set_initial_timer_count(value);
break;
case 0x3e0: // timer divide configuration
// only bits 3, 1, and 0 are writable
@ -649,14 +630,14 @@ void bx_local_apic_c::write_spurious_interrupt_register(Bit32u value)
spurious_vector = (value & 0xf0) | 0xf;
#endif
software_enabled = (value >> 8) & 1;
focus_disable = (value >> 9) & 1;
software_enabled = (value >> 8) & 1;
focus_disable = (value >> 9) & 1;
if (! software_enabled) {
for (unsigned i=0; i<APIC_LVT_ENTRIES; i++) {
lvt[i] |= 0x10000; // all LVT are masked
}
}
if (! software_enabled) {
for (unsigned i=0; i<APIC_LVT_ENTRIES; i++) {
lvt[i] |= 0x10000; // all LVT are masked
}
}
}
void bx_local_apic_c::receive_EOI(Bit32u value)
@ -996,7 +977,7 @@ Bit8u bx_local_apic_c::get_apr(void)
return (Bit8u) apr;
}
bx_bool bx_local_apic_c::is_focus(Bit32u vector)
bx_bool bx_local_apic_c::is_focus(Bit8u vector)
{
if (focus_disable) return 0;
return (irr[vector] || isr[vector]) ? 1 : 0;
@ -1006,7 +987,7 @@ void bx_local_apic_c::adjust_arb_id(int winning_id)
{
int __arb_id, __win_arb_id;
// adjust arbitration priorities
for (int i = 0; i < BX_LOCAL_APIC_NUM; i++) {
for (int i = 0; i < BX_NUM_LOCAL_APICS; i++) {
if (i != winning_id) {
__arb_id = local_apic_index[i]->get_arb_id();
if (__arb_id == APIC_MAX_ID) {
@ -1059,4 +1040,30 @@ void bx_local_apic_c::periodic(void)
}
}
void bx_local_apic_c::set_initial_timer_count(Bit32u value)
{
// If active before, deactive the current timer before changing it.
if (timer_active) {
bx_pc_system.deactivate_timer(timer_handle);
timer_active = 0;
}
timer_initial = value;
timer_current = 0;
if (timer_initial != 0) // terminate the counting if timer_initial = 0
{
// This should trigger the counter to start. If already started,
// restart from the new start value.
BX_DEBUG(("APIC: Initial Timer Count Register = %u\n", value));
timer_current = timer_initial;
timer_active = 1;
Bit32u timervec = lvt[APIC_LVT_TIMER];
bx_bool continuous = (timervec & 0x20000) > 0;
ticksInitial = bx_pc_system.time_ticks(); // Take a reading.
bx_pc_system.activate_timer_ticks(timer_handle,
Bit64u(timer_initial) * Bit64u(timer_divide_factor), continuous);
}
}
#endif /* if BX_SUPPORT_APIC */

View File

@ -1,5 +1,5 @@
/////////////////////////////////////////////////////////////////////////
// $Id: apic.h,v 1.23 2005-12-12 19:44:06 sshwarts Exp $
// $Id: apic.h,v 1.24 2005-12-26 19:42:09 sshwarts Exp $
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2001 MandrakeSoft S.A.
@ -29,11 +29,6 @@
#ifndef BX_CPU_APIC_H
# define BX_CPU_APIC_H 1
typedef enum {
APIC_TYPE_IOAPIC,
APIC_TYPE_LOCAL_APIC
} bx_apic_type_t;
#define APIC_BASE_ADDR 0xfee00000 // default APIC address
// todo: Pentium APIC_VERSION_ID (Pentium has 3 LVT entries)
@ -50,6 +45,13 @@ typedef enum {
#if BX_SUPPORT_APIC
typedef enum {
APIC_TYPE_IOAPIC,
APIC_TYPE_LOCAL_APIC
} bx_apic_type_t;
#define BX_NUM_LOCAL_APICS BX_SMP_PROCESSORS
class BOCHSAPI bx_generic_apic_c : public logfunctions {
protected:
bx_address base_addr;
@ -58,7 +60,8 @@ protected:
public:
bx_generic_apic_c ();
virtual ~bx_generic_apic_c () { }
virtual void init ();
// init is called during RESET and when an INIT message is delivered
virtual void init () { }
virtual void reset () { }
bx_address get_base (void) const { return base_addr; }
void set_base (bx_address newbase);
@ -71,7 +74,6 @@ public:
virtual void write(Bit32u address, Bit32u *value, unsigned len) = 0;
virtual Bit32u get_delivery_bitmask (Bit8u dest, Bit8u dest_mode);
virtual bx_bool deliver (Bit8u dest, Bit8u dest_mode, Bit8u delivery_mode, Bit8u vector, Bit8u level, Bit8u trig_mode);
virtual bx_bool match_logical_addr (Bit8u address) = 0;
virtual bx_apic_type_t get_type () = 0;
int apic_bus_arbitrate(Bit32u apic_mask);
int apic_bus_arbitrate_lowpri(Bit32u apic_mask);
@ -79,7 +81,6 @@ public:
void arbitrate_and_trigger_one(Bit32u deliver_bitmask, Bit32u vector, Bit8u trigger_mode);
};
#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
@ -185,7 +186,6 @@ public:
void service_local_apic(void);
void print_status(void);
virtual bx_bool match_logical_addr (Bit8u address);
virtual bx_bool is_local_apic(void) const { return 1; }
virtual bx_apic_type_t get_type(void) { return APIC_TYPE_LOCAL_APIC; }
virtual Bit32u get_delivery_bitmask (Bit8u dest, Bit8u dest_mode);
virtual bx_bool deliver (Bit8u destination, Bit8u dest_mode, Bit8u delivery_mode, Bit8u vector, Bit8u level, Bit8u trig_mode);
@ -193,21 +193,27 @@ public:
void set_tpr (Bit8u tpr);
Bit8u get_ppr (void);
Bit8u get_apr (void);
bx_bool is_focus(Bit32u vector);
bx_bool is_focus(Bit8u vector);
void adjust_arb_id(int winning_id); // adjust the arbitration id after a bus arbitration
static void periodic_smf(void *); // KPL
void periodic(void); // KPL
void set_divide_configuration (Bit32u value);
static void periodic_smf(void *);
void periodic(void);
void set_divide_configuration(Bit32u value);
void set_initial_timer_count(Bit32u value);
Bit32u get_arb_id (void);
void set_arb_id (Bit32u newid);
};
// For P6 and Pentium family processors the local APIC ID feild is 4 bits.
#define APIC_MAX_ID 0xf
#define APIC_ID_MASK 0xf
#ifdef BX_IMPLEMENT_XAPIC
#define APIC_MAX_ID 0xff
#define APIC_ID_MASK 0xff
#else
#define APIC_MAX_ID 0x0f
#define APIC_ID_MASK 0x0f
#endif
extern bx_generic_apic_c *apic_index[APIC_MAX_ID];
extern bx_local_apic_c *local_apic_index[BX_LOCAL_APIC_NUM];
extern bx_local_apic_c *local_apic_index[BX_NUM_LOCAL_APICS];
#endif // if BX_SUPPORT_APIC

View File

@ -1,5 +1,5 @@
/////////////////////////////////////////////////////////////////////////
// $Id: ioapic.h,v 1.10 2005-12-13 20:27:23 sshwarts Exp $
// $Id: ioapic.h,v 1.11 2005-12-26 19:42:09 sshwarts Exp $
/////////////////////////////////////////////////////////////////////////
extern class bx_ioapic_c bx_ioapic;
@ -54,7 +54,5 @@ public:
void raise_irq (unsigned num, unsigned from);
void lower_irq (unsigned num, unsigned from);
void service_ioapic ();
virtual bx_bool match_logical_addr (Bit8u address) { return 0; }
virtual bx_bool is_local_apic () { return 0; }
virtual bx_apic_type_t get_type () { return APIC_TYPE_IOAPIC; }
};