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:
committed by
Giacomo Travaglini
parent
7d5696d1a9
commit
93c7fa5731
@@ -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)")
|
||||
|
||||
@@ -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')
|
||||
|
||||
@@ -64,6 +64,13 @@ BaseGic::~BaseGic()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
BaseGic::init()
|
||||
{
|
||||
PioDevice::init();
|
||||
getSystem()->setGIC(this);
|
||||
}
|
||||
|
||||
const BaseGic::Params *
|
||||
BaseGic::params() const
|
||||
{
|
||||
|
||||
@@ -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
275
src/dev/arm/gic_v3.cc
Normal 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
142
src/dev/arm/gic_v3.hh
Normal 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__
|
||||
2362
src/dev/arm/gic_v3_cpu_interface.cc
Normal file
2362
src/dev/arm/gic_v3_cpu_interface.cc
Normal file
File diff suppressed because it is too large
Load Diff
301
src/dev/arm/gic_v3_cpu_interface.hh
Normal file
301
src/dev/arm/gic_v3_cpu_interface.hh
Normal 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__
|
||||
1132
src/dev/arm/gic_v3_distributor.cc
Normal file
1132
src/dev/arm/gic_v3_distributor.cc
Normal file
File diff suppressed because it is too large
Load Diff
218
src/dev/arm/gic_v3_distributor.hh
Normal file
218
src/dev/arm/gic_v3_distributor.hh
Normal 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__
|
||||
834
src/dev/arm/gic_v3_redistributor.cc
Normal file
834
src/dev/arm/gic_v3_redistributor.cc
Normal 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);
|
||||
}
|
||||
183
src/dev/arm/gic_v3_redistributor.hh
Normal file
183
src/dev/arm/gic_v3_redistributor.hh
Normal 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__
|
||||
Reference in New Issue
Block a user