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