]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Core/Pei/Memory/MemoryServices.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / MdeModulePkg / Core / Pei / Memory / MemoryServices.c
index a64bb3c6339d53db2c940bc715edbcbe689a2b1d..3b2e15699fc3bf467cf7e60705b538ec2c193e98 100644 (file)
@@ -1,90 +1,73 @@
-/*++\r
-\r
-Copyright (c) 2006, Intel Corporation                                                         \r
-All rights reserved. This program and the accompanying materials                          \r
-are licensed and made available under the terms and conditions of the BSD License         \r
-which accompanies this 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
+/** @file\r
+  EFI PEI Core memory services\r
 \r
-Module Name:\r
+Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>\r
+SPDX-License-Identifier: BSD-2-Clause-Patent\r
 \r
-  MemoryServices.c\r
+**/\r
 \r
-Abstract:\r
+#include "PeiMain.h"\r
 \r
-  EFI PEI Core memory services\r
+/**\r
 \r
---*/\r
+  Initialize the memory services.\r
 \r
-#include <PeiMain.h>\r
+  @param PrivateData     Points to PeiCore's private instance data.\r
+  @param SecCoreData     Points to a data structure containing information about the PEI core's operating\r
+                         environment, such as the size and location of temporary RAM, the stack location and\r
+                         the BFV location.\r
+  @param OldCoreData     Pointer to the PEI Core data.\r
+                         NULL if being run in non-permanent memory mode.\r
 \r
+**/\r
 VOID\r
 InitializeMemoryServices (\r
   IN PEI_CORE_INSTANCE           *PrivateData,\r
   IN CONST EFI_SEC_PEI_HAND_OFF  *SecCoreData,\r
   IN PEI_CORE_INSTANCE           *OldCoreData\r
   )\r
-/*++\r
-\r
-Routine Description:\r
-\r
-  Initialize the memory services.\r
-\r
-Arguments:\r
-\r
-  PeiServices          - The PEI core services table.\r
-  SecCoreData          - Points to a data structure containing information about the PEI core's operating\r
-                         environment, such as the size and location of temporary RAM, the stack location and\r
-                         the BFV location.\r
-\r
-  OldCoreData          - Pointer to the PEI Core data.\r
-                         NULL if being run in non-permament memory mode.\r
-\r
-Returns:\r
-\r
-  None\r
-\r
---*/\r
 {\r
-  \r
-  PrivateData->SwitchStackSignal      = FALSE;\r
+  PrivateData->SwitchStackSignal = FALSE;\r
 \r
+  //\r
+  // First entering PeiCore, following code will initialized some field\r
+  // in PeiCore's private data according to hand off data from SEC core.\r
+  //\r
   if (OldCoreData == NULL) {\r
-\r
     PrivateData->PeiMemoryInstalled = FALSE;\r
+    PrivateData->HobList.Raw        = SecCoreData->PeiTemporaryRamBase;\r
 \r
-    PrivateData->BottomOfCarHeap        = SecCoreData->PeiTemporaryRamBase; \r
-    PrivateData->TopOfCarHeap           = (VOID *)((UINTN)(PrivateData->BottomOfCarHeap) + SecCoreData->PeiTemporaryRamSize);\r
-    PrivateData->SizeOfTemporaryMemory  = SecCoreData->TemporaryRamSize;\r
-    PrivateData->StackSize              = (UINT64) SecCoreData->StackSize;\r
-    \r
-    DEBUG_CODE_BEGIN ();\r
-      PrivateData->SizeOfCacheAsRam = SecCoreData->PeiTemporaryRamSize + SecCoreData->StackSize;\r
-      PrivateData->MaxTopOfCarHeap  = (VOID *) ((UINTN) PrivateData->BottomOfCarHeap + (UINTN) PrivateData->SizeOfCacheAsRam);\r
-      PrivateData->StackBase        = (EFI_PHYSICAL_ADDRESS) (UINTN) SecCoreData->StackBase;\r
-      PrivateData->StackSize        = (UINT64) SecCoreData->StackSize;\r
-    DEBUG_CODE_END ();\r
-\r
-    PrivateData->HobList.Raw = PrivateData->BottomOfCarHeap;\r
-    \r
     PeiCoreBuildHobHandoffInfoTable (\r
       BOOT_WITH_FULL_CONFIGURATION,\r
-      (EFI_PHYSICAL_ADDRESS) (UINTN) PrivateData->BottomOfCarHeap,\r
-      (UINTN) SecCoreData->PeiTemporaryRamSize\r
+      (EFI_PHYSICAL_ADDRESS)(UINTN)SecCoreData->PeiTemporaryRamBase,\r
+      (UINTN)SecCoreData->PeiTemporaryRamSize\r
       );\r
 \r
     //\r
-    // Set PS to point to ServiceTableShadow in Cache\r
+    // Set Ps to point to ServiceTableShadow in Cache\r
     //\r
-    PrivateData->PS = &(PrivateData->ServiceTableShadow);\r
+    PrivateData->Ps = &(PrivateData->ServiceTableShadow);\r
   }\r
-  \r
+\r
   return;\r
 }\r
 \r
