/*
- * Copyright (c) 2010 ARM Limited
+ * Copyright (c) 2010, 2012-2015 ARM Limited
* All rights reserved
*
* The license below extends only to copyright in the software and shall
*/
#ifndef __ARCH_ARM_ISA_HH__
-#define __ARCH_MRM_ISA_HH__
+#define __ARCH_ARM_ISA_HH__
+#include "arch/arm/isa_device.hh"
#include "arch/arm/registers.hh"
+#include "arch/arm/system.hh"
+#include "arch/arm/tlb.hh"
#include "arch/arm/types.hh"
+#include "debug/Checkpoint.hh"
+#include "sim/sim_object.hh"
+#include "enums/DecoderFlavour.hh"
+struct ArmISAParams;
+struct DummyArmISADeviceParams;
class ThreadContext;
class Checkpoint;
class EventManager;
namespace ArmISA
{
- class ISA
+
+ /**
+ * At the moment there are 57 registers which need to be aliased/
+ * translated with other registers in the ISA. This enum helps with that
+ * translation.
+ */
+ enum translateTable {
+ miscRegTranslateCSSELR_EL1,
+ miscRegTranslateSCTLR_EL1,
+ miscRegTranslateSCTLR_EL2,
+ miscRegTranslateACTLR_EL1,
+ miscRegTranslateACTLR_EL2,
+ miscRegTranslateCPACR_EL1,
+ miscRegTranslateCPTR_EL2,
+ miscRegTranslateHCR_EL2,
+ miscRegTranslateMDCR_EL2,
+ miscRegTranslateHSTR_EL2,
+ miscRegTranslateHACR_EL2,
+ miscRegTranslateTTBR0_EL1,
+ miscRegTranslateTTBR1_EL1,
+ miscRegTranslateTTBR0_EL2,
+ miscRegTranslateVTTBR_EL2,
+ miscRegTranslateTCR_EL1,
+ miscRegTranslateTCR_EL2,
+ miscRegTranslateVTCR_EL2,
+ miscRegTranslateAFSR0_EL1,
+ miscRegTranslateAFSR1_EL1,
+ miscRegTranslateAFSR0_EL2,
+ miscRegTranslateAFSR1_EL2,
+ miscRegTranslateESR_EL2,
+ miscRegTranslateFAR_EL1,
+ miscRegTranslateFAR_EL2,
+ miscRegTranslateHPFAR_EL2,
+ miscRegTranslatePAR_EL1,
+ miscRegTranslateMAIR_EL1,
+ miscRegTranslateMAIR_EL2,
+ miscRegTranslateAMAIR_EL1,
+ miscRegTranslateVBAR_EL1,
+ miscRegTranslateVBAR_EL2,
+ miscRegTranslateCONTEXTIDR_EL1,
+ miscRegTranslateTPIDR_EL0,
+ miscRegTranslateTPIDRRO_EL0,
+ miscRegTranslateTPIDR_EL1,
+ miscRegTranslateTPIDR_EL2,
+ miscRegTranslateTEECR32_EL1,
+ miscRegTranslateCNTFRQ_EL0,
+ miscRegTranslateCNTPCT_EL0,
+ miscRegTranslateCNTVCT_EL0,
+ miscRegTranslateCNTVOFF_EL2,
+ miscRegTranslateCNTKCTL_EL1,
+ miscRegTranslateCNTHCTL_EL2,
+ miscRegTranslateCNTP_TVAL_EL0,
+ miscRegTranslateCNTP_CTL_EL0,
+ miscRegTranslateCNTP_CVAL_EL0,
+ miscRegTranslateCNTV_TVAL_EL0,
+ miscRegTranslateCNTV_CTL_EL0,
+ miscRegTranslateCNTV_CVAL_EL0,
+ miscRegTranslateCNTHP_TVAL_EL2,
+ miscRegTranslateCNTHP_CTL_EL2,
+ miscRegTranslateCNTHP_CVAL_EL2,
+ miscRegTranslateDACR32_EL2,
+ miscRegTranslateIFSR32_EL2,
+ miscRegTranslateTEEHBR32_EL1,
+ miscRegTranslateSDER32_EL3,
+ miscRegTranslateMax
+ };
+
+ class ISA : public SimObject
{
protected:
+ // Parent system
+ ArmSystem *system;
+
+ // Micro Architecture
+ const Enums::DecoderFlavour _decoderFlavour;
+
+ /** 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;
+
+ // Cached copies of system-level properties
+ bool haveSecurity;
+ bool haveLPAE;
+ bool haveVirtualization;
+ bool haveLargeAsid64;
+ uint8_t physAddrRange64;
+
+ /** Register translation entry used in lookUpMiscReg */
+ struct MiscRegLUTEntry {
+ uint32_t lower;
+ uint32_t upper;
+ };
+
+ struct MiscRegInitializerEntry {
+ uint32_t index;
+ struct MiscRegLUTEntry entry;
+ };
+
+ /** Register table noting all translations */
+ static const struct MiscRegInitializerEntry
+ MiscRegSwitch[miscRegTranslateMax];
+
+ /** Translation table accessible via the value of the register */
+ std::vector<struct MiscRegLUTEntry> lookUpMiscReg;
+
MiscReg miscRegs[NumMiscRegs];
const IntRegIndex *intRegMap;
void
updateRegMap(CPSR cpsr)
{
- switch (cpsr.mode) {
- case MODE_USER:
- case MODE_SYSTEM:
- intRegMap = IntRegUsrMap;
- break;
- case MODE_FIQ:
- intRegMap = IntRegFiqMap;
- break;
- case MODE_IRQ:
- intRegMap = IntRegIrqMap;
- break;
- case MODE_SVC:
- intRegMap = IntRegSvcMap;
- break;
- case MODE_MON:
- intRegMap = IntRegMonMap;
- break;
- case MODE_ABORT:
- intRegMap = IntRegAbtMap;
- break;
- case MODE_UNDEFINED:
- intRegMap = IntRegUndMap;
- break;
- default:
- panic("Unrecognized mode setting in CPSR.\n");
- }
- }
-
- public:
- void clear()
- {
- memset(miscRegs, 0, sizeof(miscRegs));
- CPSR cpsr = 0;
- cpsr.mode = MODE_USER;
- miscRegs[MISCREG_CPSR] = cpsr;
- updateRegMap(cpsr);
-
- SCTLR sctlr = 0;
- sctlr.nmfi = 1;
- sctlr.rao1 = 1;
- sctlr.rao2 = 1;
- sctlr.rao3 = 1;
- sctlr.rao4 = 1;
- miscRegs[MISCREG_SCTLR] = sctlr;
-
- /*
- * Technically this should be 0, but we don't support those
- * settings.
- */
- miscRegs[MISCREG_CPACR] = 0x0fffffff;
-
- /* One region, unified map. */
- miscRegs[MISCREG_MPUIR] = 0x100;
-
- /*
- * Implemented = '5' from "M5",
- * Variant = 0,
- */
- miscRegs[MISCREG_MIDR] =
- (0x35 << 24) | //Implementor is '5' from "M5"
- (0 << 20) | //Variant
- (0xf << 16) | //Architecture from CPUID scheme
- (0 << 4) | //Primary part number
- (0 << 0) | //Revision
- 0;
-
- //XXX We need to initialize the rest of the state.
- }
-
- MiscReg
- readMiscRegNoEffect(int misc_reg)
- {
- assert(misc_reg < NumMiscRegs);
- if (misc_reg == MISCREG_SPSR) {
- CPSR cpsr = miscRegs[MISCREG_CPSR];
+ if (cpsr.width == 0) {
+ intRegMap = IntReg64Map;
+ } else {
switch (cpsr.mode) {
case MODE_USER:
- return miscRegs[MISCREG_SPSR];
+ case MODE_SYSTEM:
+ intRegMap = IntRegUsrMap;
+ break;
case MODE_FIQ:
- return miscRegs[MISCREG_SPSR_FIQ];
+ intRegMap = IntRegFiqMap;
+ break;
case MODE_IRQ:
- return miscRegs[MISCREG_SPSR_IRQ];
+ intRegMap = IntRegIrqMap;
+ break;
case MODE_SVC:
- return miscRegs[MISCREG_SPSR_SVC];
+ intRegMap = IntRegSvcMap;
+ break;
case MODE_MON:
- return miscRegs[MISCREG_SPSR_MON];
+ intRegMap = IntRegMonMap;
+ break;
case MODE_ABORT:
- return miscRegs[MISCREG_SPSR_ABT];
+ intRegMap = IntRegAbtMap;
+ break;
+ case MODE_HYP:
+ intRegMap = IntRegHypMap;
+ break;
case MODE_UNDEFINED:
- return miscRegs[MISCREG_SPSR_UND];
+ intRegMap = IntRegUndMap;
+ break;
default:
- return miscRegs[MISCREG_SPSR];
+ panic("Unrecognized mode setting in CPSR.\n");
}
}
- return miscRegs[misc_reg];
}
- MiscReg
- readMiscReg(int misc_reg, ThreadContext *tc)
+ BaseISADevice &getGenericTimer(ThreadContext *tc);
+
+
+ private:
+ inline void assert32(ThreadContext *tc) {
+ CPSR cpsr M5_VAR_USED = readMiscReg(MISCREG_CPSR, tc);
+ assert(cpsr.width);
+ }
+
+ inline void assert64(ThreadContext *tc) {
+ CPSR cpsr M5_VAR_USED = readMiscReg(MISCREG_CPSR, tc);
+ assert(!cpsr.width);
+ }
+
+ void tlbiVA(ThreadContext *tc, MiscReg newVal, uint16_t asid,
+ bool secure_lookup, uint8_t target_el);
+
+ void tlbiALL(ThreadContext *tc, bool secure_lookup, uint8_t target_el);
+
+ void tlbiALLN(ThreadContext *tc, bool hyp, uint8_t target_el);
+
+ void tlbiMVA(ThreadContext *tc, MiscReg newVal, bool secure_lookup,
+ bool hyp, uint8_t target_el);
+
+ public:
+ void clear();
+ void clear64(const ArmISAParams *p);
+
+ MiscReg readMiscRegNoEffect(int misc_reg) const;
+ MiscReg readMiscReg(int misc_reg, ThreadContext *tc);
+ void setMiscRegNoEffect(int misc_reg, const MiscReg &val);
+ void setMiscReg(int misc_reg, const MiscReg &val, ThreadContext *tc);
+
+ int
+ flattenIntIndex(int reg) const
{
- if (misc_reg == MISCREG_CPSR) {
- CPSR cpsr = miscRegs[misc_reg];
- Addr pc = tc->readPC();
- if (pc & (ULL(1) << PcJBitShift))
- cpsr.j = 1;
- else
- cpsr.j = 0;
- if (pc & (ULL(1) << PcTBitShift))
- cpsr.t = 1;
- else
- cpsr.t = 0;
- return cpsr;
- }
- if (misc_reg >= MISCREG_CP15_UNIMP_START &&
- misc_reg < MISCREG_CP15_END) {
- panic("Unimplemented CP15 register %s read.\n",
- miscRegName[misc_reg]);
- }
- switch (misc_reg) {
- case MISCREG_CLIDR:
- warn("The clidr register always reports 0 caches.\n");
- break;
- case MISCREG_CCSIDR:
- warn("The ccsidr register isn't implemented and "
- "always reads as 0.\n");
- break;
+ assert(reg >= 0);
+ if (reg < NUM_ARCH_INTREGS) {
+ return intRegMap[reg];
+ } else if (reg < NUM_INTREGS) {
+ return reg;
+ } else if (reg == INTREG_SPX) {
+ CPSR cpsr = miscRegs[MISCREG_CPSR];
+ ExceptionLevel el = opModeToEL(
+ (OperatingMode) (uint8_t) cpsr.mode);
+ if (!cpsr.sp && el != EL0)
+ return INTREG_SP0;
+ switch (el) {
+ case EL3:
+ return INTREG_SP3;
+ // @todo: uncomment this to enable Virtualization
+ // case EL2:
+ // return INTREG_SP2;
+ case EL1:
+ return INTREG_SP1;
+ case EL0:
+ return INTREG_SP0;
+ default:
+ panic("Invalid exception level");
+ break;
+ }
+ } else {
+ return flattenIntRegModeIndex(reg);
}
- return readMiscRegNoEffect(misc_reg);
}
- void
- setMiscRegNoEffect(int misc_reg, const MiscReg &val)
+ int
+ flattenFloatIndex(int reg) const
+ {
+ assert(reg >= 0);
+ return reg;
+ }
+
+ int
+ flattenCCIndex(int reg) const
+ {
+ assert(reg >= 0);
+ return reg;
+ }
+
+ int
+ flattenMiscIndex(int reg) const
{
- assert(misc_reg < NumMiscRegs);
- if (misc_reg == MISCREG_SPSR) {
+ 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:
- miscRegs[MISCREG_SPSR] = val;
- return;
+ warn("User mode does not have SPSR\n");
+ flat_idx = MISCREG_SPSR;
+ break;
case MODE_FIQ:
- miscRegs[MISCREG_SPSR_FIQ] = val;
- return;
+ flat_idx = MISCREG_SPSR_FIQ;
+ break;
case MODE_IRQ:
- miscRegs[MISCREG_SPSR_IRQ] = val;
- return;
+ flat_idx = MISCREG_SPSR_IRQ;
+ break;
case MODE_SVC:
- miscRegs[MISCREG_SPSR_SVC] = val;
- return;
+ flat_idx = MISCREG_SPSR_SVC;
+ break;
case MODE_MON:
- miscRegs[MISCREG_SPSR_MON] = val;
- return;
+ flat_idx = MISCREG_SPSR_MON;
+ break;
case MODE_ABORT:
- miscRegs[MISCREG_SPSR_ABT] = val;
- return;
+ flat_idx = MISCREG_SPSR_ABT;
+ break;
+ case MODE_HYP:
+ flat_idx = MISCREG_SPSR_HYP;
+ break;
case MODE_UNDEFINED:
- miscRegs[MISCREG_SPSR_UND] = val;
- return;
+ flat_idx = MISCREG_SPSR_UND;
+ break;
default:
- miscRegs[MISCREG_SPSR] = val;
- return;
+ warn("Trying to access SPSR in an invalid mode: %d\n",
+ cpsr.mode);
+ flat_idx = MISCREG_SPSR;
+ break;
}
- }
- miscRegs[misc_reg] = val;
- }
-
- void
- setMiscReg(int misc_reg, const MiscReg &val, ThreadContext *tc)
- {
- MiscReg newVal = val;
- if (misc_reg == MISCREG_CPSR) {
- updateRegMap(val);
- CPSR cpsr = val;
- Addr npc = tc->readNextPC() & ~PcModeMask;
- if (cpsr.j)
- npc = npc | (ULL(1) << PcJBitShift);
- if (cpsr.t)
- npc = npc | (ULL(1) << PcTBitShift);
-
- tc->setNextPC(npc);
- }
- if (misc_reg >= MISCREG_CP15_UNIMP_START &&
- misc_reg < MISCREG_CP15_END) {
- panic("Unimplemented CP15 register %s wrote with %#x.\n",
- miscRegName[misc_reg], val);
- }
- switch (misc_reg) {
- case MISCREG_CPACR:
- newVal = bits(val, 27, 0);
- if (newVal != 0x0fffffff) {
- panic("Disabling coprocessors isn't implemented.\n");
+ } else if (miscRegInfo[reg][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 (miscRegInfo[reg][MISCREG_BANKED]) {
+ bool secureReg = haveSecurity &&
+ inSecureState(miscRegs[MISCREG_SCR],
+ miscRegs[MISCREG_CPSR]);
+ flat_idx += secureReg ? 2 : 1;
}
- break;
- case MISCREG_CSSELR:
- warn("The csselr register isn't implemented.\n");
- break;
}
- return setMiscRegNoEffect(misc_reg, newVal);
+ return flat_idx;
}
- int
- flattenIntIndex(int reg)
+ void serialize(CheckpointOut &cp) const
{
- assert(reg >= 0);
- if (reg < NUM_ARCH_INTREGS) {
- return intRegMap[reg];
- } else if (reg < NUM_INTREGS) {
- return reg;
- } else {
- reg -= NUM_INTREGS;
- assert(reg < NUM_ARCH_INTREGS);
- return reg;
- }
- }
+ DPRINTF(Checkpoint, "Serializing Arm Misc Registers\n");
+ SERIALIZE_ARRAY(miscRegs, NumMiscRegs);
- int
- flattenFloatIndex(int reg)
+ SERIALIZE_SCALAR(haveSecurity);
+ SERIALIZE_SCALAR(haveLPAE);
+ SERIALIZE_SCALAR(haveVirtualization);
+ SERIALIZE_SCALAR(haveLargeAsid64);
+ SERIALIZE_SCALAR(physAddrRange64);
+ }
+ void unserialize(CheckpointIn &cp)
{
- return reg;
+ DPRINTF(Checkpoint, "Unserializing Arm Misc Registers\n");
+ UNSERIALIZE_ARRAY(miscRegs, NumMiscRegs);
+ CPSR tmp_cpsr = miscRegs[MISCREG_CPSR];
+ updateRegMap(tmp_cpsr);
+
+ UNSERIALIZE_SCALAR(haveSecurity);
+ UNSERIALIZE_SCALAR(haveLPAE);
+ UNSERIALIZE_SCALAR(haveVirtualization);
+ UNSERIALIZE_SCALAR(haveLargeAsid64);
+ UNSERIALIZE_SCALAR(physAddrRange64);
}
- void serialize(EventManager *em, std::ostream &os)
- {}
- void unserialize(EventManager *em, Checkpoint *cp,
- const std::string §ion)
- {}
+ void startup(ThreadContext *tc) {}
- ISA()
- {
- clear();
- }
+ Enums::DecoderFlavour decoderFlavour() const { return _decoderFlavour; }
+
+ /// Explicitly import the otherwise hidden startup
+ using SimObject::startup;
+
+ typedef ArmISAParams Params;
+
+ const Params *params() const;
+
+ ISA(Params *p);
};
}