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