mirror of
				https://github.com/acidanthera/audk.git
				synced 2025-10-31 19:23:54 +01:00 
			
		
		
		
	REF: https://bugzilla.tianocore.org/show_bug.cgi?id=3737 Apply uncrustify changes to .c/.h files in the MdeModulePkg package Cc: Andrew Fish <afish@apple.com> Cc: Leif Lindholm <leif@nuviainc.com> Cc: Michael D Kinney <michael.d.kinney@intel.com> Signed-off-by: Michael Kubacki <michael.kubacki@microsoft.com> Reviewed-by: Liming Gao <gaoliming@byosoft.com.cn>
		
			
				
	
	
		
			1783 lines
		
	
	
		
			68 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1783 lines
		
	
	
		
			68 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 ((DEBUG_INFO, "LOADING MODULE FIXED INFO: PcdLoadFixAddressRuntimeCodePageNumber= 0x%x.\n", PcdGet32 (PcdLoadFixAddressRuntimeCodePageNumber)));
 | |
|   DEBUG ((DEBUG_INFO, "LOADING MODULE FIXED INFO: PcdLoadFixAddressBootTimeCodePageNumber= 0x%x.\n", PcdGet32 (PcdLoadFixAddressBootTimeCodePageNumber)));
 | |
|   DEBUG ((DEBUG_INFO, "LOADING MODULE FIXED INFO: PcdLoadFixAddressPeiCodePageNumber= 0x%x.\n", PcdGet32 (PcdLoadFixAddressPeiCodePageNumber)));
 | |
|   DEBUG ((DEBUG_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 ((DEBUG_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 ((DEBUG_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 ((DEBUG_INFO, "LOADING MODULE FIXED INFO:Top Address 0x%lx is valid \n", TopLoadingAddress));
 | |
|       TopLoadingAddress += MINIMUM_INITIAL_MEMORY_SIZE;
 | |
|     } else {
 | |
|       DEBUG ((DEBUG_INFO, "LOADING MODULE FIXED ERROR:Top Address 0x%lx is invalid \n", TopLoadingAddress));
 | |
|       DEBUG ((DEBUG_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 ((
 | |
|                 DEBUG_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 ((DEBUG_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 ((DEBUG_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 ((DEBUG_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 ((DEBUG_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 ((DEBUG_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 ((DEBUG_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 ((DEBUG_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         Successfully 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_VERBOSE, "%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 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           Successfully 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_PHYSICAL_ADDRESS        FvHeaderAddress;
 | |
|   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),
 | |
|                   &FvHeaderAddress
 | |
|                   );
 | |
|       ASSERT_EFI_ERROR (Status);
 | |
|       MigratedFvHeader = (EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)FvHeaderAddress;
 | |
| 
 | |
|       //
 | |
|       // 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),
 | |
|                   &FvHeaderAddress
 | |
|                   );
 | |
|       ASSERT_EFI_ERROR (Status);
 | |
|       RawDataFvHeader = (EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)FvHeaderAddress;
 | |
| 
 | |
|       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;
 | |
| }
 |