BasePeCoff.c revision 2c69d6ffee7a9a17262b58dd454e7e9476302cb8
1/** @file
2
3  Functions to get info and load PE/COFF image.
4
5Copyright (c) 2004 - 2010, Intel Corporation. All rights reserved.<BR>
6Portions Copyright (c) 2011 - 2013, ARM Ltd. All rights reserved.<BR>
7This program and the accompanying materials
8are licensed and made available under the terms and conditions of the BSD License
9which accompanies this distribution.  The full text of the license may be found at
10http://opensource.org/licenses/bsd-license.php
11
12THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
13WITHOUT 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
22typedef union {
23  VOID                         *Header;
24  EFI_IMAGE_OPTIONAL_HEADER32  *Optional32;
25  EFI_IMAGE_OPTIONAL_HEADER64  *Optional64;
26} EFI_IMAGE_OPTIONAL_HEADER_POINTER;
27
28STATIC
29RETURN_STATUS
30PeCoffLoaderGetPeHeader (
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
36STATIC
37RETURN_STATUS
38PeCoffLoaderCheckImageType (
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
44STATIC
45VOID *
46PeCoffLoaderImageAddress (
47  IN OUT PE_COFF_LOADER_IMAGE_CONTEXT  *ImageContext,
48  IN     UINTN                         Address
49  );
50
51RETURN_STATUS
52PeCoffLoaderRelocateIa32Image (
53  IN UINT16      *Reloc,
54  IN OUT CHAR8   *Fixup,
55  IN OUT CHAR8   **FixupData,
56  IN UINT64      Adjust
57  );
58
59RETURN_STATUS
60PeCoffLoaderRelocateIpfImage (
61  IN UINT16      *Reloc,
62  IN OUT CHAR8   *Fixup,
63  IN OUT CHAR8   **FixupData,
64  IN UINT64      Adjust
65  );
66
67RETURN_STATUS
68PeCoffLoaderRelocateArmImage (
69  IN UINT16      **Reloc,
70  IN OUT CHAR8   *Fixup,
71  IN OUT CHAR8   **FixupData,
72  IN UINT64      Adjust
73  );
74
75STATIC
76RETURN_STATUS
77PeCoffLoaderGetPeHeader (
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
84Routine Description:
85
86  Retrieves the PE or TE Header from a PE/COFF or TE image
87
88Arguments:
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
96Returns:
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
148STATIC
149RETURN_STATUS
150PeCoffLoaderCheckImageType (
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
157Routine Description:
158
159  Checks the PE or TE header of a PE/COFF or TE image to determine if it supported
160
161Arguments:
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
169Returns:
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
236RETURN_STATUS
237EFIAPI
238PeCoffLoaderGetImageInfo (
239  IN OUT PE_COFF_LOADER_IMAGE_CONTEXT           *ImageContext
240  )
241/*++
242
243Routine Description:
244
245  Retrieves information on a PE/COFF image
246
247Arguments:
248
249  This         - Calling context
250  ImageContext - The context of the image being loaded
251
252Returns:
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)) {
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
536STATIC
537VOID *
538PeCoffLoaderImageAddress (
539  IN OUT PE_COFF_LOADER_IMAGE_CONTEXT          *ImageContext,
540  IN     UINTN                                 Address
541  )
542/*++
543
544Routine Description:
545
546  Converts an image address to the loaded address
547
548Arguments:
549
550  ImageContext  - The context of the image being loaded
551
552  Address       - The address to be converted to the loaded address
553
554Returns:
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
568RETURN_STATUS
569EFIAPI
570PeCoffLoaderRelocateImage (
571  IN OUT PE_COFF_LOADER_IMAGE_CONTEXT  *ImageContext
572  )
573/*++
574
575Routine Description:
576
577  Relocates a PE/COFF image in memory
578
579Arguments:
580
581  This         - Calling context
582
583  ImageContext - Contains information on the loaded image to relocate
584
585Returns:
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        RelocBase = PeCoffLoaderImageAddress (ImageContext, RelocDir->VirtualAddress);
649        RelocBaseEnd = PeCoffLoaderImageAddress (
650                        ImageContext,
651                        RelocDir->VirtualAddress + RelocDir->Size - 1
652                        );
653      } else {
654        //
655        // Set base and end to bypass processing below.
656        //
657        RelocBase = RelocBaseEnd = 0;
658      }
659    } else {
660      Adjust = (UINT64) BaseAddress - OptionHeader.Optional64->ImageBase;
661      OptionHeader.Optional64->ImageBase = BaseAddress;
662      MachineType = ImageContext->Machine;
663      //
664      // Find the relocation block
665      //
666      // Per the PE/COFF spec, you can't assume that a given data directory
667      // is present in the image. You have to check the NumberOfRvaAndSizes in
668      // the optional header to verify a desired directory entry is there.
669      //
670      if (OptionHeader.Optional64->NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC) {
671        RelocDir  = &OptionHeader.Optional64->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC];
672        RelocBase = PeCoffLoaderImageAddress (ImageContext, RelocDir->VirtualAddress);
673        RelocBaseEnd = PeCoffLoaderImageAddress (
674                        ImageContext,
675                        RelocDir->VirtualAddress + RelocDir->Size - 1
676                        );
677      } else {
678        //
679        // Set base and end to bypass processing below.
680        //
681        RelocBase = RelocBaseEnd = 0;
682      }
683    }
684  } else {
685    TeHdr             = (EFI_TE_IMAGE_HEADER *) (UINTN) (ImageContext->ImageAddress);
686    Adjust            = (UINT64) (BaseAddress - TeHdr->ImageBase);
687    TeHdr->ImageBase  = (UINT64) (BaseAddress);
688    MachineType = TeHdr->Machine;
689
690    //
691    // Find the relocation block
692    //
693    RelocDir = &TeHdr->DataDirectory[0];
694    RelocBase = (EFI_IMAGE_BASE_RELOCATION *)(UINTN)(
695                                    ImageContext->ImageAddress +
696                                    RelocDir->VirtualAddress +
697                                    sizeof(EFI_TE_IMAGE_HEADER) -
698                                    TeHdr->StrippedSize
699                                    );
700    RelocBaseEnd = (EFI_IMAGE_BASE_RELOCATION *) ((UINTN) RelocBase + (UINTN) RelocDir->Size - 1);
701  }
702
703  //
704  // Run the relocation information and apply the fixups
705  //
706  FixupData = ImageContext->FixupData;
707  while (RelocBase < RelocBaseEnd) {
708
709    Reloc     = (UINT16 *) ((CHAR8 *) RelocBase + sizeof (EFI_IMAGE_BASE_RELOCATION));
710    RelocEnd  = (UINT16 *) ((CHAR8 *) RelocBase + RelocBase->SizeOfBlock);
711    if (!(ImageContext->IsTeImage)) {
712      FixupBase = PeCoffLoaderImageAddress (ImageContext, RelocBase->VirtualAddress);
713    } else {
714      FixupBase = (CHAR8 *)(UINTN)(ImageContext->ImageAddress +
715                    RelocBase->VirtualAddress +
716                    sizeof(EFI_TE_IMAGE_HEADER) -
717                    TeHdr->StrippedSize
718                    );
719    }
720
721    if ((CHAR8 *) RelocEnd < (CHAR8 *) ((UINTN) ImageContext->ImageAddress) ||
722        (CHAR8 *) RelocEnd > (CHAR8 *)((UINTN)ImageContext->ImageAddress +
723          (UINTN)ImageContext->ImageSize)) {
724      ImageContext->ImageError = IMAGE_ERROR_FAILED_RELOCATION;
725      return RETURN_LOAD_ERROR;
726    }
727
728    //
729    // Run this relocation record
730    //
731    while (Reloc < RelocEnd) {
732
733      Fixup = FixupBase + (*Reloc & 0xFFF);
734      switch ((*Reloc) >> 12) {
735      case EFI_IMAGE_REL_BASED_ABSOLUTE:
736        break;
737
738      case EFI_IMAGE_REL_BASED_HIGH:
739        F16   = (UINT16 *) Fixup;
740        *F16 = (UINT16) (*F16 + ((UINT16) ((UINT32) Adjust >> 16)));
741        if (FixupData != NULL) {
742          *(UINT16 *) FixupData = *F16;
743          FixupData             = FixupData + sizeof (UINT16);
744        }
745        break;
746
747      case EFI_IMAGE_REL_BASED_LOW:
748        F16   = (UINT16 *) Fixup;
749        *F16  = (UINT16) (*F16 + (UINT16) Adjust);
750        if (FixupData != NULL) {
751          *(UINT16 *) FixupData = *F16;
752          FixupData             = FixupData + sizeof (UINT16);
753        }
754        break;
755
756      case EFI_IMAGE_REL_BASED_HIGHLOW:
757        F32   = (UINT32 *) Fixup;
758        *F32  = *F32 + (UINT32) Adjust;
759        if (FixupData != NULL) {
760          FixupData             = ALIGN_POINTER (FixupData, sizeof (UINT32));
761          *(UINT32 *) FixupData = *F32;
762          FixupData             = FixupData + sizeof (UINT32);
763        }
764        break;
765
766      case EFI_IMAGE_REL_BASED_DIR64:
767        F64   = (UINT64 *) Fixup;
768        *F64  = *F64 + (UINT64) Adjust;
769        if (FixupData != NULL) {
770          FixupData             = ALIGN_POINTER (FixupData, sizeof (UINT64));
771          *(UINT64 *) FixupData = *F64;
772          FixupData             = FixupData + sizeof (UINT64);
773        }
774        break;
775
776      case EFI_IMAGE_REL_BASED_HIGHADJ:
777        //
778        // Return the same EFI_UNSUPPORTED return code as
779        // PeCoffLoaderRelocateImageEx() returns if it does not recognize
780        // the relocation type.
781        //
782        ImageContext->ImageError = IMAGE_ERROR_FAILED_RELOCATION;
783        return RETURN_UNSUPPORTED;
784
785      default:
786        switch (MachineType) {
787        case EFI_IMAGE_MACHINE_IA32:
788          Status = PeCoffLoaderRelocateIa32Image (Reloc, Fixup, &FixupData, Adjust);
789          break;
790        case EFI_IMAGE_MACHINE_ARMT:
791          Status = PeCoffLoaderRelocateArmImage (&Reloc, Fixup, &FixupData, Adjust);
792          break;
793        case EFI_IMAGE_MACHINE_IA64:
794          Status = PeCoffLoaderRelocateIpfImage (Reloc, Fixup, &FixupData, Adjust);
795          break;
796        default:
797          Status = RETURN_UNSUPPORTED;
798          break;
799        }
800        if (RETURN_ERROR (Status)) {
801          ImageContext->ImageError = IMAGE_ERROR_FAILED_RELOCATION;
802          return Status;
803        }
804      }
805
806      //
807      // Next relocation record
808      //
809      Reloc += 1;
810    }
811
812    //
813    // Next reloc block
814    //
815    RelocBase = (EFI_IMAGE_BASE_RELOCATION *) RelocEnd;
816  }
817
818  return RETURN_SUCCESS;
819}
820
821RETURN_STATUS
822EFIAPI
823PeCoffLoaderLoadImage (
824  IN OUT PE_COFF_LOADER_IMAGE_CONTEXT  *ImageContext
825  )
826/*++
827
828Routine Description:
829
830  Loads a PE/COFF image into memory
831
832Arguments:
833
834  This         - Calling context
835
836  ImageContext - Contains information on image to load into memory
837
838Returns:
839
840  RETURN_SUCCESS            if the PE/COFF image was loaded
841  RETURN_BUFFER_TOO_SMALL   if the caller did not provide a large enough buffer
842  RETURN_LOAD_ERROR         if the image is a runtime driver with no relocations
843  RETURN_INVALID_PARAMETER  if the image address is invalid
844
845--*/
846{
847  RETURN_STATUS                         Status;
848  EFI_IMAGE_OPTIONAL_HEADER_UNION       *PeHdr;
849  EFI_TE_IMAGE_HEADER                   *TeHdr;
850  PE_COFF_LOADER_IMAGE_CONTEXT          CheckContext;
851  EFI_IMAGE_SECTION_HEADER              *FirstSection;
852  EFI_IMAGE_SECTION_HEADER              *Section;
853  UINTN                                 NumberOfSections;
854  UINTN                                 Index;
855  CHAR8                                 *Base;
856  CHAR8                                 *End;
857  CHAR8                                 *MaxEnd;
858  EFI_IMAGE_DATA_DIRECTORY              *DirectoryEntry;
859  EFI_IMAGE_DEBUG_DIRECTORY_ENTRY       *DebugEntry;
860  UINTN                                 Size;
861  UINT32                                TempDebugEntryRva;
862  EFI_IMAGE_OPTIONAL_HEADER_POINTER     OptionHeader;
863
864  PeHdr = NULL;
865  TeHdr = NULL;
866  OptionHeader.Header = NULL;
867  //
868  // Assume success
869  //
870  ImageContext->ImageError = IMAGE_ERROR_SUCCESS;
871
872  //
873  // Copy the provided context info into our local version, get what we
874  // can from the original image, and then use that to make sure everything
875  // is legit.
876  //
877  CopyMem (&CheckContext, ImageContext, sizeof (PE_COFF_LOADER_IMAGE_CONTEXT));
878
879  Status = PeCoffLoaderGetImageInfo (&CheckContext);
880  if (RETURN_ERROR (Status)) {
881    return Status;
882  }
883
884  //
885  // Make sure there is enough allocated space for the image being loaded
886  //
887  if (ImageContext->ImageSize < CheckContext.ImageSize) {
888    ImageContext->ImageError = IMAGE_ERROR_INVALID_IMAGE_SIZE;
889    return RETURN_BUFFER_TOO_SMALL;
890  }
891
892  //
893  // If there's no relocations, then make sure it's not a runtime driver,
894  // and that it's being loaded at the linked address.
895  //
896  if (CheckContext.RelocationsStripped) {
897    //
898    // If the image does not contain relocations and it is a runtime driver
899    // then return an error.
900    //
901    if (CheckContext.ImageType == EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER) {
902      ImageContext->ImageError = IMAGE_ERROR_INVALID_SUBSYSTEM;
903      return RETURN_LOAD_ERROR;
904    }
905    //
906    // If the image does not contain relocations, and the requested load address
907    // is not the linked address, then return an error.
908    //
909    if (CheckContext.ImageAddress != ImageContext->ImageAddress) {
910      ImageContext->ImageError = IMAGE_ERROR_INVALID_IMAGE_ADDRESS;
911      return RETURN_INVALID_PARAMETER;
912    }
913  }
914  //
915  // Make sure the allocated space has the proper section alignment
916  //
917  if (!(ImageContext->IsTeImage)) {
918    if ((ImageContext->ImageAddress & (CheckContext.SectionAlignment - 1)) != 0) {
919      ImageContext->ImageError = IMAGE_ERROR_INVALID_SECTION_ALIGNMENT;
920      return RETURN_INVALID_PARAMETER;
921    }
922  }
923  //
924  // Read the entire PE/COFF or TE header into memory
925  //
926  if (!(ImageContext->IsTeImage)) {
927    Status = ImageContext->ImageRead (
928                            ImageContext->Handle,
929                            0,
930                            &ImageContext->SizeOfHeaders,
931                            (VOID *) (UINTN) ImageContext->ImageAddress
932                            );
933
934    PeHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)
935      ((UINTN)ImageContext->ImageAddress + ImageContext->PeCoffHeaderOffset);
936
937    OptionHeader.Header = (VOID *) &(PeHdr->Pe32.OptionalHeader);
938
939    FirstSection = (EFI_IMAGE_SECTION_HEADER *) (
940                      (UINTN)ImageContext->ImageAddress +
941                      ImageContext->PeCoffHeaderOffset +
942                      sizeof(UINT32) +
943                      sizeof(EFI_IMAGE_FILE_HEADER) +
944                      PeHdr->Pe32.FileHeader.SizeOfOptionalHeader
945      );
946    NumberOfSections = (UINTN) (PeHdr->Pe32.FileHeader.NumberOfSections);
947  } else {
948    Status = ImageContext->ImageRead (
949                            ImageContext->Handle,
950                            0,
951                            &ImageContext->SizeOfHeaders,
952                            (VOID *) (UINTN) ImageContext->ImageAddress
953                            );
954
955    TeHdr             = (EFI_TE_IMAGE_HEADER *) (UINTN) (ImageContext->ImageAddress);
956
957    FirstSection = (EFI_IMAGE_SECTION_HEADER *) (
958          (UINTN)ImageContext->ImageAddress +
959          sizeof(EFI_TE_IMAGE_HEADER)
960          );
961    NumberOfSections  = (UINTN) (TeHdr->NumberOfSections);
962
963  }
964
965  if (RETURN_ERROR (Status)) {
966    ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;
967    return RETURN_LOAD_ERROR;
968  }
969
970  //
971  // Load each section of the image
972  //
973  Section = FirstSection;
974  for (Index = 0, MaxEnd = NULL; Index < NumberOfSections; Index++) {
975
976    //
977    // Compute sections address
978    //
979    Base = PeCoffLoaderImageAddress (ImageContext, Section->VirtualAddress);
980    End = PeCoffLoaderImageAddress (
981            ImageContext,
982            Section->VirtualAddress + Section->Misc.VirtualSize - 1
983            );
984
985    //
986    // If the base start or end address resolved to 0, then fail.
987    //
988    if ((Base == NULL) || (End == NULL)) {
989      ImageContext->ImageError = IMAGE_ERROR_SECTION_NOT_LOADED;
990      return RETURN_LOAD_ERROR;
991    }
992
993
994    if (ImageContext->IsTeImage) {
995      Base  = (CHAR8 *) ((UINTN) Base + sizeof (EFI_TE_IMAGE_HEADER) - (UINTN) TeHdr->StrippedSize);
996      End   = (CHAR8 *) ((UINTN) End + sizeof (EFI_TE_IMAGE_HEADER) - (UINTN) TeHdr->StrippedSize);
997    }
998
999    if (End > MaxEnd) {
1000      MaxEnd = End;
1001    }
1002
1003    //
1004    // Read the section
1005    //
1006    Size = (UINTN) Section->Misc.VirtualSize;
1007    if ((Size == 0) || (Size > Section->SizeOfRawData)) {
1008      Size = (UINTN) Section->SizeOfRawData;
1009    }
1010
1011    if (Section->SizeOfRawData) {
1012      if (!(ImageContext->IsTeImage)) {
1013        Status = ImageContext->ImageRead (
1014                                ImageContext->Handle,
1015                                Section->PointerToRawData,
1016                                &Size,
1017                                Base
1018                                );
1019      } else {
1020        Status = ImageContext->ImageRead (
1021                                ImageContext->Handle,
1022                                Section->PointerToRawData + sizeof (EFI_TE_IMAGE_HEADER) - (UINTN) TeHdr->StrippedSize,
1023                                &Size,
1024                                Base
1025                                );
1026      }
1027
1028      if (RETURN_ERROR (Status)) {
1029        ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;
1030        return Status;
1031      }
1032    }
1033
1034    //
1035    // If raw size is less then virt size, zero fill the remaining
1036    //
1037
1038    if (Size < Section->Misc.VirtualSize) {
1039      ZeroMem (Base + Size, Section->Misc.VirtualSize - Size);
1040    }
1041
1042    //
1043    // Next Section
1044    //
1045    Section += 1;
1046  }
1047
1048  //
1049  // Get image's entry point
1050  //
1051  if (!(ImageContext->IsTeImage)) {
1052    ImageContext->EntryPoint = (PHYSICAL_ADDRESS) (UINTN) PeCoffLoaderImageAddress (
1053                                                                ImageContext,
1054                                                                PeHdr->Pe32.OptionalHeader.AddressOfEntryPoint
1055                                                                );
1056  } else {
1057    ImageContext->EntryPoint =  (PHYSICAL_ADDRESS) (
1058                       (UINTN)ImageContext->ImageAddress +
1059                       (UINTN)TeHdr->AddressOfEntryPoint +
1060                       (UINTN)sizeof(EFI_TE_IMAGE_HEADER) -
1061          (UINTN) TeHdr->StrippedSize
1062      );
1063  }
1064
1065  //
1066  // Determine the size of the fixup data
1067  //
1068  // Per the PE/COFF spec, you can't assume that a given data directory
1069  // is present in the image. You have to check the NumberOfRvaAndSizes in
1070  // the optional header to verify a desired directory entry is there.
1071  //
1072  if (!(ImageContext->IsTeImage)) {
1073    if (PeHdr->Pe32.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
1074      if (OptionHeader.Optional32->NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC) {
1075        DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)
1076          &OptionHeader.Optional32->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC];
1077        ImageContext->FixupDataSize = DirectoryEntry->Size / sizeof (UINT16) * sizeof (UINTN);
1078      } else {
1079        ImageContext->FixupDataSize = 0;
1080      }
1081    } else {
1082      if (OptionHeader.Optional64->NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC) {
1083        DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)
1084          &OptionHeader.Optional64->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC];
1085        ImageContext->FixupDataSize = DirectoryEntry->Size / sizeof (UINT16) * sizeof (UINTN);
1086      } else {
1087        ImageContext->FixupDataSize = 0;
1088      }
1089    }
1090  } else {
1091    DirectoryEntry              = &TeHdr->DataDirectory[0];
1092    ImageContext->FixupDataSize = DirectoryEntry->Size / sizeof (UINT16) * sizeof (UINTN);
1093  }
1094  //
1095  // Consumer must allocate a buffer for the relocation fixup log.
1096  // Only used for runtime drivers.
1097  //
1098  ImageContext->FixupData = NULL;
1099
1100  //
1101  // Load the Codeview info if present
1102  //
1103  if (ImageContext->DebugDirectoryEntryRva != 0) {
1104    if (!(ImageContext->IsTeImage)) {
1105      DebugEntry = PeCoffLoaderImageAddress (
1106                    ImageContext,
1107                    ImageContext->DebugDirectoryEntryRva
1108                    );
1109    } else {
1110      DebugEntry = (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *)(UINTN)(
1111                                               ImageContext->ImageAddress +
1112                                               ImageContext->DebugDirectoryEntryRva +
1113                                               sizeof(EFI_TE_IMAGE_HEADER) -
1114                                               TeHdr->StrippedSize
1115                                               );
1116    }
1117
1118    if (DebugEntry != NULL) {
1119      TempDebugEntryRva = DebugEntry->RVA;
1120      if (DebugEntry->RVA == 0 && DebugEntry->FileOffset != 0) {
1121        Section--;
1122        if ((UINTN) Section->SizeOfRawData < Section->Misc.VirtualSize) {
1123          TempDebugEntryRva = Section->VirtualAddress + Section->Misc.VirtualSize;
1124        } else {
1125          TempDebugEntryRva = Section->VirtualAddress + Section->SizeOfRawData;
1126        }
1127      }
1128
1129      if (TempDebugEntryRva != 0) {
1130        if (!(ImageContext->IsTeImage)) {
1131          ImageContext->CodeView = PeCoffLoaderImageAddress (ImageContext, TempDebugEntryRva);
1132        } else {
1133          ImageContext->CodeView = (VOID *)(
1134                      (UINTN)ImageContext->ImageAddress +
1135                      (UINTN)TempDebugEntryRva +
1136                      (UINTN)sizeof(EFI_TE_IMAGE_HEADER) -
1137                (UINTN) TeHdr->StrippedSize
1138            );
1139        }
1140
1141        if (ImageContext->CodeView == NULL) {
1142          ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;
1143          return RETURN_LOAD_ERROR;
1144        }
1145
1146        if (DebugEntry->RVA == 0) {
1147          Size = DebugEntry->SizeOfData;
1148          if (!(ImageContext->IsTeImage)) {
1149            Status = ImageContext->ImageRead (
1150                                    ImageContext->Handle,
1151                                    DebugEntry->FileOffset,
1152                                    &Size,
1153                                    ImageContext->CodeView
1154                                    );
1155          } else {
1156            Status = ImageContext->ImageRead (
1157                                    ImageContext->Handle,
1158                                    DebugEntry->FileOffset + sizeof (EFI_TE_IMAGE_HEADER) - TeHdr->StrippedSize,
1159                                    &Size,
1160                                    ImageContext->CodeView
1161                                    );
1162            //
1163            // Should we apply fix up to this field according to the size difference between PE and TE?
1164            // Because now we maintain TE header fields unfixed, this field will also remain as they are
1165            // in original PE image.
1166            //
1167          }
1168
1169          if (RETURN_ERROR (Status)) {
1170            ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;
1171            return RETURN_LOAD_ERROR;
1172          }
1173
1174          DebugEntry->RVA = TempDebugEntryRva;
1175        }
1176
1177        switch (*(UINT32 *) ImageContext->CodeView) {
1178        case CODEVIEW_SIGNATURE_NB10:
1179          ImageContext->PdbPointer = (CHAR8 *) ImageContext->CodeView + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY);
1180          break;
1181
1182        case CODEVIEW_SIGNATURE_RSDS:
1183          ImageContext->PdbPointer = (CHAR8 *) ImageContext->CodeView + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY);
1184          break;
1185
1186        case CODEVIEW_SIGNATURE_MTOC:
1187          ImageContext->PdbPointer = (CHAR8 *) ImageContext->CodeView + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_MTOC_ENTRY);
1188
1189        default:
1190          break;
1191        }
1192      }
1193    }
1194  }
1195
1196  return Status;
1197}
1198
1199/**
1200  Returns a pointer to the PDB file name for a raw PE/COFF image that is not
1201  loaded into system memory with the PE/COFF Loader Library functions.
1202
1203  Returns the PDB file name for the PE/COFF image specified by Pe32Data.  If
1204  the PE/COFF image specified by Pe32Data is not a valid, then NULL is
1205  returned.  If the PE/COFF image specified by Pe32Data does not contain a
1206  debug directory entry, then NULL is returned.  If the debug directory entry
1207  in the PE/COFF image specified by Pe32Data does not contain a PDB file name,
1208  then NULL is returned.
1209  If Pe32Data is NULL, then return NULL.
1210
1211  @param  Pe32Data   Pointer to the PE/COFF image that is loaded in system
1212                     memory.
1213
1214  @return The PDB file name for the PE/COFF image specified by Pe32Data or NULL
1215          if it cannot be retrieved.
1216
1217**/
1218VOID *
1219EFIAPI
1220PeCoffLoaderGetPdbPointer (
1221  IN VOID  *Pe32Data
1222  )
1223{
1224  EFI_IMAGE_DOS_HEADER                  *DosHdr;
1225  EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION   Hdr;
1226  EFI_IMAGE_DATA_DIRECTORY              *DirectoryEntry;
1227  EFI_IMAGE_DEBUG_DIRECTORY_ENTRY       *DebugEntry;
1228  UINTN                                 DirCount;
1229  VOID                                  *CodeViewEntryPointer;
1230  INTN                                  TEImageAdjust;
1231  UINT32                                NumberOfRvaAndSizes;
1232  UINT16                                Magic;
1233  EFI_IMAGE_SECTION_HEADER              *SectionHeader;
1234  UINT32                                Index, Index1;
1235
1236  if (Pe32Data == NULL) {
1237    return NULL;
1238  }
1239
1240  TEImageAdjust       = 0;
1241  DirectoryEntry      = NULL;
1242  DebugEntry          = NULL;
1243  NumberOfRvaAndSizes = 0;
1244  Index               = 0;
1245  Index1              = 0;
1246  SectionHeader       = NULL;
1247
1248  DosHdr = (EFI_IMAGE_DOS_HEADER *)Pe32Data;
1249  if (EFI_IMAGE_DOS_SIGNATURE == DosHdr->e_magic) {
1250    //
1251    // DOS image header is present, so read the PE header after the DOS image header.
1252    //
1253    Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINTN) Pe32Data + (UINTN) ((DosHdr->e_lfanew) & 0x0ffff));
1254  } else {
1255    //
1256    // DOS image header is not present, so PE header is at the image base.
1257    //
1258    Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)Pe32Data;
1259  }
1260
1261  if (EFI_TE_IMAGE_HEADER_SIGNATURE == Hdr.Te->Signature) {
1262    if (Hdr.Te->DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress != 0) {
1263      DirectoryEntry  = &Hdr.Te->DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG];
1264      TEImageAdjust   = sizeof (EFI_TE_IMAGE_HEADER) - Hdr.Te->StrippedSize;
1265
1266      //
1267      // Get the DebugEntry offset in the raw data image.
1268      //
1269      SectionHeader = (EFI_IMAGE_SECTION_HEADER *) (Hdr.Te + 1);
1270      Index = Hdr.Te->NumberOfSections;
1271      for (Index1 = 0; Index1 < Index; Index1 ++) {
1272        if ((DirectoryEntry->VirtualAddress >= SectionHeader[Index1].VirtualAddress) &&
1273           (DirectoryEntry->VirtualAddress < (SectionHeader[Index1].VirtualAddress + SectionHeader[Index1].Misc.VirtualSize))) {
1274          DebugEntry = (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *)((UINTN) Hdr.Te +
1275                        DirectoryEntry->VirtualAddress -
1276                        SectionHeader [Index1].VirtualAddress +
1277                        SectionHeader [Index1].PointerToRawData +
1278                        TEImageAdjust);
1279          break;
1280        }
1281      }
1282    }
1283  } else if (EFI_IMAGE_NT_SIGNATURE == Hdr.Pe32->Signature) {
1284    //
1285    // NOTE: We use Machine field to identify PE32/PE32+, instead of Magic.
1286    //       It is due to backward-compatibility, for some system might
1287    //       generate PE32+ image with PE32 Magic.
1288    //
1289    switch (Hdr.Pe32->FileHeader.Machine) {
1290    case EFI_IMAGE_MACHINE_IA32:
1291    case EFI_IMAGE_MACHINE_ARMT:
1292      //
1293      // Assume PE32 image with IA32 Machine field.
1294      //
1295      Magic = EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC;
1296      break;
1297    case EFI_IMAGE_MACHINE_X64:
1298    case EFI_IMAGE_MACHINE_IPF:
1299      //
1300      // Assume PE32+ image with X64 or IPF Machine field
1301      //
1302      Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC;
1303      break;
1304    default:
1305      //
1306      // For unknow Machine field, use Magic in optional Header
1307      //
1308      Magic = Hdr.Pe32->OptionalHeader.Magic;
1309    }
1310
1311    SectionHeader = (EFI_IMAGE_SECTION_HEADER *) (
1312                       (UINT8 *) Hdr.Pe32 +
1313                       sizeof (UINT32) +
1314                       sizeof (EFI_IMAGE_FILE_HEADER) +
1315                       Hdr.Pe32->FileHeader.SizeOfOptionalHeader
1316                       );
1317    Index = Hdr.Pe32->FileHeader.NumberOfSections;
1318
1319    if (EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC == Magic) {
1320      //
1321      // Use PE32 offset get Debug Directory Entry
1322      //
1323      NumberOfRvaAndSizes = Hdr.Pe32->OptionalHeader.NumberOfRvaAndSizes;
1324      DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)&(Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG]);
1325    } else if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
1326      //
1327      // Use PE32+ offset get Debug Directory Entry
1328      //
1329      NumberOfRvaAndSizes = Hdr.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes;
1330      DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)&(Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG]);
1331    }
1332
1333    if (NumberOfRvaAndSizes <= EFI_IMAGE_DIRECTORY_ENTRY_DEBUG || DirectoryEntry->VirtualAddress == 0) {
1334      DirectoryEntry = NULL;
1335      DebugEntry = NULL;
1336    } else {
1337      //
1338      // Get the DebugEntry offset in the raw data image.
1339      //
1340      for (Index1 = 0; Index1 < Index; Index1 ++) {
1341        if ((DirectoryEntry->VirtualAddress >= SectionHeader[Index1].VirtualAddress) &&
1342           (DirectoryEntry->VirtualAddress < (SectionHeader[Index1].VirtualAddress + SectionHeader[Index1].Misc.VirtualSize))) {
1343          DebugEntry = (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *) (
1344                       (UINTN) Pe32Data +
1345                       DirectoryEntry->VirtualAddress -
1346                       SectionHeader[Index1].VirtualAddress +
1347                       SectionHeader[Index1].PointerToRawData);
1348          break;
1349        }
1350      }
1351    }
1352  } else {
1353    return NULL;
1354  }
1355
1356  if (NULL == DebugEntry || NULL == DirectoryEntry) {
1357    return NULL;
1358  }
1359
1360  //
1361  // Scan the directory to find the debug entry.
1362  //
1363  for (DirCount = 0; DirCount < DirectoryEntry->Size; DirCount += sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY), DebugEntry++) {
1364    if (EFI_IMAGE_DEBUG_TYPE_CODEVIEW == DebugEntry->Type) {
1365      if (DebugEntry->SizeOfData > 0) {
1366        //
1367        // Get the DebugEntry offset in the raw data image.
1368        //
1369        CodeViewEntryPointer = NULL;
1370        for (Index1 = 0; Index1 < Index; Index1 ++) {
1371          if ((DebugEntry->RVA >= SectionHeader[Index1].VirtualAddress) &&
1372             (DebugEntry->RVA < (SectionHeader[Index1].VirtualAddress + SectionHeader[Index1].Misc.VirtualSize))) {
1373            CodeViewEntryPointer = (VOID *) (
1374                                   ((UINTN)Pe32Data) +
1375                                   (UINTN) DebugEntry->RVA -
1376                                   SectionHeader[Index1].VirtualAddress +
1377                                   SectionHeader[Index1].PointerToRawData +
1378                                   (UINTN)TEImageAdjust);
1379            break;
1380          }
1381        }
1382        if (Index1 >= Index) {
1383          //
1384          // Can't find CodeViewEntryPointer in raw PE/COFF image.
1385          //
1386          continue;
1387        }
1388        switch (* (UINT32 *) CodeViewEntryPointer) {
1389        case CODEVIEW_SIGNATURE_NB10:
1390          return (VOID *) ((CHAR8 *)CodeViewEntryPointer + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY));
1391        case CODEVIEW_SIGNATURE_RSDS:
1392          return (VOID *) ((CHAR8 *)CodeViewEntryPointer + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY));
1393        case CODEVIEW_SIGNATURE_MTOC:
1394          return (VOID *) ((CHAR8 *)CodeViewEntryPointer + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_MTOC_ENTRY));
1395        default:
1396          break;
1397        }
1398      }
1399    }
1400  }
1401
1402  return NULL;
1403}
1404
1405
1406RETURN_STATUS
1407EFIAPI
1408PeCoffLoaderGetEntryPoint (
1409  IN  VOID  *Pe32Data,
1410  OUT VOID  **EntryPoint,
1411  OUT VOID  **BaseOfImage
1412  )
1413{
1414  EFI_IMAGE_DOS_HEADER                  *DosHdr;
1415  EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION   Hdr;
1416
1417  DosHdr = (EFI_IMAGE_DOS_HEADER *)Pe32Data;
1418  if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) {
1419    //
1420    // DOS image header is present, so read the PE header after the DOS image header.
1421    //
1422    Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINTN) Pe32Data + (UINTN) ((DosHdr->e_lfanew) & 0x0ffff));
1423  } else {
1424    //
1425    // DOS image header is not present, so PE header is at the image base.
1426    //
1427    Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)Pe32Data;
1428  }
1429
1430  //
1431  // Calculate the entry point relative to the start of the image.
1432  // AddressOfEntryPoint is common for PE32 & PE32+
1433  //
1434  if (Hdr.Te->Signature == EFI_TE_IMAGE_HEADER_SIGNATURE) {
1435    *BaseOfImage = (VOID *)(UINTN)(Hdr.Te->ImageBase + Hdr.Te->StrippedSize - sizeof (EFI_TE_IMAGE_HEADER));
1436    *EntryPoint = (VOID *)((UINTN)*BaseOfImage + (Hdr.Te->AddressOfEntryPoint & 0x0ffffffff) + sizeof(EFI_TE_IMAGE_HEADER) - Hdr.Te->StrippedSize);
1437    return RETURN_SUCCESS;
1438  } else if (Hdr.Pe32->Signature == EFI_IMAGE_NT_SIGNATURE) {
1439    *EntryPoint = (VOID *)(UINTN)Hdr.Pe32->OptionalHeader.AddressOfEntryPoint;
1440    if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
1441      *BaseOfImage = (VOID *)(UINTN)Hdr.Pe32->OptionalHeader.ImageBase;
1442    } else {
1443      *BaseOfImage = (VOID *)(UINTN)Hdr.Pe32Plus->OptionalHeader.ImageBase;
1444    }
1445    *EntryPoint = (VOID *)(UINTN)((UINTN)*EntryPoint + (UINTN)*BaseOfImage);
1446    return RETURN_SUCCESS;
1447  }
1448
1449  return RETURN_UNSUPPORTED;
1450}
1451