1 /* SPDX-License-Identifier: GPL-2.0 */ 2 #ifndef _ASM_GENERIC_FUTEX_H 3 #define _ASM_GENERIC_FUTEX_H 4 5 #include <linux/futex.h> 6 #include <linux/uaccess.h> 7 #include <asm/errno.h> 8 9 #ifndef CONFIG_SMP 10 /* 11 * The following implementation only for uniprocessor machines. 12 * It relies on preempt_disable() ensuring mutual exclusion. 13 * 14 */ 15 16 /** 17 * arch_futex_atomic_op_inuser() - Atomic arithmetic operation with constant 18 * argument and comparison of the previous 19 * futex value with another constant. 20 * 21 * @encoded_op: encoded operation to execute 22 * @uaddr: pointer to user space address 23 * 24 * Return: 25 * 0 - On success 26 * -EFAULT - User access resulted in a page fault 27 * -EAGAIN - Atomic operation was unable to complete due to contention 28 * -ENOSYS - Operation not supported 29 */ 30 static inline int 31 arch_futex_atomic_op_inuser(int op, u32 oparg, int *oval, u32 __user *uaddr) 32 { 33 int oldval, ret; 34 u32 tmp; 35 36 preempt_disable(); 37 38 ret = -EFAULT; 39 if (unlikely(get_user(oldval, uaddr) != 0)) 40 goto out_pagefault_enable; 41 42 ret = 0; 43 tmp = oldval; 44 45 switch (op) { 46 case FUTEX_OP_SET: 47 tmp = oparg; 48 break; 49 case FUTEX_OP_ADD: 50 tmp += oparg; 51 break; 52 case FUTEX_OP_OR: 53 tmp |= oparg; 54 break; 55 case FUTEX_OP_ANDN: 56 tmp &= ~oparg; 57 break; 58 case FUTEX_OP_XOR: 59 tmp ^= oparg; 60 break; 61 default: 62 ret = -ENOSYS; 63 } 64 65 if (ret == 0 && unlikely(put_user(tmp, uaddr) != 0)) 66 ret = -EFAULT; 67 68 out_pagefault_enable: 69 preempt_enable(); 70 71 if (ret == 0) 72 *oval = oldval; 73 74 return ret; 75 } 76 77 /** 78 * futex_atomic_cmpxchg_inatomic() - Compare and exchange the content of the 79 * uaddr with newval if the current value is 80 * oldval. 81 * @uval: pointer to store content of @uaddr 82 * @uaddr: pointer to user space address 83 * @oldval: old value 84 * @newval: new value to store to @uaddr 85 * 86 * Return: 87 * 0 - On success 88 * -EFAULT - User access resulted in a page fault 89 * -EAGAIN - Atomic operation was unable to complete due to contention 90 * -ENOSYS - Function not implemented (only if !HAVE_FUTEX_CMPXCHG) 91 */ 92 static inline int 93 futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr, 94 u32 oldval, u32 newval) 95 { 96 u32 val; 97 98 preempt_disable(); 99 if (unlikely(get_user(val, uaddr) != 0)) { 100 preempt_enable(); 101 return -EFAULT; 102 } 103 104 if (val == oldval && unlikely(put_user(newval, uaddr) != 0)) { 105 preempt_enable(); 106 return -EFAULT; 107 } 108 109 *uval = val; 110 preempt_enable(); 111 112 return 0; 113 } 114 115 #else 116 static inline int 117 arch_futex_atomic_op_inuser(int op, u32 oparg, int *oval, u32 __user *uaddr) 118 { 119 return -ENOSYS; 120 } 121 122 static inline int 123 futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr, 124 u32 oldval, u32 newval) 125 { 126 return -ENOSYS; 127 } 128 129 #endif /* CONFIG_SMP */ 130 #endif 131