2 * User address space access functions.
3 * The non inlined parts of asm-m32r/uaccess.h are here.
5 * Copyright 1997 Andi Kleen <ak@muc.de>
6 * Copyright 1997 Linus Torvalds
7 * Copyright 2001, 2002, 2004 Hirokazu Takata
9 #include <linux/prefetch.h>
10 #include <linux/string.h>
11 #include <linux/thread_info.h>
12 #include <linux/uaccess.h>
15 __generic_copy_to_user(void __user
*to
, const void *from
, unsigned long n
)
18 if (access_ok(VERIFY_WRITE
, to
, n
))
19 __copy_user(to
,from
,n
);
24 __generic_copy_from_user(void *to
, const void __user
*from
, unsigned long n
)
27 if (access_ok(VERIFY_READ
, from
, n
))
28 __copy_user_zeroing(to
,from
,n
);
36 * Copy a null terminated string from userspace.
39 #ifdef CONFIG_ISA_DUAL_ISSUE
41 #define __do_strncpy_from_user(dst,src,count,res) \
43 int __d0, __d1, __d2; \
44 __asm__ __volatile__( \
47 "0: ldb r14, @%3 || addi %3, #1\n" \
48 " stb r14, @%4 || addi %4, #1\n" \
56 ".section .fixup,\"ax\"\n" \
58 "3: seth r14, #high(2b)\n" \
59 " or3 r14, r14, #low(2b)\n" \
60 " jmp r14 || ldi %0, #%5\n" \
62 ".section __ex_table,\"a\"\n" \
66 : "=&r"(res), "=&r"(count), "=&r" (__d0), "=&r" (__d1), \
68 : "i"(-EFAULT), "0"(count), "1"(count), "3"(src), \
70 : "r14", "cbit", "memory"); \
73 #else /* not CONFIG_ISA_DUAL_ISSUE */
75 #define __do_strncpy_from_user(dst,src,count,res) \
77 int __d0, __d1, __d2; \
78 __asm__ __volatile__( \
92 ".section .fixup,\"ax\"\n" \
95 " seth r14, #high(2b)\n" \
96 " or3 r14, r14, #low(2b)\n" \
99 ".section __ex_table,\"a\"\n" \
103 : "=&r"(res), "=&r"(count), "=&r" (__d0), "=&r" (__d1), \
105 : "i"(-EFAULT), "0"(count), "1"(count), "3"(src), \
107 : "r14", "cbit", "memory"); \
110 #endif /* CONFIG_ISA_DUAL_ISSUE */
113 __strncpy_from_user(char *dst
, const char __user
*src
, long count
)
116 __do_strncpy_from_user(dst
, src
, count
, res
);
121 strncpy_from_user(char *dst
, const char __user
*src
, long count
)
124 if (access_ok(VERIFY_READ
, src
, 1))
125 __do_strncpy_from_user(dst
, src
, count
, res
);
134 #ifdef CONFIG_ISA_DUAL_ISSUE
136 #define __do_clear_user(addr,size) \
139 __asm__ __volatile__( \
141 " and3 r14, %0, #3\n" \
143 " and3 r14, %1, #3\n" \
145 " and3 %1, %1, #3\n" \
149 "0: ; word clear \n" \
150 " st %6, @+%0 || addi %2, #-1\n" \
154 "2: ; byte clear \n" \
155 " stb %6, @%0 || addi %1, #-1\n" \
160 ".section .fixup,\"ax\"\n" \
163 " seth r14, #high(9b)\n" \
164 " or3 r14, r14, #low(9b)\n" \
165 " jmp r14 || add %1, %2\n" \
167 ".section __ex_table,\"a\"\n" \
172 : "=&r"(__dst), "=&r"(size), "=&r"(__c) \
173 : "0"(addr), "1"(size), "2"(size / 4), "r"(0) \
174 : "r14", "cbit", "memory"); \
177 #else /* not CONFIG_ISA_DUAL_ISSUE */
179 #define __do_clear_user(addr,size) \
182 __asm__ __volatile__( \
184 " and3 r14, %0, #3\n" \
186 " and3 r14, %1, #3\n" \
188 " and3 %1, %1, #3\n" \
192 "0: st %6, @+%0 ; word clear \n" \
197 "2: stb %6, @%0 ; byte clear \n" \
203 ".section .fixup,\"ax\"\n" \
207 " seth r14, #high(9b)\n" \
208 " or3 r14, r14, #low(9b)\n" \
211 ".section __ex_table,\"a\"\n" \
216 : "=&r"(__dst), "=&r"(size), "=&r"(__c) \
217 : "0"(addr), "1"(size), "2"(size / 4), "r"(0) \
218 : "r14", "cbit", "memory"); \
221 #endif /* not CONFIG_ISA_DUAL_ISSUE */
224 clear_user(void __user
*to
, unsigned long n
)
226 if (access_ok(VERIFY_WRITE
, to
, n
))
227 __do_clear_user(to
, n
);
232 __clear_user(void __user
*to
, unsigned long n
)
234 __do_clear_user(to
, n
);
239 * Return the size of a string (including the ending 0)
241 * Return 0 on exception, a value greater than N if too long
244 #ifdef CONFIG_ISA_DUAL_ISSUE
246 long strnlen_user(const char __user
*s
, long n
)
248 unsigned long mask
= -__addr_ok(s
);
251 __asm__
__volatile__(
252 " and %0, %5 || mv r1, %1\n"
253 " beqz %0, strnlen_exit\n"
255 " bnez r0, strnlen_byte_loop\n"
257 " bc strnlen_byte_loop\n"
258 "strnlen_word_loop:\n"
261 " bc strnlen_last_bytes_fixup\n"
263 " beqz %0, strnlen_exit\n"
264 " bgtz %0, strnlen_word_loop\n"
265 "strnlen_last_bytes:\n"
267 "strnlen_last_bytes_fixup:\n"
269 "strnlen_byte_loop:\n"
270 "1: ldb r0, @%1 || addi %0, #-1\n"
271 " beqz r0, strnlen_exit\n"
273 " bnez %0, strnlen_byte_loop\n"
279 ".section .fixup,\"ax\"\n"
283 "5: seth r1, #high(9b)\n"
284 " or3 r1, r1, #low(9b)\n"
285 " jmp r1 || ldi %0, #0\n"
287 ".section __ex_table,\"a\"\n"
292 : "=&r" (res
), "=r" (s
)
293 : "0" (n
), "1" (s
), "r" (n
& 3), "r" (mask
), "r"(0x01010101)
294 : "r0", "r1", "cbit");
296 /* NOTE: strnlen_user() algorithm:
299 * for (p = s; n-- && *p != '\0'; ++p)
305 /* NOTE: If a null char. exists, return 0.
306 * if ((x - 0x01010101) & ~x & 0x80808080)\n"
313 #else /* not CONFIG_ISA_DUAL_ISSUE */
315 long strnlen_user(const char __user
*s
, long n
)
317 unsigned long mask
= -__addr_ok(s
);
320 __asm__
__volatile__(
323 " beqz %0, strnlen_exit\n"
325 " bnez r0, strnlen_byte_loop\n"
327 " bc strnlen_byte_loop\n"
329 "strnlen_word_loop:\n"
335 " bnez r2, strnlen_last_bytes_fixup\n"
337 " beqz %0, strnlen_exit\n"
338 " bgtz %0, strnlen_word_loop\n"
339 "strnlen_last_bytes:\n"
341 "strnlen_last_bytes_fixup:\n"
343 "strnlen_byte_loop:\n"
346 " beqz r0, strnlen_exit\n"
348 " bnez %0, strnlen_byte_loop\n"
354 ".section .fixup,\"ax\"\n"
359 " seth r1, #high(9b)\n"
360 " or3 r1, r1, #low(9b)\n"
363 ".section __ex_table,\"a\"\n"
368 : "=&r" (res
), "=r" (s
)
369 : "0" (n
), "1" (s
), "r" (n
& 3), "r" (mask
), "r"(0x01010101)
370 : "r0", "r1", "r2", "r3", "cbit");
372 /* NOTE: strnlen_user() algorithm:
375 * for (p = s; n-- && *p != '\0'; ++p)
381 /* NOTE: If a null char. exists, return 0.
382 * if ((x - 0x01010101) & ~x & 0x80808080)\n"
389 #endif /* CONFIG_ISA_DUAL_ISSUE */