1 /* SPDX-License-Identifier: GPL-2.0-only */
2 /* Copyright 2002 Andi Kleen */
4 #include <linux/export.h>
5 #include <linux/linkage.h>
6 #include <linux/cfi_types.h>
8 #include <asm/cpufeatures.h>
9 #include <asm/alternative.h>
11 .section .noinstr.text, "ax"
14 * memcpy - Copy a memory block.
22 * rax original destination
24 * The FSRM alternative should be done inline (avoiding the call and
25 * the disgusting return handling), but that would require some help
26 * from the compiler for better calling conventions.
28 * The 'rep movsb' itself is small enough to replace the call, but the
29 * two register moves blow up the code. And one of them is "needed"
30 * only for the return value that is the same as the source input,
31 * which the compiler could/should do much better anyway.
33 SYM_TYPED_FUNC_START(__memcpy)
34 ALTERNATIVE "jmp memcpy_orig", "", X86_FEATURE_FSRM
40 SYM_FUNC_END(__memcpy)
41 EXPORT_SYMBOL(__memcpy)
43 SYM_FUNC_ALIAS_MEMFUNC(memcpy, __memcpy)
46 SYM_FUNC_START_LOCAL(memcpy_orig)
53 * We check whether memory false dependence could occur,
54 * then jump to corresponding copy mode.
63 * Move in blocks of 4x8 bytes:
76 jae .Lcopy_forward_loop
82 * Calculate copy position to tail.
88 * At most 3 ALU operations in one cycle,
89 * so append NOPS in the same 16 bytes trunk.
101 movq %r10, -3*8(%rdi)
102 movq %r11, -4*8(%rdi)
103 leaq -4*8(%rdi), %rdi
104 jae .Lcopy_backward_loop
107 * Calculate copy position to head.
117 * Move data from 16 bytes to 31 bytes.
121 movq -2*8(%rsi, %rdx), %r10
122 movq -1*8(%rsi, %rdx), %r11
125 movq %r10, -2*8(%rdi, %rdx)
126 movq %r11, -1*8(%rdi, %rdx)
133 * Move data from 8 bytes to 15 bytes.
136 movq -1*8(%rsi, %rdx), %r9
138 movq %r9, -1*8(%rdi, %rdx)
146 * Move data from 4 bytes to 7 bytes.
149 movl -4(%rsi, %rdx), %r8d
151 movl %r8d, -4(%rdi, %rdx)
158 * Move data from 1 bytes to 3 bytes.
163 movzbq (%rsi, %rdx), %r9
165 movb %r9b, (%rdi, %rdx)
171 SYM_FUNC_END(memcpy_orig)