Home | History | Annotate | Download | only in Dispatcher
      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
     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
    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
    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
    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
    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
    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
   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
   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
   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