IN UINTN Alignment\r
)\r
{\r
- EFI_PHYSICAL_ADDRESS Memory;\r
- EFI_PHYSICAL_ADDRESS AlignedMemory;\r
- EFI_PEI_HOB_POINTERS Hob;\r
- BOOLEAN SkipBeforeMemHob;\r
- BOOLEAN SkipAfterMemHob;\r
- EFI_PHYSICAL_ADDRESS HobBaseAddress;\r
- UINT64 HobLength;\r
- EFI_MEMORY_TYPE HobMemoryType;\r
- UINTN TotalPages;\r
+ EFI_STATUS Status;\r
+ EFI_PHYSICAL_ADDRESS Memory;\r
+ UINTN AlignedMemory;\r
+ UINTN AlignmentMask;\r
+ UINTN UnalignedPages;\r
+ UINTN RealPages;\r
\r
//\r
// Alignment must be a power of two or zero.\r
if (Pages == 0) {\r
return NULL;\r
}\r
- //\r
- // Make sure that Pages plus EFI_SIZE_TO_PAGES (Alignment) does not overflow.\r
- //\r
- ASSERT (Pages <= (MAX_ADDRESS - EFI_SIZE_TO_PAGES (Alignment))); \r
-\r
- //\r
- // We would rather waste some memory to save PEI code size.\r
- // meaning in addition to the requested size for the aligned mem,\r
- // we simply reserve an overhead memory equal to Alignmemt(page-aligned), no matter what.\r
- // The overhead mem size could be reduced later with more involved malloc mechanisms\r
- // (e.g., somthing that can detect the alignment boundary before allocating memory or \r
- // can request that memory be allocated at a certain address that is aleady aligned).\r
- //\r
- TotalPages = Pages + (Alignment <= EFI_PAGE_SIZE ? 0 : EFI_SIZE_TO_PAGES(Alignment));\r
- Memory = (EFI_PHYSICAL_ADDRESS) (UINTN) InternalAllocatePages (MemoryType, TotalPages);\r
- if (Memory == 0) {\r
- DEBUG((DEBUG_INFO, "Out of memory resource! \n"));\r
- return NULL;\r
- }\r
- DEBUG ((DEBUG_INFO, "Allocated Memory unaligned: Address = 0x%LX, Pages = 0x%X, Type = %d \n", Memory, TotalPages, (UINTN) MemoryType));\r
-\r
- //\r
- // Alignment calculation\r
- //\r
- AlignedMemory = Memory;\r
if (Alignment > EFI_PAGE_SIZE) {\r
- AlignedMemory = ALIGN_VALUE (Memory, Alignment);\r
- }\r
- DEBUG ((DEBUG_INFO, "After aligning to 0x%X bytes: Address = 0x%LX, Pages = 0x%X \n", Alignment, AlignedMemory, Pages));\r
-\r
- //\r
- // In general three HOBs cover the total allocated space.\r
- // The aligned portion is covered by the aligned mem HOB and\r
- // the unaligned(to be freed) portions before and after the aligned portion are covered by newly created HOBs.\r
- //\r
- // Before mem HOB covers the region between "Memory" and "AlignedMemory"\r
- // Aligned mem HOB covers the region between "AlignedMemory" and "AlignedMemory + EFI_PAGES_TO_SIZE(Pages)"\r
- // After mem HOB covers the region between "AlignedMemory + EFI_PAGES_TO_SIZE(Pages)" and "Memory + EFI_PAGES_TO_SIZE(TotalPages)"\r
- //\r
- // The before or after mem HOBs need to be skipped under special cases where the aligned portion\r
- // touches either the top or bottom of the original allocated space.\r
- //\r
- SkipBeforeMemHob = FALSE;\r
- SkipAfterMemHob = FALSE;\r
- if (Memory == AlignedMemory) {\r
- SkipBeforeMemHob = TRUE;\r
- }\r
- if ((Memory + EFI_PAGES_TO_SIZE(TotalPages)) == (AlignedMemory + EFI_PAGES_TO_SIZE(Pages))) {\r
//\r
- // This condition is never met in the current implementation.\r
- // There is always some after-mem since the overhead mem(used in TotalPages)\r
- // is no less than Alignment.\r
+ // Calculate the total number of pages since alignment is larger than page size.\r
//\r
- SkipAfterMemHob = TRUE;\r
- }\r
-\r
- // \r
- // Search for the mem HOB referring to the original(unaligned) allocation \r
- // and update the size and type if needed.\r
- //\r
- Hob.Raw = GetFirstHob (EFI_HOB_TYPE_MEMORY_ALLOCATION);\r
- while (Hob.Raw != NULL) {\r
- if (Hob.MemoryAllocation->AllocDescriptor.MemoryBaseAddress == Memory) {\r
- break;\r
- }\r
- Hob.Raw = GET_NEXT_HOB (Hob);\r
- Hob.Raw = GetNextHob (EFI_HOB_TYPE_MEMORY_ALLOCATION, Hob.Raw);\r
- }\r
- ASSERT (Hob.Raw != NULL);\r
- if (SkipBeforeMemHob) {\r
+ AlignmentMask = Alignment - 1;\r
+ RealPages = Pages + EFI_SIZE_TO_PAGES (Alignment);\r
//\r
- // Use this HOB as aligned mem HOB as there is no portion before it.\r
+ // Make sure that Pages plus EFI_SIZE_TO_PAGES (Alignment) does not overflow.\r
//\r
- HobLength = EFI_PAGES_TO_SIZE(Pages);\r
- Hob.MemoryAllocation->AllocDescriptor.MemoryLength = HobLength;\r
+ ASSERT (RealPages > Pages);\r
+\r
+ Status = PeiServicesAllocatePages (MemoryType, RealPages, &Memory);\r
+ if (EFI_ERROR (Status)) {\r
+ return NULL;\r
+ }\r
+ AlignedMemory = ((UINTN) Memory + AlignmentMask) & ~AlignmentMask;\r
+ UnalignedPages = EFI_SIZE_TO_PAGES (AlignedMemory - (UINTN) Memory);\r
+ if (UnalignedPages > 0) {\r
+ //\r
+ // Free first unaligned page(s).\r
+ //\r
+ Status = PeiServicesFreePages (Memory, UnalignedPages);\r
+ ASSERT_EFI_ERROR (Status);\r
+ }\r
+ Memory = AlignedMemory + EFI_PAGES_TO_SIZE (Pages);\r
+ UnalignedPages = RealPages - Pages - UnalignedPages;\r
+ if (UnalignedPages > 0) {\r
+ //\r
+ // Free last unaligned page(s).\r
+ //\r
+ Status = PeiServicesFreePages (Memory, UnalignedPages);\r
+ ASSERT_EFI_ERROR (Status);\r
+ }\r
} else {\r
//\r
- // Use this HOB as before mem HOB and create a new HOB for the aligned portion \r
+ // Do not over-allocate pages in this case.\r
//\r
- HobLength = (AlignedMemory - Memory); \r
- Hob.MemoryAllocation->AllocDescriptor.MemoryLength = HobLength;\r
- Hob.MemoryAllocation->AllocDescriptor.MemoryType = EfiConventionalMemory;\r
- }\r
-\r
- HobBaseAddress = Hob.MemoryAllocation->AllocDescriptor.MemoryBaseAddress;\r
- HobMemoryType = Hob.MemoryAllocation->AllocDescriptor.MemoryType;\r
-\r
- //\r
- // Build the aligned mem HOB if needed\r
- //\r
- if (!SkipBeforeMemHob) {\r
- DEBUG((DEBUG_INFO, "Updated before-mem HOB with BaseAddress = %LX, Length = %LX, MemoryType = %d \n",\r
- HobBaseAddress, HobLength, (UINTN) HobMemoryType));\r
-\r
- HobBaseAddress = AlignedMemory;\r
- HobLength = EFI_PAGES_TO_SIZE(Pages);\r
- HobMemoryType = MemoryType;\r
-\r
- BuildMemoryAllocationHob (\r
- HobBaseAddress,\r
- HobLength,\r
- HobMemoryType\r
- );\r
-\r
- DEBUG((DEBUG_INFO, "Created aligned-mem HOB with BaseAddress = %LX, Length = %LX, MemoryType = %d \n",\r
- HobBaseAddress, HobLength, (UINTN) HobMemoryType));\r
- } else {\r
- if (HobBaseAddress != 0) {\r
- DEBUG((DEBUG_INFO, "Updated aligned-mem HOB with BaseAddress = %LX, Length = %LX, MemoryType = %d \n",\r
- HobBaseAddress, HobLength, (UINTN) HobMemoryType));\r
+ Status = PeiServicesAllocatePages (MemoryType, Pages, &Memory);\r
+ if (EFI_ERROR (Status)) {\r
+ return NULL;\r
}\r
+ AlignedMemory = (UINTN) Memory;\r
}\r
-\r
-\r
- //\r
- // Build the after mem HOB if needed\r
- //\r
- if (!SkipAfterMemHob) {\r
- HobBaseAddress = AlignedMemory + EFI_PAGES_TO_SIZE(Pages);\r
- HobLength = (Memory + EFI_PAGES_TO_SIZE(TotalPages)) - (AlignedMemory + EFI_PAGES_TO_SIZE(Pages));\r
- HobMemoryType = EfiConventionalMemory;\r
-\r
- BuildMemoryAllocationHob (\r
- HobBaseAddress,\r
- HobLength,\r
- HobMemoryType\r
- );\r
-\r
- DEBUG((DEBUG_INFO, "Created after-mem HOB with BaseAddress = %LX, Length = %LX, MemoryType = %d \n",\r
- HobBaseAddress, HobLength, (UINTN) HobMemoryType));\r
- }\r
-\r
- return (VOID *) (UINTN) AlignedMemory;\r
+ return (VOID *) AlignedMemory;\r
}\r
\r
/**\r