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)); setReg(reg, gtoh(val));
return latency; 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 Tick
X86ISA::Interrupts::recvMessage(PacketPtr pkt) X86ISA::Interrupts::recvMessage(PacketPtr pkt)
@ -260,49 +302,8 @@ X86ISA::Interrupts::recvMessage(PacketPtr pkt)
assert((message.destMode == 0 && message.destination == id) || assert((message.destMode == 0 && message.destination == id) ||
(bits((int)message.destination, id))); (bits((int)message.destination, id)));
/* requestInterrupt(message.vector,
* Fixed and lowest-priority delivery mode interrupts are handled message.deliveryMode, message.trigger);
* 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;
}
}
} }
break; break;
default: default:
@ -503,10 +504,10 @@ X86ISA::Interrupts::getInterrupt(ThreadContext * tc)
return new SystemManagementInterrupt(); return new SystemManagementInterrupt();
} else if (pendingNmi) { } else if (pendingNmi) {
DPRINTF(LocalApic, "Generated NMI fault object.\n"); DPRINTF(LocalApic, "Generated NMI fault object.\n");
return new NonMaskableInterrupt(nmiMessage.vector); return new NonMaskableInterrupt(nmiVector);
} else if (pendingInit) { } else if (pendingInit) {
DPRINTF(LocalApic, "Generated INIT fault object.\n"); DPRINTF(LocalApic, "Generated INIT fault object.\n");
return new InitInterrupt(initMessage.vector); return new InitInterrupt(initVector);
} else { } else {
panic("pendingUnmaskableInt set, but no unmaskable " panic("pendingUnmaskableInt set, but no unmaskable "
"ints were pending.\n"); "ints were pending.\n");
@ -514,7 +515,7 @@ X86ISA::Interrupts::getInterrupt(ThreadContext * tc)
} }
} else if (pendingExtInt) { } else if (pendingExtInt) {
DPRINTF(LocalApic, "Generated external interrupt fault object.\n"); DPRINTF(LocalApic, "Generated external interrupt fault object.\n");
return new ExternalInterrupt(extIntMessage.vector); return new ExternalInterrupt(extIntVector);
} else { } else {
DPRINTF(LocalApic, "Generated regular interrupt fault object.\n"); DPRINTF(LocalApic, "Generated regular interrupt fault object.\n");
// The only thing left are fixed and lowest priority interrupts. // 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 // Storage for the APIC registers
uint32_t regs[NUM_APIC_REGS]; 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. * Timing related stuff.
*/ */
@ -87,13 +98,20 @@ class Interrupts : public BasicPioDevice, IntDev
class ApicTimerEvent : public Event class ApicTimerEvent : public Event
{ {
private:
Interrupts *localApic;
public: public:
ApicTimerEvent() : Event() ApicTimerEvent(Interrupts *_localApic) :
Event(), localApic(_localApic)
{} {}
void process() 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. * the IRR.
*/ */
bool pendingSmi; bool pendingSmi;
TriggerIntMessage smiMessage; uint8_t smiVector;
bool pendingNmi; bool pendingNmi;
TriggerIntMessage nmiMessage; uint8_t nmiVector;
bool pendingExtInt; bool pendingExtInt;
TriggerIntMessage extIntMessage; uint8_t extIntVector;
bool pendingInit; bool pendingInit;
TriggerIntMessage initMessage; uint8_t initVector;
// This is a quick check whether any of the above (except ExtInt) are set. // This is a quick check whether any of the above (except ExtInt) are set.
bool pendingUnmaskableInt; bool pendingUnmaskableInt;
@ -163,6 +181,8 @@ class Interrupts : public BasicPioDevice, IntDev
return bits(regs[base + (vector % 32)], vector >> 5); return bits(regs[base + (vector % 32)], vector >> 5);
} }
void requestInterrupt(uint8_t vector, uint8_t deliveryMode, bool level);
public: public:
/* /*
* Params stuff. * Params stuff.
@ -187,6 +207,15 @@ class Interrupts : public BasicPioDevice, IntDev
Tick write(PacketPtr pkt); Tick write(PacketPtr pkt);
Tick recvMessage(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) void addressRanges(AddrRangeList &range_list)
{ {
range_list.clear(); range_list.clear();
@ -225,10 +254,11 @@ 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), apicTimerEvent(this),
pendingNmi(false), nmiMessage(0), pendingSmi(false), smiVector(0),
pendingExtInt(false), extIntMessage(0), pendingNmi(false), nmiVector(0),
pendingInit(false), initMessage(0), pendingExtInt(false), extIntVector(0),
pendingInit(false), initVector(0),
pendingUnmaskableInt(false) pendingUnmaskableInt(false)
{ {
pioSize = PageBytes; pioSize = PageBytes;