copy_page.S 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397
  1. /* $Id: copy_page.S,v 1.8 2003/08/25 17:03:10 lethal Exp $
  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. *
  8. */
  9. #include <linux/linkage.h>
  10. /*
  11. * copy_page_slow
  12. * @to: P1 address
  13. * @from: P1 address
  14. *
  15. * void copy_page_slow(void *to, void *from)
  16. */
  17. /*
  18. * r0, r1, r2, r3, r4, r5, r6, r7 --- scratch
  19. * r8 --- from + 4096
  20. * r9 --- not used
  21. * r10 --- to
  22. * r11 --- from
  23. */
  24. ENTRY(copy_page_slow)
  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.w .L4096,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_SH3)
  43. mov.l r0,@r10
  44. #elif defined(CONFIG_CPU_SH4)
  45. movca.l r0,@r10
  46. mov r10,r0
  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. #if defined(CONFIG_CPU_SH4)
  69. /*
  70. * __copy_user_page
  71. * @to: P1 address (with same color)
  72. * @from: P1 address
  73. * @orig_to: P1 address
  74. *
  75. * void __copy_user_page(void *to, void *from, void *orig_to)
  76. */
  77. /*
  78. * r0, r1, r2, r3, r4, r5, r6, r7 --- scratch
  79. * r8 --- from + 4096
  80. * r9 --- orig_to
  81. * r10 --- to
  82. * r11 --- from
  83. */
  84. ENTRY(__copy_user_page)
  85. mov.l r8,@-r15
  86. mov.l r9,@-r15
  87. mov.l r10,@-r15
  88. mov.l r11,@-r15
  89. mov r4,r10
  90. mov r5,r11
  91. mov r6,r9
  92. mov r5,r8
  93. mov.w .L4096,r0
  94. add r0,r8
  95. !
  96. 1: ocbi @r9
  97. add #32,r9
  98. mov.l @r11+,r0
  99. mov.l @r11+,r1
  100. mov.l @r11+,r2
  101. mov.l @r11+,r3
  102. mov.l @r11+,r4
  103. mov.l @r11+,r5
  104. mov.l @r11+,r6
  105. mov.l @r11+,r7
  106. movca.l r0,@r10
  107. mov r10,r0
  108. add #32,r10
  109. mov.l r7,@-r10
  110. mov.l r6,@-r10
  111. mov.l r5,@-r10
  112. mov.l r4,@-r10
  113. mov.l r3,@-r10
  114. mov.l r2,@-r10
  115. mov.l r1,@-r10
  116. ocbwb @r0
  117. cmp/eq r11,r8
  118. bf/s 1b
  119. add #28,r10
  120. !
  121. mov.l @r15+,r11
  122. mov.l @r15+,r10
  123. mov.l @r15+,r9
  124. mov.l @r15+,r8
  125. rts
  126. nop
  127. #endif
  128. .L4096: .word 4096
  129. /*
  130. * __kernel_size_t __copy_user(void *to, const void *from, __kernel_size_t n);
  131. * Return the number of bytes NOT copied
  132. */
  133. #define EX(...) \
  134. 9999: __VA_ARGS__ ; \
  135. .section __ex_table, "a"; \
  136. .long 9999b, 6000f ; \
  137. .previous
  138. ENTRY(__copy_user)
  139. tst r6,r6 ! Check explicitly for zero
  140. bf 1f
  141. rts
  142. mov #0,r0 ! normal return
  143. 1:
  144. mov.l r10,@-r15
  145. mov.l r9,@-r15
  146. mov.l r8,@-r15
  147. mov r4,r3
  148. add r6,r3 ! last destination address
  149. mov #12,r0 ! Check if small number of bytes
  150. cmp/gt r0,r6
  151. bt 2f
  152. bra .L_cleanup_loop
  153. nop
  154. 2:
  155. neg r5,r0 ! Calculate bytes needed to align source
  156. add #4,r0
  157. and #3,r0
  158. tst r0,r0
  159. bt .L_jump
  160. mov r0,r1
  161. .L_loop1:
  162. ! Copy bytes to align source
  163. EX( mov.b @r5+,r0 )
  164. dt r1
  165. EX( mov.b r0,@r4 )
  166. add #-1,r6
  167. bf/s .L_loop1
  168. add #1,r4
  169. .L_jump:
  170. mov r6,r2 ! Calculate number of longwords to copy
  171. shlr2 r2
  172. tst r2,r2
  173. bt .L_cleanup
  174. mov r4,r0 ! Jump to appropriate routine
  175. and #3,r0
  176. mov r0,r1
  177. shll2 r1
  178. mova .L_jump_tbl,r0
  179. mov.l @(r0,r1),r1
  180. jmp @r1
  181. nop
  182. .align 2
  183. .L_jump_tbl:
  184. .long .L_dest00
  185. .long .L_dest01
  186. .long .L_dest10
  187. .long .L_dest11
  188. ! Destination = 00
  189. .L_dest00:
  190. mov r2,r7
  191. shlr2 r7
  192. shlr r7
  193. tst r7,r7
  194. mov #7,r0
  195. bt/s 1f
  196. and r0,r2
  197. .align 2
  198. 2:
  199. EX( mov.l @r5+,r0 )
  200. EX( mov.l @r5+,r8 )
  201. EX( mov.l @r5+,r9 )
  202. EX( mov.l @r5+,r10 )
  203. EX( mov.l r0,@r4 )
  204. EX( mov.l r8,@(4,r4) )
  205. EX( mov.l r9,@(8,r4) )
  206. EX( mov.l r10,@(12,r4) )
  207. EX( mov.l @r5+,r0 )
  208. EX( mov.l @r5+,r8 )
  209. EX( mov.l @r5+,r9 )
  210. EX( mov.l @r5+,r10 )
  211. dt r7
  212. EX( mov.l r0,@(16,r4) )
  213. EX( mov.l r8,@(20,r4) )
  214. EX( mov.l r9,@(24,r4) )
  215. EX( mov.l r10,@(28,r4) )
  216. bf/s 2b
  217. add #32,r4
  218. tst r2,r2
  219. bt .L_cleanup
  220. 1:
  221. EX( mov.l @r5+,r0 )
  222. dt r2
  223. EX( mov.l r0,@r4 )
  224. bf/s 1b
  225. add #4,r4
  226. bra .L_cleanup
  227. nop
  228. ! Destination = 10
  229. .L_dest10:
  230. mov r2,r7
  231. shlr2 r7
  232. shlr r7
  233. tst r7,r7
  234. mov #7,r0
  235. bt/s 1f
  236. and r0,r2
  237. 2:
  238. dt r7
  239. #ifdef __LITTLE_ENDIAN__
  240. EX( mov.l @r5+,r0 )
  241. EX( mov.l @r5+,r1 )
  242. EX( mov.l @r5+,r8 )
  243. EX( mov.l @r5+,r9 )
  244. EX( mov.l @r5+,r10 )
  245. EX( mov.w r0,@r4 )
  246. add #2,r4
  247. xtrct r1,r0
  248. xtrct r8,r1
  249. xtrct r9,r8
  250. xtrct r10,r9
  251. EX( mov.l r0,@r4 )
  252. EX( mov.l r1,@(4,r4) )
  253. EX( mov.l r8,@(8,r4) )
  254. EX( mov.l r9,@(12,r4) )
  255. EX( mov.l @r5+,r1 )
  256. EX( mov.l @r5+,r8 )
  257. EX( mov.l @r5+,r0 )
  258. xtrct r1,r10
  259. xtrct r8,r1
  260. xtrct r0,r8
  261. shlr16 r0
  262. EX( mov.l r10,@(16,r4) )
  263. EX( mov.l r1,@(20,r4) )
  264. EX( mov.l r8,@(24,r4) )
  265. EX( mov.w r0,@(28,r4) )
  266. bf/s 2b
  267. add #30,r4
  268. #else
  269. EX( mov.l @(28,r5),r0 )
  270. EX( mov.l @(24,r5),r8 )
  271. EX( mov.l @(20,r5),r9 )
  272. EX( mov.l @(16,r5),r10 )
  273. EX( mov.w r0,@(30,r4) )
  274. add #-2,r4
  275. xtrct r8,r0
  276. xtrct r9,r8
  277. xtrct r10,r9
  278. EX( mov.l r0,@(28,r4) )
  279. EX( mov.l r8,@(24,r4) )
  280. EX( mov.l r9,@(20,r4) )
  281. EX( mov.l @(12,r5),r0 )
  282. EX( mov.l @(8,r5),r8 )
  283. xtrct r0,r10
  284. EX( mov.l @(4,r5),r9 )
  285. mov.l r10,@(16,r4)
  286. EX( mov.l @r5,r10 )
  287. xtrct r8,r0
  288. xtrct r9,r8
  289. xtrct r10,r9
  290. EX( mov.l r0,@(12,r4) )
  291. EX( mov.l r8,@(8,r4) )
  292. swap.w r10,r0
  293. EX( mov.l r9,@(4,r4) )
  294. EX( mov.w r0,@(2,r4) )
  295. add #32,r5
  296. bf/s 2b
  297. add #34,r4
  298. #endif
  299. tst r2,r2
  300. bt .L_cleanup
  301. 1: ! Read longword, write two words per iteration
  302. EX( mov.l @r5+,r0 )
  303. dt r2
  304. #ifdef __LITTLE_ENDIAN__
  305. EX( mov.w r0,@r4 )
  306. shlr16 r0
  307. EX( mov.w r0,@(2,r4) )
  308. #else
  309. EX( mov.w r0,@(2,r4) )
  310. shlr16 r0
  311. EX( mov.w r0,@r4 )
  312. #endif
  313. bf/s 1b
  314. add #4,r4
  315. bra .L_cleanup
  316. nop
  317. ! Destination = 01 or 11
  318. .L_dest01:
  319. .L_dest11:
  320. ! Read longword, write byte, word, byte per iteration
  321. EX( mov.l @r5+,r0 )
  322. dt r2
  323. #ifdef __LITTLE_ENDIAN__
  324. EX( mov.b r0,@r4 )
  325. shlr8 r0
  326. add #1,r4
  327. EX( mov.w r0,@r4 )
  328. shlr16 r0
  329. EX( mov.b r0,@(2,r4) )
  330. bf/s .L_dest01
  331. add #3,r4
  332. #else
  333. EX( mov.b r0,@(3,r4) )
  334. shlr8 r0
  335. swap.w r0,r7
  336. EX( mov.b r7,@r4 )
  337. add #1,r4
  338. EX( mov.w r0,@r4 )
  339. bf/s .L_dest01
  340. add #3,r4
  341. #endif
  342. ! Cleanup last few bytes
  343. .L_cleanup:
  344. mov r6,r0
  345. and #3,r0
  346. tst r0,r0
  347. bt .L_exit
  348. mov r0,r6
  349. .L_cleanup_loop:
  350. EX( mov.b @r5+,r0 )
  351. dt r6
  352. EX( mov.b r0,@r4 )
  353. bf/s .L_cleanup_loop
  354. add #1,r4
  355. .L_exit:
  356. mov #0,r0 ! normal return
  357. 5000:
  358. # Exception handler:
  359. .section .fixup, "ax"
  360. 6000:
  361. mov.l 8000f,r1
  362. mov r3,r0
  363. jmp @r1
  364. sub r4,r0
  365. .align 2
  366. 8000: .long 5000b
  367. .previous
  368. mov.l @r15+,r8
  369. mov.l @r15+,r9
  370. rts
  371. mov.l @r15+,r10