Clarify licensing and update to SPDX 3.0 identifiers
[librseq.git] / include / rseq / rseq-ppc.h
CommitLineData
744d0b8b 1/* SPDX-License-Identifier: LGPL-2.1-only OR MIT */
784b0012
MD
2/*
3 * rseq-ppc.h
4 *
5 * (C) Copyright 2016-2018 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
6 * (C) Copyright 2016-2018 - Boqun Feng <boqun.feng@gmail.com>
7 */
8
9#define RSEQ_SIG 0x53053053
10
11#define rseq_smp_mb() __asm__ __volatile__ ("sync" ::: "memory", "cc")
12#define rseq_smp_lwsync() __asm__ __volatile__ ("lwsync" ::: "memory", "cc")
13#define rseq_smp_rmb() rseq_smp_lwsync()
14#define rseq_smp_wmb() rseq_smp_lwsync()
15
16#define rseq_smp_load_acquire(p) \
17__extension__ ({ \
18 __typeof(*p) ____p1 = RSEQ_READ_ONCE(*p); \
19 rseq_smp_lwsync(); \
20 ____p1; \
21})
22
23#define rseq_smp_acquire__after_ctrl_dep() rseq_smp_lwsync()
24
25#define rseq_smp_store_release(p, v) \
26do { \
27 rseq_smp_lwsync(); \
28 RSEQ_WRITE_ONCE(*p, v); \
29} while (0)
30
31#ifdef RSEQ_SKIP_FASTPATH
32#include "rseq-skip.h"
33#else /* !RSEQ_SKIP_FASTPATH */
34
35/*
36 * The __rseq_table section can be used by debuggers to better handle
37 * single-stepping through the restartable critical sections.
38 */
39
40#ifdef __PPC64__
41
42#define STORE_WORD "std "
43#define LOAD_WORD "ld "
44#define LOADX_WORD "ldx "
45#define CMP_WORD "cmpd "
46
47#define __RSEQ_ASM_DEFINE_TABLE(label, version, flags, \
48 start_ip, post_commit_offset, abort_ip) \
49 ".pushsection __rseq_table, \"aw\"\n\t" \
50 ".balign 32\n\t" \
51 __rseq_str(label) ":\n\t" \
52 ".long " __rseq_str(version) ", " __rseq_str(flags) "\n\t" \
53 ".quad " __rseq_str(start_ip) ", " __rseq_str(post_commit_offset) ", " __rseq_str(abort_ip) "\n\t" \
54 ".popsection\n\t"
55
56#define RSEQ_ASM_STORE_RSEQ_CS(label, cs_label, rseq_cs) \
57 RSEQ_INJECT_ASM(1) \
58 "lis %%r17, (" __rseq_str(cs_label) ")@highest\n\t" \
59 "ori %%r17, %%r17, (" __rseq_str(cs_label) ")@higher\n\t" \
60 "rldicr %%r17, %%r17, 32, 31\n\t" \
61 "oris %%r17, %%r17, (" __rseq_str(cs_label) ")@high\n\t" \
62 "ori %%r17, %%r17, (" __rseq_str(cs_label) ")@l\n\t" \
63 "std %%r17, %[" __rseq_str(rseq_cs) "]\n\t" \
64 __rseq_str(label) ":\n\t"
65
66#else /* #ifdef __PPC64__ */
67
68#define STORE_WORD "stw "
69#define LOAD_WORD "lwz "
70#define LOADX_WORD "lwzx "
71#define CMP_WORD "cmpw "
72
73#define __RSEQ_ASM_DEFINE_TABLE(label, version, flags, \
74 start_ip, post_commit_offset, abort_ip) \
75 ".pushsection __rseq_table, \"aw\"\n\t" \
76 ".balign 32\n\t" \
77 __rseq_str(label) ":\n\t" \
78 ".long " __rseq_str(version) ", " __rseq_str(flags) "\n\t" \
79 /* 32-bit only supported on BE */ \
80 ".long 0x0, " __rseq_str(start_ip) ", 0x0, " __rseq_str(post_commit_offset) ", 0x0, " __rseq_str(abort_ip) "\n\t" \
81 ".popsection\n\t"
82
83#define RSEQ_ASM_STORE_RSEQ_CS(label, cs_label, rseq_cs) \
84 RSEQ_INJECT_ASM(1) \
85 "lis %%r17, (" __rseq_str(cs_label) ")@ha\n\t" \
86 "addi %%r17, %%r17, (" __rseq_str(cs_label) ")@l\n\t" \
87 "stw %%r17, %[" __rseq_str(rseq_cs) "]\n\t" \
88 __rseq_str(label) ":\n\t"
89
90#endif /* #ifdef __PPC64__ */
91
92#define RSEQ_ASM_DEFINE_TABLE(label, start_ip, post_commit_ip, abort_ip) \
93 __RSEQ_ASM_DEFINE_TABLE(label, 0x0, 0x0, start_ip, \
94 (post_commit_ip - start_ip), abort_ip)
95
96#define RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, label) \
97 RSEQ_INJECT_ASM(2) \
98 "lwz %%r17, %[" __rseq_str(current_cpu_id) "]\n\t" \
99 "cmpw cr7, %[" __rseq_str(cpu_id) "], %%r17\n\t" \
100 "bne- cr7, " __rseq_str(label) "\n\t"
101
102#define RSEQ_ASM_DEFINE_ABORT(label, abort_label) \
103 ".pushsection __rseq_failure, \"ax\"\n\t" \
104 ".long " __rseq_str(RSEQ_SIG) "\n\t" \
105 __rseq_str(label) ":\n\t" \
106 "b %l[" __rseq_str(abort_label) "]\n\t" \
107 ".popsection\n\t"
108
109/*
110 * RSEQ_ASM_OPs: asm operations for rseq
111 * RSEQ_ASM_OP_R_*: has hard-code registers in it
112 * RSEQ_ASM_OP_* (else): doesn't have hard-code registers(unless cr7)
113 */
114#define RSEQ_ASM_OP_CMPEQ(var, expect, label) \
115 LOAD_WORD "%%r17, %[" __rseq_str(var) "]\n\t" \
116 CMP_WORD "cr7, %%r17, %[" __rseq_str(expect) "]\n\t" \
117 "bne- cr7, " __rseq_str(label) "\n\t"
118
119#define RSEQ_ASM_OP_CMPNE(var, expectnot, label) \
120 LOAD_WORD "%%r17, %[" __rseq_str(var) "]\n\t" \
121 CMP_WORD "cr7, %%r17, %[" __rseq_str(expectnot) "]\n\t" \
122 "beq- cr7, " __rseq_str(label) "\n\t"
123
124#define RSEQ_ASM_OP_STORE(value, var) \
125 STORE_WORD "%[" __rseq_str(value) "], %[" __rseq_str(var) "]\n\t"
126
127/* Load @var to r17 */
128#define RSEQ_ASM_OP_R_LOAD(var) \
129 LOAD_WORD "%%r17, %[" __rseq_str(var) "]\n\t"
130
131/* Store r17 to @var */
132#define RSEQ_ASM_OP_R_STORE(var) \
133 STORE_WORD "%%r17, %[" __rseq_str(var) "]\n\t"
134
135/* Add @count to r17 */
136#define RSEQ_ASM_OP_R_ADD(count) \
137 "add %%r17, %[" __rseq_str(count) "], %%r17\n\t"
138
139/* Load (r17 + voffp) to r17 */
140#define RSEQ_ASM_OP_R_LOADX(voffp) \
141 LOADX_WORD "%%r17, %[" __rseq_str(voffp) "], %%r17\n\t"
142
143/* TODO: implement a faster memcpy. */
144#define RSEQ_ASM_OP_R_MEMCPY() \
145 "cmpdi %%r19, 0\n\t" \
146 "beq 333f\n\t" \
147 "addi %%r20, %%r20, -1\n\t" \
148 "addi %%r21, %%r21, -1\n\t" \
149 "222:\n\t" \
150 "lbzu %%r18, 1(%%r20)\n\t" \
151 "stbu %%r18, 1(%%r21)\n\t" \
152 "addi %%r19, %%r19, -1\n\t" \
153 "cmpdi %%r19, 0\n\t" \
154 "bne 222b\n\t" \
155 "333:\n\t" \
156
157#define RSEQ_ASM_OP_R_FINAL_STORE(var, post_commit_label) \
158 STORE_WORD "%%r17, %[" __rseq_str(var) "]\n\t" \
159 __rseq_str(post_commit_label) ":\n\t"
160
161#define RSEQ_ASM_OP_FINAL_STORE(value, var, post_commit_label) \
162 STORE_WORD "%[" __rseq_str(value) "], %[" __rseq_str(var) "]\n\t" \
163 __rseq_str(post_commit_label) ":\n\t"
164
165static inline __attribute__((always_inline))
166int rseq_cmpeqv_storev(intptr_t *v, intptr_t expect, intptr_t newv, int cpu)
167{
168 RSEQ_INJECT_C(9)
169
170 __asm__ __volatile__ goto (
171 RSEQ_ASM_DEFINE_TABLE(3, 1f, 2f, 4f) /* start, commit, abort */
172 /* Start rseq by storing table entry pointer into rseq_cs. */
173 RSEQ_ASM_STORE_RSEQ_CS(1, 3b, rseq_cs)
174 /* cmp cpuid */
175 RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f)
176 RSEQ_INJECT_ASM(3)
177 /* cmp @v equal to @expect */
178 RSEQ_ASM_OP_CMPEQ(v, expect, %l[cmpfail])
179 RSEQ_INJECT_ASM(4)
180#ifdef RSEQ_COMPARE_TWICE
181 /* cmp cpuid */
182 RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1])
183 /* cmp @v equal to @expect */
184 RSEQ_ASM_OP_CMPEQ(v, expect, %l[error2])
185#endif
186 /* final store */
187 RSEQ_ASM_OP_FINAL_STORE(newv, v, 2)
188 RSEQ_INJECT_ASM(5)
189 RSEQ_ASM_DEFINE_ABORT(4, abort)
190 : /* gcc asm goto does not allow outputs */
191 : [cpu_id] "r" (cpu),
192 [current_cpu_id] "m" (__rseq_abi.cpu_id),
193 [rseq_cs] "m" (__rseq_abi.rseq_cs),
194 [v] "m" (*v),
195 [expect] "r" (expect),
196 [newv] "r" (newv)
197 RSEQ_INJECT_INPUT
198 : "memory", "cc", "r17"
199 RSEQ_INJECT_CLOBBER
200 : abort, cmpfail
201#ifdef RSEQ_COMPARE_TWICE
202 , error1, error2
203#endif
204 );
205 return 0;
206abort:
207 RSEQ_INJECT_FAILED
208 return -1;
209cmpfail:
210 return 1;
211#ifdef RSEQ_COMPARE_TWICE
212error1:
213 rseq_bug("cpu_id comparison failed");
214error2:
215 rseq_bug("expected value comparison failed");
216#endif
217}
218
219static inline __attribute__((always_inline))
220int rseq_cmpnev_storeoffp_load(intptr_t *v, intptr_t expectnot,
221 off_t voffp, intptr_t *load, int cpu)
222{
223 RSEQ_INJECT_C(9)
224
225 __asm__ __volatile__ goto (
226 RSEQ_ASM_DEFINE_TABLE(3, 1f, 2f, 4f) /* start, commit, abort */
227 /* Start rseq by storing table entry pointer into rseq_cs. */
228 RSEQ_ASM_STORE_RSEQ_CS(1, 3b, rseq_cs)
229 /* cmp cpuid */
230 RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f)
231 RSEQ_INJECT_ASM(3)
232 /* cmp @v not equal to @expectnot */
233 RSEQ_ASM_OP_CMPNE(v, expectnot, %l[cmpfail])
234 RSEQ_INJECT_ASM(4)
235#ifdef RSEQ_COMPARE_TWICE
236 /* cmp cpuid */
237 RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1])
238 /* cmp @v not equal to @expectnot */
239 RSEQ_ASM_OP_CMPNE(v, expectnot, %l[error2])
240#endif
241 /* load the value of @v */
242 RSEQ_ASM_OP_R_LOAD(v)
243 /* store it in @load */
244 RSEQ_ASM_OP_R_STORE(load)
245 /* dereference voffp(v) */
246 RSEQ_ASM_OP_R_LOADX(voffp)
247 /* final store the value at voffp(v) */
248 RSEQ_ASM_OP_R_FINAL_STORE(v, 2)
249 RSEQ_INJECT_ASM(5)
250 RSEQ_ASM_DEFINE_ABORT(4, abort)
251 : /* gcc asm goto does not allow outputs */
252 : [cpu_id] "r" (cpu),
253 [current_cpu_id] "m" (__rseq_abi.cpu_id),
254 [rseq_cs] "m" (__rseq_abi.rseq_cs),
255 /* final store input */
256 [v] "m" (*v),
257 [expectnot] "r" (expectnot),
258 [voffp] "b" (voffp),
259 [load] "m" (*load)
260 RSEQ_INJECT_INPUT
261 : "memory", "cc", "r17"
262 RSEQ_INJECT_CLOBBER
263 : abort, cmpfail
264#ifdef RSEQ_COMPARE_TWICE
265 , error1, error2
266#endif
267 );
268 return 0;
269abort:
270 RSEQ_INJECT_FAILED
271 return -1;
272cmpfail:
273 return 1;
274#ifdef RSEQ_COMPARE_TWICE
275error1:
276 rseq_bug("cpu_id comparison failed");
277error2:
278 rseq_bug("expected value comparison failed");
279#endif
280}
281
282static inline __attribute__((always_inline))
283int rseq_addv(intptr_t *v, intptr_t count, int cpu)
284{
285 RSEQ_INJECT_C(9)
286
287 __asm__ __volatile__ goto (
288 RSEQ_ASM_DEFINE_TABLE(3, 1f, 2f, 4f) /* start, commit, abort */
289 /* Start rseq by storing table entry pointer into rseq_cs. */
290 RSEQ_ASM_STORE_RSEQ_CS(1, 3b, rseq_cs)
291 /* cmp cpuid */
292 RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f)
293 RSEQ_INJECT_ASM(3)
294#ifdef RSEQ_COMPARE_TWICE
295 /* cmp cpuid */
296 RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1])
297#endif
298 /* load the value of @v */
299 RSEQ_ASM_OP_R_LOAD(v)
300 /* add @count to it */
301 RSEQ_ASM_OP_R_ADD(count)
302 /* final store */
303 RSEQ_ASM_OP_R_FINAL_STORE(v, 2)
304 RSEQ_INJECT_ASM(4)
305 RSEQ_ASM_DEFINE_ABORT(4, abort)
306 : /* gcc asm goto does not allow outputs */
307 : [cpu_id] "r" (cpu),
308 [current_cpu_id] "m" (__rseq_abi.cpu_id),
309 [rseq_cs] "m" (__rseq_abi.rseq_cs),
310 /* final store input */
311 [v] "m" (*v),
312 [count] "r" (count)
313 RSEQ_INJECT_INPUT
314 : "memory", "cc", "r17"
315 RSEQ_INJECT_CLOBBER
316 : abort
317#ifdef RSEQ_COMPARE_TWICE
318 , error1
319#endif
320 );
321 return 0;
322abort:
323 RSEQ_INJECT_FAILED
324 return -1;
325#ifdef RSEQ_COMPARE_TWICE
326error1:
327 rseq_bug("cpu_id comparison failed");
328#endif
329}
330
331static inline __attribute__((always_inline))
332int rseq_cmpeqv_trystorev_storev(intptr_t *v, intptr_t expect,
333 intptr_t *v2, intptr_t newv2,
334 intptr_t newv, int cpu)
335{
336 RSEQ_INJECT_C(9)
337
338 __asm__ __volatile__ goto (
339 RSEQ_ASM_DEFINE_TABLE(3, 1f, 2f, 4f) /* start, commit, abort */
340 /* Start rseq by storing table entry pointer into rseq_cs. */
341 RSEQ_ASM_STORE_RSEQ_CS(1, 3b, rseq_cs)
342 /* cmp cpuid */
343 RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f)
344 RSEQ_INJECT_ASM(3)
345 /* cmp @v equal to @expect */
346 RSEQ_ASM_OP_CMPEQ(v, expect, %l[cmpfail])
347 RSEQ_INJECT_ASM(4)
348#ifdef RSEQ_COMPARE_TWICE
349 /* cmp cpuid */
350 RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1])
351 /* cmp @v equal to @expect */
352 RSEQ_ASM_OP_CMPEQ(v, expect, %l[error2])
353#endif
354 /* try store */
355 RSEQ_ASM_OP_STORE(newv2, v2)
356 RSEQ_INJECT_ASM(5)
357 /* final store */
358 RSEQ_ASM_OP_FINAL_STORE(newv, v, 2)
359 RSEQ_INJECT_ASM(6)
360 RSEQ_ASM_DEFINE_ABORT(4, abort)
361 : /* gcc asm goto does not allow outputs */
362 : [cpu_id] "r" (cpu),
363 [current_cpu_id] "m" (__rseq_abi.cpu_id),
364 [rseq_cs] "m" (__rseq_abi.rseq_cs),
365 /* try store input */
366 [v2] "m" (*v2),
367 [newv2] "r" (newv2),
368 /* final store input */
369 [v] "m" (*v),
370 [expect] "r" (expect),
371 [newv] "r" (newv)
372 RSEQ_INJECT_INPUT
373 : "memory", "cc", "r17"
374 RSEQ_INJECT_CLOBBER
375 : abort, cmpfail
376#ifdef RSEQ_COMPARE_TWICE
377 , error1, error2
378#endif
379 );
380 return 0;
381abort:
382 RSEQ_INJECT_FAILED
383 return -1;
384cmpfail:
385 return 1;
386#ifdef RSEQ_COMPARE_TWICE
387error1:
388 rseq_bug("cpu_id comparison failed");
389error2:
390 rseq_bug("expected value comparison failed");
391#endif
392}
393
394static inline __attribute__((always_inline))
395int rseq_cmpeqv_trystorev_storev_release(intptr_t *v, intptr_t expect,
396 intptr_t *v2, intptr_t newv2,
397 intptr_t newv, int cpu)
398{
399 RSEQ_INJECT_C(9)
400
401 __asm__ __volatile__ goto (
402 RSEQ_ASM_DEFINE_TABLE(3, 1f, 2f, 4f) /* start, commit, abort */
403 /* Start rseq by storing table entry pointer into rseq_cs. */
404 RSEQ_ASM_STORE_RSEQ_CS(1, 3b, rseq_cs)
405 /* cmp cpuid */
406 RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f)
407 RSEQ_INJECT_ASM(3)
408 /* cmp @v equal to @expect */
409 RSEQ_ASM_OP_CMPEQ(v, expect, %l[cmpfail])
410 RSEQ_INJECT_ASM(4)
411#ifdef RSEQ_COMPARE_TWICE
412 /* cmp cpuid */
413 RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1])
414 /* cmp @v equal to @expect */
415 RSEQ_ASM_OP_CMPEQ(v, expect, %l[error2])
416#endif
417 /* try store */
418 RSEQ_ASM_OP_STORE(newv2, v2)
419 RSEQ_INJECT_ASM(5)
420 /* for 'release' */
421 "lwsync\n\t"
422 /* final store */
423 RSEQ_ASM_OP_FINAL_STORE(newv, v, 2)
424 RSEQ_INJECT_ASM(6)
425 RSEQ_ASM_DEFINE_ABORT(4, abort)
426 : /* gcc asm goto does not allow outputs */
427 : [cpu_id] "r" (cpu),
428 [current_cpu_id] "m" (__rseq_abi.cpu_id),
429 [rseq_cs] "m" (__rseq_abi.rseq_cs),
430 /* try store input */
431 [v2] "m" (*v2),
432 [newv2] "r" (newv2),
433 /* final store input */
434 [v] "m" (*v),
435 [expect] "r" (expect),
436 [newv] "r" (newv)
437 RSEQ_INJECT_INPUT
438 : "memory", "cc", "r17"
439 RSEQ_INJECT_CLOBBER
440 : abort, cmpfail
441#ifdef RSEQ_COMPARE_TWICE
442 , error1, error2
443#endif
444 );
445 return 0;
446abort:
447 RSEQ_INJECT_FAILED
448 return -1;
449cmpfail:
450 return 1;
451#ifdef RSEQ_COMPARE_TWICE
452error1:
453 rseq_bug("cpu_id comparison failed");
454error2:
455 rseq_bug("expected value comparison failed");
456#endif
457}
458
459static inline __attribute__((always_inline))
460int rseq_cmpeqv_cmpeqv_storev(intptr_t *v, intptr_t expect,
461 intptr_t *v2, intptr_t expect2,
462 intptr_t newv, int cpu)
463{
464 RSEQ_INJECT_C(9)
465
466 __asm__ __volatile__ goto (
467 RSEQ_ASM_DEFINE_TABLE(3, 1f, 2f, 4f) /* start, commit, abort */
468 /* Start rseq by storing table entry pointer into rseq_cs. */
469 RSEQ_ASM_STORE_RSEQ_CS(1, 3b, rseq_cs)
470 /* cmp cpuid */
471 RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f)
472 RSEQ_INJECT_ASM(3)
473 /* cmp @v equal to @expect */
474 RSEQ_ASM_OP_CMPEQ(v, expect, %l[cmpfail])
475 RSEQ_INJECT_ASM(4)
476 /* cmp @v2 equal to @expct2 */
477 RSEQ_ASM_OP_CMPEQ(v2, expect2, %l[cmpfail])
478 RSEQ_INJECT_ASM(5)
479#ifdef RSEQ_COMPARE_TWICE
480 /* cmp cpuid */
481 RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1])
482 /* cmp @v equal to @expect */
483 RSEQ_ASM_OP_CMPEQ(v, expect, %l[error2])
484 /* cmp @v2 equal to @expct2 */
485 RSEQ_ASM_OP_CMPEQ(v2, expect2, %l[error3])
486#endif
487 /* final store */
488 RSEQ_ASM_OP_FINAL_STORE(newv, v, 2)
489 RSEQ_INJECT_ASM(6)
490 RSEQ_ASM_DEFINE_ABORT(4, abort)
491 : /* gcc asm goto does not allow outputs */
492 : [cpu_id] "r" (cpu),
493 [current_cpu_id] "m" (__rseq_abi.cpu_id),
494 [rseq_cs] "m" (__rseq_abi.rseq_cs),
495 /* cmp2 input */
496 [v2] "m" (*v2),
497 [expect2] "r" (expect2),
498 /* final store input */
499 [v] "m" (*v),
500 [expect] "r" (expect),
501 [newv] "r" (newv)
502 RSEQ_INJECT_INPUT
503 : "memory", "cc", "r17"
504 RSEQ_INJECT_CLOBBER
505 : abort, cmpfail
506#ifdef RSEQ_COMPARE_TWICE
507 , error1, error2, error3
508#endif
509 );
510 return 0;
511abort:
512 RSEQ_INJECT_FAILED
513 return -1;
514cmpfail:
515 return 1;
516#ifdef RSEQ_COMPARE_TWICE
517error1:
518 rseq_bug("cpu_id comparison failed");
519error2:
520 rseq_bug("1st expected value comparison failed");
521error3:
522 rseq_bug("2nd expected value comparison failed");
523#endif
524}
525
526static inline __attribute__((always_inline))
527int rseq_cmpeqv_trymemcpy_storev(intptr_t *v, intptr_t expect,
528 void *dst, void *src, size_t len,
529 intptr_t newv, int cpu)
530{
531 RSEQ_INJECT_C(9)
532
533 __asm__ __volatile__ goto (
534 RSEQ_ASM_DEFINE_TABLE(3, 1f, 2f, 4f) /* start, commit, abort */
535 /* setup for mempcy */
536 "mr %%r19, %[len]\n\t"
537 "mr %%r20, %[src]\n\t"
538 "mr %%r21, %[dst]\n\t"
539 /* Start rseq by storing table entry pointer into rseq_cs. */
540 RSEQ_ASM_STORE_RSEQ_CS(1, 3b, rseq_cs)
541 /* cmp cpuid */
542 RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f)
543 RSEQ_INJECT_ASM(3)
544 /* cmp @v equal to @expect */
545 RSEQ_ASM_OP_CMPEQ(v, expect, %l[cmpfail])
546 RSEQ_INJECT_ASM(4)
547#ifdef RSEQ_COMPARE_TWICE
548 /* cmp cpuid */
549 RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1])
550 /* cmp @v equal to @expect */
551 RSEQ_ASM_OP_CMPEQ(v, expect, %l[error2])
552#endif
553 /* try memcpy */
554 RSEQ_ASM_OP_R_MEMCPY()
555 RSEQ_INJECT_ASM(5)
556 /* final store */
557 RSEQ_ASM_OP_FINAL_STORE(newv, v, 2)
558 RSEQ_INJECT_ASM(6)
559 /* teardown */
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),
565 /* final store input */
566 [v] "m" (*v),
567 [expect] "r" (expect),
568 [newv] "r" (newv),
569 /* try memcpy input */
570 [dst] "r" (dst),
571 [src] "r" (src),
572 [len] "r" (len)
573 RSEQ_INJECT_INPUT
574 : "memory", "cc", "r17", "r18", "r19", "r20", "r21"
575 RSEQ_INJECT_CLOBBER
576 : abort, cmpfail
577#ifdef RSEQ_COMPARE_TWICE
578 , error1, error2
579#endif
580 );
581 return 0;
582abort:
583 RSEQ_INJECT_FAILED
584 return -1;
585cmpfail:
586 return 1;
587#ifdef RSEQ_COMPARE_TWICE
588error1:
589 rseq_bug("cpu_id comparison failed");
590error2:
591 rseq_bug("expected value comparison failed");
592#endif
593}
594
595static inline __attribute__((always_inline))
596int rseq_cmpeqv_trymemcpy_storev_release(intptr_t *v, intptr_t expect,
597 void *dst, void *src, size_t len,
598 intptr_t newv, int cpu)
599{
600 RSEQ_INJECT_C(9)
601
602 __asm__ __volatile__ goto (
603 RSEQ_ASM_DEFINE_TABLE(3, 1f, 2f, 4f) /* start, commit, abort */
604 /* setup for mempcy */
605 "mr %%r19, %[len]\n\t"
606 "mr %%r20, %[src]\n\t"
607 "mr %%r21, %[dst]\n\t"
608 /* Start rseq by storing table entry pointer into rseq_cs. */
609 RSEQ_ASM_STORE_RSEQ_CS(1, 3b, rseq_cs)
610 /* cmp cpuid */
611 RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f)
612 RSEQ_INJECT_ASM(3)
613 /* cmp @v equal to @expect */
614 RSEQ_ASM_OP_CMPEQ(v, expect, %l[cmpfail])
615 RSEQ_INJECT_ASM(4)
616#ifdef RSEQ_COMPARE_TWICE
617 /* cmp cpuid */
618 RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1])
619 /* cmp @v equal to @expect */
620 RSEQ_ASM_OP_CMPEQ(v, expect, %l[error2])
621#endif
622 /* try memcpy */
623 RSEQ_ASM_OP_R_MEMCPY()
624 RSEQ_INJECT_ASM(5)
625 /* for 'release' */
626 "lwsync\n\t"
627 /* final store */
628 RSEQ_ASM_OP_FINAL_STORE(newv, v, 2)
629 RSEQ_INJECT_ASM(6)
630 /* teardown */
631 RSEQ_ASM_DEFINE_ABORT(4, abort)
632 : /* gcc asm goto does not allow outputs */
633 : [cpu_id] "r" (cpu),
634 [current_cpu_id] "m" (__rseq_abi.cpu_id),
635 [rseq_cs] "m" (__rseq_abi.rseq_cs),
636 /* final store input */
637 [v] "m" (*v),
638 [expect] "r" (expect),
639 [newv] "r" (newv),
640 /* try memcpy input */
641 [dst] "r" (dst),
642 [src] "r" (src),
643 [len] "r" (len)
644 RSEQ_INJECT_INPUT
645 : "memory", "cc", "r17", "r18", "r19", "r20", "r21"
646 RSEQ_INJECT_CLOBBER
647 : abort, cmpfail
648#ifdef RSEQ_COMPARE_TWICE
649 , error1, error2
650#endif
651 );
652 return 0;
653abort:
654 RSEQ_INJECT_FAILED
655 return -1;
656cmpfail:
657 return 1;
658#ifdef RSEQ_COMPARE_TWICE
659error1:
660 rseq_bug("cpu_id comparison failed");
661error2:
662 rseq_bug("expected value comparison failed");
663#endif
664}
665
666#undef STORE_WORD
667#undef LOAD_WORD
668#undef LOADX_WORD
669#undef CMP_WORD
670
671#endif /* !RSEQ_SKIP_FASTPATH */
This page took 0.04876 seconds and 4 git commands to generate.