copy_user_uncached_64.S 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242
  1. /* SPDX-License-Identifier: GPL-2.0-only */
  2. /*
  3. * Copyright 2023 Linus Torvalds <torvalds@linux-foundation.org>
  4. */
  5. #include <linux/export.h>
  6. #include <linux/linkage.h>
  7. #include <asm/asm.h>
  8. /*
  9. * copy_user_nocache - Uncached memory copy with exception handling
  10. *
  11. * This copies from user space into kernel space, but the kernel
  12. * space accesses can take a machine check exception, so they too
  13. * need exception handling.
  14. *
  15. * Note: only 32-bit and 64-bit stores have non-temporal versions,
  16. * and we only use aligned versions. Any unaligned parts at the
  17. * start or end of the copy will be done using normal cached stores.
  18. *
  19. * Input:
  20. * rdi destination
  21. * rsi source
  22. * edx count
  23. *
  24. * Output:
  25. * rax uncopied bytes or 0 if successful.
  26. */
  27. SYM_FUNC_START(__copy_user_nocache)
  28. /* If destination is not 7-byte aligned, we'll have to align it */
  29. testb $7,%dil
  30. jne .Lalign
  31. .Lis_aligned:
  32. cmp $64,%edx
  33. jb .Lquadwords
  34. .p2align 4,0x90
  35. .Lunrolled:
  36. 10: movq (%rsi),%r8
  37. 11: movq 8(%rsi),%r9
  38. 12: movq 16(%rsi),%r10
  39. 13: movq 24(%rsi),%r11
  40. 20: movnti %r8,(%rdi)
  41. 21: movnti %r9,8(%rdi)
  42. 22: movnti %r10,16(%rdi)
  43. 23: movnti %r11,24(%rdi)
  44. 30: movq 32(%rsi),%r8
  45. 31: movq 40(%rsi),%r9
  46. 32: movq 48(%rsi),%r10
  47. 33: movq 56(%rsi),%r11
  48. 40: movnti %r8,32(%rdi)
  49. 41: movnti %r9,40(%rdi)
  50. 42: movnti %r10,48(%rdi)
  51. 43: movnti %r11,56(%rdi)
  52. addq $64,%rsi
  53. addq $64,%rdi
  54. sub $64,%edx
  55. cmp $64,%edx
  56. jae .Lunrolled
  57. /*
  58. * First set of user mode loads have been done
  59. * without any stores, so if they fail, we can
  60. * just try the non-unrolled loop.
  61. */
  62. _ASM_EXTABLE_UA(10b, .Lquadwords)
  63. _ASM_EXTABLE_UA(11b, .Lquadwords)
  64. _ASM_EXTABLE_UA(12b, .Lquadwords)
  65. _ASM_EXTABLE_UA(13b, .Lquadwords)
  66. /*
  67. * The second set of user mode loads have been
  68. * done with 32 bytes stored to the destination,
  69. * so we need to take that into account before
  70. * falling back to the unrolled loop.
  71. */
  72. _ASM_EXTABLE_UA(30b, .Lfixup32)
  73. _ASM_EXTABLE_UA(31b, .Lfixup32)
  74. _ASM_EXTABLE_UA(32b, .Lfixup32)
  75. _ASM_EXTABLE_UA(33b, .Lfixup32)
  76. /*
  77. * An exception on a write means that we're
  78. * done, but we need to update the count
  79. * depending on where in the unrolled loop
  80. * we were.
  81. */
  82. _ASM_EXTABLE_UA(20b, .Ldone0)
  83. _ASM_EXTABLE_UA(21b, .Ldone8)
  84. _ASM_EXTABLE_UA(22b, .Ldone16)
  85. _ASM_EXTABLE_UA(23b, .Ldone24)
  86. _ASM_EXTABLE_UA(40b, .Ldone32)
  87. _ASM_EXTABLE_UA(41b, .Ldone40)
  88. _ASM_EXTABLE_UA(42b, .Ldone48)
  89. _ASM_EXTABLE_UA(43b, .Ldone56)
  90. .Lquadwords:
  91. cmp $8,%edx
  92. jb .Llong
  93. 50: movq (%rsi),%rax
  94. 51: movnti %rax,(%rdi)
  95. addq $8,%rsi
  96. addq $8,%rdi
  97. sub $8,%edx
  98. jmp .Lquadwords
  99. /*
  100. * If we fail on the last full quadword, we will
  101. * not try to do any byte-wise cached accesses.
  102. * We will try to do one more 4-byte uncached
  103. * one, though.
  104. */
  105. _ASM_EXTABLE_UA(50b, .Llast4)
  106. _ASM_EXTABLE_UA(51b, .Ldone0)
  107. .Llong:
  108. test $4,%dl
  109. je .Lword
  110. 60: movl (%rsi),%eax
  111. 61: movnti %eax,(%rdi)
  112. addq $4,%rsi
  113. addq $4,%rdi
  114. sub $4,%edx
  115. .Lword:
  116. sfence
  117. test $2,%dl
  118. je .Lbyte
  119. 70: movw (%rsi),%ax
  120. 71: movw %ax,(%rdi)
  121. addq $2,%rsi
  122. addq $2,%rdi
  123. sub $2,%edx
  124. .Lbyte:
  125. test $1,%dl
  126. je .Ldone
  127. 80: movb (%rsi),%al
  128. 81: movb %al,(%rdi)
  129. dec %edx
  130. .Ldone:
  131. mov %edx,%eax
  132. RET
  133. /*
  134. * If we fail on the last four bytes, we won't
  135. * bother with any fixups. It's dead, Jim. Note
  136. * that there's no need for 'sfence' for any
  137. * of this, since the exception will have been
  138. * serializing.
  139. */
  140. _ASM_EXTABLE_UA(60b, .Ldone)
  141. _ASM_EXTABLE_UA(61b, .Ldone)
  142. _ASM_EXTABLE_UA(70b, .Ldone)
  143. _ASM_EXTABLE_UA(71b, .Ldone)
  144. _ASM_EXTABLE_UA(80b, .Ldone)
  145. _ASM_EXTABLE_UA(81b, .Ldone)
  146. /*
  147. * This is the "head needs aliging" case when
  148. * the destination isn't 8-byte aligned. The
  149. * 4-byte case can be done uncached, but any
  150. * smaller alignment is done with regular stores.
  151. */
  152. .Lalign:
  153. test $1,%dil
  154. je .Lalign_word
  155. test %edx,%edx
  156. je .Ldone
  157. 90: movb (%rsi),%al
  158. 91: movb %al,(%rdi)
  159. inc %rsi
  160. inc %rdi
  161. dec %edx
  162. .Lalign_word:
  163. test $2,%dil
  164. je .Lalign_long
  165. cmp $2,%edx
  166. jb .Lbyte
  167. 92: movw (%rsi),%ax
  168. 93: movw %ax,(%rdi)
  169. addq $2,%rsi
  170. addq $2,%rdi
  171. sub $2,%edx
  172. .Lalign_long:
  173. test $4,%dil
  174. je .Lis_aligned
  175. cmp $4,%edx
  176. jb .Lword
  177. 94: movl (%rsi),%eax
  178. 95: movnti %eax,(%rdi)
  179. addq $4,%rsi
  180. addq $4,%rdi
  181. sub $4,%edx
  182. jmp .Lis_aligned
  183. /*
  184. * If we fail on the initial alignment accesses,
  185. * we're all done. Again, no point in trying to
  186. * do byte-by-byte probing if the 4-byte load
  187. * fails - we're not doing any uncached accesses
  188. * any more.
  189. */
  190. _ASM_EXTABLE_UA(90b, .Ldone)
  191. _ASM_EXTABLE_UA(91b, .Ldone)
  192. _ASM_EXTABLE_UA(92b, .Ldone)
  193. _ASM_EXTABLE_UA(93b, .Ldone)
  194. _ASM_EXTABLE_UA(94b, .Ldone)
  195. _ASM_EXTABLE_UA(95b, .Ldone)
  196. /*
  197. * Exception table fixups for faults in the middle
  198. */
  199. .Ldone56: sub $8,%edx
  200. .Ldone48: sub $8,%edx
  201. .Ldone40: sub $8,%edx
  202. .Ldone32: sub $8,%edx
  203. .Ldone24: sub $8,%edx
  204. .Ldone16: sub $8,%edx
  205. .Ldone8: sub $8,%edx
  206. .Ldone0:
  207. mov %edx,%eax
  208. RET
  209. .Lfixup32:
  210. addq $32,%rsi
  211. addq $32,%rdi
  212. sub $32,%edx
  213. jmp .Lquadwords
  214. .Llast4:
  215. 52: movl (%rsi),%eax
  216. 53: movnti %eax,(%rdi)
  217. sfence
  218. sub $4,%edx
  219. mov %edx,%eax
  220. RET
  221. _ASM_EXTABLE_UA(52b, .Ldone0)
  222. _ASM_EXTABLE_UA(53b, .Ldone0)
  223. SYM_FUNC_END(__copy_user_nocache)
  224. EXPORT_SYMBOL(__copy_user_nocache)