3 Copyright (c) 1999-2006 Intel Corporation. All rights reserved
4 This program and the accompanying materials are licensed and made available
5 under the terms and conditions of the BSD License which accompanies this
6 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.
19 This contains all code necessary to build the PeiRebase.exe utility.
20 This utility relies heavily on the PeiRebase DLL. Definitions for both
21 can be found in the PEI Rebase Utility Specification, review draft.
29 #include <Common/UefiBaseTypes.h>
30 #include <Common/FirmwareVolumeImageFormat.h>
31 #include <Common/FirmwareFileSystem.h>
32 #include <Library/PeCoffLib.h>
34 #include "CommonLib.h"
37 #include "EfiUtilityMsgs.h"
38 #include "PeiRebaseExe.h"
44 OUT BOOLEAN
*ErasePolarity
56 This utility relocates PEI XIP PE32s in a FV.
60 argc - Number of command line arguments
62 BaseAddress The base address to use for rebasing the FV. The correct
63 format is a hex number preceded by 0x.
64 InputFileName The name of the input FV file.
65 OutputFileName The name of the output FV file.
67 Arguments come in pair in any order.
74 0 No error conditions detected.
75 1 One or more of the input parameters is invalid.
76 2 A resource required by the utility was unavailable.
77 Most commonly this will be memory allocation or file creation.
78 3 PeiRebase.dll could not be loaded.
79 4 Error executing the PEI rebase.
84 CHAR8 InputFileName
[_MAX_PATH
];
85 CHAR8
*OutputFileName
;
86 EFI_PHYSICAL_ADDRESS XipBase
, BsBase
, RtBase
;
95 EFI_FIRMWARE_VOLUME_HEADER
*FvImage
;
97 EFI_FFS_FILE_HEADER
*CurrentFile
;
98 BOOLEAN ErasePolarity
;
99 MEMORY_FILE InfMemoryFile
;
100 CHAR8 StringBuffer
[0x100];
102 ErasePolarity
= FALSE
;
104 // Set utility name for error/warning reporting purposes.
106 SetUtilityName (UTILITY_NAME
);
108 // Verify the correct number of arguments
110 if (argc
!= MAX_ARGS
) {
116 // Initialize variables
118 InputFileName
[0] = '\0';
119 OutputFileName
= NULL
;
120 XipBase
= BsBase
= RtBase
= 0;
124 ErasePolarity
= FALSE
;
131 // Parse the command line arguments
133 for (Index
= 1; Index
< MAX_ARGS
; Index
+= 2) {
135 // Make sure argument pair begin with - or /
137 if (argv
[Index
][0] != '-' && argv
[Index
][0] != '/') {
139 Error (NULL
, 0, 0, argv
[Index
], "unrecognized option");
143 // Make sure argument specifier is only one letter
145 if (argv
[Index
][2] != 0) {
147 Error (NULL
, 0, 0, argv
[Index
], "unrecognized option");
151 // Determine argument to read
153 switch (argv
[Index
][1]) {
156 if (strlen (InputFileName
) == 0) {
157 strcpy (InputFileName
, argv
[Index
+ 1]);
160 Error (NULL
, 0, 0, argv
[Index
+ 1], "only one -i InputFileName may be specified");
167 if (OutputFileName
== NULL
) {
168 OutputFileName
= argv
[Index
+ 1];
171 Error (NULL
, 0, 0, argv
[Index
+ 1], "only one -o OutputFileName may be specified");
179 // Load INF file into memory & initialize MEMORY_FILE structure
181 Status
= GetFileImage (argv
[Index
+ 1], &InfMemoryFile
.FileImage
, (UINT32
*)&InfMemoryFile
.Eof
);
182 InfMemoryFile
.Eof
= InfMemoryFile
.FileImage
+ (UINT32
)(UINTN
)InfMemoryFile
.Eof
;
183 InfMemoryFile
.CurrentFilePointer
= InfMemoryFile
.FileImage
;
184 if (EFI_ERROR (Status
)) {
185 Error (NULL
, 0, 0, argv
[Index
+ 1], "Error opening FvInfFile");
190 // Read BaseAddress from fv.inf file
192 FindToken (&InfMemoryFile
, "[options]", "EFI_BASE_ADDRESS", 0, StringBuffer
);
195 // Free INF file image
197 free (InfMemoryFile
.FileImage
);
200 // Point argv[Index + 1] to StringBuffer so that it could be processed as "-b"
202 argv
[Index
+ 1] = StringBuffer
;
208 Error (NULL
, 0, 0, argv
[Index
+ 1], "XipBaseAddress may be specified only once by either -b or -f");
212 Status
= AsciiStringToUint64 (argv
[Index
+ 1], FALSE
, &XipBase
);
213 if (EFI_ERROR (Status
)) {
215 Error (NULL
, 0, 0, argv
[Index
+ 1], "invalid hex digit given for XIP base address");
226 Error (NULL
, 0, 0, argv
[Index
+ 1], "-d BsBaseAddress may be specified only once");
230 Status
= AsciiStringToUint64 (argv
[Index
+ 1], FALSE
, &BsBase
);
231 if (EFI_ERROR (Status
)) {
233 Error (NULL
, 0, 0, argv
[Index
+ 1], "invalid hex digit given for BS_DRIVER base address");
244 Error (NULL
, 0, 0, argv
[Index
+ 1], "-r RtBaseAddress may be specified only once");
248 Status
= AsciiStringToUint64 (argv
[Index
+ 1], FALSE
, &RtBase
);
249 if (EFI_ERROR (Status
)) {
251 Error (NULL
, 0, 0, argv
[Index
+ 1], "invalid hex digit given for RT_DRIVER base address");
260 Error (NULL
, 0, 0, argv
[Index
], "unrecognized argument");
266 // Open the file containing the FV
268 InputFile
= fopen (InputFileName
, "rb");
269 if (InputFile
== NULL
) {
270 Error (NULL
, 0, 0, InputFileName
, "could not open input file for reading");
277 strcat (InputFileName
, ".log");
278 LogFile
= fopen (InputFileName
, "a");
279 if (LogFile
== NULL
) {
280 Error (NULL
, 0, 0, InputFileName
, "could not append to log file");
284 // Determine size of FV
286 Status
= ReadHeader (InputFile
, &FvSize
, &ErasePolarity
);
287 if (EFI_ERROR (Status
)) {
288 Error (NULL
, 0, 0, "could not parse the FV header", NULL
);
292 // Allocate a buffer for the FV image
294 FvImage
= malloc (FvSize
);
295 if (FvImage
== NULL
) {
296 Error (NULL
, 0, 0, "application error", "memory allocation failed");
300 // Read the entire FV to the buffer
302 BytesRead
= fread (FvImage
, 1, FvSize
, InputFile
);
305 if ((unsigned int) BytesRead
!= FvSize
) {
306 Error (NULL
, 0, 0, InputFileName
, "failed to read from file");
310 // Prepare to walk the FV image
312 InitializeFvLib (FvImage
, FvSize
);
314 // Get the first file
316 Status
= GetNextFile (NULL
, &CurrentFile
);
317 if (EFI_ERROR (Status
)) {
318 Error (NULL
, 0, 0, "cannot find the first file in the FV image", NULL
);
322 // Check if each file should be rebased
324 while (CurrentFile
!= NULL
) {
331 XipBase
+ (UINTN
)CurrentFile
- (UINTN
)FvImage
,
337 if (EFI_ERROR (Status
)) {
340 case EFI_INVALID_PARAMETER
:
341 Error (NULL
, 0, 0, "invalid parameter passed to FfsRebase", NULL
);
345 Error (NULL
, 0, 0, "error detected while rebasing -- aborted", NULL
);
348 case EFI_OUT_OF_RESOURCES
:
349 Error (NULL
, 0, 0, "FfsRebase could not allocate required resources", NULL
);
353 Error (NULL
, 0, 0, "FfsRebase could not locate a PE32 section", NULL
);
357 Error (NULL
, 0, 0, "FfsRebase returned unknown status", "status=0x%08X", Status
);
366 Status
= GetNextFile (CurrentFile
, &CurrentFile
);
367 if (EFI_ERROR (Status
)) {
368 Error (NULL
, 0, 0, "cannot find the next file in the FV image", NULL
);
373 // Open the output file
375 OutputFile
= fopen (OutputFileName
, "wb");
376 if (OutputFile
== NULL
) {
377 Error (NULL
, 0, 0, OutputFileName
, "failed to open output file");
381 if (fwrite (FvImage
, 1, FvSize
, OutputFile
) != FvSize
) {
382 Error (NULL
, 0, 0, "failed to write to output file", 0);
387 if (InputFile
!= NULL
) {
391 // If we created an output file, and there was an error, remove it so
392 // subsequent builds will rebuild it.
394 if (OutputFile
!= NULL
) {
395 if (GetUtilityStatus () == STATUS_ERROR
) {
396 remove (OutputFileName
);
402 if (LogFile
!= NULL
) {
406 if (FvImage
!= NULL
) {
410 return GetUtilityStatus ();
417 OUT BOOLEAN
*ErasePolarity
423 This function determines the size of the FV and the erase polarity. The
424 erase polarity is the FALSE value for file state.
428 InputFile The file that contains the FV image.
429 FvSize The size of the FV.
430 ErasePolarity The FV erase polarity.
434 EFI_SUCCESS Function completed successfully.
435 EFI_INVALID_PARAMETER A required parameter was NULL or is out of range.
436 EFI_ABORTED The function encountered an error.
440 EFI_FIRMWARE_VOLUME_HEADER VolumeHeader
;
441 EFI_FV_BLOCK_MAP_ENTRY BlockMap
;
449 // Check input parameters
451 if ((InputFile
== NULL
) || (FvSize
== NULL
) || (ErasePolarity
== NULL
)) {
452 Error (NULL
, 0, 0, "ReadHeader()", "invalid input parameter");
453 return EFI_INVALID_PARAMETER
;
458 fread (&VolumeHeader
, sizeof (EFI_FIRMWARE_VOLUME_HEADER
) - sizeof (EFI_FV_BLOCK_MAP_ENTRY
), 1, InputFile
);
459 BytesRead
= sizeof (EFI_FIRMWARE_VOLUME_HEADER
) - sizeof (EFI_FV_BLOCK_MAP_ENTRY
);
460 Signature
[0] = VolumeHeader
.Signature
;
464 // Get erase polarity
466 if (VolumeHeader
.Attributes
& EFI_FVB_ERASE_POLARITY
) {
467 *ErasePolarity
= TRUE
;
471 fread (&BlockMap
, sizeof (EFI_FV_BLOCK_MAP_ENTRY
), 1, InputFile
);
472 BytesRead
+= sizeof (EFI_FV_BLOCK_MAP_ENTRY
);
474 if (BlockMap
.NumBlocks
!= 0) {
475 Size
+= BlockMap
.NumBlocks
* BlockMap
.BlockLength
;
478 } while (!(BlockMap
.NumBlocks
== 0 && BlockMap
.BlockLength
== 0));
480 if (VolumeHeader
.FvLength
!= Size
) {
481 Error (NULL
, 0, 0, "volume size not consistant with block maps", NULL
);
500 Displays the standard utility information to SDTOUT
513 "%s, PEI Rebase Utility. Version %i.%i, %s.\n\n",
515 UTILITY_MAJOR_VERSION
,
516 UTILITY_MINOR_VERSION
,
529 Displays the utility usage syntax to STDOUT
542 "Usage: %s -I InputFileName -O OutputFileName -B BaseAddress\n",
545 printf (" Where:\n");
546 printf (" InputFileName is the name of the EFI FV file to rebase.\n");
547 printf (" OutputFileName is the desired output file name.\n");
548 printf (" BaseAddress is the FV base address to rebase against.\n");
549 printf (" Argument pair may be in any order.\n\n");
554 IN OUT EFI_FFS_FILE_HEADER
*FfsFile
,
556 IN OUT EFI_PHYSICAL_ADDRESS XipBase
,
557 IN OUT EFI_PHYSICAL_ADDRESS
*BsBase
,
558 IN OUT EFI_PHYSICAL_ADDRESS
*RtBase
,
565 This function determines if a file is XIP and should be rebased. It will
566 rebase any PE32 sections found in the file using the base address.
570 FfsFile A pointer to Ffs file image.
571 BaseAddress The base address to use for rebasing the file image.
575 EFI_SUCCESS The image was properly rebased.
576 EFI_INVALID_PARAMETER An input parameter is invalid.
577 EFI_ABORTED An error occurred while rebasing the input file image.
578 EFI_OUT_OF_RESOURCES Could not allocate a required resource.
579 EFI_NOT_FOUND No compressed sections could be found.
584 PE_COFF_LOADER_IMAGE_CONTEXT ImageContext
;
585 UINTN MemoryImagePointer
;
586 UINTN MemoryImagePointerAligned
;
587 EFI_PHYSICAL_ADDRESS ImageAddress
;
589 EFI_PHYSICAL_ADDRESS EntryPoint
;
590 UINT32 Pe32ImageSize
;
591 EFI_PHYSICAL_ADDRESS NewPe32BaseAddress
;
593 EFI_FILE_SECTION_POINTER CurrentPe32Section
;
594 EFI_FFS_FILE_STATE SavedState
;
595 EFI_IMAGE_NT_HEADERS32
*PeHdr
;
596 EFI_IMAGE_NT_HEADERS64
*PePlusHdr
;
597 UINT32
*PeHdrSizeOfImage
;
598 UINT32
*PeHdrChecksum
;
599 EFI_TE_IMAGE_HEADER
*TEImageHeader
;
601 EFI_IMAGE_DOS_HEADER
*DosHeader
;
602 UINT8 FileGuidString
[80];
604 EFI_FFS_FILE_TAIL TailValue
;
605 EFI_PHYSICAL_ADDRESS
*BaseToUpdate
;
608 // Verify input parameters
610 if (FfsFile
== NULL
) {
611 return EFI_INVALID_PARAMETER
;
614 // Convert the GUID to a string so we can at least report which file
615 // if we find an error.
617 PrintGuidToBuffer (&FfsFile
->Name
, FileGuidString
, sizeof (FileGuidString
), TRUE
);
618 if (FfsFile
->Attributes
& FFS_ATTRIB_TAIL_PRESENT
) {
619 TailSize
= sizeof (EFI_FFS_FILE_TAIL
);
624 // Do some cursory checks on the FFS file contents
626 Status
= VerifyFfsFile (FfsFile
);
627 if (EFI_ERROR (Status
)) {
628 Error (NULL
, 0, 0, "file does not appear to be a valid FFS file, cannot be rebased", FileGuidString
);
629 return EFI_INVALID_PARAMETER
;
633 // We only process files potentially containing PE32 sections.
635 switch (FfsFile
->Type
) {
636 case EFI_FV_FILETYPE_SECURITY_CORE
:
637 case EFI_FV_FILETYPE_PEI_CORE
:
638 case EFI_FV_FILETYPE_PEIM
:
639 case EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER
:
640 case EFI_FV_FILETYPE_DRIVER
:
641 case EFI_FV_FILETYPE_DXE_CORE
:
648 // Rebase each PE32 section
650 Status
= EFI_SUCCESS
;
651 for (Index
= 1;; Index
++) {
652 Status
= GetSectionByType (FfsFile
, EFI_SECTION_PE32
, Index
, &CurrentPe32Section
);
653 if (EFI_ERROR (Status
)) {
659 // Initialize context
661 memset (&ImageContext
, 0, sizeof (ImageContext
));
662 ImageContext
.Handle
= (VOID
*) ((UINTN
) CurrentPe32Section
.Pe32Section
+ sizeof (EFI_PE32_SECTION
));
663 ImageContext
.ImageRead
= (PE_COFF_LOADER_READ_FILE
) FfsRebaseImageRead
;
664 Status
= PeCoffLoaderGetImageInfo (&ImageContext
);
665 if (EFI_ERROR (Status
)) {
666 Error (NULL
, 0, 0, "GetImageInfo() call failed on rebase", FileGuidString
);
671 // Calculate the PE32 base address, based on file type
673 switch (FfsFile
->Type
) {
674 case EFI_FV_FILETYPE_SECURITY_CORE
:
675 case EFI_FV_FILETYPE_PEI_CORE
:
676 case EFI_FV_FILETYPE_PEIM
:
677 case EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER
:
678 if ((Flags
& 1) == 0) {
680 // We aren't relocating XIP code, so skip it.
687 (UINTN
)CurrentPe32Section
.Pe32Section
+
688 sizeof (EFI_COMMON_SECTION_HEADER
) -
690 BaseToUpdate
= &XipBase
;
693 case EFI_FV_FILETYPE_DRIVER
:
694 PeHdr
= (EFI_IMAGE_NT_HEADERS32
*)(
695 (UINTN
)CurrentPe32Section
.Pe32Section
+
696 sizeof (EFI_COMMON_SECTION_HEADER
) +
697 ImageContext
.PeCoffHeaderOffset
699 switch (PeHdr
->OptionalHeader
.Subsystem
) {
700 case EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER
:
701 if ((Flags
& 4) == 0) {
703 // RT drivers aren't supposed to be relocated
708 NewPe32BaseAddress
= *RtBase
;
709 BaseToUpdate
= RtBase
;
714 // We treat all other subsystems the same as BS_DRIVER
716 if ((Flags
& 2) == 0) {
718 // Skip all BS_DRIVER's
723 NewPe32BaseAddress
= *BsBase
;
724 BaseToUpdate
= BsBase
;
729 case EFI_FV_FILETYPE_DXE_CORE
:
730 if ((Flags
& 2) == 0) {
737 NewPe32BaseAddress
= *BsBase
;
738 BaseToUpdate
= BsBase
;
743 // Not supported file type
749 // Allocate a buffer for the image to be loaded into.
751 Pe32ImageSize
= GetLength (CurrentPe32Section
.Pe32Section
->CommonHeader
.Size
) - sizeof (EFI_PE32_SECTION
);
752 MemoryImagePointer
= (UINTN
) (malloc (Pe32ImageSize
+ 0x10000));
753 if (MemoryImagePointer
== 0) {
754 Error (NULL
, 0, 0, "memory allocation failure", NULL
);
755 return EFI_OUT_OF_RESOURCES
;
757 memset ((void *) MemoryImagePointer
, 0, Pe32ImageSize
+ 0x10000);
758 MemoryImagePointerAligned
= (MemoryImagePointer
+ 0x0FFFF) & (-1 << 16);
761 ImageContext
.ImageAddress
= MemoryImagePointerAligned
;
763 Status
= PeCoffLoaderLoadImage (&ImageContext
);
764 if (EFI_ERROR (Status
)) {
765 Error (NULL
, 0, 0, "LoadImage() call failed on rebase", FileGuidString
);
766 free ((VOID
*) MemoryImagePointer
);
771 // Check if section-alignment and file-alignment match or not
773 if (!(ImageContext
.IsTeImage
)) {
774 PeHdr
= (EFI_IMAGE_NT_HEADERS
*)((UINTN
)ImageContext
.ImageAddress
+
775 ImageContext
.PeCoffHeaderOffset
);
776 if (PeHdr
->OptionalHeader
.SectionAlignment
!= PeHdr
->OptionalHeader
.FileAlignment
) {
777 Error (NULL
, 0, 0, "Section-Alignment and File-Alignment does not match", FileGuidString
);
778 free ((VOID
*) MemoryImagePointer
);
784 // BUGBUG: TE Image Header lack section-alignment and file-alignment info
788 ImageContext
.DestinationAddress
= NewPe32BaseAddress
;
789 Status
= PeCoffLoaderRelocateImage (&ImageContext
);
790 if (EFI_ERROR (Status
)) {
791 Error (NULL
, 0, 0, "RelocateImage() call failed on rebase", FileGuidString
);
792 free ((VOID
*) MemoryImagePointer
);
796 ImageAddress
= ImageContext
.ImageAddress
;
797 ImageSize
= ImageContext
.ImageSize
;
798 EntryPoint
= ImageContext
.EntryPoint
;
800 if (ImageSize
> Pe32ImageSize
) {
805 "rebased image is larger than original PE32 image",
806 "0x%X > 0x%X, file %s",
811 free ((VOID
*) MemoryImagePointer
);
816 // Update BASE address
822 ImageContext
.DestinationAddress
,
823 ImageContext
.PdbPointer
== NULL
? "*" : ImageContext
.PdbPointer
825 *BaseToUpdate
+= EFI_SIZE_TO_PAGES (ImageContext
.ImageSize
) * EFI_PAGE_SIZE
;
828 // Since we may have updated the Codeview RVA, we need to insure the PE
829 // header indicates the image is large enough to contain the Codeview data
830 // so it will be loaded properly later if the PEIM is reloaded into memory...
832 PeHdr
= (VOID
*) ((UINTN
) ImageAddress
+ ImageContext
.PeCoffHeaderOffset
);
833 PePlusHdr
= (EFI_IMAGE_NT_HEADERS64
*)PeHdr
;
834 if (PeHdr
->FileHeader
.Machine
== EFI_IMAGE_MACHINE_IA32
) {
835 PeHdrSizeOfImage
= (UINT32
*) (&(PeHdr
->OptionalHeader
).SizeOfImage
);
836 PeHdrChecksum
= (UINT32
*) (&(PeHdr
->OptionalHeader
).CheckSum
);
837 } else if (PeHdr
->FileHeader
.Machine
== EFI_IMAGE_MACHINE_IA64
) {
838 PeHdrSizeOfImage
= (UINT32
*) (&(PePlusHdr
->OptionalHeader
).SizeOfImage
);
839 PeHdrChecksum
= (UINT32
*) (&(PePlusHdr
->OptionalHeader
).CheckSum
);
840 } else if (PeHdr
->FileHeader
.Machine
== EFI_IMAGE_MACHINE_X64
) {
841 PeHdrSizeOfImage
= (UINT32
*) (&(PePlusHdr
->OptionalHeader
).SizeOfImage
);
842 PeHdrChecksum
= (UINT32
*) (&(PePlusHdr
->OptionalHeader
).CheckSum
);
848 "unknown machine type in PE32 image",
849 "machine type=0x%X, file=%s",
850 (UINT32
) PeHdr
->FileHeader
.Machine
,
853 free ((VOID
*) MemoryImagePointer
);
857 if (*PeHdrSizeOfImage
!= ImageContext
.ImageSize
) {
858 *PeHdrSizeOfImage
= (UINT32
) ImageContext
.ImageSize
;
859 if (*PeHdrChecksum
) {
864 memcpy (CurrentPe32Section
.Pe32Section
+ 1, (VOID
*) MemoryImagePointerAligned
, (UINT32
) ImageSize
);
866 free ((VOID
*) MemoryImagePointer
);
869 // Now update file checksum
871 if (FfsFile
->Attributes
& FFS_ATTRIB_TAIL_PRESENT
) {
872 TailSize
= sizeof (EFI_FFS_FILE_TAIL
);
877 if (FfsFile
->Attributes
& FFS_ATTRIB_CHECKSUM
) {
878 SavedState
= FfsFile
->State
;
879 FfsFile
->IntegrityCheck
.Checksum
.File
= 0;
881 if (FfsFile
->Attributes
& FFS_ATTRIB_CHECKSUM
) {
882 FfsFile
->IntegrityCheck
.Checksum
.File
= CalculateChecksum8 (
884 GetLength (FfsFile
->Size
) - TailSize
887 FfsFile
->IntegrityCheck
.Checksum
.File
= FFS_FIXED_CHECKSUM
;
890 FfsFile
->State
= SavedState
;
893 // Update tail if present
895 if (FfsFile
->Attributes
& FFS_ATTRIB_TAIL_PRESENT
) {
896 TailValue
= (EFI_FFS_FILE_TAIL
) (~(FfsFile
->IntegrityCheck
.TailReference
));
897 *(EFI_FFS_FILE_TAIL
*) (((UINTN
) FfsFile
+ GetLength (FfsFile
->Size
) - sizeof (EFI_FFS_FILE_TAIL
))) = TailValue
;
901 if ((Flags
& 1) == 0 || (
902 FfsFile
->Type
!= EFI_FV_FILETYPE_SECURITY_CORE
&&
903 FfsFile
->Type
!= EFI_FV_FILETYPE_PEI_CORE
&&
905 FfsFile
->Type
!= EFI_FV_FILETYPE_PEIM
&&
906 FfsFile
->Type
!= EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER
909 // Only XIP code may have a TE section
915 // Now process TE sections
917 for (Index
= 1;; Index
++) {
918 Status
= GetSectionByType (FfsFile
, EFI_SECTION_TE
, Index
, &CurrentPe32Section
);
919 if (EFI_ERROR (Status
)) {
924 // Calculate the TE base address, the FFS file base plus the offset of the TE section less the size stripped off
927 TEImageHeader
= (EFI_TE_IMAGE_HEADER
*) ((UINT8
*) CurrentPe32Section
.Pe32Section
+ sizeof (EFI_COMMON_SECTION_HEADER
));
929 NewPe32BaseAddress
= ((UINT32
) XipBase
) +
931 (UINTN
) CurrentPe32Section
.Pe32Section
+
932 sizeof (EFI_COMMON_SECTION_HEADER
) +
933 sizeof (EFI_TE_IMAGE_HEADER
) -
934 TEImageHeader
->StrippedSize
-
939 // Allocate a buffer to unshrink the image into.
941 Pe32ImageSize
= GetLength (CurrentPe32Section
.Pe32Section
->CommonHeader
.Size
) - sizeof (EFI_PE32_SECTION
) -
942 sizeof (EFI_TE_IMAGE_HEADER
);
943 Pe32ImageSize
+= TEImageHeader
->StrippedSize
;
944 TEBuffer
= (UINT8
*) malloc (Pe32ImageSize
);
945 if (TEBuffer
== NULL
) {
946 Error (NULL
, 0, 0, "failed to allocate memory", NULL
);
947 return EFI_OUT_OF_RESOURCES
;
950 // Expand the image into our buffer and fill in critical fields in the DOS header
951 // Fill in fields required by the loader.
952 // At offset 0x3C is the offset to the PE signature. We'll put it immediately following the offset value
955 memset (TEBuffer
, 0, Pe32ImageSize
);
956 DosHeader
= (EFI_IMAGE_DOS_HEADER
*) TEBuffer
;
957 DosHeader
->e_magic
= EFI_IMAGE_DOS_SIGNATURE
;
958 *(UINT32
*) (TEBuffer
+ 0x3C) = 0x40;
959 PeHdr
= (EFI_IMAGE_NT_HEADERS
*) (TEBuffer
+ 0x40);
960 PePlusHdr
= (EFI_IMAGE_NT_HEADERS64
*)PeHdr
;
961 PeHdr
->Signature
= EFI_IMAGE_NT_SIGNATURE
;
962 PeHdr
->FileHeader
.Machine
= TEImageHeader
->Machine
;
963 PeHdr
->FileHeader
.NumberOfSections
= TEImageHeader
->NumberOfSections
;
966 // Say the size of the optional header is the total we stripped off less the size of a PE file header and PE signature and
967 // the 0x40 bytes for our DOS header.
969 PeHdr
->FileHeader
.SizeOfOptionalHeader
= (UINT16
) (TEImageHeader
->StrippedSize
- 0x40 - sizeof (UINT32
) - sizeof (EFI_IMAGE_FILE_HEADER
));
970 if (TEImageHeader
->Machine
== EFI_IMAGE_MACHINE_IA32
) {
971 PeHdr
->OptionalHeader
.Magic
= EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
;
972 } else if (TEImageHeader
->Machine
== EFI_IMAGE_MACHINE_IA64
) {
973 PePlusHdr
->OptionalHeader
.Magic
= EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC
;
974 } else if (TEImageHeader
->Machine
== EFI_IMAGE_MACHINE_X64
) {
975 PePlusHdr
->OptionalHeader
.Magic
= EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC
;
981 "unknown machine type in TE image",
982 "machine type=0x%X, file=%s",
983 (UINT32
) TEImageHeader
->Machine
,
990 if (PeHdr
->OptionalHeader
.Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
991 PeHdr
->OptionalHeader
.ImageBase
= (UINTN
) (TEImageHeader
->ImageBase
- TEImageHeader
->StrippedSize
+ sizeof (EFI_TE_IMAGE_HEADER
));
992 PeHdr
->OptionalHeader
.SizeOfImage
= Pe32ImageSize
;
993 PeHdr
->OptionalHeader
.Subsystem
= TEImageHeader
->Subsystem
;
994 PeHdr
->OptionalHeader
.SizeOfHeaders
= TEImageHeader
->StrippedSize
+ TEImageHeader
->NumberOfSections
*
995 sizeof (EFI_IMAGE_SECTION_HEADER
) - 12;
998 // Set NumberOfRvaAndSizes in the optional header to what we had available in the original image
1000 if ((TEImageHeader
->DataDirectory
[EFI_TE_IMAGE_DIRECTORY_ENTRY_BASERELOC
].VirtualAddress
!= 0) ||
1001 (TEImageHeader
->DataDirectory
[EFI_TE_IMAGE_DIRECTORY_ENTRY_BASERELOC
].Size
!= 0)
1003 PeHdr
->OptionalHeader
.NumberOfRvaAndSizes
= EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
+ 1;
1004 PeHdr
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
].VirtualAddress
= TEImageHeader
->DataDirectory
[EFI_TE_IMAGE_DIRECTORY_ENTRY_BASERELOC
].VirtualAddress
;
1005 PeHdr
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
].Size
= TEImageHeader
->DataDirectory
[EFI_TE_IMAGE_DIRECTORY_ENTRY_BASERELOC
].Size
;
1008 if ((TEImageHeader
->DataDirectory
[EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG
].VirtualAddress
!= 0) ||
1009 (TEImageHeader
->DataDirectory
[EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG
].Size
!= 0)
1011 PeHdr
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG
].VirtualAddress
= TEImageHeader
->DataDirectory
[EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG
].VirtualAddress
;
1012 PeHdr
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG
].Size
= TEImageHeader
->DataDirectory
[EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG
].Size
;
1013 if (PeHdr
->OptionalHeader
.NumberOfRvaAndSizes
< EFI_IMAGE_DIRECTORY_ENTRY_DEBUG
+ 1) {
1014 PeHdr
->OptionalHeader
.NumberOfRvaAndSizes
= EFI_IMAGE_DIRECTORY_ENTRY_DEBUG
+ 1;
1018 // NOTE: These values are defaults, and should be verified to be correct in the GenTE utility
1020 PeHdr
->OptionalHeader
.SectionAlignment
= 0x10;
1022 PePlusHdr
->OptionalHeader
.ImageBase
= (UINTN
) (TEImageHeader
->ImageBase
- TEImageHeader
->StrippedSize
+ sizeof (EFI_TE_IMAGE_HEADER
));
1023 PePlusHdr
->OptionalHeader
.SizeOfImage
= Pe32ImageSize
;
1024 PePlusHdr
->OptionalHeader
.Subsystem
= TEImageHeader
->Subsystem
;
1025 PePlusHdr
->OptionalHeader
.SizeOfHeaders
= TEImageHeader
->StrippedSize
+ TEImageHeader
->NumberOfSections
*
1026 sizeof (EFI_IMAGE_SECTION_HEADER
) - 12;
1029 // Set NumberOfRvaAndSizes in the optional header to what we had available in the original image
1031 if ((TEImageHeader
->DataDirectory
[EFI_TE_IMAGE_DIRECTORY_ENTRY_BASERELOC
].VirtualAddress
!= 0) ||
1032 (TEImageHeader
->DataDirectory
[EFI_TE_IMAGE_DIRECTORY_ENTRY_BASERELOC
].Size
!= 0)
1034 PePlusHdr
->OptionalHeader
.NumberOfRvaAndSizes
= EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
+ 1;
1035 PePlusHdr
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
].VirtualAddress
= TEImageHeader
->DataDirectory
[EFI_TE_IMAGE_DIRECTORY_ENTRY_BASERELOC
].VirtualAddress
;
1036 PePlusHdr
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
].Size
= TEImageHeader
->DataDirectory
[EFI_TE_IMAGE_DIRECTORY_ENTRY_BASERELOC
].Size
;
1039 if ((TEImageHeader
->DataDirectory
[EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG
].VirtualAddress
!= 0) ||
1040 (TEImageHeader
->DataDirectory
[EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG
].Size
!= 0)
1042 PePlusHdr
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG
].VirtualAddress
= TEImageHeader
->DataDirectory
[EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG
].VirtualAddress
;
1043 PePlusHdr
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG
].Size
= TEImageHeader
->DataDirectory
[EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG
].Size
;
1044 if (PePlusHdr
->OptionalHeader
.NumberOfRvaAndSizes
< EFI_IMAGE_DIRECTORY_ENTRY_DEBUG
+ 1) {
1045 PePlusHdr
->OptionalHeader
.NumberOfRvaAndSizes
= EFI_IMAGE_DIRECTORY_ENTRY_DEBUG
+ 1;
1049 // NOTE: These values are defaults, and should be verified to be correct in the GenTE utility
1051 PePlusHdr
->OptionalHeader
.SectionAlignment
= 0x10;
1055 // Copy the rest of the image to its original offset
1058 TEBuffer
+ TEImageHeader
->StrippedSize
,
1059 (UINT8
*) CurrentPe32Section
.Pe32Section
+ sizeof (EFI_PE32_SECTION
) + sizeof (EFI_TE_IMAGE_HEADER
),
1060 GetLength (CurrentPe32Section
.Pe32Section
->CommonHeader
.Size
) - sizeof (EFI_PE32_SECTION
) -
1061 sizeof (EFI_TE_IMAGE_HEADER
)
1065 // Initialize context
1067 memset (&ImageContext
, 0, sizeof (ImageContext
));
1068 ImageContext
.Handle
= (VOID
*) TEBuffer
;
1069 ImageContext
.ImageRead
= (PE_COFF_LOADER_READ_FILE
) FfsRebaseImageRead
;
1071 Status
= PeCoffLoaderGetImageInfo (&ImageContext
);
1073 if (EFI_ERROR (Status
)) {
1074 Error (NULL
, 0, 0, "GetImageInfo() call failed on rebase of TE image", FileGuidString
);
1079 // Allocate a buffer for the image to be loaded into.
1081 MemoryImagePointer
= (UINTN
) (malloc (Pe32ImageSize
+ 0x10000));
1082 if (MemoryImagePointer
== 0) {
1083 Error (NULL
, 0, 0, "memory allocation error on rebase of TE image", FileGuidString
);
1085 return EFI_OUT_OF_RESOURCES
;
1087 memset ((void *) MemoryImagePointer
, 0, Pe32ImageSize
+ 0x10000);
1088 MemoryImagePointerAligned
= (MemoryImagePointer
+ 0x0FFFF) & (-1 << 16);
1091 ImageContext
.ImageAddress
= MemoryImagePointerAligned
;
1092 Status
= PeCoffLoaderLoadImage (&ImageContext
);
1093 if (EFI_ERROR (Status
)) {
1094 Error (NULL
, 0, 0, "LoadImage() call failed on rebase of TE image", FileGuidString
);
1096 free ((VOID
*) MemoryImagePointer
);
1100 ImageContext
.DestinationAddress
= NewPe32BaseAddress
;
1101 Status
= PeCoffLoaderRelocateImage (&ImageContext
);
1102 if (EFI_ERROR (Status
)) {
1103 Error (NULL
, 0, 0, "RelocateImage() call failed on rebase of TE image", FileGuidString
);
1104 free ((VOID
*) MemoryImagePointer
);
1109 ImageAddress
= ImageContext
.ImageAddress
;
1110 ImageSize
= ImageContext
.ImageSize
;
1111 EntryPoint
= ImageContext
.EntryPoint
;
1114 // Since we may have updated the Codeview RVA, we need to insure the PE
1115 // header indicates the image is large enough to contain the Codeview data
1116 // so it will be loaded properly later if the PEIM is reloaded into memory...
1118 PeHdr
= (VOID
*) ((UINTN
) ImageAddress
+ ImageContext
.PeCoffHeaderOffset
);
1119 PePlusHdr
= (EFI_IMAGE_NT_HEADERS64
*)PeHdr
;
1120 if (PeHdr
->FileHeader
.Machine
== EFI_IMAGE_MACHINE_IA32
) {
1121 PeHdrSizeOfImage
= (UINT32
*) (&(PeHdr
->OptionalHeader
).SizeOfImage
);
1122 PeHdrChecksum
= (UINT32
*) (&(PeHdr
->OptionalHeader
).CheckSum
);
1123 } else if (PeHdr
->FileHeader
.Machine
== EFI_IMAGE_MACHINE_IA64
) {
1124 PeHdrSizeOfImage
= (UINT32
*) (&(PePlusHdr
->OptionalHeader
).SizeOfImage
);
1125 PeHdrChecksum
= (UINT32
*) (&(PePlusHdr
->OptionalHeader
).CheckSum
);
1126 } else if (PeHdr
->FileHeader
.Machine
== EFI_IMAGE_MACHINE_X64
) {
1127 PeHdrSizeOfImage
= (UINT32
*) (&(PePlusHdr
->OptionalHeader
).SizeOfImage
);
1128 PeHdrChecksum
= (UINT32
*) (&(PePlusHdr
->OptionalHeader
).CheckSum
);
1134 "unknown machine type in TE image",
1135 "machine type=0x%X, file=%s",
1136 (UINT32
) PeHdr
->FileHeader
.Machine
,
1139 free ((VOID
*) MemoryImagePointer
);
1144 if (*PeHdrSizeOfImage
!= ImageContext
.ImageSize
) {
1145 *PeHdrSizeOfImage
= (UINT32
) ImageContext
.ImageSize
;
1146 if (*PeHdrChecksum
) {
1151 TEImageHeader
->ImageBase
= (UINT64
) (NewPe32BaseAddress
+ TEImageHeader
->StrippedSize
- sizeof (EFI_TE_IMAGE_HEADER
));
1153 (UINT8
*) (CurrentPe32Section
.Pe32Section
+ 1) + sizeof (EFI_TE_IMAGE_HEADER
),
1154 (VOID
*) ((UINT8
*) MemoryImagePointerAligned
+ TEImageHeader
->StrippedSize
),
1155 GetLength (CurrentPe32Section
.Pe32Section
->CommonHeader
.Size
) - sizeof (EFI_PE32_SECTION
) -
1156 sizeof (EFI_TE_IMAGE_HEADER
)
1158 if (FfsFile
->Attributes
& FFS_ATTRIB_TAIL_PRESENT
) {
1159 TailSize
= sizeof (EFI_FFS_FILE_TAIL
);
1164 // Now update file checksum
1166 if (FfsFile
->Attributes
& FFS_ATTRIB_CHECKSUM
) {
1167 SavedState
= FfsFile
->State
;
1168 FfsFile
->IntegrityCheck
.Checksum
.File
= 0;
1170 if (FfsFile
->Attributes
& FFS_ATTRIB_CHECKSUM
) {
1171 FfsFile
->IntegrityCheck
.Checksum
.File
= CalculateChecksum8 (
1173 GetLength (FfsFile
->Size
) - TailSize
1176 FfsFile
->IntegrityCheck
.Checksum
.File
= FFS_FIXED_CHECKSUM
;
1179 FfsFile
->State
= SavedState
;
1182 // Update tail if present
1184 if (FfsFile
->Attributes
& FFS_ATTRIB_TAIL_PRESENT
) {
1185 TailValue
= (EFI_FFS_FILE_TAIL
) (~(FfsFile
->IntegrityCheck
.TailReference
));
1186 *(EFI_FFS_FILE_TAIL
*) (((UINTN
) FfsFile
+ GetLength (FfsFile
->Size
) - sizeof (EFI_FFS_FILE_TAIL
))) = TailValue
;
1193 ImageContext
.DestinationAddress
,
1194 ImageContext
.PdbPointer
== NULL
? "*" : ImageContext
.PdbPointer
1200 free ((VOID
*) MemoryImagePointer
);
1208 FfsRebaseImageRead (
1209 IN VOID
*FileHandle
,
1210 IN UINTN FileOffset
,
1211 IN OUT UINT32
*ReadSize
,
1216 Routine Description:
1218 Support routine for the PE/COFF Loader that reads a buffer from a PE/COFF file
1222 FileHandle - The handle to the PE/COFF file
1224 FileOffset - The offset, in bytes, into the file to read
1226 ReadSize - The number of bytes to read from the file starting at FileOffset
1228 Buffer - A pointer to the buffer to read the data into.
1232 EFI_SUCCESS - ReadSize bytes of data were read into Buffer from the PE/COFF file starting at FileOffset
1236 CHAR8
*Destination8
;
1240 Destination8
= Buffer
;
1241 Source8
= (CHAR8
*) ((UINTN
) FileHandle
+ FileOffset
);
1244 *(Destination8
++) = *(Source8
++);