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;