MdeModulePkg/DxeCore: use separate lock for pool allocations

In preparation of adding memory permission attribute management to
the pool allocator, split off the locking of the pool metadata into
a separate lock. This is an improvement in itself, given that pool
allocations can only interfere with the page allocation bookkeeping
if pool pages are allocated or released. But it is also required to
ensure that the permission attribute management does not deadlock,
given that it may trigger page table splits leading to additional
page tables being allocated.

Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Reviewed-by: Jiewen Yao <jiewen.yao@intel.com>
Reviewed-by: Liming Gao <liming.gao@intel.com>
This commit is contained in:
Ard Biesheuvel 2017-02-24 14:21:18 +00:00
parent 16dc5b68fc
commit f31c36c293
1 changed files with 48 additions and 10 deletions

View File

@ -15,6 +15,8 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
#include "DxeMain.h" #include "DxeMain.h"
#include "Imem.h" #include "Imem.h"
STATIC EFI_LOCK mPoolMemoryLock = EFI_INITIALIZE_LOCK_VARIABLE (TPL_NOTIFY);
#define POOL_FREE_SIGNATURE SIGNATURE_32('p','f','r','0') #define POOL_FREE_SIGNATURE SIGNATURE_32('p','f','r','0')
typedef struct { typedef struct {
UINT32 Signature; UINT32 Signature;
@ -239,13 +241,13 @@ CoreInternalAllocatePool (
// //
// Acquire the memory lock and make the allocation // Acquire the memory lock and make the allocation
// //
Status = CoreAcquireLockOrFail (&gMemoryLock); Status = CoreAcquireLockOrFail (&mPoolMemoryLock);
if (EFI_ERROR (Status)) { if (EFI_ERROR (Status)) {
return EFI_OUT_OF_RESOURCES; return EFI_OUT_OF_RESOURCES;
} }
*Buffer = CoreAllocatePoolI (PoolType, Size); *Buffer = CoreAllocatePoolI (PoolType, Size);
CoreReleaseMemoryLock (); CoreReleaseLock (&mPoolMemoryLock);
return (*Buffer != NULL) ? EFI_SUCCESS : EFI_OUT_OF_RESOURCES; return (*Buffer != NULL) ? EFI_SUCCESS : EFI_OUT_OF_RESOURCES;
} }
@ -289,6 +291,28 @@ CoreAllocatePool (
return Status; return Status;
} }
STATIC
VOID *
CoreAllocatePoolPagesI (
IN EFI_MEMORY_TYPE PoolType,
IN UINTN NoPages,
IN UINTN Granularity
)
{
VOID *Buffer;
EFI_STATUS Status;
Status = CoreAcquireLockOrFail (&gMemoryLock);
if (EFI_ERROR (Status)) {
return NULL;
}
Buffer = CoreAllocatePoolPages (PoolType, NoPages, Granularity);
CoreReleaseMemoryLock ();
return Buffer;
}
/** /**
Internal function to allocate pool of a particular type. Internal function to allocate pool of a particular type.
Caller must have the memory lock held Caller must have the memory lock held
@ -317,7 +341,7 @@ CoreAllocatePoolI (
UINTN NoPages; UINTN NoPages;
UINTN Granularity; UINTN Granularity;
ASSERT_LOCKED (&gMemoryLock); ASSERT_LOCKED (&mPoolMemoryLock);
if (PoolType == EfiACPIReclaimMemory || if (PoolType == EfiACPIReclaimMemory ||
PoolType == EfiACPIMemoryNVS || PoolType == EfiACPIMemoryNVS ||
@ -355,7 +379,7 @@ CoreAllocatePoolI (
if (Index >= SIZE_TO_LIST (Granularity)) { if (Index >= SIZE_TO_LIST (Granularity)) {
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); NoPages &= ~(UINTN)(EFI_SIZE_TO_PAGES (Granularity) - 1);
Head = CoreAllocatePoolPages (PoolType, NoPages, Granularity); Head = CoreAllocatePoolPagesI (PoolType, NoPages, Granularity);
goto Done; goto Done;
} }
@ -383,7 +407,7 @@ CoreAllocatePoolI (
// //
// Get another page // Get another page
// //
NewPage = CoreAllocatePoolPages(PoolType, EFI_SIZE_TO_PAGES (Granularity), Granularity); NewPage = CoreAllocatePoolPagesI (PoolType, EFI_SIZE_TO_PAGES (Granularity), Granularity);
if (NewPage == NULL) { if (NewPage == NULL) {
goto Done; goto Done;
} }
@ -486,9 +510,9 @@ CoreInternalFreePool (
return EFI_INVALID_PARAMETER; return EFI_INVALID_PARAMETER;
} }
CoreAcquireMemoryLock (); CoreAcquireLock (&mPoolMemoryLock);
Status = CoreFreePoolI (Buffer, PoolType); Status = CoreFreePoolI (Buffer, PoolType);
CoreReleaseMemoryLock (); CoreReleaseLock (&mPoolMemoryLock);
return Status; return Status;
} }
@ -525,6 +549,19 @@ CoreFreePool (
return Status; return Status;
} }
STATIC
VOID
CoreFreePoolPagesI (
IN EFI_MEMORY_TYPE PoolType,
IN EFI_PHYSICAL_ADDRESS Memory,
IN UINTN NoPages
)
{
CoreAcquireMemoryLock ();
CoreFreePoolPages (Memory, NoPages);
CoreReleaseMemoryLock ();
}
/** /**
Internal function to free a pool entry. Internal function to free a pool entry.
Caller must have the memory lock held Caller must have the memory lock held
@ -573,7 +610,7 @@ CoreFreePoolI (
// //
ASSERT (Tail->Signature == POOL_TAIL_SIGNATURE); ASSERT (Tail->Signature == POOL_TAIL_SIGNATURE);
ASSERT (Head->Size == Tail->Size); ASSERT (Head->Size == Tail->Size);
ASSERT_LOCKED (&gMemoryLock); ASSERT_LOCKED (&mPoolMemoryLock);
if (Tail->Signature != POOL_TAIL_SIGNATURE) { if (Tail->Signature != POOL_TAIL_SIGNATURE) {
return EFI_INVALID_PARAMETER; return EFI_INVALID_PARAMETER;
@ -624,7 +661,7 @@ CoreFreePoolI (
// //
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); NoPages &= ~(UINTN)(EFI_SIZE_TO_PAGES (Granularity) - 1);
CoreFreePoolPages ((EFI_PHYSICAL_ADDRESS) (UINTN) Head, NoPages); CoreFreePoolPagesI (Pool->MemoryType, (EFI_PHYSICAL_ADDRESS) (UINTN) Head, NoPages);
} else { } else {
@ -680,7 +717,8 @@ CoreFreePoolI (
// //
// Free the page // 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));
} }
} }
} }