bcopyinout.S revision 137463
1/* $NetBSD: bcopyinout.S,v 1.11 2003/10/13 21:22:40 scw Exp $ */ 2 3/* 4 * Copyright (c) 2002 Wasabi Systems, Inc. 5 * All rights reserved. 6 * 7 * Written by Allen Briggs for Wasabi Systems, Inc. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. All advertising materials mentioning features or use of this software 18 * must display the following acknowledgement: 19 * This product includes software developed for the NetBSD Project by 20 * Wasabi Systems, Inc. 21 * 4. The name of Wasabi Systems, Inc. may not be used to endorse 22 * or promote products derived from this software without specific prior 23 * written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND 26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 27 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 28 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC 29 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 30 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 31 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 32 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 33 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 34 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 35 * POSSIBILITY OF SUCH DAMAGE. 36 */ 37 38 39#include "assym.s" 40 41#include <machine/asm.h> 42 43__FBSDID("$FreeBSD: head/sys/arm/arm/bcopyinout.S 137463 2004-11-09 16:47:47Z cognet $"); 44#ifdef __XSCALE__ 45#include <arm/arm/bcopyinout_xscale.S> 46#else 47 48 .text 49 .align 0 50 51#ifdef MULTIPROCESSOR 52.Lcpu_info: 53 .word _C_LABEL(cpu_info) 54#else 55.Lcurpcb: 56 .word _C_LABEL(__pcpu) + PC_CURPCB 57#endif 58 59#define SAVE_REGS stmfd sp!, {r4-r11} 60#define RESTORE_REGS ldmfd sp!, {r4-r11} 61 62#if defined(__XSCALE__) 63#define HELLOCPP # 64#define PREFETCH(rx,o) pld [ rx , HELLOCPP (o) ] 65#else 66#define PREFETCH(rx,o) 67#endif 68 69/* 70 * r0 = user space address 71 * r1 = kernel space address 72 * r2 = length 73 * 74 * Copies bytes from user space to kernel space 75 * 76 * We save/restore r4-r11: 77 * r4-r11 are scratch 78 */ 79ENTRY(copyin) 80 /* Quick exit if length is zero */ 81 teq r2, #0 82 moveq r0, #0 83 RETEQ 84 85 SAVE_REGS 86#ifdef MULTIPROCESSOR 87 /* XXX Probably not appropriate for non-Hydra SMPs */ 88 stmfd sp!, {r0-r2, r14} 89 bl _C_LABEL(cpu_number) 90 ldr r4, .Lcpu_info 91 ldr r4, [r4, r0, lsl #2] 92 ldr r4, [r4, #CI_CURPCB] 93 ldmfd sp!, {r0-r2, r14} 94#else 95 ldr r4, .Lcurpcb 96 ldr r4, [r4] 97#endif 98 99 ldr r5, [r4, #PCB_ONFAULT] 100 adr r3, .Lcopyfault 101 str r3, [r4, #PCB_ONFAULT] 102 103 PREFETCH(r0, 0) 104 PREFETCH(r1, 0) 105 106 /* 107 * If not too many bytes, take the slow path. 108 */ 109 cmp r2, #0x08 110 blt .Licleanup 111 112 /* 113 * Align destination to word boundary. 114 */ 115 and r6, r1, #0x3 116 ldr pc, [pc, r6, lsl #2] 117 b .Lialend 118 .word .Lialend 119 .word .Lial3 120 .word .Lial2 121 .word .Lial1 122.Lial3: ldrbt r6, [r0], #1 123 sub r2, r2, #1 124 strb r6, [r1], #1 125.Lial2: ldrbt r7, [r0], #1 126 sub r2, r2, #1 127 strb r7, [r1], #1 128.Lial1: ldrbt r6, [r0], #1 129 sub r2, r2, #1 130 strb r6, [r1], #1 131.Lialend: 132 133 /* 134 * If few bytes left, finish slow. 135 */ 136 cmp r2, #0x08 137 blt .Licleanup 138 139 /* 140 * If source is not aligned, finish slow. 141 */ 142 ands r3, r0, #0x03 143 bne .Licleanup 144 145 cmp r2, #0x60 /* Must be > 0x5f for unrolled cacheline */ 146 blt .Licleanup8 147 148 /* 149 * Align destination to cacheline boundary. 150 * If source and destination are nicely aligned, this can be a big 151 * win. If not, it's still cheaper to copy in groups of 32 even if 152 * we don't get the nice cacheline alignment. 153 */ 154 and r6, r1, #0x1f 155 ldr pc, [pc, r6] 156 b .Licaligned 157 .word .Licaligned 158 .word .Lical28 159 .word .Lical24 160 .word .Lical20 161 .word .Lical16 162 .word .Lical12 163 .word .Lical8 164 .word .Lical4 165.Lical28:ldrt r6, [r0], #4 166 sub r2, r2, #4 167 str r6, [r1], #4 168.Lical24:ldrt r7, [r0], #4 169 sub r2, r2, #4 170 str r7, [r1], #4 171.Lical20:ldrt r6, [r0], #4 172 sub r2, r2, #4 173 str r6, [r1], #4 174.Lical16:ldrt r7, [r0], #4 175 sub r2, r2, #4 176 str r7, [r1], #4 177.Lical12:ldrt r6, [r0], #4 178 sub r2, r2, #4 179 str r6, [r1], #4 180.Lical8:ldrt r7, [r0], #4 181 sub r2, r2, #4 182 str r7, [r1], #4 183.Lical4:ldrt r6, [r0], #4 184 sub r2, r2, #4 185 str r6, [r1], #4 186 187 /* 188 * We start with > 0x40 bytes to copy (>= 0x60 got us into this 189 * part of the code, and we may have knocked that down by as much 190 * as 0x1c getting aligned). 191 * 192 * This loop basically works out to: 193 * do { 194 * prefetch-next-cacheline(s) 195 * bytes -= 0x20; 196 * copy cacheline 197 * } while (bytes >= 0x40); 198 * bytes -= 0x20; 199 * copy cacheline 200 */ 201.Licaligned: 202 PREFETCH(r0, 32) 203 PREFETCH(r1, 32) 204 205 sub r2, r2, #0x20 206 207 /* Copy a cacheline */ 208 ldrt r10, [r0], #4 209 ldrt r11, [r0], #4 210 ldrt r6, [r0], #4 211 ldrt r7, [r0], #4 212 ldrt r8, [r0], #4 213 ldrt r9, [r0], #4 214 stmia r1!, {r10-r11} 215 ldrt r10, [r0], #4 216 ldrt r11, [r0], #4 217 stmia r1!, {r6-r11} 218 219 cmp r2, #0x40 220 bge .Licaligned 221 222 sub r2, r2, #0x20 223 224 /* Copy a cacheline */ 225 ldrt r10, [r0], #4 226 ldrt r11, [r0], #4 227 ldrt r6, [r0], #4 228 ldrt r7, [r0], #4 229 ldrt r8, [r0], #4 230 ldrt r9, [r0], #4 231 stmia r1!, {r10-r11} 232 ldrt r10, [r0], #4 233 ldrt r11, [r0], #4 234 stmia r1!, {r6-r11} 235 236 cmp r2, #0x08 237 blt .Liprecleanup 238 239.Licleanup8: 240 ldrt r8, [r0], #4 241 ldrt r9, [r0], #4 242 sub r2, r2, #8 243 stmia r1!, {r8, r9} 244 cmp r2, #8 245 bge .Licleanup8 246 247.Liprecleanup: 248 /* 249 * If we're done, bail. 250 */ 251 cmp r2, #0 252 beq .Lout 253 254.Licleanup: 255 and r6, r2, #0x3 256 ldr pc, [pc, r6, lsl #2] 257 b .Licend 258 .word .Lic4 259 .word .Lic1 260 .word .Lic2 261 .word .Lic3 262.Lic4: ldrbt r6, [r0], #1 263 sub r2, r2, #1 264 strb r6, [r1], #1 265.Lic3: ldrbt r7, [r0], #1 266 sub r2, r2, #1 267 strb r7, [r1], #1 268.Lic2: ldrbt r6, [r0], #1 269 sub r2, r2, #1 270 strb r6, [r1], #1 271.Lic1: ldrbt r7, [r0], #1 272 subs r2, r2, #1 273 strb r7, [r1], #1 274.Licend: 275 bne .Licleanup 276 277.Liout: 278 mov r0, #0 279 280 str r5, [r4, #PCB_ONFAULT] 281 RESTORE_REGS 282 283 RET 284 285.Lcopyfault: 286 mov r0, #14 /* EFAULT */ 287 str r5, [r4, #PCB_ONFAULT] 288 RESTORE_REGS 289 290 RET 291 292/* 293 * r0 = kernel space address 294 * r1 = user space address 295 * r2 = length 296 * 297 * Copies bytes from kernel space to user space 298 * 299 * We save/restore r4-r11: 300 * r4-r11 are scratch 301 */ 302 303ENTRY(copyout) 304 /* Quick exit if length is zero */ 305 teq r2, #0 306 moveq r0, #0 307 RETeq 308 309 SAVE_REGS 310#ifdef MULTIPROCESSOR 311 /* XXX Probably not appropriate for non-Hydra SMPs */ 312 stmfd sp!, {r0-r2, r14} 313 bl _C_LABEL(cpu_number) 314 ldr r4, .Lcpu_info 315 ldr r4, [r4, r0, lsl #2] 316 ldr r4, [r4, #CI_CURPCB] 317 ldmfd sp!, {r0-r2, r14} 318#else 319 ldr r4, .Lcurpcb 320 ldr r4, [r4] 321#endif 322 323 ldr r5, [r4, #PCB_ONFAULT] 324 adr r3, .Lcopyfault 325 str r3, [r4, #PCB_ONFAULT] 326 327 PREFETCH(r0, 0) 328 PREFETCH(r1, 0) 329 330 /* 331 * If not too many bytes, take the slow path. 332 */ 333 cmp r2, #0x08 334 blt .Lcleanup 335 336 /* 337 * Align destination to word boundary. 338 */ 339 and r6, r1, #0x3 340 ldr pc, [pc, r6, lsl #2] 341 b .Lalend 342 .word .Lalend 343 .word .Lal3 344 .word .Lal2 345 .word .Lal1 346.Lal3: ldrb r6, [r0], #1 347 sub r2, r2, #1 348 strbt r6, [r1], #1 349.Lal2: ldrb r7, [r0], #1 350 sub r2, r2, #1 351 strbt r7, [r1], #1 352.Lal1: ldrb r6, [r0], #1 353 sub r2, r2, #1 354 strbt r6, [r1], #1 355.Lalend: 356 357 /* 358 * If few bytes left, finish slow. 359 */ 360 cmp r2, #0x08 361 blt .Lcleanup 362 363 /* 364 * If source is not aligned, finish slow. 365 */ 366 ands r3, r0, #0x03 367 bne .Lcleanup 368 369 cmp r2, #0x60 /* Must be > 0x5f for unrolled cacheline */ 370 blt .Lcleanup8 371 372 /* 373 * Align source & destination to cacheline boundary. 374 */ 375 and r6, r1, #0x1f 376 ldr pc, [pc, r6] 377 b .Lcaligned 378 .word .Lcaligned 379 .word .Lcal28 380 .word .Lcal24 381 .word .Lcal20 382 .word .Lcal16 383 .word .Lcal12 384 .word .Lcal8 385 .word .Lcal4 386.Lcal28:ldr r6, [r0], #4 387 sub r2, r2, #4 388 strt r6, [r1], #4 389.Lcal24:ldr r7, [r0], #4 390 sub r2, r2, #4 391 strt r7, [r1], #4 392.Lcal20:ldr r6, [r0], #4 393 sub r2, r2, #4 394 strt r6, [r1], #4 395.Lcal16:ldr r7, [r0], #4 396 sub r2, r2, #4 397 strt r7, [r1], #4 398.Lcal12:ldr r6, [r0], #4 399 sub r2, r2, #4 400 strt r6, [r1], #4 401.Lcal8: ldr r7, [r0], #4 402 sub r2, r2, #4 403 strt r7, [r1], #4 404.Lcal4: ldr r6, [r0], #4 405 sub r2, r2, #4 406 strt r6, [r1], #4 407 408 /* 409 * We start with > 0x40 bytes to copy (>= 0x60 got us into this 410 * part of the code, and we may have knocked that down by as much 411 * as 0x1c getting aligned). 412 * 413 * This loop basically works out to: 414 * do { 415 * prefetch-next-cacheline(s) 416 * bytes -= 0x20; 417 * copy cacheline 418 * } while (bytes >= 0x40); 419 * bytes -= 0x20; 420 * copy cacheline 421 */ 422.Lcaligned: 423 PREFETCH(r0, 32) 424 PREFETCH(r1, 32) 425 426 sub r2, r2, #0x20 427 428 /* Copy a cacheline */ 429 ldmia r0!, {r6-r11} 430 strt r6, [r1], #4 431 strt r7, [r1], #4 432 ldmia r0!, {r6-r7} 433 strt r8, [r1], #4 434 strt r9, [r1], #4 435 strt r10, [r1], #4 436 strt r11, [r1], #4 437 strt r6, [r1], #4 438 strt r7, [r1], #4 439 440 cmp r2, #0x40 441 bge .Lcaligned 442 443 sub r2, r2, #0x20 444 445 /* Copy a cacheline */ 446 ldmia r0!, {r6-r11} 447 strt r6, [r1], #4 448 strt r7, [r1], #4 449 ldmia r0!, {r6-r7} 450 strt r8, [r1], #4 451 strt r9, [r1], #4 452 strt r10, [r1], #4 453 strt r11, [r1], #4 454 strt r6, [r1], #4 455 strt r7, [r1], #4 456 457 cmp r2, #0x08 458 blt .Lprecleanup 459 460.Lcleanup8: 461 ldmia r0!, {r8-r9} 462 sub r2, r2, #8 463 strt r8, [r1], #4 464 strt r9, [r1], #4 465 cmp r2, #8 466 bge .Lcleanup8 467 468.Lprecleanup: 469 /* 470 * If we're done, bail. 471 */ 472 cmp r2, #0 473 beq .Lout 474 475.Lcleanup: 476 and r6, r2, #0x3 477 ldr pc, [pc, r6, lsl #2] 478 b .Lcend 479 .word .Lc4 480 .word .Lc1 481 .word .Lc2 482 .word .Lc3 483.Lc4: ldrb r6, [r0], #1 484 sub r2, r2, #1 485 strbt r6, [r1], #1 486.Lc3: ldrb r7, [r0], #1 487 sub r2, r2, #1 488 strbt r7, [r1], #1 489.Lc2: ldrb r6, [r0], #1 490 sub r2, r2, #1 491 strbt r6, [r1], #1 492.Lc1: ldrb r7, [r0], #1 493 subs r2, r2, #1 494 strbt r7, [r1], #1 495.Lcend: 496 bne .Lcleanup 497 498.Lout: 499 mov r0, #0 500 501 str r5, [r4, #PCB_ONFAULT] 502 RESTORE_REGS 503 504 RET 505 506/* 507 * r0 = kernel space source address 508 * r1 = kernel space destination address 509 * r2 = length 510 * 511 * Copies bytes from kernel space to kernel space, aborting on page fault 512 * 513 * Copy of copyout, but without the ldrt/strt instructions. 514 */ 515 516ENTRY(kcopy) 517 /* Quick exit if length is zero */ 518 teq r2, #0 519 moveq r0, #0 520 RETeq 521 522 SAVE_REGS 523#ifdef MULTIPROCESSOR 524 /* XXX Probably not appropriate for non-Hydra SMPs */ 525 stmfd sp!, {r0-r2, r14} 526 bl _C_LABEL(cpu_number) 527 ldr r4, .Lcpu_info 528 ldr r4, [r4, r0, lsl #2] 529 ldr r4, [r4, #CI_CURPCB] 530 ldmfd sp!, {r0-r2, r14} 531#else 532 ldr r4, .Lcurpcb 533 ldr r4, [r4] 534#endif 535 536 ldr r5, [r4, #PCB_ONFAULT] 537 adr r3, .Lcopyfault 538 str r3, [r4, #PCB_ONFAULT] 539 540 PREFETCH(r0, 0) 541 PREFETCH(r1, 0) 542 543 /* 544 * If not too many bytes, take the slow path. 545 */ 546 cmp r2, #0x08 547 blt .Lkcleanup 548 549 /* 550 * Align destination to word boundary. 551 */ 552 and r6, r1, #0x3 553 ldr pc, [pc, r6, lsl #2] 554 b .Lkalend 555 .word .Lkalend 556 .word .Lkal3 557 .word .Lkal2 558 .word .Lkal1 559.Lkal3: ldrb r6, [r0], #1 560 sub r2, r2, #1 561 strb r6, [r1], #1 562.Lkal2: ldrb r7, [r0], #1 563 sub r2, r2, #1 564 strb r7, [r1], #1 565.Lkal1: ldrb r6, [r0], #1 566 sub r2, r2, #1 567 strb r6, [r1], #1 568.Lkalend: 569 570 /* 571 * If few bytes left, finish slow. 572 */ 573 cmp r2, #0x08 574 blt .Lkcleanup 575 576 /* 577 * If source is not aligned, finish slow. 578 */ 579 ands r3, r0, #0x03 580 bne .Lkcleanup 581 582 cmp r2, #0x60 /* Must be > 0x5f for unrolled cacheline */ 583 blt .Lkcleanup8 584 585 /* 586 * Align source & destination to cacheline boundary. 587 */ 588 and r6, r1, #0x1f 589 ldr pc, [pc, r6] 590 b .Lkcaligned 591 .word .Lkcaligned 592 .word .Lkcal28 593 .word .Lkcal24 594 .word .Lkcal20 595 .word .Lkcal16 596 .word .Lkcal12 597 .word .Lkcal8 598 .word .Lkcal4 599.Lkcal28:ldr r6, [r0], #4 600 sub r2, r2, #4 601 str r6, [r1], #4 602.Lkcal24:ldr r7, [r0], #4 603 sub r2, r2, #4 604 str r7, [r1], #4 605.Lkcal20:ldr r6, [r0], #4 606 sub r2, r2, #4 607 str r6, [r1], #4 608.Lkcal16:ldr r7, [r0], #4 609 sub r2, r2, #4 610 str r7, [r1], #4 611.Lkcal12:ldr r6, [r0], #4 612 sub r2, r2, #4 613 str r6, [r1], #4 614.Lkcal8:ldr r7, [r0], #4 615 sub r2, r2, #4 616 str r7, [r1], #4 617.Lkcal4:ldr r6, [r0], #4 618 sub r2, r2, #4 619 str r6, [r1], #4 620 621 /* 622 * We start with > 0x40 bytes to copy (>= 0x60 got us into this 623 * part of the code, and we may have knocked that down by as much 624 * as 0x1c getting aligned). 625 * 626 * This loop basically works out to: 627 * do { 628 * prefetch-next-cacheline(s) 629 * bytes -= 0x20; 630 * copy cacheline 631 * } while (bytes >= 0x40); 632 * bytes -= 0x20; 633 * copy cacheline 634 */ 635.Lkcaligned: 636 PREFETCH(r0, 32) 637 PREFETCH(r1, 32) 638 639 sub r2, r2, #0x20 640 641 /* Copy a cacheline */ 642 ldmia r0!, {r6-r11} 643 stmia r1!, {r6, r7} 644 ldmia r0!, {r6, r7} 645 stmia r1!, {r8-r11} 646 stmia r1!, {r6, r7} 647 648 cmp r2, #0x40 649 bge .Lkcaligned 650 651 sub r2, r2, #0x20 652 653 /* Copy a cacheline */ 654 ldmia r0!, {r6-r11} 655 stmia r1!, {r6-r7} 656 ldmia r0!, {r6-r7} 657 stmia r1!, {r8-r11} 658 stmia r1!, {r6-r7} 659 660 cmp r2, #0x08 661 blt .Lkprecleanup 662 663.Lkcleanup8: 664 ldmia r0!, {r8-r9} 665 sub r2, r2, #8 666 stmia r1!, {r8-r9} 667 cmp r2, #8 668 bge .Lkcleanup8 669 670.Lkprecleanup: 671 /* 672 * If we're done, bail. 673 */ 674 cmp r2, #0 675 beq .Lkout 676 677.Lkcleanup: 678 and r6, r2, #0x3 679 ldr pc, [pc, r6, lsl #2] 680 b .Lkcend 681 .word .Lkc4 682 .word .Lkc1 683 .word .Lkc2 684 .word .Lkc3 685.Lkc4: ldrb r6, [r0], #1 686 sub r2, r2, #1 687 strb r6, [r1], #1 688.Lkc3: ldrb r7, [r0], #1 689 sub r2, r2, #1 690 strb r7, [r1], #1 691.Lkc2: ldrb r6, [r0], #1 692 sub r2, r2, #1 693 strb r6, [r1], #1 694.Lkc1: ldrb r7, [r0], #1 695 subs r2, r2, #1 696 strb r7, [r1], #1 697.Lkcend: 698 bne .Lkcleanup 699 700.Lkout: 701 mov r0, #0 702 703 str r5, [r4, #PCB_ONFAULT] 704 RESTORE_REGS 705 706 RET 707#endif /* !__XSCALE__ */ 708 709/* 710 * int badaddr_read_1(const uint8_t *src, uint8_t *dest) 711 * 712 * Copies a single 8-bit value from src to dest, returning 0 on success, 713 * else EFAULT if a page fault occurred. 714 */ 715ENTRY(badaddr_read_1) 716#ifdef MULTIPROCESSOR 717 /* XXX Probably not appropriate for non-Hydra SMPs */ 718 stmfd sp!, {r0-r1, r14} 719 bl _C_LABEL(cpu_number) 720 ldr r2, .Lcpu_info 721 ldr r2, [r2, r0, lsl #2] 722 ldr r2, [r2, #CI_CURPCB] 723 ldmfd sp!, {r0-r1, r14} 724#else 725 ldr r2, .Lcurpcb 726 ldr r2, [r2] 727#endif 728 ldr ip, [r2, #PCB_ONFAULT] 729 adr r3, 1f 730 str r3, [r2, #PCB_ONFAULT] 731 nop 732 nop 733 nop 734 ldrb r3, [r0] 735 nop 736 nop 737 nop 738 strb r3, [r1] 739 mov r0, #0 /* No fault */ 7401: str ip, [r2, #PCB_ONFAULT] 741 RET 742 743/* 744 * int badaddr_read_2(const uint16_t *src, uint16_t *dest) 745 * 746 * Copies a single 16-bit value from src to dest, returning 0 on success, 747 * else EFAULT if a page fault occurred. 748 */ 749ENTRY(badaddr_read_2) 750#ifdef MULTIPROCESSOR 751 /* XXX Probably not appropriate for non-Hydra SMPs */ 752 stmfd sp!, {r0-r1, r14} 753 bl _C_LABEL(cpu_number) 754 ldr r2, .Lcpu_info 755 ldr r2, [r2, r0, lsl #2] 756 ldr r2, [r2, #CI_CURPCB] 757 ldmfd sp!, {r0-r1, r14} 758#else 759 ldr r2, .Lcurpcb 760 ldr r2, [r2] 761#endif 762 ldr ip, [r2, #PCB_ONFAULT] 763 adr r3, 1f 764 str r3, [r2, #PCB_ONFAULT] 765 nop 766 nop 767 nop 768 ldrh r3, [r0] 769 nop 770 nop 771 nop 772 strh r3, [r1] 773 mov r0, #0 /* No fault */ 7741: str ip, [r2, #PCB_ONFAULT] 775 RET 776 777/* 778 * int badaddr_read_4(const uint32_t *src, uint32_t *dest) 779 * 780 * Copies a single 32-bit value from src to dest, returning 0 on success, 781 * else EFAULT if a page fault occurred. 782 */ 783ENTRY(badaddr_read_4) 784#ifdef MULTIPROCESSOR 785 /* XXX Probably not appropriate for non-Hydra SMPs */ 786 stmfd sp!, {r0-r1, r14} 787 bl _C_LABEL(cpu_number) 788 ldr r2, .Lcpu_info 789 ldr r2, [r2, r0, lsl #2] 790 ldr r2, [r2, #CI_CURPCB] 791 ldmfd sp!, {r0-r1, r14} 792#else 793 ldr r2, .Lcurpcb 794 ldr r2, [r2] 795#endif 796 ldr ip, [r2, #PCB_ONFAULT] 797 adr r3, 1f 798 str r3, [r2, #PCB_ONFAULT] 799 nop 800 nop 801 nop 802 ldr r3, [r0] 803 nop 804 nop 805 nop 806 str r3, [r1] 807 mov r0, #0 /* No fault */ 8081: str ip, [r2, #PCB_ONFAULT] 809 RET 810 811