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