]> git.proxmox.com Git - mirror_qemu.git/blame - atomic_template.h
tcg: Add atomic helpers
[mirror_qemu.git] / atomic_template.h
CommitLineData
c482cb11
RH
1/*
2 * Atomic helper templates
3 * Included from tcg-runtime.c and cputlb.c.
4 *
5 * Copyright (c) 2016 Red Hat, Inc
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
19 */
20
21#if DATA_SIZE == 8
22# define SUFFIX q
23# define DATA_TYPE uint64_t
24# define BSWAP bswap64
25#elif DATA_SIZE == 4
26# define SUFFIX l
27# define DATA_TYPE uint32_t
28# define BSWAP bswap32
29#elif DATA_SIZE == 2
30# define SUFFIX w
31# define DATA_TYPE uint16_t
32# define BSWAP bswap16
33#elif DATA_SIZE == 1
34# define SUFFIX b
35# define DATA_TYPE uint8_t
36# define BSWAP
37#else
38# error unsupported data size
39#endif
40
41#if DATA_SIZE >= 4
42# define ABI_TYPE DATA_TYPE
43#else
44# define ABI_TYPE uint32_t
45#endif
46
47/* Define host-endian atomic operations. Note that END is used within
48 the ATOMIC_NAME macro, and redefined below. */
49#if DATA_SIZE == 1
50# define END
51#elif defined(HOST_WORDS_BIGENDIAN)
52# define END _be
53#else
54# define END _le
55#endif
56
57ABI_TYPE ATOMIC_NAME(cmpxchg)(CPUArchState *env, target_ulong addr,
58 ABI_TYPE cmpv, ABI_TYPE newv EXTRA_ARGS)
59{
60 DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP;
61 return atomic_cmpxchg__nocheck(haddr, cmpv, newv);
62}
63
64ABI_TYPE ATOMIC_NAME(xchg)(CPUArchState *env, target_ulong addr,
65 ABI_TYPE val EXTRA_ARGS)
66{
67 DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP;
68 return atomic_xchg__nocheck(haddr, val);
69}
70
71#define GEN_ATOMIC_HELPER(X) \
72ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr, \
73 ABI_TYPE val EXTRA_ARGS) \
74{ \
75 DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP; \
76 return atomic_##X(haddr, val); \
77} \
78
79GEN_ATOMIC_HELPER(fetch_add)
80GEN_ATOMIC_HELPER(fetch_and)
81GEN_ATOMIC_HELPER(fetch_or)
82GEN_ATOMIC_HELPER(fetch_xor)
83GEN_ATOMIC_HELPER(add_fetch)
84GEN_ATOMIC_HELPER(and_fetch)
85GEN_ATOMIC_HELPER(or_fetch)
86GEN_ATOMIC_HELPER(xor_fetch)
87
88#undef GEN_ATOMIC_HELPER
89#undef END
90
91#if DATA_SIZE > 1
92
93/* Define reverse-host-endian atomic operations. Note that END is used
94 within the ATOMIC_NAME macro. */
95#ifdef HOST_WORDS_BIGENDIAN
96# define END _le
97#else
98# define END _be
99#endif
100
101ABI_TYPE ATOMIC_NAME(cmpxchg)(CPUArchState *env, target_ulong addr,
102 ABI_TYPE cmpv, ABI_TYPE newv EXTRA_ARGS)
103{
104 DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP;
105 return BSWAP(atomic_cmpxchg__nocheck(haddr, BSWAP(cmpv), BSWAP(newv)));
106}
107
108ABI_TYPE ATOMIC_NAME(xchg)(CPUArchState *env, target_ulong addr,
109 ABI_TYPE val EXTRA_ARGS)
110{
111 DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP;
112 return BSWAP(atomic_xchg__nocheck(haddr, BSWAP(val)));
113}
114
115#define GEN_ATOMIC_HELPER(X) \
116ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr, \
117 ABI_TYPE val EXTRA_ARGS) \
118{ \
119 DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP; \
120 return BSWAP(atomic_##X(haddr, BSWAP(val))); \
121}
122
123GEN_ATOMIC_HELPER(fetch_and)
124GEN_ATOMIC_HELPER(fetch_or)
125GEN_ATOMIC_HELPER(fetch_xor)
126GEN_ATOMIC_HELPER(and_fetch)
127GEN_ATOMIC_HELPER(or_fetch)
128GEN_ATOMIC_HELPER(xor_fetch)
129
130#undef GEN_ATOMIC_HELPER
131
132/* Note that for addition, we need to use a separate cmpxchg loop instead
133 of bswaps for the reverse-host-endian helpers. */
134ABI_TYPE ATOMIC_NAME(fetch_add)(CPUArchState *env, target_ulong addr,
135 ABI_TYPE val EXTRA_ARGS)
136{
137 DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP;
138 DATA_TYPE ldo, ldn, ret, sto;
139
140 ldo = atomic_read__nocheck(haddr);
141 while (1) {
142 ret = BSWAP(ldo);
143 sto = BSWAP(ret + val);
144 ldn = atomic_cmpxchg__nocheck(haddr, ldo, sto);
145 if (ldn == ldo) {
146 return ret;
147 }
148 ldo = ldn;
149 }
150}
151
152ABI_TYPE ATOMIC_NAME(add_fetch)(CPUArchState *env, target_ulong addr,
153 ABI_TYPE val EXTRA_ARGS)
154{
155 DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP;
156 DATA_TYPE ldo, ldn, ret, sto;
157
158 ldo = atomic_read__nocheck(haddr);
159 while (1) {
160 ret = BSWAP(ldo) + val;
161 sto = BSWAP(ret);
162 ldn = atomic_cmpxchg__nocheck(haddr, ldo, sto);
163 if (ldn == ldo) {
164 return ret;
165 }
166 ldo = ldn;
167 }
168}
169
170#undef END
171#endif /* DATA_SIZE > 1 */
172
173#undef BSWAP
174#undef ABI_TYPE
175#undef DATA_TYPE
176#undef SUFFIX
177#undef DATA_SIZE