1#ifndef __SCORE_UACCESS_H
2#define __SCORE_UACCESS_H
3
4#include <linux/kernel.h>
5#include <linux/errno.h>
6#include <linux/thread_info.h>
7
8#define VERIFY_READ 0
9#define VERIFY_WRITE 1
10
11#define get_ds() (KERNEL_DS)
12#define get_fs() (current_thread_info()->addr_limit)
13#define segment_eq(a, b) ((a).seg == (b).seg)
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28#define __ua_size(size) \
29 ((__builtin_constant_p(size) && (signed long) (size) > 0) ? 0 : (size))
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51#define __access_ok(addr, size) \
52 (((long)((get_fs().seg) & \
53 ((addr) | ((addr) + (size)) | \
54 __ua_size(size)))) == 0)
55
56#define access_ok(type, addr, size) \
57 likely(__access_ok((unsigned long)(addr), (size)))
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75#define put_user(x, ptr) __put_user_check((x), (ptr), sizeof(*(ptr)))
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94#define get_user(x, ptr) __get_user_check((x), (ptr), sizeof(*(ptr)))
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115#define __put_user(x, ptr) __put_user_nocheck((x), (ptr), sizeof(*(ptr)))
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137#define __get_user(x, ptr) __get_user_nocheck((x), (ptr), sizeof(*(ptr)))
138
139struct __large_struct { unsigned long buf[100]; };
140#define __m(x) (*(struct __large_struct __user *)(x))
141
142
143
144
145
146extern void __get_user_unknown(void);
147
148#define __get_user_common(val, size, ptr) \
149do { \
150 switch (size) { \
151 case 1: \
152 __get_user_asm(val, "lb", ptr); \
153 break; \
154 case 2: \
155 __get_user_asm(val, "lh", ptr); \
156 break; \
157 case 4: \
158 __get_user_asm(val, "lw", ptr); \
159 break; \
160 case 8: \
161 if ((copy_from_user((void *)&val, ptr, 8)) == 0) \
162 __gu_err = 0; \
163 else \
164 __gu_err = -EFAULT; \
165 break; \
166 default: \
167 __get_user_unknown(); \
168 break; \
169 } \
170} while (0)
171
172#define __get_user_nocheck(x, ptr, size) \
173({ \
174 long __gu_err = 0; \
175 __get_user_common((x), size, ptr); \
176 __gu_err; \
177})
178
179#define __get_user_check(x, ptr, size) \
180({ \
181 long __gu_err = -EFAULT; \
182 const __typeof__(*(ptr)) __user *__gu_ptr = (ptr); \
183 \
184 if (likely(access_ok(VERIFY_READ, __gu_ptr, size))) \
185 __get_user_common((x), size, __gu_ptr); \
186 \
187 __gu_err; \
188})
189
190#define __get_user_asm(val, insn, addr) \
191{ \
192 long __gu_tmp; \
193 \
194 __asm__ __volatile__( \
195 "1:" insn " %1, %3\n" \
196 "2:\n" \
197 ".section .fixup,\"ax\"\n" \
198 "3:li %0, %4\n" \
199 "j 2b\n" \
200 ".previous\n" \
201 ".section __ex_table,\"a\"\n" \
202 ".word 1b, 3b\n" \
203 ".previous\n" \
204 : "=r" (__gu_err), "=r" (__gu_tmp) \
205 : "0" (0), "o" (__m(addr)), "i" (-EFAULT)); \
206 \
207 (val) = (__typeof__(*(addr))) __gu_tmp; \
208}
209
210
211
212
213
214#define __put_user_nocheck(val, ptr, size) \
215({ \
216 __typeof__(*(ptr)) __pu_val; \
217 long __pu_err = 0; \
218 \
219 __pu_val = (val); \
220 switch (size) { \
221 case 1: \
222 __put_user_asm("sb", ptr); \
223 break; \
224 case 2: \
225 __put_user_asm("sh", ptr); \
226 break; \
227 case 4: \
228 __put_user_asm("sw", ptr); \
229 break; \
230 case 8: \
231 if ((__copy_to_user((void *)ptr, &__pu_val, 8)) == 0) \
232 __pu_err = 0; \
233 else \
234 __pu_err = -EFAULT; \
235 break; \
236 default: \
237 __put_user_unknown(); \
238 break; \
239 } \
240 __pu_err; \
241})
242
243
244#define __put_user_check(val, ptr, size) \
245({ \
246 __typeof__(*(ptr)) __user *__pu_addr = (ptr); \
247 __typeof__(*(ptr)) __pu_val = (val); \
248 long __pu_err = -EFAULT; \
249 \
250 if (likely(access_ok(VERIFY_WRITE, __pu_addr, size))) { \
251 switch (size) { \
252 case 1: \
253 __put_user_asm("sb", __pu_addr); \
254 break; \
255 case 2: \
256 __put_user_asm("sh", __pu_addr); \
257 break; \
258 case 4: \
259 __put_user_asm("sw", __pu_addr); \
260 break; \
261 case 8: \
262 if ((__copy_to_user((void *)__pu_addr, &__pu_val, 8)) == 0)\
263 __pu_err = 0; \
264 else \
265 __pu_err = -EFAULT; \
266 break; \
267 default: \
268 __put_user_unknown(); \
269 break; \
270 } \
271 } \
272 __pu_err; \
273})
274
275#define __put_user_asm(insn, ptr) \
276 __asm__ __volatile__( \
277 "1:" insn " %2, %3\n" \
278 "2:\n" \
279 ".section .fixup,\"ax\"\n" \
280 "3:li %0, %4\n" \
281 "j 2b\n" \
282 ".previous\n" \
283 ".section __ex_table,\"a\"\n" \
284 ".word 1b, 3b\n" \
285 ".previous\n" \
286 : "=r" (__pu_err) \
287 : "0" (0), "r" (__pu_val), "o" (__m(ptr)), \
288 "i" (-EFAULT));
289
290extern void __put_user_unknown(void);
291extern int __copy_tofrom_user(void *to, const void *from, unsigned long len);
292
293static inline unsigned long
294copy_from_user(void *to, const void *from, unsigned long len)
295{
296 unsigned long over;
297
298 if (access_ok(VERIFY_READ, from, len))
299 return __copy_tofrom_user(to, from, len);
300
301 if ((unsigned long)from < TASK_SIZE) {
302 over = (unsigned long)from + len - TASK_SIZE;
303 return __copy_tofrom_user(to, from, len - over) + over;
304 }
305 return len;
306}
307
308static inline unsigned long
309copy_to_user(void *to, const void *from, unsigned long len)
310{
311 unsigned long over;
312
313 if (access_ok(VERIFY_WRITE, to, len))
314 return __copy_tofrom_user(to, from, len);
315
316 if ((unsigned long)to < TASK_SIZE) {
317 over = (unsigned long)to + len - TASK_SIZE;
318 return __copy_tofrom_user(to, from, len - over) + over;
319 }
320 return len;
321}
322
323#define __copy_from_user(to, from, len) \
324 __copy_tofrom_user((to), (from), (len))
325
326#define __copy_to_user(to, from, len) \
327 __copy_tofrom_user((to), (from), (len))
328
329static inline unsigned long
330__copy_to_user_inatomic(void *to, const void *from, unsigned long len)
331{
332 return __copy_to_user(to, from, len);
333}
334
335static inline unsigned long
336__copy_from_user_inatomic(void *to, const void *from, unsigned long len)
337{
338 return __copy_from_user(to, from, len);
339}
340
341#define __copy_in_user(to, from, len) __copy_from_user(to, from, len)
342
343static inline unsigned long
344copy_in_user(void *to, const void *from, unsigned long len)
345{
346 if (access_ok(VERIFY_READ, from, len) &&
347 access_ok(VERFITY_WRITE, to, len))
348 return copy_from_user(to, from, len);
349}
350
351
352
353
354
355
356
357
358
359
360
361
362extern unsigned long __clear_user(void __user *src, unsigned long size);
363
364static inline unsigned long clear_user(char *src, unsigned long size)
365{
366 if (access_ok(VERIFY_WRITE, src, size))
367 return __clear_user(src, size);
368
369 return -EFAULT;
370}
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391extern int __strncpy_from_user(char *dst, const char *src, long len);
392
393static inline int strncpy_from_user(char *dst, const char *src, long len)
394{
395 if (access_ok(VERIFY_READ, src, 1))
396 return __strncpy_from_user(dst, src, len);
397
398 return -EFAULT;
399}
400
401extern int __strlen_user(const char *src);
402static inline long strlen_user(const char __user *src)
403{
404 return __strlen_user(src);
405}
406
407extern int __strnlen_user(const char *str, long len);
408static inline long strnlen_user(const char __user *str, long len)
409{
410 if (!access_ok(VERIFY_READ, str, 0))
411 return 0;
412 else
413 return __strnlen_user(str, len);
414}
415
416struct exception_table_entry {
417 unsigned long insn;
418 unsigned long fixup;
419};
420
421extern int fixup_exception(struct pt_regs *regs);
422
423#endif
424
425