xref: /openbmc/linux/tools/testing/selftests/rseq/rseq-ppc.h (revision c900529f3d9161bfde5cca0754f83b4d3c3e0220)
12e155fb7SMathieu Desnoyers /* SPDX-License-Identifier: LGPL-2.1 OR MIT */
22e155fb7SMathieu Desnoyers /*
32e155fb7SMathieu Desnoyers  * rseq-ppc.h
42e155fb7SMathieu Desnoyers  *
5e61bd94cSMathieu Desnoyers  * (C) Copyright 2016-2022 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
62e155fb7SMathieu Desnoyers  * (C) Copyright 2016-2018 - Boqun Feng <boqun.feng@gmail.com>
72e155fb7SMathieu Desnoyers  */
82e155fb7SMathieu Desnoyers 
9496fd0fcSMathieu Desnoyers /*
10496fd0fcSMathieu Desnoyers  * RSEQ_SIG is used with the following trap instruction:
11496fd0fcSMathieu Desnoyers  *
12496fd0fcSMathieu Desnoyers  * powerpc-be:    0f e5 00 0b           twui   r5,11
13496fd0fcSMathieu Desnoyers  * powerpc64-le:  0b 00 e5 0f           twui   r5,11
14496fd0fcSMathieu Desnoyers  * powerpc64-be:  0f e5 00 0b           twui   r5,11
15496fd0fcSMathieu Desnoyers  */
16496fd0fcSMathieu Desnoyers 
17496fd0fcSMathieu Desnoyers #define RSEQ_SIG	0x0fe5000b
182e155fb7SMathieu Desnoyers 
192e155fb7SMathieu Desnoyers #define rseq_smp_mb()		__asm__ __volatile__ ("sync"	::: "memory", "cc")
202e155fb7SMathieu Desnoyers #define rseq_smp_lwsync()	__asm__ __volatile__ ("lwsync"	::: "memory", "cc")
212e155fb7SMathieu Desnoyers #define rseq_smp_rmb()		rseq_smp_lwsync()
222e155fb7SMathieu Desnoyers #define rseq_smp_wmb()		rseq_smp_lwsync()
232e155fb7SMathieu Desnoyers 
242e155fb7SMathieu Desnoyers #define rseq_smp_load_acquire(p)					\
252e155fb7SMathieu Desnoyers __extension__ ({							\
26*2b2fe605SMathieu Desnoyers 	rseq_unqual_scalar_typeof(*(p)) ____p1 = RSEQ_READ_ONCE(*(p));	\
272e155fb7SMathieu Desnoyers 	rseq_smp_lwsync();						\
282e155fb7SMathieu Desnoyers 	____p1;								\
292e155fb7SMathieu Desnoyers })
302e155fb7SMathieu Desnoyers 
312e155fb7SMathieu Desnoyers #define rseq_smp_acquire__after_ctrl_dep()	rseq_smp_lwsync()
322e155fb7SMathieu Desnoyers 
332e155fb7SMathieu Desnoyers #define rseq_smp_store_release(p, v)					\
342e155fb7SMathieu Desnoyers do {									\
352e155fb7SMathieu Desnoyers 	rseq_smp_lwsync();						\
36*2b2fe605SMathieu Desnoyers 	RSEQ_WRITE_ONCE(*(p), v);					\
372e155fb7SMathieu Desnoyers } while (0)
382e155fb7SMathieu Desnoyers 
392e155fb7SMathieu Desnoyers /*
40a3e3131fSMathieu Desnoyers  * The __rseq_cs_ptr_array and __rseq_cs sections can be used by debuggers to
41a3e3131fSMathieu Desnoyers  * better handle single-stepping through the restartable critical sections.
422e155fb7SMathieu Desnoyers  */
432e155fb7SMathieu Desnoyers 
442e155fb7SMathieu Desnoyers #ifdef __PPC64__
452e155fb7SMathieu Desnoyers 
46de6b52a2SMathieu Desnoyers #define RSEQ_STORE_LONG(arg)	"std%U[" __rseq_str(arg) "]%X[" __rseq_str(arg) "] "	/* To memory ("m" constraint) */
47de6b52a2SMathieu Desnoyers #define RSEQ_STORE_INT(arg)	"stw%U[" __rseq_str(arg) "]%X[" __rseq_str(arg) "] "	/* To memory ("m" constraint) */
48de6b52a2SMathieu Desnoyers #define RSEQ_LOAD_LONG(arg)	"ld%U[" __rseq_str(arg) "]%X[" __rseq_str(arg) "] "	/* From memory ("m" constraint) */
49de6b52a2SMathieu Desnoyers #define RSEQ_LOAD_INT(arg)	"lwz%U[" __rseq_str(arg) "]%X[" __rseq_str(arg) "] "	/* From memory ("m" constraint) */
50de6b52a2SMathieu Desnoyers #define RSEQ_LOADX_LONG		"ldx "							/* From base register ("b" constraint) */
51de6b52a2SMathieu Desnoyers #define RSEQ_CMP_LONG		"cmpd "
52de6b52a2SMathieu Desnoyers #define RSEQ_CMP_LONG_INT	"cmpdi "
532e155fb7SMathieu Desnoyers 
542e155fb7SMathieu Desnoyers #define __RSEQ_ASM_DEFINE_TABLE(label, version, flags,				\
552e155fb7SMathieu Desnoyers 			start_ip, post_commit_offset, abort_ip)			\
56a3e3131fSMathieu Desnoyers 		".pushsection __rseq_cs, \"aw\"\n\t"				\
572e155fb7SMathieu Desnoyers 		".balign 32\n\t"						\
582e155fb7SMathieu Desnoyers 		__rseq_str(label) ":\n\t"					\
592e155fb7SMathieu Desnoyers 		".long " __rseq_str(version) ", " __rseq_str(flags) "\n\t"	\
602e155fb7SMathieu Desnoyers 		".quad " __rseq_str(start_ip) ", " __rseq_str(post_commit_offset) ", " __rseq_str(abort_ip) "\n\t" \
61a3e3131fSMathieu Desnoyers 		".popsection\n\t"						\
62a3e3131fSMathieu Desnoyers 		".pushsection __rseq_cs_ptr_array, \"aw\"\n\t"			\
63a3e3131fSMathieu Desnoyers 		".quad " __rseq_str(label) "b\n\t"				\
642e155fb7SMathieu Desnoyers 		".popsection\n\t"
652e155fb7SMathieu Desnoyers 
662e155fb7SMathieu Desnoyers #define RSEQ_ASM_STORE_RSEQ_CS(label, cs_label, rseq_cs)			\
672e155fb7SMathieu Desnoyers 		RSEQ_INJECT_ASM(1)						\
682e155fb7SMathieu Desnoyers 		"lis %%r17, (" __rseq_str(cs_label) ")@highest\n\t"		\
692e155fb7SMathieu Desnoyers 		"ori %%r17, %%r17, (" __rseq_str(cs_label) ")@higher\n\t"	\
702e155fb7SMathieu Desnoyers 		"rldicr %%r17, %%r17, 32, 31\n\t"				\
712e155fb7SMathieu Desnoyers 		"oris %%r17, %%r17, (" __rseq_str(cs_label) ")@high\n\t"	\
722e155fb7SMathieu Desnoyers 		"ori %%r17, %%r17, (" __rseq_str(cs_label) ")@l\n\t"		\
732e155fb7SMathieu Desnoyers 		"std %%r17, %[" __rseq_str(rseq_cs) "]\n\t"			\
742e155fb7SMathieu Desnoyers 		__rseq_str(label) ":\n\t"
752e155fb7SMathieu Desnoyers 
764fe2088eSMathieu Desnoyers /*
774fe2088eSMathieu Desnoyers  * Exit points of a rseq critical section consist of all instructions outside
784fe2088eSMathieu Desnoyers  * of the critical section where a critical section can either branch to or
794fe2088eSMathieu Desnoyers  * reach through the normal course of its execution. The abort IP and the
80a3e3131fSMathieu Desnoyers  * post-commit IP are already part of the __rseq_cs section and should not be
81a3e3131fSMathieu Desnoyers  * explicitly defined as additional exit points. Knowing all exit points is
824fe2088eSMathieu Desnoyers  * useful to assist debuggers stepping over the critical section.
834fe2088eSMathieu Desnoyers  */
844fe2088eSMathieu Desnoyers #define RSEQ_ASM_DEFINE_EXIT_POINT(start_ip, exit_ip)			\
854fe2088eSMathieu Desnoyers 		".pushsection __rseq_exit_point_array, \"aw\"\n\t"	\
864fe2088eSMathieu Desnoyers 		".quad " __rseq_str(start_ip) ", " __rseq_str(exit_ip) "\n\t" \
874fe2088eSMathieu Desnoyers 		".popsection\n\t"
884fe2088eSMathieu Desnoyers 
892e155fb7SMathieu Desnoyers #else /* #ifdef __PPC64__ */
902e155fb7SMathieu Desnoyers 
91de6b52a2SMathieu Desnoyers #define RSEQ_STORE_LONG(arg)	"stw%U[" __rseq_str(arg) "]%X[" __rseq_str(arg) "] "	/* To memory ("m" constraint) */
92de6b52a2SMathieu Desnoyers #define RSEQ_STORE_INT(arg)	RSEQ_STORE_LONG(arg)					/* To memory ("m" constraint) */
93de6b52a2SMathieu Desnoyers #define RSEQ_LOAD_LONG(arg)	"lwz%U[" __rseq_str(arg) "]%X[" __rseq_str(arg) "] "	/* From memory ("m" constraint) */
94de6b52a2SMathieu Desnoyers #define RSEQ_LOAD_INT(arg)	RSEQ_LOAD_LONG(arg)					/* From memory ("m" constraint) */
95de6b52a2SMathieu Desnoyers #define RSEQ_LOADX_LONG		"lwzx "							/* From base register ("b" constraint) */
96de6b52a2SMathieu Desnoyers #define RSEQ_CMP_LONG		"cmpw "
97de6b52a2SMathieu Desnoyers #define RSEQ_CMP_LONG_INT	"cmpwi "
982e155fb7SMathieu Desnoyers 
992e155fb7SMathieu Desnoyers #define __RSEQ_ASM_DEFINE_TABLE(label, version, flags,				\
1002e155fb7SMathieu Desnoyers 			start_ip, post_commit_offset, abort_ip)			\
101a3e3131fSMathieu Desnoyers 		".pushsection __rseq_cs, \"aw\"\n\t"				\
1022e155fb7SMathieu Desnoyers 		".balign 32\n\t"						\
1032e155fb7SMathieu Desnoyers 		__rseq_str(label) ":\n\t"					\
1042e155fb7SMathieu Desnoyers 		".long " __rseq_str(version) ", " __rseq_str(flags) "\n\t"	\
1052e155fb7SMathieu Desnoyers 		/* 32-bit only supported on BE */				\
1062e155fb7SMathieu Desnoyers 		".long 0x0, " __rseq_str(start_ip) ", 0x0, " __rseq_str(post_commit_offset) ", 0x0, " __rseq_str(abort_ip) "\n\t" \
107a3e3131fSMathieu Desnoyers 		".popsection\n\t"					\
108a3e3131fSMathieu Desnoyers 		".pushsection __rseq_cs_ptr_array, \"aw\"\n\t"		\
109a3e3131fSMathieu Desnoyers 		".long 0x0, " __rseq_str(label) "b\n\t"			\
1102e155fb7SMathieu Desnoyers 		".popsection\n\t"
1112e155fb7SMathieu Desnoyers 
1124fe2088eSMathieu Desnoyers /*
1134fe2088eSMathieu Desnoyers  * Exit points of a rseq critical section consist of all instructions outside
1144fe2088eSMathieu Desnoyers  * of the critical section where a critical section can either branch to or
1154fe2088eSMathieu Desnoyers  * reach through the normal course of its execution. The abort IP and the
116a3e3131fSMathieu Desnoyers  * post-commit IP are already part of the __rseq_cs section and should not be
117a3e3131fSMathieu Desnoyers  * explicitly defined as additional exit points. Knowing all exit points is
1184fe2088eSMathieu Desnoyers  * useful to assist debuggers stepping over the critical section.
1194fe2088eSMathieu Desnoyers  */
1204fe2088eSMathieu Desnoyers #define RSEQ_ASM_DEFINE_EXIT_POINT(start_ip, exit_ip)				\
1214fe2088eSMathieu Desnoyers 		".pushsection __rseq_exit_point_array, \"aw\"\n\t"		\
1224fe2088eSMathieu Desnoyers 		/* 32-bit only supported on BE */				\
1234fe2088eSMathieu Desnoyers 		".long 0x0, " __rseq_str(start_ip) ", 0x0, " __rseq_str(exit_ip) "\n\t"	\
1244fe2088eSMathieu Desnoyers 		".popsection\n\t"
1254fe2088eSMathieu Desnoyers 
1262e155fb7SMathieu Desnoyers #define RSEQ_ASM_STORE_RSEQ_CS(label, cs_label, rseq_cs)			\
1272e155fb7SMathieu Desnoyers 		RSEQ_INJECT_ASM(1)						\
1282e155fb7SMathieu Desnoyers 		"lis %%r17, (" __rseq_str(cs_label) ")@ha\n\t"			\
1292e155fb7SMathieu Desnoyers 		"addi %%r17, %%r17, (" __rseq_str(cs_label) ")@l\n\t"		\
130de6b52a2SMathieu Desnoyers 		RSEQ_STORE_INT(rseq_cs) "%%r17, %[" __rseq_str(rseq_cs) "]\n\t"	\
1312e155fb7SMathieu Desnoyers 		__rseq_str(label) ":\n\t"
1322e155fb7SMathieu Desnoyers 
1332e155fb7SMathieu Desnoyers #endif /* #ifdef __PPC64__ */
1342e155fb7SMathieu Desnoyers 
1352e155fb7SMathieu Desnoyers #define RSEQ_ASM_DEFINE_TABLE(label, start_ip, post_commit_ip, abort_ip)	\
1362e155fb7SMathieu Desnoyers 		__RSEQ_ASM_DEFINE_TABLE(label, 0x0, 0x0, start_ip,		\
1372e155fb7SMathieu Desnoyers 					(post_commit_ip - start_ip), abort_ip)
1382e155fb7SMathieu Desnoyers 
1392e155fb7SMathieu Desnoyers #define RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, label)			\
1402e155fb7SMathieu Desnoyers 		RSEQ_INJECT_ASM(2)						\
141de6b52a2SMathieu Desnoyers 		RSEQ_LOAD_INT(current_cpu_id) "%%r17, %[" __rseq_str(current_cpu_id) "]\n\t" \
1422e155fb7SMathieu Desnoyers 		"cmpw cr7, %[" __rseq_str(cpu_id) "], %%r17\n\t"		\
1432e155fb7SMathieu Desnoyers 		"bne- cr7, " __rseq_str(label) "\n\t"
1442e155fb7SMathieu Desnoyers 
1452e155fb7SMathieu Desnoyers #define RSEQ_ASM_DEFINE_ABORT(label, abort_label)				\
1462e155fb7SMathieu Desnoyers 		".pushsection __rseq_failure, \"ax\"\n\t"			\
1472e155fb7SMathieu Desnoyers 		".long " __rseq_str(RSEQ_SIG) "\n\t"				\
1482e155fb7SMathieu Desnoyers 		__rseq_str(label) ":\n\t"					\
1492e155fb7SMathieu Desnoyers 		"b %l[" __rseq_str(abort_label) "]\n\t"				\
1502e155fb7SMathieu Desnoyers 		".popsection\n\t"
1512e155fb7SMathieu Desnoyers 
1522e155fb7SMathieu Desnoyers /*
1532e155fb7SMathieu Desnoyers  * RSEQ_ASM_OPs: asm operations for rseq
1542e155fb7SMathieu Desnoyers  * 	RSEQ_ASM_OP_R_*: has hard-code registers in it
1552e155fb7SMathieu Desnoyers  * 	RSEQ_ASM_OP_* (else): doesn't have hard-code registers(unless cr7)
1562e155fb7SMathieu Desnoyers  */
1572e155fb7SMathieu Desnoyers #define RSEQ_ASM_OP_CMPEQ(var, expect, label)					\
158de6b52a2SMathieu Desnoyers 		RSEQ_LOAD_LONG(var) "%%r17, %[" __rseq_str(var) "]\n\t"		\
159de6b52a2SMathieu Desnoyers 		RSEQ_CMP_LONG "cr7, %%r17, %[" __rseq_str(expect) "]\n\t"		\
1602e155fb7SMathieu Desnoyers 		"bne- cr7, " __rseq_str(label) "\n\t"
1612e155fb7SMathieu Desnoyers 
1622e155fb7SMathieu Desnoyers #define RSEQ_ASM_OP_CMPNE(var, expectnot, label)				\
163de6b52a2SMathieu Desnoyers 		RSEQ_LOAD_LONG(var) "%%r17, %[" __rseq_str(var) "]\n\t"		\
164de6b52a2SMathieu Desnoyers 		RSEQ_CMP_LONG "cr7, %%r17, %[" __rseq_str(expectnot) "]\n\t"		\
1652e155fb7SMathieu Desnoyers 		"beq- cr7, " __rseq_str(label) "\n\t"
1662e155fb7SMathieu Desnoyers 
1672e155fb7SMathieu Desnoyers #define RSEQ_ASM_OP_STORE(value, var)						\
168de6b52a2SMathieu Desnoyers 		RSEQ_STORE_LONG(var) "%[" __rseq_str(value) "], %[" __rseq_str(var) "]\n\t"
1692e155fb7SMathieu Desnoyers 
1702e155fb7SMathieu Desnoyers /* Load @var to r17 */
1712e155fb7SMathieu Desnoyers #define RSEQ_ASM_OP_R_LOAD(var)							\
172de6b52a2SMathieu Desnoyers 		RSEQ_LOAD_LONG(var) "%%r17, %[" __rseq_str(var) "]\n\t"
1732e155fb7SMathieu Desnoyers 
1742e155fb7SMathieu Desnoyers /* Store r17 to @var */
1752e155fb7SMathieu Desnoyers #define RSEQ_ASM_OP_R_STORE(var)						\
176de6b52a2SMathieu Desnoyers 		RSEQ_STORE_LONG(var) "%%r17, %[" __rseq_str(var) "]\n\t"
1772e155fb7SMathieu Desnoyers 
1782e155fb7SMathieu Desnoyers /* Add @count to r17 */
1792e155fb7SMathieu Desnoyers #define RSEQ_ASM_OP_R_ADD(count)						\
1802e155fb7SMathieu Desnoyers 		"add %%r17, %[" __rseq_str(count) "], %%r17\n\t"
1812e155fb7SMathieu Desnoyers 
1822e155fb7SMathieu Desnoyers /* Load (r17 + voffp) to r17 */
1832e155fb7SMathieu Desnoyers #define RSEQ_ASM_OP_R_LOADX(voffp)						\
184de6b52a2SMathieu Desnoyers 		RSEQ_LOADX_LONG "%%r17, %[" __rseq_str(voffp) "], %%r17\n\t"
1852e155fb7SMathieu Desnoyers 
1862e155fb7SMathieu Desnoyers /* TODO: implement a faster memcpy. */
1872e155fb7SMathieu Desnoyers #define RSEQ_ASM_OP_R_MEMCPY() \
188de6b52a2SMathieu Desnoyers 		RSEQ_CMP_LONG_INT "%%r19, 0\n\t" \
1892e155fb7SMathieu Desnoyers 		"beq 333f\n\t" \
1902e155fb7SMathieu Desnoyers 		"addi %%r20, %%r20, -1\n\t" \
1912e155fb7SMathieu Desnoyers 		"addi %%r21, %%r21, -1\n\t" \
1922e155fb7SMathieu Desnoyers 		"222:\n\t" \
1932e155fb7SMathieu Desnoyers 		"lbzu %%r18, 1(%%r20)\n\t" \
1942e155fb7SMathieu Desnoyers 		"stbu %%r18, 1(%%r21)\n\t" \
1952e155fb7SMathieu Desnoyers 		"addi %%r19, %%r19, -1\n\t" \
196de6b52a2SMathieu Desnoyers 		RSEQ_CMP_LONG_INT "%%r19, 0\n\t" \
1972e155fb7SMathieu Desnoyers 		"bne 222b\n\t" \
1982e155fb7SMathieu Desnoyers 		"333:\n\t" \
1992e155fb7SMathieu Desnoyers 
2002e155fb7SMathieu Desnoyers #define RSEQ_ASM_OP_R_FINAL_STORE(var, post_commit_label)			\
201de6b52a2SMathieu Desnoyers 		RSEQ_STORE_LONG(var) "%%r17, %[" __rseq_str(var) "]\n\t"			\
2022e155fb7SMathieu Desnoyers 		__rseq_str(post_commit_label) ":\n\t"
2032e155fb7SMathieu Desnoyers 
2042e155fb7SMathieu Desnoyers #define RSEQ_ASM_OP_FINAL_STORE(value, var, post_commit_label)			\
205de6b52a2SMathieu Desnoyers 		RSEQ_STORE_LONG(var) "%[" __rseq_str(value) "], %[" __rseq_str(var) "]\n\t" \
2062e155fb7SMathieu Desnoyers 		__rseq_str(post_commit_label) ":\n\t"
2072e155fb7SMathieu Desnoyers 
208e61bd94cSMathieu Desnoyers /* Per-cpu-id indexing. */
2092e155fb7SMathieu Desnoyers 
210e61bd94cSMathieu Desnoyers #define RSEQ_TEMPLATE_CPU_ID
211e61bd94cSMathieu Desnoyers #define RSEQ_TEMPLATE_MO_RELAXED
212e61bd94cSMathieu Desnoyers #include "rseq-ppc-bits.h"
213e61bd94cSMathieu Desnoyers #undef RSEQ_TEMPLATE_MO_RELAXED
2142e155fb7SMathieu Desnoyers 
215e61bd94cSMathieu Desnoyers #define RSEQ_TEMPLATE_MO_RELEASE
216e61bd94cSMathieu Desnoyers #include "rseq-ppc-bits.h"
217e61bd94cSMathieu Desnoyers #undef RSEQ_TEMPLATE_MO_RELEASE
218e61bd94cSMathieu Desnoyers #undef RSEQ_TEMPLATE_CPU_ID
2192e155fb7SMathieu Desnoyers 
220e61bd94cSMathieu Desnoyers /* Per-mm-cid indexing. */
2212e155fb7SMathieu Desnoyers 
222e61bd94cSMathieu Desnoyers #define RSEQ_TEMPLATE_MM_CID
223e61bd94cSMathieu Desnoyers #define RSEQ_TEMPLATE_MO_RELAXED
224e61bd94cSMathieu Desnoyers #include "rseq-ppc-bits.h"
225e61bd94cSMathieu Desnoyers #undef RSEQ_TEMPLATE_MO_RELAXED
2262e155fb7SMathieu Desnoyers 
227e61bd94cSMathieu Desnoyers #define RSEQ_TEMPLATE_MO_RELEASE
228e61bd94cSMathieu Desnoyers #include "rseq-ppc-bits.h"
229e61bd94cSMathieu Desnoyers #undef RSEQ_TEMPLATE_MO_RELEASE
230e61bd94cSMathieu Desnoyers #undef RSEQ_TEMPLATE_MM_CID
2312e155fb7SMathieu Desnoyers 
232e61bd94cSMathieu Desnoyers /* APIs which are not based on cpu ids. */
2332e155fb7SMathieu Desnoyers 
234e61bd94cSMathieu Desnoyers #define RSEQ_TEMPLATE_CPU_ID_NONE
235e61bd94cSMathieu Desnoyers #define RSEQ_TEMPLATE_MO_RELAXED
236e61bd94cSMathieu Desnoyers #include "rseq-ppc-bits.h"
237e61bd94cSMathieu Desnoyers #undef RSEQ_TEMPLATE_MO_RELAXED
238e61bd94cSMathieu Desnoyers #undef RSEQ_TEMPLATE_CPU_ID_NONE
239