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