/* SPDX-License-Identifier: GPL-2.0-only */1/*2* linux/arch/arm/lib/copy_template.s3*4* Code template for optimized memory copy functions5*6* Author: Nicolas Pitre7* Created: Sep 28, 20058* Copyright: MontaVista Software, Inc.9*/1011/*12* Theory of operation13* -------------------14*15* This file provides the core code for a forward memory copy used in16* the implementation of memcopy(), copy_to_user() and copy_from_user().17*18* The including file must define the following accessor macros19* according to the need of the given function:20*21* ldr1w ptr reg abort22*23* This loads one word from 'ptr', stores it in 'reg' and increments24* 'ptr' to the next word. The 'abort' argument is used for fixup tables.25*26* ldr4w ptr reg1 reg2 reg3 reg4 abort27* ldr8w ptr, reg1 reg2 reg3 reg4 reg5 reg6 reg7 reg8 abort28*29* This loads four or eight words starting from 'ptr', stores them30* in provided registers and increments 'ptr' past those words.31* The'abort' argument is used for fixup tables.32*33* ldr1b ptr reg cond abort34*35* Similar to ldr1w, but it loads a byte and increments 'ptr' one byte.36* It also must apply the condition code if provided, otherwise the37* "al" condition is assumed by default.38*39* str1w ptr reg abort40* str8w ptr reg1 reg2 reg3 reg4 reg5 reg6 reg7 reg8 abort41* str1b ptr reg cond abort42*43* Same as their ldr* counterparts, but data is stored to 'ptr' location44* rather than being loaded.45*46* enter reg1 reg247*48* Preserve the provided registers on the stack plus any additional49* data as needed by the implementation including this code. Called50* upon code entry.51*52* usave reg1 reg253*54* Unwind annotation macro is corresponding for 'enter' macro.55* It tell unwinder that preserved some provided registers on the stack56* and additional data by a prior 'enter' macro.57*58* exit reg1 reg259*60* Restore registers with the values previously saved with the61* 'preserv' macro. Called upon code termination.62*63* LDR1W_SHIFT64* STR1W_SHIFT65*66* Correction to be applied to the "ip" register when branching into67* the ldr1w or str1w instructions (some of these macros may expand to68* than one 32bit instruction in Thumb-2)69*/7071UNWIND( .fnstart )72enter r4, UNWIND(fpreg,) lr73UNWIND( .setfp fpreg, sp )74UNWIND( mov fpreg, sp )7576subs r2, r2, #477blt 8f78ands ip, r0, #379PLD( pld [r1, #0] )80bne 9f81ands ip, r1, #382bne 10f83841: subs r2, r2, #(28)85stmfd sp!, {r5, r6, r8, r9}86blt 5f8788CALGN( ands ip, r0, #31 )89CALGN( rsb r3, ip, #32 )90CALGN( sbcsne r4, r3, r2 ) @ C is always set here91CALGN( bcs 2f )92CALGN( adr r4, 6f )93CALGN( subs r2, r2, r3 ) @ C gets set94CALGN( add pc, r4, ip )9596PLD( pld [r1, #0] )972: PLD( subs r2, r2, #96 )98PLD( pld [r1, #28] )99PLD( blt 4f )100PLD( pld [r1, #60] )101PLD( pld [r1, #92] )1021033: PLD( pld [r1, #124] )1044: ldr8w r1, r3, r4, r5, r6, r8, r9, ip, lr, abort=20f105subs r2, r2, #32106str8w r0, r3, r4, r5, r6, r8, r9, ip, lr, abort=20f107bge 3b108PLD( cmn r2, #96 )109PLD( bge 4b )1101115: ands ip, r2, #28112rsb ip, ip, #32113#if LDR1W_SHIFT > 0114lsl ip, ip, #LDR1W_SHIFT115#endif116addne pc, pc, ip @ C is always clear here117b 7f1186:119.rept (1 << LDR1W_SHIFT)120W(nop)121.endr122ldr1w r1, r3, abort=20f123ldr1w r1, r4, abort=20f124ldr1w r1, r5, abort=20f125ldr1w r1, r6, abort=20f126ldr1w r1, r8, abort=20f127ldr1w r1, r9, abort=20f128ldr1w r1, lr, abort=20f129130#if LDR1W_SHIFT < STR1W_SHIFT131lsl ip, ip, #STR1W_SHIFT - LDR1W_SHIFT132#elif LDR1W_SHIFT > STR1W_SHIFT133lsr ip, ip, #LDR1W_SHIFT - STR1W_SHIFT134#endif135add pc, pc, ip136nop137.rept (1 << STR1W_SHIFT)138W(nop)139.endr140str1w r0, r3, abort=20f141str1w r0, r4, abort=20f142str1w r0, r5, abort=20f143str1w r0, r6, abort=20f144str1w r0, r8, abort=20f145str1w r0, r9, abort=20f146str1w r0, lr, abort=20f147148CALGN( bcs 2b )1491507: ldmfd sp!, {r5, r6, r8, r9}1511528: movs r2, r2, lsl #31153ldr1b r1, r3, ne, abort=21f154ldr1b r1, r4, cs, abort=21f155ldr1b r1, ip, cs, abort=21f156str1b r0, r3, ne, abort=21f157str1b r0, r4, cs, abort=21f158str1b r0, ip, cs, abort=21f159160exit r4, UNWIND(fpreg,) pc1611629: rsb ip, ip, #4163cmp ip, #2164ldr1b r1, r3, gt, abort=21f165ldr1b r1, r4, ge, abort=21f166ldr1b r1, lr, abort=21f167str1b r0, r3, gt, abort=21f168str1b r0, r4, ge, abort=21f169subs r2, r2, ip170str1b r0, lr, abort=21f171blt 8b172ands ip, r1, #3173beq 1b17417510: bic r1, r1, #3176cmp ip, #2177ldr1w r1, lr, abort=21f178beq 17f179bgt 18f180181182.macro forward_copy_shift pull push183184subs r2, r2, #28185blt 14f186187CALGN( ands ip, r0, #31 )188CALGN( rsb ip, ip, #32 )189CALGN( sbcsne r4, ip, r2 ) @ C is always set here190CALGN( subcc r2, r2, ip )191CALGN( bcc 15f )19219311: stmfd sp!, {r5, r6, r8 - r10}194195PLD( pld [r1, #0] )196PLD( subs r2, r2, #96 )197PLD( pld [r1, #28] )198PLD( blt 13f )199PLD( pld [r1, #60] )200PLD( pld [r1, #92] )20120212: PLD( pld [r1, #124] )20313: ldr4w r1, r4, r5, r6, r8, abort=19f204mov r3, lr, lspull #\pull205subs r2, r2, #32206ldr4w r1, r9, r10, ip, lr, abort=19f207orr r3, r3, r4, lspush #\push208mov r4, r4, lspull #\pull209orr r4, r4, r5, lspush #\push210mov r5, r5, lspull #\pull211orr r5, r5, r6, lspush #\push212mov r6, r6, lspull #\pull213orr r6, r6, r8, lspush #\push214mov r8, r8, lspull #\pull215orr r8, r8, r9, lspush #\push216mov r9, r9, lspull #\pull217orr r9, r9, r10, lspush #\push218mov r10, r10, lspull #\pull219orr r10, r10, ip, lspush #\push220mov ip, ip, lspull #\pull221orr ip, ip, lr, lspush #\push222str8w r0, r3, r4, r5, r6, r8, r9, r10, ip, abort=19f223bge 12b224PLD( cmn r2, #96 )225PLD( bge 13b )226227ldmfd sp!, {r5, r6, r8 - r10}22822914: ands ip, r2, #28230beq 16f23123215: mov r3, lr, lspull #\pull233ldr1w r1, lr, abort=21f234subs ip, ip, #4235orr r3, r3, lr, lspush #\push236str1w r0, r3, abort=21f237bgt 15b238CALGN( cmp r2, #0 )239CALGN( bge 11b )24024116: sub r1, r1, #(\push / 8)242b 8b243244.endm245246247forward_copy_shift pull=8 push=2424824917: forward_copy_shift pull=16 push=1625025118: forward_copy_shift pull=24 push=8252253UNWIND( .fnend )254255/*256* Abort preamble and completion macros.257* If a fixup handler is required then those macros must surround it.258* It is assumed that the fixup code will handle the private part of259* the exit macro.260*/261262.macro copy_abort_preamble26319: ldmfd sp!, {r5, r6, r8 - r10}264b 21f26520: ldmfd sp!, {r5, r6, r8, r9}26621:267.endm268269.macro copy_abort_end270ldmfd sp!, {r4, UNWIND(fpreg,) pc}271.endm272273274275