|
@@ -0,0 +1,214 @@
|
|
|
+/*
|
|
|
+ * linux/arch/unicore32/lib/copy_template.S
|
|
|
+ *
|
|
|
+ * Code specific to PKUnity SoC and UniCore ISA
|
|
|
+ *
|
|
|
+ * Copyright (C) 2001-2010 GUAN Xue-tao
|
|
|
+ *
|
|
|
+ * This program is free software; you can redistribute it and/or modify
|
|
|
+ * it under the terms of the GNU General Public License version 2 as
|
|
|
+ * published by the Free Software Foundation.
|
|
|
+ */
|
|
|
+
|
|
|
+/*
|
|
|
+ * 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
|
|
|
+
|