either a null pointer or a unique pointer. The value of a pointer that\r
refers to freed space is indeterminate.\r
\r
-Copyright (c) 2010, Intel Corporation. All rights reserved.<BR>\r
-This program and the accompanying materials\r
-are licensed and made available under the terms and conditions of the BSD License\r
-which accompanies this distribution. The full text of the license may be found at\r
-http://opensource.org/licenses/bsd-license.php\r
-\r
-THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
-WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
-\r
+ Copyright (c) 2010 - 2014, Intel Corporation. All rights reserved.<BR>\r
+ This program and the accompanying materials\r
+ are licensed and made available under the terms and conditions of the BSD License\r
+ which accompanies this distribution. The full text of the license may be found at\r
+ http://opensource.org/licenses/bsd-license.php\r
+\r
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
*/\r
-#include <Base.h>\r
#include <Uefi.h>\r
#include <Library/MemoryAllocationLib.h>\r
#include <Library/UefiBootServicesTableLib.h>\r
+#include <Library/BaseLib.h>\r
#include <Library/BaseMemoryLib.h>\r
#include <Library/DebugLib.h>\r
\r
#include <stdlib.h>\r
#include <errno.h>\r
\r
+#define CPOOL_HEAD_SIGNATURE SIGNATURE_32('C','p','h','d')\r
+\r
/** The UEFI functions do not provide a way to determine the size of an\r
allocated region of memory given just a pointer to the start of that\r
region. Since this is required for the implementation of realloc,\r
- the memory head structure from Core/Dxe/Mem/Pool.c has been reproduced\r
- here.\r
+ the memory head structure, CPOOL_HEAD, containing the necessary\r
+ information is prepended to the requested space.\r
\r
- NOTE: If the UEFI implementation is changed, the realloc function may cease\r
- to function properly.\r
+ The order of members is important. This structure is 8-byte aligned,\r
+ as per the UEFI specification for memory allocation functions. By\r
+ specifying Size as a 64-bit value and placing it immediately before\r
+ Data, it ensures that Data will always be 8-byte aligned.\r
+\r
+ On IA32 systems, this structure is 24 bytes long, excluding Data.\r
+ On X64 systems, this structure is 32 bytes long, excluding Data.\r
**/\r
-#define POOL_HEAD_SIGNATURE SIGNATURE_32('p','h','d','0')\r
typedef struct {\r
+ LIST_ENTRY List;\r
UINT32 Signature;\r
- UINT32 Size;\r
- EFI_MEMORY_TYPE Type;\r
- UINTN Reserved;\r
+ UINT64 Size;\r
CHAR8 Data[1];\r
-} POOL_HEAD;\r
+} CPOOL_HEAD;\r
+\r
+// List of memory allocated by malloc/calloc/etc.\r
+static LIST_ENTRY MemPoolHead = INITIALIZE_LIST_HEAD_VARIABLE(MemPoolHead);\r
\r
/****************************/\r
\r
void *\r
malloc(size_t Size)\r
{\r
+ CPOOL_HEAD *Head;\r
void *RetVal;\r
EFI_STATUS Status;\r
+ UINTN NodeSize;\r
\r
if( Size == 0) {\r
errno = EINVAL; // Make errno diffenent, just in case of a lingering ENOMEM.\r
+ DEBUG((DEBUG_ERROR, "ERROR malloc: Zero Size\n"));\r
return NULL;\r
}\r
\r
- Status = gBS->AllocatePool( EfiLoaderData, (UINTN)Size, &RetVal);\r
+ NodeSize = (UINTN)(Size + sizeof(CPOOL_HEAD));\r
+\r
+ DEBUG((DEBUG_POOL, "malloc(%d): NodeSz: %d", Size, NodeSize));\r
+\r
+ Status = gBS->AllocatePool( EfiLoaderData, NodeSize, &Head);\r
if( Status != EFI_SUCCESS) {\r
RetVal = NULL;\r
errno = ENOMEM;\r
+ DEBUG((DEBUG_ERROR, "\nERROR malloc: AllocatePool returned %r\n", Status));\r
+ }\r
+ else {\r
+ assert(Head != NULL);\r
+ // Fill out the pool header\r
+ Head->Signature = CPOOL_HEAD_SIGNATURE;\r
+ Head->Size = NodeSize;\r
+\r
+ // Add this node to the list\r
+ (void)InsertTailList(&MemPoolHead, (LIST_ENTRY *)Head);\r
+\r
+ // Return a pointer to the data\r
+ RetVal = (void*)Head->Data;\r
+ DEBUG((DEBUG_POOL, " Head: %p, Returns %p\n", Head, RetVal));\r
}\r
+\r
return RetVal;\r
}\r
\r
size_t NumSize;\r
\r
NumSize = Num * Size;\r
- if (NumSize == 0) {\r
- return NULL;\r
- }\r
+ RetVal = NULL;\r
+ if (NumSize != 0) {\r
RetVal = malloc(NumSize);\r
if( RetVal != NULL) {\r
(VOID)ZeroMem( RetVal, NumSize);\r
}\r
+ }\r
+ DEBUG((DEBUG_POOL, "0x%p = calloc(%d, %d)\n", RetVal, Num, Size));\r
+\r
return RetVal;\r
}\r
\r
void\r
free(void *Ptr)\r
{\r
+ CPOOL_HEAD *Head;\r
+\r
+ Head = BASE_CR(Ptr, CPOOL_HEAD, Data);\r
+ assert(Head != NULL);\r
+ DEBUG((DEBUG_POOL, "free(%p): Head: %p\n", Ptr, Head));\r
+\r
if(Ptr != NULL) {\r
- (void) gBS->FreePool (Ptr);\r
+ if (Head->Signature == CPOOL_HEAD_SIGNATURE) {\r
+ (void) RemoveEntryList((LIST_ENTRY *)Head); // Remove this node from the malloc pool\r
+ (void) gBS->FreePool (Head); // Now free the associated memory\r
+ }\r
+ else {\r
+ errno = EFAULT;\r
+ DEBUG((DEBUG_ERROR, "ERROR free(0x%p): Signature is 0x%8X, expected 0x%8X\n",\r
+ Ptr, Head->Signature, CPOOL_HEAD_SIGNATURE));\r
}\r
+ }\r
+ DEBUG((DEBUG_POOL, "free Done\n"));\r
}\r
\r
/** The realloc function changes the size of the object pointed to by Ptr to\r
NULL is returned and errno will be unchanged.\r
**/\r
void *\r
-realloc(void *Ptr, size_t NewSize)\r
+realloc(void *Ptr, size_t ReqSize)\r
{\r
void *RetVal = NULL;\r
- POOL_HEAD *Head;\r
- UINTN OldSize = 0;\r
- UINTN NumCpy;\r
+ CPOOL_HEAD *Head = NULL;\r
+ size_t OldSize = 0;\r
+ size_t NewSize;\r
+ size_t NumCpy;\r
\r
// Find out the size of the OLD memory region\r
if( Ptr != NULL) {\r
- Head = BASE_CR (Ptr, POOL_HEAD, Data);\r
+ Head = BASE_CR (Ptr, CPOOL_HEAD, Data);\r
assert(Head != NULL);\r
- if (Head->Signature != POOL_HEAD_SIGNATURE) {\r
+ if (Head->Signature != CPOOL_HEAD_SIGNATURE) {\r
errno = EFAULT;\r
+ DEBUG((DEBUG_ERROR, "ERROR realloc(0x%p): Signature is 0x%8X, expected 0x%8X\n",\r
+ Ptr, Head->Signature, CPOOL_HEAD_SIGNATURE));\r
return NULL;\r
}\r
- OldSize = Head->Size;\r
+ OldSize = (size_t)Head->Size;\r
}\r
\r
// At this point, Ptr is either NULL or a valid pointer to an allocated space\r
+ NewSize = (size_t)(ReqSize + (sizeof(CPOOL_HEAD)));\r
\r
- if( NewSize > 0) {\r
+ if( ReqSize > 0) {\r
RetVal = malloc(NewSize); // Get the NEW memory region\r
if( Ptr != NULL) { // If there is an OLD region...\r
if( RetVal != NULL) { // and the NEW region was successfully allocated\r
(VOID)CopyMem( RetVal, Ptr, NumCpy); // Copy old data to the new region.\r
free( Ptr); // and reclaim the old region.\r
}\r
+ else {\r
+ errno = ENOMEM;\r
+ }\r
}\r
}\r
else {\r
- if( Ptr != NULL) {\r
free( Ptr); // Reclaim the old region.\r
}\r
- }\r
+ DEBUG((DEBUG_POOL, "0x%p = realloc(%p, %d): Head: %p NewSz: %d\n",\r
+ RetVal, Ptr, ReqSize, Head, NewSize));\r
\r
return RetVal;\r
}\r