1 // SPDX-License-Identifier: GPL-2.0
3 * User address space access functions.
4 * The non inlined parts of asm-m32r/uaccess.h are here.
6 * Copyright 1997 Andi Kleen <ak@muc.de>
7 * Copyright 1997 Linus Torvalds
8 * Copyright 2001, 2002, 2004 Hirokazu Takata
10 #include <linux/prefetch.h>
11 #include <linux/string.h>
12 #include <linux/thread_info.h>
13 #include <linux/uaccess.h>
16 * Copy a null terminated string from userspace.
19 #ifdef CONFIG_ISA_DUAL_ISSUE
21 #define __do_strncpy_from_user(dst,src,count,res) \
23 int __d0, __d1, __d2; \
24 __asm__ __volatile__( \
27 "0: ldb r14, @%3 || addi %3, #1\n" \
28 " stb r14, @%4 || addi %4, #1\n" \
36 ".section .fixup,\"ax\"\n" \
38 "3: seth r14, #high(2b)\n" \
39 " or3 r14, r14, #low(2b)\n" \
40 " jmp r14 || ldi %0, #%5\n" \
42 ".section __ex_table,\"a\"\n" \
46 : "=&r"(res), "=&r"(count), "=&r" (__d0), "=&r" (__d1), \
48 : "i"(-EFAULT), "0"(count), "1"(count), "3"(src), \
50 : "r14", "cbit", "memory"); \
53 #else /* not CONFIG_ISA_DUAL_ISSUE */
55 #define __do_strncpy_from_user(dst,src,count,res) \
57 int __d0, __d1, __d2; \
58 __asm__ __volatile__( \
72 ".section .fixup,\"ax\"\n" \
75 " seth r14, #high(2b)\n" \
76 " or3 r14, r14, #low(2b)\n" \
79 ".section __ex_table,\"a\"\n" \
83 : "=&r"(res), "=&r"(count), "=&r" (__d0), "=&r" (__d1), \
85 : "i"(-EFAULT), "0"(count), "1"(count), "3"(src), \
87 : "r14", "cbit", "memory"); \
90 #endif /* CONFIG_ISA_DUAL_ISSUE */
93 strncpy_from_user(char *dst
, const char __user
*src
, long count
)
96 if (access_ok(VERIFY_READ
, src
, 1))
97 __do_strncpy_from_user(dst
, src
, count
, res
);
106 #ifdef CONFIG_ISA_DUAL_ISSUE
108 #define __do_clear_user(addr,size) \
111 __asm__ __volatile__( \
113 " and3 r14, %0, #3\n" \
115 " and3 r14, %1, #3\n" \
117 " and3 %1, %1, #3\n" \
121 "0: ; word clear \n" \
122 " st %6, @+%0 || addi %2, #-1\n" \
126 "2: ; byte clear \n" \
127 " stb %6, @%0 || addi %1, #-1\n" \
132 ".section .fixup,\"ax\"\n" \
135 " seth r14, #high(9b)\n" \
136 " or3 r14, r14, #low(9b)\n" \
137 " jmp r14 || add %1, %2\n" \
139 ".section __ex_table,\"a\"\n" \
144 : "=&r"(__dst), "=&r"(size), "=&r"(__c) \
145 : "0"(addr), "1"(size), "2"(size / 4), "r"(0) \
146 : "r14", "cbit", "memory"); \
149 #else /* not CONFIG_ISA_DUAL_ISSUE */
151 #define __do_clear_user(addr,size) \
154 __asm__ __volatile__( \
156 " and3 r14, %0, #3\n" \
158 " and3 r14, %1, #3\n" \
160 " and3 %1, %1, #3\n" \
164 "0: st %6, @+%0 ; word clear \n" \
169 "2: stb %6, @%0 ; byte clear \n" \
175 ".section .fixup,\"ax\"\n" \
179 " seth r14, #high(9b)\n" \
180 " or3 r14, r14, #low(9b)\n" \
183 ".section __ex_table,\"a\"\n" \
188 : "=&r"(__dst), "=&r"(size), "=&r"(__c) \
189 : "0"(addr), "1"(size), "2"(size / 4), "r"(0) \
190 : "r14", "cbit", "memory"); \
193 #endif /* not CONFIG_ISA_DUAL_ISSUE */
196 clear_user(void __user
*to
, unsigned long n
)
198 if (access_ok(VERIFY_WRITE
, to
, n
))
199 __do_clear_user(to
, n
);
204 __clear_user(void __user
*to
, unsigned long n
)
206 __do_clear_user(to
, n
);
211 * Return the size of a string (including the ending 0)
213 * Return 0 on exception, a value greater than N if too long
216 #ifdef CONFIG_ISA_DUAL_ISSUE
218 long strnlen_user(const char __user
*s
, long n
)
220 unsigned long mask
= -__addr_ok(s
);
223 __asm__
__volatile__(
224 " and %0, %5 || mv r1, %1\n"
225 " beqz %0, strnlen_exit\n"
227 " bnez r0, strnlen_byte_loop\n"
229 " bc strnlen_byte_loop\n"
230 "strnlen_word_loop:\n"
233 " bc strnlen_last_bytes_fixup\n"
235 " beqz %0, strnlen_exit\n"
236 " bgtz %0, strnlen_word_loop\n"
237 "strnlen_last_bytes:\n"
239 "strnlen_last_bytes_fixup:\n"
241 "strnlen_byte_loop:\n"
242 "1: ldb r0, @%1 || addi %0, #-1\n"
243 " beqz r0, strnlen_exit\n"
245 " bnez %0, strnlen_byte_loop\n"
251 ".section .fixup,\"ax\"\n"
255 "5: seth r1, #high(9b)\n"
256 " or3 r1, r1, #low(9b)\n"
257 " jmp r1 || ldi %0, #0\n"
259 ".section __ex_table,\"a\"\n"
264 : "=&r" (res
), "=r" (s
)
265 : "0" (n
), "1" (s
), "r" (n
& 3), "r" (mask
), "r"(0x01010101)
266 : "r0", "r1", "cbit");
268 /* NOTE: strnlen_user() algorithm:
271 * for (p = s; n-- && *p != '\0'; ++p)
277 /* NOTE: If a null char. exists, return 0.
278 * if ((x - 0x01010101) & ~x & 0x80808080)\n"
285 #else /* not CONFIG_ISA_DUAL_ISSUE */
287 long strnlen_user(const char __user
*s
, long n
)
289 unsigned long mask
= -__addr_ok(s
);
292 __asm__
__volatile__(
295 " beqz %0, strnlen_exit\n"
297 " bnez r0, strnlen_byte_loop\n"
299 " bc strnlen_byte_loop\n"
301 "strnlen_word_loop:\n"
307 " bnez r2, strnlen_last_bytes_fixup\n"
309 " beqz %0, strnlen_exit\n"
310 " bgtz %0, strnlen_word_loop\n"
311 "strnlen_last_bytes:\n"
313 "strnlen_last_bytes_fixup:\n"
315 "strnlen_byte_loop:\n"
318 " beqz r0, strnlen_exit\n"
320 " bnez %0, strnlen_byte_loop\n"
326 ".section .fixup,\"ax\"\n"
331 " seth r1, #high(9b)\n"
332 " or3 r1, r1, #low(9b)\n"
335 ".section __ex_table,\"a\"\n"
340 : "=&r" (res
), "=r" (s
)
341 : "0" (n
), "1" (s
), "r" (n
& 3), "r" (mask
), "r"(0x01010101)
342 : "r0", "r1", "r2", "r3", "cbit");
344 /* NOTE: strnlen_user() algorithm:
347 * for (p = s; n-- && *p != '\0'; ++p)
353 /* NOTE: If a null char. exists, return 0.
354 * if ((x - 0x01010101) & ~x & 0x80808080)\n"
361 #endif /* CONFIG_ISA_DUAL_ISSUE */