dev-arm: Add a GICv3 model

Change-Id: Ib0067fc743f84ff7be9f12d2fc33ddf63736bdd1
Reviewed-on: https://gem5-review.googlesource.com/c/13436
Reviewed-by: Giacomo Travaglini <giacomo.travaglini@arm.com>
Maintainer: Giacomo Travaglini <giacomo.travaglini@arm.com>
This commit is contained in:
Jairo Balart
2018-10-11 16:05:12 +02:00
committed by Giacomo Travaglini
parent 7d5696d1a9
commit 93c7fa5731
19 changed files with 6811 additions and 9 deletions

View File

@@ -160,3 +160,15 @@ class VGic(PioDevice):
node.appendPhandle(gic)
yield node
class Gicv3(BaseGic):
type = 'Gicv3'
cxx_header = "dev/arm/gic_v3.hh"
dist_addr = Param.Addr(0x2c000000, "Address for distributor")
dist_pio_delay = Param.Latency('10ns', "Delay for PIO r/w to distributor")
redist_addr = Param.Addr(0x2c010000, "Address for redistributors")
redist_pio_delay = Param.Latency('10ns',
"Delay for PIO r/w to redistributors")
it_lines = Param.UInt32(1020,
"Number of interrupt lines supported (max = 1020)")

View File

@@ -57,6 +57,10 @@ if env['TARGET_ISA'] == 'arm':
Source('generic_timer.cc')
Source('gic_v2.cc')
Source('gic_v2m.cc')
Source('gic_v3.cc')
Source('gic_v3_cpu_interface.cc')
Source('gic_v3_distributor.cc')
Source('gic_v3_redistributor.cc')
Source('pl011.cc')
Source('pl111.cc')
Source('hdlcd.cc')

View File

