60 #include "debug/LocalApic.hh" 74 int shift = ((conf & 0x8) >> 1) | (conf & 0x3);
75 shift = (shift + 1) % 8;
184 panic(
"Accessed reserved register field %#x.\n", paddr);
197 panic(
"Accessed more than one register at a time in the APIC!\n");
201 "Reading Local APIC register %d at offset %#x as %#x.\n",
203 pkt->
setData(((uint8_t *)&val) + (offset &
mask(3)));
214 panic(
"Accessed more than one register at a time in the APIC!\n");
219 "Writing Local APIC register %d at offset %#x as %#x.\n",
220 reg, offset,
letoh(val));
221 setReg(reg,
letoh(val));
234 if (deliveryMode == DeliveryMode::Fixed ||
235 deliveryMode == DeliveryMode::LowestPriority) {
236 DPRINTF(LocalApic,
"Interrupt is an %s.\n",
237 DeliveryMode::names[deliveryMode]);
249 }
else if (!DeliveryMode::isReserved(deliveryMode)) {
250 DPRINTF(LocalApic,
"Interrupt is an %s.\n",
251 DeliveryMode::names[deliveryMode]);
252 if (deliveryMode == DeliveryMode::SMI && !pendingSmi) {
253 pendingUnmaskableInt = pendingSmi =
true;
255 }
else if (deliveryMode == DeliveryMode::NMI && !pendingNmi) {
256 pendingUnmaskableInt = pendingNmi =
true;
258 }
else if (deliveryMode == DeliveryMode::ExtInt && !pendingExtInt) {
259 pendingExtInt =
true;
261 }
else if (deliveryMode == DeliveryMode::INIT && !pendingInit) {
262 pendingUnmaskableInt = pendingInit =
true;
264 }
else if (deliveryMode == DeliveryMode::SIPI &&
265 !pendingStartup && !startedUp) {
266 pendingUnmaskableInt = pendingStartup =
true;
279 if (cpu != NULL && cpu->cpuId() != newCPU->
cpuId()) {
280 panic(
"Local APICs can't be moved between CPUs" 281 " with different IDs.\n");
284 initialApicId = cpu->
cpuId();
285 regs[
APIC_ID] = (initialApicId << 24);
293 panic_if(!intMasterPort.isConnected(),
294 "Int port not connected to anything!");
296 "Pio port of %s not connected to anything!",
name());
298 intSlavePort.sendRangeChange();
299 pioPort.sendRangeChange();
312 TriggerIntMessage message = pkt->
getRaw<TriggerIntMessage>();
314 "Got Trigger Interrupt message with vector %#x.\n",
317 requestInterrupt(message.vector,
318 message.deliveryMode, message.trigger);
322 panic(
"Local apic got unknown interrupt message at offset %#x.\n",
334 if (--pendingIPIs == 0) {
337 low.deliveryStatus = 0;
340 DPRINTF(LocalApic,
"ICR is now idle.\n");
371 panic(
"Local APIC Trigger Mode registers are unimplemented.\n");
375 panic(
"Local APIC Arbitration Priority register unimplemented.\n");
378 panic(
"Local APIC Processor Priority register unimplemented.\n");
385 if (apicTimerEvent.scheduled()) {
387 uint64_t ticksPerCount = clockPeriod() *
390 uint64_t
val = apicTimerEvent.when() -
curTick();
392 val = (val + ticksPerCount - 1) / ticksPerCount;
407 uint32_t newVal =
val;
410 panic(
"Local APIC In-Service registers are unimplemented.\n");
414 panic(
"Local APIC Trigger Mode registers are unimplemented.\n");
418 panic(
"Local APIC Interrupt Request registers " 419 "are unimplemented.\n");
432 panic(
"Local APIC Arbitration Priority register unimplemented.\n");
435 panic(
"Local APIC Processor Priority register unimplemented.\n");
443 newVal = val & 0xFF000000;
446 newVal = val | 0x0FFFFFFF;
452 warn(
"Focus processor checking not implemented.\n");
470 if (low.deliveryStatus) {
476 TriggerIntMessage message = 0;
477 message.destination = high.destination;
478 message.vector = low.vector;
479 message.deliveryMode = low.deliveryMode;
480 message.destMode = low.destMode;
481 message.level = low.level;
482 message.trigger = low.trigger;
484 int numContexts = sys->numContexts();
485 switch (low.destShorthand) {
487 if (message.deliveryMode == DeliveryMode::LowestPriority) {
488 panic(
"Lowest priority delivery mode " 489 "IPIs aren't implemented.\n");
491 if (message.destMode == 1) {
492 int dest = message.destination;
493 hack_once(
"Assuming logical destinations are 1 << id.\n");
494 for (
int i = 0;
i < numContexts;
i++) {
500 if (message.destination == 0xFF) {
501 for (
int i = 0;
i < numContexts;
i++) {
502 if (
i == initialApicId) {
503 requestInterrupt(message.vector,
504 message.deliveryMode, message.trigger);
510 if (message.destination == initialApicId) {
511 requestInterrupt(message.vector,
512 message.deliveryMode, message.trigger);
514 apics.push_back(message.destination);
521 requestInterrupt(message.vector,
522 message.deliveryMode, message.trigger);
525 requestInterrupt(message.vector,
526 message.deliveryMode, message.trigger);
530 for (
int i = 0;
i < numContexts;
i++) {
531 if (
i != initialApicId) {
540 low.deliveryStatus = 1;
541 pendingIPIs += apics.size();
544 for (
auto id: apics) {
546 intMasterPort.sendMessage(pkt, sys->isTimingMode(),
547 [
this](
PacketPtr pkt) { completeIPI(pkt); });
559 uint64_t readOnlyMask = (1 << 12) | (1 << 14);
560 newVal = (val & ~readOnlyMask) |
561 (regs[reg] & readOnlyMask);
566 newVal =
bits(val, 31, 0);
568 uint64_t newCount = newVal *
573 reschedule(apicTimerEvent,
575 clockPeriod() - offset,
true);
578 reschedule(apicTimerEvent,
580 clockPeriod(),
true);
627 DPRINTF(LocalApic,
"Reported pending unmaskable interrupt.\n");
632 DPRINTF(LocalApic,
"Reported pending external interrupt.\n");
637 DPRINTF(LocalApic,
"Reported pending regular interrupt.\n");
660 DPRINTF(LocalApic,
"Generated SMI fault object.\n");
661 return std::make_shared<SystemManagementInterrupt>();
663 DPRINTF(LocalApic,
"Generated NMI fault object.\n");
664 return std::make_shared<NonMaskableInterrupt>(
nmiVector);
666 DPRINTF(LocalApic,
"Generated INIT fault object.\n");
667 return std::make_shared<InitInterrupt>(
initVector);
669 DPRINTF(LocalApic,
"Generating SIPI fault object.\n");
672 panic(
"pendingUnmaskableInt set, but no unmaskable " 673 "ints were pending.\n");
677 DPRINTF(LocalApic,
"Generated external interrupt fault object.\n");
678 return std::make_shared<ExternalInterrupt>(
extIntVector);
680 DPRINTF(LocalApic,
"Generated regular interrupt fault object.\n");
682 return std::make_shared<ExternalInterrupt>(
IRRV);
692 DPRINTF(LocalApic,
"SMI sent to core.\n");
695 DPRINTF(LocalApic,
"NMI sent to core.\n");
698 DPRINTF(LocalApic,
"Init sent to core.\n");
702 DPRINTF(LocalApic,
"SIPI sent to core.\n");
711 DPRINTF(LocalApic,
"Interrupt %d sent to core.\n",
IRRV);
740 bool apicTimerEventScheduled = apicTimerEvent.scheduled();
742 Tick apicTimerEventTick = apicTimerEvent.when();
765 bool apicTimerEventScheduled;
767 if (apicTimerEventScheduled) {
768 Tick apicTimerEventTick;
770 if (apicTimerEvent.scheduled()) {
771 reschedule(apicTimerEvent, apicTimerEventTick,
true);
773 schedule(apicTimerEvent, apicTimerEventTick);
779 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)
#define SERIALIZE_ARRAY(member, size)
ApicRegIndex decodeAddr(Addr paddr)
void writeData(uint8_t *p) const
Copy data from the packet to the memory at the provided pointer.
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
virtual const std::string name() const
A Packet is used to encapsulate a transfer between two objects in the memory system (e...
Tick recvMessage(PacketPtr pkt)
Declaration of top level class for PC platform components.
#define SERIALIZE_SCALAR(scalar)
#define UNSERIALIZE_ARRAY(member, size)
bool checkInterruptsRaw() const
Check if there are pending interrupts without ignoring the interrupts disabled flag.
AddrRange RangeEx(Addr start, Addr end)
void reschedule(Event &event, Tick when, bool always=false)
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
void schedule(Event &event, Tick when)
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