1 /* SPDX-License-Identifier: GPL-2.0-only */
2 /*
3 * Copyright (C) 2004, 2007-2010, 2011-2012 Synopsys, Inc. (www.synopsys.com)
4 *
5 * vineetg: June 2010
6 * -__clear_user( ) called multiple times during elf load was byte loop
7 * converted to do as much word clear as possible.
8 *
9 * vineetg: Dec 2009
10 * -Hand crafted constant propagation for "constant" copy sizes
11 * -stock kernel shrunk by 33K at -O3
12 *
13 * vineetg: Sept 2009
14 * -Added option to (UN)inline copy_(to|from)_user to reduce code sz
15 * -kernel shrunk by 200K even at -O3 (gcc 4.2.1)
16 * -Enabled when doing -Os
17 *
18 * Amit Bhor, Sameer Dhavale: Codito Technologies 2004
19 */
20
21 #ifndef _ASM_ARC_UACCESS_H
22 #define _ASM_ARC_UACCESS_H
23
24 #include <linux/string.h> /* for generic string functions */
25
26
27 #define __kernel_ok (uaccess_kernel())
28
29 /*
30 * Algorithmically, for __user_ok() we want do:
31 * (start < TASK_SIZE) && (start+len < TASK_SIZE)
32 * where TASK_SIZE could either be retrieved from thread_info->addr_limit or
33 * emitted directly in code.
34 *
35 * This can however be rewritten as follows:
36 * (len <= TASK_SIZE) && (start+len < TASK_SIZE)
37 *
38 * Because it essentially checks if buffer end is within limit and @len is
39 * non-ngeative, which implies that buffer start will be within limit too.
40 *
41 * The reason for rewriting being, for majority of cases, @len is generally
42 * compile time constant, causing first sub-expression to be compile time
43 * subsumed.
44 *
45 * The second part would generate weird large LIMMs e.g. (0x6000_0000 - 0x10),
46 * so we check for TASK_SIZE using get_fs() since the addr_limit load from mem
47 * would already have been done at this call site for __kernel_ok()
48 *
49 */
50 #define __user_ok(addr, sz) (((sz) <= TASK_SIZE) && \
51 ((addr) <= (get_fs() - (sz))))
52 #define __access_ok(addr, sz) (unlikely(__kernel_ok) || \
53 likely(__user_ok((addr), (sz))))
54
55 /*********** Single byte/hword/word copies ******************/
56
57 #define __get_user_fn(sz, u, k) \
58 ({ \
59 long __ret = 0; /* success by default */ \
60 switch (sz) { \
61 case 1: __arc_get_user_one(*(k), u, "ldb", __ret); break; \
62 case 2: __arc_get_user_one(*(k), u, "ldw", __ret); break; \
63 case 4: __arc_get_user_one(*(k), u, "ld", __ret); break; \
64 case 8: __arc_get_user_one_64(*(k), u, __ret); break; \
65 } \
66 __ret; \
67 })
68
69 /*
70 * Returns 0 on success, -EFAULT if not.
71 * @ret already contains 0 - given that errors will be less likely
72 * (hence +r asm constraint below).
73 * In case of error, fixup code will make it -EFAULT
74 */
75 #define __arc_get_user_one(dst, src, op, ret) \
76 __asm__ __volatile__( \
77 "1: "op" %1,[%2]\n" \
78 "2: ;nop\n" \
79 " .section .fixup, \"ax\"\n" \
80 " .align 4\n" \
81 "3: # return -EFAULT\n" \
82 " mov %0, %3\n" \
83 " # zero out dst ptr\n" \
84 " mov %1, 0\n" \
85 " j 2b\n" \
86 " .previous\n" \
87 " .section __ex_table, \"a\"\n" \
88 " .align 4\n" \
89 " .word 1b,3b\n" \
90 " .previous\n" \
91 \
92 : "+r" (ret), "=r" (dst) \
93 : "r" (src), "ir" (-EFAULT))
94
95 #define __arc_get_user_one_64(dst, src, ret) \
96 __asm__ __volatile__( \
97 "1: ld %1,[%2]\n" \
98 "4: ld %R1,[%2, 4]\n" \
99 "2: ;nop\n" \
100 " .section .fixup, \"ax\"\n" \
101 " .align 4\n" \
102 "3: # return -EFAULT\n" \
103 " mov %0, %3\n" \
104 " # zero out dst ptr\n" \
105 " mov %1, 0\n" \
106 " mov %R1, 0\n" \
107 " j 2b\n" \
108 " .previous\n" \
109 " .section __ex_table, \"a\"\n" \
110 " .align 4\n" \
111 " .word 1b,3b\n" \
112 " .word 4b,3b\n" \
113 " .previous\n" \
114 \
115 : "+r" (ret), "=r" (dst) \
116 : "r" (src), "ir" (-EFAULT))
117
118 #define __put_user_fn(sz, u, k) \
119 ({ \
120 long __ret = 0; /* success by default */ \
121 switch (sz) { \
122 case 1: __arc_put_user_one(*(k), u, "stb", __ret); break; \
123 case 2: __arc_put_user_one(*(k), u, "stw", __ret); break; \
124 case 4: __arc_put_user_one(*(k), u, "st", __ret); break; \
125 case 8: __arc_put_user_one_64(*(k), u, __ret); break; \
126 } \
127 __ret; \
128 })
129
130 #define __arc_put_user_one(src, dst, op, ret) \
131 __asm__ __volatile__( \
132 "1: "op" %1,[%2]\n" \
133 "2: ;nop\n" \
134 " .section .fixup, \"ax\"\n" \
135 " .align 4\n" \
136 "3: mov %0, %3\n" \
137 " j 2b\n" \
138 " .previous\n" \
139 " .section __ex_table, \"a\"\n" \
140 " .align 4\n" \
141 " .word 1b,3b\n" \
142 " .previous\n" \
143 \
144 : "+r" (ret) \
145 : "r" (src), "r" (dst), "ir" (-EFAULT))
146
147 #define __arc_put_user_one_64(src, dst, ret) \
148 __asm__ __volatile__( \
149 "1: st %1,[%2]\n" \
150 "4: st %R1,[%2, 4]\n" \
151 "2: ;nop\n" \
152 " .section .fixup, \"ax\"\n" \
153 " .align 4\n" \
154 "3: mov %0, %3\n" \
155 " j 2b\n" \
156 " .previous\n" \
157 " .section __ex_table, \"a\"\n" \
158 " .align 4\n" \
159 " .word 1b,3b\n" \
160 " .word 4b,3b\n" \
161 " .previous\n" \
162 \
163 : "+r" (ret) \
164 : "r" (src), "r" (dst), "ir" (-EFAULT))
165
166
167 static inline unsigned long
raw_copy_from_user(void * to,const void __user * from,unsigned long n)168 raw_copy_from_user(void *to, const void __user *from, unsigned long n)
169 {
170 long res = 0;
171 char val;
172 unsigned long tmp1, tmp2, tmp3, tmp4;
173 unsigned long orig_n = n;
174
175 if (n == 0)
176 return 0;
177
178 /* unaligned */
179 if (((unsigned long)to & 0x3) || ((unsigned long)from & 0x3)) {
180
181 unsigned char tmp;
182
183 __asm__ __volatile__ (
184 " mov.f lp_count, %0 \n"
185 " lpnz 2f \n"
186 "1: ldb.ab %1, [%3, 1] \n"
187 " stb.ab %1, [%2, 1] \n"
188 " sub %0,%0,1 \n"
189 "2: ;nop \n"
190 " .section .fixup, \"ax\" \n"
191 " .align 4 \n"
192 "3: j 2b \n"
193 " .previous \n"
194 " .section __ex_table, \"a\" \n"
195 " .align 4 \n"
196 " .word 1b, 3b \n"
197 " .previous \n"
198
199 : "+r" (n),
200 /*
201 * Note as an '&' earlyclobber operand to make sure the
202 * temporary register inside the loop is not the same as
203 * FROM or TO.
204 */
205 "=&r" (tmp), "+r" (to), "+r" (from)
206 :
207 : "lp_count", "memory");
208
209 return n;
210 }
211
212 /*
213 * Hand-crafted constant propagation to reduce code sz of the
214 * laddered copy 16x,8,4,2,1
215 */
216 if (__builtin_constant_p(orig_n)) {
217 res = orig_n;
218
219 if (orig_n / 16) {
220 orig_n = orig_n % 16;
221
222 __asm__ __volatile__(
223 " lsr lp_count, %7,4 \n"
224 " lp 3f \n"
225 "1: ld.ab %3, [%2, 4] \n"
226 "11: ld.ab %4, [%2, 4] \n"
227 "12: ld.ab %5, [%2, 4] \n"
228 "13: ld.ab %6, [%2, 4] \n"
229 " st.ab %3, [%1, 4] \n"
230 " st.ab %4, [%1, 4] \n"
231 " st.ab %5, [%1, 4] \n"
232 " st.ab %6, [%1, 4] \n"
233 " sub %0,%0,16 \n"
234 "3: ;nop \n"
235 " .section .fixup, \"ax\" \n"
236 " .align 4 \n"
237 "4: j 3b \n"
238 " .previous \n"
239 " .section __ex_table, \"a\" \n"
240 " .align 4 \n"
241 " .word 1b, 4b \n"
242 " .word 11b,4b \n"
243 " .word 12b,4b \n"
244 " .word 13b,4b \n"
245 " .previous \n"
246 : "+r" (res), "+r"(to), "+r"(from),
247 "=r"(tmp1), "=r"(tmp2), "=r"(tmp3), "=r"(tmp4)
248 : "ir"(n)
249 : "lp_count", "memory");
250 }
251 if (orig_n / 8) {
252 orig_n = orig_n % 8;
253
254 __asm__ __volatile__(
255 "14: ld.ab %3, [%2,4] \n"
256 "15: ld.ab %4, [%2,4] \n"
257 " st.ab %3, [%1,4] \n"
258 " st.ab %4, [%1,4] \n"
259 " sub %0,%0,8 \n"
260 "31: ;nop \n"
261 " .section .fixup, \"ax\" \n"
262 " .align 4 \n"
263 "4: j 31b \n"
264 " .previous \n"
265 " .section __ex_table, \"a\" \n"
266 " .align 4 \n"
267 " .word 14b,4b \n"
268 " .word 15b,4b \n"
269 " .previous \n"
270 : "+r" (res), "+r"(to), "+r"(from),
271 "=r"(tmp1), "=r"(tmp2)
272 :
273 : "memory");
274 }
275 if (orig_n / 4) {
276 orig_n = orig_n % 4;
277
278 __asm__ __volatile__(
279 "16: ld.ab %3, [%2,4] \n"
280 " st.ab %3, [%1,4] \n"
281 " sub %0,%0,4 \n"
282 "32: ;nop \n"
283 " .section .fixup, \"ax\" \n"
284 " .align 4 \n"
285 "4: j 32b \n"
286 " .previous \n"
287 " .section __ex_table, \"a\" \n"
288 " .align 4 \n"
289 " .word 16b,4b \n"
290 " .previous \n"
291 : "+r" (res), "+r"(to), "+r"(from), "=r"(tmp1)
292 :
293 : "memory");
294 }
295 if (orig_n / 2) {
296 orig_n = orig_n % 2;
297
298 __asm__ __volatile__(
299 "17: ldw.ab %3, [%2,2] \n"
300 " stw.ab %3, [%1,2] \n"
301 " sub %0,%0,2 \n"
302 "33: ;nop \n"
303 " .section .fixup, \"ax\" \n"
304 " .align 4 \n"
305 "4: j 33b \n"
306 " .previous \n"
307 " .section __ex_table, \"a\" \n"
308 " .align 4 \n"
309 " .word 17b,4b \n"
310 " .previous \n"
311 : "+r" (res), "+r"(to), "+r"(from), "=r"(tmp1)
312 :
313 : "memory");
314 }
315 if (orig_n & 1) {
316 __asm__ __volatile__(
317 "18: ldb.ab %3, [%2,2] \n"
318 " stb.ab %3, [%1,2] \n"
319 " sub %0,%0,1 \n"
320 "34: ; nop \n"
321 " .section .fixup, \"ax\" \n"
322 " .align 4 \n"
323 "4: j 34b \n"
324 " .previous \n"
325 " .section __ex_table, \"a\" \n"
326 " .align 4 \n"
327 " .word 18b,4b \n"
328 " .previous \n"
329 : "+r" (res), "+r"(to), "+r"(from), "=r"(tmp1)
330 :
331 : "memory");
332 }
333 } else { /* n is NOT constant, so laddered copy of 16x,8,4,2,1 */
334
335 __asm__ __volatile__(
336 " mov %0,%3 \n"
337 " lsr.f lp_count, %3,4 \n" /* 16x bytes */
338 " lpnz 3f \n"
339 "1: ld.ab %5, [%2, 4] \n"
340 "11: ld.ab %6, [%2, 4] \n"
341 "12: ld.ab %7, [%2, 4] \n"
342 "13: ld.ab %8, [%2, 4] \n"
343 " st.ab %5, [%1, 4] \n"
344 " st.ab %6, [%1, 4] \n"
345 " st.ab %7, [%1, 4] \n"
346 " st.ab %8, [%1, 4] \n"
347 " sub %0,%0,16 \n"
348 "3: and.f %3,%3,0xf \n" /* stragglers */
349 " bz 34f \n"
350 " bbit0 %3,3,31f \n" /* 8 bytes left */
351 "14: ld.ab %5, [%2,4] \n"
352 "15: ld.ab %6, [%2,4] \n"
353 " st.ab %5, [%1,4] \n"
354 " st.ab %6, [%1,4] \n"
355 " sub.f %0,%0,8 \n"
356 "31: bbit0 %3,2,32f \n" /* 4 bytes left */
357 "16: ld.ab %5, [%2,4] \n"
358 " st.ab %5, [%1,4] \n"
359 " sub.f %0,%0,4 \n"
360 "32: bbit0 %3,1,33f \n" /* 2 bytes left */
361 "17: ldw.ab %5, [%2,2] \n"
362 " stw.ab %5, [%1,2] \n"
363 " sub.f %0,%0,2 \n"
364 "33: bbit0 %3,0,34f \n"
365 "18: ldb.ab %5, [%2,1] \n" /* 1 byte left */
366 " stb.ab %5, [%1,1] \n"
367 " sub.f %0,%0,1 \n"
368 "34: ;nop \n"
369 " .section .fixup, \"ax\" \n"
370 " .align 4 \n"
371 "4: j 34b \n"
372 " .previous \n"
373 " .section __ex_table, \"a\" \n"
374 " .align 4 \n"
375 " .word 1b, 4b \n"
376 " .word 11b,4b \n"
377 " .word 12b,4b \n"
378 " .word 13b,4b \n"
379 " .word 14b,4b \n"
380 " .word 15b,4b \n"
381 " .word 16b,4b \n"
382 " .word 17b,4b \n"
383 " .word 18b,4b \n"
384 " .previous \n"
385 : "=r" (res), "+r"(to), "+r"(from), "+r"(n), "=r"(val),
386 "=r"(tmp1), "=r"(tmp2), "=r"(tmp3), "=r"(tmp4)
387 :
388 : "lp_count", "memory");
389 }
390
391 return res;
392 }
393
394 static inline unsigned long
raw_copy_to_user(void __user * to,const void * from,unsigned long n)395 raw_copy_to_user(void __user *to, const void *from, unsigned long n)
396 {
397 long res = 0;
398 char val;
399 unsigned long tmp1, tmp2, tmp3, tmp4;
400 unsigned long orig_n = n;
401
402 if (n == 0)
403 return 0;
404
405 /* unaligned */
406 if (((unsigned long)to & 0x3) || ((unsigned long)from & 0x3)) {
407
408 unsigned char tmp;
409
410 __asm__ __volatile__(
411 " mov.f lp_count, %0 \n"
412 " lpnz 3f \n"
413 " ldb.ab %1, [%3, 1] \n"
414 "1: stb.ab %1, [%2, 1] \n"
415 " sub %0, %0, 1 \n"
416 "3: ;nop \n"
417 " .section .fixup, \"ax\" \n"
418 " .align 4 \n"
419 "4: j 3b \n"
420 " .previous \n"
421 " .section __ex_table, \"a\" \n"
422 " .align 4 \n"
423 " .word 1b, 4b \n"
424 " .previous \n"
425
426 : "+r" (n),
427 /* Note as an '&' earlyclobber operand to make sure the
428 * temporary register inside the loop is not the same as
429 * FROM or TO.
430 */
431 "=&r" (tmp), "+r" (to), "+r" (from)
432 :
433 : "lp_count", "memory");
434
435 return n;
436 }
437
438 if (__builtin_constant_p(orig_n)) {
439 res = orig_n;
440
441 if (orig_n / 16) {
442 orig_n = orig_n % 16;
443
444 __asm__ __volatile__(
445 " lsr lp_count, %7,4 \n"
446 " lp 3f \n"
447 " ld.ab %3, [%2, 4] \n"
448 " ld.ab %4, [%2, 4] \n"
449 " ld.ab %5, [%2, 4] \n"
450 " ld.ab %6, [%2, 4] \n"
451 "1: st.ab %3, [%1, 4] \n"
452 "11: st.ab %4, [%1, 4] \n"
453 "12: st.ab %5, [%1, 4] \n"
454 "13: st.ab %6, [%1, 4] \n"
455 " sub %0, %0, 16 \n"
456 "3:;nop \n"
457 " .section .fixup, \"ax\" \n"
458 " .align 4 \n"
459 "4: j 3b \n"
460 " .previous \n"
461 " .section __ex_table, \"a\" \n"
462 " .align 4 \n"
463 " .word 1b, 4b \n"
464 " .word 11b,4b \n"
465 " .word 12b,4b \n"
466 " .word 13b,4b \n"
467 " .previous \n"
468 : "+r" (res), "+r"(to), "+r"(from),
469 "=r"(tmp1), "=r"(tmp2), "=r"(tmp3), "=r"(tmp4)
470 : "ir"(n)
471 : "lp_count", "memory");
472 }
473 if (orig_n / 8) {
474 orig_n = orig_n % 8;
475
476 __asm__ __volatile__(
477 " ld.ab %3, [%2,4] \n"
478 " ld.ab %4, [%2,4] \n"
479 "14: st.ab %3, [%1,4] \n"
480 "15: st.ab %4, [%1,4] \n"
481 " sub %0, %0, 8 \n"
482 "31:;nop \n"
483 " .section .fixup, \"ax\" \n"
484 " .align 4 \n"
485 "4: j 31b \n"
486 " .previous \n"
487 " .section __ex_table, \"a\" \n"
488 " .align 4 \n"
489 " .word 14b,4b \n"
490 " .word 15b,4b \n"
491 " .previous \n"
492 : "+r" (res), "+r"(to), "+r"(from),
493 "=r"(tmp1), "=r"(tmp2)
494 :
495 : "memory");
496 }
497 if (orig_n / 4) {
498 orig_n = orig_n % 4;
499
500 __asm__ __volatile__(
501 " ld.ab %3, [%2,4] \n"
502 "16: st.ab %3, [%1,4] \n"
503 " sub %0, %0, 4 \n"
504 "32:;nop \n"
505 " .section .fixup, \"ax\" \n"
506 " .align 4 \n"
507 "4: j 32b \n"
508 " .previous \n"
509 " .section __ex_table, \"a\" \n"
510 " .align 4 \n"
511 " .word 16b,4b \n"
512 " .previous \n"
513 : "+r" (res), "+r"(to), "+r"(from), "=r"(tmp1)
514 :
515 : "memory");
516 }
517 if (orig_n / 2) {
518 orig_n = orig_n % 2;
519
520 __asm__ __volatile__(
521 " ldw.ab %3, [%2,2] \n"
522 "17: stw.ab %3, [%1,2] \n"
523 " sub %0, %0, 2 \n"
524 "33:;nop \n"
525 " .section .fixup, \"ax\" \n"
526 " .align 4 \n"
527 "4: j 33b \n"
528 " .previous \n"
529 " .section __ex_table, \"a\" \n"
530 " .align 4 \n"
531 " .word 17b,4b \n"
532 " .previous \n"
533 : "+r" (res), "+r"(to), "+r"(from), "=r"(tmp1)
534 :
535 : "memory");
536 }
537 if (orig_n & 1) {
538 __asm__ __volatile__(
539 " ldb.ab %3, [%2,1] \n"
540 "18: stb.ab %3, [%1,1] \n"
541 " sub %0, %0, 1 \n"
542 "34: ;nop \n"
543 " .section .fixup, \"ax\" \n"
544 " .align 4 \n"
545 "4: j 34b \n"
546 " .previous \n"
547 " .section __ex_table, \"a\" \n"
548 " .align 4 \n"
549 " .word 18b,4b \n"
550 " .previous \n"
551 : "+r" (res), "+r"(to), "+r"(from), "=r"(tmp1)
552 :
553 : "memory");
554 }
555 } else { /* n is NOT constant, so laddered copy of 16x,8,4,2,1 */
556
557 __asm__ __volatile__(
558 " mov %0,%3 \n"
559 " lsr.f lp_count, %3,4 \n" /* 16x bytes */
560 " lpnz 3f \n"
561 " ld.ab %5, [%2, 4] \n"
562 " ld.ab %6, [%2, 4] \n"
563 " ld.ab %7, [%2, 4] \n"
564 " ld.ab %8, [%2, 4] \n"
565 "1: st.ab %5, [%1, 4] \n"
566 "11: st.ab %6, [%1, 4] \n"
567 "12: st.ab %7, [%1, 4] \n"
568 "13: st.ab %8, [%1, 4] \n"
569 " sub %0, %0, 16 \n"
570 "3: and.f %3,%3,0xf \n" /* stragglers */
571 " bz 34f \n"
572 " bbit0 %3,3,31f \n" /* 8 bytes left */
573 " ld.ab %5, [%2,4] \n"
574 " ld.ab %6, [%2,4] \n"
575 "14: st.ab %5, [%1,4] \n"
576 "15: st.ab %6, [%1,4] \n"
577 " sub.f %0, %0, 8 \n"
578 "31: bbit0 %3,2,32f \n" /* 4 bytes left */
579 " ld.ab %5, [%2,4] \n"
580 "16: st.ab %5, [%1,4] \n"
581 " sub.f %0, %0, 4 \n"
582 "32: bbit0 %3,1,33f \n" /* 2 bytes left */
583 " ldw.ab %5, [%2,2] \n"
584 "17: stw.ab %5, [%1,2] \n"
585 " sub.f %0, %0, 2 \n"
586 "33: bbit0 %3,0,34f \n"
587 " ldb.ab %5, [%2,1] \n" /* 1 byte left */
588 "18: stb.ab %5, [%1,1] \n"
589 " sub.f %0, %0, 1 \n"
590 "34: ;nop \n"
591 " .section .fixup, \"ax\" \n"
592 " .align 4 \n"
593 "4: j 34b \n"
594 " .previous \n"
595 " .section __ex_table, \"a\" \n"
596 " .align 4 \n"
597 " .word 1b, 4b \n"
598 " .word 11b,4b \n"
599 " .word 12b,4b \n"
600 " .word 13b,4b \n"
601 " .word 14b,4b \n"
602 " .word 15b,4b \n"
603 " .word 16b,4b \n"
604 " .word 17b,4b \n"
605 " .word 18b,4b \n"
606 " .previous \n"
607 : "=r" (res), "+r"(to), "+r"(from), "+r"(n), "=r"(val),
608 "=r"(tmp1), "=r"(tmp2), "=r"(tmp3), "=r"(tmp4)
609 :
610 : "lp_count", "memory");
611 }
612
613 return res;
614 }
615
__arc_clear_user(void __user * to,unsigned long n)616 static inline unsigned long __arc_clear_user(void __user *to, unsigned long n)
617 {
618 long res = n;
619 unsigned char *d_char = to;
620
621 __asm__ __volatile__(
622 " bbit0 %0, 0, 1f \n"
623 "75: stb.ab %2, [%0,1] \n"
624 " sub %1, %1, 1 \n"
625 "1: bbit0 %0, 1, 2f \n"
626 "76: stw.ab %2, [%0,2] \n"
627 " sub %1, %1, 2 \n"
628 "2: asr.f lp_count, %1, 2 \n"
629 " lpnz 3f \n"
630 "77: st.ab %2, [%0,4] \n"
631 " sub %1, %1, 4 \n"
632 "3: bbit0 %1, 1, 4f \n"
633 "78: stw.ab %2, [%0,2] \n"
634 " sub %1, %1, 2 \n"
635 "4: bbit0 %1, 0, 5f \n"
636 "79: stb.ab %2, [%0,1] \n"
637 " sub %1, %1, 1 \n"
638 "5: \n"
639 " .section .fixup, \"ax\" \n"
640 " .align 4 \n"
641 "3: j 5b \n"
642 " .previous \n"
643 " .section __ex_table, \"a\" \n"
644 " .align 4 \n"
645 " .word 75b, 3b \n"
646 " .word 76b, 3b \n"
647 " .word 77b, 3b \n"
648 " .word 78b, 3b \n"
649 " .word 79b, 3b \n"
650 " .previous \n"
651 : "+r"(d_char), "+r"(res)
652 : "i"(0)
653 : "lp_count", "memory");
654
655 return res;
656 }
657
658 static inline long
__arc_strncpy_from_user(char * dst,const char __user * src,long count)659 __arc_strncpy_from_user(char *dst, const char __user *src, long count)
660 {
661 long res = 0;
662 char val;
663
664 if (count == 0)
665 return 0;
666
667 __asm__ __volatile__(
668 " mov lp_count, %5 \n"
669 " lp 3f \n"
670 "1: ldb.ab %3, [%2, 1] \n"
671 " breq.d %3, 0, 3f \n"
672 " stb.ab %3, [%1, 1] \n"
673 " add %0, %0, 1 # Num of NON NULL bytes copied \n"
674 "3: \n"
675 " .section .fixup, \"ax\" \n"
676 " .align 4 \n"
677 "4: mov %0, %4 # sets @res as -EFAULT \n"
678 " j 3b \n"
679 " .previous \n"
680 " .section __ex_table, \"a\" \n"
681 " .align 4 \n"
682 " .word 1b, 4b \n"
683 " .previous \n"
684 : "+r"(res), "+r"(dst), "+r"(src), "=r"(val)
685 : "g"(-EFAULT), "r"(count)
686 : "lp_count", "memory");
687
688 return res;
689 }
690
__arc_strnlen_user(const char __user * s,long n)691 static inline long __arc_strnlen_user(const char __user *s, long n)
692 {
693 long res, tmp1, cnt;
694 char val;
695
696 __asm__ __volatile__(
697 " mov %2, %1 \n"
698 "1: ldb.ab %3, [%0, 1] \n"
699 " breq.d %3, 0, 2f \n"
700 " sub.f %2, %2, 1 \n"
701 " bnz 1b \n"
702 " sub %2, %2, 1 \n"
703 "2: sub %0, %1, %2 \n"
704 "3: ;nop \n"
705 " .section .fixup, \"ax\" \n"
706 " .align 4 \n"
707 "4: mov %0, 0 \n"
708 " j 3b \n"
709 " .previous \n"
710 " .section __ex_table, \"a\" \n"
711 " .align 4 \n"
712 " .word 1b, 4b \n"
713 " .previous \n"
714 : "=r"(res), "=r"(tmp1), "=r"(cnt), "=r"(val)
715 : "0"(s), "1"(n)
716 : "memory");
717
718 return res;
719 }
720
721 #ifndef CONFIG_CC_OPTIMIZE_FOR_SIZE
722
723 #define INLINE_COPY_TO_USER
724 #define INLINE_COPY_FROM_USER
725
726 #define __clear_user(d, n) __arc_clear_user(d, n)
727 #define __strncpy_from_user(d, s, n) __arc_strncpy_from_user(d, s, n)
728 #define __strnlen_user(s, n) __arc_strnlen_user(s, n)
729 #else
730 extern unsigned long arc_clear_user_noinline(void __user *to,
731 unsigned long n);
732 extern long arc_strncpy_from_user_noinline (char *dst, const char __user *src,
733 long count);
734 extern long arc_strnlen_user_noinline(const char __user *src, long n);
735
736 #define __clear_user(d, n) arc_clear_user_noinline(d, n)
737 #define __strncpy_from_user(d, s, n) arc_strncpy_from_user_noinline(d, s, n)
738 #define __strnlen_user(s, n) arc_strnlen_user_noinline(s, n)
739
740 #endif
741
742 #include <asm/segment.h>
743 #include <asm-generic/uaccess.h>
744
745 #endif
746