]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Core/Pei/Memory/MemoryServices.c
MdeModulePkg PeiCore: Fix typos
[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
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
64ca6802 472 PEIMs to allocate memory ranges that are managed by the PEI Foundation.\r
b1f6a7c6 473\r
b2374cec
SZ
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
64ca6802 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
b2374cec 482 @param Memory Pointer to a physical address. On output, the address is set to the base\r
64ca6802 483 of the page range that was allocated.\r
b1f6a7c6 484\r
64ca6802 485 @retval EFI_SUCCESS The memory range was successfully allocated.\r
486 @retval EFI_OUT_OF_RESOURCES The pages could not be allocated.\r
b2374cec 487 @retval EFI_INVALID_PARAMETER Type is not equal to EfiLoaderCode, EfiLoaderData, EfiRuntimeServicesCode,\r
64ca6802 488 EfiRuntimeServicesData, EfiBootServicesCode, EfiBootServicesData,\r
ab6fb25a 489 EfiACPIReclaimMemory, EfiReservedMemoryType, or EfiACPIMemoryNVS.\r
b1f6a7c6 490\r
491**/\r
192f6d4c 492EFI_STATUS\r
493EFIAPI\r
494PeiAllocatePages (\r
82b8c8df 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
192f6d4c 499 )\r
192f6d4c 500{\r
b2374cec 501 EFI_STATUS Status;\r
192f6d4c 502 PEI_CORE_INSTANCE *PrivateData;\r
503 EFI_PEI_HOB_POINTERS Hob;\r
58dcdada 504 EFI_PHYSICAL_ADDRESS *FreeMemoryTop;\r
505 EFI_PHYSICAL_ADDRESS *FreeMemoryBottom;\r
62031991 506 UINTN RemainingPages;\r
e1e7e0fb
AB
507 UINTN Granularity;\r
508 UINTN Padding;\r
192f6d4c 509\r
64ca6802 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
ab6fb25a 517 (MemoryType != EfiReservedMemoryType) &&\r
64ca6802 518 (MemoryType != EfiACPIMemoryNVS)) {\r
519 return EFI_INVALID_PARAMETER;\r
520 }\r
521\r
e1e7e0fb
AB
522 Granularity = DEFAULT_PAGE_ALLOCATION_GRANULARITY;\r
523\r
b2374cec
SZ
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
e1e7e0fb
AB
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
b2374cec 546 if (!PrivateData->PeiMemoryInstalled && PrivateData->SwitchStackSignal) {\r
58dcdada 547 //\r
b2374cec 548 // When PeiInstallMemory is called but temporary memory has *not* been moved to permanent memory,\r
5f300691 549 // the AllocatePage will depend on the field of PEI_CORE_INSTANCE structure.\r
58dcdada 550 //\r
b2374cec
SZ
551 FreeMemoryTop = &(PrivateData->FreePhysicalMemoryTop);\r
552 FreeMemoryBottom = &(PrivateData->PhysicalMemoryBegin);\r
58dcdada 553 } else {\r
554 FreeMemoryTop = &(Hob.HandoffInformationTable->EfiFreeMemoryTop);\r
555 FreeMemoryBottom = &(Hob.HandoffInformationTable->EfiFreeMemoryBottom);\r
192f6d4c 556 }\r
557\r
192f6d4c 558 //\r
e1e7e0fb
AB
559 // Check to see if on correct boundary for the memory type.\r
560 // If not aligned, make the allocation aligned.\r
192f6d4c 561 //\r
e1e7e0fb
AB
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
b2374cec 574 InternalBuildMemoryAllocationHob (\r
e1e7e0fb
AB
575 *(FreeMemoryTop),\r
576 Padding & ~(UINTN)EFI_PAGE_MASK,\r
577 EfiConventionalMemory\r
578 );\r
579 }\r
5e574a01 580\r
192f6d4c 581 //\r
5e574a01 582 // Verify that there is sufficient memory to satisfy the allocation.\r
192f6d4c 583 //\r
b2374cec 584 RemainingPages = (UINTN)(*FreeMemoryTop - *FreeMemoryBottom) >> EFI_PAGE_SHIFT;\r
98a601b1 585 //\r
5e574a01 586 // The number of remaining pages needs to be greater than or equal to that of the request pages.\r
98a601b1 587 //\r
e1e7e0fb 588 Pages = ALIGN_VALUE (Pages, EFI_SIZE_TO_PAGES (Granularity));\r
5e574a01 589 if (RemainingPages < Pages) {\r
b2374cec
SZ
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
62031991 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
192f6d4c 599 return EFI_OUT_OF_RESOURCES;\r
600 } else {\r
601 //\r
602 // Update the PHIT to reflect the memory usage\r
603 //\r
58dcdada 604 *(FreeMemoryTop) -= Pages * EFI_PAGE_SIZE;\r
192f6d4c 605\r
606 //\r
607 // Update the value for the caller\r
608 //\r
58dcdada 609 *Memory = *(FreeMemoryTop);\r
192f6d4c 610\r
611 //\r
612 // Create a memory allocation HOB.\r
613 //\r
b2374cec 614 InternalBuildMemoryAllocationHob (\r
58dcdada 615 *(FreeMemoryTop),\r
0a7d0741 616 Pages * EFI_PAGE_SIZE,\r
192f6d4c 617 MemoryType\r
618 );\r
619\r
620 return EFI_SUCCESS;\r
621 }\r
622}\r
623\r
b2374cec
SZ
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
b1f6a7c6 759/**\r
760\r
d39d1260
MK
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
d1102dba 763 memory does not exceed to 64K, so the biggest pool size could be allocated is\r
82b8c8df 764 64K.\r
b1f6a7c6 765\r
82b8c8df 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
b1f6a7c6 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
192f6d4c 775EFI_STATUS\r
776EFIAPI\r
777PeiAllocatePool (\r
82b8c8df 778 IN CONST EFI_PEI_SERVICES **PeiServices,\r
779 IN UINTN Size,\r
780 OUT VOID **Buffer\r
192f6d4c 781 )\r
192f6d4c 782{\r
783 EFI_STATUS Status;\r
784 EFI_HOB_MEMORY_POOL *Hob;\r
785\r
82b8c8df 786 //\r
787 // If some "post-memory" PEIM wishes to allocate larger pool,\r
788 // it should use AllocatePages service instead.\r
789 //\r
d1102dba 790\r
82b8c8df 791 //\r
792 // Generally, the size of heap in temporary memory does not exceed to 64K,\r
d39d1260 793 // HobLength is multiples of 8 bytes, so the maximum size of pool is 0xFFF8 - sizeof (EFI_HOB_MEMORY_POOL)\r
82b8c8df 794 //\r
e94728b3 795 if (Size > (0xFFF8 - sizeof (EFI_HOB_MEMORY_POOL))) {\r
2e76dc7e 796 return EFI_OUT_OF_RESOURCES;\r
797 }\r
d1102dba 798\r
82b8c8df 799 Status = PeiServicesCreateHob (\r
192f6d4c 800 EFI_HOB_TYPE_MEMORY_POOL,\r
801 (UINT16)(sizeof (EFI_HOB_MEMORY_POOL) + Size),\r
802 (VOID **)&Hob\r
803 );\r
772cba09 804 ASSERT_EFI_ERROR (Status);\r
8797683f
BB
805\r
806 if (EFI_ERROR (Status)) {\r
807 *Buffer = NULL;\r
808 } else {\r
809 *Buffer = Hob + 1;\r
810 }\r
192f6d4c 811\r
192f6d4c 812 return Status;\r
813}\r