Warning: This file is not a C or C++ file. It does not have highlighting.
1 | /* Atomic operations used inside libc. Linux/SH version. |
---|---|
2 | Copyright (C) 2003-2022 Free Software Foundation, Inc. |
3 | This file is part of the GNU C Library. |
4 | |
5 | The GNU C Library is free software; you can redistribute it and/or |
6 | modify it under the terms of the GNU Lesser General Public |
7 | License as published by the Free Software Foundation; either |
8 | version 2.1 of the License, or (at your option) any later version. |
9 | |
10 | The GNU C Library is distributed in the hope that it will be useful, |
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
13 | Lesser General Public License for more details. |
14 | |
15 | You should have received a copy of the GNU Lesser General Public |
16 | License along with the GNU C Library; if not, see |
17 | <https://www.gnu.org/licenses/>. */ |
18 | |
19 | #define __HAVE_64B_ATOMICS 0 |
20 | #define USE_ATOMIC_COMPILER_BUILTINS 0 |
21 | |
22 | /* XXX Is this actually correct? */ |
23 | #define ATOMIC_EXCHANGE_USES_CAS 1 |
24 | |
25 | /* SH kernel has implemented a gUSA ("g" User Space Atomicity) support |
26 | for the user space atomicity. The atomicity macros use this scheme. |
27 | |
28 | Reference: |
29 | Niibe Yutaka, "gUSA: Simple and Efficient User Space Atomicity |
30 | Emulation with Little Kernel Modification", Linux Conference 2002, |
31 | Japan. http://lc.linux.or.jp/lc2002/papers/niibe0919h.pdf (in |
32 | Japanese). |
33 | |
34 | B.N. Bershad, D. Redell, and J. Ellis, "Fast Mutual Exclusion for |
35 | Uniprocessors", Proceedings of the Fifth Architectural Support for |
36 | Programming Languages and Operating Systems (ASPLOS), pp. 223-233, |
37 | October 1992. http://www.cs.washington.edu/homes/bershad/Papers/Rcs.ps |
38 | |
39 | SuperH ABI: |
40 | r15: -(size of atomic instruction sequence) < 0 |
41 | r0: end point |
42 | r1: saved stack pointer |
43 | */ |
44 | |
45 | #define __arch_compare_and_exchange_val_8_acq(mem, newval, oldval) \ |
46 | ({ __typeof (*(mem)) __result; \ |
47 | __asm __volatile ("\ |
48 | mova 1f,r0\n\ |
49 | .align 2\n\ |
50 | mov r15,r1\n\ |
51 | mov #(0f-1f),r15\n\ |
52 | 0: mov.b @%1,%0\n\ |
53 | cmp/eq %0,%3\n\ |
54 | bf 1f\n\ |
55 | mov.b %2,@%1\n\ |
56 | 1: mov r1,r15"\ |
57 | : "=&r" (__result) : "u" (mem), "u" (newval), "u" (oldval) \ |
58 | : "r0", "r1", "t", "memory"); \ |
59 | __result; }) |
60 | |
61 | #define __arch_compare_and_exchange_val_16_acq(mem, newval, oldval) \ |
62 | ({ __typeof (*(mem)) __result; \ |
63 | __asm __volatile ("\ |
64 | mova 1f,r0\n\ |
65 | mov r15,r1\n\ |
66 | .align 2\n\ |
67 | mov #(0f-1f),r15\n\ |
68 | mov #-8,r15\n\ |
69 | 0: mov.w @%1,%0\n\ |
70 | cmp/eq %0,%3\n\ |
71 | bf 1f\n\ |
72 | mov.w %2,@%1\n\ |
73 | 1: mov r1,r15"\ |
74 | : "=&r" (__result) : "u" (mem), "u" (newval), "u" (oldval) \ |
75 | : "r0", "r1", "t", "memory"); \ |
76 | __result; }) |
77 | |
78 | #define __arch_compare_and_exchange_val_32_acq(mem, newval, oldval) \ |
79 | ({ __typeof (*(mem)) __result; \ |
80 | __asm __volatile ("\ |
81 | mova 1f,r0\n\ |
82 | .align 2\n\ |
83 | mov r15,r1\n\ |
84 | mov #(0f-1f),r15\n\ |
85 | 0: mov.l @%1,%0\n\ |
86 | cmp/eq %0,%3\n\ |
87 | bf 1f\n\ |
88 | mov.l %2,@%1\n\ |
89 | 1: mov r1,r15"\ |
90 | : "=&r" (__result) : "u" (mem), "u" (newval), "u" (oldval) \ |
91 | : "r0", "r1", "t", "memory"); \ |
92 | __result; }) |
93 | |
94 | /* XXX We do not really need 64-bit compare-and-exchange. At least |
95 | not in the moment. Using it would mean causing portability |
96 | problems since not many other 32-bit architectures have support for |
97 | such an operation. So don't define any code for now. */ |
98 | |
99 | # define __arch_compare_and_exchange_val_64_acq(mem, newval, oldval) \ |
100 | (abort (), (__typeof (*mem)) 0) |
101 | |
102 | #define atomic_exchange_and_add(mem, value) \ |
103 | ({ __typeof (*(mem)) __result, __tmp, __value = (value); \ |
104 | if (sizeof (*(mem)) == 1) \ |
105 | __asm __volatile ("\ |
106 | mova 1f,r0\n\ |
107 | .align 2\n\ |
108 | mov r15,r1\n\ |
109 | mov #(0f-1f),r15\n\ |
110 | 0: mov.b @%2,%0\n\ |
111 | mov %1,r2\n\ |
112 | add %0,r2\n\ |
113 | mov.b r2,@%2\n\ |
114 | 1: mov r1,r15"\ |
115 | : "=&r" (__result), "=&r" (__tmp) : "u" (mem), "1" (__value) \ |
116 | : "r0", "r1", "r2", "memory"); \ |
117 | else if (sizeof (*(mem)) == 2) \ |
118 | __asm __volatile ("\ |
119 | mova 1f,r0\n\ |
120 | .align 2\n\ |
121 | mov r15,r1\n\ |
122 | mov #(0f-1f),r15\n\ |
123 | 0: mov.w @%2,%0\n\ |
124 | mov %1,r2\n\ |
125 | add %0,r2\n\ |
126 | mov.w r2,@%2\n\ |
127 | 1: mov r1,r15"\ |
128 | : "=&r" (__result), "=&r" (__tmp) : "u" (mem), "1" (__value) \ |
129 | : "r0", "r1", "r2", "memory"); \ |
130 | else if (sizeof (*(mem)) == 4) \ |
131 | __asm __volatile ("\ |
132 | mova 1f,r0\n\ |
133 | .align 2\n\ |
134 | mov r15,r1\n\ |
135 | mov #(0f-1f),r15\n\ |
136 | 0: mov.l @%2,%0\n\ |
137 | mov %1,r2\n\ |
138 | add %0,r2\n\ |
139 | mov.l r2,@%2\n\ |
140 | 1: mov r1,r15"\ |
141 | : "=&r" (__result), "=&r" (__tmp) : "u" (mem), "1" (__value) \ |
142 | : "r0", "r1", "r2", "memory"); \ |
143 | else \ |
144 | { \ |
145 | __typeof (mem) memp = (mem); \ |
146 | do \ |
147 | __result = *memp; \ |
148 | while (__arch_compare_and_exchange_val_64_acq \ |
149 | (memp, __result + __value, __result) == __result); \ |
150 | (void) __value; \ |
151 | } \ |
152 | __result; }) |
153 | |
154 | #define atomic_add(mem, value) \ |
155 | (void) ({ __typeof (*(mem)) __tmp, __value = (value); \ |
156 | if (sizeof (*(mem)) == 1) \ |
157 | __asm __volatile ("\ |
158 | mova 1f,r0\n\ |
159 | mov r15,r1\n\ |
160 | .align 2\n\ |
161 | mov #(0f-1f),r15\n\ |
162 | 0: mov.b @%1,r2\n\ |
163 | add %0,r2\n\ |
164 | mov.b r2,@%1\n\ |
165 | 1: mov r1,r15"\ |
166 | : "=&r" (__tmp) : "u" (mem), "0" (__value) \ |
167 | : "r0", "r1", "r2", "memory"); \ |
168 | else if (sizeof (*(mem)) == 2) \ |
169 | __asm __volatile ("\ |
170 | mova 1f,r0\n\ |
171 | mov r15,r1\n\ |
172 | .align 2\n\ |
173 | mov #(0f-1f),r15\n\ |
174 | 0: mov.w @%1,r2\n\ |
175 | add %0,r2\n\ |
176 | mov.w r2,@%1\n\ |
177 | 1: mov r1,r15"\ |
178 | : "=&r" (__tmp) : "u" (mem), "0" (__value) \ |
179 | : "r0", "r1", "r2", "memory"); \ |
180 | else if (sizeof (*(mem)) == 4) \ |
181 | __asm __volatile ("\ |
182 | mova 1f,r0\n\ |
183 | mov r15,r1\n\ |
184 | .align 2\n\ |
185 | mov #(0f-1f),r15\n\ |
186 | 0: mov.l @%1,r2\n\ |
187 | add %0,r2\n\ |
188 | mov.l r2,@%1\n\ |
189 | 1: mov r1,r15"\ |
190 | : "=&r" (__tmp) : "u" (mem), "0" (__value) \ |
191 | : "r0", "r1", "r2", "memory"); \ |
192 | else \ |
193 | { \ |
194 | __typeof (*(mem)) oldval; \ |
195 | __typeof (mem) memp = (mem); \ |
196 | do \ |
197 | oldval = *memp; \ |
198 | while (__arch_compare_and_exchange_val_64_acq \ |
199 | (memp, oldval + __value, oldval) == oldval); \ |
200 | (void) __value; \ |
201 | } \ |
202 | }) |
203 | |
204 | #define atomic_add_negative(mem, value) \ |
205 | ({ unsigned char __result; \ |
206 | __typeof (*(mem)) __tmp, __value = (value); \ |
207 | if (sizeof (*(mem)) == 1) \ |
208 | __asm __volatile ("\ |
209 | mova 1f,r0\n\ |
210 | mov r15,r1\n\ |
211 | .align 2\n\ |
212 | mov #(0f-1f),r15\n\ |
213 | 0: mov.b @%2,r2\n\ |
214 | add %1,r2\n\ |
215 | mov.b r2,@%2\n\ |
216 | 1: mov r1,r15\n\ |
217 | shal r2\n\ |
218 | movt %0"\ |
219 | : "=r" (__result), "=&r" (__tmp) : "u" (mem), "1" (__value) \ |
220 | : "r0", "r1", "r2", "t", "memory"); \ |
221 | else if (sizeof (*(mem)) == 2) \ |
222 | __asm __volatile ("\ |
223 | mova 1f,r0\n\ |
224 | mov r15,r1\n\ |
225 | .align 2\n\ |
226 | mov #(0f-1f),r15\n\ |
227 | 0: mov.w @%2,r2\n\ |
228 | add %1,r2\n\ |
229 | mov.w r2,@%2\n\ |
230 | 1: mov r1,r15\n\ |
231 | shal r2\n\ |
232 | movt %0"\ |
233 | : "=r" (__result), "=&r" (__tmp) : "u" (mem), "1" (__value) \ |
234 | : "r0", "r1", "r2", "t", "memory"); \ |
235 | else if (sizeof (*(mem)) == 4) \ |
236 | __asm __volatile ("\ |
237 | mova 1f,r0\n\ |
238 | mov r15,r1\n\ |
239 | .align 2\n\ |
240 | mov #(0f-1f),r15\n\ |
241 | 0: mov.l @%2,r2\n\ |
242 | add %1,r2\n\ |
243 | mov.l r2,@%2\n\ |
244 | 1: mov r1,r15\n\ |
245 | shal r2\n\ |
246 | movt %0"\ |
247 | : "=r" (__result), "=&r" (__tmp) : "u" (mem), "1" (__value) \ |
248 | : "r0", "r1", "r2", "t", "memory"); \ |
249 | else \ |
250 | abort (); \ |
251 | __result; }) |
252 | |
253 | #define atomic_add_zero(mem, value) \ |
254 | ({ unsigned char __result; \ |
255 | __typeof (*(mem)) __tmp, __value = (value); \ |
256 | if (sizeof (*(mem)) == 1) \ |
257 | __asm __volatile ("\ |
258 | mova 1f,r0\n\ |
259 | mov r15,r1\n\ |
260 | .align 2\n\ |
261 | mov #(0f-1f),r15\n\ |
262 | 0: mov.b @%2,r2\n\ |
263 | add %1,r2\n\ |
264 | mov.b r2,@%2\n\ |
265 | 1: mov r1,r15\n\ |
266 | tst r2,r2\n\ |
267 | movt %0"\ |
268 | : "=r" (__result), "=&r" (__tmp) : "u" (mem), "1" (__value) \ |
269 | : "r0", "r1", "r2", "t", "memory"); \ |
270 | else if (sizeof (*(mem)) == 2) \ |
271 | __asm __volatile ("\ |
272 | mova 1f,r0\n\ |
273 | mov r15,r1\n\ |
274 | .align 2\n\ |
275 | mov #(0f-1f),r15\n\ |
276 | 0: mov.w @%2,r2\n\ |
277 | add %1,r2\n\ |
278 | mov.w r2,@%2\n\ |
279 | 1: mov r1,r15\n\ |
280 | tst r2,r2\n\ |
281 | movt %0"\ |
282 | : "=r" (__result), "=&r" (__tmp) : "u" (mem), "1" (__value) \ |
283 | : "r0", "r1", "r2", "t", "memory"); \ |
284 | else if (sizeof (*(mem)) == 4) \ |
285 | __asm __volatile ("\ |
286 | mova 1f,r0\n\ |
287 | mov r15,r1\n\ |
288 | .align 2\n\ |
289 | mov #(0f-1f),r15\n\ |
290 | 0: mov.l @%2,r2\n\ |
291 | add %1,r2\n\ |
292 | mov.l r2,@%2\n\ |
293 | 1: mov r1,r15\n\ |
294 | tst r2,r2\n\ |
295 | movt %0"\ |
296 | : "=r" (__result), "=&r" (__tmp) : "u" (mem), "1" (__value) \ |
297 | : "r0", "r1", "r2", "t", "memory"); \ |
298 | else \ |
299 | abort (); \ |
300 | __result; }) |
301 | |
302 | #define atomic_increment_and_test(mem) atomic_add_zero((mem), 1) |
303 | #define atomic_decrement_and_test(mem) atomic_add_zero((mem), -1) |
304 | |
305 | #define atomic_bit_set(mem, bit) \ |
306 | (void) ({ unsigned int __mask = 1 << (bit); \ |
307 | if (sizeof (*(mem)) == 1) \ |
308 | __asm __volatile ("\ |
309 | mova 1f,r0\n\ |
310 | mov r15,r1\n\ |
311 | .align 2\n\ |
312 | mov #(0f-1f),r15\n\ |
313 | 0: mov.b @%0,r2\n\ |
314 | or %1,r2\n\ |
315 | mov.b r2,@%0\n\ |
316 | 1: mov r1,r15"\ |
317 | : : "u" (mem), "u" (__mask) \ |
318 | : "r0", "r1", "r2", "memory"); \ |
319 | else if (sizeof (*(mem)) == 2) \ |
320 | __asm __volatile ("\ |
321 | mova 1f,r0\n\ |
322 | mov r15,r1\n\ |
323 | .align 2\n\ |
324 | mov #(0f-1f),r15\n\ |
325 | 0: mov.w @%0,r2\n\ |
326 | or %1,r2\n\ |
327 | mov.w r2,@%0\n\ |
328 | 1: mov r1,r15"\ |
329 | : : "u" (mem), "u" (__mask) \ |
330 | : "r0", "r1", "r2", "memory"); \ |
331 | else if (sizeof (*(mem)) == 4) \ |
332 | __asm __volatile ("\ |
333 | mova 1f,r0\n\ |
334 | mov r15,r1\n\ |
335 | .align 2\n\ |
336 | mov #(0f-1f),r15\n\ |
337 | 0: mov.l @%0,r2\n\ |
338 | or %1,r2\n\ |
339 | mov.l r2,@%0\n\ |
340 | 1: mov r1,r15"\ |
341 | : : "u" (mem), "u" (__mask) \ |
342 | : "r0", "r1", "r2", "memory"); \ |
343 | else \ |
344 | abort (); \ |
345 | }) |
346 | |
347 | #define atomic_bit_test_set(mem, bit) \ |
348 | ({ unsigned int __mask = 1 << (bit); \ |
349 | unsigned int __result = __mask; \ |
350 | if (sizeof (*(mem)) == 1) \ |
351 | __asm __volatile ("\ |
352 | mova 1f,r0\n\ |
353 | .align 2\n\ |
354 | mov r15,r1\n\ |
355 | mov #(0f-1f),r15\n\ |
356 | 0: mov.b @%2,r2\n\ |
357 | mov r2,r3\n\ |
358 | or %1,r2\n\ |
359 | mov.b r2,@%2\n\ |
360 | 1: mov r1,r15\n\ |
361 | and r3,%0"\ |
362 | : "=&r" (__result), "=&r" (__mask) \ |
363 | : "u" (mem), "0" (__result), "1" (__mask) \ |
364 | : "r0", "r1", "r2", "r3", "memory"); \ |
365 | else if (sizeof (*(mem)) == 2) \ |
366 | __asm __volatile ("\ |
367 | mova 1f,r0\n\ |
368 | .align 2\n\ |
369 | mov r15,r1\n\ |
370 | mov #(0f-1f),r15\n\ |
371 | 0: mov.w @%2,r2\n\ |
372 | mov r2,r3\n\ |
373 | or %1,r2\n\ |
374 | mov.w %1,@%2\n\ |
375 | 1: mov r1,r15\n\ |
376 | and r3,%0"\ |
377 | : "=&r" (__result), "=&r" (__mask) \ |
378 | : "u" (mem), "0" (__result), "1" (__mask) \ |
379 | : "r0", "r1", "r2", "r3", "memory"); \ |
380 | else if (sizeof (*(mem)) == 4) \ |
381 | __asm __volatile ("\ |
382 | mova 1f,r0\n\ |
383 | .align 2\n\ |
384 | mov r15,r1\n\ |
385 | mov #(0f-1f),r15\n\ |
386 | 0: mov.l @%2,r2\n\ |
387 | mov r2,r3\n\ |
388 | or r2,%1\n\ |
389 | mov.l %1,@%2\n\ |
390 | 1: mov r1,r15\n\ |
391 | and r3,%0"\ |
392 | : "=&r" (__result), "=&r" (__mask) \ |
393 | : "u" (mem), "0" (__result), "1" (__mask) \ |
394 | : "r0", "r1", "r2", "r3", "memory"); \ |
395 | else \ |
396 | abort (); \ |
397 | __result; }) |
398 |
Warning: This file is not a C or C++ file. It does not have highlighting.