1129198Scognet/* $NetBSD: bcopyinout_xscale.S,v 1.3 2003/12/15 09:27:18 scw Exp $ */ 2129198Scognet 3139735Simp/*- 4129198Scognet * Copyright 2003 Wasabi Systems, Inc. 5129198Scognet * All rights reserved. 6129198Scognet * 7129198Scognet * Written by Steve C. Woodford for Wasabi Systems, Inc. 8129198Scognet * 9129198Scognet * Redistribution and use in source and binary forms, with or without 10129198Scognet * modification, are permitted provided that the following conditions 11129198Scognet * are met: 12129198Scognet * 1. Redistributions of source code must retain the above copyright 13129198Scognet * notice, this list of conditions and the following disclaimer. 14129198Scognet * 2. Redistributions in binary form must reproduce the above copyright 15129198Scognet * notice, this list of conditions and the following disclaimer in the 16129198Scognet * documentation and/or other materials provided with the distribution. 17129198Scognet * 3. All advertising materials mentioning features or use of this software 18129198Scognet * must display the following acknowledgement: 19129198Scognet * This product includes software developed for the NetBSD Project by 20129198Scognet * Wasabi Systems, Inc. 21129198Scognet * 4. The name of Wasabi Systems, Inc. may not be used to endorse 22129198Scognet * or promote products derived from this software without specific prior 23129198Scognet * written permission. 24129198Scognet * 25129198Scognet * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND 26129198Scognet * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 27129198Scognet * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 28129198Scognet * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC 29129198Scognet * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 30129198Scognet * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 31129198Scognet * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 32129198Scognet * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 33129198Scognet * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 34129198Scognet * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 35129198Scognet * POSSIBILITY OF SUCH DAMAGE. 36129198Scognet */ 37129198Scognet 38129198Scognet#include <machine/asm.h> 39129198Scognet__FBSDID("$FreeBSD$"); 40129198Scognet 41275418Sandrew .syntax unified 42129198Scognet .text 43276596Sian .align 2 44129198Scognet 45284264Sandrew#if __ARM_ARCH >= 6 46239268Sgonzo#define GET_PCB(tmp) \ 47239268Sgonzo mrc p15, 0, tmp, c13, c0, 4; \ 48261415Scognet add tmp, tmp, #(TD_PCB) 49129198Scognet#else 50129198Scognet.Lcurpcb: 51129198Scognet .word _C_LABEL(__pcpu) + PC_CURPCB 52239268Sgonzo#define GET_PCB(tmp) \ 53239268Sgonzo ldr tmp, .Lcurpcb 54129198Scognet#endif 55129198Scognet 56129198Scognet/* 57129198Scognet * r0 = user space address 58129198Scognet * r1 = kernel space address 59129198Scognet * r2 = length 60129198Scognet * 61129198Scognet * Copies bytes from user space to kernel space 62129198Scognet */ 63129198ScognetENTRY(copyin) 64129198Scognet cmp r2, #0x00 65129198Scognet movle r0, #0x00 66129198Scognet movle pc, lr /* Bail early if length is <= 0 */ 67129198Scognet 68289372Skib adds r3, r0, r2 69289372Skib movcs r0, #EFAULT 70289372Skib RETc(cs) 71289372Skib 72289372Skib ldr r12, =(VM_MAXUSER_ADDRESS + 1) 73289372Skib cmp r3, r12 74289372Skib movcs r0, #EFAULT 75289372Skib RETc(cs) 76289372Skib 77150864Scognet ldr r3, .L_arm_memcpy 78150864Scognet ldr r3, [r3] 79150864Scognet cmp r3, #0 80150864Scognet beq .Lnormal 81150864Scognet ldr r3, .L_min_memcpy_size 82150864Scognet ldr r3, [r3] 83150864Scognet cmp r2, r3 84150864Scognet blt .Lnormal 85150864Scognet stmfd sp!, {r0-r2, r4, lr} 86150864Scognet mov r3, r0 87150864Scognet mov r0, r1 88150864Scognet mov r1, r3 89150864Scognet mov r3, #2 /* SRC_IS_USER */ 90150864Scognet ldr r4, .L_arm_memcpy 91150864Scognet mov lr, pc 92150864Scognet ldr pc, [r4] 93150864Scognet cmp r0, #0 94150864Scognet ldmfd sp!, {r0-r2, r4, lr} 95150864Scognet moveq r0, #0 96150864Scognet RETeq 97283366Sandrew 98150864Scognet.Lnormal: 99129198Scognet stmfd sp!, {r10-r11, lr} 100129198Scognet 101239268Sgonzo GET_PCB(r10) 102129198Scognet ldr r10, [r10] 103129198Scognet 104129198Scognet mov r3, #0x00 105129198Scognet adr ip, .Lcopyin_fault 106129198Scognet ldr r11, [r10, #PCB_ONFAULT] 107129198Scognet str ip, [r10, #PCB_ONFAULT] 108129198Scognet bl .Lcopyin_guts 109129198Scognet str r11, [r10, #PCB_ONFAULT] 110129198Scognet mov r0, #0x00 111129198Scognet ldmfd sp!, {r10-r11, pc} 112129198Scognet 113129198Scognet.Lcopyin_fault: 114239033Sandrew ldr r0, =EFAULT 115129198Scognet str r11, [r10, #PCB_ONFAULT] 116129198Scognet cmp r3, #0x00 117275418Sandrew ldmfdgt sp!, {r4-r7} /* r3 > 0 Restore r4-r7 */ 118275418Sandrew ldmfdlt sp!, {r4-r9} /* r3 < 0 Restore r4-r9 */ 119129198Scognet ldmfd sp!, {r10-r11, pc} 120129198Scognet 121129198Scognet.Lcopyin_guts: 122129198Scognet pld [r0] 123129198Scognet /* Word-align the destination buffer */ 124129198Scognet ands ip, r1, #0x03 /* Already word aligned? */ 125129198Scognet beq .Lcopyin_wordaligned /* Yup */ 126129198Scognet rsb ip, ip, #0x04 127129198Scognet cmp r2, ip /* Enough bytes left to align it? */ 128129198Scognet blt .Lcopyin_l4_2 /* Nope. Just copy bytewise */ 129129198Scognet sub r2, r2, ip 130129198Scognet rsbs ip, ip, #0x03 131129198Scognet addne pc, pc, ip, lsl #3 132129198Scognet nop 133129198Scognet ldrbt ip, [r0], #0x01 134129198Scognet strb ip, [r1], #0x01 135129198Scognet ldrbt ip, [r0], #0x01 136129198Scognet strb ip, [r1], #0x01 137129198Scognet ldrbt ip, [r0], #0x01 138129198Scognet strb ip, [r1], #0x01 139129198Scognet cmp r2, #0x00 /* All done? */ 140137463Scognet RETeq 141129198Scognet 142129198Scognet /* Destination buffer is now word aligned */ 143129198Scognet.Lcopyin_wordaligned: 144129198Scognet ands ip, r0, #0x03 /* Is src also word-aligned? */ 145129198Scognet bne .Lcopyin_bad_align /* Nope. Things just got bad */ 146129198Scognet cmp r2, #0x08 /* Less than 8 bytes remaining? */ 147129198Scognet blt .Lcopyin_w_less_than8 148129198Scognet 149129198Scognet /* Quad-align the destination buffer */ 150129198Scognet tst r1, #0x07 /* Already quad aligned? */ 151275418Sandrew ldrtne ip, [r0], #0x04 152153273Scognet strne ip, [r1], #0x04 153153273Scognet subne r2, r2, #0x04 154129198Scognet stmfd sp!, {r4-r9} /* Free up some registers */ 155129198Scognet mov r3, #-1 /* Signal restore r4-r9 */ 156129198Scognet 157129198Scognet /* Destination buffer quad aligned, source is word aligned */ 158129198Scognet subs r2, r2, #0x80 159129198Scognet blt .Lcopyin_w_lessthan128 160129198Scognet 161129198Scognet /* Copy 128 bytes at a time */ 162129198Scognet.Lcopyin_w_loop128: 163129198Scognet ldrt r4, [r0], #0x04 /* LD:00-03 */ 164129198Scognet ldrt r5, [r0], #0x04 /* LD:04-07 */ 165129198Scognet pld [r0, #0x18] /* Prefetch 0x20 */ 166129198Scognet ldrt r6, [r0], #0x04 /* LD:08-0b */ 167129198Scognet ldrt r7, [r0], #0x04 /* LD:0c-0f */ 168129198Scognet ldrt r8, [r0], #0x04 /* LD:10-13 */ 169129198Scognet ldrt r9, [r0], #0x04 /* LD:14-17 */ 170129198Scognet strd r4, [r1], #0x08 /* ST:00-07 */ 171129198Scognet ldrt r4, [r0], #0x04 /* LD:18-1b */ 172129198Scognet ldrt r5, [r0], #0x04 /* LD:1c-1f */ 173129198Scognet strd r6, [r1], #0x08 /* ST:08-0f */ 174129198Scognet ldrt r6, [r0], #0x04 /* LD:20-23 */ 175129198Scognet ldrt r7, [r0], #0x04 /* LD:24-27 */ 176129198Scognet pld [r0, #0x18] /* Prefetch 0x40 */ 177129198Scognet strd r8, [r1], #0x08 /* ST:10-17 */ 178129198Scognet ldrt r8, [r0], #0x04 /* LD:28-2b */ 179129198Scognet ldrt r9, [r0], #0x04 /* LD:2c-2f */ 180129198Scognet strd r4, [r1], #0x08 /* ST:18-1f */ 181129198Scognet ldrt r4, [r0], #0x04 /* LD:30-33 */ 182129198Scognet ldrt r5, [r0], #0x04 /* LD:34-37 */ 183129198Scognet strd r6, [r1], #0x08 /* ST:20-27 */ 184129198Scognet ldrt r6, [r0], #0x04 /* LD:38-3b */ 185129198Scognet ldrt r7, [r0], #0x04 /* LD:3c-3f */ 186129198Scognet strd r8, [r1], #0x08 /* ST:28-2f */ 187129198Scognet ldrt r8, [r0], #0x04 /* LD:40-43 */ 188129198Scognet ldrt r9, [r0], #0x04 /* LD:44-47 */ 189129198Scognet pld [r0, #0x18] /* Prefetch 0x60 */ 190129198Scognet strd r4, [r1], #0x08 /* ST:30-37 */ 191129198Scognet ldrt r4, [r0], #0x04 /* LD:48-4b */ 192129198Scognet ldrt r5, [r0], #0x04 /* LD:4c-4f */ 193129198Scognet strd r6, [r1], #0x08 /* ST:38-3f */ 194129198Scognet ldrt r6, [r0], #0x04 /* LD:50-53 */ 195129198Scognet ldrt r7, [r0], #0x04 /* LD:54-57 */ 196129198Scognet strd r8, [r1], #0x08 /* ST:40-47 */ 197129198Scognet ldrt r8, [r0], #0x04 /* LD:58-5b */ 198129198Scognet ldrt r9, [r0], #0x04 /* LD:5c-5f */ 199129198Scognet strd r4, [r1], #0x08 /* ST:48-4f */ 200129198Scognet ldrt r4, [r0], #0x04 /* LD:60-63 */ 201129198Scognet ldrt r5, [r0], #0x04 /* LD:64-67 */ 202129198Scognet pld [r0, #0x18] /* Prefetch 0x80 */ 203129198Scognet strd r6, [r1], #0x08 /* ST:50-57 */ 204129198Scognet ldrt r6, [r0], #0x04 /* LD:68-6b */ 205129198Scognet ldrt r7, [r0], #0x04 /* LD:6c-6f */ 206129198Scognet strd r8, [r1], #0x08 /* ST:58-5f */ 207129198Scognet ldrt r8, [r0], #0x04 /* LD:70-73 */ 208129198Scognet ldrt r9, [r0], #0x04 /* LD:74-77 */ 209129198Scognet strd r4, [r1], #0x08 /* ST:60-67 */ 210129198Scognet ldrt r4, [r0], #0x04 /* LD:78-7b */ 211129198Scognet ldrt r5, [r0], #0x04 /* LD:7c-7f */ 212129198Scognet strd r6, [r1], #0x08 /* ST:68-6f */ 213129198Scognet strd r8, [r1], #0x08 /* ST:70-77 */ 214129198Scognet subs r2, r2, #0x80 215129198Scognet strd r4, [r1], #0x08 /* ST:78-7f */ 216129198Scognet bge .Lcopyin_w_loop128 217129198Scognet 218129198Scognet.Lcopyin_w_lessthan128: 219129198Scognet adds r2, r2, #0x80 /* Adjust for extra sub */ 220275418Sandrew ldmfdeq sp!, {r4-r9} 221137463Scognet RETeq 222129198Scognet subs r2, r2, #0x20 223129198Scognet blt .Lcopyin_w_lessthan32 224129198Scognet 225129198Scognet /* Copy 32 bytes at a time */ 226129198Scognet.Lcopyin_w_loop32: 227129198Scognet ldrt r4, [r0], #0x04 228129198Scognet ldrt r5, [r0], #0x04 229129198Scognet pld [r0, #0x18] 230129198Scognet ldrt r6, [r0], #0x04 231129198Scognet ldrt r7, [r0], #0x04 232129198Scognet ldrt r8, [r0], #0x04 233129198Scognet ldrt r9, [r0], #0x04 234129198Scognet strd r4, [r1], #0x08 235129198Scognet ldrt r4, [r0], #0x04 236129198Scognet ldrt r5, [r0], #0x04 237129198Scognet strd r6, [r1], #0x08 238129198Scognet strd r8, [r1], #0x08 239129198Scognet subs r2, r2, #0x20 240129198Scognet strd r4, [r1], #0x08 241129198Scognet bge .Lcopyin_w_loop32 242129198Scognet 243129198Scognet.Lcopyin_w_lessthan32: 244129198Scognet adds r2, r2, #0x20 /* Adjust for extra sub */ 245275418Sandrew ldmfdeq sp!, {r4-r9} 246137463Scognet RETeq /* Return now if done */ 247129198Scognet 248129198Scognet and r4, r2, #0x18 249129198Scognet rsb r5, r4, #0x18 250129198Scognet subs r2, r2, r4 251129198Scognet add pc, pc, r5, lsl #1 252129198Scognet nop 253129198Scognet 254129198Scognet /* At least 24 bytes remaining */ 255129198Scognet ldrt r4, [r0], #0x04 256129198Scognet ldrt r5, [r0], #0x04 257129198Scognet nop 258129198Scognet strd r4, [r1], #0x08 259129198Scognet 260129198Scognet /* At least 16 bytes remaining */ 261129198Scognet ldrt r4, [r0], #0x04 262129198Scognet ldrt r5, [r0], #0x04 263129198Scognet nop 264129198Scognet strd r4, [r1], #0x08 265129198Scognet 266129198Scognet /* At least 8 bytes remaining */ 267129198Scognet ldrt r4, [r0], #0x04 268129198Scognet ldrt r5, [r0], #0x04 269129198Scognet nop 270129198Scognet strd r4, [r1], #0x08 271129198Scognet 272129198Scognet /* Less than 8 bytes remaining */ 273129198Scognet ldmfd sp!, {r4-r9} 274137463Scognet RETeq /* Return now if done */ 275129198Scognet mov r3, #0x00 276129198Scognet 277129198Scognet.Lcopyin_w_less_than8: 278129198Scognet subs r2, r2, #0x04 279275418Sandrew ldrtge ip, [r0], #0x04 280129198Scognet strge ip, [r1], #0x04 281137463Scognet RETeq /* Return now if done */ 282129198Scognet addlt r2, r2, #0x04 283129198Scognet ldrbt ip, [r0], #0x01 284129198Scognet cmp r2, #0x02 285275418Sandrew ldrbtge r2, [r0], #0x01 286129198Scognet strb ip, [r1], #0x01 287275418Sandrew ldrbtgt ip, [r0] 288275418Sandrew strbge r2, [r1], #0x01 289275418Sandrew strbgt ip, [r1] 290137463Scognet RET 291129198Scognet 292129198Scognet/* 293129198Scognet * At this point, it has not been possible to word align both buffers. 294129198Scognet * The destination buffer (r1) is word aligned, but the source buffer 295129198Scognet * (r0) is not. 296129198Scognet */ 297129198Scognet.Lcopyin_bad_align: 298129198Scognet stmfd sp!, {r4-r7} 299129198Scognet mov r3, #0x01 300129198Scognet bic r0, r0, #0x03 301129198Scognet cmp ip, #2 302129198Scognet ldrt ip, [r0], #0x04 303129198Scognet bgt .Lcopyin_bad3 304129198Scognet beq .Lcopyin_bad2 305129198Scognet b .Lcopyin_bad1 306129198Scognet 307129198Scognet.Lcopyin_bad1_loop16: 308129198Scognet#ifdef __ARMEB__ 309129198Scognet mov r4, ip, lsl #8 310129198Scognet#else 311129198Scognet mov r4, ip, lsr #8 312129198Scognet#endif 313129198Scognet ldrt r5, [r0], #0x04 314129198Scognet pld [r0, #0x018] 315129198Scognet ldrt r6, [r0], #0x04 316129198Scognet ldrt r7, [r0], #0x04 317129198Scognet ldrt ip, [r0], #0x04 318129198Scognet#ifdef __ARMEB__ 319129198Scognet orr r4, r4, r5, lsr #24 320129198Scognet mov r5, r5, lsl #8 321129198Scognet orr r5, r5, r6, lsr #24 322129198Scognet mov r6, r6, lsl #8 323129198Scognet orr r6, r6, r7, lsr #24 324129198Scognet mov r7, r7, lsl #8 325129198Scognet orr r7, r7, ip, lsr #24 326129198Scognet#else 327129198Scognet orr r4, r4, r5, lsl #24 328129198Scognet mov r5, r5, lsr #8 329129198Scognet orr r5, r5, r6, lsl #24 330129198Scognet mov r6, r6, lsr #8 331129198Scognet orr r6, r6, r7, lsl #24 332129198Scognet mov r7, r7, lsr #8 333129198Scognet orr r7, r7, ip, lsl #24 334129198Scognet#endif 335129198Scognet str r4, [r1], #0x04 336129198Scognet str r5, [r1], #0x04 337129198Scognet str r6, [r1], #0x04 338129198Scognet str r7, [r1], #0x04 339129198Scognet.Lcopyin_bad1: 340236991Simp subs r2, r2, #0x10 341129198Scognet bge .Lcopyin_bad1_loop16 342129198Scognet 343236991Simp adds r2, r2, #0x10 344275418Sandrew ldmfdeq sp!, {r4-r7} 345137463Scognet RETeq /* Return now if done */ 346129198Scognet subs r2, r2, #0x04 347129198Scognet sublt r0, r0, #0x03 348129198Scognet blt .Lcopyin_l4 349129198Scognet 350129198Scognet.Lcopyin_bad1_loop4: 351129198Scognet#ifdef __ARMEB__ 352129198Scognet mov r4, ip, lsl #8 353129198Scognet#else 354129198Scognet mov r4, ip, lsr #8 355129198Scognet#endif 356129198Scognet ldrt ip, [r0], #0x04 357129198Scognet subs r2, r2, #0x04 358129198Scognet#ifdef __ARMEB__ 359129198Scognet orr r4, r4, ip, lsr #24 360129198Scognet#else 361129198Scognet orr r4, r4, ip, lsl #24 362129198Scognet#endif 363129198Scognet str r4, [r1], #0x04 364129198Scognet bge .Lcopyin_bad1_loop4 365129198Scognet sub r0, r0, #0x03 366129198Scognet b .Lcopyin_l4 367129198Scognet 368129198Scognet.Lcopyin_bad2_loop16: 369129198Scognet#ifdef __ARMEB__ 370129198Scognet mov r4, ip, lsl #16 371129198Scognet#else 372129198Scognet mov r4, ip, lsr #16 373129198Scognet#endif 374129198Scognet ldrt r5, [r0], #0x04 375129198Scognet pld [r0, #0x018] 376129198Scognet ldrt r6, [r0], #0x04 377129198Scognet ldrt r7, [r0], #0x04 378129198Scognet ldrt ip, [r0], #0x04 379129198Scognet#ifdef __ARMEB__ 380129198Scognet orr r4, r4, r5, lsr #16 381129198Scognet mov r5, r5, lsl #16 382129198Scognet orr r5, r5, r6, lsr #16 383129198Scognet mov r6, r6, lsl #16 384129198Scognet orr r6, r6, r7, lsr #16 385129198Scognet mov r7, r7, lsl #16 386129198Scognet orr r7, r7, ip, lsr #16 387129198Scognet#else 388129198Scognet orr r4, r4, r5, lsl #16 389129198Scognet mov r5, r5, lsr #16 390129198Scognet orr r5, r5, r6, lsl #16 391129198Scognet mov r6, r6, lsr #16 392129198Scognet orr r6, r6, r7, lsl #16 393129198Scognet mov r7, r7, lsr #16 394129198Scognet orr r7, r7, ip, lsl #16 395129198Scognet#endif 396129198Scognet str r4, [r1], #0x04 397129198Scognet str r5, [r1], #0x04 398129198Scognet str r6, [r1], #0x04 399129198Scognet str r7, [r1], #0x04 400129198Scognet.Lcopyin_bad2: 401236991Simp subs r2, r2, #0x10 402129198Scognet bge .Lcopyin_bad2_loop16 403129198Scognet 404236991Simp adds r2, r2, #0x10 405275418Sandrew ldmfdeq sp!, {r4-r7} 406137463Scognet RETeq /* Return now if done */ 407129198Scognet subs r2, r2, #0x04 408129198Scognet sublt r0, r0, #0x02 409129198Scognet blt .Lcopyin_l4 410129198Scognet 411129198Scognet.Lcopyin_bad2_loop4: 412129198Scognet#ifdef __ARMEB__ 413129198Scognet mov r4, ip, lsl #16 414129198Scognet#else 415129198Scognet mov r4, ip, lsr #16 416129198Scognet#endif 417129198Scognet ldrt ip, [r0], #0x04 418129198Scognet subs r2, r2, #0x04 419129198Scognet#ifdef __ARMEB__ 420129198Scognet orr r4, r4, ip, lsr #16 421129198Scognet#else 422129198Scognet orr r4, r4, ip, lsl #16 423129198Scognet#endif 424129198Scognet str r4, [r1], #0x04 425129198Scognet bge .Lcopyin_bad2_loop4 426129198Scognet sub r0, r0, #0x02 427129198Scognet b .Lcopyin_l4 428129198Scognet 429129198Scognet.Lcopyin_bad3_loop16: 430129198Scognet#ifdef __ARMEB__ 431129198Scognet mov r4, ip, lsl #24 432129198Scognet#else 433129198Scognet mov r4, ip, lsr #24 434129198Scognet#endif 435129198Scognet ldrt r5, [r0], #0x04 436129198Scognet pld [r0, #0x018] 437129198Scognet ldrt r6, [r0], #0x04 438129198Scognet ldrt r7, [r0], #0x04 439129198Scognet ldrt ip, [r0], #0x04 440129198Scognet#ifdef __ARMEB__ 441129198Scognet orr r4, r4, r5, lsr #8 442129198Scognet mov r5, r5, lsl #24 443129198Scognet orr r5, r5, r6, lsr #8 444129198Scognet mov r6, r6, lsl #24 445129198Scognet orr r6, r6, r7, lsr #8 446129198Scognet mov r7, r7, lsl #24 447129198Scognet orr r7, r7, ip, lsr #8 448129198Scognet#else 449129198Scognet orr r4, r4, r5, lsl #8 450129198Scognet mov r5, r5, lsr #24 451129198Scognet orr r5, r5, r6, lsl #8 452129198Scognet mov r6, r6, lsr #24 453129198Scognet orr r6, r6, r7, lsl #8 454129198Scognet mov r7, r7, lsr #24 455129198Scognet orr r7, r7, ip, lsl #8 456129198Scognet#endif 457129198Scognet str r4, [r1], #0x04 458129198Scognet str r5, [r1], #0x04 459129198Scognet str r6, [r1], #0x04 460129198Scognet str r7, [r1], #0x04 461129198Scognet.Lcopyin_bad3: 462236991Simp subs r2, r2, #0x10 463129198Scognet bge .Lcopyin_bad3_loop16 464129198Scognet 465236991Simp adds r2, r2, #0x10 466275418Sandrew ldmfdeq sp!, {r4-r7} 467137463Scognet RETeq /* Return now if done */ 468129198Scognet subs r2, r2, #0x04 469129198Scognet sublt r0, r0, #0x01 470129198Scognet blt .Lcopyin_l4 471129198Scognet 472129198Scognet.Lcopyin_bad3_loop4: 473129198Scognet#ifdef __ARMEB__ 474129198Scognet mov r4, ip, lsl #24 475129198Scognet#else 476129198Scognet mov r4, ip, lsr #24 477129198Scognet#endif 478129198Scognet ldrt ip, [r0], #0x04 479129198Scognet subs r2, r2, #0x04 480129198Scognet#ifdef __ARMEB__ 481129198Scognet orr r4, r4, ip, lsr #8 482129198Scognet#else 483129198Scognet orr r4, r4, ip, lsl #8 484129198Scognet#endif 485129198Scognet str r4, [r1], #0x04 486129198Scognet bge .Lcopyin_bad3_loop4 487129198Scognet sub r0, r0, #0x01 488129198Scognet 489129198Scognet.Lcopyin_l4: 490129198Scognet ldmfd sp!, {r4-r7} 491129198Scognet mov r3, #0x00 492129198Scognet adds r2, r2, #0x04 493137463Scognet RETeq 494129198Scognet.Lcopyin_l4_2: 495129198Scognet rsbs r2, r2, #0x03 496129198Scognet addne pc, pc, r2, lsl #3 497129198Scognet nop 498129198Scognet ldrbt ip, [r0], #0x01 499129198Scognet strb ip, [r1], #0x01 500129198Scognet ldrbt ip, [r0], #0x01 501129198Scognet strb ip, [r1], #0x01 502129198Scognet ldrbt ip, [r0] 503129198Scognet strb ip, [r1] 504137463Scognet RET 505248361SandrewEND(copyin) 506129198Scognet 507129198Scognet/* 508129198Scognet * r0 = kernel space address 509129198Scognet * r1 = user space address 510129198Scognet * r2 = length 511129198Scognet * 512129198Scognet * Copies bytes from kernel space to user space 513129198Scognet */ 514129198ScognetENTRY(copyout) 515129198Scognet cmp r2, #0x00 516129198Scognet movle r0, #0x00 517129198Scognet movle pc, lr /* Bail early if length is <= 0 */ 518129198Scognet 519289372Skib adds r3, r1, r2 520289372Skib movcs r0, #EFAULT 521289372Skib RETc(cs) 522289372Skib 523289372Skib ldr r12, =(VM_MAXUSER_ADDRESS + 1) 524289372Skib cmp r3, r12 525289372Skib movcs r0, #EFAULT 526289372Skib RETc(cs) 527289372Skib 528150864Scognet ldr r3, .L_arm_memcpy 529150864Scognet ldr r3, [r3] 530150864Scognet cmp r3, #0 531150864Scognet beq .Lnormale 532150864Scognet ldr r3, .L_min_memcpy_size 533150864Scognet ldr r3, [r3] 534150864Scognet cmp r2, r3 535150864Scognet blt .Lnormale 536150864Scognet stmfd sp!, {r0-r2, r4, lr} 537150864Scognet mov r3, r0 538150864Scognet mov r0, r1 539150864Scognet mov r1, r3 540150864Scognet mov r3, #1 /* DST_IS_USER */ 541150864Scognet ldr r4, .L_arm_memcpy 542150864Scognet mov lr, pc 543150864Scognet ldr pc, [r4] 544150864Scognet cmp r0, #0 545150864Scognet ldmfd sp!, {r0-r2, r4, lr} 546150864Scognet moveq r0, #0 547150864Scognet RETeq 548283366Sandrew 549283366Sandrew.Lnormale: 550129198Scognet stmfd sp!, {r10-r11, lr} 551129198Scognet 552239268Sgonzo GET_PCB(r10) 553129198Scognet ldr r10, [r10] 554129198Scognet 555129198Scognet mov r3, #0x00 556129198Scognet adr ip, .Lcopyout_fault 557129198Scognet ldr r11, [r10, #PCB_ONFAULT] 558129198Scognet str ip, [r10, #PCB_ONFAULT] 559129198Scognet bl .Lcopyout_guts 560129198Scognet str r11, [r10, #PCB_ONFAULT] 561129198Scognet mov r0, #0x00 562129198Scognet ldmfd sp!, {r10-r11, pc} 563129198Scognet 564129198Scognet.Lcopyout_fault: 565239033Sandrew ldr r0, =EFAULT 566129198Scognet str r11, [r10, #PCB_ONFAULT] 567129198Scognet cmp r3, #0x00 568275418Sandrew ldmfdgt sp!, {r4-r7} /* r3 > 0 Restore r4-r7 */ 569275418Sandrew ldmfdlt sp!, {r4-r9} /* r3 < 0 Restore r4-r9 */ 570129198Scognet ldmfd sp!, {r10-r11, pc} 571129198Scognet 572129198Scognet.Lcopyout_guts: 573129198Scognet pld [r0] 574129198Scognet /* Word-align the destination buffer */ 575129198Scognet ands ip, r1, #0x03 /* Already word aligned? */ 576129198Scognet beq .Lcopyout_wordaligned /* Yup */ 577129198Scognet rsb ip, ip, #0x04 578129198Scognet cmp r2, ip /* Enough bytes left to align it? */ 579129198Scognet blt .Lcopyout_l4_2 /* Nope. Just copy bytewise */ 580129198Scognet sub r2, r2, ip 581129198Scognet rsbs ip, ip, #0x03 582129198Scognet addne pc, pc, ip, lsl #3 583129198Scognet nop 584129198Scognet ldrb ip, [r0], #0x01 585129198Scognet strbt ip, [r1], #0x01 586129198Scognet ldrb ip, [r0], #0x01 587129198Scognet strbt ip, [r1], #0x01 588129198Scognet ldrb ip, [r0], #0x01 589129198Scognet strbt ip, [r1], #0x01 590129198Scognet cmp r2, #0x00 /* All done? */ 591137463Scognet RETeq 592129198Scognet 593129198Scognet /* Destination buffer is now word aligned */ 594129198Scognet.Lcopyout_wordaligned: 595129198Scognet ands ip, r0, #0x03 /* Is src also word-aligned? */ 596129198Scognet bne .Lcopyout_bad_align /* Nope. Things just got bad */ 597129198Scognet cmp r2, #0x08 /* Less than 8 bytes remaining? */ 598129198Scognet blt .Lcopyout_w_less_than8 599129198Scognet 600129198Scognet /* Quad-align the destination buffer */ 601153273Scognet tst r0, #0x07 /* Already quad aligned? */ 602129198Scognet ldrne ip, [r0], #0x04 603153273Scognet subne r2, r2, #0x04 604275418Sandrew strtne ip, [r1], #0x04 605283366Sandrew 606129198Scognet stmfd sp!, {r4-r9} /* Free up some registers */ 607129198Scognet mov r3, #-1 /* Signal restore r4-r9 */ 608129198Scognet 609153273Scognet /* Destination buffer word aligned, source is quad aligned */ 610129198Scognet subs r2, r2, #0x80 611129198Scognet blt .Lcopyout_w_lessthan128 612129198Scognet 613129198Scognet /* Copy 128 bytes at a time */ 614129198Scognet.Lcopyout_w_loop128: 615153273Scognet ldrd r4, [r0], #0x08 /* LD:00-07 */ 616129198Scognet pld [r0, #0x18] /* Prefetch 0x20 */ 617153273Scognet ldrd r6, [r0], #0x08 /* LD:08-0f */ 618153273Scognet ldrd r8, [r0], #0x08 /* LD:10-17 */ 619129198Scognet strt r4, [r1], #0x04 /* ST:00-03 */ 620129198Scognet strt r5, [r1], #0x04 /* ST:04-07 */ 621153273Scognet ldrd r4, [r0], #0x08 /* LD:18-1f */ 622129198Scognet strt r6, [r1], #0x04 /* ST:08-0b */ 623129198Scognet strt r7, [r1], #0x04 /* ST:0c-0f */ 624153273Scognet ldrd r6, [r0], #0x08 /* LD:20-27 */ 625129198Scognet pld [r0, #0x18] /* Prefetch 0x40 */ 626129198Scognet strt r8, [r1], #0x04 /* ST:10-13 */ 627129198Scognet strt r9, [r1], #0x04 /* ST:14-17 */ 628153273Scognet ldrd r8, [r0], #0x08 /* LD:28-2f */ 629129198Scognet strt r4, [r1], #0x04 /* ST:18-1b */ 630129198Scognet strt r5, [r1], #0x04 /* ST:1c-1f */ 631153273Scognet ldrd r4, [r0], #0x08 /* LD:30-37 */ 632129198Scognet strt r6, [r1], #0x04 /* ST:20-23 */ 633129198Scognet strt r7, [r1], #0x04 /* ST:24-27 */ 634153273Scognet ldrd r6, [r0], #0x08 /* LD:38-3f */ 635129198Scognet strt r8, [r1], #0x04 /* ST:28-2b */ 636129198Scognet strt r9, [r1], #0x04 /* ST:2c-2f */ 637153273Scognet ldrd r8, [r0], #0x08 /* LD:40-47 */ 638129198Scognet pld [r0, #0x18] /* Prefetch 0x60 */ 639129198Scognet strt r4, [r1], #0x04 /* ST:30-33 */ 640129198Scognet strt r5, [r1], #0x04 /* ST:34-37 */ 641153273Scognet ldrd r4, [r0], #0x08 /* LD:48-4f */ 642129198Scognet strt r6, [r1], #0x04 /* ST:38-3b */ 643129198Scognet strt r7, [r1], #0x04 /* ST:3c-3f */ 644153273Scognet ldrd r6, [r0], #0x08 /* LD:50-57 */ 645129198Scognet strt r8, [r1], #0x04 /* ST:40-43 */ 646129198Scognet strt r9, [r1], #0x04 /* ST:44-47 */ 647153273Scognet ldrd r8, [r0], #0x08 /* LD:58-4f */ 648129198Scognet strt r4, [r1], #0x04 /* ST:48-4b */ 649129198Scognet strt r5, [r1], #0x04 /* ST:4c-4f */ 650153273Scognet ldrd r4, [r0], #0x08 /* LD:60-67 */ 651129198Scognet pld [r0, #0x18] /* Prefetch 0x80 */ 652129198Scognet strt r6, [r1], #0x04 /* ST:50-53 */ 653129198Scognet strt r7, [r1], #0x04 /* ST:54-57 */ 654153273Scognet ldrd r6, [r0], #0x08 /* LD:68-6f */ 655129198Scognet strt r8, [r1], #0x04 /* ST:58-5b */ 656129198Scognet strt r9, [r1], #0x04 /* ST:5c-5f */ 657153273Scognet ldrd r8, [r0], #0x08 /* LD:70-77 */ 658129198Scognet strt r4, [r1], #0x04 /* ST:60-63 */ 659129198Scognet strt r5, [r1], #0x04 /* ST:64-67 */ 660153273Scognet ldrd r4, [r0], #0x08 /* LD:78-7f */ 661129198Scognet strt r6, [r1], #0x04 /* ST:68-6b */ 662129198Scognet strt r7, [r1], #0x04 /* ST:6c-6f */ 663129198Scognet strt r8, [r1], #0x04 /* ST:70-73 */ 664129198Scognet strt r9, [r1], #0x04 /* ST:74-77 */ 665129198Scognet subs r2, r2, #0x80 666129198Scognet strt r4, [r1], #0x04 /* ST:78-7b */ 667129198Scognet strt r5, [r1], #0x04 /* ST:7c-7f */ 668129198Scognet bge .Lcopyout_w_loop128 669129198Scognet 670129198Scognet.Lcopyout_w_lessthan128: 671129198Scognet adds r2, r2, #0x80 /* Adjust for extra sub */ 672275418Sandrew ldmfdeq sp!, {r4-r9} 673137463Scognet RETeq /* Return now if done */ 674129198Scognet subs r2, r2, #0x20 675129198Scognet blt .Lcopyout_w_lessthan32 676129198Scognet 677129198Scognet /* Copy 32 bytes at a time */ 678129198Scognet.Lcopyout_w_loop32: 679153273Scognet ldrd r4, [r0], #0x08 680129198Scognet pld [r0, #0x18] 681153273Scognet ldrd r6, [r0], #0x08 682153273Scognet ldrd r8, [r0], #0x08 683129198Scognet strt r4, [r1], #0x04 684129198Scognet strt r5, [r1], #0x04 685153273Scognet ldrd r4, [r0], #0x08 686129198Scognet strt r6, [r1], #0x04 687129198Scognet strt r7, [r1], #0x04 688129198Scognet strt r8, [r1], #0x04 689129198Scognet strt r9, [r1], #0x04 690129198Scognet subs r2, r2, #0x20 691129198Scognet strt r4, [r1], #0x04 692129198Scognet strt r5, [r1], #0x04 693129198Scognet bge .Lcopyout_w_loop32 694129198Scognet 695129198Scognet.Lcopyout_w_lessthan32: 696129198Scognet adds r2, r2, #0x20 /* Adjust for extra sub */ 697275418Sandrew ldmfdeq sp!, {r4-r9} 698137463Scognet RETeq /* Return now if done */ 699129198Scognet 700129198Scognet and r4, r2, #0x18 701129198Scognet rsb r5, r4, #0x18 702129198Scognet subs r2, r2, r4 703129198Scognet add pc, pc, r5, lsl #1 704129198Scognet nop 705129198Scognet 706129198Scognet /* At least 24 bytes remaining */ 707153273Scognet ldrd r4, [r0], #0x08 708129198Scognet strt r4, [r1], #0x04 709129198Scognet strt r5, [r1], #0x04 710153273Scognet nop 711129198Scognet 712129198Scognet /* At least 16 bytes remaining */ 713153273Scognet ldrd r4, [r0], #0x08 714129198Scognet strt r4, [r1], #0x04 715129198Scognet strt r5, [r1], #0x04 716153273Scognet nop 717129198Scognet 718129198Scognet /* At least 8 bytes remaining */ 719153273Scognet ldrd r4, [r0], #0x08 720129198Scognet strt r4, [r1], #0x04 721129198Scognet strt r5, [r1], #0x04 722153273Scognet nop 723129198Scognet 724129198Scognet /* Less than 8 bytes remaining */ 725129198Scognet ldmfd sp!, {r4-r9} 726137463Scognet RETeq /* Return now if done */ 727129198Scognet mov r3, #0x00 728129198Scognet 729129198Scognet.Lcopyout_w_less_than8: 730129198Scognet subs r2, r2, #0x04 731129198Scognet ldrge ip, [r0], #0x04 732275418Sandrew strtge ip, [r1], #0x04 733137463Scognet RETeq /* Return now if done */ 734129198Scognet addlt r2, r2, #0x04 735129198Scognet ldrb ip, [r0], #0x01 736129198Scognet cmp r2, #0x02 737275418Sandrew ldrbge r2, [r0], #0x01 738129198Scognet strbt ip, [r1], #0x01 739275418Sandrew ldrbgt ip, [r0] 740275418Sandrew strbtge r2, [r1], #0x01 741275418Sandrew strbtgt ip, [r1] 742137463Scognet RET 743129198Scognet 744129198Scognet/* 745129198Scognet * At this point, it has not been possible to word align both buffers. 746129198Scognet * The destination buffer (r1) is word aligned, but the source buffer 747129198Scognet * (r0) is not. 748129198Scognet */ 749129198Scognet.Lcopyout_bad_align: 750129198Scognet stmfd sp!, {r4-r7} 751129198Scognet mov r3, #0x01 752129198Scognet bic r0, r0, #0x03 753129198Scognet cmp ip, #2 754129198Scognet ldr ip, [r0], #0x04 755129198Scognet bgt .Lcopyout_bad3 756129198Scognet beq .Lcopyout_bad2 757129198Scognet b .Lcopyout_bad1 758129198Scognet 759129198Scognet.Lcopyout_bad1_loop16: 760129198Scognet#ifdef __ARMEB__ 761129198Scognet mov r4, ip, lsl #8 762129198Scognet#else 763129198Scognet mov r4, ip, lsr #8 764129198Scognet#endif 765129198Scognet ldr r5, [r0], #0x04 766129198Scognet pld [r0, #0x018] 767129198Scognet ldr r6, [r0], #0x04 768129198Scognet ldr r7, [r0], #0x04 769129198Scognet ldr ip, [r0], #0x04 770129198Scognet#ifdef __ARMEB__ 771129198Scognet orr r4, r4, r5, lsr #24 772129198Scognet mov r5, r5, lsl #8 773129198Scognet orr r5, r5, r6, lsr #24 774129198Scognet mov r6, r6, lsl #8 775129198Scognet orr r6, r6, r7, lsr #24 776129198Scognet mov r7, r7, lsl #8 777129198Scognet orr r7, r7, ip, lsr #24 778129198Scognet#else 779129198Scognet orr r4, r4, r5, lsl #24 780129198Scognet mov r5, r5, lsr #8 781129198Scognet orr r5, r5, r6, lsl #24 782129198Scognet mov r6, r6, lsr #8 783129198Scognet orr r6, r6, r7, lsl #24 784129198Scognet mov r7, r7, lsr #8 785129198Scognet orr r7, r7, ip, lsl #24 786129198Scognet#endif 787129198Scognet strt r4, [r1], #0x04 788129198Scognet strt r5, [r1], #0x04 789129198Scognet strt r6, [r1], #0x04 790129198Scognet strt r7, [r1], #0x04 791129198Scognet.Lcopyout_bad1: 792236991Simp subs r2, r2, #0x10 793129198Scognet bge .Lcopyout_bad1_loop16 794129198Scognet 795236991Simp adds r2, r2, #0x10 796275418Sandrew ldmfdeq sp!, {r4-r7} 797137463Scognet RETeq /* Return now if done */ 798129198Scognet subs r2, r2, #0x04 799129198Scognet sublt r0, r0, #0x03 800129198Scognet blt .Lcopyout_l4 801129198Scognet 802129198Scognet.Lcopyout_bad1_loop4: 803129198Scognet#ifdef __ARMEB__ 804129198Scognet mov r4, ip, lsl #8 805129198Scognet#else 806129198Scognet mov r4, ip, lsr #8 807129198Scognet#endif 808129198Scognet ldr ip, [r0], #0x04 809129198Scognet subs r2, r2, #0x04 810129198Scognet#ifdef __ARMEB__ 811129198Scognet orr r4, r4, ip, lsr #24 812129198Scognet#else 813129198Scognet orr r4, r4, ip, lsl #24 814129198Scognet#endif 815129198Scognet strt r4, [r1], #0x04 816129198Scognet bge .Lcopyout_bad1_loop4 817129198Scognet sub r0, r0, #0x03 818129198Scognet b .Lcopyout_l4 819129198Scognet 820129198Scognet.Lcopyout_bad2_loop16: 821129198Scognet#ifdef __ARMEB__ 822129198Scognet mov r4, ip, lsl #16 823129198Scognet#else 824129198Scognet mov r4, ip, lsr #16 825129198Scognet#endif 826129198Scognet ldr r5, [r0], #0x04 827129198Scognet pld [r0, #0x018] 828129198Scognet ldr r6, [r0], #0x04 829129198Scognet ldr r7, [r0], #0x04 830129198Scognet ldr ip, [r0], #0x04 831129198Scognet#ifdef __ARMEB__ 832129198Scognet orr r4, r4, r5, lsr #16 833129198Scognet mov r5, r5, lsl #16 834129198Scognet orr r5, r5, r6, lsr #16 835129198Scognet mov r6, r6, lsl #16 836129198Scognet orr r6, r6, r7, lsr #16 837129198Scognet mov r7, r7, lsl #16 838129198Scognet orr r7, r7, ip, lsr #16 839129198Scognet#else 840129198Scognet orr r4, r4, r5, lsl #16 841129198Scognet mov r5, r5, lsr #16 842129198Scognet orr r5, r5, r6, lsl #16 843129198Scognet mov r6, r6, lsr #16 844129198Scognet orr r6, r6, r7, lsl #16 845129198Scognet mov r7, r7, lsr #16 846129198Scognet orr r7, r7, ip, lsl #16 847129198Scognet#endif 848129198Scognet strt r4, [r1], #0x04 849129198Scognet strt r5, [r1], #0x04 850129198Scognet strt r6, [r1], #0x04 851129198Scognet strt r7, [r1], #0x04 852129198Scognet.Lcopyout_bad2: 853236991Simp subs r2, r2, #0x10 854129198Scognet bge .Lcopyout_bad2_loop16 855129198Scognet 856236991Simp adds r2, r2, #0x10 857275418Sandrew ldmfdeq sp!, {r4-r7} 858137463Scognet RETeq /* Return now if done */ 859129198Scognet subs r2, r2, #0x04 860129198Scognet sublt r0, r0, #0x02 861129198Scognet blt .Lcopyout_l4 862129198Scognet 863129198Scognet.Lcopyout_bad2_loop4: 864129198Scognet#ifdef __ARMEB__ 865129198Scognet mov r4, ip, lsl #16 866129198Scognet#else 867129198Scognet mov r4, ip, lsr #16 868129198Scognet#endif 869129198Scognet ldr ip, [r0], #0x04 870129198Scognet subs r2, r2, #0x04 871129198Scognet#ifdef __ARMEB__ 872129198Scognet orr r4, r4, ip, lsr #16 873129198Scognet#else 874129198Scognet orr r4, r4, ip, lsl #16 875129198Scognet#endif 876129198Scognet strt r4, [r1], #0x04 877129198Scognet bge .Lcopyout_bad2_loop4 878129198Scognet sub r0, r0, #0x02 879129198Scognet b .Lcopyout_l4 880129198Scognet 881129198Scognet.Lcopyout_bad3_loop16: 882129198Scognet#ifdef __ARMEB__ 883129198Scognet mov r4, ip, lsl #24 884129198Scognet#else 885129198Scognet mov r4, ip, lsr #24 886129198Scognet#endif 887129198Scognet ldr r5, [r0], #0x04 888129198Scognet pld [r0, #0x018] 889129198Scognet ldr r6, [r0], #0x04 890129198Scognet ldr r7, [r0], #0x04 891129198Scognet ldr ip, [r0], #0x04 892129198Scognet#ifdef __ARMEB__ 893129198Scognet orr r4, r4, r5, lsr #8 894129198Scognet mov r5, r5, lsl #24 895129198Scognet orr r5, r5, r6, lsr #8 896129198Scognet mov r6, r6, lsl #24 897129198Scognet orr r6, r6, r7, lsr #8 898129198Scognet mov r7, r7, lsl #24 899129198Scognet orr r7, r7, ip, lsr #8 900129198Scognet#else 901129198Scognet orr r4, r4, r5, lsl #8 902129198Scognet mov r5, r5, lsr #24 903129198Scognet orr r5, r5, r6, lsl #8 904129198Scognet mov r6, r6, lsr #24 905129198Scognet orr r6, r6, r7, lsl #8 906129198Scognet mov r7, r7, lsr #24 907129198Scognet orr r7, r7, ip, lsl #8 908129198Scognet#endif 909129198Scognet strt r4, [r1], #0x04 910129198Scognet strt r5, [r1], #0x04 911129198Scognet strt r6, [r1], #0x04 912129198Scognet strt r7, [r1], #0x04 913129198Scognet.Lcopyout_bad3: 914236991Simp subs r2, r2, #0x10 915129198Scognet bge .Lcopyout_bad3_loop16 916129198Scognet 917236991Simp adds r2, r2, #0x10 918275418Sandrew ldmfdeq sp!, {r4-r7} 919137463Scognet RETeq /* Return now if done */ 920129198Scognet subs r2, r2, #0x04 921129198Scognet sublt r0, r0, #0x01 922129198Scognet blt .Lcopyout_l4 923129198Scognet 924129198Scognet.Lcopyout_bad3_loop4: 925129198Scognet#ifdef __ARMEB__ 926129198Scognet mov r4, ip, lsl #24 927129198Scognet#else 928129198Scognet mov r4, ip, lsr #24 929129198Scognet#endif 930129198Scognet ldr ip, [r0], #0x04 931129198Scognet subs r2, r2, #0x04 932129198Scognet#ifdef __ARMEB__ 933129198Scognet orr r4, r4, ip, lsr #8 934129198Scognet#else 935129198Scognet orr r4, r4, ip, lsl #8 936129198Scognet#endif 937129198Scognet strt r4, [r1], #0x04 938129198Scognet bge .Lcopyout_bad3_loop4 939129198Scognet sub r0, r0, #0x01 940129198Scognet 941129198Scognet.Lcopyout_l4: 942129198Scognet ldmfd sp!, {r4-r7} 943129198Scognet mov r3, #0x00 944129198Scognet adds r2, r2, #0x04 945137463Scognet RETeq 946129198Scognet.Lcopyout_l4_2: 947129198Scognet rsbs r2, r2, #0x03 948129198Scognet addne pc, pc, r2, lsl #3 949129198Scognet nop 950129198Scognet ldrb ip, [r0], #0x01 951129198Scognet strbt ip, [r1], #0x01 952129198Scognet ldrb ip, [r0], #0x01 953129198Scognet strbt ip, [r1], #0x01 954129198Scognet ldrb ip, [r0] 955129198Scognet strbt ip, [r1] 956137463Scognet RET 957248361SandrewEND(copyout) 958248361Sandrew 959