1/* SPDX-License-Identifier: GPL-2.0 */
2#ifndef _ASM_POWERPC_FUTEX_H
3#define _ASM_POWERPC_FUTEX_H
4
5#ifdef __KERNEL__
6
7#include <linux/futex.h>
8#include <linux/uaccess.h>
9#include <asm/errno.h>
10#include <asm/synch.h>
11
12#define __futex_atomic_op(insn, ret, oldval, uaddr, oparg) \
13  __asm__ __volatile ( \
14	PPC_ATOMIC_ENTRY_BARRIER \
15"1:	lwarx	%0,0,%2\n" \
16	insn \
17"2:	stwcx.	%1,0,%2\n" \
18	"bne-	1b\n" \
19	PPC_ATOMIC_EXIT_BARRIER \
20	"li	%1,0\n" \
21"3:	.section .fixup,\"ax\"\n" \
22"4:	li	%1,%3\n" \
23	"b	3b\n" \
24	".previous\n" \
25	EX_TABLE(1b, 4b) \
26	EX_TABLE(2b, 4b) \
27	: "=&r" (oldval), "=&r" (ret) \
28	: "b" (uaddr), "i" (-EFAULT), "r" (oparg) \
29	: "cr0", "memory")
30
31static inline int arch_futex_atomic_op_inuser(int op, int oparg, int *oval,
32		u32 __user *uaddr)
33{
34	int oldval = 0, ret;
35
36	if (!access_ok(uaddr, sizeof(u32)))
37		return -EFAULT;
38	allow_read_write_user(uaddr, uaddr, sizeof(*uaddr));
39
40	switch (op) {
41	case FUTEX_OP_SET:
42		__futex_atomic_op("mr %1,%4\n", ret, oldval, uaddr, oparg);
43		break;
44	case FUTEX_OP_ADD:
45		__futex_atomic_op("add %1,%0,%4\n", ret, oldval, uaddr, oparg);
46		break;
47	case FUTEX_OP_OR:
48		__futex_atomic_op("or %1,%0,%4\n", ret, oldval, uaddr, oparg);
49		break;
50	case FUTEX_OP_ANDN:
51		__futex_atomic_op("andc %1,%0,%4\n", ret, oldval, uaddr, oparg);
52		break;
53	case FUTEX_OP_XOR:
54		__futex_atomic_op("xor %1,%0,%4\n", ret, oldval, uaddr, oparg);
55		break;
56	default:
57		ret = -ENOSYS;
58	}
59
60	*oval = oldval;
61
62	prevent_read_write_user(uaddr, uaddr, sizeof(*uaddr));
63	return ret;
64}
65
66static inline int
67futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
68			      u32 oldval, u32 newval)
69{
70	int ret = 0;
71	u32 prev;
72
73	if (!access_ok(uaddr, sizeof(u32)))
74		return -EFAULT;
75
76	allow_read_write_user(uaddr, uaddr, sizeof(*uaddr));
77
78        __asm__ __volatile__ (
79        PPC_ATOMIC_ENTRY_BARRIER
80"1:     lwarx   %1,0,%3         # futex_atomic_cmpxchg_inatomic\n\
81        cmpw    0,%1,%4\n\
82        bne-    3f\n"
83"2:     stwcx.  %5,0,%3\n\
84        bne-    1b\n"
85        PPC_ATOMIC_EXIT_BARRIER
86"3:	.section .fixup,\"ax\"\n\
874:	li	%0,%6\n\
88	b	3b\n\
89	.previous\n"
90	EX_TABLE(1b, 4b)
91	EX_TABLE(2b, 4b)
92        : "+r" (ret), "=&r" (prev), "+m" (*uaddr)
93        : "r" (uaddr), "r" (oldval), "r" (newval), "i" (-EFAULT)
94        : "cc", "memory");
95
96	*uval = prev;
97	prevent_read_write_user(uaddr, uaddr, sizeof(*uaddr));
98
99        return ret;
100}
101
102#endif /* __KERNEL__ */
103#endif /* _ASM_POWERPC_FUTEX_H */
104