blob: 22c5ad71b144d626b4e50dea2484312bb3f6507f [file] [log] [blame]
/*
* Copyright (c) 2019-2020 ARM Limited
* All rights reserved
*
* The license below extends only to copyright in the software and shall
* not be construed as granting a license to any other intellectual
* property including but not limited to intellectual property relating
* to a hardware implementation of the functionality of the software
* licensed hereunder. You may use the software subject to the license
* terms below provided that you ensure that this notice is replicated
* unmodified and in its entirety in all distributions of the software,
* modified or unmodified, in source code or in binary form.
*
* 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.
*/
#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"
namespace gem5
{
class Gicv3Distributor : public Serializable
{
private:
friend class Gicv3Redistributor;
friend class Gicv3CPUInterface;
friend class Gicv3Its;
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,
// Interrupt Controller Type Register 2
GICD_TYPER2 = 0x000C,
// Error Reporting Status Register
GICD_STATUSR = 0x0010,
// Set Non-secure SPI Pending Register
GICD_SETSPI_NSR = 0x0040,
// Clear Non-secure SPI Pending Register
GICD_CLRSPI_NSR = 0x0048,
// Set Secure SPI Pending Register
GICD_SETSPI_SR = 0x0050,
// Clear Secure SPI Pending Register
GICD_CLRSPI_SR = 0x0058,
// Software Generated Interrupt Register
GICD_SGIR = 0x0f00,
// 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_ENABLEGRP1 = 1 << 0;
static const uint32_t GICD_CTLR_ENABLEGRP1NS = 1 << 1;
static const uint32_t GICD_CTLR_ENABLEGRP1A = 1 << 1;
static const uint32_t GICD_CTLR_ENABLEGRP1S = 1 << 2;
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> irqPendingIspendr;
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;
uint32_t gicdTyper;
uint32_t gicdPidr0;
uint32_t gicdPidr1;
uint32_t gicdPidr2;
uint32_t gicdPidr3;
uint32_t gicdPidr4;
public:
static const uint32_t ADDR_RANGE_SIZE = 0x10000;
static const uint32_t IDBITS = 0xf;
protected:
void activateIRQ(uint32_t int_id);
void deactivateIRQ(uint32_t int_id);
void fullUpdate();
Gicv3::GroupId getIntGroup(int int_id) const;
inline bool
groupEnabled(Gicv3::GroupId group) const
{
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");
}
}
}
Gicv3::IntStatus intStatus(uint32_t int_id) const;
inline bool isNotSPI(uint32_t int_id) const
{
if (int_id < (Gicv3::SGI_MAX + Gicv3::PPI_MAX) || int_id >= itLines) {
return true;
} else {
return false;
}
}
bool isLevelSensitive(uint32_t int_id) const
{
return irqConfig[int_id] == Gicv3::INT_LEVEL_SENSITIVE;
}
/**
* This helper is used to check if an interrupt should be treated as
* edge triggered in the following scenarios:
*
* a) While activating the interrupt
* b) While clearing an interrupt via ICPENDR
*
* In fact, in these two situations, a level sensitive interrupt
* which had been made pending via a write to ISPENDR, will be
* treated as it if was edge triggered.
*/
bool treatAsEdgeTriggered(uint32_t int_id) const
{
return !isLevelSensitive(int_id) || irqPendingIspendr[int_id];
}
inline bool nsAccessToSecInt(uint32_t int_id, bool is_secure_access) const
{
return !DS && !is_secure_access && getIntGroup(int_id) != Gicv3::G1NS;
}
void serialize(CheckpointOut & cp) const override;
void unserialize(CheckpointIn & cp) override;
void update();
Gicv3CPUInterface* route(uint32_t int_id);
public:
Gicv3Distributor(Gicv3 * gic, uint32_t it_lines);
void sendInt(uint32_t int_id);
void clearInt(uint32_t int_id);
void deassertSPI(uint32_t int_id);
void clearIrqCpuInterface(uint32_t int_id);
void init();
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);
};
} // namespace gem5
#endif //__DEV_ARM_GICV3_DISTRIBUTOR_H__