Commit 3f26c122 authored by Riku Voipio's avatar Riku Voipio Committed by Aurelien Jarno
Browse files

target-arm: refactor cp15.c13 register access



Access the cp15.c13 TLS registers directly with TCG ops instead of with
a slow helper. If the the cp15 read/write was not TLS register access,
fall back to the cp15 helper.

This makes accessing __thread variables in linux-user when apps are compiled
with -mtp=cp15 possible. legal cp15 register to acces from linux-user are
already checked in cp15_user_ok.

While at it, make the cp15.c13 Thread ID registers available only on
ARMv6K and newer.

Signed-off-by: default avatarRiku Voipio <riku.voipio@nokia.com>
parent fd052bf6
Loading
Loading
Loading
Loading
+0 −16
Original line number Diff line number Diff line
@@ -511,7 +511,6 @@ void HELPER(set_cp15)(CPUState *env, uint32_t insn, uint32_t val)
uint32_t HELPER(get_cp15)(CPUState *env, uint32_t insn)
{
    cpu_abort(env, "cp15 insn %08x\n", insn);
    return 0;
}

/* These should probably raise undefined insn exceptions.  */
@@ -1491,15 +1490,6 @@ void HELPER(set_cp15)(CPUState *env, uint32_t insn, uint32_t val)
              tlb_flush(env, 0);
            env->cp15.c13_context = val;
            break;
        case 2:
            env->cp15.c13_tls1 = val;
            break;
        case 3:
            env->cp15.c13_tls2 = val;
            break;
        case 4:
            env->cp15.c13_tls3 = val;
            break;
        default:
            goto bad_reg;
        }
@@ -1779,12 +1769,6 @@ uint32_t HELPER(get_cp15)(CPUState *env, uint32_t insn)
            return env->cp15.c13_fcse;
        case 1:
            return env->cp15.c13_context;
        case 2:
            return env->cp15.c13_tls1;
        case 3:
            return env->cp15.c13_tls2;
        case 4:
            return env->cp15.c13_tls3;
        default:
            goto bad_reg;
        }
+55 −0
Original line number Diff line number Diff line
@@ -2455,6 +2455,57 @@ static int cp15_user_ok(uint32_t insn)
    return 0;
}

static int cp15_tls_load_store(CPUState *env, DisasContext *s, uint32_t insn, uint32_t rd)
{
    TCGv tmp;
    int cpn = (insn >> 16) & 0xf;
    int cpm = insn & 0xf;
    int op = ((insn >> 5) & 7) | ((insn >> 18) & 0x38);

    if (!arm_feature(env, ARM_FEATURE_V6K))
        return 0;

    if (!(cpn == 13 && cpm == 0))
        return 0;

    if (insn & ARM_CP_RW_BIT) {
        tmp = new_tmp();
        switch (op) {
        case 2:
            tcg_gen_ld_i32(tmp, cpu_env, offsetof(CPUARMState, cp15.c13_tls1));
            break;
        case 3:
            tcg_gen_ld_i32(tmp, cpu_env, offsetof(CPUARMState, cp15.c13_tls2));
            break;
        case 4:
            tcg_gen_ld_i32(tmp, cpu_env, offsetof(CPUARMState, cp15.c13_tls3));
            break;
        default:
            dead_tmp(tmp);
            return 0;
        }
        store_reg(s, rd, tmp);

    } else {
        tmp = load_reg(s, rd);
        switch (op) {
        case 2:
            tcg_gen_st_i32(tmp, cpu_env, offsetof(CPUARMState, cp15.c13_tls1));
            break;
        case 3:
            tcg_gen_st_i32(tmp, cpu_env, offsetof(CPUARMState, cp15.c13_tls2));
            break;
        case 4:
            tcg_gen_st_i32(tmp, cpu_env, offsetof(CPUARMState, cp15.c13_tls3));
            break;
        default:
            return 0;
        }
        dead_tmp(tmp);
    }
    return 1;
}

/* Disassemble system coprocessor (cp15) instruction.  Return nonzero if
   instruction is not defined.  */
static int disas_cp15_insn(CPUState *env, DisasContext *s, uint32_t insn)
@@ -2489,6 +2540,10 @@ static int disas_cp15_insn(CPUState *env, DisasContext *s, uint32_t insn)
        return 0;
    }
    rd = (insn >> 12) & 0xf;

    if (cp15_tls_load_store(env, s, insn, rd))
        return 0;

    tmp2 = tcg_const_i32(insn);
    if (insn & ARM_CP_RW_BIT) {
        tmp = new_tmp();