1/* 2 * Authors: Bjorn Wesen (bjornw@axis.com) 3 * Hans-Peter Nilsson (hp@axis.com) 4 * 5 */ 6#ifndef _CRIS_ARCH_UACCESS_H 7#define _CRIS_ARCH_UACCESS_H 8 9/* 10 * We don't tell gcc that we are accessing memory, but this is OK 11 * because we do not write to any memory gcc knows about, so there 12 * are no aliasing issues. 13 * 14 * Note that PC at a fault is the address *after* the faulting 15 * instruction. 16 */ 17#define __put_user_asm(x, addr, err, op) \ 18 __asm__ __volatile__( \ 19 " "op" %1,[%2]\n" \ 20 "2:\n" \ 21 " .section .fixup,\"ax\"\n" \ 22 "3: move.d %3,%0\n" \ 23 " jump 2b\n" \ 24 " .previous\n" \ 25 " .section __ex_table,\"a\"\n" \ 26 " .dword 2b,3b\n" \ 27 " .previous\n" \ 28 : "=r" (err) \ 29 : "r" (x), "r" (addr), "g" (-EFAULT), "0" (err)) 30 31#define __put_user_asm_64(x, addr, err) \ 32 __asm__ __volatile__( \ 33 " move.d %M1,[%2]\n" \ 34 "2: move.d %H1,[%2+4]\n" \ 35 "4:\n" \ 36 " .section .fixup,\"ax\"\n" \ 37 "3: move.d %3,%0\n" \ 38 " jump 4b\n" \ 39 " .previous\n" \ 40 " .section __ex_table,\"a\"\n" \ 41 " .dword 2b,3b\n" \ 42 " .dword 4b,3b\n" \ 43 " .previous\n" \ 44 : "=r" (err) \ 45 : "r" (x), "r" (addr), "g" (-EFAULT), "0" (err)) 46 47/* See comment before __put_user_asm. */ 48 49#define __get_user_asm(x, addr, err, op) \ 50 __asm__ __volatile__( \ 51 " "op" [%2],%1\n" \ 52 "2:\n" \ 53 " .section .fixup,\"ax\"\n" \ 54 "3: move.d %3,%0\n" \ 55 " moveq 0,%1\n" \ 56 " jump 2b\n" \ 57 " .previous\n" \ 58 " .section __ex_table,\"a\"\n" \ 59 " .dword 2b,3b\n" \ 60 " .previous\n" \ 61 : "=r" (err), "=r" (x) \ 62 : "r" (addr), "g" (-EFAULT), "0" (err)) 63 64#define __get_user_asm_64(x, addr, err) \ 65 __asm__ __volatile__( \ 66 " move.d [%2],%M1\n" \ 67 "2: move.d [%2+4],%H1\n" \ 68 "4:\n" \ 69 " .section .fixup,\"ax\"\n" \ 70 "3: move.d %3,%0\n" \ 71 " moveq 0,%1\n" \ 72 " jump 4b\n" \ 73 " .previous\n" \ 74 " .section __ex_table,\"a\"\n" \ 75 " .dword 2b,3b\n" \ 76 " .dword 4b,3b\n" \ 77 " .previous\n" \ 78 : "=r" (err), "=r" (x) \ 79 : "r" (addr), "g" (-EFAULT), "0" (err)) 80 81/* 82 * Copy a null terminated string from userspace. 83 * 84 * Must return: 85 * -EFAULT for an exception 86 * count if we hit the buffer limit 87 * bytes copied if we hit a null byte 88 * (without the null byte) 89 */ 90static inline long 91__do_strncpy_from_user(char *dst, const char *src, long count) 92{ 93 long res; 94 95 if (count == 0) 96 return 0; 97 98 /* 99 * Currently, in 2.4.0-test9, most ports use a simple byte-copy loop. 100 * So do we. 101 * 102 * This code is deduced from: 103 * 104 * char tmp2; 105 * long tmp1, tmp3 106 * tmp1 = count; 107 * while ((*dst++ = (tmp2 = *src++)) != 0 108 * && --tmp1) 109 * ; 110 * 111 * res = count - tmp1; 112 * 113 * with tweaks. 114 */ 115 116 __asm__ __volatile__ ( 117 " move.d %3,%0\n" 118 " move.b [%2+],$r9\n" 119 "1: beq 2f\n" 120 " move.b $r9,[%1+]\n" 121 122 " subq 1,%0\n" 123 " bne 1b\n" 124 " move.b [%2+],$r9\n" 125 126 "2: sub.d %3,%0\n" 127 " neg.d %0,%0\n" 128 "3:\n" 129 " .section .fixup,\"ax\"\n" 130 "4: move.d %7,%0\n" 131 " jump 3b\n" 132 133 /* There's one address for a fault at the first move, and 134 two possible PC values for a fault at the second move, 135 being a delay-slot filler. However, the branch-target 136 for the second move is the same as the first address. 137 Just so you don't get confused... */ 138 " .previous\n" 139 " .section __ex_table,\"a\"\n" 140 " .dword 1b,4b\n" 141 " .dword 2b,4b\n" 142 " .previous" 143 : "=r" (res), "=r" (dst), "=r" (src), "=r" (count) 144 : "3" (count), "1" (dst), "2" (src), "g" (-EFAULT) 145 : "r9"); 146 147 return res; 148} 149 150/* A few copy asms to build up the more complex ones from. 151 152 Note again, a post-increment is performed regardless of whether a bus 153 fault occurred in that instruction, and PC for a faulted insn is the 154 address *after* the insn. */ 155 156#define __asm_copy_user_cont(to, from, ret, COPY, FIXUP, TENTRY) \ 157 __asm__ __volatile__ ( \ 158 COPY \ 159 "1:\n" \ 160 " .section .fixup,\"ax\"\n" \ 161 FIXUP \ 162 " jump 1b\n" \ 163 " .previous\n" \ 164 " .section __ex_table,\"a\"\n" \ 165 TENTRY \ 166 " .previous\n" \ 167 : "=r" (to), "=r" (from), "=r" (ret) \ 168 : "0" (to), "1" (from), "2" (ret) \ 169 : "r9", "memory") 170 171#define __asm_copy_from_user_1(to, from, ret) \ 172 __asm_copy_user_cont(to, from, ret, \ 173 " move.b [%1+],$r9\n" \ 174 "2: move.b $r9,[%0+]\n", \ 175 "3: addq 1,%2\n" \ 176 " clear.b [%0+]\n", \ 177 " .dword 2b,3b\n") 178 179#define __asm_copy_from_user_2x_cont(to, from, ret, COPY, FIXUP, TENTRY) \ 180 __asm_copy_user_cont(to, from, ret, \ 181 " move.w [%1+],$r9\n" \ 182 "2: move.w $r9,[%0+]\n" COPY, \ 183 "3: addq 2,%2\n" \ 184 " clear.w [%0+]\n" FIXUP, \ 185 " .dword 2b,3b\n" TENTRY) 186 187#define __asm_copy_from_user_2(to, from, ret) \ 188 __asm_copy_from_user_2x_cont(to, from, ret, "", "", "") 189 190#define __asm_copy_from_user_3(to, from, ret) \ 191 __asm_copy_from_user_2x_cont(to, from, ret, \ 192 " move.b [%1+],$r9\n" \ 193 "4: move.b $r9,[%0+]\n", \ 194 "5: addq 1,%2\n" \ 195 " clear.b [%0+]\n", \ 196 " .dword 4b,5b\n") 197 198#define __asm_copy_from_user_4x_cont(to, from, ret, COPY, FIXUP, TENTRY) \ 199 __asm_copy_user_cont(to, from, ret, \ 200 " move.d [%1+],$r9\n" \ 201 "2: move.d $r9,[%0+]\n" COPY, \ 202 "3: addq 4,%2\n" \ 203 " clear.d [%0+]\n" FIXUP, \ 204 " .dword 2b,3b\n" TENTRY) 205 206#define __asm_copy_from_user_4(to, from, ret) \ 207 __asm_copy_from_user_4x_cont(to, from, ret, "", "", "") 208 209#define __asm_copy_from_user_5(to, from, ret) \ 210 __asm_copy_from_user_4x_cont(to, from, ret, \ 211 " move.b [%1+],$r9\n" \ 212 "4: move.b $r9,[%0+]\n", \ 213 "5: addq 1,%2\n" \ 214 " clear.b [%0+]\n", \ 215 " .dword 4b,5b\n") 216 217#define __asm_copy_from_user_6x_cont(to, from, ret, COPY, FIXUP, TENTRY) \ 218 __asm_copy_from_user_4x_cont(to, from, ret, \ 219 " move.w [%1+],$r9\n" \ 220 "4: move.w $r9,[%0+]\n" COPY, \ 221 "5: addq 2,%2\n" \ 222 " clear.w [%0+]\n" FIXUP, \ 223 " .dword 4b,5b\n" TENTRY) 224 225#define __asm_copy_from_user_6(to, from, ret) \ 226 __asm_copy_from_user_6x_cont(to, from, ret, "", "", "") 227 228#define __asm_copy_from_user_7(to, from, ret) \ 229 __asm_copy_from_user_6x_cont(to, from, ret, \ 230 " move.b [%1+],$r9\n" \ 231 "6: move.b $r9,[%0+]\n", \ 232 "7: addq 1,%2\n" \ 233 " clear.b [%0+]\n", \ 234 " .dword 6b,7b\n") 235 236#define __asm_copy_from_user_8x_cont(to, from, ret, COPY, FIXUP, TENTRY) \ 237 __asm_copy_from_user_4x_cont(to, from, ret, \ 238 " move.d [%1+],$r9\n" \ 239 "4: move.d $r9,[%0+]\n" COPY, \ 240 "5: addq 4,%2\n" \ 241 " clear.d [%0+]\n" FIXUP, \ 242 " .dword 4b,5b\n" TENTRY) 243 244#define __asm_copy_from_user_8(to, from, ret) \ 245 __asm_copy_from_user_8x_cont(to, from, ret, "", "", "") 246 247#define __asm_copy_from_user_9(to, from, ret) \ 248 __asm_copy_from_user_8x_cont(to, from, ret, \ 249 " move.b [%1+],$r9\n" \ 250 "6: move.b $r9,[%0+]\n", \ 251 "7: addq 1,%2\n" \ 252 " clear.b [%0+]\n", \ 253 " .dword 6b,7b\n") 254 255#define __asm_copy_from_user_10x_cont(to, from, ret, COPY, FIXUP, TENTRY) \ 256 __asm_copy_from_user_8x_cont(to, from, ret, \ 257 " move.w [%1+],$r9\n" \ 258 "6: move.w $r9,[%0+]\n" COPY, \ 259 "7: addq 2,%2\n" \ 260 " clear.w [%0+]\n" FIXUP, \ 261 " .dword 6b,7b\n" TENTRY) 262 263#define __asm_copy_from_user_10(to, from, ret) \ 264 __asm_copy_from_user_10x_cont(to, from, ret, "", "", "") 265 266#define __asm_copy_from_user_11(to, from, ret) \ 267 __asm_copy_from_user_10x_cont(to, from, ret, \ 268 " move.b [%1+],$r9\n" \ 269 "8: move.b $r9,[%0+]\n", \ 270 "9: addq 1,%2\n" \ 271 " clear.b [%0+]\n", \ 272 " .dword 8b,9b\n") 273 274#define __asm_copy_from_user_12x_cont(to, from, ret, COPY, FIXUP, TENTRY) \ 275 __asm_copy_from_user_8x_cont(to, from, ret, \ 276 " move.d [%1+],$r9\n" \ 277 "6: move.d $r9,[%0+]\n" COPY, \ 278 "7: addq 4,%2\n" \ 279 " clear.d [%0+]\n" FIXUP, \ 280 " .dword 6b,7b\n" TENTRY) 281 282#define __asm_copy_from_user_12(to, from, ret) \ 283 __asm_copy_from_user_12x_cont(to, from, ret, "", "", "") 284 285#define __asm_copy_from_user_13(to, from, ret) \ 286 __asm_copy_from_user_12x_cont(to, from, ret, \ 287 " move.b [%1+],$r9\n" \ 288 "8: move.b $r9,[%0+]\n", \ 289 "9: addq 1,%2\n" \ 290 " clear.b [%0+]\n", \ 291 " .dword 8b,9b\n") 292 293#define __asm_copy_from_user_14x_cont(to, from, ret, COPY, FIXUP, TENTRY) \ 294 __asm_copy_from_user_12x_cont(to, from, ret, \ 295 " move.w [%1+],$r9\n" \ 296 "8: move.w $r9,[%0+]\n" COPY, \ 297 "9: addq 2,%2\n" \ 298 " clear.w [%0+]\n" FIXUP, \ 299 " .dword 8b,9b\n" TENTRY) 300 301#define __asm_copy_from_user_14(to, from, ret) \ 302 __asm_copy_from_user_14x_cont(to, from, ret, "", "", "") 303 304#define __asm_copy_from_user_15(to, from, ret) \ 305 __asm_copy_from_user_14x_cont(to, from, ret, \ 306 " move.b [%1+],$r9\n" \ 307 "10: move.b $r9,[%0+]\n", \ 308 "11: addq 1,%2\n" \ 309 " clear.b [%0+]\n", \ 310 " .dword 10b,11b\n") 311 312#define __asm_copy_from_user_16x_cont(to, from, ret, COPY, FIXUP, TENTRY) \ 313 __asm_copy_from_user_12x_cont(to, from, ret, \ 314 " move.d [%1+],$r9\n" \ 315 "8: move.d $r9,[%0+]\n" COPY, \ 316 "9: addq 4,%2\n" \ 317 " clear.d [%0+]\n" FIXUP, \ 318 " .dword 8b,9b\n" TENTRY) 319 320#define __asm_copy_from_user_16(to, from, ret) \ 321 __asm_copy_from_user_16x_cont(to, from, ret, "", "", "") 322 323#define __asm_copy_from_user_20x_cont(to, from, ret, COPY, FIXUP, TENTRY) \ 324 __asm_copy_from_user_16x_cont(to, from, ret, \ 325 " move.d [%1+],$r9\n" \ 326 "10: move.d $r9,[%0+]\n" COPY, \ 327 "11: addq 4,%2\n" \ 328 " clear.d [%0+]\n" FIXUP, \ 329 " .dword 10b,11b\n" TENTRY) 330 331#define __asm_copy_from_user_20(to, from, ret) \ 332 __asm_copy_from_user_20x_cont(to, from, ret, "", "", "") 333 334#define __asm_copy_from_user_24x_cont(to, from, ret, COPY, FIXUP, TENTRY) \ 335 __asm_copy_from_user_20x_cont(to, from, ret, \ 336 " move.d [%1+],$r9\n" \ 337 "12: move.d $r9,[%0+]\n" COPY, \ 338 "13: addq 4,%2\n" \ 339 " clear.d [%0+]\n" FIXUP, \ 340 " .dword 12b,13b\n" TENTRY) 341 342#define __asm_copy_from_user_24(to, from, ret) \ 343 __asm_copy_from_user_24x_cont(to, from, ret, "", "", "") 344 345/* And now, the to-user ones. */ 346 347#define __asm_copy_to_user_1(to, from, ret) \ 348 __asm_copy_user_cont(to, from, ret, \ 349 " move.b [%1+],$r9\n" \ 350 " move.b $r9,[%0+]\n2:\n", \ 351 "3: addq 1,%2\n", \ 352 " .dword 2b,3b\n") 353 354#define __asm_copy_to_user_2x_cont(to, from, ret, COPY, FIXUP, TENTRY) \ 355 __asm_copy_user_cont(to, from, ret, \ 356 " move.w [%1+],$r9\n" \ 357 " move.w $r9,[%0+]\n2:\n" COPY, \ 358 "3: addq 2,%2\n" FIXUP, \ 359 " .dword 2b,3b\n" TENTRY) 360 361#define __asm_copy_to_user_2(to, from, ret) \ 362 __asm_copy_to_user_2x_cont(to, from, ret, "", "", "") 363 364#define __asm_copy_to_user_3(to, from, ret) \ 365 __asm_copy_to_user_2x_cont(to, from, ret, \ 366 " move.b [%1+],$r9\n" \ 367 " move.b $r9,[%0+]\n4:\n", \ 368 "5: addq 1,%2\n", \ 369 " .dword 4b,5b\n") 370 371#define __asm_copy_to_user_4x_cont(to, from, ret, COPY, FIXUP, TENTRY) \ 372 __asm_copy_user_cont(to, from, ret, \ 373 " move.d [%1+],$r9\n" \ 374 " move.d $r9,[%0+]\n2:\n" COPY, \ 375 "3: addq 4,%2\n" FIXUP, \ 376 " .dword 2b,3b\n" TENTRY) 377 378#define __asm_copy_to_user_4(to, from, ret) \ 379 __asm_copy_to_user_4x_cont(to, from, ret, "", "", "") 380 381#define __asm_copy_to_user_5(to, from, ret) \ 382 __asm_copy_to_user_4x_cont(to, from, ret, \ 383 " move.b [%1+],$r9\n" \ 384 " move.b $r9,[%0+]\n4:\n", \ 385 "5: addq 1,%2\n", \ 386 " .dword 4b,5b\n") 387 388#define __asm_copy_to_user_6x_cont(to, from, ret, COPY, FIXUP, TENTRY) \ 389 __asm_copy_to_user_4x_cont(to, from, ret, \ 390 " move.w [%1+],$r9\n" \ 391 " move.w $r9,[%0+]\n4:\n" COPY, \ 392 "5: addq 2,%2\n" FIXUP, \ 393 " .dword 4b,5b\n" TENTRY) 394 395#define __asm_copy_to_user_6(to, from, ret) \ 396 __asm_copy_to_user_6x_cont(to, from, ret, "", "", "") 397 398#define __asm_copy_to_user_7(to, from, ret) \ 399 __asm_copy_to_user_6x_cont(to, from, ret, \ 400 " move.b [%1+],$r9\n" \ 401 " move.b $r9,[%0+]\n6:\n", \ 402 "7: addq 1,%2\n", \ 403 " .dword 6b,7b\n") 404 405#define __asm_copy_to_user_8x_cont(to, from, ret, COPY, FIXUP, TENTRY) \ 406 __asm_copy_to_user_4x_cont(to, from, ret, \ 407 " move.d [%1+],$r9\n" \ 408 " move.d $r9,[%0+]\n4:\n" COPY, \ 409 "5: addq 4,%2\n" FIXUP, \ 410 " .dword 4b,5b\n" TENTRY) 411 412#define __asm_copy_to_user_8(to, from, ret) \ 413 __asm_copy_to_user_8x_cont(to, from, ret, "", "", "") 414 415#define __asm_copy_to_user_9(to, from, ret) \ 416 __asm_copy_to_user_8x_cont(to, from, ret, \ 417 " move.b [%1+],$r9\n" \ 418 " move.b $r9,[%0+]\n6:\n", \ 419 "7: addq 1,%2\n", \ 420 " .dword 6b,7b\n") 421 422#define __asm_copy_to_user_10x_cont(to, from, ret, COPY, FIXUP, TENTRY) \ 423 __asm_copy_to_user_8x_cont(to, from, ret, \ 424 " move.w [%1+],$r9\n" \ 425 " move.w $r9,[%0+]\n6:\n" COPY, \ 426 "7: addq 2,%2\n" FIXUP, \ 427 " .dword 6b,7b\n" TENTRY) 428 429#define __asm_copy_to_user_10(to, from, ret) \ 430 __asm_copy_to_user_10x_cont(to, from, ret, "", "", "") 431 432#define __asm_copy_to_user_11(to, from, ret) \ 433 __asm_copy_to_user_10x_cont(to, from, ret, \ 434 " move.b [%1+],$r9\n" \ 435 " move.b $r9,[%0+]\n8:\n", \ 436 "9: addq 1,%2\n", \ 437 " .dword 8b,9b\n") 438 439#define __asm_copy_to_user_12x_cont(to, from, ret, COPY, FIXUP, TENTRY) \ 440 __asm_copy_to_user_8x_cont(to, from, ret, \ 441 " move.d [%1+],$r9\n" \ 442 " move.d $r9,[%0+]\n6:\n" COPY, \ 443 "7: addq 4,%2\n" FIXUP, \ 444 " .dword 6b,7b\n" TENTRY) 445 446#define __asm_copy_to_user_12(to, from, ret) \ 447 __asm_copy_to_user_12x_cont(to, from, ret, "", "", "") 448 449#define __asm_copy_to_user_13(to, from, ret) \ 450 __asm_copy_to_user_12x_cont(to, from, ret, \ 451 " move.b [%1+],$r9\n" \ 452 " move.b $r9,[%0+]\n8:\n", \ 453 "9: addq 1,%2\n", \ 454 " .dword 8b,9b\n") 455 456#define __asm_copy_to_user_14x_cont(to, from, ret, COPY, FIXUP, TENTRY) \ 457 __asm_copy_to_user_12x_cont(to, from, ret, \ 458 " move.w [%1+],$r9\n" \ 459 " move.w $r9,[%0+]\n8:\n" COPY, \ 460 "9: addq 2,%2\n" FIXUP, \ 461 " .dword 8b,9b\n" TENTRY) 462 463#define __asm_copy_to_user_14(to, from, ret) \ 464 __asm_copy_to_user_14x_cont(to, from, ret, "", "", "") 465 466#define __asm_copy_to_user_15(to, from, ret) \ 467 __asm_copy_to_user_14x_cont(to, from, ret, \ 468 " move.b [%1+],$r9\n" \ 469 " move.b $r9,[%0+]\n10:\n", \ 470 "11: addq 1,%2\n", \ 471 " .dword 10b,11b\n") 472 473#define __asm_copy_to_user_16x_cont(to, from, ret, COPY, FIXUP, TENTRY) \ 474 __asm_copy_to_user_12x_cont(to, from, ret, \ 475 " move.d [%1+],$r9\n" \ 476 " move.d $r9,[%0+]\n8:\n" COPY, \ 477 "9: addq 4,%2\n" FIXUP, \ 478 " .dword 8b,9b\n" TENTRY) 479 480#define __asm_copy_to_user_16(to, from, ret) \ 481 __asm_copy_to_user_16x_cont(to, from, ret, "", "", "") 482 483#define __asm_copy_to_user_20x_cont(to, from, ret, COPY, FIXUP, TENTRY) \ 484 __asm_copy_to_user_16x_cont(to, from, ret, \ 485 " move.d [%1+],$r9\n" \ 486 " move.d $r9,[%0+]\n10:\n" COPY, \ 487 "11: addq 4,%2\n" FIXUP, \ 488 " .dword 10b,11b\n" TENTRY) 489 490#define __asm_copy_to_user_20(to, from, ret) \ 491 __asm_copy_to_user_20x_cont(to, from, ret, "", "", "") 492 493#define __asm_copy_to_user_24x_cont(to, from, ret, COPY, FIXUP, TENTRY) \ 494 __asm_copy_to_user_20x_cont(to, from, ret, \ 495 " move.d [%1+],$r9\n" \ 496 " move.d $r9,[%0+]\n12:\n" COPY, \ 497 "13: addq 4,%2\n" FIXUP, \ 498 " .dword 12b,13b\n" TENTRY) 499 500#define __asm_copy_to_user_24(to, from, ret) \ 501 __asm_copy_to_user_24x_cont(to, from, ret, "", "", "") 502 503/* Define a few clearing asms with exception handlers. */ 504 505/* This frame-asm is like the __asm_copy_user_cont one, but has one less 506 input. */ 507 508#define __asm_clear(to, ret, CLEAR, FIXUP, TENTRY) \ 509 __asm__ __volatile__ ( \ 510 CLEAR \ 511 "1:\n" \ 512 " .section .fixup,\"ax\"\n" \ 513 FIXUP \ 514 " jump 1b\n" \ 515 " .previous\n" \ 516 " .section __ex_table,\"a\"\n" \ 517 TENTRY \ 518 " .previous" \ 519 : "=r" (to), "=r" (ret) \ 520 : "0" (to), "1" (ret) \ 521 : "memory") 522 523#define __asm_clear_1(to, ret) \ 524 __asm_clear(to, ret, \ 525 " clear.b [%0+]\n2:\n", \ 526 "3: addq 1,%1\n", \ 527 " .dword 2b,3b\n") 528 529#define __asm_clear_2(to, ret) \ 530 __asm_clear(to, ret, \ 531 " clear.w [%0+]\n2:\n", \ 532 "3: addq 2,%1\n", \ 533 " .dword 2b,3b\n") 534 535#define __asm_clear_3(to, ret) \ 536 __asm_clear(to, ret, \ 537 " clear.w [%0+]\n" \ 538 "2: clear.b [%0+]\n3:\n", \ 539 "4: addq 2,%1\n" \ 540 "5: addq 1,%1\n", \ 541 " .dword 2b,4b\n" \ 542 " .dword 3b,5b\n") 543 544#define __asm_clear_4x_cont(to, ret, CLEAR, FIXUP, TENTRY) \ 545 __asm_clear(to, ret, \ 546 " clear.d [%0+]\n2:\n" CLEAR, \ 547 "3: addq 4,%1\n" FIXUP, \ 548 " .dword 2b,3b\n" TENTRY) 549 550#define __asm_clear_4(to, ret) \ 551 __asm_clear_4x_cont(to, ret, "", "", "") 552 553#define __asm_clear_8x_cont(to, ret, CLEAR, FIXUP, TENTRY) \ 554 __asm_clear_4x_cont(to, ret, \ 555 " clear.d [%0+]\n4:\n" CLEAR, \ 556 "5: addq 4,%1\n" FIXUP, \ 557 " .dword 4b,5b\n" TENTRY) 558 559#define __asm_clear_8(to, ret) \ 560 __asm_clear_8x_cont(to, ret, "", "", "") 561 562#define __asm_clear_12x_cont(to, ret, CLEAR, FIXUP, TENTRY) \ 563 __asm_clear_8x_cont(to, ret, \ 564 " clear.d [%0+]\n6:\n" CLEAR, \ 565 "7: addq 4,%1\n" FIXUP, \ 566 " .dword 6b,7b\n" TENTRY) 567 568#define __asm_clear_12(to, ret) \ 569 __asm_clear_12x_cont(to, ret, "", "", "") 570 571#define __asm_clear_16x_cont(to, ret, CLEAR, FIXUP, TENTRY) \ 572 __asm_clear_12x_cont(to, ret, \ 573 " clear.d [%0+]\n8:\n" CLEAR, \ 574 "9: addq 4,%1\n" FIXUP, \ 575 " .dword 8b,9b\n" TENTRY) 576 577#define __asm_clear_16(to, ret) \ 578 __asm_clear_16x_cont(to, ret, "", "", "") 579 580#define __asm_clear_20x_cont(to, ret, CLEAR, FIXUP, TENTRY) \ 581 __asm_clear_16x_cont(to, ret, \ 582 " clear.d [%0+]\n10:\n" CLEAR, \ 583 "11: addq 4,%1\n" FIXUP, \ 584 " .dword 10b,11b\n" TENTRY) 585 586#define __asm_clear_20(to, ret) \ 587 __asm_clear_20x_cont(to, ret, "", "", "") 588 589#define __asm_clear_24x_cont(to, ret, CLEAR, FIXUP, TENTRY) \ 590 __asm_clear_20x_cont(to, ret, \ 591 " clear.d [%0+]\n12:\n" CLEAR, \ 592 "13: addq 4,%1\n" FIXUP, \ 593 " .dword 12b,13b\n" TENTRY) 594 595#define __asm_clear_24(to, ret) \ 596 __asm_clear_24x_cont(to, ret, "", "", "") 597 598/* 599 * Return the size of a string (including the ending 0) 600 * 601 * Return length of string in userspace including terminating 0 602 * or 0 for error. Return a value greater than N if too long. 603 */ 604 605static inline long 606strnlen_user(const char *s, long n) 607{ 608 long res, tmp1; 609 610 if (!access_ok(VERIFY_READ, s, 0)) 611 return 0; 612 613 /* 614 * This code is deduced from: 615 * 616 * tmp1 = n; 617 * while (tmp1-- > 0 && *s++) 618 * ; 619 * 620 * res = n - tmp1; 621 * 622 * (with tweaks). 623 */ 624 625 __asm__ __volatile__ ( 626 " move.d %1,$r9\n" 627 "0:\n" 628 " ble 1f\n" 629 " subq 1,$r9\n" 630 631 " test.b [%0+]\n" 632 " bne 0b\n" 633 " test.d $r9\n" 634 "1:\n" 635 " move.d %1,%0\n" 636 " sub.d $r9,%0\n" 637 "2:\n" 638 " .section .fixup,\"ax\"\n" 639 640 "3: clear.d %0\n" 641 " jump 2b\n" 642 643 /* There's one address for a fault at the first move, and 644 two possible PC values for a fault at the second move, 645 being a delay-slot filler. However, the branch-target 646 for the second move is the same as the first address. 647 Just so you don't get confused... */ 648 " .previous\n" 649 " .section __ex_table,\"a\"\n" 650 " .dword 0b,3b\n" 651 " .dword 1b,3b\n" 652 " .previous\n" 653 : "=r" (res), "=r" (tmp1) 654 : "0" (s), "1" (n) 655 : "r9"); 656 657 return res; 658} 659 660#endif 661