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