qemu-commits
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-commits] [COMMIT 590bc60] MIPS atomic instructions


From: Anthony Liguori
Subject: [Qemu-commits] [COMMIT 590bc60] MIPS atomic instructions
Date: Fri, 10 Jul 2009 19:16:37 -0000

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
 




reply via email to

[Prev in Thread] Current Thread [Next in Thread]