Commit 590bc601d800d16a77676926898019f7285bd615

Authored by Paul Brook
1 parent ff867ddc

MIPS atomic instructions

Implement MIPS ll/sc instructions using atomic compare+exchange.

Signed-off-by: Paul Brook <paul@codesourcery.com>
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