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.
66 MapFileName The name of the map file of relocation info.
68 Arguments come in pair in any order.
76 0 No error conditions detected.
77 1 One or more of the input parameters is invalid.
78 2 A resource required by the utility was unavailable.
79 Most commonly this will be memory allocation or file creation.
80 3 PeiRebase.dll could not be loaded.
81 4 Error executing the PEI rebase.
86 CHAR8 InputFileName
[_MAX_PATH
];
87 CHAR8 OutputFileName
[_MAX_PATH
];
88 CHAR8 MapFileName
[_MAX_PATH
];
89 EFI_PHYSICAL_ADDRESS BaseAddress
;
90 BOOLEAN BaseAddressSet
;
98 EFI_FIRMWARE_VOLUME_HEADER
*FvImage
;
100 EFI_FFS_FILE_HEADER
*CurrentFile
;
101 BOOLEAN ErasePolarity
;
102 EFI_PHYSICAL_ADDRESS CurrentFileBaseAddress
;
103 CHAR8 InfFileName
[_MAX_PATH
];
106 MEMORY_FILE InfMemoryFile
;
108 ErasePolarity
= FALSE
;
110 // Set utility name for error/warning reporting purposes.
112 SetUtilityName (UTILITY_NAME
);
114 // Verify the correct number of arguments
116 if (argc
!= MAX_ARGS
) {
122 // Initialize variables
124 InputFileName
[0] = 0;
125 OutputFileName
[0] = 0;
128 BaseAddressSet
= FALSE
;
131 ErasePolarity
= FALSE
;
138 strcpy (InfFileName
, "");
141 // Parse the command line arguments
143 for (Index
= 1; Index
< MAX_ARGS
; Index
+= 2) {
145 // Make sure argument pair begin with - or /
147 if (argv
[Index
][0] != '-' && argv
[Index
][0] != '/') {
149 Error (NULL
, 0, 0, argv
[Index
], "unrecognized option");
153 // Make sure argument specifier is only one letter
155 if (argv
[Index
][2] != 0) {
157 Error (NULL
, 0, 0, argv
[Index
], "unrecognized option");
161 // Determine argument to read
163 switch (argv
[Index
][1]) {
166 if (strlen (InputFileName
) == 0) {
167 strcpy (InputFileName
, argv
[Index
+ 1]);
170 Error (NULL
, 0, 0, argv
[Index
+ 1], "only one -i InputFileName may be specified");
177 if (strlen (OutputFileName
) == 0) {
178 strcpy (OutputFileName
, argv
[Index
+ 1]);
181 Error (NULL
, 0, 0, argv
[Index
+ 1], "only one -o OutputFileName may be specified");
188 if (!BaseAddressSet
) {
189 Status
= AsciiStringToUint64 (argv
[Index
+ 1], FALSE
, &BaseAddress
);
190 if (EFI_ERROR (Status
)) {
192 Error (NULL
, 0, 0, argv
[Index
+ 1], "invalid hex digit given for the base address");
196 BaseAddressSet
= TRUE
;
199 Error (NULL
, 0, 0, argv
[Index
+ 1], "-b BaseAddress may only be specified once");
206 if (!BaseAddressSet
) {
207 strcpy (InfFileName
, argv
[Index
+ 1]);
209 // Read the INF file image
211 Status
= GetFileImage (InfFileName
, &InfFileImage
, &InfFileSize
);
212 if (EFI_ERROR (Status
)) {
214 Error (NULL
, 0, 0, argv
[Index
+ 1], "-f FvInfFile can't be opened.");
218 // Initialize file structures
220 InfMemoryFile
.FileImage
= InfFileImage
;
221 InfMemoryFile
.CurrentFilePointer
= InfFileImage
;
222 InfMemoryFile
.Eof
= InfFileImage
+ InfFileSize
;
224 // Read BaseAddress from fv.inf file.
226 FindToken (&InfMemoryFile
, "[options]", "EFI_BASE_ADDRESS", 0, InfFileName
);
228 // free Inf File Image
233 // Convert string to UINT64 base address.
235 Status
= AsciiStringToUint64 (InfFileName
, FALSE
, &BaseAddress
);
236 if (EFI_ERROR (Status
)) {
238 Error (NULL
, 0, 0, argv
[Index
+ 1], "can't find the base address in the specified fv.inf file.");
242 BaseAddressSet
= TRUE
;
245 Error (NULL
, 0, 0, argv
[Index
+ 1], "BaseAddress has been got once from fv.inf or the specified base address.");
252 if (strlen (MapFileName
) == 0) {
253 strcpy (MapFileName
, argv
[Index
+ 1]);
256 Error (NULL
, 0, 0, argv
[Index
+ 1], "only one -m MapFileName may be specified");
263 Error (NULL
, 0, 0, argv
[Index
], "unrecognized argument");
270 // Create the Map file if we need it
272 if (strlen (MapFileName
) != 0) {
273 MapFile
= fopen (MapFileName
, "w");
274 if (MapFile
== NULL
) {
275 Error (NULL
, 0, 0, MapFileName
, "failed to open map file");
281 // Open the file containing the FV
283 InputFile
= fopen (InputFileName
, "rb");
284 if (InputFile
== NULL
) {
285 Error (NULL
, 0, 0, InputFileName
, "could not open input file for reading");
289 // Determine size of FV
291 Status
= ReadHeader (InputFile
, &FvSize
, &ErasePolarity
);
292 if (EFI_ERROR (Status
)) {
293 Error (NULL
, 0, 0, "could not parse the FV header", NULL
);
297 // Allocate a buffer for the FV image
299 FvImage
= malloc (FvSize
);
300 if (FvImage
== NULL
) {
301 Error (NULL
, 0, 0, "application error", "memory allocation failed");
305 // Read the entire FV to the buffer
307 BytesRead
= fread (FvImage
, 1, FvSize
, InputFile
);
310 if ((unsigned int) BytesRead
!= FvSize
) {
311 Error (NULL
, 0, 0, InputFileName
, "failed to read from file");
315 // Prepare to walk the FV image
317 InitializeFvLib (FvImage
, FvSize
);
319 // Get the first file
321 Status
= GetNextFile (NULL
, &CurrentFile
);
322 if (EFI_ERROR (Status
)) {
323 Error (NULL
, 0, 0, "cannot find the first file in the FV image", NULL
);
327 // Check if each file should be rebased
329 while (CurrentFile
!= NULL
) {
333 CurrentFileBaseAddress
= BaseAddress
+ ((UINTN
) CurrentFile
- (UINTN
) FvImage
);
334 Status
= FfsRebase (CurrentFile
, CurrentFileBaseAddress
, MapFile
);
336 if (EFI_ERROR (Status
)) {
339 case EFI_INVALID_PARAMETER
:
340 Error (NULL
, 0, 0, "invalid parameter passed to FfsRebase", NULL
);
344 Error (NULL
, 0, 0, "error detected while rebasing -- aborted", NULL
);
347 case EFI_OUT_OF_RESOURCES
:
348 Error (NULL
, 0, 0, "FfsRebase could not allocate required resources", NULL
);
352 Error (NULL
, 0, 0, "FfsRebase could not locate a PE32 section", NULL
);
356 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 (MapFile
!= 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] -F FvInfFileName -M MapFile\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 agains.\n");
549 printf (" FvInfFileName is the fv.inf to be used to generate this fv image.\n");
550 printf (" BaseAddress can also be got from the fv.inf file.\n");
551 printf (" Choose only one method to input BaseAddress.\n");
552 printf (" MapFileName is an optional map file of the relocations\n");
553 printf (" Argument pair may be in any order.\n\n");
558 IN OUT EFI_FFS_FILE_HEADER
*FfsFile
,
559 IN EFI_PHYSICAL_ADDRESS BaseAddress
,
560 IN
FILE *MapFile OPTIONAL
566 This function determines if a file is XIP and should be rebased. It will
567 rebase any PE32 sections found in the file using the base address.
571 FfsFile A pointer to Ffs file image.
572 BaseAddress The base address to use for rebasing the file image.
573 MapFile Optional file to dump relocation information into
577 EFI_SUCCESS The image was properly rebased.
578 EFI_INVALID_PARAMETER An input parameter is invalid.
579 EFI_ABORTED An error occurred while rebasing the input file image.
580 EFI_OUT_OF_RESOURCES Could not allocate a required resource.
581 EFI_NOT_FOUND No compressed sections could be found.
586 PE_COFF_LOADER_IMAGE_CONTEXT ImageContext
;
587 UINTN MemoryImagePointer
;
588 UINTN MemoryImagePointerAligned
;
589 EFI_PHYSICAL_ADDRESS ImageAddress
;
591 EFI_PHYSICAL_ADDRESS EntryPoint
;
592 UINT32 Pe32ImageSize
;
593 UINT32 NewPe32BaseAddress
;
595 EFI_FILE_SECTION_POINTER CurrentPe32Section
;
596 EFI_FFS_FILE_STATE SavedState
;
597 EFI_IMAGE_NT_HEADERS
*PeHdr
;
598 UINT32
*PeHdrSizeOfImage
;
599 UINT32
*PeHdrChecksum
;
601 EFI_TE_IMAGE_HEADER
*TEImageHeader
;
603 EFI_IMAGE_DOS_HEADER
*DosHeader
;
604 UINT8 FileGuidString
[80];
606 EFI_FFS_FILE_TAIL TailValue
;
609 // Verify input parameters
611 if (FfsFile
== NULL
) {
612 return EFI_INVALID_PARAMETER
;
616 // Convert the GUID to a string so we can at least report which file
617 // if we find an error.
619 PrintGuidToBuffer (&FfsFile
->Name
, FileGuidString
, sizeof (FileGuidString
), TRUE
);
620 if (FfsFile
->Attributes
& FFS_ATTRIB_TAIL_PRESENT
) {
621 TailSize
= sizeof (EFI_FFS_FILE_TAIL
);
627 // Do some cursory checks on the FFS file contents
629 Status
= VerifyFfsFile (FfsFile
);
630 if (EFI_ERROR (Status
)) {
631 Error (NULL
, 0, 0, "file does not appear to be a valid FFS file, cannot be rebased", FileGuidString
);
632 return EFI_INVALID_PARAMETER
;
635 memset (&ImageContext
, 0, sizeof (ImageContext
));
638 // Check if XIP file type. If not XIP, don't rebase.
640 if (FfsFile
->Type
!= EFI_FV_FILETYPE_PEI_CORE
&&
641 FfsFile
->Type
!= EFI_FV_FILETYPE_PEIM
&&
642 FfsFile
->Type
!= EFI_FV_FILETYPE_SECURITY_CORE
&&
643 FfsFile
->Type
!= EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER
649 // Rebase each PE32 section
651 Status
= EFI_SUCCESS
;
653 for (Index
= 1;; Index
++) {
654 Status
= GetSectionByType (FfsFile
, EFI_SECTION_PE32
, Index
, &CurrentPe32Section
);
655 if (EFI_ERROR (Status
)) {
662 // Calculate the PE32 base address, the FFS file base plus the offset of the PE32 section
664 NewPe32BaseAddress
= ((UINT32
) BaseAddress
) + ((UINTN
) CurrentPe32Section
.Pe32Section
+ sizeof (EFI_COMMON_SECTION_HEADER
) - (UINTN
) FfsFile
);
667 // Initialize context
669 memset (&ImageContext
, 0, sizeof (ImageContext
));
670 ImageContext
.Handle
= (VOID
*) ((UINTN
) CurrentPe32Section
.Pe32Section
+ sizeof (EFI_PE32_SECTION
));
671 ImageContext
.ImageRead
= (PE_COFF_LOADER_READ_FILE
) FfsRebaseImageRead
;
673 Status
= PeCoffLoaderGetImageInfo (&ImageContext
);
675 if (EFI_ERROR (Status
)) {
676 Error (NULL
, 0, 0, "GetImageInfo() call failed on rebase", FileGuidString
);
680 // Allocate a buffer for the image to be loaded into.
682 Pe32ImageSize
= GetLength (CurrentPe32Section
.Pe32Section
->CommonHeader
.Size
) - sizeof (EFI_PE32_SECTION
);
683 MemoryImagePointer
= (UINTN
) (malloc (Pe32ImageSize
+ 0x10000));
684 if (MemoryImagePointer
== 0) {
685 Error (NULL
, 0, 0, "memory allocation failure", NULL
);
686 return EFI_OUT_OF_RESOURCES
;
688 memset ((void *) MemoryImagePointer
, 0, Pe32ImageSize
+ 0x10000);
689 MemoryImagePointerAligned
= (MemoryImagePointer
+ 0x0FFFF) & (-1 << 16);
692 ImageContext
.ImageAddress
= MemoryImagePointerAligned
;
694 Status
= PeCoffLoaderLoadImage (&ImageContext
);
695 if (EFI_ERROR (Status
)) {
696 Error (NULL
, 0, 0, "LoadImage() call failed on rebase", FileGuidString
);
697 free ((VOID
*) MemoryImagePointer
);
702 // Check if section-alignment and file-alignment match or not
704 if (!(ImageContext
.IsTeImage
)) {
705 PeHdr
= (EFI_IMAGE_NT_HEADERS
*)((UINTN
)ImageContext
.ImageAddress
+
706 ImageContext
.PeCoffHeaderOffset
);
707 if (PeHdr
->OptionalHeader
.SectionAlignment
!= PeHdr
->OptionalHeader
.FileAlignment
) {
708 Error (NULL
, 0, 0, "Section-Alignment and File-Alignment does not match", FileGuidString
);
709 free ((VOID
*) MemoryImagePointer
);
715 // BUGBUG: TE Image Header lack section-alignment and file-alignment info
719 ImageContext
.DestinationAddress
= NewPe32BaseAddress
;
720 Status
= PeCoffLoaderRelocateImage (&ImageContext
);
721 if (EFI_ERROR (Status
)) {
722 Error (NULL
, 0, 0, "RelocateImage() call failed on rebase", FileGuidString
);
723 free ((VOID
*) MemoryImagePointer
);
727 ImageAddress
= ImageContext
.ImageAddress
;
728 ImageSize
= ImageContext
.ImageSize
;
729 EntryPoint
= ImageContext
.EntryPoint
;
731 if (ImageSize
> Pe32ImageSize
) {
736 "rebased image is larger than original PE32 image",
737 "0x%X > 0x%X, file %s",
742 free ((VOID
*) MemoryImagePointer
);
746 // Since we may have updated the Codeview RVA, we need to insure the PE
747 // header indicates the image is large enough to contain the Codeview data
748 // so it will be loaded properly later if the PEIM is reloaded into memory...
750 PeHdr
= (VOID
*) ((UINTN
) ImageAddress
+ ImageContext
.PeCoffHeaderOffset
);
751 if (PeHdr
->FileHeader
.Machine
== EFI_IMAGE_MACHINE_IA32
) {
752 PeHdrSizeOfImage
= (UINT32
*) (&(*(EFI_IMAGE_OPTIONAL_HEADER32
*) &PeHdr
->OptionalHeader
).SizeOfImage
);
753 PeHdrChecksum
= (UINT32
*) (&(*(EFI_IMAGE_OPTIONAL_HEADER32
*) &PeHdr
->OptionalHeader
).CheckSum
);
754 } else if (PeHdr
->FileHeader
.Machine
== EFI_IMAGE_MACHINE_IA64
) {
755 PeHdrSizeOfImage
= (UINT32
*) (&(*(EFI_IMAGE_OPTIONAL_HEADER64
*) &PeHdr
->OptionalHeader
).SizeOfImage
);
756 PeHdrChecksum
= (UINT32
*) (&(*(EFI_IMAGE_OPTIONAL_HEADER64
*) &PeHdr
->OptionalHeader
).CheckSum
);
757 } else if (PeHdr
->FileHeader
.Machine
== EFI_IMAGE_MACHINE_X64
) {
758 PeHdrSizeOfImage
= (UINT32
*) (&(*(EFI_IMAGE_OPTIONAL_HEADER64
*) &PeHdr
->OptionalHeader
).SizeOfImage
);
759 PeHdrChecksum
= (UINT32
*) (&(*(EFI_IMAGE_OPTIONAL_HEADER64
*) &PeHdr
->OptionalHeader
).CheckSum
);
765 "unknown machine type in PE32 image",
766 "machine type=0x%X, file=%s",
767 (UINT32
) PeHdr
->FileHeader
.Machine
,
770 free ((VOID
*) MemoryImagePointer
);
774 if (*PeHdrSizeOfImage
!= ImageContext
.ImageSize
) {
775 *PeHdrSizeOfImage
= (UINT32
) ImageContext
.ImageSize
;
776 if (*PeHdrChecksum
) {
781 memcpy (CurrentPe32Section
.Pe32Section
+ 1, (VOID
*) MemoryImagePointerAligned
, (UINT32
) ImageSize
);
784 // Get EntryPoint in Flash Region.
786 EntryPoint
= NewPe32BaseAddress
+ EntryPoint
- ImageAddress
;
789 // If a map file was selected output mapping information for any file that
792 if (MapFile
!= NULL
) {
793 fprintf (MapFile
, "PE32 File: %s Base:%08lx", FileGuidString
, BaseAddress
);
794 fprintf (MapFile
, " EntryPoint:%08lx", EntryPoint
);
795 if (ImageContext
.PdbPointer
!= NULL
) {
796 fprintf (MapFile
, " FileName: %s", ImageContext
.PdbPointer
);
798 fprintf (MapFile
, "\n");
801 free ((VOID
*) MemoryImagePointer
);
804 // Now update file checksum
806 if (FfsFile
->Attributes
& FFS_ATTRIB_TAIL_PRESENT
) {
807 TailSize
= sizeof (EFI_FFS_FILE_TAIL
);
812 if (FfsFile
->Attributes
& FFS_ATTRIB_CHECKSUM
) {
813 SavedState
= FfsFile
->State
;
814 FfsFile
->IntegrityCheck
.Checksum
.File
= 0;
816 if (FfsFile
->Attributes
& FFS_ATTRIB_CHECKSUM
) {
817 FfsFile
->IntegrityCheck
.Checksum
.File
= CalculateChecksum8 (
819 GetLength (FfsFile
->Size
) - TailSize
822 FfsFile
->IntegrityCheck
.Checksum
.File
= FFS_FIXED_CHECKSUM
;
825 FfsFile
->State
= SavedState
;
828 // Update tail if present
830 if (FfsFile
->Attributes
& FFS_ATTRIB_TAIL_PRESENT
) {
831 TailValue
= (EFI_FFS_FILE_TAIL
) (~(FfsFile
->IntegrityCheck
.TailReference
));
832 *(EFI_FFS_FILE_TAIL
*) (((UINTN
) FfsFile
+ GetLength (FfsFile
->Size
) - sizeof (EFI_FFS_FILE_TAIL
))) = TailValue
;
836 // Now process TE sections
838 for (Index
= 1;; Index
++) {
839 Status
= GetSectionByType (FfsFile
, EFI_SECTION_TE
, Index
, &CurrentPe32Section
);
840 if (EFI_ERROR (Status
)) {
847 // Calculate the TE base address, the FFS file base plus the offset of the TE section less the size stripped off
850 TEImageHeader
= (EFI_TE_IMAGE_HEADER
*) ((UINT8
*) CurrentPe32Section
.Pe32Section
+ sizeof (EFI_COMMON_SECTION_HEADER
));
852 NewPe32BaseAddress
= ((UINT32
) BaseAddress
) +
854 (UINTN
) CurrentPe32Section
.Pe32Section
+
855 sizeof (EFI_COMMON_SECTION_HEADER
) +
856 sizeof (EFI_TE_IMAGE_HEADER
) -
857 TEImageHeader
->StrippedSize
-
862 // Allocate a buffer to unshrink the image into.
864 Pe32ImageSize
= GetLength (CurrentPe32Section
.Pe32Section
->CommonHeader
.Size
) - sizeof (EFI_PE32_SECTION
) -
865 sizeof (EFI_TE_IMAGE_HEADER
);
866 Pe32ImageSize
+= TEImageHeader
->StrippedSize
;
867 TEBuffer
= (UINT8
*) malloc (Pe32ImageSize
);
868 if (TEBuffer
== NULL
) {
869 Error (NULL
, 0, 0, "failed to allocate memory", NULL
);
870 return EFI_OUT_OF_RESOURCES
;
873 // Expand the image into our buffer and fill in critical fields in the DOS header
874 // Fill in fields required by the loader.
875 // At offset 0x3C is the offset to the PE signature. We'll put it immediately following the offset value
878 memset (TEBuffer
, 0, Pe32ImageSize
);
879 DosHeader
= (EFI_IMAGE_DOS_HEADER
*) TEBuffer
;
880 DosHeader
->e_magic
= EFI_IMAGE_DOS_SIGNATURE
;
881 *(UINT32
*) (TEBuffer
+ 0x3C) = 0x40;
882 PeHdr
= (EFI_IMAGE_NT_HEADERS
*) (TEBuffer
+ 0x40);
883 PeHdr
->Signature
= EFI_IMAGE_NT_SIGNATURE
;
884 PeHdr
->FileHeader
.Machine
= TEImageHeader
->Machine
;
885 PeHdr
->FileHeader
.NumberOfSections
= TEImageHeader
->NumberOfSections
;
888 // 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
889 // the 0x40 bytes for our DOS header.
891 PeHdr
->FileHeader
.SizeOfOptionalHeader
= (UINT16
) (TEImageHeader
->StrippedSize
- 0x40 - sizeof (UINT32
) - sizeof (EFI_IMAGE_FILE_HEADER
));
892 PeHdr
->OptionalHeader
.ImageBase
= (UINTN
) (TEImageHeader
->ImageBase
- TEImageHeader
->StrippedSize
+ sizeof (EFI_TE_IMAGE_HEADER
));
893 PeHdr
->OptionalHeader
.AddressOfEntryPoint
= TEImageHeader
->AddressOfEntryPoint
;
894 PeHdr
->OptionalHeader
.BaseOfCode
= TEImageHeader
->BaseOfCode
;
895 PeHdr
->OptionalHeader
.SizeOfImage
= Pe32ImageSize
;
896 PeHdr
->OptionalHeader
.Subsystem
= TEImageHeader
->Subsystem
;
897 PeHdr
->OptionalHeader
.SizeOfImage
= Pe32ImageSize
;
898 PeHdr
->OptionalHeader
.SizeOfHeaders
= TEImageHeader
->StrippedSize
+ TEImageHeader
->NumberOfSections
*
899 sizeof (EFI_IMAGE_SECTION_HEADER
) - 12;
902 // Set NumberOfRvaAndSizes in the optional header to what we had available in the original image
904 if ((TEImageHeader
->DataDirectory
[EFI_TE_IMAGE_DIRECTORY_ENTRY_BASERELOC
].VirtualAddress
!= 0) ||
905 (TEImageHeader
->DataDirectory
[EFI_TE_IMAGE_DIRECTORY_ENTRY_BASERELOC
].Size
!= 0)
907 PeHdr
->OptionalHeader
.NumberOfRvaAndSizes
= EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
+ 1;
908 PeHdr
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
].VirtualAddress
= TEImageHeader
->DataDirectory
[EFI_TE_IMAGE_DIRECTORY_ENTRY_BASERELOC
].VirtualAddress
;
909 PeHdr
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
].Size
= TEImageHeader
->DataDirectory
[EFI_TE_IMAGE_DIRECTORY_ENTRY_BASERELOC
].Size
;
912 if ((TEImageHeader
->DataDirectory
[EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG
].VirtualAddress
!= 0) ||
913 (TEImageHeader
->DataDirectory
[EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG
].Size
!= 0)
915 PeHdr
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG
].VirtualAddress
= TEImageHeader
->DataDirectory
[EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG
].VirtualAddress
;
916 PeHdr
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG
].Size
= TEImageHeader
->DataDirectory
[EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG
].Size
;
917 if (PeHdr
->OptionalHeader
.NumberOfRvaAndSizes
< EFI_IMAGE_DIRECTORY_ENTRY_DEBUG
+ 1) {
918 PeHdr
->OptionalHeader
.NumberOfRvaAndSizes
= EFI_IMAGE_DIRECTORY_ENTRY_DEBUG
+ 1;
922 // NOTE: These values are defaults, and should be verified to be correct in the GenTE utility
924 PeHdr
->OptionalHeader
.SectionAlignment
= 0x10;
927 // Copy the rest of the image to its original offset
930 TEBuffer
+ TEImageHeader
->StrippedSize
,
931 (UINT8
*) CurrentPe32Section
.Pe32Section
+ sizeof (EFI_PE32_SECTION
) + sizeof (EFI_TE_IMAGE_HEADER
),
932 GetLength (CurrentPe32Section
.Pe32Section
->CommonHeader
.Size
) - sizeof (EFI_PE32_SECTION
) -
933 sizeof (EFI_TE_IMAGE_HEADER
)
937 // Initialize context
939 memset (&ImageContext
, 0, sizeof (ImageContext
));
940 ImageContext
.Handle
= (VOID
*) TEBuffer
;
941 ImageContext
.ImageRead
= (PE_COFF_LOADER_READ_FILE
) FfsRebaseImageRead
;
943 Status
= PeCoffLoaderGetImageInfo (&ImageContext
);
945 if (EFI_ERROR (Status
)) {
946 Error (NULL
, 0, 0, "GetImageInfo() call failed on rebase of TE image", FileGuidString
);
951 // Allocate a buffer for the image to be loaded into.
953 MemoryImagePointer
= (UINTN
) (malloc (Pe32ImageSize
+ 0x10000));
954 if (MemoryImagePointer
== 0) {
955 Error (NULL
, 0, 0, "memory allocation error on rebase of TE image", FileGuidString
);
957 return EFI_OUT_OF_RESOURCES
;
959 memset ((void *) MemoryImagePointer
, 0, Pe32ImageSize
+ 0x10000);
960 MemoryImagePointerAligned
= (MemoryImagePointer
+ 0x0FFFF) & (-1 << 16);
963 ImageContext
.ImageAddress
= MemoryImagePointerAligned
;
964 Status
= PeCoffLoaderLoadImage (&ImageContext
);
965 if (EFI_ERROR (Status
)) {
966 Error (NULL
, 0, 0, "LoadImage() call failed on rebase of TE image", FileGuidString
);
968 free ((VOID
*) MemoryImagePointer
);
973 // Check if section-alignment and file-alignment match or not
974 // BUGBUG: TE Image Header lack section-alignment and file-alignment info
977 ImageContext
.DestinationAddress
= NewPe32BaseAddress
;
978 Status
= PeCoffLoaderRelocateImage (&ImageContext
);
979 if (EFI_ERROR (Status
)) {
980 Error (NULL
, 0, 0, "RelocateImage() call failed on rebase of TE image", FileGuidString
);
981 free ((VOID
*) MemoryImagePointer
);
986 ImageAddress
= ImageContext
.ImageAddress
;
987 ImageSize
= ImageContext
.ImageSize
;
988 EntryPoint
= ImageContext
.EntryPoint
;
991 // Since we may have updated the Codeview RVA, we need to insure the PE
992 // header indicates the image is large enough to contain the Codeview data
993 // so it will be loaded properly later if the PEIM is reloaded into memory...
995 PeHdr
= (VOID
*) ((UINTN
) ImageAddress
+ ImageContext
.PeCoffHeaderOffset
);
996 if (PeHdr
->FileHeader
.Machine
== EFI_IMAGE_MACHINE_IA32
) {
997 PeHdrSizeOfImage
= (UINT32
*) (&(*(EFI_IMAGE_OPTIONAL_HEADER32
*) &PeHdr
->OptionalHeader
).SizeOfImage
);
998 PeHdrChecksum
= (UINT32
*) (&(*(EFI_IMAGE_OPTIONAL_HEADER32
*) &PeHdr
->OptionalHeader
).CheckSum
);
999 } else if (PeHdr
->FileHeader
.Machine
== EFI_IMAGE_MACHINE_IA64
) {
1000 PeHdrSizeOfImage
= (UINT32
*) (&(*(EFI_IMAGE_OPTIONAL_HEADER64
*) &PeHdr
->OptionalHeader
).SizeOfImage
);
1001 PeHdrChecksum
= (UINT32
*) (&(*(EFI_IMAGE_OPTIONAL_HEADER64
*) &PeHdr
->OptionalHeader
).CheckSum
);
1007 "unknown machine type in TE image",
1008 "machine type=0x%X, file=%s",
1009 (UINT32
) PeHdr
->FileHeader
.Machine
,
1012 free ((VOID
*) MemoryImagePointer
);
1017 if (*PeHdrSizeOfImage
!= ImageContext
.ImageSize
) {
1018 *PeHdrSizeOfImage
= (UINT32
) ImageContext
.ImageSize
;
1019 if (*PeHdrChecksum
) {
1024 TEImageHeader
->ImageBase
= (UINT64
) (NewPe32BaseAddress
+ TEImageHeader
->StrippedSize
- sizeof (EFI_TE_IMAGE_HEADER
));
1026 (UINT8
*) (CurrentPe32Section
.Pe32Section
+ 1) + sizeof (EFI_TE_IMAGE_HEADER
),
1027 (VOID
*) ((UINT8
*) MemoryImagePointerAligned
+ TEImageHeader
->StrippedSize
),
1028 GetLength (CurrentPe32Section
.Pe32Section
->CommonHeader
.Size
) - sizeof (EFI_PE32_SECTION
) -
1029 sizeof (EFI_TE_IMAGE_HEADER
)
1033 // Get EntryPoint in Flash Region.
1035 EntryPoint
= NewPe32BaseAddress
+ EntryPoint
- ImageAddress
;
1038 // If a map file was selected output mapping information for any file that
1041 if (MapFile
!= NULL
) {
1042 fprintf (MapFile
, "TE File: %s Base:%08lx", FileGuidString
, BaseAddress
);
1043 fprintf (MapFile
, " EntryPoint:%08lx", EntryPoint
);
1044 if (ImageContext
.PdbPointer
!= NULL
) {
1045 fprintf (MapFile
, " FileName: %s", ImageContext
.PdbPointer
);
1047 fprintf (MapFile
, "\n");
1050 free ((VOID
*) MemoryImagePointer
);
1052 if (FfsFile
->Attributes
& FFS_ATTRIB_TAIL_PRESENT
) {
1053 TailSize
= sizeof (EFI_FFS_FILE_TAIL
);
1058 // Now update file checksum
1060 if (FfsFile
->Attributes
& FFS_ATTRIB_CHECKSUM
) {
1061 SavedState
= FfsFile
->State
;
1062 FfsFile
->IntegrityCheck
.Checksum
.File
= 0;
1064 if (FfsFile
->Attributes
& FFS_ATTRIB_CHECKSUM
) {
1065 FfsFile
->IntegrityCheck
.Checksum
.File
= CalculateChecksum8 (
1067 GetLength (FfsFile
->Size
) - TailSize
1070 FfsFile
->IntegrityCheck
.Checksum
.File
= FFS_FIXED_CHECKSUM
;
1073 FfsFile
->State
= SavedState
;
1076 // Update tail if present
1078 if (FfsFile
->Attributes
& FFS_ATTRIB_TAIL_PRESENT
) {
1079 TailValue
= (EFI_FFS_FILE_TAIL
) (~(FfsFile
->IntegrityCheck
.TailReference
));
1080 *(EFI_FFS_FILE_TAIL
*) (((UINTN
) FfsFile
+ GetLength (FfsFile
->Size
) - sizeof (EFI_FFS_FILE_TAIL
))) = TailValue
;
1084 // If we found no files, then emit an error if no compressed sections either
1086 if (FoundCount
== 0) {
1087 Status
= GetSectionByType (FfsFile
, EFI_SECTION_COMPRESSION
, Index
, &CurrentPe32Section
);
1088 if (EFI_ERROR (Status
)) {
1089 Error (NULL
, 0, 0, "no PE32, TE, nor compressed section found in FV file", FileGuidString
);
1090 return EFI_NOT_FOUND
;
1098 FfsRebaseImageRead (
1099 IN VOID
*FileHandle
,
1100 IN UINTN FileOffset
,
1101 IN OUT UINT32
*ReadSize
,
1106 Routine Description:
1108 Support routine for the PE/COFF Loader that reads a buffer from a PE/COFF file
1112 FileHandle - The handle to the PE/COFF file
1114 FileOffset - The offset, in bytes, into the file to read
1116 ReadSize - The number of bytes to read from the file starting at FileOffset
1118 Buffer - A pointer to the buffer to read the data into.
1122 EFI_SUCCESS - ReadSize bytes of data were read into Buffer from the PE/COFF file starting at FileOffset
1126 CHAR8
*Destination8
;
1130 Destination8
= Buffer
;
1131 Source8
= (CHAR8
*) ((UINTN
) FileHandle
+ FileOffset
);
1134 *(Destination8
++) = *(Source8
++);