-/** @file \r
-\r
+/** @file\r
UEFI Memory pool management functions.\r
\r
-Copyright (c) 2006 - 2008, Intel Corporation \r
-All rights reserved. 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
+Copyright (c) 2006 - 2016, 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
**/\r
\r
-#include <DxeMain.h>\r
+#include "DxeMain.h"\r
+#include "Imem.h"\r
+\r
+STATIC EFI_LOCK mPoolMemoryLock = EFI_INITIALIZE_LOCK_VARIABLE (TPL_NOTIFY);\r
\r
-#define POOL_FREE_SIGNATURE EFI_SIGNATURE_32('p','f','r','0')\r
+#define POOL_FREE_SIGNATURE SIGNATURE_32('p','f','r','0')\r
typedef struct {\r
UINT32 Signature;\r
UINT32 Index;\r
} POOL_FREE;\r
\r
\r
-#define POOL_HEAD_SIGNATURE EFI_SIGNATURE_32('p','h','d','0')\r
+#define POOL_HEAD_SIGNATURE SIGNATURE_32('p','h','d','0')\r
typedef struct {\r
UINT32 Signature;\r
- UINT32 Size;\r
+ UINT32 Reserved;\r
EFI_MEMORY_TYPE Type;\r
- UINTN Reserved;\r
+ UINTN Size;\r
CHAR8 Data[1];\r
} POOL_HEAD;\r
\r
-#define SIZE_OF_POOL_HEAD EFI_FIELD_OFFSET(POOL_HEAD,Data)\r
+#define SIZE_OF_POOL_HEAD OFFSET_OF(POOL_HEAD,Data)\r
\r
-#define POOL_TAIL_SIGNATURE EFI_SIGNATURE_32('p','t','a','l')\r
+#define POOL_TAIL_SIGNATURE SIGNATURE_32('p','t','a','l')\r
typedef struct {\r
UINT32 Signature;\r
- UINT32 Size;\r
+ UINT32 Reserved;\r
+ UINTN Size;\r
} POOL_TAIL;\r
\r
-\r
-#define POOL_SHIFT 7\r
-\r
#define POOL_OVERHEAD (SIZE_OF_POOL_HEAD + sizeof(POOL_TAIL))\r
\r
#define HEAD_TO_TAIL(a) \\r
((POOL_TAIL *) (((CHAR8 *) (a)) + (a)->Size - sizeof(POOL_TAIL)));\r
\r
+//\r
+// Each element is the sum of the 2 previous ones: this allows us to migrate\r
+// blocks between bins by splitting them up, while not wasting too much memory\r
+// as we would in a strict power-of-2 sequence\r
+//\r
+STATIC CONST UINT16 mPoolSizeTable[] = {\r
+ 128, 256, 384, 640, 1024, 1664, 2688, 4352, 7040, 11392, 18432, 29824\r
+};\r
\r
-#define SIZE_TO_LIST(a) ((a) >> POOL_SHIFT)\r
-#define LIST_TO_SIZE(a) ((a+1) << POOL_SHIFT)\r
+#define SIZE_TO_LIST(a) (GetPoolIndexFromSize (a))\r
+#define LIST_TO_SIZE(a) (mPoolSizeTable [a])\r
\r
-#define MAX_POOL_LIST SIZE_TO_LIST(DEFAULT_PAGE_ALLOCATION)\r
+#define MAX_POOL_LIST (ARRAY_SIZE (mPoolSizeTable))\r
\r
#define MAX_POOL_SIZE (MAX_ADDRESS - POOL_OVERHEAD)\r
\r
// Globals\r
//\r
\r
-#define POOL_SIGNATURE EFI_SIGNATURE_32('p','l','s','t')\r
+#define POOL_SIGNATURE SIGNATURE_32('p','l','s','t')\r
typedef struct {\r
INTN Signature;\r
UINTN Used;\r
EFI_MEMORY_TYPE MemoryType;\r
LIST_ENTRY FreeList[MAX_POOL_LIST];\r
LIST_ENTRY Link;\r
-} POOL; \r
-\r
-\r
-POOL PoolHead[EfiMaxMemoryType];\r
-LIST_ENTRY PoolHeadList;\r
+} POOL;\r
\r
//\r
+// Pool header for each memory type.\r
+//\r
+POOL mPoolHead[EfiMaxMemoryType];\r
+\r
//\r
+// List of pool header to search for the appropriate memory type.\r
//\r
+LIST_ENTRY mPoolHeadList = INITIALIZE_LIST_HEAD_VARIABLE (mPoolHeadList);\r
+\r
+/**\r
+ Get pool size table index from the specified size.\r
+\r
+ @param Size The specified size to get index from pool table.\r
\r
+ @return The index of pool size table.\r
+\r
+**/\r
+STATIC\r
+UINTN\r
+GetPoolIndexFromSize (\r
+ UINTN Size\r
+ )\r
+{\r
+ UINTN Index;\r
+\r
+ for (Index = 0; Index < MAX_POOL_LIST; Index++) {\r
+ if (mPoolSizeTable [Index] >= Size) {\r
+ return Index;\r
+ }\r
+ }\r
+ return MAX_POOL_LIST;\r
+}\r
\r
/**\r
Called to initialize the pool.\r
UINTN Index;\r
\r
for (Type=0; Type < EfiMaxMemoryType; Type++) {\r
- PoolHead[Type].Signature = 0;\r
- PoolHead[Type].Used = 0;\r
- PoolHead[Type].MemoryType = (EFI_MEMORY_TYPE) Type;\r
+ mPoolHead[Type].Signature = 0;\r
+ mPoolHead[Type].Used = 0;\r
+ mPoolHead[Type].MemoryType = (EFI_MEMORY_TYPE) Type;\r
for (Index=0; Index < MAX_POOL_LIST; Index++) {\r
- InitializeListHead (&PoolHead[Type].FreeList[Index]);\r
+ InitializeListHead (&mPoolHead[Type].FreeList[Index]);\r
}\r
}\r
- InitializeListHead (&PoolHeadList);\r
}\r
\r
\r
/**\r
Look up pool head for specified memory type.\r
\r
- @param MemoryType Memory type of which pool head is looked for \r
+ @param MemoryType Memory type of which pool head is looked for\r
\r
@return Pointer of Corresponding pool head.\r
\r
**/\r
-STATIC\r
POOL *\r
LookupPoolHead (\r
IN EFI_MEMORY_TYPE MemoryType\r
POOL *Pool;\r
UINTN Index;\r
\r
- if (MemoryType >= 0 && MemoryType < EfiMaxMemoryType) {\r
- return &PoolHead[MemoryType];\r
+ if ((UINT32)MemoryType < EfiMaxMemoryType) {\r
+ return &mPoolHead[MemoryType];\r
}\r
\r
- if (MemoryType < 0) {\r
+ //\r
+ // MemoryType values in the range 0x80000000..0xFFFFFFFF are reserved for use by UEFI\r
+ // OS loaders that are provided by operating system vendors.\r
+ // MemoryType values in the range 0x70000000..0x7FFFFFFF are reserved for OEM use.\r
+ //\r
+ if ((UINT32) MemoryType >= MEMORY_TYPE_OEM_RESERVED_MIN) {\r
\r
- for (Link = PoolHeadList.ForwardLink; Link != &PoolHeadList; Link = Link->ForwardLink) {\r
+ for (Link = mPoolHeadList.ForwardLink; Link != &mPoolHeadList; Link = Link->ForwardLink) {\r
Pool = CR(Link, POOL, Link, POOL_SIGNATURE);\r
if (Pool->MemoryType == MemoryType) {\r
return Pool;\r
InitializeListHead (&Pool->FreeList[Index]);\r
}\r
\r
- InsertHeadList (&PoolHeadList, &Pool->Link);\r
+ InsertHeadList (&mPoolHeadList, &Pool->Link);\r
\r
return Pool;\r
}\r
return NULL;\r
}\r
\r
- \r
\r
\r
/**\r
Allocate pool of a particular type.\r
\r
- @param PoolType Type of pool to allocate \r
- @param Size The amount of pool to allocate \r
- @param Buffer The address to return a pointer to the allocated \r
- pool \r
+ @param PoolType Type of pool to allocate\r
+ @param Size The amount of pool to allocate\r
+ @param Buffer The address to return a pointer to the allocated\r
+ pool\r
\r
- @retval EFI_INVALID_PARAMETER PoolType not valid \r
- @retval EFI_OUT_OF_RESOURCES Size exceeds max pool size or allocation failed. \r
+ @retval EFI_INVALID_PARAMETER Buffer is NULL.\r
+ PoolType is in the range EfiMaxMemoryType..0x6FFFFFFF.\r
+ PoolType is EfiPersistentMemory.\r
+ @retval EFI_OUT_OF_RESOURCES Size exceeds max pool size or allocation failed.\r
@retval EFI_SUCCESS Pool successfully allocated.\r
\r
**/\r
EFI_STATUS\r
EFIAPI\r
-CoreAllocatePool (\r
+CoreInternalAllocatePool (\r
IN EFI_MEMORY_TYPE PoolType,\r
IN UINTN Size,\r
OUT VOID **Buffer\r
//\r
// If it's not a valid type, fail it\r
//\r
- if ((PoolType >= EfiMaxMemoryType && PoolType <= 0x7fffffff) ||\r
- PoolType == EfiConventionalMemory) {\r
+ if ((PoolType >= EfiMaxMemoryType && PoolType < MEMORY_TYPE_OEM_RESERVED_MIN) ||\r
+ (PoolType == EfiConventionalMemory) || (PoolType == EfiPersistentMemory)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (Buffer == NULL) {\r
return EFI_INVALID_PARAMETER;\r
}\r
- \r
+\r
*Buffer = NULL;\r
- \r
+\r
//\r
// If size is too large, fail it\r
// Base on the EFI spec, return status of EFI_OUT_OF_RESOURCES\r
//\r
// Acquire the memory lock and make the allocation\r
//\r
- Status = CoreAcquireLockOrFail (&gMemoryLock);\r
+ Status = CoreAcquireLockOrFail (&mPoolMemoryLock);\r
if (EFI_ERROR (Status)) {\r
return EFI_OUT_OF_RESOURCES;\r
}\r
\r
*Buffer = CoreAllocatePoolI (PoolType, Size);\r
- CoreReleaseMemoryLock ();\r
+ CoreReleaseLock (&mPoolMemoryLock);\r
return (*Buffer != NULL) ? EFI_SUCCESS : EFI_OUT_OF_RESOURCES;\r
}\r
\r
+/**\r
+ Allocate pool of a particular type.\r
+\r
+ @param PoolType Type of pool to allocate\r
+ @param Size The amount of pool to allocate\r
+ @param Buffer The address to return a pointer to the allocated\r
+ pool\r
+\r
+ @retval EFI_INVALID_PARAMETER Buffer is NULL.\r
+ PoolType is in the range EfiMaxMemoryType..0x6FFFFFFF.\r
+ PoolType is EfiPersistentMemory.\r
+ @retval EFI_OUT_OF_RESOURCES Size exceeds max pool size or allocation failed.\r
+ @retval EFI_SUCCESS Pool successfully allocated.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+CoreAllocatePool (\r
+ IN EFI_MEMORY_TYPE PoolType,\r
+ IN UINTN Size,\r
+ OUT VOID **Buffer\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ Status = CoreInternalAllocatePool (PoolType, Size, Buffer);\r
+ if (!EFI_ERROR (Status)) {\r
+ CoreUpdateProfile (\r
+ (EFI_PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS (0),\r
+ MemoryProfileActionAllocatePool,\r
+ PoolType,\r
+ Size,\r
+ *Buffer,\r
+ NULL\r
+ );\r
+ InstallMemoryAttributesTableOnMemoryAllocation (PoolType);\r
+ }\r
+ return Status;\r
+}\r
+\r
+STATIC\r
+VOID *\r
+CoreAllocatePoolPagesI (\r
+ IN EFI_MEMORY_TYPE PoolType,\r
+ IN UINTN NoPages,\r
+ IN UINTN Granularity\r
+ )\r
+{\r
+ VOID *Buffer;\r
+ EFI_STATUS Status;\r
\r
+ Status = CoreAcquireLockOrFail (&gMemoryLock);\r
+ if (EFI_ERROR (Status)) {\r
+ return NULL;\r
+ }\r
+\r
+ Buffer = CoreAllocatePoolPages (PoolType, NoPages, Granularity);\r
+ CoreReleaseMemoryLock ();\r
+\r
+ if (Buffer != NULL) {\r
+ ApplyMemoryProtectionPolicy (EfiConventionalMemory, PoolType,\r
+ (EFI_PHYSICAL_ADDRESS)(UINTN)Buffer, EFI_PAGES_TO_SIZE (NoPages));\r
+ }\r
+ return Buffer;\r
+}\r
\r
/**\r
Internal function to allocate pool of a particular type.\r
Caller must have the memory lock held\r
\r
- @param PoolType Type of pool to allocate \r
- @param Size The amount of pool to allocate \r
+ @param PoolType Type of pool to allocate\r
+ @param Size The amount of pool to allocate\r
\r
@return The allocate pool, or NULL\r
\r
VOID *Buffer;\r
UINTN Index;\r
UINTN FSize;\r
- UINTN Offset;\r
- UINTN Adjustment;\r
+ UINTN Offset, MaxOffset;\r
UINTN NoPages;\r
+ UINTN Granularity;\r
+\r
+ ASSERT_LOCKED (&mPoolMemoryLock);\r
+\r
+ if (PoolType == EfiACPIReclaimMemory ||\r
+ PoolType == EfiACPIMemoryNVS ||\r
+ PoolType == EfiRuntimeServicesCode ||\r
+ PoolType == EfiRuntimeServicesData) {\r
\r
- ASSERT_LOCKED (&gMemoryLock);\r
+ Granularity = RUNTIME_PAGE_ALLOCATION_GRANULARITY;\r
+ } else {\r
+ Granularity = DEFAULT_PAGE_ALLOCATION_GRANULARITY;\r
+ }\r
\r
//\r
// Adjust the size by the pool header & tail overhead\r
//\r
- \r
+\r
//\r
// Adjusting the Size to be of proper alignment so that\r
// we don't get an unaligned access fault later when\r
// pool_Tail is being initialized\r
//\r
- ALIGN_VARIABLE (Size, Adjustment);\r
+ Size = ALIGN_VARIABLE (Size);\r
\r
Size += POOL_OVERHEAD;\r
Index = SIZE_TO_LIST(Size);\r
// If allocation is over max size, just allocate pages for the request\r
// (slow)\r
//\r
- if (Index >= MAX_POOL_LIST) {\r
- NoPages = EFI_SIZE_TO_PAGES(Size) + EFI_SIZE_TO_PAGES (DEFAULT_PAGE_ALLOCATION) - 1;\r
- NoPages &= ~(EFI_SIZE_TO_PAGES (DEFAULT_PAGE_ALLOCATION) - 1);\r
- Head = CoreAllocatePoolPages (PoolType, NoPages, DEFAULT_PAGE_ALLOCATION);\r
+ if (Index >= SIZE_TO_LIST (Granularity)) {\r
+ NoPages = EFI_SIZE_TO_PAGES(Size) + EFI_SIZE_TO_PAGES (Granularity) - 1;\r
+ NoPages &= ~(UINTN)(EFI_SIZE_TO_PAGES (Granularity) - 1);\r
+ Head = CoreAllocatePoolPagesI (PoolType, NoPages, Granularity);\r
goto Done;\r
}\r
\r
//\r
if (IsListEmpty (&Pool->FreeList[Index])) {\r
\r
+ Offset = LIST_TO_SIZE (Index);\r
+ MaxOffset = Granularity;\r
+\r
+ //\r
+ // Check the bins holding larger blocks, and carve one up if needed\r
+ //\r
+ while (++Index < SIZE_TO_LIST (Granularity)) {\r
+ if (!IsListEmpty (&Pool->FreeList[Index])) {\r
+ Free = CR (Pool->FreeList[Index].ForwardLink, POOL_FREE, Link, POOL_FREE_SIGNATURE);\r
+ RemoveEntryList (&Free->Link);\r
+ NewPage = (VOID *) Free;\r
+ MaxOffset = LIST_TO_SIZE (Index);\r
+ goto Carve;\r
+ }\r
+ }\r
+\r
//\r
// Get another page\r
//\r
- NewPage = CoreAllocatePoolPages(PoolType, EFI_SIZE_TO_PAGES (DEFAULT_PAGE_ALLOCATION), DEFAULT_PAGE_ALLOCATION);\r
+ NewPage = CoreAllocatePoolPagesI (PoolType, EFI_SIZE_TO_PAGES (Granularity), Granularity);\r
if (NewPage == NULL) {\r
goto Done;\r
}\r
\r
//\r
- // Carve up new page into free pool blocks\r
+ // Serve the allocation request from the head of the allocated block\r
+ //\r
+Carve:\r
+ Head = (POOL_HEAD *) NewPage;\r
+\r
+ //\r
+ // Carve up remaining space into free pool blocks\r
//\r
- Offset = 0;\r
- while (Offset < DEFAULT_PAGE_ALLOCATION) {\r
+ Index--;\r
+ while (Offset < MaxOffset) {\r
ASSERT (Index < MAX_POOL_LIST);\r
FSize = LIST_TO_SIZE(Index);\r
\r
- while (Offset + FSize <= DEFAULT_PAGE_ALLOCATION) {\r
- Free = (POOL_FREE *) &NewPage[Offset]; \r
+ while (Offset + FSize <= MaxOffset) {\r
+ Free = (POOL_FREE *) &NewPage[Offset];\r
Free->Signature = POOL_FREE_SIGNATURE;\r
Free->Index = (UINT32)Index;\r
InsertHeadList (&Pool->FreeList[Index], &Free->Link);\r
Offset += FSize;\r
}\r
-\r
Index -= 1;\r
}\r
\r
- ASSERT (Offset == DEFAULT_PAGE_ALLOCATION);\r
- Index = SIZE_TO_LIST(Size);\r
+ ASSERT (Offset == MaxOffset);\r
+ goto Done;\r
}\r
\r
//\r
Buffer = NULL;\r
\r
if (Head != NULL) {\r
- \r
+\r
//\r
// If we have a pool buffer, fill in the header & tail info\r
//\r
Head->Signature = POOL_HEAD_SIGNATURE;\r
- Head->Size = (UINT32) Size;\r
+ Head->Size = Size;\r
Head->Type = (EFI_MEMORY_TYPE) PoolType;\r
Tail = HEAD_TO_TAIL (Head);\r
Tail->Signature = POOL_TAIL_SIGNATURE;\r
- Tail->Size = (UINT32) Size;\r
+ Tail->Size = Size;\r
Buffer = Head->Data;\r
DEBUG_CLEAR_MEMORY (Buffer, Size - POOL_OVERHEAD);\r
\r
- DEBUG (\r
- (DEBUG_POOL,\r
- "AllocatePoolI: Type %x, Addr %x (len %x) %,d\n",\r
- PoolType, \r
- Buffer, \r
- Size - POOL_OVERHEAD, \r
- Pool->Used)\r
- );\r
+ DEBUG ((\r
+ DEBUG_POOL,\r
+ "AllocatePoolI: Type %x, Addr %p (len %lx) %,ld\n", PoolType,\r
+ Buffer,\r
+ (UINT64)(Size - POOL_OVERHEAD),\r
+ (UINT64) Pool->Used\r
+ ));\r
\r
//\r
// Account the allocation\r
Pool->Used += Size;\r
\r
} else {\r
- DEBUG ((DEBUG_ERROR | DEBUG_POOL, "AllocatePool: failed to allocate %d bytes\n", Size));\r
+ DEBUG ((DEBUG_ERROR | DEBUG_POOL, "AllocatePool: failed to allocate %ld bytes\n", (UINT64) Size));\r
}\r
\r
return Buffer;\r
}\r
- \r
\r
\r
\r
/**\r
Frees pool.\r
\r
- @param Buffer The allocated pool entry to free \r
+ @param Buffer The allocated pool entry to free\r
+ @param PoolType Pointer to pool type\r
\r
- @retval EFI_INVALID_PARAMETER Buffer is not a valid value. \r
+ @retval EFI_INVALID_PARAMETER Buffer is not a valid value.\r
@retval EFI_SUCCESS Pool successfully freed.\r
\r
**/\r
EFI_STATUS\r
EFIAPI\r
-CoreFreePool (\r
- IN VOID *Buffer\r
+CoreInternalFreePool (\r
+ IN VOID *Buffer,\r
+ OUT EFI_MEMORY_TYPE *PoolType OPTIONAL\r
)\r
{\r
EFI_STATUS Status;\r
\r
- if (NULL == Buffer) {\r
+ if (Buffer == NULL) {\r
return EFI_INVALID_PARAMETER;\r
}\r
\r
- CoreAcquireMemoryLock ();\r
- Status = CoreFreePoolI (Buffer);\r
- CoreReleaseMemoryLock ();\r
+ CoreAcquireLock (&mPoolMemoryLock);\r
+ Status = CoreFreePoolI (Buffer, PoolType);\r
+ CoreReleaseLock (&mPoolMemoryLock);\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Frees pool.\r
+\r
+ @param Buffer The allocated pool entry to free\r
+\r
+ @retval EFI_INVALID_PARAMETER Buffer is not a valid value.\r
+ @retval EFI_SUCCESS Pool successfully freed.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+CoreFreePool (\r
+ IN VOID *Buffer\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_MEMORY_TYPE PoolType;\r
+\r
+ Status = CoreInternalFreePool (Buffer, &PoolType);\r
+ if (!EFI_ERROR (Status)) {\r
+ CoreUpdateProfile (\r
+ (EFI_PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS (0),\r
+ MemoryProfileActionFreePool,\r
+ PoolType,\r
+ 0,\r
+ Buffer,\r
+ NULL\r
+ );\r
+ InstallMemoryAttributesTableOnMemoryAllocation (PoolType);\r
+ }\r
return Status;\r
}\r
\r
+STATIC\r
+VOID\r
+CoreFreePoolPagesI (\r
+ IN EFI_MEMORY_TYPE PoolType,\r
+ IN EFI_PHYSICAL_ADDRESS Memory,\r
+ IN UINTN NoPages\r
+ )\r
+{\r
+ CoreAcquireMemoryLock ();\r
+ CoreFreePoolPages (Memory, NoPages);\r
+ CoreReleaseMemoryLock ();\r
\r
+ ApplyMemoryProtectionPolicy (PoolType, EfiConventionalMemory,\r
+ (EFI_PHYSICAL_ADDRESS)(UINTN)Memory, EFI_PAGES_TO_SIZE (NoPages));\r
+}\r
\r
/**\r
Internal function to free a pool entry.\r
Caller must have the memory lock held\r
\r
- @param Buffer The allocated pool entry to free \r
+ @param Buffer The allocated pool entry to free\r
+ @param PoolType Pointer to pool type\r
\r
- @retval EFI_INVALID_PARAMETER Buffer not valid \r
+ @retval EFI_INVALID_PARAMETER Buffer not valid\r
@retval EFI_SUCCESS Buffer successfully freed.\r
\r
**/\r
EFI_STATUS\r
CoreFreePoolI (\r
- IN VOID *Buffer\r
+ IN VOID *Buffer,\r
+ OUT EFI_MEMORY_TYPE *PoolType OPTIONAL\r
)\r
{\r
POOL *Pool;\r
UINTN NoPages;\r
UINTN Size;\r
CHAR8 *NewPage;\r
- UINTN FSize;\r
UINTN Offset;\r
BOOLEAN AllFree;\r
+ UINTN Granularity;\r
\r
- ASSERT(NULL != Buffer);\r
+ ASSERT(Buffer != NULL);\r
//\r
// Get the head & tail of the pool entry\r
//\r
Head = CR (Buffer, POOL_HEAD, Data, POOL_HEAD_SIGNATURE);\r
- ASSERT(NULL != Head);\r
+ ASSERT(Head != NULL);\r
\r
if (Head->Signature != POOL_HEAD_SIGNATURE) {\r
return EFI_INVALID_PARAMETER;\r
}\r
\r
Tail = HEAD_TO_TAIL (Head);\r
- ASSERT(NULL != Tail);\r
+ ASSERT(Tail != NULL);\r
\r
//\r
// Debug\r
//\r
ASSERT (Tail->Signature == POOL_TAIL_SIGNATURE);\r
ASSERT (Head->Size == Tail->Size);\r
- ASSERT_LOCKED (&gMemoryLock);\r
+ ASSERT_LOCKED (&mPoolMemoryLock);\r
\r
if (Tail->Signature != POOL_TAIL_SIGNATURE) {\r
return EFI_INVALID_PARAMETER;\r
return EFI_INVALID_PARAMETER;\r
}\r
Pool->Used -= Size;\r
- DEBUG ((DEBUG_POOL, "FreePool: %x (len %x) %,d\n", Head->Data, Head->Size - POOL_OVERHEAD, Pool->Used));\r
+ DEBUG ((DEBUG_POOL, "FreePool: %p (len %lx) %,ld\n", Head->Data, (UINT64)(Head->Size - POOL_OVERHEAD), (UINT64) Pool->Used));\r
+\r
+ if (Head->Type == EfiACPIReclaimMemory ||\r
+ Head->Type == EfiACPIMemoryNVS ||\r
+ Head->Type == EfiRuntimeServicesCode ||\r
+ Head->Type == EfiRuntimeServicesData) {\r
+\r
+ Granularity = RUNTIME_PAGE_ALLOCATION_GRANULARITY;\r
+ } else {\r
+ Granularity = DEFAULT_PAGE_ALLOCATION_GRANULARITY;\r
+ }\r
+\r
+ if (PoolType != NULL) {\r
+ *PoolType = Head->Type;\r
+ }\r
\r
//\r
- // Determine the pool list \r
+ // Determine the pool list\r
//\r
Index = SIZE_TO_LIST(Size);\r
DEBUG_CLEAR_MEMORY (Head, Size);\r
//\r
// If it's not on the list, it must be pool pages\r
//\r
- if (Index >= MAX_POOL_LIST) {\r
+ if (Index >= SIZE_TO_LIST (Granularity)) {\r
\r
//\r
// Return the memory pages back to free memory\r
//\r
- NoPages = EFI_SIZE_TO_PAGES(Size) + EFI_SIZE_TO_PAGES (DEFAULT_PAGE_ALLOCATION) - 1;\r
- NoPages &= ~(EFI_SIZE_TO_PAGES (DEFAULT_PAGE_ALLOCATION) - 1);\r
- CoreFreePoolPages ((EFI_PHYSICAL_ADDRESS) (UINTN) Head, NoPages);\r
+ NoPages = EFI_SIZE_TO_PAGES(Size) + EFI_SIZE_TO_PAGES (Granularity) - 1;\r
+ NoPages &= ~(UINTN)(EFI_SIZE_TO_PAGES (Granularity) - 1);\r
+ CoreFreePoolPagesI (Pool->MemoryType, (EFI_PHYSICAL_ADDRESS) (UINTN) Head, NoPages);\r
\r
} else {\r
\r
// Put the pool entry onto the free pool list\r
//\r
Free = (POOL_FREE *) Head;\r
- ASSERT(NULL != Free);\r
+ ASSERT(Free != NULL);\r
Free->Signature = POOL_FREE_SIGNATURE;\r
Free->Index = (UINT32)Index;\r
InsertHeadList (&Pool->FreeList[Index], &Free->Link);\r
\r
//\r
- // See if all the pool entries in the same page as Free are freed pool \r
+ // See if all the pool entries in the same page as Free are freed pool\r
// entries\r
//\r
- NewPage = (CHAR8 *)((UINTN)Free & ~((DEFAULT_PAGE_ALLOCATION) -1));\r
+ NewPage = (CHAR8 *)((UINTN)Free & ~(Granularity - 1));\r
Free = (POOL_FREE *) &NewPage[0];\r
- ASSERT(NULL != Free);\r
+ ASSERT(Free != NULL);\r
\r
if (Free->Signature == POOL_FREE_SIGNATURE) {\r
\r
- Index = Free->Index;\r
-\r
AllFree = TRUE;\r
Offset = 0;\r
- \r
- while ((Offset < DEFAULT_PAGE_ALLOCATION) && (AllFree)) {\r
- FSize = LIST_TO_SIZE(Index);\r
- while (Offset + FSize <= DEFAULT_PAGE_ALLOCATION) {\r
- Free = (POOL_FREE *) &NewPage[Offset];\r
- ASSERT(NULL != Free);\r
- if (Free->Signature != POOL_FREE_SIGNATURE) {\r
- AllFree = FALSE;\r
- }\r
- Offset += FSize;\r
+\r
+ while ((Offset < Granularity) && (AllFree)) {\r
+ Free = (POOL_FREE *) &NewPage[Offset];\r
+ ASSERT(Free != NULL);\r
+ if (Free->Signature != POOL_FREE_SIGNATURE) {\r
+ AllFree = FALSE;\r
}\r
- Index -= 1;\r
+ Offset += LIST_TO_SIZE(Free->Index);\r
}\r
\r
if (AllFree) {\r
\r
//\r
- // All of the pool entries in the same page as Free are free pool \r
+ // All of the pool entries in the same page as Free are free pool\r
// entries\r
// Remove all of these pool entries from the free loop lists.\r
//\r
Free = (POOL_FREE *) &NewPage[0];\r
- ASSERT(NULL != Free);\r
- Index = Free->Index;\r
+ ASSERT(Free != NULL);\r
Offset = 0;\r
- \r
- while (Offset < DEFAULT_PAGE_ALLOCATION) {\r
- FSize = LIST_TO_SIZE(Index);\r
- while (Offset + FSize <= DEFAULT_PAGE_ALLOCATION) {\r
- Free = (POOL_FREE *) &NewPage[Offset];\r
- ASSERT(NULL != Free);\r
- RemoveEntryList (&Free->Link);\r
- Offset += FSize;\r
- }\r
- Index -= 1;\r
+\r
+ while (Offset < Granularity) {\r
+ Free = (POOL_FREE *) &NewPage[Offset];\r
+ ASSERT(Free != NULL);\r
+ RemoveEntryList (&Free->Link);\r
+ Offset += LIST_TO_SIZE(Free->Index);\r
}\r
\r
//\r
// Free the page\r
//\r
- CoreFreePoolPages ((EFI_PHYSICAL_ADDRESS) (UINTN)NewPage, EFI_SIZE_TO_PAGES (DEFAULT_PAGE_ALLOCATION));\r
+ CoreFreePoolPagesI (Pool->MemoryType, (EFI_PHYSICAL_ADDRESS) (UINTN)NewPage,\r
+ EFI_SIZE_TO_PAGES (Granularity));\r
}\r
}\r
}\r
\r
//\r
- // If this is an OS specific memory type, then check to see if the last \r
+ // If this is an OS/OEM specific memory type, then check to see if the last\r
// portion of that memory type has been freed. If it has, then free the\r
// list entry for that memory type\r
//\r
- if (Pool->MemoryType < 0 && Pool->Used == 0) {\r
+ if (((UINT32) Pool->MemoryType >= MEMORY_TYPE_OEM_RESERVED_MIN) && Pool->Used == 0) {\r
RemoveEntryList (&Pool->Link);\r
- CoreFreePoolI (Pool);\r
+ CoreFreePoolI (Pool, NULL);\r
}\r
\r
return EFI_SUCCESS;\r
}\r
+\r