1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21#include "qemu/plugin.h"
22
23#if DATA_SIZE == 16
24# define SUFFIX o
25# define DATA_TYPE Int128
26# define BSWAP bswap128
27# define SHIFT 4
28#elif DATA_SIZE == 8
29# define SUFFIX q
30# define DATA_TYPE aligned_uint64_t
31# define SDATA_TYPE aligned_int64_t
32# define BSWAP bswap64
33# define SHIFT 3
34#elif DATA_SIZE == 4
35# define SUFFIX l
36# define DATA_TYPE uint32_t
37# define SDATA_TYPE int32_t
38# define BSWAP bswap32
39# define SHIFT 2
40#elif DATA_SIZE == 2
41# define SUFFIX w
42# define DATA_TYPE uint16_t
43# define SDATA_TYPE int16_t
44# define BSWAP bswap16
45# define SHIFT 1
46#elif DATA_SIZE == 1
47# define SUFFIX b
48# define DATA_TYPE uint8_t
49# define SDATA_TYPE int8_t
50# define BSWAP
51# define SHIFT 0
52#else
53# error unsupported data size
54#endif
55
56#if DATA_SIZE >= 4
57# define ABI_TYPE DATA_TYPE
58#else
59# define ABI_TYPE uint32_t
60#endif
61
62
63
64#if DATA_SIZE == 1
65# define END
66#elif defined(HOST_WORDS_BIGENDIAN)
67# define END _be
68#else
69# define END _le
70#endif
71
72ABI_TYPE ATOMIC_NAME(cmpxchg)(CPUArchState *env, target_ulong addr,
73 ABI_TYPE cmpv, ABI_TYPE newv,
74 MemOpIdx oi, uintptr_t retaddr)
75{
76 DATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE,
77 PAGE_READ | PAGE_WRITE, retaddr);
78 DATA_TYPE ret;
79
80 atomic_trace_rmw_pre(env, addr, oi);
81#if DATA_SIZE == 16
82 ret = atomic16_cmpxchg(haddr, cmpv, newv);
83#else
84 ret = qatomic_cmpxchg__nocheck(haddr, cmpv, newv);
85#endif
86 ATOMIC_MMU_CLEANUP;
87 atomic_trace_rmw_post(env, addr, oi);
88 return ret;
89}
90
91#if DATA_SIZE >= 16
92#if HAVE_ATOMIC128
93ABI_TYPE ATOMIC_NAME(ld)(CPUArchState *env, target_ulong addr,
94 MemOpIdx oi, uintptr_t retaddr)
95{
96 DATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE,
97 PAGE_READ, retaddr);
98 DATA_TYPE val;
99
100 atomic_trace_ld_pre(env, addr, oi);
101 val = atomic16_read(haddr);
102 ATOMIC_MMU_CLEANUP;
103 atomic_trace_ld_post(env, addr, oi);
104 return val;
105}
106
107void ATOMIC_NAME(st)(CPUArchState *env, target_ulong addr, ABI_TYPE val,
108 MemOpIdx oi, uintptr_t retaddr)
109{
110 DATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE,
111 PAGE_WRITE, retaddr);
112
113 atomic_trace_st_pre(env, addr, oi);
114 atomic16_set(haddr, val);
115 ATOMIC_MMU_CLEANUP;
116 atomic_trace_st_post(env, addr, oi);
117}
118#endif
119#else
120ABI_TYPE ATOMIC_NAME(xchg)(CPUArchState *env, target_ulong addr, ABI_TYPE val,
121 MemOpIdx oi, uintptr_t retaddr)
122{
123 DATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE,
124 PAGE_READ | PAGE_WRITE, retaddr);
125 DATA_TYPE ret;
126
127 atomic_trace_rmw_pre(env, addr, oi);
128 ret = qatomic_xchg__nocheck(haddr, val);
129 ATOMIC_MMU_CLEANUP;
130 atomic_trace_rmw_post(env, addr, oi);
131 return ret;
132}
133
134#define GEN_ATOMIC_HELPER(X) \
135ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr, \
136 ABI_TYPE val, MemOpIdx oi, uintptr_t retaddr) \
137{ \
138 DATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE, \
139 PAGE_READ | PAGE_WRITE, retaddr); \
140 DATA_TYPE ret; \
141 atomic_trace_rmw_pre(env, addr, oi); \
142 ret = qatomic_##X(haddr, val); \
143 ATOMIC_MMU_CLEANUP; \
144 atomic_trace_rmw_post(env, addr, oi); \
145 return ret; \
146}
147
148GEN_ATOMIC_HELPER(fetch_add)
149GEN_ATOMIC_HELPER(fetch_and)
150GEN_ATOMIC_HELPER(fetch_or)
151GEN_ATOMIC_HELPER(fetch_xor)
152GEN_ATOMIC_HELPER(add_fetch)
153GEN_ATOMIC_HELPER(and_fetch)
154GEN_ATOMIC_HELPER(or_fetch)
155GEN_ATOMIC_HELPER(xor_fetch)
156
157#undef GEN_ATOMIC_HELPER
158
159
160
161
162
163
164
165
166
167#define GEN_ATOMIC_HELPER_FN(X, FN, XDATA_TYPE, RET) \
168ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr, \
169 ABI_TYPE xval, MemOpIdx oi, uintptr_t retaddr) \
170{ \
171 XDATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE, \
172 PAGE_READ | PAGE_WRITE, retaddr); \
173 XDATA_TYPE cmp, old, new, val = xval; \
174 atomic_trace_rmw_pre(env, addr, oi); \
175 smp_mb(); \
176 cmp = qatomic_read__nocheck(haddr); \
177 do { \
178 old = cmp; new = FN(old, val); \
179 cmp = qatomic_cmpxchg__nocheck(haddr, old, new); \
180 } while (cmp != old); \
181 ATOMIC_MMU_CLEANUP; \
182 atomic_trace_rmw_post(env, addr, oi); \
183 return RET; \
184}
185
186GEN_ATOMIC_HELPER_FN(fetch_smin, MIN, SDATA_TYPE, old)
187GEN_ATOMIC_HELPER_FN(fetch_umin, MIN, DATA_TYPE, old)
188GEN_ATOMIC_HELPER_FN(fetch_smax, MAX, SDATA_TYPE, old)
189GEN_ATOMIC_HELPER_FN(fetch_umax, MAX, DATA_TYPE, old)
190
191GEN_ATOMIC_HELPER_FN(smin_fetch, MIN, SDATA_TYPE, new)
192GEN_ATOMIC_HELPER_FN(umin_fetch, MIN, DATA_TYPE, new)
193GEN_ATOMIC_HELPER_FN(smax_fetch, MAX, SDATA_TYPE, new)
194GEN_ATOMIC_HELPER_FN(umax_fetch, MAX, DATA_TYPE, new)
195
196#undef GEN_ATOMIC_HELPER_FN
197#endif
198
199#undef END
200
201#if DATA_SIZE > 1
202
203
204
205#ifdef HOST_WORDS_BIGENDIAN
206# define END _le
207#else
208# define END _be
209#endif
210
211ABI_TYPE ATOMIC_NAME(cmpxchg)(CPUArchState *env, target_ulong addr,
212 ABI_TYPE cmpv, ABI_TYPE newv,
213 MemOpIdx oi, uintptr_t retaddr)
214{
215 DATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE,
216 PAGE_READ | PAGE_WRITE, retaddr);
217 DATA_TYPE ret;
218
219 atomic_trace_rmw_pre(env, addr, oi);
220#if DATA_SIZE == 16
221 ret = atomic16_cmpxchg(haddr, BSWAP(cmpv), BSWAP(newv));
222#else
223 ret = qatomic_cmpxchg__nocheck(haddr, BSWAP(cmpv), BSWAP(newv));
224#endif
225 ATOMIC_MMU_CLEANUP;
226 atomic_trace_rmw_post(env, addr, oi);
227 return BSWAP(ret);
228}
229
230#if DATA_SIZE >= 16
231#if HAVE_ATOMIC128
232ABI_TYPE ATOMIC_NAME(ld)(CPUArchState *env, target_ulong addr,
233 MemOpIdx oi, uintptr_t retaddr)
234{
235 DATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE,
236 PAGE_READ, retaddr);
237 DATA_TYPE val;
238
239 atomic_trace_ld_pre(env, addr, oi);
240 val = atomic16_read(haddr);
241 ATOMIC_MMU_CLEANUP;
242 atomic_trace_ld_post(env, addr, oi);
243 return BSWAP(val);
244}
245
246void ATOMIC_NAME(st)(CPUArchState *env, target_ulong addr, ABI_TYPE val,
247 MemOpIdx oi, uintptr_t retaddr)
248{
249 DATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE,
250 PAGE_WRITE, retaddr);
251
252 atomic_trace_st_pre(env, addr, oi);
253 val = BSWAP(val);
254 atomic16_set(haddr, val);
255 ATOMIC_MMU_CLEANUP;
256 atomic_trace_st_post(env, addr, oi);
257}
258#endif
259#else
260ABI_TYPE ATOMIC_NAME(xchg)(CPUArchState *env, target_ulong addr, ABI_TYPE val,
261 MemOpIdx oi, uintptr_t retaddr)
262{
263 DATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE,
264 PAGE_READ | PAGE_WRITE, retaddr);
265 ABI_TYPE ret;
266
267 atomic_trace_rmw_pre(env, addr, oi);
268 ret = qatomic_xchg__nocheck(haddr, BSWAP(val));
269 ATOMIC_MMU_CLEANUP;
270 atomic_trace_rmw_post(env, addr, oi);
271 return BSWAP(ret);
272}
273
274#define GEN_ATOMIC_HELPER(X) \
275ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr, \
276 ABI_TYPE val, MemOpIdx oi, uintptr_t retaddr) \
277{ \
278 DATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE, \
279 PAGE_READ | PAGE_WRITE, retaddr); \
280 DATA_TYPE ret; \
281 atomic_trace_rmw_pre(env, addr, oi); \
282 ret = qatomic_##X(haddr, BSWAP(val)); \
283 ATOMIC_MMU_CLEANUP; \
284 atomic_trace_rmw_post(env, addr, oi); \
285 return BSWAP(ret); \
286}
287
288GEN_ATOMIC_HELPER(fetch_and)
289GEN_ATOMIC_HELPER(fetch_or)
290GEN_ATOMIC_HELPER(fetch_xor)
291GEN_ATOMIC_HELPER(and_fetch)
292GEN_ATOMIC_HELPER(or_fetch)
293GEN_ATOMIC_HELPER(xor_fetch)
294
295#undef GEN_ATOMIC_HELPER
296
297
298
299
300
301
302
303
304#define GEN_ATOMIC_HELPER_FN(X, FN, XDATA_TYPE, RET) \
305ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr, \
306 ABI_TYPE xval, MemOpIdx oi, uintptr_t retaddr) \
307{ \
308 XDATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE, \
309 PAGE_READ | PAGE_WRITE, retaddr); \
310 XDATA_TYPE ldo, ldn, old, new, val = xval; \
311 atomic_trace_rmw_pre(env, addr, oi); \
312 smp_mb(); \
313 ldn = qatomic_read__nocheck(haddr); \
314 do { \
315 ldo = ldn; old = BSWAP(ldo); new = FN(old, val); \
316 ldn = qatomic_cmpxchg__nocheck(haddr, ldo, BSWAP(new)); \
317 } while (ldo != ldn); \
318 ATOMIC_MMU_CLEANUP; \
319 atomic_trace_rmw_post(env, addr, oi); \
320 return RET; \
321}
322
323GEN_ATOMIC_HELPER_FN(fetch_smin, MIN, SDATA_TYPE, old)
324GEN_ATOMIC_HELPER_FN(fetch_umin, MIN, DATA_TYPE, old)
325GEN_ATOMIC_HELPER_FN(fetch_smax, MAX, SDATA_TYPE, old)
326GEN_ATOMIC_HELPER_FN(fetch_umax, MAX, DATA_TYPE, old)
327
328GEN_ATOMIC_HELPER_FN(smin_fetch, MIN, SDATA_TYPE, new)
329GEN_ATOMIC_HELPER_FN(umin_fetch, MIN, DATA_TYPE, new)
330GEN_ATOMIC_HELPER_FN(smax_fetch, MAX, SDATA_TYPE, new)
331GEN_ATOMIC_HELPER_FN(umax_fetch, MAX, DATA_TYPE, new)
332
333
334
335#define ADD(X, Y) (X + Y)
336GEN_ATOMIC_HELPER_FN(fetch_add, ADD, DATA_TYPE, old)
337GEN_ATOMIC_HELPER_FN(add_fetch, ADD, DATA_TYPE, new)
338#undef ADD
339
340#undef GEN_ATOMIC_HELPER_FN
341#endif
342
343#undef END
344#endif
345
346#undef BSWAP
347#undef ABI_TYPE
348#undef DATA_TYPE
349#undef SDATA_TYPE
350#undef SUFFIX
351#undef DATA_SIZE
352#undef SHIFT
353