]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Core/Pei/Dispatcher/Dispatcher.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / MdeModulePkg / Core / Pei / Dispatcher / Dispatcher.c
index 0f712ede481a28400a40528777e1e5a1850750ef..3552feda8f1b59923f0eb26705773895c3a937a4 100644 (file)
 /** @file\r
   EFI PEI Core dispatch services\r
-  \r
-Copyright (c) 2006 - 2010, Intel Corporation\r
-All rights reserved. This program and the accompanying materials\r
-are licensed and made available under the terms and conditions of the BSD License\r
-which accompanies this distribution.  The full text of the license may be found at\r
-http://opensource.org/licenses/bsd-license.php\r
 \r
-THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
-WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>\r
+(C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>\r
+SPDX-License-Identifier: BSD-2-Clause-Patent\r
 \r
 **/\r
 \r
 #include "PeiMain.h"\r
 \r
-///\r
-/// temporary memory is filled with this initial value during SEC phase\r
-///\r
-#define INIT_CAR_VALUE 0x5AA55AA5\r
+/**\r
+\r
+  Discover all PEIMs and optional Apriori file in one FV. There is at most one\r
+  Apriori file in one FV.\r
+\r
+\r
+  @param Private          Pointer to the private data passed in from caller\r
+  @param CoreFileHandle   The instance of PEI_CORE_FV_HANDLE.\r
+\r
+**/\r
+VOID\r
+DiscoverPeimsAndOrderWithApriori (\r
+  IN  PEI_CORE_INSTANCE   *Private,\r
+  IN  PEI_CORE_FV_HANDLE  *CoreFileHandle\r
+  )\r
+{\r
+  EFI_STATUS                   Status;\r
+  EFI_PEI_FILE_HANDLE          FileHandle;\r
+  EFI_PEI_FILE_HANDLE          AprioriFileHandle;\r
+  EFI_GUID                     *Apriori;\r
+  UINTN                        Index;\r
+  UINTN                        Index2;\r
+  UINTN                        PeimIndex;\r
+  UINTN                        PeimCount;\r
+  EFI_GUID                     *Guid;\r
+  EFI_PEI_FILE_HANDLE          *TempFileHandles;\r
+  EFI_GUID                     *TempFileGuid;\r
+  EFI_PEI_FIRMWARE_VOLUME_PPI  *FvPpi;\r
+  EFI_FV_FILE_INFO             FileInfo;\r
+\r
+  FvPpi = CoreFileHandle->FvPpi;\r
+\r
+  //\r
+  // Walk the FV and find all the PEIMs and the Apriori file.\r
+  //\r
+  AprioriFileHandle             = NULL;\r
+  Private->CurrentFvFileHandles = NULL;\r
+  Guid                          = NULL;\r
+\r
+  //\r
+  // If the current FV has been scanned, directly get its cached records.\r
+  //\r
+  if (CoreFileHandle->ScanFv) {\r
+    Private->CurrentFvFileHandles = CoreFileHandle->FvFileHandles;\r
+    return;\r
+  }\r
+\r
+  TempFileHandles = Private->TempFileHandles;\r
+  TempFileGuid    = Private->TempFileGuid;\r
+\r
+  //\r
+  // Go ahead to scan this FV, get PeimCount and cache FileHandles within it to TempFileHandles.\r
+  //\r
+  PeimCount  = 0;\r
+  FileHandle = NULL;\r
+  do {\r
+    Status = FvPpi->FindFileByType (FvPpi, PEI_CORE_INTERNAL_FFS_FILE_DISPATCH_TYPE, CoreFileHandle->FvHandle, &FileHandle);\r
+    if (!EFI_ERROR (Status)) {\r
+      if (PeimCount >= Private->TempPeimCount) {\r
+        //\r
+        // Run out of room, grow the buffer.\r
+        //\r
+        TempFileHandles = AllocatePool (\r
+                            sizeof (EFI_PEI_FILE_HANDLE) * (Private->TempPeimCount + TEMP_FILE_GROWTH_STEP)\r
+                            );\r
+        ASSERT (TempFileHandles != NULL);\r
+        CopyMem (\r
+          TempFileHandles,\r
+          Private->TempFileHandles,\r
+          sizeof (EFI_PEI_FILE_HANDLE) * Private->TempPeimCount\r
+          );\r
+        Private->TempFileHandles = TempFileHandles;\r
+        TempFileGuid             = AllocatePool (\r
+                                     sizeof (EFI_GUID) * (Private->TempPeimCount + TEMP_FILE_GROWTH_STEP)\r
+                                     );\r
+        ASSERT (TempFileGuid != NULL);\r
+        CopyMem (\r
+          TempFileGuid,\r
+          Private->TempFileGuid,\r
+          sizeof (EFI_GUID) * Private->TempPeimCount\r
+          );\r
+        Private->TempFileGuid  = TempFileGuid;\r
+        Private->TempPeimCount = Private->TempPeimCount + TEMP_FILE_GROWTH_STEP;\r
+      }\r
+\r
+      TempFileHandles[PeimCount++] = FileHandle;\r
+    }\r
+  } while (!EFI_ERROR (Status));\r
+\r
+  DEBUG ((\r
+    DEBUG_INFO,\r
+    "%a(): Found 0x%x PEI FFS files in the %dth FV\n",\r
+    __FUNCTION__,\r
+    PeimCount,\r
+    Private->CurrentPeimFvCount\r
+    ));\r
+\r
+  if (PeimCount == 0) {\r
+    //\r
+    // No PEIM FFS file is found, set ScanFv flag and return.\r
+    //\r
+    CoreFileHandle->ScanFv = TRUE;\r
+    return;\r
+  }\r
+\r
+  //\r
+  // Record PeimCount, allocate buffer for PeimState and FvFileHandles.\r
+  //\r
+  CoreFileHandle->PeimCount = PeimCount;\r
+  CoreFileHandle->PeimState = AllocateZeroPool (sizeof (UINT8) * PeimCount);\r
+  ASSERT (CoreFileHandle->PeimState != NULL);\r
+  CoreFileHandle->FvFileHandles = AllocateZeroPool (sizeof (EFI_PEI_FILE_HANDLE) * PeimCount);\r
+  ASSERT (CoreFileHandle->FvFileHandles != NULL);\r
+\r
+  //\r
+  // Get Apriori File handle\r
+  //\r
+  Private->AprioriCount = 0;\r
+  Status                = FvPpi->FindFileByName (FvPpi, &gPeiAprioriFileNameGuid, &CoreFileHandle->FvHandle, &AprioriFileHandle);\r
+  if (!EFI_ERROR (Status) && (AprioriFileHandle != NULL)) {\r
+    //\r
+    // Read the Apriori file\r
+    //\r
+    Status = FvPpi->FindSectionByType (FvPpi, EFI_SECTION_RAW, AprioriFileHandle, (VOID **)&Apriori);\r
+    if (!EFI_ERROR (Status)) {\r
+      //\r
+      // Calculate the number of PEIMs in the Apriori file\r
+      //\r
+      Status = FvPpi->GetFileInfo (FvPpi, AprioriFileHandle, &FileInfo);\r
+      ASSERT_EFI_ERROR (Status);\r
+      Private->AprioriCount = FileInfo.BufferSize;\r
+      if (IS_SECTION2 (FileInfo.Buffer)) {\r
+        Private->AprioriCount -= sizeof (EFI_COMMON_SECTION_HEADER2);\r
+      } else {\r
+        Private->AprioriCount -= sizeof (EFI_COMMON_SECTION_HEADER);\r
+      }\r
+\r
+      Private->AprioriCount /= sizeof (EFI_GUID);\r
+\r
+      for (Index = 0; Index < PeimCount; Index++) {\r
+        //\r
+        // Make an array of file name GUIDs that matches the FileHandle array so we can convert\r
+        // quickly from file name to file handle\r
+        //\r
+        Status = FvPpi->GetFileInfo (FvPpi, TempFileHandles[Index], &FileInfo);\r
+        ASSERT_EFI_ERROR (Status);\r
+        CopyMem (&TempFileGuid[Index], &FileInfo.FileName, sizeof (EFI_GUID));\r
+      }\r
+\r
+      //\r
+      // Walk through TempFileGuid array to find out who is invalid PEIM GUID in Apriori file.\r
+      // Add available PEIMs in Apriori file into FvFileHandles array.\r
+      //\r
+      Index = 0;\r
+      for (Index2 = 0; Index2 < Private->AprioriCount; Index2++) {\r
+        Guid = ScanGuid (TempFileGuid, PeimCount * sizeof (EFI_GUID), &Apriori[Index2]);\r
+        if (Guid != NULL) {\r
+          PeimIndex                              = ((UINTN)Guid - (UINTN)&TempFileGuid[0])/sizeof (EFI_GUID);\r
+          CoreFileHandle->FvFileHandles[Index++] = TempFileHandles[PeimIndex];\r
+\r
+          //\r
+          // Since we have copied the file handle we can remove it from this list.\r
+          //\r
+          TempFileHandles[PeimIndex] = NULL;\r
+        }\r
+      }\r
+\r
+      //\r
+      // Update valid AprioriCount\r
+      //\r
+      Private->AprioriCount = Index;\r
+\r
+      //\r
+      // Add in any PEIMs not in the Apriori file\r
+      //\r
+      for (Index2 = 0; Index2 < PeimCount; Index2++) {\r
+        if (TempFileHandles[Index2] != NULL) {\r
+          CoreFileHandle->FvFileHandles[Index++] = TempFileHandles[Index2];\r
+          TempFileHandles[Index2]                = NULL;\r
+        }\r
+      }\r
+\r
+      ASSERT (Index == PeimCount);\r
+    }\r
+  } else {\r
+    CopyMem (CoreFileHandle->FvFileHandles, TempFileHandles, sizeof (EFI_PEI_FILE_HANDLE) * PeimCount);\r
+  }\r
+\r
+  //\r
+  // The current FV File Handles have been cached. So that we don't have to scan the FV again.\r
+  // Instead, we can retrieve the file handles within this FV from cached records.\r
+  //\r
+  CoreFileHandle->ScanFv        = TRUE;\r
+  Private->CurrentFvFileHandles = CoreFileHandle->FvFileHandles;\r
+}\r
+\r
+//\r
+// This is the minimum memory required by DxeCore initialization. When LMFA feature enabled,\r
+// This part of memory still need reserved on the very top of memory so that the DXE Core could\r
+// use these memory for data initialization. This macro should be sync with the same marco\r
+// defined in DXE Core.\r
+//\r
+#define MINIMUM_INITIAL_MEMORY_SIZE  0x10000\r
+\r
+/**\r
+  This function is to test if the memory range described in resource HOB is available or not.\r
+\r
+  This function should only be invoked when Loading Module at Fixed Address(LMFA) feature is enabled. Some platform may allocate the\r
+  memory before PeiLoadFixAddressHook in invoked. so this function is to test if the memory range described by the input resource HOB is\r
+  available or not.\r
+\r
+  @param PrivateData         Pointer to the private data passed in from caller\r
+  @param ResourceHob         Pointer to a resource HOB which described the memory range described by the input resource HOB\r
+**/\r
+BOOLEAN\r
+PeiLoadFixAddressIsMemoryRangeAvailable (\r
+  IN PEI_CORE_INSTANCE            *PrivateData,\r
+  IN EFI_HOB_RESOURCE_DESCRIPTOR  *ResourceHob\r
+  )\r
+{\r
+  EFI_HOB_MEMORY_ALLOCATION  *MemoryHob;\r
+  BOOLEAN                    IsAvailable;\r
+  EFI_PEI_HOB_POINTERS       Hob;\r
+\r
+  IsAvailable = TRUE;\r
+  if ((PrivateData == NULL) || (ResourceHob == NULL)) {\r
+    return FALSE;\r
+  }\r
+\r
+  //\r
+  // test if the memory range describe in the HOB is already allocated.\r
+  //\r
+  for (Hob.Raw = PrivateData->HobList.Raw; !END_OF_HOB_LIST (Hob); Hob.Raw = GET_NEXT_HOB (Hob)) {\r
+    //\r
+    // See if this is a memory allocation HOB\r
+    //\r
+    if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_MEMORY_ALLOCATION) {\r
+      MemoryHob = Hob.MemoryAllocation;\r
+      if ((MemoryHob->AllocDescriptor.MemoryBaseAddress == ResourceHob->PhysicalStart) &&\r
+          (MemoryHob->AllocDescriptor.MemoryBaseAddress + MemoryHob->AllocDescriptor.MemoryLength == ResourceHob->PhysicalStart + ResourceHob->ResourceLength))\r
+      {\r
+        IsAvailable = FALSE;\r
+        break;\r
+      }\r
+    }\r
+  }\r
+\r
+  return IsAvailable;\r
+}\r
+\r
+/**\r
+  Hook function for Loading Module at Fixed Address feature\r
+\r
+  This function should only be invoked when Loading Module at Fixed Address(LMFA) feature is enabled. When feature is\r
+  configured as Load Modules at Fix Absolute Address, this function is to validate the top address assigned by user. When\r
+  feature is configured as Load Modules at Fixed Offset, the function is to find the top address which is TOLM-TSEG in general.\r
+  And also the function will re-install PEI memory.\r
+\r
+  @param PrivateData         Pointer to the private data passed in from caller\r
+\r
+**/\r
+VOID\r
+PeiLoadFixAddressHook (\r
+  IN PEI_CORE_INSTANCE  *PrivateData\r
+  )\r
+{\r
+  EFI_PHYSICAL_ADDRESS         TopLoadingAddress;\r
+  UINT64                       PeiMemorySize;\r
+  UINT64                       TotalReservedMemorySize;\r
+  UINT64                       MemoryRangeEnd;\r
+  EFI_PHYSICAL_ADDRESS         HighAddress;\r
+  EFI_HOB_RESOURCE_DESCRIPTOR  *ResourceHob;\r
+  EFI_HOB_RESOURCE_DESCRIPTOR  *NextResourceHob;\r
+  EFI_HOB_RESOURCE_DESCRIPTOR  *CurrentResourceHob;\r
+  EFI_PEI_HOB_POINTERS         CurrentHob;\r
+  EFI_PEI_HOB_POINTERS         Hob;\r
+  EFI_PEI_HOB_POINTERS         NextHob;\r
+  EFI_HOB_MEMORY_ALLOCATION    *MemoryHob;\r
+\r
+  //\r
+  // Initialize Local Variables\r
+  //\r
+  CurrentResourceHob = NULL;\r
+  ResourceHob        = NULL;\r
+  NextResourceHob    = NULL;\r
+  HighAddress        = 0;\r
+  TopLoadingAddress  = 0;\r
+  MemoryRangeEnd     = 0;\r
+  CurrentHob.Raw     = PrivateData->HobList.Raw;\r
+  PeiMemorySize      = PrivateData->PhysicalMemoryLength;\r
+  //\r
+  // The top reserved memory include 3 parts: the topest range is for DXE core initialization with the size  MINIMUM_INITIAL_MEMORY_SIZE\r
+  // then RuntimeCodePage range and Boot time code range.\r
+  //\r
+  TotalReservedMemorySize  = MINIMUM_INITIAL_MEMORY_SIZE + EFI_PAGES_TO_SIZE (PcdGet32 (PcdLoadFixAddressRuntimeCodePageNumber));\r
+  TotalReservedMemorySize += EFI_PAGES_TO_SIZE (PcdGet32 (PcdLoadFixAddressBootTimeCodePageNumber));\r
+  //\r
+  // PEI memory range lies below the top reserved memory\r
+  //\r
+  TotalReservedMemorySize += PeiMemorySize;\r
+\r
+  DEBUG ((DEBUG_INFO, "LOADING MODULE FIXED INFO: PcdLoadFixAddressRuntimeCodePageNumber= 0x%x.\n", PcdGet32 (PcdLoadFixAddressRuntimeCodePageNumber)));\r
+  DEBUG ((DEBUG_INFO, "LOADING MODULE FIXED INFO: PcdLoadFixAddressBootTimeCodePageNumber= 0x%x.\n", PcdGet32 (PcdLoadFixAddressBootTimeCodePageNumber)));\r
+  DEBUG ((DEBUG_INFO, "LOADING MODULE FIXED INFO: PcdLoadFixAddressPeiCodePageNumber= 0x%x.\n", PcdGet32 (PcdLoadFixAddressPeiCodePageNumber)));\r
+  DEBUG ((DEBUG_INFO, "LOADING MODULE FIXED INFO: Total Reserved Memory Size = 0x%lx.\n", TotalReservedMemorySize));\r
+  //\r
+  // Loop through the system memory typed HOB to merge the adjacent memory range\r
+  //\r
+  for (Hob.Raw = PrivateData->HobList.Raw; !END_OF_HOB_LIST (Hob); Hob.Raw = GET_NEXT_HOB (Hob)) {\r
+    //\r
+    // See if this is a resource descriptor HOB\r
+    //\r
+    if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {\r
+      ResourceHob = Hob.ResourceDescriptor;\r
+      //\r
+      // If range described in this HOB is not system memory or higher than MAX_ADDRESS, ignored.\r
+      //\r
+      if ((ResourceHob->ResourceType != EFI_RESOURCE_SYSTEM_MEMORY) ||\r
+          (ResourceHob->PhysicalStart + ResourceHob->ResourceLength > MAX_ADDRESS))\r
+      {\r
+        continue;\r
+      }\r
+\r
+      for (NextHob.Raw = PrivateData->HobList.Raw; !END_OF_HOB_LIST (NextHob); NextHob.Raw = GET_NEXT_HOB (NextHob)) {\r
+        if (NextHob.Raw == Hob.Raw) {\r
+          continue;\r
+        }\r
+\r
+        //\r
+        // See if this is a resource descriptor HOB\r
+        //\r
+        if (GET_HOB_TYPE (NextHob) == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {\r
+          NextResourceHob = NextHob.ResourceDescriptor;\r
+          //\r
+          // test if range described in this NextResourceHob is system memory and have the same attribute.\r
+          // Note: Here is a assumption that system memory should always be healthy even without test.\r
+          //\r
+          if ((NextResourceHob->ResourceType == EFI_RESOURCE_SYSTEM_MEMORY) &&\r
+              (((NextResourceHob->ResourceAttribute^ResourceHob->ResourceAttribute)&(~EFI_RESOURCE_ATTRIBUTE_TESTED)) == 0))\r
+          {\r
+            //\r
+            // See if the memory range described in ResourceHob and NextResourceHob is adjacent\r
+            //\r
+            if (((ResourceHob->PhysicalStart <= NextResourceHob->PhysicalStart) &&\r
+                 (ResourceHob->PhysicalStart + ResourceHob->ResourceLength >= NextResourceHob->PhysicalStart)) ||\r
+                ((ResourceHob->PhysicalStart >= NextResourceHob->PhysicalStart) &&\r
+                 (ResourceHob->PhysicalStart <= NextResourceHob->PhysicalStart + NextResourceHob->ResourceLength)))\r
+            {\r
+              MemoryRangeEnd = ((ResourceHob->PhysicalStart + ResourceHob->ResourceLength) > (NextResourceHob->PhysicalStart + NextResourceHob->ResourceLength)) ?\r
+                               (ResourceHob->PhysicalStart + ResourceHob->ResourceLength) : (NextResourceHob->PhysicalStart + NextResourceHob->ResourceLength);\r
+\r
+              ResourceHob->PhysicalStart = (ResourceHob->PhysicalStart < NextResourceHob->PhysicalStart) ?\r
+                                           ResourceHob->PhysicalStart : NextResourceHob->PhysicalStart;\r
+\r
+              ResourceHob->ResourceLength = (MemoryRangeEnd - ResourceHob->PhysicalStart);\r
+\r
+              ResourceHob->ResourceAttribute = ResourceHob->ResourceAttribute & (~EFI_RESOURCE_ATTRIBUTE_TESTED);\r
+              //\r
+              // Delete the NextResourceHob by marking it as unused.\r
+              //\r
+              GET_HOB_TYPE (NextHob) = EFI_HOB_TYPE_UNUSED;\r
+            }\r
+          }\r
+        }\r
+      }\r
+    }\r
+  }\r
+\r
+  //\r
+  // Some platform is already allocated pages before the HOB re-org. Here to build dedicated resource HOB to describe\r
+  //  the allocated memory range\r
+  //\r
+  for (Hob.Raw = PrivateData->HobList.Raw; !END_OF_HOB_LIST (Hob); Hob.Raw = GET_NEXT_HOB (Hob)) {\r
+    //\r
+    // See if this is a memory allocation HOB\r
+    //\r
+    if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_MEMORY_ALLOCATION) {\r
+      MemoryHob = Hob.MemoryAllocation;\r
+      for (NextHob.Raw = PrivateData->HobList.Raw; !END_OF_HOB_LIST (NextHob); NextHob.Raw = GET_NEXT_HOB (NextHob)) {\r
+        //\r
+        // See if this is a resource descriptor HOB\r
+        //\r
+        if (GET_HOB_TYPE (NextHob) == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {\r
+          NextResourceHob = NextHob.ResourceDescriptor;\r
+          //\r
+          // If range described in this HOB is not system memory or higher than MAX_ADDRESS, ignored.\r
+          //\r
+          if ((NextResourceHob->ResourceType != EFI_RESOURCE_SYSTEM_MEMORY) || (NextResourceHob->PhysicalStart + NextResourceHob->ResourceLength > MAX_ADDRESS)) {\r
+            continue;\r
+          }\r
+\r
+          //\r
+          // If the range describe in memory allocation HOB belongs to the memory range described by the resource HOB\r
+          //\r
+          if ((MemoryHob->AllocDescriptor.MemoryBaseAddress >= NextResourceHob->PhysicalStart) &&\r
+              (MemoryHob->AllocDescriptor.MemoryBaseAddress + MemoryHob->AllocDescriptor.MemoryLength <= NextResourceHob->PhysicalStart + NextResourceHob->ResourceLength))\r
+          {\r
+            //\r
+            // Build separate resource HOB for this allocated range\r
+            //\r
+            if (MemoryHob->AllocDescriptor.MemoryBaseAddress > NextResourceHob->PhysicalStart) {\r
+              BuildResourceDescriptorHob (\r
+                EFI_RESOURCE_SYSTEM_MEMORY,\r
+                NextResourceHob->ResourceAttribute,\r
+                NextResourceHob->PhysicalStart,\r
+                (MemoryHob->AllocDescriptor.MemoryBaseAddress - NextResourceHob->PhysicalStart)\r
+                );\r
+            }\r
+\r
+            if (MemoryHob->AllocDescriptor.MemoryBaseAddress + MemoryHob->AllocDescriptor.MemoryLength < NextResourceHob->PhysicalStart + NextResourceHob->ResourceLength) {\r
+              BuildResourceDescriptorHob (\r
+                EFI_RESOURCE_SYSTEM_MEMORY,\r
+                NextResourceHob->ResourceAttribute,\r
+                MemoryHob->AllocDescriptor.MemoryBaseAddress + MemoryHob->AllocDescriptor.MemoryLength,\r
+                (NextResourceHob->PhysicalStart + NextResourceHob->ResourceLength -(MemoryHob->AllocDescriptor.MemoryBaseAddress + MemoryHob->AllocDescriptor.MemoryLength))\r
+                );\r
+            }\r
+\r
+            NextResourceHob->PhysicalStart  = MemoryHob->AllocDescriptor.MemoryBaseAddress;\r
+            NextResourceHob->ResourceLength = MemoryHob->AllocDescriptor.MemoryLength;\r
+            break;\r
+          }\r
+        }\r
+      }\r
+    }\r
+  }\r
+\r
+  //\r
+  // Try to find and validate the TOP address.\r
+  //\r
+  if ((INT64)PcdGet64 (PcdLoadModuleAtFixAddressEnable) > 0 ) {\r
+    //\r
+    // The LMFA feature is enabled as load module at fixed absolute address.\r
+    //\r
+    TopLoadingAddress = (EFI_PHYSICAL_ADDRESS)PcdGet64 (PcdLoadModuleAtFixAddressEnable);\r
+    DEBUG ((DEBUG_INFO, "LOADING MODULE FIXED INFO: Loading module at fixed absolute address.\n"));\r
+    //\r
+    // validate the Address. Loop the resource descriptor HOB to make sure the address is in valid memory range\r
+    //\r
+    if ((TopLoadingAddress & EFI_PAGE_MASK) != 0) {\r
+      DEBUG ((DEBUG_INFO, "LOADING MODULE FIXED ERROR:Top Address 0x%lx is invalid since top address should be page align. \n", TopLoadingAddress));\r
+      ASSERT (FALSE);\r
+    }\r
+\r
+    //\r
+    // Search for a memory region that is below MAX_ADDRESS and in which TopLoadingAddress lies\r
+    //\r
+    for (Hob.Raw = PrivateData->HobList.Raw; !END_OF_HOB_LIST (Hob); Hob.Raw = GET_NEXT_HOB (Hob)) {\r
+      //\r
+      // See if this is a resource descriptor HOB\r
+      //\r
+      if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {\r
+        ResourceHob = Hob.ResourceDescriptor;\r
+        //\r
+        // See if this resource descriptor HOB describes tested system memory below MAX_ADDRESS\r
+        //\r
+        if ((ResourceHob->ResourceType == EFI_RESOURCE_SYSTEM_MEMORY) &&\r
+            (ResourceHob->PhysicalStart + ResourceHob->ResourceLength <= MAX_ADDRESS))\r
+        {\r
+          //\r
+          // See if Top address specified by user is valid.\r
+          //\r
+          if ((ResourceHob->PhysicalStart + TotalReservedMemorySize < TopLoadingAddress) &&\r
+              ((ResourceHob->PhysicalStart + ResourceHob->ResourceLength - MINIMUM_INITIAL_MEMORY_SIZE) >= TopLoadingAddress) &&\r
+              PeiLoadFixAddressIsMemoryRangeAvailable (PrivateData, ResourceHob))\r
+          {\r
+            CurrentResourceHob = ResourceHob;\r
+            CurrentHob         = Hob;\r
+            break;\r
+          }\r
+        }\r
+      }\r
+    }\r
+\r
+    if (CurrentResourceHob != NULL) {\r
+      DEBUG ((DEBUG_INFO, "LOADING MODULE FIXED INFO:Top Address 0x%lx is valid \n", TopLoadingAddress));\r
+      TopLoadingAddress += MINIMUM_INITIAL_MEMORY_SIZE;\r
+    } else {\r
+      DEBUG ((DEBUG_INFO, "LOADING MODULE FIXED ERROR:Top Address 0x%lx is invalid \n", TopLoadingAddress));\r
+      DEBUG ((DEBUG_INFO, "LOADING MODULE FIXED ERROR:The recommended Top Address for the platform is: \n"));\r
+      //\r
+      // Print the recommended Top address range.\r
+      //\r
+      for (Hob.Raw = PrivateData->HobList.Raw; !END_OF_HOB_LIST (Hob); Hob.Raw = GET_NEXT_HOB (Hob)) {\r
+        //\r
+        // See if this is a resource descriptor HOB\r
+        //\r
+        if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {\r
+          ResourceHob = Hob.ResourceDescriptor;\r
+          //\r
+          // See if this resource descriptor HOB describes tested system memory below MAX_ADDRESS\r
+          //\r
+          if ((ResourceHob->ResourceType == EFI_RESOURCE_SYSTEM_MEMORY) &&\r
+              (ResourceHob->PhysicalStart + ResourceHob->ResourceLength <= MAX_ADDRESS))\r
+          {\r
+            //\r
+            // See if Top address specified by user is valid.\r
+            //\r
+            if ((ResourceHob->ResourceLength > TotalReservedMemorySize) && PeiLoadFixAddressIsMemoryRangeAvailable (PrivateData, ResourceHob)) {\r
+              DEBUG ((\r
+                DEBUG_INFO,\r
+                "(0x%lx, 0x%lx)\n",\r
+                (ResourceHob->PhysicalStart + TotalReservedMemorySize -MINIMUM_INITIAL_MEMORY_SIZE),\r
+                (ResourceHob->PhysicalStart + ResourceHob->ResourceLength -MINIMUM_INITIAL_MEMORY_SIZE)\r
+                ));\r
+            }\r
+          }\r
+        }\r
+      }\r
+\r
+      //\r
+      // Assert here\r
+      //\r
+      ASSERT (FALSE);\r
+      return;\r
+    }\r
+  } else {\r
+    //\r
+    // The LMFA feature is enabled as load module at fixed offset relative to TOLM\r
+    // Parse the Hob list to find the topest available memory. Generally it is (TOLM - TSEG)\r
+    //\r
+    //\r
+    // Search for a tested memory region that is below MAX_ADDRESS\r
+    //\r
+    for (Hob.Raw = PrivateData->HobList.Raw; !END_OF_HOB_LIST (Hob); Hob.Raw = GET_NEXT_HOB (Hob)) {\r
+      //\r
+      // See if this is a resource descriptor HOB\r
+      //\r
+      if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {\r
+        ResourceHob = Hob.ResourceDescriptor;\r
+        //\r
+        // See if this resource descriptor HOB describes tested system memory below MAX_ADDRESS\r
+        //\r
+        if ((ResourceHob->ResourceType == EFI_RESOURCE_SYSTEM_MEMORY) &&\r
+            (ResourceHob->PhysicalStart + ResourceHob->ResourceLength <= MAX_ADDRESS) &&\r
+            (ResourceHob->ResourceLength > TotalReservedMemorySize) && PeiLoadFixAddressIsMemoryRangeAvailable (PrivateData, ResourceHob))\r
+        {\r
+          //\r
+          // See if this is the highest largest system memory region below MaxAddress\r
+          //\r
+          if (ResourceHob->PhysicalStart > HighAddress) {\r
+            CurrentResourceHob = ResourceHob;\r
+            CurrentHob         = Hob;\r
+            HighAddress        = CurrentResourceHob->PhysicalStart;\r
+          }\r
+        }\r
+      }\r
+    }\r
+\r
+    if (CurrentResourceHob == NULL) {\r
+      DEBUG ((DEBUG_INFO, "LOADING MODULE FIXED ERROR:The System Memory is too small\n"));\r
+      //\r
+      // Assert here\r
+      //\r
+      ASSERT (FALSE);\r
+      return;\r
+    } else {\r
+      TopLoadingAddress = CurrentResourceHob->PhysicalStart + CurrentResourceHob->ResourceLength;\r
+    }\r
+  }\r
+\r
+  if (CurrentResourceHob != NULL) {\r
+    //\r
+    // rebuild resource HOB for PEI memory and reserved memory\r
+    //\r
+    BuildResourceDescriptorHob (\r
+      EFI_RESOURCE_SYSTEM_MEMORY,\r
+      (\r
+       EFI_RESOURCE_ATTRIBUTE_PRESENT |\r
+       EFI_RESOURCE_ATTRIBUTE_INITIALIZED |\r
+       EFI_RESOURCE_ATTRIBUTE_TESTED |\r
+       EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE |\r
+       EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE |\r
+       EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE |\r
+       EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE\r
+      ),\r
+      (TopLoadingAddress - TotalReservedMemorySize),\r
+      TotalReservedMemorySize\r
+      );\r
+    //\r
+    // rebuild resource for the remain memory if necessary\r
+    //\r
+    if (CurrentResourceHob->PhysicalStart < TopLoadingAddress - TotalReservedMemorySize) {\r
+      BuildResourceDescriptorHob (\r
+        EFI_RESOURCE_SYSTEM_MEMORY,\r
+        (\r
+         EFI_RESOURCE_ATTRIBUTE_PRESENT |\r
+         EFI_RESOURCE_ATTRIBUTE_INITIALIZED |\r
+         EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE |\r
+         EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE |\r
+         EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE |\r
+         EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE\r
+        ),\r
+        CurrentResourceHob->PhysicalStart,\r
+        (TopLoadingAddress - TotalReservedMemorySize - CurrentResourceHob->PhysicalStart)\r
+        );\r
+    }\r
+\r
+    if (CurrentResourceHob->PhysicalStart + CurrentResourceHob->ResourceLength  > TopLoadingAddress ) {\r
+      BuildResourceDescriptorHob (\r
+        EFI_RESOURCE_SYSTEM_MEMORY,\r
+        (\r
+         EFI_RESOURCE_ATTRIBUTE_PRESENT |\r
+         EFI_RESOURCE_ATTRIBUTE_INITIALIZED |\r
+         EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE |\r
+         EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE |\r
+         EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE |\r
+         EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE\r
+        ),\r
+        TopLoadingAddress,\r
+        (CurrentResourceHob->PhysicalStart + CurrentResourceHob->ResourceLength  - TopLoadingAddress)\r
+        );\r
+    }\r
+\r
+    //\r
+    // Delete CurrentHob by marking it as unused since the memory range described by is rebuilt.\r
+    //\r
+    GET_HOB_TYPE (CurrentHob) = EFI_HOB_TYPE_UNUSED;\r
+  }\r
+\r
+  //\r
+  // Cache the top address for Loading Module at Fixed Address feature\r
+  //\r
+  PrivateData->LoadModuleAtFixAddressTopAddress = TopLoadingAddress - MINIMUM_INITIAL_MEMORY_SIZE;\r
+  DEBUG ((DEBUG_INFO, "LOADING MODULE FIXED INFO: Top address = 0x%lx\n", PrivateData->LoadModuleAtFixAddressTopAddress));\r
+  //\r
+  // reinstall the PEI memory relative to TopLoadingAddress\r
+  //\r
+  PrivateData->PhysicalMemoryBegin   = TopLoadingAddress - TotalReservedMemorySize;\r
+  PrivateData->FreePhysicalMemoryTop = PrivateData->PhysicalMemoryBegin + PeiMemorySize;\r
+}\r
+\r
+/**\r
+  This routine is invoked in switch stack as PeiCore Entry.\r
+\r
+  @param SecCoreData     Points to a data structure containing information about the PEI core's operating\r
+                         environment, such as the size and location of temporary RAM, the stack location and\r
+                         the BFV location.\r
+  @param Private         Pointer to old core data that is used to initialize the\r
+                         core's data areas.\r
+**/\r
+VOID\r
+EFIAPI\r
+PeiCoreEntry (\r
+  IN CONST EFI_SEC_PEI_HAND_OFF  *SecCoreData,\r
+  IN PEI_CORE_INSTANCE           *Private\r
+  )\r
+{\r
+  //\r
+  // Entry PEI Phase 2\r
+  //\r
+  PeiCore (SecCoreData, NULL, Private);\r
+}\r
+\r
+/**\r
+  Check SwitchStackSignal and switch stack if SwitchStackSignal is TRUE.\r
+\r
+  @param[in] SecCoreData    Points to a data structure containing information about the PEI core's operating\r
+                            environment, such as the size and location of temporary RAM, the stack location and\r
+                            the BFV location.\r
+  @param[in] Private        Pointer to the private data passed in from caller.\r
+\r
+**/\r
+VOID\r
+PeiCheckAndSwitchStack (\r
+  IN CONST EFI_SEC_PEI_HAND_OFF  *SecCoreData,\r
+  IN PEI_CORE_INSTANCE           *Private\r
+  )\r
+{\r
+  VOID                               *LoadFixPeiCodeBegin;\r
+  EFI_STATUS                         Status;\r
+  CONST EFI_PEI_SERVICES             **PeiServices;\r
+  UINT64                             NewStackSize;\r
+  EFI_PHYSICAL_ADDRESS               TopOfOldStack;\r
+  EFI_PHYSICAL_ADDRESS               TopOfNewStack;\r
+  UINTN                              StackOffset;\r
+  BOOLEAN                            StackOffsetPositive;\r
+  EFI_PHYSICAL_ADDRESS               TemporaryRamBase;\r
+  UINTN                              TemporaryRamSize;\r
+  UINTN                              TemporaryStackSize;\r
+  VOID                               *TemporaryStackBase;\r
+  UINTN                              PeiTemporaryRamSize;\r
+  VOID                               *PeiTemporaryRamBase;\r
+  EFI_PEI_TEMPORARY_RAM_SUPPORT_PPI  *TemporaryRamSupportPpi;\r
+  EFI_PHYSICAL_ADDRESS               BaseOfNewHeap;\r
+  EFI_PHYSICAL_ADDRESS               HoleMemBase;\r
+  UINTN                              HoleMemSize;\r
+  UINTN                              HeapTemporaryRamSize;\r
+  EFI_PHYSICAL_ADDRESS               TempBase1;\r
+  UINTN                              TempSize1;\r
+  EFI_PHYSICAL_ADDRESS               TempBase2;\r
+  UINTN                              TempSize2;\r
+  UINTN                              Index;\r
+\r
+  PeiServices = (CONST EFI_PEI_SERVICES **)&Private->Ps;\r
+\r
+  if (Private->SwitchStackSignal) {\r
+    //\r
+    // Before switch stack from temporary memory to permanent memory, calculate the heap and stack\r
+    // usage in temporary memory for debugging.\r
+    //\r
+    DEBUG_CODE_BEGIN ();\r
+    UINT32                *StackPointer;\r
+    EFI_PEI_HOB_POINTERS  Hob;\r
+\r
+    for (  StackPointer = (UINT32 *)SecCoreData->StackBase;\r
+           (StackPointer < (UINT32 *)((UINTN)SecCoreData->StackBase + SecCoreData->StackSize)) \\r
+        && (*StackPointer == PcdGet32 (PcdInitValueInTempStack));\r
+           StackPointer++)\r
+    {\r
+    }\r
+\r
+    DEBUG ((DEBUG_INFO, "Temp Stack : BaseAddress=0x%p Length=0x%X\n", SecCoreData->StackBase, (UINT32)SecCoreData->StackSize));\r
+    DEBUG ((DEBUG_INFO, "Temp Heap  : BaseAddress=0x%p Length=0x%X\n", SecCoreData->PeiTemporaryRamBase, (UINT32)SecCoreData->PeiTemporaryRamSize));\r
+    DEBUG ((DEBUG_INFO, "Total temporary memory:    %d bytes.\n", (UINT32)SecCoreData->TemporaryRamSize));\r
+    DEBUG ((\r
+      DEBUG_INFO,\r
+      "  temporary memory stack ever used:       %d bytes.\n",\r
+      (UINT32)(SecCoreData->StackSize - ((UINTN)StackPointer - (UINTN)SecCoreData->StackBase))\r
+      ));\r
+    DEBUG ((\r
+      DEBUG_INFO,\r
+      "  temporary memory heap used for HobList: %d bytes.\n",\r
+      (UINT32)((UINTN)Private->HobList.HandoffInformationTable->EfiFreeMemoryBottom - (UINTN)Private->HobList.Raw)\r
+      ));\r
+    DEBUG ((\r
+      DEBUG_INFO,\r
+      "  temporary memory heap occupied by memory pages: %d bytes.\n",\r
+      (UINT32)(UINTN)(Private->HobList.HandoffInformationTable->EfiMemoryTop - Private->HobList.HandoffInformationTable->EfiFreeMemoryTop)\r
+      ));\r
+    for (Hob.Raw = Private->HobList.Raw; !END_OF_HOB_LIST (Hob); Hob.Raw = GET_NEXT_HOB (Hob)) {\r
+      if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_MEMORY_ALLOCATION) {\r
+        DEBUG ((\r
+          DEBUG_INFO,\r
+          "Memory Allocation 0x%08x 0x%0lx - 0x%0lx\n", \\r
+          Hob.MemoryAllocation->AllocDescriptor.MemoryType,               \\r
+          Hob.MemoryAllocation->AllocDescriptor.MemoryBaseAddress,        \\r
+          Hob.MemoryAllocation->AllocDescriptor.MemoryBaseAddress + Hob.MemoryAllocation->AllocDescriptor.MemoryLength - 1\r
+          ));\r
+      }\r
+    }\r
+\r
+    DEBUG_CODE_END ();\r
+\r
+    if ((PcdGet64 (PcdLoadModuleAtFixAddressEnable) != 0) && (Private->HobList.HandoffInformationTable->BootMode != BOOT_ON_S3_RESUME)) {\r
+      //\r
+      // Loading Module at Fixed Address is enabled\r
+      //\r
+      PeiLoadFixAddressHook (Private);\r
+\r
+      //\r
+      // If Loading Module at Fixed Address is enabled, Allocating memory range for Pei code range.\r
+      //\r
+      LoadFixPeiCodeBegin = AllocatePages ((UINTN)PcdGet32 (PcdLoadFixAddressPeiCodePageNumber));\r
+      DEBUG ((DEBUG_INFO, "LOADING MODULE FIXED INFO: PeiCodeBegin = 0x%lX, PeiCodeTop= 0x%lX\n", (UINT64)(UINTN)LoadFixPeiCodeBegin, (UINT64)((UINTN)LoadFixPeiCodeBegin + PcdGet32 (PcdLoadFixAddressPeiCodePageNumber) * EFI_PAGE_SIZE)));\r
+    }\r
+\r
+    //\r
+    // Reserve the size of new stack at bottom of physical memory\r
+    //\r
+    // The size of new stack in permanent memory must be the same size\r
+    // or larger than the size of old stack in temporary memory.\r
+    // But if new stack is smaller than the size of old stack, we also reserve\r
+    // the size of old stack at bottom of permanent memory.\r
+    //\r
+    NewStackSize = RShiftU64 (Private->PhysicalMemoryLength, 1);\r
+    NewStackSize = ALIGN_VALUE (NewStackSize, EFI_PAGE_SIZE);\r
+    NewStackSize = MIN (PcdGet32 (PcdPeiCoreMaxPeiStackSize), NewStackSize);\r
+    DEBUG ((DEBUG_INFO, "Old Stack size %d, New stack size %d\n", (UINT32)SecCoreData->StackSize, (UINT32)NewStackSize));\r
+    ASSERT (NewStackSize >= SecCoreData->StackSize);\r
+\r
+    //\r
+    // Calculate stack offset and heap offset between temporary memory and new permanent\r
+    // memory separately.\r
+    //\r
+    TopOfOldStack = (UINTN)SecCoreData->StackBase + SecCoreData->StackSize;\r
+    TopOfNewStack = Private->PhysicalMemoryBegin + NewStackSize;\r
+    if (TopOfNewStack >= TopOfOldStack) {\r
+      StackOffsetPositive = TRUE;\r
+      StackOffset         = (UINTN)(TopOfNewStack - TopOfOldStack);\r
+    } else {\r
+      StackOffsetPositive = FALSE;\r
+      StackOffset         = (UINTN)(TopOfOldStack - TopOfNewStack);\r
+    }\r
+\r
+    Private->StackOffsetPositive = StackOffsetPositive;\r
+    Private->StackOffset         = StackOffset;\r
+\r
+    //\r
+    // Build Stack HOB that describes the permanent memory stack\r
+    //\r
+    DEBUG ((DEBUG_INFO, "Stack Hob: BaseAddress=0x%lX Length=0x%lX\n", TopOfNewStack - NewStackSize, NewStackSize));\r
+    BuildStackHob (TopOfNewStack - NewStackSize, NewStackSize);\r
+\r
+    //\r
+    // Cache information from SecCoreData into locals before SecCoreData is converted to a permanent memory address\r
+    //\r
+    TemporaryRamBase    = (EFI_PHYSICAL_ADDRESS)(UINTN)SecCoreData->TemporaryRamBase;\r
+    TemporaryRamSize    = SecCoreData->TemporaryRamSize;\r
+    TemporaryStackSize  = SecCoreData->StackSize;\r
+    TemporaryStackBase  = SecCoreData->StackBase;\r
+    PeiTemporaryRamSize = SecCoreData->PeiTemporaryRamSize;\r
+    PeiTemporaryRamBase = SecCoreData->PeiTemporaryRamBase;\r
+\r
+    //\r
+    // TemporaryRamSupportPpi is produced by platform's SEC\r
+    //\r
+    Status = PeiServicesLocatePpi (\r
+               &gEfiTemporaryRamSupportPpiGuid,\r
+               0,\r
+               NULL,\r
+               (VOID **)&TemporaryRamSupportPpi\r
+               );\r
+    if (!EFI_ERROR (Status)) {\r
+      //\r
+      // Heap Offset\r
+      //\r
+      BaseOfNewHeap = TopOfNewStack;\r
+      if (BaseOfNewHeap >= (UINTN)SecCoreData->PeiTemporaryRamBase) {\r
+        Private->HeapOffsetPositive = TRUE;\r
+        Private->HeapOffset         = (UINTN)(BaseOfNewHeap - (UINTN)SecCoreData->PeiTemporaryRamBase);\r
+      } else {\r
+        Private->HeapOffsetPositive = FALSE;\r
+        Private->HeapOffset         = (UINTN)((UINTN)SecCoreData->PeiTemporaryRamBase - BaseOfNewHeap);\r
+      }\r
+\r
+      DEBUG ((DEBUG_INFO, "Heap Offset = 0x%lX Stack Offset = 0x%lX\n", (UINT64)Private->HeapOffset, (UINT64)Private->StackOffset));\r
+\r
+      //\r
+      // Calculate new HandOffTable and PrivateData address in permanent memory's stack\r
+      //\r
+      if (StackOffsetPositive) {\r
+        SecCoreData = (CONST EFI_SEC_PEI_HAND_OFF *)((UINTN)(VOID *)SecCoreData + StackOffset);\r
+        Private     = (PEI_CORE_INSTANCE *)((UINTN)(VOID *)Private + StackOffset);\r
+      } else {\r
+        SecCoreData = (CONST EFI_SEC_PEI_HAND_OFF *)((UINTN)(VOID *)SecCoreData - StackOffset);\r
+        Private     = (PEI_CORE_INSTANCE *)((UINTN)(VOID *)Private - StackOffset);\r
+      }\r
+\r
+      //\r
+      // Temporary Ram Support PPI is provided by platform, it will copy\r
+      // temporary memory to permanent memory and do stack switching.\r
+      // After invoking Temporary Ram Support PPI, the following code's\r
+      // stack is in permanent memory.\r
+      //\r
+      TemporaryRamSupportPpi->TemporaryRamMigration (\r
+                                PeiServices,\r
+                                TemporaryRamBase,\r
+                                (EFI_PHYSICAL_ADDRESS)(UINTN)(TopOfNewStack - TemporaryStackSize),\r
+                                TemporaryRamSize\r
+                                );\r
+\r
+      //\r
+      // Migrate memory pages allocated in pre-memory phase.\r
+      // It could not be called before calling TemporaryRamSupportPpi->TemporaryRamMigration()\r
+      // as the migrated memory pages may be overridden by TemporaryRamSupportPpi->TemporaryRamMigration().\r
+      //\r
+      MigrateMemoryPages (Private, TRUE);\r
+\r
+      //\r
+      // Entry PEI Phase 2\r
+      //\r
+      PeiCore (SecCoreData, NULL, Private);\r
+    } else {\r
+      //\r
+      // Migrate memory pages allocated in pre-memory phase.\r
+      //\r
+      MigrateMemoryPages (Private, FALSE);\r
+\r
+      //\r
+      // Migrate the PEI Services Table pointer from temporary RAM to permanent RAM.\r
+      //\r
+      MigratePeiServicesTablePointer ();\r
+\r
+      //\r
+      // Heap Offset\r
+      //\r
+      BaseOfNewHeap = TopOfNewStack;\r
+      HoleMemBase   = TopOfNewStack;\r
+      HoleMemSize   = TemporaryRamSize - PeiTemporaryRamSize - TemporaryStackSize;\r
+      if (HoleMemSize != 0) {\r
+        //\r
+        // Make sure HOB List start address is 8 byte alignment.\r
+        //\r
+        BaseOfNewHeap = ALIGN_VALUE (BaseOfNewHeap + HoleMemSize, 8);\r
+      }\r
+\r
+      if (BaseOfNewHeap >= (UINTN)SecCoreData->PeiTemporaryRamBase) {\r
+        Private->HeapOffsetPositive = TRUE;\r
+        Private->HeapOffset         = (UINTN)(BaseOfNewHeap - (UINTN)SecCoreData->PeiTemporaryRamBase);\r
+      } else {\r
+        Private->HeapOffsetPositive = FALSE;\r
+        Private->HeapOffset         = (UINTN)((UINTN)SecCoreData->PeiTemporaryRamBase - BaseOfNewHeap);\r
+      }\r
+\r
+      DEBUG ((DEBUG_INFO, "Heap Offset = 0x%lX Stack Offset = 0x%lX\n", (UINT64)Private->HeapOffset, (UINT64)Private->StackOffset));\r
+\r
+      //\r
+      // Migrate Heap\r
+      //\r
+      HeapTemporaryRamSize = (UINTN)(Private->HobList.HandoffInformationTable->EfiFreeMemoryBottom - Private->HobList.HandoffInformationTable->EfiMemoryBottom);\r
+      ASSERT (BaseOfNewHeap + HeapTemporaryRamSize <= Private->FreePhysicalMemoryTop);\r
+      CopyMem ((UINT8 *)(UINTN)BaseOfNewHeap, PeiTemporaryRamBase, HeapTemporaryRamSize);\r
+\r
+      //\r
+      // Migrate Stack\r
+      //\r
+      CopyMem ((UINT8 *)(UINTN)(TopOfNewStack - TemporaryStackSize), TemporaryStackBase, TemporaryStackSize);\r
+\r
+      //\r
+      // Copy Hole Range Data\r
+      //\r
+      if (HoleMemSize != 0) {\r
+        //\r
+        // Prepare Hole\r
+        //\r
+        if (PeiTemporaryRamBase < TemporaryStackBase) {\r
+          TempBase1 = (EFI_PHYSICAL_ADDRESS)(UINTN)PeiTemporaryRamBase;\r
+          TempSize1 = PeiTemporaryRamSize;\r
+          TempBase2 = (EFI_PHYSICAL_ADDRESS)(UINTN)TemporaryStackBase;\r
+          TempSize2 = TemporaryStackSize;\r
+        } else {\r
+          TempBase1 = (EFI_PHYSICAL_ADDRESS)(UINTN)TemporaryStackBase;\r
+          TempSize1 = TemporaryStackSize;\r
+          TempBase2 = (EFI_PHYSICAL_ADDRESS)(UINTN)PeiTemporaryRamBase;\r
+          TempSize2 = PeiTemporaryRamSize;\r
+        }\r
+\r
+        if (TemporaryRamBase < TempBase1) {\r
+          Private->HoleData[0].Base = TemporaryRamBase;\r
+          Private->HoleData[0].Size = (UINTN)(TempBase1 - TemporaryRamBase);\r
+        }\r
+\r
+        if (TempBase1 + TempSize1 < TempBase2) {\r
+          Private->HoleData[1].Base = TempBase1 + TempSize1;\r
+          Private->HoleData[1].Size = (UINTN)(TempBase2 - TempBase1 - TempSize1);\r
+        }\r
+\r
+        if (TempBase2 + TempSize2 < TemporaryRamBase + TemporaryRamSize) {\r
+          Private->HoleData[2].Base = TempBase2 + TempSize2;\r
+          Private->HoleData[2].Size = (UINTN)(TemporaryRamBase + TemporaryRamSize - TempBase2 - TempSize2);\r
+        }\r
+\r
+        //\r
+        // Copy Hole Range data.\r
+        //\r
+        for (Index = 0; Index < HOLE_MAX_NUMBER; Index++) {\r
+          if (Private->HoleData[Index].Size > 0) {\r
+            if (HoleMemBase > Private->HoleData[Index].Base) {\r
+              Private->HoleData[Index].OffsetPositive = TRUE;\r
+              Private->HoleData[Index].Offset         = (UINTN)(HoleMemBase - Private->HoleData[Index].Base);\r
+            } else {\r
+              Private->HoleData[Index].OffsetPositive = FALSE;\r
+              Private->HoleData[Index].Offset         = (UINTN)(Private->HoleData[Index].Base - HoleMemBase);\r
+            }\r
+\r
+            CopyMem ((VOID *)(UINTN)HoleMemBase, (VOID *)(UINTN)Private->HoleData[Index].Base, Private->HoleData[Index].Size);\r
+            HoleMemBase = HoleMemBase + Private->HoleData[Index].Size;\r
+          }\r
+        }\r
+      }\r
+\r
+      //\r
+      // Switch new stack\r
+      //\r
+      SwitchStack (\r
+        (SWITCH_STACK_ENTRY_POINT)(UINTN)PeiCoreEntry,\r
+        (VOID *)SecCoreData,\r
+        (VOID *)Private,\r
+        (VOID *)(UINTN)TopOfNewStack\r
+        );\r
+    }\r
+\r
+    //\r
+    // Code should not come here\r
+    //\r
+    ASSERT (FALSE);\r
+  }\r
+}\r
+\r
+/**\r
+  Migrate a PEIM from temporary RAM to permanent memory.\r
+\r
+  @param PeimFileHandle       Pointer to the FFS file header of the image.\r
+  @param MigratedFileHandle   Pointer to the FFS file header of the migrated image.\r
+\r
+  @retval EFI_SUCCESS         Successfully migrated the PEIM to permanent memory.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+MigratePeim (\r
+  IN  EFI_PEI_FILE_HANDLE  FileHandle,\r
+  IN  EFI_PEI_FILE_HANDLE  MigratedFileHandle\r
+  )\r
+{\r
+  EFI_STATUS           Status;\r
+  EFI_FFS_FILE_HEADER  *FileHeader;\r
+  VOID                 *Pe32Data;\r
+  VOID                 *ImageAddress;\r
+  CHAR8                *AsciiString;\r
+  UINTN                Index;\r
+\r
+  Status = EFI_SUCCESS;\r
+\r
+  FileHeader = (EFI_FFS_FILE_HEADER *)FileHandle;\r
+  ASSERT (!IS_FFS_FILE2 (FileHeader));\r
+\r
+  ImageAddress = NULL;\r
+  PeiGetPe32Data (MigratedFileHandle, &ImageAddress);\r
+  if (ImageAddress != NULL) {\r
+    DEBUG_CODE_BEGIN ();\r
+    AsciiString = PeCoffLoaderGetPdbPointer (ImageAddress);\r
+    for (Index = 0; AsciiString[Index] != 0; Index++) {\r
+      if ((AsciiString[Index] == '\\') || (AsciiString[Index] == '/')) {\r
+        AsciiString = AsciiString + Index + 1;\r
+        Index       = 0;\r
+      } else if (AsciiString[Index] == '.') {\r
+        AsciiString[Index] = 0;\r
+      }\r
+    }\r
 \r
-typedef struct {\r
-  EFI_STATUS_CODE_DATA  DataHeader;\r
-  EFI_HANDLE            Handle;\r
-} PEIM_FILE_HANDLE_EXTENDED_DATA;\r
+    DEBUG ((DEBUG_VERBOSE, "%a", AsciiString));\r
+    DEBUG_CODE_END ();\r
 \r
-/**\r
+    Pe32Data = (VOID *)((UINTN)ImageAddress - (UINTN)MigratedFileHandle + (UINTN)FileHandle);\r
+    Status   = LoadAndRelocatePeCoffImageInPlace (Pe32Data, ImageAddress);\r
+    ASSERT_EFI_ERROR (Status);\r
+  }\r
 \r
-  Discover all Peims and optional Apriori file in one FV. There is at most one\r
-  Apriori file in one FV.\r
+  return Status;\r
+}\r
 \r
+/**\r
+  Migrate Status Code Callback function pointers inside an FV from temporary memory to permanent memory.\r
 \r
-  @param Private          Pointer to the private data passed in from caller\r
-  @param CoreFileHandle   The instance of PEI_CORE_FV_HANDLE.\r
+  @param OrgFvHandle      Address of FV handle in temporary memory.\r
+  @param FvHandle         Address of FV handle in permanent memory.\r
+  @param FvSize           Size of the FV.\r
 \r
 **/\r
 VOID\r
