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 28c482cb11SRichard Henderson # define BSWAP bswap64 29c482cb11SRichard Henderson #elif DATA_SIZE == 4 30c482cb11SRichard Henderson # define SUFFIX l 31c482cb11SRichard Henderson # define DATA_TYPE uint32_t 32c482cb11SRichard Henderson # define BSWAP bswap32 33c482cb11SRichard Henderson #elif DATA_SIZE == 2 34c482cb11SRichard Henderson # define SUFFIX w 35c482cb11SRichard Henderson # define DATA_TYPE uint16_t 36c482cb11SRichard Henderson # define BSWAP bswap16 37c482cb11SRichard Henderson #elif DATA_SIZE == 1 38c482cb11SRichard Henderson # define SUFFIX b 39c482cb11SRichard Henderson # define DATA_TYPE uint8_t 40c482cb11SRichard Henderson # define BSWAP 41c482cb11SRichard Henderson #else 42c482cb11SRichard Henderson # error unsupported data size 43c482cb11SRichard Henderson #endif 44c482cb11SRichard Henderson 45c482cb11SRichard Henderson #if DATA_SIZE >= 4 46c482cb11SRichard Henderson # define ABI_TYPE DATA_TYPE 47c482cb11SRichard Henderson #else 48c482cb11SRichard Henderson # define ABI_TYPE uint32_t 49c482cb11SRichard Henderson #endif 50c482cb11SRichard Henderson 51c482cb11SRichard Henderson /* Define host-endian atomic operations. Note that END is used within 52c482cb11SRichard Henderson the ATOMIC_NAME macro, and redefined below. */ 53c482cb11SRichard Henderson #if DATA_SIZE == 1 54c482cb11SRichard Henderson # define END 55c482cb11SRichard Henderson #elif defined(HOST_WORDS_BIGENDIAN) 56c482cb11SRichard Henderson # define END _be 57c482cb11SRichard Henderson #else 58c482cb11SRichard Henderson # define END _le 59c482cb11SRichard Henderson #endif 60c482cb11SRichard Henderson 61c482cb11SRichard Henderson ABI_TYPE ATOMIC_NAME(cmpxchg)(CPUArchState *env, target_ulong addr, 62c482cb11SRichard Henderson ABI_TYPE cmpv, ABI_TYPE newv EXTRA_ARGS) 63c482cb11SRichard Henderson { 64c482cb11SRichard Henderson DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP; 65*ec603b55SRichard Henderson DATA_TYPE ret = atomic_cmpxchg__nocheck(haddr, cmpv, newv); 66*ec603b55SRichard Henderson ATOMIC_MMU_CLEANUP; 67*ec603b55SRichard Henderson return ret; 68c482cb11SRichard Henderson } 69c482cb11SRichard Henderson 707ebee43eSRichard Henderson #if DATA_SIZE >= 16 717ebee43eSRichard Henderson ABI_TYPE ATOMIC_NAME(ld)(CPUArchState *env, target_ulong addr EXTRA_ARGS) 727ebee43eSRichard Henderson { 737ebee43eSRichard Henderson DATA_TYPE val, *haddr = ATOMIC_MMU_LOOKUP; 747ebee43eSRichard Henderson __atomic_load(haddr, &val, __ATOMIC_RELAXED); 75*ec603b55SRichard Henderson ATOMIC_MMU_CLEANUP; 767ebee43eSRichard Henderson return val; 777ebee43eSRichard Henderson } 787ebee43eSRichard Henderson 797ebee43eSRichard Henderson void ATOMIC_NAME(st)(CPUArchState *env, target_ulong addr, 807ebee43eSRichard Henderson ABI_TYPE val EXTRA_ARGS) 817ebee43eSRichard Henderson { 827ebee43eSRichard Henderson DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP; 837ebee43eSRichard Henderson __atomic_store(haddr, &val, __ATOMIC_RELAXED); 84*ec603b55SRichard Henderson ATOMIC_MMU_CLEANUP; 857ebee43eSRichard Henderson } 867ebee43eSRichard Henderson #else 87c482cb11SRichard Henderson ABI_TYPE ATOMIC_NAME(xchg)(CPUArchState *env, target_ulong addr, 88c482cb11SRichard Henderson ABI_TYPE val EXTRA_ARGS) 89c482cb11SRichard Henderson { 90c482cb11SRichard Henderson DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP; 91*ec603b55SRichard Henderson DATA_TYPE ret = atomic_xchg__nocheck(haddr, val); 92*ec603b55SRichard Henderson ATOMIC_MMU_CLEANUP; 93*ec603b55SRichard Henderson return ret; 94c482cb11SRichard Henderson } 95c482cb11SRichard Henderson 96c482cb11SRichard Henderson #define GEN_ATOMIC_HELPER(X) \ 97c482cb11SRichard Henderson ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr, \ 98c482cb11SRichard Henderson ABI_TYPE val EXTRA_ARGS) \ 99c482cb11SRichard Henderson { \ 100c482cb11SRichard Henderson DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP; \ 101*ec603b55SRichard Henderson DATA_TYPE ret = atomic_##X(haddr, val); \ 102*ec603b55SRichard Henderson ATOMIC_MMU_CLEANUP; \ 103*ec603b55SRichard Henderson return ret; \ 104*ec603b55SRichard Henderson } 105c482cb11SRichard Henderson 106c482cb11SRichard Henderson GEN_ATOMIC_HELPER(fetch_add) 107c482cb11SRichard Henderson GEN_ATOMIC_HELPER(fetch_and) 108c482cb11SRichard Henderson GEN_ATOMIC_HELPER(fetch_or) 109c482cb11SRichard Henderson GEN_ATOMIC_HELPER(fetch_xor) 110c482cb11SRichard Henderson GEN_ATOMIC_HELPER(add_fetch) 111c482cb11SRichard Henderson GEN_ATOMIC_HELPER(and_fetch) 112c482cb11SRichard Henderson GEN_ATOMIC_HELPER(or_fetch) 113c482cb11SRichard Henderson GEN_ATOMIC_HELPER(xor_fetch) 114c482cb11SRichard Henderson 115c482cb11SRichard Henderson #undef GEN_ATOMIC_HELPER 1167ebee43eSRichard Henderson #endif /* DATA SIZE >= 16 */ 1177ebee43eSRichard Henderson 118c482cb11SRichard Henderson #undef END 119c482cb11SRichard Henderson 120c482cb11SRichard Henderson #if DATA_SIZE > 1 121c482cb11SRichard Henderson 122c482cb11SRichard Henderson /* Define reverse-host-endian atomic operations. Note that END is used 123c482cb11SRichard Henderson within the ATOMIC_NAME macro. */ 124c482cb11SRichard Henderson #ifdef HOST_WORDS_BIGENDIAN 125c482cb11SRichard Henderson # define END _le 126c482cb11SRichard Henderson #else 127c482cb11SRichard Henderson # define END _be 128c482cb11SRichard Henderson #endif 129c482cb11SRichard Henderson 130c482cb11SRichard Henderson ABI_TYPE ATOMIC_NAME(cmpxchg)(CPUArchState *env, target_ulong addr, 131c482cb11SRichard Henderson ABI_TYPE cmpv, ABI_TYPE newv EXTRA_ARGS) 132c482cb11SRichard Henderson { 133c482cb11SRichard Henderson DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP; 134*ec603b55SRichard Henderson DATA_TYPE ret = atomic_cmpxchg__nocheck(haddr, BSWAP(cmpv), BSWAP(newv)); 135*ec603b55SRichard Henderson ATOMIC_MMU_CLEANUP; 136*ec603b55SRichard Henderson return BSWAP(ret); 137c482cb11SRichard Henderson } 138c482cb11SRichard Henderson 1397ebee43eSRichard Henderson #if DATA_SIZE >= 16 1407ebee43eSRichard Henderson ABI_TYPE ATOMIC_NAME(ld)(CPUArchState *env, target_ulong addr EXTRA_ARGS) 1417ebee43eSRichard Henderson { 1427ebee43eSRichard Henderson DATA_TYPE val, *haddr = ATOMIC_MMU_LOOKUP; 1437ebee43eSRichard Henderson __atomic_load(haddr, &val, __ATOMIC_RELAXED); 144*ec603b55SRichard Henderson ATOMIC_MMU_CLEANUP; 1457ebee43eSRichard Henderson return BSWAP(val); 1467ebee43eSRichard Henderson } 1477ebee43eSRichard Henderson 1487ebee43eSRichard Henderson void ATOMIC_NAME(st)(CPUArchState *env, target_ulong addr, 1497ebee43eSRichard Henderson ABI_TYPE val EXTRA_ARGS) 1507ebee43eSRichard Henderson { 1517ebee43eSRichard Henderson DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP; 1527ebee43eSRichard Henderson val = BSWAP(val); 1537ebee43eSRichard Henderson __atomic_store(haddr, &val, __ATOMIC_RELAXED); 154*ec603b55SRichard Henderson ATOMIC_MMU_CLEANUP; 1557ebee43eSRichard Henderson } 1567ebee43eSRichard Henderson #else 157c482cb11SRichard Henderson ABI_TYPE ATOMIC_NAME(xchg)(CPUArchState *env, target_ulong addr, 158c482cb11SRichard Henderson ABI_TYPE val EXTRA_ARGS) 159c482cb11SRichard Henderson { 160c482cb11SRichard Henderson DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP; 161*ec603b55SRichard Henderson ABI_TYPE ret = atomic_xchg__nocheck(haddr, BSWAP(val)); 162*ec603b55SRichard Henderson ATOMIC_MMU_CLEANUP; 163*ec603b55SRichard Henderson return BSWAP(ret); 164c482cb11SRichard Henderson } 165c482cb11SRichard Henderson 166c482cb11SRichard Henderson #define GEN_ATOMIC_HELPER(X) \ 167c482cb11SRichard Henderson ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr, \ 168c482cb11SRichard Henderson ABI_TYPE val EXTRA_ARGS) \ 169c482cb11SRichard Henderson { \ 170c482cb11SRichard Henderson DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP; \ 171*ec603b55SRichard Henderson DATA_TYPE ret = atomic_##X(haddr, BSWAP(val)); \ 172*ec603b55SRichard Henderson ATOMIC_MMU_CLEANUP; \ 173*ec603b55SRichard Henderson return BSWAP(ret); \ 174c482cb11SRichard Henderson } 175c482cb11SRichard Henderson 176c482cb11SRichard Henderson GEN_ATOMIC_HELPER(fetch_and) 177c482cb11SRichard Henderson GEN_ATOMIC_HELPER(fetch_or) 178c482cb11SRichard Henderson GEN_ATOMIC_HELPER(fetch_xor) 179c482cb11SRichard Henderson GEN_ATOMIC_HELPER(and_fetch) 180c482cb11SRichard Henderson GEN_ATOMIC_HELPER(or_fetch) 181c482cb11SRichard Henderson GEN_ATOMIC_HELPER(xor_fetch) 182c482cb11SRichard Henderson 183c482cb11SRichard Henderson #undef GEN_ATOMIC_HELPER 184c482cb11SRichard Henderson 185c482cb11SRichard Henderson /* Note that for addition, we need to use a separate cmpxchg loop instead 186c482cb11SRichard Henderson of bswaps for the reverse-host-endian helpers. */ 187c482cb11SRichard Henderson ABI_TYPE ATOMIC_NAME(fetch_add)(CPUArchState *env, target_ulong addr, 188c482cb11SRichard Henderson ABI_TYPE val EXTRA_ARGS) 189c482cb11SRichard Henderson { 190c482cb11SRichard Henderson DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP; 191c482cb11SRichard Henderson DATA_TYPE ldo, ldn, ret, sto; 192c482cb11SRichard Henderson 193c482cb11SRichard Henderson ldo = atomic_read__nocheck(haddr); 194c482cb11SRichard Henderson while (1) { 195c482cb11SRichard Henderson ret = BSWAP(ldo); 196c482cb11SRichard Henderson sto = BSWAP(ret + val); 197c482cb11SRichard Henderson ldn = atomic_cmpxchg__nocheck(haddr, ldo, sto); 198c482cb11SRichard Henderson if (ldn == ldo) { 199*ec603b55SRichard Henderson ATOMIC_MMU_CLEANUP; 200c482cb11SRichard Henderson return ret; 201c482cb11SRichard Henderson } 202c482cb11SRichard Henderson ldo = ldn; 203c482cb11SRichard Henderson } 204c482cb11SRichard Henderson } 205c482cb11SRichard Henderson 206c482cb11SRichard Henderson ABI_TYPE ATOMIC_NAME(add_fetch)(CPUArchState *env, target_ulong addr, 207c482cb11SRichard Henderson ABI_TYPE val EXTRA_ARGS) 208c482cb11SRichard Henderson { 209c482cb11SRichard Henderson DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP; 210c482cb11SRichard Henderson DATA_TYPE ldo, ldn, ret, sto; 211c482cb11SRichard Henderson 212c482cb11SRichard Henderson ldo = atomic_read__nocheck(haddr); 213c482cb11SRichard Henderson while (1) { 214c482cb11SRichard Henderson ret = BSWAP(ldo) + val; 215c482cb11SRichard Henderson sto = BSWAP(ret); 216c482cb11SRichard Henderson ldn = atomic_cmpxchg__nocheck(haddr, ldo, sto); 217c482cb11SRichard Henderson if (ldn == ldo) { 218*ec603b55SRichard Henderson ATOMIC_MMU_CLEANUP; 219c482cb11SRichard Henderson return ret; 220c482cb11SRichard Henderson } 221c482cb11SRichard Henderson ldo = ldn; 222c482cb11SRichard Henderson } 223c482cb11SRichard Henderson } 2247ebee43eSRichard Henderson #endif /* DATA_SIZE >= 16 */ 225c482cb11SRichard Henderson 226c482cb11SRichard Henderson #undef END 227c482cb11SRichard Henderson #endif /* DATA_SIZE > 1 */ 228c482cb11SRichard Henderson 229c482cb11SRichard Henderson #undef BSWAP 230c482cb11SRichard Henderson #undef ABI_TYPE 231c482cb11SRichard Henderson #undef DATA_TYPE 232c482cb11SRichard Henderson #undef SUFFIX 233c482cb11SRichard Henderson #undef DATA_SIZE 234