1/* $NetBSD: memmove.S,v 1.4 2003/10/14 07:51:45 scw Exp $ */ 2 3/*- 4 * Copyright (c) 1997 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Neil A. Carson and Mark Brinicombe 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32#include <machine/asm.h> 33.syntax unified 34 35#ifndef _BCOPY 36/* LINTSTUB: Func: void *memmove(void *, const void *, size_t) */ 37ENTRY(memmove) 38#else 39/* bcopy = memcpy/memmove with arguments reversed. */ 40/* LINTSTUB: Func: void bcopy(void *, void *, size_t) */ 41ENTRY(bcopy) 42 /* switch the source and destination registers */ 43 eor r0, r1, r0 44 eor r1, r0, r1 45 eor r0, r1, r0 46#endif 47 /* Do the buffers overlap? */ 48 cmp r0, r1 49 it eq 50 RETeq /* Bail now if src/dst are the same */ 51 ite cc 52 subcc r3, r0, r1 /* if (dst > src) r3 = dst - src */ 53 subcs r3, r1, r0 /* if (src > dsr) r3 = src - dst */ 54 cmp r3, r2 /* if (r3 < len) we have an overlap */ 55 bcc PIC_SYM(_C_LABEL(memcpy), PLT) 56 57 /* Determine copy direction */ 58 cmp r1, r0 59 it cc 60 bcc .Lmemmove_backwards 61 62 itt eq 63 moveq r0, #0 /* Quick abort for len=0 */ 64 RETeq 65 66 stmdb sp!, {r0, lr} /* memmove() returns dest addr */ 67 subs r2, r2, #4 68 blt .Lmemmove_fl4 /* less than 4 bytes */ 69 ands r12, r0, #3 70 bne .Lmemmove_fdestul /* oh unaligned destination addr */ 71 ands r12, r1, #3 72 bne .Lmemmove_fsrcul /* oh unaligned source addr */ 73 74.Lmemmove_ft8: 75 /* We have aligned source and destination */ 76 subs r2, r2, #8 77 blt .Lmemmove_fl12 /* less than 12 bytes (4 from above) */ 78 subs r2, r2, #0x14 79 blt .Lmemmove_fl32 /* less than 32 bytes (12 from above) */ 80 stmdb sp!, {r4} /* borrow r4 */ 81 82 /* blat 32 bytes at a time */ 83 /* XXX for really big copies perhaps we should use more registers */ 84.Lmemmove_floop32: 85 ldmia r1!, {r3, r4, r12, lr} 86 stmia r0!, {r3, r4, r12, lr} 87 ldmia r1!, {r3, r4, r12, lr} 88 stmia r0!, {r3, r4, r12, lr} 89 subs r2, r2, #0x20 90 bge .Lmemmove_floop32 91 92 cmn r2, #0x10 93 ittt ge 94 ldmiage r1!, {r3, r4, r12, lr} /* blat a remaining 16 bytes */ 95 stmiage r0!, {r3, r4, r12, lr} 96 subge r2, r2, #0x10 97 ldmia sp!, {r4} /* return r4 */ 98 99.Lmemmove_fl32: 100 adds r2, r2, #0x14 101 102 /* blat 12 bytes at a time */ 103.Lmemmove_floop12: 104 ittt ge 105 ldmiage r1!, {r3, r12, lr} 106 stmiage r0!, {r3, r12, lr} 107 subsge r2, r2, #0x0c 108 bge .Lmemmove_floop12 109 110.Lmemmove_fl12: 111 adds r2, r2, #8 112 blt .Lmemmove_fl4 113 114 subs r2, r2, #4 115 itt lt 116 ldrlt r3, [r1], #4 117 strlt r3, [r0], #4 118 ittt ge 119 ldmiage r1!, {r3, r12} 120 stmiage r0!, {r3, r12} 121 subge r2, r2, #4 122 123.Lmemmove_fl4: 124 /* less than 4 bytes to go */ 125 adds r2, r2, #4 126 it eq 127 ldmiaeq sp!, {r0, pc} /* done */ 128 129 /* copy the crud byte at a time */ 130 cmp r2, #2 131 ldrb r3, [r1], #1 132 strb r3, [r0], #1 133 itt ge 134 ldrbge r3, [r1], #1 135 strbge r3, [r0], #1 136 itt gt 137 ldrbgt r3, [r1], #1 138 strbgt r3, [r0], #1 139 ldmia sp!, {r0, pc} 140 141 /* erg - unaligned destination */ 142.Lmemmove_fdestul: 143 rsb r12, r12, #4 144 cmp r12, #2 145 146 /* align destination with byte copies */ 147 ldrb r3, [r1], #1 148 strb r3, [r0], #1 149 itt ge 150 ldrbge r3, [r1], #1 151 strbge r3, [r0], #1 152 itt gt 153 ldrbgt r3, [r1], #1 154 strbgt r3, [r0], #1 155 subs r2, r2, r12 156 blt .Lmemmove_fl4 /* less the 4 bytes */ 157 158 ands r12, r1, #3 159 beq .Lmemmove_ft8 /* we have an aligned source */ 160 161 /* erg - unaligned source */ 162 /* This is where it gets nasty ... */ 163.Lmemmove_fsrcul: 164 bic r1, r1, #3 165 ldr lr, [r1], #4 166 cmp r12, #2 167 bgt .Lmemmove_fsrcul3 168 beq .Lmemmove_fsrcul2 169 cmp r2, #0x0c 170 blt .Lmemmove_fsrcul1loop4 171 sub r2, r2, #0x0c 172 stmdb sp!, {r4, r5} 173 174.Lmemmove_fsrcul1loop16: 175#ifdef __ARMEB__ 176 mov r3, lr, lsl #8 177#else 178 mov r3, lr, lsr #8 179#endif 180 ldmia r1!, {r4, r5, r12, lr} 181#ifdef __ARMEB__ 182 orr r3, r3, r4, lsr #24 183 mov r4, r4, lsl #8 184 orr r4, r4, r5, lsr #24 185 mov r5, r5, lsl #8 186 orr r5, r5, r12, lsr #24 187 mov r12, r12, lsl #8 188 orr r12, r12, lr, lsr #24 189#else 190 orr r3, r3, r4, lsl #24 191 mov r4, r4, lsr #8 192 orr r4, r4, r5, lsl #24 193 mov r5, r5, lsr #8 194 orr r5, r5, r12, lsl #24 195 mov r12, r12, lsr #8 196 orr r12, r12, lr, lsl #24 197#endif 198 stmia r0!, {r3-r5, r12} 199 subs r2, r2, #0x10 200 bge .Lmemmove_fsrcul1loop16 201 ldmia sp!, {r4, r5} 202 adds r2, r2, #0x0c 203 blt .Lmemmove_fsrcul1l4 204 205.Lmemmove_fsrcul1loop4: 206#ifdef __ARMEB__ 207 mov r12, lr, lsl #8 208#else 209 mov r12, lr, lsr #8 210#endif 211 ldr lr, [r1], #4 212#ifdef __ARMEB__ 213 orr r12, r12, lr, lsr #24 214#else 215 orr r12, r12, lr, lsl #24 216#endif 217 str r12, [r0], #4 218 subs r2, r2, #4 219 bge .Lmemmove_fsrcul1loop4 220 221.Lmemmove_fsrcul1l4: 222 sub r1, r1, #3 223 b .Lmemmove_fl4 224 225.Lmemmove_fsrcul2: 226 cmp r2, #0x0c 227 blt .Lmemmove_fsrcul2loop4 228 sub r2, r2, #0x0c 229 stmdb sp!, {r4, r5} 230 231.Lmemmove_fsrcul2loop16: 232#ifdef __ARMEB__ 233 mov r3, lr, lsl #16 234#else 235 mov r3, lr, lsr #16 236#endif 237 ldmia r1!, {r4, r5, r12, lr} 238#ifdef __ARMEB__ 239 orr r3, r3, r4, lsr #16 240 mov r4, r4, lsl #16 241 orr r4, r4, r5, lsr #16 242 mov r5, r5, lsl #16 243 orr r5, r5, r12, lsr #16 244 mov r12, r12, lsl #16 245 orr r12, r12, lr, lsr #16 246#else 247 orr r3, r3, r4, lsl #16 248 mov r4, r4, lsr #16 249 orr r4, r4, r5, lsl #16 250 mov r5, r5, lsr #16 251 orr r5, r5, r12, lsl #16 252 mov r12, r12, lsr #16 253 orr r12, r12, lr, lsl #16 254#endif 255 stmia r0!, {r3-r5, r12} 256 subs r2, r2, #0x10 257 bge .Lmemmove_fsrcul2loop16 258 ldmia sp!, {r4, r5} 259 adds r2, r2, #0x0c 260 blt .Lmemmove_fsrcul2l4 261 262.Lmemmove_fsrcul2loop4: 263#ifdef __ARMEB__ 264 mov r12, lr, lsl #16 265#else 266 mov r12, lr, lsr #16 267#endif 268 ldr lr, [r1], #4 269#ifdef __ARMEB__ 270 orr r12, r12, lr, lsr #16 271#else 272 orr r12, r12, lr, lsl #16 273#endif 274 str r12, [r0], #4 275 subs r2, r2, #4 276 bge .Lmemmove_fsrcul2loop4 277 278.Lmemmove_fsrcul2l4: 279 sub r1, r1, #2 280 b .Lmemmove_fl4 281 282.Lmemmove_fsrcul3: 283 cmp r2, #0x0c 284 blt .Lmemmove_fsrcul3loop4 285 sub r2, r2, #0x0c 286 stmdb sp!, {r4, r5} 287 288.Lmemmove_fsrcul3loop16: 289#ifdef __ARMEB__ 290 mov r3, lr, lsl #24 291#else 292 mov r3, lr, lsr #24 293#endif 294 ldmia r1!, {r4, r5, r12, lr} 295#ifdef __ARMEB__ 296 orr r3, r3, r4, lsr #8 297 mov r4, r4, lsl #24 298 orr r4, r4, r5, lsr #8 299 mov r5, r5, lsl #24 300 orr r5, r5, r12, lsr #8 301 mov r12, r12, lsl #24 302 orr r12, r12, lr, lsr #8 303#else 304 orr r3, r3, r4, lsl #8 305 mov r4, r4, lsr #24 306 orr r4, r4, r5, lsl #8 307 mov r5, r5, lsr #24 308 orr r5, r5, r12, lsl #8 309 mov r12, r12, lsr #24 310 orr r12, r12, lr, lsl #8 311#endif 312 stmia r0!, {r3-r5, r12} 313 subs r2, r2, #0x10 314 bge .Lmemmove_fsrcul3loop16 315 ldmia sp!, {r4, r5} 316 adds r2, r2, #0x0c 317 blt .Lmemmove_fsrcul3l4 318 319.Lmemmove_fsrcul3loop4: 320#ifdef __ARMEB__ 321 mov r12, lr, lsl #24 322#else 323 mov r12, lr, lsr #24 324#endif 325 ldr lr, [r1], #4 326#ifdef __ARMEB__ 327 orr r12, r12, lr, lsr #8 328#else 329 orr r12, r12, lr, lsl #8 330#endif 331 str r12, [r0], #4 332 subs r2, r2, #4 333 bge .Lmemmove_fsrcul3loop4 334 335.Lmemmove_fsrcul3l4: 336 sub r1, r1, #1 337 b .Lmemmove_fl4 338 339.Lmemmove_backwards: 340 add r1, r1, r2 341 add r0, r0, r2 342 subs r2, r2, #4 343 blt .Lmemmove_bl4 /* less than 4 bytes */ 344 ands r12, r0, #3 345 bne .Lmemmove_bdestul /* oh unaligned destination addr */ 346 ands r12, r1, #3 347 bne .Lmemmove_bsrcul /* oh unaligned source addr */ 348 349.Lmemmove_bt8: 350 /* We have aligned source and destination */ 351 subs r2, r2, #8 352 blt .Lmemmove_bl12 /* less than 12 bytes (4 from above) */ 353 stmdb sp!, {r4, lr} 354 subs r2, r2, #0x14 /* less than 32 bytes (12 from above) */ 355 blt .Lmemmove_bl32 356 357 /* blat 32 bytes at a time */ 358 /* XXX for really big copies perhaps we should use more registers */ 359.Lmemmove_bloop32: 360 ldmdb r1!, {r3, r4, r12, lr} 361 stmdb r0!, {r3, r4, r12, lr} 362 ldmdb r1!, {r3, r4, r12, lr} 363 stmdb r0!, {r3, r4, r12, lr} 364 subs r2, r2, #0x20 365 bge .Lmemmove_bloop32 366 367.Lmemmove_bl32: 368 cmn r2, #0x10 369 ittt ge 370 ldmdbge r1!, {r3, r4, r12, lr} /* blat a remaining 16 bytes */ 371 stmdbge r0!, {r3, r4, r12, lr} 372 subge r2, r2, #0x10 373 adds r2, r2, #0x14 374 ittt ge 375 ldmdbge r1!, {r3, r12, lr} /* blat a remaining 12 bytes */ 376 stmdbge r0!, {r3, r12, lr} 377 subge r2, r2, #0x0c 378 ldmia sp!, {r4, lr} 379 380.Lmemmove_bl12: 381 adds r2, r2, #8 382 blt .Lmemmove_bl4 383 subs r2, r2, #4 384 itt lt 385 ldrlt r3, [r1, #-4]! 386 strlt r3, [r0, #-4]! 387 ittt ge 388 ldmdbge r1!, {r3, r12} 389 stmdbge r0!, {r3, r12} 390 subge r2, r2, #4 391 392.Lmemmove_bl4: 393 /* less than 4 bytes to go */ 394 adds r2, r2, #4 395 it eq 396 RETeq /* done */ 397 398 /* copy the crud byte at a time */ 399 cmp r2, #2 400 ldrb r3, [r1, #-1]! 401 strb r3, [r0, #-1]! 402 itt ge 403 ldrbge r3, [r1, #-1]! 404 strbge r3, [r0, #-1]! 405 itt gt 406 ldrbgt r3, [r1, #-1]! 407 strbgt r3, [r0, #-1]! 408 RET 409 410 /* erg - unaligned destination */ 411.Lmemmove_bdestul: 412 cmp r12, #2 413 414 /* align destination with byte copies */ 415 ldrb r3, [r1, #-1]! 416 strb r3, [r0, #-1]! 417 itt ge 418 ldrbge r3, [r1, #-1]! 419 strbge r3, [r0, #-1]! 420 itt gt 421 ldrbgt r3, [r1, #-1]! 422 strbgt r3, [r0, #-1]! 423 subs r2, r2, r12 424 blt .Lmemmove_bl4 /* less than 4 bytes to go */ 425 ands r12, r1, #3 426 beq .Lmemmove_bt8 /* we have an aligned source */ 427 428 /* erg - unaligned source */ 429 /* This is where it gets nasty ... */ 430.Lmemmove_bsrcul: 431 bic r1, r1, #3 432 ldr r3, [r1, #0] 433 cmp r12, #2 434 blt .Lmemmove_bsrcul1 435 beq .Lmemmove_bsrcul2 436 cmp r2, #0x0c 437 blt .Lmemmove_bsrcul3loop4 438 sub r2, r2, #0x0c 439 stmdb sp!, {r4, r5, lr} 440 441.Lmemmove_bsrcul3loop16: 442#ifdef __ARMEB__ 443 mov lr, r3, lsr #8 444#else 445 mov lr, r3, lsl #8 446#endif 447 ldmdb r1!, {r3-r5, r12} 448#ifdef __ARMEB__ 449 orr lr, lr, r12, lsl #24 450 mov r12, r12, lsr #8 451 orr r12, r12, r5, lsl #24 452 mov r5, r5, lsr #8 453 orr r5, r5, r4, lsl #24 454 mov r4, r4, lsr #8 455 orr r4, r4, r3, lsl #24 456#else 457 orr lr, lr, r12, lsr #24 458 mov r12, r12, lsl #8 459 orr r12, r12, r5, lsr #24 460 mov r5, r5, lsl #8 461 orr r5, r5, r4, lsr #24 462 mov r4, r4, lsl #8 463 orr r4, r4, r3, lsr #24 464#endif 465 stmdb r0!, {r4, r5, r12, lr} 466 subs r2, r2, #0x10 467 bge .Lmemmove_bsrcul3loop16 468 ldmia sp!, {r4, r5, lr} 469 adds r2, r2, #0x0c 470 blt .Lmemmove_bsrcul3l4 471 472.Lmemmove_bsrcul3loop4: 473#ifdef __ARMEB__ 474 mov r12, r3, lsr #8 475#else 476 mov r12, r3, lsl #8 477#endif 478 ldr r3, [r1, #-4]! 479#ifdef __ARMEB__ 480 orr r12, r12, r3, lsl #24 481#else 482 orr r12, r12, r3, lsr #24 483#endif 484 str r12, [r0, #-4]! 485 subs r2, r2, #4 486 bge .Lmemmove_bsrcul3loop4 487 488.Lmemmove_bsrcul3l4: 489 add r1, r1, #3 490 b .Lmemmove_bl4 491 492.Lmemmove_bsrcul2: 493 cmp r2, #0x0c 494 blt .Lmemmove_bsrcul2loop4 495 sub r2, r2, #0x0c 496 stmdb sp!, {r4, r5, lr} 497 498.Lmemmove_bsrcul2loop16: 499#ifdef __ARMEB__ 500 mov lr, r3, lsr #16 501#else 502 mov lr, r3, lsl #16 503#endif 504 ldmdb r1!, {r3-r5, r12} 505#ifdef __ARMEB__ 506 orr lr, lr, r12, lsl #16 507 mov r12, r12, lsr #16 508 orr r12, r12, r5, lsl #16 509 mov r5, r5, lsr #16 510 orr r5, r5, r4, lsl #16 511 mov r4, r4, lsr #16 512 orr r4, r4, r3, lsl #16 513#else 514 orr lr, lr, r12, lsr #16 515 mov r12, r12, lsl #16 516 orr r12, r12, r5, lsr #16 517 mov r5, r5, lsl #16 518 orr r5, r5, r4, lsr #16 519 mov r4, r4, lsl #16 520 orr r4, r4, r3, lsr #16 521#endif 522 stmdb r0!, {r4, r5, r12, lr} 523 subs r2, r2, #0x10 524 bge .Lmemmove_bsrcul2loop16 525 ldmia sp!, {r4, r5, lr} 526 adds r2, r2, #0x0c 527 blt .Lmemmove_bsrcul2l4 528 529.Lmemmove_bsrcul2loop4: 530#ifdef __ARMEB__ 531 mov r12, r3, lsr #16 532#else 533 mov r12, r3, lsl #16 534#endif 535 ldr r3, [r1, #-4]! 536#ifdef __ARMEB__ 537 orr r12, r12, r3, lsl #16 538#else 539 orr r12, r12, r3, lsr #16 540#endif 541 str r12, [r0, #-4]! 542 subs r2, r2, #4 543 bge .Lmemmove_bsrcul2loop4 544 545.Lmemmove_bsrcul2l4: 546 add r1, r1, #2 547 b .Lmemmove_bl4 548 549.Lmemmove_bsrcul1: 550 cmp r2, #0x0c 551 blt .Lmemmove_bsrcul1loop4 552 sub r2, r2, #0x0c 553 stmdb sp!, {r4, r5, lr} 554 555.Lmemmove_bsrcul1loop32: 556#ifdef __ARMEB__ 557 mov lr, r3, lsr #24 558#else 559 mov lr, r3, lsl #24 560#endif 561 ldmdb r1!, {r3-r5, r12} 562#ifdef __ARMEB__ 563 orr lr, lr, r12, lsl #8 564 mov r12, r12, lsr #24 565 orr r12, r12, r5, lsl #8 566 mov r5, r5, lsr #24 567 orr r5, r5, r4, lsl #8 568 mov r4, r4, lsr #24 569 orr r4, r4, r3, lsl #8 570#else 571 orr lr, lr, r12, lsr #8 572 mov r12, r12, lsl #24 573 orr r12, r12, r5, lsr #8 574 mov r5, r5, lsl #24 575 orr r5, r5, r4, lsr #8 576 mov r4, r4, lsl #24 577 orr r4, r4, r3, lsr #8 578#endif 579 stmdb r0!, {r4, r5, r12, lr} 580 subs r2, r2, #0x10 581 bge .Lmemmove_bsrcul1loop32 582 ldmia sp!, {r4, r5, lr} 583 adds r2, r2, #0x0c 584 blt .Lmemmove_bsrcul1l4 585 586.Lmemmove_bsrcul1loop4: 587#ifdef __ARMEB__ 588 mov r12, r3, lsr #24 589#else 590 mov r12, r3, lsl #24 591#endif 592 ldr r3, [r1, #-4]! 593#ifdef __ARMEB__ 594 orr r12, r12, r3, lsl #8 595#else 596 orr r12, r12, r3, lsr #8 597#endif 598 str r12, [r0, #-4]! 599 subs r2, r2, #4 600 bge .Lmemmove_bsrcul1loop4 601 602.Lmemmove_bsrcul1l4: 603 add r1, r1, #1 604 b .Lmemmove_bl4 605#ifndef _BCOPY 606END(memmove) 607#else 608END(bcopy) 609#endif 610 611 .section .note.GNU-stack,"",%progbits 612