xref: /linux/arch/x86/entry/vdso/common/vfutex.c (revision b8ea7da314c2efcb9c2f559ed65b7a36c869d68e)
1 // SPDX-License-Identifier: GPL-2.0-only
2 #include <vdso/futex.h>
3 
4 /*
5  * Assembly template for the try unlock functions. The basic functionality is:
6  *
7  *		mov		esi, %eax	Move the TID into EAX
8  *		xor		%ecx, %ecx	Clear ECX
9  *		lock_cmpxchgl	%ecx, (%rdi)	Attempt the TID -> 0 transition
10  * .Lcs_start:					Start of the critical section
11  *		jnz		.Lcs_end	If cmpxchl failed jump to the end
12  * .Lcs_success:				Start of the success section
13  *		movq		%rcx, (%rdx)	Set the pending op pointer to 0
14  * .Lcs_end:					End of the critical section
15  *
16  * .Lcs_start and .Lcs_end establish the critical section range. .Lcs_success is
17  * technically not required, but there for illustration, debugging and testing.
18  *
19  * When CONFIG_COMPAT is enabled then the 64-bit VDSO provides two functions.
20  * One for the regular 64-bit sized pending operation pointer and one for a
21  * 32-bit sized pointer to support gaming emulators.
22  *
23  * The 32-bit VDSO provides only the one for 32-bit sized pointers.
24  */
25 #define __stringify_1(x...)	#x
26 #define __stringify(x...)	__stringify_1(x)
27 
28 #define LABEL(prefix, which)	__stringify(prefix##_try_unlock_cs_##which:)
29 
30 #define JNZ_END(prefix)		"jnz " __stringify(prefix) "_try_unlock_cs_end\n"
31 
32 #define CLEAR_POPQ		"movq	%[zero],  %a[pop]\n"
33 #define CLEAR_POPL		"movl	%k[zero], %a[pop]\n"
34 
35 #define futex_robust_try_unlock(prefix, clear_pop, __lock, __tid, __pop)\
36 ({									\
37 	asm volatile (							\
38 		"						\n"	\
39 		"	lock cmpxchgl	%k[zero], %a[lock]	\n"	\
40 		"						\n"	\
41 		LABEL(prefix, start)					\
42 		"						\n"	\
43 		JNZ_END(prefix)						\
44 		"						\n"	\
45 		LABEL(prefix, success)					\
46 		"						\n"	\
47 			clear_pop					\
48 		"						\n"	\
49 		LABEL(prefix, end)					\
50 		: [tid]   "+&a" (__tid)					\
51 		: [lock]  "D"   (__lock),				\
52 		  [pop]   "d"   (__pop),				\
53 		  [zero]  "r"   (0UL)					\
54 		: "memory"						\
55 	);								\
56 	__tid;								\
57 })
58 
59 #ifdef __x86_64__
60 __u32 __vdso_futex_robust_list64_try_unlock(__u32 *lock, __u32 tid, __u64 *pop)
61 {
62 	return futex_robust_try_unlock(__futex_list64, CLEAR_POPQ, lock, tid, pop);
63 }
64 #endif /* __x86_64__ */
65 
66 #if defined(CONFIG_X86_32) || defined(CONFIG_COMPAT)
67 __u32 __vdso_futex_robust_list32_try_unlock(__u32 *lock, __u32 tid, __u32 *pop)
68 {
69 	return futex_robust_try_unlock(__futex_list32, CLEAR_POPL, lock, tid, pop);
70 }
71 #endif /* CONFIG_X86_32 || CONFIG_COMPAT */
72