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, 74*48688fafSRichard Henderson ABI_TYPE cmpv, ABI_TYPE newv, 75*48688fafSRichard Henderson TCGMemOpIdx oi, uintptr_t retaddr) 7610f7d4d5SPhilippe Mathieu-Daudé { 7734d49937SPeter Maydell ATOMIC_MMU_DECLS; 7808dff435SRichard Henderson DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP_RW; 79d071f4cdSEmilio G. Cota DATA_TYPE ret; 804e6b1384SRichard Henderson uint16_t info = trace_mem_build_info(SHIFT, false, 0, false, 81cfec3885SEmilio G. Cota ATOMIC_MMU_IDX); 82d071f4cdSEmilio G. Cota 83cfec3885SEmilio G. Cota atomic_trace_rmw_pre(env, addr, info); 84e6cd4bb5SRichard Henderson #if DATA_SIZE == 16 85e6cd4bb5SRichard Henderson ret = atomic16_cmpxchg(haddr, cmpv, newv); 86e6cd4bb5SRichard Henderson #else 87d73415a3SStefan Hajnoczi ret = qatomic_cmpxchg__nocheck(haddr, cmpv, newv); 88e6cd4bb5SRichard Henderson #endif 89ec603b55SRichard Henderson ATOMIC_MMU_CLEANUP; 90cfec3885SEmilio G. Cota atomic_trace_rmw_post(env, addr, info); 91ec603b55SRichard Henderson return ret; 9210f7d4d5SPhilippe Mathieu-Daudé } 9310f7d4d5SPhilippe Mathieu-Daudé 9410f7d4d5SPhilippe Mathieu-Daudé #if DATA_SIZE >= 16 95e6cd4bb5SRichard Henderson #if HAVE_ATOMIC128 96*48688fafSRichard Henderson ABI_TYPE ATOMIC_NAME(ld)(CPUArchState *env, target_ulong addr, 97*48688fafSRichard Henderson TCGMemOpIdx oi, uintptr_t retaddr) 9810f7d4d5SPhilippe Mathieu-Daudé { 9934d49937SPeter Maydell ATOMIC_MMU_DECLS; 10008dff435SRichard Henderson DATA_TYPE val, *haddr = ATOMIC_MMU_LOOKUP_R; 1014e6b1384SRichard Henderson uint16_t info = trace_mem_build_info(SHIFT, false, 0, false, 102cfec3885SEmilio G. Cota ATOMIC_MMU_IDX); 103d071f4cdSEmilio G. Cota 104cfec3885SEmilio G. Cota atomic_trace_ld_pre(env, addr, info); 105e6cd4bb5SRichard Henderson val = atomic16_read(haddr); 106ec603b55SRichard Henderson ATOMIC_MMU_CLEANUP; 107cfec3885SEmilio G. Cota atomic_trace_ld_post(env, addr, info); 10810f7d4d5SPhilippe Mathieu-Daudé return val; 10910f7d4d5SPhilippe Mathieu-Daudé } 11010f7d4d5SPhilippe Mathieu-Daudé 111*48688fafSRichard Henderson void ATOMIC_NAME(st)(CPUArchState *env, target_ulong addr, ABI_TYPE val, 112*48688fafSRichard Henderson TCGMemOpIdx oi, uintptr_t retaddr) 11310f7d4d5SPhilippe Mathieu-Daudé { 11434d49937SPeter Maydell ATOMIC_MMU_DECLS; 11508dff435SRichard Henderson DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP_W; 1164e6b1384SRichard Henderson uint16_t info = trace_mem_build_info(SHIFT, false, 0, true, 117cfec3885SEmilio G. Cota ATOMIC_MMU_IDX); 118d071f4cdSEmilio G. Cota 119cfec3885SEmilio G. Cota atomic_trace_st_pre(env, addr, info); 120e6cd4bb5SRichard Henderson atomic16_set(haddr, val); 121ec603b55SRichard Henderson ATOMIC_MMU_CLEANUP; 122cfec3885SEmilio G. Cota atomic_trace_st_post(env, addr, info); 12310f7d4d5SPhilippe Mathieu-Daudé } 124e6cd4bb5SRichard Henderson #endif 12510f7d4d5SPhilippe Mathieu-Daudé #else 126*48688fafSRichard Henderson ABI_TYPE ATOMIC_NAME(xchg)(CPUArchState *env, target_ulong addr, ABI_TYPE val, 127*48688fafSRichard Henderson TCGMemOpIdx oi, uintptr_t retaddr) 12810f7d4d5SPhilippe Mathieu-Daudé { 12934d49937SPeter Maydell ATOMIC_MMU_DECLS; 13008dff435SRichard Henderson DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP_RW; 131d071f4cdSEmilio G. Cota DATA_TYPE ret; 1324e6b1384SRichard Henderson uint16_t info = trace_mem_build_info(SHIFT, false, 0, false, 133cfec3885SEmilio G. Cota ATOMIC_MMU_IDX); 134d071f4cdSEmilio G. Cota 135cfec3885SEmilio G. Cota atomic_trace_rmw_pre(env, addr, info); 136d73415a3SStefan Hajnoczi ret = qatomic_xchg__nocheck(haddr, val); 137ec603b55SRichard Henderson ATOMIC_MMU_CLEANUP; 138cfec3885SEmilio G. Cota atomic_trace_rmw_post(env, addr, info); 139ec603b55SRichard Henderson return ret; 14010f7d4d5SPhilippe Mathieu-Daudé } 14110f7d4d5SPhilippe Mathieu-Daudé 14210f7d4d5SPhilippe Mathieu-Daudé #define GEN_ATOMIC_HELPER(X) \ 14310f7d4d5SPhilippe Mathieu-Daudé ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr, \ 144*48688fafSRichard Henderson ABI_TYPE val, TCGMemOpIdx oi, uintptr_t retaddr) \ 14510f7d4d5SPhilippe Mathieu-Daudé { \ 14634d49937SPeter Maydell ATOMIC_MMU_DECLS; \ 14708dff435SRichard Henderson DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP_RW; \ 148d071f4cdSEmilio G. Cota DATA_TYPE ret; \ 1494e6b1384SRichard Henderson uint16_t info = trace_mem_build_info(SHIFT, false, 0, false, \ 150cfec3885SEmilio G. Cota ATOMIC_MMU_IDX); \ 151cfec3885SEmilio G. Cota atomic_trace_rmw_pre(env, addr, info); \ 152d73415a3SStefan Hajnoczi ret = qatomic_##X(haddr, val); \ 153ec603b55SRichard Henderson ATOMIC_MMU_CLEANUP; \ 154cfec3885SEmilio G. Cota atomic_trace_rmw_post(env, addr, info); \ 155ec603b55SRichard Henderson return ret; \ 156ec603b55SRichard Henderson } 15710f7d4d5SPhilippe Mathieu-Daudé 15810f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(fetch_add) 15910f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(fetch_and) 16010f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(fetch_or) 16110f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(fetch_xor) 16210f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(add_fetch) 16310f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(and_fetch) 16410f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(or_fetch) 16510f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(xor_fetch) 16610f7d4d5SPhilippe Mathieu-Daudé 16710f7d4d5SPhilippe Mathieu-Daudé #undef GEN_ATOMIC_HELPER 1685507c2bfSRichard Henderson 1695507c2bfSRichard Henderson /* These helpers are, as a whole, full barriers. Within the helper, 1705507c2bfSRichard Henderson * the leading barrier is explicit and the trailing barrier is within 1715507c2bfSRichard Henderson * cmpxchg primitive. 172d071f4cdSEmilio G. Cota * 173d071f4cdSEmilio G. Cota * Trace this load + RMW loop as a single RMW op. This way, regardless 174d071f4cdSEmilio G. Cota * of CF_PARALLEL's value, we'll trace just a read and a write. 1755507c2bfSRichard Henderson */ 1765507c2bfSRichard Henderson #define GEN_ATOMIC_HELPER_FN(X, FN, XDATA_TYPE, RET) \ 1775507c2bfSRichard Henderson ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr, \ 178*48688fafSRichard Henderson ABI_TYPE xval, TCGMemOpIdx oi, uintptr_t retaddr) \ 1795507c2bfSRichard Henderson { \ 1805507c2bfSRichard Henderson ATOMIC_MMU_DECLS; \ 18108dff435SRichard Henderson XDATA_TYPE *haddr = ATOMIC_MMU_LOOKUP_RW; \ 1825507c2bfSRichard Henderson XDATA_TYPE cmp, old, new, val = xval; \ 1834e6b1384SRichard Henderson uint16_t info = trace_mem_build_info(SHIFT, false, 0, false, \ 184cfec3885SEmilio G. Cota ATOMIC_MMU_IDX); \ 185cfec3885SEmilio G. Cota atomic_trace_rmw_pre(env, addr, info); \ 1865507c2bfSRichard Henderson smp_mb(); \ 187d73415a3SStefan Hajnoczi cmp = qatomic_read__nocheck(haddr); \ 1885507c2bfSRichard Henderson do { \ 1895507c2bfSRichard Henderson old = cmp; new = FN(old, val); \ 190d73415a3SStefan Hajnoczi cmp = qatomic_cmpxchg__nocheck(haddr, old, new); \ 1915507c2bfSRichard Henderson } while (cmp != old); \ 1925507c2bfSRichard Henderson ATOMIC_MMU_CLEANUP; \ 193cfec3885SEmilio G. Cota atomic_trace_rmw_post(env, addr, info); \ 1945507c2bfSRichard Henderson return RET; \ 1955507c2bfSRichard Henderson } 1965507c2bfSRichard Henderson 1975507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(fetch_smin, MIN, SDATA_TYPE, old) 1985507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(fetch_umin, MIN, DATA_TYPE, old) 1995507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(fetch_smax, MAX, SDATA_TYPE, old) 2005507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(fetch_umax, MAX, DATA_TYPE, old) 2015507c2bfSRichard Henderson 2025507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(smin_fetch, MIN, SDATA_TYPE, new) 2035507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(umin_fetch, MIN, DATA_TYPE, new) 2045507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(smax_fetch, MAX, SDATA_TYPE, new) 2055507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(umax_fetch, MAX, DATA_TYPE, new) 2065507c2bfSRichard Henderson 2075507c2bfSRichard Henderson #undef GEN_ATOMIC_HELPER_FN 20810f7d4d5SPhilippe Mathieu-Daudé #endif /* DATA SIZE >= 16 */ 20910f7d4d5SPhilippe Mathieu-Daudé 21010f7d4d5SPhilippe Mathieu-Daudé #undef END 21110f7d4d5SPhilippe Mathieu-Daudé 21210f7d4d5SPhilippe Mathieu-Daudé #if DATA_SIZE > 1 21310f7d4d5SPhilippe Mathieu-Daudé 21410f7d4d5SPhilippe Mathieu-Daudé /* Define reverse-host-endian atomic operations. Note that END is used 21510f7d4d5SPhilippe Mathieu-Daudé within the ATOMIC_NAME macro. */ 21610f7d4d5SPhilippe Mathieu-Daudé #ifdef HOST_WORDS_BIGENDIAN 21710f7d4d5SPhilippe Mathieu-Daudé # define END _le 21810f7d4d5SPhilippe Mathieu-Daudé #else 21910f7d4d5SPhilippe Mathieu-Daudé # define END _be 22010f7d4d5SPhilippe Mathieu-Daudé #endif 22110f7d4d5SPhilippe Mathieu-Daudé 22210f7d4d5SPhilippe Mathieu-Daudé ABI_TYPE ATOMIC_NAME(cmpxchg)(CPUArchState *env, target_ulong addr, 223*48688fafSRichard Henderson ABI_TYPE cmpv, ABI_TYPE newv, 224*48688fafSRichard Henderson TCGMemOpIdx oi, uintptr_t retaddr) 22510f7d4d5SPhilippe Mathieu-Daudé { 22634d49937SPeter Maydell ATOMIC_MMU_DECLS; 22708dff435SRichard Henderson DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP_RW; 228d071f4cdSEmilio G. Cota DATA_TYPE ret; 2294e6b1384SRichard Henderson uint16_t info = trace_mem_build_info(SHIFT, false, MO_BSWAP, false, 230cfec3885SEmilio G. Cota ATOMIC_MMU_IDX); 231d071f4cdSEmilio G. Cota 232cfec3885SEmilio G. Cota atomic_trace_rmw_pre(env, addr, info); 233e6cd4bb5SRichard Henderson #if DATA_SIZE == 16 234e6cd4bb5SRichard Henderson ret = atomic16_cmpxchg(haddr, BSWAP(cmpv), BSWAP(newv)); 235e6cd4bb5SRichard Henderson #else 236d73415a3SStefan Hajnoczi ret = qatomic_cmpxchg__nocheck(haddr, BSWAP(cmpv), BSWAP(newv)); 237e6cd4bb5SRichard Henderson #endif 238ec603b55SRichard Henderson ATOMIC_MMU_CLEANUP; 239cfec3885SEmilio G. Cota atomic_trace_rmw_post(env, addr, info); 240ec603b55SRichard Henderson return BSWAP(ret); 24110f7d4d5SPhilippe Mathieu-Daudé } 24210f7d4d5SPhilippe Mathieu-Daudé 24310f7d4d5SPhilippe Mathieu-Daudé #if DATA_SIZE >= 16 244e6cd4bb5SRichard Henderson #if HAVE_ATOMIC128 245*48688fafSRichard Henderson ABI_TYPE ATOMIC_NAME(ld)(CPUArchState *env, target_ulong addr, 246*48688fafSRichard Henderson TCGMemOpIdx oi, uintptr_t retaddr) 24710f7d4d5SPhilippe Mathieu-Daudé { 24834d49937SPeter Maydell ATOMIC_MMU_DECLS; 24908dff435SRichard Henderson DATA_TYPE val, *haddr = ATOMIC_MMU_LOOKUP_R; 2504e6b1384SRichard Henderson uint16_t info = trace_mem_build_info(SHIFT, false, MO_BSWAP, false, 251cfec3885SEmilio G. Cota ATOMIC_MMU_IDX); 252d071f4cdSEmilio G. Cota 253cfec3885SEmilio G. Cota atomic_trace_ld_pre(env, addr, info); 254e6cd4bb5SRichard Henderson val = atomic16_read(haddr); 255ec603b55SRichard Henderson ATOMIC_MMU_CLEANUP; 256cfec3885SEmilio G. Cota atomic_trace_ld_post(env, addr, info); 25710f7d4d5SPhilippe Mathieu-Daudé return BSWAP(val); 25810f7d4d5SPhilippe Mathieu-Daudé } 25910f7d4d5SPhilippe Mathieu-Daudé 260*48688fafSRichard Henderson void ATOMIC_NAME(st)(CPUArchState *env, target_ulong addr, ABI_TYPE val, 261*48688fafSRichard Henderson TCGMemOpIdx oi, uintptr_t retaddr) 26210f7d4d5SPhilippe Mathieu-Daudé { 26334d49937SPeter Maydell ATOMIC_MMU_DECLS; 26408dff435SRichard Henderson DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP_W; 2654e6b1384SRichard Henderson uint16_t info = trace_mem_build_info(SHIFT, false, MO_BSWAP, true, 266cfec3885SEmilio G. Cota ATOMIC_MMU_IDX); 267d071f4cdSEmilio G. Cota 268cfec3885SEmilio G. Cota val = BSWAP(val); 269cfec3885SEmilio G. Cota atomic_trace_st_pre(env, addr, info); 27010f7d4d5SPhilippe Mathieu-Daudé val = BSWAP(val); 271e6cd4bb5SRichard Henderson atomic16_set(haddr, val); 272ec603b55SRichard Henderson ATOMIC_MMU_CLEANUP; 273cfec3885SEmilio G. Cota atomic_trace_st_post(env, addr, info); 27410f7d4d5SPhilippe Mathieu-Daudé } 275e6cd4bb5SRichard Henderson #endif 27610f7d4d5SPhilippe Mathieu-Daudé #else 277*48688fafSRichard Henderson ABI_TYPE ATOMIC_NAME(xchg)(CPUArchState *env, target_ulong addr, ABI_TYPE val, 278*48688fafSRichard Henderson TCGMemOpIdx oi, uintptr_t retaddr) 27910f7d4d5SPhilippe Mathieu-Daudé { 28034d49937SPeter Maydell ATOMIC_MMU_DECLS; 28108dff435SRichard Henderson DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP_RW; 282d071f4cdSEmilio G. Cota ABI_TYPE ret; 2834e6b1384SRichard Henderson uint16_t info = trace_mem_build_info(SHIFT, false, MO_BSWAP, false, 284cfec3885SEmilio G. Cota ATOMIC_MMU_IDX); 285d071f4cdSEmilio G. Cota 286cfec3885SEmilio G. Cota atomic_trace_rmw_pre(env, addr, info); 287d73415a3SStefan Hajnoczi ret = qatomic_xchg__nocheck(haddr, BSWAP(val)); 288ec603b55SRichard Henderson ATOMIC_MMU_CLEANUP; 289cfec3885SEmilio G. Cota atomic_trace_rmw_post(env, addr, info); 290ec603b55SRichard Henderson return BSWAP(ret); 29110f7d4d5SPhilippe Mathieu-Daudé } 29210f7d4d5SPhilippe Mathieu-Daudé 29310f7d4d5SPhilippe Mathieu-Daudé #define GEN_ATOMIC_HELPER(X) \ 29410f7d4d5SPhilippe Mathieu-Daudé ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr, \ 295*48688fafSRichard Henderson ABI_TYPE val, TCGMemOpIdx oi, uintptr_t retaddr) \ 29610f7d4d5SPhilippe Mathieu-Daudé { \ 29734d49937SPeter Maydell ATOMIC_MMU_DECLS; \ 29808dff435SRichard Henderson DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP_RW; \ 299d071f4cdSEmilio G. Cota DATA_TYPE ret; \ 3004e6b1384SRichard Henderson uint16_t info = trace_mem_build_info(SHIFT, false, MO_BSWAP, \ 3014e6b1384SRichard Henderson false, ATOMIC_MMU_IDX); \ 302cfec3885SEmilio G. Cota atomic_trace_rmw_pre(env, addr, info); \ 303d73415a3SStefan Hajnoczi ret = qatomic_##X(haddr, BSWAP(val)); \ 304ec603b55SRichard Henderson ATOMIC_MMU_CLEANUP; \ 305cfec3885SEmilio G. Cota atomic_trace_rmw_post(env, addr, info); \ 306ec603b55SRichard Henderson return BSWAP(ret); \ 30710f7d4d5SPhilippe Mathieu-Daudé } 30810f7d4d5SPhilippe Mathieu-Daudé 30910f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(fetch_and) 31010f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(fetch_or) 31110f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(fetch_xor) 31210f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(and_fetch) 31310f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(or_fetch) 31410f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(xor_fetch) 31510f7d4d5SPhilippe Mathieu-Daudé 31610f7d4d5SPhilippe Mathieu-Daudé #undef GEN_ATOMIC_HELPER 31710f7d4d5SPhilippe Mathieu-Daudé 3185507c2bfSRichard Henderson /* These helpers are, as a whole, full barriers. Within the helper, 3195507c2bfSRichard Henderson * the leading barrier is explicit and the trailing barrier is within 3205507c2bfSRichard Henderson * cmpxchg primitive. 321d071f4cdSEmilio G. Cota * 322d071f4cdSEmilio G. Cota * Trace this load + RMW loop as a single RMW op. This way, regardless 323d071f4cdSEmilio G. Cota * of CF_PARALLEL's value, we'll trace just a read and a write. 3245507c2bfSRichard Henderson */ 3255507c2bfSRichard Henderson #define GEN_ATOMIC_HELPER_FN(X, FN, XDATA_TYPE, RET) \ 3265507c2bfSRichard Henderson ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr, \ 327*48688fafSRichard Henderson ABI_TYPE xval, TCGMemOpIdx oi, uintptr_t retaddr) \ 3285507c2bfSRichard Henderson { \ 3295507c2bfSRichard Henderson ATOMIC_MMU_DECLS; \ 33008dff435SRichard Henderson XDATA_TYPE *haddr = ATOMIC_MMU_LOOKUP_RW; \ 3315507c2bfSRichard Henderson XDATA_TYPE ldo, ldn, old, new, val = xval; \ 3324e6b1384SRichard Henderson uint16_t info = trace_mem_build_info(SHIFT, false, MO_BSWAP, \ 3334e6b1384SRichard Henderson false, ATOMIC_MMU_IDX); \ 334cfec3885SEmilio G. Cota atomic_trace_rmw_pre(env, addr, info); \ 3355507c2bfSRichard Henderson smp_mb(); \ 336d73415a3SStefan Hajnoczi ldn = qatomic_read__nocheck(haddr); \ 3375507c2bfSRichard Henderson do { \ 3385507c2bfSRichard Henderson ldo = ldn; old = BSWAP(ldo); new = FN(old, val); \ 339d73415a3SStefan Hajnoczi ldn = qatomic_cmpxchg__nocheck(haddr, ldo, BSWAP(new)); \ 3405507c2bfSRichard Henderson } while (ldo != ldn); \ 3415507c2bfSRichard Henderson ATOMIC_MMU_CLEANUP; \ 342cfec3885SEmilio G. Cota atomic_trace_rmw_post(env, addr, info); \ 3435507c2bfSRichard Henderson return RET; \ 3445507c2bfSRichard Henderson } 3455507c2bfSRichard Henderson 3465507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(fetch_smin, MIN, SDATA_TYPE, old) 3475507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(fetch_umin, MIN, DATA_TYPE, old) 3485507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(fetch_smax, MAX, SDATA_TYPE, old) 3495507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(fetch_umax, MAX, DATA_TYPE, old) 3505507c2bfSRichard Henderson 3515507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(smin_fetch, MIN, SDATA_TYPE, new) 3525507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(umin_fetch, MIN, DATA_TYPE, new) 3535507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(smax_fetch, MAX, SDATA_TYPE, new) 3545507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(umax_fetch, MAX, DATA_TYPE, new) 3555507c2bfSRichard Henderson 35658edf9eeSRichard Henderson /* Note that for addition, we need to use a separate cmpxchg loop instead 35758edf9eeSRichard Henderson of bswaps for the reverse-host-endian helpers. */ 35858edf9eeSRichard Henderson #define ADD(X, Y) (X + Y) 35958edf9eeSRichard Henderson GEN_ATOMIC_HELPER_FN(fetch_add, ADD, DATA_TYPE, old) 36058edf9eeSRichard Henderson GEN_ATOMIC_HELPER_FN(add_fetch, ADD, DATA_TYPE, new) 36158edf9eeSRichard Henderson #undef ADD 36258edf9eeSRichard Henderson 3635507c2bfSRichard Henderson #undef GEN_ATOMIC_HELPER_FN 36410f7d4d5SPhilippe Mathieu-Daudé #endif /* DATA_SIZE >= 16 */ 36510f7d4d5SPhilippe Mathieu-Daudé 36610f7d4d5SPhilippe Mathieu-Daudé #undef END 36710f7d4d5SPhilippe Mathieu-Daudé #endif /* DATA_SIZE > 1 */ 36810f7d4d5SPhilippe Mathieu-Daudé 36910f7d4d5SPhilippe Mathieu-Daudé #undef BSWAP 37010f7d4d5SPhilippe Mathieu-Daudé #undef ABI_TYPE 37110f7d4d5SPhilippe Mathieu-Daudé #undef DATA_TYPE 3725507c2bfSRichard Henderson #undef SDATA_TYPE 37310f7d4d5SPhilippe Mathieu-Daudé #undef SUFFIX 37410f7d4d5SPhilippe Mathieu-Daudé #undef DATA_SIZE 375d071f4cdSEmilio G. Cota #undef SHIFT 376