]> git.proxmox.com Git - mirror_edk2.git/blob - EdkCompatibilityPkg/Foundation/Library/EfiCommonLib/Ia32/EfiCopyMem.S
34487a3719e2221d9cb4d98b112ac1b995ea3b04
[mirror_edk2.git] / EdkCompatibilityPkg / Foundation / Library / EfiCommonLib / Ia32 / EfiCopyMem.S
1 #/*++
2 #
3 #Copyright (c) 2006, Intel Corporation
4 #All rights reserved. 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 jle _StartByteCopy
79
80 movl %edi, %eax
81 addl %ecx, %eax # Dest + Count
82 cmpl %esi, %eax
83 jle _StartByteCopy
84
85 cmpl %edi, %esi
86 je _CopyMemDone
87 jl _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