1/* 2 * linux/arch/arm/lib/memmove.S 3 * 4 * Author: Nicolas Pitre 5 * Created: Sep 28, 2005 6 * Copyright: (C) 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 <linux/linkage.h> 14#include <asm/assembler.h> 15#include <asm/unwind.h> 16 17 .text 18 19/* 20 * Prototype: void *memmove(void *dest, const void *src, size_t n); 21 * 22 * Note: 23 * 24 * If the memory regions don't overlap, we simply branch to memcpy which is 25 * normally a bit faster. Otherwise the copy is done going downwards. This 26 * is a transposition of the code from copy_template.S but with the copy 27 * occurring in the opposite direction. 28 */ 29 30ENTRY(memmove) 31 UNWIND( .fnstart ) 32 33 subs ip, r0, r1 34 cmphi r2, ip 35 bls memcpy 36 37 stmfd sp!, {r0, r4, lr} 38 UNWIND( .fnend ) 39 40 UNWIND( .fnstart ) 41 UNWIND( .save {r0, r4, lr} ) @ in first stmfd block 42 add r1, r1, r2 43 add r0, r0, r2 44 subs r2, r2, #4 45 blt 8f 46 ands ip, r0, #3 47 PLD( pld [r1, #-4] ) 48 bne 9f 49 ands ip, r1, #3 50 bne 10f 51 521: subs r2, r2, #(28) 53 stmfd sp!, {r5 - r8} 54 UNWIND( .fnend ) 55 56 UNWIND( .fnstart ) 57 UNWIND( .save {r0, r4, lr} ) 58 UNWIND( .save {r5 - r8} ) @ in second stmfd block 59 blt 5f 60 61 CALGN( ands ip, r0, #31 ) 62 CALGN( sbcsne r4, ip, r2 ) @ C is always set here 63 CALGN( bcs 2f ) 64 CALGN( adr r4, 6f ) 65 CALGN( subs r2, r2, ip ) @ C is set here 66 CALGN( rsb ip, ip, #32 ) 67 CALGN( add pc, r4, ip ) 68 69 PLD( pld [r1, #-4] ) 702: PLD( subs r2, r2, #96 ) 71 PLD( pld [r1, #-32] ) 72 PLD( blt 4f ) 73 PLD( pld [r1, #-64] ) 74 PLD( pld [r1, #-96] ) 75 763: PLD( pld [r1, #-128] ) 774: ldmdb r1!, {r3, r4, r5, r6, r7, r8, ip, lr} 78 subs r2, r2, #32 79 stmdb r0!, {r3, r4, r5, r6, r7, r8, ip, lr} 80 bge 3b 81 PLD( cmn r2, #96 ) 82 PLD( bge 4b ) 83 845: ands ip, r2, #28 85 rsb ip, ip, #32 86 addne pc, pc, ip @ C is always clear here 87 b 7f 886: W(nop) 89 W(ldr) r3, [r1, #-4]! 90 W(ldr) r4, [r1, #-4]! 91 W(ldr) r5, [r1, #-4]! 92 W(ldr) r6, [r1, #-4]! 93 W(ldr) r7, [r1, #-4]! 94 W(ldr) r8, [r1, #-4]! 95 W(ldr) lr, [r1, #-4]! 96 97 add pc, pc, ip 98 nop 99 W(nop) 100 W(str) r3, [r0, #-4]! 101 W(str) r4, [r0, #-4]! 102 W(str) r5, [r0, #-4]! 103 W(str) r6, [r0, #-4]! 104 W(str) r7, [r0, #-4]! 105 W(str) r8, [r0, #-4]! 106 W(str) lr, [r0, #-4]! 107 108 CALGN( bcs 2b ) 109 1107: ldmfd sp!, {r5 - r8} 111 UNWIND( .fnend ) @ end of second stmfd block 112 113 UNWIND( .fnstart ) 114 UNWIND( .save {r0, r4, lr} ) @ still in first stmfd block 115 1168: movs r2, r2, lsl #31 117 ldrbne r3, [r1, #-1]! 118 ldrbcs r4, [r1, #-1]! 119 ldrbcs ip, [r1, #-1] 120 strbne r3, [r0, #-1]! 121 strbcs r4, [r0, #-1]! 122 strbcs ip, [r0, #-1] 123 ldmfd sp!, {r0, r4, pc} 124 1259: cmp ip, #2 126 ldrbgt r3, [r1, #-1]! 127 ldrbge r4, [r1, #-1]! 128 ldrb lr, [r1, #-1]! 129 strbgt r3, [r0, #-1]! 130 strbge r4, [r0, #-1]! 131 subs r2, r2, ip 132 strb lr, [r0, #-1]! 133 blt 8b 134 ands ip, r1, #3 135 beq 1b 136 13710: bic r1, r1, #3 138 cmp ip, #2 139 ldr r3, [r1, #0] 140 beq 17f 141 blt 18f 142 UNWIND( .fnend ) 143 144 145 .macro backward_copy_shift push pull 146 147 UNWIND( .fnstart ) 148 UNWIND( .save {r0, r4, lr} ) @ still in first stmfd block 149 subs r2, r2, #28 150 blt 14f 151 152 CALGN( ands ip, r0, #31 ) 153 CALGN( sbcsne r4, ip, r2 ) @ C is always set here 154 CALGN( subcc r2, r2, ip ) 155 CALGN( bcc 15f ) 156 15711: stmfd sp!, {r5 - r9} 158 UNWIND( .fnend ) 159 160 UNWIND( .fnstart ) 161 UNWIND( .save {r0, r4, lr} ) 162 UNWIND( .save {r5 - r9} ) @ in new second stmfd block 163 164 PLD( pld [r1, #-4] ) 165 PLD( subs r2, r2, #96 ) 166 PLD( pld [r1, #-32] ) 167 PLD( blt 13f ) 168 PLD( pld [r1, #-64] ) 169 PLD( pld [r1, #-96] ) 170 17112: PLD( pld [r1, #-128] ) 17213: ldmdb r1!, {r7, r8, r9, ip} 173 mov lr, r3, lspush #\push 174 subs r2, r2, #32 175 ldmdb r1!, {r3, r4, r5, r6} 176 orr lr, lr, ip, lspull #\pull 177 mov ip, ip, lspush #\push 178 orr ip, ip, r9, lspull #\pull 179 mov r9, r9, lspush #\push 180 orr r9, r9, r8, lspull #\pull 181 mov r8, r8, lspush #\push 182 orr r8, r8, r7, lspull #\pull 183 mov r7, r7, lspush #\push 184 orr r7, r7, r6, lspull #\pull 185 mov r6, r6, lspush #\push 186 orr r6, r6, r5, lspull #\pull 187 mov r5, r5, lspush #\push 188 orr r5, r5, r4, lspull #\pull 189 mov r4, r4, lspush #\push 190 orr r4, r4, r3, lspull #\pull 191 stmdb r0!, {r4 - r9, ip, lr} 192 bge 12b 193 PLD( cmn r2, #96 ) 194 PLD( bge 13b ) 195 196 ldmfd sp!, {r5 - r9} 197 UNWIND( .fnend ) @ end of the second stmfd block 198 199 UNWIND( .fnstart ) 200 UNWIND( .save {r0, r4, lr} ) @ still in first stmfd block 201 20214: ands ip, r2, #28 203 beq 16f 204 20515: mov lr, r3, lspush #\push 206 ldr r3, [r1, #-4]! 207 subs ip, ip, #4 208 orr lr, lr, r3, lspull #\pull 209 str lr, [r0, #-4]! 210 bgt 15b 211 CALGN( cmp r2, #0 ) 212 CALGN( bge 11b ) 213 21416: add r1, r1, #(\pull / 8) 215 b 8b 216 UNWIND( .fnend ) 217 218 .endm 219 220 221 backward_copy_shift push=8 pull=24 222 22317: backward_copy_shift push=16 pull=16 224 22518: backward_copy_shift push=24 pull=8 226 227ENDPROC(memmove) 228