This source file includes following definitions.
- rseq_cmpeqv_storev
- rseq_cmpnev_storeoffp_load
- rseq_addv
- rseq_cmpeqv_trystorev_storev
- rseq_cmpeqv_trystorev_storev_release
- rseq_cmpeqv_cmpeqv_storev
- rseq_cmpeqv_trymemcpy_storev
- rseq_cmpeqv_trymemcpy_storev_release
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57 #ifdef __ARMEB__
58 #define RSEQ_SIG 0xf3def5e7
59 #else
60 #define RSEQ_SIG 0xe7f5def3
61 #endif
62
63 #define rseq_smp_mb() __asm__ __volatile__ ("dmb" ::: "memory", "cc")
64 #define rseq_smp_rmb() __asm__ __volatile__ ("dmb" ::: "memory", "cc")
65 #define rseq_smp_wmb() __asm__ __volatile__ ("dmb" ::: "memory", "cc")
66
67 #define rseq_smp_load_acquire(p) \
68 __extension__ ({ \
69 __typeof(*p) ____p1 = RSEQ_READ_ONCE(*p); \
70 rseq_smp_mb(); \
71 ____p1; \
72 })
73
74 #define rseq_smp_acquire__after_ctrl_dep() rseq_smp_rmb()
75
76 #define rseq_smp_store_release(p, v) \
77 do { \
78 rseq_smp_mb(); \
79 RSEQ_WRITE_ONCE(*p, v); \
80 } while (0)
81
82 #ifdef RSEQ_SKIP_FASTPATH
83 #include "rseq-skip.h"
84 #else
85
86 #define __RSEQ_ASM_DEFINE_TABLE(label, version, flags, start_ip, \
87 post_commit_offset, abort_ip) \
88 ".pushsection __rseq_cs, \"aw\"\n\t" \
89 ".balign 32\n\t" \
90 __rseq_str(label) ":\n\t" \
91 ".word " __rseq_str(version) ", " __rseq_str(flags) "\n\t" \
92 ".word " __rseq_str(start_ip) ", 0x0, " __rseq_str(post_commit_offset) ", 0x0, " __rseq_str(abort_ip) ", 0x0\n\t" \
93 ".popsection\n\t" \
94 ".pushsection __rseq_cs_ptr_array, \"aw\"\n\t" \
95 ".word " __rseq_str(label) "b, 0x0\n\t" \
96 ".popsection\n\t"
97
98 #define RSEQ_ASM_DEFINE_TABLE(label, start_ip, post_commit_ip, abort_ip) \
99 __RSEQ_ASM_DEFINE_TABLE(label, 0x0, 0x0, start_ip, \
100 (post_commit_ip - start_ip), abort_ip)
101
102
103
104
105
106
107
108
109
110 #define RSEQ_ASM_DEFINE_EXIT_POINT(start_ip, exit_ip) \
111 ".pushsection __rseq_exit_point_array, \"aw\"\n\t" \
112 ".word " __rseq_str(start_ip) ", 0x0, " __rseq_str(exit_ip) ", 0x0\n\t" \
113 ".popsection\n\t"
114
115 #define RSEQ_ASM_STORE_RSEQ_CS(label, cs_label, rseq_cs) \
116 RSEQ_INJECT_ASM(1) \
117 "adr r0, " __rseq_str(cs_label) "\n\t" \
118 "str r0, %[" __rseq_str(rseq_cs) "]\n\t" \
119 __rseq_str(label) ":\n\t"
120
121 #define RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, label) \
122 RSEQ_INJECT_ASM(2) \
123 "ldr r0, %[" __rseq_str(current_cpu_id) "]\n\t" \
124 "cmp %[" __rseq_str(cpu_id) "], r0\n\t" \
125 "bne " __rseq_str(label) "\n\t"
126
127 #define __RSEQ_ASM_DEFINE_ABORT(table_label, label, teardown, \
128 abort_label, version, flags, \
129 start_ip, post_commit_offset, abort_ip) \
130 ".balign 32\n\t" \
131 __rseq_str(table_label) ":\n\t" \
132 ".word " __rseq_str(version) ", " __rseq_str(flags) "\n\t" \
133 ".word " __rseq_str(start_ip) ", 0x0, " __rseq_str(post_commit_offset) ", 0x0, " __rseq_str(abort_ip) ", 0x0\n\t" \
134 ".word " __rseq_str(RSEQ_SIG) "\n\t" \
135 __rseq_str(label) ":\n\t" \
136 teardown \
137 "b %l[" __rseq_str(abort_label) "]\n\t"
138
139 #define RSEQ_ASM_DEFINE_ABORT(table_label, label, teardown, abort_label, \
140 start_ip, post_commit_ip, abort_ip) \
141 __RSEQ_ASM_DEFINE_ABORT(table_label, label, teardown, \
142 abort_label, 0x0, 0x0, start_ip, \
143 (post_commit_ip - start_ip), abort_ip)
144
145 #define RSEQ_ASM_DEFINE_CMPFAIL(label, teardown, cmpfail_label) \
146 __rseq_str(label) ":\n\t" \
147 teardown \
148 "b %l[" __rseq_str(cmpfail_label) "]\n\t"
149
150 #define rseq_workaround_gcc_asm_size_guess() __asm__ __volatile__("")
151
152 static inline __attribute__((always_inline))
153 int rseq_cmpeqv_storev(intptr_t *v, intptr_t expect, intptr_t newv, int cpu)
154 {
155 RSEQ_INJECT_C(9)
156
157 rseq_workaround_gcc_asm_size_guess();
158 __asm__ __volatile__ goto (
159 RSEQ_ASM_DEFINE_TABLE(9, 1f, 2f, 4f)
160 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[cmpfail])
161 #ifdef RSEQ_COMPARE_TWICE
162 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error1])
163 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error2])
164 #endif
165
166 RSEQ_ASM_STORE_RSEQ_CS(1, 3f, rseq_cs)
167 RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f)
168 RSEQ_INJECT_ASM(3)
169 "ldr r0, %[v]\n\t"
170 "cmp %[expect], r0\n\t"
171 "bne %l[cmpfail]\n\t"
172 RSEQ_INJECT_ASM(4)
173 #ifdef RSEQ_COMPARE_TWICE
174 RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1])
175 "ldr r0, %[v]\n\t"
176 "cmp %[expect], r0\n\t"
177 "bne %l[error2]\n\t"
178 #endif
179
180 "str %[newv], %[v]\n\t"
181 "2:\n\t"
182 RSEQ_INJECT_ASM(5)
183 "b 5f\n\t"
184 RSEQ_ASM_DEFINE_ABORT(3, 4, "", abort, 1b, 2b, 4f)
185 "5:\n\t"
186 :
187 : [cpu_id] "r" (cpu),
188 [current_cpu_id] "m" (__rseq_abi.cpu_id),
189 [rseq_cs] "m" (__rseq_abi.rseq_cs),
190 [v] "m" (*v),
191 [expect] "r" (expect),
192 [newv] "r" (newv)
193 RSEQ_INJECT_INPUT
194 : "r0", "memory", "cc"
195 RSEQ_INJECT_CLOBBER
196 : abort, cmpfail
197 #ifdef RSEQ_COMPARE_TWICE
198 , error1, error2
199 #endif
200 );
201 rseq_workaround_gcc_asm_size_guess();
202 return 0;
203 abort:
204 rseq_workaround_gcc_asm_size_guess();
205 RSEQ_INJECT_FAILED
206 return -1;
207 cmpfail:
208 rseq_workaround_gcc_asm_size_guess();
209 return 1;
210 #ifdef RSEQ_COMPARE_TWICE
211 error1:
212 rseq_bug("cpu_id comparison failed");
213 error2:
214 rseq_bug("expected value comparison failed");
215 #endif
216 }
217
218 static inline __attribute__((always_inline))
219 int rseq_cmpnev_storeoffp_load(intptr_t *v, intptr_t expectnot,
220 off_t voffp, intptr_t *load, int cpu)
221 {
222 RSEQ_INJECT_C(9)
223
224 rseq_workaround_gcc_asm_size_guess();
225 __asm__ __volatile__ goto (
226 RSEQ_ASM_DEFINE_TABLE(9, 1f, 2f, 4f)
227 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[cmpfail])
228 #ifdef RSEQ_COMPARE_TWICE
229 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error1])
230 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error2])
231 #endif
232
233 RSEQ_ASM_STORE_RSEQ_CS(1, 3f, rseq_cs)
234 RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f)
235 RSEQ_INJECT_ASM(3)
236 "ldr r0, %[v]\n\t"
237 "cmp %[expectnot], r0\n\t"
238 "beq %l[cmpfail]\n\t"
239 RSEQ_INJECT_ASM(4)
240 #ifdef RSEQ_COMPARE_TWICE
241 RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1])
242 "ldr r0, %[v]\n\t"
243 "cmp %[expectnot], r0\n\t"
244 "beq %l[error2]\n\t"
245 #endif
246 "str r0, %[load]\n\t"
247 "add r0, %[voffp]\n\t"
248 "ldr r0, [r0]\n\t"
249
250 "str r0, %[v]\n\t"
251 "2:\n\t"
252 RSEQ_INJECT_ASM(5)
253 "b 5f\n\t"
254 RSEQ_ASM_DEFINE_ABORT(3, 4, "", abort, 1b, 2b, 4f)
255 "5:\n\t"
256 :
257 : [cpu_id] "r" (cpu),
258 [current_cpu_id] "m" (__rseq_abi.cpu_id),
259 [rseq_cs] "m" (__rseq_abi.rseq_cs),
260
261 [v] "m" (*v),
262 [expectnot] "r" (expectnot),
263 [voffp] "Ir" (voffp),
264 [load] "m" (*load)
265 RSEQ_INJECT_INPUT
266 : "r0", "memory", "cc"
267 RSEQ_INJECT_CLOBBER
268 : abort, cmpfail
269 #ifdef RSEQ_COMPARE_TWICE
270 , error1, error2
271 #endif
272 );
273 rseq_workaround_gcc_asm_size_guess();
274 return 0;
275 abort:
276 rseq_workaround_gcc_asm_size_guess();
277 RSEQ_INJECT_FAILED
278 return -1;
279 cmpfail:
280 rseq_workaround_gcc_asm_size_guess();
281 return 1;
282 #ifdef RSEQ_COMPARE_TWICE
283 error1:
284 rseq_bug("cpu_id comparison failed");
285 error2:
286 rseq_bug("expected value comparison failed");
287 #endif
288 }
289
290 static inline __attribute__((always_inline))
291 int rseq_addv(intptr_t *v, intptr_t count, int cpu)
292 {
293 RSEQ_INJECT_C(9)
294
295 rseq_workaround_gcc_asm_size_guess();
296 __asm__ __volatile__ goto (
297 RSEQ_ASM_DEFINE_TABLE(9, 1f, 2f, 4f)
298 #ifdef RSEQ_COMPARE_TWICE
299 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error1])
300 #endif
301
302 RSEQ_ASM_STORE_RSEQ_CS(1, 3f, rseq_cs)
303 RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f)
304 RSEQ_INJECT_ASM(3)
305 #ifdef RSEQ_COMPARE_TWICE
306 RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1])
307 #endif
308 "ldr r0, %[v]\n\t"
309 "add r0, %[count]\n\t"
310
311 "str r0, %[v]\n\t"
312 "2:\n\t"
313 RSEQ_INJECT_ASM(4)
314 "b 5f\n\t"
315 RSEQ_ASM_DEFINE_ABORT(3, 4, "", abort, 1b, 2b, 4f)
316 "5:\n\t"
317 :
318 : [cpu_id] "r" (cpu),
319 [current_cpu_id] "m" (__rseq_abi.cpu_id),
320 [rseq_cs] "m" (__rseq_abi.rseq_cs),
321 [v] "m" (*v),
322 [count] "Ir" (count)
323 RSEQ_INJECT_INPUT
324 : "r0", "memory", "cc"
325 RSEQ_INJECT_CLOBBER
326 : abort
327 #ifdef RSEQ_COMPARE_TWICE
328 , error1
329 #endif
330 );
331 rseq_workaround_gcc_asm_size_guess();
332 return 0;
333 abort:
334 rseq_workaround_gcc_asm_size_guess();
335 RSEQ_INJECT_FAILED
336 return -1;
337 #ifdef RSEQ_COMPARE_TWICE
338 error1:
339 rseq_bug("cpu_id comparison failed");
340 #endif
341 }
342
343 static inline __attribute__((always_inline))
344 int rseq_cmpeqv_trystorev_storev(intptr_t *v, intptr_t expect,
345 intptr_t *v2, intptr_t newv2,
346 intptr_t newv, int cpu)
347 {
348 RSEQ_INJECT_C(9)
349
350 rseq_workaround_gcc_asm_size_guess();
351 __asm__ __volatile__ goto (
352 RSEQ_ASM_DEFINE_TABLE(9, 1f, 2f, 4f)
353 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[cmpfail])
354 #ifdef RSEQ_COMPARE_TWICE
355 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error1])
356 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error2])
357 #endif
358
359 RSEQ_ASM_STORE_RSEQ_CS(1, 3f, rseq_cs)
360 RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f)
361 RSEQ_INJECT_ASM(3)
362 "ldr r0, %[v]\n\t"
363 "cmp %[expect], r0\n\t"
364 "bne %l[cmpfail]\n\t"
365 RSEQ_INJECT_ASM(4)
366 #ifdef RSEQ_COMPARE_TWICE
367 RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1])
368 "ldr r0, %[v]\n\t"
369 "cmp %[expect], r0\n\t"
370 "bne %l[error2]\n\t"
371 #endif
372
373 "str %[newv2], %[v2]\n\t"
374 RSEQ_INJECT_ASM(5)
375
376 "str %[newv], %[v]\n\t"
377 "2:\n\t"
378 RSEQ_INJECT_ASM(6)
379 "b 5f\n\t"
380 RSEQ_ASM_DEFINE_ABORT(3, 4, "", abort, 1b, 2b, 4f)
381 "5:\n\t"
382 :
383 : [cpu_id] "r" (cpu),
384 [current_cpu_id] "m" (__rseq_abi.cpu_id),
385 [rseq_cs] "m" (__rseq_abi.rseq_cs),
386
387 [v2] "m" (*v2),
388 [newv2] "r" (newv2),
389
390 [v] "m" (*v),
391 [expect] "r" (expect),
392 [newv] "r" (newv)
393 RSEQ_INJECT_INPUT
394 : "r0", "memory", "cc"
395 RSEQ_INJECT_CLOBBER
396 : abort, cmpfail
397 #ifdef RSEQ_COMPARE_TWICE
398 , error1, error2
399 #endif
400 );
401 rseq_workaround_gcc_asm_size_guess();
402 return 0;
403 abort:
404 rseq_workaround_gcc_asm_size_guess();
405 RSEQ_INJECT_FAILED
406 return -1;
407 cmpfail:
408 rseq_workaround_gcc_asm_size_guess();
409 return 1;
410 #ifdef RSEQ_COMPARE_TWICE
411 error1:
412 rseq_bug("cpu_id comparison failed");
413 error2:
414 rseq_bug("expected value comparison failed");
415 #endif
416 }
417
418 static inline __attribute__((always_inline))
419 int rseq_cmpeqv_trystorev_storev_release(intptr_t *v, intptr_t expect,
420 intptr_t *v2, intptr_t newv2,
421 intptr_t newv, int cpu)
422 {
423 RSEQ_INJECT_C(9)
424
425 rseq_workaround_gcc_asm_size_guess();
426 __asm__ __volatile__ goto (
427 RSEQ_ASM_DEFINE_TABLE(9, 1f, 2f, 4f)
428 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[cmpfail])
429 #ifdef RSEQ_COMPARE_TWICE
430 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error1])
431 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error2])
432 #endif
433
434 RSEQ_ASM_STORE_RSEQ_CS(1, 3f, rseq_cs)
435 RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f)
436 RSEQ_INJECT_ASM(3)
437 "ldr r0, %[v]\n\t"
438 "cmp %[expect], r0\n\t"
439 "bne %l[cmpfail]\n\t"
440 RSEQ_INJECT_ASM(4)
441 #ifdef RSEQ_COMPARE_TWICE
442 RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1])
443 "ldr r0, %[v]\n\t"
444 "cmp %[expect], r0\n\t"
445 "bne %l[error2]\n\t"
446 #endif
447
448 "str %[newv2], %[v2]\n\t"
449 RSEQ_INJECT_ASM(5)
450 "dmb\n\t"
451
452 "str %[newv], %[v]\n\t"
453 "2:\n\t"
454 RSEQ_INJECT_ASM(6)
455 "b 5f\n\t"
456 RSEQ_ASM_DEFINE_ABORT(3, 4, "", abort, 1b, 2b, 4f)
457 "5:\n\t"
458 :
459 : [cpu_id] "r" (cpu),
460 [current_cpu_id] "m" (__rseq_abi.cpu_id),
461 [rseq_cs] "m" (__rseq_abi.rseq_cs),
462
463 [v2] "m" (*v2),
464 [newv2] "r" (newv2),
465
466 [v] "m" (*v),
467 [expect] "r" (expect),
468 [newv] "r" (newv)
469 RSEQ_INJECT_INPUT
470 : "r0", "memory", "cc"
471 RSEQ_INJECT_CLOBBER
472 : abort, cmpfail
473 #ifdef RSEQ_COMPARE_TWICE
474 , error1, error2
475 #endif
476 );
477 rseq_workaround_gcc_asm_size_guess();
478 return 0;
479 abort:
480 rseq_workaround_gcc_asm_size_guess();
481 RSEQ_INJECT_FAILED
482 return -1;
483 cmpfail:
484 rseq_workaround_gcc_asm_size_guess();
485 return 1;
486 #ifdef RSEQ_COMPARE_TWICE
487 error1:
488 rseq_bug("cpu_id comparison failed");
489 error2:
490 rseq_bug("expected value comparison failed");
491 #endif
492 }
493
494 static inline __attribute__((always_inline))
495 int rseq_cmpeqv_cmpeqv_storev(intptr_t *v, intptr_t expect,
496 intptr_t *v2, intptr_t expect2,
497 intptr_t newv, int cpu)
498 {
499 RSEQ_INJECT_C(9)
500
501 rseq_workaround_gcc_asm_size_guess();
502 __asm__ __volatile__ goto (
503 RSEQ_ASM_DEFINE_TABLE(9, 1f, 2f, 4f)
504 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[cmpfail])
505 #ifdef RSEQ_COMPARE_TWICE
506 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error1])
507 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error2])
508 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error3])
509 #endif
510
511 RSEQ_ASM_STORE_RSEQ_CS(1, 3f, rseq_cs)
512 RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f)
513 RSEQ_INJECT_ASM(3)
514 "ldr r0, %[v]\n\t"
515 "cmp %[expect], r0\n\t"
516 "bne %l[cmpfail]\n\t"
517 RSEQ_INJECT_ASM(4)
518 "ldr r0, %[v2]\n\t"
519 "cmp %[expect2], r0\n\t"
520 "bne %l[cmpfail]\n\t"
521 RSEQ_INJECT_ASM(5)
522 #ifdef RSEQ_COMPARE_TWICE
523 RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1])
524 "ldr r0, %[v]\n\t"
525 "cmp %[expect], r0\n\t"
526 "bne %l[error2]\n\t"
527 "ldr r0, %[v2]\n\t"
528 "cmp %[expect2], r0\n\t"
529 "bne %l[error3]\n\t"
530 #endif
531
532 "str %[newv], %[v]\n\t"
533 "2:\n\t"
534 RSEQ_INJECT_ASM(6)
535 "b 5f\n\t"
536 RSEQ_ASM_DEFINE_ABORT(3, 4, "", abort, 1b, 2b, 4f)
537 "5:\n\t"
538 :
539 : [cpu_id] "r" (cpu),
540 [current_cpu_id] "m" (__rseq_abi.cpu_id),
541 [rseq_cs] "m" (__rseq_abi.rseq_cs),
542
543 [v2] "m" (*v2),
544 [expect2] "r" (expect2),
545
546 [v] "m" (*v),
547 [expect] "r" (expect),
548 [newv] "r" (newv)
549 RSEQ_INJECT_INPUT
550 : "r0", "memory", "cc"
551 RSEQ_INJECT_CLOBBER
552 : abort, cmpfail
553 #ifdef RSEQ_COMPARE_TWICE
554 , error1, error2, error3
555 #endif
556 );
557 rseq_workaround_gcc_asm_size_guess();
558 return 0;
559 abort:
560 rseq_workaround_gcc_asm_size_guess();
561 RSEQ_INJECT_FAILED
562 return -1;
563 cmpfail:
564 rseq_workaround_gcc_asm_size_guess();
565 return 1;
566 #ifdef RSEQ_COMPARE_TWICE
567 error1:
568 rseq_bug("cpu_id comparison failed");
569 error2:
570 rseq_bug("1st expected value comparison failed");
571 error3:
572 rseq_bug("2nd expected value comparison failed");
573 #endif
574 }
575
576 static inline __attribute__((always_inline))
577 int rseq_cmpeqv_trymemcpy_storev(intptr_t *v, intptr_t expect,
578 void *dst, void *src, size_t len,
579 intptr_t newv, int cpu)
580 {
581 uint32_t rseq_scratch[3];
582
583 RSEQ_INJECT_C(9)
584
585 rseq_workaround_gcc_asm_size_guess();
586 __asm__ __volatile__ goto (
587 RSEQ_ASM_DEFINE_TABLE(9, 1f, 2f, 4f)
588 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[cmpfail])
589 #ifdef RSEQ_COMPARE_TWICE
590 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error1])
591 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error2])
592 #endif
593 "str %[src], %[rseq_scratch0]\n\t"
594 "str %[dst], %[rseq_scratch1]\n\t"
595 "str %[len], %[rseq_scratch2]\n\t"
596
597 RSEQ_ASM_STORE_RSEQ_CS(1, 3f, rseq_cs)
598 RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f)
599 RSEQ_INJECT_ASM(3)
600 "ldr r0, %[v]\n\t"
601 "cmp %[expect], r0\n\t"
602 "bne 5f\n\t"
603 RSEQ_INJECT_ASM(4)
604 #ifdef RSEQ_COMPARE_TWICE
605 RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 6f)
606 "ldr r0, %[v]\n\t"
607 "cmp %[expect], r0\n\t"
608 "bne 7f\n\t"
609 #endif
610
611 "cmp %[len], #0\n\t" \
612 "beq 333f\n\t" \
613 "222:\n\t" \
614 "ldrb %%r0, [%[src]]\n\t" \
615 "strb %%r0, [%[dst]]\n\t" \
616 "adds %[src], #1\n\t" \
617 "adds %[dst], #1\n\t" \
618 "subs %[len], #1\n\t" \
619 "bne 222b\n\t" \
620 "333:\n\t" \
621 RSEQ_INJECT_ASM(5)
622
623 "str %[newv], %[v]\n\t"
624 "2:\n\t"
625 RSEQ_INJECT_ASM(6)
626
627 "ldr %[len], %[rseq_scratch2]\n\t"
628 "ldr %[dst], %[rseq_scratch1]\n\t"
629 "ldr %[src], %[rseq_scratch0]\n\t"
630 "b 8f\n\t"
631 RSEQ_ASM_DEFINE_ABORT(3, 4,
632
633 "ldr %[len], %[rseq_scratch2]\n\t"
634 "ldr %[dst], %[rseq_scratch1]\n\t"
635 "ldr %[src], %[rseq_scratch0]\n\t",
636 abort, 1b, 2b, 4f)
637 RSEQ_ASM_DEFINE_CMPFAIL(5,
638
639 "ldr %[len], %[rseq_scratch2]\n\t"
640 "ldr %[dst], %[rseq_scratch1]\n\t"
641 "ldr %[src], %[rseq_scratch0]\n\t",
642 cmpfail)
643 #ifdef RSEQ_COMPARE_TWICE
644 RSEQ_ASM_DEFINE_CMPFAIL(6,
645
646 "ldr %[len], %[rseq_scratch2]\n\t"
647 "ldr %[dst], %[rseq_scratch1]\n\t"
648 "ldr %[src], %[rseq_scratch0]\n\t",
649 error1)
650 RSEQ_ASM_DEFINE_CMPFAIL(7,
651
652 "ldr %[len], %[rseq_scratch2]\n\t"
653 "ldr %[dst], %[rseq_scratch1]\n\t"
654 "ldr %[src], %[rseq_scratch0]\n\t",
655 error2)
656 #endif
657 "8:\n\t"
658 :
659 : [cpu_id] "r" (cpu),
660 [current_cpu_id] "m" (__rseq_abi.cpu_id),
661 [rseq_cs] "m" (__rseq_abi.rseq_cs),
662
663 [v] "m" (*v),
664 [expect] "r" (expect),
665 [newv] "r" (newv),
666
667 [dst] "r" (dst),
668 [src] "r" (src),
669 [len] "r" (len),
670 [rseq_scratch0] "m" (rseq_scratch[0]),
671 [rseq_scratch1] "m" (rseq_scratch[1]),
672 [rseq_scratch2] "m" (rseq_scratch[2])
673 RSEQ_INJECT_INPUT
674 : "r0", "memory", "cc"
675 RSEQ_INJECT_CLOBBER
676 : abort, cmpfail
677 #ifdef RSEQ_COMPARE_TWICE
678 , error1, error2
679 #endif
680 );
681 rseq_workaround_gcc_asm_size_guess();
682 return 0;
683 abort:
684 rseq_workaround_gcc_asm_size_guess();
685 RSEQ_INJECT_FAILED
686 return -1;
687 cmpfail:
688 rseq_workaround_gcc_asm_size_guess();
689 return 1;
690 #ifdef RSEQ_COMPARE_TWICE
691 error1:
692 rseq_workaround_gcc_asm_size_guess();
693 rseq_bug("cpu_id comparison failed");
694 error2:
695 rseq_workaround_gcc_asm_size_guess();
696 rseq_bug("expected value comparison failed");
697 #endif
698 }
699
700 static inline __attribute__((always_inline))
701 int rseq_cmpeqv_trymemcpy_storev_release(intptr_t *v, intptr_t expect,
702 void *dst, void *src, size_t len,
703 intptr_t newv, int cpu)
704 {
705 uint32_t rseq_scratch[3];
706
707 RSEQ_INJECT_C(9)
708
709 rseq_workaround_gcc_asm_size_guess();
710 __asm__ __volatile__ goto (
711 RSEQ_ASM_DEFINE_TABLE(9, 1f, 2f, 4f)
712 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[cmpfail])
713 #ifdef RSEQ_COMPARE_TWICE
714 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error1])
715 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error2])
716 #endif
717 "str %[src], %[rseq_scratch0]\n\t"
718 "str %[dst], %[rseq_scratch1]\n\t"
719 "str %[len], %[rseq_scratch2]\n\t"
720
721 RSEQ_ASM_STORE_RSEQ_CS(1, 3f, rseq_cs)
722 RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f)
723 RSEQ_INJECT_ASM(3)
724 "ldr r0, %[v]\n\t"
725 "cmp %[expect], r0\n\t"
726 "bne 5f\n\t"
727 RSEQ_INJECT_ASM(4)
728 #ifdef RSEQ_COMPARE_TWICE
729 RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 6f)
730 "ldr r0, %[v]\n\t"
731 "cmp %[expect], r0\n\t"
732 "bne 7f\n\t"
733 #endif
734
735 "cmp %[len], #0\n\t" \
736 "beq 333f\n\t" \
737 "222:\n\t" \
738 "ldrb %%r0, [%[src]]\n\t" \
739 "strb %%r0, [%[dst]]\n\t" \
740 "adds %[src], #1\n\t" \
741 "adds %[dst], #1\n\t" \
742 "subs %[len], #1\n\t" \
743 "bne 222b\n\t" \
744 "333:\n\t" \
745 RSEQ_INJECT_ASM(5)
746 "dmb\n\t"
747
748 "str %[newv], %[v]\n\t"
749 "2:\n\t"
750 RSEQ_INJECT_ASM(6)
751
752 "ldr %[len], %[rseq_scratch2]\n\t"
753 "ldr %[dst], %[rseq_scratch1]\n\t"
754 "ldr %[src], %[rseq_scratch0]\n\t"
755 "b 8f\n\t"
756 RSEQ_ASM_DEFINE_ABORT(3, 4,
757
758 "ldr %[len], %[rseq_scratch2]\n\t"
759 "ldr %[dst], %[rseq_scratch1]\n\t"
760 "ldr %[src], %[rseq_scratch0]\n\t",
761 abort, 1b, 2b, 4f)
762 RSEQ_ASM_DEFINE_CMPFAIL(5,
763
764 "ldr %[len], %[rseq_scratch2]\n\t"
765 "ldr %[dst], %[rseq_scratch1]\n\t"
766 "ldr %[src], %[rseq_scratch0]\n\t",
767 cmpfail)
768 #ifdef RSEQ_COMPARE_TWICE
769 RSEQ_ASM_DEFINE_CMPFAIL(6,
770
771 "ldr %[len], %[rseq_scratch2]\n\t"
772 "ldr %[dst], %[rseq_scratch1]\n\t"
773 "ldr %[src], %[rseq_scratch0]\n\t",
774 error1)
775 RSEQ_ASM_DEFINE_CMPFAIL(7,
776
777 "ldr %[len], %[rseq_scratch2]\n\t"
778 "ldr %[dst], %[rseq_scratch1]\n\t"
779 "ldr %[src], %[rseq_scratch0]\n\t",
780 error2)
781 #endif
782 "8:\n\t"
783 :
784 : [cpu_id] "r" (cpu),
785 [current_cpu_id] "m" (__rseq_abi.cpu_id),
786 [rseq_cs] "m" (__rseq_abi.rseq_cs),
787
788 [v] "m" (*v),
789 [expect] "r" (expect),
790 [newv] "r" (newv),
791
792 [dst] "r" (dst),
793 [src] "r" (src),
794 [len] "r" (len),
795 [rseq_scratch0] "m" (rseq_scratch[0]),
796 [rseq_scratch1] "m" (rseq_scratch[1]),
797 [rseq_scratch2] "m" (rseq_scratch[2])
798 RSEQ_INJECT_INPUT
799 : "r0", "memory", "cc"
800 RSEQ_INJECT_CLOBBER
801 : abort, cmpfail
802 #ifdef RSEQ_COMPARE_TWICE
803 , error1, error2
804 #endif
805 );
806 rseq_workaround_gcc_asm_size_guess();
807 return 0;
808 abort:
809 rseq_workaround_gcc_asm_size_guess();
810 RSEQ_INJECT_FAILED
811 return -1;
812 cmpfail:
813 rseq_workaround_gcc_asm_size_guess();
814 return 1;
815 #ifdef RSEQ_COMPARE_TWICE
816 error1:
817 rseq_workaround_gcc_asm_size_guess();
818 rseq_bug("cpu_id comparison failed");
819 error2:
820 rseq_workaround_gcc_asm_size_guess();
821 rseq_bug("expected value comparison failed");
822 #endif
823 }
824
825 #endif