1 /* SPDX-License-Identifier: MIT */
2 /* SPDX-FileCopyrightText: 2022 Vincent Chen <vincent.chen@sifive.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_load_cbne_store__ptr
)(intptr_t *v
, intptr_t expect
, intptr_t newv
, int cpu
)
20 __asm__ __volatile__
goto(RSEQ_ASM_DEFINE_TABLE(1, 2f
, 3f
, 4f
)
21 RSEQ_ASM_DEFINE_EXIT_POINT(2f
, "%l[ne]")
22 #ifdef RSEQ_COMPARE_TWICE
23 RSEQ_ASM_DEFINE_EXIT_POINT(2f
, "%l[error1]")
24 RSEQ_ASM_DEFINE_EXIT_POINT(2f
, "%l[error2]")
26 RSEQ_ASM_STORE_RSEQ_CS(2, 1b
, rseq_cs
)
27 RSEQ_ASM_CBNE_CPU_ID(cpu_id
, current_cpu_id
, 4f
)
29 RSEQ_ASM_OP_CBNE(v
, expect
, "%l[ne]")
31 #ifdef RSEQ_COMPARE_TWICE
32 RSEQ_ASM_CBNE_CPU_ID(cpu_id
, current_cpu_id
, "%l[error1]")
33 RSEQ_ASM_OP_CBNE(v
, expect
, "%l[error2]")
35 RSEQ_ASM_OP_FINAL_STORE(newv
, v
, 3)
37 RSEQ_ASM_DEFINE_ABORT(4, "", abort
)
38 : /* gcc asm goto does not allow outputs */
40 [current_cpu_id
] "m" (rseq_get_abi()->RSEQ_TEMPLATE_CPU_ID_FIELD
),
41 [rseq_cs
] "m" (rseq_get_abi()->rseq_cs
.arch
.ptr
),
43 [expect
] "r" (expect
),
46 : "memory", RSEQ_ASM_TMP_REG_1
49 #ifdef RSEQ_COMPARE_TWICE
60 #ifdef RSEQ_COMPARE_TWICE
62 rseq_bug("cpu_id comparison failed");
64 rseq_bug("expected value comparison failed");
68 static inline __attribute__((always_inline
))
69 int RSEQ_TEMPLATE_IDENTIFIER(rseq_load_cbeq_store_add_load_store__ptr
)(intptr_t *v
, intptr_t expectnot
,
70 off_t voffp
, intptr_t *load
, int cpu
)
74 __asm__ __volatile__
goto(RSEQ_ASM_DEFINE_TABLE(1, 2f
, 3f
, 4f
)
75 RSEQ_ASM_DEFINE_EXIT_POINT(2f
, "%l[eq]")
76 #ifdef RSEQ_COMPARE_TWICE
77 RSEQ_ASM_DEFINE_EXIT_POINT(2f
, "%l[error1]")
78 RSEQ_ASM_DEFINE_EXIT_POINT(2f
, "%l[error2]")
80 RSEQ_ASM_STORE_RSEQ_CS(2, 1b
, rseq_cs
)
81 RSEQ_ASM_CBNE_CPU_ID(cpu_id
, current_cpu_id
, 4f
)
83 RSEQ_ASM_OP_CBEQ(v
, expectnot
, "%l[eq]")
85 #ifdef RSEQ_COMPARE_TWICE
86 RSEQ_ASM_CBNE_CPU_ID(cpu_id
, current_cpu_id
, "%l[error1]")
87 RSEQ_ASM_OP_CBEQ(v
, expectnot
, "%l[error2]")
90 RSEQ_ASM_OP_R_STORE(load
)
91 RSEQ_ASM_OP_R_LOAD_OFF(voffp
)
92 RSEQ_ASM_OP_R_FINAL_STORE(v
, 3)
94 RSEQ_ASM_DEFINE_ABORT(4, "", abort
)
95 : /* gcc asm goto does not allow outputs */
97 [current_cpu_id
] "m" (rseq_get_abi()->RSEQ_TEMPLATE_CPU_ID_FIELD
),
98 [rseq_cs
] "m" (rseq_get_abi()->rseq_cs
.arch
.ptr
),
100 [expectnot
] "r" (expectnot
),
104 : "memory", RSEQ_ASM_TMP_REG_1
107 #ifdef RSEQ_COMPARE_TWICE
117 #ifdef RSEQ_COMPARE_TWICE
119 rseq_bug("cpu_id comparison failed");
121 rseq_bug("expected value comparison failed");
125 static inline __attribute__((always_inline
))
126 int RSEQ_TEMPLATE_IDENTIFIER(rseq_load_add_store__ptr
)(intptr_t *v
, intptr_t count
, int cpu
)
130 __asm__ __volatile__
goto(RSEQ_ASM_DEFINE_TABLE(1, 2f
, 3f
, 4f
)
131 #ifdef RSEQ_COMPARE_TWICE
132 RSEQ_ASM_DEFINE_EXIT_POINT(2f
, "%l[error1]")
134 RSEQ_ASM_STORE_RSEQ_CS(2, 1b
, rseq_cs
)
135 RSEQ_ASM_CBNE_CPU_ID(cpu_id
, current_cpu_id
, 4f
)
137 #ifdef RSEQ_COMPARE_TWICE
138 RSEQ_ASM_CBNE_CPU_ID(cpu_id
, current_cpu_id
, "%l[error1]")
140 RSEQ_ASM_OP_R_LOAD(v
)
141 RSEQ_ASM_OP_R_ADD(count
)
142 RSEQ_ASM_OP_R_FINAL_STORE(v
, 3)
144 RSEQ_ASM_DEFINE_ABORT(4, "", abort
)
145 : /* gcc asm goto does not allow outputs */
146 : [cpu_id
] "r" (cpu
),
147 [current_cpu_id
] "m" (rseq_get_abi()->RSEQ_TEMPLATE_CPU_ID_FIELD
),
148 [rseq_cs
] "m" (rseq_get_abi()->rseq_cs
.arch
.ptr
),
152 : "memory", RSEQ_ASM_TMP_REG_1
155 #ifdef RSEQ_COMPARE_TWICE
163 #ifdef RSEQ_COMPARE_TWICE
165 rseq_bug("cpu_id comparison failed");
169 static inline __attribute__((always_inline
))
170 int RSEQ_TEMPLATE_IDENTIFIER(rseq_load_cbne_load_cbne_store__ptr
)(intptr_t *v
, intptr_t expect
,
171 intptr_t *v2
, intptr_t expect2
,
172 intptr_t newv
, int cpu
)
176 __asm__ __volatile__
goto(RSEQ_ASM_DEFINE_TABLE(1, 2f
, 3f
, 4f
)
177 RSEQ_ASM_DEFINE_EXIT_POINT(2f
, "%l[ne]")
178 #ifdef RSEQ_COMPARE_TWICE
179 RSEQ_ASM_DEFINE_EXIT_POINT(2f
, "%l[error1]")
180 RSEQ_ASM_DEFINE_EXIT_POINT(2f
, "%l[error2]")
181 RSEQ_ASM_DEFINE_EXIT_POINT(2f
, "%l[error3]")
183 RSEQ_ASM_STORE_RSEQ_CS(2, 1b
, rseq_cs
)
184 RSEQ_ASM_CBNE_CPU_ID(cpu_id
, current_cpu_id
, 4f
)
186 RSEQ_ASM_OP_CBNE(v
, expect
, "%l[ne]")
188 RSEQ_ASM_OP_CBNE(v2
, expect2
, "%l[ne]")
190 #ifdef RSEQ_COMPARE_TWICE
191 RSEQ_ASM_CBNE_CPU_ID(cpu_id
, current_cpu_id
, "%l[error1]")
192 RSEQ_ASM_OP_CBNE(v
, expect
, "%l[error2]")
193 RSEQ_ASM_OP_CBNE(v2
, expect2
, "%l[error3]")
195 RSEQ_ASM_OP_FINAL_STORE(newv
, v
, 3)
197 RSEQ_ASM_DEFINE_ABORT(4, "", abort
)
198 : /* gcc asm goto does not allow outputs */
199 : [cpu_id
] "r" (cpu
),
200 [current_cpu_id
] "m" (rseq_get_abi()->RSEQ_TEMPLATE_CPU_ID_FIELD
),
201 [rseq_cs
] "m" (rseq_get_abi()->rseq_cs
.arch
.ptr
),
203 [expect
] "r" (expect
),
205 [expect2
] "r" (expect2
),
208 : "memory", RSEQ_ASM_TMP_REG_1
211 #ifdef RSEQ_COMPARE_TWICE
212 , error1
, error2
, error3
222 #ifdef RSEQ_COMPARE_TWICE
224 rseq_bug("cpu_id comparison failed");
226 rseq_bug("expected value comparison failed");
228 rseq_bug("2nd expected value comparison failed");
232 #define RSEQ_ARCH_HAS_OFFSET_DEREF_ADDV
234 static inline __attribute__((always_inline
))
235 int RSEQ_TEMPLATE_IDENTIFIER(rseq_load_add_load_add_store__ptr
)(intptr_t *ptr
, off_t off
, intptr_t inc
, int cpu
)
239 __asm__ __volatile__
goto(RSEQ_ASM_DEFINE_TABLE(1, 2f
, 3f
, 4f
)
240 #ifdef RSEQ_COMPARE_TWICE
241 RSEQ_ASM_DEFINE_EXIT_POINT(2f
, "%l[error1]")
243 RSEQ_ASM_STORE_RSEQ_CS(2, 1b
, rseq_cs
)
244 RSEQ_ASM_CBNE_CPU_ID(cpu_id
, current_cpu_id
, 4f
)
246 #ifdef RSEQ_COMPARE_TWICE
247 RSEQ_ASM_CBNE_CPU_ID(cpu_id
, current_cpu_id
, "%l[error1]")
249 RSEQ_ASM_OP_R_DEREF_ADDV(ptr
, off
, 3)
251 RSEQ_ASM_DEFINE_ABORT(4, "", abort
)
252 : /* gcc asm goto does not allow outputs */
253 : [cpu_id
] "r" (cpu
),
254 [current_cpu_id
] "m" (rseq_get_abi()->RSEQ_TEMPLATE_CPU_ID_FIELD
),
255 [rseq_cs
] "m" (rseq_get_abi()->rseq_cs
.arch
.ptr
),
260 : "memory", RSEQ_ASM_TMP_REG_1
263 #ifdef RSEQ_COMPARE_TWICE
271 #ifdef RSEQ_COMPARE_TWICE
273 rseq_bug("cpu_id comparison failed");
277 #endif /* #if defined(RSEQ_TEMPLATE_MO_RELAXED) &&
278 (defined(RSEQ_TEMPLATE_CPU_ID) || defined(RSEQ_TEMPLATE_MM_CID)) */
280 #if (defined(RSEQ_TEMPLATE_MO_RELAXED) || defined(RSEQ_TEMPLATE_MO_RELEASE)) && \
281 (defined(RSEQ_TEMPLATE_CPU_ID) || defined(RSEQ_TEMPLATE_MM_CID))
283 static inline __attribute__((always_inline
))
284 int RSEQ_TEMPLATE_IDENTIFIER(rseq_load_cbne_store_store__ptr
)(intptr_t *v
, intptr_t expect
,
285 intptr_t *v2
, intptr_t newv2
,
286 intptr_t newv
, int cpu
)
290 __asm__ __volatile__
goto(RSEQ_ASM_DEFINE_TABLE(1, 2f
, 3f
, 4f
)
291 RSEQ_ASM_DEFINE_EXIT_POINT(2f
, "%l[ne]")
292 #ifdef RSEQ_COMPARE_TWICE
293 RSEQ_ASM_DEFINE_EXIT_POINT(2f
, "%l[error1]")
294 RSEQ_ASM_DEFINE_EXIT_POINT(2f
, "%l[error2]")
296 RSEQ_ASM_STORE_RSEQ_CS(2, 1b
, rseq_cs
)
297 RSEQ_ASM_CBNE_CPU_ID(cpu_id
, current_cpu_id
, 4f
)
299 RSEQ_ASM_OP_CBNE(v
, expect
, "%l[ne]")
301 #ifdef RSEQ_COMPARE_TWICE
302 RSEQ_ASM_CBNE_CPU_ID(cpu_id
, current_cpu_id
, "%l[error1]")
303 RSEQ_ASM_OP_CBNE(v
, expect
, "%l[error2]")
305 RSEQ_ASM_OP_STORE(newv2
, v2
)
307 #ifdef RSEQ_TEMPLATE_MO_RELEASE
308 RSEQ_ASM_OP_FINAL_STORE_RELEASE(newv
, v
, 3)
310 RSEQ_ASM_OP_FINAL_STORE(newv
, v
, 3)
313 RSEQ_ASM_DEFINE_ABORT(4, "", abort
)
314 : /* gcc asm goto does not allow outputs */
315 : [cpu_id
] "r" (cpu
),
316 [current_cpu_id
] "m" (rseq_get_abi()->RSEQ_TEMPLATE_CPU_ID_FIELD
),
317 [rseq_cs
] "m" (rseq_get_abi()->rseq_cs
.arch
.ptr
),
318 [expect
] "r" (expect
),
324 : "memory", RSEQ_ASM_TMP_REG_1
327 #ifdef RSEQ_COMPARE_TWICE
338 #ifdef RSEQ_COMPARE_TWICE
340 rseq_bug("cpu_id comparison failed");
342 rseq_bug("expected value comparison failed");
346 static inline __attribute__((always_inline
))
347 int RSEQ_TEMPLATE_IDENTIFIER(rseq_load_cbne_memcpy_store__ptr
)(intptr_t *v
, intptr_t expect
,
348 void *dst
, void *src
, size_t len
,
349 intptr_t newv
, int cpu
)
352 __asm__ __volatile__
goto(RSEQ_ASM_DEFINE_TABLE(1, 2f
, 3f
, 4f
)
353 RSEQ_ASM_DEFINE_EXIT_POINT(2f
, "%l[ne]")
354 #ifdef RSEQ_COMPARE_TWICE
355 RSEQ_ASM_DEFINE_EXIT_POINT(2f
, "%l[error1]")
356 RSEQ_ASM_DEFINE_EXIT_POINT(2f
, "%l[error2]")
358 RSEQ_ASM_STORE_RSEQ_CS(2, 1b
, rseq_cs
)
359 RSEQ_ASM_CBNE_CPU_ID(cpu_id
, current_cpu_id
, 4f
)
361 RSEQ_ASM_OP_CBNE(v
, expect
, "%l[ne]")
363 #ifdef RSEQ_COMPARE_TWICE
364 RSEQ_ASM_CBNE_CPU_ID(cpu_id
, current_cpu_id
, "%l[error1]")
365 RSEQ_ASM_OP_CBNE(v
, expect
, "%l[error2]")
367 RSEQ_ASM_OP_R_BAD_MEMCPY(dst
, src
, len
)
369 #ifdef RSEQ_TEMPLATE_MO_RELEASE
370 RSEQ_ASM_OP_FINAL_STORE_RELEASE(newv
, v
, 3)
372 RSEQ_ASM_OP_FINAL_STORE(newv
, v
, 3)
375 RSEQ_ASM_DEFINE_ABORT(4, "", abort
)
376 : /* gcc asm goto does not allow outputs */
377 : [cpu_id
] "r" (cpu
),
378 [current_cpu_id
] "m" (rseq_get_abi()->RSEQ_TEMPLATE_CPU_ID_FIELD
),
379 [rseq_cs
] "m" (rseq_get_abi()->rseq_cs
.arch
.ptr
),
380 [expect
] "r" (expect
),
387 : "memory", RSEQ_ASM_TMP_REG_1
, RSEQ_ASM_TMP_REG_2
,
388 RSEQ_ASM_TMP_REG_3
, RSEQ_ASM_TMP_REG_4
391 #ifdef RSEQ_COMPARE_TWICE
402 #ifdef RSEQ_COMPARE_TWICE
404 rseq_bug("cpu_id comparison failed");
406 rseq_bug("expected value comparison failed");
410 #endif /* #if (defined(RSEQ_TEMPLATE_MO_RELAXED) || defined(RSEQ_TEMPLATE_MO_RELEASE)) &&
411 (defined(RSEQ_TEMPLATE_CPU_ID) || defined(RSEQ_TEMPLATE_MM_CID)) */
413 #include "rseq-bits-reset.h"