Home | History | Annotate | Download | only in Ia32
      1 #/*++
      2 #
      3 #Copyright (c) 2006, Intel Corporation. All rights reserved.<BR>
      4 #This program and the accompanying materials
      5 #are licensed and made available under the terms and conditions of the BSD License
      6 #which accompanies this distribution.  The full text of the license may be found at
      7 #http://opensource.org/licenses/bsd-license.php
      8 #
      9 #THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     10 #WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     11 #
     12 #Module Name:
     13 #
     14 #  EfiCopyMem.c
     15 #
     16 #Abstract:
     17 #
     18 #  This is the code that supports IA32-optimized CopyMem service
     19 #
     20 #--*/
     21 #include "EfiBind.h"
     22 #---------------------------------------------------------------------------
     23     .686:
     24     #.MODEL flat,C
     25     .mmx:
     26     .code:
     27 
     28 #---------------------------------------------------------------------------
     29 
     30 .globl ASM_PFX(EfiCommonLibCopyMem)
     31 
     32 #VOID
     33 #EfiCommonLibCopyMem (
     34 #  IN VOID   *Destination,
     35 #  IN VOID   *Source,
     36 #  IN UINTN  Count
     37 #  )
     38 #/*++
     39 #
     40 #Routine Description:
     41 #
     42 #  Copy Length bytes from Source to Destination.
     43 #
     44 #Arguments:
     45 #
     46 #  Destination - Target of copy
     47 #
     48 #  Source      - Place to copy from
     49 #
     50 #  Length      - Number of bytes to copy
     51 #
     52 #Returns:
     53 #
     54 #  None
     55 #
     56 #--*/
     57 ASM_PFX(EfiCommonLibCopyMem):
     58 
     59   pushl  %ebp
     60   movl   %esp, %ebp
     61   pushl  %ecx # reserve space for Scratch Local variable UINT64 MmxSave
     62   pushl  %ecx
     63   pushl  %esi
     64   pushl  %edi
     65 
     66   movl  0x10(%ebp), %ecx  # Count
     67   movl  0xC(%ebp), %esi  # Source
     68   movl  8(%ebp), %edi  # Destination
     69 
     70 ##First off, make sure we have no overlap. That is to say,
     71 ##   if (Source == Destination)           => do nothing
     72 ##   if (Source + Count <= Destination)   => regular copy
     73 ##   if (Destination + Count <= Source)   => regular copy
     74 ##   otherwise, do a reverse copy
     75   movl  %esi, %eax
     76   addl  %ecx, %eax                    # Source + Count
     77   cmpl  %edi, %eax
     78   jbe   _StartByteCopy
     79 
     80   movl  %edi, %eax
     81   addl  %ecx, %eax                    # Dest + Count
     82   cmpl  %esi, %eax
     83   jbe   _StartByteCopy
     84 
     85   cmpl  %edi, %esi
     86   je    _CopyMemDone
     87   jb    _CopyOverlapped               # too bad -- overlaps
     88 
     89   # Pick up misaligned start bytes to get destination pointer 4-byte aligned
     90 _StartByteCopy:
     91   cmpl  $0, %ecx
     92   je    _CopyMemDone                # Count == 0, all done
     93   movl  %edi, %edx
     94   andb  $3, %dl                     # check lower 2 bits of address
     95   testb %dl, %dl
     96   je    _CopyBlocks                 # already aligned?
     97 
     98   # Copy a byte
     99   movb  (%esi), %al                 # get byte from Source
    100   movb  %al, (%edi)                 # write byte to Destination
    101   decl   %ecx
    102   incl  %edi
    103   incl  %esi
    104   jmp   _StartByteCopy               # back to top of loop
    105 
    106 _CopyBlocks:
    107   # Compute how many 64-byte blocks we can clear
    108   movl  %ecx, %eax                  # get Count in eax
    109   shrl  $6, %eax                    # convert to 64-byte count
    110   shll  $6, %eax                    # convert back to bytes
    111   subl  %eax, %ecx                  # subtract from the original count
    112   shrl  $6, %eax                    # and this is how many 64-byte blocks
    113 
    114   # If no 64-byte blocks, then skip
    115   cmpl  $0, %eax
    116   je    _CopyRemainingDWords
    117 
    118   # Save mm0 to UINT64 MmxSave
    119   movq  %mm0, -8(%ebp)
    120 
    121 copymmx:
    122 
    123   movq  %ds:(%esi), %mm0
    124   movq  %mm0, %ds:(%edi)
    125   movq  %ds:8(%esi), %mm0
    126   movq  %mm0, %ds:8(%edi)
    127   movq  %ds:16(%esi), %mm0
    128   movq  %mm0, %ds:16(%edi)
    129   movq  %ds:24(%esi), %mm0
    130   movq  %mm0, %ds:24(%edi)
    131   movq  %ds:32(%esi), %mm0
    132   movq  %mm0, %ds:32(%edi)
    133   movq  %ds:40(%esi), %mm0
    134   movq  %mm0, %ds:40(%edi)
    135   movq  %ds:48(%esi), %mm0
    136   movq  %mm0, %ds:48(%edi)
    137   movq  %ds:56(%esi), %mm0
    138   movq  %mm0, %ds:56(%edi)
    139 
    140   addl  $64, %edi
    141   addl  $64, %esi
    142   decl  %eax
    143   jnz   copymmx
    144 
    145 # Restore mm0 from MmxSave
    146   movq  -8(%ebp), %mm0
    147   emms                                 # Exit MMX Instruction
    148 
    149   # Copy as many DWORDS as possible
    150 _CopyRemainingDWords:
    151   cmpl  $4, %ecx
    152   jb    _CopyRemainingBytes
    153 
    154   movl  (%esi), %eax                # get data from Source
    155   movl  %eax, (%edi)                # write byte to Destination
    156   subl  $4, %ecx                    # decrement Count
    157   addl  $4, %esi                    # advance Source pointer
    158   addl  $4, %edi                    # advance Destination pointer
    159   jmp   _CopyRemainingDWords        # back to top
    160 
    161 _CopyRemainingBytes:
    162   cmpl  $0, %ecx
    163   je    _CopyMemDone
    164   movb  (%esi), %al                 # get byte from Source
    165   movb  %al, (%edi)                 # write byte to Destination
    166   decl   %ecx
    167   incl   %esi
    168   incl  %edi                     # advance Destination pointer
    169   jmp   _CopyRemainingBytes         # back to top of loop
    170 
    171   #
    172   # We do this block if the source and destination buffers overlap. To
    173   # handle it, copy starting at the end of the source buffer and work
    174   # your way back. Since this is the atypical case, this code has not
    175   # been optimized, and thus simply copies bytes.
    176   #
    177 _CopyOverlapped:
    178 
    179   # Move the source and destination pointers to the end of the range
    180   addl  %ecx, %esi                    # Source + Count
    181   decl   %esi
    182   addl  %ecx, %edi                    # Dest + Count
    183   decl   %edi
    184 
    185 _CopyOverlappedLoop:
    186   cmpl  $0, %ecx
    187   je    _CopyMemDone
    188   movb  (%esi), %al                 # get byte from Source
    189   movb  %al, (%edi)                 # write byte to Destination
    190   decl   %ecx
    191   decl   %esi
    192   decl  %edi
    193   jmp   _CopyOverlappedLoop         # back to top of loop
    194 
    195 _CopyMemDone:
    196 
    197   popl  %edi
    198   popl  %esi
    199   leave
    200   ret
    201 #EfiCommonLibCopyMem ENDP
    202 
    203