0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021 #ifndef _ASM_ARC_UACCESS_H
0022 #define _ASM_ARC_UACCESS_H
0023
0024 #include <linux/string.h> /* for generic string functions */
0025
0026
0027
0028 #define __get_user_fn(sz, u, k) \
0029 ({ \
0030 long __ret = 0; \
0031 switch (sz) { \
0032 case 1: __arc_get_user_one(*(k), u, "ldb", __ret); break; \
0033 case 2: __arc_get_user_one(*(k), u, "ldw", __ret); break; \
0034 case 4: __arc_get_user_one(*(k), u, "ld", __ret); break; \
0035 case 8: __arc_get_user_one_64(*(k), u, __ret); break; \
0036 } \
0037 __ret; \
0038 })
0039
0040
0041
0042
0043
0044
0045
0046 #define __arc_get_user_one(dst, src, op, ret) \
0047 __asm__ __volatile__( \
0048 "1: "op" %1,[%2]\n" \
0049 "2: ;nop\n" \
0050 " .section .fixup, \"ax\"\n" \
0051 " .align 4\n" \
0052 "3: # return -EFAULT\n" \
0053 " mov %0, %3\n" \
0054 " # zero out dst ptr\n" \
0055 " mov %1, 0\n" \
0056 " j 2b\n" \
0057 " .previous\n" \
0058 " .section __ex_table, \"a\"\n" \
0059 " .align 4\n" \
0060 " .word 1b,3b\n" \
0061 " .previous\n" \
0062 \
0063 : "+r" (ret), "=r" (dst) \
0064 : "r" (src), "ir" (-EFAULT))
0065
0066 #define __arc_get_user_one_64(dst, src, ret) \
0067 __asm__ __volatile__( \
0068 "1: ld %1,[%2]\n" \
0069 "4: ld %R1,[%2, 4]\n" \
0070 "2: ;nop\n" \
0071 " .section .fixup, \"ax\"\n" \
0072 " .align 4\n" \
0073 "3: # return -EFAULT\n" \
0074 " mov %0, %3\n" \
0075 " # zero out dst ptr\n" \
0076 " mov %1, 0\n" \
0077 " mov %R1, 0\n" \
0078 " j 2b\n" \
0079 " .previous\n" \
0080 " .section __ex_table, \"a\"\n" \
0081 " .align 4\n" \
0082 " .word 1b,3b\n" \
0083 " .word 4b,3b\n" \
0084 " .previous\n" \
0085 \
0086 : "+r" (ret), "=r" (dst) \
0087 : "r" (src), "ir" (-EFAULT))
0088
0089 #define __put_user_fn(sz, u, k) \
0090 ({ \
0091 long __ret = 0; \
0092 switch (sz) { \
0093 case 1: __arc_put_user_one(*(k), u, "stb", __ret); break; \
0094 case 2: __arc_put_user_one(*(k), u, "stw", __ret); break; \
0095 case 4: __arc_put_user_one(*(k), u, "st", __ret); break; \
0096 case 8: __arc_put_user_one_64(*(k), u, __ret); break; \
0097 } \
0098 __ret; \
0099 })
0100
0101 #define __arc_put_user_one(src, dst, op, ret) \
0102 __asm__ __volatile__( \
0103 "1: "op" %1,[%2]\n" \
0104 "2: ;nop\n" \
0105 " .section .fixup, \"ax\"\n" \
0106 " .align 4\n" \
0107 "3: mov %0, %3\n" \
0108 " j 2b\n" \
0109 " .previous\n" \
0110 " .section __ex_table, \"a\"\n" \
0111 " .align 4\n" \
0112 " .word 1b,3b\n" \
0113 " .previous\n" \
0114 \
0115 : "+r" (ret) \
0116 : "r" (src), "r" (dst), "ir" (-EFAULT))
0117
0118 #define __arc_put_user_one_64(src, dst, ret) \
0119 __asm__ __volatile__( \
0120 "1: st %1,[%2]\n" \
0121 "4: st %R1,[%2, 4]\n" \
0122 "2: ;nop\n" \
0123 " .section .fixup, \"ax\"\n" \
0124 " .align 4\n" \
0125 "3: mov %0, %3\n" \
0126 " j 2b\n" \
0127 " .previous\n" \
0128 " .section __ex_table, \"a\"\n" \
0129 " .align 4\n" \
0130 " .word 1b,3b\n" \
0131 " .word 4b,3b\n" \
0132 " .previous\n" \
0133 \
0134 : "+r" (ret) \
0135 : "r" (src), "r" (dst), "ir" (-EFAULT))
0136
0137
0138 static inline unsigned long
0139 raw_copy_from_user(void *to, const void __user *from, unsigned long n)
0140 {
0141 long res = 0;
0142 char val;
0143 unsigned long tmp1, tmp2, tmp3, tmp4;
0144 unsigned long orig_n = n;
0145
0146 if (n == 0)
0147 return 0;
0148
0149
0150 if (((unsigned long)to & 0x3) || ((unsigned long)from & 0x3)) {
0151
0152 unsigned char tmp;
0153
0154 __asm__ __volatile__ (
0155 " mov.f lp_count, %0 \n"
0156 " lpnz 2f \n"
0157 "1: ldb.ab %1, [%3, 1] \n"
0158 " stb.ab %1, [%2, 1] \n"
0159 " sub %0,%0,1 \n"
0160 "2: ;nop \n"
0161 " .section .fixup, \"ax\" \n"
0162 " .align 4 \n"
0163 "3: j 2b \n"
0164 " .previous \n"
0165 " .section __ex_table, \"a\" \n"
0166 " .align 4 \n"
0167 " .word 1b, 3b \n"
0168 " .previous \n"
0169
0170 : "+r" (n),
0171
0172
0173
0174
0175
0176 "=&r" (tmp), "+r" (to), "+r" (from)
0177 :
0178 : "lp_count", "memory");
0179
0180 return n;
0181 }
0182
0183
0184
0185
0186
0187 if (__builtin_constant_p(orig_n)) {
0188 res = orig_n;
0189
0190 if (orig_n / 16) {
0191 orig_n = orig_n % 16;
0192
0193 __asm__ __volatile__(
0194 " lsr lp_count, %7,4 \n"
0195 " lp 3f \n"
0196 "1: ld.ab %3, [%2, 4] \n"
0197 "11: ld.ab %4, [%2, 4] \n"
0198 "12: ld.ab %5, [%2, 4] \n"
0199 "13: ld.ab %6, [%2, 4] \n"
0200 " st.ab %3, [%1, 4] \n"
0201 " st.ab %4, [%1, 4] \n"
0202 " st.ab %5, [%1, 4] \n"
0203 " st.ab %6, [%1, 4] \n"
0204 " sub %0,%0,16 \n"
0205 "3: ;nop \n"
0206 " .section .fixup, \"ax\" \n"
0207 " .align 4 \n"
0208 "4: j 3b \n"
0209 " .previous \n"
0210 " .section __ex_table, \"a\" \n"
0211 " .align 4 \n"
0212 " .word 1b, 4b \n"
0213 " .word 11b,4b \n"
0214 " .word 12b,4b \n"
0215 " .word 13b,4b \n"
0216 " .previous \n"
0217 : "+r" (res), "+r"(to), "+r"(from),
0218 "=r"(tmp1), "=r"(tmp2), "=r"(tmp3), "=r"(tmp4)
0219 : "ir"(n)
0220 : "lp_count", "memory");
0221 }
0222 if (orig_n / 8) {
0223 orig_n = orig_n % 8;
0224
0225 __asm__ __volatile__(
0226 "14: ld.ab %3, [%2,4] \n"
0227 "15: ld.ab %4, [%2,4] \n"
0228 " st.ab %3, [%1,4] \n"
0229 " st.ab %4, [%1,4] \n"
0230 " sub %0,%0,8 \n"
0231 "31: ;nop \n"
0232 " .section .fixup, \"ax\" \n"
0233 " .align 4 \n"
0234 "4: j 31b \n"
0235 " .previous \n"
0236 " .section __ex_table, \"a\" \n"
0237 " .align 4 \n"
0238 " .word 14b,4b \n"
0239 " .word 15b,4b \n"
0240 " .previous \n"
0241 : "+r" (res), "+r"(to), "+r"(from),
0242 "=r"(tmp1), "=r"(tmp2)
0243 :
0244 : "memory");
0245 }
0246 if (orig_n / 4) {
0247 orig_n = orig_n % 4;
0248
0249 __asm__ __volatile__(
0250 "16: ld.ab %3, [%2,4] \n"
0251 " st.ab %3, [%1,4] \n"
0252 " sub %0,%0,4 \n"
0253 "32: ;nop \n"
0254 " .section .fixup, \"ax\" \n"
0255 " .align 4 \n"
0256 "4: j 32b \n"
0257 " .previous \n"
0258 " .section __ex_table, \"a\" \n"
0259 " .align 4 \n"
0260 " .word 16b,4b \n"
0261 " .previous \n"
0262 : "+r" (res), "+r"(to), "+r"(from), "=r"(tmp1)
0263 :
0264 : "memory");
0265 }
0266 if (orig_n / 2) {
0267 orig_n = orig_n % 2;
0268
0269 __asm__ __volatile__(
0270 "17: ldw.ab %3, [%2,2] \n"
0271 " stw.ab %3, [%1,2] \n"
0272 " sub %0,%0,2 \n"
0273 "33: ;nop \n"
0274 " .section .fixup, \"ax\" \n"
0275 " .align 4 \n"
0276 "4: j 33b \n"
0277 " .previous \n"
0278 " .section __ex_table, \"a\" \n"
0279 " .align 4 \n"
0280 " .word 17b,4b \n"
0281 " .previous \n"
0282 : "+r" (res), "+r"(to), "+r"(from), "=r"(tmp1)
0283 :
0284 : "memory");
0285 }
0286 if (orig_n & 1) {
0287 __asm__ __volatile__(
0288 "18: ldb.ab %3, [%2,2] \n"
0289 " stb.ab %3, [%1,2] \n"
0290 " sub %0,%0,1 \n"
0291 "34: ; nop \n"
0292 " .section .fixup, \"ax\" \n"
0293 " .align 4 \n"
0294 "4: j 34b \n"
0295 " .previous \n"
0296 " .section __ex_table, \"a\" \n"
0297 " .align 4 \n"
0298 " .word 18b,4b \n"
0299 " .previous \n"
0300 : "+r" (res), "+r"(to), "+r"(from), "=r"(tmp1)
0301 :
0302 : "memory");
0303 }
0304 } else {
0305
0306 __asm__ __volatile__(
0307 " mov %0,%3 \n"
0308 " lsr.f lp_count, %3,4 \n"
0309 " lpnz 3f \n"
0310 "1: ld.ab %5, [%2, 4] \n"
0311 "11: ld.ab %6, [%2, 4] \n"
0312 "12: ld.ab %7, [%2, 4] \n"
0313 "13: ld.ab %8, [%2, 4] \n"
0314 " st.ab %5, [%1, 4] \n"
0315 " st.ab %6, [%1, 4] \n"
0316 " st.ab %7, [%1, 4] \n"
0317 " st.ab %8, [%1, 4] \n"
0318 " sub %0,%0,16 \n"
0319 "3: and.f %3,%3,0xf \n"
0320 " bz 34f \n"
0321 " bbit0 %3,3,31f \n"
0322 "14: ld.ab %5, [%2,4] \n"
0323 "15: ld.ab %6, [%2,4] \n"
0324 " st.ab %5, [%1,4] \n"
0325 " st.ab %6, [%1,4] \n"
0326 " sub.f %0,%0,8 \n"
0327 "31: bbit0 %3,2,32f \n"
0328 "16: ld.ab %5, [%2,4] \n"
0329 " st.ab %5, [%1,4] \n"
0330 " sub.f %0,%0,4 \n"
0331 "32: bbit0 %3,1,33f \n"
0332 "17: ldw.ab %5, [%2,2] \n"
0333 " stw.ab %5, [%1,2] \n"
0334 " sub.f %0,%0,2 \n"
0335 "33: bbit0 %3,0,34f \n"
0336 "18: ldb.ab %5, [%2,1] \n"
0337 " stb.ab %5, [%1,1] \n"
0338 " sub.f %0,%0,1 \n"
0339 "34: ;nop \n"
0340 " .section .fixup, \"ax\" \n"
0341 " .align 4 \n"
0342 "4: j 34b \n"
0343 " .previous \n"
0344 " .section __ex_table, \"a\" \n"
0345 " .align 4 \n"
0346 " .word 1b, 4b \n"
0347 " .word 11b,4b \n"
0348 " .word 12b,4b \n"
0349 " .word 13b,4b \n"
0350 " .word 14b,4b \n"
0351 " .word 15b,4b \n"
0352 " .word 16b,4b \n"
0353 " .word 17b,4b \n"
0354 " .word 18b,4b \n"
0355 " .previous \n"
0356 : "=r" (res), "+r"(to), "+r"(from), "+r"(n), "=r"(val),
0357 "=r"(tmp1), "=r"(tmp2), "=r"(tmp3), "=r"(tmp4)
0358 :
0359 : "lp_count", "memory");
0360 }
0361
0362 return res;
0363 }
0364
0365 static inline unsigned long
0366 raw_copy_to_user(void __user *to, const void *from, unsigned long n)
0367 {
0368 long res = 0;
0369 char val;
0370 unsigned long tmp1, tmp2, tmp3, tmp4;
0371 unsigned long orig_n = n;
0372
0373 if (n == 0)
0374 return 0;
0375
0376
0377 if (((unsigned long)to & 0x3) || ((unsigned long)from & 0x3)) {
0378
0379 unsigned char tmp;
0380
0381 __asm__ __volatile__(
0382 " mov.f lp_count, %0 \n"
0383 " lpnz 3f \n"
0384 " ldb.ab %1, [%3, 1] \n"
0385 "1: stb.ab %1, [%2, 1] \n"
0386 " sub %0, %0, 1 \n"
0387 "3: ;nop \n"
0388 " .section .fixup, \"ax\" \n"
0389 " .align 4 \n"
0390 "4: j 3b \n"
0391 " .previous \n"
0392 " .section __ex_table, \"a\" \n"
0393 " .align 4 \n"
0394 " .word 1b, 4b \n"
0395 " .previous \n"
0396
0397 : "+r" (n),
0398
0399
0400
0401
0402 "=&r" (tmp), "+r" (to), "+r" (from)
0403 :
0404 : "lp_count", "memory");
0405
0406 return n;
0407 }
0408
0409 if (__builtin_constant_p(orig_n)) {
0410 res = orig_n;
0411
0412 if (orig_n / 16) {
0413 orig_n = orig_n % 16;
0414
0415 __asm__ __volatile__(
0416 " lsr lp_count, %7,4 \n"
0417 " lp 3f \n"
0418 " ld.ab %3, [%2, 4] \n"
0419 " ld.ab %4, [%2, 4] \n"
0420 " ld.ab %5, [%2, 4] \n"
0421 " ld.ab %6, [%2, 4] \n"
0422 "1: st.ab %3, [%1, 4] \n"
0423 "11: st.ab %4, [%1, 4] \n"
0424 "12: st.ab %5, [%1, 4] \n"
0425 "13: st.ab %6, [%1, 4] \n"
0426 " sub %0, %0, 16 \n"
0427 "3:;nop \n"
0428 " .section .fixup, \"ax\" \n"
0429 " .align 4 \n"
0430 "4: j 3b \n"
0431 " .previous \n"
0432 " .section __ex_table, \"a\" \n"
0433 " .align 4 \n"
0434 " .word 1b, 4b \n"
0435 " .word 11b,4b \n"
0436 " .word 12b,4b \n"
0437 " .word 13b,4b \n"
0438 " .previous \n"
0439 : "+r" (res), "+r"(to), "+r"(from),
0440 "=r"(tmp1), "=r"(tmp2), "=r"(tmp3), "=r"(tmp4)
0441 : "ir"(n)
0442 : "lp_count", "memory");
0443 }
0444 if (orig_n / 8) {
0445 orig_n = orig_n % 8;
0446
0447 __asm__ __volatile__(
0448 " ld.ab %3, [%2,4] \n"
0449 " ld.ab %4, [%2,4] \n"
0450 "14: st.ab %3, [%1,4] \n"
0451 "15: st.ab %4, [%1,4] \n"
0452 " sub %0, %0, 8 \n"
0453 "31:;nop \n"
0454 " .section .fixup, \"ax\" \n"
0455 " .align 4 \n"
0456 "4: j 31b \n"
0457 " .previous \n"
0458 " .section __ex_table, \"a\" \n"
0459 " .align 4 \n"
0460 " .word 14b,4b \n"
0461 " .word 15b,4b \n"
0462 " .previous \n"
0463 : "+r" (res), "+r"(to), "+r"(from),
0464 "=r"(tmp1), "=r"(tmp2)
0465 :
0466 : "memory");
0467 }
0468 if (orig_n / 4) {
0469 orig_n = orig_n % 4;
0470
0471 __asm__ __volatile__(
0472 " ld.ab %3, [%2,4] \n"
0473 "16: st.ab %3, [%1,4] \n"
0474 " sub %0, %0, 4 \n"
0475 "32:;nop \n"
0476 " .section .fixup, \"ax\" \n"
0477 " .align 4 \n"
0478 "4: j 32b \n"
0479 " .previous \n"
0480 " .section __ex_table, \"a\" \n"
0481 " .align 4 \n"
0482 " .word 16b,4b \n"
0483 " .previous \n"
0484 : "+r" (res), "+r"(to), "+r"(from), "=r"(tmp1)
0485 :
0486 : "memory");
0487 }
0488 if (orig_n / 2) {
0489 orig_n = orig_n % 2;
0490
0491 __asm__ __volatile__(
0492 " ldw.ab %3, [%2,2] \n"
0493 "17: stw.ab %3, [%1,2] \n"
0494 " sub %0, %0, 2 \n"
0495 "33:;nop \n"
0496 " .section .fixup, \"ax\" \n"
0497 " .align 4 \n"
0498 "4: j 33b \n"
0499 " .previous \n"
0500 " .section __ex_table, \"a\" \n"
0501 " .align 4 \n"
0502 " .word 17b,4b \n"
0503 " .previous \n"
0504 : "+r" (res), "+r"(to), "+r"(from), "=r"(tmp1)
0505 :
0506 : "memory");
0507 }
0508 if (orig_n & 1) {
0509 __asm__ __volatile__(
0510 " ldb.ab %3, [%2,1] \n"
0511 "18: stb.ab %3, [%1,1] \n"
0512 " sub %0, %0, 1 \n"
0513 "34: ;nop \n"
0514 " .section .fixup, \"ax\" \n"
0515 " .align 4 \n"
0516 "4: j 34b \n"
0517 " .previous \n"
0518 " .section __ex_table, \"a\" \n"
0519 " .align 4 \n"
0520 " .word 18b,4b \n"
0521 " .previous \n"
0522 : "+r" (res), "+r"(to), "+r"(from), "=r"(tmp1)
0523 :
0524 : "memory");
0525 }
0526 } else {
0527
0528 __asm__ __volatile__(
0529 " mov %0,%3 \n"
0530 " lsr.f lp_count, %3,4 \n"
0531 " lpnz 3f \n"
0532 " ld.ab %5, [%2, 4] \n"
0533 " ld.ab %6, [%2, 4] \n"
0534 " ld.ab %7, [%2, 4] \n"
0535 " ld.ab %8, [%2, 4] \n"
0536 "1: st.ab %5, [%1, 4] \n"
0537 "11: st.ab %6, [%1, 4] \n"
0538 "12: st.ab %7, [%1, 4] \n"
0539 "13: st.ab %8, [%1, 4] \n"
0540 " sub %0, %0, 16 \n"
0541 "3: and.f %3,%3,0xf \n"
0542 " bz 34f \n"
0543 " bbit0 %3,3,31f \n"
0544 " ld.ab %5, [%2,4] \n"
0545 " ld.ab %6, [%2,4] \n"
0546 "14: st.ab %5, [%1,4] \n"
0547 "15: st.ab %6, [%1,4] \n"
0548 " sub.f %0, %0, 8 \n"
0549 "31: bbit0 %3,2,32f \n"
0550 " ld.ab %5, [%2,4] \n"
0551 "16: st.ab %5, [%1,4] \n"
0552 " sub.f %0, %0, 4 \n"
0553 "32: bbit0 %3,1,33f \n"
0554 " ldw.ab %5, [%2,2] \n"
0555 "17: stw.ab %5, [%1,2] \n"
0556 " sub.f %0, %0, 2 \n"
0557 "33: bbit0 %3,0,34f \n"
0558 " ldb.ab %5, [%2,1] \n"
0559 "18: stb.ab %5, [%1,1] \n"
0560 " sub.f %0, %0, 1 \n"
0561 "34: ;nop \n"
0562 " .section .fixup, \"ax\" \n"
0563 " .align 4 \n"
0564 "4: j 34b \n"
0565 " .previous \n"
0566 " .section __ex_table, \"a\" \n"
0567 " .align 4 \n"
0568 " .word 1b, 4b \n"
0569 " .word 11b,4b \n"
0570 " .word 12b,4b \n"
0571 " .word 13b,4b \n"
0572 " .word 14b,4b \n"
0573 " .word 15b,4b \n"
0574 " .word 16b,4b \n"
0575 " .word 17b,4b \n"
0576 " .word 18b,4b \n"
0577 " .previous \n"
0578 : "=r" (res), "+r"(to), "+r"(from), "+r"(n), "=r"(val),
0579 "=r"(tmp1), "=r"(tmp2), "=r"(tmp3), "=r"(tmp4)
0580 :
0581 : "lp_count", "memory");
0582 }
0583
0584 return res;
0585 }
0586
0587 static inline unsigned long __arc_clear_user(void __user *to, unsigned long n)
0588 {
0589 long res = n;
0590 unsigned char *d_char = to;
0591
0592 __asm__ __volatile__(
0593 " bbit0 %0, 0, 1f \n"
0594 "75: stb.ab %2, [%0,1] \n"
0595 " sub %1, %1, 1 \n"
0596 "1: bbit0 %0, 1, 2f \n"
0597 "76: stw.ab %2, [%0,2] \n"
0598 " sub %1, %1, 2 \n"
0599 "2: asr.f lp_count, %1, 2 \n"
0600 " lpnz 3f \n"
0601 "77: st.ab %2, [%0,4] \n"
0602 " sub %1, %1, 4 \n"
0603 "3: bbit0 %1, 1, 4f \n"
0604 "78: stw.ab %2, [%0,2] \n"
0605 " sub %1, %1, 2 \n"
0606 "4: bbit0 %1, 0, 5f \n"
0607 "79: stb.ab %2, [%0,1] \n"
0608 " sub %1, %1, 1 \n"
0609 "5: \n"
0610 " .section .fixup, \"ax\" \n"
0611 " .align 4 \n"
0612 "3: j 5b \n"
0613 " .previous \n"
0614 " .section __ex_table, \"a\" \n"
0615 " .align 4 \n"
0616 " .word 75b, 3b \n"
0617 " .word 76b, 3b \n"
0618 " .word 77b, 3b \n"
0619 " .word 78b, 3b \n"
0620 " .word 79b, 3b \n"
0621 " .previous \n"
0622 : "+r"(d_char), "+r"(res)
0623 : "i"(0)
0624 : "lp_count", "memory");
0625
0626 return res;
0627 }
0628
0629 #ifndef CONFIG_CC_OPTIMIZE_FOR_SIZE
0630
0631 #define INLINE_COPY_TO_USER
0632 #define INLINE_COPY_FROM_USER
0633
0634 #define __clear_user(d, n) __arc_clear_user(d, n)
0635 #else
0636 extern unsigned long arc_clear_user_noinline(void __user *to,
0637 unsigned long n);
0638 #define __clear_user(d, n) arc_clear_user_noinline(d, n)
0639 #endif
0640
0641 #include <asm-generic/uaccess.h>
0642
0643 #endif