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 1010f7d4d5SPhilippe Mathieu-Daudé * version 2 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é 2110f7d4d5SPhilippe Mathieu-Daudé #if DATA_SIZE == 16 2210f7d4d5SPhilippe Mathieu-Daudé # define SUFFIX o 2310f7d4d5SPhilippe Mathieu-Daudé # define DATA_TYPE Int128 2410f7d4d5SPhilippe Mathieu-Daudé # define BSWAP bswap128 2510f7d4d5SPhilippe Mathieu-Daudé #elif DATA_SIZE == 8 2610f7d4d5SPhilippe Mathieu-Daudé # define SUFFIX q 2710f7d4d5SPhilippe Mathieu-Daudé # define DATA_TYPE uint64_t 2810f7d4d5SPhilippe Mathieu-Daudé # define BSWAP bswap64 2910f7d4d5SPhilippe Mathieu-Daudé #elif DATA_SIZE == 4 3010f7d4d5SPhilippe Mathieu-Daudé # define SUFFIX l 3110f7d4d5SPhilippe Mathieu-Daudé # define DATA_TYPE uint32_t 3210f7d4d5SPhilippe Mathieu-Daudé # define BSWAP bswap32 3310f7d4d5SPhilippe Mathieu-Daudé #elif DATA_SIZE == 2 3410f7d4d5SPhilippe Mathieu-Daudé # define SUFFIX w 3510f7d4d5SPhilippe Mathieu-Daudé # define DATA_TYPE uint16_t 3610f7d4d5SPhilippe Mathieu-Daudé # define BSWAP bswap16 3710f7d4d5SPhilippe Mathieu-Daudé #elif DATA_SIZE == 1 3810f7d4d5SPhilippe Mathieu-Daudé # define SUFFIX b 3910f7d4d5SPhilippe Mathieu-Daudé # define DATA_TYPE uint8_t 4010f7d4d5SPhilippe Mathieu-Daudé # define BSWAP 4110f7d4d5SPhilippe Mathieu-Daudé #else 4210f7d4d5SPhilippe Mathieu-Daudé # error unsupported data size 4310f7d4d5SPhilippe Mathieu-Daudé #endif 4410f7d4d5SPhilippe Mathieu-Daudé 4510f7d4d5SPhilippe Mathieu-Daudé #if DATA_SIZE >= 4 4610f7d4d5SPhilippe Mathieu-Daudé # define ABI_TYPE DATA_TYPE 4710f7d4d5SPhilippe Mathieu-Daudé #else 4810f7d4d5SPhilippe Mathieu-Daudé # define ABI_TYPE uint32_t 4910f7d4d5SPhilippe Mathieu-Daudé #endif 5010f7d4d5SPhilippe Mathieu-Daudé 5110f7d4d5SPhilippe Mathieu-Daudé /* Define host-endian atomic operations. Note that END is used within 5210f7d4d5SPhilippe Mathieu-Daudé the ATOMIC_NAME macro, and redefined below. */ 5310f7d4d5SPhilippe Mathieu-Daudé #if DATA_SIZE == 1 5410f7d4d5SPhilippe Mathieu-Daudé # define END 5510f7d4d5SPhilippe Mathieu-Daudé #elif defined(HOST_WORDS_BIGENDIAN) 5610f7d4d5SPhilippe Mathieu-Daudé # define END _be 5710f7d4d5SPhilippe Mathieu-Daudé #else 5810f7d4d5SPhilippe Mathieu-Daudé # define END _le 5910f7d4d5SPhilippe Mathieu-Daudé #endif 6010f7d4d5SPhilippe Mathieu-Daudé 6110f7d4d5SPhilippe Mathieu-Daudé ABI_TYPE ATOMIC_NAME(cmpxchg)(CPUArchState *env, target_ulong addr, 6210f7d4d5SPhilippe Mathieu-Daudé ABI_TYPE cmpv, ABI_TYPE newv EXTRA_ARGS) 6310f7d4d5SPhilippe Mathieu-Daudé { 6410f7d4d5SPhilippe Mathieu-Daudé 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; 6810f7d4d5SPhilippe Mathieu-Daudé } 6910f7d4d5SPhilippe Mathieu-Daudé 7010f7d4d5SPhilippe Mathieu-Daudé #if DATA_SIZE >= 16 7110f7d4d5SPhilippe Mathieu-Daudé ABI_TYPE ATOMIC_NAME(ld)(CPUArchState *env, target_ulong addr EXTRA_ARGS) 7210f7d4d5SPhilippe Mathieu-Daudé { 7310f7d4d5SPhilippe Mathieu-Daudé DATA_TYPE val, *haddr = ATOMIC_MMU_LOOKUP; 7410f7d4d5SPhilippe Mathieu-Daudé __atomic_load(haddr, &val, __ATOMIC_RELAXED); 75*ec603b55SRichard Henderson ATOMIC_MMU_CLEANUP; 7610f7d4d5SPhilippe Mathieu-Daudé return val; 7710f7d4d5SPhilippe Mathieu-Daudé } 7810f7d4d5SPhilippe Mathieu-Daudé 7910f7d4d5SPhilippe Mathieu-Daudé void ATOMIC_NAME(st)(CPUArchState *env, target_ulong addr, 8010f7d4d5SPhilippe Mathieu-Daudé ABI_TYPE val EXTRA_ARGS) 8110f7d4d5SPhilippe Mathieu-Daudé { 8210f7d4d5SPhilippe Mathieu-Daudé DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP; 8310f7d4d5SPhilippe Mathieu-Daudé __atomic_store(haddr, &val, __ATOMIC_RELAXED); 84*ec603b55SRichard Henderson ATOMIC_MMU_CLEANUP; 8510f7d4d5SPhilippe Mathieu-Daudé } 8610f7d4d5SPhilippe Mathieu-Daudé #else 8710f7d4d5SPhilippe Mathieu-Daudé ABI_TYPE ATOMIC_NAME(xchg)(CPUArchState *env, target_ulong addr, 8810f7d4d5SPhilippe Mathieu-Daudé ABI_TYPE val EXTRA_ARGS) 8910f7d4d5SPhilippe Mathieu-Daudé { 9010f7d4d5SPhilippe Mathieu-Daudé 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; 9410f7d4d5SPhilippe Mathieu-Daudé } 9510f7d4d5SPhilippe Mathieu-Daudé 9610f7d4d5SPhilippe Mathieu-Daudé #define GEN_ATOMIC_HELPER(X) \ 9710f7d4d5SPhilippe Mathieu-Daudé ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr, \ 9810f7d4d5SPhilippe Mathieu-Daudé ABI_TYPE val EXTRA_ARGS) \ 9910f7d4d5SPhilippe Mathieu-Daudé { \ 10010f7d4d5SPhilippe Mathieu-Daudé 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 } 10510f7d4d5SPhilippe Mathieu-Daudé 10610f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(fetch_add) 10710f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(fetch_and) 10810f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(fetch_or) 10910f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(fetch_xor) 11010f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(add_fetch) 11110f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(and_fetch) 11210f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(or_fetch) 11310f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(xor_fetch) 11410f7d4d5SPhilippe Mathieu-Daudé 11510f7d4d5SPhilippe Mathieu-Daudé #undef GEN_ATOMIC_HELPER 11610f7d4d5SPhilippe Mathieu-Daudé #endif /* DATA SIZE >= 16 */ 11710f7d4d5SPhilippe Mathieu-Daudé 11810f7d4d5SPhilippe Mathieu-Daudé #undef END 11910f7d4d5SPhilippe Mathieu-Daudé 12010f7d4d5SPhilippe Mathieu-Daudé #if DATA_SIZE > 1 12110f7d4d5SPhilippe Mathieu-Daudé 12210f7d4d5SPhilippe Mathieu-Daudé /* Define reverse-host-endian atomic operations. Note that END is used 12310f7d4d5SPhilippe Mathieu-Daudé within the ATOMIC_NAME macro. */ 12410f7d4d5SPhilippe Mathieu-Daudé #ifdef HOST_WORDS_BIGENDIAN 12510f7d4d5SPhilippe Mathieu-Daudé # define END _le 12610f7d4d5SPhilippe Mathieu-Daudé #else 12710f7d4d5SPhilippe Mathieu-Daudé # define END _be 12810f7d4d5SPhilippe Mathieu-Daudé #endif 12910f7d4d5SPhilippe Mathieu-Daudé 13010f7d4d5SPhilippe Mathieu-Daudé ABI_TYPE ATOMIC_NAME(cmpxchg)(CPUArchState *env, target_ulong addr, 13110f7d4d5SPhilippe Mathieu-Daudé ABI_TYPE cmpv, ABI_TYPE newv EXTRA_ARGS) 13210f7d4d5SPhilippe Mathieu-Daudé { 13310f7d4d5SPhilippe Mathieu-Daudé 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); 13710f7d4d5SPhilippe Mathieu-Daudé } 13810f7d4d5SPhilippe Mathieu-Daudé 13910f7d4d5SPhilippe Mathieu-Daudé #if DATA_SIZE >= 16 14010f7d4d5SPhilippe Mathieu-Daudé ABI_TYPE ATOMIC_NAME(ld)(CPUArchState *env, target_ulong addr EXTRA_ARGS) 14110f7d4d5SPhilippe Mathieu-Daudé { 14210f7d4d5SPhilippe Mathieu-Daudé DATA_TYPE val, *haddr = ATOMIC_MMU_LOOKUP; 14310f7d4d5SPhilippe Mathieu-Daudé __atomic_load(haddr, &val, __ATOMIC_RELAXED); 144*ec603b55SRichard Henderson ATOMIC_MMU_CLEANUP; 14510f7d4d5SPhilippe Mathieu-Daudé return BSWAP(val); 14610f7d4d5SPhilippe Mathieu-Daudé } 14710f7d4d5SPhilippe Mathieu-Daudé 14810f7d4d5SPhilippe Mathieu-Daudé void ATOMIC_NAME(st)(CPUArchState *env, target_ulong addr, 14910f7d4d5SPhilippe Mathieu-Daudé ABI_TYPE val EXTRA_ARGS) 15010f7d4d5SPhilippe Mathieu-Daudé { 15110f7d4d5SPhilippe Mathieu-Daudé DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP; 15210f7d4d5SPhilippe Mathieu-Daudé val = BSWAP(val); 15310f7d4d5SPhilippe Mathieu-Daudé __atomic_store(haddr, &val, __ATOMIC_RELAXED); 154*ec603b55SRichard Henderson ATOMIC_MMU_CLEANUP; 15510f7d4d5SPhilippe Mathieu-Daudé } 15610f7d4d5SPhilippe Mathieu-Daudé #else 15710f7d4d5SPhilippe Mathieu-Daudé ABI_TYPE ATOMIC_NAME(xchg)(CPUArchState *env, target_ulong addr, 15810f7d4d5SPhilippe Mathieu-Daudé ABI_TYPE val EXTRA_ARGS) 15910f7d4d5SPhilippe Mathieu-Daudé { 16010f7d4d5SPhilippe Mathieu-Daudé 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); 16410f7d4d5SPhilippe Mathieu-Daudé } 16510f7d4d5SPhilippe Mathieu-Daudé 16610f7d4d5SPhilippe Mathieu-Daudé #define GEN_ATOMIC_HELPER(X) \ 16710f7d4d5SPhilippe Mathieu-Daudé ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr, \ 16810f7d4d5SPhilippe Mathieu-Daudé ABI_TYPE val EXTRA_ARGS) \ 16910f7d4d5SPhilippe Mathieu-Daudé { \ 17010f7d4d5SPhilippe Mathieu-Daudé 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); \ 17410f7d4d5SPhilippe Mathieu-Daudé } 17510f7d4d5SPhilippe Mathieu-Daudé 17610f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(fetch_and) 17710f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(fetch_or) 17810f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(fetch_xor) 17910f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(and_fetch) 18010f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(or_fetch) 18110f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(xor_fetch) 18210f7d4d5SPhilippe Mathieu-Daudé 18310f7d4d5SPhilippe Mathieu-Daudé #undef GEN_ATOMIC_HELPER 18410f7d4d5SPhilippe Mathieu-Daudé 18510f7d4d5SPhilippe Mathieu-Daudé /* Note that for addition, we need to use a separate cmpxchg loop instead 18610f7d4d5SPhilippe Mathieu-Daudé of bswaps for the reverse-host-endian helpers. */ 18710f7d4d5SPhilippe Mathieu-Daudé ABI_TYPE ATOMIC_NAME(fetch_add)(CPUArchState *env, target_ulong addr, 18810f7d4d5SPhilippe Mathieu-Daudé ABI_TYPE val EXTRA_ARGS) 18910f7d4d5SPhilippe Mathieu-Daudé { 19010f7d4d5SPhilippe Mathieu-Daudé DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP; 19110f7d4d5SPhilippe Mathieu-Daudé DATA_TYPE ldo, ldn, ret, sto; 19210f7d4d5SPhilippe Mathieu-Daudé 19310f7d4d5SPhilippe Mathieu-Daudé ldo = atomic_read__nocheck(haddr); 19410f7d4d5SPhilippe Mathieu-Daudé while (1) { 19510f7d4d5SPhilippe Mathieu-Daudé ret = BSWAP(ldo); 19610f7d4d5SPhilippe Mathieu-Daudé sto = BSWAP(ret + val); 19710f7d4d5SPhilippe Mathieu-Daudé ldn = atomic_cmpxchg__nocheck(haddr, ldo, sto); 19810f7d4d5SPhilippe Mathieu-Daudé if (ldn == ldo) { 199*ec603b55SRichard Henderson ATOMIC_MMU_CLEANUP; 20010f7d4d5SPhilippe Mathieu-Daudé return ret; 20110f7d4d5SPhilippe Mathieu-Daudé } 20210f7d4d5SPhilippe Mathieu-Daudé ldo = ldn; 20310f7d4d5SPhilippe Mathieu-Daudé } 20410f7d4d5SPhilippe Mathieu-Daudé } 20510f7d4d5SPhilippe Mathieu-Daudé 20610f7d4d5SPhilippe Mathieu-Daudé ABI_TYPE ATOMIC_NAME(add_fetch)(CPUArchState *env, target_ulong addr, 20710f7d4d5SPhilippe Mathieu-Daudé ABI_TYPE val EXTRA_ARGS) 20810f7d4d5SPhilippe Mathieu-Daudé { 20910f7d4d5SPhilippe Mathieu-Daudé DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP; 21010f7d4d5SPhilippe Mathieu-Daudé DATA_TYPE ldo, ldn, ret, sto; 21110f7d4d5SPhilippe Mathieu-Daudé 21210f7d4d5SPhilippe Mathieu-Daudé ldo = atomic_read__nocheck(haddr); 21310f7d4d5SPhilippe Mathieu-Daudé while (1) { 21410f7d4d5SPhilippe Mathieu-Daudé ret = BSWAP(ldo) + val; 21510f7d4d5SPhilippe Mathieu-Daudé sto = BSWAP(ret); 21610f7d4d5SPhilippe Mathieu-Daudé ldn = atomic_cmpxchg__nocheck(haddr, ldo, sto); 21710f7d4d5SPhilippe Mathieu-Daudé if (ldn == ldo) { 218*ec603b55SRichard Henderson ATOMIC_MMU_CLEANUP; 21910f7d4d5SPhilippe Mathieu-Daudé return ret; 22010f7d4d5SPhilippe Mathieu-Daudé } 22110f7d4d5SPhilippe Mathieu-Daudé ldo = ldn; 22210f7d4d5SPhilippe Mathieu-Daudé } 22310f7d4d5SPhilippe Mathieu-Daudé } 22410f7d4d5SPhilippe Mathieu-Daudé #endif /* DATA_SIZE >= 16 */ 22510f7d4d5SPhilippe Mathieu-Daudé 22610f7d4d5SPhilippe Mathieu-Daudé #undef END 22710f7d4d5SPhilippe Mathieu-Daudé #endif /* DATA_SIZE > 1 */ 22810f7d4d5SPhilippe Mathieu-Daudé 22910f7d4d5SPhilippe Mathieu-Daudé #undef BSWAP 23010f7d4d5SPhilippe Mathieu-Daudé #undef ABI_TYPE 23110f7d4d5SPhilippe Mathieu-Daudé #undef DATA_TYPE 23210f7d4d5SPhilippe Mathieu-Daudé #undef SUFFIX 23310f7d4d5SPhilippe Mathieu-Daudé #undef DATA_SIZE 234