1 /* SPDX-License-Identifier: MIT */
2 /* SPDX-FileCopyrightText: 2018 MIPS Tech LLC */
3 /* SPDX-FileCopyrightText: 2016-2018 Mathieu Desnoyers <mathieu.desnoyers@efficios.com> */
6 * Author: Paul Burton <paul.burton@mips.com>
10 * RSEQ_SIG uses the break instruction. The instruction pattern is:
13 * 0350000d break 0x350
16 * 00100350 break 0x350
19 * 0000d407 break 0x350
21 * For nanoMIPS32 and microMIPS, the instruction stream is encoded as 16-bit
22 * halfwords, so the signature halfwords need to be swapped accordingly for
25 #if defined(__nanomips__)
27 # define RSEQ_SIG 0x03500010
29 # define RSEQ_SIG 0x00100350
31 #elif defined(__mips_micromips)
33 # define RSEQ_SIG 0xd4070000
35 # define RSEQ_SIG 0x0000d407
37 #elif defined(__mips__)
38 # define RSEQ_SIG 0x0350000d
40 /* Unknown MIPS architecture. */
43 #define rseq_smp_mb() __asm__ __volatile__ ("sync" ::: "memory")
44 #define rseq_smp_rmb() rseq_smp_mb()
45 #define rseq_smp_wmb() rseq_smp_mb()
47 #define rseq_smp_load_acquire(p) \
49 rseq_unqual_scalar_typeof(*(p)) ____p1 = RSEQ_READ_ONCE(*(p)); \
54 #define rseq_smp_acquire__after_ctrl_dep() rseq_smp_rmb()
56 #define rseq_smp_store_release(p, v) \
59 RSEQ_WRITE_ONCE(*(p), v); \
62 #ifdef RSEQ_SKIP_FASTPATH
63 #include "rseq-skip.h"
64 #else /* !RSEQ_SKIP_FASTPATH */
66 #if _MIPS_SZLONG == 64
67 # define LONG ".dword"
68 # define LONG_LA "dla"
71 # define LONG_ADDI "daddiu"
72 # define U32_U64_PAD(x) x
73 #elif _MIPS_SZLONG == 32
78 # define LONG_ADDI "addiu"
80 # define U32_U64_PAD(x) "0x0, " x
82 # define U32_U64_PAD(x) x ", 0x0"
85 # error unsupported _MIPS_SZLONG
88 #define __RSEQ_ASM_DEFINE_TABLE(label, version, flags, start_ip, \
89 post_commit_offset, abort_ip) \
90 ".pushsection __rseq_cs, \"aw\"\n\t" \
92 __rseq_str(label) ":\n\t" \
93 ".word " __rseq_str(version) ", " __rseq_str(flags) "\n\t" \
94 LONG " " U32_U64_PAD(__rseq_str(start_ip)) "\n\t" \
95 LONG " " U32_U64_PAD(__rseq_str(post_commit_offset)) "\n\t" \
96 LONG " " U32_U64_PAD(__rseq_str(abort_ip)) "\n\t" \
98 ".pushsection __rseq_cs_ptr_array, \"aw\"\n\t" \
99 LONG " " U32_U64_PAD(__rseq_str(label) "b") "\n\t" \
102 #define RSEQ_ASM_DEFINE_TABLE(label, start_ip, post_commit_ip, abort_ip) \
103 __RSEQ_ASM_DEFINE_TABLE(label, 0x0, 0x0, start_ip, \
104 (post_commit_ip - start_ip), abort_ip)
107 * Exit points of a rseq critical section consist of all instructions outside
108 * of the critical section where a critical section can either branch to or
109 * reach through the normal course of its execution. The abort IP and the
110 * post-commit IP are already part of the __rseq_cs section and should not be
111 * explicitly defined as additional exit points. Knowing all exit points is
112 * useful to assist debuggers stepping over the critical section.
114 #define RSEQ_ASM_DEFINE_EXIT_POINT(start_ip, exit_ip) \
115 ".pushsection __rseq_exit_point_array, \"aw\"\n\t" \
116 LONG " " U32_U64_PAD(__rseq_str(start_ip)) "\n\t" \
117 LONG " " U32_U64_PAD(__rseq_str(exit_ip)) "\n\t" \
120 #define RSEQ_ASM_STORE_RSEQ_CS(label, cs_label, rseq_cs) \
122 LONG_LA " $4, " __rseq_str(cs_label) "\n\t" \
123 LONG_S " $4, %[" __rseq_str(rseq_cs) "]\n\t" \
124 __rseq_str(label) ":\n\t"
126 #define RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, label) \
128 "lw $4, %[" __rseq_str(current_cpu_id) "]\n\t" \
129 "bne $4, %[" __rseq_str(cpu_id) "], " __rseq_str(label) "\n\t"
131 #define __RSEQ_ASM_DEFINE_ABORT(table_label, label, teardown, \
132 abort_label, version, flags, \
133 start_ip, post_commit_offset, abort_ip) \
135 __rseq_str(table_label) ":\n\t" \
136 ".word " __rseq_str(version) ", " __rseq_str(flags) "\n\t" \
137 LONG " " U32_U64_PAD(__rseq_str(start_ip)) "\n\t" \
138 LONG " " U32_U64_PAD(__rseq_str(post_commit_offset)) "\n\t" \
139 LONG " " U32_U64_PAD(__rseq_str(abort_ip)) "\n\t" \
140 ".word " __rseq_str(RSEQ_SIG) "\n\t" \
141 __rseq_str(label) ":\n\t" \
143 "b %l[" __rseq_str(abort_label) "]\n\t"
145 #define RSEQ_ASM_DEFINE_ABORT(table_label, label, teardown, abort_label, \
146 start_ip, post_commit_ip, abort_ip) \
147 __RSEQ_ASM_DEFINE_ABORT(table_label, label, teardown, \
148 abort_label, 0x0, 0x0, start_ip, \
149 (post_commit_ip - start_ip), abort_ip)
151 #define RSEQ_ASM_DEFINE_CMPFAIL(label, teardown, cmpfail_label) \
152 __rseq_str(label) ":\n\t" \
154 "b %l[" __rseq_str(cmpfail_label) "]\n\t"
156 static inline __attribute__((always_inline
))
157 int rseq_cmpeqv_storev(intptr_t *v
, intptr_t expect
, intptr_t newv
, int cpu
)
161 __asm__ __volatile__
goto (
162 RSEQ_ASM_DEFINE_TABLE(9, 1f
, 2f
, 4f
) /* start, commit, abort */
163 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[cmpfail
])
164 #ifdef RSEQ_COMPARE_TWICE
165 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error1
])
166 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error2
])
168 /* Start rseq by storing table entry pointer into rseq_cs. */
169 RSEQ_ASM_STORE_RSEQ_CS(1, 3f
, rseq_cs
)
170 RSEQ_ASM_CMP_CPU_ID(cpu_id
, current_cpu_id
, 4f
)
172 LONG_L
" $4, %[v]\n\t"
173 "bne $4, %[expect], %l[cmpfail]\n\t"
175 #ifdef RSEQ_COMPARE_TWICE
176 RSEQ_ASM_CMP_CPU_ID(cpu_id
, current_cpu_id
, %l
[error1
])
177 LONG_L
" $4, %[v]\n\t"
178 "bne $4, %[expect], %l[error2]\n\t"
181 LONG_S
" %[newv], %[v]\n\t"
185 RSEQ_ASM_DEFINE_ABORT(3, 4, "", abort
, 1b
, 2b
, 4f
)
187 : /* gcc asm goto does not allow outputs */
188 : [cpu_id
] "r" (cpu
),
189 [current_cpu_id
] "m" (rseq_get_abi()->cpu_id
),
190 [rseq_cs
] "m" (rseq_get_abi()->rseq_cs
.arch
.ptr
),
192 [expect
] "r" (expect
),
198 #ifdef RSEQ_COMPARE_TWICE
208 #ifdef RSEQ_COMPARE_TWICE
210 rseq_bug("cpu_id comparison failed");
212 rseq_bug("expected value comparison failed");
216 static inline __attribute__((always_inline
))
217 int rseq_cmpnev_storeoffp_load(intptr_t *v
, intptr_t expectnot
,
218 long voffp
, intptr_t *load
, int cpu
)
222 __asm__ __volatile__
goto (
223 RSEQ_ASM_DEFINE_TABLE(9, 1f
, 2f
, 4f
) /* start, commit, abort */
224 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[cmpfail
])
225 #ifdef RSEQ_COMPARE_TWICE
226 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error1
])
227 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error2
])
229 /* Start rseq by storing table entry pointer into rseq_cs. */
230 RSEQ_ASM_STORE_RSEQ_CS(1, 3f
, rseq_cs
)
231 RSEQ_ASM_CMP_CPU_ID(cpu_id
, current_cpu_id
, 4f
)
233 LONG_L
" $4, %[v]\n\t"
234 "beq $4, %[expectnot], %l[cmpfail]\n\t"
236 #ifdef RSEQ_COMPARE_TWICE
237 RSEQ_ASM_CMP_CPU_ID(cpu_id
, current_cpu_id
, %l
[error1
])
238 LONG_L
" $4, %[v]\n\t"
239 "beq $4, %[expectnot], %l[error2]\n\t"
241 LONG_S
" $4, %[load]\n\t"
242 LONG_ADDI
" $4, %[voffp]\n\t"
243 LONG_L
" $4, 0($4)\n\t"
245 LONG_S
" $4, %[v]\n\t"
249 RSEQ_ASM_DEFINE_ABORT(3, 4, "", abort
, 1b
, 2b
, 4f
)
251 : /* gcc asm goto does not allow outputs */
252 : [cpu_id
] "r" (cpu
),
253 [current_cpu_id
] "m" (rseq_get_abi()->cpu_id
),
254 [rseq_cs
] "m" (rseq_get_abi()->rseq_cs
.arch
.ptr
),
255 /* final store input */
257 [expectnot
] "r" (expectnot
),
258 [voffp
] "Ir" (voffp
),
264 #ifdef RSEQ_COMPARE_TWICE
274 #ifdef RSEQ_COMPARE_TWICE
276 rseq_bug("cpu_id comparison failed");
278 rseq_bug("expected value comparison failed");
282 static inline __attribute__((always_inline
))
283 int rseq_addv(intptr_t *v
, intptr_t count
, int cpu
)
287 __asm__ __volatile__
goto (
288 RSEQ_ASM_DEFINE_TABLE(9, 1f
, 2f
, 4f
) /* start, commit, abort */
289 #ifdef RSEQ_COMPARE_TWICE
290 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error1
])
292 /* Start rseq by storing table entry pointer into rseq_cs. */
293 RSEQ_ASM_STORE_RSEQ_CS(1, 3f
, rseq_cs
)
294 RSEQ_ASM_CMP_CPU_ID(cpu_id
, current_cpu_id
, 4f
)
296 #ifdef RSEQ_COMPARE_TWICE
297 RSEQ_ASM_CMP_CPU_ID(cpu_id
, current_cpu_id
, %l
[error1
])
299 LONG_L
" $4, %[v]\n\t"
300 LONG_ADDI
" $4, %[count]\n\t"
302 LONG_S
" $4, %[v]\n\t"
306 RSEQ_ASM_DEFINE_ABORT(3, 4, "", abort
, 1b
, 2b
, 4f
)
308 : /* gcc asm goto does not allow outputs */
309 : [cpu_id
] "r" (cpu
),
310 [current_cpu_id
] "m" (rseq_get_abi()->cpu_id
),
311 [rseq_cs
] "m" (rseq_get_abi()->rseq_cs
.arch
.ptr
),
318 #ifdef RSEQ_COMPARE_TWICE
326 #ifdef RSEQ_COMPARE_TWICE
328 rseq_bug("cpu_id comparison failed");
332 static inline __attribute__((always_inline
))
333 int rseq_cmpeqv_trystorev_storev(intptr_t *v
, intptr_t expect
,
334 intptr_t *v2
, intptr_t newv2
,
335 intptr_t newv
, int cpu
)
339 __asm__ __volatile__
goto (
340 RSEQ_ASM_DEFINE_TABLE(9, 1f
, 2f
, 4f
) /* start, commit, abort */
341 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[cmpfail
])
342 #ifdef RSEQ_COMPARE_TWICE
343 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error1
])
344 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error2
])
346 /* Start rseq by storing table entry pointer into rseq_cs. */
347 RSEQ_ASM_STORE_RSEQ_CS(1, 3f
, rseq_cs
)
348 RSEQ_ASM_CMP_CPU_ID(cpu_id
, current_cpu_id
, 4f
)
350 LONG_L
" $4, %[v]\n\t"
351 "bne $4, %[expect], %l[cmpfail]\n\t"
353 #ifdef RSEQ_COMPARE_TWICE
354 RSEQ_ASM_CMP_CPU_ID(cpu_id
, current_cpu_id
, %l
[error1
])
355 LONG_L
" $4, %[v]\n\t"
356 "bne $4, %[expect], %l[error2]\n\t"
359 LONG_S
" %[newv2], %[v2]\n\t"
362 LONG_S
" %[newv], %[v]\n\t"
366 RSEQ_ASM_DEFINE_ABORT(3, 4, "", abort
, 1b
, 2b
, 4f
)
368 : /* gcc asm goto does not allow outputs */
369 : [cpu_id
] "r" (cpu
),
370 [current_cpu_id
] "m" (rseq_get_abi()->cpu_id
),
371 [rseq_cs
] "m" (rseq_get_abi()->rseq_cs
.arch
.ptr
),
372 /* try store input */
375 /* final store input */
377 [expect
] "r" (expect
),
383 #ifdef RSEQ_COMPARE_TWICE
393 #ifdef RSEQ_COMPARE_TWICE
395 rseq_bug("cpu_id comparison failed");
397 rseq_bug("expected value comparison failed");
401 static inline __attribute__((always_inline
))
402 int rseq_cmpeqv_trystorev_storev_release(intptr_t *v
, intptr_t expect
,
403 intptr_t *v2
, intptr_t newv2
,
404 intptr_t newv
, int cpu
)
408 __asm__ __volatile__
goto (
409 RSEQ_ASM_DEFINE_TABLE(9, 1f
, 2f
, 4f
) /* start, commit, abort */
410 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[cmpfail
])
411 #ifdef RSEQ_COMPARE_TWICE
412 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error1
])
413 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error2
])
415 /* Start rseq by storing table entry pointer into rseq_cs. */
416 RSEQ_ASM_STORE_RSEQ_CS(1, 3f
, rseq_cs
)
417 RSEQ_ASM_CMP_CPU_ID(cpu_id
, current_cpu_id
, 4f
)
419 LONG_L
" $4, %[v]\n\t"
420 "bne $4, %[expect], %l[cmpfail]\n\t"
422 #ifdef RSEQ_COMPARE_TWICE
423 RSEQ_ASM_CMP_CPU_ID(cpu_id
, current_cpu_id
, %l
[error1
])
424 LONG_L
" $4, %[v]\n\t"
425 "bne $4, %[expect], %l[error2]\n\t"
428 LONG_S
" %[newv2], %[v2]\n\t"
430 "sync\n\t" /* full sync provides store-release */
432 LONG_S
" %[newv], %[v]\n\t"
436 RSEQ_ASM_DEFINE_ABORT(3, 4, "", abort
, 1b
, 2b
, 4f
)
438 : /* gcc asm goto does not allow outputs */
439 : [cpu_id
] "r" (cpu
),
440 [current_cpu_id
] "m" (rseq_get_abi()->cpu_id
),
441 [rseq_cs
] "m" (rseq_get_abi()->rseq_cs
.arch
.ptr
),
442 /* try store input */
445 /* final store input */
447 [expect
] "r" (expect
),
453 #ifdef RSEQ_COMPARE_TWICE
463 #ifdef RSEQ_COMPARE_TWICE
465 rseq_bug("cpu_id comparison failed");
467 rseq_bug("expected value comparison failed");
471 static inline __attribute__((always_inline
))
472 int rseq_cmpeqv_cmpeqv_storev(intptr_t *v
, intptr_t expect
,
473 intptr_t *v2
, intptr_t expect2
,
474 intptr_t newv
, int cpu
)
478 __asm__ __volatile__
goto (
479 RSEQ_ASM_DEFINE_TABLE(9, 1f
, 2f
, 4f
) /* start, commit, abort */
480 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[cmpfail
])
481 #ifdef RSEQ_COMPARE_TWICE
482 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error1
])
483 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error2
])
484 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error3
])
486 /* Start rseq by storing table entry pointer into rseq_cs. */
487 RSEQ_ASM_STORE_RSEQ_CS(1, 3f
, rseq_cs
)
488 RSEQ_ASM_CMP_CPU_ID(cpu_id
, current_cpu_id
, 4f
)
490 LONG_L
" $4, %[v]\n\t"
491 "bne $4, %[expect], %l[cmpfail]\n\t"
493 LONG_L
" $4, %[v2]\n\t"
494 "bne $4, %[expect2], %l[cmpfail]\n\t"
496 #ifdef RSEQ_COMPARE_TWICE
497 RSEQ_ASM_CMP_CPU_ID(cpu_id
, current_cpu_id
, %l
[error1
])
498 LONG_L
" $4, %[v]\n\t"
499 "bne $4, %[expect], %l[error2]\n\t"
500 LONG_L
" $4, %[v2]\n\t"
501 "bne $4, %[expect2], %l[error3]\n\t"
504 LONG_S
" %[newv], %[v]\n\t"
508 RSEQ_ASM_DEFINE_ABORT(3, 4, "", abort
, 1b
, 2b
, 4f
)
510 : /* gcc asm goto does not allow outputs */
511 : [cpu_id
] "r" (cpu
),
512 [current_cpu_id
] "m" (rseq_get_abi()->cpu_id
),
513 [rseq_cs
] "m" (rseq_get_abi()->rseq_cs
.arch
.ptr
),
516 [expect2
] "r" (expect2
),
517 /* final store input */
519 [expect
] "r" (expect
),
525 #ifdef RSEQ_COMPARE_TWICE
526 , error1
, error2
, error3
535 #ifdef RSEQ_COMPARE_TWICE
537 rseq_bug("cpu_id comparison failed");
539 rseq_bug("1st expected value comparison failed");
541 rseq_bug("2nd expected value comparison failed");
545 static inline __attribute__((always_inline
))
546 int rseq_cmpeqv_trymemcpy_storev(intptr_t *v
, intptr_t expect
,
547 void *dst
, void *src
, size_t len
,
548 intptr_t newv
, int cpu
)
550 uintptr_t rseq_scratch
[3];
554 __asm__ __volatile__
goto (
555 RSEQ_ASM_DEFINE_TABLE(9, 1f
, 2f
, 4f
) /* start, commit, abort */
556 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[cmpfail
])
557 #ifdef RSEQ_COMPARE_TWICE
558 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error1
])
559 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error2
])
561 LONG_S
" %[src], %[rseq_scratch0]\n\t"
562 LONG_S
" %[dst], %[rseq_scratch1]\n\t"
563 LONG_S
" %[len], %[rseq_scratch2]\n\t"
564 /* Start rseq by storing table entry pointer into rseq_cs. */
565 RSEQ_ASM_STORE_RSEQ_CS(1, 3f
, rseq_cs
)
566 RSEQ_ASM_CMP_CPU_ID(cpu_id
, current_cpu_id
, 4f
)
568 LONG_L
" $4, %[v]\n\t"
569 "bne $4, %[expect], 5f\n\t"
571 #ifdef RSEQ_COMPARE_TWICE
572 RSEQ_ASM_CMP_CPU_ID(cpu_id
, current_cpu_id
, 6f
)
573 LONG_L
" $4, %[v]\n\t"
574 "bne $4, %[expect], 7f\n\t"
577 "beqz %[len], 333f\n\t" \
579 "lb $4, 0(%[src])\n\t" \
580 "sb $4, 0(%[dst])\n\t" \
581 LONG_ADDI
" %[src], 1\n\t" \
582 LONG_ADDI
" %[dst], 1\n\t" \
583 LONG_ADDI
" %[len], -1\n\t" \
584 "bnez %[len], 222b\n\t" \
588 LONG_S
" %[newv], %[v]\n\t"
592 LONG_L
" %[len], %[rseq_scratch2]\n\t"
593 LONG_L
" %[dst], %[rseq_scratch1]\n\t"
594 LONG_L
" %[src], %[rseq_scratch0]\n\t"
596 RSEQ_ASM_DEFINE_ABORT(3, 4,
598 LONG_L
" %[len], %[rseq_scratch2]\n\t"
599 LONG_L
" %[dst], %[rseq_scratch1]\n\t"
600 LONG_L
" %[src], %[rseq_scratch0]\n\t",
602 RSEQ_ASM_DEFINE_CMPFAIL(5,
604 LONG_L
" %[len], %[rseq_scratch2]\n\t"
605 LONG_L
" %[dst], %[rseq_scratch1]\n\t"
606 LONG_L
" %[src], %[rseq_scratch0]\n\t",
608 #ifdef RSEQ_COMPARE_TWICE
609 RSEQ_ASM_DEFINE_CMPFAIL(6,
611 LONG_L
" %[len], %[rseq_scratch2]\n\t"
612 LONG_L
" %[dst], %[rseq_scratch1]\n\t"
613 LONG_L
" %[src], %[rseq_scratch0]\n\t",
615 RSEQ_ASM_DEFINE_CMPFAIL(7,
617 LONG_L
" %[len], %[rseq_scratch2]\n\t"
618 LONG_L
" %[dst], %[rseq_scratch1]\n\t"
619 LONG_L
" %[src], %[rseq_scratch0]\n\t",
623 : /* gcc asm goto does not allow outputs */
624 : [cpu_id
] "r" (cpu
),
625 [current_cpu_id
] "m" (rseq_get_abi()->cpu_id
),
626 [rseq_cs
] "m" (rseq_get_abi()->rseq_cs
.arch
.ptr
),
627 /* final store input */
629 [expect
] "r" (expect
),
631 /* try memcpy input */
635 [rseq_scratch0
] "m" (rseq_scratch
[0]),
636 [rseq_scratch1
] "m" (rseq_scratch
[1]),
637 [rseq_scratch2
] "m" (rseq_scratch
[2])
642 #ifdef RSEQ_COMPARE_TWICE
652 #ifdef RSEQ_COMPARE_TWICE
654 rseq_bug("cpu_id comparison failed");
656 rseq_bug("expected value comparison failed");
660 static inline __attribute__((always_inline
))
661 int rseq_cmpeqv_trymemcpy_storev_release(intptr_t *v
, intptr_t expect
,
662 void *dst
, void *src
, size_t len
,
663 intptr_t newv
, int cpu
)
665 uintptr_t rseq_scratch
[3];
669 __asm__ __volatile__
goto (
670 RSEQ_ASM_DEFINE_TABLE(9, 1f
, 2f
, 4f
) /* start, commit, abort */
671 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[cmpfail
])
672 #ifdef RSEQ_COMPARE_TWICE
673 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error1
])
674 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error2
])
676 LONG_S
" %[src], %[rseq_scratch0]\n\t"
677 LONG_S
" %[dst], %[rseq_scratch1]\n\t"
678 LONG_S
" %[len], %[rseq_scratch2]\n\t"
679 /* Start rseq by storing table entry pointer into rseq_cs. */
680 RSEQ_ASM_STORE_RSEQ_CS(1, 3f
, rseq_cs
)
681 RSEQ_ASM_CMP_CPU_ID(cpu_id
, current_cpu_id
, 4f
)
683 LONG_L
" $4, %[v]\n\t"
684 "bne $4, %[expect], 5f\n\t"
686 #ifdef RSEQ_COMPARE_TWICE
687 RSEQ_ASM_CMP_CPU_ID(cpu_id
, current_cpu_id
, 6f
)
688 LONG_L
" $4, %[v]\n\t"
689 "bne $4, %[expect], 7f\n\t"
692 "beqz %[len], 333f\n\t" \
694 "lb $4, 0(%[src])\n\t" \
695 "sb $4, 0(%[dst])\n\t" \
696 LONG_ADDI
" %[src], 1\n\t" \
697 LONG_ADDI
" %[dst], 1\n\t" \
698 LONG_ADDI
" %[len], -1\n\t" \
699 "bnez %[len], 222b\n\t" \
702 "sync\n\t" /* full sync provides store-release */
704 LONG_S
" %[newv], %[v]\n\t"
708 LONG_L
" %[len], %[rseq_scratch2]\n\t"
709 LONG_L
" %[dst], %[rseq_scratch1]\n\t"
710 LONG_L
" %[src], %[rseq_scratch0]\n\t"
712 RSEQ_ASM_DEFINE_ABORT(3, 4,
714 LONG_L
" %[len], %[rseq_scratch2]\n\t"
715 LONG_L
" %[dst], %[rseq_scratch1]\n\t"
716 LONG_L
" %[src], %[rseq_scratch0]\n\t",
718 RSEQ_ASM_DEFINE_CMPFAIL(5,
720 LONG_L
" %[len], %[rseq_scratch2]\n\t"
721 LONG_L
" %[dst], %[rseq_scratch1]\n\t"
722 LONG_L
" %[src], %[rseq_scratch0]\n\t",
724 #ifdef RSEQ_COMPARE_TWICE
725 RSEQ_ASM_DEFINE_CMPFAIL(6,
727 LONG_L
" %[len], %[rseq_scratch2]\n\t"
728 LONG_L
" %[dst], %[rseq_scratch1]\n\t"
729 LONG_L
" %[src], %[rseq_scratch0]\n\t",
731 RSEQ_ASM_DEFINE_CMPFAIL(7,
733 LONG_L
" %[len], %[rseq_scratch2]\n\t"
734 LONG_L
" %[dst], %[rseq_scratch1]\n\t"
735 LONG_L
" %[src], %[rseq_scratch0]\n\t",
739 : /* gcc asm goto does not allow outputs */
740 : [cpu_id
] "r" (cpu
),
741 [current_cpu_id
] "m" (rseq_get_abi()->cpu_id
),
742 [rseq_cs
] "m" (rseq_get_abi()->rseq_cs
.arch
.ptr
),
743 /* final store input */
745 [expect
] "r" (expect
),
747 /* try memcpy input */
751 [rseq_scratch0
] "m" (rseq_scratch
[0]),
752 [rseq_scratch1
] "m" (rseq_scratch
[1]),
753 [rseq_scratch2
] "m" (rseq_scratch
[2])
758 #ifdef RSEQ_COMPARE_TWICE
768 #ifdef RSEQ_COMPARE_TWICE
770 rseq_bug("cpu_id comparison failed");
772 rseq_bug("expected value comparison failed");
776 #endif /* !RSEQ_SKIP_FASTPATH */
This page took 0.061515 seconds and 4 git commands to generate.