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
7 #include <linux/module.h>
8 #include <asm/uaccess.h>
9
__generic_copy_from_user(void * to,const void __user * from,unsigned long n)10 unsigned long __generic_copy_from_user(void *to, const void __user *from,
11 unsigned long n)
12 {
13 unsigned long tmp, res;
14
15 asm volatile ("\n"
16 " tst.l %0\n"
17 " jeq 2f\n"
18 "1: moves.l (%1)+,%3\n"
19 " move.l %3,(%2)+\n"
20 " subq.l #1,%0\n"
21 " jne 1b\n"
22 "2: btst #1,%5\n"
23 " jeq 4f\n"
24 "3: moves.w (%1)+,%3\n"
25 " move.w %3,(%2)+\n"
26 "4: btst #0,%5\n"
27 " jeq 6f\n"
28 "5: moves.b (%1)+,%3\n"
29 " move.b %3,(%2)+\n"
30 "6:\n"
31 " .section .fixup,\"ax\"\n"
32 " .even\n"
33 "10: move.l %0,%3\n"
34 "7: clr.l (%2)+\n"
35 " subq.l #1,%3\n"
36 " jne 7b\n"
37 " lsl.l #2,%0\n"
38 " btst #1,%5\n"
39 " jeq 8f\n"
40 "30: clr.w (%2)+\n"
41 " addq.l #2,%0\n"
42 "8: btst #0,%5\n"
43 " jeq 6b\n"
44 "50: clr.b (%2)+\n"
45 " addq.l #1,%0\n"
46 " jra 6b\n"
47 " .previous\n"
48 "\n"
49 " .section __ex_table,\"a\"\n"
50 " .align 4\n"
51 " .long 1b,10b\n"
52 " .long 3b,30b\n"
53 " .long 5b,50b\n"
54 " .previous"
55 : "=d" (res), "+a" (from), "+a" (to), "=&r" (tmp)
56 : "0" (n / 4), "d" (n & 3));
57
58 return res;
59 }
60 EXPORT_SYMBOL(__generic_copy_from_user);
61
__generic_copy_to_user(void __user * to,const void * from,unsigned long n)62 unsigned long __generic_copy_to_user(void __user *to, const void *from,
63 unsigned long n)
64 {
65 unsigned long tmp, res;
66
67 asm volatile ("\n"
68 " tst.l %0\n"
69 " jeq 4f\n"
70 "1: move.l (%1)+,%3\n"
71 "2: moves.l %3,(%2)+\n"
72 "3: subq.l #1,%0\n"
73 " jne 1b\n"
74 "4: btst #1,%5\n"
75 " jeq 6f\n"
76 " move.w (%1)+,%3\n"
77 "5: moves.w %3,(%2)+\n"
78 "6: btst #0,%5\n"
79 " jeq 8f\n"
80 " move.b (%1)+,%3\n"
81 "7: moves.b %3,(%2)+\n"
82 "8:\n"
83 " .section .fixup,\"ax\"\n"
84 " .even\n"
85 "20: lsl.l #2,%0\n"
86 "50: add.l %5,%0\n"
87 " jra 8b\n"
88 " .previous\n"
89 "\n"
90 " .section __ex_table,\"a\"\n"
91 " .align 4\n"
92 " .long 2b,20b\n"
93 " .long 3b,20b\n"
94 " .long 5b,50b\n"
95 " .long 6b,50b\n"
96 " .long 7b,50b\n"
97 " .long 8b,50b\n"
98 " .previous"
99 : "=d" (res), "+a" (from), "+a" (to), "=&r" (tmp)
100 : "0" (n / 4), "d" (n & 3));
101
102 return res;
103 }
104 EXPORT_SYMBOL(__generic_copy_to_user);
105
106 /*
107 * Copy a null terminated string from userspace.
108 */
strncpy_from_user(char * dst,const char __user * src,long count)109 long strncpy_from_user(char *dst, const char __user *src, long count)
110 {
111 long res;
112 char c;
113
114 if (count <= 0)
115 return count;
116
117 asm volatile ("\n"
118 "1: moves.b (%2)+,%4\n"
119 " move.b %4,(%1)+\n"
120 " jeq 2f\n"
121 " subq.l #1,%3\n"
122 " jne 1b\n"
123 "2: sub.l %3,%0\n"
124 "3:\n"
125 " .section .fixup,\"ax\"\n"
126 " .even\n"
127 "10: move.l %5,%0\n"
128 " jra 3b\n"
129 " .previous\n"
130 "\n"
131 " .section __ex_table,\"a\"\n"
132 " .align 4\n"
133 " .long 1b,10b\n"
134 " .previous"
135 : "=d" (res), "+a" (dst), "+a" (src), "+r" (count), "=&d" (c)
136 : "i" (-EFAULT), "0" (count));
137
138 return res;
139 }
140 EXPORT_SYMBOL(strncpy_from_user);
141
142 /*
143 * Return the size of a string (including the ending 0)
144 *
145 * Return 0 on exception, a value greater than N if too long
146 */
strnlen_user(const char __user * src,long n)147 long strnlen_user(const char __user *src, long n)
148 {
149 char c;
150 long res;
151
152 asm volatile ("\n"
153 "1: subq.l #1,%1\n"
154 " jmi 3f\n"
155 "2: moves.b (%0)+,%2\n"
156 " tst.b %2\n"
157 " jne 1b\n"
158 " jra 4f\n"
159 "\n"
160 "3: addq.l #1,%0\n"
161 "4: sub.l %4,%0\n"
162 "5:\n"
163 " .section .fixup,\"ax\"\n"
164 " .even\n"
165 "20: sub.l %0,%0\n"
166 " jra 5b\n"
167 " .previous\n"
168 "\n"
169 " .section __ex_table,\"a\"\n"
170 " .align 4\n"
171 " .long 2b,20b\n"
172 " .previous\n"
173 : "=&a" (res), "+d" (n), "=&d" (c)
174 : "0" (src), "r" (src));
175
176 return res;
177 }
178 EXPORT_SYMBOL(strnlen_user);
179
180 /*
181 * Zero Userspace
182 */
183
__clear_user(void __user * to,unsigned long n)184 unsigned long __clear_user(void __user *to, unsigned long n)
185 {
186 unsigned long res;
187
188 asm volatile ("\n"
189 " tst.l %0\n"
190 " jeq 3f\n"
191 "1: moves.l %2,(%1)+\n"
192 "2: subq.l #1,%0\n"
193 " jne 1b\n"
194 "3: btst #1,%4\n"
195 " jeq 5f\n"
196 "4: moves.w %2,(%1)+\n"
197 "5: btst #0,%4\n"
198 " jeq 7f\n"
199 "6: moves.b %2,(%1)\n"
200 "7:\n"
201 " .section .fixup,\"ax\"\n"
202 " .even\n"
203 "10: lsl.l #2,%0\n"
204 "40: add.l %4,%0\n"
205 " jra 7b\n"
206 " .previous\n"
207 "\n"
208 " .section __ex_table,\"a\"\n"
209 " .align 4\n"
210 " .long 1b,10b\n"
211 " .long 2b,10b\n"
212 " .long 4b,40b\n"
213 " .long 5b,40b\n"
214 " .long 6b,40b\n"
215 " .long 7b,40b\n"
216 " .previous"
217 : "=d" (res), "+a" (to)
218 : "r" (0), "0" (n / 4), "d" (n & 3));
219
220 return res;
221 }
222 EXPORT_SYMBOL(__clear_user);
223