896cef1aca5f43b8da34b8d9d45b2858f3ce84e5
[linux-2.6.git] / arch / m32r / lib / usercopy.c
1 /*
2  * User address space access functions.
3  * The non inlined parts of asm-m32r/uaccess.h are here.
4  *
5  * Copyright 1997 Andi Kleen <ak@muc.de>
6  * Copyright 1997 Linus Torvalds
7  * Copyright 2001, 2002, 2004 Hirokazu Takata
8  */
9 #include <linux/prefetch.h>
10 #include <linux/string.h>
11 #include <linux/thread_info.h>
12 #include <asm/uaccess.h>
13
14 unsigned long
15 __generic_copy_to_user(void __user *to, const void *from, unsigned long n)
16 {
17         prefetch(from);
18         if (access_ok(VERIFY_WRITE, to, n))
19                 __copy_user(to,from,n);
20         return n;
21 }
22
23 unsigned long
24 __generic_copy_from_user(void *to, const void __user *from, unsigned long n)
25 {
26         prefetchw(to);
27         if (access_ok(VERIFY_READ, from, n))
28                 __copy_user_zeroing(to,from,n);
29         else
30                 memset(to, 0, n);
31         return n;
32 }
33
34
35 /*
36  * Copy a null terminated string from userspace.
37  */
38
39 #ifdef CONFIG_ISA_DUAL_ISSUE
40
41 #define __do_strncpy_from_user(dst,src,count,res)                       \
42 do {                                                                    \
43         int __d0, __d1, __d2;                                           \
44         __asm__ __volatile__(                                           \
45                 "       beqz    %1, 2f\n"                               \
46                 "       .fillinsn\n"                                    \
47                 "0:     ldb     r14, @%3    ||  addi    %3, #1\n"       \
48                 "       stb     r14, @%4    ||  addi    %4, #1\n"       \
49                 "       beqz    r14, 1f\n"                              \
50                 "       addi    %1, #-1\n"                              \
51                 "       bnez    %1, 0b\n"                               \
52                 "       .fillinsn\n"                                    \
53                 "1:     sub     %0, %1\n"                               \
54                 "       .fillinsn\n"                                    \
55                 "2:\n"                                                  \
56                 ".section .fixup,\"ax\"\n"                              \
57                 "       .balign 4\n"                                    \
58                 "3:     seth    r14, #high(2b)\n"                       \
59                 "       or3     r14, r14, #low(2b)\n"                   \
60                 "       jmp     r14         ||  ldi     %0, #%5\n"      \
61                 ".previous\n"                                           \
62                 ".section __ex_table,\"a\"\n"                           \
63                 "       .balign 4\n"                                    \
64                 "       .long 0b,3b\n"                                  \
65                 ".previous"                                             \
66                 : "=&r"(res), "=&r"(count), "=&r" (__d0), "=&r" (__d1), \
67                   "=&r" (__d2)                                          \
68                 : "i"(-EFAULT), "0"(count), "1"(count), "3"(src),       \
69                   "4"(dst)                                              \
70                 : "r14", "cbit", "memory");                             \
71 } while (0)
72
73 #else /* not CONFIG_ISA_DUAL_ISSUE */
74
75 #define __do_strncpy_from_user(dst,src,count,res)                       \
76 do {                                                                    \
77         int __d0, __d1, __d2;                                           \
78         __asm__ __volatile__(                                           \
79                 "       beqz    %1, 2f\n"                               \
80                 "       .fillinsn\n"                                    \
81                 "0:     ldb     r14, @%3\n"                             \
82                 "       stb     r14, @%4\n"                             \
83                 "       addi    %3, #1\n"                               \
84                 "       addi    %4, #1\n"                               \
85                 "       beqz    r14, 1f\n"                              \
86                 "       addi    %1, #-1\n"                              \
87                 "       bnez    %1, 0b\n"                               \
88                 "       .fillinsn\n"                                    \
89                 "1:     sub     %0, %1\n"                               \
90                 "       .fillinsn\n"                                    \
91                 "2:\n"                                                  \
92                 ".section .fixup,\"ax\"\n"                              \
93                 "       .balign 4\n"                                    \
94                 "3:     ldi     %0, #%5\n"                              \
95                 "       seth    r14, #high(2b)\n"                       \
96                 "       or3     r14, r14, #low(2b)\n"                   \
97                 "       jmp     r14\n"                                  \
98                 ".previous\n"                                           \
99                 ".section __ex_table,\"a\"\n"                           \
100                 "       .balign 4\n"                                    \
101                 "       .long 0b,3b\n"                                  \
102                 ".previous"                                             \
103                 : "=&r"(res), "=&r"(count), "=&r" (__d0), "=&r" (__d1), \
104                   "=&r" (__d2)                                          \
105                 : "i"(-EFAULT), "0"(count), "1"(count), "3"(src),       \
106                   "4"(dst)                                              \
107                 : "r14", "cbit", "memory");                             \
108 } while (0)
109
110 #endif /* CONFIG_ISA_DUAL_ISSUE */
111
112 long
113 __strncpy_from_user(char *dst, const char __user *src, long count)
114 {
115         long res;
116         __do_strncpy_from_user(dst, src, count, res);
117         return res;
118 }
119
120 long
121 strncpy_from_user(char *dst, const char __user *src, long count)
122 {
123         long res = -EFAULT;
124         if (access_ok(VERIFY_READ, src, 1))
125                 __do_strncpy_from_user(dst, src, count, res);
126         return res;
127 }
128
129
130 /*
131  * Zero Userspace
132  */
133
134 #ifdef CONFIG_ISA_DUAL_ISSUE
135
136 #define __do_clear_user(addr,size)                                      \
137 do {                                                                    \
138         int __dst, __c;                                                 \
139         __asm__ __volatile__(                                           \
140                 "       beqz    %1, 9f\n"                               \
141                 "       and3    r14, %0, #3\n"                          \
142                 "       bnez    r14, 2f\n"                              \
143                 "       and3    r14, %1, #3\n"                          \
144                 "       bnez    r14, 2f\n"                              \
145                 "       and3    %1, %1, #3\n"                           \
146                 "       beqz    %2, 2f\n"                               \
147                 "       addi    %0, #-4\n"                              \
148                 "       .fillinsn\n"                                    \
149                 "0:     ; word clear \n"                                \
150                 "       st      %6, @+%0    ||  addi    %2, #-1\n"      \
151                 "       bnez    %2, 0b\n"                               \
152                 "       beqz    %1, 9f\n"                               \
153                 "       .fillinsn\n"                                    \
154                 "2:     ; byte clear \n"                                \
155                 "       stb     %6, @%0     ||  addi    %1, #-1\n"      \
156                 "       addi    %0, #1\n"                               \
157                 "       bnez    %1, 2b\n"                               \
158                 "       .fillinsn\n"                                    \
159                 "9:\n"                                                  \
160                 ".section .fixup,\"ax\"\n"                              \
161                 "       .balign 4\n"                                    \
162                 "4:     slli    %2, #2\n"                               \
163                 "       seth    r14, #high(9b)\n"                       \
164                 "       or3     r14, r14, #low(9b)\n"                   \
165                 "       jmp     r14         ||  add     %1, %2\n"       \
166                 ".previous\n"                                           \
167                 ".section __ex_table,\"a\"\n"                           \
168                 "       .balign 4\n"                                    \
169                 "       .long 0b,4b\n"                                  \
170                 "       .long 2b,9b\n"                                  \
171                 ".previous\n"                                           \
172                 : "=&r"(__dst), "=&r"(size), "=&r"(__c)                 \
173                 : "0"(addr), "1"(size), "2"(size / 4), "r"(0)           \
174                 : "r14", "cbit", "memory");                             \
175 } while (0)
176
177 #else /* not CONFIG_ISA_DUAL_ISSUE */
178
179 #define __do_clear_user(addr,size)                                      \
180 do {                                                                    \
181         int __dst, __c;                                                 \
182         __asm__ __volatile__(                                           \
183                 "       beqz    %1, 9f\n"                               \
184                 "       and3    r14, %0, #3\n"                          \
185                 "       bnez    r14, 2f\n"                              \
186                 "       and3    r14, %1, #3\n"                          \
187                 "       bnez    r14, 2f\n"                              \
188                 "       and3    %1, %1, #3\n"                           \
189                 "       beqz    %2, 2f\n"                               \
190                 "       addi    %0, #-4\n"                              \
191                 "       .fillinsn\n"                                    \
192                 "0:     st      %6, @+%0        ; word clear \n"        \
193                 "       addi    %2, #-1\n"                              \
194                 "       bnez    %2, 0b\n"                               \
195                 "       beqz    %1, 9f\n"                               \
196                 "       .fillinsn\n"                                    \
197                 "2:     stb     %6, @%0         ; byte clear \n"        \
198                 "       addi    %1, #-1\n"                              \
199                 "       addi    %0, #1\n"                               \
200                 "       bnez    %1, 2b\n"                               \
201                 "       .fillinsn\n"                                    \
202                 "9:\n"                                                  \
203                 ".section .fixup,\"ax\"\n"                              \
204                 "       .balign 4\n"                                    \
205                 "4:     slli    %2, #2\n"                               \
206                 "       add     %1, %2\n"                               \
207                 "       seth    r14, #high(9b)\n"                       \
208                 "       or3     r14, r14, #low(9b)\n"                   \
209                 "       jmp     r14\n"                                  \
210                 ".previous\n"                                           \
211                 ".section __ex_table,\"a\"\n"                           \
212                 "       .balign 4\n"                                    \
213                 "       .long 0b,4b\n"                                  \
214                 "       .long 2b,9b\n"                                  \
215                 ".previous\n"                                           \
216                 : "=&r"(__dst), "=&r"(size), "=&r"(__c)                 \
217                 : "0"(addr), "1"(size), "2"(size / 4), "r"(0)           \
218                 : "r14", "cbit", "memory");                             \
219 } while (0)
220
221 #endif /* not CONFIG_ISA_DUAL_ISSUE */
222
223 unsigned long
224 clear_user(void __user *to, unsigned long n)
225 {
226         if (access_ok(VERIFY_WRITE, to, n))
227                 __do_clear_user(to, n);
228         return n;
229 }
230
231 unsigned long
232 __clear_user(void __user *to, unsigned long n)
233 {
234         __do_clear_user(to, n);
235         return n;
236 }
237
238 /*
239  * Return the size of a string (including the ending 0)
240  *
241  * Return 0 on exception, a value greater than N if too long
242  */
243
244 #ifdef CONFIG_ISA_DUAL_ISSUE
245
246 long strnlen_user(const char __user *s, long n)
247 {
248         unsigned long mask = -__addr_ok(s);
249         unsigned long res;
250
251         __asm__ __volatile__(
252                 "       and     %0, %5      ||  mv      r1, %1\n"
253                 "       beqz    %0, strnlen_exit\n"
254                 "       and3    r0, %1, #3\n"
255                 "       bnez    r0, strnlen_byte_loop\n"
256                 "       cmpui   %0, #4\n"
257                 "       bc      strnlen_byte_loop\n"
258                 "strnlen_word_loop:\n"
259                 "0:     ld      r0, @%1+\n"
260                 "       pcmpbz  r0\n"
261                 "       bc      strnlen_last_bytes_fixup\n"
262                 "       addi    %0, #-4\n"
263                 "       beqz    %0, strnlen_exit\n"
264                 "       bgtz    %0, strnlen_word_loop\n"
265                 "strnlen_last_bytes:\n"
266                 "       mv      %0, %4\n"
267                 "strnlen_last_bytes_fixup:\n"
268                 "       addi    %1, #-4\n"
269                 "strnlen_byte_loop:\n"
270                 "1:     ldb     r0, @%1     ||  addi    %0, #-1\n"
271                 "       beqz    r0, strnlen_exit\n"
272                 "       addi    %1, #1\n"
273                 "       bnez    %0, strnlen_byte_loop\n"
274                 "strnlen_exit:\n"
275                 "       sub     %1, r1\n"
276                 "       add3    %0, %1, #1\n"
277                 "       .fillinsn\n"
278                 "9:\n"
279                 ".section .fixup,\"ax\"\n"
280                 "       .balign 4\n"
281                 "4:     addi    %1, #-4\n"
282                 "       .fillinsn\n"
283                 "5:     seth    r1, #high(9b)\n"
284                 "       or3     r1, r1, #low(9b)\n"
285                 "       jmp     r1          ||  ldi     %0, #0\n"
286                 ".previous\n"
287                 ".section __ex_table,\"a\"\n"
288                 "       .balign 4\n"
289                 "       .long 0b,4b\n"
290                 "       .long 1b,5b\n"
291                 ".previous"
292                 : "=&r" (res), "=r" (s)
293                 : "0" (n), "1" (s), "r" (n & 3), "r" (mask), "r"(0x01010101)
294                 : "r0", "r1", "cbit");
295
296         /* NOTE: strnlen_user() algorism:
297          * {
298          *   char *p;
299          *   for (p = s; n-- && *p != '\0'; ++p)
300          *     ;
301          *   return p - s + 1;
302          * }
303          */
304
305         /* NOTE: If a null char. exists, return 0.
306          * if ((x - 0x01010101) & ~x & 0x80808080)\n"
307          *   return 0;\n"
308          */
309
310         return res & mask;
311 }
312
313 #else /* not CONFIG_ISA_DUAL_ISSUE */
314
315 long strnlen_user(const char __user *s, long n)
316 {
317         unsigned long mask = -__addr_ok(s);
318         unsigned long res;
319
320         __asm__ __volatile__(
321                 "       and     %0, %5\n"
322                 "       mv      r1, %1\n"
323                 "       beqz    %0, strnlen_exit\n"
324                 "       and3    r0, %1, #3\n"
325                 "       bnez    r0, strnlen_byte_loop\n"
326                 "       cmpui   %0, #4\n"
327                 "       bc      strnlen_byte_loop\n"
328                 "       sll3    r3, %6, #7\n"
329                 "strnlen_word_loop:\n"
330                 "0:     ld      r0, @%1+\n"
331                 "       not     r2, r0\n"
332                 "       sub     r0, %6\n"
333                 "       and     r2, r3\n"
334                 "       and     r2, r0\n"
335                 "       bnez    r2, strnlen_last_bytes_fixup\n"
336                 "       addi    %0, #-4\n"
337                 "       beqz    %0, strnlen_exit\n"
338                 "       bgtz    %0, strnlen_word_loop\n"
339                 "strnlen_last_bytes:\n"
340                 "       mv      %0, %4\n"
341                 "strnlen_last_bytes_fixup:\n"
342                 "       addi    %1, #-4\n"
343                 "strnlen_byte_loop:\n"
344                 "1:     ldb     r0, @%1\n"
345                 "       addi    %0, #-1\n"
346                 "       beqz    r0, strnlen_exit\n"
347                 "       addi    %1, #1\n"
348                 "       bnez    %0, strnlen_byte_loop\n"
349                 "strnlen_exit:\n"
350                 "       sub     %1, r1\n"
351                 "       add3    %0, %1, #1\n"
352                 "       .fillinsn\n"
353                 "9:\n"
354                 ".section .fixup,\"ax\"\n"
355                 "       .balign 4\n"
356                 "4:     addi    %1, #-4\n"
357                 "       .fillinsn\n"
358                 "5:     ldi     %0, #0\n"
359                 "       seth    r1, #high(9b)\n"
360                 "       or3     r1, r1, #low(9b)\n"
361                 "       jmp     r1\n"
362                 ".previous\n"
363                 ".section __ex_table,\"a\"\n"
364                 "       .balign 4\n"
365                 "       .long 0b,4b\n"
366                 "       .long 1b,5b\n"
367                 ".previous"
368                 : "=&r" (res), "=r" (s)
369                 : "0" (n), "1" (s), "r" (n & 3), "r" (mask), "r"(0x01010101)
370                 : "r0", "r1", "r2", "r3", "cbit");
371
372         /* NOTE: strnlen_user() algorism:
373          * {
374          *   char *p;
375          *   for (p = s; n-- && *p != '\0'; ++p)
376          *     ;
377          *   return p - s + 1;
378          * }
379          */
380
381         /* NOTE: If a null char. exists, return 0.
382          * if ((x - 0x01010101) & ~x & 0x80808080)\n"
383          *   return 0;\n"
384          */
385
386         return res & mask;
387 }
388
389 #endif /* CONFIG_ISA_DUAL_ISSUE */
390