]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - MdeModulePkg/Core/Pei/Dispatcher/Dispatcher.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / MdeModulePkg / Core / Pei / Dispatcher / Dispatcher.c
... / ...
CommitLineData
1/** @file\r
2 EFI PEI Core dispatch services\r
3\r
4Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>\r
5(C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>\r
6SPDX-License-Identifier: BSD-2-Clause-Patent\r
7\r
8**/\r
9\r
10#include "PeiMain.h"\r
11\r
12/**\r
13\r
14 Discover all PEIMs and optional Apriori file in one FV. There is at most one\r
15 Apriori file in one FV.\r
16\r
17\r
18 @param Private Pointer to the private data passed in from caller\r
19 @param CoreFileHandle The instance of PEI_CORE_FV_HANDLE.\r
20\r
21**/\r
22VOID\r
23DiscoverPeimsAndOrderWithApriori (\r
24 IN PEI_CORE_INSTANCE *Private,\r
25 IN PEI_CORE_FV_HANDLE *CoreFileHandle\r
26 )\r
27{\r
28 EFI_STATUS Status;\r
29 EFI_PEI_FILE_HANDLE FileHandle;\r
30 EFI_PEI_FILE_HANDLE AprioriFileHandle;\r
31 EFI_GUID *Apriori;\r
32 UINTN Index;\r
33 UINTN Index2;\r
34 UINTN PeimIndex;\r
35 UINTN PeimCount;\r
36 EFI_GUID *Guid;\r
37 EFI_PEI_FILE_HANDLE *TempFileHandles;\r
38 EFI_GUID *TempFileGuid;\r
39 EFI_PEI_FIRMWARE_VOLUME_PPI *FvPpi;\r
40 EFI_FV_FILE_INFO FileInfo;\r
41\r
42 FvPpi = CoreFileHandle->FvPpi;\r
43\r
44 //\r
45 // Walk the FV and find all the PEIMs and the Apriori file.\r
46 //\r
47 AprioriFileHandle = NULL;\r
48 Private->CurrentFvFileHandles = NULL;\r
49 Guid = NULL;\r
50\r
51 //\r
52 // If the current FV has been scanned, directly get its cached records.\r
53 //\r
54 if (CoreFileHandle->ScanFv) {\r
55 Private->CurrentFvFileHandles = CoreFileHandle->FvFileHandles;\r
56 return;\r
57 }\r
58\r
59 TempFileHandles = Private->TempFileHandles;\r
60 TempFileGuid = Private->TempFileGuid;\r
61\r
62 //\r
63 // Go ahead to scan this FV, get PeimCount and cache FileHandles within it to TempFileHandles.\r
64 //\r
65 PeimCount = 0;\r
66 FileHandle = NULL;\r
67 do {\r
68 Status = FvPpi->FindFileByType (FvPpi, PEI_CORE_INTERNAL_FFS_FILE_DISPATCH_TYPE, CoreFileHandle->FvHandle, &FileHandle);\r
69 if (!EFI_ERROR (Status)) {\r
70 if (PeimCount >= Private->TempPeimCount) {\r
71 //\r
72 // Run out of room, grow the buffer.\r
73 //\r
74 TempFileHandles = AllocatePool (\r
75 sizeof (EFI_PEI_FILE_HANDLE) * (Private->TempPeimCount + TEMP_FILE_GROWTH_STEP)\r
76 );\r
77 ASSERT (TempFileHandles != NULL);\r
78 CopyMem (\r
79 TempFileHandles,\r
80 Private->TempFileHandles,\r
81 sizeof (EFI_PEI_FILE_HANDLE) * Private->TempPeimCount\r
82 );\r
83 Private->TempFileHandles = TempFileHandles;\r
84 TempFileGuid = AllocatePool (\r
85 sizeof (EFI_GUID) * (Private->TempPeimCount + TEMP_FILE_GROWTH_STEP)\r
86 );\r
87 ASSERT (TempFileGuid != NULL);\r
88 CopyMem (\r
89 TempFileGuid,\r
90 Private->TempFileGuid,\r
91 sizeof (EFI_GUID) * Private->TempPeimCount\r
92 );\r
93 Private->TempFileGuid = TempFileGuid;\r
94 Private->TempPeimCount = Private->TempPeimCount + TEMP_FILE_GROWTH_STEP;\r
95 }\r
96\r
97 TempFileHandles[PeimCount++] = FileHandle;\r
98 }\r
99 } while (!EFI_ERROR (Status));\r
100\r
101 DEBUG ((\r
102 DEBUG_INFO,\r
103 "%a(): Found 0x%x PEI FFS files in the %dth FV\n",\r
104 __FUNCTION__,\r
105 PeimCount,\r
106 Private->CurrentPeimFvCount\r
107 ));\r
108\r
109 if (PeimCount == 0) {\r
110 //\r
111 // No PEIM FFS file is found, set ScanFv flag and return.\r
112 //\r
113 CoreFileHandle->ScanFv = TRUE;\r
114 return;\r
115 }\r
116\r
117 //\r
118 // Record PeimCount, allocate buffer for PeimState and FvFileHandles.\r
119 //\r
120 CoreFileHandle->PeimCount = PeimCount;\r
121 CoreFileHandle->PeimState = AllocateZeroPool (sizeof (UINT8) * PeimCount);\r
122 ASSERT (CoreFileHandle->PeimState != NULL);\r
123 CoreFileHandle->FvFileHandles = AllocateZeroPool (sizeof (EFI_PEI_FILE_HANDLE) * PeimCount);\r
124 ASSERT (CoreFileHandle->FvFileHandles != NULL);\r
125\r
126 //\r
127 // Get Apriori File handle\r
128 //\r
129 Private->AprioriCount = 0;\r
130 Status = FvPpi->FindFileByName (FvPpi, &gPeiAprioriFileNameGuid, &CoreFileHandle->FvHandle, &AprioriFileHandle);\r
131 if (!EFI_ERROR (Status) && (AprioriFileHandle != NULL)) {\r
132 //\r
133 // Read the Apriori file\r
134 //\r
135 Status = FvPpi->FindSectionByType (FvPpi, EFI_SECTION_RAW, AprioriFileHandle, (VOID **)&Apriori);\r
136 if (!EFI_ERROR (Status)) {\r
137 //\r
138 // Calculate the number of PEIMs in the Apriori file\r
139 //\r
140 Status = FvPpi->GetFileInfo (FvPpi, AprioriFileHandle, &FileInfo);\r
141 ASSERT_EFI_ERROR (Status);\r
142 Private->AprioriCount = FileInfo.BufferSize;\r
143 if (IS_SECTION2 (FileInfo.Buffer)) {\r
144 Private->AprioriCount -= sizeof (EFI_COMMON_SECTION_HEADER2);\r
145 } else {\r
146 Private->AprioriCount -= sizeof (EFI_COMMON_SECTION_HEADER);\r
147 }\r
148\r
149 Private->AprioriCount /= sizeof (EFI_GUID);\r
150\r
151 for (Index = 0; Index < PeimCount; Index++) {\r
152 //\r
153 // Make an array of file name GUIDs that matches the FileHandle array so we can convert\r
154 // quickly from file name to file handle\r
155 //\r
156 Status = FvPpi->GetFileInfo (FvPpi, TempFileHandles[Index], &FileInfo);\r
157 ASSERT_EFI_ERROR (Status);\r
158 CopyMem (&TempFileGuid[Index], &FileInfo.FileName, sizeof (EFI_GUID));\r
159 }\r
160\r
161 //\r
162 // Walk through TempFileGuid array to find out who is invalid PEIM GUID in Apriori file.\r
163 // Add available PEIMs in Apriori file into FvFileHandles array.\r
164 //\r
165 Index = 0;\r
166 for (Index2 = 0; Index2 < Private->AprioriCount; Index2++) {\r
167 Guid = ScanGuid (TempFileGuid, PeimCount * sizeof (EFI_GUID), &Apriori[Index2]);\r
168 if (Guid != NULL) {\r
169 PeimIndex = ((UINTN)Guid - (UINTN)&TempFileGuid[0])/sizeof (EFI_GUID);\r
170 CoreFileHandle->FvFileHandles[Index++] = TempFileHandles[PeimIndex];\r
171\r
172 //\r
173 // Since we have copied the file handle we can remove it from this list.\r
174 //\r
175 TempFileHandles[PeimIndex] = NULL;\r
176 }\r
177 }\r
178\r
179 //\r
180 // Update valid AprioriCount\r
181 //\r
182 Private->AprioriCount = Index;\r
183\r
184 //\r
185 // Add in any PEIMs not in the Apriori file\r
186 //\r
187 for (Index2 = 0; Index2 < PeimCount; Index2++) {\r
188 if (TempFileHandles[Index2] != NULL) {\r
189 CoreFileHandle->FvFileHandles[Index++] = TempFileHandles[Index2];\r
190 TempFileHandles[Index2] = NULL;\r
191 }\r
192 }\r
193\r
194 ASSERT (Index == PeimCount);\r
195 }\r
196 } else {\r
197 CopyMem (CoreFileHandle->FvFileHandles, TempFileHandles, sizeof (EFI_PEI_FILE_HANDLE) * PeimCount);\r
198 }\r
199\r
200 //\r
201 // The current FV File Handles have been cached. So that we don't have to scan the FV again.\r
202 // Instead, we can retrieve the file handles within this FV from cached records.\r
203 //\r
204 CoreFileHandle->ScanFv = TRUE;\r
205 Private->CurrentFvFileHandles = CoreFileHandle->FvFileHandles;\r
206}\r
207\r
208//\r
209// This is the minimum memory required by DxeCore initialization. When LMFA feature enabled,\r
210// This part of memory still need reserved on the very top of memory so that the DXE Core could\r
211// use these memory for data initialization. This macro should be sync with the same marco\r
212// defined in DXE Core.\r
213//\r
214#define MINIMUM_INITIAL_MEMORY_SIZE 0x10000\r
215\r
216/**\r
217 This function is to test if the memory range described in resource HOB is available or not.\r
218\r
219 This function should only be invoked when Loading Module at Fixed Address(LMFA) feature is enabled. Some platform may allocate the\r
220 memory before PeiLoadFixAddressHook in invoked. so this function is to test if the memory range described by the input resource HOB is\r
221 available or not.\r
222\r
223 @param PrivateData Pointer to the private data passed in from caller\r
224 @param ResourceHob Pointer to a resource HOB which described the memory range described by the input resource HOB\r
225**/\r
226BOOLEAN\r
227PeiLoadFixAddressIsMemoryRangeAvailable (\r
228 IN PEI_CORE_INSTANCE *PrivateData,\r
229 IN EFI_HOB_RESOURCE_DESCRIPTOR *ResourceHob\r
230 )\r
231{\r
232 EFI_HOB_MEMORY_ALLOCATION *MemoryHob;\r
233 BOOLEAN IsAvailable;\r
234 EFI_PEI_HOB_POINTERS Hob;\r
235\r
236 IsAvailable = TRUE;\r
237 if ((PrivateData == NULL) || (ResourceHob == NULL)) {\r
238 return FALSE;\r
239 }\r
240\r
241 //\r
242 // test if the memory range describe in the HOB is already allocated.\r
243 //\r
244 for (Hob.Raw = PrivateData->HobList.Raw; !END_OF_HOB_LIST (Hob); Hob.Raw = GET_NEXT_HOB (Hob)) {\r
245 //\r
246 // See if this is a memory allocation HOB\r
247 //\r
248 if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_MEMORY_ALLOCATION) {\r
249 MemoryHob = Hob.MemoryAllocation;\r
250 if ((MemoryHob->AllocDescriptor.MemoryBaseAddress == ResourceHob->PhysicalStart) &&\r
251 (MemoryHob->AllocDescriptor.MemoryBaseAddress + MemoryHob->AllocDescriptor.MemoryLength == ResourceHob->PhysicalStart + ResourceHob->ResourceLength))\r
252 {\r
253 IsAvailable = FALSE;\r
254 break;\r
255 }\r
256 }\r
257 }\r
258\r
259 return IsAvailable;\r
260}\r
261\r
262/**\r
263 Hook function for Loading Module at Fixed Address feature\r
264\r
265 This function should only be invoked when Loading Module at Fixed Address(LMFA) feature is enabled. When feature is\r
266 configured as Load Modules at Fix Absolute Address, this function is to validate the top address assigned by user. When\r
267 feature is configured as Load Modules at Fixed Offset, the function is to find the top address which is TOLM-TSEG in general.\r
268 And also the function will re-install PEI memory.\r
269\r
270 @param PrivateData Pointer to the private data passed in from caller\r
271\r
272**/\r
273VOID\r
274PeiLoadFixAddressHook (\r
275 IN PEI_CORE_INSTANCE *PrivateData\r
276 )\r
277{\r
278 EFI_PHYSICAL_ADDRESS TopLoadingAddress;\r
279 UINT64 PeiMemorySize;\r
280 UINT64 TotalReservedMemorySize;\r
281 UINT64 MemoryRangeEnd;\r
282 EFI_PHYSICAL_ADDRESS HighAddress;\r
283 EFI_HOB_RESOURCE_DESCRIPTOR *ResourceHob;\r
284 EFI_HOB_RESOURCE_DESCRIPTOR *NextResourceHob;\r
285 EFI_HOB_RESOURCE_DESCRIPTOR *CurrentResourceHob;\r
286 EFI_PEI_HOB_POINTERS CurrentHob;\r
287 EFI_PEI_HOB_POINTERS Hob;\r
288 EFI_PEI_HOB_POINTERS NextHob;\r
289 EFI_HOB_MEMORY_ALLOCATION *MemoryHob;\r
290\r
291 //\r
292 // Initialize Local Variables\r
293 //\r
294 CurrentResourceHob = NULL;\r
295 ResourceHob = NULL;\r
296 NextResourceHob = NULL;\r
297 HighAddress = 0;\r
298 TopLoadingAddress = 0;\r
299 MemoryRangeEnd = 0;\r
300 CurrentHob.Raw = PrivateData->HobList.Raw;\r
301 PeiMemorySize = PrivateData->PhysicalMemoryLength;\r
302 //\r
303 // The top reserved memory include 3 parts: the topest range is for DXE core initialization with the size MINIMUM_INITIAL_MEMORY_SIZE\r
304 // then RuntimeCodePage range and Boot time code range.\r
305 //\r
306 TotalReservedMemorySize = MINIMUM_INITIAL_MEMORY_SIZE + EFI_PAGES_TO_SIZE (PcdGet32 (PcdLoadFixAddressRuntimeCodePageNumber));\r
307 TotalReservedMemorySize += EFI_PAGES_TO_SIZE (PcdGet32 (PcdLoadFixAddressBootTimeCodePageNumber));\r
308 //\r
309 // PEI memory range lies below the top reserved memory\r
310 //\r
311 TotalReservedMemorySize += PeiMemorySize;\r
312\r
313 DEBUG ((DEBUG_INFO, "LOADING MODULE FIXED INFO: PcdLoadFixAddressRuntimeCodePageNumber= 0x%x.\n", PcdGet32 (PcdLoadFixAddressRuntimeCodePageNumber)));\r
314 DEBUG ((DEBUG_INFO, "LOADING MODULE FIXED INFO: PcdLoadFixAddressBootTimeCodePageNumber= 0x%x.\n", PcdGet32 (PcdLoadFixAddressBootTimeCodePageNumber)));\r
315 DEBUG ((DEBUG_INFO, "LOADING MODULE FIXED INFO: PcdLoadFixAddressPeiCodePageNumber= 0x%x.\n", PcdGet32 (PcdLoadFixAddressPeiCodePageNumber)));\r
316 DEBUG ((DEBUG_INFO, "LOADING MODULE FIXED INFO: Total Reserved Memory Size = 0x%lx.\n", TotalReservedMemorySize));\r
317 //\r
318 // Loop through the system memory typed HOB to merge the adjacent memory range\r
319 //\r
320 for (Hob.Raw = PrivateData->HobList.Raw; !END_OF_HOB_LIST (Hob); Hob.Raw = GET_NEXT_HOB (Hob)) {\r
321 //\r
322 // See if this is a resource descriptor HOB\r
323 //\r
324 if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {\r
325 ResourceHob = Hob.ResourceDescriptor;\r
326 //\r
327 // If range described in this HOB is not system memory or higher than MAX_ADDRESS, ignored.\r
328 //\r
329 if ((ResourceHob->ResourceType != EFI_RESOURCE_SYSTEM_MEMORY) ||\r
330 (ResourceHob->PhysicalStart + ResourceHob->ResourceLength > MAX_ADDRESS))\r
331 {\r
332 continue;\r
333 }\r
334\r
335 for (NextHob.Raw = PrivateData->HobList.Raw; !END_OF_HOB_LIST (NextHob); NextHob.Raw = GET_NEXT_HOB (NextHob)) {\r
336 if (NextHob.Raw == Hob.Raw) {\r
337 continue;\r
338 }\r
339\r
340 //\r
341 // See if this is a resource descriptor HOB\r
342 //\r
343 if (GET_HOB_TYPE (NextHob) == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {\r
344 NextResourceHob = NextHob.ResourceDescriptor;\r
345 //\r
346 // test if range described in this NextResourceHob is system memory and have the same attribute.\r
347 // Note: Here is a assumption that system memory should always be healthy even without test.\r
348 //\r
349 if ((NextResourceHob->ResourceType == EFI_RESOURCE_SYSTEM_MEMORY) &&\r
350 (((NextResourceHob->ResourceAttribute^ResourceHob->ResourceAttribute)&(~EFI_RESOURCE_ATTRIBUTE_TESTED)) == 0))\r
351 {\r
352 //\r
353 // See if the memory range described in ResourceHob and NextResourceHob is adjacent\r
354 //\r
355 if (((ResourceHob->PhysicalStart <= NextResourceHob->PhysicalStart) &&\r
356 (ResourceHob->PhysicalStart + ResourceHob->ResourceLength >= NextResourceHob->PhysicalStart)) ||\r
357 ((ResourceHob->PhysicalStart >= NextResourceHob->PhysicalStart) &&\r
358 (ResourceHob->PhysicalStart <= NextResourceHob->PhysicalStart + NextResourceHob->ResourceLength)))\r
359 {\r
360 MemoryRangeEnd = ((ResourceHob->PhysicalStart + ResourceHob->ResourceLength) > (NextResourceHob->PhysicalStart + NextResourceHob->ResourceLength)) ?\r
361 (ResourceHob->PhysicalStart + ResourceHob->ResourceLength) : (NextResourceHob->PhysicalStart + NextResourceHob->ResourceLength);\r
362\r
363 ResourceHob->PhysicalStart = (ResourceHob->PhysicalStart < NextResourceHob->PhysicalStart) ?\r
364 ResourceHob->PhysicalStart : NextResourceHob->PhysicalStart;\r
365\r
366 ResourceHob->ResourceLength = (MemoryRangeEnd - ResourceHob->PhysicalStart);\r
367\r
368 ResourceHob->ResourceAttribute = ResourceHob->ResourceAttribute & (~EFI_RESOURCE_ATTRIBUTE_TESTED);\r
369 //\r
370 // Delete the NextResourceHob by marking it as unused.\r
371 //\r
372 GET_HOB_TYPE (NextHob) = EFI_HOB_TYPE_UNUSED;\r
373 }\r
374 }\r
375 }\r
376 }\r
377 }\r
378 }\r
379\r
380 //\r
381 // Some platform is already allocated pages before the HOB re-org. Here to build dedicated resource HOB to describe\r
382 // the allocated memory range\r
383 //\r
384 for (Hob.Raw = PrivateData->HobList.Raw; !END_OF_HOB_LIST (Hob); Hob.Raw = GET_NEXT_HOB (Hob)) {\r
385 //\r
386 // See if this is a memory allocation HOB\r
387 //\r
388 if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_MEMORY_ALLOCATION) {\r
389 MemoryHob = Hob.MemoryAllocation;\r
390 for (NextHob.Raw = PrivateData->HobList.Raw; !END_OF_HOB_LIST (NextHob); NextHob.Raw = GET_NEXT_HOB (NextHob)) {\r
391 //\r
392 // See if this is a resource descriptor HOB\r
393 //\r
394 if (GET_HOB_TYPE (NextHob) == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {\r
395 NextResourceHob = NextHob.ResourceDescriptor;\r
396 //\r
397 // If range described in this HOB is not system memory or higher than MAX_ADDRESS, ignored.\r
398 //\r
399 if ((NextResourceHob->ResourceType != EFI_RESOURCE_SYSTEM_MEMORY) || (NextResourceHob->PhysicalStart + NextResourceHob->ResourceLength > MAX_ADDRESS)) {\r
400 continue;\r
401 }\r
402\r
403 //\r
404 // If the range describe in memory allocation HOB belongs to the memory range described by the resource HOB\r
405 //\r
406 if ((MemoryHob->AllocDescriptor.MemoryBaseAddress >= NextResourceHob->PhysicalStart) &&\r
407 (MemoryHob->AllocDescriptor.MemoryBaseAddress + MemoryHob->AllocDescriptor.MemoryLength <= NextResourceHob->PhysicalStart + NextResourceHob->ResourceLength))\r
408 {\r
409 //\r
410 // Build separate resource HOB for this allocated range\r
411 //\r
412 if (MemoryHob->AllocDescriptor.MemoryBaseAddress > NextResourceHob->PhysicalStart) {\r
413 BuildResourceDescriptorHob (\r
414 EFI_RESOURCE_SYSTEM_MEMORY,\r
415 NextResourceHob->ResourceAttribute,\r
416 NextResourceHob->PhysicalStart,\r
417 (MemoryHob->AllocDescriptor.MemoryBaseAddress - NextResourceHob->PhysicalStart)\r
418 );\r
419 }\r
420\r
421 if (MemoryHob->AllocDescriptor.MemoryBaseAddress + MemoryHob->AllocDescriptor.MemoryLength < NextResourceHob->PhysicalStart + NextResourceHob->ResourceLength) {\r
422 BuildResourceDescriptorHob (\r
423 EFI_RESOURCE_SYSTEM_MEMORY,\r
424 NextResourceHob->ResourceAttribute,\r
425 MemoryHob->AllocDescriptor.MemoryBaseAddress + MemoryHob->AllocDescriptor.MemoryLength,\r
426 (NextResourceHob->PhysicalStart + NextResourceHob->ResourceLength -(MemoryHob->AllocDescriptor.MemoryBaseAddress + MemoryHob->AllocDescriptor.MemoryLength))\r
427 );\r
428 }\r
429\r
430 NextResourceHob->PhysicalStart = MemoryHob->AllocDescriptor.MemoryBaseAddress;\r
431 NextResourceHob->ResourceLength = MemoryHob->AllocDescriptor.MemoryLength;\r
432 break;\r
433 }\r
434 }\r
435 }\r
436 }\r
437 }\r
438\r
439 //\r
440 // Try to find and validate the TOP address.\r
441 //\r
442 if ((INT64)PcdGet64 (PcdLoadModuleAtFixAddressEnable) > 0 ) {\r
443 //\r
444 // The LMFA feature is enabled as load module at fixed absolute address.\r
445 //\r
446 TopLoadingAddress = (EFI_PHYSICAL_ADDRESS)PcdGet64 (PcdLoadModuleAtFixAddressEnable);\r
447 DEBUG ((DEBUG_INFO, "LOADING MODULE FIXED INFO: Loading module at fixed absolute address.\n"));\r
448 //\r
449 // validate the Address. Loop the resource descriptor HOB to make sure the address is in valid memory range\r
450 //\r
451 if ((TopLoadingAddress & EFI_PAGE_MASK) != 0) {\r
452 DEBUG ((DEBUG_INFO, "LOADING MODULE FIXED ERROR:Top Address 0x%lx is invalid since top address should be page align. \n", TopLoadingAddress));\r
453 ASSERT (FALSE);\r
454 }\r
455\r
456 //\r
457 // Search for a memory region that is below MAX_ADDRESS and in which TopLoadingAddress lies\r
458 //\r
459 for (Hob.Raw = PrivateData->HobList.Raw; !END_OF_HOB_LIST (Hob); Hob.Raw = GET_NEXT_HOB (Hob)) {\r
460 //\r
461 // See if this is a resource descriptor HOB\r
462 //\r
463 if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {\r
464 ResourceHob = Hob.ResourceDescriptor;\r
465 //\r
466 // See if this resource descriptor HOB describes tested system memory below MAX_ADDRESS\r
467 //\r
468 if ((ResourceHob->ResourceType == EFI_RESOURCE_SYSTEM_MEMORY) &&\r
469 (ResourceHob->PhysicalStart + ResourceHob->ResourceLength <= MAX_ADDRESS))\r
470 {\r
471 //\r
472 // See if Top address specified by user is valid.\r
473 //\r
474 if ((ResourceHob->PhysicalStart + TotalReservedMemorySize < TopLoadingAddress) &&\r
475 ((ResourceHob->PhysicalStart + ResourceHob->ResourceLength - MINIMUM_INITIAL_MEMORY_SIZE) >= TopLoadingAddress) &&\r
476 PeiLoadFixAddressIsMemoryRangeAvailable (PrivateData, ResourceHob))\r
477 {\r
478 CurrentResourceHob = ResourceHob;\r
479 CurrentHob = Hob;\r
480 break;\r
481 }\r
482 }\r
483 }\r
484 }\r
485\r
486 if (CurrentResourceHob != NULL) {\r
487 DEBUG ((DEBUG_INFO, "LOADING MODULE FIXED INFO:Top Address 0x%lx is valid \n", TopLoadingAddress));\r
488 TopLoadingAddress += MINIMUM_INITIAL_MEMORY_SIZE;\r
489 } else {\r
490 DEBUG ((DEBUG_INFO, "LOADING MODULE FIXED ERROR:Top Address 0x%lx is invalid \n", TopLoadingAddress));\r
491 DEBUG ((DEBUG_INFO, "LOADING MODULE FIXED ERROR:The recommended Top Address for the platform is: \n"));\r
492 //\r
493 // Print the recommended Top address range.\r
494 //\r
495 for (Hob.Raw = PrivateData->HobList.Raw; !END_OF_HOB_LIST (Hob); Hob.Raw = GET_NEXT_HOB (Hob)) {\r
496 //\r
497 // See if this is a resource descriptor HOB\r
498 //\r
499 if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {\r
500 ResourceHob = Hob.ResourceDescriptor;\r
501 //\r
502 // See if this resource descriptor HOB describes tested system memory below MAX_ADDRESS\r
503 //\r
504 if ((ResourceHob->ResourceType == EFI_RESOURCE_SYSTEM_MEMORY) &&\r
505 (ResourceHob->PhysicalStart + ResourceHob->ResourceLength <= MAX_ADDRESS))\r
506 {\r
507 //\r
508 // See if Top address specified by user is valid.\r
509 //\r
510 if ((ResourceHob->ResourceLength > TotalReservedMemorySize) && PeiLoadFixAddressIsMemoryRangeAvailable (PrivateData, ResourceHob)) {\r
511 DEBUG ((\r
512 DEBUG_INFO,\r
513 "(0x%lx, 0x%lx)\n",\r
514 (ResourceHob->PhysicalStart + TotalReservedMemorySize -MINIMUM_INITIAL_MEMORY_SIZE),\r
515 (ResourceHob->PhysicalStart + ResourceHob->ResourceLength -MINIMUM_INITIAL_MEMORY_SIZE)\r
516 ));\r
517 }\r
518 }\r
519 }\r
520 }\r
521\r
522 //\r
523 // Assert here\r
524 //\r
525 ASSERT (FALSE);\r
526 return;\r
527 }\r
528 } else {\r
529 //\r
530 // The LMFA feature is enabled as load module at fixed offset relative to TOLM\r
531 // Parse the Hob list to find the topest available memory. Generally it is (TOLM - TSEG)\r
532 //\r
533 //\r
534 // Search for a tested memory region that is below MAX_ADDRESS\r
535 //\r
536 for (Hob.Raw = PrivateData->HobList.Raw; !END_OF_HOB_LIST (Hob); Hob.Raw = GET_NEXT_HOB (Hob)) {\r
537 //\r
538 // See if this is a resource descriptor HOB\r
539 //\r
540 if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {\r
541 ResourceHob = Hob.ResourceDescriptor;\r
542 //\r
543 // See if this resource descriptor HOB describes tested system memory below MAX_ADDRESS\r
544 //\r
545 if ((ResourceHob->ResourceType == EFI_RESOURCE_SYSTEM_MEMORY) &&\r
546 (ResourceHob->PhysicalStart + ResourceHob->ResourceLength <= MAX_ADDRESS) &&\r
547 (ResourceHob->ResourceLength > TotalReservedMemorySize) && PeiLoadFixAddressIsMemoryRangeAvailable (PrivateData, ResourceHob))\r
548 {\r
549 //\r
550 // See if this is the highest largest system memory region below MaxAddress\r
551 //\r
552 if (ResourceHob->PhysicalStart > HighAddress) {\r
553 CurrentResourceHob = ResourceHob;\r
554 CurrentHob = Hob;\r
555 HighAddress = CurrentResourceHob->PhysicalStart;\r
556 }\r
557 }\r
558 }\r
559 }\r
560\r
561 if (CurrentResourceHob == NULL) {\r
562 DEBUG ((DEBUG_INFO, "LOADING MODULE FIXED ERROR:The System Memory is too small\n"));\r
563 //\r
564 // Assert here\r
565 //\r
566 ASSERT (FALSE);\r
567 return;\r
568 } else {\r
569 TopLoadingAddress = CurrentResourceHob->PhysicalStart + CurrentResourceHob->ResourceLength;\r
570 }\r
571 }\r
572\r
573 if (CurrentResourceHob != NULL) {\r
574 //\r
575 // rebuild resource HOB for PEI memory and reserved memory\r
576 //\r
577 BuildResourceDescriptorHob (\r
578 EFI_RESOURCE_SYSTEM_MEMORY,\r
579 (\r
580 EFI_RESOURCE_ATTRIBUTE_PRESENT |\r
581 EFI_RESOURCE_ATTRIBUTE_INITIALIZED |\r
582 EFI_RESOURCE_ATTRIBUTE_TESTED |\r
583 EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE |\r
584 EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE |\r
585 EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE |\r
586 EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE\r
587 ),\r
588 (TopLoadingAddress - TotalReservedMemorySize),\r
589 TotalReservedMemorySize\r
590 );\r
591 //\r
592 // rebuild resource for the remain memory if necessary\r
593 //\r
594 if (CurrentResourceHob->PhysicalStart < TopLoadingAddress - TotalReservedMemorySize) {\r
595 BuildResourceDescriptorHob (\r
596 EFI_RESOURCE_SYSTEM_MEMORY,\r
597 (\r
598 EFI_RESOURCE_ATTRIBUTE_PRESENT |\r
599 EFI_RESOURCE_ATTRIBUTE_INITIALIZED |\r
600 EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE |\r
601 EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE |\r
602 EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE |\r
603 EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE\r
604 ),\r
605 CurrentResourceHob->PhysicalStart,\r
606 (TopLoadingAddress - TotalReservedMemorySize - CurrentResourceHob->PhysicalStart)\r
607 );\r
608 }\r
609\r
610 if (CurrentResourceHob->PhysicalStart + CurrentResourceHob->ResourceLength > TopLoadingAddress ) {\r
611 BuildResourceDescriptorHob (\r
612 EFI_RESOURCE_SYSTEM_MEMORY,\r
613 (\r
614 EFI_RESOURCE_ATTRIBUTE_PRESENT |\r
615 EFI_RESOURCE_ATTRIBUTE_INITIALIZED |\r
616 EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE |\r
617 EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE |\r
618 EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE |\r
619 EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE\r
620 ),\r
621 TopLoadingAddress,\r
622 (CurrentResourceHob->PhysicalStart + CurrentResourceHob->ResourceLength - TopLoadingAddress)\r
623 );\r
624 }\r
625\r
626 //\r
627 // Delete CurrentHob by marking it as unused since the memory range described by is rebuilt.\r
628 //\r
629 GET_HOB_TYPE (CurrentHob) = EFI_HOB_TYPE_UNUSED;\r
630 }\r
631\r
632 //\r
633 // Cache the top address for Loading Module at Fixed Address feature\r
634 //\r
635 PrivateData->LoadModuleAtFixAddressTopAddress = TopLoadingAddress - MINIMUM_INITIAL_MEMORY_SIZE;\r
636 DEBUG ((DEBUG_INFO, "LOADING MODULE FIXED INFO: Top address = 0x%lx\n", PrivateData->LoadModuleAtFixAddressTopAddress));\r
637 //\r
638 // reinstall the PEI memory relative to TopLoadingAddress\r
639 //\r
640 PrivateData->PhysicalMemoryBegin = TopLoadingAddress - TotalReservedMemorySize;\r
641 PrivateData->FreePhysicalMemoryTop = PrivateData->PhysicalMemoryBegin + PeiMemorySize;\r
642}\r
643\r
644/**\r
645 This routine is invoked in switch stack as PeiCore Entry.\r
646\r
647 @param SecCoreData Points to a data structure containing information about the PEI core's operating\r
648 environment, such as the size and location of temporary RAM, the stack location and\r
649 the BFV location.\r
650 @param Private Pointer to old core data that is used to initialize the\r
651 core's data areas.\r
652**/\r
653VOID\r
654EFIAPI\r
655PeiCoreEntry (\r
656 IN CONST EFI_SEC_PEI_HAND_OFF *SecCoreData,\r
657 IN PEI_CORE_INSTANCE *Private\r
658 )\r
659{\r
660 //\r
661 // Entry PEI Phase 2\r
662 //\r
663 PeiCore (SecCoreData, NULL, Private);\r
664}\r
665\r
666/**\r
667 Check SwitchStackSignal and switch stack if SwitchStackSignal is TRUE.\r
668\r
669 @param[in] SecCoreData Points to a data structure containing information about the PEI core's operating\r
670 environment, such as the size and location of temporary RAM, the stack location and\r
671 the BFV location.\r
672 @param[in] Private Pointer to the private data passed in from caller.\r
673\r
674**/\r
675VOID\r
676PeiCheckAndSwitchStack (\r
677 IN CONST EFI_SEC_PEI_HAND_OFF *SecCoreData,\r
678 IN PEI_CORE_INSTANCE *Private\r
679 )\r
680{\r
681 VOID *LoadFixPeiCodeBegin;\r
682 EFI_STATUS Status;\r
683 CONST EFI_PEI_SERVICES **PeiServices;\r
684 UINT64 NewStackSize;\r
685 EFI_PHYSICAL_ADDRESS TopOfOldStack;\r
686 EFI_PHYSICAL_ADDRESS TopOfNewStack;\r
687 UINTN StackOffset;\r
688 BOOLEAN StackOffsetPositive;\r
689 EFI_PHYSICAL_ADDRESS TemporaryRamBase;\r
690 UINTN TemporaryRamSize;\r
691 UINTN TemporaryStackSize;\r
692 VOID *TemporaryStackBase;\r
693 UINTN PeiTemporaryRamSize;\r
694 VOID *PeiTemporaryRamBase;\r
695 EFI_PEI_TEMPORARY_RAM_SUPPORT_PPI *TemporaryRamSupportPpi;\r
696 EFI_PHYSICAL_ADDRESS BaseOfNewHeap;\r
697 EFI_PHYSICAL_ADDRESS HoleMemBase;\r
698 UINTN HoleMemSize;\r
699 UINTN HeapTemporaryRamSize;\r
700 EFI_PHYSICAL_ADDRESS TempBase1;\r
701 UINTN TempSize1;\r
702 EFI_PHYSICAL_ADDRESS TempBase2;\r
703 UINTN TempSize2;\r
704 UINTN Index;\r
705\r
706 PeiServices = (CONST EFI_PEI_SERVICES **)&Private->Ps;\r
707\r
708 if (Private->SwitchStackSignal) {\r
709 //\r
710 // Before switch stack from temporary memory to permanent memory, calculate the heap and stack\r
711 // usage in temporary memory for debugging.\r
712 //\r
713 DEBUG_CODE_BEGIN ();\r
714 UINT32 *StackPointer;\r
715 EFI_PEI_HOB_POINTERS Hob;\r
716\r
717 for ( StackPointer = (UINT32 *)SecCoreData->StackBase;\r
718 (StackPointer < (UINT32 *)((UINTN)SecCoreData->StackBase + SecCoreData->StackSize)) \\r
719 && (*StackPointer == PcdGet32 (PcdInitValueInTempStack));\r
720 StackPointer++)\r
721 {\r
722 }\r
723\r
724 DEBUG ((DEBUG_INFO, "Temp Stack : BaseAddress=0x%p Length=0x%X\n", SecCoreData->StackBase, (UINT32)SecCoreData->StackSize));\r
725 DEBUG ((DEBUG_INFO, "Temp Heap : BaseAddress=0x%p Length=0x%X\n", SecCoreData->PeiTemporaryRamBase, (UINT32)SecCoreData->PeiTemporaryRamSize));\r
726 DEBUG ((DEBUG_INFO, "Total temporary memory: %d bytes.\n", (UINT32)SecCoreData->TemporaryRamSize));\r
727 DEBUG ((\r
728 DEBUG_INFO,\r
729 " temporary memory stack ever used: %d bytes.\n",\r
730 (UINT32)(SecCoreData->StackSize - ((UINTN)StackPointer - (UINTN)SecCoreData->StackBase))\r
731 ));\r
732 DEBUG ((\r
733 DEBUG_INFO,\r
734 " temporary memory heap used for HobList: %d bytes.\n",\r
735 (UINT32)((UINTN)Private->HobList.HandoffInformationTable->EfiFreeMemoryBottom - (UINTN)Private->HobList.Raw)\r
736 ));\r
737 DEBUG ((\r
738 DEBUG_INFO,\r
739 " temporary memory heap occupied by memory pages: %d bytes.\n",\r
740 (UINT32)(UINTN)(Private->HobList.HandoffInformationTable->EfiMemoryTop - Private->HobList.HandoffInformationTable->EfiFreeMemoryTop)\r
741 ));\r
742 for (Hob.Raw = Private->HobList.Raw; !END_OF_HOB_LIST (Hob); Hob.Raw = GET_NEXT_HOB (Hob)) {\r
743 if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_MEMORY_ALLOCATION) {\r
744 DEBUG ((\r
745 DEBUG_INFO,\r
746 "Memory Allocation 0x%08x 0x%0lx - 0x%0lx\n", \\r
747 Hob.MemoryAllocation->AllocDescriptor.MemoryType, \\r
748 Hob.MemoryAllocation->AllocDescriptor.MemoryBaseAddress, \\r
749 Hob.MemoryAllocation->AllocDescriptor.MemoryBaseAddress + Hob.MemoryAllocation->AllocDescriptor.MemoryLength - 1\r
750 ));\r
751 }\r
752 }\r
753\r
754 DEBUG_CODE_END ();\r
755\r
756 if ((PcdGet64 (PcdLoadModuleAtFixAddressEnable) != 0) && (Private->HobList.HandoffInformationTable->BootMode != BOOT_ON_S3_RESUME)) {\r
757 //\r
758 // Loading Module at Fixed Address is enabled\r
759 //\r
760 PeiLoadFixAddressHook (Private);\r
761\r
762 //\r
763 // If Loading Module at Fixed Address is enabled, Allocating memory range for Pei code range.\r
764 //\r
765 LoadFixPeiCodeBegin = AllocatePages ((UINTN)PcdGet32 (PcdLoadFixAddressPeiCodePageNumber));\r
766 DEBUG ((DEBUG_INFO, "LOADING MODULE FIXED INFO: PeiCodeBegin = 0x%lX, PeiCodeTop= 0x%lX\n", (UINT64)(UINTN)LoadFixPeiCodeBegin, (UINT64)((UINTN)LoadFixPeiCodeBegin + PcdGet32 (PcdLoadFixAddressPeiCodePageNumber) * EFI_PAGE_SIZE)));\r
767 }\r
768\r
769 //\r
770 // Reserve the size of new stack at bottom of physical memory\r
771 //\r
772 // The size of new stack in permanent memory must be the same size\r
773 // or larger than the size of old stack in temporary memory.\r
774 // But if new stack is smaller than the size of old stack, we also reserve\r
775 // the size of old stack at bottom of permanent memory.\r
776 //\r
777 NewStackSize = RShiftU64 (Private->PhysicalMemoryLength, 1);\r
778 NewStackSize = ALIGN_VALUE (NewStackSize, EFI_PAGE_SIZE);\r
779 NewStackSize = MIN (PcdGet32 (PcdPeiCoreMaxPeiStackSize), NewStackSize);\r
780 DEBUG ((DEBUG_INFO, "Old Stack size %d, New stack size %d\n", (UINT32)SecCoreData->StackSize, (UINT32)NewStackSize));\r
781 ASSERT (NewStackSize >= SecCoreData->StackSize);\r
782\r
783 //\r
784 // Calculate stack offset and heap offset between temporary memory and new permanent\r
785 // memory separately.\r
786 //\r
787 TopOfOldStack = (UINTN)SecCoreData->StackBase + SecCoreData->StackSize;\r
788 TopOfNewStack = Private->PhysicalMemoryBegin + NewStackSize;\r
789 if (TopOfNewStack >= TopOfOldStack) {\r
790 StackOffsetPositive = TRUE;\r
791 StackOffset = (UINTN)(TopOfNewStack - TopOfOldStack);\r
792 } else {\r
793 StackOffsetPositive = FALSE;\r
794 StackOffset = (UINTN)(TopOfOldStack - TopOfNewStack);\r
795 }\r
796\r
797 Private->StackOffsetPositive = StackOffsetPositive;\r
798 Private->StackOffset = StackOffset;\r
799\r
800 //\r
801 // Build Stack HOB that describes the permanent memory stack\r
802 //\r
803 DEBUG ((DEBUG_INFO, "Stack Hob: BaseAddress=0x%lX Length=0x%lX\n", TopOfNewStack - NewStackSize, NewStackSize));\r
804 BuildStackHob (TopOfNewStack - NewStackSize, NewStackSize);\r
805\r
806 //\r
807 // Cache information from SecCoreData into locals before SecCoreData is converted to a permanent memory address\r
808 //\r
809 TemporaryRamBase = (EFI_PHYSICAL_ADDRESS)(UINTN)SecCoreData->TemporaryRamBase;\r
810 TemporaryRamSize = SecCoreData->TemporaryRamSize;\r
811 TemporaryStackSize = SecCoreData->StackSize;\r
812 TemporaryStackBase = SecCoreData->StackBase;\r
813 PeiTemporaryRamSize = SecCoreData->PeiTemporaryRamSize;\r
814 PeiTemporaryRamBase = SecCoreData->PeiTemporaryRamBase;\r
815\r
816 //\r
817 // TemporaryRamSupportPpi is produced by platform's SEC\r
818 //\r
819 Status = PeiServicesLocatePpi (\r
820 &gEfiTemporaryRamSupportPpiGuid,\r
821 0,\r
822 NULL,\r
823 (VOID **)&TemporaryRamSupportPpi\r
824 );\r
825 if (!EFI_ERROR (Status)) {\r
826 //\r
827 // Heap Offset\r
828 //\r
829 BaseOfNewHeap = TopOfNewStack;\r
830 if (BaseOfNewHeap >= (UINTN)SecCoreData->PeiTemporaryRamBase) {\r
831 Private->HeapOffsetPositive = TRUE;\r
832 Private->HeapOffset = (UINTN)(BaseOfNewHeap - (UINTN)SecCoreData->PeiTemporaryRamBase);\r
833 } else {\r
834 Private->HeapOffsetPositive = FALSE;\r
835 Private->HeapOffset = (UINTN)((UINTN)SecCoreData->PeiTemporaryRamBase - BaseOfNewHeap);\r
836 }\r
837\r
838 DEBUG ((DEBUG_INFO, "Heap Offset = 0x%lX Stack Offset = 0x%lX\n", (UINT64)Private->HeapOffset, (UINT64)Private->StackOffset));\r
839\r
840 //\r
841 // Calculate new HandOffTable and PrivateData address in permanent memory's stack\r
842 //\r
843 if (StackOffsetPositive) {\r
844 SecCoreData = (CONST EFI_SEC_PEI_HAND_OFF *)((UINTN)(VOID *)SecCoreData + StackOffset);\r
845 Private = (PEI_CORE_INSTANCE *)((UINTN)(VOID *)Private + StackOffset);\r
846 } else {\r
847 SecCoreData = (CONST EFI_SEC_PEI_HAND_OFF *)((UINTN)(VOID *)SecCoreData - StackOffset);\r
848 Private = (PEI_CORE_INSTANCE *)((UINTN)(VOID *)Private - StackOffset);\r
849 }\r
850\r
851 //\r
852 // Temporary Ram Support PPI is provided by platform, it will copy\r
853 // temporary memory to permanent memory and do stack switching.\r
854 // After invoking Temporary Ram Support PPI, the following code's\r
855 // stack is in permanent memory.\r
856 //\r
857 TemporaryRamSupportPpi->TemporaryRamMigration (\r
858 PeiServices,\r
859 TemporaryRamBase,\r
860 (EFI_PHYSICAL_ADDRESS)(UINTN)(TopOfNewStack - TemporaryStackSize),\r
861 TemporaryRamSize\r
862 );\r
863\r
864 //\r
865 // Migrate memory pages allocated in pre-memory phase.\r
866 // It could not be called before calling TemporaryRamSupportPpi->TemporaryRamMigration()\r
867 // as the migrated memory pages may be overridden by TemporaryRamSupportPpi->TemporaryRamMigration().\r
868 //\r
869 MigrateMemoryPages (Private, TRUE);\r
870\r
871 //\r
872 // Entry PEI Phase 2\r
873 //\r
874 PeiCore (SecCoreData, NULL, Private);\r
875 } else {\r
876 //\r
877 // Migrate memory pages allocated in pre-memory phase.\r
878 //\r
879 MigrateMemoryPages (Private, FALSE);\r
880\r
881 //\r
882 // Migrate the PEI Services Table pointer from temporary RAM to permanent RAM.\r
883 //\r
884 MigratePeiServicesTablePointer ();\r
885\r
886 //\r
887 // Heap Offset\r
888 //\r
889 BaseOfNewHeap = TopOfNewStack;\r
890 HoleMemBase = TopOfNewStack;\r
891 HoleMemSize = TemporaryRamSize - PeiTemporaryRamSize - TemporaryStackSize;\r
892 if (HoleMemSize != 0) {\r
893 //\r
894 // Make sure HOB List start address is 8 byte alignment.\r
895 //\r
896 BaseOfNewHeap = ALIGN_VALUE (BaseOfNewHeap + HoleMemSize, 8);\r
897 }\r
898\r
899 if (BaseOfNewHeap >= (UINTN)SecCoreData->PeiTemporaryRamBase) {\r
900 Private->HeapOffsetPositive = TRUE;\r
901 Private->HeapOffset = (UINTN)(BaseOfNewHeap - (UINTN)SecCoreData->PeiTemporaryRamBase);\r
902 } else {\r
903 Private->HeapOffsetPositive = FALSE;\r
904 Private->HeapOffset = (UINTN)((UINTN)SecCoreData->PeiTemporaryRamBase - BaseOfNewHeap);\r
905 }\r
906\r
907 DEBUG ((DEBUG_INFO, "Heap Offset = 0x%lX Stack Offset = 0x%lX\n", (UINT64)Private->HeapOffset, (UINT64)Private->StackOffset));\r
908\r
909 //\r
910 // Migrate Heap\r
911 //\r
912 HeapTemporaryRamSize = (UINTN)(Private->HobList.HandoffInformationTable->EfiFreeMemoryBottom - Private->HobList.HandoffInformationTable->EfiMemoryBottom);\r
913 ASSERT (BaseOfNewHeap + HeapTemporaryRamSize <= Private->FreePhysicalMemoryTop);\r
914 CopyMem ((UINT8 *)(UINTN)BaseOfNewHeap, PeiTemporaryRamBase, HeapTemporaryRamSize);\r
915\r
916 //\r
917 // Migrate Stack\r
918 //\r
919 CopyMem ((UINT8 *)(UINTN)(TopOfNewStack - TemporaryStackSize), TemporaryStackBase, TemporaryStackSize);\r
920\r
921 //\r
922 // Copy Hole Range Data\r
923 //\r
924 if (HoleMemSize != 0) {\r
925 //\r
926 // Prepare Hole\r
927 //\r
928 if (PeiTemporaryRamBase < TemporaryStackBase) {\r
929 TempBase1 = (EFI_PHYSICAL_ADDRESS)(UINTN)PeiTemporaryRamBase;\r
930 TempSize1 = PeiTemporaryRamSize;\r
931 TempBase2 = (EFI_PHYSICAL_ADDRESS)(UINTN)TemporaryStackBase;\r
932 TempSize2 = TemporaryStackSize;\r
933 } else {\r
934 TempBase1 = (EFI_PHYSICAL_ADDRESS)(UINTN)TemporaryStackBase;\r
935 TempSize1 = TemporaryStackSize;\r
936 TempBase2 = (EFI_PHYSICAL_ADDRESS)(UINTN)PeiTemporaryRamBase;\r
937 TempSize2 = PeiTemporaryRamSize;\r
938 }\r
939\r
940 if (TemporaryRamBase < TempBase1) {\r
941 Private->HoleData[0].Base = TemporaryRamBase;\r
942 Private->HoleData[0].Size = (UINTN)(TempBase1 - TemporaryRamBase);\r
943 }\r
944\r
945 if (TempBase1 + TempSize1 < TempBase2) {\r
946 Private->HoleData[1].Base = TempBase1 + TempSize1;\r
947 Private->HoleData[1].Size = (UINTN)(TempBase2 - TempBase1 - TempSize1);\r
948 }\r
949\r
950 if (TempBase2 + TempSize2 < TemporaryRamBase + TemporaryRamSize) {\r
951 Private->HoleData[2].Base = TempBase2 + TempSize2;\r
952 Private->HoleData[2].Size = (UINTN)(TemporaryRamBase + TemporaryRamSize - TempBase2 - TempSize2);\r
953 }\r
954\r
955 //\r
956 // Copy Hole Range data.\r
957 //\r
958 for (Index = 0; Index < HOLE_MAX_NUMBER; Index++) {\r
959 if (Private->HoleData[Index].Size > 0) {\r
960 if (HoleMemBase > Private->HoleData[Index].Base) {\r
961 Private->HoleData[Index].OffsetPositive = TRUE;\r
962 Private->HoleData[Index].Offset = (UINTN)(HoleMemBase - Private->HoleData[Index].Base);\r
963 } else {\r
964 Private->HoleData[Index].OffsetPositive = FALSE;\r
965 Private->HoleData[Index].Offset = (UINTN)(Private->HoleData[Index].Base - HoleMemBase);\r
966 }\r
967\r
968 CopyMem ((VOID *)(UINTN)HoleMemBase, (VOID *)(UINTN)Private->HoleData[Index].Base, Private->HoleData[Index].Size);\r
969 HoleMemBase = HoleMemBase + Private->HoleData[Index].Size;\r
970 }\r
971 }\r
972 }\r
973\r
974 //\r
975 // Switch new stack\r
976 //\r
977 SwitchStack (\r
978 (SWITCH_STACK_ENTRY_POINT)(UINTN)PeiCoreEntry,\r
979 (VOID *)SecCoreData,\r
980 (VOID *)Private,\r
981 (VOID *)(UINTN)TopOfNewStack\r
982 );\r
983 }\r
984\r
985 //\r
986 // Code should not come here\r
987 //\r
988 ASSERT (FALSE);\r
989 }\r
990}\r
991\r
992/**\r
993 Migrate a PEIM from temporary RAM to permanent memory.\r
994\r
995 @param PeimFileHandle Pointer to the FFS file header of the image.\r
996 @param MigratedFileHandle Pointer to the FFS file header of the migrated image.\r
997\r
998 @retval EFI_SUCCESS Successfully migrated the PEIM to permanent memory.\r
999\r
1000**/\r
1001EFI_STATUS\r
1002EFIAPI\r
1003MigratePeim (\r
1004 IN EFI_PEI_FILE_HANDLE FileHandle,\r
1005 IN EFI_PEI_FILE_HANDLE MigratedFileHandle\r
1006 )\r
1007{\r
1008 EFI_STATUS Status;\r
1009 EFI_FFS_FILE_HEADER *FileHeader;\r
1010 VOID *Pe32Data;\r
1011 VOID *ImageAddress;\r
1012 CHAR8 *AsciiString;\r
1013 UINTN Index;\r
1014\r
1015 Status = EFI_SUCCESS;\r
1016\r
1017 FileHeader = (EFI_FFS_FILE_HEADER *)FileHandle;\r
1018 ASSERT (!IS_FFS_FILE2 (FileHeader));\r
1019\r
1020 ImageAddress = NULL;\r
1021 PeiGetPe32Data (MigratedFileHandle, &ImageAddress);\r
1022 if (ImageAddress != NULL) {\r
1023 DEBUG_CODE_BEGIN ();\r
1024 AsciiString = PeCoffLoaderGetPdbPointer (ImageAddress);\r
1025 for (Index = 0; AsciiString[Index] != 0; Index++) {\r
1026 if ((AsciiString[Index] == '\\') || (AsciiString[Index] == '/')) {\r
1027 AsciiString = AsciiString + Index + 1;\r
1028 Index = 0;\r
1029 } else if (AsciiString[Index] == '.') {\r
1030 AsciiString[Index] = 0;\r
1031 }\r
1032 }\r
1033\r
1034 DEBUG ((DEBUG_VERBOSE, "%a", AsciiString));\r
1035 DEBUG_CODE_END ();\r
1036\r
1037 Pe32Data = (VOID *)((UINTN)ImageAddress - (UINTN)MigratedFileHandle + (UINTN)FileHandle);\r
1038 Status = LoadAndRelocatePeCoffImageInPlace (Pe32Data, ImageAddress);\r
1039 ASSERT_EFI_ERROR (Status);\r
1040 }\r
1041\r
1042 return Status;\r
1043}\r
1044\r
1045/**\r
1046 Migrate Status Code Callback function pointers inside an FV from temporary memory to permanent memory.\r
1047\r
1048 @param OrgFvHandle Address of FV handle in temporary memory.\r
1049 @param FvHandle Address of FV handle in permanent memory.\r
1050 @param FvSize Size of the FV.\r
1051\r
1052**/\r
1053VOID\r
1054ConvertStatusCodeCallbacks (\r
1055 IN UINTN OrgFvHandle,\r
1056 IN UINTN FvHandle,\r
1057 IN UINTN FvSize\r
1058 )\r
1059{\r
1060 EFI_PEI_HOB_POINTERS Hob;\r
1061 UINTN *NumberOfEntries;\r
1062 UINTN *CallbackEntry;\r
1063 UINTN Index;\r
1064\r
1065 Hob.Raw = GetFirstGuidHob (&gStatusCodeCallbackGuid);\r
1066 while (Hob.Raw != NULL) {\r
1067 NumberOfEntries = GET_GUID_HOB_DATA (Hob);\r
1068 CallbackEntry = NumberOfEntries + 1;\r
1069 for (Index = 0; Index < *NumberOfEntries; Index++) {\r
1070 if (((VOID *)CallbackEntry[Index]) != NULL) {\r
1071 if ((CallbackEntry[Index] >= OrgFvHandle) && (CallbackEntry[Index] < (OrgFvHandle + FvSize))) {\r
1072 DEBUG ((\r
1073 DEBUG_INFO,\r
1074 "Migrating CallbackEntry[%Lu] from 0x%0*Lx to ",\r
1075 (UINT64)Index,\r
1076 (sizeof CallbackEntry[Index]) * 2,\r
1077 (UINT64)CallbackEntry[Index]\r
1078 ));\r
1079 if (OrgFvHandle > FvHandle) {\r
1080 CallbackEntry[Index] = CallbackEntry[Index] - (OrgFvHandle - FvHandle);\r
1081 } else {\r
1082 CallbackEntry[Index] = CallbackEntry[Index] + (FvHandle - OrgFvHandle);\r
1083 }\r
1084\r
1085 DEBUG ((\r
1086 DEBUG_INFO,\r
1087 "0x%0*Lx\n",\r
1088 (sizeof CallbackEntry[Index]) * 2,\r
1089 (UINT64)CallbackEntry[Index]\r
1090 ));\r
1091 }\r
1092 }\r
1093 }\r
1094\r
1095 Hob.Raw = GET_NEXT_HOB (Hob);\r
1096 Hob.Raw = GetNextGuidHob (&gStatusCodeCallbackGuid, Hob.Raw);\r
1097 }\r
1098}\r
1099\r
1100/**\r
1101 Migrates PEIMs in the given firmware volume.\r
1102\r
1103 @param Private Pointer to the PeiCore's private data structure.\r
1104 @param FvIndex The firmware volume index to migrate.\r
1105 @param OrgFvHandle The handle to the firmware volume in temporary memory.\r
1106 @param FvHandle The handle to the firmware volume in permanent memory.\r
1107\r
1108 @retval EFI_SUCCESS The PEIMs in the FV were migrated successfully\r
1109 @retval EFI_INVALID_PARAMETER The Private pointer is NULL or FvCount is invalid.\r
1110\r
1111**/\r
1112EFI_STATUS\r
1113EFIAPI\r
1114MigratePeimsInFv (\r
1115 IN PEI_CORE_INSTANCE *Private,\r
1116 IN UINTN FvIndex,\r
1117 IN UINTN OrgFvHandle,\r
1118 IN UINTN FvHandle\r
1119 )\r
1120{\r
1121 EFI_STATUS Status;\r
1122 volatile UINTN FileIndex;\r
1123 EFI_PEI_FILE_HANDLE MigratedFileHandle;\r
1124 EFI_PEI_FILE_HANDLE FileHandle;\r
1125\r
1126 if ((Private == NULL) || (FvIndex >= Private->FvCount)) {\r
1127 return EFI_INVALID_PARAMETER;\r
1128 }\r
1129\r
1130 if (Private->Fv[FvIndex].ScanFv) {\r
1131 for (FileIndex = 0; FileIndex < Private->Fv[FvIndex].PeimCount; FileIndex++) {\r
1132 if (Private->Fv[FvIndex].FvFileHandles[FileIndex] != NULL) {\r
1133 FileHandle = Private->Fv[FvIndex].FvFileHandles[FileIndex];\r
1134\r
1135 MigratedFileHandle = (EFI_PEI_FILE_HANDLE)((UINTN)FileHandle - OrgFvHandle + FvHandle);\r
1136\r
1137 DEBUG ((DEBUG_VERBOSE, " Migrating FileHandle %2d ", FileIndex));\r
1138 Status = MigratePeim (FileHandle, MigratedFileHandle);\r
1139 DEBUG ((DEBUG_VERBOSE, "\n"));\r
1140 ASSERT_EFI_ERROR (Status);\r
1141\r
1142 if (!EFI_ERROR (Status)) {\r
1143 Private->Fv[FvIndex].FvFileHandles[FileIndex] = MigratedFileHandle;\r
1144 if (FvIndex == Private->CurrentPeimFvCount) {\r
1145 Private->CurrentFvFileHandles[FileIndex] = MigratedFileHandle;\r
1146 }\r
1147 }\r
1148 }\r
1149 }\r
1150 }\r
1151\r
1152 return EFI_SUCCESS;\r
1153}\r
1154\r
1155/**\r
1156 Migrate FVs out of temporary RAM before the cache is flushed.\r
1157\r
1158 @param Private PeiCore's private data structure\r
1159 @param SecCoreData Points to a data structure containing information about the PEI core's operating\r
1160 environment, such as the size and location of temporary RAM, the stack location and\r
1161 the BFV location.\r
1162\r
1163 @retval EFI_SUCCESS Successfully migrated installed FVs from temporary RAM to permanent memory.\r
1164 @retval EFI_OUT_OF_RESOURCES Insufficient memory exists to allocate needed pages.\r
1165\r
1166**/\r
1167EFI_STATUS\r
1168EFIAPI\r
1169EvacuateTempRam (\r
1170 IN PEI_CORE_INSTANCE *Private,\r
1171 IN CONST EFI_SEC_PEI_HAND_OFF *SecCoreData\r
1172 )\r
1173{\r
1174 EFI_STATUS Status;\r
1175 volatile UINTN FvIndex;\r
1176 volatile UINTN FvChildIndex;\r
1177 UINTN ChildFvOffset;\r
1178 EFI_PHYSICAL_ADDRESS FvHeaderAddress;\r
1179 EFI_FIRMWARE_VOLUME_HEADER *FvHeader;\r
1180 EFI_FIRMWARE_VOLUME_HEADER *ChildFvHeader;\r
1181 EFI_FIRMWARE_VOLUME_HEADER *MigratedFvHeader;\r
1182 EFI_FIRMWARE_VOLUME_HEADER *RawDataFvHeader;\r
1183 EFI_FIRMWARE_VOLUME_HEADER *MigratedChildFvHeader;\r
1184\r
1185 PEI_CORE_FV_HANDLE PeiCoreFvHandle;\r
1186 EFI_PEI_CORE_FV_LOCATION_PPI *PeiCoreFvLocationPpi;\r
1187 EDKII_MIGRATED_FV_INFO MigratedFvInfo;\r
1188\r
1189 ASSERT (Private->PeiMemoryInstalled);\r
1190\r
1191 DEBUG ((DEBUG_VERBOSE, "Beginning evacuation of content in temporary RAM.\n"));\r
1192\r
1193 //\r
1194 // Migrate PPI Pointers of PEI_CORE from temporary memory to newly loaded PEI_CORE in permanent memory.\r
1195 //\r
1196 Status = PeiLocatePpi ((CONST EFI_PEI_SERVICES **)&Private->Ps, &gEfiPeiCoreFvLocationPpiGuid, 0, NULL, (VOID **)&PeiCoreFvLocationPpi);\r
1197 if (!EFI_ERROR (Status) && (PeiCoreFvLocationPpi->PeiCoreFvLocation != NULL)) {\r
1198 PeiCoreFvHandle.FvHandle = (EFI_PEI_FV_HANDLE)PeiCoreFvLocationPpi->PeiCoreFvLocation;\r
1199 } else {\r
1200 PeiCoreFvHandle.FvHandle = (EFI_PEI_FV_HANDLE)SecCoreData->BootFirmwareVolumeBase;\r
1201 }\r
1202\r
1203 for (FvIndex = 0; FvIndex < Private->FvCount; FvIndex++) {\r
1204 if (Private->Fv[FvIndex].FvHandle == PeiCoreFvHandle.FvHandle) {\r
1205 CopyMem (&PeiCoreFvHandle, &Private->Fv[FvIndex], sizeof (PEI_CORE_FV_HANDLE));\r
1206 break;\r
1207 }\r
1208 }\r
1209\r
1210 Status = EFI_SUCCESS;\r
1211\r
1212 ConvertPeiCorePpiPointers (Private, &PeiCoreFvHandle);\r
1213\r
1214 for (FvIndex = 0; FvIndex < Private->FvCount; FvIndex++) {\r
1215 FvHeader = Private->Fv[FvIndex].FvHeader;\r
1216 ASSERT (FvHeader != NULL);\r
1217 ASSERT (FvIndex < Private->FvCount);\r
1218\r
1219 DEBUG ((DEBUG_VERBOSE, "FV[%02d] at 0x%x.\n", FvIndex, (UINTN)FvHeader));\r
1220 if (\r
1221 !(\r
1222 ((EFI_PHYSICAL_ADDRESS)(UINTN)FvHeader >= Private->PhysicalMemoryBegin) &&\r
1223 (((EFI_PHYSICAL_ADDRESS)(UINTN)FvHeader + (FvHeader->FvLength - 1)) < Private->FreePhysicalMemoryTop)\r
1224 )\r
1225 )\r
1226 {\r
1227 //\r
1228 // Allocate page to save the rebased PEIMs, the PEIMs will get dispatched later.\r
1229 //\r
1230 Status = PeiServicesAllocatePages (\r
1231 EfiBootServicesCode,\r
1232 EFI_SIZE_TO_PAGES ((UINTN)FvHeader->FvLength),\r
1233 &FvHeaderAddress\r
1234 );\r
1235 ASSERT_EFI_ERROR (Status);\r
1236 MigratedFvHeader = (EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)FvHeaderAddress;\r
1237\r
1238 //\r
1239 // Allocate pool to save the raw PEIMs, which is used to keep consistent context across\r
1240 // multiple boot and PCR0 will keep the same no matter if the address of allocated page is changed.\r
1241 //\r
1242 Status = PeiServicesAllocatePages (\r
1243 EfiBootServicesCode,\r
1244 EFI_SIZE_TO_PAGES ((UINTN)FvHeader->FvLength),\r
1245 &FvHeaderAddress\r
1246 );\r
1247 ASSERT_EFI_ERROR (Status);\r
1248 RawDataFvHeader = (EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)FvHeaderAddress;\r
1249\r
1250 DEBUG ((\r
1251 DEBUG_VERBOSE,\r
1252 " Migrating FV[%d] from 0x%08X to 0x%08X\n",\r
1253 FvIndex,\r
1254 (UINTN)FvHeader,\r
1255 (UINTN)MigratedFvHeader\r
1256 ));\r
1257\r
1258 //\r
1259 // Copy the context to the rebased pages and raw pages, and create hob to save the\r
1260 // information. The MigratedFvInfo HOB will never be produced when\r
1261 // PcdMigrateTemporaryRamFirmwareVolumes is FALSE, because the PCD control the\r
1262 // feature.\r
1263 //\r
1264 CopyMem (MigratedFvHeader, FvHeader, (UINTN)FvHeader->FvLength);\r
1265 CopyMem (RawDataFvHeader, MigratedFvHeader, (UINTN)FvHeader->FvLength);\r
1266 MigratedFvInfo.FvOrgBase = (UINT32)(UINTN)FvHeader;\r
1267 MigratedFvInfo.FvNewBase = (UINT32)(UINTN)MigratedFvHeader;\r
1268 MigratedFvInfo.FvDataBase = (UINT32)(UINTN)RawDataFvHeader;\r
1269 MigratedFvInfo.FvLength = (UINT32)(UINTN)FvHeader->FvLength;\r
1270 BuildGuidDataHob (&gEdkiiMigratedFvInfoGuid, &MigratedFvInfo, sizeof (MigratedFvInfo));\r
1271\r
1272 //\r
1273 // Migrate any children for this FV now\r
1274 //\r
1275 for (FvChildIndex = FvIndex; FvChildIndex < Private->FvCount; FvChildIndex++) {\r
1276 ChildFvHeader = Private->Fv[FvChildIndex].FvHeader;\r
1277 if (\r
1278 ((UINTN)ChildFvHeader > (UINTN)FvHeader) &&\r
1279 (((UINTN)ChildFvHeader + ChildFvHeader->FvLength) < ((UINTN)FvHeader) + FvHeader->FvLength)\r
1280 )\r
1281 {\r
1282 DEBUG ((DEBUG_VERBOSE, " Child FV[%02d] is being migrated.\n", FvChildIndex));\r
1283 ChildFvOffset = (UINTN)ChildFvHeader - (UINTN)FvHeader;\r
1284 DEBUG ((DEBUG_VERBOSE, " Child FV offset = 0x%x.\n", ChildFvOffset));\r
1285 MigratedChildFvHeader = (EFI_FIRMWARE_VOLUME_HEADER *)((UINTN)MigratedFvHeader + ChildFvOffset);\r
1286 Private->Fv[FvChildIndex].FvHeader = MigratedChildFvHeader;\r
1287 Private->Fv[FvChildIndex].FvHandle = (EFI_PEI_FV_HANDLE)MigratedChildFvHeader;\r
1288 DEBUG ((DEBUG_VERBOSE, " Child migrated FV header at 0x%x.\n", (UINTN)MigratedChildFvHeader));\r
1289\r
1290 Status = MigratePeimsInFv (Private, FvChildIndex, (UINTN)ChildFvHeader, (UINTN)MigratedChildFvHeader);\r
1291 ASSERT_EFI_ERROR (Status);\r
1292\r
1293 ConvertPpiPointersFv (\r
1294 Private,\r
1295 (UINTN)ChildFvHeader,\r
1296 (UINTN)MigratedChildFvHeader,\r
1297 (UINTN)ChildFvHeader->FvLength - 1\r
1298 );\r
1299\r
1300 ConvertStatusCodeCallbacks (\r
1301 (UINTN)ChildFvHeader,\r
1302 (UINTN)MigratedChildFvHeader,\r
1303 (UINTN)ChildFvHeader->FvLength - 1\r
1304 );\r
1305\r
1306 ConvertFvHob (Private, (UINTN)ChildFvHeader, (UINTN)MigratedChildFvHeader);\r
1307 }\r
1308 }\r
1309\r
1310 Private->Fv[FvIndex].FvHeader = MigratedFvHeader;\r
1311 Private->Fv[FvIndex].FvHandle = (EFI_PEI_FV_HANDLE)MigratedFvHeader;\r
1312\r
1313 Status = MigratePeimsInFv (Private, FvIndex, (UINTN)FvHeader, (UINTN)MigratedFvHeader);\r
1314 ASSERT_EFI_ERROR (Status);\r
1315\r
1316 ConvertPpiPointersFv (\r
1317 Private,\r
1318 (UINTN)FvHeader,\r
1319 (UINTN)MigratedFvHeader,\r
1320 (UINTN)FvHeader->FvLength - 1\r
1321 );\r
1322\r
1323 ConvertStatusCodeCallbacks (\r
1324 (UINTN)FvHeader,\r
1325 (UINTN)MigratedFvHeader,\r
1326 (UINTN)FvHeader->FvLength - 1\r
1327 );\r
1328\r
1329 ConvertFvHob (Private, (UINTN)FvHeader, (UINTN)MigratedFvHeader);\r
1330 }\r
1331 }\r
1332\r
1333 RemoveFvHobsInTemporaryMemory (Private);\r
1334\r
1335 return Status;\r
1336}\r
1337\r
1338/**\r
1339 Conduct PEIM dispatch.\r
1340\r
1341 @param SecCoreData Points to a data structure containing information about the PEI core's operating\r
1342 environment, such as the size and location of temporary RAM, the stack location and\r
1343 the BFV location.\r
1344 @param Private Pointer to the private data passed in from caller\r
1345\r
1346**/\r
1347VOID\r
1348PeiDispatcher (\r
1349 IN CONST EFI_SEC_PEI_HAND_OFF *SecCoreData,\r
1350 IN PEI_CORE_INSTANCE *Private\r
1351 )\r
1352{\r
1353 EFI_STATUS Status;\r
1354 UINT32 Index1;\r
1355 UINT32 Index2;\r
1356 CONST EFI_PEI_SERVICES **PeiServices;\r
1357 EFI_PEI_FILE_HANDLE PeimFileHandle;\r
1358 UINTN FvCount;\r
1359 UINTN PeimCount;\r
1360 UINT32 AuthenticationState;\r
1361 EFI_PHYSICAL_ADDRESS EntryPoint;\r
1362 EFI_PEIM_ENTRY_POINT2 PeimEntryPoint;\r
1363 UINTN SaveCurrentPeimCount;\r
1364 UINTN SaveCurrentFvCount;\r
1365 EFI_PEI_FILE_HANDLE SaveCurrentFileHandle;\r
1366 EFI_FV_FILE_INFO FvFileInfo;\r
1367 PEI_CORE_FV_HANDLE *CoreFvHandle;\r
1368\r
1369 PeiServices = (CONST EFI_PEI_SERVICES **)&Private->Ps;\r
1370 PeimEntryPoint = NULL;\r
1371 PeimFileHandle = NULL;\r
1372 EntryPoint = 0;\r
1373\r
1374 if ((Private->PeiMemoryInstalled) &&\r
1375 (PcdGetBool (PcdMigrateTemporaryRamFirmwareVolumes) ||\r
1376 (Private->HobList.HandoffInformationTable->BootMode != BOOT_ON_S3_RESUME) ||\r
1377 PcdGetBool (PcdShadowPeimOnS3Boot))\r
1378 )\r
1379 {\r
1380 //\r
1381 // Once real memory is available, shadow the RegisterForShadow modules. And meanwhile\r
1382 // update the modules' status from PEIM_STATE_REGISTER_FOR_SHADOW to PEIM_STATE_DONE.\r
1383 //\r
1384 SaveCurrentPeimCount = Private->CurrentPeimCount;\r
1385 SaveCurrentFvCount = Private->CurrentPeimFvCount;\r
1386 SaveCurrentFileHandle = Private->CurrentFileHandle;\r
1387\r
1388 for (Index1 = 0; Index1 < Private->FvCount; Index1++) {\r
1389 for (Index2 = 0; Index2 < Private->Fv[Index1].PeimCount; Index2++) {\r
1390 if (Private->Fv[Index1].PeimState[Index2] == PEIM_STATE_REGISTER_FOR_SHADOW) {\r
1391 PeimFileHandle = Private->Fv[Index1].FvFileHandles[Index2];\r
1392 Private->CurrentFileHandle = PeimFileHandle;\r
1393 Private->CurrentPeimFvCount = Index1;\r
1394 Private->CurrentPeimCount = Index2;\r
1395 Status = PeiLoadImage (\r
1396 (CONST EFI_PEI_SERVICES **)&Private->Ps,\r
1397 PeimFileHandle,\r
1398 PEIM_STATE_REGISTER_FOR_SHADOW,\r
1399 &EntryPoint,\r
1400 &AuthenticationState\r
1401 );\r
1402 if (Status == EFI_SUCCESS) {\r
1403 //\r
1404 // PEIM_STATE_REGISTER_FOR_SHADOW move to PEIM_STATE_DONE\r
1405 //\r
1406 Private->Fv[Index1].PeimState[Index2]++;\r
1407 //\r
1408 // Call the PEIM entry point\r
1409 //\r
1410 PeimEntryPoint = (EFI_PEIM_ENTRY_POINT2)(UINTN)EntryPoint;\r
1411\r
1412 PERF_START_IMAGE_BEGIN (PeimFileHandle);\r
1413 PeimEntryPoint (PeimFileHandle, (const EFI_PEI_SERVICES **)&Private->Ps);\r
1414 PERF_START_IMAGE_END (PeimFileHandle);\r
1415 }\r
1416\r
1417 //\r
1418 // Process the Notify list and dispatch any notifies for\r
1419 // newly installed PPIs.\r
1420 //\r
1421 ProcessDispatchNotifyList (Private);\r
1422 }\r
1423 }\r
1424 }\r
1425\r
1426 Private->CurrentFileHandle = SaveCurrentFileHandle;\r
1427 Private->CurrentPeimFvCount = SaveCurrentFvCount;\r
1428 Private->CurrentPeimCount = SaveCurrentPeimCount;\r
1429 }\r
1430\r
1431 //\r
1432 // This is the main dispatch loop. It will search known FVs for PEIMs and\r
1433 // attempt to dispatch them. If any PEIM gets dispatched through a single\r
1434 // pass of the dispatcher, it will start over from the BFV again to see\r
1435 // if any new PEIMs dependencies got satisfied. With a well ordered\r
1436 // FV where PEIMs are found in the order their dependencies are also\r
1437 // satisfied, this dispatcher should run only once.\r
1438 //\r
1439 do {\r
1440 //\r
1441 // In case that reenter PeiCore happens, the last pass record is still available.\r
1442 //\r
1443 if (!Private->PeimDispatcherReenter) {\r
1444 Private->PeimNeedingDispatch = FALSE;\r
1445 Private->PeimDispatchOnThisPass = FALSE;\r
1446 } else {\r
1447 Private->PeimDispatcherReenter = FALSE;\r
1448 }\r
1449\r
1450 for (FvCount = Private->CurrentPeimFvCount; FvCount < Private->FvCount; FvCount++) {\r
1451 CoreFvHandle = FindNextCoreFvHandle (Private, FvCount);\r
1452 ASSERT (CoreFvHandle != NULL);\r
1453\r
1454 //\r
1455 // If the FV has corresponding EFI_PEI_FIRMWARE_VOLUME_PPI instance, then dispatch it.\r
1456 //\r
1457 if (CoreFvHandle->FvPpi == NULL) {\r
1458 continue;\r
1459 }\r
1460\r
1461 Private->CurrentPeimFvCount = FvCount;\r
1462\r
1463 if (Private->CurrentPeimCount == 0) {\r
1464 //\r
1465 // When going through each FV, at first, search Apriori file to\r
1466 // reorder all PEIMs to ensure the PEIMs in Apriori file to get\r
1467 // dispatch at first.\r
1468 //\r
1469 DiscoverPeimsAndOrderWithApriori (Private, CoreFvHandle);\r
1470 }\r
1471\r
1472 //\r
1473 // Start to dispatch all modules within the current FV.\r
1474 //\r
1475 for (PeimCount = Private->CurrentPeimCount;\r
1476 PeimCount < Private->Fv[FvCount].PeimCount;\r
1477 PeimCount++)\r
1478 {\r
1479 Private->CurrentPeimCount = PeimCount;\r
1480 PeimFileHandle = Private->CurrentFileHandle = Private->CurrentFvFileHandles[PeimCount];\r
1481\r
1482 if (Private->Fv[FvCount].PeimState[PeimCount] == PEIM_STATE_NOT_DISPATCHED) {\r
1483 if (!DepexSatisfied (Private, PeimFileHandle, PeimCount)) {\r
1484 Private->PeimNeedingDispatch = TRUE;\r
1485 } else {\r
1486 Status = CoreFvHandle->FvPpi->GetFileInfo (CoreFvHandle->FvPpi, PeimFileHandle, &FvFileInfo);\r
1487 ASSERT_EFI_ERROR (Status);\r
1488 if (FvFileInfo.FileType == EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE) {\r
1489 //\r
1490 // For FV type file, Produce new FvInfo PPI and FV HOB\r
1491 //\r
1492 Status = ProcessFvFile (Private, &Private->Fv[FvCount], PeimFileHandle);\r
1493 if (Status == EFI_SUCCESS) {\r
1494 //\r
1495 // PEIM_STATE_NOT_DISPATCHED move to PEIM_STATE_DISPATCHED\r
1496 //\r
1497 Private->Fv[FvCount].PeimState[PeimCount]++;\r
1498 Private->PeimDispatchOnThisPass = TRUE;\r
1499 } else {\r
1500 //\r
1501 // The related GuidedSectionExtraction/Decompress PPI for the\r
1502 // encapsulated FV image section may be installed in the rest\r
1503 // of this do-while loop, so need to make another pass.\r
1504 //\r
1505 Private->PeimNeedingDispatch = TRUE;\r
1506 }\r
1507 } else {\r
1508 //\r
1509 // For PEIM driver, Load its entry point\r
1510 //\r
1511 Status = PeiLoadImage (\r
1512 PeiServices,\r
1513 PeimFileHandle,\r
1514 PEIM_STATE_NOT_DISPATCHED,\r
1515 &EntryPoint,\r
1516 &AuthenticationState\r
1517 );\r
1518 if (Status == EFI_SUCCESS) {\r
1519 //\r
1520 // The PEIM has its dependencies satisfied, and its entry point\r
1521 // has been found, so invoke it.\r
1522 //\r
1523 PERF_START_IMAGE_BEGIN (PeimFileHandle);\r
1524\r
1525 REPORT_STATUS_CODE_WITH_EXTENDED_DATA (\r
1526 EFI_PROGRESS_CODE,\r
1527 (EFI_SOFTWARE_PEI_CORE | EFI_SW_PC_INIT_BEGIN),\r
1528 (VOID *)(&PeimFileHandle),\r
1529 sizeof (PeimFileHandle)\r
1530 );\r
1531\r
1532 Status = VerifyPeim (Private, CoreFvHandle->FvHandle, PeimFileHandle, AuthenticationState);\r
1533 if (Status != EFI_SECURITY_VIOLATION) {\r
1534 //\r
1535 // PEIM_STATE_NOT_DISPATCHED move to PEIM_STATE_DISPATCHED\r
1536 //\r
1537 Private->Fv[FvCount].PeimState[PeimCount]++;\r
1538 //\r
1539 // Call the PEIM entry point for PEIM driver\r
1540 //\r
1541 PeimEntryPoint = (EFI_PEIM_ENTRY_POINT2)(UINTN)EntryPoint;\r
1542 PeimEntryPoint (PeimFileHandle, (const EFI_PEI_SERVICES **)PeiServices);\r
1543 Private->PeimDispatchOnThisPass = TRUE;\r
1544 } else {\r
1545 //\r
1546 // The related GuidedSectionExtraction PPI for the\r
1547 // signed PEIM image section may be installed in the rest\r
1548 // of this do-while loop, so need to make another pass.\r
1549 //\r
1550 Private->PeimNeedingDispatch = TRUE;\r
1551 }\r
1552\r
1553 REPORT_STATUS_CODE_WITH_EXTENDED_DATA (\r
1554 EFI_PROGRESS_CODE,\r
1555 (EFI_SOFTWARE_PEI_CORE | EFI_SW_PC_INIT_END),\r
1556 (VOID *)(&PeimFileHandle),\r
1557 sizeof (PeimFileHandle)\r
1558 );\r
1559 PERF_START_IMAGE_END (PeimFileHandle);\r
1560 }\r
1561 }\r
1562\r
1563 PeiCheckAndSwitchStack (SecCoreData, Private);\r
1564\r
1565 //\r
1566 // Process the Notify list and dispatch any notifies for\r
1567 // newly installed PPIs.\r
1568 //\r
1569 ProcessDispatchNotifyList (Private);\r
1570\r
1571 //\r
1572 // Recheck SwitchStackSignal after ProcessDispatchNotifyList()\r
1573 // in case PeiInstallPeiMemory() is done in a callback with\r
1574 // EFI_PEI_PPI_DESCRIPTOR_NOTIFY_DISPATCH.\r
1575 //\r
1576 PeiCheckAndSwitchStack (SecCoreData, Private);\r
1577\r
1578 if ((Private->PeiMemoryInstalled) && (Private->Fv[FvCount].PeimState[PeimCount] == PEIM_STATE_REGISTER_FOR_SHADOW) && \\r
1579 (PcdGetBool (PcdMigrateTemporaryRamFirmwareVolumes) ||\r
1580 (Private->HobList.HandoffInformationTable->BootMode != BOOT_ON_S3_RESUME) ||\r
1581 PcdGetBool (PcdShadowPeimOnS3Boot))\r
1582 )\r
1583 {\r
1584 //\r
1585 // If memory is available we shadow images by default for performance reasons.\r
1586 // We call the entry point a 2nd time so the module knows it's shadowed.\r
1587 //\r
1588 // PERF_START (PeiServices, L"PEIM", PeimFileHandle, 0);\r
1589 if ((Private->HobList.HandoffInformationTable->BootMode != BOOT_ON_S3_RESUME) && !PcdGetBool (PcdShadowPeimOnBoot) &&\r
1590 !PcdGetBool (PcdMigrateTemporaryRamFirmwareVolumes))\r
1591 {\r
1592 //\r
1593 // Load PEIM into Memory for Register for shadow PEIM.\r
1594 //\r
1595 Status = PeiLoadImage (\r
1596 PeiServices,\r
1597 PeimFileHandle,\r
1598 PEIM_STATE_REGISTER_FOR_SHADOW,\r
1599 &EntryPoint,\r
1600 &AuthenticationState\r
1601 );\r
1602 if (Status == EFI_SUCCESS) {\r
1603 PeimEntryPoint = (EFI_PEIM_ENTRY_POINT2)(UINTN)EntryPoint;\r
1604 }\r
1605 }\r
1606\r
1607 ASSERT (PeimEntryPoint != NULL);\r
1608 PeimEntryPoint (PeimFileHandle, (const EFI_PEI_SERVICES **)PeiServices);\r
1609 // PERF_END (PeiServices, L"PEIM", PeimFileHandle, 0);\r
1610\r
1611 //\r
1612 // PEIM_STATE_REGISTER_FOR_SHADOW move to PEIM_STATE_DONE\r
1613 //\r
1614 Private->Fv[FvCount].PeimState[PeimCount]++;\r
1615\r
1616 //\r
1617 // Process the Notify list and dispatch any notifies for\r
1618 // newly installed PPIs.\r
1619 //\r
1620 ProcessDispatchNotifyList (Private);\r
1621 }\r
1622 }\r
1623 }\r
1624 }\r
1625\r
1626 //\r
1627 // Before walking through the next FV, we should set them to NULL/0 to\r
1628 // start at the beginning of the next FV.\r
1629 //\r
1630 Private->CurrentFileHandle = NULL;\r
1631 Private->CurrentPeimCount = 0;\r
1632 Private->CurrentFvFileHandles = NULL;\r
1633 }\r
1634\r
1635 //\r
1636 // Before making another pass, we should set it to 0 to\r
1637 // go through all the FVs.\r
1638 //\r
1639 Private->CurrentPeimFvCount = 0;\r
1640\r
1641 //\r
1642 // PeimNeedingDispatch being TRUE means we found a PEIM/FV that did not get\r
1643 // dispatched. So we need to make another pass\r
1644 //\r
1645 // PeimDispatchOnThisPass being TRUE means we dispatched a PEIM/FV on this\r
1646 // pass. If we did not dispatch a PEIM/FV there is no point in trying again\r
1647 // as it will fail the next time too (nothing has changed).\r
1648 //\r
1649 } while (Private->PeimNeedingDispatch && Private->PeimDispatchOnThisPass);\r
1650}\r
1651\r
1652/**\r
1653 Initialize the Dispatcher's data members\r
1654\r
1655 @param PrivateData PeiCore's private data structure\r
1656 @param OldCoreData Old data from SecCore\r
1657 NULL if being run in non-permanent memory mode.\r
1658 @param SecCoreData Points to a data structure containing information about the PEI core's operating\r
1659 environment, such as the size and location of temporary RAM, the stack location and\r
1660 the BFV location.\r
1661\r
1662 @return None.\r
1663\r
1664**/\r
1665VOID\r
1666InitializeDispatcherData (\r
1667 IN PEI_CORE_INSTANCE *PrivateData,\r
1668 IN PEI_CORE_INSTANCE *OldCoreData,\r
1669 IN CONST EFI_SEC_PEI_HAND_OFF *SecCoreData\r
1670 )\r
1671{\r
1672 if (OldCoreData == NULL) {\r
1673 PrivateData->PeimDispatcherReenter = FALSE;\r
1674 PeiInitializeFv (PrivateData, SecCoreData);\r
1675 } else {\r
1676 PeiReinitializeFv (PrivateData);\r
1677 }\r
1678\r
1679 return;\r
1680}\r
1681\r
1682/**\r
1683 This routine parses the Dependency Expression, if available, and\r
1684 decides if the module can be executed.\r
1685\r
1686\r
1687 @param Private PeiCore's private data structure\r
1688 @param FileHandle PEIM's file handle\r
1689 @param PeimCount Peim count in all dispatched PEIMs.\r
1690\r
1691 @retval TRUE Can be dispatched\r
1692 @retval FALSE Cannot be dispatched\r
1693\r
1694**/\r
1695BOOLEAN\r
1696DepexSatisfied (\r
1697 IN PEI_CORE_INSTANCE *Private,\r
1698 IN EFI_PEI_FILE_HANDLE FileHandle,\r
1699 IN UINTN PeimCount\r
1700 )\r
1701{\r
1702 EFI_STATUS Status;\r
1703 VOID *DepexData;\r
1704 EFI_FV_FILE_INFO FileInfo;\r
1705\r
1706 Status = PeiServicesFfsGetFileInfo (FileHandle, &FileInfo);\r
1707 if (EFI_ERROR (Status)) {\r
1708 DEBUG ((DEBUG_DISPATCH, "Evaluate PEI DEPEX for FFS(Unknown)\n"));\r
1709 } else {\r
1710 DEBUG ((DEBUG_DISPATCH, "Evaluate PEI DEPEX for FFS(%g)\n", &FileInfo.FileName));\r
1711 }\r
1712\r
1713 if (PeimCount < Private->AprioriCount) {\r
1714 //\r
1715 // If it's in the Apriori file then we set DEPEX to TRUE\r
1716 //\r
1717 DEBUG ((DEBUG_DISPATCH, " RESULT = TRUE (Apriori)\n"));\r
1718 return TRUE;\r
1719 }\r
1720\r
1721 //\r
1722 // Depex section not in the encapsulated section.\r
1723 //\r
1724 Status = PeiServicesFfsFindSectionData (\r
1725 EFI_SECTION_PEI_DEPEX,\r
1726 FileHandle,\r
1727 (VOID **)&DepexData\r
1728 );\r
1729\r
1730 if (EFI_ERROR (Status)) {\r
1731 //\r
1732 // If there is no DEPEX, assume the module can be executed\r
1733 //\r
1734 DEBUG ((DEBUG_DISPATCH, " RESULT = TRUE (No DEPEX)\n"));\r
1735 return TRUE;\r
1736 }\r
1737\r
1738 //\r
1739 // Evaluate a given DEPEX\r
1740 //\r
1741 return PeimDispatchReadiness (&Private->Ps, DepexData);\r
1742}\r
1743\r
1744/**\r
1745 This routine enables a PEIM to register itself for shadow when the PEI Foundation\r
1746 discovers permanent memory.\r
1747\r
1748 @param FileHandle File handle of a PEIM.\r
1749\r
1750 @retval EFI_NOT_FOUND The file handle doesn't point to PEIM itself.\r
1751 @retval EFI_ALREADY_STARTED Indicate that the PEIM has been registered itself.\r
1752 @retval EFI_SUCCESS Successfully to register itself.\r
1753\r
1754**/\r
1755EFI_STATUS\r
1756EFIAPI\r
1757PeiRegisterForShadow (\r
1758 IN EFI_PEI_FILE_HANDLE FileHandle\r
1759 )\r
1760{\r
1761 PEI_CORE_INSTANCE *Private;\r
1762\r
1763 Private = PEI_CORE_INSTANCE_FROM_PS_THIS (GetPeiServicesTablePointer ());\r
1764\r
1765 if (Private->CurrentFileHandle != FileHandle) {\r
1766 //\r
1767 // The FileHandle must be for the current PEIM\r
1768 //\r
1769 return EFI_NOT_FOUND;\r
1770 }\r
1771\r
1772 if (Private->Fv[Private->CurrentPeimFvCount].PeimState[Private->CurrentPeimCount] >= PEIM_STATE_REGISTER_FOR_SHADOW) {\r
1773 //\r
1774 // If the PEIM has already entered the PEIM_STATE_REGISTER_FOR_SHADOW or PEIM_STATE_DONE then it's already been started\r
1775 //\r
1776 return EFI_ALREADY_STARTED;\r
1777 }\r
1778\r
1779 Private->Fv[Private->CurrentPeimFvCount].PeimState[Private->CurrentPeimCount] = PEIM_STATE_REGISTER_FOR_SHADOW;\r
1780\r
1781 return EFI_SUCCESS;\r
1782}\r