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