X86: Make the local APIC timer event generate an interrupt.
authorGabe Black <gblack@eecs.umich.edu>
Mon, 13 Oct 2008 06:28:49 +0000 (23:28 -0700)
committerGabe Black <gblack@eecs.umich.edu>
Mon, 13 Oct 2008 06:28:49 +0000 (23:28 -0700)
src/arch/x86/interrupts.cc
src/arch/x86/interrupts.hh

index df1b40e5bdec7de236265c7d1ff33bef1a7490c3..bbc6513786fd0fd15253d106823d3be97828dd4b 100644 (file)
@@ -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.
index 85a0f6478c385a41ffcdd1ff3e23570f299c167d..a998e2b12e5c7195d7ff6bc1544b8ede3d787856 100644 (file)
@@ -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;