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 * Copy a null terminated string from userspace.
18 #ifdef CONFIG_ISA_DUAL_ISSUE
20 #define __do_strncpy_from_user(dst,src,count,res) \
22 int __d0, __d1, __d2; \
23 __asm__ __volatile__( \
26 "0: ldb r14, @%3 || addi %3, #1\n" \
27 " stb r14, @%4 || addi %4, #1\n" \
35 ".section .fixup,\"ax\"\n" \
37 "3: seth r14, #high(2b)\n" \
38 " or3 r14, r14, #low(2b)\n" \
39 " jmp r14 || ldi %0, #%5\n" \
41 ".section __ex_table,\"a\"\n" \
45 : "=&r"(res), "=&r"(count), "=&r" (__d0), "=&r" (__d1), \
47 : "i"(-EFAULT), "0"(count), "1"(count), "3"(src), \
49 : "r14", "cbit", "memory"); \
52 #else /* not CONFIG_ISA_DUAL_ISSUE */
54 #define __do_strncpy_from_user(dst,src,count,res) \
56 int __d0, __d1, __d2; \
57 __asm__ __volatile__( \
71 ".section .fixup,\"ax\"\n" \
74 " seth r14, #high(2b)\n" \
75 " or3 r14, r14, #low(2b)\n" \
78 ".section __ex_table,\"a\"\n" \
82 : "=&r"(res), "=&r"(count), "=&r" (__d0), "=&r" (__d1), \
84 : "i"(-EFAULT), "0"(count), "1"(count), "3"(src), \
86 : "r14", "cbit", "memory"); \
89 #endif /* CONFIG_ISA_DUAL_ISSUE */
92 strncpy_from_user(char *dst
, const char __user
*src
, long count
)
95 if (access_ok(VERIFY_READ
, src
, 1))
96 __do_strncpy_from_user(dst
, src
, count
, res
);
105 #ifdef CONFIG_ISA_DUAL_ISSUE
107 #define __do_clear_user(addr,size) \
110 __asm__ __volatile__( \
112 " and3 r14, %0, #3\n" \
114 " and3 r14, %1, #3\n" \
116 " and3 %1, %1, #3\n" \
120 "0: ; word clear \n" \
121 " st %6, @+%0 || addi %2, #-1\n" \
125 "2: ; byte clear \n" \
126 " stb %6, @%0 || addi %1, #-1\n" \
131 ".section .fixup,\"ax\"\n" \
134 " seth r14, #high(9b)\n" \
135 " or3 r14, r14, #low(9b)\n" \
136 " jmp r14 || add %1, %2\n" \
138 ".section __ex_table,\"a\"\n" \
143 : "=&r"(__dst), "=&r"(size), "=&r"(__c) \
144 : "0"(addr), "1"(size), "2"(size / 4), "r"(0) \
145 : "r14", "cbit", "memory"); \
148 #else /* not CONFIG_ISA_DUAL_ISSUE */
150 #define __do_clear_user(addr,size) \
153 __asm__ __volatile__( \
155 " and3 r14, %0, #3\n" \
157 " and3 r14, %1, #3\n" \
159 " and3 %1, %1, #3\n" \
163 "0: st %6, @+%0 ; word clear \n" \
168 "2: stb %6, @%0 ; byte clear \n" \
174 ".section .fixup,\"ax\"\n" \
178 " seth r14, #high(9b)\n" \
179 " or3 r14, r14, #low(9b)\n" \
182 ".section __ex_table,\"a\"\n" \
187 : "=&r"(__dst), "=&r"(size), "=&r"(__c) \
188 : "0"(addr), "1"(size), "2"(size / 4), "r"(0) \
189 : "r14", "cbit", "memory"); \
192 #endif /* not CONFIG_ISA_DUAL_ISSUE */
195 clear_user(void __user
*to
, unsigned long n
)
197 if (access_ok(VERIFY_WRITE
, to
, n
))
198 __do_clear_user(to
, n
);
203 __clear_user(void __user
*to
, unsigned long n
)
205 __do_clear_user(to
, n
);
210 * Return the size of a string (including the ending 0)
212 * Return 0 on exception, a value greater than N if too long
215 #ifdef CONFIG_ISA_DUAL_ISSUE
217 long strnlen_user(const char __user
*s
, long n
)
219 unsigned long mask
= -__addr_ok(s
);
222 __asm__
__volatile__(
223 " and %0, %5 || mv r1, %1\n"
224 " beqz %0, strnlen_exit\n"
226 " bnez r0, strnlen_byte_loop\n"
228 " bc strnlen_byte_loop\n"
229 "strnlen_word_loop:\n"
232 " bc strnlen_last_bytes_fixup\n"
234 " beqz %0, strnlen_exit\n"
235 " bgtz %0, strnlen_word_loop\n"
236 "strnlen_last_bytes:\n"
238 "strnlen_last_bytes_fixup:\n"
240 "strnlen_byte_loop:\n"
241 "1: ldb r0, @%1 || addi %0, #-1\n"
242 " beqz r0, strnlen_exit\n"
244 " bnez %0, strnlen_byte_loop\n"
250 ".section .fixup,\"ax\"\n"
254 "5: seth r1, #high(9b)\n"
255 " or3 r1, r1, #low(9b)\n"
256 " jmp r1 || ldi %0, #0\n"
258 ".section __ex_table,\"a\"\n"
263 : "=&r" (res
), "=r" (s
)
264 : "0" (n
), "1" (s
), "r" (n
& 3), "r" (mask
), "r"(0x01010101)
265 : "r0", "r1", "cbit");
267 /* NOTE: strnlen_user() algorithm:
270 * for (p = s; n-- && *p != '\0'; ++p)
276 /* NOTE: If a null char. exists, return 0.
277 * if ((x - 0x01010101) & ~x & 0x80808080)\n"
284 #else /* not CONFIG_ISA_DUAL_ISSUE */
286 long strnlen_user(const char __user
*s
, long n
)
288 unsigned long mask
= -__addr_ok(s
);
291 __asm__
__volatile__(
294 " beqz %0, strnlen_exit\n"
296 " bnez r0, strnlen_byte_loop\n"
298 " bc strnlen_byte_loop\n"
300 "strnlen_word_loop:\n"
306 " bnez r2, strnlen_last_bytes_fixup\n"
308 " beqz %0, strnlen_exit\n"
309 " bgtz %0, strnlen_word_loop\n"
310 "strnlen_last_bytes:\n"
312 "strnlen_last_bytes_fixup:\n"
314 "strnlen_byte_loop:\n"
317 " beqz r0, strnlen_exit\n"
319 " bnez %0, strnlen_byte_loop\n"
325 ".section .fixup,\"ax\"\n"
330 " seth r1, #high(9b)\n"
331 " or3 r1, r1, #low(9b)\n"
334 ".section __ex_table,\"a\"\n"
339 : "=&r" (res
), "=r" (s
)
340 : "0" (n
), "1" (s
), "r" (n
& 3), "r" (mask
), "r"(0x01010101)
341 : "r0", "r1", "r2", "r3", "cbit");
343 /* NOTE: strnlen_user() algorithm:
346 * for (p = s; n-- && *p != '\0'; ++p)
352 /* NOTE: If a null char. exists, return 0.
353 * if ((x - 0x01010101) & ~x & 0x80808080)\n"
360 #endif /* CONFIG_ISA_DUAL_ISSUE */