1c482cb11SRichard Henderson /* 2c482cb11SRichard Henderson * Atomic helper templates 3c482cb11SRichard Henderson * Included from tcg-runtime.c and cputlb.c. 4c482cb11SRichard Henderson * 5c482cb11SRichard Henderson * Copyright (c) 2016 Red Hat, Inc 6c482cb11SRichard Henderson * 7c482cb11SRichard Henderson * This library is free software; you can redistribute it and/or 8c482cb11SRichard Henderson * modify it under the terms of the GNU Lesser General Public 9c482cb11SRichard Henderson * License as published by the Free Software Foundation; either 10c482cb11SRichard Henderson * version 2 of the License, or (at your option) any later version. 11c482cb11SRichard Henderson * 12c482cb11SRichard Henderson * This library is distributed in the hope that it will be useful, 13c482cb11SRichard Henderson * but WITHOUT ANY WARRANTY; without even the implied warranty of 14c482cb11SRichard Henderson * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15c482cb11SRichard Henderson * Lesser General Public License for more details. 16c482cb11SRichard Henderson * 17c482cb11SRichard Henderson * You should have received a copy of the GNU Lesser General Public 18c482cb11SRichard Henderson * License along with this library; if not, see <http://www.gnu.org/licenses/>. 19c482cb11SRichard Henderson */ 20c482cb11SRichard Henderson 217ebee43eSRichard Henderson #if DATA_SIZE == 16 227ebee43eSRichard Henderson # define SUFFIX o 237ebee43eSRichard Henderson # define DATA_TYPE Int128 247ebee43eSRichard Henderson # define BSWAP bswap128 257ebee43eSRichard Henderson #elif DATA_SIZE == 8 26c482cb11SRichard Henderson # define SUFFIX q 27c482cb11SRichard Henderson # define DATA_TYPE uint64_t 28*5507c2bfSRichard Henderson # define SDATA_TYPE int64_t 29c482cb11SRichard Henderson # define BSWAP bswap64 30c482cb11SRichard Henderson #elif DATA_SIZE == 4 31c482cb11SRichard Henderson # define SUFFIX l 32c482cb11SRichard Henderson # define DATA_TYPE uint32_t 33*5507c2bfSRichard Henderson # define SDATA_TYPE int32_t 34c482cb11SRichard Henderson # define BSWAP bswap32 35c482cb11SRichard Henderson #elif DATA_SIZE == 2 36c482cb11SRichard Henderson # define SUFFIX w 37c482cb11SRichard Henderson # define DATA_TYPE uint16_t 38*5507c2bfSRichard Henderson # define SDATA_TYPE int16_t 39c482cb11SRichard Henderson # define BSWAP bswap16 40c482cb11SRichard Henderson #elif DATA_SIZE == 1 41c482cb11SRichard Henderson # define SUFFIX b 42c482cb11SRichard Henderson # define DATA_TYPE uint8_t 43*5507c2bfSRichard Henderson # define SDATA_TYPE int8_t 44c482cb11SRichard Henderson # define BSWAP 45c482cb11SRichard Henderson #else 46c482cb11SRichard Henderson # error unsupported data size 47c482cb11SRichard Henderson #endif 48c482cb11SRichard Henderson 49c482cb11SRichard Henderson #if DATA_SIZE >= 4 50c482cb11SRichard Henderson # define ABI_TYPE DATA_TYPE 51c482cb11SRichard Henderson #else 52c482cb11SRichard Henderson # define ABI_TYPE uint32_t 53c482cb11SRichard Henderson #endif 54c482cb11SRichard Henderson 55c482cb11SRichard Henderson /* Define host-endian atomic operations. Note that END is used within 56c482cb11SRichard Henderson the ATOMIC_NAME macro, and redefined below. */ 57c482cb11SRichard Henderson #if DATA_SIZE == 1 58c482cb11SRichard Henderson # define END 59c482cb11SRichard Henderson #elif defined(HOST_WORDS_BIGENDIAN) 60c482cb11SRichard Henderson # define END _be 61c482cb11SRichard Henderson #else 62c482cb11SRichard Henderson # define END _le 63c482cb11SRichard Henderson #endif 64c482cb11SRichard Henderson 65c482cb11SRichard Henderson ABI_TYPE ATOMIC_NAME(cmpxchg)(CPUArchState *env, target_ulong addr, 66c482cb11SRichard Henderson ABI_TYPE cmpv, ABI_TYPE newv EXTRA_ARGS) 67c482cb11SRichard Henderson { 6834d49937SPeter Maydell ATOMIC_MMU_DECLS; 69c482cb11SRichard Henderson DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP; 70ec603b55SRichard Henderson DATA_TYPE ret = atomic_cmpxchg__nocheck(haddr, cmpv, newv); 71ec603b55SRichard Henderson ATOMIC_MMU_CLEANUP; 72ec603b55SRichard Henderson return ret; 73c482cb11SRichard Henderson } 74c482cb11SRichard Henderson 757ebee43eSRichard Henderson #if DATA_SIZE >= 16 767ebee43eSRichard Henderson ABI_TYPE ATOMIC_NAME(ld)(CPUArchState *env, target_ulong addr EXTRA_ARGS) 777ebee43eSRichard Henderson { 7834d49937SPeter Maydell ATOMIC_MMU_DECLS; 797ebee43eSRichard Henderson DATA_TYPE val, *haddr = ATOMIC_MMU_LOOKUP; 807ebee43eSRichard Henderson __atomic_load(haddr, &val, __ATOMIC_RELAXED); 81ec603b55SRichard Henderson ATOMIC_MMU_CLEANUP; 827ebee43eSRichard Henderson return val; 837ebee43eSRichard Henderson } 847ebee43eSRichard Henderson 857ebee43eSRichard Henderson void ATOMIC_NAME(st)(CPUArchState *env, target_ulong addr, 867ebee43eSRichard Henderson ABI_TYPE val EXTRA_ARGS) 877ebee43eSRichard Henderson { 8834d49937SPeter Maydell ATOMIC_MMU_DECLS; 897ebee43eSRichard Henderson DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP; 907ebee43eSRichard Henderson __atomic_store(haddr, &val, __ATOMIC_RELAXED); 91ec603b55SRichard Henderson ATOMIC_MMU_CLEANUP; 927ebee43eSRichard Henderson } 937ebee43eSRichard Henderson #else 94c482cb11SRichard Henderson ABI_TYPE ATOMIC_NAME(xchg)(CPUArchState *env, target_ulong addr, 95c482cb11SRichard Henderson ABI_TYPE val EXTRA_ARGS) 96c482cb11SRichard Henderson { 9734d49937SPeter Maydell ATOMIC_MMU_DECLS; 98c482cb11SRichard Henderson DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP; 99ec603b55SRichard Henderson DATA_TYPE ret = atomic_xchg__nocheck(haddr, val); 100ec603b55SRichard Henderson ATOMIC_MMU_CLEANUP; 101ec603b55SRichard Henderson return ret; 102c482cb11SRichard Henderson } 103c482cb11SRichard Henderson 104c482cb11SRichard Henderson #define GEN_ATOMIC_HELPER(X) \ 105c482cb11SRichard Henderson ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr, \ 106c482cb11SRichard Henderson ABI_TYPE val EXTRA_ARGS) \ 107c482cb11SRichard Henderson { \ 10834d49937SPeter Maydell ATOMIC_MMU_DECLS; \ 109c482cb11SRichard Henderson DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP; \ 110ec603b55SRichard Henderson DATA_TYPE ret = atomic_##X(haddr, val); \ 111ec603b55SRichard Henderson ATOMIC_MMU_CLEANUP; \ 112ec603b55SRichard Henderson return ret; \ 113ec603b55SRichard Henderson } 114c482cb11SRichard Henderson 115c482cb11SRichard Henderson GEN_ATOMIC_HELPER(fetch_add) 116c482cb11SRichard Henderson GEN_ATOMIC_HELPER(fetch_and) 117c482cb11SRichard Henderson GEN_ATOMIC_HELPER(fetch_or) 118c482cb11SRichard Henderson GEN_ATOMIC_HELPER(fetch_xor) 119c482cb11SRichard Henderson GEN_ATOMIC_HELPER(add_fetch) 120c482cb11SRichard Henderson GEN_ATOMIC_HELPER(and_fetch) 121c482cb11SRichard Henderson GEN_ATOMIC_HELPER(or_fetch) 122c482cb11SRichard Henderson GEN_ATOMIC_HELPER(xor_fetch) 123c482cb11SRichard Henderson 124c482cb11SRichard Henderson #undef GEN_ATOMIC_HELPER 125*5507c2bfSRichard Henderson 126*5507c2bfSRichard Henderson /* These helpers are, as a whole, full barriers. Within the helper, 127*5507c2bfSRichard Henderson * the leading barrier is explicit and the trailing barrier is within 128*5507c2bfSRichard Henderson * cmpxchg primitive. 129*5507c2bfSRichard Henderson */ 130*5507c2bfSRichard Henderson #define GEN_ATOMIC_HELPER_FN(X, FN, XDATA_TYPE, RET) \ 131*5507c2bfSRichard Henderson ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr, \ 132*5507c2bfSRichard Henderson ABI_TYPE xval EXTRA_ARGS) \ 133*5507c2bfSRichard Henderson { \ 134*5507c2bfSRichard Henderson ATOMIC_MMU_DECLS; \ 135*5507c2bfSRichard Henderson XDATA_TYPE *haddr = ATOMIC_MMU_LOOKUP; \ 136*5507c2bfSRichard Henderson XDATA_TYPE cmp, old, new, val = xval; \ 137*5507c2bfSRichard Henderson smp_mb(); \ 138*5507c2bfSRichard Henderson cmp = atomic_read__nocheck(haddr); \ 139*5507c2bfSRichard Henderson do { \ 140*5507c2bfSRichard Henderson old = cmp; new = FN(old, val); \ 141*5507c2bfSRichard Henderson cmp = atomic_cmpxchg__nocheck(haddr, old, new); \ 142*5507c2bfSRichard Henderson } while (cmp != old); \ 143*5507c2bfSRichard Henderson ATOMIC_MMU_CLEANUP; \ 144*5507c2bfSRichard Henderson return RET; \ 145*5507c2bfSRichard Henderson } 146*5507c2bfSRichard Henderson 147*5507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(fetch_smin, MIN, SDATA_TYPE, old) 148*5507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(fetch_umin, MIN, DATA_TYPE, old) 149*5507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(fetch_smax, MAX, SDATA_TYPE, old) 150*5507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(fetch_umax, MAX, DATA_TYPE, old) 151*5507c2bfSRichard Henderson 152*5507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(smin_fetch, MIN, SDATA_TYPE, new) 153*5507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(umin_fetch, MIN, DATA_TYPE, new) 154*5507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(smax_fetch, MAX, SDATA_TYPE, new) 155*5507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(umax_fetch, MAX, DATA_TYPE, new) 156*5507c2bfSRichard Henderson 157*5507c2bfSRichard Henderson #undef GEN_ATOMIC_HELPER_FN 1587ebee43eSRichard Henderson #endif /* DATA SIZE >= 16 */ 1597ebee43eSRichard Henderson 160c482cb11SRichard Henderson #undef END 161c482cb11SRichard Henderson 162c482cb11SRichard Henderson #if DATA_SIZE > 1 163c482cb11SRichard Henderson 164c482cb11SRichard Henderson /* Define reverse-host-endian atomic operations. Note that END is used 165c482cb11SRichard Henderson within the ATOMIC_NAME macro. */ 166c482cb11SRichard Henderson #ifdef HOST_WORDS_BIGENDIAN 167c482cb11SRichard Henderson # define END _le 168c482cb11SRichard Henderson #else 169c482cb11SRichard Henderson # define END _be 170c482cb11SRichard Henderson #endif 171c482cb11SRichard Henderson 172c482cb11SRichard Henderson ABI_TYPE ATOMIC_NAME(cmpxchg)(CPUArchState *env, target_ulong addr, 173c482cb11SRichard Henderson ABI_TYPE cmpv, ABI_TYPE newv EXTRA_ARGS) 174c482cb11SRichard Henderson { 17534d49937SPeter Maydell ATOMIC_MMU_DECLS; 176c482cb11SRichard Henderson DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP; 177ec603b55SRichard Henderson DATA_TYPE ret = atomic_cmpxchg__nocheck(haddr, BSWAP(cmpv), BSWAP(newv)); 178ec603b55SRichard Henderson ATOMIC_MMU_CLEANUP; 179ec603b55SRichard Henderson return BSWAP(ret); 180c482cb11SRichard Henderson } 181c482cb11SRichard Henderson 1827ebee43eSRichard Henderson #if DATA_SIZE >= 16 1837ebee43eSRichard Henderson ABI_TYPE ATOMIC_NAME(ld)(CPUArchState *env, target_ulong addr EXTRA_ARGS) 1847ebee43eSRichard Henderson { 18534d49937SPeter Maydell ATOMIC_MMU_DECLS; 1867ebee43eSRichard Henderson DATA_TYPE val, *haddr = ATOMIC_MMU_LOOKUP; 1877ebee43eSRichard Henderson __atomic_load(haddr, &val, __ATOMIC_RELAXED); 188ec603b55SRichard Henderson ATOMIC_MMU_CLEANUP; 1897ebee43eSRichard Henderson return BSWAP(val); 1907ebee43eSRichard Henderson } 1917ebee43eSRichard Henderson 1927ebee43eSRichard Henderson void ATOMIC_NAME(st)(CPUArchState *env, target_ulong addr, 1937ebee43eSRichard Henderson ABI_TYPE val EXTRA_ARGS) 1947ebee43eSRichard Henderson { 19534d49937SPeter Maydell ATOMIC_MMU_DECLS; 1967ebee43eSRichard Henderson DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP; 1977ebee43eSRichard Henderson val = BSWAP(val); 1987ebee43eSRichard Henderson __atomic_store(haddr, &val, __ATOMIC_RELAXED); 199ec603b55SRichard Henderson ATOMIC_MMU_CLEANUP; 2007ebee43eSRichard Henderson } 2017ebee43eSRichard Henderson #else 202c482cb11SRichard Henderson ABI_TYPE ATOMIC_NAME(xchg)(CPUArchState *env, target_ulong addr, 203c482cb11SRichard Henderson ABI_TYPE val EXTRA_ARGS) 204c482cb11SRichard Henderson { 20534d49937SPeter Maydell ATOMIC_MMU_DECLS; 206c482cb11SRichard Henderson DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP; 207ec603b55SRichard Henderson ABI_TYPE ret = atomic_xchg__nocheck(haddr, BSWAP(val)); 208ec603b55SRichard Henderson ATOMIC_MMU_CLEANUP; 209ec603b55SRichard Henderson return BSWAP(ret); 210c482cb11SRichard Henderson } 211c482cb11SRichard Henderson 212c482cb11SRichard Henderson #define GEN_ATOMIC_HELPER(X) \ 213c482cb11SRichard Henderson ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr, \ 214c482cb11SRichard Henderson ABI_TYPE val EXTRA_ARGS) \ 215c482cb11SRichard Henderson { \ 21634d49937SPeter Maydell ATOMIC_MMU_DECLS; \ 217c482cb11SRichard Henderson DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP; \ 218ec603b55SRichard Henderson DATA_TYPE ret = atomic_##X(haddr, BSWAP(val)); \ 219ec603b55SRichard Henderson ATOMIC_MMU_CLEANUP; \ 220ec603b55SRichard Henderson return BSWAP(ret); \ 221c482cb11SRichard Henderson } 222c482cb11SRichard Henderson 223c482cb11SRichard Henderson GEN_ATOMIC_HELPER(fetch_and) 224c482cb11SRichard Henderson GEN_ATOMIC_HELPER(fetch_or) 225c482cb11SRichard Henderson GEN_ATOMIC_HELPER(fetch_xor) 226c482cb11SRichard Henderson GEN_ATOMIC_HELPER(and_fetch) 227c482cb11SRichard Henderson GEN_ATOMIC_HELPER(or_fetch) 228c482cb11SRichard Henderson GEN_ATOMIC_HELPER(xor_fetch) 229c482cb11SRichard Henderson 230c482cb11SRichard Henderson #undef GEN_ATOMIC_HELPER 231c482cb11SRichard Henderson 232c482cb11SRichard Henderson /* Note that for addition, we need to use a separate cmpxchg loop instead 233c482cb11SRichard Henderson of bswaps for the reverse-host-endian helpers. */ 234c482cb11SRichard Henderson ABI_TYPE ATOMIC_NAME(fetch_add)(CPUArchState *env, target_ulong addr, 235c482cb11SRichard Henderson ABI_TYPE val EXTRA_ARGS) 236c482cb11SRichard Henderson { 23734d49937SPeter Maydell ATOMIC_MMU_DECLS; 238c482cb11SRichard Henderson DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP; 239c482cb11SRichard Henderson DATA_TYPE ldo, ldn, ret, sto; 240c482cb11SRichard Henderson 241c482cb11SRichard Henderson ldo = atomic_read__nocheck(haddr); 242c482cb11SRichard Henderson while (1) { 243c482cb11SRichard Henderson ret = BSWAP(ldo); 244c482cb11SRichard Henderson sto = BSWAP(ret + val); 245c482cb11SRichard Henderson ldn = atomic_cmpxchg__nocheck(haddr, ldo, sto); 246c482cb11SRichard Henderson if (ldn == ldo) { 247ec603b55SRichard Henderson ATOMIC_MMU_CLEANUP; 248c482cb11SRichard Henderson return ret; 249c482cb11SRichard Henderson } 250c482cb11SRichard Henderson ldo = ldn; 251c482cb11SRichard Henderson } 252c482cb11SRichard Henderson } 253c482cb11SRichard Henderson 254c482cb11SRichard Henderson ABI_TYPE ATOMIC_NAME(add_fetch)(CPUArchState *env, target_ulong addr, 255c482cb11SRichard Henderson ABI_TYPE val EXTRA_ARGS) 256c482cb11SRichard Henderson { 25734d49937SPeter Maydell ATOMIC_MMU_DECLS; 258c482cb11SRichard Henderson DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP; 259c482cb11SRichard Henderson DATA_TYPE ldo, ldn, ret, sto; 260c482cb11SRichard Henderson 261c482cb11SRichard Henderson ldo = atomic_read__nocheck(haddr); 262c482cb11SRichard Henderson while (1) { 263c482cb11SRichard Henderson ret = BSWAP(ldo) + val; 264c482cb11SRichard Henderson sto = BSWAP(ret); 265c482cb11SRichard Henderson ldn = atomic_cmpxchg__nocheck(haddr, ldo, sto); 266c482cb11SRichard Henderson if (ldn == ldo) { 267ec603b55SRichard Henderson ATOMIC_MMU_CLEANUP; 268c482cb11SRichard Henderson return ret; 269c482cb11SRichard Henderson } 270c482cb11SRichard Henderson ldo = ldn; 271c482cb11SRichard Henderson } 272c482cb11SRichard Henderson } 273*5507c2bfSRichard Henderson 274*5507c2bfSRichard Henderson /* These helpers are, as a whole, full barriers. Within the helper, 275*5507c2bfSRichard Henderson * the leading barrier is explicit and the trailing barrier is within 276*5507c2bfSRichard Henderson * cmpxchg primitive. 277*5507c2bfSRichard Henderson */ 278*5507c2bfSRichard Henderson #define GEN_ATOMIC_HELPER_FN(X, FN, XDATA_TYPE, RET) \ 279*5507c2bfSRichard Henderson ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr, \ 280*5507c2bfSRichard Henderson ABI_TYPE xval EXTRA_ARGS) \ 281*5507c2bfSRichard Henderson { \ 282*5507c2bfSRichard Henderson ATOMIC_MMU_DECLS; \ 283*5507c2bfSRichard Henderson XDATA_TYPE *haddr = ATOMIC_MMU_LOOKUP; \ 284*5507c2bfSRichard Henderson XDATA_TYPE ldo, ldn, old, new, val = xval; \ 285*5507c2bfSRichard Henderson smp_mb(); \ 286*5507c2bfSRichard Henderson ldn = atomic_read__nocheck(haddr); \ 287*5507c2bfSRichard Henderson do { \ 288*5507c2bfSRichard Henderson ldo = ldn; old = BSWAP(ldo); new = FN(old, val); \ 289*5507c2bfSRichard Henderson ldn = atomic_cmpxchg__nocheck(haddr, ldo, BSWAP(new)); \ 290*5507c2bfSRichard Henderson } while (ldo != ldn); \ 291*5507c2bfSRichard Henderson ATOMIC_MMU_CLEANUP; \ 292*5507c2bfSRichard Henderson return RET; \ 293*5507c2bfSRichard Henderson } 294*5507c2bfSRichard Henderson 295*5507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(fetch_smin, MIN, SDATA_TYPE, old) 296*5507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(fetch_umin, MIN, DATA_TYPE, old) 297*5507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(fetch_smax, MAX, SDATA_TYPE, old) 298*5507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(fetch_umax, MAX, DATA_TYPE, old) 299*5507c2bfSRichard Henderson 300*5507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(smin_fetch, MIN, SDATA_TYPE, new) 301*5507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(umin_fetch, MIN, DATA_TYPE, new) 302*5507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(smax_fetch, MAX, SDATA_TYPE, new) 303*5507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(umax_fetch, MAX, DATA_TYPE, new) 304*5507c2bfSRichard Henderson 305*5507c2bfSRichard Henderson #undef GEN_ATOMIC_HELPER_FN 3067ebee43eSRichard Henderson #endif /* DATA_SIZE >= 16 */ 307c482cb11SRichard Henderson 308c482cb11SRichard Henderson #undef END 309c482cb11SRichard Henderson #endif /* DATA_SIZE > 1 */ 310c482cb11SRichard Henderson 311c482cb11SRichard Henderson #undef BSWAP 312c482cb11SRichard Henderson #undef ABI_TYPE 313c482cb11SRichard Henderson #undef DATA_TYPE 314*5507c2bfSRichard Henderson #undef SDATA_TYPE 315c482cb11SRichard Henderson #undef SUFFIX 316c482cb11SRichard Henderson #undef DATA_SIZE 317