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
14unsigned long
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
23unsigned long
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)			\
42do {									\
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)			\
76do {									\
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
112long
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
120long
121strncpy_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)					\
137do {									\
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)					\
180do {									\
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
223unsigned long
224clear_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
231unsigned long
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
246long 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
315long 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