copy_template.S 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273
  1. /* SPDX-License-Identifier: GPL-2.0-only */
  2. /*
  3. * linux/arch/arm/lib/copy_template.s
  4. *
  5. * Code template for optimized memory copy functions
  6. *
  7. * Author: Nicolas Pitre
  8. * Created: Sep 28, 2005
  9. * Copyright: MontaVista Software, Inc.
  10. */
  11. /*
  12. * Theory of operation
  13. * -------------------
  14. *
  15. * This file provides the core code for a forward memory copy used in
  16. * the implementation of memcopy(), copy_to_user() and copy_from_user().
  17. *
  18. * The including file must define the following accessor macros
  19. * according to the need of the given function:
  20. *
  21. * ldr1w ptr reg abort
  22. *
  23. * This loads one word from 'ptr', stores it in 'reg' and increments
  24. * 'ptr' to the next word. The 'abort' argument is used for fixup tables.
  25. *
  26. * ldr4w ptr reg1 reg2 reg3 reg4 abort
  27. * ldr8w ptr, reg1 reg2 reg3 reg4 reg5 reg6 reg7 reg8 abort
  28. *
  29. * This loads four or eight words starting from 'ptr', stores them
  30. * in provided registers and increments 'ptr' past those words.
  31. * The'abort' argument is used for fixup tables.
  32. *
  33. * ldr1b ptr reg cond abort
  34. *
  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 the
  37. * "al" condition is assumed by default.
  38. *
  39. * str1w ptr reg abort
  40. * str8w ptr reg1 reg2 reg3 reg4 reg5 reg6 reg7 reg8 abort
  41. * str1b ptr reg cond abort
  42. *
  43. * Same as their ldr* counterparts, but data is stored to 'ptr' location
  44. * rather than being loaded.
  45. *
  46. * enter reg1 reg2
  47. *
  48. * Preserve the provided registers on the stack plus any additional
  49. * data as needed by the implementation including this code. Called
  50. * upon code entry.
  51. *
  52. * usave reg1 reg2
  53. *
  54. * Unwind annotation macro is corresponding for 'enter' macro.
  55. * It tell unwinder that preserved some provided registers on the stack
  56. * and additional data by a prior 'enter' macro.
  57. *
  58. * exit reg1 reg2
  59. *
  60. * Restore registers with the values previously saved with the
  61. * 'preserv' macro. Called upon code termination.
  62. *
  63. * LDR1W_SHIFT
  64. * STR1W_SHIFT
  65. *
  66. * Correction to be applied to the "ip" register when branching into
  67. * the ldr1w or str1w instructions (some of these macros may expand to
  68. * than one 32bit instruction in Thumb-2)
  69. */
  70. UNWIND( .fnstart )
  71. enter r4, UNWIND(fpreg,) lr
  72. UNWIND( .setfp fpreg, sp )
  73. UNWIND( mov fpreg, sp )
  74. subs r2, r2, #4
  75. blt 8f
  76. ands ip, r0, #3
  77. PLD( pld [r1, #0] )
  78. bne 9f
  79. ands ip, r1, #3
  80. bne 10f
  81. 1: subs r2, r2, #(28)
  82. stmfd sp!, {r5, r6, r8, r9}
  83. blt 5f
  84. CALGN( ands ip, r0, #31 )
  85. CALGN( rsb r3, ip, #32 )
  86. CALGN( sbcsne r4, r3, r2 ) @ C is always set here
  87. CALGN( bcs 2f )
  88. CALGN( adr r4, 6f )
  89. CALGN( subs r2, r2, r3 ) @ C gets set
  90. CALGN( add pc, r4, ip )
  91. PLD( pld [r1, #0] )
  92. 2: PLD( subs r2, r2, #96 )
  93. PLD( pld [r1, #28] )
  94. PLD( blt 4f )
  95. PLD( pld [r1, #60] )
  96. PLD( pld [r1, #92] )
  97. 3: PLD( pld [r1, #124] )
  98. 4: ldr8w r1, r3, r4, r5, r6, r8, r9, ip, lr, abort=20f
  99. subs r2, r2, #32
  100. str8w r0, r3, r4, r5, r6, r8, r9, ip, lr, abort=20f
  101. bge 3b
  102. PLD( cmn r2, #96 )
  103. PLD( bge 4b )
  104. 5: ands ip, r2, #28
  105. rsb ip, ip, #32
  106. #if LDR1W_SHIFT > 0
  107. lsl ip, ip, #LDR1W_SHIFT
  108. #endif
  109. addne pc, pc, ip @ C is always clear here
  110. b 7f
  111. 6:
  112. .rept (1 << LDR1W_SHIFT)
  113. W(nop)
  114. .endr
  115. ldr1w r1, r3, abort=20f
  116. ldr1w r1, r4, abort=20f
  117. ldr1w r1, r5, abort=20f
  118. ldr1w r1, r6, abort=20f
  119. ldr1w r1, r8, abort=20f
  120. ldr1w r1, r9, abort=20f
  121. ldr1w r1, lr, abort=20f
  122. #if LDR1W_SHIFT < STR1W_SHIFT
  123. lsl ip, ip, #STR1W_SHIFT - LDR1W_SHIFT
  124. #elif LDR1W_SHIFT > STR1W_SHIFT
  125. lsr ip, ip, #LDR1W_SHIFT - STR1W_SHIFT
  126. #endif
  127. add pc, pc, ip
  128. nop
  129. .rept (1 << STR1W_SHIFT)
  130. W(nop)
  131. .endr
  132. str1w r0, r3, abort=20f
  133. str1w r0, r4, abort=20f
  134. str1w r0, r5, abort=20f
  135. str1w r0, r6, abort=20f
  136. str1w r0, r8, abort=20f
  137. str1w r0, r9, abort=20f
  138. str1w r0, lr, abort=20f
  139. CALGN( bcs 2b )
  140. 7: ldmfd sp!, {r5, r6, r8, r9}
  141. 8: movs r2, r2, lsl #31
  142. ldr1b r1, r3, ne, abort=21f
  143. ldr1b r1, r4, cs, abort=21f
  144. ldr1b r1, ip, cs, abort=21f
  145. str1b r0, r3, ne, abort=21f
  146. str1b r0, r4, cs, abort=21f
  147. str1b r0, ip, cs, abort=21f
  148. exit r4, UNWIND(fpreg,) pc
  149. 9: rsb ip, ip, #4
  150. cmp ip, #2
  151. ldr1b r1, r3, gt, abort=21f
  152. ldr1b r1, r4, ge, abort=21f
  153. ldr1b r1, lr, abort=21f
  154. str1b r0, r3, gt, abort=21f
  155. str1b r0, r4, ge, abort=21f
  156. subs r2, r2, ip
  157. str1b r0, lr, abort=21f
  158. blt 8b
  159. ands ip, r1, #3
  160. beq 1b
  161. 10: bic r1, r1, #3
  162. cmp ip, #2
  163. ldr1w r1, lr, abort=21f
  164. beq 17f
  165. bgt 18f
  166. .macro forward_copy_shift pull push
  167. subs r2, r2, #28
  168. blt 14f
  169. CALGN( ands ip, r0, #31 )
  170. CALGN( rsb ip, ip, #32 )
  171. CALGN( sbcsne r4, ip, r2 ) @ C is always set here
  172. CALGN( subcc r2, r2, ip )
  173. CALGN( bcc 15f )
  174. 11: stmfd sp!, {r5, r6, r8 - r10}
  175. PLD( pld [r1, #0] )
  176. PLD( subs r2, r2, #96 )
  177. PLD( pld [r1, #28] )
  178. PLD( blt 13f )
  179. PLD( pld [r1, #60] )
  180. PLD( pld [r1, #92] )
  181. 12: PLD( pld [r1, #124] )
  182. 13: ldr4w r1, r4, r5, r6, r8, abort=19f
  183. mov r3, lr, lspull #\pull
  184. subs r2, r2, #32
  185. ldr4w r1, r9, r10, ip, lr, abort=19f
  186. orr r3, r3, r4, lspush #\push
  187. mov r4, r4, lspull #\pull
  188. orr r4, r4, r5, lspush #\push
  189. mov r5, r5, lspull #\pull
  190. orr r5, r5, r6, lspush #\push
  191. mov r6, r6, lspull #\pull
  192. orr r6, r6, r8, lspush #\push
  193. mov r8, r8, lspull #\pull
  194. orr r8, r8, r9, lspush #\push
  195. mov r9, r9, lspull #\pull
  196. orr r9, r9, r10, lspush #\push
  197. mov r10, r10, lspull #\pull
  198. orr r10, r10, ip, lspush #\push
  199. mov ip, ip, lspull #\pull
  200. orr ip, ip, lr, lspush #\push
  201. str8w r0, r3, r4, r5, r6, r8, r9, r10, ip, abort=19f
  202. bge 12b
  203. PLD( cmn r2, #96 )
  204. PLD( bge 13b )
  205. ldmfd sp!, {r5, r6, r8 - r10}
  206. 14: ands ip, r2, #28
  207. beq 16f
  208. 15: mov r3, lr, lspull #\pull
  209. ldr1w r1, lr, abort=21f
  210. subs ip, ip, #4
  211. orr r3, r3, lr, lspush #\push
  212. str1w r0, r3, abort=21f
  213. bgt 15b
  214. CALGN( cmp r2, #0 )
  215. CALGN( bge 11b )
  216. 16: sub r1, r1, #(\push / 8)
  217. b 8b
  218. .endm
  219. forward_copy_shift pull=8 push=24
  220. 17: forward_copy_shift pull=16 push=16
  221. 18: forward_copy_shift pull=24 push=8
  222. UNWIND( .fnend )
  223. /*
  224. * Abort preamble and completion macros.
  225. * If a fixup handler is required then those macros must surround it.
  226. * It is assumed that the fixup code will handle the private part of
  227. * the exit macro.
  228. */
  229. .macro copy_abort_preamble
  230. 19: ldmfd sp!, {r5, r6, r8 - r10}
  231. b 21f
  232. 20: ldmfd sp!, {r5, r6, r8, r9}
  233. 21:
  234. .endm
  235. .macro copy_abort_end
  236. ldmfd sp!, {r4, UNWIND(fpreg,) pc}
  237. .endm