mirror of https://gitee.com/openkylin/qemu.git
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:
parent
ff867ddcbd
commit
590bc601d8
|
@ -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",
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
Loading…
Reference in New Issue