REF: https://bugzilla.tianocore.org/show_bug.cgi?id=3098 XCODE5 toolchain in NOOPT mode generates memcpy when trying to copy PEI_CORE_FV_HANDLE structure. This breaks OVMF compilation with XCODE5. Cc: Jian J Wang <jian.j.wang@intel.com> Cc: Hao A Wu <hao.a.wu@intel.com> Cc: Jordan Justen <jordan.l.justen@intel.com> Cc: Laszlo Ersek <lersek@redhat.com> Cc: Ard Biesheuvel <ard.biesheuvel@arm.com> Signed-off-by: Vitaly Cheptsov <cheptsov@ispras.ru> Reviewed-by: Liming Gao <gaoliming@byosoft.com.cn> Reviewed-by: Michael D Kinney <michael.d.kinney@intel.com>
		
			
				
	
	
		
			1829 lines
		
	
	
		
			72 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1829 lines
		
	
	
		
			72 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/** @file
 | 
						|
  EFI PEI Core dispatch services
 | 
						|
 | 
						|
Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
 | 
						|
(C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>
 | 
						|
SPDX-License-Identifier: BSD-2-Clause-Patent
 | 
						|
 | 
						|
**/
 | 
						|
 | 
						|
#include "PeiMain.h"
 | 
						|
 | 
						|
/**
 | 
						|
 | 
						|
  Discover all PEIMs and optional Apriori file in one FV. There is at most one
 | 
						|
  Apriori file in one FV.
 | 
						|
 | 
						|
 | 
						|
  @param Private          Pointer to the private data passed in from caller
 | 
						|
  @param CoreFileHandle   The instance of PEI_CORE_FV_HANDLE.
 | 
						|
 | 
						|
**/
 | 
						|
VOID
 | 
						|
