copy_page.S 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390
  1. /* SPDX-License-Identifier: GPL-2.0 */
  2. /*
  3. * copy_page, __copy_user_page, __copy_user implementation of SuperH
  4. *
  5. * Copyright (C) 2001 Niibe Yutaka & Kaz Kojima
  6. * Copyright (C) 2002 Toshinobu Sugioka
  7. * Copyright (C) 2006 Paul Mundt
  8. */
  9. #include <linux/linkage.h>
  10. #include <asm/page.h>
  11. /*
  12. * copy_page
  13. * @to: P1 address
  14. * @from: P1 address
  15. *
  16. * void copy_page(void *to, void *from)
  17. */
  18. /*
  19. * r0, r1, r2, r3, r4, r5, r6, r7 --- scratch
  20. * r8 --- from + PAGE_SIZE
  21. * r9 --- not used
  22. * r10 --- to
  23. * r11 --- from
  24. */
  25. ENTRY(copy_page)
  26. mov.l r8,@-r15
  27. mov.l r10,@-r15
  28. mov.l r11,@-r15
  29. mov r4,r10
  30. mov r5,r11
  31. mov r5,r8
  32. mov #(PAGE_SIZE >> 10), r0
  33. shll8 r0
  34. shll2 r0
  35. add r0,r8
  36. !
  37. 1: mov.l @r11+,r0
  38. mov.l @r11+,r1
  39. mov.l @r11+,r2
  40. mov.l @r11+,r3
  41. mov.l @r11+,r4
  42. mov.l @r11+,r5
  43. mov.l @r11+,r6
  44. mov.l @r11+,r7
  45. #if defined(CONFIG_CPU_SH4)
  46. movca.l r0,@r10
  47. #else
  48. mov.l r0,@r10
  49. #endif
  50. add #32,r10
  51. mov.l r7,@-r10
  52. mov.l r6,@-r10
  53. mov.l r5,@-r10
  54. mov.l r4,@-r10
  55. mov.l r3,@-r10
  56. mov.l r2,@-r10
  57. mov.l r1,@-r10
  58. cmp/eq r11,r8
  59. bf/s 1b
  60. add #28,r10
  61. !
  62. mov.l @r15+,r11
  63. mov.l @r15+,r10
  64. mov.l @r15+,r8
  65. rts
  66. nop
  67. /*
  68. * __kernel_size_t __copy_user(void *to, const void *from, __kernel_size_t n);
  69. * Return the number of bytes NOT copied
  70. */
  71. #define EX(...) \
  72. 9999: __VA_ARGS__ ; \
  73. .section __ex_table, "a"; \
  74. .long 9999b, 6000f ; \
  75. .previous
  76. #define EX_NO_POP(...) \
  77. 9999: __VA_ARGS__ ; \
  78. .section __ex_table, "a"; \
  79. .long 9999b, 6005f ; \
  80. .previous
  81. ENTRY(__copy_user)
  82. ! Check if small number of bytes
  83. mov #11,r0
  84. mov r4,r3
  85. cmp/gt r0,r6 ! r6 (len) > r0 (11)
  86. bf/s .L_cleanup_loop_no_pop
  87. add r6,r3 ! last destination address
  88. ! Calculate bytes needed to align to src
  89. mov.l r11,@-r15
  90. neg r5,r0
  91. mov.l r10,@-r15
  92. add #4,r0
  93. mov.l r9,@-r15
  94. and #3,r0
  95. mov.l r8,@-r15
  96. tst r0,r0
  97. bt 2f
  98. 1:
  99. ! Copy bytes to long word align src
  100. EX( mov.b @r5+,r1 )
  101. dt r0
  102. add #-1,r6
  103. EX( mov.b r1,@r4 )
  104. bf/s 1b
  105. add #1,r4
  106. ! Jump to appropriate routine depending on dest
  107. 2: mov #3,r1
  108. mov r6, r2
  109. and r4,r1
  110. shlr2 r2
  111. shll2 r1
  112. mova .L_jump_tbl,r0
  113. mov.l @(r0,r1),r1
  114. jmp @r1
  115. nop
  116. .align 2
  117. .L_jump_tbl:
  118. .long .L_dest00
  119. .long .L_dest01
  120. .long .L_dest10
  121. .long .L_dest11
  122. /*
  123. * Come here if there are less than 12 bytes to copy
  124. *
  125. * Keep the branch target close, so the bf/s callee doesn't overflow
  126. * and result in a more expensive branch being inserted. This is the
  127. * fast-path for small copies, the jump via the jump table will hit the
  128. * default slow-path cleanup. -PFM.
  129. */
  130. .L_cleanup_loop_no_pop:
  131. tst r6,r6 ! Check explicitly for zero
  132. bt 1f
  133. 2:
  134. EX_NO_POP( mov.b @r5+,r0 )
  135. dt r6
  136. EX_NO_POP( mov.b r0,@r4 )
  137. bf/s 2b
  138. add #1,r4
  139. 1: mov #0,r0 ! normal return
  140. 5000:
  141. # Exception handler:
  142. .section .fixup, "ax"
  143. 6005:
  144. mov.l 8000f,r1
  145. mov r3,r0
  146. jmp @r1
  147. sub r4,r0
  148. .align 2
  149. 8000: .long 5000b
  150. .previous
  151. rts
  152. nop
  153. ! Destination = 00
  154. .L_dest00:
  155. ! Skip the large copy for small transfers
  156. mov #(32+32-4), r0
  157. cmp/gt r6, r0 ! r0 (60) > r6 (len)
  158. bt 1f
  159. ! Align dest to a 32 byte boundary
  160. neg r4,r0
  161. add #0x20, r0
  162. and #0x1f, r0
  163. tst r0, r0
  164. bt 2f
  165. sub r0, r6
  166. shlr2 r0
  167. 3:
  168. EX( mov.l @r5+,r1 )
  169. dt r0
  170. EX( mov.l r1,@r4 )
  171. bf/s 3b
  172. add #4,r4
  173. 2:
  174. EX( mov.l @r5+,r0 )
  175. EX( mov.l @r5+,r1 )
  176. EX( mov.l @r5+,r2 )
  177. EX( mov.l @r5+,r7 )
  178. EX( mov.l @r5+,r8 )
  179. EX( mov.l @r5+,r9 )
  180. EX( mov.l @r5+,r10 )
  181. EX( mov.l @r5+,r11 )
  182. #ifdef CONFIG_CPU_SH4
  183. EX( movca.l r0,@r4 )
  184. #else
  185. EX( mov.l r0,@r4 )
  186. #endif
  187. add #-32, r6
  188. EX( mov.l r1,@(4,r4) )
  189. mov #32, r0
  190. EX( mov.l r2,@(8,r4) )
  191. cmp/gt r6, r0 ! r0 (32) > r6 (len)
  192. EX( mov.l r7,@(12,r4) )
  193. EX( mov.l r8,@(16,r4) )
  194. EX( mov.l r9,@(20,r4) )
  195. EX( mov.l r10,@(24,r4) )
  196. EX( mov.l r11,@(28,r4) )
  197. bf/s 2b
  198. add #32,r4
  199. 1: mov r6, r0
  200. shlr2 r0
  201. tst r0, r0
  202. bt .L_cleanup
  203. 1:
  204. EX( mov.l @r5+,r1 )
  205. dt r0
  206. EX( mov.l r1,@r4 )
  207. bf/s 1b
  208. add #4,r4
  209. bra .L_cleanup
  210. nop
  211. ! Destination = 10
  212. .L_dest10:
  213. mov r2,r7
  214. shlr2 r7
  215. shlr r7
  216. tst r7,r7
  217. mov #7,r0
  218. bt/s 1f
  219. and r0,r2
  220. 2:
  221. dt r7
  222. #ifdef CONFIG_CPU_LITTLE_ENDIAN
  223. EX( mov.l @r5+,r0 )
  224. EX( mov.l @r5+,r1 )
  225. EX( mov.l @r5+,r8 )
  226. EX( mov.l @r5+,r9 )
  227. EX( mov.l @r5+,r10 )
  228. EX( mov.w r0,@r4 )
  229. add #2,r4
  230. xtrct r1,r0
  231. xtrct r8,r1
  232. xtrct r9,r8
  233. xtrct r10,r9
  234. EX( mov.l r0,@r4 )
  235. EX( mov.l r1,@(4,r4) )
  236. EX( mov.l r8,@(8,r4) )
  237. EX( mov.l r9,@(12,r4) )
  238. EX( mov.l @r5+,r1 )
  239. EX( mov.l @r5+,r8 )
  240. EX( mov.l @r5+,r0 )
  241. xtrct r1,r10
  242. xtrct r8,r1
  243. xtrct r0,r8
  244. shlr16 r0
  245. EX( mov.l r10,@(16,r4) )
  246. EX( mov.l r1,@(20,r4) )
  247. EX( mov.l r8,@(24,r4) )
  248. EX( mov.w r0,@(28,r4) )
  249. bf/s 2b
  250. add #30,r4
  251. #else
  252. EX( mov.l @(28,r5),r0 )
  253. EX( mov.l @(24,r5),r8 )
  254. EX( mov.l @(20,r5),r9 )
  255. EX( mov.l @(16,r5),r10 )
  256. EX( mov.w r0,@(30,r4) )
  257. add #-2,r4
  258. xtrct r8,r0
  259. xtrct r9,r8
  260. xtrct r10,r9
  261. EX( mov.l r0,@(28,r4) )
  262. EX( mov.l r8,@(24,r4) )
  263. EX( mov.l r9,@(20,r4) )
  264. EX( mov.l @(12,r5),r0 )
  265. EX( mov.l @(8,r5),r8 )
  266. xtrct r0,r10
  267. EX( mov.l @(4,r5),r9 )
  268. mov.l r10,@(16,r4)
  269. EX( mov.l @r5,r10 )
  270. xtrct r8,r0
  271. xtrct r9,r8
  272. xtrct r10,r9
  273. EX( mov.l r0,@(12,r4) )
  274. EX( mov.l r8,@(8,r4) )
  275. swap.w r10,r0
  276. EX( mov.l r9,@(4,r4) )
  277. EX( mov.w r0,@(2,r4) )
  278. add #32,r5
  279. bf/s 2b
  280. add #34,r4
  281. #endif
  282. tst r2,r2
  283. bt .L_cleanup
  284. 1: ! Read longword, write two words per iteration
  285. EX( mov.l @r5+,r0 )
  286. dt r2
  287. #ifdef CONFIG_CPU_LITTLE_ENDIAN
  288. EX( mov.w r0,@r4 )
  289. shlr16 r0
  290. EX( mov.w r0,@(2,r4) )
  291. #else
  292. EX( mov.w r0,@(2,r4) )
  293. shlr16 r0
  294. EX( mov.w r0,@r4 )
  295. #endif
  296. bf/s 1b
  297. add #4,r4
  298. bra .L_cleanup
  299. nop
  300. ! Destination = 01 or 11
  301. .L_dest01:
  302. .L_dest11:
  303. ! Read longword, write byte, word, byte per iteration
  304. EX( mov.l @r5+,r0 )
  305. dt r2
  306. #ifdef CONFIG_CPU_LITTLE_ENDIAN
  307. EX( mov.b r0,@r4 )
  308. shlr8 r0
  309. add #1,r4
  310. EX( mov.w r0,@r4 )
  311. shlr16 r0
  312. EX( mov.b r0,@(2,r4) )
  313. bf/s .L_dest01
  314. add #3,r4
  315. #else
  316. EX( mov.b r0,@(3,r4) )
  317. shlr8 r0
  318. swap.w r0,r7
  319. EX( mov.b r7,@r4 )
  320. add #1,r4
  321. EX( mov.w r0,@r4 )
  322. bf/s .L_dest01
  323. add #3,r4
  324. #endif
  325. ! Cleanup last few bytes
  326. .L_cleanup:
  327. mov r6,r0
  328. and #3,r0
  329. tst r0,r0
  330. bt .L_exit
  331. mov r0,r6
  332. .L_cleanup_loop:
  333. EX( mov.b @r5+,r0 )
  334. dt r6
  335. EX( mov.b r0,@r4 )
  336. bf/s .L_cleanup_loop
  337. add #1,r4
  338. .L_exit:
  339. mov #0,r0 ! normal return
  340. 5000:
  341. # Exception handler:
  342. .section .fixup, "ax"
  343. 6000:
  344. mov.l 8000f,r1
  345. mov r3,r0
  346. jmp @r1
  347. sub r4,r0
  348. .align 2
  349. 8000: .long 5000b
  350. .previous
  351. mov.l @r15+,r8
  352. mov.l @r15+,r9
  353. mov.l @r15+,r10
  354. rts
  355. mov.l @r15+,r11