Merge tag 'drm-next-2018-08-17' of git://anongit.freedesktop.org/drm/drm
[sfrench/cifs-2.6.git] / tools / testing / selftests / rseq / rseq-arm64.h
1 /* SPDX-License-Identifier: LGPL-2.1 OR MIT */
2 /*
3  * rseq-arm64.h
4  *
5  * (C) Copyright 2016-2018 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
6  * (C) Copyright 2018 - Will Deacon <will.deacon@arm.com>
7  */
8
9 #define RSEQ_SIG        0xd428bc00      /* BRK #0x45E0 */
10
11 #define rseq_smp_mb()   __asm__ __volatile__ ("dmb ish" ::: "memory")
12 #define rseq_smp_rmb()  __asm__ __volatile__ ("dmb ishld" ::: "memory")
13 #define rseq_smp_wmb()  __asm__ __volatile__ ("dmb ishst" ::: "memory")
14
15 #define rseq_smp_load_acquire(p)                                                \
16 __extension__ ({                                                                \
17         __typeof(*p) ____p1;                                                    \
18         switch (sizeof(*p)) {                                                   \
19         case 1:                                                                 \
20                 asm volatile ("ldarb %w0, %1"                                   \
21                         : "=r" (*(__u8 *)p)                                     \
22                         : "Q" (*p) : "memory");                                 \
23                 break;                                                          \
24         case 2:                                                                 \
25                 asm volatile ("ldarh %w0, %1"                                   \
26                         : "=r" (*(__u16 *)p)                                    \
27                         : "Q" (*p) : "memory");                                 \
28                 break;                                                          \
29         case 4:                                                                 \
30                 asm volatile ("ldar %w0, %1"                                    \
31                         : "=r" (*(__u32 *)p)                                    \
32                         : "Q" (*p) : "memory");                                 \
33                 break;                                                          \
34         case 8:                                                                 \
35                 asm volatile ("ldar %0, %1"                                     \
36                         : "=r" (*(__u64 *)p)                                    \
37                         : "Q" (*p) : "memory");                                 \
38                 break;                                                          \
39         }                                                                       \
40         ____p1;                                                                 \
41 })
42
43 #define rseq_smp_acquire__after_ctrl_dep()      rseq_smp_rmb()
44
45 #define rseq_smp_store_release(p, v)                                            \
46 do {                                                                            \
47         switch (sizeof(*p)) {                                                   \
48         case 1:                                                                 \
49                 asm volatile ("stlrb %w1, %0"                                   \
50                                 : "=Q" (*p)                                     \
51                                 : "r" ((__u8)v)                                 \
52                                 : "memory");                                    \
53                 break;                                                          \
54         case 2:                                                                 \
55                 asm volatile ("stlrh %w1, %0"                                   \
56                                 : "=Q" (*p)                                     \
57                                 : "r" ((__u16)v)                                \
58                                 : "memory");                                    \
59                 break;                                                          \
60         case 4:                                                                 \
61                 asm volatile ("stlr %w1, %0"                                    \
62                                 : "=Q" (*p)                                     \
63                                 : "r" ((__u32)v)                                \
64                                 : "memory");                                    \
65                 break;                                                          \
66         case 8:                                                                 \
67                 asm volatile ("stlr %1, %0"                                     \
68                                 : "=Q" (*p)                                     \
69                                 : "r" ((__u64)v)                                \
70                                 : "memory");                                    \
71                 break;                                                          \
72         }                                                                       \
73 } while (0)
74
75 #ifdef RSEQ_SKIP_FASTPATH
76 #include "rseq-skip.h"
77 #else /* !RSEQ_SKIP_FASTPATH */
78
79 #define RSEQ_ASM_TMP_REG32      "w15"
80 #define RSEQ_ASM_TMP_REG        "x15"
81 #define RSEQ_ASM_TMP_REG_2      "x14"
82
83 #define __RSEQ_ASM_DEFINE_TABLE(label, version, flags, start_ip,                \
84                                 post_commit_offset, abort_ip)                   \
85         "       .pushsection    __rseq_table, \"aw\"\n"                         \
86         "       .balign 32\n"                                                   \
87         __rseq_str(label) ":\n"                                                 \
88         "       .long   " __rseq_str(version) ", " __rseq_str(flags) "\n"       \
89         "       .quad   " __rseq_str(start_ip) ", "                             \
90                           __rseq_str(post_commit_offset) ", "                   \
91                           __rseq_str(abort_ip) "\n"                             \
92         "       .popsection\n"
93
94 #define RSEQ_ASM_DEFINE_TABLE(label, start_ip, post_commit_ip, abort_ip)        \
95         __RSEQ_ASM_DEFINE_TABLE(label, 0x0, 0x0, start_ip,                      \
96                                 (post_commit_ip - start_ip), abort_ip)
97
98 #define RSEQ_ASM_STORE_RSEQ_CS(label, cs_label, rseq_cs)                        \
99         RSEQ_INJECT_ASM(1)                                                      \
100         "       adrp    " RSEQ_ASM_TMP_REG ", " __rseq_str(cs_label) "\n"       \
101         "       add     " RSEQ_ASM_TMP_REG ", " RSEQ_ASM_TMP_REG                \
102                         ", :lo12:" __rseq_str(cs_label) "\n"                    \
103         "       str     " RSEQ_ASM_TMP_REG ", %[" __rseq_str(rseq_cs) "]\n"     \
104         __rseq_str(label) ":\n"
105
106 #define RSEQ_ASM_DEFINE_ABORT(label, abort_label)                               \
107         "       b       222f\n"                                                 \
108         "       .inst   "       __rseq_str(RSEQ_SIG) "\n"                       \
109         __rseq_str(label) ":\n"                                                 \
110         "       b       %l[" __rseq_str(abort_label) "]\n"                      \
111         "222:\n"
112
113 #define RSEQ_ASM_OP_STORE(value, var)                                           \
114         "       str     %[" __rseq_str(value) "], %[" __rseq_str(var) "]\n"
115
116 #define RSEQ_ASM_OP_STORE_RELEASE(value, var)                                   \
117         "       stlr    %[" __rseq_str(value) "], %[" __rseq_str(var) "]\n"
118
119 #define RSEQ_ASM_OP_FINAL_STORE(value, var, post_commit_label)                  \
120         RSEQ_ASM_OP_STORE(value, var)                                           \
121         __rseq_str(post_commit_label) ":\n"
122
123 #define RSEQ_ASM_OP_FINAL_STORE_RELEASE(value, var, post_commit_label)          \
124         RSEQ_ASM_OP_STORE_RELEASE(value, var)                                   \
125         __rseq_str(post_commit_label) ":\n"
126
127 #define RSEQ_ASM_OP_CMPEQ(var, expect, label)                                   \
128         "       ldr     " RSEQ_ASM_TMP_REG ", %[" __rseq_str(var) "]\n"         \
129         "       sub     " RSEQ_ASM_TMP_REG ", " RSEQ_ASM_TMP_REG                \
130                         ", %[" __rseq_str(expect) "]\n"                         \
131         "       cbnz    " RSEQ_ASM_TMP_REG ", " __rseq_str(label) "\n"
132
133 #define RSEQ_ASM_OP_CMPEQ32(var, expect, label)                                 \
134         "       ldr     " RSEQ_ASM_TMP_REG32 ", %[" __rseq_str(var) "]\n"       \
135         "       sub     " RSEQ_ASM_TMP_REG32 ", " RSEQ_ASM_TMP_REG32            \
136                         ", %w[" __rseq_str(expect) "]\n"                        \
137         "       cbnz    " RSEQ_ASM_TMP_REG32 ", " __rseq_str(label) "\n"
138
139 #define RSEQ_ASM_OP_CMPNE(var, expect, label)                                   \
140         "       ldr     " RSEQ_ASM_TMP_REG ", %[" __rseq_str(var) "]\n"         \
141         "       sub     " RSEQ_ASM_TMP_REG ", " RSEQ_ASM_TMP_REG                \
142                         ", %[" __rseq_str(expect) "]\n"                         \
143         "       cbz     " RSEQ_ASM_TMP_REG ", " __rseq_str(label) "\n"
144
145 #define RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, label)                      \
146         RSEQ_INJECT_ASM(2)                                                      \
147         RSEQ_ASM_OP_CMPEQ32(current_cpu_id, cpu_id, label)
148
149 #define RSEQ_ASM_OP_R_LOAD(var)                                                 \
150         "       ldr     " RSEQ_ASM_TMP_REG ", %[" __rseq_str(var) "]\n"
151
152 #define RSEQ_ASM_OP_R_STORE(var)                                                \
153         "       str     " RSEQ_ASM_TMP_REG ", %[" __rseq_str(var) "]\n"
154
155 #define RSEQ_ASM_OP_R_LOAD_OFF(offset)                                          \
156         "       ldr     " RSEQ_ASM_TMP_REG ", [" RSEQ_ASM_TMP_REG               \
157                         ", %[" __rseq_str(offset) "]]\n"
158
159 #define RSEQ_ASM_OP_R_ADD(count)                                                \
160         "       add     " RSEQ_ASM_TMP_REG ", " RSEQ_ASM_TMP_REG                \
161                         ", %[" __rseq_str(count) "]\n"
162
163 #define RSEQ_ASM_OP_R_FINAL_STORE(var, post_commit_label)                       \
164         "       str     " RSEQ_ASM_TMP_REG ", %[" __rseq_str(var) "]\n"         \
165         __rseq_str(post_commit_label) ":\n"
166
167 #define RSEQ_ASM_OP_R_BAD_MEMCPY(dst, src, len)                                 \
168         "       cbz     %[" __rseq_str(len) "], 333f\n"                         \
169         "       mov     " RSEQ_ASM_TMP_REG_2 ", %[" __rseq_str(len) "]\n"       \
170         "222:   sub     " RSEQ_ASM_TMP_REG_2 ", " RSEQ_ASM_TMP_REG_2 ", #1\n"   \
171         "       ldrb    " RSEQ_ASM_TMP_REG32 ", [%[" __rseq_str(src) "]"        \
172                         ", " RSEQ_ASM_TMP_REG_2 "]\n"                           \
173         "       strb    " RSEQ_ASM_TMP_REG32 ", [%[" __rseq_str(dst) "]"        \
174                         ", " RSEQ_ASM_TMP_REG_2 "]\n"                           \
175         "       cbnz    " RSEQ_ASM_TMP_REG_2 ", 222b\n"                         \
176         "333:\n"
177
178 static inline __attribute__((always_inline))
179 int rseq_cmpeqv_storev(intptr_t *v, intptr_t expect, intptr_t newv, int cpu)
180 {
181         RSEQ_INJECT_C(9)
182
183         __asm__ __volatile__ goto (
184                 RSEQ_ASM_DEFINE_TABLE(1, 2f, 3f, 4f)
185                 RSEQ_ASM_STORE_RSEQ_CS(2, 1b, rseq_cs)
186                 RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f)
187                 RSEQ_INJECT_ASM(3)
188                 RSEQ_ASM_OP_CMPEQ(v, expect, %l[cmpfail])
189                 RSEQ_INJECT_ASM(4)
190 #ifdef RSEQ_COMPARE_TWICE
191                 RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1])
192                 RSEQ_ASM_OP_CMPEQ(v, expect, %l[error2])
193 #endif
194                 RSEQ_ASM_OP_FINAL_STORE(newv, v, 3)
195                 RSEQ_INJECT_ASM(5)
196                 RSEQ_ASM_DEFINE_ABORT(4, abort)
197                 : /* gcc asm goto does not allow outputs */
198                 : [cpu_id]              "r" (cpu),
199                   [current_cpu_id]      "Qo" (__rseq_abi.cpu_id),
200                   [rseq_cs]             "m" (__rseq_abi.rseq_cs),
201                   [v]                   "Qo" (*v),
202                   [expect]              "r" (expect),
203                   [newv]                "r" (newv)
204                   RSEQ_INJECT_INPUT
205                 : "memory", RSEQ_ASM_TMP_REG
206                 : abort, cmpfail
207 #ifdef RSEQ_COMPARE_TWICE
208                   , error1, error2
209 #endif
210         );
211
212         return 0;
213 abort:
214         RSEQ_INJECT_FAILED
215         return -1;
216 cmpfail:
217         return 1;
218 #ifdef RSEQ_COMPARE_TWICE
219 error1:
220         rseq_bug("cpu_id comparison failed");
221 error2:
222         rseq_bug("expected value comparison failed");
223 #endif
224 }
225
226 static inline __attribute__((always_inline))
227 int rseq_cmpnev_storeoffp_load(intptr_t *v, intptr_t expectnot,
228                                off_t voffp, intptr_t *load, int cpu)
229 {
230         RSEQ_INJECT_C(9)
231
232         __asm__ __volatile__ goto (
233                 RSEQ_ASM_DEFINE_TABLE(1, 2f, 3f, 4f)
234                 RSEQ_ASM_STORE_RSEQ_CS(2, 1b, rseq_cs)
235                 RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f)
236                 RSEQ_INJECT_ASM(3)
237                 RSEQ_ASM_OP_CMPNE(v, expectnot, %l[cmpfail])
238                 RSEQ_INJECT_ASM(4)
239 #ifdef RSEQ_COMPARE_TWICE
240                 RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1])
241                 RSEQ_ASM_OP_CMPNE(v, expectnot, %l[error2])
242 #endif
243                 RSEQ_ASM_OP_R_LOAD(v)
244                 RSEQ_ASM_OP_R_STORE(load)
245                 RSEQ_ASM_OP_R_LOAD_OFF(voffp)
246                 RSEQ_ASM_OP_R_FINAL_STORE(v, 3)
247                 RSEQ_INJECT_ASM(5)
248                 RSEQ_ASM_DEFINE_ABORT(4, abort)
249                 : /* gcc asm goto does not allow outputs */
250                 : [cpu_id]              "r" (cpu),
251                   [current_cpu_id]      "Qo" (__rseq_abi.cpu_id),
252                   [rseq_cs]             "m" (__rseq_abi.rseq_cs),
253                   [v]                   "Qo" (*v),
254                   [expectnot]           "r" (expectnot),
255                   [load]                "Qo" (*load),
256                   [voffp]               "r" (voffp)
257                   RSEQ_INJECT_INPUT
258                 : "memory", RSEQ_ASM_TMP_REG
259                 : abort, cmpfail
260 #ifdef RSEQ_COMPARE_TWICE
261                   , error1, error2
262 #endif
263         );
264         return 0;
265 abort:
266         RSEQ_INJECT_FAILED
267         return -1;
268 cmpfail:
269         return 1;
270 #ifdef RSEQ_COMPARE_TWICE
271 error1:
272         rseq_bug("cpu_id comparison failed");
273 error2:
274         rseq_bug("expected value comparison failed");
275 #endif
276 }
277
278 static inline __attribute__((always_inline))
279 int rseq_addv(intptr_t *v, intptr_t count, int cpu)
280 {
281         RSEQ_INJECT_C(9)
282
283         __asm__ __volatile__ goto (
284                 RSEQ_ASM_DEFINE_TABLE(1, 2f, 3f, 4f)
285                 RSEQ_ASM_STORE_RSEQ_CS(2, 1b, rseq_cs)
286                 RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f)
287                 RSEQ_INJECT_ASM(3)
288 #ifdef RSEQ_COMPARE_TWICE
289                 RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1])
290 #endif
291                 RSEQ_ASM_OP_R_LOAD(v)
292                 RSEQ_ASM_OP_R_ADD(count)
293                 RSEQ_ASM_OP_R_FINAL_STORE(v, 3)
294                 RSEQ_INJECT_ASM(4)
295                 RSEQ_ASM_DEFINE_ABORT(4, abort)
296                 : /* gcc asm goto does not allow outputs */
297                 : [cpu_id]              "r" (cpu),
298                   [current_cpu_id]      "Qo" (__rseq_abi.cpu_id),
299                   [rseq_cs]             "m" (__rseq_abi.rseq_cs),
300                   [v]                   "Qo" (*v),
301                   [count]               "r" (count)
302                   RSEQ_INJECT_INPUT
303                 : "memory", RSEQ_ASM_TMP_REG
304                 : abort
305 #ifdef RSEQ_COMPARE_TWICE
306                   , error1
307 #endif
308         );
309         return 0;
310 abort:
311         RSEQ_INJECT_FAILED
312         return -1;
313 #ifdef RSEQ_COMPARE_TWICE
314 error1:
315         rseq_bug("cpu_id comparison failed");
316 #endif
317 }
318
319 static inline __attribute__((always_inline))
320 int rseq_cmpeqv_trystorev_storev(intptr_t *v, intptr_t expect,
321                                  intptr_t *v2, intptr_t newv2,
322                                  intptr_t newv, int cpu)
323 {
324         RSEQ_INJECT_C(9)
325
326         __asm__ __volatile__ goto (
327                 RSEQ_ASM_DEFINE_TABLE(1, 2f, 3f, 4f)
328                 RSEQ_ASM_STORE_RSEQ_CS(2, 1b, rseq_cs)
329                 RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f)
330                 RSEQ_INJECT_ASM(3)
331                 RSEQ_ASM_OP_CMPEQ(v, expect, %l[cmpfail])
332                 RSEQ_INJECT_ASM(4)
333 #ifdef RSEQ_COMPARE_TWICE
334                 RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1])
335                 RSEQ_ASM_OP_CMPEQ(v, expect, %l[error2])
336 #endif
337                 RSEQ_ASM_OP_STORE(newv2, v2)
338                 RSEQ_INJECT_ASM(5)
339                 RSEQ_ASM_OP_FINAL_STORE(newv, v, 3)
340                 RSEQ_INJECT_ASM(6)
341                 RSEQ_ASM_DEFINE_ABORT(4, abort)
342                 : /* gcc asm goto does not allow outputs */
343                 : [cpu_id]              "r" (cpu),
344                   [current_cpu_id]      "Qo" (__rseq_abi.cpu_id),
345                   [rseq_cs]             "m" (__rseq_abi.rseq_cs),
346                   [expect]              "r" (expect),
347                   [v]                   "Qo" (*v),
348                   [newv]                "r" (newv),
349                   [v2]                  "Qo" (*v2),
350                   [newv2]               "r" (newv2)
351                   RSEQ_INJECT_INPUT
352                 : "memory", RSEQ_ASM_TMP_REG
353                 : abort, cmpfail
354 #ifdef RSEQ_COMPARE_TWICE
355                   , error1, error2
356 #endif
357         );
358
359         return 0;
360 abort:
361         RSEQ_INJECT_FAILED
362         return -1;
363 cmpfail:
364         return 1;
365 #ifdef RSEQ_COMPARE_TWICE
366 error1:
367         rseq_bug("cpu_id comparison failed");
368 error2:
369         rseq_bug("expected value comparison failed");
370 #endif
371 }
372
373 static inline __attribute__((always_inline))
374 int rseq_cmpeqv_trystorev_storev_release(intptr_t *v, intptr_t expect,
375                                          intptr_t *v2, intptr_t newv2,
376                                          intptr_t newv, int cpu)
377 {
378         RSEQ_INJECT_C(9)
379
380         __asm__ __volatile__ goto (
381                 RSEQ_ASM_DEFINE_TABLE(1, 2f, 3f, 4f)
382                 RSEQ_ASM_STORE_RSEQ_CS(2, 1b, rseq_cs)
383                 RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f)
384                 RSEQ_INJECT_ASM(3)
385                 RSEQ_ASM_OP_CMPEQ(v, expect, %l[cmpfail])
386                 RSEQ_INJECT_ASM(4)
387 #ifdef RSEQ_COMPARE_TWICE
388                 RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1])
389                 RSEQ_ASM_OP_CMPEQ(v, expect, %l[error2])
390 #endif
391                 RSEQ_ASM_OP_STORE(newv2, v2)
392                 RSEQ_INJECT_ASM(5)
393                 RSEQ_ASM_OP_FINAL_STORE_RELEASE(newv, v, 3)
394                 RSEQ_INJECT_ASM(6)
395                 RSEQ_ASM_DEFINE_ABORT(4, abort)
396                 : /* gcc asm goto does not allow outputs */
397                 : [cpu_id]              "r" (cpu),
398                   [current_cpu_id]      "Qo" (__rseq_abi.cpu_id),
399                   [rseq_cs]             "m" (__rseq_abi.rseq_cs),
400                   [expect]              "r" (expect),
401                   [v]                   "Qo" (*v),
402                   [newv]                "r" (newv),
403                   [v2]                  "Qo" (*v2),
404                   [newv2]               "r" (newv2)
405                   RSEQ_INJECT_INPUT
406                 : "memory", RSEQ_ASM_TMP_REG
407                 : abort, cmpfail
408 #ifdef RSEQ_COMPARE_TWICE
409                   , error1, error2
410 #endif
411         );
412
413         return 0;
414 abort:
415         RSEQ_INJECT_FAILED
416         return -1;
417 cmpfail:
418         return 1;
419 #ifdef RSEQ_COMPARE_TWICE
420 error1:
421         rseq_bug("cpu_id comparison failed");
422 error2:
423         rseq_bug("expected value comparison failed");
424 #endif
425 }
426
427 static inline __attribute__((always_inline))
428 int rseq_cmpeqv_cmpeqv_storev(intptr_t *v, intptr_t expect,
429                               intptr_t *v2, intptr_t expect2,
430                               intptr_t newv, int cpu)
431 {
432         RSEQ_INJECT_C(9)
433
434         __asm__ __volatile__ goto (
435                 RSEQ_ASM_DEFINE_TABLE(1, 2f, 3f, 4f)
436                 RSEQ_ASM_STORE_RSEQ_CS(2, 1b, rseq_cs)
437                 RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f)
438                 RSEQ_INJECT_ASM(3)
439                 RSEQ_ASM_OP_CMPEQ(v, expect, %l[cmpfail])
440                 RSEQ_INJECT_ASM(4)
441                 RSEQ_ASM_OP_CMPEQ(v2, expect2, %l[cmpfail])
442                 RSEQ_INJECT_ASM(5)
443 #ifdef RSEQ_COMPARE_TWICE
444                 RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1])
445                 RSEQ_ASM_OP_CMPEQ(v, expect, %l[error2])
446                 RSEQ_ASM_OP_CMPEQ(v2, expect2, %l[error3])
447 #endif
448                 RSEQ_ASM_OP_FINAL_STORE(newv, v, 3)
449                 RSEQ_INJECT_ASM(6)
450                 RSEQ_ASM_DEFINE_ABORT(4, abort)
451                 : /* gcc asm goto does not allow outputs */
452                 : [cpu_id]              "r" (cpu),
453                   [current_cpu_id]      "Qo" (__rseq_abi.cpu_id),
454                   [rseq_cs]             "m" (__rseq_abi.rseq_cs),
455                   [v]                   "Qo" (*v),
456                   [expect]              "r" (expect),
457                   [v2]                  "Qo" (*v2),
458                   [expect2]             "r" (expect2),
459                   [newv]                "r" (newv)
460                   RSEQ_INJECT_INPUT
461                 : "memory", RSEQ_ASM_TMP_REG
462                 : abort, cmpfail
463 #ifdef RSEQ_COMPARE_TWICE
464                   , error1, error2, error3
465 #endif
466         );
467
468         return 0;
469 abort:
470         RSEQ_INJECT_FAILED
471         return -1;
472 cmpfail:
473         return 1;
474 #ifdef RSEQ_COMPARE_TWICE
475 error1:
476         rseq_bug("cpu_id comparison failed");
477 error2:
478         rseq_bug("expected value comparison failed");
479 error3:
480         rseq_bug("2nd expected value comparison failed");
481 #endif
482 }
483
484 static inline __attribute__((always_inline))
485 int rseq_cmpeqv_trymemcpy_storev(intptr_t *v, intptr_t expect,
486                                  void *dst, void *src, size_t len,
487                                  intptr_t newv, int cpu)
488 {
489         RSEQ_INJECT_C(9)
490
491         __asm__ __volatile__ goto (
492                 RSEQ_ASM_DEFINE_TABLE(1, 2f, 3f, 4f)
493                 RSEQ_ASM_STORE_RSEQ_CS(2, 1b, rseq_cs)
494                 RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f)
495                 RSEQ_INJECT_ASM(3)
496                 RSEQ_ASM_OP_CMPEQ(v, expect, %l[cmpfail])
497                 RSEQ_INJECT_ASM(4)
498 #ifdef RSEQ_COMPARE_TWICE
499                 RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1])
500                 RSEQ_ASM_OP_CMPEQ(v, expect, %l[error2])
501 #endif
502                 RSEQ_ASM_OP_R_BAD_MEMCPY(dst, src, len)
503                 RSEQ_INJECT_ASM(5)
504                 RSEQ_ASM_OP_FINAL_STORE(newv, v, 3)
505                 RSEQ_INJECT_ASM(6)
506                 RSEQ_ASM_DEFINE_ABORT(4, abort)
507                 : /* gcc asm goto does not allow outputs */
508                 : [cpu_id]              "r" (cpu),
509                   [current_cpu_id]      "Qo" (__rseq_abi.cpu_id),
510                   [rseq_cs]             "m" (__rseq_abi.rseq_cs),
511                   [expect]              "r" (expect),
512                   [v]                   "Qo" (*v),
513                   [newv]                "r" (newv),
514                   [dst]                 "r" (dst),
515                   [src]                 "r" (src),
516                   [len]                 "r" (len)
517                   RSEQ_INJECT_INPUT
518                 : "memory", RSEQ_ASM_TMP_REG, RSEQ_ASM_TMP_REG_2
519                 : abort, cmpfail
520 #ifdef RSEQ_COMPARE_TWICE
521                   , error1, error2
522 #endif
523         );
524
525         return 0;
526 abort:
527         RSEQ_INJECT_FAILED
528         return -1;
529 cmpfail:
530         return 1;
531 #ifdef RSEQ_COMPARE_TWICE
532 error1:
533         rseq_bug("cpu_id comparison failed");
534 error2:
535         rseq_bug("expected value comparison failed");
536 #endif
537 }
538
539 static inline __attribute__((always_inline))
540 int rseq_cmpeqv_trymemcpy_storev_release(intptr_t *v, intptr_t expect,
541                                          void *dst, void *src, size_t len,
542                                          intptr_t newv, int cpu)
543 {
544         RSEQ_INJECT_C(9)
545
546         __asm__ __volatile__ goto (
547                 RSEQ_ASM_DEFINE_TABLE(1, 2f, 3f, 4f)
548                 RSEQ_ASM_STORE_RSEQ_CS(2, 1b, rseq_cs)
549                 RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f)
550                 RSEQ_INJECT_ASM(3)
551                 RSEQ_ASM_OP_CMPEQ(v, expect, %l[cmpfail])
552                 RSEQ_INJECT_ASM(4)
553 #ifdef RSEQ_COMPARE_TWICE
554                 RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1])
555                 RSEQ_ASM_OP_CMPEQ(v, expect, %l[error2])
556 #endif
557                 RSEQ_ASM_OP_R_BAD_MEMCPY(dst, src, len)
558                 RSEQ_INJECT_ASM(5)
559                 RSEQ_ASM_OP_FINAL_STORE_RELEASE(newv, v, 3)
560                 RSEQ_INJECT_ASM(6)
561                 RSEQ_ASM_DEFINE_ABORT(4, abort)
562                 : /* gcc asm goto does not allow outputs */
563                 : [cpu_id]              "r" (cpu),
564                   [current_cpu_id]      "Qo" (__rseq_abi.cpu_id),
565                   [rseq_cs]             "m" (__rseq_abi.rseq_cs),
566                   [expect]              "r" (expect),
567                   [v]                   "Qo" (*v),
568                   [newv]                "r" (newv),
569                   [dst]                 "r" (dst),
570                   [src]                 "r" (src),
571                   [len]                 "r" (len)
572                   RSEQ_INJECT_INPUT
573                 : "memory", RSEQ_ASM_TMP_REG, RSEQ_ASM_TMP_REG_2
574                 : abort, cmpfail
575 #ifdef RSEQ_COMPARE_TWICE
576                   , error1, error2
577 #endif
578         );
579
580         return 0;
581 abort:
582         RSEQ_INJECT_FAILED
583         return -1;
584 cmpfail:
585         return 1;
586 #ifdef RSEQ_COMPARE_TWICE
587 error1:
588         rseq_bug("cpu_id comparison failed");
589 error2:
590         rseq_bug("expected value comparison failed");
591 #endif
592 }
593
594 #endif /* !RSEQ_SKIP_FASTPATH */