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 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  
... ...