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é 21e6d86bedSEmilio 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 319ef0c6d6SRichard Henderson # define DATA_TYPE aligned_uint64_t 329ef0c6d6SRichard Henderson # define SDATA_TYPE aligned_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 6710f7d4d5SPhilippe Mathieu-Daudé #elif defined(HOST_WORDS_BIGENDIAN) 6810f7d4d5SPhilippe Mathieu-Daudé # define END _be 6910f7d4d5SPhilippe Mathieu-Daudé #else 7010f7d4d5SPhilippe Mathieu-Daudé # define END _le 7110f7d4d5SPhilippe Mathieu-Daudé #endif 7210f7d4d5SPhilippe Mathieu-Daudé 7310f7d4d5SPhilippe Mathieu-Daudé ABI_TYPE ATOMIC_NAME(cmpxchg)(CPUArchState *env, target_ulong addr, 7448688fafSRichard Henderson ABI_TYPE cmpv, ABI_TYPE newv, 75*9002ffcbSRichard Henderson MemOpIdx oi, uintptr_t retaddr) 7610f7d4d5SPhilippe Mathieu-Daudé { 77a754f7f3SRichard Henderson DATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE, 78a754f7f3SRichard Henderson PAGE_READ | PAGE_WRITE, retaddr); 79d071f4cdSEmilio G. Cota DATA_TYPE ret; 80f3e182b1SRichard Henderson uint16_t info = atomic_trace_rmw_pre(env, addr, oi); 81d071f4cdSEmilio G. Cota 82e6cd4bb5SRichard Henderson #if DATA_SIZE == 16 83e6cd4bb5SRichard Henderson ret = atomic16_cmpxchg(haddr, cmpv, newv); 84e6cd4bb5SRichard Henderson #else 85d73415a3SStefan Hajnoczi ret = qatomic_cmpxchg__nocheck(haddr, cmpv, newv); 86e6cd4bb5SRichard Henderson #endif 87ec603b55SRichard Henderson ATOMIC_MMU_CLEANUP; 88cfec3885SEmilio G. Cota atomic_trace_rmw_post(env, addr, info); 89ec603b55SRichard Henderson return ret; 9010f7d4d5SPhilippe Mathieu-Daudé } 9110f7d4d5SPhilippe Mathieu-Daudé 9210f7d4d5SPhilippe Mathieu-Daudé #if DATA_SIZE >= 16 93e6cd4bb5SRichard Henderson #if HAVE_ATOMIC128 9448688fafSRichard Henderson ABI_TYPE ATOMIC_NAME(ld)(CPUArchState *env, target_ulong addr, 95*9002ffcbSRichard Henderson MemOpIdx oi, uintptr_t retaddr) 9610f7d4d5SPhilippe Mathieu-Daudé { 97a754f7f3SRichard Henderson DATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE, 98a754f7f3SRichard Henderson PAGE_READ, retaddr); 99a754f7f3SRichard Henderson DATA_TYPE val; 100f3e182b1SRichard Henderson uint16_t info = atomic_trace_ld_pre(env, addr, oi); 101d071f4cdSEmilio G. Cota 102e6cd4bb5SRichard Henderson val = atomic16_read(haddr); 103ec603b55SRichard Henderson ATOMIC_MMU_CLEANUP; 104cfec3885SEmilio G. Cota atomic_trace_ld_post(env, addr, info); 10510f7d4d5SPhilippe Mathieu-Daudé return val; 10610f7d4d5SPhilippe Mathieu-Daudé } 10710f7d4d5SPhilippe Mathieu-Daudé 10848688fafSRichard Henderson void ATOMIC_NAME(st)(CPUArchState *env, target_ulong addr, ABI_TYPE val, 109*9002ffcbSRichard Henderson MemOpIdx oi, uintptr_t retaddr) 11010f7d4d5SPhilippe Mathieu-Daudé { 111a754f7f3SRichard Henderson DATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE, 112a754f7f3SRichard Henderson PAGE_WRITE, retaddr); 113f3e182b1SRichard Henderson uint16_t info = atomic_trace_st_pre(env, addr, oi); 114d071f4cdSEmilio G. Cota 115e6cd4bb5SRichard Henderson atomic16_set(haddr, val); 116ec603b55SRichard Henderson ATOMIC_MMU_CLEANUP; 117cfec3885SEmilio G. Cota atomic_trace_st_post(env, addr, info); 11810f7d4d5SPhilippe Mathieu-Daudé } 119e6cd4bb5SRichard Henderson #endif 12010f7d4d5SPhilippe Mathieu-Daudé #else 12148688fafSRichard Henderson ABI_TYPE ATOMIC_NAME(xchg)(CPUArchState *env, target_ulong addr, ABI_TYPE val, 122*9002ffcbSRichard Henderson MemOpIdx oi, uintptr_t retaddr) 12310f7d4d5SPhilippe Mathieu-Daudé { 124a754f7f3SRichard Henderson DATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE, 125a754f7f3SRichard Henderson PAGE_READ | PAGE_WRITE, retaddr); 126d071f4cdSEmilio G. Cota DATA_TYPE ret; 127f3e182b1SRichard Henderson uint16_t info = atomic_trace_rmw_pre(env, addr, oi); 128d071f4cdSEmilio G. Cota 129d73415a3SStefan Hajnoczi ret = qatomic_xchg__nocheck(haddr, val); 130ec603b55SRichard Henderson ATOMIC_MMU_CLEANUP; 131cfec3885SEmilio G. Cota atomic_trace_rmw_post(env, addr, info); 132ec603b55SRichard Henderson return ret; 13310f7d4d5SPhilippe Mathieu-Daudé } 13410f7d4d5SPhilippe Mathieu-Daudé 13510f7d4d5SPhilippe Mathieu-Daudé #define GEN_ATOMIC_HELPER(X) \ 13610f7d4d5SPhilippe Mathieu-Daudé ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr, \ 137*9002ffcbSRichard Henderson ABI_TYPE val, MemOpIdx oi, uintptr_t retaddr) \ 13810f7d4d5SPhilippe Mathieu-Daudé { \ 139a754f7f3SRichard Henderson DATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE, \ 140a754f7f3SRichard Henderson PAGE_READ | PAGE_WRITE, retaddr); \ 141d071f4cdSEmilio G. Cota DATA_TYPE ret; \ 142f3e182b1SRichard Henderson uint16_t info = atomic_trace_rmw_pre(env, addr, oi); \ 143d73415a3SStefan Hajnoczi ret = qatomic_##X(haddr, val); \ 144ec603b55SRichard Henderson ATOMIC_MMU_CLEANUP; \ 145cfec3885SEmilio G. Cota atomic_trace_rmw_post(env, addr, info); \ 146ec603b55SRichard Henderson return ret; \ 147ec603b55SRichard Henderson } 14810f7d4d5SPhilippe Mathieu-Daudé 14910f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(fetch_add) 15010f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(fetch_and) 15110f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(fetch_or) 15210f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(fetch_xor) 15310f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(add_fetch) 15410f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(and_fetch) 15510f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(or_fetch) 15610f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(xor_fetch) 15710f7d4d5SPhilippe Mathieu-Daudé 15810f7d4d5SPhilippe Mathieu-Daudé #undef GEN_ATOMIC_HELPER 1595507c2bfSRichard Henderson 160a754f7f3SRichard Henderson /* 161a754f7f3SRichard Henderson * These helpers are, as a whole, full barriers. Within the helper, 1625507c2bfSRichard Henderson * the leading barrier is explicit and the trailing barrier is within 1635507c2bfSRichard Henderson * cmpxchg primitive. 164d071f4cdSEmilio G. Cota * 165d071f4cdSEmilio G. Cota * Trace this load + RMW loop as a single RMW op. This way, regardless 166d071f4cdSEmilio G. Cota * of CF_PARALLEL's value, we'll trace just a read and a write. 1675507c2bfSRichard Henderson */ 1685507c2bfSRichard Henderson #define GEN_ATOMIC_HELPER_FN(X, FN, XDATA_TYPE, RET) \ 1695507c2bfSRichard Henderson ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr, \ 170*9002ffcbSRichard Henderson ABI_TYPE xval, MemOpIdx oi, uintptr_t retaddr) \ 1715507c2bfSRichard Henderson { \ 172a754f7f3SRichard Henderson XDATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE, \ 173a754f7f3SRichard Henderson PAGE_READ | PAGE_WRITE, retaddr); \ 1745507c2bfSRichard Henderson XDATA_TYPE cmp, old, new, val = xval; \ 175f3e182b1SRichard Henderson uint16_t info = atomic_trace_rmw_pre(env, addr, oi); \ 1765507c2bfSRichard Henderson smp_mb(); \ 177d73415a3SStefan Hajnoczi cmp = qatomic_read__nocheck(haddr); \ 1785507c2bfSRichard Henderson do { \ 1795507c2bfSRichard Henderson old = cmp; new = FN(old, val); \ 180d73415a3SStefan Hajnoczi cmp = qatomic_cmpxchg__nocheck(haddr, old, new); \ 1815507c2bfSRichard Henderson } while (cmp != old); \ 1825507c2bfSRichard Henderson ATOMIC_MMU_CLEANUP; \ 183cfec3885SEmilio G. Cota atomic_trace_rmw_post(env, addr, info); \ 1845507c2bfSRichard Henderson return RET; \ 1855507c2bfSRichard Henderson } 1865507c2bfSRichard Henderson 1875507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(fetch_smin, MIN, SDATA_TYPE, old) 1885507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(fetch_umin, MIN, DATA_TYPE, old) 1895507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(fetch_smax, MAX, SDATA_TYPE, old) 1905507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(fetch_umax, MAX, DATA_TYPE, old) 1915507c2bfSRichard Henderson 1925507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(smin_fetch, MIN, SDATA_TYPE, new) 1935507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(umin_fetch, MIN, DATA_TYPE, new) 1945507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(smax_fetch, MAX, SDATA_TYPE, new) 1955507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(umax_fetch, MAX, DATA_TYPE, new) 1965507c2bfSRichard Henderson 1975507c2bfSRichard Henderson #undef GEN_ATOMIC_HELPER_FN 19810f7d4d5SPhilippe Mathieu-Daudé #endif /* DATA SIZE >= 16 */ 19910f7d4d5SPhilippe Mathieu-Daudé 20010f7d4d5SPhilippe Mathieu-Daudé #undef END 20110f7d4d5SPhilippe Mathieu-Daudé 20210f7d4d5SPhilippe Mathieu-Daudé #if DATA_SIZE > 1 20310f7d4d5SPhilippe Mathieu-Daudé 20410f7d4d5SPhilippe Mathieu-Daudé /* Define reverse-host-endian atomic operations. Note that END is used 20510f7d4d5SPhilippe Mathieu-Daudé within the ATOMIC_NAME macro. */ 20610f7d4d5SPhilippe Mathieu-Daudé #ifdef HOST_WORDS_BIGENDIAN 20710f7d4d5SPhilippe Mathieu-Daudé # define END _le 20810f7d4d5SPhilippe Mathieu-Daudé #else 20910f7d4d5SPhilippe Mathieu-Daudé # define END _be 21010f7d4d5SPhilippe Mathieu-Daudé #endif 21110f7d4d5SPhilippe Mathieu-Daudé 21210f7d4d5SPhilippe Mathieu-Daudé ABI_TYPE ATOMIC_NAME(cmpxchg)(CPUArchState *env, target_ulong addr, 21348688fafSRichard Henderson ABI_TYPE cmpv, ABI_TYPE newv, 214*9002ffcbSRichard Henderson MemOpIdx oi, uintptr_t retaddr) 21510f7d4d5SPhilippe Mathieu-Daudé { 216a754f7f3SRichard Henderson DATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE, 217a754f7f3SRichard Henderson PAGE_READ | PAGE_WRITE, retaddr); 218d071f4cdSEmilio G. Cota DATA_TYPE ret; 219f3e182b1SRichard Henderson uint16_t info = atomic_trace_rmw_pre(env, addr, oi); 220d071f4cdSEmilio G. Cota 221e6cd4bb5SRichard Henderson #if DATA_SIZE == 16 222e6cd4bb5SRichard Henderson ret = atomic16_cmpxchg(haddr, BSWAP(cmpv), BSWAP(newv)); 223e6cd4bb5SRichard Henderson #else 224d73415a3SStefan Hajnoczi ret = qatomic_cmpxchg__nocheck(haddr, BSWAP(cmpv), BSWAP(newv)); 225e6cd4bb5SRichard Henderson #endif 226ec603b55SRichard Henderson ATOMIC_MMU_CLEANUP; 227cfec3885SEmilio G. Cota atomic_trace_rmw_post(env, addr, info); 228ec603b55SRichard Henderson return BSWAP(ret); 22910f7d4d5SPhilippe Mathieu-Daudé } 23010f7d4d5SPhilippe Mathieu-Daudé 23110f7d4d5SPhilippe Mathieu-Daudé #if DATA_SIZE >= 16 232e6cd4bb5SRichard Henderson #if HAVE_ATOMIC128 23348688fafSRichard Henderson ABI_TYPE ATOMIC_NAME(ld)(CPUArchState *env, target_ulong addr, 234*9002ffcbSRichard Henderson MemOpIdx oi, uintptr_t retaddr) 23510f7d4d5SPhilippe Mathieu-Daudé { 236a754f7f3SRichard Henderson DATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE, 237a754f7f3SRichard Henderson PAGE_READ, retaddr); 238a754f7f3SRichard Henderson DATA_TYPE val; 239f3e182b1SRichard Henderson uint16_t info = atomic_trace_ld_pre(env, addr, oi); 240d071f4cdSEmilio G. Cota 241e6cd4bb5SRichard Henderson val = atomic16_read(haddr); 242ec603b55SRichard Henderson ATOMIC_MMU_CLEANUP; 243cfec3885SEmilio G. Cota atomic_trace_ld_post(env, addr, info); 24410f7d4d5SPhilippe Mathieu-Daudé return BSWAP(val); 24510f7d4d5SPhilippe Mathieu-Daudé } 24610f7d4d5SPhilippe Mathieu-Daudé 24748688fafSRichard Henderson void ATOMIC_NAME(st)(CPUArchState *env, target_ulong addr, ABI_TYPE val, 248*9002ffcbSRichard Henderson MemOpIdx oi, uintptr_t retaddr) 24910f7d4d5SPhilippe Mathieu-Daudé { 250a754f7f3SRichard Henderson DATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE, 251a754f7f3SRichard Henderson PAGE_WRITE, retaddr); 252f3e182b1SRichard Henderson uint16_t info = atomic_trace_st_pre(env, addr, oi); 253d071f4cdSEmilio G. Cota 254cfec3885SEmilio G. Cota val = BSWAP(val); 255e6cd4bb5SRichard Henderson atomic16_set(haddr, val); 256ec603b55SRichard Henderson ATOMIC_MMU_CLEANUP; 257cfec3885SEmilio G. Cota atomic_trace_st_post(env, addr, info); 25810f7d4d5SPhilippe Mathieu-Daudé } 259e6cd4bb5SRichard Henderson #endif 26010f7d4d5SPhilippe Mathieu-Daudé #else 26148688fafSRichard Henderson ABI_TYPE ATOMIC_NAME(xchg)(CPUArchState *env, target_ulong addr, ABI_TYPE val, 262*9002ffcbSRichard Henderson MemOpIdx oi, uintptr_t retaddr) 26310f7d4d5SPhilippe Mathieu-Daudé { 264a754f7f3SRichard Henderson DATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE, 265a754f7f3SRichard Henderson PAGE_READ | PAGE_WRITE, retaddr); 266d071f4cdSEmilio G. Cota ABI_TYPE ret; 267f3e182b1SRichard Henderson uint16_t info = atomic_trace_rmw_pre(env, addr, oi); 268d071f4cdSEmilio G. Cota 269d73415a3SStefan Hajnoczi ret = qatomic_xchg__nocheck(haddr, BSWAP(val)); 270ec603b55SRichard Henderson ATOMIC_MMU_CLEANUP; 271cfec3885SEmilio G. Cota atomic_trace_rmw_post(env, addr, info); 272ec603b55SRichard Henderson return BSWAP(ret); 27310f7d4d5SPhilippe Mathieu-Daudé } 27410f7d4d5SPhilippe Mathieu-Daudé 27510f7d4d5SPhilippe Mathieu-Daudé #define GEN_ATOMIC_HELPER(X) \ 27610f7d4d5SPhilippe Mathieu-Daudé ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr, \ 277*9002ffcbSRichard Henderson ABI_TYPE val, MemOpIdx oi, uintptr_t retaddr) \ 27810f7d4d5SPhilippe Mathieu-Daudé { \ 279a754f7f3SRichard Henderson DATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE, \ 280a754f7f3SRichard Henderson PAGE_READ | PAGE_WRITE, retaddr); \ 281d071f4cdSEmilio G. Cota DATA_TYPE ret; \ 282f3e182b1SRichard Henderson uint16_t info = atomic_trace_rmw_pre(env, addr, oi); \ 283d73415a3SStefan Hajnoczi ret = qatomic_##X(haddr, BSWAP(val)); \ 284ec603b55SRichard Henderson ATOMIC_MMU_CLEANUP; \ 285cfec3885SEmilio G. Cota atomic_trace_rmw_post(env, addr, info); \ 286ec603b55SRichard Henderson return BSWAP(ret); \ 28710f7d4d5SPhilippe Mathieu-Daudé } 28810f7d4d5SPhilippe Mathieu-Daudé 28910f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(fetch_and) 29010f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(fetch_or) 29110f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(fetch_xor) 29210f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(and_fetch) 29310f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(or_fetch) 29410f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(xor_fetch) 29510f7d4d5SPhilippe Mathieu-Daudé 29610f7d4d5SPhilippe Mathieu-Daudé #undef GEN_ATOMIC_HELPER 29710f7d4d5SPhilippe Mathieu-Daudé 2985507c2bfSRichard Henderson /* These helpers are, as a whole, full barriers. Within the helper, 2995507c2bfSRichard Henderson * the leading barrier is explicit and the trailing barrier is within 3005507c2bfSRichard Henderson * cmpxchg primitive. 301d071f4cdSEmilio G. Cota * 302d071f4cdSEmilio G. Cota * Trace this load + RMW loop as a single RMW op. This way, regardless 303d071f4cdSEmilio G. Cota * of CF_PARALLEL's value, we'll trace just a read and a write. 3045507c2bfSRichard Henderson */ 3055507c2bfSRichard Henderson #define GEN_ATOMIC_HELPER_FN(X, FN, XDATA_TYPE, RET) \ 3065507c2bfSRichard Henderson ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr, \ 307*9002ffcbSRichard Henderson ABI_TYPE xval, MemOpIdx oi, uintptr_t retaddr) \ 3085507c2bfSRichard Henderson { \ 309a754f7f3SRichard Henderson XDATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE, \ 310a754f7f3SRichard Henderson PAGE_READ | PAGE_WRITE, retaddr); \ 3115507c2bfSRichard Henderson XDATA_TYPE ldo, ldn, old, new, val = xval; \ 312f3e182b1SRichard Henderson uint16_t info = atomic_trace_rmw_pre(env, addr, oi); \ 3135507c2bfSRichard Henderson smp_mb(); \ 314d73415a3SStefan Hajnoczi ldn = qatomic_read__nocheck(haddr); \ 3155507c2bfSRichard Henderson do { \ 3165507c2bfSRichard Henderson ldo = ldn; old = BSWAP(ldo); new = FN(old, val); \ 317d73415a3SStefan Hajnoczi ldn = qatomic_cmpxchg__nocheck(haddr, ldo, BSWAP(new)); \ 3185507c2bfSRichard Henderson } while (ldo != ldn); \ 3195507c2bfSRichard Henderson ATOMIC_MMU_CLEANUP; \ 320cfec3885SEmilio G. Cota atomic_trace_rmw_post(env, addr, info); \ 3215507c2bfSRichard Henderson return RET; \ 3225507c2bfSRichard Henderson } 3235507c2bfSRichard Henderson 3245507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(fetch_smin, MIN, SDATA_TYPE, old) 3255507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(fetch_umin, MIN, DATA_TYPE, old) 3265507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(fetch_smax, MAX, SDATA_TYPE, old) 3275507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(fetch_umax, MAX, DATA_TYPE, old) 3285507c2bfSRichard Henderson 3295507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(smin_fetch, MIN, SDATA_TYPE, new) 3305507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(umin_fetch, MIN, DATA_TYPE, new) 3315507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(smax_fetch, MAX, SDATA_TYPE, new) 3325507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(umax_fetch, MAX, DATA_TYPE, new) 3335507c2bfSRichard Henderson 33458edf9eeSRichard Henderson /* Note that for addition, we need to use a separate cmpxchg loop instead 33558edf9eeSRichard Henderson of bswaps for the reverse-host-endian helpers. */ 33658edf9eeSRichard Henderson #define ADD(X, Y) (X + Y) 33758edf9eeSRichard Henderson GEN_ATOMIC_HELPER_FN(fetch_add, ADD, DATA_TYPE, old) 33858edf9eeSRichard Henderson GEN_ATOMIC_HELPER_FN(add_fetch, ADD, DATA_TYPE, new) 33958edf9eeSRichard Henderson #undef ADD 34058edf9eeSRichard Henderson 3415507c2bfSRichard Henderson #undef GEN_ATOMIC_HELPER_FN 34210f7d4d5SPhilippe Mathieu-Daudé #endif /* DATA_SIZE >= 16 */ 34310f7d4d5SPhilippe Mathieu-Daudé 34410f7d4d5SPhilippe Mathieu-Daudé #undef END 34510f7d4d5SPhilippe Mathieu-Daudé #endif /* DATA_SIZE > 1 */ 34610f7d4d5SPhilippe Mathieu-Daudé 34710f7d4d5SPhilippe Mathieu-Daudé #undef BSWAP 34810f7d4d5SPhilippe Mathieu-Daudé #undef ABI_TYPE 34910f7d4d5SPhilippe Mathieu-Daudé #undef DATA_TYPE 3505507c2bfSRichard Henderson #undef SDATA_TYPE 35110f7d4d5SPhilippe Mathieu-Daudé #undef SUFFIX 35210f7d4d5SPhilippe Mathieu-Daudé #undef DATA_SIZE 353d071f4cdSEmilio G. Cota #undef SHIFT 354