]> git.proxmox.com Git - mirror_edk2.git/blobdiff - StandaloneMmPkg/Core/Pool.c
StandaloneMmPkg/Core: Implementation of Standalone MM Core Module.
[mirror_edk2.git] / StandaloneMmPkg / Core / Pool.c
diff --git a/StandaloneMmPkg/Core/Pool.c b/StandaloneMmPkg/Core/Pool.c
new file mode 100644 (file)
index 0000000..ce6cfcb
--- /dev/null
@@ -0,0 +1,293 @@
+/** @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