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