45#include "debug/GIC.hh"
52using namespace ArmISA;
60 cpuInterface(nullptr),
63 peInLowPowerState(true),
65 irqEnabled(
Gicv3::SGI_MAX +
Gicv3::PPI_MAX, false),
66 irqPending(
Gicv3::SGI_MAX +
Gicv3::PPI_MAX, false),
67 irqPendingIspendr(
Gicv3::SGI_MAX +
Gicv3::PPI_MAX, false),
68 irqActive(
Gicv3::SGI_MAX +
Gicv3::PPI_MAX, false),
69 irqPriority(
Gicv3::SGI_MAX +
Gicv3::PPI_MAX, 0),
77 lpiConfigurationTablePtr(0),
79 lpiPendingTablePtr(0),
80 addrRangeSize(
gic->params().gicv4 ? 0x40000 : 0x20000)
100 for (
int i = 0, int_id = first_intid;
i < size;
i++, int_id++) {
109 prio = (prio << 1) & 0xff;
113 value |= prio << (
i * 8);
136 value |= GICR_CTLR_ENABLE_LPIS;
170 (1 << 5) | (last << 4) | (1 << 3) | (1 << 0);
191 uint8_t part_1 = 0x4;
192 return (des_0 << 4) | (part_1 << 0);
205 return (size << 4) | (des_2 << 0);
221 for (
int int_id = 0; int_id < 8 * size; int_id++) {
222 value |= (
irqGroup[int_id] << int_id);
232 for (
int int_id = 0; int_id < 8 * size; int_id++) {
241 value |= (1 << int_id);
252 for (
int int_id = 0; int_id < 8 * size; int_id++) {
270 for (
int int_id = 0; int_id < 8 * size; int_id++) {
289 for (
int i = 0, int_id = first_int_id;
i < 32;
290 i =
i + 2, int_id++) {
312 if (!is_secure_access) {
316 for (
int int_id = 0; int_id < 8 * size; int_id++) {
332 if (!is_secure_access) {
336 for (
int i = 0, int_id = 0;
i < 8 * size;
337 i =
i + 2, int_id++) {
380 gic->
reserved(
"Gicv3Redistributor::read(): invalid offset %#x\n",
addr);
387 bool is_secure_access)
392 for (
int i = 0, int_id = first_intid;
i < size;
i++, int_id++) {
393 uint8_t prio =
bits(
data, (
i + 1) * 8 - 1, (
i * 8));
401 prio = 0x80 | (prio >> 1);
406 DPRINTF(GIC,
"Gicv3Redistributor::write(): "
407 "int_id %d priority %d\n", int_id,
irqPriority[int_id]);
433 DPRINTF(GIC,
"Gicv3Redistributor::write(): "
434 "PE entering in low power state\n");
437 DPRINTF(GIC,
"Gicv3Redistributor::write(): powering up PE\n");
450 for (
int int_id = 0; int_id < 8 * size; int_id++) {
452 DPRINTF(GIC,
"Gicv3Redistributor::write(): "
453 "int_id %d group %d\n", int_id,
irqGroup[int_id]);
459 for (
int int_id = 0; int_id < 8 * size; int_id++) {
473 DPRINTF(GIC,
"Gicv3Redistributor::write(): "
474 "int_id %d enable %i\n", int_id,
irqEnabled[int_id]);
480 for (
int int_id = 0; int_id < 8 * size; int_id++) {
488 bool disable =
data & (1 << int_id) ? 1 : 0;
494 DPRINTF(GIC,
"Gicv3Redistributor::write(): "
495 "int_id %d enable %i\n", int_id,
irqEnabled[int_id]);
501 for (
int int_id = 0; int_id < 8 * size; int_id++) {
509 bool pending =
data & (1 << int_id) ? 1 : 0;
512 DPRINTF(GIC,
"Gicv3Redistributor::write() "
513 "(GICR_ISPENDR0): int_id %d (PPI) "
514 "pending bit set\n", int_id);
524 for (
int int_id = 0; int_id < 8 * size; int_id++) {
532 bool clear =
data & (1 << int_id) ? 1 : 0;
542 for (
int int_id = 0; int_id < 8 * size; int_id++) {
554 DPRINTF(GIC,
"Gicv3Redistributor::write(): "
555 "int_id %d active set\n", int_id);
565 for (
int int_id = 0; int_id < 8 * size; int_id++) {
573 bool clear =
data & (1 << int_id) ? 1 : 0;
577 DPRINTF(GIC,
"Gicv3Redistributor::write(): "
578 "int_id %d active cleared\n", int_id);
593 for (
int i = 0, int_id = first_intid;
i < 8 * size;
594 i =
i + 2, int_id++) {
605 DPRINTF(GIC,
"Gicv3Redistributor::write(): "
606 "int_id %d (PPI) config %d\n",
617 for (
int int_id = 0; int_id < 8 * size; int_id++) {
618 if (!is_secure_access) {
634 if (!is_secure_access) {
637 for (
int i = 0, int_id = 0;
i < 8 * size;
638 i =
i + 2, int_id++) {
707 gic->
reserved(
"Gicv3Redistributor::write(): invalid offset %#x\n",
addr);
719 DPRINTF(GIC,
"Gicv3Redistributor::sendPPInt(): "
720 "int_id %d (PPI) pending bit set\n", int_id);
741 bool forward =
false;
759 forward = (group == int_group) ||
764 if (!forward)
return;
768 DPRINTF(GIC,
"Gicv3ReDistributor::sendSGI(): "
769 "int_id %d (SGI) pending bit set\n", int_id);
820 int_id < cpuInterface->hppi.intid)) {
831 const uint32_t largest_lpi_id = 1 << (
lpiIDBits + 1);
834 uint8_t lpi_pending_table[largest_lpi_id / 8];
835 uint8_t lpi_config_table[number_lpis];
839 sizeof(lpi_pending_table));
843 sizeof(lpi_config_table));
847 uint32_t lpi_pending_entry_byte = lpi_id / 8;
848 uint8_t lpi_pending_entry_bit_position = lpi_id % 8;
849 bool lpi_is_pending = lpi_pending_table[lpi_pending_entry_byte] &
850 1 << lpi_pending_entry_bit_position;
853 LPIConfigurationTableEntry config_entry =
854 lpi_config_table[lpi_configuration_entry_index];
856 bool lpi_is_enable = config_entry.enable;
863 if (lpi_is_pending && lpi_is_enable && group_enabled) {
864 uint8_t lpi_priority = config_entry.priority << 2;
866 if ((lpi_priority < cpuInterface->hppi.prio) ||
892 uint8_t lpi_pending_entry;
895 sizeof(lpi_pending_entry));
897 return lpi_pending_entry;
907 sizeof(lpi_pending_entry));
916 uint8_t lpi_pending_entry_bit_position = lpi_id % 8;
917 bool is_set = lpi_pending_entry & (1 << lpi_pending_entry_bit_position);
931 uint32_t lpi_id =
data & 0xffffffff;
932 uint32_t largest_lpi_id = 1 << (
lpiIDBits + 1);
934 if (lpi_id > largest_lpi_id) {
943 uint8_t lpi_pending_entry_bit_position = lpi_id % 8;
944 bool is_set = lpi_pending_entry & (1 << lpi_pending_entry_bit_position);
953 lpi_pending_entry |= 1 << (lpi_pending_entry_bit_position);
961 lpi_pending_entry &= ~(1 << (lpi_pending_entry_bit_position));
virtual bool blockIntUpdate() const
When trasferring the state between two GICs (essentially writing architectural registers) an interrup...
ArmSystem * getSystem() const
void clearPendingInterrupts(void)
void resetHppi(uint32_t intid)
void deassertWakeRequest(void)
void assertWakeRequest(void)
bool havePendingInterrupts(void) const
bool groupEnabled(Gicv3::GroupId group) const
uint8_t readEntryLPI(uint32_t intid)
static const uint32_t GICR_WAKER_ProcessorSleep
void clearPPInt(uint32_t int_id)
bool isPendingLPI(uint32_t intid)
static const uint32_t GICR_CTLR_DPG1S
std::vector< uint8_t > irqGroup
Gicv3Distributor * distributor
std::vector< uint8_t > irqPriority
uint32_t getAffinity() const
bool canBeSelectedFor1toNInterrupt(Gicv3::GroupId group) const
void activateIRQ(uint32_t int_id)
std::vector< bool > irqActive
Gicv3Redistributor(Gicv3 *gic, uint32_t cpu_id)
static const uint32_t GICR_WAKER_ChildrenAsleep
std::vector< bool > irqPending
std::vector< uint8_t > irqNsacr
void writeEntryLPI(uint32_t intid, uint8_t lpi_entry)
void sendPPInt(uint32_t int_id)
bool isLevelSensitive(uint32_t int_id) const
Gicv3::GroupId getIntGroup(int int_id) const
void serialize(CheckpointOut &cp) const override
Serialize an object.
void copy(Gicv3Registers *from, Gicv3Registers *to)
void deactivateIRQ(uint32_t int_id)
std::vector< bool > irqEnabled
std::vector< Gicv3::IntTriggerType > irqConfig
static const uint32_t SMALLEST_LPI_ID
static const uint32_t GICR_CTLR_DPG1NS
static const uint32_t GICR_CTLR_DPG0
void sendSGI(uint32_t int_id, Gicv3::GroupId group, bool ns)
bool treatAsEdgeTriggered(uint32_t int_id) const
This helper is used to check if an interrupt should be treated as edge triggered in the following sce...
Addr lpiConfigurationTablePtr
static const AddrRange GICR_IPRIORITYR
Gicv3::IntStatus intStatus(uint32_t int_id) const
std::vector< uint8_t > irqGrpmod
Gicv3CPUInterface * cpuInterface
uint64_t read(Addr addr, size_t size, bool is_secure_access)
void write(Addr addr, uint64_t data, size_t size, bool is_secure_access)
void unserialize(CheckpointIn &cp) override
Unserialize an object.
void setClrLPI(uint64_t data, bool set)
std::vector< bool > irqPendingIspendr
static void clearRedistRegister(Gicv3Registers *to, const ArmISA::Affinity &aff, Addr daddr)
static void copyRedistRange(Gicv3Registers *from, Gicv3Registers *to, const ArmISA::Affinity &aff, Addr daddr, size_t size)
static void copyRedistRegister(Gicv3Registers *from, Gicv3Registers *to, const ArmISA::Affinity &aff, Addr daddr)
Gicv3Distributor * getDistributor() const
void reserved(const char *fmt, Args... args) const
Gicv3CPUInterface * getCPUInterface(int cpu_id) const
void readBlob(Addr addr, void *p, uint64_t size) const
Higher level interfaces based on the above.
void writeBlob(Addr addr, const void *p, uint64_t size) const
Same as tryWriteBlob, but insists on success.
PortProxy physProxy
Port to physical memory used for writing object files into ram at boot.
ThreadContext is the external interface to all thread state for anything outside of the CPU.
bool contains(const Addr &a) const
Determine if the range contains an address.
Addr start() const
Get the start address of the range.
Addr size() const
Get the size of the address range.
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 UNSERIALIZE_CONTAINER(member)
#define SERIALIZE_CONTAINER(member)
Affinity getAffinity(ArmSystem *arm_sys, ThreadContext *tc)
Retrieves MPIDR_EL1.
Bitfield< 11, 0 > affinity
Copyright (c) 2024 - Pranith Kumar Copyright (c) 2020 Inria All rights reserved.
std::ostream CheckpointOut
uint64_t Addr
Address type This will probably be moved somewhere else in the near future.
static void activate(const char *expr)
#define UNSERIALIZE_SCALAR(scalar)
#define SERIALIZE_SCALAR(scalar)