]> git.proxmox.com Git - mirror_edk2.git/blob - StdLib/LibC/StdLib/Malloc.c
Change the PciBusDxe driver to install the PCI enumeration complete GUID in the PCI...
[mirror_edk2.git] / StdLib / LibC / StdLib / Malloc.c
1 /** @file
2 Definitions for memory allocation routines: calloc, malloc, realloc, free.
3
4 The order and contiguity of storage allocated by successive calls to the
5 calloc, malloc, and realloc functions is unspecified. The pointer returned
6 if the allocation succeeds is suitably aligned so that it may be assigned to
7 a pointer of any type of object and then used to access such an object or an
8 array of such objects in the space allocated (until the space is explicitly
9 freed or reallocated). Each such allocation shall yield a pointer to an
10 object disjoint from any other object. The pointer returned points to the
11 start (lowest byte address) of the allocated space. If the space can not be
12 allocated, a null pointer is returned. If the size of the space requested
13 is zero, the behavior is implementation-defined; the value returned shall be
14 either a null pointer or a unique pointer. The value of a pointer that
15 refers to freed space is indeterminate.
16
17 Copyright (c) 2010, Intel Corporation. All rights reserved.<BR>
18 This program and the accompanying materials
19 are licensed and made available under the terms and conditions of the BSD License
20 which accompanies this distribution. The full text of the license may be found at
21 http://opensource.org/licenses/bsd-license.php
22
23 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
24 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
25
26 */
27 #include <Base.h>
28 #include <Uefi.h>
29 #include <Library/MemoryAllocationLib.h>
30 #include <Library/UefiBootServicesTableLib.h>
31 #include <Library/BaseMemoryLib.h>
32 #include <Library/DebugLib.h>
33
34 #include <LibConfig.h>
35
36 #include <assert.h>
37 #include <stdlib.h>
38 #include <errno.h>
39
40 /** The UEFI functions do not provide a way to determine the size of an
41 allocated region of memory given just a pointer to the start of that
42 region. Since this is required for the implementation of realloc,
43 the memory head structure from Core/Dxe/Mem/Pool.c has been reproduced
44 here.
45
46 NOTE: If the UEFI implementation is changed, the realloc function may cease
47 to function properly.
48 **/
49 #define POOL_HEAD_SIGNATURE SIGNATURE_32('p','h','d','0')
50 typedef struct {
51 UINT32 Signature;
52 UINT32 Size;
53 EFI_MEMORY_TYPE Type;
54 UINTN Reserved;
55 CHAR8 Data[1];
56 } POOL_HEAD;
57
58 /****************************/
59
60 /** The malloc function allocates space for an object whose size is specified
61 by size and whose value is indeterminate.
62
63 This implementation uses the UEFI memory allocation boot services to get a
64 region of memory that is 8-byte aligned and of the specified size. The
65 region is allocated with type EfiLoaderData.
66
67 @param size Size, in bytes, of the region to allocate.
68
69 @return NULL is returned if the space could not be allocated and errno
70 contains the cause. Otherwise, a pointer to an 8-byte aligned
71 region of the requested size is returned.<BR>
72 If NULL is returned, errno may contain:
73 - EINVAL: Requested Size is zero.
74 - ENOMEM: Memory could not be allocated.
75 **/
76 void *
77 malloc(size_t Size)
78 {
79 void *RetVal;
80 EFI_STATUS Status;
81
82 if( Size == 0) {
83 errno = EINVAL; // Make errno diffenent, just in case of a lingering ENOMEM.
84 return NULL;
85 }
86
87 Status = gBS->AllocatePool( EfiLoaderData, (UINTN)Size, &RetVal);
88 if( Status != EFI_SUCCESS) {
89 RetVal = NULL;
90 errno = ENOMEM;
91 }
92 return RetVal;
93 }
94
95 /** The calloc function allocates space for an array of Num objects, each of
96 whose size is Size. The space is initialized to all bits zero.
97
98 This implementation uses the UEFI memory allocation boot services to get a
99 region of memory that is 8-byte aligned and of the specified size. The
100 region is allocated with type EfiLoaderData.
101
102 @param Num Number of objects to allocate.
103 @param Size Size, in bytes, of the objects to allocate space for.
104
105 @return NULL is returned if the space could not be allocated and errno
106 contains the cause. Otherwise, a pointer to an 8-byte aligned
107 region of the requested size is returned.
108 **/
109 void *
110 calloc(size_t Num, size_t Size)
111 {
112 void *RetVal;
113 size_t NumSize;
114
115 NumSize = Num * Size;
116 if (NumSize == 0) {
117 return NULL;
118 }
119 RetVal = malloc(NumSize);
120 if( RetVal != NULL) {
121 (VOID)ZeroMem( RetVal, NumSize);
122 }
123 return RetVal;
124 }
125
126 /** The free function causes the space pointed to by Ptr to be deallocated,
127 that is, made available for further allocation.
128
129 If Ptr is a null pointer, no action occurs. Otherwise, if the argument
130 does not match a pointer earlier returned by the calloc, malloc, or realloc
131 function, or if the space has been deallocated by a call to free or
132 realloc, the behavior is undefined.
133
134 @param Ptr Pointer to a previously allocated region of memory to be freed.
135
136 **/
137 void
138 free(void *Ptr)
139 {
140 if(Ptr != NULL) {
141 (void) gBS->FreePool (Ptr);
142 }
143 }
144
145 /** The realloc function changes the size of the object pointed to by Ptr to
146 the size specified by NewSize.
147
148 The contents of the object are unchanged up to the lesser of the new and
149 old sizes. If the new size is larger, the value of the newly allocated
150 portion of the object is indeterminate.
151
152 If Ptr is a null pointer, the realloc function behaves like the malloc
153 function for the specified size.
154
155 If Ptr does not match a pointer earlier returned by the calloc, malloc, or
156 realloc function, or if the space has been deallocated by a call to the free
157 or realloc function, the behavior is undefined.
158
159 If the space cannot be allocated, the object pointed to by Ptr is unchanged.
160
161 If NewSize is zero and Ptr is not a null pointer, the object it points to
162 is freed.
163
164 This implementation uses the UEFI memory allocation boot services to get a
165 region of memory that is 8-byte aligned and of the specified size. The
166 region is allocated with type EfiLoaderData.
167
168 The following combinations of Ptr and NewSize can occur:<BR>
169 Ptr NewSize<BR>
170 -------- -------------------<BR>
171 - NULL 0 Returns NULL;
172 - NULL > 0 Same as malloc(NewSize)
173 - invalid X Returns NULL;
174 - valid NewSize >= OldSize Returns malloc(NewSize) with Oldsize bytes copied from Ptr
175 - valid NewSize < OldSize Returns new buffer with Oldsize bytes copied from Ptr
176 - valid 0 Return NULL. Frees Ptr.
177
178
179 @param Ptr Pointer to a previously allocated region of memory to be resized.
180 @param NewSize Size, in bytes, of the new object to allocate space for.
181
182 @return NULL is returned if the space could not be allocated and errno
183 contains the cause. Otherwise, a pointer to an 8-byte aligned
184 region of the requested size is returned. If NewSize is zero,
185 NULL is returned and errno will be unchanged.
186 **/
187 void *
188 realloc(void *Ptr, size_t NewSize)
189 {
190 void *RetVal = NULL;
191 POOL_HEAD *Head;
192 UINTN OldSize = 0;
193 UINTN NumCpy;
194
195 // Find out the size of the OLD memory region
196 if( Ptr != NULL) {
197 Head = BASE_CR (Ptr, POOL_HEAD, Data);
198 assert(Head != NULL);
199 if (Head->Signature != POOL_HEAD_SIGNATURE) {
200 errno = EFAULT;
201 return NULL;
202 }
203 OldSize = Head->Size;
204 }
205
206 // At this point, Ptr is either NULL or a valid pointer to an allocated space
207
208 if( NewSize > 0) {
209 RetVal = malloc(NewSize); // Get the NEW memory region
210 if( Ptr != NULL) { // If there is an OLD region...
211 if( RetVal != NULL) { // and the NEW region was successfully allocated
212 NumCpy = OldSize;
213 if( OldSize > NewSize) {
214 NumCpy = NewSize;
215 }
216 (VOID)CopyMem( RetVal, Ptr, NumCpy); // Copy old data to the new region.
217 free( Ptr); // and reclaim the old region.
218 }
219 }
220 }
221 else {
222 if( Ptr != NULL) {
223 free( Ptr); // Reclaim the old region.
224 }
225 }
226
227 return RetVal;
228 }