#/*++ # #Copyright (c) 2006, Intel Corporation. All rights reserved.
#This program and the accompanying materials #are licensed and made available under the terms and conditions of the BSD License #which accompanies this distribution. The full text of the license may be found at #http://opensource.org/licenses/bsd-license.php # #THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, #WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. # #Module Name: # # EfiCopyMem.c # #Abstract: # # This is the code that supports IA32-optimized CopyMem service # #--*/ #include "EfiBind.h" #--------------------------------------------------------------------------- .686: #.MODEL flat,C .mmx: .code: #--------------------------------------------------------------------------- .globl ASM_PFX(EfiCommonLibCopyMem) #VOID #EfiCommonLibCopyMem ( # IN VOID *Destination, # IN VOID *Source, # IN UINTN Count # ) #/*++ # #Routine Description: # # Copy Length bytes from Source to Destination. # #Arguments: # # Destination - Target of copy # # Source - Place to copy from # # Length - Number of bytes to copy # #Returns: # # None # #--*/ ASM_PFX(EfiCommonLibCopyMem): pushl %ebp movl %esp, %ebp pushl %ecx # reserve space for Scratch Local variable UINT64 MmxSave pushl %ecx pushl %esi pushl %edi movl 0x10(%ebp), %ecx # Count movl 0xC(%ebp), %esi # Source movl 8(%ebp), %edi # Destination ##First off, make sure we have no overlap. That is to say, ## if (Source == Destination) => do nothing ## if (Source + Count <= Destination) => regular copy ## if (Destination + Count <= Source) => regular copy ## otherwise, do a reverse copy movl %esi, %eax addl %ecx, %eax # Source + Count cmpl %edi, %eax jbe _StartByteCopy movl %edi, %eax addl %ecx, %eax # Dest + Count cmpl %esi, %eax jbe _StartByteCopy cmpl %edi, %esi je _CopyMemDone jb _CopyOverlapped # too bad -- overlaps # Pick up misaligned start bytes to get destination pointer 4-byte aligned _StartByteCopy: cmpl $0, %ecx je _CopyMemDone # Count == 0, all done movl %edi, %edx andb $3, %dl # check lower 2 bits of address testb %dl, %dl je _CopyBlocks # already aligned? # Copy a byte movb (%esi), %al # get byte from Source movb %al, (%edi) # write byte to Destination decl %ecx incl %edi incl %esi jmp _StartByteCopy # back to top of loop _CopyBlocks: # Compute how many 64-byte blocks we can clear movl %ecx, %eax # get Count in eax shrl $6, %eax # convert to 64-byte count shll $6, %eax # convert back to bytes subl %eax, %ecx # subtract from the original count shrl $6, %eax # and this is how many 64-byte blocks # If no 64-byte blocks, then skip cmpl $0, %eax je _CopyRemainingDWords # Save mm0 to UINT64 MmxSave movq %mm0, -8(%ebp) copymmx: movq %ds:(%esi), %mm0 movq %mm0, %ds:(%edi) movq %ds:8(%esi), %mm0 movq %mm0, %ds:8(%edi) movq %ds:16(%esi), %mm0 movq %mm0, %ds:16(%edi) movq %ds:24(%esi), %mm0 movq %mm0, %ds:24(%edi) movq %ds:32(%esi), %mm0 movq %mm0, %ds:32(%edi) movq %ds:40(%esi), %mm0 movq %mm0, %ds:40(%edi) movq %ds:48(%esi), %mm0 movq %mm0, %ds:48(%edi) movq %ds:56(%esi), %mm0 movq %mm0, %ds:56(%edi) addl $64, %edi addl $64, %esi decl %eax jnz copymmx # Restore mm0 from MmxSave movq -8(%ebp), %mm0 emms # Exit MMX Instruction # Copy as many DWORDS as possible _CopyRemainingDWords: cmpl $4, %ecx jb _CopyRemainingBytes movl (%esi), %eax # get data from Source movl %eax, (%edi) # write byte to Destination subl $4, %ecx # decrement Count addl $4, %esi # advance Source pointer addl $4, %edi # advance Destination pointer jmp _CopyRemainingDWords # back to top _CopyRemainingBytes: cmpl $0, %ecx je _CopyMemDone movb (%esi), %al # get byte from Source movb %al, (%edi) # write byte to Destination decl %ecx incl %esi incl %edi # advance Destination pointer jmp _CopyRemainingBytes # back to top of loop # # We do this block if the source and destination buffers overlap. To # handle it, copy starting at the end of the source buffer and work # your way back. Since this is the atypical case, this code has not # been optimized, and thus simply copies bytes. # _CopyOverlapped: # Move the source and destination pointers to the end of the range addl %ecx, %esi # Source + Count decl %esi addl %ecx, %edi # Dest + Count decl %edi _CopyOverlappedLoop: cmpl $0, %ecx je _CopyMemDone movb (%esi), %al # get byte from Source movb %al, (%edi) # write byte to Destination decl %ecx decl %esi decl %edi jmp _CopyOverlappedLoop # back to top of loop _CopyMemDone: popl %edi popl %esi leave ret #EfiCommonLibCopyMem ENDP