xref: /linux/arch/nios2/mm/uaccess.c (revision ca55b2fef3a9373fcfc30f82fd26bc7fccbda732)
1 /*
2  * This file is subject to the terms and conditions of the GNU General Public
3  * License.  See the file "COPYING" in the main directory of this archive
4  * for more details.
5  *
6  * Copyright (C) 2009, Wind River Systems Inc
7  * Implemented by fredrik.markstrom@gmail.com and ivarholmqvist@gmail.com
8  */
9 
10 #include <linux/export.h>
11 #include <linux/uaccess.h>
12 
13 asm(".global	__copy_from_user\n"
14 	"   .type __copy_from_user, @function\n"
15 	"__copy_from_user:\n"
16 	"   movi  r2,7\n"
17 	"   mov   r3,r4\n"
18 	"   bge   r2,r6,1f\n"
19 	"   xor   r2,r4,r5\n"
20 	"   andi  r2,r2,3\n"
21 	"   movi  r7,3\n"
22 	"   beq   r2,zero,4f\n"
23 	"1: addi  r6,r6,-1\n"
24 	"   movi  r2,-1\n"
25 	"   beq   r6,r2,3f\n"
26 	"   mov   r7,r2\n"
27 	"2: ldbu  r2,0(r5)\n"
28 	"   addi  r6,r6,-1\n"
29 	"   addi  r5,r5,1\n"
30 	"   stb   r2,0(r3)\n"
31 	"   addi  r3,r3,1\n"
32 	"   bne   r6,r7,2b\n"
33 	"3:\n"
34 	"   addi  r2,r6,1\n"
35 	"   ret\n"
36 	"13:mov   r2,r6\n"
37 	"   ret\n"
38 	"4: andi  r2,r4,1\n"
39 	"   cmpeq r2,r2,zero\n"
40 	"   beq   r2,zero,7f\n"
41 	"5: andi  r2,r3,2\n"
42 	"   beq   r2,zero,6f\n"
43 	"9: ldhu  r2,0(r5)\n"
44 	"   addi  r6,r6,-2\n"
45 	"   addi  r5,r5,2\n"
46 	"   sth   r2,0(r3)\n"
47 	"   addi  r3,r3,2\n"
48 	"6: bge   r7,r6,1b\n"
49 	"10:ldw   r2,0(r5)\n"
50 	"   addi  r6,r6,-4\n"
51 	"   addi  r5,r5,4\n"
52 	"   stw   r2,0(r3)\n"
53 	"   addi  r3,r3,4\n"
54 	"   br    6b\n"
55 	"7: ldbu  r2,0(r5)\n"
56 	"   addi  r6,r6,-1\n"
57 	"   addi  r5,r5,1\n"
58 	"   addi  r3,r4,1\n"
59 	"   stb   r2,0(r4)\n"
60 	"   br    5b\n"
61 	".section __ex_table,\"a\"\n"
62 	".word 2b,3b\n"
63 	".word 9b,13b\n"
64 	".word 10b,13b\n"
65 	".word 7b,13b\n"
66 	".previous\n"
67 	);
68 EXPORT_SYMBOL(__copy_from_user);
69 
70 asm(
71 	"   .global __copy_to_user\n"
72 	"   .type __copy_to_user, @function\n"
73 	"__copy_to_user:\n"
74 	"   movi  r2,7\n"
75 	"   mov   r3,r4\n"
76 	"   bge   r2,r6,1f\n"
77 	"   xor   r2,r4,r5\n"
78 	"   andi  r2,r2,3\n"
79 	"   movi  r7,3\n"
80 	"   beq   r2,zero,4f\n"
81 	/* Bail if we try to copy zero bytes  */
82 	"1: addi  r6,r6,-1\n"
83 	"   movi  r2,-1\n"
84 	"   beq   r6,r2,3f\n"
85 	/* Copy byte by byte for small copies and if src^dst != 0 */
86 	"   mov   r7,r2\n"
87 	"2: ldbu  r2,0(r5)\n"
88 	"   addi  r5,r5,1\n"
89 	"9: stb   r2,0(r3)\n"
90 	"   addi  r6,r6,-1\n"
91 	"   addi  r3,r3,1\n"
92 	"   bne   r6,r7,2b\n"
93 	"3: addi  r2,r6,1\n"
94 	"   ret\n"
95 	"13:mov   r2,r6\n"
96 	"   ret\n"
97 	/*  If 'to' is an odd address byte copy */
98 	"4: andi  r2,r4,1\n"
99 	"   cmpeq r2,r2,zero\n"
100 	"   beq   r2,zero,7f\n"
101 	/* If 'to' is not divideable by four copy halfwords */
102 	"5: andi  r2,r3,2\n"
103 	"   beq   r2,zero,6f\n"
104 	"   ldhu  r2,0(r5)\n"
105 	"   addi  r5,r5,2\n"
106 	"10:sth   r2,0(r3)\n"
107 	"   addi  r6,r6,-2\n"
108 	"   addi  r3,r3,2\n"
109 	/* Copy words */
110 	"6: bge   r7,r6,1b\n"
111 	"   ldw   r2,0(r5)\n"
112 	"   addi  r5,r5,4\n"
113 	"11:stw   r2,0(r3)\n"
114 	"   addi  r6,r6,-4\n"
115 	"   addi  r3,r3,4\n"
116 	"   br    6b\n"
117 	/* Copy remaining bytes */
118 	"7: ldbu  r2,0(r5)\n"
119 	"   addi  r5,r5,1\n"
120 	"   addi  r3,r4,1\n"
121 	"12: stb  r2,0(r4)\n"
122 	"   addi  r6,r6,-1\n"
123 	"   br    5b\n"
124 	".section __ex_table,\"a\"\n"
125 	".word 9b,3b\n"
126 	".word 10b,13b\n"
127 	".word 11b,13b\n"
128 	".word 12b,13b\n"
129 	".previous\n");
130 EXPORT_SYMBOL(__copy_to_user);
131 
132 long strncpy_from_user(char *__to, const char __user *__from, long __len)
133 {
134 	int l = strnlen_user(__from, __len);
135 	int is_zt = 1;
136 
137 	if (l > __len) {
138 		is_zt = 0;
139 		l = __len;
140 	}
141 
142 	if (l == 0 || copy_from_user(__to, __from, l))
143 		return -EFAULT;
144 
145 	if (is_zt)
146 		l--;
147 	return l;
148 }
149 
150 long strnlen_user(const char __user *s, long n)
151 {
152 	long i;
153 
154 	for (i = 0; i < n; i++) {
155 		char c;
156 
157 		if (get_user(c, s + i) == -EFAULT)
158 			return 0;
159 		if (c == 0)
160 			return i + 1;
161 	}
162 	return n + 1;
163 }
164