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