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 |