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
;
104 ErasePolarity
= FALSE
;
106 // Set utility name for error/warning reporting purposes.
108 SetUtilityName (UTILITY_NAME
);
110 // Verify the correct number of arguments
112 if (argc
!= MAX_ARGS
) {
118 // Initialize variables
120 InputFileName
[0] = 0;
121 OutputFileName
[0] = 0;
124 BaseAddressSet
= FALSE
;
127 ErasePolarity
= FALSE
;
134 // Parse the command line arguments
136 for (Index
= 1; Index
< MAX_ARGS
; Index
+= 2) {
138 // Make sure argument pair begin with - or /
140 if (argv
[Index
][0] != '-' && argv
[Index
][0] != '/') {
142 Error (NULL
, 0, 0, argv
[Index
], "unrecognized option");
146 // Make sure argument specifier is only one letter
148 if (argv
[Index
][2] != 0) {
150 Error (NULL
, 0, 0, argv
[Index
], "unrecognized option");
154 // Determine argument to read
156 switch (argv
[Index
][1]) {
159 if (strlen (InputFileName
) == 0) {
160 strcpy (InputFileName
, argv
[Index
+ 1]);
163 Error (NULL
, 0, 0, argv
[Index
+ 1], "only one -i InputFileName may be specified");
170 if (strlen (OutputFileName
) == 0) {
171 strcpy (OutputFileName
, argv
[Index
+ 1]);
174 Error (NULL
, 0, 0, argv
[Index
+ 1], "only one -o OutputFileName may be specified");
181 if (!BaseAddressSet
) {
182 Status
= AsciiStringToUint64 (argv
[Index
+ 1], FALSE
, &BaseAddress
);
183 if (EFI_ERROR (Status
)) {
185 Error (NULL
, 0, 0, argv
[Index
+ 1], "invalid hex digit given for the base address");
189 BaseAddressSet
= TRUE
;
192 Error (NULL
, 0, 0, argv
[Index
+ 1], "-b BaseAddress may only be specified once");
199 if (strlen (MapFileName
) == 0) {
200 strcpy (MapFileName
, argv
[Index
+ 1]);
203 Error (NULL
, 0, 0, argv
[Index
+ 1], "only one -m MapFileName may be specified");
210 Error (NULL
, 0, 0, argv
[Index
], "unrecognized argument");
217 // Create the Map file if we need it
219 if (strlen (MapFileName
) != 0) {
220 MapFile
= fopen (MapFileName
, "w");
221 if (MapFile
== NULL
) {
222 Error (NULL
, 0, 0, MapFileName
, "failed to open map file");
228 // Open the file containing the FV
230 InputFile
= fopen (InputFileName
, "rb");
231 if (InputFile
== NULL
) {
232 Error (NULL
, 0, 0, InputFileName
, "could not open input file for reading");
236 // Determine size of FV
238 Status
= ReadHeader (InputFile
, &FvSize
, &ErasePolarity
);
239 if (EFI_ERROR (Status
)) {
240 Error (NULL
, 0, 0, "could not parse the FV header", NULL
);
244 // Allocate a buffer for the FV image
246 FvImage
= malloc (FvSize
);
247 if (FvImage
== NULL
) {
248 Error (NULL
, 0, 0, "application error", "memory allocation failed");
252 // Read the entire FV to the buffer
254 BytesRead
= fread (FvImage
, 1, FvSize
, InputFile
);
257 if ((unsigned int) BytesRead
!= FvSize
) {
258 Error (NULL
, 0, 0, InputFileName
, "failed to read from file");
262 // Prepare to walk the FV image
264 InitializeFvLib (FvImage
, FvSize
);
266 // Get the first file
268 Status
= GetNextFile (NULL
, &CurrentFile
);
269 if (EFI_ERROR (Status
)) {
270 Error (NULL
, 0, 0, "cannot find the first file in the FV image", NULL
);
274 // Check if each file should be rebased
276 while (CurrentFile
!= NULL
) {
280 CurrentFileBaseAddress
= BaseAddress
+ ((UINTN
) CurrentFile
- (UINTN
) FvImage
);
281 Status
= FfsRebase (CurrentFile
, CurrentFileBaseAddress
, MapFile
);
283 if (EFI_ERROR (Status
)) {
286 case EFI_INVALID_PARAMETER
:
287 Error (NULL
, 0, 0, "invalid parameter passed to FfsRebase", NULL
);
291 Error (NULL
, 0, 0, "error detected while rebasing -- aborted", NULL
);
294 case EFI_OUT_OF_RESOURCES
:
295 Error (NULL
, 0, 0, "FfsRebase could not allocate required resources", NULL
);
299 Error (NULL
, 0, 0, "FfsRebase could not locate a PE32 section", NULL
);
303 Error (NULL
, 0, 0, "FfsRebase returned unknown status", "status=0x%08X", Status
);
313 Status
= GetNextFile (CurrentFile
, &CurrentFile
);
314 if (EFI_ERROR (Status
)) {
315 Error (NULL
, 0, 0, "cannot find the next file in the FV image", NULL
);
320 // Open the output file
322 OutputFile
= fopen (OutputFileName
, "wb");
323 if (OutputFile
== NULL
) {
324 Error (NULL
, 0, 0, OutputFileName
, "failed to open output file");
328 if (fwrite (FvImage
, 1, FvSize
, OutputFile
) != FvSize
) {
329 Error (NULL
, 0, 0, "failed to write to output file", 0);
334 if (InputFile
!= NULL
) {
338 // If we created an output file, and there was an error, remove it so
339 // subsequent builds will rebuild it.
341 if (OutputFile
!= NULL
) {
342 if (GetUtilityStatus () == STATUS_ERROR
) {
343 remove (OutputFileName
);
349 if (MapFile
!= NULL
) {
353 if (FvImage
!= NULL
) {
357 return GetUtilityStatus ();
364 OUT BOOLEAN
*ErasePolarity
370 This function determines the size of the FV and the erase polarity. The
371 erase polarity is the FALSE value for file state.
375 InputFile The file that contains the FV image.
376 FvSize The size of the FV.
377 ErasePolarity The FV erase polarity.
381 EFI_SUCCESS Function completed successfully.
382 EFI_INVALID_PARAMETER A required parameter was NULL or is out of range.
383 EFI_ABORTED The function encountered an error.
387 EFI_FIRMWARE_VOLUME_HEADER VolumeHeader
;
388 EFI_FV_BLOCK_MAP_ENTRY BlockMap
;
396 // Check input parameters
398 if ((InputFile
== NULL
) || (FvSize
== NULL
) || (ErasePolarity
== NULL
)) {
399 Error (NULL
, 0, 0, "ReadHeader()", "invalid input parameter");
400 return EFI_INVALID_PARAMETER
;
405 fread (&VolumeHeader
, sizeof (EFI_FIRMWARE_VOLUME_HEADER
) - sizeof (EFI_FV_BLOCK_MAP_ENTRY
), 1, InputFile
);
406 BytesRead
= sizeof (EFI_FIRMWARE_VOLUME_HEADER
) - sizeof (EFI_FV_BLOCK_MAP_ENTRY
);
407 Signature
[0] = VolumeHeader
.Signature
;
411 // Get erase polarity
413 if (VolumeHeader
.Attributes
& EFI_FVB_ERASE_POLARITY
) {
414 *ErasePolarity
= TRUE
;
418 fread (&BlockMap
, sizeof (EFI_FV_BLOCK_MAP_ENTRY
), 1, InputFile
);
419 BytesRead
+= sizeof (EFI_FV_BLOCK_MAP_ENTRY
);
421 if (BlockMap
.NumBlocks
!= 0) {
422 Size
+= BlockMap
.NumBlocks
* BlockMap
.BlockLength
;
425 } while (!(BlockMap
.NumBlocks
== 0 && BlockMap
.BlockLength
== 0));
427 if (VolumeHeader
.FvLength
!= Size
) {
428 Error (NULL
, 0, 0, "volume size not consistant with block maps", NULL
);
447 Displays the standard utility information to SDTOUT
460 "%s, PEI Rebase Utility. Version %i.%i, %s.\n\n",
462 UTILITY_MAJOR_VERSION
,
463 UTILITY_MINOR_VERSION
,
476 Displays the utility usage syntax to STDOUT
489 "Usage: %s -I InputFileName -O OutputFileName -B BaseAddress [-M MapFile]\n",
492 printf (" Where:\n");
493 printf (" InputFileName is the name of the EFI FV file to rebase.\n");
494 printf (" OutputFileName is the desired output file name.\n");
495 printf (" BaseAddress is the FV base address to rebase agains.\n");
496 printf (" MapFileName is an optional map file of the relocations\n");
497 printf (" Argument pair may be in any order.\n\n");
502 IN OUT EFI_FFS_FILE_HEADER
*FfsFile
,
503 IN EFI_PHYSICAL_ADDRESS BaseAddress
,
504 IN
FILE *MapFile OPTIONAL
510 This function determines if a file is XIP and should be rebased. It will
511 rebase any PE32 sections found in the file using the base address.
515 FfsFile A pointer to Ffs file image.
516 BaseAddress The base address to use for rebasing the file image.
517 MapFile Optional file to dump relocation information into
521 EFI_SUCCESS The image was properly rebased.
522 EFI_INVALID_PARAMETER An input parameter is invalid.
523 EFI_ABORTED An error occurred while rebasing the input file image.
524 EFI_OUT_OF_RESOURCES Could not allocate a required resource.
525 EFI_NOT_FOUND No compressed sections could be found.
530 PE_COFF_LOADER_IMAGE_CONTEXT ImageContext
;
531 UINTN MemoryImagePointer
;
532 UINTN MemoryImagePointerAligned
;
533 EFI_PHYSICAL_ADDRESS ImageAddress
;
535 EFI_PHYSICAL_ADDRESS EntryPoint
;
536 UINT32 Pe32ImageSize
;
537 UINT32 NewPe32BaseAddress
;
539 EFI_FILE_SECTION_POINTER CurrentPe32Section
;
540 EFI_FFS_FILE_STATE SavedState
;
541 EFI_IMAGE_NT_HEADERS
*PeHdr
;
542 UINT32
*PeHdrSizeOfImage
;
543 UINT32
*PeHdrChecksum
;
545 EFI_TE_IMAGE_HEADER
*TEImageHeader
;
547 EFI_IMAGE_DOS_HEADER
*DosHeader
;
548 UINT8 FileGuidString
[80];
550 EFI_FFS_FILE_TAIL TailValue
;
553 // Verify input parameters
555 if (FfsFile
== NULL
) {
556 return EFI_INVALID_PARAMETER
;
560 // Convert the GUID to a string so we can at least report which file
561 // if we find an error.
563 PrintGuidToBuffer (&FfsFile
->Name
, FileGuidString
, sizeof (FileGuidString
), TRUE
);
564 if (FfsFile
->Attributes
& FFS_ATTRIB_TAIL_PRESENT
) {
565 TailSize
= sizeof (EFI_FFS_FILE_TAIL
);
571 // Do some cursory checks on the FFS file contents
573 Status
= VerifyFfsFile (FfsFile
);
574 if (EFI_ERROR (Status
)) {
575 Error (NULL
, 0, 0, "file does not appear to be a valid FFS file, cannot be rebased", FileGuidString
);
576 return EFI_INVALID_PARAMETER
;
579 memset (&ImageContext
, 0, sizeof (ImageContext
));
582 // Check if XIP file type. If not XIP, don't rebase.
584 if (FfsFile
->Type
!= EFI_FV_FILETYPE_PEI_CORE
&&
585 FfsFile
->Type
!= EFI_FV_FILETYPE_PEIM
&&
586 FfsFile
->Type
!= EFI_FV_FILETYPE_SECURITY_CORE
&&
587 FfsFile
->Type
!= EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER
593 // Rebase each PE32 section
595 Status
= EFI_SUCCESS
;
597 for (Index
= 1;; Index
++) {
598 Status
= GetSectionByType (FfsFile
, EFI_SECTION_PE32
, Index
, &CurrentPe32Section
);
599 if (EFI_ERROR (Status
)) {
606 // Calculate the PE32 base address, the FFS file base plus the offset of the PE32 section
608 NewPe32BaseAddress
= ((UINT32
) BaseAddress
) + ((UINTN
) CurrentPe32Section
.Pe32Section
+ sizeof (EFI_COMMON_SECTION_HEADER
) - (UINTN
) FfsFile
);
611 // Initialize context
613 memset (&ImageContext
, 0, sizeof (ImageContext
));
614 ImageContext
.Handle
= (VOID
*) ((UINTN
) CurrentPe32Section
.Pe32Section
+ sizeof (EFI_PE32_SECTION
));
615 ImageContext
.ImageRead
= (PE_COFF_LOADER_READ_FILE
) FfsRebaseImageRead
;
617 Status
= PeCoffLoaderGetImageInfo (&ImageContext
);
619 if (EFI_ERROR (Status
)) {
620 Error (NULL
, 0, 0, "GetImageInfo() call failed on rebase", FileGuidString
);
624 // Allocate a buffer for the image to be loaded into.
626 Pe32ImageSize
= GetLength (CurrentPe32Section
.Pe32Section
->CommonHeader
.Size
) - sizeof (EFI_PE32_SECTION
);
627 MemoryImagePointer
= (UINTN
) (malloc (Pe32ImageSize
+ 0x1000));
628 if (MemoryImagePointer
== 0) {
629 Error (NULL
, 0, 0, "memory allocation failure", NULL
);
630 return EFI_OUT_OF_RESOURCES
;
632 memset ((void *) MemoryImagePointer
, 0, Pe32ImageSize
+ 0x1000);
633 MemoryImagePointerAligned
= (MemoryImagePointer
+ 0x0FFF) & (-1 << 12);
636 ImageContext
.ImageAddress
= MemoryImagePointerAligned
;
638 Status
= PeCoffLoaderLoadImage (&ImageContext
);
639 if (EFI_ERROR (Status
)) {
640 Error (NULL
, 0, 0, "LoadImage() call failed on rebase", FileGuidString
);
641 free ((VOID
*) MemoryImagePointer
);
645 ImageContext
.DestinationAddress
= NewPe32BaseAddress
;
646 Status
= PeCoffLoaderRelocateImage (&ImageContext
);
647 if (EFI_ERROR (Status
)) {
648 Error (NULL
, 0, 0, "RelocateImage() call failed on rebase", FileGuidString
);
649 free ((VOID
*) MemoryImagePointer
);
653 ImageAddress
= ImageContext
.ImageAddress
;
654 ImageSize
= ImageContext
.ImageSize
;
655 EntryPoint
= ImageContext
.EntryPoint
;
657 if (ImageSize
> Pe32ImageSize
) {
662 "rebased image is larger than original PE32 image",
663 "0x%X > 0x%X, file %s",
668 free ((VOID
*) MemoryImagePointer
);
672 // Since we may have updated the Codeview RVA, we need to insure the PE
673 // header indicates the image is large enough to contain the Codeview data
674 // so it will be loaded properly later if the PEIM is reloaded into memory...
676 PeHdr
= (VOID
*) ((UINTN
) ImageAddress
+ ImageContext
.PeCoffHeaderOffset
);
677 if (PeHdr
->FileHeader
.Machine
== EFI_IMAGE_MACHINE_IA32
) {
678 PeHdrSizeOfImage
= (UINT32
*) (&(*(EFI_IMAGE_OPTIONAL_HEADER32
*) &PeHdr
->OptionalHeader
).SizeOfImage
);
679 PeHdrChecksum
= (UINT32
*) (&(*(EFI_IMAGE_OPTIONAL_HEADER32
*) &PeHdr
->OptionalHeader
).CheckSum
);
680 } else if (PeHdr
->FileHeader
.Machine
== EFI_IMAGE_MACHINE_IA64
) {
681 PeHdrSizeOfImage
= (UINT32
*) (&(*(EFI_IMAGE_OPTIONAL_HEADER64
*) &PeHdr
->OptionalHeader
).SizeOfImage
);
682 PeHdrChecksum
= (UINT32
*) (&(*(EFI_IMAGE_OPTIONAL_HEADER64
*) &PeHdr
->OptionalHeader
).CheckSum
);
683 } else if (PeHdr
->FileHeader
.Machine
== EFI_IMAGE_MACHINE_X64
) {
684 PeHdrSizeOfImage
= (UINT32
*) (&(*(EFI_IMAGE_OPTIONAL_HEADER64
*) &PeHdr
->OptionalHeader
).SizeOfImage
);
685 PeHdrChecksum
= (UINT32
*) (&(*(EFI_IMAGE_OPTIONAL_HEADER64
*) &PeHdr
->OptionalHeader
).CheckSum
);
691 "unknown machine type in PE32 image",
692 "machine type=0x%X, file=%s",
693 (UINT32
) PeHdr
->FileHeader
.Machine
,
696 free ((VOID
*) MemoryImagePointer
);
700 if (*PeHdrSizeOfImage
!= ImageContext
.ImageSize
) {
701 *PeHdrSizeOfImage
= (UINT32
) ImageContext
.ImageSize
;
702 if (*PeHdrChecksum
) {
707 memcpy (CurrentPe32Section
.Pe32Section
+ 1, (VOID
*) MemoryImagePointerAligned
, (UINT32
) ImageSize
);
710 // Get EntryPoint in Flash Region.
712 EntryPoint
= NewPe32BaseAddress
+ EntryPoint
- ImageAddress
;
715 // If a map file was selected output mapping information for any file that
718 if (MapFile
!= NULL
) {
719 fprintf (MapFile
, "PE32 File: %s Base:%08lx", FileGuidString
, BaseAddress
);
720 fprintf (MapFile
, " EntryPoint:%08lx", EntryPoint
);
721 if (ImageContext
.PdbPointer
!= NULL
) {
722 fprintf (MapFile
, " FileName: %s", ImageContext
.PdbPointer
);
724 fprintf (MapFile
, "\n");
727 free ((VOID
*) MemoryImagePointer
);
730 // Now update file checksum
732 if (FfsFile
->Attributes
& FFS_ATTRIB_TAIL_PRESENT
) {
733 TailSize
= sizeof (EFI_FFS_FILE_TAIL
);
738 if (FfsFile
->Attributes
& FFS_ATTRIB_CHECKSUM
) {
739 SavedState
= FfsFile
->State
;
740 FfsFile
->IntegrityCheck
.Checksum
.File
= 0;
742 if (FfsFile
->Attributes
& FFS_ATTRIB_CHECKSUM
) {
743 FfsFile
->IntegrityCheck
.Checksum
.File
= CalculateChecksum8 (
745 GetLength (FfsFile
->Size
) - TailSize
748 FfsFile
->IntegrityCheck
.Checksum
.File
= FFS_FIXED_CHECKSUM
;
751 FfsFile
->State
= SavedState
;
754 // Update tail if present
756 if (FfsFile
->Attributes
& FFS_ATTRIB_TAIL_PRESENT
) {
757 TailValue
= (EFI_FFS_FILE_TAIL
) (~(FfsFile
->IntegrityCheck
.TailReference
));
758 *(EFI_FFS_FILE_TAIL
*) (((UINTN
) FfsFile
+ GetLength (FfsFile
->Size
) - sizeof (EFI_FFS_FILE_TAIL
))) = TailValue
;
762 // Now process TE sections
764 for (Index
= 1;; Index
++) {
765 Status
= GetSectionByType (FfsFile
, EFI_SECTION_TE
, Index
, &CurrentPe32Section
);
766 if (EFI_ERROR (Status
)) {
773 // Calculate the TE base address, the FFS file base plus the offset of the TE section less the size stripped off
776 TEImageHeader
= (EFI_TE_IMAGE_HEADER
*) ((UINT8
*) CurrentPe32Section
.Pe32Section
+ sizeof (EFI_COMMON_SECTION_HEADER
));
778 NewPe32BaseAddress
= ((UINT32
) BaseAddress
) +
780 (UINTN
) CurrentPe32Section
.Pe32Section
+
781 sizeof (EFI_COMMON_SECTION_HEADER
) +
782 sizeof (EFI_TE_IMAGE_HEADER
) -
783 TEImageHeader
->StrippedSize
-
788 // Allocate a buffer to unshrink the image into.
790 Pe32ImageSize
= GetLength (CurrentPe32Section
.Pe32Section
->CommonHeader
.Size
) - sizeof (EFI_PE32_SECTION
) -
791 sizeof (EFI_TE_IMAGE_HEADER
);
792 Pe32ImageSize
+= TEImageHeader
->StrippedSize
;
793 TEBuffer
= (UINT8
*) malloc (Pe32ImageSize
);
794 if (TEBuffer
== NULL
) {
795 Error (NULL
, 0, 0, "failed to allocate memory", NULL
);
796 return EFI_OUT_OF_RESOURCES
;
799 // Expand the image into our buffer and fill in critical fields in the DOS header
800 // Fill in fields required by the loader.
801 // At offset 0x3C is the offset to the PE signature. We'll put it immediately following the offset value
804 memset (TEBuffer
, 0, Pe32ImageSize
);
805 DosHeader
= (EFI_IMAGE_DOS_HEADER
*) TEBuffer
;
806 DosHeader
->e_magic
= EFI_IMAGE_DOS_SIGNATURE
;
807 *(UINT32
*) (TEBuffer
+ 0x3C) = 0x40;
808 PeHdr
= (EFI_IMAGE_NT_HEADERS
*) (TEBuffer
+ 0x40);
809 PeHdr
->Signature
= EFI_IMAGE_NT_SIGNATURE
;
810 PeHdr
->FileHeader
.Machine
= TEImageHeader
->Machine
;
811 PeHdr
->FileHeader
.NumberOfSections
= TEImageHeader
->NumberOfSections
;
814 // 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
815 // the 0x40 bytes for our DOS header.
817 PeHdr
->FileHeader
.SizeOfOptionalHeader
= (UINT16
) (TEImageHeader
->StrippedSize
- 0x40 - sizeof (UINT32
) - sizeof (EFI_IMAGE_FILE_HEADER
));
818 PeHdr
->OptionalHeader
.ImageBase
= (UINTN
) (TEImageHeader
->ImageBase
- TEImageHeader
->StrippedSize
+ sizeof (EFI_TE_IMAGE_HEADER
));
819 PeHdr
->OptionalHeader
.AddressOfEntryPoint
= TEImageHeader
->AddressOfEntryPoint
;
820 PeHdr
->OptionalHeader
.BaseOfCode
= TEImageHeader
->BaseOfCode
;
821 PeHdr
->OptionalHeader
.SizeOfImage
= Pe32ImageSize
;
822 PeHdr
->OptionalHeader
.Subsystem
= TEImageHeader
->Subsystem
;
823 PeHdr
->OptionalHeader
.SizeOfImage
= Pe32ImageSize
;
824 PeHdr
->OptionalHeader
.SizeOfHeaders
= TEImageHeader
->StrippedSize
+ TEImageHeader
->NumberOfSections
*
825 sizeof (EFI_IMAGE_SECTION_HEADER
) - 12;
828 // Set NumberOfRvaAndSizes in the optional header to what we had available in the original image
830 if ((TEImageHeader
->DataDirectory
[EFI_TE_IMAGE_DIRECTORY_ENTRY_BASERELOC
].VirtualAddress
!= 0) ||
831 (TEImageHeader
->DataDirectory
[EFI_TE_IMAGE_DIRECTORY_ENTRY_BASERELOC
].Size
!= 0)
833 PeHdr
->OptionalHeader
.NumberOfRvaAndSizes
= EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
+ 1;
834 PeHdr
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
].VirtualAddress
= TEImageHeader
->DataDirectory
[EFI_TE_IMAGE_DIRECTORY_ENTRY_BASERELOC
].VirtualAddress
;
835 PeHdr
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
].Size
= TEImageHeader
->DataDirectory
[EFI_TE_IMAGE_DIRECTORY_ENTRY_BASERELOC
].Size
;
838 if ((TEImageHeader
->DataDirectory
[EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG
].VirtualAddress
!= 0) ||
839 (TEImageHeader
->DataDirectory
[EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG
].Size
!= 0)
841 PeHdr
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG
].VirtualAddress
= TEImageHeader
->DataDirectory
[EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG
].VirtualAddress
;
842 PeHdr
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG
].Size
= TEImageHeader
->DataDirectory
[EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG
].Size
;
843 if (PeHdr
->OptionalHeader
.NumberOfRvaAndSizes
< EFI_IMAGE_DIRECTORY_ENTRY_DEBUG
+ 1) {
844 PeHdr
->OptionalHeader
.NumberOfRvaAndSizes
= EFI_IMAGE_DIRECTORY_ENTRY_DEBUG
+ 1;
848 // NOTE: These values are defaults, and should be verified to be correct in the GenTE utility
850 PeHdr
->OptionalHeader
.SectionAlignment
= 0x10;
853 // Copy the rest of the image to its original offset
856 TEBuffer
+ TEImageHeader
->StrippedSize
,
857 (UINT8
*) CurrentPe32Section
.Pe32Section
+ sizeof (EFI_PE32_SECTION
) + sizeof (EFI_TE_IMAGE_HEADER
),
858 GetLength (CurrentPe32Section
.Pe32Section
->CommonHeader
.Size
) - sizeof (EFI_PE32_SECTION
) -
859 sizeof (EFI_TE_IMAGE_HEADER
)
863 // Initialize context
865 memset (&ImageContext
, 0, sizeof (ImageContext
));
866 ImageContext
.Handle
= (VOID
*) TEBuffer
;
867 ImageContext
.ImageRead
= (PE_COFF_LOADER_READ_FILE
) FfsRebaseImageRead
;
869 Status
= PeCoffLoaderGetImageInfo (&ImageContext
);
871 if (EFI_ERROR (Status
)) {
872 Error (NULL
, 0, 0, "GetImageInfo() call failed on rebase of TE image", FileGuidString
);
877 // Allocate a buffer for the image to be loaded into.
879 MemoryImagePointer
= (UINTN
) (malloc (Pe32ImageSize
+ 0x1000));
880 if (MemoryImagePointer
== 0) {
881 Error (NULL
, 0, 0, "memory allocation error on rebase of TE image", FileGuidString
);
883 return EFI_OUT_OF_RESOURCES
;
885 memset ((void *) MemoryImagePointer
, 0, Pe32ImageSize
+ 0x1000);
886 MemoryImagePointerAligned
= (MemoryImagePointer
+ 0x0FFF) & (-1 << 12);
889 ImageContext
.ImageAddress
= MemoryImagePointerAligned
;
890 Status
= PeCoffLoaderLoadImage (&ImageContext
);
891 if (EFI_ERROR (Status
)) {
892 Error (NULL
, 0, 0, "LoadImage() call failed on rebase of TE image", FileGuidString
);
894 free ((VOID
*) MemoryImagePointer
);
898 ImageContext
.DestinationAddress
= NewPe32BaseAddress
;
899 Status
= PeCoffLoaderRelocateImage (&ImageContext
);
900 if (EFI_ERROR (Status
)) {
901 Error (NULL
, 0, 0, "RelocateImage() call failed on rebase of TE image", FileGuidString
);
902 free ((VOID
*) MemoryImagePointer
);
907 ImageAddress
= ImageContext
.ImageAddress
;
908 ImageSize
= ImageContext
.ImageSize
;
909 EntryPoint
= ImageContext
.EntryPoint
;
912 // Since we may have updated the Codeview RVA, we need to insure the PE
913 // header indicates the image is large enough to contain the Codeview data
914 // so it will be loaded properly later if the PEIM is reloaded into memory...
916 PeHdr
= (VOID
*) ((UINTN
) ImageAddress
+ ImageContext
.PeCoffHeaderOffset
);
917 if (PeHdr
->FileHeader
.Machine
== EFI_IMAGE_MACHINE_IA32
) {
918 PeHdrSizeOfImage
= (UINT32
*) (&(*(EFI_IMAGE_OPTIONAL_HEADER32
*) &PeHdr
->OptionalHeader
).SizeOfImage
);
919 PeHdrChecksum
= (UINT32
*) (&(*(EFI_IMAGE_OPTIONAL_HEADER32
*) &PeHdr
->OptionalHeader
).CheckSum
);
920 } else if (PeHdr
->FileHeader
.Machine
== EFI_IMAGE_MACHINE_IA64
) {
921 PeHdrSizeOfImage
= (UINT32
*) (&(*(EFI_IMAGE_OPTIONAL_HEADER64
*) &PeHdr
->OptionalHeader
).SizeOfImage
);
922 PeHdrChecksum
= (UINT32
*) (&(*(EFI_IMAGE_OPTIONAL_HEADER64
*) &PeHdr
->OptionalHeader
).CheckSum
);
928 "unknown machine type in TE image",
929 "machine type=0x%X, file=%s",
930 (UINT32
) PeHdr
->FileHeader
.Machine
,
933 free ((VOID
*) MemoryImagePointer
);
938 if (*PeHdrSizeOfImage
!= ImageContext
.ImageSize
) {
939 *PeHdrSizeOfImage
= (UINT32
) ImageContext
.ImageSize
;
940 if (*PeHdrChecksum
) {
945 TEImageHeader
->ImageBase
= (UINT64
) (NewPe32BaseAddress
+ TEImageHeader
->StrippedSize
- sizeof (EFI_TE_IMAGE_HEADER
));
947 (UINT8
*) (CurrentPe32Section
.Pe32Section
+ 1) + sizeof (EFI_TE_IMAGE_HEADER
),
948 (VOID
*) ((UINT8
*) MemoryImagePointerAligned
+ TEImageHeader
->StrippedSize
),
949 GetLength (CurrentPe32Section
.Pe32Section
->CommonHeader
.Size
) - sizeof (EFI_PE32_SECTION
) -
950 sizeof (EFI_TE_IMAGE_HEADER
)
954 // Get EntryPoint in Flash Region.
956 EntryPoint
= NewPe32BaseAddress
+ EntryPoint
- ImageAddress
;
959 // If a map file was selected output mapping information for any file that
962 if (MapFile
!= NULL
) {
963 fprintf (MapFile
, "TE File: %s Base:%08lx", FileGuidString
, BaseAddress
);
964 fprintf (MapFile
, " EntryPoint:%08lx", EntryPoint
);
965 if (ImageContext
.PdbPointer
!= NULL
) {
966 fprintf (MapFile
, " FileName: %s", ImageContext
.PdbPointer
);
968 fprintf (MapFile
, "\n");
971 free ((VOID
*) MemoryImagePointer
);
973 if (FfsFile
->Attributes
& FFS_ATTRIB_TAIL_PRESENT
) {
974 TailSize
= sizeof (EFI_FFS_FILE_TAIL
);
979 // Now update file checksum
981 if (FfsFile
->Attributes
& FFS_ATTRIB_CHECKSUM
) {
982 SavedState
= FfsFile
->State
;
983 FfsFile
->IntegrityCheck
.Checksum
.File
= 0;
985 if (FfsFile
->Attributes
& FFS_ATTRIB_CHECKSUM
) {
986 FfsFile
->IntegrityCheck
.Checksum
.File
= CalculateChecksum8 (
988 GetLength (FfsFile
->Size
) - TailSize
991 FfsFile
->IntegrityCheck
.Checksum
.File
= FFS_FIXED_CHECKSUM
;
994 FfsFile
->State
= SavedState
;
997 // Update tail if present
999 if (FfsFile
->Attributes
& FFS_ATTRIB_TAIL_PRESENT
) {
1000 TailValue
= (EFI_FFS_FILE_TAIL
) (~(FfsFile
->IntegrityCheck
.TailReference
));
1001 *(EFI_FFS_FILE_TAIL
*) (((UINTN
) FfsFile
+ GetLength (FfsFile
->Size
) - sizeof (EFI_FFS_FILE_TAIL
))) = TailValue
;
1005 // If we found no files, then emit an error if no compressed sections either
1007 if (FoundCount
== 0) {
1008 Status
= GetSectionByType (FfsFile
, EFI_SECTION_COMPRESSION
, Index
, &CurrentPe32Section
);
1009 if (EFI_ERROR (Status
)) {
1010 Error (NULL
, 0, 0, "no PE32, TE, nor compressed section found in FV file", FileGuidString
);
1011 return EFI_NOT_FOUND
;
1019 FfsRebaseImageRead (
1020 IN VOID
*FileHandle
,
1021 IN UINTN FileOffset
,
1022 IN OUT UINT32
*ReadSize
,
1027 Routine Description:
1029 Support routine for the PE/COFF Loader that reads a buffer from a PE/COFF file
1033 FileHandle - The handle to the PE/COFF file
1035 FileOffset - The offset, in bytes, into the file to read
1037 ReadSize - The number of bytes to read from the file starting at FileOffset
1039 Buffer - A pointer to the buffer to read the data into.
1043 EFI_SUCCESS - ReadSize bytes of data were read into Buffer from the PE/COFF file starting at FileOffset
1047 CHAR8
*Destination8
;
1051 Destination8
= Buffer
;
1052 Source8
= (CHAR8
*) ((UINTN
) FileHandle
+ FileOffset
);
1055 *(Destination8
++) = *(Source8
++);