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 #include <Common/UefiBaseTypes.h>
26 #include <Common/EfiImage.h>
27 #include <Library/PeCoffLib.h>
31 PeCoffLoaderGetPeHeader (
32 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
,
33 OUT EFI_IMAGE_NT_HEADERS
*PeHdr
,
34 OUT EFI_TE_IMAGE_HEADER
*TeHdr
39 PeCoffLoaderCheckImageType (
40 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
,
41 IN EFI_IMAGE_NT_HEADERS
*PeHdr
,
42 IN EFI_TE_IMAGE_HEADER
*TeHdr
47 PeCoffLoaderImageAddress (
48 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
,
55 PeCoffLoaderGetPeHeader (
56 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
,
57 OUT EFI_IMAGE_NT_HEADERS
*PeHdr
,
58 OUT EFI_TE_IMAGE_HEADER
*TeHdr
64 Retrieves the PE or TE Header from a PE/COFF or TE image
68 ImageContext - The context of the image being loaded
70 PeHdr - The buffer in which to return the PE header
72 TeHdr - The buffer in which to return the TE header
76 RETURN_SUCCESS if the PE or TE Header is read,
77 Otherwise, the error status from reading the PE/COFF or TE image using the ImageRead function.
82 EFI_IMAGE_DOS_HEADER DosHdr
;
85 ImageContext
->IsTeImage
= FALSE
;
87 // Read the DOS image headers
89 Size
= sizeof (EFI_IMAGE_DOS_HEADER
);
90 Status
= ImageContext
->ImageRead (
96 if (RETURN_ERROR (Status
)) {
97 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
101 ImageContext
->PeCoffHeaderOffset
= 0;
102 if (DosHdr
.e_magic
== EFI_IMAGE_DOS_SIGNATURE
) {
104 // DOS image header is present, so read the PE header after the DOS image header
106 ImageContext
->PeCoffHeaderOffset
= DosHdr
.e_lfanew
;
109 // Read the PE/COFF Header
111 Size
= sizeof (EFI_IMAGE_NT_HEADERS
);
112 Status
= ImageContext
->ImageRead (
113 ImageContext
->Handle
,
114 ImageContext
->PeCoffHeaderOffset
,
118 if (RETURN_ERROR (Status
)) {
119 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
123 // Check the PE/COFF Header Signature. If not, then try to read a TE header
125 if (PeHdr
->Signature
!= EFI_IMAGE_NT_SIGNATURE
) {
126 Size
= sizeof (EFI_TE_IMAGE_HEADER
);
127 Status
= ImageContext
->ImageRead (
128 ImageContext
->Handle
,
133 if (TeHdr
->Signature
!= EFI_TE_IMAGE_HEADER_SIGNATURE
) {
134 return RETURN_UNSUPPORTED
;
137 ImageContext
->IsTeImage
= TRUE
;
140 return RETURN_SUCCESS
;
145 PeCoffLoaderCheckImageType (
146 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
,
147 IN EFI_IMAGE_NT_HEADERS
*PeHdr
,
148 IN EFI_TE_IMAGE_HEADER
*TeHdr
154 Checks the PE or TE header of a PE/COFF or TE image to determine if it supported
158 ImageContext - The context of the image being loaded
160 PeHdr - The buffer in which to return the PE header
162 TeHdr - The buffer in which to return the TE header
166 RETURN_SUCCESS if the PE/COFF or TE image is supported
167 RETURN_UNSUPPORTED of the PE/COFF or TE image is not supported.
172 // See if the machine type is supported. We support a native machine type (IA-32/Itanium-based)
173 // and the machine type for the Virtual Machine.
175 if (ImageContext
->IsTeImage
== FALSE
) {
176 ImageContext
->Machine
= PeHdr
->FileHeader
.Machine
;
178 ImageContext
->Machine
= TeHdr
->Machine
;
181 if (!(EFI_IMAGE_MACHINE_TYPE_SUPPORTED (ImageContext
->Machine
))) {
182 ImageContext
->ImageError
= IMAGE_ERROR_INVALID_MACHINE_TYPE
;
183 return RETURN_UNSUPPORTED
;
187 // See if the image type is supported. We support EFI Applications,
188 // EFI Boot Service Drivers, and EFI Runtime Drivers.
190 if (ImageContext
->IsTeImage
== FALSE
) {
191 ImageContext
->ImageType
= PeHdr
->OptionalHeader
.Subsystem
;
193 ImageContext
->ImageType
= (UINT16
) (TeHdr
->Subsystem
);
197 return RETURN_SUCCESS
;
202 PeCoffLoaderGetImageInfo (
203 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
209 Retrieves information on a PE/COFF image
213 This - Calling context
214 ImageContext - The context of the image being loaded
218 RETURN_SUCCESS - The information on the PE/COFF image was collected.
219 RETURN_INVALID_PARAMETER - ImageContext is NULL.
220 RETURN_UNSUPPORTED - The PE/COFF image is not supported.
221 Otherwise - The error status from reading the PE/COFF image using the
222 ImageContext->ImageRead() function
226 RETURN_STATUS Status
;
227 EFI_IMAGE_NT_HEADERS PeHdr
;
228 EFI_TE_IMAGE_HEADER TeHdr
;
229 EFI_IMAGE_DATA_DIRECTORY
*DebugDirectoryEntry
;
232 UINTN DebugDirectoryEntryRva
;
233 UINTN DebugDirectoryEntryFileOffset
;
234 UINTN SectionHeaderOffset
;
235 EFI_IMAGE_SECTION_HEADER SectionHeader
;
236 EFI_IMAGE_DEBUG_DIRECTORY_ENTRY DebugEntry
;
238 if (NULL
== ImageContext
) {
239 return RETURN_INVALID_PARAMETER
;
244 ImageContext
->ImageError
= IMAGE_ERROR_SUCCESS
;
246 Status
= PeCoffLoaderGetPeHeader (ImageContext
, &PeHdr
, &TeHdr
);
247 if (RETURN_ERROR (Status
)) {
251 // Verify machine type
253 Status
= PeCoffLoaderCheckImageType (ImageContext
, &PeHdr
, &TeHdr
);
254 if (RETURN_ERROR (Status
)) {
258 // Retrieve the base address of the image
260 if (!(ImageContext
->IsTeImage
)) {
261 ImageContext
->ImageAddress
= PeHdr
.OptionalHeader
.ImageBase
;
263 ImageContext
->ImageAddress
= (PHYSICAL_ADDRESS
) (TeHdr
.ImageBase
+ sizeof (EFI_TE_IMAGE_HEADER
) - TeHdr
.StrippedSize
);
266 // Initialize the alternate destination address to 0 indicating that it
267 // should not be used.
269 ImageContext
->DestinationAddress
= 0;
272 // Initialize the codeview pointer.
274 ImageContext
->CodeView
= NULL
;
275 ImageContext
->PdbPointer
= NULL
;
278 // Three cases with regards to relocations:
279 // - Image has base relocs, RELOCS_STRIPPED==0 => image is relocatable
280 // - Image has no base relocs, RELOCS_STRIPPED==1 => Image is not relocatable
281 // - Image has no base relocs, RELOCS_STRIPPED==0 => Image is relocatable but
282 // has no base relocs to apply
283 // Obviously having base relocations with RELOCS_STRIPPED==1 is invalid.
285 // Look at the file header to determine if relocations have been stripped, and
286 // save this info in the image context for later use.
288 if ((!(ImageContext
->IsTeImage
)) && ((PeHdr
.FileHeader
.Characteristics
& EFI_IMAGE_FILE_RELOCS_STRIPPED
) != 0)) {
289 ImageContext
->RelocationsStripped
= TRUE
;
291 ImageContext
->RelocationsStripped
= FALSE
;
294 if (!(ImageContext
->IsTeImage
)) {
295 ImageContext
->ImageSize
= (UINT64
) PeHdr
.OptionalHeader
.SizeOfImage
;
296 ImageContext
->SectionAlignment
= PeHdr
.OptionalHeader
.SectionAlignment
;
297 ImageContext
->SizeOfHeaders
= PeHdr
.OptionalHeader
.SizeOfHeaders
;
300 // Modify ImageSize to contain .PDB file name if required and initialize
303 if (PeHdr
.OptionalHeader
.NumberOfRvaAndSizes
> EFI_IMAGE_DIRECTORY_ENTRY_DEBUG
) {
304 DebugDirectoryEntry
= (EFI_IMAGE_DATA_DIRECTORY
*) &(PeHdr
.OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG
]);
306 DebugDirectoryEntryRva
= DebugDirectoryEntry
->VirtualAddress
;
309 // Determine the file offset of the debug directory... This means we walk
310 // the sections to find which section contains the RVA of the debug
313 DebugDirectoryEntryFileOffset
= 0;
315 SectionHeaderOffset
= (UINTN
)(
316 ImageContext
->PeCoffHeaderOffset
+
318 sizeof (EFI_IMAGE_FILE_HEADER
) +
319 PeHdr
.FileHeader
.SizeOfOptionalHeader
322 for (Index
= 0; Index
< PeHdr
.FileHeader
.NumberOfSections
; Index
++) {
324 // Read section header from file
326 Size
= sizeof (EFI_IMAGE_SECTION_HEADER
);
327 Status
= ImageContext
->ImageRead (
328 ImageContext
->Handle
,
333 if (RETURN_ERROR (Status
)) {
334 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
338 if (DebugDirectoryEntryRva
>= SectionHeader
.VirtualAddress
&&
339 DebugDirectoryEntryRva
< SectionHeader
.VirtualAddress
+ SectionHeader
.Misc
.VirtualSize
) {
340 DebugDirectoryEntryFileOffset
=
341 DebugDirectoryEntryRva
- SectionHeader
.VirtualAddress
+ SectionHeader
.PointerToRawData
;
345 SectionHeaderOffset
+= sizeof (EFI_IMAGE_SECTION_HEADER
);
348 if (DebugDirectoryEntryFileOffset
!= 0) {
349 for (Index
= 0; Index
< (DebugDirectoryEntry
->Size
); Index
+= Size
) {
351 // Read next debug directory entry
353 Size
= sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
);
354 Status
= ImageContext
->ImageRead (
355 ImageContext
->Handle
,
356 DebugDirectoryEntryFileOffset
,
360 if (RETURN_ERROR (Status
)) {
361 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
365 if (DebugEntry
.Type
== EFI_IMAGE_DEBUG_TYPE_CODEVIEW
) {
366 ImageContext
->DebugDirectoryEntryRva
= (UINT32
) (DebugDirectoryEntryRva
+ Index
);
367 if (DebugEntry
.RVA
== 0 && DebugEntry
.FileOffset
!= 0) {
368 ImageContext
->ImageSize
+= DebugEntry
.SizeOfData
;
371 return RETURN_SUCCESS
;
377 ImageContext
->ImageSize
= 0;
378 ImageContext
->SectionAlignment
= 4096;
379 ImageContext
->SizeOfHeaders
= sizeof (EFI_TE_IMAGE_HEADER
) + (UINTN
) TeHdr
.BaseOfCode
- (UINTN
) TeHdr
.StrippedSize
;
381 DebugDirectoryEntry
= &TeHdr
.DataDirectory
[1];
382 DebugDirectoryEntryRva
= DebugDirectoryEntry
->VirtualAddress
;
383 SectionHeaderOffset
= (UINTN
) (sizeof (EFI_TE_IMAGE_HEADER
));
385 DebugDirectoryEntryFileOffset
= 0;
387 for (Index
= 0; Index
< TeHdr
.NumberOfSections
;) {
389 // Read section header from file
391 Size
= sizeof (EFI_IMAGE_SECTION_HEADER
);
392 Status
= ImageContext
->ImageRead (
393 ImageContext
->Handle
,
398 if (RETURN_ERROR (Status
)) {
399 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
403 if (DebugDirectoryEntryRva
>= SectionHeader
.VirtualAddress
&&
404 DebugDirectoryEntryRva
< SectionHeader
.VirtualAddress
+ SectionHeader
.Misc
.VirtualSize
) {
405 DebugDirectoryEntryFileOffset
= DebugDirectoryEntryRva
-
406 SectionHeader
.VirtualAddress
+
407 SectionHeader
.PointerToRawData
+
408 sizeof (EFI_TE_IMAGE_HEADER
) -
412 // File offset of the debug directory was found, if this is not the last
413 // section, then skip to the last section for calculating the image size.
415 if (Index
< (UINTN
) TeHdr
.NumberOfSections
- 1) {
416 SectionHeaderOffset
+= (TeHdr
.NumberOfSections
- 1 - Index
) * sizeof (EFI_IMAGE_SECTION_HEADER
);
417 Index
= TeHdr
.NumberOfSections
- 1;
423 // In Te image header there is not a field to describe the ImageSize.
424 // Actually, the ImageSize equals the RVA plus the VirtualSize of
425 // the last section mapped into memory (Must be rounded up to
426 // a mulitple of Section Alignment). Per the PE/COFF specification, the
427 // section headers in the Section Table must appear in order of the RVA
428 // values for the corresponding sections. So the ImageSize can be determined
429 // by the RVA and the VirtualSize of the last section header in the
432 if ((++Index
) == (UINTN
) TeHdr
.NumberOfSections
) {
433 ImageContext
->ImageSize
= (SectionHeader
.VirtualAddress
+ SectionHeader
.Misc
.VirtualSize
+
434 ImageContext
->SectionAlignment
- 1) & ~(ImageContext
->SectionAlignment
- 1);
437 SectionHeaderOffset
+= sizeof (EFI_IMAGE_SECTION_HEADER
);
440 if (DebugDirectoryEntryFileOffset
!= 0) {
441 for (Index
= 0; Index
< (DebugDirectoryEntry
->Size
); Index
+= Size
) {
443 // Read next debug directory entry
445 Size
= sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
);
446 Status
= ImageContext
->ImageRead (
447 ImageContext
->Handle
,
448 DebugDirectoryEntryFileOffset
,
452 if (RETURN_ERROR (Status
)) {
453 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
457 if (DebugEntry
.Type
== EFI_IMAGE_DEBUG_TYPE_CODEVIEW
) {
458 ImageContext
->DebugDirectoryEntryRva
= (UINT32
) (DebugDirectoryEntryRva
+ Index
);
459 return RETURN_SUCCESS
;
465 return RETURN_SUCCESS
;
470 PeCoffLoaderImageAddress (
471 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
,
478 Converts an image address to the loaded address
482 ImageContext - The context of the image being loaded
484 Address - The address to be converted to the loaded address
488 NULL if the address can not be converted, otherwise, the converted address
492 if (Address
>= ImageContext
->ImageSize
) {
493 ImageContext
->ImageError
= IMAGE_ERROR_INVALID_IMAGE_ADDRESS
;
497 return (CHAR8
*) ((UINTN
) ImageContext
->ImageAddress
+ Address
);
502 PeCoffLoaderRelocateImage (
503 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
509 Relocates a PE/COFF image in memory
513 This - Calling context
515 ImageContext - Contains information on the loaded image to relocate
519 RETURN_SUCCESS if the PE/COFF image was relocated
520 RETURN_LOAD_ERROR if the image is not a valid PE/COFF image
521 RETURN_UNSUPPORTED not support
525 RETURN_STATUS Status
;
526 EFI_IMAGE_NT_HEADERS
*PeHdr
;
527 EFI_TE_IMAGE_HEADER
*TeHdr
;
528 EFI_IMAGE_DATA_DIRECTORY
*RelocDir
;
530 EFI_IMAGE_BASE_RELOCATION
*RelocBase
;
531 EFI_IMAGE_BASE_RELOCATION
*RelocBaseEnd
;
539 PHYSICAL_ADDRESS BaseAddress
;
546 ImageContext
->ImageError
= IMAGE_ERROR_SUCCESS
;
549 // If there are no relocation entries, then we are done
551 if (ImageContext
->RelocationsStripped
) {
552 return RETURN_SUCCESS
;
556 // If the destination address is not 0, use that rather than the
557 // image address as the relocation target.
559 if (ImageContext
->DestinationAddress
) {
560 BaseAddress
= ImageContext
->DestinationAddress
;
562 BaseAddress
= ImageContext
->ImageAddress
;
565 if (!(ImageContext
->IsTeImage
)) {
566 PeHdr
= (EFI_IMAGE_NT_HEADERS
*)((UINTN
)ImageContext
->ImageAddress
+
567 ImageContext
->PeCoffHeaderOffset
);
568 Adjust
= (UINT64
) BaseAddress
- PeHdr
->OptionalHeader
.ImageBase
;
569 PeHdr
->OptionalHeader
.ImageBase
= (UINTN
) BaseAddress
;
572 // Find the relocation block
574 // Per the PE/COFF spec, you can't assume that a given data directory
575 // is present in the image. You have to check the NumberOfRvaAndSizes in
576 // the optional header to verify a desired directory entry is there.
578 if (PeHdr
->OptionalHeader
.NumberOfRvaAndSizes
> EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
) {
579 RelocDir
= &PeHdr
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
];
580 RelocBase
= PeCoffLoaderImageAddress (ImageContext
, RelocDir
->VirtualAddress
);
581 RelocBaseEnd
= PeCoffLoaderImageAddress (
583 RelocDir
->VirtualAddress
+ RelocDir
->Size
- 1
587 // Set base and end to bypass processing below.
589 RelocBase
= RelocBaseEnd
= 0;
592 TeHdr
= (EFI_TE_IMAGE_HEADER
*) (UINTN
) (ImageContext
->ImageAddress
);
593 Adjust
= (UINT64
) (BaseAddress
- TeHdr
->ImageBase
);
594 TeHdr
->ImageBase
= (UINT64
) (BaseAddress
);
597 // Find the relocation block
599 RelocDir
= &TeHdr
->DataDirectory
[0];
600 RelocBase
= (EFI_IMAGE_BASE_RELOCATION
*)(UINTN
)(
601 ImageContext
->ImageAddress
+
602 RelocDir
->VirtualAddress
+
603 sizeof(EFI_TE_IMAGE_HEADER
) -
606 RelocBaseEnd
= (EFI_IMAGE_BASE_RELOCATION
*) ((UINTN
) RelocBase
+ (UINTN
) RelocDir
->Size
- 1);
610 // Run the relocation information and apply the fixups
612 FixupData
= ImageContext
->FixupData
;
613 while (RelocBase
< RelocBaseEnd
) {
615 Reloc
= (UINT16
*) ((CHAR8
*) RelocBase
+ sizeof (EFI_IMAGE_BASE_RELOCATION
));
616 RelocEnd
= (UINT16
*) ((CHAR8
*) RelocBase
+ RelocBase
->SizeOfBlock
);
617 if (!(ImageContext
->IsTeImage
)) {
618 FixupBase
= PeCoffLoaderImageAddress (ImageContext
, RelocBase
->VirtualAddress
);
620 FixupBase
= (CHAR8
*)(UINTN
)(ImageContext
->ImageAddress
+
621 RelocBase
->VirtualAddress
+
622 sizeof(EFI_TE_IMAGE_HEADER
) -
627 if ((CHAR8
*) RelocEnd
< (CHAR8
*) ((UINTN
) ImageContext
->ImageAddress
) ||
628 (CHAR8
*) RelocEnd
> (CHAR8
*)((UINTN
)ImageContext
->ImageAddress
+
629 (UINTN
)ImageContext
->ImageSize
)) {
630 ImageContext
->ImageError
= IMAGE_ERROR_FAILED_RELOCATION
;
631 return RETURN_LOAD_ERROR
;
635 // Run this relocation record
637 while (Reloc
< RelocEnd
) {
639 Fixup
= FixupBase
+ (*Reloc
& 0xFFF);
640 switch ((*Reloc
) >> 12) {
641 case EFI_IMAGE_REL_BASED_ABSOLUTE
:
644 case EFI_IMAGE_REL_BASED_HIGH
:
645 F16
= (UINT16
*) Fixup
;
646 *F16
= (UINT16
) (*F16
+ ((UINT16
) ((UINT32
) Adjust
>> 16)));
647 if (FixupData
!= NULL
) {
648 *(UINT16
*) FixupData
= *F16
;
649 FixupData
= FixupData
+ sizeof (UINT16
);
653 case EFI_IMAGE_REL_BASED_LOW
:
654 F16
= (UINT16
*) Fixup
;
655 *F16
= (UINT16
) (*F16
+ (UINT16
) Adjust
);
656 if (FixupData
!= NULL
) {
657 *(UINT16
*) FixupData
= *F16
;
658 FixupData
= FixupData
+ sizeof (UINT16
);
662 case EFI_IMAGE_REL_BASED_HIGHLOW
:
663 F32
= (UINT32
*) Fixup
;
664 *F32
= *F32
+ (UINT32
) Adjust
;
665 if (FixupData
!= NULL
) {
666 FixupData
= ALIGN_POINTER (FixupData
, sizeof (UINT32
));
667 *(UINT32
*) FixupData
= *F32
;
668 FixupData
= FixupData
+ sizeof (UINT32
);
672 case EFI_IMAGE_REL_BASED_HIGHADJ
:
674 // Return the same EFI_UNSUPPORTED return code as
675 // PeCoffLoaderRelocateImageEx() returns if it does not recognize
676 // the relocation type.
678 ImageContext
->ImageError
= IMAGE_ERROR_FAILED_RELOCATION
;
679 return RETURN_UNSUPPORTED
;
682 Status
= PeCoffLoaderRelocateImageEx (Reloc
, Fixup
, &FixupData
, Adjust
);
683 if (RETURN_ERROR (Status
)) {
684 ImageContext
->ImageError
= IMAGE_ERROR_FAILED_RELOCATION
;
690 // Next relocation record
698 RelocBase
= (EFI_IMAGE_BASE_RELOCATION
*) RelocEnd
;
701 return RETURN_SUCCESS
;
706 PeCoffLoaderLoadImage (
707 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
713 Loads a PE/COFF image into memory
717 This - Calling context
719 ImageContext - Contains information on image to load into memory
723 RETURN_SUCCESS if the PE/COFF image was loaded
724 RETURN_BUFFER_TOO_SMALL if the caller did not provide a large enough buffer
725 RETURN_LOAD_ERROR if the image is a runtime driver with no relocations
726 RETURN_INVALID_PARAMETER if the image address is invalid
730 RETURN_STATUS Status
;
731 EFI_IMAGE_NT_HEADERS
*PeHdr
;
732 EFI_TE_IMAGE_HEADER
*TeHdr
;
733 PE_COFF_LOADER_IMAGE_CONTEXT CheckContext
;
734 EFI_IMAGE_SECTION_HEADER
*FirstSection
;
735 EFI_IMAGE_SECTION_HEADER
*Section
;
736 UINTN NumberOfSections
;
741 EFI_IMAGE_DATA_DIRECTORY
*DirectoryEntry
;
742 EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
*DebugEntry
;
744 UINT32 TempDebugEntryRva
;
751 ImageContext
->ImageError
= IMAGE_ERROR_SUCCESS
;
754 // Copy the provided context info into our local version, get what we
755 // can from the original image, and then use that to make sure everything
758 CopyMem (&CheckContext
, ImageContext
, sizeof (PE_COFF_LOADER_IMAGE_CONTEXT
));
760 Status
= PeCoffLoaderGetImageInfo (&CheckContext
);
761 if (RETURN_ERROR (Status
)) {
766 // Make sure there is enough allocated space for the image being loaded
768 if (ImageContext
->ImageSize
< CheckContext
.ImageSize
) {
769 ImageContext
->ImageError
= IMAGE_ERROR_INVALID_IMAGE_SIZE
;
770 return RETURN_BUFFER_TOO_SMALL
;
774 // If there's no relocations, then make sure it's not a runtime driver,
775 // and that it's being loaded at the linked address.
777 if (CheckContext
.RelocationsStripped
) {
779 // If the image does not contain relocations and it is a runtime driver
780 // then return an error.
782 if (CheckContext
.ImageType
== EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER
) {
783 ImageContext
->ImageError
= IMAGE_ERROR_INVALID_SUBSYSTEM
;
784 return RETURN_LOAD_ERROR
;
787 // If the image does not contain relocations, and the requested load address
788 // is not the linked address, then return an error.
790 if (CheckContext
.ImageAddress
!= ImageContext
->ImageAddress
) {
791 ImageContext
->ImageError
= IMAGE_ERROR_INVALID_IMAGE_ADDRESS
;
792 return RETURN_INVALID_PARAMETER
;
796 // Make sure the allocated space has the proper section alignment
798 if (!(ImageContext
->IsTeImage
)) {
799 if ((ImageContext
->ImageAddress
& (CheckContext
.SectionAlignment
- 1)) != 0) {
800 ImageContext
->ImageError
= IMAGE_ERROR_INVALID_SECTION_ALIGNMENT
;
801 return RETURN_INVALID_PARAMETER
;
805 // Read the entire PE/COFF or TE header into memory
807 if (!(ImageContext
->IsTeImage
)) {
808 Status
= ImageContext
->ImageRead (
809 ImageContext
->Handle
,
811 &ImageContext
->SizeOfHeaders
,
812 (VOID
*) (UINTN
) ImageContext
->ImageAddress
815 PeHdr
= (EFI_IMAGE_NT_HEADERS
*)
816 ((UINTN
)ImageContext
->ImageAddress
+ ImageContext
->PeCoffHeaderOffset
);
818 FirstSection
= (EFI_IMAGE_SECTION_HEADER
*) (
819 (UINTN
)ImageContext
->ImageAddress
+
820 ImageContext
->PeCoffHeaderOffset
+
822 sizeof(EFI_IMAGE_FILE_HEADER
) +
823 PeHdr
->FileHeader
.SizeOfOptionalHeader
825 NumberOfSections
= (UINTN
) (PeHdr
->FileHeader
.NumberOfSections
);
827 Status
= ImageContext
->ImageRead (
828 ImageContext
->Handle
,
830 &ImageContext
->SizeOfHeaders
,
831 (void *) (UINTN
) ImageContext
->ImageAddress
834 TeHdr
= (EFI_TE_IMAGE_HEADER
*) (UINTN
) (ImageContext
->ImageAddress
);
836 FirstSection
= (EFI_IMAGE_SECTION_HEADER
*) (
837 (UINTN
)ImageContext
->ImageAddress
+
838 sizeof(EFI_TE_IMAGE_HEADER
)
840 NumberOfSections
= (UINTN
) (TeHdr
->NumberOfSections
);
844 if (RETURN_ERROR (Status
)) {
845 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
846 return RETURN_LOAD_ERROR
;
850 // Load each section of the image
852 Section
= FirstSection
;
853 for (Index
= 0, MaxEnd
= NULL
; Index
< NumberOfSections
; Index
++) {
856 // Compute sections address
858 Base
= PeCoffLoaderImageAddress (ImageContext
, Section
->VirtualAddress
);
859 End
= PeCoffLoaderImageAddress (
861 Section
->VirtualAddress
+ Section
->Misc
.VirtualSize
- 1
863 if (ImageContext
->IsTeImage
) {
864 Base
= (CHAR8
*) ((UINTN
) Base
+ sizeof (EFI_TE_IMAGE_HEADER
) - (UINTN
) TeHdr
->StrippedSize
);
865 End
= (CHAR8
*) ((UINTN
) End
+ sizeof (EFI_TE_IMAGE_HEADER
) - (UINTN
) TeHdr
->StrippedSize
);
872 // If the base start or end address resolved to 0, then fail.
874 if ((Base
== NULL
) || (End
== NULL
)) {
875 ImageContext
->ImageError
= IMAGE_ERROR_SECTION_NOT_LOADED
;
876 return RETURN_LOAD_ERROR
;
882 Size
= (UINTN
) Section
->Misc
.VirtualSize
;
883 if ((Size
== 0) || (Size
> Section
->SizeOfRawData
)) {
884 Size
= (UINTN
) Section
->SizeOfRawData
;
887 if (Section
->SizeOfRawData
) {
888 if (!(ImageContext
->IsTeImage
)) {
889 Status
= ImageContext
->ImageRead (
890 ImageContext
->Handle
,
891 Section
->PointerToRawData
,
896 Status
= ImageContext
->ImageRead (
897 ImageContext
->Handle
,
898 Section
->PointerToRawData
+ sizeof (EFI_TE_IMAGE_HEADER
) - (UINTN
) TeHdr
->StrippedSize
,
904 if (RETURN_ERROR (Status
)) {
905 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
911 // If raw size is less then virt size, zero fill the remaining
914 if (Size
< Section
->Misc
.VirtualSize
) {
915 ZeroMem (Base
+ Size
, Section
->Misc
.VirtualSize
- Size
);
925 // Get image's entry point
927 if (!(ImageContext
->IsTeImage
)) {
928 ImageContext
->EntryPoint
= (PHYSICAL_ADDRESS
) (UINTN
) PeCoffLoaderImageAddress (
930 PeHdr
->OptionalHeader
.AddressOfEntryPoint
933 ImageContext
->EntryPoint
= (PHYSICAL_ADDRESS
) (
934 (UINTN
)ImageContext
->ImageAddress
+
935 (UINTN
)TeHdr
->AddressOfEntryPoint
+
936 (UINTN
)sizeof(EFI_TE_IMAGE_HEADER
) -
937 (UINTN
) TeHdr
->StrippedSize
942 // Determine the size of the fixup data
944 // Per the PE/COFF spec, you can't assume that a given data directory
945 // is present in the image. You have to check the NumberOfRvaAndSizes in
946 // the optional header to verify a desired directory entry is there.
948 if (!(ImageContext
->IsTeImage
)) {
949 if (PeHdr
->OptionalHeader
.NumberOfRvaAndSizes
> EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
) {
950 DirectoryEntry
= (EFI_IMAGE_DATA_DIRECTORY
*)
951 &PeHdr
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
];
952 ImageContext
->FixupDataSize
= DirectoryEntry
->Size
/ sizeof (UINT16
) * sizeof (UINTN
);
954 ImageContext
->FixupDataSize
= 0;
957 DirectoryEntry
= &TeHdr
->DataDirectory
[0];
958 ImageContext
->FixupDataSize
= DirectoryEntry
->Size
/ sizeof (UINT16
) * sizeof (UINTN
);
961 // Consumer must allocate a buffer for the relocation fixup log.
962 // Only used for runtime drivers.
964 ImageContext
->FixupData
= NULL
;
967 // Load the Codeview info if present
969 if (ImageContext
->DebugDirectoryEntryRva
!= 0) {
970 if (!(ImageContext
->IsTeImage
)) {
971 DebugEntry
= PeCoffLoaderImageAddress (
973 ImageContext
->DebugDirectoryEntryRva
976 DebugEntry
= (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
*)(UINTN
)(
977 ImageContext
->ImageAddress
+
978 ImageContext
->DebugDirectoryEntryRva
+
979 sizeof(EFI_TE_IMAGE_HEADER
) -
984 if (DebugEntry
!= NULL
) {
985 TempDebugEntryRva
= DebugEntry
->RVA
;
986 if (DebugEntry
->RVA
== 0 && DebugEntry
->FileOffset
!= 0) {
988 if ((UINTN
) Section
->SizeOfRawData
< Section
->Misc
.VirtualSize
) {
989 TempDebugEntryRva
= Section
->VirtualAddress
+ Section
->Misc
.VirtualSize
;
991 TempDebugEntryRva
= Section
->VirtualAddress
+ Section
->SizeOfRawData
;
995 if (TempDebugEntryRva
!= 0) {
996 if (!(ImageContext
->IsTeImage
)) {
997 ImageContext
->CodeView
= PeCoffLoaderImageAddress (ImageContext
, TempDebugEntryRva
);
999 ImageContext
->CodeView
= (VOID
*)(
1000 (UINTN
)ImageContext
->ImageAddress
+
1001 (UINTN
)TempDebugEntryRva
+
1002 (UINTN
)sizeof(EFI_TE_IMAGE_HEADER
) -
1003 (UINTN
) TeHdr
->StrippedSize
1007 if (ImageContext
->CodeView
== NULL
) {
1008 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
1009 return RETURN_LOAD_ERROR
;
1012 if (DebugEntry
->RVA
== 0) {
1013 Size
= DebugEntry
->SizeOfData
;
1014 if (!(ImageContext
->IsTeImage
)) {
1015 Status
= ImageContext
->ImageRead (
1016 ImageContext
->Handle
,
1017 DebugEntry
->FileOffset
,
1019 ImageContext
->CodeView
1022 Status
= ImageContext
->ImageRead (
1023 ImageContext
->Handle
,
1024 DebugEntry
->FileOffset
+ sizeof (EFI_TE_IMAGE_HEADER
) - TeHdr
->StrippedSize
,
1026 ImageContext
->CodeView
1029 // Should we apply fix up to this field according to the size difference between PE and TE?
1030 // Because now we maintain TE header fields unfixed, this field will also remain as they are
1031 // in original PE image.
1035 if (RETURN_ERROR (Status
)) {
1036 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
1037 return RETURN_LOAD_ERROR
;
1040 DebugEntry
->RVA
= TempDebugEntryRva
;
1043 switch (*(UINT32
*) ImageContext
->CodeView
) {
1044 case CODEVIEW_SIGNATURE_NB10
:
1045 ImageContext
->PdbPointer
= (CHAR8
*) ImageContext
->CodeView
+ sizeof (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY
);
1048 case CODEVIEW_SIGNATURE_RSDS
:
1049 ImageContext
->PdbPointer
= (CHAR8
*) ImageContext
->CodeView
+ sizeof (EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY
);