copy_user_64.S 2.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  1. /* SPDX-License-Identifier: GPL-2.0-only */
  2. /*
  3. * Copyright 2008 Vitaly Mayatskikh <vmayatsk@redhat.com>
  4. * Copyright 2002 Andi Kleen, SuSE Labs.
  5. *
  6. * Functions to copy from and to user space.
  7. */
  8. #include <linux/export.h>
  9. #include <linux/linkage.h>
  10. #include <asm/cpufeatures.h>
  11. #include <asm/alternative.h>
  12. #include <asm/asm.h>
  13. /*
  14. * rep_movs_alternative - memory copy with exception handling.
  15. * This version is for CPUs that don't have FSRM (Fast Short Rep Movs)
  16. *
  17. * Input:
  18. * rdi destination
  19. * rsi source
  20. * rcx count
  21. *
  22. * Output:
  23. * rcx uncopied bytes or 0 if successful.
  24. *
  25. * NOTE! The calling convention is very intentionally the same as
  26. * for 'rep movs', so that we can rewrite the function call with
  27. * just a plain 'rep movs' on machines that have FSRM. But to make
  28. * it simpler for us, we can clobber rsi/rdi and rax freely.
  29. */
  30. SYM_FUNC_START(rep_movs_alternative)
  31. cmpq $64,%rcx
  32. jae .Llarge
  33. cmp $8,%ecx
  34. jae .Lword
  35. testl %ecx,%ecx
  36. je .Lexit
  37. .Lcopy_user_tail:
  38. 0: movb (%rsi),%al
  39. 1: movb %al,(%rdi)
  40. inc %rdi
  41. inc %rsi
  42. dec %rcx
  43. jne .Lcopy_user_tail
  44. .Lexit:
  45. RET
  46. _ASM_EXTABLE_UA( 0b, .Lexit)
  47. _ASM_EXTABLE_UA( 1b, .Lexit)
  48. .p2align 4
  49. .Lword:
  50. 2: movq (%rsi),%rax
  51. 3: movq %rax,(%rdi)
  52. addq $8,%rsi
  53. addq $8,%rdi
  54. sub $8,%ecx
  55. je .Lexit
  56. cmp $8,%ecx
  57. jae .Lword
  58. jmp .Lcopy_user_tail
  59. _ASM_EXTABLE_UA( 2b, .Lcopy_user_tail)
  60. _ASM_EXTABLE_UA( 3b, .Lcopy_user_tail)
  61. .Llarge:
  62. 0: ALTERNATIVE "jmp .Llarge_movsq", "rep movsb", X86_FEATURE_ERMS
  63. 1: RET
  64. _ASM_EXTABLE_UA( 0b, 1b)
  65. .Llarge_movsq:
  66. /* Do the first possibly unaligned word */
  67. 0: movq (%rsi),%rax
  68. 1: movq %rax,(%rdi)
  69. _ASM_EXTABLE_UA( 0b, .Lcopy_user_tail)
  70. _ASM_EXTABLE_UA( 1b, .Lcopy_user_tail)
  71. /* What would be the offset to the aligned destination? */
  72. leaq 8(%rdi),%rax
  73. andq $-8,%rax
  74. subq %rdi,%rax
  75. /* .. and update pointers and count to match */
  76. addq %rax,%rdi
  77. addq %rax,%rsi
  78. subq %rax,%rcx
  79. /* make %rcx contain the number of words, %rax the remainder */
  80. movq %rcx,%rax
  81. shrq $3,%rcx
  82. andl $7,%eax
  83. 0: rep movsq
  84. movl %eax,%ecx
  85. testl %ecx,%ecx
  86. jne .Lcopy_user_tail
  87. RET
  88. 1: leaq (%rax,%rcx,8),%rcx
  89. jmp .Lcopy_user_tail
  90. _ASM_EXTABLE_UA( 0b, 1b)
  91. SYM_FUNC_END(rep_movs_alternative)
  92. EXPORT_SYMBOL(rep_movs_alternative)