copy_page.S 6.1 KB

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