4 Copyright (c) 2006, Intel Corporation
5 All rights reserved. This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
13 Module Name: PeCoffLoader.c
22 PeCoffLoaderGetPeHeader (
23 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
,
24 OUT EFI_IMAGE_NT_HEADERS
*PeHdr
,
25 OUT EFI_TE_IMAGE_HEADER
*TeHdr
30 PeCoffLoaderCheckImageType (
31 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
,
32 IN EFI_IMAGE_NT_HEADERS
*PeHdr
,
33 IN EFI_TE_IMAGE_HEADER
*TeHdr
38 PeCoffLoaderImageAddress (
39 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
,
44 PeCoffLoaderRelocateImageEx (
47 IN OUT CHAR8
**FixupData
,
54 Retrieves the PE or TE Header from a PE/COFF or TE image.
56 @param ImageContext The context of the image being loaded.
58 @param PeHdr The buffer in which to return the PE header.
60 @param TeHdr The buffer in which to return the TE header.
63 RETURN_SUCCESS if the PE or TE Header is read,
64 Otherwise, the error status from reading the PE/COFF or TE image using the ImageRead function.
69 PeCoffLoaderGetPeHeader (
70 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
,
71 OUT EFI_IMAGE_NT_HEADERS
*PeHdr
,
72 OUT EFI_TE_IMAGE_HEADER
*TeHdr
76 EFI_IMAGE_DOS_HEADER DosHdr
;
79 ImageContext
->IsTeImage
= FALSE
;
81 // Read the DOS image headers
83 Size
= sizeof (EFI_IMAGE_DOS_HEADER
);
84 Status
= ImageContext
->ImageRead (
90 if (RETURN_ERROR (Status
)) {
91 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
95 ImageContext
->PeCoffHeaderOffset
= 0;
96 if (DosHdr
.e_magic
== EFI_IMAGE_DOS_SIGNATURE
) {
98 // DOS image header is present, so read the PE header after the DOS image header
100 ImageContext
->PeCoffHeaderOffset
= DosHdr
.e_lfanew
;
103 // Read the PE/COFF Header
105 Size
= sizeof (EFI_IMAGE_NT_HEADERS
);
106 Status
= ImageContext
->ImageRead (
107 ImageContext
->Handle
,
108 ImageContext
->PeCoffHeaderOffset
,
112 if (RETURN_ERROR (Status
)) {
113 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
117 // Check the PE/COFF Header Signature. If not, then try to read a TE header
119 if (PeHdr
->Signature
!= EFI_IMAGE_NT_SIGNATURE
) {
120 Size
= sizeof (EFI_TE_IMAGE_HEADER
);
121 Status
= ImageContext
->ImageRead (
122 ImageContext
->Handle
,
127 if (TeHdr
->Signature
!= EFI_TE_IMAGE_HEADER_SIGNATURE
) {
128 return RETURN_UNSUPPORTED
;
131 ImageContext
->IsTeImage
= TRUE
;
134 return RETURN_SUCCESS
;
138 Checks the PE or TE header of a PE/COFF or TE image to determine if it supported.
140 @param ImageContext The context of the image being loaded.
142 @param PeHdr The buffer in which to return the PE header.
144 @param TeHdr The buffer in which to return the TE header.
146 @retval RETURN_SUCCESS if the PE/COFF or TE image is supported
147 @retval RETURN_UNSUPPORTED of the PE/COFF or TE image is not supported.
152 PeCoffLoaderCheckImageType (
153 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
,
154 IN EFI_IMAGE_NT_HEADERS
*PeHdr
,
155 IN EFI_TE_IMAGE_HEADER
*TeHdr
159 // See if the machine type is supported. We support a native machine type (IA-32/Itanium-based)
160 // and the machine type for the Virtual Machine.
162 if (ImageContext
->IsTeImage
== FALSE
) {
163 ImageContext
->Machine
= PeHdr
->FileHeader
.Machine
;
165 ImageContext
->Machine
= TeHdr
->Machine
;
168 if (!(EFI_IMAGE_MACHINE_TYPE_SUPPORTED (ImageContext
->Machine
))) {
169 ImageContext
->ImageError
= IMAGE_ERROR_INVALID_MACHINE_TYPE
;
170 return RETURN_UNSUPPORTED
;
174 // See if the image type is supported. We support EFI Applications,
175 // EFI Boot Service Drivers, and EFI Runtime Drivers.
177 if (ImageContext
->IsTeImage
== FALSE
) {
178 ImageContext
->ImageType
= PeHdr
->OptionalHeader
.Subsystem
;
180 ImageContext
->ImageType
= (UINT16
) (TeHdr
->Subsystem
);
184 return RETURN_SUCCESS
;
188 Retrieves information on a PE/COFF image.
190 @param This Calling context
191 @param ImageContext The context of the image being loaded
193 @retval RETURN_SUCCESS The information on the PE/COFF image was collected.
194 @retval RETURN_INVALID_PARAMETER ImageContext is NULL.
195 @retval RETURN_UNSUPPORTED The PE/COFF image is not supported.
196 @retval Otherwise The error status from reading the PE/COFF image using the
197 ImageContext->ImageRead() function
202 PeCoffLoaderGetImageInfo (
203 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
206 RETURN_STATUS Status
;
207 EFI_IMAGE_NT_HEADERS PeHdr
;
208 EFI_TE_IMAGE_HEADER TeHdr
;
209 EFI_IMAGE_DATA_DIRECTORY
*DebugDirectoryEntry
;
212 UINTN DebugDirectoryEntryRva
;
213 UINTN DebugDirectoryEntryFileOffset
;
214 UINTN SectionHeaderOffset
;
215 EFI_IMAGE_SECTION_HEADER SectionHeader
;
216 EFI_IMAGE_DEBUG_DIRECTORY_ENTRY DebugEntry
;
218 if (NULL
== ImageContext
) {
219 return RETURN_INVALID_PARAMETER
;
224 ImageContext
->ImageError
= IMAGE_ERROR_SUCCESS
;
226 Status
= PeCoffLoaderGetPeHeader (ImageContext
, &PeHdr
, &TeHdr
);
227 if (RETURN_ERROR (Status
)) {
231 // Verify machine type
233 Status
= PeCoffLoaderCheckImageType (ImageContext
, &PeHdr
, &TeHdr
);
234 if (RETURN_ERROR (Status
)) {
238 // Retrieve the base address of the image
240 if (!(ImageContext
->IsTeImage
)) {
241 ImageContext
->ImageAddress
= PeHdr
.OptionalHeader
.ImageBase
;
243 ImageContext
->ImageAddress
= (PHYSICAL_ADDRESS
) (TeHdr
.ImageBase
);
246 // Initialize the alternate destination address to 0 indicating that it
247 // should not be used.
249 ImageContext
->DestinationAddress
= 0;
252 // Initialize the codeview pointer.
254 ImageContext
->CodeView
= NULL
;
255 ImageContext
->PdbPointer
= NULL
;
258 // Three cases with regards to relocations:
259 // - Image has base relocs, RELOCS_STRIPPED==0 => image is relocatable
260 // - Image has no base relocs, RELOCS_STRIPPED==1 => Image is not relocatable
261 // - Image has no base relocs, RELOCS_STRIPPED==0 => Image is relocatable but
262 // has no base relocs to apply
263 // Obviously having base relocations with RELOCS_STRIPPED==1 is invalid.
265 // Look at the file header to determine if relocations have been stripped, and
266 // save this info in the image context for later use.
268 if ((!(ImageContext
->IsTeImage
)) && ((PeHdr
.FileHeader
.Characteristics
& EFI_IMAGE_FILE_RELOCS_STRIPPED
) != 0)) {
269 ImageContext
->RelocationsStripped
= TRUE
;
271 ImageContext
->RelocationsStripped
= FALSE
;
274 if (!(ImageContext
->IsTeImage
)) {
275 ImageContext
->ImageSize
= (UINT64
) PeHdr
.OptionalHeader
.SizeOfImage
;
276 ImageContext
->SectionAlignment
= PeHdr
.OptionalHeader
.SectionAlignment
;
277 ImageContext
->SizeOfHeaders
= PeHdr
.OptionalHeader
.SizeOfHeaders
;
280 // Modify ImageSize to contain .PDB file name if required and initialize
283 if (PeHdr
.OptionalHeader
.NumberOfRvaAndSizes
> EFI_IMAGE_DIRECTORY_ENTRY_DEBUG
) {
284 DebugDirectoryEntry
= (EFI_IMAGE_DATA_DIRECTORY
*) &(PeHdr
.OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG
]);
286 DebugDirectoryEntryRva
= DebugDirectoryEntry
->VirtualAddress
;
289 // Determine the file offset of the debug directory... This means we walk
290 // the sections to find which section contains the RVA of the debug
293 DebugDirectoryEntryFileOffset
= 0;
295 SectionHeaderOffset
= (UINTN
)(
296 ImageContext
->PeCoffHeaderOffset
+
298 sizeof (EFI_IMAGE_FILE_HEADER
) +
299 PeHdr
.FileHeader
.SizeOfOptionalHeader
302 for (Index
= 0; Index
< PeHdr
.FileHeader
.NumberOfSections
; Index
++) {
304 // Read section header from file
306 Size
= sizeof (EFI_IMAGE_SECTION_HEADER
);
307 Status
= ImageContext
->ImageRead (
308 ImageContext
->Handle
,
313 if (RETURN_ERROR (Status
)) {
314 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
318 if (DebugDirectoryEntryRva
>= SectionHeader
.VirtualAddress
&&
319 DebugDirectoryEntryRva
< SectionHeader
.VirtualAddress
+ SectionHeader
.Misc
.VirtualSize
) {
320 DebugDirectoryEntryFileOffset
=
321 DebugDirectoryEntryRva
- SectionHeader
.VirtualAddress
+ SectionHeader
.PointerToRawData
;
325 SectionHeaderOffset
+= sizeof (EFI_IMAGE_SECTION_HEADER
);
328 if (DebugDirectoryEntryFileOffset
!= 0) {
329 for (Index
= 0; Index
< DebugDirectoryEntry
->Size
; Index
++) {
331 // Read next debug directory entry
333 Size
= sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
);
334 Status
= ImageContext
->ImageRead (
335 ImageContext
->Handle
,
336 DebugDirectoryEntryFileOffset
,
340 if (RETURN_ERROR (Status
)) {
341 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
345 if (DebugEntry
.Type
== EFI_IMAGE_DEBUG_TYPE_CODEVIEW
) {
346 ImageContext
->DebugDirectoryEntryRva
= (UINT32
) (DebugDirectoryEntryRva
+ Index
* sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
));
347 if (DebugEntry
.RVA
== 0 && DebugEntry
.FileOffset
!= 0) {
348 ImageContext
->ImageSize
+= DebugEntry
.SizeOfData
;
351 return RETURN_SUCCESS
;
357 ImageContext
->ImageSize
= 0;
358 ImageContext
->SectionAlignment
= 4096;
359 ImageContext
->SizeOfHeaders
= sizeof (EFI_TE_IMAGE_HEADER
) + (UINTN
) TeHdr
.BaseOfCode
- (UINTN
) TeHdr
.StrippedSize
;
361 DebugDirectoryEntry
= &TeHdr
.DataDirectory
[1];
362 DebugDirectoryEntryRva
= DebugDirectoryEntry
->VirtualAddress
;
363 SectionHeaderOffset
= (UINTN
) (sizeof (EFI_TE_IMAGE_HEADER
));
365 DebugDirectoryEntryFileOffset
= 0;
367 for (Index
= 0; Index
< TeHdr
.NumberOfSections
;) {
369 // Read section header from file
371 Size
= sizeof (EFI_IMAGE_SECTION_HEADER
);
372 Status
= ImageContext
->ImageRead (
373 ImageContext
->Handle
,
378 if (RETURN_ERROR (Status
)) {
379 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
383 if (DebugDirectoryEntryRva
>= SectionHeader
.VirtualAddress
&&
384 DebugDirectoryEntryRva
< SectionHeader
.VirtualAddress
+ SectionHeader
.Misc
.VirtualSize
) {
385 DebugDirectoryEntryFileOffset
= DebugDirectoryEntryRva
-
386 SectionHeader
.VirtualAddress
+
387 SectionHeader
.PointerToRawData
+
388 sizeof (EFI_TE_IMAGE_HEADER
) -
392 // File offset of the debug directory was found, if this is not the last
393 // section, then skip to the last section for calculating the image size.
395 if (Index
< (UINTN
) TeHdr
.NumberOfSections
- 1) {
396 SectionHeaderOffset
+= (TeHdr
.NumberOfSections
- 1 - Index
) * sizeof (EFI_IMAGE_SECTION_HEADER
);
397 Index
= TeHdr
.NumberOfSections
- 1;
403 // In Te image header there is not a field to describe the ImageSize.
404 // Actually, the ImageSize equals the RVA plus the VirtualSize of
405 // the last section mapped into memory (Must be rounded up to
406 // a mulitple of Section Alignment). Per the PE/COFF specification, the
407 // section headers in the Section Table must appear in order of the RVA
408 // values for the corresponding sections. So the ImageSize can be determined
409 // by the RVA and the VirtualSize of the last section header in the
412 if ((++Index
) == (UINTN
) TeHdr
.NumberOfSections
) {
413 ImageContext
->ImageSize
= (SectionHeader
.VirtualAddress
+ SectionHeader
.Misc
.VirtualSize
+
414 ImageContext
->SectionAlignment
- 1) & ~(ImageContext
->SectionAlignment
- 1);
417 SectionHeaderOffset
+= sizeof (EFI_IMAGE_SECTION_HEADER
);
420 if (DebugDirectoryEntryFileOffset
!= 0) {
421 for (Index
= 0; Index
< DebugDirectoryEntry
->Size
; Index
++) {
423 // Read next debug directory entry
425 Size
= sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
);
426 Status
= ImageContext
->ImageRead (
427 ImageContext
->Handle
,
428 DebugDirectoryEntryFileOffset
,
432 if (RETURN_ERROR (Status
)) {
433 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
437 if (DebugEntry
.Type
== EFI_IMAGE_DEBUG_TYPE_CODEVIEW
) {
438 ImageContext
->DebugDirectoryEntryRva
= (UINT32
) (DebugDirectoryEntryRva
+ Index
* sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
));
439 return RETURN_SUCCESS
;
445 return RETURN_SUCCESS
;
449 Converts an image address to the loaded address.
451 @param ImageContext The context of the image being loaded.
453 @param Address The address to be converted to the loaded address.
455 @return NULL if the address can not be converted, otherwise, the converted address
460 PeCoffLoaderImageAddress (
461 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
,
465 if (Address
>= ImageContext
->ImageSize
) {
466 ImageContext
->ImageError
= IMAGE_ERROR_INVALID_IMAGE_ADDRESS
;
470 return (CHAR8
*) ((UINTN
) ImageContext
->ImageAddress
+ Address
);
474 Relocates a PE/COFF image in memory.
476 @param This Calling context.
478 @param ImageContext Contains information on the loaded image to relocate.
480 @retval RETURN_SUCCESS if the PE/COFF image was relocated.
481 @retval RETURN_LOAD_ERROR if the image is not a valid PE/COFF image.
482 @retval RETURN_UNSUPPORTED not support.
487 PeCoffLoaderRelocateImage (
488 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
491 RETURN_STATUS Status
;
492 EFI_IMAGE_NT_HEADERS
*PeHdr
;
493 EFI_TE_IMAGE_HEADER
*TeHdr
;
494 EFI_IMAGE_DATA_DIRECTORY
*RelocDir
;
496 EFI_IMAGE_BASE_RELOCATION
*RelocBase
;
497 EFI_IMAGE_BASE_RELOCATION
*RelocBaseEnd
;
505 PHYSICAL_ADDRESS BaseAddress
;
512 ImageContext
->ImageError
= IMAGE_ERROR_SUCCESS
;
515 // If there are no relocation entries, then we are done
517 if (ImageContext
->RelocationsStripped
) {
518 return RETURN_SUCCESS
;
522 // If the destination address is not 0, use that rather than the
523 // image address as the relocation target.
525 if (ImageContext
->DestinationAddress
) {
526 BaseAddress
= ImageContext
->DestinationAddress
;
528 BaseAddress
= ImageContext
->ImageAddress
;
531 if (!(ImageContext
->IsTeImage
)) {
532 PeHdr
= (EFI_IMAGE_NT_HEADERS
*)((UINTN
)ImageContext
->ImageAddress
+
533 ImageContext
->PeCoffHeaderOffset
);
534 Adjust
= (UINT64
) BaseAddress
- PeHdr
->OptionalHeader
.ImageBase
;
535 PeHdr
->OptionalHeader
.ImageBase
= (UINTN
)BaseAddress
;
538 // Find the relocation block
540 // Per the PE/COFF spec, you can't assume that a given data directory
541 // is present in the image. You have to check the NumberOfRvaAndSizes in
542 // the optional header to verify a desired directory entry is there.
544 if (PeHdr
->OptionalHeader
.NumberOfRvaAndSizes
> EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
) {
545 RelocDir
= &PeHdr
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
];
546 RelocBase
= PeCoffLoaderImageAddress (ImageContext
, RelocDir
->VirtualAddress
);
547 RelocBaseEnd
= PeCoffLoaderImageAddress (
549 RelocDir
->VirtualAddress
+ RelocDir
->Size
- 1
553 // Set base and end to bypass processing below.
555 RelocBase
= RelocBaseEnd
= 0;
558 TeHdr
= (EFI_TE_IMAGE_HEADER
*) (UINTN
) (ImageContext
->ImageAddress
);
559 Adjust
= (UINT64
) (BaseAddress
- TeHdr
->ImageBase
);
560 TeHdr
->ImageBase
= (UINT64
) (BaseAddress
);
563 // Find the relocation block
565 RelocDir
= &TeHdr
->DataDirectory
[0];
566 RelocBase
= (EFI_IMAGE_BASE_RELOCATION
*)(UINTN
)(
567 ImageContext
->ImageAddress
+
568 RelocDir
->VirtualAddress
+
569 sizeof(EFI_TE_IMAGE_HEADER
) -
572 RelocBaseEnd
= (EFI_IMAGE_BASE_RELOCATION
*) ((UINTN
) RelocBase
+ (UINTN
) RelocDir
->Size
- 1);
576 // Run the relocation information and apply the fixups
578 FixupData
= ImageContext
->FixupData
;
579 while (RelocBase
< RelocBaseEnd
) {
581 Reloc
= (UINT16
*) ((CHAR8
*) RelocBase
+ sizeof (EFI_IMAGE_BASE_RELOCATION
));
582 RelocEnd
= (UINT16
*) ((CHAR8
*) RelocBase
+ RelocBase
->SizeOfBlock
);
583 if (!(ImageContext
->IsTeImage
)) {
584 FixupBase
= PeCoffLoaderImageAddress (ImageContext
, RelocBase
->VirtualAddress
);
586 FixupBase
= (CHAR8
*)(UINTN
)(ImageContext
->ImageAddress
+
587 RelocBase
->VirtualAddress
+
588 sizeof(EFI_TE_IMAGE_HEADER
) -
593 if ((CHAR8
*) RelocEnd
< (CHAR8
*) ((UINTN
) ImageContext
->ImageAddress
) ||
594 (CHAR8
*) RelocEnd
> (CHAR8
*)((UINTN
)ImageContext
->ImageAddress
+
595 (UINTN
)ImageContext
->ImageSize
)) {
596 ImageContext
->ImageError
= IMAGE_ERROR_FAILED_RELOCATION
;
597 return RETURN_LOAD_ERROR
;
601 // Run this relocation record
603 while (Reloc
< RelocEnd
) {
605 Fixup
= FixupBase
+ (*Reloc
& 0xFFF);
606 switch ((*Reloc
) >> 12) {
607 case EFI_IMAGE_REL_BASED_ABSOLUTE
:
610 case EFI_IMAGE_REL_BASED_HIGH
:
611 F16
= (UINT16
*) Fixup
;
612 *F16
= (UINT16
) ((*F16
<< 16) + (UINT16
) Adjust
);
613 if (FixupData
!= NULL
) {
614 *(UINT16
*) FixupData
= *F16
;
615 FixupData
= FixupData
+ sizeof (UINT16
);
619 case EFI_IMAGE_REL_BASED_LOW
:
620 F16
= (UINT16
*) Fixup
;
621 *F16
= (UINT16
) (*F16
+ (UINT16
) Adjust
);
622 if (FixupData
!= NULL
) {
623 *(UINT16
*) FixupData
= *F16
;
624 FixupData
= FixupData
+ sizeof (UINT16
);
628 case EFI_IMAGE_REL_BASED_HIGHLOW
:
629 F32
= (UINT32
*) Fixup
;
630 *F32
= *F32
+ (UINT32
) Adjust
;
631 if (FixupData
!= NULL
) {
632 FixupData
= ALIGN_POINTER (FixupData
, sizeof (UINT32
));
633 *(UINT32
*) FixupData
= *F32
;
634 FixupData
= FixupData
+ sizeof (UINT32
);
638 case EFI_IMAGE_REL_BASED_HIGHADJ
:
640 // Return the same EFI_UNSUPPORTED return code as
641 // PeCoffLoaderRelocateImageEx() returns if it does not recognize
642 // the relocation type.
644 ImageContext
->ImageError
= IMAGE_ERROR_FAILED_RELOCATION
;
645 return RETURN_UNSUPPORTED
;
648 Status
= PeCoffLoaderRelocateImageEx (Reloc
, Fixup
, &FixupData
, Adjust
);
649 if (RETURN_ERROR (Status
)) {
650 ImageContext
->ImageError
= IMAGE_ERROR_FAILED_RELOCATION
;
656 // Next relocation record
664 RelocBase
= (EFI_IMAGE_BASE_RELOCATION
*) RelocEnd
;
667 return RETURN_SUCCESS
;
671 Loads a PE/COFF image into memory.
673 @param This Calling context.
675 @param ImageContext Contains information on image to load into memory.
677 @retval RETURN_SUCCESS if the PE/COFF image was loaded.
678 @retval RETURN_BUFFER_TOO_SMALL if the caller did not provide a large enough buffer.
679 @retval RETURN_LOAD_ERROR if the image is a runtime driver with no relocations.
680 @retval RETURN_INVALID_PARAMETER if the image address is invalid.
685 PeCoffLoaderLoadImage (
686 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
689 RETURN_STATUS Status
;
690 EFI_IMAGE_NT_HEADERS
*PeHdr
;
691 EFI_TE_IMAGE_HEADER
*TeHdr
;
692 PE_COFF_LOADER_IMAGE_CONTEXT CheckContext
;
693 EFI_IMAGE_SECTION_HEADER
*FirstSection
;
694 EFI_IMAGE_SECTION_HEADER
*Section
;
695 UINTN NumberOfSections
;
700 EFI_IMAGE_DATA_DIRECTORY
*DirectoryEntry
;
701 EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
*DebugEntry
;
703 UINT32 TempDebugEntryRva
;
710 ImageContext
->ImageError
= IMAGE_ERROR_SUCCESS
;
713 // Copy the provided context info into our local version, get what we
714 // can from the original image, and then use that to make sure everything
717 CopyMem (&CheckContext
, ImageContext
, sizeof (PE_COFF_LOADER_IMAGE_CONTEXT
));
719 Status
= PeCoffLoaderGetImageInfo (&CheckContext
);
720 if (RETURN_ERROR (Status
)) {
725 // Make sure there is enough allocated space for the image being loaded
727 if (ImageContext
->ImageSize
< CheckContext
.ImageSize
) {
728 ImageContext
->ImageError
= IMAGE_ERROR_INVALID_IMAGE_SIZE
;
729 return RETURN_BUFFER_TOO_SMALL
;
733 // If there's no relocations, then make sure it's not a runtime driver,
734 // and that it's being loaded at the linked address.
736 if (CheckContext
.RelocationsStripped
) {
738 // If the image does not contain relocations and it is a runtime driver
739 // then return an error.
741 if (CheckContext
.ImageType
== EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER
) {
742 ImageContext
->ImageError
= IMAGE_ERROR_INVALID_SUBSYSTEM
;
743 return RETURN_LOAD_ERROR
;
746 // If the image does not contain relocations, and the requested load address
747 // is not the linked address, then return an error.
749 if (CheckContext
.ImageAddress
!= ImageContext
->ImageAddress
) {
750 ImageContext
->ImageError
= IMAGE_ERROR_INVALID_IMAGE_ADDRESS
;
751 return RETURN_INVALID_PARAMETER
;
755 // Make sure the allocated space has the proper section alignment
757 if (!(ImageContext
->IsTeImage
)) {
758 if ((ImageContext
->ImageAddress
& (CheckContext
.SectionAlignment
- 1)) != 0) {
759 ImageContext
->ImageError
= IMAGE_ERROR_INVALID_SECTION_ALIGNMENT
;
760 return RETURN_INVALID_PARAMETER
;
764 // Read the entire PE/COFF or TE header into memory
766 if (!(ImageContext
->IsTeImage
)) {
767 Status
= ImageContext
->ImageRead (
768 ImageContext
->Handle
,
770 &ImageContext
->SizeOfHeaders
,
771 (VOID
*) (UINTN
) ImageContext
->ImageAddress
774 PeHdr
= (EFI_IMAGE_NT_HEADERS
*)
775 ((UINTN
)ImageContext
->ImageAddress
+ ImageContext
->PeCoffHeaderOffset
);
777 FirstSection
= (EFI_IMAGE_SECTION_HEADER
*) (
778 (UINTN
)ImageContext
->ImageAddress
+
779 ImageContext
->PeCoffHeaderOffset
+
781 sizeof(EFI_IMAGE_FILE_HEADER
) +
782 PeHdr
->FileHeader
.SizeOfOptionalHeader
784 NumberOfSections
= (UINTN
) (PeHdr
->FileHeader
.NumberOfSections
);
786 Status
= ImageContext
->ImageRead (
787 ImageContext
->Handle
,
789 &ImageContext
->SizeOfHeaders
,
790 (void *) (UINTN
) ImageContext
->ImageAddress
793 TeHdr
= (EFI_TE_IMAGE_HEADER
*) (UINTN
) (ImageContext
->ImageAddress
);
795 FirstSection
= (EFI_IMAGE_SECTION_HEADER
*) (
796 (UINTN
)ImageContext
->ImageAddress
+
797 sizeof(EFI_TE_IMAGE_HEADER
)
799 NumberOfSections
= (UINTN
) (TeHdr
->NumberOfSections
);
803 if (RETURN_ERROR (Status
)) {
804 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
805 return RETURN_LOAD_ERROR
;
809 // Load each section of the image
811 Section
= FirstSection
;
812 for (Index
= 0, MaxEnd
= NULL
; Index
< NumberOfSections
; Index
++) {
815 // Compute sections address
817 Base
= PeCoffLoaderImageAddress (ImageContext
, Section
->VirtualAddress
);
818 End
= PeCoffLoaderImageAddress (
820 Section
->VirtualAddress
+ Section
->Misc
.VirtualSize
- 1
822 if (ImageContext
->IsTeImage
) {
823 Base
= (CHAR8
*) ((UINTN
) Base
+ sizeof (EFI_TE_IMAGE_HEADER
) - (UINTN
) TeHdr
->StrippedSize
);
824 End
= (CHAR8
*) ((UINTN
) End
+ sizeof (EFI_TE_IMAGE_HEADER
) - (UINTN
) TeHdr
->StrippedSize
);
831 // If the base start or end address resolved to 0, then fail.
833 if ((Base
== NULL
) || (End
== NULL
)) {
834 ImageContext
->ImageError
= IMAGE_ERROR_SECTION_NOT_LOADED
;
835 return RETURN_LOAD_ERROR
;
841 Size
= (UINTN
) Section
->Misc
.VirtualSize
;
842 if ((Size
== 0) || (Size
> Section
->SizeOfRawData
)) {
843 Size
= (UINTN
) Section
->SizeOfRawData
;
846 if (Section
->SizeOfRawData
) {
847 if (!(ImageContext
->IsTeImage
)) {
848 Status
= ImageContext
->ImageRead (
849 ImageContext
->Handle
,
850 Section
->PointerToRawData
,
855 Status
= ImageContext
->ImageRead (
856 ImageContext
->Handle
,
857 Section
->PointerToRawData
+ sizeof (EFI_TE_IMAGE_HEADER
) - (UINTN
) TeHdr
->StrippedSize
,
863 if (RETURN_ERROR (Status
)) {
864 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
870 // If raw size is less then virt size, zero fill the remaining
873 if (Size
< Section
->Misc
.VirtualSize
) {
874 ZeroMem (Base
+ Size
, Section
->Misc
.VirtualSize
- Size
);
884 // Get image's entry point
886 if (!(ImageContext
->IsTeImage
)) {
887 ImageContext
->EntryPoint
= (PHYSICAL_ADDRESS
) (UINTN
) PeCoffLoaderImageAddress (
889 PeHdr
->OptionalHeader
.AddressOfEntryPoint
892 ImageContext
->EntryPoint
= (PHYSICAL_ADDRESS
) (
893 (UINTN
)ImageContext
->ImageAddress
+
894 (UINTN
)TeHdr
->AddressOfEntryPoint
+
895 (UINTN
)sizeof(EFI_TE_IMAGE_HEADER
) -
896 (UINTN
) TeHdr
->StrippedSize
901 // Determine the size of the fixup data
903 // Per the PE/COFF spec, you can't assume that a given data directory
904 // is present in the image. You have to check the NumberOfRvaAndSizes in
905 // the optional header to verify a desired directory entry is there.
907 if (!(ImageContext
->IsTeImage
)) {
908 if (PeHdr
->OptionalHeader
.NumberOfRvaAndSizes
> EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
) {
909 DirectoryEntry
= (EFI_IMAGE_DATA_DIRECTORY
*)
910 &PeHdr
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
];
911 ImageContext
->FixupDataSize
= DirectoryEntry
->Size
/ sizeof (UINT16
) * sizeof (UINTN
);
913 ImageContext
->FixupDataSize
= 0;
916 DirectoryEntry
= &TeHdr
->DataDirectory
[0];
917 ImageContext
->FixupDataSize
= DirectoryEntry
->Size
/ sizeof (UINT16
) * sizeof (UINTN
);
920 // Consumer must allocate a buffer for the relocation fixup log.
921 // Only used for runtime drivers.
923 ImageContext
->FixupData
= NULL
;
926 // Load the Codeview info if present
928 if (ImageContext
->DebugDirectoryEntryRva
!= 0) {
929 if (!(ImageContext
->IsTeImage
)) {
930 DebugEntry
= PeCoffLoaderImageAddress (
932 ImageContext
->DebugDirectoryEntryRva
935 DebugEntry
= (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
*)(UINTN
)(
936 ImageContext
->ImageAddress
+
937 ImageContext
->DebugDirectoryEntryRva
+
938 sizeof(EFI_TE_IMAGE_HEADER
) -
943 if (DebugEntry
!= NULL
) {
944 TempDebugEntryRva
= DebugEntry
->RVA
;
945 if (DebugEntry
->RVA
== 0 && DebugEntry
->FileOffset
!= 0) {
947 if ((UINTN
) Section
->SizeOfRawData
< Section
->Misc
.VirtualSize
) {
948 TempDebugEntryRva
= Section
->VirtualAddress
+ Section
->Misc
.VirtualSize
;
950 TempDebugEntryRva
= Section
->VirtualAddress
+ Section
->SizeOfRawData
;
954 if (TempDebugEntryRva
!= 0) {
955 if (!(ImageContext
->IsTeImage
)) {
956 ImageContext
->CodeView
= PeCoffLoaderImageAddress (ImageContext
, TempDebugEntryRva
);
958 ImageContext
->CodeView
= (VOID
*)(
959 (UINTN
)ImageContext
->ImageAddress
+
960 (UINTN
)TempDebugEntryRva
+
961 (UINTN
)sizeof(EFI_TE_IMAGE_HEADER
) -
962 (UINTN
) TeHdr
->StrippedSize
966 if (ImageContext
->CodeView
== NULL
) {
967 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
968 return RETURN_LOAD_ERROR
;
971 if (DebugEntry
->RVA
== 0) {
972 Size
= DebugEntry
->SizeOfData
;
973 if (!(ImageContext
->IsTeImage
)) {
974 Status
= ImageContext
->ImageRead (
975 ImageContext
->Handle
,
976 DebugEntry
->FileOffset
,
978 ImageContext
->CodeView
981 Status
= ImageContext
->ImageRead (
982 ImageContext
->Handle
,
983 DebugEntry
->FileOffset
+ sizeof (EFI_TE_IMAGE_HEADER
) - TeHdr
->StrippedSize
,
985 ImageContext
->CodeView
988 // Should we apply fix up to this field according to the size difference between PE and TE?
989 // Because now we maintain TE header fields unfixed, this field will also remain as they are
990 // in original PE image.
994 if (RETURN_ERROR (Status
)) {
995 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
996 return RETURN_LOAD_ERROR
;
999 DebugEntry
->RVA
= TempDebugEntryRva
;
1002 switch (*(UINT32
*) ImageContext
->CodeView
) {
1003 case CODEVIEW_SIGNATURE_NB10
:
1004 ImageContext
->PdbPointer
= (CHAR8
*) ImageContext
->CodeView
+ sizeof (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY
);
1007 case CODEVIEW_SIGNATURE_RSDS
:
1008 ImageContext
->PdbPointer
= (CHAR8
*) ImageContext
->CodeView
+ sizeof (EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY
);