5873b26a82
bochs.h already not include iodev.h which reduces compilation dependences for almost all cpu and fpu files, now cpu files will not be recompiled if iodev includes was changed
177 lines
4.7 KiB
C++
177 lines
4.7 KiB
C++
/////////////////////////////////////////////////////////////////////////
|
|
// $Id: ioapic.cc,v 1.12 2004-06-19 15:20:12 sshwarts Exp $
|
|
/////////////////////////////////////////////////////////////////////////
|
|
//
|
|
#include <stdio.h>
|
|
|
|
#include "iodev.h"
|
|
#if BX_SUPPORT_APIC
|
|
|
|
class bx_ioapic_c bx_ioapic;
|
|
#define LOG_THIS bx_ioapic.
|
|
|
|
void
|
|
bx_io_redirect_entry_t::parse_value ()
|
|
{
|
|
dest = (value >> 56) & 0xff;
|
|
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
|
|
dest_mode = (value >> 11) & 1;
|
|
delivery_mode = (value >> 8) & 7;
|
|
vector = (value >> 0) & 0xff;
|
|
}
|
|
|
|
void
|
|
bx_io_redirect_entry_t::sprintf_self (char *buf)
|
|
{
|
|
sprintf (buf, "dest=%02x, masked=%d, trig_mode=%d, remote_irr=%d, polarity=%d, delivery_status=%d, dest_mode=%d, delivery_mode=%d, vector=%02x", dest, masked, trig_mode, remote_irr, polarity, delivery_status, dest_mode, delivery_mode, vector);
|
|
}
|
|
|
|
bx_ioapic_c::bx_ioapic_c ()
|
|
: bx_generic_apic_c ()
|
|
{
|
|
put("IOAP");
|
|
settype(IOAPICLOG);
|
|
}
|
|
|
|
bx_ioapic_c::~bx_ioapic_c () {
|
|
}
|
|
|
|
void
|
|
bx_ioapic_c::init ()
|
|
{
|
|
bx_generic_apic_c::init ();
|
|
BX_DEBUG(("initializing I/O APIC"));
|
|
base_addr = 0xfec00000;
|
|
ioregsel = 0;
|
|
// all interrupts masked
|
|
for (int i=0; i<BX_IOAPIC_NUM_PINS; i++) {
|
|
ioredtbl[i].set_even_word (0x00010000);
|
|
ioredtbl[i].set_odd_word (0x00000000);
|
|
}
|
|
irr = 0;
|
|
}
|
|
|
|
void
|
|
bx_ioapic_c::reset (unsigned type)
|
|
{
|
|
}
|
|
|
|
void
|
|
bx_ioapic_c::read_aligned(Bit32u address, Bit32u *data, unsigned len)
|
|
{
|
|
BX_DEBUG( ("I/O APIC read_aligned addr=%08x, len=%d", address, len));
|
|
BX_ASSERT (len == 4);
|
|
address &= 0xff;
|
|
if (address == 0x00) {
|
|
// select register
|
|
*data = ioregsel;
|
|
return;
|
|
} else if (address != 0x10) {
|
|
BX_PANIC(("IOAPIC: read from unsupported address"));
|
|
}
|
|
// only reached when reading data register
|
|
switch (ioregsel) {
|
|
case 0x00: // APIC ID
|
|
*data = ((id & 0xf) << 24);
|
|
return;
|
|
case 0x01: // version
|
|
*data = (((BX_IOAPIC_NUM_PINS-1) & 0xff) << 16)
|
|
| (BX_IOAPIC_VERSION_ID & 0x0f);
|
|
return;
|
|
case 0x02:
|
|
BX_INFO(("IOAPIC: arbitration ID unsupported, returned 0"));
|
|
*data = 0;
|
|
return;
|
|
default:
|
|
int index = (ioregsel - 0x10) >> 1;
|
|
if (index >= 0 && index < BX_IOAPIC_NUM_PINS) {
|
|
bx_io_redirect_entry_t *entry = ioredtbl + index;
|
|
*data = (ioregsel&1) ? entry->get_odd_word() : entry->get_even_word ();
|
|
return;
|
|
}
|
|
BX_PANIC(("IOAPIC: IOREGSEL points to undefined register %02x", ioregsel));
|
|
}
|
|
}
|
|
|
|
void
|
|
bx_ioapic_c::write(Bit32u address, Bit32u *value, unsigned len)
|
|
{
|
|
BX_DEBUG(("IOAPIC: write addr=%08x, data=%08x, len=%d", address, *value, len));
|
|
address &= 0xff;
|
|
if (address == 0x00) {
|
|
ioregsel = *value;
|
|
return;
|
|
} else if (address != 0x10) {
|
|
BX_PANIC(("IOAPIC: write to unsupported address"));
|
|
}
|
|
// only reached when writing data register
|
|
switch (ioregsel) {
|
|
case 0x00: // set APIC ID
|
|
{
|
|
Bit8u newid = (*value >> 24) & 0xf;
|
|
BX_INFO(("IOAPIC: setting id to 0x%x", newid));
|
|
set_id (newid);
|
|
return;
|
|
}
|
|
case 0x01: // version
|
|
case 0x02: // arbitration id
|
|
BX_INFO(("IOAPIC: could not write, IOREGSEL=0x%02x", ioregsel));
|
|
return;
|
|
default:
|
|
int index = (ioregsel - 0x10) >> 1;
|
|
if (index >= 0 && index < BX_IOAPIC_NUM_PINS) {
|
|
bx_io_redirect_entry_t *entry = ioredtbl + index;
|
|
if (ioregsel&1)
|
|
entry->set_odd_word (*value);
|
|
else
|
|
entry->set_even_word (*value);
|
|
char buf[1024];
|
|
entry->sprintf_self (buf);
|
|
BX_DEBUG(("IOAPIC: now entry[%d] is %s", index, buf));
|
|
service_ioapic ();
|
|
return;
|
|
}
|
|
BX_PANIC(("IOAPIC: IOREGSEL points to undefined register %02x", ioregsel));
|
|
}
|
|
}
|
|
|
|
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) {
|
|
Bit32u bit = 1<<vector;
|
|
if ((irr & bit) == 0) {
|
|
irr |= bit;
|
|
service_ioapic ();
|
|
}
|
|
} else BX_PANIC(("IOAPIC: vector %d out of range", vector));
|
|
}
|
|
|
|
void bx_ioapic_c::untrigger_irq (unsigned num, unsigned from)
|
|
{
|
|
BX_DEBUG(("IOAPIC: interrupt %d went away", num));
|
|
}
|
|
|
|
void bx_ioapic_c::service_ioapic ()
|
|
{
|
|
// look in IRR and deliver any interrupts that are not masked.
|
|
BX_DEBUG(("IOAPIC: servicing"));
|
|
for (unsigned bit=0; bit < BX_IOAPIC_NUM_PINS; bit++) {
|
|
if (irr & (1<<bit)) {
|
|
bx_io_redirect_entry_t *entry = ioredtbl + bit;
|
|
if (!entry->masked) {
|
|
// clear irr bit and deliver
|
|
bx_bool done = deliver (entry->dest, entry->dest_mode, entry->delivery_mode, entry->vector, entry->polarity, entry->trig_mode);
|
|
if (done) irr &= ~(1<<bit);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#endif /* if BX_SUPPORT_APIC */
|