@@ -64,6 +64,13 @@ BaseGic::~BaseGic()
{
}
void
BaseGic::init()
{
PioDevice::init();
getSystem()->setGIC(this);
}
const BaseGic::Params *
BaseGic::params() const
{

View File

@@ -46,6 +46,7 @@
#include <unordered_map>
#include "arch/arm/system.hh"
#include "dev/io_device.hh"
class Platform;
@@ -67,6 +68,7 @@ class BaseGic : public PioDevice
BaseGic(const Params *p);
virtual ~BaseGic();
void init() override;
const Params * params() const;
@@ -99,6 +101,12 @@ class BaseGic : public PioDevice
*/
virtual void clearInt(uint32_t num) = 0;
ArmSystem *
getSystem() const
{
return (ArmSystem *) sys;
}
protected:
/** Platform this GIC belongs to. */
Platform *platform;

275
src/dev/arm/gic_v3.cc Normal file
View File

@@ -0,0 +1,275 @@
/*
* Copyright (c) 2018 Metempsy Technology Consulting
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: Jairo Balart
*/
#include "dev/arm/gic_v3.hh"
#include "cpu/intr_control.hh"
#include "debug/GIC.hh"
#include "debug/Interrupt.hh"
#include "dev/arm/gic_v3_cpu_interface.hh"
#include "dev/arm/gic_v3_distributor.hh"
#include "dev/arm/gic_v3_redistributor.hh"
#include "dev/platform.hh"
#include "mem/packet.hh"
#include "mem/packet_access.hh"
Gicv3::Gicv3(const Params * p)
: BaseGic(p)
{
}
Gicv3::~Gicv3()
{
}
void
Gicv3::init()
{
distRange = RangeSize(params()->dist_addr,
Gicv3Distributor::ADDR_RANGE_SIZE - 1);
redistRange = RangeSize(params()->redist_addr,
Gicv3Redistributor::ADDR_RANGE_SIZE * sys->numContexts() - 1);
addrRanges = {distRange, redistRange};
BaseGic::init();
distributor = new Gicv3Distributor(this, params()->it_lines);
redistributors.resize(sys->numContexts(), nullptr);
cpuInterfaces.resize(sys->numContexts(), nullptr);
for (int i = 0; i < sys->numContexts(); i++) {
redistributors[i] = new Gicv3Redistributor(this, i);
cpuInterfaces[i] = new Gicv3CPUInterface(this, i);
}
distributor->init();
for (int i = 0; i < sys->numContexts(); i++) {
redistributors[i]->init();
cpuInterfaces[i]->init();
}
}
void
Gicv3::initState()
{
distributor->initState();
for (int i = 0; i < sys->numContexts(); i++) {
redistributors[i]->initState();
cpuInterfaces[i]->initState();
}
}
Tick
Gicv3::read(PacketPtr pkt)
{
const Addr addr = pkt->getAddr();
const size_t size = pkt->getSize();
const ContextID context_id = pkt->req->contextId();
bool is_secure_access = pkt->isSecure();
uint64_t resp = 0;
Tick delay = 0;
if (distRange.contains(addr)) {
const Addr daddr = addr - distRange.start();
panic_if(!distributor, "Distributor is null!");
resp = distributor->read(daddr, size, is_secure_access);
delay = params()->dist_pio_delay;
DPRINTF(GIC, "Gicv3::read(): (distributor) context_id %d register %#x "
"size %d is_secure_access %d (value %#x)\n",
context_id, daddr, size, is_secure_access, resp);
} else if (redistRange.contains(addr)) {
Addr daddr = addr - redistRange.start();
uint32_t redistributor_id =
daddr / Gicv3Redistributor::ADDR_RANGE_SIZE;
daddr = daddr % Gicv3Redistributor::ADDR_RANGE_SIZE;
panic_if(redistributor_id >= redistributors.size(),
"Invalid redistributor_id!");
panic_if(!redistributors[redistributor_id], "Redistributor is null!");
resp = redistributors[redistributor_id]->read(daddr, size,
is_secure_access);
delay = params()->redist_pio_delay;
DPRINTF(GIC, "Gicv3::read(): (redistributor %d) context_id %d "
"register %#x size %d is_secure_access %d (value %#x)\n",
redistributor_id, context_id, daddr, size, is_secure_access,
resp);
} else {
panic("Gicv3::read(): unknown address %#x\n", addr);
}
pkt->setUintX(resp, LittleEndianByteOrder);
pkt->makeAtomicResponse();
return delay;
}
Tick
Gicv3::write(PacketPtr pkt)
{
const size_t size = pkt->getSize();
uint64_t data = pkt->getUintX(LittleEndianByteOrder);
const Addr addr = pkt->getAddr();
const ContextID context_id = pkt->req->contextId();
bool is_secure_access = pkt->isSecure();
Tick delay = 0;
if (distRange.contains(addr)) {
const Addr daddr = addr - distRange.start();
panic_if(!distributor, "Distributor is null!");
DPRINTF(GIC, "Gicv3::write(): (distributor) context_id %d "
"register %#x size %d is_secure_access %d value %#x\n",
context_id, daddr, size, is_secure_access, data);
distributor->write(daddr, data, size, is_secure_access);
delay = params()->dist_pio_delay;
} else if (redistRange.contains(addr)) {
Addr daddr = addr - redistRange.start();
uint32_t redistributor_id =
daddr / Gicv3Redistributor::ADDR_RANGE_SIZE;
daddr = daddr % Gicv3Redistributor::ADDR_RANGE_SIZE;
panic_if(redistributor_id >= redistributors.size(),
"Invalid redistributor_id!");
panic_if(!redistributors[redistributor_id], "Redistributor is null!");
DPRINTF(GIC, "Gicv3::write(): (redistributor %d) context_id %d "
"register %#x size %d is_secure_access %d value %#x\n",
redistributor_id, context_id, daddr, size, is_secure_access,
data);
redistributors[redistributor_id]->write(daddr, data, size,
is_secure_access);
delay = params()->redist_pio_delay;
} else {
panic("Gicv3::write(): unknown address %#x\n", addr);
}
pkt->makeAtomicResponse();
return delay;
}
void
Gicv3::sendInt(uint32_t int_id)
{
panic_if(int_id < Gicv3::SGI_MAX + Gicv3::PPI_MAX, "Invalid SPI!");
panic_if(int_id >= Gicv3::INTID_SECURE, "Invalid SPI!");
DPRINTF(Interrupt, "Gicv3::sendInt(): received SPI %d\n", int_id);
distributor->sendInt(int_id);
}
void
Gicv3::clearInt(uint32_t number)
{
distributor->intDeasserted(number);
}
void
Gicv3::sendPPInt(uint32_t int_id, uint32_t cpu)
{
panic_if(cpu >= redistributors.size(), "Invalid cpuID sending PPI!");
panic_if(int_id < Gicv3::SGI_MAX, "Invalid PPI!");
panic_if(int_id >= Gicv3::SGI_MAX + Gicv3::PPI_MAX, "Invalid PPI!");
DPRINTF(Interrupt, "Gicv3::sendPPInt(): received PPI %d cpuTarget %#x\n",
int_id, cpu);
redistributors[cpu]->sendPPInt(int_id);
}
void
Gicv3::clearPPInt(uint32_t num, uint32_t cpu)
{
}
void
Gicv3::postInt(uint32_t cpu, ArmISA::InterruptTypes int_type)
{
postDelayedInt(cpu, int_type);
}
void
Gicv3::deassertInt(uint32_t cpu, ArmISA::InterruptTypes int_type)
{
platform->intrctrl->clear(cpu, int_type, 0);
}
void
Gicv3::postDelayedInt(uint32_t cpu, ArmISA::InterruptTypes int_type)
{
platform->intrctrl->post(cpu, int_type, 0);
}
Gicv3Redistributor *
Gicv3::getRedistributorByAffinity(uint32_t affinity)
{
for (auto & redistributor : redistributors) {
if (redistributor->getAffinity() == affinity) {
return redistributor;
}
}
return nullptr;
}
void
Gicv3::serialize(CheckpointOut & cp) const
{
distributor->serializeSection(cp, "distributor");
for (uint32_t redistributor_id = 0;
redistributor_id < redistributors.size();
redistributor_id++)
redistributors[redistributor_id]->serializeSection(cp,
csprintf("redistributors.%i", redistributor_id));
for (uint32_t cpu_interface_id = 0;
cpu_interface_id < cpuInterfaces.size();
cpu_interface_id++)
cpuInterfaces[cpu_interface_id]->serializeSection(cp,
csprintf("cpuInterface.%i", cpu_interface_id));
}
void
Gicv3::unserialize(CheckpointIn & cp)
{
getSystem()->setGIC(this);
distributor->unserializeSection(cp, "distributor");
for (uint32_t redistributor_id = 0;
redistributor_id < redistributors.size();
redistributor_id++)
redistributors[redistributor_id]->unserializeSection(cp,
csprintf("redistributors.%i", redistributor_id));
for (uint32_t cpu_interface_id = 0;
cpu_interface_id < cpuInterfaces.size();
cpu_interface_id++)
cpuInterfaces[cpu_interface_id]->unserializeSection(cp,
csprintf("cpuInterface.%i", cpu_interface_id));
}
Gicv3 *
Gicv3Params::create()
{
return new Gicv3(this);
}

142
src/dev/arm/gic_v3.hh Normal file
View File

@@ -0,0 +1,142 @@
/*
* Copyright (c) 2018 Metempsy Technology Consulting
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: Jairo Balart
*/
#ifndef __DEV_ARM_GICV3_H__
#define __DEV_ARM_GICV3_H__
#include "dev/arm/base_gic.hh"
#include "params/Gicv3.hh"
class Gicv3Distributor;
class Gicv3Redistributor;
class Gicv3CPUInterface;
class Gicv3 : public BaseGic
{
protected:
Gicv3Distributor * distributor;
std::vector<Gicv3Redistributor *> redistributors;
std::vector<Gicv3CPUInterface *> cpuInterfaces;
AddrRange distRange;
AddrRange redistRange;
AddrRangeList addrRanges;
public:
// Special interrupt IDs
static const int INTID_SECURE = 1020;
static const int INTID_NONSECURE = 1021;
static const int INTID_SPURIOUS = 1023;
// Number of Software Generated Interrupts
static const int SGI_MAX = 16;
// Number of Private Peripheral Interrupts
static const int PPI_MAX = 16;
typedef enum {
INT_INACTIVE,
INT_PENDING,
INT_ACTIVE,
INT_ACTIVE_PENDING,
} IntStatus;
typedef enum {
G0S,
G1S,
G1NS,
} GroupId;
typedef enum {
INT_LEVEL_SENSITIVE,
INT_EDGE_TRIGGERED,
} IntTriggerType;
typedef Gicv3Params Params;
const Params *
params() const
{
return dynamic_cast<const Params *>(_params);
}
Gicv3(const Params * p);
~Gicv3();
void init() override;
void initState() override;
AddrRangeList
getAddrRanges() const override
{
return addrRanges;
}
Tick read(PacketPtr pkt) override;
Tick write(PacketPtr pkt) override;
void sendInt(uint32_t int_id) override;
void clearInt(uint32_t int_id) override;
void sendPPInt(uint32_t int_id, uint32_t cpu) override;
void clearPPInt(uint32_t int_id, uint32_t cpu) override;
void serialize(CheckpointOut & cp) const override;
void unserialize(CheckpointIn & cp) override;
Gicv3Distributor *
getDistributor() const
{
return distributor;
}
Gicv3CPUInterface *
getCPUInterface(int cpu_id) const
{
assert(cpu_id < cpuInterfaces.size() and cpuInterfaces[cpu_id]);
return cpuInterfaces[cpu_id];
}
Gicv3Redistributor *
getRedistributor(ContextID context_id) const
{
assert(context_id < redistributors.size() and
redistributors[context_id]);
return redistributors[context_id];
}
Gicv3Redistributor * getRedistributorByAffinity(uint32_t affinity);
void postInt(uint32_t cpu, ArmISA::InterruptTypes int_type);
void postDelayedInt(uint32_t cpu, ArmISA::InterruptTypes int_type);
void deassertInt(uint32_t cpu, ArmISA::InterruptTypes int_type);
protected:
void reset();
};
#endif //__DEV_ARM_GICV3_H__

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,301 @@
/*
* Copyright (c) 2018 Metempsy Technology Consulting
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: Jairo Balart
*/
#ifndef __DEV_ARM_GICV3_CPU_INTERFACE_H__
#define __DEV_ARM_GICV3_CPU_INTERFACE_H__
#include "arch/arm/isa_device.hh"
#include "dev/arm/gic_v3.hh"
class Gicv3Redistributor;
class Gicv3Distributor;
class Gicv3CPUInterface : public ArmISA::BaseISADevice, public Serializable
{
private:
friend class Gicv3Redistributor;
friend class Gicv3Distributor;
protected:
Gicv3 * gic;
Gicv3Redistributor * redistributor;
Gicv3Distributor * distributor;
uint32_t cpuId;
static const uint32_t ICC_SRE_EL1_SRE = 1 << 0;
static const uint32_t ICC_SRE_EL1_DFB = 1 << 1;
static const uint32_t ICC_SRE_EL1_DIB = 1 << 2;
static const uint32_t ICC_SRE_EL2_SRE = 1 << 0;
static const uint32_t ICC_SRE_EL2_DFB = 1 << 1;
static const uint32_t ICC_SRE_EL2_DIB = 1 << 2;
static const uint32_t ICC_SRE_EL2_ENABLE = 1 << 3;
static const uint32_t ICC_SRE_EL3_SRE = 1 << 0;
static const uint32_t ICC_SRE_EL3_DFB = 1 << 1;
static const uint32_t ICC_SRE_EL3_DIB = 1 << 2;
static const uint32_t ICC_SRE_EL3_ENABLE = 1 << 3;
static const uint32_t ICC_CTLR_EL3_CBPR_EL1S = 1 << 0;
static const uint32_t ICC_CTLR_EL3_CBPR_EL1NS = 1 << 1;
static const uint32_t ICC_CTLR_EL3_EOIMODE_EL3 = 1 << 2;
static const uint32_t ICC_CTLR_EL3_EOIMODE_EL1S = 1 << 3;
static const uint32_t ICC_CTLR_EL3_EOIMODE_EL1NS = 1 << 4;
static const uint32_t ICC_CTLR_EL3_RM = 1 << 5;
static const uint32_t ICC_CTLR_EL3_PMHE = 1 << 6;
static const uint32_t ICC_CTLR_EL3_PRIBITS_SHIFT = 8;
static const uint32_t ICC_CTLR_EL3_IDBITS_SHIFT = 11;
static const uint32_t ICC_CTLR_EL3_SEIS = 1 << 14;
static const uint32_t ICC_CTLR_EL3_A3V = 1 << 15;
static const uint32_t ICC_CTLR_EL3_nDS = 1 << 17;
static const uint32_t ICC_CTLR_EL3_RSS = 1 << 18;
static const uint32_t ICC_CTLR_EL1_CBPR = 1 << 0;
static const uint32_t ICC_CTLR_EL1_EOIMODE = 1 << 1;
static const uint32_t ICC_CTLR_EL1_PMHE = 1 << 6;
static const uint32_t ICC_CTLR_EL1_SEIS = 1 << 14;
static const uint32_t ICC_CTLR_EL1_A3V = 1 << 15;
static const uint32_t ICC_CTLR_EL1_RSS = 1 << 18;
static const uint32_t ICC_CTLR_EL1_PRIBITS_SHIFT = 8;
static const uint32_t ICC_CTLR_EL1_PRIBITS_MASK =
7U << ICC_CTLR_EL1_PRIBITS_SHIFT;
static const uint32_t ICC_CTLR_EL1_IDBITS_SHIFT = 11;
static const uint32_t ICC_IGRPEN0_EL1_ENABLE = 1 << 0;
static const uint32_t ICC_IGRPEN1_EL1_ENABLE = 1 << 0;
static const uint32_t ICC_IGRPEN1_EL3_ENABLEGRP1NS = 1 << 0;
static const uint32_t ICC_IGRPEN1_EL3_ENABLEGRP1S = 1 << 1;
static const uint8_t PRIORITY_BITS = 5;
/* Minimum BPR for Secure, or when security not enabled */
static const uint8_t GIC_MIN_BPR = 2;
/* Minimum BPR for Nonsecure when security is enabled */
static const uint8_t GIC_MIN_BPR_NS = GIC_MIN_BPR + 1;
static const uint8_t VIRTUAL_PRIORITY_BITS = 5;
static const uint8_t VIRTUAL_PREEMPTION_BITS = 5;
static const uint8_t VIRTUAL_NUM_LIST_REGS = 16;
static const uint8_t GIC_MIN_VBPR = 7 - VIRTUAL_PREEMPTION_BITS;
typedef struct {
uint32_t intid;
uint8_t prio;
Gicv3::GroupId group;
} hppi_t;
hppi_t hppi;
// GIC CPU interface memory mapped control registers (legacy)
enum {
GICC_CTLR = 0x0000,
GICC_PMR = 0x0004,
GICC_BPR = 0x0008,
GICC_IAR = 0x000C,
GICC_EOIR = 0x0010,
GICC_RPR = 0x0014,
GICC_HPPI = 0x0018,
GICC_ABPR = 0x001C,
GICC_AIAR = 0x0020,
GICC_AEOIR = 0x0024,
GICC_AHPPIR = 0x0028,
GICC_STATUSR = 0x002C,
GICC_IIDR = 0x00FC,
};
static const AddrRange GICC_APR;
static const AddrRange GICC_NSAPR;
// GIC CPU virtual interface memory mapped control registers (legacy)
enum {
GICH_HCR = 0x0000,
GICH_VTR = 0x0004,
GICH_VMCR = 0x0008,
GICH_MISR = 0x0010,
GICH_EISR = 0x0020,
GICH_ELRSR = 0x0030,
};
static const AddrRange GICH_APR;
static const AddrRange GICH_LR;
static const uint32_t ICH_HCR_EL2_EN = 1 << 0;
static const uint32_t ICH_HCR_EL2_UIE = 1 << 1;
static const uint32_t ICH_HCR_EL2_LRENPIE = 1 << 2;
static const uint32_t ICH_HCR_EL2_NPIE = 1 << 3;
static const uint32_t ICH_HCR_EL2_VGRP0EIE = 1 << 4;
static const uint32_t ICH_HCR_EL2_VGRP0DIE = 1 << 5;
static const uint32_t ICH_HCR_EL2_VGRP1EIE = 1 << 6;
static const uint32_t ICH_HCR_EL2_VGRP1DIE = 1 << 7;
static const uint32_t ICH_HCR_EL2_TC = 1 << 10;
static const uint32_t ICH_HCR_EL2_TALL0 = 1 << 11;
static const uint32_t ICH_HCR_EL2_TALL1 = 1 << 12;
static const uint32_t ICH_HCR_EL2_TSEI = 1 << 13;
static const uint32_t ICH_HCR_EL2_TDIR = 1 << 14;
static const uint32_t ICH_HCR_EL2_EOICOUNT_MASK = 0x1fU << 27;
static const uint64_t ICH_LR_EL2_VINTID_SHIFT = 0;
static const uint64_t ICH_LR_EL2_VINTID_LENGTH = 32;
static const uint64_t ICH_LR_EL2_VINTID_MASK =
(0xffffffffULL << ICH_LR_EL2_VINTID_SHIFT);
static const uint64_t ICH_LR_EL2_PINTID_SHIFT = 32;
static const uint64_t ICH_LR_EL2_PINTID_LENGTH = 10;
static const uint64_t ICH_LR_EL2_PINTID_MASK =
(0x3ffULL << ICH_LR_EL2_PINTID_SHIFT);
/* Note that EOI shares with the top bit of the pINTID field */
static const uint64_t ICH_LR_EL2_EOI = (1ULL << 41);
static const uint64_t ICH_LR_EL2_PRIORITY_SHIFT = 48;
static const uint64_t ICH_LR_EL2_PRIORITY_LENGTH = 8;
static const uint64_t ICH_LR_EL2_PRIORITY_MASK =
(0xffULL << ICH_LR_EL2_PRIORITY_SHIFT);
static const uint64_t ICH_LR_EL2_GROUP = (1ULL << 60);
static const uint64_t ICH_LR_EL2_HW = (1ULL << 61);
static const uint64_t ICH_LR_EL2_STATE_SHIFT = 62;
static const uint64_t ICH_LR_EL2_STATE_LENGTH = 2;
static const uint64_t ICH_LR_EL2_STATE_MASK =
(3ULL << ICH_LR_EL2_STATE_SHIFT);
/* values for the state field: */
static const uint64_t ICH_LR_EL2_STATE_INVALID = 0;
static const uint64_t ICH_LR_EL2_STATE_PENDING = 1;
static const uint64_t ICH_LR_EL2_STATE_ACTIVE = 2;
static const uint64_t ICH_LR_EL2_STATE_ACTIVE_PENDING = 3;
static const uint64_t ICH_LR_EL2_STATE_PENDING_BIT =
(1ULL << ICH_LR_EL2_STATE_SHIFT);
static const uint64_t ICH_LR_EL2_STATE_ACTIVE_BIT =
(2ULL << ICH_LR_EL2_STATE_SHIFT);
static const uint64_t ICH_LRC_PRIORITY_SHIFT =
ICH_LR_EL2_PRIORITY_SHIFT - 32;
static const uint64_t ICH_LRC_PRIORITY_LENGTH =
ICH_LR_EL2_PRIORITY_LENGTH;
static const uint32_t ICH_MISR_EL2_EOI = (1 << 0);
static const uint32_t ICH_MISR_EL2_U = (1 << 1);
static const uint32_t ICH_MISR_EL2_LRENP = (1 << 2);
static const uint32_t ICH_MISR_EL2_NP = (1 << 3);
static const uint32_t ICH_MISR_EL2_VGRP0E = (1 << 4);
static const uint32_t ICH_MISR_EL2_VGRP0D = (1 << 5);
static const uint32_t ICH_MISR_EL2_VGRP1E = (1 << 6);
static const uint32_t ICH_MISR_EL2_VGRP1D = (1 << 7);
static const uint32_t ICH_VMCR_EL2_VENG0_SHIFT = 0;
static const uint32_t ICH_VMCR_EL2_VENG0 =
(1 << ICH_VMCR_EL2_VENG0_SHIFT);
static const uint32_t ICH_VMCR_EL2_VENG1_SHIFT = 1;
static const uint32_t ICH_VMCR_EL2_VENG1 =
(1 << ICH_VMCR_EL2_VENG1_SHIFT);
static const uint32_t ICH_VMCR_EL2_VACKCTL = (1 << 2);
static const uint32_t ICH_VMCR_EL2_VFIQEN = (1 << 3);
static const uint32_t ICH_VMCR_EL2_VCBPR_SHIFT = 4;
static const uint32_t ICH_VMCR_EL2_VCBPR =
(1 << ICH_VMCR_EL2_VCBPR_SHIFT);
static const uint32_t ICH_VMCR_EL2_VEOIM_SHIFT = 9;
static const uint32_t ICH_VMCR_EL2_VEOIM =
(1 << ICH_VMCR_EL2_VEOIM_SHIFT);
static const uint32_t ICH_VMCR_EL2_VBPR1_SHIFT = 18;
static const uint32_t ICH_VMCR_EL2_VBPR1_LENGTH = 3;
static const uint32_t ICH_VMCR_EL2_VBPR1_MASK =
(0x7U << ICH_VMCR_EL2_VBPR1_SHIFT);
static const uint32_t ICH_VMCR_EL2_VBPR0_SHIFT = 21;
static const uint32_t ICH_VMCR_EL2_VBPR0_LENGTH = 3;
static const uint32_t ICH_VMCR_EL2_VBPR0_MASK =
(0x7U << ICH_VMCR_EL2_VBPR0_SHIFT);
static const uint32_t ICH_VMCR_EL2_VPMR_SHIFT = 24;
static const uint32_t ICH_VMCR_EL2_VPMR_LENGTH = 8;
static const uint32_t ICH_VMCR_EL2_VPMR_MASK =
(0xffU << ICH_VMCR_EL2_VPMR_SHIFT);
static const uint32_t ICH_VTR_EL2_LISTREGS_SHIFT = 0;
static const uint32_t ICH_VTR_EL2_TDS = 1 << 19;
static const uint32_t ICH_VTR_EL2_NV4 = 1 << 20;
static const uint32_t ICH_VTR_EL2_A3V = 1 << 21;
static const uint32_t ICH_VTR_EL2_SEIS = 1 << 22;
static const uint32_t ICH_VTR_EL2_IDBITS_SHIFT = 23;
static const uint32_t ICH_VTR_EL2_PREBITS_SHIFT = 26;
static const uint32_t ICH_VTR_EL2_PRIBITS_SHIFT = 29;
public:
Gicv3CPUInterface(Gicv3 * gic, uint32_t cpu_id);
~Gicv3CPUInterface();
void init();
void initState();
ArmISA::MiscReg readMiscReg(int misc_reg) override;
void setMiscReg(int misc_reg, ArmISA::MiscReg val) override;
void update();
void virtualUpdate();
void serialize(CheckpointOut & cp) const override;
void unserialize(CheckpointIn & cp) override;
protected:
void reset();
bool hppiCanPreempt();
bool hppviCanPreempt(int lrIdx);
bool groupEnabled(Gicv3::GroupId group);
uint8_t highestActivePriority();
uint8_t virtualHighestActivePriority();
bool inSecureState();
int currEL();
bool haveEL(ArmISA::ExceptionLevel el);
void activateIRQ(uint32_t intid, Gicv3::GroupId group);
void virtualActivateIRQ(uint32_t lrIdx);
void deactivateIRQ(uint32_t intid, Gicv3::GroupId group);
void virtualDeactivateIRQ(int lrIdx);
uint32_t groupPriorityMask(Gicv3::GroupId group);
uint32_t virtualGroupPriorityMask(Gicv3::GroupId group);
void dropPriority(Gicv3::GroupId group);
uint8_t virtualDropPriority();
ArmISA::InterruptTypes intSignalType(Gicv3::GroupId group);
bool isEOISplitMode();
bool virtualIsEOISplitMode();
bool isSecureBelowEL3();
bool inSecureState2();
uint32_t eoiMaintenanceInterruptStatus(uint32_t * misr);
uint32_t maintenanceInterruptStatus();
int highestActiveGroup();
bool getHCREL2FMO();
bool getHCREL2IMO();
uint32_t getHPPIR1();
uint32_t getHPPIR0();
int getHPPVILR();
int virtualFindActive(uint32_t intid);
void virtualIncrementEOICount();
bool isEL3OrMon();
bool isAA64();
};
#endif //__DEV_ARM_GICV3_CPU_INTERFACE_H__

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,218 @@
/*
* Copyright (c) 2018 Metempsy Technology Consulting
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: Jairo Balart
*/
#ifndef __DEV_ARM_GICV3_DISTRIBUTOR_H__
#define __DEV_ARM_GICV3_DISTRIBUTOR_H__
#include "base/addr_range.hh"
#include "dev/arm/gic_v3.hh"
#include "sim/serialize.hh"
class Gicv3Distributor : public Serializable
{
private:
friend class Gicv3Redistributor;
friend class Gicv3CPUInterface;
protected:
Gicv3 * gic;
const uint32_t itLines;
enum {
// Control Register
GICD_CTLR = 0x0000,
// Interrupt Controller Type Register
GICD_TYPER = 0x0004,
// Implementer Identification Register
GICD_IIDR = 0x0008,
// Error Reporting Status Register
GICD_STATUSR = 0x0010,
// Peripheral ID0 Register
GICD_PIDR0 = 0xffe0,
// Peripheral ID1 Register
GICD_PIDR1 = 0xffe4,
// Peripheral ID2 Register
GICD_PIDR2 = 0xffe8,
// Peripheral ID3 Register
GICD_PIDR3 = 0xffec,
// Peripheral ID4 Register
GICD_PIDR4 = 0xffd0,
// Peripheral ID5 Register
GICD_PIDR5 = 0xffd4,
// Peripheral ID6 Register
GICD_PIDR6 = 0xffd8,
// Peripheral ID7 Register
GICD_PIDR7 = 0xffdc,
};
// Interrupt Group Registers
static const AddrRange GICD_IGROUPR;
// Interrupt Set-Enable Registers
static const AddrRange GICD_ISENABLER;
// Interrupt Clear-Enable Registers
static const AddrRange GICD_ICENABLER;
// Interrupt Set-Pending Registers
static const AddrRange GICD_ISPENDR;
// Interrupt Clear-Pending Registers
static const AddrRange GICD_ICPENDR;
// Interrupt Set-Active Registers
static const AddrRange GICD_ISACTIVER;
// Interrupt Clear-Active Registers
static const AddrRange GICD_ICACTIVER;
// Interrupt Priority Registers
static const AddrRange GICD_IPRIORITYR;
// Interrupt Processor Targets Registers
static const AddrRange GICD_ITARGETSR; // GICv2 legacy
// Interrupt Configuration Registers
static const AddrRange GICD_ICFGR;
// Interrupt Group Modifier Registers
static const AddrRange GICD_IGRPMODR;
// Non-secure Access Control Registers
static const AddrRange GICD_NSACR;
// SGI Clear-Pending Registers
static const AddrRange GICD_CPENDSGIR; // GICv2 legacy
// SGI Set-Pending Registers
static const AddrRange GICD_SPENDSGIR; // GICv2 legacy
// Interrupt Routing Registers
static const AddrRange GICD_IROUTER;
BitUnion64(IROUTER)
Bitfield<63, 40> res0_1;
Bitfield<39, 32> Aff3;
Bitfield<31> IRM;
Bitfield<30, 24> res0_2;
Bitfield<23, 16> Aff2;
Bitfield<15, 8> Aff1;
Bitfield<7, 0> Aff0;
EndBitUnion(IROUTER)
static const uint32_t GICD_CTLR_ENABLEGRP0 = 1 << 0;
static const uint32_t GICD_CTLR_ENABLEGRP1NS = 1 << 1;
static const uint32_t GICD_CTLR_ENABLEGRP1S = 1 << 2;
static const uint32_t GICD_CTLR_ENABLEGRP1 = 1 << 0;
static const uint32_t GICD_CTLR_ENABLEGRP1A = 1 << 1;
static const uint32_t GICD_CTLR_DS = 1 << 6;
bool ARE;
bool DS;
bool EnableGrp1S;
bool EnableGrp1NS;
bool EnableGrp0;
std::vector <uint8_t> irqGroup;
std::vector <bool> irqEnabled;
std::vector <bool> irqPending;
std::vector <bool> irqActive;
std::vector <uint8_t> irqPriority;
std::vector <Gicv3::IntTriggerType> irqConfig;
std::vector <uint8_t> irqGrpmod;
std::vector <uint8_t> irqNsacr;
std::vector <IROUTER> irqAffinityRouting;
public:
static const uint32_t ADDR_RANGE_SIZE = 0x10000;
Gicv3Distributor(Gicv3 * gic, uint32_t it_lines);
~Gicv3Distributor();
void init();
void initState();
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 serialize(CheckpointOut & cp) const override;
void unserialize(CheckpointIn & cp) override;
bool
groupEnabled(Gicv3::GroupId group)
{
if (DS == 0) {
switch (group) {
case Gicv3::G0S:
return EnableGrp0;
case Gicv3::G1S:
return EnableGrp1S;
case Gicv3::G1NS:
return EnableGrp1NS;
default:
panic("Gicv3Distributor::groupEnabled(): "
"invalid group!\n");
}
} else {
switch (group) {
case Gicv3::G0S:
return EnableGrp0;
case Gicv3::G1S:
case Gicv3::G1NS:
return EnableGrp1NS;
default:
panic("Gicv3Distributor::groupEnabled(): "
"invalid group!\n");
}
}
}
void sendInt(uint32_t int_id);
void intDeasserted(uint32_t int_id);
Gicv3::IntStatus intStatus(uint32_t int_id);
void updateAndInformCPUInterfaces();
void update();
void fullUpdate();
void activateIRQ(uint32_t int_id);
void deactivateIRQ(uint32_t int_id);
inline bool isNotSPI(uint8_t int_id)
{
if (int_id < (Gicv3::SGI_MAX + Gicv3::PPI_MAX) || int_id >= itLines) {
return true;
} else {
return false;
}
}
inline bool nsAccessToSecInt(uint8_t int_id, bool is_secure_access)
{
return !DS && !is_secure_access && getIntGroup(int_id) != Gicv3::G1NS;
}
protected:
void reset();
Gicv3::GroupId getIntGroup(int int_id);
};
#endif //__DEV_ARM_GICV3_DISTRIBUTOR_H__

View File

@@ -0,0 +1,834 @@
/*
* Copyright (c) 2018 Metempsy Technology Consulting
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: Jairo Balart
*/
#include "dev/arm/gic_v3_redistributor.hh"
#include "arch/arm/utility.hh"
#include "debug/GIC.hh"
#include "dev/arm/gic_v3_cpu_interface.hh"
#include "dev/arm/gic_v3_distributor.hh"
const AddrRange Gicv3Redistributor::GICR_IPRIORITYR(SGI_base + 0x0400,
SGI_base + 0x041f);
Gicv3Redistributor::Gicv3Redistributor(Gicv3 * gic, uint32_t cpu_id)
: gic(gic),
distributor(nullptr),
cpuInterface(nullptr),
cpuId(cpu_id),
irqGroup(Gicv3::SGI_MAX + Gicv3::PPI_MAX),
irqEnabled(Gicv3::SGI_MAX + Gicv3::PPI_MAX),
irqPending(Gicv3::SGI_MAX + Gicv3::PPI_MAX),
irqActive(Gicv3::SGI_MAX + Gicv3::PPI_MAX),
irqPriority(Gicv3::SGI_MAX + Gicv3::PPI_MAX),
irqConfig(Gicv3::SGI_MAX + Gicv3::PPI_MAX),
irqGrpmod(Gicv3::SGI_MAX + Gicv3::PPI_MAX),
irqNsacr(Gicv3::SGI_MAX + Gicv3::PPI_MAX)
{
}
Gicv3Redistributor::~Gicv3Redistributor()
{
}
void
Gicv3Redistributor::init()
{
distributor = gic->getDistributor();
cpuInterface = gic->getCPUInterface(cpuId);
}
void
Gicv3Redistributor::initState()
{
reset();
}
void
Gicv3Redistributor::reset()
{
peInLowPowerState = true;
std::fill(irqGroup.begin(), irqGroup.end(), 0);
std::fill(irqEnabled.begin(), irqEnabled.end(), false);
std::fill(irqPending.begin(), irqPending.end(), false);
std::fill(irqActive.begin(), irqActive.end(), false);
std::fill(irqPriority.begin(), irqPriority.end(), 0);
// SGIs have edge-triggered behavior
for (uint32_t int_id = 0; int_id < Gicv3::SGI_MAX; int_id++) {
irqConfig[int_id] = Gicv3::INT_EDGE_TRIGGERED;
}
std::fill(irqGrpmod.begin(), irqGrpmod.end(), 0);
std::fill(irqNsacr.begin(), irqNsacr.end(), 0);
DPG1S = false;
DPG1NS = false;
DPG0 = false;
}
uint64_t
Gicv3Redistributor::read(Addr addr, size_t size, bool is_secure_access)
{
if (GICR_IPRIORITYR.contains(addr)) { // Interrupt Priority Registers
uint64_t value = 0;
int first_intid = addr - GICR_IPRIORITYR.start();
for (int i = 0, int_id = first_intid; i < size; i++, int_id++) {
uint8_t prio = irqPriority[int_id];
if (!distributor->DS && !is_secure_access) {
if (getIntGroup(int_id) != Gicv3::G1NS) {
// RAZ/WI for non-secure accesses for secure interrupts
continue;
} else {
// NS view
prio = (prio << 1) & 0xff;
}
}
value |= prio << (i * 8);
}
return value;
}
switch (addr) {
case GICR_CTLR: { // Control Register
uint64_t value = 0;
if (DPG1S) {
value |= GICR_CTLR_DPG1S;
}
if (DPG1NS) {
value |= GICR_CTLR_DPG1NS;
}
if (DPG0) {
value |= GICR_CTLR_DPG0;
}
return value;
}
case GICR_IIDR: // Implementer Identification Register
//return 0x43b; // r0p0 GIC-500
return 0;
case GICR_TYPER: { // Type Register
/*
* Affinity_Value [63:32] == X
* (The identity of the PE associated with this Redistributor)
* CommonLPIAff [25:24] == 01
* (All Redistributors with the same Aff3 value must share an
* LPI Configuration table)
* Processor_Number [23:8] == X
* (A unique identifier for the PE)
* DPGS [5] == 1
* (GICR_CTLR.DPG* bits are supported)
* Last [4] == X
* (This Redistributor is the highest-numbered Redistributor in
* a series of contiguous Redistributor pages)
* DirectLPI [3] == 0
* (direct injection of LPIs not supported)
* VLPIS [1] == 0
* (virtual LPIs not supported)
* PLPIS [0] == 0
* (physical LPIs not supported)
*/
uint64_t affinity = getAffinity();
int last = cpuId == (gic->getSystem()->numContexts() - 1);
return (affinity << 32) | (1 << 24) | (cpuId << 8) |
(1 << 5) | (last << 4);
}
case GICR_WAKER: // Wake Register
if (!distributor->DS && !is_secure_access) {
// RAZ/WI for non-secure accesses
return 0;
}
if (peInLowPowerState) {
return GICR_WAKER_ChildrenAsleep | GICR_WAKER_ProcessorSleep;
} else {
return 0;
}
case GICR_PIDR0: { // Peripheral ID0 Register
uint8_t part_0 = 0x92; // Part number, bits[7:0]
return part_0;
}
case GICR_PIDR1: { // Peripheral ID1 Register
uint8_t des_0 = 0xB; // JEP106 identification code, bits[3:0]
uint8_t part_1 = 0x4; // Part number, bits[11:8]
return (des_0 << 4) | (part_1 << 0);
}
case GICR_PIDR2: { // Peripheral ID2 Register
uint8_t arch_rev = 0x3; // 0x3 GICv3
uint8_t jedec = 0x1; // JEP code
uint8_t des_1 = 0x3; // JEP106 identification code, bits[6:4]
return (arch_rev << 4) | (jedec << 3) | (des_1 << 0);
}
case GICR_PIDR3: // Peripheral ID3 Register
return 0x0; // Implementation defined
case GICR_PIDR4: { // Peripheral ID4 Register
uint8_t size = 0x4; // 64 KB software visible page
uint8_t des_2 = 0x4; // ARM implementation
return (size << 4) | (des_2 << 0);
}
case GICR_PIDR5: // Peripheral ID5 Register
case GICR_PIDR6: // Peripheral ID6 Register
case GICR_PIDR7: // Peripheral ID7 Register
return 0; // RES0
case GICR_IGROUPR0: { // Interrupt Group Register 0
uint64_t value = 0;
if (!distributor->DS && !is_secure_access) {
// RAZ/WI for non-secure accesses
return 0;
}
for (int int_id = 0; int_id < 8 * size; int_id++) {
value |= (irqGroup[int_id] << int_id);
}
return value;
}
case GICR_ISENABLER0: // Interrupt Set-Enable Register 0
case GICR_ICENABLER0: { // Interrupt Clear-Enable Register 0
uint64_t value = 0;
for (int int_id = 0; int_id < 8 * size; int_id++) {
if (!distributor->DS && !is_secure_access) {
// RAZ/WI for non-secure accesses for secure interrupts
if (getIntGroup(int_id) != Gicv3::G1NS) {
continue;
}
}
if (irqEnabled[int_id]) {
value |= (1 << int_id);
}
}
return value;
}
case GICR_ISPENDR0: // Interrupt Set-Pending Register 0
case GICR_ICPENDR0: { // Interrupt Clear-Pending Register 0
uint64_t value = 0;
for (int int_id = 0; int_id < 8 * size; int_id++) {
if (!distributor->DS && !is_secure_access) {
// RAZ/WI for non-secure accesses for secure interrupts
if (getIntGroup(int_id) != Gicv3::G1NS) {
continue;
}
}
value |= (irqPending[int_id] << int_id);
}
return value;
}
case GICR_ISACTIVER0: // Interrupt Set-Active Register 0
case GICR_ICACTIVER0: { // Interrupt Clear-Active Register 0
uint64_t value = 0;
for (int int_id = 0; int_id < 8 * size; int_id++) {
if (!distributor->DS && !is_secure_access) {
// RAZ/WI for non-secure accesses for secure interrupts
if (getIntGroup(int_id) != Gicv3::G1NS) {
continue;
}
}
value |= irqActive[int_id] << int_id;
}
return value;
}
case GICR_ICFGR0: // SGI Configuration Register
case GICR_ICFGR1: { // PPI Configuration Register
uint64_t value = 0;
uint32_t first_int_id = addr == GICR_ICFGR0 ? 0 : Gicv3::SGI_MAX;
for (int i = 0, int_id = first_int_id; i < 32;
i = i + 2, int_id++) {
if (!distributor->DS && !is_secure_access) {
// RAZ/WI for non-secure accesses for secure interrupts
if (getIntGroup(int_id) != Gicv3::G1NS) {
continue;
}
}
if (irqConfig[int_id] == Gicv3::INT_EDGE_TRIGGERED) {
value |= (0x2) << i;
}
}
return value;
}
case GICR_IGRPMODR0: { // Interrupt Group Modifier Register 0
uint64_t value = 0;
if (distributor->DS) {
value = 0;
} else {
if (!is_secure_access) {
// RAZ/WI for non-secure accesses
value = 0;
} else {
for (int int_id = 0; int_id < 8 * size; int_id++) {
value |= irqGrpmod[int_id] << int_id;
}
}
}
return value;
}
case GICR_NSACR: { // Non-secure Access Control Register
uint64_t value = 0;
if (distributor->DS) {
// RAZ/WI
value = 0;
} else {
if (!is_secure_access) {
// RAZ/WI
value = 0;
} else {
for (int i = 0, int_id = 0; i < 8 * size;
i = i + 2, int_id++) {
value |= irqNsacr[int_id] << i;
}
}
}
return value;
}
default:
panic("Gicv3Redistributor::read(): invalid offset %#x\n", addr);
break;
}
}
void
Gicv3Redistributor::write(Addr addr, uint64_t data, size_t size,
bool is_secure_access)
{
if (GICR_IPRIORITYR.contains(addr)) { // Interrupt Priority Registers
int first_intid = addr - GICR_IPRIORITYR.start();
for (int i = 0, int_id = first_intid; i < size; i++, int_id++) {
uint8_t prio = bits(data, (i + 1) * 8 - 1, (i * 8));
if (!distributor->DS && !is_secure_access) {
if (getIntGroup(int_id) != Gicv3::G1NS) {
// RAZ/WI for non-secure accesses for secure interrupts
continue;
} else {
// NS view
prio = 0x80 | (prio >> 1);
}
}
irqPriority[int_id] = prio;
DPRINTF(GIC, "Gicv3Redistributor::write(): "
"int_id %d priority %d\n", int_id, irqPriority[int_id]);
}
return;
}
switch (addr) {
case GICR_CTLR: {
// GICR_TYPER.LPIS is 0 so Enable_LPIs is RES0
DPG1S = data & GICR_CTLR_DPG1S;
DPG1NS = data & GICR_CTLR_DPG1NS;
DPG0 = data & GICR_CTLR_DPG0;
break;
}
case GICR_WAKER: // Wake Register
if (!distributor->DS && !is_secure_access) {
// RAZ/WI for non-secure accesses
return;
}
if (not peInLowPowerState and
(data & GICR_WAKER_ProcessorSleep)) {
DPRINTF(GIC, "Gicv3Redistributor::write(): "
"PE entering in low power state\n");
} else if (peInLowPowerState and
not(data & GICR_WAKER_ProcessorSleep)) {
DPRINTF(GIC, "Gicv3Redistributor::write(): powering up PE\n");
}
peInLowPowerState = data & GICR_WAKER_ProcessorSleep;
break;
case GICR_IGROUPR0: // Interrupt Group Register 0
if (!distributor->DS && !is_secure_access) {
// RAZ/WI for non-secure accesses
return;
}
for (int int_id = 0; int_id < 8 * size; int_id++) {
irqGroup[int_id] = data & (1 << int_id) ? 1 : 0;
DPRINTF(GIC, "Gicv3Redistributor::write(): "
"int_id %d group %d\n", int_id, irqGroup[int_id]);
}
break;
case GICR_ISENABLER0: // Interrupt Set-Enable Register 0
for (int int_id = 0; int_id < 8 * size; int_id++) {
if (!distributor->DS && !is_secure_access) {
// RAZ/WI for non-secure accesses for secure interrupts
if (getIntGroup(int_id) != Gicv3::G1NS) {
continue;
}
}
bool enable = data & (1 << int_id) ? 1 : 0;
if (enable) {
irqEnabled[int_id] = true;
}
DPRINTF(GIC, "Gicv3Redistributor::write(): "
"int_id %d enable %i\n", int_id, irqEnabled[int_id]);
}
break;
case GICR_ICENABLER0: // Interrupt Clear-Enable Register 0
for (int int_id = 0; int_id < 8 * size; int_id++) {
if (!distributor->DS && !is_secure_access) {
// RAZ/WI for non-secure accesses for secure interrupts
if (getIntGroup(int_id) != Gicv3::G1NS) {
continue;
}
}
bool disable = data & (1 << int_id) ? 1 : 0;
if (disable) {
irqEnabled[int_id] = false;
}
DPRINTF(GIC, "Gicv3Redistributor::write(): "
"int_id %d enable %i\n", int_id, irqEnabled[int_id]);
}
break;
case GICR_ISPENDR0: // Interrupt Set-Pending Register 0
for (int int_id = 0; int_id < 8 * size; int_id++) {
if (!distributor->DS && !is_secure_access) {
// RAZ/WI for non-secure accesses for secure interrupts
if (getIntGroup(int_id) != Gicv3::G1NS) {
continue;
}
}
bool pending = data & (1 << int_id) ? 1 : 0;
if (pending) {
DPRINTF(GIC, "Gicv3Redistributor::write() "
"(GICR_ISPENDR0): int_id %d (PPI) "
"pending bit set\n", int_id);
irqPending[int_id] = true;
}
}
updateAndInformCPUInterface();
break;
case GICR_ICPENDR0:// Interrupt Clear-Pending Register 0
for (int int_id = 0; int_id < 8 * size; int_id++) {
if (!distributor->DS && !is_secure_access) {
// RAZ/WI for non-secure accesses for secure interrupts
if (getIntGroup(int_id) != Gicv3::G1NS) {
continue;
}
}
bool clear = data & (1 << int_id) ? 1 : 0;
if (clear) {
irqPending[int_id] = false;
}
}
break;
case GICR_ISACTIVER0: // Interrupt Set-Active Register 0
for (int int_id = 0; int_id < 8 * size; int_id++) {
if (!distributor->DS && !is_secure_access) {
// RAZ/WI for non-secure accesses for secure interrupts
if (getIntGroup(int_id) != Gicv3::G1NS) {
continue;
}
}
bool activate = data & (1 << int_id) ? 1 : 0;
if (activate) {
if (!irqActive[int_id]) {
DPRINTF(GIC, "Gicv3Redistributor::write(): "
"int_id %d active set\n", int_id);
}
irqActive[int_id] = true;
}
}
break;
case GICR_ICACTIVER0: // Interrupt Clear-Active Register 0
for (int int_id = 0; int_id < 8 * size; int_id++) {
if (!distributor->DS && !is_secure_access) {
// RAZ/WI for non-secure accesses for secure interrupts
if (getIntGroup(int_id) != Gicv3::G1NS) {
continue;
}
}
bool clear = data & (1 << int_id) ? 1 : 0;
if (clear) {
if (irqActive[int_id]) {
DPRINTF(GIC, "Gicv3Redistributor::write(): "
"int_id %d active cleared\n", int_id);
}
irqActive[int_id] = false;
}
}
break;
case GICR_ICFGR1: { // PPI Configuration Register
int first_intid = Gicv3::SGI_MAX;
for (int i = 0, int_id = first_intid; i < 8 * size;
i = i + 2, int_id++) {
if (!distributor->DS && !is_secure_access) {
// RAZ/WI for non-secure accesses for secure interrupts
if (getIntGroup(int_id) != Gicv3::G1NS) {
continue;
}
}
irqConfig[int_id] = data & (0x2 << i)
? Gicv3::INT_EDGE_TRIGGERED :
Gicv3::INT_LEVEL_SENSITIVE;
DPRINTF(GIC, "Gicv3Redistributor::write(): "
"int_id %d (PPI) config %d\n",
int_id, irqConfig[int_id]);
}
break;
}
case GICR_IGRPMODR0: { // Interrupt Group Modifier Register 0
if (distributor->DS) {
// RAZ/WI if secutiry disabled
} else {
for (int int_id = 0; int_id < 8 * size; int_id++) {
if (!is_secure_access) {
// RAZ/WI for non-secure accesses
continue;
}
irqGrpmod[int_id] = data & (1 << int_id);
}
}
break;
}
case GICR_NSACR: { // Non-secure Access Control Register
if (distributor->DS) {
// RAZ/WI
} else {
if (!is_secure_access) {
// RAZ/WI
} else {
for (int i = 0, int_id = 0; i < 8 * size;
i = i + 2, int_id++) {
irqNsacr[int_id] = (data >> i) & 0x3;
}
}
}
break;
}
default:
panic("Gicv3Redistributor::write(): invalid offset %#x\n", addr);
break;
}
}
void
Gicv3Redistributor::sendPPInt(uint32_t int_id)
{
assert((int_id >= Gicv3::SGI_MAX) &&
(int_id < Gicv3::SGI_MAX + Gicv3::PPI_MAX));
irqPending[int_id] = true;
DPRINTF(GIC, "Gicv3Redistributor::sendPPInt(): "
"int_id %d (PPI) pending bit set\n", int_id);
updateAndInformCPUInterface();
}
void
Gicv3Redistributor::sendSGI(uint32_t int_id, Gicv3::GroupId group, bool ns)
{
assert(int_id < Gicv3::SGI_MAX);
Gicv3::GroupId int_group = getIntGroup(int_id);
// asked for secure group 1
// configured as group 0
// send group 0
if (int_group == Gicv3::G0S && group == Gicv3::G1S) {
group = Gicv3::G0S;
}
if (group == Gicv3::G0S and int_group != Gicv3::G0S) {
return;
}
if (ns && distributor->DS == 0) {
int nsaccess = irqNsacr[int_id];
if ((int_group == Gicv3::G0S && nsaccess < 1) ||
(int_group == Gicv3::G1S && nsaccess < 2)) {
return;
}
}
irqPending[int_id] = true;
DPRINTF(GIC, "Gicv3ReDistributor::sendSGI(): "
"int_id %d (SGI) pending bit set\n", int_id);
updateAndInformCPUInterface();
}
Gicv3::IntStatus
Gicv3Redistributor::intStatus(uint32_t int_id)
{
assert(int_id < Gicv3::SGI_MAX + Gicv3::PPI_MAX);
if (irqPending[int_id]) {
if (irqActive[int_id]) {
return Gicv3::INT_ACTIVE_PENDING;
}
return Gicv3::INT_PENDING;
} else if (irqActive[int_id]) {
return Gicv3::INT_ACTIVE;
} else {
return Gicv3::INT_INACTIVE;
}
}
/*
* Recalculate the highest priority pending interrupt after a
* change to redistributor state.
*/
void
Gicv3Redistributor::update()
{
bool new_hppi = false;
for (int int_id = 0; int_id < Gicv3::SGI_MAX + Gicv3::PPI_MAX; int_id++) {
Gicv3::GroupId int_group = getIntGroup(int_id);
bool group_enabled = distributor->groupEnabled(int_group);
if (irqPending[int_id] && irqEnabled[int_id] &&
!irqActive[int_id] && group_enabled) {
if ((irqPriority[int_id] < cpuInterface->hppi.prio) ||
/*
* Multiple pending ints with same priority.
* Implementation choice which one to signal.
* Our implementation selects the one with the lower id.
*/
(irqPriority[int_id] == cpuInterface->hppi.prio &&
int_id < cpuInterface->hppi.intid)) {
cpuInterface->hppi.intid = int_id;
cpuInterface->hppi.prio = irqPriority[int_id];
cpuInterface->hppi.group = int_group;
new_hppi = true;
}
}
}
if (!new_hppi && cpuInterface->hppi.prio != 0xff &&
cpuInterface->hppi.intid < Gicv3::SGI_MAX + Gicv3::PPI_MAX) {
distributor->fullUpdate();
}
}
void
Gicv3Redistributor::updateAndInformCPUInterface()
{
update();
cpuInterface->update();
}
Gicv3::GroupId
Gicv3Redistributor::getIntGroup(int int_id)
{
assert(int_id < (Gicv3::SGI_MAX + Gicv3::PPI_MAX));
if (distributor->DS) {
if (irqGroup[int_id] == 0) {
return Gicv3::G0S;
} else {
return Gicv3::G1NS;
}
} else {
if (irqGrpmod[int_id] == 0 && irqGroup[int_id] == 0) {
return Gicv3::G0S;
} else if (irqGrpmod[int_id] == 0 && irqGroup[int_id] == 1) {
return Gicv3::G1NS;
} else if (irqGrpmod[int_id] == 1 && irqGroup[int_id] == 0) {
return Gicv3::G1S;
} else if (irqGrpmod[int_id] == 1 && irqGroup[int_id] == 1) {
return Gicv3::G1NS;
}
}
M5_UNREACHABLE;
}
void
Gicv3Redistributor::activateIRQ(uint32_t int_id)
{
irqPending[int_id] = false;
irqActive[int_id] = true;
}
void
Gicv3Redistributor::deactivateIRQ(uint32_t int_id)
{
irqActive[int_id] = false;
}
uint32_t
Gicv3Redistributor::getAffinity()
{
ThreadContext * tc = gic->getSystem()->getThreadContext(cpuId);
uint64_t mpidr = getMPIDR(gic->getSystem(), tc);
/*
* Aff3 = MPIDR[39:32]
* (Note getMPIDR() returns uint32_t so Aff3 is always 0...)
* Aff2 = MPIDR[23:16]
* Aff1 = MPIDR[15:8]
* Aff0 = MPIDR[7:0]
* affinity = Aff3.Aff2.Aff1.Aff0
*/
uint64_t affinity = ((mpidr & 0xff00000000) >> 8) | (mpidr & (0xffffff));
return affinity;
}
bool
Gicv3Redistributor::canBeSelectedFor1toNInterrupt(Gicv3::GroupId group)
{
if (peInLowPowerState) {
return false;
}
if (!distributor->groupEnabled(group)) {
return false;
}
if ((group == Gicv3::G1S) && DPG1S) {
return false;
}
if ((group == Gicv3::G1NS) && DPG1NS) {
return false;
}
if ((group == Gicv3::G0S) && DPG0) {
return false;
}
return true;
}
void
Gicv3Redistributor::serialize(CheckpointOut & cp) const
{
SERIALIZE_SCALAR(peInLowPowerState);
SERIALIZE_CONTAINER(irqGroup);
SERIALIZE_CONTAINER(irqEnabled);
SERIALIZE_CONTAINER(irqPending);
SERIALIZE_CONTAINER(irqActive);
SERIALIZE_CONTAINER(irqPriority);
SERIALIZE_CONTAINER(irqConfig);
SERIALIZE_CONTAINER(irqGrpmod);
SERIALIZE_CONTAINER(irqNsacr);
SERIALIZE_SCALAR(DPG1S);
SERIALIZE_SCALAR(DPG1NS);
SERIALIZE_SCALAR(DPG0);
}
void
Gicv3Redistributor::unserialize(CheckpointIn & cp)
{
UNSERIALIZE_SCALAR(peInLowPowerState);
UNSERIALIZE_CONTAINER(irqGroup);
UNSERIALIZE_CONTAINER(irqEnabled);
UNSERIALIZE_CONTAINER(irqPending);
UNSERIALIZE_CONTAINER(irqActive);
UNSERIALIZE_CONTAINER(irqPriority);
UNSERIALIZE_CONTAINER(irqConfig);
UNSERIALIZE_CONTAINER(irqGrpmod);
UNSERIALIZE_CONTAINER(irqNsacr);
UNSERIALIZE_SCALAR(DPG1S);
UNSERIALIZE_SCALAR(DPG1NS);
UNSERIALIZE_SCALAR(DPG0);
}

View File

@@ -0,0 +1,183 @@
/*
* Copyright (c) 2018 Metempsy Technology Consulting
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: Jairo Balart
*/
#ifndef __DEV_ARM_GICV3_REDISTRIBUTOR_H__
#define __DEV_ARM_GICV3_REDISTRIBUTOR_H__
#include "base/addr_range.hh"
#include "dev/arm/gic_v3.hh"
#include "sim/serialize.hh"
class Gicv3Distributor;
class Gicv3CPUInterface;
class Gicv3Redistributor : public Serializable
{
private:
friend class Gicv3CPUInterface;
friend class Gicv3Distributor;
protected:
Gicv3 * gic;
Gicv3Distributor * distributor;
Gicv3CPUInterface * cpuInterface;
uint32_t cpuId;
/*
* GICv3 defines 2 contiguous 64KB frames for each redistributor.
* Order of frames must be RD_base, SGI_base.
*/
static const uint32_t RD_base = 0x0;
static const uint32_t SGI_base = 0x10000;
enum {
// Control Register
GICR_CTLR = RD_base + 0x0000,
// Implementer Identification Register
GICR_IIDR = RD_base + 0x0004,
// Type Register
GICR_TYPER = RD_base + 0x0008,
// Wake Register
GICR_WAKER = RD_base + 0x0014,
// Peripheral ID0 Register
GICR_PIDR0 = RD_base + 0xffe0,
// Peripheral ID1 Register
GICR_PIDR1 = RD_base + 0xffe4,
// Peripheral ID2 Register
GICR_PIDR2 = RD_base + 0xffe8,
// Peripheral ID3 Register
GICR_PIDR3 = RD_base + 0xffec,
// Peripheral ID4 Register
GICR_PIDR4 = RD_base + 0xffd0,
// Peripheral ID5 Register
GICR_PIDR5 = RD_base + 0xffd4,
// Peripheral ID6 Register
GICR_PIDR6 = RD_base + 0xffd8,
// Peripheral ID7 Register
GICR_PIDR7 = RD_base + 0xffdc,
};
static const uint32_t GICR_WAKER_ProcessorSleep = 1 << 1;
static const uint32_t GICR_WAKER_ChildrenAsleep = 1 << 2;
bool peInLowPowerState;
enum {
// Interrupt Group Register 0
GICR_IGROUPR0 = SGI_base + 0x0080,
// Interrupt Set-Enable Register 0
GICR_ISENABLER0 = SGI_base + 0x0100,
// Interrupt Clear-Enable Register 0
GICR_ICENABLER0 = SGI_base + 0x0180,
// Interrupt Set-Pending Register 0
GICR_ISPENDR0 = SGI_base + 0x0200,
// Interrupt Clear-Pending Register 0
GICR_ICPENDR0 = SGI_base + 0x0280,
// Interrupt Set-Active Register 0
GICR_ISACTIVER0 = SGI_base + 0x0300,
// Interrupt Clear-Active Register 0
GICR_ICACTIVER0 = SGI_base + 0x0380,
// SGI Configuration Register
GICR_ICFGR0 = SGI_base + 0x0c00,
// PPI Configuration Register
GICR_ICFGR1 = SGI_base + 0x0c04,
// Interrupt Group Modifier Register 0
GICR_IGRPMODR0 = SGI_base + 0x0d00,
// Non-secure Access Control Register
GICR_NSACR = SGI_base + 0x0e00,
};
// Interrupt Priority Registers
static const AddrRange GICR_IPRIORITYR;
std::vector <uint8_t> irqGroup;
std::vector <bool> irqEnabled;
std::vector <bool> irqPending;
std::vector <bool> irqActive;
std::vector <uint8_t> irqPriority;
std::vector <Gicv3::IntTriggerType> irqConfig;
std::vector <uint8_t> irqGrpmod;
std::vector <uint8_t> irqNsacr;
bool DPG1S;
bool DPG1NS;
bool DPG0;
static const uint32_t GICR_CTLR_DPG0 = 1 << 24;
static const uint32_t GICR_CTLR_DPG1NS = 1 << 25;
static const uint32_t GICR_CTLR_DPG1S = 1 << 26;
public:
/*
* GICv3 defines only 2 64K consecutive frames for the redistributor
* (RD_base and SGI_base) but we are using 2 extra 64K stride frames
* to match GICv4 that defines 4 64K consecutive frames for them.
* Note this must match with DTB/DTS GIC node definition and boot
* loader code.
*/
static const uint32_t ADDR_RANGE_SIZE = 0x40000;
Gicv3Redistributor(Gicv3 * gic, uint32_t cpu_id);
~Gicv3Redistributor();
void init();
void initState();
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 sendPPInt(uint32_t int_id);
void sendSGI(uint32_t int_id, Gicv3::GroupId group, bool ns);
void serialize(CheckpointOut & cp) const override;
void unserialize(CheckpointIn & cp) override;
uint32_t getAffinity();
Gicv3CPUInterface *
getCPUInterface() const
{
return cpuInterface;
}
bool canBeSelectedFor1toNInterrupt(Gicv3::GroupId group);
protected:
void reset();
void update();
void updateAndInformCPUInterface();
Gicv3::IntStatus intStatus(uint32_t int_id);
Gicv3::GroupId getIntGroup(int int_id);
void activateIRQ(uint32_t int_id);
void deactivateIRQ(uint32_t int_id);
};
#endif //__DEV_ARM_GICV3_REDISTRIBUTOR_H__