2 EFI PEI Core memory services
4 Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
19 Initialize the memory services.
21 @param PrivateData Points to PeiCore's private instance data.
22 @param SecCoreData Points to a data structure containing information about the PEI core's operating
23 environment, such as the size and location of temporary RAM, the stack location and
25 @param OldCoreData Pointer to the PEI Core data.
26 NULL if being run in non-permament memory mode.
30 InitializeMemoryServices (
31 IN PEI_CORE_INSTANCE
*PrivateData
,
32 IN CONST EFI_SEC_PEI_HAND_OFF
*SecCoreData
,
33 IN PEI_CORE_INSTANCE
*OldCoreData
37 PrivateData
->SwitchStackSignal
= FALSE
;
40 // First entering PeiCore, following code will initialized some field
41 // in PeiCore's private data according to hand off data from sec core.
43 if (OldCoreData
== NULL
) {
45 PrivateData
->PeiMemoryInstalled
= FALSE
;
46 PrivateData
->HobList
.Raw
= SecCoreData
->PeiTemporaryRamBase
;
48 PeiCoreBuildHobHandoffInfoTable (
49 BOOT_WITH_FULL_CONFIGURATION
,
50 (EFI_PHYSICAL_ADDRESS
) (UINTN
) SecCoreData
->PeiTemporaryRamBase
,
51 (UINTN
) SecCoreData
->PeiTemporaryRamSize
55 // Set Ps to point to ServiceTableShadow in Cache
57 PrivateData
->Ps
= &(PrivateData
->ServiceTableShadow
);
65 This function registers the found memory configuration with the PEI Foundation.
67 The usage model is that the PEIM that discovers the permanent memory shall invoke this service.
68 This routine will hold discoveried memory information into PeiCore's private data,
69 and set SwitchStackSignal flag. After PEIM who discovery memory is dispatched,
70 PeiDispatcher will migrate temporary memory to permenement memory.
72 @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
73 @param MemoryBegin Start of memory address.
74 @param MemoryLength Length of memory.
76 @return EFI_SUCCESS Always success.
82 IN CONST EFI_PEI_SERVICES
**PeiServices
,
83 IN EFI_PHYSICAL_ADDRESS MemoryBegin
,
84 IN UINT64 MemoryLength
87 PEI_CORE_INSTANCE
*PrivateData
;
89 DEBUG ((EFI_D_INFO
, "PeiInstallPeiMemory MemoryBegin 0x%LX, MemoryLength 0x%LX\n", MemoryBegin
, MemoryLength
));
90 PrivateData
= PEI_CORE_INSTANCE_FROM_PS_THIS (PeiServices
);
93 // PEI_SERVICE.InstallPeiMemory should only be called one time during whole PEI phase.
94 // If it is invoked more than one time, ASSERT information is given for developer debugging in debug tip and
95 // simply return EFI_SUCESS in release tip to ignore it.
97 if (PrivateData
->PeiMemoryInstalled
) {
98 DEBUG ((EFI_D_ERROR
, "ERROR: PeiInstallPeiMemory is called more than once!\n"));
103 PrivateData
->PhysicalMemoryBegin
= MemoryBegin
;
104 PrivateData
->PhysicalMemoryLength
= MemoryLength
;
105 PrivateData
->FreePhysicalMemoryTop
= MemoryBegin
+ MemoryLength
;
107 PrivateData
->SwitchStackSignal
= TRUE
;
113 Migrate memory pages allocated in pre-memory phase.
114 Copy memory pages at temporary heap top to permanent heap top.
116 @param[in] Private Pointer to the private data passed in from caller.
117 @param[in] TemporaryRamMigrated Temporary memory has been migrated to permanent memory.
122 IN PEI_CORE_INSTANCE
*Private
,
123 IN BOOLEAN TemporaryRamMigrated
126 EFI_PHYSICAL_ADDRESS NewMemPagesBase
;
127 EFI_PHYSICAL_ADDRESS MemPagesBase
;
129 Private
->MemoryPages
.Size
= (UINTN
) (Private
->HobList
.HandoffInformationTable
->EfiMemoryTop
-
130 Private
->HobList
.HandoffInformationTable
->EfiFreeMemoryTop
);
131 if (Private
->MemoryPages
.Size
== 0) {
133 // No any memory page allocated in pre-memory phase.
137 Private
->MemoryPages
.Base
= Private
->HobList
.HandoffInformationTable
->EfiFreeMemoryTop
;
139 ASSERT (Private
->MemoryPages
.Size
<= Private
->FreePhysicalMemoryTop
);
140 NewMemPagesBase
= Private
->FreePhysicalMemoryTop
- Private
->MemoryPages
.Size
;
141 NewMemPagesBase
&= ~(UINT64
)EFI_PAGE_MASK
;
142 ASSERT (NewMemPagesBase
>= Private
->PhysicalMemoryBegin
);
144 // Copy memory pages at temporary heap top to permanent heap top.
146 if (TemporaryRamMigrated
) {
148 // Memory pages at temporary heap top has been migrated to permanent heap,
149 // Here still needs to copy them from permanent heap to permanent heap top.
151 MemPagesBase
= Private
->MemoryPages
.Base
;
152 if (Private
->HeapOffsetPositive
) {
153 MemPagesBase
+= Private
->HeapOffset
;
155 MemPagesBase
-= Private
->HeapOffset
;
157 CopyMem ((VOID
*)(UINTN
)NewMemPagesBase
, (VOID
*)(UINTN
)MemPagesBase
, Private
->MemoryPages
.Size
);
159 CopyMem ((VOID
*)(UINTN
)NewMemPagesBase
, (VOID
*)(UINTN
)Private
->MemoryPages
.Base
, Private
->MemoryPages
.Size
);
162 if (NewMemPagesBase
>= Private
->MemoryPages
.Base
) {
163 Private
->MemoryPages
.OffsetPositive
= TRUE
;
164 Private
->MemoryPages
.Offset
= (UINTN
)(NewMemPagesBase
- Private
->MemoryPages
.Base
);
166 Private
->MemoryPages
.OffsetPositive
= FALSE
;
167 Private
->MemoryPages
.Offset
= (UINTN
)(Private
->MemoryPages
.Base
- NewMemPagesBase
);
170 DEBUG ((DEBUG_INFO
, "Pages Offset = 0x%lX\n", (UINT64
) Private
->MemoryPages
.Offset
));
172 Private
->FreePhysicalMemoryTop
= NewMemPagesBase
;
176 Migrate MemoryBaseAddress in memory allocation HOBs
177 from the temporary memory to PEI installed memory.
179 @param[in] PrivateData Pointer to PeiCore's private data structure.
183 ConvertMemoryAllocationHobs (
184 IN PEI_CORE_INSTANCE
*PrivateData
187 EFI_PEI_HOB_POINTERS Hob
;
188 EFI_HOB_MEMORY_ALLOCATION
*MemoryAllocationHob
;
189 EFI_PHYSICAL_ADDRESS OldMemPagesBase
;
190 UINTN OldMemPagesSize
;
192 if (PrivateData
->MemoryPages
.Size
== 0) {
194 // No any memory page allocated in pre-memory phase.
199 OldMemPagesBase
= PrivateData
->MemoryPages
.Base
;
200 OldMemPagesSize
= PrivateData
->MemoryPages
.Size
;
202 MemoryAllocationHob
= NULL
;
203 Hob
.Raw
= GetFirstHob (EFI_HOB_TYPE_MEMORY_ALLOCATION
);
204 while (Hob
.Raw
!= NULL
) {
205 MemoryAllocationHob
= (EFI_HOB_MEMORY_ALLOCATION
*) Hob
.Raw
;
206 if ((MemoryAllocationHob
->AllocDescriptor
.MemoryBaseAddress
>= OldMemPagesBase
) &&
207 (MemoryAllocationHob
->AllocDescriptor
.MemoryBaseAddress
< (OldMemPagesBase
+ OldMemPagesSize
))
209 if (PrivateData
->MemoryPages
.OffsetPositive
) {
210 MemoryAllocationHob
->AllocDescriptor
.MemoryBaseAddress
+= PrivateData
->MemoryPages
.Offset
;
212 MemoryAllocationHob
->AllocDescriptor
.MemoryBaseAddress
-= PrivateData
->MemoryPages
.Offset
;
216 Hob
.Raw
= GET_NEXT_HOB (Hob
);
217 Hob
.Raw
= GetNextHob (EFI_HOB_TYPE_MEMORY_ALLOCATION
, Hob
.Raw
);
222 Internal function to build a HOB for the memory allocation.
223 It will search and reuse the unused(freed) memory allocation HOB,
224 or build memory allocation HOB normally if no unused(freed) memory allocation HOB found.
226 @param[in] BaseAddress The 64 bit physical address of the memory.
227 @param[in] Length The length of the memory allocation in bytes.
228 @param[in] MemoryType The type of memory allocated by this HOB.
232 InternalBuildMemoryAllocationHob (
233 IN EFI_PHYSICAL_ADDRESS BaseAddress
,
235 IN EFI_MEMORY_TYPE MemoryType
238 EFI_PEI_HOB_POINTERS Hob
;
239 EFI_HOB_MEMORY_ALLOCATION
*MemoryAllocationHob
;
242 // Search unused(freed) memory allocation HOB.
244 MemoryAllocationHob
= NULL
;
245 Hob
.Raw
= GetFirstHob (EFI_HOB_TYPE_UNUSED
);
246 while (Hob
.Raw
!= NULL
) {
247 if (Hob
.Header
->HobLength
== sizeof (EFI_HOB_MEMORY_ALLOCATION
)) {
248 MemoryAllocationHob
= (EFI_HOB_MEMORY_ALLOCATION
*) Hob
.Raw
;
252 Hob
.Raw
= GET_NEXT_HOB (Hob
);
253 Hob
.Raw
= GetNextHob (EFI_HOB_TYPE_UNUSED
, Hob
.Raw
);
256 if (MemoryAllocationHob
!= NULL
) {
258 // Reuse the unused(freed) memory allocation HOB.
260 MemoryAllocationHob
->Header
.HobType
= EFI_HOB_TYPE_MEMORY_ALLOCATION
;
261 ZeroMem (&(MemoryAllocationHob
->AllocDescriptor
.Name
), sizeof (EFI_GUID
));
262 MemoryAllocationHob
->AllocDescriptor
.MemoryBaseAddress
= BaseAddress
;
263 MemoryAllocationHob
->AllocDescriptor
.MemoryLength
= Length
;
264 MemoryAllocationHob
->AllocDescriptor
.MemoryType
= MemoryType
;
266 // Zero the reserved space to match HOB spec
268 ZeroMem (MemoryAllocationHob
->AllocDescriptor
.Reserved
, sizeof (MemoryAllocationHob
->AllocDescriptor
.Reserved
));
271 // No unused(freed) memory allocation HOB found.
272 // Build memory allocation HOB normally.
274 BuildMemoryAllocationHob (
283 Update or split memory allocation HOB for memory pages allocate and free.
285 @param[in, out] MemoryAllocationHob Pointer to the memory allocation HOB
286 that needs to be updated or split.
287 On output, it will be filled with
288 the input Memory, Bytes and MemoryType.
289 @param[in] Memory Memory to allocate or free.
290 @param[in] Bytes Bytes to allocate or free.
291 @param[in] MemoryType EfiConventionalMemory for pages free,
292 others for pages allocate.
296 UpdateOrSplitMemoryAllocationHob (
297 IN OUT EFI_HOB_MEMORY_ALLOCATION
*MemoryAllocationHob
,
298 IN EFI_PHYSICAL_ADDRESS Memory
,
300 IN EFI_MEMORY_TYPE MemoryType
303 if ((Memory
+ Bytes
) <
304 (MemoryAllocationHob
->AllocDescriptor
.MemoryBaseAddress
+ MemoryAllocationHob
->AllocDescriptor
.MemoryLength
)) {
306 // Last pages need to be split out.
308 InternalBuildMemoryAllocationHob (
310 (MemoryAllocationHob
->AllocDescriptor
.MemoryBaseAddress
+ MemoryAllocationHob
->AllocDescriptor
.MemoryLength
) - (Memory
+ Bytes
),
311 MemoryAllocationHob
->AllocDescriptor
.MemoryType
315 if (Memory
> MemoryAllocationHob
->AllocDescriptor
.MemoryBaseAddress
) {
317 // First pages need to be split out.
319 InternalBuildMemoryAllocationHob (
320 MemoryAllocationHob
->AllocDescriptor
.MemoryBaseAddress
,
321 Memory
- MemoryAllocationHob
->AllocDescriptor
.MemoryBaseAddress
,
322 MemoryAllocationHob
->AllocDescriptor
.MemoryType
327 // Update the memory allocation HOB.
329 MemoryAllocationHob
->AllocDescriptor
.MemoryBaseAddress
= Memory
;
330 MemoryAllocationHob
->AllocDescriptor
.MemoryLength
= Bytes
;
331 MemoryAllocationHob
->AllocDescriptor
.MemoryType
= MemoryType
;
335 Merge adjacent free memory ranges in memory allocation HOBs.
337 @retval TRUE There are free memory ranges merged.
338 @retval FALSE No free memory ranges merged.
342 MergeFreeMemoryInMemoryAllocationHob (
346 EFI_PEI_HOB_POINTERS Hob
;
347 EFI_PEI_HOB_POINTERS Hob2
;
348 EFI_HOB_MEMORY_ALLOCATION
*MemoryHob
;
349 EFI_HOB_MEMORY_ALLOCATION
*MemoryHob2
;
356 Hob
.Raw
= GetFirstHob (EFI_HOB_TYPE_MEMORY_ALLOCATION
);
357 while (Hob
.Raw
!= NULL
) {
358 if (Hob
.MemoryAllocation
->AllocDescriptor
.MemoryType
== EfiConventionalMemory
) {
359 MemoryHob
= (EFI_HOB_MEMORY_ALLOCATION
*) Hob
.Raw
;
360 Start
= MemoryHob
->AllocDescriptor
.MemoryBaseAddress
;
361 End
= MemoryHob
->AllocDescriptor
.MemoryBaseAddress
+ MemoryHob
->AllocDescriptor
.MemoryLength
;
363 Hob2
.Raw
= GET_NEXT_HOB (Hob
);
364 Hob2
.Raw
= GetNextHob (EFI_HOB_TYPE_MEMORY_ALLOCATION
, Hob
.Raw
);
365 while (Hob2
.Raw
!= NULL
) {
366 if (Hob2
.MemoryAllocation
->AllocDescriptor
.MemoryType
== EfiConventionalMemory
) {
367 MemoryHob2
= (EFI_HOB_MEMORY_ALLOCATION
*) Hob2
.Raw
;
368 if (Start
== (MemoryHob2
->AllocDescriptor
.MemoryBaseAddress
+ MemoryHob2
->AllocDescriptor
.MemoryLength
)) {
370 // Merge adjacent two free memory ranges.
372 MemoryHob2
->AllocDescriptor
.MemoryLength
+= MemoryHob
->AllocDescriptor
.MemoryLength
;
375 // Mark MemoryHob to be unused(freed).
377 MemoryHob
->Header
.HobType
= EFI_HOB_TYPE_UNUSED
;
379 } else if (End
== MemoryHob2
->AllocDescriptor
.MemoryBaseAddress
) {
381 // Merge adjacent two free memory ranges.
383 MemoryHob2
->AllocDescriptor
.MemoryBaseAddress
= MemoryHob
->AllocDescriptor
.MemoryBaseAddress
;
384 MemoryHob2
->AllocDescriptor
.MemoryLength
+= MemoryHob
->AllocDescriptor
.MemoryLength
;
387 // Mark MemoryHob to be unused(freed).
389 MemoryHob
->Header
.HobType
= EFI_HOB_TYPE_UNUSED
;
393 Hob2
.Raw
= GET_NEXT_HOB (Hob2
);
394 Hob2
.Raw
= GetNextHob (EFI_HOB_TYPE_MEMORY_ALLOCATION
, Hob2
.Raw
);
397 Hob
.Raw
= GET_NEXT_HOB (Hob
);
398 Hob
.Raw
= GetNextHob (EFI_HOB_TYPE_MEMORY_ALLOCATION
, Hob
.Raw
);
405 Find free memory by searching memory allocation HOBs.
407 @param[in] MemoryType The type of memory to allocate.
408 @param[in] Pages The number of contiguous 4 KB pages to allocate.
409 @param[in] Granularity Page allocation granularity.
410 @param[out] Memory Pointer to a physical address. On output, the address is set to the base
411 of the page range that was allocated.
413 @retval EFI_SUCCESS The memory range was successfully allocated.
414 @retval EFI_NOT_FOUND No memory allocation HOB with big enough free memory found.
418 FindFreeMemoryFromMemoryAllocationHob (
419 IN EFI_MEMORY_TYPE MemoryType
,
421 IN UINTN Granularity
,
422 OUT EFI_PHYSICAL_ADDRESS
*Memory
425 EFI_PEI_HOB_POINTERS Hob
;
426 EFI_HOB_MEMORY_ALLOCATION
*MemoryAllocationHob
;
428 EFI_PHYSICAL_ADDRESS BaseAddress
;
430 Bytes
= LShiftU64 (Pages
, EFI_PAGE_SHIFT
);
433 MemoryAllocationHob
= NULL
;
434 Hob
.Raw
= GetFirstHob (EFI_HOB_TYPE_MEMORY_ALLOCATION
);
435 while (Hob
.Raw
!= NULL
) {
436 if ((Hob
.MemoryAllocation
->AllocDescriptor
.MemoryType
== EfiConventionalMemory
) &&
437 (Hob
.MemoryAllocation
->AllocDescriptor
.MemoryLength
>= Bytes
)) {
439 // Found one memory allocation HOB with big enough free memory.
441 MemoryAllocationHob
= (EFI_HOB_MEMORY_ALLOCATION
*) Hob
.Raw
;
442 BaseAddress
= MemoryAllocationHob
->AllocDescriptor
.MemoryBaseAddress
+
443 MemoryAllocationHob
->AllocDescriptor
.MemoryLength
- Bytes
;
445 // Make sure the granularity could be satisfied.
447 BaseAddress
&= ~((EFI_PHYSICAL_ADDRESS
) Granularity
- 1);
448 if (BaseAddress
>= MemoryAllocationHob
->AllocDescriptor
.MemoryBaseAddress
) {
452 MemoryAllocationHob
= NULL
;
457 Hob
.Raw
= GET_NEXT_HOB (Hob
);
458 Hob
.Raw
= GetNextHob (EFI_HOB_TYPE_MEMORY_ALLOCATION
, Hob
.Raw
);
461 if (MemoryAllocationHob
!= NULL
) {
462 UpdateOrSplitMemoryAllocationHob (MemoryAllocationHob
, BaseAddress
, Bytes
, MemoryType
);
463 *Memory
= BaseAddress
;
466 if (MergeFreeMemoryInMemoryAllocationHob ()) {
468 // Retry if there are free memory ranges merged.
470 return FindFreeMemoryFromMemoryAllocationHob (MemoryType
, Pages
, Granularity
, Memory
);
472 return EFI_NOT_FOUND
;
477 The purpose of the service is to publish an interface that allows
478 PEIMs to allocate memory ranges that are managed by the PEI Foundation.
480 Prior to InstallPeiMemory() being called, PEI will allocate pages from the heap.
481 After InstallPeiMemory() is called, PEI will allocate pages within the region
482 of memory provided by InstallPeiMemory() service in a best-effort fashion.
483 Location-specific allocations are not managed by the PEI foundation code.
485 @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
486 @param MemoryType The type of memory to allocate.
487 @param Pages The number of contiguous 4 KB pages to allocate.
488 @param Memory Pointer to a physical address. On output, the address is set to the base
489 of the page range that was allocated.
491 @retval EFI_SUCCESS The memory range was successfully allocated.
492 @retval EFI_OUT_OF_RESOURCES The pages could not be allocated.
493 @retval EFI_INVALID_PARAMETER Type is not equal to EfiLoaderCode, EfiLoaderData, EfiRuntimeServicesCode,
494 EfiRuntimeServicesData, EfiBootServicesCode, EfiBootServicesData,
495 EfiACPIReclaimMemory, EfiReservedMemoryType, or EfiACPIMemoryNVS.
501 IN CONST EFI_PEI_SERVICES
**PeiServices
,
502 IN EFI_MEMORY_TYPE MemoryType
,
504 OUT EFI_PHYSICAL_ADDRESS
*Memory
508 PEI_CORE_INSTANCE
*PrivateData
;
509 EFI_PEI_HOB_POINTERS Hob
;
510 EFI_PHYSICAL_ADDRESS
*FreeMemoryTop
;
511 EFI_PHYSICAL_ADDRESS
*FreeMemoryBottom
;
512 UINTN RemainingPages
;
516 if ((MemoryType
!= EfiLoaderCode
) &&
517 (MemoryType
!= EfiLoaderData
) &&
518 (MemoryType
!= EfiRuntimeServicesCode
) &&
519 (MemoryType
!= EfiRuntimeServicesData
) &&
520 (MemoryType
!= EfiBootServicesCode
) &&
521 (MemoryType
!= EfiBootServicesData
) &&
522 (MemoryType
!= EfiACPIReclaimMemory
) &&
523 (MemoryType
!= EfiReservedMemoryType
) &&
524 (MemoryType
!= EfiACPIMemoryNVS
)) {
525 return EFI_INVALID_PARAMETER
;
528 Granularity
= DEFAULT_PAGE_ALLOCATION_GRANULARITY
;
530 PrivateData
= PEI_CORE_INSTANCE_FROM_PS_THIS (PeiServices
);
531 Hob
.Raw
= PrivateData
->HobList
.Raw
;
533 if (Hob
.Raw
== NULL
) {
535 // HOB is not initialized yet.
537 return EFI_NOT_AVAILABLE_YET
;
540 if (RUNTIME_PAGE_ALLOCATION_GRANULARITY
> DEFAULT_PAGE_ALLOCATION_GRANULARITY
&&
541 (MemoryType
== EfiACPIReclaimMemory
||
542 MemoryType
== EfiACPIMemoryNVS
||
543 MemoryType
== EfiRuntimeServicesCode
||
544 MemoryType
== EfiRuntimeServicesData
)) {
546 Granularity
= RUNTIME_PAGE_ALLOCATION_GRANULARITY
;
548 DEBUG ((DEBUG_INFO
, "AllocatePages: aligning allocation to %d KB\n",
549 Granularity
/ SIZE_1KB
));
552 if (!PrivateData
->PeiMemoryInstalled
&& PrivateData
->SwitchStackSignal
) {
554 // When PeiInstallMemory is called but temporary memory has *not* been moved to permanent memory,
555 // the AllocatePage will depend on the field of PEI_CORE_INSTANCE structure.
557 FreeMemoryTop
= &(PrivateData
->FreePhysicalMemoryTop
);
558 FreeMemoryBottom
= &(PrivateData
->PhysicalMemoryBegin
);
560 FreeMemoryTop
= &(Hob
.HandoffInformationTable
->EfiFreeMemoryTop
);
561 FreeMemoryBottom
= &(Hob
.HandoffInformationTable
->EfiFreeMemoryBottom
);
565 // Check to see if on correct boundary for the memory type.
566 // If not aligned, make the allocation aligned.
568 Padding
= *(FreeMemoryTop
) & (Granularity
- 1);
569 if ((UINTN
) (*FreeMemoryTop
- *FreeMemoryBottom
) < Padding
) {
570 DEBUG ((DEBUG_ERROR
, "AllocatePages failed: Out of space after padding.\n"));
571 return EFI_OUT_OF_RESOURCES
;
574 *(FreeMemoryTop
) -= Padding
;
575 if (Padding
>= EFI_PAGE_SIZE
) {
577 // Create a memory allocation HOB to cover
578 // the pages that we will lose to rounding
580 InternalBuildMemoryAllocationHob (
582 Padding
& ~(UINTN
)EFI_PAGE_MASK
,
583 EfiConventionalMemory
588 // Verify that there is sufficient memory to satisfy the allocation.
590 RemainingPages
= (UINTN
)(*FreeMemoryTop
- *FreeMemoryBottom
) >> EFI_PAGE_SHIFT
;
592 // The number of remaining pages needs to be greater than or equal to that of the request pages.
594 Pages
= ALIGN_VALUE (Pages
, EFI_SIZE_TO_PAGES (Granularity
));
595 if (RemainingPages
< Pages
) {
597 // Try to find free memory by searching memory allocation HOBs.
599 Status
= FindFreeMemoryFromMemoryAllocationHob (MemoryType
, Pages
, Granularity
, Memory
);
600 if (!EFI_ERROR (Status
)) {
603 DEBUG ((EFI_D_ERROR
, "AllocatePages failed: No 0x%lx Pages is available.\n", (UINT64
) Pages
));
604 DEBUG ((EFI_D_ERROR
, "There is only left 0x%lx pages memory resource to be allocated.\n", (UINT64
) RemainingPages
));
605 return EFI_OUT_OF_RESOURCES
;
608 // Update the PHIT to reflect the memory usage
610 *(FreeMemoryTop
) -= Pages
* EFI_PAGE_SIZE
;
613 // Update the value for the caller
615 *Memory
= *(FreeMemoryTop
);
618 // Create a memory allocation HOB.
620 InternalBuildMemoryAllocationHob (
622 Pages
* EFI_PAGE_SIZE
,
631 Mark the memory allocation HOB to be unused(freed) and update *FreeMemoryTop
632 if MemoryBaseAddress == *FreeMemoryTop.
634 @param[in] PrivateData Pointer to PeiCore's private data structure.
635 @param[in, out] MemoryAllocationHobToFree Pointer to memory allocation HOB to be freed.
639 FreeMemoryAllocationHob (
640 IN PEI_CORE_INSTANCE
*PrivateData
,
641 IN OUT EFI_HOB_MEMORY_ALLOCATION
*MemoryAllocationHobToFree
644 EFI_PEI_HOB_POINTERS Hob
;
645 EFI_PHYSICAL_ADDRESS
*FreeMemoryTop
;
646 EFI_HOB_MEMORY_ALLOCATION
*MemoryAllocationHob
;
648 Hob
.Raw
= PrivateData
->HobList
.Raw
;
650 if (!PrivateData
->PeiMemoryInstalled
&& PrivateData
->SwitchStackSignal
) {
652 // When PeiInstallMemory is called but temporary memory has *not* been moved to permanent memory,
653 // use the FreePhysicalMemoryTop field of PEI_CORE_INSTANCE structure.
655 FreeMemoryTop
= &(PrivateData
->FreePhysicalMemoryTop
);
657 FreeMemoryTop
= &(Hob
.HandoffInformationTable
->EfiFreeMemoryTop
);
660 if (MemoryAllocationHobToFree
->AllocDescriptor
.MemoryBaseAddress
== *FreeMemoryTop
) {
662 // Update *FreeMemoryTop.
664 *FreeMemoryTop
+= MemoryAllocationHobToFree
->AllocDescriptor
.MemoryLength
;
666 // Mark the memory allocation HOB to be unused(freed).
668 MemoryAllocationHobToFree
->Header
.HobType
= EFI_HOB_TYPE_UNUSED
;
670 MemoryAllocationHob
= NULL
;
671 Hob
.Raw
= GetFirstHob (EFI_HOB_TYPE_MEMORY_ALLOCATION
);
672 while (Hob
.Raw
!= NULL
) {
673 if ((Hob
.MemoryAllocation
->AllocDescriptor
.MemoryType
== EfiConventionalMemory
) &&
674 (Hob
.MemoryAllocation
->AllocDescriptor
.MemoryBaseAddress
== *FreeMemoryTop
)) {
676 // Found memory allocation HOB that has EfiConventionalMemory MemoryType and
677 // MemoryBaseAddress == new *FreeMemoryTop.
679 MemoryAllocationHob
= (EFI_HOB_MEMORY_ALLOCATION
*) Hob
.Raw
;
682 Hob
.Raw
= GET_NEXT_HOB (Hob
);
683 Hob
.Raw
= GetNextHob (EFI_HOB_TYPE_MEMORY_ALLOCATION
, Hob
.Raw
);
686 // Free memory allocation HOB iteratively.
688 if (MemoryAllocationHob
!= NULL
) {
689 FreeMemoryAllocationHob (PrivateData
, MemoryAllocationHob
);
697 @param[in] PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
698 @param[in] Memory The base physical address of the pages to be freed.
699 @param[in] Pages The number of contiguous 4 KB pages to free.
701 @retval EFI_SUCCESS The requested pages were freed.
702 @retval EFI_INVALID_PARAMETER Memory is not a page-aligned address or Pages is invalid.
703 @retval EFI_NOT_FOUND The requested memory pages were not allocated with
710 IN CONST EFI_PEI_SERVICES
**PeiServices
,
711 IN EFI_PHYSICAL_ADDRESS Memory
,
715 PEI_CORE_INSTANCE
*PrivateData
;
719 EFI_PEI_HOB_POINTERS Hob
;
720 EFI_HOB_MEMORY_ALLOCATION
*MemoryAllocationHob
;
722 Bytes
= LShiftU64 (Pages
, EFI_PAGE_SHIFT
);
724 End
= Start
+ Bytes
- 1;
726 if (Pages
== 0 || ((Start
& EFI_PAGE_MASK
) != 0) || (Start
>= End
)) {
727 return EFI_INVALID_PARAMETER
;
730 PrivateData
= PEI_CORE_INSTANCE_FROM_PS_THIS (PeiServices
);
731 Hob
.Raw
= PrivateData
->HobList
.Raw
;
733 if (Hob
.Raw
== NULL
) {
735 // HOB is not initialized yet.
737 return EFI_NOT_AVAILABLE_YET
;
740 MemoryAllocationHob
= NULL
;
741 Hob
.Raw
= GetFirstHob (EFI_HOB_TYPE_MEMORY_ALLOCATION
);
742 while (Hob
.Raw
!= NULL
) {
743 if ((Hob
.MemoryAllocation
->AllocDescriptor
.MemoryType
!= EfiConventionalMemory
) &&
744 (Memory
>= Hob
.MemoryAllocation
->AllocDescriptor
.MemoryBaseAddress
) &&
745 ((Memory
+ Bytes
) <= (Hob
.MemoryAllocation
->AllocDescriptor
.MemoryBaseAddress
+ Hob
.MemoryAllocation
->AllocDescriptor
.MemoryLength
))) {
747 // Found the memory allocation HOB that includes the memory pages to be freed.
749 MemoryAllocationHob
= (EFI_HOB_MEMORY_ALLOCATION
*) Hob
.Raw
;
752 Hob
.Raw
= GET_NEXT_HOB (Hob
);
753 Hob
.Raw
= GetNextHob (EFI_HOB_TYPE_MEMORY_ALLOCATION
, Hob
.Raw
);
756 if (MemoryAllocationHob
!= NULL
) {
757 UpdateOrSplitMemoryAllocationHob (MemoryAllocationHob
, Memory
, Bytes
, EfiConventionalMemory
);
758 FreeMemoryAllocationHob (PrivateData
, MemoryAllocationHob
);
761 return EFI_NOT_FOUND
;
767 Pool allocation service. Before permanent memory is discoveried, the pool will
768 be allocated the heap in the temporary memory. Genenrally, the size of heap in temporary
769 memory does not exceed to 64K, so the biggest pool size could be allocated is
772 @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
773 @param Size Amount of memory required
774 @param Buffer Address of pointer to the buffer
776 @retval EFI_SUCCESS The allocation was successful
777 @retval EFI_OUT_OF_RESOURCES There is not enough heap to satisfy the requirement
778 to allocate the requested size.
784 IN CONST EFI_PEI_SERVICES
**PeiServices
,
790 EFI_HOB_MEMORY_POOL
*Hob
;
793 // If some "post-memory" PEIM wishes to allocate larger pool,
794 // it should use AllocatePages service instead.
798 // Generally, the size of heap in temporary memory does not exceed to 64K,
799 // HobLength is multiples of 8 bytes, so the maxmium size of pool is 0xFFF8 - sizeof (EFI_HOB_MEMORY_POOL)
801 if (Size
> (0xFFF8 - sizeof (EFI_HOB_MEMORY_POOL
))) {
802 return EFI_OUT_OF_RESOURCES
;
805 Status
= PeiServicesCreateHob (
806 EFI_HOB_TYPE_MEMORY_POOL
,
807 (UINT16
)(sizeof (EFI_HOB_MEMORY_POOL
) + Size
),
810 ASSERT_EFI_ERROR (Status
);