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