Home | History | Annotate | Download | only in Image
      1 /** @file
      2   Pei Core Load Image Support
      3 
      4 Copyright (c) 2006 - 2015, 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 arry to figure out if the memory range the image will be loaded in is available or not. If
    143   memory range is avaliable, the function will mark the correponding 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 addres 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 loadding 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 loadding 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               FixLoaddingAddress;
    232    UINT16                             Index;
    233    UINTN                              Size;
    234    UINT16                             NumberOfSections;
    235    UINT64                             ValueInSectionHeader;
    236 
    237 
    238    FixLoaddingAddress = 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 loadding 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 fileds 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 runing in memory
    300            //
    301            FixLoaddingAddress = 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            FixLoaddingAddress = (EFI_PHYSICAL_ADDRESS)(Private->LoadModuleAtFixAddressTopAddress + (INT64)ValueInSectionHeader);
    308          }
    309          //
    310          // Check if the memory range is avaliable.
    311          //
    312          Status = CheckAndMarkFixLoadingMemoryUsageBitMap (Private, FixLoaddingAddress, (UINT32) ImageContext->ImageSize);
    313          if (!EFI_ERROR(Status)) {
    314            //
    315            // The assigned address is valid. Return the specified loadding address
    316            //
    317            ImageContext->ImageAddress = FixLoaddingAddress;
    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)FixLoaddingAddress, 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                               IsRegisterForShadow;
    362 
    363   Private = PEI_CORE_INSTANCE_FROM_PS_THIS (GetPeiServicesTablePointer ());
    364 
    365   ReturnStatus = EFI_SUCCESS;
    366   IsXipImage   = FALSE;
    367   ZeroMem (&ImageContext, sizeof (ImageContext));
    368   ImageContext.Handle = Pe32Data;
    369   Status              = GetImageReadFunction (&ImageContext);
    370 
    371   ASSERT_EFI_ERROR (Status);
    372 
    373   Status = PeCoffLoaderGetImageInfo (&ImageContext);
    374   if (EFI_ERROR (Status)) {
    375     return Status;
    376   }
    377 
    378   //
    379   // Initilize local IsS3Boot and IsRegisterForShadow variable
    380   //
    381   IsS3Boot = FALSE;
    382   if (Private->HobList.HandoffInformationTable->BootMode == BOOT_ON_S3_RESUME) {
    383     IsS3Boot = TRUE;
    384   }
    385   IsRegisterForShadow = FALSE;
    386   if ((Private->CurrentFileHandle == FileHandle)
    387     && (Private->Fv[Private->CurrentPeimFvCount].PeimState[Private->CurrentPeimCount] == PEIM_STATE_REGISITER_FOR_SHADOW)) {
    388     IsRegisterForShadow = TRUE;
    389   }
    390 
    391   //
    392   // XIP image that ImageAddress is same to Image handle.
    393   //
    394   if (ImageContext.ImageAddress == (EFI_PHYSICAL_ADDRESS)(UINTN) Pe32Data) {
    395     IsXipImage = TRUE;
    396   }
    397 
    398   //
    399   // When Image has no reloc section, it can't be relocated into memory.
    400   //
    401   if (ImageContext.RelocationsStripped && (Private->PeiMemoryInstalled) && (
    402       (!IsS3Boot && (PcdGetBool (PcdShadowPeimOnBoot) || IsRegisterForShadow)) || (IsS3Boot && PcdGetBool (PcdShadowPeimOnS3Boot)))) {
    403     DEBUG ((EFI_D_INFO|EFI_D_LOAD, "The image at 0x%08x without reloc section can't be loaded into memory\n", (UINTN) Pe32Data));
    404   }
    405 
    406   //
    407   // Set default base address to current image address.
    408   //
    409   ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)(UINTN) Pe32Data;
    410 
    411   //
    412   // Allocate Memory for the image when memory is ready, and image is relocatable.
    413   // On normal boot, PcdShadowPeimOnBoot decides whether load PEIM or PeiCore into memory.
    414   // On S3 boot, PcdShadowPeimOnS3Boot decides whether load PEIM or PeiCore into memory.
    415   //
    416   if ((!ImageContext.RelocationsStripped) && (Private->PeiMemoryInstalled) && (
    417       (!IsS3Boot && (PcdGetBool (PcdShadowPeimOnBoot) || IsRegisterForShadow)) || (IsS3Boot && PcdGetBool (PcdShadowPeimOnS3Boot)))) {
    418     //
    419     // Allocate more buffer to avoid buffer overflow.
    420     //
    421     if (ImageContext.IsTeImage) {
    422       AlignImageSize = ImageContext.ImageSize + ((EFI_TE_IMAGE_HEADER *) Pe32Data)->StrippedSize - sizeof (EFI_TE_IMAGE_HEADER);
    423     } else {
    424       AlignImageSize = ImageContext.ImageSize;
    425     }
    426 
    427     if (ImageContext.SectionAlignment > EFI_PAGE_SIZE) {
    428       AlignImageSize += ImageContext.SectionAlignment;
    429     }
    430 
    431     if (PcdGet64(PcdLoadModuleAtFixAddressEnable) != 0 && (Private->HobList.HandoffInformationTable->BootMode != BOOT_ON_S3_RESUME)) {
    432       Status = GetPeCoffImageFixLoadingAssignedAddress(&ImageContext, Private);
    433       if (EFI_ERROR (Status)){
    434         DEBUG ((EFI_D_INFO|EFI_D_LOAD, "LOADING MODULE FIXED ERROR: Failed to load module at fixed address. \n"));
    435         //
    436         // The PEIM is not assiged valid address, try to allocate page to load it.
    437         //
    438         ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)(UINTN) AllocatePages (EFI_SIZE_TO_PAGES ((UINT32) AlignImageSize));
    439       }
    440     } else {
    441       ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)(UINTN) AllocatePages (EFI_SIZE_TO_PAGES ((UINT32) AlignImageSize));
    442     }
    443     if (ImageContext.ImageAddress != 0) {
    444       //
    445       // Adjust the Image Address to make sure it is section alignment.
    446       //
    447       if (ImageContext.SectionAlignment > EFI_PAGE_SIZE) {
    448         ImageContext.ImageAddress =
    449             (ImageContext.ImageAddress + ImageContext.SectionAlignment - 1) &
    450             ~((UINTN)ImageContext.SectionAlignment - 1);
    451       }
    452       //
    453       // Fix alignment requirement when Load IPF TeImage into memory.
    454       // Skip the reserved space for the stripped PeHeader when load TeImage into memory.
    455       //
    456       if (ImageContext.IsTeImage) {
    457         ImageContext.ImageAddress = ImageContext.ImageAddress +
    458                                     ((EFI_TE_IMAGE_HEADER *) Pe32Data)->StrippedSize -
    459                                     sizeof (EFI_TE_IMAGE_HEADER);
    460       }
    461     } else {
    462       //
    463       // No enough memory resource.
    464       //
    465       if (IsXipImage) {
    466         //
    467         // XIP image can still be invoked.
    468         //
    469         ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)(UINTN) Pe32Data;
    470         ReturnStatus = EFI_WARN_BUFFER_TOO_SMALL;
    471       } else {
    472         //
    473         // Non XIP image can't be loaded because no enough memory is allocated.
    474         //
    475         ASSERT (FALSE);
    476         return EFI_OUT_OF_RESOURCES;
    477       }
    478     }
    479   }
    480 
    481   //
    482   // Load the image to our new buffer
    483   //
    484   Status = PeCoffLoaderLoadImage (&ImageContext);
    485   if (EFI_ERROR (Status)) {
    486     return Status;
    487   }
    488   //
    489   // Relocate the image in our new buffer
    490   //
    491   Status = PeCoffLoaderRelocateImage (&ImageContext);
    492   if (EFI_ERROR (Status)) {
    493     return Status;
    494   }
    495 
    496   //
    497   // Flush the instruction cache so the image data is written before we execute it
    498   //
    499   if (ImageContext.ImageAddress != (EFI_PHYSICAL_ADDRESS)(UINTN) Pe32Data) {
    500     InvalidateInstructionCacheRange ((VOID *)(UINTN)ImageContext.ImageAddress, (UINTN)ImageContext.ImageSize);
    501   }
    502 
    503   *ImageAddress = ImageContext.ImageAddress;
    504   *ImageSize    = ImageContext.ImageSize;
    505   *EntryPoint   = ImageContext.EntryPoint;
    506 
    507   return ReturnStatus;
    508 }
    509 
    510 /**
    511   Loads a PEIM into memory for subsequent execution. If there are compressed
    512   images or images that need to be relocated into memory for performance reasons,
    513   this service performs that transformation.
    514 
    515   @param PeiServices      An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation
    516   @param FileHandle       Pointer to the FFS file header of the image.
    517   @param ImageAddressArg  Pointer to PE/TE image.
    518   @param ImageSizeArg     Size of PE/TE image.
    519   @param EntryPoint       Pointer to entry point of specified image file for output.
    520   @param AuthenticationState - Pointer to attestation authentication state of image.
    521 
    522   @retval EFI_SUCCESS      Image is successfully loaded.
    523   @retval EFI_NOT_FOUND    Fail to locate necessary PPI.
    524   @retval EFI_UNSUPPORTED  Image Machine Type is not supported.
    525   @retval EFI_WARN_BUFFER_TOO_SMALL
    526                            There is not enough heap to allocate the requested size.
    527                            This will not prevent the XIP image from being invoked.
    528 
    529 **/
    530 EFI_STATUS
    531 PeiLoadImageLoadImage (
    532   IN     CONST EFI_PEI_SERVICES       **PeiServices,
    533   IN     EFI_PEI_FILE_HANDLE          FileHandle,
    534   OUT    EFI_PHYSICAL_ADDRESS         *ImageAddressArg,  OPTIONAL
    535   OUT    UINT64                       *ImageSizeArg,     OPTIONAL
    536   OUT    EFI_PHYSICAL_ADDRESS         *EntryPoint,
    537   OUT    UINT32                       *AuthenticationState
    538   )
    539 {
    540   EFI_STATUS                  Status;
    541   VOID                        *Pe32Data;
    542   EFI_PHYSICAL_ADDRESS        ImageAddress;
    543   UINT64                      ImageSize;
    544   EFI_PHYSICAL_ADDRESS        ImageEntryPoint;
    545   UINT16                      Machine;
    546   EFI_SECTION_TYPE            SearchType1;
    547   EFI_SECTION_TYPE            SearchType2;
    548 
    549   *EntryPoint          = 0;
    550   ImageSize            = 0;
    551   *AuthenticationState = 0;
    552 
    553   if (FeaturePcdGet (PcdPeiCoreImageLoaderSearchTeSectionFirst)) {
    554     SearchType1 = EFI_SECTION_TE;
    555     SearchType2 = EFI_SECTION_PE32;
    556   } else {
    557     SearchType1 = EFI_SECTION_PE32;
    558     SearchType2 = EFI_SECTION_TE;
    559   }
    560 
    561   //
    562   // Try to find a first exe section (if PcdPeiCoreImageLoaderSearchTeSectionFirst
    563   // is true, TE will be searched first).
    564   //
    565   Status = PeiServicesFfsFindSectionData3 (
    566              SearchType1,
    567              0,
    568              FileHandle,
    569              &Pe32Data,
    570              AuthenticationState
    571              );
    572   //
    573   // If we didn't find a first exe section, try to find the second exe section.
    574   //
    575   if (EFI_ERROR (Status)) {
    576     Status = PeiServicesFfsFindSectionData3 (
    577                SearchType2,
    578                0,
    579                FileHandle,
    580                &Pe32Data,
    581                AuthenticationState
    582                );
    583     if (EFI_ERROR (Status)) {
    584       //
    585       // PEI core only carry the loader function for TE and PE32 executables
    586       // If this two section does not exist, just return.
    587       //
    588       return Status;
    589     }
    590   }
    591 
    592   //
    593   // If memory is installed, perform the shadow operations
    594   //
    595   Status = LoadAndRelocatePeCoffImage (
    596     FileHandle,
    597     Pe32Data,
    598     &ImageAddress,
    599     &ImageSize,
    600     &ImageEntryPoint
    601   );
    602 
    603   ASSERT_EFI_ERROR (Status);
    604 
    605 
    606   if (EFI_ERROR (Status)) {
    607     return Status;
    608   }
    609 
    610   //
    611   // Got the entry point from the loaded Pe32Data
    612   //
    613   Pe32Data    = (VOID *) ((UINTN) ImageAddress);
    614   *EntryPoint = ImageEntryPoint;
    615 
    616   Machine = PeCoffLoaderGetMachineType (Pe32Data);
    617 
    618   if (!EFI_IMAGE_MACHINE_TYPE_SUPPORTED (Machine)) {
    619     if (!EFI_IMAGE_MACHINE_CROSS_TYPE_SUPPORTED (Machine)) {
    620       return EFI_UNSUPPORTED;
    621     }
    622   }
    623 
    624   if (ImageAddressArg != NULL) {
    625     *ImageAddressArg = ImageAddress;
    626   }
    627 
    628   if (ImageSizeArg != NULL) {
    629     *ImageSizeArg = ImageSize;
    630   }
    631 
    632   DEBUG_CODE_BEGIN ();
    633     CHAR8                              *AsciiString;
    634     CHAR8                              EfiFileName[512];
    635     INT32                              Index;
    636     INT32                              StartIndex;
    637 
    638     //
    639     // Print debug message: Loading PEIM at 0x12345678 EntryPoint=0x12345688 Driver.efi
    640     //
    641     if (Machine != EFI_IMAGE_MACHINE_IA64) {
    642       DEBUG ((EFI_D_INFO | EFI_D_LOAD, "Loading PEIM at 0x%11p EntryPoint=0x%11p ", (VOID *)(UINTN)ImageAddress, (VOID *)(UINTN)*EntryPoint));
    643     } else {
    644       //
    645       // For IPF Image, the real entry point should be print.
    646       //
    647       DEBUG ((EFI_D_INFO | EFI_D_LOAD, "Loading PEIM at 0x%11p EntryPoint=0x%11p ", (VOID *)(UINTN)ImageAddress, (VOID *)(UINTN)(*(UINT64 *)(UINTN)*EntryPoint)));
    648     }
    649 
    650     //
    651     // Print Module Name by PeImage PDB file name.
    652     //
    653     AsciiString = PeCoffLoaderGetPdbPointer (Pe32Data);
    654 
    655     if (AsciiString != NULL) {
    656       StartIndex = 0;
    657       for (Index = 0; AsciiString[Index] != 0; Index++) {
    658         if (AsciiString[Index] == '\\' || AsciiString[Index] == '/') {
    659           StartIndex = Index + 1;
    660         }
    661       }
    662 
    663       //
    664       // Copy the PDB file name to our temporary string, and replace .pdb with .efi
    665       // The PDB file name is limited in the range of 0~511.
    666       // If the length is bigger than 511, trim the redudant characters to avoid overflow in array boundary.
    667       //
    668       for (Index = 0; Index < sizeof (EfiFileName) - 4; Index++) {
    669         EfiFileName[Index] = AsciiString[Index + StartIndex];
    670         if (EfiFileName[Index] == 0) {
    671           EfiFileName[Index] = '.';
    672         }
    673         if (EfiFileName[Index] == '.') {
    674           EfiFileName[Index + 1] = 'e';
    675           EfiFileName[Index + 2] = 'f';
    676           EfiFileName[Index + 3] = 'i';
    677           EfiFileName[Index + 4] = 0;
    678           break;
    679         }
    680       }
    681 
    682       if (Index == sizeof (EfiFileName) - 4) {
    683         EfiFileName[Index] = 0;
    684       }
    685 
    686       DEBUG ((EFI_D_INFO | EFI_D_LOAD, "%a", EfiFileName));
    687     }
    688 
    689   DEBUG_CODE_END ();
    690 
    691   DEBUG ((EFI_D_INFO | EFI_D_LOAD, "\n"));
    692 
    693   return EFI_SUCCESS;
    694 
    695 }
    696 
    697 
    698 /**
    699   The wrapper function of PeiLoadImageLoadImage().
    700 
    701   @param This            - Pointer to EFI_PEI_LOAD_FILE_PPI.
    702   @param FileHandle      - Pointer to the FFS file header of the image.
    703   @param ImageAddressArg - Pointer to PE/TE image.
    704   @param ImageSizeArg    - Size of PE/TE image.
    705   @param EntryPoint      - Pointer to entry point of specified image file for output.
    706   @param AuthenticationState - Pointer to attestation authentication state of image.
    707 
    708   @return Status of PeiLoadImageLoadImage().
    709 
    710 **/
    711 EFI_STATUS
    712 EFIAPI
    713 PeiLoadImageLoadImageWrapper (
    714   IN     CONST EFI_PEI_LOAD_FILE_PPI  *This,
    715   IN     EFI_PEI_FILE_HANDLE          FileHandle,
    716   OUT    EFI_PHYSICAL_ADDRESS         *ImageAddressArg,  OPTIONAL
    717   OUT    UINT64                       *ImageSizeArg,     OPTIONAL
    718   OUT    EFI_PHYSICAL_ADDRESS         *EntryPoint,
    719   OUT    UINT32                       *AuthenticationState
    720   )
    721 {
    722   return PeiLoadImageLoadImage (
    723            GetPeiServicesTablePointer (),
    724            FileHandle,
    725            ImageAddressArg,
    726            ImageSizeArg,
    727            EntryPoint,
    728            AuthenticationState
    729            );
    730 }
    731 
    732 /**
    733   Check whether the input image has the relocation.
    734 
    735   @param  Pe32Data   Pointer to the PE/COFF or TE image.
    736 
    737   @retval TRUE       Relocation is stripped.
    738   @retval FALSE      Relocation is not stripped.
    739 
    740 **/
    741 BOOLEAN
    742 RelocationIsStrip (
    743   IN VOID  *Pe32Data
    744   )
    745 {
    746   EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION  Hdr;
    747   EFI_IMAGE_DOS_HEADER                 *DosHdr;
    748 
    749   ASSERT (Pe32Data != NULL);
    750 
    751   DosHdr = (EFI_IMAGE_DOS_HEADER *)Pe32Data;
    752   if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) {
    753     //
    754     // DOS image header is present, so read the PE header after the DOS image header.
    755     //
    756     Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINTN) Pe32Data + (UINTN) ((DosHdr->e_lfanew) & 0x0ffff));
    757   } else {
    758     //
    759     // DOS image header is not present, so PE header is at the image base.
    760     //
    761     Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)Pe32Data;
    762   }
    763 
    764   //
    765   // Three cases with regards to relocations:
    766   // - Image has base relocs, RELOCS_STRIPPED==0    => image is relocatable
    767   // - Image has no base relocs, RELOCS_STRIPPED==1 => Image is not relocatable
    768   // - Image has no base relocs, RELOCS_STRIPPED==0 => Image is relocatable but
    769   //   has no base relocs to apply
    770   // Obviously having base relocations with RELOCS_STRIPPED==1 is invalid.
    771   //
    772   // Look at the file header to determine if relocations have been stripped, and
    773   // save this info in the image context for later use.
    774   //
    775   if (Hdr.Te->Signature == EFI_TE_IMAGE_HEADER_SIGNATURE) {
    776     if ((Hdr.Te->DataDirectory[0].Size == 0) && (Hdr.Te->DataDirectory[0].VirtualAddress == 0)) {
    777       return TRUE;
    778     } else {
    779       return FALSE;
    780     }
    781   } else if (Hdr.Pe32->Signature == EFI_IMAGE_NT_SIGNATURE)  {
    782     if ((Hdr.Pe32->FileHeader.Characteristics & EFI_IMAGE_FILE_RELOCS_STRIPPED) != 0) {
    783       return TRUE;
    784     } else {
    785       return FALSE;
    786     }
    787   }
    788 
    789   return FALSE;
    790 }
    791 
    792 /**
    793   Routine to load image file for subsequent execution by LoadFile Ppi.
    794   If any LoadFile Ppi is not found, the build-in support function for the PE32+/TE
    795   XIP image format is used.
    796 
    797   @param PeiServices     - An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation
    798   @param FileHandle      - Pointer to the FFS file header of the image.
    799   @param PeimState       - The dispatch state of the input PEIM handle.
    800   @param EntryPoint      - Pointer to entry point of specified image file for output.
    801   @param AuthenticationState - Pointer to attestation authentication state of image.
    802 
    803   @retval EFI_SUCCESS    - Image is successfully loaded.
    804   @retval EFI_NOT_FOUND  - Fail to locate necessary PPI
    805   @retval Others         - Fail to load file.
    806 
    807 **/
    808 EFI_STATUS
    809 PeiLoadImage (
    810   IN     CONST EFI_PEI_SERVICES       **PeiServices,
    811   IN     EFI_PEI_FILE_HANDLE          FileHandle,
    812   IN     UINT8                        PeimState,
    813   OUT    EFI_PHYSICAL_ADDRESS         *EntryPoint,
    814   OUT    UINT32                       *AuthenticationState
    815   )
    816 {
    817   EFI_STATUS              PpiStatus;
    818   EFI_STATUS              Status;
    819   UINTN                   Index;
    820   EFI_PEI_LOAD_FILE_PPI   *LoadFile;
    821   EFI_PHYSICAL_ADDRESS    ImageAddress;
    822   UINT64                  ImageSize;
    823   BOOLEAN                 IsStrip;
    824 
    825   IsStrip = FALSE;
    826   //
    827   // If any instances of PEI_LOAD_FILE_PPI are installed, they are called.
    828   // one at a time, until one reports EFI_SUCCESS.
    829   //
    830   Index = 0;
    831   do {
    832     PpiStatus = PeiServicesLocatePpi (
    833                   &gEfiPeiLoadFilePpiGuid,
    834                   Index,
    835                   NULL,
    836                   (VOID **)&LoadFile
    837                   );
    838     if (!EFI_ERROR (PpiStatus)) {
    839       Status = LoadFile->LoadFile (
    840                           LoadFile,
    841                           FileHandle,
    842                           &ImageAddress,
    843                           &ImageSize,
    844                           EntryPoint,
    845                           AuthenticationState
    846                           );
    847       if (!EFI_ERROR (Status) || Status == EFI_WARN_BUFFER_TOO_SMALL) {
    848         //
    849         // The shadowed PEIM must be relocatable.
    850         //
    851         if (PeimState == PEIM_STATE_REGISITER_FOR_SHADOW) {
    852           IsStrip = RelocationIsStrip ((VOID *) (UINTN) ImageAddress);
    853           ASSERT (!IsStrip);
    854           if (IsStrip) {
    855             return EFI_UNSUPPORTED;
    856           }
    857         }
    858 
    859         //
    860         // The image to be started must have the machine type supported by PeiCore.
    861         //
    862         ASSERT (EFI_IMAGE_MACHINE_TYPE_SUPPORTED (PeCoffLoaderGetMachineType ((VOID *) (UINTN) ImageAddress)));
    863         if (!EFI_IMAGE_MACHINE_TYPE_SUPPORTED (PeCoffLoaderGetMachineType ((VOID *) (UINTN) ImageAddress))) {
    864           return EFI_UNSUPPORTED;
    865         }
    866         return EFI_SUCCESS;
    867       }
    868     }
    869     Index++;
    870   } while (!EFI_ERROR (PpiStatus));
    871 
    872   return PpiStatus;
    873 }
    874 
    875 
    876 /**
    877 
    878   Install Pei Load File PPI.
    879 
    880 
    881   @param PrivateData     - Pointer to PEI_CORE_INSTANCE.
    882   @param OldCoreData     - Pointer to PEI_CORE_INSTANCE.
    883 
    884 **/
    885 VOID
    886 InitializeImageServices (
    887   IN  PEI_CORE_INSTANCE   *PrivateData,
    888   IN  PEI_CORE_INSTANCE   *OldCoreData
    889   )
    890 {
    891   if (OldCoreData == NULL) {
    892     //
    893     // The first time we are XIP (running from FLASH). We need to remember the
    894     // FLASH address so we can reinstall the memory version that runs faster
    895     //
    896     PrivateData->XipLoadFile = &gPpiLoadFilePpiList;
    897     PeiServicesInstallPpi (PrivateData->XipLoadFile);
    898   } else {
    899     //
    900     // 2nd time we are running from memory so replace the XIP version with the
    901     // new memory version.
    902     //
    903     PeiServicesReInstallPpi (PrivateData->XipLoadFile, &gPpiLoadFilePpiList);
    904   }
    905 }
    906 
    907 
    908 
    909 
    910