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