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 * For UP, it's relies on the fact that pagefault_disable() also disables
12 * preemption to ensure mutual exclusion.
13 *
14 */
15
16/**
17 * futex_atomic_op_inuser() - Atomic arithmetic operation with constant
18 *			  argument and comparison of the previous
19 *			  futex value with another constant.
20 *
21 * @encoded_op:	encoded operation to execute
22 * @uaddr:	pointer to user space address
23 *
24 * Return:
25 * 0 - On success
26 * <0 - On error
27 */
28static inline int
29futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
30{
31	int op = (encoded_op >> 28) & 7;
32	int cmp = (encoded_op >> 24) & 15;
33	int oparg = (encoded_op << 8) >> 20;
34	int cmparg = (encoded_op << 20) >> 20;
35	int oldval, ret;
36	u32 tmp;
37
38	if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
39		oparg = 1 << oparg;
40
41	pagefault_disable();
42
43	ret = -EFAULT;
44	if (unlikely(get_user(oldval, uaddr) != 0))
45		goto out_pagefault_enable;
46
47	ret = 0;
48	tmp = oldval;
49
50	switch (op) {
51	case FUTEX_OP_SET:
52		tmp = oparg;
53		break;
54	case FUTEX_OP_ADD:
55		tmp += oparg;
56		break;
57	case FUTEX_OP_OR:
58		tmp |= oparg;
59		break;
60	case FUTEX_OP_ANDN:
61		tmp &= ~oparg;
62		break;
63	case FUTEX_OP_XOR:
64		tmp ^= oparg;
65		break;
66	default:
67		ret = -ENOSYS;
68	}
69
70	if (ret == 0 && unlikely(put_user(tmp, uaddr) != 0))
71		ret = -EFAULT;
72
73out_pagefault_enable:
74	pagefault_enable();
75
76	if (ret == 0) {
77		switch (cmp) {
78		case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
79		case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
80		case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break;
81		case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break;
82		case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break;
83		case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break;
84		default: ret = -ENOSYS;
85		}
86	}
87	return ret;
88}
89
90/**
91 * futex_atomic_cmpxchg_inatomic() - Compare and exchange the content of the
92 *				uaddr with newval if the current value is
93 *				oldval.
94 * @uval:	pointer to store content of @uaddr
95 * @uaddr:	pointer to user space address
96 * @oldval:	old value
97 * @newval:	new value to store to @uaddr
98 *
99 * Return:
100 * 0 - On success
101 * <0 - On error
102 */
103static inline int
104futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
105			      u32 oldval, u32 newval)
106{
107	u32 val;
108
109	if (unlikely(get_user(val, uaddr) != 0))
110		return -EFAULT;
111
112	if (val == oldval && unlikely(put_user(newval, uaddr) != 0))
113		return -EFAULT;
114
115	*uval = val;
116
117	return 0;
118}
119
120#else
121static inline int
122futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr)
123{
124	int op = (encoded_op >> 28) & 7;
125	int cmp = (encoded_op >> 24) & 15;
126	int oparg = (encoded_op << 8) >> 20;
127	int cmparg = (encoded_op << 20) >> 20;
128	int oldval = 0, ret;
129	if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
130		oparg = 1 << oparg;
131
132	if (! access_ok (VERIFY_WRITE, uaddr, sizeof(u32)))
133		return -EFAULT;
134
135	pagefault_disable();
136
137	switch (op) {
138	case FUTEX_OP_SET:
139	case FUTEX_OP_ADD:
140	case FUTEX_OP_OR:
141	case FUTEX_OP_ANDN:
142	case FUTEX_OP_XOR:
143	default:
144		ret = -ENOSYS;
145	}
146
147	pagefault_enable();
148
149	if (!ret) {
150		switch (cmp) {
151		case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
152		case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
153		case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break;
154		case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break;
155		case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break;
156		case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break;
157		default: ret = -ENOSYS;
158		}
159	}
160	return ret;
161}
162
163static inline int
164futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
165			      u32 oldval, u32 newval)
166{
167	return -ENOSYS;
168}
169
170#endif /* CONFIG_SMP */
171#endif
172