1 /*++
2 
3 Copyright (c) 2006 - 2010, 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 
22 #include "Tiano.h"
23 
24 VOID
EfiCommonLibCopyMem(IN VOID * Destination,IN VOID * Source,IN UINTN Count)25 EfiCommonLibCopyMem (
26   IN VOID   *Destination,
27   IN VOID   *Source,
28   IN UINTN  Count
29   )
30 /*++
31 
32 Routine Description:
33 
34   Copy Length bytes from Source to Destination.
35 
36 Arguments:
37 
38   Destination - Target of copy
39 
40   Source      - Place to copy from
41 
42   Length      - Number of bytes to copy
43 
44 Returns:
45 
46   None
47 
48 --*/
49 {
50   UINT64 MmxSave;
51   __asm {
52 
53   mov   ecx, Count
54   mov   esi, Source
55   mov   edi, Destination
56 
57   ; First off, make sure we have no overlap. That is to say,
58   ;   if (Source == Destination)           => do nothing
59   ;   if (Source + Count <= Destination)   => regular copy
60   ;   if (Destination + Count <= Source)   => regular copy
61   ;   if (Source >= Destination)           => regular copy
62   ;   otherwise, do a reverse copy
63   mov   eax, esi
64   add   eax, ecx                      ; Source + Count
65   cmp   eax, edi
66   jbe   _StartByteCopy
67 
68   mov   eax, edi
69   add   eax, ecx                      ; Dest + Count
70   cmp   eax, esi
71   jbe   _StartByteCopy
72 
73   cmp   esi, edi
74   je    _CopyMemDone
75   jb    _CopyOverlapped               ; too bad -- overlaps
76 
77   ; Pick up misaligned start bytes to get destination pointer 4-byte aligned
78 _StartByteCopy:
79   cmp   ecx, 0
80   je    _CopyMemDone                ; Count == 0, all done
81   mov   edx, edi
82   and   dl, 3                       ; check lower 2 bits of address
83   test  dl, dl
84   je    SHORT _CopyBlocks           ; already aligned?
85 
86   ; Copy a byte
87   mov   al, BYTE PTR [esi]          ; get byte from Source
88   mov   BYTE PTR [edi], al          ; write byte to Destination
89   dec    ecx
90   inc   edi
91   inc   esi
92   jmp   _StartByteCopy               ; back to top of loop
93 
94 _CopyBlocks:
95   ; Compute how many 64-byte blocks we can clear
96   mov   eax, ecx                    ; get Count in eax
97   shr   eax, 6                      ; convert to 64-byte count
98   shl   eax, 6                      ; convert back to bytes
99   sub   ecx, eax                    ; subtract from the original count
100   shr   eax, 6                      ; and this is how many 64-byte blocks
101 
102   ; If no 64-byte blocks, then skip
103   cmp   eax, 0
104   je    _CopyRemainingDWords
105 
106   ; Save mm0
107   movq  MmxSave, mm0
108 
109 copymmx:
110 
111   movq  mm0, QWORD PTR ds:[esi]
112   movq  QWORD PTR ds:[edi], mm0
113   movq  mm0, QWORD PTR ds:[esi+8]
114   movq  QWORD PTR ds:[edi+8], mm0
115   movq  mm0, QWORD PTR ds:[esi+16]
116   movq  QWORD PTR ds:[edi+16], mm0
117   movq  mm0, QWORD PTR ds:[esi+24]
118   movq  QWORD PTR ds:[edi+24], mm0
119   movq  mm0, QWORD PTR ds:[esi+32]
120   movq  QWORD PTR ds:[edi+32], mm0
121   movq  mm0, QWORD PTR ds:[esi+40]
122   movq  QWORD PTR ds:[edi+40], mm0
123   movq  mm0, QWORD PTR ds:[esi+48]
124   movq  QWORD PTR ds:[edi+48], mm0
125   movq  mm0, QWORD PTR ds:[esi+56]
126   movq  QWORD PTR ds:[edi+56], mm0
127 
128   add   edi, 64
129   add   esi, 64
130   dec   eax
131   jnz   copymmx
132 
133 ; Restore mm0
134   movq  mm0, MmxSave
135   emms                                 ; Exit MMX Instruction
136 
137   ; Copy as many DWORDS as possible
138 _CopyRemainingDWords:
139   cmp   ecx, 4
140   jb    _CopyRemainingBytes
141 
142   mov   eax, DWORD PTR [esi]        ; get data from Source
143   mov   DWORD PTR [edi], eax        ; write byte to Destination
144   sub   ecx, 4                      ; decrement Count
145   add   esi, 4                      ; advance Source pointer
146   add   edi, 4                      ; advance Destination pointer
147   jmp   _CopyRemainingDWords        ; back to top
148 
149 _CopyRemainingBytes:
150   cmp   ecx, 0
151   je    _CopyMemDone
152   mov   al, BYTE PTR [esi]          ; get byte from Source
153   mov   BYTE PTR [edi], al          ; write byte to Destination
154   dec    ecx
155   inc    esi
156   inc   edi                      ; advance Destination pointer
157   jmp   SHORT _CopyRemainingBytes   ; back to top of loop
158 
159   ;
160   ; We do this block if the source and destination buffers overlap. To
161   ; handle it, copy starting at the end of the source buffer and work
162   ; your way back. Since this is the atypical case, this code has not
163   ; been optimized, and thus simply copies bytes.
164   ;
165 _CopyOverlapped:
166 
167   ; Move the source and destination pointers to the end of the range
168   add   esi, ecx                      ; Source + Count
169   dec    esi
170   add   edi, ecx                      ; Dest + Count
171   dec    edi
172 
173 _CopyOverlappedLoop:
174   cmp   ecx, 0
175   je    _CopyMemDone
176   mov   al, BYTE PTR [esi]          ; get byte from Source
177   mov   BYTE PTR [edi], al          ; write byte to Destination
178   dec    ecx
179   dec    esi
180   dec   edi
181   jmp   _CopyOverlappedLoop         ; back to top of loop
182 
183 _CopyMemDone:
184   }
185 }
186