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