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 | 1826 | |
| 1827 | 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 | 1878 | void cpu_loop(CPUMIPSState *env) |
| 1830 | 1879 | { |
| 1831 | 1880 | target_siginfo_t info; |
| ... | ... | @@ -1833,7 +1882,9 @@ void cpu_loop(CPUMIPSState *env) |
| 1833 | 1882 | unsigned int syscall_num; |
| 1834 | 1883 | |
| 1835 | 1884 | for(;;) { |
| 1885 | + cpu_exec_start(env); | |
| 1836 | 1886 | trapnr = cpu_mips_exec(env); |
| 1887 | + cpu_exec_end(env); | |
| 1837 | 1888 | switch(trapnr) { |
| 1838 | 1889 | case EXCP_SYSCALL: |
| 1839 | 1890 | syscall_num = env->active_tc.gpr[2] - 4000; |
| ... | ... | @@ -1910,6 +1961,15 @@ void cpu_loop(CPUMIPSState *env) |
| 1910 | 1961 | } |
| 1911 | 1962 | } |
| 1912 | 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 | 1973 | default: |
| 1914 | 1974 | // error: |
| 1915 | 1975 | fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n", | ... | ... |
target-mips/cpu.h
| ... | ... | @@ -375,6 +375,9 @@ struct CPUMIPSState { |
| 375 | 375 | int32_t CP0_Config7; |
| 376 | 376 | /* XXX: Maybe make LLAddr per-TC? */ |
| 377 | 377 | target_ulong CP0_LLAddr; |
| 378 | + target_ulong llval; | |
| 379 | + target_ulong llnewval; | |
| 380 | + target_ulong llreg; | |
| 378 | 381 | target_ulong CP0_WatchLo[8]; |
| 379 | 382 | int32_t CP0_WatchHi[8]; |
| 380 | 383 | target_ulong CP0_XContext; |
| ... | ... | @@ -559,6 +562,8 @@ enum { |
| 559 | 562 | |
| 560 | 563 | EXCP_LAST = EXCP_CACHE, |
| 561 | 564 | }; |
| 565 | +/* Dummy exception for conditional stores. */ | |
| 566 | +#define EXCP_SC 0x100 | |
| 562 | 567 | |
| 563 | 568 | int cpu_mips_exec(CPUMIPSState *s); |
| 564 | 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 | 919 | tcg_gen_mov_tl(t0, arg1); \ |
| 920 | 920 | tcg_gen_qemu_##fname(ret, arg1, ctx->mem_idx); \ |
| 921 | 921 | tcg_gen_st_tl(t0, cpu_env, offsetof(CPUState, CP0_LLAddr)); \ |
| 922 | + tcg_gen_st_tl(ret, cpu_env, offsetof(CPUState, llval)); \ | |
| 922 | 923 | tcg_temp_free(t0); \ |
| 923 | 924 | } |
| 924 | 925 | OP_LD_ATOMIC(ll,ld32s); |
| ... | ... | @@ -927,32 +928,66 @@ OP_LD_ATOMIC(lld,ld64); |
| 927 | 928 | #endif |
| 928 | 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 | 989 | #if defined(TARGET_MIPS64) |
| 955 | -OP_ST_ATOMIC(scd,st64,0x7); | |
| 990 | +OP_ST_ATOMIC(scd,st64,ld64,0x7); | |
| 956 | 991 | #endif |
| 957 | 992 | #undef OP_ST_ATOMIC |
| 958 | 993 | ... | ... |