summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGabe Black <gblack@eecs.umich.edu>2008-10-12 13:44:24 -0700
committerGabe Black <gblack@eecs.umich.edu>2008-10-12 13:44:24 -0700
commit876f4845f258ed09d348135d8af8cf4a17de1b8a (patch)
tree2d109af5103908a7f1561f3610b8e55add81ec7f
parent4d5c7f70389b8911e37d391b09023dbf6a6ab0d9 (diff)
downloadgem5-876f4845f258ed09d348135d8af8cf4a17de1b8a.tar.xz
X86: Make the local APIC handle interrupt messages from the IO APIC.
-rw-r--r--src/arch/x86/faults.hh5
-rw-r--r--src/arch/x86/interrupts.cc67
-rw-r--r--src/arch/x86/interrupts.hh136
-rw-r--r--src/arch/x86/intmessage.hh39
-rw-r--r--src/dev/x86/i82094aa.cc31
-rw-r--r--src/dev/x86/i8259.hh3
-rw-r--r--src/dev/x86/pc.cc3
7 files changed, 217 insertions, 67 deletions
diff --git a/src/arch/x86/faults.hh b/src/arch/x86/faults.hh
index a54bc8ee9..8fe90299d 100644
--- a/src/arch/x86/faults.hh
+++ b/src/arch/x86/faults.hh
@@ -351,9 +351,10 @@ namespace X86ISA
class ExternalInterrupt : public X86Interrupt
{
+ uint8_t vector;
public:
- ExternalInterrupt() :
- X86Interrupt("External Interrupt", "#INTR")
+ ExternalInterrupt(uint8_t _vector) :
+ X86Interrupt("External Interrupt", "#INTR"), vector(_vector)
{}
};
diff --git a/src/arch/x86/interrupts.cc b/src/arch/x86/interrupts.cc
index 5614a37eb..a7c238ace 100644
--- a/src/arch/x86/interrupts.cc
+++ b/src/arch/x86/interrupts.cc
@@ -57,7 +57,9 @@
#include "arch/x86/apicregs.hh"
#include "arch/x86/interrupts.hh"
+#include "arch/x86/intmessage.hh"
#include "cpu/base.hh"
+#include "mem/packet_access.hh"
int
divideFromConf(uint32_t conf)
@@ -242,12 +244,43 @@ X86ISA::Interrupts::write(PacketPtr pkt)
Tick
X86ISA::Interrupts::recvMessage(PacketPtr pkt)
{
- Addr offset = pkt->getAddr() - x86InterruptAddress(0, 0);
+ uint8_t id = 0;
+ Addr offset = pkt->getAddr() - x86InterruptAddress(id, 0);
assert(pkt->cmd == MemCmd::MessageReq);
switch(offset)
{
case 0:
- DPRINTF(LocalApic, "Got Trigger Interrupt message.\n");
+ {
+ TriggerIntMessage message = pkt->get<TriggerIntMessage>();
+ uint8_t vector = message.vector;
+ DPRINTF(LocalApic,
+ "Got Trigger Interrupt message with vector %#x.\n",
+ vector);
+ // Make sure we're really supposed to get this.
+ assert((message.destMode == 0 && message.destination == id) ||
+ (bits((int)message.destination, id)));
+ if (DeliveryMode::isUnmaskable(message.deliveryMode)) {
+ DPRINTF(LocalApic, "Interrupt is an %s and unmaskable.\n",
+ DeliveryMode::names[message.deliveryMode]);
+ panic("Unmaskable interrupts aren't implemented.\n");
+ } else if (DeliveryMode::isMaskable(message.deliveryMode)) {
+ DPRINTF(LocalApic, "Interrupt is an %s and maskable.\n",
+ DeliveryMode::names[message.deliveryMode]);
+ // Queue up the interrupt in the IRR.
+ if (vector > IRRV)
+ IRRV = vector;
+ if (!getRegArrayBit(APIC_INTERRUPT_REQUEST_BASE, vector)) {
+ setRegArrayBit(APIC_INTERRUPT_REQUEST_BASE, vector);
+ if (message.trigger) {
+ // Level triggered.
+ setRegArrayBit(APIC_TRIGGER_MODE_BASE, vector);
+ } else {
+ // Edge triggered.
+ clearRegArrayBit(APIC_TRIGGER_MODE_BASE, vector);
+ }
+ }
+ }
+ }
break;
default:
panic("Local apic got unknown interrupt message at offset %#x.\n",
@@ -414,6 +447,36 @@ X86ISA::Interrupts::setReg(ApicRegIndex reg, uint32_t val)
return;
}
+bool
+X86ISA::Interrupts::check_interrupts(ThreadContext * tc) const
+{
+ RFLAGS rflags = tc->readMiscRegNoEffect(MISCREG_RFLAGS);
+ if (IRRV > ISRV && rflags.intf &&
+ bits(IRRV, 7, 4) > bits(regs[APIC_TASK_PRIORITY], 7, 4)) {
+ return true;
+ }
+ return false;
+}
+
+Fault
+X86ISA::Interrupts::getInterrupt(ThreadContext * tc)
+{
+ assert(check_interrupts(tc));
+ return new ExternalInterrupt(IRRV);
+}
+
+void
+X86ISA::Interrupts::updateIntrInfo(ThreadContext * tc)
+{
+ assert(check_interrupts(tc));
+ // Mark the interrupt as "in service".
+ ISRV = IRRV;
+ setRegArrayBit(APIC_IN_SERVICE_BASE, ISRV);
+ // Clear it out of the IRR.
+ clearRegArrayBit(APIC_INTERRUPT_REQUEST_BASE, IRRV);
+ updateIRRV();
+}
+
X86ISA::Interrupts *
X86LocalApicParams::create()
{
diff --git a/src/arch/x86/interrupts.hh b/src/arch/x86/interrupts.hh
index c4760dc0f..cfc1ada9d 100644
--- a/src/arch/x86/interrupts.hh
+++ b/src/arch/x86/interrupts.hh
@@ -60,6 +60,7 @@
#include "arch/x86/apicregs.hh"
#include "arch/x86/faults.hh"
+#include "base/bitfield.hh"
#include "cpu/thread_context.hh"
#include "dev/io_device.hh"
#include "dev/x86/intdev.hh"
@@ -74,7 +75,12 @@ namespace X86ISA
class Interrupts : public BasicPioDevice, IntDev
{
protected:
+ // Storage for the APIC registers
uint32_t regs[NUM_APIC_REGS];
+
+ /*
+ * Timing related stuff.
+ */
Tick latency;
Tick clock;
@@ -92,7 +98,58 @@ class Interrupts : public BasicPioDevice, IntDev
ApicTimerEvent apicTimerEvent;
+ /*
+ * IRR and ISR maintenance.
+ */
+ uint8_t IRRV;
+ uint8_t ISRV;
+
+ int
+ findRegArrayMSB(ApicRegIndex base)
+ {
+ int offset = 7;
+ do {
+ if (regs[base + offset] != 0) {
+ return offset * 32 + findMsbSet(regs[base + offset]);
+ }
+ } while (offset--);
+ return 0;
+ }
+
+ void
+ updateIRRV()
+ {
+ IRRV = findRegArrayMSB(APIC_INTERRUPT_REQUEST_BASE);
+ }
+
+ void
+ updateISRV()
+ {
+ ISRV = findRegArrayMSB(APIC_IN_SERVICE_BASE);
+ }
+
+ void
+ setRegArrayBit(ApicRegIndex base, uint8_t vector)
+ {
+ regs[base + (vector % 32)] |= (1 << (vector >> 5));
+ }
+
+ void
+ clearRegArrayBit(ApicRegIndex base, uint8_t vector)
+ {
+ regs[base + (vector % 32)] &= ~(1 << (vector >> 5));
+ }
+
+ bool
+ getRegArrayBit(ApicRegIndex base, uint8_t vector)
+ {
+ return bits(regs[base + (vector % 32)], vector >> 5);
+ }
+
public:
+ /*
+ * Params stuff.
+ */
typedef X86LocalApicParams Params;
void setClock(Tick newClock)
@@ -106,6 +163,9 @@ class Interrupts : public BasicPioDevice, IntDev
return dynamic_cast<const Params *>(_params);
}
+ /*
+ * Functions to interact with the interrupt port from IntDev.
+ */
Tick read(PacketPtr pkt);
Tick write(PacketPtr pkt);
Tick recvMessage(PacketPtr pkt);
@@ -124,6 +184,17 @@ class Interrupts : public BasicPioDevice, IntDev
x86InterruptAddress(0, 0) + PhysAddrAPICRangeSize));
}
+ Port *getPort(const std::string &if_name, int idx = -1)
+ {
+ if (if_name == "int_port")
+ return intPort;
+ return BasicPioDevice::getPort(if_name, idx);
+ }
+
+ /*
+ * Functions to access and manipulate the APIC's registers.
+ */
+
uint32_t readReg(ApicRegIndex miscReg);
void setReg(ApicRegIndex reg, uint32_t val);
void setRegNoEffect(ApicRegIndex reg, uint32_t val)
@@ -131,29 +202,47 @@ class Interrupts : public BasicPioDevice, IntDev
regs[reg] = val;
}
+ /*
+ * Constructor.
+ */
+
Interrupts(Params * p) : BasicPioDevice(p), IntDev(this),
latency(p->pio_latency), clock(0)
{
pioSize = PageBytes;
+ memset(regs, 0, sizeof(regs));
//Set the local apic DFR to the flat model.
regs[APIC_DESTINATION_FORMAT] = (uint32_t)(-1);
- memset(regs, 0, sizeof(regs));
- clear_all();
+ ISRV = 0;
+ IRRV = 0;
}
- Port *getPort(const std::string &if_name, int idx = -1)
+ /*
+ * Functions for retrieving interrupts for the CPU to handle.
+ */
+
+ bool check_interrupts(ThreadContext * tc) const;
+ Fault getInterrupt(ThreadContext * tc);
+ void updateIntrInfo(ThreadContext * tc);
+
+ /*
+ * Serialization.
+ */
+
+ void serialize(std::ostream & os)
{
- if (if_name == "int_port")
- return intPort;
- return BasicPioDevice::getPort(if_name, idx);
+ panic("Interrupts::serialize unimplemented!\n");
}
- int InterruptLevel(uint64_t softint)
+ void unserialize(Checkpoint * cp, const std::string & section)
{
- panic("Interrupts::InterruptLevel unimplemented!\n");
- return 0;
+ panic("Interrupts::unserialize unimplemented!\n");
}
+ /*
+ * Old functions needed for compatability but which will be phased out
+ * eventually.
+ */
void post(int int_num, int index)
{
panic("Interrupts::post unimplemented!\n");
@@ -161,37 +250,12 @@ class Interrupts : public BasicPioDevice, IntDev
void clear(int int_num, int index)
{
- warn("Interrupts::clear unimplemented!\n");
+ panic("Interrupts::clear unimplemented!\n");
}
void clear_all()
{
- warn("Interrupts::clear_all unimplemented!\n");
- }
-
- bool check_interrupts(ThreadContext * tc) const
- {
- return false;
- }
-
- Fault getInterrupt(ThreadContext * tc)
- {
- return NoFault;
- }
-
- void updateIntrInfo(ThreadContext * tc)
- {
- panic("Interrupts::updateIntrInfo unimplemented!\n");
- }
-
- void serialize(std::ostream & os)
- {
- panic("Interrupts::serialize unimplemented!\n");
- }
-
- void unserialize(Checkpoint * cp, const std::string & section)
- {
- panic("Interrupts::unserialize unimplemented!\n");
+ panic("Interrupts::clear_all unimplemented!\n");
}
};
diff --git a/src/arch/x86/intmessage.hh b/src/arch/x86/intmessage.hh
index 64e821a41..a018a997b 100644
--- a/src/arch/x86/intmessage.hh
+++ b/src/arch/x86/intmessage.hh
@@ -44,8 +44,47 @@ namespace X86ISA
Bitfield<15, 8> vector;
Bitfield<18, 16> deliveryMode;
Bitfield<19> destMode;
+ Bitfield<20> level;
+ Bitfield<21> trigger;
EndBitUnion(TriggerIntMessage)
+ namespace DeliveryMode
+ {
+ enum IntDeliveryMode {
+ Fixed = 0,
+ LowestPriority = 1,
+ SMI = 2,
+ NMI = 4,
+ INIT = 5,
+ ExtInt = 7,
+ NumModes
+ };
+
+ static const char * const names[NumModes] = {
+ "Fixed", "LowestPriority", "SMI", "Reserved",
+ "NMI", "INIT", "Reserved", "ExtInt"
+ };
+
+ static inline bool
+ isUnmaskable(int mode)
+ {
+ return (mode == SMI || mode == NMI ||
+ mode == INIT || mode == ExtInt);
+ }
+
+ static inline bool
+ isMaskable(int mode)
+ {
+ return (mode == Fixed || mode == LowestPriority);
+ }
+
+ static inline bool
+ isReserved(int mode)
+ {
+ return !(isMaskable(mode) || isUnmaskable(mode));
+ }
+ }
+
static const Addr TriggerIntOffset = 0;
static inline PacketPtr
diff --git a/src/dev/x86/i82094aa.cc b/src/dev/x86/i82094aa.cc
index 1ae3b01cf..d7f479106 100644
--- a/src/dev/x86/i82094aa.cc
+++ b/src/dev/x86/i82094aa.cc
@@ -146,33 +146,12 @@ X86ISA::I82094AA::signalInterrupt(int line)
return;
} else {
if (DTRACE(I82094AA)) {
- switch(entry.deliveryMode) {
- case 0:
- DPRINTF(I82094AA, "Delivery mode is: Fixed.\n");
- break;
- case 1:
- DPRINTF(I82094AA, "Delivery mode is: Lowest Priority.\n");
- break;
- case 2:
- DPRINTF(I82094AA, "Delivery mode is: SMI.\n");
- break;
- case 3:
+ if (DeliveryMode::isReserved(entry.deliveryMode)) {
fatal("Tried to use reserved delivery mode "
"for IO APIC entry %d.\n", line);
- break;
- case 4:
- DPRINTF(I82094AA, "Delivery mode is: NMI.\n");
- break;
- case 5:
- DPRINTF(I82094AA, "Delivery mode is: INIT.\n");
- break;
- case 6:
- fatal("Tried to use reserved delivery mode "
- "for IO APIC entry %d.\n", line);
- break;
- case 7:
- DPRINTF(I82094AA, "Delivery mode is: ExtINT.\n");
- break;
+ } else {
+ DPRINTF(I82094AA, "Delivery mode is: %s.\n",
+ DeliveryMode::names[entry.deliveryMode]);
}
DPRINTF(I82094AA, "Vector is %#x.\n", entry.vector);
}
@@ -182,6 +161,8 @@ X86ISA::I82094AA::signalInterrupt(int line)
message.vector = entry.vector;
message.deliveryMode = entry.deliveryMode;
message.destMode = entry.destMode;
+ message.level = entry.polarity;
+ message.trigger = entry.trigger;
if (entry.destMode == 0) {
DPRINTF(I82094AA,
diff --git a/src/dev/x86/i8259.hh b/src/dev/x86/i8259.hh
index 1c14e5397..7804fe3b7 100644
--- a/src/dev/x86/i8259.hh
+++ b/src/dev/x86/i8259.hh
@@ -76,7 +76,8 @@ class I8259 : public BasicPioDevice, public IntDev
I8259(Params * p) : BasicPioDevice(p), IntDev(this),
latency(p->pio_latency), output(p->output),
- mode(p->mode), readIRR(true), initControlWord(0)
+ mode(p->mode), IRR(0), ISR(0), IMR(0),
+ readIRR(true), initControlWord(0)
{
pioSize = 2;
}
diff --git a/src/dev/x86/pc.cc b/src/dev/x86/pc.cc
index 4cd81dd50..94fb23e21 100644
--- a/src/dev/x86/pc.cc
+++ b/src/dev/x86/pc.cc
@@ -36,6 +36,7 @@
#include <string>
#include <vector>
+#include "arch/x86/intmessage.hh"
#include "arch/x86/x86_traits.hh"
#include "cpu/intr_control.hh"
#include "dev/terminal.hh"
@@ -78,7 +79,7 @@ Pc::init()
*/
I82094AA & ioApic = *southBridge->ioApic;
I82094AA::RedirTableEntry entry = 0;
- entry.deliveryMode = 0x7;
+ entry.deliveryMode = DeliveryMode::ExtInt;
entry.vector = 0x20;
ioApic.writeReg(0x10, entry.bottomDW);
ioApic.writeReg(0x11, entry.topDW);