1 /* SPDX-License-Identifier: LGPL-2.1 OR MIT */
5 * (C) Copyright 2016-2018 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
6 * (C) Copyright 2016-2018 - Boqun Feng <boqun.feng@gmail.com>
10 * RSEQ_SIG is used with the following trap instruction:
12 * powerpc-be: 0f e5 00 0b twui r5,11
13 * powerpc64-le: 0b 00 e5 0f twui r5,11
14 * powerpc64-be: 0f e5 00 0b twui r5,11
17 #define RSEQ_SIG 0x0fe5000b
19 #define rseq_smp_mb() __asm__ __volatile__ ("sync" ::: "memory", "cc")
20 #define rseq_smp_lwsync() __asm__ __volatile__ ("lwsync" ::: "memory", "cc")
21 #define rseq_smp_rmb() rseq_smp_lwsync()
22 #define rseq_smp_wmb() rseq_smp_lwsync()
24 #define rseq_smp_load_acquire(p) \
26 __typeof(*p) ____p1 = RSEQ_READ_ONCE(*p); \
31 #define rseq_smp_acquire__after_ctrl_dep() rseq_smp_lwsync()
33 #define rseq_smp_store_release(p, v) \
36 RSEQ_WRITE_ONCE(*p, v); \
39 #ifdef RSEQ_SKIP_FASTPATH
40 #include "rseq-skip.h"
41 #else /* !RSEQ_SKIP_FASTPATH */
44 * The __rseq_cs_ptr_array and __rseq_cs sections can be used by debuggers to
45 * better handle single-stepping through the restartable critical sections.
50 #define STORE_WORD "std "
51 #define LOAD_WORD "ld "
52 #define LOADX_WORD "ldx "
53 #define CMP_WORD "cmpd "
55 #define __RSEQ_ASM_DEFINE_TABLE(label, version, flags, \
56 start_ip, post_commit_offset, abort_ip) \
57 ".pushsection __rseq_cs, \"aw\"\n\t" \
59 __rseq_str(label) ":\n\t" \
60 ".long " __rseq_str(version) ", " __rseq_str(flags) "\n\t" \
61 ".quad " __rseq_str(start_ip) ", " __rseq_str(post_commit_offset) ", " __rseq_str(abort_ip) "\n\t" \
63 ".pushsection __rseq_cs_ptr_array, \"aw\"\n\t" \
64 ".quad " __rseq_str(label) "b\n\t" \
67 #define RSEQ_ASM_STORE_RSEQ_CS(label, cs_label, rseq_cs) \
69 "lis %%r17, (" __rseq_str(cs_label) ")@highest\n\t" \
70 "ori %%r17, %%r17, (" __rseq_str(cs_label) ")@higher\n\t" \
71 "rldicr %%r17, %%r17, 32, 31\n\t" \
72 "oris %%r17, %%r17, (" __rseq_str(cs_label) ")@high\n\t" \
73 "ori %%r17, %%r17, (" __rseq_str(cs_label) ")@l\n\t" \
74 "std %%r17, %[" __rseq_str(rseq_cs) "]\n\t" \
75 __rseq_str(label) ":\n\t"
78 * Exit points of a rseq critical section consist of all instructions outside
79 * of the critical section where a critical section can either branch to or
80 * reach through the normal course of its execution. The abort IP and the
81 * post-commit IP are already part of the __rseq_cs section and should not be
82 * explicitly defined as additional exit points. Knowing all exit points is
83 * useful to assist debuggers stepping over the critical section.
85 #define RSEQ_ASM_DEFINE_EXIT_POINT(start_ip, exit_ip) \
86 ".pushsection __rseq_exit_point_array, \"aw\"\n\t" \
87 ".quad " __rseq_str(start_ip) ", " __rseq_str(exit_ip) "\n\t" \
90 #else /* #ifdef __PPC64__ */
92 #define STORE_WORD "stw "
93 #define LOAD_WORD "lwz "
94 #define LOADX_WORD "lwzx "
95 #define CMP_WORD "cmpw "
97 #define __RSEQ_ASM_DEFINE_TABLE(label, version, flags, \
98 start_ip, post_commit_offset, abort_ip) \
99 ".pushsection __rseq_cs, \"aw\"\n\t" \
101 __rseq_str(label) ":\n\t" \
102 ".long " __rseq_str(version) ", " __rseq_str(flags) "\n\t" \
103 /* 32-bit only supported on BE */ \
104 ".long 0x0, " __rseq_str(start_ip) ", 0x0, " __rseq_str(post_commit_offset) ", 0x0, " __rseq_str(abort_ip) "\n\t" \
106 ".pushsection __rseq_cs_ptr_array, \"aw\"\n\t" \
107 ".long 0x0, " __rseq_str(label) "b\n\t" \
111 * Exit points of a rseq critical section consist of all instructions outside
112 * of the critical section where a critical section can either branch to or
113 * reach through the normal course of its execution. The abort IP and the
114 * post-commit IP are already part of the __rseq_cs section and should not be
115 * explicitly defined as additional exit points. Knowing all exit points is
116 * useful to assist debuggers stepping over the critical section.
118 #define RSEQ_ASM_DEFINE_EXIT_POINT(start_ip, exit_ip) \
119 ".pushsection __rseq_exit_point_array, \"aw\"\n\t" \
120 /* 32-bit only supported on BE */ \
121 ".long 0x0, " __rseq_str(start_ip) ", 0x0, " __rseq_str(exit_ip) "\n\t" \
124 #define RSEQ_ASM_STORE_RSEQ_CS(label, cs_label, rseq_cs) \
126 "lis %%r17, (" __rseq_str(cs_label) ")@ha\n\t" \
127 "addi %%r17, %%r17, (" __rseq_str(cs_label) ")@l\n\t" \
128 "stw %%r17, %[" __rseq_str(rseq_cs) "]\n\t" \
129 __rseq_str(label) ":\n\t"
131 #endif /* #ifdef __PPC64__ */
133 #define RSEQ_ASM_DEFINE_TABLE(label, start_ip, post_commit_ip, abort_ip) \
134 __RSEQ_ASM_DEFINE_TABLE(label, 0x0, 0x0, start_ip, \
135 (post_commit_ip - start_ip), abort_ip)
137 #define RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, label) \
139 "lwz %%r17, %[" __rseq_str(current_cpu_id) "]\n\t" \
140 "cmpw cr7, %[" __rseq_str(cpu_id) "], %%r17\n\t" \
141 "bne- cr7, " __rseq_str(label) "\n\t"
143 #define RSEQ_ASM_DEFINE_ABORT(label, abort_label) \
144 ".pushsection __rseq_failure, \"ax\"\n\t" \
145 ".long " __rseq_str(RSEQ_SIG) "\n\t" \
146 __rseq_str(label) ":\n\t" \
147 "b %l[" __rseq_str(abort_label) "]\n\t" \
151 * RSEQ_ASM_OPs: asm operations for rseq
152 * RSEQ_ASM_OP_R_*: has hard-code registers in it
153 * RSEQ_ASM_OP_* (else): doesn't have hard-code registers(unless cr7)
155 #define RSEQ_ASM_OP_CMPEQ(var, expect, label) \
156 LOAD_WORD "%%r17, %[" __rseq_str(var) "]\n\t" \
157 CMP_WORD "cr7, %%r17, %[" __rseq_str(expect) "]\n\t" \
158 "bne- cr7, " __rseq_str(label) "\n\t"
160 #define RSEQ_ASM_OP_CMPNE(var, expectnot, label) \
161 LOAD_WORD "%%r17, %[" __rseq_str(var) "]\n\t" \
162 CMP_WORD "cr7, %%r17, %[" __rseq_str(expectnot) "]\n\t" \
163 "beq- cr7, " __rseq_str(label) "\n\t"
165 #define RSEQ_ASM_OP_STORE(value, var) \
166 STORE_WORD "%[" __rseq_str(value) "], %[" __rseq_str(var) "]\n\t"
168 /* Load @var to r17 */
169 #define RSEQ_ASM_OP_R_LOAD(var) \
170 LOAD_WORD "%%r17, %[" __rseq_str(var) "]\n\t"
172 /* Store r17 to @var */
173 #define RSEQ_ASM_OP_R_STORE(var) \
174 STORE_WORD "%%r17, %[" __rseq_str(var) "]\n\t"
176 /* Add @count to r17 */
177 #define RSEQ_ASM_OP_R_ADD(count) \
178 "add %%r17, %[" __rseq_str(count) "], %%r17\n\t"
180 /* Load (r17 + voffp) to r17 */
181 #define RSEQ_ASM_OP_R_LOADX(voffp) \
182 LOADX_WORD "%%r17, %[" __rseq_str(voffp) "], %%r17\n\t"
184 /* TODO: implement a faster memcpy. */
185 #define RSEQ_ASM_OP_R_MEMCPY() \
186 "cmpdi %%r19, 0\n\t" \
188 "addi %%r20, %%r20, -1\n\t" \
189 "addi %%r21, %%r21, -1\n\t" \
191 "lbzu %%r18, 1(%%r20)\n\t" \
192 "stbu %%r18, 1(%%r21)\n\t" \
193 "addi %%r19, %%r19, -1\n\t" \
194 "cmpdi %%r19, 0\n\t" \
198 #define RSEQ_ASM_OP_R_FINAL_STORE(var, post_commit_label) \
199 STORE_WORD "%%r17, %[" __rseq_str(var) "]\n\t" \
200 __rseq_str(post_commit_label) ":\n\t"
202 #define RSEQ_ASM_OP_FINAL_STORE(value, var, post_commit_label) \
203 STORE_WORD "%[" __rseq_str(value) "], %[" __rseq_str(var) "]\n\t" \
204 __rseq_str(post_commit_label) ":\n\t"
206 static inline __attribute__((always_inline))
207 int rseq_cmpeqv_storev(intptr_t *v, intptr_t expect, intptr_t newv, int cpu)
211 __asm__ __volatile__ goto (
212 RSEQ_ASM_DEFINE_TABLE(3, 1f, 2f, 4f) /* start, commit, abort */
213 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[cmpfail])
214 #ifdef RSEQ_COMPARE_TWICE
215 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error1])
216 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error2])
218 /* Start rseq by storing table entry pointer into rseq_cs. */
219 RSEQ_ASM_STORE_RSEQ_CS(1, 3b, rseq_cs)
221 RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f)
223 /* cmp @v equal to @expect */
224 RSEQ_ASM_OP_CMPEQ(v, expect, %l[cmpfail])
226 #ifdef RSEQ_COMPARE_TWICE
228 RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1])
229 /* cmp @v equal to @expect */
230 RSEQ_ASM_OP_CMPEQ(v, expect, %l[error2])
233 RSEQ_ASM_OP_FINAL_STORE(newv, v, 2)
235 RSEQ_ASM_DEFINE_ABORT(4, abort)
236 : /* gcc asm goto does not allow outputs */
237 : [cpu_id] "r" (cpu),
238 [current_cpu_id] "m" (__rseq_abi.cpu_id),
239 [rseq_cs] "m" (__rseq_abi.rseq_cs),
241 [expect] "r" (expect),
244 : "memory", "cc", "r17"
247 #ifdef RSEQ_COMPARE_TWICE
257 #ifdef RSEQ_COMPARE_TWICE
259 rseq_bug("cpu_id comparison failed");
261 rseq_bug("expected value comparison failed");
265 static inline __attribute__((always_inline))
266 int rseq_cmpnev_storeoffp_load(intptr_t *v, intptr_t expectnot,
267 off_t voffp, intptr_t *load, int cpu)
271 __asm__ __volatile__ goto (
272 RSEQ_ASM_DEFINE_TABLE(3, 1f, 2f, 4f) /* start, commit, abort */
273 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[cmpfail])
274 #ifdef RSEQ_COMPARE_TWICE
275 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error1])
276 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error2])
278 /* Start rseq by storing table entry pointer into rseq_cs. */
279 RSEQ_ASM_STORE_RSEQ_CS(1, 3b, rseq_cs)
281 RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f)
283 /* cmp @v not equal to @expectnot */
284 RSEQ_ASM_OP_CMPNE(v, expectnot, %l[cmpfail])
286 #ifdef RSEQ_COMPARE_TWICE
288 RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1])
289 /* cmp @v not equal to @expectnot */
290 RSEQ_ASM_OP_CMPNE(v, expectnot, %l[error2])
292 /* load the value of @v */
293 RSEQ_ASM_OP_R_LOAD(v)
294 /* store it in @load */
295 RSEQ_ASM_OP_R_STORE(load)
296 /* dereference voffp(v) */
297 RSEQ_ASM_OP_R_LOADX(voffp)
298 /* final store the value at voffp(v) */
299 RSEQ_ASM_OP_R_FINAL_STORE(v, 2)
301 RSEQ_ASM_DEFINE_ABORT(4, abort)
302 : /* gcc asm goto does not allow outputs */
303 : [cpu_id] "r" (cpu),
304 [current_cpu_id] "m" (__rseq_abi.cpu_id),
305 [rseq_cs] "m" (__rseq_abi.rseq_cs),
306 /* final store input */
308 [expectnot] "r" (expectnot),
312 : "memory", "cc", "r17"
315 #ifdef RSEQ_COMPARE_TWICE
325 #ifdef RSEQ_COMPARE_TWICE
327 rseq_bug("cpu_id comparison failed");
329 rseq_bug("expected value comparison failed");
333 static inline __attribute__((always_inline))
334 int rseq_addv(intptr_t *v, intptr_t count, int cpu)
338 __asm__ __volatile__ goto (
339 RSEQ_ASM_DEFINE_TABLE(3, 1f, 2f, 4f) /* start, commit, abort */
340 #ifdef RSEQ_COMPARE_TWICE
341 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error1])
343 /* Start rseq by storing table entry pointer into rseq_cs. */
344 RSEQ_ASM_STORE_RSEQ_CS(1, 3b, rseq_cs)
346 RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f)
348 #ifdef RSEQ_COMPARE_TWICE
350 RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1])
352 /* load the value of @v */
353 RSEQ_ASM_OP_R_LOAD(v)
354 /* add @count to it */
355 RSEQ_ASM_OP_R_ADD(count)
357 RSEQ_ASM_OP_R_FINAL_STORE(v, 2)
359 RSEQ_ASM_DEFINE_ABORT(4, abort)
360 : /* gcc asm goto does not allow outputs */
361 : [cpu_id] "r" (cpu),
362 [current_cpu_id] "m" (__rseq_abi.cpu_id),
363 [rseq_cs] "m" (__rseq_abi.rseq_cs),
364 /* final store input */
368 : "memory", "cc", "r17"
371 #ifdef RSEQ_COMPARE_TWICE
379 #ifdef RSEQ_COMPARE_TWICE
381 rseq_bug("cpu_id comparison failed");
385 static inline __attribute__((always_inline))
386 int rseq_cmpeqv_trystorev_storev(intptr_t *v, intptr_t expect,
387 intptr_t *v2, intptr_t newv2,
388 intptr_t newv, int cpu)
392 __asm__ __volatile__ goto (
393 RSEQ_ASM_DEFINE_TABLE(3, 1f, 2f, 4f) /* start, commit, abort */
394 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[cmpfail])
395 #ifdef RSEQ_COMPARE_TWICE
396 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error1])
397 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error2])
399 /* Start rseq by storing table entry pointer into rseq_cs. */
400 RSEQ_ASM_STORE_RSEQ_CS(1, 3b, rseq_cs)
402 RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f)
404 /* cmp @v equal to @expect */
405 RSEQ_ASM_OP_CMPEQ(v, expect, %l[cmpfail])
407 #ifdef RSEQ_COMPARE_TWICE
409 RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1])
410 /* cmp @v equal to @expect */
411 RSEQ_ASM_OP_CMPEQ(v, expect, %l[error2])
414 RSEQ_ASM_OP_STORE(newv2, v2)
417 RSEQ_ASM_OP_FINAL_STORE(newv, v, 2)
419 RSEQ_ASM_DEFINE_ABORT(4, abort)
420 : /* gcc asm goto does not allow outputs */
421 : [cpu_id] "r" (cpu),
422 [current_cpu_id] "m" (__rseq_abi.cpu_id),
423 [rseq_cs] "m" (__rseq_abi.rseq_cs),
424 /* try store input */
427 /* final store input */
429 [expect] "r" (expect),
432 : "memory", "cc", "r17"
435 #ifdef RSEQ_COMPARE_TWICE
445 #ifdef RSEQ_COMPARE_TWICE
447 rseq_bug("cpu_id comparison failed");
449 rseq_bug("expected value comparison failed");
453 static inline __attribute__((always_inline))
454 int rseq_cmpeqv_trystorev_storev_release(intptr_t *v, intptr_t expect,
455 intptr_t *v2, intptr_t newv2,
456 intptr_t newv, int cpu)
460 __asm__ __volatile__ goto (
461 RSEQ_ASM_DEFINE_TABLE(3, 1f, 2f, 4f) /* start, commit, abort */
462 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[cmpfail])
463 #ifdef RSEQ_COMPARE_TWICE
464 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error1])
465 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error2])
467 /* Start rseq by storing table entry pointer into rseq_cs. */
468 RSEQ_ASM_STORE_RSEQ_CS(1, 3b, rseq_cs)
470 RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f)
472 /* cmp @v equal to @expect */
473 RSEQ_ASM_OP_CMPEQ(v, expect, %l[cmpfail])
475 #ifdef RSEQ_COMPARE_TWICE
477 RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1])
478 /* cmp @v equal to @expect */
479 RSEQ_ASM_OP_CMPEQ(v, expect, %l[error2])
482 RSEQ_ASM_OP_STORE(newv2, v2)
487 RSEQ_ASM_OP_FINAL_STORE(newv, v, 2)
489 RSEQ_ASM_DEFINE_ABORT(4, abort)
490 : /* gcc asm goto does not allow outputs */
491 : [cpu_id] "r" (cpu),
492 [current_cpu_id] "m" (__rseq_abi.cpu_id),
493 [rseq_cs] "m" (__rseq_abi.rseq_cs),
494 /* try store input */
497 /* final store input */
499 [expect] "r" (expect),
502 : "memory", "cc", "r17"
505 #ifdef RSEQ_COMPARE_TWICE
515 #ifdef RSEQ_COMPARE_TWICE
517 rseq_bug("cpu_id comparison failed");
519 rseq_bug("expected value comparison failed");
523 static inline __attribute__((always_inline))
524 int rseq_cmpeqv_cmpeqv_storev(intptr_t *v, intptr_t expect,
525 intptr_t *v2, intptr_t expect2,
526 intptr_t newv, int cpu)
530 __asm__ __volatile__ goto (
531 RSEQ_ASM_DEFINE_TABLE(3, 1f, 2f, 4f) /* start, commit, abort */
532 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[cmpfail])
533 #ifdef RSEQ_COMPARE_TWICE
534 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error1])
535 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error2])
536 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error3])
538 /* Start rseq by storing table entry pointer into rseq_cs. */
539 RSEQ_ASM_STORE_RSEQ_CS(1, 3b, rseq_cs)
541 RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f)
543 /* cmp @v equal to @expect */
544 RSEQ_ASM_OP_CMPEQ(v, expect, %l[cmpfail])
546 /* cmp @v2 equal to @expct2 */
547 RSEQ_ASM_OP_CMPEQ(v2, expect2, %l[cmpfail])
549 #ifdef RSEQ_COMPARE_TWICE
551 RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1])
552 /* cmp @v equal to @expect */
553 RSEQ_ASM_OP_CMPEQ(v, expect, %l[error2])
554 /* cmp @v2 equal to @expct2 */
555 RSEQ_ASM_OP_CMPEQ(v2, expect2, %l[error3])
558 RSEQ_ASM_OP_FINAL_STORE(newv, v, 2)
560 RSEQ_ASM_DEFINE_ABORT(4, abort)
561 : /* gcc asm goto does not allow outputs */
562 : [cpu_id] "r" (cpu),
563 [current_cpu_id] "m" (__rseq_abi.cpu_id),
564 [rseq_cs] "m" (__rseq_abi.rseq_cs),
567 [expect2] "r" (expect2),
568 /* final store input */
570 [expect] "r" (expect),
573 : "memory", "cc", "r17"
576 #ifdef RSEQ_COMPARE_TWICE
577 , error1, error2, error3
586 #ifdef RSEQ_COMPARE_TWICE
588 rseq_bug("cpu_id comparison failed");
590 rseq_bug("1st expected value comparison failed");
592 rseq_bug("2nd expected value comparison failed");
596 static inline __attribute__((always_inline))
597 int rseq_cmpeqv_trymemcpy_storev(intptr_t *v, intptr_t expect,
598 void *dst, void *src, size_t len,
599 intptr_t newv, int cpu)
603 __asm__ __volatile__ goto (
604 RSEQ_ASM_DEFINE_TABLE(3, 1f, 2f, 4f) /* start, commit, abort */
605 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[cmpfail])
606 #ifdef RSEQ_COMPARE_TWICE
607 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error1])
608 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error2])
610 /* setup for mempcy */
611 "mr %%r19, %[len]\n\t"
612 "mr %%r20, %[src]\n\t"
613 "mr %%r21, %[dst]\n\t"
614 /* Start rseq by storing table entry pointer into rseq_cs. */
615 RSEQ_ASM_STORE_RSEQ_CS(1, 3b, rseq_cs)
617 RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f)
619 /* cmp @v equal to @expect */
620 RSEQ_ASM_OP_CMPEQ(v, expect, %l[cmpfail])
622 #ifdef RSEQ_COMPARE_TWICE
624 RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1])
625 /* cmp @v equal to @expect */
626 RSEQ_ASM_OP_CMPEQ(v, expect, %l[error2])
629 RSEQ_ASM_OP_R_MEMCPY()
632 RSEQ_ASM_OP_FINAL_STORE(newv, v, 2)
635 RSEQ_ASM_DEFINE_ABORT(4, abort)
636 : /* gcc asm goto does not allow outputs */
637 : [cpu_id] "r" (cpu),
638 [current_cpu_id] "m" (__rseq_abi.cpu_id),
639 [rseq_cs] "m" (__rseq_abi.rseq_cs),
640 /* final store input */
642 [expect] "r" (expect),
644 /* try memcpy input */
649 : "memory", "cc", "r17", "r18", "r19", "r20", "r21"
652 #ifdef RSEQ_COMPARE_TWICE
662 #ifdef RSEQ_COMPARE_TWICE
664 rseq_bug("cpu_id comparison failed");
666 rseq_bug("expected value comparison failed");
670 static inline __attribute__((always_inline))
671 int rseq_cmpeqv_trymemcpy_storev_release(intptr_t *v, intptr_t expect,
672 void *dst, void *src, size_t len,
673 intptr_t newv, int cpu)
677 __asm__ __volatile__ goto (
678 RSEQ_ASM_DEFINE_TABLE(3, 1f, 2f, 4f) /* start, commit, abort */
679 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[cmpfail])
680 #ifdef RSEQ_COMPARE_TWICE
681 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error1])
682 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error2])
684 /* setup for mempcy */
685 "mr %%r19, %[len]\n\t"
686 "mr %%r20, %[src]\n\t"
687 "mr %%r21, %[dst]\n\t"
688 /* Start rseq by storing table entry pointer into rseq_cs. */
689 RSEQ_ASM_STORE_RSEQ_CS(1, 3b, rseq_cs)
691 RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f)
693 /* cmp @v equal to @expect */
694 RSEQ_ASM_OP_CMPEQ(v, expect, %l[cmpfail])
696 #ifdef RSEQ_COMPARE_TWICE
698 RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1])
699 /* cmp @v equal to @expect */
700 RSEQ_ASM_OP_CMPEQ(v, expect, %l[error2])
703 RSEQ_ASM_OP_R_MEMCPY()
708 RSEQ_ASM_OP_FINAL_STORE(newv, v, 2)
711 RSEQ_ASM_DEFINE_ABORT(4, abort)
712 : /* gcc asm goto does not allow outputs */
713 : [cpu_id] "r" (cpu),
714 [current_cpu_id] "m" (__rseq_abi.cpu_id),
715 [rseq_cs] "m" (__rseq_abi.rseq_cs),
716 /* final store input */
718 [expect] "r" (expect),
720 /* try memcpy input */
725 : "memory", "cc", "r17", "r18", "r19", "r20", "r21"
728 #ifdef RSEQ_COMPARE_TWICE
738 #ifdef RSEQ_COMPARE_TWICE
740 rseq_bug("cpu_id comparison failed");
742 rseq_bug("expected value comparison failed");
751 #endif /* !RSEQ_SKIP_FASTPATH */