X-Git-Url: https://git.proxmox.com/?p=mirror_edk2.git;a=blobdiff_plain;f=MdeModulePkg%2FCore%2FDxe%2FMem%2FPool.c;h=734fc94bf6129ad20f3e8846c9cf13aaee7266ab;hp=528c8e8ce9a52326d0db5e1d6dd718e158b13475;hb=9d510e61fceee7b92955ef9a3c20343752d8ce3f;hpb=2eb989bc29c2c0bacae6d79fc7e066c58ec12b5e diff --git a/MdeModulePkg/Core/Dxe/Mem/Pool.c b/MdeModulePkg/Core/Dxe/Mem/Pool.c index 528c8e8ce9..734fc94bf6 100644 --- a/MdeModulePkg/Core/Dxe/Mem/Pool.c +++ b/MdeModulePkg/Core/Dxe/Mem/Pool.c @@ -1,19 +1,16 @@ /** @file UEFI Memory pool management functions. -Copyright (c) 2006 - 2016, 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 SIGNATURE_32('p','f','r','0') typedef struct { @@ -23,7 +20,8 @@ typedef struct { } POOL_FREE; -#define POOL_HEAD_SIGNATURE 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 Reserved; @@ -52,13 +50,13 @@ typedef struct { // as we would in a strict power-of-2 sequence // STATIC CONST UINT16 mPoolSizeTable[] = { - 64, 128, 192, 320, 512, 832, 1344, 2176, 3520, 5696, 9216, 14912, 24128 + 128, 256, 384, 640, 1024, 1664, 2688, 4352, 7040, 11392, 18432, 29824 }; #define SIZE_TO_LIST(a) (GetPoolIndexFromSize (a)) #define LIST_TO_SIZE(a) (mPoolSizeTable [a]) -#define MAX_POOL_LIST (sizeof (mPoolSizeTable) / sizeof (mPoolSizeTable[0])) +#define MAX_POOL_LIST (ARRAY_SIZE (mPoolSizeTable)) #define MAX_POOL_SIZE (MAX_ADDRESS - POOL_OVERHEAD) @@ -167,7 +165,7 @@ LookupPoolHead ( } } - Pool = CoreAllocatePoolI (EfiBootServicesData, sizeof (POOL)); + Pool = CoreAllocatePoolI (EfiBootServicesData, sizeof (POOL), FALSE); if (Pool == NULL) { return NULL; } @@ -212,7 +210,8 @@ CoreInternalAllocatePool ( OUT VOID **Buffer ) { - EFI_STATUS Status; + EFI_STATUS Status; + BOOLEAN NeedGuard; // // If it's not a valid type, fail it @@ -236,16 +235,18 @@ CoreInternalAllocatePool ( 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; } @@ -276,17 +277,68 @@ CoreAllocatePool ( Status = CoreInternalAllocatePool (PoolType, Size, Buffer); if (!EFI_ERROR (Status)) { - CoreUpdateProfile ((EFI_PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS (0), MemoryProfileActionAllocatePool, PoolType, Size, *Buffer); + 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. Caller must have the memory lock held @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 @@ -294,7 +346,8 @@ CoreAllocatePool ( VOID * CoreAllocatePoolI ( IN EFI_MEMORY_TYPE PoolType, - IN UINTN Size + IN UINTN Size, + IN BOOLEAN NeedGuard ) { POOL *Pool; @@ -308,23 +361,29 @@ CoreAllocatePoolI ( UINTN Offset, MaxOffset; UINTN NoPages; UINTN Granularity; + BOOLEAN HasPoolTail; + BOOLEAN PageAsPool; - ASSERT_LOCKED (&gMemoryLock); + ASSERT_LOCKED (&mPoolMemoryLock); if (PoolType == EfiACPIReclaimMemory || PoolType == EfiACPIMemoryNVS || PoolType == EfiRuntimeServicesCode || PoolType == EfiRuntimeServicesData) { - Granularity = EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT; + Granularity = RUNTIME_PAGE_ALLOCATION_GRANULARITY; } else { - Granularity = DEFAULT_PAGE_ALLOCATION; + 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 @@ -344,10 +403,16 @@ CoreAllocatePoolI ( // If allocation is over max size, just allocate pages for the request // (slow) // - if (Index >= SIZE_TO_LIST (Granularity)) { - NoPages = EFI_SIZE_TO_PAGES(Size) + EFI_SIZE_TO_PAGES (Granularity) - 1; + 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 = CoreAllocatePoolPages (PoolType, NoPages, Granularity); + Head = CoreAllocatePoolPagesI (PoolType, NoPages, Granularity, NeedGuard); + if (NeedGuard) { + Head = AdjustPoolHeadA ((EFI_PHYSICAL_ADDRESS)(UINTN)Head, NoPages, Size); + } goto Done; } @@ -375,7 +440,8 @@ CoreAllocatePoolI ( // // Get another page // - NewPage = CoreAllocatePoolPages(PoolType, EFI_SIZE_TO_PAGES (Granularity), Granularity); + NewPage = CoreAllocatePoolPagesI (PoolType, EFI_SIZE_TO_PAGES (Granularity), + Granularity, NeedGuard); if (NewPage == NULL) { goto Done; } @@ -421,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->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 = 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)); @@ -459,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. @@ -467,7 +543,8 @@ Done: EFI_STATUS EFIAPI CoreInternalFreePool ( - IN VOID *Buffer + IN VOID *Buffer, + OUT EFI_MEMORY_TYPE *PoolType OPTIONAL ) { EFI_STATUS Status; @@ -476,9 +553,9 @@ CoreInternalFreePool ( return EFI_INVALID_PARAMETER; } - CoreAcquireMemoryLock (); - Status = CoreFreePoolI (Buffer); - CoreReleaseMemoryLock (); + CoreAcquireLock (&mPoolMemoryLock); + Status = CoreFreePoolI (Buffer, PoolType); + CoreReleaseLock (&mPoolMemoryLock); return Status; } @@ -497,20 +574,91 @@ CoreFreePool ( IN VOID *Buffer ) { - EFI_STATUS Status; + EFI_STATUS Status; + EFI_MEMORY_TYPE PoolType; - Status = CoreInternalFreePool (Buffer); + Status = CoreInternalFreePool (Buffer, &PoolType); if (!EFI_ERROR (Status)) { - CoreUpdateProfile ((EFI_PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS (0), MemoryProfileActionFreePool, (EFI_MEMORY_TYPE) 0, 0, Buffer); + 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 (); + CoreFreePoolPages (Memory, NoPages); + CoreReleaseMemoryLock (); + + 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. @@ -518,7 +666,8 @@ CoreFreePool ( **/ EFI_STATUS CoreFreePoolI ( - IN VOID *Buffer + IN VOID *Buffer, + OUT EFI_MEMORY_TYPE *PoolType OPTIONAL ) { POOL *Pool; @@ -532,36 +681,51 @@ CoreFreePoolI ( 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 // @@ -578,9 +742,13 @@ CoreFreePoolI ( Head->Type == EfiRuntimeServicesCode || Head->Type == EfiRuntimeServicesData) { - Granularity = EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT; + Granularity = RUNTIME_PAGE_ALLOCATION_GRANULARITY; } else { - Granularity = DEFAULT_PAGE_ALLOCATION; + Granularity = DEFAULT_PAGE_ALLOCATION_GRANULARITY; + } + + if (PoolType != NULL) { + *PoolType = Head->Type; } // @@ -592,14 +760,27 @@ CoreFreePoolI ( // // If it's not on the list, it must be pool pages // - if (Index >= SIZE_TO_LIST (Granularity)) { + 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 (Granularity) - 1; + NoPages = EFI_SIZE_TO_PAGES (Size) + EFI_SIZE_TO_PAGES (Granularity) - 1; NoPages &= ~(UINTN)(EFI_SIZE_TO_PAGES (Granularity) - 1); - CoreFreePoolPages ((EFI_PHYSICAL_ADDRESS) (UINTN) Head, NoPages); + 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 { @@ -655,7 +836,8 @@ CoreFreePoolI ( // // Free the page // - CoreFreePoolPages ((EFI_PHYSICAL_ADDRESS) (UINTN)NewPage, EFI_SIZE_TO_PAGES (Granularity)); + CoreFreePoolPagesI (Pool->MemoryType, (EFI_PHYSICAL_ADDRESS) (UINTN)NewPage, + EFI_SIZE_TO_PAGES (Granularity)); } } } @@ -667,7 +849,7 @@ CoreFreePoolI ( // if (((UINT32) Pool->MemoryType >= MEMORY_TYPE_OEM_RESERVED_MIN) && Pool->Used == 0) { RemoveEntryList (&Pool->Link); - CoreFreePoolI (Pool); + CoreFreePoolI (Pool, NULL); } return EFI_SUCCESS;