X86: Make the local APIC process interrupts and send them to the CPU.

This commit is contained in:
Gabe Black 2008-10-12 13:45:21 -07:00
parent 876f4845f2
commit ec9d3aad71
4 changed files with 121 additions and 33 deletions

View 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:

View 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 *

View 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));

View 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;
}
}