1 /* SPDX-License-Identifier: LGPL-2.1 OR MIT */
3 * Author: Paul Burton <paul.burton@mips.com>
4 * (C) Copyright 2018 MIPS Tech LLC
5 * (C) Copyright 2016-2022 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
8 #include "rseq-bits-template.h"
10 #if defined(RSEQ_TEMPLATE_MO_RELAXED) && \
11 (defined(RSEQ_TEMPLATE_CPU_ID) || defined(RSEQ_TEMPLATE_MM_CID))
13 static inline __attribute__((always_inline
))
14 int RSEQ_TEMPLATE_IDENTIFIER(rseq_cmpeqv_storev
)(intptr_t *v
, intptr_t expect
, intptr_t newv
, int cpu
)
18 __asm__ __volatile__
goto (
19 RSEQ_ASM_DEFINE_TABLE(9, 1f
, 2f
, 4f
) /* start, commit, abort */
20 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[cmpfail
])
21 #ifdef RSEQ_COMPARE_TWICE
22 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error1
])
23 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error2
])
25 /* Start rseq by storing table entry pointer into rseq_cs. */
26 RSEQ_ASM_STORE_RSEQ_CS(1, 3f
, rseq_cs
)
27 RSEQ_ASM_CMP_CPU_ID(cpu_id
, current_cpu_id
, 4f
)
29 LONG_L
" $4, %[v]\n\t"
30 "bne $4, %[expect], %l[cmpfail]\n\t"
32 #ifdef RSEQ_COMPARE_TWICE
33 RSEQ_ASM_CMP_CPU_ID(cpu_id
, current_cpu_id
, %l
[error1
])
34 LONG_L
" $4, %[v]\n\t"
35 "bne $4, %[expect], %l[error2]\n\t"
38 LONG_S
" %[newv], %[v]\n\t"
42 RSEQ_ASM_DEFINE_ABORT(3, 4, "", abort
, 1b
, 2b
, 4f
)
44 : /* gcc asm goto does not allow outputs */
46 [current_cpu_id
] "m" (rseq_get_abi()->RSEQ_TEMPLATE_CPU_ID_FIELD
),
47 [rseq_cs
] "m" (rseq_get_abi()->rseq_cs
.arch
.ptr
),
49 [expect
] "r" (expect
),
55 #ifdef RSEQ_COMPARE_TWICE
65 #ifdef RSEQ_COMPARE_TWICE
67 rseq_bug("cpu_id comparison failed");
69 rseq_bug("expected value comparison failed");
73 static inline __attribute__((always_inline
))
74 int RSEQ_TEMPLATE_IDENTIFIER(rseq_cmpnev_storeoffp_load
)(intptr_t *v
, intptr_t expectnot
,
75 long voffp
, intptr_t *load
, int cpu
)
79 __asm__ __volatile__
goto (
80 RSEQ_ASM_DEFINE_TABLE(9, 1f
, 2f
, 4f
) /* start, commit, abort */
81 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[cmpfail
])
82 #ifdef RSEQ_COMPARE_TWICE
83 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error1
])
84 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error2
])
86 /* Start rseq by storing table entry pointer into rseq_cs. */
87 RSEQ_ASM_STORE_RSEQ_CS(1, 3f
, rseq_cs
)
88 RSEQ_ASM_CMP_CPU_ID(cpu_id
, current_cpu_id
, 4f
)
90 LONG_L
" $4, %[v]\n\t"
91 "beq $4, %[expectnot], %l[cmpfail]\n\t"
93 #ifdef RSEQ_COMPARE_TWICE
94 RSEQ_ASM_CMP_CPU_ID(cpu_id
, current_cpu_id
, %l
[error1
])
95 LONG_L
" $4, %[v]\n\t"
96 "beq $4, %[expectnot], %l[error2]\n\t"
98 LONG_S
" $4, %[load]\n\t"
99 LONG_ADDI
" $4, %[voffp]\n\t"
100 LONG_L
" $4, 0($4)\n\t"
102 LONG_S
" $4, %[v]\n\t"
106 RSEQ_ASM_DEFINE_ABORT(3, 4, "", abort
, 1b
, 2b
, 4f
)
108 : /* gcc asm goto does not allow outputs */
109 : [cpu_id
] "r" (cpu
),
110 [current_cpu_id
] "m" (rseq_get_abi()->RSEQ_TEMPLATE_CPU_ID_FIELD
),
111 [rseq_cs
] "m" (rseq_get_abi()->rseq_cs
.arch
.ptr
),
112 /* final store input */
114 [expectnot
] "r" (expectnot
),
115 [voffp
] "Ir" (voffp
),
121 #ifdef RSEQ_COMPARE_TWICE
131 #ifdef RSEQ_COMPARE_TWICE
133 rseq_bug("cpu_id comparison failed");
135 rseq_bug("expected value comparison failed");
139 static inline __attribute__((always_inline
))
140 int RSEQ_TEMPLATE_IDENTIFIER(rseq_addv
)(intptr_t *v
, intptr_t count
, int cpu
)
144 __asm__ __volatile__
goto (
145 RSEQ_ASM_DEFINE_TABLE(9, 1f
, 2f
, 4f
) /* start, commit, abort */
146 #ifdef RSEQ_COMPARE_TWICE
147 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error1
])
149 /* Start rseq by storing table entry pointer into rseq_cs. */
150 RSEQ_ASM_STORE_RSEQ_CS(1, 3f
, rseq_cs
)
151 RSEQ_ASM_CMP_CPU_ID(cpu_id
, current_cpu_id
, 4f
)
153 #ifdef RSEQ_COMPARE_TWICE
154 RSEQ_ASM_CMP_CPU_ID(cpu_id
, current_cpu_id
, %l
[error1
])
156 LONG_L
" $4, %[v]\n\t"
157 LONG_ADDI
" $4, %[count]\n\t"
159 LONG_S
" $4, %[v]\n\t"
163 RSEQ_ASM_DEFINE_ABORT(3, 4, "", abort
, 1b
, 2b
, 4f
)
165 : /* gcc asm goto does not allow outputs */
166 : [cpu_id
] "r" (cpu
),
167 [current_cpu_id
] "m" (rseq_get_abi()->RSEQ_TEMPLATE_CPU_ID_FIELD
),
168 [rseq_cs
] "m" (rseq_get_abi()->rseq_cs
.arch
.ptr
),
175 #ifdef RSEQ_COMPARE_TWICE
183 #ifdef RSEQ_COMPARE_TWICE
185 rseq_bug("cpu_id comparison failed");
189 static inline __attribute__((always_inline
))
190 int RSEQ_TEMPLATE_IDENTIFIER(rseq_cmpeqv_cmpeqv_storev
)(intptr_t *v
, intptr_t expect
,
191 intptr_t *v2
, intptr_t expect2
,
192 intptr_t newv
, int cpu
)
196 __asm__ __volatile__
goto (
197 RSEQ_ASM_DEFINE_TABLE(9, 1f
, 2f
, 4f
) /* start, commit, abort */
198 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[cmpfail
])
199 #ifdef RSEQ_COMPARE_TWICE
200 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error1
])
201 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error2
])
202 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error3
])
204 /* Start rseq by storing table entry pointer into rseq_cs. */
205 RSEQ_ASM_STORE_RSEQ_CS(1, 3f
, rseq_cs
)
206 RSEQ_ASM_CMP_CPU_ID(cpu_id
, current_cpu_id
, 4f
)
208 LONG_L
" $4, %[v]\n\t"
209 "bne $4, %[expect], %l[cmpfail]\n\t"
211 LONG_L
" $4, %[v2]\n\t"
212 "bne $4, %[expect2], %l[cmpfail]\n\t"
214 #ifdef RSEQ_COMPARE_TWICE
215 RSEQ_ASM_CMP_CPU_ID(cpu_id
, current_cpu_id
, %l
[error1
])
216 LONG_L
" $4, %[v]\n\t"
217 "bne $4, %[expect], %l[error2]\n\t"
218 LONG_L
" $4, %[v2]\n\t"
219 "bne $4, %[expect2], %l[error3]\n\t"
222 LONG_S
" %[newv], %[v]\n\t"
226 RSEQ_ASM_DEFINE_ABORT(3, 4, "", abort
, 1b
, 2b
, 4f
)
228 : /* gcc asm goto does not allow outputs */
229 : [cpu_id
] "r" (cpu
),
230 [current_cpu_id
] "m" (rseq_get_abi()->RSEQ_TEMPLATE_CPU_ID_FIELD
),
231 [rseq_cs
] "m" (rseq_get_abi()->rseq_cs
.arch
.ptr
),
234 [expect2
] "r" (expect2
),
235 /* final store input */
237 [expect
] "r" (expect
),
243 #ifdef RSEQ_COMPARE_TWICE
244 , error1
, error2
, error3
253 #ifdef RSEQ_COMPARE_TWICE
255 rseq_bug("cpu_id comparison failed");
257 rseq_bug("1st expected value comparison failed");
259 rseq_bug("2nd expected value comparison failed");
263 #endif /* #if defined(RSEQ_TEMPLATE_MO_RELAXED) &&
264 (defined(RSEQ_TEMPLATE_CPU_ID) || defined(RSEQ_TEMPLATE_MM_CID)) */
266 #if (defined(RSEQ_TEMPLATE_MO_RELAXED) || defined(RSEQ_TEMPLATE_MO_RELEASE)) && \
267 (defined(RSEQ_TEMPLATE_CPU_ID) || defined(RSEQ_TEMPLATE_MM_CID))
269 static inline __attribute__((always_inline
))
270 int RSEQ_TEMPLATE_IDENTIFIER(rseq_cmpeqv_trystorev_storev
)(intptr_t *v
, intptr_t expect
,
271 intptr_t *v2
, intptr_t newv2
,
272 intptr_t newv
, int cpu
)
276 __asm__ __volatile__
goto (
277 RSEQ_ASM_DEFINE_TABLE(9, 1f
, 2f
, 4f
) /* start, commit, abort */
278 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[cmpfail
])
279 #ifdef RSEQ_COMPARE_TWICE
280 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error1
])
281 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error2
])
283 /* Start rseq by storing table entry pointer into rseq_cs. */
284 RSEQ_ASM_STORE_RSEQ_CS(1, 3f
, rseq_cs
)
285 RSEQ_ASM_CMP_CPU_ID(cpu_id
, current_cpu_id
, 4f
)
287 LONG_L
" $4, %[v]\n\t"
288 "bne $4, %[expect], %l[cmpfail]\n\t"
290 #ifdef RSEQ_COMPARE_TWICE
291 RSEQ_ASM_CMP_CPU_ID(cpu_id
, current_cpu_id
, %l
[error1
])
292 LONG_L
" $4, %[v]\n\t"
293 "bne $4, %[expect], %l[error2]\n\t"
296 LONG_S
" %[newv2], %[v2]\n\t"
298 #ifdef RSEQ_TEMPLATE_MO_RELEASE
299 "sync\n\t" /* full sync provides store-release */
302 LONG_S
" %[newv], %[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()->RSEQ_TEMPLATE_CPU_ID_FIELD
),
311 [rseq_cs
] "m" (rseq_get_abi()->rseq_cs
.arch
.ptr
),
312 /* try store input */
315 /* final store input */
317 [expect
] "r" (expect
),
323 #ifdef RSEQ_COMPARE_TWICE
333 #ifdef RSEQ_COMPARE_TWICE
335 rseq_bug("cpu_id comparison failed");
337 rseq_bug("expected value comparison failed");
341 static inline __attribute__((always_inline
))
342 int RSEQ_TEMPLATE_IDENTIFIER(rseq_cmpeqv_trymemcpy_storev
)(intptr_t *v
, intptr_t expect
,
343 void *dst
, void *src
, size_t len
,
344 intptr_t newv
, int cpu
)
346 uintptr_t rseq_scratch
[3];
350 __asm__ __volatile__
goto (
351 RSEQ_ASM_DEFINE_TABLE(9, 1f
, 2f
, 4f
) /* start, commit, abort */
352 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[cmpfail
])
353 #ifdef RSEQ_COMPARE_TWICE
354 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error1
])
355 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error2
])
357 LONG_S
" %[src], %[rseq_scratch0]\n\t"
358 LONG_S
" %[dst], %[rseq_scratch1]\n\t"
359 LONG_S
" %[len], %[rseq_scratch2]\n\t"
360 /* Start rseq by storing table entry pointer into rseq_cs. */
361 RSEQ_ASM_STORE_RSEQ_CS(1, 3f
, rseq_cs
)
362 RSEQ_ASM_CMP_CPU_ID(cpu_id
, current_cpu_id
, 4f
)
364 LONG_L
" $4, %[v]\n\t"
365 "bne $4, %[expect], 5f\n\t"
367 #ifdef RSEQ_COMPARE_TWICE
368 RSEQ_ASM_CMP_CPU_ID(cpu_id
, current_cpu_id
, 6f
)
369 LONG_L
" $4, %[v]\n\t"
370 "bne $4, %[expect], 7f\n\t"
373 "beqz %[len], 333f\n\t" \
375 "lb $4, 0(%[src])\n\t" \
376 "sb $4, 0(%[dst])\n\t" \
377 LONG_ADDI
" %[src], 1\n\t" \
378 LONG_ADDI
" %[dst], 1\n\t" \
379 LONG_ADDI
" %[len], -1\n\t" \
380 "bnez %[len], 222b\n\t" \
383 #ifdef RSEQ_TEMPLATE_MO_RELEASE
384 "sync\n\t" /* full sync provides store-release */
387 LONG_S
" %[newv], %[v]\n\t"
391 LONG_L
" %[len], %[rseq_scratch2]\n\t"
392 LONG_L
" %[dst], %[rseq_scratch1]\n\t"
393 LONG_L
" %[src], %[rseq_scratch0]\n\t"
395 RSEQ_ASM_DEFINE_ABORT(3, 4,
397 LONG_L
" %[len], %[rseq_scratch2]\n\t"
398 LONG_L
" %[dst], %[rseq_scratch1]\n\t"
399 LONG_L
" %[src], %[rseq_scratch0]\n\t",
401 RSEQ_ASM_DEFINE_CMPFAIL(5,
403 LONG_L
" %[len], %[rseq_scratch2]\n\t"
404 LONG_L
" %[dst], %[rseq_scratch1]\n\t"
405 LONG_L
" %[src], %[rseq_scratch0]\n\t",
407 #ifdef RSEQ_COMPARE_TWICE
408 RSEQ_ASM_DEFINE_CMPFAIL(6,
410 LONG_L
" %[len], %[rseq_scratch2]\n\t"
411 LONG_L
" %[dst], %[rseq_scratch1]\n\t"
412 LONG_L
" %[src], %[rseq_scratch0]\n\t",
414 RSEQ_ASM_DEFINE_CMPFAIL(7,
416 LONG_L
" %[len], %[rseq_scratch2]\n\t"
417 LONG_L
" %[dst], %[rseq_scratch1]\n\t"
418 LONG_L
" %[src], %[rseq_scratch0]\n\t",
422 : /* gcc asm goto does not allow outputs */
423 : [cpu_id
] "r" (cpu
),
424 [current_cpu_id
] "m" (rseq_get_abi()->RSEQ_TEMPLATE_CPU_ID_FIELD
),
425 [rseq_cs
] "m" (rseq_get_abi()->rseq_cs
.arch
.ptr
),
426 /* final store input */
428 [expect
] "r" (expect
),
430 /* try memcpy input */
434 [rseq_scratch0
] "m" (rseq_scratch
[0]),
435 [rseq_scratch1
] "m" (rseq_scratch
[1]),
436 [rseq_scratch2
] "m" (rseq_scratch
[2])
441 #ifdef RSEQ_COMPARE_TWICE
451 #ifdef RSEQ_COMPARE_TWICE
453 rseq_bug("cpu_id comparison failed");
455 rseq_bug("expected value comparison failed");
459 #endif /* #if (defined(RSEQ_TEMPLATE_MO_RELAXED) || defined(RSEQ_TEMPLATE_MO_RELEASE)) &&
460 (defined(RSEQ_TEMPLATE_CPU_ID) || defined(RSEQ_TEMPLATE_MM_CID)) */
462 #include "rseq-bits-reset.h"