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