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