1 /* SPDX-License-Identifier: MIT */
2 /* SPDX-FileCopyrightText: 2016-2018 Mathieu Desnoyers <mathieu.desnoyers@efficios.com> */
3 /* SPDX-FileCopyrightText: 2018 Will Deacon <will.deacon@arm.com> */
9 #include "rseq-bits-template.h"
12 * Refer to rseq-pseudocode.h for documentation and pseudo-code of the
13 * rseq critical section helpers.
15 #include "rseq-pseudocode.h"
17 #if defined(RSEQ_TEMPLATE_MO_RELAXED) && \
18 (defined(RSEQ_TEMPLATE_CPU_ID) || defined(RSEQ_TEMPLATE_MM_CID))
20 static inline __attribute__((always_inline
))
21 int RSEQ_TEMPLATE_IDENTIFIER(rseq_load_cbne_store__ptr
)(intptr_t *v
, intptr_t expect
, intptr_t newv
, int cpu
)
25 __asm__ __volatile__
goto (
26 RSEQ_ASM_DEFINE_TABLE(1, 2f
, 3f
, 4f
)
27 RSEQ_ASM_DEFINE_EXIT_POINT(2f
, %l
[ne
])
28 #ifdef RSEQ_COMPARE_TWICE
29 RSEQ_ASM_DEFINE_EXIT_POINT(2f
, %l
[error1
])
30 RSEQ_ASM_DEFINE_EXIT_POINT(2f
, %l
[error2
])
32 RSEQ_ASM_STORE_RSEQ_CS(2, 1b
, rseq_cs
)
33 RSEQ_ASM_CBNE_CPU_ID(cpu_id
, current_cpu_id
, 4f
)
35 RSEQ_ASM_OP_CBNE(v
, expect
, %l
[ne
])
37 #ifdef RSEQ_COMPARE_TWICE
38 RSEQ_ASM_CBNE_CPU_ID(cpu_id
, current_cpu_id
, %l
[error1
])
39 RSEQ_ASM_OP_CBNE(v
, expect
, %l
[error2
])
41 RSEQ_ASM_OP_FINAL_STORE(newv
, v
, 3)
43 RSEQ_ASM_DEFINE_ABORT(4, "", abort
)
44 : /* gcc asm goto does not allow outputs */
46 [current_cpu_id
] "Qo" (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", RSEQ_ASM_TMP_REG
54 #ifdef RSEQ_COMPARE_TWICE
58 rseq_after_asm_goto();
61 rseq_after_asm_goto();
65 rseq_after_asm_goto();
67 #ifdef RSEQ_COMPARE_TWICE
69 rseq_after_asm_goto();
70 rseq_bug("cpu_id comparison failed");
72 rseq_after_asm_goto();
73 rseq_bug("expected value comparison failed");
77 static inline __attribute__((always_inline
))
78 int RSEQ_TEMPLATE_IDENTIFIER(rseq_load_cbeq_store_add_load_store__ptr
)(intptr_t *v
, intptr_t expectnot
,
79 long voffp
, intptr_t *load
, int cpu
)
83 __asm__ __volatile__
goto (
84 RSEQ_ASM_DEFINE_TABLE(1, 2f
, 3f
, 4f
)
85 RSEQ_ASM_DEFINE_EXIT_POINT(2f
, %l
[eq
])
86 #ifdef RSEQ_COMPARE_TWICE
87 RSEQ_ASM_DEFINE_EXIT_POINT(2f
, %l
[error1
])
88 RSEQ_ASM_DEFINE_EXIT_POINT(2f
, %l
[error2
])
90 RSEQ_ASM_STORE_RSEQ_CS(2, 1b
, rseq_cs
)
91 RSEQ_ASM_CBNE_CPU_ID(cpu_id
, current_cpu_id
, 4f
)
93 RSEQ_ASM_OP_CBEQ(v
, expectnot
, %l
[eq
])
95 #ifdef RSEQ_COMPARE_TWICE
96 RSEQ_ASM_CBNE_CPU_ID(cpu_id
, current_cpu_id
, %l
[error1
])
97 RSEQ_ASM_OP_CBEQ(v
, expectnot
, %l
[error2
])
100 RSEQ_ASM_OP_R_STORE(load
)
101 RSEQ_ASM_OP_R_LOAD_OFF(voffp
)
102 RSEQ_ASM_OP_R_FINAL_STORE(v
, 3)
104 RSEQ_ASM_DEFINE_ABORT(4, "", abort
)
105 : /* gcc asm goto does not allow outputs */
106 : [cpu_id
] "r" (cpu
),
107 [current_cpu_id
] "Qo" (rseq_get_abi()->RSEQ_TEMPLATE_CPU_ID_FIELD
),
108 [rseq_cs
] "m" (rseq_get_abi()->rseq_cs
.arch
.ptr
),
110 [expectnot
] "r" (expectnot
),
114 : "memory", RSEQ_ASM_TMP_REG
116 #ifdef RSEQ_COMPARE_TWICE
120 rseq_after_asm_goto();
123 rseq_after_asm_goto();
127 rseq_after_asm_goto();
129 #ifdef RSEQ_COMPARE_TWICE
131 rseq_after_asm_goto();
132 rseq_bug("cpu_id comparison failed");
134 rseq_after_asm_goto();
135 rseq_bug("expected value comparison failed");
139 static inline __attribute__((always_inline
))
140 int RSEQ_TEMPLATE_IDENTIFIER(rseq_load_add_store__ptr
)(intptr_t *v
, intptr_t count
, int cpu
)
144 __asm__ __volatile__
goto (
145 RSEQ_ASM_DEFINE_TABLE(1, 2f
, 3f
, 4f
)
146 #ifdef RSEQ_COMPARE_TWICE
147 RSEQ_ASM_DEFINE_EXIT_POINT(2f
, %l
[error1
])
149 RSEQ_ASM_STORE_RSEQ_CS(2, 1b
, rseq_cs
)
150 RSEQ_ASM_CBNE_CPU_ID(cpu_id
, current_cpu_id
, 4f
)
152 #ifdef RSEQ_COMPARE_TWICE
153 RSEQ_ASM_CBNE_CPU_ID(cpu_id
, current_cpu_id
, %l
[error1
])
155 RSEQ_ASM_OP_R_LOAD(v
)
156 RSEQ_ASM_OP_R_ADD(count
)
157 RSEQ_ASM_OP_R_FINAL_STORE(v
, 3)
159 RSEQ_ASM_DEFINE_ABORT(4, "", abort
)
160 : /* gcc asm goto does not allow outputs */
161 : [cpu_id
] "r" (cpu
),
162 [current_cpu_id
] "Qo" (rseq_get_abi()->RSEQ_TEMPLATE_CPU_ID_FIELD
),
163 [rseq_cs
] "m" (rseq_get_abi()->rseq_cs
.arch
.ptr
),
167 : "memory", RSEQ_ASM_TMP_REG
169 #ifdef RSEQ_COMPARE_TWICE
173 rseq_after_asm_goto();
176 rseq_after_asm_goto();
179 #ifdef RSEQ_COMPARE_TWICE
181 rseq_after_asm_goto();
182 rseq_bug("cpu_id comparison failed");
186 static inline __attribute__((always_inline
))
187 int RSEQ_TEMPLATE_IDENTIFIER(rseq_load_cbne_load_cbne_store__ptr
)(intptr_t *v
, intptr_t expect
,
188 intptr_t *v2
, intptr_t expect2
,
189 intptr_t newv
, int cpu
)
193 __asm__ __volatile__
goto (
194 RSEQ_ASM_DEFINE_TABLE(1, 2f
, 3f
, 4f
)
195 RSEQ_ASM_DEFINE_EXIT_POINT(2f
, %l
[ne
])
196 #ifdef RSEQ_COMPARE_TWICE
197 RSEQ_ASM_DEFINE_EXIT_POINT(2f
, %l
[error1
])
198 RSEQ_ASM_DEFINE_EXIT_POINT(2f
, %l
[error2
])
199 RSEQ_ASM_DEFINE_EXIT_POINT(2f
, %l
[error3
])
201 RSEQ_ASM_STORE_RSEQ_CS(2, 1b
, rseq_cs
)
202 RSEQ_ASM_CBNE_CPU_ID(cpu_id
, current_cpu_id
, 4f
)
204 RSEQ_ASM_OP_CBNE(v
, expect
, %l
[ne
])
206 RSEQ_ASM_OP_CBNE(v2
, expect2
, %l
[ne
])
208 #ifdef RSEQ_COMPARE_TWICE
209 RSEQ_ASM_CBNE_CPU_ID(cpu_id
, current_cpu_id
, %l
[error1
])
210 RSEQ_ASM_OP_CBNE(v
, expect
, %l
[error2
])
211 RSEQ_ASM_OP_CBNE(v2
, expect2
, %l
[error3
])
213 RSEQ_ASM_OP_FINAL_STORE(newv
, v
, 3)
215 RSEQ_ASM_DEFINE_ABORT(4, "", abort
)
216 : /* gcc asm goto does not allow outputs */
217 : [cpu_id
] "r" (cpu
),
218 [current_cpu_id
] "Qo" (rseq_get_abi()->RSEQ_TEMPLATE_CPU_ID_FIELD
),
219 [rseq_cs
] "m" (rseq_get_abi()->rseq_cs
.arch
.ptr
),
221 [expect
] "r" (expect
),
223 [expect2
] "r" (expect2
),
226 : "memory", RSEQ_ASM_TMP_REG
228 #ifdef RSEQ_COMPARE_TWICE
229 , error1
, error2
, error3
232 rseq_after_asm_goto();
235 rseq_after_asm_goto();
239 rseq_after_asm_goto();
241 #ifdef RSEQ_COMPARE_TWICE
243 rseq_after_asm_goto();
244 rseq_bug("cpu_id comparison failed");
246 rseq_after_asm_goto();
247 rseq_bug("expected value comparison failed");
249 rseq_after_asm_goto();
250 rseq_bug("2nd expected value comparison failed");
254 #endif /* #if defined(RSEQ_TEMPLATE_MO_RELAXED) &&
255 (defined(RSEQ_TEMPLATE_CPU_ID) || defined(RSEQ_TEMPLATE_MM_CID)) */
257 #if (defined(RSEQ_TEMPLATE_MO_RELAXED) || defined(RSEQ_TEMPLATE_MO_RELEASE)) && \
258 (defined(RSEQ_TEMPLATE_CPU_ID) || defined(RSEQ_TEMPLATE_MM_CID))
260 static inline __attribute__((always_inline
))
261 int RSEQ_TEMPLATE_IDENTIFIER(rseq_load_cbne_store_store__ptr
)(intptr_t *v
, intptr_t expect
,
262 intptr_t *v2
, intptr_t newv2
,
263 intptr_t newv
, int cpu
)
267 __asm__ __volatile__
goto (
268 RSEQ_ASM_DEFINE_TABLE(1, 2f
, 3f
, 4f
)
269 RSEQ_ASM_DEFINE_EXIT_POINT(2f
, %l
[ne
])
270 #ifdef RSEQ_COMPARE_TWICE
271 RSEQ_ASM_DEFINE_EXIT_POINT(2f
, %l
[error1
])
272 RSEQ_ASM_DEFINE_EXIT_POINT(2f
, %l
[error2
])
274 RSEQ_ASM_STORE_RSEQ_CS(2, 1b
, rseq_cs
)
275 RSEQ_ASM_CBNE_CPU_ID(cpu_id
, current_cpu_id
, 4f
)
277 RSEQ_ASM_OP_CBNE(v
, expect
, %l
[ne
])
279 #ifdef RSEQ_COMPARE_TWICE
280 RSEQ_ASM_CBNE_CPU_ID(cpu_id
, current_cpu_id
, %l
[error1
])
281 RSEQ_ASM_OP_CBNE(v
, expect
, %l
[error2
])
283 RSEQ_ASM_OP_STORE(newv2
, v2
)
285 #ifdef RSEQ_TEMPLATE_MO_RELEASE
286 RSEQ_ASM_OP_FINAL_STORE_RELEASE(newv
, v
, 3)
288 RSEQ_ASM_OP_FINAL_STORE(newv
, v
, 3)
291 RSEQ_ASM_DEFINE_ABORT(4, "", abort
)
292 : /* gcc asm goto does not allow outputs */
293 : [cpu_id
] "r" (cpu
),
294 [current_cpu_id
] "Qo" (rseq_get_abi()->RSEQ_TEMPLATE_CPU_ID_FIELD
),
295 [rseq_cs
] "m" (rseq_get_abi()->rseq_cs
.arch
.ptr
),
296 [expect
] "r" (expect
),
302 : "memory", RSEQ_ASM_TMP_REG
304 #ifdef RSEQ_COMPARE_TWICE
308 rseq_after_asm_goto();
311 rseq_after_asm_goto();
315 rseq_after_asm_goto();
317 #ifdef RSEQ_COMPARE_TWICE
319 rseq_after_asm_goto();
320 rseq_bug("cpu_id comparison failed");
322 rseq_after_asm_goto();
323 rseq_bug("expected value comparison failed");
327 static inline __attribute__((always_inline
))
328 int RSEQ_TEMPLATE_IDENTIFIER(rseq_load_cbne_memcpy_store__ptr
)(intptr_t *v
, intptr_t expect
,
329 void *dst
, void *src
, size_t len
,
330 intptr_t newv
, int cpu
)
334 __asm__ __volatile__
goto (
335 RSEQ_ASM_DEFINE_TABLE(1, 2f
, 3f
, 4f
)
336 RSEQ_ASM_DEFINE_EXIT_POINT(2f
, %l
[ne
])
337 #ifdef RSEQ_COMPARE_TWICE
338 RSEQ_ASM_DEFINE_EXIT_POINT(2f
, %l
[error1
])
339 RSEQ_ASM_DEFINE_EXIT_POINT(2f
, %l
[error2
])
341 RSEQ_ASM_STORE_RSEQ_CS(2, 1b
, rseq_cs
)
342 RSEQ_ASM_CBNE_CPU_ID(cpu_id
, current_cpu_id
, 4f
)
344 RSEQ_ASM_OP_CBNE(v
, expect
, %l
[ne
])
346 #ifdef RSEQ_COMPARE_TWICE
347 RSEQ_ASM_CBNE_CPU_ID(cpu_id
, current_cpu_id
, %l
[error1
])
348 RSEQ_ASM_OP_CBNE(v
, expect
, %l
[error2
])
350 RSEQ_ASM_OP_R_BAD_MEMCPY(dst
, src
, len
)
352 #ifdef RSEQ_TEMPLATE_MO_RELEASE
353 RSEQ_ASM_OP_FINAL_STORE_RELEASE(newv
, v
, 3)
355 RSEQ_ASM_OP_FINAL_STORE(newv
, v
, 3)
358 RSEQ_ASM_DEFINE_ABORT(4, "", abort
)
359 : /* gcc asm goto does not allow outputs */
360 : [cpu_id
] "r" (cpu
),
361 [current_cpu_id
] "Qo" (rseq_get_abi()->RSEQ_TEMPLATE_CPU_ID_FIELD
),
362 [rseq_cs
] "m" (rseq_get_abi()->rseq_cs
.arch
.ptr
),
363 [expect
] "r" (expect
),
370 : "memory", RSEQ_ASM_TMP_REG
, RSEQ_ASM_TMP_REG_2
372 #ifdef RSEQ_COMPARE_TWICE
376 rseq_after_asm_goto();
379 rseq_after_asm_goto();
383 rseq_after_asm_goto();
385 #ifdef RSEQ_COMPARE_TWICE
387 rseq_after_asm_goto();
388 rseq_bug("cpu_id comparison failed");
390 rseq_after_asm_goto();
391 rseq_bug("expected value comparison failed");
395 #endif /* #if (defined(RSEQ_TEMPLATE_MO_RELAXED) || defined(RSEQ_TEMPLATE_MO_RELEASE)) &&
396 (defined(RSEQ_TEMPLATE_CPU_ID) || defined(RSEQ_TEMPLATE_MM_CID)) */
398 #include "rseq-bits-reset.h"