[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [Qemu-commits] [COMMIT 590bc60] MIPS atomic instructions
From: |
Stefan Weil |
Subject: |
Re: [Qemu-commits] [COMMIT 590bc60] MIPS atomic instructions |
Date: |
Sat, 11 Jul 2009 15:26:51 +0200 |
User-agent: |
Mozilla-Thunderbird 2.0.0.19 (X11/20090103) |
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.
Regards,
Stefan
tail /tmp/qemu.log
cpu_mips_handle_mmu_fault pc 803be010 ad 80440000 rw 0 mmu_idx 0 smmu 1
cpu_mips_handle_mmu_fault address=80440000 ret 0 physical 00440000 prot 3
cpu_mips_handle_mmu_fault pc 803be010 ad 8044218c rw 0 mmu_idx 0 smmu 1
cpu_mips_handle_mmu_fault address=8044218c ret 0 physical 0044218c prot 3
IN: lock_kernel
0x803be024: ll v1,-1952(v0)
0x803be028: bnez v1,0x803be084
0x803be02c: li v1,1
cpu_mips_handle_mmu_fault pc 803be024 ad 8045f860 rw 0 mmu_idx 0 smmu 1
cpu_mips_handle_mmu_fault address=8045f860 ret 0 physical 0045f860 prot 3
IN: lock_kernel
0x803be030: sc v1,-1952(v0)
0x803be034: beqz v1,0x803be084
0x803be038: nop
helper_raise_exception_err: 13 0
do_interrupt enter: PC 803be030 EPC 00000000 address error store exception
do_interrupt: PC 80000180 EPC 803be030 cause 5
S 10000002 C 00000414 A 00000001 D 00000000
cpu_mips_handle_mmu_fault pc 80000180 ad 80000180 rw 2 mmu_idx 0 smmu 1
cpu_mips_handle_mmu_fault address=80000180 ret 0 physical 00000180 prot 3
IN:
0x80000180: nop
0x80000184: nop
0x80000188: nop
0x8000018c: nop
0x80000190: nop
0x80000194: nop
0x80000198: nop
0x8000019c: nop
git bisect:
590bc601d800d16a77676926898019f7285bd615 is first bad commit
commit 590bc601d800d16a77676926898019f7285bd615
Author: Paul Brook <address@hidden>
Date: Thu Jul 9 17:45:17 2009 +0100
MIPS atomic instructions
Implement MIPS ll/sc instructions using atomic compare+exchange.
Signed-off-by: Paul Brook <address@hidden>
:040000 040000 6a2612835514be1613a4442a2d2049f4e86b6c1c
99d5856ab75ce7c78476dcea1944664b96f7b893 M linux-user
:040000 040000 1f589f37740184bd10cc93a59b4f936bb20766c6
de548a4e6629b53204045f58c5285aff5a8ea4e4 M target-mips