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