File: /usr/src/linux/include/asm-cris/uaccess.h
1 /*
2 * Authors: Bjorn Wesen (bjornw@axis.com)
3 * Hans-Peter Nilsson (hp@axis.com)
4 *
5 * $Log: uaccess.h,v $
6 * Revision 1.5 2000/10/25 03:33:21 hp
7 * - Provide implementation for everything else but get_user and put_user;
8 * copying inline to/from user for constant length 0..16, 20, 24, and
9 * clearing for 0..4, 8, 12, 16, 20, 24, strncpy_from_user and strnlen_user
10 * always inline.
11 * - Constraints for destination addr in get_user cannot be memory, only reg.
12 * - Correct labels for PC at expected fault points.
13 * - Nits with assembly code.
14 * - Don't use statement expressions without value; use "do {} while (0)".
15 * - Return correct values from __generic_... functions.
16 *
17 * Revision 1.4 2000/09/12 16:28:25 bjornw
18 * * Removed comments from the get/put user asm code
19 * * Constrains for destination addr in put_user cannot be memory, only reg
20 *
21 * Revision 1.3 2000/09/12 14:30:20 bjornw
22 * MAX_ADDR_USER does not exist anymore
23 *
24 * Revision 1.2 2000/07/13 15:52:48 bjornw
25 * New user-access functions
26 *
27 * Revision 1.1.1.1 2000/07/10 16:32:31 bjornw
28 * CRIS architecture, working draft
29 *
30 *
31 *
32 */
33
34 /* Asm:s have been tweaked (within the domain of correctness) to give
35 satisfactory results for "gcc version 2.96 20000427 (experimental)".
36
37 Check regularly...
38
39 Register r9 is chosen for temporaries, being a call-clobbered register
40 first in line to be used (notably for local blocks), not colliding with
41 parameter registers. */
42
43 #ifndef _CRIS_UACCESS_H
44 #define _CRIS_UACCESS_H
45
46 #ifndef __ASSEMBLY__
47 #include <linux/sched.h>
48 #include <linux/errno.h>
49 #include <asm/processor.h>
50 #include <asm/page.h>
51
52 #define VERIFY_READ 0
53 #define VERIFY_WRITE 1
54
55 /*
56 * The fs value determines whether argument validity checking should be
57 * performed or not. If get_fs() == USER_DS, checking is performed, with
58 * get_fs() == KERNEL_DS, checking is bypassed.
59 *
60 * For historical reasons, these macros are grossly misnamed.
61 */
62
63 #define MAKE_MM_SEG(s) ((mm_segment_t) { (s) })
64
65 /* addr_limit is the maximum accessible address for the task. we misuse
66 * the KERNEL_DS and USER_DS values to both assign and compare the
67 * addr_limit values through the equally misnamed get/set_fs macros.
68 * (see above)
69 */
70
71 #define KERNEL_DS MAKE_MM_SEG(0xFFFFFFFF)
72 #define USER_DS MAKE_MM_SEG(TASK_SIZE)
73
74 #define get_ds() (KERNEL_DS)
75 #define get_fs() (current->addr_limit)
76 #define set_fs(x) (current->addr_limit = (x))
77
78 #define segment_eq(a,b) ((a).seg == (b).seg)
79
80 #define __kernel_ok (segment_eq(get_fs(), KERNEL_DS))
81 #define __user_ok(addr,size) (((size) <= TASK_SIZE)&&((addr) <= TASK_SIZE-(size)))
82 #define __access_ok(addr,size) (__kernel_ok || __user_ok((addr),(size)))
83 #define access_ok(type,addr,size) __access_ok((unsigned long)(addr),(size))
84
85 extern inline int verify_area(int type, const void * addr, unsigned long size)
86 {
87 return access_ok(type,addr,size) ? 0 : -EFAULT;
88 }
89
90
91 /*
92 * The exception table consists of pairs of addresses: the first is the
93 * address of an instruction that is allowed to fault, and the second is
94 * the address at which the program should continue. No registers are
95 * modified, so it is entirely up to the continuation code to figure out
96 * what to do.
97 *
98 * All the routines below use bits of fixup code that are out of line
99 * with the main instruction path. This means when everything is well,
100 * we don't even have to jump over them. Further, they do not intrude
101 * on our cache or tlb entries.
102 */
103
104 struct exception_table_entry
105 {
106 unsigned long insn, fixup;
107 };
108
109 /* Returns 0 if exception not found and fixup otherwise. */
110 extern unsigned long search_exception_table(unsigned long);
111
112
113 /*
114 * These are the main single-value transfer routines. They automatically
115 * use the right size if we just have the right pointer type.
116 *
117 * This gets kind of ugly. We want to return _two_ values in "get_user()"
118 * and yet we don't want to do any pointers, because that is too much
119 * of a performance impact. Thus we have a few rather ugly macros here,
120 * and hide all the uglyness from the user.
121 *
122 * The "__xxx" versions of the user access functions are versions that
123 * do not verify the address space, that must have been done previously
124 * with a separate "access_ok()" call (this is used when we do multiple
125 * accesses to the same area of user memory).
126 *
127 * As we use the same address space for kernel and user data on
128 * CRIS, we can just do these as direct assignments. (Of course, the
129 * exception handling means that it's no longer "just"...)
130 */
131 #define get_user(x,ptr) \
132 __get_user_check((x),(ptr),sizeof(*(ptr)))
133 #define put_user(x,ptr) \
134 __put_user_check((__typeof__(*(ptr)))(x),(ptr),sizeof(*(ptr)))
135
136 #define __get_user(x,ptr) \
137 __get_user_nocheck((x),(ptr),sizeof(*(ptr)))
138 #define __put_user(x,ptr) \
139 __put_user_nocheck((__typeof__(*(ptr)))(x),(ptr),sizeof(*(ptr)))
140
141 /*
142 * The "xxx_ret" versions return constant specified in third argument, if
143 * something bad happens. These macros can be optimized for the
144 * case of just returning from the function xxx_ret is used.
145 */
146
147 #define put_user_ret(x,ptr,ret) \
148 do { if (put_user(x,ptr)) return ret; } while (0)
149
150 #define get_user_ret(x,ptr,ret) \
151 do { if (get_user(x,ptr)) return ret; } while (0)
152
153 #define __put_user_ret(x,ptr,ret) \
154 do { if (__put_user(x,ptr)) return ret; } while (0)
155
156 #define __get_user_ret(x,ptr,ret) \
157 do { if (__get_user(x,ptr)) return ret; } while (0)
158
159
160 extern long __put_user_bad(void);
161
162 #define __put_user_nocheck(x,ptr,size) \
163 ({ \
164 long __pu_err; \
165 __put_user_size((x),(ptr),(size),__pu_err); \
166 __pu_err; \
167 })
168
169 #define __put_user_check(x,ptr,size) \
170 ({ \
171 long __pu_err = -EFAULT; \
172 __typeof__(*(ptr)) *__pu_addr = (ptr); \
173 if (access_ok(VERIFY_WRITE,__pu_addr,size)) \
174 __put_user_size((x),__pu_addr,(size),__pu_err); \
175 __pu_err; \
176 })
177
178 #define __put_user_size(x,ptr,size,retval) \
179 do { \
180 retval = 0; \
181 switch (size) { \
182 case 1: __put_user_asm(x,ptr,retval,"move.b"); break; \
183 case 2: __put_user_asm(x,ptr,retval,"move.w"); break; \
184 case 4: __put_user_asm(x,ptr,retval,"move.d"); break; \
185 default: __put_user_bad(); \
186 } \
187 } while (0)
188
189 struct __large_struct { unsigned long buf[100]; };
190 #define __m(x) (*(struct __large_struct *)(x))
191
192 /*
193 * We don't tell gcc that we are accessing memory, but this is OK
194 * because we do not write to any memory gcc knows about, so there
195 * are no aliasing issues.
196 *
197 * Note that PC at a fault is the address *after* the faulting
198 * instruction.
199 */
200 #define __put_user_asm(x, addr, err, op) \
201 __asm__ __volatile__( \
202 " "op" %1,[%2]\n" \
203 "2:\n" \
204 " .section .fixup,\"ax\"\n" \
205 "3: move.d %3,%0\n" \
206 " jump 2b\n" \
207 " .previous\n" \
208 " .section __ex_table,\"a\"\n" \
209 " .dword 2b,3b\n" \
210 " .previous\n" \
211 : "=r" (err) \
212 : "r" (x), "r" (addr), "g" (-EFAULT), "0" (err))
213
214
215 #define __get_user_nocheck(x,ptr,size) \
216 ({ \
217 long __gu_err, __gu_val; \
218 __get_user_size(__gu_val,(ptr),(size),__gu_err); \
219 (x) = (__typeof__(*(ptr)))__gu_val; \
220 __gu_err; \
221 })
222
223 #define __get_user_check(x,ptr,size) \
224 ({ \
225 long __gu_err = -EFAULT, __gu_val = 0; \
226 const __typeof__(*(ptr)) *__gu_addr = (ptr); \
227 if (access_ok(VERIFY_READ,__gu_addr,size)) \
228 __get_user_size(__gu_val,__gu_addr,(size),__gu_err); \
229 (x) = (__typeof__(*(ptr)))__gu_val; \
230 __gu_err; \
231 })
232
233 extern long __get_user_bad(void);
234
235 #define __get_user_size(x,ptr,size,retval) \
236 do { \
237 retval = 0; \
238 switch (size) { \
239 case 1: __get_user_asm(x,ptr,retval,"move.b"); break; \
240 case 2: __get_user_asm(x,ptr,retval,"move.w"); break; \
241 case 4: __get_user_asm(x,ptr,retval,"move.d"); break; \
242 default: (x) = __get_user_bad(); \
243 } \
244 } while (0)
245
246 /* See comment before __put_user_asm. */
247
248 #define __get_user_asm(x, addr, err, op) \
249 __asm__ __volatile__( \
250 " "op" [%2],%1\n" \
251 "2:\n" \
252 " .section .fixup,\"ax\"\n" \
253 "3: move.d %3,%0\n" \
254 " moveq 0,%1\n" \
255 " jump 2b\n" \
256 " .previous\n" \
257 " .section __ex_table,\"a\"\n" \
258 " .dword 2b,3b\n" \
259 " .previous\n" \
260 : "=r" (err), "=r" (x) \
261 : "r" (addr), "g" (-EFAULT), "0" (err))
262
263 /* More complex functions. Most are inline, but some call functions that
264 live in lib/usercopy.c */
265
266 extern unsigned long __copy_user(void *to, const void *from, unsigned long n);
267 extern unsigned long __copy_user_zeroing(void *to, const void *from, unsigned long n);
268 extern unsigned long __do_clear_user(void *to, unsigned long n);
269
270 /*
271 * Copy a null terminated string from userspace.
272 *
273 * Must return:
274 * -EFAULT for an exception
275 * count if we hit the buffer limit
276 * bytes copied if we hit a null byte
277 * (without the null byte)
278 */
279
280 static inline long
281 __do_strncpy_from_user(char *dst, const char *src, long count)
282 {
283 long res;
284
285 if (count == 0)
286 return 0;
287
288 /*
289 * Currently, in 2.4.0-test9, most ports use a simple byte-copy loop.
290 * So do we.
291 *
292 * This code is deduced from:
293 *
294 * char tmp2;
295 * long tmp1, tmp3
296 * tmp1 = count;
297 * while ((*dst++ = (tmp2 = *src++)) != 0
298 * && --tmp1)
299 * ;
300 *
301 * res = count - tmp1;
302 *
303 * with tweaks.
304 */
305
306 __asm__ __volatile__ (
307 " move.d %3,%0\n"
308 " move.b [%2+],r9\n"
309 "1: beq 2f\n"
310 " move.b r9,[%1+]\n"
311
312 " subq 1,%0\n"
313 " bne 1b\n"
314 " move.b [%2+],r9\n"
315
316 "2: sub.d %3,%0\n"
317 " neg.d %0,%0\n"
318 "3:\n"
319 " .section .fixup,\"ax\"\n"
320 "4: move.d %7,%0\n"
321 " jump 3b\n"
322
323 /* There's one address for a fault at the first move, and
324 two possible PC values for a fault at the second move,
325 being a delay-slot filler. However, the branch-target
326 for the second move is the same as the first address.
327 Just so you don't get confused... */
328 " .previous\n"
329 " .section __ex_table,\"a\"\n"
330 " .dword 1b,4b\n"
331 " .dword 2b,4b\n"
332 " .previous"
333 : "=r" (res), "=r" (dst), "=r" (src), "=r" (count)
334 : "3" (count), "1" (dst), "2" (src), "g" (-EFAULT)
335 : "r9");
336
337 return res;
338 }
339
340 static inline unsigned long
341 __generic_copy_to_user(void *to, const void *from, unsigned long n)
342 {
343 if (access_ok(VERIFY_WRITE, to, n))
344 return __copy_user(to,from,n);
345 return n;
346 }
347
348 static inline unsigned long
349 __generic_copy_from_user(void *to, const void *from, unsigned long n)
350 {
351 if (access_ok(VERIFY_READ, from, n))
352 return __copy_user_zeroing(to,from,n);
353 return n;
354 }
355
356 static inline unsigned long
357 __generic_clear_user(void *to, unsigned long n)
358 {
359 if (access_ok(VERIFY_WRITE, to, n))
360 return __do_clear_user(to,n);
361 return n;
362 }
363
364 static inline long
365 __strncpy_from_user(char *dst, const char *src, long count)
366 {
367 return __do_strncpy_from_user(dst, src, count);
368 }
369
370 static inline long
371 strncpy_from_user(char *dst, const char *src, long count)
372 {
373 long res = -EFAULT;
374 if (access_ok(VERIFY_READ, src, 1))
375 res = __do_strncpy_from_user(dst, src, count);
376 return res;
377 }
378
379 /* A few copy asms to build up the more complex ones from.
380
381 Note again, a post-increment is performed regardless of whether a bus
382 fault occurred in that instruction, and PC for a faulted insn is the
383 address *after* the insn. */
384
385 #define __asm_copy_user_cont(to, from, ret, COPY, FIXUP, TENTRY) \
386 __asm__ __volatile__ ( \
387 COPY \
388 "1:\n" \
389 " .section .fixup,\"ax\"\n" \
390 FIXUP \
391 " jump 1b\n" \
392 " .previous\n" \
393 " .section __ex_table,\"a\"\n" \
394 TENTRY \
395 " .previous\n" \
396 : "=r" (to), "=r" (from), "=r" (ret) \
397 : "0" (to), "1" (from), "2" (ret) \
398 : "r9", "memory")
399
400 #define __asm_copy_from_user_1(to, from, ret) \
401 __asm_copy_user_cont(to, from, ret, \
402 " move.b [%1+],r9\n" \
403 "2: move.b r9,[%0+]\n", \
404 "3: addq 1,%2\n" \
405 " clear.b [%0+]\n", \
406 " .dword 2b,3b\n")
407
408 #define __asm_copy_from_user_2x_cont(to, from, ret, COPY, FIXUP, TENTRY) \
409 __asm_copy_user_cont(to, from, ret, \
410 " move.w [%1+],r9\n" \
411 "2: move.w r9,[%0+]\n" COPY, \
412 "3: addq 2,%2\n" \
413 " clear.w [%0+]\n" FIXUP, \
414 " .dword 2b,3b\n" TENTRY)
415
416 #define __asm_copy_from_user_2(to, from, ret) \
417 __asm_copy_from_user_2x_cont(to, from, ret, "", "", "")
418
419 #define __asm_copy_from_user_3(to, from, ret) \
420 __asm_copy_from_user_2x_cont(to, from, ret, \
421 " move.b [%1+],r9\n" \
422 "4: move.b r9,[%0+]\n", \
423 "5: addq 1,%2\n" \
424 " clear.b [%0+]\n", \
425 " .dword 4b,5b\n")
426
427 #define __asm_copy_from_user_4x_cont(to, from, ret, COPY, FIXUP, TENTRY) \
428 __asm_copy_user_cont(to, from, ret, \
429 " move.d [%1+],r9\n" \
430 "2: move.d r9,[%0+]\n" COPY, \
431 "3: addq 4,%2\n" \
432 " clear.d [%0+]\n" FIXUP, \
433 " .dword 2b,3b\n" TENTRY)
434
435 #define __asm_copy_from_user_4(to, from, ret) \
436 __asm_copy_from_user_4x_cont(to, from, ret, "", "", "")
437
438 #define __asm_copy_from_user_5(to, from, ret) \
439 __asm_copy_from_user_4x_cont(to, from, ret, \
440 " move.b [%1+],r9\n" \
441 "4: move.b r9,[%0+]\n", \
442 "5: addq 1,%2\n" \
443 " clear.b [%0+]\n", \
444 " .dword 4b,5b\n")
445
446 #define __asm_copy_from_user_6x_cont(to, from, ret, COPY, FIXUP, TENTRY) \
447 __asm_copy_from_user_4x_cont(to, from, ret, \
448 " move.w [%1+],r9\n" \
449 "4: move.w r9,[%0+]\n" COPY, \
450 "5: addq 2,%2\n" \
451 " clear.w [%0+]\n" FIXUP, \
452 " .dword 4b,5b\n" TENTRY)
453
454 #define __asm_copy_from_user_6(to, from, ret) \
455 __asm_copy_from_user_6x_cont(to, from, ret, "", "", "")
456
457 #define __asm_copy_from_user_7(to, from, ret) \
458 __asm_copy_from_user_6x_cont(to, from, ret, \
459 " move.b [%1+],r9\n" \
460 "6: move.b r9,[%0+]\n", \
461 "7: addq 1,%2\n" \
462 " clear.b [%0+]\n", \
463 " .dword 6b,7b\n")
464
465 #define __asm_copy_from_user_8x_cont(to, from, ret, COPY, FIXUP, TENTRY) \
466 __asm_copy_from_user_4x_cont(to, from, ret, \
467 " move.d [%1+],r9\n" \
468 "4: move.d r9,[%0+]\n" COPY, \
469 "5: addq 4,%2\n" \
470 " clear.d [%0+]\n" FIXUP, \
471 " .dword 4b,5b\n" TENTRY)
472
473 #define __asm_copy_from_user_8(to, from, ret) \
474 __asm_copy_from_user_8x_cont(to, from, ret, "", "", "")
475
476 #define __asm_copy_from_user_9(to, from, ret) \
477 __asm_copy_from_user_8x_cont(to, from, ret, \
478 " move.b [%1+],r9\n" \
479 "6: move.b r9,[%0+]\n", \
480 "7: addq 1,%2\n" \
481 " clear.b [%0+]\n", \
482 " .dword 6b,7b\n")
483
484 #define __asm_copy_from_user_10x_cont(to, from, ret, COPY, FIXUP, TENTRY) \
485 __asm_copy_from_user_8x_cont(to, from, ret, \
486 " move.w [%1+],r9\n" \
487 "6: move.w r9,[%0+]\n" COPY, \
488 "7: addq 2,%2\n" \
489 " clear.w [%0+]\n" FIXUP, \
490 " .dword 6b,7b\n" TENTRY)
491
492 #define __asm_copy_from_user_10(to, from, ret) \
493 __asm_copy_from_user_10x_cont(to, from, ret, "", "", "")
494
495 #define __asm_copy_from_user_11(to, from, ret) \
496 __asm_copy_from_user_10x_cont(to, from, ret, \
497 " move.b [%1+],r9\n" \
498 "8: move.b r9,[%0+]\n", \
499 "9: addq 1,%2\n" \
500 " clear.b [%0+]\n", \
501 " .dword 8b,9b\n")
502
503 #define __asm_copy_from_user_12x_cont(to, from, ret, COPY, FIXUP, TENTRY) \
504 __asm_copy_from_user_8x_cont(to, from, ret, \
505 " move.d [%1+],r9\n" \
506 "6: move.d r9,[%0+]\n" COPY, \
507 "7: addq 4,%2\n" \
508 " clear.d [%0+]\n" FIXUP, \
509 " .dword 6b,7b\n" TENTRY)
510
511 #define __asm_copy_from_user_12(to, from, ret) \
512 __asm_copy_from_user_12x_cont(to, from, ret, "", "", "")
513
514 #define __asm_copy_from_user_13(to, from, ret) \
515 __asm_copy_from_user_12x_cont(to, from, ret, \
516 " move.b [%1+],r9\n" \
517 "8: move.b r9,[%0+]\n", \
518 "9: addq 1,%2\n" \
519 " clear.b [%0+]\n", \
520 " .dword 8b,9b\n")
521
522 #define __asm_copy_from_user_14x_cont(to, from, ret, COPY, FIXUP, TENTRY) \
523 __asm_copy_from_user_12x_cont(to, from, ret, \
524 " move.w [%1+],r9\n" \
525 "8: move.w r9,[%0+]\n" COPY, \
526 "9: addq 2,%2\n" \
527 " clear.w [%0+]\n" FIXUP, \
528 " .dword 8b,9b\n" TENTRY)
529
530 #define __asm_copy_from_user_14(to, from, ret) \
531 __asm_copy_from_user_14x_cont(to, from, ret, "", "", "")
532
533 #define __asm_copy_from_user_15(to, from, ret) \
534 __asm_copy_from_user_14x_cont(to, from, ret, \
535 " move.b [%1+],r9\n" \
536 "10: move.b r9,[%0+]\n", \
537 "11: addq 1,%2\n" \
538 " clear.b [%0+]\n", \
539 " .dword 10b,11b\n")
540
541 #define __asm_copy_from_user_16x_cont(to, from, ret, COPY, FIXUP, TENTRY) \
542 __asm_copy_from_user_12x_cont(to, from, ret, \
543 " move.d [%1+],r9\n" \
544 "8: move.d r9,[%0+]\n" COPY, \
545 "9: addq 4,%2\n" \
546 " clear.d [%0+]\n" FIXUP, \
547 " .dword 8b,9b\n" TENTRY)
548
549 #define __asm_copy_from_user_16(to, from, ret) \
550 __asm_copy_from_user_16x_cont(to, from, ret, "", "", "")
551
552 #define __asm_copy_from_user_20x_cont(to, from, ret, COPY, FIXUP, TENTRY) \
553 __asm_copy_from_user_16x_cont(to, from, ret, \
554 " move.d [%1+],r9\n" \
555 "10: move.d r9,[%0+]\n" COPY, \
556 "11: addq 4,%2\n" \
557 " clear.d [%0+]\n" FIXUP, \
558 " .dword 10b,11b\n" TENTRY)
559
560 #define __asm_copy_from_user_20(to, from, ret) \
561 __asm_copy_from_user_20x_cont(to, from, ret, "", "", "")
562
563 #define __asm_copy_from_user_24x_cont(to, from, ret, COPY, FIXUP, TENTRY) \
564 __asm_copy_from_user_20x_cont(to, from, ret, \
565 " move.d [%1+],r9\n" \
566 "12: move.d r9,[%0+]\n" COPY, \
567 "13: addq 4,%2\n" \
568 " clear.d [%0+]\n" FIXUP, \
569 " .dword 12b,13b\n" TENTRY)
570
571 #define __asm_copy_from_user_24(to, from, ret) \
572 __asm_copy_from_user_24x_cont(to, from, ret, "", "", "")
573
574 /* And now, the to-user ones. */
575
576 #define __asm_copy_to_user_1(to, from, ret) \
577 __asm_copy_user_cont(to, from, ret, \
578 " move.b [%1+],r9\n" \
579 " move.b r9,[%0+]\n2:\n", \
580 "3: addq 1,%2\n", \
581 " .dword 2b,3b\n")
582
583 #define __asm_copy_to_user_2x_cont(to, from, ret, COPY, FIXUP, TENTRY) \
584 __asm_copy_user_cont(to, from, ret, \
585 " move.w [%1+],r9\n" \
586 " move.w r9,[%0+]\n2:\n" COPY, \
587 "3: addq 2,%2\n" FIXUP, \
588 " .dword 2b,3b\n" TENTRY)
589
590 #define __asm_copy_to_user_2(to, from, ret) \
591 __asm_copy_to_user_2x_cont(to, from, ret, "", "", "")
592
593 #define __asm_copy_to_user_3(to, from, ret) \
594 __asm_copy_to_user_2x_cont(to, from, ret, \
595 " move.b [%1+],r9\n" \
596 " move.b r9,[%0+]\n4:\n", \
597 "5: addq 1,%2\n", \
598 " .dword 4b,5b\n")
599
600 #define __asm_copy_to_user_4x_cont(to, from, ret, COPY, FIXUP, TENTRY) \
601 __asm_copy_user_cont(to, from, ret, \
602 " move.d [%1+],r9\n" \
603 " move.d r9,[%0+]\n2:\n" COPY, \
604 "3: addq 4,%2\n" FIXUP, \
605 " .dword 2b,3b\n" TENTRY)
606
607 #define __asm_copy_to_user_4(to, from, ret) \
608 __asm_copy_to_user_4x_cont(to, from, ret, "", "", "")
609
610 #define __asm_copy_to_user_5(to, from, ret) \
611 __asm_copy_to_user_4x_cont(to, from, ret, \
612 " move.b [%1+],r9\n" \
613 " move.b r9,[%0+]\n4:\n", \
614 "5: addq 1,%2\n", \
615 " .dword 4b,5b\n")
616
617 #define __asm_copy_to_user_6x_cont(to, from, ret, COPY, FIXUP, TENTRY) \
618 __asm_copy_to_user_4x_cont(to, from, ret, \
619 " move.w [%1+],r9\n" \
620 " move.w r9,[%0+]\n4:\n" COPY, \
621 "5: addq 2,%2\n" FIXUP, \
622 " .dword 4b,5b\n" TENTRY)
623
624 #define __asm_copy_to_user_6(to, from, ret) \
625 __asm_copy_to_user_6x_cont(to, from, ret, "", "", "")
626
627 #define __asm_copy_to_user_7(to, from, ret) \
628 __asm_copy_to_user_6x_cont(to, from, ret, \
629 " move.b [%1+],r9\n" \
630 " move.b r9,[%0+]\n6:\n", \
631 "7: addq 1,%2\n", \
632 " .dword 6b,7b\n")
633
634 #define __asm_copy_to_user_8x_cont(to, from, ret, COPY, FIXUP, TENTRY) \
635 __asm_copy_to_user_4x_cont(to, from, ret, \
636 " move.d [%1+],r9\n" \
637 " move.d r9,[%0+]\n4:\n" COPY, \
638 "5: addq 4,%2\n" FIXUP, \
639 " .dword 4b,5b\n" TENTRY)
640
641 #define __asm_copy_to_user_8(to, from, ret) \
642 __asm_copy_to_user_8x_cont(to, from, ret, "", "", "")
643
644 #define __asm_copy_to_user_9(to, from, ret) \
645 __asm_copy_to_user_8x_cont(to, from, ret, \
646 " move.b [%1+],r9\n" \
647 " move.b r9,[%0+]\n6:\n", \
648 "7: addq 1,%2\n", \
649 " .dword 6b,7b\n")
650
651 #define __asm_copy_to_user_10x_cont(to, from, ret, COPY, FIXUP, TENTRY) \
652 __asm_copy_to_user_8x_cont(to, from, ret, \
653 " move.w [%1+],r9\n" \
654 " move.w r9,[%0+]\n6:\n" COPY, \
655 "7: addq 2,%2\n" FIXUP, \
656 " .dword 6b,7b\n" TENTRY)
657
658 #define __asm_copy_to_user_10(to, from, ret) \
659 __asm_copy_to_user_10x_cont(to, from, ret, "", "", "")
660
661 #define __asm_copy_to_user_11(to, from, ret) \
662 __asm_copy_to_user_10x_cont(to, from, ret, \
663 " move.b [%1+],r9\n" \
664 " move.b r9,[%0+]\n8:\n", \
665 "9: addq 1,%2\n", \
666 " .dword 8b,9b\n")
667
668 #define __asm_copy_to_user_12x_cont(to, from, ret, COPY, FIXUP, TENTRY) \
669 __asm_copy_to_user_8x_cont(to, from, ret, \
670 " move.d [%1+],r9\n" \
671 " move.d r9,[%0+]\n6:\n" COPY, \
672 "7: addq 4,%2\n" FIXUP, \
673 " .dword 6b,7b\n" TENTRY)
674
675 #define __asm_copy_to_user_12(to, from, ret) \
676 __asm_copy_to_user_12x_cont(to, from, ret, "", "", "")
677
678 #define __asm_copy_to_user_13(to, from, ret) \
679 __asm_copy_to_user_12x_cont(to, from, ret, \
680 " move.b [%1+],r9\n" \
681 " move.b r9,[%0+]\n8:\n", \
682 "9: addq 1,%2\n", \
683 " .dword 8b,9b\n")
684
685 #define __asm_copy_to_user_14x_cont(to, from, ret, COPY, FIXUP, TENTRY) \
686 __asm_copy_to_user_12x_cont(to, from, ret, \
687 " move.w [%1+],r9\n" \
688 " move.w r9,[%0+]\n8:\n" COPY, \
689 "9: addq 2,%2\n" FIXUP, \
690 " .dword 8b,9b\n" TENTRY)
691
692 #define __asm_copy_to_user_14(to, from, ret) \
693 __asm_copy_to_user_14x_cont(to, from, ret, "", "", "")
694
695 #define __asm_copy_to_user_15(to, from, ret) \
696 __asm_copy_to_user_14x_cont(to, from, ret, \
697 " move.b [%1+],r9\n" \
698 " move.b r9,[%0+]\n10:\n", \
699 "11: addq 1,%2\n", \
700 " .dword 10b,11b\n")
701
702 #define __asm_copy_to_user_16x_cont(to, from, ret, COPY, FIXUP, TENTRY) \
703 __asm_copy_to_user_12x_cont(to, from, ret, \
704 " move.d [%1+],r9\n" \
705 " move.d r9,[%0+]\n8:\n" COPY, \
706 "9: addq 4,%2\n" FIXUP, \
707 " .dword 8b,9b\n" TENTRY)
708
709 #define __asm_copy_to_user_16(to, from, ret) \
710 __asm_copy_to_user_16x_cont(to, from, ret, "", "", "")
711
712 #define __asm_copy_to_user_20x_cont(to, from, ret, COPY, FIXUP, TENTRY) \
713 __asm_copy_to_user_16x_cont(to, from, ret, \
714 " move.d [%1+],r9\n" \
715 " move.d r9,[%0+]\n10:\n" COPY, \
716 "11: addq 4,%2\n" FIXUP, \
717 " .dword 10b,11b\n" TENTRY)
718
719 #define __asm_copy_to_user_20(to, from, ret) \
720 __asm_copy_to_user_20x_cont(to, from, ret, "", "", "")
721
722 #define __asm_copy_to_user_24x_cont(to, from, ret, COPY, FIXUP, TENTRY) \
723 __asm_copy_to_user_20x_cont(to, from, ret, \
724 " move.d [%1+],r9\n" \
725 " move.d r9,[%0+]\n12:\n" COPY, \
726 "13: addq 4,%2\n" FIXUP, \
727 " .dword 12b,13b\n" TENTRY)
728
729 #define __asm_copy_to_user_24(to, from, ret) \
730 __asm_copy_to_user_24x_cont(to, from, ret, "", "", "")
731
732 /* Define a few clearing asms with exception handlers. */
733
734 /* This frame-asm is like the __asm_copy_user_cont one, but has one less
735 input. */
736
737 #define __asm_clear(to, ret, CLEAR, FIXUP, TENTRY) \
738 __asm__ __volatile__ ( \
739 CLEAR \
740 "1:\n" \
741 " .section .fixup,\"ax\"\n" \
742 FIXUP \
743 " jump 1b\n" \
744 " .previous\n" \
745 " .section __ex_table,\"a\"\n" \
746 TENTRY \
747 " .previous" \
748 : "=r" (to), "=r" (ret) \
749 : "0" (to), "1" (ret) \
750 : "r9", "memory")
751
752 #define __asm_clear_1(to, ret) \
753 __asm_clear(to, ret, \
754 " clear.b [%0+]\n2:\n", \
755 "3: addq 1,%1\n", \
756 " .dword 2b,3b\n")
757
758 #define __asm_clear_2(to, ret) \
759 __asm_clear(to, ret, \
760 " clear.w [%0+]\n2:\n", \
761 "3: addq 2,%1\n", \
762 " .dword 2b,3b\n")
763
764 #define __asm_clear_3(to, ret) \
765 __asm_clear(to, ret, \
766 " clear.w [%0+]\n" \
767 "2: clear.b [%0+]\n3:\n", \
768 "4: addq 2,%1\n" \
769 "5: addq 1,%1\n", \
770 " .dword 2b,4b\n" \
771 " .dword 3b,5b\n")
772
773 #define __asm_clear_4x_cont(to, ret, CLEAR, FIXUP, TENTRY) \
774 __asm_clear(to, ret, \
775 " clear.d [%0+]\n2:\n" CLEAR, \
776 "3: addq 4,%1\n" FIXUP, \
777 " .dword 2b,3b\n" TENTRY)
778
779 #define __asm_clear_4(to, ret) \
780 __asm_clear_4x_cont(to, ret, "", "", "")
781
782 #define __asm_clear_8x_cont(to, ret, CLEAR, FIXUP, TENTRY) \
783 __asm_clear_4x_cont(to, ret, \
784 " clear.d [%0+]\n4:\n" CLEAR, \
785 "5: addq 4,%1\n" FIXUP, \
786 " .dword 4b,5b\n" TENTRY)
787
788 #define __asm_clear_8(to, ret) \
789 __asm_clear_8x_cont(to, ret, "", "", "")
790
791 #define __asm_clear_12x_cont(to, ret, CLEAR, FIXUP, TENTRY) \
792 __asm_clear_8x_cont(to, ret, \
793 " clear.d [%0+]\n6:\n" CLEAR, \
794 "7: addq 4,%1\n" FIXUP, \
795 " .dword 6b,7b\n" TENTRY)
796
797 #define __asm_clear_12(to, ret) \
798 __asm_clear_12x_cont(to, ret, "", "", "")
799
800 #define __asm_clear_16x_cont(to, ret, CLEAR, FIXUP, TENTRY) \
801 __asm_clear_12x_cont(to, ret, \
802 " clear.d [%0+]\n8:\n" CLEAR, \
803 "9: addq 4,%1\n" FIXUP, \
804 " .dword 8b,9b\n" TENTRY)
805
806 #define __asm_clear_16(to, ret) \
807 __asm_clear_16x_cont(to, ret, "", "", "")
808
809 #define __asm_clear_20x_cont(to, ret, CLEAR, FIXUP, TENTRY) \
810 __asm_clear_16x_cont(to, ret, \
811 " clear.d [%0+]\n10:\n" CLEAR, \
812 "11: addq 4,%1\n" FIXUP, \
813 " .dword 10b,11b\n" TENTRY)
814
815 #define __asm_clear_20(to, ret) \
816 __asm_clear_20x_cont(to, ret, "", "", "")
817
818 #define __asm_clear_24x_cont(to, ret, CLEAR, FIXUP, TENTRY) \
819 __asm_clear_20x_cont(to, ret, \
820 " clear.d [%0+]\n12:\n" CLEAR, \
821 "13: addq 4,%1\n" FIXUP, \
822 " .dword 12b,13b\n" TENTRY)
823
824 #define __asm_clear_24(to, ret) \
825 __asm_clear_24x_cont(to, ret, "", "", "")
826
827 /* Note that if these expand awfully if made into switch constructs, so
828 don't do that. */
829
830 static inline unsigned long
831 __constant_copy_from_user(void *to, const void *from, unsigned long n)
832 {
833 unsigned long ret = 0;
834 if (n == 0)
835 ;
836 else if (n == 1)
837 __asm_copy_from_user_1(to, from, ret);
838 else if (n == 2)
839 __asm_copy_from_user_2(to, from, ret);
840 else if (n == 3)
841 __asm_copy_from_user_3(to, from, ret);
842 else if (n == 4)
843 __asm_copy_from_user_4(to, from, ret);
844 else if (n == 5)
845 __asm_copy_from_user_5(to, from, ret);
846 else if (n == 6)
847 __asm_copy_from_user_6(to, from, ret);
848 else if (n == 7)
849 __asm_copy_from_user_7(to, from, ret);
850 else if (n == 8)
851 __asm_copy_from_user_8(to, from, ret);
852 else if (n == 9)
853 __asm_copy_from_user_9(to, from, ret);
854 else if (n == 10)
855 __asm_copy_from_user_10(to, from, ret);
856 else if (n == 11)
857 __asm_copy_from_user_11(to, from, ret);
858 else if (n == 12)
859 __asm_copy_from_user_12(to, from, ret);
860 else if (n == 13)
861 __asm_copy_from_user_13(to, from, ret);
862 else if (n == 14)
863 __asm_copy_from_user_14(to, from, ret);
864 else if (n == 15)
865 __asm_copy_from_user_15(to, from, ret);
866 else if (n == 16)
867 __asm_copy_from_user_16(to, from, ret);
868 else if (n == 20)
869 __asm_copy_from_user_20(to, from, ret);
870 else if (n == 24)
871 __asm_copy_from_user_24(to, from, ret);
872 else
873 ret = __generic_copy_from_user(to, from, n);
874
875 return ret;
876 }
877
878 /* Ditto, don't make a switch out of this. */
879
880 static inline unsigned long
881 __constant_copy_to_user(void *to, const void *from, unsigned long n)
882 {
883 unsigned long ret = 0;
884 if (n == 0)
885 ;
886 else if (n == 1)
887 __asm_copy_to_user_1(to, from, ret);
888 else if (n == 2)
889 __asm_copy_to_user_2(to, from, ret);
890 else if (n == 3)
891 __asm_copy_to_user_3(to, from, ret);
892 else if (n == 4)
893 __asm_copy_to_user_4(to, from, ret);
894 else if (n == 5)
895 __asm_copy_to_user_5(to, from, ret);
896 else if (n == 6)
897 __asm_copy_to_user_6(to, from, ret);
898 else if (n == 7)
899 __asm_copy_to_user_7(to, from, ret);
900 else if (n == 8)
901 __asm_copy_to_user_8(to, from, ret);
902 else if (n == 9)
903 __asm_copy_to_user_9(to, from, ret);
904 else if (n == 10)
905 __asm_copy_to_user_10(to, from, ret);
906 else if (n == 11)
907 __asm_copy_to_user_11(to, from, ret);
908 else if (n == 12)
909 __asm_copy_to_user_12(to, from, ret);
910 else if (n == 13)
911 __asm_copy_to_user_13(to, from, ret);
912 else if (n == 14)
913 __asm_copy_to_user_14(to, from, ret);
914 else if (n == 15)
915 __asm_copy_to_user_15(to, from, ret);
916 else if (n == 16)
917 __asm_copy_to_user_16(to, from, ret);
918 else if (n == 20)
919 __asm_copy_to_user_20(to, from, ret);
920 else if (n == 24)
921 __asm_copy_to_user_24(to, from, ret);
922 else
923 ret = __generic_copy_to_user(to, from, n);
924
925 return ret;
926 }
927
928 /* No switch, please. */
929
930 static inline unsigned long
931 __constant_clear_user(void *to, unsigned long n)
932 {
933 unsigned long ret = 0;
934 if (n == 0)
935 ;
936 else if (n == 1)
937 __asm_clear_1(to, ret);
938 else if (n == 2)
939 __asm_clear_2(to, ret);
940 else if (n == 3)
941 __asm_clear_3(to, ret);
942 else if (n == 4)
943 __asm_clear_4(to, ret);
944 else if (n == 8)
945 __asm_clear_8(to, ret);
946 else if (n == 12)
947 __asm_clear_12(to, ret);
948 else if (n == 16)
949 __asm_clear_16(to, ret);
950 else if (n == 20)
951 __asm_clear_20(to, ret);
952 else if (n == 24)
953 __asm_clear_24(to, ret);
954 else
955 ret = __generic_clear_user(to, n);
956
957 return ret;
958 }
959
960
961 #define clear_user(to, n) \
962 (__builtin_constant_p(n) ? \
963 __constant_clear_user(to, n) : \
964 __generic_clear_user(to, n))
965
966 #define copy_from_user(to, from, n) \
967 (__builtin_constant_p(n) ? \
968 __constant_copy_from_user(to, from, n) : \
969 __generic_copy_from_user(to, from, n))
970
971 #define copy_to_user(to, from, n) \
972 (__builtin_constant_p(n) ? \
973 __constant_copy_to_user(to, from, n) : \
974 __generic_copy_to_user(to, from, n))
975
976 #define copy_to_user_ret(to,from,n,retval) \
977 do { if (copy_to_user(to,from,n)) return retval; } while (0)
978 #define copy_from_user_ret(to,from,n,retval) \
979 do { if (copy_from_user(to,from,n)) return retval; } while (0)
980
981 /* We let the __ versions of copy_from/to_user inline, because they're often
982 * used in fast paths and have only a small space overhead.
983 */
984
985 static inline unsigned long
986 __generic_copy_from_user_nocheck(void *to, const void *from, unsigned long n)
987 {
988 return __copy_user_zeroing(to,from,n);
989 }
990
991 static inline unsigned long
992 __generic_copy_to_user_nocheck(void *to, const void *from, unsigned long n)
993 {
994 return __copy_user(to,from,n);
995 }
996
997 static inline unsigned long
998 __generic_clear_user_nocheck(void *to, unsigned long n)
999 {
1000 return __do_clear_user(to,n);
1001 }
1002
1003 /* without checking */
1004
1005 #define __copy_to_user(to,from,n) __generic_copy_to_user_nocheck((to),(from),(n))
1006 #define __copy_from_user(to,from,n) __generic_copy_from_user_nocheck((to),(from),(n))
1007 #define __clear_user(to,n) __generic_clear_user_nocheck((to),(n))
1008
1009 /*
1010 * Return the size of a string (including the ending 0)
1011 *
1012 * Return length of string in userspace including terminating 0
1013 * or 0 for error. Return a value greater than N if too long.
1014 */
1015
1016 static inline long
1017 strnlen_user(const char *s, long n)
1018 {
1019 long res, tmp1, tmp2;
1020
1021 if (!access_ok(VERIFY_READ, s, 0))
1022 return 0;
1023
1024 /*
1025 * This code is deduced from:
1026 *
1027 * tmp1 = n;
1028 * while (tmp1-- > 0 && *s++)
1029 * ;
1030 *
1031 * res = n - tmp1;
1032 *
1033 * (with tweaks).
1034 */
1035
1036 __asm__ __volatile__ (
1037 " move.d %1,r9\n"
1038 "0:\n"
1039 " ble 1f\n"
1040 " subq 1,r9\n"
1041
1042 " test.b [%0+]\n"
1043 " bne 0b\n"
1044 " test.d r9\n"
1045 "1:\n"
1046 " move.d %1,%0\n"
1047 " sub.d r9,%0\n"
1048 "2:\n"
1049 " .section .fixup,\"ax\"\n"
1050
1051 "3: clear.d %0\n"
1052 " jump 2b\n"
1053
1054 /* There's one address for a fault at the first move, and
1055 two possible PC values for a fault at the second move,
1056 being a delay-slot filler. However, the branch-target
1057 for the second move is the same as the first address.
1058 Just so you don't get confused... */
1059 " .previous\n"
1060 " .section __ex_table,\"a\"\n"
1061 " .dword 0b,3b\n"
1062 " .dword 1b,3b\n"
1063 " .previous\n"
1064 : "=r" (res), "=r" (tmp1)
1065 : "0" (s), "1" (n)
1066 : "r9");
1067
1068 return res;
1069 }
1070
1071 #define strlen_user(str) strnlen_user((str), 0x7ffffffe)
1072
1073 #endif /* __ASSEMBLY__ */
1074
1075 #endif /* _CRIS_UACCESS_H */
1076