1 /* SPDX-License-Identifier: MIT */
2 /* SPDX-FileCopyrightText: 2018 Vasily Gorbik <gor@linux.ibm.com> */
4 #include "rseq-bits-template.h"
7 * Refer to rseq-pseudocode.h for documentation and pseudo-code of the
8 * rseq critical section helpers.
10 #include "rseq-pseudocode.h"
12 #if defined(RSEQ_TEMPLATE_MO_RELAXED) && \
13 (defined(RSEQ_TEMPLATE_CPU_ID) || defined(RSEQ_TEMPLATE_MM_CID))
15 static inline __attribute__((always_inline
))
16 int RSEQ_TEMPLATE_IDENTIFIER(rseq_cmpeqv_storev
)(intptr_t *v
, intptr_t expect
, intptr_t newv
, int cpu
)
20 __asm__ __volatile__
goto (
21 RSEQ_ASM_DEFINE_TABLE(3, 1f
, 2f
, 4f
) /* start, commit, abort */
22 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[cmpfail
])
23 #ifdef RSEQ_COMPARE_TWICE
24 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error1
])
25 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error2
])
27 /* Start rseq by storing table entry pointer into rseq_cs. */
28 RSEQ_ASM_STORE_RSEQ_CS(1, 3b
, rseq_cs
)
29 RSEQ_ASM_CBNE_CPU_ID(cpu_id
, current_cpu_id
, 4f
)
31 LONG_CMP
" %[expect], %[v]\n\t"
34 #ifdef RSEQ_COMPARE_TWICE
35 RSEQ_ASM_CBNE_CPU_ID(cpu_id
, current_cpu_id
, %l
[error1
])
36 LONG_CMP
" %[expect], %[v]\n\t"
40 LONG_S
" %[newv], %[v]\n\t"
43 RSEQ_ASM_DEFINE_ABORT(4, "", abort
)
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
),
52 : "memory", "cc", "r0"
55 #ifdef RSEQ_COMPARE_TWICE
59 rseq_after_asm_goto();
62 rseq_after_asm_goto();
66 rseq_after_asm_goto();
68 #ifdef RSEQ_COMPARE_TWICE
70 rseq_after_asm_goto();
71 rseq_bug("cpu_id comparison failed");
73 rseq_after_asm_goto();
74 rseq_bug("expected value comparison failed");
79 * Compare @v against @expectnot. When it does _not_ match, load @v
80 * into @load, and store the content of *@v + voffp into @v.
82 static inline __attribute__((always_inline
))
83 int RSEQ_TEMPLATE_IDENTIFIER(rseq_cmpnev_storeoffp_load
)(intptr_t *v
, intptr_t expectnot
,
84 long voffp
, intptr_t *load
, int cpu
)
88 __asm__ __volatile__
goto (
89 RSEQ_ASM_DEFINE_TABLE(3, 1f
, 2f
, 4f
) /* start, commit, abort */
90 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[cmpfail
])
91 #ifdef RSEQ_COMPARE_TWICE
92 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error1
])
93 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error2
])
95 /* Start rseq by storing table entry pointer into rseq_cs. */
96 RSEQ_ASM_STORE_RSEQ_CS(1, 3b
, rseq_cs
)
97 RSEQ_ASM_CBNE_CPU_ID(cpu_id
, current_cpu_id
, 4f
)
99 LONG_L
" %%r1, %[v]\n\t"
100 LONG_CMP_R
" %%r1, %[expectnot]\n\t"
103 #ifdef RSEQ_COMPARE_TWICE
104 RSEQ_ASM_CBNE_CPU_ID(cpu_id
, current_cpu_id
, %l
[error1
])
105 LONG_L
" %%r1, %[v]\n\t"
106 LONG_CMP_R
" %%r1, %[expectnot]\n\t"
109 LONG_S
" %%r1, %[load]\n\t"
110 LONG_ADD_R
" %%r1, %[voffp]\n\t"
111 LONG_L
" %%r1, 0(%%r1)\n\t"
113 LONG_S
" %%r1, %[v]\n\t"
116 RSEQ_ASM_DEFINE_ABORT(4, "", abort
)
117 : /* gcc asm goto does not allow outputs */
118 : [cpu_id
] "r" (cpu
),
119 [current_cpu_id
] "m" (rseq_get_abi()->RSEQ_TEMPLATE_CPU_ID_FIELD
),
120 [rseq_cs
] "m" (rseq_get_abi()->rseq_cs
.arch
.ptr
),
121 /* final store input */
123 [expectnot
] "r" (expectnot
),
127 : "memory", "cc", "r0", "r1"
130 #ifdef RSEQ_COMPARE_TWICE
134 rseq_after_asm_goto();
137 rseq_after_asm_goto();
141 rseq_after_asm_goto();
143 #ifdef RSEQ_COMPARE_TWICE
145 rseq_after_asm_goto();
146 rseq_bug("cpu_id comparison failed");
148 rseq_after_asm_goto();
149 rseq_bug("expected value comparison failed");
153 static inline __attribute__((always_inline
))
154 int RSEQ_TEMPLATE_IDENTIFIER(rseq_addv
)(intptr_t *v
, intptr_t count
, int cpu
)
158 __asm__ __volatile__
goto (
159 RSEQ_ASM_DEFINE_TABLE(3, 1f
, 2f
, 4f
) /* start, commit, abort */
160 #ifdef RSEQ_COMPARE_TWICE
161 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error1
])
163 /* Start rseq by storing table entry pointer into rseq_cs. */
164 RSEQ_ASM_STORE_RSEQ_CS(1, 3b
, rseq_cs
)
165 RSEQ_ASM_CBNE_CPU_ID(cpu_id
, current_cpu_id
, 4f
)
167 #ifdef RSEQ_COMPARE_TWICE
168 RSEQ_ASM_CBNE_CPU_ID(cpu_id
, current_cpu_id
, %l
[error1
])
170 LONG_L
" %%r0, %[v]\n\t"
171 LONG_ADD_R
" %%r0, %[count]\n\t"
173 LONG_S
" %%r0, %[v]\n\t"
176 RSEQ_ASM_DEFINE_ABORT(4, "", abort
)
177 : /* gcc asm goto does not allow outputs */
178 : [cpu_id
] "r" (cpu
),
179 [current_cpu_id
] "m" (rseq_get_abi()->RSEQ_TEMPLATE_CPU_ID_FIELD
),
180 [rseq_cs
] "m" (rseq_get_abi()->rseq_cs
.arch
.ptr
),
181 /* final store input */
185 : "memory", "cc", "r0"
188 #ifdef RSEQ_COMPARE_TWICE
192 rseq_after_asm_goto();
195 rseq_after_asm_goto();
198 #ifdef RSEQ_COMPARE_TWICE
200 rseq_after_asm_goto();
201 rseq_bug("cpu_id comparison failed");
205 static inline __attribute__((always_inline
))
206 int RSEQ_TEMPLATE_IDENTIFIER(rseq_cmpeqv_cmpeqv_storev
)(intptr_t *v
, intptr_t expect
,
207 intptr_t *v2
, intptr_t expect2
,
208 intptr_t newv
, int cpu
)
212 __asm__ __volatile__
goto (
213 RSEQ_ASM_DEFINE_TABLE(3, 1f
, 2f
, 4f
) /* start, commit, abort */
214 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[cmpfail
])
215 #ifdef RSEQ_COMPARE_TWICE
216 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error1
])
217 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error2
])
218 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error3
])
220 /* Start rseq by storing table entry pointer into rseq_cs. */
221 RSEQ_ASM_STORE_RSEQ_CS(1, 3b
, rseq_cs
)
222 RSEQ_ASM_CBNE_CPU_ID(cpu_id
, current_cpu_id
, 4f
)
224 LONG_CMP
" %[expect], %[v]\n\t"
225 "jnz %l[cmpfail]\n\t"
227 LONG_CMP
" %[expect2], %[v2]\n\t"
228 "jnz %l[cmpfail]\n\t"
230 #ifdef RSEQ_COMPARE_TWICE
231 RSEQ_ASM_CBNE_CPU_ID(cpu_id
, current_cpu_id
, %l
[error1
])
232 LONG_CMP
" %[expect], %[v]\n\t"
234 LONG_CMP
" %[expect2], %[v2]\n\t"
238 LONG_S
" %[newv], %[v]\n\t"
241 RSEQ_ASM_DEFINE_ABORT(4, "", abort
)
242 : /* gcc asm goto does not allow outputs */
243 : [cpu_id
] "r" (cpu
),
244 [current_cpu_id
] "m" (rseq_get_abi()->RSEQ_TEMPLATE_CPU_ID_FIELD
),
245 [rseq_cs
] "m" (rseq_get_abi()->rseq_cs
.arch
.ptr
),
248 [expect2
] "r" (expect2
),
249 /* final store input */
251 [expect
] "r" (expect
),
254 : "memory", "cc", "r0"
257 #ifdef RSEQ_COMPARE_TWICE
258 , error1
, error2
, error3
261 rseq_after_asm_goto();
264 rseq_after_asm_goto();
268 rseq_after_asm_goto();
270 #ifdef RSEQ_COMPARE_TWICE
272 rseq_after_asm_goto();
273 rseq_bug("cpu_id comparison failed");
275 rseq_after_asm_goto();
276 rseq_bug("1st expected value comparison failed");
278 rseq_after_asm_goto();
279 rseq_bug("2nd expected value comparison failed");
283 #endif /* #if defined(RSEQ_TEMPLATE_MO_RELAXED) &&
284 (defined(RSEQ_TEMPLATE_CPU_ID) || defined(RSEQ_TEMPLATE_MM_CID)) */
286 #if (defined(RSEQ_TEMPLATE_MO_RELAXED) || defined(RSEQ_TEMPLATE_MO_RELEASE)) && \
287 (defined(RSEQ_TEMPLATE_CPU_ID) || defined(RSEQ_TEMPLATE_MM_CID))
290 static inline __attribute__((always_inline
))
291 int RSEQ_TEMPLATE_IDENTIFIER(rseq_cmpeqv_trystorev_storev
)(intptr_t *v
, intptr_t expect
,
292 intptr_t *v2
, intptr_t newv2
,
293 intptr_t newv
, int cpu
)
297 __asm__ __volatile__
goto (
298 RSEQ_ASM_DEFINE_TABLE(3, 1f
, 2f
, 4f
) /* start, commit, abort */
299 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[cmpfail
])
300 #ifdef RSEQ_COMPARE_TWICE
301 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error1
])
302 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error2
])
304 /* Start rseq by storing table entry pointer into rseq_cs. */
305 RSEQ_ASM_STORE_RSEQ_CS(1, 3b
, rseq_cs
)
306 RSEQ_ASM_CBNE_CPU_ID(cpu_id
, current_cpu_id
, 4f
)
308 LONG_CMP
" %[expect], %[v]\n\t"
309 "jnz %l[cmpfail]\n\t"
311 #ifdef RSEQ_COMPARE_TWICE
312 RSEQ_ASM_CBNE_CPU_ID(cpu_id
, current_cpu_id
, %l
[error1
])
313 LONG_CMP
" %[expect], %[v]\n\t"
317 LONG_S
" %[newv2], %[v2]\n\t"
320 LONG_S
" %[newv], %[v]\n\t"
323 RSEQ_ASM_DEFINE_ABORT(4, "", abort
)
324 : /* gcc asm goto does not allow outputs */
325 : [cpu_id
] "r" (cpu
),
326 [current_cpu_id
] "m" (rseq_get_abi()->RSEQ_TEMPLATE_CPU_ID_FIELD
),
327 [rseq_cs
] "m" (rseq_get_abi()->rseq_cs
.arch
.ptr
),
328 /* try store input */
331 /* final store input */
333 [expect
] "r" (expect
),
336 : "memory", "cc", "r0"
339 #ifdef RSEQ_COMPARE_TWICE
343 rseq_after_asm_goto();
346 rseq_after_asm_goto();
350 rseq_after_asm_goto();
352 #ifdef RSEQ_COMPARE_TWICE
354 rseq_after_asm_goto();
355 rseq_bug("cpu_id comparison failed");
357 rseq_after_asm_goto();
358 rseq_bug("expected value comparison failed");
363 static inline __attribute__((always_inline
))
364 int RSEQ_TEMPLATE_IDENTIFIER(rseq_cmpeqv_trymemcpy_storev
)(intptr_t *v
, intptr_t expect
,
365 void *dst
, void *src
, size_t len
,
366 intptr_t newv
, int cpu
)
368 uint64_t rseq_scratch
[3];
372 __asm__ __volatile__
goto (
373 RSEQ_ASM_DEFINE_TABLE(3, 1f
, 2f
, 4f
) /* start, commit, abort */
374 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[cmpfail
])
375 #ifdef RSEQ_COMPARE_TWICE
376 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error1
])
377 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error2
])
379 LONG_S
" %[src], %[rseq_scratch0]\n\t"
380 LONG_S
" %[dst], %[rseq_scratch1]\n\t"
381 LONG_S
" %[len], %[rseq_scratch2]\n\t"
382 /* Start rseq by storing table entry pointer into rseq_cs. */
383 RSEQ_ASM_STORE_RSEQ_CS(1, 3b
, rseq_cs
)
384 RSEQ_ASM_CBNE_CPU_ID(cpu_id
, current_cpu_id
, 4f
)
386 LONG_CMP
" %[expect], %[v]\n\t"
389 #ifdef RSEQ_COMPARE_TWICE
390 RSEQ_ASM_CBNE_CPU_ID(cpu_id
, current_cpu_id
, 6f
)
391 LONG_CMP
" %[expect], %[v]\n\t"
395 LONG_LT_R
" %[len], %[len]\n\t"
398 "ic %%r0,0(%[src])\n\t"
399 "stc %%r0,0(%[dst])\n\t"
400 LONG_ADDI
" %[src], 1\n\t"
401 LONG_ADDI
" %[dst], 1\n\t"
402 LONG_ADDI
" %[len], -1\n\t"
407 LONG_S
" %[newv], %[v]\n\t"
411 LONG_L
" %[len], %[rseq_scratch2]\n\t"
412 LONG_L
" %[dst], %[rseq_scratch1]\n\t"
413 LONG_L
" %[src], %[rseq_scratch0]\n\t"
414 RSEQ_ASM_DEFINE_ABORT(4,
415 LONG_L
" %[len], %[rseq_scratch2]\n\t"
416 LONG_L
" %[dst], %[rseq_scratch1]\n\t"
417 LONG_L
" %[src], %[rseq_scratch0]\n\t",
419 RSEQ_ASM_DEFINE_CMPFAIL(5,
420 LONG_L
" %[len], %[rseq_scratch2]\n\t"
421 LONG_L
" %[dst], %[rseq_scratch1]\n\t"
422 LONG_L
" %[src], %[rseq_scratch0]\n\t",
424 #ifdef RSEQ_COMPARE_TWICE
425 RSEQ_ASM_DEFINE_CMPFAIL(6,
426 LONG_L
" %[len], %[rseq_scratch2]\n\t"
427 LONG_L
" %[dst], %[rseq_scratch1]\n\t"
428 LONG_L
" %[src], %[rseq_scratch0]\n\t",
430 RSEQ_ASM_DEFINE_CMPFAIL(7,
431 LONG_L
" %[len], %[rseq_scratch2]\n\t"
432 LONG_L
" %[dst], %[rseq_scratch1]\n\t"
433 LONG_L
" %[src], %[rseq_scratch0]\n\t",
436 : /* gcc asm goto does not allow outputs */
437 : [cpu_id
] "r" (cpu
),
438 [current_cpu_id
] "m" (rseq_get_abi()->RSEQ_TEMPLATE_CPU_ID_FIELD
),
439 [rseq_cs
] "m" (rseq_get_abi()->rseq_cs
.arch
.ptr
),
440 /* final store input */
442 [expect
] "r" (expect
),
444 /* try memcpy input */
448 [rseq_scratch0
] "m" (rseq_scratch
[0]),
449 [rseq_scratch1
] "m" (rseq_scratch
[1]),
450 [rseq_scratch2
] "m" (rseq_scratch
[2])
452 : "memory", "cc", "r0"
455 #ifdef RSEQ_COMPARE_TWICE
459 rseq_after_asm_goto();
462 rseq_after_asm_goto();
466 rseq_after_asm_goto();
468 #ifdef RSEQ_COMPARE_TWICE
470 rseq_after_asm_goto();
471 rseq_bug("cpu_id comparison failed");
473 rseq_after_asm_goto();
474 rseq_bug("expected value comparison failed");
478 #endif /* #if (defined(RSEQ_TEMPLATE_MO_RELAXED) || defined(RSEQ_TEMPLATE_MO_RELEASE)) &&
479 (defined(RSEQ_TEMPLATE_CPU_ID) || defined(RSEQ_TEMPLATE_MM_CID)) */
481 #include "rseq-bits-reset.h"