From 6099733fc5d411550b19312e3c06dc41674fa463 Mon Sep 17 00:00:00 2001 From: Leon Alrae Date: Fri, 15 Feb 2019 17:08:09 -0500 Subject: [PATCH] target/mips: reimplement SC instruction emulation and use cmpxchg Completely rewrite conditional stores handling. Use cmpxchg. This eliminates need for separate implementations of SC instruction emulation for user and system emulation. Backports commit 33a07fa2db66376e6ee780d4a8b064dc5118cf34 from qemu --- qemu/target/mips/cpu.h | 4 -- qemu/target/mips/helper.c | 6 +- qemu/target/mips/helper.h | 2 - qemu/target/mips/op_helper.c | 25 ------- qemu/target/mips/translate.c | 125 ++++++++++++----------------------- qemu/tcg/tcg.h | 1 + 6 files changed, 45 insertions(+), 118 deletions(-) diff --git a/qemu/target/mips/cpu.h b/qemu/target/mips/cpu.h index 5a8f9de1..49ec302b 100644 --- a/qemu/target/mips/cpu.h +++ b/qemu/target/mips/cpu.h @@ -875,10 +875,8 @@ struct CPUMIPSState { /* XXX: Maybe make LLAddr per-TC? */ target_ulong lladdr; /* LL virtual address compared against SC */ target_ulong llval; - target_ulong llnewval; uint64_t llval_wp; uint32_t llnewval_wp; - target_ulong llreg; uint64_t CP0_LLAddr_rw_bitmask; int CP0_LLAddr_shift; /* @@ -1158,8 +1156,6 @@ enum { EXCP_LAST = EXCP_TLBRI, }; -/* Dummy exception for conditional stores. */ -#define EXCP_SC 0x100 /* * This is an internally generated WAKE request line. diff --git a/qemu/target/mips/helper.c b/qemu/target/mips/helper.c index 441e6413..61ef1026 100644 --- a/qemu/target/mips/helper.c +++ b/qemu/target/mips/helper.c @@ -1452,10 +1452,8 @@ void QEMU_NORETURN do_raise_exception_err(CPUMIPSState *env, { CPUState *cs = CPU(mips_env_get_cpu(env)); - if (exception < EXCP_SC) { - qemu_log_mask(CPU_LOG_INT, "%s: %d %d\n", - __func__, exception, error_code); - } + qemu_log_mask(CPU_LOG_INT, "%s: %d %d\n", + __func__, exception, error_code); cs->exception_index = exception; env->error_code = error_code; diff --git a/qemu/target/mips/helper.h b/qemu/target/mips/helper.h index 1b7a8ef5..0da6f9a0 100644 --- a/qemu/target/mips/helper.h +++ b/qemu/target/mips/helper.h @@ -13,10 +13,8 @@ DEF_HELPER_4(swr, void, env, tl, tl, int) #ifndef CONFIG_USER_ONLY DEF_HELPER_3(ll, tl, env, tl, int) -DEF_HELPER_4(sc, tl, env, tl, tl, int) #ifdef TARGET_MIPS64 DEF_HELPER_3(lld, tl, env, tl, int) -DEF_HELPER_4(scd, tl, env, tl, tl, int) #endif #endif diff --git a/qemu/target/mips/op_helper.c b/qemu/target/mips/op_helper.c index da2060ad..7d889254 100644 --- a/qemu/target/mips/op_helper.c +++ b/qemu/target/mips/op_helper.c @@ -376,31 +376,6 @@ HELPER_LD_ATOMIC(ll, lw, 0x3) HELPER_LD_ATOMIC(lld, ld, 0x7) #endif #undef HELPER_LD_ATOMIC - -#define HELPER_ST_ATOMIC(name, ld_insn, st_insn, almask) \ -target_ulong helper_##name(CPUMIPSState *env, target_ulong arg1, \ - target_ulong arg2, int mem_idx) \ -{ \ - target_long tmp; \ - \ - if (arg2 & almask) { \ - env->CP0_BadVAddr = arg2; \ - do_raise_exception(env, EXCP_AdES, GETPC()); \ - } \ - if (arg2 == env->lladdr) { \ - tmp = do_##ld_insn(env, arg2, mem_idx, GETPC()); \ - if (tmp == env->llval) { \ - do_##st_insn(env, arg2, arg1, mem_idx, GETPC()); \ - return 1; \ - } \ - } \ - return 0; \ -} -HELPER_ST_ATOMIC(sc, lw, sw, 0x3) -#ifdef TARGET_MIPS64 -HELPER_ST_ATOMIC(scd, ld, sd, 0x7) -#endif -#undef HELPER_ST_ATOMIC #endif #ifdef TARGET_WORDS_BIGENDIAN diff --git a/qemu/target/mips/translate.c b/qemu/target/mips/translate.c index 313cf202..b55e1bd3 100644 --- a/qemu/target/mips/translate.c +++ b/qemu/target/mips/translate.c @@ -3333,50 +3333,6 @@ OP_LD_ATOMIC(lld,ld64); #endif #undef OP_LD_ATOMIC -#ifdef CONFIG_USER_ONLY -#define OP_ST_ATOMIC(insn,fname,ldname,almask) \ -static inline void op_st_##insn(TCGv arg1, TCGv arg2, int rt, int mem_idx, \ - DisasContext *ctx) \ -{ \ - TCGContext *tcg_ctx = ctx->uc->tcg_ctx; \ - TCGv t0 = tcg_temp_new(tcg_ctx); \ - TCGLabel *l1 = gen_new_label(tcg_ctx); \ - TCGLabel *l2 = gen_new_label(tcg_ctx); \ - \ - tcg_gen_andi_tl(tcg_ctx, t0, arg2, almask); \ - tcg_gen_brcondi_tl(tcg_ctx, TCG_COND_EQ, t0, 0, l1); \ - tcg_gen_st_tl(tcg_ctx, arg2, tcg_ctx->cpu_env, offsetof(CPUMIPSState, CP0_BadVAddr)); \ - generate_exception(ctx, EXCP_AdES); \ - gen_set_label(tcg_ctx, l1); \ - tcg_gen_ld_tl(tcg_ctx, t0, tcg_ctx->cpu_env, offsetof(CPUMIPSState, lladdr)); \ - tcg_gen_brcond_tl(tcg_ctx, TCG_COND_NE, arg2, t0, l2); \ - tcg_gen_movi_tl(tcg_ctx, t0, rt | ((almask << 3) & 0x20)); \ - tcg_gen_st_tl(tcg_ctx, t0, tcg_ctx->cpu_env, offsetof(CPUMIPSState, llreg)); \ - tcg_gen_st_tl(tcg_ctx, arg1, tcg_ctx->cpu_env, offsetof(CPUMIPSState, llnewval)); \ - generate_exception_end(ctx, EXCP_SC); \ - gen_set_label(tcg_ctx, l2); \ - tcg_gen_movi_tl(tcg_ctx, t0, 0); \ - gen_store_gpr(ctx, t0, rt); \ - tcg_temp_free(tcg_ctx, t0); \ -} -#else -#define OP_ST_ATOMIC(insn,fname,ldname,almask) \ -static inline void op_st_##insn(TCGv arg1, TCGv arg2, int rt, int mem_idx, \ - DisasContext *ctx) \ -{ \ - TCGContext *tcg_ctx = ctx->uc->tcg_ctx; \ - TCGv t0 = tcg_temp_new(tcg_ctx); \ - gen_helper_1e2i(tcg_ctx, insn, t0, arg1, arg2, ctx->mem_idx); \ - gen_store_gpr(ctx, t0, rt); \ - tcg_temp_free(tcg_ctx, t0); \ -} -#endif -OP_ST_ATOMIC(sc,st32,ld32s,0x3); -#if defined(TARGET_MIPS64) -OP_ST_ATOMIC(scd,st64,ld64,0x7); -#endif -#undef OP_ST_ATOMIC - static void gen_base_offset_addr (DisasContext *ctx, TCGv addr, int base, int offset) { @@ -3693,41 +3649,39 @@ static void gen_st (DisasContext *ctx, uint32_t opc, int rt, /* Store conditional */ -static void gen_st_cond (DisasContext *ctx, uint32_t opc, int rt, - int base, int16_t offset) +static void gen_st_cond(DisasContext *ctx, int rt, int base, int offset, + TCGMemOp tcg_mo, bool eva) { TCGContext *tcg_ctx = ctx->uc->tcg_ctx; - TCGv t0, t1; - int mem_idx = ctx->mem_idx; + TCGv addr, t0, val; + TCGLabel *l1 = gen_new_label(tcg_ctx); + TCGLabel *done = gen_new_label(tcg_ctx); -#ifdef CONFIG_USER_ONLY - t0 = tcg_temp_local_new(tcg_ctx); - t1 = tcg_temp_local_new(tcg_ctx); -#else t0 = tcg_temp_new(tcg_ctx); - t1 = tcg_temp_new(tcg_ctx); -#endif - gen_base_offset_addr(ctx, t0, base, offset); - gen_load_gpr(ctx, t1, rt); - switch (opc) { -#if defined(TARGET_MIPS64) - case OPC_SCD: - case R6_OPC_SCD: - op_st_scd(t1, t0, rt, mem_idx, ctx); - break; -#endif - case OPC_SCE: - mem_idx = MIPS_HFLAG_UM; - /* fall through */ - case OPC_SC: - case R6_OPC_SC: - op_st_sc(t1, t0, rt, mem_idx, ctx); - break; - } - tcg_temp_free(tcg_ctx, t1); + addr = tcg_temp_new(tcg_ctx); + /* compare the address against that of the preceeding LL */ + gen_base_offset_addr(ctx, addr, base, offset); + tcg_gen_brcond_tl(tcg_ctx, TCG_COND_EQ, addr, tcg_ctx->cpu_lladdr, l1); + tcg_temp_free(tcg_ctx, addr); + tcg_gen_movi_tl(tcg_ctx, t0, 0); + gen_store_gpr(ctx, t0, rt); + tcg_gen_br(tcg_ctx, done); + + gen_set_label(tcg_ctx, l1); + /* generate cmpxchg */ + val = tcg_temp_new(tcg_ctx); + gen_load_gpr(ctx, val, rt); + tcg_gen_atomic_cmpxchg_tl(tcg_ctx, t0, tcg_ctx->cpu_lladdr, tcg_ctx->cpu_llval, val, + eva ? MIPS_HFLAG_UM : ctx->mem_idx, tcg_mo); + tcg_gen_setcond_tl(tcg_ctx, TCG_COND_EQ, t0, t0, tcg_ctx->cpu_llval); + gen_store_gpr(ctx, t0, rt); + tcg_temp_free(tcg_ctx, val); + + gen_set_label(tcg_ctx, done); tcg_temp_free(tcg_ctx, t0); } + static void gen_scwp(DisasContext *ctx, uint32_t base, int16_t offset, uint32_t reg1, uint32_t reg2, bool eva) { @@ -16967,13 +16921,13 @@ static void decode_micromips32_opc(CPUMIPSState *env, DisasContext *ctx) gen_st(ctx, mips32_op, rt, rs, offset); break; case SC: - gen_st_cond(ctx, OPC_SC, rt, rs, offset); + gen_st_cond(ctx, rt, rs, offset, MO_TESL, false); break; #if defined(TARGET_MIPS64) case SCD: check_insn(ctx, ISA_MIPS3); check_mips_64(ctx); - gen_st_cond(ctx, OPC_SCD, rt, rs, offset); + gen_st_cond(ctx, rt, rs, offset, MO_TEQ, false); break; #endif case LD_EVA: @@ -17054,7 +17008,7 @@ static void decode_micromips32_opc(CPUMIPSState *env, DisasContext *ctx) mips32_op = OPC_SHE; goto do_st_lr; case SCE: - gen_st_cond(ctx, OPC_SCE, rt, rs, offset); + gen_st_cond(ctx, rt, rs, offset, MO_TESL, true); break; case SWE: mips32_op = OPC_SWE; @@ -21691,7 +21645,7 @@ static int decode_nanomips_32_48_opc(CPUMIPSState *env, DisasContext *ctx) case NM_P_SC: switch (ctx->opcode & 0x03) { case NM_SC: - gen_st_cond(ctx, OPC_SC, rt, rs, s); + gen_st_cond(ctx, rt, rs, s, MO_TESL, false); break; case NM_SCWP: check_xnp(ctx); @@ -21794,7 +21748,7 @@ static int decode_nanomips_32_48_opc(CPUMIPSState *env, DisasContext *ctx) check_xnp(ctx); check_eva(ctx); check_cp0_enabled(ctx); - gen_st_cond(ctx, OPC_SCE, rt, rs, s); + gen_st_cond(ctx, rt, rs, s, MO_TESL, true); break; case NM_SCWPE: check_xnp(ctx); @@ -26852,7 +26806,7 @@ static void decode_opc_special3_r6(CPUMIPSState *env, DisasContext *ctx) } break; case R6_OPC_SC: - gen_st_cond(ctx, op1, rt, rs, imm); + gen_st_cond(ctx, rt, rs, imm, MO_TESL, false); break; case R6_OPC_LL: gen_ld(ctx, op1, rt, rs, imm); @@ -26879,7 +26833,7 @@ static void decode_opc_special3_r6(CPUMIPSState *env, DisasContext *ctx) break; #if defined(TARGET_MIPS64) case R6_OPC_SCD: - gen_st_cond(ctx, op1, rt, rs, imm); + gen_st_cond(ctx, rt, rs, imm, MO_TEQ, false); break; case R6_OPC_LLD: gen_ld(ctx, op1, rt, rs, imm); @@ -27737,7 +27691,7 @@ static void decode_opc_special3(CPUMIPSState *env, DisasContext *ctx) return; case OPC_SCE: check_cp0_enabled(ctx); - gen_st_cond(ctx, op1, rt, rs, imm); + gen_st_cond(ctx, rt, rs, imm, MO_TESL, true); return; case OPC_CACHEE: check_cp0_enabled(ctx); @@ -29359,8 +29313,8 @@ static void decode_opc(CPUMIPSState *env, DisasContext *ctx, bool *insn_need_pat if (ctx->insn_flags & INSN_R5900) { check_insn_opc_user_only(ctx, INSN_R5900); } - gen_st_cond(ctx, op, rt, rs, imm); - break; + gen_st_cond(ctx, rt, rs, imm, MO_TESL, false); + break; case OPC_CACHE: check_insn_opc_removed(ctx, ISA_MIPS32R6); check_cp0_enabled(ctx); @@ -29659,7 +29613,7 @@ static void decode_opc(CPUMIPSState *env, DisasContext *ctx, bool *insn_need_pat check_insn_opc_user_only(ctx, INSN_R5900); } check_mips_64(ctx); - gen_st_cond(ctx, op, rt, rs, imm); + gen_st_cond(ctx, rt, rs, imm, MO_TEQ, false); break; case OPC_BNVC: /* OPC_BNEZALC, OPC_BNEC, OPC_DADDI */ if (ctx->insn_flags & ISA_MIPS32R6) { @@ -30037,6 +29991,11 @@ void mips_tcg_init(struct uc_struct *uc) offsetof(CPUMIPSState, active_fpu.fcr31), "fcr31"); + tcg_ctx->cpu_lladdr = tcg_global_mem_new(tcg_ctx, tcg_ctx->cpu_env, offsetof(CPUMIPSState, lladdr), + "lladdr"); + tcg_ctx->cpu_llval = tcg_global_mem_new(tcg_ctx, tcg_ctx->cpu_env, offsetof(CPUMIPSState, llval), + "llval"); + #if defined(TARGET_MIPS64) tcg_ctx->cpu_mmr[0] = NULL; for (i = 1; i < 32; i++) { diff --git a/qemu/tcg/tcg.h b/qemu/tcg/tcg.h index bf4977cb..3976a78b 100644 --- a/qemu/tcg/tcg.h +++ b/qemu/tcg/tcg.h @@ -903,6 +903,7 @@ struct TCGContext { TCGv cpu_PC; TCGv cpu_HI[4], cpu_LO[4]; // MIPS_DSP_ACC = 4 in qemu/target-mips/cpu.h TCGv cpu_dspctrl; + TCGv cpu_lladdr, cpu_llval; TCGv btarget; TCGv bcond; TCGv_i32 hflags;