1d8834a13SMatthias Weisser/* 2d8834a13SMatthias Weisser * linux/arch/arm/lib/memcpy.S 3d8834a13SMatthias Weisser * 4d8834a13SMatthias Weisser * Author: Nicolas Pitre 5d8834a13SMatthias Weisser * Created: Sep 28, 2005 6d8834a13SMatthias Weisser * Copyright: MontaVista Software, Inc. 7d8834a13SMatthias Weisser * 8d8834a13SMatthias Weisser * This program is free software; you can redistribute it and/or modify 9d8834a13SMatthias Weisser * it under the terms of the GNU General Public License version 2 as 10d8834a13SMatthias Weisser * published by the Free Software Foundation. 11d8834a13SMatthias Weisser */ 12d8834a13SMatthias Weisser 13*75d7a0d7SStefan Agner#include <linux/linkage.h> 14d8834a13SMatthias Weisser#include <asm/assembler.h> 15d8834a13SMatthias Weisser 16*75d7a0d7SStefan Agner#ifdef CONFIG_SYS_THUMB_BUILD 17*75d7a0d7SStefan Agner#define W(instr) instr.w 18*75d7a0d7SStefan Agner#else 19d8834a13SMatthias Weisser#define W(instr) instr 20*75d7a0d7SStefan Agner#endif 21d8834a13SMatthias Weisser 22d8834a13SMatthias Weisser#define LDR1W_SHIFT 0 23d8834a13SMatthias Weisser#define STR1W_SHIFT 0 24d8834a13SMatthias Weisser 25d8834a13SMatthias Weisser .macro ldr1w ptr reg abort 26d8834a13SMatthias Weisser W(ldr) \reg, [\ptr], #4 27d8834a13SMatthias Weisser .endm 28d8834a13SMatthias Weisser 29d8834a13SMatthias Weisser .macro ldr4w ptr reg1 reg2 reg3 reg4 abort 30d8834a13SMatthias Weisser ldmia \ptr!, {\reg1, \reg2, \reg3, \reg4} 31d8834a13SMatthias Weisser .endm 32d8834a13SMatthias Weisser 33d8834a13SMatthias Weisser .macro ldr8w ptr reg1 reg2 reg3 reg4 reg5 reg6 reg7 reg8 abort 34d8834a13SMatthias Weisser ldmia \ptr!, {\reg1, \reg2, \reg3, \reg4, \reg5, \reg6, \reg7, \reg8} 35d8834a13SMatthias Weisser .endm 36d8834a13SMatthias Weisser 37d8834a13SMatthias Weisser .macro ldr1b ptr reg cond=al abort 38*75d7a0d7SStefan Agner ldrb\cond\() \reg, [\ptr], #1 39d8834a13SMatthias Weisser .endm 40d8834a13SMatthias Weisser 41d8834a13SMatthias Weisser .macro str1w ptr reg abort 42d8834a13SMatthias Weisser W(str) \reg, [\ptr], #4 43d8834a13SMatthias Weisser .endm 44d8834a13SMatthias Weisser 45d8834a13SMatthias Weisser .macro str8w ptr reg1 reg2 reg3 reg4 reg5 reg6 reg7 reg8 abort 46d8834a13SMatthias Weisser stmia \ptr!, {\reg1, \reg2, \reg3, \reg4, \reg5, \reg6, \reg7, \reg8} 47d8834a13SMatthias Weisser .endm 48d8834a13SMatthias Weisser 49d8834a13SMatthias Weisser .macro str1b ptr reg cond=al abort 50*75d7a0d7SStefan Agner strb\cond\() \reg, [\ptr], #1 51d8834a13SMatthias Weisser .endm 52d8834a13SMatthias Weisser 53d8834a13SMatthias Weisser .macro enter reg1 reg2 54d8834a13SMatthias Weisser stmdb sp!, {r0, \reg1, \reg2} 55d8834a13SMatthias Weisser .endm 56d8834a13SMatthias Weisser 57d8834a13SMatthias Weisser .macro exit reg1 reg2 58d8834a13SMatthias Weisser ldmfd sp!, {r0, \reg1, \reg2} 59d8834a13SMatthias Weisser .endm 60d8834a13SMatthias Weisser 61d8834a13SMatthias Weisser .text 62d8834a13SMatthias Weisser 63d8834a13SMatthias Weisser/* Prototype: void *memcpy(void *dest, const void *src, size_t n); */ 64*75d7a0d7SStefan Agner .syntax unified 65*75d7a0d7SStefan Agner#ifdef CONFIG_SYS_THUMB_BUILD 66*75d7a0d7SStefan Agner .thumb 67*75d7a0d7SStefan Agner .thumb_func 68*75d7a0d7SStefan Agner#endif 69*75d7a0d7SStefan AgnerENTRY(memcpy) 7034fe8281SMatthias Weisser cmp r0, r1 7134fe8281SMatthias Weisser moveq pc, lr 7234fe8281SMatthias Weisser 73d8834a13SMatthias Weisser enter r4, lr 74d8834a13SMatthias Weisser 75d8834a13SMatthias Weisser subs r2, r2, #4 76d8834a13SMatthias Weisser blt 8f 77d8834a13SMatthias Weisser ands ip, r0, #3 78d8834a13SMatthias Weisser PLD( pld [r1, #0] ) 79d8834a13SMatthias Weisser bne 9f 80d8834a13SMatthias Weisser ands ip, r1, #3 81d8834a13SMatthias Weisser bne 10f 82d8834a13SMatthias Weisser 83d8834a13SMatthias Weisser1: subs r2, r2, #(28) 84d8834a13SMatthias Weisser stmfd sp!, {r5 - r8} 85d8834a13SMatthias Weisser blt 5f 86d8834a13SMatthias Weisser 87d8834a13SMatthias Weisser CALGN( ands ip, r0, #31 ) 88d8834a13SMatthias Weisser CALGN( rsb r3, ip, #32 ) 89*75d7a0d7SStefan Agner CALGN( sbcsne r4, r3, r2 ) @ C is always set here 90d8834a13SMatthias Weisser CALGN( bcs 2f ) 91d8834a13SMatthias Weisser CALGN( adr r4, 6f ) 92d8834a13SMatthias Weisser CALGN( subs r2, r2, r3 ) @ C gets set 93d8834a13SMatthias Weisser CALGN( add pc, r4, ip ) 94d8834a13SMatthias Weisser 95d8834a13SMatthias Weisser PLD( pld [r1, #0] ) 96d8834a13SMatthias Weisser2: PLD( subs r2, r2, #96 ) 97d8834a13SMatthias Weisser PLD( pld [r1, #28] ) 98d8834a13SMatthias Weisser PLD( blt 4f ) 99d8834a13SMatthias Weisser PLD( pld [r1, #60] ) 100d8834a13SMatthias Weisser PLD( pld [r1, #92] ) 101d8834a13SMatthias Weisser 102d8834a13SMatthias Weisser3: PLD( pld [r1, #124] ) 103d8834a13SMatthias Weisser4: ldr8w r1, r3, r4, r5, r6, r7, r8, ip, lr, abort=20f 104d8834a13SMatthias Weisser subs r2, r2, #32 105d8834a13SMatthias Weisser str8w r0, r3, r4, r5, r6, r7, r8, ip, lr, abort=20f 106d8834a13SMatthias Weisser bge 3b 107d8834a13SMatthias Weisser PLD( cmn r2, #96 ) 108d8834a13SMatthias Weisser PLD( bge 4b ) 109d8834a13SMatthias Weisser 110d8834a13SMatthias Weisser5: ands ip, r2, #28 111d8834a13SMatthias Weisser rsb ip, ip, #32 112d8834a13SMatthias Weisser#if LDR1W_SHIFT > 0 113d8834a13SMatthias Weisser lsl ip, ip, #LDR1W_SHIFT 114d8834a13SMatthias Weisser#endif 115d8834a13SMatthias Weisser addne pc, pc, ip @ C is always clear here 116d8834a13SMatthias Weisser b 7f 117d8834a13SMatthias Weisser6: 118d8834a13SMatthias Weisser .rept (1 << LDR1W_SHIFT) 119d8834a13SMatthias Weisser W(nop) 120d8834a13SMatthias Weisser .endr 121d8834a13SMatthias Weisser ldr1w r1, r3, abort=20f 122d8834a13SMatthias Weisser ldr1w r1, r4, abort=20f 123d8834a13SMatthias Weisser ldr1w r1, r5, abort=20f 124d8834a13SMatthias Weisser ldr1w r1, r6, abort=20f 125d8834a13SMatthias Weisser ldr1w r1, r7, abort=20f 126d8834a13SMatthias Weisser ldr1w r1, r8, abort=20f 127d8834a13SMatthias Weisser ldr1w r1, lr, abort=20f 128d8834a13SMatthias Weisser 129d8834a13SMatthias Weisser#if LDR1W_SHIFT < STR1W_SHIFT 130d8834a13SMatthias Weisser lsl ip, ip, #STR1W_SHIFT - LDR1W_SHIFT 131d8834a13SMatthias Weisser#elif LDR1W_SHIFT > STR1W_SHIFT 132d8834a13SMatthias Weisser lsr ip, ip, #LDR1W_SHIFT - STR1W_SHIFT 133d8834a13SMatthias Weisser#endif 134d8834a13SMatthias Weisser add pc, pc, ip 135d8834a13SMatthias Weisser nop 136d8834a13SMatthias Weisser .rept (1 << STR1W_SHIFT) 137d8834a13SMatthias Weisser W(nop) 138d8834a13SMatthias Weisser .endr 139d8834a13SMatthias Weisser str1w r0, r3, abort=20f 140d8834a13SMatthias Weisser str1w r0, r4, abort=20f 141d8834a13SMatthias Weisser str1w r0, r5, abort=20f 142d8834a13SMatthias Weisser str1w r0, r6, abort=20f 143d8834a13SMatthias Weisser str1w r0, r7, abort=20f 144d8834a13SMatthias Weisser str1w r0, r8, abort=20f 145d8834a13SMatthias Weisser str1w r0, lr, abort=20f 146d8834a13SMatthias Weisser 147d8834a13SMatthias Weisser CALGN( bcs 2b ) 148d8834a13SMatthias Weisser 149d8834a13SMatthias Weisser7: ldmfd sp!, {r5 - r8} 150d8834a13SMatthias Weisser 151d8834a13SMatthias Weisser8: movs r2, r2, lsl #31 152d8834a13SMatthias Weisser ldr1b r1, r3, ne, abort=21f 153d8834a13SMatthias Weisser ldr1b r1, r4, cs, abort=21f 154d8834a13SMatthias Weisser ldr1b r1, ip, cs, abort=21f 155d8834a13SMatthias Weisser str1b r0, r3, ne, abort=21f 156d8834a13SMatthias Weisser str1b r0, r4, cs, abort=21f 157d8834a13SMatthias Weisser str1b r0, ip, cs, abort=21f 158d8834a13SMatthias Weisser 159d8834a13SMatthias Weisser exit r4, pc 160d8834a13SMatthias Weisser 161d8834a13SMatthias Weisser9: rsb ip, ip, #4 162d8834a13SMatthias Weisser cmp ip, #2 163d8834a13SMatthias Weisser ldr1b r1, r3, gt, abort=21f 164d8834a13SMatthias Weisser ldr1b r1, r4, ge, abort=21f 165d8834a13SMatthias Weisser ldr1b r1, lr, abort=21f 166d8834a13SMatthias Weisser str1b r0, r3, gt, abort=21f 167d8834a13SMatthias Weisser str1b r0, r4, ge, abort=21f 168d8834a13SMatthias Weisser subs r2, r2, ip 169d8834a13SMatthias Weisser str1b r0, lr, abort=21f 170d8834a13SMatthias Weisser blt 8b 171d8834a13SMatthias Weisser ands ip, r1, #3 172d8834a13SMatthias Weisser beq 1b 173d8834a13SMatthias Weisser 174d8834a13SMatthias Weisser10: bic r1, r1, #3 175d8834a13SMatthias Weisser cmp ip, #2 176d8834a13SMatthias Weisser ldr1w r1, lr, abort=21f 177d8834a13SMatthias Weisser beq 17f 178d8834a13SMatthias Weisser bgt 18f 179d8834a13SMatthias Weisser 180d8834a13SMatthias Weisser 181d8834a13SMatthias Weisser .macro forward_copy_shift pull push 182d8834a13SMatthias Weisser 183d8834a13SMatthias Weisser subs r2, r2, #28 184d8834a13SMatthias Weisser blt 14f 185d8834a13SMatthias Weisser 186d8834a13SMatthias Weisser CALGN( ands ip, r0, #31 ) 187d8834a13SMatthias Weisser CALGN( rsb ip, ip, #32 ) 188*75d7a0d7SStefan Agner CALGN( sbcsne r4, ip, r2 ) @ C is always set here 189d8834a13SMatthias Weisser CALGN( subcc r2, r2, ip ) 190d8834a13SMatthias Weisser CALGN( bcc 15f ) 191d8834a13SMatthias Weisser 192d8834a13SMatthias Weisser11: stmfd sp!, {r5 - r9} 193d8834a13SMatthias Weisser 194d8834a13SMatthias Weisser PLD( pld [r1, #0] ) 195d8834a13SMatthias Weisser PLD( subs r2, r2, #96 ) 196d8834a13SMatthias Weisser PLD( pld [r1, #28] ) 197d8834a13SMatthias Weisser PLD( blt 13f ) 198d8834a13SMatthias Weisser PLD( pld [r1, #60] ) 199d8834a13SMatthias Weisser PLD( pld [r1, #92] ) 200d8834a13SMatthias Weisser 201d8834a13SMatthias Weisser12: PLD( pld [r1, #124] ) 202d8834a13SMatthias Weisser13: ldr4w r1, r4, r5, r6, r7, abort=19f 203*75d7a0d7SStefan Agner mov r3, lr, lspull #\pull 204d8834a13SMatthias Weisser subs r2, r2, #32 205d8834a13SMatthias Weisser ldr4w r1, r8, r9, ip, lr, abort=19f 206*75d7a0d7SStefan Agner orr r3, r3, r4, lspush #\push 207*75d7a0d7SStefan Agner mov r4, r4, lspull #\pull 208*75d7a0d7SStefan Agner orr r4, r4, r5, lspush #\push 209*75d7a0d7SStefan Agner mov r5, r5, lspull #\pull 210*75d7a0d7SStefan Agner orr r5, r5, r6, lspush #\push 211*75d7a0d7SStefan Agner mov r6, r6, lspull #\pull 212*75d7a0d7SStefan Agner orr r6, r6, r7, lspush #\push 213*75d7a0d7SStefan Agner mov r7, r7, lspull #\pull 214*75d7a0d7SStefan Agner orr r7, r7, r8, lspush #\push 215*75d7a0d7SStefan Agner mov r8, r8, lspull #\pull 216*75d7a0d7SStefan Agner orr r8, r8, r9, lspush #\push 217*75d7a0d7SStefan Agner mov r9, r9, lspull #\pull 218*75d7a0d7SStefan Agner orr r9, r9, ip, lspush #\push 219*75d7a0d7SStefan Agner mov ip, ip, lspull #\pull 220*75d7a0d7SStefan Agner orr ip, ip, lr, lspush #\push 221d8834a13SMatthias Weisser str8w r0, r3, r4, r5, r6, r7, r8, r9, ip, , abort=19f 222d8834a13SMatthias Weisser bge 12b 223d8834a13SMatthias Weisser PLD( cmn r2, #96 ) 224d8834a13SMatthias Weisser PLD( bge 13b ) 225d8834a13SMatthias Weisser 226d8834a13SMatthias Weisser ldmfd sp!, {r5 - r9} 227d8834a13SMatthias Weisser 228d8834a13SMatthias Weisser14: ands ip, r2, #28 229d8834a13SMatthias Weisser beq 16f 230d8834a13SMatthias Weisser 231*75d7a0d7SStefan Agner15: mov r3, lr, lspull #\pull 232d8834a13SMatthias Weisser ldr1w r1, lr, abort=21f 233d8834a13SMatthias Weisser subs ip, ip, #4 234*75d7a0d7SStefan Agner orr r3, r3, lr, lspush #\push 235d8834a13SMatthias Weisser str1w r0, r3, abort=21f 236d8834a13SMatthias Weisser bgt 15b 237d8834a13SMatthias Weisser CALGN( cmp r2, #0 ) 238d8834a13SMatthias Weisser CALGN( bge 11b ) 239d8834a13SMatthias Weisser 240d8834a13SMatthias Weisser16: sub r1, r1, #(\push / 8) 241d8834a13SMatthias Weisser b 8b 242d8834a13SMatthias Weisser 243d8834a13SMatthias Weisser .endm 244d8834a13SMatthias Weisser 245d8834a13SMatthias Weisser 246d8834a13SMatthias Weisser forward_copy_shift pull=8 push=24 247d8834a13SMatthias Weisser 248d8834a13SMatthias Weisser17: forward_copy_shift pull=16 push=16 249d8834a13SMatthias Weisser 250d8834a13SMatthias Weisser18: forward_copy_shift pull=24 push=8 251*75d7a0d7SStefan Agner 252*75d7a0d7SStefan Agner 253*75d7a0d7SStefan Agner/* 254*75d7a0d7SStefan Agner * Abort preamble and completion macros. 255*75d7a0d7SStefan Agner * If a fixup handler is required then those macros must surround it. 256*75d7a0d7SStefan Agner * It is assumed that the fixup code will handle the private part of 257*75d7a0d7SStefan Agner * the exit macro. 258*75d7a0d7SStefan Agner */ 259*75d7a0d7SStefan Agner 260*75d7a0d7SStefan Agner .macro copy_abort_preamble 261*75d7a0d7SStefan Agner19: ldmfd sp!, {r5 - r9} 262*75d7a0d7SStefan Agner b 21f 263*75d7a0d7SStefan Agner20: ldmfd sp!, {r5 - r8} 264*75d7a0d7SStefan Agner21: 265*75d7a0d7SStefan Agner .endm 266*75d7a0d7SStefan Agner 267*75d7a0d7SStefan Agner .macro copy_abort_end 268*75d7a0d7SStefan Agner ldmfd sp!, {r4, pc} 269*75d7a0d7SStefan Agner .endm 270*75d7a0d7SStefan Agner 271*75d7a0d7SStefan AgnerENDPROC(memcpy) 272