1*4882a593Smuzhiyun /* SPDX-License-Identifier: LGPL-2.1 OR MIT */
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * rseq-ppc.h
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * (C) Copyright 2016-2018 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
6*4882a593Smuzhiyun * (C) Copyright 2016-2018 - Boqun Feng <boqun.feng@gmail.com>
7*4882a593Smuzhiyun */
8*4882a593Smuzhiyun
9*4882a593Smuzhiyun /*
10*4882a593Smuzhiyun * RSEQ_SIG is used with the following trap instruction:
11*4882a593Smuzhiyun *
12*4882a593Smuzhiyun * powerpc-be: 0f e5 00 0b twui r5,11
13*4882a593Smuzhiyun * powerpc64-le: 0b 00 e5 0f twui r5,11
14*4882a593Smuzhiyun * powerpc64-be: 0f e5 00 0b twui r5,11
15*4882a593Smuzhiyun */
16*4882a593Smuzhiyun
17*4882a593Smuzhiyun #define RSEQ_SIG 0x0fe5000b
18*4882a593Smuzhiyun
19*4882a593Smuzhiyun #define rseq_smp_mb() __asm__ __volatile__ ("sync" ::: "memory", "cc")
20*4882a593Smuzhiyun #define rseq_smp_lwsync() __asm__ __volatile__ ("lwsync" ::: "memory", "cc")
21*4882a593Smuzhiyun #define rseq_smp_rmb() rseq_smp_lwsync()
22*4882a593Smuzhiyun #define rseq_smp_wmb() rseq_smp_lwsync()
23*4882a593Smuzhiyun
24*4882a593Smuzhiyun #define rseq_smp_load_acquire(p) \
25*4882a593Smuzhiyun __extension__ ({ \
26*4882a593Smuzhiyun __typeof(*p) ____p1 = RSEQ_READ_ONCE(*p); \
27*4882a593Smuzhiyun rseq_smp_lwsync(); \
28*4882a593Smuzhiyun ____p1; \
29*4882a593Smuzhiyun })
30*4882a593Smuzhiyun
31*4882a593Smuzhiyun #define rseq_smp_acquire__after_ctrl_dep() rseq_smp_lwsync()
32*4882a593Smuzhiyun
33*4882a593Smuzhiyun #define rseq_smp_store_release(p, v) \
34*4882a593Smuzhiyun do { \
35*4882a593Smuzhiyun rseq_smp_lwsync(); \
36*4882a593Smuzhiyun RSEQ_WRITE_ONCE(*p, v); \
37*4882a593Smuzhiyun } while (0)
38*4882a593Smuzhiyun
39*4882a593Smuzhiyun #ifdef RSEQ_SKIP_FASTPATH
40*4882a593Smuzhiyun #include "rseq-skip.h"
41*4882a593Smuzhiyun #else /* !RSEQ_SKIP_FASTPATH */
42*4882a593Smuzhiyun
43*4882a593Smuzhiyun /*
44*4882a593Smuzhiyun * The __rseq_cs_ptr_array and __rseq_cs sections can be used by debuggers to
45*4882a593Smuzhiyun * better handle single-stepping through the restartable critical sections.
46*4882a593Smuzhiyun */
47*4882a593Smuzhiyun
48*4882a593Smuzhiyun #ifdef __PPC64__
49*4882a593Smuzhiyun
50*4882a593Smuzhiyun #define RSEQ_STORE_LONG(arg) "std%U[" __rseq_str(arg) "]%X[" __rseq_str(arg) "] " /* To memory ("m" constraint) */
51*4882a593Smuzhiyun #define RSEQ_STORE_INT(arg) "stw%U[" __rseq_str(arg) "]%X[" __rseq_str(arg) "] " /* To memory ("m" constraint) */
52*4882a593Smuzhiyun #define RSEQ_LOAD_LONG(arg) "ld%U[" __rseq_str(arg) "]%X[" __rseq_str(arg) "] " /* From memory ("m" constraint) */
53*4882a593Smuzhiyun #define RSEQ_LOAD_INT(arg) "lwz%U[" __rseq_str(arg) "]%X[" __rseq_str(arg) "] " /* From memory ("m" constraint) */
54*4882a593Smuzhiyun #define RSEQ_LOADX_LONG "ldx " /* From base register ("b" constraint) */
55*4882a593Smuzhiyun #define RSEQ_CMP_LONG "cmpd "
56*4882a593Smuzhiyun #define RSEQ_CMP_LONG_INT "cmpdi "
57*4882a593Smuzhiyun
58*4882a593Smuzhiyun #define __RSEQ_ASM_DEFINE_TABLE(label, version, flags, \
59*4882a593Smuzhiyun start_ip, post_commit_offset, abort_ip) \
60*4882a593Smuzhiyun ".pushsection __rseq_cs, \"aw\"\n\t" \
61*4882a593Smuzhiyun ".balign 32\n\t" \
62*4882a593Smuzhiyun __rseq_str(label) ":\n\t" \
63*4882a593Smuzhiyun ".long " __rseq_str(version) ", " __rseq_str(flags) "\n\t" \
64*4882a593Smuzhiyun ".quad " __rseq_str(start_ip) ", " __rseq_str(post_commit_offset) ", " __rseq_str(abort_ip) "\n\t" \
65*4882a593Smuzhiyun ".popsection\n\t" \
66*4882a593Smuzhiyun ".pushsection __rseq_cs_ptr_array, \"aw\"\n\t" \
67*4882a593Smuzhiyun ".quad " __rseq_str(label) "b\n\t" \
68*4882a593Smuzhiyun ".popsection\n\t"
69*4882a593Smuzhiyun
70*4882a593Smuzhiyun #define RSEQ_ASM_STORE_RSEQ_CS(label, cs_label, rseq_cs) \
71*4882a593Smuzhiyun RSEQ_INJECT_ASM(1) \
72*4882a593Smuzhiyun "lis %%r17, (" __rseq_str(cs_label) ")@highest\n\t" \
73*4882a593Smuzhiyun "ori %%r17, %%r17, (" __rseq_str(cs_label) ")@higher\n\t" \
74*4882a593Smuzhiyun "rldicr %%r17, %%r17, 32, 31\n\t" \
75*4882a593Smuzhiyun "oris %%r17, %%r17, (" __rseq_str(cs_label) ")@high\n\t" \
76*4882a593Smuzhiyun "ori %%r17, %%r17, (" __rseq_str(cs_label) ")@l\n\t" \
77*4882a593Smuzhiyun "std %%r17, %[" __rseq_str(rseq_cs) "]\n\t" \
78*4882a593Smuzhiyun __rseq_str(label) ":\n\t"
79*4882a593Smuzhiyun
80*4882a593Smuzhiyun /*
81*4882a593Smuzhiyun * Exit points of a rseq critical section consist of all instructions outside
82*4882a593Smuzhiyun * of the critical section where a critical section can either branch to or
83*4882a593Smuzhiyun * reach through the normal course of its execution. The abort IP and the
84*4882a593Smuzhiyun * post-commit IP are already part of the __rseq_cs section and should not be
85*4882a593Smuzhiyun * explicitly defined as additional exit points. Knowing all exit points is
86*4882a593Smuzhiyun * useful to assist debuggers stepping over the critical section.
87*4882a593Smuzhiyun */
88*4882a593Smuzhiyun #define RSEQ_ASM_DEFINE_EXIT_POINT(start_ip, exit_ip) \
89*4882a593Smuzhiyun ".pushsection __rseq_exit_point_array, \"aw\"\n\t" \
90*4882a593Smuzhiyun ".quad " __rseq_str(start_ip) ", " __rseq_str(exit_ip) "\n\t" \
91*4882a593Smuzhiyun ".popsection\n\t"
92*4882a593Smuzhiyun
93*4882a593Smuzhiyun #else /* #ifdef __PPC64__ */
94*4882a593Smuzhiyun
95*4882a593Smuzhiyun #define RSEQ_STORE_LONG(arg) "stw%U[" __rseq_str(arg) "]%X[" __rseq_str(arg) "] " /* To memory ("m" constraint) */
96*4882a593Smuzhiyun #define RSEQ_STORE_INT(arg) RSEQ_STORE_LONG(arg) /* To memory ("m" constraint) */
97*4882a593Smuzhiyun #define RSEQ_LOAD_LONG(arg) "lwz%U[" __rseq_str(arg) "]%X[" __rseq_str(arg) "] " /* From memory ("m" constraint) */
98*4882a593Smuzhiyun #define RSEQ_LOAD_INT(arg) RSEQ_LOAD_LONG(arg) /* From memory ("m" constraint) */
99*4882a593Smuzhiyun #define RSEQ_LOADX_LONG "lwzx " /* From base register ("b" constraint) */
100*4882a593Smuzhiyun #define RSEQ_CMP_LONG "cmpw "
101*4882a593Smuzhiyun #define RSEQ_CMP_LONG_INT "cmpwi "
102*4882a593Smuzhiyun
103*4882a593Smuzhiyun #define __RSEQ_ASM_DEFINE_TABLE(label, version, flags, \
104*4882a593Smuzhiyun start_ip, post_commit_offset, abort_ip) \
105*4882a593Smuzhiyun ".pushsection __rseq_cs, \"aw\"\n\t" \
106*4882a593Smuzhiyun ".balign 32\n\t" \
107*4882a593Smuzhiyun __rseq_str(label) ":\n\t" \
108*4882a593Smuzhiyun ".long " __rseq_str(version) ", " __rseq_str(flags) "\n\t" \
109*4882a593Smuzhiyun /* 32-bit only supported on BE */ \
110*4882a593Smuzhiyun ".long 0x0, " __rseq_str(start_ip) ", 0x0, " __rseq_str(post_commit_offset) ", 0x0, " __rseq_str(abort_ip) "\n\t" \
111*4882a593Smuzhiyun ".popsection\n\t" \
112*4882a593Smuzhiyun ".pushsection __rseq_cs_ptr_array, \"aw\"\n\t" \
113*4882a593Smuzhiyun ".long 0x0, " __rseq_str(label) "b\n\t" \
114*4882a593Smuzhiyun ".popsection\n\t"
115*4882a593Smuzhiyun
116*4882a593Smuzhiyun /*
117*4882a593Smuzhiyun * Exit points of a rseq critical section consist of all instructions outside
118*4882a593Smuzhiyun * of the critical section where a critical section can either branch to or
119*4882a593Smuzhiyun * reach through the normal course of its execution. The abort IP and the
120*4882a593Smuzhiyun * post-commit IP are already part of the __rseq_cs section and should not be
121*4882a593Smuzhiyun * explicitly defined as additional exit points. Knowing all exit points is
122*4882a593Smuzhiyun * useful to assist debuggers stepping over the critical section.
123*4882a593Smuzhiyun */
124*4882a593Smuzhiyun #define RSEQ_ASM_DEFINE_EXIT_POINT(start_ip, exit_ip) \
125*4882a593Smuzhiyun ".pushsection __rseq_exit_point_array, \"aw\"\n\t" \
126*4882a593Smuzhiyun /* 32-bit only supported on BE */ \
127*4882a593Smuzhiyun ".long 0x0, " __rseq_str(start_ip) ", 0x0, " __rseq_str(exit_ip) "\n\t" \
128*4882a593Smuzhiyun ".popsection\n\t"
129*4882a593Smuzhiyun
130*4882a593Smuzhiyun #define RSEQ_ASM_STORE_RSEQ_CS(label, cs_label, rseq_cs) \
131*4882a593Smuzhiyun RSEQ_INJECT_ASM(1) \
132*4882a593Smuzhiyun "lis %%r17, (" __rseq_str(cs_label) ")@ha\n\t" \
133*4882a593Smuzhiyun "addi %%r17, %%r17, (" __rseq_str(cs_label) ")@l\n\t" \
134*4882a593Smuzhiyun RSEQ_STORE_INT(rseq_cs) "%%r17, %[" __rseq_str(rseq_cs) "]\n\t" \
135*4882a593Smuzhiyun __rseq_str(label) ":\n\t"
136*4882a593Smuzhiyun
137*4882a593Smuzhiyun #endif /* #ifdef __PPC64__ */
138*4882a593Smuzhiyun
139*4882a593Smuzhiyun #define RSEQ_ASM_DEFINE_TABLE(label, start_ip, post_commit_ip, abort_ip) \
140*4882a593Smuzhiyun __RSEQ_ASM_DEFINE_TABLE(label, 0x0, 0x0, start_ip, \
141*4882a593Smuzhiyun (post_commit_ip - start_ip), abort_ip)
142*4882a593Smuzhiyun
143*4882a593Smuzhiyun #define RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, label) \
144*4882a593Smuzhiyun RSEQ_INJECT_ASM(2) \
145*4882a593Smuzhiyun RSEQ_LOAD_INT(current_cpu_id) "%%r17, %[" __rseq_str(current_cpu_id) "]\n\t" \
146*4882a593Smuzhiyun "cmpw cr7, %[" __rseq_str(cpu_id) "], %%r17\n\t" \
147*4882a593Smuzhiyun "bne- cr7, " __rseq_str(label) "\n\t"
148*4882a593Smuzhiyun
149*4882a593Smuzhiyun #define RSEQ_ASM_DEFINE_ABORT(label, abort_label) \
150*4882a593Smuzhiyun ".pushsection __rseq_failure, \"ax\"\n\t" \
151*4882a593Smuzhiyun ".long " __rseq_str(RSEQ_SIG) "\n\t" \
152*4882a593Smuzhiyun __rseq_str(label) ":\n\t" \
153*4882a593Smuzhiyun "b %l[" __rseq_str(abort_label) "]\n\t" \
154*4882a593Smuzhiyun ".popsection\n\t"
155*4882a593Smuzhiyun
156*4882a593Smuzhiyun /*
157*4882a593Smuzhiyun * RSEQ_ASM_OPs: asm operations for rseq
158*4882a593Smuzhiyun * RSEQ_ASM_OP_R_*: has hard-code registers in it
159*4882a593Smuzhiyun * RSEQ_ASM_OP_* (else): doesn't have hard-code registers(unless cr7)
160*4882a593Smuzhiyun */
161*4882a593Smuzhiyun #define RSEQ_ASM_OP_CMPEQ(var, expect, label) \
162*4882a593Smuzhiyun RSEQ_LOAD_LONG(var) "%%r17, %[" __rseq_str(var) "]\n\t" \
163*4882a593Smuzhiyun RSEQ_CMP_LONG "cr7, %%r17, %[" __rseq_str(expect) "]\n\t" \
164*4882a593Smuzhiyun "bne- cr7, " __rseq_str(label) "\n\t"
165*4882a593Smuzhiyun
166*4882a593Smuzhiyun #define RSEQ_ASM_OP_CMPNE(var, expectnot, label) \
167*4882a593Smuzhiyun RSEQ_LOAD_LONG(var) "%%r17, %[" __rseq_str(var) "]\n\t" \
168*4882a593Smuzhiyun RSEQ_CMP_LONG "cr7, %%r17, %[" __rseq_str(expectnot) "]\n\t" \
169*4882a593Smuzhiyun "beq- cr7, " __rseq_str(label) "\n\t"
170*4882a593Smuzhiyun
171*4882a593Smuzhiyun #define RSEQ_ASM_OP_STORE(value, var) \
172*4882a593Smuzhiyun RSEQ_STORE_LONG(var) "%[" __rseq_str(value) "], %[" __rseq_str(var) "]\n\t"
173*4882a593Smuzhiyun
174*4882a593Smuzhiyun /* Load @var to r17 */
175*4882a593Smuzhiyun #define RSEQ_ASM_OP_R_LOAD(var) \
176*4882a593Smuzhiyun RSEQ_LOAD_LONG(var) "%%r17, %[" __rseq_str(var) "]\n\t"
177*4882a593Smuzhiyun
178*4882a593Smuzhiyun /* Store r17 to @var */
179*4882a593Smuzhiyun #define RSEQ_ASM_OP_R_STORE(var) \
180*4882a593Smuzhiyun RSEQ_STORE_LONG(var) "%%r17, %[" __rseq_str(var) "]\n\t"
181*4882a593Smuzhiyun
182*4882a593Smuzhiyun /* Add @count to r17 */
183*4882a593Smuzhiyun #define RSEQ_ASM_OP_R_ADD(count) \
184*4882a593Smuzhiyun "add %%r17, %[" __rseq_str(count) "], %%r17\n\t"
185*4882a593Smuzhiyun
186*4882a593Smuzhiyun /* Load (r17 + voffp) to r17 */
187*4882a593Smuzhiyun #define RSEQ_ASM_OP_R_LOADX(voffp) \
188*4882a593Smuzhiyun RSEQ_LOADX_LONG "%%r17, %[" __rseq_str(voffp) "], %%r17\n\t"
189*4882a593Smuzhiyun
190*4882a593Smuzhiyun /* TODO: implement a faster memcpy. */
191*4882a593Smuzhiyun #define RSEQ_ASM_OP_R_MEMCPY() \
192*4882a593Smuzhiyun RSEQ_CMP_LONG_INT "%%r19, 0\n\t" \
193*4882a593Smuzhiyun "beq 333f\n\t" \
194*4882a593Smuzhiyun "addi %%r20, %%r20, -1\n\t" \
195*4882a593Smuzhiyun "addi %%r21, %%r21, -1\n\t" \
196*4882a593Smuzhiyun "222:\n\t" \
197*4882a593Smuzhiyun "lbzu %%r18, 1(%%r20)\n\t" \
198*4882a593Smuzhiyun "stbu %%r18, 1(%%r21)\n\t" \
199*4882a593Smuzhiyun "addi %%r19, %%r19, -1\n\t" \
200*4882a593Smuzhiyun RSEQ_CMP_LONG_INT "%%r19, 0\n\t" \
201*4882a593Smuzhiyun "bne 222b\n\t" \
202*4882a593Smuzhiyun "333:\n\t" \
203*4882a593Smuzhiyun
204*4882a593Smuzhiyun #define RSEQ_ASM_OP_R_FINAL_STORE(var, post_commit_label) \
205*4882a593Smuzhiyun RSEQ_STORE_LONG(var) "%%r17, %[" __rseq_str(var) "]\n\t" \
206*4882a593Smuzhiyun __rseq_str(post_commit_label) ":\n\t"
207*4882a593Smuzhiyun
208*4882a593Smuzhiyun #define RSEQ_ASM_OP_FINAL_STORE(value, var, post_commit_label) \
209*4882a593Smuzhiyun RSEQ_STORE_LONG(var) "%[" __rseq_str(value) "], %[" __rseq_str(var) "]\n\t" \
210*4882a593Smuzhiyun __rseq_str(post_commit_label) ":\n\t"
211*4882a593Smuzhiyun
212*4882a593Smuzhiyun static inline __attribute__((always_inline))
rseq_cmpeqv_storev(intptr_t * v,intptr_t expect,intptr_t newv,int cpu)213*4882a593Smuzhiyun int rseq_cmpeqv_storev(intptr_t *v, intptr_t expect, intptr_t newv, int cpu)
214*4882a593Smuzhiyun {
215*4882a593Smuzhiyun RSEQ_INJECT_C(9)
216*4882a593Smuzhiyun
217*4882a593Smuzhiyun __asm__ __volatile__ goto (
218*4882a593Smuzhiyun RSEQ_ASM_DEFINE_TABLE(3, 1f, 2f, 4f) /* start, commit, abort */
219*4882a593Smuzhiyun RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[cmpfail])
220*4882a593Smuzhiyun #ifdef RSEQ_COMPARE_TWICE
221*4882a593Smuzhiyun RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error1])
222*4882a593Smuzhiyun RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error2])
223*4882a593Smuzhiyun #endif
224*4882a593Smuzhiyun /* Start rseq by storing table entry pointer into rseq_cs. */
225*4882a593Smuzhiyun RSEQ_ASM_STORE_RSEQ_CS(1, 3b, rseq_cs)
226*4882a593Smuzhiyun /* cmp cpuid */
227*4882a593Smuzhiyun RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f)
228*4882a593Smuzhiyun RSEQ_INJECT_ASM(3)
229*4882a593Smuzhiyun /* cmp @v equal to @expect */
230*4882a593Smuzhiyun RSEQ_ASM_OP_CMPEQ(v, expect, %l[cmpfail])
231*4882a593Smuzhiyun RSEQ_INJECT_ASM(4)
232*4882a593Smuzhiyun #ifdef RSEQ_COMPARE_TWICE
233*4882a593Smuzhiyun /* cmp cpuid */
234*4882a593Smuzhiyun RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1])
235*4882a593Smuzhiyun /* cmp @v equal to @expect */
236*4882a593Smuzhiyun RSEQ_ASM_OP_CMPEQ(v, expect, %l[error2])
237*4882a593Smuzhiyun #endif
238*4882a593Smuzhiyun /* final store */
239*4882a593Smuzhiyun RSEQ_ASM_OP_FINAL_STORE(newv, v, 2)
240*4882a593Smuzhiyun RSEQ_INJECT_ASM(5)
241*4882a593Smuzhiyun RSEQ_ASM_DEFINE_ABORT(4, abort)
242*4882a593Smuzhiyun : /* gcc asm goto does not allow outputs */
243*4882a593Smuzhiyun : [cpu_id] "r" (cpu),
244*4882a593Smuzhiyun [current_cpu_id] "m" (rseq_get_abi()->cpu_id),
245*4882a593Smuzhiyun [rseq_cs] "m" (rseq_get_abi()->rseq_cs.arch.ptr),
246*4882a593Smuzhiyun [v] "m" (*v),
247*4882a593Smuzhiyun [expect] "r" (expect),
248*4882a593Smuzhiyun [newv] "r" (newv)
249*4882a593Smuzhiyun RSEQ_INJECT_INPUT
250*4882a593Smuzhiyun : "memory", "cc", "r17"
251*4882a593Smuzhiyun RSEQ_INJECT_CLOBBER
252*4882a593Smuzhiyun : abort, cmpfail
253*4882a593Smuzhiyun #ifdef RSEQ_COMPARE_TWICE
254*4882a593Smuzhiyun , error1, error2
255*4882a593Smuzhiyun #endif
256*4882a593Smuzhiyun );
257*4882a593Smuzhiyun rseq_after_asm_goto();
258*4882a593Smuzhiyun return 0;
259*4882a593Smuzhiyun abort:
260*4882a593Smuzhiyun rseq_after_asm_goto();
261*4882a593Smuzhiyun RSEQ_INJECT_FAILED
262*4882a593Smuzhiyun return -1;
263*4882a593Smuzhiyun cmpfail:
264*4882a593Smuzhiyun rseq_after_asm_goto();
265*4882a593Smuzhiyun return 1;
266*4882a593Smuzhiyun #ifdef RSEQ_COMPARE_TWICE
267*4882a593Smuzhiyun error1:
268*4882a593Smuzhiyun rseq_after_asm_goto();
269*4882a593Smuzhiyun rseq_bug("cpu_id comparison failed");
270*4882a593Smuzhiyun error2:
271*4882a593Smuzhiyun rseq_after_asm_goto();
272*4882a593Smuzhiyun rseq_bug("expected value comparison failed");
273*4882a593Smuzhiyun #endif
274*4882a593Smuzhiyun }
275*4882a593Smuzhiyun
276*4882a593Smuzhiyun static inline __attribute__((always_inline))
rseq_cmpnev_storeoffp_load(intptr_t * v,intptr_t expectnot,long voffp,intptr_t * load,int cpu)277*4882a593Smuzhiyun int rseq_cmpnev_storeoffp_load(intptr_t *v, intptr_t expectnot,
278*4882a593Smuzhiyun long voffp, intptr_t *load, int cpu)
279*4882a593Smuzhiyun {
280*4882a593Smuzhiyun RSEQ_INJECT_C(9)
281*4882a593Smuzhiyun
282*4882a593Smuzhiyun __asm__ __volatile__ goto (
283*4882a593Smuzhiyun RSEQ_ASM_DEFINE_TABLE(3, 1f, 2f, 4f) /* start, commit, abort */
284*4882a593Smuzhiyun RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[cmpfail])
285*4882a593Smuzhiyun #ifdef RSEQ_COMPARE_TWICE
286*4882a593Smuzhiyun RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error1])
287*4882a593Smuzhiyun RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error2])
288*4882a593Smuzhiyun #endif
289*4882a593Smuzhiyun /* Start rseq by storing table entry pointer into rseq_cs. */
290*4882a593Smuzhiyun RSEQ_ASM_STORE_RSEQ_CS(1, 3b, rseq_cs)
291*4882a593Smuzhiyun /* cmp cpuid */
292*4882a593Smuzhiyun RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f)
293*4882a593Smuzhiyun RSEQ_INJECT_ASM(3)
294*4882a593Smuzhiyun /* cmp @v not equal to @expectnot */
295*4882a593Smuzhiyun RSEQ_ASM_OP_CMPNE(v, expectnot, %l[cmpfail])
296*4882a593Smuzhiyun RSEQ_INJECT_ASM(4)
297*4882a593Smuzhiyun #ifdef RSEQ_COMPARE_TWICE
298*4882a593Smuzhiyun /* cmp cpuid */
299*4882a593Smuzhiyun RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1])
300*4882a593Smuzhiyun /* cmp @v not equal to @expectnot */
301*4882a593Smuzhiyun RSEQ_ASM_OP_CMPNE(v, expectnot, %l[error2])
302*4882a593Smuzhiyun #endif
303*4882a593Smuzhiyun /* load the value of @v */
304*4882a593Smuzhiyun RSEQ_ASM_OP_R_LOAD(v)
305*4882a593Smuzhiyun /* store it in @load */
306*4882a593Smuzhiyun RSEQ_ASM_OP_R_STORE(load)
307*4882a593Smuzhiyun /* dereference voffp(v) */
308*4882a593Smuzhiyun RSEQ_ASM_OP_R_LOADX(voffp)
309*4882a593Smuzhiyun /* final store the value at voffp(v) */
310*4882a593Smuzhiyun RSEQ_ASM_OP_R_FINAL_STORE(v, 2)
311*4882a593Smuzhiyun RSEQ_INJECT_ASM(5)
312*4882a593Smuzhiyun RSEQ_ASM_DEFINE_ABORT(4, abort)
313*4882a593Smuzhiyun : /* gcc asm goto does not allow outputs */
314*4882a593Smuzhiyun : [cpu_id] "r" (cpu),
315*4882a593Smuzhiyun [current_cpu_id] "m" (rseq_get_abi()->cpu_id),
316*4882a593Smuzhiyun [rseq_cs] "m" (rseq_get_abi()->rseq_cs.arch.ptr),
317*4882a593Smuzhiyun /* final store input */
318*4882a593Smuzhiyun [v] "m" (*v),
319*4882a593Smuzhiyun [expectnot] "r" (expectnot),
320*4882a593Smuzhiyun [voffp] "b" (voffp),
321*4882a593Smuzhiyun [load] "m" (*load)
322*4882a593Smuzhiyun RSEQ_INJECT_INPUT
323*4882a593Smuzhiyun : "memory", "cc", "r17"
324*4882a593Smuzhiyun RSEQ_INJECT_CLOBBER
325*4882a593Smuzhiyun : abort, cmpfail
326*4882a593Smuzhiyun #ifdef RSEQ_COMPARE_TWICE
327*4882a593Smuzhiyun , error1, error2
328*4882a593Smuzhiyun #endif
329*4882a593Smuzhiyun );
330*4882a593Smuzhiyun rseq_after_asm_goto();
331*4882a593Smuzhiyun return 0;
332*4882a593Smuzhiyun abort:
333*4882a593Smuzhiyun rseq_after_asm_goto();
334*4882a593Smuzhiyun RSEQ_INJECT_FAILED
335*4882a593Smuzhiyun return -1;
336*4882a593Smuzhiyun cmpfail:
337*4882a593Smuzhiyun rseq_after_asm_goto();
338*4882a593Smuzhiyun return 1;
339*4882a593Smuzhiyun #ifdef RSEQ_COMPARE_TWICE
340*4882a593Smuzhiyun error1:
341*4882a593Smuzhiyun rseq_after_asm_goto();
342*4882a593Smuzhiyun rseq_bug("cpu_id comparison failed");
343*4882a593Smuzhiyun error2:
344*4882a593Smuzhiyun rseq_after_asm_goto();
345*4882a593Smuzhiyun rseq_bug("expected value comparison failed");
346*4882a593Smuzhiyun #endif
347*4882a593Smuzhiyun }
348*4882a593Smuzhiyun
349*4882a593Smuzhiyun static inline __attribute__((always_inline))
rseq_addv(intptr_t * v,intptr_t count,int cpu)350*4882a593Smuzhiyun int rseq_addv(intptr_t *v, intptr_t count, int cpu)
351*4882a593Smuzhiyun {
352*4882a593Smuzhiyun RSEQ_INJECT_C(9)
353*4882a593Smuzhiyun
354*4882a593Smuzhiyun __asm__ __volatile__ goto (
355*4882a593Smuzhiyun RSEQ_ASM_DEFINE_TABLE(3, 1f, 2f, 4f) /* start, commit, abort */
356*4882a593Smuzhiyun #ifdef RSEQ_COMPARE_TWICE
357*4882a593Smuzhiyun RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error1])
358*4882a593Smuzhiyun #endif
359*4882a593Smuzhiyun /* Start rseq by storing table entry pointer into rseq_cs. */
360*4882a593Smuzhiyun RSEQ_ASM_STORE_RSEQ_CS(1, 3b, rseq_cs)
361*4882a593Smuzhiyun /* cmp cpuid */
362*4882a593Smuzhiyun RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f)
363*4882a593Smuzhiyun RSEQ_INJECT_ASM(3)
364*4882a593Smuzhiyun #ifdef RSEQ_COMPARE_TWICE
365*4882a593Smuzhiyun /* cmp cpuid */
366*4882a593Smuzhiyun RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1])
367*4882a593Smuzhiyun #endif
368*4882a593Smuzhiyun /* load the value of @v */
369*4882a593Smuzhiyun RSEQ_ASM_OP_R_LOAD(v)
370*4882a593Smuzhiyun /* add @count to it */
371*4882a593Smuzhiyun RSEQ_ASM_OP_R_ADD(count)
372*4882a593Smuzhiyun /* final store */
373*4882a593Smuzhiyun RSEQ_ASM_OP_R_FINAL_STORE(v, 2)
374*4882a593Smuzhiyun RSEQ_INJECT_ASM(4)
375*4882a593Smuzhiyun RSEQ_ASM_DEFINE_ABORT(4, abort)
376*4882a593Smuzhiyun : /* gcc asm goto does not allow outputs */
377*4882a593Smuzhiyun : [cpu_id] "r" (cpu),
378*4882a593Smuzhiyun [current_cpu_id] "m" (rseq_get_abi()->cpu_id),
379*4882a593Smuzhiyun [rseq_cs] "m" (rseq_get_abi()->rseq_cs.arch.ptr),
380*4882a593Smuzhiyun /* final store input */
381*4882a593Smuzhiyun [v] "m" (*v),
382*4882a593Smuzhiyun [count] "r" (count)
383*4882a593Smuzhiyun RSEQ_INJECT_INPUT
384*4882a593Smuzhiyun : "memory", "cc", "r17"
385*4882a593Smuzhiyun RSEQ_INJECT_CLOBBER
386*4882a593Smuzhiyun : abort
387*4882a593Smuzhiyun #ifdef RSEQ_COMPARE_TWICE
388*4882a593Smuzhiyun , error1
389*4882a593Smuzhiyun #endif
390*4882a593Smuzhiyun );
391*4882a593Smuzhiyun rseq_after_asm_goto();
392*4882a593Smuzhiyun return 0;
393*4882a593Smuzhiyun abort:
394*4882a593Smuzhiyun rseq_after_asm_goto();
395*4882a593Smuzhiyun RSEQ_INJECT_FAILED
396*4882a593Smuzhiyun return -1;
397*4882a593Smuzhiyun #ifdef RSEQ_COMPARE_TWICE
398*4882a593Smuzhiyun error1:
399*4882a593Smuzhiyun rseq_after_asm_goto();
400*4882a593Smuzhiyun rseq_bug("cpu_id comparison failed");
401*4882a593Smuzhiyun #endif
402*4882a593Smuzhiyun }
403*4882a593Smuzhiyun
404*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)405*4882a593Smuzhiyun int rseq_cmpeqv_trystorev_storev(intptr_t *v, intptr_t expect,
406*4882a593Smuzhiyun intptr_t *v2, intptr_t newv2,
407*4882a593Smuzhiyun intptr_t newv, int cpu)
408*4882a593Smuzhiyun {
409*4882a593Smuzhiyun RSEQ_INJECT_C(9)
410*4882a593Smuzhiyun
411*4882a593Smuzhiyun __asm__ __volatile__ goto (
412*4882a593Smuzhiyun RSEQ_ASM_DEFINE_TABLE(3, 1f, 2f, 4f) /* start, commit, abort */
413*4882a593Smuzhiyun RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[cmpfail])
414*4882a593Smuzhiyun #ifdef RSEQ_COMPARE_TWICE
415*4882a593Smuzhiyun RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error1])
416*4882a593Smuzhiyun RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error2])
417*4882a593Smuzhiyun #endif
418*4882a593Smuzhiyun /* Start rseq by storing table entry pointer into rseq_cs. */
419*4882a593Smuzhiyun RSEQ_ASM_STORE_RSEQ_CS(1, 3b, rseq_cs)
420*4882a593Smuzhiyun /* cmp cpuid */
421*4882a593Smuzhiyun RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f)
422*4882a593Smuzhiyun RSEQ_INJECT_ASM(3)
423*4882a593Smuzhiyun /* cmp @v equal to @expect */
424*4882a593Smuzhiyun RSEQ_ASM_OP_CMPEQ(v, expect, %l[cmpfail])
425*4882a593Smuzhiyun RSEQ_INJECT_ASM(4)
426*4882a593Smuzhiyun #ifdef RSEQ_COMPARE_TWICE
427*4882a593Smuzhiyun /* cmp cpuid */
428*4882a593Smuzhiyun RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1])
429*4882a593Smuzhiyun /* cmp @v equal to @expect */
430*4882a593Smuzhiyun RSEQ_ASM_OP_CMPEQ(v, expect, %l[error2])
431*4882a593Smuzhiyun #endif
432*4882a593Smuzhiyun /* try store */
433*4882a593Smuzhiyun RSEQ_ASM_OP_STORE(newv2, v2)
434*4882a593Smuzhiyun RSEQ_INJECT_ASM(5)
435*4882a593Smuzhiyun /* final store */
436*4882a593Smuzhiyun RSEQ_ASM_OP_FINAL_STORE(newv, v, 2)
437*4882a593Smuzhiyun RSEQ_INJECT_ASM(6)
438*4882a593Smuzhiyun RSEQ_ASM_DEFINE_ABORT(4, abort)
439*4882a593Smuzhiyun : /* gcc asm goto does not allow outputs */
440*4882a593Smuzhiyun : [cpu_id] "r" (cpu),
441*4882a593Smuzhiyun [current_cpu_id] "m" (rseq_get_abi()->cpu_id),
442*4882a593Smuzhiyun [rseq_cs] "m" (rseq_get_abi()->rseq_cs.arch.ptr),
443*4882a593Smuzhiyun /* try store input */
444*4882a593Smuzhiyun [v2] "m" (*v2),
445*4882a593Smuzhiyun [newv2] "r" (newv2),
446*4882a593Smuzhiyun /* final store input */
447*4882a593Smuzhiyun [v] "m" (*v),
448*4882a593Smuzhiyun [expect] "r" (expect),
449*4882a593Smuzhiyun [newv] "r" (newv)
450*4882a593Smuzhiyun RSEQ_INJECT_INPUT
451*4882a593Smuzhiyun : "memory", "cc", "r17"
452*4882a593Smuzhiyun RSEQ_INJECT_CLOBBER
453*4882a593Smuzhiyun : abort, cmpfail
454*4882a593Smuzhiyun #ifdef RSEQ_COMPARE_TWICE
455*4882a593Smuzhiyun , error1, error2
456*4882a593Smuzhiyun #endif
457*4882a593Smuzhiyun );
458*4882a593Smuzhiyun rseq_after_asm_goto();
459*4882a593Smuzhiyun return 0;
460*4882a593Smuzhiyun abort:
461*4882a593Smuzhiyun rseq_after_asm_goto();
462*4882a593Smuzhiyun RSEQ_INJECT_FAILED
463*4882a593Smuzhiyun return -1;
464*4882a593Smuzhiyun cmpfail:
465*4882a593Smuzhiyun rseq_after_asm_goto();
466*4882a593Smuzhiyun return 1;
467*4882a593Smuzhiyun #ifdef RSEQ_COMPARE_TWICE
468*4882a593Smuzhiyun error1:
469*4882a593Smuzhiyun rseq_after_asm_goto();
470*4882a593Smuzhiyun rseq_bug("cpu_id comparison failed");
471*4882a593Smuzhiyun error2:
472*4882a593Smuzhiyun rseq_after_asm_goto();
473*4882a593Smuzhiyun rseq_bug("expected value comparison failed");
474*4882a593Smuzhiyun #endif
475*4882a593Smuzhiyun }
476*4882a593Smuzhiyun
477*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)478*4882a593Smuzhiyun int rseq_cmpeqv_trystorev_storev_release(intptr_t *v, intptr_t expect,
479*4882a593Smuzhiyun intptr_t *v2, intptr_t newv2,
480*4882a593Smuzhiyun intptr_t newv, int cpu)
481*4882a593Smuzhiyun {
482*4882a593Smuzhiyun RSEQ_INJECT_C(9)
483*4882a593Smuzhiyun
484*4882a593Smuzhiyun __asm__ __volatile__ goto (
485*4882a593Smuzhiyun RSEQ_ASM_DEFINE_TABLE(3, 1f, 2f, 4f) /* start, commit, abort */
486*4882a593Smuzhiyun RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[cmpfail])
487*4882a593Smuzhiyun #ifdef RSEQ_COMPARE_TWICE
488*4882a593Smuzhiyun RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error1])
489*4882a593Smuzhiyun RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error2])
490*4882a593Smuzhiyun #endif
491*4882a593Smuzhiyun /* Start rseq by storing table entry pointer into rseq_cs. */
492*4882a593Smuzhiyun RSEQ_ASM_STORE_RSEQ_CS(1, 3b, rseq_cs)
493*4882a593Smuzhiyun /* cmp cpuid */
494*4882a593Smuzhiyun RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f)
495*4882a593Smuzhiyun RSEQ_INJECT_ASM(3)
496*4882a593Smuzhiyun /* cmp @v equal to @expect */
497*4882a593Smuzhiyun RSEQ_ASM_OP_CMPEQ(v, expect, %l[cmpfail])
498*4882a593Smuzhiyun RSEQ_INJECT_ASM(4)
499*4882a593Smuzhiyun #ifdef RSEQ_COMPARE_TWICE
500*4882a593Smuzhiyun /* cmp cpuid */
501*4882a593Smuzhiyun RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1])
502*4882a593Smuzhiyun /* cmp @v equal to @expect */
503*4882a593Smuzhiyun RSEQ_ASM_OP_CMPEQ(v, expect, %l[error2])
504*4882a593Smuzhiyun #endif
505*4882a593Smuzhiyun /* try store */
506*4882a593Smuzhiyun RSEQ_ASM_OP_STORE(newv2, v2)
507*4882a593Smuzhiyun RSEQ_INJECT_ASM(5)
508*4882a593Smuzhiyun /* for 'release' */
509*4882a593Smuzhiyun "lwsync\n\t"
510*4882a593Smuzhiyun /* final store */
511*4882a593Smuzhiyun RSEQ_ASM_OP_FINAL_STORE(newv, v, 2)
512*4882a593Smuzhiyun RSEQ_INJECT_ASM(6)
513*4882a593Smuzhiyun RSEQ_ASM_DEFINE_ABORT(4, abort)
514*4882a593Smuzhiyun : /* gcc asm goto does not allow outputs */
515*4882a593Smuzhiyun : [cpu_id] "r" (cpu),
516*4882a593Smuzhiyun [current_cpu_id] "m" (rseq_get_abi()->cpu_id),
517*4882a593Smuzhiyun [rseq_cs] "m" (rseq_get_abi()->rseq_cs.arch.ptr),
518*4882a593Smuzhiyun /* try store input */
519*4882a593Smuzhiyun [v2] "m" (*v2),
520*4882a593Smuzhiyun [newv2] "r" (newv2),
521*4882a593Smuzhiyun /* final store input */
522*4882a593Smuzhiyun [v] "m" (*v),
523*4882a593Smuzhiyun [expect] "r" (expect),
524*4882a593Smuzhiyun [newv] "r" (newv)
525*4882a593Smuzhiyun RSEQ_INJECT_INPUT
526*4882a593Smuzhiyun : "memory", "cc", "r17"
527*4882a593Smuzhiyun RSEQ_INJECT_CLOBBER
528*4882a593Smuzhiyun : abort, cmpfail
529*4882a593Smuzhiyun #ifdef RSEQ_COMPARE_TWICE
530*4882a593Smuzhiyun , error1, error2
531*4882a593Smuzhiyun #endif
532*4882a593Smuzhiyun );
533*4882a593Smuzhiyun rseq_after_asm_goto();
534*4882a593Smuzhiyun return 0;
535*4882a593Smuzhiyun abort:
536*4882a593Smuzhiyun rseq_after_asm_goto();
537*4882a593Smuzhiyun RSEQ_INJECT_FAILED
538*4882a593Smuzhiyun return -1;
539*4882a593Smuzhiyun cmpfail:
540*4882a593Smuzhiyun rseq_after_asm_goto();
541*4882a593Smuzhiyun return 1;
542*4882a593Smuzhiyun #ifdef RSEQ_COMPARE_TWICE
543*4882a593Smuzhiyun error1:
544*4882a593Smuzhiyun rseq_after_asm_goto();
545*4882a593Smuzhiyun rseq_bug("cpu_id comparison failed");
546*4882a593Smuzhiyun error2:
547*4882a593Smuzhiyun rseq_after_asm_goto();
548*4882a593Smuzhiyun rseq_bug("expected value comparison failed");
549*4882a593Smuzhiyun #endif
550*4882a593Smuzhiyun }
551*4882a593Smuzhiyun
552*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)553*4882a593Smuzhiyun int rseq_cmpeqv_cmpeqv_storev(intptr_t *v, intptr_t expect,
554*4882a593Smuzhiyun intptr_t *v2, intptr_t expect2,
555*4882a593Smuzhiyun intptr_t newv, int cpu)
556*4882a593Smuzhiyun {
557*4882a593Smuzhiyun RSEQ_INJECT_C(9)
558*4882a593Smuzhiyun
559*4882a593Smuzhiyun __asm__ __volatile__ goto (
560*4882a593Smuzhiyun RSEQ_ASM_DEFINE_TABLE(3, 1f, 2f, 4f) /* start, commit, abort */
561*4882a593Smuzhiyun RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[cmpfail])
562*4882a593Smuzhiyun #ifdef RSEQ_COMPARE_TWICE
563*4882a593Smuzhiyun RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error1])
564*4882a593Smuzhiyun RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error2])
565*4882a593Smuzhiyun RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error3])
566*4882a593Smuzhiyun #endif
567*4882a593Smuzhiyun /* Start rseq by storing table entry pointer into rseq_cs. */
568*4882a593Smuzhiyun RSEQ_ASM_STORE_RSEQ_CS(1, 3b, rseq_cs)
569*4882a593Smuzhiyun /* cmp cpuid */
570*4882a593Smuzhiyun RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f)
571*4882a593Smuzhiyun RSEQ_INJECT_ASM(3)
572*4882a593Smuzhiyun /* cmp @v equal to @expect */
573*4882a593Smuzhiyun RSEQ_ASM_OP_CMPEQ(v, expect, %l[cmpfail])
574*4882a593Smuzhiyun RSEQ_INJECT_ASM(4)
575*4882a593Smuzhiyun /* cmp @v2 equal to @expct2 */
576*4882a593Smuzhiyun RSEQ_ASM_OP_CMPEQ(v2, expect2, %l[cmpfail])
577*4882a593Smuzhiyun RSEQ_INJECT_ASM(5)
578*4882a593Smuzhiyun #ifdef RSEQ_COMPARE_TWICE
579*4882a593Smuzhiyun /* cmp cpuid */
580*4882a593Smuzhiyun RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1])
581*4882a593Smuzhiyun /* cmp @v equal to @expect */
582*4882a593Smuzhiyun RSEQ_ASM_OP_CMPEQ(v, expect, %l[error2])
583*4882a593Smuzhiyun /* cmp @v2 equal to @expct2 */
584*4882a593Smuzhiyun RSEQ_ASM_OP_CMPEQ(v2, expect2, %l[error3])
585*4882a593Smuzhiyun #endif
586*4882a593Smuzhiyun /* final store */
587*4882a593Smuzhiyun RSEQ_ASM_OP_FINAL_STORE(newv, v, 2)
588*4882a593Smuzhiyun RSEQ_INJECT_ASM(6)
589*4882a593Smuzhiyun RSEQ_ASM_DEFINE_ABORT(4, abort)
590*4882a593Smuzhiyun : /* gcc asm goto does not allow outputs */
591*4882a593Smuzhiyun : [cpu_id] "r" (cpu),
592*4882a593Smuzhiyun [current_cpu_id] "m" (rseq_get_abi()->cpu_id),
593*4882a593Smuzhiyun [rseq_cs] "m" (rseq_get_abi()->rseq_cs.arch.ptr),
594*4882a593Smuzhiyun /* cmp2 input */
595*4882a593Smuzhiyun [v2] "m" (*v2),
596*4882a593Smuzhiyun [expect2] "r" (expect2),
597*4882a593Smuzhiyun /* final store input */
598*4882a593Smuzhiyun [v] "m" (*v),
599*4882a593Smuzhiyun [expect] "r" (expect),
600*4882a593Smuzhiyun [newv] "r" (newv)
601*4882a593Smuzhiyun RSEQ_INJECT_INPUT
602*4882a593Smuzhiyun : "memory", "cc", "r17"
603*4882a593Smuzhiyun RSEQ_INJECT_CLOBBER
604*4882a593Smuzhiyun : abort, cmpfail
605*4882a593Smuzhiyun #ifdef RSEQ_COMPARE_TWICE
606*4882a593Smuzhiyun , error1, error2, error3
607*4882a593Smuzhiyun #endif
608*4882a593Smuzhiyun );
609*4882a593Smuzhiyun rseq_after_asm_goto();
610*4882a593Smuzhiyun return 0;
611*4882a593Smuzhiyun abort:
612*4882a593Smuzhiyun rseq_after_asm_goto();
613*4882a593Smuzhiyun RSEQ_INJECT_FAILED
614*4882a593Smuzhiyun return -1;
615*4882a593Smuzhiyun cmpfail:
616*4882a593Smuzhiyun rseq_after_asm_goto();
617*4882a593Smuzhiyun return 1;
618*4882a593Smuzhiyun #ifdef RSEQ_COMPARE_TWICE
619*4882a593Smuzhiyun error1:
620*4882a593Smuzhiyun rseq_after_asm_goto();
621*4882a593Smuzhiyun rseq_bug("cpu_id comparison failed");
622*4882a593Smuzhiyun error2:
623*4882a593Smuzhiyun rseq_after_asm_goto();
624*4882a593Smuzhiyun rseq_bug("1st expected value comparison failed");
625*4882a593Smuzhiyun error3:
626*4882a593Smuzhiyun rseq_after_asm_goto();
627*4882a593Smuzhiyun rseq_bug("2nd expected value comparison failed");
628*4882a593Smuzhiyun #endif
629*4882a593Smuzhiyun }
630*4882a593Smuzhiyun
631*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)632*4882a593Smuzhiyun int rseq_cmpeqv_trymemcpy_storev(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(3, 1f, 2f, 4f) /* start, commit, abort */
640*4882a593Smuzhiyun RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[cmpfail])
641*4882a593Smuzhiyun #ifdef RSEQ_COMPARE_TWICE
642*4882a593Smuzhiyun RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error1])
643*4882a593Smuzhiyun RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error2])
644*4882a593Smuzhiyun #endif
645*4882a593Smuzhiyun /* setup for mempcy */
646*4882a593Smuzhiyun "mr %%r19, %[len]\n\t"
647*4882a593Smuzhiyun "mr %%r20, %[src]\n\t"
648*4882a593Smuzhiyun "mr %%r21, %[dst]\n\t"
649*4882a593Smuzhiyun /* Start rseq by storing table entry pointer into rseq_cs. */
650*4882a593Smuzhiyun RSEQ_ASM_STORE_RSEQ_CS(1, 3b, rseq_cs)
651*4882a593Smuzhiyun /* cmp cpuid */
652*4882a593Smuzhiyun RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f)
653*4882a593Smuzhiyun RSEQ_INJECT_ASM(3)
654*4882a593Smuzhiyun /* cmp @v equal to @expect */
655*4882a593Smuzhiyun RSEQ_ASM_OP_CMPEQ(v, expect, %l[cmpfail])
656*4882a593Smuzhiyun RSEQ_INJECT_ASM(4)
657*4882a593Smuzhiyun #ifdef RSEQ_COMPARE_TWICE
658*4882a593Smuzhiyun /* cmp cpuid */
659*4882a593Smuzhiyun RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1])
660*4882a593Smuzhiyun /* cmp @v equal to @expect */
661*4882a593Smuzhiyun RSEQ_ASM_OP_CMPEQ(v, expect, %l[error2])
662*4882a593Smuzhiyun #endif
663*4882a593Smuzhiyun /* try memcpy */
664*4882a593Smuzhiyun RSEQ_ASM_OP_R_MEMCPY()
665*4882a593Smuzhiyun RSEQ_INJECT_ASM(5)
666*4882a593Smuzhiyun /* final store */
667*4882a593Smuzhiyun RSEQ_ASM_OP_FINAL_STORE(newv, v, 2)
668*4882a593Smuzhiyun RSEQ_INJECT_ASM(6)
669*4882a593Smuzhiyun /* teardown */
670*4882a593Smuzhiyun RSEQ_ASM_DEFINE_ABORT(4, abort)
671*4882a593Smuzhiyun : /* gcc asm goto does not allow outputs */
672*4882a593Smuzhiyun : [cpu_id] "r" (cpu),
673*4882a593Smuzhiyun [current_cpu_id] "m" (rseq_get_abi()->cpu_id),
674*4882a593Smuzhiyun [rseq_cs] "m" (rseq_get_abi()->rseq_cs.arch.ptr),
675*4882a593Smuzhiyun /* final store input */
676*4882a593Smuzhiyun [v] "m" (*v),
677*4882a593Smuzhiyun [expect] "r" (expect),
678*4882a593Smuzhiyun [newv] "r" (newv),
679*4882a593Smuzhiyun /* try memcpy input */
680*4882a593Smuzhiyun [dst] "r" (dst),
681*4882a593Smuzhiyun [src] "r" (src),
682*4882a593Smuzhiyun [len] "r" (len)
683*4882a593Smuzhiyun RSEQ_INJECT_INPUT
684*4882a593Smuzhiyun : "memory", "cc", "r17", "r18", "r19", "r20", "r21"
685*4882a593Smuzhiyun RSEQ_INJECT_CLOBBER
686*4882a593Smuzhiyun : abort, cmpfail
687*4882a593Smuzhiyun #ifdef RSEQ_COMPARE_TWICE
688*4882a593Smuzhiyun , error1, error2
689*4882a593Smuzhiyun #endif
690*4882a593Smuzhiyun );
691*4882a593Smuzhiyun rseq_after_asm_goto();
692*4882a593Smuzhiyun return 0;
693*4882a593Smuzhiyun abort:
694*4882a593Smuzhiyun rseq_after_asm_goto();
695*4882a593Smuzhiyun RSEQ_INJECT_FAILED
696*4882a593Smuzhiyun return -1;
697*4882a593Smuzhiyun cmpfail:
698*4882a593Smuzhiyun rseq_after_asm_goto();
699*4882a593Smuzhiyun return 1;
700*4882a593Smuzhiyun #ifdef RSEQ_COMPARE_TWICE
701*4882a593Smuzhiyun error1:
702*4882a593Smuzhiyun rseq_after_asm_goto();
703*4882a593Smuzhiyun rseq_bug("cpu_id comparison failed");
704*4882a593Smuzhiyun error2:
705*4882a593Smuzhiyun rseq_after_asm_goto();
706*4882a593Smuzhiyun rseq_bug("expected value comparison failed");
707*4882a593Smuzhiyun #endif
708*4882a593Smuzhiyun }
709*4882a593Smuzhiyun
710*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)711*4882a593Smuzhiyun int rseq_cmpeqv_trymemcpy_storev_release(intptr_t *v, intptr_t expect,
712*4882a593Smuzhiyun void *dst, void *src, size_t len,
713*4882a593Smuzhiyun intptr_t newv, int cpu)
714*4882a593Smuzhiyun {
715*4882a593Smuzhiyun RSEQ_INJECT_C(9)
716*4882a593Smuzhiyun
717*4882a593Smuzhiyun __asm__ __volatile__ goto (
718*4882a593Smuzhiyun RSEQ_ASM_DEFINE_TABLE(3, 1f, 2f, 4f) /* start, commit, abort */
719*4882a593Smuzhiyun RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[cmpfail])
720*4882a593Smuzhiyun #ifdef RSEQ_COMPARE_TWICE
721*4882a593Smuzhiyun RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error1])
722*4882a593Smuzhiyun RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error2])
723*4882a593Smuzhiyun #endif
724*4882a593Smuzhiyun /* setup for mempcy */
725*4882a593Smuzhiyun "mr %%r19, %[len]\n\t"
726*4882a593Smuzhiyun "mr %%r20, %[src]\n\t"
727*4882a593Smuzhiyun "mr %%r21, %[dst]\n\t"
728*4882a593Smuzhiyun /* Start rseq by storing table entry pointer into rseq_cs. */
729*4882a593Smuzhiyun RSEQ_ASM_STORE_RSEQ_CS(1, 3b, rseq_cs)
730*4882a593Smuzhiyun /* cmp cpuid */
731*4882a593Smuzhiyun RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f)
732*4882a593Smuzhiyun RSEQ_INJECT_ASM(3)
733*4882a593Smuzhiyun /* cmp @v equal to @expect */
734*4882a593Smuzhiyun RSEQ_ASM_OP_CMPEQ(v, expect, %l[cmpfail])
735*4882a593Smuzhiyun RSEQ_INJECT_ASM(4)
736*4882a593Smuzhiyun #ifdef RSEQ_COMPARE_TWICE
737*4882a593Smuzhiyun /* cmp cpuid */
738*4882a593Smuzhiyun RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1])
739*4882a593Smuzhiyun /* cmp @v equal to @expect */
740*4882a593Smuzhiyun RSEQ_ASM_OP_CMPEQ(v, expect, %l[error2])
741*4882a593Smuzhiyun #endif
742*4882a593Smuzhiyun /* try memcpy */
743*4882a593Smuzhiyun RSEQ_ASM_OP_R_MEMCPY()
744*4882a593Smuzhiyun RSEQ_INJECT_ASM(5)
745*4882a593Smuzhiyun /* for 'release' */
746*4882a593Smuzhiyun "lwsync\n\t"
747*4882a593Smuzhiyun /* final store */
748*4882a593Smuzhiyun RSEQ_ASM_OP_FINAL_STORE(newv, v, 2)
749*4882a593Smuzhiyun RSEQ_INJECT_ASM(6)
750*4882a593Smuzhiyun /* teardown */
751*4882a593Smuzhiyun RSEQ_ASM_DEFINE_ABORT(4, abort)
752*4882a593Smuzhiyun : /* gcc asm goto does not allow outputs */
753*4882a593Smuzhiyun : [cpu_id] "r" (cpu),
754*4882a593Smuzhiyun [current_cpu_id] "m" (rseq_get_abi()->cpu_id),
755*4882a593Smuzhiyun [rseq_cs] "m" (rseq_get_abi()->rseq_cs.arch.ptr),
756*4882a593Smuzhiyun /* final store input */
757*4882a593Smuzhiyun [v] "m" (*v),
758*4882a593Smuzhiyun [expect] "r" (expect),
759*4882a593Smuzhiyun [newv] "r" (newv),
760*4882a593Smuzhiyun /* try memcpy input */
761*4882a593Smuzhiyun [dst] "r" (dst),
762*4882a593Smuzhiyun [src] "r" (src),
763*4882a593Smuzhiyun [len] "r" (len)
764*4882a593Smuzhiyun RSEQ_INJECT_INPUT
765*4882a593Smuzhiyun : "memory", "cc", "r17", "r18", "r19", "r20", "r21"
766*4882a593Smuzhiyun RSEQ_INJECT_CLOBBER
767*4882a593Smuzhiyun : abort, cmpfail
768*4882a593Smuzhiyun #ifdef RSEQ_COMPARE_TWICE
769*4882a593Smuzhiyun , error1, error2
770*4882a593Smuzhiyun #endif
771*4882a593Smuzhiyun );
772*4882a593Smuzhiyun rseq_after_asm_goto();
773*4882a593Smuzhiyun return 0;
774*4882a593Smuzhiyun abort:
775*4882a593Smuzhiyun rseq_after_asm_goto();
776*4882a593Smuzhiyun RSEQ_INJECT_FAILED
777*4882a593Smuzhiyun return -1;
778*4882a593Smuzhiyun cmpfail:
779*4882a593Smuzhiyun rseq_after_asm_goto();
780*4882a593Smuzhiyun return 1;
781*4882a593Smuzhiyun #ifdef RSEQ_COMPARE_TWICE
782*4882a593Smuzhiyun error1:
783*4882a593Smuzhiyun rseq_after_asm_goto();
784*4882a593Smuzhiyun rseq_bug("cpu_id comparison failed");
785*4882a593Smuzhiyun error2:
786*4882a593Smuzhiyun rseq_after_asm_goto();
787*4882a593Smuzhiyun rseq_bug("expected value comparison failed");
788*4882a593Smuzhiyun #endif
789*4882a593Smuzhiyun }
790*4882a593Smuzhiyun
791*4882a593Smuzhiyun #endif /* !RSEQ_SKIP_FASTPATH */
792