-/*++\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 EFI_PEI_SERVICES **PeiServices,\r
- IN EFI_PEI_STARTUP_DESCRIPTOR *PeiStartupDescriptor,\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
+ PrivateData->SwitchStackSignal = FALSE;\r
\r
-Routine Description:\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
+ PrivateData->PeiMemoryInstalled = FALSE;\r
+ PrivateData->HobList.Raw = SecCoreData->PeiTemporaryRamBase;\r
\r
- Initialize the memory services.\r
+ PeiCoreBuildHobHandoffInfoTable (\r
+ BOOT_WITH_FULL_CONFIGURATION,\r
+ (EFI_PHYSICAL_ADDRESS)(UINTN)SecCoreData->PeiTemporaryRamBase,\r
+ (UINTN)SecCoreData->PeiTemporaryRamSize\r
+ );\r
\r
-Arguments:\r
+ //\r
+ // Set Ps to point to ServiceTableShadow in Cache\r
+ //\r
+ PrivateData->Ps = &(PrivateData->ServiceTableShadow);\r
+ }\r
+\r
+ return;\r
+}\r
+\r
+/**\r
\r
- PeiServices - The PEI core services table.\r
- PeiStartupDescriptor - Information and services provided by SEC phase.\r
- OldCoreData - Pointer to the PEI Core data.\r
- NULL if being run in non-permament memory mode.\r
+ This function registers the found memory configuration with the PEI Foundation.\r
\r
-Returns:\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
- None\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
---*/\r
+ @return EFI_SUCCESS Always success.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+PeiInstallPeiMemory (\r
+ IN CONST EFI_PEI_SERVICES **PeiServices,\r
+ IN EFI_PHYSICAL_ADDRESS MemoryBegin,\r
+ IN UINT64 MemoryLength\r
+ )\r
{\r
- PEI_CORE_INSTANCE *PrivateData;\r
- UINT64 SizeOfCarHeap;\r
+ PEI_CORE_INSTANCE *PrivateData;\r
\r
+ DEBUG ((DEBUG_INFO, "PeiInstallPeiMemory MemoryBegin 0x%LX, MemoryLength 0x%LX\n", MemoryBegin, MemoryLength));\r
PrivateData = PEI_CORE_INSTANCE_FROM_PS_THIS (PeiServices);\r
- PrivateData->SwitchStackSignal = FALSE;\r
\r
- if (OldCoreData == NULL) {\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
- PrivateData->PeiMemoryInstalled = FALSE;\r
+ PrivateData->PhysicalMemoryBegin = MemoryBegin;\r
+ PrivateData->PhysicalMemoryLength = MemoryLength;\r
+ PrivateData->FreePhysicalMemoryTop = MemoryBegin + MemoryLength;\r
\r
- PrivateData->BottomOfCarHeap = (VOID *) (((UINTN)(VOID *)(&PrivateData))\r
- & (~((PeiStartupDescriptor->SizeOfCacheAsRam) - 1))); \r
- PrivateData->TopOfCarHeap = (VOID *)((UINTN)(PrivateData->BottomOfCarHeap) + PeiStartupDescriptor->SizeOfCacheAsRam);\r
- //\r
- // SizeOfCarHeap is 1/2 (arbitrary) of CacheAsRam Size.\r
- //\r
- SizeOfCarHeap = (UINT64) PeiStartupDescriptor->SizeOfCacheAsRam;\r
- SizeOfCarHeap = RShiftU64 (SizeOfCarHeap, 1);\r
- \r
- DEBUG_CODE_BEGIN ();\r
- PrivateData->SizeOfCacheAsRam = PeiStartupDescriptor->SizeOfCacheAsRam;\r
- PrivateData->MaxTopOfCarHeap = (VOID *) ((UINTN) PrivateData->BottomOfCarHeap + (UINTN) SizeOfCarHeap);\r
- DEBUG_CODE_END ();\r
+ PrivateData->SwitchStackSignal = TRUE;\r
\r
- PrivateData->HobList.Raw = PrivateData->BottomOfCarHeap;\r
- \r
- PeiCoreBuildHobHandoffInfoTable (\r
- BOOT_WITH_FULL_CONFIGURATION,\r
- (EFI_PHYSICAL_ADDRESS) (UINTN) PrivateData->BottomOfCarHeap,\r
- (UINTN) SizeOfCarHeap\r
- );\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
+ @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
+**/\r
+VOID\r
+MigrateMemoryPages (\r
+ IN PEI_CORE_INSTANCE *Private,\r
+ IN BOOLEAN TemporaryRamMigrated\r
+ )\r
+{\r
+ EFI_PHYSICAL_ADDRESS NewMemPagesBase;\r
+ EFI_PHYSICAL_ADDRESS MemPagesBase;\r
+\r
+ Private->MemoryPages.Size = (UINTN)(Private->HobList.HandoffInformationTable->EfiMemoryTop -\r
+ Private->HobList.HandoffInformationTable->EfiFreeMemoryTop);\r
+ if (Private->MemoryPages.Size == 0) {\r
//\r
- // Copy PeiServices from ROM to Cache in PrivateData\r
+ // No any memory page allocated in pre-memory phase.\r
//\r
- CopyMem (&(PrivateData->ServiceTableShadow), *PeiServices, sizeof (EFI_PEI_SERVICES));\r
+ return;\r
+ }\r
\r
+ Private->MemoryPages.Base = Private->HobList.HandoffInformationTable->EfiFreeMemoryTop;\r
+\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
- // Set PS to point to ServiceTableShadow in Cache\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
- PrivateData->PS = &(PrivateData->ServiceTableShadow);\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
- // \r
- // Set PS to point to ServiceTableShadow in Cache one time after the \r
- // stack switched to main memory \r
- // \r
- PrivateData->PS = &(PrivateData->ServiceTableShadow); \r
-} \r
+ CopyMem ((VOID *)(UINTN)NewMemPagesBase, (VOID *)(UINTN)Private->MemoryPages.Base, Private->MemoryPages.Size);\r
+ }\r
\r
- return;\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
-PeiInstallPeiMemory (\r
- IN EFI_PEI_SERVICES **PeiServices,\r
- IN EFI_PHYSICAL_ADDRESS MemoryBegin,\r
- IN UINT64 MemoryLength\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
+{\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
-Routine Description:\r
+/**\r
+ Migrate the base address in firmware volume allocation HOBs\r
+ from temporary memory to PEI installed memory.\r
\r
- Install the permanent memory is now available.\r
- Creates HOB (PHIT and Stack).\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
-Arguments:\r
+**/\r
+VOID\r
+ConvertFvHob (\r
+ IN PEI_CORE_INSTANCE *PrivateData,\r
+ IN UINTN OrgFvHandle,\r
+ IN UINTN FvHandle\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
- PeiServices - The PEI core services table.\r
- MemoryBegin - Start of memory address.\r
- MemoryLength - Length of memory.\r
+/**\r
+ Migrate MemoryBaseAddress in memory allocation HOBs\r
+ from the temporary memory to PEI installed memory.\r
\r
-Returns:\r
+ @param[in] PrivateData Pointer to PeiCore's private data structure.\r
\r
- Status - EFI_SUCCESS\r
- \r
---*/\r
+**/\r
+VOID\r
+ConvertMemoryAllocationHobs (\r
+ IN PEI_CORE_INSTANCE *PrivateData\r
+ )\r
{\r
- PEI_CORE_INSTANCE *PrivateData;\r
- EFI_HOB_HANDOFF_INFO_TABLE *OldHandOffHob;\r
- EFI_HOB_HANDOFF_INFO_TABLE *NewHandOffHob;\r
- UINT64 PeiStackSize;\r
- UINT64 EfiFreeMemorySize;\r
- EFI_PHYSICAL_ADDRESS PhysicalAddressOfOldHob;\r
- \r
- PrivateData = PEI_CORE_INSTANCE_FROM_PS_THIS (PeiServices);\r
+ EFI_PEI_HOB_POINTERS Hob;\r
+ EFI_HOB_MEMORY_ALLOCATION *MemoryAllocationHob;\r
+ EFI_PHYSICAL_ADDRESS OldMemPagesBase;\r
+ UINTN OldMemPagesSize;\r
\r
- PrivateData->SwitchStackSignal = TRUE;\r
- PrivateData->PeiMemoryInstalled = TRUE;\r
+ if (PrivateData->MemoryPages.Size == 0) {\r
+ //\r
+ // No any memory page allocated in pre-memory phase.\r
+ //\r
+ return;\r
+ }\r
+\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
+ Hob.Raw = GET_NEXT_HOB (Hob);\r
+ Hob.Raw = GetNextHob (EFI_HOB_TYPE_MEMORY_ALLOCATION, Hob.Raw);\r
+ }\r
+}\r
\r
- PrivateData->StackBase = MemoryBegin;\r
- \r
- PeiStackSize = RShiftU64 (MemoryLength, 1);\r
- if (PEI_STACK_SIZE > PeiStackSize) {\r
- PrivateData->StackSize = PeiStackSize;\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
+ @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
+VOID\r
+InternalBuildMemoryAllocationHob (\r
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,\r
+ IN UINT64 Length,\r
+ IN EFI_MEMORY_TYPE MemoryType\r
+ )\r
+{\r
+ EFI_PEI_HOB_POINTERS Hob;\r
+ EFI_HOB_MEMORY_ALLOCATION *MemoryAllocationHob;\r
+\r
+ //\r
+ // Search unused(freed) memory allocation HOB.\r
+ //\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
+ // Reuse the unused(freed) memory allocation HOB.\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
- PrivateData->StackSize = PEI_STACK_SIZE;\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
- OldHandOffHob = PrivateData->HobList.HandoffInformationTable;\r
+/**\r
+ Update or split memory allocation HOB for memory pages allocate and free.\r
\r
- PrivateData->HobList.Raw = (VOID *)((UINTN)(MemoryBegin + PrivateData->StackSize));\r
- NewHandOffHob = PrivateData->HobList.HandoffInformationTable;\r
- PhysicalAddressOfOldHob = (EFI_PHYSICAL_ADDRESS) (UINTN) OldHandOffHob;\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
- EfiFreeMemorySize = OldHandOffHob->EfiFreeMemoryBottom - PhysicalAddressOfOldHob;\r
- \r
- DEBUG ((EFI_D_INFO, "HOBLIST address before memory init = 0x%08x\n", OldHandOffHob));\r
- DEBUG ((EFI_D_INFO, "HOBLIST address after memory init = 0x%08x\n", NewHandOffHob));\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
- CopyMem (\r
- NewHandOffHob,\r
- OldHandOffHob,\r
- (UINTN)EfiFreeMemorySize\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
+ // Update the memory allocation HOB.\r
+ //\r
+ MemoryAllocationHob->AllocDescriptor.MemoryBaseAddress = Memory;\r
+ MemoryAllocationHob->AllocDescriptor.MemoryLength = Bytes;\r
+ MemoryAllocationHob->AllocDescriptor.MemoryType = MemoryType;\r
+}\r
\r
- NewHandOffHob->EfiMemoryTop = MemoryBegin + MemoryLength;\r
- NewHandOffHob->EfiFreeMemoryTop = NewHandOffHob->EfiMemoryTop;\r
- NewHandOffHob->EfiMemoryBottom = MemoryBegin;\r
- \r
- NewHandOffHob->EfiFreeMemoryBottom = (UINTN)NewHandOffHob + EfiFreeMemorySize; \r
- \r
- NewHandOffHob->EfiEndOfHobList = (UINTN)NewHandOffHob +\r
- (OldHandOffHob->EfiEndOfHobList -\r
- PhysicalAddressOfOldHob);\r
+/**\r
+ Merge adjacent free memory ranges in memory allocation HOBs.\r
\r
- ConvertPpiPointers (PeiServices, OldHandOffHob, NewHandOffHob);\r
+ @retval TRUE There are free memory ranges merged.\r
+ @retval FALSE No free memory ranges merged.\r
\r
- BuildStackHob (PrivateData->StackBase, PrivateData->StackSize);\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 EFI_SUCCESS; \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
-EFIAPI\r
-PeiAllocatePages (\r
- IN EFI_PEI_SERVICES **PeiServices,\r
- IN EFI_MEMORY_TYPE MemoryType,\r
- IN UINTN Pages,\r
- OUT EFI_PHYSICAL_ADDRESS *Memory\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
+{\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
-Routine Description:\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
- Memory allocation service on permanent memory, \r
- not usable prior to the memory installation.\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
-Arguments:\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
- 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
+ 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
-Returns:\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
- 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
+ @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
+**/\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
- PEI_CORE_INSTANCE *PrivateData;\r
- EFI_PEI_HOB_POINTERS Hob;\r
- EFI_PHYSICAL_ADDRESS Offset;\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
- //\r
- // Check if Hob already available\r
- //\r
- if (!PrivateData->PeiMemoryInstalled) {\r
+ if (Hob.Raw == NULL) {\r
+ //\r
+ // HOB is not initialized yet.\r
+ //\r
return EFI_NOT_AVAILABLE_YET;\r
}\r
\r
- Hob.Raw = PrivateData->HobList.Raw;\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
- //\r
- // Check to see if on 4k boundary\r
- //\r
- Offset = Hob.HandoffInformationTable->EfiFreeMemoryTop & 0xFFF;\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
- Hob.HandoffInformationTable->EfiFreeMemoryTop -= 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
+ *(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 (Hob.HandoffInformationTable->EfiFreeMemoryTop - ((Pages * EFI_PAGE_SIZE) + sizeof (EFI_HOB_MEMORY_ALLOCATION)) < \r
- Hob.HandoffInformationTable->EfiFreeMemoryBottom) {\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) (Hob.HandoffInformationTable->EfiFreeMemoryTop - Hob.HandoffInformationTable->EfiFreeMemoryBottom))));\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
//\r
- Hob.HandoffInformationTable->EfiFreeMemoryTop -= Pages * EFI_PAGE_SIZE;\r
+ *(FreeMemoryTop) -= Pages * EFI_PAGE_SIZE;\r
\r
//\r
// Update the value for the caller\r
//\r
- *Memory = Hob.HandoffInformationTable->EfiFreeMemoryTop;\r
+ *Memory = *(FreeMemoryTop);\r
\r
//\r
// Create a memory allocation HOB.\r
//\r
- BuildMemoryAllocationHob (\r
- Hob.HandoffInformationTable->EfiFreeMemoryTop,\r
- Pages * EFI_PAGE_SIZE + Offset,\r
+ InternalBuildMemoryAllocationHob (\r
+ *(FreeMemoryTop),\r
+ Pages * EFI_PAGE_SIZE,\r
MemoryType\r
);\r
\r
}\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 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
-Routine Description:\r
+ PrivateData = PEI_CORE_INSTANCE_FROM_PS_THIS (PeiServices);\r
+ Hob.Raw = PrivateData->HobList.Raw;\r
\r
- Memory allocation service on the CAR. \r
+ if (Hob.Raw == NULL) {\r
+ //\r
+ // HOB is not initialized yet.\r
+ //\r
+ return EFI_NOT_AVAILABLE_YET;\r
+ }\r
\r
-Arguments:\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
+ Hob.Raw = GET_NEXT_HOB (Hob);\r
+ Hob.Raw = GetNextHob (EFI_HOB_TYPE_MEMORY_ALLOCATION, Hob.Raw);\r
+ }\r
\r
- PeiServices - The PEI core services table.\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
+/**\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