Commit c0f4af17 authored by Peter Maydell's avatar Peter Maydell
Browse files

target-arm: Don't handle c15_cpar changes via tb_flush()



At the moment we try to handle c15_cpar with the strategy of:
 * emit generated code which makes assumptions about its value
 * when the register value changes call tb_flush() to throw
   away the now-invalid generated code
This works because XScale CPUs are always uniprocessor, but
it's confusing because it suggests that the same approach can
be taken for other registers. It also means we do a tb_flush()
on CPU reset, which makes multithreaded linux-user binaries
even more likely to fail than would otherwise be the case.

Replace it with a combination of TB flags for the access
checks done on cp0/cp1 for the XScale and iwMMXt instructions,
plus a runtime check for cp2..cp13 coprocessor accesses.

Signed-off-by: default avatarPeter Maydell <peter.maydell@linaro.org>
Message-id: 1411056959-23070-1-git-send-email-peter.maydell@linaro.org
parent f59492b9
Loading
Loading
Loading
Loading
+0 −5
Original line number Diff line number Diff line
@@ -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()) {
+9 −0
Original line number Diff line number Diff line
@@ -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;
+1 −6
Original line number Diff line number Diff line
@@ -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[] = {
+11 −0
Original line number Diff line number Diff line
@@ -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;
+21 −19
Original line number Diff line number Diff line
@@ -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:
    /* 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;
    default:
        break;
    }

    /* 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,10 +7674,12 @@ 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.  */
            ARCH(5TE);
@@ -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;
Loading