diff --git a/target-arm/cpu.c b/target-arm/cpu.c index 6ab0e03dbd..248778d57a 100644 --- a/target-arm/cpu.c +++ b/target-arm/cpu.c @@ -173,11 +173,6 @@ static void arm_cpu_reset(CPUState *s) set_float_detect_tininess(float_tininess_before_rounding, &env->vfp.standard_fp_status); tlb_flush(s, 1); - /* Reset is a state change for some CPUARMState fields which we - * bake assumptions about into translated code, so we need to - * tb_flush(). - */ - tb_flush(env); #ifndef CONFIG_USER_ONLY if (kvm_enabled()) { diff --git a/target-arm/cpu.h b/target-arm/cpu.h index fa6ae0acc3..7bd3af9c07 100644 --- a/target-arm/cpu.h +++ b/target-arm/cpu.h @@ -1224,6 +1224,11 @@ static inline bool arm_singlestep_active(CPUARMState *env) #define ARM_TBFLAG_SS_ACTIVE_MASK (1 << ARM_TBFLAG_SS_ACTIVE_SHIFT) #define ARM_TBFLAG_PSTATE_SS_SHIFT 19 #define ARM_TBFLAG_PSTATE_SS_MASK (1 << ARM_TBFLAG_PSTATE_SS_SHIFT) +/* We store the bottom two bits of the CPAR as TB flags and handle + * checks on the other bits at runtime + */ +#define ARM_TBFLAG_XSCALE_CPAR_SHIFT 20 +#define ARM_TBFLAG_XSCALE_CPAR_MASK (3 << ARM_TBFLAG_XSCALE_CPAR_SHIFT) /* Bit usage when in AArch64 state */ #define ARM_TBFLAG_AA64_EL_SHIFT 0 @@ -1258,6 +1263,8 @@ static inline bool arm_singlestep_active(CPUARMState *env) (((F) & ARM_TBFLAG_SS_ACTIVE_MASK) >> ARM_TBFLAG_SS_ACTIVE_SHIFT) #define ARM_TBFLAG_PSTATE_SS(F) \ (((F) & ARM_TBFLAG_PSTATE_SS_MASK) >> ARM_TBFLAG_PSTATE_SS_SHIFT) +#define ARM_TBFLAG_XSCALE_CPAR(F) \ + (((F) & ARM_TBFLAG_XSCALE_CPAR_MASK) >> ARM_TBFLAG_XSCALE_CPAR_SHIFT) #define ARM_TBFLAG_AA64_EL(F) \ (((F) & ARM_TBFLAG_AA64_EL_MASK) >> ARM_TBFLAG_AA64_EL_SHIFT) #define ARM_TBFLAG_AA64_FPEN(F) \ @@ -1335,6 +1342,8 @@ static inline void cpu_get_tb_cpu_state(CPUARMState *env, target_ulong *pc, *flags |= ARM_TBFLAG_PSTATE_SS_MASK; } } + *flags |= (extract32(env->cp15.c15_cpar, 0, 2) + << ARM_TBFLAG_XSCALE_CPAR_SHIFT); } *cs_base = 0; diff --git a/target-arm/helper.c b/target-arm/helper.c index d246d36de4..dd9fca56f6 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -1714,12 +1714,7 @@ static const ARMCPRegInfo omap_cp_reginfo[] = { static void xscale_cpar_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value) { - value &= 0x3fff; - if (env->cp15.c15_cpar != value) { - /* Changes cp0 to cp13 behavior, so needs a TB flush. */ - tb_flush(env); - env->cp15.c15_cpar = value; - } + env->cp15.c15_cpar = value & 0x3fff; } static const ARMCPRegInfo xscale_cp_reginfo[] = { diff --git a/target-arm/op_helper.c b/target-arm/op_helper.c index d0bcd97fbb..25243bd487 100644 --- a/target-arm/op_helper.c +++ b/target-arm/op_helper.c @@ -301,6 +301,17 @@ void HELPER(set_user_reg)(CPUARMState *env, uint32_t regno, uint32_t val) void HELPER(access_check_cp_reg)(CPUARMState *env, void *rip, uint32_t syndrome) { const ARMCPRegInfo *ri = rip; + + if (arm_feature(env, ARM_FEATURE_XSCALE) && ri->cp < 14 + && extract32(env->cp15.c15_cpar, ri->cp, 1) == 0) { + env->exception.syndrome = syndrome; + raise_exception(env, EXCP_UDEF); + } + + if (!ri->accessfn) { + return; + } + switch (ri->accessfn(env, ri)) { case CP_ACCESS_OK: return; diff --git a/target-arm/translate.c b/target-arm/translate.c index 2c0b1deaea..8a2994fcb4 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -7001,22 +7001,18 @@ static int disas_coproc_insn(CPUARMState * env, DisasContext *s, uint32_t insn) const ARMCPRegInfo *ri; cpnum = (insn >> 8) & 0xf; - if (arm_feature(env, ARM_FEATURE_XSCALE) - && ((env->cp15.c15_cpar ^ 0x3fff) & (1 << cpnum))) - return 1; - /* First check for coprocessor space used for actual instructions */ - switch (cpnum) { - case 0: - case 1: - if (arm_feature(env, ARM_FEATURE_IWMMXT)) { - return disas_iwmmxt_insn(env, s, insn); - } else if (arm_feature(env, ARM_FEATURE_XSCALE)) { - return disas_dsp_insn(env, s, insn); - } - return 1; - default: - break; + /* First check for coprocessor space used for XScale/iwMMXt insns */ + if (arm_feature(env, ARM_FEATURE_XSCALE) && (cpnum < 2)) { + if (extract32(s->c15_cpar, cpnum, 1) == 0) { + return 1; + } + if (arm_feature(env, ARM_FEATURE_IWMMXT)) { + return disas_iwmmxt_insn(env, s, insn); + } else if (arm_feature(env, ARM_FEATURE_XSCALE)) { + return disas_dsp_insn(env, s, insn); + } + return 1; } /* Otherwise treat as a generic register access */ @@ -7049,9 +7045,12 @@ static int disas_coproc_insn(CPUARMState * env, DisasContext *s, uint32_t insn) return 1; } - if (ri->accessfn) { + if (ri->accessfn || + (arm_feature(env, ARM_FEATURE_XSCALE) && cpnum < 14)) { /* Emit code to perform further access permissions checks at * runtime; this may result in an exception. + * Note that on XScale all cp0..c13 registers do an access check + * call in order to handle c15_cpar. */ TCGv_ptr tmpptr; TCGv_i32 tcg_syn; @@ -7675,9 +7674,11 @@ static void disas_arm_insn(CPUARMState * env, DisasContext *s) } else if ((insn & 0x0e000f00) == 0x0c000100) { if (arm_feature(env, ARM_FEATURE_IWMMXT)) { /* iWMMXt register transfer. */ - if (env->cp15.c15_cpar & (1 << 1)) - if (!disas_iwmmxt_insn(env, s, insn)) + if (extract32(s->c15_cpar, 1, 1)) { + if (!disas_iwmmxt_insn(env, s, insn)) { return; + } + } } } else if ((insn & 0x0fe00000) == 0x0c400000) { /* Coprocessor double register transfer. */ @@ -10942,6 +10943,7 @@ static inline void gen_intermediate_code_internal(ARMCPU *cpu, dc->vfp_enabled = ARM_TBFLAG_VFPEN(tb->flags); dc->vec_len = ARM_TBFLAG_VECLEN(tb->flags); dc->vec_stride = ARM_TBFLAG_VECSTRIDE(tb->flags); + dc->c15_cpar = ARM_TBFLAG_XSCALE_CPAR(tb->flags); dc->cp_regs = cpu->cp_regs; dc->current_pl = arm_current_pl(env); dc->features = env->features; diff --git a/target-arm/translate.h b/target-arm/translate.h index b90d27514d..85c6f9dcb2 100644 --- a/target-arm/translate.h +++ b/target-arm/translate.h @@ -52,6 +52,8 @@ typedef struct DisasContext { bool is_ldex; /* True if a single-step exception will be taken to the current EL */ bool ss_same_el; + /* Bottom two bits of XScale c15_cpar coprocessor access control reg */ + int c15_cpar; #define TMP_A64_MAX 16 int tmp_a64_count; TCGv_i64 tmp_a64[TMP_A64_MAX];