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