18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-only */ 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * linux/arch/arm/lib/memmove.S 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Author: Nicolas Pitre 68c2ecf20Sopenharmony_ci * Created: Sep 28, 2005 78c2ecf20Sopenharmony_ci * Copyright: (C) MontaVista Software Inc. 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include <linux/linkage.h> 118c2ecf20Sopenharmony_ci#include <asm/assembler.h> 128c2ecf20Sopenharmony_ci#include <asm/unwind.h> 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci .text 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci/* 178c2ecf20Sopenharmony_ci * Prototype: void *memmove(void *dest, const void *src, size_t n); 188c2ecf20Sopenharmony_ci * 198c2ecf20Sopenharmony_ci * Note: 208c2ecf20Sopenharmony_ci * 218c2ecf20Sopenharmony_ci * If the memory regions don't overlap, we simply branch to memcpy which is 228c2ecf20Sopenharmony_ci * normally a bit faster. Otherwise the copy is done going downwards. This 238c2ecf20Sopenharmony_ci * is a transposition of the code from copy_template.S but with the copy 248c2ecf20Sopenharmony_ci * occurring in the opposite direction. 258c2ecf20Sopenharmony_ci */ 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ciENTRY(__memmove) 288c2ecf20Sopenharmony_ciWEAK(memmove) 298c2ecf20Sopenharmony_ci UNWIND( .fnstart ) 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci subs ip, r0, r1 328c2ecf20Sopenharmony_ci cmphi r2, ip 338c2ecf20Sopenharmony_ci bls __memcpy 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci stmfd sp!, {r0, r4, lr} 368c2ecf20Sopenharmony_ci UNWIND( .fnend ) 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci UNWIND( .fnstart ) 398c2ecf20Sopenharmony_ci UNWIND( .save {r0, r4, lr} ) @ in first stmfd block 408c2ecf20Sopenharmony_ci add r1, r1, r2 418c2ecf20Sopenharmony_ci add r0, r0, r2 428c2ecf20Sopenharmony_ci subs r2, r2, #4 438c2ecf20Sopenharmony_ci blt 8f 448c2ecf20Sopenharmony_ci ands ip, r0, #3 458c2ecf20Sopenharmony_ci PLD( pld [r1, #-4] ) 468c2ecf20Sopenharmony_ci bne 9f 478c2ecf20Sopenharmony_ci ands ip, r1, #3 488c2ecf20Sopenharmony_ci bne 10f 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci1: subs r2, r2, #(28) 518c2ecf20Sopenharmony_ci stmfd sp!, {r5 - r8} 528c2ecf20Sopenharmony_ci UNWIND( .fnend ) 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci UNWIND( .fnstart ) 558c2ecf20Sopenharmony_ci UNWIND( .save {r0, r4, lr} ) 568c2ecf20Sopenharmony_ci UNWIND( .save {r5 - r8} ) @ in second stmfd block 578c2ecf20Sopenharmony_ci blt 5f 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci CALGN( ands ip, r0, #31 ) 608c2ecf20Sopenharmony_ci CALGN( sbcsne r4, ip, r2 ) @ C is always set here 618c2ecf20Sopenharmony_ci CALGN( bcs 2f ) 628c2ecf20Sopenharmony_ci CALGN( adr r4, 6f ) 638c2ecf20Sopenharmony_ci CALGN( subs r2, r2, ip ) @ C is set here 648c2ecf20Sopenharmony_ci CALGN( rsb ip, ip, #32 ) 658c2ecf20Sopenharmony_ci CALGN( add pc, r4, ip ) 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci PLD( pld [r1, #-4] ) 688c2ecf20Sopenharmony_ci2: PLD( subs r2, r2, #96 ) 698c2ecf20Sopenharmony_ci PLD( pld [r1, #-32] ) 708c2ecf20Sopenharmony_ci PLD( blt 4f ) 718c2ecf20Sopenharmony_ci PLD( pld [r1, #-64] ) 728c2ecf20Sopenharmony_ci PLD( pld [r1, #-96] ) 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci3: PLD( pld [r1, #-128] ) 758c2ecf20Sopenharmony_ci4: ldmdb r1!, {r3, r4, r5, r6, r7, r8, ip, lr} 768c2ecf20Sopenharmony_ci subs r2, r2, #32 778c2ecf20Sopenharmony_ci stmdb r0!, {r3, r4, r5, r6, r7, r8, ip, lr} 788c2ecf20Sopenharmony_ci bge 3b 798c2ecf20Sopenharmony_ci PLD( cmn r2, #96 ) 808c2ecf20Sopenharmony_ci PLD( bge 4b ) 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci5: ands ip, r2, #28 838c2ecf20Sopenharmony_ci rsb ip, ip, #32 848c2ecf20Sopenharmony_ci addne pc, pc, ip @ C is always clear here 858c2ecf20Sopenharmony_ci b 7f 868c2ecf20Sopenharmony_ci6: W(nop) 878c2ecf20Sopenharmony_ci W(ldr) r3, [r1, #-4]! 888c2ecf20Sopenharmony_ci W(ldr) r4, [r1, #-4]! 898c2ecf20Sopenharmony_ci W(ldr) r5, [r1, #-4]! 908c2ecf20Sopenharmony_ci W(ldr) r6, [r1, #-4]! 918c2ecf20Sopenharmony_ci W(ldr) r7, [r1, #-4]! 928c2ecf20Sopenharmony_ci W(ldr) r8, [r1, #-4]! 938c2ecf20Sopenharmony_ci W(ldr) lr, [r1, #-4]! 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci add pc, pc, ip 968c2ecf20Sopenharmony_ci nop 978c2ecf20Sopenharmony_ci W(nop) 988c2ecf20Sopenharmony_ci W(str) r3, [r0, #-4]! 998c2ecf20Sopenharmony_ci W(str) r4, [r0, #-4]! 1008c2ecf20Sopenharmony_ci W(str) r5, [r0, #-4]! 1018c2ecf20Sopenharmony_ci W(str) r6, [r0, #-4]! 1028c2ecf20Sopenharmony_ci W(str) r7, [r0, #-4]! 1038c2ecf20Sopenharmony_ci W(str) r8, [r0, #-4]! 1048c2ecf20Sopenharmony_ci W(str) lr, [r0, #-4]! 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci CALGN( bcs 2b ) 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci7: ldmfd sp!, {r5 - r8} 1098c2ecf20Sopenharmony_ci UNWIND( .fnend ) @ end of second stmfd block 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci UNWIND( .fnstart ) 1128c2ecf20Sopenharmony_ci UNWIND( .save {r0, r4, lr} ) @ still in first stmfd block 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci8: movs r2, r2, lsl #31 1158c2ecf20Sopenharmony_ci ldrbne r3, [r1, #-1]! 1168c2ecf20Sopenharmony_ci ldrbcs r4, [r1, #-1]! 1178c2ecf20Sopenharmony_ci ldrbcs ip, [r1, #-1] 1188c2ecf20Sopenharmony_ci strbne r3, [r0, #-1]! 1198c2ecf20Sopenharmony_ci strbcs r4, [r0, #-1]! 1208c2ecf20Sopenharmony_ci strbcs ip, [r0, #-1] 1218c2ecf20Sopenharmony_ci ldmfd sp!, {r0, r4, pc} 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci9: cmp ip, #2 1248c2ecf20Sopenharmony_ci ldrbgt r3, [r1, #-1]! 1258c2ecf20Sopenharmony_ci ldrbge r4, [r1, #-1]! 1268c2ecf20Sopenharmony_ci ldrb lr, [r1, #-1]! 1278c2ecf20Sopenharmony_ci strbgt r3, [r0, #-1]! 1288c2ecf20Sopenharmony_ci strbge r4, [r0, #-1]! 1298c2ecf20Sopenharmony_ci subs r2, r2, ip 1308c2ecf20Sopenharmony_ci strb lr, [r0, #-1]! 1318c2ecf20Sopenharmony_ci blt 8b 1328c2ecf20Sopenharmony_ci ands ip, r1, #3 1338c2ecf20Sopenharmony_ci beq 1b 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci10: bic r1, r1, #3 1368c2ecf20Sopenharmony_ci cmp ip, #2 1378c2ecf20Sopenharmony_ci ldr r3, [r1, #0] 1388c2ecf20Sopenharmony_ci beq 17f 1398c2ecf20Sopenharmony_ci blt 18f 1408c2ecf20Sopenharmony_ci UNWIND( .fnend ) 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci .macro backward_copy_shift push pull 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci UNWIND( .fnstart ) 1468c2ecf20Sopenharmony_ci UNWIND( .save {r0, r4, lr} ) @ still in first stmfd block 1478c2ecf20Sopenharmony_ci subs r2, r2, #28 1488c2ecf20Sopenharmony_ci blt 14f 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci CALGN( ands ip, r0, #31 ) 1518c2ecf20Sopenharmony_ci CALGN( sbcsne r4, ip, r2 ) @ C is always set here 1528c2ecf20Sopenharmony_ci CALGN( subcc r2, r2, ip ) 1538c2ecf20Sopenharmony_ci CALGN( bcc 15f ) 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci11: stmfd sp!, {r5 - r9} 1568c2ecf20Sopenharmony_ci UNWIND( .fnend ) 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci UNWIND( .fnstart ) 1598c2ecf20Sopenharmony_ci UNWIND( .save {r0, r4, lr} ) 1608c2ecf20Sopenharmony_ci UNWIND( .save {r5 - r9} ) @ in new second stmfd block 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci PLD( pld [r1, #-4] ) 1638c2ecf20Sopenharmony_ci PLD( subs r2, r2, #96 ) 1648c2ecf20Sopenharmony_ci PLD( pld [r1, #-32] ) 1658c2ecf20Sopenharmony_ci PLD( blt 13f ) 1668c2ecf20Sopenharmony_ci PLD( pld [r1, #-64] ) 1678c2ecf20Sopenharmony_ci PLD( pld [r1, #-96] ) 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci12: PLD( pld [r1, #-128] ) 1708c2ecf20Sopenharmony_ci13: ldmdb r1!, {r7, r8, r9, ip} 1718c2ecf20Sopenharmony_ci mov lr, r3, lspush #\push 1728c2ecf20Sopenharmony_ci subs r2, r2, #32 1738c2ecf20Sopenharmony_ci ldmdb r1!, {r3, r4, r5, r6} 1748c2ecf20Sopenharmony_ci orr lr, lr, ip, lspull #\pull 1758c2ecf20Sopenharmony_ci mov ip, ip, lspush #\push 1768c2ecf20Sopenharmony_ci orr ip, ip, r9, lspull #\pull 1778c2ecf20Sopenharmony_ci mov r9, r9, lspush #\push 1788c2ecf20Sopenharmony_ci orr r9, r9, r8, lspull #\pull 1798c2ecf20Sopenharmony_ci mov r8, r8, lspush #\push 1808c2ecf20Sopenharmony_ci orr r8, r8, r7, lspull #\pull 1818c2ecf20Sopenharmony_ci mov r7, r7, lspush #\push 1828c2ecf20Sopenharmony_ci orr r7, r7, r6, lspull #\pull 1838c2ecf20Sopenharmony_ci mov r6, r6, lspush #\push 1848c2ecf20Sopenharmony_ci orr r6, r6, r5, lspull #\pull 1858c2ecf20Sopenharmony_ci mov r5, r5, lspush #\push 1868c2ecf20Sopenharmony_ci orr r5, r5, r4, lspull #\pull 1878c2ecf20Sopenharmony_ci mov r4, r4, lspush #\push 1888c2ecf20Sopenharmony_ci orr r4, r4, r3, lspull #\pull 1898c2ecf20Sopenharmony_ci stmdb r0!, {r4 - r9, ip, lr} 1908c2ecf20Sopenharmony_ci bge 12b 1918c2ecf20Sopenharmony_ci PLD( cmn r2, #96 ) 1928c2ecf20Sopenharmony_ci PLD( bge 13b ) 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci ldmfd sp!, {r5 - r9} 1958c2ecf20Sopenharmony_ci UNWIND( .fnend ) @ end of the second stmfd block 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci UNWIND( .fnstart ) 1988c2ecf20Sopenharmony_ci UNWIND( .save {r0, r4, lr} ) @ still in first stmfd block 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci14: ands ip, r2, #28 2018c2ecf20Sopenharmony_ci beq 16f 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci15: mov lr, r3, lspush #\push 2048c2ecf20Sopenharmony_ci ldr r3, [r1, #-4]! 2058c2ecf20Sopenharmony_ci subs ip, ip, #4 2068c2ecf20Sopenharmony_ci orr lr, lr, r3, lspull #\pull 2078c2ecf20Sopenharmony_ci str lr, [r0, #-4]! 2088c2ecf20Sopenharmony_ci bgt 15b 2098c2ecf20Sopenharmony_ci CALGN( cmp r2, #0 ) 2108c2ecf20Sopenharmony_ci CALGN( bge 11b ) 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci16: add r1, r1, #(\pull / 8) 2138c2ecf20Sopenharmony_ci b 8b 2148c2ecf20Sopenharmony_ci UNWIND( .fnend ) 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci .endm 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci backward_copy_shift push=8 pull=24 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci17: backward_copy_shift push=16 pull=16 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci18: backward_copy_shift push=24 pull=8 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ciENDPROC(memmove) 2268c2ecf20Sopenharmony_ciENDPROC(__memmove) 227