3 Copyright (c) 2004 - 2005, Intel Corporation
4 All rights reserved. This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
25 #define EFI_SPECIFICATION_VERSION 0x00000000
26 #define EDK_RELEASE_VERSION 0x00020000
28 #include <Library/PeCoffLib.h>
29 #include <Library/BaseMemoryLib.h>
33 PeCoffLoaderGetPeHeader (
34 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
,
35 OUT EFI_IMAGE_NT_HEADERS
*PeHdr
,
36 OUT EFI_TE_IMAGE_HEADER
*TeHdr
41 PeCoffLoaderCheckImageType (
42 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
,
43 IN EFI_IMAGE_NT_HEADERS
*PeHdr
,
44 IN EFI_TE_IMAGE_HEADER
*TeHdr
49 PeCoffLoaderImageAddress (
50 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
,
57 PeCoffLoaderGetPeHeader (
58 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
,
59 OUT EFI_IMAGE_NT_HEADERS
*PeHdr
,
60 OUT EFI_TE_IMAGE_HEADER
*TeHdr
66 Retrieves the PE or TE Header from a PE/COFF or TE image
70 ImageContext - The context of the image being loaded
72 PeHdr - The buffer in which to return the PE header
74 TeHdr - The buffer in which to return the TE header
78 RETURN_SUCCESS if the PE or TE Header is read,
79 Otherwise, the error status from reading the PE/COFF or TE image using the ImageRead function.
84 EFI_IMAGE_DOS_HEADER DosHdr
;
87 ImageContext
->IsTeImage
= FALSE
;
89 // Read the DOS image headers
91 Size
= sizeof (EFI_IMAGE_DOS_HEADER
);
92 Status
= ImageContext
->ImageRead (
98 if (RETURN_ERROR (Status
)) {
99 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
103 ImageContext
->PeCoffHeaderOffset
= 0;
104 if (DosHdr
.e_magic
== EFI_IMAGE_DOS_SIGNATURE
) {
106 // DOS image header is present, so read the PE header after the DOS image header
108 ImageContext
->PeCoffHeaderOffset
= DosHdr
.e_lfanew
;
111 // Read the PE/COFF Header
113 Size
= sizeof (EFI_IMAGE_NT_HEADERS
);
114 Status
= ImageContext
->ImageRead (
115 ImageContext
->Handle
,
116 ImageContext
->PeCoffHeaderOffset
,
120 if (RETURN_ERROR (Status
)) {
121 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
125 // Check the PE/COFF Header Signature. If not, then try to read a TE header
127 if (PeHdr
->Signature
!= EFI_IMAGE_NT_SIGNATURE
) {
128 Size
= sizeof (EFI_TE_IMAGE_HEADER
);
129 Status
= ImageContext
->ImageRead (
130 ImageContext
->Handle
,
135 if (TeHdr
->Signature
!= EFI_TE_IMAGE_HEADER_SIGNATURE
) {
136 return RETURN_UNSUPPORTED
;
139 ImageContext
->IsTeImage
= TRUE
;
142 return RETURN_SUCCESS
;
147 PeCoffLoaderCheckImageType (
148 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
,
149 IN EFI_IMAGE_NT_HEADERS
*PeHdr
,
150 IN EFI_TE_IMAGE_HEADER
*TeHdr
156 Checks the PE or TE header of a PE/COFF or TE image to determine if it supported
160 ImageContext - The context of the image being loaded
162 PeHdr - The buffer in which to return the PE header
164 TeHdr - The buffer in which to return the TE header
168 RETURN_SUCCESS if the PE/COFF or TE image is supported
169 RETURN_UNSUPPORTED of the PE/COFF or TE image is not supported.
174 // See if the machine type is supported. We support a native machine type (IA-32/Itanium-based)
175 // and the machine type for the Virtual Machine.
177 if (ImageContext
->IsTeImage
== FALSE
) {
178 ImageContext
->Machine
= PeHdr
->FileHeader
.Machine
;
180 ImageContext
->Machine
= TeHdr
->Machine
;
183 if (!(EFI_IMAGE_MACHINE_TYPE_SUPPORTED (ImageContext
->Machine
))) {
184 ImageContext
->ImageError
= IMAGE_ERROR_INVALID_MACHINE_TYPE
;
185 return RETURN_UNSUPPORTED
;
189 // See if the image type is supported. We support EFI Applications,
190 // EFI Boot Service Drivers, and EFI Runtime Drivers.
192 if (ImageContext
->IsTeImage
== FALSE
) {
193 ImageContext
->ImageType
= PeHdr
->OptionalHeader
.Subsystem
;
195 ImageContext
->ImageType
= (UINT16
) (TeHdr
->Subsystem
);
199 return RETURN_SUCCESS
;
204 PeCoffLoaderGetImageInfo (
205 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
211 Retrieves information on a PE/COFF image
215 This - Calling context
216 ImageContext - The context of the image being loaded
220 RETURN_SUCCESS - The information on the PE/COFF image was collected.
221 RETURN_INVALID_PARAMETER - ImageContext is NULL.
222 RETURN_UNSUPPORTED - The PE/COFF image is not supported.
223 Otherwise - The error status from reading the PE/COFF image using the
224 ImageContext->ImageRead() function
228 RETURN_STATUS Status
;
229 EFI_IMAGE_NT_HEADERS PeHdr
;
230 EFI_TE_IMAGE_HEADER TeHdr
;
231 EFI_IMAGE_DATA_DIRECTORY
*DebugDirectoryEntry
;
234 UINTN DebugDirectoryEntryRva
;
235 UINTN DebugDirectoryEntryFileOffset
;
236 UINTN SectionHeaderOffset
;
237 EFI_IMAGE_SECTION_HEADER SectionHeader
;
238 EFI_IMAGE_DEBUG_DIRECTORY_ENTRY DebugEntry
;
240 if (NULL
== ImageContext
) {
241 return RETURN_INVALID_PARAMETER
;
246 ImageContext
->ImageError
= IMAGE_ERROR_SUCCESS
;
248 Status
= PeCoffLoaderGetPeHeader (ImageContext
, &PeHdr
, &TeHdr
);
249 if (RETURN_ERROR (Status
)) {
253 // Verify machine type
255 Status
= PeCoffLoaderCheckImageType (ImageContext
, &PeHdr
, &TeHdr
);
256 if (RETURN_ERROR (Status
)) {
260 // Retrieve the base address of the image
262 if (!(ImageContext
->IsTeImage
)) {
263 ImageContext
->ImageAddress
= PeHdr
.OptionalHeader
.ImageBase
;
265 ImageContext
->ImageAddress
= (PHYSICAL_ADDRESS
) (TeHdr
.ImageBase
);
268 // Initialize the alternate destination address to 0 indicating that it
269 // should not be used.
271 ImageContext
->DestinationAddress
= 0;
274 // Initialize the codeview pointer.
276 ImageContext
->CodeView
= NULL
;
277 ImageContext
->PdbPointer
= NULL
;
280 // Three cases with regards to relocations:
281 // - Image has base relocs, RELOCS_STRIPPED==0 => image is relocatable
282 // - Image has no base relocs, RELOCS_STRIPPED==1 => Image is not relocatable
283 // - Image has no base relocs, RELOCS_STRIPPED==0 => Image is relocatable but
284 // has no base relocs to apply
285 // Obviously having base relocations with RELOCS_STRIPPED==1 is invalid.
287 // Look at the file header to determine if relocations have been stripped, and
288 // save this info in the image context for later use.
290 if ((!(ImageContext
->IsTeImage
)) && ((PeHdr
.FileHeader
.Characteristics
& EFI_IMAGE_FILE_RELOCS_STRIPPED
) != 0)) {
291 ImageContext
->RelocationsStripped
= TRUE
;
293 ImageContext
->RelocationsStripped
= FALSE
;
296 if (!(ImageContext
->IsTeImage
)) {
297 ImageContext
->ImageSize
= (UINT64
) PeHdr
.OptionalHeader
.SizeOfImage
;
298 ImageContext
->SectionAlignment
= PeHdr
.OptionalHeader
.SectionAlignment
;
299 ImageContext
->SizeOfHeaders
= PeHdr
.OptionalHeader
.SizeOfHeaders
;
302 // Modify ImageSize to contain .PDB file name if required and initialize
305 if (PeHdr
.OptionalHeader
.NumberOfRvaAndSizes
> EFI_IMAGE_DIRECTORY_ENTRY_DEBUG
) {
306 DebugDirectoryEntry
= (EFI_IMAGE_DATA_DIRECTORY
*) &(PeHdr
.OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG
]);
308 DebugDirectoryEntryRva
= DebugDirectoryEntry
->VirtualAddress
;
311 // Determine the file offset of the debug directory... This means we walk
312 // the sections to find which section contains the RVA of the debug
315 DebugDirectoryEntryFileOffset
= 0;
317 SectionHeaderOffset
= (UINTN
)(
318 ImageContext
->PeCoffHeaderOffset
+
320 sizeof (EFI_IMAGE_FILE_HEADER
) +
321 PeHdr
.FileHeader
.SizeOfOptionalHeader
324 for (Index
= 0; Index
< PeHdr
.FileHeader
.NumberOfSections
; Index
++) {
326 // Read section header from file
328 Size
= sizeof (EFI_IMAGE_SECTION_HEADER
);
329 Status
= ImageContext
->ImageRead (
330 ImageContext
->Handle
,
335 if (RETURN_ERROR (Status
)) {
336 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
340 if (DebugDirectoryEntryRva
>= SectionHeader
.VirtualAddress
&&
341 DebugDirectoryEntryRva
< SectionHeader
.VirtualAddress
+ SectionHeader
.Misc
.VirtualSize
) {
342 DebugDirectoryEntryFileOffset
=
343 DebugDirectoryEntryRva
- SectionHeader
.VirtualAddress
+ SectionHeader
.PointerToRawData
;
347 SectionHeaderOffset
+= sizeof (EFI_IMAGE_SECTION_HEADER
);
350 if (DebugDirectoryEntryFileOffset
!= 0) {
351 for (Index
= 0; Index
< DebugDirectoryEntry
->Size
; Index
++) {
353 // Read next debug directory entry
355 Size
= sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
);
356 Status
= ImageContext
->ImageRead (
357 ImageContext
->Handle
,
358 DebugDirectoryEntryFileOffset
,
362 if (RETURN_ERROR (Status
)) {
363 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
367 if (DebugEntry
.Type
== EFI_IMAGE_DEBUG_TYPE_CODEVIEW
) {
368 ImageContext
->DebugDirectoryEntryRva
= (UINT32
) (DebugDirectoryEntryRva
+ Index
* sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
));
369 if (DebugEntry
.RVA
== 0 && DebugEntry
.FileOffset
!= 0) {
370 ImageContext
->ImageSize
+= DebugEntry
.SizeOfData
;
373 return RETURN_SUCCESS
;
379 ImageContext
->ImageSize
= 0;
380 ImageContext
->SectionAlignment
= 4096;
381 ImageContext
->SizeOfHeaders
= sizeof (EFI_TE_IMAGE_HEADER
) + (UINTN
) TeHdr
.BaseOfCode
- (UINTN
) TeHdr
.StrippedSize
;
383 DebugDirectoryEntry
= &TeHdr
.DataDirectory
[1];
384 DebugDirectoryEntryRva
= DebugDirectoryEntry
->VirtualAddress
;
385 SectionHeaderOffset
= (UINTN
) (sizeof (EFI_TE_IMAGE_HEADER
));
387 DebugDirectoryEntryFileOffset
= 0;
389 for (Index
= 0; Index
< TeHdr
.NumberOfSections
;) {
391 // Read section header from file
393 Size
= sizeof (EFI_IMAGE_SECTION_HEADER
);
394 Status
= ImageContext
->ImageRead (
395 ImageContext
->Handle
,
400 if (RETURN_ERROR (Status
)) {
401 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
405 if (DebugDirectoryEntryRva
>= SectionHeader
.VirtualAddress
&&
406 DebugDirectoryEntryRva
< SectionHeader
.VirtualAddress
+ SectionHeader
.Misc
.VirtualSize
) {
407 DebugDirectoryEntryFileOffset
= DebugDirectoryEntryRva
-
408 SectionHeader
.VirtualAddress
+
409 SectionHeader
.PointerToRawData
+
410 sizeof (EFI_TE_IMAGE_HEADER
) -
414 // File offset of the debug directory was found, if this is not the last
415 // section, then skip to the last section for calculating the image size.
417 if (Index
< (UINTN
) TeHdr
.NumberOfSections
- 1) {
418 SectionHeaderOffset
+= (TeHdr
.NumberOfSections
- 1 - Index
) * sizeof (EFI_IMAGE_SECTION_HEADER
);
419 Index
= TeHdr
.NumberOfSections
- 1;
425 // In Te image header there is not a field to describe the ImageSize.
426 // Actually, the ImageSize equals the RVA plus the VirtualSize of
427 // the last section mapped into memory (Must be rounded up to
428 // a mulitple of Section Alignment). Per the PE/COFF specification, the
429 // section headers in the Section Table must appear in order of the RVA
430 // values for the corresponding sections. So the ImageSize can be determined
431 // by the RVA and the VirtualSize of the last section header in the
434 if ((++Index
) == (UINTN
) TeHdr
.NumberOfSections
) {
435 ImageContext
->ImageSize
= (SectionHeader
.VirtualAddress
+ SectionHeader
.Misc
.VirtualSize
+
436 ImageContext
->SectionAlignment
- 1) & ~(ImageContext
->SectionAlignment
- 1);
439 SectionHeaderOffset
+= sizeof (EFI_IMAGE_SECTION_HEADER
);
442 if (DebugDirectoryEntryFileOffset
!= 0) {
443 for (Index
= 0; Index
< DebugDirectoryEntry
->Size
; Index
++) {
445 // Read next debug directory entry
447 Size
= sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
);
448 Status
= ImageContext
->ImageRead (
449 ImageContext
->Handle
,
450 DebugDirectoryEntryFileOffset
,
454 if (RETURN_ERROR (Status
)) {
455 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
459 if (DebugEntry
.Type
== EFI_IMAGE_DEBUG_TYPE_CODEVIEW
) {
460 ImageContext
->DebugDirectoryEntryRva
= (UINT32
) (DebugDirectoryEntryRva
+ Index
* sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
));
461 return RETURN_SUCCESS
;
467 return RETURN_SUCCESS
;
472 PeCoffLoaderImageAddress (
473 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
,
480 Converts an image address to the loaded address
484 ImageContext - The context of the image being loaded
486 Address - The address to be converted to the loaded address
490 NULL if the address can not be converted, otherwise, the converted address
494 if (Address
>= ImageContext
->ImageSize
) {
495 ImageContext
->ImageError
= IMAGE_ERROR_INVALID_IMAGE_ADDRESS
;
499 return (CHAR8
*) ((UINTN
) ImageContext
->ImageAddress
+ Address
);
504 PeCoffLoaderRelocateImage (
505 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
511 Relocates a PE/COFF image in memory
515 This - Calling context
517 ImageContext - Contains information on the loaded image to relocate
521 RETURN_SUCCESS if the PE/COFF image was relocated
522 RETURN_LOAD_ERROR if the image is not a valid PE/COFF image
523 RETURN_UNSUPPORTED not support
527 RETURN_STATUS Status
;
528 EFI_IMAGE_NT_HEADERS
*PeHdr
;
529 EFI_TE_IMAGE_HEADER
*TeHdr
;
530 EFI_IMAGE_DATA_DIRECTORY
*RelocDir
;
532 EFI_IMAGE_BASE_RELOCATION
*RelocBase
;
533 EFI_IMAGE_BASE_RELOCATION
*RelocBaseEnd
;
541 PHYSICAL_ADDRESS BaseAddress
;
548 ImageContext
->ImageError
= IMAGE_ERROR_SUCCESS
;
551 // If there are no relocation entries, then we are done
553 if (ImageContext
->RelocationsStripped
) {
554 return RETURN_SUCCESS
;
558 // If the destination address is not 0, use that rather than the
559 // image address as the relocation target.
561 if (ImageContext
->DestinationAddress
) {
562 BaseAddress
= ImageContext
->DestinationAddress
;
564 BaseAddress
= ImageContext
->ImageAddress
;
567 if (!(ImageContext
->IsTeImage
)) {
568 PeHdr
= (EFI_IMAGE_NT_HEADERS
*)((UINTN
)ImageContext
->ImageAddress
+
569 ImageContext
->PeCoffHeaderOffset
);
570 Adjust
= (UINT64
) BaseAddress
- PeHdr
->OptionalHeader
.ImageBase
;
571 PeHdr
->OptionalHeader
.ImageBase
= (UINTN
) BaseAddress
;
574 // Find the relocation block
576 // Per the PE/COFF spec, you can't assume that a given data directory
577 // is present in the image. You have to check the NumberOfRvaAndSizes in
578 // the optional header to verify a desired directory entry is there.
580 if (PeHdr
->OptionalHeader
.NumberOfRvaAndSizes
> EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
) {
581 RelocDir
= &PeHdr
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
];
582 RelocBase
= PeCoffLoaderImageAddress (ImageContext
, RelocDir
->VirtualAddress
);
583 RelocBaseEnd
= PeCoffLoaderImageAddress (
585 RelocDir
->VirtualAddress
+ RelocDir
->Size
- 1
589 // Set base and end to bypass processing below.
591 RelocBase
= RelocBaseEnd
= 0;
594 TeHdr
= (EFI_TE_IMAGE_HEADER
*) (UINTN
) (ImageContext
->ImageAddress
);
595 Adjust
= (UINT64
) (BaseAddress
- TeHdr
->ImageBase
);
596 TeHdr
->ImageBase
= (UINT64
) (BaseAddress
);
599 // Find the relocation block
601 RelocDir
= &TeHdr
->DataDirectory
[0];
602 RelocBase
= (EFI_IMAGE_BASE_RELOCATION
*)(UINTN
)(
603 ImageContext
->ImageAddress
+
604 RelocDir
->VirtualAddress
+
605 sizeof(EFI_TE_IMAGE_HEADER
) -
608 RelocBaseEnd
= (EFI_IMAGE_BASE_RELOCATION
*) ((UINTN
) RelocBase
+ (UINTN
) RelocDir
->Size
- 1);
612 // Run the relocation information and apply the fixups
614 FixupData
= ImageContext
->FixupData
;
615 while (RelocBase
< RelocBaseEnd
) {
617 Reloc
= (UINT16
*) ((CHAR8
*) RelocBase
+ sizeof (EFI_IMAGE_BASE_RELOCATION
));
618 RelocEnd
= (UINT16
*) ((CHAR8
*) RelocBase
+ RelocBase
->SizeOfBlock
);
619 if (!(ImageContext
->IsTeImage
)) {
620 FixupBase
= PeCoffLoaderImageAddress (ImageContext
, RelocBase
->VirtualAddress
);
622 FixupBase
= (CHAR8
*)(UINTN
)(ImageContext
->ImageAddress
+
623 RelocBase
->VirtualAddress
+
624 sizeof(EFI_TE_IMAGE_HEADER
) -
629 if ((CHAR8
*) RelocEnd
< (CHAR8
*) ((UINTN
) ImageContext
->ImageAddress
) ||
630 (CHAR8
*) RelocEnd
> (CHAR8
*)((UINTN
)ImageContext
->ImageAddress
+
631 (UINTN
)ImageContext
->ImageSize
)) {
632 ImageContext
->ImageError
= IMAGE_ERROR_FAILED_RELOCATION
;
633 return RETURN_LOAD_ERROR
;
637 // Run this relocation record
639 while (Reloc
< RelocEnd
) {
641 Fixup
= FixupBase
+ (*Reloc
& 0xFFF);
642 switch ((*Reloc
) >> 12) {
643 case EFI_IMAGE_REL_BASED_ABSOLUTE
:
646 case EFI_IMAGE_REL_BASED_HIGH
:
647 F16
= (UINT16
*) Fixup
;
648 *F16
= (UINT16
) ((*F16
<< 16) + (UINT16
) Adjust
);
649 if (FixupData
!= NULL
) {
650 *(UINT16
*) FixupData
= *F16
;
651 FixupData
= FixupData
+ sizeof (UINT16
);
655 case EFI_IMAGE_REL_BASED_LOW
:
656 F16
= (UINT16
*) Fixup
;
657 *F16
= (UINT16
) (*F16
+ (UINT16
) Adjust
);
658 if (FixupData
!= NULL
) {
659 *(UINT16
*) FixupData
= *F16
;
660 FixupData
= FixupData
+ sizeof (UINT16
);
664 case EFI_IMAGE_REL_BASED_HIGHLOW
:
665 F32
= (UINT32
*) Fixup
;
666 *F32
= *F32
+ (UINT32
) Adjust
;
667 if (FixupData
!= NULL
) {
668 FixupData
= ALIGN_POINTER (FixupData
, sizeof (UINT32
));
669 *(UINT32
*) FixupData
= *F32
;
670 FixupData
= FixupData
+ sizeof (UINT32
);
674 case EFI_IMAGE_REL_BASED_HIGHADJ
:
676 // Return the same EFI_UNSUPPORTED return code as
677 // PeCoffLoaderRelocateImageEx() returns if it does not recognize
678 // the relocation type.
680 ImageContext
->ImageError
= IMAGE_ERROR_FAILED_RELOCATION
;
681 return RETURN_UNSUPPORTED
;
684 Status
= PeCoffLoaderRelocateImageEx (Reloc
, Fixup
, &FixupData
, Adjust
);
685 if (RETURN_ERROR (Status
)) {
686 ImageContext
->ImageError
= IMAGE_ERROR_FAILED_RELOCATION
;
692 // Next relocation record
700 RelocBase
= (EFI_IMAGE_BASE_RELOCATION
*) RelocEnd
;
703 return RETURN_SUCCESS
;
708 PeCoffLoaderLoadImage (
709 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
715 Loads a PE/COFF image into memory
719 This - Calling context
721 ImageContext - Contains information on image to load into memory
725 RETURN_SUCCESS if the PE/COFF image was loaded
726 RETURN_BUFFER_TOO_SMALL if the caller did not provide a large enough buffer
727 RETURN_LOAD_ERROR if the image is a runtime driver with no relocations
728 RETURN_INVALID_PARAMETER if the image address is invalid
732 RETURN_STATUS Status
;
733 EFI_IMAGE_NT_HEADERS
*PeHdr
;
734 EFI_TE_IMAGE_HEADER
*TeHdr
;
735 PE_COFF_LOADER_IMAGE_CONTEXT CheckContext
;
736 EFI_IMAGE_SECTION_HEADER
*FirstSection
;
737 EFI_IMAGE_SECTION_HEADER
*Section
;
738 UINTN NumberOfSections
;
743 EFI_IMAGE_DATA_DIRECTORY
*DirectoryEntry
;
744 EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
*DebugEntry
;
746 UINT32 TempDebugEntryRva
;
753 ImageContext
->ImageError
= IMAGE_ERROR_SUCCESS
;
756 // Copy the provided context info into our local version, get what we
757 // can from the original image, and then use that to make sure everything
760 CopyMem (&CheckContext
, ImageContext
, sizeof (PE_COFF_LOADER_IMAGE_CONTEXT
));
762 Status
= PeCoffLoaderGetImageInfo (&CheckContext
);
763 if (RETURN_ERROR (Status
)) {
768 // Make sure there is enough allocated space for the image being loaded
770 if (ImageContext
->ImageSize
< CheckContext
.ImageSize
) {
771 ImageContext
->ImageError
= IMAGE_ERROR_INVALID_IMAGE_SIZE
;
772 return RETURN_BUFFER_TOO_SMALL
;
776 // If there's no relocations, then make sure it's not a runtime driver,
777 // and that it's being loaded at the linked address.
779 if (CheckContext
.RelocationsStripped
) {
781 // If the image does not contain relocations and it is a runtime driver
782 // then return an error.
784 if (CheckContext
.ImageType
== EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER
) {
785 ImageContext
->ImageError
= IMAGE_ERROR_INVALID_SUBSYSTEM
;
786 return RETURN_LOAD_ERROR
;
789 // If the image does not contain relocations, and the requested load address
790 // is not the linked address, then return an error.
792 if (CheckContext
.ImageAddress
!= ImageContext
->ImageAddress
) {
793 ImageContext
->ImageError
= IMAGE_ERROR_INVALID_IMAGE_ADDRESS
;
794 return RETURN_INVALID_PARAMETER
;
798 // Make sure the allocated space has the proper section alignment
800 if (!(ImageContext
->IsTeImage
)) {
801 if ((ImageContext
->ImageAddress
& (CheckContext
.SectionAlignment
- 1)) != 0) {
802 ImageContext
->ImageError
= IMAGE_ERROR_INVALID_SECTION_ALIGNMENT
;
803 return RETURN_INVALID_PARAMETER
;
807 // Read the entire PE/COFF or TE header into memory
809 if (!(ImageContext
->IsTeImage
)) {
810 Status
= ImageContext
->ImageRead (
811 ImageContext
->Handle
,
813 &ImageContext
->SizeOfHeaders
,
814 (VOID
*) (UINTN
) ImageContext
->ImageAddress
817 PeHdr
= (EFI_IMAGE_NT_HEADERS
*)
818 ((UINTN
)ImageContext
->ImageAddress
+ ImageContext
->PeCoffHeaderOffset
);
820 FirstSection
= (EFI_IMAGE_SECTION_HEADER
*) (
821 (UINTN
)ImageContext
->ImageAddress
+
822 ImageContext
->PeCoffHeaderOffset
+
824 sizeof(EFI_IMAGE_FILE_HEADER
) +
825 PeHdr
->FileHeader
.SizeOfOptionalHeader
827 NumberOfSections
= (UINTN
) (PeHdr
->FileHeader
.NumberOfSections
);
829 Status
= ImageContext
->ImageRead (
830 ImageContext
->Handle
,
832 &ImageContext
->SizeOfHeaders
,
833 (void *) (UINTN
) ImageContext
->ImageAddress
836 TeHdr
= (EFI_TE_IMAGE_HEADER
*) (UINTN
) (ImageContext
->ImageAddress
);
838 FirstSection
= (EFI_IMAGE_SECTION_HEADER
*) (
839 (UINTN
)ImageContext
->ImageAddress
+
840 sizeof(EFI_TE_IMAGE_HEADER
)
842 NumberOfSections
= (UINTN
) (TeHdr
->NumberOfSections
);
846 if (RETURN_ERROR (Status
)) {
847 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
848 return RETURN_LOAD_ERROR
;
852 // Load each section of the image
854 Section
= FirstSection
;
855 for (Index
= 0, MaxEnd
= NULL
; Index
< NumberOfSections
; Index
++) {
858 // Compute sections address
860 Base
= PeCoffLoaderImageAddress (ImageContext
, Section
->VirtualAddress
);
861 End
= PeCoffLoaderImageAddress (
863 Section
->VirtualAddress
+ Section
->Misc
.VirtualSize
- 1
865 if (ImageContext
->IsTeImage
) {
866 Base
= (CHAR8
*) ((UINTN
) Base
+ sizeof (EFI_TE_IMAGE_HEADER
) - (UINTN
) TeHdr
->StrippedSize
);
867 End
= (CHAR8
*) ((UINTN
) End
+ sizeof (EFI_TE_IMAGE_HEADER
) - (UINTN
) TeHdr
->StrippedSize
);
874 // If the base start or end address resolved to 0, then fail.
876 if ((Base
== NULL
) || (End
== NULL
)) {
877 ImageContext
->ImageError
= IMAGE_ERROR_SECTION_NOT_LOADED
;
878 return RETURN_LOAD_ERROR
;
884 Size
= (UINTN
) Section
->Misc
.VirtualSize
;
885 if ((Size
== 0) || (Size
> Section
->SizeOfRawData
)) {
886 Size
= (UINTN
) Section
->SizeOfRawData
;
889 if (Section
->SizeOfRawData
) {
890 if (!(ImageContext
->IsTeImage
)) {
891 Status
= ImageContext
->ImageRead (
892 ImageContext
->Handle
,
893 Section
->PointerToRawData
,
898 Status
= ImageContext
->ImageRead (
899 ImageContext
->Handle
,
900 Section
->PointerToRawData
+ sizeof (EFI_TE_IMAGE_HEADER
) - (UINTN
) TeHdr
->StrippedSize
,
906 if (RETURN_ERROR (Status
)) {
907 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
913 // If raw size is less then virt size, zero fill the remaining
916 if (Size
< Section
->Misc
.VirtualSize
) {
917 ZeroMem (Base
+ Size
, Section
->Misc
.VirtualSize
- Size
);
927 // Get image's entry point
929 if (!(ImageContext
->IsTeImage
)) {
930 ImageContext
->EntryPoint
= (PHYSICAL_ADDRESS
) (UINTN
) PeCoffLoaderImageAddress (
932 PeHdr
->OptionalHeader
.AddressOfEntryPoint
935 ImageContext
->EntryPoint
= (PHYSICAL_ADDRESS
) (
936 (UINTN
)ImageContext
->ImageAddress
+
937 (UINTN
)TeHdr
->AddressOfEntryPoint
+
938 (UINTN
)sizeof(EFI_TE_IMAGE_HEADER
) -
939 (UINTN
) TeHdr
->StrippedSize
944 // Determine the size of the fixup data
946 // Per the PE/COFF spec, you can't assume that a given data directory
947 // is present in the image. You have to check the NumberOfRvaAndSizes in
948 // the optional header to verify a desired directory entry is there.
950 if (!(ImageContext
->IsTeImage
)) {
951 if (PeHdr
->OptionalHeader
.NumberOfRvaAndSizes
> EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
) {
952 DirectoryEntry
= (EFI_IMAGE_DATA_DIRECTORY
*)
953 &PeHdr
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
];
954 ImageContext
->FixupDataSize
= DirectoryEntry
->Size
/ sizeof (UINT16
) * sizeof (UINTN
);
956 ImageContext
->FixupDataSize
= 0;
959 DirectoryEntry
= &TeHdr
->DataDirectory
[0];
960 ImageContext
->FixupDataSize
= DirectoryEntry
->Size
/ sizeof (UINT16
) * sizeof (UINTN
);
963 // Consumer must allocate a buffer for the relocation fixup log.
964 // Only used for runtime drivers.
966 ImageContext
->FixupData
= NULL
;
969 // Load the Codeview info if present
971 if (ImageContext
->DebugDirectoryEntryRva
!= 0) {
972 if (!(ImageContext
->IsTeImage
)) {
973 DebugEntry
= PeCoffLoaderImageAddress (
975 ImageContext
->DebugDirectoryEntryRva
978 DebugEntry
= (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
*)(UINTN
)(
979 ImageContext
->ImageAddress
+
980 ImageContext
->DebugDirectoryEntryRva
+
981 sizeof(EFI_TE_IMAGE_HEADER
) -
986 if (DebugEntry
!= NULL
) {
987 TempDebugEntryRva
= DebugEntry
->RVA
;
988 if (DebugEntry
->RVA
== 0 && DebugEntry
->FileOffset
!= 0) {
990 if ((UINTN
) Section
->SizeOfRawData
< Section
->Misc
.VirtualSize
) {
991 TempDebugEntryRva
= Section
->VirtualAddress
+ Section
->Misc
.VirtualSize
;
993 TempDebugEntryRva
= Section
->VirtualAddress
+ Section
->SizeOfRawData
;
997 if (TempDebugEntryRva
!= 0) {
998 if (!(ImageContext
->IsTeImage
)) {
999 ImageContext
->CodeView
= PeCoffLoaderImageAddress (ImageContext
, TempDebugEntryRva
);
1001 ImageContext
->CodeView
= (VOID
*)(
1002 (UINTN
)ImageContext
->ImageAddress
+
1003 (UINTN
)TempDebugEntryRva
+
1004 (UINTN
)sizeof(EFI_TE_IMAGE_HEADER
) -
1005 (UINTN
) TeHdr
->StrippedSize
1009 if (ImageContext
->CodeView
== NULL
) {
1010 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
1011 return RETURN_LOAD_ERROR
;
1014 if (DebugEntry
->RVA
== 0) {
1015 Size
= DebugEntry
->SizeOfData
;
1016 if (!(ImageContext
->IsTeImage
)) {
1017 Status
= ImageContext
->ImageRead (
1018 ImageContext
->Handle
,
1019 DebugEntry
->FileOffset
,
1021 ImageContext
->CodeView
1024 Status
= ImageContext
->ImageRead (
1025 ImageContext
->Handle
,
1026 DebugEntry
->FileOffset
+ sizeof (EFI_TE_IMAGE_HEADER
) - TeHdr
->StrippedSize
,
1028 ImageContext
->CodeView
1031 // Should we apply fix up to this field according to the size difference between PE and TE?
1032 // Because now we maintain TE header fields unfixed, this field will also remain as they are
1033 // in original PE image.
1037 if (RETURN_ERROR (Status
)) {
1038 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
1039 return RETURN_LOAD_ERROR
;
1042 DebugEntry
->RVA
= TempDebugEntryRva
;
1045 switch (*(UINT32
*) ImageContext
->CodeView
) {
1046 case CODEVIEW_SIGNATURE_NB10
:
1047 ImageContext
->PdbPointer
= (CHAR8
*) ImageContext
->CodeView
+ sizeof (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY
);
1050 case CODEVIEW_SIGNATURE_RSDS
:
1051 ImageContext
->PdbPointer
= (CHAR8
*) ImageContext
->CodeView
+ sizeof (EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY
);