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