MIPS atomic instructions

Implement MIPS ll/sc instructions using atomic compare+exchange.

Signed-off-by: Paul Brook <paul@codesourcery.com>
This commit is contained in:
Paul Brook 2009-07-09 17:45:17 +01:00
parent ff867ddcbd
commit 590bc601d8
3 changed files with 124 additions and 24 deletions

View File

@ -1826,6 +1826,55 @@ static const uint8_t mips_syscall_args[] = {
#undef MIPS_SYS
static int do_store_exclusive(CPUMIPSState *env)
{
target_ulong addr;
target_ulong page_addr;
target_ulong val;
int flags;
int segv = 0;
int reg;
int d;
addr = env->CP0_LLAddr;
page_addr = addr & TARGET_PAGE_MASK;
start_exclusive();
mmap_lock();
flags = page_get_flags(page_addr);
if ((flags & PAGE_READ) == 0) {
segv = 1;
} else {
reg = env->llreg & 0x1f;
d = (env->llreg & 0x20) != 0;
if (d) {
segv = get_user_s64(val, addr);
} else {
segv = get_user_s32(val, addr);
}
if (!segv) {
if (val != env->llval) {
env->active_tc.gpr[reg] = 0;
} else {
if (d) {
segv = put_user_u64(env->llnewval, addr);
} else {
segv = put_user_u32(env->llnewval, addr);
}
if (!segv) {
env->active_tc.gpr[reg] = 1;
}
}
}
}
env->CP0_LLAddr = -1;
if (!segv) {
env->active_tc.PC += 4;
}
mmap_unlock();
end_exclusive();
return segv;
}
void cpu_loop(CPUMIPSState *env)
{
target_siginfo_t info;
@ -1833,7 +1882,9 @@ void cpu_loop(CPUMIPSState *env)
unsigned int syscall_num;
for(;;) {
cpu_exec_start(env);
trapnr = cpu_mips_exec(env);
cpu_exec_end(env);
switch(trapnr) {
case EXCP_SYSCALL:
syscall_num = env->active_tc.gpr[2] - 4000;
@ -1910,6 +1961,15 @@ void cpu_loop(CPUMIPSState *env)
}
}
break;
case EXCP_SC:
if (do_store_exclusive(env)) {
info.si_signo = TARGET_SIGSEGV;
info.si_errno = 0;
info.si_code = TARGET_SEGV_MAPERR;
info._sifields._sigfault._addr = env->active_tc.PC;
queue_signal(env, info.si_signo, &info);
}
break;
default:
// error:
fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n",

View File

@ -375,6 +375,9 @@ struct CPUMIPSState {
int32_t CP0_Config7;
/* XXX: Maybe make LLAddr per-TC? */
target_ulong CP0_LLAddr;
target_ulong llval;
target_ulong llnewval;
target_ulong llreg;
target_ulong CP0_WatchLo[8];
int32_t CP0_WatchHi[8];
target_ulong CP0_XContext;
@ -559,6 +562,8 @@ enum {
EXCP_LAST = EXCP_CACHE,
};
/* Dummy exception for conditional stores. */
#define EXCP_SC 0x100
int cpu_mips_exec(CPUMIPSState *s);
CPUMIPSState *cpu_mips_init(const char *cpu_model);

View File

@ -919,6 +919,7 @@ static inline void op_ldst_##insn(TCGv ret, TCGv arg1, DisasContext *ctx) \
tcg_gen_mov_tl(t0, arg1); \
tcg_gen_qemu_##fname(ret, arg1, ctx->mem_idx); \
tcg_gen_st_tl(t0, cpu_env, offsetof(CPUState, CP0_LLAddr)); \
tcg_gen_st_tl(ret, cpu_env, offsetof(CPUState, llval)); \
tcg_temp_free(t0); \
}
OP_LD_ATOMIC(ll,ld32s);
@ -927,32 +928,66 @@ OP_LD_ATOMIC(lld,ld64);
#endif
#undef OP_LD_ATOMIC
#define OP_ST_ATOMIC(insn,fname,almask) \
static inline void op_ldst_##insn(TCGv ret, TCGv arg1, TCGv arg2, DisasContext *ctx) \
{ \
TCGv t0 = tcg_temp_new(); \
int l1 = gen_new_label(); \
int l2 = gen_new_label(); \
int l3 = gen_new_label(); \
\
tcg_gen_andi_tl(t0, arg2, almask); \
tcg_gen_brcondi_tl(TCG_COND_EQ, t0, 0, l1); \
tcg_gen_st_tl(arg2, cpu_env, offsetof(CPUState, CP0_BadVAddr)); \
generate_exception(ctx, EXCP_AdES); \
gen_set_label(l1); \
tcg_gen_ld_tl(t0, cpu_env, offsetof(CPUState, CP0_LLAddr)); \
tcg_gen_brcond_tl(TCG_COND_NE, arg2, t0, l2); \
tcg_temp_free(t0); \
tcg_gen_qemu_##fname(arg1, arg2, ctx->mem_idx); \
tcg_gen_movi_tl(ret, 1); \
tcg_gen_br(l3); \
gen_set_label(l2); \
tcg_gen_movi_tl(ret, 0); \
gen_set_label(l3); \
#ifdef CONFIG_USER_ONLY
#define OP_ST_ATOMIC(insn,fname,ldname,almask) \
static inline void op_ldst_##insn(TCGv arg1, TCGv arg2, int rt, DisasContext *ctx) \
{ \
TCGv t0 = tcg_temp_new(); \
int l1 = gen_new_label(); \
int l2 = gen_new_label(); \
\
tcg_gen_andi_tl(t0, arg2, almask); \
tcg_gen_brcondi_tl(TCG_COND_EQ, t0, 0, l1); \
tcg_gen_st_tl(arg2, cpu_env, offsetof(CPUState, CP0_BadVAddr)); \
generate_exception(ctx, EXCP_AdES); \
gen_set_label(l1); \
tcg_gen_ld_tl(t0, cpu_env, offsetof(CPUState, CP0_LLAddr)); \
tcg_gen_brcond_tl(TCG_COND_NE, arg2, t0, l2); \
tcg_gen_movi_tl(t0, rt | ((almask << 3) & 0x20)); \
tcg_gen_st_tl(t0, cpu_env, offsetof(CPUState, llreg)); \
tcg_gen_st_tl(arg1, cpu_env, offsetof(CPUState, llnewval)); \
gen_helper_0i(raise_exception, EXCP_SC); \
gen_set_label(l2); \
tcg_gen_movi_tl(t0, 0); \
gen_store_gpr(t0, rt); \
tcg_temp_free(t0); \
}
OP_ST_ATOMIC(sc,st32,0x3);
#else
#define OP_ST_ATOMIC(insn,fname,ldname,almask) \
static inline void op_ldst_##insn(TCGv arg1, TCGv arg2, int rt, DisasContext *ctx) \
{ \
TCGv t0 = tcg_temp_new(); \
TCGv t1 = tcg_temp_new(); \
int l1 = gen_new_label(); \
int l2 = gen_new_label(); \
int l3 = gen_new_label(); \
\
tcg_gen_andi_tl(t0, arg2, almask); \
tcg_gen_brcondi_tl(TCG_COND_EQ, t0, 0, l1); \
tcg_gen_st_tl(arg2, cpu_env, offsetof(CPUState, CP0_BadVAddr)); \
generate_exception(ctx, EXCP_AdES); \
gen_set_label(l1); \
tcg_gen_ld_tl(t0, cpu_env, offsetof(CPUState, CP0_LLAddr)); \
tcg_gen_brcond_tl(TCG_COND_NE, arg2, t0, l2); \
tcg_gen_ld_tl(t0, cpu_env, offsetof(CPUState, llval)); \
tcg_gen_qemu_##ldname(t1, arg2, ctx->mem_idx); \
tcg_gen_brcond_tl(TCG_COND_NE, t0, t1, l2); \
tcg_temp_free(t1); \
tcg_gen_qemu_##fname(arg1, arg2, ctx->mem_idx); \
tcg_gen_movi_tl(t0, 1); \
gen_store_gpr(t0, rt); \
tcg_gen_br(l3); \
gen_set_label(l2); \
tcg_gen_movi_tl(t0, 0); \
gen_store_gpr(t0, rt); \
gen_set_label(l3); \
tcg_temp_free(t0); \
}
#endif
OP_ST_ATOMIC(sc,st32,ld32s,0x3);
#if defined(TARGET_MIPS64)
OP_ST_ATOMIC(scd,st64,0x7);
OP_ST_ATOMIC(scd,st64,ld64,0x7);
#endif
#undef OP_ST_ATOMIC