xref: /openbmc/qemu/accel/tcg/atomic_template.h (revision ec603b5584fa71213ef8f324fe89e4b27cc9d2bc)
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