1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21#include "trace/mem.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 uint64_t
31# define SDATA_TYPE 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#define ATOMIC_TRACE_RMW do { \
63 uint8_t info = glue(trace_mem_build_info_no_se, MEND)(SHIFT, false); \
64 \
65 trace_guest_mem_before_exec(ENV_GET_CPU(env), addr, info); \
66 trace_guest_mem_before_exec(ENV_GET_CPU(env), addr, \
67 info | TRACE_MEM_ST); \
68 } while (0)
69
70#define ATOMIC_TRACE_LD do { \
71 uint8_t info = glue(trace_mem_build_info_no_se, MEND)(SHIFT, false); \
72 \
73 trace_guest_mem_before_exec(ENV_GET_CPU(env), addr, info); \
74 } while (0)
75
76# define ATOMIC_TRACE_ST do { \
77 uint8_t info = glue(trace_mem_build_info_no_se, MEND)(SHIFT, true); \
78 \
79 trace_guest_mem_before_exec(ENV_GET_CPU(env), addr, info); \
80 } while (0)
81
82
83
84#if DATA_SIZE == 1
85# define END
86# define MEND _be
87#elif defined(HOST_WORDS_BIGENDIAN)
88# define END _be
89# define MEND _be
90#else
91# define END _le
92# define MEND _le
93#endif
94
95ABI_TYPE ATOMIC_NAME(cmpxchg)(CPUArchState *env, target_ulong addr,
96 ABI_TYPE cmpv, ABI_TYPE newv EXTRA_ARGS)
97{
98 ATOMIC_MMU_DECLS;
99 DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP;
100 DATA_TYPE ret;
101
102 ATOMIC_TRACE_RMW;
103 ret = atomic_cmpxchg__nocheck(haddr, cmpv, newv);
104 ATOMIC_MMU_CLEANUP;
105 return ret;
106}
107
108#if DATA_SIZE >= 16
109ABI_TYPE ATOMIC_NAME(ld)(CPUArchState *env, target_ulong addr EXTRA_ARGS)
110{
111 ATOMIC_MMU_DECLS;
112 DATA_TYPE val, *haddr = ATOMIC_MMU_LOOKUP;
113
114 ATOMIC_TRACE_LD;
115 __atomic_load(haddr, &val, __ATOMIC_RELAXED);
116 ATOMIC_MMU_CLEANUP;
117 return val;
118}
119
120void ATOMIC_NAME(st)(CPUArchState *env, target_ulong addr,
121 ABI_TYPE val EXTRA_ARGS)
122{
123 ATOMIC_MMU_DECLS;
124 DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP;
125
126 ATOMIC_TRACE_ST;
127 __atomic_store(haddr, &val, __ATOMIC_RELAXED);
128 ATOMIC_MMU_CLEANUP;
129}
130#else
131ABI_TYPE ATOMIC_NAME(xchg)(CPUArchState *env, target_ulong addr,
132 ABI_TYPE val EXTRA_ARGS)
133{
134 ATOMIC_MMU_DECLS;
135 DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP;
136 DATA_TYPE ret;
137
138 ATOMIC_TRACE_RMW;
139 ret = atomic_xchg__nocheck(haddr, val);
140 ATOMIC_MMU_CLEANUP;
141 return ret;
142}
143
144#define GEN_ATOMIC_HELPER(X) \
145ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr, \
146 ABI_TYPE val EXTRA_ARGS) \
147{ \
148 ATOMIC_MMU_DECLS; \
149 DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP; \
150 DATA_TYPE ret; \
151 \
152 ATOMIC_TRACE_RMW; \
153 ret = atomic_##X(haddr, val); \
154 ATOMIC_MMU_CLEANUP; \
155 return ret; \
156}
157
158GEN_ATOMIC_HELPER(fetch_add)
159GEN_ATOMIC_HELPER(fetch_and)
160GEN_ATOMIC_HELPER(fetch_or)
161GEN_ATOMIC_HELPER(fetch_xor)
162GEN_ATOMIC_HELPER(add_fetch)
163GEN_ATOMIC_HELPER(and_fetch)
164GEN_ATOMIC_HELPER(or_fetch)
165GEN_ATOMIC_HELPER(xor_fetch)
166
167#undef GEN_ATOMIC_HELPER
168
169
170
171
172
173
174
175
176#define GEN_ATOMIC_HELPER_FN(X, FN, XDATA_TYPE, RET) \
177ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr, \
178 ABI_TYPE xval EXTRA_ARGS) \
179{ \
180 ATOMIC_MMU_DECLS; \
181 XDATA_TYPE *haddr = ATOMIC_MMU_LOOKUP; \
182 XDATA_TYPE cmp, old, new, val = xval; \
183 \
184 ATOMIC_TRACE_RMW; \
185 smp_mb(); \
186 cmp = atomic_read__nocheck(haddr); \
187 do { \
188 old = cmp; new = FN(old, val); \
189 cmp = atomic_cmpxchg__nocheck(haddr, old, new); \
190 } while (cmp != old); \
191 ATOMIC_MMU_CLEANUP; \
192 return RET; \
193}
194
195GEN_ATOMIC_HELPER_FN(fetch_smin, MIN, SDATA_TYPE, old)
196GEN_ATOMIC_HELPER_FN(fetch_umin, MIN, DATA_TYPE, old)
197GEN_ATOMIC_HELPER_FN(fetch_smax, MAX, SDATA_TYPE, old)
198GEN_ATOMIC_HELPER_FN(fetch_umax, MAX, DATA_TYPE, old)
199
200GEN_ATOMIC_HELPER_FN(smin_fetch, MIN, SDATA_TYPE, new)
201GEN_ATOMIC_HELPER_FN(umin_fetch, MIN, DATA_TYPE, new)
202GEN_ATOMIC_HELPER_FN(smax_fetch, MAX, SDATA_TYPE, new)
203GEN_ATOMIC_HELPER_FN(umax_fetch, MAX, DATA_TYPE, new)
204
205#undef GEN_ATOMIC_HELPER_FN
206#endif
207
208#undef END
209#undef MEND
210
211#if DATA_SIZE > 1
212
213
214
215#ifdef HOST_WORDS_BIGENDIAN
216# define END _le
217# define MEND _le
218#else
219# define END _be
220# define MEND _be
221#endif
222
223ABI_TYPE ATOMIC_NAME(cmpxchg)(CPUArchState *env, target_ulong addr,
224 ABI_TYPE cmpv, ABI_TYPE newv EXTRA_ARGS)
225{
226 ATOMIC_MMU_DECLS;
227 DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP;
228 DATA_TYPE ret;
229
230 ATOMIC_TRACE_RMW;
231 ret = atomic_cmpxchg__nocheck(haddr, BSWAP(cmpv), BSWAP(newv));
232 ATOMIC_MMU_CLEANUP;
233 return BSWAP(ret);
234}
235
236#if DATA_SIZE >= 16
237ABI_TYPE ATOMIC_NAME(ld)(CPUArchState *env, target_ulong addr EXTRA_ARGS)
238{
239 ATOMIC_MMU_DECLS;
240 DATA_TYPE val, *haddr = ATOMIC_MMU_LOOKUP;
241
242 ATOMIC_TRACE_LD;
243 __atomic_load(haddr, &val, __ATOMIC_RELAXED);
244 ATOMIC_MMU_CLEANUP;
245 return BSWAP(val);
246}
247
248void ATOMIC_NAME(st)(CPUArchState *env, target_ulong addr,
249 ABI_TYPE val EXTRA_ARGS)
250{
251 ATOMIC_MMU_DECLS;
252 DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP;
253
254 ATOMIC_TRACE_ST;
255 val = BSWAP(val);
256 __atomic_store(haddr, &val, __ATOMIC_RELAXED);
257 ATOMIC_MMU_CLEANUP;
258}
259#else
260ABI_TYPE ATOMIC_NAME(xchg)(CPUArchState *env, target_ulong addr,
261 ABI_TYPE val EXTRA_ARGS)
262{
263 ATOMIC_MMU_DECLS;
264 DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP;
265 ABI_TYPE ret;
266
267 ATOMIC_TRACE_RMW;
268 ret = atomic_xchg__nocheck(haddr, BSWAP(val));
269 ATOMIC_MMU_CLEANUP;
270 return BSWAP(ret);
271}
272
273#define GEN_ATOMIC_HELPER(X) \
274ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr, \
275 ABI_TYPE val EXTRA_ARGS) \
276{ \
277 ATOMIC_MMU_DECLS; \
278 DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP; \
279 DATA_TYPE ret; \
280 \
281 ATOMIC_TRACE_RMW; \
282 ret = atomic_##X(haddr, BSWAP(val)); \
283 ATOMIC_MMU_CLEANUP; \
284 return BSWAP(ret); \
285}
286
287GEN_ATOMIC_HELPER(fetch_and)
288GEN_ATOMIC_HELPER(fetch_or)
289GEN_ATOMIC_HELPER(fetch_xor)
290GEN_ATOMIC_HELPER(and_fetch)
291GEN_ATOMIC_HELPER(or_fetch)
292GEN_ATOMIC_HELPER(xor_fetch)
293
294#undef GEN_ATOMIC_HELPER
295
296
297
298
299
300
301
302
303#define GEN_ATOMIC_HELPER_FN(X, FN, XDATA_TYPE, RET) \
304ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr, \
305 ABI_TYPE xval EXTRA_ARGS) \
306{ \
307 ATOMIC_MMU_DECLS; \
308 XDATA_TYPE *haddr = ATOMIC_MMU_LOOKUP; \
309 XDATA_TYPE ldo, ldn, old, new, val = xval; \
310 \
311 ATOMIC_TRACE_RMW; \
312 smp_mb(); \
313 ldn = atomic_read__nocheck(haddr); \
314 do { \
315 ldo = ldn; old = BSWAP(ldo); new = FN(old, val); \
316 ldn = atomic_cmpxchg__nocheck(haddr, ldo, BSWAP(new)); \
317 } while (ldo != ldn); \
318 ATOMIC_MMU_CLEANUP; \
319 return RET; \
320}
321
322GEN_ATOMIC_HELPER_FN(fetch_smin, MIN, SDATA_TYPE, old)
323GEN_ATOMIC_HELPER_FN(fetch_umin, MIN, DATA_TYPE, old)
324GEN_ATOMIC_HELPER_FN(fetch_smax, MAX, SDATA_TYPE, old)
325GEN_ATOMIC_HELPER_FN(fetch_umax, MAX, DATA_TYPE, old)
326
327GEN_ATOMIC_HELPER_FN(smin_fetch, MIN, SDATA_TYPE, new)
328GEN_ATOMIC_HELPER_FN(umin_fetch, MIN, DATA_TYPE, new)
329GEN_ATOMIC_HELPER_FN(smax_fetch, MAX, SDATA_TYPE, new)
330GEN_ATOMIC_HELPER_FN(umax_fetch, MAX, DATA_TYPE, new)
331
332
333
334#define ADD(X, Y) (X + Y)
335GEN_ATOMIC_HELPER_FN(fetch_add, ADD, DATA_TYPE, old)
336GEN_ATOMIC_HELPER_FN(add_fetch, ADD, DATA_TYPE, new)
337#undef ADD
338
339#undef GEN_ATOMIC_HELPER_FN
340#endif
341
342#undef END
343#undef MEND
344#endif
345
346#undef ATOMIC_TRACE_ST
347#undef ATOMIC_TRACE_LD
348#undef ATOMIC_TRACE_RMW
349
350#undef BSWAP
351#undef ABI_TYPE
352#undef DATA_TYPE
353#undef SDATA_TYPE
354#undef SUFFIX
355#undef DATA_SIZE
356#undef SHIFT
357