arch-x86,dev: Use INTA to get the vector for the IO APIC.

When receiving an ExtInt at the IO APIC, use an INTA and not a direct
pointer to find the vector to use.

Change-Id: I173f99645c3bbd20de9cbeb17e00b4f91ac66089
Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/55695
Reviewed-by: Gabe Black <gabe.black@gmail.com>
Maintainer: Gabe Black <gabe.black@gmail.com>
Tested-by: kokoro <noreply+kokoro@google.com>
This commit is contained in:
Gabe Black
2022-01-20 23:53:25 -08:00
parent 38bb440383
commit db76b935eb
6 changed files with 89 additions and 65 deletions

View File

@@ -88,6 +88,17 @@ namespace X86ISA
return buildIntPacket(addr, message);
}
static inline PacketPtr
buildIntAcknowledgePacket()
{
RequestPtr req = std::make_shared<Request>(
PhysAddrIntA, 1, Request::UNCACHEABLE,
Request::intRequestorId);
PacketPtr pkt = new Packet(req, MemCmd::ReadReq);
pkt->allocate();
return pkt;
}
} // namespace X86ISA
} // namespace gem5

View File

@@ -38,6 +38,5 @@ class I82094AA(BasicPioDevice):
int_requestor = RequestPort("Port for sending interrupt messages")
int_latency = Param.Latency('1ns', \
"Latency for an interrupt to propagate through this device.")
external_int_pic = Param.I8259(NULL, "External PIC, if any")
inputs = VectorIntSinkPin('The pins that drive this IO APIC')

View File

@@ -81,7 +81,6 @@ class SouthBridge(SimObject):
# Tell the devices about each other
self.pic1.slave = self.pic2
self.speaker.i8254 = self.pit
self.io_apic.external_int_pic = self.pic1
# Connect to the bus
self.cmos.pio = bus.mem_side_ports
self.dma1.pio = bus.mem_side_ports

View File

