[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [Qemu-commits] [COMMIT 590bc60] MIPS atomic instructions
From: |
Aurelien Jarno |
Subject: |
Re: [Qemu-commits] [COMMIT 590bc60] MIPS atomic instructions |
Date: |
Sun, 12 Jul 2009 02:44:23 +0200 |
User-agent: |
Mutt/1.5.18 (2008-05-17) |
On Sat, Jul 11, 2009 at 03:26:51PM +0200, Stefan Weil wrote:
> Anthony Liguori schrieb:
> > From: Paul Brook <address@hidden>
> >
> > Implement MIPS ll/sc instructions using atomic compare+exchange.
> >
> > Signed-off-by: Paul Brook <address@hidden>
> >
> > diff --git a/linux-user/main.c b/linux-user/main.c
> > index 7348447..30290a5 100644
> > --- a/linux-user/main.c
> > +++ b/linux-user/main.c
> > @@ -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",
> > diff --git a/target-mips/cpu.h b/target-mips/cpu.h
> > index 6ebb82b..bb9a49b 100644
> > --- a/target-mips/cpu.h
> > +++ b/target-mips/cpu.h
> > @@ -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);
> > diff --git a/target-mips/translate.c b/target-mips/translate.c
> > index d316b9d..cf467f8 100644
> > --- a/target-mips/translate.c
> > +++ b/target-mips/translate.c
> > @@ -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
> >
>
> After this patch, MIPS malta fails to boot linux.
> Other MIPS emulations even crash QEMU.
>
The macro has been modified to take different arguments, but the main
code hasn't been changed. As a result it does not even compile with
--enable-debug-tcg.
--
Aurelien Jarno GPG: 1024D/F1BCDB73
address@hidden http://www.aurel32.net