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.
27 #include "PeCoffLoaderEx.h"
29 #ifdef EFI_NT_EMULATOR
31 #include "EfiHobLib.h"
32 #include EFI_PPI_DEFINITION (NtLoadAsDll)
37 PeCoffLoaderGetPeHeader (
38 IN OUT EFI_PEI_PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
,
39 OUT EFI_IMAGE_NT_HEADERS
*PeHdr
,
40 OUT EFI_TE_IMAGE_HEADER
*TeHdr
45 PeCoffLoaderCheckImageType (
46 IN OUT EFI_PEI_PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
,
47 IN EFI_IMAGE_NT_HEADERS
*PeHdr
,
48 IN EFI_TE_IMAGE_HEADER
*TeHdr
53 PeCoffLoaderImageAddress (
54 IN OUT EFI_PEI_PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
,
60 PeCoffLoaderGetImageInfo (
61 IN EFI_PEI_PE_COFF_LOADER_PROTOCOL
*This
,
62 IN OUT EFI_PEI_PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
67 PeCoffLoaderRelocateImage (
68 IN EFI_PEI_PE_COFF_LOADER_PROTOCOL
*This
,
69 IN OUT EFI_PEI_PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
74 PeCoffLoaderLoadImage (
75 IN EFI_PEI_PE_COFF_LOADER_PROTOCOL
*This
,
76 IN OUT EFI_PEI_PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
81 PeCoffLoaderUnloadImage (
82 IN EFI_PEI_PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
85 EFI_PEI_PE_COFF_LOADER_PROTOCOL mPeCoffLoader
= {
86 PeCoffLoaderGetImageInfo
,
87 PeCoffLoaderLoadImage
,
88 PeCoffLoaderRelocateImage
,
89 PeCoffLoaderUnloadImage
92 #ifdef EFI_NT_EMULATOR
93 EFI_NT_LOAD_AS_DLL_PPI
*mPeCoffLoaderWinNtLoadAsDll
= NULL
;
97 InstallEfiPeiPeCoffLoader (
98 IN EFI_PEI_SERVICES
**PeiServices
,
99 IN OUT EFI_PEI_PE_COFF_LOADER_PROTOCOL
**This
,
100 IN EFI_PEI_PPI_DESCRIPTOR
*ThisPpi
106 Install PE/COFF loader PPI
110 PeiServices - General purpose services available to every PEIM
112 This - Pointer to get Pei PE coff loader protocol as output
114 ThisPpi - Passed in as EFI_NT_LOAD_AS_DLL_PPI on NT_EMULATOR platform
124 Status
= EFI_SUCCESS
;
126 #ifdef EFI_NT_EMULATOR
128 // For use by PEI Core and Modules
130 if (NULL
!= PeiServices
) {
131 Status
= (**PeiServices
).LocatePpi (
133 &gEfiNtLoadAsDllPpiGuid
,
136 &mPeCoffLoaderWinNtLoadAsDll
140 // Now in SecMain or ERM usage, bind appropriately
142 PEI_ASSERT (PeiServices
, (NULL
!= ThisPpi
));
144 mPeCoffLoaderWinNtLoadAsDll
= (EFI_NT_LOAD_AS_DLL_PPI
*) ThisPpi
;
145 PEI_ASSERT (PeiServices
, (NULL
!= mPeCoffLoaderWinNtLoadAsDll
));
150 *This
= &mPeCoffLoader
;
158 PeCoffLoaderGetPeHeader (
159 IN OUT EFI_PEI_PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
,
160 OUT EFI_IMAGE_NT_HEADERS
*PeHdr
,
161 OUT EFI_TE_IMAGE_HEADER
*TeHdr
167 Retrieves the PE or TE Header from a PE/COFF or TE image
171 ImageContext - The context of the image being loaded
173 PeHdr - The buffer in which to return the PE header
175 TeHdr - The buffer in which to return the TE header
179 EFI_SUCCESS if the PE or TE Header is read,
180 Otherwise, the error status from reading the PE/COFF or TE image using the ImageRead function.
185 EFI_IMAGE_DOS_HEADER DosHdr
;
188 ImageContext
->IsTeImage
= FALSE
;
190 // Read the DOS image headers
192 Size
= sizeof (EFI_IMAGE_DOS_HEADER
);
193 Status
= ImageContext
->ImageRead (
194 ImageContext
->Handle
,
199 if (EFI_ERROR (Status
)) {
200 ImageContext
->ImageError
= EFI_IMAGE_ERROR_IMAGE_READ
;
204 ImageContext
->PeCoffHeaderOffset
= 0;
205 if (DosHdr
.e_magic
== EFI_IMAGE_DOS_SIGNATURE
) {
207 // DOS image header is present, so read the PE header after the DOS image header
209 ImageContext
->PeCoffHeaderOffset
= DosHdr
.e_lfanew
;
212 // Read the PE/COFF Header
214 Size
= sizeof (EFI_IMAGE_NT_HEADERS
);
215 Status
= ImageContext
->ImageRead (
216 ImageContext
->Handle
,
217 ImageContext
->PeCoffHeaderOffset
,
221 if (EFI_ERROR (Status
)) {
222 ImageContext
->ImageError
= EFI_IMAGE_ERROR_IMAGE_READ
;
226 // Check the PE/COFF Header Signature. If not, then try to read a TE header
228 if (PeHdr
->Signature
!= EFI_IMAGE_NT_SIGNATURE
) {
229 Size
= sizeof (EFI_TE_IMAGE_HEADER
);
230 Status
= ImageContext
->ImageRead (
231 ImageContext
->Handle
,
236 if (TeHdr
->Signature
!= EFI_TE_IMAGE_HEADER_SIGNATURE
) {
237 return EFI_UNSUPPORTED
;
240 ImageContext
->IsTeImage
= TRUE
;
248 PeCoffLoaderCheckImageType (
249 IN OUT EFI_PEI_PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
,
250 IN EFI_IMAGE_NT_HEADERS
*PeHdr
,
251 IN EFI_TE_IMAGE_HEADER
*TeHdr
257 Checks the PE or TE header of a PE/COFF or TE image to determine if it supported
261 ImageContext - The context of the image being loaded
263 PeHdr - The buffer in which to return the PE header
265 TeHdr - The buffer in which to return the TE header
269 EFI_SUCCESS if the PE/COFF or TE image is supported
270 EFI_UNSUPPORTED of the PE/COFF or TE image is not supported.
275 // See if the machine type is supported. We support a native machine type (IA-32/Itanium-based)
276 // and the machine type for the Virtual Machine.
278 if (ImageContext
->IsTeImage
== FALSE
) {
279 ImageContext
->Machine
= PeHdr
->FileHeader
.Machine
;
281 ImageContext
->Machine
= TeHdr
->Machine
;
284 if (!(EFI_IMAGE_MACHINE_TYPE_SUPPORTED (ImageContext
->Machine
))) {
285 ImageContext
->ImageError
= EFI_IMAGE_ERROR_INVALID_MACHINE_TYPE
;
286 return EFI_UNSUPPORTED
;
290 // See if the image type is supported. We support EFI Applications,
291 // EFI Boot Service Drivers, and EFI Runtime Drivers.
293 if (ImageContext
->IsTeImage
== FALSE
) {
294 ImageContext
->ImageType
= PeHdr
->OptionalHeader
.Subsystem
;
296 ImageContext
->ImageType
= (UINT16
) (TeHdr
->Subsystem
);
299 switch (ImageContext
->ImageType
) {
301 case EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION
:
302 ImageContext
->ImageCodeMemoryType
= EfiLoaderCode
;
303 ImageContext
->ImageDataMemoryType
= EfiLoaderData
;
306 case EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER
:
307 ImageContext
->ImageCodeMemoryType
= EfiBootServicesCode
;
308 ImageContext
->ImageDataMemoryType
= EfiBootServicesData
;
311 case EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER
:
312 case EFI_IMAGE_SUBSYSTEM_SAL_RUNTIME_DRIVER
:
313 ImageContext
->ImageCodeMemoryType
= EfiRuntimeServicesCode
;
314 ImageContext
->ImageDataMemoryType
= EfiRuntimeServicesData
;
318 ImageContext
->ImageError
= EFI_IMAGE_ERROR_INVALID_SUBSYSTEM
;
319 return EFI_UNSUPPORTED
;
327 PeCoffLoaderGetImageInfo (
328 IN EFI_PEI_PE_COFF_LOADER_PROTOCOL
*This
,
329 IN OUT EFI_PEI_PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
335 Retrieves information on a PE/COFF image
339 This - Calling context
340 ImageContext - The context of the image being loaded
344 EFI_SUCCESS - The information on the PE/COFF image was collected.
345 EFI_INVALID_PARAMETER - ImageContext is NULL.
346 EFI_UNSUPPORTED - The PE/COFF image is not supported.
347 Otherwise - The error status from reading the PE/COFF image using the
348 ImageContext->ImageRead() function
353 EFI_IMAGE_NT_HEADERS PeHdr
;
354 EFI_TE_IMAGE_HEADER TeHdr
;
355 EFI_IMAGE_DATA_DIRECTORY
*DebugDirectoryEntry
;
358 UINTN DebugDirectoryEntryRva
;
359 UINTN DebugDirectoryEntryFileOffset
;
360 UINTN SectionHeaderOffset
;
361 EFI_IMAGE_SECTION_HEADER SectionHeader
;
362 EFI_IMAGE_DEBUG_DIRECTORY_ENTRY DebugEntry
;
364 if (NULL
== ImageContext
) {
365 return EFI_INVALID_PARAMETER
;
370 ImageContext
->ImageError
= EFI_IMAGE_ERROR_SUCCESS
;
372 Status
= PeCoffLoaderGetPeHeader (ImageContext
, &PeHdr
, &TeHdr
);
373 if (EFI_ERROR (Status
)) {
377 // Verify machine type
379 Status
= PeCoffLoaderCheckImageType (ImageContext
, &PeHdr
, &TeHdr
);
380 if (EFI_ERROR (Status
)) {
384 // Retrieve the base address of the image
386 if (!(ImageContext
->IsTeImage
)) {
387 ImageContext
->ImageAddress
= PeHdr
.OptionalHeader
.ImageBase
;
389 ImageContext
->ImageAddress
= (EFI_PHYSICAL_ADDRESS
) (TeHdr
.ImageBase
);
392 // Initialize the alternate destination address to 0 indicating that it
393 // should not be used.
395 ImageContext
->DestinationAddress
= 0;
398 // Initialize the codeview pointer.
400 ImageContext
->CodeView
= NULL
;
401 ImageContext
->PdbPointer
= NULL
;
404 // Three cases with regards to relocations:
405 // - Image has base relocs, RELOCS_STRIPPED==0 => image is relocatable
406 // - Image has no base relocs, RELOCS_STRIPPED==1 => Image is not relocatable
407 // - Image has no base relocs, RELOCS_STRIPPED==0 => Image is relocatable but
408 // has no base relocs to apply
409 // Obviously having base relocations with RELOCS_STRIPPED==1 is invalid.
411 // Look at the file header to determine if relocations have been stripped, and
412 // save this info in the image context for later use.
414 if ((!(ImageContext
->IsTeImage
)) && ((PeHdr
.FileHeader
.Characteristics
& EFI_IMAGE_FILE_RELOCS_STRIPPED
) != 0)) {
415 ImageContext
->RelocationsStripped
= TRUE
;
417 ImageContext
->RelocationsStripped
= FALSE
;
420 if (!(ImageContext
->IsTeImage
)) {
421 ImageContext
->ImageSize
= (UINT64
) PeHdr
.OptionalHeader
.SizeOfImage
;
422 ImageContext
->SectionAlignment
= PeHdr
.OptionalHeader
.SectionAlignment
;
423 ImageContext
->SizeOfHeaders
= PeHdr
.OptionalHeader
.SizeOfHeaders
;
426 // Modify ImageSize to contain .PDB file name if required and initialize
429 if (PeHdr
.OptionalHeader
.NumberOfRvaAndSizes
> EFI_IMAGE_DIRECTORY_ENTRY_DEBUG
) {
430 DebugDirectoryEntry
= (EFI_IMAGE_DATA_DIRECTORY
*) &(PeHdr
.OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG
]);
432 DebugDirectoryEntryRva
= DebugDirectoryEntry
->VirtualAddress
;
435 // Determine the file offset of the debug directory... This means we walk
436 // the sections to find which section contains the RVA of the debug
439 DebugDirectoryEntryFileOffset
= 0;
441 SectionHeaderOffset
= (UINTN
)(
442 ImageContext
->PeCoffHeaderOffset
+
444 sizeof (EFI_IMAGE_FILE_HEADER
) +
445 PeHdr
.FileHeader
.SizeOfOptionalHeader
448 for (Index
= 0; Index
< PeHdr
.FileHeader
.NumberOfSections
; Index
++) {
450 // Read section header from file
452 Size
= sizeof (EFI_IMAGE_SECTION_HEADER
);
453 Status
= ImageContext
->ImageRead (
454 ImageContext
->Handle
,
459 if (EFI_ERROR (Status
)) {
460 ImageContext
->ImageError
= EFI_IMAGE_ERROR_IMAGE_READ
;
464 if (DebugDirectoryEntryRva
>= SectionHeader
.VirtualAddress
&&
465 DebugDirectoryEntryRva
< SectionHeader
.VirtualAddress
+ SectionHeader
.Misc
.VirtualSize
) {
466 DebugDirectoryEntryFileOffset
=
467 DebugDirectoryEntryRva
- SectionHeader
.VirtualAddress
+ SectionHeader
.PointerToRawData
;
471 SectionHeaderOffset
+= sizeof (EFI_IMAGE_SECTION_HEADER
);
474 if (DebugDirectoryEntryFileOffset
!= 0) {
475 for (Index
= 0; Index
< DebugDirectoryEntry
->Size
; Index
++) {
477 // Read next debug directory entry
479 Size
= sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
);
480 Status
= ImageContext
->ImageRead (
481 ImageContext
->Handle
,
482 DebugDirectoryEntryFileOffset
,
486 if (EFI_ERROR (Status
)) {
487 ImageContext
->ImageError
= EFI_IMAGE_ERROR_IMAGE_READ
;
491 if (DebugEntry
.Type
== EFI_IMAGE_DEBUG_TYPE_CODEVIEW
) {
492 ImageContext
->DebugDirectoryEntryRva
= (UINT32
) (DebugDirectoryEntryRva
+ Index
* sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
));
493 if (DebugEntry
.RVA
== 0 && DebugEntry
.FileOffset
!= 0) {
494 ImageContext
->ImageSize
+= DebugEntry
.SizeOfData
;
503 ImageContext
->ImageSize
= 0;
504 ImageContext
->SectionAlignment
= 4096;
505 ImageContext
->SizeOfHeaders
= sizeof (EFI_TE_IMAGE_HEADER
) + (UINTN
) TeHdr
.BaseOfCode
- (UINTN
) TeHdr
.StrippedSize
;
507 DebugDirectoryEntry
= &TeHdr
.DataDirectory
[1];
508 DebugDirectoryEntryRva
= DebugDirectoryEntry
->VirtualAddress
;
509 SectionHeaderOffset
= (UINTN
) (sizeof (EFI_TE_IMAGE_HEADER
));
511 DebugDirectoryEntryFileOffset
= 0;
513 for (Index
= 0; Index
< TeHdr
.NumberOfSections
;) {
515 // Read section header from file
517 Size
= sizeof (EFI_IMAGE_SECTION_HEADER
);
518 Status
= ImageContext
->ImageRead (
519 ImageContext
->Handle
,
524 if (EFI_ERROR (Status
)) {
525 ImageContext
->ImageError
= EFI_IMAGE_ERROR_IMAGE_READ
;
529 if (DebugDirectoryEntryRva
>= SectionHeader
.VirtualAddress
&&
530 DebugDirectoryEntryRva
< SectionHeader
.VirtualAddress
+ SectionHeader
.Misc
.VirtualSize
) {
531 DebugDirectoryEntryFileOffset
= DebugDirectoryEntryRva
-
532 SectionHeader
.VirtualAddress
+
533 SectionHeader
.PointerToRawData
+
534 sizeof (EFI_TE_IMAGE_HEADER
) -
538 // File offset of the debug directory was found, if this is not the last
539 // section, then skip to the last section for calculating the image size.
541 if (Index
< (UINTN
) TeHdr
.NumberOfSections
- 1) {
542 SectionHeaderOffset
+= (TeHdr
.NumberOfSections
- 1 - Index
) * sizeof (EFI_IMAGE_SECTION_HEADER
);
543 Index
= TeHdr
.NumberOfSections
- 1;
549 // In Te image header there is not a field to describe the ImageSize.
550 // Actually, the ImageSize equals the RVA plus the VirtualSize of
551 // the last section mapped into memory (Must be rounded up to
552 // a mulitple of Section Alignment). Per the PE/COFF specification, the
553 // section headers in the Section Table must appear in order of the RVA
554 // values for the corresponding sections. So the ImageSize can be determined
555 // by the RVA and the VirtualSize of the last section header in the
558 if ((++Index
) == (UINTN
) TeHdr
.NumberOfSections
) {
559 ImageContext
->ImageSize
= (SectionHeader
.VirtualAddress
+ SectionHeader
.Misc
.VirtualSize
+
560 ImageContext
->SectionAlignment
- 1) & ~(ImageContext
->SectionAlignment
- 1);
563 SectionHeaderOffset
+= sizeof (EFI_IMAGE_SECTION_HEADER
);
566 if (DebugDirectoryEntryFileOffset
!= 0) {
567 for (Index
= 0; Index
< DebugDirectoryEntry
->Size
; Index
++) {
569 // Read next debug directory entry
571 Size
= sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
);
572 Status
= ImageContext
->ImageRead (
573 ImageContext
->Handle
,
574 DebugDirectoryEntryFileOffset
,
578 if (EFI_ERROR (Status
)) {
579 ImageContext
->ImageError
= EFI_IMAGE_ERROR_IMAGE_READ
;
583 if (DebugEntry
.Type
== EFI_IMAGE_DEBUG_TYPE_CODEVIEW
) {
584 ImageContext
->DebugDirectoryEntryRva
= (UINT32
) (DebugDirectoryEntryRva
+ Index
* sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
));
596 PeCoffLoaderImageAddress (
597 IN OUT EFI_PEI_PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
,
604 Converts an image address to the loaded address
608 ImageContext - The context of the image being loaded
610 Address - The address to be converted to the loaded address
614 NULL if the address can not be converted, otherwise, the converted address
618 if (Address
>= ImageContext
->ImageSize
) {
619 ImageContext
->ImageError
= EFI_IMAGE_ERROR_INVALID_IMAGE_ADDRESS
;
623 return (CHAR8
*) ((UINTN
) ImageContext
->ImageAddress
+ Address
);
628 PeCoffLoaderRelocateImage (
629 IN EFI_PEI_PE_COFF_LOADER_PROTOCOL
*This
,
630 IN OUT EFI_PEI_PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
636 Relocates a PE/COFF image in memory
640 This - Calling context
642 ImageContext - Contains information on the loaded image to relocate
646 EFI_SUCCESS if the PE/COFF image was relocated
647 EFI_LOAD_ERROR if the image is not a valid PE/COFF image
648 EFI_UNSUPPORTED not support
653 EFI_IMAGE_NT_HEADERS
*PeHdr
;
654 EFI_TE_IMAGE_HEADER
*TeHdr
;
655 EFI_IMAGE_DATA_DIRECTORY
*RelocDir
;
657 EFI_IMAGE_BASE_RELOCATION
*RelocBase
;
658 EFI_IMAGE_BASE_RELOCATION
*RelocBaseEnd
;
666 EFI_PHYSICAL_ADDRESS BaseAddress
;
667 #ifdef EFI_NT_EMULATOR
678 ImageContext
->ImageError
= EFI_IMAGE_ERROR_SUCCESS
;
681 // If there are no relocation entries, then we are done
683 if (ImageContext
->RelocationsStripped
) {
688 // If the destination address is not 0, use that rather than the
689 // image address as the relocation target.
691 if (ImageContext
->DestinationAddress
) {
692 BaseAddress
= ImageContext
->DestinationAddress
;
694 BaseAddress
= ImageContext
->ImageAddress
;
697 if (!(ImageContext
->IsTeImage
)) {
698 PeHdr
= (EFI_IMAGE_NT_HEADERS
*)((UINTN
)ImageContext
->ImageAddress
+
699 ImageContext
->PeCoffHeaderOffset
);
700 Adjust
= (UINT64
) BaseAddress
- PeHdr
->OptionalHeader
.ImageBase
;
701 PeHdr
->OptionalHeader
.ImageBase
= (UINTN
) BaseAddress
;
704 // Find the relocation block
706 // Per the PE/COFF spec, you can't assume that a given data directory
707 // is present in the image. You have to check the NumberOfRvaAndSizes in
708 // the optional header to verify a desired directory entry is there.
710 if (PeHdr
->OptionalHeader
.NumberOfRvaAndSizes
> EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
) {
711 RelocDir
= &PeHdr
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
];
712 RelocBase
= PeCoffLoaderImageAddress (ImageContext
, RelocDir
->VirtualAddress
);
713 RelocBaseEnd
= PeCoffLoaderImageAddress (
715 RelocDir
->VirtualAddress
+ RelocDir
->Size
- 1
719 // Set base and end to bypass processing below.
721 RelocBase
= RelocBaseEnd
= 0;
724 TeHdr
= (EFI_TE_IMAGE_HEADER
*) (UINTN
) (ImageContext
->ImageAddress
);
725 Adjust
= (UINT64
) (BaseAddress
- TeHdr
->ImageBase
);
726 TeHdr
->ImageBase
= (UINT64
) (BaseAddress
);
729 // Find the relocation block
731 RelocDir
= &TeHdr
->DataDirectory
[0];
732 RelocBase
= (EFI_IMAGE_BASE_RELOCATION
*)(UINTN
)(
733 ImageContext
->ImageAddress
+
734 RelocDir
->VirtualAddress
+
735 sizeof(EFI_TE_IMAGE_HEADER
) -
738 RelocBaseEnd
= (EFI_IMAGE_BASE_RELOCATION
*) ((UINTN
) RelocBase
+ (UINTN
) RelocDir
->Size
- 1);
742 // Run the relocation information and apply the fixups
744 FixupData
= ImageContext
->FixupData
;
745 while (RelocBase
< RelocBaseEnd
) {
747 Reloc
= (UINT16
*) ((CHAR8
*) RelocBase
+ sizeof (EFI_IMAGE_BASE_RELOCATION
));
748 RelocEnd
= (UINT16
*) ((CHAR8
*) RelocBase
+ RelocBase
->SizeOfBlock
);
749 if (!(ImageContext
->IsTeImage
)) {
750 FixupBase
= PeCoffLoaderImageAddress (ImageContext
, RelocBase
->VirtualAddress
);
752 FixupBase
= (CHAR8
*)(UINTN
)(ImageContext
->ImageAddress
+
753 RelocBase
->VirtualAddress
+
754 sizeof(EFI_TE_IMAGE_HEADER
) -
759 if ((CHAR8
*) RelocEnd
< (CHAR8
*) ((UINTN
) ImageContext
->ImageAddress
) ||
760 (CHAR8
*) RelocEnd
> (CHAR8
*)((UINTN
)ImageContext
->ImageAddress
+
761 (UINTN
)ImageContext
->ImageSize
)) {
762 ImageContext
->ImageError
= EFI_IMAGE_ERROR_FAILED_RELOCATION
;
763 return EFI_LOAD_ERROR
;
767 // Run this relocation record
769 while (Reloc
< RelocEnd
) {
771 Fixup
= FixupBase
+ (*Reloc
& 0xFFF);
772 switch ((*Reloc
) >> 12) {
773 case EFI_IMAGE_REL_BASED_ABSOLUTE
:
776 case EFI_IMAGE_REL_BASED_HIGH
:
777 F16
= (UINT16
*) Fixup
;
778 *F16
= (UINT16
) ((*F16
<< 16) + (UINT16
) Adjust
);
779 if (FixupData
!= NULL
) {
780 *(UINT16
*) FixupData
= *F16
;
781 FixupData
= FixupData
+ sizeof (UINT16
);
785 case EFI_IMAGE_REL_BASED_LOW
:
786 F16
= (UINT16
*) Fixup
;
787 *F16
= (UINT16
) (*F16
+ (UINT16
) Adjust
);
788 if (FixupData
!= NULL
) {
789 *(UINT16
*) FixupData
= *F16
;
790 FixupData
= FixupData
+ sizeof (UINT16
);
794 case EFI_IMAGE_REL_BASED_HIGHLOW
:
795 F32
= (UINT32
*) Fixup
;
796 *F32
= *F32
+ (UINT32
) Adjust
;
797 if (FixupData
!= NULL
) {
798 FixupData
= ALIGN_POINTER (FixupData
, sizeof (UINT32
));
799 *(UINT32
*) FixupData
= *F32
;
800 FixupData
= FixupData
+ sizeof (UINT32
);
804 case EFI_IMAGE_REL_BASED_HIGHADJ
:
806 // Return the same EFI_UNSUPPORTED return code as
807 // PeCoffLoaderRelocateImageEx() returns if it does not recognize
808 // the relocation type.
810 ImageContext
->ImageError
= EFI_IMAGE_ERROR_FAILED_RELOCATION
;
811 return EFI_UNSUPPORTED
;
814 Status
= PeCoffLoaderRelocateImageEx (Reloc
, Fixup
, &FixupData
, Adjust
);
815 if (EFI_ERROR (Status
)) {
816 ImageContext
->ImageError
= EFI_IMAGE_ERROR_FAILED_RELOCATION
;
822 // Next relocation record
830 RelocBase
= (EFI_IMAGE_BASE_RELOCATION
*) RelocEnd
;
833 #ifdef EFI_NT_EMULATOR
834 DllEntryPoint
= NULL
;
835 ImageContext
->ModHandle
= NULL
;
837 // Load the DLL if it's not an EBC image.
839 if ((ImageContext
->PdbPointer
!= NULL
) &&
840 (ImageContext
->Machine
!= EFI_IMAGE_MACHINE_EBC
)) {
841 Status
= mPeCoffLoaderWinNtLoadAsDll
->Entry (
842 ImageContext
->PdbPointer
,
847 if (!EFI_ERROR (Status
) && DllEntryPoint
!= NULL
) {
848 ImageContext
->EntryPoint
= (EFI_PHYSICAL_ADDRESS
) (UINTN
) DllEntryPoint
;
849 ImageContext
->ModHandle
= ModHandle
;
859 PeCoffLoaderLoadImage (
860 IN EFI_PEI_PE_COFF_LOADER_PROTOCOL
*This
,
861 IN OUT EFI_PEI_PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
867 Loads a PE/COFF image into memory
871 This - Calling context
873 ImageContext - Contains information on image to load into memory
877 EFI_SUCCESS if the PE/COFF image was loaded
878 EFI_BUFFER_TOO_SMALL if the caller did not provide a large enough buffer
879 EFI_LOAD_ERROR if the image is a runtime driver with no relocations
880 EFI_INVALID_PARAMETER if the image address is invalid
885 EFI_IMAGE_NT_HEADERS
*PeHdr
;
886 EFI_TE_IMAGE_HEADER
*TeHdr
;
887 EFI_PEI_PE_COFF_LOADER_IMAGE_CONTEXT CheckContext
;
888 EFI_IMAGE_SECTION_HEADER
*FirstSection
;
889 EFI_IMAGE_SECTION_HEADER
*Section
;
890 UINTN NumberOfSections
;
895 EFI_IMAGE_DATA_DIRECTORY
*DirectoryEntry
;
896 EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
*DebugEntry
;
898 UINT32 TempDebugEntryRva
;
905 ImageContext
->ImageError
= EFI_IMAGE_ERROR_SUCCESS
;
908 // Copy the provided context info into our local version, get what we
909 // can from the original image, and then use that to make sure everything
912 CopyMem (&CheckContext
, ImageContext
, sizeof (EFI_PEI_PE_COFF_LOADER_IMAGE_CONTEXT
));
914 Status
= PeCoffLoaderGetImageInfo (
918 if (EFI_ERROR (Status
)) {
923 // Make sure there is enough allocated space for the image being loaded
925 if (ImageContext
->ImageSize
< CheckContext
.ImageSize
) {
926 ImageContext
->ImageError
= EFI_IMAGE_ERROR_INVALID_IMAGE_SIZE
;
927 return EFI_BUFFER_TOO_SMALL
;
931 // If there's no relocations, then make sure it's not a runtime driver,
932 // and that it's being loaded at the linked address.
934 if (CheckContext
.RelocationsStripped
) {
936 // If the image does not contain relocations and it is a runtime driver
937 // then return an error.
939 if (CheckContext
.ImageType
== EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER
) {
940 ImageContext
->ImageError
= EFI_IMAGE_ERROR_INVALID_SUBSYSTEM
;
941 return EFI_LOAD_ERROR
;
944 // If the image does not contain relocations, and the requested load address
945 // is not the linked address, then return an error.
947 if (CheckContext
.ImageAddress
!= ImageContext
->ImageAddress
) {
948 ImageContext
->ImageError
= EFI_IMAGE_ERROR_INVALID_IMAGE_ADDRESS
;
949 return EFI_INVALID_PARAMETER
;
953 // Make sure the allocated space has the proper section alignment
955 if (!(ImageContext
->IsTeImage
)) {
956 if ((ImageContext
->ImageAddress
& (CheckContext
.SectionAlignment
- 1)) != 0) {
957 ImageContext
->ImageError
= EFI_IMAGE_ERROR_INVALID_SECTION_ALIGNMENT
;
958 return EFI_INVALID_PARAMETER
;
962 // Read the entire PE/COFF or TE header into memory
964 if (!(ImageContext
->IsTeImage
)) {
965 Status
= ImageContext
->ImageRead (
966 ImageContext
->Handle
,
968 &ImageContext
->SizeOfHeaders
,
969 (VOID
*) (UINTN
) ImageContext
->ImageAddress
972 PeHdr
= (EFI_IMAGE_NT_HEADERS
*)
973 ((UINTN
)ImageContext
->ImageAddress
+ ImageContext
->PeCoffHeaderOffset
);
975 FirstSection
= (EFI_IMAGE_SECTION_HEADER
*) (
976 (UINTN
)ImageContext
->ImageAddress
+
977 ImageContext
->PeCoffHeaderOffset
+
979 sizeof(EFI_IMAGE_FILE_HEADER
) +
980 PeHdr
->FileHeader
.SizeOfOptionalHeader
982 NumberOfSections
= (UINTN
) (PeHdr
->FileHeader
.NumberOfSections
);
984 Status
= ImageContext
->ImageRead (
985 ImageContext
->Handle
,
987 &ImageContext
->SizeOfHeaders
,
988 (void *) (UINTN
) ImageContext
->ImageAddress
991 TeHdr
= (EFI_TE_IMAGE_HEADER
*) (UINTN
) (ImageContext
->ImageAddress
);
993 FirstSection
= (EFI_IMAGE_SECTION_HEADER
*) (
994 (UINTN
)ImageContext
->ImageAddress
+
995 sizeof(EFI_TE_IMAGE_HEADER
)
997 NumberOfSections
= (UINTN
) (TeHdr
->NumberOfSections
);
1001 if (EFI_ERROR (Status
)) {
1002 ImageContext
->ImageError
= EFI_IMAGE_ERROR_IMAGE_READ
;
1003 return EFI_LOAD_ERROR
;
1007 // Load each section of the image
1009 Section
= FirstSection
;
1010 for (Index
= 0, MaxEnd
= NULL
; Index
< NumberOfSections
; Index
++) {
1013 // Compute sections address
1015 Base
= PeCoffLoaderImageAddress (ImageContext
, Section
->VirtualAddress
);
1016 End
= PeCoffLoaderImageAddress (
1018 Section
->VirtualAddress
+ Section
->Misc
.VirtualSize
- 1
1020 if (ImageContext
->IsTeImage
) {
1021 Base
= (CHAR8
*) ((UINTN
) Base
+ sizeof (EFI_TE_IMAGE_HEADER
) - (UINTN
) TeHdr
->StrippedSize
);
1022 End
= (CHAR8
*) ((UINTN
) End
+ sizeof (EFI_TE_IMAGE_HEADER
) - (UINTN
) TeHdr
->StrippedSize
);
1029 // If the base start or end address resolved to 0, then fail.
1031 if ((Base
== NULL
) || (End
== NULL
)) {
1032 ImageContext
->ImageError
= EFI_IMAGE_ERROR_SECTION_NOT_LOADED
;
1033 return EFI_LOAD_ERROR
;
1039 Size
= (UINTN
) Section
->Misc
.VirtualSize
;
1040 if ((Size
== 0) || (Size
> Section
->SizeOfRawData
)) {
1041 Size
= (UINTN
) Section
->SizeOfRawData
;
1044 if (Section
->SizeOfRawData
) {
1045 if (!(ImageContext
->IsTeImage
)) {
1046 Status
= ImageContext
->ImageRead (
1047 ImageContext
->Handle
,
1048 Section
->PointerToRawData
,
1053 Status
= ImageContext
->ImageRead (
1054 ImageContext
->Handle
,
1055 Section
->PointerToRawData
+ sizeof (EFI_TE_IMAGE_HEADER
) - (UINTN
) TeHdr
->StrippedSize
,
1061 if (EFI_ERROR (Status
)) {
1062 ImageContext
->ImageError
= EFI_IMAGE_ERROR_IMAGE_READ
;
1068 // If raw size is less then virt size, zero fill the remaining
1071 if (Size
< Section
->Misc
.VirtualSize
) {
1072 ZeroMem (Base
+ Size
, Section
->Misc
.VirtualSize
- Size
);
1082 // Get image's entry point
1084 if (!(ImageContext
->IsTeImage
)) {
1085 ImageContext
->EntryPoint
= (EFI_PHYSICAL_ADDRESS
) (UINTN
) PeCoffLoaderImageAddress (
1087 PeHdr
->OptionalHeader
.AddressOfEntryPoint
1090 ImageContext
->EntryPoint
= (EFI_PHYSICAL_ADDRESS
) (
1091 (UINTN
)ImageContext
->ImageAddress
+
1092 (UINTN
)TeHdr
->AddressOfEntryPoint
+
1093 (UINTN
)sizeof(EFI_TE_IMAGE_HEADER
) -
1094 (UINTN
) TeHdr
->StrippedSize
1099 // Determine the size of the fixup data
1101 // Per the PE/COFF spec, you can't assume that a given data directory
1102 // is present in the image. You have to check the NumberOfRvaAndSizes in
1103 // the optional header to verify a desired directory entry is there.
1105 if (!(ImageContext
->IsTeImage
)) {
1106 if (PeHdr
->OptionalHeader
.NumberOfRvaAndSizes
> EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
) {
1107 DirectoryEntry
= (EFI_IMAGE_DATA_DIRECTORY
*)
1108 &PeHdr
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
];
1109 ImageContext
->FixupDataSize
= DirectoryEntry
->Size
/ sizeof (UINT16
) * sizeof (UINTN
);
1111 ImageContext
->FixupDataSize
= 0;
1114 DirectoryEntry
= &TeHdr
->DataDirectory
[0];
1115 ImageContext
->FixupDataSize
= DirectoryEntry
->Size
/ sizeof (UINT16
) * sizeof (UINTN
);
1118 // Consumer must allocate a buffer for the relocation fixup log.
1119 // Only used for runtime drivers.
1121 ImageContext
->FixupData
= NULL
;
1124 // Load the Codeview info if present
1126 if (ImageContext
->DebugDirectoryEntryRva
!= 0) {
1127 if (!(ImageContext
->IsTeImage
)) {
1128 DebugEntry
= PeCoffLoaderImageAddress (
1130 ImageContext
->DebugDirectoryEntryRva
1133 DebugEntry
= (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
*)(UINTN
)(
1134 ImageContext
->ImageAddress
+
1135 ImageContext
->DebugDirectoryEntryRva
+
1136 sizeof(EFI_TE_IMAGE_HEADER
) -
1141 if (DebugEntry
!= NULL
) {
1142 TempDebugEntryRva
= DebugEntry
->RVA
;
1143 if (DebugEntry
->RVA
== 0 && DebugEntry
->FileOffset
!= 0) {
1145 if ((UINTN
) Section
->SizeOfRawData
< Section
->Misc
.VirtualSize
) {
1146 TempDebugEntryRva
= Section
->VirtualAddress
+ Section
->Misc
.VirtualSize
;
1148 TempDebugEntryRva
= Section
->VirtualAddress
+ Section
->SizeOfRawData
;
1152 if (TempDebugEntryRva
!= 0) {
1153 if (!(ImageContext
->IsTeImage
)) {
1154 ImageContext
->CodeView
= PeCoffLoaderImageAddress (ImageContext
, TempDebugEntryRva
);
1156 ImageContext
->CodeView
= (VOID
*)(
1157 (UINTN
)ImageContext
->ImageAddress
+
1158 (UINTN
)TempDebugEntryRva
+
1159 (UINTN
)sizeof(EFI_TE_IMAGE_HEADER
) -
1160 (UINTN
) TeHdr
->StrippedSize
1164 if (ImageContext
->CodeView
== NULL
) {
1165 ImageContext
->ImageError
= EFI_IMAGE_ERROR_IMAGE_READ
;
1166 return EFI_LOAD_ERROR
;
1169 if (DebugEntry
->RVA
== 0) {
1170 Size
= DebugEntry
->SizeOfData
;
1171 if (!(ImageContext
->IsTeImage
)) {
1172 Status
= ImageContext
->ImageRead (
1173 ImageContext
->Handle
,
1174 DebugEntry
->FileOffset
,
1176 ImageContext
->CodeView
1179 Status
= ImageContext
->ImageRead (
1180 ImageContext
->Handle
,
1181 DebugEntry
->FileOffset
+ sizeof (EFI_TE_IMAGE_HEADER
) - TeHdr
->StrippedSize
,
1183 ImageContext
->CodeView
1186 // Should we apply fix up to this field according to the size difference between PE and TE?
1187 // Because now we maintain TE header fields unfixed, this field will also remain as they are
1188 // in original PE image.
1192 if (EFI_ERROR (Status
)) {
1193 ImageContext
->ImageError
= EFI_IMAGE_ERROR_IMAGE_READ
;
1194 return EFI_LOAD_ERROR
;
1197 DebugEntry
->RVA
= TempDebugEntryRva
;
1200 switch (*(UINT32
*) ImageContext
->CodeView
) {
1201 case CODEVIEW_SIGNATURE_NB10
:
1202 ImageContext
->PdbPointer
= (CHAR8
*) ImageContext
->CodeView
+ sizeof (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY
);
1205 case CODEVIEW_SIGNATURE_RSDS
:
1206 ImageContext
->PdbPointer
= (CHAR8
*) ImageContext
->CodeView
+ sizeof (EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY
);
1221 PeCoffLoaderUnloadImage (
1222 IN EFI_PEI_PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
1226 Routine Description:
1228 Unload a PE/COFF image from memory
1232 ImageContext - Contains information on image to load into memory
1240 #ifdef EFI_NT_EMULATOR
1242 // Calling Win32 API free library
1244 mPeCoffLoaderWinNtLoadAsDll
->FreeLibrary (ImageContext
->ModHandle
);