2 This file contains the internal functions required to generate a Firmware Volume.
4 Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>
5 Portions Copyright (c) 2011 - 2013, ARM Ltd. All rights reserved.<BR>
6 Portions Copyright (c) 2016 HP Development Company, L.P.<BR>
7 SPDX-License-Identifier: BSD-2-Clause-Patent
15 #if defined(__FreeBSD__)
17 #elif defined(__GNUC__)
18 #include <uuid/uuid.h>
29 #include <Guid/FfsSectionAlignmentPadding.h>
31 #include "WinNtInclude.h"
32 #include "GenFvInternalLib.h"
34 #include "PeCoffLib.h"
36 #define ARMT_UNCONDITIONAL_JUMP_INSTRUCTION 0xEB000000
37 #define ARM64_UNCONDITIONAL_JUMP_INSTRUCTION 0x14000000
40 STATIC UINT32 MaxFfsAlignment
= 0;
41 BOOLEAN VtfFileFlag
= FALSE
;
43 EFI_GUID mEfiFirmwareVolumeTopFileGuid
= EFI_FFS_VOLUME_TOP_FILE_GUID
;
44 EFI_GUID mFileGuidArray
[MAX_NUMBER_OF_FILES_IN_FV
];
45 EFI_GUID mZeroGuid
= {0x0, 0x0, 0x0, {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}};
46 EFI_GUID mDefaultCapsuleGuid
= {0x3B6686BD, 0x0D76, 0x4030, { 0xB7, 0x0E, 0xB5, 0x51, 0x9E, 0x2F, 0xC5, 0xA0 }};
47 EFI_GUID mEfiFfsSectionAlignmentPaddingGuid
= EFI_FFS_SECTION_ALIGNMENT_PADDING_GUID
;
49 CHAR8
*mFvbAttributeName
[] = {
50 EFI_FVB2_READ_DISABLED_CAP_STRING
,
51 EFI_FVB2_READ_ENABLED_CAP_STRING
,
52 EFI_FVB2_READ_STATUS_STRING
,
53 EFI_FVB2_WRITE_DISABLED_CAP_STRING
,
54 EFI_FVB2_WRITE_ENABLED_CAP_STRING
,
55 EFI_FVB2_WRITE_STATUS_STRING
,
56 EFI_FVB2_LOCK_CAP_STRING
,
57 EFI_FVB2_LOCK_STATUS_STRING
,
59 EFI_FVB2_STICKY_WRITE_STRING
,
60 EFI_FVB2_MEMORY_MAPPED_STRING
,
61 EFI_FVB2_ERASE_POLARITY_STRING
,
62 EFI_FVB2_READ_LOCK_CAP_STRING
,
63 EFI_FVB2_READ_LOCK_STATUS_STRING
,
64 EFI_FVB2_WRITE_LOCK_CAP_STRING
,
65 EFI_FVB2_WRITE_LOCK_STATUS_STRING
68 CHAR8
*mFvbAlignmentName
[] = {
69 EFI_FVB2_ALIGNMENT_1_STRING
,
70 EFI_FVB2_ALIGNMENT_2_STRING
,
71 EFI_FVB2_ALIGNMENT_4_STRING
,
72 EFI_FVB2_ALIGNMENT_8_STRING
,
73 EFI_FVB2_ALIGNMENT_16_STRING
,
74 EFI_FVB2_ALIGNMENT_32_STRING
,
75 EFI_FVB2_ALIGNMENT_64_STRING
,
76 EFI_FVB2_ALIGNMENT_128_STRING
,
77 EFI_FVB2_ALIGNMENT_256_STRING
,
78 EFI_FVB2_ALIGNMENT_512_STRING
,
79 EFI_FVB2_ALIGNMENT_1K_STRING
,
80 EFI_FVB2_ALIGNMENT_2K_STRING
,
81 EFI_FVB2_ALIGNMENT_4K_STRING
,
82 EFI_FVB2_ALIGNMENT_8K_STRING
,
83 EFI_FVB2_ALIGNMENT_16K_STRING
,
84 EFI_FVB2_ALIGNMENT_32K_STRING
,
85 EFI_FVB2_ALIGNMENT_64K_STRING
,
86 EFI_FVB2_ALIGNMENT_128K_STRING
,
87 EFI_FVB2_ALIGNMENT_256K_STRING
,
88 EFI_FVB2_ALIGNMENT_512K_STRING
,
89 EFI_FVB2_ALIGNMENT_1M_STRING
,
90 EFI_FVB2_ALIGNMENT_2M_STRING
,
91 EFI_FVB2_ALIGNMENT_4M_STRING
,
92 EFI_FVB2_ALIGNMENT_8M_STRING
,
93 EFI_FVB2_ALIGNMENT_16M_STRING
,
94 EFI_FVB2_ALIGNMENT_32M_STRING
,
95 EFI_FVB2_ALIGNMENT_64M_STRING
,
96 EFI_FVB2_ALIGNMENT_128M_STRING
,
97 EFI_FVB2_ALIGNMENT_256M_STRING
,
98 EFI_FVB2_ALIGNMENT_512M_STRING
,
99 EFI_FVB2_ALIGNMENT_1G_STRING
,
100 EFI_FVB2_ALIGNMENT_2G_STRING
104 // This data array will be located at the base of the Firmware Volume Header (FVH)
105 // in the boot block. It must not exceed 14 bytes of code. The last 2 bytes
106 // will be used to keep the FVH checksum consistent.
107 // This code will be run in response to a startup IPI for HT-enabled systems.
109 #define SIZEOF_STARTUP_DATA_ARRAY 0x10
111 UINT8 m128kRecoveryStartupApDataArray
[SIZEOF_STARTUP_DATA_ARRAY
] = {
113 // EA D0 FF 00 F0 ; far jmp F000:FFD0
114 // 0, 0, 0, 0, 0, 0, 0, 0, 0, ; Reserved bytes
115 // 0, 0 ; Checksum Padding
135 UINT8 m64kRecoveryStartupApDataArray
[SIZEOF_STARTUP_DATA_ARRAY
] = {
137 // EB CE ; jmp short ($-0x30)
138 // ; (from offset 0x0 to offset 0xFFD0)
139 // 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ; Reserved bytes
140 // 0, 0 ; Checksum Padding
161 CAP_INFO mCapDataInfo
;
162 BOOLEAN mIsLargeFfs
= FALSE
;
164 EFI_PHYSICAL_ADDRESS mFvBaseAddress
[0x10];
165 UINT32 mFvBaseAddressNumber
= 0;
169 IN MEMORY_FILE
*InfFile
,
176 This function parses a FV.INF file and copies info into a FV_INFO structure.
180 InfFile Memory file image.
181 FvInfo Information read from INF file.
185 EFI_SUCCESS INF file information successfully retrieved.
186 EFI_ABORTED INF file has an invalid format.
187 EFI_NOT_FOUND A required string was not found in the INF file.
190 CHAR8 Value
[MAX_LONG_FILE_PATH
];
198 // Read the FV base address
200 if (!mFvDataInfo
.BaseAddressSet
) {
201 Status
= FindToken (InfFile
, OPTIONS_SECTION_STRING
, EFI_FV_BASE_ADDRESS_STRING
, 0, Value
);
202 if (Status
== EFI_SUCCESS
) {
204 // Get the base address
206 Status
= AsciiStringToUint64 (Value
, FALSE
, &Value64
);
207 if (EFI_ERROR (Status
)) {
208 Error (NULL
, 0, 2000, "Invalid parameter", "%s = %s", EFI_FV_BASE_ADDRESS_STRING
, Value
);
211 DebugMsg (NULL
, 0, 9, "rebase address", "%s = %s", EFI_FV_BASE_ADDRESS_STRING
, Value
);
213 FvInfo
->BaseAddress
= Value64
;
214 FvInfo
->BaseAddressSet
= TRUE
;
219 // Read the FV File System Guid
221 if (!FvInfo
->FvFileSystemGuidSet
) {
222 Status
= FindToken (InfFile
, OPTIONS_SECTION_STRING
, EFI_FV_FILESYSTEMGUID_STRING
, 0, Value
);
223 if (Status
== EFI_SUCCESS
) {
225 // Get the guid value
227 Status
= StringToGuid (Value
, &GuidValue
);
228 if (EFI_ERROR (Status
)) {
229 Error (NULL
, 0, 2000, "Invalid parameter", "%s = %s", EFI_FV_FILESYSTEMGUID_STRING
, Value
);
232 memcpy (&FvInfo
->FvFileSystemGuid
, &GuidValue
, sizeof (EFI_GUID
));
233 FvInfo
->FvFileSystemGuidSet
= TRUE
;
238 // Read the FV Extension Header File Name
240 Status
= FindToken (InfFile
, ATTRIBUTES_SECTION_STRING
, EFI_FV_EXT_HEADER_FILE_NAME
, 0, Value
);
241 if (Status
== EFI_SUCCESS
) {
242 strcpy (FvInfo
->FvExtHeaderFile
, Value
);
246 // Read the FV file name
248 Status
= FindToken (InfFile
, OPTIONS_SECTION_STRING
, EFI_FV_FILE_NAME_STRING
, 0, Value
);
249 if (Status
== EFI_SUCCESS
) {
251 // copy the file name
253 strcpy (FvInfo
->FvName
, Value
);
259 for (Index
= 0; Index
< sizeof (mFvbAttributeName
)/sizeof (CHAR8
*); Index
++) {
260 if ((mFvbAttributeName
[Index
] != NULL
) && \
261 (FindToken (InfFile
, ATTRIBUTES_SECTION_STRING
, mFvbAttributeName
[Index
], 0, Value
) == EFI_SUCCESS
)) {
262 if ((strcmp (Value
, TRUE_STRING
) == 0) || (strcmp (Value
, ONE_STRING
) == 0)) {
263 FvInfo
->FvAttributes
|= 1 << Index
;
264 } else if ((strcmp (Value
, FALSE_STRING
) != 0) && (strcmp (Value
, ZERO_STRING
) != 0)) {
265 Error (NULL
, 0, 2000, "Invalid parameter", "%s expected %s | %s", mFvbAttributeName
[Index
], TRUE_STRING
, FALSE_STRING
);
274 for (Index
= 0; Index
< sizeof (mFvbAlignmentName
)/sizeof (CHAR8
*); Index
++) {
275 if (FindToken (InfFile
, ATTRIBUTES_SECTION_STRING
, mFvbAlignmentName
[Index
], 0, Value
) == EFI_SUCCESS
) {
276 if (strcmp (Value
, TRUE_STRING
) == 0) {
277 FvInfo
->FvAttributes
|= Index
<< 16;
278 DebugMsg (NULL
, 0, 9, "FV file alignment", "Align = %s", mFvbAlignmentName
[Index
]);
285 // Read weak alignment flag
287 Status
= FindToken (InfFile
, ATTRIBUTES_SECTION_STRING
, EFI_FV_WEAK_ALIGNMENT_STRING
, 0, Value
);
288 if (Status
== EFI_SUCCESS
) {
289 if ((strcmp (Value
, TRUE_STRING
) == 0) || (strcmp (Value
, ONE_STRING
) == 0)) {
290 FvInfo
->FvAttributes
|= EFI_FVB2_WEAK_ALIGNMENT
;
291 } else if ((strcmp (Value
, FALSE_STRING
) != 0) && (strcmp (Value
, ZERO_STRING
) != 0)) {
292 Error (NULL
, 0, 2000, "Invalid parameter", "Weak alignment value expected one of TRUE, FALSE, 1 or 0.");
300 for (Index
= 0; Index
< MAX_NUMBER_OF_FV_BLOCKS
; Index
++) {
301 if (FvInfo
->FvBlocks
[Index
].Length
== 0) {
305 Status
= FindToken (InfFile
, OPTIONS_SECTION_STRING
, EFI_BLOCK_SIZE_STRING
, Index
, Value
);
307 if (Status
== EFI_SUCCESS
) {
309 // Update the size of block
311 Status
= AsciiStringToUint64 (Value
, FALSE
, &Value64
);
312 if (EFI_ERROR (Status
)) {
313 Error (NULL
, 0, 2000, "Invalid parameter", "%s = %s", EFI_BLOCK_SIZE_STRING
, Value
);
317 FvInfo
->FvBlocks
[Index
].Length
= (UINT32
) Value64
;
318 DebugMsg (NULL
, 0, 9, "FV Block Size", "%s = %s", EFI_BLOCK_SIZE_STRING
, Value
);
321 // If there is no blocks size, but there is the number of block, then we have a mismatched pair
322 // and should return an error.
324 Status
= FindToken (InfFile
, OPTIONS_SECTION_STRING
, EFI_NUM_BLOCKS_STRING
, Index
, Value
);
325 if (!EFI_ERROR (Status
)) {
326 Error (NULL
, 0, 2000, "Invalid parameter", "both %s and %s must be specified.", EFI_NUM_BLOCKS_STRING
, EFI_BLOCK_SIZE_STRING
);
337 // Read blocks number
339 Status
= FindToken (InfFile
, OPTIONS_SECTION_STRING
, EFI_NUM_BLOCKS_STRING
, Index
, Value
);
341 if (Status
== EFI_SUCCESS
) {
343 // Update the number of blocks
345 Status
= AsciiStringToUint64 (Value
, FALSE
, &Value64
);
346 if (EFI_ERROR (Status
)) {
347 Error (NULL
, 0, 2000, "Invalid parameter", "%s = %s", EFI_NUM_BLOCKS_STRING
, Value
);
351 FvInfo
->FvBlocks
[Index
].NumBlocks
= (UINT32
) Value64
;
352 DebugMsg (NULL
, 0, 9, "FV Block Number", "%s = %s", EFI_NUM_BLOCKS_STRING
, Value
);
358 Error (NULL
, 0, 2001, "Missing required argument", "block size.");
366 for (Number
= 0; Number
< MAX_NUMBER_OF_FILES_IN_FV
; Number
++) {
367 if (FvInfo
->FvFiles
[Number
][0] == '\0') {
372 for (Index
= 0; Number
+ Index
< MAX_NUMBER_OF_FILES_IN_FV
; Index
++) {
374 // Read the FFS file list
376 Status
= FindToken (InfFile
, FILES_SECTION_STRING
, EFI_FILE_NAME_STRING
, Index
, Value
);
378 if (Status
== EFI_SUCCESS
) {
382 strcpy (FvInfo
->FvFiles
[Number
+ Index
], Value
);
383 DebugMsg (NULL
, 0, 9, "FV component file", "the %uth name is %s", (unsigned) Index
, Value
);
389 if ((Index
+ Number
) == 0) {
390 Warning (NULL
, 0, 0, "FV components are not specified.", NULL
);
398 IN EFI_FFS_FILE_HEADER
*FfsFile
,
399 IN EFI_FIRMWARE_VOLUME_HEADER
*FvHeader
405 This function changes the FFS file attributes based on the erase polarity
406 of the FV. Update the reserved bits of State to EFI_FVB2_ERASE_POLARITY.
419 if (FvHeader
->Attributes
& EFI_FVB2_ERASE_POLARITY
) {
420 FfsFile
->State
= (UINT8
)~(FfsFile
->State
);
421 // FfsFile->State |= ~(UINT8) EFI_FILE_ALL_STATE_BITS;
427 IN EFI_FFS_FILE_HEADER
*FfsFile
,
428 IN OUT UINT32
*Alignment
434 This function determines the alignment of the FFS input file from the file
439 FfsFile FFS file to parse
440 Alignment The minimum required alignment offset of the FFS file
444 EFI_SUCCESS The function completed successfully.
445 EFI_INVALID_PARAMETER One of the input parameters was invalid.
446 EFI_ABORTED An error occurred.
451 // Verify input parameters.
453 if (FfsFile
== NULL
|| Alignment
== NULL
) {
454 return EFI_INVALID_PARAMETER
;
457 switch ((FfsFile
->Attributes
>> 3) & 0x07) {
462 //if bit 1 have set, 128K byte alignment
464 if (FfsFile
->Attributes
& FFS_ATTRIB_DATA_ALIGNMENT2
) {
474 //if bit 1 have set, 256K byte alignment
476 if (FfsFile
->Attributes
& FFS_ATTRIB_DATA_ALIGNMENT2
) {
485 // 128 byte alignment
486 //if bit 1 have set, 512K byte alignment
488 if (FfsFile
->Attributes
& FFS_ATTRIB_DATA_ALIGNMENT2
) {
497 // 512 byte alignment
498 //if bit 1 have set, 1M byte alignment
500 if (FfsFile
->Attributes
& FFS_ATTRIB_DATA_ALIGNMENT2
) {
510 //if bit 1 have set, 2M byte alignment
512 if (FfsFile
->Attributes
& FFS_ATTRIB_DATA_ALIGNMENT2
) {
522 //if bit 1 have set, 4M byte alignment
524 if (FfsFile
->Attributes
& FFS_ATTRIB_DATA_ALIGNMENT2
) {
533 // 32K byte alignment
534 //if bit 1 have set , 8M byte alignment
536 if (FfsFile
->Attributes
& FFS_ATTRIB_DATA_ALIGNMENT2
) {
545 // 64K byte alignment
546 //if bit 1 have set, 16M alignment
548 if (FfsFile
->Attributes
& FFS_ATTRIB_DATA_ALIGNMENT2
) {
564 IN OUT MEMORY_FILE
*FvImage
,
565 IN UINT32 DataAlignment
,
567 IN EFI_FIRMWARE_VOLUME_EXT_HEADER
*ExtHeader
,
568 IN UINT32 NextFfsSize
574 This function adds a pad file to the FV image if it required to align the
575 data of the next file.
579 FvImage The memory image of the FV to add it to.
580 The current offset must be valid.
581 DataAlignment The data alignment of the next FFS file.
582 FvEnd End of the empty data in FvImage.
583 ExtHeader PI FvExtHeader Optional
587 EFI_SUCCESS The function completed successfully.
588 EFI_INVALID_PARAMETER One of the input parameters was invalid.
589 EFI_OUT_OF_RESOURCES Insufficient resources exist in the FV to complete
594 EFI_FFS_FILE_HEADER
*PadFile
;
596 UINT32 NextFfsHeaderSize
;
597 UINT32 CurFfsHeaderSize
;
601 CurFfsHeaderSize
= sizeof (EFI_FFS_FILE_HEADER
);
603 // Verify input parameters.
605 if (FvImage
== NULL
) {
606 return EFI_INVALID_PARAMETER
;
610 // Calculate the pad file size
614 // Append extension header size
616 if (ExtHeader
!= NULL
) {
617 PadFileSize
= ExtHeader
->ExtHeaderSize
;
618 if (PadFileSize
+ sizeof (EFI_FFS_FILE_HEADER
) >= MAX_FFS_SIZE
) {
619 CurFfsHeaderSize
= sizeof (EFI_FFS_FILE_HEADER2
);
621 PadFileSize
+= CurFfsHeaderSize
;
623 NextFfsHeaderSize
= sizeof (EFI_FFS_FILE_HEADER
);
624 if (NextFfsSize
>= MAX_FFS_SIZE
) {
625 NextFfsHeaderSize
= sizeof (EFI_FFS_FILE_HEADER2
);
628 // Check if a pad file is necessary
630 if (((UINTN
) FvImage
->CurrentFilePointer
- (UINTN
) FvImage
->FileImage
+ NextFfsHeaderSize
) % DataAlignment
== 0) {
633 PadFileSize
= (UINTN
) FvImage
->CurrentFilePointer
- (UINTN
) FvImage
->FileImage
+ sizeof (EFI_FFS_FILE_HEADER
) + NextFfsHeaderSize
;
635 // Add whatever it takes to get to the next aligned address
637 while ((PadFileSize
% DataAlignment
) != 0) {
641 // Subtract the next file header size
643 PadFileSize
-= NextFfsHeaderSize
;
645 // Subtract the starting offset to get size
647 PadFileSize
-= (UINTN
) FvImage
->CurrentFilePointer
- (UINTN
) FvImage
->FileImage
;
651 // Verify that we have enough space for the file header
653 if (((UINTN
) FvImage
->CurrentFilePointer
+ PadFileSize
) > (UINTN
) FvEnd
) {
654 return EFI_OUT_OF_RESOURCES
;
658 // Write pad file header
660 PadFile
= (EFI_FFS_FILE_HEADER
*) FvImage
->CurrentFilePointer
;
663 // Write PadFile FFS header with PadType, don't need to set PAD file guid in its header.
665 PadFile
->Type
= EFI_FV_FILETYPE_FFS_PAD
;
666 PadFile
->Attributes
= 0;
669 // Write pad file size (calculated size minus next file header size)
671 if (PadFileSize
>= MAX_FFS_SIZE
) {
672 memset(PadFile
->Size
, 0, sizeof(UINT8
) * 3);
673 ((EFI_FFS_FILE_HEADER2
*)PadFile
)->ExtendedSize
= PadFileSize
;
674 PadFile
->Attributes
|= FFS_ATTRIB_LARGE_FILE
;
676 PadFile
->Size
[0] = (UINT8
) (PadFileSize
& 0xFF);
677 PadFile
->Size
[1] = (UINT8
) ((PadFileSize
>> 8) & 0xFF);
678 PadFile
->Size
[2] = (UINT8
) ((PadFileSize
>> 16) & 0xFF);
682 // Fill in checksums and state, they must be 0 for checksumming.
684 PadFile
->IntegrityCheck
.Checksum
.Header
= 0;
685 PadFile
->IntegrityCheck
.Checksum
.File
= 0;
687 PadFile
->IntegrityCheck
.Checksum
.Header
= CalculateChecksum8 ((UINT8
*) PadFile
, CurFfsHeaderSize
);
688 PadFile
->IntegrityCheck
.Checksum
.File
= FFS_FIXED_CHECKSUM
;
690 PadFile
->State
= EFI_FILE_HEADER_CONSTRUCTION
| EFI_FILE_HEADER_VALID
| EFI_FILE_DATA_VALID
;
692 (EFI_FFS_FILE_HEADER
*) PadFile
,
693 (EFI_FIRMWARE_VOLUME_HEADER
*) FvImage
->FileImage
697 // Update the current FV pointer
699 FvImage
->CurrentFilePointer
+= PadFileSize
;
701 if (ExtHeader
!= NULL
) {
703 // Copy Fv Extension Header and Set Fv Extension header offset
705 if (ExtHeader
->ExtHeaderSize
> sizeof (EFI_FIRMWARE_VOLUME_EXT_HEADER
)) {
706 for (Index
= sizeof (EFI_FIRMWARE_VOLUME_EXT_HEADER
); Index
< ExtHeader
->ExtHeaderSize
;) {
707 if (((EFI_FIRMWARE_VOLUME_EXT_ENTRY
*)((UINT8
*)ExtHeader
+ Index
))-> ExtEntryType
== EFI_FV_EXT_TYPE_USED_SIZE_TYPE
) {
709 ((EFI_FIRMWARE_VOLUME_EXT_ENTRY_USED_SIZE_TYPE
*)((UINT8
*)ExtHeader
+ Index
))->UsedSize
= mFvTotalSize
;
711 ((EFI_FIRMWARE_VOLUME_EXT_ENTRY_USED_SIZE_TYPE
*)((UINT8
*)ExtHeader
+ Index
))->UsedSize
= mFvTakenSize
;
715 Index
+= ((EFI_FIRMWARE_VOLUME_EXT_ENTRY
*)((UINT8
*)ExtHeader
+ Index
))-> ExtEntrySize
;
718 memcpy ((UINT8
*)PadFile
+ CurFfsHeaderSize
, ExtHeader
, ExtHeader
->ExtHeaderSize
);
719 ((EFI_FIRMWARE_VOLUME_HEADER
*) FvImage
->FileImage
)->ExtHeaderOffset
= (UINT16
) ((UINTN
) ((UINT8
*)PadFile
+ CurFfsHeaderSize
) - (UINTN
) FvImage
->FileImage
);
721 // Make next file start at QWord Boundary
723 while (((UINTN
) FvImage
->CurrentFilePointer
& (EFI_FFS_FILE_HEADER_ALIGNMENT
- 1)) != 0) {
724 FvImage
->CurrentFilePointer
++;
733 IN EFI_FFS_FILE_HEADER
*FileBuffer
739 This function checks the header to validate if it is a VTF file
743 FileBuffer Buffer in which content of a file has been read.
747 TRUE If this is a VTF file
748 FALSE If this is not a VTF file
752 if (!memcmp (&FileBuffer
->Name
, &mEfiFirmwareVolumeTopFileGuid
, sizeof (EFI_GUID
))) {
761 IN OUT
FILE *FvMapFile
,
763 IN EFI_FFS_FILE_HEADER
*FfsFile
,
764 IN EFI_PHYSICAL_ADDRESS ImageBaseAddress
,
765 IN PE_COFF_LOADER_IMAGE_CONTEXT
*pImageContext
771 This function gets the basic debug information (entrypoint, baseaddress, .text, .data section base address)
772 from PE/COFF image and abstracts Pe Map file information and add them into FvMap file for Debug.
776 FvMapFile A pointer to FvMap File
777 FileName Ffs File PathName
778 FfsFile A pointer to Ffs file image.
779 ImageBaseAddress PeImage Base Address.
780 pImageContext Image Context Information.
784 EFI_SUCCESS Added required map information.
788 CHAR8 PeMapFileName
[MAX_LONG_FILE_PATH
];
790 CHAR8 FileGuidName
[MAX_LINE_LEN
];
792 CHAR8 Line
[MAX_LINE_LEN
];
793 CHAR8 KeyWord
[MAX_LINE_LEN
];
794 CHAR8 KeyWord2
[MAX_LINE_LEN
];
795 CHAR8 FunctionName
[MAX_LINE_LEN
];
796 EFI_PHYSICAL_ADDRESS FunctionAddress
;
798 CHAR8 FunctionTypeName
[MAX_LINE_LEN
];
800 UINT32 AddressOfEntryPoint
;
802 EFI_IMAGE_OPTIONAL_HEADER_UNION
*ImgHdr
;
803 EFI_TE_IMAGE_HEADER
*TEImageHeader
;
804 EFI_IMAGE_SECTION_HEADER
*SectionHeader
;
805 long long TempLongAddress
;
806 UINT32 TextVirtualAddress
;
807 UINT32 DataVirtualAddress
;
808 EFI_PHYSICAL_ADDRESS LinkTimeBaseAddress
;
812 // Init local variable
816 // Print FileGuid to string buffer.
818 PrintGuidToBuffer (&FfsFile
->Name
, (UINT8
*)FileGuidName
, MAX_LINE_LEN
, TRUE
);
821 // Construct Map file Name
823 if (strlen (FileName
) >= MAX_LONG_FILE_PATH
) {
826 strncpy (PeMapFileName
, FileName
, MAX_LONG_FILE_PATH
- 1);
827 PeMapFileName
[MAX_LONG_FILE_PATH
- 1] = 0;
830 // Change '\\' to '/', unified path format.
832 Cptr
= PeMapFileName
;
833 while (*Cptr
!= '\0') {
835 *Cptr
= FILE_SEP_CHAR
;
843 Cptr
= PeMapFileName
+ strlen (PeMapFileName
);
844 while ((*Cptr
!= '.') && (Cptr
>= PeMapFileName
)) {
847 if (Cptr
< PeMapFileName
) {
848 return EFI_NOT_FOUND
;
860 while ((*Cptr
!= FILE_SEP_CHAR
) && (Cptr
>= PeMapFileName
)) {
864 if (strlen (Cptr
+ 1) >= MAX_LINE_LEN
) {
867 strncpy (KeyWord
, Cptr
+ 1, MAX_LINE_LEN
- 1);
868 KeyWord
[MAX_LINE_LEN
- 1] = 0;
872 // AddressOfEntryPoint and Offset in Image
874 if (!pImageContext
->IsTeImage
) {
875 ImgHdr
= (EFI_IMAGE_OPTIONAL_HEADER_UNION
*) ((UINT8
*) pImageContext
->Handle
+ pImageContext
->PeCoffHeaderOffset
);
876 AddressOfEntryPoint
= ImgHdr
->Pe32
.OptionalHeader
.AddressOfEntryPoint
;
878 SectionHeader
= (EFI_IMAGE_SECTION_HEADER
*) (
881 sizeof (EFI_IMAGE_FILE_HEADER
) +
882 ImgHdr
->Pe32
.FileHeader
.SizeOfOptionalHeader
884 Index
= ImgHdr
->Pe32
.FileHeader
.NumberOfSections
;
886 TEImageHeader
= (EFI_TE_IMAGE_HEADER
*) pImageContext
->Handle
;
887 AddressOfEntryPoint
= TEImageHeader
->AddressOfEntryPoint
;
888 Offset
= TEImageHeader
->StrippedSize
- sizeof (EFI_TE_IMAGE_HEADER
);
889 SectionHeader
= (EFI_IMAGE_SECTION_HEADER
*) (TEImageHeader
+ 1);
890 Index
= TEImageHeader
->NumberOfSections
;
894 // module information output
896 if (ImageBaseAddress
== 0) {
897 fprintf (FvMapFile
, "%s (dummy) (", KeyWord
);
898 fprintf (FvMapFile
, "BaseAddress=%010llx, ", (unsigned long long) ImageBaseAddress
);
900 fprintf (FvMapFile
, "%s (Fixed Flash Address, ", KeyWord
);
901 fprintf (FvMapFile
, "BaseAddress=0x%010llx, ", (unsigned long long) (ImageBaseAddress
+ Offset
));
904 fprintf (FvMapFile
, "EntryPoint=0x%010llx", (unsigned long long) (ImageBaseAddress
+ AddressOfEntryPoint
));
905 fprintf (FvMapFile
, ")\n");
907 fprintf (FvMapFile
, "(GUID=%s", FileGuidName
);
908 TextVirtualAddress
= 0;
909 DataVirtualAddress
= 0;
910 for (; Index
> 0; Index
--, SectionHeader
++) {
911 if (stricmp ((CHAR8
*)SectionHeader
->Name
, ".text") == 0) {
912 TextVirtualAddress
= SectionHeader
->VirtualAddress
;
913 } else if (stricmp ((CHAR8
*)SectionHeader
->Name
, ".data") == 0) {
914 DataVirtualAddress
= SectionHeader
->VirtualAddress
;
915 } else if (stricmp ((CHAR8
*)SectionHeader
->Name
, ".sdata") == 0) {
916 DataVirtualAddress
= SectionHeader
->VirtualAddress
;
919 fprintf (FvMapFile
, " .textbaseaddress=0x%010llx", (unsigned long long) (ImageBaseAddress
+ TextVirtualAddress
));
920 fprintf (FvMapFile
, " .databaseaddress=0x%010llx", (unsigned long long) (ImageBaseAddress
+ DataVirtualAddress
));
921 fprintf (FvMapFile
, ")\n\n");
926 PeMapFile
= fopen (LongFilePath (PeMapFileName
), "r");
927 if (PeMapFile
== NULL
) {
928 // fprintf (stdout, "can't open %s file to reading\n", PeMapFileName);
931 VerboseMsg ("The map file is %s", PeMapFileName
);
934 // Output Functions information into Fv Map file
936 LinkTimeBaseAddress
= 0;
938 while (fgets (Line
, MAX_LINE_LEN
, PeMapFile
) != NULL
) {
942 if (Line
[0] == 0x0a) {
947 // By Address and Static keyword
949 if (FunctionType
== 0) {
950 sscanf (Line
, "%s", KeyWord
);
951 if (stricmp (KeyWord
, "Address") == 0) {
952 sscanf (Line
, "%s %s", KeyWord
, KeyWord2
);
953 if (stricmp (KeyWord2
, "Size") == 0) {
962 fgets (Line
, MAX_LINE_LEN
, PeMapFile
);
963 } else if (stricmp (KeyWord
, "Static") == 0) {
965 // static function list
968 fgets (Line
, MAX_LINE_LEN
, PeMapFile
);
969 } else if (stricmp (KeyWord
, "Preferred") ==0) {
970 sscanf (Line
+ strlen (" Preferred load address is"), "%llx", &TempLongAddress
);
971 LinkTimeBaseAddress
= (UINT64
) TempLongAddress
;
976 // Printf Function Information
978 if (FunctionType
== 1) {
980 sscanf (Line
, "%llx %s %s %s", &TempLongAddress
, KeyWord
, KeyWord2
, FunctionTypeName
);
981 FunctionAddress
= (UINT64
) TempLongAddress
;
982 if (FunctionTypeName
[0] == '_' ) {
983 fprintf (FvMapFile
, " 0x%010llx ", (unsigned long long) (ImageBaseAddress
+ FunctionAddress
- LinkTimeBaseAddress
));
984 fprintf (FvMapFile
, "%s\n", FunctionTypeName
);
987 sscanf (Line
, "%s %s %llx %s", KeyWord
, FunctionName
, &TempLongAddress
, FunctionTypeName
);
988 FunctionAddress
= (UINT64
) TempLongAddress
;
989 if (FunctionTypeName
[1] == '\0' && (FunctionTypeName
[0] == 'f' || FunctionTypeName
[0] == 'F')) {
990 fprintf (FvMapFile
, " 0x%010llx ", (unsigned long long) (ImageBaseAddress
+ FunctionAddress
- LinkTimeBaseAddress
));
991 fprintf (FvMapFile
, "%s\n", FunctionName
);
994 } else if (FunctionType
== 2) {
995 sscanf (Line
, "%s %s %llx %s", KeyWord
, FunctionName
, &TempLongAddress
, FunctionTypeName
);
996 FunctionAddress
= (UINT64
) TempLongAddress
;
997 if (FunctionTypeName
[1] == '\0' && (FunctionTypeName
[0] == 'f' || FunctionTypeName
[0] == 'F')) {
998 fprintf (FvMapFile
, " 0x%010llx ", (unsigned long long) (ImageBaseAddress
+ FunctionAddress
- LinkTimeBaseAddress
));
999 fprintf (FvMapFile
, "%s\n", FunctionName
);
1006 fprintf (FvMapFile
, "\n\n");
1014 AdjustInternalFfsPadding (
1015 IN OUT EFI_FFS_FILE_HEADER
*FfsFile
,
1016 IN OUT MEMORY_FILE
*FvImage
,
1018 IN OUT UINTN
*FileSize
1022 Routine Description:
1024 This function looks for a dedicated alignment padding section in the FFS, and
1025 shrinks it to the size required to line up subsequent sections correctly.
1029 FfsFile A pointer to Ffs file image.
1030 FvImage The memory image of the FV to adjust it to.
1031 Alignment Current file alignment
1032 FileSize Reference to a variable holding the size of the FFS file
1036 TRUE Padding section was found and updated successfully
1041 EFI_FILE_SECTION_POINTER PadSection
;
1044 UINT32 FfsHeaderLength
;
1045 UINT32 FfsFileLength
;
1048 EFI_FFS_INTEGRITY_CHECK
*IntegrityCheck
;
1051 // Figure out the misalignment: all FFS sections are aligned relative to the
1052 // start of the FFS payload, so use that as the base of the misalignment
1055 FfsHeaderLength
= GetFfsHeaderLength(FfsFile
);
1056 Misalignment
= (UINTN
) FvImage
->CurrentFilePointer
-
1057 (UINTN
) FvImage
->FileImage
+ FfsHeaderLength
;
1058 Misalignment
&= Alignment
- 1;
1059 if (Misalignment
== 0) {
1060 // Nothing to do, return success
1065 // We only apply this optimization to FFS files with the FIXED attribute set,
1066 // since the FFS will not be loadable at arbitrary offsets anymore after
1067 // we adjust the size of the padding section.
1069 if ((FfsFile
->Attributes
& FFS_ATTRIB_FIXED
) == 0) {
1074 // Look for a dedicated padding section that we can adjust to compensate
1075 // for the misalignment. If such a padding section exists, it precedes all
1076 // sections with alignment requirements, and so the adjustment will correct
1079 Status
= GetSectionByType (FfsFile
, EFI_SECTION_FREEFORM_SUBTYPE_GUID
, 1,
1081 if (EFI_ERROR (Status
) ||
1082 CompareGuid (&PadSection
.FreeformSubtypeSection
->SubTypeGuid
,
1083 &mEfiFfsSectionAlignmentPaddingGuid
) != 0) {
1088 // Find out if the size of the padding section is sufficient to compensate
1089 // for the misalignment.
1091 PadSize
= GetSectionFileLength (PadSection
.CommonHeader
);
1092 if (Misalignment
> PadSize
- sizeof (EFI_FREEFORM_SUBTYPE_GUID_SECTION
)) {
1097 // Move the remainder of the FFS file towards the front, and adjust the
1098 // file size output parameter.
1100 Remainder
= (UINT8
*) PadSection
.CommonHeader
+ PadSize
;
1101 memmove (Remainder
- Misalignment
, Remainder
,
1102 *FileSize
- (UINTN
) (Remainder
- (UINTN
) FfsFile
));
1103 *FileSize
-= Misalignment
;
1106 // Update the padding section's length with the new values. Note that the
1107 // padding is always < 64 KB, so we can ignore EFI_COMMON_SECTION_HEADER2
1110 PadSize
-= Misalignment
;
1111 PadSection
.CommonHeader
->Size
[0] = (UINT8
) (PadSize
& 0xff);
1112 PadSection
.CommonHeader
->Size
[1] = (UINT8
) ((PadSize
& 0xff00) >> 8);
1113 PadSection
.CommonHeader
->Size
[2] = (UINT8
) ((PadSize
& 0xff0000) >> 16);
1116 // Update the FFS header with the new overall length
1118 FfsFileLength
= GetFfsFileLength (FfsFile
) - Misalignment
;
1119 if (FfsHeaderLength
> sizeof(EFI_FFS_FILE_HEADER
)) {
1120 ((EFI_FFS_FILE_HEADER2
*)FfsFile
)->ExtendedSize
= FfsFileLength
;
1122 FfsFile
->Size
[0] = (UINT8
) (FfsFileLength
& 0x000000FF);
1123 FfsFile
->Size
[1] = (UINT8
) ((FfsFileLength
& 0x0000FF00) >> 8);
1124 FfsFile
->Size
[2] = (UINT8
) ((FfsFileLength
& 0x00FF0000) >> 16);
1128 // Clear the alignment bits: these have become meaningless now that we have
1129 // adjusted the padding section.
1131 FfsFile
->Attributes
&= ~(FFS_ATTRIB_DATA_ALIGNMENT
| FFS_ATTRIB_DATA_ALIGNMENT2
);
1134 // Recalculate the FFS header checksum. Instead of setting Header and State
1135 // both to zero, set Header to (UINT8)(-State) so State preserves its original
1138 IntegrityCheck
= &FfsFile
->IntegrityCheck
;
1139 IntegrityCheck
->Checksum
.Header
= (UINT8
) (0x100 - FfsFile
->State
);
1140 IntegrityCheck
->Checksum
.File
= 0;
1142 IntegrityCheck
->Checksum
.Header
= CalculateChecksum8 (
1143 (UINT8
*) FfsFile
, FfsHeaderLength
);
1145 if (FfsFile
->Attributes
& FFS_ATTRIB_CHECKSUM
) {
1147 // Ffs header checksum = zero, so only need to calculate ffs body.
1149 IntegrityCheck
->Checksum
.File
= CalculateChecksum8 (
1150 (UINT8
*) FfsFile
+ FfsHeaderLength
,
1151 FfsFileLength
- FfsHeaderLength
);
1153 IntegrityCheck
->Checksum
.File
= FFS_FIXED_CHECKSUM
;
1161 IN OUT MEMORY_FILE
*FvImage
,
1164 IN OUT EFI_FFS_FILE_HEADER
**VtfFileImage
,
1166 IN
FILE *FvReportFile
1170 Routine Description:
1172 This function adds a file to the FV image. The file will pad to the
1173 appropriate alignment if required.
1177 FvImage The memory image of the FV to add it to. The current offset
1179 FvInfo Pointer to information about the FV.
1180 Index The file in the FvInfo file list to add.
1181 VtfFileImage A pointer to the VTF file within the FvImage. If this is equal
1182 to the end of the FvImage then no VTF previously found.
1183 FvMapFile Pointer to FvMap File
1184 FvReportFile Pointer to FvReport File
1188 EFI_SUCCESS The function completed successfully.
1189 EFI_INVALID_PARAMETER One of the input parameters was invalid.
1190 EFI_ABORTED An error occurred.
1191 EFI_OUT_OF_RESOURCES Insufficient resources exist to complete the add.
1199 UINT32 CurrentFileAlignment
;
1202 UINT8 FileGuidString
[PRINTED_GUID_BUFFER_SIZE
];
1206 // Verify input parameters.
1208 if (FvImage
== NULL
|| FvInfo
== NULL
|| FvInfo
->FvFiles
[Index
][0] == 0 || VtfFileImage
== NULL
) {
1209 return EFI_INVALID_PARAMETER
;
1213 // Read the file to add
1215 NewFile
= fopen (LongFilePath (FvInfo
->FvFiles
[Index
]), "rb");
1217 if (NewFile
== NULL
) {
1218 Error (NULL
, 0, 0001, "Error opening file", FvInfo
->FvFiles
[Index
]);
1223 // Get the file size
1225 FileSize
= _filelength (fileno (NewFile
));
1228 // Read the file into a buffer
1230 FileBuffer
= malloc (FileSize
);
1231 if (FileBuffer
== NULL
) {
1233 Error (NULL
, 0, 4001, "Resource", "memory cannot be allocated!");
1234 return EFI_OUT_OF_RESOURCES
;
1237 NumBytesRead
= fread (FileBuffer
, sizeof (UINT8
), FileSize
, NewFile
);
1240 // Done with the file, from this point on we will just use the buffer read.
1245 // Verify read successful
1247 if (NumBytesRead
!= sizeof (UINT8
) * FileSize
) {
1249 Error (NULL
, 0, 0004, "Error reading file", FvInfo
->FvFiles
[Index
]);
1254 // For None PI Ffs file, directly add them into FvImage.
1256 if (!FvInfo
->IsPiFvImage
) {
1257 memcpy (FvImage
->CurrentFilePointer
, FileBuffer
, FileSize
);
1258 if (FvInfo
->SizeofFvFiles
[Index
] > FileSize
) {
1259 FvImage
->CurrentFilePointer
+= FvInfo
->SizeofFvFiles
[Index
];
1261 FvImage
->CurrentFilePointer
+= FileSize
;
1269 Status
= VerifyFfsFile ((EFI_FFS_FILE_HEADER
*)FileBuffer
);
1270 if (EFI_ERROR (Status
)) {
1272 Error (NULL
, 0, 3000, "Invalid", "%s is not a valid FFS file.", FvInfo
->FvFiles
[Index
]);
1273 return EFI_INVALID_PARAMETER
;
1277 // Verify space exists to add the file
1279 if (FileSize
> (UINTN
) ((UINTN
) *VtfFileImage
- (UINTN
) FvImage
->CurrentFilePointer
)) {
1281 Error (NULL
, 0, 4002, "Resource", "FV space is full, not enough room to add file %s.", FvInfo
->FvFiles
[Index
]);
1282 return EFI_OUT_OF_RESOURCES
;
1286 // Verify the input file is the duplicated file in this Fv image
1288 for (Index1
= 0; Index1
< Index
; Index1
++) {
1289 if (CompareGuid ((EFI_GUID
*) FileBuffer
, &mFileGuidArray
[Index1
]) == 0) {
1290 Error (NULL
, 0, 2000, "Invalid parameter", "the %dth file and %uth file have the same file GUID.", (unsigned) Index1
+ 1, (unsigned) Index
+ 1);
1291 PrintGuid ((EFI_GUID
*) FileBuffer
);
1293 return EFI_INVALID_PARAMETER
;
1296 CopyMem (&mFileGuidArray
[Index
], FileBuffer
, sizeof (EFI_GUID
));
1299 // Update the file state based on polarity of the FV.
1301 UpdateFfsFileState (
1302 (EFI_FFS_FILE_HEADER
*) FileBuffer
,
1303 (EFI_FIRMWARE_VOLUME_HEADER
*) FvImage
->FileImage
1307 // Check if alignment is required
1309 ReadFfsAlignment ((EFI_FFS_FILE_HEADER
*) FileBuffer
, &CurrentFileAlignment
);
1312 // Find the largest alignment of all the FFS files in the FV
1314 if (CurrentFileAlignment
> MaxFfsAlignment
) {
1315 MaxFfsAlignment
= CurrentFileAlignment
;
1318 // If we have a VTF file, add it at the top.
1320 if (IsVtfFile ((EFI_FFS_FILE_HEADER
*) FileBuffer
)) {
1321 if ((UINTN
) *VtfFileImage
== (UINTN
) FvImage
->Eof
) {
1323 // No previous VTF, add this one.
1325 *VtfFileImage
= (EFI_FFS_FILE_HEADER
*) (UINTN
) ((UINTN
) FvImage
->FileImage
+ FvInfo
->Size
- FileSize
);
1327 // Sanity check. The file MUST align appropriately
1329 if (((UINTN
) *VtfFileImage
+ GetFfsHeaderLength((EFI_FFS_FILE_HEADER
*)FileBuffer
) - (UINTN
) FvImage
->FileImage
) % (1 << CurrentFileAlignment
)) {
1330 Error (NULL
, 0, 3000, "Invalid", "VTF file cannot be aligned on a %u-byte boundary.", (unsigned) (1 << CurrentFileAlignment
));
1335 // Rebase the PE or TE image in FileBuffer of FFS file for XIP
1336 // Rebase for the debug genfvmap tool
1338 Status
= FfsRebase (FvInfo
, FvInfo
->FvFiles
[Index
], (EFI_FFS_FILE_HEADER
*) FileBuffer
, (UINTN
) *VtfFileImage
- (UINTN
) FvImage
->FileImage
, FvMapFile
);
1339 if (EFI_ERROR (Status
)) {
1340 Error (NULL
, 0, 3000, "Invalid", "Could not rebase %s.", FvInfo
->FvFiles
[Index
]);
1346 memcpy (*VtfFileImage
, FileBuffer
, FileSize
);
1348 PrintGuidToBuffer ((EFI_GUID
*) FileBuffer
, FileGuidString
, sizeof (FileGuidString
), TRUE
);
1349 fprintf (FvReportFile
, "0x%08X %s\n", (unsigned)(UINTN
) (((UINT8
*)*VtfFileImage
) - (UINTN
)FvImage
->FileImage
), FileGuidString
);
1352 DebugMsg (NULL
, 0, 9, "Add VTF FFS file in FV image", NULL
);
1356 // Already found a VTF file.
1358 Error (NULL
, 0, 3000, "Invalid", "multiple VTF files are not permitted within a single FV.");
1365 // Add pad file if necessary
1367 if (!AdjustInternalFfsPadding ((EFI_FFS_FILE_HEADER
*) FileBuffer
, FvImage
,
1368 1 << CurrentFileAlignment
, &FileSize
)) {
1369 Status
= AddPadFile (FvImage
, 1 << CurrentFileAlignment
, *VtfFileImage
, NULL
, FileSize
);
1370 if (EFI_ERROR (Status
)) {
1371 Error (NULL
, 0, 4002, "Resource", "FV space is full, could not add pad file for data alignment property.");
1379 if ((UINTN
) (FvImage
->CurrentFilePointer
+ FileSize
) <= (UINTN
) (*VtfFileImage
)) {
1381 // Rebase the PE or TE image in FileBuffer of FFS file for XIP.
1382 // Rebase Bs and Rt drivers for the debug genfvmap tool.
1384 Status
= FfsRebase (FvInfo
, FvInfo
->FvFiles
[Index
], (EFI_FFS_FILE_HEADER
*) FileBuffer
, (UINTN
) FvImage
->CurrentFilePointer
- (UINTN
) FvImage
->FileImage
, FvMapFile
);
1385 if (EFI_ERROR (Status
)) {
1386 Error (NULL
, 0, 3000, "Invalid", "Could not rebase %s.", FvInfo
->FvFiles
[Index
]);
1392 memcpy (FvImage
->CurrentFilePointer
, FileBuffer
, FileSize
);
1393 PrintGuidToBuffer ((EFI_GUID
*) FileBuffer
, FileGuidString
, sizeof (FileGuidString
), TRUE
);
1394 fprintf (FvReportFile
, "0x%08X %s\n", (unsigned) (FvImage
->CurrentFilePointer
- FvImage
->FileImage
), FileGuidString
);
1395 FvImage
->CurrentFilePointer
+= FileSize
;
1397 Error (NULL
, 0, 4002, "Resource", "FV space is full, cannot add file %s.", FvInfo
->FvFiles
[Index
]);
1402 // Make next file start at QWord Boundary
1404 while (((UINTN
) FvImage
->CurrentFilePointer
& (EFI_FFS_FILE_HEADER_ALIGNMENT
- 1)) != 0) {
1405 FvImage
->CurrentFilePointer
++;
1410 // Free allocated memory.
1419 IN MEMORY_FILE
*FvImage
,
1420 IN EFI_FFS_FILE_HEADER
*VtfFileImage
1424 Routine Description:
1426 This function places a pad file between the last file in the FV and the VTF
1427 file if the VTF file exists.
1431 FvImage Memory file for the FV memory image
1432 VtfFileImage The address of the VTF file. If this is the end of the FV
1433 image, no VTF exists and no pad file is needed.
1437 EFI_SUCCESS Completed successfully.
1438 EFI_INVALID_PARAMETER One of the input parameters was NULL.
1442 EFI_FFS_FILE_HEADER
*PadFile
;
1444 UINT32 FfsHeaderSize
;
1447 // If there is no VTF or the VTF naturally follows the previous file without a
1448 // pad file, then there's nothing to do
1450 if ((UINTN
) VtfFileImage
== (UINTN
) FvImage
->Eof
|| \
1451 ((UINTN
) VtfFileImage
== (UINTN
) FvImage
->CurrentFilePointer
)) {
1455 if ((UINTN
) VtfFileImage
< (UINTN
) FvImage
->CurrentFilePointer
) {
1456 return EFI_INVALID_PARAMETER
;
1460 // Pad file starts at beginning of free space
1462 PadFile
= (EFI_FFS_FILE_HEADER
*) FvImage
->CurrentFilePointer
;
1465 // write PadFile FFS header with PadType, don't need to set PAD file guid in its header.
1467 PadFile
->Type
= EFI_FV_FILETYPE_FFS_PAD
;
1468 PadFile
->Attributes
= 0;
1471 // FileSize includes the EFI_FFS_FILE_HEADER
1473 FileSize
= (UINTN
) VtfFileImage
- (UINTN
) FvImage
->CurrentFilePointer
;
1474 if (FileSize
>= MAX_FFS_SIZE
) {
1475 PadFile
->Attributes
|= FFS_ATTRIB_LARGE_FILE
;
1476 memset(PadFile
->Size
, 0, sizeof(UINT8
) * 3);
1477 ((EFI_FFS_FILE_HEADER2
*)PadFile
)->ExtendedSize
= FileSize
;
1478 FfsHeaderSize
= sizeof(EFI_FFS_FILE_HEADER2
);
1481 PadFile
->Size
[0] = (UINT8
) (FileSize
& 0x000000FF);
1482 PadFile
->Size
[1] = (UINT8
) ((FileSize
& 0x0000FF00) >> 8);
1483 PadFile
->Size
[2] = (UINT8
) ((FileSize
& 0x00FF0000) >> 16);
1484 FfsHeaderSize
= sizeof(EFI_FFS_FILE_HEADER
);
1488 // Fill in checksums and state, must be zero during checksum calculation.
1490 PadFile
->IntegrityCheck
.Checksum
.Header
= 0;
1491 PadFile
->IntegrityCheck
.Checksum
.File
= 0;
1493 PadFile
->IntegrityCheck
.Checksum
.Header
= CalculateChecksum8 ((UINT8
*) PadFile
, FfsHeaderSize
);
1494 PadFile
->IntegrityCheck
.Checksum
.File
= FFS_FIXED_CHECKSUM
;
1496 PadFile
->State
= EFI_FILE_HEADER_CONSTRUCTION
| EFI_FILE_HEADER_VALID
| EFI_FILE_DATA_VALID
;
1498 UpdateFfsFileState (
1499 (EFI_FFS_FILE_HEADER
*) PadFile
,
1500 (EFI_FIRMWARE_VOLUME_HEADER
*) FvImage
->FileImage
1503 // Update the current FV pointer
1505 FvImage
->CurrentFilePointer
= FvImage
->Eof
;
1512 IN MEMORY_FILE
*FvImage
,
1514 IN EFI_FFS_FILE_HEADER
*VtfFile
1518 Routine Description:
1520 This parses the FV looking for the PEI core and then plugs the address into
1521 the SALE_ENTRY point of the BSF/VTF for IPF and does BUGBUG TBD action to
1522 complete an IA32 Bootstrap FV.
1526 FvImage Memory file for the FV memory image
1527 FvInfo Information read from INF file.
1528 VtfFile Pointer to the VTF file in the FV image.
1532 EFI_SUCCESS Function Completed successfully.
1533 EFI_ABORTED Error encountered.
1534 EFI_INVALID_PARAMETER A required parameter was NULL.
1535 EFI_NOT_FOUND PEI Core file not found.
1539 EFI_FFS_FILE_HEADER
*PeiCoreFile
;
1540 EFI_FFS_FILE_HEADER
*SecCoreFile
;
1542 EFI_FILE_SECTION_POINTER Pe32Section
;
1546 EFI_PHYSICAL_ADDRESS PeiCorePhysicalAddress
;
1547 EFI_PHYSICAL_ADDRESS SecCorePhysicalAddress
;
1548 INT32 Ia32SecEntryOffset
;
1549 UINT32
*Ia32ResetAddressPtr
;
1551 UINT8
*BytePointer2
;
1552 UINT16
*WordPointer
;
1556 EFI_FFS_FILE_STATE SavedState
;
1557 BOOLEAN Vtf0Detected
;
1558 UINT32 FfsHeaderSize
;
1559 UINT32 SecHeaderSize
;
1562 // Verify input parameters
1564 if (FvImage
== NULL
|| FvInfo
== NULL
|| VtfFile
== NULL
) {
1565 return EFI_INVALID_PARAMETER
;
1568 // Initialize FV library
1570 InitializeFvLib (FvImage
->FileImage
, FvInfo
->Size
);
1575 Status
= VerifyFfsFile (VtfFile
);
1576 if (EFI_ERROR (Status
)) {
1577 return EFI_INVALID_PARAMETER
;
1581 (((UINTN
)FvImage
->Eof
- (UINTN
)FvImage
->FileImage
) >=
1582 IA32_X64_VTF_SIGNATURE_OFFSET
) &&
1583 (*(UINT32
*)(VOID
*)((UINTN
) FvImage
->Eof
-
1584 IA32_X64_VTF_SIGNATURE_OFFSET
) ==
1585 IA32_X64_VTF0_SIGNATURE
)
1587 Vtf0Detected
= TRUE
;
1589 Vtf0Detected
= FALSE
;
1593 // Find the Sec Core
1595 Status
= GetFileByType (EFI_FV_FILETYPE_SECURITY_CORE
, 1, &SecCoreFile
);
1596 if (EFI_ERROR (Status
) || SecCoreFile
== NULL
) {
1599 // If the SEC core file is not found, but the VTF-0 signature
1600 // is found, we'll treat it as a VTF-0 'Volume Top File'.
1601 // This means no modifications are required to the VTF.
1606 Error (NULL
, 0, 3000, "Invalid", "could not find the SEC core file in the FV.");
1610 // Sec Core found, now find PE32 section
1612 Status
= GetSectionByType (SecCoreFile
, EFI_SECTION_PE32
, 1, &Pe32Section
);
1613 if (Status
== EFI_NOT_FOUND
) {
1614 Status
= GetSectionByType (SecCoreFile
, EFI_SECTION_TE
, 1, &Pe32Section
);
1617 if (EFI_ERROR (Status
)) {
1618 Error (NULL
, 0, 3000, "Invalid", "could not find a PE32 section in the SEC core file.");
1622 SecHeaderSize
= GetSectionHeaderLength(Pe32Section
.CommonHeader
);
1623 Status
= GetPe32Info (
1624 (VOID
*) ((UINTN
) Pe32Section
.Pe32Section
+ SecHeaderSize
),
1630 if (EFI_ERROR (Status
)) {
1631 Error (NULL
, 0, 3000, "Invalid", "could not get the PE32 entry point for the SEC core.");
1637 (MachineType
== EFI_IMAGE_MACHINE_IA32
||
1638 MachineType
== EFI_IMAGE_MACHINE_X64
)
1641 // If the SEC core code is IA32 or X64 and the VTF-0 signature
1642 // is found, we'll treat it as a VTF-0 'Volume Top File'.
1643 // This means no modifications are required to the VTF.
1649 // Physical address is FV base + offset of PE32 + offset of the entry point
1651 SecCorePhysicalAddress
= FvInfo
->BaseAddress
;
1652 SecCorePhysicalAddress
+= (UINTN
) Pe32Section
.Pe32Section
+ SecHeaderSize
- (UINTN
) FvImage
->FileImage
;
1653 SecCorePhysicalAddress
+= EntryPoint
;
1654 DebugMsg (NULL
, 0, 9, "SecCore physical entry point address", "Address = 0x%llX", (unsigned long long) SecCorePhysicalAddress
);
1657 // Find the PEI Core
1659 PeiCorePhysicalAddress
= 0;
1660 Status
= GetFileByType (EFI_FV_FILETYPE_PEI_CORE
, 1, &PeiCoreFile
);
1661 if (!EFI_ERROR (Status
) && (PeiCoreFile
!= NULL
)) {
1663 // PEI Core found, now find PE32 or TE section
1665 Status
= GetSectionByType (PeiCoreFile
, EFI_SECTION_PE32
, 1, &Pe32Section
);
1666 if (Status
== EFI_NOT_FOUND
) {
1667 Status
= GetSectionByType (PeiCoreFile
, EFI_SECTION_TE
, 1, &Pe32Section
);
1670 if (EFI_ERROR (Status
)) {
1671 Error (NULL
, 0, 3000, "Invalid", "could not find either a PE32 or a TE section in PEI core file.");
1675 SecHeaderSize
= GetSectionHeaderLength(Pe32Section
.CommonHeader
);
1676 Status
= GetPe32Info (
1677 (VOID
*) ((UINTN
) Pe32Section
.Pe32Section
+ SecHeaderSize
),
1683 if (EFI_ERROR (Status
)) {
1684 Error (NULL
, 0, 3000, "Invalid", "could not get the PE32 entry point for the PEI core.");
1688 // Physical address is FV base + offset of PE32 + offset of the entry point
1690 PeiCorePhysicalAddress
= FvInfo
->BaseAddress
;
1691 PeiCorePhysicalAddress
+= (UINTN
) Pe32Section
.Pe32Section
+ SecHeaderSize
- (UINTN
) FvImage
->FileImage
;
1692 PeiCorePhysicalAddress
+= EntryPoint
;
1693 DebugMsg (NULL
, 0, 9, "PeiCore physical entry point address", "Address = 0x%llX", (unsigned long long) PeiCorePhysicalAddress
);
1696 if (MachineType
== EFI_IMAGE_MACHINE_IA32
|| MachineType
== EFI_IMAGE_MACHINE_X64
) {
1697 if (PeiCorePhysicalAddress
!= 0) {
1699 // Get the location to update
1701 Ia32ResetAddressPtr
= (UINT32
*) ((UINTN
) FvImage
->Eof
- IA32_PEI_CORE_ENTRY_OFFSET
);
1704 // Write lower 32 bits of physical address for Pei Core entry
1706 *Ia32ResetAddressPtr
= (UINT32
) PeiCorePhysicalAddress
;
1709 // Write SecCore Entry point relative address into the jmp instruction in reset vector.
1711 Ia32ResetAddressPtr
= (UINT32
*) ((UINTN
) FvImage
->Eof
- IA32_SEC_CORE_ENTRY_OFFSET
);
1713 Ia32SecEntryOffset
= (INT32
) (SecCorePhysicalAddress
- (FV_IMAGES_TOP_ADDRESS
- IA32_SEC_CORE_ENTRY_OFFSET
+ 2));
1714 if (Ia32SecEntryOffset
<= -65536) {
1715 Error (NULL
, 0, 3000, "Invalid", "The SEC EXE file size is too large, it must be less than 64K.");
1716 return STATUS_ERROR
;
1719 *(UINT16
*) Ia32ResetAddressPtr
= (UINT16
) Ia32SecEntryOffset
;
1722 // Update the BFV base address
1724 Ia32ResetAddressPtr
= (UINT32
*) ((UINTN
) FvImage
->Eof
- 4);
1725 *Ia32ResetAddressPtr
= (UINT32
) (FvInfo
->BaseAddress
);
1726 DebugMsg (NULL
, 0, 9, "update BFV base address in the top FV image", "BFV base address = 0x%llX.", (unsigned long long) FvInfo
->BaseAddress
);
1729 // Update the Startup AP in the FVH header block ZeroVector region.
1731 BytePointer
= (UINT8
*) ((UINTN
) FvImage
->FileImage
);
1732 if (FvInfo
->Size
<= 0x10000) {
1733 BytePointer2
= m64kRecoveryStartupApDataArray
;
1734 } else if (FvInfo
->Size
<= 0x20000) {
1735 BytePointer2
= m128kRecoveryStartupApDataArray
;
1737 BytePointer2
= m128kRecoveryStartupApDataArray
;
1739 // Find the position to place Ap reset vector, the offset
1740 // between the position and the end of Fvrecovery.fv file
1741 // should not exceed 128kB to prevent Ap reset vector from
1742 // outside legacy E and F segment
1744 Status
= FindApResetVectorPosition (FvImage
, &BytePointer
);
1745 if (EFI_ERROR (Status
)) {
1746 Error (NULL
, 0, 3000, "Invalid", "FV image does not have enough space to place AP reset vector. The FV image needs to reserve at least 4KB of unused space.");
1751 for (Index
= 0; Index
< SIZEOF_STARTUP_DATA_ARRAY
; Index
++) {
1752 BytePointer
[Index
] = BytePointer2
[Index
];
1755 // Calculate the checksum
1758 WordPointer
= (UINT16
*) (BytePointer
);
1759 for (Index
= 0; Index
< SIZEOF_STARTUP_DATA_ARRAY
/ 2; Index
++) {
1760 CheckSum
= (UINT16
) (CheckSum
+ ((UINT16
) *WordPointer
));
1764 // Update the checksum field
1766 WordPointer
= (UINT16
*) (BytePointer
+ SIZEOF_STARTUP_DATA_ARRAY
- 2);
1767 *WordPointer
= (UINT16
) (0x10000 - (UINT32
) CheckSum
);
1770 // IpiVector at the 4k aligned address in the top 2 blocks in the PEI FV.
1772 IpiVector
= (UINT32
) (FV_IMAGES_TOP_ADDRESS
- ((UINTN
) FvImage
->Eof
- (UINTN
) BytePointer
));
1773 DebugMsg (NULL
, 0, 9, "Startup AP Vector address", "IpiVector at 0x%X", (unsigned) IpiVector
);
1774 if ((IpiVector
& 0xFFF) != 0) {
1775 Error (NULL
, 0, 3000, "Invalid", "Startup AP Vector address are not 4K aligned, because the FV size is not 4K aligned");
1778 IpiVector
= IpiVector
>> 12;
1779 IpiVector
= IpiVector
& 0xFF;
1782 // Write IPI Vector at Offset FvrecoveryFileSize - 8
1784 Ia32ResetAddressPtr
= (UINT32
*) ((UINTN
) FvImage
->Eof
- 8);
1785 *Ia32ResetAddressPtr
= IpiVector
;
1786 } else if (MachineType
== EFI_IMAGE_MACHINE_ARMT
) {
1788 // Since the ARM reset vector is in the FV Header you really don't need a
1789 // Volume Top File, but if you have one for some reason don't crash...
1791 } else if (MachineType
== EFI_IMAGE_MACHINE_AARCH64
) {
1793 // Since the AArch64 reset vector is in the FV Header you really don't need a
1794 // Volume Top File, but if you have one for some reason don't crash...
1797 Error (NULL
, 0, 3000, "Invalid", "machine type=0x%X in PEI core.", MachineType
);
1802 // Now update file checksum
1804 SavedState
= VtfFile
->State
;
1805 VtfFile
->IntegrityCheck
.Checksum
.File
= 0;
1807 if (VtfFile
->Attributes
& FFS_ATTRIB_CHECKSUM
) {
1808 FfsHeaderSize
= GetFfsHeaderLength(VtfFile
);
1809 VtfFile
->IntegrityCheck
.Checksum
.File
= CalculateChecksum8 (
1810 (UINT8
*) ((UINT8
*)VtfFile
+ FfsHeaderSize
),
1811 GetFfsFileLength (VtfFile
) - FfsHeaderSize
1814 VtfFile
->IntegrityCheck
.Checksum
.File
= FFS_FIXED_CHECKSUM
;
1817 VtfFile
->State
= SavedState
;
1824 IN VOID
*FvImageBuffer
,
1826 IN EFI_FV_FILETYPE FileType
,
1827 OUT EFI_FILE_SECTION_POINTER
*Pe32Section
1831 Routine Description:
1833 Recursively searches the FV for the FFS file of specified type (typically
1834 SEC or PEI core) and extracts the PE32 section for further processing.
1838 FvImageBuffer Buffer containing FV data
1839 FvSize Size of the FV
1840 FileType Type of FFS file to search for
1841 Pe32Section PE32 section pointer when FFS file is found.
1845 EFI_SUCCESS Function Completed successfully.
1846 EFI_ABORTED Error encountered.
1847 EFI_INVALID_PARAMETER A required parameter was NULL.
1848 EFI_NOT_FOUND Core file not found.
1853 EFI_FIRMWARE_VOLUME_HEADER
*OrigFvHeader
;
1854 UINT32 OrigFvLength
;
1855 EFI_FFS_FILE_HEADER
*CoreFfsFile
;
1856 UINTN FvImageFileCount
;
1857 EFI_FFS_FILE_HEADER
*FvImageFile
;
1858 UINTN EncapFvSectionCount
;
1859 EFI_FILE_SECTION_POINTER EncapFvSection
;
1860 EFI_FIRMWARE_VOLUME_HEADER
*EncapsulatedFvHeader
;
1862 if (Pe32Section
== NULL
) {
1863 return EFI_INVALID_PARAMETER
;
1867 // Initialize FV library, saving previous values
1869 OrigFvHeader
= (EFI_FIRMWARE_VOLUME_HEADER
*)NULL
;
1870 GetFvHeader (&OrigFvHeader
, &OrigFvLength
);
1871 InitializeFvLib(FvImageBuffer
, (UINT32
)FvSize
);
1874 // First see if we can obtain the file directly in outer FV
1876 Status
= GetFileByType(FileType
, 1, &CoreFfsFile
);
1877 if (!EFI_ERROR(Status
) && (CoreFfsFile
!= NULL
) ) {
1880 // Core found, now find PE32 or TE section
1882 Status
= GetSectionByType(CoreFfsFile
, EFI_SECTION_PE32
, 1, Pe32Section
);
1883 if (EFI_ERROR(Status
)) {
1884 Status
= GetSectionByType(CoreFfsFile
, EFI_SECTION_TE
, 1, Pe32Section
);
1887 if (EFI_ERROR(Status
)) {
1888 Error(NULL
, 0, 3000, "Invalid", "could not find a PE32 section in the core file.");
1893 // Core PE/TE section, found, return
1895 Status
= EFI_SUCCESS
;
1900 // File was not found, look for FV Image file
1903 // iterate through all FV image files in outer FV
1904 for (FvImageFileCount
= 1;; FvImageFileCount
++) {
1906 Status
= GetFileByType(EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE
, FvImageFileCount
, &FvImageFile
);
1908 if (EFI_ERROR(Status
) || (FvImageFile
== NULL
) ) {
1909 // exit FV image file loop, no more found
1913 // Found an fv image file, look for an FV image section. The PI spec does not
1914 // preclude multiple FV image sections so we loop accordingly.
1915 for (EncapFvSectionCount
= 1;; EncapFvSectionCount
++) {
1917 // Look for the next FV image section. The section search code will
1918 // iterate into encapsulation sections. For example, it will iterate
1919 // into an EFI_SECTION_GUID_DEFINED encapsulation section to find the
1920 // EFI_SECTION_FIRMWARE_VOLUME_IMAGE sections contained therein.
1921 Status
= GetSectionByType(FvImageFile
, EFI_SECTION_FIRMWARE_VOLUME_IMAGE
, EncapFvSectionCount
, &EncapFvSection
);
1923 if (EFI_ERROR(Status
)) {
1924 // exit section inner loop, no more found
1928 EncapsulatedFvHeader
= (EFI_FIRMWARE_VOLUME_HEADER
*)((UINT8
*)EncapFvSection
.FVImageSection
+ GetSectionHeaderLength(EncapFvSection
.FVImageSection
));
1930 // recurse to search the encapsulated FV for this core file type
1931 Status
= FindCorePeSection(EncapsulatedFvHeader
, EncapsulatedFvHeader
->FvLength
, FileType
, Pe32Section
);
1933 if (!EFI_ERROR(Status
)) {
1934 // we found the core in the capsulated image, success
1938 } // end encapsulated fv image section loop
1939 } // end fv image file loop
1941 // core was not found
1942 Status
= EFI_NOT_FOUND
;
1946 // restore FV lib values
1947 if(OrigFvHeader
!= NULL
) {
1948 InitializeFvLib(OrigFvHeader
, OrigFvLength
);
1956 IN EFI_FILE_SECTION_POINTER Pe32Section
,
1957 OUT UINT16
*CoreMachineType
1961 Routine Description:
1963 Returns the machine type of a P32 image, typically SEC or PEI core.
1967 Pe32Section PE32 section data
1968 CoreMachineType The extracted machine type
1972 EFI_SUCCESS Function Completed successfully.
1973 EFI_ABORTED Error encountered.
1974 EFI_INVALID_PARAMETER A required parameter was NULL.
1982 if (CoreMachineType
== NULL
) {
1983 return EFI_INVALID_PARAMETER
;
1986 Status
= GetPe32Info(
1987 (VOID
*)((UINTN
)Pe32Section
.Pe32Section
+ GetSectionHeaderLength(Pe32Section
.CommonHeader
)),
1992 if (EFI_ERROR(Status
)) {
1993 Error(NULL
, 0, 3000, "Invalid", "could not get the PE32 machine type for the core.");
2001 GetCoreEntryPointAddress(
2002 IN VOID
*FvImageBuffer
,
2004 IN EFI_FILE_SECTION_POINTER Pe32Section
,
2005 OUT EFI_PHYSICAL_ADDRESS
*CoreEntryAddress
2009 Routine Description:
2011 Returns the physical address of the core (SEC or PEI) entry point.
2015 FvImageBuffer Pointer to buffer containing FV data
2016 FvInfo Info for the parent FV
2017 Pe32Section PE32 section data
2018 CoreEntryAddress The extracted core entry physical address
2022 EFI_SUCCESS Function Completed successfully.
2023 EFI_ABORTED Error encountered.
2024 EFI_INVALID_PARAMETER A required parameter was NULL.
2032 EFI_PHYSICAL_ADDRESS EntryPhysicalAddress
;
2034 if (CoreEntryAddress
== NULL
) {
2035 return EFI_INVALID_PARAMETER
;
2038 Status
= GetPe32Info(
2039 (VOID
*)((UINTN
)Pe32Section
.Pe32Section
+ GetSectionHeaderLength(Pe32Section
.CommonHeader
)),
2044 if (EFI_ERROR(Status
)) {
2045 Error(NULL
, 0, 3000, "Invalid", "could not get the PE32 entry point for the core.");
2050 // Physical address is FV base + offset of PE32 + offset of the entry point
2052 EntryPhysicalAddress
= FvInfo
->BaseAddress
;
2053 EntryPhysicalAddress
+= (UINTN
)Pe32Section
.Pe32Section
+ GetSectionHeaderLength(Pe32Section
.CommonHeader
) - (UINTN
)FvImageBuffer
;
2054 EntryPhysicalAddress
+= EntryPoint
;
2056 *CoreEntryAddress
= EntryPhysicalAddress
;
2062 UpdateArmResetVectorIfNeeded (
2063 IN MEMORY_FILE
*FvImage
,
2068 Routine Description:
2069 This parses the FV looking for SEC and patches that address into the
2070 beginning of the FV header.
2072 For ARM32 the reset vector is at 0x00000000 or 0xFFFF0000.
2073 For AArch64 the reset vector is at 0x00000000.
2075 This would commonly map to the first entry in the ROM.
2085 We support two schemes on ARM.
2086 1) Beginning of the FV is the reset vector
2087 2) Reset vector is data bytes FDF file and that code branches to reset vector
2088 in the beginning of the FV (fixed size offset).
2090 Need to have the jump for the reset vector at location zero.
2091 We also need to store the address or PEI (if it exists).
2092 We stub out a return from interrupt in case the debugger
2093 is using SWI (not done for AArch64, not enough space in struct).
2094 The optional entry to the common exception handler is
2095 to support full featured exception handling from ROM and is currently
2096 not support by this tool.
2099 FvImage Memory file for the FV memory image
2100 FvInfo Information read from INF file.
2104 EFI_SUCCESS Function Completed successfully.
2105 EFI_ABORTED Error encountered.
2106 EFI_INVALID_PARAMETER A required parameter was NULL.
2107 EFI_NOT_FOUND PEI Core file not found.
2112 EFI_FILE_SECTION_POINTER SecPe32
;
2113 EFI_FILE_SECTION_POINTER PeiPe32
;
2114 BOOLEAN UpdateVectorSec
= FALSE
;
2115 BOOLEAN UpdateVectorPei
= FALSE
;
2116 UINT16 MachineType
= 0;
2117 EFI_PHYSICAL_ADDRESS SecCoreEntryAddress
= 0;
2118 UINT16 PeiMachineType
= 0;
2119 EFI_PHYSICAL_ADDRESS PeiCoreEntryAddress
= 0;
2122 // Verify input parameters
2124 if (FvImage
== NULL
|| FvInfo
== NULL
) {
2125 return EFI_INVALID_PARAMETER
;
2129 // Locate an SEC Core instance and if found extract the machine type and entry point address
2131 Status
= FindCorePeSection(FvImage
->FileImage
, FvInfo
->Size
, EFI_FV_FILETYPE_SECURITY_CORE
, &SecPe32
);
2132 if (!EFI_ERROR(Status
)) {
2134 Status
= GetCoreMachineType(SecPe32
, &MachineType
);
2135 if (EFI_ERROR(Status
)) {
2136 Error(NULL
, 0, 3000, "Invalid", "Could not get the PE32 machine type for SEC Core.");
2140 Status
= GetCoreEntryPointAddress(FvImage
->FileImage
, FvInfo
, SecPe32
, &SecCoreEntryAddress
);
2141 if (EFI_ERROR(Status
)) {
2142 Error(NULL
, 0, 3000, "Invalid", "Could not get the PE32 entry point address for SEC Core.");
2146 VerboseMsg("UpdateArmResetVectorIfNeeded found SEC core entry at 0x%llx", (unsigned long long)SecCoreEntryAddress
);
2147 UpdateVectorSec
= TRUE
;
2151 // Locate a PEI Core instance and if found extract the machine type and entry point address
2153 Status
= FindCorePeSection(FvImage
->FileImage
, FvInfo
->Size
, EFI_FV_FILETYPE_PEI_CORE
, &PeiPe32
);
2154 if (!EFI_ERROR(Status
)) {
2156 Status
= GetCoreMachineType(PeiPe32
, &PeiMachineType
);
2157 if (EFI_ERROR(Status
)) {
2158 Error(NULL
, 0, 3000, "Invalid", "Could not get the PE32 machine type for PEI Core.");
2162 Status
= GetCoreEntryPointAddress(FvImage
->FileImage
, FvInfo
, PeiPe32
, &PeiCoreEntryAddress
);
2163 if (EFI_ERROR(Status
)) {
2164 Error(NULL
, 0, 3000, "Invalid", "Could not get the PE32 entry point address for PEI Core.");
2168 VerboseMsg("UpdateArmResetVectorIfNeeded found PEI core entry at 0x%llx", (unsigned long long)PeiCoreEntryAddress
);
2170 // if we previously found an SEC Core make sure machine types match
2171 if (UpdateVectorSec
&& (MachineType
!= PeiMachineType
)) {
2172 Error(NULL
, 0, 3000, "Invalid", "SEC and PEI machine types do not match, can't update reset vector");
2176 MachineType
= PeiMachineType
;
2179 UpdateVectorPei
= TRUE
;
2182 if (!UpdateVectorSec
&& !UpdateVectorPei
) {
2186 if (MachineType
== EFI_IMAGE_MACHINE_ARMT
) {
2187 // ARM: Array of 4 UINT32s:
2188 // 0 - is branch relative to SEC entry point
2189 // 1 - PEI Entry Point
2190 // 2 - movs pc,lr for a SWI handler
2191 // 3 - Place holder for Common Exception Handler
2192 UINT32 ResetVector
[4];
2194 memset(ResetVector
, 0, sizeof (ResetVector
));
2196 // if we found an SEC core entry point then generate a branch instruction
2197 // to it and populate a debugger SWI entry as well
2198 if (UpdateVectorSec
) {
2200 VerboseMsg("UpdateArmResetVectorIfNeeded updating ARM SEC vector");
2202 // B SecEntryPoint - signed_immed_24 part +/-32MB offset
2203 // on ARM, the PC is always 8 ahead, so we're not really jumping from the base address, but from base address + 8
2204 ResetVector
[0] = (INT32
)(SecCoreEntryAddress
- FvInfo
->BaseAddress
- 8) >> 2;
2206 if (ResetVector
[0] > 0x00FFFFFF) {
2207 Error(NULL
, 0, 3000, "Invalid", "SEC Entry point must be within 32MB of the start of the FV");
2211 // Add opcode for an unconditional branch with no link. i.e.: " B SecEntryPoint"
2212 ResetVector
[0] |= ARMT_UNCONDITIONAL_JUMP_INSTRUCTION
;
2214 // SWI handler movs pc,lr. Just in case a debugger uses SWI
2215 ResetVector
[2] = 0xE1B0F07E;
2217 // Place holder to support a common interrupt handler from ROM.
2218 // Currently not supported. For this to be used the reset vector would not be in this FV
2219 // and the exception vectors would be hard coded in the ROM and just through this address
2220 // to find a common handler in the a module in the FV.
2224 // if a PEI core entry was found place its address in the vector area
2225 if (UpdateVectorPei
) {
2227 VerboseMsg("UpdateArmResetVectorIfNeeded updating ARM PEI address");
2229 // Address of PEI Core, if we have one
2230 ResetVector
[1] = (UINT32
)PeiCoreEntryAddress
;
2234 // Copy to the beginning of the FV
2236 memcpy(FvImage
->FileImage
, ResetVector
, sizeof (ResetVector
));
2238 } else if (MachineType
== EFI_IMAGE_MACHINE_AARCH64
) {
2239 // AArch64: Used as UINT64 ResetVector[2]
2240 // 0 - is branch relative to SEC entry point
2241 // 1 - PEI Entry Point
2242 UINT64 ResetVector
[2];
2244 memset(ResetVector
, 0, sizeof (ResetVector
));
2247 ARMT above has an entry in ResetVector[2] for SWI. The way we are using the ResetVector
2248 array at the moment, for AArch64, does not allow us space for this as the header only
2249 allows for a fixed amount of bytes at the start. If we are sure that UEFI will live
2250 within the first 4GB of addressable RAM we could potentially adopt the same ResetVector
2251 layout as above. But for the moment we replace the four 32bit vectors with two 64bit
2252 vectors in the same area of the Image heasder. This allows UEFI to start from a 64bit
2256 // if we found an SEC core entry point then generate a branch instruction to it
2257 if (UpdateVectorSec
) {
2259 VerboseMsg("UpdateArmResetVectorIfNeeded updating AArch64 SEC vector");
2261 ResetVector
[0] = (UINT64
)(SecCoreEntryAddress
- FvInfo
->BaseAddress
) >> 2;
2263 // B SecEntryPoint - signed_immed_26 part +/-128MB offset
2264 if (ResetVector
[0] > 0x03FFFFFF) {
2265 Error(NULL
, 0, 3000, "Invalid", "SEC Entry point must be within 128MB of the start of the FV");
2268 // Add opcode for an unconditional branch with no link. i.e.: " B SecEntryPoint"
2269 ResetVector
[0] |= ARM64_UNCONDITIONAL_JUMP_INSTRUCTION
;
2272 // if a PEI core entry was found place its address in the vector area
2273 if (UpdateVectorPei
) {
2275 VerboseMsg("UpdateArmResetVectorIfNeeded updating AArch64 PEI address");
2277 // Address of PEI Core, if we have one
2278 ResetVector
[1] = (UINT64
)PeiCoreEntryAddress
;
2282 // Copy to the beginning of the FV
2284 memcpy(FvImage
->FileImage
, ResetVector
, sizeof (ResetVector
));
2287 Error(NULL
, 0, 3000, "Invalid", "Unknown machine type");
2297 OUT UINT32
*EntryPoint
,
2298 OUT UINT32
*BaseOfCode
,
2299 OUT UINT16
*MachineType
2303 Routine Description:
2305 Retrieves the PE32 entry point offset and machine type from PE image or TeImage.
2306 See EfiImage.h for machine types. The entry point offset is from the beginning
2307 of the PE32 buffer passed in.
2311 Pe32 Beginning of the PE32.
2312 EntryPoint Offset from the beginning of the PE32 to the image entry point.
2313 BaseOfCode Base address of code.
2314 MachineType Magic number for the machine type.
2318 EFI_SUCCESS Function completed successfully.
2319 EFI_ABORTED Error encountered.
2320 EFI_INVALID_PARAMETER A required parameter was NULL.
2321 EFI_UNSUPPORTED The operation is unsupported.
2325 EFI_IMAGE_DOS_HEADER
*DosHeader
;
2326 EFI_IMAGE_OPTIONAL_HEADER_UNION
*ImgHdr
;
2327 EFI_TE_IMAGE_HEADER
*TeHeader
;
2330 // Verify input parameters
2333 return EFI_INVALID_PARAMETER
;
2337 // First check whether it is one TE Image.
2339 TeHeader
= (EFI_TE_IMAGE_HEADER
*) Pe32
;
2340 if (TeHeader
->Signature
== EFI_TE_IMAGE_HEADER_SIGNATURE
) {
2342 // By TeImage Header to get output
2344 *EntryPoint
= TeHeader
->AddressOfEntryPoint
+ sizeof (EFI_TE_IMAGE_HEADER
) - TeHeader
->StrippedSize
;
2345 *BaseOfCode
= TeHeader
->BaseOfCode
+ sizeof (EFI_TE_IMAGE_HEADER
) - TeHeader
->StrippedSize
;
2346 *MachineType
= TeHeader
->Machine
;
2350 // Then check whether
2351 // First is the DOS header
2353 DosHeader
= (EFI_IMAGE_DOS_HEADER
*) Pe32
;
2356 // Verify DOS header is expected
2358 if (DosHeader
->e_magic
!= EFI_IMAGE_DOS_SIGNATURE
) {
2359 Error (NULL
, 0, 3000, "Invalid", "Unknown magic number in the DOS header, 0x%04X.", DosHeader
->e_magic
);
2360 return EFI_UNSUPPORTED
;
2363 // Immediately following is the NT header.
2365 ImgHdr
= (EFI_IMAGE_OPTIONAL_HEADER_UNION
*) ((UINTN
) Pe32
+ DosHeader
->e_lfanew
);
2368 // Verify NT header is expected
2370 if (ImgHdr
->Pe32
.Signature
!= EFI_IMAGE_NT_SIGNATURE
) {
2371 Error (NULL
, 0, 3000, "Invalid", "Unrecognized image signature 0x%08X.", (unsigned) ImgHdr
->Pe32
.Signature
);
2372 return EFI_UNSUPPORTED
;
2377 *EntryPoint
= ImgHdr
->Pe32
.OptionalHeader
.AddressOfEntryPoint
;
2378 *BaseOfCode
= ImgHdr
->Pe32
.OptionalHeader
.BaseOfCode
;
2379 *MachineType
= ImgHdr
->Pe32
.FileHeader
.Machine
;
2383 // Verify machine type is supported
2385 if ((*MachineType
!= EFI_IMAGE_MACHINE_IA32
) && (*MachineType
!= EFI_IMAGE_MACHINE_X64
) && (*MachineType
!= EFI_IMAGE_MACHINE_EBC
) &&
2386 (*MachineType
!= EFI_IMAGE_MACHINE_ARMT
) && (*MachineType
!= EFI_IMAGE_MACHINE_AARCH64
)) {
2387 Error (NULL
, 0, 3000, "Invalid", "Unrecognized machine type in the PE32 file.");
2388 return EFI_UNSUPPORTED
;
2396 IN CHAR8
*InfFileImage
,
2397 IN UINTN InfFileSize
,
2398 IN CHAR8
*FvFileName
,
2399 IN CHAR8
*MapFileName
2403 Routine Description:
2405 This is the main function which will be called from application.
2409 InfFileImage Buffer containing the INF file contents.
2410 InfFileSize Size of the contents of the InfFileImage buffer.
2411 FvFileName Requested name for the FV file.
2412 MapFileName Fv map file to log fv driver information.
2416 EFI_SUCCESS Function completed successfully.
2417 EFI_OUT_OF_RESOURCES Could not allocate required resources.
2418 EFI_ABORTED Error encountered.
2419 EFI_INVALID_PARAMETER A required parameter was NULL.
2424 MEMORY_FILE InfMemoryFile
;
2425 MEMORY_FILE FvImageMemoryFile
;
2427 EFI_FIRMWARE_VOLUME_HEADER
*FvHeader
;
2428 EFI_FFS_FILE_HEADER
*VtfFileImage
;
2429 UINT8
*FvBufferHeader
; // to make sure fvimage header 8 type alignment.
2435 EFI_FIRMWARE_VOLUME_EXT_HEADER
*FvExtHeader
;
2436 FILE *FvExtHeaderFile
;
2438 CHAR8
*FvReportName
;
2441 FvBufferHeader
= NULL
;
2445 FvReportName
= NULL
;
2446 FvReportFile
= NULL
;
2448 if (InfFileImage
!= NULL
) {
2450 // Initialize file structures
2452 InfMemoryFile
.FileImage
= InfFileImage
;
2453 InfMemoryFile
.CurrentFilePointer
= InfFileImage
;
2454 InfMemoryFile
.Eof
= InfFileImage
+ InfFileSize
;
2457 // Parse the FV inf file for header information
2459 Status
= ParseFvInf (&InfMemoryFile
, &mFvDataInfo
);
2460 if (EFI_ERROR (Status
)) {
2461 Error (NULL
, 0, 0003, "Error parsing file", "the input FV INF file.");
2467 // Update the file name return values
2469 if (FvFileName
== NULL
&& mFvDataInfo
.FvName
[0] != '\0') {
2470 FvFileName
= mFvDataInfo
.FvName
;
2473 if (FvFileName
== NULL
) {
2474 Error (NULL
, 0, 1001, "Missing option", "Output file name");
2478 if (mFvDataInfo
.FvBlocks
[0].Length
== 0) {
2479 Error (NULL
, 0, 1001, "Missing required argument", "Block Size");
2484 // Debug message Fv File System Guid
2486 if (mFvDataInfo
.FvFileSystemGuidSet
) {
2487 DebugMsg (NULL
, 0, 9, "FV File System Guid", "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X",
2488 (unsigned) mFvDataInfo
.FvFileSystemGuid
.Data1
,
2489 mFvDataInfo
.FvFileSystemGuid
.Data2
,
2490 mFvDataInfo
.FvFileSystemGuid
.Data3
,
2491 mFvDataInfo
.FvFileSystemGuid
.Data4
[0],
2492 mFvDataInfo
.FvFileSystemGuid
.Data4
[1],
2493 mFvDataInfo
.FvFileSystemGuid
.Data4
[2],
2494 mFvDataInfo
.FvFileSystemGuid
.Data4
[3],
2495 mFvDataInfo
.FvFileSystemGuid
.Data4
[4],
2496 mFvDataInfo
.FvFileSystemGuid
.Data4
[5],
2497 mFvDataInfo
.FvFileSystemGuid
.Data4
[6],
2498 mFvDataInfo
.FvFileSystemGuid
.Data4
[7]);
2502 // Add PI FV extension header
2505 FvExtHeaderFile
= NULL
;
2506 if (mFvDataInfo
.FvExtHeaderFile
[0] != 0) {
2508 // Open the FV Extension Header file
2510 FvExtHeaderFile
= fopen (LongFilePath (mFvDataInfo
.FvExtHeaderFile
), "rb");
2511 if (FvExtHeaderFile
== NULL
) {
2512 Error (NULL
, 0, 0001, "Error opening file", mFvDataInfo
.FvExtHeaderFile
);
2517 // Get the file size
2519 FileSize
= _filelength (fileno (FvExtHeaderFile
));
2522 // Allocate a buffer for the FV Extension Header
2524 FvExtHeader
= malloc(FileSize
);
2525 if (FvExtHeader
== NULL
) {
2526 fclose (FvExtHeaderFile
);
2527 return EFI_OUT_OF_RESOURCES
;
2531 // Read the FV Extension Header
2533 fread (FvExtHeader
, sizeof (UINT8
), FileSize
, FvExtHeaderFile
);
2534 fclose (FvExtHeaderFile
);
2537 // See if there is an override for the FV Name GUID
2539 if (mFvDataInfo
.FvNameGuidSet
) {
2540 memcpy (&FvExtHeader
->FvName
, &mFvDataInfo
.FvNameGuid
, sizeof (EFI_GUID
));
2542 memcpy (&mFvDataInfo
.FvNameGuid
, &FvExtHeader
->FvName
, sizeof (EFI_GUID
));
2543 mFvDataInfo
.FvNameGuidSet
= TRUE
;
2544 } else if (mFvDataInfo
.FvNameGuidSet
) {
2546 // Allocate a buffer for the FV Extension Header
2548 FvExtHeader
= malloc(sizeof (EFI_FIRMWARE_VOLUME_EXT_HEADER
));
2549 if (FvExtHeader
== NULL
) {
2550 return EFI_OUT_OF_RESOURCES
;
2552 memcpy (&FvExtHeader
->FvName
, &mFvDataInfo
.FvNameGuid
, sizeof (EFI_GUID
));
2553 FvExtHeader
->ExtHeaderSize
= sizeof (EFI_FIRMWARE_VOLUME_EXT_HEADER
);
2557 // Debug message Fv Name Guid
2559 if (mFvDataInfo
.FvNameGuidSet
) {
2560 DebugMsg (NULL
, 0, 9, "FV Name Guid", "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X",
2561 (unsigned) mFvDataInfo
.FvNameGuid
.Data1
,
2562 mFvDataInfo
.FvNameGuid
.Data2
,
2563 mFvDataInfo
.FvNameGuid
.Data3
,
2564 mFvDataInfo
.FvNameGuid
.Data4
[0],
2565 mFvDataInfo
.FvNameGuid
.Data4
[1],
2566 mFvDataInfo
.FvNameGuid
.Data4
[2],
2567 mFvDataInfo
.FvNameGuid
.Data4
[3],
2568 mFvDataInfo
.FvNameGuid
.Data4
[4],
2569 mFvDataInfo
.FvNameGuid
.Data4
[5],
2570 mFvDataInfo
.FvNameGuid
.Data4
[6],
2571 mFvDataInfo
.FvNameGuid
.Data4
[7]);
2574 if (CompareGuid (&mFvDataInfo
.FvFileSystemGuid
, &mEfiFirmwareFileSystem2Guid
) == 0 ||
2575 CompareGuid (&mFvDataInfo
.FvFileSystemGuid
, &mEfiFirmwareFileSystem3Guid
) == 0) {
2576 mFvDataInfo
.IsPiFvImage
= TRUE
;
2580 // FvMap file to log the function address of all modules in one Fvimage
2582 if (MapFileName
!= NULL
) {
2583 if (strlen (MapFileName
) > MAX_LONG_FILE_PATH
- 1) {
2584 Error (NULL
, 0, 1003, "Invalid option value", "MapFileName %s is too long!", MapFileName
);
2585 Status
= EFI_ABORTED
;
2589 FvMapName
= malloc (strlen (MapFileName
) + 1);
2590 if (FvMapName
== NULL
) {
2591 Error (NULL
, 0, 4001, "Resource", "memory cannot be allocated!");
2592 Status
= EFI_OUT_OF_RESOURCES
;
2596 strcpy (FvMapName
, MapFileName
);
2598 if (strlen (FvFileName
) + strlen (".map") > MAX_LONG_FILE_PATH
- 1) {
2599 Error (NULL
, 0, 1003, "Invalid option value", "FvFileName %s is too long!", FvFileName
);
2600 Status
= EFI_ABORTED
;
2604 FvMapName
= malloc (strlen (FvFileName
) + strlen (".map") + 1);
2605 if (FvMapName
== NULL
) {
2606 Error (NULL
, 0, 4001, "Resource", "memory cannot be allocated!");
2607 Status
= EFI_OUT_OF_RESOURCES
;
2611 strcpy (FvMapName
, FvFileName
);
2612 strcat (FvMapName
, ".map");
2614 VerboseMsg ("FV Map file name is %s", FvMapName
);
2617 // FvReport file to log the FV information in one Fvimage
2619 if (strlen (FvFileName
) + strlen (".txt") > MAX_LONG_FILE_PATH
- 1) {
2620 Error (NULL
, 0, 1003, "Invalid option value", "FvFileName %s is too long!", FvFileName
);
2621 Status
= EFI_ABORTED
;
2625 FvReportName
= malloc (strlen (FvFileName
) + strlen (".txt") + 1);
2626 if (FvReportName
== NULL
) {
2627 Error (NULL
, 0, 4001, "Resource", "memory cannot be allocated!");
2628 Status
= EFI_OUT_OF_RESOURCES
;
2632 strcpy (FvReportName
, FvFileName
);
2633 strcat (FvReportName
, ".txt");
2636 // Calculate the FV size and Update Fv Size based on the actual FFS files.
2637 // And Update mFvDataInfo data.
2639 Status
= CalculateFvSize (&mFvDataInfo
);
2640 if (EFI_ERROR (Status
)) {
2643 VerboseMsg ("the generated FV image size is %u bytes", (unsigned) mFvDataInfo
.Size
);
2646 // support fv image and empty fv image
2648 FvImageSize
= mFvDataInfo
.Size
;
2651 // Allocate the FV, assure FvImage Header 8 byte alignment
2653 FvBufferHeader
= malloc (FvImageSize
+ sizeof (UINT64
));
2654 if (FvBufferHeader
== NULL
) {
2655 Status
= EFI_OUT_OF_RESOURCES
;
2658 FvImage
= (UINT8
*) (((UINTN
) FvBufferHeader
+ 7) & ~7);
2661 // Initialize the FV to the erase polarity
2663 if (mFvDataInfo
.FvAttributes
== 0) {
2665 // Set Default Fv Attribute
2667 mFvDataInfo
.FvAttributes
= FV_DEFAULT_ATTRIBUTE
;
2669 if (mFvDataInfo
.FvAttributes
& EFI_FVB2_ERASE_POLARITY
) {
2670 memset (FvImage
, -1, FvImageSize
);
2672 memset (FvImage
, 0, FvImageSize
);
2676 // Initialize FV header
2678 FvHeader
= (EFI_FIRMWARE_VOLUME_HEADER
*) FvImage
;
2681 // Initialize the zero vector to all zeros.
2683 memset (FvHeader
->ZeroVector
, 0, 16);
2686 // Copy the Fv file system GUID
2688 memcpy (&FvHeader
->FileSystemGuid
, &mFvDataInfo
.FvFileSystemGuid
, sizeof (EFI_GUID
));
2690 FvHeader
->FvLength
= FvImageSize
;
2691 FvHeader
->Signature
= EFI_FVH_SIGNATURE
;
2692 FvHeader
->Attributes
= mFvDataInfo
.FvAttributes
;
2693 FvHeader
->Revision
= EFI_FVH_REVISION
;
2694 FvHeader
->ExtHeaderOffset
= 0;
2695 FvHeader
->Reserved
[0] = 0;
2698 // Copy firmware block map
2700 for (Index
= 0; mFvDataInfo
.FvBlocks
[Index
].Length
!= 0; Index
++) {
2701 FvHeader
->BlockMap
[Index
].NumBlocks
= mFvDataInfo
.FvBlocks
[Index
].NumBlocks
;
2702 FvHeader
->BlockMap
[Index
].Length
= mFvDataInfo
.FvBlocks
[Index
].Length
;
2706 // Add block map terminator
2708 FvHeader
->BlockMap
[Index
].NumBlocks
= 0;
2709 FvHeader
->BlockMap
[Index
].Length
= 0;
2712 // Complete the header
2714 FvHeader
->HeaderLength
= (UINT16
) (((UINTN
) &(FvHeader
->BlockMap
[Index
+ 1])) - (UINTN
) FvImage
);
2715 FvHeader
->Checksum
= 0;
2716 FvHeader
->Checksum
= CalculateChecksum16 ((UINT16
*) FvHeader
, FvHeader
->HeaderLength
/ sizeof (UINT16
));
2719 // If there is no FFS file, generate one empty FV
2721 if (mFvDataInfo
.FvFiles
[0][0] == 0 && !mFvDataInfo
.FvNameGuidSet
) {
2726 // Initialize our "file" view of the buffer
2728 FvImageMemoryFile
.FileImage
= (CHAR8
*)FvImage
;
2729 FvImageMemoryFile
.CurrentFilePointer
= (CHAR8
*)FvImage
+ FvHeader
->HeaderLength
;
2730 FvImageMemoryFile
.Eof
= (CHAR8
*)FvImage
+ FvImageSize
;
2733 // Initialize the FV library.
2735 InitializeFvLib (FvImageMemoryFile
.FileImage
, FvImageSize
);
2738 // Initialize the VTF file address.
2740 VtfFileImage
= (EFI_FFS_FILE_HEADER
*) FvImageMemoryFile
.Eof
;
2745 FvMapFile
= fopen (LongFilePath (FvMapName
), "w");
2746 if (FvMapFile
== NULL
) {
2747 Error (NULL
, 0, 0001, "Error opening file", FvMapName
);
2748 Status
= EFI_ABORTED
;
2753 // Open FvReport file
2755 FvReportFile
= fopen (LongFilePath (FvReportName
), "w");
2756 if (FvReportFile
== NULL
) {
2757 Error (NULL
, 0, 0001, "Error opening file", FvReportName
);
2758 Status
= EFI_ABORTED
;
2762 // record FV size information into FvMap file.
2764 if (mFvTotalSize
!= 0) {
2765 fprintf (FvMapFile
, EFI_FV_TOTAL_SIZE_STRING
);
2766 fprintf (FvMapFile
, " = 0x%x\n", (unsigned) mFvTotalSize
);
2768 if (mFvTakenSize
!= 0) {
2769 fprintf (FvMapFile
, EFI_FV_TAKEN_SIZE_STRING
);
2770 fprintf (FvMapFile
, " = 0x%x\n", (unsigned) mFvTakenSize
);
2772 if (mFvTotalSize
!= 0 && mFvTakenSize
!= 0) {
2773 fprintf (FvMapFile
, EFI_FV_SPACE_SIZE_STRING
);
2774 fprintf (FvMapFile
, " = 0x%x\n\n", (unsigned) (mFvTotalSize
- mFvTakenSize
));
2778 // record FV size information to FvReportFile.
2780 fprintf (FvReportFile
, "%s = 0x%x\n", EFI_FV_TOTAL_SIZE_STRING
, (unsigned) mFvTotalSize
);
2781 fprintf (FvReportFile
, "%s = 0x%x\n", EFI_FV_TAKEN_SIZE_STRING
, (unsigned) mFvTakenSize
);
2784 // Add PI FV extension header
2786 if (FvExtHeader
!= NULL
) {
2788 // Add FV Extended Header contents to the FV as a PAD file
2790 AddPadFile (&FvImageMemoryFile
, 4, VtfFileImage
, FvExtHeader
, 0);
2793 // Fv Extension header change update Fv Header Check sum
2795 FvHeader
->Checksum
= 0;
2796 FvHeader
->Checksum
= CalculateChecksum16 ((UINT16
*) FvHeader
, FvHeader
->HeaderLength
/ sizeof (UINT16
));
2802 for (Index
= 0; mFvDataInfo
.FvFiles
[Index
][0] != 0; Index
++) {
2806 Status
= AddFile (&FvImageMemoryFile
, &mFvDataInfo
, Index
, &VtfFileImage
, FvMapFile
, FvReportFile
);
2809 // Exit if error detected while adding the file
2811 if (EFI_ERROR (Status
)) {
2817 // If there is a VTF file, some special actions need to occur.
2819 if ((UINTN
) VtfFileImage
!= (UINTN
) FvImageMemoryFile
.Eof
) {
2821 // Pad from the end of the last file to the beginning of the VTF file.
2822 // If the left space is less than sizeof (EFI_FFS_FILE_HEADER)?
2824 Status
= PadFvImage (&FvImageMemoryFile
, VtfFileImage
);
2825 if (EFI_ERROR (Status
)) {
2826 Error (NULL
, 0, 4002, "Resource", "FV space is full, cannot add pad file between the last file and the VTF file.");
2831 // Update reset vector (SALE_ENTRY for IPF)
2832 // Now for IA32 and IA64 platform, the fv which has bsf file must have the
2833 // EndAddress of 0xFFFFFFFF (unless the section was rebased).
2834 // Thus, only this type fv needs to update the reset vector.
2835 // If the PEI Core is found, the VTF file will probably get
2836 // corrupted by updating the entry point.
2838 if (mFvDataInfo
.ForceRebase
== 1 ||
2839 (mFvDataInfo
.BaseAddress
+ mFvDataInfo
.Size
) == FV_IMAGES_TOP_ADDRESS
) {
2840 Status
= UpdateResetVector (&FvImageMemoryFile
, &mFvDataInfo
, VtfFileImage
);
2841 if (EFI_ERROR(Status
)) {
2842 Error (NULL
, 0, 3000, "Invalid", "Could not update the reset vector.");
2845 DebugMsg (NULL
, 0, 9, "Update Reset vector in VTF file", NULL
);
2851 Status
= UpdateArmResetVectorIfNeeded (&FvImageMemoryFile
, &mFvDataInfo
);
2852 if (EFI_ERROR (Status
)) {
2853 Error (NULL
, 0, 3000, "Invalid", "Could not update the reset vector.");
2858 // Update Checksum for FvHeader
2860 FvHeader
->Checksum
= 0;
2861 FvHeader
->Checksum
= CalculateChecksum16 ((UINT16
*) FvHeader
, FvHeader
->HeaderLength
/ sizeof (UINT16
));
2865 // Update FV Alignment attribute to the largest alignment of all the FFS files in the FV
2867 if (((FvHeader
->Attributes
& EFI_FVB2_WEAK_ALIGNMENT
) != EFI_FVB2_WEAK_ALIGNMENT
) &&
2868 (((FvHeader
->Attributes
& EFI_FVB2_ALIGNMENT
) >> 16)) < MaxFfsAlignment
) {
2869 FvHeader
->Attributes
= ((MaxFfsAlignment
<< 16) | (FvHeader
->Attributes
& 0xFFFF));
2871 // Update Checksum for FvHeader
2873 FvHeader
->Checksum
= 0;
2874 FvHeader
->Checksum
= CalculateChecksum16 ((UINT16
*) FvHeader
, FvHeader
->HeaderLength
/ sizeof (UINT16
));
2878 // If there are large FFS in FV, the file system GUID should set to system 3 GUID.
2880 if (mIsLargeFfs
&& CompareGuid (&FvHeader
->FileSystemGuid
, &mEfiFirmwareFileSystem2Guid
) == 0) {
2881 memcpy (&FvHeader
->FileSystemGuid
, &mEfiFirmwareFileSystem3Guid
, sizeof (EFI_GUID
));
2882 FvHeader
->Checksum
= 0;
2883 FvHeader
->Checksum
= CalculateChecksum16 ((UINT16
*) FvHeader
, FvHeader
->HeaderLength
/ sizeof (UINT16
));
2890 FvFile
= fopen (LongFilePath (FvFileName
), "wb");
2891 if (FvFile
== NULL
) {
2892 Error (NULL
, 0, 0001, "Error opening file", FvFileName
);
2893 Status
= EFI_ABORTED
;
2897 if (fwrite (FvImage
, 1, FvImageSize
, FvFile
) != FvImageSize
) {
2898 Error (NULL
, 0, 0002, "Error writing file", FvFileName
);
2899 Status
= EFI_ABORTED
;
2904 if (FvBufferHeader
!= NULL
) {
2905 free (FvBufferHeader
);
2908 if (FvExtHeader
!= NULL
) {
2912 if (FvMapName
!= NULL
) {
2916 if (FvReportName
!= NULL
) {
2917 free (FvReportName
);
2920 if (FvFile
!= NULL
) {
2925 if (FvMapFile
!= NULL
) {
2930 if (FvReportFile
!= NULL
) {
2931 fflush (FvReportFile
);
2932 fclose (FvReportFile
);
2938 UpdatePeiCoreEntryInFit (
2939 IN FIT_TABLE
*FitTablePtr
,
2940 IN UINT64 PeiCorePhysicalAddress
2944 Routine Description:
2946 This function is used to update the Pei Core address in FIT, this can be used by Sec core to pass control from
2951 FitTablePtr - The pointer of FIT_TABLE.
2952 PeiCorePhysicalAddress - The address of Pei Core entry.
2956 EFI_SUCCESS - The PEI_CORE FIT entry was updated successfully.
2957 EFI_NOT_FOUND - Not found the PEI_CORE FIT entry.
2961 FIT_TABLE
*TmpFitPtr
;
2963 UINTN NumFitComponents
;
2965 TmpFitPtr
= FitTablePtr
;
2966 NumFitComponents
= TmpFitPtr
->CompSize
;
2968 for (Index
= 0; Index
< NumFitComponents
; Index
++) {
2969 if ((TmpFitPtr
->CvAndType
& FIT_TYPE_MASK
) == COMP_TYPE_FIT_PEICORE
) {
2970 TmpFitPtr
->CompAddress
= PeiCorePhysicalAddress
;
2977 return EFI_NOT_FOUND
;
2982 IN FIT_TABLE
*FitTablePtr
2986 Routine Description:
2988 This function is used to update the checksum for FIT.
2993 FitTablePtr - The pointer of FIT_TABLE.
3001 if ((FitTablePtr
->CvAndType
& CHECKSUM_BIT_MASK
) >> 7) {
3002 FitTablePtr
->CheckSum
= 0;
3003 FitTablePtr
->CheckSum
= CalculateChecksum8 ((UINT8
*) FitTablePtr
, FitTablePtr
->CompSize
* 16);
3012 Routine Description:
3013 Calculate the FV size and Update Fv Size based on the actual FFS files.
3014 And Update FvInfo data.
3017 FvInfoPtr - The pointer to FV_INFO structure.
3020 EFI_ABORTED - Ffs Image Error
3021 EFI_SUCCESS - Successfully update FvSize
3024 UINTN CurrentOffset
;
3028 UINTN FvExtendHeaderSize
;
3029 UINT32 FfsAlignment
;
3030 UINT32 FfsHeaderSize
;
3031 EFI_FFS_FILE_HEADER FfsHeader
;
3034 FvExtendHeaderSize
= 0;
3040 // Compute size for easy access later
3042 FvInfoPtr
->Size
= 0;
3043 for (Index
= 0; FvInfoPtr
->FvBlocks
[Index
].NumBlocks
> 0 && FvInfoPtr
->FvBlocks
[Index
].Length
> 0; Index
++) {
3044 FvInfoPtr
->Size
+= FvInfoPtr
->FvBlocks
[Index
].NumBlocks
* FvInfoPtr
->FvBlocks
[Index
].Length
;
3048 // Calculate the required sizes for all FFS files.
3050 CurrentOffset
= sizeof (EFI_FIRMWARE_VOLUME_HEADER
);
3052 for (Index
= 1;; Index
++) {
3053 CurrentOffset
+= sizeof (EFI_FV_BLOCK_MAP_ENTRY
);
3054 if (FvInfoPtr
->FvBlocks
[Index
].NumBlocks
== 0 || FvInfoPtr
->FvBlocks
[Index
].Length
== 0) {
3060 // Calculate PI extension header
3062 if (mFvDataInfo
.FvExtHeaderFile
[0] != '\0') {
3063 fpin
= fopen (LongFilePath (mFvDataInfo
.FvExtHeaderFile
), "rb");
3065 Error (NULL
, 0, 0001, "Error opening file", mFvDataInfo
.FvExtHeaderFile
);
3068 FvExtendHeaderSize
= _filelength (fileno (fpin
));
3070 if (sizeof (EFI_FFS_FILE_HEADER
) + FvExtendHeaderSize
>= MAX_FFS_SIZE
) {
3071 CurrentOffset
+= sizeof (EFI_FFS_FILE_HEADER2
) + FvExtendHeaderSize
;
3074 CurrentOffset
+= sizeof (EFI_FFS_FILE_HEADER
) + FvExtendHeaderSize
;
3076 CurrentOffset
= (CurrentOffset
+ 7) & (~7);
3077 } else if (mFvDataInfo
.FvNameGuidSet
) {
3078 CurrentOffset
+= sizeof (EFI_FFS_FILE_HEADER
) + sizeof (EFI_FIRMWARE_VOLUME_EXT_HEADER
);
3079 CurrentOffset
= (CurrentOffset
+ 7) & (~7);
3083 // Accumulate every FFS file size.
3085 for (Index
= 0; FvInfoPtr
->FvFiles
[Index
][0] != 0; Index
++) {
3090 fpin
= fopen (LongFilePath (FvInfoPtr
->FvFiles
[Index
]), "rb");
3092 Error (NULL
, 0, 0001, "Error opening file", FvInfoPtr
->FvFiles
[Index
]);
3096 // Get the file size
3098 FfsFileSize
= _filelength (fileno (fpin
));
3099 if (FfsFileSize
>= MAX_FFS_SIZE
) {
3100 FfsHeaderSize
= sizeof(EFI_FFS_FILE_HEADER2
);
3103 FfsHeaderSize
= sizeof(EFI_FFS_FILE_HEADER
);
3106 // Read Ffs File header
3108 fread (&FfsHeader
, sizeof (UINT8
), sizeof (EFI_FFS_FILE_HEADER
), fpin
);
3114 if (FvInfoPtr
->IsPiFvImage
) {
3116 // Check whether this ffs file is vtf file
3118 if (IsVtfFile (&FfsHeader
)) {
3121 // One Fv image can't have two vtf files.
3123 Error (NULL
, 0, 3000,"Invalid", "One Fv image can't have two vtf files.");
3127 VtfFileSize
= FfsFileSize
;
3132 // Get the alignment of FFS file
3134 ReadFfsAlignment (&FfsHeader
, &FfsAlignment
);
3135 FfsAlignment
= 1 << FfsAlignment
;
3139 if (((CurrentOffset
+ FfsHeaderSize
) % FfsAlignment
) != 0) {
3141 // Only EFI_FFS_FILE_HEADER is needed for a pad section.
3143 CurrentOffset
= (CurrentOffset
+ FfsHeaderSize
+ sizeof(EFI_FFS_FILE_HEADER
) + FfsAlignment
- 1) & ~(FfsAlignment
- 1);
3144 CurrentOffset
-= FfsHeaderSize
;
3149 // Add ffs file size
3151 if (FvInfoPtr
->SizeofFvFiles
[Index
] > FfsFileSize
) {
3152 CurrentOffset
+= FvInfoPtr
->SizeofFvFiles
[Index
];
3154 CurrentOffset
+= FfsFileSize
;
3158 // Make next ffs file start at QWord Boundary
3160 if (FvInfoPtr
->IsPiFvImage
) {
3161 CurrentOffset
= (CurrentOffset
+ EFI_FFS_FILE_HEADER_ALIGNMENT
- 1) & ~(EFI_FFS_FILE_HEADER_ALIGNMENT
- 1);
3164 CurrentOffset
+= VtfFileSize
;
3165 DebugMsg (NULL
, 0, 9, "FvImage size", "The calculated fv image size is 0x%x and the current set fv image size is 0x%x", (unsigned) CurrentOffset
, (unsigned) FvInfoPtr
->Size
);
3167 if (FvInfoPtr
->Size
== 0) {
3169 // Update FvInfo data
3171 FvInfoPtr
->FvBlocks
[0].NumBlocks
= CurrentOffset
/ FvInfoPtr
->FvBlocks
[0].Length
+ ((CurrentOffset
% FvInfoPtr
->FvBlocks
[0].Length
)?1:0);
3172 FvInfoPtr
->Size
= FvInfoPtr
->FvBlocks
[0].NumBlocks
* FvInfoPtr
->FvBlocks
[0].Length
;
3173 FvInfoPtr
->FvBlocks
[1].NumBlocks
= 0;
3174 FvInfoPtr
->FvBlocks
[1].Length
= 0;
3175 } else if (FvInfoPtr
->Size
< CurrentOffset
) {
3179 Error (NULL
, 0, 3000, "Invalid", "the required fv image size 0x%x exceeds the set fv image size 0x%x", (unsigned) CurrentOffset
, (unsigned) FvInfoPtr
->Size
);
3180 return EFI_INVALID_PARAMETER
;
3184 // Set Fv Size Information
3186 mFvTotalSize
= FvInfoPtr
->Size
;
3187 mFvTakenSize
= CurrentOffset
;
3193 FfsRebaseImageRead (
3194 IN VOID
*FileHandle
,
3195 IN UINTN FileOffset
,
3196 IN OUT UINT32
*ReadSize
,
3201 Routine Description:
3203 Support routine for the PE/COFF Loader that reads a buffer from a PE/COFF file
3207 FileHandle - The handle to the PE/COFF file
3209 FileOffset - The offset, in bytes, into the file to read
3211 ReadSize - The number of bytes to read from the file starting at FileOffset
3213 Buffer - A pointer to the buffer to read the data into.
3217 EFI_SUCCESS - ReadSize bytes of data were read into Buffer from the PE/COFF file starting at FileOffset
3221 CHAR8
*Destination8
;
3225 Destination8
= Buffer
;
3226 Source8
= (CHAR8
*) ((UINTN
) FileHandle
+ FileOffset
);
3229 *(Destination8
++) = *(Source8
++);
3238 IN EFI_FFS_FILE_HEADER
*FfsFile
,
3243 Routine Description:
3245 This function gets all child FvImages in the input FfsFile, and records
3246 their base address to the parent image.
3249 FvInfo A pointer to FV_INFO structure.
3250 FfsFile A pointer to Ffs file image that may contain FvImage.
3251 XipOffset The offset address to the parent FvImage base.
3255 EFI_SUCCESS Base address of child Fv image is recorded.
3260 EFI_FILE_SECTION_POINTER SubFvSection
;
3261 EFI_FIRMWARE_VOLUME_HEADER
*SubFvImageHeader
;
3262 EFI_PHYSICAL_ADDRESS SubFvBaseAddress
;
3263 EFI_FILE_SECTION_POINTER CorePe32
;
3266 for (Index
= 1;; Index
++) {
3270 Status
= GetSectionByType (FfsFile
, EFI_SECTION_FIRMWARE_VOLUME_IMAGE
, Index
, &SubFvSection
);
3271 if (EFI_ERROR (Status
)) {
3274 SubFvImageHeader
= (EFI_FIRMWARE_VOLUME_HEADER
*) ((UINT8
*) SubFvSection
.FVImageSection
+ GetSectionHeaderLength(SubFvSection
.FVImageSection
));
3277 // See if there's an SEC core in the child FV
3278 Status
= FindCorePeSection(SubFvImageHeader
, SubFvImageHeader
->FvLength
, EFI_FV_FILETYPE_SECURITY_CORE
, &CorePe32
);
3280 // if we couldn't find the SEC core, look for a PEI core
3281 if (EFI_ERROR(Status
)) {
3282 Status
= FindCorePeSection(SubFvImageHeader
, SubFvImageHeader
->FvLength
, EFI_FV_FILETYPE_PEI_CORE
, &CorePe32
);
3285 if (!EFI_ERROR(Status
)) {
3286 Status
= GetCoreMachineType(CorePe32
, &MachineType
);
3287 if (EFI_ERROR(Status
)) {
3288 Error(NULL
, 0, 3000, "Invalid", "Could not get the PE32 machine type for SEC/PEI Core.");
3292 // machine type is ARM, set a flag so ARM reset vector processing occurs
3293 if ((MachineType
== EFI_IMAGE_MACHINE_ARMT
) || (MachineType
== EFI_IMAGE_MACHINE_AARCH64
)) {
3294 VerboseMsg("Located ARM/AArch64 SEC/PEI core in child FV");
3302 SubFvBaseAddress
= FvInfo
->BaseAddress
+ (UINTN
) SubFvImageHeader
- (UINTN
) FfsFile
+ XipOffset
;
3303 mFvBaseAddress
[mFvBaseAddressNumber
++ ] = SubFvBaseAddress
;
3311 IN OUT FV_INFO
*FvInfo
,
3313 IN OUT EFI_FFS_FILE_HEADER
*FfsFile
,
3319 Routine Description:
3321 This function determines if a file is XIP and should be rebased. It will
3322 rebase any PE32 sections found in the file using the base address.
3326 FvInfo A pointer to FV_INFO structure.
3327 FileName Ffs File PathName
3328 FfsFile A pointer to Ffs file image.
3329 XipOffset The offset address to use for rebasing the XIP file image.
3330 FvMapFile FvMapFile to record the function address in one Fvimage
3334 EFI_SUCCESS The image was properly rebased.
3335 EFI_INVALID_PARAMETER An input parameter is invalid.
3336 EFI_ABORTED An error occurred while rebasing the input file image.
3337 EFI_OUT_OF_RESOURCES Could not allocate a required resource.
3338 EFI_NOT_FOUND No compressed sections could be found.
3343 PE_COFF_LOADER_IMAGE_CONTEXT ImageContext
;
3344 PE_COFF_LOADER_IMAGE_CONTEXT OrigImageContext
;
3345 EFI_PHYSICAL_ADDRESS XipBase
;
3346 EFI_PHYSICAL_ADDRESS NewPe32BaseAddress
;
3348 EFI_FILE_SECTION_POINTER CurrentPe32Section
;
3349 EFI_FFS_FILE_STATE SavedState
;
3350 EFI_IMAGE_OPTIONAL_HEADER_UNION
*ImgHdr
;
3351 EFI_TE_IMAGE_HEADER
*TEImageHeader
;
3352 UINT8
*MemoryImagePointer
;
3353 EFI_IMAGE_SECTION_HEADER
*SectionHeader
;
3354 CHAR8 PeFileName
[MAX_LONG_FILE_PATH
];
3357 UINT8
*PeFileBuffer
;
3360 UINT32 FfsHeaderSize
;
3361 UINT32 CurSecHdrSize
;
3364 MemoryImagePointer
= NULL
;
3365 TEImageHeader
= NULL
;
3367 SectionHeader
= NULL
;
3370 PeFileBuffer
= NULL
;
3373 // Don't need to relocate image when BaseAddress is zero and no ForceRebase Flag specified.
3375 if ((FvInfo
->BaseAddress
== 0) && (FvInfo
->ForceRebase
== -1)) {
3380 // If ForceRebase Flag specified to FALSE, will always not take rebase action.
3382 if (FvInfo
->ForceRebase
== 0) {
3387 XipBase
= FvInfo
->BaseAddress
+ XipOffset
;
3390 // We only process files potentially containing PE32 sections.
3392 switch (FfsFile
->Type
) {
3393 case EFI_FV_FILETYPE_SECURITY_CORE
:
3394 case EFI_FV_FILETYPE_PEI_CORE
:
3395 case EFI_FV_FILETYPE_PEIM
:
3396 case EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER
:
3397 case EFI_FV_FILETYPE_DRIVER
:
3398 case EFI_FV_FILETYPE_DXE_CORE
:
3400 case EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE
:
3402 // Rebase the inside FvImage.
3404 GetChildFvFromFfs (FvInfo
, FfsFile
, XipOffset
);
3407 // Search PE/TE section in FV sectin.
3414 FfsHeaderSize
= GetFfsHeaderLength(FfsFile
);
3416 // Rebase each PE32 section
3418 Status
= EFI_SUCCESS
;
3419 for (Index
= 1;; Index
++) {
3423 NewPe32BaseAddress
= 0;
3428 Status
= GetSectionByType (FfsFile
, EFI_SECTION_PE32
, Index
, &CurrentPe32Section
);
3429 if (EFI_ERROR (Status
)) {
3432 CurSecHdrSize
= GetSectionHeaderLength(CurrentPe32Section
.CommonHeader
);
3435 // Initialize context
3437 memset (&ImageContext
, 0, sizeof (ImageContext
));
3438 ImageContext
.Handle
= (VOID
*) ((UINTN
) CurrentPe32Section
.Pe32Section
+ CurSecHdrSize
);
3439 ImageContext
.ImageRead
= (PE_COFF_LOADER_READ_FILE
) FfsRebaseImageRead
;
3440 Status
= PeCoffLoaderGetImageInfo (&ImageContext
);
3441 if (EFI_ERROR (Status
)) {
3442 Error (NULL
, 0, 3000, "Invalid PeImage", "The input file is %s and the return status is %x", FileName
, (int) Status
);
3446 if ( (ImageContext
.Machine
== EFI_IMAGE_MACHINE_ARMT
) ||
3447 (ImageContext
.Machine
== EFI_IMAGE_MACHINE_AARCH64
) ) {
3452 // Keep Image Context for PE image in FV
3454 memcpy (&OrigImageContext
, &ImageContext
, sizeof (ImageContext
));
3457 // Get File PdbPointer
3459 PdbPointer
= PeCoffLoaderGetPdbPointer (ImageContext
.Handle
);
3462 // Get PeHeader pointer
3464 ImgHdr
= (EFI_IMAGE_OPTIONAL_HEADER_UNION
*)((UINTN
) CurrentPe32Section
.Pe32Section
+ CurSecHdrSize
+ ImageContext
.PeCoffHeaderOffset
);
3467 // Calculate the PE32 base address, based on file type
3469 switch (FfsFile
->Type
) {
3470 case EFI_FV_FILETYPE_SECURITY_CORE
:
3471 case EFI_FV_FILETYPE_PEI_CORE
:
3472 case EFI_FV_FILETYPE_PEIM
:
3473 case EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER
:
3475 // Check if section-alignment and file-alignment match or not
3477 if ((ImgHdr
->Pe32
.OptionalHeader
.SectionAlignment
!= ImgHdr
->Pe32
.OptionalHeader
.FileAlignment
)) {
3479 // Xip module has the same section alignment and file alignment.
3481 Error (NULL
, 0, 3000, "Invalid", "PE image Section-Alignment and File-Alignment do not match : %s.", FileName
);
3485 // PeImage has no reloc section. It will try to get reloc data from the original EFI image.
3487 if (ImageContext
.RelocationsStripped
) {
3489 // Construct the original efi file Name
3491 if (strlen (FileName
) >= MAX_LONG_FILE_PATH
) {
3492 Error (NULL
, 0, 2000, "Invalid", "The file name %s is too long.", FileName
);
3495 strncpy (PeFileName
, FileName
, MAX_LONG_FILE_PATH
- 1);
3496 PeFileName
[MAX_LONG_FILE_PATH
- 1] = 0;
3497 Cptr
= PeFileName
+ strlen (PeFileName
);
3498 while (*Cptr
!= '.') {
3502 Error (NULL
, 0, 3000, "Invalid", "The file %s has no .reloc section.", FileName
);
3510 PeFile
= fopen (LongFilePath (PeFileName
), "rb");
3511 if (PeFile
== NULL
) {
3512 Warning (NULL
, 0, 0, "Invalid", "The file %s has no .reloc section.", FileName
);
3513 //Error (NULL, 0, 3000, "Invalid", "The file %s has no .reloc section.", FileName);
3514 //return EFI_ABORTED;
3518 // Get the file size
3520 PeFileSize
= _filelength (fileno (PeFile
));
3521 PeFileBuffer
= (UINT8
*) malloc (PeFileSize
);
3522 if (PeFileBuffer
== NULL
) {
3524 Error (NULL
, 0, 4001, "Resource", "memory cannot be allocated on rebase of %s", FileName
);
3525 return EFI_OUT_OF_RESOURCES
;
3530 fread (PeFileBuffer
, sizeof (UINT8
), PeFileSize
, PeFile
);
3536 // Handle pointer to the original efi image.
3538 ImageContext
.Handle
= PeFileBuffer
;
3539 Status
= PeCoffLoaderGetImageInfo (&ImageContext
);
3540 if (EFI_ERROR (Status
)) {
3541 Error (NULL
, 0, 3000, "Invalid PeImage", "The input file is %s and the return status is %x", FileName
, (int) Status
);
3544 ImageContext
.RelocationsStripped
= FALSE
;
3547 NewPe32BaseAddress
= XipBase
+ (UINTN
) CurrentPe32Section
.Pe32Section
+ CurSecHdrSize
- (UINTN
)FfsFile
;
3550 case EFI_FV_FILETYPE_DRIVER
:
3551 case EFI_FV_FILETYPE_DXE_CORE
:
3553 // Check if section-alignment and file-alignment match or not
3555 if ((ImgHdr
->Pe32
.OptionalHeader
.SectionAlignment
!= ImgHdr
->Pe32
.OptionalHeader
.FileAlignment
)) {
3557 // Xip module has the same section alignment and file alignment.
3559 Error (NULL
, 0, 3000, "Invalid", "PE image Section-Alignment and File-Alignment do not match : %s.", FileName
);
3562 NewPe32BaseAddress
= XipBase
+ (UINTN
) CurrentPe32Section
.Pe32Section
+ CurSecHdrSize
- (UINTN
)FfsFile
;
3567 // Not supported file type
3573 // Relocation doesn't exist
3575 if (ImageContext
.RelocationsStripped
) {
3576 Warning (NULL
, 0, 0, "Invalid", "The file %s has no .reloc section.", FileName
);
3581 // Relocation exist and rebase
3584 // Load and Relocate Image Data
3586 MemoryImagePointer
= (UINT8
*) malloc ((UINTN
) ImageContext
.ImageSize
+ ImageContext
.SectionAlignment
);
3587 if (MemoryImagePointer
== NULL
) {
3588 Error (NULL
, 0, 4001, "Resource", "memory cannot be allocated on rebase of %s", FileName
);
3589 return EFI_OUT_OF_RESOURCES
;
3591 memset ((VOID
*) MemoryImagePointer
, 0, (UINTN
) ImageContext
.ImageSize
+ ImageContext
.SectionAlignment
);
3592 ImageContext
.ImageAddress
= ((UINTN
) MemoryImagePointer
+ ImageContext
.SectionAlignment
- 1) & (~((UINTN
) ImageContext
.SectionAlignment
- 1));
3594 Status
= PeCoffLoaderLoadImage (&ImageContext
);
3595 if (EFI_ERROR (Status
)) {
3596 Error (NULL
, 0, 3000, "Invalid", "LocateImage() call failed on rebase of %s", FileName
);
3597 free ((VOID
*) MemoryImagePointer
);
3601 ImageContext
.DestinationAddress
= NewPe32BaseAddress
;
3602 Status
= PeCoffLoaderRelocateImage (&ImageContext
);
3603 if (EFI_ERROR (Status
)) {
3604 Error (NULL
, 0, 3000, "Invalid", "RelocateImage() call failed on rebase of %s", FileName
);
3605 free ((VOID
*) MemoryImagePointer
);
3610 // Copy Relocated data to raw image file.
3612 SectionHeader
= (EFI_IMAGE_SECTION_HEADER
*) (
3615 sizeof (EFI_IMAGE_FILE_HEADER
) +
3616 ImgHdr
->Pe32
.FileHeader
.SizeOfOptionalHeader
3619 for (Index
= 0; Index
< ImgHdr
->Pe32
.FileHeader
.NumberOfSections
; Index
++, SectionHeader
++) {
3621 (UINT8
*) CurrentPe32Section
.Pe32Section
+ CurSecHdrSize
+ SectionHeader
->PointerToRawData
,
3622 (VOID
*) (UINTN
) (ImageContext
.ImageAddress
+ SectionHeader
->VirtualAddress
),
3623 SectionHeader
->SizeOfRawData
3627 free ((VOID
*) MemoryImagePointer
);
3628 MemoryImagePointer
= NULL
;
3629 if (PeFileBuffer
!= NULL
) {
3630 free (PeFileBuffer
);
3631 PeFileBuffer
= NULL
;
3635 // Update Image Base Address
3637 if (ImgHdr
->Pe32
.OptionalHeader
.Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
3638 ImgHdr
->Pe32
.OptionalHeader
.ImageBase
= (UINT32
) NewPe32BaseAddress
;
3639 } else if (ImgHdr
->Pe32Plus
.OptionalHeader
.Magic
== EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC
) {
3640 ImgHdr
->Pe32Plus
.OptionalHeader
.ImageBase
= NewPe32BaseAddress
;
3642 Error (NULL
, 0, 3000, "Invalid", "unknown PE magic signature %X in PE32 image %s",
3643 ImgHdr
->Pe32
.OptionalHeader
.Magic
,
3650 // Now update file checksum
3652 if (FfsFile
->Attributes
& FFS_ATTRIB_CHECKSUM
) {
3653 SavedState
= FfsFile
->State
;
3654 FfsFile
->IntegrityCheck
.Checksum
.File
= 0;
3656 FfsFile
->IntegrityCheck
.Checksum
.File
= CalculateChecksum8 (
3657 (UINT8
*) ((UINT8
*)FfsFile
+ FfsHeaderSize
),
3658 GetFfsFileLength (FfsFile
) - FfsHeaderSize
3660 FfsFile
->State
= SavedState
;
3664 // Get this module function address from ModulePeMapFile and add them into FvMap file
3668 // Default use FileName as map file path
3670 if (PdbPointer
== NULL
) {
3671 PdbPointer
= FileName
;
3674 WriteMapFile (FvMapFile
, PdbPointer
, FfsFile
, NewPe32BaseAddress
, &OrigImageContext
);
3677 if (FfsFile
->Type
!= EFI_FV_FILETYPE_SECURITY_CORE
&&
3678 FfsFile
->Type
!= EFI_FV_FILETYPE_PEI_CORE
&&
3679 FfsFile
->Type
!= EFI_FV_FILETYPE_PEIM
&&
3680 FfsFile
->Type
!= EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER
&&
3681 FfsFile
->Type
!= EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE
3684 // Only Peim code may have a TE section
3690 // Now process TE sections
3692 for (Index
= 1;; Index
++) {
3693 NewPe32BaseAddress
= 0;
3698 Status
= GetSectionByType (FfsFile
, EFI_SECTION_TE
, Index
, &CurrentPe32Section
);
3699 if (EFI_ERROR (Status
)) {
3703 CurSecHdrSize
= GetSectionHeaderLength(CurrentPe32Section
.CommonHeader
);
3706 // Calculate the TE base address, the FFS file base plus the offset of the TE section less the size stripped off
3709 TEImageHeader
= (EFI_TE_IMAGE_HEADER
*) ((UINT8
*) CurrentPe32Section
.Pe32Section
+ CurSecHdrSize
);
3712 // Initialize context, load image info.
3714 memset (&ImageContext
, 0, sizeof (ImageContext
));
3715 ImageContext
.Handle
= (VOID
*) TEImageHeader
;
3716 ImageContext
.ImageRead
= (PE_COFF_LOADER_READ_FILE
) FfsRebaseImageRead
;
3717 Status
= PeCoffLoaderGetImageInfo (&ImageContext
);
3718 if (EFI_ERROR (Status
)) {
3719 Error (NULL
, 0, 3000, "Invalid TeImage", "The input file is %s and the return status is %x", FileName
, (int) Status
);
3723 if ( (ImageContext
.Machine
== EFI_IMAGE_MACHINE_ARMT
) ||
3724 (ImageContext
.Machine
== EFI_IMAGE_MACHINE_AARCH64
) ) {
3729 // Keep Image Context for TE image in FV
3731 memcpy (&OrigImageContext
, &ImageContext
, sizeof (ImageContext
));
3734 // Get File PdbPointer
3736 PdbPointer
= PeCoffLoaderGetPdbPointer (ImageContext
.Handle
);
3739 // Set new rebased address.
3741 NewPe32BaseAddress
= XipBase
+ (UINTN
) TEImageHeader
+ sizeof (EFI_TE_IMAGE_HEADER
) \
3742 - TEImageHeader
->StrippedSize
- (UINTN
) FfsFile
;
3745 // if reloc is stripped, try to get the original efi image to get reloc info.
3747 if (ImageContext
.RelocationsStripped
) {
3749 // Construct the original efi file name
3751 if (strlen (FileName
) >= MAX_LONG_FILE_PATH
) {
3752 Error (NULL
, 0, 2000, "Invalid", "The file name %s is too long.", FileName
);
3755 strncpy (PeFileName
, FileName
, MAX_LONG_FILE_PATH
- 1);
3756 PeFileName
[MAX_LONG_FILE_PATH
- 1] = 0;
3757 Cptr
= PeFileName
+ strlen (PeFileName
);
3758 while (*Cptr
!= '.') {
3763 Error (NULL
, 0, 3000, "Invalid", "The file %s has no .reloc section.", FileName
);
3772 PeFile
= fopen (LongFilePath (PeFileName
), "rb");
3773 if (PeFile
== NULL
) {
3774 Warning (NULL
, 0, 0, "Invalid", "The file %s has no .reloc section.", FileName
);
3775 //Error (NULL, 0, 3000, "Invalid", "The file %s has no .reloc section.", FileName);
3776 //return EFI_ABORTED;
3779 // Get the file size
3781 PeFileSize
= _filelength (fileno (PeFile
));
3782 PeFileBuffer
= (UINT8
*) malloc (PeFileSize
);
3783 if (PeFileBuffer
== NULL
) {
3785 Error (NULL
, 0, 4001, "Resource", "memory cannot be allocated on rebase of %s", FileName
);
3786 return EFI_OUT_OF_RESOURCES
;
3791 fread (PeFileBuffer
, sizeof (UINT8
), PeFileSize
, PeFile
);
3797 // Append reloc section into TeImage
3799 ImageContext
.Handle
= PeFileBuffer
;
3800 Status
= PeCoffLoaderGetImageInfo (&ImageContext
);
3801 if (EFI_ERROR (Status
)) {
3802 Error (NULL
, 0, 3000, "Invalid TeImage", "The input file is %s and the return status is %x", FileName
, (int) Status
);
3805 ImageContext
.RelocationsStripped
= FALSE
;
3809 // Relocation doesn't exist
3811 if (ImageContext
.RelocationsStripped
) {
3812 Warning (NULL
, 0, 0, "Invalid", "The file %s has no .reloc section.", FileName
);
3817 // Relocation exist and rebase
3820 // Load and Relocate Image Data
3822 MemoryImagePointer
= (UINT8
*) malloc ((UINTN
) ImageContext
.ImageSize
+ ImageContext
.SectionAlignment
);
3823 if (MemoryImagePointer
== NULL
) {
3824 Error (NULL
, 0, 4001, "Resource", "memory cannot be allocated on rebase of %s", FileName
);
3825 return EFI_OUT_OF_RESOURCES
;
3827 memset ((VOID
*) MemoryImagePointer
, 0, (UINTN
) ImageContext
.ImageSize
+ ImageContext
.SectionAlignment
);
3828 ImageContext
.ImageAddress
= ((UINTN
) MemoryImagePointer
+ ImageContext
.SectionAlignment
- 1) & (~((UINTN
) ImageContext
.SectionAlignment
- 1));
3830 Status
= PeCoffLoaderLoadImage (&ImageContext
);
3831 if (EFI_ERROR (Status
)) {
3832 Error (NULL
, 0, 3000, "Invalid", "LocateImage() call failed on rebase of %s", FileName
);
3833 free ((VOID
*) MemoryImagePointer
);
3837 // Reloacate TeImage
3839 ImageContext
.DestinationAddress
= NewPe32BaseAddress
;
3840 Status
= PeCoffLoaderRelocateImage (&ImageContext
);
3841 if (EFI_ERROR (Status
)) {
3842 Error (NULL
, 0, 3000, "Invalid", "RelocateImage() call failed on rebase of TE image %s", FileName
);
3843 free ((VOID
*) MemoryImagePointer
);
3848 // Copy the relocated image into raw image file.
3850 SectionHeader
= (EFI_IMAGE_SECTION_HEADER
*) (TEImageHeader
+ 1);
3851 for (Index
= 0; Index
< TEImageHeader
->NumberOfSections
; Index
++, SectionHeader
++) {
3852 if (!ImageContext
.IsTeImage
) {
3854 (UINT8
*) TEImageHeader
+ sizeof (EFI_TE_IMAGE_HEADER
) - TEImageHeader
->StrippedSize
+ SectionHeader
->PointerToRawData
,
3855 (VOID
*) (UINTN
) (ImageContext
.ImageAddress
+ SectionHeader
->VirtualAddress
),
3856 SectionHeader
->SizeOfRawData
3860 (UINT8
*) TEImageHeader
+ sizeof (EFI_TE_IMAGE_HEADER
) - TEImageHeader
->StrippedSize
+ SectionHeader
->PointerToRawData
,
3861 (VOID
*) (UINTN
) (ImageContext
.ImageAddress
+ sizeof (EFI_TE_IMAGE_HEADER
) - TEImageHeader
->StrippedSize
+ SectionHeader
->VirtualAddress
),
3862 SectionHeader
->SizeOfRawData
3868 // Free the allocated memory resource
3870 free ((VOID
*) MemoryImagePointer
);
3871 MemoryImagePointer
= NULL
;
3872 if (PeFileBuffer
!= NULL
) {
3873 free (PeFileBuffer
);
3874 PeFileBuffer
= NULL
;
3878 // Update Image Base Address
3880 TEImageHeader
->ImageBase
= NewPe32BaseAddress
;
3883 // Now update file checksum
3885 if (FfsFile
->Attributes
& FFS_ATTRIB_CHECKSUM
) {
3886 SavedState
= FfsFile
->State
;
3887 FfsFile
->IntegrityCheck
.Checksum
.File
= 0;
3889 FfsFile
->IntegrityCheck
.Checksum
.File
= CalculateChecksum8 (
3890 (UINT8
*)((UINT8
*)FfsFile
+ FfsHeaderSize
),
3891 GetFfsFileLength (FfsFile
) - FfsHeaderSize
3893 FfsFile
->State
= SavedState
;
3896 // Get this module function address from ModulePeMapFile and add them into FvMap file
3900 // Default use FileName as map file path
3902 if (PdbPointer
== NULL
) {
3903 PdbPointer
= FileName
;
3919 FindApResetVectorPosition (
3920 IN MEMORY_FILE
*FvImage
,
3925 Routine Description:
3927 Find the position in this FvImage to place Ap reset vector.
3931 FvImage Memory file for the FV memory image.
3932 Pointer Pointer to pointer to position.
3936 EFI_NOT_FOUND - No satisfied position is found.
3937 EFI_SUCCESS - The suitable position is return.
3941 EFI_FFS_FILE_HEADER
*PadFile
;
3947 for (Index
= 1; ;Index
++) {
3949 // Find Pad File to add ApResetVector info
3951 Status
= GetFileByType (EFI_FV_FILETYPE_FFS_PAD
, Index
, &PadFile
);
3952 if (EFI_ERROR (Status
) || (PadFile
== NULL
)) {
3954 // No Pad file to be found.
3959 // Get Pad file size.
3961 FileLength
= GetFfsFileLength(PadFile
);
3962 FileLength
= (FileLength
+ EFI_FFS_FILE_HEADER_ALIGNMENT
- 1) & ~(EFI_FFS_FILE_HEADER_ALIGNMENT
- 1);
3964 // FixPoint must be align on 0x1000 relative to FvImage Header
3966 FixPoint
= (UINT8
*) PadFile
+ GetFfsHeaderLength(PadFile
);
3967 FixPoint
= FixPoint
+ 0x1000 - (((UINTN
) FixPoint
- (UINTN
) FvImage
->FileImage
) & 0xFFF);
3969 // FixPoint be larger at the last place of one fv image.
3971 while (((UINTN
) FixPoint
+ SIZEOF_STARTUP_DATA_ARRAY
- (UINTN
) PadFile
) <= FileLength
) {
3976 if ((UINTN
) FixPoint
< ((UINTN
) PadFile
+ GetFfsHeaderLength(PadFile
))) {
3978 // No alignment FixPoint in this Pad File.
3983 if ((UINTN
) FvImage
->Eof
- (UINTN
)FixPoint
<= 0x20000) {
3985 // Find the position to place ApResetVector
3987 *Pointer
= FixPoint
;
3992 return EFI_NOT_FOUND
;
3997 IN MEMORY_FILE
*InfFile
,
3998 OUT CAP_INFO
*CapInfo
4002 Routine Description:
4004 This function parses a Cap.INF file and copies info into a CAP_INFO structure.
4008 InfFile Memory file image.
4009 CapInfo Information read from INF file.
4013 EFI_SUCCESS INF file information successfully retrieved.
4014 EFI_ABORTED INF file has an invalid format.
4015 EFI_NOT_FOUND A required string was not found in the INF file.
4018 CHAR8 Value
[MAX_LONG_FILE_PATH
];
4020 UINTN Index
, Number
;
4024 // Initialize Cap info
4026 // memset (CapInfo, 0, sizeof (CAP_INFO));
4030 // Read the Capsule Guid
4032 Status
= FindToken (InfFile
, OPTIONS_SECTION_STRING
, EFI_CAPSULE_GUID_STRING
, 0, Value
);
4033 if (Status
== EFI_SUCCESS
) {
4035 // Get the Capsule Guid
4037 Status
= StringToGuid (Value
, &CapInfo
->CapGuid
);
4038 if (EFI_ERROR (Status
)) {
4039 Error (NULL
, 0, 2000, "Invalid parameter", "%s = %s", EFI_CAPSULE_GUID_STRING
, Value
);
4042 DebugMsg (NULL
, 0, 9, "Capsule Guid", "%s = %s", EFI_CAPSULE_GUID_STRING
, Value
);
4046 // Read the Capsule Header Size
4048 Status
= FindToken (InfFile
, OPTIONS_SECTION_STRING
, EFI_CAPSULE_HEADER_SIZE_STRING
, 0, Value
);
4049 if (Status
== EFI_SUCCESS
) {
4050 Status
= AsciiStringToUint64 (Value
, FALSE
, &Value64
);
4051 if (EFI_ERROR (Status
)) {
4052 Error (NULL
, 0, 2000, "Invalid parameter", "%s = %s", EFI_CAPSULE_HEADER_SIZE_STRING
, Value
);
4055 CapInfo
->HeaderSize
= (UINT32
) Value64
;
4056 DebugMsg (NULL
, 0, 9, "Capsule Header size", "%s = %s", EFI_CAPSULE_HEADER_SIZE_STRING
, Value
);
4060 // Read the Capsule Flag
4062 Status
= FindToken (InfFile
, OPTIONS_SECTION_STRING
, EFI_CAPSULE_FLAGS_STRING
, 0, Value
);
4063 if (Status
== EFI_SUCCESS
) {
4064 if (strstr (Value
, "PopulateSystemTable") != NULL
) {
4065 CapInfo
->Flags
|= CAPSULE_FLAGS_PERSIST_ACROSS_RESET
| CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE
;
4066 if (strstr (Value
, "InitiateReset") != NULL
) {
4067 CapInfo
->Flags
|= CAPSULE_FLAGS_INITIATE_RESET
;
4069 } else if (strstr (Value
, "PersistAcrossReset") != NULL
) {
4070 CapInfo
->Flags
|= CAPSULE_FLAGS_PERSIST_ACROSS_RESET
;
4071 if (strstr (Value
, "InitiateReset") != NULL
) {
4072 CapInfo
->Flags
|= CAPSULE_FLAGS_INITIATE_RESET
;
4075 Error (NULL
, 0, 2000, "Invalid parameter", "invalid Flag setting for %s.", EFI_CAPSULE_FLAGS_STRING
);
4078 DebugMsg (NULL
, 0, 9, "Capsule Flag", Value
);
4081 Status
= FindToken (InfFile
, OPTIONS_SECTION_STRING
, EFI_OEM_CAPSULE_FLAGS_STRING
, 0, Value
);
4082 if (Status
== EFI_SUCCESS
) {
4083 Status
= AsciiStringToUint64 (Value
, FALSE
, &Value64
);
4084 if (EFI_ERROR (Status
) || Value64
> 0xffff) {
4085 Error (NULL
, 0, 2000, "Invalid parameter",
4086 "invalid Flag setting for %s. Must be integer value between 0x0000 and 0xffff.",
4087 EFI_OEM_CAPSULE_FLAGS_STRING
);
4090 CapInfo
->Flags
|= Value64
;
4091 DebugMsg (NULL
, 0, 9, "Capsule Extend Flag", Value
);
4095 // Read Capsule File name
4097 Status
= FindToken (InfFile
, OPTIONS_SECTION_STRING
, EFI_FILE_NAME_STRING
, 0, Value
);
4098 if (Status
== EFI_SUCCESS
) {
4100 // Get output file name
4102 strcpy (CapInfo
->CapName
, Value
);
4106 // Read the Capsule FileImage
4109 for (Index
= 0; Index
< MAX_NUMBER_OF_FILES_IN_CAP
; Index
++) {
4110 if (CapInfo
->CapFiles
[Index
][0] != '\0') {
4114 // Read the capsule file name
4116 Status
= FindToken (InfFile
, FILES_SECTION_STRING
, EFI_FILE_NAME_STRING
, Number
++, Value
);
4118 if (Status
== EFI_SUCCESS
) {
4122 strcpy (CapInfo
->CapFiles
[Index
], Value
);
4123 DebugMsg (NULL
, 0, 9, "Capsule component file", "the %uth file name is %s", (unsigned) Index
, CapInfo
->CapFiles
[Index
]);
4130 Warning (NULL
, 0, 0, "Capsule components are not specified.", NULL
);
4138 IN CHAR8
*InfFileImage
,
4139 IN UINTN InfFileSize
,
4140 IN CHAR8
*CapFileName
4144 Routine Description:
4146 This is the main function which will be called from application to create UEFI Capsule image.
4150 InfFileImage Buffer containing the INF file contents.
4151 InfFileSize Size of the contents of the InfFileImage buffer.
4152 CapFileName Requested name for the Cap file.
4156 EFI_SUCCESS Function completed successfully.
4157 EFI_OUT_OF_RESOURCES Could not allocate required resources.
4158 EFI_ABORTED Error encountered.
4159 EFI_INVALID_PARAMETER A required parameter was NULL.
4165 EFI_CAPSULE_HEADER
*CapsuleHeader
;
4166 MEMORY_FILE InfMemoryFile
;
4172 if (InfFileImage
!= NULL
) {
4174 // Initialize file structures
4176 InfMemoryFile
.FileImage
= InfFileImage
;
4177 InfMemoryFile
.CurrentFilePointer
= InfFileImage
;
4178 InfMemoryFile
.Eof
= InfFileImage
+ InfFileSize
;
4181 // Parse the Cap inf file for header information
4183 Status
= ParseCapInf (&InfMemoryFile
, &mCapDataInfo
);
4184 if (Status
!= EFI_SUCCESS
) {
4189 if (mCapDataInfo
.HeaderSize
== 0) {
4191 // make header size align 16 bytes.
4193 mCapDataInfo
.HeaderSize
= sizeof (EFI_CAPSULE_HEADER
);
4194 mCapDataInfo
.HeaderSize
= (mCapDataInfo
.HeaderSize
+ 0xF) & ~0xF;
4197 if (mCapDataInfo
.HeaderSize
< sizeof (EFI_CAPSULE_HEADER
)) {
4198 Error (NULL
, 0, 2000, "Invalid parameter", "The specified HeaderSize cannot be less than the size of EFI_CAPSULE_HEADER.");
4199 return EFI_INVALID_PARAMETER
;
4202 if (CapFileName
== NULL
&& mCapDataInfo
.CapName
[0] != '\0') {
4203 CapFileName
= mCapDataInfo
.CapName
;
4206 if (CapFileName
== NULL
) {
4207 Error (NULL
, 0, 2001, "Missing required argument", "Output Capsule file name");
4208 return EFI_INVALID_PARAMETER
;
4212 // Set Default Capsule Guid value
4214 if (CompareGuid (&mCapDataInfo
.CapGuid
, &mZeroGuid
) == 0) {
4215 memcpy (&mCapDataInfo
.CapGuid
, &mDefaultCapsuleGuid
, sizeof (EFI_GUID
));
4218 // Calculate the size of capsule image.
4222 CapSize
= mCapDataInfo
.HeaderSize
;
4223 while (mCapDataInfo
.CapFiles
[Index
][0] != '\0') {
4224 fpin
= fopen (LongFilePath (mCapDataInfo
.CapFiles
[Index
]), "rb");
4226 Error (NULL
, 0, 0001, "Error opening file", mCapDataInfo
.CapFiles
[Index
]);
4229 FileSize
= _filelength (fileno (fpin
));
4230 CapSize
+= FileSize
;
4236 // Allocate buffer for capsule image.
4238 CapBuffer
= (UINT8
*) malloc (CapSize
);
4239 if (CapBuffer
== NULL
) {
4240 Error (NULL
, 0, 4001, "Resource", "memory cannot be allocated for creating the capsule.");
4241 return EFI_OUT_OF_RESOURCES
;
4245 // Initialize the capsule header to zero
4247 memset (CapBuffer
, 0, mCapDataInfo
.HeaderSize
);
4250 // create capsule header and get capsule body
4252 CapsuleHeader
= (EFI_CAPSULE_HEADER
*) CapBuffer
;
4253 memcpy (&CapsuleHeader
->CapsuleGuid
, &mCapDataInfo
.CapGuid
, sizeof (EFI_GUID
));
4254 CapsuleHeader
->HeaderSize
= mCapDataInfo
.HeaderSize
;
4255 CapsuleHeader
->Flags
= mCapDataInfo
.Flags
;
4256 CapsuleHeader
->CapsuleImageSize
= CapSize
;
4260 CapSize
= CapsuleHeader
->HeaderSize
;
4261 while (mCapDataInfo
.CapFiles
[Index
][0] != '\0') {
4262 fpin
= fopen (LongFilePath (mCapDataInfo
.CapFiles
[Index
]), "rb");
4264 Error (NULL
, 0, 0001, "Error opening file", mCapDataInfo
.CapFiles
[Index
]);
4268 FileSize
= _filelength (fileno (fpin
));
4269 fread (CapBuffer
+ CapSize
, 1, FileSize
, fpin
);
4272 CapSize
+= FileSize
;
4276 // write capsule data into the output file
4278 fpout
= fopen (LongFilePath (CapFileName
), "wb");
4279 if (fpout
== NULL
) {
4280 Error (NULL
, 0, 0001, "Error opening file", CapFileName
);
4285 fwrite (CapBuffer
, 1, CapSize
, fpout
);
4289 VerboseMsg ("The size of the generated capsule image is %u bytes", (unsigned) CapSize
);