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