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 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 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