+ 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