copy_template.S 6.9 KB

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