xref: /linux/arch/s390/include/asm/futex.h (revision b731bc5f49651bb85ef31fa1db6e76a0fe10d572)
1 /* SPDX-License-Identifier: GPL-2.0 */
2 #ifndef _ASM_S390_FUTEX_H
3 #define _ASM_S390_FUTEX_H
4 
5 #include <linux/instrumented.h>
6 #include <linux/uaccess.h>
7 #include <linux/futex.h>
8 #include <asm/asm-extable.h>
9 #include <asm/mmu_context.h>
10 #include <asm/errno.h>
11 
12 #define FUTEX_OP_FUNC(name, insn)						\
13 static uaccess_kmsan_or_inline int						\
14 __futex_atomic_##name(int oparg, int *old, u32 __user *uaddr)			\
15 {										\
16 	int rc, new;								\
17 										\
18 	instrument_copy_from_user_before(old, uaddr, sizeof(*old));		\
19 	asm_inline volatile(							\
20 		"	sacf	256\n"						\
21 		"0:	l	%[old],%[uaddr]\n"				\
22 		"1:"insn							\
23 		"2:	cs	%[old],%[new],%[uaddr]\n"			\
24 		"3:	jl	1b\n"						\
25 		"	lhi	%[rc],0\n"					\
26 		"4:	sacf	768\n"						\
27 		EX_TABLE_UA_FAULT(0b, 4b, %[rc])				\
28 		EX_TABLE_UA_FAULT(1b, 4b, %[rc])				\
29 		EX_TABLE_UA_FAULT(2b, 4b, %[rc])				\
30 		EX_TABLE_UA_FAULT(3b, 4b, %[rc])				\
31 		: [rc] "=d" (rc), [old] "=&d" (*old),				\
32 		  [new] "=&d" (new), [uaddr] "+Q" (*uaddr)			\
33 		: [oparg] "d" (oparg)						\
34 		: "cc");							\
35 	if (!rc)								\
36 		instrument_copy_from_user_after(old, uaddr, sizeof(*old), 0);	\
37 	return rc;								\
38 }
39 
40 FUTEX_OP_FUNC(set, "lr %[new],%[oparg]\n")
41 FUTEX_OP_FUNC(add, "lr %[new],%[old]\n ar %[new],%[oparg]\n")
42 FUTEX_OP_FUNC(or,  "lr %[new],%[old]\n or %[new],%[oparg]\n")
43 FUTEX_OP_FUNC(and, "lr %[new],%[old]\n nr %[new],%[oparg]\n")
44 FUTEX_OP_FUNC(xor, "lr %[new],%[old]\n xr %[new],%[oparg]\n")
45 
46 static inline
arch_futex_atomic_op_inuser(int op,int oparg,int * oval,u32 __user * uaddr)47 int arch_futex_atomic_op_inuser(int op, int oparg, int *oval, u32 __user *uaddr)
48 {
49 	int old, rc;
50 
51 	switch (op) {
52 	case FUTEX_OP_SET:
53 		rc = __futex_atomic_set(oparg, &old, uaddr);
54 		break;
55 	case FUTEX_OP_ADD:
56 		rc = __futex_atomic_add(oparg, &old, uaddr);
57 		break;
58 	case FUTEX_OP_OR:
59 		rc = __futex_atomic_or(oparg, &old, uaddr);
60 		break;
61 	case FUTEX_OP_ANDN:
62 		rc = __futex_atomic_and(~oparg, &old, uaddr);
63 		break;
64 	case FUTEX_OP_XOR:
65 		rc = __futex_atomic_xor(oparg, &old, uaddr);
66 		break;
67 	default:
68 		rc = -ENOSYS;
69 	}
70 	if (!rc)
71 		*oval = old;
72 	return rc;
73 }
74 
75 static uaccess_kmsan_or_inline
futex_atomic_cmpxchg_inatomic(u32 * uval,u32 __user * uaddr,u32 oldval,u32 newval)76 int futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr, u32 oldval, u32 newval)
77 {
78 	int rc;
79 
80 	instrument_copy_from_user_before(uval, uaddr, sizeof(*uval));
81 	asm_inline volatile(
82 		"	sacf	256\n"
83 		"0:	cs	%[old],%[new],%[uaddr]\n"
84 		"1:	lhi	%[rc],0\n"
85 		"2:	sacf	768\n"
86 		EX_TABLE_UA_FAULT(0b, 2b, %[rc])
87 		EX_TABLE_UA_FAULT(1b, 2b, %[rc])
88 		: [rc] "=d" (rc), [old] "+d" (oldval), [uaddr] "+Q" (*uaddr)
89 		: [new] "d" (newval)
90 		: "cc", "memory");
91 	*uval = oldval;
92 	instrument_copy_from_user_after(uval, uaddr, sizeof(*uval), 0);
93 	return rc;
94 }
95 
96 #endif /* _ASM_S390_FUTEX_H */
97