X86: Make the local APIC process interrupts and send them to the CPU.
authorGabe Black <gblack@eecs.umich.edu>
Sun, 12 Oct 2008 20:45:21 +0000 (13:45 -0700)
committerGabe Black <gblack@eecs.umich.edu>
Sun, 12 Oct 2008 20:45:21 +0000 (13:45 -0700)
src/arch/x86/faults.hh
src/arch/x86/interrupts.cc
src/arch/x86/interrupts.hh
src/arch/x86/intmessage.hh

index 8fe90299d9212c40147a62719ace393c3e950ea7..b15ad15d1ca312655d1eef4fff97595fe738311e 100644 (file)
@@ -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:
index a7c238acecb88460a84ed15ffdb9ec587b73ad9f..280fa5dd10c1436427e0cc6b54a5318d0f4e3fd1 100644 (file)
@@ -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 *
index cfc1ada9d9c994f636201598697866a29caf97f1..85a0f6478c385a41ffcdd1ff3e23570f299c167d 100644 (file)
@@ -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));
index a018a997b1f2e00a43fc3881e25b2dbfa1771192..6a5b3aa305100b0fcca66997af2f8528309567f5 100644 (file)
@@ -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;
         }
     }