Home | History | Annotate | Download | only in Common
      1 /** @file
      2 
      3   Functions to get info and load PE/COFF image.
      4 
      5 Copyright (c) 2004 - 2016, Intel Corporation. All rights reserved.<BR>
      6 Portions Copyright (c) 2011 - 2013, ARM Ltd. All rights reserved.<BR>
      7 This program and the accompanying materials
      8 are licensed and made available under the terms and conditions of the BSD License
      9 which accompanies this distribution.  The full text of the license may be found at
     10 http://opensource.org/licenses/bsd-license.php
     11 
     12 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     13 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     14 
     15 **/
     16 
     17 #include <Common/UefiBaseTypes.h>
     18 #include <CommonLib.h>
     19 #include <IndustryStandard/PeImage.h>
     20 #include "PeCoffLib.h"
     21 
     22 typedef union {
     23   VOID                         *Header;
     24   EFI_IMAGE_OPTIONAL_HEADER32  *Optional32;
     25   EFI_IMAGE_OPTIONAL_HEADER64  *Optional64;
     26 } EFI_IMAGE_OPTIONAL_HEADER_POINTER;
     27 
     28 STATIC
     29 RETURN_STATUS
     30 PeCoffLoaderGetPeHeader (
     31   IN OUT PE_COFF_LOADER_IMAGE_CONTEXT    *ImageContext,
     32   OUT    EFI_IMAGE_OPTIONAL_HEADER_UNION **PeHdr,
     33   OUT    EFI_TE_IMAGE_HEADER             **TeHdr
     34   );
     35 
     36 STATIC
     37 RETURN_STATUS
     38 PeCoffLoaderCheckImageType (
     39   IN OUT PE_COFF_LOADER_IMAGE_CONTEXT    *ImageContext,
     40   IN     EFI_IMAGE_OPTIONAL_HEADER_UNION *PeHdr,
     41   IN     EFI_TE_IMAGE_HEADER             *TeHdr
     42   );
     43 
     44 STATIC
     45 VOID *
     46 PeCoffLoaderImageAddress (
     47   IN OUT PE_COFF_LOADER_IMAGE_CONTEXT  *ImageContext,
     48   IN     UINTN                         Address
     49   );
     50 
     51 RETURN_STATUS
     52 PeCoffLoaderRelocateIa32Image (
     53   IN UINT16      *Reloc,
     54   IN OUT CHAR8   *Fixup,
     55   IN OUT CHAR8   **FixupData,
     56   IN UINT64      Adjust
     57   );
     58 
     59 RETURN_STATUS
     60 PeCoffLoaderRelocateIpfImage (
     61   IN UINT16      *Reloc,
     62   IN OUT CHAR8   *Fixup,
     63   IN OUT CHAR8   **FixupData,
     64   IN UINT64      Adjust
     65   );
     66 
     67 RETURN_STATUS
     68 PeCoffLoaderRelocateArmImage (
     69   IN UINT16      **Reloc,
     70   IN OUT CHAR8   *Fixup,
     71   IN OUT CHAR8   **FixupData,
     72   IN UINT64      Adjust
     73   );
     74 
     75 STATIC
     76 RETURN_STATUS
     77 PeCoffLoaderGetPeHeader (
     78   IN OUT PE_COFF_LOADER_IMAGE_CONTEXT    *ImageContext,
     79   OUT    EFI_IMAGE_OPTIONAL_HEADER_UNION **PeHdr,
     80   OUT    EFI_TE_IMAGE_HEADER             **TeHdr
     81   )
     82 /*++
     83 
     84 Routine Description:
     85 
     86   Retrieves the PE or TE Header from a PE/COFF or TE image
     87 
     88 Arguments:
     89 
     90   ImageContext  - The context of the image being loaded
     91 
     92   PeHdr         - The buffer in which to return the PE header
     93 
     94   TeHdr         - The buffer in which to return the TE header
     95 
     96 Returns:
     97 
     98   RETURN_SUCCESS if the PE or TE Header is read,
     99   Otherwise, the error status from reading the PE/COFF or TE image using the ImageRead function.
    100 
    101 --*/
    102 {
    103   RETURN_STATUS         Status;
    104   EFI_IMAGE_DOS_HEADER  DosHdr;
    105   UINTN                 Size;
    106 
    107   ImageContext->IsTeImage = FALSE;
    108   //
    109   // Read the DOS image headers
    110   //
    111   Size = sizeof (EFI_IMAGE_DOS_HEADER);
    112   Status = ImageContext->ImageRead (
    113                           ImageContext->Handle,
    114                           0,
    115                           &Size,
    116                           &DosHdr
    117                           );
    118   if (RETURN_ERROR (Status)) {
    119     ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;
    120     return Status;
    121   }
    122 
    123   ImageContext->PeCoffHeaderOffset = 0;
    124   if (DosHdr.e_magic == EFI_IMAGE_DOS_SIGNATURE) {
    125     //
    126     // DOS image header is present, so read the PE header after the DOS image header
    127     //
    128     ImageContext->PeCoffHeaderOffset = DosHdr.e_lfanew;
    129   }
    130   //
    131   // Get the PE/COFF Header pointer
    132   //
    133   *PeHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *) ((UINTN)ImageContext->Handle + ImageContext->PeCoffHeaderOffset);
    134   if ((*PeHdr)->Pe32.Signature != EFI_IMAGE_NT_SIGNATURE) {
    135     //
    136     // Check the PE/COFF Header Signature. If not, then try to get a TE header
    137     //
    138     *TeHdr = (EFI_TE_IMAGE_HEADER *)*PeHdr;
    139     if ((*TeHdr)->Signature != EFI_TE_IMAGE_HEADER_SIGNATURE) {
    140       return RETURN_UNSUPPORTED;
    141     }
    142     ImageContext->IsTeImage = TRUE;
    143   }
    144 
    145   return RETURN_SUCCESS;
    146 }
    147 
    148 STATIC
    149 RETURN_STATUS
    150 PeCoffLoaderCheckImageType (
    151   IN OUT PE_COFF_LOADER_IMAGE_CONTEXT          *ImageContext,
    152   IN     EFI_IMAGE_OPTIONAL_HEADER_UNION       *PeHdr,
    153   IN     EFI_TE_IMAGE_HEADER                   *TeHdr
    154   )
    155 /*++
    156 
    157 Routine Description:
    158 
    159   Checks the PE or TE header of a PE/COFF or TE image to determine if it supported
    160 
    161 Arguments:
    162 
    163   ImageContext  - The context of the image being loaded
    164 
    165   PeHdr         - The buffer in which to return the PE header
    166 
    167   TeHdr         - The buffer in which to return the TE header
    168 
    169 Returns:
    170 
    171   RETURN_SUCCESS if the PE/COFF or TE image is supported
    172   RETURN_UNSUPPORTED of the PE/COFF or TE image is not supported.
    173 
    174 --*/
    175 {
    176   //
    177   // See if the machine type is supported.
    178   // We support a native machine type (IA-32/Itanium-based)
    179   //
    180   if (ImageContext->IsTeImage == FALSE) {
    181     ImageContext->Machine = PeHdr->Pe32.FileHeader.Machine;
    182   } else {
    183     ImageContext->Machine = TeHdr->Machine;
    184   }
    185 
    186   if (ImageContext->Machine != EFI_IMAGE_MACHINE_IA32 && \
    187       ImageContext->Machine != EFI_IMAGE_MACHINE_IA64 && \
    188       ImageContext->Machine != EFI_IMAGE_MACHINE_X64  && \
    189       ImageContext->Machine != EFI_IMAGE_MACHINE_ARMT && \
    190       ImageContext->Machine != EFI_IMAGE_MACHINE_EBC  && \
    191       ImageContext->Machine != EFI_IMAGE_MACHINE_AARCH64) {
    192     if (ImageContext->Machine == IMAGE_FILE_MACHINE_ARM) {
    193       //
    194       // There are two types of ARM images. Pure ARM and ARM/Thumb.
    195       // If we see the ARM say it is the ARM/Thumb so there is only
    196       // a single machine type we need to check for ARM.
    197       //
    198       ImageContext->Machine = EFI_IMAGE_MACHINE_ARMT;
    199       if (ImageContext->IsTeImage == FALSE) {
    200         PeHdr->Pe32.FileHeader.Machine = ImageContext->Machine;
    201       } else {
    202         TeHdr->Machine = ImageContext->Machine;
    203       }
    204 
    205     } else {
    206       //
    207       // unsupported PeImage machine type
    208       //
    209       return RETURN_UNSUPPORTED;
    210     }
    211   }
    212 
    213   //
    214   // See if the image type is supported.  We support EFI Applications,
    215   // EFI Boot Service Drivers, EFI Runtime Drivers and EFI SAL Drivers.
    216   //
    217   if (ImageContext->IsTeImage == FALSE) {
    218     ImageContext->ImageType = PeHdr->Pe32.OptionalHeader.Subsystem;
    219   } else {
    220     ImageContext->ImageType = (UINT16) (TeHdr->Subsystem);
    221   }
    222 
    223   if (ImageContext->ImageType != EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION && \
    224       ImageContext->ImageType != EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER && \
    225       ImageContext->ImageType != EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER && \
    226       ImageContext->ImageType != EFI_IMAGE_SUBSYSTEM_SAL_RUNTIME_DRIVER) {
    227     //
    228     // upsupported PeImage subsystem type
    229     //
    230     return RETURN_UNSUPPORTED;
    231   }
    232 
    233   return RETURN_SUCCESS;
    234 }
    235 
    236 RETURN_STATUS
    237 EFIAPI
    238 PeCoffLoaderGetImageInfo (
    239   IN OUT PE_COFF_LOADER_IMAGE_CONTEXT           *ImageContext
    240   )
    241 /*++
    242 
    243 Routine Description:
    244 
    245   Retrieves information on a PE/COFF image
    246 
    247 Arguments:
    248 
    249   This         - Calling context
    250   ImageContext - The context of the image being loaded
    251 
    252 Returns:
    253 
    254   RETURN_SUCCESS           - The information on the PE/COFF image was collected.
    255   RETURN_INVALID_PARAMETER - ImageContext is NULL.
    256   RETURN_UNSUPPORTED       - The PE/COFF image is not supported.
    257   Otherwise             - The error status from reading the PE/COFF image using the
    258                           ImageContext->ImageRead() function
    259 
    260 --*/
    261 {
    262   RETURN_STATUS                   Status;
    263   EFI_IMAGE_OPTIONAL_HEADER_UNION *PeHdr;
    264   EFI_TE_IMAGE_HEADER             *TeHdr;
    265   EFI_IMAGE_DATA_DIRECTORY        *DebugDirectoryEntry;
    266   UINTN                           Size;
    267   UINTN                           Index;
    268   UINTN                           DebugDirectoryEntryRva;
    269   UINTN                           DebugDirectoryEntryFileOffset;
    270   UINTN                           SectionHeaderOffset;
    271   EFI_IMAGE_SECTION_HEADER        SectionHeader;
    272   EFI_IMAGE_DEBUG_DIRECTORY_ENTRY DebugEntry;
    273   EFI_IMAGE_OPTIONAL_HEADER_POINTER OptionHeader;
    274 
    275   PeHdr = NULL;
    276   TeHdr = NULL;
    277   DebugDirectoryEntry    = NULL;
    278   DebugDirectoryEntryRva = 0;
    279 
    280   if (NULL == ImageContext) {
    281     return RETURN_INVALID_PARAMETER;
    282   }
    283   //
    284   // Assume success
    285   //
    286   ImageContext->ImageError  = IMAGE_ERROR_SUCCESS;
    287 
    288   Status                    = PeCoffLoaderGetPeHeader (ImageContext, &PeHdr, &TeHdr);
    289   if (RETURN_ERROR (Status)) {
    290     return Status;
    291   }
    292 
    293   //
    294   // Verify machine type
    295   //
    296   Status = PeCoffLoaderCheckImageType (ImageContext, PeHdr, TeHdr);
    297   if (RETURN_ERROR (Status)) {
    298     return Status;
    299   }
    300   OptionHeader.Header = (VOID *) &(PeHdr->Pe32.OptionalHeader);
    301 
    302   //
    303   // Retrieve the base address of the image
    304   //
    305   if (!(ImageContext->IsTeImage)) {
    306     if (PeHdr->Pe32.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
    307       ImageContext->ImageAddress = (PHYSICAL_ADDRESS) OptionHeader.Optional32->ImageBase;
    308     } else {
    309       ImageContext->ImageAddress = (PHYSICAL_ADDRESS) OptionHeader.Optional64->ImageBase;
    310     }
    311   } else {
    312     ImageContext->ImageAddress = (PHYSICAL_ADDRESS) (TeHdr->ImageBase + TeHdr->StrippedSize - sizeof (EFI_TE_IMAGE_HEADER));
    313   }
    314   //
    315   // Initialize the alternate destination address to 0 indicating that it
    316   // should not be used.
    317   //
    318   ImageContext->DestinationAddress = 0;
    319 
    320   //
    321   // Initialize the codeview pointer.
    322   //
    323   ImageContext->CodeView    = NULL;
    324   ImageContext->PdbPointer  = NULL;
    325 
    326   //
    327   // Three cases with regards to relocations:
    328   // - Image has base relocs, RELOCS_STRIPPED==0    => image is relocatable
    329   // - Image has no base relocs, RELOCS_STRIPPED==1 => Image is not relocatable
    330   // - Image has no base relocs, RELOCS_STRIPPED==0 => Image is relocatable but
    331   //   has no base relocs to apply
    332   // Obviously having base relocations with RELOCS_STRIPPED==1 is invalid.
    333   //
    334   // Look at the file header to determine if relocations have been stripped, and
    335   // save this info in the image context for later use.
    336   //
    337   if ((!(ImageContext->IsTeImage)) && ((PeHdr->Pe32.FileHeader.Characteristics & EFI_IMAGE_FILE_RELOCS_STRIPPED) != 0)) {
    338     ImageContext->RelocationsStripped = TRUE;
    339   } else if ((ImageContext->IsTeImage) && (TeHdr->DataDirectory[0].Size == 0) && (TeHdr->DataDirectory[0].VirtualAddress == 0)) {
    340     ImageContext->RelocationsStripped = TRUE;
    341   } else {
    342     ImageContext->RelocationsStripped = FALSE;
    343   }
    344 
    345   if (!(ImageContext->IsTeImage)) {
    346 
    347     if (PeHdr->Pe32.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
    348       ImageContext->ImageSize         = (UINT64) OptionHeader.Optional32->SizeOfImage;
    349       ImageContext->SectionAlignment  = OptionHeader.Optional32->SectionAlignment;
    350       ImageContext->SizeOfHeaders     = OptionHeader.Optional32->SizeOfHeaders;
    351 
    352       //
    353       // Modify ImageSize to contain .PDB file name if required and initialize
    354       // PdbRVA field...
    355       //
    356       if (OptionHeader.Optional32->NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_DEBUG) {
    357         DebugDirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *) &(OptionHeader.Optional32->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG]);
    358         DebugDirectoryEntryRva = DebugDirectoryEntry->VirtualAddress;
    359       }
    360     } else {
    361       ImageContext->ImageSize         = (UINT64) OptionHeader.Optional64->SizeOfImage;
    362       ImageContext->SectionAlignment  = OptionHeader.Optional64->SectionAlignment;
    363       ImageContext->SizeOfHeaders     = OptionHeader.Optional64->SizeOfHeaders;
    364 
    365       //
    366       // Modify ImageSize to contain .PDB file name if required and initialize
    367       // PdbRVA field...
    368       //
    369       if (OptionHeader.Optional64->NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_DEBUG) {
    370         DebugDirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *) &(OptionHeader.Optional64->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG]);
    371         DebugDirectoryEntryRva = DebugDirectoryEntry->VirtualAddress;
    372       }
    373     }
    374 
    375     if (DebugDirectoryEntryRva != 0) {
    376       //
    377       // Determine the file offset of the debug directory...  This means we walk
    378       // the sections to find which section contains the RVA of the debug
    379       // directory
    380       //
    381       DebugDirectoryEntryFileOffset = 0;
    382 
    383       SectionHeaderOffset = (UINTN)(
    384                                ImageContext->PeCoffHeaderOffset +
    385                                sizeof (UINT32) +
    386                                sizeof (EFI_IMAGE_FILE_HEADER) +
    387                                PeHdr->Pe32.FileHeader.SizeOfOptionalHeader
    388                                );
    389 
    390       for (Index = 0; Index < PeHdr->Pe32.FileHeader.NumberOfSections; Index++) {
    391         //
    392         // Read section header from file
    393         //
    394         Size = sizeof (EFI_IMAGE_SECTION_HEADER);
    395         Status = ImageContext->ImageRead (
    396                                  ImageContext->Handle,
    397                                  SectionHeaderOffset,
    398                                  &Size,
    399                                  &SectionHeader
    400                                  );
    401         if (RETURN_ERROR (Status)) {
    402           ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;
    403           return Status;
    404         }
    405 
    406         if (DebugDirectoryEntryRva >= SectionHeader.VirtualAddress &&
    407             DebugDirectoryEntryRva < SectionHeader.VirtualAddress + SectionHeader.Misc.VirtualSize) {
    408             DebugDirectoryEntryFileOffset =
    409             DebugDirectoryEntryRva - SectionHeader.VirtualAddress + SectionHeader.PointerToRawData;
    410           break;
    411         }
    412 
    413         SectionHeaderOffset += sizeof (EFI_IMAGE_SECTION_HEADER);
    414       }
    415 
    416       if (DebugDirectoryEntryFileOffset != 0) {
    417         for (Index = 0; Index < DebugDirectoryEntry->Size; Index += sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY)) {
    418           //
    419           // Read next debug directory entry
    420           //
    421           Size = sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY);
    422           Status = ImageContext->ImageRead (
    423                                    ImageContext->Handle,
    424                                    DebugDirectoryEntryFileOffset + Index,
    425                                    &Size,
    426                                    &DebugEntry
    427                                    );
    428           if (RETURN_ERROR (Status)) {
    429             ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;
    430             return Status;
    431           }
    432 
    433           if (DebugEntry.Type == EFI_IMAGE_DEBUG_TYPE_CODEVIEW) {
    434             ImageContext->DebugDirectoryEntryRva = (UINT32) (DebugDirectoryEntryRva + Index);
    435             if (DebugEntry.RVA == 0 && DebugEntry.FileOffset != 0) {
    436               ImageContext->ImageSize += DebugEntry.SizeOfData;
    437             }
    438 
    439             return RETURN_SUCCESS;
    440           }
    441         }
    442       }
    443     }
    444   } else {
    445     ImageContext->ImageSize         = 0;
    446     ImageContext->SectionAlignment  = 4096;
    447     ImageContext->SizeOfHeaders     = sizeof (EFI_TE_IMAGE_HEADER) + (UINTN) TeHdr->BaseOfCode - (UINTN) TeHdr->StrippedSize;
    448 
    449     DebugDirectoryEntry             = &TeHdr->DataDirectory[1];
    450     DebugDirectoryEntryRva          = DebugDirectoryEntry->VirtualAddress;
    451     SectionHeaderOffset             = (UINTN) (sizeof (EFI_TE_IMAGE_HEADER));
    452 
    453     DebugDirectoryEntryFileOffset   = 0;
    454 
    455     for (Index = 0; Index < TeHdr->NumberOfSections;) {
    456       //
    457       // Read section header from file
    458       //
    459       Size = sizeof (EFI_IMAGE_SECTION_HEADER);
    460       Status = ImageContext->ImageRead (
    461                                ImageContext->Handle,
    462                                SectionHeaderOffset,
    463                                &Size,
    464                                &SectionHeader
    465                                );
    466       if (RETURN_ERROR (Status)) {
    467         ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;
    468         return Status;
    469       }
    470 
    471       if (DebugDirectoryEntryRva >= SectionHeader.VirtualAddress &&
    472           DebugDirectoryEntryRva < SectionHeader.VirtualAddress + SectionHeader.Misc.VirtualSize) {
    473         DebugDirectoryEntryFileOffset = DebugDirectoryEntryRva -
    474           SectionHeader.VirtualAddress +
    475           SectionHeader.PointerToRawData +
    476           sizeof (EFI_TE_IMAGE_HEADER) -
    477           TeHdr->StrippedSize;
    478 
    479         //
    480         // File offset of the debug directory was found, if this is not the last
    481         // section, then skip to the last section for calculating the image size.
    482         //
    483         if (Index < (UINTN) TeHdr->NumberOfSections - 1) {
    484           SectionHeaderOffset += (TeHdr->NumberOfSections - 1 - Index) * sizeof (EFI_IMAGE_SECTION_HEADER);
    485           Index = TeHdr->NumberOfSections - 1;
    486           continue;
    487         }
    488       }
    489 
    490       //
    491       // In Te image header there is not a field to describe the ImageSize.
    492       // Actually, the ImageSize equals the RVA plus the VirtualSize of
    493       // the last section mapped into memory (Must be rounded up to
    494       // a mulitple of Section Alignment). Per the PE/COFF specification, the
    495       // section headers in the Section Table must appear in order of the RVA
    496       // values for the corresponding sections. So the ImageSize can be determined
    497       // by the RVA and the VirtualSize of the last section header in the
    498       // Section Table.
    499       //
    500       if ((++Index) == (UINTN) TeHdr->NumberOfSections) {
    501         ImageContext->ImageSize = (SectionHeader.VirtualAddress + SectionHeader.Misc.VirtualSize +
    502                                    ImageContext->SectionAlignment - 1) & ~(ImageContext->SectionAlignment - 1);
    503       }
    504 
    505       SectionHeaderOffset += sizeof (EFI_IMAGE_SECTION_HEADER);
    506     }
    507 
    508     if (DebugDirectoryEntryFileOffset != 0) {
    509       for (Index = 0; Index < DebugDirectoryEntry->Size; Index += sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY)) {
    510         //
    511         // Read next debug directory entry
    512         //
    513         Size = sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY);
    514         Status = ImageContext->ImageRead (
    515                                  ImageContext->Handle,
    516                                  DebugDirectoryEntryFileOffset,
    517                                  &Size,
    518                                  &DebugEntry
    519                                  );
    520         if (RETURN_ERROR (Status)) {
    521           ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;
    522           return Status;
    523         }
    524 
    525         if (DebugEntry.Type == EFI_IMAGE_DEBUG_TYPE_CODEVIEW) {
    526           ImageContext->DebugDirectoryEntryRva = (UINT32) (DebugDirectoryEntryRva + Index);
    527           return RETURN_SUCCESS;
    528         }
    529       }
    530     }
    531   }
    532 
    533   return RETURN_SUCCESS;
    534 }
    535 
    536 STATIC
    537 VOID *
    538 PeCoffLoaderImageAddress (
    539   IN OUT PE_COFF_LOADER_IMAGE_CONTEXT          *ImageContext,
    540   IN     UINTN                                 Address
    541   )
    542 /*++
    543 
    544 Routine Description:
    545 
    546   Converts an image address to the loaded address
    547 
    548 Arguments:
    549 
    550   ImageContext  - The context of the image being loaded
    551 
    552   Address       - The address to be converted to the loaded address
    553 
    554 Returns:
    555 
    556   NULL if the address can not be converted, otherwise, the converted address
    557 
    558 --*/
    559 {
    560   if (Address >= ImageContext->ImageSize) {
    561     ImageContext->ImageError = IMAGE_ERROR_INVALID_IMAGE_ADDRESS;
    562     return NULL;
    563   }
    564 
    565   return (UINT8 *) ((UINTN) ImageContext->ImageAddress + Address);
    566 }
    567 
    568 RETURN_STATUS
    569 EFIAPI
    570 PeCoffLoaderRelocateImage (
    571   IN OUT PE_COFF_LOADER_IMAGE_CONTEXT  *ImageContext
    572   )
    573 /*++
    574 
    575 Routine Description:
    576 
    577   Relocates a PE/COFF image in memory
    578 
    579 Arguments:
    580 
    581   This         - Calling context
    582 
    583   ImageContext - Contains information on the loaded image to relocate
    584 
    585 Returns:
    586 
    587   RETURN_SUCCESS      if the PE/COFF image was relocated
    588   RETURN_LOAD_ERROR   if the image is not a valid PE/COFF image
    589   RETURN_UNSUPPORTED  not support
    590 
    591 --*/
    592 {
    593   RETURN_STATUS                         Status;
    594   EFI_IMAGE_OPTIONAL_HEADER_UNION       *PeHdr;
    595   EFI_TE_IMAGE_HEADER                   *TeHdr;
    596   EFI_IMAGE_DATA_DIRECTORY              *RelocDir;
    597   UINT64                                Adjust;
    598   EFI_IMAGE_BASE_RELOCATION             *RelocBase;
    599   EFI_IMAGE_BASE_RELOCATION             *RelocBaseEnd;
    600   UINT16                                *Reloc;
    601   UINT16                                *RelocEnd;
    602   CHAR8                                 *Fixup;
    603   CHAR8                                 *FixupBase;
    604   UINT16                                *F16;
    605   UINT32                                *F32;
    606   UINT64                                *F64;
    607   CHAR8                                 *FixupData;
    608   PHYSICAL_ADDRESS                      BaseAddress;
    609   UINT16                                MachineType;
    610   EFI_IMAGE_OPTIONAL_HEADER_POINTER     OptionHeader;
    611 
    612   PeHdr = NULL;
    613   TeHdr = NULL;
    614   //
    615   // Assume success
    616   //
    617   ImageContext->ImageError = IMAGE_ERROR_SUCCESS;
    618 
    619   //
    620   // If there are no relocation entries, then we are done
    621   //
    622   if (ImageContext->RelocationsStripped) {
    623     return RETURN_SUCCESS;
    624   }
    625 
    626   //
    627   // Use DestinationAddress field of ImageContext as the relocation address even if it is 0.
    628   //
    629   BaseAddress = ImageContext->DestinationAddress;
    630 
    631   if (!(ImageContext->IsTeImage)) {
    632     PeHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)((UINTN)ImageContext->ImageAddress +
    633                                             ImageContext->PeCoffHeaderOffset);
    634     OptionHeader.Header = (VOID *) &(PeHdr->Pe32.OptionalHeader);
    635     if (PeHdr->Pe32.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
    636       Adjust = (UINT64) BaseAddress - OptionHeader.Optional32->ImageBase;
    637       OptionHeader.Optional32->ImageBase = (UINT32) BaseAddress;
    638       MachineType = ImageContext->Machine;
    639       //
    640       // Find the relocation block
    641       //
    642       // Per the PE/COFF spec, you can't assume that a given data directory
    643       // is present in the image. You have to check the NumberOfRvaAndSizes in
    644       // the optional header to verify a desired directory entry is there.
    645       //
    646       if (OptionHeader.Optional32->NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC) {
    647         RelocDir  = &OptionHeader.Optional32->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC];
    648         if ((RelocDir != NULL) && (RelocDir->Size > 0)) {
    649           RelocBase = PeCoffLoaderImageAddress (ImageContext, RelocDir->VirtualAddress);
    650           RelocBaseEnd = PeCoffLoaderImageAddress (
    651                            ImageContext,
    652                            RelocDir->VirtualAddress + RelocDir->Size - 1
    653                            );
    654           if (RelocBase == NULL || RelocBaseEnd == NULL || RelocBaseEnd < RelocBase) {
    655             ImageContext->ImageError = IMAGE_ERROR_FAILED_RELOCATION;
    656             return RETURN_LOAD_ERROR;
    657           }
    658         } else {
    659           //
    660           // Set base and end to bypass processing below.
    661           //
    662           RelocBase = RelocBaseEnd = 0;
    663         }
    664       } else {
    665         //
    666         // Set base and end to bypass processing below.
    667         //
    668         RelocBase = RelocBaseEnd = 0;
    669       }
    670     } else {
    671       Adjust = (UINT64) BaseAddress - OptionHeader.Optional64->ImageBase;
    672       OptionHeader.Optional64->ImageBase = BaseAddress;
    673       MachineType = ImageContext->Machine;
    674       //
    675       // Find the relocation block
    676       //
    677       // Per the PE/COFF spec, you can't assume that a given data directory
    678       // is present in the image. You have to check the NumberOfRvaAndSizes in
    679       // the optional header to verify a desired directory entry is there.
    680       //
    681       if (OptionHeader.Optional64->NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC) {
    682         RelocDir  = &OptionHeader.Optional64->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC];
    683         if ((RelocDir != NULL) && (RelocDir->Size > 0)) {
    684           RelocBase = PeCoffLoaderImageAddress (ImageContext, RelocDir->VirtualAddress);
    685           RelocBaseEnd = PeCoffLoaderImageAddress (
    686                            ImageContext,
    687                            RelocDir->VirtualAddress + RelocDir->Size - 1
    688                           );
    689           if (RelocBase == NULL || RelocBaseEnd == NULL || RelocBaseEnd < RelocBase) {
    690             ImageContext->ImageError = IMAGE_ERROR_FAILED_RELOCATION;
    691             return RETURN_LOAD_ERROR;
    692           }
    693         } else {
    694           //
    695           // Set base and end to bypass processing below.
    696           //
    697           RelocBase = RelocBaseEnd = 0;
    698         }
    699       } else {
    700         //
    701         // Set base and end to bypass processing below.
    702         //
    703         RelocBase = RelocBaseEnd = 0;
    704       }
    705     }
    706   } else {
    707     TeHdr             = (EFI_TE_IMAGE_HEADER *) (UINTN) (ImageContext->ImageAddress);
    708     Adjust            = (UINT64) (BaseAddress - TeHdr->ImageBase);
    709     TeHdr->ImageBase  = (UINT64) (BaseAddress);
    710     MachineType = TeHdr->Machine;
    711 
    712     //
    713     // Find the relocation block
    714     //
    715     RelocDir = &TeHdr->DataDirectory[0];
    716     RelocBase = (EFI_IMAGE_BASE_RELOCATION *)(UINTN)(
    717                                     ImageContext->ImageAddress +
    718                                     RelocDir->VirtualAddress +
    719                                     sizeof(EFI_TE_IMAGE_HEADER) -
    720                                     TeHdr->StrippedSize
    721                                     );
    722     RelocBaseEnd = (EFI_IMAGE_BASE_RELOCATION *) ((UINTN) RelocBase + (UINTN) RelocDir->Size - 1);
    723   }
    724 
    725   //
    726   // Run the relocation information and apply the fixups
    727   //
    728   FixupData = ImageContext->FixupData;
    729   while (RelocBase < RelocBaseEnd) {
    730 
    731     Reloc     = (UINT16 *) ((CHAR8 *) RelocBase + sizeof (EFI_IMAGE_BASE_RELOCATION));
    732     RelocEnd  = (UINT16 *) ((CHAR8 *) RelocBase + RelocBase->SizeOfBlock);
    733     if (!(ImageContext->IsTeImage)) {
    734       FixupBase = PeCoffLoaderImageAddress (ImageContext, RelocBase->VirtualAddress);
    735       if (FixupBase == NULL) {
    736         ImageContext->ImageError = IMAGE_ERROR_FAILED_RELOCATION;
    737         return RETURN_LOAD_ERROR;
    738       }
    739     } else {
    740       FixupBase = (CHAR8 *)(UINTN)(ImageContext->ImageAddress +
    741                     RelocBase->VirtualAddress +
    742                     sizeof(EFI_TE_IMAGE_HEADER) -
    743                     TeHdr->StrippedSize
    744                     );
    745     }
    746 
    747     if ((CHAR8 *) RelocEnd < (CHAR8 *) ((UINTN) ImageContext->ImageAddress) ||
    748         (CHAR8 *) RelocEnd > (CHAR8 *)((UINTN)ImageContext->ImageAddress +
    749           (UINTN)ImageContext->ImageSize)) {
    750       ImageContext->ImageError = IMAGE_ERROR_FAILED_RELOCATION;
    751       return RETURN_LOAD_ERROR;
    752     }
    753 
    754     //
    755     // Run this relocation record
    756     //
    757     while (Reloc < RelocEnd) {
    758 
    759       Fixup = FixupBase + (*Reloc & 0xFFF);
    760       switch ((*Reloc) >> 12) {
    761       case EFI_IMAGE_REL_BASED_ABSOLUTE:
    762         break;
    763 
    764       case EFI_IMAGE_REL_BASED_HIGH:
    765         F16   = (UINT16 *) Fixup;
    766         *F16 = (UINT16) (*F16 + ((UINT16) ((UINT32) Adjust >> 16)));
    767         if (FixupData != NULL) {
    768           *(UINT16 *) FixupData = *F16;
    769           FixupData             = FixupData + sizeof (UINT16);
    770         }
    771         break;
    772 
    773       case EFI_IMAGE_REL_BASED_LOW:
    774         F16   = (UINT16 *) Fixup;
    775         *F16  = (UINT16) (*F16 + (UINT16) Adjust);
    776         if (FixupData != NULL) {
    777           *(UINT16 *) FixupData = *F16;
    778           FixupData             = FixupData + sizeof (UINT16);
    779         }
    780         break;
    781 
    782       case EFI_IMAGE_REL_BASED_HIGHLOW:
    783         F32   = (UINT32 *) Fixup;
    784         *F32  = *F32 + (UINT32) Adjust;
    785         if (FixupData != NULL) {
    786           FixupData             = ALIGN_POINTER (FixupData, sizeof (UINT32));
    787           *(UINT32 *) FixupData = *F32;
    788           FixupData             = FixupData + sizeof (UINT32);
    789         }
    790         break;
    791 
    792       case EFI_IMAGE_REL_BASED_DIR64:
    793         F64   = (UINT64 *) Fixup;
    794         *F64  = *F64 + (UINT64) Adjust;
    795         if (FixupData != NULL) {
    796           FixupData             = ALIGN_POINTER (FixupData, sizeof (UINT64));
    797           *(UINT64 *) FixupData = *F64;
    798           FixupData             = FixupData + sizeof (UINT64);
    799         }
    800         break;
    801 
    802       case EFI_IMAGE_REL_BASED_HIGHADJ:
    803         //
    804         // Return the same EFI_UNSUPPORTED return code as
    805         // PeCoffLoaderRelocateImageEx() returns if it does not recognize
    806         // the relocation type.
    807         //
    808         ImageContext->ImageError = IMAGE_ERROR_FAILED_RELOCATION;
    809         return RETURN_UNSUPPORTED;
    810 
    811       default:
    812         switch (MachineType) {
    813         case EFI_IMAGE_MACHINE_IA32:
    814           Status = PeCoffLoaderRelocateIa32Image (Reloc, Fixup, &FixupData, Adjust);
    815           break;
    816         case EFI_IMAGE_MACHINE_ARMT:
    817           Status = PeCoffLoaderRelocateArmImage (&Reloc, Fixup, &FixupData, Adjust);
    818           break;
    819         case EFI_IMAGE_MACHINE_IA64:
    820           Status = PeCoffLoaderRelocateIpfImage (Reloc, Fixup, &FixupData, Adjust);
    821           break;
    822         default:
    823           Status = RETURN_UNSUPPORTED;
    824           break;
    825         }
    826         if (RETURN_ERROR (Status)) {
    827           ImageContext->ImageError = IMAGE_ERROR_FAILED_RELOCATION;
    828           return Status;
    829         }
    830       }
    831 
    832       //
    833       // Next relocation record
    834       //
    835       Reloc += 1;
    836     }
    837 
    838     //
    839     // Next reloc block
    840     //
    841     RelocBase = (EFI_IMAGE_BASE_RELOCATION *) RelocEnd;
    842   }
    843 
    844   return RETURN_SUCCESS;
    845 }
    846 
    847 RETURN_STATUS
    848 EFIAPI
    849 PeCoffLoaderLoadImage (
    850   IN OUT PE_COFF_LOADER_IMAGE_CONTEXT  *ImageContext
    851   )
    852 /*++
    853 
    854 Routine Description:
    855 
    856   Loads a PE/COFF image into memory
    857 
    858 Arguments:
    859 
    860   This         - Calling context
    861 
    862   ImageContext - Contains information on image to load into memory
    863 
    864 Returns:
    865 
    866   RETURN_SUCCESS            if the PE/COFF image was loaded
    867   RETURN_BUFFER_TOO_SMALL   if the caller did not provide a large enough buffer
    868   RETURN_LOAD_ERROR         if the image is a runtime driver with no relocations
    869   RETURN_INVALID_PARAMETER  if the image address is invalid
    870 
    871 --*/
    872 {
    873   RETURN_STATUS                         Status;
    874   EFI_IMAGE_OPTIONAL_HEADER_UNION       *PeHdr;
    875   EFI_TE_IMAGE_HEADER                   *TeHdr;
    876   PE_COFF_LOADER_IMAGE_CONTEXT          CheckContext;
    877   EFI_IMAGE_SECTION_HEADER              *FirstSection;
    878   EFI_IMAGE_SECTION_HEADER              *Section;
    879   UINTN                                 NumberOfSections;
    880   UINTN                                 Index;
    881   CHAR8                                 *Base;
    882   CHAR8                                 *End;
    883   CHAR8                                 *MaxEnd;
    884   EFI_IMAGE_DATA_DIRECTORY              *DirectoryEntry;
    885   EFI_IMAGE_DEBUG_DIRECTORY_ENTRY       *DebugEntry;
    886   UINTN                                 Size;
    887   UINT32                                TempDebugEntryRva;
    888   EFI_IMAGE_OPTIONAL_HEADER_POINTER     OptionHeader;
    889 
    890   PeHdr = NULL;
    891   TeHdr = NULL;
    892   OptionHeader.Header = NULL;
    893   //
    894   // Assume success
    895   //
    896   ImageContext->ImageError = IMAGE_ERROR_SUCCESS;
    897 
    898   //
    899   // Copy the provided context info into our local version, get what we
    900   // can from the original image, and then use that to make sure everything
    901   // is legit.
    902   //
    903   CopyMem (&CheckContext, ImageContext, sizeof (PE_COFF_LOADER_IMAGE_CONTEXT));
    904 
    905   Status = PeCoffLoaderGetImageInfo (&CheckContext);
    906   if (RETURN_ERROR (Status)) {
    907     return Status;
    908   }
    909 
    910   //
    911   // Make sure there is enough allocated space for the image being loaded
    912   //
    913   if (ImageContext->ImageSize < CheckContext.ImageSize) {
    914     ImageContext->ImageError = IMAGE_ERROR_INVALID_IMAGE_SIZE;
    915     return RETURN_BUFFER_TOO_SMALL;
    916   }
    917 
    918   //
    919   // If there's no relocations, then make sure it's not a runtime driver,
    920   // and that it's being loaded at the linked address.
    921   //
    922   if (CheckContext.RelocationsStripped) {
    923     //
    924     // If the image does not contain relocations and it is a runtime driver
    925     // then return an error.
    926     //
    927     if (CheckContext.ImageType == EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER) {
    928       ImageContext->ImageError = IMAGE_ERROR_INVALID_SUBSYSTEM;
    929       return RETURN_LOAD_ERROR;
    930     }
    931     //
    932     // If the image does not contain relocations, and the requested load address
    933     // is not the linked address, then return an error.
    934     //
    935     if (CheckContext.ImageAddress != ImageContext->ImageAddress) {
    936       ImageContext->ImageError = IMAGE_ERROR_INVALID_IMAGE_ADDRESS;
    937       return RETURN_INVALID_PARAMETER;
    938     }
    939   }
    940   //
    941   // Make sure the allocated space has the proper section alignment
    942   //
    943   if (!(ImageContext->IsTeImage)) {
    944     if ((ImageContext->ImageAddress & (CheckContext.SectionAlignment - 1)) != 0) {
    945       ImageContext->ImageError = IMAGE_ERROR_INVALID_SECTION_ALIGNMENT;
    946       return RETURN_INVALID_PARAMETER;
    947     }
    948   }
    949   //
    950   // Read the entire PE/COFF or TE header into memory
    951   //
    952   if (!(ImageContext->IsTeImage)) {
    953     Status = ImageContext->ImageRead (
    954                             ImageContext->Handle,
    955                             0,
    956                             &ImageContext->SizeOfHeaders,
    957                             (VOID *) (UINTN) ImageContext->ImageAddress
    958                             );
    959 
    960     PeHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)
    961       ((UINTN)ImageContext->ImageAddress + ImageContext->PeCoffHeaderOffset);
    962 
    963     OptionHeader.Header = (VOID *) &(PeHdr->Pe32.OptionalHeader);
    964 
    965     FirstSection = (EFI_IMAGE_SECTION_HEADER *) (
    966                       (UINTN)ImageContext->ImageAddress +
    967                       ImageContext->PeCoffHeaderOffset +
    968                       sizeof(UINT32) +
    969                       sizeof(EFI_IMAGE_FILE_HEADER) +
    970                       PeHdr->Pe32.FileHeader.SizeOfOptionalHeader
    971       );
    972     NumberOfSections = (UINTN) (PeHdr->Pe32.FileHeader.NumberOfSections);
    973   } else {
    974     Status = ImageContext->ImageRead (
    975                             ImageContext->Handle,
    976                             0,
    977                             &ImageContext->SizeOfHeaders,
    978                             (VOID *) (UINTN) ImageContext->ImageAddress
    979                             );
    980 
    981     TeHdr             = (EFI_TE_IMAGE_HEADER *) (UINTN) (ImageContext->ImageAddress);
    982 
    983     FirstSection = (EFI_IMAGE_SECTION_HEADER *) (
    984           (UINTN)ImageContext->ImageAddress +
    985           sizeof(EFI_TE_IMAGE_HEADER)
    986           );
    987     NumberOfSections  = (UINTN) (TeHdr->NumberOfSections);
    988 
    989   }
    990 
    991   if (RETURN_ERROR (Status)) {
    992     ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;
    993     return RETURN_LOAD_ERROR;
    994   }
    995 
    996   //
    997   // Load each section of the image
    998   //
    999   Section = FirstSection;
   1000   for (Index = 0, MaxEnd = NULL; Index < NumberOfSections; Index++) {
   1001 
   1002     //
   1003     // Compute sections address
   1004     //
   1005     Base = PeCoffLoaderImageAddress (ImageContext, Section->VirtualAddress);
   1006     End = PeCoffLoaderImageAddress (
   1007             ImageContext,
   1008             Section->VirtualAddress + Section->Misc.VirtualSize - 1
   1009             );
   1010 
   1011     //
   1012     // If the base start or end address resolved to 0, then fail.
   1013     //
   1014     if ((Base == NULL) || (End == NULL)) {
   1015       ImageContext->ImageError = IMAGE_ERROR_SECTION_NOT_LOADED;
   1016       return RETURN_LOAD_ERROR;
   1017     }
   1018 
   1019 
   1020     if (ImageContext->IsTeImage) {
   1021       Base  = (CHAR8 *) ((UINTN) Base + sizeof (EFI_TE_IMAGE_HEADER) - (UINTN) TeHdr->StrippedSize);
   1022       End   = (CHAR8 *) ((UINTN) End + sizeof (EFI_TE_IMAGE_HEADER) - (UINTN) TeHdr->StrippedSize);
   1023     }
   1024 
   1025     if (End > MaxEnd) {
   1026       MaxEnd = End;
   1027     }
   1028 
   1029     //
   1030     // Read the section
   1031     //
   1032     Size = (UINTN) Section->Misc.VirtualSize;
   1033     if ((Size == 0) || (Size > Section->SizeOfRawData)) {
   1034       Size = (UINTN) Section->SizeOfRawData;
   1035     }
   1036 
   1037     if (Section->SizeOfRawData) {
   1038       if (!(ImageContext->IsTeImage)) {
   1039         Status = ImageContext->ImageRead (
   1040                                 ImageContext->Handle,
   1041                                 Section->PointerToRawData,
   1042                                 &Size,
   1043                                 Base
   1044                                 );
   1045       } else {
   1046         Status = ImageContext->ImageRead (
   1047                                 ImageContext->Handle,
   1048                                 Section->PointerToRawData + sizeof (EFI_TE_IMAGE_HEADER) - (UINTN) TeHdr->StrippedSize,
   1049                                 &Size,
   1050                                 Base
   1051                                 );
   1052       }
   1053 
   1054       if (RETURN_ERROR (Status)) {
   1055         ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;
   1056         return Status;
   1057       }
   1058     }
   1059 
   1060     //
   1061     // If raw size is less then virt size, zero fill the remaining
   1062     //
   1063 
   1064     if (Size < Section->Misc.VirtualSize) {
   1065       ZeroMem (Base + Size, Section->Misc.VirtualSize - Size);
   1066     }
   1067 
   1068     //
   1069     // Next Section
   1070     //
   1071     Section += 1;
   1072   }
   1073 
   1074   //
   1075   // Get image's entry point
   1076   //
   1077   if (!(ImageContext->IsTeImage)) {
   1078     ImageContext->EntryPoint = (PHYSICAL_ADDRESS) (UINTN) PeCoffLoaderImageAddress (
   1079                                                                 ImageContext,
   1080                                                                 PeHdr->Pe32.OptionalHeader.AddressOfEntryPoint
   1081                                                                 );
   1082   } else {
   1083     ImageContext->EntryPoint =  (PHYSICAL_ADDRESS) (
   1084                        (UINTN)ImageContext->ImageAddress +
   1085                        (UINTN)TeHdr->AddressOfEntryPoint +
   1086                        (UINTN)sizeof(EFI_TE_IMAGE_HEADER) -
   1087           (UINTN) TeHdr->StrippedSize
   1088       );
   1089   }
   1090 
   1091   //
   1092   // Determine the size of the fixup data
   1093   //
   1094   // Per the PE/COFF spec, you can't assume that a given data directory
   1095   // is present in the image. You have to check the NumberOfRvaAndSizes in
   1096   // the optional header to verify a desired directory entry is there.
   1097   //
   1098   if (!(ImageContext->IsTeImage)) {
   1099     if (PeHdr->Pe32.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
   1100       if (OptionHeader.Optional32->NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC) {
   1101         DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)
   1102           &OptionHeader.Optional32->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC];
   1103         ImageContext->FixupDataSize = DirectoryEntry->Size / sizeof (UINT16) * sizeof (UINTN);
   1104       } else {
   1105         ImageContext->FixupDataSize = 0;
   1106       }
   1107     } else {
   1108       if (OptionHeader.Optional64->NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC) {
   1109         DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)
   1110           &OptionHeader.Optional64->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC];
   1111         ImageContext->FixupDataSize = DirectoryEntry->Size / sizeof (UINT16) * sizeof (UINTN);
   1112       } else {
   1113         ImageContext->FixupDataSize = 0;
   1114       }
   1115     }
   1116   } else {
   1117     DirectoryEntry              = &TeHdr->DataDirectory[0];
   1118     ImageContext->FixupDataSize = DirectoryEntry->Size / sizeof (UINT16) * sizeof (UINTN);
   1119   }
   1120   //
   1121   // Consumer must allocate a buffer for the relocation fixup log.
   1122   // Only used for runtime drivers.
   1123   //
   1124   ImageContext->FixupData = NULL;
   1125 
   1126   //
   1127   // Load the Codeview info if present
   1128   //
   1129   if (ImageContext->DebugDirectoryEntryRva != 0) {
   1130     if (!(ImageContext->IsTeImage)) {
   1131       DebugEntry = PeCoffLoaderImageAddress (
   1132                     ImageContext,
   1133                     ImageContext->DebugDirectoryEntryRva
   1134                     );
   1135     } else {
   1136       DebugEntry = (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *)(UINTN)(
   1137                                                ImageContext->ImageAddress +
   1138                                                ImageContext->DebugDirectoryEntryRva +
   1139                                                sizeof(EFI_TE_IMAGE_HEADER) -
   1140                                                TeHdr->StrippedSize
   1141                                                );
   1142     }
   1143 
   1144     if (DebugEntry != NULL) {
   1145       TempDebugEntryRva = DebugEntry->RVA;
   1146       if (DebugEntry->RVA == 0 && DebugEntry->FileOffset != 0) {
   1147         Section--;
   1148         if ((UINTN) Section->SizeOfRawData < Section->Misc.VirtualSize) {
   1149           TempDebugEntryRva = Section->VirtualAddress + Section->Misc.VirtualSize;
   1150         } else {
   1151           TempDebugEntryRva = Section->VirtualAddress + Section->SizeOfRawData;
   1152         }
   1153       }
   1154 
   1155       if (TempDebugEntryRva != 0) {
   1156         if (!(ImageContext->IsTeImage)) {
   1157           ImageContext->CodeView = PeCoffLoaderImageAddress (ImageContext, TempDebugEntryRva);
   1158         } else {
   1159           ImageContext->CodeView = (VOID *)(
   1160                       (UINTN)ImageContext->ImageAddress +
   1161                       (UINTN)TempDebugEntryRva +
   1162                       (UINTN)sizeof(EFI_TE_IMAGE_HEADER) -
   1163                 (UINTN) TeHdr->StrippedSize
   1164             );
   1165         }
   1166 
   1167         if (ImageContext->CodeView == NULL) {
   1168           ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;
   1169           return RETURN_LOAD_ERROR;
   1170         }
   1171 
   1172         if (DebugEntry->RVA == 0) {
   1173           Size = DebugEntry->SizeOfData;
   1174           if (!(ImageContext->IsTeImage)) {
   1175             Status = ImageContext->ImageRead (
   1176                                     ImageContext->Handle,
   1177                                     DebugEntry->FileOffset,
   1178                                     &Size,
   1179                                     ImageContext->CodeView
   1180                                     );
   1181           } else {
   1182             Status = ImageContext->ImageRead (
   1183                                     ImageContext->Handle,
   1184                                     DebugEntry->FileOffset + sizeof (EFI_TE_IMAGE_HEADER) - TeHdr->StrippedSize,
   1185                                     &Size,
   1186                                     ImageContext->CodeView
   1187                                     );
   1188             //
   1189             // Should we apply fix up to this field according to the size difference between PE and TE?
   1190             // Because now we maintain TE header fields unfixed, this field will also remain as they are
   1191             // in original PE image.
   1192             //
   1193           }
   1194 
   1195           if (RETURN_ERROR (Status)) {
   1196             ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;
   1197             return RETURN_LOAD_ERROR;
   1198           }
   1199 
   1200           DebugEntry->RVA = TempDebugEntryRva;
   1201         }
   1202 
   1203         switch (*(UINT32 *) ImageContext->CodeView) {
   1204         case CODEVIEW_SIGNATURE_NB10:
   1205           ImageContext->PdbPointer = (CHAR8 *) ImageContext->CodeView + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY);
   1206           break;
   1207 
   1208         case CODEVIEW_SIGNATURE_RSDS:
   1209           ImageContext->PdbPointer = (CHAR8 *) ImageContext->CodeView + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY);
   1210           break;
   1211 
   1212         case CODEVIEW_SIGNATURE_MTOC:
   1213           ImageContext->PdbPointer = (CHAR8 *) ImageContext->CodeView + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_MTOC_ENTRY);
   1214 
   1215         default:
   1216           break;
   1217         }
   1218       }
   1219     }
   1220   }
   1221 
   1222   return Status;
   1223 }
   1224 
   1225 /**
   1226   Returns a pointer to the PDB file name for a raw PE/COFF image that is not
   1227   loaded into system memory with the PE/COFF Loader Library functions.
   1228 
   1229   Returns the PDB file name for the PE/COFF image specified by Pe32Data.  If
   1230   the PE/COFF image specified by Pe32Data is not a valid, then NULL is
   1231   returned.  If the PE/COFF image specified by Pe32Data does not contain a
   1232   debug directory entry, then NULL is returned.  If the debug directory entry
   1233   in the PE/COFF image specified by Pe32Data does not contain a PDB file name,
   1234   then NULL is returned.
   1235   If Pe32Data is NULL, then return NULL.
   1236 
   1237   @param  Pe32Data   Pointer to the PE/COFF image that is loaded in system
   1238                      memory.
   1239 
   1240   @return The PDB file name for the PE/COFF image specified by Pe32Data or NULL
   1241           if it cannot be retrieved.
   1242 
   1243 **/
   1244 VOID *
   1245 EFIAPI
   1246 PeCoffLoaderGetPdbPointer (
   1247   IN VOID  *Pe32Data
   1248   )
   1249 {
   1250   EFI_IMAGE_DOS_HEADER                  *DosHdr;
   1251   EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION   Hdr;
   1252   EFI_IMAGE_DATA_DIRECTORY              *DirectoryEntry;
   1253   EFI_IMAGE_DEBUG_DIRECTORY_ENTRY       *DebugEntry;
   1254   UINTN                                 DirCount;
   1255   VOID                                  *CodeViewEntryPointer;
   1256   INTN                                  TEImageAdjust;
   1257   UINT32                                NumberOfRvaAndSizes;
   1258   UINT16                                Magic;
   1259   EFI_IMAGE_SECTION_HEADER              *SectionHeader;
   1260   UINT32                                Index, Index1;
   1261 
   1262   if (Pe32Data == NULL) {
   1263     return NULL;
   1264   }
   1265 
   1266   TEImageAdjust       = 0;
   1267   DirectoryEntry      = NULL;
   1268   DebugEntry          = NULL;
   1269   NumberOfRvaAndSizes = 0;
   1270   Index               = 0;
   1271   Index1              = 0;
   1272   SectionHeader       = NULL;
   1273 
   1274   DosHdr = (EFI_IMAGE_DOS_HEADER *)Pe32Data;
   1275   if (EFI_IMAGE_DOS_SIGNATURE == DosHdr->e_magic) {
   1276     //
   1277     // DOS image header is present, so read the PE header after the DOS image header.
   1278     //
   1279     Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINTN) Pe32Data + (UINTN) ((DosHdr->e_lfanew) & 0x0ffff));
   1280   } else {
   1281     //
   1282     // DOS image header is not present, so PE header is at the image base.
   1283     //
   1284     Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)Pe32Data;
   1285   }
   1286 
   1287   if (EFI_TE_IMAGE_HEADER_SIGNATURE == Hdr.Te->Signature) {
   1288     if (Hdr.Te->DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress != 0) {
   1289       DirectoryEntry  = &Hdr.Te->DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG];
   1290       TEImageAdjust   = sizeof (EFI_TE_IMAGE_HEADER) - Hdr.Te->StrippedSize;
   1291 
   1292       //
   1293       // Get the DebugEntry offset in the raw data image.
   1294       //
   1295       SectionHeader = (EFI_IMAGE_SECTION_HEADER *) (Hdr.Te + 1);
   1296       Index = Hdr.Te->NumberOfSections;
   1297       for (Index1 = 0; Index1 < Index; Index1 ++) {
   1298         if ((DirectoryEntry->VirtualAddress >= SectionHeader[Index1].VirtualAddress) &&
   1299            (DirectoryEntry->VirtualAddress < (SectionHeader[Index1].VirtualAddress + SectionHeader[Index1].Misc.VirtualSize))) {
   1300           DebugEntry = (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *)((UINTN) Hdr.Te +
   1301                         DirectoryEntry->VirtualAddress -
   1302                         SectionHeader [Index1].VirtualAddress +
   1303                         SectionHeader [Index1].PointerToRawData +
   1304                         TEImageAdjust);
   1305           break;
   1306         }
   1307       }
   1308     }
   1309   } else if (EFI_IMAGE_NT_SIGNATURE == Hdr.Pe32->Signature) {
   1310     //
   1311     // NOTE: We use Machine field to identify PE32/PE32+, instead of Magic.
   1312     //       It is due to backward-compatibility, for some system might
   1313     //       generate PE32+ image with PE32 Magic.
   1314     //
   1315     switch (Hdr.Pe32->FileHeader.Machine) {
   1316     case EFI_IMAGE_MACHINE_IA32:
   1317     case EFI_IMAGE_MACHINE_ARMT:
   1318       //
   1319       // Assume PE32 image with IA32 Machine field.
   1320       //
   1321       Magic = EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC;
   1322       break;
   1323     case EFI_IMAGE_MACHINE_X64:
   1324     case EFI_IMAGE_MACHINE_IPF:
   1325       //
   1326       // Assume PE32+ image with X64 or IPF Machine field
   1327       //
   1328       Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC;
   1329       break;
   1330     default:
   1331       //
   1332       // For unknow Machine field, use Magic in optional Header
   1333       //
   1334       Magic = Hdr.Pe32->OptionalHeader.Magic;
   1335     }
   1336 
   1337     SectionHeader = (EFI_IMAGE_SECTION_HEADER *) (
   1338                        (UINT8 *) Hdr.Pe32 +
   1339                        sizeof (UINT32) +
   1340                        sizeof (EFI_IMAGE_FILE_HEADER) +
   1341                        Hdr.Pe32->FileHeader.SizeOfOptionalHeader
   1342                        );
   1343     Index = Hdr.Pe32->FileHeader.NumberOfSections;
   1344 
   1345     if (EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC == Magic) {
   1346       //
   1347       // Use PE32 offset get Debug Directory Entry
   1348       //
   1349       NumberOfRvaAndSizes = Hdr.Pe32->OptionalHeader.NumberOfRvaAndSizes;
   1350       DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)&(Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG]);
   1351     } else if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
   1352       //
   1353       // Use PE32+ offset get Debug Directory Entry
   1354       //
   1355       NumberOfRvaAndSizes = Hdr.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes;
   1356       DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)&(Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG]);
   1357     }
   1358 
   1359     if (NumberOfRvaAndSizes <= EFI_IMAGE_DIRECTORY_ENTRY_DEBUG || DirectoryEntry->VirtualAddress == 0) {
   1360       DirectoryEntry = NULL;
   1361       DebugEntry = NULL;
   1362     } else {
   1363       //
   1364       // Get the DebugEntry offset in the raw data image.
   1365       //
   1366       for (Index1 = 0; Index1 < Index; Index1 ++) {
   1367         if ((DirectoryEntry->VirtualAddress >= SectionHeader[Index1].VirtualAddress) &&
   1368            (DirectoryEntry->VirtualAddress < (SectionHeader[Index1].VirtualAddress + SectionHeader[Index1].Misc.VirtualSize))) {
   1369           DebugEntry = (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *) (
   1370                        (UINTN) Pe32Data +
   1371                        DirectoryEntry->VirtualAddress -
   1372                        SectionHeader[Index1].VirtualAddress +
   1373                        SectionHeader[Index1].PointerToRawData);
   1374           break;
   1375         }
   1376       }
   1377     }
   1378   } else {
   1379     return NULL;
   1380   }
   1381 
   1382   if (NULL == DebugEntry || NULL == DirectoryEntry) {
   1383     return NULL;
   1384   }
   1385 
   1386   //
   1387   // Scan the directory to find the debug entry.
   1388   //
   1389   for (DirCount = 0; DirCount < DirectoryEntry->Size; DirCount += sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY), DebugEntry++) {
   1390     if (EFI_IMAGE_DEBUG_TYPE_CODEVIEW == DebugEntry->Type) {
   1391       if (DebugEntry->SizeOfData > 0) {
   1392         //
   1393         // Get the DebugEntry offset in the raw data image.
   1394         //
   1395         CodeViewEntryPointer = NULL;
   1396         for (Index1 = 0; Index1 < Index; Index1 ++) {
   1397           if ((DebugEntry->RVA >= SectionHeader[Index1].VirtualAddress) &&
   1398              (DebugEntry->RVA < (SectionHeader[Index1].VirtualAddress + SectionHeader[Index1].Misc.VirtualSize))) {
   1399             CodeViewEntryPointer = (VOID *) (
   1400                                    ((UINTN)Pe32Data) +
   1401                                    (UINTN) DebugEntry->RVA -
   1402                                    SectionHeader[Index1].VirtualAddress +
   1403                                    SectionHeader[Index1].PointerToRawData +
   1404                                    (UINTN)TEImageAdjust);
   1405             break;
   1406           }
   1407         }
   1408         if (Index1 >= Index) {
   1409           //
   1410           // Can't find CodeViewEntryPointer in raw PE/COFF image.
   1411           //
   1412           continue;
   1413         }
   1414         switch (* (UINT32 *) CodeViewEntryPointer) {
   1415         case CODEVIEW_SIGNATURE_NB10:
   1416           return (VOID *) ((CHAR8 *)CodeViewEntryPointer + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY));
   1417         case CODEVIEW_SIGNATURE_RSDS:
   1418           return (VOID *) ((CHAR8 *)CodeViewEntryPointer + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY));
   1419         case CODEVIEW_SIGNATURE_MTOC:
   1420           return (VOID *) ((CHAR8 *)CodeViewEntryPointer + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_MTOC_ENTRY));
   1421         default:
   1422           break;
   1423         }
   1424       }
   1425     }
   1426   }
   1427 
   1428   return NULL;
   1429 }
   1430 
   1431 
   1432 RETURN_STATUS
   1433 EFIAPI
   1434 PeCoffLoaderGetEntryPoint (
   1435   IN  VOID  *Pe32Data,
   1436   OUT VOID  **EntryPoint,
   1437   OUT VOID  **BaseOfImage
   1438   )
   1439 {
   1440   EFI_IMAGE_DOS_HEADER                  *DosHdr;
   1441   EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION   Hdr;
   1442 
   1443   DosHdr = (EFI_IMAGE_DOS_HEADER *)Pe32Data;
   1444   if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) {
   1445     //
   1446     // DOS image header is present, so read the PE header after the DOS image header.
   1447     //
   1448     Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINTN) Pe32Data + (UINTN) ((DosHdr->e_lfanew) & 0x0ffff));
   1449   } else {
   1450     //
   1451     // DOS image header is not present, so PE header is at the image base.
   1452     //
   1453     Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)Pe32Data;
   1454   }
   1455 
   1456   //
   1457   // Calculate the entry point relative to the start of the image.
   1458   // AddressOfEntryPoint is common for PE32 & PE32+
   1459   //
   1460   if (Hdr.Te->Signature == EFI_TE_IMAGE_HEADER_SIGNATURE) {
   1461     *BaseOfImage = (VOID *)(UINTN)(Hdr.Te->ImageBase + Hdr.Te->StrippedSize - sizeof (EFI_TE_IMAGE_HEADER));
   1462     *EntryPoint = (VOID *)((UINTN)*BaseOfImage + (Hdr.Te->AddressOfEntryPoint & 0x0ffffffff) + sizeof(EFI_TE_IMAGE_HEADER) - Hdr.Te->StrippedSize);
   1463     return RETURN_SUCCESS;
   1464   } else if (Hdr.Pe32->Signature == EFI_IMAGE_NT_SIGNATURE) {
   1465     *EntryPoint = (VOID *)(UINTN)Hdr.Pe32->OptionalHeader.AddressOfEntryPoint;
   1466     if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
   1467       *BaseOfImage = (VOID *)(UINTN)Hdr.Pe32->OptionalHeader.ImageBase;
   1468     } else {
   1469       *BaseOfImage = (VOID *)(UINTN)Hdr.Pe32Plus->OptionalHeader.ImageBase;
   1470     }
   1471     *EntryPoint = (VOID *)(UINTN)((UINTN)*EntryPoint + (UINTN)*BaseOfImage);
   1472     return RETURN_SUCCESS;
   1473   }
   1474 
   1475   return RETURN_UNSUPPORTED;
   1476 }
   1477