X86: Make the local APIC timer event generate an interrupt.

This commit is contained in:
Gabe Black 2008-10-12 23:28:49 -07:00
parent bdc28d793d
commit 33ebd04474
2 changed files with 87 additions and 56 deletions

View file

@ -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.

View file

@ -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;