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