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