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