diff options
-rw-r--r-- | target-arm/cpu.h | 52 | ||||
-rw-r--r-- | target-arm/helper.c | 46 | ||||
-rw-r--r-- | target-arm/translate-a64.c | 2 | ||||
-rw-r--r-- | target-arm/translate.h | 2 |
4 files changed, 100 insertions, 2 deletions
diff --git a/target-arm/cpu.h b/target-arm/cpu.h index 76d824d315..2218c00dad 100644 --- a/target-arm/cpu.h +++ b/target-arm/cpu.h @@ -2191,7 +2191,11 @@ static inline bool arm_cpu_data_is_big_endian(CPUARMState *env) #define ARM_TBFLAG_BE_DATA_SHIFT 20 #define ARM_TBFLAG_BE_DATA_MASK (1 << ARM_TBFLAG_BE_DATA_SHIFT) -/* Bit usage when in AArch64 state: currently we have no A64 specific bits */ +/* Bit usage when in AArch64 state */ +#define ARM_TBFLAG_TBI0_SHIFT 0 /* TBI0 for EL0/1 or TBI for EL2/3 */ +#define ARM_TBFLAG_TBI0_MASK (0x1ull << ARM_TBFLAG_TBI0_SHIFT) +#define ARM_TBFLAG_TBI1_SHIFT 1 /* TBI1 for EL0/1 */ +#define ARM_TBFLAG_TBI1_MASK (0x1ull << ARM_TBFLAG_TBI1_SHIFT) /* some convenience accessor macros */ #define ARM_TBFLAG_AARCH64_STATE(F) \ @@ -2222,6 +2226,10 @@ static inline bool arm_cpu_data_is_big_endian(CPUARMState *env) (((F) & ARM_TBFLAG_NS_MASK) >> ARM_TBFLAG_NS_SHIFT) #define ARM_TBFLAG_BE_DATA(F) \ (((F) & ARM_TBFLAG_BE_DATA_MASK) >> ARM_TBFLAG_BE_DATA_SHIFT) +#define ARM_TBFLAG_TBI0(F) \ + (((F) & ARM_TBFLAG_TBI0_MASK) >> ARM_TBFLAG_TBI0_SHIFT) +#define ARM_TBFLAG_TBI1(F) \ + (((F) & ARM_TBFLAG_TBI1_MASK) >> ARM_TBFLAG_TBI1_SHIFT) static inline bool bswap_code(bool sctlr_b) { @@ -2319,12 +2327,51 @@ static inline bool arm_cpu_bswap_data(CPUARMState *env) } #endif +#ifndef CONFIG_USER_ONLY +/** + * arm_regime_tbi0: + * @env: CPUARMState + * @mmu_idx: MMU index indicating required translation regime + * + * Extracts the TBI0 value from the appropriate TCR for the current EL + * + * Returns: the TBI0 value. + */ +uint32_t arm_regime_tbi0(CPUARMState *env, ARMMMUIdx mmu_idx); + +/** + * arm_regime_tbi1: + * @env: CPUARMState + * @mmu_idx: MMU index indicating required translation regime + * + * Extracts the TBI1 value from the appropriate TCR for the current EL + * + * Returns: the TBI1 value. + */ +uint32_t arm_regime_tbi1(CPUARMState *env, ARMMMUIdx mmu_idx); +#else +/* We can't handle tagged addresses properly in user-only mode */ +static inline uint32_t arm_regime_tbi0(CPUARMState *env, ARMMMUIdx mmu_idx) +{ + return 0; +} + +static inline uint32_t arm_regime_tbi1(CPUARMState *env, ARMMMUIdx mmu_idx) +{ + return 0; +} +#endif + static inline void cpu_get_tb_cpu_state(CPUARMState *env, target_ulong *pc, target_ulong *cs_base, uint32_t *flags) { + ARMMMUIdx mmu_idx = cpu_mmu_index(env, false); if (is_a64(env)) { *pc = env->pc; *flags = ARM_TBFLAG_AARCH64_STATE_MASK; + /* Get control bits for tagged addresses */ + *flags |= (arm_regime_tbi0(env, mmu_idx) << ARM_TBFLAG_TBI0_SHIFT); + *flags |= (arm_regime_tbi1(env, mmu_idx) << ARM_TBFLAG_TBI1_SHIFT); } else { *pc = env->regs[15]; *flags = (env->thumb << ARM_TBFLAG_THUMB_SHIFT) @@ -2343,7 +2390,8 @@ static inline void cpu_get_tb_cpu_state(CPUARMState *env, target_ulong *pc, << ARM_TBFLAG_XSCALE_CPAR_SHIFT); } - *flags |= (cpu_mmu_index(env, false) << ARM_TBFLAG_MMUIDX_SHIFT); + *flags |= (mmu_idx << ARM_TBFLAG_MMUIDX_SHIFT); + /* The SS_ACTIVE and PSTATE_SS bits correspond to the state machine * states defined in the ARM ARM for software singlestep: * SS_ACTIVE PSTATE.SS State diff --git a/target-arm/helper.c b/target-arm/helper.c index 25f612d493..70e274221c 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -6720,6 +6720,52 @@ static inline TCR *regime_tcr(CPUARMState *env, ARMMMUIdx mmu_idx) return &env->cp15.tcr_el[regime_el(env, mmu_idx)]; } +/* Returns TBI0 value for current regime el */ +uint32_t arm_regime_tbi0(CPUARMState *env, ARMMMUIdx mmu_idx) +{ + TCR *tcr; + uint32_t el; + + /* For EL0 and EL1, TBI is controlled by stage 1's TCR, so convert + * a stage 1+2 mmu index into the appropriate stage 1 mmu index. + */ + if (mmu_idx == ARMMMUIdx_S12NSE0 || mmu_idx == ARMMMUIdx_S12NSE1) { + mmu_idx += ARMMMUIdx_S1NSE0; + } + + tcr = regime_tcr(env, mmu_idx); + el = regime_el(env, mmu_idx); + + if (el > 1) { + return extract64(tcr->raw_tcr, 20, 1); + } else { + return extract64(tcr->raw_tcr, 37, 1); + } +} + +/* Returns TBI1 value for current regime el */ +uint32_t arm_regime_tbi1(CPUARMState *env, ARMMMUIdx mmu_idx) +{ + TCR *tcr; + uint32_t el; + + /* For EL0 and EL1, TBI is controlled by stage 1's TCR, so convert + * a stage 1+2 mmu index into the appropriate stage 1 mmu index. + */ + if (mmu_idx == ARMMMUIdx_S12NSE0 || mmu_idx == ARMMMUIdx_S12NSE1) { + mmu_idx += ARMMMUIdx_S1NSE0; + } + + tcr = regime_tcr(env, mmu_idx); + el = regime_el(env, mmu_idx); + + if (el > 1) { + return 0; + } else { + return extract64(tcr->raw_tcr, 38, 1); + } +} + /* Return the TTBR associated with this translation regime */ static inline uint64_t regime_ttbr(CPUARMState *env, ARMMMUIdx mmu_idx, int ttbrn) diff --git a/target-arm/translate-a64.c b/target-arm/translate-a64.c index 307e281557..3b15d2cf7f 100644 --- a/target-arm/translate-a64.c +++ b/target-arm/translate-a64.c @@ -11175,6 +11175,8 @@ void gen_intermediate_code_a64(ARMCPU *cpu, TranslationBlock *tb) dc->condexec_mask = 0; dc->condexec_cond = 0; dc->mmu_idx = ARM_TBFLAG_MMUIDX(tb->flags); + dc->tbi0 = ARM_TBFLAG_TBI0(tb->flags); + dc->tbi1 = ARM_TBFLAG_TBI1(tb->flags); dc->current_el = arm_mmu_idx_to_el(dc->mmu_idx); #if !defined(CONFIG_USER_ONLY) dc->user = (dc->current_el == 0); diff --git a/target-arm/translate.h b/target-arm/translate.h index dbd7ac83d5..a53f25a407 100644 --- a/target-arm/translate.h +++ b/target-arm/translate.h @@ -22,6 +22,8 @@ typedef struct DisasContext { int user; #endif ARMMMUIdx mmu_idx; /* MMU index to use for normal loads/stores */ + bool tbi0; /* TBI0 for EL0/1 or TBI for EL2/3 */ + bool tbi1; /* TBI1 for EL0/1, not used for EL2/3 */ bool ns; /* Use non-secure CPREG bank on access */ int fp_excp_el; /* FP exception EL or 0 if enabled */ /* Flag indicating that exceptions from secure mode are routed to EL3. */ |