1 /* SPDX-License-Identifier: MIT */
2 /* SPDX-FileCopyrightText: 2016-2018 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_CBNE_CPU_ID(cpu_id
, current_cpu_id
, 4f
)
30 "cmp %[expect], r0\n\t"
33 #ifdef RSEQ_COMPARE_TWICE
34 RSEQ_ASM_CBNE_CPU_ID(cpu_id
, current_cpu_id
, %l
[error1
])
36 "cmp %[expect], r0\n\t"
40 "str %[newv], %[v]\n\t"
44 RSEQ_ASM_DEFINE_ABORT(3, 4, "", abort
, 1b
, 2b
, 4f
)
46 : /* gcc asm goto does not allow outputs */
48 [current_cpu_id
] "m" (rseq_get_abi()->RSEQ_TEMPLATE_CPU_ID_FIELD
),
49 [rseq_cs
] "m" (rseq_get_abi()->rseq_cs
.arch
.ptr
),
51 [expect
] "r" (expect
),
54 : "r0", "memory", "cc"
57 #ifdef RSEQ_COMPARE_TWICE
61 rseq_after_asm_goto();
64 rseq_after_asm_goto();
68 rseq_after_asm_goto();
70 #ifdef RSEQ_COMPARE_TWICE
72 rseq_after_asm_goto();
73 rseq_bug("cpu_id comparison failed");
75 rseq_after_asm_goto();
76 rseq_bug("expected value comparison failed");
80 static inline __attribute__((always_inline
))
81 int RSEQ_TEMPLATE_IDENTIFIER(rseq_cmpnev_storeoffp_load
)(intptr_t *v
, intptr_t expectnot
,
82 long voffp
, intptr_t *load
, int cpu
)
86 __asm__ __volatile__
goto (
87 RSEQ_ASM_DEFINE_TABLE(9, 1f
, 2f
, 4f
) /* start, commit, abort */
88 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[cmpfail
])
89 #ifdef RSEQ_COMPARE_TWICE
90 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error1
])
91 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error2
])
93 /* Start rseq by storing table entry pointer into rseq_cs. */
94 RSEQ_ASM_STORE_RSEQ_CS(1, 3f
, rseq_cs
)
95 RSEQ_ASM_CBNE_CPU_ID(cpu_id
, current_cpu_id
, 4f
)
98 "cmp %[expectnot], r0\n\t"
101 #ifdef RSEQ_COMPARE_TWICE
102 RSEQ_ASM_CBNE_CPU_ID(cpu_id
, current_cpu_id
, %l
[error1
])
104 "cmp %[expectnot], r0\n\t"
107 "str r0, %[load]\n\t"
108 "add r0, %[voffp]\n\t"
115 RSEQ_ASM_DEFINE_ABORT(3, 4, "", abort
, 1b
, 2b
, 4f
)
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
),
124 [voffp
] "Ir" (voffp
),
127 : "r0", "memory", "cc"
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(9, 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, 3f
, 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
])
171 "add r0, %[count]\n\t"
177 RSEQ_ASM_DEFINE_ABORT(3, 4, "", abort
, 1b
, 2b
, 4f
)
179 : /* gcc asm goto does not allow outputs */
180 : [cpu_id
] "r" (cpu
),
181 [current_cpu_id
] "m" (rseq_get_abi()->RSEQ_TEMPLATE_CPU_ID_FIELD
),
182 [rseq_cs
] "m" (rseq_get_abi()->rseq_cs
.arch
.ptr
),
186 : "r0", "memory", "cc"
189 #ifdef RSEQ_COMPARE_TWICE
193 rseq_after_asm_goto();
196 rseq_after_asm_goto();
199 #ifdef RSEQ_COMPARE_TWICE
201 rseq_after_asm_goto();
202 rseq_bug("cpu_id comparison failed");
206 static inline __attribute__((always_inline
))
207 int RSEQ_TEMPLATE_IDENTIFIER(rseq_cmpeqv_cmpeqv_storev
)(intptr_t *v
, intptr_t expect
,
208 intptr_t *v2
, intptr_t expect2
,
209 intptr_t newv
, int cpu
)
213 __asm__ __volatile__
goto (
214 RSEQ_ASM_DEFINE_TABLE(9, 1f
, 2f
, 4f
) /* start, commit, abort */
215 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[cmpfail
])
216 #ifdef RSEQ_COMPARE_TWICE
217 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error1
])
218 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error2
])
219 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error3
])
221 /* Start rseq by storing table entry pointer into rseq_cs. */
222 RSEQ_ASM_STORE_RSEQ_CS(1, 3f
, rseq_cs
)
223 RSEQ_ASM_CBNE_CPU_ID(cpu_id
, current_cpu_id
, 4f
)
226 "cmp %[expect], r0\n\t"
227 "bne %l[cmpfail]\n\t"
230 "cmp %[expect2], r0\n\t"
231 "bne %l[cmpfail]\n\t"
233 #ifdef RSEQ_COMPARE_TWICE
234 RSEQ_ASM_CBNE_CPU_ID(cpu_id
, current_cpu_id
, %l
[error1
])
236 "cmp %[expect], r0\n\t"
239 "cmp %[expect2], r0\n\t"
243 "str %[newv], %[v]\n\t"
247 RSEQ_ASM_DEFINE_ABORT(3, 4, "", abort
, 1b
, 2b
, 4f
)
249 : /* gcc asm goto does not allow outputs */
250 : [cpu_id
] "r" (cpu
),
251 [current_cpu_id
] "m" (rseq_get_abi()->RSEQ_TEMPLATE_CPU_ID_FIELD
),
252 [rseq_cs
] "m" (rseq_get_abi()->rseq_cs
.arch
.ptr
),
255 [expect2
] "r" (expect2
),
256 /* final store input */
258 [expect
] "r" (expect
),
261 : "r0", "memory", "cc"
264 #ifdef RSEQ_COMPARE_TWICE
265 , error1
, error2
, error3
268 rseq_after_asm_goto();
271 rseq_after_asm_goto();
275 rseq_after_asm_goto();
277 #ifdef RSEQ_COMPARE_TWICE
279 rseq_after_asm_goto();
280 rseq_bug("cpu_id comparison failed");
282 rseq_after_asm_goto();
283 rseq_bug("1st expected value comparison failed");
285 rseq_after_asm_goto();
286 rseq_bug("2nd expected value comparison failed");
290 #endif /* #if defined(RSEQ_TEMPLATE_MO_RELAXED) &&
291 (defined(RSEQ_TEMPLATE_CPU_ID) || defined(RSEQ_TEMPLATE_MM_CID)) */
293 #if (defined(RSEQ_TEMPLATE_MO_RELAXED) || defined(RSEQ_TEMPLATE_MO_RELEASE)) && \
294 (defined(RSEQ_TEMPLATE_CPU_ID) || defined(RSEQ_TEMPLATE_MM_CID))
296 static inline __attribute__((always_inline
))
297 int RSEQ_TEMPLATE_IDENTIFIER(rseq_cmpeqv_trystorev_storev
)(intptr_t *v
, intptr_t expect
,
298 intptr_t *v2
, intptr_t newv2
,
299 intptr_t newv
, int cpu
)
303 __asm__ __volatile__
goto (
304 RSEQ_ASM_DEFINE_TABLE(9, 1f
, 2f
, 4f
) /* start, commit, abort */
305 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[cmpfail
])
306 #ifdef RSEQ_COMPARE_TWICE
307 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error1
])
308 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error2
])
310 /* Start rseq by storing table entry pointer into rseq_cs. */
311 RSEQ_ASM_STORE_RSEQ_CS(1, 3f
, rseq_cs
)
312 RSEQ_ASM_CBNE_CPU_ID(cpu_id
, current_cpu_id
, 4f
)
315 "cmp %[expect], r0\n\t"
316 "bne %l[cmpfail]\n\t"
318 #ifdef RSEQ_COMPARE_TWICE
319 RSEQ_ASM_CBNE_CPU_ID(cpu_id
, current_cpu_id
, %l
[error1
])
321 "cmp %[expect], r0\n\t"
325 "str %[newv2], %[v2]\n\t"
327 #ifdef RSEQ_TEMPLATE_MO_RELEASE
328 "dmb\n\t" /* full mb provides store-release */
331 "str %[newv], %[v]\n\t"
335 RSEQ_ASM_DEFINE_ABORT(3, 4, "", abort
, 1b
, 2b
, 4f
)
337 : /* gcc asm goto does not allow outputs */
338 : [cpu_id
] "r" (cpu
),
339 [current_cpu_id
] "m" (rseq_get_abi()->RSEQ_TEMPLATE_CPU_ID_FIELD
),
340 [rseq_cs
] "m" (rseq_get_abi()->rseq_cs
.arch
.ptr
),
341 /* try store input */
344 /* final store input */
346 [expect
] "r" (expect
),
349 : "r0", "memory", "cc"
352 #ifdef RSEQ_COMPARE_TWICE
356 rseq_after_asm_goto();
359 rseq_after_asm_goto();
363 rseq_after_asm_goto();
365 #ifdef RSEQ_COMPARE_TWICE
367 rseq_after_asm_goto();
368 rseq_bug("cpu_id comparison failed");
370 rseq_after_asm_goto();
371 rseq_bug("expected value comparison failed");
376 static inline __attribute__((always_inline
))
377 int RSEQ_TEMPLATE_IDENTIFIER(rseq_cmpeqv_trymemcpy_storev
)(intptr_t *v
, intptr_t expect
,
378 void *dst
, void *src
, size_t len
,
379 intptr_t newv
, int cpu
)
381 uint32_t rseq_scratch
[3];
385 __asm__ __volatile__
goto (
386 RSEQ_ASM_DEFINE_TABLE(9, 1f
, 2f
, 4f
) /* start, commit, abort */
387 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[cmpfail
])
388 #ifdef RSEQ_COMPARE_TWICE
389 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error1
])
390 RSEQ_ASM_DEFINE_EXIT_POINT(1f
, %l
[error2
])
392 "str %[src], %[rseq_scratch0]\n\t"
393 "str %[dst], %[rseq_scratch1]\n\t"
394 "str %[len], %[rseq_scratch2]\n\t"
395 /* Start rseq by storing table entry pointer into rseq_cs. */
396 RSEQ_ASM_STORE_RSEQ_CS(1, 3f
, rseq_cs
)
397 RSEQ_ASM_CBNE_CPU_ID(cpu_id
, current_cpu_id
, 4f
)
400 "cmp %[expect], r0\n\t"
403 #ifdef RSEQ_COMPARE_TWICE
404 RSEQ_ASM_CBNE_CPU_ID(cpu_id
, current_cpu_id
, 6f
)
406 "cmp %[expect], r0\n\t"
410 "cmp %[len], #0\n\t" \
413 "ldrb %%r0, [%[src]]\n\t" \
414 "strb %%r0, [%[dst]]\n\t" \
415 "adds %[src], #1\n\t" \
416 "adds %[dst], #1\n\t" \
417 "subs %[len], #1\n\t" \
421 #ifdef RSEQ_TEMPLATE_MO_RELEASE
422 "dmb\n\t" /* full mb provides store-release */
425 "str %[newv], %[v]\n\t"
429 "ldr %[len], %[rseq_scratch2]\n\t"
430 "ldr %[dst], %[rseq_scratch1]\n\t"
431 "ldr %[src], %[rseq_scratch0]\n\t"
433 RSEQ_ASM_DEFINE_ABORT(3, 4,
435 "ldr %[len], %[rseq_scratch2]\n\t"
436 "ldr %[dst], %[rseq_scratch1]\n\t"
437 "ldr %[src], %[rseq_scratch0]\n\t",
439 RSEQ_ASM_DEFINE_CMPFAIL(5,
441 "ldr %[len], %[rseq_scratch2]\n\t"
442 "ldr %[dst], %[rseq_scratch1]\n\t"
443 "ldr %[src], %[rseq_scratch0]\n\t",
445 #ifdef RSEQ_COMPARE_TWICE
446 RSEQ_ASM_DEFINE_CMPFAIL(6,
448 "ldr %[len], %[rseq_scratch2]\n\t"
449 "ldr %[dst], %[rseq_scratch1]\n\t"
450 "ldr %[src], %[rseq_scratch0]\n\t",
452 RSEQ_ASM_DEFINE_CMPFAIL(7,
454 "ldr %[len], %[rseq_scratch2]\n\t"
455 "ldr %[dst], %[rseq_scratch1]\n\t"
456 "ldr %[src], %[rseq_scratch0]\n\t",
460 : /* gcc asm goto does not allow outputs */
461 : [cpu_id
] "r" (cpu
),
462 [current_cpu_id
] "m" (rseq_get_abi()->RSEQ_TEMPLATE_CPU_ID_FIELD
),
463 [rseq_cs
] "m" (rseq_get_abi()->rseq_cs
.arch
.ptr
),
464 /* final store input */
466 [expect
] "r" (expect
),
468 /* try memcpy input */
472 [rseq_scratch0
] "m" (rseq_scratch
[0]),
473 [rseq_scratch1
] "m" (rseq_scratch
[1]),
474 [rseq_scratch2
] "m" (rseq_scratch
[2])
476 : "r0", "memory", "cc"
479 #ifdef RSEQ_COMPARE_TWICE
483 rseq_after_asm_goto();
486 rseq_after_asm_goto();
490 rseq_after_asm_goto();
492 #ifdef RSEQ_COMPARE_TWICE
494 rseq_after_asm_goto();
495 rseq_bug("cpu_id comparison failed");
497 rseq_after_asm_goto();
498 rseq_bug("expected value comparison failed");
502 #endif /* #if (defined(RSEQ_TEMPLATE_MO_RELAXED) || defined(RSEQ_TEMPLATE_MO_RELEASE)) &&
503 (defined(RSEQ_TEMPLATE_CPU_ID) || defined(RSEQ_TEMPLATE_MM_CID)) */
505 #include "rseq-bits-reset.h"