212 lines
4.4 KiB
ArmAsm
212 lines
4.4 KiB
ArmAsm
/* SPDX-License-Identifier: GPL-2.0-only */
|
|
/*
|
|
* linux/arch/unicore32/lib/copy_template.S
|
|
*
|
|
* Code specific to PKUnity SoC and UniCore ISA
|
|
*
|
|
* Copyright (C) 2001-2010 GUAN Xue-tao
|
|
*/
|
|
|
|
/*
|
|
* Theory of operation
|
|
* -------------------
|
|
*
|
|
* This file provides the core code for a forward memory copy used in
|
|
* the implementation of memcopy(), copy_to_user() and copy_from_user().
|
|
*
|
|
* The including file must define the following accessor macros
|
|
* according to the need of the given function:
|
|
*
|
|
* ldr1w ptr reg abort
|
|
*
|
|
* This loads one word from 'ptr', stores it in 'reg' and increments
|
|
* 'ptr' to the next word. The 'abort' argument is used for fixup tables.
|
|
*
|
|
* ldr4w ptr reg1 reg2 reg3 reg4 abort
|
|
* ldr8w ptr, reg1 reg2 reg3 reg4 reg5 reg6 reg7 reg8 abort
|
|
*
|
|
* This loads four or eight words starting from 'ptr', stores them
|
|
* in provided registers and increments 'ptr' past those words.
|
|
* The'abort' argument is used for fixup tables.
|
|
*
|
|
* ldr1b ptr reg cond abort
|
|
*
|
|
* Similar to ldr1w, but it loads a byte and increments 'ptr' one byte.
|
|
* It also must apply the condition code if provided, otherwise the
|
|
* "al" condition is assumed by default.
|
|
*
|
|
* str1w ptr reg abort
|
|
* str8w ptr reg1 reg2 reg3 reg4 reg5 reg6 reg7 reg8 abort
|
|
* str1b ptr reg cond abort
|
|
*
|
|
* Same as their ldr* counterparts, but data is stored to 'ptr' location
|
|
* rather than being loaded.
|
|
*
|
|
* enter
|
|
*
|
|
* Preserve the provided registers on the stack plus any additional
|
|
* data as needed by the implementation including this code. Called
|
|
* upon code entry.
|
|
*
|
|
* exit
|
|
*
|
|
* Restore registers with the values previously saved with the
|
|
* 'preserv' macro. Called upon code termination.
|
|
*/
|
|
|
|
|
|
enter
|
|
|
|
sub.a r2, r2, #4
|
|
bsl 8f
|
|
and.a ip, r0, #3
|
|
bne 9f
|
|
and.a ip, r1, #3
|
|
bne 10f
|
|
|
|
1: sub.a r2, r2, #(28)
|
|
stm.w (r5 - r8), [sp-]
|
|
bsl 5f
|
|
|
|
3:
|
|
4: ldr8w r1, r3, r4, r5, r6, r7, r8, r10, r11, abort=20f
|
|
sub.a r2, r2, #32
|
|
str8w r0, r3, r4, r5, r6, r7, r8, r10, r11, abort=20f
|
|
beg 3b
|
|
|
|
5: and.a ip, r2, #28
|
|
rsub ip, ip, #32
|
|
beq 7f
|
|
add pc, pc, ip @ C is always clear here
|
|
nop
|
|
|
|
ldr1w r1, r3, abort=20f
|
|
ldr1w r1, r4, abort=20f
|
|
ldr1w r1, r5, abort=20f
|
|
ldr1w r1, r6, abort=20f
|
|
ldr1w r1, r7, abort=20f
|
|
ldr1w r1, r8, abort=20f
|
|
ldr1w r1, r11, abort=20f
|
|
|
|
add pc, pc, ip
|
|
nop
|
|
|
|
str1w r0, r3, abort=20f
|
|
str1w r0, r4, abort=20f
|
|
str1w r0, r5, abort=20f
|
|
str1w r0, r6, abort=20f
|
|
str1w r0, r7, abort=20f
|
|
str1w r0, r8, abort=20f
|
|
str1w r0, r11, abort=20f
|
|
|
|
7: ldm.w (r5 - r8), [sp]+
|
|
|
|
8: mov.a r2, r2 << #31
|
|
ldr1b r1, r3, ne, abort=21f
|
|
ldr1b r1, r4, ea, abort=21f
|
|
ldr1b r1, r10, ea, abort=21f
|
|
str1b r0, r3, ne, abort=21f
|
|
str1b r0, r4, ea, abort=21f
|
|
str1b r0, r10, ea, abort=21f
|
|
|
|
exit
|
|
|
|
9: rsub ip, ip, #4
|
|
csub.a ip, #2
|
|
ldr1b r1, r3, sg, abort=21f
|
|
ldr1b r1, r4, eg, abort=21f
|
|
ldr1b r1, r11, abort=21f
|
|
str1b r0, r3, sg, abort=21f
|
|
str1b r0, r4, eg, abort=21f
|
|
sub.a r2, r2, ip
|
|
str1b r0, r11, abort=21f
|
|
bsl 8b
|
|
and.a ip, r1, #3
|
|
beq 1b
|
|
|
|
10: andn r1, r1, #3
|
|
csub.a ip, #2
|
|
ldr1w r1, r11, abort=21f
|
|
beq 17f
|
|
bsg 18f
|
|
|
|
|
|
.macro forward_copy_shift a b
|
|
|
|
sub.a r2, r2, #28
|
|
bsl 14f
|
|
|
|
11: stm.w (r5 - r9), [sp-]
|
|
|
|
12:
|
|
ldr4w r1, r4, r5, r6, r7, abort=19f
|
|
mov r3, r11 pull #\a
|
|
sub.a r2, r2, #32
|
|
ldr4w r1, r8, r9, r10, r11, abort=19f
|
|
or r3, r3, r4 push #\b
|
|
mov r4, r4 pull #\a
|
|
or r4, r4, r5 push #\b
|
|
mov r5, r5 pull #\a
|
|
or r5, r5, r6 push #\b
|
|
mov r6, r6 pull #\a
|
|
or r6, r6, r7 push #\b
|
|
mov r7, r7 pull #\a
|
|
or r7, r7, r8 push #\b
|
|
mov r8, r8 pull #\a
|
|
or r8, r8, r9 push #\b
|
|
mov r9, r9 pull #\a
|
|
or r9, r9, r10 push #\b
|
|
mov r10, r10 pull #\a
|
|
or r10, r10, r11 push #\b
|
|
str8w r0, r3, r4, r5, r6, r7, r8, r9, r10, , abort=19f
|
|
beg 12b
|
|
|
|
ldm.w (r5 - r9), [sp]+
|
|
|
|
14: and.a ip, r2, #28
|
|
beq 16f
|
|
|
|
15: mov r3, r11 pull #\a
|
|
ldr1w r1, r11, abort=21f
|
|
sub.a ip, ip, #4
|
|
or r3, r3, r11 push #\b
|
|
str1w r0, r3, abort=21f
|
|
bsg 15b
|
|
|
|
16: sub r1, r1, #(\b / 8)
|
|
b 8b
|
|
|
|
.endm
|
|
|
|
|
|
forward_copy_shift a=8 b=24
|
|
|
|
17: forward_copy_shift a=16 b=16
|
|
|
|
18: forward_copy_shift a=24 b=8
|
|
|
|
|
|
/*
|
|
* Abort preamble and completion macros.
|
|
* If a fixup handler is required then those macros must surround it.
|
|
* It is assumed that the fixup code will handle the private part of
|
|
* the exit macro.
|
|
*/
|
|
|
|
.macro copy_abort_preamble
|
|
19: ldm.w (r5 - r9), [sp]+
|
|
b 21f
|
|
299: .word 0 @ store lr
|
|
@ to avoid function call in fixup
|
|
20: ldm.w (r5 - r8), [sp]+
|
|
21:
|
|
adr r1, 299b
|
|
stw lr, [r1]
|
|
.endm
|
|
|
|
.macro copy_abort_end
|
|
adr lr, 299b
|
|
ldw pc, [lr]
|
|
.endm
|
|
|