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