Home | History | Annotate | Download | only in Image
      1 /** @file
      2   Pei Core Load Image Support
      3 
      4 Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>
      5 This program and the accompanying materials
      6 are licensed and made available under the terms and conditions of the BSD License
      7 which accompanies this distribution.  The full text of the license may be found at
      8 http://opensource.org/licenses/bsd-license.php
      9 
     10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     12 
     13 **/
     14 
     15 #include "PeiMain.h"
     16 
     17 
     18 EFI_PEI_LOAD_FILE_PPI   mPeiLoadImagePpi = {
     19   PeiLoadImageLoadImageWrapper
     20 };
     21 
     22 
     23 EFI_PEI_PPI_DESCRIPTOR     gPpiLoadFilePpiList = {
     24   (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
     25   &gEfiPeiLoadFilePpiGuid,
     26   &mPeiLoadImagePpi
     27 };
     28 
     29 /**
     30 
     31   Support routine for the PE/COFF Loader that reads a buffer from a PE/COFF file.
     32   The function is used for XIP code to have optimized memory copy.
     33 
     34   @param FileHandle      - The handle to the PE/COFF file
     35   @param FileOffset      - The offset, in bytes, into the file to read
     36   @param ReadSize        - The number of bytes to read from the file starting at FileOffset
     37   @param Buffer          - A pointer to the buffer to read the data into.
     38 
     39   @return EFI_SUCCESS - ReadSize bytes of data were read into Buffer from the PE/COFF file starting at FileOffset
     40 
     41 **/
     42 EFI_STATUS
     43 EFIAPI
     44 PeiImageRead (
     45   IN     VOID    *FileHandle,
     46   IN     UINTN   FileOffset,
     47   IN     UINTN   *ReadSize,
     48   OUT    VOID    *Buffer
     49   )
     50 {
     51   CHAR8 *Destination8;
     52   CHAR8 *Source8;
     53 
     54   Destination8  = Buffer;
     55   Source8       = (CHAR8 *) ((UINTN) FileHandle + FileOffset);
     56   if (Destination8 != Source8) {
     57     CopyMem (Destination8, Source8, *ReadSize);
     58   }
     59 
     60   return EFI_SUCCESS;
     61 }
     62 
     63 /**
     64 
     65   Support routine for the PE/COFF Loader that reads a buffer from a PE/COFF file.
     66   The function is implemented as PIC so as to support shadowing.
     67 
     68   @param FileHandle      - The handle to the PE/COFF file
     69   @param FileOffset      - The offset, in bytes, into the file to read
     70   @param ReadSize        - The number of bytes to read from the file starting at FileOffset
     71   @param Buffer          - A pointer to the buffer to read the data into.
     72 
     73   @return EFI_SUCCESS - ReadSize bytes of data were read into Buffer from the PE/COFF file starting at FileOffset
     74 
     75 **/
     76 EFI_STATUS
     77 EFIAPI
     78 PeiImageReadForShadow (
     79   IN     VOID    *FileHandle,
     80   IN     UINTN   FileOffset,
     81   IN     UINTN   *ReadSize,
     82   OUT    VOID    *Buffer
     83   )
     84 {
     85   volatile CHAR8  *Destination8;
     86   CHAR8           *Source8;
     87   UINTN           Length;
     88 
     89   Destination8  = Buffer;
     90   Source8       = (CHAR8 *) ((UINTN) FileHandle + FileOffset);
     91   if (Destination8 != Source8) {
     92     Length        = *ReadSize;
     93     while ((Length--) > 0) {
     94       *(Destination8++) = *(Source8++);
     95     }
     96   }
     97 
     98   return EFI_SUCCESS;
     99 }
    100 
    101 /**
    102 
    103   Support routine to get the Image read file function.
    104 
    105   @param ImageContext    - The context of the image being loaded
    106 
    107   @retval EFI_SUCCESS - If Image function location is found
    108 
    109 **/
    110 EFI_STATUS
    111 GetImageReadFunction (
    112   IN      PE_COFF_LOADER_IMAGE_CONTEXT  *ImageContext
    113   )
    114 {
    115   PEI_CORE_INSTANCE  *Private;
    116   VOID*  MemoryBuffer;
    117 
    118   Private = PEI_CORE_INSTANCE_FROM_PS_THIS (GetPeiServicesTablePointer ());
    119 
    120   if (Private->PeiMemoryInstalled  && (((Private->HobList.HandoffInformationTable->BootMode != BOOT_ON_S3_RESUME) && PcdGetBool (PcdShadowPeimOnBoot)) ||
    121       ((Private->HobList.HandoffInformationTable->BootMode == BOOT_ON_S3_RESUME) && PcdGetBool (PcdShadowPeimOnS3Boot))) &&
    122       (EFI_IMAGE_MACHINE_TYPE_SUPPORTED(EFI_IMAGE_MACHINE_X64) || EFI_IMAGE_MACHINE_TYPE_SUPPORTED(EFI_IMAGE_MACHINE_IA32))) {
    123     //
    124     // Shadow algorithm makes lots of non ANSI C assumptions and only works for IA32 and X64
    125     //  compilers that have been tested
    126     //
    127     if (Private->ShadowedImageRead == NULL) {
    128       MemoryBuffer = AllocatePages (0x400 / EFI_PAGE_SIZE + 1);
    129       ASSERT (MemoryBuffer != NULL);
    130       CopyMem (MemoryBuffer, (CONST VOID *) (UINTN) PeiImageReadForShadow, 0x400);
    131       Private->ShadowedImageRead = (PE_COFF_LOADER_READ_FILE) (UINTN) MemoryBuffer;
    132     }
    133 
    134     ImageContext->ImageRead = Private->ShadowedImageRead;
    135   } else {
    136     ImageContext->ImageRead = PeiImageRead;
    137   }
    138 
    139   return EFI_SUCCESS;
    140 }
    141 /**
    142   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
    143   memory range is available, the function will mark the corresponding bits to 1 which indicates the memory range is used.
    144   The function is only invoked when load modules at fixed address feature is enabled.
    145 
    146   @param  Private                  Pointer to the private data passed in from caller
    147   @param  ImageBase                The base address the image will be loaded at.
    148   @param  ImageSize                The size of the image
    149 
    150   @retval EFI_SUCCESS              The memory range the image will be loaded in is available
    151   @retval EFI_NOT_FOUND            The memory range the image will be loaded in is not available
    152 **/
    153 EFI_STATUS
    154 CheckAndMarkFixLoadingMemoryUsageBitMap (
    155   IN  PEI_CORE_INSTANCE             *Private,
    156   IN  EFI_PHYSICAL_ADDRESS          ImageBase,
    157   IN  UINT32                        ImageSize
    158   )
    159 {
    160    UINT32                             DxeCodePageNumber;
    161    UINT64                             ReservedCodeSize;
    162    EFI_PHYSICAL_ADDRESS               PeiCodeBase;
    163    UINT32                             BaseOffsetPageNumber;
    164    UINT32                             TopOffsetPageNumber;
    165    UINT32                             Index;
    166    UINT64                             *MemoryUsageBitMap;
    167 
    168 
    169    //
    170    // The reserved code range includes RuntimeCodePage range, Boot time code range and PEI code range.
    171    //
    172    DxeCodePageNumber = PcdGet32(PcdLoadFixAddressBootTimeCodePageNumber);
    173    DxeCodePageNumber += PcdGet32(PcdLoadFixAddressRuntimeCodePageNumber);
    174    ReservedCodeSize  = EFI_PAGES_TO_SIZE(DxeCodePageNumber + PcdGet32(PcdLoadFixAddressPeiCodePageNumber));
    175    PeiCodeBase       = Private->LoadModuleAtFixAddressTopAddress - ReservedCodeSize;
    176 
    177    //
    178    // Test the memory range for loading the image in the PEI code range.
    179    //
    180    if ((Private->LoadModuleAtFixAddressTopAddress - EFI_PAGES_TO_SIZE(DxeCodePageNumber)) < (ImageBase + ImageSize) ||
    181        (PeiCodeBase > ImageBase)) {
    182      return EFI_NOT_FOUND;
    183    }
    184 
    185    //
    186    // Test if the memory is avalaible or not.
    187    //
    188    MemoryUsageBitMap    = Private->PeiCodeMemoryRangeUsageBitMap;
    189    BaseOffsetPageNumber = EFI_SIZE_TO_PAGES((UINT32)(ImageBase - PeiCodeBase));
    190    TopOffsetPageNumber  = EFI_SIZE_TO_PAGES((UINT32)(ImageBase + ImageSize - PeiCodeBase));
    191    for (Index = BaseOffsetPageNumber; Index < TopOffsetPageNumber; Index ++) {
    192      if ((MemoryUsageBitMap[Index / 64] & LShiftU64(1, (Index % 64))) != 0) {
    193        //
    194        // This page is already used.
    195        //
    196        return EFI_NOT_FOUND;
    197      }
    198    }
    199 
    200    //
    201    // Being here means the memory range is available.  So mark the bits for the memory range
    202    //
    203    for (Index = BaseOffsetPageNumber; Index < TopOffsetPageNumber; Index ++) {
    204      MemoryUsageBitMap[Index / 64] |= LShiftU64(1, (Index % 64));
    205    }
    206    return  EFI_SUCCESS;
    207 }
    208 /**
    209 
    210   Get the fixed loading address from image header assigned by build tool. This function only be called
    211   when Loading module at Fixed address feature enabled.
    212 
    213   @param ImageContext              Pointer to the image context structure that describes the PE/COFF
    214                                     image that needs to be examined by this function.
    215   @param Private                    Pointer to the private data passed in from caller
    216 
    217   @retval EFI_SUCCESS               An fixed loading address is assigned to this image by build tools .
    218   @retval EFI_NOT_FOUND             The image has no assigned fixed loading address.
    219 
    220 **/
    221 EFI_STATUS
    222 GetPeCoffImageFixLoadingAssignedAddress(
    223   IN OUT PE_COFF_LOADER_IMAGE_CONTEXT  *ImageContext,
    224   IN     PEI_CORE_INSTANCE             *Private
    225   )
    226 {
    227    UINTN                              SectionHeaderOffset;
    228    EFI_STATUS                         Status;
    229    EFI_IMAGE_SECTION_HEADER           SectionHeader;
    230    EFI_IMAGE_OPTIONAL_HEADER_UNION    *ImgHdr;
    231    EFI_PHYSICAL_ADDRESS               FixLoadingAddress;
    232    UINT16                             Index;
    233    UINTN                              Size;
    234    UINT16                             NumberOfSections;
    235    UINT64                             ValueInSectionHeader;
    236 
    237 
    238    FixLoadingAddress = 0;
    239    Status = EFI_NOT_FOUND;
    240 
    241    //
    242    // Get PeHeader pointer
    243    //
    244    ImgHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)((CHAR8* )ImageContext->Handle + ImageContext->PeCoffHeaderOffset);
    245    if (ImageContext->IsTeImage) {
    246      //
    247      // for TE image, the fix loading address is saved in first section header that doesn't point
    248      // to code section.
    249      //
    250      SectionHeaderOffset = sizeof (EFI_TE_IMAGE_HEADER);
    251      NumberOfSections = ImgHdr->Te.NumberOfSections;
    252    } else {
    253      SectionHeaderOffset = (UINTN)(
    254                                  ImageContext->PeCoffHeaderOffset +
    255                                  sizeof (UINT32) +
    256                                  sizeof (EFI_IMAGE_FILE_HEADER) +
    257                                  ImgHdr->Pe32.FileHeader.SizeOfOptionalHeader
    258                                  );
    259       NumberOfSections = ImgHdr->Pe32.FileHeader.NumberOfSections;
    260    }
    261    //
    262    // Get base address from the first section header that doesn't point to code section.
    263    //
    264    for (Index = 0; Index < NumberOfSections; Index++) {
    265      //
    266      // Read section header from file
    267      //
    268      Size = sizeof (EFI_IMAGE_SECTION_HEADER);
    269      Status = ImageContext->ImageRead (
    270                               ImageContext->Handle,
    271                               SectionHeaderOffset,
    272                               &Size,
    273                               &SectionHeader
    274                               );
    275      if (EFI_ERROR (Status)) {
    276        return Status;
    277      }
    278 
    279      Status = EFI_NOT_FOUND;
    280 
    281      if ((SectionHeader.Characteristics & EFI_IMAGE_SCN_CNT_CODE) == 0) {
    282        //
    283        // Build tool will save the address in PointerToRelocations & PointerToLineNumbers fields in the first section header
    284        // that doesn't point to code section in image header, as well as ImageBase field of image header. A notable thing is
    285        // that for PEIM, the value in ImageBase field may not be equal to the value in PointerToRelocations & PointerToLineNumbers because
    286        // for XIP PEIM, ImageBase field holds the image base address running on the Flash. And PointerToRelocations & PointerToLineNumbers
    287        // 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
    288        // module is assigned a loading address by tools, PointerToRelocations & PointerToLineNumbers fields should NOT be Zero, or
    289        // else, these 2 fields should be set to Zero
    290        //
    291        ValueInSectionHeader = ReadUnaligned64((UINT64*)&SectionHeader.PointerToRelocations);
    292        if (ValueInSectionHeader != 0) {
    293          //
    294          // Found first section header that doesn't point to code section.
    295          //
    296          if ((INT64)PcdGet64(PcdLoadModuleAtFixAddressEnable) > 0) {
    297            //
    298            // When LMFA feature is configured as Load Module at Fixed Absolute Address mode, PointerToRelocations & PointerToLineNumbers field
    299            // hold the absolute address of image base running in memory
    300            //
    301            FixLoadingAddress = ValueInSectionHeader;
    302          } else {
    303            //
    304            // When LMFA feature is configured as Load Module at Fixed offset mode, PointerToRelocations & PointerToLineNumbers field
    305            // hold the offset relative to a platform-specific top address.
    306            //
    307            FixLoadingAddress = (EFI_PHYSICAL_ADDRESS)(Private->LoadModuleAtFixAddressTopAddress + (INT64)ValueInSectionHeader);
    308          }
    309          //
    310          // Check if the memory range is available.
    311          //
    312          Status = CheckAndMarkFixLoadingMemoryUsageBitMap (Private, FixLoadingAddress, (UINT32) ImageContext->ImageSize);
    313          if (!EFI_ERROR(Status)) {
    314            //
    315            // The assigned address is valid. Return the specified loading address
    316            //
    317            ImageContext->ImageAddress = FixLoadingAddress;
    318          }
    319        }
    320        break;
    321      }
    322      SectionHeaderOffset += sizeof (EFI_IMAGE_SECTION_HEADER);
    323    }
    324    DEBUG ((EFI_D_INFO|EFI_D_LOAD, "LOADING MODULE FIXED INFO: Loading module at fixed address 0x%11p. Status= %r \n", (VOID *)(UINTN)FixLoadingAddress, Status));
    325    return Status;
    326 }
    327 /**
    328 
    329   Loads and relocates a PE/COFF image into memory.
    330   If the image is not relocatable, it will not be loaded into memory and be loaded as XIP image.
    331 
    332   @param FileHandle      - Pointer to the FFS file header of the image.
    333   @param Pe32Data        - The base address of the PE/COFF file that is to be loaded and relocated
    334   @param ImageAddress    - The base address of the relocated PE/COFF image
    335   @param ImageSize       - The size of the relocated PE/COFF image
    336   @param EntryPoint      - The entry point of the relocated PE/COFF image
    337 
    338   @retval EFI_SUCCESS           The file was loaded and relocated
    339   @retval EFI_OUT_OF_RESOURCES  There was not enough memory to load and relocate the PE/COFF file
    340   @retval EFI_WARN_BUFFER_TOO_SMALL
    341                                 There is not enough heap to allocate the requested size.
    342                                 This will not prevent the XIP image from being invoked.
    343 
    344 **/
    345 EFI_STATUS
    346 LoadAndRelocatePeCoffImage (
    347   IN  EFI_PEI_FILE_HANDLE                       FileHandle,
    348   IN  VOID                                      *Pe32Data,
    349   OUT EFI_PHYSICAL_ADDRESS                      *ImageAddress,
    350   OUT UINT64                                    *ImageSize,
    351   OUT EFI_PHYSICAL_ADDRESS                      *EntryPoint
    352   )
    353 {
    354   EFI_STATUS                            Status;
    355   PE_COFF_LOADER_IMAGE_CONTEXT          ImageContext;
    356   PEI_CORE_INSTANCE                     *Private;
    357   UINT64                                AlignImageSize;
    358   BOOLEAN                               IsXipImage;
    359   EFI_STATUS                            ReturnStatus;
    360   BOOLEAN                               IsS3Boot;
    361   BOOLEAN                               IsPeiModule;
    362   BOOLEAN                               IsRegisterForShadow;
    363   EFI_FV_FILE_INFO                      FileInfo;
    364 
    365   Private = PEI_CORE_INSTANCE_FROM_PS_THIS (GetPeiServicesTablePointer ());
    366 
    367   ReturnStatus = EFI_SUCCESS;
    368   IsXipImage   = FALSE;
    369   ZeroMem (&ImageContext, sizeof (ImageContext));
    370   ImageContext.Handle = Pe32Data;
    371   Status              = GetImageReadFunction (&ImageContext);
    372 
    373   ASSERT_EFI_ERROR (Status);
    374 
    375   Status = PeCoffLoaderGetImageInfo (&ImageContext);
    376   if (EFI_ERROR (Status)) {
    377     return Status;
    378   }
    379 
    380   //
    381   // Initilize local IsS3Boot and IsRegisterForShadow variable
    382   //
    383   IsS3Boot = FALSE;
    384   if (Private->HobList.HandoffInformationTable->BootMode == BOOT_ON_S3_RESUME) {
    385     IsS3Boot = TRUE;
    386   }
    387   IsRegisterForShadow = FALSE;
    388   if ((Private->CurrentFileHandle == FileHandle)
    389     && (Private->Fv[Private->CurrentPeimFvCount].PeimState[Private->CurrentPeimCount] == PEIM_STATE_REGISITER_FOR_SHADOW)) {
    390     IsRegisterForShadow = TRUE;
    391   }
    392 
    393   //
    394   // XIP image that ImageAddress is same to Image handle.
    395   //
    396   if (ImageContext.ImageAddress == (EFI_PHYSICAL_ADDRESS)(UINTN) Pe32Data) {
    397     IsXipImage = TRUE;
    398   }
    399 
    400   //
    401   // Get file type first
    402   //
    403   Status = PeiServicesFfsGetFileInfo (FileHandle, &FileInfo);
    404   ASSERT_EFI_ERROR (Status);
    405 
    406   //
    407   // Check whether the file type is PEI module.
    408   //
    409   IsPeiModule = FALSE;
    410   if (FileInfo.FileType == EFI_FV_FILETYPE_PEI_CORE ||
    411       FileInfo.FileType == EFI_FV_FILETYPE_PEIM ||
    412       FileInfo.FileType == EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER) {
    413     IsPeiModule = TRUE;
    414   }
    415 
    416   //
    417   // When Image has no reloc section, it can't be relocated into memory.
    418   //
    419   if (ImageContext.RelocationsStripped && (Private->PeiMemoryInstalled) && ((!IsPeiModule) ||
    420       (!IsS3Boot && (PcdGetBool (PcdShadowPeimOnBoot) || IsRegisterForShadow)) || (IsS3Boot && PcdGetBool (PcdShadowPeimOnS3Boot)))) {
    421     DEBUG ((EFI_D_INFO|EFI_D_LOAD, "The image at 0x%08x without reloc section can't be loaded into memory\n", (UINTN) Pe32Data));
    422   }
    423 
    424   //
    425   // Set default base address to current image address.
    426   //
    427   ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)(UINTN) Pe32Data;
    428 
    429   //
    430   // Allocate Memory for the image when memory is ready, and image is relocatable.
    431   // On normal boot, PcdShadowPeimOnBoot decides whether load PEIM or PeiCore into memory.
    432   // On S3 boot, PcdShadowPeimOnS3Boot decides whether load PEIM or PeiCore into memory.
    433   //
    434   if ((!ImageContext.RelocationsStripped) && (Private->PeiMemoryInstalled) && ((!IsPeiModule) ||
    435       (!IsS3Boot && (PcdGetBool (PcdShadowPeimOnBoot) || IsRegisterForShadow)) || (IsS3Boot && PcdGetBool (PcdShadowPeimOnS3Boot)))) {
    436     //
    437     // Allocate more buffer to avoid buffer overflow.
    438     //
    439     if (ImageContext.IsTeImage) {
    440       AlignImageSize = ImageContext.ImageSize + ((EFI_TE_IMAGE_HEADER *) Pe32Data)->StrippedSize - sizeof (EFI_TE_IMAGE_HEADER);
    441     } else {
    442       AlignImageSize = ImageContext.ImageSize;
    443     }
    444 
    445     if (ImageContext.SectionAlignment > EFI_PAGE_SIZE) {
    446       AlignImageSize += ImageContext.SectionAlignment;
    447     }
    448 
    449     if (PcdGet64(PcdLoadModuleAtFixAddressEnable) != 0 && (Private->HobList.HandoffInformationTable->BootMode != BOOT_ON_S3_RESUME)) {
    450       Status = GetPeCoffImageFixLoadingAssignedAddress(&ImageContext, Private);
    451       if (EFI_ERROR (Status)){
    452         DEBUG ((EFI_D_INFO|EFI_D_LOAD, "LOADING MODULE FIXED ERROR: Failed to load module at fixed address. \n"));
    453         //
    454         // The PEIM is not assiged valid address, try to allocate page to load it.
    455         //
    456         ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)(UINTN) AllocatePages (EFI_SIZE_TO_PAGES ((UINT32) AlignImageSize));
    457       }
    458     } else {
    459       ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)(UINTN) AllocatePages (EFI_SIZE_TO_PAGES ((UINT32) AlignImageSize));
    460     }
    461     if (ImageContext.ImageAddress != 0) {
    462       //
    463       // Adjust the Image Address to make sure it is section alignment.
    464       //
    465       if (ImageContext.SectionAlignment > EFI_PAGE_SIZE) {
    466         ImageContext.ImageAddress =
    467             (ImageContext.ImageAddress + ImageContext.SectionAlignment - 1) &
    468             ~((UINTN)ImageContext.SectionAlignment - 1);
    469       }
    470       //
    471       // Fix alignment requirement when Load IPF TeImage into memory.
    472       // Skip the reserved space for the stripped PeHeader when load TeImage into memory.
    473       //
    474       if (ImageContext.IsTeImage) {
    475         ImageContext.ImageAddress = ImageContext.ImageAddress +
    476                                     ((EFI_TE_IMAGE_HEADER *) Pe32Data)->StrippedSize -
    477                                     sizeof (EFI_TE_IMAGE_HEADER);
    478       }
    479     } else {
    480       //
    481       // No enough memory resource.
    482       //
    483       if (IsXipImage) {
    484         //
    485         // XIP image can still be invoked.
    486         //
    487         ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)(UINTN) Pe32Data;
    488         ReturnStatus = EFI_WARN_BUFFER_TOO_SMALL;
    489       } else {
    490         //
    491         // Non XIP image can't be loaded because no enough memory is allocated.
    492         //
    493         ASSERT (FALSE);
    494         return EFI_OUT_OF_RESOURCES;
    495       }
    496     }
    497   }
    498 
    499   //
    500   // Load the image to our new buffer
    501   //
    502   Status = PeCoffLoaderLoadImage (&ImageContext);
    503   if (EFI_ERROR (Status)) {
    504     return Status;
    505   }
    506   //
    507   // Relocate the image in our new buffer
    508   //
    509   Status = PeCoffLoaderRelocateImage (&ImageContext);
    510   if (EFI_ERROR (Status)) {
    511     return Status;
    512   }
    513 
    514   //
    515   // Flush the instruction cache so the image data is written before we execute it
    516   //
    517   if (ImageContext.ImageAddress != (EFI_PHYSICAL_ADDRESS)(UINTN) Pe32Data) {
    518     InvalidateInstructionCacheRange ((VOID *)(UINTN)ImageContext.ImageAddress, (UINTN)ImageContext.ImageSize);
    519   }
    520 
    521   *ImageAddress = ImageContext.ImageAddress;
    522   *ImageSize    = ImageContext.ImageSize;
    523   *EntryPoint   = ImageContext.EntryPoint;
    524 
    525   return ReturnStatus;
    526 }
    527 
    528 /**
    529   Loads a PEIM into memory for subsequent execution. If there are compressed
    530   images or images that need to be relocated into memory for performance reasons,
    531   this service performs that transformation.
    532 
    533   @param PeiServices      An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation
    534   @param FileHandle       Pointer to the FFS file header of the image.
    535   @param ImageAddressArg  Pointer to PE/TE image.
    536   @param ImageSizeArg     Size of PE/TE image.
    537   @param EntryPoint       Pointer to entry point of specified image file for output.
    538   @param AuthenticationState - Pointer to attestation authentication state of image.
    539 
    540   @retval EFI_SUCCESS      Image is successfully loaded.
    541   @retval EFI_NOT_FOUND    Fail to locate necessary PPI.
    542   @retval EFI_UNSUPPORTED  Image Machine Type is not supported.
    543   @retval EFI_WARN_BUFFER_TOO_SMALL
    544                            There is not enough heap to allocate the requested size.
    545                            This will not prevent the XIP image from being invoked.
    546 
    547 **/
    548 EFI_STATUS
    549 PeiLoadImageLoadImage (
    550   IN     CONST EFI_PEI_SERVICES       **PeiServices,
    551   IN     EFI_PEI_FILE_HANDLE          FileHandle,
    552   OUT    EFI_PHYSICAL_ADDRESS         *ImageAddressArg,  OPTIONAL
    553   OUT    UINT64                       *ImageSizeArg,     OPTIONAL
    554   OUT    EFI_PHYSICAL_ADDRESS         *EntryPoint,
    555   OUT    UINT32                       *AuthenticationState
    556   )
    557 {
    558   EFI_STATUS                  Status;
    559   VOID                        *Pe32Data;
    560   EFI_PHYSICAL_ADDRESS        ImageAddress;
    561   UINT64                      ImageSize;
    562   EFI_PHYSICAL_ADDRESS        ImageEntryPoint;
    563   UINT16                      Machine;
    564   EFI_SECTION_TYPE            SearchType1;
    565   EFI_SECTION_TYPE            SearchType2;
    566 
    567   *EntryPoint          = 0;
    568   ImageSize            = 0;
    569   *AuthenticationState = 0;
    570 
    571   if (FeaturePcdGet (PcdPeiCoreImageLoaderSearchTeSectionFirst)) {
    572     SearchType1 = EFI_SECTION_TE;
    573     SearchType2 = EFI_SECTION_PE32;
    574   } else {
    575     SearchType1 = EFI_SECTION_PE32;
    576     SearchType2 = EFI_SECTION_TE;
    577   }
    578 
    579   //
    580   // Try to find a first exe section (if PcdPeiCoreImageLoaderSearchTeSectionFirst
    581   // is true, TE will be searched first).
    582   //
    583   Status = PeiServicesFfsFindSectionData3 (
    584              SearchType1,
    585              0,
    586              FileHandle,
    587              &Pe32Data,
    588              AuthenticationState
    589              );
    590   //
    591   // If we didn't find a first exe section, try to find the second exe section.
    592   //
    593   if (EFI_ERROR (Status)) {
    594     Status = PeiServicesFfsFindSectionData3 (
    595                SearchType2,
    596                0,
    597                FileHandle,
    598                &Pe32Data,
    599                AuthenticationState
    600                );
    601     if (EFI_ERROR (Status)) {
    602       //
    603       // PEI core only carry the loader function for TE and PE32 executables
    604       // If this two section does not exist, just return.
    605       //
    606       return Status;
    607     }
    608   }
    609 
    610   //
    611   // If memory is installed, perform the shadow operations
    612   //
    613   Status = LoadAndRelocatePeCoffImage (
    614     FileHandle,
    615     Pe32Data,
    616     &ImageAddress,
    617     &ImageSize,
    618     &ImageEntryPoint
    619   );
    620 
    621   ASSERT_EFI_ERROR (Status);
    622 
    623 
    624   if (EFI_ERROR (Status)) {
    625     return Status;
    626   }
    627 
    628   //
    629   // Got the entry point from the loaded Pe32Data
    630   //
    631   Pe32Data    = (VOID *) ((UINTN) ImageAddress);
    632   *EntryPoint = ImageEntryPoint;
    633 
    634   Machine = PeCoffLoaderGetMachineType (Pe32Data);
    635 
    636   if (!EFI_IMAGE_MACHINE_TYPE_SUPPORTED (Machine)) {
    637     if (!EFI_IMAGE_MACHINE_CROSS_TYPE_SUPPORTED (Machine)) {
    638       return EFI_UNSUPPORTED;
    639     }
    640   }
    641 
    642   if (ImageAddressArg != NULL) {
    643     *ImageAddressArg = ImageAddress;
    644   }
    645 
    646   if (ImageSizeArg != NULL) {
    647     *ImageSizeArg = ImageSize;
    648   }
    649 
    650   DEBUG_CODE_BEGIN ();
    651     CHAR8                              *AsciiString;
    652     CHAR8                              EfiFileName[512];
    653     INT32                              Index;
    654     INT32                              StartIndex;
    655 
    656     //
    657     // Print debug message: Loading PEIM at 0x12345678 EntryPoint=0x12345688 Driver.efi
    658     //
    659     if (Machine != EFI_IMAGE_MACHINE_IA64) {
    660       DEBUG ((EFI_D_INFO | EFI_D_LOAD, "Loading PEIM at 0x%11p EntryPoint=0x%11p ", (VOID *)(UINTN)ImageAddress, (VOID *)(UINTN)*EntryPoint));
    661     } else {
    662       //
    663       // For IPF Image, the real entry point should be print.
    664       //
    665       DEBUG ((EFI_D_INFO | EFI_D_LOAD, "Loading PEIM at 0x%11p EntryPoint=0x%11p ", (VOID *)(UINTN)ImageAddress, (VOID *)(UINTN)(*(UINT64 *)(UINTN)*EntryPoint)));
    666     }
    667 
    668     //
    669     // Print Module Name by PeImage PDB file name.
    670     //
    671     AsciiString = PeCoffLoaderGetPdbPointer (Pe32Data);
    672 
    673     if (AsciiString != NULL) {
    674       StartIndex = 0;
    675       for (Index = 0; AsciiString[Index] != 0; Index++) {
    676         if (AsciiString[Index] == '\\' || AsciiString[Index] == '/') {
    677           StartIndex = Index + 1;
    678         }
    679       }
    680 
    681       //
    682       // Copy the PDB file name to our temporary string, and replace .pdb with .efi
    683       // The PDB file name is limited in the range of 0~511.
    684       // If the length is bigger than 511, trim the redudant characters to avoid overflow in array boundary.
    685       //
    686       for (Index = 0; Index < sizeof (EfiFileName) - 4; Index++) {
    687         EfiFileName[Index] = AsciiString[Index + StartIndex];
    688         if (EfiFileName[Index] == 0) {
    689           EfiFileName[Index] = '.';
    690         }
    691         if (EfiFileName[Index] == '.') {
    692           EfiFileName[Index + 1] = 'e';
    693           EfiFileName[Index + 2] = 'f';
    694           EfiFileName[Index + 3] = 'i';
    695           EfiFileName[Index + 4] = 0;
    696           break;
    697         }
    698       }
    699 
    700       if (Index == sizeof (EfiFileName) - 4) {
    701         EfiFileName[Index] = 0;
    702       }
    703 
    704       DEBUG ((EFI_D_INFO | EFI_D_LOAD, "%a", EfiFileName));
    705     }
    706 
    707   DEBUG_CODE_END ();
    708 
    709   DEBUG ((EFI_D_INFO | EFI_D_LOAD, "\n"));
    710 
    711   return EFI_SUCCESS;
    712 
    713 }
    714 
    715 
    716 /**
    717   The wrapper function of PeiLoadImageLoadImage().
    718 
    719   @param This            - Pointer to EFI_PEI_LOAD_FILE_PPI.
    720   @param FileHandle      - Pointer to the FFS file header of the image.
    721   @param ImageAddressArg - Pointer to PE/TE image.
    722   @param ImageSizeArg    - Size of PE/TE image.
    723   @param EntryPoint      - Pointer to entry point of specified image file for output.
    724   @param AuthenticationState - Pointer to attestation authentication state of image.
    725 
    726   @return Status of PeiLoadImageLoadImage().
    727 
    728 **/
    729 EFI_STATUS
    730 EFIAPI
    731 PeiLoadImageLoadImageWrapper (
    732   IN     CONST EFI_PEI_LOAD_FILE_PPI  *This,
    733   IN     EFI_PEI_FILE_HANDLE          FileHandle,
    734   OUT    EFI_PHYSICAL_ADDRESS         *ImageAddressArg,  OPTIONAL
    735   OUT    UINT64                       *ImageSizeArg,     OPTIONAL
    736   OUT    EFI_PHYSICAL_ADDRESS         *EntryPoint,
    737   OUT    UINT32                       *AuthenticationState
    738   )
    739 {
    740   return PeiLoadImageLoadImage (
    741            GetPeiServicesTablePointer (),
    742            FileHandle,
    743            ImageAddressArg,
    744            ImageSizeArg,
    745            EntryPoint,
    746            AuthenticationState
    747            );
    748 }
    749 
    750 /**
    751   Check whether the input image has the relocation.
    752 
    753   @param  Pe32Data   Pointer to the PE/COFF or TE image.
    754 
    755   @retval TRUE       Relocation is stripped.
    756   @retval FALSE      Relocation is not stripped.
    757 
    758 **/
    759 BOOLEAN
    760 RelocationIsStrip (
    761   IN VOID  *Pe32Data
    762   )
    763 {
    764   EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION  Hdr;
    765   EFI_IMAGE_DOS_HEADER                 *DosHdr;
    766 
    767   ASSERT (Pe32Data != NULL);
    768 
    769   DosHdr = (EFI_IMAGE_DOS_HEADER *)Pe32Data;
    770   if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) {
    771     //
    772     // DOS image header is present, so read the PE header after the DOS image header.
    773     //
    774     Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINTN) Pe32Data + (UINTN) ((DosHdr->e_lfanew) & 0x0ffff));
    775   } else {
    776     //
    777     // DOS image header is not present, so PE header is at the image base.
    778     //
    779     Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)Pe32Data;
    780   }
    781 
    782   //
    783   // Three cases with regards to relocations:
    784   // - Image has base relocs, RELOCS_STRIPPED==0    => image is relocatable
    785   // - Image has no base relocs, RELOCS_STRIPPED==1 => Image is not relocatable
    786   // - Image has no base relocs, RELOCS_STRIPPED==0 => Image is relocatable but
    787   //   has no base relocs to apply
    788   // Obviously having base relocations with RELOCS_STRIPPED==1 is invalid.
    789   //
    790   // Look at the file header to determine if relocations have been stripped, and
    791   // save this info in the image context for later use.
    792   //
    793   if (Hdr.Te->Signature == EFI_TE_IMAGE_HEADER_SIGNATURE) {
    794     if ((Hdr.Te->DataDirectory[0].Size == 0) && (Hdr.Te->DataDirectory[0].VirtualAddress == 0)) {
    795       return TRUE;
    796     } else {
    797       return FALSE;
    798     }
    799   } else if (Hdr.Pe32->Signature == EFI_IMAGE_NT_SIGNATURE)  {
    800     if ((Hdr.Pe32->FileHeader.Characteristics & EFI_IMAGE_FILE_RELOCS_STRIPPED) != 0) {
    801       return TRUE;
    802     } else {
    803       return FALSE;
    804     }
    805   }
    806 
    807   return FALSE;
    808 }
    809 
    810 /**
    811   Routine to load image file for subsequent execution by LoadFile Ppi.
    812   If any LoadFile Ppi is not found, the build-in support function for the PE32+/TE
    813   XIP image format is used.
    814 
    815   @param PeiServices     - An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation
    816   @param FileHandle      - Pointer to the FFS file header of the image.
    817   @param PeimState       - The dispatch state of the input PEIM handle.
    818   @param EntryPoint      - Pointer to entry point of specified image file for output.
    819   @param AuthenticationState - Pointer to attestation authentication state of image.
    820 
    821   @retval EFI_SUCCESS    - Image is successfully loaded.
    822   @retval EFI_NOT_FOUND  - Fail to locate necessary PPI
    823   @retval Others         - Fail to load file.
    824 
    825 **/
    826 EFI_STATUS
    827 PeiLoadImage (
    828   IN     CONST EFI_PEI_SERVICES       **PeiServices,
    829   IN     EFI_PEI_FILE_HANDLE          FileHandle,
    830   IN     UINT8                        PeimState,
    831   OUT    EFI_PHYSICAL_ADDRESS         *EntryPoint,
    832   OUT    UINT32                       *AuthenticationState
    833   )
    834 {
    835   EFI_STATUS              PpiStatus;
    836   EFI_STATUS              Status;
    837   UINTN                   Index;
    838   EFI_PEI_LOAD_FILE_PPI   *LoadFile;
    839   EFI_PHYSICAL_ADDRESS    ImageAddress;
    840   UINT64                  ImageSize;
    841   BOOLEAN                 IsStrip;
    842 
    843   IsStrip = FALSE;
    844   //
    845   // If any instances of PEI_LOAD_FILE_PPI are installed, they are called.
    846   // one at a time, until one reports EFI_SUCCESS.
    847   //
    848   Index = 0;
    849   do {
    850     PpiStatus = PeiServicesLocatePpi (
    851                   &gEfiPeiLoadFilePpiGuid,
    852                   Index,
    853                   NULL,
    854                   (VOID **)&LoadFile
    855                   );
    856     if (!EFI_ERROR (PpiStatus)) {
    857       Status = LoadFile->LoadFile (
    858                           LoadFile,
    859                           FileHandle,
    860                           &ImageAddress,
    861                           &ImageSize,
    862                           EntryPoint,
    863                           AuthenticationState
    864                           );
    865       if (!EFI_ERROR (Status) || Status == EFI_WARN_BUFFER_TOO_SMALL) {
    866         //
    867         // The shadowed PEIM must be relocatable.
    868         //
    869         if (PeimState == PEIM_STATE_REGISITER_FOR_SHADOW) {
    870           IsStrip = RelocationIsStrip ((VOID *) (UINTN) ImageAddress);
    871           ASSERT (!IsStrip);
    872           if (IsStrip) {
    873             return EFI_UNSUPPORTED;
    874           }
    875         }
    876 
    877         //
    878         // The image to be started must have the machine type supported by PeiCore.
    879         //
    880         ASSERT (EFI_IMAGE_MACHINE_TYPE_SUPPORTED (PeCoffLoaderGetMachineType ((VOID *) (UINTN) ImageAddress)));
    881         if (!EFI_IMAGE_MACHINE_TYPE_SUPPORTED (PeCoffLoaderGetMachineType ((VOID *) (UINTN) ImageAddress))) {
    882           return EFI_UNSUPPORTED;
    883         }
    884         return EFI_SUCCESS;
    885       }
    886     }
    887     Index++;
    888   } while (!EFI_ERROR (PpiStatus));
    889 
    890   return PpiStatus;
    891 }
    892 
    893 
    894 /**
    895 
    896   Install Pei Load File PPI.
    897 
    898 
    899   @param PrivateData     - Pointer to PEI_CORE_INSTANCE.
    900   @param OldCoreData     - Pointer to PEI_CORE_INSTANCE.
    901 
    902 **/
    903 VOID
    904 InitializeImageServices (
    905   IN  PEI_CORE_INSTANCE   *PrivateData,
    906   IN  PEI_CORE_INSTANCE   *OldCoreData
    907   )
    908 {
    909   if (OldCoreData == NULL) {
    910     //
    911     // The first time we are XIP (running from FLASH). We need to remember the
    912     // FLASH address so we can reinstall the memory version that runs faster
    913     //
    914     PrivateData->XipLoadFile = &gPpiLoadFilePpiList;
    915     PeiServicesInstallPpi (PrivateData->XipLoadFile);
    916   } else {
    917     //
    918     // 2nd time we are running from memory so replace the XIP version with the
    919     // new memory version.
    920     //
    921     PeiServicesReInstallPpi (PrivateData->XipLoadFile, &gPpiLoadFilePpiList);
    922   }
    923 }
    924 
    925 
    926 
    927 
    928