162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-only */ 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * linux/arch/arm/lib/memmove.S 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Author: Nicolas Pitre 662306a36Sopenharmony_ci * Created: Sep 28, 2005 762306a36Sopenharmony_ci * Copyright: (C) MontaVista Software Inc. 862306a36Sopenharmony_ci */ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include <linux/linkage.h> 1162306a36Sopenharmony_ci#include <asm/assembler.h> 1262306a36Sopenharmony_ci#include <asm/unwind.h> 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci .text 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci/* 1762306a36Sopenharmony_ci * Prototype: void *memmove(void *dest, const void *src, size_t n); 1862306a36Sopenharmony_ci * 1962306a36Sopenharmony_ci * Note: 2062306a36Sopenharmony_ci * 2162306a36Sopenharmony_ci * If the memory regions don't overlap, we simply branch to memcpy which is 2262306a36Sopenharmony_ci * normally a bit faster. Otherwise the copy is done going downwards. This 2362306a36Sopenharmony_ci * is a transposition of the code from copy_template.S but with the copy 2462306a36Sopenharmony_ci * occurring in the opposite direction. 2562306a36Sopenharmony_ci */ 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ciENTRY(__memmove) 2862306a36Sopenharmony_ciWEAK(memmove) 2962306a36Sopenharmony_ci UNWIND( .fnstart ) 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci subs ip, r0, r1 3262306a36Sopenharmony_ci cmphi r2, ip 3362306a36Sopenharmony_ci bls __memcpy 3462306a36Sopenharmony_ci UNWIND( .fnend ) 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci UNWIND( .fnstart ) 3762306a36Sopenharmony_ci UNWIND( .save {r0, r4, fpreg, lr} ) 3862306a36Sopenharmony_ci stmfd sp!, {r0, r4, UNWIND(fpreg,) lr} 3962306a36Sopenharmony_ci UNWIND( .setfp fpreg, sp ) 4062306a36Sopenharmony_ci UNWIND( mov fpreg, sp ) 4162306a36Sopenharmony_ci add r1, r1, r2 4262306a36Sopenharmony_ci add r0, r0, r2 4362306a36Sopenharmony_ci subs r2, r2, #4 4462306a36Sopenharmony_ci blt 8f 4562306a36Sopenharmony_ci ands ip, r0, #3 4662306a36Sopenharmony_ci PLD( pld [r1, #-4] ) 4762306a36Sopenharmony_ci bne 9f 4862306a36Sopenharmony_ci ands ip, r1, #3 4962306a36Sopenharmony_ci bne 10f 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci1: subs r2, r2, #(28) 5262306a36Sopenharmony_ci stmfd sp!, {r5, r6, r8, r9} 5362306a36Sopenharmony_ci blt 5f 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci CALGN( ands ip, r0, #31 ) 5662306a36Sopenharmony_ci CALGN( sbcsne r4, ip, r2 ) @ C is always set here 5762306a36Sopenharmony_ci CALGN( bcs 2f ) 5862306a36Sopenharmony_ci CALGN( adr r4, 6f ) 5962306a36Sopenharmony_ci CALGN( subs r2, r2, ip ) @ C is set here 6062306a36Sopenharmony_ci CALGN( rsb ip, ip, #32 ) 6162306a36Sopenharmony_ci CALGN( add pc, r4, ip ) 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci PLD( pld [r1, #-4] ) 6462306a36Sopenharmony_ci2: PLD( subs r2, r2, #96 ) 6562306a36Sopenharmony_ci PLD( pld [r1, #-32] ) 6662306a36Sopenharmony_ci PLD( blt 4f ) 6762306a36Sopenharmony_ci PLD( pld [r1, #-64] ) 6862306a36Sopenharmony_ci PLD( pld [r1, #-96] ) 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci3: PLD( pld [r1, #-128] ) 7162306a36Sopenharmony_ci4: ldmdb r1!, {r3, r4, r5, r6, r8, r9, ip, lr} 7262306a36Sopenharmony_ci subs r2, r2, #32 7362306a36Sopenharmony_ci stmdb r0!, {r3, r4, r5, r6, r8, r9, ip, lr} 7462306a36Sopenharmony_ci bge 3b 7562306a36Sopenharmony_ci PLD( cmn r2, #96 ) 7662306a36Sopenharmony_ci PLD( bge 4b ) 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci5: ands ip, r2, #28 7962306a36Sopenharmony_ci rsb ip, ip, #32 8062306a36Sopenharmony_ci addne pc, pc, ip @ C is always clear here 8162306a36Sopenharmony_ci b 7f 8262306a36Sopenharmony_ci6: W(nop) 8362306a36Sopenharmony_ci W(ldr) r3, [r1, #-4]! 8462306a36Sopenharmony_ci W(ldr) r4, [r1, #-4]! 8562306a36Sopenharmony_ci W(ldr) r5, [r1, #-4]! 8662306a36Sopenharmony_ci W(ldr) r6, [r1, #-4]! 8762306a36Sopenharmony_ci W(ldr) r8, [r1, #-4]! 8862306a36Sopenharmony_ci W(ldr) r9, [r1, #-4]! 8962306a36Sopenharmony_ci W(ldr) lr, [r1, #-4]! 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci add pc, pc, ip 9262306a36Sopenharmony_ci nop 9362306a36Sopenharmony_ci W(nop) 9462306a36Sopenharmony_ci W(str) r3, [r0, #-4]! 9562306a36Sopenharmony_ci W(str) r4, [r0, #-4]! 9662306a36Sopenharmony_ci W(str) r5, [r0, #-4]! 9762306a36Sopenharmony_ci W(str) r6, [r0, #-4]! 9862306a36Sopenharmony_ci W(str) r8, [r0, #-4]! 9962306a36Sopenharmony_ci W(str) r9, [r0, #-4]! 10062306a36Sopenharmony_ci W(str) lr, [r0, #-4]! 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci CALGN( bcs 2b ) 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci7: ldmfd sp!, {r5, r6, r8, r9} 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci8: movs r2, r2, lsl #31 10762306a36Sopenharmony_ci ldrbne r3, [r1, #-1]! 10862306a36Sopenharmony_ci ldrbcs r4, [r1, #-1]! 10962306a36Sopenharmony_ci ldrbcs ip, [r1, #-1] 11062306a36Sopenharmony_ci strbne r3, [r0, #-1]! 11162306a36Sopenharmony_ci strbcs r4, [r0, #-1]! 11262306a36Sopenharmony_ci strbcs ip, [r0, #-1] 11362306a36Sopenharmony_ci ldmfd sp!, {r0, r4, UNWIND(fpreg,) pc} 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci9: cmp ip, #2 11662306a36Sopenharmony_ci ldrbgt r3, [r1, #-1]! 11762306a36Sopenharmony_ci ldrbge r4, [r1, #-1]! 11862306a36Sopenharmony_ci ldrb lr, [r1, #-1]! 11962306a36Sopenharmony_ci strbgt r3, [r0, #-1]! 12062306a36Sopenharmony_ci strbge r4, [r0, #-1]! 12162306a36Sopenharmony_ci subs r2, r2, ip 12262306a36Sopenharmony_ci strb lr, [r0, #-1]! 12362306a36Sopenharmony_ci blt 8b 12462306a36Sopenharmony_ci ands ip, r1, #3 12562306a36Sopenharmony_ci beq 1b 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci10: bic r1, r1, #3 12862306a36Sopenharmony_ci cmp ip, #2 12962306a36Sopenharmony_ci ldr r3, [r1, #0] 13062306a36Sopenharmony_ci beq 17f 13162306a36Sopenharmony_ci blt 18f 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci .macro backward_copy_shift push pull 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci subs r2, r2, #28 13762306a36Sopenharmony_ci blt 14f 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci CALGN( ands ip, r0, #31 ) 14062306a36Sopenharmony_ci CALGN( sbcsne r4, ip, r2 ) @ C is always set here 14162306a36Sopenharmony_ci CALGN( subcc r2, r2, ip ) 14262306a36Sopenharmony_ci CALGN( bcc 15f ) 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci11: stmfd sp!, {r5, r6, r8 - r10} 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci PLD( pld [r1, #-4] ) 14762306a36Sopenharmony_ci PLD( subs r2, r2, #96 ) 14862306a36Sopenharmony_ci PLD( pld [r1, #-32] ) 14962306a36Sopenharmony_ci PLD( blt 13f ) 15062306a36Sopenharmony_ci PLD( pld [r1, #-64] ) 15162306a36Sopenharmony_ci PLD( pld [r1, #-96] ) 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci12: PLD( pld [r1, #-128] ) 15462306a36Sopenharmony_ci13: ldmdb r1!, {r8, r9, r10, ip} 15562306a36Sopenharmony_ci mov lr, r3, lspush #\push 15662306a36Sopenharmony_ci subs r2, r2, #32 15762306a36Sopenharmony_ci ldmdb r1!, {r3, r4, r5, r6} 15862306a36Sopenharmony_ci orr lr, lr, ip, lspull #\pull 15962306a36Sopenharmony_ci mov ip, ip, lspush #\push 16062306a36Sopenharmony_ci orr ip, ip, r10, lspull #\pull 16162306a36Sopenharmony_ci mov r10, r10, lspush #\push 16262306a36Sopenharmony_ci orr r10, r10, r9, lspull #\pull 16362306a36Sopenharmony_ci mov r9, r9, lspush #\push 16462306a36Sopenharmony_ci orr r9, r9, r8, lspull #\pull 16562306a36Sopenharmony_ci mov r8, r8, lspush #\push 16662306a36Sopenharmony_ci orr r8, r8, r6, lspull #\pull 16762306a36Sopenharmony_ci mov r6, r6, lspush #\push 16862306a36Sopenharmony_ci orr r6, r6, r5, lspull #\pull 16962306a36Sopenharmony_ci mov r5, r5, lspush #\push 17062306a36Sopenharmony_ci orr r5, r5, r4, lspull #\pull 17162306a36Sopenharmony_ci mov r4, r4, lspush #\push 17262306a36Sopenharmony_ci orr r4, r4, r3, lspull #\pull 17362306a36Sopenharmony_ci stmdb r0!, {r4 - r6, r8 - r10, ip, lr} 17462306a36Sopenharmony_ci bge 12b 17562306a36Sopenharmony_ci PLD( cmn r2, #96 ) 17662306a36Sopenharmony_ci PLD( bge 13b ) 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci ldmfd sp!, {r5, r6, r8 - r10} 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci14: ands ip, r2, #28 18162306a36Sopenharmony_ci beq 16f 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci15: mov lr, r3, lspush #\push 18462306a36Sopenharmony_ci ldr r3, [r1, #-4]! 18562306a36Sopenharmony_ci subs ip, ip, #4 18662306a36Sopenharmony_ci orr lr, lr, r3, lspull #\pull 18762306a36Sopenharmony_ci str lr, [r0, #-4]! 18862306a36Sopenharmony_ci bgt 15b 18962306a36Sopenharmony_ci CALGN( cmp r2, #0 ) 19062306a36Sopenharmony_ci CALGN( bge 11b ) 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci16: add r1, r1, #(\pull / 8) 19362306a36Sopenharmony_ci b 8b 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci .endm 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci backward_copy_shift push=8 pull=24 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci17: backward_copy_shift push=16 pull=16 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci18: backward_copy_shift push=24 pull=8 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci UNWIND( .fnend ) 20562306a36Sopenharmony_ciENDPROC(memmove) 20662306a36Sopenharmony_ciENDPROC(__memmove) 207