blob: 2d1dd2106c4dddac42d01732e2e20d863eb0c550 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
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
15unsigned long
Al Viroa8809482005-09-26 06:19:28 +010016__generic_copy_to_user(void __user *to, const void *from, unsigned long n)
Linus Torvalds1da177e2005-04-16 15:20:36 -070017{
18 prefetch(from);
19 if (access_ok(VERIFY_WRITE, to, n))
20 __copy_user(to,from,n);
21 return n;
22}
23
24unsigned long
Al Viroa8809482005-09-26 06:19:28 +010025__generic_copy_from_user(void *to, const void __user *from, unsigned long n)
Linus Torvalds1da177e2005-04-16 15:20:36 -070026{
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) \
43do { \
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" \
Hirokazu Takata6ced13c2006-02-24 13:03:51 -080067 : "=&r"(res), "=&r"(count), "=&r" (__d0), "=&r" (__d1), \
Linus Torvalds1da177e2005-04-16 15:20:36 -070068 "=&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) \
77do { \
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" \
Hirokazu Takata6ced13c2006-02-24 13:03:51 -0800104 : "=&r"(res), "=&r"(count), "=&r" (__d0), "=&r" (__d1), \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700105 "=&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
113long
Al Viroa8809482005-09-26 06:19:28 +0100114__strncpy_from_user(char *dst, const char __user *src, long count)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700115{
116 long res;
117 __do_strncpy_from_user(dst, src, count, res);
118 return res;
119}
120
121long
Al Viroa8809482005-09-26 06:19:28 +0100122strncpy_from_user(char *dst, const char __user *src, long count)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700123{
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) \
138do { \
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) \
181do { \
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
224unsigned long
Al Viroa8809482005-09-26 06:19:28 +0100225clear_user(void __user *to, unsigned long n)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700226{
227 if (access_ok(VERIFY_WRITE, to, n))
228 __do_clear_user(to, n);
229 return n;
230}
231
232unsigned long
Al Viroa8809482005-09-26 06:19:28 +0100233__clear_user(void __user *to, unsigned long n)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700234{
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
Al Viroa8809482005-09-26 06:19:28 +0100247long strnlen_user(const char __user *s, long n)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700248{
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
Al Viroa8809482005-09-26 06:19:28 +0100316long strnlen_user(const char __user *s, long n)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700317{
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