staging: rtl8192u: remove redundant assignment to pointer crypt
[linux/fpc-iii.git] / tools / testing / selftests / rseq / rseq-x86.h
blobb2da6004fe307931a500d0b50eba52cb46a06645
1 /* SPDX-License-Identifier: LGPL-2.1 OR MIT */
2 /*
3 * rseq-x86.h
5 * (C) Copyright 2016-2018 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
6 */
8 #include <stdint.h>
11 * RSEQ_SIG is used with the following reserved undefined instructions, which
12 * trap in user-space:
14 * x86-32: 0f b9 3d 53 30 05 53 ud1 0x53053053,%edi
15 * x86-64: 0f b9 3d 53 30 05 53 ud1 0x53053053(%rip),%edi
17 #define RSEQ_SIG 0x53053053
20 * Due to a compiler optimization bug in gcc-8 with asm goto and TLS asm input
21 * operands, we cannot use "m" input operands, and rather pass the __rseq_abi
22 * address through a "r" input operand.
25 /* Offset of cpu_id and rseq_cs fields in struct rseq. */
26 #define RSEQ_CPU_ID_OFFSET 4
27 #define RSEQ_CS_OFFSET 8
29 #ifdef __x86_64__
31 #define rseq_smp_mb() \
32 __asm__ __volatile__ ("lock; addl $0,-128(%%rsp)" ::: "memory", "cc")
33 #define rseq_smp_rmb() rseq_barrier()
34 #define rseq_smp_wmb() rseq_barrier()
36 #define rseq_smp_load_acquire(p) \
37 __extension__ ({ \
38 __typeof(*p) ____p1 = RSEQ_READ_ONCE(*p); \
39 rseq_barrier(); \
40 ____p1; \
43 #define rseq_smp_acquire__after_ctrl_dep() rseq_smp_rmb()
45 #define rseq_smp_store_release(p, v) \
46 do { \
47 rseq_barrier(); \
48 RSEQ_WRITE_ONCE(*p, v); \
49 } while (0)
51 #ifdef RSEQ_SKIP_FASTPATH
52 #include "rseq-skip.h"
53 #else /* !RSEQ_SKIP_FASTPATH */
55 #define __RSEQ_ASM_DEFINE_TABLE(label, version, flags, \
56 start_ip, post_commit_offset, abort_ip) \
57 ".pushsection __rseq_cs, \"aw\"\n\t" \
58 ".balign 32\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" \
62 ".popsection\n\t" \
63 ".pushsection __rseq_cs_ptr_array, \"aw\"\n\t" \
64 ".quad " __rseq_str(label) "b\n\t" \
65 ".popsection\n\t"
68 #define RSEQ_ASM_DEFINE_TABLE(label, start_ip, post_commit_ip, abort_ip) \
69 __RSEQ_ASM_DEFINE_TABLE(label, 0x0, 0x0, start_ip, \
70 (post_commit_ip - start_ip), abort_ip)
73 * Exit points of a rseq critical section consist of all instructions outside
74 * of the critical section where a critical section can either branch to or
75 * reach through the normal course of its execution. The abort IP and the
76 * post-commit IP are already part of the __rseq_cs section and should not be
77 * explicitly defined as additional exit points. Knowing all exit points is
78 * useful to assist debuggers stepping over the critical section.
80 #define RSEQ_ASM_DEFINE_EXIT_POINT(start_ip, exit_ip) \
81 ".pushsection __rseq_exit_point_array, \"aw\"\n\t" \
82 ".quad " __rseq_str(start_ip) ", " __rseq_str(exit_ip) "\n\t" \
83 ".popsection\n\t"
85 #define RSEQ_ASM_STORE_RSEQ_CS(label, cs_label, rseq_cs) \
86 RSEQ_INJECT_ASM(1) \
87 "leaq " __rseq_str(cs_label) "(%%rip), %%rax\n\t" \
88 "movq %%rax, " __rseq_str(rseq_cs) "\n\t" \
89 __rseq_str(label) ":\n\t"
91 #define RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, label) \
92 RSEQ_INJECT_ASM(2) \
93 "cmpl %[" __rseq_str(cpu_id) "], " __rseq_str(current_cpu_id) "\n\t" \
94 "jnz " __rseq_str(label) "\n\t"
96 #define RSEQ_ASM_DEFINE_ABORT(label, teardown, abort_label) \
97 ".pushsection __rseq_failure, \"ax\"\n\t" \
98 /* Disassembler-friendly signature: ud1 <sig>(%rip),%edi. */ \
99 ".byte 0x0f, 0xb9, 0x3d\n\t" \
100 ".long " __rseq_str(RSEQ_SIG) "\n\t" \
101 __rseq_str(label) ":\n\t" \
102 teardown \
103 "jmp %l[" __rseq_str(abort_label) "]\n\t" \
104 ".popsection\n\t"
106 #define RSEQ_ASM_DEFINE_CMPFAIL(label, teardown, cmpfail_label) \
107 ".pushsection __rseq_failure, \"ax\"\n\t" \
108 __rseq_str(label) ":\n\t" \
109 teardown \
110 "jmp %l[" __rseq_str(cmpfail_label) "]\n\t" \
111 ".popsection\n\t"
113 static inline __attribute__((always_inline))
114 int rseq_cmpeqv_storev(intptr_t *v, intptr_t expect, intptr_t newv, int cpu)
116 RSEQ_INJECT_C(9)
118 __asm__ __volatile__ goto (
119 RSEQ_ASM_DEFINE_TABLE(3, 1f, 2f, 4f) /* start, commit, abort */
120 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[cmpfail])
121 #ifdef RSEQ_COMPARE_TWICE
122 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error1])
123 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error2])
124 #endif
125 /* Start rseq by storing table entry pointer into rseq_cs. */
126 RSEQ_ASM_STORE_RSEQ_CS(1, 3b, RSEQ_CS_OFFSET(%[rseq_abi]))
127 RSEQ_ASM_CMP_CPU_ID(cpu_id, RSEQ_CPU_ID_OFFSET(%[rseq_abi]), 4f)
128 RSEQ_INJECT_ASM(3)
129 "cmpq %[v], %[expect]\n\t"
130 "jnz %l[cmpfail]\n\t"
131 RSEQ_INJECT_ASM(4)
132 #ifdef RSEQ_COMPARE_TWICE
133 RSEQ_ASM_CMP_CPU_ID(cpu_id, RSEQ_CPU_ID_OFFSET(%[rseq_abi]), %l[error1])
134 "cmpq %[v], %[expect]\n\t"
135 "jnz %l[error2]\n\t"
136 #endif
137 /* final store */
138 "movq %[newv], %[v]\n\t"
139 "2:\n\t"
140 RSEQ_INJECT_ASM(5)
141 RSEQ_ASM_DEFINE_ABORT(4, "", abort)
142 : /* gcc asm goto does not allow outputs */
143 : [cpu_id] "r" (cpu),
144 [rseq_abi] "r" (&__rseq_abi),
145 [v] "m" (*v),
146 [expect] "r" (expect),
147 [newv] "r" (newv)
148 : "memory", "cc", "rax"
149 RSEQ_INJECT_CLOBBER
150 : abort, cmpfail
151 #ifdef RSEQ_COMPARE_TWICE
152 , error1, error2
153 #endif
155 return 0;
156 abort:
157 RSEQ_INJECT_FAILED
158 return -1;
159 cmpfail:
160 return 1;
161 #ifdef RSEQ_COMPARE_TWICE
162 error1:
163 rseq_bug("cpu_id comparison failed");
164 error2:
165 rseq_bug("expected value comparison failed");
166 #endif
170 * Compare @v against @expectnot. When it does _not_ match, load @v
171 * into @load, and store the content of *@v + voffp into @v.
173 static inline __attribute__((always_inline))
174 int rseq_cmpnev_storeoffp_load(intptr_t *v, intptr_t expectnot,
175 off_t voffp, intptr_t *load, int cpu)
177 RSEQ_INJECT_C(9)
179 __asm__ __volatile__ goto (
180 RSEQ_ASM_DEFINE_TABLE(3, 1f, 2f, 4f) /* start, commit, abort */
181 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[cmpfail])
182 #ifdef RSEQ_COMPARE_TWICE
183 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error1])
184 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error2])
185 #endif
186 /* Start rseq by storing table entry pointer into rseq_cs. */
187 RSEQ_ASM_STORE_RSEQ_CS(1, 3b, RSEQ_CS_OFFSET(%[rseq_abi]))
188 RSEQ_ASM_CMP_CPU_ID(cpu_id, RSEQ_CPU_ID_OFFSET(%[rseq_abi]), 4f)
189 RSEQ_INJECT_ASM(3)
190 "movq %[v], %%rbx\n\t"
191 "cmpq %%rbx, %[expectnot]\n\t"
192 "je %l[cmpfail]\n\t"
193 RSEQ_INJECT_ASM(4)
194 #ifdef RSEQ_COMPARE_TWICE
195 RSEQ_ASM_CMP_CPU_ID(cpu_id, RSEQ_CPU_ID_OFFSET(%[rseq_abi]), %l[error1])
196 "movq %[v], %%rbx\n\t"
197 "cmpq %%rbx, %[expectnot]\n\t"
198 "je %l[error2]\n\t"
199 #endif
200 "movq %%rbx, %[load]\n\t"
201 "addq %[voffp], %%rbx\n\t"
202 "movq (%%rbx), %%rbx\n\t"
203 /* final store */
204 "movq %%rbx, %[v]\n\t"
205 "2:\n\t"
206 RSEQ_INJECT_ASM(5)
207 RSEQ_ASM_DEFINE_ABORT(4, "", abort)
208 : /* gcc asm goto does not allow outputs */
209 : [cpu_id] "r" (cpu),
210 [rseq_abi] "r" (&__rseq_abi),
211 /* final store input */
212 [v] "m" (*v),
213 [expectnot] "r" (expectnot),
214 [voffp] "er" (voffp),
215 [load] "m" (*load)
216 : "memory", "cc", "rax", "rbx"
217 RSEQ_INJECT_CLOBBER
218 : abort, cmpfail
219 #ifdef RSEQ_COMPARE_TWICE
220 , error1, error2
221 #endif
223 return 0;
224 abort:
225 RSEQ_INJECT_FAILED
226 return -1;
227 cmpfail:
228 return 1;
229 #ifdef RSEQ_COMPARE_TWICE
230 error1:
231 rseq_bug("cpu_id comparison failed");
232 error2:
233 rseq_bug("expected value comparison failed");
234 #endif
237 static inline __attribute__((always_inline))
238 int rseq_addv(intptr_t *v, intptr_t count, int cpu)
240 RSEQ_INJECT_C(9)
242 __asm__ __volatile__ goto (
243 RSEQ_ASM_DEFINE_TABLE(3, 1f, 2f, 4f) /* start, commit, abort */
244 #ifdef RSEQ_COMPARE_TWICE
245 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error1])
246 #endif
247 /* Start rseq by storing table entry pointer into rseq_cs. */
248 RSEQ_ASM_STORE_RSEQ_CS(1, 3b, RSEQ_CS_OFFSET(%[rseq_abi]))
249 RSEQ_ASM_CMP_CPU_ID(cpu_id, RSEQ_CPU_ID_OFFSET(%[rseq_abi]), 4f)
250 RSEQ_INJECT_ASM(3)
251 #ifdef RSEQ_COMPARE_TWICE
252 RSEQ_ASM_CMP_CPU_ID(cpu_id, RSEQ_CPU_ID_OFFSET(%[rseq_abi]), %l[error1])
253 #endif
254 /* final store */
255 "addq %[count], %[v]\n\t"
256 "2:\n\t"
257 RSEQ_INJECT_ASM(4)
258 RSEQ_ASM_DEFINE_ABORT(4, "", abort)
259 : /* gcc asm goto does not allow outputs */
260 : [cpu_id] "r" (cpu),
261 [rseq_abi] "r" (&__rseq_abi),
262 /* final store input */
263 [v] "m" (*v),
264 [count] "er" (count)
265 : "memory", "cc", "rax"
266 RSEQ_INJECT_CLOBBER
267 : abort
268 #ifdef RSEQ_COMPARE_TWICE
269 , error1
270 #endif
272 return 0;
273 abort:
274 RSEQ_INJECT_FAILED
275 return -1;
276 #ifdef RSEQ_COMPARE_TWICE
277 error1:
278 rseq_bug("cpu_id comparison failed");
279 #endif
282 static inline __attribute__((always_inline))
283 int rseq_cmpeqv_trystorev_storev(intptr_t *v, intptr_t expect,
284 intptr_t *v2, intptr_t newv2,
285 intptr_t newv, int cpu)
287 RSEQ_INJECT_C(9)
289 __asm__ __volatile__ goto (
290 RSEQ_ASM_DEFINE_TABLE(3, 1f, 2f, 4f) /* start, commit, abort */
291 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[cmpfail])
292 #ifdef RSEQ_COMPARE_TWICE
293 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error1])
294 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error2])
295 #endif
296 /* Start rseq by storing table entry pointer into rseq_cs. */
297 RSEQ_ASM_STORE_RSEQ_CS(1, 3b, RSEQ_CS_OFFSET(%[rseq_abi]))
298 RSEQ_ASM_CMP_CPU_ID(cpu_id, RSEQ_CPU_ID_OFFSET(%[rseq_abi]), 4f)
299 RSEQ_INJECT_ASM(3)
300 "cmpq %[v], %[expect]\n\t"
301 "jnz %l[cmpfail]\n\t"
302 RSEQ_INJECT_ASM(4)
303 #ifdef RSEQ_COMPARE_TWICE
304 RSEQ_ASM_CMP_CPU_ID(cpu_id, RSEQ_CPU_ID_OFFSET(%[rseq_abi]), %l[error1])
305 "cmpq %[v], %[expect]\n\t"
306 "jnz %l[error2]\n\t"
307 #endif
308 /* try store */
309 "movq %[newv2], %[v2]\n\t"
310 RSEQ_INJECT_ASM(5)
311 /* final store */
312 "movq %[newv], %[v]\n\t"
313 "2:\n\t"
314 RSEQ_INJECT_ASM(6)
315 RSEQ_ASM_DEFINE_ABORT(4, "", abort)
316 : /* gcc asm goto does not allow outputs */
317 : [cpu_id] "r" (cpu),
318 [rseq_abi] "r" (&__rseq_abi),
319 /* try store input */
320 [v2] "m" (*v2),
321 [newv2] "r" (newv2),
322 /* final store input */
323 [v] "m" (*v),
324 [expect] "r" (expect),
325 [newv] "r" (newv)
326 : "memory", "cc", "rax"
327 RSEQ_INJECT_CLOBBER
328 : abort, cmpfail
329 #ifdef RSEQ_COMPARE_TWICE
330 , error1, error2
331 #endif
333 return 0;
334 abort:
335 RSEQ_INJECT_FAILED
336 return -1;
337 cmpfail:
338 return 1;
339 #ifdef RSEQ_COMPARE_TWICE
340 error1:
341 rseq_bug("cpu_id comparison failed");
342 error2:
343 rseq_bug("expected value comparison failed");
344 #endif
347 /* x86-64 is TSO. */
348 static inline __attribute__((always_inline))
349 int rseq_cmpeqv_trystorev_storev_release(intptr_t *v, intptr_t expect,
350 intptr_t *v2, intptr_t newv2,
351 intptr_t newv, int cpu)
353 return rseq_cmpeqv_trystorev_storev(v, expect, v2, newv2, newv, cpu);
356 static inline __attribute__((always_inline))
357 int rseq_cmpeqv_cmpeqv_storev(intptr_t *v, intptr_t expect,
358 intptr_t *v2, intptr_t expect2,
359 intptr_t newv, int cpu)
361 RSEQ_INJECT_C(9)
363 __asm__ __volatile__ goto (
364 RSEQ_ASM_DEFINE_TABLE(3, 1f, 2f, 4f) /* start, commit, abort */
365 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[cmpfail])
366 #ifdef RSEQ_COMPARE_TWICE
367 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error1])
368 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error2])
369 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error3])
370 #endif
371 /* Start rseq by storing table entry pointer into rseq_cs. */
372 RSEQ_ASM_STORE_RSEQ_CS(1, 3b, RSEQ_CS_OFFSET(%[rseq_abi]))
373 RSEQ_ASM_CMP_CPU_ID(cpu_id, RSEQ_CPU_ID_OFFSET(%[rseq_abi]), 4f)
374 RSEQ_INJECT_ASM(3)
375 "cmpq %[v], %[expect]\n\t"
376 "jnz %l[cmpfail]\n\t"
377 RSEQ_INJECT_ASM(4)
378 "cmpq %[v2], %[expect2]\n\t"
379 "jnz %l[cmpfail]\n\t"
380 RSEQ_INJECT_ASM(5)
381 #ifdef RSEQ_COMPARE_TWICE
382 RSEQ_ASM_CMP_CPU_ID(cpu_id, RSEQ_CPU_ID_OFFSET(%[rseq_abi]), %l[error1])
383 "cmpq %[v], %[expect]\n\t"
384 "jnz %l[error2]\n\t"
385 "cmpq %[v2], %[expect2]\n\t"
386 "jnz %l[error3]\n\t"
387 #endif
388 /* final store */
389 "movq %[newv], %[v]\n\t"
390 "2:\n\t"
391 RSEQ_INJECT_ASM(6)
392 RSEQ_ASM_DEFINE_ABORT(4, "", abort)
393 : /* gcc asm goto does not allow outputs */
394 : [cpu_id] "r" (cpu),
395 [rseq_abi] "r" (&__rseq_abi),
396 /* cmp2 input */
397 [v2] "m" (*v2),
398 [expect2] "r" (expect2),
399 /* final store input */
400 [v] "m" (*v),
401 [expect] "r" (expect),
402 [newv] "r" (newv)
403 : "memory", "cc", "rax"
404 RSEQ_INJECT_CLOBBER
405 : abort, cmpfail
406 #ifdef RSEQ_COMPARE_TWICE
407 , error1, error2, error3
408 #endif
410 return 0;
411 abort:
412 RSEQ_INJECT_FAILED
413 return -1;
414 cmpfail:
415 return 1;
416 #ifdef RSEQ_COMPARE_TWICE
417 error1:
418 rseq_bug("cpu_id comparison failed");
419 error2:
420 rseq_bug("1st expected value comparison failed");
421 error3:
422 rseq_bug("2nd expected value comparison failed");
423 #endif
426 static inline __attribute__((always_inline))
427 int rseq_cmpeqv_trymemcpy_storev(intptr_t *v, intptr_t expect,
428 void *dst, void *src, size_t len,
429 intptr_t newv, int cpu)
431 uint64_t rseq_scratch[3];
433 RSEQ_INJECT_C(9)
435 __asm__ __volatile__ goto (
436 RSEQ_ASM_DEFINE_TABLE(3, 1f, 2f, 4f) /* start, commit, abort */
437 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[cmpfail])
438 #ifdef RSEQ_COMPARE_TWICE
439 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error1])
440 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error2])
441 #endif
442 "movq %[src], %[rseq_scratch0]\n\t"
443 "movq %[dst], %[rseq_scratch1]\n\t"
444 "movq %[len], %[rseq_scratch2]\n\t"
445 /* Start rseq by storing table entry pointer into rseq_cs. */
446 RSEQ_ASM_STORE_RSEQ_CS(1, 3b, RSEQ_CS_OFFSET(%[rseq_abi]))
447 RSEQ_ASM_CMP_CPU_ID(cpu_id, RSEQ_CPU_ID_OFFSET(%[rseq_abi]), 4f)
448 RSEQ_INJECT_ASM(3)
449 "cmpq %[v], %[expect]\n\t"
450 "jnz 5f\n\t"
451 RSEQ_INJECT_ASM(4)
452 #ifdef RSEQ_COMPARE_TWICE
453 RSEQ_ASM_CMP_CPU_ID(cpu_id, RSEQ_CPU_ID_OFFSET(%[rseq_abi]), 6f)
454 "cmpq %[v], %[expect]\n\t"
455 "jnz 7f\n\t"
456 #endif
457 /* try memcpy */
458 "test %[len], %[len]\n\t" \
459 "jz 333f\n\t" \
460 "222:\n\t" \
461 "movb (%[src]), %%al\n\t" \
462 "movb %%al, (%[dst])\n\t" \
463 "inc %[src]\n\t" \
464 "inc %[dst]\n\t" \
465 "dec %[len]\n\t" \
466 "jnz 222b\n\t" \
467 "333:\n\t" \
468 RSEQ_INJECT_ASM(5)
469 /* final store */
470 "movq %[newv], %[v]\n\t"
471 "2:\n\t"
472 RSEQ_INJECT_ASM(6)
473 /* teardown */
474 "movq %[rseq_scratch2], %[len]\n\t"
475 "movq %[rseq_scratch1], %[dst]\n\t"
476 "movq %[rseq_scratch0], %[src]\n\t"
477 RSEQ_ASM_DEFINE_ABORT(4,
478 "movq %[rseq_scratch2], %[len]\n\t"
479 "movq %[rseq_scratch1], %[dst]\n\t"
480 "movq %[rseq_scratch0], %[src]\n\t",
481 abort)
482 RSEQ_ASM_DEFINE_CMPFAIL(5,
483 "movq %[rseq_scratch2], %[len]\n\t"
484 "movq %[rseq_scratch1], %[dst]\n\t"
485 "movq %[rseq_scratch0], %[src]\n\t",
486 cmpfail)
487 #ifdef RSEQ_COMPARE_TWICE
488 RSEQ_ASM_DEFINE_CMPFAIL(6,
489 "movq %[rseq_scratch2], %[len]\n\t"
490 "movq %[rseq_scratch1], %[dst]\n\t"
491 "movq %[rseq_scratch0], %[src]\n\t",
492 error1)
493 RSEQ_ASM_DEFINE_CMPFAIL(7,
494 "movq %[rseq_scratch2], %[len]\n\t"
495 "movq %[rseq_scratch1], %[dst]\n\t"
496 "movq %[rseq_scratch0], %[src]\n\t",
497 error2)
498 #endif
499 : /* gcc asm goto does not allow outputs */
500 : [cpu_id] "r" (cpu),
501 [rseq_abi] "r" (&__rseq_abi),
502 /* final store input */
503 [v] "m" (*v),
504 [expect] "r" (expect),
505 [newv] "r" (newv),
506 /* try memcpy input */
507 [dst] "r" (dst),
508 [src] "r" (src),
509 [len] "r" (len),
510 [rseq_scratch0] "m" (rseq_scratch[0]),
511 [rseq_scratch1] "m" (rseq_scratch[1]),
512 [rseq_scratch2] "m" (rseq_scratch[2])
513 : "memory", "cc", "rax"
514 RSEQ_INJECT_CLOBBER
515 : abort, cmpfail
516 #ifdef RSEQ_COMPARE_TWICE
517 , error1, error2
518 #endif
520 return 0;
521 abort:
522 RSEQ_INJECT_FAILED
523 return -1;
524 cmpfail:
525 return 1;
526 #ifdef RSEQ_COMPARE_TWICE
527 error1:
528 rseq_bug("cpu_id comparison failed");
529 error2:
530 rseq_bug("expected value comparison failed");
531 #endif
534 /* x86-64 is TSO. */
535 static inline __attribute__((always_inline))
536 int rseq_cmpeqv_trymemcpy_storev_release(intptr_t *v, intptr_t expect,
537 void *dst, void *src, size_t len,
538 intptr_t newv, int cpu)
540 return rseq_cmpeqv_trymemcpy_storev(v, expect, dst, src, len,
541 newv, cpu);
544 #endif /* !RSEQ_SKIP_FASTPATH */
546 #elif __i386__
548 #define rseq_smp_mb() \
549 __asm__ __volatile__ ("lock; addl $0,-128(%%esp)" ::: "memory", "cc")
550 #define rseq_smp_rmb() \
551 __asm__ __volatile__ ("lock; addl $0,-128(%%esp)" ::: "memory", "cc")
552 #define rseq_smp_wmb() \
553 __asm__ __volatile__ ("lock; addl $0,-128(%%esp)" ::: "memory", "cc")
555 #define rseq_smp_load_acquire(p) \
556 __extension__ ({ \
557 __typeof(*p) ____p1 = RSEQ_READ_ONCE(*p); \
558 rseq_smp_mb(); \
559 ____p1; \
562 #define rseq_smp_acquire__after_ctrl_dep() rseq_smp_rmb()
564 #define rseq_smp_store_release(p, v) \
565 do { \
566 rseq_smp_mb(); \
567 RSEQ_WRITE_ONCE(*p, v); \
568 } while (0)
570 #ifdef RSEQ_SKIP_FASTPATH
571 #include "rseq-skip.h"
572 #else /* !RSEQ_SKIP_FASTPATH */
575 * Use eax as scratch register and take memory operands as input to
576 * lessen register pressure. Especially needed when compiling in O0.
578 #define __RSEQ_ASM_DEFINE_TABLE(label, version, flags, \
579 start_ip, post_commit_offset, abort_ip) \
580 ".pushsection __rseq_cs, \"aw\"\n\t" \
581 ".balign 32\n\t" \
582 __rseq_str(label) ":\n\t" \
583 ".long " __rseq_str(version) ", " __rseq_str(flags) "\n\t" \
584 ".long " __rseq_str(start_ip) ", 0x0, " __rseq_str(post_commit_offset) ", 0x0, " __rseq_str(abort_ip) ", 0x0\n\t" \
585 ".popsection\n\t" \
586 ".pushsection __rseq_cs_ptr_array, \"aw\"\n\t" \
587 ".long " __rseq_str(label) "b, 0x0\n\t" \
588 ".popsection\n\t"
590 #define RSEQ_ASM_DEFINE_TABLE(label, start_ip, post_commit_ip, abort_ip) \
591 __RSEQ_ASM_DEFINE_TABLE(label, 0x0, 0x0, start_ip, \
592 (post_commit_ip - start_ip), abort_ip)
595 * Exit points of a rseq critical section consist of all instructions outside
596 * of the critical section where a critical section can either branch to or
597 * reach through the normal course of its execution. The abort IP and the
598 * post-commit IP are already part of the __rseq_cs section and should not be
599 * explicitly defined as additional exit points. Knowing all exit points is
600 * useful to assist debuggers stepping over the critical section.
602 #define RSEQ_ASM_DEFINE_EXIT_POINT(start_ip, exit_ip) \
603 ".pushsection __rseq_exit_point_array, \"aw\"\n\t" \
604 ".long " __rseq_str(start_ip) ", 0x0, " __rseq_str(exit_ip) ", 0x0\n\t" \
605 ".popsection\n\t"
607 #define RSEQ_ASM_STORE_RSEQ_CS(label, cs_label, rseq_cs) \
608 RSEQ_INJECT_ASM(1) \
609 "movl $" __rseq_str(cs_label) ", " __rseq_str(rseq_cs) "\n\t" \
610 __rseq_str(label) ":\n\t"
612 #define RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, label) \
613 RSEQ_INJECT_ASM(2) \
614 "cmpl %[" __rseq_str(cpu_id) "], " __rseq_str(current_cpu_id) "\n\t" \
615 "jnz " __rseq_str(label) "\n\t"
617 #define RSEQ_ASM_DEFINE_ABORT(label, teardown, abort_label) \
618 ".pushsection __rseq_failure, \"ax\"\n\t" \
619 /* Disassembler-friendly signature: ud1 <sig>,%edi. */ \
620 ".byte 0x0f, 0xb9, 0x3d\n\t" \
621 ".long " __rseq_str(RSEQ_SIG) "\n\t" \
622 __rseq_str(label) ":\n\t" \
623 teardown \
624 "jmp %l[" __rseq_str(abort_label) "]\n\t" \
625 ".popsection\n\t"
627 #define RSEQ_ASM_DEFINE_CMPFAIL(label, teardown, cmpfail_label) \
628 ".pushsection __rseq_failure, \"ax\"\n\t" \
629 __rseq_str(label) ":\n\t" \
630 teardown \
631 "jmp %l[" __rseq_str(cmpfail_label) "]\n\t" \
632 ".popsection\n\t"
634 static inline __attribute__((always_inline))
635 int rseq_cmpeqv_storev(intptr_t *v, intptr_t expect, intptr_t newv, int cpu)
637 RSEQ_INJECT_C(9)
639 __asm__ __volatile__ goto (
640 RSEQ_ASM_DEFINE_TABLE(3, 1f, 2f, 4f) /* start, commit, abort */
641 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[cmpfail])
642 #ifdef RSEQ_COMPARE_TWICE
643 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error1])
644 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error2])
645 #endif
646 /* Start rseq by storing table entry pointer into rseq_cs. */
647 RSEQ_ASM_STORE_RSEQ_CS(1, 3b, RSEQ_CS_OFFSET(%[rseq_abi]))
648 RSEQ_ASM_CMP_CPU_ID(cpu_id, RSEQ_CPU_ID_OFFSET(%[rseq_abi]), 4f)
649 RSEQ_INJECT_ASM(3)
650 "cmpl %[v], %[expect]\n\t"
651 "jnz %l[cmpfail]\n\t"
652 RSEQ_INJECT_ASM(4)
653 #ifdef RSEQ_COMPARE_TWICE
654 RSEQ_ASM_CMP_CPU_ID(cpu_id, RSEQ_CPU_ID_OFFSET(%[rseq_abi]), %l[error1])
655 "cmpl %[v], %[expect]\n\t"
656 "jnz %l[error2]\n\t"
657 #endif
658 /* final store */
659 "movl %[newv], %[v]\n\t"
660 "2:\n\t"
661 RSEQ_INJECT_ASM(5)
662 RSEQ_ASM_DEFINE_ABORT(4, "", abort)
663 : /* gcc asm goto does not allow outputs */
664 : [cpu_id] "r" (cpu),
665 [rseq_abi] "r" (&__rseq_abi),
666 [v] "m" (*v),
667 [expect] "r" (expect),
668 [newv] "r" (newv)
669 : "memory", "cc", "eax"
670 RSEQ_INJECT_CLOBBER
671 : abort, cmpfail
672 #ifdef RSEQ_COMPARE_TWICE
673 , error1, error2
674 #endif
676 return 0;
677 abort:
678 RSEQ_INJECT_FAILED
679 return -1;
680 cmpfail:
681 return 1;
682 #ifdef RSEQ_COMPARE_TWICE
683 error1:
684 rseq_bug("cpu_id comparison failed");
685 error2:
686 rseq_bug("expected value comparison failed");
687 #endif
691 * Compare @v against @expectnot. When it does _not_ match, load @v
692 * into @load, and store the content of *@v + voffp into @v.
694 static inline __attribute__((always_inline))
695 int rseq_cmpnev_storeoffp_load(intptr_t *v, intptr_t expectnot,
696 off_t voffp, intptr_t *load, int cpu)
698 RSEQ_INJECT_C(9)
700 __asm__ __volatile__ goto (
701 RSEQ_ASM_DEFINE_TABLE(3, 1f, 2f, 4f) /* start, commit, abort */
702 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[cmpfail])
703 #ifdef RSEQ_COMPARE_TWICE
704 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error1])
705 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error2])
706 #endif
707 /* Start rseq by storing table entry pointer into rseq_cs. */
708 RSEQ_ASM_STORE_RSEQ_CS(1, 3b, RSEQ_CS_OFFSET(%[rseq_abi]))
709 RSEQ_ASM_CMP_CPU_ID(cpu_id, RSEQ_CPU_ID_OFFSET(%[rseq_abi]), 4f)
710 RSEQ_INJECT_ASM(3)
711 "movl %[v], %%ebx\n\t"
712 "cmpl %%ebx, %[expectnot]\n\t"
713 "je %l[cmpfail]\n\t"
714 RSEQ_INJECT_ASM(4)
715 #ifdef RSEQ_COMPARE_TWICE
716 RSEQ_ASM_CMP_CPU_ID(cpu_id, RSEQ_CPU_ID_OFFSET(%[rseq_abi]), %l[error1])
717 "movl %[v], %%ebx\n\t"
718 "cmpl %%ebx, %[expectnot]\n\t"
719 "je %l[error2]\n\t"
720 #endif
721 "movl %%ebx, %[load]\n\t"
722 "addl %[voffp], %%ebx\n\t"
723 "movl (%%ebx), %%ebx\n\t"
724 /* final store */
725 "movl %%ebx, %[v]\n\t"
726 "2:\n\t"
727 RSEQ_INJECT_ASM(5)
728 RSEQ_ASM_DEFINE_ABORT(4, "", abort)
729 : /* gcc asm goto does not allow outputs */
730 : [cpu_id] "r" (cpu),
731 [rseq_abi] "r" (&__rseq_abi),
732 /* final store input */
733 [v] "m" (*v),
734 [expectnot] "r" (expectnot),
735 [voffp] "ir" (voffp),
736 [load] "m" (*load)
737 : "memory", "cc", "eax", "ebx"
738 RSEQ_INJECT_CLOBBER
739 : abort, cmpfail
740 #ifdef RSEQ_COMPARE_TWICE
741 , error1, error2
742 #endif
744 return 0;
745 abort:
746 RSEQ_INJECT_FAILED
747 return -1;
748 cmpfail:
749 return 1;
750 #ifdef RSEQ_COMPARE_TWICE
751 error1:
752 rseq_bug("cpu_id comparison failed");
753 error2:
754 rseq_bug("expected value comparison failed");
755 #endif
758 static inline __attribute__((always_inline))
759 int rseq_addv(intptr_t *v, intptr_t count, int cpu)
761 RSEQ_INJECT_C(9)
763 __asm__ __volatile__ goto (
764 RSEQ_ASM_DEFINE_TABLE(3, 1f, 2f, 4f) /* start, commit, abort */
765 #ifdef RSEQ_COMPARE_TWICE
766 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error1])
767 #endif
768 /* Start rseq by storing table entry pointer into rseq_cs. */
769 RSEQ_ASM_STORE_RSEQ_CS(1, 3b, RSEQ_CS_OFFSET(%[rseq_abi]))
770 RSEQ_ASM_CMP_CPU_ID(cpu_id, RSEQ_CPU_ID_OFFSET(%[rseq_abi]), 4f)
771 RSEQ_INJECT_ASM(3)
772 #ifdef RSEQ_COMPARE_TWICE
773 RSEQ_ASM_CMP_CPU_ID(cpu_id, RSEQ_CPU_ID_OFFSET(%[rseq_abi]), %l[error1])
774 #endif
775 /* final store */
776 "addl %[count], %[v]\n\t"
777 "2:\n\t"
778 RSEQ_INJECT_ASM(4)
779 RSEQ_ASM_DEFINE_ABORT(4, "", abort)
780 : /* gcc asm goto does not allow outputs */
781 : [cpu_id] "r" (cpu),
782 [rseq_abi] "r" (&__rseq_abi),
783 /* final store input */
784 [v] "m" (*v),
785 [count] "ir" (count)
786 : "memory", "cc", "eax"
787 RSEQ_INJECT_CLOBBER
788 : abort
789 #ifdef RSEQ_COMPARE_TWICE
790 , error1
791 #endif
793 return 0;
794 abort:
795 RSEQ_INJECT_FAILED
796 return -1;
797 #ifdef RSEQ_COMPARE_TWICE
798 error1:
799 rseq_bug("cpu_id comparison failed");
800 #endif
803 static inline __attribute__((always_inline))
804 int rseq_cmpeqv_trystorev_storev(intptr_t *v, intptr_t expect,
805 intptr_t *v2, intptr_t newv2,
806 intptr_t newv, int cpu)
808 RSEQ_INJECT_C(9)
810 __asm__ __volatile__ goto (
811 RSEQ_ASM_DEFINE_TABLE(3, 1f, 2f, 4f) /* start, commit, abort */
812 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[cmpfail])
813 #ifdef RSEQ_COMPARE_TWICE
814 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error1])
815 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error2])
816 #endif
817 /* Start rseq by storing table entry pointer into rseq_cs. */
818 RSEQ_ASM_STORE_RSEQ_CS(1, 3b, RSEQ_CS_OFFSET(%[rseq_abi]))
819 RSEQ_ASM_CMP_CPU_ID(cpu_id, RSEQ_CPU_ID_OFFSET(%[rseq_abi]), 4f)
820 RSEQ_INJECT_ASM(3)
821 "cmpl %[v], %[expect]\n\t"
822 "jnz %l[cmpfail]\n\t"
823 RSEQ_INJECT_ASM(4)
824 #ifdef RSEQ_COMPARE_TWICE
825 RSEQ_ASM_CMP_CPU_ID(cpu_id, RSEQ_CPU_ID_OFFSET(%[rseq_abi]), %l[error1])
826 "cmpl %[v], %[expect]\n\t"
827 "jnz %l[error2]\n\t"
828 #endif
829 /* try store */
830 "movl %[newv2], %%eax\n\t"
831 "movl %%eax, %[v2]\n\t"
832 RSEQ_INJECT_ASM(5)
833 /* final store */
834 "movl %[newv], %[v]\n\t"
835 "2:\n\t"
836 RSEQ_INJECT_ASM(6)
837 RSEQ_ASM_DEFINE_ABORT(4, "", abort)
838 : /* gcc asm goto does not allow outputs */
839 : [cpu_id] "r" (cpu),
840 [rseq_abi] "r" (&__rseq_abi),
841 /* try store input */
842 [v2] "m" (*v2),
843 [newv2] "m" (newv2),
844 /* final store input */
845 [v] "m" (*v),
846 [expect] "r" (expect),
847 [newv] "r" (newv)
848 : "memory", "cc", "eax"
849 RSEQ_INJECT_CLOBBER
850 : abort, cmpfail
851 #ifdef RSEQ_COMPARE_TWICE
852 , error1, error2
853 #endif
855 return 0;
856 abort:
857 RSEQ_INJECT_FAILED
858 return -1;
859 cmpfail:
860 return 1;
861 #ifdef RSEQ_COMPARE_TWICE
862 error1:
863 rseq_bug("cpu_id comparison failed");
864 error2:
865 rseq_bug("expected value comparison failed");
866 #endif
869 static inline __attribute__((always_inline))
870 int rseq_cmpeqv_trystorev_storev_release(intptr_t *v, intptr_t expect,
871 intptr_t *v2, intptr_t newv2,
872 intptr_t newv, int cpu)
874 RSEQ_INJECT_C(9)
876 __asm__ __volatile__ goto (
877 RSEQ_ASM_DEFINE_TABLE(3, 1f, 2f, 4f) /* start, commit, abort */
878 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[cmpfail])
879 #ifdef RSEQ_COMPARE_TWICE
880 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error1])
881 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error2])
882 #endif
883 /* Start rseq by storing table entry pointer into rseq_cs. */
884 RSEQ_ASM_STORE_RSEQ_CS(1, 3b, RSEQ_CS_OFFSET(%[rseq_abi]))
885 RSEQ_ASM_CMP_CPU_ID(cpu_id, RSEQ_CPU_ID_OFFSET(%[rseq_abi]), 4f)
886 RSEQ_INJECT_ASM(3)
887 "movl %[expect], %%eax\n\t"
888 "cmpl %[v], %%eax\n\t"
889 "jnz %l[cmpfail]\n\t"
890 RSEQ_INJECT_ASM(4)
891 #ifdef RSEQ_COMPARE_TWICE
892 RSEQ_ASM_CMP_CPU_ID(cpu_id, RSEQ_CPU_ID_OFFSET(%[rseq_abi]), %l[error1])
893 "movl %[expect], %%eax\n\t"
894 "cmpl %[v], %%eax\n\t"
895 "jnz %l[error2]\n\t"
896 #endif
897 /* try store */
898 "movl %[newv2], %[v2]\n\t"
899 RSEQ_INJECT_ASM(5)
900 "lock; addl $0,-128(%%esp)\n\t"
901 /* final store */
902 "movl %[newv], %[v]\n\t"
903 "2:\n\t"
904 RSEQ_INJECT_ASM(6)
905 RSEQ_ASM_DEFINE_ABORT(4, "", abort)
906 : /* gcc asm goto does not allow outputs */
907 : [cpu_id] "r" (cpu),
908 [rseq_abi] "r" (&__rseq_abi),
909 /* try store input */
910 [v2] "m" (*v2),
911 [newv2] "r" (newv2),
912 /* final store input */
913 [v] "m" (*v),
914 [expect] "m" (expect),
915 [newv] "r" (newv)
916 : "memory", "cc", "eax"
917 RSEQ_INJECT_CLOBBER
918 : abort, cmpfail
919 #ifdef RSEQ_COMPARE_TWICE
920 , error1, error2
921 #endif
923 return 0;
924 abort:
925 RSEQ_INJECT_FAILED
926 return -1;
927 cmpfail:
928 return 1;
929 #ifdef RSEQ_COMPARE_TWICE
930 error1:
931 rseq_bug("cpu_id comparison failed");
932 error2:
933 rseq_bug("expected value comparison failed");
934 #endif
938 static inline __attribute__((always_inline))
939 int rseq_cmpeqv_cmpeqv_storev(intptr_t *v, intptr_t expect,
940 intptr_t *v2, intptr_t expect2,
941 intptr_t newv, int cpu)
943 RSEQ_INJECT_C(9)
945 __asm__ __volatile__ goto (
946 RSEQ_ASM_DEFINE_TABLE(3, 1f, 2f, 4f) /* start, commit, abort */
947 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[cmpfail])
948 #ifdef RSEQ_COMPARE_TWICE
949 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error1])
950 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error2])
951 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error3])
952 #endif
953 /* Start rseq by storing table entry pointer into rseq_cs. */
954 RSEQ_ASM_STORE_RSEQ_CS(1, 3b, RSEQ_CS_OFFSET(%[rseq_abi]))
955 RSEQ_ASM_CMP_CPU_ID(cpu_id, RSEQ_CPU_ID_OFFSET(%[rseq_abi]), 4f)
956 RSEQ_INJECT_ASM(3)
957 "cmpl %[v], %[expect]\n\t"
958 "jnz %l[cmpfail]\n\t"
959 RSEQ_INJECT_ASM(4)
960 "cmpl %[expect2], %[v2]\n\t"
961 "jnz %l[cmpfail]\n\t"
962 RSEQ_INJECT_ASM(5)
963 #ifdef RSEQ_COMPARE_TWICE
964 RSEQ_ASM_CMP_CPU_ID(cpu_id, RSEQ_CPU_ID_OFFSET(%[rseq_abi]), %l[error1])
965 "cmpl %[v], %[expect]\n\t"
966 "jnz %l[error2]\n\t"
967 "cmpl %[expect2], %[v2]\n\t"
968 "jnz %l[error3]\n\t"
969 #endif
970 "movl %[newv], %%eax\n\t"
971 /* final store */
972 "movl %%eax, %[v]\n\t"
973 "2:\n\t"
974 RSEQ_INJECT_ASM(6)
975 RSEQ_ASM_DEFINE_ABORT(4, "", abort)
976 : /* gcc asm goto does not allow outputs */
977 : [cpu_id] "r" (cpu),
978 [rseq_abi] "r" (&__rseq_abi),
979 /* cmp2 input */
980 [v2] "m" (*v2),
981 [expect2] "r" (expect2),
982 /* final store input */
983 [v] "m" (*v),
984 [expect] "r" (expect),
985 [newv] "m" (newv)
986 : "memory", "cc", "eax"
987 RSEQ_INJECT_CLOBBER
988 : abort, cmpfail
989 #ifdef RSEQ_COMPARE_TWICE
990 , error1, error2, error3
991 #endif
993 return 0;
994 abort:
995 RSEQ_INJECT_FAILED
996 return -1;
997 cmpfail:
998 return 1;
999 #ifdef RSEQ_COMPARE_TWICE
1000 error1:
1001 rseq_bug("cpu_id comparison failed");
1002 error2:
1003 rseq_bug("1st expected value comparison failed");
1004 error3:
1005 rseq_bug("2nd expected value comparison failed");
1006 #endif
1009 /* TODO: implement a faster memcpy. */
1010 static inline __attribute__((always_inline))
1011 int rseq_cmpeqv_trymemcpy_storev(intptr_t *v, intptr_t expect,
1012 void *dst, void *src, size_t len,
1013 intptr_t newv, int cpu)
1015 uint32_t rseq_scratch[3];
1017 RSEQ_INJECT_C(9)
1019 __asm__ __volatile__ goto (
1020 RSEQ_ASM_DEFINE_TABLE(3, 1f, 2f, 4f) /* start, commit, abort */
1021 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[cmpfail])
1022 #ifdef RSEQ_COMPARE_TWICE
1023 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error1])
1024 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error2])
1025 #endif
1026 "movl %[src], %[rseq_scratch0]\n\t"
1027 "movl %[dst], %[rseq_scratch1]\n\t"
1028 "movl %[len], %[rseq_scratch2]\n\t"
1029 /* Start rseq by storing table entry pointer into rseq_cs. */
1030 RSEQ_ASM_STORE_RSEQ_CS(1, 3b, RSEQ_CS_OFFSET(%[rseq_abi]))
1031 RSEQ_ASM_CMP_CPU_ID(cpu_id, RSEQ_CPU_ID_OFFSET(%[rseq_abi]), 4f)
1032 RSEQ_INJECT_ASM(3)
1033 "movl %[expect], %%eax\n\t"
1034 "cmpl %%eax, %[v]\n\t"
1035 "jnz 5f\n\t"
1036 RSEQ_INJECT_ASM(4)
1037 #ifdef RSEQ_COMPARE_TWICE
1038 RSEQ_ASM_CMP_CPU_ID(cpu_id, RSEQ_CPU_ID_OFFSET(%[rseq_abi]), 6f)
1039 "movl %[expect], %%eax\n\t"
1040 "cmpl %%eax, %[v]\n\t"
1041 "jnz 7f\n\t"
1042 #endif
1043 /* try memcpy */
1044 "test %[len], %[len]\n\t" \
1045 "jz 333f\n\t" \
1046 "222:\n\t" \
1047 "movb (%[src]), %%al\n\t" \
1048 "movb %%al, (%[dst])\n\t" \
1049 "inc %[src]\n\t" \
1050 "inc %[dst]\n\t" \
1051 "dec %[len]\n\t" \
1052 "jnz 222b\n\t" \
1053 "333:\n\t" \
1054 RSEQ_INJECT_ASM(5)
1055 "movl %[newv], %%eax\n\t"
1056 /* final store */
1057 "movl %%eax, %[v]\n\t"
1058 "2:\n\t"
1059 RSEQ_INJECT_ASM(6)
1060 /* teardown */
1061 "movl %[rseq_scratch2], %[len]\n\t"
1062 "movl %[rseq_scratch1], %[dst]\n\t"
1063 "movl %[rseq_scratch0], %[src]\n\t"
1064 RSEQ_ASM_DEFINE_ABORT(4,
1065 "movl %[rseq_scratch2], %[len]\n\t"
1066 "movl %[rseq_scratch1], %[dst]\n\t"
1067 "movl %[rseq_scratch0], %[src]\n\t",
1068 abort)
1069 RSEQ_ASM_DEFINE_CMPFAIL(5,
1070 "movl %[rseq_scratch2], %[len]\n\t"
1071 "movl %[rseq_scratch1], %[dst]\n\t"
1072 "movl %[rseq_scratch0], %[src]\n\t",
1073 cmpfail)
1074 #ifdef RSEQ_COMPARE_TWICE
1075 RSEQ_ASM_DEFINE_CMPFAIL(6,
1076 "movl %[rseq_scratch2], %[len]\n\t"
1077 "movl %[rseq_scratch1], %[dst]\n\t"
1078 "movl %[rseq_scratch0], %[src]\n\t",
1079 error1)
1080 RSEQ_ASM_DEFINE_CMPFAIL(7,
1081 "movl %[rseq_scratch2], %[len]\n\t"
1082 "movl %[rseq_scratch1], %[dst]\n\t"
1083 "movl %[rseq_scratch0], %[src]\n\t",
1084 error2)
1085 #endif
1086 : /* gcc asm goto does not allow outputs */
1087 : [cpu_id] "r" (cpu),
1088 [rseq_abi] "r" (&__rseq_abi),
1089 /* final store input */
1090 [v] "m" (*v),
1091 [expect] "m" (expect),
1092 [newv] "m" (newv),
1093 /* try memcpy input */
1094 [dst] "r" (dst),
1095 [src] "r" (src),
1096 [len] "r" (len),
1097 [rseq_scratch0] "m" (rseq_scratch[0]),
1098 [rseq_scratch1] "m" (rseq_scratch[1]),
1099 [rseq_scratch2] "m" (rseq_scratch[2])
1100 : "memory", "cc", "eax"
1101 RSEQ_INJECT_CLOBBER
1102 : abort, cmpfail
1103 #ifdef RSEQ_COMPARE_TWICE
1104 , error1, error2
1105 #endif
1107 return 0;
1108 abort:
1109 RSEQ_INJECT_FAILED
1110 return -1;
1111 cmpfail:
1112 return 1;
1113 #ifdef RSEQ_COMPARE_TWICE
1114 error1:
1115 rseq_bug("cpu_id comparison failed");
1116 error2:
1117 rseq_bug("expected value comparison failed");
1118 #endif
1121 /* TODO: implement a faster memcpy. */
1122 static inline __attribute__((always_inline))
1123 int rseq_cmpeqv_trymemcpy_storev_release(intptr_t *v, intptr_t expect,
1124 void *dst, void *src, size_t len,
1125 intptr_t newv, int cpu)
1127 uint32_t rseq_scratch[3];
1129 RSEQ_INJECT_C(9)
1131 __asm__ __volatile__ goto (
1132 RSEQ_ASM_DEFINE_TABLE(3, 1f, 2f, 4f) /* start, commit, abort */
1133 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[cmpfail])
1134 #ifdef RSEQ_COMPARE_TWICE
1135 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error1])
1136 RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error2])
1137 #endif
1138 "movl %[src], %[rseq_scratch0]\n\t"
1139 "movl %[dst], %[rseq_scratch1]\n\t"
1140 "movl %[len], %[rseq_scratch2]\n\t"
1141 /* Start rseq by storing table entry pointer into rseq_cs. */
1142 RSEQ_ASM_STORE_RSEQ_CS(1, 3b, RSEQ_CS_OFFSET(%[rseq_abi]))
1143 RSEQ_ASM_CMP_CPU_ID(cpu_id, RSEQ_CPU_ID_OFFSET(%[rseq_abi]), 4f)
1144 RSEQ_INJECT_ASM(3)
1145 "movl %[expect], %%eax\n\t"
1146 "cmpl %%eax, %[v]\n\t"
1147 "jnz 5f\n\t"
1148 RSEQ_INJECT_ASM(4)
1149 #ifdef RSEQ_COMPARE_TWICE
1150 RSEQ_ASM_CMP_CPU_ID(cpu_id, RSEQ_CPU_ID_OFFSET(%[rseq_abi]), 6f)
1151 "movl %[expect], %%eax\n\t"
1152 "cmpl %%eax, %[v]\n\t"
1153 "jnz 7f\n\t"
1154 #endif
1155 /* try memcpy */
1156 "test %[len], %[len]\n\t" \
1157 "jz 333f\n\t" \
1158 "222:\n\t" \
1159 "movb (%[src]), %%al\n\t" \
1160 "movb %%al, (%[dst])\n\t" \
1161 "inc %[src]\n\t" \
1162 "inc %[dst]\n\t" \
1163 "dec %[len]\n\t" \
1164 "jnz 222b\n\t" \
1165 "333:\n\t" \
1166 RSEQ_INJECT_ASM(5)
1167 "lock; addl $0,-128(%%esp)\n\t"
1168 "movl %[newv], %%eax\n\t"
1169 /* final store */
1170 "movl %%eax, %[v]\n\t"
1171 "2:\n\t"
1172 RSEQ_INJECT_ASM(6)
1173 /* teardown */
1174 "movl %[rseq_scratch2], %[len]\n\t"
1175 "movl %[rseq_scratch1], %[dst]\n\t"
1176 "movl %[rseq_scratch0], %[src]\n\t"
1177 RSEQ_ASM_DEFINE_ABORT(4,
1178 "movl %[rseq_scratch2], %[len]\n\t"
1179 "movl %[rseq_scratch1], %[dst]\n\t"
1180 "movl %[rseq_scratch0], %[src]\n\t",
1181 abort)
1182 RSEQ_ASM_DEFINE_CMPFAIL(5,
1183 "movl %[rseq_scratch2], %[len]\n\t"
1184 "movl %[rseq_scratch1], %[dst]\n\t"
1185 "movl %[rseq_scratch0], %[src]\n\t",
1186 cmpfail)
1187 #ifdef RSEQ_COMPARE_TWICE
1188 RSEQ_ASM_DEFINE_CMPFAIL(6,
1189 "movl %[rseq_scratch2], %[len]\n\t"
1190 "movl %[rseq_scratch1], %[dst]\n\t"
1191 "movl %[rseq_scratch0], %[src]\n\t",
1192 error1)
1193 RSEQ_ASM_DEFINE_CMPFAIL(7,
1194 "movl %[rseq_scratch2], %[len]\n\t"
1195 "movl %[rseq_scratch1], %[dst]\n\t"
1196 "movl %[rseq_scratch0], %[src]\n\t",
1197 error2)
1198 #endif
1199 : /* gcc asm goto does not allow outputs */
1200 : [cpu_id] "r" (cpu),
1201 [rseq_abi] "r" (&__rseq_abi),
1202 /* final store input */
1203 [v] "m" (*v),
1204 [expect] "m" (expect),
1205 [newv] "m" (newv),
1206 /* try memcpy input */
1207 [dst] "r" (dst),
1208 [src] "r" (src),
1209 [len] "r" (len),
1210 [rseq_scratch0] "m" (rseq_scratch[0]),
1211 [rseq_scratch1] "m" (rseq_scratch[1]),
1212 [rseq_scratch2] "m" (rseq_scratch[2])
1213 : "memory", "cc", "eax"
1214 RSEQ_INJECT_CLOBBER
1215 : abort, cmpfail
1216 #ifdef RSEQ_COMPARE_TWICE
1217 , error1, error2
1218 #endif
1220 return 0;
1221 abort:
1222 RSEQ_INJECT_FAILED
1223 return -1;
1224 cmpfail:
1225 return 1;
1226 #ifdef RSEQ_COMPARE_TWICE
1227 error1:
1228 rseq_bug("cpu_id comparison failed");
1229 error2:
1230 rseq_bug("expected value comparison failed");
1231 #endif
1234 #endif /* !RSEQ_SKIP_FASTPATH */
1236 #endif