-DiscoverPeimsAndOrderWithApriori (\r
-  IN  PEI_CORE_INSTANCE    *Private,\r
-  IN  PEI_CORE_FV_HANDLE   *CoreFileHandle\r
+ConvertStatusCodeCallbacks (\r
+  IN  UINTN  OrgFvHandle,\r
+  IN  UINTN  FvHandle,\r
+  IN  UINTN  FvSize\r
   )\r
 {\r
-  EFI_STATUS                          Status;\r
-  EFI_PEI_FV_HANDLE                   FileHandle;\r
-  EFI_PEI_FILE_HANDLE                 AprioriFileHandle;\r
-  EFI_GUID                            *Apriori;\r
-  UINTN                               Index;\r
-  UINTN                               Index2;\r
-  UINTN                               PeimIndex;\r
-  UINTN                               PeimCount;\r
-  EFI_GUID                            *Guid;\r
-  EFI_PEI_FV_HANDLE                   TempFileHandles[FixedPcdGet32 (PcdPeiCoreMaxPeimPerFv)];\r
-  EFI_GUID                            FileGuid[FixedPcdGet32 (PcdPeiCoreMaxPeimPerFv)];\r
-  EFI_PEI_FIRMWARE_VOLUME_PPI         *FvPpi;\r
-  EFI_FV_FILE_INFO                    FileInfo;\r
-  \r
-  FvPpi = CoreFileHandle->FvPpi;\r
-  \r
-  //\r
-  // Walk the FV and find all the PEIMs and the Apriori file.\r
-  //\r
-  AprioriFileHandle = NULL;\r
-  Private->CurrentFvFileHandles[0] = NULL;\r
-  Guid = NULL;\r
-  FileHandle = NULL;\r
+  EFI_PEI_HOB_POINTERS  Hob;\r
+  UINTN                 *NumberOfEntries;\r
+  UINTN                 *CallbackEntry;\r
+  UINTN                 Index;\r
+\r
+  Hob.Raw = GetFirstGuidHob (&gStatusCodeCallbackGuid);\r
+  while (Hob.Raw != NULL) {\r
+    NumberOfEntries = GET_GUID_HOB_DATA (Hob);\r
+    CallbackEntry   = NumberOfEntries + 1;\r
+    for (Index = 0; Index < *NumberOfEntries; Index++) {\r
+      if (((VOID *)CallbackEntry[Index]) != NULL) {\r
+        if ((CallbackEntry[Index] >= OrgFvHandle) && (CallbackEntry[Index] < (OrgFvHandle + FvSize))) {\r
+          DEBUG ((\r
+            DEBUG_INFO,\r
+            "Migrating CallbackEntry[%Lu] from 0x%0*Lx to ",\r
+            (UINT64)Index,\r
+            (sizeof CallbackEntry[Index]) * 2,\r
+            (UINT64)CallbackEntry[Index]\r
+            ));\r
+          if (OrgFvHandle > FvHandle) {\r
+            CallbackEntry[Index] = CallbackEntry[Index] - (OrgFvHandle - FvHandle);\r
+          } else {\r
+            CallbackEntry[Index] = CallbackEntry[Index] + (FvHandle - OrgFvHandle);\r
+          }\r
 \r
-  //\r
-  // If the current Fv has been scanned, directly get its cachable record.\r
-  //\r
-  if (Private->Fv[Private->CurrentPeimFvCount].ScanFv) {\r
-    CopyMem (Private->CurrentFvFileHandles, Private->Fv[Private->CurrentPeimFvCount].FvFileHandles, sizeof (Private->CurrentFvFileHandles));\r
-    return;\r
+          DEBUG ((\r
+            DEBUG_INFO,\r
+            "0x%0*Lx\n",\r
+            (sizeof CallbackEntry[Index]) * 2,\r
+            (UINT64)CallbackEntry[Index]\r
+            ));\r
+        }\r
+      }\r
+    }\r
+\r
+    Hob.Raw = GET_NEXT_HOB (Hob);\r
+    Hob.Raw = GetNextGuidHob (&gStatusCodeCallbackGuid, Hob.Raw);\r
+  }\r
+}\r
+\r
+/**\r
+  Migrates PEIMs in the given firmware volume.\r
+\r
+  @param Private          Pointer to the PeiCore's private data structure.\r
+  @param FvIndex          The firmware volume index to migrate.\r
+  @param OrgFvHandle      The handle to the firmware volume in temporary memory.\r
+  @param FvHandle         The handle to the firmware volume in permanent memory.\r
+\r
+  @retval   EFI_SUCCESS           The PEIMs in the FV were migrated successfully\r
+  @retval   EFI_INVALID_PARAMETER The Private pointer is NULL or FvCount is invalid.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+MigratePeimsInFv (\r
+  IN PEI_CORE_INSTANCE  *Private,\r
+  IN  UINTN             FvIndex,\r
+  IN  UINTN             OrgFvHandle,\r
+  IN  UINTN             FvHandle\r
+  )\r
+{\r
+  EFI_STATUS           Status;\r
+  volatile UINTN       FileIndex;\r
+  EFI_PEI_FILE_HANDLE  MigratedFileHandle;\r
+  EFI_PEI_FILE_HANDLE  FileHandle;\r
+\r
+  if ((Private == NULL) || (FvIndex >= Private->FvCount)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (Private->Fv[FvIndex].ScanFv) {\r
+    for (FileIndex = 0; FileIndex < Private->Fv[FvIndex].PeimCount; FileIndex++) {\r
+      if (Private->Fv[FvIndex].FvFileHandles[FileIndex] != NULL) {\r
+        FileHandle = Private->Fv[FvIndex].FvFileHandles[FileIndex];\r
+\r
+        MigratedFileHandle = (EFI_PEI_FILE_HANDLE)((UINTN)FileHandle - OrgFvHandle + FvHandle);\r
+\r
+        DEBUG ((DEBUG_VERBOSE, "    Migrating FileHandle %2d ", FileIndex));\r
+        Status = MigratePeim (FileHandle, MigratedFileHandle);\r
+        DEBUG ((DEBUG_VERBOSE, "\n"));\r
+        ASSERT_EFI_ERROR (Status);\r
+\r
+        if (!EFI_ERROR (Status)) {\r
+          Private->Fv[FvIndex].FvFileHandles[FileIndex] = MigratedFileHandle;\r
+          if (FvIndex == Private->CurrentPeimFvCount) {\r
+            Private->CurrentFvFileHandles[FileIndex] = MigratedFileHandle;\r
+          }\r
+        }\r
+      }\r
+    }\r
   }\r
 \r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Migrate FVs out of temporary RAM before the cache is flushed.\r
+\r
+  @param Private         PeiCore's private data structure\r
+  @param SecCoreData     Points to a data structure containing information about the PEI core's operating\r
+                         environment, such as the size and location of temporary RAM, the stack location and\r
+                         the BFV location.\r
+\r
+  @retval EFI_SUCCESS           Successfully migrated installed FVs from temporary RAM to permanent memory.\r
+  @retval EFI_OUT_OF_RESOURCES  Insufficient memory exists to allocate needed pages.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EvacuateTempRam (\r
+  IN PEI_CORE_INSTANCE           *Private,\r
+  IN CONST EFI_SEC_PEI_HAND_OFF  *SecCoreData\r
+  )\r
+{\r
+  EFI_STATUS                  Status;\r
+  volatile UINTN              FvIndex;\r
+  volatile UINTN              FvChildIndex;\r
+  UINTN                       ChildFvOffset;\r
+  EFI_PHYSICAL_ADDRESS        FvHeaderAddress;\r
+  EFI_FIRMWARE_VOLUME_HEADER  *FvHeader;\r
+  EFI_FIRMWARE_VOLUME_HEADER  *ChildFvHeader;\r
+  EFI_FIRMWARE_VOLUME_HEADER  *MigratedFvHeader;\r
+  EFI_FIRMWARE_VOLUME_HEADER  *RawDataFvHeader;\r
+  EFI_FIRMWARE_VOLUME_HEADER  *MigratedChildFvHeader;\r
+\r
+  PEI_CORE_FV_HANDLE            PeiCoreFvHandle;\r
+  EFI_PEI_CORE_FV_LOCATION_PPI  *PeiCoreFvLocationPpi;\r
+  EDKII_MIGRATED_FV_INFO        MigratedFvInfo;\r
+\r
+  ASSERT (Private->PeiMemoryInstalled);\r
+\r
+  DEBUG ((DEBUG_VERBOSE, "Beginning evacuation of content in temporary RAM.\n"));\r
+\r
   //\r
-  // Go ahead to scan this Fv, and cache FileHandles within it.\r
+  // Migrate PPI Pointers of PEI_CORE from temporary memory to newly loaded PEI_CORE in permanent memory.\r
   //\r
-  for (PeimCount = 0; PeimCount < PcdGet32 (PcdPeiCoreMaxPeimPerFv); PeimCount++) {\r
-    Status = FvPpi->FindFileByType (FvPpi, PEI_CORE_INTERNAL_FFS_FILE_DISPATCH_TYPE, CoreFileHandle->FvHandle, &FileHandle);\r
-    if (Status != EFI_SUCCESS) {\r
+  Status = PeiLocatePpi ((CONST EFI_PEI_SERVICES **)&Private->Ps, &gEfiPeiCoreFvLocationPpiGuid, 0, NULL, (VOID **)&PeiCoreFvLocationPpi);\r
+  if (!EFI_ERROR (Status) && (PeiCoreFvLocationPpi->PeiCoreFvLocation != NULL)) {\r
+    PeiCoreFvHandle.FvHandle = (EFI_PEI_FV_HANDLE)PeiCoreFvLocationPpi->PeiCoreFvLocation;\r
+  } else {\r
+    PeiCoreFvHandle.FvHandle = (EFI_PEI_FV_HANDLE)SecCoreData->BootFirmwareVolumeBase;\r
+  }\r
+\r
+  for (FvIndex = 0; FvIndex < Private->FvCount; FvIndex++) {\r
+    if (Private->Fv[FvIndex].FvHandle == PeiCoreFvHandle.FvHandle) {\r
+      CopyMem (&PeiCoreFvHandle, &Private->Fv[FvIndex], sizeof (PEI_CORE_FV_HANDLE));\r
       break;\r
     }\r
-\r
-    Private->CurrentFvFileHandles[PeimCount] = FileHandle;\r
   }\r
-  \r
-  //\r
-  // Check whether the count of Peims exceeds the max support PEIMs in a FV image\r
-  // If more Peims are required in a FV image, PcdPeiCoreMaxPeimPerFv can be set to a larger value in DSC file.\r
-  //\r
-  ASSERT (PeimCount < PcdGet32 (PcdPeiCoreMaxPeimPerFv));\r
 \r
-  //\r
-  // Get Apriori File handle\r
-  //\r
-  Private->AprioriCount = 0;\r
-  Status = FvPpi->FindFileByName (FvPpi, &gPeiAprioriFileNameGuid, &CoreFileHandle->FvHandle, &AprioriFileHandle);\r
-  if (!EFI_ERROR(Status) && AprioriFileHandle != NULL) {\r
-    //\r
-    // Read the Apriori file\r
-    //\r
-    Status = FvPpi->FindSectionByType (FvPpi, EFI_SECTION_RAW, AprioriFileHandle, (VOID **) &Apriori);\r
-    if (!EFI_ERROR (Status)) {\r
+  Status = EFI_SUCCESS;\r
+\r
+  ConvertPeiCorePpiPointers (Private, &PeiCoreFvHandle);\r
+\r
+  for (FvIndex = 0; FvIndex < Private->FvCount; FvIndex++) {\r
+    FvHeader = Private->Fv[FvIndex].FvHeader;\r
+    ASSERT (FvHeader != NULL);\r
+    ASSERT (FvIndex < Private->FvCount);\r
+\r
+    DEBUG ((DEBUG_VERBOSE, "FV[%02d] at 0x%x.\n", FvIndex, (UINTN)FvHeader));\r
+    if (\r
+        !(\r
+          ((EFI_PHYSICAL_ADDRESS)(UINTN)FvHeader >= Private->PhysicalMemoryBegin) &&\r
+          (((EFI_PHYSICAL_ADDRESS)(UINTN)FvHeader + (FvHeader->FvLength - 1)) < Private->FreePhysicalMemoryTop)\r
+          )\r
+        )\r
+    {\r
       //\r
-      // Calculate the number of PEIMs in the A Priori list\r
+      // Allocate page to save the rebased PEIMs, the PEIMs will get dispatched later.\r
       //\r
-      Status = FvPpi->GetFileInfo (FvPpi, AprioriFileHandle, &FileInfo);\r
+      Status =  PeiServicesAllocatePages (\r
+                  EfiBootServicesCode,\r
+                  EFI_SIZE_TO_PAGES ((UINTN)FvHeader->FvLength),\r
+                  &FvHeaderAddress\r
+                  );\r
       ASSERT_EFI_ERROR (Status);\r
-      Private->AprioriCount = FileInfo.BufferSize & 0x00FFFFFF;\r
-      Private->AprioriCount -= sizeof (EFI_COMMON_SECTION_HEADER);\r
-      Private->AprioriCount /= sizeof (EFI_GUID);\r
-\r
-      ZeroMem (FileGuid, sizeof (FileGuid));\r
-      for (Index = 0; Index < PeimCount; Index++) {\r
-        //\r
-        // Make an array of file name guids that matches the FileHandle array so we can convert\r
-        // quickly from file name to file handle\r
-        //\r
-        Status = FvPpi->GetFileInfo (FvPpi, Private->CurrentFvFileHandles[Index], &FileInfo);\r
-        CopyMem (&FileGuid[Index], &FileInfo.FileName, sizeof(EFI_GUID));\r
-      }\r
+      MigratedFvHeader = (EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)FvHeaderAddress;\r
 \r
       //\r
-      // Walk through FileGuid array to find out who is invalid PEIM guid in Apriori file.\r
-      // Add avalible PEIMs in Apriori file into TempFileHandles array at first.\r
+      // Allocate pool to save the raw PEIMs, which is used to keep consistent context across\r
+      // multiple boot and PCR0 will keep the same no matter if the address of allocated page is changed.\r
       //\r
-      Index2 = 0;\r
-      for (Index = 0; Index2 < Private->AprioriCount; Index++) {\r
-        while (Index2 < Private->AprioriCount) {\r
-          Guid = ScanGuid (FileGuid, PeimCount * sizeof (EFI_GUID), &Apriori[Index2++]);\r
-          if (Guid != NULL) {\r
-            break;\r
-          }\r
-        }\r
-        if (Guid == NULL) {\r
-          break;\r
-        }\r
-        PeimIndex = ((UINTN)Guid - (UINTN)&FileGuid[0])/sizeof (EFI_GUID);\r
-        TempFileHandles[Index] = Private->CurrentFvFileHandles[PeimIndex];\r
+      Status =  PeiServicesAllocatePages (\r
+                  EfiBootServicesCode,\r
+                  EFI_SIZE_TO_PAGES ((UINTN)FvHeader->FvLength),\r
+                  &FvHeaderAddress\r
+                  );\r
+      ASSERT_EFI_ERROR (Status);\r
+      RawDataFvHeader = (EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)FvHeaderAddress;\r
 \r
-        //\r
-        // Since we have copied the file handle we can remove it from this list.\r
-        //\r
-        Private->CurrentFvFileHandles[PeimIndex] = NULL;\r
-      }\r
+      DEBUG ((\r
+        DEBUG_VERBOSE,\r
+        "  Migrating FV[%d] from 0x%08X to 0x%08X\n",\r
+        FvIndex,\r
+        (UINTN)FvHeader,\r
+        (UINTN)MigratedFvHeader\r
+        ));\r
 \r
       //\r
-      // Update valid Aprioricount\r
+      // Copy the context to the rebased pages and raw pages, and create hob to save the\r
+      // information. The MigratedFvInfo HOB will never be produced when\r
+      // PcdMigrateTemporaryRamFirmwareVolumes is FALSE, because the PCD control the\r
+      // feature.\r
       //\r
-      Private->AprioriCount = Index;\r
+      CopyMem (MigratedFvHeader, FvHeader, (UINTN)FvHeader->FvLength);\r
+      CopyMem (RawDataFvHeader, MigratedFvHeader, (UINTN)FvHeader->FvLength);\r
+      MigratedFvInfo.FvOrgBase  = (UINT32)(UINTN)FvHeader;\r
+      MigratedFvInfo.FvNewBase  = (UINT32)(UINTN)MigratedFvHeader;\r
+      MigratedFvInfo.FvDataBase = (UINT32)(UINTN)RawDataFvHeader;\r
+      MigratedFvInfo.FvLength   = (UINT32)(UINTN)FvHeader->FvLength;\r
+      BuildGuidDataHob (&gEdkiiMigratedFvInfoGuid, &MigratedFvInfo, sizeof (MigratedFvInfo));\r
 \r
       //\r
-      // Add in any PEIMs not in the Apriori file\r
+      // Migrate any children for this FV now\r
       //\r
-      for (;Index < PeimCount; Index++) {\r
-        for (Index2 = 0; Index2 < PeimCount; Index2++) {\r
-          if (Private->CurrentFvFileHandles[Index2] != NULL) {\r
-            TempFileHandles[Index] = Private->CurrentFvFileHandles[Index2];\r
-            Private->CurrentFvFileHandles[Index2] = NULL;\r
-            break;\r
-          }\r
+      for (FvChildIndex = FvIndex; FvChildIndex < Private->FvCount; FvChildIndex++) {\r
+        ChildFvHeader = Private->Fv[FvChildIndex].FvHeader;\r
+        if (\r
+            ((UINTN)ChildFvHeader > (UINTN)FvHeader) &&\r
+            (((UINTN)ChildFvHeader + ChildFvHeader->FvLength) < ((UINTN)FvHeader) + FvHeader->FvLength)\r
+            )\r
+        {\r
+          DEBUG ((DEBUG_VERBOSE, "    Child FV[%02d] is being migrated.\n", FvChildIndex));\r
+          ChildFvOffset = (UINTN)ChildFvHeader - (UINTN)FvHeader;\r
+          DEBUG ((DEBUG_VERBOSE, "    Child FV offset = 0x%x.\n", ChildFvOffset));\r
+          MigratedChildFvHeader              = (EFI_FIRMWARE_VOLUME_HEADER *)((UINTN)MigratedFvHeader + ChildFvOffset);\r
+          Private->Fv[FvChildIndex].FvHeader = MigratedChildFvHeader;\r
+          Private->Fv[FvChildIndex].FvHandle = (EFI_PEI_FV_HANDLE)MigratedChildFvHeader;\r
+          DEBUG ((DEBUG_VERBOSE, "    Child migrated FV header at 0x%x.\n", (UINTN)MigratedChildFvHeader));\r
+\r
+          Status =  MigratePeimsInFv (Private, FvChildIndex, (UINTN)ChildFvHeader, (UINTN)MigratedChildFvHeader);\r
+          ASSERT_EFI_ERROR (Status);\r
+\r
+          ConvertPpiPointersFv (\r
+            Private,\r
+            (UINTN)ChildFvHeader,\r
+            (UINTN)MigratedChildFvHeader,\r
+            (UINTN)ChildFvHeader->FvLength - 1\r
+            );\r
+\r
+          ConvertStatusCodeCallbacks (\r
+            (UINTN)ChildFvHeader,\r
+            (UINTN)MigratedChildFvHeader,\r
+            (UINTN)ChildFvHeader->FvLength - 1\r
+            );\r
+\r
+          ConvertFvHob (Private, (UINTN)ChildFvHeader, (UINTN)MigratedChildFvHeader);\r
         }\r
       }\r
-      //\r
-      //Index the end of array contains re-range Pei moudle.\r
-      //\r
-      TempFileHandles[Index] = NULL;\r
 \r
-      //\r
-      // Private->CurrentFvFileHandles is currently in PEIM in the FV order.\r
-      // We need to update it to start with files in the A Priori list and\r
-      // then the remaining files in PEIM order.\r
-      //\r
-      CopyMem (Private->CurrentFvFileHandles, TempFileHandles, sizeof (Private->CurrentFvFileHandles));\r
-    }\r
-  }\r
-  //\r
-  // Cache the current Fv File Handle. So that we don't have to scan the Fv again.\r
-  // Instead, we can retrieve the file handles within this Fv from cachable data.\r
-  //\r
-  Private->Fv[Private->CurrentPeimFvCount].ScanFv = TRUE;\r
-  CopyMem (Private->Fv[Private->CurrentPeimFvCount].FvFileHandles, Private->CurrentFvFileHandles, sizeof (Private->CurrentFvFileHandles));\r
-\r
-}\r
+      Private->Fv[FvIndex].FvHeader = MigratedFvHeader;\r
+      Private->Fv[FvIndex].FvHandle = (EFI_PEI_FV_HANDLE)MigratedFvHeader;\r
 \r
-/**\r
-  Shadow PeiCore module from flash to installed memory.\r
-  \r
-  @param PeiServices     An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.\r
-  @param PrivateInMem    PeiCore's private data structure\r
+      Status = MigratePeimsInFv (Private, FvIndex, (UINTN)FvHeader, (UINTN)MigratedFvHeader);\r
+      ASSERT_EFI_ERROR (Status);\r
 \r
-  @return PeiCore function address after shadowing.\r
-**/\r
-VOID*\r
-ShadowPeiCore(\r
-  IN CONST EFI_PEI_SERVICES     **PeiServices,\r
-  IN       PEI_CORE_INSTANCE    *PrivateInMem\r
-  )\r
-{\r
-  EFI_PEI_FILE_HANDLE  PeiCoreFileHandle;\r
-  EFI_PHYSICAL_ADDRESS EntryPoint;\r
-  EFI_STATUS           Status;\r
-  UINT32               AuthenticationState;\r
+      ConvertPpiPointersFv (\r
+        Private,\r
+        (UINTN)FvHeader,\r
+        (UINTN)MigratedFvHeader,\r
+        (UINTN)FvHeader->FvLength - 1\r
+        );\r
 \r
-  PeiCoreFileHandle = NULL;\r
+      ConvertStatusCodeCallbacks (\r
+        (UINTN)FvHeader,\r
+        (UINTN)MigratedFvHeader,\r
+        (UINTN)FvHeader->FvLength - 1\r
+        );\r
 \r
-  //\r
-  // Find the PEI Core in the BFV\r
-  //\r
-  Status = PrivateInMem->Fv[0].FvPpi->FindFileByType (\r
-                                        PrivateInMem->Fv[0].FvPpi,\r
-                                        EFI_FV_FILETYPE_PEI_CORE,\r
-                                        PrivateInMem->Fv[0].FvHandle,\r
-                                        &PeiCoreFileHandle\r
-                                        );\r
-  ASSERT_EFI_ERROR (Status);\r
+      ConvertFvHob (Private, (UINTN)FvHeader, (UINTN)MigratedFvHeader);\r
+    }\r
+  }\r
 \r
-  //\r
-  // Shadow PEI Core into memory so it will run faster\r
-  //\r
-  Status = PeiLoadImage (\r
-              PeiServices,\r
-              *((EFI_PEI_FILE_HANDLE*)&PeiCoreFileHandle),\r
-              PEIM_STATE_REGISITER_FOR_SHADOW,\r
-              &EntryPoint,\r
-              &AuthenticationState\r
-              );\r
-  ASSERT_EFI_ERROR (Status);\r
+  RemoveFvHobsInTemporaryMemory (Private);\r
 \r
-  //\r
-  // Compute the PeiCore's function address after shaowed PeiCore.\r
-  // _ModuleEntryPoint is PeiCore main function entry\r
-  //\r
-  return (VOID*) ((UINTN) EntryPoint + (UINTN) PeiCore - (UINTN) _ModuleEntryPoint);\r
+  return Status;\r
 }\r
 \r
 /**\r
@@ -249,86 +1350,79 @@ PeiDispatcher (
   IN PEI_CORE_INSTANCE           *Private\r
   )\r
 {\r
-  EFI_STATUS                          Status;\r
-  UINT32                              Index1;\r
-  UINT32                              Index2;\r
-  CONST EFI_PEI_SERVICES              **PeiServices;\r
-  EFI_PEI_FILE_HANDLE                 PeimFileHandle;\r
-  UINTN                               FvCount;\r
-  UINTN                               PeimCount;\r
-  UINT32                              AuthenticationState;\r
-  EFI_PHYSICAL_ADDRESS                EntryPoint;\r
-  EFI_PEIM_ENTRY_POINT2               PeimEntryPoint;\r
-  UINTN                               SaveCurrentPeimCount;\r
-  UINTN                               SaveCurrentFvCount;\r
-  EFI_PEI_FILE_HANDLE                 SaveCurrentFileHandle;\r
-  PEIM_FILE_HANDLE_EXTENDED_DATA      ExtendedData;\r
-  EFI_PHYSICAL_ADDRESS                NewPermenentMemoryBase;\r
-  TEMPORARY_RAM_SUPPORT_PPI           *TemporaryRamSupportPpi;\r
-  EFI_HOB_HANDOFF_INFO_TABLE          *OldHandOffTable;\r
-  EFI_HOB_HANDOFF_INFO_TABLE          *NewHandOffTable;\r
-  INTN                                StackOffset;\r
-  INTN                                HeapOffset;\r
-  PEI_CORE_INSTANCE                   *PrivateInMem;\r
-  UINT64                              NewPeiStackSize;\r
-  UINT64                              OldPeiStackSize;\r
-  UINT64                              StackGap;\r
-  EFI_FV_FILE_INFO                    FvFileInfo;\r
-  UINTN                               OldCheckingTop;\r
-  UINTN                               OldCheckingBottom;\r
-  PEI_CORE_FV_HANDLE                  *CoreFvHandle;\r
-\r
-  PeiServices = (CONST EFI_PEI_SERVICES **) &Private->PS;\r
+  EFI_STATUS              Status;\r
+  UINT32                  Index1;\r
+  UINT32                  Index2;\r
+  CONST EFI_PEI_SERVICES  **PeiServices;\r
+  EFI_PEI_FILE_HANDLE     PeimFileHandle;\r
+  UINTN                   FvCount;\r
+  UINTN                   PeimCount;\r
+  UINT32                  AuthenticationState;\r
+  EFI_PHYSICAL_ADDRESS    EntryPoint;\r
+  EFI_PEIM_ENTRY_POINT2   PeimEntryPoint;\r
+  UINTN                   SaveCurrentPeimCount;\r
+  UINTN                   SaveCurrentFvCount;\r
+  EFI_PEI_FILE_HANDLE     SaveCurrentFileHandle;\r
+  EFI_FV_FILE_INFO        FvFileInfo;\r
+  PEI_CORE_FV_HANDLE      *CoreFvHandle;\r
+\r
+  PeiServices    = (CONST EFI_PEI_SERVICES **)&Private->Ps;\r
   PeimEntryPoint = NULL;\r
   PeimFileHandle = NULL;\r
   EntryPoint     = 0;\r
 \r
-  if ((Private->PeiMemoryInstalled) && (Private->HobList.HandoffInformationTable->BootMode != BOOT_ON_S3_RESUME)) {\r
+  if ((Private->PeiMemoryInstalled) &&\r
+      (PcdGetBool (PcdMigrateTemporaryRamFirmwareVolumes) ||\r
+       (Private->HobList.HandoffInformationTable->BootMode != BOOT_ON_S3_RESUME) ||\r
+       PcdGetBool (PcdShadowPeimOnS3Boot))\r
+      )\r
+  {\r
     //\r
     // Once real memory is available, shadow the RegisterForShadow modules. And meanwhile\r
-    // update the modules' status from PEIM_STATE_REGISITER_FOR_SHADOW to PEIM_STATE_DONE.\r
+    // update the modules' status from PEIM_STATE_REGISTER_FOR_SHADOW to PEIM_STATE_DONE.\r
     //\r
     SaveCurrentPeimCount  = Private->CurrentPeimCount;\r
     SaveCurrentFvCount    = Private->CurrentPeimFvCount;\r
     SaveCurrentFileHandle =  Private->CurrentFileHandle;\r
 \r
-    for (Index1 = 0; Index1 <= SaveCurrentFvCount; Index1++) {\r
-      for (Index2 = 0; (Index2 < PcdGet32 (PcdPeiCoreMaxPeimPerFv)) && (Private->Fv[Index1].FvFileHandles[Index2] != NULL); Index2++) {\r
-        if (Private->Fv[Index1].PeimState[Index2] == PEIM_STATE_REGISITER_FOR_SHADOW) {\r
-          PeimFileHandle = Private->Fv[Index1].FvFileHandles[Index2];\r
-          Status = PeiLoadImage (\r
-                    (CONST EFI_PEI_SERVICES **) &Private->PS,\r
-                    PeimFileHandle,\r
-                    PEIM_STATE_REGISITER_FOR_SHADOW,\r
-                    &EntryPoint,\r
-                    &AuthenticationState\r
-                    );\r
+    for (Index1 = 0; Index1 < Private->FvCount; Index1++) {\r
+      for (Index2 = 0; Index2 < Private->Fv[Index1].PeimCount; Index2++) {\r
+        if (Private->Fv[Index1].PeimState[Index2] == PEIM_STATE_REGISTER_FOR_SHADOW) {\r
+          PeimFileHandle              = Private->Fv[Index1].FvFileHandles[Index2];\r
+          Private->CurrentFileHandle  = PeimFileHandle;\r
+          Private->CurrentPeimFvCount = Index1;\r
+          Private->CurrentPeimCount   = Index2;\r
+          Status                      = PeiLoadImage (\r
+                                          (CONST EFI_PEI_SERVICES **)&Private->Ps,\r
+                                          PeimFileHandle,\r
+                                          PEIM_STATE_REGISTER_FOR_SHADOW,\r
+                                          &EntryPoint,\r
+                                          &AuthenticationState\r
+                                          );\r
           if (Status == EFI_SUCCESS) {\r
             //\r
-            // PEIM_STATE_REGISITER_FOR_SHADOW move to PEIM_STATE_DONE\r
+            // PEIM_STATE_REGISTER_FOR_SHADOW move to PEIM_STATE_DONE\r
             //\r
             Private->Fv[Index1].PeimState[Index2]++;\r
-            Private->CurrentFileHandle   = PeimFileHandle;\r
-            Private->CurrentPeimFvCount  = Index1;\r
-            Private->CurrentPeimCount    = Index2;\r
             //\r
             // Call the PEIM entry point\r
             //\r
             PeimEntryPoint = (EFI_PEIM_ENTRY_POINT2)(UINTN)EntryPoint;\r
 \r
-            PERF_START (0, "PEIM", NULL, 0);\r
-            PeimEntryPoint(PeimFileHandle, (const EFI_PEI_SERVICES **) &Private->PS);\r
-            PERF_END (0, "PEIM", NULL, 0);\r
+            PERF_START_IMAGE_BEGIN (PeimFileHandle);\r
+            PeimEntryPoint (PeimFileHandle, (const EFI_PEI_SERVICES **)&Private->Ps);\r
+            PERF_START_IMAGE_END (PeimFileHandle);\r
           }\r
 \r
           //\r
           // Process the Notify list and dispatch any notifies for\r
           // newly installed PPIs.\r
           //\r
-          ProcessNotifyList (Private);\r
+          ProcessDispatchNotifyList (Private);\r
         }\r
       }\r
     }\r
+\r
     Private->CurrentFileHandle  = SaveCurrentFileHandle;\r
     Private->CurrentPeimFvCount = SaveCurrentFvCount;\r
     Private->CurrentPeimCount   = SaveCurrentPeimCount;\r
@@ -337,33 +1431,33 @@ PeiDispatcher (
   //\r
   // This is the main dispatch loop.  It will search known FVs for PEIMs and\r
   // attempt to dispatch them.  If any PEIM gets dispatched through a single\r
-  // pass of the dispatcher, it will start over from the Bfv again to see\r
+  // pass of the dispatcher, it will start over from the BFV again to see\r
   // if any new PEIMs dependencies got satisfied.  With a well ordered\r
   // FV where PEIMs are found in the order their dependencies are also\r
-  // satisfied, this dipatcher should run only once.\r
+  // satisfied, this dispatcher should run only once.\r
   //\r
   do {\r
     //\r
-    // In case that reenter PeiCore happens, the last pass record is still available.   \r
+    // In case that reenter PeiCore happens, the last pass record is still available.\r
     //\r
     if (!Private->PeimDispatcherReenter) {\r
-      Private->PeimNeedingDispatch      = FALSE;\r
-      Private->PeimDispatchOnThisPass   = FALSE;\r
+      Private->PeimNeedingDispatch    = FALSE;\r
+      Private->PeimDispatchOnThisPass = FALSE;\r
     } else {\r
-      Private->PeimDispatcherReenter    = FALSE;\r
+      Private->PeimDispatcherReenter = FALSE;\r
     }\r
-    \r
+\r
     for (FvCount = Private->CurrentPeimFvCount; FvCount < Private->FvCount; FvCount++) {\r
       CoreFvHandle = FindNextCoreFvHandle (Private, FvCount);\r
       ASSERT (CoreFvHandle != NULL);\r
-      \r
+\r
       //\r
       // If the FV has corresponding EFI_PEI_FIRMWARE_VOLUME_PPI instance, then dispatch it.\r
       //\r
       if (CoreFvHandle->FvPpi == NULL) {\r
         continue;\r
       }\r
-      \r
+\r
       Private->CurrentPeimFvCount = FvCount;\r
 \r
       if (Private->CurrentPeimCount == 0) {\r
@@ -376,13 +1470,14 @@ PeiDispatcher (
       }\r
 \r
       //\r
-      // Start to dispatch all modules within the current Fv.\r
+      // Start to dispatch all modules within the current FV.\r
       //\r
       for (PeimCount = Private->CurrentPeimCount;\r
-           (PeimCount < PcdGet32 (PcdPeiCoreMaxPeimPerFv)) && (Private->CurrentFvFileHandles[PeimCount] != NULL);\r
-           PeimCount++) {\r
-        Private->CurrentPeimCount  = PeimCount;\r
-        PeimFileHandle = Private->CurrentFileHandle = Private->CurrentFvFileHandles[PeimCount];\r
+           PeimCount < Private->Fv[FvCount].PeimCount;\r
+           PeimCount++)\r
+      {\r
+        Private->CurrentPeimCount = PeimCount;\r
+        PeimFileHandle            = Private->CurrentFileHandle = Private->CurrentFvFileHandles[PeimCount];\r
 \r
         if (Private->Fv[FvCount].PeimState[PeimCount] == PEIM_STATE_NOT_DISPATCHED) {\r
           if (!DepexSatisfied (Private, PeimFileHandle, PeimCount)) {\r
@@ -392,10 +1487,23 @@ PeiDispatcher (
             ASSERT_EFI_ERROR (Status);\r
             if (FvFileInfo.FileType == EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE) {\r
               //\r
-              // For Fv type file, Produce new FV PPI and FV hob\r
+              // For FV type file, Produce new FvInfo PPI and FV HOB\r
               //\r
-              Status = ProcessFvFile (&Private->Fv[FvCount], PeimFileHandle);\r
-              AuthenticationState = 0;\r
+              Status = ProcessFvFile (Private, &Private->Fv[FvCount], PeimFileHandle);\r
+              if (Status == EFI_SUCCESS) {\r
+                //\r
+                // PEIM_STATE_NOT_DISPATCHED move to PEIM_STATE_DISPATCHED\r
+                //\r
+                Private->Fv[FvCount].PeimState[PeimCount]++;\r
+                Private->PeimDispatchOnThisPass = TRUE;\r
+              } else {\r
+                //\r
+                // The related GuidedSectionExtraction/Decompress PPI for the\r
+                // encapsulated FV image section may be installed in the rest\r
+                // of this do-while loop, so need to make another pass.\r
+                //\r
+                Private->PeimNeedingDispatch = TRUE;\r
+              }\r
             } else {\r
               //\r
               // For PEIM driver, Load its entry point\r
@@ -407,256 +1515,101 @@ PeiDispatcher (
                          &EntryPoint,\r
                          &AuthenticationState\r
                          );\r
-            }\r
-\r
-            if ((Status == EFI_SUCCESS)) {\r
-              //\r
-              // The PEIM has its dependencies satisfied, and its entry point\r
-              // has been found, so invoke it.\r
-              //\r
-              PERF_START (0, "PEIM", NULL, 0);\r
-\r
-              ExtendedData.Handle = (EFI_HANDLE)PeimFileHandle;\r
-\r
-              REPORT_STATUS_CODE_WITH_EXTENDED_DATA (\r
-                EFI_PROGRESS_CODE,\r
-                (EFI_SOFTWARE_PEI_CORE | EFI_SW_PC_INIT_BEGIN),\r
-                (VOID *)(&ExtendedData),\r
-                sizeof (ExtendedData)\r
-                );\r
-\r
-              Status = VerifyPeim (Private, CoreFvHandle->FvHandle, PeimFileHandle);\r
-              if (Status != EFI_SECURITY_VIOLATION && (AuthenticationState == 0)) {\r
+              if (Status == EFI_SUCCESS) {\r
                 //\r
-                // PEIM_STATE_NOT_DISPATCHED move to PEIM_STATE_DISPATCHED\r
+                // The PEIM has its dependencies satisfied, and its entry point\r
+                // has been found, so invoke it.\r
                 //\r
-                Private->Fv[FvCount].PeimState[PeimCount]++;\r
+                PERF_START_IMAGE_BEGIN (PeimFileHandle);\r
 \r
-                if (FvFileInfo.FileType != EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE) {\r
+                REPORT_STATUS_CODE_WITH_EXTENDED_DATA (\r
+                  EFI_PROGRESS_CODE,\r
+                  (EFI_SOFTWARE_PEI_CORE | EFI_SW_PC_INIT_BEGIN),\r
+                  (VOID *)(&PeimFileHandle),\r
+                  sizeof (PeimFileHandle)\r
+                  );\r
+\r
+                Status = VerifyPeim (Private, CoreFvHandle->FvHandle, PeimFileHandle, AuthenticationState);\r
+                if (Status != EFI_SECURITY_VIOLATION) {\r
+                  //\r
+                  // PEIM_STATE_NOT_DISPATCHED move to PEIM_STATE_DISPATCHED\r
+                  //\r
+                  Private->Fv[FvCount].PeimState[PeimCount]++;\r
                   //\r
                   // Call the PEIM entry point for PEIM driver\r
                   //\r
                   PeimEntryPoint = (EFI_PEIM_ENTRY_POINT2)(UINTN)EntryPoint;\r
-                  PeimEntryPoint (PeimFileHandle, (const EFI_PEI_SERVICES **) PeiServices);\r
+                  PeimEntryPoint (PeimFileHandle, (const EFI_PEI_SERVICES **)PeiServices);\r
+                  Private->PeimDispatchOnThisPass = TRUE;\r
+                } else {\r
+                  //\r
+                  // The related GuidedSectionExtraction PPI for the\r
+                  // signed PEIM image section may be installed in the rest\r
+                  // of this do-while loop, so need to make another pass.\r
+                  //\r
+                  Private->PeimNeedingDispatch = TRUE;\r
                 }\r
 \r
-                Private->PeimDispatchOnThisPass = TRUE;\r
+                REPORT_STATUS_CODE_WITH_EXTENDED_DATA (\r
+                  EFI_PROGRESS_CODE,\r
+                  (EFI_SOFTWARE_PEI_CORE | EFI_SW_PC_INIT_END),\r
+                  (VOID *)(&PeimFileHandle),\r
+                  sizeof (PeimFileHandle)\r
+                  );\r
+                PERF_START_IMAGE_END (PeimFileHandle);\r
               }\r
-\r
-              REPORT_STATUS_CODE_WITH_EXTENDED_DATA (\r
-                EFI_PROGRESS_CODE,\r
-                (EFI_SOFTWARE_PEI_CORE | EFI_SW_PC_INIT_BEGIN),\r
-                (VOID *)(&ExtendedData),\r
-                sizeof (ExtendedData)\r
-                );\r
-              PERF_END (0, "PEIM", NULL, 0);\r
-\r
             }\r
 \r
-            if (Private->SwitchStackSignal) {\r
-              //\r
-              // Before switch stack from temporary memory to permenent memory, caculate the heap and stack\r
-              // usage in temporary memory for debuging.\r
-              //\r
-              DEBUG_CODE_BEGIN ();\r
-                UINT32  *StackPointer;\r
-                \r
-                for (StackPointer = (UINT32*)SecCoreData->StackBase;\r
-                     (StackPointer < (UINT32*)((UINTN)SecCoreData->StackBase + SecCoreData->StackSize)) \\r
-                     && (*StackPointer == INIT_CAR_VALUE);\r
-                     StackPointer ++);\r
-                     \r
-                DEBUG ((EFI_D_INFO, "Total temporary memory:    %d bytes.\n", (UINT32)SecCoreData->TemporaryRamSize));\r
-                DEBUG ((EFI_D_INFO, "  temporary memory stack ever used: %d bytes.\n",\r
-                       (SecCoreData->StackSize - ((UINTN) StackPointer - (UINTN)SecCoreData->StackBase))\r
-                      ));\r
-                DEBUG ((EFI_D_INFO, "  temporary memory heap used:       %d bytes.\n",\r
-                       ((UINTN) Private->HobList.HandoffInformationTable->EfiFreeMemoryBottom -\r
-                       (UINTN) Private->HobList.Raw)\r
-                      ));\r
-              DEBUG_CODE_END ();\r
-              \r
-              //\r
-              // Reserve the size of new stack at bottom of physical memory\r
-              //\r
-              OldPeiStackSize = (UINT64) SecCoreData->StackSize;\r
-              NewPeiStackSize = (RShiftU64 (Private->PhysicalMemoryLength, 1) + EFI_PAGE_MASK) & ~EFI_PAGE_MASK;\r
-              if (PcdGet32(PcdPeiCoreMaxPeiStackSize) > (UINT32) NewPeiStackSize) {\r
-                Private->StackSize = NewPeiStackSize;\r
-              } else {\r
-                Private->StackSize = PcdGet32(PcdPeiCoreMaxPeiStackSize);\r
-              }\r
-\r
-              //\r
-              // In theory, the size of new stack in permenent memory should large than\r
-              // size of old stack in temporary memory.\r
-              // But if new stack is smaller than the size of old stack, we also reserve\r
-              // the size of old stack at bottom of permenent memory.\r
-              //\r
-              DEBUG ((EFI_D_INFO, "Old Stack size %d, New stack size %d\n", (INT32) OldPeiStackSize, (INT32) Private->StackSize));\r
-              ASSERT (Private->StackSize >= OldPeiStackSize);\r
-              StackGap = Private->StackSize - OldPeiStackSize;\r
-\r
-              //\r
-              // Update HandOffHob for new installed permenent memory\r
-              //\r
-              OldHandOffTable   = Private->HobList.HandoffInformationTable;\r
-              OldCheckingBottom = (UINTN)(SecCoreData->TemporaryRamBase);\r
-              OldCheckingTop    = (UINTN)(OldCheckingBottom + SecCoreData->TemporaryRamSize);\r
-\r
-              //\r
-              // The whole temporary memory will be migrated to physical memory.\r
-              // CAUTION: The new base is computed accounding to gap of new stack.\r
-              //\r
-              NewPermenentMemoryBase = Private->PhysicalMemoryBegin + StackGap;\r
-              \r
-              //\r
-              // Caculate stack offset and heap offset between temporary memory and new permement \r
-              // memory seperately.\r
-              //\r
-              StackOffset            = (UINTN) NewPermenentMemoryBase - (UINTN) SecCoreData->StackBase;\r
-              HeapOffset             = (INTN) ((UINTN) Private->PhysicalMemoryBegin + Private->StackSize - \\r
-                                               (UINTN) SecCoreData->PeiTemporaryRamBase);\r
-              DEBUG ((EFI_D_INFO, "Heap Offset = 0x%lX Stack Offset = 0x%lX\n", (INT64)HeapOffset, (INT64)StackOffset));\r
-              \r
-              //\r
-              // Caculate new HandOffTable and PrivateData address in permenet memory's stack\r
-              //\r
-              NewHandOffTable        = (EFI_HOB_HANDOFF_INFO_TABLE *)((UINTN)OldHandOffTable + HeapOffset);\r
-              PrivateInMem           = (PEI_CORE_INSTANCE *)((UINTN) (VOID*) Private + StackOffset);\r
-\r
-              //\r
-              // TemporaryRamSupportPpi is produced by platform's SEC\r
-              //\r
-              Status = PeiLocatePpi (\r
-                         (CONST EFI_PEI_SERVICES **) PeiServices,\r
-                         &gEfiTemporaryRamSupportPpiGuid,\r
-                         0,\r
-                         NULL,\r
-                         (VOID**)&TemporaryRamSupportPpi\r
-                         );\r
-\r
-\r
-              if (!EFI_ERROR (Status)) {\r
-                //\r
-                // Temporary Ram support Ppi is provided by platform, it will copy \r
-                // temporary memory to permenent memory and do stack switching.\r
-                // After invoken temporary Ram support, following code's stack is in \r
-                // memory but not in temporary memory.\r
-                //\r
-                TemporaryRamSupportPpi->TemporaryRamMigration (\r
-                                          (CONST EFI_PEI_SERVICES **) PeiServices,\r
-                                          (EFI_PHYSICAL_ADDRESS)(UINTN) SecCoreData->TemporaryRamBase,\r
-                                          (EFI_PHYSICAL_ADDRESS)(UINTN) NewPermenentMemoryBase,\r
-                                          SecCoreData->TemporaryRamSize\r
-                                          );\r
-\r
-              } else {\r
-                //\r
-                // In IA32/x64/Itanium architecture, we need platform provide\r
-                // TEMPORAY_RAM_MIGRATION_PPI.\r
-                //\r
-                ASSERT (FALSE);\r
-              }\r
-\r
-\r
-              //\r
-              //\r
-              // Fixup the PeiCore's private data\r
-              //\r
-              PrivateInMem->PS          = &PrivateInMem->ServiceTableShadow;\r
-              PrivateInMem->CpuIo       = &PrivateInMem->ServiceTableShadow.CpuIo;\r
-              PrivateInMem->HobList.Raw = (VOID*) ((UINTN) PrivateInMem->HobList.Raw + HeapOffset);\r
-              PrivateInMem->StackBase   = (EFI_PHYSICAL_ADDRESS)(((UINTN)PrivateInMem->PhysicalMemoryBegin + EFI_PAGE_MASK) & ~EFI_PAGE_MASK);\r
-\r
-              PeiServices = (CONST EFI_PEI_SERVICES **) &PrivateInMem->PS;\r
-\r
-              //\r
-              // Fixup for PeiService's address\r
-              //\r
-              SetPeiServicesTablePointer(PeiServices);\r
-\r
-              //\r
-              // Update HandOffHob for new installed permenent memory\r
-              //\r
-              NewHandOffTable->EfiEndOfHobList =\r
-                (EFI_PHYSICAL_ADDRESS)((UINTN) NewHandOffTable->EfiEndOfHobList + HeapOffset);\r
-              NewHandOffTable->EfiMemoryTop        = PrivateInMem->PhysicalMemoryBegin +\r
-                                                     PrivateInMem->PhysicalMemoryLength;\r
-              NewHandOffTable->EfiMemoryBottom     = PrivateInMem->PhysicalMemoryBegin;\r
-              NewHandOffTable->EfiFreeMemoryTop    = PrivateInMem->FreePhysicalMemoryTop;\r
-              NewHandOffTable->EfiFreeMemoryBottom = NewHandOffTable->EfiEndOfHobList +\r
-                                                     sizeof (EFI_HOB_GENERIC_HEADER);\r
-\r
-              //\r
-              // We need convert the PPI desciptor's pointer\r
-              //\r
-              ConvertPpiPointers (PrivateInMem, \r
-                                  OldCheckingBottom, \r
-                                  OldCheckingTop, \r
-                                  HeapOffset\r
-                                  );\r
-\r
-              DEBUG ((EFI_D_INFO, "Stack Hob: BaseAddress=0x%lX Length=0x%lX\n",\r
-                                  PrivateInMem->StackBase,\r
-                                  PrivateInMem->StackSize));\r
-              BuildStackHob (PrivateInMem->StackBase, PrivateInMem->StackSize);\r
-\r
-              //\r
-              // After the whole temporary memory is migrated, then we can allocate page in\r
-              // permenent memory.\r
-              //\r
-              PrivateInMem->PeiMemoryInstalled     = TRUE;\r
-\r
-              //\r
-              // Indicate that PeiCore reenter\r
-              //\r
-              PrivateInMem->PeimDispatcherReenter  = TRUE;\r
-              \r
-              //\r
-              // Shadow PEI Core. When permanent memory is avaiable, shadow\r
-              // PEI Core and PEIMs to get high performance.\r
-              //\r
-              PrivateInMem->ShadowedPeiCore = ShadowPeiCore (\r
-                                                PeiServices,\r
-                                                PrivateInMem\r
-                                                );\r
-              //\r
-              // Process the Notify list and dispatch any notifies for\r
-              // newly installed PPIs.\r
-              //\r
-              ProcessNotifyList (PrivateInMem);\r
-\r
-              //\r
-              // Entry PEI Phase 2\r
-              //\r
-              PeiCore (SecCoreData, NULL, PrivateInMem);\r
-\r
-              //\r
-              // Code should not come here\r
-              //\r
-              ASSERT_EFI_ERROR(FALSE);\r
-            }\r
+            PeiCheckAndSwitchStack (SecCoreData, Private);\r
 \r
             //\r
             // Process the Notify list and dispatch any notifies for\r
             // newly installed PPIs.\r
             //\r
-            ProcessNotifyList (Private);\r
+            ProcessDispatchNotifyList (Private);\r
 \r
-            if ((Private->PeiMemoryInstalled) && (Private->Fv[FvCount].PeimState[PeimCount] == PEIM_STATE_REGISITER_FOR_SHADOW) &&   \\r
-                (Private->HobList.HandoffInformationTable->BootMode != BOOT_ON_S3_RESUME)) {\r
+            //\r
+            // Recheck SwitchStackSignal after ProcessDispatchNotifyList()\r
+            // in case PeiInstallPeiMemory() is done in a callback with\r
+            // EFI_PEI_PPI_DESCRIPTOR_NOTIFY_DISPATCH.\r
+            //\r
+            PeiCheckAndSwitchStack (SecCoreData, Private);\r
+\r
+            if ((Private->PeiMemoryInstalled) && (Private->Fv[FvCount].PeimState[PeimCount] == PEIM_STATE_REGISTER_FOR_SHADOW) &&   \\r
+                (PcdGetBool (PcdMigrateTemporaryRamFirmwareVolumes) ||\r
+                 (Private->HobList.HandoffInformationTable->BootMode != BOOT_ON_S3_RESUME) ||\r
+                 PcdGetBool (PcdShadowPeimOnS3Boot))\r
+                )\r
+            {\r
               //\r
-              // If memory is availble we shadow images by default for performance reasons.\r
+              // If memory is available we shadow images by default for performance reasons.\r
               // We call the entry point a 2nd time so the module knows it's shadowed.\r
               //\r
-              //PERF_START (PeiServices, L"PEIM", PeimFileHandle, 0);\r
+              // PERF_START (PeiServices, L"PEIM", PeimFileHandle, 0);\r
+              if ((Private->HobList.HandoffInformationTable->BootMode != BOOT_ON_S3_RESUME) && !PcdGetBool (PcdShadowPeimOnBoot) &&\r
+                  !PcdGetBool (PcdMigrateTemporaryRamFirmwareVolumes))\r
+              {\r
+                //\r
+                // Load PEIM into Memory for Register for shadow PEIM.\r
+                //\r
+                Status = PeiLoadImage (\r
+                           PeiServices,\r
+                           PeimFileHandle,\r
+                           PEIM_STATE_REGISTER_FOR_SHADOW,\r
+                           &EntryPoint,\r
+                           &AuthenticationState\r
+                           );\r
+                if (Status == EFI_SUCCESS) {\r
+                  PeimEntryPoint = (EFI_PEIM_ENTRY_POINT2)(UINTN)EntryPoint;\r
+                }\r
+              }\r
+\r
               ASSERT (PeimEntryPoint != NULL);\r
-              PeimEntryPoint (PeimFileHandle, (const EFI_PEI_SERVICES **) PeiServices);\r
-              //PERF_END (PeiServices, L"PEIM", PeimFileHandle, 0);\r
+              PeimEntryPoint (PeimFileHandle, (const EFI_PEI_SERVICES **)PeiServices);\r
+              // PERF_END (PeiServices, L"PEIM", PeimFileHandle, 0);\r
 \r
               //\r
-              // PEIM_STATE_REGISITER_FOR_SHADOW move to PEIM_STATE_DONE\r
+              // PEIM_STATE_REGISTER_FOR_SHADOW move to PEIM_STATE_DONE\r
               //\r
               Private->Fv[FvCount].PeimState[PeimCount]++;\r
 \r
@@ -664,41 +1617,36 @@ PeiDispatcher (
               // Process the Notify list and dispatch any notifies for\r
               // newly installed PPIs.\r
               //\r
-              ProcessNotifyList (Private);\r
+              ProcessDispatchNotifyList (Private);\r
             }\r
           }\r
         }\r
       }\r
 \r
       //\r
-      // We set to NULL here to optimize the 2nd entry to this routine after\r
-      //  memory is found. This reprevents rescanning of the FV. We set to\r
-      //  NULL here so we start at the begining of the next FV\r
-      //\r
-      Private->CurrentFileHandle = NULL;\r
-      Private->CurrentPeimCount = 0;\r
+      // Before walking through the next FV, we should set them to NULL/0 to\r
+      // start at the beginning of the next FV.\r
       //\r
-      // Before walking through the next FV,Private->CurrentFvFileHandles[]should set to NULL\r
-      //\r
-      SetMem (Private->CurrentFvFileHandles, sizeof (Private->CurrentFvFileHandles), 0);\r
+      Private->CurrentFileHandle    = NULL;\r
+      Private->CurrentPeimCount     = 0;\r
+      Private->CurrentFvFileHandles = NULL;\r
     }\r
 \r
     //\r
-    // Before making another pass, we should set Private->CurrentPeimFvCount =0 to go\r
-    // through all the FV.\r
+    // Before making another pass, we should set it to 0 to\r
+    // go through all the FVs.\r
     //\r
     Private->CurrentPeimFvCount = 0;\r
 \r
     //\r
-    // PeimNeedingDispatch being TRUE means we found a PEIM that did not get\r
+    // PeimNeedingDispatch being TRUE means we found a PEIM/FV that did not get\r
     //  dispatched. So we need to make another pass\r
     //\r
-    // PeimDispatchOnThisPass being TRUE means we dispatched a PEIM on this\r
-    //  pass. If we did not dispatch a PEIM there is no point in trying again\r
+    // PeimDispatchOnThisPass being TRUE means we dispatched a PEIM/FV on this\r
+    //  pass. If we did not dispatch a PEIM/FV there is no point in trying again\r
     //  as it will fail the next time too (nothing has changed).\r
     //\r
   } while (Private->PeimNeedingDispatch && Private->PeimDispatchOnThisPass);\r
-\r
 }\r
 \r
 /**\r
@@ -706,7 +1654,7 @@ PeiDispatcher (
 \r
   @param PrivateData     PeiCore's private data structure\r
   @param OldCoreData     Old data from SecCore\r
-                         NULL if being run in non-permament memory mode.\r
+                         NULL if being run in non-permanent memory mode.\r
   @param SecCoreData     Points to a data structure containing information about the PEI core's operating\r
                          environment, such as the size and location of temporary RAM, the stack location and\r
                          the BFV location.\r
@@ -716,9 +1664,9 @@ PeiDispatcher (
 **/\r
 VOID\r
 InitializeDispatcherData (\r
-  IN PEI_CORE_INSTANCE            *PrivateData,\r
-  IN PEI_CORE_INSTANCE            *OldCoreData,\r
-  IN CONST EFI_SEC_PEI_HAND_OFF   *SecCoreData\r
+  IN PEI_CORE_INSTANCE           *PrivateData,\r
+  IN PEI_CORE_INSTANCE           *OldCoreData,\r
+  IN CONST EFI_SEC_PEI_HAND_OFF  *SecCoreData\r
   )\r
 {\r
   if (OldCoreData == NULL) {\r
@@ -746,18 +1694,27 @@ InitializeDispatcherData (
 **/\r
 BOOLEAN\r
 DepexSatisfied (\r
-  IN PEI_CORE_INSTANCE          *Private,\r
-  IN EFI_PEI_FILE_HANDLE        FileHandle,\r
-  IN UINTN                      PeimCount\r
+  IN PEI_CORE_INSTANCE    *Private,\r
+  IN EFI_PEI_FILE_HANDLE  FileHandle,\r
+  IN UINTN                PeimCount\r
   )\r
 {\r
-  EFI_STATUS           Status;\r
-  VOID                 *DepexData;\r
+  EFI_STATUS        Status;\r
+  VOID              *DepexData;\r
+  EFI_FV_FILE_INFO  FileInfo;\r
+\r
+  Status = PeiServicesFfsGetFileInfo (FileHandle, &FileInfo);\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((DEBUG_DISPATCH, "Evaluate PEI DEPEX for FFS(Unknown)\n"));\r
+  } else {\r
+    DEBUG ((DEBUG_DISPATCH, "Evaluate PEI DEPEX for FFS(%g)\n", &FileInfo.FileName));\r
+  }\r
 \r
   if (PeimCount < Private->AprioriCount) {\r
     //\r
-    // If its in the A priori file then we set Depex to TRUE\r
+    // If it's in the Apriori file then we set DEPEX to TRUE\r
     //\r
+    DEBUG ((DEBUG_DISPATCH, "  RESULT = TRUE (Apriori)\n"));\r
     return TRUE;\r
   }\r
 \r
@@ -765,27 +1722,28 @@ DepexSatisfied (
   // Depex section not in the encapsulated section.\r
   //\r
   Status = PeiServicesFfsFindSectionData (\r
-              EFI_SECTION_PEI_DEPEX,\r
-              FileHandle,\r
-              (VOID **)&DepexData\r
-              );\r
+             EFI_SECTION_PEI_DEPEX,\r
+             FileHandle,\r
+             (VOID **)&DepexData\r
+             );\r
 \r
   if (EFI_ERROR (Status)) {\r
     //\r
     // If there is no DEPEX, assume the module can be executed\r
     //\r
+    DEBUG ((DEBUG_DISPATCH, "  RESULT = TRUE (No DEPEX)\n"));\r
     return TRUE;\r
   }\r
 \r
   //\r
   // Evaluate a given DEPEX\r
   //\r
-  return PeimDispatchReadiness (&Private->PS, DepexData);\r
+  return PeimDispatchReadiness (&Private->Ps, DepexData);\r
 }\r
 \r
 /**\r
-  This routine enable a PEIM to register itself to shadow when PEI Foundation\r
-  discovery permanent memory.\r
+  This routine enables a PEIM to register itself for shadow when the PEI Foundation\r
+  discovers permanent memory.\r
 \r
   @param FileHandle             File handle of a PEIM.\r
 \r
@@ -797,10 +1755,11 @@ DepexSatisfied (
 EFI_STATUS\r
 EFIAPI\r
 PeiRegisterForShadow (\r
-  IN EFI_PEI_FILE_HANDLE       FileHandle\r
+  IN EFI_PEI_FILE_HANDLE  FileHandle\r
   )\r
 {\r
-  PEI_CORE_INSTANCE            *Private;\r
+  PEI_CORE_INSTANCE  *Private;\r
+\r
   Private = PEI_CORE_INSTANCE_FROM_PS_THIS (GetPeiServicesTablePointer ());\r
 \r
   if (Private->CurrentFileHandle != FileHandle) {\r
@@ -810,17 +1769,14 @@ PeiRegisterForShadow (
     return EFI_NOT_FOUND;\r
   }\r
 \r
-  if (Private->Fv[Private->CurrentPeimFvCount].PeimState[Private->CurrentPeimCount] >= PEIM_STATE_REGISITER_FOR_SHADOW) {\r
+  if (Private->Fv[Private->CurrentPeimFvCount].PeimState[Private->CurrentPeimCount] >= PEIM_STATE_REGISTER_FOR_SHADOW) {\r
     //\r
     // If the PEIM has already entered the PEIM_STATE_REGISTER_FOR_SHADOW or PEIM_STATE_DONE then it's already been started\r
     //\r
     return EFI_ALREADY_STARTED;\r
   }\r
 \r
-  Private->Fv[Private->CurrentPeimFvCount].PeimState[Private->CurrentPeimCount] = PEIM_STATE_REGISITER_FOR_SHADOW;\r
+  Private->Fv[Private->CurrentPeimFvCount].PeimState[Private->CurrentPeimCount] = PEIM_STATE_REGISTER_FOR_SHADOW;\r
 \r
   return EFI_SUCCESS;\r
 }\r
-\r
-\r
-\r