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