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