arch-x86: Implement the LINT0 pin for the LAPIC.
This pin should be connected to the master I8259 output which is used to bypass the IOAPIC when it is disabled and the local APIC is in virtual wire mode. This is how the system is supposed to start, and can later be switched into symmetric multiprocessing mode later on by an SMP aware OS (most of them). Only the BSP should have it's LINT0 pin connected to the I8259, since I8259 type interrupts are only usable by a single CPU at a time. Change-Id: I0e3e3338f14d384c26da660cf54779579eb0d641 Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/55696 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:
@@ -42,7 +42,7 @@ from m5.proxy import *
|
||||
|
||||
from m5.objects.BaseInterrupts import BaseInterrupts
|
||||
from m5.objects.ClockDomain import DerivedClockDomain
|
||||
from m5.SimObject import SimObject
|
||||
from m5.objects.IntPin import IntSinkPin
|
||||
|
||||
class X86LocalApic(BaseInterrupts):
|
||||
type = 'X86LocalApic'
|
||||
@@ -57,6 +57,9 @@ class X86LocalApic(BaseInterrupts):
|
||||
int_slave = DeprecatedParam(int_responder,
|
||||
'`int_slave` is now called `int_responder`')
|
||||
|
||||
lint0 = IntSinkPin('Local interrupt pin 0')
|
||||
lint1 = IntSinkPin('Local interrupt pin 1')
|
||||
|
||||
int_latency = Param.Latency('1ns', \
|
||||
"Latency for an interrupt to propagate through this device.")
|
||||
pio = ResponsePort("Programmed I/O port")
|
||||
|
||||
@@ -274,6 +274,40 @@ X86ISA::Interrupts::requestInterrupt(uint8_t vector,
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
X86ISA::Interrupts::raiseInterruptPin(int number)
|
||||
{
|
||||
panic_if(number < 0 || number > 1,
|
||||
"Asked to raise unrecognized int pin %d.", number);
|
||||
DPRINTF(LocalApic, "Raised wired interrupt pin LINT%d.\n", number);
|
||||
|
||||
const LVTEntry entry =
|
||||
regs[(number == 0) ? APIC_LVT_LINT0 : APIC_LVT_LINT1];
|
||||
|
||||
if (entry.masked) {
|
||||
DPRINTF(LocalApic, "The interrupt was masked.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
PacketPtr pkt = buildIntAcknowledgePacket();
|
||||
auto on_completion = [this, dm=entry.deliveryMode, trigger=entry.trigger](
|
||||
PacketPtr pkt) {
|
||||
requestInterrupt(pkt->getLE<uint8_t>(), dm, trigger);
|
||||
delete pkt;
|
||||
};
|
||||
intRequestPort.sendMessage(pkt, sys->isTimingMode(), on_completion);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
X86ISA::Interrupts::lowerInterruptPin(int number)
|
||||
{
|
||||
panic_if(number < 0 || number > 1,
|
||||
"Asked to lower unrecognized int pin %d.", number);
|
||||
DPRINTF(LocalApic, "Lowered wired interrupt pin LINT%d.\n", number);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
X86ISA::Interrupts::setThreadContext(ThreadContext *_tc)
|
||||
{
|
||||
@@ -602,6 +636,8 @@ X86ISA::Interrupts::Interrupts(const Params &p)
|
||||
apicTimerEvent([this]{ processApicTimerEvent(); }, name()),
|
||||
intResponsePort(name() + ".int_responder", this, this),
|
||||
intRequestPort(name() + ".int_requestor", this, this, p.int_latency),
|
||||
lint0Pin(name() + ".lint0", 0, this, 0),
|
||||
lint1Pin(name() + ".lint1", 0, this, 1),
|
||||
pioPort(this), pioDelay(p.pio_latency)
|
||||
{
|
||||
memset(regs, 0, sizeof(regs));
|
||||
|
||||
@@ -56,6 +56,7 @@
|
||||
#include "arch/x86/regs/apic.hh"
|
||||
#include "base/bitfield.hh"
|
||||
#include "cpu/thread_context.hh"
|
||||
#include "dev/intpin.hh"
|
||||
#include "dev/io_device.hh"
|
||||
#include "dev/x86/intdev.hh"
|
||||
#include "params/X86LocalApic.hh"
|
||||
@@ -176,10 +177,14 @@ class Interrupts : public BaseInterrupts
|
||||
|
||||
int initialApicId = 0;
|
||||
|
||||
// Ports for interrupts.
|
||||
// Ports for interrupt messages.
|
||||
IntResponsePort<Interrupts> intResponsePort;
|
||||
IntRequestPort<Interrupts> intRequestPort;
|
||||
|
||||
// Pins for wired interrupts.
|
||||
IntSinkPin<Interrupts> lint0Pin;
|
||||
IntSinkPin<Interrupts> lint1Pin;
|
||||
|
||||
// Port for memory mapped register accesses.
|
||||
PioPort<Interrupts> pioPort;
|
||||
|
||||
@@ -222,8 +227,12 @@ class Interrupts : public BaseInterrupts
|
||||
AddrRangeList getAddrRanges() const;
|
||||
AddrRangeList getIntAddrRange() const;
|
||||
|
||||
Port &getPort(const std::string &if_name,
|
||||
PortID idx=InvalidPortID) override
|
||||
void raiseInterruptPin(int number);
|
||||
void lowerInterruptPin(int number);
|
||||
|
||||
Port &
|
||||
getPort(const std::string &if_name,
|
||||
PortID idx=InvalidPortID) override
|
||||
{
|
||||
if (if_name == "int_requestor") {
|
||||
return intRequestPort;
|
||||
@@ -231,8 +240,13 @@ class Interrupts : public BaseInterrupts
|
||||
return intResponsePort;
|
||||
} else if (if_name == "pio") {
|
||||
return pioPort;
|
||||
} else if (if_name == "lint0") {
|
||||
return lint0Pin;
|
||||
} else if (if_name == "lint1") {
|
||||
return lint1Pin;
|
||||
} else {
|
||||
return SimObject::getPort(if_name, idx);
|
||||
}
|
||||
return SimObject::getPort(if_name, idx);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
Reference in New Issue
Block a user