diff options
author | Aurelien Jarno <aurelien@aurel32.net> | 2009-11-30 15:39:54 +0100 |
---|---|---|
committer | Aurelien Jarno <aurelien@aurel32.net> | 2009-11-30 16:18:28 +0100 |
commit | e7139c440c489ed31bb81ccb5e456ae9d8fe1c1e (patch) | |
tree | cc8b275ae0455e4589fba5bb0a8d98b46eebe82c /target-mips/op_helper.c | |
parent | 25b91e32e0c93cb60cf9be43a52881de00c91be6 (diff) |
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>
Diffstat (limited to 'target-mips/op_helper.c')
-rw-r--r-- | target-mips/op_helper.c | 39 |
1 files changed, 39 insertions, 0 deletions
diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c index fe1c9160d5..be75af5e6e 100644 --- a/target-mips/op_helper.c +++ b/target-mips/op_helper.c @@ -275,6 +275,45 @@ void helper_dmultu (target_ulong arg1, target_ulong arg2) } #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)) |