Bochs/bochs/iodev/ioapic.cc

171 lines
4.6 KiB
C++
Raw Normal View History

#include <stdio.h>
#include "bochs.h"
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 ()
{
setprefix("IOAP");
settype(IOAPICLOG);
}
bx_ioapic_c::~bx_ioapic_c () {
}
void
bx_ioapic_c::init ()
{
bx_generic_apic_c::init ();
if (bx_dbg.ioapic)
BX_INFO(("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::read_aligned(Bit32u address, Bit32u *data, unsigned len)
{
if (bx_dbg.ioapic)
BX_INFO( ("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)
{
if (bx_dbg.ioapic)
BX_INFO(("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);
if (bx_dbg.ioapic)
BX_INFO(("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)
{
if (bx_dbg.ioapic)
BX_INFO(("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)
{
if (bx_dbg.ioapic)
BX_INFO(("IOAPIC: interrupt %d went away", num));
}
void bx_ioapic_c::service_ioapic ()
{
// look in IRR and deliver any interrupts that are not masked.
if (bx_dbg.ioapic)
BX_INFO(("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
Boolean done = deliver (entry->dest, entry->dest_mode, entry->delivery_mode, entry->vector, entry->polarity, entry->trig_mode);
if (done) irr &= ~(1<<bit);
}
}
}
}