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