target-mips: use physical address in lladdr

Currently the ll/sc instructions use the virtual address in both
user and system mode. Use the physical address insteead in system
mode.

Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c
index fe1c916..be75af5 100644
--- a/target-mips/op_helper.c
+++ b/target-mips/op_helper.c
@@ -275,6 +275,45 @@
 }
 #endif
 
+#ifndef CONFIG_USER_ONLY
+#define HELPER_LD_ATOMIC(name, insn)                                          \
+target_ulong helper_##name(target_ulong arg, int mem_idx)                     \
+{                                                                             \
+    env->lladdr = do_translate_address(env, arg, 0);                          \
+    env->llval = do_##insn(arg, mem_idx);                                     \
+    return env->llval;                                                        \
+}
+HELPER_LD_ATOMIC(ll, lw)
+#ifdef TARGET_MIPS64
+HELPER_LD_ATOMIC(lld, ld)
+#endif
+#undef HELPER_LD_ATOMIC
+
+#define HELPER_ST_ATOMIC(name, ld_insn, st_insn, almask)                      \
+target_ulong helper_##name(target_ulong arg1, target_ulong arg2, int mem_idx) \
+{                                                                             \
+    target_long tmp;                                                          \
+                                                                              \
+    if (arg2 & almask) {                                                      \
+        env->CP0_BadVAddr = arg2;                                             \
+        helper_raise_exception(EXCP_AdES);                                    \
+    }                                                                         \
+    if (do_translate_address(env, arg2, 1) == env->lladdr) {                  \
+        tmp = do_##ld_insn(arg2, mem_idx);                                    \
+        if (tmp == env->llval) {                                              \
+            do_##st_insn(arg2, arg1, mem_idx);                                \
+            return 1;                                                         \
+        }                                                                     \
+    }                                                                         \
+    return 0;                                                                 \
+}
+HELPER_ST_ATOMIC(sc, lw, sw, 0x3)
+#ifdef TARGET_MIPS64
+HELPER_ST_ATOMIC(scd, ld, sd, 0x7)
+#endif
+#undef HELPER_ST_ATOMIC
+#endif
+
 #ifdef TARGET_WORDS_BIGENDIAN
 #define GET_LMASK(v) ((v) & 3)
 #define GET_OFFSET(addr, offset) (addr + (offset))