aboutsummaryrefslogtreecommitdiffstats
path: root/tools/ioemu/iodev/ioapic.cc
diff options
context:
space:
mode:
Diffstat (limited to 'tools/ioemu/iodev/ioapic.cc')
-rw-r--r--tools/ioemu/iodev/ioapic.cc175
1 files changed, 175 insertions, 0 deletions
diff --git a/tools/ioemu/iodev/ioapic.cc b/tools/ioemu/iodev/ioapic.cc
new file mode 100644
index 0000000000..8aaf67f848
--- /dev/null
+++ b/tools/ioemu/iodev/ioapic.cc
@@ -0,0 +1,175 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: ioapic.cc,v 1.11 2002/11/19 05:47:45 bdenney Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+#include <stdio.h>
+#include "bochs.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 */