| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200 |
- /* SPDX-License-Identifier: GPL-2.0 */
- #include <linux/export.h>
- #include <linux/linkage.h>
- SYM_FUNC_START(memmove)
- /*
- * void *memmove(void *dest_in, const void *src_in, size_t n)
- * -mregparm=3 passes these in registers:
- * dest_in: %eax
- * src_in: %edx
- * n: %ecx
- * See also: arch/x86/entry/calling.h for description of the calling convention.
- *
- * n can remain in %ecx, but for `rep movsl`, we'll need dest in %edi and src
- * in %esi.
- */
- .set dest_in, %eax
- .set dest, %edi
- .set src_in, %edx
- .set src, %esi
- .set n, %ecx
- .set tmp0, %edx
- .set tmp0w, %dx
- .set tmp1, %ebx
- .set tmp1w, %bx
- .set tmp2, %eax
- .set tmp3b, %cl
- /*
- * Save all callee-saved registers, because this function is going to clobber
- * all of them:
- */
- pushl %ebp
- movl %esp, %ebp // set standard frame pointer
- pushl %ebx
- pushl %edi
- pushl %esi
- pushl %eax // save 'dest_in' parameter [eax] as the return value
- movl src_in, src
- movl dest_in, dest
- /* Handle more 16 bytes in loop */
- cmpl $0x10, n
- jb .Lmove_16B
- /* Decide forward/backward copy mode */
- cmpl dest, src
- jb .Lbackwards_header
- /*
- * movs instruction have many startup latency
- * so we handle small size by general register.
- */
- cmpl $680, n
- jb .Ltoo_small_forwards
- /* movs instruction is only good for aligned case. */
- movl src, tmp0
- xorl dest, tmp0
- andl $0xff, tmp0
- jz .Lforward_movs
- .Ltoo_small_forwards:
- subl $0x10, n
- /* We gobble 16 bytes forward in each loop. */
- .Lmove_16B_forwards_loop:
- subl $0x10, n
- movl 0*4(src), tmp0
- movl 1*4(src), tmp1
- movl tmp0, 0*4(dest)
- movl tmp1, 1*4(dest)
- movl 2*4(src), tmp0
- movl 3*4(src), tmp1
- movl tmp0, 2*4(dest)
- movl tmp1, 3*4(dest)
- leal 0x10(src), src
- leal 0x10(dest), dest
- jae .Lmove_16B_forwards_loop
- addl $0x10, n
- jmp .Lmove_16B
- /* Handle data forward by movs. */
- .p2align 4
- .Lforward_movs:
- movl -4(src, n), tmp0
- leal -4(dest, n), tmp1
- shrl $2, n
- rep movsl
- movl tmp0, (tmp1)
- jmp .Ldone
- /* Handle data backward by movs. */
- .p2align 4
- .Lbackwards_movs:
- movl (src), tmp0
- movl dest, tmp1
- leal -4(src, n), src
- leal -4(dest, n), dest
- shrl $2, n
- std
- rep movsl
- movl tmp0,(tmp1)
- cld
- jmp .Ldone
- /* Start to prepare for backward copy. */
- .p2align 4
- .Lbackwards_header:
- cmpl $680, n
- jb .Ltoo_small_backwards
- movl src, tmp0
- xorl dest, tmp0
- andl $0xff, tmp0
- jz .Lbackwards_movs
- /* Calculate copy position to tail. */
- .Ltoo_small_backwards:
- addl n, src
- addl n, dest
- subl $0x10, n
- /* We gobble 16 bytes backward in each loop. */
- .Lmove_16B_backwards_loop:
- subl $0x10, n
- movl -1*4(src), tmp0
- movl -2*4(src), tmp1
- movl tmp0, -1*4(dest)
- movl tmp1, -2*4(dest)
- movl -3*4(src), tmp0
- movl -4*4(src), tmp1
- movl tmp0, -3*4(dest)
- movl tmp1, -4*4(dest)
- leal -0x10(src), src
- leal -0x10(dest), dest
- jae .Lmove_16B_backwards_loop
- /* Calculate copy position to head. */
- addl $0x10, n
- subl n, src
- subl n, dest
- /* Move data from 8 bytes to 15 bytes. */
- .p2align 4
- .Lmove_16B:
- cmpl $8, n
- jb .Lmove_8B
- movl 0*4(src), tmp0
- movl 1*4(src), tmp1
- movl -2*4(src, n), tmp2
- movl -1*4(src, n), src
- movl tmp0, 0*4(dest)
- movl tmp1, 1*4(dest)
- movl tmp2, -2*4(dest, n)
- movl src, -1*4(dest, n)
- jmp .Ldone
- /* Move data from 4 bytes to 7 bytes. */
- .p2align 4
- .Lmove_8B:
- cmpl $4, n
- jb .Lmove_4B
- movl 0*4(src), tmp0
- movl -1*4(src, n), tmp1
- movl tmp0, 0*4(dest)
- movl tmp1, -1*4(dest, n)
- jmp .Ldone
- /* Move data from 2 bytes to 3 bytes. */
- .p2align 4
- .Lmove_4B:
- cmpl $2, n
- jb .Lmove_1B
- movw 0*2(src), tmp0w
- movw -1*2(src, n), tmp1w
- movw tmp0w, 0*2(dest)
- movw tmp1w, -1*2(dest, n)
- jmp .Ldone
- /* Move data for 1 byte. */
- .p2align 4
- .Lmove_1B:
- cmpl $1, n
- jb .Ldone
- movb (src), tmp3b
- movb tmp3b, (dest)
- .p2align 4
- .Ldone:
- popl dest_in // restore 'dest_in' [eax] as the return value
- /* Restore all callee-saved registers: */
- popl %esi
- popl %edi
- popl %ebx
- popl %ebp
- RET
- SYM_FUNC_END(memmove)
- EXPORT_SYMBOL(memmove)
|