]> git.proxmox.com Git - mirror_edk2.git/commitdiff
StdLib: Modify the memory allocation routines to not be dependent upon the internal...
authorDaryl McDaniel <daryl.mcdaniel@intel.com>
Fri, 7 Mar 2014 01:05:30 +0000 (01:05 +0000)
committerdarylm503 <darylm503@6f19259b-4bc3-4df7-8a09-765794883524>
Fri, 7 Mar 2014 01:05:30 +0000 (01:05 +0000)
StdLib/LibC/StdLib/Malloc.c
Create a private data structure, CPOOL_HEAD, which contains housekeeping information for StdLib’s memory allocation functions.  An instance of this structure is prepended to every chunk of allocated memory.  The structure links the allocation into a doubly-linked list and keeps track of the size of each allocation unit.  This information is then available for use by the realloc function.

Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Daryl McDaniel <daryl.mcdaniel@intel.com>
Reviewed-by: Jaben Carsey <jaben.carsey@intel.com>
Reviewed-by: Erik Bjorge <erik.c.bjorge@intel.com>
Reviewed-by: Rosenbaum, Lee G <lee.g.rosenbaum@intel.com>
git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@15319 6f19259b-4bc3-4df7-8a09-765794883524

StdLib/LibC/StdLib/Malloc.c

index 3f79deb49bed4c5294ca8b7fd00ffe40471fafda..df6e702476f9ab87dd0469b307477d4247ddff42 100644 (file)
   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
@@ -37,23 +36,31 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 #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
@@ -76,19 +83,41 @@ typedef struct {
 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
@@ -113,13 +142,15 @@ calloc(size_t Num, size_t Size)
   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
@@ -137,9 +168,24 @@ calloc(size_t Num, size_t Size)
 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
@@ -185,27 +231,31 @@ free(void *Ptr)
               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
@@ -216,13 +266,16 @@ realloc(void *Ptr, size_t NewSize)
         (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