DiscoverPeimsAndOrderWithApriori (
 | 
						|
  IN  PEI_CORE_INSTANCE    *Private,
 | 
						|
  IN  PEI_CORE_FV_HANDLE   *CoreFileHandle
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS                          Status;
 | 
						|
  EFI_PEI_FILE_HANDLE                 FileHandle;
 | 
						|
  EFI_PEI_FILE_HANDLE                 AprioriFileHandle;
 | 
						|
  EFI_GUID                            *Apriori;
 | 
						|
  UINTN                               Index;
 | 
						|
  UINTN                               Index2;
 | 
						|
  UINTN                               PeimIndex;
 | 
						|
  UINTN                               PeimCount;
 | 
						|
  EFI_GUID                            *Guid;
 | 
						|
  EFI_PEI_FILE_HANDLE                 *TempFileHandles;
 | 
						|
  EFI_GUID                            *TempFileGuid;
 | 
						|
  EFI_PEI_FIRMWARE_VOLUME_PPI         *FvPpi;
 | 
						|
  EFI_FV_FILE_INFO                    FileInfo;
 | 
						|
 | 
						|
  FvPpi = CoreFileHandle->FvPpi;
 | 
						|
 | 
						|
  //
 | 
						|
  // Walk the FV and find all the PEIMs and the Apriori file.
 | 
						|
  //
 | 
						|
  AprioriFileHandle = NULL;
 | 
						|
  Private->CurrentFvFileHandles = NULL;
 | 
						|
  Guid = NULL;
 | 
						|
 | 
						|
  //
 | 
						|
  // If the current FV has been scanned, directly get its cached records.
 | 
						|
  //
 | 
						|
  if (CoreFileHandle->ScanFv) {
 | 
						|
    Private->CurrentFvFileHandles = CoreFileHandle->FvFileHandles;
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  TempFileHandles = Private->TempFileHandles;
 | 
						|
  TempFileGuid    = Private->TempFileGuid;
 | 
						|
 | 
						|
  //
 | 
						|
  // Go ahead to scan this FV, get PeimCount and cache FileHandles within it to TempFileHandles.
 | 
						|
  //
 | 
						|
  PeimCount = 0;
 | 
						|
  FileHandle = NULL;
 | 
						|
  do {
 | 
						|
    Status = FvPpi->FindFileByType (FvPpi, PEI_CORE_INTERNAL_FFS_FILE_DISPATCH_TYPE, CoreFileHandle->FvHandle, &FileHandle);
 | 
						|
    if (!EFI_ERROR (Status)) {
 | 
						|
      if (PeimCount >= Private->TempPeimCount) {
 | 
						|
        //
 | 
						|
        // Run out of room, grow the buffer.
 | 
						|
        //
 | 
						|
        TempFileHandles = AllocatePool (
 | 
						|
                            sizeof (EFI_PEI_FILE_HANDLE) * (Private->TempPeimCount + TEMP_FILE_GROWTH_STEP));
 | 
						|
        ASSERT (TempFileHandles != NULL);
 | 
						|
        CopyMem (
 | 
						|
          TempFileHandles,
 | 
						|
          Private->TempFileHandles,
 | 
						|
          sizeof (EFI_PEI_FILE_HANDLE) * Private->TempPeimCount
 | 
						|
          );
 | 
						|
        Private->TempFileHandles = TempFileHandles;
 | 
						|
        TempFileGuid = AllocatePool (
 | 
						|
                         sizeof (EFI_GUID) * (Private->TempPeimCount + TEMP_FILE_GROWTH_STEP));
 | 
						|
        ASSERT (TempFileGuid != NULL);
 | 
						|
        CopyMem (
 | 
						|
          TempFileGuid,
 | 
						|
          Private->TempFileGuid,
 | 
						|
          sizeof (EFI_GUID) * Private->TempPeimCount
 | 
						|
          );
 | 
						|
        Private->TempFileGuid = TempFileGuid;
 | 
						|
        Private->TempPeimCount = Private->TempPeimCount + TEMP_FILE_GROWTH_STEP;
 | 
						|
      }
 | 
						|
 | 
						|
      TempFileHandles[PeimCount++] = FileHandle;
 | 
						|
    }
 | 
						|
  } while (!EFI_ERROR (Status));
 | 
						|
 | 
						|
  DEBUG ((
 | 
						|
    DEBUG_INFO,
 | 
						|
    "%a(): Found 0x%x PEI FFS files in the %dth FV\n",
 | 
						|
    __FUNCTION__,
 | 
						|
    PeimCount,
 | 
						|
    Private->CurrentPeimFvCount
 | 
						|
    ));
 | 
						|
 | 
						|
  if (PeimCount == 0) {
 | 
						|
    //
 | 
						|
    // No PEIM FFS file is found, set ScanFv flag and return.
 | 
						|
    //
 | 
						|
    CoreFileHandle->ScanFv = TRUE;
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Record PeimCount, allocate buffer for PeimState and FvFileHandles.
 | 
						|
  //
 | 
						|
  CoreFileHandle->PeimCount = PeimCount;
 | 
						|
  CoreFileHandle->PeimState = AllocateZeroPool (sizeof (UINT8) * PeimCount);
 | 
						|
  ASSERT (CoreFileHandle->PeimState != NULL);
 | 
						|
  CoreFileHandle->FvFileHandles = AllocateZeroPool (sizeof (EFI_PEI_FILE_HANDLE) * PeimCount);
 | 
						|
  ASSERT (CoreFileHandle->FvFileHandles != NULL);
 | 
						|
 | 
						|
  //
 | 
						|
  // Get Apriori File handle
 | 
						|
  //
 | 
						|
  Private->AprioriCount = 0;
 | 
						|
  Status = FvPpi->FindFileByName (FvPpi, &gPeiAprioriFileNameGuid, &CoreFileHandle->FvHandle, &AprioriFileHandle);
 | 
						|
  if (!EFI_ERROR(Status) && AprioriFileHandle != NULL) {
 | 
						|
    //
 | 
						|
    // Read the Apriori file
 | 
						|
    //
 | 
						|
    Status = FvPpi->FindSectionByType (FvPpi, EFI_SECTION_RAW, AprioriFileHandle, (VOID **) &Apriori);
 | 
						|
    if (!EFI_ERROR (Status)) {
 | 
						|
      //
 | 
						|
      // Calculate the number of PEIMs in the Apriori file
 | 
						|
      //
 | 
						|
      Status = FvPpi->GetFileInfo (FvPpi, AprioriFileHandle, &FileInfo);
 | 
						|
      ASSERT_EFI_ERROR (Status);
 | 
						|
      Private->AprioriCount = FileInfo.BufferSize;
 | 
						|
      if (IS_SECTION2 (FileInfo.Buffer)) {
 | 
						|
        Private->AprioriCount -= sizeof (EFI_COMMON_SECTION_HEADER2);
 | 
						|
      } else {
 | 
						|
        Private->AprioriCount -= sizeof (EFI_COMMON_SECTION_HEADER);
 | 
						|
      }
 | 
						|
      Private->AprioriCount /= sizeof (EFI_GUID);
 | 
						|
 | 
						|
      for (Index = 0; Index < PeimCount; Index++) {
 | 
						|
        //
 | 
						|
        // Make an array of file name GUIDs that matches the FileHandle array so we can convert
 | 
						|
        // quickly from file name to file handle
 | 
						|
        //
 | 
						|
        Status = FvPpi->GetFileInfo (FvPpi, TempFileHandles[Index], &FileInfo);
 | 
						|
        ASSERT_EFI_ERROR (Status);
 | 
						|
        CopyMem (&TempFileGuid[Index], &FileInfo.FileName, sizeof(EFI_GUID));
 | 
						|
      }
 | 
						|
 | 
						|
      //
 | 
						|
      // Walk through TempFileGuid array to find out who is invalid PEIM GUID in Apriori file.
 | 
						|
      // Add available PEIMs in Apriori file into FvFileHandles array.
 | 
						|
      //
 | 
						|
      Index = 0;
 | 
						|
      for (Index2 = 0; Index2 < Private->AprioriCount; Index2++) {
 | 
						|
        Guid = ScanGuid (TempFileGuid, PeimCount * sizeof (EFI_GUID), &Apriori[Index2]);
 | 
						|
        if (Guid != NULL) {
 | 
						|
          PeimIndex = ((UINTN)Guid - (UINTN)&TempFileGuid[0])/sizeof (EFI_GUID);
 | 
						|
          CoreFileHandle->FvFileHandles[Index++] = TempFileHandles[PeimIndex];
 | 
						|
 | 
						|
          //
 | 
						|
          // Since we have copied the file handle we can remove it from this list.
 | 
						|
          //
 | 
						|
          TempFileHandles[PeimIndex] = NULL;
 | 
						|
        }
 | 
						|
      }
 | 
						|
 | 
						|
      //
 | 
						|
      // Update valid AprioriCount
 | 
						|
      //
 | 
						|
      Private->AprioriCount = Index;
 | 
						|
 | 
						|
      //
 | 
						|
      // Add in any PEIMs not in the Apriori file
 | 
						|
      //
 | 
						|
      for (Index2 = 0; Index2 < PeimCount; Index2++) {
 | 
						|
        if (TempFileHandles[Index2] != NULL) {
 | 
						|
          CoreFileHandle->FvFileHandles[Index++] = TempFileHandles[Index2];
 | 
						|
          TempFileHandles[Index2] = NULL;
 | 
						|
        }
 | 
						|
      }
 | 
						|
      ASSERT (Index == PeimCount);
 | 
						|
    }
 | 
						|
  } else {
 | 
						|
    CopyMem (CoreFileHandle->FvFileHandles, TempFileHandles, sizeof (EFI_PEI_FILE_HANDLE) * PeimCount);
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // The current FV File Handles have been cached. So that we don't have to scan the FV again.
 | 
						|
  // Instead, we can retrieve the file handles within this FV from cached records.
 | 
						|
  //
 | 
						|
  CoreFileHandle->ScanFv = TRUE;
 | 
						|
  Private->CurrentFvFileHandles = CoreFileHandle->FvFileHandles;
 | 
						|
}
 | 
						|
 | 
						|
//
 | 
						|
// This is the minimum memory required by DxeCore initialization. When LMFA feature enabled,
 | 
						|
// This part of memory still need reserved on the very top of memory so that the DXE Core could
 | 
						|
// use these memory for data initialization. This macro should be sync with the same marco
 | 
						|
// defined in DXE Core.
 | 
						|
//
 | 
						|
#define MINIMUM_INITIAL_MEMORY_SIZE 0x10000
 | 
						|
/**
 | 
						|
  This function is to test if the memory range described in resource HOB is available or not.
 | 
						|
 | 
						|
  This function should only be invoked when Loading Module at Fixed Address(LMFA) feature is enabled. Some platform may allocate the
 | 
						|
  memory before PeiLoadFixAddressHook in invoked. so this function is to test if the memory range described by the input resource HOB is
 | 
						|
  available or not.
 | 
						|
 | 
						|
  @param PrivateData         Pointer to the private data passed in from caller
 | 
						|
  @param ResourceHob         Pointer to a resource HOB which described the memory range described by the input resource HOB
 | 
						|
**/
 | 
						|
BOOLEAN
 | 
						|
PeiLoadFixAddressIsMemoryRangeAvailable (
 | 
						|
  IN PEI_CORE_INSTANCE                  *PrivateData,
 | 
						|
  IN EFI_HOB_RESOURCE_DESCRIPTOR        *ResourceHob
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_HOB_MEMORY_ALLOCATION          *MemoryHob;
 | 
						|
  BOOLEAN                             IsAvailable;
 | 
						|
  EFI_PEI_HOB_POINTERS                Hob;
 | 
						|
 | 
						|
  IsAvailable = TRUE;
 | 
						|
  if (PrivateData == NULL || ResourceHob == NULL) {
 | 
						|
    return FALSE;
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // test if the memory range describe in the HOB is already allocated.
 | 
						|
  //
 | 
						|
  for (Hob.Raw = PrivateData->HobList.Raw; !END_OF_HOB_LIST(Hob); Hob.Raw = GET_NEXT_HOB(Hob)) {
 | 
						|
    //
 | 
						|
    // See if this is a memory allocation HOB
 | 
						|
    //
 | 
						|
    if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_MEMORY_ALLOCATION) {
 | 
						|
      MemoryHob = Hob.MemoryAllocation;
 | 
						|
      if(MemoryHob->AllocDescriptor.MemoryBaseAddress == ResourceHob->PhysicalStart &&
 | 
						|
         MemoryHob->AllocDescriptor.MemoryBaseAddress + MemoryHob->AllocDescriptor.MemoryLength == ResourceHob->PhysicalStart + ResourceHob->ResourceLength) {
 | 
						|
         IsAvailable = FALSE;
 | 
						|
         break;
 | 
						|
       }
 | 
						|
     }
 | 
						|
  }
 | 
						|
 | 
						|
  return IsAvailable;
 | 
						|
 | 
						|
}
 | 
						|
/**
 | 
						|
  Hook function for Loading Module at Fixed Address feature
 | 
						|
 | 
						|
  This function should only be invoked when Loading Module at Fixed Address(LMFA) feature is enabled. When feature is
 | 
						|
  configured as Load Modules at Fix Absolute Address, this function is to validate the top address assigned by user. When
 | 
						|
  feature is configured as Load Modules at Fixed Offset, the function is to find the top address which is TOLM-TSEG in general.
 | 
						|
  And also the function will re-install PEI memory.
 | 
						|
 | 
						|
  @param PrivateData         Pointer to the private data passed in from caller
 | 
						|
 | 
						|
**/
 | 
						|
VOID
 | 
						|
PeiLoadFixAddressHook(
 | 
						|
  IN PEI_CORE_INSTANCE           *PrivateData
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_PHYSICAL_ADDRESS               TopLoadingAddress;
 | 
						|
  UINT64                             PeiMemorySize;
 | 
						|
  UINT64                             TotalReservedMemorySize;
 | 
						|
  UINT64                             MemoryRangeEnd;
 | 
						|
  EFI_PHYSICAL_ADDRESS               HighAddress;
 | 
						|
  EFI_HOB_RESOURCE_DESCRIPTOR        *ResourceHob;
 | 
						|
  EFI_HOB_RESOURCE_DESCRIPTOR        *NextResourceHob;
 | 
						|
  EFI_HOB_RESOURCE_DESCRIPTOR        *CurrentResourceHob;
 | 
						|
  EFI_PEI_HOB_POINTERS               CurrentHob;
 | 
						|
  EFI_PEI_HOB_POINTERS               Hob;
 | 
						|
  EFI_PEI_HOB_POINTERS               NextHob;
 | 
						|
  EFI_HOB_MEMORY_ALLOCATION          *MemoryHob;
 | 
						|
  //
 | 
						|
  // Initialize Local Variables
 | 
						|
  //
 | 
						|
  CurrentResourceHob    = NULL;
 | 
						|
  ResourceHob           = NULL;
 | 
						|
  NextResourceHob       = NULL;
 | 
						|
  HighAddress           = 0;
 | 
						|
  TopLoadingAddress     = 0;
 | 
						|
  MemoryRangeEnd      = 0;
 | 
						|
  CurrentHob.Raw      = PrivateData->HobList.Raw;
 | 
						|
  PeiMemorySize = PrivateData->PhysicalMemoryLength;
 | 
						|
  //
 | 
						|
  // The top reserved memory include 3 parts: the topest range is for DXE core initialization with the size  MINIMUM_INITIAL_MEMORY_SIZE
 | 
						|
  // then RuntimeCodePage range and Boot time code range.
 | 
						|
  //
 | 
						|
  TotalReservedMemorySize = MINIMUM_INITIAL_MEMORY_SIZE + EFI_PAGES_TO_SIZE(PcdGet32(PcdLoadFixAddressRuntimeCodePageNumber));
 | 
						|
  TotalReservedMemorySize+= EFI_PAGES_TO_SIZE(PcdGet32(PcdLoadFixAddressBootTimeCodePageNumber)) ;
 | 
						|
  //
 | 
						|
  // PEI memory range lies below the top reserved memory
 | 
						|
  //
 | 
						|
  TotalReservedMemorySize += PeiMemorySize;
 | 
						|
 | 
						|
  DEBUG ((EFI_D_INFO, "LOADING MODULE FIXED INFO: PcdLoadFixAddressRuntimeCodePageNumber= 0x%x.\n", PcdGet32(PcdLoadFixAddressRuntimeCodePageNumber)));
 | 
						|
  DEBUG ((EFI_D_INFO, "LOADING MODULE FIXED INFO: PcdLoadFixAddressBootTimeCodePageNumber= 0x%x.\n", PcdGet32(PcdLoadFixAddressBootTimeCodePageNumber)));
 | 
						|
  DEBUG ((EFI_D_INFO, "LOADING MODULE FIXED INFO: PcdLoadFixAddressPeiCodePageNumber= 0x%x.\n", PcdGet32(PcdLoadFixAddressPeiCodePageNumber)));
 | 
						|
  DEBUG ((EFI_D_INFO, "LOADING MODULE FIXED INFO: Total Reserved Memory Size = 0x%lx.\n", TotalReservedMemorySize));
 | 
						|
  //
 | 
						|
  // Loop through the system memory typed HOB to merge the adjacent memory range
 | 
						|
  //
 | 
						|
  for (Hob.Raw = PrivateData->HobList.Raw; !END_OF_HOB_LIST(Hob); Hob.Raw = GET_NEXT_HOB(Hob)) {
 | 
						|
    //
 | 
						|
    // See if this is a resource descriptor HOB
 | 
						|
    //
 | 
						|
    if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {
 | 
						|
 | 
						|
      ResourceHob = Hob.ResourceDescriptor;
 | 
						|
      //
 | 
						|
      // If range described in this HOB is not system memory or higher than MAX_ADDRESS, ignored.
 | 
						|
      //
 | 
						|
      if (ResourceHob->ResourceType != EFI_RESOURCE_SYSTEM_MEMORY ||
 | 
						|
          ResourceHob->PhysicalStart + ResourceHob->ResourceLength > MAX_ADDRESS)   {
 | 
						|
        continue;
 | 
						|
      }
 | 
						|
 | 
						|
      for (NextHob.Raw = PrivateData->HobList.Raw; !END_OF_HOB_LIST(NextHob); NextHob.Raw = GET_NEXT_HOB(NextHob)) {
 | 
						|
        if (NextHob.Raw == Hob.Raw){
 | 
						|
          continue;
 | 
						|
        }
 | 
						|
        //
 | 
						|
        // See if this is a resource descriptor HOB
 | 
						|
        //
 | 
						|
        if (GET_HOB_TYPE (NextHob) == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {
 | 
						|
 | 
						|
          NextResourceHob = NextHob.ResourceDescriptor;
 | 
						|
          //
 | 
						|
          // test if range described in this NextResourceHob is system memory and have the same attribute.
 | 
						|
          // Note: Here is a assumption that system memory should always be healthy even without test.
 | 
						|
          //
 | 
						|
          if (NextResourceHob->ResourceType == EFI_RESOURCE_SYSTEM_MEMORY &&
 | 
						|
             (((NextResourceHob->ResourceAttribute^ResourceHob->ResourceAttribute)&(~EFI_RESOURCE_ATTRIBUTE_TESTED)) == 0)){
 | 
						|
 | 
						|
              //
 | 
						|
              // See if the memory range described in ResourceHob and NextResourceHob is adjacent
 | 
						|
              //
 | 
						|
              if ((ResourceHob->PhysicalStart <= NextResourceHob->PhysicalStart &&
 | 
						|
                    ResourceHob->PhysicalStart + ResourceHob->ResourceLength >= NextResourceHob->PhysicalStart)||
 | 
						|
                  (ResourceHob->PhysicalStart >= NextResourceHob->PhysicalStart&&
 | 
						|
                     ResourceHob->PhysicalStart <= NextResourceHob->PhysicalStart + NextResourceHob->ResourceLength)) {
 | 
						|
 | 
						|
                MemoryRangeEnd = ((ResourceHob->PhysicalStart + ResourceHob->ResourceLength)>(NextResourceHob->PhysicalStart + NextResourceHob->ResourceLength)) ?
 | 
						|
                                     (ResourceHob->PhysicalStart + ResourceHob->ResourceLength):(NextResourceHob->PhysicalStart + NextResourceHob->ResourceLength);
 | 
						|
 | 
						|
                ResourceHob->PhysicalStart = (ResourceHob->PhysicalStart < NextResourceHob->PhysicalStart) ?
 | 
						|
                                                    ResourceHob->PhysicalStart : NextResourceHob->PhysicalStart;
 | 
						|
 | 
						|
 | 
						|
                ResourceHob->ResourceLength = (MemoryRangeEnd - ResourceHob->PhysicalStart);
 | 
						|
 | 
						|
                ResourceHob->ResourceAttribute = ResourceHob->ResourceAttribute & (~EFI_RESOURCE_ATTRIBUTE_TESTED);
 | 
						|
                //
 | 
						|
                // Delete the NextResourceHob by marking it as unused.
 | 
						|
                //
 | 
						|
                GET_HOB_TYPE (NextHob) = EFI_HOB_TYPE_UNUSED;
 | 
						|
 | 
						|
              }
 | 
						|
           }
 | 
						|
        }
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // Some platform is already allocated pages before the HOB re-org. Here to build dedicated resource HOB to describe
 | 
						|
  //  the allocated memory range
 | 
						|
  //
 | 
						|
  for (Hob.Raw = PrivateData->HobList.Raw; !END_OF_HOB_LIST(Hob); Hob.Raw = GET_NEXT_HOB(Hob)) {
 | 
						|
    //
 | 
						|
    // See if this is a memory allocation HOB
 | 
						|
    //
 | 
						|
    if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_MEMORY_ALLOCATION) {
 | 
						|
      MemoryHob = Hob.MemoryAllocation;
 | 
						|
      for (NextHob.Raw = PrivateData->HobList.Raw; !END_OF_HOB_LIST(NextHob); NextHob.Raw = GET_NEXT_HOB(NextHob)) {
 | 
						|
        //
 | 
						|
        // See if this is a resource descriptor HOB
 | 
						|
        //
 | 
						|
        if (GET_HOB_TYPE (NextHob) == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {
 | 
						|
          NextResourceHob = NextHob.ResourceDescriptor;
 | 
						|
          //
 | 
						|
          // If range described in this HOB is not system memory or higher than MAX_ADDRESS, ignored.
 | 
						|
          //
 | 
						|
          if (NextResourceHob->ResourceType != EFI_RESOURCE_SYSTEM_MEMORY || NextResourceHob->PhysicalStart + NextResourceHob->ResourceLength > MAX_ADDRESS) {
 | 
						|
            continue;
 | 
						|
          }
 | 
						|
          //
 | 
						|
          // If the range describe in memory allocation HOB belongs to the memory range described by the resource HOB
 | 
						|
          //
 | 
						|
          if (MemoryHob->AllocDescriptor.MemoryBaseAddress >= NextResourceHob->PhysicalStart &&
 | 
						|
              MemoryHob->AllocDescriptor.MemoryBaseAddress + MemoryHob->AllocDescriptor.MemoryLength <= NextResourceHob->PhysicalStart + NextResourceHob->ResourceLength) {
 | 
						|
             //
 | 
						|
             // Build separate resource HOB for this allocated range
 | 
						|
             //
 | 
						|
             if (MemoryHob->AllocDescriptor.MemoryBaseAddress > NextResourceHob->PhysicalStart) {
 | 
						|
               BuildResourceDescriptorHob (
 | 
						|
                 EFI_RESOURCE_SYSTEM_MEMORY,
 | 
						|
                 NextResourceHob->ResourceAttribute,
 | 
						|
                 NextResourceHob->PhysicalStart,
 | 
						|
                 (MemoryHob->AllocDescriptor.MemoryBaseAddress - NextResourceHob->PhysicalStart)
 | 
						|
               );
 | 
						|
             }
 | 
						|
             if (MemoryHob->AllocDescriptor.MemoryBaseAddress + MemoryHob->AllocDescriptor.MemoryLength < NextResourceHob->PhysicalStart + NextResourceHob->ResourceLength) {
 | 
						|
               BuildResourceDescriptorHob (
 | 
						|
                 EFI_RESOURCE_SYSTEM_MEMORY,
 | 
						|
                 NextResourceHob->ResourceAttribute,
 | 
						|
                 MemoryHob->AllocDescriptor.MemoryBaseAddress + MemoryHob->AllocDescriptor.MemoryLength,
 | 
						|
                 (NextResourceHob->PhysicalStart + NextResourceHob->ResourceLength -(MemoryHob->AllocDescriptor.MemoryBaseAddress + MemoryHob->AllocDescriptor.MemoryLength))
 | 
						|
               );
 | 
						|
             }
 | 
						|
             NextResourceHob->PhysicalStart = MemoryHob->AllocDescriptor.MemoryBaseAddress;
 | 
						|
             NextResourceHob->ResourceLength = MemoryHob->AllocDescriptor.MemoryLength;
 | 
						|
             break;
 | 
						|
          }
 | 
						|
        }
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Try to find and validate the TOP address.
 | 
						|
  //
 | 
						|
  if ((INT64)PcdGet64(PcdLoadModuleAtFixAddressEnable) > 0 ) {
 | 
						|
    //
 | 
						|
    // The LMFA feature is enabled as load module at fixed absolute address.
 | 
						|
    //
 | 
						|
    TopLoadingAddress = (EFI_PHYSICAL_ADDRESS)PcdGet64(PcdLoadModuleAtFixAddressEnable);
 | 
						|
    DEBUG ((EFI_D_INFO, "LOADING MODULE FIXED INFO: Loading module at fixed absolute address.\n"));
 | 
						|
    //
 | 
						|
    // validate the Address. Loop the resource descriptor HOB to make sure the address is in valid memory range
 | 
						|
    //
 | 
						|
    if ((TopLoadingAddress & EFI_PAGE_MASK) != 0) {
 | 
						|
      DEBUG ((EFI_D_INFO, "LOADING MODULE FIXED ERROR:Top Address 0x%lx is invalid since top address should be page align. \n", TopLoadingAddress));
 | 
						|
      ASSERT (FALSE);
 | 
						|
    }
 | 
						|
    //
 | 
						|
    // Search for a memory region that is below MAX_ADDRESS and in which TopLoadingAddress lies
 | 
						|
    //
 | 
						|
    for (Hob.Raw = PrivateData->HobList.Raw; !END_OF_HOB_LIST(Hob); Hob.Raw = GET_NEXT_HOB(Hob)) {
 | 
						|
      //
 | 
						|
      // See if this is a resource descriptor HOB
 | 
						|
      //
 | 
						|
      if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {
 | 
						|
 | 
						|
        ResourceHob = Hob.ResourceDescriptor;
 | 
						|
        //
 | 
						|
        // See if this resource descriptor HOB describes tested system memory below MAX_ADDRESS
 | 
						|
        //
 | 
						|
        if (ResourceHob->ResourceType == EFI_RESOURCE_SYSTEM_MEMORY &&
 | 
						|
            ResourceHob->PhysicalStart + ResourceHob->ResourceLength <= MAX_ADDRESS) {
 | 
						|
            //
 | 
						|
            // See if Top address specified by user is valid.
 | 
						|
            //
 | 
						|
            if (ResourceHob->PhysicalStart + TotalReservedMemorySize < TopLoadingAddress &&
 | 
						|
                (ResourceHob->PhysicalStart + ResourceHob->ResourceLength - MINIMUM_INITIAL_MEMORY_SIZE) >= TopLoadingAddress &&
 | 
						|
                PeiLoadFixAddressIsMemoryRangeAvailable(PrivateData, ResourceHob)) {
 | 
						|
              CurrentResourceHob = ResourceHob;
 | 
						|
              CurrentHob = Hob;
 | 
						|
              break;
 | 
						|
           }
 | 
						|
        }
 | 
						|
      }
 | 
						|
    }
 | 
						|
    if (CurrentResourceHob != NULL) {
 | 
						|
      DEBUG ((EFI_D_INFO, "LOADING MODULE FIXED INFO:Top Address 0x%lx is valid \n",  TopLoadingAddress));
 | 
						|
      TopLoadingAddress += MINIMUM_INITIAL_MEMORY_SIZE;
 | 
						|
    } else {
 | 
						|
      DEBUG ((EFI_D_INFO, "LOADING MODULE FIXED ERROR:Top Address 0x%lx is invalid \n",  TopLoadingAddress));
 | 
						|
      DEBUG ((EFI_D_INFO, "LOADING MODULE FIXED ERROR:The recommended Top Address for the platform is: \n"));
 | 
						|
      //
 | 
						|
      // Print the recommended Top address range.
 | 
						|
      //
 | 
						|
      for (Hob.Raw = PrivateData->HobList.Raw; !END_OF_HOB_LIST(Hob); Hob.Raw = GET_NEXT_HOB(Hob)) {
 | 
						|
        //
 | 
						|
        // See if this is a resource descriptor HOB
 | 
						|
        //
 | 
						|
        if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {
 | 
						|
 | 
						|
          ResourceHob = Hob.ResourceDescriptor;
 | 
						|
          //
 | 
						|
          // See if this resource descriptor HOB describes tested system memory below MAX_ADDRESS
 | 
						|
          //
 | 
						|
          if (ResourceHob->ResourceType == EFI_RESOURCE_SYSTEM_MEMORY &&
 | 
						|
              ResourceHob->PhysicalStart + ResourceHob->ResourceLength <= MAX_ADDRESS) {
 | 
						|
              //
 | 
						|
              // See if Top address specified by user is valid.
 | 
						|
              //
 | 
						|
              if (ResourceHob->ResourceLength > TotalReservedMemorySize && PeiLoadFixAddressIsMemoryRangeAvailable(PrivateData, ResourceHob)) {
 | 
						|
                 DEBUG ((EFI_D_INFO, "(0x%lx, 0x%lx)\n",
 | 
						|
                          (ResourceHob->PhysicalStart + TotalReservedMemorySize -MINIMUM_INITIAL_MEMORY_SIZE),
 | 
						|
                          (ResourceHob->PhysicalStart + ResourceHob->ResourceLength -MINIMUM_INITIAL_MEMORY_SIZE)
 | 
						|
                        ));
 | 
						|
              }
 | 
						|
          }
 | 
						|
        }
 | 
						|
      }
 | 
						|
      //
 | 
						|
      // Assert here
 | 
						|
      //
 | 
						|
      ASSERT (FALSE);
 | 
						|
      return;
 | 
						|
    }
 | 
						|
  } else {
 | 
						|
    //
 | 
						|
    // The LMFA feature is enabled as load module at fixed offset relative to TOLM
 | 
						|
    // Parse the Hob list to find the topest available memory. Generally it is (TOLM - TSEG)
 | 
						|
    //
 | 
						|
    //
 | 
						|
    // Search for a tested memory region that is below MAX_ADDRESS
 | 
						|
    //
 | 
						|
    for (Hob.Raw = PrivateData->HobList.Raw; !END_OF_HOB_LIST(Hob); Hob.Raw = GET_NEXT_HOB(Hob)) {
 | 
						|
      //
 | 
						|
      // See if this is a resource descriptor HOB
 | 
						|
      //
 | 
						|
      if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {
 | 
						|
 | 
						|
        ResourceHob = Hob.ResourceDescriptor;
 | 
						|
        //
 | 
						|
        // See if this resource descriptor HOB describes tested system memory below MAX_ADDRESS
 | 
						|
        //
 | 
						|
        if (ResourceHob->ResourceType == EFI_RESOURCE_SYSTEM_MEMORY &&
 | 
						|
            ResourceHob->PhysicalStart + ResourceHob->ResourceLength <= MAX_ADDRESS &&
 | 
						|
            ResourceHob->ResourceLength > TotalReservedMemorySize && PeiLoadFixAddressIsMemoryRangeAvailable(PrivateData, ResourceHob)) {
 | 
						|
          //
 | 
						|
          // See if this is the highest largest system memory region below MaxAddress
 | 
						|
          //
 | 
						|
          if (ResourceHob->PhysicalStart > HighAddress) {
 | 
						|
             CurrentResourceHob = ResourceHob;
 | 
						|
             CurrentHob = Hob;
 | 
						|
             HighAddress = CurrentResourceHob->PhysicalStart;
 | 
						|
          }
 | 
						|
        }
 | 
						|
      }
 | 
						|
    }
 | 
						|
    if (CurrentResourceHob == NULL) {
 | 
						|
      DEBUG ((EFI_D_INFO, "LOADING MODULE FIXED ERROR:The System Memory is too small\n"));
 | 
						|
      //
 | 
						|
      // Assert here
 | 
						|
      //
 | 
						|
      ASSERT (FALSE);
 | 
						|
      return;
 | 
						|
    } else {
 | 
						|
      TopLoadingAddress = CurrentResourceHob->PhysicalStart + CurrentResourceHob->ResourceLength ;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  if (CurrentResourceHob != NULL) {
 | 
						|
    //
 | 
						|
    // rebuild resource HOB for PEI memory and reserved memory
 | 
						|
    //
 | 
						|
    BuildResourceDescriptorHob (
 | 
						|
      EFI_RESOURCE_SYSTEM_MEMORY,
 | 
						|
      (
 | 
						|
      EFI_RESOURCE_ATTRIBUTE_PRESENT |
 | 
						|
      EFI_RESOURCE_ATTRIBUTE_INITIALIZED |
 | 
						|
      EFI_RESOURCE_ATTRIBUTE_TESTED |
 | 
						|
      EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE |
 | 
						|
      EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE |
 | 
						|
      EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE |
 | 
						|
      EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE
 | 
						|
      ),
 | 
						|
      (TopLoadingAddress - TotalReservedMemorySize),
 | 
						|
      TotalReservedMemorySize
 | 
						|
    );
 | 
						|
    //
 | 
						|
    // rebuild resource for the remain memory if necessary
 | 
						|
    //
 | 
						|
    if (CurrentResourceHob->PhysicalStart < TopLoadingAddress - TotalReservedMemorySize) {
 | 
						|
      BuildResourceDescriptorHob (
 | 
						|
        EFI_RESOURCE_SYSTEM_MEMORY,
 | 
						|
        (
 | 
						|
         EFI_RESOURCE_ATTRIBUTE_PRESENT |
 | 
						|
         EFI_RESOURCE_ATTRIBUTE_INITIALIZED |
 | 
						|
         EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE |
 | 
						|
         EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE |
 | 
						|
         EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE |
 | 
						|
         EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE
 | 
						|
         ),
 | 
						|
         CurrentResourceHob->PhysicalStart,
 | 
						|
         (TopLoadingAddress - TotalReservedMemorySize - CurrentResourceHob->PhysicalStart)
 | 
						|
       );
 | 
						|
    }
 | 
						|
    if (CurrentResourceHob->PhysicalStart + CurrentResourceHob->ResourceLength  > TopLoadingAddress ) {
 | 
						|
      BuildResourceDescriptorHob (
 | 
						|
        EFI_RESOURCE_SYSTEM_MEMORY,
 | 
						|
        (
 | 
						|
         EFI_RESOURCE_ATTRIBUTE_PRESENT |
 | 
						|
         EFI_RESOURCE_ATTRIBUTE_INITIALIZED |
 | 
						|
         EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE |
 | 
						|
         EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE |
 | 
						|
         EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE |
 | 
						|
         EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE
 | 
						|
         ),
 | 
						|
         TopLoadingAddress,
 | 
						|
         (CurrentResourceHob->PhysicalStart + CurrentResourceHob->ResourceLength  - TopLoadingAddress)
 | 
						|
       );
 | 
						|
    }
 | 
						|
    //
 | 
						|
    // Delete CurrentHob by marking it as unused since the memory range described by is rebuilt.
 | 
						|
    //
 | 
						|
    GET_HOB_TYPE (CurrentHob) = EFI_HOB_TYPE_UNUSED;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Cache the top address for Loading Module at Fixed Address feature
 | 
						|
  //
 | 
						|
  PrivateData->LoadModuleAtFixAddressTopAddress = TopLoadingAddress - MINIMUM_INITIAL_MEMORY_SIZE;
 | 
						|
  DEBUG ((EFI_D_INFO, "LOADING MODULE FIXED INFO: Top address = 0x%lx\n",  PrivateData->LoadModuleAtFixAddressTopAddress));
 | 
						|
  //
 | 
						|
  // reinstall the PEI memory relative to TopLoadingAddress
 | 
						|
  //
 | 
						|
  PrivateData->PhysicalMemoryBegin   = TopLoadingAddress - TotalReservedMemorySize;
 | 
						|
  PrivateData->FreePhysicalMemoryTop = PrivateData->PhysicalMemoryBegin + PeiMemorySize;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  This routine is invoked in switch stack as PeiCore Entry.
 | 
						|
 | 
						|
  @param SecCoreData     Points to a data structure containing information about the PEI core's operating
 | 
						|
                         environment, such as the size and location of temporary RAM, the stack location and
 | 
						|
                         the BFV location.
 | 
						|
  @param Private         Pointer to old core data that is used to initialize the
 | 
						|
                         core's data areas.
 | 
						|
**/
 | 
						|
VOID
 | 
						|
EFIAPI
 | 
						|
PeiCoreEntry (
 | 
						|
  IN CONST EFI_SEC_PEI_HAND_OFF    *SecCoreData,
 | 
						|
  IN PEI_CORE_INSTANCE             *Private
 | 
						|
  )
 | 
						|
{
 | 
						|
  //
 | 
						|
  // Entry PEI Phase 2
 | 
						|
  //
 | 
						|
  PeiCore (SecCoreData, NULL, Private);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Check SwitchStackSignal and switch stack if SwitchStackSignal is TRUE.
 | 
						|
 | 
						|
  @param[in] SecCoreData    Points to a data structure containing information about the PEI core's operating
 | 
						|
                            environment, such as the size and location of temporary RAM, the stack location and
 | 
						|
                            the BFV location.
 | 
						|
  @param[in] Private        Pointer to the private data passed in from caller.
 | 
						|
 | 
						|
**/
 | 
						|
VOID
 | 
						|
PeiCheckAndSwitchStack (
 | 
						|
  IN CONST EFI_SEC_PEI_HAND_OFF         *SecCoreData,
 | 
						|
  IN PEI_CORE_INSTANCE                  *Private
 | 
						|
  )
 | 
						|
{
 | 
						|
  VOID                                  *LoadFixPeiCodeBegin;
 | 
						|
  EFI_STATUS                            Status;
 | 
						|
  CONST EFI_PEI_SERVICES                **PeiServices;
 | 
						|
  UINT64                                NewStackSize;
 | 
						|
  EFI_PHYSICAL_ADDRESS                  TopOfOldStack;
 | 
						|
  EFI_PHYSICAL_ADDRESS                  TopOfNewStack;
 | 
						|
  UINTN                                 StackOffset;
 | 
						|
  BOOLEAN                               StackOffsetPositive;
 | 
						|
  EFI_PHYSICAL_ADDRESS                  TemporaryRamBase;
 | 
						|
  UINTN                                 TemporaryRamSize;
 | 
						|
  UINTN                                 TemporaryStackSize;
 | 
						|
  VOID                                  *TemporaryStackBase;
 | 
						|
  UINTN                                 PeiTemporaryRamSize;
 | 
						|
  VOID                                  *PeiTemporaryRamBase;
 | 
						|
  EFI_PEI_TEMPORARY_RAM_SUPPORT_PPI     *TemporaryRamSupportPpi;
 | 
						|
  EFI_PHYSICAL_ADDRESS                  BaseOfNewHeap;
 | 
						|
  EFI_PHYSICAL_ADDRESS                  HoleMemBase;
 | 
						|
  UINTN                                 HoleMemSize;
 | 
						|
  UINTN                                 HeapTemporaryRamSize;
 | 
						|
  EFI_PHYSICAL_ADDRESS                  TempBase1;
 | 
						|
  UINTN                                 TempSize1;
 | 
						|
  EFI_PHYSICAL_ADDRESS                  TempBase2;
 | 
						|
  UINTN                                 TempSize2;
 | 
						|
  UINTN                                 Index;
 | 
						|
 | 
						|
  PeiServices = (CONST EFI_PEI_SERVICES **) &Private->Ps;
 | 
						|
 | 
						|
  if (Private->SwitchStackSignal) {
 | 
						|
    //
 | 
						|
    // Before switch stack from temporary memory to permanent memory, calculate the heap and stack
 | 
						|
    // usage in temporary memory for debugging.
 | 
						|
    //
 | 
						|
    DEBUG_CODE_BEGIN ();
 | 
						|
      UINT32                *StackPointer;
 | 
						|
      EFI_PEI_HOB_POINTERS  Hob;
 | 
						|
 | 
						|
      for (StackPointer = (UINT32*)SecCoreData->StackBase;
 | 
						|
           (StackPointer < (UINT32*)((UINTN)SecCoreData->StackBase + SecCoreData->StackSize)) \
 | 
						|
           && (*StackPointer == PcdGet32 (PcdInitValueInTempStack));
 | 
						|
           StackPointer ++) {
 | 
						|
      }
 | 
						|
 | 
						|
      DEBUG ((DEBUG_INFO, "Temp Stack : BaseAddress=0x%p Length=0x%X\n", SecCoreData->StackBase, (UINT32)SecCoreData->StackSize));
 | 
						|
      DEBUG ((DEBUG_INFO, "Temp Heap  : BaseAddress=0x%p Length=0x%X\n", SecCoreData->PeiTemporaryRamBase, (UINT32)SecCoreData->PeiTemporaryRamSize));
 | 
						|
      DEBUG ((DEBUG_INFO, "Total temporary memory:    %d bytes.\n", (UINT32)SecCoreData->TemporaryRamSize));
 | 
						|
      DEBUG ((DEBUG_INFO, "  temporary memory stack ever used:       %d bytes.\n",
 | 
						|
             (UINT32)(SecCoreData->StackSize - ((UINTN) StackPointer - (UINTN)SecCoreData->StackBase))
 | 
						|
            ));
 | 
						|
      DEBUG ((DEBUG_INFO, "  temporary memory heap used for HobList: %d bytes.\n",
 | 
						|
             (UINT32)((UINTN)Private->HobList.HandoffInformationTable->EfiFreeMemoryBottom - (UINTN)Private->HobList.Raw)
 | 
						|
            ));
 | 
						|
      DEBUG ((DEBUG_INFO, "  temporary memory heap occupied by memory pages: %d bytes.\n",
 | 
						|
             (UINT32)(UINTN)(Private->HobList.HandoffInformationTable->EfiMemoryTop - Private->HobList.HandoffInformationTable->EfiFreeMemoryTop)
 | 
						|
            ));
 | 
						|
      for (Hob.Raw = Private->HobList.Raw; !END_OF_HOB_LIST(Hob); Hob.Raw = GET_NEXT_HOB(Hob)) {
 | 
						|
        if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_MEMORY_ALLOCATION) {
 | 
						|
          DEBUG ((DEBUG_INFO, "Memory Allocation 0x%08x 0x%0lx - 0x%0lx\n", \
 | 
						|
            Hob.MemoryAllocation->AllocDescriptor.MemoryType,               \
 | 
						|
            Hob.MemoryAllocation->AllocDescriptor.MemoryBaseAddress,        \
 | 
						|
            Hob.MemoryAllocation->AllocDescriptor.MemoryBaseAddress + Hob.MemoryAllocation->AllocDescriptor.MemoryLength - 1));
 | 
						|
        }
 | 
						|
      }
 | 
						|
    DEBUG_CODE_END ();
 | 
						|
 | 
						|
    if (PcdGet64(PcdLoadModuleAtFixAddressEnable) != 0 && (Private->HobList.HandoffInformationTable->BootMode != BOOT_ON_S3_RESUME)) {
 | 
						|
      //
 | 
						|
      // Loading Module at Fixed Address is enabled
 | 
						|
      //
 | 
						|
      PeiLoadFixAddressHook (Private);
 | 
						|
 | 
						|
      //
 | 
						|
      // If Loading Module at Fixed Address is enabled, Allocating memory range for Pei code range.
 | 
						|
      //
 | 
						|
      LoadFixPeiCodeBegin = AllocatePages((UINTN)PcdGet32(PcdLoadFixAddressPeiCodePageNumber));
 | 
						|
      DEBUG ((EFI_D_INFO, "LOADING MODULE FIXED INFO: PeiCodeBegin = 0x%lX, PeiCodeTop= 0x%lX\n", (UINT64)(UINTN)LoadFixPeiCodeBegin, (UINT64)((UINTN)LoadFixPeiCodeBegin + PcdGet32(PcdLoadFixAddressPeiCodePageNumber) * EFI_PAGE_SIZE)));
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    // Reserve the size of new stack at bottom of physical memory
 | 
						|
    //
 | 
						|
    // The size of new stack in permanent memory must be the same size
 | 
						|
    // or larger than the size of old stack in temporary memory.
 | 
						|
    // But if new stack is smaller than the size of old stack, we also reserve
 | 
						|
    // the size of old stack at bottom of permanent memory.
 | 
						|
    //
 | 
						|
    NewStackSize = RShiftU64 (Private->PhysicalMemoryLength, 1);
 | 
						|
    NewStackSize = ALIGN_VALUE (NewStackSize, EFI_PAGE_SIZE);
 | 
						|
    NewStackSize = MIN (PcdGet32(PcdPeiCoreMaxPeiStackSize), NewStackSize);
 | 
						|
    DEBUG ((EFI_D_INFO, "Old Stack size %d, New stack size %d\n", (UINT32)SecCoreData->StackSize, (UINT32)NewStackSize));
 | 
						|
    ASSERT (NewStackSize >= SecCoreData->StackSize);
 | 
						|
 | 
						|
    //
 | 
						|
    // Calculate stack offset and heap offset between temporary memory and new permanent
 | 
						|
    // memory separately.
 | 
						|
    //
 | 
						|
    TopOfOldStack = (UINTN)SecCoreData->StackBase + SecCoreData->StackSize;
 | 
						|
    TopOfNewStack = Private->PhysicalMemoryBegin + NewStackSize;
 | 
						|
    if (TopOfNewStack >= TopOfOldStack) {
 | 
						|
      StackOffsetPositive = TRUE;
 | 
						|
      StackOffset = (UINTN)(TopOfNewStack - TopOfOldStack);
 | 
						|
    } else {
 | 
						|
      StackOffsetPositive = FALSE;
 | 
						|
      StackOffset = (UINTN)(TopOfOldStack - TopOfNewStack);
 | 
						|
    }
 | 
						|
    Private->StackOffsetPositive = StackOffsetPositive;
 | 
						|
    Private->StackOffset = StackOffset;
 | 
						|
 | 
						|
    //
 | 
						|
    // Build Stack HOB that describes the permanent memory stack
 | 
						|
    //
 | 
						|
    DEBUG ((EFI_D_INFO, "Stack Hob: BaseAddress=0x%lX Length=0x%lX\n", TopOfNewStack - NewStackSize, NewStackSize));
 | 
						|
    BuildStackHob (TopOfNewStack - NewStackSize, NewStackSize);
 | 
						|
 | 
						|
    //
 | 
						|
    // Cache information from SecCoreData into locals before SecCoreData is converted to a permanent memory address
 | 
						|
    //
 | 
						|
    TemporaryRamBase    = (EFI_PHYSICAL_ADDRESS)(UINTN)SecCoreData->TemporaryRamBase;
 | 
						|
    TemporaryRamSize    = SecCoreData->TemporaryRamSize;
 | 
						|
    TemporaryStackSize  = SecCoreData->StackSize;
 | 
						|
    TemporaryStackBase  = SecCoreData->StackBase;
 | 
						|
    PeiTemporaryRamSize = SecCoreData->PeiTemporaryRamSize;
 | 
						|
    PeiTemporaryRamBase = SecCoreData->PeiTemporaryRamBase;
 | 
						|
 | 
						|
    //
 | 
						|
    // TemporaryRamSupportPpi is produced by platform's SEC
 | 
						|
    //
 | 
						|
    Status = PeiServicesLocatePpi (
 | 
						|
               &gEfiTemporaryRamSupportPpiGuid,
 | 
						|
               0,
 | 
						|
               NULL,
 | 
						|
               (VOID**)&TemporaryRamSupportPpi
 | 
						|
               );
 | 
						|
    if (!EFI_ERROR (Status)) {
 | 
						|
      //
 | 
						|
      // Heap Offset
 | 
						|
      //
 | 
						|
      BaseOfNewHeap = TopOfNewStack;
 | 
						|
      if (BaseOfNewHeap >= (UINTN)SecCoreData->PeiTemporaryRamBase) {
 | 
						|
        Private->HeapOffsetPositive = TRUE;
 | 
						|
        Private->HeapOffset = (UINTN)(BaseOfNewHeap - (UINTN)SecCoreData->PeiTemporaryRamBase);
 | 
						|
      } else {
 | 
						|
        Private->HeapOffsetPositive = FALSE;
 | 
						|
        Private->HeapOffset = (UINTN)((UINTN)SecCoreData->PeiTemporaryRamBase - BaseOfNewHeap);
 | 
						|
      }
 | 
						|
 | 
						|
      DEBUG ((EFI_D_INFO, "Heap Offset = 0x%lX Stack Offset = 0x%lX\n", (UINT64) Private->HeapOffset, (UINT64) Private->StackOffset));
 | 
						|
 | 
						|
      //
 | 
						|
      // Calculate new HandOffTable and PrivateData address in permanent memory's stack
 | 
						|
      //
 | 
						|
      if (StackOffsetPositive) {
 | 
						|
        SecCoreData = (CONST EFI_SEC_PEI_HAND_OFF *)((UINTN)(VOID *)SecCoreData + StackOffset);
 | 
						|
        Private = (PEI_CORE_INSTANCE *)((UINTN)(VOID *)Private + StackOffset);
 | 
						|
      } else {
 | 
						|
        SecCoreData = (CONST EFI_SEC_PEI_HAND_OFF *)((UINTN)(VOID *)SecCoreData - StackOffset);
 | 
						|
        Private = (PEI_CORE_INSTANCE *)((UINTN)(VOID *)Private - StackOffset);
 | 
						|
      }
 | 
						|
 | 
						|
      //
 | 
						|
      // Temporary Ram Support PPI is provided by platform, it will copy
 | 
						|
      // temporary memory to permanent memory and do stack switching.
 | 
						|
      // After invoking Temporary Ram Support PPI, the following code's
 | 
						|
      // stack is in permanent memory.
 | 
						|
      //
 | 
						|
      TemporaryRamSupportPpi->TemporaryRamMigration (
 | 
						|
                                PeiServices,
 | 
						|
                                TemporaryRamBase,
 | 
						|
                                (EFI_PHYSICAL_ADDRESS)(UINTN)(TopOfNewStack - TemporaryStackSize),
 | 
						|
                                TemporaryRamSize
 | 
						|
                                );
 | 
						|
 | 
						|
      //
 | 
						|
      // Migrate memory pages allocated in pre-memory phase.
 | 
						|
      // It could not be called before calling TemporaryRamSupportPpi->TemporaryRamMigration()
 | 
						|
      // as the migrated memory pages may be overridden by TemporaryRamSupportPpi->TemporaryRamMigration().
 | 
						|
      //
 | 
						|
      MigrateMemoryPages (Private, TRUE);
 | 
						|
 | 
						|
      //
 | 
						|
      // Entry PEI Phase 2
 | 
						|
      //
 | 
						|
      PeiCore (SecCoreData, NULL, Private);
 | 
						|
    } else {
 | 
						|
      //
 | 
						|
      // Migrate memory pages allocated in pre-memory phase.
 | 
						|
      //
 | 
						|
      MigrateMemoryPages (Private, FALSE);
 | 
						|
 | 
						|
      //
 | 
						|
      // Migrate the PEI Services Table pointer from temporary RAM to permanent RAM.
 | 
						|
      //
 | 
						|
      MigratePeiServicesTablePointer ();
 | 
						|
 | 
						|
      //
 | 
						|
      // Heap Offset
 | 
						|
      //
 | 
						|
      BaseOfNewHeap = TopOfNewStack;
 | 
						|
      HoleMemBase   = TopOfNewStack;
 | 
						|
      HoleMemSize   = TemporaryRamSize - PeiTemporaryRamSize - TemporaryStackSize;
 | 
						|
      if (HoleMemSize != 0) {
 | 
						|
        //
 | 
						|
        // Make sure HOB List start address is 8 byte alignment.
 | 
						|
        //
 | 
						|
        BaseOfNewHeap = ALIGN_VALUE (BaseOfNewHeap + HoleMemSize, 8);
 | 
						|
      }
 | 
						|
      if (BaseOfNewHeap >= (UINTN)SecCoreData->PeiTemporaryRamBase) {
 | 
						|
        Private->HeapOffsetPositive = TRUE;
 | 
						|
        Private->HeapOffset = (UINTN)(BaseOfNewHeap - (UINTN)SecCoreData->PeiTemporaryRamBase);
 | 
						|
      } else {
 | 
						|
        Private->HeapOffsetPositive = FALSE;
 | 
						|
        Private->HeapOffset = (UINTN)((UINTN)SecCoreData->PeiTemporaryRamBase - BaseOfNewHeap);
 | 
						|
      }
 | 
						|
 | 
						|
      DEBUG ((EFI_D_INFO, "Heap Offset = 0x%lX Stack Offset = 0x%lX\n", (UINT64) Private->HeapOffset, (UINT64) Private->StackOffset));
 | 
						|
 | 
						|
      //
 | 
						|
      // Migrate Heap
 | 
						|
      //
 | 
						|
      HeapTemporaryRamSize = (UINTN) (Private->HobList.HandoffInformationTable->EfiFreeMemoryBottom - Private->HobList.HandoffInformationTable->EfiMemoryBottom);
 | 
						|
      ASSERT (BaseOfNewHeap + HeapTemporaryRamSize <= Private->FreePhysicalMemoryTop);
 | 
						|
      CopyMem ((UINT8 *) (UINTN) BaseOfNewHeap, PeiTemporaryRamBase, HeapTemporaryRamSize);
 | 
						|
 | 
						|
      //
 | 
						|
      // Migrate Stack
 | 
						|
      //
 | 
						|
      CopyMem ((UINT8 *) (UINTN) (TopOfNewStack - TemporaryStackSize), TemporaryStackBase, TemporaryStackSize);
 | 
						|
 | 
						|
      //
 | 
						|
      // Copy Hole Range Data
 | 
						|
      //
 | 
						|
      if (HoleMemSize != 0) {
 | 
						|
        //
 | 
						|
        // Prepare Hole
 | 
						|
        //
 | 
						|
        if (PeiTemporaryRamBase < TemporaryStackBase) {
 | 
						|
          TempBase1 = (EFI_PHYSICAL_ADDRESS) (UINTN) PeiTemporaryRamBase;
 | 
						|
          TempSize1 = PeiTemporaryRamSize;
 | 
						|
          TempBase2 = (EFI_PHYSICAL_ADDRESS) (UINTN) TemporaryStackBase;
 | 
						|
          TempSize2 = TemporaryStackSize;
 | 
						|
        } else {
 | 
						|
          TempBase1 = (EFI_PHYSICAL_ADDRESS) (UINTN) TemporaryStackBase;
 | 
						|
          TempSize1 = TemporaryStackSize;
 | 
						|
          TempBase2 =(EFI_PHYSICAL_ADDRESS) (UINTN) PeiTemporaryRamBase;
 | 
						|
          TempSize2 = PeiTemporaryRamSize;
 | 
						|
        }
 | 
						|
        if (TemporaryRamBase < TempBase1) {
 | 
						|
          Private->HoleData[0].Base = TemporaryRamBase;
 | 
						|
          Private->HoleData[0].Size = (UINTN) (TempBase1 - TemporaryRamBase);
 | 
						|
        }
 | 
						|
        if (TempBase1 + TempSize1 < TempBase2) {
 | 
						|
          Private->HoleData[1].Base = TempBase1 + TempSize1;
 | 
						|
          Private->HoleData[1].Size = (UINTN) (TempBase2 - TempBase1 - TempSize1);
 | 
						|
        }
 | 
						|
        if (TempBase2 + TempSize2 < TemporaryRamBase + TemporaryRamSize) {
 | 
						|
          Private->HoleData[2].Base = TempBase2 + TempSize2;
 | 
						|
          Private->HoleData[2].Size = (UINTN) (TemporaryRamBase + TemporaryRamSize - TempBase2 - TempSize2);
 | 
						|
        }
 | 
						|
 | 
						|
        //
 | 
						|
        // Copy Hole Range data.
 | 
						|
        //
 | 
						|
        for (Index = 0; Index < HOLE_MAX_NUMBER; Index ++) {
 | 
						|
          if (Private->HoleData[Index].Size > 0) {
 | 
						|
            if (HoleMemBase > Private->HoleData[Index].Base) {
 | 
						|
              Private->HoleData[Index].OffsetPositive = TRUE;
 | 
						|
              Private->HoleData[Index].Offset = (UINTN) (HoleMemBase - Private->HoleData[Index].Base);
 | 
						|
            } else {
 | 
						|
              Private->HoleData[Index].OffsetPositive = FALSE;
 | 
						|
              Private->HoleData[Index].Offset = (UINTN) (Private->HoleData[Index].Base - HoleMemBase);
 | 
						|
            }
 | 
						|
            CopyMem ((VOID *) (UINTN) HoleMemBase, (VOID *) (UINTN) Private->HoleData[Index].Base, Private->HoleData[Index].Size);
 | 
						|
            HoleMemBase = HoleMemBase + Private->HoleData[Index].Size;
 | 
						|
          }
 | 
						|
        }
 | 
						|
      }
 | 
						|
 | 
						|
      //
 | 
						|
      // Switch new stack
 | 
						|
      //
 | 
						|
      SwitchStack (
 | 
						|
        (SWITCH_STACK_ENTRY_POINT)(UINTN)PeiCoreEntry,
 | 
						|
        (VOID *) SecCoreData,
 | 
						|
        (VOID *) Private,
 | 
						|
        (VOID *) (UINTN) TopOfNewStack
 | 
						|
        );
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    // Code should not come here
 | 
						|
    //
 | 
						|
    ASSERT (FALSE);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Migrate a PEIM from temporary RAM to permanent memory.
 | 
						|
 | 
						|
  @param PeimFileHandle       Pointer to the FFS file header of the image.
 | 
						|
  @param MigratedFileHandle   Pointer to the FFS file header of the migrated image.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS         Sucessfully migrated the PEIM to permanent memory.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
MigratePeim (
 | 
						|
  IN  EFI_PEI_FILE_HANDLE     FileHandle,
 | 
						|
  IN  EFI_PEI_FILE_HANDLE     MigratedFileHandle
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS                Status;
 | 
						|
  EFI_FFS_FILE_HEADER       *FileHeader;
 | 
						|
  VOID                      *Pe32Data;
 | 
						|
  VOID                      *ImageAddress;
 | 
						|
  CHAR8                     *AsciiString;
 | 
						|
  UINTN                     Index;
 | 
						|
 | 
						|
  Status = EFI_SUCCESS;
 | 
						|
 | 
						|
  FileHeader = (EFI_FFS_FILE_HEADER *) FileHandle;
 | 
						|
  ASSERT (!IS_FFS_FILE2 (FileHeader));
 | 
						|
 | 
						|
  ImageAddress = NULL;
 | 
						|
  PeiGetPe32Data (MigratedFileHandle, &ImageAddress);
 | 
						|
  if (ImageAddress != NULL) {
 | 
						|
    DEBUG_CODE_BEGIN ();
 | 
						|
    AsciiString = PeCoffLoaderGetPdbPointer (ImageAddress);
 | 
						|
    for (Index = 0; AsciiString[Index] != 0; Index++) {
 | 
						|
      if (AsciiString[Index] == '\\' || AsciiString[Index] == '/') {
 | 
						|
        AsciiString = AsciiString + Index + 1;
 | 
						|
        Index = 0;
 | 
						|
      } else if (AsciiString[Index] == '.') {
 | 
						|
        AsciiString[Index] = 0;
 | 
						|
      }
 | 
						|
    }
 | 
						|
    DEBUG ((DEBUG_INFO, "%a", AsciiString));
 | 
						|
    DEBUG_CODE_END ();
 | 
						|
 | 
						|
    Pe32Data = (VOID *) ((UINTN) ImageAddress - (UINTN) MigratedFileHandle + (UINTN) FileHandle);
 | 
						|
    Status = LoadAndRelocatePeCoffImageInPlace (Pe32Data, ImageAddress);
 | 
						|
    ASSERT_EFI_ERROR (Status);
 | 
						|
  }
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Migrate Status Code Callback function pointers inside an FV from temporary memory to permanent memory.
 | 
						|
 | 
						|
  @param OrgFvHandle      Address of FV handle in temporary memory.
 | 
						|
  @param FvHandle         Address of FV handle in permanent memory.
 | 
						|
  @param FvSize           Size of the FV.
 | 
						|
 | 
						|
**/
 | 
						|
VOID
 | 
						|
ConvertStatusCodeCallbacks (
 | 
						|
  IN  UINTN                   OrgFvHandle,
 | 
						|
  IN  UINTN                   FvHandle,
 | 
						|
  IN  UINTN                   FvSize
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_PEI_HOB_POINTERS    Hob;
 | 
						|
  UINTN                   *NumberOfEntries;
 | 
						|
  UINTN                   *CallbackEntry;
 | 
						|
  UINTN                   Index;
 | 
						|
 | 
						|
  Hob.Raw  = GetFirstGuidHob (&gStatusCodeCallbackGuid);
 | 
						|
  while (Hob.Raw != NULL) {
 | 
						|
    NumberOfEntries = GET_GUID_HOB_DATA (Hob);
 | 
						|
    CallbackEntry   = NumberOfEntries + 1;
 | 
						|
    for (Index = 0; Index < *NumberOfEntries; Index++) {
 | 
						|
      if (((VOID *) CallbackEntry[Index]) != NULL) {
 | 
						|
        if ((CallbackEntry[Index] >= OrgFvHandle) && (CallbackEntry[Index] < (OrgFvHandle + FvSize))) {
 | 
						|
          DEBUG ((
 | 
						|
            DEBUG_INFO,
 | 
						|
            "Migrating CallbackEntry[%Lu] from 0x%0*Lx to ",
 | 
						|
            (UINT64)Index,
 | 
						|
            (sizeof CallbackEntry[Index]) * 2,
 | 
						|
            (UINT64)CallbackEntry[Index]
 | 
						|
            ));
 | 
						|
          if (OrgFvHandle > FvHandle) {
 | 
						|
            CallbackEntry[Index] = CallbackEntry[Index] - (OrgFvHandle - FvHandle);
 | 
						|
          } else {
 | 
						|
            CallbackEntry[Index] = CallbackEntry[Index] + (FvHandle - OrgFvHandle);
 | 
						|
          }
 | 
						|
          DEBUG ((
 | 
						|
            DEBUG_INFO,
 | 
						|
            "0x%0*Lx\n",
 | 
						|
            (sizeof CallbackEntry[Index]) * 2,
 | 
						|
            (UINT64)CallbackEntry[Index]
 | 
						|
            ));
 | 
						|
        }
 | 
						|
      }
 | 
						|
    }
 | 
						|
    Hob.Raw = GET_NEXT_HOB (Hob);
 | 
						|
    Hob.Raw = GetNextGuidHob (&gStatusCodeCallbackGuid, Hob.Raw);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Migrates SEC modules in the given firmware volume.
 | 
						|
 | 
						|
  Migrating SECURITY_CORE files requires special treatment since they are not tracked for PEI dispatch.
 | 
						|
 | 
						|
  This functioun should be called after the FV has been copied to its post-memory location and the PEI Core FV list has
 | 
						|
  been updated.
 | 
						|
 | 
						|
  @param Private          Pointer to the PeiCore's private data structure.
 | 
						|
  @param FvIndex          The firmware volume index to migrate.
 | 
						|
  @param OrgFvHandle      The handle to the firmware volume in temporary memory.
 | 
						|
 | 
						|
  @retval   EFI_SUCCESS           SEC modules were migrated successfully
 | 
						|
  @retval   EFI_INVALID_PARAMETER The Private pointer is NULL or FvCount is invalid.
 | 
						|
  @retval   EFI_NOT_FOUND         Can't find valid FFS header.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
MigrateSecModulesInFv (
 | 
						|
  IN PEI_CORE_INSTANCE    *Private,
 | 
						|
  IN  UINTN               FvIndex,
 | 
						|
  IN  UINTN               OrgFvHandle
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS                  Status;
 | 
						|
  EFI_STATUS                  FindFileStatus;
 | 
						|
  EFI_PEI_FILE_HANDLE         MigratedFileHandle;
 | 
						|
  EFI_PEI_FILE_HANDLE         FileHandle;
 | 
						|
  UINT32                      SectionAuthenticationStatus;
 | 
						|
  UINT32                      FileSize;
 | 
						|
  VOID                        *OrgPe32SectionData;
 | 
						|
  VOID                        *Pe32SectionData;
 | 
						|
  EFI_FFS_FILE_HEADER         *FfsFileHeader;
 | 
						|
  EFI_COMMON_SECTION_HEADER   *Section;
 | 
						|
  BOOLEAN                     IsFfs3Fv;
 | 
						|
  UINTN                       SectionInstance;
 | 
						|
 | 
						|
  if (Private == NULL || FvIndex >= Private->FvCount) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  do {
 | 
						|
    FindFileStatus =  PeiFfsFindNextFile (
 | 
						|
                        GetPeiServicesTablePointer (),
 | 
						|
                        EFI_FV_FILETYPE_SECURITY_CORE,
 | 
						|
                        Private->Fv[FvIndex].FvHandle,
 | 
						|
                        &MigratedFileHandle
 | 
						|
                        );
 | 
						|
    if (!EFI_ERROR (FindFileStatus ) && MigratedFileHandle != NULL) {
 | 
						|
      FileHandle = (EFI_PEI_FILE_HANDLE) ((UINTN) MigratedFileHandle - (UINTN) Private->Fv[FvIndex].FvHandle + OrgFvHandle);
 | 
						|
      FfsFileHeader = (EFI_FFS_FILE_HEADER *) MigratedFileHandle;
 | 
						|
 | 
						|
      DEBUG ((DEBUG_VERBOSE, "    Migrating SEC_CORE MigratedFileHandle at 0x%x.\n", (UINTN) MigratedFileHandle));
 | 
						|
      DEBUG ((DEBUG_VERBOSE, "                       FileHandle at 0x%x.\n", (UINTN) FileHandle));
 | 
						|
 | 
						|
      IsFfs3Fv = CompareGuid (&Private->Fv[FvIndex].FvHeader->FileSystemGuid, &gEfiFirmwareFileSystem3Guid);
 | 
						|
      if (IS_FFS_FILE2 (FfsFileHeader)) {
 | 
						|
        ASSERT (FFS_FILE2_SIZE (FfsFileHeader) > 0x00FFFFFF);
 | 
						|
        if (!IsFfs3Fv) {
 | 
						|
          DEBUG ((DEBUG_ERROR, "It is a FFS3 formatted file: %g in a non-FFS3 formatted FV.\n", &FfsFileHeader->Name));
 | 
						|
          return EFI_NOT_FOUND;
 | 
						|
        }
 | 
						|
        Section = (EFI_COMMON_SECTION_HEADER *) ((UINT8 *) FfsFileHeader + sizeof (EFI_FFS_FILE_HEADER2));
 | 
						|
        FileSize = FFS_FILE2_SIZE (FfsFileHeader) - sizeof (EFI_FFS_FILE_HEADER2);
 | 
						|
      } else {
 | 
						|
        Section = (EFI_COMMON_SECTION_HEADER *) ((UINT8 *) FfsFileHeader + sizeof (EFI_FFS_FILE_HEADER));
 | 
						|
        FileSize = FFS_FILE_SIZE (FfsFileHeader) - sizeof (EFI_FFS_FILE_HEADER);
 | 
						|
      }
 | 
						|
 | 
						|
      SectionInstance = 1;
 | 
						|
      SectionAuthenticationStatus = 0;
 | 
						|
      Status = ProcessSection (
 | 
						|
                GetPeiServicesTablePointer (),
 | 
						|
                EFI_SECTION_PE32,
 | 
						|
                &SectionInstance,
 | 
						|
                Section,
 | 
						|
                FileSize,
 | 
						|
                &Pe32SectionData,
 | 
						|
                &SectionAuthenticationStatus,
 | 
						|
                IsFfs3Fv
 | 
						|
                );
 | 
						|
 | 
						|
      if (!EFI_ERROR (Status)) {
 | 
						|
        OrgPe32SectionData = (VOID *) ((UINTN) Pe32SectionData - (UINTN) MigratedFileHandle + (UINTN) FileHandle);
 | 
						|
        DEBUG ((DEBUG_VERBOSE, "      PE32 section in migrated file at 0x%x.\n", (UINTN) Pe32SectionData));
 | 
						|
        DEBUG ((DEBUG_VERBOSE, "      PE32 section in original file at 0x%x.\n", (UINTN) OrgPe32SectionData));
 | 
						|
        Status = LoadAndRelocatePeCoffImageInPlace (OrgPe32SectionData, Pe32SectionData);
 | 
						|
        ASSERT_EFI_ERROR (Status);
 | 
						|
      }
 | 
						|
    }
 | 
						|
  } while (!EFI_ERROR (FindFileStatus));
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Migrates PEIMs in the given firmware volume.
 | 
						|
 | 
						|
  @param Private          Pointer to the PeiCore's private data structure.
 | 
						|
  @param FvIndex          The firmware volume index to migrate.
 | 
						|
  @param OrgFvHandle      The handle to the firmware volume in temporary memory.
 | 
						|
  @param FvHandle         The handle to the firmware volume in permanent memory.
 | 
						|
 | 
						|
  @retval   EFI_SUCCESS           The PEIMs in the FV were migrated successfully
 | 
						|
  @retval   EFI_INVALID_PARAMETER The Private pointer is NULL or FvCount is invalid.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
MigratePeimsInFv (
 | 
						|
  IN PEI_CORE_INSTANCE    *Private,
 | 
						|
  IN  UINTN               FvIndex,
 | 
						|
  IN  UINTN               OrgFvHandle,
 | 
						|
  IN  UINTN               FvHandle
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS              Status;
 | 
						|
  volatile UINTN          FileIndex;
 | 
						|
  EFI_PEI_FILE_HANDLE     MigratedFileHandle;
 | 
						|
  EFI_PEI_FILE_HANDLE     FileHandle;
 | 
						|
 | 
						|
  if (Private == NULL || FvIndex >= Private->FvCount) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  if (Private->Fv[FvIndex].ScanFv) {
 | 
						|
    for (FileIndex = 0; FileIndex < Private->Fv[FvIndex].PeimCount; FileIndex++) {
 | 
						|
      if (Private->Fv[FvIndex].FvFileHandles[FileIndex] != NULL) {
 | 
						|
        FileHandle = Private->Fv[FvIndex].FvFileHandles[FileIndex];
 | 
						|
 | 
						|
        MigratedFileHandle = (EFI_PEI_FILE_HANDLE) ((UINTN) FileHandle - OrgFvHandle + FvHandle);
 | 
						|
 | 
						|
        DEBUG ((DEBUG_VERBOSE, "    Migrating FileHandle %2d ", FileIndex));
 | 
						|
        Status = MigratePeim (FileHandle, MigratedFileHandle);
 | 
						|
        DEBUG ((DEBUG_VERBOSE, "\n"));
 | 
						|
        ASSERT_EFI_ERROR (Status);
 | 
						|
 | 
						|
        if (!EFI_ERROR (Status)) {
 | 
						|
          Private->Fv[FvIndex].FvFileHandles[FileIndex] = MigratedFileHandle;
 | 
						|
          if (FvIndex == Private->CurrentPeimFvCount) {
 | 
						|
            Private->CurrentFvFileHandles[FileIndex] = MigratedFileHandle;
 | 
						|
          }
 | 
						|
        }
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Migrate FVs out of temporary RAM before the cache is flushed.
 | 
						|
 | 
						|
  @param Private         PeiCore's private data structure
 | 
						|
  @param SecCoreData     Points to a data structure containing information about the PEI core's operating
 | 
						|
                         environment, such as the size and location of temporary RAM, the stack location and
 | 
						|
                         the BFV location.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS           Succesfully migrated installed FVs from temporary RAM to permanent memory.
 | 
						|
  @retval EFI_OUT_OF_RESOURCES  Insufficient memory exists to allocate needed pages.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
EvacuateTempRam (
 | 
						|
  IN PEI_CORE_INSTANCE            *Private,
 | 
						|
  IN CONST EFI_SEC_PEI_HAND_OFF   *SecCoreData
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS                    Status;
 | 
						|
  volatile UINTN                FvIndex;
 | 
						|
  volatile UINTN                FvChildIndex;
 | 
						|
  UINTN                         ChildFvOffset;
 | 
						|
  EFI_FIRMWARE_VOLUME_HEADER    *FvHeader;
 | 
						|
  EFI_FIRMWARE_VOLUME_HEADER    *ChildFvHeader;
 | 
						|
  EFI_FIRMWARE_VOLUME_HEADER    *MigratedFvHeader;
 | 
						|
  EFI_FIRMWARE_VOLUME_HEADER    *RawDataFvHeader;
 | 
						|
  EFI_FIRMWARE_VOLUME_HEADER    *MigratedChildFvHeader;
 | 
						|
 | 
						|
  PEI_CORE_FV_HANDLE            PeiCoreFvHandle;
 | 
						|
  EFI_PEI_CORE_FV_LOCATION_PPI  *PeiCoreFvLocationPpi;
 | 
						|
  EDKII_MIGRATED_FV_INFO        MigratedFvInfo;
 | 
						|
 | 
						|
  ASSERT (Private->PeiMemoryInstalled);
 | 
						|
 | 
						|
  DEBUG ((DEBUG_VERBOSE, "Beginning evacuation of content in temporary RAM.\n"));
 | 
						|
 | 
						|
  //
 | 
						|
  // Migrate PPI Pointers of PEI_CORE from temporary memory to newly loaded PEI_CORE in permanent memory.
 | 
						|
  //
 | 
						|
  Status = PeiLocatePpi ((CONST EFI_PEI_SERVICES **) &Private->Ps, &gEfiPeiCoreFvLocationPpiGuid, 0, NULL, (VOID **) &PeiCoreFvLocationPpi);
 | 
						|
  if (!EFI_ERROR (Status) && (PeiCoreFvLocationPpi->PeiCoreFvLocation != NULL)) {
 | 
						|
    PeiCoreFvHandle.FvHandle = (EFI_PEI_FV_HANDLE) PeiCoreFvLocationPpi->PeiCoreFvLocation;
 | 
						|
  } else {
 | 
						|
    PeiCoreFvHandle.FvHandle = (EFI_PEI_FV_HANDLE) SecCoreData->BootFirmwareVolumeBase;
 | 
						|
  }
 | 
						|
  for (FvIndex = 0; FvIndex < Private->FvCount; FvIndex++) {
 | 
						|
    if (Private->Fv[FvIndex].FvHandle == PeiCoreFvHandle.FvHandle) {
 | 
						|
      CopyMem (&PeiCoreFvHandle, &Private->Fv[FvIndex], sizeof (PEI_CORE_FV_HANDLE));
 | 
						|
      break;
 | 
						|
    }
 | 
						|
  }
 | 
						|
  Status = EFI_SUCCESS;
 | 
						|
 | 
						|
  ConvertPeiCorePpiPointers (Private, &PeiCoreFvHandle);
 | 
						|
 | 
						|
  for (FvIndex = 0; FvIndex < Private->FvCount; FvIndex++) {
 | 
						|
    FvHeader = Private->Fv[FvIndex].FvHeader;
 | 
						|
    ASSERT (FvHeader != NULL);
 | 
						|
    ASSERT (FvIndex < Private->FvCount);
 | 
						|
 | 
						|
    DEBUG ((DEBUG_VERBOSE, "FV[%02d] at 0x%x.\n", FvIndex, (UINTN) FvHeader));
 | 
						|
    if (
 | 
						|
      !(
 | 
						|
        ((EFI_PHYSICAL_ADDRESS)(UINTN) FvHeader >= Private->PhysicalMemoryBegin) &&
 | 
						|
        (((EFI_PHYSICAL_ADDRESS)(UINTN) FvHeader + (FvHeader->FvLength - 1)) < Private->FreePhysicalMemoryTop)
 | 
						|
        )
 | 
						|
      ) {
 | 
						|
      //
 | 
						|
      // Allocate page to save the rebased PEIMs, the PEIMs will get dispatched later.
 | 
						|
      //
 | 
						|
      Status =  PeiServicesAllocatePages (
 | 
						|
                  EfiBootServicesCode,
 | 
						|
                  EFI_SIZE_TO_PAGES ((UINTN) FvHeader->FvLength),
 | 
						|
                  (EFI_PHYSICAL_ADDRESS *) &MigratedFvHeader
 | 
						|
                  );
 | 
						|
      ASSERT_EFI_ERROR (Status);
 | 
						|
 | 
						|
      //
 | 
						|
      // Allocate pool to save the raw PEIMs, which is used to keep consistent context across
 | 
						|
      // multiple boot and PCR0 will keep the same no matter if the address of allocated page is changed.
 | 
						|
      //
 | 
						|
      Status =  PeiServicesAllocatePages (
 | 
						|
                  EfiBootServicesCode,
 | 
						|
                  EFI_SIZE_TO_PAGES ((UINTN) FvHeader->FvLength),
 | 
						|
                  (EFI_PHYSICAL_ADDRESS *) &RawDataFvHeader
 | 
						|
                  );
 | 
						|
      ASSERT_EFI_ERROR (Status);
 | 
						|
 | 
						|
      DEBUG ((
 | 
						|
        DEBUG_VERBOSE,
 | 
						|
        "  Migrating FV[%d] from 0x%08X to 0x%08X\n",
 | 
						|
        FvIndex,
 | 
						|
        (UINTN) FvHeader,
 | 
						|
        (UINTN) MigratedFvHeader
 | 
						|
        ));
 | 
						|
 | 
						|
      //
 | 
						|
      // Copy the context to the rebased pages and raw pages, and create hob to save the
 | 
						|
      // information. The MigratedFvInfo HOB will never be produced when
 | 
						|
      // PcdMigrateTemporaryRamFirmwareVolumes is FALSE, because the PCD control the
 | 
						|
      // feature.
 | 
						|
      //
 | 
						|
      CopyMem (MigratedFvHeader, FvHeader, (UINTN) FvHeader->FvLength);
 | 
						|
      CopyMem (RawDataFvHeader, MigratedFvHeader, (UINTN) FvHeader->FvLength);
 | 
						|
      MigratedFvInfo.FvOrgBase  = (UINT32) (UINTN) FvHeader;
 | 
						|
      MigratedFvInfo.FvNewBase  = (UINT32) (UINTN) MigratedFvHeader;
 | 
						|
      MigratedFvInfo.FvDataBase = (UINT32) (UINTN) RawDataFvHeader;
 | 
						|
      MigratedFvInfo.FvLength   = (UINT32) (UINTN) FvHeader->FvLength;
 | 
						|
      BuildGuidDataHob (&gEdkiiMigratedFvInfoGuid, &MigratedFvInfo, sizeof (MigratedFvInfo));
 | 
						|
 | 
						|
      //
 | 
						|
      // Migrate any children for this FV now
 | 
						|
      //
 | 
						|
      for (FvChildIndex = FvIndex; FvChildIndex < Private->FvCount; FvChildIndex++) {
 | 
						|
        ChildFvHeader = Private->Fv[FvChildIndex].FvHeader;
 | 
						|
        if (
 | 
						|
          ((UINTN) ChildFvHeader > (UINTN) FvHeader) &&
 | 
						|
          (((UINTN) ChildFvHeader + ChildFvHeader->FvLength) < ((UINTN) FvHeader) + FvHeader->FvLength)
 | 
						|
          ) {
 | 
						|
          DEBUG ((DEBUG_VERBOSE, "    Child FV[%02d] is being migrated.\n", FvChildIndex));
 | 
						|
          ChildFvOffset = (UINTN) ChildFvHeader - (UINTN) FvHeader;
 | 
						|
          DEBUG ((DEBUG_VERBOSE, "    Child FV offset = 0x%x.\n", ChildFvOffset));
 | 
						|
          MigratedChildFvHeader = (EFI_FIRMWARE_VOLUME_HEADER *) ((UINTN) MigratedFvHeader + ChildFvOffset);
 | 
						|
          Private->Fv[FvChildIndex].FvHeader = MigratedChildFvHeader;
 | 
						|
          Private->Fv[FvChildIndex].FvHandle = (EFI_PEI_FV_HANDLE) MigratedChildFvHeader;
 | 
						|
          DEBUG ((DEBUG_VERBOSE, "    Child migrated FV header at 0x%x.\n", (UINTN) MigratedChildFvHeader));
 | 
						|
 | 
						|
          Status =  MigratePeimsInFv (Private, FvChildIndex, (UINTN) ChildFvHeader, (UINTN) MigratedChildFvHeader);
 | 
						|
          ASSERT_EFI_ERROR (Status);
 | 
						|
 | 
						|
          ConvertPpiPointersFv (
 | 
						|
            Private,
 | 
						|
            (UINTN) ChildFvHeader,
 | 
						|
            (UINTN) MigratedChildFvHeader,
 | 
						|
            (UINTN) ChildFvHeader->FvLength - 1
 | 
						|
            );
 | 
						|
 | 
						|
          ConvertStatusCodeCallbacks (
 | 
						|
            (UINTN) ChildFvHeader,
 | 
						|
            (UINTN) MigratedChildFvHeader,
 | 
						|
            (UINTN) ChildFvHeader->FvLength - 1
 | 
						|
            );
 | 
						|
 | 
						|
          ConvertFvHob (Private, (UINTN) ChildFvHeader, (UINTN) MigratedChildFvHeader);
 | 
						|
        }
 | 
						|
      }
 | 
						|
      Private->Fv[FvIndex].FvHeader = MigratedFvHeader;
 | 
						|
      Private->Fv[FvIndex].FvHandle = (EFI_PEI_FV_HANDLE) MigratedFvHeader;
 | 
						|
 | 
						|
      Status = MigratePeimsInFv (Private, FvIndex, (UINTN) FvHeader, (UINTN) MigratedFvHeader);
 | 
						|
      ASSERT_EFI_ERROR (Status);
 | 
						|
 | 
						|
      ConvertPpiPointersFv (
 | 
						|
        Private,
 | 
						|
        (UINTN) FvHeader,
 | 
						|
        (UINTN) MigratedFvHeader,
 | 
						|
        (UINTN) FvHeader->FvLength - 1
 | 
						|
        );
 | 
						|
 | 
						|
      ConvertStatusCodeCallbacks (
 | 
						|
        (UINTN) FvHeader,
 | 
						|
        (UINTN) MigratedFvHeader,
 | 
						|
        (UINTN) FvHeader->FvLength - 1
 | 
						|
        );
 | 
						|
 | 
						|
      ConvertFvHob (Private, (UINTN) FvHeader, (UINTN) MigratedFvHeader);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  RemoveFvHobsInTemporaryMemory (Private);
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Conduct PEIM dispatch.
 | 
						|
 | 
						|
  @param SecCoreData     Points to a data structure containing information about the PEI core's operating
 | 
						|
                         environment, such as the size and location of temporary RAM, the stack location and
 | 
						|
                         the BFV location.
 | 
						|
  @param Private         Pointer to the private data passed in from caller
 | 
						|
 | 
						|
**/
 | 
						|
VOID
 | 
						|
PeiDispatcher (
 | 
						|
  IN CONST EFI_SEC_PEI_HAND_OFF  *SecCoreData,
 | 
						|
  IN PEI_CORE_INSTANCE           *Private
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS                          Status;
 | 
						|
  UINT32                              Index1;
 | 
						|
  UINT32                              Index2;
 | 
						|
  CONST EFI_PEI_SERVICES              **PeiServices;
 | 
						|
  EFI_PEI_FILE_HANDLE                 PeimFileHandle;
 | 
						|
  UINTN                               FvCount;
 | 
						|
  UINTN                               PeimCount;
 | 
						|
  UINT32                              AuthenticationState;
 | 
						|
  EFI_PHYSICAL_ADDRESS                EntryPoint;
 | 
						|
  EFI_PEIM_ENTRY_POINT2               PeimEntryPoint;
 | 
						|
  UINTN                               SaveCurrentPeimCount;
 | 
						|
  UINTN                               SaveCurrentFvCount;
 | 
						|
  EFI_PEI_FILE_HANDLE                 SaveCurrentFileHandle;
 | 
						|
  EFI_FV_FILE_INFO                    FvFileInfo;
 | 
						|
  PEI_CORE_FV_HANDLE                  *CoreFvHandle;
 | 
						|
 | 
						|
  PeiServices = (CONST EFI_PEI_SERVICES **) &Private->Ps;
 | 
						|
  PeimEntryPoint = NULL;
 | 
						|
  PeimFileHandle = NULL;
 | 
						|
  EntryPoint     = 0;
 | 
						|
 | 
						|
  if ((Private->PeiMemoryInstalled) &&
 | 
						|
      (PcdGetBool (PcdMigrateTemporaryRamFirmwareVolumes) ||
 | 
						|
       (Private->HobList.HandoffInformationTable->BootMode != BOOT_ON_S3_RESUME) ||
 | 
						|
       PcdGetBool (PcdShadowPeimOnS3Boot))
 | 
						|
    ) {
 | 
						|
    //
 | 
						|
    // Once real memory is available, shadow the RegisterForShadow modules. And meanwhile
 | 
						|
    // update the modules' status from PEIM_STATE_REGISTER_FOR_SHADOW to PEIM_STATE_DONE.
 | 
						|
    //
 | 
						|
    SaveCurrentPeimCount  = Private->CurrentPeimCount;
 | 
						|
    SaveCurrentFvCount    = Private->CurrentPeimFvCount;
 | 
						|
    SaveCurrentFileHandle =  Private->CurrentFileHandle;
 | 
						|
 | 
						|
    for (Index1 = 0; Index1 < Private->FvCount; Index1++) {
 | 
						|
      for (Index2 = 0; Index2 < Private->Fv[Index1].PeimCount; Index2++) {
 | 
						|
        if (Private->Fv[Index1].PeimState[Index2] == PEIM_STATE_REGISTER_FOR_SHADOW) {
 | 
						|
          PeimFileHandle = Private->Fv[Index1].FvFileHandles[Index2];
 | 
						|
          Private->CurrentFileHandle   = PeimFileHandle;
 | 
						|
          Private->CurrentPeimFvCount  = Index1;
 | 
						|
          Private->CurrentPeimCount    = Index2;
 | 
						|
          Status = PeiLoadImage (
 | 
						|
                    (CONST EFI_PEI_SERVICES **) &Private->Ps,
 | 
						|
                    PeimFileHandle,
 | 
						|
                    PEIM_STATE_REGISTER_FOR_SHADOW,
 | 
						|
                    &EntryPoint,
 | 
						|
                    &AuthenticationState
 | 
						|
                    );
 | 
						|
          if (Status == EFI_SUCCESS) {
 | 
						|
            //
 | 
						|
            // PEIM_STATE_REGISTER_FOR_SHADOW move to PEIM_STATE_DONE
 | 
						|
            //
 | 
						|
            Private->Fv[Index1].PeimState[Index2]++;
 | 
						|
            //
 | 
						|
            // Call the PEIM entry point
 | 
						|
            //
 | 
						|
            PeimEntryPoint = (EFI_PEIM_ENTRY_POINT2)(UINTN)EntryPoint;
 | 
						|
 | 
						|
            PERF_START_IMAGE_BEGIN (PeimFileHandle);
 | 
						|
            PeimEntryPoint(PeimFileHandle, (const EFI_PEI_SERVICES **) &Private->Ps);
 | 
						|
            PERF_START_IMAGE_END (PeimFileHandle);
 | 
						|
          }
 | 
						|
 | 
						|
          //
 | 
						|
          // Process the Notify list and dispatch any notifies for
 | 
						|
          // newly installed PPIs.
 | 
						|
          //
 | 
						|
          ProcessDispatchNotifyList (Private);
 | 
						|
        }
 | 
						|
      }
 | 
						|
    }
 | 
						|
    Private->CurrentFileHandle  = SaveCurrentFileHandle;
 | 
						|
    Private->CurrentPeimFvCount = SaveCurrentFvCount;
 | 
						|
    Private->CurrentPeimCount   = SaveCurrentPeimCount;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // This is the main dispatch loop.  It will search known FVs for PEIMs and
 | 
						|
  // attempt to dispatch them.  If any PEIM gets dispatched through a single
 | 
						|
  // pass of the dispatcher, it will start over from the BFV again to see
 | 
						|
  // if any new PEIMs dependencies got satisfied.  With a well ordered
 | 
						|
  // FV where PEIMs are found in the order their dependencies are also
 | 
						|
  // satisfied, this dispatcher should run only once.
 | 
						|
  //
 | 
						|
  do {
 | 
						|
    //
 | 
						|
    // In case that reenter PeiCore happens, the last pass record is still available.
 | 
						|
    //
 | 
						|
    if (!Private->PeimDispatcherReenter) {
 | 
						|
      Private->PeimNeedingDispatch      = FALSE;
 | 
						|
      Private->PeimDispatchOnThisPass   = FALSE;
 | 
						|
    } else {
 | 
						|
      Private->PeimDispatcherReenter    = FALSE;
 | 
						|
    }
 | 
						|
 | 
						|
    for (FvCount = Private->CurrentPeimFvCount; FvCount < Private->FvCount; FvCount++) {
 | 
						|
      CoreFvHandle = FindNextCoreFvHandle (Private, FvCount);
 | 
						|
      ASSERT (CoreFvHandle != NULL);
 | 
						|
 | 
						|
      //
 | 
						|
      // If the FV has corresponding EFI_PEI_FIRMWARE_VOLUME_PPI instance, then dispatch it.
 | 
						|
      //
 | 
						|
      if (CoreFvHandle->FvPpi == NULL) {
 | 
						|
        continue;
 | 
						|
      }
 | 
						|
 | 
						|
      Private->CurrentPeimFvCount = FvCount;
 | 
						|
 | 
						|
      if (Private->CurrentPeimCount == 0) {
 | 
						|
        //
 | 
						|
        // When going through each FV, at first, search Apriori file to
 | 
						|
        // reorder all PEIMs to ensure the PEIMs in Apriori file to get
 | 
						|
        // dispatch at first.
 | 
						|
        //
 | 
						|
        DiscoverPeimsAndOrderWithApriori (Private, CoreFvHandle);
 | 
						|
      }
 | 
						|
 | 
						|
      //
 | 
						|
      // Start to dispatch all modules within the current FV.
 | 
						|
      //
 | 
						|
      for (PeimCount = Private->CurrentPeimCount;
 | 
						|
           PeimCount < Private->Fv[FvCount].PeimCount;
 | 
						|
           PeimCount++) {
 | 
						|
        Private->CurrentPeimCount  = PeimCount;
 | 
						|
        PeimFileHandle = Private->CurrentFileHandle = Private->CurrentFvFileHandles[PeimCount];
 | 
						|
 | 
						|
        if (Private->Fv[FvCount].PeimState[PeimCount] == PEIM_STATE_NOT_DISPATCHED) {
 | 
						|
          if (!DepexSatisfied (Private, PeimFileHandle, PeimCount)) {
 | 
						|
            Private->PeimNeedingDispatch = TRUE;
 | 
						|
          } else {
 | 
						|
            Status = CoreFvHandle->FvPpi->GetFileInfo (CoreFvHandle->FvPpi, PeimFileHandle, &FvFileInfo);
 | 
						|
            ASSERT_EFI_ERROR (Status);
 | 
						|
            if (FvFileInfo.FileType == EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE) {
 | 
						|
              //
 | 
						|
              // For FV type file, Produce new FvInfo PPI and FV HOB
 | 
						|
              //
 | 
						|
              Status = ProcessFvFile (Private, &Private->Fv[FvCount], PeimFileHandle);
 | 
						|
              if (Status == EFI_SUCCESS) {
 | 
						|
                //
 | 
						|
                // PEIM_STATE_NOT_DISPATCHED move to PEIM_STATE_DISPATCHED
 | 
						|
                //
 | 
						|
                Private->Fv[FvCount].PeimState[PeimCount]++;
 | 
						|
                Private->PeimDispatchOnThisPass = TRUE;
 | 
						|
              } else {
 | 
						|
                //
 | 
						|
                // The related GuidedSectionExtraction/Decompress PPI for the
 | 
						|
                // encapsulated FV image section may be installed in the rest
 | 
						|
                // of this do-while loop, so need to make another pass.
 | 
						|
                //
 | 
						|
                Private->PeimNeedingDispatch = TRUE;
 | 
						|
              }
 | 
						|
            } else {
 | 
						|
              //
 | 
						|
              // For PEIM driver, Load its entry point
 | 
						|
              //
 | 
						|
              Status = PeiLoadImage (
 | 
						|
                         PeiServices,
 | 
						|
                         PeimFileHandle,
 | 
						|
                         PEIM_STATE_NOT_DISPATCHED,
 | 
						|
                         &EntryPoint,
 | 
						|
                         &AuthenticationState
 | 
						|
                         );
 | 
						|
              if (Status == EFI_SUCCESS) {
 | 
						|
                //
 | 
						|
                // The PEIM has its dependencies satisfied, and its entry point
 | 
						|
                // has been found, so invoke it.
 | 
						|
                //
 | 
						|
                PERF_START_IMAGE_BEGIN (PeimFileHandle);
 | 
						|
 | 
						|
                REPORT_STATUS_CODE_WITH_EXTENDED_DATA (
 | 
						|
                  EFI_PROGRESS_CODE,
 | 
						|
                  (EFI_SOFTWARE_PEI_CORE | EFI_SW_PC_INIT_BEGIN),
 | 
						|
                  (VOID *)(&PeimFileHandle),
 | 
						|
                  sizeof (PeimFileHandle)
 | 
						|
                  );
 | 
						|
 | 
						|
                Status = VerifyPeim (Private, CoreFvHandle->FvHandle, PeimFileHandle, AuthenticationState);
 | 
						|
                if (Status != EFI_SECURITY_VIOLATION) {
 | 
						|
                  //
 | 
						|
                  // PEIM_STATE_NOT_DISPATCHED move to PEIM_STATE_DISPATCHED
 | 
						|
                  //
 | 
						|
                  Private->Fv[FvCount].PeimState[PeimCount]++;
 | 
						|
                  //
 | 
						|
                  // Call the PEIM entry point for PEIM driver
 | 
						|
                  //
 | 
						|
                  PeimEntryPoint = (EFI_PEIM_ENTRY_POINT2)(UINTN)EntryPoint;
 | 
						|
                  PeimEntryPoint (PeimFileHandle, (const EFI_PEI_SERVICES **) PeiServices);
 | 
						|
                  Private->PeimDispatchOnThisPass = TRUE;
 | 
						|
                } else {
 | 
						|
                  //
 | 
						|
                  // The related GuidedSectionExtraction PPI for the
 | 
						|
                  // signed PEIM image section may be installed in the rest
 | 
						|
                  // of this do-while loop, so need to make another pass.
 | 
						|
                  //
 | 
						|
                  Private->PeimNeedingDispatch = TRUE;
 | 
						|
                }
 | 
						|
 | 
						|
                REPORT_STATUS_CODE_WITH_EXTENDED_DATA (
 | 
						|
                  EFI_PROGRESS_CODE,
 | 
						|
                  (EFI_SOFTWARE_PEI_CORE | EFI_SW_PC_INIT_END),
 | 
						|
                  (VOID *)(&PeimFileHandle),
 | 
						|
                  sizeof (PeimFileHandle)
 | 
						|
                  );
 | 
						|
                PERF_START_IMAGE_END (PeimFileHandle);
 | 
						|
 | 
						|
              }
 | 
						|
            }
 | 
						|
 | 
						|
            PeiCheckAndSwitchStack (SecCoreData, Private);
 | 
						|
 | 
						|
            //
 | 
						|
            // Process the Notify list and dispatch any notifies for
 | 
						|
            // newly installed PPIs.
 | 
						|
            //
 | 
						|
            ProcessDispatchNotifyList (Private);
 | 
						|
 | 
						|
            //
 | 
						|
            // Recheck SwitchStackSignal after ProcessDispatchNotifyList()
 | 
						|
            // in case PeiInstallPeiMemory() is done in a callback with
 | 
						|
            // EFI_PEI_PPI_DESCRIPTOR_NOTIFY_DISPATCH.
 | 
						|
            //
 | 
						|
            PeiCheckAndSwitchStack (SecCoreData, Private);
 | 
						|
 | 
						|
            if ((Private->PeiMemoryInstalled) && (Private->Fv[FvCount].PeimState[PeimCount] == PEIM_STATE_REGISTER_FOR_SHADOW) &&   \
 | 
						|
                (PcdGetBool (PcdMigrateTemporaryRamFirmwareVolumes) ||
 | 
						|
                 (Private->HobList.HandoffInformationTable->BootMode != BOOT_ON_S3_RESUME) ||
 | 
						|
                 PcdGetBool (PcdShadowPeimOnS3Boot))
 | 
						|
              ) {
 | 
						|
              //
 | 
						|
              // If memory is available we shadow images by default for performance reasons.
 | 
						|
              // We call the entry point a 2nd time so the module knows it's shadowed.
 | 
						|
              //
 | 
						|
              //PERF_START (PeiServices, L"PEIM", PeimFileHandle, 0);
 | 
						|
              if ((Private->HobList.HandoffInformationTable->BootMode != BOOT_ON_S3_RESUME) && !PcdGetBool (PcdShadowPeimOnBoot) &&
 | 
						|
                  !PcdGetBool (PcdMigrateTemporaryRamFirmwareVolumes)) {
 | 
						|
                //
 | 
						|
                // Load PEIM into Memory for Register for shadow PEIM.
 | 
						|
                //
 | 
						|
                Status = PeiLoadImage (
 | 
						|
                           PeiServices,
 | 
						|
                           PeimFileHandle,
 | 
						|
                           PEIM_STATE_REGISTER_FOR_SHADOW,
 | 
						|
                           &EntryPoint,
 | 
						|
                           &AuthenticationState
 | 
						|
                           );
 | 
						|
                if (Status == EFI_SUCCESS) {
 | 
						|
                  PeimEntryPoint = (EFI_PEIM_ENTRY_POINT2)(UINTN)EntryPoint;
 | 
						|
                }
 | 
						|
              }
 | 
						|
              ASSERT (PeimEntryPoint != NULL);
 | 
						|
              PeimEntryPoint (PeimFileHandle, (const EFI_PEI_SERVICES **) PeiServices);
 | 
						|
              //PERF_END (PeiServices, L"PEIM", PeimFileHandle, 0);
 | 
						|
 | 
						|
              //
 | 
						|
              // PEIM_STATE_REGISTER_FOR_SHADOW move to PEIM_STATE_DONE
 | 
						|
              //
 | 
						|
              Private->Fv[FvCount].PeimState[PeimCount]++;
 | 
						|
 | 
						|
              //
 | 
						|
              // Process the Notify list and dispatch any notifies for
 | 
						|
              // newly installed PPIs.
 | 
						|
              //
 | 
						|
              ProcessDispatchNotifyList (Private);
 | 
						|
            }
 | 
						|
          }
 | 
						|
        }
 | 
						|
      }
 | 
						|
 | 
						|
      //
 | 
						|
      // Before walking through the next FV, we should set them to NULL/0 to
 | 
						|
      // start at the beginning of the next FV.
 | 
						|
      //
 | 
						|
      Private->CurrentFileHandle = NULL;
 | 
						|
      Private->CurrentPeimCount = 0;
 | 
						|
      Private->CurrentFvFileHandles = NULL;
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    // Before making another pass, we should set it to 0 to
 | 
						|
    // go through all the FVs.
 | 
						|
    //
 | 
						|
    Private->CurrentPeimFvCount = 0;
 | 
						|
 | 
						|
    //
 | 
						|
    // PeimNeedingDispatch being TRUE means we found a PEIM/FV that did not get
 | 
						|
    //  dispatched. So we need to make another pass
 | 
						|
    //
 | 
						|
    // PeimDispatchOnThisPass being TRUE means we dispatched a PEIM/FV on this
 | 
						|
    //  pass. If we did not dispatch a PEIM/FV there is no point in trying again
 | 
						|
    //  as it will fail the next time too (nothing has changed).
 | 
						|
    //
 | 
						|
  } while (Private->PeimNeedingDispatch && Private->PeimDispatchOnThisPass);
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Initialize the Dispatcher's data members
 | 
						|
 | 
						|
  @param PrivateData     PeiCore's private data structure
 | 
						|
  @param OldCoreData     Old data from SecCore
 | 
						|
                         NULL if being run in non-permanent memory mode.
 | 
						|
  @param SecCoreData     Points to a data structure containing information about the PEI core's operating
 | 
						|
                         environment, such as the size and location of temporary RAM, the stack location and
 | 
						|
                         the BFV location.
 | 
						|
 | 
						|
  @return None.
 | 
						|
 | 
						|
**/
 | 
						|
VOID
 | 
						|
InitializeDispatcherData (
 | 
						|
  IN PEI_CORE_INSTANCE            *PrivateData,
 | 
						|
  IN PEI_CORE_INSTANCE            *OldCoreData,
 | 
						|
  IN CONST EFI_SEC_PEI_HAND_OFF   *SecCoreData
 | 
						|
  )
 | 
						|
{
 | 
						|
  if (OldCoreData == NULL) {
 | 
						|
    PrivateData->PeimDispatcherReenter = FALSE;
 | 
						|
    PeiInitializeFv (PrivateData, SecCoreData);
 | 
						|
  } else {
 | 
						|
    PeiReinitializeFv (PrivateData);
 | 
						|
  }
 | 
						|
 | 
						|
  return;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  This routine parses the Dependency Expression, if available, and
 | 
						|
  decides if the module can be executed.
 | 
						|
 | 
						|
 | 
						|
  @param Private         PeiCore's private data structure
 | 
						|
  @param FileHandle      PEIM's file handle
 | 
						|
  @param PeimCount       Peim count in all dispatched PEIMs.
 | 
						|
 | 
						|
  @retval TRUE   Can be dispatched
 | 
						|
  @retval FALSE  Cannot be dispatched
 | 
						|
 | 
						|
**/
 | 
						|
BOOLEAN
 | 
						|
DepexSatisfied (
 | 
						|
  IN PEI_CORE_INSTANCE          *Private,
 | 
						|
  IN EFI_PEI_FILE_HANDLE        FileHandle,
 | 
						|
  IN UINTN                      PeimCount
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS           Status;
 | 
						|
  VOID                 *DepexData;
 | 
						|
  EFI_FV_FILE_INFO     FileInfo;
 | 
						|
 | 
						|
  Status = PeiServicesFfsGetFileInfo (FileHandle, &FileInfo);
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    DEBUG ((DEBUG_DISPATCH, "Evaluate PEI DEPEX for FFS(Unknown)\n"));
 | 
						|
  } else {
 | 
						|
    DEBUG ((DEBUG_DISPATCH, "Evaluate PEI DEPEX for FFS(%g)\n", &FileInfo.FileName));
 | 
						|
  }
 | 
						|
 | 
						|
  if (PeimCount < Private->AprioriCount) {
 | 
						|
    //
 | 
						|
    // If it's in the Apriori file then we set DEPEX to TRUE
 | 
						|
    //
 | 
						|
    DEBUG ((DEBUG_DISPATCH, "  RESULT = TRUE (Apriori)\n"));
 | 
						|
    return TRUE;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Depex section not in the encapsulated section.
 | 
						|
  //
 | 
						|
  Status = PeiServicesFfsFindSectionData (
 | 
						|
              EFI_SECTION_PEI_DEPEX,
 | 
						|
              FileHandle,
 | 
						|
              (VOID **)&DepexData
 | 
						|
              );
 | 
						|
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    //
 | 
						|
    // If there is no DEPEX, assume the module can be executed
 | 
						|
    //
 | 
						|
    DEBUG ((DEBUG_DISPATCH, "  RESULT = TRUE (No DEPEX)\n"));
 | 
						|
    return TRUE;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Evaluate a given DEPEX
 | 
						|
  //
 | 
						|
  return PeimDispatchReadiness (&Private->Ps, DepexData);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  This routine enables a PEIM to register itself for shadow when the PEI Foundation
 | 
						|
  discovers permanent memory.
 | 
						|
 | 
						|
  @param FileHandle             File handle of a PEIM.
 | 
						|
 | 
						|
  @retval EFI_NOT_FOUND         The file handle doesn't point to PEIM itself.
 | 
						|
  @retval EFI_ALREADY_STARTED   Indicate that the PEIM has been registered itself.
 | 
						|
  @retval EFI_SUCCESS           Successfully to register itself.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
PeiRegisterForShadow (
 | 
						|
  IN EFI_PEI_FILE_HANDLE       FileHandle
 | 
						|
  )
 | 
						|
{
 | 
						|
  PEI_CORE_INSTANCE            *Private;
 | 
						|
  Private = PEI_CORE_INSTANCE_FROM_PS_THIS (GetPeiServicesTablePointer ());
 | 
						|
 | 
						|
  if (Private->CurrentFileHandle != FileHandle) {
 | 
						|
    //
 | 
						|
    // The FileHandle must be for the current PEIM
 | 
						|
    //
 | 
						|
    return EFI_NOT_FOUND;
 | 
						|
  }
 | 
						|
 | 
						|
  if (Private->Fv[Private->CurrentPeimFvCount].PeimState[Private->CurrentPeimCount] >= PEIM_STATE_REGISTER_FOR_SHADOW) {
 | 
						|
    //
 | 
						|
    // If the PEIM has already entered the PEIM_STATE_REGISTER_FOR_SHADOW or PEIM_STATE_DONE then it's already been started
 | 
						|
    //
 | 
						|
    return EFI_ALREADY_STARTED;
 | 
						|
  }
 | 
						|
 | 
						|
  Private->Fv[Private->CurrentPeimFvCount].PeimState[Private->CurrentPeimCount] = PEIM_STATE_REGISTER_FOR_SHADOW;
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 |