diff options
Diffstat (limited to 'src/arch/arm/isa.hh')
-rw-r--r-- | src/arch/arm/isa.hh | 331 |
1 files changed, 274 insertions, 57 deletions
diff --git a/src/arch/arm/isa.hh b/src/arch/arm/isa.hh index c747fc770..c72d5d50f 100644 --- a/src/arch/arm/isa.hh +++ b/src/arch/arm/isa.hh @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 ARM Limited + * Copyright (c) 2010, 2012-2013 ARM Limited * All rights reserved * * The license below extends only to copyright in the software and shall @@ -44,9 +44,11 @@ #define __ARCH_ARM_ISA_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 "dev/arm/generic_timer.hh" #include "sim/sim_object.hh" struct ArmISAParams; @@ -56,45 +58,174 @@ class EventManager; namespace ArmISA { + + /** + * 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; + + // 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"); + if (cpsr.width == 0) { + intRegMap = IntReg64Map; + } else { + 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_HYP: + intRegMap = IntRegHypMap; + break; + case MODE_UNDEFINED: + intRegMap = IntRegUndMap; + break; + default: + panic("Unrecognized mode setting in CPSR.\n"); + } } } + ::GenericTimer::SystemCounter * getSystemCounter(ThreadContext *tc); + ::GenericTimer::ArchTimer * getArchTimer(ThreadContext *tc, + int cpu_id); + + + 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, uint8_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); @@ -109,28 +240,28 @@ namespace ArmISA return intRegMap[reg]; } else if (reg < NUM_INTREGS) { return reg; - } else { - int mode = reg / intRegsPerMode; - reg = reg % intRegsPerMode; - switch (mode) { - case MODE_USER: - case MODE_SYSTEM: - return INTREG_USR(reg); - case MODE_FIQ: - return INTREG_FIQ(reg); - case MODE_IRQ: - return INTREG_IRQ(reg); - case MODE_SVC: - return INTREG_SVC(reg); - case MODE_MON: - return INTREG_MON(reg); - case MODE_ABORT: - return INTREG_ABT(reg); - case MODE_UNDEFINED: - return INTREG_UND(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("Flattening into an unknown mode.\n"); + panic("Invalid exception level"); + break; } + } else { + return flattenIntRegModeIndex(reg); } } @@ -150,47 +281,127 @@ namespace ArmISA int flattenMiscIndex(int reg) const { + int flat_idx = reg; + if (reg == MISCREG_SPSR) { - int spsr_idx = NUM_MISCREGS; 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"); - spsr_idx = MISCREG_SPSR; + flat_idx = MISCREG_SPSR; break; case MODE_FIQ: - spsr_idx = MISCREG_SPSR_FIQ; + flat_idx = MISCREG_SPSR_FIQ; break; case MODE_IRQ: - spsr_idx = MISCREG_SPSR_IRQ; + flat_idx = MISCREG_SPSR_IRQ; break; case MODE_SVC: - spsr_idx = MISCREG_SPSR_SVC; + flat_idx = MISCREG_SPSR_SVC; break; case MODE_MON: - spsr_idx = MISCREG_SPSR_MON; + flat_idx = MISCREG_SPSR_MON; break; case MODE_ABORT: - spsr_idx = MISCREG_SPSR_ABT; + flat_idx = MISCREG_SPSR_ABT; + break; + case MODE_HYP: + flat_idx = MISCREG_SPSR_HYP; break; case MODE_UNDEFINED: - spsr_idx = MISCREG_SPSR_UND; + flat_idx = MISCREG_SPSR_UND; break; default: warn("Trying to access SPSR in an invalid mode: %d\n", cpsr.mode); - spsr_idx = MISCREG_SPSR; + flat_idx = MISCREG_SPSR; break; } - return spsr_idx; + } 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; + } } - return reg; + return flat_idx; } void serialize(std::ostream &os) { DPRINTF(Checkpoint, "Serializing Arm Misc Registers\n"); SERIALIZE_ARRAY(miscRegs, NumMiscRegs); + + SERIALIZE_SCALAR(haveSecurity); + SERIALIZE_SCALAR(haveLPAE); + SERIALIZE_SCALAR(haveVirtualization); + SERIALIZE_SCALAR(haveLargeAsid64); + SERIALIZE_SCALAR(physAddrRange64); } void unserialize(Checkpoint *cp, const std::string §ion) { @@ -198,6 +409,12 @@ namespace ArmISA 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 startup(ThreadContext *tc) {} |