/** @file\r
UEFI Memory pool management functions.\r
\r
-Copyright (c) 2006 - 2012, 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
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>\r
+SPDX-License-Identifier: BSD-2-Clause-Patent\r
\r
**/\r
\r
#include "DxeMain.h"\r
#include "Imem.h"\r
+#include "HeapGuard.h"\r
+\r
+STATIC EFI_LOCK mPoolMemoryLock = EFI_INITIALIZE_LOCK_VARIABLE (TPL_NOTIFY);\r
\r
#define POOL_FREE_SIGNATURE SIGNATURE_32('p','f','r','0')\r
typedef struct {\r
} POOL_FREE;\r
\r
\r
-#define POOL_HEAD_SIGNATURE SIGNATURE_32('p','h','d','0')\r
+#define POOL_HEAD_SIGNATURE SIGNATURE_32('p','h','d','0')\r
+#define POOLPAGE_HEAD_SIGNATURE SIGNATURE_32('p','h','d','1')\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 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
//\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
mPoolHead[Type].Used = 0;\r
mPoolHead[Type].MemoryType = (EFI_MEMORY_TYPE) Type;\r
for (Index=0; Index < MAX_POOL_LIST; Index++) {\r
- InitializeListHead (&mPoolHead[Type].FreeList[Index]);\r
+ InitializeListHead (&mPoolHead[Type].FreeList[Index]);\r
}\r
}\r
}\r
}\r
\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 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 ((INT32)MemoryType < 0) {\r
+ if ((UINT32) MemoryType >= MEMORY_TYPE_OEM_RESERVED_MIN) {\r
\r
for (Link = mPoolHeadList.ForwardLink; Link != &mPoolHeadList; Link = Link->ForwardLink) {\r
Pool = CR(Link, POOL, Link, POOL_SIGNATURE);\r
}\r
}\r
\r
- Pool = CoreAllocatePoolI (EfiBootServicesData, sizeof (POOL));\r
+ Pool = CoreAllocatePoolI (EfiBootServicesData, sizeof (POOL), FALSE);\r
if (Pool == NULL) {\r
return NULL;\r
}\r
@param Buffer The address to return a pointer to the allocated\r
pool\r
\r
- @retval EFI_INVALID_PARAMETER PoolType not valid or Buffer is NULL. \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
{\r
- EFI_STATUS Status;\r
+ EFI_STATUS Status;\r
+ BOOLEAN NeedGuard;\r
\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
return EFI_OUT_OF_RESOURCES;\r
}\r
\r
+ NeedGuard = IsPoolTypeToGuard (PoolType) && !mOnGuarding;\r
+\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
+ *Buffer = CoreAllocatePoolI (PoolType, Size, NeedGuard);\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
+/**\r
+ Internal function. Used by the pool functions to allocate pages\r
+ to back pool allocation requests.\r
+\r
+ @param PoolType The type of memory for the new pool pages\r
+ @param NoPages No of pages to allocate\r
+ @param Granularity Bits to align.\r
+ @param NeedGuard Flag to indicate Guard page is needed or not\r
+\r
+ @return The allocated memory, or NULL\r
+\r
+**/\r
+STATIC\r
+VOID *\r
+CoreAllocatePoolPagesI (\r
+ IN EFI_MEMORY_TYPE PoolType,\r
+ IN UINTN NoPages,\r
+ IN UINTN Granularity,\r
+ IN BOOLEAN NeedGuard\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, NeedGuard);\r
+ CoreReleaseMemoryLock ();\r
+\r
+ if (Buffer != NULL) {\r
+ if (NeedGuard) {\r
+ SetGuardForMemory ((EFI_PHYSICAL_ADDRESS)(UINTN)Buffer, NoPages);\r
+ }\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
\r
@param PoolType Type of pool to allocate\r
@param Size The amount of pool to allocate\r
+ @param NeedGuard Flag to indicate Guard page is needed or not\r
\r
@return The allocate pool, or NULL\r
\r
VOID *\r
CoreAllocatePoolI (\r
IN EFI_MEMORY_TYPE PoolType,\r
- IN UINTN Size\r
+ IN UINTN Size,\r
+ IN BOOLEAN NeedGuard\r
)\r
{\r
POOL *Pool;\r
VOID *Buffer;\r
UINTN Index;\r
UINTN FSize;\r
- UINTN Offset;\r
+ UINTN Offset, MaxOffset;\r
UINTN NoPages;\r
+ UINTN Granularity;\r
+ BOOLEAN HasPoolTail;\r
+ BOOLEAN PageAsPool;\r
+\r
+ ASSERT_LOCKED (&mPoolMemoryLock);\r
\r
- ASSERT_LOCKED (&gMemoryLock);\r
+ if (PoolType == EfiACPIReclaimMemory ||\r
+ PoolType == EfiACPIMemoryNVS ||\r
+ PoolType == EfiRuntimeServicesCode ||\r
+ PoolType == EfiRuntimeServicesData) {\r
+\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
+ HasPoolTail = !(NeedGuard &&\r
+ ((PcdGet8 (PcdHeapGuardPropertyMask) & BIT7) == 0));\r
+ PageAsPool = (IsHeapGuardEnabled (GUARD_HEAP_TYPE_FREED) && !mOnGuarding);\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
// 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) || NeedGuard || PageAsPool) {\r
+ if (!HasPoolTail) {\r
+ Size -= sizeof (POOL_TAIL);\r
+ }\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, NeedGuard);\r
+ if (NeedGuard) {\r
+ Head = AdjustPoolHeadA ((EFI_PHYSICAL_ADDRESS)(UINTN)Head, NoPages, Size);\r
+ }\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),\r
+ Granularity, NeedGuard);\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
- Offset = 0;\r
- while (Offset < DEFAULT_PAGE_ALLOCATION) {\r
+ // Carve up remaining space into free pool blocks\r
+ //\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
+ 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
\r
if (Head != NULL) {\r
\r
+ //\r
+ // Account the allocation\r
+ //\r
+ Pool->Used += Size;\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->Signature = (PageAsPool) ? POOLPAGE_HEAD_SIGNATURE : POOL_HEAD_SIGNATURE;\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
Buffer = Head->Data;\r
- DEBUG_CLEAR_MEMORY (Buffer, Size - POOL_OVERHEAD);\r
+\r
+ if (HasPoolTail) {\r
+ Tail = HEAD_TO_TAIL (Head);\r
+ Tail->Signature = POOL_TAIL_SIGNATURE;\r
+ Tail->Size = Size;\r
+\r
+ Size -= POOL_OVERHEAD;\r
+ } else {\r
+ Size -= SIZE_OF_POOL_HEAD;\r
+ }\r
+\r
+ DEBUG_CLEAR_MEMORY (Buffer, Size);\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)Size,\r
(UINT64) Pool->Used\r
));\r
\r
- //\r
- // Account the allocation\r
- //\r
- Pool->Used += Size;\r
\r
} else {\r
DEBUG ((DEBUG_ERROR | DEBUG_POOL, "AllocatePool: failed to allocate %ld bytes\n", (UINT64) Size));\r
Frees pool.\r
\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_SUCCESS Pool successfully freed.\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
return EFI_INVALID_PARAMETER;\r
}\r
\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
+/**\r
+ Internal function. Frees pool pages allocated via CoreAllocatePoolPagesI().\r
+\r
+ @param PoolType The type of memory for the pool pages\r
+ @param Memory The base address to free\r
+ @param NoPages The number of pages to free\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
- Status = CoreFreePoolI (Buffer);\r
+ CoreFreePoolPages (Memory, NoPages);\r
CoreReleaseMemoryLock ();\r
- return Status;\r
+\r
+ GuardFreedPagesChecked (Memory, NoPages);\r
+ ApplyMemoryProtectionPolicy (PoolType, EfiConventionalMemory,\r
+ (EFI_PHYSICAL_ADDRESS)(UINTN)Memory, EFI_PAGES_TO_SIZE (NoPages));\r
}\r
\r
+/**\r
+ Internal function. Frees guarded pool pages.\r
\r
+ @param PoolType The type of memory for the pool pages\r
+ @param Memory The base address to free\r
+ @param NoPages The number of pages to free\r
+\r
+**/\r
+STATIC\r
+VOID\r
+CoreFreePoolPagesWithGuard (\r
+ IN EFI_MEMORY_TYPE PoolType,\r
+ IN EFI_PHYSICAL_ADDRESS Memory,\r
+ IN UINTN NoPages\r
+ )\r
+{\r
+ EFI_PHYSICAL_ADDRESS MemoryGuarded;\r
+ UINTN NoPagesGuarded;\r
+\r
+ MemoryGuarded = Memory;\r
+ NoPagesGuarded = NoPages;\r
+\r
+ AdjustMemoryF (&Memory, &NoPages);\r
+ //\r
+ // It's safe to unset Guard page inside memory lock because there should\r
+ // be no memory allocation occurred in updating memory page attribute at\r
+ // this point. And unsetting Guard page before free will prevent Guard\r
+ // page just freed back to pool from being allocated right away before\r
+ // marking it usable (from non-present to present).\r
+ //\r
+ UnsetGuardForMemory (MemoryGuarded, NoPagesGuarded);\r
+ if (NoPages > 0) {\r
+ CoreFreePoolPagesI (PoolType, Memory, NoPages);\r
+ }\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 PoolType Pointer to pool type\r
\r
@retval EFI_INVALID_PARAMETER Buffer not valid\r
@retval EFI_SUCCESS Buffer successfully freed.\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
+ BOOLEAN IsGuarded;\r
+ BOOLEAN HasPoolTail;\r
+ BOOLEAN PageAsPool;\r
\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
+ Head = BASE_CR (Buffer, POOL_HEAD, Data);\r
ASSERT(Head != NULL);\r
\r
- if (Head->Signature != POOL_HEAD_SIGNATURE) {\r
+ if (Head->Signature != POOL_HEAD_SIGNATURE &&\r
+ Head->Signature != POOLPAGE_HEAD_SIGNATURE) {\r
+ ASSERT (Head->Signature == POOL_HEAD_SIGNATURE ||\r
+ Head->Signature == POOLPAGE_HEAD_SIGNATURE);\r
return EFI_INVALID_PARAMETER;\r
}\r
\r
- Tail = HEAD_TO_TAIL (Head);\r
- ASSERT(Tail != NULL);\r
+ IsGuarded = IsPoolTypeToGuard (Head->Type) &&\r
+ IsMemoryGuarded ((EFI_PHYSICAL_ADDRESS)(UINTN)Head);\r
+ HasPoolTail = !(IsGuarded &&\r
+ ((PcdGet8 (PcdHeapGuardPropertyMask) & BIT7) == 0));\r
+ PageAsPool = (Head->Signature == POOLPAGE_HEAD_SIGNATURE);\r
\r
- //\r
- // Debug\r
- //\r
- ASSERT (Tail->Signature == POOL_TAIL_SIGNATURE);\r
- ASSERT (Head->Size == Tail->Size);\r
- ASSERT_LOCKED (&gMemoryLock);\r
+ if (HasPoolTail) {\r
+ Tail = HEAD_TO_TAIL (Head);\r
+ ASSERT (Tail != NULL);\r
\r
- if (Tail->Signature != POOL_TAIL_SIGNATURE) {\r
- return EFI_INVALID_PARAMETER;\r
- }\r
+ //\r
+ // Debug\r
+ //\r
+ ASSERT (Tail->Signature == POOL_TAIL_SIGNATURE);\r
+ ASSERT (Head->Size == Tail->Size);\r
\r
- if (Head->Size != Tail->Size) {\r
- return EFI_INVALID_PARAMETER;\r
+ if (Tail->Signature != POOL_TAIL_SIGNATURE) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (Head->Size != Tail->Size) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
}\r
\r
+ ASSERT_LOCKED (&mPoolMemoryLock);\r
+\r
//\r
// Determine the pool type and account for it\r
//\r
Pool->Used -= Size;\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
//\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) || IsGuarded || PageAsPool) {\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
+ if (IsGuarded) {\r
+ Head = AdjustPoolHeadF ((EFI_PHYSICAL_ADDRESS)(UINTN)Head);\r
+ CoreFreePoolPagesWithGuard (\r
+ Pool->MemoryType,\r
+ (EFI_PHYSICAL_ADDRESS)(UINTN)Head,\r
+ NoPages\r
+ );\r
+ } else {\r
+ CoreFreePoolPagesI (\r
+ Pool->MemoryType,\r
+ (EFI_PHYSICAL_ADDRESS)(UINTN)Head,\r
+ NoPages\r
+ );\r
+ }\r
\r
} else {\r
\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(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(Free != NULL);\r
- if (Free->Signature != POOL_FREE_SIGNATURE) {\r
- AllFree = FALSE;\r
- }\r
- Offset += FSize;\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
Free = (POOL_FREE *) &NewPage[0];\r
ASSERT(Free != NULL);\r
- Index = Free->Index;\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(Free != NULL);\r
- RemoveEntryList (&Free->Link);\r
- Offset += FSize;\r
- }\r
- Index -= 1;\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 ((INT32)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