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 bool sacf_flag; \
17 int rc, new; \
18 \
19 instrument_copy_from_user_before(old, uaddr, sizeof(*old)); \
20 sacf_flag = enable_sacf_uaccess(); \
21 asm_inline volatile( \
22 " sacf 256\n" \
23 "0: l %[old],%[uaddr]\n" \
24 "1:"insn \
25 "2: cs %[old],%[new],%[uaddr]\n" \
26 "3: jl 1b\n" \
27 " lhi %[rc],0\n" \
28 "4: sacf 768\n" \
29 EX_TABLE_UA_FAULT(0b, 4b, %[rc]) \
30 EX_TABLE_UA_FAULT(1b, 4b, %[rc]) \
31 EX_TABLE_UA_FAULT(2b, 4b, %[rc]) \
32 EX_TABLE_UA_FAULT(3b, 4b, %[rc]) \
33 : [rc] "=d" (rc), [old] "=&d" (*old), \
34 [new] "=&d" (new), [uaddr] "+Q" (*uaddr) \
35 : [oparg] "d" (oparg) \
36 : "cc"); \
37 disable_sacf_uaccess(sacf_flag); \
38 if (!rc) \
39 instrument_copy_from_user_after(old, uaddr, sizeof(*old), 0); \
40 return rc; \
41 }
42
43 FUTEX_OP_FUNC(set, "lr %[new],%[oparg]\n")
44 FUTEX_OP_FUNC(add, "lr %[new],%[old]\n ar %[new],%[oparg]\n")
45 FUTEX_OP_FUNC(or, "lr %[new],%[old]\n or %[new],%[oparg]\n")
46 FUTEX_OP_FUNC(and, "lr %[new],%[old]\n nr %[new],%[oparg]\n")
47 FUTEX_OP_FUNC(xor, "lr %[new],%[old]\n xr %[new],%[oparg]\n")
48
49 static inline
arch_futex_atomic_op_inuser(int op,int oparg,int * oval,u32 __user * uaddr)50 int arch_futex_atomic_op_inuser(int op, int oparg, int *oval, u32 __user *uaddr)
51 {
52 int old, rc;
53
54 switch (op) {
55 case FUTEX_OP_SET:
56 rc = __futex_atomic_set(oparg, &old, uaddr);
57 break;
58 case FUTEX_OP_ADD:
59 rc = __futex_atomic_add(oparg, &old, uaddr);
60 break;
61 case FUTEX_OP_OR:
62 rc = __futex_atomic_or(oparg, &old, uaddr);
63 break;
64 case FUTEX_OP_ANDN:
65 rc = __futex_atomic_and(~oparg, &old, uaddr);
66 break;
67 case FUTEX_OP_XOR:
68 rc = __futex_atomic_xor(oparg, &old, uaddr);
69 break;
70 default:
71 rc = -ENOSYS;
72 }
73 if (!rc)
74 *oval = old;
75 return rc;
76 }
77
78 static uaccess_kmsan_or_inline
futex_atomic_cmpxchg_inatomic(u32 * uval,u32 __user * uaddr,u32 oldval,u32 newval)79 int futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr, u32 oldval, u32 newval)
80 {
81 bool sacf_flag;
82 int rc;
83
84 instrument_copy_from_user_before(uval, uaddr, sizeof(*uval));
85 sacf_flag = enable_sacf_uaccess();
86 asm_inline volatile(
87 " sacf 256\n"
88 "0: cs %[old],%[new],%[uaddr]\n"
89 "1: lhi %[rc],0\n"
90 "2: sacf 768\n"
91 EX_TABLE_UA_FAULT(0b, 2b, %[rc])
92 EX_TABLE_UA_FAULT(1b, 2b, %[rc])
93 : [rc] "=d" (rc), [old] "+d" (oldval), [uaddr] "+Q" (*uaddr)
94 : [new] "d" (newval)
95 : "cc", "memory");
96 disable_sacf_uaccess(sacf_flag);
97 *uval = oldval;
98 instrument_copy_from_user_after(uval, uaddr, sizeof(*uval), 0);
99 return rc;
100 }
101
102 #endif /* _ASM_S390_FUTEX_H */
103