From ec9d3aad71ec75b3f7b5ea96dd41f067a9261392 Mon Sep 17 00:00:00 2001 From: Gabe Black Date: Sun, 12 Oct 2008 13:45:21 -0700 Subject: [PATCH] X86: Make the local APIC process interrupts and send them to the CPU. --- src/arch/x86/faults.hh | 22 ++++++++- src/arch/x86/interrupts.cc | 93 +++++++++++++++++++++++++++++++------- src/arch/x86/interrupts.hh | 24 +++++++++- src/arch/x86/intmessage.hh | 15 +----- 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" @@ -98,6 +99,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. */ @@ -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 @@ -65,23 +65,10 @@ namespace X86ISA "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)); + return mode == 3 || mode == 6; } }