@@ -43,8 +43,7 @@ namespace gem5
{
X86ISA::I82094AA::I82094AA(const Params &p)
: BasicPioDevice(p, 20), extIntPic(p.external_int_pic),
lowestPriorityOffset(0),
: BasicPioDevice(p, 20), lowestPriorityOffset(0),
intRequestPort(name() + ".int_request", this, this, p.int_latency)
{
// This assumes there's only one I/O APIC in the system and since the apic
@@ -179,7 +178,7 @@ X86ISA::I82094AA::readReg(uint8_t offset)
}
void
X86ISA::I82094AA::signalInterrupt(int line)
X86ISA::I82094AA::requestInterrupt(int line)
{
DPRINTF(I82094AA, "Received interrupt %d.\n", line);
assert(line < TableSize);
@@ -187,67 +186,83 @@ X86ISA::I82094AA::signalInterrupt(int line)
if (entry.mask) {
DPRINTF(I82094AA, "Entry was masked.\n");
return;
}
TriggerIntMessage message = 0;
message.destination = entry.dest;
message.deliveryMode = entry.deliveryMode;
message.destMode = entry.destMode;
message.level = entry.polarity;
message.trigger = entry.trigger;
if (entry.deliveryMode == delivery_mode::ExtInt) {
// We need to ask the I8259 for the vector.
PacketPtr pkt = buildIntAcknowledgePacket();
auto on_completion = [this, message](PacketPtr pkt) {
auto msg_copy = message;
msg_copy.vector = pkt->getLE<uint8_t>();
signalInterrupt(msg_copy);
delete pkt;
};
intRequestPort.sendMessage(pkt, sys->isTimingMode(),
on_completion);
} else {
TriggerIntMessage message = 0;
message.destination = entry.dest;
if (entry.deliveryMode == delivery_mode::ExtInt) {
assert(extIntPic);
message.vector = extIntPic->getVector();
} else {
message.vector = entry.vector;
message.vector = entry.vector;
signalInterrupt(message);
}
}
void
X86ISA::I82094AA::signalInterrupt(TriggerIntMessage message)
{
std::list<int> apics;
int numContexts = sys->threads.size();
if (message.destMode == 0) {
if (message.deliveryMode == delivery_mode::LowestPriority) {
panic("Lowest priority delivery mode from the "
"IO APIC aren't supported in physical "
"destination mode.\n");
}
message.deliveryMode = entry.deliveryMode;
message.destMode = entry.destMode;
message.level = entry.polarity;
message.trigger = entry.trigger;
std::list<int> apics;
int numContexts = sys->threads.size();
if (message.destMode == 0) {
if (message.deliveryMode == delivery_mode::LowestPriority) {
panic("Lowest priority delivery mode from the "
"IO APIC aren't supported in physical "
"destination mode.\n");
}
if (message.destination == 0xFF) {
for (int i = 0; i < numContexts; i++) {
apics.push_back(i);
}
} else {
apics.push_back(message.destination);
}
} else {
if (message.destination == 0xFF) {
for (int i = 0; i < numContexts; i++) {
BaseInterrupts *base_int = sys->threads[i]->
getCpuPtr()->getInterruptController(0);
auto *localApic = dynamic_cast<Interrupts *>(base_int);
if ((localApic->readReg(APIC_LOGICAL_DESTINATION) >> 24) &
message.destination) {
apics.push_back(localApic->getInitialApicId());
}
apics.push_back(i);
}
if (message.deliveryMode == delivery_mode::LowestPriority &&
apics.size()) {
// The manual seems to suggest that the chipset just does
// something reasonable for these instead of actually using
// state from the local APIC. We'll just rotate an offset
// through the set of APICs selected above.
uint64_t modOffset = lowestPriorityOffset % apics.size();
lowestPriorityOffset++;
auto apicIt = apics.begin();
while (modOffset--) {
apicIt++;
assert(apicIt != apics.end());
}
int selected = *apicIt;
apics.clear();
apics.push_back(selected);
} else {
apics.push_back(message.destination);
}
} else {
for (int i = 0; i < numContexts; i++) {
BaseInterrupts *base_int = sys->threads[i]->
getCpuPtr()->getInterruptController(0);
auto *localApic = dynamic_cast<Interrupts *>(base_int);
if ((localApic->readReg(APIC_LOGICAL_DESTINATION) >> 24) &
message.destination) {
apics.push_back(localApic->getInitialApicId());
}
}
for (auto id: apics) {
PacketPtr pkt = buildIntTriggerPacket(id, message);
intRequestPort.sendMessage(pkt, sys->isTimingMode());
if (message.deliveryMode == delivery_mode::LowestPriority &&
apics.size()) {
// The manual seems to suggest that the chipset just does
// something reasonable for these instead of actually using
// state from the local APIC. We'll just rotate an offset
// through the set of APICs selected above.
uint64_t modOffset = lowestPriorityOffset % apics.size();
lowestPriorityOffset++;
auto apicIt = apics.begin();
while (modOffset--) {
apicIt++;
assert(apicIt != apics.end());
}
int selected = *apicIt;
apics.clear();
apics.push_back(selected);
}
}
for (auto id: apics) {
PacketPtr pkt = buildIntTriggerPacket(id, message);
intRequestPort.sendMessage(pkt, sys->isTimingMode());
}
}
void
@@ -255,7 +270,7 @@ X86ISA::I82094AA::raiseInterruptPin(int number)
{
assert(number < TableSize);
if (!pinStates[number])
signalInterrupt(number);
requestInterrupt(number);
pinStates[number] = true;
}

View File

@@ -31,6 +31,7 @@
#include <map>
#include "arch/x86/intmessage.hh"
#include "base/bitunion.hh"
#include "dev/x86/intdev.hh"
#include "dev/intpin.hh"
@@ -43,7 +44,6 @@ namespace gem5
namespace X86ISA
{
class I8259;
class Interrupts;
class I82094AA : public BasicPioDevice
@@ -66,8 +66,6 @@ class I82094AA : public BasicPioDevice
EndBitUnion(RedirTableEntry)
protected:
I8259 * extIntPic;
uint8_t regSel;
uint8_t initialApicId;
uint8_t id;
@@ -87,6 +85,8 @@ class I82094AA : public BasicPioDevice
IntRequestPort<I82094AA> intRequestPort;
void signalInterrupt(TriggerIntMessage message);
public:
using Params = I82094AAParams;
@@ -105,7 +105,7 @@ class I82094AA : public BasicPioDevice
bool recvResponse(PacketPtr pkt);
void signalInterrupt(int line);
void requestInterrupt(int line);
void raiseInterruptPin(int number);
void lowerInterruptPin(int number);

View File

@@ -107,7 +107,7 @@ Pc::init()
void
Pc::postConsoleInt()
{
southBridge->ioApic->signalInterrupt(4);
southBridge->ioApic->requestInterrupt(4);
southBridge->pic1->signalInterrupt(4);
}
@@ -121,7 +121,7 @@ Pc::clearConsoleInt()
void
Pc::postPciInt(int line)
{
southBridge->ioApic->signalInterrupt(line);
southBridge->ioApic->requestInterrupt(line);
}
void