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