]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - MdeModulePkg/Core/Pei/Memory/MemoryServices.c
MdeModulePkg PeiCore: Fix typos
[mirror_edk2.git] / MdeModulePkg / Core / Pei / Memory / MemoryServices.c
... / ...
CommitLineData
1/** @file\r
2 EFI PEI Core memory services\r
3\r
4Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>\r
5SPDX-License-Identifier: BSD-2-Clause-Patent\r
6\r
7**/\r
8\r
9#include "PeiMain.h"\r
10\r
11/**\r
12\r
13 Initialize the memory services.\r
14\r
15 @param PrivateData Points to PeiCore's private instance data.\r
16 @param SecCoreData Points to a data structure containing information about the PEI core's operating\r
17 environment, such as the size and location of temporary RAM, the stack location and\r
18 the BFV location.\r
19 @param OldCoreData Pointer to the PEI Core data.\r
20 NULL if being run in non-permanent memory mode.\r
21\r
22**/\r
23VOID\r
24InitializeMemoryServices (\r
25 IN PEI_CORE_INSTANCE *PrivateData,\r
26 IN CONST EFI_SEC_PEI_HAND_OFF *SecCoreData,\r
27 IN PEI_CORE_INSTANCE *OldCoreData\r
28 )\r
29{\r
30\r
31 PrivateData->SwitchStackSignal = FALSE;\r
32\r
33 //\r
34 // First entering PeiCore, following code will initialized some field\r
35 // in PeiCore's private data according to hand off data from SEC core.\r
36 //\r
37 if (OldCoreData == NULL) {\r
38\r
39 PrivateData->PeiMemoryInstalled = FALSE;\r
40 PrivateData->HobList.Raw = SecCoreData->PeiTemporaryRamBase;\r
41\r
42 PeiCoreBuildHobHandoffInfoTable (\r
43 BOOT_WITH_FULL_CONFIGURATION,\r
44 (EFI_PHYSICAL_ADDRESS) (UINTN) SecCoreData->PeiTemporaryRamBase,\r
45 (UINTN) SecCoreData->PeiTemporaryRamSize\r
46 );\r
47\r
48 //\r
49 // Set Ps to point to ServiceTableShadow in Cache\r
50 //\r
51 PrivateData->Ps = &(PrivateData->ServiceTableShadow);\r
52 }\r
53\r
54 return;\r
55}\r
56\r
57/**\r
58\r
59 This function registers the found memory configuration with the PEI Foundation.\r
60\r
61 The usage model is that the PEIM that discovers the permanent memory shall invoke this service.\r
62 This routine will hold discoveried memory information into PeiCore's private data,\r
63 and set SwitchStackSignal flag. After PEIM who discovery memory is dispatched,\r
64 PeiDispatcher will migrate temporary memory to permanent memory.\r
65\r
66 @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.\r
67 @param MemoryBegin Start of memory address.\r
68 @param MemoryLength Length of memory.\r
69\r
70 @return EFI_SUCCESS Always success.\r
71\r
72**/\r
73EFI_STATUS\r
74EFIAPI\r
75PeiInstallPeiMemory (\r
76 IN CONST EFI_PEI_SERVICES **PeiServices,\r
77 IN EFI_PHYSICAL_ADDRESS MemoryBegin,\r
78 IN UINT64 MemoryLength\r
79 )\r
80{\r
81 PEI_CORE_INSTANCE *PrivateData;\r
82\r
83 DEBUG ((EFI_D_INFO, "PeiInstallPeiMemory MemoryBegin 0x%LX, MemoryLength 0x%LX\n", MemoryBegin, MemoryLength));\r
84 PrivateData = PEI_CORE_INSTANCE_FROM_PS_THIS (PeiServices);\r
85\r
86 //\r
87 // PEI_SERVICE.InstallPeiMemory should only be called one time during whole PEI phase.\r
88 // If it is invoked more than one time, ASSERT information is given for developer debugging in debug tip and\r
89 // simply return EFI_SUCCESS in release tip to ignore it.\r
90 //\r
91 if (PrivateData->PeiMemoryInstalled) {\r
92 DEBUG ((EFI_D_ERROR, "ERROR: PeiInstallPeiMemory is called more than once!\n"));\r
93 ASSERT (FALSE);\r
94 return EFI_SUCCESS;\r
95 }\r
96\r
97 PrivateData->PhysicalMemoryBegin = MemoryBegin;\r
98 PrivateData->PhysicalMemoryLength = MemoryLength;\r
99 PrivateData->FreePhysicalMemoryTop = MemoryBegin + MemoryLength;\r
100\r
101 PrivateData->SwitchStackSignal = TRUE;\r
102\r
103 return EFI_SUCCESS;\r
104}\r
105\r
106/**\r
107 Migrate memory pages allocated in pre-memory phase.\r
108 Copy memory pages at temporary heap top to permanent heap top.\r
109\r
110 @param[in] Private Pointer to the private data passed in from caller.\r
111 @param[in] TemporaryRamMigrated Temporary memory has been migrated to permanent memory.\r
112\r
113**/\r
114VOID\r
115MigrateMemoryPages (\r
116 IN PEI_CORE_INSTANCE *Private,\r
117 IN BOOLEAN TemporaryRamMigrated\r
118 )\r
119{\r
120 EFI_PHYSICAL_ADDRESS NewMemPagesBase;\r
121 EFI_PHYSICAL_ADDRESS MemPagesBase;\r
122\r
123 Private->MemoryPages.Size = (UINTN) (Private->HobList.HandoffInformationTable->EfiMemoryTop -\r
124 Private->HobList.HandoffInformationTable->EfiFreeMemoryTop);\r
125 if (Private->MemoryPages.Size == 0) {\r
126 //\r
127 // No any memory page allocated in pre-memory phase.\r
128 //\r
129 return;\r
130 }\r
131 Private->MemoryPages.Base = Private->HobList.HandoffInformationTable->EfiFreeMemoryTop;\r
132\r
133 ASSERT (Private->MemoryPages.Size <= Private->FreePhysicalMemoryTop);\r
134 NewMemPagesBase = Private->FreePhysicalMemoryTop - Private->MemoryPages.Size;\r
135 NewMemPagesBase &= ~(UINT64)EFI_PAGE_MASK;\r
136 ASSERT (NewMemPagesBase >= Private->PhysicalMemoryBegin);\r
137 //\r
138 // Copy memory pages at temporary heap top to permanent heap top.\r
139 //\r
140 if (TemporaryRamMigrated) {\r
141 //\r
142 // Memory pages at temporary heap top has been migrated to permanent heap,\r
143 // Here still needs to copy them from permanent heap to permanent heap top.\r
144 //\r
145 MemPagesBase = Private->MemoryPages.Base;\r
146 if (Private->HeapOffsetPositive) {\r
147 MemPagesBase += Private->HeapOffset;\r
148 } else {\r
149 MemPagesBase -= Private->HeapOffset;\r
150 }\r
151 CopyMem ((VOID *)(UINTN)NewMemPagesBase, (VOID *)(UINTN)MemPagesBase, Private->MemoryPages.Size);\r
152 } else {\r
153 CopyMem ((VOID *)(UINTN)NewMemPagesBase, (VOID *)(UINTN)Private->MemoryPages.Base, Private->MemoryPages.Size);\r
154 }\r
155\r
156 if (NewMemPagesBase >= Private->MemoryPages.Base) {\r
157 Private->MemoryPages.OffsetPositive = TRUE;\r
158 Private->MemoryPages.Offset = (UINTN)(NewMemPagesBase - Private->MemoryPages.Base);\r
159 } else {\r
160 Private->MemoryPages.OffsetPositive = FALSE;\r
161 Private->MemoryPages.Offset = (UINTN)(Private->MemoryPages.Base - NewMemPagesBase);\r
162 }\r
163\r
164 DEBUG ((DEBUG_INFO, "Pages Offset = 0x%lX\n", (UINT64) Private->MemoryPages.Offset));\r
165\r
166 Private->FreePhysicalMemoryTop = NewMemPagesBase;\r
167}\r
168\r
169/**\r
170 Migrate MemoryBaseAddress in memory allocation HOBs\r
171 from the temporary memory to PEI installed memory.\r
172\r
173 @param[in] PrivateData Pointer to PeiCore's private data structure.\r
174\r
175**/\r
176VOID\r
177ConvertMemoryAllocationHobs (\r
178 IN PEI_CORE_INSTANCE *PrivateData\r
179 )\r
180{\r
181 EFI_PEI_HOB_POINTERS Hob;\r
182 EFI_HOB_MEMORY_ALLOCATION *MemoryAllocationHob;\r
183 EFI_PHYSICAL_ADDRESS OldMemPagesBase;\r
184 UINTN OldMemPagesSize;\r
185\r
186 if (PrivateData->MemoryPages.Size == 0) {\r
187 //\r
188 // No any memory page allocated in pre-memory phase.\r
189 //\r
190 return;\r
191 }\r
192\r
193 OldMemPagesBase = PrivateData->MemoryPages.Base;\r
194 OldMemPagesSize = PrivateData->MemoryPages.Size;\r
195\r
196 MemoryAllocationHob = NULL;\r
197 Hob.Raw = GetFirstHob (EFI_HOB_TYPE_MEMORY_ALLOCATION);\r
198 while (Hob.Raw != NULL) {\r
199 MemoryAllocationHob = (EFI_HOB_MEMORY_ALLOCATION *) Hob.Raw;\r
200 if ((MemoryAllocationHob->AllocDescriptor.MemoryBaseAddress >= OldMemPagesBase) &&\r
201 (MemoryAllocationHob->AllocDescriptor.MemoryBaseAddress < (OldMemPagesBase + OldMemPagesSize))\r
202 ) {\r
203 if (PrivateData->MemoryPages.OffsetPositive) {\r
204 MemoryAllocationHob->AllocDescriptor.MemoryBaseAddress += PrivateData->MemoryPages.Offset;\r
205 } else {\r
206 MemoryAllocationHob->AllocDescriptor.MemoryBaseAddress -= PrivateData->MemoryPages.Offset;\r
207 }\r
208 }\r
209\r
210 Hob.Raw = GET_NEXT_HOB (Hob);\r
211 Hob.Raw = GetNextHob (EFI_HOB_TYPE_MEMORY_ALLOCATION, Hob.Raw);\r
212 }\r
213}\r
214\r
215/**\r
216 Internal function to build a HOB for the memory allocation.\r
217 It will search and reuse the unused(freed) memory allocation HOB,\r
218 or build memory allocation HOB normally if no unused(freed) memory allocation HOB found.\r
219\r
220 @param[in] BaseAddress The 64 bit physical address of the memory.\r
221 @param[in] Length The length of the memory allocation in bytes.\r
222 @param[in] MemoryType The type of memory allocated by this HOB.\r
223\r
224**/\r
225VOID\r
226InternalBuildMemoryAllocationHob (\r
227 IN EFI_PHYSICAL_ADDRESS BaseAddress,\r
228 IN UINT64 Length,\r
229 IN EFI_MEMORY_TYPE MemoryType\r
230 )\r
231{\r
232 EFI_PEI_HOB_POINTERS Hob;\r
233 EFI_HOB_MEMORY_ALLOCATION *MemoryAllocationHob;\r
234\r
235 //\r
236 // Search unused(freed) memory allocation HOB.\r
237 //\r
238 MemoryAllocationHob = NULL;\r
239 Hob.Raw = GetFirstHob (EFI_HOB_TYPE_UNUSED);\r
240 while (Hob.Raw != NULL) {\r
241 if (Hob.Header->HobLength == sizeof (EFI_HOB_MEMORY_ALLOCATION)) {\r
242 MemoryAllocationHob = (EFI_HOB_MEMORY_ALLOCATION *) Hob.Raw;\r
243 break;\r
244 }\r
245\r
246 Hob.Raw = GET_NEXT_HOB (Hob);\r
247 Hob.Raw = GetNextHob (EFI_HOB_TYPE_UNUSED, Hob.Raw);\r
248 }\r
249\r
250 if (MemoryAllocationHob != NULL) {\r
251 //\r
252 // Reuse the unused(freed) memory allocation HOB.\r
253 //\r
254 MemoryAllocationHob->Header.HobType = EFI_HOB_TYPE_MEMORY_ALLOCATION;\r
255 ZeroMem (&(MemoryAllocationHob->AllocDescriptor.Name), sizeof (EFI_GUID));\r
256 MemoryAllocationHob->AllocDescriptor.MemoryBaseAddress = BaseAddress;\r
257 MemoryAllocationHob->AllocDescriptor.MemoryLength = Length;\r
258 MemoryAllocationHob->AllocDescriptor.MemoryType = MemoryType;\r
259 //\r
260 // Zero the reserved space to match HOB spec\r
261 //\r
262 ZeroMem (MemoryAllocationHob->AllocDescriptor.Reserved, sizeof (MemoryAllocationHob->AllocDescriptor.Reserved));\r
263 } else {\r
264 //\r
265 // No unused(freed) memory allocation HOB found.\r
266 // Build memory allocation HOB normally.\r
267 //\r
268 BuildMemoryAllocationHob (\r
269 BaseAddress,\r
270 Length,\r
271 MemoryType\r
272 );\r
273 }\r
274}\r
275\r
276/**\r
277 Update or split memory allocation HOB for memory pages allocate and free.\r
278\r
279 @param[in, out] MemoryAllocationHob Pointer to the memory allocation HOB\r
280 that needs to be updated or split.\r
281 On output, it will be filled with\r
282 the input Memory, Bytes and MemoryType.\r
283 @param[in] Memory Memory to allocate or free.\r
284 @param[in] Bytes Bytes to allocate or free.\r
285 @param[in] MemoryType EfiConventionalMemory for pages free,\r
286 others for pages allocate.\r
287\r
288**/\r
289VOID\r
290UpdateOrSplitMemoryAllocationHob (\r
291 IN OUT EFI_HOB_MEMORY_ALLOCATION *MemoryAllocationHob,\r
292 IN EFI_PHYSICAL_ADDRESS Memory,\r
293 IN UINT64 Bytes,\r
294 IN EFI_MEMORY_TYPE MemoryType\r
295 )\r
296{\r
297 if ((Memory + Bytes) <\r
298 (MemoryAllocationHob->AllocDescriptor.MemoryBaseAddress + MemoryAllocationHob->AllocDescriptor.MemoryLength)) {\r
299 //\r
300 // Last pages need to be split out.\r
301 //\r
302 InternalBuildMemoryAllocationHob (\r
303 Memory + Bytes,\r
304 (MemoryAllocationHob->AllocDescriptor.MemoryBaseAddress + MemoryAllocationHob->AllocDescriptor.MemoryLength) - (Memory + Bytes),\r
305 MemoryAllocationHob->AllocDescriptor.MemoryType\r
306 );\r
307 }\r
308\r
309 if (Memory > MemoryAllocationHob->AllocDescriptor.MemoryBaseAddress) {\r
310 //\r
311 // First pages need to be split out.\r
312 //\r
313 InternalBuildMemoryAllocationHob (\r
314 MemoryAllocationHob->AllocDescriptor.MemoryBaseAddress,\r
315 Memory - MemoryAllocationHob->AllocDescriptor.MemoryBaseAddress,\r
316 MemoryAllocationHob->AllocDescriptor.MemoryType\r
317 );\r
318 }\r
319\r
320 //\r
321 // Update the memory allocation HOB.\r
322 //\r
323 MemoryAllocationHob->AllocDescriptor.MemoryBaseAddress = Memory;\r
324 MemoryAllocationHob->AllocDescriptor.MemoryLength = Bytes;\r
325 MemoryAllocationHob->AllocDescriptor.MemoryType = MemoryType;\r
326}\r
327\r
328/**\r
329 Merge adjacent free memory ranges in memory allocation HOBs.\r
330\r
331 @retval TRUE There are free memory ranges merged.\r
332 @retval FALSE No free memory ranges merged.\r
333\r
334**/\r
335BOOLEAN\r
336MergeFreeMemoryInMemoryAllocationHob (\r
337 VOID\r
338 )\r
339{\r
340 EFI_PEI_HOB_POINTERS Hob;\r
341 EFI_PEI_HOB_POINTERS Hob2;\r
342 EFI_HOB_MEMORY_ALLOCATION *MemoryHob;\r
343 EFI_HOB_MEMORY_ALLOCATION *MemoryHob2;\r
344 UINT64 Start;\r
345 UINT64 End;\r
346 BOOLEAN Merged;\r
347\r
348 Merged = FALSE;\r
349\r
350 Hob.Raw = GetFirstHob (EFI_HOB_TYPE_MEMORY_ALLOCATION);\r
351 while (Hob.Raw != NULL) {\r
352 if (Hob.MemoryAllocation->AllocDescriptor.MemoryType == EfiConventionalMemory) {\r
353 MemoryHob = (EFI_HOB_MEMORY_ALLOCATION *) Hob.Raw;\r
354 Start = MemoryHob->AllocDescriptor.MemoryBaseAddress;\r
355 End = MemoryHob->AllocDescriptor.MemoryBaseAddress + MemoryHob->AllocDescriptor.MemoryLength;\r
356\r
357 Hob2.Raw = GET_NEXT_HOB (Hob);\r
358 Hob2.Raw = GetNextHob (EFI_HOB_TYPE_MEMORY_ALLOCATION, Hob.Raw);\r
359 while (Hob2.Raw != NULL) {\r
360 if (Hob2.MemoryAllocation->AllocDescriptor.MemoryType == EfiConventionalMemory) {\r
361 MemoryHob2 = (EFI_HOB_MEMORY_ALLOCATION *) Hob2.Raw;\r
362 if (Start == (MemoryHob2->AllocDescriptor.MemoryBaseAddress + MemoryHob2->AllocDescriptor.MemoryLength)) {\r
363 //\r
364 // Merge adjacent two free memory ranges.\r
365 //\r
366 MemoryHob2->AllocDescriptor.MemoryLength += MemoryHob->AllocDescriptor.MemoryLength;\r
367 Merged = TRUE;\r
368 //\r
369 // Mark MemoryHob to be unused(freed).\r
370 //\r
371 MemoryHob->Header.HobType = EFI_HOB_TYPE_UNUSED;\r
372 break;\r
373 } else if (End == MemoryHob2->AllocDescriptor.MemoryBaseAddress) {\r
374 //\r
375 // Merge adjacent two free memory ranges.\r
376 //\r
377 MemoryHob2->AllocDescriptor.MemoryBaseAddress = MemoryHob->AllocDescriptor.MemoryBaseAddress;\r
378 MemoryHob2->AllocDescriptor.MemoryLength += MemoryHob->AllocDescriptor.MemoryLength;\r
379 Merged = TRUE;\r
380 //\r
381 // Mark MemoryHob to be unused(freed).\r
382 //\r
383 MemoryHob->Header.HobType = EFI_HOB_TYPE_UNUSED;\r
384 break;\r
385 }\r
386 }\r
387 Hob2.Raw = GET_NEXT_HOB (Hob2);\r
388 Hob2.Raw = GetNextHob (EFI_HOB_TYPE_MEMORY_ALLOCATION, Hob2.Raw);\r
389 }\r
390 }\r
391 Hob.Raw = GET_NEXT_HOB (Hob);\r
392 Hob.Raw = GetNextHob (EFI_HOB_TYPE_MEMORY_ALLOCATION, Hob.Raw);\r
393 }\r
394\r
395 return Merged;\r
396}\r
397\r
398/**\r
399 Find free memory by searching memory allocation HOBs.\r
400\r
401 @param[in] MemoryType The type of memory to allocate.\r
402 @param[in] Pages The number of contiguous 4 KB pages to allocate.\r
403 @param[in] Granularity Page allocation granularity.\r
404 @param[out] Memory Pointer to a physical address. On output, the address is set to the base\r
405 of the page range that was allocated.\r
406\r
407 @retval EFI_SUCCESS The memory range was successfully allocated.\r
408 @retval EFI_NOT_FOUND No memory allocation HOB with big enough free memory found.\r
409\r
410**/\r
411EFI_STATUS\r
412FindFreeMemoryFromMemoryAllocationHob (\r
413 IN EFI_MEMORY_TYPE MemoryType,\r
414 IN UINTN Pages,\r
415 IN UINTN Granularity,\r
416 OUT EFI_PHYSICAL_ADDRESS *Memory\r
417 )\r
418{\r
419 EFI_PEI_HOB_POINTERS Hob;\r
420 EFI_HOB_MEMORY_ALLOCATION *MemoryAllocationHob;\r
421 UINT64 Bytes;\r
422 EFI_PHYSICAL_ADDRESS BaseAddress;\r
423\r
424 Bytes = LShiftU64 (Pages, EFI_PAGE_SHIFT);\r
425\r
426 BaseAddress = 0;\r
427 MemoryAllocationHob = NULL;\r
428 Hob.Raw = GetFirstHob (EFI_HOB_TYPE_MEMORY_ALLOCATION);\r
429 while (Hob.Raw != NULL) {\r
430 if ((Hob.MemoryAllocation->AllocDescriptor.MemoryType == EfiConventionalMemory) &&\r
431 (Hob.MemoryAllocation->AllocDescriptor.MemoryLength >= Bytes)) {\r
432 //\r
433 // Found one memory allocation HOB with big enough free memory.\r
434 //\r
435 MemoryAllocationHob = (EFI_HOB_MEMORY_ALLOCATION *) Hob.Raw;\r
436 BaseAddress = MemoryAllocationHob->AllocDescriptor.MemoryBaseAddress +\r
437 MemoryAllocationHob->AllocDescriptor.MemoryLength - Bytes;\r
438 //\r
439 // Make sure the granularity could be satisfied.\r
440 //\r
441 BaseAddress &= ~((EFI_PHYSICAL_ADDRESS) Granularity - 1);\r
442 if (BaseAddress >= MemoryAllocationHob->AllocDescriptor.MemoryBaseAddress) {\r
443 break;\r
444 }\r
445 BaseAddress = 0;\r
446 MemoryAllocationHob = NULL;\r
447 }\r
448 //\r
449 // Continue to find.\r
450 //\r
451 Hob.Raw = GET_NEXT_HOB (Hob);\r
452 Hob.Raw = GetNextHob (EFI_HOB_TYPE_MEMORY_ALLOCATION, Hob.Raw);\r
453 }\r
454\r
455 if (MemoryAllocationHob != NULL) {\r
456 UpdateOrSplitMemoryAllocationHob (MemoryAllocationHob, BaseAddress, Bytes, MemoryType);\r
457 *Memory = BaseAddress;\r
458 return EFI_SUCCESS;\r
459 } else {\r
460 if (MergeFreeMemoryInMemoryAllocationHob ()) {\r
461 //\r
462 // Retry if there are free memory ranges merged.\r
463 //\r
464 return FindFreeMemoryFromMemoryAllocationHob (MemoryType, Pages, Granularity, Memory);\r
465 }\r
466 return EFI_NOT_FOUND;\r
467 }\r
468}\r
469\r
470/**\r
471 The purpose of the service is to publish an interface that allows\r
472 PEIMs to allocate memory ranges that are managed by the PEI Foundation.\r
473\r
474 Prior to InstallPeiMemory() being called, PEI will allocate pages from the heap.\r
475 After InstallPeiMemory() is called, PEI will allocate pages within the region\r
476 of memory provided by InstallPeiMemory() service in a best-effort fashion.\r
477 Location-specific allocations are not managed by the PEI foundation code.\r
478\r
479 @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.\r
480 @param MemoryType The type of memory to allocate.\r
481 @param Pages The number of contiguous 4 KB pages to allocate.\r
482 @param Memory Pointer to a physical address. On output, the address is set to the base\r
483 of the page range that was allocated.\r
484\r
485 @retval EFI_SUCCESS The memory range was successfully allocated.\r
486 @retval EFI_OUT_OF_RESOURCES The pages could not be allocated.\r
487 @retval EFI_INVALID_PARAMETER Type is not equal to EfiLoaderCode, EfiLoaderData, EfiRuntimeServicesCode,\r
488 EfiRuntimeServicesData, EfiBootServicesCode, EfiBootServicesData,\r
489 EfiACPIReclaimMemory, EfiReservedMemoryType, or EfiACPIMemoryNVS.\r
490\r
491**/\r
492EFI_STATUS\r
493EFIAPI\r
494PeiAllocatePages (\r
495 IN CONST EFI_PEI_SERVICES **PeiServices,\r
496 IN EFI_MEMORY_TYPE MemoryType,\r
497 IN UINTN Pages,\r
498 OUT EFI_PHYSICAL_ADDRESS *Memory\r
499 )\r
500{\r
501 EFI_STATUS Status;\r
502 PEI_CORE_INSTANCE *PrivateData;\r
503 EFI_PEI_HOB_POINTERS Hob;\r
504 EFI_PHYSICAL_ADDRESS *FreeMemoryTop;\r
505 EFI_PHYSICAL_ADDRESS *FreeMemoryBottom;\r
506 UINTN RemainingPages;\r
507 UINTN Granularity;\r
508 UINTN Padding;\r
509\r
510 if ((MemoryType != EfiLoaderCode) &&\r
511 (MemoryType != EfiLoaderData) &&\r
512 (MemoryType != EfiRuntimeServicesCode) &&\r
513 (MemoryType != EfiRuntimeServicesData) &&\r
514 (MemoryType != EfiBootServicesCode) &&\r
515 (MemoryType != EfiBootServicesData) &&\r
516 (MemoryType != EfiACPIReclaimMemory) &&\r
517 (MemoryType != EfiReservedMemoryType) &&\r
518 (MemoryType != EfiACPIMemoryNVS)) {\r
519 return EFI_INVALID_PARAMETER;\r
520 }\r
521\r
522 Granularity = DEFAULT_PAGE_ALLOCATION_GRANULARITY;\r
523\r
524 PrivateData = PEI_CORE_INSTANCE_FROM_PS_THIS (PeiServices);\r
525 Hob.Raw = PrivateData->HobList.Raw;\r
526\r
527 if (Hob.Raw == NULL) {\r
528 //\r
529 // HOB is not initialized yet.\r
530 //\r
531 return EFI_NOT_AVAILABLE_YET;\r
532 }\r
533\r
534 if (RUNTIME_PAGE_ALLOCATION_GRANULARITY > DEFAULT_PAGE_ALLOCATION_GRANULARITY &&\r
535 (MemoryType == EfiACPIReclaimMemory ||\r
536 MemoryType == EfiACPIMemoryNVS ||\r
537 MemoryType == EfiRuntimeServicesCode ||\r
538 MemoryType == EfiRuntimeServicesData)) {\r
539\r
540 Granularity = RUNTIME_PAGE_ALLOCATION_GRANULARITY;\r
541\r
542 DEBUG ((DEBUG_INFO, "AllocatePages: aligning allocation to %d KB\n",\r
543 Granularity / SIZE_1KB));\r
544 }\r
545\r
546 if (!PrivateData->PeiMemoryInstalled && PrivateData->SwitchStackSignal) {\r
547 //\r
548 // When PeiInstallMemory is called but temporary memory has *not* been moved to permanent memory,\r
549 // the AllocatePage will depend on the field of PEI_CORE_INSTANCE structure.\r
550 //\r
551 FreeMemoryTop = &(PrivateData->FreePhysicalMemoryTop);\r
552 FreeMemoryBottom = &(PrivateData->PhysicalMemoryBegin);\r
553 } else {\r
554 FreeMemoryTop = &(Hob.HandoffInformationTable->EfiFreeMemoryTop);\r
555 FreeMemoryBottom = &(Hob.HandoffInformationTable->EfiFreeMemoryBottom);\r
556 }\r
557\r
558 //\r
559 // Check to see if on correct boundary for the memory type.\r
560 // If not aligned, make the allocation aligned.\r
561 //\r
562 Padding = *(FreeMemoryTop) & (Granularity - 1);\r
563 if ((UINTN) (*FreeMemoryTop - *FreeMemoryBottom) < Padding) {\r
564 DEBUG ((DEBUG_ERROR, "AllocatePages failed: Out of space after padding.\n"));\r
565 return EFI_OUT_OF_RESOURCES;\r
566 }\r
567\r
568 *(FreeMemoryTop) -= Padding;\r
569 if (Padding >= EFI_PAGE_SIZE) {\r
570 //\r
571 // Create a memory allocation HOB to cover\r
572 // the pages that we will lose to rounding\r
573 //\r
574 InternalBuildMemoryAllocationHob (\r
575 *(FreeMemoryTop),\r
576 Padding & ~(UINTN)EFI_PAGE_MASK,\r
577 EfiConventionalMemory\r
578 );\r
579 }\r
580\r
581 //\r
582 // Verify that there is sufficient memory to satisfy the allocation.\r
583 //\r
584 RemainingPages = (UINTN)(*FreeMemoryTop - *FreeMemoryBottom) >> EFI_PAGE_SHIFT;\r
585 //\r
586 // The number of remaining pages needs to be greater than or equal to that of the request pages.\r
587 //\r
588 Pages = ALIGN_VALUE (Pages, EFI_SIZE_TO_PAGES (Granularity));\r
589 if (RemainingPages < Pages) {\r
590 //\r
591 // Try to find free memory by searching memory allocation HOBs.\r
592 //\r
593 Status = FindFreeMemoryFromMemoryAllocationHob (MemoryType, Pages, Granularity, Memory);\r
594 if (!EFI_ERROR (Status)) {\r
595 return Status;\r
596 }\r
597 DEBUG ((EFI_D_ERROR, "AllocatePages failed: No 0x%lx Pages is available.\n", (UINT64) Pages));\r
598 DEBUG ((EFI_D_ERROR, "There is only left 0x%lx pages memory resource to be allocated.\n", (UINT64) RemainingPages));\r
599 return EFI_OUT_OF_RESOURCES;\r
600 } else {\r
601 //\r
602 // Update the PHIT to reflect the memory usage\r
603 //\r
604 *(FreeMemoryTop) -= Pages * EFI_PAGE_SIZE;\r
605\r
606 //\r
607 // Update the value for the caller\r
608 //\r
609 *Memory = *(FreeMemoryTop);\r
610\r
611 //\r
612 // Create a memory allocation HOB.\r
613 //\r
614 InternalBuildMemoryAllocationHob (\r
615 *(FreeMemoryTop),\r
616 Pages * EFI_PAGE_SIZE,\r
617 MemoryType\r
618 );\r
619\r
620 return EFI_SUCCESS;\r
621 }\r
622}\r
623\r
624/**\r
625 Mark the memory allocation HOB to be unused(freed) and update *FreeMemoryTop\r
626 if MemoryBaseAddress == *FreeMemoryTop.\r
627\r
628 @param[in] PrivateData Pointer to PeiCore's private data structure.\r
629 @param[in, out] MemoryAllocationHobToFree Pointer to memory allocation HOB to be freed.\r
630\r
631**/\r
632VOID\r
633FreeMemoryAllocationHob (\r
634 IN PEI_CORE_INSTANCE *PrivateData,\r
635 IN OUT EFI_HOB_MEMORY_ALLOCATION *MemoryAllocationHobToFree\r
636 )\r
637{\r
638 EFI_PEI_HOB_POINTERS Hob;\r
639 EFI_PHYSICAL_ADDRESS *FreeMemoryTop;\r
640 EFI_HOB_MEMORY_ALLOCATION *MemoryAllocationHob;\r
641\r
642 Hob.Raw = PrivateData->HobList.Raw;\r
643\r
644 if (!PrivateData->PeiMemoryInstalled && PrivateData->SwitchStackSignal) {\r
645 //\r
646 // When PeiInstallMemory is called but temporary memory has *not* been moved to permanent memory,\r
647 // use the FreePhysicalMemoryTop field of PEI_CORE_INSTANCE structure.\r
648 //\r
649 FreeMemoryTop = &(PrivateData->FreePhysicalMemoryTop);\r
650 } else {\r
651 FreeMemoryTop = &(Hob.HandoffInformationTable->EfiFreeMemoryTop);\r
652 }\r
653\r
654 if (MemoryAllocationHobToFree->AllocDescriptor.MemoryBaseAddress == *FreeMemoryTop) {\r
655 //\r
656 // Update *FreeMemoryTop.\r
657 //\r
658 *FreeMemoryTop += MemoryAllocationHobToFree->AllocDescriptor.MemoryLength;\r
659 //\r
660 // Mark the memory allocation HOB to be unused(freed).\r
661 //\r
662 MemoryAllocationHobToFree->Header.HobType = EFI_HOB_TYPE_UNUSED;\r
663\r
664 MemoryAllocationHob = NULL;\r
665 Hob.Raw = GetFirstHob (EFI_HOB_TYPE_MEMORY_ALLOCATION);\r
666 while (Hob.Raw != NULL) {\r
667 if ((Hob.MemoryAllocation->AllocDescriptor.MemoryType == EfiConventionalMemory) &&\r
668 (Hob.MemoryAllocation->AllocDescriptor.MemoryBaseAddress == *FreeMemoryTop)) {\r
669 //\r
670 // Found memory allocation HOB that has EfiConventionalMemory MemoryType and\r
671 // MemoryBaseAddress == new *FreeMemoryTop.\r
672 //\r
673 MemoryAllocationHob = (EFI_HOB_MEMORY_ALLOCATION *) Hob.Raw;\r
674 break;\r
675 }\r
676 Hob.Raw = GET_NEXT_HOB (Hob);\r
677 Hob.Raw = GetNextHob (EFI_HOB_TYPE_MEMORY_ALLOCATION, Hob.Raw);\r
678 }\r
679 //\r
680 // Free memory allocation HOB iteratively.\r
681 //\r
682 if (MemoryAllocationHob != NULL) {\r
683 FreeMemoryAllocationHob (PrivateData, MemoryAllocationHob);\r
684 }\r
685 }\r
686}\r
687\r
688/**\r
689 Frees memory pages.\r
690\r
691 @param[in] PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.\r
692 @param[in] Memory The base physical address of the pages to be freed.\r
693 @param[in] Pages The number of contiguous 4 KB pages to free.\r
694\r
695 @retval EFI_SUCCESS The requested pages were freed.\r
696 @retval EFI_INVALID_PARAMETER Memory is not a page-aligned address or Pages is invalid.\r
697 @retval EFI_NOT_FOUND The requested memory pages were not allocated with\r
698 AllocatePages().\r
699\r
700**/\r
701EFI_STATUS\r
702EFIAPI\r
703PeiFreePages (\r
704 IN CONST EFI_PEI_SERVICES **PeiServices,\r
705 IN EFI_PHYSICAL_ADDRESS Memory,\r
706 IN UINTN Pages\r
707 )\r
708{\r
709 PEI_CORE_INSTANCE *PrivateData;\r
710 UINT64 Bytes;\r
711 UINT64 Start;\r
712 UINT64 End;\r
713 EFI_PEI_HOB_POINTERS Hob;\r
714 EFI_HOB_MEMORY_ALLOCATION *MemoryAllocationHob;\r
715\r
716 Bytes = LShiftU64 (Pages, EFI_PAGE_SHIFT);\r
717 Start = Memory;\r
718 End = Start + Bytes - 1;\r
719\r
720 if (Pages == 0 || ((Start & EFI_PAGE_MASK) != 0) || (Start >= End)) {\r
721 return EFI_INVALID_PARAMETER;\r
722 }\r
723\r
724 PrivateData = PEI_CORE_INSTANCE_FROM_PS_THIS (PeiServices);\r
725 Hob.Raw = PrivateData->HobList.Raw;\r
726\r
727 if (Hob.Raw == NULL) {\r
728 //\r
729 // HOB is not initialized yet.\r
730 //\r
731 return EFI_NOT_AVAILABLE_YET;\r
732 }\r
733\r
734 MemoryAllocationHob = NULL;\r
735 Hob.Raw = GetFirstHob (EFI_HOB_TYPE_MEMORY_ALLOCATION);\r
736 while (Hob.Raw != NULL) {\r
737 if ((Hob.MemoryAllocation->AllocDescriptor.MemoryType != EfiConventionalMemory) &&\r
738 (Memory >= Hob.MemoryAllocation->AllocDescriptor.MemoryBaseAddress) &&\r
739 ((Memory + Bytes) <= (Hob.MemoryAllocation->AllocDescriptor.MemoryBaseAddress + Hob.MemoryAllocation->AllocDescriptor.MemoryLength))) {\r
740 //\r
741 // Found the memory allocation HOB that includes the memory pages to be freed.\r
742 //\r
743 MemoryAllocationHob = (EFI_HOB_MEMORY_ALLOCATION *) Hob.Raw;\r
744 break;\r
745 }\r
746 Hob.Raw = GET_NEXT_HOB (Hob);\r
747 Hob.Raw = GetNextHob (EFI_HOB_TYPE_MEMORY_ALLOCATION, Hob.Raw);\r
748 }\r
749\r
750 if (MemoryAllocationHob != NULL) {\r
751 UpdateOrSplitMemoryAllocationHob (MemoryAllocationHob, Memory, Bytes, EfiConventionalMemory);\r
752 FreeMemoryAllocationHob (PrivateData, MemoryAllocationHob);\r
753 return EFI_SUCCESS;\r
754 } else {\r
755 return EFI_NOT_FOUND;\r
756 }\r
757}\r
758\r
759/**\r
760\r
761 Pool allocation service. Before permanent memory is discovered, the pool will\r
762 be allocated the heap in the temporary memory. Generally, the size of heap in temporary\r
763 memory does not exceed to 64K, so the biggest pool size could be allocated is\r
764 64K.\r
765\r
766 @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.\r
767 @param Size Amount of memory required\r
768 @param Buffer Address of pointer to the buffer\r
769\r
770 @retval EFI_SUCCESS The allocation was successful\r
771 @retval EFI_OUT_OF_RESOURCES There is not enough heap to satisfy the requirement\r
772 to allocate the requested size.\r
773\r
774**/\r
775EFI_STATUS\r
776EFIAPI\r
777PeiAllocatePool (\r
778 IN CONST EFI_PEI_SERVICES **PeiServices,\r
779 IN UINTN Size,\r
780 OUT VOID **Buffer\r
781 )\r
782{\r
783 EFI_STATUS Status;\r
784 EFI_HOB_MEMORY_POOL *Hob;\r
785\r
786 //\r
787 // If some "post-memory" PEIM wishes to allocate larger pool,\r
788 // it should use AllocatePages service instead.\r
789 //\r
790\r
791 //\r
792 // Generally, the size of heap in temporary memory does not exceed to 64K,\r
793 // HobLength is multiples of 8 bytes, so the maximum size of pool is 0xFFF8 - sizeof (EFI_HOB_MEMORY_POOL)\r
794 //\r
795 if (Size > (0xFFF8 - sizeof (EFI_HOB_MEMORY_POOL))) {\r
796 return EFI_OUT_OF_RESOURCES;\r
797 }\r
798\r
799 Status = PeiServicesCreateHob (\r
800 EFI_HOB_TYPE_MEMORY_POOL,\r
801 (UINT16)(sizeof (EFI_HOB_MEMORY_POOL) + Size),\r
802 (VOID **)&Hob\r
803 );\r
804 ASSERT_EFI_ERROR (Status);\r
805\r
806 if (EFI_ERROR (Status)) {\r
807 *Buffer = NULL;\r
808 } else {\r
809 *Buffer = Hob + 1;\r
810 }\r
811\r
812 return Status;\r
813}\r