]> git.proxmox.com Git - mirror_edk2.git/blame - StdLib/LibC/StdLib/Malloc.c
BaseTools/GenFfs: add FFS file types for MM modules.
[mirror_edk2.git] / StdLib / LibC / StdLib / Malloc.c
CommitLineData
2aa62f2b 1/** @file\r
2 Definitions for memory allocation routines: calloc, malloc, realloc, free.\r
3\r
4 The order and contiguity of storage allocated by successive calls to the\r
5 calloc, malloc, and realloc functions is unspecified. The pointer returned\r
6 if the allocation succeeds is suitably aligned so that it may be assigned to\r
7 a pointer of any type of object and then used to access such an object or an\r
8 array of such objects in the space allocated (until the space is explicitly\r
9 freed or reallocated). Each such allocation shall yield a pointer to an\r
10 object disjoint from any other object. The pointer returned points to the\r
11 start (lowest byte address) of the allocated space. If the space can not be\r
12 allocated, a null pointer is returned. If the size of the space requested\r
13 is zero, the behavior is implementation-defined; the value returned shall be\r
14 either a null pointer or a unique pointer. The value of a pointer that\r
15 refers to freed space is indeterminate.\r
16\r
7292c69b
DM
17 Copyright (c) 2010 - 2014, Intel Corporation. All rights reserved.<BR>\r
18 This program and the accompanying materials\r
19 are licensed and made available under the terms and conditions of the BSD License\r
20 which accompanies this distribution. The full text of the license may be found at\r
21 http://opensource.org/licenses/bsd-license.php\r
22\r
23 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
24 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
2aa62f2b 25 */\r
2aa62f2b 26#include <Uefi.h>\r
27#include <Library/MemoryAllocationLib.h>\r
28#include <Library/UefiBootServicesTableLib.h>\r
7292c69b 29#include <Library/BaseLib.h>\r
2aa62f2b 30#include <Library/BaseMemoryLib.h>\r
31#include <Library/DebugLib.h>\r
32\r
33#include <LibConfig.h>\r
34\r
35#include <assert.h>\r
36#include <stdlib.h>\r
37#include <errno.h>\r
38\r
7292c69b
DM
39#define CPOOL_HEAD_SIGNATURE SIGNATURE_32('C','p','h','d')\r
40\r
2aa62f2b 41/** The UEFI functions do not provide a way to determine the size of an\r
42 allocated region of memory given just a pointer to the start of that\r
43 region. Since this is required for the implementation of realloc,\r
7292c69b
DM
44 the memory head structure, CPOOL_HEAD, containing the necessary\r
45 information is prepended to the requested space.\r
2aa62f2b 46\r
7292c69b
DM
47 The order of members is important. This structure is 8-byte aligned,\r
48 as per the UEFI specification for memory allocation functions. By\r
49 specifying Size as a 64-bit value and placing it immediately before\r
50 Data, it ensures that Data will always be 8-byte aligned.\r
51\r
52 On IA32 systems, this structure is 24 bytes long, excluding Data.\r
53 On X64 systems, this structure is 32 bytes long, excluding Data.\r
2aa62f2b 54**/\r
2aa62f2b 55typedef struct {\r
7292c69b 56 LIST_ENTRY List;\r
2aa62f2b 57 UINT32 Signature;\r
7292c69b 58 UINT64 Size;\r
2aa62f2b 59 CHAR8 Data[1];\r
7292c69b
DM
60} CPOOL_HEAD;\r
61\r
62// List of memory allocated by malloc/calloc/etc.\r
63static LIST_ENTRY MemPoolHead = INITIALIZE_LIST_HEAD_VARIABLE(MemPoolHead);\r
2aa62f2b 64\r
65/****************************/\r
66\r
67/** The malloc function allocates space for an object whose size is specified\r
68 by size and whose value is indeterminate.\r
69\r
70 This implementation uses the UEFI memory allocation boot services to get a\r
71 region of memory that is 8-byte aligned and of the specified size. The\r
72 region is allocated with type EfiLoaderData.\r
73\r
74 @param size Size, in bytes, of the region to allocate.\r
75\r
76 @return NULL is returned if the space could not be allocated and errno\r
77 contains the cause. Otherwise, a pointer to an 8-byte aligned\r
78 region of the requested size is returned.<BR>\r
79 If NULL is returned, errno may contain:\r
80 - EINVAL: Requested Size is zero.\r
81 - ENOMEM: Memory could not be allocated.\r
82**/\r
83void *\r
84malloc(size_t Size)\r
85{\r
7292c69b 86 CPOOL_HEAD *Head;\r
69c87eff
DM
87 void *RetVal;\r
88 EFI_STATUS Status;\r
7292c69b 89 UINTN NodeSize;\r
2aa62f2b 90\r
91 if( Size == 0) {\r
92 errno = EINVAL; // Make errno diffenent, just in case of a lingering ENOMEM.\r
7292c69b 93 DEBUG((DEBUG_ERROR, "ERROR malloc: Zero Size\n"));\r
2aa62f2b 94 return NULL;\r
95 }\r
96\r
7292c69b
DM
97 NodeSize = (UINTN)(Size + sizeof(CPOOL_HEAD));\r
98\r
99 DEBUG((DEBUG_POOL, "malloc(%d): NodeSz: %d", Size, NodeSize));\r
100\r
69c87eff 101 Status = gBS->AllocatePool( EfiLoaderData, NodeSize, (void**)&Head);\r
2aa62f2b 102 if( Status != EFI_SUCCESS) {\r
103 RetVal = NULL;\r
104 errno = ENOMEM;\r
7292c69b
DM
105 DEBUG((DEBUG_ERROR, "\nERROR malloc: AllocatePool returned %r\n", Status));\r
106 }\r
107 else {\r
108 assert(Head != NULL);\r
109 // Fill out the pool header\r
110 Head->Signature = CPOOL_HEAD_SIGNATURE;\r
111 Head->Size = NodeSize;\r
112\r
113 // Add this node to the list\r
114 (void)InsertTailList(&MemPoolHead, (LIST_ENTRY *)Head);\r
115\r
116 // Return a pointer to the data\r
117 RetVal = (void*)Head->Data;\r
118 DEBUG((DEBUG_POOL, " Head: %p, Returns %p\n", Head, RetVal));\r
2aa62f2b 119 }\r
7292c69b 120\r
2aa62f2b 121 return RetVal;\r
122}\r
123\r
124/** The calloc function allocates space for an array of Num objects, each of\r
125 whose size is Size. The space is initialized to all bits zero.\r
126\r
127 This implementation uses the UEFI memory allocation boot services to get a\r
128 region of memory that is 8-byte aligned and of the specified size. The\r
129 region is allocated with type EfiLoaderData.\r
130\r
131 @param Num Number of objects to allocate.\r
132 @param Size Size, in bytes, of the objects to allocate space for.\r
133\r
134 @return NULL is returned if the space could not be allocated and errno\r
135 contains the cause. Otherwise, a pointer to an 8-byte aligned\r
136 region of the requested size is returned.\r
137**/\r
138void *\r
139calloc(size_t Num, size_t Size)\r
140{\r
141 void *RetVal;\r
142 size_t NumSize;\r
143\r
144 NumSize = Num * Size;\r
7292c69b
DM
145 RetVal = NULL;\r
146 if (NumSize != 0) {\r
2aa62f2b 147 RetVal = malloc(NumSize);\r
148 if( RetVal != NULL) {\r
149 (VOID)ZeroMem( RetVal, NumSize);\r
150 }\r
7292c69b
DM
151 }\r
152 DEBUG((DEBUG_POOL, "0x%p = calloc(%d, %d)\n", RetVal, Num, Size));\r
153\r
2aa62f2b 154 return RetVal;\r
155}\r
156\r
157/** The free function causes the space pointed to by Ptr to be deallocated,\r
158 that is, made available for further allocation.\r
159\r
160 If Ptr is a null pointer, no action occurs. Otherwise, if the argument\r
161 does not match a pointer earlier returned by the calloc, malloc, or realloc\r
162 function, or if the space has been deallocated by a call to free or\r
163 realloc, the behavior is undefined.\r
164\r
165 @param Ptr Pointer to a previously allocated region of memory to be freed.\r
166\r
167**/\r
168void\r
169free(void *Ptr)\r
170{\r
7292c69b
DM
171 CPOOL_HEAD *Head;\r
172\r
173 Head = BASE_CR(Ptr, CPOOL_HEAD, Data);\r
174 assert(Head != NULL);\r
175 DEBUG((DEBUG_POOL, "free(%p): Head: %p\n", Ptr, Head));\r
176\r
565b3c80 177 if(Ptr != NULL) {\r
7292c69b
DM
178 if (Head->Signature == CPOOL_HEAD_SIGNATURE) {\r
179 (void) RemoveEntryList((LIST_ENTRY *)Head); // Remove this node from the malloc pool\r
180 (void) gBS->FreePool (Head); // Now free the associated memory\r
181 }\r
182 else {\r
183 errno = EFAULT;\r
184 DEBUG((DEBUG_ERROR, "ERROR free(0x%p): Signature is 0x%8X, expected 0x%8X\n",\r
185 Ptr, Head->Signature, CPOOL_HEAD_SIGNATURE));\r
dfa51bb6 186 }\r
7292c69b
DM
187 }\r
188 DEBUG((DEBUG_POOL, "free Done\n"));\r
2aa62f2b 189}\r
190\r
191/** The realloc function changes the size of the object pointed to by Ptr to\r
192 the size specified by NewSize.\r
193\r
194 The contents of the object are unchanged up to the lesser of the new and\r
195 old sizes. If the new size is larger, the value of the newly allocated\r
196 portion of the object is indeterminate.\r
197\r
198 If Ptr is a null pointer, the realloc function behaves like the malloc\r
199 function for the specified size.\r
200\r
201 If Ptr does not match a pointer earlier returned by the calloc, malloc, or\r
202 realloc function, or if the space has been deallocated by a call to the free\r
203 or realloc function, the behavior is undefined.\r
204\r
205 If the space cannot be allocated, the object pointed to by Ptr is unchanged.\r
206\r
207 If NewSize is zero and Ptr is not a null pointer, the object it points to\r
208 is freed.\r
209\r
210 This implementation uses the UEFI memory allocation boot services to get a\r
211 region of memory that is 8-byte aligned and of the specified size. The\r
212 region is allocated with type EfiLoaderData.\r
213\r
214 The following combinations of Ptr and NewSize can occur:<BR>\r
215 Ptr NewSize<BR>\r
216 -------- -------------------<BR>\r
217 - NULL 0 Returns NULL;\r
218 - NULL > 0 Same as malloc(NewSize)\r
219 - invalid X Returns NULL;\r
220 - valid NewSize >= OldSize Returns malloc(NewSize) with Oldsize bytes copied from Ptr\r
221 - valid NewSize < OldSize Returns new buffer with Oldsize bytes copied from Ptr\r
222 - valid 0 Return NULL. Frees Ptr.\r
223\r
224\r
225 @param Ptr Pointer to a previously allocated region of memory to be resized.\r
226 @param NewSize Size, in bytes, of the new object to allocate space for.\r
227\r
228 @return NULL is returned if the space could not be allocated and errno\r
229 contains the cause. Otherwise, a pointer to an 8-byte aligned\r
230 region of the requested size is returned. If NewSize is zero,\r
231 NULL is returned and errno will be unchanged.\r
232**/\r
233void *\r
7292c69b 234realloc(void *Ptr, size_t ReqSize)\r
2aa62f2b 235{\r
236 void *RetVal = NULL;\r
7292c69b
DM
237 CPOOL_HEAD *Head = NULL;\r
238 size_t OldSize = 0;\r
239 size_t NewSize;\r
240 size_t NumCpy;\r
2aa62f2b 241\r
242 // Find out the size of the OLD memory region\r
243 if( Ptr != NULL) {\r
7292c69b 244 Head = BASE_CR (Ptr, CPOOL_HEAD, Data);\r
2aa62f2b 245 assert(Head != NULL);\r
7292c69b 246 if (Head->Signature != CPOOL_HEAD_SIGNATURE) {\r
2aa62f2b 247 errno = EFAULT;\r
7292c69b
DM
248 DEBUG((DEBUG_ERROR, "ERROR realloc(0x%p): Signature is 0x%8X, expected 0x%8X\n",\r
249 Ptr, Head->Signature, CPOOL_HEAD_SIGNATURE));\r
2aa62f2b 250 return NULL;\r
251 }\r
7292c69b 252 OldSize = (size_t)Head->Size;\r
2aa62f2b 253 }\r
254\r
255 // At this point, Ptr is either NULL or a valid pointer to an allocated space\r
7292c69b 256 NewSize = (size_t)(ReqSize + (sizeof(CPOOL_HEAD)));\r
2aa62f2b 257\r
7292c69b 258 if( ReqSize > 0) {\r
2aa62f2b 259 RetVal = malloc(NewSize); // Get the NEW memory region\r
260 if( Ptr != NULL) { // If there is an OLD region...\r
261 if( RetVal != NULL) { // and the NEW region was successfully allocated\r
262 NumCpy = OldSize;\r
263 if( OldSize > NewSize) {\r
264 NumCpy = NewSize;\r
265 }\r
266 (VOID)CopyMem( RetVal, Ptr, NumCpy); // Copy old data to the new region.\r
267 free( Ptr); // and reclaim the old region.\r
268 }\r
7292c69b
DM
269 else {\r
270 errno = ENOMEM;\r
271 }\r
2aa62f2b 272 }\r
273 }\r
274 else {\r
dfa51bb6
DM
275 free( Ptr); // Reclaim the old region.\r
276 }\r
7292c69b
DM
277 DEBUG((DEBUG_POOL, "0x%p = realloc(%p, %d): Head: %p NewSz: %d\n",\r
278 RetVal, Ptr, ReqSize, Head, NewSize));\r
2aa62f2b 279\r
280 return RetVal;\r
281}\r