blob: 1f7a7561a7978b94d2a59c945cd4cd647a968ff8 [file] [log] [blame]
/*
* Copyright (c) 2010, 2012-2021 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) 2009 The Regents of The University of Michigan
* 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 __ARCH_ARM_ISA_HH__
#define __ARCH_ARM_ISA_HH__
#include "arch/arm/isa_device.hh"
#include "arch/arm/mmu.hh"
#include "arch/arm/pcstate.hh"
#include "arch/arm/regs/int.hh"
#include "arch/arm/regs/misc.hh"
#include "arch/arm/regs/vec.hh"
#include "arch/arm/self_debug.hh"
#include "arch/arm/system.hh"
#include "arch/arm/types.hh"
#include "arch/arm/utility.hh"
#include "arch/generic/isa.hh"
#include "debug/Checkpoint.hh"
#include "enums/DecoderFlavor.hh"
#include "sim/sim_object.hh"
namespace gem5
{
struct ArmISAParams;
struct DummyArmISADeviceParams;
class Checkpoint;
class EventManager;
namespace ArmISA
{
class ISA : public BaseISA
{
protected:
// Parent system
ArmSystem *system;
// Micro Architecture
const enums::DecoderFlavor _decoderFlavor;
/** Dummy device for to handle non-existing ISA devices */
DummyISADevice dummyDevice;
// PMU belonging to this ISA
BaseISADevice *pmu;
// Generic timer interface belonging to this ISA
std::unique_ptr<BaseISADevice> timer;
// GICv3 CPU interface belonging to this ISA
std::unique_ptr<BaseISADevice> gicv3CpuInterface;
// Cached copies of system-level properties
bool highestELIs64;
bool haveLargeAsid64;
uint8_t physAddrRange;
/** SVE vector length in quadwords */
unsigned sveVL;
/** This could be either a FS or a SE release */
const ArmRelease *release;
/**
* If true, accesses to IMPLEMENTATION DEFINED registers are treated
* as NOP hence not causing UNDEFINED INSTRUCTION.
*/
bool impdefAsNop;
SelfDebug * selfDebug;
const MiscRegLUTEntryInitializer
InitReg(uint32_t reg)
{
return MiscRegLUTEntryInitializer(lookUpMiscReg[reg]);
}
void initializeMiscRegMetadata();
BaseISADevice &getGenericTimer();
BaseISADevice &getGICv3CPUInterface();
RegVal miscRegs[NUM_MISCREGS];
const RegId *intRegMap;
void
updateRegMap(CPSR cpsr)
{
if (cpsr.width == 0) {
intRegMap = int_reg::Reg64Map;
} else {
switch (cpsr.mode) {
case MODE_USER:
case MODE_SYSTEM:
intRegMap = int_reg::RegUsrMap;
break;
case MODE_FIQ:
intRegMap = int_reg::RegFiqMap;
break;
case MODE_IRQ:
intRegMap = int_reg::RegIrqMap;
break;
case MODE_SVC:
intRegMap = int_reg::RegSvcMap;
break;
case MODE_MON:
intRegMap = int_reg::RegMonMap;
break;
case MODE_ABORT:
intRegMap = int_reg::RegAbtMap;
break;
case MODE_HYP:
intRegMap = int_reg::RegHypMap;
break;
case MODE_UNDEFINED:
intRegMap = int_reg::RegUndMap;
break;
default:
panic("Unrecognized mode setting in CPSR.\n");
}
}
}
public:
const RegId &mapIntRegId(RegIndex idx) const { return intRegMap[idx]; }
public:
void clear() override;
protected:
void clear32(const ArmISAParams &p, const SCTLR &sctlr_rst);
void clear64(const ArmISAParams &p);
void initID32(const ArmISAParams &p);
void initID64(const ArmISAParams &p);
void addressTranslation(MMU::ArmTranslationType tran_type,
BaseMMU::Mode mode, Request::Flags flags, RegVal val);
void addressTranslation64(MMU::ArmTranslationType tran_type,
BaseMMU::Mode mode, Request::Flags flags, RegVal val);
public:
SelfDebug*
getSelfDebug() const
{
return selfDebug;
}
static SelfDebug*
getSelfDebug(ThreadContext *tc)
{
auto *arm_isa = static_cast<ArmISA::ISA *>(tc->getIsaPtr());
return arm_isa->getSelfDebug();
}
const ArmRelease* getRelease() const { return release; }
RegVal readMiscRegNoEffect(RegIndex idx) const override;
RegVal readMiscReg(RegIndex idx) override;
void setMiscRegNoEffect(RegIndex idx, RegVal val) override;
void setMiscReg(RegIndex, RegVal val) override;
int
flattenMiscIndex(int reg) const
{
assert(reg >= 0);
int flat_idx = reg;
if (reg == MISCREG_SPSR) {
CPSR cpsr = miscRegs[MISCREG_CPSR];
switch (cpsr.mode) {
case MODE_EL0T:
warn("User mode does not have SPSR\n");
flat_idx = MISCREG_SPSR;
break;
case MODE_EL1T:
case MODE_EL1H:
flat_idx = MISCREG_SPSR_EL1;
break;
case MODE_EL2T:
case MODE_EL2H:
flat_idx = MISCREG_SPSR_EL2;
break;
case MODE_EL3T:
case MODE_EL3H:
flat_idx = MISCREG_SPSR_EL3;
break;
case MODE_USER:
warn("User mode does not have SPSR\n");
flat_idx = MISCREG_SPSR;
break;
case MODE_FIQ:
flat_idx = MISCREG_SPSR_FIQ;
break;
case MODE_IRQ:
flat_idx = MISCREG_SPSR_IRQ;
break;
case MODE_SVC:
flat_idx = MISCREG_SPSR_SVC;
break;
case MODE_MON:
flat_idx = MISCREG_SPSR_MON;
break;
case MODE_ABORT:
flat_idx = MISCREG_SPSR_ABT;
break;
case MODE_HYP:
flat_idx = MISCREG_SPSR_HYP;
break;
case MODE_UNDEFINED:
flat_idx = MISCREG_SPSR_UND;
break;
default:
warn("Trying to access SPSR in an invalid mode: %d\n",
cpsr.mode);
flat_idx = MISCREG_SPSR;
break;
}
} else if (lookUpMiscReg[reg].info[MISCREG_MUTEX]) {
// Mutually exclusive CP15 register
switch (reg) {
case MISCREG_PRRR_MAIR0:
case MISCREG_PRRR_MAIR0_NS:
case MISCREG_PRRR_MAIR0_S:
{
TTBCR ttbcr = readMiscRegNoEffect(MISCREG_TTBCR);
// If the muxed reg has been flattened, work out the
// offset and apply it to the unmuxed reg
int idxOffset = reg - MISCREG_PRRR_MAIR0;
if (ttbcr.eae)
flat_idx = flattenMiscIndex(MISCREG_MAIR0 +
idxOffset);
else
flat_idx = flattenMiscIndex(MISCREG_PRRR +
idxOffset);
}
break;
case MISCREG_NMRR_MAIR1:
case MISCREG_NMRR_MAIR1_NS:
case MISCREG_NMRR_MAIR1_S:
{
TTBCR ttbcr = readMiscRegNoEffect(MISCREG_TTBCR);
// If the muxed reg has been flattened, work out the
// offset and apply it to the unmuxed reg
int idxOffset = reg - MISCREG_NMRR_MAIR1;
if (ttbcr.eae)
flat_idx = flattenMiscIndex(MISCREG_MAIR1 +
idxOffset);
else
flat_idx = flattenMiscIndex(MISCREG_NMRR +
idxOffset);
}
break;
case MISCREG_PMXEVTYPER_PMCCFILTR:
{
PMSELR pmselr = miscRegs[MISCREG_PMSELR];
if (pmselr.sel == 31)
flat_idx = flattenMiscIndex(MISCREG_PMCCFILTR);
else
flat_idx = flattenMiscIndex(MISCREG_PMXEVTYPER);
}
break;
default:
panic("Unrecognized misc. register.\n");
break;
}
} else {
if (lookUpMiscReg[reg].info[MISCREG_BANKED]) {
bool secure_reg = !highestELIs64 && inSecureState();
flat_idx += secure_reg ? 2 : 1;
} else {
flat_idx = snsBankedIndex64((MiscRegIndex)reg,
!inSecureState());
}
}
return flat_idx;
}
/**
* Returns the enconcing equivalent when VHE is implemented and
* HCR_EL2.E2H is enabled and executing at EL2
*/
int redirectRegVHE(int misc_reg);
int
snsBankedIndex64(MiscRegIndex reg, bool ns) const
{
int reg_as_int = static_cast<int>(reg);
if (lookUpMiscReg[reg].info[MISCREG_BANKED64]) {
reg_as_int += (release->has(ArmExtension::SECURITY) && !ns) ?
2 : 1;
}
return reg_as_int;
}
std::pair<int,int>
getMiscIndices(int misc_reg) const
{
// Note: indexes of AArch64 registers are left unchanged
int flat_idx = flattenMiscIndex(misc_reg);
if (lookUpMiscReg[flat_idx].lower == 0) {
return std::make_pair(flat_idx, 0);
}
// do additional S/NS flattenings if mapped to NS while in S
bool S = !highestELIs64 && inSecureState();
int lower = lookUpMiscReg[flat_idx].lower;
int upper = lookUpMiscReg[flat_idx].upper;
// upper == 0, which is CPSR, is not MISCREG_BANKED_CHILD (no-op)
lower += S && lookUpMiscReg[lower].info[MISCREG_BANKED_CHILD];
upper += S && lookUpMiscReg[upper].info[MISCREG_BANKED_CHILD];
return std::make_pair(lower, upper);
}
/** Return true if the PE is in Secure state */
bool inSecureState() const;
/**
* Returns the current Exception Level (EL) of the ISA object
*/
ExceptionLevel currEL() const;
unsigned getCurSveVecLenInBits() const;
unsigned getCurSveVecLenInBitsAtReset() const { return sveVL * 128; }
template <typename Elem>
static void
zeroSveVecRegUpperPart(Elem *v, unsigned eCount)
{
static_assert(sizeof(Elem) <= sizeof(uint64_t),
"Elem type is too large.");
eCount *= (sizeof(uint64_t) / sizeof(Elem));
for (int i = 16 / sizeof(Elem); i < eCount; ++i) {
v[i] = 0;
}
}
void serialize(CheckpointOut &cp) const override;
void unserialize(CheckpointIn &cp) override;
void startup() override;
void setupThreadContext();
PCStateBase *
newPCState(Addr new_inst_addr=0) const override
{
return new PCState(new_inst_addr);
}
void takeOverFrom(ThreadContext *new_tc,
ThreadContext *old_tc) override;
enums::DecoderFlavor decoderFlavor() const { return _decoderFlavor; }
PARAMS(ArmISA);
ISA(const Params &p);
uint64_t
getExecutingAsid() const override
{
return readMiscRegNoEffect(MISCREG_CONTEXTIDR);
}
bool
inUserMode() const override
{
CPSR cpsr = miscRegs[MISCREG_CPSR];
return ArmISA::inUserMode(cpsr);
}
void copyRegsFrom(ThreadContext *src) override;
void handleLockedRead(const RequestPtr &req) override;
void handleLockedRead(ExecContext *xc, const RequestPtr &req) override;
bool handleLockedWrite(const RequestPtr &req,
Addr cacheBlockMask) override;
bool handleLockedWrite(ExecContext *xc, const RequestPtr &req,
Addr cacheBlockMask) override;
void handleLockedSnoop(PacketPtr pkt, Addr cacheBlockMask) override;
void handleLockedSnoop(ExecContext *xc, PacketPtr pkt,
Addr cacheBlockMask) override;
void handleLockedSnoopHit() override;
void handleLockedSnoopHit(ExecContext *xc) override;
void globalClearExclusive() override;
void globalClearExclusive(ExecContext *xc) override;
};
} // namespace ArmISA
} // namespace gem5
#endif