Commit 590bc601d800d16a77676926898019f7285bd615
1 parent
ff867ddc
MIPS atomic instructions
Implement MIPS ll/sc instructions using atomic compare+exchange. Signed-off-by: Paul Brook <paul@codesourcery.com>
Showing
3 changed files
with
124 additions
and
24 deletions
linux-user/main.c
| @@ -1826,6 +1826,55 @@ static const uint8_t mips_syscall_args[] = { | @@ -1826,6 +1826,55 @@ static const uint8_t mips_syscall_args[] = { | ||
| 1826 | 1826 | ||
| 1827 | #undef MIPS_SYS | 1827 | #undef MIPS_SYS |
| 1828 | 1828 | ||
| 1829 | +static int do_store_exclusive(CPUMIPSState *env) | ||
| 1830 | +{ | ||
| 1831 | + target_ulong addr; | ||
| 1832 | + target_ulong page_addr; | ||
| 1833 | + target_ulong val; | ||
| 1834 | + int flags; | ||
| 1835 | + int segv = 0; | ||
| 1836 | + int reg; | ||
| 1837 | + int d; | ||
| 1838 | + | ||
| 1839 | + addr = env->CP0_LLAddr; | ||
| 1840 | + page_addr = addr & TARGET_PAGE_MASK; | ||
| 1841 | + start_exclusive(); | ||
| 1842 | + mmap_lock(); | ||
| 1843 | + flags = page_get_flags(page_addr); | ||
| 1844 | + if ((flags & PAGE_READ) == 0) { | ||
| 1845 | + segv = 1; | ||
| 1846 | + } else { | ||
| 1847 | + reg = env->llreg & 0x1f; | ||
| 1848 | + d = (env->llreg & 0x20) != 0; | ||
| 1849 | + if (d) { | ||
| 1850 | + segv = get_user_s64(val, addr); | ||
| 1851 | + } else { | ||
| 1852 | + segv = get_user_s32(val, addr); | ||
| 1853 | + } | ||
| 1854 | + if (!segv) { | ||
| 1855 | + if (val != env->llval) { | ||
| 1856 | + env->active_tc.gpr[reg] = 0; | ||
| 1857 | + } else { | ||
| 1858 | + if (d) { | ||
| 1859 | + segv = put_user_u64(env->llnewval, addr); | ||
| 1860 | + } else { | ||
| 1861 | + segv = put_user_u32(env->llnewval, addr); | ||
| 1862 | + } | ||
| 1863 | + if (!segv) { | ||
| 1864 | + env->active_tc.gpr[reg] = 1; | ||
| 1865 | + } | ||
| 1866 | + } | ||
| 1867 | + } | ||
| 1868 | + } | ||
| 1869 | + env->CP0_LLAddr = -1; | ||
| 1870 | + if (!segv) { | ||
| 1871 | + env->active_tc.PC += 4; | ||
| 1872 | + } | ||
| 1873 | + mmap_unlock(); | ||
| 1874 | + end_exclusive(); | ||
| 1875 | + return segv; | ||
| 1876 | +} | ||
| 1877 | + | ||
| 1829 | void cpu_loop(CPUMIPSState *env) | 1878 | void cpu_loop(CPUMIPSState *env) |
| 1830 | { | 1879 | { |
| 1831 | target_siginfo_t info; | 1880 | target_siginfo_t info; |
| @@ -1833,7 +1882,9 @@ void cpu_loop(CPUMIPSState *env) | @@ -1833,7 +1882,9 @@ void cpu_loop(CPUMIPSState *env) | ||
| 1833 | unsigned int syscall_num; | 1882 | unsigned int syscall_num; |
| 1834 | 1883 | ||
| 1835 | for(;;) { | 1884 | for(;;) { |
| 1885 | + cpu_exec_start(env); | ||
| 1836 | trapnr = cpu_mips_exec(env); | 1886 | trapnr = cpu_mips_exec(env); |
| 1887 | + cpu_exec_end(env); | ||
| 1837 | switch(trapnr) { | 1888 | switch(trapnr) { |
| 1838 | case EXCP_SYSCALL: | 1889 | case EXCP_SYSCALL: |
| 1839 | syscall_num = env->active_tc.gpr[2] - 4000; | 1890 | syscall_num = env->active_tc.gpr[2] - 4000; |
| @@ -1910,6 +1961,15 @@ void cpu_loop(CPUMIPSState *env) | @@ -1910,6 +1961,15 @@ void cpu_loop(CPUMIPSState *env) | ||
| 1910 | } | 1961 | } |
| 1911 | } | 1962 | } |
| 1912 | break; | 1963 | break; |
| 1964 | + case EXCP_SC: | ||
| 1965 | + if (do_store_exclusive(env)) { | ||
| 1966 | + info.si_signo = TARGET_SIGSEGV; | ||
| 1967 | + info.si_errno = 0; | ||
| 1968 | + info.si_code = TARGET_SEGV_MAPERR; | ||
| 1969 | + info._sifields._sigfault._addr = env->active_tc.PC; | ||
| 1970 | + queue_signal(env, info.si_signo, &info); | ||
| 1971 | + } | ||
| 1972 | + break; | ||
| 1913 | default: | 1973 | default: |
| 1914 | // error: | 1974 | // error: |
| 1915 | fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n", | 1975 | fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n", |
target-mips/cpu.h
| @@ -375,6 +375,9 @@ struct CPUMIPSState { | @@ -375,6 +375,9 @@ struct CPUMIPSState { | ||
| 375 | int32_t CP0_Config7; | 375 | int32_t CP0_Config7; |
| 376 | /* XXX: Maybe make LLAddr per-TC? */ | 376 | /* XXX: Maybe make LLAddr per-TC? */ |
| 377 | target_ulong CP0_LLAddr; | 377 | target_ulong CP0_LLAddr; |
| 378 | + target_ulong llval; | ||
| 379 | + target_ulong llnewval; | ||
| 380 | + target_ulong llreg; | ||
| 378 | target_ulong CP0_WatchLo[8]; | 381 | target_ulong CP0_WatchLo[8]; |
| 379 | int32_t CP0_WatchHi[8]; | 382 | int32_t CP0_WatchHi[8]; |
| 380 | target_ulong CP0_XContext; | 383 | target_ulong CP0_XContext; |
| @@ -559,6 +562,8 @@ enum { | @@ -559,6 +562,8 @@ enum { | ||
| 559 | 562 | ||
| 560 | EXCP_LAST = EXCP_CACHE, | 563 | EXCP_LAST = EXCP_CACHE, |
| 561 | }; | 564 | }; |
| 565 | +/* Dummy exception for conditional stores. */ | ||
| 566 | +#define EXCP_SC 0x100 | ||
| 562 | 567 | ||
| 563 | int cpu_mips_exec(CPUMIPSState *s); | 568 | int cpu_mips_exec(CPUMIPSState *s); |
| 564 | CPUMIPSState *cpu_mips_init(const char *cpu_model); | 569 | CPUMIPSState *cpu_mips_init(const char *cpu_model); |
target-mips/translate.c
| @@ -919,6 +919,7 @@ static inline void op_ldst_##insn(TCGv ret, TCGv arg1, DisasContext *ctx) \ | @@ -919,6 +919,7 @@ static inline void op_ldst_##insn(TCGv ret, TCGv arg1, DisasContext *ctx) \ | ||
| 919 | tcg_gen_mov_tl(t0, arg1); \ | 919 | tcg_gen_mov_tl(t0, arg1); \ |
| 920 | tcg_gen_qemu_##fname(ret, arg1, ctx->mem_idx); \ | 920 | tcg_gen_qemu_##fname(ret, arg1, ctx->mem_idx); \ |
| 921 | tcg_gen_st_tl(t0, cpu_env, offsetof(CPUState, CP0_LLAddr)); \ | 921 | tcg_gen_st_tl(t0, cpu_env, offsetof(CPUState, CP0_LLAddr)); \ |
| 922 | + tcg_gen_st_tl(ret, cpu_env, offsetof(CPUState, llval)); \ | ||
| 922 | tcg_temp_free(t0); \ | 923 | tcg_temp_free(t0); \ |
| 923 | } | 924 | } |
| 924 | OP_LD_ATOMIC(ll,ld32s); | 925 | OP_LD_ATOMIC(ll,ld32s); |
| @@ -927,32 +928,66 @@ OP_LD_ATOMIC(lld,ld64); | @@ -927,32 +928,66 @@ OP_LD_ATOMIC(lld,ld64); | ||
| 927 | #endif | 928 | #endif |
| 928 | #undef OP_LD_ATOMIC | 929 | #undef OP_LD_ATOMIC |
| 929 | 930 | ||
| 930 | -#define OP_ST_ATOMIC(insn,fname,almask) \ | ||
| 931 | -static inline void op_ldst_##insn(TCGv ret, TCGv arg1, TCGv arg2, DisasContext *ctx) \ | ||
| 932 | -{ \ | ||
| 933 | - TCGv t0 = tcg_temp_new(); \ | ||
| 934 | - int l1 = gen_new_label(); \ | ||
| 935 | - int l2 = gen_new_label(); \ | ||
| 936 | - int l3 = gen_new_label(); \ | ||
| 937 | - \ | ||
| 938 | - tcg_gen_andi_tl(t0, arg2, almask); \ | ||
| 939 | - tcg_gen_brcondi_tl(TCG_COND_EQ, t0, 0, l1); \ | ||
| 940 | - tcg_gen_st_tl(arg2, cpu_env, offsetof(CPUState, CP0_BadVAddr)); \ | ||
| 941 | - generate_exception(ctx, EXCP_AdES); \ | ||
| 942 | - gen_set_label(l1); \ | ||
| 943 | - tcg_gen_ld_tl(t0, cpu_env, offsetof(CPUState, CP0_LLAddr)); \ | ||
| 944 | - tcg_gen_brcond_tl(TCG_COND_NE, arg2, t0, l2); \ | ||
| 945 | - tcg_temp_free(t0); \ | ||
| 946 | - tcg_gen_qemu_##fname(arg1, arg2, ctx->mem_idx); \ | ||
| 947 | - tcg_gen_movi_tl(ret, 1); \ | ||
| 948 | - tcg_gen_br(l3); \ | ||
| 949 | - gen_set_label(l2); \ | ||
| 950 | - tcg_gen_movi_tl(ret, 0); \ | ||
| 951 | - gen_set_label(l3); \ | 931 | +#ifdef CONFIG_USER_ONLY |
| 932 | +#define OP_ST_ATOMIC(insn,fname,ldname,almask) \ | ||
| 933 | +static inline void op_ldst_##insn(TCGv arg1, TCGv arg2, int rt, DisasContext *ctx) \ | ||
| 934 | +{ \ | ||
| 935 | + TCGv t0 = tcg_temp_new(); \ | ||
| 936 | + int l1 = gen_new_label(); \ | ||
| 937 | + int l2 = gen_new_label(); \ | ||
| 938 | + \ | ||
| 939 | + tcg_gen_andi_tl(t0, arg2, almask); \ | ||
| 940 | + tcg_gen_brcondi_tl(TCG_COND_EQ, t0, 0, l1); \ | ||
| 941 | + tcg_gen_st_tl(arg2, cpu_env, offsetof(CPUState, CP0_BadVAddr)); \ | ||
| 942 | + generate_exception(ctx, EXCP_AdES); \ | ||
| 943 | + gen_set_label(l1); \ | ||
| 944 | + tcg_gen_ld_tl(t0, cpu_env, offsetof(CPUState, CP0_LLAddr)); \ | ||
| 945 | + tcg_gen_brcond_tl(TCG_COND_NE, arg2, t0, l2); \ | ||
| 946 | + tcg_gen_movi_tl(t0, rt | ((almask << 3) & 0x20)); \ | ||
| 947 | + tcg_gen_st_tl(t0, cpu_env, offsetof(CPUState, llreg)); \ | ||
| 948 | + tcg_gen_st_tl(arg1, cpu_env, offsetof(CPUState, llnewval)); \ | ||
| 949 | + gen_helper_0i(raise_exception, EXCP_SC); \ | ||
| 950 | + gen_set_label(l2); \ | ||
| 951 | + tcg_gen_movi_tl(t0, 0); \ | ||
| 952 | + gen_store_gpr(t0, rt); \ | ||
| 953 | + tcg_temp_free(t0); \ | ||
| 952 | } | 954 | } |
| 953 | -OP_ST_ATOMIC(sc,st32,0x3); | 955 | +#else |
| 956 | +#define OP_ST_ATOMIC(insn,fname,ldname,almask) \ | ||
| 957 | +static inline void op_ldst_##insn(TCGv arg1, TCGv arg2, int rt, DisasContext *ctx) \ | ||
| 958 | +{ \ | ||
| 959 | + TCGv t0 = tcg_temp_new(); \ | ||
| 960 | + TCGv t1 = tcg_temp_new(); \ | ||
| 961 | + int l1 = gen_new_label(); \ | ||
| 962 | + int l2 = gen_new_label(); \ | ||
| 963 | + int l3 = gen_new_label(); \ | ||
| 964 | + \ | ||
| 965 | + tcg_gen_andi_tl(t0, arg2, almask); \ | ||
| 966 | + tcg_gen_brcondi_tl(TCG_COND_EQ, t0, 0, l1); \ | ||
| 967 | + tcg_gen_st_tl(arg2, cpu_env, offsetof(CPUState, CP0_BadVAddr)); \ | ||
| 968 | + generate_exception(ctx, EXCP_AdES); \ | ||
| 969 | + gen_set_label(l1); \ | ||
| 970 | + tcg_gen_ld_tl(t0, cpu_env, offsetof(CPUState, CP0_LLAddr)); \ | ||
| 971 | + tcg_gen_brcond_tl(TCG_COND_NE, arg2, t0, l2); \ | ||
| 972 | + tcg_gen_ld_tl(t0, cpu_env, offsetof(CPUState, llval)); \ | ||
| 973 | + tcg_gen_qemu_##ldname(t1, arg2, ctx->mem_idx); \ | ||
| 974 | + tcg_gen_brcond_tl(TCG_COND_NE, t0, t1, l2); \ | ||
| 975 | + tcg_temp_free(t1); \ | ||
| 976 | + tcg_gen_qemu_##fname(arg1, arg2, ctx->mem_idx); \ | ||
| 977 | + tcg_gen_movi_tl(t0, 1); \ | ||
| 978 | + gen_store_gpr(t0, rt); \ | ||
| 979 | + tcg_gen_br(l3); \ | ||
| 980 | + gen_set_label(l2); \ | ||
| 981 | + tcg_gen_movi_tl(t0, 0); \ | ||
| 982 | + gen_store_gpr(t0, rt); \ | ||
| 983 | + gen_set_label(l3); \ | ||
| 984 | + tcg_temp_free(t0); \ | ||
| 985 | +} | ||
| 986 | +#endif | ||
| 987 | + | ||
| 988 | +OP_ST_ATOMIC(sc,st32,ld32s,0x3); | ||
| 954 | #if defined(TARGET_MIPS64) | 989 | #if defined(TARGET_MIPS64) |
| 955 | -OP_ST_ATOMIC(scd,st64,0x7); | 990 | +OP_ST_ATOMIC(scd,st64,ld64,0x7); |
| 956 | #endif | 991 | #endif |
| 957 | #undef OP_ST_ATOMIC | 992 | #undef OP_ST_ATOMIC |
| 958 | 993 |