Update GenFw and GenFv tool to support more features based on base tools spec.
[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   DebugDirectoryEntry    = NULL;\r
266   DebugDirectoryEntryRva = 0;\r
267 \r
268   if (NULL == ImageContext) {\r
269     return RETURN_INVALID_PARAMETER;\r
270   }\r
271   //\r
272   // Assume success\r
273   //\r
274   ImageContext->ImageError  = IMAGE_ERROR_SUCCESS;\r
275 \r
276   Status                    = PeCoffLoaderGetPeHeader (ImageContext, &PeHdr, &TeHdr);\r
277   if (RETURN_ERROR (Status)) {\r
278     return Status;\r
279   }\r
280 \r
281   //\r
282   // Verify machine type\r
283   //\r
284   Status = PeCoffLoaderCheckImageType (ImageContext, PeHdr, TeHdr);\r
285   if (RETURN_ERROR (Status)) {\r
286     return Status;\r
287   }\r
288   OptionHeader.Header = (VOID *) &(PeHdr->OptionalHeader);\r
289 \r
290   //\r
291   // Retrieve the base address of the image\r
292   //\r
293   if (!(ImageContext->IsTeImage)) {\r
294     if (ImageContext->Machine == EFI_IMAGE_MACHINE_IA32) {\r
295       ImageContext->ImageAddress = (PHYSICAL_ADDRESS) OptionHeader.Optional32->ImageBase;\r
296     } else {\r
297       ImageContext->ImageAddress = (PHYSICAL_ADDRESS) OptionHeader.Optional64->ImageBase;\r
298     }\r
299   } else {\r
300     ImageContext->ImageAddress = (PHYSICAL_ADDRESS) (TeHdr->ImageBase + TeHdr->StrippedSize - sizeof (EFI_TE_IMAGE_HEADER));\r
301   }\r
302   //\r
303   // Initialize the alternate destination address to 0 indicating that it\r
304   // should not be used.\r
305   //\r
306   ImageContext->DestinationAddress = 0;\r
307 \r
308   //\r
309   // Initialize the codeview pointer.\r
310   //\r
311   ImageContext->CodeView    = NULL;\r
312   ImageContext->PdbPointer  = NULL;\r
313 \r
314   //\r
315   // Three cases with regards to relocations:\r
316   // - Image has base relocs, RELOCS_STRIPPED==0    => image is relocatable\r
317   // - Image has no base relocs, RELOCS_STRIPPED==1 => Image is not relocatable\r
318   // - Image has no base relocs, RELOCS_STRIPPED==0 => Image is relocatable but\r
319   //   has no base relocs to apply\r
320   // Obviously having base relocations with RELOCS_STRIPPED==1 is invalid.\r
321   //\r
322   // Look at the file header to determine if relocations have been stripped, and\r
323   // save this info in the image context for later use.\r
324   //\r
325   if ((!(ImageContext->IsTeImage)) && ((PeHdr->FileHeader.Characteristics & EFI_IMAGE_FILE_RELOCS_STRIPPED) != 0)) {\r
326     ImageContext->RelocationsStripped = TRUE;\r
327   } else {\r
328     ImageContext->RelocationsStripped = FALSE;\r
329   }\r
330 \r
331   if (!(ImageContext->IsTeImage)) {\r
332 \r
333     if (ImageContext->Machine == EFI_IMAGE_MACHINE_IA32) {\r
334       ImageContext->ImageSize         = (UINT64) OptionHeader.Optional32->SizeOfImage;\r
335       ImageContext->SectionAlignment  = OptionHeader.Optional32->SectionAlignment;\r
336       ImageContext->SizeOfHeaders     = OptionHeader.Optional32->SizeOfHeaders;\r
337   \r
338       //\r
339       // Modify ImageSize to contain .PDB file name if required and initialize\r
340       // PdbRVA field...\r
341       //\r
342       if (OptionHeader.Optional32->NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_DEBUG) {\r
343         DebugDirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *) &(OptionHeader.Optional32->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG]);\r
344         DebugDirectoryEntryRva = DebugDirectoryEntry->VirtualAddress;\r
345       }\r
346     } else {\r
347       ImageContext->ImageSize         = (UINT64) OptionHeader.Optional64->SizeOfImage;\r
348       ImageContext->SectionAlignment  = OptionHeader.Optional64->SectionAlignment;\r
349       ImageContext->SizeOfHeaders     = OptionHeader.Optional64->SizeOfHeaders;\r
350   \r
351       //\r
352       // Modify ImageSize to contain .PDB file name if required and initialize\r
353       // PdbRVA field...\r
354       //\r
355       if (OptionHeader.Optional64->NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_DEBUG) {\r
356         DebugDirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *) &(OptionHeader.Optional64->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG]);\r
357         DebugDirectoryEntryRva = DebugDirectoryEntry->VirtualAddress;\r
358       }\r
359     }\r
360     \r
361     if (DebugDirectoryEntryRva != 0) {\r
362       //\r
363       // Determine the file offset of the debug directory...  This means we walk\r
364       // the sections to find which section contains the RVA of the debug\r
365       // directory\r
366       //\r
367       DebugDirectoryEntryFileOffset = 0;\r
368 \r
369       SectionHeaderOffset = (UINTN)(\r
370                                ImageContext->PeCoffHeaderOffset +\r
371                                sizeof (UINT32) + \r
372                                sizeof (EFI_IMAGE_FILE_HEADER) + \r
373                                PeHdr->FileHeader.SizeOfOptionalHeader\r
374                                );\r
375 \r
376       for (Index = 0; Index < PeHdr->FileHeader.NumberOfSections; Index++) {\r
377         //\r
378         // Read section header from file\r
379         //\r
380         Size = sizeof (EFI_IMAGE_SECTION_HEADER);\r
381         Status = ImageContext->ImageRead (\r
382                                  ImageContext->Handle,\r
383                                  SectionHeaderOffset,\r
384                                  &Size,\r
385                                  &SectionHeader\r
386                                  );\r
387         if (RETURN_ERROR (Status)) {\r
388           ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;\r
389           return Status;\r
390         }\r
391 \r
392         if (DebugDirectoryEntryRva >= SectionHeader.VirtualAddress &&\r
393             DebugDirectoryEntryRva < SectionHeader.VirtualAddress + SectionHeader.Misc.VirtualSize) {\r
394             DebugDirectoryEntryFileOffset =\r
395             DebugDirectoryEntryRva - SectionHeader.VirtualAddress + SectionHeader.PointerToRawData;\r
396           break;\r
397         }\r
398 \r
399         SectionHeaderOffset += sizeof (EFI_IMAGE_SECTION_HEADER);\r
400       }\r
401 \r
402       if (DebugDirectoryEntryFileOffset != 0) {    \r
403         for (Index = 0; Index < DebugDirectoryEntry->Size; Index += sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY)) {\r
404           //\r
405           // Read next debug directory entry\r
406           //\r
407           Size = sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY);    \r
408           Status = ImageContext->ImageRead (\r
409                                    ImageContext->Handle,\r
410                                    DebugDirectoryEntryFileOffset + Index,\r
411                                    &Size,\r
412                                    &DebugEntry\r
413                                    );\r
414           if (RETURN_ERROR (Status)) {\r
415             ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;\r
416             return Status;\r
417           }\r
418 \r
419           if (DebugEntry.Type == EFI_IMAGE_DEBUG_TYPE_CODEVIEW) {\r
420             ImageContext->DebugDirectoryEntryRva = (UINT32) (DebugDirectoryEntryRva + Index);\r
421             if (DebugEntry.RVA == 0 && DebugEntry.FileOffset != 0) {\r
422               ImageContext->ImageSize += DebugEntry.SizeOfData;\r
423             }\r
424 \r
425             return RETURN_SUCCESS;\r
426           }\r
427         }\r
428       }\r
429     }\r
430   } else {\r
431     ImageContext->ImageSize         = 0;\r
432     ImageContext->SectionAlignment  = 4096;\r
433     ImageContext->SizeOfHeaders     = sizeof (EFI_TE_IMAGE_HEADER) + (UINTN) TeHdr->BaseOfCode - (UINTN) TeHdr->StrippedSize;\r
434 \r
435     DebugDirectoryEntry             = &TeHdr->DataDirectory[1];\r
436     DebugDirectoryEntryRva          = DebugDirectoryEntry->VirtualAddress;\r
437     SectionHeaderOffset             = (UINTN) (sizeof (EFI_TE_IMAGE_HEADER));\r
438 \r
439     DebugDirectoryEntryFileOffset   = 0;\r
440 \r
441     for (Index = 0; Index < TeHdr->NumberOfSections;) {\r
442       //\r
443       // Read section header from file\r
444       //\r
445       Size = sizeof (EFI_IMAGE_SECTION_HEADER);\r
446       Status = ImageContext->ImageRead (\r
447                                ImageContext->Handle,\r
448                                SectionHeaderOffset,\r
449                                &Size,\r
450                                &SectionHeader\r
451                                );\r
452       if (RETURN_ERROR (Status)) {\r
453         ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;\r
454         return Status;\r
455       }\r
456 \r
457       if (DebugDirectoryEntryRva >= SectionHeader.VirtualAddress &&\r
458           DebugDirectoryEntryRva < SectionHeader.VirtualAddress + SectionHeader.Misc.VirtualSize) {\r
459         DebugDirectoryEntryFileOffset = DebugDirectoryEntryRva -\r
460           SectionHeader.VirtualAddress +\r
461           SectionHeader.PointerToRawData +\r
462           sizeof (EFI_TE_IMAGE_HEADER) -\r
463           TeHdr->StrippedSize;\r
464 \r
465         //\r
466         // File offset of the debug directory was found, if this is not the last\r
467         // section, then skip to the last section for calculating the image size.\r
468         //\r
469         if (Index < (UINTN) TeHdr->NumberOfSections - 1) {\r
470           SectionHeaderOffset += (TeHdr->NumberOfSections - 1 - Index) * sizeof (EFI_IMAGE_SECTION_HEADER);\r
471           Index = TeHdr->NumberOfSections - 1;\r
472           continue;\r
473         }\r
474       }\r
475 \r
476       //\r
477       // In Te image header there is not a field to describe the ImageSize.\r
478       // Actually, the ImageSize equals the RVA plus the VirtualSize of \r
479       // the last section mapped into memory (Must be rounded up to \r
480       // a mulitple of Section Alignment). Per the PE/COFF specification, the\r
481       // section headers in the Section Table must appear in order of the RVA\r
482       // values for the corresponding sections. So the ImageSize can be determined\r
483       // by the RVA and the VirtualSize of the last section header in the\r
484       // Section Table.\r
485       //\r
486       if ((++Index) == (UINTN) TeHdr->NumberOfSections) {\r
487         ImageContext->ImageSize = (SectionHeader.VirtualAddress + SectionHeader.Misc.VirtualSize +\r
488                                    ImageContext->SectionAlignment - 1) & ~(ImageContext->SectionAlignment - 1);\r
489       }\r
490 \r
491       SectionHeaderOffset += sizeof (EFI_IMAGE_SECTION_HEADER);\r
492     }\r
493 \r
494     if (DebugDirectoryEntryFileOffset != 0) {\r
495       for (Index = 0; Index < DebugDirectoryEntry->Size; Index += sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY)) {\r
496         //\r
497         // Read next debug directory entry\r
498         //\r
499         Size = sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY);\r
500         Status = ImageContext->ImageRead (\r
501                                  ImageContext->Handle,\r
502                                  DebugDirectoryEntryFileOffset,\r
503                                  &Size,\r
504                                  &DebugEntry\r
505                                  );\r
506         if (RETURN_ERROR (Status)) {\r
507           ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;\r
508           return Status;\r
509         }\r
510 \r
511         if (DebugEntry.Type == EFI_IMAGE_DEBUG_TYPE_CODEVIEW) {\r
512           ImageContext->DebugDirectoryEntryRva = (UINT32) (DebugDirectoryEntryRva + Index);\r
513           return RETURN_SUCCESS;\r
514         }\r
515       }\r
516     }\r
517   }\r
518 \r
519   return RETURN_SUCCESS;\r
520 }\r
521 \r
522 STATIC\r
523 VOID *\r
524 PeCoffLoaderImageAddress (\r
525   IN OUT PE_COFF_LOADER_IMAGE_CONTEXT          *ImageContext,\r
526   IN     UINTN                                 Address\r
527   )\r
528 /*++\r
529 \r
530 Routine Description:\r
531 \r
532   Converts an image address to the loaded address\r
533 \r
534 Arguments:\r
535 \r
536   ImageContext  - The context of the image being loaded\r
537 \r
538   Address       - The address to be converted to the loaded address\r
539 \r
540 Returns:\r
541 \r
542   NULL if the address can not be converted, otherwise, the converted address\r
543 \r
544 --*/\r
545 {\r
546   if (Address >= ImageContext->ImageSize) {\r
547     ImageContext->ImageError = IMAGE_ERROR_INVALID_IMAGE_ADDRESS;\r
548     return NULL;\r
549   }\r
550 \r
551   return (UINT8 *) ((UINTN) ImageContext->ImageAddress + Address);\r
552 }\r
553 \r
554 RETURN_STATUS\r
555 EFIAPI\r
556 PeCoffLoaderRelocateImage (\r
557   IN OUT PE_COFF_LOADER_IMAGE_CONTEXT  *ImageContext\r
558   )\r
559 /*++\r
560 \r
561 Routine Description:\r
562 \r
563   Relocates a PE/COFF image in memory\r
564 \r
565 Arguments:\r
566 \r
567   This         - Calling context\r
568 \r
569   ImageContext - Contains information on the loaded image to relocate\r
570 \r
571 Returns:\r
572 \r
573   RETURN_SUCCESS      if the PE/COFF image was relocated\r
574   RETURN_LOAD_ERROR   if the image is not a valid PE/COFF image\r
575   RETURN_UNSUPPORTED  not support\r
576 \r
577 --*/\r
578 {\r
579   RETURN_STATUS             Status;\r
580   EFI_IMAGE_NT_HEADERS      *PeHdr;\r
581   EFI_TE_IMAGE_HEADER       *TeHdr;\r
582   EFI_IMAGE_DATA_DIRECTORY  *RelocDir;\r
583   UINT64                     Adjust;\r
584   EFI_IMAGE_BASE_RELOCATION *RelocBase;\r
585   EFI_IMAGE_BASE_RELOCATION *RelocBaseEnd;\r
586   UINT16                    *Reloc;\r
587   UINT16                    *RelocEnd;\r
588   CHAR8                     *Fixup;\r
589   CHAR8                     *FixupBase;\r
590   UINT16                    *F16;\r
591   UINT32                    *F32;\r
592   CHAR8                     *FixupData;\r
593   PHYSICAL_ADDRESS          BaseAddress;\r
594   UINT16                    MachineType;\r
595   EFI_IMAGE_OPTIONAL_HEADER_POINTER     OptionHeader;\r
596 \r
597   PeHdr = NULL;\r
598   TeHdr = NULL;\r
599   //\r
600   // Assume success\r
601   //\r
602   ImageContext->ImageError = IMAGE_ERROR_SUCCESS;\r
603 \r
604   //\r
605   // If there are no relocation entries, then we are done\r
606   //\r
607   if (ImageContext->RelocationsStripped) {\r
608     return RETURN_SUCCESS;\r
609   }\r
610 \r
611   //\r
612   // If the destination address is not 0, use that rather than the\r
613   // image address as the relocation target.\r
614   //\r
615   if (ImageContext->DestinationAddress) {\r
616     BaseAddress = ImageContext->DestinationAddress;\r
617   } else {\r
618     BaseAddress = ImageContext->ImageAddress;\r
619   }\r
620 \r
621   if (!(ImageContext->IsTeImage)) {\r
622     PeHdr = (EFI_IMAGE_NT_HEADERS *)((UINTN)ImageContext->ImageAddress + \r
623                                             ImageContext->PeCoffHeaderOffset);\r
624     OptionHeader.Header = (VOID *) &(PeHdr->OptionalHeader);\r
625     if (ImageContext->Machine == EFI_IMAGE_MACHINE_IA32) {\r
626       Adjust = (UINT64) BaseAddress - OptionHeader.Optional32->ImageBase;\r
627       OptionHeader.Optional32->ImageBase = (UINT32) BaseAddress;\r
628       MachineType = ImageContext->Machine;\r
629       //\r
630       // Find the relocation block\r
631       //\r
632       // Per the PE/COFF spec, you can't assume that a given data directory\r
633       // is present in the image. You have to check the NumberOfRvaAndSizes in\r
634       // the optional header to verify a desired directory entry is there.\r
635       //\r
636       if (OptionHeader.Optional32->NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC) {\r
637         RelocDir  = &OptionHeader.Optional32->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC];\r
638         RelocBase = PeCoffLoaderImageAddress (ImageContext, RelocDir->VirtualAddress);\r
639         RelocBaseEnd = PeCoffLoaderImageAddress (\r
640                         ImageContext,\r
641                         RelocDir->VirtualAddress + RelocDir->Size - 1\r
642                         );\r
643       } else {\r
644         //\r
645         // Set base and end to bypass processing below.\r
646         //\r
647         RelocBase = RelocBaseEnd = 0;\r
648       }\r
649     } else {\r
650       Adjust = (UINT64) BaseAddress - OptionHeader.Optional64->ImageBase;\r
651       OptionHeader.Optional64->ImageBase = BaseAddress;\r
652       MachineType = ImageContext->Machine;\r
653       //\r
654       // Find the relocation block\r
655       //\r
656       // Per the PE/COFF spec, you can't assume that a given data directory\r
657       // is present in the image. You have to check the NumberOfRvaAndSizes in\r
658       // the optional header to verify a desired directory entry is there.\r
659       //\r
660       if (OptionHeader.Optional64->NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC) {\r
661         RelocDir  = &OptionHeader.Optional64->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC];\r
662         RelocBase = PeCoffLoaderImageAddress (ImageContext, RelocDir->VirtualAddress);\r
663         RelocBaseEnd = PeCoffLoaderImageAddress (\r
664                         ImageContext,\r
665                         RelocDir->VirtualAddress + RelocDir->Size - 1\r
666                         );\r
667       } else {\r
668         //\r
669         // Set base and end to bypass processing below.\r
670         //\r
671         RelocBase = RelocBaseEnd = 0;\r
672       }\r
673     }\r
674   } else {\r
675     TeHdr             = (EFI_TE_IMAGE_HEADER *) (UINTN) (ImageContext->ImageAddress);\r
676     Adjust            = (UINT64) (BaseAddress - TeHdr->ImageBase);\r
677     TeHdr->ImageBase  = (UINT64) (BaseAddress);\r
678     MachineType = TeHdr->Machine;\r
679     \r
680     //\r
681     // Find the relocation block\r
682     //\r
683     RelocDir = &TeHdr->DataDirectory[0];\r
684     RelocBase = (EFI_IMAGE_BASE_RELOCATION *)(UINTN)(\r
685                                     ImageContext->ImageAddress + \r
686                                     RelocDir->VirtualAddress +\r
687                                     sizeof(EFI_TE_IMAGE_HEADER) - \r
688                                     TeHdr->StrippedSize\r
689                                     );\r
690     RelocBaseEnd = (EFI_IMAGE_BASE_RELOCATION *) ((UINTN) RelocBase + (UINTN) RelocDir->Size - 1);\r
691   }\r
692   \r
693   //\r
694   // Run the relocation information and apply the fixups\r
695   //\r
696   FixupData = ImageContext->FixupData;\r
697   while (RelocBase < RelocBaseEnd) {\r
698 \r
699     Reloc     = (UINT16 *) ((CHAR8 *) RelocBase + sizeof (EFI_IMAGE_BASE_RELOCATION));\r
700     RelocEnd  = (UINT16 *) ((CHAR8 *) RelocBase + RelocBase->SizeOfBlock);\r
701     if (!(ImageContext->IsTeImage)) {\r
702       FixupBase = PeCoffLoaderImageAddress (ImageContext, RelocBase->VirtualAddress);\r
703     } else {\r
704       FixupBase = (CHAR8 *)(UINTN)(ImageContext->ImageAddress +\r
705                     RelocBase->VirtualAddress +\r
706                     sizeof(EFI_TE_IMAGE_HEADER) - \r
707                     TeHdr->StrippedSize\r
708                     );\r
709     }\r
710 \r
711     if ((CHAR8 *) RelocEnd < (CHAR8 *) ((UINTN) ImageContext->ImageAddress) ||\r
712         (CHAR8 *) RelocEnd > (CHAR8 *)((UINTN)ImageContext->ImageAddress + \r
713           (UINTN)ImageContext->ImageSize)) {\r
714       ImageContext->ImageError = IMAGE_ERROR_FAILED_RELOCATION;\r
715       return RETURN_LOAD_ERROR;\r
716     }\r
717 \r
718     //\r
719     // Run this relocation record\r
720     //\r
721     while (Reloc < RelocEnd) {\r
722 \r
723       Fixup = FixupBase + (*Reloc & 0xFFF);\r
724       switch ((*Reloc) >> 12) {\r
725       case EFI_IMAGE_REL_BASED_ABSOLUTE:\r
726         break;\r
727 \r
728       case EFI_IMAGE_REL_BASED_HIGH:\r
729         F16   = (UINT16 *) Fixup;\r
730         *F16 = (UINT16) (*F16 + ((UINT16) ((UINT32) Adjust >> 16)));\r
731         if (FixupData != NULL) {\r
732           *(UINT16 *) FixupData = *F16;\r
733           FixupData             = FixupData + sizeof (UINT16);\r
734         }\r
735         break;\r
736 \r
737       case EFI_IMAGE_REL_BASED_LOW:\r
738         F16   = (UINT16 *) Fixup;\r
739         *F16  = (UINT16) (*F16 + (UINT16) Adjust);\r
740         if (FixupData != NULL) {\r
741           *(UINT16 *) FixupData = *F16;\r
742           FixupData             = FixupData + sizeof (UINT16);\r
743         }\r
744         break;\r
745 \r
746       case EFI_IMAGE_REL_BASED_HIGHLOW:\r
747         F32   = (UINT32 *) Fixup;\r
748         *F32  = *F32 + (UINT32) Adjust;\r
749         if (FixupData != NULL) {\r
750           FixupData             = ALIGN_POINTER (FixupData, sizeof (UINT32));\r
751           *(UINT32 *) FixupData = *F32;\r
752           FixupData             = FixupData + sizeof (UINT32);\r
753         }\r
754         break;\r
755 \r
756       case EFI_IMAGE_REL_BASED_HIGHADJ:\r
757         //\r
758         // Return the same EFI_UNSUPPORTED return code as\r
759         // PeCoffLoaderRelocateImageEx() returns if it does not recognize\r
760         // the relocation type.\r
761         //\r
762         ImageContext->ImageError = IMAGE_ERROR_FAILED_RELOCATION;\r
763         return RETURN_UNSUPPORTED;\r
764 \r
765       default:\r
766         switch (MachineType) {\r
767         case EFI_IMAGE_MACHINE_IA32:\r
768           Status = PeCoffLoaderRelocateIa32Image (Reloc, Fixup, &FixupData, Adjust);\r
769           break;\r
770         case EFI_IMAGE_MACHINE_X64:\r
771           Status = PeCoffLoaderRelocateX64Image (Reloc, Fixup, &FixupData, Adjust);\r
772           break;\r
773         case EFI_IMAGE_MACHINE_IA64:\r
774           Status = PeCoffLoaderRelocateIpfImage (Reloc, Fixup, &FixupData, Adjust);\r
775           break;\r
776         default:\r
777           Status = RETURN_UNSUPPORTED;\r
778           break;\r
779         }\r
780         if (RETURN_ERROR (Status)) {\r
781           ImageContext->ImageError = IMAGE_ERROR_FAILED_RELOCATION;\r
782           return Status;\r
783         }\r
784       }\r
785 \r
786       //\r
787       // Next relocation record\r
788       //\r
789       Reloc += 1;\r
790     }\r
791 \r
792     //\r
793     // Next reloc block\r
794     //\r
795     RelocBase = (EFI_IMAGE_BASE_RELOCATION *) RelocEnd;\r
796   }\r
797 \r
798   return RETURN_SUCCESS;\r
799 }\r
800 \r
801 RETURN_STATUS\r
802 EFIAPI\r
803 PeCoffLoaderLoadImage (\r
804   IN OUT PE_COFF_LOADER_IMAGE_CONTEXT  *ImageContext\r
805   )\r
806 /*++\r
807 \r
808 Routine Description:\r
809 \r
810   Loads a PE/COFF image into memory\r
811 \r
812 Arguments:\r
813 \r
814   This         - Calling context\r
815 \r
816   ImageContext - Contains information on image to load into memory\r
817 \r
818 Returns:\r
819 \r
820   RETURN_SUCCESS            if the PE/COFF image was loaded\r
821   RETURN_BUFFER_TOO_SMALL   if the caller did not provide a large enough buffer\r
822   RETURN_LOAD_ERROR         if the image is a runtime driver with no relocations\r
823   RETURN_INVALID_PARAMETER  if the image address is invalid\r
824 \r
825 --*/\r
826 {\r
827   RETURN_STATUS                         Status;\r
828   EFI_IMAGE_NT_HEADERS                  *PeHdr;\r
829   EFI_TE_IMAGE_HEADER                   *TeHdr;\r
830   PE_COFF_LOADER_IMAGE_CONTEXT          CheckContext;\r
831   EFI_IMAGE_SECTION_HEADER              *FirstSection;\r
832   EFI_IMAGE_SECTION_HEADER              *Section;\r
833   UINTN                                 NumberOfSections;\r
834   UINTN                                 Index;\r
835   CHAR8                                 *Base;\r
836   CHAR8                                 *End;\r
837   CHAR8                                 *MaxEnd;\r
838   EFI_IMAGE_DATA_DIRECTORY              *DirectoryEntry;\r
839   EFI_IMAGE_DEBUG_DIRECTORY_ENTRY       *DebugEntry;\r
840   UINTN                                 Size;\r
841   UINT32                                TempDebugEntryRva;\r
842   EFI_IMAGE_OPTIONAL_HEADER_POINTER     OptionHeader;\r
843 \r
844   PeHdr = NULL;\r
845   TeHdr = NULL;\r
846   //\r
847   // Assume success\r
848   //\r
849   ImageContext->ImageError = IMAGE_ERROR_SUCCESS;\r
850 \r
851   //\r
852   // Copy the provided context info into our local version, get what we\r
853   // can from the original image, and then use that to make sure everything\r
854   // is legit.\r
855   //\r
856   CopyMem (&CheckContext, ImageContext, sizeof (PE_COFF_LOADER_IMAGE_CONTEXT));\r
857 \r
858   Status = PeCoffLoaderGetImageInfo (&CheckContext);\r
859   if (RETURN_ERROR (Status)) {\r
860     return Status;\r
861   }\r
862 \r
863   //\r
864   // Make sure there is enough allocated space for the image being loaded\r
865   //\r
866   if (ImageContext->ImageSize < CheckContext.ImageSize) {\r
867     ImageContext->ImageError = IMAGE_ERROR_INVALID_IMAGE_SIZE;\r
868     return RETURN_BUFFER_TOO_SMALL;\r
869   }\r
870 \r
871   //\r
872   // If there's no relocations, then make sure it's not a runtime driver,\r
873   // and that it's being loaded at the linked address.\r
874   //\r
875   if (CheckContext.RelocationsStripped) {\r
876     //\r
877     // If the image does not contain relocations and it is a runtime driver\r
878     // then return an error.\r
879     //\r
880     if (CheckContext.ImageType == EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER) {\r
881       ImageContext->ImageError = IMAGE_ERROR_INVALID_SUBSYSTEM;\r
882       return RETURN_LOAD_ERROR;\r
883     }\r
884     //\r
885     // If the image does not contain relocations, and the requested load address\r
886     // is not the linked address, then return an error.\r
887     //\r
888     if (CheckContext.ImageAddress != ImageContext->ImageAddress) {\r
889       ImageContext->ImageError = IMAGE_ERROR_INVALID_IMAGE_ADDRESS;\r
890       return RETURN_INVALID_PARAMETER;\r
891     }\r
892   }\r
893   //\r
894   // Make sure the allocated space has the proper section alignment\r
895   //\r
896   if (!(ImageContext->IsTeImage)) {\r
897     if ((ImageContext->ImageAddress & (CheckContext.SectionAlignment - 1)) != 0) {\r
898       ImageContext->ImageError = IMAGE_ERROR_INVALID_SECTION_ALIGNMENT;\r
899       return RETURN_INVALID_PARAMETER;\r
900     }\r
901   }\r
902   //\r
903   // Read the entire PE/COFF or TE header into memory\r
904   //\r
905   if (!(ImageContext->IsTeImage)) {\r
906     Status = ImageContext->ImageRead (\r
907                             ImageContext->Handle,\r
908                             0,\r
909                             &ImageContext->SizeOfHeaders,\r
910                             (VOID *) (UINTN) ImageContext->ImageAddress\r
911                             );\r
912 \r
913     PeHdr = (EFI_IMAGE_NT_HEADERS *)\r
914       ((UINTN)ImageContext->ImageAddress + ImageContext->PeCoffHeaderOffset);\r
915 \r
916     OptionHeader.Header = (VOID *) &(PeHdr->OptionalHeader);\r
917     \r
918     FirstSection = (EFI_IMAGE_SECTION_HEADER *) (\r
919                       (UINTN)ImageContext->ImageAddress +\r
920                       ImageContext->PeCoffHeaderOffset +\r
921                       sizeof(UINT32) + \r
922                       sizeof(EFI_IMAGE_FILE_HEADER) + \r
923                       PeHdr->FileHeader.SizeOfOptionalHeader\r
924       );\r
925     NumberOfSections = (UINTN) (PeHdr->FileHeader.NumberOfSections);\r
926   } else {\r
927     Status = ImageContext->ImageRead (\r
928                             ImageContext->Handle,\r
929                             0,\r
930                             &ImageContext->SizeOfHeaders,\r
931                             (void *) (UINTN) ImageContext->ImageAddress\r
932                             );\r
933 \r
934     TeHdr             = (EFI_TE_IMAGE_HEADER *) (UINTN) (ImageContext->ImageAddress);\r
935 \r
936     FirstSection = (EFI_IMAGE_SECTION_HEADER *) (\r
937           (UINTN)ImageContext->ImageAddress +\r
938           sizeof(EFI_TE_IMAGE_HEADER)\r
939           );\r
940     NumberOfSections  = (UINTN) (TeHdr->NumberOfSections);\r
941 \r
942   }\r
943 \r
944   if (RETURN_ERROR (Status)) {\r
945     ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;\r
946     return RETURN_LOAD_ERROR;\r
947   }\r
948 \r
949   //\r
950   // Load each section of the image\r
951   //\r
952   Section = FirstSection;\r
953   for (Index = 0, MaxEnd = NULL; Index < NumberOfSections; Index++) {\r
954 \r
955     //\r
956     // Compute sections address\r
957     //\r
958     Base = PeCoffLoaderImageAddress (ImageContext, Section->VirtualAddress);\r
959     End = PeCoffLoaderImageAddress (\r
960             ImageContext,\r
961             Section->VirtualAddress + Section->Misc.VirtualSize - 1\r
962             );\r
963     if (ImageContext->IsTeImage) {\r
964       Base  = (CHAR8 *) ((UINTN) Base + sizeof (EFI_TE_IMAGE_HEADER) - (UINTN) TeHdr->StrippedSize);\r
965       End   = (CHAR8 *) ((UINTN) End + sizeof (EFI_TE_IMAGE_HEADER) - (UINTN) TeHdr->StrippedSize);\r
966     }\r
967 \r
968     if (End > MaxEnd) {\r
969       MaxEnd = End;\r
970     }\r
971     //\r
972     // If the base start or end address resolved to 0, then fail.\r
973     //\r
974     if ((Base == NULL) || (End == NULL)) {\r
975       ImageContext->ImageError = IMAGE_ERROR_SECTION_NOT_LOADED;\r
976       return RETURN_LOAD_ERROR;\r
977     }\r
978 \r
979     //\r
980     // Read the section\r
981     //\r
982     Size = (UINTN) Section->Misc.VirtualSize;\r
983     if ((Size == 0) || (Size > Section->SizeOfRawData)) {\r
984       Size = (UINTN) Section->SizeOfRawData;\r
985     }\r
986 \r
987     if (Section->SizeOfRawData) {\r
988       if (!(ImageContext->IsTeImage)) {\r
989         Status = ImageContext->ImageRead (\r
990                                 ImageContext->Handle,\r
991                                 Section->PointerToRawData,\r
992                                 &Size,\r
993                                 Base\r
994                                 );\r
995       } else {\r
996         Status = ImageContext->ImageRead (\r
997                                 ImageContext->Handle,\r
998                                 Section->PointerToRawData + sizeof (EFI_TE_IMAGE_HEADER) - (UINTN) TeHdr->StrippedSize,\r
999                                 &Size,\r
1000                                 Base\r
1001                                 );\r
1002       }\r
1003 \r
1004       if (RETURN_ERROR (Status)) {\r
1005         ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;\r
1006         return Status;\r
1007       }\r
1008     }\r
1009 \r
1010     //\r
1011     // If raw size is less then virt size, zero fill the remaining\r
1012     //\r
1013 \r
1014     if (Size < Section->Misc.VirtualSize) {\r
1015       ZeroMem (Base + Size, Section->Misc.VirtualSize - Size);\r
1016     }\r
1017 \r
1018     //\r
1019     // Next Section\r
1020     //\r
1021     Section += 1;\r
1022   }\r
1023 \r
1024   //\r
1025   // Get image's entry point\r
1026   //\r
1027   if (!(ImageContext->IsTeImage)) {\r
1028     ImageContext->EntryPoint = (PHYSICAL_ADDRESS) (UINTN) PeCoffLoaderImageAddress (\r
1029                                                                 ImageContext,\r
1030                                                                 PeHdr->OptionalHeader.AddressOfEntryPoint\r
1031                                                                 );\r
1032   } else {\r
1033     ImageContext->EntryPoint =  (PHYSICAL_ADDRESS) (\r
1034                        (UINTN)ImageContext->ImageAddress +\r
1035                        (UINTN)TeHdr->AddressOfEntryPoint +\r
1036                        (UINTN)sizeof(EFI_TE_IMAGE_HEADER) -\r
1037           (UINTN) TeHdr->StrippedSize\r
1038       );\r
1039   }\r
1040 \r
1041   //\r
1042   // Determine the size of the fixup data\r
1043   //\r
1044   // Per the PE/COFF spec, you can't assume that a given data directory\r
1045   // is present in the image. You have to check the NumberOfRvaAndSizes in\r
1046   // the optional header to verify a desired directory entry is there.\r
1047   //\r
1048   if (!(ImageContext->IsTeImage)) {\r
1049     if (ImageContext->Machine == EFI_IMAGE_MACHINE_IA32) {\r
1050       if (OptionHeader.Optional32->NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC) {\r
1051         DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)\r
1052           &OptionHeader.Optional32->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC];\r
1053         ImageContext->FixupDataSize = DirectoryEntry->Size / sizeof (UINT16) * sizeof (UINTN);\r
1054       } else {\r
1055         ImageContext->FixupDataSize = 0;\r
1056       }\r
1057     } else {\r
1058       if (OptionHeader.Optional64->NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC) {\r
1059         DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)\r
1060           &OptionHeader.Optional64->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC];\r
1061         ImageContext->FixupDataSize = DirectoryEntry->Size / sizeof (UINT16) * sizeof (UINTN);\r
1062       } else {\r
1063         ImageContext->FixupDataSize = 0;\r
1064       }\r
1065     }\r
1066   } else {\r
1067     DirectoryEntry              = &TeHdr->DataDirectory[0];\r
1068     ImageContext->FixupDataSize = DirectoryEntry->Size / sizeof (UINT16) * sizeof (UINTN);\r
1069   }\r
1070   //\r
1071   // Consumer must allocate a buffer for the relocation fixup log.\r
1072   // Only used for runtime drivers.\r
1073   //\r
1074   ImageContext->FixupData = NULL;\r
1075 \r
1076   //\r
1077   // Load the Codeview info if present\r
1078   //\r
1079   if (ImageContext->DebugDirectoryEntryRva != 0) {\r
1080     if (!(ImageContext->IsTeImage)) {\r
1081       DebugEntry = PeCoffLoaderImageAddress (\r
1082                     ImageContext,\r
1083                     ImageContext->DebugDirectoryEntryRva\r
1084                     );\r
1085     } else {\r
1086       DebugEntry = (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *)(UINTN)(\r
1087                                                ImageContext->ImageAddress +\r
1088                                                ImageContext->DebugDirectoryEntryRva +\r
1089                                                sizeof(EFI_TE_IMAGE_HEADER) -\r
1090                                                TeHdr->StrippedSize\r
1091                                                );\r
1092     }\r
1093 \r
1094     if (DebugEntry != NULL) {\r
1095       TempDebugEntryRva = DebugEntry->RVA;\r
1096       if (DebugEntry->RVA == 0 && DebugEntry->FileOffset != 0) {\r
1097         Section--;\r
1098         if ((UINTN) Section->SizeOfRawData < Section->Misc.VirtualSize) {\r
1099           TempDebugEntryRva = Section->VirtualAddress + Section->Misc.VirtualSize;\r
1100         } else {\r
1101           TempDebugEntryRva = Section->VirtualAddress + Section->SizeOfRawData;\r
1102         }\r
1103       }\r
1104 \r
1105       if (TempDebugEntryRva != 0) {\r
1106         if (!(ImageContext->IsTeImage)) {\r
1107           ImageContext->CodeView = PeCoffLoaderImageAddress (ImageContext, TempDebugEntryRva);\r
1108         } else {\r
1109           ImageContext->CodeView = (VOID *)(\r
1110                       (UINTN)ImageContext->ImageAddress +\r
1111                       (UINTN)TempDebugEntryRva +\r
1112                       (UINTN)sizeof(EFI_TE_IMAGE_HEADER) -\r
1113                 (UINTN) TeHdr->StrippedSize\r
1114             );\r
1115         }\r
1116 \r
1117         if (ImageContext->CodeView == NULL) {\r
1118           ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;\r
1119           return RETURN_LOAD_ERROR;\r
1120         }\r
1121 \r
1122         if (DebugEntry->RVA == 0) {\r
1123           Size = DebugEntry->SizeOfData;\r
1124           if (!(ImageContext->IsTeImage)) {\r
1125             Status = ImageContext->ImageRead (\r
1126                                     ImageContext->Handle,\r
1127                                     DebugEntry->FileOffset,\r
1128                                     &Size,\r
1129                                     ImageContext->CodeView\r
1130                                     );\r
1131           } else {\r
1132             Status = ImageContext->ImageRead (\r
1133                                     ImageContext->Handle,\r
1134                                     DebugEntry->FileOffset + sizeof (EFI_TE_IMAGE_HEADER) - TeHdr->StrippedSize,\r
1135                                     &Size,\r
1136                                     ImageContext->CodeView\r
1137                                     );\r
1138             //\r
1139             // Should we apply fix up to this field according to the size difference between PE and TE?\r
1140             // Because now we maintain TE header fields unfixed, this field will also remain as they are\r
1141             // in original PE image.\r
1142             //\r
1143           }\r
1144 \r
1145           if (RETURN_ERROR (Status)) {\r
1146             ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;\r
1147             return RETURN_LOAD_ERROR;\r
1148           }\r
1149 \r
1150           DebugEntry->RVA = TempDebugEntryRva;\r
1151         }\r
1152 \r
1153         switch (*(UINT32 *) ImageContext->CodeView) {\r
1154         case CODEVIEW_SIGNATURE_NB10:\r
1155           ImageContext->PdbPointer = (CHAR8 *) ImageContext->CodeView + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY);\r
1156           break;\r
1157 \r
1158         case CODEVIEW_SIGNATURE_RSDS:\r
1159           ImageContext->PdbPointer = (CHAR8 *) ImageContext->CodeView + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY);\r
1160           break;\r
1161 \r
1162         default:\r
1163           break;\r
1164         }\r
1165       }\r
1166     }\r
1167   }\r
1168 \r
1169   return Status;\r
1170 }\r