X-Git-Url: https://git.proxmox.com/?p=mirror_edk2.git;a=blobdiff_plain;f=MdeModulePkg%2FCore%2FDxe%2FMem%2FPool.c;h=734fc94bf6129ad20f3e8846c9cf13aaee7266ab;hp=cea6fada4c367c95b4b53c4ffef1d1900e1eb85f;hb=9d510e61fceee7b92955ef9a3c20343752d8ce3f;hpb=ec90508b3d3ff22a698a0446cb09d551d7466045
diff --git a/MdeModulePkg/Core/Dxe/Mem/Pool.c b/MdeModulePkg/Core/Dxe/Mem/Pool.c
index cea6fada4c..734fc94bf6 100644
--- a/MdeModulePkg/Core/Dxe/Mem/Pool.c
+++ b/MdeModulePkg/Core/Dxe/Mem/Pool.c
@@ -1,21 +1,18 @@
/** @file
UEFI Memory pool management functions.
-Copyright (c) 2006 - 2008, Intel Corporation.
-All rights reserved. This program and the accompanying materials
-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
-http://opensource.org/licenses/bsd-license.php
-
-THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
-WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include "DxeMain.h"
#include "Imem.h"
+#include "HeapGuard.h"
+
+STATIC EFI_LOCK mPoolMemoryLock = EFI_INITIALIZE_LOCK_VARIABLE (TPL_NOTIFY);
-#define POOL_FREE_SIGNATURE EFI_SIGNATURE_32('p','f','r','0')
+#define POOL_FREE_SIGNATURE SIGNATURE_32('p','f','r','0')
typedef struct {
UINT32 Signature;
UINT32 Index;
@@ -23,36 +20,43 @@ typedef struct {
} POOL_FREE;
-#define POOL_HEAD_SIGNATURE EFI_SIGNATURE_32('p','h','d','0')
+#define POOL_HEAD_SIGNATURE SIGNATURE_32('p','h','d','0')
+#define POOLPAGE_HEAD_SIGNATURE SIGNATURE_32('p','h','d','1')
typedef struct {
UINT32 Signature;
- UINT32 Size;
+ UINT32 Reserved;
EFI_MEMORY_TYPE Type;
- UINTN Reserved;
+ UINTN Size;
CHAR8 Data[1];
} POOL_HEAD;
-#define SIZE_OF_POOL_HEAD EFI_FIELD_OFFSET(POOL_HEAD,Data)
+#define SIZE_OF_POOL_HEAD OFFSET_OF(POOL_HEAD,Data)
-#define POOL_TAIL_SIGNATURE EFI_SIGNATURE_32('p','t','a','l')
+#define POOL_TAIL_SIGNATURE SIGNATURE_32('p','t','a','l')
typedef struct {
UINT32 Signature;
- UINT32 Size;
+ UINT32 Reserved;
+ UINTN Size;
} POOL_TAIL;
-
-#define POOL_SHIFT 7
-
#define POOL_OVERHEAD (SIZE_OF_POOL_HEAD + sizeof(POOL_TAIL))
#define HEAD_TO_TAIL(a) \
((POOL_TAIL *) (((CHAR8 *) (a)) + (a)->Size - sizeof(POOL_TAIL)));
+//
+// Each element is the sum of the 2 previous ones: this allows us to migrate
+// blocks between bins by splitting them up, while not wasting too much memory
+// as we would in a strict power-of-2 sequence
+//
+STATIC CONST UINT16 mPoolSizeTable[] = {
+ 128, 256, 384, 640, 1024, 1664, 2688, 4352, 7040, 11392, 18432, 29824
+};
-#define SIZE_TO_LIST(a) ((a) >> POOL_SHIFT)
-#define LIST_TO_SIZE(a) ((a+1) << POOL_SHIFT)
+#define SIZE_TO_LIST(a) (GetPoolIndexFromSize (a))
+#define LIST_TO_SIZE(a) (mPoolSizeTable [a])
-#define MAX_POOL_LIST SIZE_TO_LIST(DEFAULT_PAGE_ALLOCATION)
+#define MAX_POOL_LIST (ARRAY_SIZE (mPoolSizeTable))
#define MAX_POOL_SIZE (MAX_ADDRESS - POOL_OVERHEAD)
@@ -60,7 +64,7 @@ typedef struct {
// Globals
//
-#define POOL_SIGNATURE EFI_SIGNATURE_32('p','l','s','t')
+#define POOL_SIGNATURE SIGNATURE_32('p','l','s','t')
typedef struct {
INTN Signature;
UINTN Used;
@@ -79,6 +83,29 @@ POOL mPoolHead[EfiMaxMemoryType];
//
LIST_ENTRY mPoolHeadList = INITIALIZE_LIST_HEAD_VARIABLE (mPoolHeadList);
+/**
+ Get pool size table index from the specified size.
+
+ @param Size The specified size to get index from pool table.
+
+ @return The index of pool size table.
+
+**/
+STATIC
+UINTN
+GetPoolIndexFromSize (
+ UINTN Size
+ )
+{
+ UINTN Index;
+
+ for (Index = 0; Index < MAX_POOL_LIST; Index++) {
+ if (mPoolSizeTable [Index] >= Size) {
+ return Index;
+ }
+ }
+ return MAX_POOL_LIST;
+}
/**
Called to initialize the pool.
@@ -97,7 +124,7 @@ CoreInitializePool (
mPoolHead[Type].Used = 0;
mPoolHead[Type].MemoryType = (EFI_MEMORY_TYPE) Type;
for (Index=0; Index < MAX_POOL_LIST; Index++) {
- InitializeListHead (&mPoolHead[Type].FreeList[Index]);
+ InitializeListHead (&mPoolHead[Type].FreeList[Index]);
}
}
}
@@ -120,11 +147,16 @@ LookupPoolHead (
POOL *Pool;
UINTN Index;
- if (MemoryType >= 0 && MemoryType < EfiMaxMemoryType) {
+ if ((UINT32)MemoryType < EfiMaxMemoryType) {
return &mPoolHead[MemoryType];
}
- if (MemoryType < 0) {
+ //
+ // MemoryType values in the range 0x80000000..0xFFFFFFFF are reserved for use by UEFI
+ // OS loaders that are provided by operating system vendors.
+ // MemoryType values in the range 0x70000000..0x7FFFFFFF are reserved for OEM use.
+ //
+ if ((UINT32) MemoryType >= MEMORY_TYPE_OEM_RESERVED_MIN) {
for (Link = mPoolHeadList.ForwardLink; Link != &mPoolHeadList; Link = Link->ForwardLink) {
Pool = CR(Link, POOL, Link, POOL_SIGNATURE);
@@ -133,7 +165,7 @@ LookupPoolHead (
}
}
- Pool = CoreAllocatePoolI (EfiBootServicesData, sizeof (POOL));
+ Pool = CoreAllocatePoolI (EfiBootServicesData, sizeof (POOL), FALSE);
if (Pool == NULL) {
return NULL;
}
@@ -163,26 +195,33 @@ LookupPoolHead (
@param Buffer The address to return a pointer to the allocated
pool
- @retval EFI_INVALID_PARAMETER PoolType not valid
+ @retval EFI_INVALID_PARAMETER Buffer is NULL.
+ PoolType is in the range EfiMaxMemoryType..0x6FFFFFFF.
+ PoolType is EfiPersistentMemory.
@retval EFI_OUT_OF_RESOURCES Size exceeds max pool size or allocation failed.
@retval EFI_SUCCESS Pool successfully allocated.
**/
EFI_STATUS
EFIAPI
-CoreAllocatePool (
+CoreInternalAllocatePool (
IN EFI_MEMORY_TYPE PoolType,
IN UINTN Size,
OUT VOID **Buffer
)
{
- EFI_STATUS Status;
+ EFI_STATUS Status;
+ BOOLEAN NeedGuard;
//
// If it's not a valid type, fail it
//
- if ((PoolType >= EfiMaxMemoryType && PoolType <= 0x7fffffff) ||
- PoolType == EfiConventionalMemory) {
+ if ((PoolType >= EfiMaxMemoryType && PoolType < MEMORY_TYPE_OEM_RESERVED_MIN) ||
+ (PoolType == EfiConventionalMemory) || (PoolType == EfiPersistentMemory)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Buffer == NULL) {
return EFI_INVALID_PARAMETER;
}
@@ -196,20 +235,102 @@ CoreAllocatePool (
return EFI_OUT_OF_RESOURCES;
}
+ NeedGuard = IsPoolTypeToGuard (PoolType) && !mOnGuarding;
+
//
// Acquire the memory lock and make the allocation
//
- Status = CoreAcquireLockOrFail (&gMemoryLock);
+ Status = CoreAcquireLockOrFail (&mPoolMemoryLock);
if (EFI_ERROR (Status)) {
return EFI_OUT_OF_RESOURCES;
}
- *Buffer = CoreAllocatePoolI (PoolType, Size);
- CoreReleaseMemoryLock ();
+ *Buffer = CoreAllocatePoolI (PoolType, Size, NeedGuard);
+ CoreReleaseLock (&mPoolMemoryLock);
return (*Buffer != NULL) ? EFI_SUCCESS : EFI_OUT_OF_RESOURCES;
}
+/**
+ Allocate pool of a particular type.
+
+ @param PoolType Type of pool to allocate
+ @param Size The amount of pool to allocate
+ @param Buffer The address to return a pointer to the allocated
+ pool
+
+ @retval EFI_INVALID_PARAMETER Buffer is NULL.
+ PoolType is in the range EfiMaxMemoryType..0x6FFFFFFF.
+ PoolType is EfiPersistentMemory.
+ @retval EFI_OUT_OF_RESOURCES Size exceeds max pool size or allocation failed.
+ @retval EFI_SUCCESS Pool successfully allocated.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreAllocatePool (
+ IN EFI_MEMORY_TYPE PoolType,
+ IN UINTN Size,
+ OUT VOID **Buffer
+ )
+{
+ EFI_STATUS Status;
+
+ Status = CoreInternalAllocatePool (PoolType, Size, Buffer);
+ if (!EFI_ERROR (Status)) {
+ CoreUpdateProfile (
+ (EFI_PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS (0),
+ MemoryProfileActionAllocatePool,
+ PoolType,
+ Size,
+ *Buffer,
+ NULL
+ );
+ InstallMemoryAttributesTableOnMemoryAllocation (PoolType);
+ }
+ return Status;
+}
+
+/**
+ Internal function. Used by the pool functions to allocate pages
+ to back pool allocation requests.
+
+ @param PoolType The type of memory for the new pool pages
+ @param NoPages No of pages to allocate
+ @param Granularity Bits to align.
+ @param NeedGuard Flag to indicate Guard page is needed or not
+
+ @return The allocated memory, or NULL
+
+**/
+STATIC
+VOID *
+CoreAllocatePoolPagesI (
+ IN EFI_MEMORY_TYPE PoolType,
+ IN UINTN NoPages,
+ IN UINTN Granularity,
+ IN BOOLEAN NeedGuard
+ )
+{
+ VOID *Buffer;
+ EFI_STATUS Status;
+
+ Status = CoreAcquireLockOrFail (&gMemoryLock);
+ if (EFI_ERROR (Status)) {
+ return NULL;
+ }
+
+ Buffer = CoreAllocatePoolPages (PoolType, NoPages, Granularity, NeedGuard);
+ CoreReleaseMemoryLock ();
+ if (Buffer != NULL) {
+ if (NeedGuard) {
+ SetGuardForMemory ((EFI_PHYSICAL_ADDRESS)(UINTN)Buffer, NoPages);
+ }
+ ApplyMemoryProtectionPolicy(EfiConventionalMemory, PoolType,
+ (EFI_PHYSICAL_ADDRESS)(UINTN)Buffer, EFI_PAGES_TO_SIZE (NoPages));
+ }
+ return Buffer;
+}
/**
Internal function to allocate pool of a particular type.
@@ -217,6 +338,7 @@ CoreAllocatePool (
@param PoolType Type of pool to allocate
@param Size The amount of pool to allocate
+ @param NeedGuard Flag to indicate Guard page is needed or not
@return The allocate pool, or NULL
@@ -224,7 +346,8 @@ CoreAllocatePool (
VOID *
CoreAllocatePoolI (
IN EFI_MEMORY_TYPE PoolType,
- IN UINTN Size
+ IN UINTN Size,
+ IN BOOLEAN NeedGuard
)
{
POOL *Pool;
@@ -235,15 +358,32 @@ CoreAllocatePoolI (
VOID *Buffer;
UINTN Index;
UINTN FSize;
- UINTN Offset;
+ UINTN Offset, MaxOffset;
UINTN NoPages;
+ UINTN Granularity;
+ BOOLEAN HasPoolTail;
+ BOOLEAN PageAsPool;
+
+ ASSERT_LOCKED (&mPoolMemoryLock);
- ASSERT_LOCKED (&gMemoryLock);
+ if (PoolType == EfiACPIReclaimMemory ||
+ PoolType == EfiACPIMemoryNVS ||
+ PoolType == EfiRuntimeServicesCode ||
+ PoolType == EfiRuntimeServicesData) {
+
+ Granularity = RUNTIME_PAGE_ALLOCATION_GRANULARITY;
+ } else {
+ Granularity = DEFAULT_PAGE_ALLOCATION_GRANULARITY;
+ }
//
// Adjust the size by the pool header & tail overhead
//
+ HasPoolTail = !(NeedGuard &&
+ ((PcdGet8 (PcdHeapGuardPropertyMask) & BIT7) == 0));
+ PageAsPool = (IsHeapGuardEnabled (GUARD_HEAP_TYPE_FREED) && !mOnGuarding);
+
//
// Adjusting the Size to be of proper alignment so that
// we don't get an unaligned access fault later when
@@ -263,10 +403,16 @@ CoreAllocatePoolI (
// If allocation is over max size, just allocate pages for the request
// (slow)
//
- if (Index >= MAX_POOL_LIST) {
- NoPages = EFI_SIZE_TO_PAGES(Size) + EFI_SIZE_TO_PAGES (DEFAULT_PAGE_ALLOCATION) - 1;
- NoPages &= ~(EFI_SIZE_TO_PAGES (DEFAULT_PAGE_ALLOCATION) - 1);
- Head = CoreAllocatePoolPages (PoolType, NoPages, DEFAULT_PAGE_ALLOCATION);
+ if (Index >= SIZE_TO_LIST (Granularity) || NeedGuard || PageAsPool) {
+ if (!HasPoolTail) {
+ Size -= sizeof (POOL_TAIL);
+ }
+ NoPages = EFI_SIZE_TO_PAGES (Size) + EFI_SIZE_TO_PAGES (Granularity) - 1;
+ NoPages &= ~(UINTN)(EFI_SIZE_TO_PAGES (Granularity) - 1);
+ Head = CoreAllocatePoolPagesI (PoolType, NoPages, Granularity, NeedGuard);
+ if (NeedGuard) {
+ Head = AdjustPoolHeadA ((EFI_PHYSICAL_ADDRESS)(UINTN)Head, NoPages, Size);
+ }
goto Done;
}
@@ -275,35 +421,57 @@ CoreAllocatePoolI (
//
if (IsListEmpty (&Pool->FreeList[Index])) {
+ Offset = LIST_TO_SIZE (Index);
+ MaxOffset = Granularity;
+
+ //
+ // Check the bins holding larger blocks, and carve one up if needed
+ //
+ while (++Index < SIZE_TO_LIST (Granularity)) {
+ if (!IsListEmpty (&Pool->FreeList[Index])) {
+ Free = CR (Pool->FreeList[Index].ForwardLink, POOL_FREE, Link, POOL_FREE_SIGNATURE);
+ RemoveEntryList (&Free->Link);
+ NewPage = (VOID *) Free;
+ MaxOffset = LIST_TO_SIZE (Index);
+ goto Carve;
+ }
+ }
+
//
// Get another page
//
- NewPage = CoreAllocatePoolPages(PoolType, EFI_SIZE_TO_PAGES (DEFAULT_PAGE_ALLOCATION), DEFAULT_PAGE_ALLOCATION);
+ NewPage = CoreAllocatePoolPagesI (PoolType, EFI_SIZE_TO_PAGES (Granularity),
+ Granularity, NeedGuard);
if (NewPage == NULL) {
goto Done;
}
//
- // Carve up new page into free pool blocks
+ // Serve the allocation request from the head of the allocated block
+ //
+Carve:
+ Head = (POOL_HEAD *) NewPage;
+
+ //
+ // Carve up remaining space into free pool blocks
//
- Offset = 0;
- while (Offset < DEFAULT_PAGE_ALLOCATION) {
+ Index--;
+ while (Offset < MaxOffset) {
ASSERT (Index < MAX_POOL_LIST);
FSize = LIST_TO_SIZE(Index);
- while (Offset + FSize <= DEFAULT_PAGE_ALLOCATION) {
+ while (Offset + FSize <= MaxOffset) {
Free = (POOL_FREE *) &NewPage[Offset];
Free->Signature = POOL_FREE_SIGNATURE;
Free->Index = (UINT32)Index;
InsertHeadList (&Pool->FreeList[Index], &Free->Link);
Offset += FSize;
}
-
Index -= 1;
}
- ASSERT (Offset == DEFAULT_PAGE_ALLOCATION);
- Index = SIZE_TO_LIST(Size);
+ ASSERT (Offset == MaxOffset);
+ goto Done;
}
//
@@ -319,30 +487,39 @@ Done:
if (Head != NULL) {
+ //
+ // Account the allocation
+ //
+ Pool->Used += Size;
+
//
// If we have a pool buffer, fill in the header & tail info
//
- Head->Signature = POOL_HEAD_SIGNATURE;
- Head->Size = (UINT32) Size;
+ Head->Signature = (PageAsPool) ? POOLPAGE_HEAD_SIGNATURE : POOL_HEAD_SIGNATURE;
+ Head->Size = Size;
Head->Type = (EFI_MEMORY_TYPE) PoolType;
- Tail = HEAD_TO_TAIL (Head);
- Tail->Signature = POOL_TAIL_SIGNATURE;
- Tail->Size = (UINT32) Size;
Buffer = Head->Data;
- DEBUG_CLEAR_MEMORY (Buffer, Size - POOL_OVERHEAD);
+
+ if (HasPoolTail) {
+ Tail = HEAD_TO_TAIL (Head);
+ Tail->Signature = POOL_TAIL_SIGNATURE;
+ Tail->Size = Size;
+
+ Size -= POOL_OVERHEAD;
+ } else {
+ Size -= SIZE_OF_POOL_HEAD;
+ }
+
+ DEBUG_CLEAR_MEMORY (Buffer, Size);
DEBUG ((
DEBUG_POOL,
"AllocatePoolI: Type %x, Addr %p (len %lx) %,ld\n", PoolType,
Buffer,
- (UINT64)(Size - POOL_OVERHEAD),
+ (UINT64)Size,
(UINT64) Pool->Used
));
- //
- // Account the allocation
- //
- Pool->Used += Size;
} else {
DEBUG ((DEBUG_ERROR | DEBUG_POOL, "AllocatePool: failed to allocate %ld bytes\n", (UINT64) Size));
@@ -357,6 +534,7 @@ Done:
Frees pool.
@param Buffer The allocated pool entry to free
+ @param PoolType Pointer to pool type
@retval EFI_INVALID_PARAMETER Buffer is not a valid value.
@retval EFI_SUCCESS Pool successfully freed.
@@ -364,8 +542,9 @@ Done:
**/
EFI_STATUS
EFIAPI
-CoreFreePool (
- IN VOID *Buffer
+CoreInternalFreePool (
+ IN VOID *Buffer,
+ OUT EFI_MEMORY_TYPE *PoolType OPTIONAL
)
{
EFI_STATUS Status;
@@ -374,19 +553,112 @@ CoreFreePool (
return EFI_INVALID_PARAMETER;
}
+ CoreAcquireLock (&mPoolMemoryLock);
+ Status = CoreFreePoolI (Buffer, PoolType);
+ CoreReleaseLock (&mPoolMemoryLock);
+ return Status;
+}
+
+/**
+ Frees pool.
+
+ @param Buffer The allocated pool entry to free
+
+ @retval EFI_INVALID_PARAMETER Buffer is not a valid value.
+ @retval EFI_SUCCESS Pool successfully freed.
+
+**/
+EFI_STATUS
+EFIAPI
+CoreFreePool (
+ IN VOID *Buffer
+ )
+{
+ EFI_STATUS Status;
+ EFI_MEMORY_TYPE PoolType;
+
+ Status = CoreInternalFreePool (Buffer, &PoolType);
+ if (!EFI_ERROR (Status)) {
+ CoreUpdateProfile (
+ (EFI_PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS (0),
+ MemoryProfileActionFreePool,
+ PoolType,
+ 0,
+ Buffer,
+ NULL
+ );
+ InstallMemoryAttributesTableOnMemoryAllocation (PoolType);
+ }
+ return Status;
+}
+
+/**
+ Internal function. Frees pool pages allocated via CoreAllocatePoolPagesI().
+
+ @param PoolType The type of memory for the pool pages
+ @param Memory The base address to free
+ @param NoPages The number of pages to free
+
+**/
+STATIC
+VOID
+CoreFreePoolPagesI (
+ IN EFI_MEMORY_TYPE PoolType,
+ IN EFI_PHYSICAL_ADDRESS Memory,
+ IN UINTN NoPages
+ )
+{
CoreAcquireMemoryLock ();
- Status = CoreFreePoolI (Buffer);
+ CoreFreePoolPages (Memory, NoPages);
CoreReleaseMemoryLock ();
- return Status;
+
+ GuardFreedPagesChecked (Memory, NoPages);
+ ApplyMemoryProtectionPolicy (PoolType, EfiConventionalMemory,
+ (EFI_PHYSICAL_ADDRESS)(UINTN)Memory, EFI_PAGES_TO_SIZE (NoPages));
}
+/**
+ Internal function. Frees guarded pool pages.
+
+ @param PoolType The type of memory for the pool pages
+ @param Memory The base address to free
+ @param NoPages The number of pages to free
+
+**/
+STATIC
+VOID
+CoreFreePoolPagesWithGuard (
+ IN EFI_MEMORY_TYPE PoolType,
+ IN EFI_PHYSICAL_ADDRESS Memory,
+ IN UINTN NoPages
+ )
+{
+ EFI_PHYSICAL_ADDRESS MemoryGuarded;
+ UINTN NoPagesGuarded;
+
+ MemoryGuarded = Memory;
+ NoPagesGuarded = NoPages;
+ AdjustMemoryF (&Memory, &NoPages);
+ //
+ // It's safe to unset Guard page inside memory lock because there should
+ // be no memory allocation occurred in updating memory page attribute at
+ // this point. And unsetting Guard page before free will prevent Guard
+ // page just freed back to pool from being allocated right away before
+ // marking it usable (from non-present to present).
+ //
+ UnsetGuardForMemory (MemoryGuarded, NoPagesGuarded);
+ if (NoPages > 0) {
+ CoreFreePoolPagesI (PoolType, Memory, NoPages);
+ }
+}
/**
Internal function to free a pool entry.
Caller must have the memory lock held
@param Buffer The allocated pool entry to free
+ @param PoolType Pointer to pool type
@retval EFI_INVALID_PARAMETER Buffer not valid
@retval EFI_SUCCESS Buffer successfully freed.
@@ -394,7 +666,8 @@ CoreFreePool (
**/
EFI_STATUS
CoreFreePoolI (
- IN VOID *Buffer
+ IN VOID *Buffer,
+ OUT EFI_MEMORY_TYPE *PoolType OPTIONAL
)
{
POOL *Pool;
@@ -405,39 +678,54 @@ CoreFreePoolI (
UINTN NoPages;
UINTN Size;
CHAR8 *NewPage;
- UINTN FSize;
UINTN Offset;
BOOLEAN AllFree;
+ UINTN Granularity;
+ BOOLEAN IsGuarded;
+ BOOLEAN HasPoolTail;
+ BOOLEAN PageAsPool;
ASSERT(Buffer != NULL);
//
// Get the head & tail of the pool entry
//
- Head = CR (Buffer, POOL_HEAD, Data, POOL_HEAD_SIGNATURE);
+ Head = BASE_CR (Buffer, POOL_HEAD, Data);
ASSERT(Head != NULL);
- if (Head->Signature != POOL_HEAD_SIGNATURE) {
+ if (Head->Signature != POOL_HEAD_SIGNATURE &&
+ Head->Signature != POOLPAGE_HEAD_SIGNATURE) {
+ ASSERT (Head->Signature == POOL_HEAD_SIGNATURE ||
+ Head->Signature == POOLPAGE_HEAD_SIGNATURE);
return EFI_INVALID_PARAMETER;
}
- Tail = HEAD_TO_TAIL (Head);
- ASSERT(Tail != NULL);
+ IsGuarded = IsPoolTypeToGuard (Head->Type) &&
+ IsMemoryGuarded ((EFI_PHYSICAL_ADDRESS)(UINTN)Head);
+ HasPoolTail = !(IsGuarded &&
+ ((PcdGet8 (PcdHeapGuardPropertyMask) & BIT7) == 0));
+ PageAsPool = (Head->Signature == POOLPAGE_HEAD_SIGNATURE);
- //
- // Debug
- //
- ASSERT (Tail->Signature == POOL_TAIL_SIGNATURE);
- ASSERT (Head->Size == Tail->Size);
- ASSERT_LOCKED (&gMemoryLock);
+ if (HasPoolTail) {
+ Tail = HEAD_TO_TAIL (Head);
+ ASSERT (Tail != NULL);
- if (Tail->Signature != POOL_TAIL_SIGNATURE) {
- return EFI_INVALID_PARAMETER;
- }
+ //
+ // Debug
+ //
+ ASSERT (Tail->Signature == POOL_TAIL_SIGNATURE);
+ ASSERT (Head->Size == Tail->Size);
- if (Head->Size != Tail->Size) {
- return EFI_INVALID_PARAMETER;
+ if (Tail->Signature != POOL_TAIL_SIGNATURE) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Head->Size != Tail->Size) {
+ return EFI_INVALID_PARAMETER;
+ }
}
+ ASSERT_LOCKED (&mPoolMemoryLock);
+
//
// Determine the pool type and account for it
//
@@ -449,6 +737,20 @@ CoreFreePoolI (
Pool->Used -= Size;
DEBUG ((DEBUG_POOL, "FreePool: %p (len %lx) %,ld\n", Head->Data, (UINT64)(Head->Size - POOL_OVERHEAD), (UINT64) Pool->Used));
+ if (Head->Type == EfiACPIReclaimMemory ||
+ Head->Type == EfiACPIMemoryNVS ||
+ Head->Type == EfiRuntimeServicesCode ||
+ Head->Type == EfiRuntimeServicesData) {
+
+ Granularity = RUNTIME_PAGE_ALLOCATION_GRANULARITY;
+ } else {
+ Granularity = DEFAULT_PAGE_ALLOCATION_GRANULARITY;
+ }
+
+ if (PoolType != NULL) {
+ *PoolType = Head->Type;
+ }
+
//
// Determine the pool list
//
@@ -458,14 +760,27 @@ CoreFreePoolI (
//
// If it's not on the list, it must be pool pages
//
- if (Index >= MAX_POOL_LIST) {
+ if (Index >= SIZE_TO_LIST (Granularity) || IsGuarded || PageAsPool) {
//
// Return the memory pages back to free memory
//
- NoPages = EFI_SIZE_TO_PAGES(Size) + EFI_SIZE_TO_PAGES (DEFAULT_PAGE_ALLOCATION) - 1;
- NoPages &= ~(EFI_SIZE_TO_PAGES (DEFAULT_PAGE_ALLOCATION) - 1);
- CoreFreePoolPages ((EFI_PHYSICAL_ADDRESS) (UINTN) Head, NoPages);
+ NoPages = EFI_SIZE_TO_PAGES (Size) + EFI_SIZE_TO_PAGES (Granularity) - 1;
+ NoPages &= ~(UINTN)(EFI_SIZE_TO_PAGES (Granularity) - 1);
+ if (IsGuarded) {
+ Head = AdjustPoolHeadF ((EFI_PHYSICAL_ADDRESS)(UINTN)Head);
+ CoreFreePoolPagesWithGuard (
+ Pool->MemoryType,
+ (EFI_PHYSICAL_ADDRESS)(UINTN)Head,
+ NoPages
+ );
+ } else {
+ CoreFreePoolPagesI (
+ Pool->MemoryType,
+ (EFI_PHYSICAL_ADDRESS)(UINTN)Head,
+ NoPages
+ );
+ }
} else {
@@ -482,28 +797,22 @@ CoreFreePoolI (
// See if all the pool entries in the same page as Free are freed pool
// entries
//
- NewPage = (CHAR8 *)((UINTN)Free & ~((DEFAULT_PAGE_ALLOCATION) -1));
+ NewPage = (CHAR8 *)((UINTN)Free & ~(Granularity - 1));
Free = (POOL_FREE *) &NewPage[0];
ASSERT(Free != NULL);
if (Free->Signature == POOL_FREE_SIGNATURE) {
- Index = Free->Index;
-
AllFree = TRUE;
Offset = 0;
- while ((Offset < DEFAULT_PAGE_ALLOCATION) && (AllFree)) {
- FSize = LIST_TO_SIZE(Index);
- while (Offset + FSize <= DEFAULT_PAGE_ALLOCATION) {
- Free = (POOL_FREE *) &NewPage[Offset];
- ASSERT(Free != NULL);
- if (Free->Signature != POOL_FREE_SIGNATURE) {
- AllFree = FALSE;
- }
- Offset += FSize;
+ while ((Offset < Granularity) && (AllFree)) {
+ Free = (POOL_FREE *) &NewPage[Offset];
+ ASSERT(Free != NULL);
+ if (Free->Signature != POOL_FREE_SIGNATURE) {
+ AllFree = FALSE;
}
- Index -= 1;
+ Offset += LIST_TO_SIZE(Free->Index);
}
if (AllFree) {
@@ -515,37 +824,34 @@ CoreFreePoolI (
//
Free = (POOL_FREE *) &NewPage[0];
ASSERT(Free != NULL);
- Index = Free->Index;
Offset = 0;
- while (Offset < DEFAULT_PAGE_ALLOCATION) {
- FSize = LIST_TO_SIZE(Index);
- while (Offset + FSize <= DEFAULT_PAGE_ALLOCATION) {
- Free = (POOL_FREE *) &NewPage[Offset];
- ASSERT(Free != NULL);
- RemoveEntryList (&Free->Link);
- Offset += FSize;
- }
- Index -= 1;
+ while (Offset < Granularity) {
+ Free = (POOL_FREE *) &NewPage[Offset];
+ ASSERT(Free != NULL);
+ RemoveEntryList (&Free->Link);
+ Offset += LIST_TO_SIZE(Free->Index);
}
//
// Free the page
//
- CoreFreePoolPages ((EFI_PHYSICAL_ADDRESS) (UINTN)NewPage, EFI_SIZE_TO_PAGES (DEFAULT_PAGE_ALLOCATION));
+ CoreFreePoolPagesI (Pool->MemoryType, (EFI_PHYSICAL_ADDRESS) (UINTN)NewPage,
+ EFI_SIZE_TO_PAGES (Granularity));
}
}
}
//
- // If this is an OS specific memory type, then check to see if the last
+ // If this is an OS/OEM specific memory type, then check to see if the last
// portion of that memory type has been freed. If it has, then free the
// list entry for that memory type
//
- if (Pool->MemoryType < 0 && Pool->Used == 0) {
+ if (((UINT32) Pool->MemoryType >= MEMORY_TYPE_OEM_RESERVED_MIN) && Pool->Used == 0) {
RemoveEntryList (&Pool->Link);
- CoreFreePoolI (Pool);
+ CoreFreePoolI (Pool, NULL);
}
return EFI_SUCCESS;
}
+