summaryrefslogtreecommitdiff
path: root/MdeModulePkg/Core/Pei/Image/Image.c
diff options
context:
space:
mode:
Diffstat (limited to 'MdeModulePkg/Core/Pei/Image/Image.c')
-rw-r--r--MdeModulePkg/Core/Pei/Image/Image.c1964
1 files changed, 982 insertions, 982 deletions
diff --git a/MdeModulePkg/Core/Pei/Image/Image.c b/MdeModulePkg/Core/Pei/Image/Image.c
index cee9f09c6e..46d7f60fc4 100644
--- a/MdeModulePkg/Core/Pei/Image/Image.c
+++ b/MdeModulePkg/Core/Pei/Image/Image.c
@@ -1,982 +1,982 @@
-/** @file
- Pei Core Load Image Support
-
-Copyright (c) 2006 - 2021, Intel Corporation. All rights reserved.<BR>
-SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#include "PeiMain.h"
-
-EFI_PEI_LOAD_FILE_PPI mPeiLoadImagePpi = {
- PeiLoadImageLoadImageWrapper
-};
-
-EFI_PEI_PPI_DESCRIPTOR gPpiLoadFilePpiList = {
- (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
- &gEfiPeiLoadFilePpiGuid,
- &mPeiLoadImagePpi
-};
-
-/**
-
- Support routine for the PE/COFF Loader that reads a buffer from a PE/COFF file.
- The function is used for XIP code to have optimized memory copy.
-
- @param FileHandle - The handle to the PE/COFF file
- @param FileOffset - The offset, in bytes, into the file to read
- @param ReadSize - The number of bytes to read from the file starting at FileOffset
- @param Buffer - A pointer to the buffer to read the data into.
-
- @return EFI_SUCCESS - ReadSize bytes of data were read into Buffer from the PE/COFF file starting at FileOffset
-
-**/
-EFI_STATUS
-EFIAPI
-PeiImageRead (
- IN VOID *FileHandle,
- IN UINTN FileOffset,
- IN UINTN *ReadSize,
- OUT VOID *Buffer
- )
-{
- CHAR8 *Destination8;
- CHAR8 *Source8;
-
- Destination8 = Buffer;
- Source8 = (CHAR8 *)((UINTN)FileHandle + FileOffset);
- if (Destination8 != Source8) {
- CopyMem (Destination8, Source8, *ReadSize);
- }
-
- return EFI_SUCCESS;
-}
-
-/**
- To check memory usage bit map array to figure out if the memory range the image will be loaded in is available or not. If
- memory range is available, the function will mark the corresponding bits to 1 which indicates the memory range is used.
- The function is only invoked when load modules at fixed address feature is enabled.
-
- @param Private Pointer to the private data passed in from caller
- @param ImageBase The base address the image will be loaded at.
- @param ImageSize The size of the image
-
- @retval EFI_SUCCESS The memory range the image will be loaded in is available
- @retval EFI_NOT_FOUND The memory range the image will be loaded in is not available
-**/
-EFI_STATUS
-CheckAndMarkFixLoadingMemoryUsageBitMap (
- IN PEI_CORE_INSTANCE *Private,
- IN EFI_PHYSICAL_ADDRESS ImageBase,
- IN UINT32 ImageSize
- )
-{
- UINT32 DxeCodePageNumber;
- UINT64 ReservedCodeSize;
- EFI_PHYSICAL_ADDRESS PeiCodeBase;
- UINT32 BaseOffsetPageNumber;
- UINT32 TopOffsetPageNumber;
- UINT32 Index;
- UINT64 *MemoryUsageBitMap;
-
- //
- // The reserved code range includes RuntimeCodePage range, Boot time code range and PEI code range.
- //
- DxeCodePageNumber = PcdGet32 (PcdLoadFixAddressBootTimeCodePageNumber);
- DxeCodePageNumber += PcdGet32 (PcdLoadFixAddressRuntimeCodePageNumber);
- ReservedCodeSize = EFI_PAGES_TO_SIZE (DxeCodePageNumber + PcdGet32 (PcdLoadFixAddressPeiCodePageNumber));
- PeiCodeBase = Private->LoadModuleAtFixAddressTopAddress - ReservedCodeSize;
-
- //
- // Test the memory range for loading the image in the PEI code range.
- //
- if (((Private->LoadModuleAtFixAddressTopAddress - EFI_PAGES_TO_SIZE (DxeCodePageNumber)) < (ImageBase + ImageSize)) ||
- (PeiCodeBase > ImageBase))
- {
- return EFI_NOT_FOUND;
- }
-
- //
- // Test if the memory is available or not.
- //
- MemoryUsageBitMap = Private->PeiCodeMemoryRangeUsageBitMap;
- BaseOffsetPageNumber = EFI_SIZE_TO_PAGES ((UINT32)(ImageBase - PeiCodeBase));
- TopOffsetPageNumber = EFI_SIZE_TO_PAGES ((UINT32)(ImageBase + ImageSize - PeiCodeBase));
- for (Index = BaseOffsetPageNumber; Index < TopOffsetPageNumber; Index++) {
- if ((MemoryUsageBitMap[Index / 64] & LShiftU64 (1, (Index % 64))) != 0) {
- //
- // This page is already used.
- //
- return EFI_NOT_FOUND;
- }
- }
-
- //
- // Being here means the memory range is available. So mark the bits for the memory range
- //
- for (Index = BaseOffsetPageNumber; Index < TopOffsetPageNumber; Index++) {
- MemoryUsageBitMap[Index / 64] |= LShiftU64 (1, (Index % 64));
- }
-
- return EFI_SUCCESS;
-}
-
-/**
-
- Get the fixed loading address from image header assigned by build tool. This function only be called
- when Loading module at Fixed address feature enabled.
-
- @param ImageContext Pointer to the image context structure that describes the PE/COFF
- image that needs to be examined by this function.
- @param Private Pointer to the private data passed in from caller
-
- @retval EFI_SUCCESS An fixed loading address is assigned to this image by build tools .
- @retval EFI_NOT_FOUND The image has no assigned fixed loading address.
-
-**/
-EFI_STATUS
-GetPeCoffImageFixLoadingAssignedAddress (
- IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext,
- IN PEI_CORE_INSTANCE *Private
- )
-{
- UINTN SectionHeaderOffset;
- EFI_STATUS Status;
- EFI_IMAGE_SECTION_HEADER SectionHeader;
- EFI_IMAGE_OPTIONAL_HEADER_UNION *ImgHdr;
- EFI_PHYSICAL_ADDRESS FixLoadingAddress;
- UINT16 Index;
- UINTN Size;
- UINT16 NumberOfSections;
- UINT64 ValueInSectionHeader;
-
- FixLoadingAddress = 0;
- Status = EFI_NOT_FOUND;
-
- //
- // Get PeHeader pointer
- //
- ImgHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)((CHAR8 *)ImageContext->Handle + ImageContext->PeCoffHeaderOffset);
- if (ImageContext->IsTeImage) {
- //
- // for TE image, the fix loading address is saved in first section header that doesn't point
- // to code section.
- //
- SectionHeaderOffset = sizeof (EFI_TE_IMAGE_HEADER);
- NumberOfSections = ImgHdr->Te.NumberOfSections;
- } else {
- SectionHeaderOffset = ImageContext->PeCoffHeaderOffset +
- sizeof (UINT32) +
- sizeof (EFI_IMAGE_FILE_HEADER) +
- ImgHdr->Pe32.FileHeader.SizeOfOptionalHeader;
- NumberOfSections = ImgHdr->Pe32.FileHeader.NumberOfSections;
- }
-
- //
- // Get base address from the first section header that doesn't point to code section.
- //
- for (Index = 0; Index < NumberOfSections; Index++) {
- //
- // Read section header from file
- //
- Size = sizeof (EFI_IMAGE_SECTION_HEADER);
- Status = ImageContext->ImageRead (
- ImageContext->Handle,
- SectionHeaderOffset,
- &Size,
- &SectionHeader
- );
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- Status = EFI_NOT_FOUND;
-
- if ((SectionHeader.Characteristics & EFI_IMAGE_SCN_CNT_CODE) == 0) {
- //
- // Build tool will save the address in PointerToRelocations & PointerToLineNumbers fields in the first section header
- // that doesn't point to code section in image header, as well as ImageBase field of image header. A notable thing is
- // that for PEIM, the value in ImageBase field may not be equal to the value in PointerToRelocations & PointerToLineNumbers because
- // for XIP PEIM, ImageBase field holds the image base address running on the Flash. And PointerToRelocations & PointerToLineNumbers
- // hold the image base address when it is shadow to the memory. And there is an assumption that when the feature is enabled, if a
- // module is assigned a loading address by tools, PointerToRelocations & PointerToLineNumbers fields should NOT be Zero, or
- // else, these 2 fields should be set to Zero
- //
- ValueInSectionHeader = ReadUnaligned64 ((UINT64 *)&SectionHeader.PointerToRelocations);
- if (ValueInSectionHeader != 0) {
- //
- // Found first section header that doesn't point to code section.
- //
- if ((INT64)PcdGet64 (PcdLoadModuleAtFixAddressEnable) > 0) {
- //
- // When LMFA feature is configured as Load Module at Fixed Absolute Address mode, PointerToRelocations & PointerToLineNumbers field
- // hold the absolute address of image base running in memory
- //
- FixLoadingAddress = ValueInSectionHeader;
- } else {
- //
- // When LMFA feature is configured as Load Module at Fixed offset mode, PointerToRelocations & PointerToLineNumbers field
- // hold the offset relative to a platform-specific top address.
- //
- FixLoadingAddress = (EFI_PHYSICAL_ADDRESS)(Private->LoadModuleAtFixAddressTopAddress + (INT64)ValueInSectionHeader);
- }
-
- //
- // Check if the memory range is available.
- //
- Status = CheckAndMarkFixLoadingMemoryUsageBitMap (Private, FixLoadingAddress, (UINT32)ImageContext->ImageSize);
- if (!EFI_ERROR (Status)) {
- //
- // The assigned address is valid. Return the specified loading address
- //
- ImageContext->ImageAddress = FixLoadingAddress;
- }
- }
-
- break;
- }
-
- SectionHeaderOffset += sizeof (EFI_IMAGE_SECTION_HEADER);
- }
-
- DEBUG ((DEBUG_INFO|DEBUG_LOAD, "LOADING MODULE FIXED INFO: Loading module at fixed address 0x%11p. Status= %r \n", (VOID *)(UINTN)FixLoadingAddress, Status));
- return Status;
-}
-
-/**
-
- Loads and relocates a PE/COFF image into memory.
- If the image is not relocatable, it will not be loaded into memory and be loaded as XIP image.
-
- @param FileHandle - Pointer to the FFS file header of the image.
- @param Pe32Data - The base address of the PE/COFF file that is to be loaded and relocated
- @param ImageAddress - The base address of the relocated PE/COFF image
- @param ImageSize - The size of the relocated PE/COFF image
- @param EntryPoint - The entry point of the relocated PE/COFF image
-
- @retval EFI_SUCCESS The file was loaded and relocated
- @retval EFI_OUT_OF_RESOURCES There was not enough memory to load and relocate the PE/COFF file
- @retval EFI_WARN_BUFFER_TOO_SMALL
- There is not enough heap to allocate the requested size.
- This will not prevent the XIP image from being invoked.
-
-**/
-EFI_STATUS
-LoadAndRelocatePeCoffImage (
- IN EFI_PEI_FILE_HANDLE FileHandle,
- IN VOID *Pe32Data,
- OUT EFI_PHYSICAL_ADDRESS *ImageAddress,
- OUT UINT64 *ImageSize,
- OUT EFI_PHYSICAL_ADDRESS *EntryPoint
- )
-{
- EFI_STATUS Status;
- PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;
- PEI_CORE_INSTANCE *Private;
- UINT64 AlignImageSize;
- BOOLEAN IsXipImage;
- EFI_STATUS ReturnStatus;
- BOOLEAN IsS3Boot;
- BOOLEAN IsPeiModule;
- BOOLEAN IsRegisterForShadow;
- EFI_FV_FILE_INFO FileInfo;
-
- Private = PEI_CORE_INSTANCE_FROM_PS_THIS (GetPeiServicesTablePointer ());
-
- ReturnStatus = EFI_SUCCESS;
- IsXipImage = FALSE;
- ZeroMem (&ImageContext, sizeof (ImageContext));
- ImageContext.Handle = Pe32Data;
- ImageContext.ImageRead = PeiImageRead;
-
- Status = PeCoffLoaderGetImageInfo (&ImageContext);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- //
- // Initialize local IsS3Boot and IsRegisterForShadow variable
- //
- IsS3Boot = FALSE;
- if (Private->HobList.HandoffInformationTable->BootMode == BOOT_ON_S3_RESUME) {
- IsS3Boot = TRUE;
- }
-
- IsRegisterForShadow = FALSE;
- if ( (Private->CurrentFileHandle == FileHandle)
- && (Private->Fv[Private->CurrentPeimFvCount].PeimState[Private->CurrentPeimCount] == PEIM_STATE_REGISTER_FOR_SHADOW))
- {
- IsRegisterForShadow = TRUE;
- }
-
- //
- // XIP image that ImageAddress is same to Image handle.
- //
- if (ImageContext.ImageAddress == (EFI_PHYSICAL_ADDRESS)(UINTN)Pe32Data) {
- IsXipImage = TRUE;
- }
-
- //
- // Get file type first
- //
- Status = PeiServicesFfsGetFileInfo (FileHandle, &FileInfo);
- ASSERT_EFI_ERROR (Status);
-
- //
- // Check whether the file type is PEI module.
- //
- IsPeiModule = FALSE;
- if ((FileInfo.FileType == EFI_FV_FILETYPE_PEI_CORE) ||
- (FileInfo.FileType == EFI_FV_FILETYPE_PEIM) ||
- (FileInfo.FileType == EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER))
- {
- IsPeiModule = TRUE;
- }
-
- //
- // When Image has no reloc section, it can't be relocated into memory.
- //
- if (ImageContext.RelocationsStripped && (Private->PeiMemoryInstalled) &&
- ((!IsPeiModule) || PcdGetBool (PcdMigrateTemporaryRamFirmwareVolumes) ||
- (!IsS3Boot && (PcdGetBool (PcdShadowPeimOnBoot) || IsRegisterForShadow)) ||
- (IsS3Boot && PcdGetBool (PcdShadowPeimOnS3Boot)))
- )
- {
- DEBUG ((DEBUG_INFO|DEBUG_LOAD, "The image at 0x%08x without reloc section can't be loaded into memory\n", (UINTN)Pe32Data));
- }
-
- //
- // Set default base address to current image address.
- //
- ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)Pe32Data;
-
- //
- // Allocate Memory for the image when memory is ready, and image is relocatable.
- // On normal boot, PcdShadowPeimOnBoot decides whether load PEIM or PeiCore into memory.
- // On S3 boot, PcdShadowPeimOnS3Boot decides whether load PEIM or PeiCore into memory.
- //
- if ((!ImageContext.RelocationsStripped) && (Private->PeiMemoryInstalled) &&
- ((!IsPeiModule) || PcdGetBool (PcdMigrateTemporaryRamFirmwareVolumes) ||
- (!IsS3Boot && (PcdGetBool (PcdShadowPeimOnBoot) || IsRegisterForShadow)) ||
- (IsS3Boot && PcdGetBool (PcdShadowPeimOnS3Boot)))
- )
- {
- //
- // Allocate more buffer to avoid buffer overflow.
- //
- if (ImageContext.IsTeImage) {
- AlignImageSize = ImageContext.ImageSize + ((EFI_TE_IMAGE_HEADER *)Pe32Data)->StrippedSize - sizeof (EFI_TE_IMAGE_HEADER);
- } else {
- AlignImageSize = ImageContext.ImageSize;
- }
-
- if (ImageContext.SectionAlignment > EFI_PAGE_SIZE) {
- AlignImageSize += ImageContext.SectionAlignment;
- }
-
- if ((PcdGet64 (PcdLoadModuleAtFixAddressEnable) != 0) && (Private->HobList.HandoffInformationTable->BootMode != BOOT_ON_S3_RESUME)) {
- Status = GetPeCoffImageFixLoadingAssignedAddress (&ImageContext, Private);
- if (EFI_ERROR (Status)) {
- DEBUG ((DEBUG_INFO|DEBUG_LOAD, "LOADING MODULE FIXED ERROR: Failed to load module at fixed address. \n"));
- //
- // The PEIM is not assigned valid address, try to allocate page to load it.
- //
- Status = PeiServicesAllocatePages (
- EfiBootServicesCode,
- EFI_SIZE_TO_PAGES ((UINT32)AlignImageSize),
- &ImageContext.ImageAddress
- );
- }
- } else {
- Status = PeiServicesAllocatePages (
- EfiBootServicesCode,
- EFI_SIZE_TO_PAGES ((UINT32)AlignImageSize),
- &ImageContext.ImageAddress
- );
- }
-
- if (!EFI_ERROR (Status)) {
- //
- // Adjust the Image Address to make sure it is section alignment.
- //
- if (ImageContext.SectionAlignment > EFI_PAGE_SIZE) {
- ImageContext.ImageAddress =
- (ImageContext.ImageAddress + ImageContext.SectionAlignment - 1) &
- ~((UINTN)ImageContext.SectionAlignment - 1);
- }
-
- //
- // Fix alignment requirement when Load IPF TeImage into memory.
- // Skip the reserved space for the stripped PeHeader when load TeImage into memory.
- //
- if (ImageContext.IsTeImage) {
- ImageContext.ImageAddress = ImageContext.ImageAddress +
- ((EFI_TE_IMAGE_HEADER *)Pe32Data)->StrippedSize -
- sizeof (EFI_TE_IMAGE_HEADER);
- }
- } else {
- //
- // No enough memory resource.
- //
- if (IsXipImage) {
- //
- // XIP image can still be invoked.
- //
- ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)Pe32Data;
- ReturnStatus = EFI_WARN_BUFFER_TOO_SMALL;
- } else {
- //
- // Non XIP image can't be loaded because no enough memory is allocated.
- //
- ASSERT (FALSE);
- return EFI_OUT_OF_RESOURCES;
- }
- }
- }
-
- //
- // Load the image to our new buffer
- //
- Status = PeCoffLoaderLoadImage (&ImageContext);
- if (EFI_ERROR (Status)) {
- if (ImageContext.ImageError == IMAGE_ERROR_INVALID_SECTION_ALIGNMENT) {
- DEBUG ((DEBUG_ERROR, "PEIM Image Address 0x%11p doesn't meet with section alignment 0x%x.\n", (VOID *)(UINTN)ImageContext.ImageAddress, ImageContext.SectionAlignment));
- }
-
- return Status;
- }
-
- //
- // Relocate the image in our new buffer
- //
- Status = PeCoffLoaderRelocateImage (&ImageContext);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- //
- // Flush the instruction cache so the image data is written before we execute it
- //
- if (ImageContext.ImageAddress != (EFI_PHYSICAL_ADDRESS)(UINTN)Pe32Data) {
- InvalidateInstructionCacheRange ((VOID *)(UINTN)ImageContext.ImageAddress, (UINTN)ImageContext.ImageSize);
- }
-
- *ImageAddress = ImageContext.ImageAddress;
- *ImageSize = ImageContext.ImageSize;
- *EntryPoint = ImageContext.EntryPoint;
-
- return ReturnStatus;
-}
-
-/**
- Loads and relocates a PE/COFF image in place.
-
- @param Pe32Data The base address of the PE/COFF file that is to be loaded and relocated
- @param ImageAddress The base address of the relocated PE/COFF image
-
- @retval EFI_SUCCESS The file was loaded and relocated.
- @retval Others The file not be loaded and error occurred.
-
-**/
-EFI_STATUS
-LoadAndRelocatePeCoffImageInPlace (
- IN VOID *Pe32Data,
- IN VOID *ImageAddress
- )
-{
- EFI_STATUS Status;
- PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;
-
- ZeroMem (&ImageContext, sizeof (ImageContext));
- ImageContext.Handle = Pe32Data;
- ImageContext.ImageRead = PeiImageRead;
-
- Status = PeCoffLoaderGetImageInfo (&ImageContext);
- if (EFI_ERROR (Status)) {
- ASSERT_EFI_ERROR (Status);
- return Status;
- }
-
- ImageContext.ImageAddress = (PHYSICAL_ADDRESS)(UINTN)ImageAddress;
-
- //
- // Load the image in place
- //
- Status = PeCoffLoaderLoadImage (&ImageContext);
- if (EFI_ERROR (Status)) {
- ASSERT_EFI_ERROR (Status);
- return Status;
- }
-
- //
- // Relocate the image in place
- //
- Status = PeCoffLoaderRelocateImage (&ImageContext);
- if (EFI_ERROR (Status)) {
- ASSERT_EFI_ERROR (Status);
- return Status;
- }
-
- //
- // Flush the instruction cache so the image data is written before we execute it
- //
- if (ImageContext.ImageAddress != (EFI_PHYSICAL_ADDRESS)(UINTN)Pe32Data) {
- InvalidateInstructionCacheRange ((VOID *)(UINTN)ImageContext.ImageAddress, (UINTN)ImageContext.ImageSize);
- }
-
- return Status;
-}
-
-/**
- Find the PE32 Data for an FFS file.
-
- @param FileHandle Pointer to the FFS file header of the image.
- @param Pe32Data Pointer to a (VOID *) PE32 Data pointer.
-
- @retval EFI_SUCCESS Image is successfully loaded.
- @retval EFI_NOT_FOUND Fail to locate PE32 Data.
-
-**/
-EFI_STATUS
-PeiGetPe32Data (
- IN EFI_PEI_FILE_HANDLE FileHandle,
- OUT VOID **Pe32Data
- )
-{
- EFI_STATUS Status;
- EFI_SECTION_TYPE SearchType1;
- EFI_SECTION_TYPE SearchType2;
- UINT32 AuthenticationState;
-
- *Pe32Data = NULL;
-
- if (FeaturePcdGet (PcdPeiCoreImageLoaderSearchTeSectionFirst)) {
- SearchType1 = EFI_SECTION_TE;
- SearchType2 = EFI_SECTION_PE32;
- } else {
- SearchType1 = EFI_SECTION_PE32;
- SearchType2 = EFI_SECTION_TE;
- }
-
- //
- // Try to find a first exe section (if PcdPeiCoreImageLoaderSearchTeSectionFirst
- // is true, TE will be searched first).
- //
- Status = PeiServicesFfsFindSectionData3 (
- SearchType1,
- 0,
- FileHandle,
- Pe32Data,
- &AuthenticationState
- );
- //
- // If we didn't find a first exe section, try to find the second exe section.
- //
- if (EFI_ERROR (Status)) {
- Status = PeiServicesFfsFindSectionData3 (
- SearchType2,
- 0,
- FileHandle,
- Pe32Data,
- &AuthenticationState
- );
- }
-
- return Status;
-}
-
-/**
- Loads a PEIM into memory for subsequent execution. If there are compressed
- images or images that need to be relocated into memory for performance reasons,
- this service performs that transformation.
-
- @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation
- @param FileHandle Pointer to the FFS file header of the image.
- @param ImageAddressArg Pointer to PE/TE image.
- @param ImageSizeArg Size of PE/TE image.
- @param EntryPoint Pointer to entry point of specified image file for output.
- @param AuthenticationState - Pointer to attestation authentication state of image.
-
- @retval EFI_SUCCESS Image is successfully loaded.
- @retval EFI_NOT_FOUND Fail to locate necessary PPI.
- @retval EFI_UNSUPPORTED Image Machine Type is not supported.
- @retval EFI_WARN_BUFFER_TOO_SMALL
- There is not enough heap to allocate the requested size.
- This will not prevent the XIP image from being invoked.
-
-**/
-EFI_STATUS
-PeiLoadImageLoadImage (
- IN CONST EFI_PEI_SERVICES **PeiServices,
- IN EFI_PEI_FILE_HANDLE FileHandle,
- OUT EFI_PHYSICAL_ADDRESS *ImageAddressArg OPTIONAL,
- OUT UINT64 *ImageSizeArg OPTIONAL,
- OUT EFI_PHYSICAL_ADDRESS *EntryPoint,
- OUT UINT32 *AuthenticationState
- )
-{
- EFI_STATUS Status;
- VOID *Pe32Data;
- EFI_PHYSICAL_ADDRESS ImageAddress;
- UINT64 ImageSize;
- EFI_PHYSICAL_ADDRESS ImageEntryPoint;
- UINT16 Machine;
- EFI_SECTION_TYPE SearchType1;
- EFI_SECTION_TYPE SearchType2;
-
- *EntryPoint = 0;
- ImageSize = 0;
- *AuthenticationState = 0;
-
- if (FeaturePcdGet (PcdPeiCoreImageLoaderSearchTeSectionFirst)) {
- SearchType1 = EFI_SECTION_TE;
- SearchType2 = EFI_SECTION_PE32;
- } else {
- SearchType1 = EFI_SECTION_PE32;
- SearchType2 = EFI_SECTION_TE;
- }
-
- //
- // Try to find a first exe section (if PcdPeiCoreImageLoaderSearchTeSectionFirst
- // is true, TE will be searched first).
- //
- Status = PeiServicesFfsFindSectionData3 (
- SearchType1,
- 0,
- FileHandle,
- &Pe32Data,
- AuthenticationState
- );
- //
- // If we didn't find a first exe section, try to find the second exe section.
- //
- if (EFI_ERROR (Status)) {
- Status = PeiServicesFfsFindSectionData3 (
- SearchType2,
- 0,
- FileHandle,
- &Pe32Data,
- AuthenticationState
- );
- if (EFI_ERROR (Status)) {
- //
- // PEI core only carry the loader function for TE and PE32 executables
- // If this two section does not exist, just return.
- //
- return Status;
- }
- }
-
- DEBUG ((DEBUG_INFO, "Loading PEIM %g\n", FileHandle));
-
- //
- // If memory is installed, perform the shadow operations
- //
- Status = LoadAndRelocatePeCoffImage (
- FileHandle,
- Pe32Data,
- &ImageAddress,
- &ImageSize,
- &ImageEntryPoint
- );
-
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- //
- // Got the entry point from the loaded Pe32Data
- //
- Pe32Data = (VOID *)((UINTN)ImageAddress);
- *EntryPoint = ImageEntryPoint;
-
- Machine = PeCoffLoaderGetMachineType (Pe32Data);
-
- if (!EFI_IMAGE_MACHINE_TYPE_SUPPORTED (Machine)) {
- if (!EFI_IMAGE_MACHINE_CROSS_TYPE_SUPPORTED (Machine)) {
- return EFI_UNSUPPORTED;
- }
- }
-
- if (ImageAddressArg != NULL) {
- *ImageAddressArg = ImageAddress;
- }
-
- if (ImageSizeArg != NULL) {
- *ImageSizeArg = ImageSize;
- }
-
- DEBUG_CODE_BEGIN ();
- CHAR8 *AsciiString;
- CHAR8 EfiFileName[512];
- INT32 Index;
- INT32 StartIndex;
-
- //
- // Print debug message: Loading PEIM at 0x12345678 EntryPoint=0x12345688 Driver.efi
- //
- if (Machine != EFI_IMAGE_MACHINE_IA64) {
- DEBUG ((DEBUG_INFO | DEBUG_LOAD, "Loading PEIM at 0x%11p EntryPoint=0x%11p ", (VOID *)(UINTN)ImageAddress, (VOID *)(UINTN)*EntryPoint));
- } else {
- //
- // For IPF Image, the real entry point should be print.
- //
- DEBUG ((DEBUG_INFO | DEBUG_LOAD, "Loading PEIM at 0x%11p EntryPoint=0x%11p ", (VOID *)(UINTN)ImageAddress, (VOID *)(UINTN)(*(UINT64 *)(UINTN)*EntryPoint)));
- }
-
- //
- // Print Module Name by PeImage PDB file name.
- //
- AsciiString = PeCoffLoaderGetPdbPointer (Pe32Data);
-
- if (AsciiString != NULL) {
- StartIndex = 0;
- for (Index = 0; AsciiString[Index] != 0; Index++) {
- if ((AsciiString[Index] == '\\') || (AsciiString[Index] == '/')) {
- StartIndex = Index + 1;
- }
- }
-
- //
- // Copy the PDB file name to our temporary string, and replace .pdb with .efi
- // The PDB file name is limited in the range of 0~511.
- // If the length is bigger than 511, trim the redundant characters to avoid overflow in array boundary.
- //
- for (Index = 0; Index < sizeof (EfiFileName) - 4; Index++) {
- EfiFileName[Index] = AsciiString[Index + StartIndex];
- if (EfiFileName[Index] == 0) {
- EfiFileName[Index] = '.';
- }
-
- if (EfiFileName[Index] == '.') {
- EfiFileName[Index + 1] = 'e';
- EfiFileName[Index + 2] = 'f';
- EfiFileName[Index + 3] = 'i';
- EfiFileName[Index + 4] = 0;
- break;
- }
- }
-
- if (Index == sizeof (EfiFileName) - 4) {
- EfiFileName[Index] = 0;
- }
-
- DEBUG ((DEBUG_INFO | DEBUG_LOAD, "%a", EfiFileName));
- }
-
- DEBUG_CODE_END ();
-
- DEBUG ((DEBUG_INFO | DEBUG_LOAD, "\n"));
-
- return EFI_SUCCESS;
-}
-
-/**
- The wrapper function of PeiLoadImageLoadImage().
-
- @param This - Pointer to EFI_PEI_LOAD_FILE_PPI.
- @param FileHandle - Pointer to the FFS file header of the image.
- @param ImageAddressArg - Pointer to PE/TE image.
- @param ImageSizeArg - Size of PE/TE image.
- @param EntryPoint - Pointer to entry point of specified image file for output.
- @param AuthenticationState - Pointer to attestation authentication state of image.
-
- @return Status of PeiLoadImageLoadImage().
-
-**/
-EFI_STATUS
-EFIAPI
-PeiLoadImageLoadImageWrapper (
- IN CONST EFI_PEI_LOAD_FILE_PPI *This,
- IN EFI_PEI_FILE_HANDLE FileHandle,
- OUT EFI_PHYSICAL_ADDRESS *ImageAddressArg OPTIONAL,
- OUT UINT64 *ImageSizeArg OPTIONAL,
- OUT EFI_PHYSICAL_ADDRESS *EntryPoint,
- OUT UINT32 *AuthenticationState
- )
-{
- return PeiLoadImageLoadImage (
- GetPeiServicesTablePointer (),
- FileHandle,
- ImageAddressArg,
- ImageSizeArg,
- EntryPoint,
- AuthenticationState
- );
-}
-
-/**
- Check whether the input image has the relocation.
-
- @param Pe32Data Pointer to the PE/COFF or TE image.
-
- @retval TRUE Relocation is stripped.
- @retval FALSE Relocation is not stripped.
-
-**/
-BOOLEAN
-RelocationIsStrip (
- IN VOID *Pe32Data
- )
-{
- EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;
- EFI_IMAGE_DOS_HEADER *DosHdr;
-
- ASSERT (Pe32Data != NULL);
-
- DosHdr = (EFI_IMAGE_DOS_HEADER *)Pe32Data;
- if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) {
- //
- // DOS image header is present, so read the PE header after the DOS image header.
- //
- Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINTN)Pe32Data + (UINTN)((DosHdr->e_lfanew) & 0x0ffff));
- } else {
- //
- // DOS image header is not present, so PE header is at the image base.
- //
- Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)Pe32Data;
- }
-
- //
- // Three cases with regards to relocations:
- // - Image has base relocs, RELOCS_STRIPPED==0 => image is relocatable
- // - Image has no base relocs, RELOCS_STRIPPED==1 => Image is not relocatable
- // - Image has no base relocs, RELOCS_STRIPPED==0 => Image is relocatable but
- // has no base relocs to apply
- // Obviously having base relocations with RELOCS_STRIPPED==1 is invalid.
- //
- // Look at the file header to determine if relocations have been stripped, and
- // save this info in the image context for later use.
- //
- if (Hdr.Te->Signature == EFI_TE_IMAGE_HEADER_SIGNATURE) {
- if ((Hdr.Te->DataDirectory[0].Size == 0) && (Hdr.Te->DataDirectory[0].VirtualAddress == 0)) {
- return TRUE;
- } else {
- return FALSE;
- }
- } else if (Hdr.Pe32->Signature == EFI_IMAGE_NT_SIGNATURE) {
- if ((Hdr.Pe32->FileHeader.Characteristics & EFI_IMAGE_FILE_RELOCS_STRIPPED) != 0) {
- return TRUE;
- } else {
- return FALSE;
- }
- }
-
- return FALSE;
-}
-
-/**
- Routine to load image file for subsequent execution by LoadFile Ppi.
- If any LoadFile Ppi is not found, the build-in support function for the PE32+/TE
- XIP image format is used.
-
- @param PeiServices - An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation
- @param FileHandle - Pointer to the FFS file header of the image.
- @param PeimState - The dispatch state of the input PEIM handle.
- @param EntryPoint - Pointer to entry point of specified image file for output.
- @param AuthenticationState - Pointer to attestation authentication state of image.
-
- @retval EFI_SUCCESS - Image is successfully loaded.
- @retval EFI_NOT_FOUND - Fail to locate necessary PPI
- @retval Others - Fail to load file.
-
-**/
-EFI_STATUS
-PeiLoadImage (
- IN CONST EFI_PEI_SERVICES **PeiServices,
- IN EFI_PEI_FILE_HANDLE FileHandle,
- IN UINT8 PeimState,
- OUT EFI_PHYSICAL_ADDRESS *EntryPoint,
- OUT UINT32 *AuthenticationState
- )
-{
- EFI_STATUS PpiStatus;
- EFI_STATUS Status;
- UINTN Index;
- EFI_PEI_LOAD_FILE_PPI *LoadFile;
- EFI_PHYSICAL_ADDRESS ImageAddress;
- UINT64 ImageSize;
- BOOLEAN IsStrip;
-
- IsStrip = FALSE;
- //
- // If any instances of PEI_LOAD_FILE_PPI are installed, they are called.
- // one at a time, until one reports EFI_SUCCESS.
- //
- Index = 0;
- do {
- PpiStatus = PeiServicesLocatePpi (
- &gEfiPeiLoadFilePpiGuid,
- Index,
- NULL,
- (VOID **)&LoadFile
- );
- if (!EFI_ERROR (PpiStatus)) {
- Status = LoadFile->LoadFile (
- LoadFile,
- FileHandle,
- &ImageAddress,
- &ImageSize,
- EntryPoint,
- AuthenticationState
- );
- if (!EFI_ERROR (Status) || (Status == EFI_WARN_BUFFER_TOO_SMALL)) {
- //
- // The shadowed PEIM must be relocatable.
- //
- if (PeimState == PEIM_STATE_REGISTER_FOR_SHADOW) {
- IsStrip = RelocationIsStrip ((VOID *)(UINTN)ImageAddress);
- ASSERT (!IsStrip);
- if (IsStrip) {
- return EFI_UNSUPPORTED;
- }
- }
-
- //
- // The image to be started must have the machine type supported by PeiCore.
- //
- ASSERT (EFI_IMAGE_MACHINE_TYPE_SUPPORTED (PeCoffLoaderGetMachineType ((VOID *)(UINTN)ImageAddress)));
- if (!EFI_IMAGE_MACHINE_TYPE_SUPPORTED (PeCoffLoaderGetMachineType ((VOID *)(UINTN)ImageAddress))) {
- return EFI_UNSUPPORTED;
- }
-
- return EFI_SUCCESS;
- }
- }
-
- Index++;
- } while (!EFI_ERROR (PpiStatus));
-
- return PpiStatus;
-}
-
-/**
-
- Install Pei Load File PPI.
-
-
- @param PrivateData - Pointer to PEI_CORE_INSTANCE.
- @param OldCoreData - Pointer to PEI_CORE_INSTANCE.
-
-**/
-VOID
-InitializeImageServices (
- IN PEI_CORE_INSTANCE *PrivateData,
- IN PEI_CORE_INSTANCE *OldCoreData
- )
-{
- if (OldCoreData == NULL) {
- //
- // The first time we are XIP (running from FLASH). We need to remember the
- // FLASH address so we can reinstall the memory version that runs faster
- //
- PrivateData->XipLoadFile = &gPpiLoadFilePpiList;
- PeiServicesInstallPpi (PrivateData->XipLoadFile);
- } else {
- //
- // 2nd time we are running from memory so replace the XIP version with the
- // new memory version.
- //
- PeiServicesReInstallPpi (PrivateData->XipLoadFile, &gPpiLoadFilePpiList);
- }
-}
+/** @file
+ Pei Core Load Image Support
+
+Copyright (c) 2006 - 2021, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "PeiMain.h"
+
+EFI_PEI_LOAD_FILE_PPI mPeiLoadImagePpi = {
+ PeiLoadImageLoadImageWrapper
+};
+
+EFI_PEI_PPI_DESCRIPTOR gPpiLoadFilePpiList = {
+ (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
+ &gEfiPeiLoadFilePpiGuid,
+ &mPeiLoadImagePpi
+};
+
+/**
+
+ Support routine for the PE/COFF Loader that reads a buffer from a PE/COFF file.
+ The function is used for XIP code to have optimized memory copy.
+
+ @param FileHandle - The handle to the PE/COFF file
+ @param FileOffset - The offset, in bytes, into the file to read
+ @param ReadSize - The number of bytes to read from the file starting at FileOffset
+ @param Buffer - A pointer to the buffer to read the data into.
+
+ @return EFI_SUCCESS - ReadSize bytes of data were read into Buffer from the PE/COFF file starting at FileOffset
+
+**/
+EFI_STATUS
+EFIAPI
+PeiImageRead (
+ IN VOID *FileHandle,
+ IN UINTN FileOffset,
+ IN UINTN *ReadSize,
+ OUT VOID *Buffer
+ )
+{
+ CHAR8 *Destination8;
+ CHAR8 *Source8;
+
+ Destination8 = Buffer;
+ Source8 = (CHAR8 *)((UINTN)FileHandle + FileOffset);
+ if (Destination8 != Source8) {
+ CopyMem (Destination8, Source8, *ReadSize);
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ To check memory usage bit map array to figure out if the memory range the image will be loaded in is available or not. If
+ memory range is available, the function will mark the corresponding bits to 1 which indicates the memory range is used.
+ The function is only invoked when load modules at fixed address feature is enabled.
+
+ @param Private Pointer to the private data passed in from caller
+ @param ImageBase The base address the image will be loaded at.
+ @param ImageSize The size of the image
+
+ @retval EFI_SUCCESS The memory range the image will be loaded in is available
+ @retval EFI_NOT_FOUND The memory range the image will be loaded in is not available
+**/
+EFI_STATUS
+CheckAndMarkFixLoadingMemoryUsageBitMap (
+ IN PEI_CORE_INSTANCE *Private,
+ IN EFI_PHYSICAL_ADDRESS ImageBase,
+ IN UINT32 ImageSize
+ )
+{
+ UINT32 DxeCodePageNumber;
+ UINT64 ReservedCodeSize;
+ EFI_PHYSICAL_ADDRESS PeiCodeBase;
+ UINT32 BaseOffsetPageNumber;
+ UINT32 TopOffsetPageNumber;
+ UINT32 Index;
+ UINT64 *MemoryUsageBitMap;
+
+ //
+ // The reserved code range includes RuntimeCodePage range, Boot time code range and PEI code range.
+ //
+ DxeCodePageNumber = PcdGet32 (PcdLoadFixAddressBootTimeCodePageNumber);
+ DxeCodePageNumber += PcdGet32 (PcdLoadFixAddressRuntimeCodePageNumber);
+ ReservedCodeSize = EFI_PAGES_TO_SIZE (DxeCodePageNumber + PcdGet32 (PcdLoadFixAddressPeiCodePageNumber));
+ PeiCodeBase = Private->LoadModuleAtFixAddressTopAddress - ReservedCodeSize;
+
+ //
+ // Test the memory range for loading the image in the PEI code range.
+ //
+ if (((Private->LoadModuleAtFixAddressTopAddress - EFI_PAGES_TO_SIZE (DxeCodePageNumber)) < (ImageBase + ImageSize)) ||
+ (PeiCodeBase > ImageBase))
+ {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Test if the memory is available or not.
+ //
+ MemoryUsageBitMap = Private->PeiCodeMemoryRangeUsageBitMap;
+ BaseOffsetPageNumber = EFI_SIZE_TO_PAGES ((UINT32)(ImageBase - PeiCodeBase));
+ TopOffsetPageNumber = EFI_SIZE_TO_PAGES ((UINT32)(ImageBase + ImageSize - PeiCodeBase));
+ for (Index = BaseOffsetPageNumber; Index < TopOffsetPageNumber; Index++) {
+ if ((MemoryUsageBitMap[Index / 64] & LShiftU64 (1, (Index % 64))) != 0) {
+ //
+ // This page is already used.
+ //
+ return EFI_NOT_FOUND;
+ }
+ }
+
+ //
+ // Being here means the memory range is available. So mark the bits for the memory range
+ //
+ for (Index = BaseOffsetPageNumber; Index < TopOffsetPageNumber; Index++) {
+ MemoryUsageBitMap[Index / 64] |= LShiftU64 (1, (Index % 64));
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+
+ Get the fixed loading address from image header assigned by build tool. This function only be called
+ when Loading module at Fixed address feature enabled.
+
+ @param ImageContext Pointer to the image context structure that describes the PE/COFF
+ image that needs to be examined by this function.
+ @param Private Pointer to the private data passed in from caller
+
+ @retval EFI_SUCCESS An fixed loading address is assigned to this image by build tools .
+ @retval EFI_NOT_FOUND The image has no assigned fixed loading address.
+
+**/
+EFI_STATUS
+GetPeCoffImageFixLoadingAssignedAddress (
+ IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext,
+ IN PEI_CORE_INSTANCE *Private
+ )
+{
+ UINTN SectionHeaderOffset;
+ EFI_STATUS Status;
+ EFI_IMAGE_SECTION_HEADER SectionHeader;
+ EFI_IMAGE_OPTIONAL_HEADER_UNION *ImgHdr;
+ EFI_PHYSICAL_ADDRESS FixLoadingAddress;
+ UINT16 Index;
+ UINTN Size;
+ UINT16 NumberOfSections;
+ UINT64 ValueInSectionHeader;
+
+ FixLoadingAddress = 0;
+ Status = EFI_NOT_FOUND;
+
+ //
+ // Get PeHeader pointer
+ //
+ ImgHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)((CHAR8 *)ImageContext->Handle + ImageContext->PeCoffHeaderOffset);
+ if (ImageContext->IsTeImage) {
+ //
+ // for TE image, the fix loading address is saved in first section header that doesn't point
+ // to code section.
+ //
+ SectionHeaderOffset = sizeof (EFI_TE_IMAGE_HEADER);
+ NumberOfSections = ImgHdr->Te.NumberOfSections;
+ } else {
+ SectionHeaderOffset = ImageContext->PeCoffHeaderOffset +
+ sizeof (UINT32) +
+ sizeof (EFI_IMAGE_FILE_HEADER) +
+ ImgHdr->Pe32.FileHeader.SizeOfOptionalHeader;
+ NumberOfSections = ImgHdr->Pe32.FileHeader.NumberOfSections;
+ }
+
+ //
+ // Get base address from the first section header that doesn't point to code section.
+ //
+ for (Index = 0; Index < NumberOfSections; Index++) {
+ //
+ // Read section header from file
+ //
+ Size = sizeof (EFI_IMAGE_SECTION_HEADER);
+ Status = ImageContext->ImageRead (
+ ImageContext->Handle,
+ SectionHeaderOffset,
+ &Size,
+ &SectionHeader
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = EFI_NOT_FOUND;
+
+ if ((SectionHeader.Characteristics & EFI_IMAGE_SCN_CNT_CODE) == 0) {
+ //
+ // Build tool will save the address in PointerToRelocations & PointerToLineNumbers fields in the first section header
+ // that doesn't point to code section in image header, as well as ImageBase field of image header. A notable thing is
+ // that for PEIM, the value in ImageBase field may not be equal to the value in PointerToRelocations & PointerToLineNumbers because
+ // for XIP PEIM, ImageBase field holds the image base address running on the Flash. And PointerToRelocations & PointerToLineNumbers
+ // hold the image base address when it is shadow to the memory. And there is an assumption that when the feature is enabled, if a
+ // module is assigned a loading address by tools, PointerToRelocations & PointerToLineNumbers fields should NOT be Zero, or
+ // else, these 2 fields should be set to Zero
+ //
+ ValueInSectionHeader = ReadUnaligned64 ((UINT64 *)&SectionHeader.PointerToRelocations);
+ if (ValueInSectionHeader != 0) {
+ //
+ // Found first section header that doesn't point to code section.
+ //
+ if ((INT64)PcdGet64 (PcdLoadModuleAtFixAddressEnable) > 0) {
+ //
+ // When LMFA feature is configured as Load Module at Fixed Absolute Address mode, PointerToRelocations & PointerToLineNumbers field
+ // hold the absolute address of image base running in memory
+ //
+ FixLoadingAddress = ValueInSectionHeader;
+ } else {
+ //
+ // When LMFA feature is configured as Load Module at Fixed offset mode, PointerToRelocations & PointerToLineNumbers field
+ // hold the offset relative to a platform-specific top address.
+ //
+ FixLoadingAddress = (EFI_PHYSICAL_ADDRESS)(Private->LoadModuleAtFixAddressTopAddress + (INT64)ValueInSectionHeader);
+ }
+
+ //
+ // Check if the memory range is available.
+ //
+ Status = CheckAndMarkFixLoadingMemoryUsageBitMap (Private, FixLoadingAddress, (UINT32)ImageContext->ImageSize);
+ if (!EFI_ERROR (Status)) {
+ //
+ // The assigned address is valid. Return the specified loading address
+ //
+ ImageContext->ImageAddress = FixLoadingAddress;
+ }
+ }
+
+ break;
+ }
+
+ SectionHeaderOffset += sizeof (EFI_IMAGE_SECTION_HEADER);
+ }
+
+ DEBUG ((DEBUG_INFO|DEBUG_LOAD, "LOADING MODULE FIXED INFO: Loading module at fixed address 0x%11p. Status= %r \n", (VOID *)(UINTN)FixLoadingAddress, Status));
+ return Status;
+}
+
+/**
+
+ Loads and relocates a PE/COFF image into memory.
+ If the image is not relocatable, it will not be loaded into memory and be loaded as XIP image.
+
+ @param FileHandle - Pointer to the FFS file header of the image.
+ @param Pe32Data - The base address of the PE/COFF file that is to be loaded and relocated
+ @param ImageAddress - The base address of the relocated PE/COFF image
+ @param ImageSize - The size of the relocated PE/COFF image
+ @param EntryPoint - The entry point of the relocated PE/COFF image
+
+ @retval EFI_SUCCESS The file was loaded and relocated
+ @retval EFI_OUT_OF_RESOURCES There was not enough memory to load and relocate the PE/COFF file
+ @retval EFI_WARN_BUFFER_TOO_SMALL
+ There is not enough heap to allocate the requested size.
+ This will not prevent the XIP image from being invoked.
+
+**/
+EFI_STATUS
+LoadAndRelocatePeCoffImage (
+ IN EFI_PEI_FILE_HANDLE FileHandle,
+ IN VOID *Pe32Data,
+ OUT EFI_PHYSICAL_ADDRESS *ImageAddress,
+ OUT UINT64 *ImageSize,
+ OUT EFI_PHYSICAL_ADDRESS *EntryPoint
+ )
+{
+ EFI_STATUS Status;
+ PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;
+ PEI_CORE_INSTANCE *Private;
+ UINT64 AlignImageSize;
+ BOOLEAN IsXipImage;
+ EFI_STATUS ReturnStatus;
+ BOOLEAN IsS3Boot;
+ BOOLEAN IsPeiModule;
+ BOOLEAN IsRegisterForShadow;
+ EFI_FV_FILE_INFO FileInfo;
+
+ Private = PEI_CORE_INSTANCE_FROM_PS_THIS (GetPeiServicesTablePointer ());
+
+ ReturnStatus = EFI_SUCCESS;
+ IsXipImage = FALSE;
+ ZeroMem (&ImageContext, sizeof (ImageContext));
+ ImageContext.Handle = Pe32Data;
+ ImageContext.ImageRead = PeiImageRead;
+
+ Status = PeCoffLoaderGetImageInfo (&ImageContext);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Initialize local IsS3Boot and IsRegisterForShadow variable
+ //
+ IsS3Boot = FALSE;
+ if (Private->HobList.HandoffInformationTable->BootMode == BOOT_ON_S3_RESUME) {
+ IsS3Boot = TRUE;
+ }
+
+ IsRegisterForShadow = FALSE;
+ if ( (Private->CurrentFileHandle == FileHandle)
+ && (Private->Fv[Private->CurrentPeimFvCount].PeimState[Private->CurrentPeimCount] == PEIM_STATE_REGISTER_FOR_SHADOW))
+ {
+ IsRegisterForShadow = TRUE;
+ }
+
+ //
+ // XIP image that ImageAddress is same to Image handle.
+ //
+ if (ImageContext.ImageAddress == (EFI_PHYSICAL_ADDRESS)(UINTN)Pe32Data) {
+ IsXipImage = TRUE;
+ }
+
+ //
+ // Get file type first
+ //
+ Status = PeiServicesFfsGetFileInfo (FileHandle, &FileInfo);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Check whether the file type is PEI module.
+ //
+ IsPeiModule = FALSE;
+ if ((FileInfo.FileType == EFI_FV_FILETYPE_PEI_CORE) ||
+ (FileInfo.FileType == EFI_FV_FILETYPE_PEIM) ||
+ (FileInfo.FileType == EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER))
+ {
+ IsPeiModule = TRUE;
+ }
+
+ //
+ // When Image has no reloc section, it can't be relocated into memory.
+ //
+ if (ImageContext.RelocationsStripped && (Private->PeiMemoryInstalled) &&
+ ((!IsPeiModule) || PcdGetBool (PcdMigrateTemporaryRamFirmwareVolumes) ||
+ (!IsS3Boot && (PcdGetBool (PcdShadowPeimOnBoot) || IsRegisterForShadow)) ||
+ (IsS3Boot && PcdGetBool (PcdShadowPeimOnS3Boot)))
+ )
+ {
+ DEBUG ((DEBUG_INFO|DEBUG_LOAD, "The image at 0x%08x without reloc section can't be loaded into memory\n", (UINTN)Pe32Data));
+ }
+
+ //
+ // Set default base address to current image address.
+ //
+ ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)Pe32Data;
+
+ //
+ // Allocate Memory for the image when memory is ready, and image is relocatable.
+ // On normal boot, PcdShadowPeimOnBoot decides whether load PEIM or PeiCore into memory.
+ // On S3 boot, PcdShadowPeimOnS3Boot decides whether load PEIM or PeiCore into memory.
+ //
+ if ((!ImageContext.RelocationsStripped) && (Private->PeiMemoryInstalled) &&
+ ((!IsPeiModule) || PcdGetBool (PcdMigrateTemporaryRamFirmwareVolumes) ||
+ (!IsS3Boot && (PcdGetBool (PcdShadowPeimOnBoot) || IsRegisterForShadow)) ||
+ (IsS3Boot && PcdGetBool (PcdShadowPeimOnS3Boot)))
+ )
+ {
+ //
+ // Allocate more buffer to avoid buffer overflow.
+ //
+ if (ImageContext.IsTeImage) {
+ AlignImageSize = ImageContext.ImageSize + ((EFI_TE_IMAGE_HEADER *)Pe32Data)->StrippedSize - sizeof (EFI_TE_IMAGE_HEADER);
+ } else {
+ AlignImageSize = ImageContext.ImageSize;
+ }
+
+ if (ImageContext.SectionAlignment > EFI_PAGE_SIZE) {
+ AlignImageSize += ImageContext.SectionAlignment;
+ }
+
+ if ((PcdGet64 (PcdLoadModuleAtFixAddressEnable) != 0) && (Private->HobList.HandoffInformationTable->BootMode != BOOT_ON_S3_RESUME)) {
+ Status = GetPeCoffImageFixLoadingAssignedAddress (&ImageContext, Private);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_INFO|DEBUG_LOAD, "LOADING MODULE FIXED ERROR: Failed to load module at fixed address. \n"));
+ //
+ // The PEIM is not assigned valid address, try to allocate page to load it.
+ //
+ Status = PeiServicesAllocatePages (
+ EfiBootServicesCode,
+ EFI_SIZE_TO_PAGES ((UINT32)AlignImageSize),
+ &ImageContext.ImageAddress
+ );
+ }
+ } else {
+ Status = PeiServicesAllocatePages (
+ EfiBootServicesCode,
+ EFI_SIZE_TO_PAGES ((UINT32)AlignImageSize),
+ &ImageContext.ImageAddress
+ );
+ }
+
+ if (!EFI_ERROR (Status)) {
+ //
+ // Adjust the Image Address to make sure it is section alignment.
+ //
+ if (ImageContext.SectionAlignment > EFI_PAGE_SIZE) {
+ ImageContext.ImageAddress =
+ (ImageContext.ImageAddress + ImageContext.SectionAlignment - 1) &
+ ~((UINTN)ImageContext.SectionAlignment - 1);
+ }
+
+ //
+ // Fix alignment requirement when Load IPF TeImage into memory.
+ // Skip the reserved space for the stripped PeHeader when load TeImage into memory.
+ //
+ if (ImageContext.IsTeImage) {
+ ImageContext.ImageAddress = ImageContext.ImageAddress +
+ ((EFI_TE_IMAGE_HEADER *)Pe32Data)->StrippedSize -
+ sizeof (EFI_TE_IMAGE_HEADER);
+ }
+ } else {
+ //
+ // No enough memory resource.
+ //
+ if (IsXipImage) {
+ //
+ // XIP image can still be invoked.
+ //
+ ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)Pe32Data;
+ ReturnStatus = EFI_WARN_BUFFER_TOO_SMALL;
+ } else {
+ //
+ // Non XIP image can't be loaded because no enough memory is allocated.
+ //
+ ASSERT (FALSE);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ }
+ }
+
+ //
+ // Load the image to our new buffer
+ //
+ Status = PeCoffLoaderLoadImage (&ImageContext);
+ if (EFI_ERROR (Status)) {
+ if (ImageContext.ImageError == IMAGE_ERROR_INVALID_SECTION_ALIGNMENT) {
+ DEBUG ((DEBUG_ERROR, "PEIM Image Address 0x%11p doesn't meet with section alignment 0x%x.\n", (VOID *)(UINTN)ImageContext.ImageAddress, ImageContext.SectionAlignment));
+ }
+
+ return Status;
+ }
+
+ //
+ // Relocate the image in our new buffer
+ //
+ Status = PeCoffLoaderRelocateImage (&ImageContext);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Flush the instruction cache so the image data is written before we execute it
+ //
+ if (ImageContext.ImageAddress != (EFI_PHYSICAL_ADDRESS)(UINTN)Pe32Data) {
+ InvalidateInstructionCacheRange ((VOID *)(UINTN)ImageContext.ImageAddress, (UINTN)ImageContext.ImageSize);
+ }
+
+ *ImageAddress = ImageContext.ImageAddress;
+ *ImageSize = ImageContext.ImageSize;
+ *EntryPoint = ImageContext.EntryPoint;
+
+ return ReturnStatus;
+}
+
+/**
+ Loads and relocates a PE/COFF image in place.
+
+ @param Pe32Data The base address of the PE/COFF file that is to be loaded and relocated
+ @param ImageAddress The base address of the relocated PE/COFF image
+
+ @retval EFI_SUCCESS The file was loaded and relocated.
+ @retval Others The file not be loaded and error occurred.
+
+**/
+EFI_STATUS
+LoadAndRelocatePeCoffImageInPlace (
+ IN VOID *Pe32Data,
+ IN VOID *ImageAddress
+ )
+{
+ EFI_STATUS Status;
+ PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;
+
+ ZeroMem (&ImageContext, sizeof (ImageContext));
+ ImageContext.Handle = Pe32Data;
+ ImageContext.ImageRead = PeiImageRead;
+
+ Status = PeCoffLoaderGetImageInfo (&ImageContext);
+ if (EFI_ERROR (Status)) {
+ ASSERT_EFI_ERROR (Status);
+ return Status;
+ }
+
+ ImageContext.ImageAddress = (PHYSICAL_ADDRESS)(UINTN)ImageAddress;
+
+ //
+ // Load the image in place
+ //
+ Status = PeCoffLoaderLoadImage (&ImageContext);
+ if (EFI_ERROR (Status)) {
+ ASSERT_EFI_ERROR (Status);
+ return Status;
+ }
+
+ //
+ // Relocate the image in place
+ //
+ Status = PeCoffLoaderRelocateImage (&ImageContext);
+ if (EFI_ERROR (Status)) {
+ ASSERT_EFI_ERROR (Status);
+ return Status;
+ }
+
+ //
+ // Flush the instruction cache so the image data is written before we execute it
+ //
+ if (ImageContext.ImageAddress != (EFI_PHYSICAL_ADDRESS)(UINTN)Pe32Data) {
+ InvalidateInstructionCacheRange ((VOID *)(UINTN)ImageContext.ImageAddress, (UINTN)ImageContext.ImageSize);
+ }
+
+ return Status;
+}
+
+/**
+ Find the PE32 Data for an FFS file.
+
+ @param FileHandle Pointer to the FFS file header of the image.
+ @param Pe32Data Pointer to a (VOID *) PE32 Data pointer.
+
+ @retval EFI_SUCCESS Image is successfully loaded.
+ @retval EFI_NOT_FOUND Fail to locate PE32 Data.
+
+**/
+EFI_STATUS
+PeiGetPe32Data (
+ IN EFI_PEI_FILE_HANDLE FileHandle,
+ OUT VOID **Pe32Data
+ )
+{
+ EFI_STATUS Status;
+ EFI_SECTION_TYPE SearchType1;
+ EFI_SECTION_TYPE SearchType2;
+ UINT32 AuthenticationState;
+
+ *Pe32Data = NULL;
+
+ if (FeaturePcdGet (PcdPeiCoreImageLoaderSearchTeSectionFirst)) {
+ SearchType1 = EFI_SECTION_TE;
+ SearchType2 = EFI_SECTION_PE32;
+ } else {
+ SearchType1 = EFI_SECTION_PE32;
+ SearchType2 = EFI_SECTION_TE;
+ }
+
+ //
+ // Try to find a first exe section (if PcdPeiCoreImageLoaderSearchTeSectionFirst
+ // is true, TE will be searched first).
+ //
+ Status = PeiServicesFfsFindSectionData3 (
+ SearchType1,
+ 0,
+ FileHandle,
+ Pe32Data,
+ &AuthenticationState
+ );
+ //
+ // If we didn't find a first exe section, try to find the second exe section.
+ //
+ if (EFI_ERROR (Status)) {
+ Status = PeiServicesFfsFindSectionData3 (
+ SearchType2,
+ 0,
+ FileHandle,
+ Pe32Data,
+ &AuthenticationState
+ );
+ }
+
+ return Status;
+}
+
+/**
+ Loads a PEIM into memory for subsequent execution. If there are compressed
+ images or images that need to be relocated into memory for performance reasons,
+ this service performs that transformation.
+
+ @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation
+ @param FileHandle Pointer to the FFS file header of the image.
+ @param ImageAddressArg Pointer to PE/TE image.
+ @param ImageSizeArg Size of PE/TE image.
+ @param EntryPoint Pointer to entry point of specified image file for output.
+ @param AuthenticationState - Pointer to attestation authentication state of image.
+
+ @retval EFI_SUCCESS Image is successfully loaded.
+ @retval EFI_NOT_FOUND Fail to locate necessary PPI.
+ @retval EFI_UNSUPPORTED Image Machine Type is not supported.
+ @retval EFI_WARN_BUFFER_TOO_SMALL
+ There is not enough heap to allocate the requested size.
+ This will not prevent the XIP image from being invoked.
+
+**/
+EFI_STATUS
+PeiLoadImageLoadImage (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_FILE_HANDLE FileHandle,
+ OUT EFI_PHYSICAL_ADDRESS *ImageAddressArg OPTIONAL,
+ OUT UINT64 *ImageSizeArg OPTIONAL,
+ OUT EFI_PHYSICAL_ADDRESS *EntryPoint,
+ OUT UINT32 *AuthenticationState
+ )
+{
+ EFI_STATUS Status;
+ VOID *Pe32Data;
+ EFI_PHYSICAL_ADDRESS ImageAddress;
+ UINT64 ImageSize;
+ EFI_PHYSICAL_ADDRESS ImageEntryPoint;
+ UINT16 Machine;
+ EFI_SECTION_TYPE SearchType1;
+ EFI_SECTION_TYPE SearchType2;
+
+ *EntryPoint = 0;
+ ImageSize = 0;
+ *AuthenticationState = 0;
+
+ if (FeaturePcdGet (PcdPeiCoreImageLoaderSearchTeSectionFirst)) {
+ SearchType1 = EFI_SECTION_TE;
+ SearchType2 = EFI_SECTION_PE32;
+ } else {
+ SearchType1 = EFI_SECTION_PE32;
+ SearchType2 = EFI_SECTION_TE;
+ }
+
+ //
+ // Try to find a first exe section (if PcdPeiCoreImageLoaderSearchTeSectionFirst
+ // is true, TE will be searched first).
+ //
+ Status = PeiServicesFfsFindSectionData3 (
+ SearchType1,
+ 0,
+ FileHandle,
+ &Pe32Data,
+ AuthenticationState
+ );
+ //
+ // If we didn't find a first exe section, try to find the second exe section.
+ //
+ if (EFI_ERROR (Status)) {
+ Status = PeiServicesFfsFindSectionData3 (
+ SearchType2,
+ 0,
+ FileHandle,
+ &Pe32Data,
+ AuthenticationState
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // PEI core only carry the loader function for TE and PE32 executables
+ // If this two section does not exist, just return.
+ //
+ return Status;
+ }
+ }
+
+ DEBUG ((DEBUG_INFO, "Loading PEIM %g\n", FileHandle));
+
+ //
+ // If memory is installed, perform the shadow operations
+ //
+ Status = LoadAndRelocatePeCoffImage (
+ FileHandle,
+ Pe32Data,
+ &ImageAddress,
+ &ImageSize,
+ &ImageEntryPoint
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Got the entry point from the loaded Pe32Data
+ //
+ Pe32Data = (VOID *)((UINTN)ImageAddress);
+ *EntryPoint = ImageEntryPoint;
+
+ Machine = PeCoffLoaderGetMachineType (Pe32Data);
+
+ if (!EFI_IMAGE_MACHINE_TYPE_SUPPORTED (Machine)) {
+ if (!EFI_IMAGE_MACHINE_CROSS_TYPE_SUPPORTED (Machine)) {
+ return EFI_UNSUPPORTED;
+ }
+ }
+
+ if (ImageAddressArg != NULL) {
+ *ImageAddressArg = ImageAddress;
+ }
+
+ if (ImageSizeArg != NULL) {
+ *ImageSizeArg = ImageSize;
+ }
+
+ DEBUG_CODE_BEGIN ();
+ CHAR8 *AsciiString;
+ CHAR8 EfiFileName[512];
+ INT32 Index;
+ INT32 StartIndex;
+
+ //
+ // Print debug message: Loading PEIM at 0x12345678 EntryPoint=0x12345688 Driver.efi
+ //
+ if (Machine != EFI_IMAGE_MACHINE_IA64) {
+ DEBUG ((DEBUG_INFO | DEBUG_LOAD, "Loading PEIM at 0x%11p EntryPoint=0x%11p ", (VOID *)(UINTN)ImageAddress, (VOID *)(UINTN)*EntryPoint));
+ } else {
+ //
+ // For IPF Image, the real entry point should be print.
+ //
+ DEBUG ((DEBUG_INFO | DEBUG_LOAD, "Loading PEIM at 0x%11p EntryPoint=0x%11p ", (VOID *)(UINTN)ImageAddress, (VOID *)(UINTN)(*(UINT64 *)(UINTN)*EntryPoint)));
+ }
+
+ //
+ // Print Module Name by PeImage PDB file name.
+ //
+ AsciiString = PeCoffLoaderGetPdbPointer (Pe32Data);
+
+ if (AsciiString != NULL) {
+ StartIndex = 0;
+ for (Index = 0; AsciiString[Index] != 0; Index++) {
+ if ((AsciiString[Index] == '\\') || (AsciiString[Index] == '/')) {
+ StartIndex = Index + 1;
+ }
+ }
+
+ //
+ // Copy the PDB file name to our temporary string, and replace .pdb with .efi
+ // The PDB file name is limited in the range of 0~511.
+ // If the length is bigger than 511, trim the redundant characters to avoid overflow in array boundary.
+ //
+ for (Index = 0; Index < sizeof (EfiFileName) - 4; Index++) {
+ EfiFileName[Index] = AsciiString[Index + StartIndex];
+ if (EfiFileName[Index] == 0) {
+ EfiFileName[Index] = '.';
+ }
+
+ if (EfiFileName[Index] == '.') {
+ EfiFileName[Index + 1] = 'e';
+ EfiFileName[Index + 2] = 'f';
+ EfiFileName[Index + 3] = 'i';
+ EfiFileName[Index + 4] = 0;
+ break;
+ }
+ }
+
+ if (Index == sizeof (EfiFileName) - 4) {
+ EfiFileName[Index] = 0;
+ }
+
+ DEBUG ((DEBUG_INFO | DEBUG_LOAD, "%a", EfiFileName));
+ }
+
+ DEBUG_CODE_END ();
+
+ DEBUG ((DEBUG_INFO | DEBUG_LOAD, "\n"));
+
+ return EFI_SUCCESS;
+}
+
+/**
+ The wrapper function of PeiLoadImageLoadImage().
+
+ @param This - Pointer to EFI_PEI_LOAD_FILE_PPI.
+ @param FileHandle - Pointer to the FFS file header of the image.
+ @param ImageAddressArg - Pointer to PE/TE image.
+ @param ImageSizeArg - Size of PE/TE image.
+ @param EntryPoint - Pointer to entry point of specified image file for output.
+ @param AuthenticationState - Pointer to attestation authentication state of image.
+
+ @return Status of PeiLoadImageLoadImage().
+
+**/
+EFI_STATUS
+EFIAPI
+PeiLoadImageLoadImageWrapper (
+ IN CONST EFI_PEI_LOAD_FILE_PPI *This,
+ IN EFI_PEI_FILE_HANDLE FileHandle,
+ OUT EFI_PHYSICAL_ADDRESS *ImageAddressArg OPTIONAL,
+ OUT UINT64 *ImageSizeArg OPTIONAL,
+ OUT EFI_PHYSICAL_ADDRESS *EntryPoint,
+ OUT UINT32 *AuthenticationState
+ )
+{
+ return PeiLoadImageLoadImage (
+ GetPeiServicesTablePointer (),
+ FileHandle,
+ ImageAddressArg,
+ ImageSizeArg,
+ EntryPoint,
+ AuthenticationState
+ );
+}
+
+/**
+ Check whether the input image has the relocation.
+
+ @param Pe32Data Pointer to the PE/COFF or TE image.
+
+ @retval TRUE Relocation is stripped.
+ @retval FALSE Relocation is not stripped.
+
+**/
+BOOLEAN
+RelocationIsStrip (
+ IN VOID *Pe32Data
+ )
+{
+ EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;
+ EFI_IMAGE_DOS_HEADER *DosHdr;
+
+ ASSERT (Pe32Data != NULL);
+
+ DosHdr = (EFI_IMAGE_DOS_HEADER *)Pe32Data;
+ if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) {
+ //
+ // DOS image header is present, so read the PE header after the DOS image header.
+ //
+ Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINTN)Pe32Data + (UINTN)((DosHdr->e_lfanew) & 0x0ffff));
+ } else {
+ //
+ // DOS image header is not present, so PE header is at the image base.
+ //
+ Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)Pe32Data;
+ }
+
+ //
+ // Three cases with regards to relocations:
+ // - Image has base relocs, RELOCS_STRIPPED==0 => image is relocatable
+ // - Image has no base relocs, RELOCS_STRIPPED==1 => Image is not relocatable
+ // - Image has no base relocs, RELOCS_STRIPPED==0 => Image is relocatable but
+ // has no base relocs to apply
+ // Obviously having base relocations with RELOCS_STRIPPED==1 is invalid.
+ //
+ // Look at the file header to determine if relocations have been stripped, and
+ // save this info in the image context for later use.
+ //
+ if (Hdr.Te->Signature == EFI_TE_IMAGE_HEADER_SIGNATURE) {
+ if ((Hdr.Te->DataDirectory[0].Size == 0) && (Hdr.Te->DataDirectory[0].VirtualAddress == 0)) {
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+ } else if (Hdr.Pe32->Signature == EFI_IMAGE_NT_SIGNATURE) {
+ if ((Hdr.Pe32->FileHeader.Characteristics & EFI_IMAGE_FILE_RELOCS_STRIPPED) != 0) {
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+ }
+
+ return FALSE;
+}
+
+/**
+ Routine to load image file for subsequent execution by LoadFile Ppi.
+ If any LoadFile Ppi is not found, the build-in support function for the PE32+/TE
+ XIP image format is used.
+
+ @param PeiServices - An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation
+ @param FileHandle - Pointer to the FFS file header of the image.
+ @param PeimState - The dispatch state of the input PEIM handle.
+ @param EntryPoint - Pointer to entry point of specified image file for output.
+ @param AuthenticationState - Pointer to attestation authentication state of image.
+
+ @retval EFI_SUCCESS - Image is successfully loaded.
+ @retval EFI_NOT_FOUND - Fail to locate necessary PPI
+ @retval Others - Fail to load file.
+
+**/
+EFI_STATUS
+PeiLoadImage (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_FILE_HANDLE FileHandle,
+ IN UINT8 PeimState,
+ OUT EFI_PHYSICAL_ADDRESS *EntryPoint,
+ OUT UINT32 *AuthenticationState
+ )
+{
+ EFI_STATUS PpiStatus;
+ EFI_STATUS Status;
+ UINTN Index;
+ EFI_PEI_LOAD_FILE_PPI *LoadFile;
+ EFI_PHYSICAL_ADDRESS ImageAddress;
+ UINT64 ImageSize;
+ BOOLEAN IsStrip;
+
+ IsStrip = FALSE;
+ //
+ // If any instances of PEI_LOAD_FILE_PPI are installed, they are called.
+ // one at a time, until one reports EFI_SUCCESS.
+ //
+ Index = 0;
+ do {
+ PpiStatus = PeiServicesLocatePpi (
+ &gEfiPeiLoadFilePpiGuid,
+ Index,
+ NULL,
+ (VOID **)&LoadFile
+ );
+ if (!EFI_ERROR (PpiStatus)) {
+ Status = LoadFile->LoadFile (
+ LoadFile,
+ FileHandle,
+ &ImageAddress,
+ &ImageSize,
+ EntryPoint,
+ AuthenticationState
+ );
+ if (!EFI_ERROR (Status) || (Status == EFI_WARN_BUFFER_TOO_SMALL)) {
+ //
+ // The shadowed PEIM must be relocatable.
+ //
+ if (PeimState == PEIM_STATE_REGISTER_FOR_SHADOW) {
+ IsStrip = RelocationIsStrip ((VOID *)(UINTN)ImageAddress);
+ ASSERT (!IsStrip);
+ if (IsStrip) {
+ return EFI_UNSUPPORTED;
+ }
+ }
+
+ //
+ // The image to be started must have the machine type supported by PeiCore.
+ //
+ ASSERT (EFI_IMAGE_MACHINE_TYPE_SUPPORTED (PeCoffLoaderGetMachineType ((VOID *)(UINTN)ImageAddress)));
+ if (!EFI_IMAGE_MACHINE_TYPE_SUPPORTED (PeCoffLoaderGetMachineType ((VOID *)(UINTN)ImageAddress))) {
+ return EFI_UNSUPPORTED;
+ }
+
+ return EFI_SUCCESS;
+ }
+ }
+
+ Index++;
+ } while (!EFI_ERROR (PpiStatus));
+
+ return PpiStatus;
+}
+
+/**
+
+ Install Pei Load File PPI.
+
+
+ @param PrivateData - Pointer to PEI_CORE_INSTANCE.
+ @param OldCoreData - Pointer to PEI_CORE_INSTANCE.
+
+**/
+VOID
+InitializeImageServices (
+ IN PEI_CORE_INSTANCE *PrivateData,
+ IN PEI_CORE_INSTANCE *OldCoreData
+ )
+{
+ if (OldCoreData == NULL) {
+ //
+ // The first time we are XIP (running from FLASH). We need to remember the
+ // FLASH address so we can reinstall the memory version that runs faster
+ //
+ PrivateData->XipLoadFile = &gPpiLoadFilePpiList;
+ PeiServicesInstallPpi (PrivateData->XipLoadFile);
+ } else {
+ //
+ // 2nd time we are running from memory so replace the XIP version with the
+ // new memory version.
+ //
+ PeiServicesReInstallPpi (PrivateData->XipLoadFile, &gPpiLoadFilePpiList);
+ }
+}