]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Core/Pei/Memory/MemoryServices.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / MdeModulePkg / Core / Pei / Memory / MemoryServices.c
1 /** @file
2 EFI PEI Core memory services
3
4 Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
6
7 **/
8
9 #include "PeiMain.h"
10
11 /**
12
13 Initialize the memory services.
14
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
18 the BFV location.
19 @param OldCoreData Pointer to the PEI Core data.
20 NULL if being run in non-permanent memory mode.
21
22 **/
23 VOID
24 InitializeMemoryServices (
25 IN PEI_CORE_INSTANCE *PrivateData,
26 IN CONST EFI_SEC_PEI_HAND_OFF *SecCoreData,
27 IN PEI_CORE_INSTANCE *OldCoreData
28 )
29 {
30
31 PrivateData->SwitchStackSignal = FALSE;
32
33 //
34 // First entering PeiCore, following code will initialized some field
35 // in PeiCore's private data according to hand off data from SEC core.
36 //
37 if (OldCoreData == NULL) {
38
39 PrivateData->PeiMemoryInstalled = FALSE;
40 PrivateData->HobList.Raw = SecCoreData->PeiTemporaryRamBase;
41
42 PeiCoreBuildHobHandoffInfoTable (
43 BOOT_WITH_FULL_CONFIGURATION,
44 (EFI_PHYSICAL_ADDRESS) (UINTN) SecCoreData->PeiTemporaryRamBase,
45 (UINTN) SecCoreData->PeiTemporaryRamSize
46 );
47
48 //
49 // Set Ps to point to ServiceTableShadow in Cache
50 //
51 PrivateData->Ps = &(PrivateData->ServiceTableShadow);
52 }
53
54 return;
55 }
56
57 /**
58
59 This function registers the found memory configuration with the PEI Foundation.
60
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.
65
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.
69
70 @return EFI_SUCCESS Always success.
71
72 **/
73 EFI_STATUS
74 EFIAPI
75 PeiInstallPeiMemory (
76 IN CONST EFI_PEI_SERVICES **PeiServices,
77 IN EFI_PHYSICAL_ADDRESS MemoryBegin,
78 IN UINT64 MemoryLength
79 )
80 {
81 PEI_CORE_INSTANCE *PrivateData;
82
83 DEBUG ((EFI_D_INFO, "PeiInstallPeiMemory MemoryBegin 0x%LX, MemoryLength 0x%LX\n", MemoryBegin, MemoryLength));
84 PrivateData = PEI_CORE_INSTANCE_FROM_PS_THIS (PeiServices);
85
86 //
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.
90 //
91 if (PrivateData->PeiMemoryInstalled) {
92 DEBUG ((EFI_D_ERROR, "ERROR: PeiInstallPeiMemory is called more than once!\n"));
93 ASSERT (FALSE);
94 return EFI_SUCCESS;
95 }
96
97 PrivateData->PhysicalMemoryBegin = MemoryBegin;
98 PrivateData->PhysicalMemoryLength = MemoryLength;
99 PrivateData->FreePhysicalMemoryTop = MemoryBegin + MemoryLength;
100
101 PrivateData->SwitchStackSignal = TRUE;
102
103 return EFI_SUCCESS;
104 }
105
106 /**
107 Migrate memory pages allocated in pre-memory phase.
108 Copy memory pages at temporary heap top to permanent heap top.
109
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.
112
113 **/
114 VOID
115 MigrateMemoryPages (
116 IN PEI_CORE_INSTANCE *Private,
117 IN BOOLEAN TemporaryRamMigrated
118 )
119 {
120 EFI_PHYSICAL_ADDRESS NewMemPagesBase;
121 EFI_PHYSICAL_ADDRESS MemPagesBase;
122
123 Private->MemoryPages.Size = (UINTN) (Private->HobList.HandoffInformationTable->EfiMemoryTop -
124 Private->HobList.HandoffInformationTable->EfiFreeMemoryTop);
125 if (Private->MemoryPages.Size == 0) {
126 //
127 // No any memory page allocated in pre-memory phase.
128 //
129 return;
130 }
131 Private->MemoryPages.Base = Private->HobList.HandoffInformationTable->EfiFreeMemoryTop;
132
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);
137 //
138 // Copy memory pages at temporary heap top to permanent heap top.
139 //
140 if (TemporaryRamMigrated) {
141 //
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.
144 //
145 MemPagesBase = Private->MemoryPages.Base;
146 if (Private->HeapOffsetPositive) {
147 MemPagesBase += Private->HeapOffset;
148 } else {
149 MemPagesBase -= Private->HeapOffset;
150 }
151 CopyMem ((VOID *)(UINTN)NewMemPagesBase, (VOID *)(UINTN)MemPagesBase, Private->MemoryPages.Size);
152 } else {
153 CopyMem ((VOID *)(UINTN)NewMemPagesBase, (VOID *)(UINTN)Private->MemoryPages.Base, Private->MemoryPages.Size);
154 }
155
156 if (NewMemPagesBase >= Private->MemoryPages.Base) {
157 Private->MemoryPages.OffsetPositive = TRUE;
158 Private->MemoryPages.Offset = (UINTN)(NewMemPagesBase - Private->MemoryPages.Base);
159 } else {
160 Private->MemoryPages.OffsetPositive = FALSE;
161 Private->MemoryPages.Offset = (UINTN)(Private->MemoryPages.Base - NewMemPagesBase);
162 }
163
164 DEBUG ((DEBUG_INFO, "Pages Offset = 0x%lX\n", (UINT64) Private->MemoryPages.Offset));
165
166 Private->FreePhysicalMemoryTop = NewMemPagesBase;
167 }
168
169 /**
170 Migrate MemoryBaseAddress in memory allocation HOBs
171 from the temporary memory to PEI installed memory.
172
173 @param[in] PrivateData Pointer to PeiCore's private data structure.
174
175 **/
176 VOID
177 ConvertMemoryAllocationHobs (
178 IN PEI_CORE_INSTANCE *PrivateData
179 )
180 {
181 EFI_PEI_HOB_POINTERS Hob;
182 EFI_HOB_MEMORY_ALLOCATION *MemoryAllocationHob;
183 EFI_PHYSICAL_ADDRESS OldMemPagesBase;
184 UINTN OldMemPagesSize;
185
186 if (PrivateData->MemoryPages.Size == 0) {
187 //
188 // No any memory page allocated in pre-memory phase.
189 //
190 return;
191 }
192
193 OldMemPagesBase = PrivateData->MemoryPages.Base;
194 OldMemPagesSize = PrivateData->MemoryPages.Size;
195
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))
202 ) {
203 if (PrivateData->MemoryPages.OffsetPositive) {
204 MemoryAllocationHob->AllocDescriptor.MemoryBaseAddress += PrivateData->MemoryPages.Offset;
205 } else {
206 MemoryAllocationHob->AllocDescriptor.MemoryBaseAddress -= PrivateData->MemoryPages.Offset;
207 }
208 }
209
210 Hob.Raw = GET_NEXT_HOB (Hob);
211 Hob.Raw = GetNextHob (EFI_HOB_TYPE_MEMORY_ALLOCATION, Hob.Raw);
212 }
213 }
214
215 /**
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.
219
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.
223
224 **/
225 VOID
226 InternalBuildMemoryAllocationHob (
227 IN EFI_PHYSICAL_ADDRESS BaseAddress,
228 IN UINT64 Length,
229 IN EFI_MEMORY_TYPE MemoryType
230 )
231 {
232 EFI_PEI_HOB_POINTERS Hob;
233 EFI_HOB_MEMORY_ALLOCATION *MemoryAllocationHob;
234
235 //
236 // Search unused(freed) memory allocation HOB.
237 //
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;
243 break;
244 }
245
246 Hob.Raw = GET_NEXT_HOB (Hob);
247 Hob.Raw = GetNextHob (EFI_HOB_TYPE_UNUSED, Hob.Raw);
248 }
249
250 if (MemoryAllocationHob != NULL) {
251 //
252 // Reuse the unused(freed) memory allocation HOB.
253 //
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;
259 //
260 // Zero the reserved space to match HOB spec
261 //
262 ZeroMem (MemoryAllocationHob->AllocDescriptor.Reserved, sizeof (MemoryAllocationHob->AllocDescriptor.Reserved));
263 } else {
264 //
265 // No unused(freed) memory allocation HOB found.
266 // Build memory allocation HOB normally.
267 //
268 BuildMemoryAllocationHob (
269 BaseAddress,
270 Length,
271 MemoryType
272 );
273 }
274 }
275
276 /**
277 Update or split memory allocation HOB for memory pages allocate and free.
278
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.
287
288 **/
289 VOID
290 UpdateOrSplitMemoryAllocationHob (
291 IN OUT EFI_HOB_MEMORY_ALLOCATION *MemoryAllocationHob,
292 IN EFI_PHYSICAL_ADDRESS Memory,
293 IN UINT64 Bytes,
294 IN EFI_MEMORY_TYPE MemoryType
295 )
296 {
297 if ((Memory + Bytes) <
298 (MemoryAllocationHob->AllocDescriptor.MemoryBaseAddress + MemoryAllocationHob->AllocDescriptor.MemoryLength)) {
299 //
300 // Last pages need to be split out.
301 //
302 InternalBuildMemoryAllocationHob (
303 Memory + Bytes,
304 (MemoryAllocationHob->AllocDescriptor.MemoryBaseAddress + MemoryAllocationHob->AllocDescriptor.MemoryLength) - (Memory + Bytes),
305 MemoryAllocationHob->AllocDescriptor.MemoryType
306 );
307 }
308
309 if (Memory > MemoryAllocationHob->AllocDescriptor.MemoryBaseAddress) {
310 //
311 // First pages need to be split out.
312 //
313 InternalBuildMemoryAllocationHob (
314 MemoryAllocationHob->AllocDescriptor.MemoryBaseAddress,
315 Memory - MemoryAllocationHob->AllocDescriptor.MemoryBaseAddress,
316 MemoryAllocationHob->AllocDescriptor.MemoryType
317 );
318 }
319
320 //
321 // Update the memory allocation HOB.
322 //
323 MemoryAllocationHob->AllocDescriptor.MemoryBaseAddress = Memory;
324 MemoryAllocationHob->AllocDescriptor.MemoryLength = Bytes;
325 MemoryAllocationHob->AllocDescriptor.MemoryType = MemoryType;
326 }
327
328 /**
329 Merge adjacent free memory ranges in memory allocation HOBs.
330
331 @retval TRUE There are free memory ranges merged.
332 @retval FALSE No free memory ranges merged.
333
334 **/
335 BOOLEAN
336 MergeFreeMemoryInMemoryAllocationHob (
337 VOID
338 )
339 {
340 EFI_PEI_HOB_POINTERS Hob;
341 EFI_PEI_HOB_POINTERS Hob2;
342 EFI_HOB_MEMORY_ALLOCATION *MemoryHob;
343 EFI_HOB_MEMORY_ALLOCATION *MemoryHob2;
344 UINT64 Start;
345 UINT64 End;
346 BOOLEAN Merged;
347
348 Merged = FALSE;
349
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;
356
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)) {
363 //
364 // Merge adjacent two free memory ranges.
365 //
366 MemoryHob2->AllocDescriptor.MemoryLength += MemoryHob->AllocDescriptor.MemoryLength;
367 Merged = TRUE;
368 //
369 // Mark MemoryHob to be unused(freed).
370 //
371 MemoryHob->Header.HobType = EFI_HOB_TYPE_UNUSED;
372 break;
373 } else if (End == MemoryHob2->AllocDescriptor.MemoryBaseAddress) {
374 //
375 // Merge adjacent two free memory ranges.
376 //
377 MemoryHob2->AllocDescriptor.MemoryBaseAddress = MemoryHob->AllocDescriptor.MemoryBaseAddress;
378 MemoryHob2->AllocDescriptor.MemoryLength += MemoryHob->AllocDescriptor.MemoryLength;
379 Merged = TRUE;
380 //
381 // Mark MemoryHob to be unused(freed).
382 //
383 MemoryHob->Header.HobType = EFI_HOB_TYPE_UNUSED;
384 break;
385 }
386 }
387 Hob2.Raw = GET_NEXT_HOB (Hob2);
388 Hob2.Raw = GetNextHob (EFI_HOB_TYPE_MEMORY_ALLOCATION, Hob2.Raw);
389 }
390 }
391 Hob.Raw = GET_NEXT_HOB (Hob);
392 Hob.Raw = GetNextHob (EFI_HOB_TYPE_MEMORY_ALLOCATION, Hob.Raw);
393 }
394
395 return Merged;
396 }
397
398 /**
399 Find free memory by searching memory allocation HOBs.
400
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.
406
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.
409
410 **/
411 EFI_STATUS
412 FindFreeMemoryFromMemoryAllocationHob (
413 IN EFI_MEMORY_TYPE MemoryType,
414 IN UINTN Pages,
415 IN UINTN Granularity,
416 OUT EFI_PHYSICAL_ADDRESS *Memory
417 )
418 {
419 EFI_PEI_HOB_POINTERS Hob;
420 EFI_HOB_MEMORY_ALLOCATION *MemoryAllocationHob;
421 UINT64 Bytes;
422 EFI_PHYSICAL_ADDRESS BaseAddress;
423
424 Bytes = LShiftU64 (Pages, EFI_PAGE_SHIFT);
425
426 BaseAddress = 0;
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)) {
432 //
433 // Found one memory allocation HOB with big enough free memory.
434 //
435 MemoryAllocationHob = (EFI_HOB_MEMORY_ALLOCATION *) Hob.Raw;
436 BaseAddress = MemoryAllocationHob->AllocDescriptor.MemoryBaseAddress +
437 MemoryAllocationHob->AllocDescriptor.MemoryLength - Bytes;
438 //
439 // Make sure the granularity could be satisfied.
440 //
441 BaseAddress &= ~((EFI_PHYSICAL_ADDRESS) Granularity - 1);
442 if (BaseAddress >= MemoryAllocationHob->AllocDescriptor.MemoryBaseAddress) {
443 break;
444 }
445 BaseAddress = 0;
446 MemoryAllocationHob = NULL;
447 }
448 //
449 // Continue to find.
450 //
451 Hob.Raw = GET_NEXT_HOB (Hob);
452 Hob.Raw = GetNextHob (EFI_HOB_TYPE_MEMORY_ALLOCATION, Hob.Raw);
453 }
454
455 if (MemoryAllocationHob != NULL) {
456 UpdateOrSplitMemoryAllocationHob (MemoryAllocationHob, BaseAddress, Bytes, MemoryType);
457 *Memory = BaseAddress;
458 return EFI_SUCCESS;
459 } else {
460 if (MergeFreeMemoryInMemoryAllocationHob ()) {
461 //
462 // Retry if there are free memory ranges merged.
463 //
464 return FindFreeMemoryFromMemoryAllocationHob (MemoryType, Pages, Granularity, Memory);
465 }
466 return EFI_NOT_FOUND;
467 }
468 }
469
470 /**
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.
473
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.
478
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.
484
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.
490
491 **/
492 EFI_STATUS
493 EFIAPI
494 PeiAllocatePages (
495 IN CONST EFI_PEI_SERVICES **PeiServices,
496 IN EFI_MEMORY_TYPE MemoryType,
497 IN UINTN Pages,
498 OUT EFI_PHYSICAL_ADDRESS *Memory
499 )
500 {
501 EFI_STATUS Status;
502 PEI_CORE_INSTANCE *PrivateData;
503 EFI_PEI_HOB_POINTERS Hob;
504 EFI_PHYSICAL_ADDRESS *FreeMemoryTop;
505 EFI_PHYSICAL_ADDRESS *FreeMemoryBottom;
506 UINTN RemainingPages;
507 UINTN Granularity;
508 UINTN Padding;
509
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;
520 }
521
522 Granularity = DEFAULT_PAGE_ALLOCATION_GRANULARITY;
523
524 PrivateData = PEI_CORE_INSTANCE_FROM_PS_THIS (PeiServices);
525 Hob.Raw = PrivateData->HobList.Raw;
526
527 if (Hob.Raw == NULL) {
528 //
529 // HOB is not initialized yet.
530 //
531 return EFI_NOT_AVAILABLE_YET;
532 }
533
534 if (RUNTIME_PAGE_ALLOCATION_GRANULARITY > DEFAULT_PAGE_ALLOCATION_GRANULARITY &&
535 (MemoryType == EfiACPIReclaimMemory ||
536 MemoryType == EfiACPIMemoryNVS ||
537 MemoryType == EfiRuntimeServicesCode ||
538 MemoryType == EfiRuntimeServicesData)) {
539
540 Granularity = RUNTIME_PAGE_ALLOCATION_GRANULARITY;
541
542 DEBUG ((DEBUG_INFO, "AllocatePages: aligning allocation to %d KB\n",
543 Granularity / SIZE_1KB));
544 }
545
546 if (!PrivateData->PeiMemoryInstalled && PrivateData->SwitchStackSignal) {
547 //
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.
550 //
551 FreeMemoryTop = &(PrivateData->FreePhysicalMemoryTop);
552 FreeMemoryBottom = &(PrivateData->PhysicalMemoryBegin);
553 } else {
554 FreeMemoryTop = &(Hob.HandoffInformationTable->EfiFreeMemoryTop);
555 FreeMemoryBottom = &(Hob.HandoffInformationTable->EfiFreeMemoryBottom);
556 }
557
558 //
559 // Check to see if on correct boundary for the memory type.
560 // If not aligned, make the allocation aligned.
561 //
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;
566 }
567
568 *(FreeMemoryTop) -= Padding;
569 if (Padding >= EFI_PAGE_SIZE) {
570 //
571 // Create a memory allocation HOB to cover
572 // the pages that we will lose to rounding
573 //
574 InternalBuildMemoryAllocationHob (
575 *(FreeMemoryTop),
576 Padding & ~(UINTN)EFI_PAGE_MASK,
577 EfiConventionalMemory
578 );
579 }
580
581 //
582 // Verify that there is sufficient memory to satisfy the allocation.
583 //
584 RemainingPages = (UINTN)(*FreeMemoryTop - *FreeMemoryBottom) >> EFI_PAGE_SHIFT;
585 //
586 // The number of remaining pages needs to be greater than or equal to that of the request pages.
587 //
588 Pages = ALIGN_VALUE (Pages, EFI_SIZE_TO_PAGES (Granularity));
589 if (RemainingPages < Pages) {
590 //
591 // Try to find free memory by searching memory allocation HOBs.
592 //
593 Status = FindFreeMemoryFromMemoryAllocationHob (MemoryType, Pages, Granularity, Memory);
594 if (!EFI_ERROR (Status)) {
595 return Status;
596 }
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;
600 } else {
601 //
602 // Update the PHIT to reflect the memory usage
603 //
604 *(FreeMemoryTop) -= Pages * EFI_PAGE_SIZE;
605
606 //
607 // Update the value for the caller
608 //
609 *Memory = *(FreeMemoryTop);
610
611 //
612 // Create a memory allocation HOB.
613 //
614 InternalBuildMemoryAllocationHob (
615 *(FreeMemoryTop),
616 Pages * EFI_PAGE_SIZE,
617 MemoryType
618 );
619
620 return EFI_SUCCESS;
621 }
622 }
623
624 /**
625 Mark the memory allocation HOB to be unused(freed) and update *FreeMemoryTop
626 if MemoryBaseAddress == *FreeMemoryTop.
627
628 @param[in] PrivateData Pointer to PeiCore's private data structure.
629 @param[in, out] MemoryAllocationHobToFree Pointer to memory allocation HOB to be freed.
630
631 **/
632 VOID
633 FreeMemoryAllocationHob (
634 IN PEI_CORE_INSTANCE *PrivateData,
635 IN OUT EFI_HOB_MEMORY_ALLOCATION *MemoryAllocationHobToFree
636 )
637 {
638 EFI_PEI_HOB_POINTERS Hob;
639 EFI_PHYSICAL_ADDRESS *FreeMemoryTop;
640 EFI_HOB_MEMORY_ALLOCATION *MemoryAllocationHob;
641
642 Hob.Raw = PrivateData->HobList.Raw;
643
644 if (!PrivateData->PeiMemoryInstalled && PrivateData->SwitchStackSignal) {
645 //
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.
648 //
649 FreeMemoryTop = &(PrivateData->FreePhysicalMemoryTop);
650 } else {
651 FreeMemoryTop = &(Hob.HandoffInformationTable->EfiFreeMemoryTop);
652 }
653
654 if (MemoryAllocationHobToFree->AllocDescriptor.MemoryBaseAddress == *FreeMemoryTop) {
655 //
656 // Update *FreeMemoryTop.
657 //
658 *FreeMemoryTop += MemoryAllocationHobToFree->AllocDescriptor.MemoryLength;
659 //
660 // Mark the memory allocation HOB to be unused(freed).
661 //
662 MemoryAllocationHobToFree->Header.HobType = EFI_HOB_TYPE_UNUSED;
663
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)) {
669 //
670 // Found memory allocation HOB that has EfiConventionalMemory MemoryType and
671 // MemoryBaseAddress == new *FreeMemoryTop.
672 //
673 MemoryAllocationHob = (EFI_HOB_MEMORY_ALLOCATION *) Hob.Raw;
674 break;
675 }
676 Hob.Raw = GET_NEXT_HOB (Hob);
677 Hob.Raw = GetNextHob (EFI_HOB_TYPE_MEMORY_ALLOCATION, Hob.Raw);
678 }
679 //
680 // Free memory allocation HOB iteratively.
681 //
682 if (MemoryAllocationHob != NULL) {
683 FreeMemoryAllocationHob (PrivateData, MemoryAllocationHob);
684 }
685 }
686 }
687
688 /**
689 Frees memory pages.
690
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.
694
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
698 AllocatePages().
699
700 **/
701 EFI_STATUS
702 EFIAPI
703 PeiFreePages (
704 IN CONST EFI_PEI_SERVICES **PeiServices,
705 IN EFI_PHYSICAL_ADDRESS Memory,
706 IN UINTN Pages
707 )
708 {
709 PEI_CORE_INSTANCE *PrivateData;
710 UINT64 Bytes;
711 UINT64 Start;
712 UINT64 End;
713 EFI_PEI_HOB_POINTERS Hob;
714 EFI_HOB_MEMORY_ALLOCATION *MemoryAllocationHob;
715
716 Bytes = LShiftU64 (Pages, EFI_PAGE_SHIFT);
717 Start = Memory;
718 End = Start + Bytes - 1;
719
720 if (Pages == 0 || ((Start & EFI_PAGE_MASK) != 0) || (Start >= End)) {
721 return EFI_INVALID_PARAMETER;
722 }
723
724 PrivateData = PEI_CORE_INSTANCE_FROM_PS_THIS (PeiServices);
725 Hob.Raw = PrivateData->HobList.Raw;
726
727 if (Hob.Raw == NULL) {
728 //
729 // HOB is not initialized yet.
730 //
731 return EFI_NOT_AVAILABLE_YET;
732 }
733
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))) {
740 //
741 // Found the memory allocation HOB that includes the memory pages to be freed.
742 //
743 MemoryAllocationHob = (EFI_HOB_MEMORY_ALLOCATION *) Hob.Raw;
744 break;
745 }
746 Hob.Raw = GET_NEXT_HOB (Hob);
747 Hob.Raw = GetNextHob (EFI_HOB_TYPE_MEMORY_ALLOCATION, Hob.Raw);
748 }
749
750 if (MemoryAllocationHob != NULL) {
751 UpdateOrSplitMemoryAllocationHob (MemoryAllocationHob, Memory, Bytes, EfiConventionalMemory);
752 FreeMemoryAllocationHob (PrivateData, MemoryAllocationHob);
753 return EFI_SUCCESS;
754 } else {
755 return EFI_NOT_FOUND;
756 }
757 }
758
759 /**
760
761 Pool allocation service. Before permanent memory is discovered, the pool will
762 be allocated in the heap in temporary memory. Generally, the size of the heap in temporary
763 memory does not exceed 64K, so the biggest pool size could be allocated is
764 64K.
765
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
769
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.
773
774 **/
775 EFI_STATUS
776 EFIAPI
777 PeiAllocatePool (
778 IN CONST EFI_PEI_SERVICES **PeiServices,
779 IN UINTN Size,
780 OUT VOID **Buffer
781 )
782 {
783 EFI_STATUS Status;
784 EFI_HOB_MEMORY_POOL *Hob;
785
786 //
787 // If some "post-memory" PEIM wishes to allocate larger pool,
788 // it should use AllocatePages service instead.
789 //
790
791 //
792 // Generally, the size of heap in temporary memory does not exceed 64K,
793 // HobLength is multiples of 8 bytes, so the maximum size of pool is 0xFFF8 - sizeof (EFI_HOB_MEMORY_POOL)
794 //
795 if (Size > (0xFFF8 - sizeof (EFI_HOB_MEMORY_POOL))) {
796 return EFI_OUT_OF_RESOURCES;
797 }
798
799 Status = PeiServicesCreateHob (
800 EFI_HOB_TYPE_MEMORY_POOL,
801 (UINT16)(sizeof (EFI_HOB_MEMORY_POOL) + Size),
802 (VOID **)&Hob
803 );
804 ASSERT_EFI_ERROR (Status);
805
806 if (EFI_ERROR (Status)) {
807 *Buffer = NULL;
808 } else {
809 *Buffer = Hob + 1;
810 }
811
812 return Status;
813 }