xref: /OK3568_Linux_fs/kernel/tools/testing/selftests/rseq/rseq-ppc.h (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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