memcpy.S 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271
  1. /*
  2. * linux/arch/arm/lib/memcpy.S
  3. *
  4. * Author: Nicolas Pitre
  5. * Created: Sep 28, 2005
  6. * Copyright: MontaVista Software, Inc.
  7. *
  8. * This program is free software; you can redistribute it and/or modify
  9. * it under the terms of the GNU General Public License version 2 as
  10. * published by the Free Software Foundation.
  11. */
  12. #include <linux/linkage.h>
  13. #include <asm/assembler.h>
  14. #if defined(CONFIG_SYS_THUMB_BUILD) && !defined(MEMCPY_NO_THUMB_BUILD)
  15. #define W(instr) instr.w
  16. #else
  17. #define W(instr) instr
  18. #endif
  19. #define LDR1W_SHIFT 0
  20. #define STR1W_SHIFT 0
  21. .macro ldr1w ptr reg abort
  22. W(ldr) \reg, [\ptr], #4
  23. .endm
  24. .macro ldr4w ptr reg1 reg2 reg3 reg4 abort
  25. ldmia \ptr!, {\reg1, \reg2, \reg3, \reg4}
  26. .endm
  27. .macro ldr8w ptr reg1 reg2 reg3 reg4 reg5 reg6 reg7 reg8 abort
  28. ldmia \ptr!, {\reg1, \reg2, \reg3, \reg4, \reg5, \reg6, \reg7, \reg8}
  29. .endm
  30. .macro ldr1b ptr reg cond=al abort
  31. ldrb\cond\() \reg, [\ptr], #1
  32. .endm
  33. .macro str1w ptr reg abort
  34. W(str) \reg, [\ptr], #4
  35. .endm
  36. .macro str8w ptr reg1 reg2 reg3 reg4 reg5 reg6 reg7 reg8 abort
  37. stmia \ptr!, {\reg1, \reg2, \reg3, \reg4, \reg5, \reg6, \reg7, \reg8}
  38. .endm
  39. .macro str1b ptr reg cond=al abort
  40. strb\cond\() \reg, [\ptr], #1
  41. .endm
  42. .macro enter reg1 reg2
  43. stmdb sp!, {r0, \reg1, \reg2}
  44. .endm
  45. .macro exit reg1 reg2
  46. ldmfd sp!, {r0, \reg1, \reg2}
  47. .endm
  48. .text
  49. /* Prototype: void *memcpy(void *dest, const void *src, size_t n); */
  50. .syntax unified
  51. #if defined(CONFIG_SYS_THUMB_BUILD) && !defined(MEMCPY_NO_THUMB_BUILD)
  52. .thumb
  53. .thumb_func
  54. #endif
  55. ENTRY(memcpy)
  56. cmp r0, r1
  57. moveq pc, lr
  58. enter r4, lr
  59. subs r2, r2, #4
  60. blt 8f
  61. ands ip, r0, #3
  62. PLD( pld [r1, #0] )
  63. bne 9f
  64. ands ip, r1, #3
  65. bne 10f
  66. 1: subs r2, r2, #(28)
  67. stmfd sp!, {r5 - r8}
  68. blt 5f
  69. CALGN( ands ip, r0, #31 )
  70. CALGN( rsb r3, ip, #32 )
  71. CALGN( sbcsne r4, r3, r2 ) @ C is always set here
  72. CALGN( bcs 2f )
  73. CALGN( adr r4, 6f )
  74. CALGN( subs r2, r2, r3 ) @ C gets set
  75. CALGN( add pc, r4, ip )
  76. PLD( pld [r1, #0] )
  77. 2: PLD( subs r2, r2, #96 )
  78. PLD( pld [r1, #28] )
  79. PLD( blt 4f )
  80. PLD( pld [r1, #60] )
  81. PLD( pld [r1, #92] )
  82. 3: PLD( pld [r1, #124] )
  83. 4: ldr8w r1, r3, r4, r5, r6, r7, r8, ip, lr, abort=20f
  84. subs r2, r2, #32
  85. str8w r0, r3, r4, r5, r6, r7, r8, ip, lr, abort=20f
  86. bge 3b
  87. PLD( cmn r2, #96 )
  88. PLD( bge 4b )
  89. 5: ands ip, r2, #28
  90. rsb ip, ip, #32
  91. #if LDR1W_SHIFT > 0
  92. lsl ip, ip, #LDR1W_SHIFT
  93. #endif
  94. addne pc, pc, ip @ C is always clear here
  95. b 7f
  96. 6:
  97. .rept (1 << LDR1W_SHIFT)
  98. W(nop)
  99. .endr
  100. ldr1w r1, r3, abort=20f
  101. ldr1w r1, r4, abort=20f
  102. ldr1w r1, r5, abort=20f
  103. ldr1w r1, r6, abort=20f
  104. ldr1w r1, r7, abort=20f
  105. ldr1w r1, r8, abort=20f
  106. ldr1w r1, lr, abort=20f
  107. #if LDR1W_SHIFT < STR1W_SHIFT
  108. lsl ip, ip, #STR1W_SHIFT - LDR1W_SHIFT
  109. #elif LDR1W_SHIFT > STR1W_SHIFT
  110. lsr ip, ip, #LDR1W_SHIFT - STR1W_SHIFT
  111. #endif
  112. add pc, pc, ip
  113. nop
  114. .rept (1 << STR1W_SHIFT)
  115. W(nop)
  116. .endr
  117. str1w r0, r3, abort=20f
  118. str1w r0, r4, abort=20f
  119. str1w r0, r5, abort=20f
  120. str1w r0, r6, abort=20f
  121. str1w r0, r7, abort=20f
  122. str1w r0, r8, abort=20f
  123. str1w r0, lr, abort=20f
  124. CALGN( bcs 2b )
  125. 7: ldmfd sp!, {r5 - r8}
  126. 8: movs r2, r2, lsl #31
  127. ldr1b r1, r3, ne, abort=21f
  128. ldr1b r1, r4, cs, abort=21f
  129. ldr1b r1, ip, cs, abort=21f
  130. str1b r0, r3, ne, abort=21f
  131. str1b r0, r4, cs, abort=21f
  132. str1b r0, ip, cs, abort=21f
  133. exit r4, pc
  134. 9: rsb ip, ip, #4
  135. cmp ip, #2
  136. ldr1b r1, r3, gt, abort=21f
  137. ldr1b r1, r4, ge, abort=21f
  138. ldr1b r1, lr, abort=21f
  139. str1b r0, r3, gt, abort=21f
  140. str1b r0, r4, ge, abort=21f
  141. subs r2, r2, ip
  142. str1b r0, lr, abort=21f
  143. blt 8b
  144. ands ip, r1, #3
  145. beq 1b
  146. 10: bic r1, r1, #3
  147. cmp ip, #2
  148. ldr1w r1, lr, abort=21f
  149. beq 17f
  150. bgt 18f
  151. .macro forward_copy_shift pull push
  152. subs r2, r2, #28
  153. blt 14f
  154. CALGN( ands ip, r0, #31 )
  155. CALGN( rsb ip, ip, #32 )
  156. CALGN( sbcsne r4, ip, r2 ) @ C is always set here
  157. CALGN( subcc r2, r2, ip )
  158. CALGN( bcc 15f )
  159. 11: stmfd sp!, {r5 - r9}
  160. PLD( pld [r1, #0] )
  161. PLD( subs r2, r2, #96 )
  162. PLD( pld [r1, #28] )
  163. PLD( blt 13f )
  164. PLD( pld [r1, #60] )
  165. PLD( pld [r1, #92] )
  166. 12: PLD( pld [r1, #124] )
  167. 13: ldr4w r1, r4, r5, r6, r7, abort=19f
  168. mov r3, lr, lspull #\pull
  169. subs r2, r2, #32
  170. ldr4w r1, r8, r9, ip, lr, abort=19f
  171. orr r3, r3, r4, lspush #\push
  172. mov r4, r4, lspull #\pull
  173. orr r4, r4, r5, lspush #\push
  174. mov r5, r5, lspull #\pull
  175. orr r5, r5, r6, lspush #\push
  176. mov r6, r6, lspull #\pull
  177. orr r6, r6, r7, lspush #\push
  178. mov r7, r7, lspull #\pull
  179. orr r7, r7, r8, lspush #\push
  180. mov r8, r8, lspull #\pull
  181. orr r8, r8, r9, lspush #\push
  182. mov r9, r9, lspull #\pull
  183. orr r9, r9, ip, lspush #\push
  184. mov ip, ip, lspull #\pull
  185. orr ip, ip, lr, lspush #\push
  186. str8w r0, r3, r4, r5, r6, r7, r8, r9, ip, , abort=19f
  187. bge 12b
  188. PLD( cmn r2, #96 )
  189. PLD( bge 13b )
  190. ldmfd sp!, {r5 - r9}
  191. 14: ands ip, r2, #28
  192. beq 16f
  193. 15: mov r3, lr, lspull #\pull
  194. ldr1w r1, lr, abort=21f
  195. subs ip, ip, #4
  196. orr r3, r3, lr, lspush #\push
  197. str1w r0, r3, abort=21f
  198. bgt 15b
  199. CALGN( cmp r2, #0 )
  200. CALGN( bge 11b )
  201. 16: sub r1, r1, #(\push / 8)
  202. b 8b
  203. .endm
  204. forward_copy_shift pull=8 push=24
  205. 17: forward_copy_shift pull=16 push=16
  206. 18: forward_copy_shift pull=24 push=8
  207. /*
  208. * Abort preamble and completion macros.
  209. * If a fixup handler is required then those macros must surround it.
  210. * It is assumed that the fixup code will handle the private part of
  211. * the exit macro.
  212. */
  213. .macro copy_abort_preamble
  214. 19: ldmfd sp!, {r5 - r9}
  215. b 21f
  216. 20: ldmfd sp!, {r5 - r8}
  217. 21:
  218. .endm
  219. .macro copy_abort_end
  220. ldmfd sp!, {r4, pc}
  221. .endm
  222. ENDPROC(memcpy)