58 #include "debug/LocalApic.hh" 72 int shift = ((conf & 0x8) >> 1) | (conf & 0x3);
73 shift = (shift + 1) % 8;
182 panic(
"Accessed reserved register field %#x.\n", paddr);
195 panic(
"Accessed more than one register at a time in the APIC!\n");
199 "Reading Local APIC register %d at offset %#x as %#x.\n",
201 pkt->
setData(((uint8_t *)&val) + (offset &
mask(3)));
212 panic(
"Accessed more than one register at a time in the APIC!\n");
217 "Writing Local APIC register %d at offset %#x as %#x.\n",
218 reg, offset,
letoh(val));
219 setReg(reg,
letoh(val));
232 if (deliveryMode == DeliveryMode::Fixed ||
233 deliveryMode == DeliveryMode::LowestPriority) {
234 DPRINTF(LocalApic,
"Interrupt is an %s.\n",
235 DeliveryMode::names[deliveryMode]);
247 }
else if (!DeliveryMode::isReserved(deliveryMode)) {
248 DPRINTF(LocalApic,
"Interrupt is an %s.\n",
249 DeliveryMode::names[deliveryMode]);
250 if (deliveryMode == DeliveryMode::SMI && !pendingSmi) {
251 pendingUnmaskableInt = pendingSmi =
true;
253 }
else if (deliveryMode == DeliveryMode::NMI && !pendingNmi) {
254 pendingUnmaskableInt = pendingNmi =
true;
256 }
else if (deliveryMode == DeliveryMode::ExtInt && !pendingExtInt) {
257 pendingExtInt =
true;
259 }
else if (deliveryMode == DeliveryMode::INIT && !pendingInit) {
260 pendingUnmaskableInt = pendingInit =
true;
262 }
else if (deliveryMode == DeliveryMode::SIPI &&
263 !pendingStartup && !startedUp) {
264 pendingUnmaskableInt = pendingStartup =
true;
277 if (cpu != NULL && cpu->cpuId() != newCPU->
cpuId()) {
278 panic(
"Local APICs can't be moved between CPUs" 279 " with different IDs.\n");
282 initialApicId = cpu->
cpuId();
283 regs[
APIC_ID] = (initialApicId << 24);
291 panic_if(!intMasterPort.isConnected(),
292 "Int port not connected to anything!");
294 "Pio port of %s not connected to anything!",
name());
296 intSlavePort.sendRangeChange();
297 pioPort.sendRangeChange();
310 TriggerIntMessage message = pkt->
getRaw<TriggerIntMessage>();
312 "Got Trigger Interrupt message with vector %#x.\n",
315 requestInterrupt(message.vector,
316 message.deliveryMode, message.trigger);
320 panic(
"Local apic got unknown interrupt message at offset %#x.\n",
332 if (--pendingIPIs == 0) {
335 low.deliveryStatus = 0;
338 DPRINTF(LocalApic,
"ICR is now idle.\n");
369 panic(
"Local APIC Trigger Mode registers are unimplemented.\n");
373 panic(
"Local APIC Arbitration Priority register unimplemented.\n");
376 panic(
"Local APIC Processor Priority register unimplemented.\n");
383 if (apicTimerEvent.scheduled()) {
385 uint64_t ticksPerCount = clockPeriod() *
388 uint64_t
val = apicTimerEvent.when() -
curTick();
390 val = (val + ticksPerCount - 1) / ticksPerCount;
405 uint32_t newVal =
val;
408 panic(
"Local APIC In-Service registers are unimplemented.\n");
412 panic(
"Local APIC Trigger Mode registers are unimplemented.\n");
416 panic(
"Local APIC Interrupt Request registers " 417 "are unimplemented.\n");
430 panic(
"Local APIC Arbitration Priority register unimplemented.\n");
433 panic(
"Local APIC Processor Priority register unimplemented.\n");
441 newVal = val & 0xFF000000;
444 newVal = val | 0x0FFFFFFF;
450 warn(
"Focus processor checking not implemented.\n");
468 if (low.deliveryStatus) {
474 TriggerIntMessage message = 0;
475 message.destination = high.destination;
476 message.vector = low.vector;
477 message.deliveryMode = low.deliveryMode;
478 message.destMode = low.destMode;
479 message.level = low.level;
480 message.trigger = low.trigger;
482 int numContexts = sys->numContexts();
483 switch (low.destShorthand) {
485 if (message.deliveryMode == DeliveryMode::LowestPriority) {
486 panic(
"Lowest priority delivery mode " 487 "IPIs aren't implemented.\n");
489 if (message.destMode == 1) {
490 int dest = message.destination;
491 hack_once(
"Assuming logical destinations are 1 << id.\n");
492 for (
int i = 0;
i < numContexts;
i++) {
498 if (message.destination == 0xFF) {
499 for (
int i = 0;
i < numContexts;
i++) {
500 if (
i == initialApicId) {
501 requestInterrupt(message.vector,
502 message.deliveryMode, message.trigger);
508 if (message.destination == initialApicId) {
509 requestInterrupt(message.vector,
510 message.deliveryMode, message.trigger);
512 apics.push_back(message.destination);
519 requestInterrupt(message.vector,
520 message.deliveryMode, message.trigger);
523 requestInterrupt(message.vector,
524 message.deliveryMode, message.trigger);
528 for (
int i = 0;
i < numContexts;
i++) {
529 if (
i != initialApicId) {
538 low.deliveryStatus = 1;
539 pendingIPIs += apics.size();
542 for (
auto id: apics) {
544 intMasterPort.sendMessage(pkt, sys->isTimingMode(),
545 [
this](
PacketPtr pkt) { completeIPI(pkt); });
557 uint64_t readOnlyMask = (1 << 12) | (1 << 14);
558 newVal = (val & ~readOnlyMask) |
559 (regs[reg] & readOnlyMask);
564 newVal =
bits(val, 31, 0);
566 uint64_t newCount = newVal *
571 reschedule(apicTimerEvent,
573 clockPeriod() - offset,
true);
576 reschedule(apicTimerEvent,
578 clockPeriod(),
true);
625 DPRINTF(LocalApic,
"Reported pending unmaskable interrupt.\n");
630 DPRINTF(LocalApic,
"Reported pending external interrupt.\n");
635 DPRINTF(LocalApic,
"Reported pending regular interrupt.\n");
658 DPRINTF(LocalApic,
"Generated SMI fault object.\n");
659 return std::make_shared<SystemManagementInterrupt>();
661 DPRINTF(LocalApic,
"Generated NMI fault object.\n");
662 return std::make_shared<NonMaskableInterrupt>(
nmiVector);
664 DPRINTF(LocalApic,
"Generated INIT fault object.\n");
665 return std::make_shared<InitInterrupt>(
initVector);
667 DPRINTF(LocalApic,
"Generating SIPI fault object.\n");
670 panic(
"pendingUnmaskableInt set, but no unmaskable " 671 "ints were pending.\n");
675 DPRINTF(LocalApic,
"Generated external interrupt fault object.\n");
676 return std::make_shared<ExternalInterrupt>(
extIntVector);
678 DPRINTF(LocalApic,
"Generated regular interrupt fault object.\n");
680 return std::make_shared<ExternalInterrupt>(
IRRV);
690 DPRINTF(LocalApic,
"SMI sent to core.\n");
693 DPRINTF(LocalApic,
"NMI sent to core.\n");
696 DPRINTF(LocalApic,
"Init sent to core.\n");
700 DPRINTF(LocalApic,
"SIPI sent to core.\n");
709 DPRINTF(LocalApic,
"Interrupt %d sent to core.\n",
IRRV);
738 bool apicTimerEventScheduled = apicTimerEvent.scheduled();
740 Tick apicTimerEventTick = apicTimerEvent.when();
763 bool apicTimerEventScheduled;
765 if (apicTimerEventScheduled) {
766 Tick apicTimerEventTick;
768 if (apicTimerEvent.scheduled()) {
769 reschedule(apicTimerEvent, apicTimerEventTick,
true);
771 schedule(apicTimerEvent, apicTimerEventTick);
777 X86LocalApicParams::create()
#define panic(...)
This implements a cprintf based panic() function.
AddrRange RangeSize(Addr start, Addr size)
bool pendingUnmaskableInt
decltype(nullptr) constexpr NoFault
const std::string & name()
void setCPU(BaseCPU *newCPU) override
IntMasterPort< Interrupts > intMasterPort
void completeIPI(PacketPtr pkt)
uint32_t readReg(ApicRegIndex miscReg)
void updateIntrInfo(ThreadContext *tc) override
bool FullSystem
The FullSystem variable can be used to determine the current mode of simulation.
void setReg(ApicRegIndex reg, uint32_t val)
int divideFromConf(uint32_t conf)
int cpuId() const
Reads this CPU's ID.
AddrRangeList getAddrRanges() const
ThreadContext is the external interface to all thread state for anything outside of the CPU...
void init() override
init() is called after all C++ SimObjects have been created and all ports are connected.
#define UNSERIALIZE_SCALAR(scalar)
Tick curTick()
The current simulated tick.
const Addr PhysAddrAPICRangeSize
bool checkInterrupts(ThreadContext *tc) const override
Fault getInterrupt(ThreadContext *tc) override
void setData(const uint8_t *p)
Copy data into the packet from the provided pointer.
static Addr x86InterruptAddress(const uint8_t id, const uint16_t addr)
void makeAtomicResponse()
void setRegArrayBit(ApicRegIndex base, uint8_t vector)
uint64_t Tick
Tick count type.
PioPort< Interrupts > pioPort
void requestInterrupt(uint8_t vector, uint8_t deliveryMode, bool level)
ApicRegIndex decodeAddr(Addr paddr)
void writeData(uint8_t *p) const
Copy data from the packet to the memory at the provided pointer.
void schedule(Event &event, Tick when)
void reschedule(Event &event, Tick when, bool always=false)
static ApicRegIndex APIC_TRIGGER_MODE(int index)
uint32_t regs[NUM_APIC_REGS]
uint64_t Addr
Address type This will probably be moved somewhere else in the near future.
#define ULL(N)
uint64_t constant
A Packet is used to encapsulate a transfer between two objects in the memory system (e...
#define SERIALIZE_ARRAY(member, size)
Tick recvMessage(PacketPtr pkt)
Declaration of top level class for PC platform components.
#define SERIALIZE_SCALAR(scalar)
bool checkInterruptsRaw() const
Check if there are pending interrupts without ignoring the interrupts disabled flag.
AddrRange RangeEx(Addr start, Addr end)
virtual const std::string name() const
#define UNSERIALIZE_ARRAY(member, size)
void serialize(CheckpointOut &cp) const override
Serialize an object.
static ApicRegIndex APIC_IN_SERVICE(int index)
virtual RegVal readMiscRegNoEffect(RegIndex misc_reg) const =0
std::ostream CheckpointOut
This is exposed globally, independent of the ISA.
MemCmd cmd
The command field of the packet.
Tick write(PacketPtr pkt)
T getRaw() const
Get the data in the packet without byte swapping.
BaseInterruptsParams Params
IntSlavePort< Interrupts > intSlavePort
Bitfield< 18, 16 > deliveryMode
static PacketPtr buildIntTriggerPacket(int id, TriggerIntMessage message)
void unserialize(CheckpointIn &cp) override
Unserialize an object.
T bits(T val, int first, int last)
Extract the bitfield from position 'first' to 'last' (inclusive) from 'val' and right justify it...
bool triggerTimerInterrupt()
static Addr x86LocalAPICAddress(const uint8_t id, const uint16_t addr)
#define panic_if(cond,...)
Conditional panic macro that checks the supplied condition and only panics if the condition is true a...
void processApicTimerEvent()
std::shared_ptr< FaultBase > Fault
void clearRegArrayBit(ApicRegIndex base, uint8_t vector)
static ApicRegIndex APIC_INTERRUPT_REQUEST(int index)
AddrRangeList getIntAddrRange() const