59#include "debug/LocalApic.hh"
76 int shift = ((conf & 0x8) >> 1) | (conf & 0x3);
186 panic(
"Accessed reserved register field %#x.\n", paddr);
199 panic(
"Accessed more than one register at a time in the APIC!\n");
203 "Reading Local APIC register %d at offset %#x as %#x.\n",
216 panic(
"Accessed more than one register at a time in the APIC!\n");
221 "Writing Local APIC register %d at offset %#x as %#x.\n",
238 DPRINTF(LocalApic,
"Interrupt is an %s.\n",
252 DPRINTF(LocalApic,
"Interrupt is an %s.\n",
254 if (
deliveryMode == delivery_mode::SMI && !pendingSmi) {
255 pendingUnmaskableInt = pendingSmi =
true;
257 }
else if (
deliveryMode == delivery_mode::NMI && !pendingNmi) {
258 pendingUnmaskableInt = pendingNmi =
true;
260 }
else if (
deliveryMode == delivery_mode::ExtInt && !pendingExtInt) {
261 pendingExtInt =
true;
263 }
else if (
deliveryMode == delivery_mode::INIT && !pendingInit) {
264 pendingUnmaskableInt = pendingInit =
true;
267 !pendingStartup && !startedUp) {
268 pendingUnmaskableInt = pendingStartup =
true;
273 tc->getCpuPtr()->wakeup(0);
281 "Asked to raise unrecognized int pin %d.", number);
282 DPRINTF(LocalApic,
"Raised wired interrupt pin LINT%d.\n", number);
284 const LVTEntry entry =
288 DPRINTF(LocalApic,
"The interrupt was masked.\n");
293 auto on_completion = [
this,
dm=entry.deliveryMode,
trigger=entry.trigger](
298 intRequestPort.sendMessage(pkt, sys->isTimingMode(), on_completion);
306 "Asked to lower unrecognized int pin %d.", number);
307 DPRINTF(LocalApic,
"Lowered wired interrupt pin LINT%d.\n", number);
316 "Local APICs can't be moved between CPUs with different IDs.");
321 initialApicId = tc->contextId();
322 regs[
APIC_ID] = (initialApicId << 24);
330 panic_if(!intRequestPort.isConnected(),
331 "Int port not connected to anything!");
333 "Pio port of %s not connected to anything!",
name());
335 intResponsePort.sendRangeChange();
336 pioPort.sendRangeChange();
349 TriggerIntMessage message = pkt->
getRaw<TriggerIntMessage>();
351 "Got Trigger Interrupt message with vector %#x.\n",
354 requestInterrupt(message.vector,
355 message.deliveryMode, message.trigger);
359 panic(
"Local apic got unknown interrupt message at offset %#x.\n",
371 if (--pendingIPIs == 0) {
374 low.deliveryStatus = 0;
377 DPRINTF(LocalApic,
"ICR is now idle.\n");
408 panic(
"Local APIC Trigger Mode registers are unimplemented.\n");
412 panic(
"Local APIC Arbitration Priority register unimplemented.\n");
415 panic(
"Local APIC Processor Priority register unimplemented.\n");
422 if (apicTimerEvent.scheduled()) {
424 uint64_t ticksPerCount = clockPeriod() *
427 uint64_t
val = apicTimerEvent.when() -
curTick();
429 val = (
val + ticksPerCount - 1) / ticksPerCount;
444 uint32_t newVal =
val;
447 panic(
"Local APIC In-Service registers are unimplemented.\n");
451 panic(
"Local APIC Trigger Mode registers are unimplemented.\n");
455 panic(
"Local APIC Interrupt Request registers "
456 "are unimplemented.\n");
469 panic(
"Local APIC Arbitration Priority register unimplemented.\n");
472 panic(
"Local APIC Processor Priority register unimplemented.\n");
480 newVal =
val & 0xFF000000;
483 newVal =
val | 0x0FFFFFFF;
489 warn(
"Focus processor checking not implemented.\n");
507 if (low.deliveryStatus) {
513 TriggerIntMessage message = 0;
514 message.destination = high.destination;
515 message.vector = low.vector;
516 message.deliveryMode = low.deliveryMode;
517 message.destMode = low.destMode;
518 message.level = low.level;
519 message.trigger = low.trigger;
521 int numContexts = sys->threads.size();
522 switch (low.destShorthand) {
524 if (message.deliveryMode == delivery_mode::LowestPriority) {
525 panic(
"Lowest priority delivery mode "
526 "IPIs aren't implemented.\n");
528 if (message.destMode == 1) {
529 int dest = message.destination;
530 hack_once(
"Assuming logical destinations are 1 << id.\n");
531 for (
int i = 0;
i < numContexts;
i++) {
537 if (message.destination == 0xFF) {
538 for (
int i = 0;
i < numContexts;
i++) {
539 if (
i == initialApicId) {
540 requestInterrupt(message.vector,
541 message.deliveryMode, message.trigger);
547 if (message.destination == initialApicId) {
548 requestInterrupt(message.vector,
549 message.deliveryMode, message.trigger);
551 apics.push_back(message.destination);
558 requestInterrupt(message.vector,
559 message.deliveryMode, message.trigger);
562 requestInterrupt(message.vector,
563 message.deliveryMode, message.trigger);
567 for (
int i = 0;
i < numContexts;
i++) {
568 if (
i != initialApicId) {
577 low.deliveryStatus = 1;
578 pendingIPIs += apics.size();
581 for (
auto id: apics) {
583 intRequestPort.sendMessage(pkt, sys->isTimingMode(),
584 [
this](
PacketPtr pkt) { completeIPI(pkt); });
596 uint64_t readOnlyMask = (1 << 12) | (1 << 14);
597 newVal = (
val & ~readOnlyMask) |
598 (regs[
reg] & readOnlyMask);
605 uint64_t newCount = newVal *
610 reschedule(apicTimerEvent,
612 clockPeriod() -
offset,
true);
615 reschedule(apicTimerEvent,
617 clockPeriod(),
true);
638 intResponsePort(
name() +
".int_responder",
this,
this),
639 intRequestPort(
name() +
".int_requestor",
this,
this,
p.int_latency),
640 lint0Pin(
name() +
".lint0", 0,
this, 0),
641 lint1Pin(
name() +
".lint1", 0,
this, 1),
642 pioPort(
this), pioDelay(
p.pio_latency)
644 memset(regs, 0,
sizeof(regs));
669 if (pendingUnmaskableInt) {
670 DPRINTF(LocalApic,
"Reported pending unmaskable interrupt.\n");
675 DPRINTF(LocalApic,
"Reported pending external interrupt.\n");
678 if (IRRV > ISRV &&
bits(IRRV, 7, 4) >
680 DPRINTF(LocalApic,
"Reported pending regular interrupt.\n");
690 return pendingUnmaskableInt || pendingExtInt ||
691 (IRRV > ISRV &&
bits(IRRV, 7, 4) >
698 assert(checkInterrupts());
701 if (pendingUnmaskableInt) {
703 DPRINTF(LocalApic,
"Generated SMI fault object.\n");
704 return std::make_shared<SystemManagementInterrupt>();
705 }
else if (pendingNmi) {
706 DPRINTF(LocalApic,
"Generated NMI fault object.\n");
707 return std::make_shared<NonMaskableInterrupt>(nmiVector);
708 }
else if (pendingInit) {
709 DPRINTF(LocalApic,
"Generated INIT fault object.\n");
710 return std::make_shared<InitInterrupt>(initVector);
711 }
else if (pendingStartup) {
712 DPRINTF(LocalApic,
"Generating SIPI fault object.\n");
713 return std::make_shared<StartupInterrupt>(startupVector);
715 panic(
"pendingUnmaskableInt set, but no unmaskable "
716 "ints were pending.\n");
719 }
else if (pendingExtInt) {
720 DPRINTF(LocalApic,
"Generated external interrupt fault object.\n");
721 return std::make_shared<ExternalInterrupt>(extIntVector);
723 DPRINTF(LocalApic,
"Generated regular interrupt fault object.\n");
725 return std::make_shared<ExternalInterrupt>(IRRV);
732 assert(checkInterrupts());
733 if (pendingUnmaskableInt) {
735 DPRINTF(LocalApic,
"SMI sent to core.\n");
737 }
else if (pendingNmi) {
738 DPRINTF(LocalApic,
"NMI sent to core.\n");
740 }
else if (pendingInit) {
741 DPRINTF(LocalApic,
"Init sent to core.\n");
744 }
else if (pendingStartup) {
745 DPRINTF(LocalApic,
"SIPI sent to core.\n");
746 pendingStartup =
false;
749 if (!(pendingSmi || pendingNmi || pendingInit || pendingStartup))
750 pendingUnmaskableInt =
false;
751 }
else if (pendingExtInt) {
752 pendingExtInt =
false;
754 DPRINTF(LocalApic,
"Interrupt %d sent to core.\n", IRRV);
783 bool apicTimerEventScheduled = apicTimerEvent.scheduled();
785 Tick apicTimerEventTick = apicTimerEvent.when();
808 bool apicTimerEventScheduled;
810 if (apicTimerEventScheduled) {
811 Tick apicTimerEventTick;
813 if (apicTimerEvent.scheduled()) {
814 reschedule(apicTimerEvent, apicTimerEventTick,
true);
816 schedule(apicTimerEvent, apicTimerEventTick);
824 if (triggerTimerInterrupt())
virtual void setThreadContext(ThreadContext *_tc)
A Packet is used to encapsulate a transfer between two objects in the memory system (e....
void setData(const uint8_t *p)
Copy data into the packet from the provided pointer.
T getRaw() const
Get the data in the packet without byte swapping.
void makeAtomicResponse()
MemCmd cmd
The command field of the packet.
T getLE() const
Get the data in the packet byte swapped from little endian to host endian.
void writeData(uint8_t *p) const
Copy data from the packet to the memory at the provided pointer.
ThreadContext is the external interface to all thread state for anything outside of the CPU.
virtual int cpuId() const =0
void unserialize(CheckpointIn &cp) override
Unserialize an object.
Interrupts(const Params &p)
void processApicTimerEvent()
void completeIPI(PacketPtr pkt)
void init() override
init() is called after all C++ SimObjects have been created and all ports are connected.
bool checkInterrupts() const override
AddrRangeList getIntAddrRange() const
void setReg(ApicRegIndex reg, uint32_t val)
AddrRangeList getAddrRanges() const
X86LocalApicParams Params
void updateIntrInfo() override
bool checkInterruptsRaw() const
Check if there are pending interrupts without ignoring the interrupts disabled flag.
Tick recvMessage(PacketPtr pkt)
void raiseInterruptPin(int number)
void requestInterrupt(uint8_t vector, uint8_t deliveryMode, bool level)
void serialize(CheckpointOut &cp) const override
Serialize an object.
Tick write(PacketPtr pkt)
void setThreadContext(ThreadContext *_tc) override
Fault getInterrupt() override
uint32_t readReg(ApicRegIndex miscReg)
void lowerInterruptPin(int number)
AddrRange RangeEx(Addr start, Addr end)
AddrRange RangeSize(Addr start, Addr size)
constexpr T bits(T val, unsigned first, unsigned last)
Extract the bitfield from position 'first' to 'last' (inclusive) from 'val' and right justify it.
#define panic(...)
This implements a cprintf based panic() function.
#define panic_if(cond,...)
Conditional panic macro that checks the supplied condition and only panics if the condition is true a...
#define UNSERIALIZE_ARRAY(member, size)
#define SERIALIZE_ARRAY(member, size)
static ApicRegIndex APIC_TRIGGER_MODE(int index)
static PacketPtr buildIntAcknowledgePacket()
Bitfield< 18, 16 > deliveryMode
const Addr PhysAddrAPICRangeSize
static PacketPtr buildIntTriggerPacket(int id, TriggerIntMessage message)
@ APIC_LOGICAL_DESTINATION
@ APIC_INTERRUPT_COMMAND_HIGH
@ APIC_DESTINATION_FORMAT
@ APIC_INTERRUPT_REQUEST_BASE
@ APIC_INTERRUPT_COMMAND_LOW
@ APIC_LVT_THERMAL_SENSOR
@ APIC_PROCESSOR_PRIORITY
@ APIC_ARBITRATION_PRIORITY
@ APIC_SPURIOUS_INTERRUPT_VECTOR
@ APIC_DIVIDE_CONFIGURATION
@ APIC_LVT_PERFORMANCE_MONITORING_COUNTERS
static ApicRegIndex APIC_INTERRUPT_REQUEST(int index)
static ApicRegIndex APIC_IN_SERVICE(int index)
static Addr x86LocalAPICAddress(const uint8_t id, const uint16_t addr)
ApicRegIndex decodeAddr(Addr paddr)
static Addr x86InterruptAddress(const uint8_t id, const uint16_t addr)
Copyright (c) 2024 - Pranith Kumar Copyright (c) 2020 Inria All rights reserved.
std::shared_ptr< FaultBase > Fault
Tick curTick()
The universal simulation clock.
std::ostream CheckpointOut
int divideFromConf(uint32_t conf)
uint64_t Addr
Address type This will probably be moved somewhere else in the near future.
bool FullSystem
The FullSystem variable can be used to determine the current mode of simulation.
uint64_t Tick
Tick count type.
constexpr decltype(nullptr) NoFault
Declaration of top level class for PC platform components.
#define UNSERIALIZE_SCALAR(scalar)
#define SERIALIZE_SCALAR(scalar)
const std::string & name()