1/** @file
2  Base PE/COFF loader supports loading any PE32/PE32+ or TE image, but
3  only supports relocating IA32, x64, IPF, and EBC images.
4
5  Caution: This file requires additional review when modified.
6  This library will have external input - PE/COFF image.
7  This external input must be validated carefully to avoid security issue like
8  buffer overflow, integer overflow.
9
10  The basic guideline is that caller need provide ImageContext->ImageRead () with the
11  necessary data range check, to make sure when this library reads PE/COFF image, the
12  PE image buffer is always in valid range.
13  This library will also do some additional check for PE header fields.
14
15  PeCoffLoaderGetPeHeader() routine will do basic check for PE/COFF header.
16  PeCoffLoaderGetImageInfo() routine will do basic check for whole PE/COFF image.
17
18  Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
19  Portions copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR>
20  This program and the accompanying materials
21  are licensed and made available under the terms and conditions of the BSD License
22  which accompanies this distribution.  The full text of the license may be found at
23  http://opensource.org/licenses/bsd-license.php.
24
25  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
26  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
27
28**/
29
30#include "BasePeCoffLibInternals.h"
31
32/**
33  Adjust some fields in section header for TE image.
34
35  @param  SectionHeader             Pointer to the section header.
36  @param  TeStrippedOffset          Size adjust for the TE image.
37
38**/
39VOID
40PeCoffLoaderAdjustOffsetForTeImage (
41  EFI_IMAGE_SECTION_HEADER              *SectionHeader,
42  UINT32                                TeStrippedOffset
43  )
44{
45  SectionHeader->VirtualAddress   -= TeStrippedOffset;
46  SectionHeader->PointerToRawData -= TeStrippedOffset;
47}
48
49/**
50  Retrieves the magic value from the PE/COFF header.
51
52  @param  Hdr             The buffer in which to return the PE32, PE32+, or TE header.
53
54  @return EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC - Image is PE32
55  @return EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC - Image is PE32+
56
57**/
58UINT16
59PeCoffLoaderGetPeHeaderMagicValue (
60  IN  EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION  Hdr
61  )
62{
63  //
64  // NOTE: Some versions of Linux ELILO for Itanium have an incorrect magic value
65  //       in the PE/COFF Header.  If the MachineType is Itanium(IA64) and the
66  //       Magic value in the OptionalHeader is  EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
67  //       then override the returned value to EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC
68  //
69  if (Hdr.Pe32->FileHeader.Machine == IMAGE_FILE_MACHINE_IA64 && Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
70    return EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC;
71  }
72  //
73  // Return the magic value from the PC/COFF Optional Header
74  //
75  return Hdr.Pe32->OptionalHeader.Magic;
76}
77
78
79/**
80  Retrieves the PE or TE Header from a PE/COFF or TE image.
81
82  Caution: This function may receive untrusted input.
83  PE/COFF image is external input, so this routine will
84  also done many checks in PE image to make sure PE image DosHeader, PeOptionHeader,
85  SizeOfHeader, Section Data Region and Security Data Region be in PE image range.
86
87  @param  ImageContext    The context of the image being loaded.
88  @param  Hdr             The buffer in which to return the PE32, PE32+, or TE header.
89
90  @retval RETURN_SUCCESS  The PE or TE Header is read.
91  @retval Other           The error status from reading the PE/COFF or TE image using the ImageRead function.
92
93**/
94RETURN_STATUS
95PeCoffLoaderGetPeHeader (
96  IN OUT PE_COFF_LOADER_IMAGE_CONTEXT         *ImageContext,
97  OUT    EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION  Hdr
98  )
99{
100  RETURN_STATUS         Status;
101  EFI_IMAGE_DOS_HEADER  DosHdr;
102  UINTN                 Size;
103  UINTN                 ReadSize;
104  UINT16                Magic;
105  UINT32                SectionHeaderOffset;
106  UINT32                Index;
107  UINT32                HeaderWithoutDataDir;
108  CHAR8                 BufferData;
109  UINTN                 NumberOfSections;
110  EFI_IMAGE_SECTION_HEADER  SectionHeader;
111
112  //
113  // Read the DOS image header to check for its existence
114  //
115  Size = sizeof (EFI_IMAGE_DOS_HEADER);
116  ReadSize = Size;
117  Status = ImageContext->ImageRead (
118                           ImageContext->Handle,
119                           0,
120                           &Size,
121                           &DosHdr
122                           );
123  if (RETURN_ERROR (Status) || (Size != ReadSize)) {
124    ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;
125    if (Size != ReadSize) {
126      Status = RETURN_UNSUPPORTED;
127    }
128    return Status;
129  }
130
131  ImageContext->PeCoffHeaderOffset = 0;
132  if (DosHdr.e_magic == EFI_IMAGE_DOS_SIGNATURE) {
133    //
134    // DOS image header is present, so read the PE header after the DOS image
135    // header
136    //
137    ImageContext->PeCoffHeaderOffset = DosHdr.e_lfanew;
138  }
139
140  //
141  // Read the PE/COFF Header. For PE32 (32-bit) this will read in too much
142  // data, but that should not hurt anything. Hdr.Pe32->OptionalHeader.Magic
143  // determines if this is a PE32 or PE32+ image. The magic is in the same
144  // location in both images.
145  //
146  Size = sizeof (EFI_IMAGE_OPTIONAL_HEADER_UNION);
147  ReadSize = Size;
148  Status = ImageContext->ImageRead (
149                           ImageContext->Handle,
150                           ImageContext->PeCoffHeaderOffset,
151                           &Size,
152                           Hdr.Pe32
153                           );
154  if (RETURN_ERROR (Status) || (Size != ReadSize)) {
155    ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;
156    if (Size != ReadSize) {
157      Status = RETURN_UNSUPPORTED;
158    }
159    return Status;
160  }
161
162  //
163  // Use Signature to figure out if we understand the image format
164  //
165  if (Hdr.Te->Signature == EFI_TE_IMAGE_HEADER_SIGNATURE) {
166    ImageContext->IsTeImage         = TRUE;
167    ImageContext->Machine           = Hdr.Te->Machine;
168    ImageContext->ImageType         = (UINT16)(Hdr.Te->Subsystem);
169    //
170    // For TeImage, SectionAlignment is undefined to be set to Zero
171    // ImageSize can be calculated.
172    //
173    ImageContext->ImageSize         = 0;
174    ImageContext->SectionAlignment  = 0;
175    ImageContext->SizeOfHeaders     = sizeof (EFI_TE_IMAGE_HEADER) + (UINTN)Hdr.Te->BaseOfCode - (UINTN)Hdr.Te->StrippedSize;
176
177    //
178    // Check the StrippedSize.
179    //
180    if (sizeof (EFI_TE_IMAGE_HEADER) >= (UINT32)Hdr.Te->StrippedSize) {
181      ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;
182      return RETURN_UNSUPPORTED;
183    }
184
185    //
186    // Check the SizeOfHeaders field.
187    //
188    if (Hdr.Te->BaseOfCode <= Hdr.Te->StrippedSize) {
189      ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;
190      return RETURN_UNSUPPORTED;
191    }
192
193    //
194    // Read last byte of Hdr.Te->SizeOfHeaders from the file.
195    //
196    Size = 1;
197    ReadSize = Size;
198    Status = ImageContext->ImageRead (
199                             ImageContext->Handle,
200                             ImageContext->SizeOfHeaders - 1,
201                             &Size,
202                             &BufferData
203                             );
204    if (RETURN_ERROR (Status) || (Size != ReadSize)) {
205      ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;
206      if (Size != ReadSize) {
207        Status = RETURN_UNSUPPORTED;
208      }
209      return Status;
210    }
211
212    //
213    // TE Image Data Directory Entry size is non-zero, but the Data Directory Virtual Address is zero.
214    // This case is not a valid TE image.
215    //
216    if ((Hdr.Te->DataDirectory[0].Size != 0 && Hdr.Te->DataDirectory[0].VirtualAddress == 0) ||
217        (Hdr.Te->DataDirectory[1].Size != 0 && Hdr.Te->DataDirectory[1].VirtualAddress == 0)) {
218      ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;
219      return RETURN_UNSUPPORTED;
220    }
221  } else if (Hdr.Pe32->Signature == EFI_IMAGE_NT_SIGNATURE)  {
222    ImageContext->IsTeImage = FALSE;
223    ImageContext->Machine = Hdr.Pe32->FileHeader.Machine;
224
225    Magic = PeCoffLoaderGetPeHeaderMagicValue (Hdr);
226
227    if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
228      //
229      // 1. Check OptionalHeader.NumberOfRvaAndSizes filed.
230      //
231      if (EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES < Hdr.Pe32->OptionalHeader.NumberOfRvaAndSizes) {
232        ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;
233        return RETURN_UNSUPPORTED;
234      }
235
236      //
237      // 2. Check the FileHeader.SizeOfOptionalHeader field.
238      // OptionalHeader.NumberOfRvaAndSizes is not bigger than 16, so
239      // OptionalHeader.NumberOfRvaAndSizes * sizeof (EFI_IMAGE_DATA_DIRECTORY) will not overflow.
240      //
241      HeaderWithoutDataDir = sizeof (EFI_IMAGE_OPTIONAL_HEADER32) - sizeof (EFI_IMAGE_DATA_DIRECTORY) * EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES;
242      if (((UINT32)Hdr.Pe32->FileHeader.SizeOfOptionalHeader - HeaderWithoutDataDir) !=
243          Hdr.Pe32->OptionalHeader.NumberOfRvaAndSizes * sizeof (EFI_IMAGE_DATA_DIRECTORY)) {
244        ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;
245        return RETURN_UNSUPPORTED;
246      }
247
248      SectionHeaderOffset = ImageContext->PeCoffHeaderOffset + sizeof (UINT32) + sizeof (EFI_IMAGE_FILE_HEADER) + Hdr.Pe32->FileHeader.SizeOfOptionalHeader;
249      //
250      // 3. Check the FileHeader.NumberOfSections field.
251      //
252      if (Hdr.Pe32->OptionalHeader.SizeOfImage <= SectionHeaderOffset) {
253        ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;
254        return RETURN_UNSUPPORTED;
255      }
256      if ((Hdr.Pe32->OptionalHeader.SizeOfImage - SectionHeaderOffset) / EFI_IMAGE_SIZEOF_SECTION_HEADER <= Hdr.Pe32->FileHeader.NumberOfSections) {
257        ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;
258        return RETURN_UNSUPPORTED;
259      }
260
261      //
262      // 4. Check the OptionalHeader.SizeOfHeaders field.
263      //
264      if (Hdr.Pe32->OptionalHeader.SizeOfHeaders <= SectionHeaderOffset) {
265        ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;
266        return RETURN_UNSUPPORTED;
267      }
268      if (Hdr.Pe32->OptionalHeader.SizeOfHeaders >= Hdr.Pe32->OptionalHeader.SizeOfImage) {
269        ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;
270        return RETURN_UNSUPPORTED;
271      }
272      if ((Hdr.Pe32->OptionalHeader.SizeOfHeaders - SectionHeaderOffset) / EFI_IMAGE_SIZEOF_SECTION_HEADER < (UINT32)Hdr.Pe32->FileHeader.NumberOfSections) {
273        ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;
274        return RETURN_UNSUPPORTED;
275      }
276
277      //
278      // 4.2 Read last byte of Hdr.Pe32.OptionalHeader.SizeOfHeaders from the file.
279      //
280      Size = 1;
281      ReadSize = Size;
282      Status = ImageContext->ImageRead (
283                               ImageContext->Handle,
284                               Hdr.Pe32->OptionalHeader.SizeOfHeaders - 1,
285                               &Size,
286                               &BufferData
287                               );
288      if (RETURN_ERROR (Status) || (Size != ReadSize)) {
289        ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;
290        if (Size != ReadSize) {
291          Status = RETURN_UNSUPPORTED;
292        }
293        return Status;
294      }
295
296      //
297      // Check the EFI_IMAGE_DIRECTORY_ENTRY_SECURITY data.
298      // Read the last byte to make sure the data is in the image region.
299      // The DataDirectory array begin with 1, not 0, so here use < to compare not <=.
300      //
301      if (EFI_IMAGE_DIRECTORY_ENTRY_SECURITY < Hdr.Pe32->OptionalHeader.NumberOfRvaAndSizes) {
302        if (Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size != 0) {
303          //
304          // Check the member data to avoid overflow.
305          //
306          if ((UINT32) (~0) - Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].VirtualAddress <
307              Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size) {
308            ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;
309            return RETURN_UNSUPPORTED;
310          }
311
312          //
313          // Read last byte of section header from file
314          //
315          Size = 1;
316          ReadSize = Size;
317          Status = ImageContext->ImageRead (
318                                   ImageContext->Handle,
319                                   Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].VirtualAddress +
320                                    Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size - 1,
321                                   &Size,
322                                   &BufferData
323                                   );
324          if (RETURN_ERROR (Status) || (Size != ReadSize)) {
325            ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;
326            if (Size != ReadSize) {
327              Status = RETURN_UNSUPPORTED;
328            }
329            return Status;
330          }
331        }
332      }
333
334      //
335      // Use PE32 offset
336      //
337      ImageContext->ImageType         = Hdr.Pe32->OptionalHeader.Subsystem;
338      ImageContext->ImageSize         = (UINT64)Hdr.Pe32->OptionalHeader.SizeOfImage;
339      ImageContext->SectionAlignment  = Hdr.Pe32->OptionalHeader.SectionAlignment;
340      ImageContext->SizeOfHeaders     = Hdr.Pe32->OptionalHeader.SizeOfHeaders;
341
342    } else if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
343      //
344      // 1. Check FileHeader.NumberOfRvaAndSizes filed.
345      //
346      if (EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES < Hdr.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes) {
347        ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;
348        return RETURN_UNSUPPORTED;
349      }
350      //
351      // 2. Check the FileHeader.SizeOfOptionalHeader field.
352      // OptionalHeader.NumberOfRvaAndSizes is not bigger than 16, so
353      // OptionalHeader.NumberOfRvaAndSizes * sizeof (EFI_IMAGE_DATA_DIRECTORY) will not overflow.
354      //
355      HeaderWithoutDataDir = sizeof (EFI_IMAGE_OPTIONAL_HEADER64) - sizeof (EFI_IMAGE_DATA_DIRECTORY) * EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES;
356      if (((UINT32)Hdr.Pe32Plus->FileHeader.SizeOfOptionalHeader - HeaderWithoutDataDir) !=
357          Hdr.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes * sizeof (EFI_IMAGE_DATA_DIRECTORY)) {
358        ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;
359        return RETURN_UNSUPPORTED;
360      }
361
362      SectionHeaderOffset = ImageContext->PeCoffHeaderOffset + sizeof (UINT32) + sizeof (EFI_IMAGE_FILE_HEADER) + Hdr.Pe32Plus->FileHeader.SizeOfOptionalHeader;
363      //
364      // 3. Check the FileHeader.NumberOfSections field.
365      //
366      if (Hdr.Pe32Plus->OptionalHeader.SizeOfImage <= SectionHeaderOffset) {
367        ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;
368        return RETURN_UNSUPPORTED;
369      }
370      if ((Hdr.Pe32Plus->OptionalHeader.SizeOfImage - SectionHeaderOffset) / EFI_IMAGE_SIZEOF_SECTION_HEADER <= Hdr.Pe32Plus->FileHeader.NumberOfSections) {
371        ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;
372        return RETURN_UNSUPPORTED;
373      }
374
375      //
376      // 4. Check the OptionalHeader.SizeOfHeaders field.
377      //
378      if (Hdr.Pe32Plus->OptionalHeader.SizeOfHeaders <= SectionHeaderOffset) {
379        ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;
380        return RETURN_UNSUPPORTED;
381      }
382      if (Hdr.Pe32Plus->OptionalHeader.SizeOfHeaders >= Hdr.Pe32Plus->OptionalHeader.SizeOfImage) {
383        ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;
384        return RETURN_UNSUPPORTED;
385      }
386      if ((Hdr.Pe32Plus->OptionalHeader.SizeOfHeaders - SectionHeaderOffset) / EFI_IMAGE_SIZEOF_SECTION_HEADER < (UINT32)Hdr.Pe32Plus->FileHeader.NumberOfSections) {
387        ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;
388        return RETURN_UNSUPPORTED;
389      }
390
391      //
392      // 4.2 Read last byte of Hdr.Pe32Plus.OptionalHeader.SizeOfHeaders from the file.
393      //
394      Size = 1;
395      ReadSize = Size;
396      Status = ImageContext->ImageRead (
397                               ImageContext->Handle,
398                               Hdr.Pe32Plus->OptionalHeader.SizeOfHeaders - 1,
399                               &Size,
400                               &BufferData
401                               );
402      if (RETURN_ERROR (Status) || (Size != ReadSize)) {
403        ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;
404        if (Size != ReadSize) {
405          Status = RETURN_UNSUPPORTED;
406        }
407        return Status;
408      }
409
410      //
411      // Check the EFI_IMAGE_DIRECTORY_ENTRY_SECURITY data.
412      // Read the last byte to make sure the data is in the image region.
413      // The DataDirectory array begin with 1, not 0, so here use < to compare not <=.
414      //
415      if (EFI_IMAGE_DIRECTORY_ENTRY_SECURITY < Hdr.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes) {
416        if (Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size != 0) {
417          //
418          // Check the member data to avoid overflow.
419          //
420          if ((UINT32) (~0) - Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].VirtualAddress <
421              Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size) {
422            ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;
423            return RETURN_UNSUPPORTED;
424          }
425
426          //
427          // Read last byte of section header from file
428          //
429          Size = 1;
430          ReadSize = Size;
431          Status = ImageContext->ImageRead (
432                                   ImageContext->Handle,
433                                   Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].VirtualAddress +
434                                    Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size - 1,
435                                   &Size,
436                                   &BufferData
437                                   );
438          if (RETURN_ERROR (Status) || (Size != ReadSize)) {
439            ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;
440            if (Size != ReadSize) {
441              Status = RETURN_UNSUPPORTED;
442            }
443            return Status;
444          }
445        }
446      }
447
448      //
449      // Use PE32+ offset
450      //
451      ImageContext->ImageType         = Hdr.Pe32Plus->OptionalHeader.Subsystem;
452      ImageContext->ImageSize         = (UINT64) Hdr.Pe32Plus->OptionalHeader.SizeOfImage;
453      ImageContext->SectionAlignment  = Hdr.Pe32Plus->OptionalHeader.SectionAlignment;
454      ImageContext->SizeOfHeaders     = Hdr.Pe32Plus->OptionalHeader.SizeOfHeaders;
455    } else {
456      ImageContext->ImageError = IMAGE_ERROR_INVALID_MACHINE_TYPE;
457      return RETURN_UNSUPPORTED;
458    }
459  } else {
460    ImageContext->ImageError = IMAGE_ERROR_INVALID_MACHINE_TYPE;
461    return RETURN_UNSUPPORTED;
462  }
463
464  if (!PeCoffLoaderImageFormatSupported (ImageContext->Machine)) {
465    //
466    // If the PE/COFF loader does not support the image type return
467    // unsupported. This library can support lots of types of images
468    // this does not mean the user of this library can call the entry
469    // point of the image.
470    //
471    return RETURN_UNSUPPORTED;
472  }
473
474  //
475  // Check each section field.
476  //
477  if (ImageContext->IsTeImage) {
478    SectionHeaderOffset = sizeof(EFI_TE_IMAGE_HEADER);
479    NumberOfSections    = (UINTN) (Hdr.Te->NumberOfSections);
480  } else {
481    SectionHeaderOffset = ImageContext->PeCoffHeaderOffset + sizeof (UINT32) + sizeof (EFI_IMAGE_FILE_HEADER) + Hdr.Pe32->FileHeader.SizeOfOptionalHeader;
482    NumberOfSections    = (UINTN) (Hdr.Pe32->FileHeader.NumberOfSections);
483  }
484
485  for (Index = 0; Index < NumberOfSections; Index++) {
486    //
487    // Read section header from file
488    //
489    Size = sizeof (EFI_IMAGE_SECTION_HEADER);
490    ReadSize = Size;
491    Status = ImageContext->ImageRead (
492                             ImageContext->Handle,
493                             SectionHeaderOffset,
494                             &Size,
495                             &SectionHeader
496                             );
497    if (RETURN_ERROR (Status) || (Size != ReadSize)) {
498      ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;
499      if (Size != ReadSize) {
500        Status = RETURN_UNSUPPORTED;
501      }
502      return Status;
503    }
504
505    //
506    // Adjust some field in Section Header for TE image.
507    //
508    if (ImageContext->IsTeImage) {
509      PeCoffLoaderAdjustOffsetForTeImage (&SectionHeader, (UINT32)Hdr.Te->StrippedSize - sizeof (EFI_TE_IMAGE_HEADER));
510    }
511
512    if (SectionHeader.SizeOfRawData > 0) {
513      //
514      // Section data should bigger than the Pe header.
515      //
516      if (SectionHeader.VirtualAddress < ImageContext->SizeOfHeaders ||
517          SectionHeader.PointerToRawData < ImageContext->SizeOfHeaders) {
518        ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;
519        return RETURN_UNSUPPORTED;
520      }
521
522      //
523      // Check the member data to avoid overflow.
524      //
525      if ((UINT32) (~0) - SectionHeader.PointerToRawData < SectionHeader.SizeOfRawData) {
526        ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;
527        return RETURN_UNSUPPORTED;
528      }
529
530      //
531      // Base on the ImageRead function to check the section data field.
532      // Read the last byte to make sure the data is in the image region.
533      //
534      Size = 1;
535      ReadSize = Size;
536      Status = ImageContext->ImageRead (
537                               ImageContext->Handle,
538                               SectionHeader.PointerToRawData + SectionHeader.SizeOfRawData - 1,
539                               &Size,
540                               &BufferData
541                               );
542      if (RETURN_ERROR (Status) || (Size != ReadSize)) {
543        ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;
544        if (Size != ReadSize) {
545          Status = RETURN_UNSUPPORTED;
546        }
547        return Status;
548      }
549    }
550
551    //
552    // Check next section.
553    //
554    SectionHeaderOffset += sizeof (EFI_IMAGE_SECTION_HEADER);
555  }
556
557  return RETURN_SUCCESS;
558}
559
560
561/**
562  Retrieves information about a PE/COFF image.
563
564  Computes the PeCoffHeaderOffset, IsTeImage, ImageType, ImageAddress, ImageSize,
565  DestinationAddress, RelocationsStripped, SectionAlignment, SizeOfHeaders, and
566  DebugDirectoryEntryRva fields of the ImageContext structure.
567  If ImageContext is NULL, then return RETURN_INVALID_PARAMETER.
568  If the PE/COFF image accessed through the ImageRead service in the ImageContext
569  structure is not a supported PE/COFF image type, then return RETURN_UNSUPPORTED.
570  If any errors occur while computing the fields of ImageContext,
571  then the error status is returned in the ImageError field of ImageContext.
572  If the image is a TE image, then SectionAlignment is set to 0.
573  The ImageRead and Handle fields of ImageContext structure must be valid prior
574  to invoking this service.
575
576  Caution: This function may receive untrusted input.
577  PE/COFF image is external input, so this routine will
578  also done many checks in PE image to make sure PE image DosHeader, PeOptionHeader,
579  SizeOfHeader, Section Data Region and Security Data Region be in PE image range.
580
581  @param  ImageContext              The pointer to the image context structure that describes the PE/COFF
582                                    image that needs to be examined by this function.
583
584  @retval RETURN_SUCCESS            The information on the PE/COFF image was collected.
585  @retval RETURN_INVALID_PARAMETER  ImageContext is NULL.
586  @retval RETURN_UNSUPPORTED        The PE/COFF image is not supported.
587
588**/
589RETURN_STATUS
590EFIAPI
591PeCoffLoaderGetImageInfo (
592  IN OUT PE_COFF_LOADER_IMAGE_CONTEXT  *ImageContext
593  )
594{
595  RETURN_STATUS                         Status;
596  EFI_IMAGE_OPTIONAL_HEADER_UNION       HdrData;
597  EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION   Hdr;
598  EFI_IMAGE_DATA_DIRECTORY              *DebugDirectoryEntry;
599  UINTN                                 Size;
600  UINTN                                 ReadSize;
601  UINTN                                 Index;
602  UINTN                                 DebugDirectoryEntryRva;
603  UINTN                                 DebugDirectoryEntryFileOffset;
604  UINTN                                 SectionHeaderOffset;
605  EFI_IMAGE_SECTION_HEADER              SectionHeader;
606  EFI_IMAGE_DEBUG_DIRECTORY_ENTRY       DebugEntry;
607  UINT32                                NumberOfRvaAndSizes;
608  UINT16                                Magic;
609  UINT32                                TeStrippedOffset;
610
611  if (ImageContext == NULL) {
612    return RETURN_INVALID_PARAMETER;
613  }
614  //
615  // Assume success
616  //
617  ImageContext->ImageError  = IMAGE_ERROR_SUCCESS;
618
619  Hdr.Union = &HdrData;
620  Status = PeCoffLoaderGetPeHeader (ImageContext, Hdr);
621  if (RETURN_ERROR (Status)) {
622    return Status;
623  }
624
625  Magic = PeCoffLoaderGetPeHeaderMagicValue (Hdr);
626
627  //
628  // Retrieve the base address of the image
629  //
630  if (!(ImageContext->IsTeImage)) {
631    TeStrippedOffset = 0;
632    if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
633      //
634      // Use PE32 offset
635      //
636      ImageContext->ImageAddress = Hdr.Pe32->OptionalHeader.ImageBase;
637    } else {
638      //
639      // Use PE32+ offset
640      //
641      ImageContext->ImageAddress = Hdr.Pe32Plus->OptionalHeader.ImageBase;
642    }
643  } else {
644    TeStrippedOffset = (UINT32)Hdr.Te->StrippedSize - sizeof (EFI_TE_IMAGE_HEADER);
645    ImageContext->ImageAddress = (PHYSICAL_ADDRESS)(Hdr.Te->ImageBase + TeStrippedOffset);
646  }
647
648  //
649  // Initialize the alternate destination address to 0 indicating that it
650  // should not be used.
651  //
652  ImageContext->DestinationAddress = 0;
653
654  //
655  // Initialize the debug codeview pointer.
656  //
657  ImageContext->DebugDirectoryEntryRva = 0;
658  ImageContext->CodeView               = NULL;
659  ImageContext->PdbPointer             = NULL;
660
661  //
662  // Three cases with regards to relocations:
663  // - Image has base relocs, RELOCS_STRIPPED==0    => image is relocatable
664  // - Image has no base relocs, RELOCS_STRIPPED==1 => Image is not relocatable
665  // - Image has no base relocs, RELOCS_STRIPPED==0 => Image is relocatable but
666  //   has no base relocs to apply
667  // Obviously having base relocations with RELOCS_STRIPPED==1 is invalid.
668  //
669  // Look at the file header to determine if relocations have been stripped, and
670  // save this information in the image context for later use.
671  //
672  if ((!(ImageContext->IsTeImage)) && ((Hdr.Pe32->FileHeader.Characteristics & EFI_IMAGE_FILE_RELOCS_STRIPPED) != 0)) {
673    ImageContext->RelocationsStripped = TRUE;
674  } else if ((ImageContext->IsTeImage) && (Hdr.Te->DataDirectory[0].Size == 0) && (Hdr.Te->DataDirectory[0].VirtualAddress == 0)) {
675    ImageContext->RelocationsStripped = TRUE;
676  } else {
677    ImageContext->RelocationsStripped = FALSE;
678  }
679
680  if (!(ImageContext->IsTeImage)) {
681    if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
682      //
683      // Use PE32 offset
684      //
685      NumberOfRvaAndSizes = Hdr.Pe32->OptionalHeader.NumberOfRvaAndSizes;
686      DebugDirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)&(Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG]);
687    } else {
688      //
689      // Use PE32+ offset
690      //
691      NumberOfRvaAndSizes = Hdr.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes;
692      DebugDirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)&(Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG]);
693    }
694
695    if (NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_DEBUG) {
696
697      DebugDirectoryEntryRva = DebugDirectoryEntry->VirtualAddress;
698
699      //
700      // Determine the file offset of the debug directory...  This means we walk
701      // the sections to find which section contains the RVA of the debug
702      // directory
703      //
704      DebugDirectoryEntryFileOffset = 0;
705
706      SectionHeaderOffset = (UINTN)(
707                               ImageContext->PeCoffHeaderOffset +
708                               sizeof (UINT32) +
709                               sizeof (EFI_IMAGE_FILE_HEADER) +
710                               Hdr.Pe32->FileHeader.SizeOfOptionalHeader
711                               );
712
713      for (Index = 0; Index < Hdr.Pe32->FileHeader.NumberOfSections; Index++) {
714        //
715        // Read section header from file
716        //
717        Size = sizeof (EFI_IMAGE_SECTION_HEADER);
718        ReadSize = Size;
719        Status = ImageContext->ImageRead (
720                                 ImageContext->Handle,
721                                 SectionHeaderOffset,
722                                 &Size,
723                                 &SectionHeader
724                                 );
725        if (RETURN_ERROR (Status) || (Size != ReadSize)) {
726          ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;
727          if (Size != ReadSize) {
728            Status = RETURN_UNSUPPORTED;
729          }
730          return Status;
731        }
732
733        if (DebugDirectoryEntryRva >= SectionHeader.VirtualAddress &&
734            DebugDirectoryEntryRva < SectionHeader.VirtualAddress + SectionHeader.Misc.VirtualSize) {
735
736          DebugDirectoryEntryFileOffset = DebugDirectoryEntryRva - SectionHeader.VirtualAddress + SectionHeader.PointerToRawData;
737          break;
738        }
739
740        SectionHeaderOffset += sizeof (EFI_IMAGE_SECTION_HEADER);
741      }
742
743      if (DebugDirectoryEntryFileOffset != 0) {
744        for (Index = 0; Index < DebugDirectoryEntry->Size; Index += sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY)) {
745          //
746          // Read next debug directory entry
747          //
748          Size = sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY);
749          ReadSize = Size;
750          Status = ImageContext->ImageRead (
751                                   ImageContext->Handle,
752                                   DebugDirectoryEntryFileOffset + Index,
753                                   &Size,
754                                   &DebugEntry
755                                   );
756          if (RETURN_ERROR (Status) || (Size != ReadSize)) {
757            ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;
758            if (Size != ReadSize) {
759              Status = RETURN_UNSUPPORTED;
760            }
761            return Status;
762          }
763
764          //
765          // From PeCoff spec, when DebugEntry.RVA == 0 means this debug info will not load into memory.
766          // Here we will always load EFI_IMAGE_DEBUG_TYPE_CODEVIEW type debug info. so need adjust the
767          // ImageContext->ImageSize when DebugEntry.RVA == 0.
768          //
769          if (DebugEntry.Type == EFI_IMAGE_DEBUG_TYPE_CODEVIEW) {
770            ImageContext->DebugDirectoryEntryRva = (UINT32) (DebugDirectoryEntryRva + Index);
771            if (DebugEntry.RVA == 0 && DebugEntry.FileOffset != 0) {
772              ImageContext->ImageSize += DebugEntry.SizeOfData;
773            }
774
775            return RETURN_SUCCESS;
776          }
777        }
778      }
779    }
780  } else {
781
782    DebugDirectoryEntry             = &Hdr.Te->DataDirectory[1];
783    DebugDirectoryEntryRva          = DebugDirectoryEntry->VirtualAddress;
784    SectionHeaderOffset             = (UINTN)(sizeof (EFI_TE_IMAGE_HEADER));
785
786    DebugDirectoryEntryFileOffset   = 0;
787
788    for (Index = 0; Index < Hdr.Te->NumberOfSections;) {
789      //
790      // Read section header from file
791      //
792      Size   = sizeof (EFI_IMAGE_SECTION_HEADER);
793      ReadSize = Size;
794      Status = ImageContext->ImageRead (
795                               ImageContext->Handle,
796                               SectionHeaderOffset,
797                               &Size,
798                               &SectionHeader
799                               );
800      if (RETURN_ERROR (Status) || (Size != ReadSize)) {
801        ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;
802        if (Size != ReadSize) {
803          Status = RETURN_UNSUPPORTED;
804        }
805        return Status;
806      }
807
808      if (DebugDirectoryEntryRva >= SectionHeader.VirtualAddress &&
809          DebugDirectoryEntryRva < SectionHeader.VirtualAddress + SectionHeader.Misc.VirtualSize) {
810        DebugDirectoryEntryFileOffset = DebugDirectoryEntryRva -
811                                        SectionHeader.VirtualAddress +
812                                        SectionHeader.PointerToRawData -
813                                        TeStrippedOffset;
814
815        //
816        // File offset of the debug directory was found, if this is not the last
817        // section, then skip to the last section for calculating the image size.
818        //
819        if (Index < (UINTN) Hdr.Te->NumberOfSections - 1) {
820          SectionHeaderOffset += (Hdr.Te->NumberOfSections - 1 - Index) * sizeof (EFI_IMAGE_SECTION_HEADER);
821          Index = Hdr.Te->NumberOfSections - 1;
822          continue;
823        }
824      }
825
826      //
827      // In Te image header there is not a field to describe the ImageSize.
828      // Actually, the ImageSize equals the RVA plus the VirtualSize of
829      // the last section mapped into memory (Must be rounded up to
830      // a multiple of Section Alignment). Per the PE/COFF specification, the
831      // section headers in the Section Table must appear in order of the RVA
832      // values for the corresponding sections. So the ImageSize can be determined
833      // by the RVA and the VirtualSize of the last section header in the
834      // Section Table.
835      //
836      if ((++Index) == (UINTN)Hdr.Te->NumberOfSections) {
837        ImageContext->ImageSize = (SectionHeader.VirtualAddress + SectionHeader.Misc.VirtualSize) - TeStrippedOffset;
838      }
839
840      SectionHeaderOffset += sizeof (EFI_IMAGE_SECTION_HEADER);
841    }
842
843    if (DebugDirectoryEntryFileOffset != 0) {
844      for (Index = 0; Index < DebugDirectoryEntry->Size; Index += sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY)) {
845        //
846        // Read next debug directory entry
847        //
848        Size = sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY);
849        ReadSize = Size;
850        Status = ImageContext->ImageRead (
851                                 ImageContext->Handle,
852                                 DebugDirectoryEntryFileOffset + Index,
853                                 &Size,
854                                 &DebugEntry
855                                 );
856        if (RETURN_ERROR (Status) || (Size != ReadSize)) {
857          ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;
858          if (Size != ReadSize) {
859            Status = RETURN_UNSUPPORTED;
860          }
861          return Status;
862        }
863
864        if (DebugEntry.Type == EFI_IMAGE_DEBUG_TYPE_CODEVIEW) {
865          ImageContext->DebugDirectoryEntryRva = (UINT32) (DebugDirectoryEntryRva + Index);
866          return RETURN_SUCCESS;
867        }
868      }
869    }
870  }
871
872  return RETURN_SUCCESS;
873}
874
875
876/**
877  Converts an image address to the loaded address.
878
879  @param  ImageContext      The context of the image being loaded.
880  @param  Address           The address to be converted to the loaded address.
881  @param  TeStrippedOffset  Stripped offset for TE image.
882
883  @return The converted address or NULL if the address can not be converted.
884
885**/
886VOID *
887PeCoffLoaderImageAddress (
888  IN OUT PE_COFF_LOADER_IMAGE_CONTEXT          *ImageContext,
889  IN     UINTN                                 Address,
890  IN     UINTN                                 TeStrippedOffset
891  )
892{
893  //
894  // Make sure that Address and ImageSize is correct for the loaded image.
895  //
896  if (Address >= ImageContext->ImageSize + TeStrippedOffset) {
897    ImageContext->ImageError = IMAGE_ERROR_INVALID_IMAGE_ADDRESS;
898    return NULL;
899  }
900
901  return (CHAR8 *)((UINTN) ImageContext->ImageAddress + Address - TeStrippedOffset);
902}
903
904/**
905  Applies relocation fixups to a PE/COFF image that was loaded with PeCoffLoaderLoadImage().
906
907  If the DestinationAddress field of ImageContext is 0, then use the ImageAddress field of
908  ImageContext as the relocation base address.  Otherwise, use the DestinationAddress field
909  of ImageContext as the relocation base address.  The caller must allocate the relocation
910  fixup log buffer and fill in the FixupData field of ImageContext prior to calling this function.
911
912  The ImageRead, Handle, PeCoffHeaderOffset,  IsTeImage, Machine, ImageType, ImageAddress,
913  ImageSize, DestinationAddress, RelocationsStripped, SectionAlignment, SizeOfHeaders,
914  DebugDirectoryEntryRva, EntryPoint, FixupDataSize, CodeView, PdbPointer, and FixupData of
915  the ImageContext structure must be valid prior to invoking this service.
916
917  If ImageContext is NULL, then ASSERT().
918
919  Note that if the platform does not maintain coherency between the instruction cache(s) and the data
920  cache(s) in hardware, then the caller is responsible for performing cache maintenance operations
921  prior to transferring control to a PE/COFF image that is loaded using this library.
922
923  @param  ImageContext        The pointer to the image context structure that describes the PE/COFF
924                              image that is being relocated.
925
926  @retval RETURN_SUCCESS      The PE/COFF image was relocated.
927                              Extended status information is in the ImageError field of ImageContext.
928  @retval RETURN_LOAD_ERROR   The image in not a valid PE/COFF image.
929                              Extended status information is in the ImageError field of ImageContext.
930  @retval RETURN_UNSUPPORTED  A relocation record type is not supported.
931                              Extended status information is in the ImageError field of ImageContext.
932
933**/
934RETURN_STATUS
935EFIAPI
936PeCoffLoaderRelocateImage (
937  IN OUT PE_COFF_LOADER_IMAGE_CONTEXT  *ImageContext
938  )
939{
940  RETURN_STATUS                         Status;
941  EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION   Hdr;
942  EFI_IMAGE_DATA_DIRECTORY              *RelocDir;
943  UINT64                                Adjust;
944  EFI_IMAGE_BASE_RELOCATION             *RelocBaseOrg;
945  EFI_IMAGE_BASE_RELOCATION             *RelocBase;
946  EFI_IMAGE_BASE_RELOCATION             *RelocBaseEnd;
947  UINT16                                *Reloc;
948  UINT16                                *RelocEnd;
949  CHAR8                                 *Fixup;
950  CHAR8                                 *FixupBase;
951  UINT16                                *Fixup16;
952  UINT32                                *Fixup32;
953  UINT64                                *Fixup64;
954  CHAR8                                 *FixupData;
955  PHYSICAL_ADDRESS                      BaseAddress;
956  UINT32                                NumberOfRvaAndSizes;
957  UINT16                                Magic;
958  UINT32                                TeStrippedOffset;
959
960  ASSERT (ImageContext != NULL);
961
962  //
963  // Assume success
964  //
965  ImageContext->ImageError = IMAGE_ERROR_SUCCESS;
966
967  //
968  // If there are no relocation entries, then we are done
969  //
970  if (ImageContext->RelocationsStripped) {
971    // Applies additional environment specific actions to relocate fixups
972    // to a PE/COFF image if needed
973    PeCoffLoaderRelocateImageExtraAction (ImageContext);
974    return RETURN_SUCCESS;
975  }
976
977  //
978  // If the destination address is not 0, use that rather than the
979  // image address as the relocation target.
980  //
981  if (ImageContext->DestinationAddress != 0) {
982    BaseAddress = ImageContext->DestinationAddress;
983  } else {
984    BaseAddress = ImageContext->ImageAddress;
985  }
986
987  if (!(ImageContext->IsTeImage)) {
988    Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINTN)ImageContext->ImageAddress + ImageContext->PeCoffHeaderOffset);
989    TeStrippedOffset = 0;
990    Magic = PeCoffLoaderGetPeHeaderMagicValue (Hdr);
991
992    if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
993      //
994      // Use PE32 offset
995      //
996      Adjust = (UINT64)BaseAddress - Hdr.Pe32->OptionalHeader.ImageBase;
997      if (Adjust != 0) {
998        Hdr.Pe32->OptionalHeader.ImageBase = (UINT32)BaseAddress;
999      }
1000
1001      NumberOfRvaAndSizes = Hdr.Pe32->OptionalHeader.NumberOfRvaAndSizes;
1002      RelocDir  = &Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC];
1003    } else {
1004      //
1005      // Use PE32+ offset
1006      //
1007      Adjust = (UINT64) BaseAddress - Hdr.Pe32Plus->OptionalHeader.ImageBase;
1008      if (Adjust != 0) {
1009        Hdr.Pe32Plus->OptionalHeader.ImageBase = (UINT64)BaseAddress;
1010      }
1011
1012      NumberOfRvaAndSizes = Hdr.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes;
1013      RelocDir  = &Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC];
1014    }
1015
1016    //
1017    // Find the relocation block
1018    // Per the PE/COFF spec, you can't assume that a given data directory
1019    // is present in the image. You have to check the NumberOfRvaAndSizes in
1020    // the optional header to verify a desired directory entry is there.
1021    //
1022    if ((NumberOfRvaAndSizes < EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC)) {
1023      RelocDir = NULL;
1024    }
1025  } else {
1026    Hdr.Te             = (EFI_TE_IMAGE_HEADER *)(UINTN)(ImageContext->ImageAddress);
1027    TeStrippedOffset   = (UINT32)Hdr.Te->StrippedSize - sizeof (EFI_TE_IMAGE_HEADER);
1028    Adjust             = (UINT64) (BaseAddress - (Hdr.Te->ImageBase + TeStrippedOffset));
1029    if (Adjust != 0) {
1030      Hdr.Te->ImageBase  = (UINT64) (BaseAddress - TeStrippedOffset);
1031    }
1032
1033    //
1034    // Find the relocation block
1035    //
1036    RelocDir = &Hdr.Te->DataDirectory[0];
1037  }
1038
1039  if ((RelocDir != NULL) && (RelocDir->Size > 0)) {
1040    RelocBase = (EFI_IMAGE_BASE_RELOCATION *) PeCoffLoaderImageAddress (ImageContext, RelocDir->VirtualAddress, TeStrippedOffset);
1041    RelocBaseEnd = (EFI_IMAGE_BASE_RELOCATION *) PeCoffLoaderImageAddress (ImageContext,
1042                                                                            RelocDir->VirtualAddress + RelocDir->Size - 1,
1043                                                                            TeStrippedOffset
1044                                                                            );
1045    if (RelocBase == NULL || RelocBaseEnd == NULL || RelocBaseEnd < RelocBase) {
1046      ImageContext->ImageError = IMAGE_ERROR_FAILED_RELOCATION;
1047      return RETURN_LOAD_ERROR;
1048    }
1049  } else {
1050    //
1051    // Set base and end to bypass processing below.
1052    //
1053    RelocBase = RelocBaseEnd = NULL;
1054  }
1055  RelocBaseOrg = RelocBase;
1056
1057  //
1058  // If Adjust is not zero, then apply fix ups to the image
1059  //
1060  if (Adjust != 0) {
1061    //
1062    // Run the relocation information and apply the fixups
1063    //
1064    FixupData = ImageContext->FixupData;
1065    while (RelocBase < RelocBaseEnd) {
1066
1067      Reloc     = (UINT16 *) ((CHAR8 *) RelocBase + sizeof (EFI_IMAGE_BASE_RELOCATION));
1068      //
1069      // Add check for RelocBase->SizeOfBlock field.
1070      //
1071      if (RelocBase->SizeOfBlock == 0) {
1072        ImageContext->ImageError = IMAGE_ERROR_FAILED_RELOCATION;
1073        return RETURN_LOAD_ERROR;
1074      }
1075      if ((UINTN)RelocBase > MAX_ADDRESS - RelocBase->SizeOfBlock) {
1076        ImageContext->ImageError = IMAGE_ERROR_FAILED_RELOCATION;
1077        return RETURN_LOAD_ERROR;
1078      }
1079
1080      RelocEnd  = (UINT16 *) ((CHAR8 *) RelocBase + RelocBase->SizeOfBlock);
1081      if ((UINTN)RelocEnd > (UINTN)RelocBaseOrg + RelocDir->Size) {
1082        ImageContext->ImageError = IMAGE_ERROR_FAILED_RELOCATION;
1083        return RETURN_LOAD_ERROR;
1084      }
1085      FixupBase = PeCoffLoaderImageAddress (ImageContext, RelocBase->VirtualAddress, TeStrippedOffset);
1086      if (FixupBase == NULL) {
1087        ImageContext->ImageError = IMAGE_ERROR_FAILED_RELOCATION;
1088        return RETURN_LOAD_ERROR;
1089      }
1090
1091      //
1092      // Run this relocation record
1093      //
1094      while (Reloc < RelocEnd) {
1095        Fixup = PeCoffLoaderImageAddress (ImageContext, RelocBase->VirtualAddress + (*Reloc & 0xFFF), TeStrippedOffset);
1096        if (Fixup == NULL) {
1097          ImageContext->ImageError = IMAGE_ERROR_FAILED_RELOCATION;
1098          return RETURN_LOAD_ERROR;
1099        }
1100        switch ((*Reloc) >> 12) {
1101        case EFI_IMAGE_REL_BASED_ABSOLUTE:
1102          break;
1103
1104        case EFI_IMAGE_REL_BASED_HIGH:
1105          Fixup16   = (UINT16 *) Fixup;
1106          *Fixup16 = (UINT16) (*Fixup16 + ((UINT16) ((UINT32) Adjust >> 16)));
1107          if (FixupData != NULL) {
1108            *(UINT16 *) FixupData = *Fixup16;
1109            FixupData             = FixupData + sizeof (UINT16);
1110          }
1111          break;
1112
1113        case EFI_IMAGE_REL_BASED_LOW:
1114          Fixup16   = (UINT16 *) Fixup;
1115          *Fixup16  = (UINT16) (*Fixup16 + (UINT16) Adjust);
1116          if (FixupData != NULL) {
1117            *(UINT16 *) FixupData = *Fixup16;
1118            FixupData             = FixupData + sizeof (UINT16);
1119          }
1120          break;
1121
1122        case EFI_IMAGE_REL_BASED_HIGHLOW:
1123          Fixup32   = (UINT32 *) Fixup;
1124          *Fixup32  = *Fixup32 + (UINT32) Adjust;
1125          if (FixupData != NULL) {
1126            FixupData             = ALIGN_POINTER (FixupData, sizeof (UINT32));
1127            *(UINT32 *)FixupData  = *Fixup32;
1128            FixupData             = FixupData + sizeof (UINT32);
1129          }
1130          break;
1131
1132        case EFI_IMAGE_REL_BASED_DIR64:
1133          Fixup64 = (UINT64 *) Fixup;
1134          *Fixup64 = *Fixup64 + (UINT64) Adjust;
1135          if (FixupData != NULL) {
1136            FixupData = ALIGN_POINTER (FixupData, sizeof(UINT64));
1137            *(UINT64 *)(FixupData) = *Fixup64;
1138            FixupData = FixupData + sizeof(UINT64);
1139          }
1140          break;
1141
1142        default:
1143          //
1144          // The common code does not handle some of the stranger IPF relocations
1145          // PeCoffLoaderRelocateImageEx () adds support for these complex fixups
1146          // on IPF and is a No-Op on other architectures.
1147          //
1148          Status = PeCoffLoaderRelocateImageEx (Reloc, Fixup, &FixupData, Adjust);
1149          if (RETURN_ERROR (Status)) {
1150            ImageContext->ImageError = IMAGE_ERROR_FAILED_RELOCATION;
1151            return Status;
1152          }
1153        }
1154
1155        //
1156        // Next relocation record
1157        //
1158        Reloc += 1;
1159      }
1160
1161      //
1162      // Next reloc block
1163      //
1164      RelocBase = (EFI_IMAGE_BASE_RELOCATION *) RelocEnd;
1165    }
1166    ASSERT ((UINTN)FixupData <= (UINTN)ImageContext->FixupData + ImageContext->FixupDataSize);
1167
1168    //
1169    // Adjust the EntryPoint to match the linked-to address
1170    //
1171    if (ImageContext->DestinationAddress != 0) {
1172       ImageContext->EntryPoint -= (UINT64) ImageContext->ImageAddress;
1173       ImageContext->EntryPoint += (UINT64) ImageContext->DestinationAddress;
1174    }
1175  }
1176
1177  // Applies additional environment specific actions to relocate fixups
1178  // to a PE/COFF image if needed
1179  PeCoffLoaderRelocateImageExtraAction (ImageContext);
1180
1181  return RETURN_SUCCESS;
1182}
1183
1184/**
1185  Loads a PE/COFF image into memory.
1186
1187  Loads the PE/COFF image accessed through the ImageRead service of ImageContext into the buffer
1188  specified by the ImageAddress and ImageSize fields of ImageContext.  The caller must allocate
1189  the load buffer and fill in the ImageAddress and ImageSize fields prior to calling this function.
1190  The EntryPoint, FixupDataSize, CodeView, PdbPointer and HiiResourceData fields of ImageContext are computed.
1191  The ImageRead, Handle, PeCoffHeaderOffset,  IsTeImage,  Machine, ImageType, ImageAddress, ImageSize,
1192  DestinationAddress, RelocationsStripped, SectionAlignment, SizeOfHeaders, and DebugDirectoryEntryRva
1193  fields of the ImageContext structure must be valid prior to invoking this service.
1194
1195  If ImageContext is NULL, then ASSERT().
1196
1197  Note that if the platform does not maintain coherency between the instruction cache(s) and the data
1198  cache(s) in hardware, then the caller is responsible for performing cache maintenance operations
1199  prior to transferring control to a PE/COFF image that is loaded using this library.
1200
1201  @param  ImageContext              The pointer to the image context structure that describes the PE/COFF
1202                                    image that is being loaded.
1203
1204  @retval RETURN_SUCCESS            The PE/COFF image was loaded into the buffer specified by
1205                                    the ImageAddress and ImageSize fields of ImageContext.
1206                                    Extended status information is in the ImageError field of ImageContext.
1207  @retval RETURN_BUFFER_TOO_SMALL   The caller did not provide a large enough buffer.
1208                                    Extended status information is in the ImageError field of ImageContext.
1209  @retval RETURN_LOAD_ERROR         The PE/COFF image is an EFI Runtime image with no relocations.
1210                                    Extended status information is in the ImageError field of ImageContext.
1211  @retval RETURN_INVALID_PARAMETER  The image address is invalid.
1212                                    Extended status information is in the ImageError field of ImageContext.
1213
1214**/
1215RETURN_STATUS
1216EFIAPI
1217PeCoffLoaderLoadImage (
1218  IN OUT PE_COFF_LOADER_IMAGE_CONTEXT  *ImageContext
1219  )
1220{
1221  RETURN_STATUS                         Status;
1222  EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION   Hdr;
1223  PE_COFF_LOADER_IMAGE_CONTEXT          CheckContext;
1224  EFI_IMAGE_SECTION_HEADER              *FirstSection;
1225  EFI_IMAGE_SECTION_HEADER              *Section;
1226  UINTN                                 NumberOfSections;
1227  UINTN                                 Index;
1228  CHAR8                                 *Base;
1229  CHAR8                                 *End;
1230  EFI_IMAGE_DATA_DIRECTORY              *DirectoryEntry;
1231  EFI_IMAGE_DEBUG_DIRECTORY_ENTRY       *DebugEntry;
1232  UINTN                                 Size;
1233  UINT32                                TempDebugEntryRva;
1234  UINT32                                NumberOfRvaAndSizes;
1235  UINT16                                Magic;
1236  EFI_IMAGE_RESOURCE_DIRECTORY          *ResourceDirectory;
1237  EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY    *ResourceDirectoryEntry;
1238  EFI_IMAGE_RESOURCE_DIRECTORY_STRING   *ResourceDirectoryString;
1239  EFI_IMAGE_RESOURCE_DATA_ENTRY         *ResourceDataEntry;
1240  CHAR16                                *String;
1241  UINT32                                Offset;
1242  UINT32                                TeStrippedOffset;
1243
1244  ASSERT (ImageContext != NULL);
1245
1246  //
1247  // Assume success
1248  //
1249  ImageContext->ImageError = IMAGE_ERROR_SUCCESS;
1250
1251  //
1252  // Copy the provided context information into our local version, get what we
1253  // can from the original image, and then use that to make sure everything
1254  // is legit.
1255  //
1256  CopyMem (&CheckContext, ImageContext, sizeof (PE_COFF_LOADER_IMAGE_CONTEXT));
1257
1258  Status = PeCoffLoaderGetImageInfo (&CheckContext);
1259  if (RETURN_ERROR (Status)) {
1260    return Status;
1261  }
1262
1263  //
1264  // Make sure there is enough allocated space for the image being loaded
1265  //
1266  if (ImageContext->ImageSize < CheckContext.ImageSize) {
1267    ImageContext->ImageError = IMAGE_ERROR_INVALID_IMAGE_SIZE;
1268    return RETURN_BUFFER_TOO_SMALL;
1269  }
1270  if (ImageContext->ImageAddress == 0) {
1271    //
1272    // Image cannot be loaded into 0 address.
1273    //
1274    ImageContext->ImageError = IMAGE_ERROR_INVALID_IMAGE_ADDRESS;
1275    return RETURN_INVALID_PARAMETER;
1276  }
1277  //
1278  // If there's no relocations, then make sure it's not a runtime driver,
1279  // and that it's being loaded at the linked address.
1280  //
1281  if (CheckContext.RelocationsStripped) {
1282    //
1283    // If the image does not contain relocations and it is a runtime driver
1284    // then return an error.
1285    //
1286    if (CheckContext.ImageType == EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER) {
1287      ImageContext->ImageError = IMAGE_ERROR_INVALID_SUBSYSTEM;
1288      return RETURN_LOAD_ERROR;
1289    }
1290    //
1291    // If the image does not contain relocations, and the requested load address
1292    // is not the linked address, then return an error.
1293    //
1294    if (CheckContext.ImageAddress != ImageContext->ImageAddress) {
1295      ImageContext->ImageError = IMAGE_ERROR_INVALID_IMAGE_ADDRESS;
1296      return RETURN_INVALID_PARAMETER;
1297    }
1298  }
1299  //
1300  // Make sure the allocated space has the proper section alignment
1301  //
1302  if (!(ImageContext->IsTeImage)) {
1303    if ((ImageContext->ImageAddress & (CheckContext.SectionAlignment - 1)) != 0) {
1304      ImageContext->ImageError = IMAGE_ERROR_INVALID_SECTION_ALIGNMENT;
1305      return RETURN_INVALID_PARAMETER;
1306    }
1307  }
1308  //
1309  // Read the entire PE/COFF or TE header into memory
1310  //
1311  if (!(ImageContext->IsTeImage)) {
1312    Status = ImageContext->ImageRead (
1313                            ImageContext->Handle,
1314                            0,
1315                            &ImageContext->SizeOfHeaders,
1316                            (VOID *) (UINTN) ImageContext->ImageAddress
1317                            );
1318
1319    Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINTN)ImageContext->ImageAddress + ImageContext->PeCoffHeaderOffset);
1320
1321    FirstSection = (EFI_IMAGE_SECTION_HEADER *) (
1322                      (UINTN)ImageContext->ImageAddress +
1323                      ImageContext->PeCoffHeaderOffset +
1324                      sizeof(UINT32) +
1325                      sizeof(EFI_IMAGE_FILE_HEADER) +
1326                      Hdr.Pe32->FileHeader.SizeOfOptionalHeader
1327      );
1328    NumberOfSections = (UINTN) (Hdr.Pe32->FileHeader.NumberOfSections);
1329    TeStrippedOffset = 0;
1330  } else {
1331    Status = ImageContext->ImageRead (
1332                            ImageContext->Handle,
1333                            0,
1334                            &ImageContext->SizeOfHeaders,
1335                            (void *)(UINTN)ImageContext->ImageAddress
1336                            );
1337
1338    Hdr.Te = (EFI_TE_IMAGE_HEADER *)(UINTN)(ImageContext->ImageAddress);
1339    FirstSection = (EFI_IMAGE_SECTION_HEADER *) (
1340                      (UINTN)ImageContext->ImageAddress +
1341                      sizeof(EFI_TE_IMAGE_HEADER)
1342                      );
1343    NumberOfSections  = (UINTN) (Hdr.Te->NumberOfSections);
1344    TeStrippedOffset  = (UINT32) Hdr.Te->StrippedSize - sizeof (EFI_TE_IMAGE_HEADER);
1345  }
1346
1347  if (RETURN_ERROR (Status)) {
1348    ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;
1349    return RETURN_LOAD_ERROR;
1350  }
1351
1352  //
1353  // Load each section of the image
1354  //
1355  Section = FirstSection;
1356  for (Index = 0; Index < NumberOfSections; Index++) {
1357    //
1358    // Read the section
1359    //
1360    Size = (UINTN) Section->Misc.VirtualSize;
1361    if ((Size == 0) || (Size > Section->SizeOfRawData)) {
1362      Size = (UINTN) Section->SizeOfRawData;
1363    }
1364
1365    //
1366    // Compute sections address
1367    //
1368    Base = PeCoffLoaderImageAddress (ImageContext, Section->VirtualAddress, TeStrippedOffset);
1369    End  = PeCoffLoaderImageAddress (ImageContext, Section->VirtualAddress + Section->Misc.VirtualSize - 1, TeStrippedOffset);
1370
1371    //
1372    // If the size of the section is non-zero and the base address or end address resolved to 0, then fail.
1373    //
1374    if ((Size > 0) && ((Base == NULL) || (End == NULL))) {
1375      ImageContext->ImageError = IMAGE_ERROR_SECTION_NOT_LOADED;
1376      return RETURN_LOAD_ERROR;
1377    }
1378
1379    if (Section->SizeOfRawData > 0) {
1380      Status = ImageContext->ImageRead (
1381                              ImageContext->Handle,
1382                              Section->PointerToRawData - TeStrippedOffset,
1383                              &Size,
1384                              Base
1385                              );
1386      if (RETURN_ERROR (Status)) {
1387        ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;
1388        return Status;
1389      }
1390    }
1391
1392    //
1393    // If raw size is less then virtual size, zero fill the remaining
1394    //
1395
1396    if (Size < Section->Misc.VirtualSize) {
1397      ZeroMem (Base + Size, Section->Misc.VirtualSize - Size);
1398    }
1399
1400    //
1401    // Next Section
1402    //
1403    Section += 1;
1404  }
1405
1406  //
1407  // Get image's entry point
1408  //
1409  Magic = PeCoffLoaderGetPeHeaderMagicValue (Hdr);
1410  if (!(ImageContext->IsTeImage)) {
1411    //
1412    // Sizes of AddressOfEntryPoint are different so we need to do this safely
1413    //
1414    if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
1415      //
1416      // Use PE32 offset
1417      //
1418      ImageContext->EntryPoint = (PHYSICAL_ADDRESS)(UINTN)PeCoffLoaderImageAddress (
1419                                                            ImageContext,
1420                                                            (UINTN)Hdr.Pe32->OptionalHeader.AddressOfEntryPoint,
1421                                                            0
1422                                                            );
1423    } else {
1424      //
1425      // Use PE32+ offset
1426      //
1427      ImageContext->EntryPoint = (PHYSICAL_ADDRESS)(UINTN)PeCoffLoaderImageAddress (
1428                                                            ImageContext,
1429                                                            (UINTN)Hdr.Pe32Plus->OptionalHeader.AddressOfEntryPoint,
1430                                                            0
1431                                                            );
1432    }
1433  } else {
1434    ImageContext->EntryPoint = (PHYSICAL_ADDRESS)(UINTN)PeCoffLoaderImageAddress (
1435                                                          ImageContext,
1436                                                          (UINTN)Hdr.Te->AddressOfEntryPoint,
1437                                                          TeStrippedOffset
1438                                                          );
1439  }
1440
1441  //
1442  // Determine the size of the fixup data
1443  //
1444  // Per the PE/COFF spec, you can't assume that a given data directory
1445  // is present in the image. You have to check the NumberOfRvaAndSizes in
1446  // the optional header to verify a desired directory entry is there.
1447  //
1448  if (!(ImageContext->IsTeImage)) {
1449    if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
1450      //
1451      // Use PE32 offset
1452      //
1453      NumberOfRvaAndSizes = Hdr.Pe32->OptionalHeader.NumberOfRvaAndSizes;
1454      DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)&Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC];
1455    } else {
1456      //
1457      // Use PE32+ offset
1458      //
1459      NumberOfRvaAndSizes = Hdr.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes;
1460      DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)&Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC];
1461    }
1462
1463    //
1464    // Must use UINT64 here, because there might a case that 32bit loader to load 64bit image.
1465    //
1466    if (NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC) {
1467      ImageContext->FixupDataSize = DirectoryEntry->Size / sizeof (UINT16) * sizeof (UINT64);
1468    } else {
1469      ImageContext->FixupDataSize = 0;
1470    }
1471  } else {
1472    DirectoryEntry              = &Hdr.Te->DataDirectory[0];
1473    ImageContext->FixupDataSize = DirectoryEntry->Size / sizeof (UINT16) * sizeof (UINT64);
1474  }
1475  //
1476  // Consumer must allocate a buffer for the relocation fixup log.
1477  // Only used for runtime drivers.
1478  //
1479  ImageContext->FixupData = NULL;
1480
1481  //
1482  // Load the Codeview information if present
1483  //
1484  if (ImageContext->DebugDirectoryEntryRva != 0) {
1485    DebugEntry = PeCoffLoaderImageAddress (
1486                ImageContext,
1487                ImageContext->DebugDirectoryEntryRva,
1488                TeStrippedOffset
1489                );
1490    if (DebugEntry == NULL) {
1491      ImageContext->ImageError = IMAGE_ERROR_FAILED_RELOCATION;
1492      return RETURN_LOAD_ERROR;
1493    }
1494
1495    TempDebugEntryRva = DebugEntry->RVA;
1496    if (DebugEntry->RVA == 0 && DebugEntry->FileOffset != 0) {
1497      Section--;
1498      if ((UINTN)Section->SizeOfRawData < Section->Misc.VirtualSize) {
1499        TempDebugEntryRva = Section->VirtualAddress + Section->Misc.VirtualSize;
1500      } else {
1501        TempDebugEntryRva = Section->VirtualAddress + Section->SizeOfRawData;
1502      }
1503    }
1504
1505    if (TempDebugEntryRva != 0) {
1506      ImageContext->CodeView = PeCoffLoaderImageAddress (ImageContext, TempDebugEntryRva, TeStrippedOffset);
1507      if (ImageContext->CodeView == NULL) {
1508        ImageContext->ImageError = IMAGE_ERROR_FAILED_RELOCATION;
1509        return RETURN_LOAD_ERROR;
1510      }
1511
1512      if (DebugEntry->RVA == 0) {
1513        Size = DebugEntry->SizeOfData;
1514        Status = ImageContext->ImageRead (
1515                                ImageContext->Handle,
1516                                DebugEntry->FileOffset - TeStrippedOffset,
1517                                &Size,
1518                                ImageContext->CodeView
1519                                );
1520        //
1521        // Should we apply fix up to this field according to the size difference between PE and TE?
1522        // Because now we maintain TE header fields unfixed, this field will also remain as they are
1523        // in original PE image.
1524        //
1525
1526        if (RETURN_ERROR (Status)) {
1527          ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;
1528          return RETURN_LOAD_ERROR;
1529        }
1530
1531        DebugEntry->RVA = TempDebugEntryRva;
1532      }
1533
1534      switch (*(UINT32 *) ImageContext->CodeView) {
1535      case CODEVIEW_SIGNATURE_NB10:
1536        if (DebugEntry->SizeOfData < sizeof (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY)) {
1537          ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;
1538          return RETURN_UNSUPPORTED;
1539        }
1540        ImageContext->PdbPointer = (CHAR8 *)ImageContext->CodeView + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY);
1541        break;
1542
1543      case CODEVIEW_SIGNATURE_RSDS:
1544        if (DebugEntry->SizeOfData < sizeof (EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY)) {
1545          ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;
1546          return RETURN_UNSUPPORTED;
1547        }
1548        ImageContext->PdbPointer = (CHAR8 *)ImageContext->CodeView + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY);
1549        break;
1550
1551      case CODEVIEW_SIGNATURE_MTOC:
1552        if (DebugEntry->SizeOfData < sizeof (EFI_IMAGE_DEBUG_CODEVIEW_MTOC_ENTRY)) {
1553          ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;
1554          return RETURN_UNSUPPORTED;
1555        }
1556        ImageContext->PdbPointer = (CHAR8 *)ImageContext->CodeView + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_MTOC_ENTRY);
1557        break;
1558
1559      default:
1560        break;
1561      }
1562    }
1563  }
1564
1565  //
1566  // Get Image's HII resource section
1567  //
1568  ImageContext->HiiResourceData = 0;
1569  if (!(ImageContext->IsTeImage)) {
1570    if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
1571      //
1572      // Use PE32 offset
1573      //
1574      NumberOfRvaAndSizes = Hdr.Pe32->OptionalHeader.NumberOfRvaAndSizes;
1575      DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)&Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE];
1576    } else {
1577      //
1578      // Use PE32+ offset
1579      //
1580      NumberOfRvaAndSizes = Hdr.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes;
1581      DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)&Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE];
1582    }
1583
1584    if (NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE && DirectoryEntry->Size != 0) {
1585      Base = PeCoffLoaderImageAddress (ImageContext, DirectoryEntry->VirtualAddress, 0);
1586      if (Base != NULL) {
1587        ResourceDirectory = (EFI_IMAGE_RESOURCE_DIRECTORY *) Base;
1588        Offset = sizeof (EFI_IMAGE_RESOURCE_DIRECTORY) + sizeof (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY) *
1589               (ResourceDirectory->NumberOfNamedEntries + ResourceDirectory->NumberOfIdEntries);
1590        if (Offset > DirectoryEntry->Size) {
1591          ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;
1592          return RETURN_UNSUPPORTED;
1593        }
1594        ResourceDirectoryEntry = (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY *) (ResourceDirectory + 1);
1595
1596        for (Index = 0; Index < ResourceDirectory->NumberOfNamedEntries; Index++) {
1597          if (ResourceDirectoryEntry->u1.s.NameIsString) {
1598            //
1599            // Check the ResourceDirectoryEntry->u1.s.NameOffset before use it.
1600            //
1601            if (ResourceDirectoryEntry->u1.s.NameOffset >= DirectoryEntry->Size) {
1602              ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;
1603              return RETURN_UNSUPPORTED;
1604            }
1605            ResourceDirectoryString = (EFI_IMAGE_RESOURCE_DIRECTORY_STRING *) (Base + ResourceDirectoryEntry->u1.s.NameOffset);
1606            String = &ResourceDirectoryString->String[0];
1607
1608            if (ResourceDirectoryString->Length == 3 &&
1609                String[0] == L'H' &&
1610                String[1] == L'I' &&
1611                String[2] == L'I') {
1612              //
1613              // Resource Type "HII" found
1614              //
1615              if (ResourceDirectoryEntry->u2.s.DataIsDirectory) {
1616                //
1617                // Move to next level - resource Name
1618                //
1619                if (ResourceDirectoryEntry->u2.s.OffsetToDirectory >= DirectoryEntry->Size) {
1620                  ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;
1621                  return RETURN_UNSUPPORTED;
1622                }
1623                ResourceDirectory = (EFI_IMAGE_RESOURCE_DIRECTORY *) (Base + ResourceDirectoryEntry->u2.s.OffsetToDirectory);
1624                Offset = ResourceDirectoryEntry->u2.s.OffsetToDirectory + sizeof (EFI_IMAGE_RESOURCE_DIRECTORY) +
1625                         sizeof (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY) * (ResourceDirectory->NumberOfNamedEntries + ResourceDirectory->NumberOfIdEntries);
1626                if (Offset > DirectoryEntry->Size) {
1627                  ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;
1628                  return RETURN_UNSUPPORTED;
1629                }
1630                ResourceDirectoryEntry = (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY *) (ResourceDirectory + 1);
1631
1632                if (ResourceDirectoryEntry->u2.s.DataIsDirectory) {
1633                  //
1634                  // Move to next level - resource Language
1635                  //
1636                  if (ResourceDirectoryEntry->u2.s.OffsetToDirectory >= DirectoryEntry->Size) {
1637                    ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;
1638                    return RETURN_UNSUPPORTED;
1639                  }
1640                  ResourceDirectory = (EFI_IMAGE_RESOURCE_DIRECTORY *) (Base + ResourceDirectoryEntry->u2.s.OffsetToDirectory);
1641                  Offset = ResourceDirectoryEntry->u2.s.OffsetToDirectory + sizeof (EFI_IMAGE_RESOURCE_DIRECTORY) +
1642                           sizeof (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY) * (ResourceDirectory->NumberOfNamedEntries + ResourceDirectory->NumberOfIdEntries);
1643                  if (Offset > DirectoryEntry->Size) {
1644                    ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;
1645                    return RETURN_UNSUPPORTED;
1646                  }
1647                  ResourceDirectoryEntry = (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY *) (ResourceDirectory + 1);
1648                }
1649              }
1650
1651              //
1652              // Now it ought to be resource Data
1653              //
1654              if (!ResourceDirectoryEntry->u2.s.DataIsDirectory) {
1655                if (ResourceDirectoryEntry->u2.OffsetToData >= DirectoryEntry->Size) {
1656                  ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;
1657                  return RETURN_UNSUPPORTED;
1658                }
1659                ResourceDataEntry = (EFI_IMAGE_RESOURCE_DATA_ENTRY *) (Base + ResourceDirectoryEntry->u2.OffsetToData);
1660                ImageContext->HiiResourceData = (PHYSICAL_ADDRESS) (UINTN) PeCoffLoaderImageAddress (ImageContext, ResourceDataEntry->OffsetToData, 0);
1661                break;
1662              }
1663            }
1664          }
1665          ResourceDirectoryEntry++;
1666        }
1667      }
1668    }
1669  }
1670
1671  return Status;
1672}
1673
1674
1675/**
1676  Reapply fixups on a fixed up PE32/PE32+ image to allow virutal calling at EFI
1677  runtime.
1678
1679  This function reapplies relocation fixups to the PE/COFF image specified by ImageBase
1680  and ImageSize so the image will execute correctly when the PE/COFF image is mapped
1681  to the address specified by VirtualImageBase.  RelocationData must be identical
1682  to the FiuxupData buffer from the PE_COFF_LOADER_IMAGE_CONTEXT structure
1683  after this PE/COFF image was relocated with PeCoffLoaderRelocateImage().
1684
1685  Note that if the platform does not maintain coherency between the instruction cache(s) and the data
1686  cache(s) in hardware, then the caller is responsible for performing cache maintenance operations
1687  prior to transferring control to a PE/COFF image that is loaded using this library.
1688
1689  @param  ImageBase          The base address of a PE/COFF image that has been loaded
1690                             and relocated into system memory.
1691  @param  VirtImageBase      The request virtual address that the PE/COFF image is to
1692                             be fixed up for.
1693  @param  ImageSize          The size, in bytes, of the PE/COFF image.
1694  @param  RelocationData     A pointer to the relocation data that was collected when the PE/COFF
1695                             image was relocated using PeCoffLoaderRelocateImage().
1696
1697**/
1698VOID
1699EFIAPI
1700PeCoffLoaderRelocateImageForRuntime (
1701  IN  PHYSICAL_ADDRESS        ImageBase,
1702  IN  PHYSICAL_ADDRESS        VirtImageBase,
1703  IN  UINTN                   ImageSize,
1704  IN  VOID                    *RelocationData
1705  )
1706{
1707  CHAR8                               *OldBase;
1708  CHAR8                               *NewBase;
1709  EFI_IMAGE_DOS_HEADER                *DosHdr;
1710  EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;
1711  UINT32                              NumberOfRvaAndSizes;
1712  EFI_IMAGE_DATA_DIRECTORY            *DataDirectory;
1713  EFI_IMAGE_DATA_DIRECTORY            *RelocDir;
1714  EFI_IMAGE_BASE_RELOCATION           *RelocBase;
1715  EFI_IMAGE_BASE_RELOCATION           *RelocBaseEnd;
1716  UINT16                              *Reloc;
1717  UINT16                              *RelocEnd;
1718  CHAR8                               *Fixup;
1719  CHAR8                               *FixupBase;
1720  UINT16                              *Fixup16;
1721  UINT32                              *Fixup32;
1722  UINT64                              *Fixup64;
1723  CHAR8                               *FixupData;
1724  UINTN                               Adjust;
1725  RETURN_STATUS                       Status;
1726  UINT16                              Magic;
1727
1728  OldBase = (CHAR8 *)((UINTN)ImageBase);
1729  NewBase = (CHAR8 *)((UINTN)VirtImageBase);
1730  Adjust = (UINTN) NewBase - (UINTN) OldBase;
1731
1732  //
1733  // Find the image's relocate dir info
1734  //
1735  DosHdr = (EFI_IMAGE_DOS_HEADER *)OldBase;
1736  if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) {
1737    //
1738    // Valid DOS header so get address of PE header
1739    //
1740    Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)(((CHAR8 *)DosHdr) + DosHdr->e_lfanew);
1741  } else {
1742    //
1743    // No Dos header so assume image starts with PE header.
1744    //
1745    Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)OldBase;
1746  }
1747
1748  if (Hdr.Pe32->Signature != EFI_IMAGE_NT_SIGNATURE) {
1749    //
1750    // Not a valid PE image so Exit
1751    //
1752    return ;
1753  }
1754
1755  Magic = PeCoffLoaderGetPeHeaderMagicValue (Hdr);
1756
1757  if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
1758    //
1759    // Use PE32 offset
1760    //
1761    NumberOfRvaAndSizes = Hdr.Pe32->OptionalHeader.NumberOfRvaAndSizes;
1762    DataDirectory = (EFI_IMAGE_DATA_DIRECTORY *)&(Hdr.Pe32->OptionalHeader.DataDirectory[0]);
1763  } else {
1764    //
1765    // Use PE32+ offset
1766    //
1767    NumberOfRvaAndSizes = Hdr.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes;
1768    DataDirectory = (EFI_IMAGE_DATA_DIRECTORY *)&(Hdr.Pe32Plus->OptionalHeader.DataDirectory[0]);
1769  }
1770
1771  //
1772  // Find the relocation block
1773  //
1774  // Per the PE/COFF spec, you can't assume that a given data directory
1775  // is present in the image. You have to check the NumberOfRvaAndSizes in
1776  // the optional header to verify a desired directory entry is there.
1777  //
1778  if (NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC) {
1779    RelocDir      = DataDirectory + EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC;
1780    RelocBase     = (EFI_IMAGE_BASE_RELOCATION *)(UINTN)(ImageBase + RelocDir->VirtualAddress);
1781    RelocBaseEnd  = (EFI_IMAGE_BASE_RELOCATION *)(UINTN)(ImageBase + RelocDir->VirtualAddress + RelocDir->Size);
1782  } else {
1783    //
1784    // Cannot find relocations, cannot continue to relocate the image, ASSERT for this invalid image.
1785    //
1786    ASSERT (FALSE);
1787    return ;
1788  }
1789
1790  //
1791  // ASSERT for the invalid image when RelocBase and RelocBaseEnd are both NULL.
1792  //
1793  ASSERT (RelocBase != NULL && RelocBaseEnd != NULL);
1794
1795  //
1796  // Run the whole relocation block. And re-fixup data that has not been
1797  // modified. The FixupData is used to see if the image has been modified
1798  // since it was relocated. This is so data sections that have been updated
1799  // by code will not be fixed up, since that would set them back to
1800  // defaults.
1801  //
1802  FixupData = RelocationData;
1803  while (RelocBase < RelocBaseEnd) {
1804    //
1805    // Add check for RelocBase->SizeOfBlock field.
1806    //
1807    if ((RelocBase->SizeOfBlock == 0) || (RelocBase->SizeOfBlock > RelocDir->Size)) {
1808      //
1809      // Data invalid, cannot continue to relocate the image, just return.
1810      //
1811      return;
1812    }
1813
1814    Reloc     = (UINT16 *) ((UINT8 *) RelocBase + sizeof (EFI_IMAGE_BASE_RELOCATION));
1815    RelocEnd  = (UINT16 *) ((UINT8 *) RelocBase + RelocBase->SizeOfBlock);
1816    FixupBase = (CHAR8 *) ((UINTN)ImageBase) + RelocBase->VirtualAddress;
1817
1818    //
1819    // Run this relocation record
1820    //
1821    while (Reloc < RelocEnd) {
1822
1823      Fixup = FixupBase + (*Reloc & 0xFFF);
1824      switch ((*Reloc) >> 12) {
1825
1826      case EFI_IMAGE_REL_BASED_ABSOLUTE:
1827        break;
1828
1829      case EFI_IMAGE_REL_BASED_HIGH:
1830        Fixup16 = (UINT16 *) Fixup;
1831        if (*(UINT16 *) FixupData == *Fixup16) {
1832          *Fixup16 = (UINT16) (*Fixup16 + ((UINT16) ((UINT32) Adjust >> 16)));
1833        }
1834
1835        FixupData = FixupData + sizeof (UINT16);
1836        break;
1837
1838      case EFI_IMAGE_REL_BASED_LOW:
1839        Fixup16 = (UINT16 *) Fixup;
1840        if (*(UINT16 *) FixupData == *Fixup16) {
1841          *Fixup16 = (UINT16) (*Fixup16 + ((UINT16) Adjust & 0xffff));
1842        }
1843
1844        FixupData = FixupData + sizeof (UINT16);
1845        break;
1846
1847      case EFI_IMAGE_REL_BASED_HIGHLOW:
1848        Fixup32       = (UINT32 *) Fixup;
1849        FixupData = ALIGN_POINTER (FixupData, sizeof (UINT32));
1850        if (*(UINT32 *) FixupData == *Fixup32) {
1851          *Fixup32 = *Fixup32 + (UINT32) Adjust;
1852        }
1853
1854        FixupData = FixupData + sizeof (UINT32);
1855        break;
1856
1857      case EFI_IMAGE_REL_BASED_DIR64:
1858        Fixup64       = (UINT64 *)Fixup;
1859        FixupData = ALIGN_POINTER (FixupData, sizeof (UINT64));
1860        if (*(UINT64 *) FixupData == *Fixup64) {
1861          *Fixup64 = *Fixup64 + (UINT64)Adjust;
1862        }
1863
1864        FixupData = FixupData + sizeof (UINT64);
1865        break;
1866
1867      default:
1868        //
1869        // Only Itanium requires ConvertPeImage_Ex
1870        //
1871        Status = PeHotRelocateImageEx (Reloc, Fixup, &FixupData, Adjust);
1872        if (RETURN_ERROR (Status)) {
1873          return ;
1874        }
1875      }
1876      //
1877      // Next relocation record
1878      //
1879      Reloc += 1;
1880    }
1881    //
1882    // next reloc block
1883    //
1884    RelocBase = (EFI_IMAGE_BASE_RELOCATION *) RelocEnd;
1885  }
1886}
1887
1888
1889/**
1890  Reads contents of a PE/COFF image from a buffer in system memory.
1891
1892  This is the default implementation of a PE_COFF_LOADER_READ_FILE function
1893  that assumes FileHandle pointer to the beginning of a PE/COFF image.
1894  This function reads contents of the PE/COFF image that starts at the system memory
1895  address specified by FileHandle.  The read operation copies ReadSize bytes from the
1896  PE/COFF image starting at byte offset FileOffset into the buffer specified by Buffer.
1897  The size of the buffer actually read is returned in ReadSize.
1898
1899  The caller must make sure the FileOffset and ReadSize within the file scope.
1900
1901  If FileHandle is NULL, then ASSERT().
1902  If ReadSize is NULL, then ASSERT().
1903  If Buffer is NULL, then ASSERT().
1904
1905  @param  FileHandle        The pointer to base of the input stream
1906  @param  FileOffset        Offset into the PE/COFF image to begin the read operation.
1907  @param  ReadSize          On input, the size in bytes of the requested read operation.
1908                            On output, the number of bytes actually read.
1909  @param  Buffer            Output buffer that contains the data read from the PE/COFF image.
1910
1911  @retval RETURN_SUCCESS    Data is read from FileOffset from the Handle into
1912                            the buffer.
1913**/
1914RETURN_STATUS
1915EFIAPI
1916PeCoffLoaderImageReadFromMemory (
1917  IN     VOID    *FileHandle,
1918  IN     UINTN   FileOffset,
1919  IN OUT UINTN   *ReadSize,
1920  OUT    VOID    *Buffer
1921  )
1922{
1923  ASSERT (ReadSize != NULL);
1924  ASSERT (FileHandle != NULL);
1925  ASSERT (Buffer != NULL);
1926
1927  CopyMem (Buffer, ((UINT8 *)FileHandle) + FileOffset, *ReadSize);
1928  return RETURN_SUCCESS;
1929}
1930
1931/**
1932  Unloads a loaded PE/COFF image from memory and releases its taken resource.
1933  Releases any environment specific resources that were allocated when the image
1934  specified by ImageContext was loaded using PeCoffLoaderLoadImage().
1935
1936  For NT32 emulator, the PE/COFF image loaded by system needs to release.
1937  For real platform, the PE/COFF image loaded by Core doesn't needs to be unloaded,
1938  this function can simply return RETURN_SUCCESS.
1939
1940  If ImageContext is NULL, then ASSERT().
1941
1942  @param  ImageContext              The pointer to the image context structure that describes the PE/COFF
1943                                    image to be unloaded.
1944
1945  @retval RETURN_SUCCESS            The PE/COFF image was unloaded successfully.
1946**/
1947RETURN_STATUS
1948EFIAPI
1949PeCoffLoaderUnloadImage (
1950  IN OUT PE_COFF_LOADER_IMAGE_CONTEXT  *ImageContext
1951  )
1952{
1953  //
1954  // Applies additional environment specific actions to unload a
1955  // PE/COFF image if needed
1956  //
1957  PeCoffLoaderUnloadImageExtraAction (ImageContext);
1958  return RETURN_SUCCESS;
1959}
1960