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