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