1 /** @file
2   EFI PEI Core dispatch services
3 
4 Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution.  The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
9 
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12 
13 **/
14 
15 #include "PeiMain.h"
16 
17 ///
18 /// temporary memory is filled with this initial value during SEC phase
19 ///
20 #define INIT_CAR_VALUE 0x5AA55AA5
21 
22 /**
23 
24   Discover all Peims and optional Apriori file in one FV. There is at most one
25   Apriori file in one FV.
26 
27 
28   @param Private          Pointer to the private data passed in from caller
29   @param CoreFileHandle   The instance of PEI_CORE_FV_HANDLE.
30 
31 **/
32 VOID
DiscoverPeimsAndOrderWithApriori(IN PEI_CORE_INSTANCE * Private,IN PEI_CORE_FV_HANDLE * CoreFileHandle)33 DiscoverPeimsAndOrderWithApriori (
34   IN  PEI_CORE_INSTANCE    *Private,
35   IN  PEI_CORE_FV_HANDLE   *CoreFileHandle
36   )
37 {
38   EFI_STATUS                          Status;
39   EFI_PEI_FILE_HANDLE                 FileHandle;
40   EFI_PEI_FILE_HANDLE                 AprioriFileHandle;
41   EFI_GUID                            *Apriori;
42   UINTN                               Index;
43   UINTN                               Index2;
44   UINTN                               PeimIndex;
45   UINTN                               PeimCount;
46   EFI_GUID                            *Guid;
47   EFI_PEI_FILE_HANDLE                 *TempFileHandles;
48   EFI_GUID                            *FileGuid;
49   EFI_PEI_FIRMWARE_VOLUME_PPI         *FvPpi;
50   EFI_FV_FILE_INFO                    FileInfo;
51 
52   FvPpi = CoreFileHandle->FvPpi;
53 
54   //
55   // Walk the FV and find all the PEIMs and the Apriori file.
56   //
57   AprioriFileHandle = NULL;
58   Private->CurrentFvFileHandles[0] = NULL;
59   Guid = NULL;
60   FileHandle = NULL;
61   TempFileHandles = Private->FileHandles;
62   FileGuid        = Private->FileGuid;
63 
64   //
65   // If the current Fv has been scanned, directly get its cachable record.
66   //
67   if (Private->Fv[Private->CurrentPeimFvCount].ScanFv) {
68     CopyMem (Private->CurrentFvFileHandles, Private->Fv[Private->CurrentPeimFvCount].FvFileHandles, sizeof (EFI_PEI_FILE_HANDLE) * PcdGet32 (PcdPeiCoreMaxPeimPerFv));
69     return;
70   }
71 
72   //
73   // Go ahead to scan this Fv, and cache FileHandles within it.
74   //
75   Status = EFI_NOT_FOUND;
76   for (PeimCount = 0; PeimCount <= PcdGet32 (PcdPeiCoreMaxPeimPerFv); PeimCount++) {
77     Status = FvPpi->FindFileByType (FvPpi, PEI_CORE_INTERNAL_FFS_FILE_DISPATCH_TYPE, CoreFileHandle->FvHandle, &FileHandle);
78     if (Status != EFI_SUCCESS || PeimCount == PcdGet32 (PcdPeiCoreMaxPeimPerFv)) {
79       break;
80     }
81 
82     Private->CurrentFvFileHandles[PeimCount] = FileHandle;
83   }
84 
85   //
86   // Check whether the count of files exceeds the max support files in a FV image
87   // If more files are required in a FV image, PcdPeiCoreMaxPeimPerFv can be set to a larger value in DSC file.
88   //
89   ASSERT ((Status != EFI_SUCCESS) || (PeimCount < PcdGet32 (PcdPeiCoreMaxPeimPerFv)));
90 
91   //
92   // Get Apriori File handle
93   //
94   Private->AprioriCount = 0;
95   Status = FvPpi->FindFileByName (FvPpi, &gPeiAprioriFileNameGuid, &CoreFileHandle->FvHandle, &AprioriFileHandle);
96   if (!EFI_ERROR(Status) && AprioriFileHandle != NULL) {
97     //
98     // Read the Apriori file
99     //
100     Status = FvPpi->FindSectionByType (FvPpi, EFI_SECTION_RAW, AprioriFileHandle, (VOID **) &Apriori);
101     if (!EFI_ERROR (Status)) {
102       //
103       // Calculate the number of PEIMs in the A Priori list
104       //
105       Status = FvPpi->GetFileInfo (FvPpi, AprioriFileHandle, &FileInfo);
106       ASSERT_EFI_ERROR (Status);
107       Private->AprioriCount = FileInfo.BufferSize;
108       if (IS_SECTION2 (FileInfo.Buffer)) {
109         Private->AprioriCount -= sizeof (EFI_COMMON_SECTION_HEADER2);
110       } else {
111         Private->AprioriCount -= sizeof (EFI_COMMON_SECTION_HEADER);
112       }
113       Private->AprioriCount /= sizeof (EFI_GUID);
114 
115       for (Index = 0; Index < PeimCount; Index++) {
116         //
117         // Make an array of file name guids that matches the FileHandle array so we can convert
118         // quickly from file name to file handle
119         //
120         Status = FvPpi->GetFileInfo (FvPpi, Private->CurrentFvFileHandles[Index], &FileInfo);
121         CopyMem (&FileGuid[Index], &FileInfo.FileName, sizeof(EFI_GUID));
122       }
123 
124       //
125       // Walk through FileGuid array to find out who is invalid PEIM guid in Apriori file.
126       // Add available PEIMs in Apriori file into TempFileHandles array at first.
127       //
128       Index2 = 0;
129       for (Index = 0; Index2 < Private->AprioriCount; Index++) {
130         while (Index2 < Private->AprioriCount) {
131           Guid = ScanGuid (FileGuid, PeimCount * sizeof (EFI_GUID), &Apriori[Index2++]);
132           if (Guid != NULL) {
133             break;
134           }
135         }
136         if (Guid == NULL) {
137           break;
138         }
139         PeimIndex = ((UINTN)Guid - (UINTN)&FileGuid[0])/sizeof (EFI_GUID);
140         TempFileHandles[Index] = Private->CurrentFvFileHandles[PeimIndex];
141 
142         //
143         // Since we have copied the file handle we can remove it from this list.
144         //
145         Private->CurrentFvFileHandles[PeimIndex] = NULL;
146       }
147 
148       //
149       // Update valid Aprioricount
150       //
151       Private->AprioriCount = Index;
152 
153       //
154       // Add in any PEIMs not in the Apriori file
155       //
156       for (;Index < PeimCount; Index++) {
157         for (Index2 = 0; Index2 < PeimCount; Index2++) {
158           if (Private->CurrentFvFileHandles[Index2] != NULL) {
159             TempFileHandles[Index] = Private->CurrentFvFileHandles[Index2];
160             Private->CurrentFvFileHandles[Index2] = NULL;
161             break;
162           }
163         }
164       }
165       //
166       //Index the end of array contains re-range Pei moudle.
167       //
168       TempFileHandles[Index] = NULL;
169 
170       //
171       // Private->CurrentFvFileHandles is currently in PEIM in the FV order.
172       // We need to update it to start with files in the A Priori list and
173       // then the remaining files in PEIM order.
174       //
175       CopyMem (Private->CurrentFvFileHandles, TempFileHandles, sizeof (EFI_PEI_FILE_HANDLE) * PcdGet32 (PcdPeiCoreMaxPeimPerFv));
176     }
177   }
178   //
179   // Cache the current Fv File Handle. So that we don't have to scan the Fv again.
180   // Instead, we can retrieve the file handles within this Fv from cachable data.
181   //
182   Private->Fv[Private->CurrentPeimFvCount].ScanFv = TRUE;
183   CopyMem (Private->Fv[Private->CurrentPeimFvCount].FvFileHandles, Private->CurrentFvFileHandles, sizeof (EFI_PEI_FILE_HANDLE) * PcdGet32 (PcdPeiCoreMaxPeimPerFv));
184 
185 }
186 
187 //
188 // This is the minimum memory required by DxeCore initialization. When LMFA feature enabled,
189 // This part of memory still need reserved on the very top of memory so that the DXE Core could
190 // use these memory for data initialization. This macro should be sync with the same marco
191 // defined in DXE Core.
192 //
193 #define MINIMUM_INITIAL_MEMORY_SIZE 0x10000
194 /**
195   This function is to test if the memory range described in resource HOB is available or not.
196 
197   This function should only be invoked when Loading Module at Fixed Address(LMFA) feature is enabled. Some platform may allocate the
198   memory before PeiLoadFixAddressHook in invoked. so this function is to test if the memory range described by the input resource HOB is
199   available or not.
200 
201   @param PrivateData         Pointer to the private data passed in from caller
202   @param ResourceHob         Pointer to a resource HOB which described the memory range described by the input resource HOB
203 **/
204 BOOLEAN
PeiLoadFixAddressIsMemoryRangeAvailable(IN PEI_CORE_INSTANCE * PrivateData,IN EFI_HOB_RESOURCE_DESCRIPTOR * ResourceHob)205 PeiLoadFixAddressIsMemoryRangeAvailable (
206   IN PEI_CORE_INSTANCE                  *PrivateData,
207   IN EFI_HOB_RESOURCE_DESCRIPTOR        *ResourceHob
208   )
209 {
210 	EFI_HOB_MEMORY_ALLOCATION          *MemoryHob;
211 	BOOLEAN                             IsAvailable;
212 	EFI_PEI_HOB_POINTERS                Hob;
213 
214   IsAvailable = TRUE;
215 	if (PrivateData == NULL || ResourceHob == NULL) {
216 	  return FALSE;
217 	}
218 	//
219   // test if the memory range describe in the HOB is already allocated.
220   //
221   for (Hob.Raw = PrivateData->HobList.Raw; !END_OF_HOB_LIST(Hob); Hob.Raw = GET_NEXT_HOB(Hob)) {
222     //
223     // See if this is a memory allocation HOB
224     //
225     if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_MEMORY_ALLOCATION) {
226       MemoryHob = Hob.MemoryAllocation;
227       if(MemoryHob->AllocDescriptor.MemoryBaseAddress == ResourceHob->PhysicalStart &&
228          MemoryHob->AllocDescriptor.MemoryBaseAddress + MemoryHob->AllocDescriptor.MemoryLength == ResourceHob->PhysicalStart + ResourceHob->ResourceLength) {
229          IsAvailable = FALSE;
230          break;
231        }
232      }
233   }
234 
235   return IsAvailable;
236 
237 }
238 /**
239   Hook function for Loading Module at Fixed Address feature
240 
241   This function should only be invoked when Loading Module at Fixed Address(LMFA) feature is enabled. When feature is
242   configured as Load Modules at Fix Absolute Address, this function is to validate the top address assigned by user. When
243   feature is configured as Load Modules at Fixed Offset, the functino is to find the top address which is TOLM-TSEG in general.
244   And also the function will re-install PEI memory.
245 
246   @param PrivateData         Pointer to the private data passed in from caller
247 
248 **/
249 VOID
PeiLoadFixAddressHook(IN PEI_CORE_INSTANCE * PrivateData)250 PeiLoadFixAddressHook(
251   IN PEI_CORE_INSTANCE           *PrivateData
252   )
253 {
254   EFI_PHYSICAL_ADDRESS               TopLoadingAddress;
255   UINT64                             PeiMemorySize;
256   UINT64                             TotalReservedMemorySize;
257   UINT64                             MemoryRangeEnd;
258   EFI_PHYSICAL_ADDRESS               HighAddress;
259   EFI_HOB_RESOURCE_DESCRIPTOR        *ResourceHob;
260   EFI_HOB_RESOURCE_DESCRIPTOR        *NextResourceHob;
261   EFI_HOB_RESOURCE_DESCRIPTOR        *CurrentResourceHob;
262   EFI_PEI_HOB_POINTERS               CurrentHob;
263   EFI_PEI_HOB_POINTERS               Hob;
264   EFI_PEI_HOB_POINTERS               NextHob;
265   EFI_HOB_MEMORY_ALLOCATION          *MemoryHob;
266   //
267   // Initialize Local Variables
268   //
269   CurrentResourceHob    = NULL;
270   ResourceHob           = NULL;
271   NextResourceHob       = NULL;
272   HighAddress           = 0;
273   TopLoadingAddress     = 0;
274   MemoryRangeEnd      = 0;
275   CurrentHob.Raw      = PrivateData->HobList.Raw;
276   PeiMemorySize = PrivateData->PhysicalMemoryLength;
277   //
278   // The top reserved memory include 3 parts: the topest range is for DXE core initialization with the size  MINIMUM_INITIAL_MEMORY_SIZE
279   // then RuntimeCodePage range and Boot time code range.
280   //
281   TotalReservedMemorySize = MINIMUM_INITIAL_MEMORY_SIZE + EFI_PAGES_TO_SIZE(PcdGet32(PcdLoadFixAddressRuntimeCodePageNumber));
282   TotalReservedMemorySize+= EFI_PAGES_TO_SIZE(PcdGet32(PcdLoadFixAddressBootTimeCodePageNumber)) ;
283   //
284   // PEI memory range lies below the top reserved memory
285   //
286   TotalReservedMemorySize += PeiMemorySize;
287 
288   DEBUG ((EFI_D_INFO, "LOADING MODULE FIXED INFO: PcdLoadFixAddressRuntimeCodePageNumber= 0x%x.\n", PcdGet32(PcdLoadFixAddressRuntimeCodePageNumber)));
289   DEBUG ((EFI_D_INFO, "LOADING MODULE FIXED INFO: PcdLoadFixAddressBootTimeCodePageNumber= 0x%x.\n", PcdGet32(PcdLoadFixAddressBootTimeCodePageNumber)));
290   DEBUG ((EFI_D_INFO, "LOADING MODULE FIXED INFO: PcdLoadFixAddressPeiCodePageNumber= 0x%x.\n", PcdGet32(PcdLoadFixAddressPeiCodePageNumber)));
291   DEBUG ((EFI_D_INFO, "LOADING MODULE FIXED INFO: Total Reserved Memory Size = 0x%lx.\n", TotalReservedMemorySize));
292   //
293   // Loop through the system memory typed hob to merge the adjacent memory range
294   //
295   for (Hob.Raw = PrivateData->HobList.Raw; !END_OF_HOB_LIST(Hob); Hob.Raw = GET_NEXT_HOB(Hob)) {
296     //
297     // See if this is a resource descriptor HOB
298     //
299     if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {
300 
301       ResourceHob = Hob.ResourceDescriptor;
302       //
303       // If range described in this hob is not system memory or heigher than MAX_ADDRESS, ignored.
304       //
305       if (ResourceHob->ResourceType != EFI_RESOURCE_SYSTEM_MEMORY ||
306           ResourceHob->PhysicalStart + ResourceHob->ResourceLength > MAX_ADDRESS)   {
307         continue;
308       }
309 
310       for (NextHob.Raw = PrivateData->HobList.Raw; !END_OF_HOB_LIST(NextHob); NextHob.Raw = GET_NEXT_HOB(NextHob)) {
311         if (NextHob.Raw == Hob.Raw){
312           continue;
313         }
314         //
315         // See if this is a resource descriptor HOB
316         //
317         if (GET_HOB_TYPE (NextHob) == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {
318 
319           NextResourceHob = NextHob.ResourceDescriptor;
320           //
321           // test if range described in this NextResourceHob is system memory and have the same attribute.
322           // Note: Here is a assumption that system memory should always be healthy even without test.
323           //
324           if (NextResourceHob->ResourceType == EFI_RESOURCE_SYSTEM_MEMORY &&
325              (((NextResourceHob->ResourceAttribute^ResourceHob->ResourceAttribute)&(~EFI_RESOURCE_ATTRIBUTE_TESTED)) == 0)){
326 
327               //
328               // See if the memory range described in ResourceHob and NextResourceHob is adjacent
329               //
330               if ((ResourceHob->PhysicalStart <= NextResourceHob->PhysicalStart &&
331                     ResourceHob->PhysicalStart + ResourceHob->ResourceLength >= NextResourceHob->PhysicalStart)||
332                   (ResourceHob->PhysicalStart >= NextResourceHob->PhysicalStart&&
333                      ResourceHob->PhysicalStart <= NextResourceHob->PhysicalStart + NextResourceHob->ResourceLength)) {
334 
335                 MemoryRangeEnd = ((ResourceHob->PhysicalStart + ResourceHob->ResourceLength)>(NextResourceHob->PhysicalStart + NextResourceHob->ResourceLength)) ?
336                                      (ResourceHob->PhysicalStart + ResourceHob->ResourceLength):(NextResourceHob->PhysicalStart + NextResourceHob->ResourceLength);
337 
338                 ResourceHob->PhysicalStart = (ResourceHob->PhysicalStart < NextResourceHob->PhysicalStart) ?
339                                                     ResourceHob->PhysicalStart : NextResourceHob->PhysicalStart;
340 
341 
342                 ResourceHob->ResourceLength = (MemoryRangeEnd - ResourceHob->PhysicalStart);
343 
344                 ResourceHob->ResourceAttribute = ResourceHob->ResourceAttribute & (~EFI_RESOURCE_ATTRIBUTE_TESTED);
345                 //
346                 // Delete the NextResourceHob by marking it as unused.
347                 //
348                 GET_HOB_TYPE (NextHob) = EFI_HOB_TYPE_UNUSED;
349 
350               }
351            }
352         }
353       }
354     }
355   }
356   //
357   // Some platform is already allocated pages before the HOB re-org. Here to build dedicated resource HOB to describe
358   //  the allocated memory range
359   //
360   for (Hob.Raw = PrivateData->HobList.Raw; !END_OF_HOB_LIST(Hob); Hob.Raw = GET_NEXT_HOB(Hob)) {
361     //
362     // See if this is a memory allocation HOB
363     //
364     if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_MEMORY_ALLOCATION) {
365       MemoryHob = Hob.MemoryAllocation;
366       for (NextHob.Raw = PrivateData->HobList.Raw; !END_OF_HOB_LIST(NextHob); NextHob.Raw = GET_NEXT_HOB(NextHob)) {
367         //
368         // See if this is a resource descriptor HOB
369         //
370         if (GET_HOB_TYPE (NextHob) == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {
371         	NextResourceHob = NextHob.ResourceDescriptor;
372           //
373           // If range described in this hob is not system memory or heigher than MAX_ADDRESS, ignored.
374           //
375           if (NextResourceHob->ResourceType != EFI_RESOURCE_SYSTEM_MEMORY || NextResourceHob->PhysicalStart + NextResourceHob->ResourceLength > MAX_ADDRESS) {
376             continue;
377           }
378           //
379           // If the range describe in memory allocation HOB  belongs to the memroy range described by the resource hob
380           //
381           if (MemoryHob->AllocDescriptor.MemoryBaseAddress >= NextResourceHob->PhysicalStart &&
382               MemoryHob->AllocDescriptor.MemoryBaseAddress + MemoryHob->AllocDescriptor.MemoryLength <= NextResourceHob->PhysicalStart + NextResourceHob->ResourceLength) {
383              //
384              // Build seperate resource hob for this allocated range
385              //
386              if (MemoryHob->AllocDescriptor.MemoryBaseAddress > NextResourceHob->PhysicalStart) {
387                BuildResourceDescriptorHob (
388                  EFI_RESOURCE_SYSTEM_MEMORY,
389                  NextResourceHob->ResourceAttribute,
390                  NextResourceHob->PhysicalStart,
391                  (MemoryHob->AllocDescriptor.MemoryBaseAddress - NextResourceHob->PhysicalStart)
392                );
393              }
394              if (MemoryHob->AllocDescriptor.MemoryBaseAddress + MemoryHob->AllocDescriptor.MemoryLength < NextResourceHob->PhysicalStart + NextResourceHob->ResourceLength) {
395                BuildResourceDescriptorHob (
396                  EFI_RESOURCE_SYSTEM_MEMORY,
397                  NextResourceHob->ResourceAttribute,
398                  MemoryHob->AllocDescriptor.MemoryBaseAddress + MemoryHob->AllocDescriptor.MemoryLength,
399                  (NextResourceHob->PhysicalStart + NextResourceHob->ResourceLength -(MemoryHob->AllocDescriptor.MemoryBaseAddress + MemoryHob->AllocDescriptor.MemoryLength))
400                );
401              }
402              NextResourceHob->PhysicalStart = MemoryHob->AllocDescriptor.MemoryBaseAddress;
403              NextResourceHob->ResourceLength = MemoryHob->AllocDescriptor.MemoryLength;
404              break;
405           }
406         }
407       }
408     }
409   }
410 
411   //
412   // Try to find and validate the TOP address.
413   //
414   if ((INT64)PcdGet64(PcdLoadModuleAtFixAddressEnable) > 0 ) {
415     //
416     // The LMFA feature is enabled as load module at fixed absolute address.
417     //
418     TopLoadingAddress = (EFI_PHYSICAL_ADDRESS)PcdGet64(PcdLoadModuleAtFixAddressEnable);
419     DEBUG ((EFI_D_INFO, "LOADING MODULE FIXED INFO: Loading module at fixed absolute address.\n"));
420     //
421     // validate the Address. Loop the resource descriptor HOB to make sure the address is in valid memory range
422     //
423     if ((TopLoadingAddress & EFI_PAGE_MASK) != 0) {
424       DEBUG ((EFI_D_INFO, "LOADING MODULE FIXED ERROR:Top Address 0x%lx is invalid since top address should be page align. \n", TopLoadingAddress));
425       ASSERT (FALSE);
426     }
427     //
428     // Search for a memory region that is below MAX_ADDRESS and in which TopLoadingAddress lies
429     //
430     for (Hob.Raw = PrivateData->HobList.Raw; !END_OF_HOB_LIST(Hob); Hob.Raw = GET_NEXT_HOB(Hob)) {
431       //
432       // See if this is a resource descriptor HOB
433       //
434       if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {
435 
436         ResourceHob = Hob.ResourceDescriptor;
437         //
438         // See if this resource descrior HOB describes tested system memory below MAX_ADDRESS
439         //
440         if (ResourceHob->ResourceType == EFI_RESOURCE_SYSTEM_MEMORY &&
441             ResourceHob->PhysicalStart + ResourceHob->ResourceLength <= MAX_ADDRESS) {
442             //
443             // See if Top address specified by user is valid.
444             //
445             if (ResourceHob->PhysicalStart + TotalReservedMemorySize < TopLoadingAddress &&
446                 (ResourceHob->PhysicalStart + ResourceHob->ResourceLength - MINIMUM_INITIAL_MEMORY_SIZE) >= TopLoadingAddress &&
447                 PeiLoadFixAddressIsMemoryRangeAvailable(PrivateData, ResourceHob)) {
448               CurrentResourceHob = ResourceHob;
449               CurrentHob = Hob;
450               break;
451            }
452         }
453       }
454     }
455     if (CurrentResourceHob != NULL) {
456       DEBUG ((EFI_D_INFO, "LOADING MODULE FIXED INFO:Top Address 0x%lx is valid \n",  TopLoadingAddress));
457       TopLoadingAddress += MINIMUM_INITIAL_MEMORY_SIZE;
458     } else {
459       DEBUG ((EFI_D_INFO, "LOADING MODULE FIXED ERROR:Top Address 0x%lx is invalid \n",  TopLoadingAddress));
460       DEBUG ((EFI_D_INFO, "LOADING MODULE FIXED ERROR:The recommended Top Address for the platform is: \n"));
461       //
462       // Print the recomended Top address range.
463       //
464       for (Hob.Raw = PrivateData->HobList.Raw; !END_OF_HOB_LIST(Hob); Hob.Raw = GET_NEXT_HOB(Hob)) {
465         //
466         // See if this is a resource descriptor HOB
467         //
468         if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {
469 
470           ResourceHob = Hob.ResourceDescriptor;
471           //
472           // See if this resource descrior HOB describes tested system memory below MAX_ADDRESS
473           //
474           if (ResourceHob->ResourceType == EFI_RESOURCE_SYSTEM_MEMORY &&
475               ResourceHob->PhysicalStart + ResourceHob->ResourceLength <= MAX_ADDRESS) {
476               //
477               // See if Top address specified by user is valid.
478               //
479               if (ResourceHob->ResourceLength > TotalReservedMemorySize && PeiLoadFixAddressIsMemoryRangeAvailable(PrivateData, ResourceHob)) {
480                  DEBUG ((EFI_D_INFO, "(0x%lx, 0x%lx)\n",
481                           (ResourceHob->PhysicalStart + TotalReservedMemorySize -MINIMUM_INITIAL_MEMORY_SIZE),
482                           (ResourceHob->PhysicalStart + ResourceHob->ResourceLength -MINIMUM_INITIAL_MEMORY_SIZE)
483                         ));
484               }
485           }
486         }
487       }
488       //
489       // Assert here
490       //
491       ASSERT (FALSE);
492       return;
493     }
494   } else {
495     //
496     // The LMFA feature is enabled as load module at fixed offset relative to TOLM
497     // Parse the Hob list to find the topest available memory. Generally it is (TOLM - TSEG)
498     //
499     //
500     // Search for a tested memory region that is below MAX_ADDRESS
501     //
502     for (Hob.Raw = PrivateData->HobList.Raw; !END_OF_HOB_LIST(Hob); Hob.Raw = GET_NEXT_HOB(Hob)) {
503       //
504       // See if this is a resource descriptor HOB
505       //
506       if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {
507 
508         ResourceHob = Hob.ResourceDescriptor;
509         //
510         // See if this resource descrior HOB describes tested system memory below MAX_ADDRESS
511         //
512         if (ResourceHob->ResourceType == EFI_RESOURCE_SYSTEM_MEMORY &&
513             ResourceHob->PhysicalStart + ResourceHob->ResourceLength <= MAX_ADDRESS &&
514             ResourceHob->ResourceLength > TotalReservedMemorySize && PeiLoadFixAddressIsMemoryRangeAvailable(PrivateData, ResourceHob)) {
515           //
516           // See if this is the highest largest system memory region below MaxAddress
517           //
518           if (ResourceHob->PhysicalStart > HighAddress) {
519              CurrentResourceHob = ResourceHob;
520              CurrentHob = Hob;
521              HighAddress = CurrentResourceHob->PhysicalStart;
522           }
523         }
524       }
525     }
526     if (CurrentResourceHob == NULL) {
527       DEBUG ((EFI_D_INFO, "LOADING MODULE FIXED ERROR:The System Memory is too small\n"));
528       //
529       // Assert here
530       //
531       ASSERT (FALSE);
532       return;
533     } else {
534       TopLoadingAddress = CurrentResourceHob->PhysicalStart + CurrentResourceHob->ResourceLength ;
535     }
536   }
537 
538   if (CurrentResourceHob != NULL) {
539     //
540     // rebuild resource HOB for PEI memmory and reserved memory
541     //
542     BuildResourceDescriptorHob (
543       EFI_RESOURCE_SYSTEM_MEMORY,
544       (
545       EFI_RESOURCE_ATTRIBUTE_PRESENT |
546       EFI_RESOURCE_ATTRIBUTE_INITIALIZED |
547       EFI_RESOURCE_ATTRIBUTE_TESTED |
548       EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE |
549       EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE |
550       EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE |
551       EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE
552       ),
553       (TopLoadingAddress - TotalReservedMemorySize),
554       TotalReservedMemorySize
555     );
556     //
557     // rebuild resource for the remain memory if necessary
558     //
559     if (CurrentResourceHob->PhysicalStart < TopLoadingAddress - TotalReservedMemorySize) {
560       BuildResourceDescriptorHob (
561         EFI_RESOURCE_SYSTEM_MEMORY,
562         (
563          EFI_RESOURCE_ATTRIBUTE_PRESENT |
564          EFI_RESOURCE_ATTRIBUTE_INITIALIZED |
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          CurrentResourceHob->PhysicalStart,
571          (TopLoadingAddress - TotalReservedMemorySize - CurrentResourceHob->PhysicalStart)
572        );
573     }
574     if (CurrentResourceHob->PhysicalStart + CurrentResourceHob->ResourceLength  > TopLoadingAddress ) {
575       BuildResourceDescriptorHob (
576         EFI_RESOURCE_SYSTEM_MEMORY,
577         (
578          EFI_RESOURCE_ATTRIBUTE_PRESENT |
579          EFI_RESOURCE_ATTRIBUTE_INITIALIZED |
580          EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE |
581          EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE |
582          EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE |
583          EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE
584          ),
585          TopLoadingAddress,
586          (CurrentResourceHob->PhysicalStart + CurrentResourceHob->ResourceLength  - TopLoadingAddress)
587        );
588     }
589     //
590     // Delete CurrentHob by marking it as unused since the the memory range described by is rebuilt.
591     //
592     GET_HOB_TYPE (CurrentHob) = EFI_HOB_TYPE_UNUSED;
593   }
594 
595   //
596   // Cache the top address for Loading Module at Fixed Address feature
597   //
598   PrivateData->LoadModuleAtFixAddressTopAddress = TopLoadingAddress - MINIMUM_INITIAL_MEMORY_SIZE;
599   DEBUG ((EFI_D_INFO, "LOADING MODULE FIXED INFO: Top address = 0x%lx\n",  PrivateData->LoadModuleAtFixAddressTopAddress));
600   //
601   // reinstall the PEI memory relative to TopLoadingAddress
602   //
603   PrivateData->PhysicalMemoryBegin   = TopLoadingAddress - TotalReservedMemorySize;
604   PrivateData->FreePhysicalMemoryTop = PrivateData->PhysicalMemoryBegin + PeiMemorySize;
605 }
606 
607 /**
608   This routine is invoked in switch stack as PeiCore Entry.
609 
610   @param SecCoreData     Points to a data structure containing information about the PEI core's operating
611                          environment, such as the size and location of temporary RAM, the stack location and
612                          the BFV location.
613   @param Private         Pointer to old core data that is used to initialize the
614                          core's data areas.
615 **/
616 VOID
617 EFIAPI
PeiCoreEntry(IN CONST EFI_SEC_PEI_HAND_OFF * SecCoreData,IN PEI_CORE_INSTANCE * Private)618 PeiCoreEntry (
619   IN CONST EFI_SEC_PEI_HAND_OFF    *SecCoreData,
620   IN PEI_CORE_INSTANCE             *Private
621   )
622 {
623   //
624   // Entry PEI Phase 2
625   //
626   PeiCore (SecCoreData, NULL, Private);
627 }
628 
629 /**
630   Check SwitchStackSignal and switch stack if SwitchStackSignal is TRUE.
631 
632   @param[in] SecCoreData    Points to a data structure containing information about the PEI core's operating
633                             environment, such as the size and location of temporary RAM, the stack location and
634                             the BFV location.
635   @param[in] Private        Pointer to the private data passed in from caller.
636 
637 **/
638 VOID
PeiCheckAndSwitchStack(IN CONST EFI_SEC_PEI_HAND_OFF * SecCoreData,IN PEI_CORE_INSTANCE * Private)639 PeiCheckAndSwitchStack (
640   IN CONST EFI_SEC_PEI_HAND_OFF         *SecCoreData,
641   IN PEI_CORE_INSTANCE                  *Private
642   )
643 {
644   VOID                                  *LoadFixPeiCodeBegin;
645   EFI_STATUS                            Status;
646   CONST EFI_PEI_SERVICES                **PeiServices;
647   UINT64                                NewStackSize;
648   EFI_PHYSICAL_ADDRESS                  TopOfOldStack;
649   EFI_PHYSICAL_ADDRESS                  TopOfNewStack;
650   UINTN                                 StackOffset;
651   BOOLEAN                               StackOffsetPositive;
652   EFI_PHYSICAL_ADDRESS                  TemporaryRamBase;
653   UINTN                                 TemporaryRamSize;
654   UINTN                                 TemporaryStackSize;
655   VOID                                  *TemporaryStackBase;
656   UINTN                                 PeiTemporaryRamSize;
657   VOID                                  *PeiTemporaryRamBase;
658   EFI_PEI_TEMPORARY_RAM_SUPPORT_PPI     *TemporaryRamSupportPpi;
659   EFI_PHYSICAL_ADDRESS                  BaseOfNewHeap;
660   EFI_PHYSICAL_ADDRESS                  HoleMemBase;
661   UINTN                                 HoleMemSize;
662   UINTN                                 HeapTemporaryRamSize;
663   EFI_PHYSICAL_ADDRESS                  TempBase1;
664   UINTN                                 TempSize1;
665   EFI_PHYSICAL_ADDRESS                  TempBase2;
666   UINTN                                 TempSize2;
667   UINTN                                 Index;
668 
669   PeiServices = (CONST EFI_PEI_SERVICES **) &Private->Ps;
670 
671   if (Private->SwitchStackSignal) {
672     //
673     // Before switch stack from temporary memory to permenent memory, calculate the heap and stack
674     // usage in temporary memory for debuging.
675     //
676     DEBUG_CODE_BEGIN ();
677       UINT32  *StackPointer;
678 
679       for (StackPointer = (UINT32*)SecCoreData->StackBase;
680            (StackPointer < (UINT32*)((UINTN)SecCoreData->StackBase + SecCoreData->StackSize)) \
681            && (*StackPointer == INIT_CAR_VALUE);
682            StackPointer ++);
683 
684       DEBUG ((EFI_D_INFO, "Temp Stack : BaseAddress=0x%p Length=0x%X\n", SecCoreData->StackBase, (UINT32)SecCoreData->StackSize));
685       DEBUG ((EFI_D_INFO, "Temp Heap  : BaseAddress=0x%p Length=0x%X\n", Private->HobList.Raw, (UINT32)((UINTN) Private->HobList.HandoffInformationTable->EfiFreeMemoryBottom - (UINTN) Private->HobList.Raw)));
686       DEBUG ((EFI_D_INFO, "Total temporary memory:    %d bytes.\n", (UINT32)SecCoreData->TemporaryRamSize));
687       DEBUG ((EFI_D_INFO, "  temporary memory stack ever used: %d bytes.\n",
688              (UINT32)(SecCoreData->StackSize - ((UINTN) StackPointer - (UINTN)SecCoreData->StackBase))
689             ));
690       DEBUG ((EFI_D_INFO, "  temporary memory heap used:       %d bytes.\n",
691              (UINT32)((UINTN)Private->HobList.HandoffInformationTable->EfiFreeMemoryBottom - (UINTN)Private->HobList.Raw)
692             ));
693     DEBUG_CODE_END ();
694 
695     if (PcdGet64(PcdLoadModuleAtFixAddressEnable) != 0 && (Private->HobList.HandoffInformationTable->BootMode != BOOT_ON_S3_RESUME)) {
696       //
697       // Loading Module at Fixed Address is enabled
698       //
699       PeiLoadFixAddressHook (Private);
700 
701       //
702       // If Loading Module at Fixed Address is enabled, Allocating memory range for Pei code range.
703       //
704       LoadFixPeiCodeBegin = AllocatePages((UINTN)PcdGet32(PcdLoadFixAddressPeiCodePageNumber));
705       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)));
706     }
707 
708     //
709     // Reserve the size of new stack at bottom of physical memory
710     //
711     // The size of new stack in permenent memory must be the same size
712     // or larger than the size of old stack in temporary memory.
713     // But if new stack is smaller than the size of old stack, we also reserve
714     // the size of old stack at bottom of permenent memory.
715     //
716     NewStackSize = RShiftU64 (Private->PhysicalMemoryLength, 1);
717     NewStackSize = ALIGN_VALUE (NewStackSize, EFI_PAGE_SIZE);
718     NewStackSize = MIN (PcdGet32(PcdPeiCoreMaxPeiStackSize), NewStackSize);
719     DEBUG ((EFI_D_INFO, "Old Stack size %d, New stack size %d\n", (UINT32)SecCoreData->StackSize, (UINT32)NewStackSize));
720     ASSERT (NewStackSize >= SecCoreData->StackSize);
721 
722     //
723     // Calculate stack offset and heap offset between temporary memory and new permement
724     // memory seperately.
725     //
726     TopOfOldStack = (UINTN)SecCoreData->StackBase + SecCoreData->StackSize;
727     TopOfNewStack = Private->PhysicalMemoryBegin + NewStackSize;
728     if (TopOfNewStack >= TopOfOldStack) {
729       StackOffsetPositive = TRUE;
730       StackOffset = (UINTN)(TopOfNewStack - TopOfOldStack);
731     } else {
732       StackOffsetPositive = FALSE;
733       StackOffset = (UINTN)(TopOfOldStack - TopOfNewStack);
734     }
735     Private->StackOffsetPositive = StackOffsetPositive;
736     Private->StackOffset = StackOffset;
737 
738     //
739     // Build Stack HOB that describes the permanent memory stack
740     //
741     DEBUG ((EFI_D_INFO, "Stack Hob: BaseAddress=0x%lX Length=0x%lX\n", TopOfNewStack - NewStackSize, NewStackSize));
742     BuildStackHob (TopOfNewStack - NewStackSize, NewStackSize);
743 
744     //
745     // Cache information from SecCoreData into locals before SecCoreData is converted to a permanent memory address
746     //
747     TemporaryRamBase    = (EFI_PHYSICAL_ADDRESS)(UINTN)SecCoreData->TemporaryRamBase;
748     TemporaryRamSize    = SecCoreData->TemporaryRamSize;
749     TemporaryStackSize  = SecCoreData->StackSize;
750     TemporaryStackBase  = SecCoreData->StackBase;
751     PeiTemporaryRamSize = SecCoreData->PeiTemporaryRamSize;
752     PeiTemporaryRamBase = SecCoreData->PeiTemporaryRamBase;
753 
754     //
755     // TemporaryRamSupportPpi is produced by platform's SEC
756     //
757     Status = PeiServicesLocatePpi (
758                &gEfiTemporaryRamSupportPpiGuid,
759                0,
760                NULL,
761                (VOID**)&TemporaryRamSupportPpi
762                );
763     if (!EFI_ERROR (Status)) {
764       //
765       // Heap Offset
766       //
767       BaseOfNewHeap = TopOfNewStack;
768       if (BaseOfNewHeap >= (UINTN)SecCoreData->PeiTemporaryRamBase) {
769         Private->HeapOffsetPositive = TRUE;
770         Private->HeapOffset = (UINTN)(BaseOfNewHeap - (UINTN)SecCoreData->PeiTemporaryRamBase);
771       } else {
772         Private->HeapOffsetPositive = FALSE;
773         Private->HeapOffset = (UINTN)((UINTN)SecCoreData->PeiTemporaryRamBase - BaseOfNewHeap);
774       }
775 
776       DEBUG ((EFI_D_INFO, "Heap Offset = 0x%lX Stack Offset = 0x%lX\n", (UINT64) Private->HeapOffset, (UINT64) Private->StackOffset));
777 
778       //
779       // Calculate new HandOffTable and PrivateData address in permanent memory's stack
780       //
781       if (StackOffsetPositive) {
782         SecCoreData = (CONST EFI_SEC_PEI_HAND_OFF *)((UINTN)(VOID *)SecCoreData + StackOffset);
783         Private = (PEI_CORE_INSTANCE *)((UINTN)(VOID *)Private + StackOffset);
784       } else {
785         SecCoreData = (CONST EFI_SEC_PEI_HAND_OFF *)((UINTN)(VOID *)SecCoreData - StackOffset);
786         Private = (PEI_CORE_INSTANCE *)((UINTN)(VOID *)Private - StackOffset);
787       }
788 
789       //
790       // Temporary Ram Support PPI is provided by platform, it will copy
791       // temporary memory to permenent memory and do stack switching.
792       // After invoking Temporary Ram Support PPI, the following code's
793       // stack is in permanent memory.
794       //
795       TemporaryRamSupportPpi->TemporaryRamMigration (
796                                 PeiServices,
797                                 TemporaryRamBase,
798                                 (EFI_PHYSICAL_ADDRESS)(UINTN)(TopOfNewStack - TemporaryStackSize),
799                                 TemporaryRamSize
800                                 );
801 
802       //
803       // Entry PEI Phase 2
804       //
805       PeiCore (SecCoreData, NULL, Private);
806     } else {
807       //
808       // Migrate the PEI Services Table pointer from temporary RAM to permanent RAM.
809       //
810       MigratePeiServicesTablePointer ();
811 
812       //
813       // Heap Offset
814       //
815       BaseOfNewHeap = TopOfNewStack;
816       HoleMemBase   = TopOfNewStack;
817       HoleMemSize   = TemporaryRamSize - PeiTemporaryRamSize - TemporaryStackSize;
818       if (HoleMemSize != 0) {
819         //
820         // Make sure HOB List start address is 8 byte alignment.
821         //
822         BaseOfNewHeap = ALIGN_VALUE (BaseOfNewHeap + HoleMemSize, 8);
823       }
824       if (BaseOfNewHeap >= (UINTN)SecCoreData->PeiTemporaryRamBase) {
825         Private->HeapOffsetPositive = TRUE;
826         Private->HeapOffset = (UINTN)(BaseOfNewHeap - (UINTN)SecCoreData->PeiTemporaryRamBase);
827       } else {
828         Private->HeapOffsetPositive = FALSE;
829         Private->HeapOffset = (UINTN)((UINTN)SecCoreData->PeiTemporaryRamBase - BaseOfNewHeap);
830       }
831 
832       DEBUG ((EFI_D_INFO, "Heap Offset = 0x%lX Stack Offset = 0x%lX\n", (UINT64) Private->HeapOffset, (UINT64) Private->StackOffset));
833 
834       //
835       // Migrate Heap
836       //
837       HeapTemporaryRamSize = (UINTN) (Private->HobList.HandoffInformationTable->EfiFreeMemoryBottom - Private->HobList.HandoffInformationTable->EfiMemoryBottom);
838       ASSERT (BaseOfNewHeap + HeapTemporaryRamSize <= Private->FreePhysicalMemoryTop);
839       CopyMem ((UINT8 *) (UINTN) BaseOfNewHeap, (UINT8 *) PeiTemporaryRamBase, HeapTemporaryRamSize);
840 
841       //
842       // Migrate Stack
843       //
844       CopyMem ((UINT8 *) (UINTN) (TopOfNewStack - TemporaryStackSize), TemporaryStackBase, TemporaryStackSize);
845 
846       //
847       // Copy Hole Range Data
848       // Convert PPI from Hole.
849       //
850       if (HoleMemSize != 0) {
851         //
852         // Prepare Hole
853         //
854         if (PeiTemporaryRamBase < TemporaryStackBase) {
855           TempBase1 = (EFI_PHYSICAL_ADDRESS) (UINTN) PeiTemporaryRamBase;
856           TempSize1 = PeiTemporaryRamSize;
857           TempBase2 = (EFI_PHYSICAL_ADDRESS) (UINTN) TemporaryStackBase;
858           TempSize2 = TemporaryStackSize;
859         } else {
860           TempBase1 = (EFI_PHYSICAL_ADDRESS) (UINTN) TemporaryStackBase;
861           TempSize1 = TemporaryStackSize;
862           TempBase2 =(EFI_PHYSICAL_ADDRESS) (UINTN) PeiTemporaryRamBase;
863           TempSize2 = PeiTemporaryRamSize;
864         }
865         if (TemporaryRamBase < TempBase1) {
866           Private->HoleData[0].Base = TemporaryRamBase;
867           Private->HoleData[0].Size = (UINTN) (TempBase1 - TemporaryRamBase);
868         }
869         if (TempBase1 + TempSize1 < TempBase2) {
870           Private->HoleData[1].Base = TempBase1 + TempSize1;
871           Private->HoleData[1].Size = (UINTN) (TempBase2 - TempBase1 - TempSize1);
872         }
873         if (TempBase2 + TempSize2 < TemporaryRamBase + TemporaryRamSize) {
874           Private->HoleData[2].Base = TempBase2 + TempSize2;
875           Private->HoleData[2].Size = (UINTN) (TemporaryRamBase + TemporaryRamSize - TempBase2 - TempSize2);
876         }
877 
878         //
879         // Copy Hole Range data.
880         //
881         for (Index = 0; Index < HOLE_MAX_NUMBER; Index ++) {
882           if (Private->HoleData[Index].Size > 0) {
883             if (HoleMemBase > Private->HoleData[Index].Base) {
884               Private->HoleData[Index].OffsetPositive = TRUE;
885               Private->HoleData[Index].Offset = (UINTN) (HoleMemBase - Private->HoleData[Index].Base);
886             } else {
887               Private->HoleData[Index].OffsetPositive = FALSE;
888               Private->HoleData[Index].Offset = (UINTN) (Private->HoleData[Index].Base - HoleMemBase);
889             }
890             CopyMem ((VOID *) (UINTN) HoleMemBase, (VOID *) (UINTN) Private->HoleData[Index].Base, Private->HoleData[Index].Size);
891             HoleMemBase = HoleMemBase + Private->HoleData[Index].Size;
892           }
893         }
894       }
895 
896       //
897       // Switch new stack
898       //
899       SwitchStack (
900         (SWITCH_STACK_ENTRY_POINT)(UINTN)PeiCoreEntry,
901         (VOID *) SecCoreData,
902         (VOID *) Private,
903         (VOID *) (UINTN) TopOfNewStack
904         );
905     }
906 
907     //
908     // Code should not come here
909     //
910     ASSERT (FALSE);
911   }
912 }
913 
914 /**
915   Conduct PEIM dispatch.
916 
917   @param SecCoreData     Points to a data structure containing information about the PEI core's operating
918                          environment, such as the size and location of temporary RAM, the stack location and
919                          the BFV location.
920   @param Private         Pointer to the private data passed in from caller
921 
922 **/
923 VOID
PeiDispatcher(IN CONST EFI_SEC_PEI_HAND_OFF * SecCoreData,IN PEI_CORE_INSTANCE * Private)924 PeiDispatcher (
925   IN CONST EFI_SEC_PEI_HAND_OFF  *SecCoreData,
926   IN PEI_CORE_INSTANCE           *Private
927   )
928 {
929   EFI_STATUS                          Status;
930   UINT32                              Index1;
931   UINT32                              Index2;
932   CONST EFI_PEI_SERVICES              **PeiServices;
933   EFI_PEI_FILE_HANDLE                 PeimFileHandle;
934   UINTN                               FvCount;
935   UINTN                               PeimCount;
936   UINT32                              AuthenticationState;
937   EFI_PHYSICAL_ADDRESS                EntryPoint;
938   EFI_PEIM_ENTRY_POINT2               PeimEntryPoint;
939   UINTN                               SaveCurrentPeimCount;
940   UINTN                               SaveCurrentFvCount;
941   EFI_PEI_FILE_HANDLE                 SaveCurrentFileHandle;
942   EFI_FV_FILE_INFO                    FvFileInfo;
943   PEI_CORE_FV_HANDLE                  *CoreFvHandle;
944 
945   PeiServices = (CONST EFI_PEI_SERVICES **) &Private->Ps;
946   PeimEntryPoint = NULL;
947   PeimFileHandle = NULL;
948   EntryPoint     = 0;
949 
950   if ((Private->PeiMemoryInstalled) && (Private->HobList.HandoffInformationTable->BootMode != BOOT_ON_S3_RESUME || PcdGetBool (PcdShadowPeimOnS3Boot))) {
951     //
952     // Once real memory is available, shadow the RegisterForShadow modules. And meanwhile
953     // update the modules' status from PEIM_STATE_REGISITER_FOR_SHADOW to PEIM_STATE_DONE.
954     //
955     SaveCurrentPeimCount  = Private->CurrentPeimCount;
956     SaveCurrentFvCount    = Private->CurrentPeimFvCount;
957     SaveCurrentFileHandle =  Private->CurrentFileHandle;
958 
959     for (Index1 = 0; Index1 <= SaveCurrentFvCount; Index1++) {
960       for (Index2 = 0; (Index2 < PcdGet32 (PcdPeiCoreMaxPeimPerFv)) && (Private->Fv[Index1].FvFileHandles[Index2] != NULL); Index2++) {
961         if (Private->Fv[Index1].PeimState[Index2] == PEIM_STATE_REGISITER_FOR_SHADOW) {
962           PeimFileHandle = Private->Fv[Index1].FvFileHandles[Index2];
963           Private->CurrentFileHandle   = PeimFileHandle;
964           Private->CurrentPeimFvCount  = Index1;
965           Private->CurrentPeimCount    = Index2;
966           Status = PeiLoadImage (
967                     (CONST EFI_PEI_SERVICES **) &Private->Ps,
968                     PeimFileHandle,
969                     PEIM_STATE_REGISITER_FOR_SHADOW,
970                     &EntryPoint,
971                     &AuthenticationState
972                     );
973           if (Status == EFI_SUCCESS) {
974             //
975             // PEIM_STATE_REGISITER_FOR_SHADOW move to PEIM_STATE_DONE
976             //
977             Private->Fv[Index1].PeimState[Index2]++;
978             //
979             // Call the PEIM entry point
980             //
981             PeimEntryPoint = (EFI_PEIM_ENTRY_POINT2)(UINTN)EntryPoint;
982 
983             PERF_START (PeimFileHandle, "PEIM", NULL, 0);
984             PeimEntryPoint(PeimFileHandle, (const EFI_PEI_SERVICES **) &Private->Ps);
985             PERF_END (PeimFileHandle, "PEIM", NULL, 0);
986           }
987 
988           //
989           // Process the Notify list and dispatch any notifies for
990           // newly installed PPIs.
991           //
992           ProcessNotifyList (Private);
993         }
994       }
995     }
996     Private->CurrentFileHandle  = SaveCurrentFileHandle;
997     Private->CurrentPeimFvCount = SaveCurrentFvCount;
998     Private->CurrentPeimCount   = SaveCurrentPeimCount;
999   }
1000 
1001   //
1002   // This is the main dispatch loop.  It will search known FVs for PEIMs and
1003   // attempt to dispatch them.  If any PEIM gets dispatched through a single
1004   // pass of the dispatcher, it will start over from the Bfv again to see
1005   // if any new PEIMs dependencies got satisfied.  With a well ordered
1006   // FV where PEIMs are found in the order their dependencies are also
1007   // satisfied, this dipatcher should run only once.
1008   //
1009   do {
1010     //
1011     // In case that reenter PeiCore happens, the last pass record is still available.
1012     //
1013     if (!Private->PeimDispatcherReenter) {
1014       Private->PeimNeedingDispatch      = FALSE;
1015       Private->PeimDispatchOnThisPass   = FALSE;
1016     } else {
1017       Private->PeimDispatcherReenter    = FALSE;
1018     }
1019 
1020     for (FvCount = Private->CurrentPeimFvCount; FvCount < Private->FvCount; FvCount++) {
1021       CoreFvHandle = FindNextCoreFvHandle (Private, FvCount);
1022       ASSERT (CoreFvHandle != NULL);
1023 
1024       //
1025       // If the FV has corresponding EFI_PEI_FIRMWARE_VOLUME_PPI instance, then dispatch it.
1026       //
1027       if (CoreFvHandle->FvPpi == NULL) {
1028         continue;
1029       }
1030 
1031       Private->CurrentPeimFvCount = FvCount;
1032 
1033       if (Private->CurrentPeimCount == 0) {
1034         //
1035         // When going through each FV, at first, search Apriori file to
1036         // reorder all PEIMs to ensure the PEIMs in Apriori file to get
1037         // dispatch at first.
1038         //
1039         DiscoverPeimsAndOrderWithApriori (Private, CoreFvHandle);
1040       }
1041 
1042       //
1043       // Start to dispatch all modules within the current Fv.
1044       //
1045       for (PeimCount = Private->CurrentPeimCount;
1046            (PeimCount < PcdGet32 (PcdPeiCoreMaxPeimPerFv)) && (Private->CurrentFvFileHandles[PeimCount] != NULL);
1047            PeimCount++) {
1048         Private->CurrentPeimCount  = PeimCount;
1049         PeimFileHandle = Private->CurrentFileHandle = Private->CurrentFvFileHandles[PeimCount];
1050 
1051         if (Private->Fv[FvCount].PeimState[PeimCount] == PEIM_STATE_NOT_DISPATCHED) {
1052           if (!DepexSatisfied (Private, PeimFileHandle, PeimCount)) {
1053             Private->PeimNeedingDispatch = TRUE;
1054           } else {
1055             Status = CoreFvHandle->FvPpi->GetFileInfo (CoreFvHandle->FvPpi, PeimFileHandle, &FvFileInfo);
1056             ASSERT_EFI_ERROR (Status);
1057             if (FvFileInfo.FileType == EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE) {
1058               //
1059               // For Fv type file, Produce new FvInfo PPI and FV hob
1060               //
1061               Status = ProcessFvFile (Private, &Private->Fv[FvCount], PeimFileHandle);
1062               if (Status == EFI_SUCCESS) {
1063                 //
1064                 // PEIM_STATE_NOT_DISPATCHED move to PEIM_STATE_DISPATCHED
1065                 //
1066                 Private->Fv[FvCount].PeimState[PeimCount]++;
1067                 Private->PeimDispatchOnThisPass = TRUE;
1068               } else {
1069                 //
1070                 // The related GuidedSectionExtraction/Decompress PPI for the
1071                 // encapsulated FV image section may be installed in the rest
1072                 // of this do-while loop, so need to make another pass.
1073                 //
1074                 Private->PeimNeedingDispatch = TRUE;
1075               }
1076             } else {
1077               //
1078               // For PEIM driver, Load its entry point
1079               //
1080               Status = PeiLoadImage (
1081                          PeiServices,
1082                          PeimFileHandle,
1083                          PEIM_STATE_NOT_DISPATCHED,
1084                          &EntryPoint,
1085                          &AuthenticationState
1086                          );
1087               if (Status == EFI_SUCCESS) {
1088                 //
1089                 // The PEIM has its dependencies satisfied, and its entry point
1090                 // has been found, so invoke it.
1091                 //
1092                 PERF_START (PeimFileHandle, "PEIM", NULL, 0);
1093 
1094                 REPORT_STATUS_CODE_WITH_EXTENDED_DATA (
1095                   EFI_PROGRESS_CODE,
1096                   (EFI_SOFTWARE_PEI_CORE | EFI_SW_PC_INIT_BEGIN),
1097                   (VOID *)(&PeimFileHandle),
1098                   sizeof (PeimFileHandle)
1099                   );
1100 
1101                 Status = VerifyPeim (Private, CoreFvHandle->FvHandle, PeimFileHandle, AuthenticationState);
1102                 if (Status != EFI_SECURITY_VIOLATION) {
1103                   //
1104                   // PEIM_STATE_NOT_DISPATCHED move to PEIM_STATE_DISPATCHED
1105                   //
1106                   Private->Fv[FvCount].PeimState[PeimCount]++;
1107                   //
1108                   // Call the PEIM entry point for PEIM driver
1109                   //
1110                   PeimEntryPoint = (EFI_PEIM_ENTRY_POINT2)(UINTN)EntryPoint;
1111                   PeimEntryPoint (PeimFileHandle, (const EFI_PEI_SERVICES **) PeiServices);
1112                   Private->PeimDispatchOnThisPass = TRUE;
1113                 }
1114 
1115                 REPORT_STATUS_CODE_WITH_EXTENDED_DATA (
1116                   EFI_PROGRESS_CODE,
1117                   (EFI_SOFTWARE_PEI_CORE | EFI_SW_PC_INIT_END),
1118                   (VOID *)(&PeimFileHandle),
1119                   sizeof (PeimFileHandle)
1120                   );
1121                 PERF_END (PeimFileHandle, "PEIM", NULL, 0);
1122 
1123               }
1124             }
1125 
1126             PeiCheckAndSwitchStack (SecCoreData, Private);
1127 
1128             //
1129             // Process the Notify list and dispatch any notifies for
1130             // newly installed PPIs.
1131             //
1132             ProcessNotifyList (Private);
1133 
1134             //
1135             // Recheck SwitchStackSignal after ProcessNotifyList()
1136             // in case PeiInstallPeiMemory() is done in a callback with
1137             // EFI_PEI_PPI_DESCRIPTOR_NOTIFY_DISPATCH.
1138             //
1139             PeiCheckAndSwitchStack (SecCoreData, Private);
1140 
1141             if ((Private->PeiMemoryInstalled) && (Private->Fv[FvCount].PeimState[PeimCount] == PEIM_STATE_REGISITER_FOR_SHADOW) &&   \
1142                 (Private->HobList.HandoffInformationTable->BootMode != BOOT_ON_S3_RESUME || PcdGetBool (PcdShadowPeimOnS3Boot))) {
1143               //
1144               // If memory is availble we shadow images by default for performance reasons.
1145               // We call the entry point a 2nd time so the module knows it's shadowed.
1146               //
1147               //PERF_START (PeiServices, L"PEIM", PeimFileHandle, 0);
1148               if ((Private->HobList.HandoffInformationTable->BootMode != BOOT_ON_S3_RESUME) && !PcdGetBool (PcdShadowPeimOnBoot)) {
1149                 //
1150                 // Load PEIM into Memory for Register for shadow PEIM.
1151                 //
1152                 Status = PeiLoadImage (
1153                            PeiServices,
1154                            PeimFileHandle,
1155                            PEIM_STATE_REGISITER_FOR_SHADOW,
1156                            &EntryPoint,
1157                            &AuthenticationState
1158                            );
1159                 if (Status == EFI_SUCCESS) {
1160                   PeimEntryPoint = (EFI_PEIM_ENTRY_POINT2)(UINTN)EntryPoint;
1161                 }
1162               }
1163               ASSERT (PeimEntryPoint != NULL);
1164               PeimEntryPoint (PeimFileHandle, (const EFI_PEI_SERVICES **) PeiServices);
1165               //PERF_END (PeiServices, L"PEIM", PeimFileHandle, 0);
1166 
1167               //
1168               // PEIM_STATE_REGISITER_FOR_SHADOW move to PEIM_STATE_DONE
1169               //
1170               Private->Fv[FvCount].PeimState[PeimCount]++;
1171 
1172               //
1173               // Process the Notify list and dispatch any notifies for
1174               // newly installed PPIs.
1175               //
1176               ProcessNotifyList (Private);
1177             }
1178           }
1179         }
1180       }
1181 
1182       //
1183       // We set to NULL here to optimize the 2nd entry to this routine after
1184       //  memory is found. This reprevents rescanning of the FV. We set to
1185       //  NULL here so we start at the begining of the next FV
1186       //
1187       Private->CurrentFileHandle = NULL;
1188       Private->CurrentPeimCount = 0;
1189       //
1190       // Before walking through the next FV,Private->CurrentFvFileHandles[]should set to NULL
1191       //
1192       SetMem (Private->CurrentFvFileHandles, sizeof (EFI_PEI_FILE_HANDLE) * PcdGet32 (PcdPeiCoreMaxPeimPerFv), 0);
1193     }
1194 
1195     //
1196     // Before making another pass, we should set Private->CurrentPeimFvCount =0 to go
1197     // through all the FV.
1198     //
1199     Private->CurrentPeimFvCount = 0;
1200 
1201     //
1202     // PeimNeedingDispatch being TRUE means we found a PEIM/FV that did not get
1203     //  dispatched. So we need to make another pass
1204     //
1205     // PeimDispatchOnThisPass being TRUE means we dispatched a PEIM/FV on this
1206     //  pass. If we did not dispatch a PEIM/FV there is no point in trying again
1207     //  as it will fail the next time too (nothing has changed).
1208     //
1209   } while (Private->PeimNeedingDispatch && Private->PeimDispatchOnThisPass);
1210 
1211 }
1212 
1213 /**
1214   Initialize the Dispatcher's data members
1215 
1216   @param PrivateData     PeiCore's private data structure
1217   @param OldCoreData     Old data from SecCore
1218                          NULL if being run in non-permament memory mode.
1219   @param SecCoreData     Points to a data structure containing information about the PEI core's operating
1220                          environment, such as the size and location of temporary RAM, the stack location and
1221                          the BFV location.
1222 
1223   @return None.
1224 
1225 **/
1226 VOID
InitializeDispatcherData(IN PEI_CORE_INSTANCE * PrivateData,IN PEI_CORE_INSTANCE * OldCoreData,IN CONST EFI_SEC_PEI_HAND_OFF * SecCoreData)1227 InitializeDispatcherData (
1228   IN PEI_CORE_INSTANCE            *PrivateData,
1229   IN PEI_CORE_INSTANCE            *OldCoreData,
1230   IN CONST EFI_SEC_PEI_HAND_OFF   *SecCoreData
1231   )
1232 {
1233   if (OldCoreData == NULL) {
1234     PrivateData->PeimDispatcherReenter = FALSE;
1235     PeiInitializeFv (PrivateData, SecCoreData);
1236   } else {
1237     PeiReinitializeFv (PrivateData);
1238   }
1239 
1240   return;
1241 }
1242 
1243 /**
1244   This routine parses the Dependency Expression, if available, and
1245   decides if the module can be executed.
1246 
1247 
1248   @param Private         PeiCore's private data structure
1249   @param FileHandle      PEIM's file handle
1250   @param PeimCount       Peim count in all dispatched PEIMs.
1251 
1252   @retval TRUE   Can be dispatched
1253   @retval FALSE  Cannot be dispatched
1254 
1255 **/
1256 BOOLEAN
DepexSatisfied(IN PEI_CORE_INSTANCE * Private,IN EFI_PEI_FILE_HANDLE FileHandle,IN UINTN PeimCount)1257 DepexSatisfied (
1258   IN PEI_CORE_INSTANCE          *Private,
1259   IN EFI_PEI_FILE_HANDLE        FileHandle,
1260   IN UINTN                      PeimCount
1261   )
1262 {
1263   EFI_STATUS           Status;
1264   VOID                 *DepexData;
1265   EFI_FV_FILE_INFO     FileInfo;
1266 
1267   Status = PeiServicesFfsGetFileInfo (FileHandle, &FileInfo);
1268   if (EFI_ERROR (Status)) {
1269     DEBUG ((DEBUG_DISPATCH, "Evaluate PEI DEPEX for FFS(Unknown)\n"));
1270   } else {
1271     DEBUG ((DEBUG_DISPATCH, "Evaluate PEI DEPEX for FFS(%g)\n", &FileInfo.FileName));
1272   }
1273 
1274   if (PeimCount < Private->AprioriCount) {
1275     //
1276     // If its in the A priori file then we set Depex to TRUE
1277     //
1278     DEBUG ((DEBUG_DISPATCH, "  RESULT = TRUE (Apriori)\n"));
1279     return TRUE;
1280   }
1281 
1282   //
1283   // Depex section not in the encapsulated section.
1284   //
1285   Status = PeiServicesFfsFindSectionData (
1286               EFI_SECTION_PEI_DEPEX,
1287               FileHandle,
1288               (VOID **)&DepexData
1289               );
1290 
1291   if (EFI_ERROR (Status)) {
1292     //
1293     // If there is no DEPEX, assume the module can be executed
1294     //
1295     DEBUG ((DEBUG_DISPATCH, "  RESULT = TRUE (No DEPEX)\n"));
1296     return TRUE;
1297   }
1298 
1299   //
1300   // Evaluate a given DEPEX
1301   //
1302   return PeimDispatchReadiness (&Private->Ps, DepexData);
1303 }
1304 
1305 /**
1306   This routine enable a PEIM to register itself to shadow when PEI Foundation
1307   discovery permanent memory.
1308 
1309   @param FileHandle             File handle of a PEIM.
1310 
1311   @retval EFI_NOT_FOUND         The file handle doesn't point to PEIM itself.
1312   @retval EFI_ALREADY_STARTED   Indicate that the PEIM has been registered itself.
1313   @retval EFI_SUCCESS           Successfully to register itself.
1314 
1315 **/
1316 EFI_STATUS
1317 EFIAPI
PeiRegisterForShadow(IN EFI_PEI_FILE_HANDLE FileHandle)1318 PeiRegisterForShadow (
1319   IN EFI_PEI_FILE_HANDLE       FileHandle
1320   )
1321 {
1322   PEI_CORE_INSTANCE            *Private;
1323   Private = PEI_CORE_INSTANCE_FROM_PS_THIS (GetPeiServicesTablePointer ());
1324 
1325   if (Private->CurrentFileHandle != FileHandle) {
1326     //
1327     // The FileHandle must be for the current PEIM
1328     //
1329     return EFI_NOT_FOUND;
1330   }
1331 
1332   if (Private->Fv[Private->CurrentPeimFvCount].PeimState[Private->CurrentPeimCount] >= PEIM_STATE_REGISITER_FOR_SHADOW) {
1333     //
1334     // If the PEIM has already entered the PEIM_STATE_REGISTER_FOR_SHADOW or PEIM_STATE_DONE then it's already been started
1335     //
1336     return EFI_ALREADY_STARTED;
1337   }
1338 
1339   Private->Fv[Private->CurrentPeimFvCount].PeimState[Private->CurrentPeimCount] = PEIM_STATE_REGISITER_FOR_SHADOW;
1340 
1341   return EFI_SUCCESS;
1342 }
1343 
1344 
1345 
1346