// 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)
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:
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;
}
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 *
#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"
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.
*/
*/
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));