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 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 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 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 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 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