1 /** @file
2 
3   Copyright (c) 2012-2013, ARM Ltd. All rights reserved.<BR>
4 
5   This program and the accompanying materials
6   are licensed and made available under the terms and conditions of the BSD License
7   which accompanies this distribution.  The full text of the license may be found at
8   http://opensource.org/licenses/bsd-license.php
9 
10   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12 
13 **/
14 
15 #include "MemLibInternals.h"
16 
17 /**
18   Copy Length bytes from Source to Destination.
19 
20   @param  DestinationBuffer Target of copy
21   @param  SourceBuffer      Place to copy from
22   @param  Length            Number of bytes to copy
23 
24   @return Destination
25 
26 **/
27 VOID *
28 EFIAPI
InternalMemCopyMem(OUT VOID * DestinationBuffer,IN CONST VOID * SourceBuffer,IN UINTN Length)29 InternalMemCopyMem (
30   OUT     VOID                      *DestinationBuffer,
31   IN      CONST VOID                *SourceBuffer,
32   IN      UINTN                     Length
33   )
34 {
35   //
36   // Declare the local variables that actually move the data elements as
37   // volatile to prevent the optimizer from replacing this function with
38   // the intrinsic memcpy()
39   //
40   volatile UINT8                    *Destination8;
41   CONST UINT8                       *Source8;
42   volatile UINT32                   *Destination32;
43   CONST UINT32                      *Source32;
44   volatile UINT64                   *Destination64;
45   CONST UINT64                      *Source64;
46   UINTN                             Alignment;
47 
48   if ((((UINTN)DestinationBuffer & 0x7) == 0) && (((UINTN)SourceBuffer & 0x7) == 0) && (Length >= 8)) {
49     if (SourceBuffer > DestinationBuffer) {
50       Destination64 = (UINT64*)DestinationBuffer;
51       Source64 = (CONST UINT64*)SourceBuffer;
52       while (Length >= 8) {
53         *(Destination64++) = *(Source64++);
54         Length -= 8;
55       }
56 
57       // Finish if there are still some bytes to copy
58       Destination8 = (UINT8*)Destination64;
59       Source8 = (CONST UINT8*)Source64;
60       while (Length-- != 0) {
61         *(Destination8++) = *(Source8++);
62       }
63     } else if (SourceBuffer < DestinationBuffer) {
64       Destination64 = (UINT64*)((UINTN)DestinationBuffer + Length);
65       Source64 = (CONST UINT64*)((UINTN)SourceBuffer + Length);
66 
67       // Destination64 and Source64 were aligned on a 64-bit boundary
68       // but if length is not a multiple of 8 bytes then they won't be
69       // anymore.
70 
71       Alignment = Length & 0x7;
72       if (Alignment != 0) {
73         Destination8 = (UINT8*)Destination64;
74         Source8 = (CONST UINT8*)Source64;
75 
76         while (Alignment-- != 0) {
77           *(--Destination8) = *(--Source8);
78           --Length;
79         }
80         Destination64 = (UINT64*)Destination8;
81         Source64 = (CONST UINT64*)Source8;
82       }
83 
84       while (Length > 0) {
85         *(--Destination64) = *(--Source64);
86         Length -= 8;
87       }
88     }
89   } else if ((((UINTN)DestinationBuffer & 0x3) == 0) && (((UINTN)SourceBuffer & 0x3) == 0) && (Length >= 4)) {
90     if (SourceBuffer > DestinationBuffer) {
91       Destination32 = (UINT32*)DestinationBuffer;
92       Source32 = (CONST UINT32*)SourceBuffer;
93       while (Length >= 4) {
94         *(Destination32++) = *(Source32++);
95         Length -= 4;
96       }
97 
98       // Finish if there are still some bytes to copy
99       Destination8 = (UINT8*)Destination32;
100       Source8 = (CONST UINT8*)Source32;
101       while (Length-- != 0) {
102         *(Destination8++) = *(Source8++);
103       }
104     } else if (SourceBuffer < DestinationBuffer) {
105       Destination32 = (UINT32*)((UINTN)DestinationBuffer + Length);
106       Source32 = (CONST UINT32*)((UINTN)SourceBuffer + Length);
107 
108       // Destination32 and Source32 were aligned on a 32-bit boundary
109       // but if length is not a multiple of 4 bytes then they won't be
110       // anymore.
111 
112       Alignment = Length & 0x3;
113       if (Alignment != 0) {
114         Destination8 = (UINT8*)Destination32;
115         Source8 = (CONST UINT8*)Source32;
116 
117         while (Alignment-- != 0) {
118           *(--Destination8) = *(--Source8);
119           --Length;
120         }
121         Destination32 = (UINT32*)Destination8;
122         Source32 = (CONST UINT32*)Source8;
123       }
124 
125       while (Length > 0) {
126         *(--Destination32) = *(--Source32);
127         Length -= 4;
128       }
129     }
130   } else {
131     if (SourceBuffer > DestinationBuffer) {
132       Destination8 = (UINT8*)DestinationBuffer;
133       Source8 = (CONST UINT8*)SourceBuffer;
134       while (Length-- != 0) {
135         *(Destination8++) = *(Source8++);
136       }
137     } else if (SourceBuffer < DestinationBuffer) {
138       Destination8 = (UINT8*)DestinationBuffer + Length;
139       Source8 = (CONST UINT8*)SourceBuffer + Length;
140       while (Length-- != 0) {
141         *(--Destination8) = *(--Source8);
142       }
143     }
144   }
145   return DestinationBuffer;
146 }
147