1/* 2 * linux/arch/arm/lib/memcpy.S 3 * 4 * Author: Nicolas Pitre 5 * Created: Sep 28, 2005 6 * Copyright: MontaVista Software, Inc. 7 * 8 * This program is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License version 2 as 10 * published by the Free Software Foundation. 11 */ 12 13#include <asm/assembler.h> 14 15#define W(instr) instr 16 17#define LDR1W_SHIFT 0 18#define STR1W_SHIFT 0 19 20 .macro ldr1w ptr reg abort 21 W(ldr) \reg, [\ptr], #4 22 .endm 23 24 .macro ldr4w ptr reg1 reg2 reg3 reg4 abort 25 ldmia \ptr!, {\reg1, \reg2, \reg3, \reg4} 26 .endm 27 28 .macro ldr8w ptr reg1 reg2 reg3 reg4 reg5 reg6 reg7 reg8 abort 29 ldmia \ptr!, {\reg1, \reg2, \reg3, \reg4, \reg5, \reg6, \reg7, \reg8} 30 .endm 31 32 .macro ldr1b ptr reg cond=al abort 33 ldr\cond\()b \reg, [\ptr], #1 34 .endm 35 36 .macro str1w ptr reg abort 37 W(str) \reg, [\ptr], #4 38 .endm 39 40 .macro str8w ptr reg1 reg2 reg3 reg4 reg5 reg6 reg7 reg8 abort 41 stmia \ptr!, {\reg1, \reg2, \reg3, \reg4, \reg5, \reg6, \reg7, \reg8} 42 .endm 43 44 .macro str1b ptr reg cond=al abort 45 str\cond\()b \reg, [\ptr], #1 46 .endm 47 48 .macro enter reg1 reg2 49 stmdb sp!, {r0, \reg1, \reg2} 50 .endm 51 52 .macro exit reg1 reg2 53 ldmfd sp!, {r0, \reg1, \reg2} 54 .endm 55 56 .text 57 58/* Prototype: void *memcpy(void *dest, const void *src, size_t n); */ 59 60.globl memcpy 61memcpy: 62 63 cmp r0, r1 64 moveq pc, lr 65 66 enter r4, lr 67 68 subs r2, r2, #4 69 blt 8f 70 ands ip, r0, #3 71 PLD( pld [r1, #0] ) 72 bne 9f 73 ands ip, r1, #3 74 bne 10f 75 761: subs r2, r2, #(28) 77 stmfd sp!, {r5 - r8} 78 blt 5f 79 80 CALGN( ands ip, r0, #31 ) 81 CALGN( rsb r3, ip, #32 ) 82 CALGN( sbcnes r4, r3, r2 ) @ C is always set here 83 CALGN( bcs 2f ) 84 CALGN( adr r4, 6f ) 85 CALGN( subs r2, r2, r3 ) @ C gets set 86 CALGN( add pc, r4, ip ) 87 88 PLD( pld [r1, #0] ) 892: PLD( subs r2, r2, #96 ) 90 PLD( pld [r1, #28] ) 91 PLD( blt 4f ) 92 PLD( pld [r1, #60] ) 93 PLD( pld [r1, #92] ) 94 953: PLD( pld [r1, #124] ) 964: ldr8w r1, r3, r4, r5, r6, r7, r8, ip, lr, abort=20f 97 subs r2, r2, #32 98 str8w r0, r3, r4, r5, r6, r7, r8, ip, lr, abort=20f 99 bge 3b 100 PLD( cmn r2, #96 ) 101 PLD( bge 4b ) 102 1035: ands ip, r2, #28 104 rsb ip, ip, #32 105#if LDR1W_SHIFT > 0 106 lsl ip, ip, #LDR1W_SHIFT 107#endif 108 addne pc, pc, ip @ C is always clear here 109 b 7f 1106: 111 .rept (1 << LDR1W_SHIFT) 112 W(nop) 113 .endr 114 ldr1w r1, r3, abort=20f 115 ldr1w r1, r4, abort=20f 116 ldr1w r1, r5, abort=20f 117 ldr1w r1, r6, abort=20f 118 ldr1w r1, r7, abort=20f 119 ldr1w r1, r8, abort=20f 120 ldr1w r1, lr, abort=20f 121 122#if LDR1W_SHIFT < STR1W_SHIFT 123 lsl ip, ip, #STR1W_SHIFT - LDR1W_SHIFT 124#elif LDR1W_SHIFT > STR1W_SHIFT 125 lsr ip, ip, #LDR1W_SHIFT - STR1W_SHIFT 126#endif 127 add pc, pc, ip 128 nop 129 .rept (1 << STR1W_SHIFT) 130 W(nop) 131 .endr 132 str1w r0, r3, abort=20f 133 str1w r0, r4, abort=20f 134 str1w r0, r5, abort=20f 135 str1w r0, r6, abort=20f 136 str1w r0, r7, abort=20f 137 str1w r0, r8, abort=20f 138 str1w r0, lr, abort=20f 139 140 CALGN( bcs 2b ) 141 1427: ldmfd sp!, {r5 - r8} 143 1448: movs r2, r2, lsl #31 145 ldr1b r1, r3, ne, abort=21f 146 ldr1b r1, r4, cs, abort=21f 147 ldr1b r1, ip, cs, abort=21f 148 str1b r0, r3, ne, abort=21f 149 str1b r0, r4, cs, abort=21f 150 str1b r0, ip, cs, abort=21f 151 152 exit r4, pc 153 1549: rsb ip, ip, #4 155 cmp ip, #2 156 ldr1b r1, r3, gt, abort=21f 157 ldr1b r1, r4, ge, abort=21f 158 ldr1b r1, lr, abort=21f 159 str1b r0, r3, gt, abort=21f 160 str1b r0, r4, ge, abort=21f 161 subs r2, r2, ip 162 str1b r0, lr, abort=21f 163 blt 8b 164 ands ip, r1, #3 165 beq 1b 166 16710: bic r1, r1, #3 168 cmp ip, #2 169 ldr1w r1, lr, abort=21f 170 beq 17f 171 bgt 18f 172 173 174 .macro forward_copy_shift pull push 175 176 subs r2, r2, #28 177 blt 14f 178 179 CALGN( ands ip, r0, #31 ) 180 CALGN( rsb ip, ip, #32 ) 181 CALGN( sbcnes r4, ip, r2 ) @ C is always set here 182 CALGN( subcc r2, r2, ip ) 183 CALGN( bcc 15f ) 184 18511: stmfd sp!, {r5 - r9} 186 187 PLD( pld [r1, #0] ) 188 PLD( subs r2, r2, #96 ) 189 PLD( pld [r1, #28] ) 190 PLD( blt 13f ) 191 PLD( pld [r1, #60] ) 192 PLD( pld [r1, #92] ) 193 19412: PLD( pld [r1, #124] ) 19513: ldr4w r1, r4, r5, r6, r7, abort=19f 196 mov r3, lr, pull #\pull 197 subs r2, r2, #32 198 ldr4w r1, r8, r9, ip, lr, abort=19f 199 orr r3, r3, r4, push #\push 200 mov r4, r4, pull #\pull 201 orr r4, r4, r5, push #\push 202 mov r5, r5, pull #\pull 203 orr r5, r5, r6, push #\push 204 mov r6, r6, pull #\pull 205 orr r6, r6, r7, push #\push 206 mov r7, r7, pull #\pull 207 orr r7, r7, r8, push #\push 208 mov r8, r8, pull #\pull 209 orr r8, r8, r9, push #\push 210 mov r9, r9, pull #\pull 211 orr r9, r9, ip, push #\push 212 mov ip, ip, pull #\pull 213 orr ip, ip, lr, push #\push 214 str8w r0, r3, r4, r5, r6, r7, r8, r9, ip, , abort=19f 215 bge 12b 216 PLD( cmn r2, #96 ) 217 PLD( bge 13b ) 218 219 ldmfd sp!, {r5 - r9} 220 22114: ands ip, r2, #28 222 beq 16f 223 22415: mov r3, lr, pull #\pull 225 ldr1w r1, lr, abort=21f 226 subs ip, ip, #4 227 orr r3, r3, lr, push #\push 228 str1w r0, r3, abort=21f 229 bgt 15b 230 CALGN( cmp r2, #0 ) 231 CALGN( bge 11b ) 232 23316: sub r1, r1, #(\push / 8) 234 b 8b 235 236 .endm 237 238 239 forward_copy_shift pull=8 push=24 240 24117: forward_copy_shift pull=16 push=16 242 24318: forward_copy_shift pull=24 push=8 244