1 /* SPDX-License-Identifier: LGPL-2.1 OR MIT */
5 * (C) Copyright 2016-2018 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
6 * (C) Copyright 2018 - Will Deacon <will.deacon@arm.com>
9 #define RSEQ_SIG 0xd428bc00 /* BRK #0x45E0 */
11 #define rseq_smp_mb() __asm__ __volatile__ ("dmb ish" ::: "memory")
12 #define rseq_smp_rmb() __asm__ __volatile__ ("dmb ishld" ::: "memory")
13 #define rseq_smp_wmb() __asm__ __volatile__ ("dmb ishst" ::: "memory")
15 #define rseq_smp_load_acquire(p) \
17 __typeof(*p) ____p1; \
18 switch (sizeof(*p)) { \
20 asm volatile ("ldarb %w0, %1" \
22 : "Q" (*p) : "memory"); \
25 asm volatile ("ldarh %w0, %1" \
26 : "=r" (*(__u16 *)p) \
27 : "Q" (*p) : "memory"); \
30 asm volatile ("ldar %w0, %1" \
31 : "=r" (*(__u32 *)p) \
32 : "Q" (*p) : "memory"); \
35 asm volatile ("ldar %0, %1" \
36 : "=r" (*(__u64 *)p) \
37 : "Q" (*p) : "memory"); \
43 #define rseq_smp_acquire__after_ctrl_dep() rseq_smp_rmb()
45 #define rseq_smp_store_release(p, v) \
47 switch (sizeof(*p)) { \
49 asm volatile ("stlrb %w1, %0" \
55 asm volatile ("stlrh %w1, %0" \
61 asm volatile ("stlr %w1, %0" \
67 asm volatile ("stlr %1, %0" \
75 #ifdef RSEQ_SKIP_FASTPATH
76 #include "rseq-skip.h"
77 #else /* !RSEQ_SKIP_FASTPATH */
79 #define RSEQ_ASM_TMP_REG32 "w15"
80 #define RSEQ_ASM_TMP_REG "x15"
81 #define RSEQ_ASM_TMP_REG_2 "x14"
83 #define __RSEQ_ASM_DEFINE_TABLE(label, version, flags, start_ip, \
84 post_commit_offset, abort_ip) \
85 " .pushsection __rseq_table, \"aw\"\n" \
87 __rseq_str(label) ":\n" \
88 " .long " __rseq_str(version) ", " __rseq_str(flags) "\n" \
89 " .quad " __rseq_str(start_ip) ", " \
90 __rseq_str(post_commit_offset) ", " \
91 __rseq_str(abort_ip) "\n" \
94 #define RSEQ_ASM_DEFINE_TABLE(label, start_ip, post_commit_ip, abort_ip) \
95 __RSEQ_ASM_DEFINE_TABLE(label, 0x0, 0x0, start_ip, \
96 (post_commit_ip - start_ip), abort_ip)
98 #define RSEQ_ASM_STORE_RSEQ_CS(label, cs_label, rseq_cs) \
100 " adrp " RSEQ_ASM_TMP_REG ", " __rseq_str(cs_label) "\n" \
101 " add " RSEQ_ASM_TMP_REG ", " RSEQ_ASM_TMP_REG \
102 ", :lo12:" __rseq_str(cs_label) "\n" \
103 " str " RSEQ_ASM_TMP_REG ", %[" __rseq_str(rseq_cs) "]\n" \
104 __rseq_str(label) ":\n"
106 #define RSEQ_ASM_DEFINE_ABORT(label, abort_label) \
108 " .inst " __rseq_str(RSEQ_SIG) "\n" \
109 __rseq_str(label) ":\n" \
110 " b %l[" __rseq_str(abort_label) "]\n" \
113 #define RSEQ_ASM_OP_STORE(value, var) \
114 " str %[" __rseq_str(value) "], %[" __rseq_str(var) "]\n"
116 #define RSEQ_ASM_OP_STORE_RELEASE(value, var) \
117 " stlr %[" __rseq_str(value) "], %[" __rseq_str(var) "]\n"
119 #define RSEQ_ASM_OP_FINAL_STORE(value, var, post_commit_label) \
120 RSEQ_ASM_OP_STORE(value, var) \
121 __rseq_str(post_commit_label) ":\n"
123 #define RSEQ_ASM_OP_FINAL_STORE_RELEASE(value, var, post_commit_label) \
124 RSEQ_ASM_OP_STORE_RELEASE(value, var) \
125 __rseq_str(post_commit_label) ":\n"
127 #define RSEQ_ASM_OP_CMPEQ(var, expect, label) \
128 " ldr " RSEQ_ASM_TMP_REG ", %[" __rseq_str(var) "]\n" \
129 " sub " RSEQ_ASM_TMP_REG ", " RSEQ_ASM_TMP_REG \
130 ", %[" __rseq_str(expect) "]\n" \
131 " cbnz " RSEQ_ASM_TMP_REG ", " __rseq_str(label) "\n"
133 #define RSEQ_ASM_OP_CMPEQ32(var, expect, label) \
134 " ldr " RSEQ_ASM_TMP_REG32 ", %[" __rseq_str(var) "]\n" \
135 " sub " RSEQ_ASM_TMP_REG32 ", " RSEQ_ASM_TMP_REG32 \
136 ", %w[" __rseq_str(expect) "]\n" \
137 " cbnz " RSEQ_ASM_TMP_REG32 ", " __rseq_str(label) "\n"
139 #define RSEQ_ASM_OP_CMPNE(var, expect, label) \
140 " ldr " RSEQ_ASM_TMP_REG ", %[" __rseq_str(var) "]\n" \
141 " sub " RSEQ_ASM_TMP_REG ", " RSEQ_ASM_TMP_REG \
142 ", %[" __rseq_str(expect) "]\n" \
143 " cbz " RSEQ_ASM_TMP_REG ", " __rseq_str(label) "\n"
145 #define RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, label) \
147 RSEQ_ASM_OP_CMPEQ32(current_cpu_id, cpu_id, label)
149 #define RSEQ_ASM_OP_R_LOAD(var) \
150 " ldr " RSEQ_ASM_TMP_REG ", %[" __rseq_str(var) "]\n"
152 #define RSEQ_ASM_OP_R_STORE(var) \
153 " str " RSEQ_ASM_TMP_REG ", %[" __rseq_str(var) "]\n"
155 #define RSEQ_ASM_OP_R_LOAD_OFF(offset) \
156 " ldr " RSEQ_ASM_TMP_REG ", [" RSEQ_ASM_TMP_REG \
157 ", %[" __rseq_str(offset) "]]\n"
159 #define RSEQ_ASM_OP_R_ADD(count) \
160 " add " RSEQ_ASM_TMP_REG ", " RSEQ_ASM_TMP_REG \
161 ", %[" __rseq_str(count) "]\n"
163 #define RSEQ_ASM_OP_R_FINAL_STORE(var, post_commit_label) \
164 " str " RSEQ_ASM_TMP_REG ", %[" __rseq_str(var) "]\n" \
165 __rseq_str(post_commit_label) ":\n"
167 #define RSEQ_ASM_OP_R_BAD_MEMCPY(dst, src, len) \
168 " cbz %[" __rseq_str(len) "], 333f\n" \
169 " mov " RSEQ_ASM_TMP_REG_2 ", %[" __rseq_str(len) "]\n" \
170 "222: sub " RSEQ_ASM_TMP_REG_2 ", " RSEQ_ASM_TMP_REG_2 ", #1\n" \
171 " ldrb " RSEQ_ASM_TMP_REG32 ", [%[" __rseq_str(src) "]" \
172 ", " RSEQ_ASM_TMP_REG_2 "]\n" \
173 " strb " RSEQ_ASM_TMP_REG32 ", [%[" __rseq_str(dst) "]" \
174 ", " RSEQ_ASM_TMP_REG_2 "]\n" \
175 " cbnz " RSEQ_ASM_TMP_REG_2 ", 222b\n" \
178 static inline __attribute__((always_inline
))
179 int rseq_cmpeqv_storev(intptr_t *v
, intptr_t expect
, intptr_t newv
, int cpu
)
183 __asm__ __volatile__
goto (
184 RSEQ_ASM_DEFINE_TABLE(1, 2f
, 3f
, 4f
)
185 RSEQ_ASM_STORE_RSEQ_CS(2, 1b
, rseq_cs
)
186 RSEQ_ASM_CMP_CPU_ID(cpu_id
, current_cpu_id
, 4f
)
188 RSEQ_ASM_OP_CMPEQ(v
, expect
, %l
[cmpfail
])
190 #ifdef RSEQ_COMPARE_TWICE
191 RSEQ_ASM_CMP_CPU_ID(cpu_id
, current_cpu_id
, %l
[error1
])
192 RSEQ_ASM_OP_CMPEQ(v
, expect
, %l
[error2
])
194 RSEQ_ASM_OP_FINAL_STORE(newv
, v
, 3)
196 RSEQ_ASM_DEFINE_ABORT(4, abort
)
197 : /* gcc asm goto does not allow outputs */
198 : [cpu_id
] "r" (cpu
),
199 [current_cpu_id
] "Qo" (__rseq_abi
.cpu_id
),
200 [rseq_cs
] "m" (__rseq_abi
.rseq_cs
),
202 [expect
] "r" (expect
),
205 : "memory", RSEQ_ASM_TMP_REG
207 #ifdef RSEQ_COMPARE_TWICE
218 #ifdef RSEQ_COMPARE_TWICE
220 rseq_bug("cpu_id comparison failed");
222 rseq_bug("expected value comparison failed");
226 static inline __attribute__((always_inline
))
227 int rseq_cmpnev_storeoffp_load(intptr_t *v
, intptr_t expectnot
,
228 off_t voffp
, intptr_t *load
, int cpu
)
232 __asm__ __volatile__
goto (
233 RSEQ_ASM_DEFINE_TABLE(1, 2f
, 3f
, 4f
)
234 RSEQ_ASM_STORE_RSEQ_CS(2, 1b
, rseq_cs
)
235 RSEQ_ASM_CMP_CPU_ID(cpu_id
, current_cpu_id
, 4f
)
237 RSEQ_ASM_OP_CMPNE(v
, expectnot
, %l
[cmpfail
])
239 #ifdef RSEQ_COMPARE_TWICE
240 RSEQ_ASM_CMP_CPU_ID(cpu_id
, current_cpu_id
, %l
[error1
])
241 RSEQ_ASM_OP_CMPNE(v
, expectnot
, %l
[error2
])
243 RSEQ_ASM_OP_R_LOAD(v
)
244 RSEQ_ASM_OP_R_STORE(load
)
245 RSEQ_ASM_OP_R_LOAD_OFF(voffp
)
246 RSEQ_ASM_OP_R_FINAL_STORE(v
, 3)
248 RSEQ_ASM_DEFINE_ABORT(4, abort
)
249 : /* gcc asm goto does not allow outputs */
250 : [cpu_id
] "r" (cpu
),
251 [current_cpu_id
] "Qo" (__rseq_abi
.cpu_id
),
252 [rseq_cs
] "m" (__rseq_abi
.rseq_cs
),
254 [expectnot
] "r" (expectnot
),
258 : "memory", RSEQ_ASM_TMP_REG
260 #ifdef RSEQ_COMPARE_TWICE
270 #ifdef RSEQ_COMPARE_TWICE
272 rseq_bug("cpu_id comparison failed");
274 rseq_bug("expected value comparison failed");
278 static inline __attribute__((always_inline
))
279 int rseq_addv(intptr_t *v
, intptr_t count
, int cpu
)
283 __asm__ __volatile__
goto (
284 RSEQ_ASM_DEFINE_TABLE(1, 2f
, 3f
, 4f
)
285 RSEQ_ASM_STORE_RSEQ_CS(2, 1b
, rseq_cs
)
286 RSEQ_ASM_CMP_CPU_ID(cpu_id
, current_cpu_id
, 4f
)
288 #ifdef RSEQ_COMPARE_TWICE
289 RSEQ_ASM_CMP_CPU_ID(cpu_id
, current_cpu_id
, %l
[error1
])
291 RSEQ_ASM_OP_R_LOAD(v
)
292 RSEQ_ASM_OP_R_ADD(count
)
293 RSEQ_ASM_OP_R_FINAL_STORE(v
, 3)
295 RSEQ_ASM_DEFINE_ABORT(4, abort
)
296 : /* gcc asm goto does not allow outputs */
297 : [cpu_id
] "r" (cpu
),
298 [current_cpu_id
] "Qo" (__rseq_abi
.cpu_id
),
299 [rseq_cs
] "m" (__rseq_abi
.rseq_cs
),
303 : "memory", RSEQ_ASM_TMP_REG
305 #ifdef RSEQ_COMPARE_TWICE
313 #ifdef RSEQ_COMPARE_TWICE
315 rseq_bug("cpu_id comparison failed");
319 static inline __attribute__((always_inline
))
320 int rseq_cmpeqv_trystorev_storev(intptr_t *v
, intptr_t expect
,
321 intptr_t *v2
, intptr_t newv2
,
322 intptr_t newv
, int cpu
)
326 __asm__ __volatile__
goto (
327 RSEQ_ASM_DEFINE_TABLE(1, 2f
, 3f
, 4f
)
328 RSEQ_ASM_STORE_RSEQ_CS(2, 1b
, rseq_cs
)
329 RSEQ_ASM_CMP_CPU_ID(cpu_id
, current_cpu_id
, 4f
)
331 RSEQ_ASM_OP_CMPEQ(v
, expect
, %l
[cmpfail
])
333 #ifdef RSEQ_COMPARE_TWICE
334 RSEQ_ASM_CMP_CPU_ID(cpu_id
, current_cpu_id
, %l
[error1
])
335 RSEQ_ASM_OP_CMPEQ(v
, expect
, %l
[error2
])
337 RSEQ_ASM_OP_STORE(newv2
, v2
)
339 RSEQ_ASM_OP_FINAL_STORE(newv
, v
, 3)
341 RSEQ_ASM_DEFINE_ABORT(4, abort
)
342 : /* gcc asm goto does not allow outputs */
343 : [cpu_id
] "r" (cpu
),
344 [current_cpu_id
] "Qo" (__rseq_abi
.cpu_id
),
345 [rseq_cs
] "m" (__rseq_abi
.rseq_cs
),
346 [expect
] "r" (expect
),
352 : "memory", RSEQ_ASM_TMP_REG
354 #ifdef RSEQ_COMPARE_TWICE
365 #ifdef RSEQ_COMPARE_TWICE
367 rseq_bug("cpu_id comparison failed");
369 rseq_bug("expected value comparison failed");
373 static inline __attribute__((always_inline
))
374 int rseq_cmpeqv_trystorev_storev_release(intptr_t *v
, intptr_t expect
,
375 intptr_t *v2
, intptr_t newv2
,
376 intptr_t newv
, int cpu
)
380 __asm__ __volatile__
goto (
381 RSEQ_ASM_DEFINE_TABLE(1, 2f
, 3f
, 4f
)
382 RSEQ_ASM_STORE_RSEQ_CS(2, 1b
, rseq_cs
)
383 RSEQ_ASM_CMP_CPU_ID(cpu_id
, current_cpu_id
, 4f
)
385 RSEQ_ASM_OP_CMPEQ(v
, expect
, %l
[cmpfail
])
387 #ifdef RSEQ_COMPARE_TWICE
388 RSEQ_ASM_CMP_CPU_ID(cpu_id
, current_cpu_id
, %l
[error1
])
389 RSEQ_ASM_OP_CMPEQ(v
, expect
, %l
[error2
])
391 RSEQ_ASM_OP_STORE(newv2
, v2
)
393 RSEQ_ASM_OP_FINAL_STORE_RELEASE(newv
, v
, 3)
395 RSEQ_ASM_DEFINE_ABORT(4, abort
)
396 : /* gcc asm goto does not allow outputs */
397 : [cpu_id
] "r" (cpu
),
398 [current_cpu_id
] "Qo" (__rseq_abi
.cpu_id
),
399 [rseq_cs
] "m" (__rseq_abi
.rseq_cs
),
400 [expect
] "r" (expect
),
406 : "memory", RSEQ_ASM_TMP_REG
408 #ifdef RSEQ_COMPARE_TWICE
419 #ifdef RSEQ_COMPARE_TWICE
421 rseq_bug("cpu_id comparison failed");
423 rseq_bug("expected value comparison failed");
427 static inline __attribute__((always_inline
))
428 int rseq_cmpeqv_cmpeqv_storev(intptr_t *v
, intptr_t expect
,
429 intptr_t *v2
, intptr_t expect2
,
430 intptr_t newv
, int cpu
)
434 __asm__ __volatile__
goto (
435 RSEQ_ASM_DEFINE_TABLE(1, 2f
, 3f
, 4f
)
436 RSEQ_ASM_STORE_RSEQ_CS(2, 1b
, rseq_cs
)
437 RSEQ_ASM_CMP_CPU_ID(cpu_id
, current_cpu_id
, 4f
)
439 RSEQ_ASM_OP_CMPEQ(v
, expect
, %l
[cmpfail
])
441 RSEQ_ASM_OP_CMPEQ(v2
, expect2
, %l
[cmpfail
])
443 #ifdef RSEQ_COMPARE_TWICE
444 RSEQ_ASM_CMP_CPU_ID(cpu_id
, current_cpu_id
, %l
[error1
])
445 RSEQ_ASM_OP_CMPEQ(v
, expect
, %l
[error2
])
446 RSEQ_ASM_OP_CMPEQ(v2
, expect2
, %l
[error3
])
448 RSEQ_ASM_OP_FINAL_STORE(newv
, v
, 3)
450 RSEQ_ASM_DEFINE_ABORT(4, abort
)
451 : /* gcc asm goto does not allow outputs */
452 : [cpu_id
] "r" (cpu
),
453 [current_cpu_id
] "Qo" (__rseq_abi
.cpu_id
),
454 [rseq_cs
] "m" (__rseq_abi
.rseq_cs
),
456 [expect
] "r" (expect
),
458 [expect2
] "r" (expect2
),
461 : "memory", RSEQ_ASM_TMP_REG
463 #ifdef RSEQ_COMPARE_TWICE
464 , error1
, error2
, error3
474 #ifdef RSEQ_COMPARE_TWICE
476 rseq_bug("cpu_id comparison failed");
478 rseq_bug("expected value comparison failed");
480 rseq_bug("2nd expected value comparison failed");
484 static inline __attribute__((always_inline
))
485 int rseq_cmpeqv_trymemcpy_storev(intptr_t *v
, intptr_t expect
,
486 void *dst
, void *src
, size_t len
,
487 intptr_t newv
, int cpu
)
491 __asm__ __volatile__
goto (
492 RSEQ_ASM_DEFINE_TABLE(1, 2f
, 3f
, 4f
)
493 RSEQ_ASM_STORE_RSEQ_CS(2, 1b
, rseq_cs
)
494 RSEQ_ASM_CMP_CPU_ID(cpu_id
, current_cpu_id
, 4f
)
496 RSEQ_ASM_OP_CMPEQ(v
, expect
, %l
[cmpfail
])
498 #ifdef RSEQ_COMPARE_TWICE
499 RSEQ_ASM_CMP_CPU_ID(cpu_id
, current_cpu_id
, %l
[error1
])
500 RSEQ_ASM_OP_CMPEQ(v
, expect
, %l
[error2
])
502 RSEQ_ASM_OP_R_BAD_MEMCPY(dst
, src
, len
)
504 RSEQ_ASM_OP_FINAL_STORE(newv
, v
, 3)
506 RSEQ_ASM_DEFINE_ABORT(4, abort
)
507 : /* gcc asm goto does not allow outputs */
508 : [cpu_id
] "r" (cpu
),
509 [current_cpu_id
] "Qo" (__rseq_abi
.cpu_id
),
510 [rseq_cs
] "m" (__rseq_abi
.rseq_cs
),
511 [expect
] "r" (expect
),
518 : "memory", RSEQ_ASM_TMP_REG
, RSEQ_ASM_TMP_REG_2
520 #ifdef RSEQ_COMPARE_TWICE
531 #ifdef RSEQ_COMPARE_TWICE
533 rseq_bug("cpu_id comparison failed");
535 rseq_bug("expected value comparison failed");
539 static inline __attribute__((always_inline
))
540 int rseq_cmpeqv_trymemcpy_storev_release(intptr_t *v
, intptr_t expect
,
541 void *dst
, void *src
, size_t len
,
542 intptr_t newv
, int cpu
)
546 __asm__ __volatile__
goto (
547 RSEQ_ASM_DEFINE_TABLE(1, 2f
, 3f
, 4f
)
548 RSEQ_ASM_STORE_RSEQ_CS(2, 1b
, rseq_cs
)
549 RSEQ_ASM_CMP_CPU_ID(cpu_id
, current_cpu_id
, 4f
)
551 RSEQ_ASM_OP_CMPEQ(v
, expect
, %l
[cmpfail
])
553 #ifdef RSEQ_COMPARE_TWICE
554 RSEQ_ASM_CMP_CPU_ID(cpu_id
, current_cpu_id
, %l
[error1
])
555 RSEQ_ASM_OP_CMPEQ(v
, expect
, %l
[error2
])
557 RSEQ_ASM_OP_R_BAD_MEMCPY(dst
, src
, len
)
559 RSEQ_ASM_OP_FINAL_STORE_RELEASE(newv
, v
, 3)
561 RSEQ_ASM_DEFINE_ABORT(4, abort
)
562 : /* gcc asm goto does not allow outputs */
563 : [cpu_id
] "r" (cpu
),
564 [current_cpu_id
] "Qo" (__rseq_abi
.cpu_id
),
565 [rseq_cs
] "m" (__rseq_abi
.rseq_cs
),
566 [expect
] "r" (expect
),
573 : "memory", RSEQ_ASM_TMP_REG
, RSEQ_ASM_TMP_REG_2
575 #ifdef RSEQ_COMPARE_TWICE
586 #ifdef RSEQ_COMPARE_TWICE
588 rseq_bug("cpu_id comparison failed");
590 rseq_bug("expected value comparison failed");
594 #endif /* !RSEQ_SKIP_FASTPATH */