xref: /openbmc/linux/arch/riscv/include/asm/futex.h (revision 20802d8d)
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