Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/arch/frv/kernel/futex.c
10817 views
1
/* futex.c: futex operations
2
*
3
* Copyright (C) 2005 Red Hat, Inc. All Rights Reserved.
4
* Written by David Howells ([email protected])
5
*
6
* This program is free software; you can redistribute it and/or
7
* modify it under the terms of the GNU General Public License
8
* as published by the Free Software Foundation; either version
9
* 2 of the License, or (at your option) any later version.
10
*/
11
12
#include <linux/futex.h>
13
#include <linux/uaccess.h>
14
#include <asm/futex.h>
15
#include <asm/errno.h>
16
17
/*
18
* the various futex operations; MMU fault checking is ignored under no-MMU
19
* conditions
20
*/
21
static inline int atomic_futex_op_xchg_set(int oparg, u32 __user *uaddr, int *_oldval)
22
{
23
int oldval, ret;
24
25
asm("0: \n"
26
" orcc gr0,gr0,gr0,icc3 \n" /* set ICC3.Z */
27
" ckeq icc3,cc7 \n"
28
"1: ld.p %M0,%1 \n" /* LD.P/ORCR must be atomic */
29
" orcr cc7,cc7,cc3 \n" /* set CC3 to true */
30
"2: cst.p %3,%M0 ,cc3,#1 \n"
31
" corcc gr29,gr29,gr0 ,cc3,#1 \n" /* clear ICC3.Z if store happens */
32
" beq icc3,#0,0b \n"
33
" setlos 0,%2 \n"
34
"3: \n"
35
".subsection 2 \n"
36
"4: setlos %5,%2 \n"
37
" bra 3b \n"
38
".previous \n"
39
".section __ex_table,\"a\" \n"
40
" .balign 8 \n"
41
" .long 1b,4b \n"
42
" .long 2b,4b \n"
43
".previous"
44
: "+U"(*uaddr), "=&r"(oldval), "=&r"(ret), "=r"(oparg)
45
: "3"(oparg), "i"(-EFAULT)
46
: "memory", "cc7", "cc3", "icc3"
47
);
48
49
*_oldval = oldval;
50
return ret;
51
}
52
53
static inline int atomic_futex_op_xchg_add(int oparg, u32 __user *uaddr, int *_oldval)
54
{
55
int oldval, ret;
56
57
asm("0: \n"
58
" orcc gr0,gr0,gr0,icc3 \n" /* set ICC3.Z */
59
" ckeq icc3,cc7 \n"
60
"1: ld.p %M0,%1 \n" /* LD.P/ORCR must be atomic */
61
" orcr cc7,cc7,cc3 \n" /* set CC3 to true */
62
" add %1,%3,%3 \n"
63
"2: cst.p %3,%M0 ,cc3,#1 \n"
64
" corcc gr29,gr29,gr0 ,cc3,#1 \n" /* clear ICC3.Z if store happens */
65
" beq icc3,#0,0b \n"
66
" setlos 0,%2 \n"
67
"3: \n"
68
".subsection 2 \n"
69
"4: setlos %5,%2 \n"
70
" bra 3b \n"
71
".previous \n"
72
".section __ex_table,\"a\" \n"
73
" .balign 8 \n"
74
" .long 1b,4b \n"
75
" .long 2b,4b \n"
76
".previous"
77
: "+U"(*uaddr), "=&r"(oldval), "=&r"(ret), "=r"(oparg)
78
: "3"(oparg), "i"(-EFAULT)
79
: "memory", "cc7", "cc3", "icc3"
80
);
81
82
*_oldval = oldval;
83
return ret;
84
}
85
86
static inline int atomic_futex_op_xchg_or(int oparg, u32 __user *uaddr, int *_oldval)
87
{
88
int oldval, ret;
89
90
asm("0: \n"
91
" orcc gr0,gr0,gr0,icc3 \n" /* set ICC3.Z */
92
" ckeq icc3,cc7 \n"
93
"1: ld.p %M0,%1 \n" /* LD.P/ORCR must be atomic */
94
" orcr cc7,cc7,cc3 \n" /* set CC3 to true */
95
" or %1,%3,%3 \n"
96
"2: cst.p %3,%M0 ,cc3,#1 \n"
97
" corcc gr29,gr29,gr0 ,cc3,#1 \n" /* clear ICC3.Z if store happens */
98
" beq icc3,#0,0b \n"
99
" setlos 0,%2 \n"
100
"3: \n"
101
".subsection 2 \n"
102
"4: setlos %5,%2 \n"
103
" bra 3b \n"
104
".previous \n"
105
".section __ex_table,\"a\" \n"
106
" .balign 8 \n"
107
" .long 1b,4b \n"
108
" .long 2b,4b \n"
109
".previous"
110
: "+U"(*uaddr), "=&r"(oldval), "=&r"(ret), "=r"(oparg)
111
: "3"(oparg), "i"(-EFAULT)
112
: "memory", "cc7", "cc3", "icc3"
113
);
114
115
*_oldval = oldval;
116
return ret;
117
}
118
119
static inline int atomic_futex_op_xchg_and(int oparg, u32 __user *uaddr, int *_oldval)
120
{
121
int oldval, ret;
122
123
asm("0: \n"
124
" orcc gr0,gr0,gr0,icc3 \n" /* set ICC3.Z */
125
" ckeq icc3,cc7 \n"
126
"1: ld.p %M0,%1 \n" /* LD.P/ORCR must be atomic */
127
" orcr cc7,cc7,cc3 \n" /* set CC3 to true */
128
" and %1,%3,%3 \n"
129
"2: cst.p %3,%M0 ,cc3,#1 \n"
130
" corcc gr29,gr29,gr0 ,cc3,#1 \n" /* clear ICC3.Z if store happens */
131
" beq icc3,#0,0b \n"
132
" setlos 0,%2 \n"
133
"3: \n"
134
".subsection 2 \n"
135
"4: setlos %5,%2 \n"
136
" bra 3b \n"
137
".previous \n"
138
".section __ex_table,\"a\" \n"
139
" .balign 8 \n"
140
" .long 1b,4b \n"
141
" .long 2b,4b \n"
142
".previous"
143
: "+U"(*uaddr), "=&r"(oldval), "=&r"(ret), "=r"(oparg)
144
: "3"(oparg), "i"(-EFAULT)
145
: "memory", "cc7", "cc3", "icc3"
146
);
147
148
*_oldval = oldval;
149
return ret;
150
}
151
152
static inline int atomic_futex_op_xchg_xor(int oparg, u32 __user *uaddr, int *_oldval)
153
{
154
int oldval, ret;
155
156
asm("0: \n"
157
" orcc gr0,gr0,gr0,icc3 \n" /* set ICC3.Z */
158
" ckeq icc3,cc7 \n"
159
"1: ld.p %M0,%1 \n" /* LD.P/ORCR must be atomic */
160
" orcr cc7,cc7,cc3 \n" /* set CC3 to true */
161
" xor %1,%3,%3 \n"
162
"2: cst.p %3,%M0 ,cc3,#1 \n"
163
" corcc gr29,gr29,gr0 ,cc3,#1 \n" /* clear ICC3.Z if store happens */
164
" beq icc3,#0,0b \n"
165
" setlos 0,%2 \n"
166
"3: \n"
167
".subsection 2 \n"
168
"4: setlos %5,%2 \n"
169
" bra 3b \n"
170
".previous \n"
171
".section __ex_table,\"a\" \n"
172
" .balign 8 \n"
173
" .long 1b,4b \n"
174
" .long 2b,4b \n"
175
".previous"
176
: "+U"(*uaddr), "=&r"(oldval), "=&r"(ret), "=r"(oparg)
177
: "3"(oparg), "i"(-EFAULT)
178
: "memory", "cc7", "cc3", "icc3"
179
);
180
181
*_oldval = oldval;
182
return ret;
183
}
184
185
/*****************************************************************************/
186
/*
187
* do the futex operations
188
*/
189
int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
190
{
191
int op = (encoded_op >> 28) & 7;
192
int cmp = (encoded_op >> 24) & 15;
193
int oparg = (encoded_op << 8) >> 20;
194
int cmparg = (encoded_op << 20) >> 20;
195
int oldval = 0, ret;
196
197
if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
198
oparg = 1 << oparg;
199
200
if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
201
return -EFAULT;
202
203
pagefault_disable();
204
205
switch (op) {
206
case FUTEX_OP_SET:
207
ret = atomic_futex_op_xchg_set(oparg, uaddr, &oldval);
208
break;
209
case FUTEX_OP_ADD:
210
ret = atomic_futex_op_xchg_add(oparg, uaddr, &oldval);
211
break;
212
case FUTEX_OP_OR:
213
ret = atomic_futex_op_xchg_or(oparg, uaddr, &oldval);
214
break;
215
case FUTEX_OP_ANDN:
216
ret = atomic_futex_op_xchg_and(~oparg, uaddr, &oldval);
217
break;
218
case FUTEX_OP_XOR:
219
ret = atomic_futex_op_xchg_xor(oparg, uaddr, &oldval);
220
break;
221
default:
222
ret = -ENOSYS;
223
break;
224
}
225
226
pagefault_enable();
227
228
if (!ret) {
229
switch (cmp) {
230
case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
231
case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
232
case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break;
233
case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break;
234
case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break;
235
case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break;
236
default: ret = -ENOSYS; break;
237
}
238
}
239
240
return ret;
241
242
} /* end futex_atomic_op_inuser() */
243
244