1 /* SPDX-License-Identifier: LGPL-2.1 OR MIT */
2 /*
3 * rseq-arm64.h
4 *
5 * (C) Copyright 2016-2018 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
6 * (C) Copyright 2018 - Will Deacon <will.deacon@arm.com>
7 */
8
9 /*
10 * aarch64 -mbig-endian generates mixed endianness code vs data:
11 * little-endian code and big-endian data. Ensure the RSEQ_SIG signature
12 * matches code endianness.
13 */
14 #define RSEQ_SIG_CODE 0xd428bc00 /* BRK #0x45E0. */
15
16 #ifdef __AARCH64EB__
17 #define RSEQ_SIG_DATA 0x00bc28d4 /* BRK #0x45E0. */
18 #else
19 #define RSEQ_SIG_DATA RSEQ_SIG_CODE
20 #endif
21
22 #define RSEQ_SIG RSEQ_SIG_DATA
23
24 #define rseq_smp_mb() __asm__ __volatile__ ("dmb ish" ::: "memory")
25 #define rseq_smp_rmb() __asm__ __volatile__ ("dmb ishld" ::: "memory")
26 #define rseq_smp_wmb() __asm__ __volatile__ ("dmb ishst" ::: "memory")
27
28 #define rseq_smp_load_acquire(p) \
29 __extension__ ({ \
30 __typeof(*p) ____p1; \
31 switch (sizeof(*p)) { \
32 case 1: \
33 asm volatile ("ldarb %w0, %1" \
34 : "=r" (*(__u8 *)p) \
35 : "Q" (*p) : "memory"); \
36 break; \
37 case 2: \
38 asm volatile ("ldarh %w0, %1" \
39 : "=r" (*(__u16 *)p) \
40 : "Q" (*p) : "memory"); \
41 break; \
42 case 4: \
43 asm volatile ("ldar %w0, %1" \
44 : "=r" (*(__u32 *)p) \
45 : "Q" (*p) : "memory"); \
46 break; \
47 case 8: \
48 asm volatile ("ldar %0, %1" \
49 : "=r" (*(__u64 *)p) \
50 : "Q" (*p) : "memory"); \
51 break; \
52 } \
53 ____p1; \
54 })
55
56 #define rseq_smp_acquire__after_ctrl_dep() rseq_smp_rmb()
57
58 #define rseq_smp_store_release(p, v) \
59 do { \
60 switch (sizeof(*p)) { \
61 case 1: \
62 asm volatile ("stlrb %w1, %0" \
63 : "=Q" (*p) \
64 : "r" ((__u8)v) \
65 : "memory"); \
66 break; \
67 case 2: \
68 asm volatile ("stlrh %w1, %0" \
69 : "=Q" (*p) \
70 : "r" ((__u16)v) \
71 : "memory"); \
72 break; \
73 case 4: \
74 asm volatile ("stlr %w1, %0" \
75 : "=Q" (*p) \
76 : "r" ((__u32)v) \
77 : "memory"); \
78 break; \
79 case 8: \
80 asm volatile ("stlr %1, %0" \
81 : "=Q" (*p) \
82 : "r" ((__u64)v) \
83 : "memory"); \
84 break; \
85 } \
86 } while (0)
87
88 #ifdef RSEQ_SKIP_FASTPATH
89 #include "rseq-skip.h"
90 #else /* !RSEQ_SKIP_FASTPATH */
91
92 #define RSEQ_ASM_TMP_REG32 "w15"
93 #define RSEQ_ASM_TMP_REG "x15"
94 #define RSEQ_ASM_TMP_REG_2 "x14"
95
96 #define __RSEQ_ASM_DEFINE_TABLE(label, version, flags, start_ip, \
97 post_commit_offset, abort_ip) \
98 " .pushsection __rseq_cs, \"aw\"\n" \
99 " .balign 32\n" \
100 __rseq_str(label) ":\n" \
101 " .long " __rseq_str(version) ", " __rseq_str(flags) "\n" \
102 " .quad " __rseq_str(start_ip) ", " \
103 __rseq_str(post_commit_offset) ", " \
104 __rseq_str(abort_ip) "\n" \
105 " .popsection\n\t" \
106 " .pushsection __rseq_cs_ptr_array, \"aw\"\n" \
107 " .quad " __rseq_str(label) "b\n" \
108 " .popsection\n"
109
110 #define RSEQ_ASM_DEFINE_TABLE(label, start_ip, post_commit_ip, abort_ip) \
111 __RSEQ_ASM_DEFINE_TABLE(label, 0x0, 0x0, start_ip, \
112 (post_commit_ip - start_ip), abort_ip)
113
114 /*
115 * Exit points of a rseq critical section consist of all instructions outside
116 * of the critical section where a critical section can either branch to or
117 * reach through the normal course of its execution. The abort IP and the
118 * post-commit IP are already part of the __rseq_cs section and should not be
119 * explicitly defined as additional exit points. Knowing all exit points is
120 * useful to assist debuggers stepping over the critical section.
121 */
122 #define RSEQ_ASM_DEFINE_EXIT_POINT(start_ip, exit_ip) \
123 " .pushsection __rseq_exit_point_array, \"aw\"\n" \
124 " .quad " __rseq_str(start_ip) ", " __rseq_str(exit_ip) "\n" \
125 " .popsection\n"
126
127 #define RSEQ_ASM_STORE_RSEQ_CS(label, cs_label, rseq_cs) \
128 RSEQ_INJECT_ASM(1) \
129 " adrp " RSEQ_ASM_TMP_REG ", " __rseq_str(cs_label) "\n" \
130 " add " RSEQ_ASM_TMP_REG ", " RSEQ_ASM_TMP_REG \
131 ", :lo12:" __rseq_str(cs_label) "\n" \
132 " str " RSEQ_ASM_TMP_REG ", %[" __rseq_str(rseq_cs) "]\n" \
133 __rseq_str(label) ":\n"
134
135 #define RSEQ_ASM_DEFINE_ABORT(label, abort_label) \
136 " b 222f\n" \
137 " .inst " __rseq_str(RSEQ_SIG_CODE) "\n" \
138 __rseq_str(label) ":\n" \
139 " b %l[" __rseq_str(abort_label) "]\n" \
140 "222:\n"
141
142 #define RSEQ_ASM_OP_STORE(value, var) \
143 " str %[" __rseq_str(value) "], %[" __rseq_str(var) "]\n"
144
145 #define RSEQ_ASM_OP_STORE_RELEASE(value, var) \
146 " stlr %[" __rseq_str(value) "], %[" __rseq_str(var) "]\n"
147
148 #define RSEQ_ASM_OP_FINAL_STORE(value, var, post_commit_label) \
149 RSEQ_ASM_OP_STORE(value, var) \
150 __rseq_str(post_commit_label) ":\n"
151
152 #define RSEQ_ASM_OP_FINAL_STORE_RELEASE(value, var, post_commit_label) \
153 RSEQ_ASM_OP_STORE_RELEASE(value, var) \
154 __rseq_str(post_commit_label) ":\n"
155
156 #define RSEQ_ASM_OP_CMPEQ(var, expect, label) \
157 " ldr " RSEQ_ASM_TMP_REG ", %[" __rseq_str(var) "]\n" \
158 " sub " RSEQ_ASM_TMP_REG ", " RSEQ_ASM_TMP_REG \
159 ", %[" __rseq_str(expect) "]\n" \
160 " cbnz " RSEQ_ASM_TMP_REG ", " __rseq_str(label) "\n"
161
162 #define RSEQ_ASM_OP_CMPEQ32(var, expect, label) \
163 " ldr " RSEQ_ASM_TMP_REG32 ", %[" __rseq_str(var) "]\n" \
164 " sub " RSEQ_ASM_TMP_REG32 ", " RSEQ_ASM_TMP_REG32 \
165 ", %w[" __rseq_str(expect) "]\n" \
166 " cbnz " RSEQ_ASM_TMP_REG32 ", " __rseq_str(label) "\n"
167
168 #define RSEQ_ASM_OP_CMPNE(var, expect, label) \
169 " ldr " RSEQ_ASM_TMP_REG ", %[" __rseq_str(var) "]\n" \
170 " sub " RSEQ_ASM_TMP_REG ", " RSEQ_ASM_TMP_REG \
171 ", %[" __rseq_str(expect) "]\n" \
172 " cbz " RSEQ_ASM_TMP_REG ", " __rseq_str(label) "\n"
173
174 #define RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, label) \
175 RSEQ_INJECT_ASM(2) \
176 RSEQ_ASM_OP_CMPEQ32(current_cpu_id, cpu_id, label)
177
178 #define RSEQ_ASM_OP_R_LOAD(var) \
179 " ldr " RSEQ_ASM_TMP_REG ", %[" __rseq_str(var) "]\n"
180
181 #define RSEQ_ASM_OP_R_STORE(var) \
182 " str " RSEQ_ASM_TMP_REG ", %[" __rseq_str(var) "]\n"
183
184 #define RSEQ_ASM_OP_R_LOAD_OFF(offset) \
185 " ldr " RSEQ_ASM_TMP_REG ", [" RSEQ_ASM_TMP_REG \
186 ", %[" __rseq_str(offset) "]]\n"
187
188 #define RSEQ_ASM_OP_R_ADD(count) \
189 " add " RSEQ_ASM_TMP_REG ", " RSEQ_ASM_TMP_REG \
190 ", %[" __rseq_str(count) "]\n"
191
192 #define RSEQ_ASM_OP_R_FINAL_STORE(var, post_commit_label) \
193 " str " RSEQ_ASM_TMP_REG ", %[" __rseq_str(var) "]\n" \
194 __rseq_str(post_commit_label) ":\n"
195
196 #define RSEQ_ASM_OP_R_BAD_MEMCPY(dst, src, len) \
197 " cbz %[" __rseq_str(len) "], 333f\n" \
198 " mov " RSEQ_ASM_TMP_REG_2 ", %[" __rseq_str(len) "]\n" \
199 "222: sub " RSEQ_ASM_TMP_REG_2 ", " RSEQ_ASM_TMP_REG_2 ", #1\n" \
200 " ldrb " RSEQ_ASM_TMP_REG32 ", [%[" __rseq_str(src) "]" \
201 ", " RSEQ_ASM_TMP_REG_2 "]\n" \
202 " strb " RSEQ_ASM_TMP_REG32 ", [%[" __rseq_str(dst) "]" \
203 ", " RSEQ_ASM_TMP_REG_2 "]\n" \
204 " cbnz " RSEQ_ASM_TMP_REG_2 ", 222b\n" \
205 "333:\n"
206
207 static inline __attribute__((always_inline))
rseq_cmpeqv_storev(intptr_t * v,intptr_t expect,intptr_t newv,int cpu)208 int rseq_cmpeqv_storev(intptr_t *v, intptr_t expect, intptr_t newv, int cpu)
209 {
210 RSEQ_INJECT_C(9)
211
212 __asm__ __volatile__ goto (
213 RSEQ_ASM_DEFINE_TABLE(1, 2f, 3f, 4f)
214 RSEQ_ASM_DEFINE_EXIT_POINT(2f, %l[cmpfail])
215 #ifdef RSEQ_COMPARE_TWICE
216 RSEQ_ASM_DEFINE_EXIT_POINT(2f, %l[error1])
217 RSEQ_ASM_DEFINE_EXIT_POINT(2f, %l[error2])
218 #endif
219 RSEQ_ASM_STORE_RSEQ_CS(2, 1b, rseq_cs)
220 RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f)
221 RSEQ_INJECT_ASM(3)
222 RSEQ_ASM_OP_CMPEQ(v, expect, %l[cmpfail])
223 RSEQ_INJECT_ASM(4)
224 #ifdef RSEQ_COMPARE_TWICE
225 RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1])
226 RSEQ_ASM_OP_CMPEQ(v, expect, %l[error2])
227 #endif
228 RSEQ_ASM_OP_FINAL_STORE(newv, v, 3)
229 RSEQ_INJECT_ASM(5)
230 RSEQ_ASM_DEFINE_ABORT(4, abort)
231 : /* gcc asm goto does not allow outputs */
232 : [cpu_id] "r" (cpu),
233 [current_cpu_id] "Qo" (__rseq_abi.cpu_id),
234 [rseq_cs] "m" (__rseq_abi.rseq_cs),
235 [v] "Qo" (*v),
236 [expect] "r" (expect),
237 [newv] "r" (newv)
238 RSEQ_INJECT_INPUT
239 : "memory", RSEQ_ASM_TMP_REG
240 : abort, cmpfail
241 #ifdef RSEQ_COMPARE_TWICE
242 , error1, error2
243 #endif
244 );
245
246 return 0;
247 abort:
248 RSEQ_INJECT_FAILED
249 return -1;
250 cmpfail:
251 return 1;
252 #ifdef RSEQ_COMPARE_TWICE
253 error1:
254 rseq_bug("cpu_id comparison failed");
255 error2:
256 rseq_bug("expected value comparison failed");
257 #endif
258 }
259
260 static inline __attribute__((always_inline))
rseq_cmpnev_storeoffp_load(intptr_t * v,intptr_t expectnot,off_t voffp,intptr_t * load,int cpu)261 int rseq_cmpnev_storeoffp_load(intptr_t *v, intptr_t expectnot,
262 off_t voffp, intptr_t *load, int cpu)
263 {
264 RSEQ_INJECT_C(9)
265
266 __asm__ __volatile__ goto (
267 RSEQ_ASM_DEFINE_TABLE(1, 2f, 3f, 4f)
268 RSEQ_ASM_DEFINE_EXIT_POINT(2f, %l[cmpfail])
269 #ifdef RSEQ_COMPARE_TWICE
270 RSEQ_ASM_DEFINE_EXIT_POINT(2f, %l[error1])
271 RSEQ_ASM_DEFINE_EXIT_POINT(2f, %l[error2])
272 #endif
273 RSEQ_ASM_STORE_RSEQ_CS(2, 1b, rseq_cs)
274 RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f)
275 RSEQ_INJECT_ASM(3)
276 RSEQ_ASM_OP_CMPNE(v, expectnot, %l[cmpfail])
277 RSEQ_INJECT_ASM(4)
278 #ifdef RSEQ_COMPARE_TWICE
279 RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1])
280 RSEQ_ASM_OP_CMPNE(v, expectnot, %l[error2])
281 #endif
282 RSEQ_ASM_OP_R_LOAD(v)
283 RSEQ_ASM_OP_R_STORE(load)
284 RSEQ_ASM_OP_R_LOAD_OFF(voffp)
285 RSEQ_ASM_OP_R_FINAL_STORE(v, 3)
286 RSEQ_INJECT_ASM(5)
287 RSEQ_ASM_DEFINE_ABORT(4, abort)
288 : /* gcc asm goto does not allow outputs */
289 : [cpu_id] "r" (cpu),
290 [current_cpu_id] "Qo" (__rseq_abi.cpu_id),
291 [rseq_cs] "m" (__rseq_abi.rseq_cs),
292 [v] "Qo" (*v),
293 [expectnot] "r" (expectnot),
294 [load] "Qo" (*load),
295 [voffp] "r" (voffp)
296 RSEQ_INJECT_INPUT
297 : "memory", RSEQ_ASM_TMP_REG
298 : abort, cmpfail
299 #ifdef RSEQ_COMPARE_TWICE
300 , error1, error2
301 #endif
302 );
303 return 0;
304 abort:
305 RSEQ_INJECT_FAILED
306 return -1;
307 cmpfail:
308 return 1;
309 #ifdef RSEQ_COMPARE_TWICE
310 error1:
311 rseq_bug("cpu_id comparison failed");
312 error2:
313 rseq_bug("expected value comparison failed");
314 #endif
315 }
316
317 static inline __attribute__((always_inline))
rseq_addv(intptr_t * v,intptr_t count,int cpu)318 int rseq_addv(intptr_t *v, intptr_t count, int cpu)
319 {
320 RSEQ_INJECT_C(9)
321
322 __asm__ __volatile__ goto (
323 RSEQ_ASM_DEFINE_TABLE(1, 2f, 3f, 4f)
324 #ifdef RSEQ_COMPARE_TWICE
325 RSEQ_ASM_DEFINE_EXIT_POINT(2f, %l[error1])
326 #endif
327 RSEQ_ASM_STORE_RSEQ_CS(2, 1b, rseq_cs)
328 RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f)
329 RSEQ_INJECT_ASM(3)
330 #ifdef RSEQ_COMPARE_TWICE
331 RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1])
332 #endif
333 RSEQ_ASM_OP_R_LOAD(v)
334 RSEQ_ASM_OP_R_ADD(count)
335 RSEQ_ASM_OP_R_FINAL_STORE(v, 3)
336 RSEQ_INJECT_ASM(4)
337 RSEQ_ASM_DEFINE_ABORT(4, abort)
338 : /* gcc asm goto does not allow outputs */
339 : [cpu_id] "r" (cpu),
340 [current_cpu_id] "Qo" (__rseq_abi.cpu_id),
341 [rseq_cs] "m" (__rseq_abi.rseq_cs),
342 [v] "Qo" (*v),
343 [count] "r" (count)
344 RSEQ_INJECT_INPUT
345 : "memory", RSEQ_ASM_TMP_REG
346 : abort
347 #ifdef RSEQ_COMPARE_TWICE
348 , error1
349 #endif
350 );
351 return 0;
352 abort:
353 RSEQ_INJECT_FAILED
354 return -1;
355 #ifdef RSEQ_COMPARE_TWICE
356 error1:
357 rseq_bug("cpu_id comparison failed");
358 #endif
359 }
360
361 static inline __attribute__((always_inline))
rseq_cmpeqv_trystorev_storev(intptr_t * v,intptr_t expect,intptr_t * v2,intptr_t newv2,intptr_t newv,int cpu)362 int rseq_cmpeqv_trystorev_storev(intptr_t *v, intptr_t expect,
363 intptr_t *v2, intptr_t newv2,
364 intptr_t newv, int cpu)
365 {
366 RSEQ_INJECT_C(9)
367
368 __asm__ __volatile__ goto (
369 RSEQ_ASM_DEFINE_TABLE(1, 2f, 3f, 4f)
370 RSEQ_ASM_DEFINE_EXIT_POINT(2f, %l[cmpfail])
371 #ifdef RSEQ_COMPARE_TWICE
372 RSEQ_ASM_DEFINE_EXIT_POINT(2f, %l[error1])
373 RSEQ_ASM_DEFINE_EXIT_POINT(2f, %l[error2])
374 #endif
375 RSEQ_ASM_STORE_RSEQ_CS(2, 1b, rseq_cs)
376 RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f)
377 RSEQ_INJECT_ASM(3)
378 RSEQ_ASM_OP_CMPEQ(v, expect, %l[cmpfail])
379 RSEQ_INJECT_ASM(4)
380 #ifdef RSEQ_COMPARE_TWICE
381 RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1])
382 RSEQ_ASM_OP_CMPEQ(v, expect, %l[error2])
383 #endif
384 RSEQ_ASM_OP_STORE(newv2, v2)
385 RSEQ_INJECT_ASM(5)
386 RSEQ_ASM_OP_FINAL_STORE(newv, v, 3)
387 RSEQ_INJECT_ASM(6)
388 RSEQ_ASM_DEFINE_ABORT(4, abort)
389 : /* gcc asm goto does not allow outputs */
390 : [cpu_id] "r" (cpu),
391 [current_cpu_id] "Qo" (__rseq_abi.cpu_id),
392 [rseq_cs] "m" (__rseq_abi.rseq_cs),
393 [expect] "r" (expect),
394 [v] "Qo" (*v),
395 [newv] "r" (newv),
396 [v2] "Qo" (*v2),
397 [newv2] "r" (newv2)
398 RSEQ_INJECT_INPUT
399 : "memory", RSEQ_ASM_TMP_REG
400 : abort, cmpfail
401 #ifdef RSEQ_COMPARE_TWICE
402 , error1, error2
403 #endif
404 );
405
406 return 0;
407 abort:
408 RSEQ_INJECT_FAILED
409 return -1;
410 cmpfail:
411 return 1;
412 #ifdef RSEQ_COMPARE_TWICE
413 error1:
414 rseq_bug("cpu_id comparison failed");
415 error2:
416 rseq_bug("expected value comparison failed");
417 #endif
418 }
419
420 static inline __attribute__((always_inline))
rseq_cmpeqv_trystorev_storev_release(intptr_t * v,intptr_t expect,intptr_t * v2,intptr_t newv2,intptr_t newv,int cpu)421 int rseq_cmpeqv_trystorev_storev_release(intptr_t *v, intptr_t expect,
422 intptr_t *v2, intptr_t newv2,
423 intptr_t newv, int cpu)
424 {
425 RSEQ_INJECT_C(9)
426
427 __asm__ __volatile__ goto (
428 RSEQ_ASM_DEFINE_TABLE(1, 2f, 3f, 4f)
429 RSEQ_ASM_DEFINE_EXIT_POINT(2f, %l[cmpfail])
430 #ifdef RSEQ_COMPARE_TWICE
431 RSEQ_ASM_DEFINE_EXIT_POINT(2f, %l[error1])
432 RSEQ_ASM_DEFINE_EXIT_POINT(2f, %l[error2])
433 #endif
434 RSEQ_ASM_STORE_RSEQ_CS(2, 1b, rseq_cs)
435 RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f)
436 RSEQ_INJECT_ASM(3)
437 RSEQ_ASM_OP_CMPEQ(v, expect, %l[cmpfail])
438 RSEQ_INJECT_ASM(4)
439 #ifdef RSEQ_COMPARE_TWICE
440 RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1])
441 RSEQ_ASM_OP_CMPEQ(v, expect, %l[error2])
442 #endif
443 RSEQ_ASM_OP_STORE(newv2, v2)
444 RSEQ_INJECT_ASM(5)
445 RSEQ_ASM_OP_FINAL_STORE_RELEASE(newv, v, 3)
446 RSEQ_INJECT_ASM(6)
447 RSEQ_ASM_DEFINE_ABORT(4, abort)
448 : /* gcc asm goto does not allow outputs */
449 : [cpu_id] "r" (cpu),
450 [current_cpu_id] "Qo" (__rseq_abi.cpu_id),
451 [rseq_cs] "m" (__rseq_abi.rseq_cs),
452 [expect] "r" (expect),
453 [v] "Qo" (*v),
454 [newv] "r" (newv),
455 [v2] "Qo" (*v2),
456 [newv2] "r" (newv2)
457 RSEQ_INJECT_INPUT
458 : "memory", RSEQ_ASM_TMP_REG
459 : abort, cmpfail
460 #ifdef RSEQ_COMPARE_TWICE
461 , error1, error2
462 #endif
463 );
464
465 return 0;
466 abort:
467 RSEQ_INJECT_FAILED
468 return -1;
469 cmpfail:
470 return 1;
471 #ifdef RSEQ_COMPARE_TWICE
472 error1:
473 rseq_bug("cpu_id comparison failed");
474 error2:
475 rseq_bug("expected value comparison failed");
476 #endif
477 }
478
479 static inline __attribute__((always_inline))
rseq_cmpeqv_cmpeqv_storev(intptr_t * v,intptr_t expect,intptr_t * v2,intptr_t expect2,intptr_t newv,int cpu)480 int rseq_cmpeqv_cmpeqv_storev(intptr_t *v, intptr_t expect,
481 intptr_t *v2, intptr_t expect2,
482 intptr_t newv, int cpu)
483 {
484 RSEQ_INJECT_C(9)
485
486 __asm__ __volatile__ goto (
487 RSEQ_ASM_DEFINE_TABLE(1, 2f, 3f, 4f)
488 RSEQ_ASM_DEFINE_EXIT_POINT(2f, %l[cmpfail])
489 #ifdef RSEQ_COMPARE_TWICE
490 RSEQ_ASM_DEFINE_EXIT_POINT(2f, %l[error1])
491 RSEQ_ASM_DEFINE_EXIT_POINT(2f, %l[error2])
492 RSEQ_ASM_DEFINE_EXIT_POINT(2f, %l[error3])
493 #endif
494 RSEQ_ASM_STORE_RSEQ_CS(2, 1b, rseq_cs)
495 RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f)
496 RSEQ_INJECT_ASM(3)
497 RSEQ_ASM_OP_CMPEQ(v, expect, %l[cmpfail])
498 RSEQ_INJECT_ASM(4)
499 RSEQ_ASM_OP_CMPEQ(v2, expect2, %l[cmpfail])
500 RSEQ_INJECT_ASM(5)
501 #ifdef RSEQ_COMPARE_TWICE
502 RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1])
503 RSEQ_ASM_OP_CMPEQ(v, expect, %l[error2])
504 RSEQ_ASM_OP_CMPEQ(v2, expect2, %l[error3])
505 #endif
506 RSEQ_ASM_OP_FINAL_STORE(newv, v, 3)
507 RSEQ_INJECT_ASM(6)
508 RSEQ_ASM_DEFINE_ABORT(4, abort)
509 : /* gcc asm goto does not allow outputs */
510 : [cpu_id] "r" (cpu),
511 [current_cpu_id] "Qo" (__rseq_abi.cpu_id),
512 [rseq_cs] "m" (__rseq_abi.rseq_cs),
513 [v] "Qo" (*v),
514 [expect] "r" (expect),
515 [v2] "Qo" (*v2),
516 [expect2] "r" (expect2),
517 [newv] "r" (newv)
518 RSEQ_INJECT_INPUT
519 : "memory", RSEQ_ASM_TMP_REG
520 : abort, cmpfail
521 #ifdef RSEQ_COMPARE_TWICE
522 , error1, error2, error3
523 #endif
524 );
525
526 return 0;
527 abort:
528 RSEQ_INJECT_FAILED
529 return -1;
530 cmpfail:
531 return 1;
532 #ifdef RSEQ_COMPARE_TWICE
533 error1:
534 rseq_bug("cpu_id comparison failed");
535 error2:
536 rseq_bug("expected value comparison failed");
537 error3:
538 rseq_bug("2nd expected value comparison failed");
539 #endif
540 }
541
542 static inline __attribute__((always_inline))
rseq_cmpeqv_trymemcpy_storev(intptr_t * v,intptr_t expect,void * dst,void * src,size_t len,intptr_t newv,int cpu)543 int rseq_cmpeqv_trymemcpy_storev(intptr_t *v, intptr_t expect,
544 void *dst, void *src, size_t len,
545 intptr_t newv, int cpu)
546 {
547 RSEQ_INJECT_C(9)
548
549 __asm__ __volatile__ goto (
550 RSEQ_ASM_DEFINE_TABLE(1, 2f, 3f, 4f)
551 RSEQ_ASM_DEFINE_EXIT_POINT(2f, %l[cmpfail])
552 #ifdef RSEQ_COMPARE_TWICE
553 RSEQ_ASM_DEFINE_EXIT_POINT(2f, %l[error1])
554 RSEQ_ASM_DEFINE_EXIT_POINT(2f, %l[error2])
555 #endif
556 RSEQ_ASM_STORE_RSEQ_CS(2, 1b, rseq_cs)
557 RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f)
558 RSEQ_INJECT_ASM(3)
559 RSEQ_ASM_OP_CMPEQ(v, expect, %l[cmpfail])
560 RSEQ_INJECT_ASM(4)
561 #ifdef RSEQ_COMPARE_TWICE
562 RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1])
563 RSEQ_ASM_OP_CMPEQ(v, expect, %l[error2])
564 #endif
565 RSEQ_ASM_OP_R_BAD_MEMCPY(dst, src, len)
566 RSEQ_INJECT_ASM(5)
567 RSEQ_ASM_OP_FINAL_STORE(newv, v, 3)
568 RSEQ_INJECT_ASM(6)
569 RSEQ_ASM_DEFINE_ABORT(4, abort)
570 : /* gcc asm goto does not allow outputs */
571 : [cpu_id] "r" (cpu),
572 [current_cpu_id] "Qo" (__rseq_abi.cpu_id),
573 [rseq_cs] "m" (__rseq_abi.rseq_cs),
574 [expect] "r" (expect),
575 [v] "Qo" (*v),
576 [newv] "r" (newv),
577 [dst] "r" (dst),
578 [src] "r" (src),
579 [len] "r" (len)
580 RSEQ_INJECT_INPUT
581 : "memory", RSEQ_ASM_TMP_REG, RSEQ_ASM_TMP_REG_2
582 : abort, cmpfail
583 #ifdef RSEQ_COMPARE_TWICE
584 , error1, error2
585 #endif
586 );
587
588 return 0;
589 abort:
590 RSEQ_INJECT_FAILED
591 return -1;
592 cmpfail:
593 return 1;
594 #ifdef RSEQ_COMPARE_TWICE
595 error1:
596 rseq_bug("cpu_id comparison failed");
597 error2:
598 rseq_bug("expected value comparison failed");
599 #endif
600 }
601
602 static inline __attribute__((always_inline))
rseq_cmpeqv_trymemcpy_storev_release(intptr_t * v,intptr_t expect,void * dst,void * src,size_t len,intptr_t newv,int cpu)603 int rseq_cmpeqv_trymemcpy_storev_release(intptr_t *v, intptr_t expect,
604 void *dst, void *src, size_t len,
605 intptr_t newv, int cpu)
606 {
607 RSEQ_INJECT_C(9)
608
609 __asm__ __volatile__ goto (
610 RSEQ_ASM_DEFINE_TABLE(1, 2f, 3f, 4f)
611 RSEQ_ASM_DEFINE_EXIT_POINT(2f, %l[cmpfail])
612 #ifdef RSEQ_COMPARE_TWICE
613 RSEQ_ASM_DEFINE_EXIT_POINT(2f, %l[error1])
614 RSEQ_ASM_DEFINE_EXIT_POINT(2f, %l[error2])
615 #endif
616 RSEQ_ASM_STORE_RSEQ_CS(2, 1b, rseq_cs)
617 RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f)
618 RSEQ_INJECT_ASM(3)
619 RSEQ_ASM_OP_CMPEQ(v, expect, %l[cmpfail])
620 RSEQ_INJECT_ASM(4)
621 #ifdef RSEQ_COMPARE_TWICE
622 RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1])
623 RSEQ_ASM_OP_CMPEQ(v, expect, %l[error2])
624 #endif
625 RSEQ_ASM_OP_R_BAD_MEMCPY(dst, src, len)
626 RSEQ_INJECT_ASM(5)
627 RSEQ_ASM_OP_FINAL_STORE_RELEASE(newv, v, 3)
628 RSEQ_INJECT_ASM(6)
629 RSEQ_ASM_DEFINE_ABORT(4, abort)
630 : /* gcc asm goto does not allow outputs */
631 : [cpu_id] "r" (cpu),
632 [current_cpu_id] "Qo" (__rseq_abi.cpu_id),
633 [rseq_cs] "m" (__rseq_abi.rseq_cs),
634 [expect] "r" (expect),
635 [v] "Qo" (*v),
636 [newv] "r" (newv),
637 [dst] "r" (dst),
638 [src] "r" (src),
639 [len] "r" (len)
640 RSEQ_INJECT_INPUT
641 : "memory", RSEQ_ASM_TMP_REG, RSEQ_ASM_TMP_REG_2
642 : abort, cmpfail
643 #ifdef RSEQ_COMPARE_TWICE
644 , error1, error2
645 #endif
646 );
647
648 return 0;
649 abort:
650 RSEQ_INJECT_FAILED
651 return -1;
652 cmpfail:
653 return 1;
654 #ifdef RSEQ_COMPARE_TWICE
655 error1:
656 rseq_bug("cpu_id comparison failed");
657 error2:
658 rseq_bug("expected value comparison failed");
659 #endif
660 }
661
662 #endif /* !RSEQ_SKIP_FASTPATH */
663