^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) /* SPDX-License-Identifier: GPL-2.0-only */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Copyright (C) 2012 ARM Ltd.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) #ifndef __ASM_FUTEX_H
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) #define __ASM_FUTEX_H
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) #include <linux/futex.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <linux/uaccess.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <asm/errno.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #define FUTEX_MAX_LOOPS 128 /* What's the largest number you can think of? */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #define __futex_atomic_op(insn, ret, oldval, uaddr, tmp, oparg) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) do { \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) unsigned int loops = FUTEX_MAX_LOOPS; \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) uaccess_enable_privileged(); \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) asm volatile( \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) " prfm pstl1strm, %2\n" \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) "1: ldxr %w1, %2\n" \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) insn "\n" \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) "2: stlxr %w0, %w3, %2\n" \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) " cbz %w0, 3f\n" \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) " sub %w4, %w4, %w0\n" \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) " cbnz %w4, 1b\n" \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) " mov %w0, %w7\n" \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) "3:\n" \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) " dmb ish\n" \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) " .pushsection .fixup,\"ax\"\n" \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) " .align 2\n" \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) "4: mov %w0, %w6\n" \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) " b 3b\n" \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) " .popsection\n" \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) _ASM_EXTABLE(1b, 4b) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) _ASM_EXTABLE(2b, 4b) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) : "=&r" (ret), "=&r" (oldval), "+Q" (*uaddr), "=&r" (tmp), \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) "+r" (loops) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) : "r" (oparg), "Ir" (-EFAULT), "Ir" (-EAGAIN) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) : "memory"); \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) uaccess_disable_privileged(); \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) } while (0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) static inline int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) arch_futex_atomic_op_inuser(int op, int oparg, int *oval, u32 __user *_uaddr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) int oldval = 0, ret, tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) u32 __user *uaddr = __uaccess_mask_ptr(_uaddr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) if (!access_ok(_uaddr, sizeof(u32)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) switch (op) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) case FUTEX_OP_SET:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) __futex_atomic_op("mov %w3, %w5",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) ret, oldval, uaddr, tmp, oparg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) case FUTEX_OP_ADD:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) __futex_atomic_op("add %w3, %w1, %w5",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) ret, oldval, uaddr, tmp, oparg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) case FUTEX_OP_OR:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) __futex_atomic_op("orr %w3, %w1, %w5",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) ret, oldval, uaddr, tmp, oparg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) case FUTEX_OP_ANDN:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) __futex_atomic_op("and %w3, %w1, %w5",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) ret, oldval, uaddr, tmp, ~oparg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) case FUTEX_OP_XOR:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) __futex_atomic_op("eor %w3, %w1, %w5",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) ret, oldval, uaddr, tmp, oparg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) ret = -ENOSYS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) if (!ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) *oval = oldval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) static inline int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *_uaddr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) u32 oldval, u32 newval)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) int ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) unsigned int loops = FUTEX_MAX_LOOPS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) u32 val, tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) u32 __user *uaddr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) if (!access_ok(_uaddr, sizeof(u32)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) uaddr = __uaccess_mask_ptr(_uaddr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) uaccess_enable_privileged();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) asm volatile("// futex_atomic_cmpxchg_inatomic\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) " prfm pstl1strm, %2\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) "1: ldxr %w1, %2\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) " sub %w3, %w1, %w5\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) " cbnz %w3, 4f\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) "2: stlxr %w3, %w6, %2\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) " cbz %w3, 3f\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) " sub %w4, %w4, %w3\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) " cbnz %w4, 1b\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) " mov %w0, %w8\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) "3:\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) " dmb ish\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) "4:\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) " .pushsection .fixup,\"ax\"\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) "5: mov %w0, %w7\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) " b 4b\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) " .popsection\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) _ASM_EXTABLE(1b, 5b)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) _ASM_EXTABLE(2b, 5b)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) : "+r" (ret), "=&r" (val), "+Q" (*uaddr), "=&r" (tmp), "+r" (loops)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) : "r" (oldval), "r" (newval), "Ir" (-EFAULT), "Ir" (-EAGAIN)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) : "memory");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) uaccess_disable_privileged();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) if (!ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) *uval = val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) return ret;
^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 /* __ASM_FUTEX_H */