18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: LGPL-2.1 OR MIT */
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Author: Paul Burton <paul.burton@mips.com>
48c2ecf20Sopenharmony_ci * (C) Copyright 2018 MIPS Tech LLC
58c2ecf20Sopenharmony_ci *
68c2ecf20Sopenharmony_ci * Based on rseq-arm.h:
78c2ecf20Sopenharmony_ci * (C) Copyright 2016-2018 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
88c2ecf20Sopenharmony_ci */
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci/*
118c2ecf20Sopenharmony_ci * RSEQ_SIG uses the break instruction. The instruction pattern is:
128c2ecf20Sopenharmony_ci *
138c2ecf20Sopenharmony_ci * On MIPS:
148c2ecf20Sopenharmony_ci *	0350000d        break     0x350
158c2ecf20Sopenharmony_ci *
168c2ecf20Sopenharmony_ci * On nanoMIPS:
178c2ecf20Sopenharmony_ci *      00100350        break     0x350
188c2ecf20Sopenharmony_ci *
198c2ecf20Sopenharmony_ci * On microMIPS:
208c2ecf20Sopenharmony_ci *      0000d407        break     0x350
218c2ecf20Sopenharmony_ci *
228c2ecf20Sopenharmony_ci * For nanoMIPS32 and microMIPS, the instruction stream is encoded as 16-bit
238c2ecf20Sopenharmony_ci * halfwords, so the signature halfwords need to be swapped accordingly for
248c2ecf20Sopenharmony_ci * little-endian.
258c2ecf20Sopenharmony_ci */
268c2ecf20Sopenharmony_ci#if defined(__nanomips__)
278c2ecf20Sopenharmony_ci# ifdef __MIPSEL__
288c2ecf20Sopenharmony_ci#  define RSEQ_SIG	0x03500010
298c2ecf20Sopenharmony_ci# else
308c2ecf20Sopenharmony_ci#  define RSEQ_SIG	0x00100350
318c2ecf20Sopenharmony_ci# endif
328c2ecf20Sopenharmony_ci#elif defined(__mips_micromips)
338c2ecf20Sopenharmony_ci# ifdef __MIPSEL__
348c2ecf20Sopenharmony_ci#  define RSEQ_SIG	0xd4070000
358c2ecf20Sopenharmony_ci# else
368c2ecf20Sopenharmony_ci#  define RSEQ_SIG	0x0000d407
378c2ecf20Sopenharmony_ci# endif
388c2ecf20Sopenharmony_ci#elif defined(__mips__)
398c2ecf20Sopenharmony_ci# define RSEQ_SIG	0x0350000d
408c2ecf20Sopenharmony_ci#else
418c2ecf20Sopenharmony_ci/* Unknown MIPS architecture. */
428c2ecf20Sopenharmony_ci#endif
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_ci#define rseq_smp_mb()	__asm__ __volatile__ ("sync" ::: "memory")
458c2ecf20Sopenharmony_ci#define rseq_smp_rmb()	rseq_smp_mb()
468c2ecf20Sopenharmony_ci#define rseq_smp_wmb()	rseq_smp_mb()
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_ci#define rseq_smp_load_acquire(p)					\
498c2ecf20Sopenharmony_ci__extension__ ({							\
508c2ecf20Sopenharmony_ci	__typeof(*p) ____p1 = RSEQ_READ_ONCE(*p);			\
518c2ecf20Sopenharmony_ci	rseq_smp_mb();							\
528c2ecf20Sopenharmony_ci	____p1;								\
538c2ecf20Sopenharmony_ci})
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ci#define rseq_smp_acquire__after_ctrl_dep()	rseq_smp_rmb()
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_ci#define rseq_smp_store_release(p, v)					\
588c2ecf20Sopenharmony_cido {									\
598c2ecf20Sopenharmony_ci	rseq_smp_mb();							\
608c2ecf20Sopenharmony_ci	RSEQ_WRITE_ONCE(*p, v);						\
618c2ecf20Sopenharmony_ci} while (0)
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ci#ifdef RSEQ_SKIP_FASTPATH
648c2ecf20Sopenharmony_ci#include "rseq-skip.h"
658c2ecf20Sopenharmony_ci#else /* !RSEQ_SKIP_FASTPATH */
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_ci#if _MIPS_SZLONG == 64
688c2ecf20Sopenharmony_ci# define LONG			".dword"
698c2ecf20Sopenharmony_ci# define LONG_LA		"dla"
708c2ecf20Sopenharmony_ci# define LONG_L			"ld"
718c2ecf20Sopenharmony_ci# define LONG_S			"sd"
728c2ecf20Sopenharmony_ci# define LONG_ADDI		"daddiu"
738c2ecf20Sopenharmony_ci# define U32_U64_PAD(x)		x
748c2ecf20Sopenharmony_ci#elif _MIPS_SZLONG == 32
758c2ecf20Sopenharmony_ci# define LONG			".word"
768c2ecf20Sopenharmony_ci# define LONG_LA		"la"
778c2ecf20Sopenharmony_ci# define LONG_L			"lw"
788c2ecf20Sopenharmony_ci# define LONG_S			"sw"
798c2ecf20Sopenharmony_ci# define LONG_ADDI		"addiu"
808c2ecf20Sopenharmony_ci# ifdef __BIG_ENDIAN
818c2ecf20Sopenharmony_ci#  define U32_U64_PAD(x)	"0x0, " x
828c2ecf20Sopenharmony_ci# else
838c2ecf20Sopenharmony_ci#  define U32_U64_PAD(x)	x ", 0x0"
848c2ecf20Sopenharmony_ci# endif
858c2ecf20Sopenharmony_ci#else
868c2ecf20Sopenharmony_ci# error unsupported _MIPS_SZLONG
878c2ecf20Sopenharmony_ci#endif
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_ci#define __RSEQ_ASM_DEFINE_TABLE(label, version, flags, start_ip, \
908c2ecf20Sopenharmony_ci				post_commit_offset, abort_ip) \
918c2ecf20Sopenharmony_ci		".pushsection __rseq_cs, \"aw\"\n\t" \
928c2ecf20Sopenharmony_ci		".balign 32\n\t" \
938c2ecf20Sopenharmony_ci		__rseq_str(label) ":\n\t"					\
948c2ecf20Sopenharmony_ci		".word " __rseq_str(version) ", " __rseq_str(flags) "\n\t" \
958c2ecf20Sopenharmony_ci		LONG " " U32_U64_PAD(__rseq_str(start_ip)) "\n\t" \
968c2ecf20Sopenharmony_ci		LONG " " U32_U64_PAD(__rseq_str(post_commit_offset)) "\n\t" \
978c2ecf20Sopenharmony_ci		LONG " " U32_U64_PAD(__rseq_str(abort_ip)) "\n\t" \
988c2ecf20Sopenharmony_ci		".popsection\n\t" \
998c2ecf20Sopenharmony_ci		".pushsection __rseq_cs_ptr_array, \"aw\"\n\t" \
1008c2ecf20Sopenharmony_ci		LONG " " U32_U64_PAD(__rseq_str(label) "b") "\n\t" \
1018c2ecf20Sopenharmony_ci		".popsection\n\t"
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_ci#define RSEQ_ASM_DEFINE_TABLE(label, start_ip, post_commit_ip, abort_ip) \
1048c2ecf20Sopenharmony_ci	__RSEQ_ASM_DEFINE_TABLE(label, 0x0, 0x0, start_ip, \
1058c2ecf20Sopenharmony_ci				(post_commit_ip - start_ip), abort_ip)
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_ci/*
1088c2ecf20Sopenharmony_ci * Exit points of a rseq critical section consist of all instructions outside
1098c2ecf20Sopenharmony_ci * of the critical section where a critical section can either branch to or
1108c2ecf20Sopenharmony_ci * reach through the normal course of its execution. The abort IP and the
1118c2ecf20Sopenharmony_ci * post-commit IP are already part of the __rseq_cs section and should not be
1128c2ecf20Sopenharmony_ci * explicitly defined as additional exit points. Knowing all exit points is
1138c2ecf20Sopenharmony_ci * useful to assist debuggers stepping over the critical section.
1148c2ecf20Sopenharmony_ci */
1158c2ecf20Sopenharmony_ci#define RSEQ_ASM_DEFINE_EXIT_POINT(start_ip, exit_ip) \
1168c2ecf20Sopenharmony_ci		".pushsection __rseq_exit_point_array, \"aw\"\n\t" \
1178c2ecf20Sopenharmony_ci		LONG " " U32_U64_PAD(__rseq_str(start_ip)) "\n\t" \
1188c2ecf20Sopenharmony_ci		LONG " " U32_U64_PAD(__rseq_str(exit_ip)) "\n\t" \
1198c2ecf20Sopenharmony_ci		".popsection\n\t"
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_ci#define RSEQ_ASM_STORE_RSEQ_CS(label, cs_label, rseq_cs) \
1228c2ecf20Sopenharmony_ci		RSEQ_INJECT_ASM(1) \
1238c2ecf20Sopenharmony_ci		LONG_LA " $4, " __rseq_str(cs_label) "\n\t" \
1248c2ecf20Sopenharmony_ci		LONG_S  " $4, %[" __rseq_str(rseq_cs) "]\n\t" \
1258c2ecf20Sopenharmony_ci		__rseq_str(label) ":\n\t"
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_ci#define RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, label) \
1288c2ecf20Sopenharmony_ci		RSEQ_INJECT_ASM(2) \
1298c2ecf20Sopenharmony_ci		"lw  $4, %[" __rseq_str(current_cpu_id) "]\n\t" \
1308c2ecf20Sopenharmony_ci		"bne $4, %[" __rseq_str(cpu_id) "], " __rseq_str(label) "\n\t"
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_ci#define __RSEQ_ASM_DEFINE_ABORT(table_label, label, teardown, \
1338c2ecf20Sopenharmony_ci				abort_label, version, flags, \
1348c2ecf20Sopenharmony_ci				start_ip, post_commit_offset, abort_ip) \
1358c2ecf20Sopenharmony_ci		".balign 32\n\t" \
1368c2ecf20Sopenharmony_ci		__rseq_str(table_label) ":\n\t" \
1378c2ecf20Sopenharmony_ci		".word " __rseq_str(version) ", " __rseq_str(flags) "\n\t" \
1388c2ecf20Sopenharmony_ci		LONG " " U32_U64_PAD(__rseq_str(start_ip)) "\n\t" \
1398c2ecf20Sopenharmony_ci		LONG " " U32_U64_PAD(__rseq_str(post_commit_offset)) "\n\t" \
1408c2ecf20Sopenharmony_ci		LONG " " U32_U64_PAD(__rseq_str(abort_ip)) "\n\t" \
1418c2ecf20Sopenharmony_ci		".word " __rseq_str(RSEQ_SIG) "\n\t" \
1428c2ecf20Sopenharmony_ci		__rseq_str(label) ":\n\t" \
1438c2ecf20Sopenharmony_ci		teardown \
1448c2ecf20Sopenharmony_ci		"b %l[" __rseq_str(abort_label) "]\n\t"
1458c2ecf20Sopenharmony_ci
1468c2ecf20Sopenharmony_ci#define RSEQ_ASM_DEFINE_ABORT(table_label, label, teardown, abort_label, \
1478c2ecf20Sopenharmony_ci			      start_ip, post_commit_ip, abort_ip) \
1488c2ecf20Sopenharmony_ci	__RSEQ_ASM_DEFINE_ABORT(table_label, label, teardown, \
1498c2ecf20Sopenharmony_ci				abort_label, 0x0, 0x0, start_ip, \
1508c2ecf20Sopenharmony_ci				(post_commit_ip - start_ip), abort_ip)
1518c2ecf20Sopenharmony_ci
1528c2ecf20Sopenharmony_ci#define RSEQ_ASM_DEFINE_CMPFAIL(label, teardown, cmpfail_label) \
1538c2ecf20Sopenharmony_ci		__rseq_str(label) ":\n\t" \
1548c2ecf20Sopenharmony_ci		teardown \
1558c2ecf20Sopenharmony_ci		"b %l[" __rseq_str(cmpfail_label) "]\n\t"
1568c2ecf20Sopenharmony_ci
1578c2ecf20Sopenharmony_cistatic inline __attribute__((always_inline))
1588c2ecf20Sopenharmony_ciint rseq_cmpeqv_storev(intptr_t *v, intptr_t expect, intptr_t newv, int cpu)
1598c2ecf20Sopenharmony_ci{
1608c2ecf20Sopenharmony_ci	RSEQ_INJECT_C(9)
1618c2ecf20Sopenharmony_ci
1628c2ecf20Sopenharmony_ci	__asm__ __volatile__ goto (
1638c2ecf20Sopenharmony_ci		RSEQ_ASM_DEFINE_TABLE(9, 1f, 2f, 4f) /* start, commit, abort */
1648c2ecf20Sopenharmony_ci		RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[cmpfail])
1658c2ecf20Sopenharmony_ci#ifdef RSEQ_COMPARE_TWICE
1668c2ecf20Sopenharmony_ci		RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error1])
1678c2ecf20Sopenharmony_ci		RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error2])
1688c2ecf20Sopenharmony_ci#endif
1698c2ecf20Sopenharmony_ci		/* Start rseq by storing table entry pointer into rseq_cs. */
1708c2ecf20Sopenharmony_ci		RSEQ_ASM_STORE_RSEQ_CS(1, 3f, rseq_cs)
1718c2ecf20Sopenharmony_ci		RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f)
1728c2ecf20Sopenharmony_ci		RSEQ_INJECT_ASM(3)
1738c2ecf20Sopenharmony_ci		LONG_L " $4, %[v]\n\t"
1748c2ecf20Sopenharmony_ci		"bne $4, %[expect], %l[cmpfail]\n\t"
1758c2ecf20Sopenharmony_ci		RSEQ_INJECT_ASM(4)
1768c2ecf20Sopenharmony_ci#ifdef RSEQ_COMPARE_TWICE
1778c2ecf20Sopenharmony_ci		RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1])
1788c2ecf20Sopenharmony_ci		LONG_L " $4, %[v]\n\t"
1798c2ecf20Sopenharmony_ci		"bne $4, %[expect], %l[error2]\n\t"
1808c2ecf20Sopenharmony_ci#endif
1818c2ecf20Sopenharmony_ci		/* final store */
1828c2ecf20Sopenharmony_ci		LONG_S " %[newv], %[v]\n\t"
1838c2ecf20Sopenharmony_ci		"2:\n\t"
1848c2ecf20Sopenharmony_ci		RSEQ_INJECT_ASM(5)
1858c2ecf20Sopenharmony_ci		"b 5f\n\t"
1868c2ecf20Sopenharmony_ci		RSEQ_ASM_DEFINE_ABORT(3, 4, "", abort, 1b, 2b, 4f)
1878c2ecf20Sopenharmony_ci		"5:\n\t"
1888c2ecf20Sopenharmony_ci		: /* gcc asm goto does not allow outputs */
1898c2ecf20Sopenharmony_ci		: [cpu_id]		"r" (cpu),
1908c2ecf20Sopenharmony_ci		  [current_cpu_id]	"m" (rseq_get_abi()->cpu_id),
1918c2ecf20Sopenharmony_ci		  [rseq_cs]		"m" (rseq_get_abi()->rseq_cs.arch.ptr),
1928c2ecf20Sopenharmony_ci		  [v]			"m" (*v),
1938c2ecf20Sopenharmony_ci		  [expect]		"r" (expect),
1948c2ecf20Sopenharmony_ci		  [newv]		"r" (newv)
1958c2ecf20Sopenharmony_ci		  RSEQ_INJECT_INPUT
1968c2ecf20Sopenharmony_ci		: "$4", "memory"
1978c2ecf20Sopenharmony_ci		  RSEQ_INJECT_CLOBBER
1988c2ecf20Sopenharmony_ci		: abort, cmpfail
1998c2ecf20Sopenharmony_ci#ifdef RSEQ_COMPARE_TWICE
2008c2ecf20Sopenharmony_ci		  , error1, error2
2018c2ecf20Sopenharmony_ci#endif
2028c2ecf20Sopenharmony_ci	);
2038c2ecf20Sopenharmony_ci	return 0;
2048c2ecf20Sopenharmony_ciabort:
2058c2ecf20Sopenharmony_ci	RSEQ_INJECT_FAILED
2068c2ecf20Sopenharmony_ci	return -1;
2078c2ecf20Sopenharmony_cicmpfail:
2088c2ecf20Sopenharmony_ci	return 1;
2098c2ecf20Sopenharmony_ci#ifdef RSEQ_COMPARE_TWICE
2108c2ecf20Sopenharmony_cierror1:
2118c2ecf20Sopenharmony_ci	rseq_bug("cpu_id comparison failed");
2128c2ecf20Sopenharmony_cierror2:
2138c2ecf20Sopenharmony_ci	rseq_bug("expected value comparison failed");
2148c2ecf20Sopenharmony_ci#endif
2158c2ecf20Sopenharmony_ci}
2168c2ecf20Sopenharmony_ci
2178c2ecf20Sopenharmony_cistatic inline __attribute__((always_inline))
2188c2ecf20Sopenharmony_ciint rseq_cmpnev_storeoffp_load(intptr_t *v, intptr_t expectnot,
2198c2ecf20Sopenharmony_ci			       long voffp, intptr_t *load, int cpu)
2208c2ecf20Sopenharmony_ci{
2218c2ecf20Sopenharmony_ci	RSEQ_INJECT_C(9)
2228c2ecf20Sopenharmony_ci
2238c2ecf20Sopenharmony_ci	__asm__ __volatile__ goto (
2248c2ecf20Sopenharmony_ci		RSEQ_ASM_DEFINE_TABLE(9, 1f, 2f, 4f) /* start, commit, abort */
2258c2ecf20Sopenharmony_ci		RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[cmpfail])
2268c2ecf20Sopenharmony_ci#ifdef RSEQ_COMPARE_TWICE
2278c2ecf20Sopenharmony_ci		RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error1])
2288c2ecf20Sopenharmony_ci		RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error2])
2298c2ecf20Sopenharmony_ci#endif
2308c2ecf20Sopenharmony_ci		/* Start rseq by storing table entry pointer into rseq_cs. */
2318c2ecf20Sopenharmony_ci		RSEQ_ASM_STORE_RSEQ_CS(1, 3f, rseq_cs)
2328c2ecf20Sopenharmony_ci		RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f)
2338c2ecf20Sopenharmony_ci		RSEQ_INJECT_ASM(3)
2348c2ecf20Sopenharmony_ci		LONG_L " $4, %[v]\n\t"
2358c2ecf20Sopenharmony_ci		"beq $4, %[expectnot], %l[cmpfail]\n\t"
2368c2ecf20Sopenharmony_ci		RSEQ_INJECT_ASM(4)
2378c2ecf20Sopenharmony_ci#ifdef RSEQ_COMPARE_TWICE
2388c2ecf20Sopenharmony_ci		RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1])
2398c2ecf20Sopenharmony_ci		LONG_L " $4, %[v]\n\t"
2408c2ecf20Sopenharmony_ci		"beq $4, %[expectnot], %l[error2]\n\t"
2418c2ecf20Sopenharmony_ci#endif
2428c2ecf20Sopenharmony_ci		LONG_S " $4, %[load]\n\t"
2438c2ecf20Sopenharmony_ci		LONG_ADDI " $4, %[voffp]\n\t"
2448c2ecf20Sopenharmony_ci		LONG_L " $4, 0($4)\n\t"
2458c2ecf20Sopenharmony_ci		/* final store */
2468c2ecf20Sopenharmony_ci		LONG_S " $4, %[v]\n\t"
2478c2ecf20Sopenharmony_ci		"2:\n\t"
2488c2ecf20Sopenharmony_ci		RSEQ_INJECT_ASM(5)
2498c2ecf20Sopenharmony_ci		"b 5f\n\t"
2508c2ecf20Sopenharmony_ci		RSEQ_ASM_DEFINE_ABORT(3, 4, "", abort, 1b, 2b, 4f)
2518c2ecf20Sopenharmony_ci		"5:\n\t"
2528c2ecf20Sopenharmony_ci		: /* gcc asm goto does not allow outputs */
2538c2ecf20Sopenharmony_ci		: [cpu_id]		"r" (cpu),
2548c2ecf20Sopenharmony_ci		  [current_cpu_id]	"m" (rseq_get_abi()->cpu_id),
2558c2ecf20Sopenharmony_ci		  [rseq_cs]		"m" (rseq_get_abi()->rseq_cs.arch.ptr),
2568c2ecf20Sopenharmony_ci		  /* final store input */
2578c2ecf20Sopenharmony_ci		  [v]			"m" (*v),
2588c2ecf20Sopenharmony_ci		  [expectnot]		"r" (expectnot),
2598c2ecf20Sopenharmony_ci		  [voffp]		"Ir" (voffp),
2608c2ecf20Sopenharmony_ci		  [load]		"m" (*load)
2618c2ecf20Sopenharmony_ci		  RSEQ_INJECT_INPUT
2628c2ecf20Sopenharmony_ci		: "$4", "memory"
2638c2ecf20Sopenharmony_ci		  RSEQ_INJECT_CLOBBER
2648c2ecf20Sopenharmony_ci		: abort, cmpfail
2658c2ecf20Sopenharmony_ci#ifdef RSEQ_COMPARE_TWICE
2668c2ecf20Sopenharmony_ci		  , error1, error2
2678c2ecf20Sopenharmony_ci#endif
2688c2ecf20Sopenharmony_ci	);
2698c2ecf20Sopenharmony_ci	return 0;
2708c2ecf20Sopenharmony_ciabort:
2718c2ecf20Sopenharmony_ci	RSEQ_INJECT_FAILED
2728c2ecf20Sopenharmony_ci	return -1;
2738c2ecf20Sopenharmony_cicmpfail:
2748c2ecf20Sopenharmony_ci	return 1;
2758c2ecf20Sopenharmony_ci#ifdef RSEQ_COMPARE_TWICE
2768c2ecf20Sopenharmony_cierror1:
2778c2ecf20Sopenharmony_ci	rseq_bug("cpu_id comparison failed");
2788c2ecf20Sopenharmony_cierror2:
2798c2ecf20Sopenharmony_ci	rseq_bug("expected value comparison failed");
2808c2ecf20Sopenharmony_ci#endif
2818c2ecf20Sopenharmony_ci}
2828c2ecf20Sopenharmony_ci
2838c2ecf20Sopenharmony_cistatic inline __attribute__((always_inline))
2848c2ecf20Sopenharmony_ciint rseq_addv(intptr_t *v, intptr_t count, int cpu)
2858c2ecf20Sopenharmony_ci{
2868c2ecf20Sopenharmony_ci	RSEQ_INJECT_C(9)
2878c2ecf20Sopenharmony_ci
2888c2ecf20Sopenharmony_ci	__asm__ __volatile__ goto (
2898c2ecf20Sopenharmony_ci		RSEQ_ASM_DEFINE_TABLE(9, 1f, 2f, 4f) /* start, commit, abort */
2908c2ecf20Sopenharmony_ci#ifdef RSEQ_COMPARE_TWICE
2918c2ecf20Sopenharmony_ci		RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error1])
2928c2ecf20Sopenharmony_ci#endif
2938c2ecf20Sopenharmony_ci		/* Start rseq by storing table entry pointer into rseq_cs. */
2948c2ecf20Sopenharmony_ci		RSEQ_ASM_STORE_RSEQ_CS(1, 3f, rseq_cs)
2958c2ecf20Sopenharmony_ci		RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f)
2968c2ecf20Sopenharmony_ci		RSEQ_INJECT_ASM(3)
2978c2ecf20Sopenharmony_ci#ifdef RSEQ_COMPARE_TWICE
2988c2ecf20Sopenharmony_ci		RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1])
2998c2ecf20Sopenharmony_ci#endif
3008c2ecf20Sopenharmony_ci		LONG_L " $4, %[v]\n\t"
3018c2ecf20Sopenharmony_ci		LONG_ADDI " $4, %[count]\n\t"
3028c2ecf20Sopenharmony_ci		/* final store */
3038c2ecf20Sopenharmony_ci		LONG_S " $4, %[v]\n\t"
3048c2ecf20Sopenharmony_ci		"2:\n\t"
3058c2ecf20Sopenharmony_ci		RSEQ_INJECT_ASM(4)
3068c2ecf20Sopenharmony_ci		"b 5f\n\t"
3078c2ecf20Sopenharmony_ci		RSEQ_ASM_DEFINE_ABORT(3, 4, "", abort, 1b, 2b, 4f)
3088c2ecf20Sopenharmony_ci		"5:\n\t"
3098c2ecf20Sopenharmony_ci		: /* gcc asm goto does not allow outputs */
3108c2ecf20Sopenharmony_ci		: [cpu_id]		"r" (cpu),
3118c2ecf20Sopenharmony_ci		  [current_cpu_id]	"m" (rseq_get_abi()->cpu_id),
3128c2ecf20Sopenharmony_ci		  [rseq_cs]		"m" (rseq_get_abi()->rseq_cs.arch.ptr),
3138c2ecf20Sopenharmony_ci		  [v]			"m" (*v),
3148c2ecf20Sopenharmony_ci		  [count]		"Ir" (count)
3158c2ecf20Sopenharmony_ci		  RSEQ_INJECT_INPUT
3168c2ecf20Sopenharmony_ci		: "$4", "memory"
3178c2ecf20Sopenharmony_ci		  RSEQ_INJECT_CLOBBER
3188c2ecf20Sopenharmony_ci		: abort
3198c2ecf20Sopenharmony_ci#ifdef RSEQ_COMPARE_TWICE
3208c2ecf20Sopenharmony_ci		  , error1
3218c2ecf20Sopenharmony_ci#endif
3228c2ecf20Sopenharmony_ci	);
3238c2ecf20Sopenharmony_ci	return 0;
3248c2ecf20Sopenharmony_ciabort:
3258c2ecf20Sopenharmony_ci	RSEQ_INJECT_FAILED
3268c2ecf20Sopenharmony_ci	return -1;
3278c2ecf20Sopenharmony_ci#ifdef RSEQ_COMPARE_TWICE
3288c2ecf20Sopenharmony_cierror1:
3298c2ecf20Sopenharmony_ci	rseq_bug("cpu_id comparison failed");
3308c2ecf20Sopenharmony_ci#endif
3318c2ecf20Sopenharmony_ci}
3328c2ecf20Sopenharmony_ci
3338c2ecf20Sopenharmony_cistatic inline __attribute__((always_inline))
3348c2ecf20Sopenharmony_ciint rseq_cmpeqv_trystorev_storev(intptr_t *v, intptr_t expect,
3358c2ecf20Sopenharmony_ci				 intptr_t *v2, intptr_t newv2,
3368c2ecf20Sopenharmony_ci				 intptr_t newv, int cpu)
3378c2ecf20Sopenharmony_ci{
3388c2ecf20Sopenharmony_ci	RSEQ_INJECT_C(9)
3398c2ecf20Sopenharmony_ci
3408c2ecf20Sopenharmony_ci	__asm__ __volatile__ goto (
3418c2ecf20Sopenharmony_ci		RSEQ_ASM_DEFINE_TABLE(9, 1f, 2f, 4f) /* start, commit, abort */
3428c2ecf20Sopenharmony_ci		RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[cmpfail])
3438c2ecf20Sopenharmony_ci#ifdef RSEQ_COMPARE_TWICE
3448c2ecf20Sopenharmony_ci		RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error1])
3458c2ecf20Sopenharmony_ci		RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error2])
3468c2ecf20Sopenharmony_ci#endif
3478c2ecf20Sopenharmony_ci		/* Start rseq by storing table entry pointer into rseq_cs. */
3488c2ecf20Sopenharmony_ci		RSEQ_ASM_STORE_RSEQ_CS(1, 3f, rseq_cs)
3498c2ecf20Sopenharmony_ci		RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f)
3508c2ecf20Sopenharmony_ci		RSEQ_INJECT_ASM(3)
3518c2ecf20Sopenharmony_ci		LONG_L " $4, %[v]\n\t"
3528c2ecf20Sopenharmony_ci		"bne $4, %[expect], %l[cmpfail]\n\t"
3538c2ecf20Sopenharmony_ci		RSEQ_INJECT_ASM(4)
3548c2ecf20Sopenharmony_ci#ifdef RSEQ_COMPARE_TWICE
3558c2ecf20Sopenharmony_ci		RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1])
3568c2ecf20Sopenharmony_ci		LONG_L " $4, %[v]\n\t"
3578c2ecf20Sopenharmony_ci		"bne $4, %[expect], %l[error2]\n\t"
3588c2ecf20Sopenharmony_ci#endif
3598c2ecf20Sopenharmony_ci		/* try store */
3608c2ecf20Sopenharmony_ci		LONG_S " %[newv2], %[v2]\n\t"
3618c2ecf20Sopenharmony_ci		RSEQ_INJECT_ASM(5)
3628c2ecf20Sopenharmony_ci		/* final store */
3638c2ecf20Sopenharmony_ci		LONG_S " %[newv], %[v]\n\t"
3648c2ecf20Sopenharmony_ci		"2:\n\t"
3658c2ecf20Sopenharmony_ci		RSEQ_INJECT_ASM(6)
3668c2ecf20Sopenharmony_ci		"b 5f\n\t"
3678c2ecf20Sopenharmony_ci		RSEQ_ASM_DEFINE_ABORT(3, 4, "", abort, 1b, 2b, 4f)
3688c2ecf20Sopenharmony_ci		"5:\n\t"
3698c2ecf20Sopenharmony_ci		: /* gcc asm goto does not allow outputs */
3708c2ecf20Sopenharmony_ci		: [cpu_id]		"r" (cpu),
3718c2ecf20Sopenharmony_ci		  [current_cpu_id]	"m" (rseq_get_abi()->cpu_id),
3728c2ecf20Sopenharmony_ci		  [rseq_cs]		"m" (rseq_get_abi()->rseq_cs.arch.ptr),
3738c2ecf20Sopenharmony_ci		  /* try store input */
3748c2ecf20Sopenharmony_ci		  [v2]			"m" (*v2),
3758c2ecf20Sopenharmony_ci		  [newv2]		"r" (newv2),
3768c2ecf20Sopenharmony_ci		  /* final store input */
3778c2ecf20Sopenharmony_ci		  [v]			"m" (*v),
3788c2ecf20Sopenharmony_ci		  [expect]		"r" (expect),
3798c2ecf20Sopenharmony_ci		  [newv]		"r" (newv)
3808c2ecf20Sopenharmony_ci		  RSEQ_INJECT_INPUT
3818c2ecf20Sopenharmony_ci		: "$4", "memory"
3828c2ecf20Sopenharmony_ci		  RSEQ_INJECT_CLOBBER
3838c2ecf20Sopenharmony_ci		: abort, cmpfail
3848c2ecf20Sopenharmony_ci#ifdef RSEQ_COMPARE_TWICE
3858c2ecf20Sopenharmony_ci		  , error1, error2
3868c2ecf20Sopenharmony_ci#endif
3878c2ecf20Sopenharmony_ci	);
3888c2ecf20Sopenharmony_ci	return 0;
3898c2ecf20Sopenharmony_ciabort:
3908c2ecf20Sopenharmony_ci	RSEQ_INJECT_FAILED
3918c2ecf20Sopenharmony_ci	return -1;
3928c2ecf20Sopenharmony_cicmpfail:
3938c2ecf20Sopenharmony_ci	return 1;
3948c2ecf20Sopenharmony_ci#ifdef RSEQ_COMPARE_TWICE
3958c2ecf20Sopenharmony_cierror1:
3968c2ecf20Sopenharmony_ci	rseq_bug("cpu_id comparison failed");
3978c2ecf20Sopenharmony_cierror2:
3988c2ecf20Sopenharmony_ci	rseq_bug("expected value comparison failed");
3998c2ecf20Sopenharmony_ci#endif
4008c2ecf20Sopenharmony_ci}
4018c2ecf20Sopenharmony_ci
4028c2ecf20Sopenharmony_cistatic inline __attribute__((always_inline))
4038c2ecf20Sopenharmony_ciint rseq_cmpeqv_trystorev_storev_release(intptr_t *v, intptr_t expect,
4048c2ecf20Sopenharmony_ci					 intptr_t *v2, intptr_t newv2,
4058c2ecf20Sopenharmony_ci					 intptr_t newv, int cpu)
4068c2ecf20Sopenharmony_ci{
4078c2ecf20Sopenharmony_ci	RSEQ_INJECT_C(9)
4088c2ecf20Sopenharmony_ci
4098c2ecf20Sopenharmony_ci	__asm__ __volatile__ goto (
4108c2ecf20Sopenharmony_ci		RSEQ_ASM_DEFINE_TABLE(9, 1f, 2f, 4f) /* start, commit, abort */
4118c2ecf20Sopenharmony_ci		RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[cmpfail])
4128c2ecf20Sopenharmony_ci#ifdef RSEQ_COMPARE_TWICE
4138c2ecf20Sopenharmony_ci		RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error1])
4148c2ecf20Sopenharmony_ci		RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error2])
4158c2ecf20Sopenharmony_ci#endif
4168c2ecf20Sopenharmony_ci		/* Start rseq by storing table entry pointer into rseq_cs. */
4178c2ecf20Sopenharmony_ci		RSEQ_ASM_STORE_RSEQ_CS(1, 3f, rseq_cs)
4188c2ecf20Sopenharmony_ci		RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f)
4198c2ecf20Sopenharmony_ci		RSEQ_INJECT_ASM(3)
4208c2ecf20Sopenharmony_ci		LONG_L " $4, %[v]\n\t"
4218c2ecf20Sopenharmony_ci		"bne $4, %[expect], %l[cmpfail]\n\t"
4228c2ecf20Sopenharmony_ci		RSEQ_INJECT_ASM(4)
4238c2ecf20Sopenharmony_ci#ifdef RSEQ_COMPARE_TWICE
4248c2ecf20Sopenharmony_ci		RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1])
4258c2ecf20Sopenharmony_ci		LONG_L " $4, %[v]\n\t"
4268c2ecf20Sopenharmony_ci		"bne $4, %[expect], %l[error2]\n\t"
4278c2ecf20Sopenharmony_ci#endif
4288c2ecf20Sopenharmony_ci		/* try store */
4298c2ecf20Sopenharmony_ci		LONG_S " %[newv2], %[v2]\n\t"
4308c2ecf20Sopenharmony_ci		RSEQ_INJECT_ASM(5)
4318c2ecf20Sopenharmony_ci		"sync\n\t"	/* full sync provides store-release */
4328c2ecf20Sopenharmony_ci		/* final store */
4338c2ecf20Sopenharmony_ci		LONG_S " %[newv], %[v]\n\t"
4348c2ecf20Sopenharmony_ci		"2:\n\t"
4358c2ecf20Sopenharmony_ci		RSEQ_INJECT_ASM(6)
4368c2ecf20Sopenharmony_ci		"b 5f\n\t"
4378c2ecf20Sopenharmony_ci		RSEQ_ASM_DEFINE_ABORT(3, 4, "", abort, 1b, 2b, 4f)
4388c2ecf20Sopenharmony_ci		"5:\n\t"
4398c2ecf20Sopenharmony_ci		: /* gcc asm goto does not allow outputs */
4408c2ecf20Sopenharmony_ci		: [cpu_id]		"r" (cpu),
4418c2ecf20Sopenharmony_ci		  [current_cpu_id]	"m" (rseq_get_abi()->cpu_id),
4428c2ecf20Sopenharmony_ci		  [rseq_cs]		"m" (rseq_get_abi()->rseq_cs.arch.ptr),
4438c2ecf20Sopenharmony_ci		  /* try store input */
4448c2ecf20Sopenharmony_ci		  [v2]			"m" (*v2),
4458c2ecf20Sopenharmony_ci		  [newv2]		"r" (newv2),
4468c2ecf20Sopenharmony_ci		  /* final store input */
4478c2ecf20Sopenharmony_ci		  [v]			"m" (*v),
4488c2ecf20Sopenharmony_ci		  [expect]		"r" (expect),
4498c2ecf20Sopenharmony_ci		  [newv]		"r" (newv)
4508c2ecf20Sopenharmony_ci		  RSEQ_INJECT_INPUT
4518c2ecf20Sopenharmony_ci		: "$4", "memory"
4528c2ecf20Sopenharmony_ci		  RSEQ_INJECT_CLOBBER
4538c2ecf20Sopenharmony_ci		: abort, cmpfail
4548c2ecf20Sopenharmony_ci#ifdef RSEQ_COMPARE_TWICE
4558c2ecf20Sopenharmony_ci		  , error1, error2
4568c2ecf20Sopenharmony_ci#endif
4578c2ecf20Sopenharmony_ci	);
4588c2ecf20Sopenharmony_ci	return 0;
4598c2ecf20Sopenharmony_ciabort:
4608c2ecf20Sopenharmony_ci	RSEQ_INJECT_FAILED
4618c2ecf20Sopenharmony_ci	return -1;
4628c2ecf20Sopenharmony_cicmpfail:
4638c2ecf20Sopenharmony_ci	return 1;
4648c2ecf20Sopenharmony_ci#ifdef RSEQ_COMPARE_TWICE
4658c2ecf20Sopenharmony_cierror1:
4668c2ecf20Sopenharmony_ci	rseq_bug("cpu_id comparison failed");
4678c2ecf20Sopenharmony_cierror2:
4688c2ecf20Sopenharmony_ci	rseq_bug("expected value comparison failed");
4698c2ecf20Sopenharmony_ci#endif
4708c2ecf20Sopenharmony_ci}
4718c2ecf20Sopenharmony_ci
4728c2ecf20Sopenharmony_cistatic inline __attribute__((always_inline))
4738c2ecf20Sopenharmony_ciint rseq_cmpeqv_cmpeqv_storev(intptr_t *v, intptr_t expect,
4748c2ecf20Sopenharmony_ci			      intptr_t *v2, intptr_t expect2,
4758c2ecf20Sopenharmony_ci			      intptr_t newv, int cpu)
4768c2ecf20Sopenharmony_ci{
4778c2ecf20Sopenharmony_ci	RSEQ_INJECT_C(9)
4788c2ecf20Sopenharmony_ci
4798c2ecf20Sopenharmony_ci	__asm__ __volatile__ goto (
4808c2ecf20Sopenharmony_ci		RSEQ_ASM_DEFINE_TABLE(9, 1f, 2f, 4f) /* start, commit, abort */
4818c2ecf20Sopenharmony_ci		RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[cmpfail])
4828c2ecf20Sopenharmony_ci#ifdef RSEQ_COMPARE_TWICE
4838c2ecf20Sopenharmony_ci		RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error1])
4848c2ecf20Sopenharmony_ci		RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error2])
4858c2ecf20Sopenharmony_ci		RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error3])
4868c2ecf20Sopenharmony_ci#endif
4878c2ecf20Sopenharmony_ci		/* Start rseq by storing table entry pointer into rseq_cs. */
4888c2ecf20Sopenharmony_ci		RSEQ_ASM_STORE_RSEQ_CS(1, 3f, rseq_cs)
4898c2ecf20Sopenharmony_ci		RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f)
4908c2ecf20Sopenharmony_ci		RSEQ_INJECT_ASM(3)
4918c2ecf20Sopenharmony_ci		LONG_L " $4, %[v]\n\t"
4928c2ecf20Sopenharmony_ci		"bne $4, %[expect], %l[cmpfail]\n\t"
4938c2ecf20Sopenharmony_ci		RSEQ_INJECT_ASM(4)
4948c2ecf20Sopenharmony_ci		LONG_L " $4, %[v2]\n\t"
4958c2ecf20Sopenharmony_ci		"bne $4, %[expect2], %l[cmpfail]\n\t"
4968c2ecf20Sopenharmony_ci		RSEQ_INJECT_ASM(5)
4978c2ecf20Sopenharmony_ci#ifdef RSEQ_COMPARE_TWICE
4988c2ecf20Sopenharmony_ci		RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1])
4998c2ecf20Sopenharmony_ci		LONG_L " $4, %[v]\n\t"
5008c2ecf20Sopenharmony_ci		"bne $4, %[expect], %l[error2]\n\t"
5018c2ecf20Sopenharmony_ci		LONG_L " $4, %[v2]\n\t"
5028c2ecf20Sopenharmony_ci		"bne $4, %[expect2], %l[error3]\n\t"
5038c2ecf20Sopenharmony_ci#endif
5048c2ecf20Sopenharmony_ci		/* final store */
5058c2ecf20Sopenharmony_ci		LONG_S " %[newv], %[v]\n\t"
5068c2ecf20Sopenharmony_ci		"2:\n\t"
5078c2ecf20Sopenharmony_ci		RSEQ_INJECT_ASM(6)
5088c2ecf20Sopenharmony_ci		"b 5f\n\t"
5098c2ecf20Sopenharmony_ci		RSEQ_ASM_DEFINE_ABORT(3, 4, "", abort, 1b, 2b, 4f)
5108c2ecf20Sopenharmony_ci		"5:\n\t"
5118c2ecf20Sopenharmony_ci		: /* gcc asm goto does not allow outputs */
5128c2ecf20Sopenharmony_ci		: [cpu_id]		"r" (cpu),
5138c2ecf20Sopenharmony_ci		  [current_cpu_id]	"m" (rseq_get_abi()->cpu_id),
5148c2ecf20Sopenharmony_ci		  [rseq_cs]		"m" (rseq_get_abi()->rseq_cs.arch.ptr),
5158c2ecf20Sopenharmony_ci		  /* cmp2 input */
5168c2ecf20Sopenharmony_ci		  [v2]			"m" (*v2),
5178c2ecf20Sopenharmony_ci		  [expect2]		"r" (expect2),
5188c2ecf20Sopenharmony_ci		  /* final store input */
5198c2ecf20Sopenharmony_ci		  [v]			"m" (*v),
5208c2ecf20Sopenharmony_ci		  [expect]		"r" (expect),
5218c2ecf20Sopenharmony_ci		  [newv]		"r" (newv)
5228c2ecf20Sopenharmony_ci		  RSEQ_INJECT_INPUT
5238c2ecf20Sopenharmony_ci		: "$4", "memory"
5248c2ecf20Sopenharmony_ci		  RSEQ_INJECT_CLOBBER
5258c2ecf20Sopenharmony_ci		: abort, cmpfail
5268c2ecf20Sopenharmony_ci#ifdef RSEQ_COMPARE_TWICE
5278c2ecf20Sopenharmony_ci		  , error1, error2, error3
5288c2ecf20Sopenharmony_ci#endif
5298c2ecf20Sopenharmony_ci	);
5308c2ecf20Sopenharmony_ci	return 0;
5318c2ecf20Sopenharmony_ciabort:
5328c2ecf20Sopenharmony_ci	RSEQ_INJECT_FAILED
5338c2ecf20Sopenharmony_ci	return -1;
5348c2ecf20Sopenharmony_cicmpfail:
5358c2ecf20Sopenharmony_ci	return 1;
5368c2ecf20Sopenharmony_ci#ifdef RSEQ_COMPARE_TWICE
5378c2ecf20Sopenharmony_cierror1:
5388c2ecf20Sopenharmony_ci	rseq_bug("cpu_id comparison failed");
5398c2ecf20Sopenharmony_cierror2:
5408c2ecf20Sopenharmony_ci	rseq_bug("1st expected value comparison failed");
5418c2ecf20Sopenharmony_cierror3:
5428c2ecf20Sopenharmony_ci	rseq_bug("2nd expected value comparison failed");
5438c2ecf20Sopenharmony_ci#endif
5448c2ecf20Sopenharmony_ci}
5458c2ecf20Sopenharmony_ci
5468c2ecf20Sopenharmony_cistatic inline __attribute__((always_inline))
5478c2ecf20Sopenharmony_ciint rseq_cmpeqv_trymemcpy_storev(intptr_t *v, intptr_t expect,
5488c2ecf20Sopenharmony_ci				 void *dst, void *src, size_t len,
5498c2ecf20Sopenharmony_ci				 intptr_t newv, int cpu)
5508c2ecf20Sopenharmony_ci{
5518c2ecf20Sopenharmony_ci	uintptr_t rseq_scratch[3];
5528c2ecf20Sopenharmony_ci
5538c2ecf20Sopenharmony_ci	RSEQ_INJECT_C(9)
5548c2ecf20Sopenharmony_ci
5558c2ecf20Sopenharmony_ci	__asm__ __volatile__ goto (
5568c2ecf20Sopenharmony_ci		RSEQ_ASM_DEFINE_TABLE(9, 1f, 2f, 4f) /* start, commit, abort */
5578c2ecf20Sopenharmony_ci		RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[cmpfail])
5588c2ecf20Sopenharmony_ci#ifdef RSEQ_COMPARE_TWICE
5598c2ecf20Sopenharmony_ci		RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error1])
5608c2ecf20Sopenharmony_ci		RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error2])
5618c2ecf20Sopenharmony_ci#endif
5628c2ecf20Sopenharmony_ci		LONG_S " %[src], %[rseq_scratch0]\n\t"
5638c2ecf20Sopenharmony_ci		LONG_S "  %[dst], %[rseq_scratch1]\n\t"
5648c2ecf20Sopenharmony_ci		LONG_S " %[len], %[rseq_scratch2]\n\t"
5658c2ecf20Sopenharmony_ci		/* Start rseq by storing table entry pointer into rseq_cs. */
5668c2ecf20Sopenharmony_ci		RSEQ_ASM_STORE_RSEQ_CS(1, 3f, rseq_cs)
5678c2ecf20Sopenharmony_ci		RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f)
5688c2ecf20Sopenharmony_ci		RSEQ_INJECT_ASM(3)
5698c2ecf20Sopenharmony_ci		LONG_L " $4, %[v]\n\t"
5708c2ecf20Sopenharmony_ci		"bne $4, %[expect], 5f\n\t"
5718c2ecf20Sopenharmony_ci		RSEQ_INJECT_ASM(4)
5728c2ecf20Sopenharmony_ci#ifdef RSEQ_COMPARE_TWICE
5738c2ecf20Sopenharmony_ci		RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 6f)
5748c2ecf20Sopenharmony_ci		LONG_L " $4, %[v]\n\t"
5758c2ecf20Sopenharmony_ci		"bne $4, %[expect], 7f\n\t"
5768c2ecf20Sopenharmony_ci#endif
5778c2ecf20Sopenharmony_ci		/* try memcpy */
5788c2ecf20Sopenharmony_ci		"beqz %[len], 333f\n\t" \
5798c2ecf20Sopenharmony_ci		"222:\n\t" \
5808c2ecf20Sopenharmony_ci		"lb   $4, 0(%[src])\n\t" \
5818c2ecf20Sopenharmony_ci		"sb   $4, 0(%[dst])\n\t" \
5828c2ecf20Sopenharmony_ci		LONG_ADDI " %[src], 1\n\t" \
5838c2ecf20Sopenharmony_ci		LONG_ADDI " %[dst], 1\n\t" \
5848c2ecf20Sopenharmony_ci		LONG_ADDI " %[len], -1\n\t" \
5858c2ecf20Sopenharmony_ci		"bnez %[len], 222b\n\t" \
5868c2ecf20Sopenharmony_ci		"333:\n\t" \
5878c2ecf20Sopenharmony_ci		RSEQ_INJECT_ASM(5)
5888c2ecf20Sopenharmony_ci		/* final store */
5898c2ecf20Sopenharmony_ci		LONG_S " %[newv], %[v]\n\t"
5908c2ecf20Sopenharmony_ci		"2:\n\t"
5918c2ecf20Sopenharmony_ci		RSEQ_INJECT_ASM(6)
5928c2ecf20Sopenharmony_ci		/* teardown */
5938c2ecf20Sopenharmony_ci		LONG_L " %[len], %[rseq_scratch2]\n\t"
5948c2ecf20Sopenharmony_ci		LONG_L " %[dst], %[rseq_scratch1]\n\t"
5958c2ecf20Sopenharmony_ci		LONG_L " %[src], %[rseq_scratch0]\n\t"
5968c2ecf20Sopenharmony_ci		"b 8f\n\t"
5978c2ecf20Sopenharmony_ci		RSEQ_ASM_DEFINE_ABORT(3, 4,
5988c2ecf20Sopenharmony_ci				      /* teardown */
5998c2ecf20Sopenharmony_ci				      LONG_L " %[len], %[rseq_scratch2]\n\t"
6008c2ecf20Sopenharmony_ci				      LONG_L " %[dst], %[rseq_scratch1]\n\t"
6018c2ecf20Sopenharmony_ci				      LONG_L " %[src], %[rseq_scratch0]\n\t",
6028c2ecf20Sopenharmony_ci				      abort, 1b, 2b, 4f)
6038c2ecf20Sopenharmony_ci		RSEQ_ASM_DEFINE_CMPFAIL(5,
6048c2ecf20Sopenharmony_ci					/* teardown */
6058c2ecf20Sopenharmony_ci					LONG_L " %[len], %[rseq_scratch2]\n\t"
6068c2ecf20Sopenharmony_ci					LONG_L " %[dst], %[rseq_scratch1]\n\t"
6078c2ecf20Sopenharmony_ci					LONG_L " %[src], %[rseq_scratch0]\n\t",
6088c2ecf20Sopenharmony_ci					cmpfail)
6098c2ecf20Sopenharmony_ci#ifdef RSEQ_COMPARE_TWICE
6108c2ecf20Sopenharmony_ci		RSEQ_ASM_DEFINE_CMPFAIL(6,
6118c2ecf20Sopenharmony_ci					/* teardown */
6128c2ecf20Sopenharmony_ci					LONG_L " %[len], %[rseq_scratch2]\n\t"
6138c2ecf20Sopenharmony_ci					LONG_L " %[dst], %[rseq_scratch1]\n\t"
6148c2ecf20Sopenharmony_ci					LONG_L " %[src], %[rseq_scratch0]\n\t",
6158c2ecf20Sopenharmony_ci					error1)
6168c2ecf20Sopenharmony_ci		RSEQ_ASM_DEFINE_CMPFAIL(7,
6178c2ecf20Sopenharmony_ci					/* teardown */
6188c2ecf20Sopenharmony_ci					LONG_L " %[len], %[rseq_scratch2]\n\t"
6198c2ecf20Sopenharmony_ci					LONG_L " %[dst], %[rseq_scratch1]\n\t"
6208c2ecf20Sopenharmony_ci					LONG_L " %[src], %[rseq_scratch0]\n\t",
6218c2ecf20Sopenharmony_ci					error2)
6228c2ecf20Sopenharmony_ci#endif
6238c2ecf20Sopenharmony_ci		"8:\n\t"
6248c2ecf20Sopenharmony_ci		: /* gcc asm goto does not allow outputs */
6258c2ecf20Sopenharmony_ci		: [cpu_id]		"r" (cpu),
6268c2ecf20Sopenharmony_ci		  [current_cpu_id]	"m" (rseq_get_abi()->cpu_id),
6278c2ecf20Sopenharmony_ci		  [rseq_cs]		"m" (rseq_get_abi()->rseq_cs.arch.ptr),
6288c2ecf20Sopenharmony_ci		  /* final store input */
6298c2ecf20Sopenharmony_ci		  [v]			"m" (*v),
6308c2ecf20Sopenharmony_ci		  [expect]		"r" (expect),
6318c2ecf20Sopenharmony_ci		  [newv]		"r" (newv),
6328c2ecf20Sopenharmony_ci		  /* try memcpy input */
6338c2ecf20Sopenharmony_ci		  [dst]			"r" (dst),
6348c2ecf20Sopenharmony_ci		  [src]			"r" (src),
6358c2ecf20Sopenharmony_ci		  [len]			"r" (len),
6368c2ecf20Sopenharmony_ci		  [rseq_scratch0]	"m" (rseq_scratch[0]),
6378c2ecf20Sopenharmony_ci		  [rseq_scratch1]	"m" (rseq_scratch[1]),
6388c2ecf20Sopenharmony_ci		  [rseq_scratch2]	"m" (rseq_scratch[2])
6398c2ecf20Sopenharmony_ci		  RSEQ_INJECT_INPUT
6408c2ecf20Sopenharmony_ci		: "$4", "memory"
6418c2ecf20Sopenharmony_ci		  RSEQ_INJECT_CLOBBER
6428c2ecf20Sopenharmony_ci		: abort, cmpfail
6438c2ecf20Sopenharmony_ci#ifdef RSEQ_COMPARE_TWICE
6448c2ecf20Sopenharmony_ci		  , error1, error2
6458c2ecf20Sopenharmony_ci#endif
6468c2ecf20Sopenharmony_ci	);
6478c2ecf20Sopenharmony_ci	return 0;
6488c2ecf20Sopenharmony_ciabort:
6498c2ecf20Sopenharmony_ci	RSEQ_INJECT_FAILED
6508c2ecf20Sopenharmony_ci	return -1;
6518c2ecf20Sopenharmony_cicmpfail:
6528c2ecf20Sopenharmony_ci	return 1;
6538c2ecf20Sopenharmony_ci#ifdef RSEQ_COMPARE_TWICE
6548c2ecf20Sopenharmony_cierror1:
6558c2ecf20Sopenharmony_ci	rseq_bug("cpu_id comparison failed");
6568c2ecf20Sopenharmony_cierror2:
6578c2ecf20Sopenharmony_ci	rseq_bug("expected value comparison failed");
6588c2ecf20Sopenharmony_ci#endif
6598c2ecf20Sopenharmony_ci}
6608c2ecf20Sopenharmony_ci
6618c2ecf20Sopenharmony_cistatic inline __attribute__((always_inline))
6628c2ecf20Sopenharmony_ciint rseq_cmpeqv_trymemcpy_storev_release(intptr_t *v, intptr_t expect,
6638c2ecf20Sopenharmony_ci					 void *dst, void *src, size_t len,
6648c2ecf20Sopenharmony_ci					 intptr_t newv, int cpu)
6658c2ecf20Sopenharmony_ci{
6668c2ecf20Sopenharmony_ci	uintptr_t rseq_scratch[3];
6678c2ecf20Sopenharmony_ci
6688c2ecf20Sopenharmony_ci	RSEQ_INJECT_C(9)
6698c2ecf20Sopenharmony_ci
6708c2ecf20Sopenharmony_ci	__asm__ __volatile__ goto (
6718c2ecf20Sopenharmony_ci		RSEQ_ASM_DEFINE_TABLE(9, 1f, 2f, 4f) /* start, commit, abort */
6728c2ecf20Sopenharmony_ci		RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[cmpfail])
6738c2ecf20Sopenharmony_ci#ifdef RSEQ_COMPARE_TWICE
6748c2ecf20Sopenharmony_ci		RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error1])
6758c2ecf20Sopenharmony_ci		RSEQ_ASM_DEFINE_EXIT_POINT(1f, %l[error2])
6768c2ecf20Sopenharmony_ci#endif
6778c2ecf20Sopenharmony_ci		LONG_S " %[src], %[rseq_scratch0]\n\t"
6788c2ecf20Sopenharmony_ci		LONG_S " %[dst], %[rseq_scratch1]\n\t"
6798c2ecf20Sopenharmony_ci		LONG_S " %[len], %[rseq_scratch2]\n\t"
6808c2ecf20Sopenharmony_ci		/* Start rseq by storing table entry pointer into rseq_cs. */
6818c2ecf20Sopenharmony_ci		RSEQ_ASM_STORE_RSEQ_CS(1, 3f, rseq_cs)
6828c2ecf20Sopenharmony_ci		RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f)
6838c2ecf20Sopenharmony_ci		RSEQ_INJECT_ASM(3)
6848c2ecf20Sopenharmony_ci		LONG_L " $4, %[v]\n\t"
6858c2ecf20Sopenharmony_ci		"bne $4, %[expect], 5f\n\t"
6868c2ecf20Sopenharmony_ci		RSEQ_INJECT_ASM(4)
6878c2ecf20Sopenharmony_ci#ifdef RSEQ_COMPARE_TWICE
6888c2ecf20Sopenharmony_ci		RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 6f)
6898c2ecf20Sopenharmony_ci		LONG_L " $4, %[v]\n\t"
6908c2ecf20Sopenharmony_ci		"bne $4, %[expect], 7f\n\t"
6918c2ecf20Sopenharmony_ci#endif
6928c2ecf20Sopenharmony_ci		/* try memcpy */
6938c2ecf20Sopenharmony_ci		"beqz %[len], 333f\n\t" \
6948c2ecf20Sopenharmony_ci		"222:\n\t" \
6958c2ecf20Sopenharmony_ci		"lb   $4, 0(%[src])\n\t" \
6968c2ecf20Sopenharmony_ci		"sb   $4, 0(%[dst])\n\t" \
6978c2ecf20Sopenharmony_ci		LONG_ADDI " %[src], 1\n\t" \
6988c2ecf20Sopenharmony_ci		LONG_ADDI " %[dst], 1\n\t" \
6998c2ecf20Sopenharmony_ci		LONG_ADDI " %[len], -1\n\t" \
7008c2ecf20Sopenharmony_ci		"bnez %[len], 222b\n\t" \
7018c2ecf20Sopenharmony_ci		"333:\n\t" \
7028c2ecf20Sopenharmony_ci		RSEQ_INJECT_ASM(5)
7038c2ecf20Sopenharmony_ci		"sync\n\t"	/* full sync provides store-release */
7048c2ecf20Sopenharmony_ci		/* final store */
7058c2ecf20Sopenharmony_ci		LONG_S " %[newv], %[v]\n\t"
7068c2ecf20Sopenharmony_ci		"2:\n\t"
7078c2ecf20Sopenharmony_ci		RSEQ_INJECT_ASM(6)
7088c2ecf20Sopenharmony_ci		/* teardown */
7098c2ecf20Sopenharmony_ci		LONG_L " %[len], %[rseq_scratch2]\n\t"
7108c2ecf20Sopenharmony_ci		LONG_L " %[dst], %[rseq_scratch1]\n\t"
7118c2ecf20Sopenharmony_ci		LONG_L " %[src], %[rseq_scratch0]\n\t"
7128c2ecf20Sopenharmony_ci		"b 8f\n\t"
7138c2ecf20Sopenharmony_ci		RSEQ_ASM_DEFINE_ABORT(3, 4,
7148c2ecf20Sopenharmony_ci				      /* teardown */
7158c2ecf20Sopenharmony_ci				      LONG_L " %[len], %[rseq_scratch2]\n\t"
7168c2ecf20Sopenharmony_ci				      LONG_L " %[dst], %[rseq_scratch1]\n\t"
7178c2ecf20Sopenharmony_ci				      LONG_L " %[src], %[rseq_scratch0]\n\t",
7188c2ecf20Sopenharmony_ci				      abort, 1b, 2b, 4f)
7198c2ecf20Sopenharmony_ci		RSEQ_ASM_DEFINE_CMPFAIL(5,
7208c2ecf20Sopenharmony_ci					/* teardown */
7218c2ecf20Sopenharmony_ci					LONG_L " %[len], %[rseq_scratch2]\n\t"
7228c2ecf20Sopenharmony_ci					LONG_L " %[dst], %[rseq_scratch1]\n\t"
7238c2ecf20Sopenharmony_ci					LONG_L " %[src], %[rseq_scratch0]\n\t",
7248c2ecf20Sopenharmony_ci					cmpfail)
7258c2ecf20Sopenharmony_ci#ifdef RSEQ_COMPARE_TWICE
7268c2ecf20Sopenharmony_ci		RSEQ_ASM_DEFINE_CMPFAIL(6,
7278c2ecf20Sopenharmony_ci					/* teardown */
7288c2ecf20Sopenharmony_ci					LONG_L " %[len], %[rseq_scratch2]\n\t"
7298c2ecf20Sopenharmony_ci					LONG_L " %[dst], %[rseq_scratch1]\n\t"
7308c2ecf20Sopenharmony_ci					LONG_L " %[src], %[rseq_scratch0]\n\t",
7318c2ecf20Sopenharmony_ci					error1)
7328c2ecf20Sopenharmony_ci		RSEQ_ASM_DEFINE_CMPFAIL(7,
7338c2ecf20Sopenharmony_ci					/* teardown */
7348c2ecf20Sopenharmony_ci					LONG_L " %[len], %[rseq_scratch2]\n\t"
7358c2ecf20Sopenharmony_ci					LONG_L " %[dst], %[rseq_scratch1]\n\t"
7368c2ecf20Sopenharmony_ci					LONG_L " %[src], %[rseq_scratch0]\n\t",
7378c2ecf20Sopenharmony_ci					error2)
7388c2ecf20Sopenharmony_ci#endif
7398c2ecf20Sopenharmony_ci		"8:\n\t"
7408c2ecf20Sopenharmony_ci		: /* gcc asm goto does not allow outputs */
7418c2ecf20Sopenharmony_ci		: [cpu_id]		"r" (cpu),
7428c2ecf20Sopenharmony_ci		  [current_cpu_id]	"m" (rseq_get_abi()->cpu_id),
7438c2ecf20Sopenharmony_ci		  [rseq_cs]		"m" (rseq_get_abi()->rseq_cs.arch.ptr),
7448c2ecf20Sopenharmony_ci		  /* final store input */
7458c2ecf20Sopenharmony_ci		  [v]			"m" (*v),
7468c2ecf20Sopenharmony_ci		  [expect]		"r" (expect),
7478c2ecf20Sopenharmony_ci		  [newv]		"r" (newv),
7488c2ecf20Sopenharmony_ci		  /* try memcpy input */
7498c2ecf20Sopenharmony_ci		  [dst]			"r" (dst),
7508c2ecf20Sopenharmony_ci		  [src]			"r" (src),
7518c2ecf20Sopenharmony_ci		  [len]			"r" (len),
7528c2ecf20Sopenharmony_ci		  [rseq_scratch0]	"m" (rseq_scratch[0]),
7538c2ecf20Sopenharmony_ci		  [rseq_scratch1]	"m" (rseq_scratch[1]),
7548c2ecf20Sopenharmony_ci		  [rseq_scratch2]	"m" (rseq_scratch[2])
7558c2ecf20Sopenharmony_ci		  RSEQ_INJECT_INPUT
7568c2ecf20Sopenharmony_ci		: "$4", "memory"
7578c2ecf20Sopenharmony_ci		  RSEQ_INJECT_CLOBBER
7588c2ecf20Sopenharmony_ci		: abort, cmpfail
7598c2ecf20Sopenharmony_ci#ifdef RSEQ_COMPARE_TWICE
7608c2ecf20Sopenharmony_ci		  , error1, error2
7618c2ecf20Sopenharmony_ci#endif
7628c2ecf20Sopenharmony_ci	);
7638c2ecf20Sopenharmony_ci	return 0;
7648c2ecf20Sopenharmony_ciabort:
7658c2ecf20Sopenharmony_ci	RSEQ_INJECT_FAILED
7668c2ecf20Sopenharmony_ci	return -1;
7678c2ecf20Sopenharmony_cicmpfail:
7688c2ecf20Sopenharmony_ci	return 1;
7698c2ecf20Sopenharmony_ci#ifdef RSEQ_COMPARE_TWICE
7708c2ecf20Sopenharmony_cierror1:
7718c2ecf20Sopenharmony_ci	rseq_bug("cpu_id comparison failed");
7728c2ecf20Sopenharmony_cierror2:
7738c2ecf20Sopenharmony_ci	rseq_bug("expected value comparison failed");
7748c2ecf20Sopenharmony_ci#endif
7758c2ecf20Sopenharmony_ci}
7768c2ecf20Sopenharmony_ci
7778c2ecf20Sopenharmony_ci#endif /* !RSEQ_SKIP_FASTPATH */
778