1b90edb33SJim Wilson /* SPDX-License-Identifier: GPL-2.0 */
2b90edb33SJim Wilson /*
3b90edb33SJim Wilson * Copyright (c) 2006 Ralf Baechle (ralf@linux-mips.org)
4b90edb33SJim Wilson * Copyright (c) 2018 Jim Wilson (jimw@sifive.com)
5b90edb33SJim Wilson */
6b90edb33SJim Wilson
76b57ba8eSZong Li #ifndef _ASM_RISCV_FUTEX_H
86b57ba8eSZong Li #define _ASM_RISCV_FUTEX_H
9b90edb33SJim Wilson
10b90edb33SJim Wilson #include <linux/futex.h>
11b90edb33SJim Wilson #include <linux/uaccess.h>
12b90edb33SJim Wilson #include <linux/errno.h>
13b90edb33SJim Wilson #include <asm/asm.h>
146dd10d91SJisheng Zhang #include <asm/asm-extable.h>
15b90edb33SJim Wilson
166bd33e1eSChristoph Hellwig /* We don't even really need the extable code, but for now keep it simple */
176bd33e1eSChristoph Hellwig #ifndef CONFIG_MMU
186bd33e1eSChristoph Hellwig #define __enable_user_access() do { } while (0)
196bd33e1eSChristoph Hellwig #define __disable_user_access() do { } while (0)
206bd33e1eSChristoph Hellwig #endif
216bd33e1eSChristoph Hellwig
22b90edb33SJim Wilson #define __futex_atomic_op(insn, ret, oldval, uaddr, oparg) \
23b90edb33SJim Wilson { \
24b90edb33SJim Wilson __enable_user_access(); \
25b90edb33SJim Wilson __asm__ __volatile__ ( \
26b90edb33SJim Wilson "1: " insn " \n" \
27b90edb33SJim Wilson "2: \n" \
28*20802d8dSJisheng Zhang _ASM_EXTABLE_UACCESS_ERR(1b, 2b, %[r]) \
29b90edb33SJim Wilson : [r] "+r" (ret), [ov] "=&r" (oldval), \
30*20802d8dSJisheng Zhang [u] "+m" (*uaddr) \
31*20802d8dSJisheng Zhang : [op] "Jr" (oparg) \
32b90edb33SJim Wilson : "memory"); \
33b90edb33SJim Wilson __disable_user_access(); \
34b90edb33SJim Wilson }
35b90edb33SJim Wilson
36b90edb33SJim Wilson static inline int
arch_futex_atomic_op_inuser(int op,int oparg,int * oval,u32 __user * uaddr)37b90edb33SJim Wilson arch_futex_atomic_op_inuser(int op, int oparg, int *oval, u32 __user *uaddr)
38b90edb33SJim Wilson {
39b90edb33SJim Wilson int oldval = 0, ret = 0;
40b90edb33SJim Wilson
41a08971e9SAl Viro if (!access_ok(uaddr, sizeof(u32)))
42a08971e9SAl Viro return -EFAULT;
43b90edb33SJim Wilson
44b90edb33SJim Wilson switch (op) {
45b90edb33SJim Wilson case FUTEX_OP_SET:
46b90edb33SJim Wilson __futex_atomic_op("amoswap.w.aqrl %[ov],%z[op],%[u]",
47b90edb33SJim Wilson ret, oldval, uaddr, oparg);
48b90edb33SJim Wilson break;
49b90edb33SJim Wilson case FUTEX_OP_ADD:
50b90edb33SJim Wilson __futex_atomic_op("amoadd.w.aqrl %[ov],%z[op],%[u]",
51b90edb33SJim Wilson ret, oldval, uaddr, oparg);
52b90edb33SJim Wilson break;
53b90edb33SJim Wilson case FUTEX_OP_OR:
54b90edb33SJim Wilson __futex_atomic_op("amoor.w.aqrl %[ov],%z[op],%[u]",
55b90edb33SJim Wilson ret, oldval, uaddr, oparg);
56b90edb33SJim Wilson break;
57b90edb33SJim Wilson case FUTEX_OP_ANDN:
58b90edb33SJim Wilson __futex_atomic_op("amoand.w.aqrl %[ov],%z[op],%[u]",
59b90edb33SJim Wilson ret, oldval, uaddr, ~oparg);
60b90edb33SJim Wilson break;
61b90edb33SJim Wilson case FUTEX_OP_XOR:
62b90edb33SJim Wilson __futex_atomic_op("amoxor.w.aqrl %[ov],%z[op],%[u]",
63b90edb33SJim Wilson ret, oldval, uaddr, oparg);
64b90edb33SJim Wilson break;
65b90edb33SJim Wilson default:
66b90edb33SJim Wilson ret = -ENOSYS;
67b90edb33SJim Wilson }
68b90edb33SJim Wilson
69b90edb33SJim Wilson if (!ret)
70b90edb33SJim Wilson *oval = oldval;
71b90edb33SJim Wilson
72b90edb33SJim Wilson return ret;
73b90edb33SJim Wilson }
74b90edb33SJim Wilson
75b90edb33SJim Wilson static inline int
futex_atomic_cmpxchg_inatomic(u32 * uval,u32 __user * uaddr,u32 oldval,u32 newval)76b90edb33SJim Wilson futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
77b90edb33SJim Wilson u32 oldval, u32 newval)
78b90edb33SJim Wilson {
79b90edb33SJim Wilson int ret = 0;
80b90edb33SJim Wilson u32 val;
81b90edb33SJim Wilson uintptr_t tmp;
82b90edb33SJim Wilson
8396d4f267SLinus Torvalds if (!access_ok(uaddr, sizeof(u32)))
84b90edb33SJim Wilson return -EFAULT;
85b90edb33SJim Wilson
86b90edb33SJim Wilson __enable_user_access();
87b90edb33SJim Wilson __asm__ __volatile__ (
88b90edb33SJim Wilson "1: lr.w.aqrl %[v],%[u] \n"
89b90edb33SJim Wilson " bne %[v],%z[ov],3f \n"
90b90edb33SJim Wilson "2: sc.w.aqrl %[t],%z[nv],%[u] \n"
91b90edb33SJim Wilson " bnez %[t],1b \n"
92b90edb33SJim Wilson "3: \n"
93*20802d8dSJisheng Zhang _ASM_EXTABLE_UACCESS_ERR(1b, 3b, %[r]) \
94*20802d8dSJisheng Zhang _ASM_EXTABLE_UACCESS_ERR(2b, 3b, %[r]) \
95b90edb33SJim Wilson : [r] "+r" (ret), [v] "=&r" (val), [u] "+m" (*uaddr), [t] "=&r" (tmp)
96*20802d8dSJisheng Zhang : [ov] "Jr" (oldval), [nv] "Jr" (newval)
97b90edb33SJim Wilson : "memory");
98b90edb33SJim Wilson __disable_user_access();
99b90edb33SJim Wilson
100b90edb33SJim Wilson *uval = val;
101b90edb33SJim Wilson return ret;
102b90edb33SJim Wilson }
103b90edb33SJim Wilson
1046b57ba8eSZong Li #endif /* _ASM_RISCV_FUTEX_H */
105