]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Core/Pei/Memory/MemoryServices.c
MdeModule PeiCore: Support pre memory page allocation
[mirror_edk2.git] / MdeModulePkg / Core / Pei / Memory / MemoryServices.c
1 /** @file
2 EFI PEI Core memory services
3
4 Copyright (c) 2006 - 2017, 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
9
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.
12
13 **/
14
15 #include "PeiMain.h"
16
17 /**
18
19 Initialize the memory services.
20
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
24 the BFV location.
25 @param OldCoreData Pointer to the PEI Core data.
26 NULL if being run in non-permament memory mode.
27
28 **/
29 VOID
30 InitializeMemoryServices (
31 IN PEI_CORE_INSTANCE *PrivateData,
32 IN CONST EFI_SEC_PEI_HAND_OFF *SecCoreData,
33 IN PEI_CORE_INSTANCE *OldCoreData
34 )
35 {
36
37 PrivateData->SwitchStackSignal = FALSE;
38
39 //
40 // First entering PeiCore, following code will initialized some field
41 // in PeiCore's private data according to hand off data from sec core.
42 //
43 if (OldCoreData == NULL) {
44
45 PrivateData->PeiMemoryInstalled = FALSE;
46 PrivateData->HobList.Raw = SecCoreData->PeiTemporaryRamBase;
47
48 PeiCoreBuildHobHandoffInfoTable (
49 BOOT_WITH_FULL_CONFIGURATION,
50 (EFI_PHYSICAL_ADDRESS) (UINTN) SecCoreData->PeiTemporaryRamBase,
51 (UINTN) SecCoreData->PeiTemporaryRamSize
52 );
53
54 //
55 // Set Ps to point to ServiceTableShadow in Cache
56 //
57 PrivateData->Ps = &(PrivateData->ServiceTableShadow);
58 }
59
60 return;
61 }
62
63 /**
64
65 This function registers the found memory configuration with the PEI Foundation.
66
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.
71
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.
75
76 @return EFI_SUCCESS Always success.
77
78 **/
79 EFI_STATUS
80 EFIAPI
81 PeiInstallPeiMemory (
82 IN CONST EFI_PEI_SERVICES **PeiServices,
83 IN EFI_PHYSICAL_ADDRESS MemoryBegin,
84 IN UINT64 MemoryLength
85 )
86 {
87 PEI_CORE_INSTANCE *PrivateData;
88
89 DEBUG ((EFI_D_INFO, "PeiInstallPeiMemory MemoryBegin 0x%LX, MemoryLength 0x%LX\n", MemoryBegin, MemoryLength));
90 PrivateData = PEI_CORE_INSTANCE_FROM_PS_THIS (PeiServices);
91
92 //
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.
96 //
97 if (PrivateData->PeiMemoryInstalled) {
98 DEBUG ((EFI_D_ERROR, "ERROR: PeiInstallPeiMemory is called more than once!\n"));
99 ASSERT (FALSE);
100 return EFI_SUCCESS;
101 }
102
103 PrivateData->PhysicalMemoryBegin = MemoryBegin;
104 PrivateData->PhysicalMemoryLength = MemoryLength;
105 PrivateData->FreePhysicalMemoryTop = MemoryBegin + MemoryLength;
106
107 PrivateData->SwitchStackSignal = TRUE;
108
109 return EFI_SUCCESS;
110 }
111
112 /**
113 Migrate memory pages allocated in pre-memory phase.
114 Copy memory pages at temporary heap top to permanent heap top.
115
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.
118
119 **/
120 VOID
121 MigrateMemoryPages (
122 IN PEI_CORE_INSTANCE *Private,
123 IN BOOLEAN TemporaryRamMigrated
124 )
125 {
126 EFI_PHYSICAL_ADDRESS NewMemPagesBase;
127 EFI_PHYSICAL_ADDRESS MemPagesBase;
128
129 Private->MemoryPages.Size = (UINTN) (Private->HobList.HandoffInformationTable->EfiMemoryTop -
130 Private->HobList.HandoffInformationTable->EfiFreeMemoryTop);
131 if (Private->MemoryPages.Size == 0) {
132 //
133 // No any memory page allocated in pre-memory phase.
134 //
135 return;
136 }
137 Private->MemoryPages.Base = Private->HobList.HandoffInformationTable->EfiFreeMemoryTop;
138
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);
143 //
144 // Copy memory pages at temporary heap top to permanent heap top.
145 //
146 if (TemporaryRamMigrated) {
147 //
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.
150 //
151 MemPagesBase = Private->MemoryPages.Base;
152 if (Private->HeapOffsetPositive) {
153 MemPagesBase += Private->HeapOffset;
154 } else {
155 MemPagesBase -= Private->HeapOffset;
156 }
157 CopyMem ((VOID *)(UINTN)NewMemPagesBase, (VOID *)(UINTN)MemPagesBase, Private->MemoryPages.Size);
158 } else {
159 CopyMem ((VOID *)(UINTN)NewMemPagesBase, (VOID *)(UINTN)Private->MemoryPages.Base, Private->MemoryPages.Size);
160 }
161
162 if (NewMemPagesBase >= Private->MemoryPages.Base) {
163 Private->MemoryPages.OffsetPositive = TRUE;
164 Private->MemoryPages.Offset = (UINTN)(NewMemPagesBase - Private->MemoryPages.Base);
165 } else {
166 Private->MemoryPages.OffsetPositive = FALSE;
167 Private->MemoryPages.Offset = (UINTN)(Private->MemoryPages.Base - NewMemPagesBase);
168 }
169
170 DEBUG ((DEBUG_INFO, "Pages Offset = 0x%lX\n", (UINT64) Private->MemoryPages.Offset));
171
172 Private->FreePhysicalMemoryTop = NewMemPagesBase;
173 }
174
175 /**
176 Migrate MemoryBaseAddress in memory allocation HOBs
177 from the temporary memory to PEI installed memory.
178
179 @param[in] PrivateData Pointer to PeiCore's private data structure.
180
181 **/
182 VOID
183 ConvertMemoryAllocationHobs (
184 IN PEI_CORE_INSTANCE *PrivateData
185 )
186 {
187 EFI_PEI_HOB_POINTERS Hob;
188 EFI_HOB_MEMORY_ALLOCATION *MemoryAllocationHob;
189 EFI_PHYSICAL_ADDRESS OldMemPagesBase;
190 UINTN OldMemPagesSize;
191
192 if (PrivateData->MemoryPages.Size == 0) {
193 //
194 // No any memory page allocated in pre-memory phase.
195 //
196 return;
197 }
198
199 OldMemPagesBase = PrivateData->MemoryPages.Base;
200 OldMemPagesSize = PrivateData->MemoryPages.Size;
201
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))
208 ) {
209 if (PrivateData->MemoryPages.OffsetPositive) {
210 MemoryAllocationHob->AllocDescriptor.MemoryBaseAddress += PrivateData->MemoryPages.Offset;
211 } else {
212 MemoryAllocationHob->AllocDescriptor.MemoryBaseAddress -= PrivateData->MemoryPages.Offset;
213 }
214 }
215
216 Hob.Raw = GET_NEXT_HOB (Hob);
217 Hob.Raw = GetNextHob (EFI_HOB_TYPE_MEMORY_ALLOCATION, Hob.Raw);
218 }
219 }
220
221 /**
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.
225
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.
229
230 **/
231 VOID
232 InternalBuildMemoryAllocationHob (
233 IN EFI_PHYSICAL_ADDRESS BaseAddress,
234 IN UINT64 Length,
235 IN EFI_MEMORY_TYPE MemoryType
236 )
237 {
238 EFI_PEI_HOB_POINTERS Hob;
239 EFI_HOB_MEMORY_ALLOCATION *MemoryAllocationHob;
240
241 //
242 // Search unused(freed) memory allocation HOB.
243 //
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;
249 break;
250 }
251
252 Hob.Raw = GET_NEXT_HOB (Hob);
253 Hob.Raw = GetNextHob (EFI_HOB_TYPE_UNUSED, Hob.Raw);
254 }
255
256 if (MemoryAllocationHob != NULL) {
257 //
258 // Reuse the unused(freed) memory allocation HOB.
259 //
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;
265 //
266 // Zero the reserved space to match HOB spec
267 //
268 ZeroMem (MemoryAllocationHob->AllocDescriptor.Reserved, sizeof (MemoryAllocationHob->AllocDescriptor.Reserved));
269 } else {
270 //
271 // No unused(freed) memory allocation HOB found.
272 // Build memory allocation HOB normally.
273 //
274 BuildMemoryAllocationHob (
275 BaseAddress,
276 Length,
277 MemoryType
278 );
279 }
280 }
281
282 /**
283 Update or split memory allocation HOB for memory pages allocate and free.
284
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.
293
294 **/
295 VOID
296 UpdateOrSplitMemoryAllocationHob (
297 IN OUT EFI_HOB_MEMORY_ALLOCATION *MemoryAllocationHob,
298 IN EFI_PHYSICAL_ADDRESS Memory,
299 IN UINT64 Bytes,
300 IN EFI_MEMORY_TYPE MemoryType
301 )
302 {
303 if ((Memory + Bytes) <
304 (MemoryAllocationHob->AllocDescriptor.MemoryBaseAddress + MemoryAllocationHob->AllocDescriptor.MemoryLength)) {
305 //
306 // Last pages need to be split out.
307 //
308 InternalBuildMemoryAllocationHob (
309 Memory + Bytes,
310 (MemoryAllocationHob->AllocDescriptor.MemoryBaseAddress + MemoryAllocationHob->AllocDescriptor.MemoryLength) - (Memory + Bytes),
311 MemoryAllocationHob->AllocDescriptor.MemoryType
312 );
313 }
314
315 if (Memory > MemoryAllocationHob->AllocDescriptor.MemoryBaseAddress) {
316 //
317 // First pages need to be split out.
318 //
319 InternalBuildMemoryAllocationHob (
320 MemoryAllocationHob->AllocDescriptor.MemoryBaseAddress,
321 Memory - MemoryAllocationHob->AllocDescriptor.MemoryBaseAddress,
322 MemoryAllocationHob->AllocDescriptor.MemoryType
323 );
324 }
325
326 //
327 // Update the memory allocation HOB.
328 //
329 MemoryAllocationHob->AllocDescriptor.MemoryBaseAddress = Memory;
330 MemoryAllocationHob->AllocDescriptor.MemoryLength = Bytes;
331 MemoryAllocationHob->AllocDescriptor.MemoryType = MemoryType;
332 }
333
334 /**
335 Merge adjacent free memory ranges in memory allocation HOBs.
336
337 @retval TRUE There are free memory ranges merged.
338 @retval FALSE No free memory ranges merged.
339
340 **/
341 BOOLEAN
342 MergeFreeMemoryInMemoryAllocationHob (
343 VOID
344 )
345 {
346 EFI_PEI_HOB_POINTERS Hob;
347 EFI_PEI_HOB_POINTERS Hob2;
348 EFI_HOB_MEMORY_ALLOCATION *MemoryHob;
349 EFI_HOB_MEMORY_ALLOCATION *MemoryHob2;
350 UINT64 Start;
351 UINT64 End;
352 BOOLEAN Merged;
353
354 Merged = FALSE;
355
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;
362
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)) {
369 //
370 // Merge adjacent two free memory ranges.
371 //
372 MemoryHob2->AllocDescriptor.MemoryLength += MemoryHob->AllocDescriptor.MemoryLength;
373 Merged = TRUE;
374 //
375 // Mark MemoryHob to be unused(freed).
376 //
377 MemoryHob->Header.HobType = EFI_HOB_TYPE_UNUSED;
378 break;
379 } else if (End == MemoryHob2->AllocDescriptor.MemoryBaseAddress) {
380 //
381 // Merge adjacent two free memory ranges.
382 //
383 MemoryHob2->AllocDescriptor.MemoryBaseAddress = MemoryHob->AllocDescriptor.MemoryBaseAddress;
384 MemoryHob2->AllocDescriptor.MemoryLength += MemoryHob->AllocDescriptor.MemoryLength;
385 Merged = TRUE;
386 //
387 // Mark MemoryHob to be unused(freed).
388 //
389 MemoryHob->Header.HobType = EFI_HOB_TYPE_UNUSED;
390 break;
391 }
392 }
393 Hob2.Raw = GET_NEXT_HOB (Hob2);
394 Hob2.Raw = GetNextHob (EFI_HOB_TYPE_MEMORY_ALLOCATION, Hob2.Raw);
395 }
396 }
397 Hob.Raw = GET_NEXT_HOB (Hob);
398 Hob.Raw = GetNextHob (EFI_HOB_TYPE_MEMORY_ALLOCATION, Hob.Raw);
399 }
400
401 return Merged;
402 }
403
404 /**
405 Find free memory by searching memory allocation HOBs.
406
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.
412
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.
415
416 **/
417 EFI_STATUS
418 FindFreeMemoryFromMemoryAllocationHob (
419 IN EFI_MEMORY_TYPE MemoryType,
420 IN UINTN Pages,
421 IN UINTN Granularity,
422 OUT EFI_PHYSICAL_ADDRESS *Memory
423 )
424 {
425 EFI_PEI_HOB_POINTERS Hob;
426 EFI_HOB_MEMORY_ALLOCATION *MemoryAllocationHob;
427 UINT64 Bytes;
428 EFI_PHYSICAL_ADDRESS BaseAddress;
429
430 Bytes = LShiftU64 (Pages, EFI_PAGE_SHIFT);
431
432 BaseAddress = 0;
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)) {
438 //
439 // Found one memory allocation HOB with big enough free memory.
440 //
441 MemoryAllocationHob = (EFI_HOB_MEMORY_ALLOCATION *) Hob.Raw;
442 BaseAddress = MemoryAllocationHob->AllocDescriptor.MemoryBaseAddress +
443 MemoryAllocationHob->AllocDescriptor.MemoryLength - Bytes;
444 //
445 // Make sure the granularity could be satisfied.
446 //
447 BaseAddress &= ~((EFI_PHYSICAL_ADDRESS) Granularity - 1);
448 if (BaseAddress >= MemoryAllocationHob->AllocDescriptor.MemoryBaseAddress) {
449 break;
450 }
451 BaseAddress = 0;
452 MemoryAllocationHob = NULL;
453 }
454 //
455 // Continue to find.
456 //
457 Hob.Raw = GET_NEXT_HOB (Hob);
458 Hob.Raw = GetNextHob (EFI_HOB_TYPE_MEMORY_ALLOCATION, Hob.Raw);
459 }
460
461 if (MemoryAllocationHob != NULL) {
462 UpdateOrSplitMemoryAllocationHob (MemoryAllocationHob, BaseAddress, Bytes, MemoryType);
463 *Memory = BaseAddress;
464 return EFI_SUCCESS;
465 } else {
466 if (MergeFreeMemoryInMemoryAllocationHob ()) {
467 //
468 // Retry if there are free memory ranges merged.
469 //
470 return FindFreeMemoryFromMemoryAllocationHob (MemoryType, Pages, Granularity, Memory);
471 }
472 return EFI_NOT_FOUND;
473 }
474 }
475
476 /**
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.
479
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.
484
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.
490
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.
496
497 **/
498 EFI_STATUS
499 EFIAPI
500 PeiAllocatePages (
501 IN CONST EFI_PEI_SERVICES **PeiServices,
502 IN EFI_MEMORY_TYPE MemoryType,
503 IN UINTN Pages,
504 OUT EFI_PHYSICAL_ADDRESS *Memory
505 )
506 {
507 EFI_STATUS Status;
508 PEI_CORE_INSTANCE *PrivateData;
509 EFI_PEI_HOB_POINTERS Hob;
510 EFI_PHYSICAL_ADDRESS *FreeMemoryTop;
511 EFI_PHYSICAL_ADDRESS *FreeMemoryBottom;
512 UINTN RemainingPages;
513 UINTN Granularity;
514 UINTN Padding;
515
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;
526 }
527
528 Granularity = DEFAULT_PAGE_ALLOCATION_GRANULARITY;
529
530 PrivateData = PEI_CORE_INSTANCE_FROM_PS_THIS (PeiServices);
531 Hob.Raw = PrivateData->HobList.Raw;
532
533 if (Hob.Raw == NULL) {
534 //
535 // HOB is not initialized yet.
536 //
537 return EFI_NOT_AVAILABLE_YET;
538 }
539
540 if (RUNTIME_PAGE_ALLOCATION_GRANULARITY > DEFAULT_PAGE_ALLOCATION_GRANULARITY &&
541 (MemoryType == EfiACPIReclaimMemory ||
542 MemoryType == EfiACPIMemoryNVS ||
543 MemoryType == EfiRuntimeServicesCode ||
544 MemoryType == EfiRuntimeServicesData)) {
545
546 Granularity = RUNTIME_PAGE_ALLOCATION_GRANULARITY;
547
548 DEBUG ((DEBUG_INFO, "AllocatePages: aligning allocation to %d KB\n",
549 Granularity / SIZE_1KB));
550 }
551
552 if (!PrivateData->PeiMemoryInstalled && PrivateData->SwitchStackSignal) {
553 //
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.
556 //
557 FreeMemoryTop = &(PrivateData->FreePhysicalMemoryTop);
558 FreeMemoryBottom = &(PrivateData->PhysicalMemoryBegin);
559 } else {
560 FreeMemoryTop = &(Hob.HandoffInformationTable->EfiFreeMemoryTop);
561 FreeMemoryBottom = &(Hob.HandoffInformationTable->EfiFreeMemoryBottom);
562 }
563
564 //
565 // Check to see if on correct boundary for the memory type.
566 // If not aligned, make the allocation aligned.
567 //
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;
572 }
573
574 *(FreeMemoryTop) -= Padding;
575 if (Padding >= EFI_PAGE_SIZE) {
576 //
577 // Create a memory allocation HOB to cover
578 // the pages that we will lose to rounding
579 //
580 InternalBuildMemoryAllocationHob (
581 *(FreeMemoryTop),
582 Padding & ~(UINTN)EFI_PAGE_MASK,
583 EfiConventionalMemory
584 );
585 }
586
587 //
588 // Verify that there is sufficient memory to satisfy the allocation.
589 //
590 RemainingPages = (UINTN)(*FreeMemoryTop - *FreeMemoryBottom) >> EFI_PAGE_SHIFT;
591 //
592 // The number of remaining pages needs to be greater than or equal to that of the request pages.
593 //
594 Pages = ALIGN_VALUE (Pages, EFI_SIZE_TO_PAGES (Granularity));
595 if (RemainingPages < Pages) {
596 //
597 // Try to find free memory by searching memory allocation HOBs.
598 //
599 Status = FindFreeMemoryFromMemoryAllocationHob (MemoryType, Pages, Granularity, Memory);
600 if (!EFI_ERROR (Status)) {
601 return Status;
602 }
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;
606 } else {
607 //
608 // Update the PHIT to reflect the memory usage
609 //
610 *(FreeMemoryTop) -= Pages * EFI_PAGE_SIZE;
611
612 //
613 // Update the value for the caller
614 //
615 *Memory = *(FreeMemoryTop);
616
617 //
618 // Create a memory allocation HOB.
619 //
620 InternalBuildMemoryAllocationHob (
621 *(FreeMemoryTop),
622 Pages * EFI_PAGE_SIZE,
623 MemoryType
624 );
625
626 return EFI_SUCCESS;
627 }
628 }
629
630 /**
631 Mark the memory allocation HOB to be unused(freed) and update *FreeMemoryTop
632 if MemoryBaseAddress == *FreeMemoryTop.
633
634 @param[in] PrivateData Pointer to PeiCore's private data structure.
635 @param[in, out] MemoryAllocationHobToFree Pointer to memory allocation HOB to be freed.
636
637 **/
638 VOID
639 FreeMemoryAllocationHob (
640 IN PEI_CORE_INSTANCE *PrivateData,
641 IN OUT EFI_HOB_MEMORY_ALLOCATION *MemoryAllocationHobToFree
642 )
643 {
644 EFI_PEI_HOB_POINTERS Hob;
645 EFI_PHYSICAL_ADDRESS *FreeMemoryTop;
646 EFI_HOB_MEMORY_ALLOCATION *MemoryAllocationHob;
647
648 Hob.Raw = PrivateData->HobList.Raw;
649
650 if (!PrivateData->PeiMemoryInstalled && PrivateData->SwitchStackSignal) {
651 //
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.
654 //
655 FreeMemoryTop = &(PrivateData->FreePhysicalMemoryTop);
656 } else {
657 FreeMemoryTop = &(Hob.HandoffInformationTable->EfiFreeMemoryTop);
658 }
659
660 if (MemoryAllocationHobToFree->AllocDescriptor.MemoryBaseAddress == *FreeMemoryTop) {
661 //
662 // Update *FreeMemoryTop.
663 //
664 *FreeMemoryTop += MemoryAllocationHobToFree->AllocDescriptor.MemoryLength;
665 //
666 // Mark the memory allocation HOB to be unused(freed).
667 //
668 MemoryAllocationHobToFree->Header.HobType = EFI_HOB_TYPE_UNUSED;
669
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)) {
675 //
676 // Found memory allocation HOB that has EfiConventionalMemory MemoryType and
677 // MemoryBaseAddress == new *FreeMemoryTop.
678 //
679 MemoryAllocationHob = (EFI_HOB_MEMORY_ALLOCATION *) Hob.Raw;
680 break;
681 }
682 Hob.Raw = GET_NEXT_HOB (Hob);
683 Hob.Raw = GetNextHob (EFI_HOB_TYPE_MEMORY_ALLOCATION, Hob.Raw);
684 }
685 //
686 // Free memory allocation HOB iteratively.
687 //
688 if (MemoryAllocationHob != NULL) {
689 FreeMemoryAllocationHob (PrivateData, MemoryAllocationHob);
690 }
691 }
692 }
693
694 /**
695 Frees memory pages.
696
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.
700
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
704 AllocatePages().
705
706 **/
707 EFI_STATUS
708 EFIAPI
709 PeiFreePages (
710 IN CONST EFI_PEI_SERVICES **PeiServices,
711 IN EFI_PHYSICAL_ADDRESS Memory,
712 IN UINTN Pages
713 )
714 {
715 PEI_CORE_INSTANCE *PrivateData;
716 UINT64 Bytes;
717 UINT64 Start;
718 UINT64 End;
719 EFI_PEI_HOB_POINTERS Hob;
720 EFI_HOB_MEMORY_ALLOCATION *MemoryAllocationHob;
721
722 Bytes = LShiftU64 (Pages, EFI_PAGE_SHIFT);
723 Start = Memory;
724 End = Start + Bytes - 1;
725
726 if (Pages == 0 || ((Start & EFI_PAGE_MASK) != 0) || (Start >= End)) {
727 return EFI_INVALID_PARAMETER;
728 }
729
730 PrivateData = PEI_CORE_INSTANCE_FROM_PS_THIS (PeiServices);
731 Hob.Raw = PrivateData->HobList.Raw;
732
733 if (Hob.Raw == NULL) {
734 //
735 // HOB is not initialized yet.
736 //
737 return EFI_NOT_AVAILABLE_YET;
738 }
739
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))) {
746 //
747 // Found the memory allocation HOB that includes the memory pages to be freed.
748 //
749 MemoryAllocationHob = (EFI_HOB_MEMORY_ALLOCATION *) Hob.Raw;
750 break;
751 }
752 Hob.Raw = GET_NEXT_HOB (Hob);
753 Hob.Raw = GetNextHob (EFI_HOB_TYPE_MEMORY_ALLOCATION, Hob.Raw);
754 }
755
756 if (MemoryAllocationHob != NULL) {
757 UpdateOrSplitMemoryAllocationHob (MemoryAllocationHob, Memory, Bytes, EfiConventionalMemory);
758 FreeMemoryAllocationHob (PrivateData, MemoryAllocationHob);
759 return EFI_SUCCESS;
760 } else {
761 return EFI_NOT_FOUND;
762 }
763 }
764
765 /**
766
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
770 64K.
771
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
775
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.
779
780 **/
781 EFI_STATUS
782 EFIAPI
783 PeiAllocatePool (
784 IN CONST EFI_PEI_SERVICES **PeiServices,
785 IN UINTN Size,
786 OUT VOID **Buffer
787 )
788 {
789 EFI_STATUS Status;
790 EFI_HOB_MEMORY_POOL *Hob;
791
792 //
793 // If some "post-memory" PEIM wishes to allocate larger pool,
794 // it should use AllocatePages service instead.
795 //
796
797 //
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)
800 //
801 if (Size > (0xFFF8 - sizeof (EFI_HOB_MEMORY_POOL))) {
802 return EFI_OUT_OF_RESOURCES;
803 }
804
805 Status = PeiServicesCreateHob (
806 EFI_HOB_TYPE_MEMORY_POOL,
807 (UINT16)(sizeof (EFI_HOB_MEMORY_POOL) + Size),
808 (VOID **)&Hob
809 );
810 ASSERT_EFI_ERROR (Status);
811 *Buffer = Hob+1;
812
813 return Status;
814 }