summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGabe Black <gblack@eecs.umich.edu>2008-10-12 13:45:21 -0700
committerGabe Black <gblack@eecs.umich.edu>2008-10-12 13:45:21 -0700
commitec9d3aad71ec75b3f7b5ea96dd41f067a9261392 (patch)
treeace8a36db527092dc6bcde234aad5d85c1e20c17 /src
parent876f4845f258ed09d348135d8af8cf4a17de1b8a (diff)
downloadgem5-ec9d3aad71ec75b3f7b5ea96dd41f067a9261392.tar.xz
X86: Make the local APIC process interrupts and send them to the CPU.
Diffstat (limited to 'src')
-rw-r--r--src/arch/x86/faults.hh22
-rw-r--r--src/arch/x86/interrupts.cc93
-rw-r--r--src/arch/x86/interrupts.hh24
-rw-r--r--src/arch/x86/intmessage.hh15
4 files changed, 121 insertions, 33 deletions
diff --git a/src/arch/x86/faults.hh b/src/arch/x86/faults.hh
index 8fe90299d..b15ad15d1 100644
--- a/src/arch/x86/faults.hh
+++ b/src/arch/x86/faults.hh
@@ -215,9 +215,10 @@ namespace X86ISA
class NonMaskableInterrupt : public X86Interrupt
{
+ uint8_t vector;
public:
- NonMaskableInterrupt() :
- X86Interrupt("Non-Maskable-Interrupt", "#NMI")
+ NonMaskableInterrupt(uint8_t _vector) :
+ X86Interrupt("Non Maskable Interrupt", "#NMI"), vector(_vector)
{}
};
@@ -358,6 +359,23 @@ namespace X86ISA
{}
};
+ class SystemManagementInterrupt : public X86Interrupt
+ {
+ public:
+ SystemManagementInterrupt() :
+ X86Interrupt("System Management Interrupt", "#SMI")
+ {}
+ };
+
+ class InitInterrupt : public X86Interrupt
+ {
+ uint8_t vector;
+ public:
+ InitInterrupt(uint8_t _vector) :
+ X86Interrupt("INIT Interrupt", "#INIT"), vector(_vector)
+ {}
+ };
+
class SoftwareInterrupt : public X86Interrupt
{
public:
diff --git a/src/arch/x86/interrupts.cc b/src/arch/x86/interrupts.cc
index a7c238ace..280fa5dd1 100644
--- a/src/arch/x86/interrupts.cc
+++ b/src/arch/x86/interrupts.cc
@@ -259,12 +259,15 @@ X86ISA::Interrupts::recvMessage(PacketPtr pkt)
// 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",
+
+ /*
+ * Fixed and lowest-priority delivery mode interrupts are handled
+ * using the IRR/ISR registers, checking against the TPR, etc.
+ * The SMI, NMI, ExtInt, INIT, etc interrupts go straight through.
+ */
+ if (message.deliveryMode == DeliveryMode::Fixed ||
+ message.deliveryMode == DeliveryMode::LowestPriority) {
+ DPRINTF(LocalApic, "Interrupt is an %s.\n",
DeliveryMode::names[message.deliveryMode]);
// Queue up the interrupt in the IRR.
if (vector > IRRV)
@@ -279,7 +282,27 @@ X86ISA::Interrupts::recvMessage(PacketPtr pkt)
clearRegArrayBit(APIC_TRIGGER_MODE_BASE, vector);
}
}
- }
+ } else if (!DeliveryMode::isReserved(message.deliveryMode)) {
+ DPRINTF(LocalApic, "Interrupt is an %s.\n",
+ DeliveryMode::names[message.deliveryMode]);
+ if (message.deliveryMode == DeliveryMode::SMI &&
+ !pendingSmi) {
+ pendingUnmaskableInt = pendingSmi = true;
+ smiMessage = message;
+ } else if (message.deliveryMode == DeliveryMode::NMI &&
+ !pendingNmi) {
+ pendingUnmaskableInt = pendingNmi = true;
+ nmiMessage = message;
+ } else if (message.deliveryMode == DeliveryMode::ExtInt &&
+ !pendingExtInt) {
+ pendingExtInt = true;
+ extIntMessage = message;
+ } else if (message.deliveryMode == DeliveryMode::INIT &&
+ !pendingInit) {
+ pendingUnmaskableInt = pendingInit = true;
+ initMessage = message;
+ }
+ }
}
break;
default:
@@ -451,9 +474,14 @@ 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)) {
+ if (pendingUnmaskableInt)
return true;
+ if (rflags.intf) {
+ if (pendingExtInt)
+ return true;
+ if (IRRV > ISRV && bits(IRRV, 7, 4) >
+ bits(regs[APIC_TASK_PRIORITY], 7, 4))
+ return true;
}
return false;
}
@@ -462,19 +490,52 @@ Fault
X86ISA::Interrupts::getInterrupt(ThreadContext * tc)
{
assert(check_interrupts(tc));
- return new ExternalInterrupt(IRRV);
+ // These are all probably fairly uncommon, so we'll make them easier to
+ // check for.
+ if (pendingUnmaskableInt) {
+ if (pendingSmi) {
+ return new SystemManagementInterrupt();
+ } else if (pendingNmi) {
+ return new NonMaskableInterrupt(nmiMessage.vector);
+ } else if (pendingInit) {
+ return new InitInterrupt(initMessage.vector);
+ } else {
+ panic("pendingUnmaskableInt set, but no unmaskable "
+ "ints were pending.\n");
+ return NoFault;
+ }
+ } else if (pendingExtInt) {
+ return new ExternalInterrupt(extIntMessage.vector);
+ } else {
+ // The only thing left are fixed and lowest priority interrupts.
+ 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();
+ if (pendingUnmaskableInt) {
+ if (pendingSmi) {
+ pendingSmi = false;
+ } else if (pendingNmi) {
+ pendingNmi = false;
+ } else if (pendingInit) {
+ pendingInit = false;
+ }
+ if (!(pendingSmi || pendingNmi || pendingInit))
+ pendingUnmaskableInt = false;
+ } else if (pendingExtInt) {
+ pendingExtInt = false;
+ } else {
+ // 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 *
diff --git a/src/arch/x86/interrupts.hh b/src/arch/x86/interrupts.hh
index cfc1ada9d..85a0f6478 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 "arch/x86/intmessage.hh"
#include "base/bitfield.hh"
#include "cpu/thread_context.hh"
#include "dev/io_device.hh"
@@ -99,6 +100,22 @@ class Interrupts : public BasicPioDevice, IntDev
ApicTimerEvent apicTimerEvent;
/*
+ * A set of variables to keep track of interrupts that don't go through
+ * the IRR.
+ */
+ bool pendingSmi;
+ TriggerIntMessage smiMessage;
+ bool pendingNmi;
+ TriggerIntMessage nmiMessage;
+ bool pendingExtInt;
+ TriggerIntMessage extIntMessage;
+ bool pendingInit;
+ TriggerIntMessage initMessage;
+
+ // This is a quick check whether any of the above (except ExtInt) are set.
+ bool pendingUnmaskableInt;
+
+ /*
* IRR and ISR maintenance.
*/
uint8_t IRRV;
@@ -207,7 +224,12 @@ class Interrupts : public BasicPioDevice, IntDev
*/
Interrupts(Params * p) : BasicPioDevice(p), IntDev(this),
- latency(p->pio_latency), clock(0)
+ latency(p->pio_latency), clock(0),
+ pendingSmi(false), smiMessage(0),
+ pendingNmi(false), nmiMessage(0),
+ pendingExtInt(false), extIntMessage(0),
+ pendingInit(false), initMessage(0),
+ pendingUnmaskableInt(false)
{
pioSize = PageBytes;
memset(regs, 0, sizeof(regs));
diff --git a/src/arch/x86/intmessage.hh b/src/arch/x86/intmessage.hh
index a018a997b..6a5b3aa30 100644
--- a/src/arch/x86/intmessage.hh
+++ b/src/arch/x86/intmessage.hh
@@ -66,22 +66,9 @@ namespace X86ISA
};
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));
+ return mode == 3 || mode == 6;
}
}