X86: Make the local APIC process interrupts and send them to the CPU.
This commit is contained in:
parent
876f4845f2
commit
ec9d3aad71
|
@ -215,9 +215,10 @@ namespace X86ISA
|
||||||
|
|
||||||
class NonMaskableInterrupt : public X86Interrupt
|
class NonMaskableInterrupt : public X86Interrupt
|
||||||
{
|
{
|
||||||
|
uint8_t vector;
|
||||||
public:
|
public:
|
||||||
NonMaskableInterrupt() :
|
NonMaskableInterrupt(uint8_t _vector) :
|
||||||
X86Interrupt("Non-Maskable-Interrupt", "#NMI")
|
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
|
class SoftwareInterrupt : public X86Interrupt
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -259,12 +259,15 @@ X86ISA::Interrupts::recvMessage(PacketPtr pkt)
|
||||||
// Make sure we're really supposed to get this.
|
// Make sure we're really supposed to get this.
|
||||||
assert((message.destMode == 0 && message.destination == id) ||
|
assert((message.destMode == 0 && message.destination == id) ||
|
||||||
(bits((int)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]);
|
* Fixed and lowest-priority delivery mode interrupts are handled
|
||||||
panic("Unmaskable interrupts aren't implemented.\n");
|
* using the IRR/ISR registers, checking against the TPR, etc.
|
||||||
} else if (DeliveryMode::isMaskable(message.deliveryMode)) {
|
* The SMI, NMI, ExtInt, INIT, etc interrupts go straight through.
|
||||||
DPRINTF(LocalApic, "Interrupt is an %s and maskable.\n",
|
*/
|
||||||
|
if (message.deliveryMode == DeliveryMode::Fixed ||
|
||||||
|
message.deliveryMode == DeliveryMode::LowestPriority) {
|
||||||
|
DPRINTF(LocalApic, "Interrupt is an %s.\n",
|
||||||
DeliveryMode::names[message.deliveryMode]);
|
DeliveryMode::names[message.deliveryMode]);
|
||||||
// Queue up the interrupt in the IRR.
|
// Queue up the interrupt in the IRR.
|
||||||
if (vector > IRRV)
|
if (vector > IRRV)
|
||||||
|
@ -279,7 +282,27 @@ X86ISA::Interrupts::recvMessage(PacketPtr pkt)
|
||||||
clearRegArrayBit(APIC_TRIGGER_MODE_BASE, vector);
|
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;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -451,9 +474,14 @@ bool
|
||||||
X86ISA::Interrupts::check_interrupts(ThreadContext * tc) const
|
X86ISA::Interrupts::check_interrupts(ThreadContext * tc) const
|
||||||
{
|
{
|
||||||
RFLAGS rflags = tc->readMiscRegNoEffect(MISCREG_RFLAGS);
|
RFLAGS rflags = tc->readMiscRegNoEffect(MISCREG_RFLAGS);
|
||||||
if (IRRV > ISRV && rflags.intf &&
|
if (pendingUnmaskableInt)
|
||||||
bits(IRRV, 7, 4) > bits(regs[APIC_TASK_PRIORITY], 7, 4)) {
|
|
||||||
return true;
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -462,19 +490,52 @@ Fault
|
||||||
X86ISA::Interrupts::getInterrupt(ThreadContext * tc)
|
X86ISA::Interrupts::getInterrupt(ThreadContext * tc)
|
||||||
{
|
{
|
||||||
assert(check_interrupts(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
|
void
|
||||||
X86ISA::Interrupts::updateIntrInfo(ThreadContext * tc)
|
X86ISA::Interrupts::updateIntrInfo(ThreadContext * tc)
|
||||||
{
|
{
|
||||||
assert(check_interrupts(tc));
|
assert(check_interrupts(tc));
|
||||||
// Mark the interrupt as "in service".
|
if (pendingUnmaskableInt) {
|
||||||
ISRV = IRRV;
|
if (pendingSmi) {
|
||||||
setRegArrayBit(APIC_IN_SERVICE_BASE, ISRV);
|
pendingSmi = false;
|
||||||
// Clear it out of the IRR.
|
} else if (pendingNmi) {
|
||||||
clearRegArrayBit(APIC_INTERRUPT_REQUEST_BASE, IRRV);
|
pendingNmi = false;
|
||||||
updateIRRV();
|
} 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 *
|
X86ISA::Interrupts *
|
||||||
|
|
|
@ -60,6 +60,7 @@
|
||||||
|
|
||||||
#include "arch/x86/apicregs.hh"
|
#include "arch/x86/apicregs.hh"
|
||||||
#include "arch/x86/faults.hh"
|
#include "arch/x86/faults.hh"
|
||||||
|
#include "arch/x86/intmessage.hh"
|
||||||
#include "base/bitfield.hh"
|
#include "base/bitfield.hh"
|
||||||
#include "cpu/thread_context.hh"
|
#include "cpu/thread_context.hh"
|
||||||
#include "dev/io_device.hh"
|
#include "dev/io_device.hh"
|
||||||
|
@ -98,6 +99,22 @@ class Interrupts : public BasicPioDevice, IntDev
|
||||||
|
|
||||||
ApicTimerEvent apicTimerEvent;
|
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.
|
* IRR and ISR maintenance.
|
||||||
*/
|
*/
|
||||||
|
@ -207,7 +224,12 @@ class Interrupts : public BasicPioDevice, IntDev
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Interrupts(Params * p) : BasicPioDevice(p), IntDev(this),
|
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;
|
pioSize = PageBytes;
|
||||||
memset(regs, 0, sizeof(regs));
|
memset(regs, 0, sizeof(regs));
|
||||||
|
|
|
@ -65,23 +65,10 @@ namespace X86ISA
|
||||||
"NMI", "INIT", "Reserved", "ExtInt"
|
"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
|
static inline bool
|
||||||
isReserved(int mode)
|
isReserved(int mode)
|
||||||
{
|
{
|
||||||
return !(isMaskable(mode) || isUnmaskable(mode));
|
return mode == 3 || mode == 6;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue