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