--- /dev/null
+/** @file\r
+ SMM Memory pool management functions.\r
+\r
+ Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.<BR>\r
+ Copyright (c) 2016 - 2018, ARM Limited. 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
+\r
+**/\r
+\r
+#include "StandaloneMmCore.h"\r
+\r
+LIST_ENTRY mMmPoolLists[MAX_POOL_INDEX];\r
+//\r
+// To cache the MMRAM base since when Loading modules At fixed address feature is enabled,\r
+// all module is assigned an offset relative the MMRAM base in build time.\r
+//\r
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_PHYSICAL_ADDRESS gLoadModuleAtFixAddressMmramBase = 0;\r
+\r
+/**\r
+ Called to initialize the memory service.\r
+\r
+ @param MmramRangeCount Number of MMRAM Regions\r
+ @param MmramRanges Pointer to MMRAM Descriptors\r
+\r
+**/\r
+VOID\r
+MmInitializeMemoryServices (\r
+ IN UINTN MmramRangeCount,\r
+ IN EFI_MMRAM_DESCRIPTOR *MmramRanges\r
+ )\r
+{\r
+ UINTN Index;\r
+\r
+ //\r
+ // Initialize Pool list\r
+ //\r
+ for (Index = sizeof (mMmPoolLists) / sizeof (*mMmPoolLists); Index > 0;) {\r
+ InitializeListHead (&mMmPoolLists[--Index]);\r
+ }\r
+\r
+\r
+ //\r
+ // Initialize free MMRAM regions\r
+ //\r
+ for (Index = 0; Index < MmramRangeCount; Index++) {\r
+ //\r
+ // BUGBUG: Add legacy MMRAM region is buggy.\r
+ //\r
+ if (MmramRanges[Index].CpuStart < BASE_1MB) {\r
+ continue;\r
+ }\r
+ DEBUG ((DEBUG_INFO, "MmAddMemoryRegion %d : 0x%016lx - 0x%016lx\n",\r
+ Index, MmramRanges[Index].CpuStart, MmramRanges[Index].PhysicalSize));\r
+ MmAddMemoryRegion (\r
+ MmramRanges[Index].CpuStart,\r
+ MmramRanges[Index].PhysicalSize,\r
+ EfiConventionalMemory,\r
+ MmramRanges[Index].RegionState\r
+ );\r
+ }\r
+\r
+}\r
+\r
+/**\r
+ Internal Function. Allocate a pool by specified PoolIndex.\r
+\r
+ @param PoolIndex Index which indicate the Pool size.\r
+ @param FreePoolHdr The returned Free pool.\r
+\r
+ @retval EFI_OUT_OF_RESOURCES Allocation failed.\r
+ @retval EFI_SUCCESS Pool successfully allocated.\r
+\r
+**/\r
+EFI_STATUS\r
+InternalAllocPoolByIndex (\r
+ IN UINTN PoolIndex,\r
+ OUT FREE_POOL_HEADER **FreePoolHdr\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ FREE_POOL_HEADER *Hdr;\r
+ EFI_PHYSICAL_ADDRESS Address;\r
+\r
+ ASSERT (PoolIndex <= MAX_POOL_INDEX);\r
+ Status = EFI_SUCCESS;\r
+ Hdr = NULL;\r
+ if (PoolIndex == MAX_POOL_INDEX) {\r
+ Status = MmInternalAllocatePages (\r
+ AllocateAnyPages,\r
+ EfiRuntimeServicesData,\r
+ EFI_SIZE_TO_PAGES (MAX_POOL_SIZE << 1),\r
+ &Address\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+ Hdr = (FREE_POOL_HEADER *) (UINTN) Address;\r
+ } else if (!IsListEmpty (&mMmPoolLists[PoolIndex])) {\r
+ Hdr = BASE_CR (GetFirstNode (&mMmPoolLists[PoolIndex]), FREE_POOL_HEADER, Link);\r
+ RemoveEntryList (&Hdr->Link);\r
+ } else {\r
+ Status = InternalAllocPoolByIndex (PoolIndex + 1, &Hdr);\r
+ if (!EFI_ERROR (Status)) {\r
+ Hdr->Header.Size >>= 1;\r
+ Hdr->Header.Available = TRUE;\r
+ InsertHeadList (&mMmPoolLists[PoolIndex], &Hdr->Link);\r
+ Hdr = (FREE_POOL_HEADER*)((UINT8*)Hdr + Hdr->Header.Size);\r
+ }\r
+ }\r
+\r
+ if (!EFI_ERROR (Status)) {\r
+ Hdr->Header.Size = MIN_POOL_SIZE << PoolIndex;\r
+ Hdr->Header.Available = FALSE;\r
+ }\r
+\r
+ *FreePoolHdr = Hdr;\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Internal Function. Free a pool by specified PoolIndex.\r
+\r
+ @param FreePoolHdr The pool to free.\r
+\r
+ @retval EFI_SUCCESS Pool successfully freed.\r
+\r
+**/\r
+EFI_STATUS\r
+InternalFreePoolByIndex (\r
+ IN FREE_POOL_HEADER *FreePoolHdr\r
+ )\r
+{\r
+ UINTN PoolIndex;\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 = (UINTN) (HighBitSet32 ((UINT32)FreePoolHdr->Header.Size) - MIN_POOL_SHIFT);\r
+ FreePoolHdr->Header.Available = TRUE;\r
+ ASSERT (PoolIndex < MAX_POOL_INDEX);\r
+ InsertHeadList (&mMmPoolLists[PoolIndex], &FreePoolHdr->Link);\r
+ return EFI_SUCCESS;\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
+MmInternalAllocatePool (\r
+ IN EFI_MEMORY_TYPE PoolType,\r
+ IN UINTN Size,\r
+ OUT VOID **Buffer\r
+ )\r
+{\r
+ POOL_HEADER *PoolHdr;\r
+ FREE_POOL_HEADER *FreePoolHdr;\r
+ EFI_STATUS Status;\r
+ EFI_PHYSICAL_ADDRESS Address;\r
+ UINTN PoolIndex;\r
+\r
+ if (PoolType != EfiRuntimeServicesCode &&\r
+ PoolType != EfiRuntimeServicesData) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Size += sizeof (*PoolHdr);\r
+ if (Size > MAX_POOL_SIZE) {\r
+ Size = EFI_SIZE_TO_PAGES (Size);\r
+ Status = MmInternalAllocatePages (AllocateAnyPages, PoolType, Size, &Address);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ PoolHdr = (POOL_HEADER*)(UINTN)Address;\r
+ PoolHdr->Size = EFI_PAGES_TO_SIZE (Size);\r
+ PoolHdr->Available = FALSE;\r
+ *Buffer = PoolHdr + 1;\r
+ return Status;\r
+ }\r
+\r
+ Size = (Size + MIN_POOL_SIZE - 1) >> MIN_POOL_SHIFT;\r
+ PoolIndex = (UINTN) HighBitSet32 ((UINT32)Size);\r
+ if ((Size & (Size - 1)) != 0) {\r
+ PoolIndex++;\r
+ }\r
+\r
+ Status = InternalAllocPoolByIndex (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
+MmAllocatePool (\r
+ IN EFI_MEMORY_TYPE PoolType,\r
+ IN UINTN Size,\r
+ OUT VOID **Buffer\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ Status = MmInternalAllocatePool (PoolType, Size, Buffer);\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
+MmInternalFreePool (\r
+ IN VOID *Buffer\r
+ )\r
+{\r
+ FREE_POOL_HEADER *FreePoolHdr;\r
+\r
+ if (Buffer == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ FreePoolHdr = (FREE_POOL_HEADER*)((POOL_HEADER*)Buffer - 1);\r
+ ASSERT (!FreePoolHdr->Header.Available);\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 MmInternalFreePages (\r
+ (EFI_PHYSICAL_ADDRESS)(UINTN)FreePoolHdr,\r
+ EFI_SIZE_TO_PAGES (FreePoolHdr->Header.Size)\r
+ );\r
+ }\r
+ return InternalFreePoolByIndex (FreePoolHdr);\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
+MmFreePool (\r
+ IN VOID *Buffer\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ Status = MmInternalFreePool (Buffer);\r
+ return Status;\r
+}\r