110f7d4d5SPhilippe Mathieu-Daudé /* 210f7d4d5SPhilippe Mathieu-Daudé * Atomic helper templates 310f7d4d5SPhilippe Mathieu-Daudé * Included from tcg-runtime.c and cputlb.c. 410f7d4d5SPhilippe Mathieu-Daudé * 510f7d4d5SPhilippe Mathieu-Daudé * Copyright (c) 2016 Red Hat, Inc 610f7d4d5SPhilippe Mathieu-Daudé * 710f7d4d5SPhilippe Mathieu-Daudé * This library is free software; you can redistribute it and/or 810f7d4d5SPhilippe Mathieu-Daudé * modify it under the terms of the GNU Lesser General Public 910f7d4d5SPhilippe Mathieu-Daudé * License as published by the Free Software Foundation; either 10fb0343d5SThomas Huth * version 2.1 of the License, or (at your option) any later version. 1110f7d4d5SPhilippe Mathieu-Daudé * 1210f7d4d5SPhilippe Mathieu-Daudé * This library is distributed in the hope that it will be useful, 1310f7d4d5SPhilippe Mathieu-Daudé * but WITHOUT ANY WARRANTY; without even the implied warranty of 1410f7d4d5SPhilippe Mathieu-Daudé * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 1510f7d4d5SPhilippe Mathieu-Daudé * Lesser General Public License for more details. 1610f7d4d5SPhilippe Mathieu-Daudé * 1710f7d4d5SPhilippe Mathieu-Daudé * You should have received a copy of the GNU Lesser General Public 1810f7d4d5SPhilippe Mathieu-Daudé * License along with this library; if not, see <http://www.gnu.org/licenses/>. 1910f7d4d5SPhilippe Mathieu-Daudé */ 2010f7d4d5SPhilippe Mathieu-Daudé 21*e6d86bedSEmilio G. Cota #include "qemu/plugin.h" 22d071f4cdSEmilio G. Cota #include "trace/mem.h" 23d071f4cdSEmilio G. Cota 2410f7d4d5SPhilippe Mathieu-Daudé #if DATA_SIZE == 16 2510f7d4d5SPhilippe Mathieu-Daudé # define SUFFIX o 2610f7d4d5SPhilippe Mathieu-Daudé # define DATA_TYPE Int128 2710f7d4d5SPhilippe Mathieu-Daudé # define BSWAP bswap128 28d071f4cdSEmilio G. Cota # define SHIFT 4 2910f7d4d5SPhilippe Mathieu-Daudé #elif DATA_SIZE == 8 3010f7d4d5SPhilippe Mathieu-Daudé # define SUFFIX q 3110f7d4d5SPhilippe Mathieu-Daudé # define DATA_TYPE uint64_t 325507c2bfSRichard Henderson # define SDATA_TYPE int64_t 3310f7d4d5SPhilippe Mathieu-Daudé # define BSWAP bswap64 34d071f4cdSEmilio G. Cota # define SHIFT 3 3510f7d4d5SPhilippe Mathieu-Daudé #elif DATA_SIZE == 4 3610f7d4d5SPhilippe Mathieu-Daudé # define SUFFIX l 3710f7d4d5SPhilippe Mathieu-Daudé # define DATA_TYPE uint32_t 385507c2bfSRichard Henderson # define SDATA_TYPE int32_t 3910f7d4d5SPhilippe Mathieu-Daudé # define BSWAP bswap32 40d071f4cdSEmilio G. Cota # define SHIFT 2 4110f7d4d5SPhilippe Mathieu-Daudé #elif DATA_SIZE == 2 4210f7d4d5SPhilippe Mathieu-Daudé # define SUFFIX w 4310f7d4d5SPhilippe Mathieu-Daudé # define DATA_TYPE uint16_t 445507c2bfSRichard Henderson # define SDATA_TYPE int16_t 4510f7d4d5SPhilippe Mathieu-Daudé # define BSWAP bswap16 46d071f4cdSEmilio G. Cota # define SHIFT 1 4710f7d4d5SPhilippe Mathieu-Daudé #elif DATA_SIZE == 1 4810f7d4d5SPhilippe Mathieu-Daudé # define SUFFIX b 4910f7d4d5SPhilippe Mathieu-Daudé # define DATA_TYPE uint8_t 505507c2bfSRichard Henderson # define SDATA_TYPE int8_t 5110f7d4d5SPhilippe Mathieu-Daudé # define BSWAP 52d071f4cdSEmilio G. Cota # define SHIFT 0 5310f7d4d5SPhilippe Mathieu-Daudé #else 5410f7d4d5SPhilippe Mathieu-Daudé # error unsupported data size 5510f7d4d5SPhilippe Mathieu-Daudé #endif 5610f7d4d5SPhilippe Mathieu-Daudé 5710f7d4d5SPhilippe Mathieu-Daudé #if DATA_SIZE >= 4 5810f7d4d5SPhilippe Mathieu-Daudé # define ABI_TYPE DATA_TYPE 5910f7d4d5SPhilippe Mathieu-Daudé #else 6010f7d4d5SPhilippe Mathieu-Daudé # define ABI_TYPE uint32_t 6110f7d4d5SPhilippe Mathieu-Daudé #endif 6210f7d4d5SPhilippe Mathieu-Daudé 6310f7d4d5SPhilippe Mathieu-Daudé /* Define host-endian atomic operations. Note that END is used within 6410f7d4d5SPhilippe Mathieu-Daudé the ATOMIC_NAME macro, and redefined below. */ 6510f7d4d5SPhilippe Mathieu-Daudé #if DATA_SIZE == 1 6610f7d4d5SPhilippe Mathieu-Daudé # define END 67d071f4cdSEmilio G. Cota # define MEND _be /* either le or be would be fine */ 6810f7d4d5SPhilippe Mathieu-Daudé #elif defined(HOST_WORDS_BIGENDIAN) 6910f7d4d5SPhilippe Mathieu-Daudé # define END _be 70d071f4cdSEmilio G. Cota # define MEND _be 7110f7d4d5SPhilippe Mathieu-Daudé #else 7210f7d4d5SPhilippe Mathieu-Daudé # define END _le 73d071f4cdSEmilio G. Cota # define MEND _le 7410f7d4d5SPhilippe Mathieu-Daudé #endif 7510f7d4d5SPhilippe Mathieu-Daudé 7610f7d4d5SPhilippe Mathieu-Daudé ABI_TYPE ATOMIC_NAME(cmpxchg)(CPUArchState *env, target_ulong addr, 7710f7d4d5SPhilippe Mathieu-Daudé ABI_TYPE cmpv, ABI_TYPE newv EXTRA_ARGS) 7810f7d4d5SPhilippe Mathieu-Daudé { 7934d49937SPeter Maydell ATOMIC_MMU_DECLS; 8010f7d4d5SPhilippe Mathieu-Daudé DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP; 81d071f4cdSEmilio G. Cota DATA_TYPE ret; 82cfec3885SEmilio G. Cota uint16_t info = glue(trace_mem_build_info_no_se, MEND)(SHIFT, false, 83cfec3885SEmilio G. Cota ATOMIC_MMU_IDX); 84d071f4cdSEmilio G. Cota 85cfec3885SEmilio G. Cota atomic_trace_rmw_pre(env, addr, info); 86e6cd4bb5SRichard Henderson #if DATA_SIZE == 16 87e6cd4bb5SRichard Henderson ret = atomic16_cmpxchg(haddr, cmpv, newv); 88e6cd4bb5SRichard Henderson #else 89d071f4cdSEmilio G. Cota ret = atomic_cmpxchg__nocheck(haddr, cmpv, newv); 90e6cd4bb5SRichard Henderson #endif 91ec603b55SRichard Henderson ATOMIC_MMU_CLEANUP; 92cfec3885SEmilio G. Cota atomic_trace_rmw_post(env, addr, info); 93ec603b55SRichard Henderson return ret; 9410f7d4d5SPhilippe Mathieu-Daudé } 9510f7d4d5SPhilippe Mathieu-Daudé 9610f7d4d5SPhilippe Mathieu-Daudé #if DATA_SIZE >= 16 97e6cd4bb5SRichard Henderson #if HAVE_ATOMIC128 9810f7d4d5SPhilippe Mathieu-Daudé ABI_TYPE ATOMIC_NAME(ld)(CPUArchState *env, target_ulong addr EXTRA_ARGS) 9910f7d4d5SPhilippe Mathieu-Daudé { 10034d49937SPeter Maydell ATOMIC_MMU_DECLS; 10110f7d4d5SPhilippe Mathieu-Daudé DATA_TYPE val, *haddr = ATOMIC_MMU_LOOKUP; 102cfec3885SEmilio G. Cota uint16_t info = glue(trace_mem_build_info_no_se, MEND)(SHIFT, false, 103cfec3885SEmilio G. Cota ATOMIC_MMU_IDX); 104d071f4cdSEmilio G. Cota 105cfec3885SEmilio G. Cota atomic_trace_ld_pre(env, addr, info); 106e6cd4bb5SRichard Henderson val = atomic16_read(haddr); 107ec603b55SRichard Henderson ATOMIC_MMU_CLEANUP; 108cfec3885SEmilio G. Cota atomic_trace_ld_post(env, addr, info); 10910f7d4d5SPhilippe Mathieu-Daudé return val; 11010f7d4d5SPhilippe Mathieu-Daudé } 11110f7d4d5SPhilippe Mathieu-Daudé 11210f7d4d5SPhilippe Mathieu-Daudé void ATOMIC_NAME(st)(CPUArchState *env, target_ulong addr, 11310f7d4d5SPhilippe Mathieu-Daudé ABI_TYPE val EXTRA_ARGS) 11410f7d4d5SPhilippe Mathieu-Daudé { 11534d49937SPeter Maydell ATOMIC_MMU_DECLS; 11610f7d4d5SPhilippe Mathieu-Daudé DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP; 117cfec3885SEmilio G. Cota uint16_t info = glue(trace_mem_build_info_no_se, MEND)(SHIFT, true, 118cfec3885SEmilio G. Cota ATOMIC_MMU_IDX); 119d071f4cdSEmilio G. Cota 120cfec3885SEmilio G. Cota atomic_trace_st_pre(env, addr, info); 121e6cd4bb5SRichard Henderson atomic16_set(haddr, val); 122ec603b55SRichard Henderson ATOMIC_MMU_CLEANUP; 123cfec3885SEmilio G. Cota atomic_trace_st_post(env, addr, info); 12410f7d4d5SPhilippe Mathieu-Daudé } 125e6cd4bb5SRichard Henderson #endif 12610f7d4d5SPhilippe Mathieu-Daudé #else 12710f7d4d5SPhilippe Mathieu-Daudé ABI_TYPE ATOMIC_NAME(xchg)(CPUArchState *env, target_ulong addr, 12810f7d4d5SPhilippe Mathieu-Daudé ABI_TYPE val EXTRA_ARGS) 12910f7d4d5SPhilippe Mathieu-Daudé { 13034d49937SPeter Maydell ATOMIC_MMU_DECLS; 13110f7d4d5SPhilippe Mathieu-Daudé DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP; 132d071f4cdSEmilio G. Cota DATA_TYPE ret; 133cfec3885SEmilio G. Cota uint16_t info = glue(trace_mem_build_info_no_se, MEND)(SHIFT, false, 134cfec3885SEmilio G. Cota ATOMIC_MMU_IDX); 135d071f4cdSEmilio G. Cota 136cfec3885SEmilio G. Cota atomic_trace_rmw_pre(env, addr, info); 137d071f4cdSEmilio G. Cota ret = atomic_xchg__nocheck(haddr, val); 138ec603b55SRichard Henderson ATOMIC_MMU_CLEANUP; 139cfec3885SEmilio G. Cota atomic_trace_rmw_post(env, addr, info); 140ec603b55SRichard Henderson return ret; 14110f7d4d5SPhilippe Mathieu-Daudé } 14210f7d4d5SPhilippe Mathieu-Daudé 14310f7d4d5SPhilippe Mathieu-Daudé #define GEN_ATOMIC_HELPER(X) \ 14410f7d4d5SPhilippe Mathieu-Daudé ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr, \ 14510f7d4d5SPhilippe Mathieu-Daudé ABI_TYPE val EXTRA_ARGS) \ 14610f7d4d5SPhilippe Mathieu-Daudé { \ 14734d49937SPeter Maydell ATOMIC_MMU_DECLS; \ 14810f7d4d5SPhilippe Mathieu-Daudé DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP; \ 149d071f4cdSEmilio G. Cota DATA_TYPE ret; \ 150cfec3885SEmilio G. Cota uint16_t info = glue(trace_mem_build_info_no_se, MEND)(SHIFT, \ 151cfec3885SEmilio G. Cota false, \ 152cfec3885SEmilio G. Cota ATOMIC_MMU_IDX); \ 153d071f4cdSEmilio G. Cota \ 154cfec3885SEmilio G. Cota atomic_trace_rmw_pre(env, addr, info); \ 155d071f4cdSEmilio G. Cota ret = atomic_##X(haddr, val); \ 156ec603b55SRichard Henderson ATOMIC_MMU_CLEANUP; \ 157cfec3885SEmilio G. Cota atomic_trace_rmw_post(env, addr, info); \ 158ec603b55SRichard Henderson return ret; \ 159ec603b55SRichard Henderson } 16010f7d4d5SPhilippe Mathieu-Daudé 16110f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(fetch_add) 16210f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(fetch_and) 16310f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(fetch_or) 16410f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(fetch_xor) 16510f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(add_fetch) 16610f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(and_fetch) 16710f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(or_fetch) 16810f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(xor_fetch) 16910f7d4d5SPhilippe Mathieu-Daudé 17010f7d4d5SPhilippe Mathieu-Daudé #undef GEN_ATOMIC_HELPER 1715507c2bfSRichard Henderson 1725507c2bfSRichard Henderson /* These helpers are, as a whole, full barriers. Within the helper, 1735507c2bfSRichard Henderson * the leading barrier is explicit and the trailing barrier is within 1745507c2bfSRichard Henderson * cmpxchg primitive. 175d071f4cdSEmilio G. Cota * 176d071f4cdSEmilio G. Cota * Trace this load + RMW loop as a single RMW op. This way, regardless 177d071f4cdSEmilio G. Cota * of CF_PARALLEL's value, we'll trace just a read and a write. 1785507c2bfSRichard Henderson */ 1795507c2bfSRichard Henderson #define GEN_ATOMIC_HELPER_FN(X, FN, XDATA_TYPE, RET) \ 1805507c2bfSRichard Henderson ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr, \ 1815507c2bfSRichard Henderson ABI_TYPE xval EXTRA_ARGS) \ 1825507c2bfSRichard Henderson { \ 1835507c2bfSRichard Henderson ATOMIC_MMU_DECLS; \ 1845507c2bfSRichard Henderson XDATA_TYPE *haddr = ATOMIC_MMU_LOOKUP; \ 1855507c2bfSRichard Henderson XDATA_TYPE cmp, old, new, val = xval; \ 186cfec3885SEmilio G. Cota uint16_t info = glue(trace_mem_build_info_no_se, MEND)(SHIFT, \ 187cfec3885SEmilio G. Cota false, \ 188cfec3885SEmilio G. Cota ATOMIC_MMU_IDX); \ 189d071f4cdSEmilio G. Cota \ 190cfec3885SEmilio G. Cota atomic_trace_rmw_pre(env, addr, info); \ 1915507c2bfSRichard Henderson smp_mb(); \ 1925507c2bfSRichard Henderson cmp = atomic_read__nocheck(haddr); \ 1935507c2bfSRichard Henderson do { \ 1945507c2bfSRichard Henderson old = cmp; new = FN(old, val); \ 1955507c2bfSRichard Henderson cmp = atomic_cmpxchg__nocheck(haddr, old, new); \ 1965507c2bfSRichard Henderson } while (cmp != old); \ 1975507c2bfSRichard Henderson ATOMIC_MMU_CLEANUP; \ 198cfec3885SEmilio G. Cota atomic_trace_rmw_post(env, addr, info); \ 1995507c2bfSRichard Henderson return RET; \ 2005507c2bfSRichard Henderson } 2015507c2bfSRichard Henderson 2025507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(fetch_smin, MIN, SDATA_TYPE, old) 2035507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(fetch_umin, MIN, DATA_TYPE, old) 2045507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(fetch_smax, MAX, SDATA_TYPE, old) 2055507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(fetch_umax, MAX, DATA_TYPE, old) 2065507c2bfSRichard Henderson 2075507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(smin_fetch, MIN, SDATA_TYPE, new) 2085507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(umin_fetch, MIN, DATA_TYPE, new) 2095507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(smax_fetch, MAX, SDATA_TYPE, new) 2105507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(umax_fetch, MAX, DATA_TYPE, new) 2115507c2bfSRichard Henderson 2125507c2bfSRichard Henderson #undef GEN_ATOMIC_HELPER_FN 21310f7d4d5SPhilippe Mathieu-Daudé #endif /* DATA SIZE >= 16 */ 21410f7d4d5SPhilippe Mathieu-Daudé 21510f7d4d5SPhilippe Mathieu-Daudé #undef END 216d071f4cdSEmilio G. Cota #undef MEND 21710f7d4d5SPhilippe Mathieu-Daudé 21810f7d4d5SPhilippe Mathieu-Daudé #if DATA_SIZE > 1 21910f7d4d5SPhilippe Mathieu-Daudé 22010f7d4d5SPhilippe Mathieu-Daudé /* Define reverse-host-endian atomic operations. Note that END is used 22110f7d4d5SPhilippe Mathieu-Daudé within the ATOMIC_NAME macro. */ 22210f7d4d5SPhilippe Mathieu-Daudé #ifdef HOST_WORDS_BIGENDIAN 22310f7d4d5SPhilippe Mathieu-Daudé # define END _le 224d071f4cdSEmilio G. Cota # define MEND _le 22510f7d4d5SPhilippe Mathieu-Daudé #else 22610f7d4d5SPhilippe Mathieu-Daudé # define END _be 227d071f4cdSEmilio G. Cota # define MEND _be 22810f7d4d5SPhilippe Mathieu-Daudé #endif 22910f7d4d5SPhilippe Mathieu-Daudé 23010f7d4d5SPhilippe Mathieu-Daudé ABI_TYPE ATOMIC_NAME(cmpxchg)(CPUArchState *env, target_ulong addr, 23110f7d4d5SPhilippe Mathieu-Daudé ABI_TYPE cmpv, ABI_TYPE newv EXTRA_ARGS) 23210f7d4d5SPhilippe Mathieu-Daudé { 23334d49937SPeter Maydell ATOMIC_MMU_DECLS; 23410f7d4d5SPhilippe Mathieu-Daudé DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP; 235d071f4cdSEmilio G. Cota DATA_TYPE ret; 236cfec3885SEmilio G. Cota uint16_t info = glue(trace_mem_build_info_no_se, MEND)(SHIFT, 237cfec3885SEmilio G. Cota false, 238cfec3885SEmilio G. Cota ATOMIC_MMU_IDX); 239d071f4cdSEmilio G. Cota 240cfec3885SEmilio G. Cota atomic_trace_rmw_pre(env, addr, info); 241e6cd4bb5SRichard Henderson #if DATA_SIZE == 16 242e6cd4bb5SRichard Henderson ret = atomic16_cmpxchg(haddr, BSWAP(cmpv), BSWAP(newv)); 243e6cd4bb5SRichard Henderson #else 244d071f4cdSEmilio G. Cota ret = atomic_cmpxchg__nocheck(haddr, BSWAP(cmpv), BSWAP(newv)); 245e6cd4bb5SRichard Henderson #endif 246ec603b55SRichard Henderson ATOMIC_MMU_CLEANUP; 247cfec3885SEmilio G. Cota atomic_trace_rmw_post(env, addr, info); 248ec603b55SRichard Henderson return BSWAP(ret); 24910f7d4d5SPhilippe Mathieu-Daudé } 25010f7d4d5SPhilippe Mathieu-Daudé 25110f7d4d5SPhilippe Mathieu-Daudé #if DATA_SIZE >= 16 252e6cd4bb5SRichard Henderson #if HAVE_ATOMIC128 25310f7d4d5SPhilippe Mathieu-Daudé ABI_TYPE ATOMIC_NAME(ld)(CPUArchState *env, target_ulong addr EXTRA_ARGS) 25410f7d4d5SPhilippe Mathieu-Daudé { 25534d49937SPeter Maydell ATOMIC_MMU_DECLS; 25610f7d4d5SPhilippe Mathieu-Daudé DATA_TYPE val, *haddr = ATOMIC_MMU_LOOKUP; 257cfec3885SEmilio G. Cota uint16_t info = glue(trace_mem_build_info_no_se, MEND)(SHIFT, 258cfec3885SEmilio G. Cota false, 259cfec3885SEmilio G. Cota ATOMIC_MMU_IDX); 260d071f4cdSEmilio G. Cota 261cfec3885SEmilio G. Cota atomic_trace_ld_pre(env, addr, info); 262e6cd4bb5SRichard Henderson val = atomic16_read(haddr); 263ec603b55SRichard Henderson ATOMIC_MMU_CLEANUP; 264cfec3885SEmilio G. Cota atomic_trace_ld_post(env, addr, info); 26510f7d4d5SPhilippe Mathieu-Daudé return BSWAP(val); 26610f7d4d5SPhilippe Mathieu-Daudé } 26710f7d4d5SPhilippe Mathieu-Daudé 26810f7d4d5SPhilippe Mathieu-Daudé void ATOMIC_NAME(st)(CPUArchState *env, target_ulong addr, 26910f7d4d5SPhilippe Mathieu-Daudé ABI_TYPE val EXTRA_ARGS) 27010f7d4d5SPhilippe Mathieu-Daudé { 27134d49937SPeter Maydell ATOMIC_MMU_DECLS; 27210f7d4d5SPhilippe Mathieu-Daudé DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP; 273cfec3885SEmilio G. Cota uint16_t info = glue(trace_mem_build_info_no_se, MEND)(SHIFT, 274cfec3885SEmilio G. Cota true, 275cfec3885SEmilio G. Cota ATOMIC_MMU_IDX); 276d071f4cdSEmilio G. Cota 277cfec3885SEmilio G. Cota val = BSWAP(val); 278cfec3885SEmilio G. Cota atomic_trace_st_pre(env, addr, info); 27910f7d4d5SPhilippe Mathieu-Daudé val = BSWAP(val); 280e6cd4bb5SRichard Henderson atomic16_set(haddr, val); 281ec603b55SRichard Henderson ATOMIC_MMU_CLEANUP; 282cfec3885SEmilio G. Cota atomic_trace_st_post(env, addr, info); 28310f7d4d5SPhilippe Mathieu-Daudé } 284e6cd4bb5SRichard Henderson #endif 28510f7d4d5SPhilippe Mathieu-Daudé #else 28610f7d4d5SPhilippe Mathieu-Daudé ABI_TYPE ATOMIC_NAME(xchg)(CPUArchState *env, target_ulong addr, 28710f7d4d5SPhilippe Mathieu-Daudé ABI_TYPE val EXTRA_ARGS) 28810f7d4d5SPhilippe Mathieu-Daudé { 28934d49937SPeter Maydell ATOMIC_MMU_DECLS; 29010f7d4d5SPhilippe Mathieu-Daudé DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP; 291d071f4cdSEmilio G. Cota ABI_TYPE ret; 292cfec3885SEmilio G. Cota uint16_t info = glue(trace_mem_build_info_no_se, MEND)(SHIFT, 293cfec3885SEmilio G. Cota false, 294cfec3885SEmilio G. Cota ATOMIC_MMU_IDX); 295d071f4cdSEmilio G. Cota 296cfec3885SEmilio G. Cota atomic_trace_rmw_pre(env, addr, info); 297d071f4cdSEmilio G. Cota ret = atomic_xchg__nocheck(haddr, BSWAP(val)); 298ec603b55SRichard Henderson ATOMIC_MMU_CLEANUP; 299cfec3885SEmilio G. Cota atomic_trace_rmw_post(env, addr, info); 300ec603b55SRichard Henderson return BSWAP(ret); 30110f7d4d5SPhilippe Mathieu-Daudé } 30210f7d4d5SPhilippe Mathieu-Daudé 30310f7d4d5SPhilippe Mathieu-Daudé #define GEN_ATOMIC_HELPER(X) \ 30410f7d4d5SPhilippe Mathieu-Daudé ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr, \ 30510f7d4d5SPhilippe Mathieu-Daudé ABI_TYPE val EXTRA_ARGS) \ 30610f7d4d5SPhilippe Mathieu-Daudé { \ 30734d49937SPeter Maydell ATOMIC_MMU_DECLS; \ 30810f7d4d5SPhilippe Mathieu-Daudé DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP; \ 309d071f4cdSEmilio G. Cota DATA_TYPE ret; \ 310cfec3885SEmilio G. Cota uint16_t info = glue(trace_mem_build_info_no_se, MEND)(SHIFT, \ 311cfec3885SEmilio G. Cota false, \ 312cfec3885SEmilio G. Cota ATOMIC_MMU_IDX); \ 313d071f4cdSEmilio G. Cota \ 314cfec3885SEmilio G. Cota atomic_trace_rmw_pre(env, addr, info); \ 315d071f4cdSEmilio G. Cota ret = atomic_##X(haddr, BSWAP(val)); \ 316ec603b55SRichard Henderson ATOMIC_MMU_CLEANUP; \ 317cfec3885SEmilio G. Cota atomic_trace_rmw_post(env, addr, info); \ 318ec603b55SRichard Henderson return BSWAP(ret); \ 31910f7d4d5SPhilippe Mathieu-Daudé } 32010f7d4d5SPhilippe Mathieu-Daudé 32110f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(fetch_and) 32210f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(fetch_or) 32310f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(fetch_xor) 32410f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(and_fetch) 32510f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(or_fetch) 32610f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(xor_fetch) 32710f7d4d5SPhilippe Mathieu-Daudé 32810f7d4d5SPhilippe Mathieu-Daudé #undef GEN_ATOMIC_HELPER 32910f7d4d5SPhilippe Mathieu-Daudé 3305507c2bfSRichard Henderson /* These helpers are, as a whole, full barriers. Within the helper, 3315507c2bfSRichard Henderson * the leading barrier is explicit and the trailing barrier is within 3325507c2bfSRichard Henderson * cmpxchg primitive. 333d071f4cdSEmilio G. Cota * 334d071f4cdSEmilio G. Cota * Trace this load + RMW loop as a single RMW op. This way, regardless 335d071f4cdSEmilio G. Cota * of CF_PARALLEL's value, we'll trace just a read and a write. 3365507c2bfSRichard Henderson */ 3375507c2bfSRichard Henderson #define GEN_ATOMIC_HELPER_FN(X, FN, XDATA_TYPE, RET) \ 3385507c2bfSRichard Henderson ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr, \ 3395507c2bfSRichard Henderson ABI_TYPE xval EXTRA_ARGS) \ 3405507c2bfSRichard Henderson { \ 3415507c2bfSRichard Henderson ATOMIC_MMU_DECLS; \ 3425507c2bfSRichard Henderson XDATA_TYPE *haddr = ATOMIC_MMU_LOOKUP; \ 3435507c2bfSRichard Henderson XDATA_TYPE ldo, ldn, old, new, val = xval; \ 344cfec3885SEmilio G. Cota uint16_t info = glue(trace_mem_build_info_no_se, MEND)(SHIFT, \ 345cfec3885SEmilio G. Cota false, \ 346cfec3885SEmilio G. Cota ATOMIC_MMU_IDX); \ 347d071f4cdSEmilio G. Cota \ 348cfec3885SEmilio G. Cota atomic_trace_rmw_pre(env, addr, info); \ 3495507c2bfSRichard Henderson smp_mb(); \ 3505507c2bfSRichard Henderson ldn = atomic_read__nocheck(haddr); \ 3515507c2bfSRichard Henderson do { \ 3525507c2bfSRichard Henderson ldo = ldn; old = BSWAP(ldo); new = FN(old, val); \ 3535507c2bfSRichard Henderson ldn = atomic_cmpxchg__nocheck(haddr, ldo, BSWAP(new)); \ 3545507c2bfSRichard Henderson } while (ldo != ldn); \ 3555507c2bfSRichard Henderson ATOMIC_MMU_CLEANUP; \ 356cfec3885SEmilio G. Cota atomic_trace_rmw_post(env, addr, info); \ 3575507c2bfSRichard Henderson return RET; \ 3585507c2bfSRichard Henderson } 3595507c2bfSRichard Henderson 3605507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(fetch_smin, MIN, SDATA_TYPE, old) 3615507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(fetch_umin, MIN, DATA_TYPE, old) 3625507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(fetch_smax, MAX, SDATA_TYPE, old) 3635507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(fetch_umax, MAX, DATA_TYPE, old) 3645507c2bfSRichard Henderson 3655507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(smin_fetch, MIN, SDATA_TYPE, new) 3665507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(umin_fetch, MIN, DATA_TYPE, new) 3675507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(smax_fetch, MAX, SDATA_TYPE, new) 3685507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(umax_fetch, MAX, DATA_TYPE, new) 3695507c2bfSRichard Henderson 37058edf9eeSRichard Henderson /* Note that for addition, we need to use a separate cmpxchg loop instead 37158edf9eeSRichard Henderson of bswaps for the reverse-host-endian helpers. */ 37258edf9eeSRichard Henderson #define ADD(X, Y) (X + Y) 37358edf9eeSRichard Henderson GEN_ATOMIC_HELPER_FN(fetch_add, ADD, DATA_TYPE, old) 37458edf9eeSRichard Henderson GEN_ATOMIC_HELPER_FN(add_fetch, ADD, DATA_TYPE, new) 37558edf9eeSRichard Henderson #undef ADD 37658edf9eeSRichard Henderson 3775507c2bfSRichard Henderson #undef GEN_ATOMIC_HELPER_FN 37810f7d4d5SPhilippe Mathieu-Daudé #endif /* DATA_SIZE >= 16 */ 37910f7d4d5SPhilippe Mathieu-Daudé 38010f7d4d5SPhilippe Mathieu-Daudé #undef END 381d071f4cdSEmilio G. Cota #undef MEND 38210f7d4d5SPhilippe Mathieu-Daudé #endif /* DATA_SIZE > 1 */ 38310f7d4d5SPhilippe Mathieu-Daudé 38410f7d4d5SPhilippe Mathieu-Daudé #undef BSWAP 38510f7d4d5SPhilippe Mathieu-Daudé #undef ABI_TYPE 38610f7d4d5SPhilippe Mathieu-Daudé #undef DATA_TYPE 3875507c2bfSRichard Henderson #undef SDATA_TYPE 38810f7d4d5SPhilippe Mathieu-Daudé #undef SUFFIX 38910f7d4d5SPhilippe Mathieu-Daudé #undef DATA_SIZE 390d071f4cdSEmilio G. Cota #undef SHIFT 391