1 /* SPDX-License-Identifier: LGPL-2.1 OR MIT */
5 * (C) Copyright 2016-2018 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
10 #define RSEQ_SIG 0x53053053
14 #define rseq_smp_mb() \
15 __asm__ __volatile__ ("lock; addl $0,-128(%%rsp)" ::: "memory", "cc")
16 #define rseq_smp_rmb() rseq_barrier()
17 #define rseq_smp_wmb() rseq_barrier()
19 #define rseq_smp_load_acquire(p) \
21 __typeof(*p) ____p1 = RSEQ_READ_ONCE(*p); \
26 #define rseq_smp_acquire__after_ctrl_dep() rseq_smp_rmb()
28 #define rseq_smp_store_release(p, v) \
31 RSEQ_WRITE_ONCE(*p, v); \
34 #ifdef RSEQ_SKIP_FASTPATH
35 #include "rseq-skip.h"
36 #else /* !RSEQ_SKIP_FASTPATH */
38 #define __RSEQ_ASM_DEFINE_TABLE(label, version, flags, \
39 start_ip, post_commit_offset, abort_ip) \
40 ".pushsection __rseq_table, \"aw\"\n\t" \
42 __rseq_str(label) ":\n\t" \
43 ".long " __rseq_str(version) ", " __rseq_str(flags) "\n\t" \
44 ".quad " __rseq_str(start_ip) ", " __rseq_str(post_commit_offset) ", " __rseq_str(abort_ip) "\n\t" \
47 #define RSEQ_ASM_DEFINE_TABLE(label, start_ip, post_commit_ip, abort_ip) \
48 __RSEQ_ASM_DEFINE_TABLE(label, 0x0, 0x0, start_ip, \
49 (post_commit_ip - start_ip), abort_ip)
51 #define RSEQ_ASM_STORE_RSEQ_CS(label, cs_label, rseq_cs) \
53 "leaq " __rseq_str(cs_label) "(%%rip), %%rax\n\t" \
54 "movq %%rax, %[" __rseq_str(rseq_cs) "]\n\t" \
55 __rseq_str(label) ":\n\t"
57 #define RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, label) \
59 "cmpl %[" __rseq_str(cpu_id) "], %[" __rseq_str(current_cpu_id) "]\n\t" \
60 "jnz " __rseq_str(label) "\n\t"
62 #define RSEQ_ASM_DEFINE_ABORT(label, teardown, abort_label) \
63 ".pushsection __rseq_failure, \"ax\"\n\t" \
64 /* Disassembler-friendly signature: nopl <sig>(%rip). */\
65 ".byte 0x0f, 0x1f, 0x05\n\t" \
66 ".long " __rseq_str(RSEQ_SIG) "\n\t" \
67 __rseq_str(label) ":\n\t" \
69 "jmp %l[" __rseq_str(abort_label) "]\n\t" \
72 #define RSEQ_ASM_DEFINE_CMPFAIL(label, teardown, cmpfail_label) \
73 ".pushsection __rseq_failure, \"ax\"\n\t" \
74 __rseq_str(label) ":\n\t" \
76 "jmp %l[" __rseq_str(cmpfail_label) "]\n\t" \
79 static inline __attribute__((always_inline
))
80 int rseq_cmpeqv_storev(intptr_t *v
, intptr_t expect
, intptr_t newv
, int cpu
)
84 __asm__ __volatile__
goto (
85 RSEQ_ASM_DEFINE_TABLE(3, 1f
, 2f
, 4f
) /* start, commit, abort */
86 /* Start rseq by storing table entry pointer into rseq_cs. */
87 RSEQ_ASM_STORE_RSEQ_CS(1, 3b
, rseq_cs
)
88 RSEQ_ASM_CMP_CPU_ID(cpu_id
, current_cpu_id
, 4f
)
90 "cmpq %[v], %[expect]\n\t"
93 #ifdef RSEQ_COMPARE_TWICE
94 RSEQ_ASM_CMP_CPU_ID(cpu_id
, current_cpu_id
, %l
[error1
])
95 "cmpq %[v], %[expect]\n\t"
99 "movq %[newv], %[v]\n\t"
102 RSEQ_ASM_DEFINE_ABORT(4, "", abort
)
103 : /* gcc asm goto does not allow outputs */
104 : [cpu_id
] "r" (cpu
),
105 [current_cpu_id
] "m" (__rseq_abi
.cpu_id
),
106 [rseq_cs
] "m" (__rseq_abi
.rseq_cs
),
108 [expect
] "r" (expect
),
110 : "memory", "cc", "rax"
113 #ifdef RSEQ_COMPARE_TWICE
123 #ifdef RSEQ_COMPARE_TWICE
125 rseq_bug("cpu_id comparison failed");
127 rseq_bug("expected value comparison failed");
132 * Compare @v against @expectnot. When it does _not_ match, load @v
133 * into @load, and store the content of *@v + voffp into @v.
135 static inline __attribute__((always_inline
))
136 int rseq_cmpnev_storeoffp_load(intptr_t *v
, intptr_t expectnot
,
137 off_t voffp
, intptr_t *load
, int cpu
)
141 __asm__ __volatile__
goto (
142 RSEQ_ASM_DEFINE_TABLE(3, 1f
, 2f
, 4f
) /* start, commit, abort */
143 /* Start rseq by storing table entry pointer into rseq_cs. */
144 RSEQ_ASM_STORE_RSEQ_CS(1, 3b
, rseq_cs
)
145 RSEQ_ASM_CMP_CPU_ID(cpu_id
, current_cpu_id
, 4f
)
147 "movq %[v], %%rbx\n\t"
148 "cmpq %%rbx, %[expectnot]\n\t"
151 #ifdef RSEQ_COMPARE_TWICE
152 RSEQ_ASM_CMP_CPU_ID(cpu_id
, current_cpu_id
, %l
[error1
])
153 "movq %[v], %%rbx\n\t"
154 "cmpq %%rbx, %[expectnot]\n\t"
157 "movq %%rbx, %[load]\n\t"
158 "addq %[voffp], %%rbx\n\t"
159 "movq (%%rbx), %%rbx\n\t"
161 "movq %%rbx, %[v]\n\t"
164 RSEQ_ASM_DEFINE_ABORT(4, "", abort
)
165 : /* gcc asm goto does not allow outputs */
166 : [cpu_id
] "r" (cpu
),
167 [current_cpu_id
] "m" (__rseq_abi
.cpu_id
),
168 [rseq_cs
] "m" (__rseq_abi
.rseq_cs
),
169 /* final store input */
171 [expectnot
] "r" (expectnot
),
172 [voffp
] "er" (voffp
),
174 : "memory", "cc", "rax", "rbx"
177 #ifdef RSEQ_COMPARE_TWICE
187 #ifdef RSEQ_COMPARE_TWICE
189 rseq_bug("cpu_id comparison failed");
191 rseq_bug("expected value comparison failed");
195 static inline __attribute__((always_inline
))
196 int rseq_addv(intptr_t *v
, intptr_t count
, int cpu
)
200 __asm__ __volatile__
goto (
201 RSEQ_ASM_DEFINE_TABLE(3, 1f
, 2f
, 4f
) /* start, commit, abort */
202 /* Start rseq by storing table entry pointer into rseq_cs. */
203 RSEQ_ASM_STORE_RSEQ_CS(1, 3b
, rseq_cs
)
204 RSEQ_ASM_CMP_CPU_ID(cpu_id
, current_cpu_id
, 4f
)
206 #ifdef RSEQ_COMPARE_TWICE
207 RSEQ_ASM_CMP_CPU_ID(cpu_id
, current_cpu_id
, %l
[error1
])
210 "addq %[count], %[v]\n\t"
213 RSEQ_ASM_DEFINE_ABORT(4, "", abort
)
214 : /* gcc asm goto does not allow outputs */
215 : [cpu_id
] "r" (cpu
),
216 [current_cpu_id
] "m" (__rseq_abi
.cpu_id
),
217 [rseq_cs
] "m" (__rseq_abi
.rseq_cs
),
218 /* final store input */
221 : "memory", "cc", "rax"
224 #ifdef RSEQ_COMPARE_TWICE
232 #ifdef RSEQ_COMPARE_TWICE
234 rseq_bug("cpu_id comparison failed");
238 static inline __attribute__((always_inline
))
239 int rseq_cmpeqv_trystorev_storev(intptr_t *v
, intptr_t expect
,
240 intptr_t *v2
, intptr_t newv2
,
241 intptr_t newv
, int cpu
)
245 __asm__ __volatile__
goto (
246 RSEQ_ASM_DEFINE_TABLE(3, 1f
, 2f
, 4f
) /* start, commit, abort */
247 /* Start rseq by storing table entry pointer into rseq_cs. */
248 RSEQ_ASM_STORE_RSEQ_CS(1, 3b
, rseq_cs
)
249 RSEQ_ASM_CMP_CPU_ID(cpu_id
, current_cpu_id
, 4f
)
251 "cmpq %[v], %[expect]\n\t"
252 "jnz %l[cmpfail]\n\t"
254 #ifdef RSEQ_COMPARE_TWICE
255 RSEQ_ASM_CMP_CPU_ID(cpu_id
, current_cpu_id
, %l
[error1
])
256 "cmpq %[v], %[expect]\n\t"
260 "movq %[newv2], %[v2]\n\t"
263 "movq %[newv], %[v]\n\t"
266 RSEQ_ASM_DEFINE_ABORT(4, "", abort
)
267 : /* gcc asm goto does not allow outputs */
268 : [cpu_id
] "r" (cpu
),
269 [current_cpu_id
] "m" (__rseq_abi
.cpu_id
),
270 [rseq_cs
] "m" (__rseq_abi
.rseq_cs
),
271 /* try store input */
274 /* final store input */
276 [expect
] "r" (expect
),
278 : "memory", "cc", "rax"
281 #ifdef RSEQ_COMPARE_TWICE
291 #ifdef RSEQ_COMPARE_TWICE
293 rseq_bug("cpu_id comparison failed");
295 rseq_bug("expected value comparison failed");
300 static inline __attribute__((always_inline
))
301 int rseq_cmpeqv_trystorev_storev_release(intptr_t *v
, intptr_t expect
,
302 intptr_t *v2
, intptr_t newv2
,
303 intptr_t newv
, int cpu
)
305 return rseq_cmpeqv_trystorev_storev(v
, expect
, v2
, newv2
, newv
, cpu
);
308 static inline __attribute__((always_inline
))
309 int rseq_cmpeqv_cmpeqv_storev(intptr_t *v
, intptr_t expect
,
310 intptr_t *v2
, intptr_t expect2
,
311 intptr_t newv
, int cpu
)
315 __asm__ __volatile__
goto (
316 RSEQ_ASM_DEFINE_TABLE(3, 1f
, 2f
, 4f
) /* start, commit, abort */
317 /* Start rseq by storing table entry pointer into rseq_cs. */
318 RSEQ_ASM_STORE_RSEQ_CS(1, 3b
, rseq_cs
)
319 RSEQ_ASM_CMP_CPU_ID(cpu_id
, current_cpu_id
, 4f
)
321 "cmpq %[v], %[expect]\n\t"
322 "jnz %l[cmpfail]\n\t"
324 "cmpq %[v2], %[expect2]\n\t"
325 "jnz %l[cmpfail]\n\t"
327 #ifdef RSEQ_COMPARE_TWICE
328 RSEQ_ASM_CMP_CPU_ID(cpu_id
, current_cpu_id
, %l
[error1
])
329 "cmpq %[v], %[expect]\n\t"
331 "cmpq %[v2], %[expect2]\n\t"
335 "movq %[newv], %[v]\n\t"
338 RSEQ_ASM_DEFINE_ABORT(4, "", abort
)
339 : /* gcc asm goto does not allow outputs */
340 : [cpu_id
] "r" (cpu
),
341 [current_cpu_id
] "m" (__rseq_abi
.cpu_id
),
342 [rseq_cs
] "m" (__rseq_abi
.rseq_cs
),
345 [expect2
] "r" (expect2
),
346 /* final store input */
348 [expect
] "r" (expect
),
350 : "memory", "cc", "rax"
353 #ifdef RSEQ_COMPARE_TWICE
354 , error1
, error2
, error3
363 #ifdef RSEQ_COMPARE_TWICE
365 rseq_bug("cpu_id comparison failed");
367 rseq_bug("1st expected value comparison failed");
369 rseq_bug("2nd expected value comparison failed");
373 static inline __attribute__((always_inline
))
374 int rseq_cmpeqv_trymemcpy_storev(intptr_t *v
, intptr_t expect
,
375 void *dst
, void *src
, size_t len
,
376 intptr_t newv
, int cpu
)
378 uint64_t rseq_scratch
[3];
382 __asm__ __volatile__
goto (
383 RSEQ_ASM_DEFINE_TABLE(3, 1f
, 2f
, 4f
) /* start, commit, abort */
384 "movq %[src], %[rseq_scratch0]\n\t"
385 "movq %[dst], %[rseq_scratch1]\n\t"
386 "movq %[len], %[rseq_scratch2]\n\t"
387 /* Start rseq by storing table entry pointer into rseq_cs. */
388 RSEQ_ASM_STORE_RSEQ_CS(1, 3b
, rseq_cs
)
389 RSEQ_ASM_CMP_CPU_ID(cpu_id
, current_cpu_id
, 4f
)
391 "cmpq %[v], %[expect]\n\t"
394 #ifdef RSEQ_COMPARE_TWICE
395 RSEQ_ASM_CMP_CPU_ID(cpu_id
, current_cpu_id
, 6f
)
396 "cmpq %[v], %[expect]\n\t"
400 "test %[len], %[len]\n\t" \
403 "movb (%[src]), %%al\n\t" \
404 "movb %%al, (%[dst])\n\t" \
412 "movq %[newv], %[v]\n\t"
416 "movq %[rseq_scratch2], %[len]\n\t"
417 "movq %[rseq_scratch1], %[dst]\n\t"
418 "movq %[rseq_scratch0], %[src]\n\t"
419 RSEQ_ASM_DEFINE_ABORT(4,
420 "movq %[rseq_scratch2], %[len]\n\t"
421 "movq %[rseq_scratch1], %[dst]\n\t"
422 "movq %[rseq_scratch0], %[src]\n\t",
424 RSEQ_ASM_DEFINE_CMPFAIL(5,
425 "movq %[rseq_scratch2], %[len]\n\t"
426 "movq %[rseq_scratch1], %[dst]\n\t"
427 "movq %[rseq_scratch0], %[src]\n\t",
429 #ifdef RSEQ_COMPARE_TWICE
430 RSEQ_ASM_DEFINE_CMPFAIL(6,
431 "movq %[rseq_scratch2], %[len]\n\t"
432 "movq %[rseq_scratch1], %[dst]\n\t"
433 "movq %[rseq_scratch0], %[src]\n\t",
435 RSEQ_ASM_DEFINE_CMPFAIL(7,
436 "movq %[rseq_scratch2], %[len]\n\t"
437 "movq %[rseq_scratch1], %[dst]\n\t"
438 "movq %[rseq_scratch0], %[src]\n\t",
441 : /* gcc asm goto does not allow outputs */
442 : [cpu_id
] "r" (cpu
),
443 [current_cpu_id
] "m" (__rseq_abi
.cpu_id
),
444 [rseq_cs
] "m" (__rseq_abi
.rseq_cs
),
445 /* final store input */
447 [expect
] "r" (expect
),
449 /* try memcpy input */
453 [rseq_scratch0
] "m" (rseq_scratch
[0]),
454 [rseq_scratch1
] "m" (rseq_scratch
[1]),
455 [rseq_scratch2
] "m" (rseq_scratch
[2])
456 : "memory", "cc", "rax"
459 #ifdef RSEQ_COMPARE_TWICE
469 #ifdef RSEQ_COMPARE_TWICE
471 rseq_bug("cpu_id comparison failed");
473 rseq_bug("expected value comparison failed");
478 static inline __attribute__((always_inline
))
479 int rseq_cmpeqv_trymemcpy_storev_release(intptr_t *v
, intptr_t expect
,
480 void *dst
, void *src
, size_t len
,
481 intptr_t newv
, int cpu
)
483 return rseq_cmpeqv_trymemcpy_storev(v
, expect
, dst
, src
, len
,
487 #endif /* !RSEQ_SKIP_FASTPATH */
491 #define rseq_smp_mb() \
492 __asm__ __volatile__ ("lock; addl $0,-128(%%esp)" ::: "memory", "cc")
493 #define rseq_smp_rmb() \
494 __asm__ __volatile__ ("lock; addl $0,-128(%%esp)" ::: "memory", "cc")
495 #define rseq_smp_wmb() \
496 __asm__ __volatile__ ("lock; addl $0,-128(%%esp)" ::: "memory", "cc")
498 #define rseq_smp_load_acquire(p) \
500 __typeof(*p) ____p1 = RSEQ_READ_ONCE(*p); \
505 #define rseq_smp_acquire__after_ctrl_dep() rseq_smp_rmb()
507 #define rseq_smp_store_release(p, v) \
510 RSEQ_WRITE_ONCE(*p, v); \
513 #ifdef RSEQ_SKIP_FASTPATH
514 #include "rseq-skip.h"
515 #else /* !RSEQ_SKIP_FASTPATH */
518 * Use eax as scratch register and take memory operands as input to
519 * lessen register pressure. Especially needed when compiling in O0.
521 #define __RSEQ_ASM_DEFINE_TABLE(label, version, flags, \
522 start_ip, post_commit_offset, abort_ip) \
523 ".pushsection __rseq_table, \"aw\"\n\t" \
525 __rseq_str(label) ":\n\t" \
526 ".long " __rseq_str(version) ", " __rseq_str(flags) "\n\t" \
527 ".long " __rseq_str(start_ip) ", 0x0, " __rseq_str(post_commit_offset) ", 0x0, " __rseq_str(abort_ip) ", 0x0\n\t" \
530 #define RSEQ_ASM_DEFINE_TABLE(label, start_ip, post_commit_ip, abort_ip) \
531 __RSEQ_ASM_DEFINE_TABLE(label, 0x0, 0x0, start_ip, \
532 (post_commit_ip - start_ip), abort_ip)
534 #define RSEQ_ASM_STORE_RSEQ_CS(label, cs_label, rseq_cs) \
536 "movl $" __rseq_str(cs_label) ", %[rseq_cs]\n\t" \
537 __rseq_str(label) ":\n\t"
539 #define RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, label) \
541 "cmpl %[" __rseq_str(cpu_id) "], %[" __rseq_str(current_cpu_id) "]\n\t" \
542 "jnz " __rseq_str(label) "\n\t"
544 #define RSEQ_ASM_DEFINE_ABORT(label, teardown, abort_label) \
545 ".pushsection __rseq_failure, \"ax\"\n\t" \
546 /* Disassembler-friendly signature: nopl <sig>. */ \
547 ".byte 0x0f, 0x1f, 0x05\n\t" \
548 ".long " __rseq_str(RSEQ_SIG) "\n\t" \
549 __rseq_str(label) ":\n\t" \
551 "jmp %l[" __rseq_str(abort_label) "]\n\t" \
554 #define RSEQ_ASM_DEFINE_CMPFAIL(label, teardown, cmpfail_label) \
555 ".pushsection __rseq_failure, \"ax\"\n\t" \
556 __rseq_str(label) ":\n\t" \
558 "jmp %l[" __rseq_str(cmpfail_label) "]\n\t" \
561 static inline __attribute__((always_inline
))
562 int rseq_cmpeqv_storev(intptr_t *v
, intptr_t expect
, intptr_t newv
, int cpu
)
566 __asm__ __volatile__
goto (
567 RSEQ_ASM_DEFINE_TABLE(3, 1f
, 2f
, 4f
) /* start, commit, abort */
568 /* Start rseq by storing table entry pointer into rseq_cs. */
569 RSEQ_ASM_STORE_RSEQ_CS(1, 3b
, rseq_cs
)
570 RSEQ_ASM_CMP_CPU_ID(cpu_id
, current_cpu_id
, 4f
)
572 "cmpl %[v], %[expect]\n\t"
573 "jnz %l[cmpfail]\n\t"
575 #ifdef RSEQ_COMPARE_TWICE
576 RSEQ_ASM_CMP_CPU_ID(cpu_id
, current_cpu_id
, %l
[error1
])
577 "cmpl %[v], %[expect]\n\t"
581 "movl %[newv], %[v]\n\t"
584 RSEQ_ASM_DEFINE_ABORT(4, "", abort
)
585 : /* gcc asm goto does not allow outputs */
586 : [cpu_id
] "r" (cpu
),
587 [current_cpu_id
] "m" (__rseq_abi
.cpu_id
),
588 [rseq_cs
] "m" (__rseq_abi
.rseq_cs
),
590 [expect
] "r" (expect
),
592 : "memory", "cc", "eax"
595 #ifdef RSEQ_COMPARE_TWICE
605 #ifdef RSEQ_COMPARE_TWICE
607 rseq_bug("cpu_id comparison failed");
609 rseq_bug("expected value comparison failed");
614 * Compare @v against @expectnot. When it does _not_ match, load @v
615 * into @load, and store the content of *@v + voffp into @v.
617 static inline __attribute__((always_inline
))
618 int rseq_cmpnev_storeoffp_load(intptr_t *v
, intptr_t expectnot
,
619 off_t voffp
, intptr_t *load
, int cpu
)
623 __asm__ __volatile__
goto (
624 RSEQ_ASM_DEFINE_TABLE(3, 1f
, 2f
, 4f
) /* start, commit, abort */
625 /* Start rseq by storing table entry pointer into rseq_cs. */
626 RSEQ_ASM_STORE_RSEQ_CS(1, 3b
, rseq_cs
)
627 RSEQ_ASM_CMP_CPU_ID(cpu_id
, current_cpu_id
, 4f
)
629 "movl %[v], %%ebx\n\t"
630 "cmpl %%ebx, %[expectnot]\n\t"
633 #ifdef RSEQ_COMPARE_TWICE
634 RSEQ_ASM_CMP_CPU_ID(cpu_id
, current_cpu_id
, %l
[error1
])
635 "movl %[v], %%ebx\n\t"
636 "cmpl %%ebx, %[expectnot]\n\t"
639 "movl %%ebx, %[load]\n\t"
640 "addl %[voffp], %%ebx\n\t"
641 "movl (%%ebx), %%ebx\n\t"
643 "movl %%ebx, %[v]\n\t"
646 RSEQ_ASM_DEFINE_ABORT(4, "", abort
)
647 : /* gcc asm goto does not allow outputs */
648 : [cpu_id
] "r" (cpu
),
649 [current_cpu_id
] "m" (__rseq_abi
.cpu_id
),
650 [rseq_cs
] "m" (__rseq_abi
.rseq_cs
),
651 /* final store input */
653 [expectnot
] "r" (expectnot
),
654 [voffp
] "ir" (voffp
),
656 : "memory", "cc", "eax", "ebx"
659 #ifdef RSEQ_COMPARE_TWICE
669 #ifdef RSEQ_COMPARE_TWICE
671 rseq_bug("cpu_id comparison failed");
673 rseq_bug("expected value comparison failed");
677 static inline __attribute__((always_inline
))
678 int rseq_addv(intptr_t *v
, intptr_t count
, int cpu
)
682 __asm__ __volatile__
goto (
683 RSEQ_ASM_DEFINE_TABLE(3, 1f
, 2f
, 4f
) /* start, commit, abort */
684 /* Start rseq by storing table entry pointer into rseq_cs. */
685 RSEQ_ASM_STORE_RSEQ_CS(1, 3b
, rseq_cs
)
686 RSEQ_ASM_CMP_CPU_ID(cpu_id
, current_cpu_id
, 4f
)
688 #ifdef RSEQ_COMPARE_TWICE
689 RSEQ_ASM_CMP_CPU_ID(cpu_id
, current_cpu_id
, %l
[error1
])
692 "addl %[count], %[v]\n\t"
695 RSEQ_ASM_DEFINE_ABORT(4, "", abort
)
696 : /* gcc asm goto does not allow outputs */
697 : [cpu_id
] "r" (cpu
),
698 [current_cpu_id
] "m" (__rseq_abi
.cpu_id
),
699 [rseq_cs
] "m" (__rseq_abi
.rseq_cs
),
700 /* final store input */
703 : "memory", "cc", "eax"
706 #ifdef RSEQ_COMPARE_TWICE
714 #ifdef RSEQ_COMPARE_TWICE
716 rseq_bug("cpu_id comparison failed");
720 static inline __attribute__((always_inline
))
721 int rseq_cmpeqv_trystorev_storev(intptr_t *v
, intptr_t expect
,
722 intptr_t *v2
, intptr_t newv2
,
723 intptr_t newv
, int cpu
)
727 __asm__ __volatile__
goto (
728 RSEQ_ASM_DEFINE_TABLE(3, 1f
, 2f
, 4f
) /* start, commit, abort */
729 /* Start rseq by storing table entry pointer into rseq_cs. */
730 RSEQ_ASM_STORE_RSEQ_CS(1, 3b
, rseq_cs
)
731 RSEQ_ASM_CMP_CPU_ID(cpu_id
, current_cpu_id
, 4f
)
733 "cmpl %[v], %[expect]\n\t"
734 "jnz %l[cmpfail]\n\t"
736 #ifdef RSEQ_COMPARE_TWICE
737 RSEQ_ASM_CMP_CPU_ID(cpu_id
, current_cpu_id
, %l
[error1
])
738 "cmpl %[v], %[expect]\n\t"
742 "movl %[newv2], %%eax\n\t"
743 "movl %%eax, %[v2]\n\t"
746 "movl %[newv], %[v]\n\t"
749 RSEQ_ASM_DEFINE_ABORT(4, "", abort
)
750 : /* gcc asm goto does not allow outputs */
751 : [cpu_id
] "r" (cpu
),
752 [current_cpu_id
] "m" (__rseq_abi
.cpu_id
),
753 [rseq_cs
] "m" (__rseq_abi
.rseq_cs
),
754 /* try store input */
757 /* final store input */
759 [expect
] "r" (expect
),
761 : "memory", "cc", "eax"
764 #ifdef RSEQ_COMPARE_TWICE
774 #ifdef RSEQ_COMPARE_TWICE
776 rseq_bug("cpu_id comparison failed");
778 rseq_bug("expected value comparison failed");
782 static inline __attribute__((always_inline
))
783 int rseq_cmpeqv_trystorev_storev_release(intptr_t *v
, intptr_t expect
,
784 intptr_t *v2
, intptr_t newv2
,
785 intptr_t newv
, int cpu
)
789 __asm__ __volatile__
goto (
790 RSEQ_ASM_DEFINE_TABLE(3, 1f
, 2f
, 4f
) /* start, commit, abort */
791 /* Start rseq by storing table entry pointer into rseq_cs. */
792 RSEQ_ASM_STORE_RSEQ_CS(1, 3b
, rseq_cs
)
793 RSEQ_ASM_CMP_CPU_ID(cpu_id
, current_cpu_id
, 4f
)
795 "movl %[expect], %%eax\n\t"
796 "cmpl %[v], %%eax\n\t"
797 "jnz %l[cmpfail]\n\t"
799 #ifdef RSEQ_COMPARE_TWICE
800 RSEQ_ASM_CMP_CPU_ID(cpu_id
, current_cpu_id
, %l
[error1
])
801 "movl %[expect], %%eax\n\t"
802 "cmpl %[v], %%eax\n\t"
806 "movl %[newv2], %[v2]\n\t"
808 "lock; addl $0,-128(%%esp)\n\t"
810 "movl %[newv], %[v]\n\t"
813 RSEQ_ASM_DEFINE_ABORT(4, "", abort
)
814 : /* gcc asm goto does not allow outputs */
815 : [cpu_id
] "r" (cpu
),
816 [current_cpu_id
] "m" (__rseq_abi
.cpu_id
),
817 [rseq_cs
] "m" (__rseq_abi
.rseq_cs
),
818 /* try store input */
821 /* final store input */
823 [expect
] "m" (expect
),
825 : "memory", "cc", "eax"
828 #ifdef RSEQ_COMPARE_TWICE
838 #ifdef RSEQ_COMPARE_TWICE
840 rseq_bug("cpu_id comparison failed");
842 rseq_bug("expected value comparison failed");
847 static inline __attribute__((always_inline
))
848 int rseq_cmpeqv_cmpeqv_storev(intptr_t *v
, intptr_t expect
,
849 intptr_t *v2
, intptr_t expect2
,
850 intptr_t newv
, int cpu
)
854 __asm__ __volatile__
goto (
855 RSEQ_ASM_DEFINE_TABLE(3, 1f
, 2f
, 4f
) /* start, commit, abort */
856 /* Start rseq by storing table entry pointer into rseq_cs. */
857 RSEQ_ASM_STORE_RSEQ_CS(1, 3b
, rseq_cs
)
858 RSEQ_ASM_CMP_CPU_ID(cpu_id
, current_cpu_id
, 4f
)
860 "cmpl %[v], %[expect]\n\t"
861 "jnz %l[cmpfail]\n\t"
863 "cmpl %[expect2], %[v2]\n\t"
864 "jnz %l[cmpfail]\n\t"
866 #ifdef RSEQ_COMPARE_TWICE
867 RSEQ_ASM_CMP_CPU_ID(cpu_id
, current_cpu_id
, %l
[error1
])
868 "cmpl %[v], %[expect]\n\t"
870 "cmpl %[expect2], %[v2]\n\t"
873 "movl %[newv], %%eax\n\t"
875 "movl %%eax, %[v]\n\t"
878 RSEQ_ASM_DEFINE_ABORT(4, "", abort
)
879 : /* gcc asm goto does not allow outputs */
880 : [cpu_id
] "r" (cpu
),
881 [current_cpu_id
] "m" (__rseq_abi
.cpu_id
),
882 [rseq_cs
] "m" (__rseq_abi
.rseq_cs
),
885 [expect2
] "r" (expect2
),
886 /* final store input */
888 [expect
] "r" (expect
),
890 : "memory", "cc", "eax"
893 #ifdef RSEQ_COMPARE_TWICE
894 , error1
, error2
, error3
903 #ifdef RSEQ_COMPARE_TWICE
905 rseq_bug("cpu_id comparison failed");
907 rseq_bug("1st expected value comparison failed");
909 rseq_bug("2nd expected value comparison failed");
913 /* TODO: implement a faster memcpy. */
914 static inline __attribute__((always_inline
))
915 int rseq_cmpeqv_trymemcpy_storev(intptr_t *v
, intptr_t expect
,
916 void *dst
, void *src
, size_t len
,
917 intptr_t newv
, int cpu
)
919 uint32_t rseq_scratch
[3];
923 __asm__ __volatile__
goto (
924 RSEQ_ASM_DEFINE_TABLE(3, 1f
, 2f
, 4f
) /* start, commit, abort */
925 "movl %[src], %[rseq_scratch0]\n\t"
926 "movl %[dst], %[rseq_scratch1]\n\t"
927 "movl %[len], %[rseq_scratch2]\n\t"
928 /* Start rseq by storing table entry pointer into rseq_cs. */
929 RSEQ_ASM_STORE_RSEQ_CS(1, 3b
, rseq_cs
)
930 RSEQ_ASM_CMP_CPU_ID(cpu_id
, current_cpu_id
, 4f
)
932 "movl %[expect], %%eax\n\t"
933 "cmpl %%eax, %[v]\n\t"
936 #ifdef RSEQ_COMPARE_TWICE
937 RSEQ_ASM_CMP_CPU_ID(cpu_id
, current_cpu_id
, 6f
)
938 "movl %[expect], %%eax\n\t"
939 "cmpl %%eax, %[v]\n\t"
943 "test %[len], %[len]\n\t" \
946 "movb (%[src]), %%al\n\t" \
947 "movb %%al, (%[dst])\n\t" \
954 "movl %[newv], %%eax\n\t"
956 "movl %%eax, %[v]\n\t"
960 "movl %[rseq_scratch2], %[len]\n\t"
961 "movl %[rseq_scratch1], %[dst]\n\t"
962 "movl %[rseq_scratch0], %[src]\n\t"
963 RSEQ_ASM_DEFINE_ABORT(4,
964 "movl %[rseq_scratch2], %[len]\n\t"
965 "movl %[rseq_scratch1], %[dst]\n\t"
966 "movl %[rseq_scratch0], %[src]\n\t",
968 RSEQ_ASM_DEFINE_CMPFAIL(5,
969 "movl %[rseq_scratch2], %[len]\n\t"
970 "movl %[rseq_scratch1], %[dst]\n\t"
971 "movl %[rseq_scratch0], %[src]\n\t",
973 #ifdef RSEQ_COMPARE_TWICE
974 RSEQ_ASM_DEFINE_CMPFAIL(6,
975 "movl %[rseq_scratch2], %[len]\n\t"
976 "movl %[rseq_scratch1], %[dst]\n\t"
977 "movl %[rseq_scratch0], %[src]\n\t",
979 RSEQ_ASM_DEFINE_CMPFAIL(7,
980 "movl %[rseq_scratch2], %[len]\n\t"
981 "movl %[rseq_scratch1], %[dst]\n\t"
982 "movl %[rseq_scratch0], %[src]\n\t",
985 : /* gcc asm goto does not allow outputs */
986 : [cpu_id
] "r" (cpu
),
987 [current_cpu_id
] "m" (__rseq_abi
.cpu_id
),
988 [rseq_cs
] "m" (__rseq_abi
.rseq_cs
),
989 /* final store input */
991 [expect
] "m" (expect
),
993 /* try memcpy input */
997 [rseq_scratch0
] "m" (rseq_scratch
[0]),
998 [rseq_scratch1
] "m" (rseq_scratch
[1]),
999 [rseq_scratch2
] "m" (rseq_scratch
[2])
1000 : "memory", "cc", "eax"
1003 #ifdef RSEQ_COMPARE_TWICE
1013 #ifdef RSEQ_COMPARE_TWICE
1015 rseq_bug("cpu_id comparison failed");
1017 rseq_bug("expected value comparison failed");
1021 /* TODO: implement a faster memcpy. */
1022 static inline __attribute__((always_inline
))
1023 int rseq_cmpeqv_trymemcpy_storev_release(intptr_t *v
, intptr_t expect
,
1024 void *dst
, void *src
, size_t len
,
1025 intptr_t newv
, int cpu
)
1027 uint32_t rseq_scratch
[3];
1031 __asm__ __volatile__
goto (
1032 RSEQ_ASM_DEFINE_TABLE(3, 1f
, 2f
, 4f
) /* start, commit, abort */
1033 "movl %[src], %[rseq_scratch0]\n\t"
1034 "movl %[dst], %[rseq_scratch1]\n\t"
1035 "movl %[len], %[rseq_scratch2]\n\t"
1036 /* Start rseq by storing table entry pointer into rseq_cs. */
1037 RSEQ_ASM_STORE_RSEQ_CS(1, 3b
, rseq_cs
)
1038 RSEQ_ASM_CMP_CPU_ID(cpu_id
, current_cpu_id
, 4f
)
1040 "movl %[expect], %%eax\n\t"
1041 "cmpl %%eax, %[v]\n\t"
1044 #ifdef RSEQ_COMPARE_TWICE
1045 RSEQ_ASM_CMP_CPU_ID(cpu_id
, current_cpu_id
, 6f
)
1046 "movl %[expect], %%eax\n\t"
1047 "cmpl %%eax, %[v]\n\t"
1051 "test %[len], %[len]\n\t" \
1054 "movb (%[src]), %%al\n\t" \
1055 "movb %%al, (%[dst])\n\t" \
1062 "lock; addl $0,-128(%%esp)\n\t"
1063 "movl %[newv], %%eax\n\t"
1065 "movl %%eax, %[v]\n\t"
1069 "movl %[rseq_scratch2], %[len]\n\t"
1070 "movl %[rseq_scratch1], %[dst]\n\t"
1071 "movl %[rseq_scratch0], %[src]\n\t"
1072 RSEQ_ASM_DEFINE_ABORT(4,
1073 "movl %[rseq_scratch2], %[len]\n\t"
1074 "movl %[rseq_scratch1], %[dst]\n\t"
1075 "movl %[rseq_scratch0], %[src]\n\t",
1077 RSEQ_ASM_DEFINE_CMPFAIL(5,
1078 "movl %[rseq_scratch2], %[len]\n\t"
1079 "movl %[rseq_scratch1], %[dst]\n\t"
1080 "movl %[rseq_scratch0], %[src]\n\t",
1082 #ifdef RSEQ_COMPARE_TWICE
1083 RSEQ_ASM_DEFINE_CMPFAIL(6,
1084 "movl %[rseq_scratch2], %[len]\n\t"
1085 "movl %[rseq_scratch1], %[dst]\n\t"
1086 "movl %[rseq_scratch0], %[src]\n\t",
1088 RSEQ_ASM_DEFINE_CMPFAIL(7,
1089 "movl %[rseq_scratch2], %[len]\n\t"
1090 "movl %[rseq_scratch1], %[dst]\n\t"
1091 "movl %[rseq_scratch0], %[src]\n\t",
1094 : /* gcc asm goto does not allow outputs */
1095 : [cpu_id
] "r" (cpu
),
1096 [current_cpu_id
] "m" (__rseq_abi
.cpu_id
),
1097 [rseq_cs
] "m" (__rseq_abi
.rseq_cs
),
1098 /* final store input */
1100 [expect
] "m" (expect
),
1102 /* try memcpy input */
1106 [rseq_scratch0
] "m" (rseq_scratch
[0]),
1107 [rseq_scratch1
] "m" (rseq_scratch
[1]),
1108 [rseq_scratch2
] "m" (rseq_scratch
[2])
1109 : "memory", "cc", "eax"
1112 #ifdef RSEQ_COMPARE_TWICE
1122 #ifdef RSEQ_COMPARE_TWICE
1124 rseq_bug("cpu_id comparison failed");
1126 rseq_bug("expected value comparison failed");
1130 #endif /* !RSEQ_SKIP_FASTPATH */