summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGabe Black <gblack@eecs.umich.edu>2008-10-12 23:28:49 -0700
committerGabe Black <gblack@eecs.umich.edu>2008-10-12 23:28:49 -0700
commit33ebd04474a1042e5cce585802481b6e95a4e92e (patch)
tree58d83cd5d93dff8f5d2f4cf4ed15f1ead1d64adf /src
parentbdc28d793dd9b3407c513fba5c24917aa423f7ca (diff)
downloadgem5-33ebd04474a1042e5cce585802481b6e95a4e92e.tar.xz
X86: Make the local APIC timer event generate an interrupt.
Diffstat (limited to 'src')
-rw-r--r--src/arch/x86/interrupts.cc93
-rw-r--r--src/arch/x86/interrupts.hh50
2 files changed, 87 insertions, 56 deletions
diff --git a/src/arch/x86/interrupts.cc b/src/arch/x86/interrupts.cc
index df1b40e5b..bbc651378 100644
--- a/src/arch/x86/interrupts.cc
+++ b/src/arch/x86/interrupts.cc
@@ -240,6 +240,48 @@ X86ISA::Interrupts::write(PacketPtr pkt)
setReg(reg, gtoh(val));
return latency;
}
+void
+X86ISA::Interrupts::requestInterrupt(uint8_t vector,
+ uint8_t deliveryMode, bool level)
+{
+ /*
+ * 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 (deliveryMode == DeliveryMode::Fixed ||
+ deliveryMode == DeliveryMode::LowestPriority) {
+ DPRINTF(LocalApic, "Interrupt is an %s.\n",
+ DeliveryMode::names[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 (level) {
+ setRegArrayBit(APIC_TRIGGER_MODE_BASE, vector);
+ } else {
+ clearRegArrayBit(APIC_TRIGGER_MODE_BASE, vector);
+ }
+ }
+ } else if (!DeliveryMode::isReserved(deliveryMode)) {
+ DPRINTF(LocalApic, "Interrupt is an %s.\n",
+ DeliveryMode::names[deliveryMode]);
+ if (deliveryMode == DeliveryMode::SMI && !pendingSmi) {
+ pendingUnmaskableInt = pendingSmi = true;
+ smiVector = vector;
+ } else if (deliveryMode == DeliveryMode::NMI && !pendingNmi) {
+ pendingUnmaskableInt = pendingNmi = true;
+ nmiVector = vector;
+ } else if (deliveryMode == DeliveryMode::ExtInt && !pendingExtInt) {
+ pendingExtInt = true;
+ extIntVector = vector;
+ } else if (deliveryMode == DeliveryMode::INIT && !pendingInit) {
+ pendingUnmaskableInt = pendingInit = true;
+ initVector = vector;
+ }
+ }
+}
Tick
X86ISA::Interrupts::recvMessage(PacketPtr pkt)
@@ -260,49 +302,8 @@ X86ISA::Interrupts::recvMessage(PacketPtr pkt)
assert((message.destMode == 0 && message.destination == id) ||
(bits((int)message.destination, id)));
- /*
- * 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)
- 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);
- }
- }
- } 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;
- }
- }
+ requestInterrupt(message.vector,
+ message.deliveryMode, message.trigger);
}
break;
default:
@@ -503,10 +504,10 @@ X86ISA::Interrupts::getInterrupt(ThreadContext * tc)
return new SystemManagementInterrupt();
} else if (pendingNmi) {
DPRINTF(LocalApic, "Generated NMI fault object.\n");
- return new NonMaskableInterrupt(nmiMessage.vector);
+ return new NonMaskableInterrupt(nmiVector);
} else if (pendingInit) {
DPRINTF(LocalApic, "Generated INIT fault object.\n");
- return new InitInterrupt(initMessage.vector);
+ return new InitInterrupt(initVector);
} else {
panic("pendingUnmaskableInt set, but no unmaskable "
"ints were pending.\n");
@@ -514,7 +515,7 @@ X86ISA::Interrupts::getInterrupt(ThreadContext * tc)
}
} else if (pendingExtInt) {
DPRINTF(LocalApic, "Generated external interrupt fault object.\n");
- return new ExternalInterrupt(extIntMessage.vector);
+ return new ExternalInterrupt(extIntVector);
} else {
DPRINTF(LocalApic, "Generated regular interrupt fault object.\n");
// The only thing left are fixed and lowest priority interrupts.
diff --git a/src/arch/x86/interrupts.hh b/src/arch/x86/interrupts.hh
index 85a0f6478..a998e2b12 100644
--- a/src/arch/x86/interrupts.hh
+++ b/src/arch/x86/interrupts.hh
@@ -79,6 +79,17 @@ class Interrupts : public BasicPioDevice, IntDev
// Storage for the APIC registers
uint32_t regs[NUM_APIC_REGS];
+ BitUnion32(LVTEntry)
+ Bitfield<7, 0> vector;
+ Bitfield<10, 8> deliveryMode;
+ Bitfield<12> status;
+ Bitfield<13> polarity;
+ Bitfield<14> remoteIRR;
+ Bitfield<15> trigger;
+ Bitfield<16> masked;
+ Bitfield<17> periodic;
+ EndBitUnion(LVTEntry)
+
/*
* Timing related stuff.
*/
@@ -87,13 +98,20 @@ class Interrupts : public BasicPioDevice, IntDev
class ApicTimerEvent : public Event
{
+ private:
+ Interrupts *localApic;
public:
- ApicTimerEvent() : Event()
+ ApicTimerEvent(Interrupts *_localApic) :
+ Event(), localApic(_localApic)
{}
void process()
{
- warn("Local APIC timer event doesn't do anything!\n");
+ assert(localApic);
+ if (localApic->triggerTimerInterrupt()) {
+ localApic->setReg(APIC_INITIAL_COUNT,
+ localApic->readReg(APIC_INITIAL_COUNT));
+ }
}
};
@@ -104,13 +122,13 @@ class Interrupts : public BasicPioDevice, IntDev
* the IRR.
*/
bool pendingSmi;
- TriggerIntMessage smiMessage;
+ uint8_t smiVector;
bool pendingNmi;
- TriggerIntMessage nmiMessage;
+ uint8_t nmiVector;
bool pendingExtInt;
- TriggerIntMessage extIntMessage;
+ uint8_t extIntVector;
bool pendingInit;
- TriggerIntMessage initMessage;
+ uint8_t initVector;
// This is a quick check whether any of the above (except ExtInt) are set.
bool pendingUnmaskableInt;
@@ -163,6 +181,8 @@ class Interrupts : public BasicPioDevice, IntDev
return bits(regs[base + (vector % 32)], vector >> 5);
}
+ void requestInterrupt(uint8_t vector, uint8_t deliveryMode, bool level);
+
public:
/*
* Params stuff.
@@ -187,6 +207,15 @@ class Interrupts : public BasicPioDevice, IntDev
Tick write(PacketPtr pkt);
Tick recvMessage(PacketPtr pkt);
+ bool
+ triggerTimerInterrupt()
+ {
+ LVTEntry entry = regs[APIC_LVT_TIMER];
+ if (!entry.masked)
+ requestInterrupt(entry.vector, entry.deliveryMode, entry.trigger);
+ return entry.periodic;
+ }
+
void addressRanges(AddrRangeList &range_list)
{
range_list.clear();
@@ -225,10 +254,11 @@ class Interrupts : public BasicPioDevice, IntDev
Interrupts(Params * p) : BasicPioDevice(p), IntDev(this),
latency(p->pio_latency), clock(0),
- pendingSmi(false), smiMessage(0),
- pendingNmi(false), nmiMessage(0),
- pendingExtInt(false), extIntMessage(0),
- pendingInit(false), initMessage(0),
+ apicTimerEvent(this),
+ pendingSmi(false), smiVector(0),
+ pendingNmi(false), nmiVector(0),
+ pendingExtInt(false), extIntVector(0),
+ pendingInit(false), initVector(0),
pendingUnmaskableInt(false)
{
pioSize = PageBytes;