X86: Make the local APIC timer event generate an interrupt.
This commit is contained in:
parent
bdc28d793d
commit
33ebd04474
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue