/** @file\r
SMM Memory pool management functions.\r
\r
- Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR>\r
- This program and the accompanying materials are licensed and made available \r
- under the terms and conditions of the BSD License which accompanies this \r
- distribution. The full text of the license may be found at \r
- http://opensource.org/licenses/bsd-license.php \r
+ Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>\r
+ This program and the accompanying materials are licensed and made available\r
+ under the terms and conditions of the BSD License which accompanies this\r
+ 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
+ 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 "PiSmmCore.h"\r
\r
+LIST_ENTRY mSmmPoolLists[SmmPoolTypeMax][MAX_POOL_INDEX];\r
//\r
-// MIN_POOL_SHIFT must not be less than 5\r
+// To cache the SMRAM base since when Loading modules At fixed address feature is enabled,\r
+// all module is assigned an offset relative the SMRAM base in build time.\r
//\r
-#define MIN_POOL_SHIFT 6\r
-#define MIN_POOL_SIZE (1 << MIN_POOL_SHIFT)\r
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_PHYSICAL_ADDRESS gLoadModuleAtFixAddressSmramBase = 0;\r
\r
-//\r
-// MAX_POOL_SHIFT must not be less than EFI_PAGE_SHIFT - 1\r
-//\r
-#define MAX_POOL_SHIFT (EFI_PAGE_SHIFT - 1)\r
-#define MAX_POOL_SIZE (1 << MAX_POOL_SHIFT)\r
-\r
-//\r
-// MAX_POOL_INDEX are calculated by maximum and minimum pool sizes\r
-//\r
-#define MAX_POOL_INDEX (MAX_POOL_SHIFT - MIN_POOL_SHIFT + 1)\r
+/**\r
+ Convert a UEFI memory type to SMM pool type.\r
\r
-typedef struct {\r
- UINTN Size;\r
- BOOLEAN Available;\r
-} POOL_HEADER;\r
+ @param[in] MemoryType Type of pool to allocate.\r
\r
-typedef struct {\r
- POOL_HEADER Header;\r
- LIST_ENTRY Link;\r
-} FREE_POOL_HEADER;\r
+ @return SMM pool type\r
+**/\r
+SMM_POOL_TYPE\r
+UefiMemoryTypeToSmmPoolType (\r
+ IN EFI_MEMORY_TYPE MemoryType\r
+ )\r
+{\r
+ ASSERT ((MemoryType == EfiRuntimeServicesCode) || (MemoryType == EfiRuntimeServicesData));\r
+ switch (MemoryType) {\r
+ case EfiRuntimeServicesCode:\r
+ return SmmPoolTypeCode;\r
+ case EfiRuntimeServicesData:\r
+ return SmmPoolTypeData;\r
+ default:\r
+ return SmmPoolTypeMax;\r
+ }\r
+}\r
\r
-LIST_ENTRY mSmmPoolLists[MAX_POOL_INDEX];\r
\r
/**\r
Called to initialize the memory service.\r
IN EFI_SMRAM_DESCRIPTOR *SmramRanges\r
)\r
{\r
- UINTN Index;\r
+ UINTN Index;\r
+ EFI_STATUS Status;\r
+ UINTN SmmPoolTypeIndex;\r
+ EFI_LOAD_FIXED_ADDRESS_CONFIGURATION_TABLE *LMFAConfigurationTable;\r
\r
//\r
// Initialize Pool list\r
//\r
- for (Index = sizeof (mSmmPoolLists) / sizeof (*mSmmPoolLists); Index > 0;) {\r
- InitializeListHead (&mSmmPoolLists[--Index]);\r
+ for (SmmPoolTypeIndex = 0; SmmPoolTypeIndex < SmmPoolTypeMax; SmmPoolTypeIndex++) {\r
+ for (Index = 0; Index < ARRAY_SIZE (mSmmPoolLists[SmmPoolTypeIndex]); Index++) {\r
+ InitializeListHead (&mSmmPoolLists[SmmPoolTypeIndex][Index]);\r
+ }\r
+ }\r
+\r
+ Status = EfiGetSystemConfigurationTable (\r
+ &gLoadFixedAddressConfigurationTableGuid,\r
+ (VOID **) &LMFAConfigurationTable\r
+ );\r
+ if (!EFI_ERROR (Status) && LMFAConfigurationTable != NULL) {\r
+ gLoadModuleAtFixAddressSmramBase = LMFAConfigurationTable->SmramBase;\r
+ }\r
+\r
+ //\r
+ // Add Free SMRAM regions\r
+ // Need add Free memory at first, to let gSmmMemoryMap record data\r
+ //\r
+ for (Index = 0; Index < SmramRangeCount; Index++) {\r
+ if ((SmramRanges[Index].RegionState & (EFI_ALLOCATED | EFI_NEEDS_TESTING | EFI_NEEDS_ECC_INITIALIZATION)) != 0) {\r
+ continue;\r
+ }\r
+ SmmAddMemoryRegion (\r
+ SmramRanges[Index].CpuStart,\r
+ SmramRanges[Index].PhysicalSize,\r
+ EfiConventionalMemory,\r
+ SmramRanges[Index].RegionState\r
+ );\r
}\r
\r
//\r
- // Initialize free SMRAM regions\r
+ // Add the allocated SMRAM regions\r
//\r
for (Index = 0; Index < SmramRangeCount; Index++) {\r
+ if ((SmramRanges[Index].RegionState & (EFI_ALLOCATED | EFI_NEEDS_TESTING | EFI_NEEDS_ECC_INITIALIZATION)) == 0) {\r
+ continue;\r
+ }\r
SmmAddMemoryRegion (\r
SmramRanges[Index].CpuStart,\r
SmramRanges[Index].PhysicalSize,\r
SmramRanges[Index].RegionState\r
);\r
}\r
+\r
}\r
\r
/**\r
Internal Function. Allocate a pool by specified PoolIndex.\r
\r
+ @param PoolType Type of pool to allocate.\r
@param PoolIndex Index which indicate the Pool size.\r
@param FreePoolHdr The returned Free pool.\r
\r
**/\r
EFI_STATUS\r
InternalAllocPoolByIndex (\r
+ IN EFI_MEMORY_TYPE PoolType,\r
IN UINTN PoolIndex,\r
OUT FREE_POOL_HEADER **FreePoolHdr\r
)\r
{\r
- EFI_STATUS Status;\r
- FREE_POOL_HEADER *Hdr;\r
+ EFI_STATUS Status;\r
+ FREE_POOL_HEADER *Hdr;\r
+ POOL_TAIL *Tail;\r
+ EFI_PHYSICAL_ADDRESS Address;\r
+ SMM_POOL_TYPE SmmPoolType;\r
+\r
+ Address = 0;\r
+ SmmPoolType = UefiMemoryTypeToSmmPoolType(PoolType);\r
\r
ASSERT (PoolIndex <= MAX_POOL_INDEX);\r
Status = EFI_SUCCESS;\r
+ Hdr = NULL;\r
if (PoolIndex == MAX_POOL_INDEX) {\r
- Hdr = (FREE_POOL_HEADER *)AllocatePages (EFI_SIZE_TO_PAGES (MAX_POOL_SIZE << 1));\r
- if (Hdr == NULL) {\r
+ Status = SmmInternalAllocatePages (AllocateAnyPages, PoolType,\r
+ EFI_SIZE_TO_PAGES (MAX_POOL_SIZE << 1),\r
+ &Address, FALSE);\r
+ if (EFI_ERROR (Status)) {\r
return EFI_OUT_OF_RESOURCES;\r
}\r
- } else if (!IsListEmpty (&mSmmPoolLists[PoolIndex])) {\r
- Hdr = BASE_CR (GetFirstNode (&mSmmPoolLists[PoolIndex]), FREE_POOL_HEADER, Link);\r
+ Hdr = (FREE_POOL_HEADER *) (UINTN) Address;\r
+ } else if (!IsListEmpty (&mSmmPoolLists[SmmPoolType][PoolIndex])) {\r
+ Hdr = BASE_CR (GetFirstNode (&mSmmPoolLists[SmmPoolType][PoolIndex]), FREE_POOL_HEADER, Link);\r
RemoveEntryList (&Hdr->Link);\r
} else {\r
- Status = InternalAllocPoolByIndex (PoolIndex + 1, &Hdr);\r
+ Status = InternalAllocPoolByIndex (PoolType, PoolIndex + 1, &Hdr);\r
if (!EFI_ERROR (Status)) {\r
+ Hdr->Header.Signature = 0;\r
Hdr->Header.Size >>= 1;\r
Hdr->Header.Available = TRUE;\r
- InsertHeadList (&mSmmPoolLists[PoolIndex], &Hdr->Link);\r
+ Hdr->Header.Type = 0;\r
+ Tail = HEAD_TO_TAIL(&Hdr->Header);\r
+ Tail->Signature = 0;\r
+ Tail->Size = 0;\r
+ InsertHeadList (&mSmmPoolLists[SmmPoolType][PoolIndex], &Hdr->Link);\r
Hdr = (FREE_POOL_HEADER*)((UINT8*)Hdr + Hdr->Header.Size);\r
}\r
}\r
\r
if (!EFI_ERROR (Status)) {\r
+ Hdr->Header.Signature = POOL_HEAD_SIGNATURE;\r
Hdr->Header.Size = MIN_POOL_SIZE << PoolIndex;\r
Hdr->Header.Available = FALSE;\r
+ Hdr->Header.Type = PoolType;\r
+ Tail = HEAD_TO_TAIL(&Hdr->Header);\r
+ Tail->Signature = POOL_TAIL_SIGNATURE;\r
+ Tail->Size = Hdr->Header.Size;\r
}\r
\r
*FreePoolHdr = Hdr;\r
Internal Function. Free a pool by specified PoolIndex.\r
\r
@param FreePoolHdr The pool to free.\r
+ @param PoolTail The pointer to the pool tail.\r
\r
@retval EFI_SUCCESS Pool successfully freed.\r
\r
**/\r
EFI_STATUS\r
InternalFreePoolByIndex (\r
- IN FREE_POOL_HEADER *FreePoolHdr\r
+ IN FREE_POOL_HEADER *FreePoolHdr,\r
+ IN POOL_TAIL *PoolTail\r
)\r
{\r
- UINTN PoolIndex;\r
+ UINTN PoolIndex;\r
+ SMM_POOL_TYPE SmmPoolType;\r
\r
ASSERT ((FreePoolHdr->Header.Size & (FreePoolHdr->Header.Size - 1)) == 0);\r
ASSERT (((UINTN)FreePoolHdr & (FreePoolHdr->Header.Size - 1)) == 0);\r
ASSERT (FreePoolHdr->Header.Size >= MIN_POOL_SIZE);\r
\r
- PoolIndex = HighBitSet32 ((UINT32)FreePoolHdr->Header.Size) - MIN_POOL_SHIFT;\r
+ SmmPoolType = UefiMemoryTypeToSmmPoolType(FreePoolHdr->Header.Type);\r
+\r
+ PoolIndex = (UINTN) (HighBitSet32 ((UINT32)FreePoolHdr->Header.Size) - MIN_POOL_SHIFT);\r
+ FreePoolHdr->Header.Signature = 0;\r
FreePoolHdr->Header.Available = TRUE;\r
+ FreePoolHdr->Header.Type = 0;\r
+ PoolTail->Signature = 0;\r
+ PoolTail->Size = 0;\r
ASSERT (PoolIndex < MAX_POOL_INDEX);\r
- InsertHeadList (&mSmmPoolLists[PoolIndex], &FreePoolHdr->Link);\r
+ InsertHeadList (&mSmmPoolLists[SmmPoolType][PoolIndex], &FreePoolHdr->Link);\r
return EFI_SUCCESS;\r
}\r
\r
**/\r
EFI_STATUS\r
EFIAPI\r
-SmmAllocatePool (\r
+SmmInternalAllocatePool (\r
IN EFI_MEMORY_TYPE PoolType,\r
IN UINTN Size,\r
OUT VOID **Buffer\r
)\r
{\r
POOL_HEADER *PoolHdr;\r
+ POOL_TAIL *PoolTail;\r
FREE_POOL_HEADER *FreePoolHdr;\r
EFI_STATUS Status;\r
EFI_PHYSICAL_ADDRESS Address;\r
UINTN PoolIndex;\r
+ BOOLEAN HasPoolTail;\r
+ BOOLEAN NeedGuard;\r
+ UINTN NoPages;\r
+\r
+ Address = 0;\r
\r
if (PoolType != EfiRuntimeServicesCode &&\r
PoolType != EfiRuntimeServicesData) {\r
return EFI_INVALID_PARAMETER;\r
}\r
\r
- if (Size == 0) {\r
- *Buffer = NULL;\r
- return EFI_SUCCESS;\r
- }\r
+ NeedGuard = IsPoolTypeToGuard (PoolType);\r
+ HasPoolTail = !(NeedGuard &&\r
+ ((PcdGet8 (PcdHeapGuardPropertyMask) & BIT7) == 0));\r
\r
- Size += sizeof (*PoolHdr);\r
- if (Size > MAX_POOL_SIZE) {\r
- Size = EFI_SIZE_TO_PAGES (Size);\r
- Status = SmmAllocatePages (AllocateAnyPages, PoolType, Size, &Address);\r
+ //\r
+ // Adjust the size by the pool header & tail overhead\r
+ //\r
+ Size += POOL_OVERHEAD;\r
+ if (Size > MAX_POOL_SIZE || NeedGuard) {\r
+ if (!HasPoolTail) {\r
+ Size -= sizeof (POOL_TAIL);\r
+ }\r
+\r
+ NoPages = EFI_SIZE_TO_PAGES (Size);\r
+ Status = SmmInternalAllocatePages (AllocateAnyPages, PoolType, NoPages,\r
+ &Address, NeedGuard);\r
if (EFI_ERROR (Status)) {\r
return Status;\r
}\r
\r
+ if (NeedGuard) {\r
+ ASSERT (VerifyMemoryGuard (Address, NoPages) == TRUE);\r
+ Address = (EFI_PHYSICAL_ADDRESS)(UINTN)AdjustPoolHeadA (\r
+ Address,\r
+ NoPages,\r
+ Size\r
+ );\r
+ }\r
+\r
PoolHdr = (POOL_HEADER*)(UINTN)Address;\r
- PoolHdr->Size = EFI_PAGES_TO_SIZE (Size);\r
+ PoolHdr->Signature = POOL_HEAD_SIGNATURE;\r
+ PoolHdr->Size = EFI_PAGES_TO_SIZE (NoPages);\r
PoolHdr->Available = FALSE;\r
+ PoolHdr->Type = PoolType;\r
+\r
+ if (HasPoolTail) {\r
+ PoolTail = HEAD_TO_TAIL (PoolHdr);\r
+ PoolTail->Signature = POOL_TAIL_SIGNATURE;\r
+ PoolTail->Size = PoolHdr->Size;\r
+ }\r
+\r
*Buffer = PoolHdr + 1;\r
return Status;\r
}\r
\r
Size = (Size + MIN_POOL_SIZE - 1) >> MIN_POOL_SHIFT;\r
- PoolIndex = HighBitSet32 ((UINT32)Size);\r
+ PoolIndex = (UINTN) HighBitSet32 ((UINT32)Size);\r
if ((Size & (Size - 1)) != 0) {\r
PoolIndex++;\r
}\r
\r
- Status = InternalAllocPoolByIndex (PoolIndex, &FreePoolHdr);\r
- *Buffer = &FreePoolHdr->Header + 1;\r
+ Status = InternalAllocPoolByIndex (PoolType, PoolIndex, &FreePoolHdr);\r
+ if (!EFI_ERROR(Status)) {\r
+ *Buffer = &FreePoolHdr->Header + 1;\r
+ }\r
+ return Status;\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 PoolType not valid.\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
+SmmAllocatePool (\r
+ IN EFI_MEMORY_TYPE PoolType,\r
+ IN UINTN Size,\r
+ OUT VOID **Buffer\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ Status = SmmInternalAllocatePool (PoolType, Size, Buffer);\r
+ if (!EFI_ERROR (Status)) {\r
+ SmmCoreUpdateProfile (\r
+ (EFI_PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS (0),\r
+ MemoryProfileActionAllocatePool,\r
+ PoolType,\r
+ Size,\r
+ *Buffer,\r
+ NULL\r
+ );\r
+ }\r
return Status;\r
}\r
\r
**/\r
EFI_STATUS\r
EFIAPI\r
-SmmFreePool (\r
+SmmInternalFreePool (\r
IN VOID *Buffer\r
)\r
{\r
FREE_POOL_HEADER *FreePoolHdr;\r
+ POOL_TAIL *PoolTail;\r
+ BOOLEAN HasPoolTail;\r
+ BOOLEAN MemoryGuarded;\r
\r
if (Buffer == NULL) {\r
return EFI_INVALID_PARAMETER;\r
}\r
\r
+ MemoryGuarded = IsHeapGuardEnabled () &&\r
+ IsMemoryGuarded ((EFI_PHYSICAL_ADDRESS)(UINTN)Buffer);\r
+ HasPoolTail = !(MemoryGuarded &&\r
+ ((PcdGet8 (PcdHeapGuardPropertyMask) & BIT7) == 0));\r
+\r
FreePoolHdr = (FREE_POOL_HEADER*)((POOL_HEADER*)Buffer - 1);\r
+ ASSERT (FreePoolHdr->Header.Signature == POOL_HEAD_SIGNATURE);\r
ASSERT (!FreePoolHdr->Header.Available);\r
+ if (FreePoolHdr->Header.Signature != POOL_HEAD_SIGNATURE) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (HasPoolTail) {\r
+ PoolTail = HEAD_TO_TAIL (&FreePoolHdr->Header);\r
+ ASSERT (PoolTail->Signature == POOL_TAIL_SIGNATURE);\r
+ ASSERT (FreePoolHdr->Header.Size == PoolTail->Size);\r
+ if (PoolTail->Signature != POOL_TAIL_SIGNATURE) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (FreePoolHdr->Header.Size != PoolTail->Size) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ } else {\r
+ PoolTail = NULL;\r
+ }\r
+\r
+ if (MemoryGuarded) {\r
+ Buffer = AdjustPoolHeadF ((EFI_PHYSICAL_ADDRESS)(UINTN)FreePoolHdr);\r
+ return SmmInternalFreePages (\r
+ (EFI_PHYSICAL_ADDRESS)(UINTN)Buffer,\r
+ EFI_SIZE_TO_PAGES (FreePoolHdr->Header.Size),\r
+ TRUE\r
+ );\r
+ }\r
\r
if (FreePoolHdr->Header.Size > MAX_POOL_SIZE) {\r
ASSERT (((UINTN)FreePoolHdr & EFI_PAGE_MASK) == 0);\r
ASSERT ((FreePoolHdr->Header.Size & EFI_PAGE_MASK) == 0);\r
- return SmmFreePages (\r
+ return SmmInternalFreePages (\r
(EFI_PHYSICAL_ADDRESS)(UINTN)FreePoolHdr,\r
- EFI_SIZE_TO_PAGES (FreePoolHdr->Header.Size)\r
+ EFI_SIZE_TO_PAGES (FreePoolHdr->Header.Size),\r
+ FALSE\r
);\r
}\r
- return InternalFreePoolByIndex (FreePoolHdr);\r
+ return InternalFreePoolByIndex (FreePoolHdr, PoolTail);\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
+SmmFreePool (\r
+ IN VOID *Buffer\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ Status = SmmInternalFreePool (Buffer);\r
+ if (!EFI_ERROR (Status)) {\r
+ SmmCoreUpdateProfile (\r
+ (EFI_PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS (0),\r
+ MemoryProfileActionFreePool,\r
+ EfiMaxMemoryType,\r
+ 0,\r
+ Buffer,\r
+ NULL\r
+ );\r
+ }\r
+ return Status;\r
}\r