copy_user_64.S 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268
  1. /*
  2. * Copyright 2008 Vitaly Mayatskikh <vmayatsk@redhat.com>
  3. * Copyright 2002 Andi Kleen, SuSE Labs.
  4. * Subject to the GNU Public License v2.
  5. *
  6. * Functions to copy from and to user space.
  7. */
  8. #include <linux/linkage.h>
  9. #include <asm/dwarf2.h>
  10. #define FIX_ALIGNMENT 1
  11. #include <asm/current.h>
  12. #include <asm/asm-offsets.h>
  13. #include <asm/thread_info.h>
  14. #include <asm/cpufeature.h>
  15. .macro ALTERNATIVE_JUMP feature,orig,alt
  16. 0:
  17. .byte 0xe9 /* 32bit jump */
  18. .long \orig-1f /* by default jump to orig */
  19. 1:
  20. .section .altinstr_replacement,"ax"
  21. 2: .byte 0xe9 /* near jump with 32bit immediate */
  22. .long \alt-1b /* offset */ /* or alternatively to alt */
  23. .previous
  24. .section .altinstructions,"a"
  25. .align 8
  26. .quad 0b
  27. .quad 2b
  28. .byte \feature /* when feature is set */
  29. .byte 5
  30. .byte 5
  31. .previous
  32. .endm
  33. .macro ALIGN_DESTINATION
  34. #ifdef FIX_ALIGNMENT
  35. /* check for bad alignment of destination */
  36. movl %edi,%ecx
  37. andl $7,%ecx
  38. jz 102f /* already aligned */
  39. subl $8,%ecx
  40. negl %ecx
  41. subl %ecx,%edx
  42. 100: movb (%rsi),%al
  43. 101: movb %al,(%rdi)
  44. incq %rsi
  45. incq %rdi
  46. decl %ecx
  47. jnz 100b
  48. 102:
  49. .section .fixup,"ax"
  50. 103: addl %ecx,%edx /* ecx is zerorest also */
  51. jmp copy_user_handle_tail
  52. .previous
  53. .section __ex_table,"a"
  54. .align 8
  55. .quad 100b,103b
  56. .quad 101b,103b
  57. .previous
  58. #endif
  59. .endm
  60. /* Standard copy_to_user with segment limit checking */
  61. ENTRY(copy_to_user)
  62. CFI_STARTPROC
  63. GET_THREAD_INFO(%rax)
  64. movq %rdi,%rcx
  65. addq %rdx,%rcx
  66. jc bad_to_user
  67. cmpq TI_addr_limit(%rax),%rcx
  68. jae bad_to_user
  69. ALTERNATIVE_JUMP X86_FEATURE_REP_GOOD,copy_user_generic_unrolled,copy_user_generic_string
  70. CFI_ENDPROC
  71. /* Standard copy_from_user with segment limit checking */
  72. ENTRY(copy_from_user)
  73. CFI_STARTPROC
  74. GET_THREAD_INFO(%rax)
  75. movq %rsi,%rcx
  76. addq %rdx,%rcx
  77. jc bad_from_user
  78. cmpq TI_addr_limit(%rax),%rcx
  79. jae bad_from_user
  80. ALTERNATIVE_JUMP X86_FEATURE_REP_GOOD,copy_user_generic_unrolled,copy_user_generic_string
  81. CFI_ENDPROC
  82. ENDPROC(copy_from_user)
  83. ENTRY(copy_user_generic)
  84. CFI_STARTPROC
  85. ALTERNATIVE_JUMP X86_FEATURE_REP_GOOD,copy_user_generic_unrolled,copy_user_generic_string
  86. CFI_ENDPROC
  87. ENDPROC(copy_user_generic)
  88. ENTRY(__copy_from_user_inatomic)
  89. CFI_STARTPROC
  90. ALTERNATIVE_JUMP X86_FEATURE_REP_GOOD,copy_user_generic_unrolled,copy_user_generic_string
  91. CFI_ENDPROC
  92. ENDPROC(__copy_from_user_inatomic)
  93. .section .fixup,"ax"
  94. /* must zero dest */
  95. ENTRY(bad_from_user)
  96. bad_from_user:
  97. CFI_STARTPROC
  98. movl %edx,%ecx
  99. xorl %eax,%eax
  100. rep
  101. stosb
  102. bad_to_user:
  103. movl %edx,%eax
  104. ret
  105. CFI_ENDPROC
  106. ENDPROC(bad_from_user)
  107. .previous
  108. /*
  109. * copy_user_generic_unrolled - memory copy with exception handling.
  110. * This version is for CPUs like P4 that don't have efficient micro
  111. * code for rep movsq
  112. *
  113. * Input:
  114. * rdi destination
  115. * rsi source
  116. * rdx count
  117. *
  118. * Output:
  119. * eax uncopied bytes or 0 if successfull.
  120. */
  121. ENTRY(copy_user_generic_unrolled)
  122. CFI_STARTPROC
  123. cmpl $8,%edx
  124. jb 20f /* less then 8 bytes, go to byte copy loop */
  125. ALIGN_DESTINATION
  126. movl %edx,%ecx
  127. andl $63,%edx
  128. shrl $6,%ecx
  129. jz 17f
  130. 1: movq (%rsi),%r8
  131. 2: movq 1*8(%rsi),%r9
  132. 3: movq 2*8(%rsi),%r10
  133. 4: movq 3*8(%rsi),%r11
  134. 5: movq %r8,(%rdi)
  135. 6: movq %r9,1*8(%rdi)
  136. 7: movq %r10,2*8(%rdi)
  137. 8: movq %r11,3*8(%rdi)
  138. 9: movq 4*8(%rsi),%r8
  139. 10: movq 5*8(%rsi),%r9
  140. 11: movq 6*8(%rsi),%r10
  141. 12: movq 7*8(%rsi),%r11
  142. 13: movq %r8,4*8(%rdi)
  143. 14: movq %r9,5*8(%rdi)
  144. 15: movq %r10,6*8(%rdi)
  145. 16: movq %r11,7*8(%rdi)
  146. leaq 64(%rsi),%rsi
  147. leaq 64(%rdi),%rdi
  148. decl %ecx
  149. jnz 1b
  150. 17: movl %edx,%ecx
  151. andl $7,%edx
  152. shrl $3,%ecx
  153. jz 20f
  154. 18: movq (%rsi),%r8
  155. 19: movq %r8,(%rdi)
  156. leaq 8(%rsi),%rsi
  157. leaq 8(%rdi),%rdi
  158. decl %ecx
  159. jnz 18b
  160. 20: andl %edx,%edx
  161. jz 23f
  162. movl %edx,%ecx
  163. 21: movb (%rsi),%al
  164. 22: movb %al,(%rdi)
  165. incq %rsi
  166. incq %rdi
  167. decl %ecx
  168. jnz 21b
  169. 23: xor %eax,%eax
  170. ret
  171. .section .fixup,"ax"
  172. 30: shll $6,%ecx
  173. addl %ecx,%edx
  174. jmp 60f
  175. 40: lea (%rdx,%rcx,8),%rdx
  176. jmp 60f
  177. 50: movl %ecx,%edx
  178. 60: jmp copy_user_handle_tail /* ecx is zerorest also */
  179. .previous
  180. .section __ex_table,"a"
  181. .align 8
  182. .quad 1b,30b
  183. .quad 2b,30b
  184. .quad 3b,30b
  185. .quad 4b,30b
  186. .quad 5b,30b
  187. .quad 6b,30b
  188. .quad 7b,30b
  189. .quad 8b,30b
  190. .quad 9b,30b
  191. .quad 10b,30b
  192. .quad 11b,30b
  193. .quad 12b,30b
  194. .quad 13b,30b
  195. .quad 14b,30b
  196. .quad 15b,30b
  197. .quad 16b,30b
  198. .quad 18b,40b
  199. .quad 19b,40b
  200. .quad 21b,50b
  201. .quad 22b,50b
  202. .previous
  203. CFI_ENDPROC
  204. ENDPROC(copy_user_generic_unrolled)
  205. /* Some CPUs run faster using the string copy instructions.
  206. * This is also a lot simpler. Use them when possible.
  207. *
  208. * Only 4GB of copy is supported. This shouldn't be a problem
  209. * because the kernel normally only writes from/to page sized chunks
  210. * even if user space passed a longer buffer.
  211. * And more would be dangerous because both Intel and AMD have
  212. * errata with rep movsq > 4GB. If someone feels the need to fix
  213. * this please consider this.
  214. *
  215. * Input:
  216. * rdi destination
  217. * rsi source
  218. * rdx count
  219. *
  220. * Output:
  221. * eax uncopied bytes or 0 if successful.
  222. */
  223. ENTRY(copy_user_generic_string)
  224. CFI_STARTPROC
  225. andl %edx,%edx
  226. jz 4f
  227. cmpl $8,%edx
  228. jb 2f /* less than 8 bytes, go to byte copy loop */
  229. ALIGN_DESTINATION
  230. movl %edx,%ecx
  231. shrl $3,%ecx
  232. andl $7,%edx
  233. 1: rep
  234. movsq
  235. 2: movl %edx,%ecx
  236. 3: rep
  237. movsb
  238. 4: xorl %eax,%eax
  239. ret
  240. .section .fixup,"ax"
  241. 11: lea (%rdx,%rcx,8),%rcx
  242. 12: movl %ecx,%edx /* ecx is zerorest also */
  243. jmp copy_user_handle_tail
  244. .previous
  245. .section __ex_table,"a"
  246. .align 8
  247. .quad 1b,11b
  248. .quad 3b,12b
  249. .previous
  250. CFI_ENDPROC
  251. ENDPROC(copy_user_generic_string)