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"
32 PeCoffLoaderGetPeHeader (
33 IN OUT EFI_PEI_PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
,
34 OUT EFI_IMAGE_NT_HEADERS
*PeHdr
,
35 OUT EFI_TE_IMAGE_HEADER
*TeHdr
40 PeCoffLoaderCheckImageType (
41 IN OUT EFI_PEI_PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
,
42 IN EFI_IMAGE_NT_HEADERS
*PeHdr
,
43 IN EFI_TE_IMAGE_HEADER
*TeHdr
48 PeCoffLoaderImageAddress (
49 IN OUT EFI_PEI_PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
,
55 PeCoffLoaderGetImageInfo (
56 IN EFI_PEI_PE_COFF_LOADER_PROTOCOL
*This
,
57 IN OUT EFI_PEI_PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
62 PeCoffLoaderRelocateImage (
63 IN EFI_PEI_PE_COFF_LOADER_PROTOCOL
*This
,
64 IN OUT EFI_PEI_PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
69 PeCoffLoaderLoadImage (
70 IN EFI_PEI_PE_COFF_LOADER_PROTOCOL
*This
,
71 IN OUT EFI_PEI_PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
76 PeCoffLoaderUnloadImage (
77 IN EFI_PEI_PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
80 EFI_PEI_PE_COFF_LOADER_PROTOCOL mPeCoffLoader
= {
81 PeCoffLoaderGetImageInfo
,
82 PeCoffLoaderLoadImage
,
83 PeCoffLoaderRelocateImage
,
84 PeCoffLoaderUnloadImage
89 InstallEfiPeiPeCoffLoader (
90 IN EFI_PEI_SERVICES
**PeiServices
,
91 IN OUT EFI_PEI_PE_COFF_LOADER_PROTOCOL
**This
,
92 IN EFI_PEI_PPI_DESCRIPTOR
*ThisPpi
98 Install PE/COFF loader PPI
102 PeiServices - General purpose services available to every PEIM
104 This - Pointer to get Pei PE coff loader protocol as output
106 ThisPpi - Passed in as EFI_NT_LOAD_AS_DLL_PPI on NT_EMULATOR platform
115 *This
= &mPeCoffLoader
;
123 PeCoffLoaderGetPeHeader (
124 IN OUT EFI_PEI_PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
,
125 OUT EFI_IMAGE_NT_HEADERS
*PeHdr
,
126 OUT EFI_TE_IMAGE_HEADER
*TeHdr
132 Retrieves the PE or TE Header from a PE/COFF or TE image
136 ImageContext - The context of the image being loaded
138 PeHdr - The buffer in which to return the PE header
140 TeHdr - The buffer in which to return the TE header
144 EFI_SUCCESS if the PE or TE Header is read,
145 Otherwise, the error status from reading the PE/COFF or TE image using the ImageRead function.
150 EFI_IMAGE_DOS_HEADER DosHdr
;
153 ImageContext
->IsTeImage
= FALSE
;
155 // Read the DOS image headers
157 Size
= sizeof (EFI_IMAGE_DOS_HEADER
);
158 Status
= ImageContext
->ImageRead (
159 ImageContext
->Handle
,
164 if (EFI_ERROR (Status
)) {
165 ImageContext
->ImageError
= EFI_IMAGE_ERROR_IMAGE_READ
;
169 ImageContext
->PeCoffHeaderOffset
= 0;
170 if (DosHdr
.e_magic
== EFI_IMAGE_DOS_SIGNATURE
) {
172 // DOS image header is present, so read the PE header after the DOS image header
174 ImageContext
->PeCoffHeaderOffset
= DosHdr
.e_lfanew
;
177 // Read the PE/COFF Header
179 Size
= sizeof (EFI_IMAGE_NT_HEADERS
);
180 Status
= ImageContext
->ImageRead (
181 ImageContext
->Handle
,
182 ImageContext
->PeCoffHeaderOffset
,
186 if (EFI_ERROR (Status
)) {
187 ImageContext
->ImageError
= EFI_IMAGE_ERROR_IMAGE_READ
;
191 // Check the PE/COFF Header Signature. If not, then try to read a TE header
193 if (PeHdr
->Signature
!= EFI_IMAGE_NT_SIGNATURE
) {
194 Size
= sizeof (EFI_TE_IMAGE_HEADER
);
195 Status
= ImageContext
->ImageRead (
196 ImageContext
->Handle
,
201 if (TeHdr
->Signature
!= EFI_TE_IMAGE_HEADER_SIGNATURE
) {
202 return EFI_UNSUPPORTED
;
205 ImageContext
->IsTeImage
= TRUE
;
213 PeCoffLoaderCheckImageType (
214 IN OUT EFI_PEI_PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
,
215 IN EFI_IMAGE_NT_HEADERS
*PeHdr
,
216 IN EFI_TE_IMAGE_HEADER
*TeHdr
222 Checks the PE or TE header of a PE/COFF or TE image to determine if it supported
226 ImageContext - The context of the image being loaded
228 PeHdr - The buffer in which to return the PE header
230 TeHdr - The buffer in which to return the TE header
234 EFI_SUCCESS if the PE/COFF or TE image is supported
235 EFI_UNSUPPORTED of the PE/COFF or TE image is not supported.
240 // See if the machine type is supported. We support a native machine type (IA-32/Itanium-based)
241 // and the machine type for the Virtual Machine.
243 if (ImageContext
->IsTeImage
== FALSE
) {
244 ImageContext
->Machine
= PeHdr
->FileHeader
.Machine
;
246 ImageContext
->Machine
= TeHdr
->Machine
;
249 if (!(EFI_IMAGE_MACHINE_TYPE_SUPPORTED (ImageContext
->Machine
))) {
250 ImageContext
->ImageError
= EFI_IMAGE_ERROR_INVALID_MACHINE_TYPE
;
251 return EFI_UNSUPPORTED
;
255 // See if the image type is supported. We support EFI Applications,
256 // EFI Boot Service Drivers, and EFI Runtime Drivers.
258 if (ImageContext
->IsTeImage
== FALSE
) {
259 ImageContext
->ImageType
= PeHdr
->OptionalHeader
.Subsystem
;
261 ImageContext
->ImageType
= (UINT16
) (TeHdr
->Subsystem
);
264 switch (ImageContext
->ImageType
) {
266 case EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION
:
267 ImageContext
->ImageCodeMemoryType
= EfiLoaderCode
;
268 ImageContext
->ImageDataMemoryType
= EfiLoaderData
;
271 case EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER
:
272 ImageContext
->ImageCodeMemoryType
= EfiBootServicesCode
;
273 ImageContext
->ImageDataMemoryType
= EfiBootServicesData
;
276 case EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER
:
277 case EFI_IMAGE_SUBSYSTEM_SAL_RUNTIME_DRIVER
:
278 ImageContext
->ImageCodeMemoryType
= EfiRuntimeServicesCode
;
279 ImageContext
->ImageDataMemoryType
= EfiRuntimeServicesData
;
283 ImageContext
->ImageError
= EFI_IMAGE_ERROR_INVALID_SUBSYSTEM
;
284 return EFI_UNSUPPORTED
;
292 PeCoffLoaderGetImageInfo (
293 IN EFI_PEI_PE_COFF_LOADER_PROTOCOL
*This
,
294 IN OUT EFI_PEI_PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
300 Retrieves information on a PE/COFF image
304 This - Calling context
305 ImageContext - The context of the image being loaded
309 EFI_SUCCESS - The information on the PE/COFF image was collected.
310 EFI_INVALID_PARAMETER - ImageContext is NULL.
311 EFI_UNSUPPORTED - The PE/COFF image is not supported.
312 Otherwise - The error status from reading the PE/COFF image using the
313 ImageContext->ImageRead() function
318 EFI_IMAGE_NT_HEADERS PeHdr
;
319 EFI_TE_IMAGE_HEADER TeHdr
;
320 EFI_IMAGE_DATA_DIRECTORY
*DebugDirectoryEntry
;
323 UINTN DebugDirectoryEntryRva
;
324 UINTN DebugDirectoryEntryFileOffset
;
325 UINTN SectionHeaderOffset
;
326 EFI_IMAGE_SECTION_HEADER SectionHeader
;
327 EFI_IMAGE_DEBUG_DIRECTORY_ENTRY DebugEntry
;
329 if (NULL
== ImageContext
) {
330 return EFI_INVALID_PARAMETER
;
335 ImageContext
->ImageError
= EFI_IMAGE_ERROR_SUCCESS
;
337 Status
= PeCoffLoaderGetPeHeader (ImageContext
, &PeHdr
, &TeHdr
);
338 if (EFI_ERROR (Status
)) {
342 // Verify machine type
344 Status
= PeCoffLoaderCheckImageType (ImageContext
, &PeHdr
, &TeHdr
);
345 if (EFI_ERROR (Status
)) {
349 // Retrieve the base address of the image
351 if (!(ImageContext
->IsTeImage
)) {
352 ImageContext
->ImageAddress
= PeHdr
.OptionalHeader
.ImageBase
;
354 ImageContext
->ImageAddress
= (EFI_PHYSICAL_ADDRESS
) (TeHdr
.ImageBase
);
357 // Initialize the alternate destination address to 0 indicating that it
358 // should not be used.
360 ImageContext
->DestinationAddress
= 0;
363 // Initialize the codeview pointer.
365 ImageContext
->CodeView
= NULL
;
366 ImageContext
->PdbPointer
= NULL
;
369 // Three cases with regards to relocations:
370 // - Image has base relocs, RELOCS_STRIPPED==0 => image is relocatable
371 // - Image has no base relocs, RELOCS_STRIPPED==1 => Image is not relocatable
372 // - Image has no base relocs, RELOCS_STRIPPED==0 => Image is relocatable but
373 // has no base relocs to apply
374 // Obviously having base relocations with RELOCS_STRIPPED==1 is invalid.
376 // Look at the file header to determine if relocations have been stripped, and
377 // save this info in the image context for later use.
379 if ((!(ImageContext
->IsTeImage
)) && ((PeHdr
.FileHeader
.Characteristics
& EFI_IMAGE_FILE_RELOCS_STRIPPED
) != 0)) {
380 ImageContext
->RelocationsStripped
= TRUE
;
382 ImageContext
->RelocationsStripped
= FALSE
;
385 if (!(ImageContext
->IsTeImage
)) {
386 ImageContext
->ImageSize
= (UINT64
) PeHdr
.OptionalHeader
.SizeOfImage
;
387 ImageContext
->SectionAlignment
= PeHdr
.OptionalHeader
.SectionAlignment
;
388 ImageContext
->SizeOfHeaders
= PeHdr
.OptionalHeader
.SizeOfHeaders
;
391 // Modify ImageSize to contain .PDB file name if required and initialize
394 if (PeHdr
.OptionalHeader
.NumberOfRvaAndSizes
> EFI_IMAGE_DIRECTORY_ENTRY_DEBUG
) {
395 DebugDirectoryEntry
= (EFI_IMAGE_DATA_DIRECTORY
*) &(PeHdr
.OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG
]);
397 DebugDirectoryEntryRva
= DebugDirectoryEntry
->VirtualAddress
;
400 // Determine the file offset of the debug directory... This means we walk
401 // the sections to find which section contains the RVA of the debug
404 DebugDirectoryEntryFileOffset
= 0;
406 SectionHeaderOffset
= (UINTN
)(
407 ImageContext
->PeCoffHeaderOffset
+
409 sizeof (EFI_IMAGE_FILE_HEADER
) +
410 PeHdr
.FileHeader
.SizeOfOptionalHeader
413 for (Index
= 0; Index
< PeHdr
.FileHeader
.NumberOfSections
; Index
++) {
415 // Read section header from file
417 Size
= sizeof (EFI_IMAGE_SECTION_HEADER
);
418 Status
= ImageContext
->ImageRead (
419 ImageContext
->Handle
,
424 if (EFI_ERROR (Status
)) {
425 ImageContext
->ImageError
= EFI_IMAGE_ERROR_IMAGE_READ
;
429 if (DebugDirectoryEntryRva
>= SectionHeader
.VirtualAddress
&&
430 DebugDirectoryEntryRva
< SectionHeader
.VirtualAddress
+ SectionHeader
.Misc
.VirtualSize
) {
431 DebugDirectoryEntryFileOffset
=
432 DebugDirectoryEntryRva
- SectionHeader
.VirtualAddress
+ SectionHeader
.PointerToRawData
;
436 SectionHeaderOffset
+= sizeof (EFI_IMAGE_SECTION_HEADER
);
439 if (DebugDirectoryEntryFileOffset
!= 0) {
440 for (Index
= 0; Index
< DebugDirectoryEntry
->Size
; Index
++) {
442 // Read next debug directory entry
444 Size
= sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
);
445 Status
= ImageContext
->ImageRead (
446 ImageContext
->Handle
,
447 DebugDirectoryEntryFileOffset
,
451 if (EFI_ERROR (Status
)) {
452 ImageContext
->ImageError
= EFI_IMAGE_ERROR_IMAGE_READ
;
456 if (DebugEntry
.Type
== EFI_IMAGE_DEBUG_TYPE_CODEVIEW
) {
457 ImageContext
->DebugDirectoryEntryRva
= (UINT32
) (DebugDirectoryEntryRva
+ Index
* sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
));
458 if (DebugEntry
.RVA
== 0 && DebugEntry
.FileOffset
!= 0) {
459 ImageContext
->ImageSize
+= DebugEntry
.SizeOfData
;
468 ImageContext
->ImageSize
= 0;
469 ImageContext
->SectionAlignment
= 4096;
470 ImageContext
->SizeOfHeaders
= sizeof (EFI_TE_IMAGE_HEADER
) + (UINTN
) TeHdr
.BaseOfCode
- (UINTN
) TeHdr
.StrippedSize
;
472 DebugDirectoryEntry
= &TeHdr
.DataDirectory
[1];
473 DebugDirectoryEntryRva
= DebugDirectoryEntry
->VirtualAddress
;
474 SectionHeaderOffset
= (UINTN
) (sizeof (EFI_TE_IMAGE_HEADER
));
476 DebugDirectoryEntryFileOffset
= 0;
478 for (Index
= 0; Index
< TeHdr
.NumberOfSections
;) {
480 // Read section header from file
482 Size
= sizeof (EFI_IMAGE_SECTION_HEADER
);
483 Status
= ImageContext
->ImageRead (
484 ImageContext
->Handle
,
489 if (EFI_ERROR (Status
)) {
490 ImageContext
->ImageError
= EFI_IMAGE_ERROR_IMAGE_READ
;
494 if (DebugDirectoryEntryRva
>= SectionHeader
.VirtualAddress
&&
495 DebugDirectoryEntryRva
< SectionHeader
.VirtualAddress
+ SectionHeader
.Misc
.VirtualSize
) {
496 DebugDirectoryEntryFileOffset
= DebugDirectoryEntryRva
-
497 SectionHeader
.VirtualAddress
+
498 SectionHeader
.PointerToRawData
+
499 sizeof (EFI_TE_IMAGE_HEADER
) -
503 // File offset of the debug directory was found, if this is not the last
504 // section, then skip to the last section for calculating the image size.
506 if (Index
< (UINTN
) TeHdr
.NumberOfSections
- 1) {
507 SectionHeaderOffset
+= (TeHdr
.NumberOfSections
- 1 - Index
) * sizeof (EFI_IMAGE_SECTION_HEADER
);
508 Index
= TeHdr
.NumberOfSections
- 1;
514 // In Te image header there is not a field to describe the ImageSize.
515 // Actually, the ImageSize equals the RVA plus the VirtualSize of
516 // the last section mapped into memory (Must be rounded up to
517 // a mulitple of Section Alignment). Per the PE/COFF specification, the
518 // section headers in the Section Table must appear in order of the RVA
519 // values for the corresponding sections. So the ImageSize can be determined
520 // by the RVA and the VirtualSize of the last section header in the
523 if ((++Index
) == (UINTN
) TeHdr
.NumberOfSections
) {
524 ImageContext
->ImageSize
= (SectionHeader
.VirtualAddress
+ SectionHeader
.Misc
.VirtualSize
+
525 ImageContext
->SectionAlignment
- 1) & ~(ImageContext
->SectionAlignment
- 1);
528 SectionHeaderOffset
+= sizeof (EFI_IMAGE_SECTION_HEADER
);
531 if (DebugDirectoryEntryFileOffset
!= 0) {
532 for (Index
= 0; Index
< DebugDirectoryEntry
->Size
; Index
++) {
534 // Read next debug directory entry
536 Size
= sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
);
537 Status
= ImageContext
->ImageRead (
538 ImageContext
->Handle
,
539 DebugDirectoryEntryFileOffset
,
543 if (EFI_ERROR (Status
)) {
544 ImageContext
->ImageError
= EFI_IMAGE_ERROR_IMAGE_READ
;
548 if (DebugEntry
.Type
== EFI_IMAGE_DEBUG_TYPE_CODEVIEW
) {
549 ImageContext
->DebugDirectoryEntryRva
= (UINT32
) (DebugDirectoryEntryRva
+ Index
* sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
));
561 PeCoffLoaderImageAddress (
562 IN OUT EFI_PEI_PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
,
569 Converts an image address to the loaded address
573 ImageContext - The context of the image being loaded
575 Address - The address to be converted to the loaded address
579 NULL if the address can not be converted, otherwise, the converted address
583 if (Address
>= ImageContext
->ImageSize
) {
584 ImageContext
->ImageError
= EFI_IMAGE_ERROR_INVALID_IMAGE_ADDRESS
;
588 return (CHAR8
*) ((UINTN
) ImageContext
->ImageAddress
+ Address
);
593 PeCoffLoaderRelocateImage (
594 IN EFI_PEI_PE_COFF_LOADER_PROTOCOL
*This
,
595 IN OUT EFI_PEI_PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
601 Relocates a PE/COFF image in memory
605 This - Calling context
607 ImageContext - Contains information on the loaded image to relocate
611 EFI_SUCCESS if the PE/COFF image was relocated
612 EFI_LOAD_ERROR if the image is not a valid PE/COFF image
613 EFI_UNSUPPORTED not support
618 EFI_IMAGE_NT_HEADERS
*PeHdr
;
619 EFI_TE_IMAGE_HEADER
*TeHdr
;
620 EFI_IMAGE_DATA_DIRECTORY
*RelocDir
;
622 EFI_IMAGE_BASE_RELOCATION
*RelocBase
;
623 EFI_IMAGE_BASE_RELOCATION
*RelocBaseEnd
;
631 EFI_PHYSICAL_ADDRESS BaseAddress
;
638 ImageContext
->ImageError
= EFI_IMAGE_ERROR_SUCCESS
;
641 // If there are no relocation entries, then we are done
643 if (ImageContext
->RelocationsStripped
) {
648 // If the destination address is not 0, use that rather than the
649 // image address as the relocation target.
651 if (ImageContext
->DestinationAddress
) {
652 BaseAddress
= ImageContext
->DestinationAddress
;
654 BaseAddress
= ImageContext
->ImageAddress
;
657 if (!(ImageContext
->IsTeImage
)) {
658 PeHdr
= (EFI_IMAGE_NT_HEADERS
*)((UINTN
)ImageContext
->ImageAddress
+
659 ImageContext
->PeCoffHeaderOffset
);
660 Adjust
= (UINT64
) BaseAddress
- PeHdr
->OptionalHeader
.ImageBase
;
661 PeHdr
->OptionalHeader
.ImageBase
= (UINTN
) BaseAddress
;
664 // Find the relocation block
666 // Per the PE/COFF spec, you can't assume that a given data directory
667 // is present in the image. You have to check the NumberOfRvaAndSizes in
668 // the optional header to verify a desired directory entry is there.
670 if (PeHdr
->OptionalHeader
.NumberOfRvaAndSizes
> EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
) {
671 RelocDir
= &PeHdr
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
];
672 RelocBase
= PeCoffLoaderImageAddress (ImageContext
, RelocDir
->VirtualAddress
);
673 RelocBaseEnd
= PeCoffLoaderImageAddress (
675 RelocDir
->VirtualAddress
+ RelocDir
->Size
- 1
679 // Set base and end to bypass processing below.
681 RelocBase
= RelocBaseEnd
= 0;
684 TeHdr
= (EFI_TE_IMAGE_HEADER
*) (UINTN
) (ImageContext
->ImageAddress
);
685 Adjust
= (UINT64
) (BaseAddress
- TeHdr
->ImageBase
);
686 TeHdr
->ImageBase
= (UINT64
) (BaseAddress
);
689 // Find the relocation block
691 RelocDir
= &TeHdr
->DataDirectory
[0];
692 RelocBase
= (EFI_IMAGE_BASE_RELOCATION
*)(UINTN
)(
693 ImageContext
->ImageAddress
+
694 RelocDir
->VirtualAddress
+
695 sizeof(EFI_TE_IMAGE_HEADER
) -
698 RelocBaseEnd
= (EFI_IMAGE_BASE_RELOCATION
*) ((UINTN
) RelocBase
+ (UINTN
) RelocDir
->Size
- 1);
702 // Run the relocation information and apply the fixups
704 FixupData
= ImageContext
->FixupData
;
705 while (RelocBase
< RelocBaseEnd
) {
707 Reloc
= (UINT16
*) ((CHAR8
*) RelocBase
+ sizeof (EFI_IMAGE_BASE_RELOCATION
));
708 RelocEnd
= (UINT16
*) ((CHAR8
*) RelocBase
+ RelocBase
->SizeOfBlock
);
709 if (!(ImageContext
->IsTeImage
)) {
710 FixupBase
= PeCoffLoaderImageAddress (ImageContext
, RelocBase
->VirtualAddress
);
712 FixupBase
= (CHAR8
*)(UINTN
)(ImageContext
->ImageAddress
+
713 RelocBase
->VirtualAddress
+
714 sizeof(EFI_TE_IMAGE_HEADER
) -
719 if ((CHAR8
*) RelocEnd
< (CHAR8
*) ((UINTN
) ImageContext
->ImageAddress
) ||
720 (CHAR8
*) RelocEnd
> (CHAR8
*)((UINTN
)ImageContext
->ImageAddress
+
721 (UINTN
)ImageContext
->ImageSize
)) {
722 ImageContext
->ImageError
= EFI_IMAGE_ERROR_FAILED_RELOCATION
;
723 return EFI_LOAD_ERROR
;
727 // Run this relocation record
729 while (Reloc
< RelocEnd
) {
731 Fixup
= FixupBase
+ (*Reloc
& 0xFFF);
732 switch ((*Reloc
) >> 12) {
733 case EFI_IMAGE_REL_BASED_ABSOLUTE
:
736 case EFI_IMAGE_REL_BASED_HIGH
:
737 F16
= (UINT16
*) Fixup
;
738 *F16
= (UINT16
) ((*F16
<< 16) + (UINT16
) Adjust
);
739 if (FixupData
!= NULL
) {
740 *(UINT16
*) FixupData
= *F16
;
741 FixupData
= FixupData
+ sizeof (UINT16
);
745 case EFI_IMAGE_REL_BASED_LOW
:
746 F16
= (UINT16
*) Fixup
;
747 *F16
= (UINT16
) (*F16
+ (UINT16
) Adjust
);
748 if (FixupData
!= NULL
) {
749 *(UINT16
*) FixupData
= *F16
;
750 FixupData
= FixupData
+ sizeof (UINT16
);
754 case EFI_IMAGE_REL_BASED_HIGHLOW
:
755 F32
= (UINT32
*) Fixup
;
756 *F32
= *F32
+ (UINT32
) Adjust
;
757 if (FixupData
!= NULL
) {
758 FixupData
= ALIGN_POINTER (FixupData
, sizeof (UINT32
));
759 *(UINT32
*) FixupData
= *F32
;
760 FixupData
= FixupData
+ sizeof (UINT32
);
764 case EFI_IMAGE_REL_BASED_HIGHADJ
:
766 // Return the same EFI_UNSUPPORTED return code as
767 // PeCoffLoaderRelocateImageEx() returns if it does not recognize
768 // the relocation type.
770 ImageContext
->ImageError
= EFI_IMAGE_ERROR_FAILED_RELOCATION
;
771 return EFI_UNSUPPORTED
;
774 Status
= PeCoffLoaderRelocateImageEx (Reloc
, Fixup
, &FixupData
, Adjust
);
775 if (EFI_ERROR (Status
)) {
776 ImageContext
->ImageError
= EFI_IMAGE_ERROR_FAILED_RELOCATION
;
782 // Next relocation record
790 RelocBase
= (EFI_IMAGE_BASE_RELOCATION
*) RelocEnd
;
798 PeCoffLoaderLoadImage (
799 IN EFI_PEI_PE_COFF_LOADER_PROTOCOL
*This
,
800 IN OUT EFI_PEI_PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
806 Loads a PE/COFF image into memory
810 This - Calling context
812 ImageContext - Contains information on image to load into memory
816 EFI_SUCCESS if the PE/COFF image was loaded
817 EFI_BUFFER_TOO_SMALL if the caller did not provide a large enough buffer
818 EFI_LOAD_ERROR if the image is a runtime driver with no relocations
819 EFI_INVALID_PARAMETER if the image address is invalid
824 EFI_IMAGE_NT_HEADERS
*PeHdr
;
825 EFI_TE_IMAGE_HEADER
*TeHdr
;
826 EFI_PEI_PE_COFF_LOADER_IMAGE_CONTEXT CheckContext
;
827 EFI_IMAGE_SECTION_HEADER
*FirstSection
;
828 EFI_IMAGE_SECTION_HEADER
*Section
;
829 UINTN NumberOfSections
;
834 EFI_IMAGE_DATA_DIRECTORY
*DirectoryEntry
;
835 EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
*DebugEntry
;
837 UINT32 TempDebugEntryRva
;
844 ImageContext
->ImageError
= EFI_IMAGE_ERROR_SUCCESS
;
847 // Copy the provided context info into our local version, get what we
848 // can from the original image, and then use that to make sure everything
851 CopyMem (&CheckContext
, ImageContext
, sizeof (EFI_PEI_PE_COFF_LOADER_IMAGE_CONTEXT
));
853 Status
= PeCoffLoaderGetImageInfo (
857 if (EFI_ERROR (Status
)) {
862 // Make sure there is enough allocated space for the image being loaded
864 if (ImageContext
->ImageSize
< CheckContext
.ImageSize
) {
865 ImageContext
->ImageError
= EFI_IMAGE_ERROR_INVALID_IMAGE_SIZE
;
866 return EFI_BUFFER_TOO_SMALL
;
870 // If there's no relocations, then make sure it's not a runtime driver,
871 // and that it's being loaded at the linked address.
873 if (CheckContext
.RelocationsStripped
) {
875 // If the image does not contain relocations and it is a runtime driver
876 // then return an error.
878 if (CheckContext
.ImageType
== EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER
) {
879 ImageContext
->ImageError
= EFI_IMAGE_ERROR_INVALID_SUBSYSTEM
;
880 return EFI_LOAD_ERROR
;
883 // If the image does not contain relocations, and the requested load address
884 // is not the linked address, then return an error.
886 if (CheckContext
.ImageAddress
!= ImageContext
->ImageAddress
) {
887 ImageContext
->ImageError
= EFI_IMAGE_ERROR_INVALID_IMAGE_ADDRESS
;
888 return EFI_INVALID_PARAMETER
;
892 // Make sure the allocated space has the proper section alignment
894 if (!(ImageContext
->IsTeImage
)) {
895 if ((ImageContext
->ImageAddress
& (CheckContext
.SectionAlignment
- 1)) != 0) {
896 ImageContext
->ImageError
= EFI_IMAGE_ERROR_INVALID_SECTION_ALIGNMENT
;
897 return EFI_INVALID_PARAMETER
;
901 // Read the entire PE/COFF or TE header into memory
903 if (!(ImageContext
->IsTeImage
)) {
904 Status
= ImageContext
->ImageRead (
905 ImageContext
->Handle
,
907 &ImageContext
->SizeOfHeaders
,
908 (VOID
*) (UINTN
) ImageContext
->ImageAddress
911 PeHdr
= (EFI_IMAGE_NT_HEADERS
*)
912 ((UINTN
)ImageContext
->ImageAddress
+ ImageContext
->PeCoffHeaderOffset
);
914 FirstSection
= (EFI_IMAGE_SECTION_HEADER
*) (
915 (UINTN
)ImageContext
->ImageAddress
+
916 ImageContext
->PeCoffHeaderOffset
+
918 sizeof(EFI_IMAGE_FILE_HEADER
) +
919 PeHdr
->FileHeader
.SizeOfOptionalHeader
921 NumberOfSections
= (UINTN
) (PeHdr
->FileHeader
.NumberOfSections
);
923 Status
= ImageContext
->ImageRead (
924 ImageContext
->Handle
,
926 &ImageContext
->SizeOfHeaders
,
927 (void *) (UINTN
) ImageContext
->ImageAddress
930 TeHdr
= (EFI_TE_IMAGE_HEADER
*) (UINTN
) (ImageContext
->ImageAddress
);
932 FirstSection
= (EFI_IMAGE_SECTION_HEADER
*) (
933 (UINTN
)ImageContext
->ImageAddress
+
934 sizeof(EFI_TE_IMAGE_HEADER
)
936 NumberOfSections
= (UINTN
) (TeHdr
->NumberOfSections
);
940 if (EFI_ERROR (Status
)) {
941 ImageContext
->ImageError
= EFI_IMAGE_ERROR_IMAGE_READ
;
942 return EFI_LOAD_ERROR
;
946 // Load each section of the image
948 Section
= FirstSection
;
949 for (Index
= 0, MaxEnd
= NULL
; Index
< NumberOfSections
; Index
++) {
952 // Compute sections address
954 Base
= PeCoffLoaderImageAddress (ImageContext
, Section
->VirtualAddress
);
955 End
= PeCoffLoaderImageAddress (
957 Section
->VirtualAddress
+ Section
->Misc
.VirtualSize
- 1
959 if (ImageContext
->IsTeImage
) {
960 Base
= (CHAR8
*) ((UINTN
) Base
+ sizeof (EFI_TE_IMAGE_HEADER
) - (UINTN
) TeHdr
->StrippedSize
);
961 End
= (CHAR8
*) ((UINTN
) End
+ sizeof (EFI_TE_IMAGE_HEADER
) - (UINTN
) TeHdr
->StrippedSize
);
968 // If the base start or end address resolved to 0, then fail.
970 if ((Base
== NULL
) || (End
== NULL
)) {
971 ImageContext
->ImageError
= EFI_IMAGE_ERROR_SECTION_NOT_LOADED
;
972 return EFI_LOAD_ERROR
;
978 Size
= (UINTN
) Section
->Misc
.VirtualSize
;
979 if ((Size
== 0) || (Size
> Section
->SizeOfRawData
)) {
980 Size
= (UINTN
) Section
->SizeOfRawData
;
983 if (Section
->SizeOfRawData
) {
984 if (!(ImageContext
->IsTeImage
)) {
985 Status
= ImageContext
->ImageRead (
986 ImageContext
->Handle
,
987 Section
->PointerToRawData
,
992 Status
= ImageContext
->ImageRead (
993 ImageContext
->Handle
,
994 Section
->PointerToRawData
+ sizeof (EFI_TE_IMAGE_HEADER
) - (UINTN
) TeHdr
->StrippedSize
,
1000 if (EFI_ERROR (Status
)) {
1001 ImageContext
->ImageError
= EFI_IMAGE_ERROR_IMAGE_READ
;
1007 // If raw size is less then virt size, zero fill the remaining
1010 if (Size
< Section
->Misc
.VirtualSize
) {
1011 ZeroMem (Base
+ Size
, Section
->Misc
.VirtualSize
- Size
);
1021 // Get image's entry point
1023 if (!(ImageContext
->IsTeImage
)) {
1024 ImageContext
->EntryPoint
= (EFI_PHYSICAL_ADDRESS
) (UINTN
) PeCoffLoaderImageAddress (
1026 PeHdr
->OptionalHeader
.AddressOfEntryPoint
1029 ImageContext
->EntryPoint
= (EFI_PHYSICAL_ADDRESS
) (
1030 (UINTN
)ImageContext
->ImageAddress
+
1031 (UINTN
)TeHdr
->AddressOfEntryPoint
+
1032 (UINTN
)sizeof(EFI_TE_IMAGE_HEADER
) -
1033 (UINTN
) TeHdr
->StrippedSize
1038 // Determine the size of the fixup data
1040 // Per the PE/COFF spec, you can't assume that a given data directory
1041 // is present in the image. You have to check the NumberOfRvaAndSizes in
1042 // the optional header to verify a desired directory entry is there.
1044 if (!(ImageContext
->IsTeImage
)) {
1045 if (PeHdr
->OptionalHeader
.NumberOfRvaAndSizes
> EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
) {
1046 DirectoryEntry
= (EFI_IMAGE_DATA_DIRECTORY
*)
1047 &PeHdr
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
];
1048 ImageContext
->FixupDataSize
= DirectoryEntry
->Size
/ sizeof (UINT16
) * sizeof (UINTN
);
1050 ImageContext
->FixupDataSize
= 0;
1053 DirectoryEntry
= &TeHdr
->DataDirectory
[0];
1054 ImageContext
->FixupDataSize
= DirectoryEntry
->Size
/ sizeof (UINT16
) * sizeof (UINTN
);
1057 // Consumer must allocate a buffer for the relocation fixup log.
1058 // Only used for runtime drivers.
1060 ImageContext
->FixupData
= NULL
;
1063 // Load the Codeview info if present
1065 if (ImageContext
->DebugDirectoryEntryRva
!= 0) {
1066 if (!(ImageContext
->IsTeImage
)) {
1067 DebugEntry
= PeCoffLoaderImageAddress (
1069 ImageContext
->DebugDirectoryEntryRva
1072 DebugEntry
= (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
*)(UINTN
)(
1073 ImageContext
->ImageAddress
+
1074 ImageContext
->DebugDirectoryEntryRva
+
1075 sizeof(EFI_TE_IMAGE_HEADER
) -
1080 if (DebugEntry
!= NULL
) {
1081 TempDebugEntryRva
= DebugEntry
->RVA
;
1082 if (DebugEntry
->RVA
== 0 && DebugEntry
->FileOffset
!= 0) {
1084 if ((UINTN
) Section
->SizeOfRawData
< Section
->Misc
.VirtualSize
) {
1085 TempDebugEntryRva
= Section
->VirtualAddress
+ Section
->Misc
.VirtualSize
;
1087 TempDebugEntryRva
= Section
->VirtualAddress
+ Section
->SizeOfRawData
;
1091 if (TempDebugEntryRva
!= 0) {
1092 if (!(ImageContext
->IsTeImage
)) {
1093 ImageContext
->CodeView
= PeCoffLoaderImageAddress (ImageContext
, TempDebugEntryRva
);
1095 ImageContext
->CodeView
= (VOID
*)(
1096 (UINTN
)ImageContext
->ImageAddress
+
1097 (UINTN
)TempDebugEntryRva
+
1098 (UINTN
)sizeof(EFI_TE_IMAGE_HEADER
) -
1099 (UINTN
) TeHdr
->StrippedSize
1103 if (ImageContext
->CodeView
== NULL
) {
1104 ImageContext
->ImageError
= EFI_IMAGE_ERROR_IMAGE_READ
;
1105 return EFI_LOAD_ERROR
;
1108 if (DebugEntry
->RVA
== 0) {
1109 Size
= DebugEntry
->SizeOfData
;
1110 if (!(ImageContext
->IsTeImage
)) {
1111 Status
= ImageContext
->ImageRead (
1112 ImageContext
->Handle
,
1113 DebugEntry
->FileOffset
,
1115 ImageContext
->CodeView
1118 Status
= ImageContext
->ImageRead (
1119 ImageContext
->Handle
,
1120 DebugEntry
->FileOffset
+ sizeof (EFI_TE_IMAGE_HEADER
) - TeHdr
->StrippedSize
,
1122 ImageContext
->CodeView
1125 // Should we apply fix up to this field according to the size difference between PE and TE?
1126 // Because now we maintain TE header fields unfixed, this field will also remain as they are
1127 // in original PE image.
1131 if (EFI_ERROR (Status
)) {
1132 ImageContext
->ImageError
= EFI_IMAGE_ERROR_IMAGE_READ
;
1133 return EFI_LOAD_ERROR
;
1136 DebugEntry
->RVA
= TempDebugEntryRva
;
1139 switch (*(UINT32
*) ImageContext
->CodeView
) {
1140 case CODEVIEW_SIGNATURE_NB10
:
1141 ImageContext
->PdbPointer
= (CHAR8
*) ImageContext
->CodeView
+ sizeof (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY
);
1144 case CODEVIEW_SIGNATURE_RSDS
:
1145 ImageContext
->PdbPointer
= (CHAR8
*) ImageContext
->CodeView
+ sizeof (EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY
);
1160 PeCoffLoaderUnloadImage (
1161 IN EFI_PEI_PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
1165 Routine Description:
1167 Unload a PE/COFF image from memory
1171 ImageContext - Contains information on image to load into memory