X86: Make the local APIC process interrupts and send them to the CPU.
This commit is contained in:
parent
876f4845f2
commit
ec9d3aad71
4 changed files with 121 additions and 33 deletions
|
@ -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:
|
||||
|
|
|
@ -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 *
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue