summaryrefslogtreecommitdiff
path: root/src/arch/x86/interrupts.cc
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/arch/x86/interrupts.cc
parent876f4845f258ed09d348135d8af8cf4a17de1b8a (diff)
downloadgem5-ec9d3aad71ec75b3f7b5ea96dd41f067a9261392.tar.xz
X86: Make the local APIC process interrupts and send them to the CPU.
Diffstat (limited to 'src/arch/x86/interrupts.cc')
-rw-r--r--src/arch/x86/interrupts.cc93
1 files changed, 77 insertions, 16 deletions
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 *