2 EFI PEI Core memory services
4 Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
13 Initialize the memory services.
15 @param PrivateData Points to PeiCore's private instance data.
16 @param SecCoreData Points to a data structure containing information about the PEI core's operating
17 environment, such as the size and location of temporary RAM, the stack location and
19 @param OldCoreData Pointer to the PEI Core data.
20 NULL if being run in non-permanent memory mode.
24 InitializeMemoryServices (
25 IN PEI_CORE_INSTANCE
*PrivateData
,
26 IN CONST EFI_SEC_PEI_HAND_OFF
*SecCoreData
,
27 IN PEI_CORE_INSTANCE
*OldCoreData
31 PrivateData
->SwitchStackSignal
= FALSE
;
34 // First entering PeiCore, following code will initialized some field
35 // in PeiCore's private data according to hand off data from SEC core.
37 if (OldCoreData
== NULL
) {
39 PrivateData
->PeiMemoryInstalled
= FALSE
;
40 PrivateData
->HobList
.Raw
= SecCoreData
->PeiTemporaryRamBase
;
42 PeiCoreBuildHobHandoffInfoTable (
43 BOOT_WITH_FULL_CONFIGURATION
,
44 (EFI_PHYSICAL_ADDRESS
) (UINTN
) SecCoreData
->PeiTemporaryRamBase
,
45 (UINTN
) SecCoreData
->PeiTemporaryRamSize
49 // Set Ps to point to ServiceTableShadow in Cache
51 PrivateData
->Ps
= &(PrivateData
->ServiceTableShadow
);
59 This function registers the found memory configuration with the PEI Foundation.
61 The usage model is that the PEIM that discovers the permanent memory shall invoke this service.
62 This routine will hold discoveried memory information into PeiCore's private data,
63 and set SwitchStackSignal flag. After PEIM who discovery memory is dispatched,
64 PeiDispatcher will migrate temporary memory to permanent memory.
66 @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
67 @param MemoryBegin Start of memory address.
68 @param MemoryLength Length of memory.
70 @return EFI_SUCCESS Always success.
76 IN CONST EFI_PEI_SERVICES
**PeiServices
,
77 IN EFI_PHYSICAL_ADDRESS MemoryBegin
,
78 IN UINT64 MemoryLength
81 PEI_CORE_INSTANCE
*PrivateData
;
83 DEBUG ((EFI_D_INFO
, "PeiInstallPeiMemory MemoryBegin 0x%LX, MemoryLength 0x%LX\n", MemoryBegin
, MemoryLength
));
84 PrivateData
= PEI_CORE_INSTANCE_FROM_PS_THIS (PeiServices
);
87 // PEI_SERVICE.InstallPeiMemory should only be called one time during whole PEI phase.
88 // If it is invoked more than one time, ASSERT information is given for developer debugging in debug tip and
89 // simply return EFI_SUCCESS in release tip to ignore it.
91 if (PrivateData
->PeiMemoryInstalled
) {
92 DEBUG ((EFI_D_ERROR
, "ERROR: PeiInstallPeiMemory is called more than once!\n"));
97 PrivateData
->PhysicalMemoryBegin
= MemoryBegin
;
98 PrivateData
->PhysicalMemoryLength
= MemoryLength
;
99 PrivateData
->FreePhysicalMemoryTop
= MemoryBegin
+ MemoryLength
;
101 PrivateData
->SwitchStackSignal
= TRUE
;
107 Migrate memory pages allocated in pre-memory phase.
108 Copy memory pages at temporary heap top to permanent heap top.
110 @param[in] Private Pointer to the private data passed in from caller.
111 @param[in] TemporaryRamMigrated Temporary memory has been migrated to permanent memory.
116 IN PEI_CORE_INSTANCE
*Private
,
117 IN BOOLEAN TemporaryRamMigrated
120 EFI_PHYSICAL_ADDRESS NewMemPagesBase
;
121 EFI_PHYSICAL_ADDRESS MemPagesBase
;
123 Private
->MemoryPages
.Size
= (UINTN
) (Private
->HobList
.HandoffInformationTable
->EfiMemoryTop
-
124 Private
->HobList
.HandoffInformationTable
->EfiFreeMemoryTop
);
125 if (Private
->MemoryPages
.Size
== 0) {
127 // No any memory page allocated in pre-memory phase.
131 Private
->MemoryPages
.Base
= Private
->HobList
.HandoffInformationTable
->EfiFreeMemoryTop
;
133 ASSERT (Private
->MemoryPages
.Size
<= Private
->FreePhysicalMemoryTop
);
134 NewMemPagesBase
= Private
->FreePhysicalMemoryTop
- Private
->MemoryPages
.Size
;
135 NewMemPagesBase
&= ~(UINT64
)EFI_PAGE_MASK
;
136 ASSERT (NewMemPagesBase
>= Private
->PhysicalMemoryBegin
);
138 // Copy memory pages at temporary heap top to permanent heap top.
140 if (TemporaryRamMigrated
) {
142 // Memory pages at temporary heap top has been migrated to permanent heap,
143 // Here still needs to copy them from permanent heap to permanent heap top.
145 MemPagesBase
= Private
->MemoryPages
.Base
;
146 if (Private
->HeapOffsetPositive
) {
147 MemPagesBase
+= Private
->HeapOffset
;
149 MemPagesBase
-= Private
->HeapOffset
;
151 CopyMem ((VOID
*)(UINTN
)NewMemPagesBase
, (VOID
*)(UINTN
)MemPagesBase
, Private
->MemoryPages
.Size
);
153 CopyMem ((VOID
*)(UINTN
)NewMemPagesBase
, (VOID
*)(UINTN
)Private
->MemoryPages
.Base
, Private
->MemoryPages
.Size
);
156 if (NewMemPagesBase
>= Private
->MemoryPages
.Base
) {
157 Private
->MemoryPages
.OffsetPositive
= TRUE
;
158 Private
->MemoryPages
.Offset
= (UINTN
)(NewMemPagesBase
- Private
->MemoryPages
.Base
);
160 Private
->MemoryPages
.OffsetPositive
= FALSE
;
161 Private
->MemoryPages
.Offset
= (UINTN
)(Private
->MemoryPages
.Base
- NewMemPagesBase
);
164 DEBUG ((DEBUG_INFO
, "Pages Offset = 0x%lX\n", (UINT64
) Private
->MemoryPages
.Offset
));
166 Private
->FreePhysicalMemoryTop
= NewMemPagesBase
;
170 Migrate MemoryBaseAddress in memory allocation HOBs
171 from the temporary memory to PEI installed memory.
173 @param[in] PrivateData Pointer to PeiCore's private data structure.
177 ConvertMemoryAllocationHobs (
178 IN PEI_CORE_INSTANCE
*PrivateData
181 EFI_PEI_HOB_POINTERS Hob
;
182 EFI_HOB_MEMORY_ALLOCATION
*MemoryAllocationHob
;
183 EFI_PHYSICAL_ADDRESS OldMemPagesBase
;
184 UINTN OldMemPagesSize
;
186 if (PrivateData
->MemoryPages
.Size
== 0) {
188 // No any memory page allocated in pre-memory phase.
193 OldMemPagesBase
= PrivateData
->MemoryPages
.Base
;
194 OldMemPagesSize
= PrivateData
->MemoryPages
.Size
;
196 MemoryAllocationHob
= NULL
;
197 Hob
.Raw
= GetFirstHob (EFI_HOB_TYPE_MEMORY_ALLOCATION
);
198 while (Hob
.Raw
!= NULL
) {
199 MemoryAllocationHob
= (EFI_HOB_MEMORY_ALLOCATION
*) Hob
.Raw
;
200 if ((MemoryAllocationHob
->AllocDescriptor
.MemoryBaseAddress
>= OldMemPagesBase
) &&
201 (MemoryAllocationHob
->AllocDescriptor
.MemoryBaseAddress
< (OldMemPagesBase
+ OldMemPagesSize
))
203 if (PrivateData
->MemoryPages
.OffsetPositive
) {
204 MemoryAllocationHob
->AllocDescriptor
.MemoryBaseAddress
+= PrivateData
->MemoryPages
.Offset
;
206 MemoryAllocationHob
->AllocDescriptor
.MemoryBaseAddress
-= PrivateData
->MemoryPages
.Offset
;
210 Hob
.Raw
= GET_NEXT_HOB (Hob
);
211 Hob
.Raw
= GetNextHob (EFI_HOB_TYPE_MEMORY_ALLOCATION
, Hob
.Raw
);
216 Internal function to build a HOB for the memory allocation.
217 It will search and reuse the unused(freed) memory allocation HOB,
218 or build memory allocation HOB normally if no unused(freed) memory allocation HOB found.
220 @param[in] BaseAddress The 64 bit physical address of the memory.
221 @param[in] Length The length of the memory allocation in bytes.
222 @param[in] MemoryType The type of memory allocated by this HOB.
226 InternalBuildMemoryAllocationHob (
227 IN EFI_PHYSICAL_ADDRESS BaseAddress
,
229 IN EFI_MEMORY_TYPE MemoryType
232 EFI_PEI_HOB_POINTERS Hob
;
233 EFI_HOB_MEMORY_ALLOCATION
*MemoryAllocationHob
;
236 // Search unused(freed) memory allocation HOB.
238 MemoryAllocationHob
= NULL
;
239 Hob
.Raw
= GetFirstHob (EFI_HOB_TYPE_UNUSED
);
240 while (Hob
.Raw
!= NULL
) {
241 if (Hob
.Header
->HobLength
== sizeof (EFI_HOB_MEMORY_ALLOCATION
)) {
242 MemoryAllocationHob
= (EFI_HOB_MEMORY_ALLOCATION
*) Hob
.Raw
;
246 Hob
.Raw
= GET_NEXT_HOB (Hob
);
247 Hob
.Raw
= GetNextHob (EFI_HOB_TYPE_UNUSED
, Hob
.Raw
);
250 if (MemoryAllocationHob
!= NULL
) {
252 // Reuse the unused(freed) memory allocation HOB.
254 MemoryAllocationHob
->Header
.HobType
= EFI_HOB_TYPE_MEMORY_ALLOCATION
;
255 ZeroMem (&(MemoryAllocationHob
->AllocDescriptor
.Name
), sizeof (EFI_GUID
));
256 MemoryAllocationHob
->AllocDescriptor
.MemoryBaseAddress
= BaseAddress
;
257 MemoryAllocationHob
->AllocDescriptor
.MemoryLength
= Length
;
258 MemoryAllocationHob
->AllocDescriptor
.MemoryType
= MemoryType
;
260 // Zero the reserved space to match HOB spec
262 ZeroMem (MemoryAllocationHob
->AllocDescriptor
.Reserved
, sizeof (MemoryAllocationHob
->AllocDescriptor
.Reserved
));
265 // No unused(freed) memory allocation HOB found.
266 // Build memory allocation HOB normally.
268 BuildMemoryAllocationHob (
277 Update or split memory allocation HOB for memory pages allocate and free.
279 @param[in, out] MemoryAllocationHob Pointer to the memory allocation HOB
280 that needs to be updated or split.
281 On output, it will be filled with
282 the input Memory, Bytes and MemoryType.
283 @param[in] Memory Memory to allocate or free.
284 @param[in] Bytes Bytes to allocate or free.
285 @param[in] MemoryType EfiConventionalMemory for pages free,
286 others for pages allocate.
290 UpdateOrSplitMemoryAllocationHob (
291 IN OUT EFI_HOB_MEMORY_ALLOCATION
*MemoryAllocationHob
,
292 IN EFI_PHYSICAL_ADDRESS Memory
,
294 IN EFI_MEMORY_TYPE MemoryType
297 if ((Memory
+ Bytes
) <
298 (MemoryAllocationHob
->AllocDescriptor
.MemoryBaseAddress
+ MemoryAllocationHob
->AllocDescriptor
.MemoryLength
)) {
300 // Last pages need to be split out.
302 InternalBuildMemoryAllocationHob (
304 (MemoryAllocationHob
->AllocDescriptor
.MemoryBaseAddress
+ MemoryAllocationHob
->AllocDescriptor
.MemoryLength
) - (Memory
+ Bytes
),
305 MemoryAllocationHob
->AllocDescriptor
.MemoryType
309 if (Memory
> MemoryAllocationHob
->AllocDescriptor
.MemoryBaseAddress
) {
311 // First pages need to be split out.
313 InternalBuildMemoryAllocationHob (
314 MemoryAllocationHob
->AllocDescriptor
.MemoryBaseAddress
,
315 Memory
- MemoryAllocationHob
->AllocDescriptor
.MemoryBaseAddress
,
316 MemoryAllocationHob
->AllocDescriptor
.MemoryType
321 // Update the memory allocation HOB.
323 MemoryAllocationHob
->AllocDescriptor
.MemoryBaseAddress
= Memory
;
324 MemoryAllocationHob
->AllocDescriptor
.MemoryLength
= Bytes
;
325 MemoryAllocationHob
->AllocDescriptor
.MemoryType
= MemoryType
;
329 Merge adjacent free memory ranges in memory allocation HOBs.
331 @retval TRUE There are free memory ranges merged.
332 @retval FALSE No free memory ranges merged.
336 MergeFreeMemoryInMemoryAllocationHob (
340 EFI_PEI_HOB_POINTERS Hob
;
341 EFI_PEI_HOB_POINTERS Hob2
;
342 EFI_HOB_MEMORY_ALLOCATION
*MemoryHob
;
343 EFI_HOB_MEMORY_ALLOCATION
*MemoryHob2
;
350 Hob
.Raw
= GetFirstHob (EFI_HOB_TYPE_MEMORY_ALLOCATION
);
351 while (Hob
.Raw
!= NULL
) {
352 if (Hob
.MemoryAllocation
->AllocDescriptor
.MemoryType
== EfiConventionalMemory
) {
353 MemoryHob
= (EFI_HOB_MEMORY_ALLOCATION
*) Hob
.Raw
;
354 Start
= MemoryHob
->AllocDescriptor
.MemoryBaseAddress
;
355 End
= MemoryHob
->AllocDescriptor
.MemoryBaseAddress
+ MemoryHob
->AllocDescriptor
.MemoryLength
;
357 Hob2
.Raw
= GET_NEXT_HOB (Hob
);
358 Hob2
.Raw
= GetNextHob (EFI_HOB_TYPE_MEMORY_ALLOCATION
, Hob
.Raw
);
359 while (Hob2
.Raw
!= NULL
) {
360 if (Hob2
.MemoryAllocation
->AllocDescriptor
.MemoryType
== EfiConventionalMemory
) {
361 MemoryHob2
= (EFI_HOB_MEMORY_ALLOCATION
*) Hob2
.Raw
;
362 if (Start
== (MemoryHob2
->AllocDescriptor
.MemoryBaseAddress
+ MemoryHob2
->AllocDescriptor
.MemoryLength
)) {
364 // Merge adjacent two free memory ranges.
366 MemoryHob2
->AllocDescriptor
.MemoryLength
+= MemoryHob
->AllocDescriptor
.MemoryLength
;
369 // Mark MemoryHob to be unused(freed).
371 MemoryHob
->Header
.HobType
= EFI_HOB_TYPE_UNUSED
;
373 } else if (End
== MemoryHob2
->AllocDescriptor
.MemoryBaseAddress
) {
375 // Merge adjacent two free memory ranges.
377 MemoryHob2
->AllocDescriptor
.MemoryBaseAddress
= MemoryHob
->AllocDescriptor
.MemoryBaseAddress
;
378 MemoryHob2
->AllocDescriptor
.MemoryLength
+= MemoryHob
->AllocDescriptor
.MemoryLength
;
381 // Mark MemoryHob to be unused(freed).
383 MemoryHob
->Header
.HobType
= EFI_HOB_TYPE_UNUSED
;
387 Hob2
.Raw
= GET_NEXT_HOB (Hob2
);
388 Hob2
.Raw
= GetNextHob (EFI_HOB_TYPE_MEMORY_ALLOCATION
, Hob2
.Raw
);
391 Hob
.Raw
= GET_NEXT_HOB (Hob
);
392 Hob
.Raw
= GetNextHob (EFI_HOB_TYPE_MEMORY_ALLOCATION
, Hob
.Raw
);
399 Find free memory by searching memory allocation HOBs.
401 @param[in] MemoryType The type of memory to allocate.
402 @param[in] Pages The number of contiguous 4 KB pages to allocate.
403 @param[in] Granularity Page allocation granularity.
404 @param[out] Memory Pointer to a physical address. On output, the address is set to the base
405 of the page range that was allocated.
407 @retval EFI_SUCCESS The memory range was successfully allocated.
408 @retval EFI_NOT_FOUND No memory allocation HOB with big enough free memory found.
412 FindFreeMemoryFromMemoryAllocationHob (
413 IN EFI_MEMORY_TYPE MemoryType
,
415 IN UINTN Granularity
,
416 OUT EFI_PHYSICAL_ADDRESS
*Memory
419 EFI_PEI_HOB_POINTERS Hob
;
420 EFI_HOB_MEMORY_ALLOCATION
*MemoryAllocationHob
;
422 EFI_PHYSICAL_ADDRESS BaseAddress
;
424 Bytes
= LShiftU64 (Pages
, EFI_PAGE_SHIFT
);
427 MemoryAllocationHob
= NULL
;
428 Hob
.Raw
= GetFirstHob (EFI_HOB_TYPE_MEMORY_ALLOCATION
);
429 while (Hob
.Raw
!= NULL
) {
430 if ((Hob
.MemoryAllocation
->AllocDescriptor
.MemoryType
== EfiConventionalMemory
) &&
431 (Hob
.MemoryAllocation
->AllocDescriptor
.MemoryLength
>= Bytes
)) {
433 // Found one memory allocation HOB with big enough free memory.
435 MemoryAllocationHob
= (EFI_HOB_MEMORY_ALLOCATION
*) Hob
.Raw
;
436 BaseAddress
= MemoryAllocationHob
->AllocDescriptor
.MemoryBaseAddress
+
437 MemoryAllocationHob
->AllocDescriptor
.MemoryLength
- Bytes
;
439 // Make sure the granularity could be satisfied.
441 BaseAddress
&= ~((EFI_PHYSICAL_ADDRESS
) Granularity
- 1);
442 if (BaseAddress
>= MemoryAllocationHob
->AllocDescriptor
.MemoryBaseAddress
) {
446 MemoryAllocationHob
= NULL
;
451 Hob
.Raw
= GET_NEXT_HOB (Hob
);
452 Hob
.Raw
= GetNextHob (EFI_HOB_TYPE_MEMORY_ALLOCATION
, Hob
.Raw
);
455 if (MemoryAllocationHob
!= NULL
) {
456 UpdateOrSplitMemoryAllocationHob (MemoryAllocationHob
, BaseAddress
, Bytes
, MemoryType
);
457 *Memory
= BaseAddress
;
460 if (MergeFreeMemoryInMemoryAllocationHob ()) {
462 // Retry if there are free memory ranges merged.
464 return FindFreeMemoryFromMemoryAllocationHob (MemoryType
, Pages
, Granularity
, Memory
);
466 return EFI_NOT_FOUND
;
471 The purpose of the service is to publish an interface that allows
472 PEIMs to allocate memory ranges that are managed by the PEI Foundation.
474 Prior to InstallPeiMemory() being called, PEI will allocate pages from the heap.
475 After InstallPeiMemory() is called, PEI will allocate pages within the region
476 of memory provided by InstallPeiMemory() service in a best-effort fashion.
477 Location-specific allocations are not managed by the PEI foundation code.
479 @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
480 @param MemoryType The type of memory to allocate.
481 @param Pages The number of contiguous 4 KB pages to allocate.
482 @param Memory Pointer to a physical address. On output, the address is set to the base
483 of the page range that was allocated.
485 @retval EFI_SUCCESS The memory range was successfully allocated.
486 @retval EFI_OUT_OF_RESOURCES The pages could not be allocated.
487 @retval EFI_INVALID_PARAMETER Type is not equal to EfiLoaderCode, EfiLoaderData, EfiRuntimeServicesCode,
488 EfiRuntimeServicesData, EfiBootServicesCode, EfiBootServicesData,
489 EfiACPIReclaimMemory, EfiReservedMemoryType, or EfiACPIMemoryNVS.
495 IN CONST EFI_PEI_SERVICES
**PeiServices
,
496 IN EFI_MEMORY_TYPE MemoryType
,
498 OUT EFI_PHYSICAL_ADDRESS
*Memory
502 PEI_CORE_INSTANCE
*PrivateData
;
503 EFI_PEI_HOB_POINTERS Hob
;
504 EFI_PHYSICAL_ADDRESS
*FreeMemoryTop
;
505 EFI_PHYSICAL_ADDRESS
*FreeMemoryBottom
;
506 UINTN RemainingPages
;
510 if ((MemoryType
!= EfiLoaderCode
) &&
511 (MemoryType
!= EfiLoaderData
) &&
512 (MemoryType
!= EfiRuntimeServicesCode
) &&
513 (MemoryType
!= EfiRuntimeServicesData
) &&
514 (MemoryType
!= EfiBootServicesCode
) &&
515 (MemoryType
!= EfiBootServicesData
) &&
516 (MemoryType
!= EfiACPIReclaimMemory
) &&
517 (MemoryType
!= EfiReservedMemoryType
) &&
518 (MemoryType
!= EfiACPIMemoryNVS
)) {
519 return EFI_INVALID_PARAMETER
;
522 Granularity
= DEFAULT_PAGE_ALLOCATION_GRANULARITY
;
524 PrivateData
= PEI_CORE_INSTANCE_FROM_PS_THIS (PeiServices
);
525 Hob
.Raw
= PrivateData
->HobList
.Raw
;
527 if (Hob
.Raw
== NULL
) {
529 // HOB is not initialized yet.
531 return EFI_NOT_AVAILABLE_YET
;
534 if (RUNTIME_PAGE_ALLOCATION_GRANULARITY
> DEFAULT_PAGE_ALLOCATION_GRANULARITY
&&
535 (MemoryType
== EfiACPIReclaimMemory
||
536 MemoryType
== EfiACPIMemoryNVS
||
537 MemoryType
== EfiRuntimeServicesCode
||
538 MemoryType
== EfiRuntimeServicesData
)) {
540 Granularity
= RUNTIME_PAGE_ALLOCATION_GRANULARITY
;
542 DEBUG ((DEBUG_INFO
, "AllocatePages: aligning allocation to %d KB\n",
543 Granularity
/ SIZE_1KB
));
546 if (!PrivateData
->PeiMemoryInstalled
&& PrivateData
->SwitchStackSignal
) {
548 // When PeiInstallMemory is called but temporary memory has *not* been moved to permanent memory,
549 // the AllocatePage will depend on the field of PEI_CORE_INSTANCE structure.
551 FreeMemoryTop
= &(PrivateData
->FreePhysicalMemoryTop
);
552 FreeMemoryBottom
= &(PrivateData
->PhysicalMemoryBegin
);
554 FreeMemoryTop
= &(Hob
.HandoffInformationTable
->EfiFreeMemoryTop
);
555 FreeMemoryBottom
= &(Hob
.HandoffInformationTable
->EfiFreeMemoryBottom
);
559 // Check to see if on correct boundary for the memory type.
560 // If not aligned, make the allocation aligned.
562 Padding
= *(FreeMemoryTop
) & (Granularity
- 1);
563 if ((UINTN
) (*FreeMemoryTop
- *FreeMemoryBottom
) < Padding
) {
564 DEBUG ((DEBUG_ERROR
, "AllocatePages failed: Out of space after padding.\n"));
565 return EFI_OUT_OF_RESOURCES
;
568 *(FreeMemoryTop
) -= Padding
;
569 if (Padding
>= EFI_PAGE_SIZE
) {
571 // Create a memory allocation HOB to cover
572 // the pages that we will lose to rounding
574 InternalBuildMemoryAllocationHob (
576 Padding
& ~(UINTN
)EFI_PAGE_MASK
,
577 EfiConventionalMemory
582 // Verify that there is sufficient memory to satisfy the allocation.
584 RemainingPages
= (UINTN
)(*FreeMemoryTop
- *FreeMemoryBottom
) >> EFI_PAGE_SHIFT
;
586 // The number of remaining pages needs to be greater than or equal to that of the request pages.
588 Pages
= ALIGN_VALUE (Pages
, EFI_SIZE_TO_PAGES (Granularity
));
589 if (RemainingPages
< Pages
) {
591 // Try to find free memory by searching memory allocation HOBs.
593 Status
= FindFreeMemoryFromMemoryAllocationHob (MemoryType
, Pages
, Granularity
, Memory
);
594 if (!EFI_ERROR (Status
)) {
597 DEBUG ((EFI_D_ERROR
, "AllocatePages failed: No 0x%lx Pages is available.\n", (UINT64
) Pages
));
598 DEBUG ((EFI_D_ERROR
, "There is only left 0x%lx pages memory resource to be allocated.\n", (UINT64
) RemainingPages
));
599 return EFI_OUT_OF_RESOURCES
;
602 // Update the PHIT to reflect the memory usage
604 *(FreeMemoryTop
) -= Pages
* EFI_PAGE_SIZE
;
607 // Update the value for the caller
609 *Memory
= *(FreeMemoryTop
);
612 // Create a memory allocation HOB.
614 InternalBuildMemoryAllocationHob (
616 Pages
* EFI_PAGE_SIZE
,
625 Mark the memory allocation HOB to be unused(freed) and update *FreeMemoryTop
626 if MemoryBaseAddress == *FreeMemoryTop.
628 @param[in] PrivateData Pointer to PeiCore's private data structure.
629 @param[in, out] MemoryAllocationHobToFree Pointer to memory allocation HOB to be freed.
633 FreeMemoryAllocationHob (
634 IN PEI_CORE_INSTANCE
*PrivateData
,
635 IN OUT EFI_HOB_MEMORY_ALLOCATION
*MemoryAllocationHobToFree
638 EFI_PEI_HOB_POINTERS Hob
;
639 EFI_PHYSICAL_ADDRESS
*FreeMemoryTop
;
640 EFI_HOB_MEMORY_ALLOCATION
*MemoryAllocationHob
;
642 Hob
.Raw
= PrivateData
->HobList
.Raw
;
644 if (!PrivateData
->PeiMemoryInstalled
&& PrivateData
->SwitchStackSignal
) {
646 // When PeiInstallMemory is called but temporary memory has *not* been moved to permanent memory,
647 // use the FreePhysicalMemoryTop field of PEI_CORE_INSTANCE structure.
649 FreeMemoryTop
= &(PrivateData
->FreePhysicalMemoryTop
);
651 FreeMemoryTop
= &(Hob
.HandoffInformationTable
->EfiFreeMemoryTop
);
654 if (MemoryAllocationHobToFree
->AllocDescriptor
.MemoryBaseAddress
== *FreeMemoryTop
) {
656 // Update *FreeMemoryTop.
658 *FreeMemoryTop
+= MemoryAllocationHobToFree
->AllocDescriptor
.MemoryLength
;
660 // Mark the memory allocation HOB to be unused(freed).
662 MemoryAllocationHobToFree
->Header
.HobType
= EFI_HOB_TYPE_UNUSED
;
664 MemoryAllocationHob
= NULL
;
665 Hob
.Raw
= GetFirstHob (EFI_HOB_TYPE_MEMORY_ALLOCATION
);
666 while (Hob
.Raw
!= NULL
) {
667 if ((Hob
.MemoryAllocation
->AllocDescriptor
.MemoryType
== EfiConventionalMemory
) &&
668 (Hob
.MemoryAllocation
->AllocDescriptor
.MemoryBaseAddress
== *FreeMemoryTop
)) {
670 // Found memory allocation HOB that has EfiConventionalMemory MemoryType and
671 // MemoryBaseAddress == new *FreeMemoryTop.
673 MemoryAllocationHob
= (EFI_HOB_MEMORY_ALLOCATION
*) Hob
.Raw
;
676 Hob
.Raw
= GET_NEXT_HOB (Hob
);
677 Hob
.Raw
= GetNextHob (EFI_HOB_TYPE_MEMORY_ALLOCATION
, Hob
.Raw
);
680 // Free memory allocation HOB iteratively.
682 if (MemoryAllocationHob
!= NULL
) {
683 FreeMemoryAllocationHob (PrivateData
, MemoryAllocationHob
);
691 @param[in] PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
692 @param[in] Memory The base physical address of the pages to be freed.
693 @param[in] Pages The number of contiguous 4 KB pages to free.
695 @retval EFI_SUCCESS The requested pages were freed.
696 @retval EFI_INVALID_PARAMETER Memory is not a page-aligned address or Pages is invalid.
697 @retval EFI_NOT_FOUND The requested memory pages were not allocated with
704 IN CONST EFI_PEI_SERVICES
**PeiServices
,
705 IN EFI_PHYSICAL_ADDRESS Memory
,
709 PEI_CORE_INSTANCE
*PrivateData
;
713 EFI_PEI_HOB_POINTERS Hob
;
714 EFI_HOB_MEMORY_ALLOCATION
*MemoryAllocationHob
;
716 Bytes
= LShiftU64 (Pages
, EFI_PAGE_SHIFT
);
718 End
= Start
+ Bytes
- 1;
720 if (Pages
== 0 || ((Start
& EFI_PAGE_MASK
) != 0) || (Start
>= End
)) {
721 return EFI_INVALID_PARAMETER
;
724 PrivateData
= PEI_CORE_INSTANCE_FROM_PS_THIS (PeiServices
);
725 Hob
.Raw
= PrivateData
->HobList
.Raw
;
727 if (Hob
.Raw
== NULL
) {
729 // HOB is not initialized yet.
731 return EFI_NOT_AVAILABLE_YET
;
734 MemoryAllocationHob
= NULL
;
735 Hob
.Raw
= GetFirstHob (EFI_HOB_TYPE_MEMORY_ALLOCATION
);
736 while (Hob
.Raw
!= NULL
) {
737 if ((Hob
.MemoryAllocation
->AllocDescriptor
.MemoryType
!= EfiConventionalMemory
) &&
738 (Memory
>= Hob
.MemoryAllocation
->AllocDescriptor
.MemoryBaseAddress
) &&
739 ((Memory
+ Bytes
) <= (Hob
.MemoryAllocation
->AllocDescriptor
.MemoryBaseAddress
+ Hob
.MemoryAllocation
->AllocDescriptor
.MemoryLength
))) {
741 // Found the memory allocation HOB that includes the memory pages to be freed.
743 MemoryAllocationHob
= (EFI_HOB_MEMORY_ALLOCATION
*) Hob
.Raw
;
746 Hob
.Raw
= GET_NEXT_HOB (Hob
);
747 Hob
.Raw
= GetNextHob (EFI_HOB_TYPE_MEMORY_ALLOCATION
, Hob
.Raw
);
750 if (MemoryAllocationHob
!= NULL
) {
751 UpdateOrSplitMemoryAllocationHob (MemoryAllocationHob
, Memory
, Bytes
, EfiConventionalMemory
);
752 FreeMemoryAllocationHob (PrivateData
, MemoryAllocationHob
);
755 return EFI_NOT_FOUND
;
761 Pool allocation service. Before permanent memory is discovered, the pool will
762 be allocated the heap in the temporary memory. Generally, the size of heap in temporary
763 memory does not exceed to 64K, so the biggest pool size could be allocated is
766 @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
767 @param Size Amount of memory required
768 @param Buffer Address of pointer to the buffer
770 @retval EFI_SUCCESS The allocation was successful
771 @retval EFI_OUT_OF_RESOURCES There is not enough heap to satisfy the requirement
772 to allocate the requested size.
778 IN CONST EFI_PEI_SERVICES
**PeiServices
,
784 EFI_HOB_MEMORY_POOL
*Hob
;
787 // If some "post-memory" PEIM wishes to allocate larger pool,
788 // it should use AllocatePages service instead.
792 // Generally, the size of heap in temporary memory does not exceed to 64K,
793 // HobLength is multiples of 8 bytes, so the maximum size of pool is 0xFFF8 - sizeof (EFI_HOB_MEMORY_POOL)
795 if (Size
> (0xFFF8 - sizeof (EFI_HOB_MEMORY_POOL
))) {
796 return EFI_OUT_OF_RESOURCES
;
799 Status
= PeiServicesCreateHob (
800 EFI_HOB_TYPE_MEMORY_POOL
,
801 (UINT16
)(sizeof (EFI_HOB_MEMORY_POOL
) + Size
),
804 ASSERT_EFI_ERROR (Status
);
806 if (EFI_ERROR (Status
)) {