xref: /openbmc/linux/arch/nios2/mm/uaccess.c (revision 5ccc6af5)
15ccc6af5SLey Foon Tan /*
25ccc6af5SLey Foon Tan  * This file is subject to the terms and conditions of the GNU General Public
35ccc6af5SLey Foon Tan  * License.  See the file "COPYING" in the main directory of this archive
45ccc6af5SLey Foon Tan  * for more details.
55ccc6af5SLey Foon Tan  *
65ccc6af5SLey Foon Tan  * Copyright (C) 2009, Wind River Systems Inc
75ccc6af5SLey Foon Tan  * Implemented by fredrik.markstrom@gmail.com and ivarholmqvist@gmail.com
85ccc6af5SLey Foon Tan  */
95ccc6af5SLey Foon Tan 
105ccc6af5SLey Foon Tan #include <linux/export.h>
115ccc6af5SLey Foon Tan #include <linux/uaccess.h>
125ccc6af5SLey Foon Tan 
135ccc6af5SLey Foon Tan asm(".global	__copy_from_user\n"
145ccc6af5SLey Foon Tan 	"   .type __copy_from_user, @function\n"
155ccc6af5SLey Foon Tan 	"__copy_from_user:\n"
165ccc6af5SLey Foon Tan 	"   movi  r2,7\n"
175ccc6af5SLey Foon Tan 	"   mov   r3,r4\n"
185ccc6af5SLey Foon Tan 	"   bge   r2,r6,1f\n"
195ccc6af5SLey Foon Tan 	"   xor   r2,r4,r5\n"
205ccc6af5SLey Foon Tan 	"   andi  r2,r2,3\n"
215ccc6af5SLey Foon Tan 	"   movi  r7,3\n"
225ccc6af5SLey Foon Tan 	"   beq   r2,zero,4f\n"
235ccc6af5SLey Foon Tan 	"1: addi  r6,r6,-1\n"
245ccc6af5SLey Foon Tan 	"   movi  r2,-1\n"
255ccc6af5SLey Foon Tan 	"   beq   r6,r2,3f\n"
265ccc6af5SLey Foon Tan 	"   mov   r7,r2\n"
275ccc6af5SLey Foon Tan 	"2: ldbu  r2,0(r5)\n"
285ccc6af5SLey Foon Tan 	"   addi  r6,r6,-1\n"
295ccc6af5SLey Foon Tan 	"   addi  r5,r5,1\n"
305ccc6af5SLey Foon Tan 	"   stb   r2,0(r3)\n"
315ccc6af5SLey Foon Tan 	"   addi  r3,r3,1\n"
325ccc6af5SLey Foon Tan 	"   bne   r6,r7,2b\n"
335ccc6af5SLey Foon Tan 	"3:\n"
345ccc6af5SLey Foon Tan 	"   addi  r2,r6,1\n"
355ccc6af5SLey Foon Tan 	"   ret\n"
365ccc6af5SLey Foon Tan 	"13:mov   r2,r6\n"
375ccc6af5SLey Foon Tan 	"   ret\n"
385ccc6af5SLey Foon Tan 	"4: andi  r2,r4,1\n"
395ccc6af5SLey Foon Tan 	"   cmpeq r2,r2,zero\n"
405ccc6af5SLey Foon Tan 	"   beq   r2,zero,7f\n"
415ccc6af5SLey Foon Tan 	"5: andi  r2,r3,2\n"
425ccc6af5SLey Foon Tan 	"   beq   r2,zero,6f\n"
435ccc6af5SLey Foon Tan 	"9: ldhu  r2,0(r5)\n"
445ccc6af5SLey Foon Tan 	"   addi  r6,r6,-2\n"
455ccc6af5SLey Foon Tan 	"   addi  r5,r5,2\n"
465ccc6af5SLey Foon Tan 	"   sth   r2,0(r3)\n"
475ccc6af5SLey Foon Tan 	"   addi  r3,r3,2\n"
485ccc6af5SLey Foon Tan 	"6: bge   r7,r6,1b\n"
495ccc6af5SLey Foon Tan 	"10:ldw   r2,0(r5)\n"
505ccc6af5SLey Foon Tan 	"   addi  r6,r6,-4\n"
515ccc6af5SLey Foon Tan 	"   addi  r5,r5,4\n"
525ccc6af5SLey Foon Tan 	"   stw   r2,0(r3)\n"
535ccc6af5SLey Foon Tan 	"   addi  r3,r3,4\n"
545ccc6af5SLey Foon Tan 	"   br    6b\n"
555ccc6af5SLey Foon Tan 	"7: ldbu  r2,0(r5)\n"
565ccc6af5SLey Foon Tan 	"   addi  r6,r6,-1\n"
575ccc6af5SLey Foon Tan 	"   addi  r5,r5,1\n"
585ccc6af5SLey Foon Tan 	"   addi  r3,r4,1\n"
595ccc6af5SLey Foon Tan 	"   stb   r2,0(r4)\n"
605ccc6af5SLey Foon Tan 	"   br    5b\n"
615ccc6af5SLey Foon Tan 	".section __ex_table,\"a\"\n"
625ccc6af5SLey Foon Tan 	".word 2b,3b\n"
635ccc6af5SLey Foon Tan 	".word 9b,13b\n"
645ccc6af5SLey Foon Tan 	".word 10b,13b\n"
655ccc6af5SLey Foon Tan 	".word 7b,13b\n"
665ccc6af5SLey Foon Tan 	".previous\n"
675ccc6af5SLey Foon Tan 	);
685ccc6af5SLey Foon Tan EXPORT_SYMBOL(__copy_from_user);
695ccc6af5SLey Foon Tan 
705ccc6af5SLey Foon Tan asm(
715ccc6af5SLey Foon Tan 	"   .global __copy_to_user\n"
725ccc6af5SLey Foon Tan 	"   .type __copy_to_user, @function\n"
735ccc6af5SLey Foon Tan 	"__copy_to_user:\n"
745ccc6af5SLey Foon Tan 	"   movi  r2,7\n"
755ccc6af5SLey Foon Tan 	"   mov   r3,r4\n"
765ccc6af5SLey Foon Tan 	"   bge   r2,r6,1f\n"
775ccc6af5SLey Foon Tan 	"   xor   r2,r4,r5\n"
785ccc6af5SLey Foon Tan 	"   andi  r2,r2,3\n"
795ccc6af5SLey Foon Tan 	"   movi  r7,3\n"
805ccc6af5SLey Foon Tan 	"   beq   r2,zero,4f\n"
815ccc6af5SLey Foon Tan 	/* Bail if we try to copy zero bytes  */
825ccc6af5SLey Foon Tan 	"1: addi  r6,r6,-1\n"
835ccc6af5SLey Foon Tan 	"   movi  r2,-1\n"
845ccc6af5SLey Foon Tan 	"   beq   r6,r2,3f\n"
855ccc6af5SLey Foon Tan 	/* Copy byte by byte for small copies and if src^dst != 0 */
865ccc6af5SLey Foon Tan 	"   mov   r7,r2\n"
875ccc6af5SLey Foon Tan 	"2: ldbu  r2,0(r5)\n"
885ccc6af5SLey Foon Tan 	"   addi  r5,r5,1\n"
895ccc6af5SLey Foon Tan 	"9: stb   r2,0(r3)\n"
905ccc6af5SLey Foon Tan 	"   addi  r6,r6,-1\n"
915ccc6af5SLey Foon Tan 	"   addi  r3,r3,1\n"
925ccc6af5SLey Foon Tan 	"   bne   r6,r7,2b\n"
935ccc6af5SLey Foon Tan 	"3: addi  r2,r6,1\n"
945ccc6af5SLey Foon Tan 	"   ret\n"
955ccc6af5SLey Foon Tan 	"13:mov   r2,r6\n"
965ccc6af5SLey Foon Tan 	"   ret\n"
975ccc6af5SLey Foon Tan 	/*  If 'to' is an odd address byte copy */
985ccc6af5SLey Foon Tan 	"4: andi  r2,r4,1\n"
995ccc6af5SLey Foon Tan 	"   cmpeq r2,r2,zero\n"
1005ccc6af5SLey Foon Tan 	"   beq   r2,zero,7f\n"
1015ccc6af5SLey Foon Tan 	/* If 'to' is not divideable by four copy halfwords */
1025ccc6af5SLey Foon Tan 	"5: andi  r2,r3,2\n"
1035ccc6af5SLey Foon Tan 	"   beq   r2,zero,6f\n"
1045ccc6af5SLey Foon Tan 	"   ldhu  r2,0(r5)\n"
1055ccc6af5SLey Foon Tan 	"   addi  r5,r5,2\n"
1065ccc6af5SLey Foon Tan 	"10:sth   r2,0(r3)\n"
1075ccc6af5SLey Foon Tan 	"   addi  r6,r6,-2\n"
1085ccc6af5SLey Foon Tan 	"   addi  r3,r3,2\n"
1095ccc6af5SLey Foon Tan 	/* Copy words */
1105ccc6af5SLey Foon Tan 	"6: bge   r7,r6,1b\n"
1115ccc6af5SLey Foon Tan 	"   ldw   r2,0(r5)\n"
1125ccc6af5SLey Foon Tan 	"   addi  r5,r5,4\n"
1135ccc6af5SLey Foon Tan 	"11:stw   r2,0(r3)\n"
1145ccc6af5SLey Foon Tan 	"   addi  r6,r6,-4\n"
1155ccc6af5SLey Foon Tan 	"   addi  r3,r3,4\n"
1165ccc6af5SLey Foon Tan 	"   br    6b\n"
1175ccc6af5SLey Foon Tan 	/* Copy remaining bytes */
1185ccc6af5SLey Foon Tan 	"7: ldbu  r2,0(r5)\n"
1195ccc6af5SLey Foon Tan 	"   addi  r5,r5,1\n"
1205ccc6af5SLey Foon Tan 	"   addi  r3,r4,1\n"
1215ccc6af5SLey Foon Tan 	"12: stb  r2,0(r4)\n"
1225ccc6af5SLey Foon Tan 	"   addi  r6,r6,-1\n"
1235ccc6af5SLey Foon Tan 	"   br    5b\n"
1245ccc6af5SLey Foon Tan 	".section __ex_table,\"a\"\n"
1255ccc6af5SLey Foon Tan 	".word 9b,3b\n"
1265ccc6af5SLey Foon Tan 	".word 10b,13b\n"
1275ccc6af5SLey Foon Tan 	".word 11b,13b\n"
1285ccc6af5SLey Foon Tan 	".word 12b,13b\n"
1295ccc6af5SLey Foon Tan 	".previous\n");
1305ccc6af5SLey Foon Tan EXPORT_SYMBOL(__copy_to_user);
1315ccc6af5SLey Foon Tan 
1325ccc6af5SLey Foon Tan long strncpy_from_user(char *__to, const char __user *__from, long __len)
1335ccc6af5SLey Foon Tan {
1345ccc6af5SLey Foon Tan 	int l = strnlen_user(__from, __len);
1355ccc6af5SLey Foon Tan 	int is_zt = 1;
1365ccc6af5SLey Foon Tan 
1375ccc6af5SLey Foon Tan 	if (l > __len) {
1385ccc6af5SLey Foon Tan 		is_zt = 0;
1395ccc6af5SLey Foon Tan 		l = __len;
1405ccc6af5SLey Foon Tan 	}
1415ccc6af5SLey Foon Tan 
1425ccc6af5SLey Foon Tan 	if (l == 0 || copy_from_user(__to, __from, l))
1435ccc6af5SLey Foon Tan 		return -EFAULT;
1445ccc6af5SLey Foon Tan 
1455ccc6af5SLey Foon Tan 	if (is_zt)
1465ccc6af5SLey Foon Tan 		l--;
1475ccc6af5SLey Foon Tan 	return l;
1485ccc6af5SLey Foon Tan }
1495ccc6af5SLey Foon Tan 
1505ccc6af5SLey Foon Tan long strnlen_user(const char __user *s, long n)
1515ccc6af5SLey Foon Tan {
1525ccc6af5SLey Foon Tan 	long i;
1535ccc6af5SLey Foon Tan 
1545ccc6af5SLey Foon Tan 	for (i = 0; i < n; i++) {
1555ccc6af5SLey Foon Tan 		char c;
1565ccc6af5SLey Foon Tan 
1575ccc6af5SLey Foon Tan 		if (get_user(c, s + i) == -EFAULT)
1585ccc6af5SLey Foon Tan 			return 0;
1595ccc6af5SLey Foon Tan 		if (c == 0)
1605ccc6af5SLey Foon Tan 			return i + 1;
1615ccc6af5SLey Foon Tan 	}
1625ccc6af5SLey Foon Tan 	return n + 1;
1635ccc6af5SLey Foon Tan }
164