+/**\r
+\r
+  This function registers the found memory configuration with the PEI Foundation.\r
+\r
+  The usage model is that the PEIM that discovers the permanent memory shall invoke this service.\r
+  This routine will hold discoveried memory information into PeiCore's private data,\r
+  and set SwitchStackSignal flag. After PEIM who discovery memory is dispatched,\r
+  PeiDispatcher will migrate temporary memory to permanent memory.\r
+\r
+  @param PeiServices        An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.\r
+  @param MemoryBegin        Start of memory address.\r
+  @param MemoryLength       Length of memory.\r
+\r
+  @return EFI_SUCCESS Always success.\r
+\r
+**/\r
 EFI_STATUS\r
 EFIAPI\r
 PeiInstallPeiMemory (\r
@@ -92,122 +75,624 @@ PeiInstallPeiMemory (
   IN EFI_PHYSICAL_ADDRESS    MemoryBegin,\r
   IN UINT64                  MemoryLength\r
   )\r
-/*++\r
+{\r
+  PEI_CORE_INSTANCE  *PrivateData;\r
 \r
-Routine Description:\r
+  DEBUG ((DEBUG_INFO, "PeiInstallPeiMemory MemoryBegin 0x%LX, MemoryLength 0x%LX\n", MemoryBegin, MemoryLength));\r
+  PrivateData = PEI_CORE_INSTANCE_FROM_PS_THIS (PeiServices);\r
 \r
-  Install the permanent memory is now available.\r
-  Creates HOB (PHIT and Stack).\r
+  //\r
+  // PEI_SERVICE.InstallPeiMemory should only be called one time during whole PEI phase.\r
+  // If it is invoked more than one time, ASSERT information is given for developer debugging in debug tip and\r
+  // simply return EFI_SUCCESS in release tip to ignore it.\r
+  //\r
+  if (PrivateData->PeiMemoryInstalled) {\r
+    DEBUG ((DEBUG_ERROR, "ERROR: PeiInstallPeiMemory is called more than once!\n"));\r
+    ASSERT (FALSE);\r
+    return EFI_SUCCESS;\r
+  }\r
 \r
-Arguments:\r
+  PrivateData->PhysicalMemoryBegin   = MemoryBegin;\r
+  PrivateData->PhysicalMemoryLength  = MemoryLength;\r
+  PrivateData->FreePhysicalMemoryTop = MemoryBegin + MemoryLength;\r
+\r
+  PrivateData->SwitchStackSignal = TRUE;\r
 \r
-  PeiServices   - The PEI core services table.\r
-  MemoryBegin   - Start of memory address.\r
-  MemoryLength  - Length of memory.\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Migrate memory pages allocated in pre-memory phase.\r
+  Copy memory pages at temporary heap top to permanent heap top.\r
 \r
-Returns:\r
+  @param[in] Private                Pointer to the private data passed in from caller.\r
+  @param[in] TemporaryRamMigrated   Temporary memory has been migrated to permanent memory.\r
 \r
-  Status  - EFI_SUCCESS\r
-            \r
---*/\r
+**/\r
+VOID\r
+MigrateMemoryPages (\r
+  IN PEI_CORE_INSTANCE  *Private,\r
+  IN BOOLEAN            TemporaryRamMigrated\r
+  )\r
 {\r
-  PEI_CORE_INSTANCE                     *PrivateData;\r
+  EFI_PHYSICAL_ADDRESS  NewMemPagesBase;\r
+  EFI_PHYSICAL_ADDRESS  MemPagesBase;\r
 \r
-  DEBUG ((EFI_D_INFO, "PeiInstallPeiMemory MemoryBegin 0x%LX, MemoryLength 0x%LX\n", MemoryBegin, MemoryLength));\r
-  PrivateData = PEI_CORE_INSTANCE_FROM_PS_THIS (PeiServices);\r
+  Private->MemoryPages.Size = (UINTN)(Private->HobList.HandoffInformationTable->EfiMemoryTop -\r
+                                      Private->HobList.HandoffInformationTable->EfiFreeMemoryTop);\r
+  if (Private->MemoryPages.Size == 0) {\r
+    //\r
+    // No any memory page allocated in pre-memory phase.\r
+    //\r
+    return;\r
+  }\r
 \r
-  PrivateData->PhysicalMemoryBegin   = MemoryBegin;\r
-  PrivateData->PhysicalMemoryLength  = MemoryLength;\r
-  PrivateData->FreePhysicalMemoryTop = MemoryBegin + MemoryLength;\r
-   \r
-  PrivateData->SwitchStackSignal      = TRUE;\r
+  Private->MemoryPages.Base = Private->HobList.HandoffInformationTable->EfiFreeMemoryTop;\r
 \r
-  return EFI_SUCCESS;   \r
+  ASSERT (Private->MemoryPages.Size <= Private->FreePhysicalMemoryTop);\r
+  NewMemPagesBase  = Private->FreePhysicalMemoryTop - Private->MemoryPages.Size;\r
+  NewMemPagesBase &= ~(UINT64)EFI_PAGE_MASK;\r
+  ASSERT (NewMemPagesBase >= Private->PhysicalMemoryBegin);\r
+  //\r
+  // Copy memory pages at temporary heap top to permanent heap top.\r
+  //\r
+  if (TemporaryRamMigrated) {\r
+    //\r
+    // Memory pages at temporary heap top has been migrated to permanent heap,\r
+    // Here still needs to copy them from permanent heap to permanent heap top.\r
+    //\r
+    MemPagesBase = Private->MemoryPages.Base;\r
+    if (Private->HeapOffsetPositive) {\r
+      MemPagesBase += Private->HeapOffset;\r
+    } else {\r
+      MemPagesBase -= Private->HeapOffset;\r
+    }\r
+\r
+    CopyMem ((VOID *)(UINTN)NewMemPagesBase, (VOID *)(UINTN)MemPagesBase, Private->MemoryPages.Size);\r
+  } else {\r
+    CopyMem ((VOID *)(UINTN)NewMemPagesBase, (VOID *)(UINTN)Private->MemoryPages.Base, Private->MemoryPages.Size);\r
+  }\r
+\r
+  if (NewMemPagesBase >= Private->MemoryPages.Base) {\r
+    Private->MemoryPages.OffsetPositive = TRUE;\r
+    Private->MemoryPages.Offset         = (UINTN)(NewMemPagesBase - Private->MemoryPages.Base);\r
+  } else {\r
+    Private->MemoryPages.OffsetPositive = FALSE;\r
+    Private->MemoryPages.Offset         = (UINTN)(Private->MemoryPages.Base - NewMemPagesBase);\r
+  }\r
+\r
+  DEBUG ((DEBUG_INFO, "Pages Offset = 0x%lX\n", (UINT64)Private->MemoryPages.Offset));\r
+\r
+  Private->FreePhysicalMemoryTop = NewMemPagesBase;\r
 }\r
 \r
-EFI_STATUS\r
-EFIAPI\r
-PeiAllocatePages (\r
-  IN CONST EFI_PEI_SERVICES           **PeiServices,\r
-  IN EFI_MEMORY_TYPE            MemoryType,\r
-  IN UINTN                      Pages,\r
-  OUT EFI_PHYSICAL_ADDRESS      *Memory\r
+/**\r
+  Removes any FV HOBs whose base address is not in PEI installed memory.\r
+\r
+  @param[in] Private          Pointer to PeiCore's private data structure.\r
+\r
+**/\r
+VOID\r
+RemoveFvHobsInTemporaryMemory (\r
+  IN PEI_CORE_INSTANCE  *Private\r
+  )\r
+{\r
+  EFI_PEI_HOB_POINTERS     Hob;\r
+  EFI_HOB_FIRMWARE_VOLUME  *FirmwareVolumeHob;\r
+\r
+  DEBUG ((DEBUG_INFO, "Removing FVs in FV HOB not already migrated to permanent memory.\n"));\r
+\r
+  for (Hob.Raw = GetHobList (); !END_OF_HOB_LIST (Hob); Hob.Raw = GET_NEXT_HOB (Hob)) {\r
+    if ((GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_FV) || (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_FV2) || (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_FV3)) {\r
+      FirmwareVolumeHob = Hob.FirmwareVolume;\r
+      DEBUG ((DEBUG_INFO, "  Found FV HOB.\n"));\r
+      DEBUG ((\r
+        DEBUG_INFO,\r
+        "    BA=%016lx  L=%016lx\n",\r
+        FirmwareVolumeHob->BaseAddress,\r
+        FirmwareVolumeHob->Length\r
+        ));\r
+      if (\r
+          !(\r
+            ((EFI_PHYSICAL_ADDRESS)(UINTN)FirmwareVolumeHob->BaseAddress >= Private->PhysicalMemoryBegin) &&\r
+            (((EFI_PHYSICAL_ADDRESS)(UINTN)FirmwareVolumeHob->BaseAddress + (FirmwareVolumeHob->Length - 1)) < Private->FreePhysicalMemoryTop)\r
+            )\r
+          )\r
+      {\r
+        DEBUG ((DEBUG_INFO, "      Removing FV HOB to an FV in T-RAM (was not migrated).\n"));\r
+        Hob.Header->HobType = EFI_HOB_TYPE_UNUSED;\r
+      }\r
+    }\r
+  }\r
+}\r
+\r
+/**\r
+  Migrate the base address in firmware volume allocation HOBs\r
+  from temporary memory to PEI installed memory.\r
+\r
+  @param[in] PrivateData      Pointer to PeiCore's private data structure.\r
+  @param[in] OrgFvHandle      Address of FV Handle in temporary memory.\r
+  @param[in] FvHandle         Address of FV Handle in permanent memory.\r
+\r
+**/\r
+VOID\r
+ConvertFvHob (\r
+  IN PEI_CORE_INSTANCE  *PrivateData,\r
+  IN UINTN              OrgFvHandle,\r
+  IN UINTN              FvHandle\r
   )\r
-/*++\r
+{\r
+  EFI_PEI_HOB_POINTERS      Hob;\r
+  EFI_HOB_FIRMWARE_VOLUME   *FirmwareVolumeHob;\r
+  EFI_HOB_FIRMWARE_VOLUME2  *FirmwareVolume2Hob;\r
+  EFI_HOB_FIRMWARE_VOLUME3  *FirmwareVolume3Hob;\r
+\r
+  DEBUG ((DEBUG_INFO, "Converting FVs in FV HOB.\n"));\r
+\r
+  for (Hob.Raw = GetHobList (); !END_OF_HOB_LIST (Hob); Hob.Raw = GET_NEXT_HOB (Hob)) {\r
+    if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_FV) {\r
+      FirmwareVolumeHob = Hob.FirmwareVolume;\r
+      if (FirmwareVolumeHob->BaseAddress == OrgFvHandle) {\r
+        FirmwareVolumeHob->BaseAddress = FvHandle;\r
+      }\r
+    } else if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_FV2) {\r
+      FirmwareVolume2Hob = Hob.FirmwareVolume2;\r
+      if (FirmwareVolume2Hob->BaseAddress == OrgFvHandle) {\r
+        FirmwareVolume2Hob->BaseAddress = FvHandle;\r
+      }\r
+    } else if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_FV3) {\r
+      FirmwareVolume3Hob = Hob.FirmwareVolume3;\r
+      if (FirmwareVolume3Hob->BaseAddress == OrgFvHandle) {\r
+        FirmwareVolume3Hob->BaseAddress = FvHandle;\r
+      }\r
+    }\r
+  }\r
+}\r
+\r
+/**\r
+  Migrate MemoryBaseAddress in memory allocation HOBs\r
+  from the temporary memory to PEI installed memory.\r
 \r
-Routine Description:\r
+  @param[in] PrivateData        Pointer to PeiCore's private data structure.\r
+\r
+**/\r
+VOID\r
+ConvertMemoryAllocationHobs (\r
+  IN PEI_CORE_INSTANCE  *PrivateData\r
+  )\r
+{\r
+  EFI_PEI_HOB_POINTERS       Hob;\r
+  EFI_HOB_MEMORY_ALLOCATION  *MemoryAllocationHob;\r
+  EFI_PHYSICAL_ADDRESS       OldMemPagesBase;\r
+  UINTN                      OldMemPagesSize;\r
 \r
-  Memory allocation service on permanent memory, \r
-  not usable prior to the memory installation.\r
+  if (PrivateData->MemoryPages.Size == 0) {\r
+    //\r
+    // No any memory page allocated in pre-memory phase.\r
+    //\r
+    return;\r
+  }\r
 \r
-Arguments:\r
+  OldMemPagesBase = PrivateData->MemoryPages.Base;\r
+  OldMemPagesSize = PrivateData->MemoryPages.Size;\r
+\r
+  MemoryAllocationHob = NULL;\r
+  Hob.Raw             = GetFirstHob (EFI_HOB_TYPE_MEMORY_ALLOCATION);\r
+  while (Hob.Raw != NULL) {\r
+    MemoryAllocationHob = (EFI_HOB_MEMORY_ALLOCATION *)Hob.Raw;\r
+    if ((MemoryAllocationHob->AllocDescriptor.MemoryBaseAddress >= OldMemPagesBase) &&\r
+        (MemoryAllocationHob->AllocDescriptor.MemoryBaseAddress < (OldMemPagesBase + OldMemPagesSize))\r
+        )\r
+    {\r
+      if (PrivateData->MemoryPages.OffsetPositive) {\r
+        MemoryAllocationHob->AllocDescriptor.MemoryBaseAddress += PrivateData->MemoryPages.Offset;\r
+      } else {\r
+        MemoryAllocationHob->AllocDescriptor.MemoryBaseAddress -= PrivateData->MemoryPages.Offset;\r
+      }\r
+    }\r
 \r
-  PeiServices - The PEI core services table.\r
-  MemoryType  - Type of memory to allocate.\r
-  Pages       - Number of pages to allocate.\r
-  Memory      - Pointer of memory allocated.\r
+    Hob.Raw = GET_NEXT_HOB (Hob);\r
+    Hob.Raw = GetNextHob (EFI_HOB_TYPE_MEMORY_ALLOCATION, Hob.Raw);\r
+  }\r
+}\r
 \r
-Returns:\r
+/**\r
+  Internal function to build a HOB for the memory allocation.\r
+  It will search and reuse the unused(freed) memory allocation HOB,\r
+  or build memory allocation HOB normally if no unused(freed) memory allocation HOB found.\r
 \r
-  Status - EFI_SUCCESS              The allocation was successful\r
-           EFI_INVALID_PARAMETER    Only AllocateAnyAddress is supported.\r
-           EFI_NOT_AVAILABLE_YET    Called with permanent memory not available\r
-           EFI_OUT_OF_RESOURCES     There is not enough HOB heap to satisfy the requirement\r
-                                    to allocate the number of pages.\r
+  @param[in] BaseAddress        The 64 bit physical address of the memory.\r
+  @param[in] Length             The length of the memory allocation in bytes.\r
+  @param[in] MemoryType         The type of memory allocated by this HOB.\r
 \r
---*/\r
+**/\r
+VOID\r
+InternalBuildMemoryAllocationHob (\r
+  IN EFI_PHYSICAL_ADDRESS  BaseAddress,\r
+  IN UINT64                Length,\r
+  IN EFI_MEMORY_TYPE       MemoryType\r
+  )\r
 {\r
-  PEI_CORE_INSTANCE                       *PrivateData;\r
-  EFI_PEI_HOB_POINTERS                    Hob;\r
-  EFI_PHYSICAL_ADDRESS                    Offset;\r
-  EFI_PHYSICAL_ADDRESS                    *FreeMemoryTop;\r
-  EFI_PHYSICAL_ADDRESS                    *FreeMemoryBottom;\r
+  EFI_PEI_HOB_POINTERS       Hob;\r
+  EFI_HOB_MEMORY_ALLOCATION  *MemoryAllocationHob;\r
 \r
-  PrivateData = PEI_CORE_INSTANCE_FROM_PS_THIS (PeiServices);\r
-  Hob.Raw     = PrivateData->HobList.Raw;\r
-  \r
   //\r
-  // Check if Hob already available\r
+  // Search unused(freed) memory allocation HOB.\r
   //\r
-  if (!PrivateData->PeiMemoryInstalled) {\r
+  MemoryAllocationHob = NULL;\r
+  Hob.Raw             = GetFirstHob (EFI_HOB_TYPE_UNUSED);\r
+  while (Hob.Raw != NULL) {\r
+    if (Hob.Header->HobLength == sizeof (EFI_HOB_MEMORY_ALLOCATION)) {\r
+      MemoryAllocationHob = (EFI_HOB_MEMORY_ALLOCATION *)Hob.Raw;\r
+      break;\r
+    }\r
+\r
+    Hob.Raw = GET_NEXT_HOB (Hob);\r
+    Hob.Raw = GetNextHob (EFI_HOB_TYPE_UNUSED, Hob.Raw);\r
+  }\r
+\r
+  if (MemoryAllocationHob != NULL) {\r
     //\r
-    // When PeiInstallMemory is called but CAR has *not* been moved to temporary memory,\r
-    // the AllocatePage will dependent the field of PEI_CORE_INSTANCE structure.\r
+    // Reuse the unused(freed) memory allocation HOB.\r
     //\r
-    if (!PrivateData->SwitchStackSignal) {\r
-      return EFI_NOT_AVAILABLE_YET;\r
-    } else {\r
-      FreeMemoryTop     = &(PrivateData->FreePhysicalMemoryTop);\r
-      FreeMemoryBottom  = &(PrivateData->PhysicalMemoryBegin);\r
-    }\r
+    MemoryAllocationHob->Header.HobType = EFI_HOB_TYPE_MEMORY_ALLOCATION;\r
+    ZeroMem (&(MemoryAllocationHob->AllocDescriptor.Name), sizeof (EFI_GUID));\r
+    MemoryAllocationHob->AllocDescriptor.MemoryBaseAddress = BaseAddress;\r
+    MemoryAllocationHob->AllocDescriptor.MemoryLength      = Length;\r
+    MemoryAllocationHob->AllocDescriptor.MemoryType        = MemoryType;\r
+    //\r
+    // Zero the reserved space to match HOB spec\r
+    //\r
+    ZeroMem (MemoryAllocationHob->AllocDescriptor.Reserved, sizeof (MemoryAllocationHob->AllocDescriptor.Reserved));\r
   } else {\r
-    FreeMemoryTop     = &(Hob.HandoffInformationTable->EfiFreeMemoryTop);\r
-    FreeMemoryBottom  = &(Hob.HandoffInformationTable->EfiFreeMemoryBottom);\r
+    //\r
+    // No unused(freed) memory allocation HOB found.\r
+    // Build memory allocation HOB normally.\r
+    //\r
+    BuildMemoryAllocationHob (\r
+      BaseAddress,\r
+      Length,\r
+      MemoryType\r
+      );\r
   }\r
+}\r
 \r
-  \r
+/**\r
+  Update or split memory allocation HOB for memory pages allocate and free.\r
+\r
+  @param[in, out] MemoryAllocationHob   Pointer to the memory allocation HOB\r
+                                        that needs to be updated or split.\r
+                                        On output, it will be filled with\r
+                                        the input Memory, Bytes and MemoryType.\r
+  @param[in]      Memory                Memory to allocate or free.\r
+  @param[in]      Bytes                 Bytes to allocate or free.\r
+  @param[in]      MemoryType            EfiConventionalMemory for pages free,\r
+                                        others for pages allocate.\r
+\r
+**/\r
+VOID\r
+UpdateOrSplitMemoryAllocationHob (\r
+  IN OUT EFI_HOB_MEMORY_ALLOCATION  *MemoryAllocationHob,\r
+  IN EFI_PHYSICAL_ADDRESS           Memory,\r
+  IN UINT64                         Bytes,\r
+  IN EFI_MEMORY_TYPE                MemoryType\r
+  )\r
+{\r
+  if ((Memory + Bytes) <\r
+      (MemoryAllocationHob->AllocDescriptor.MemoryBaseAddress + MemoryAllocationHob->AllocDescriptor.MemoryLength))\r
+  {\r
+    //\r
+    // Last pages need to be split out.\r
+    //\r
+    InternalBuildMemoryAllocationHob (\r
+      Memory + Bytes,\r
+      (MemoryAllocationHob->AllocDescriptor.MemoryBaseAddress + MemoryAllocationHob->AllocDescriptor.MemoryLength) - (Memory + Bytes),\r
+      MemoryAllocationHob->AllocDescriptor.MemoryType\r
+      );\r
+  }\r
+\r
+  if (Memory > MemoryAllocationHob->AllocDescriptor.MemoryBaseAddress) {\r
+    //\r
+    // First pages need to be split out.\r
+    //\r
+    InternalBuildMemoryAllocationHob (\r
+      MemoryAllocationHob->AllocDescriptor.MemoryBaseAddress,\r
+      Memory - MemoryAllocationHob->AllocDescriptor.MemoryBaseAddress,\r
+      MemoryAllocationHob->AllocDescriptor.MemoryType\r
+      );\r
+  }\r
 \r
   //\r
-  // Check to see if on 4k boundary\r
+  // Update the memory allocation HOB.\r
   //\r
-  Offset = *(FreeMemoryTop) & 0xFFF;\r
-  \r
+  MemoryAllocationHob->AllocDescriptor.MemoryBaseAddress = Memory;\r
+  MemoryAllocationHob->AllocDescriptor.MemoryLength      = Bytes;\r
+  MemoryAllocationHob->AllocDescriptor.MemoryType        = MemoryType;\r
+}\r
+\r
+/**\r
+  Merge adjacent free memory ranges in memory allocation HOBs.\r
+\r
+  @retval TRUE          There are free memory ranges merged.\r
+  @retval FALSE         No free memory ranges merged.\r
+\r
+**/\r
+BOOLEAN\r
+MergeFreeMemoryInMemoryAllocationHob (\r
+  VOID\r
+  )\r
+{\r
+  EFI_PEI_HOB_POINTERS       Hob;\r
+  EFI_PEI_HOB_POINTERS       Hob2;\r
+  EFI_HOB_MEMORY_ALLOCATION  *MemoryHob;\r
+  EFI_HOB_MEMORY_ALLOCATION  *MemoryHob2;\r
+  UINT64                     Start;\r
+  UINT64                     End;\r
+  BOOLEAN                    Merged;\r
+\r
+  Merged = FALSE;\r
+\r
+  Hob.Raw = GetFirstHob (EFI_HOB_TYPE_MEMORY_ALLOCATION);\r
+  while (Hob.Raw != NULL) {\r
+    if (Hob.MemoryAllocation->AllocDescriptor.MemoryType == EfiConventionalMemory) {\r
+      MemoryHob = (EFI_HOB_MEMORY_ALLOCATION *)Hob.Raw;\r
+      Start     = MemoryHob->AllocDescriptor.MemoryBaseAddress;\r
+      End       = MemoryHob->AllocDescriptor.MemoryBaseAddress + MemoryHob->AllocDescriptor.MemoryLength;\r
+\r
+      Hob2.Raw = GET_NEXT_HOB (Hob);\r
+      Hob2.Raw = GetNextHob (EFI_HOB_TYPE_MEMORY_ALLOCATION, Hob.Raw);\r
+      while (Hob2.Raw != NULL) {\r
+        if (Hob2.MemoryAllocation->AllocDescriptor.MemoryType == EfiConventionalMemory) {\r
+          MemoryHob2 = (EFI_HOB_MEMORY_ALLOCATION *)Hob2.Raw;\r
+          if (Start == (MemoryHob2->AllocDescriptor.MemoryBaseAddress + MemoryHob2->AllocDescriptor.MemoryLength)) {\r
+            //\r
+            // Merge adjacent two free memory ranges.\r
+            //\r
+            MemoryHob2->AllocDescriptor.MemoryLength += MemoryHob->AllocDescriptor.MemoryLength;\r
+            Merged                                    = TRUE;\r
+            //\r
+            // Mark MemoryHob to be unused(freed).\r
+            //\r
+            MemoryHob->Header.HobType = EFI_HOB_TYPE_UNUSED;\r
+            break;\r
+          } else if (End == MemoryHob2->AllocDescriptor.MemoryBaseAddress) {\r
+            //\r
+            // Merge adjacent two free memory ranges.\r
+            //\r
+            MemoryHob2->AllocDescriptor.MemoryBaseAddress = MemoryHob->AllocDescriptor.MemoryBaseAddress;\r
+            MemoryHob2->AllocDescriptor.MemoryLength     += MemoryHob->AllocDescriptor.MemoryLength;\r
+            Merged                                        = TRUE;\r
+            //\r
+            // Mark MemoryHob to be unused(freed).\r
+            //\r
+            MemoryHob->Header.HobType = EFI_HOB_TYPE_UNUSED;\r
+            break;\r
+          }\r
+        }\r
+\r
+        Hob2.Raw = GET_NEXT_HOB (Hob2);\r
+        Hob2.Raw = GetNextHob (EFI_HOB_TYPE_MEMORY_ALLOCATION, Hob2.Raw);\r
+      }\r
+    }\r
+\r
+    Hob.Raw = GET_NEXT_HOB (Hob);\r
+    Hob.Raw = GetNextHob (EFI_HOB_TYPE_MEMORY_ALLOCATION, Hob.Raw);\r
+  }\r
+\r
+  return Merged;\r
+}\r
+\r
+/**\r
+  Find free memory by searching memory allocation HOBs.\r
+\r
+  @param[in]  MemoryType        The type of memory to allocate.\r
+  @param[in]  Pages             The number of contiguous 4 KB pages to allocate.\r
+  @param[in]  Granularity       Page allocation granularity.\r
+  @param[out] Memory            Pointer to a physical address. On output, the address is set to the base\r
+                                of the page range that was allocated.\r
+\r
+  @retval EFI_SUCCESS           The memory range was successfully allocated.\r
+  @retval EFI_NOT_FOUND         No memory allocation HOB with big enough free memory found.\r
+\r
+**/\r
+EFI_STATUS\r
+FindFreeMemoryFromMemoryAllocationHob (\r
+  IN  EFI_MEMORY_TYPE       MemoryType,\r
+  IN  UINTN                 Pages,\r
+  IN  UINTN                 Granularity,\r
+  OUT EFI_PHYSICAL_ADDRESS  *Memory\r
+  )\r
+{\r
+  EFI_PEI_HOB_POINTERS       Hob;\r
+  EFI_HOB_MEMORY_ALLOCATION  *MemoryAllocationHob;\r
+  UINT64                     Bytes;\r
+  EFI_PHYSICAL_ADDRESS       BaseAddress;\r
+\r
+  Bytes = LShiftU64 (Pages, EFI_PAGE_SHIFT);\r
+\r
+  BaseAddress         = 0;\r
+  MemoryAllocationHob = NULL;\r
+  Hob.Raw             = GetFirstHob (EFI_HOB_TYPE_MEMORY_ALLOCATION);\r
+  while (Hob.Raw != NULL) {\r
+    if ((Hob.MemoryAllocation->AllocDescriptor.MemoryType == EfiConventionalMemory) &&\r
+        (Hob.MemoryAllocation->AllocDescriptor.MemoryLength >= Bytes))\r
+    {\r
+      //\r
+      // Found one memory allocation HOB with big enough free memory.\r
+      //\r
+      MemoryAllocationHob = (EFI_HOB_MEMORY_ALLOCATION *)Hob.Raw;\r
+      BaseAddress         = MemoryAllocationHob->AllocDescriptor.MemoryBaseAddress +\r
+                            MemoryAllocationHob->AllocDescriptor.MemoryLength - Bytes;\r
+      //\r
+      // Make sure the granularity could be satisfied.\r
+      //\r
+      BaseAddress &= ~((EFI_PHYSICAL_ADDRESS)Granularity - 1);\r
+      if (BaseAddress >= MemoryAllocationHob->AllocDescriptor.MemoryBaseAddress) {\r
+        break;\r
+      }\r
+\r
+      BaseAddress         = 0;\r
+      MemoryAllocationHob = NULL;\r
+    }\r
+\r
+    //\r
+    // Continue to find.\r
+    //\r
+    Hob.Raw = GET_NEXT_HOB (Hob);\r
+    Hob.Raw = GetNextHob (EFI_HOB_TYPE_MEMORY_ALLOCATION, Hob.Raw);\r
+  }\r
+\r
+  if (MemoryAllocationHob != NULL) {\r
+    UpdateOrSplitMemoryAllocationHob (MemoryAllocationHob, BaseAddress, Bytes, MemoryType);\r
+    *Memory = BaseAddress;\r
+    return EFI_SUCCESS;\r
+  } else {\r
+    if (MergeFreeMemoryInMemoryAllocationHob ()) {\r
+      //\r
+      // Retry if there are free memory ranges merged.\r
+      //\r
+      return FindFreeMemoryFromMemoryAllocationHob (MemoryType, Pages, Granularity, Memory);\r
+    }\r
+\r
+    return EFI_NOT_FOUND;\r
+  }\r
+}\r
+\r
+/**\r
+  The purpose of the service is to publish an interface that allows\r
+  PEIMs to allocate memory ranges that are managed by the PEI Foundation.\r
+\r
+  Prior to InstallPeiMemory() being called, PEI will allocate pages from the heap.\r
+  After InstallPeiMemory() is called, PEI will allocate pages within the region\r
+  of memory provided by InstallPeiMemory() service in a best-effort fashion.\r
+  Location-specific allocations are not managed by the PEI foundation code.\r
+\r
+  @param  PeiServices      An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.\r
+  @param  MemoryType       The type of memory to allocate.\r
+  @param  Pages            The number of contiguous 4 KB pages to allocate.\r
+  @param  Memory           Pointer to a physical address. On output, the address is set to the base\r
+                           of the page range that was allocated.\r
+\r
+  @retval EFI_SUCCESS           The memory range was successfully allocated.\r
+  @retval EFI_OUT_OF_RESOURCES  The pages could not be allocated.\r
+  @retval EFI_INVALID_PARAMETER Type is not equal to EfiLoaderCode, EfiLoaderData, EfiRuntimeServicesCode,\r
+                                EfiRuntimeServicesData, EfiBootServicesCode, EfiBootServicesData,\r
+                                EfiACPIReclaimMemory, EfiReservedMemoryType, or EfiACPIMemoryNVS.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+PeiAllocatePages (\r
+  IN CONST EFI_PEI_SERVICES      **PeiServices,\r
+  IN       EFI_MEMORY_TYPE       MemoryType,\r
+  IN       UINTN                 Pages,\r
+  OUT      EFI_PHYSICAL_ADDRESS  *Memory\r
+  )\r
+{\r
+  EFI_STATUS            Status;\r
+  PEI_CORE_INSTANCE     *PrivateData;\r
+  EFI_PEI_HOB_POINTERS  Hob;\r
+  EFI_PHYSICAL_ADDRESS  *FreeMemoryTop;\r
+  EFI_PHYSICAL_ADDRESS  *FreeMemoryBottom;\r
+  UINTN                 RemainingPages;\r
+  UINTN                 Granularity;\r
+  UINTN                 Padding;\r
+\r
+  if ((MemoryType != EfiLoaderCode) &&\r
+      (MemoryType != EfiLoaderData) &&\r
+      (MemoryType != EfiRuntimeServicesCode) &&\r
+      (MemoryType != EfiRuntimeServicesData) &&\r
+      (MemoryType != EfiBootServicesCode) &&\r
+      (MemoryType != EfiBootServicesData) &&\r
+      (MemoryType != EfiACPIReclaimMemory) &&\r
+      (MemoryType != EfiReservedMemoryType) &&\r
+      (MemoryType != EfiACPIMemoryNVS))\r
+  {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Granularity = DEFAULT_PAGE_ALLOCATION_GRANULARITY;\r
+\r
+  PrivateData = PEI_CORE_INSTANCE_FROM_PS_THIS (PeiServices);\r
+  Hob.Raw     = PrivateData->HobList.Raw;\r
+\r
+  if (Hob.Raw == NULL) {\r
+    //\r
+    // HOB is not initialized yet.\r
+    //\r
+    return EFI_NOT_AVAILABLE_YET;\r
+  }\r
+\r
+  if ((RUNTIME_PAGE_ALLOCATION_GRANULARITY > DEFAULT_PAGE_ALLOCATION_GRANULARITY) &&\r
+      ((MemoryType == EfiACPIReclaimMemory) ||\r
+       (MemoryType == EfiACPIMemoryNVS) ||\r
+       (MemoryType == EfiRuntimeServicesCode) ||\r
+       (MemoryType == EfiRuntimeServicesData)))\r
+  {\r
+    Granularity = RUNTIME_PAGE_ALLOCATION_GRANULARITY;\r
+\r
+    DEBUG ((\r
+      DEBUG_INFO,\r
+      "AllocatePages: aligning allocation to %d KB\n",\r
+      Granularity / SIZE_1KB\r
+      ));\r
+  }\r
+\r
+  if (!PrivateData->PeiMemoryInstalled && PrivateData->SwitchStackSignal) {\r
+    //\r
+    // When PeiInstallMemory is called but temporary memory has *not* been moved to permanent memory,\r
+    // the AllocatePage will depend on the field of PEI_CORE_INSTANCE structure.\r
+    //\r
+    FreeMemoryTop    = &(PrivateData->FreePhysicalMemoryTop);\r
+    FreeMemoryBottom = &(PrivateData->PhysicalMemoryBegin);\r
+  } else {\r
+    FreeMemoryTop    = &(Hob.HandoffInformationTable->EfiFreeMemoryTop);\r
+    FreeMemoryBottom = &(Hob.HandoffInformationTable->EfiFreeMemoryBottom);\r
+  }\r
+\r
   //\r
+  // Check to see if on correct boundary for the memory type.\r
   // If not aligned, make the allocation aligned.\r
   //\r
-  if (Offset != 0) {\r
-    *(FreeMemoryTop) -= Offset;\r
+  Padding = *(FreeMemoryTop) & (Granularity - 1);\r
+  if ((UINTN)(*FreeMemoryTop - *FreeMemoryBottom) < Padding) {\r
+    DEBUG ((DEBUG_ERROR, "AllocatePages failed: Out of space after padding.\n"));\r
+    return EFI_OUT_OF_RESOURCES;\r
   }\r
-  \r
+\r
+  *(FreeMemoryTop) -= Padding;\r
+  if (Padding >= EFI_PAGE_SIZE) {\r
+    //\r
+    // Create a memory allocation HOB to cover\r
+    // the pages that we will lose to rounding\r
+    //\r
+    InternalBuildMemoryAllocationHob (\r
+      *(FreeMemoryTop),\r
+      Padding & ~(UINTN)EFI_PAGE_MASK,\r
+      EfiConventionalMemory\r
+      );\r
+  }\r
+\r
+  //\r
+  // Verify that there is sufficient memory to satisfy the allocation.\r
+  //\r
+  RemainingPages = (UINTN)(*FreeMemoryTop - *FreeMemoryBottom) >> EFI_PAGE_SHIFT;\r
   //\r
-  // Verify that there is sufficient memory to satisfy the allocation\r
+  // The number of remaining pages needs to be greater than or equal to that of the request pages.\r
   //\r
-  if (*(FreeMemoryTop) - ((Pages * EFI_PAGE_SIZE) + sizeof (EFI_HOB_MEMORY_ALLOCATION)) < \r
-      *(FreeMemoryBottom)) {\r
-    DEBUG ((EFI_D_ERROR, "AllocatePages failed: No 0x%x Pages is available.\n", Pages));\r
-    DEBUG ((EFI_D_ERROR, "There is only left 0x%x pages memory resource to be allocated.\n", \\r
-    EFI_SIZE_TO_PAGES ((UINTN) (*(FreeMemoryTop) - *(FreeMemoryBottom)))));\r
-    return  EFI_OUT_OF_RESOURCES;\r
+  Pages = ALIGN_VALUE (Pages, EFI_SIZE_TO_PAGES (Granularity));\r
+  if (RemainingPages < Pages) {\r
+    //\r
+    // Try to find free memory by searching memory allocation HOBs.\r
+    //\r
+    Status = FindFreeMemoryFromMemoryAllocationHob (MemoryType, Pages, Granularity, Memory);\r
+    if (!EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+\r
+    DEBUG ((DEBUG_ERROR, "AllocatePages failed: No 0x%lx Pages is available.\n", (UINT64)Pages));\r
+    DEBUG ((DEBUG_ERROR, "There is only left 0x%lx pages memory resource to be allocated.\n", (UINT64)RemainingPages));\r
+    return EFI_OUT_OF_RESOURCES;\r
   } else {\r
     //\r
     // Update the PHIT to reflect the memory usage\r
@@ -222,7 +707,7 @@ Returns:
     //\r
     // Create a memory allocation HOB.\r
     //\r
-    BuildMemoryAllocationHob (\r
+    InternalBuildMemoryAllocationHob (\r
       *(FreeMemoryTop),\r
       Pages * EFI_PAGE_SIZE,\r
       MemoryType\r
@@ -232,51 +717,198 @@ Returns:
   }\r
 }\r
 \r
+/**\r
+  Mark the memory allocation HOB to be unused(freed) and update *FreeMemoryTop\r
+  if MemoryBaseAddress == *FreeMemoryTop.\r
+\r
+  @param[in]      PrivateData                   Pointer to PeiCore's private data structure.\r
+  @param[in, out] MemoryAllocationHobToFree     Pointer to memory allocation HOB to be freed.\r
+\r
+**/\r
+VOID\r
+FreeMemoryAllocationHob (\r
+  IN PEI_CORE_INSTANCE              *PrivateData,\r
+  IN OUT EFI_HOB_MEMORY_ALLOCATION  *MemoryAllocationHobToFree\r
+  )\r
+{\r
+  EFI_PEI_HOB_POINTERS       Hob;\r
+  EFI_PHYSICAL_ADDRESS       *FreeMemoryTop;\r
+  EFI_HOB_MEMORY_ALLOCATION  *MemoryAllocationHob;\r
+\r
+  Hob.Raw = PrivateData->HobList.Raw;\r
+\r
+  if (!PrivateData->PeiMemoryInstalled && PrivateData->SwitchStackSignal) {\r
+    //\r
+    // When PeiInstallMemory is called but temporary memory has *not* been moved to permanent memory,\r
+    // use the FreePhysicalMemoryTop field of PEI_CORE_INSTANCE structure.\r
+    //\r
+    FreeMemoryTop = &(PrivateData->FreePhysicalMemoryTop);\r
+  } else {\r
+    FreeMemoryTop = &(Hob.HandoffInformationTable->EfiFreeMemoryTop);\r
+  }\r
+\r
+  if (MemoryAllocationHobToFree->AllocDescriptor.MemoryBaseAddress == *FreeMemoryTop) {\r
+    //\r
+    // Update *FreeMemoryTop.\r
+    //\r
+    *FreeMemoryTop += MemoryAllocationHobToFree->AllocDescriptor.MemoryLength;\r
+    //\r
+    // Mark the memory allocation HOB to be unused(freed).\r
+    //\r
+    MemoryAllocationHobToFree->Header.HobType = EFI_HOB_TYPE_UNUSED;\r
+\r
+    MemoryAllocationHob = NULL;\r
+    Hob.Raw             = GetFirstHob (EFI_HOB_TYPE_MEMORY_ALLOCATION);\r
+    while (Hob.Raw != NULL) {\r
+      if ((Hob.MemoryAllocation->AllocDescriptor.MemoryType == EfiConventionalMemory) &&\r
+          (Hob.MemoryAllocation->AllocDescriptor.MemoryBaseAddress == *FreeMemoryTop))\r
+      {\r
+        //\r
+        // Found memory allocation HOB that has EfiConventionalMemory MemoryType and\r
+        // MemoryBaseAddress == new *FreeMemoryTop.\r
+        //\r
+        MemoryAllocationHob = (EFI_HOB_MEMORY_ALLOCATION *)Hob.Raw;\r
+        break;\r
+      }\r
+\r
+      Hob.Raw = GET_NEXT_HOB (Hob);\r
+      Hob.Raw = GetNextHob (EFI_HOB_TYPE_MEMORY_ALLOCATION, Hob.Raw);\r
+    }\r
+\r
+    //\r
+    // Free memory allocation HOB iteratively.\r
+    //\r
+    if (MemoryAllocationHob != NULL) {\r
+      FreeMemoryAllocationHob (PrivateData, MemoryAllocationHob);\r
+    }\r
+  }\r
+}\r
+\r
+/**\r
+  Frees memory pages.\r
+\r
+  @param[in] PeiServices        An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.\r
+  @param[in] Memory             The base physical address of the pages to be freed.\r
+  @param[in] Pages              The number of contiguous 4 KB pages to free.\r
 \r
+  @retval EFI_SUCCESS           The requested pages were freed.\r
+  @retval EFI_INVALID_PARAMETER Memory is not a page-aligned address or Pages is invalid.\r
+  @retval EFI_NOT_FOUND         The requested memory pages were not allocated with\r
+                                AllocatePages().\r
+\r
+**/\r
 EFI_STATUS\r
 EFIAPI\r
-PeiAllocatePool (\r
-  IN CONST EFI_PEI_SERVICES           **PeiServices,\r
-  IN UINTN                      Size,\r
-  OUT VOID                      **Buffer\r
+PeiFreePages (\r
+  IN CONST EFI_PEI_SERVICES  **PeiServices,\r
+  IN EFI_PHYSICAL_ADDRESS    Memory,\r
+  IN UINTN                   Pages\r
   )\r
-/*++\r
+{\r
+  PEI_CORE_INSTANCE          *PrivateData;\r
+  UINT64                     Bytes;\r
+  UINT64                     Start;\r
+  UINT64                     End;\r
+  EFI_PEI_HOB_POINTERS       Hob;\r
+  EFI_HOB_MEMORY_ALLOCATION  *MemoryAllocationHob;\r
+\r
+  Bytes = LShiftU64 (Pages, EFI_PAGE_SHIFT);\r
+  Start = Memory;\r
+  End   = Start + Bytes - 1;\r
+\r
+  if ((Pages == 0) || ((Start & EFI_PAGE_MASK) != 0) || (Start >= End)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  PrivateData = PEI_CORE_INSTANCE_FROM_PS_THIS (PeiServices);\r
+  Hob.Raw     = PrivateData->HobList.Raw;\r
+\r
+  if (Hob.Raw == NULL) {\r
+    //\r
+    // HOB is not initialized yet.\r
+    //\r
+    return EFI_NOT_AVAILABLE_YET;\r
+  }\r
 \r
-Routine Description:\r
+  MemoryAllocationHob = NULL;\r
+  Hob.Raw             = GetFirstHob (EFI_HOB_TYPE_MEMORY_ALLOCATION);\r
+  while (Hob.Raw != NULL) {\r
+    if ((Hob.MemoryAllocation->AllocDescriptor.MemoryType != EfiConventionalMemory) &&\r
+        (Memory >= Hob.MemoryAllocation->AllocDescriptor.MemoryBaseAddress) &&\r
+        ((Memory + Bytes) <= (Hob.MemoryAllocation->AllocDescriptor.MemoryBaseAddress + Hob.MemoryAllocation->AllocDescriptor.MemoryLength)))\r
+    {\r
+      //\r
+      // Found the memory allocation HOB that includes the memory pages to be freed.\r
+      //\r
+      MemoryAllocationHob = (EFI_HOB_MEMORY_ALLOCATION *)Hob.Raw;\r
+      break;\r
+    }\r
 \r
-  Memory allocation service on the CAR.  \r
+    Hob.Raw = GET_NEXT_HOB (Hob);\r
+    Hob.Raw = GetNextHob (EFI_HOB_TYPE_MEMORY_ALLOCATION, Hob.Raw);\r
+  }\r
 \r
-Arguments:\r
+  if (MemoryAllocationHob != NULL) {\r
+    UpdateOrSplitMemoryAllocationHob (MemoryAllocationHob, Memory, Bytes, EfiConventionalMemory);\r
+    FreeMemoryAllocationHob (PrivateData, MemoryAllocationHob);\r
+    return EFI_SUCCESS;\r
+  } else {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+}\r
 \r
-  PeiServices - The PEI core services table.\r
+/**\r
 \r
-  Size        - Amount of memory required\r
+  Pool allocation service. Before permanent memory is discovered, the pool will\r
+  be allocated in the heap in temporary memory. Generally, the size of the heap in temporary\r
+  memory does not exceed 64K, so the biggest pool size could be allocated is\r
+  64K.\r
 \r
-  Buffer      - Address of pointer to the buffer\r
+  @param PeiServices               An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.\r
+  @param Size                      Amount of memory required\r
+  @param Buffer                    Address of pointer to the buffer\r
 \r
-Returns:\r
+  @retval EFI_SUCCESS              The allocation was successful\r
+  @retval EFI_OUT_OF_RESOURCES     There is not enough heap to satisfy the requirement\r
+                                   to allocate the requested size.\r
 \r
-  Status - EFI_SUCCESS              The allocation was successful\r
-           EFI_OUT_OF_RESOURCES     There is not enough heap to satisfy the requirement\r
-                                    to allocate the requested size.\r
-                                    \r
---*/\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+PeiAllocatePool (\r
+  IN CONST EFI_PEI_SERVICES  **PeiServices,\r
+  IN       UINTN             Size,\r
+  OUT      VOID              **Buffer\r
+  )\r
 {\r
-  EFI_STATUS               Status;\r
-  EFI_HOB_MEMORY_POOL      *Hob;\r
-\r
- //\r
- // If some "post-memory" PEIM wishes to allocate larger pool,\r
- // it should use AllocatePages service instead.\r
- //\r
- ASSERT (Size < 0x10000 - sizeof (EFI_HOB_MEMORY_POOL));\r
- Status = PeiServicesCreateHob (\r
+  EFI_STATUS           Status;\r
+  EFI_HOB_MEMORY_POOL  *Hob;\r
+\r
+  //\r
+  // If some "post-memory" PEIM wishes to allocate larger pool,\r
+  // it should use AllocatePages service instead.\r
+  //\r
+\r
+  //\r
+  // Generally, the size of heap in temporary memory does not exceed 64K,\r
+  // HobLength is multiples of 8 bytes, so the maximum size of pool is 0xFFF8 - sizeof (EFI_HOB_MEMORY_POOL)\r
+  //\r
+  if (Size > (0xFFF8 - sizeof (EFI_HOB_MEMORY_POOL))) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  Status = PeiServicesCreateHob (\r
              EFI_HOB_TYPE_MEMORY_POOL,\r
              (UINT16)(sizeof (EFI_HOB_MEMORY_POOL) + Size),\r
              (VOID **)&Hob\r
              );\r
-  *Buffer = Hob+1;  \r
+  ASSERT_EFI_ERROR (Status);\r
 \r
+  if (EFI_ERROR (Status)) {\r
+    *Buffer = NULL;\r
+  } else {\r
+    *Buffer = Hob + 1;\r
+  }\r
 \r
   return Status;\r
 }\r