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 Portions Copyright (c) 2020, Hewlett Packard Enterprise Development LP. All rights reserved.<BR>
8 SPDX-License-Identifier: BSD-2-Clause-Patent
16 #if defined(__FreeBSD__)
18 #elif defined(__GNUC__)
19 #include <uuid/uuid.h>
30 #include <Guid/FfsSectionAlignmentPadding.h>
32 #include "WinNtInclude.h"
33 #include "GenFvInternalLib.h"
35 #include "PeCoffLib.h"
37 #define ARMT_UNCONDITIONAL_JUMP_INSTRUCTION 0xEB000000
38 #define ARM64_UNCONDITIONAL_JUMP_INSTRUCTION 0x14000000
41 BOOLEAN mRiscV
= FALSE
;
42 STATIC UINT32 MaxFfsAlignment
= 0;
43 BOOLEAN VtfFileFlag
= FALSE
;
45 EFI_GUID mEfiFirmwareVolumeTopFileGuid
= EFI_FFS_VOLUME_TOP_FILE_GUID
;
46 EFI_GUID mFileGuidArray
[MAX_NUMBER_OF_FILES_IN_FV
];
47 EFI_GUID mZeroGuid
= {0x0, 0x0, 0x0, {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}};
48 EFI_GUID mDefaultCapsuleGuid
= {0x3B6686BD, 0x0D76, 0x4030, { 0xB7, 0x0E, 0xB5, 0x51, 0x9E, 0x2F, 0xC5, 0xA0 }};
49 EFI_GUID mEfiFfsSectionAlignmentPaddingGuid
= EFI_FFS_SECTION_ALIGNMENT_PADDING_GUID
;
51 CHAR8
*mFvbAttributeName
[] = {
52 EFI_FVB2_READ_DISABLED_CAP_STRING
,
53 EFI_FVB2_READ_ENABLED_CAP_STRING
,
54 EFI_FVB2_READ_STATUS_STRING
,
55 EFI_FVB2_WRITE_DISABLED_CAP_STRING
,
56 EFI_FVB2_WRITE_ENABLED_CAP_STRING
,
57 EFI_FVB2_WRITE_STATUS_STRING
,
58 EFI_FVB2_LOCK_CAP_STRING
,
59 EFI_FVB2_LOCK_STATUS_STRING
,
61 EFI_FVB2_STICKY_WRITE_STRING
,
62 EFI_FVB2_MEMORY_MAPPED_STRING
,
63 EFI_FVB2_ERASE_POLARITY_STRING
,
64 EFI_FVB2_READ_LOCK_CAP_STRING
,
65 EFI_FVB2_READ_LOCK_STATUS_STRING
,
66 EFI_FVB2_WRITE_LOCK_CAP_STRING
,
67 EFI_FVB2_WRITE_LOCK_STATUS_STRING
70 CHAR8
*mFvbAlignmentName
[] = {
71 EFI_FVB2_ALIGNMENT_1_STRING
,
72 EFI_FVB2_ALIGNMENT_2_STRING
,
73 EFI_FVB2_ALIGNMENT_4_STRING
,
74 EFI_FVB2_ALIGNMENT_8_STRING
,
75 EFI_FVB2_ALIGNMENT_16_STRING
,
76 EFI_FVB2_ALIGNMENT_32_STRING
,
77 EFI_FVB2_ALIGNMENT_64_STRING
,
78 EFI_FVB2_ALIGNMENT_128_STRING
,
79 EFI_FVB2_ALIGNMENT_256_STRING
,
80 EFI_FVB2_ALIGNMENT_512_STRING
,
81 EFI_FVB2_ALIGNMENT_1K_STRING
,
82 EFI_FVB2_ALIGNMENT_2K_STRING
,
83 EFI_FVB2_ALIGNMENT_4K_STRING
,
84 EFI_FVB2_ALIGNMENT_8K_STRING
,
85 EFI_FVB2_ALIGNMENT_16K_STRING
,
86 EFI_FVB2_ALIGNMENT_32K_STRING
,
87 EFI_FVB2_ALIGNMENT_64K_STRING
,
88 EFI_FVB2_ALIGNMENT_128K_STRING
,
89 EFI_FVB2_ALIGNMENT_256K_STRING
,
90 EFI_FVB2_ALIGNMENT_512K_STRING
,
91 EFI_FVB2_ALIGNMENT_1M_STRING
,
92 EFI_FVB2_ALIGNMENT_2M_STRING
,
93 EFI_FVB2_ALIGNMENT_4M_STRING
,
94 EFI_FVB2_ALIGNMENT_8M_STRING
,
95 EFI_FVB2_ALIGNMENT_16M_STRING
,
96 EFI_FVB2_ALIGNMENT_32M_STRING
,
97 EFI_FVB2_ALIGNMENT_64M_STRING
,
98 EFI_FVB2_ALIGNMENT_128M_STRING
,
99 EFI_FVB2_ALIGNMENT_256M_STRING
,
100 EFI_FVB2_ALIGNMENT_512M_STRING
,
101 EFI_FVB2_ALIGNMENT_1G_STRING
,
102 EFI_FVB2_ALIGNMENT_2G_STRING
106 // This data array will be located at the base of the Firmware Volume Header (FVH)
107 // in the boot block. It must not exceed 14 bytes of code. The last 2 bytes
108 // will be used to keep the FVH checksum consistent.
109 // This code will be run in response to a startup IPI for HT-enabled systems.
111 #define SIZEOF_STARTUP_DATA_ARRAY 0x10
113 UINT8 m128kRecoveryStartupApDataArray
[SIZEOF_STARTUP_DATA_ARRAY
] = {
115 // EA D0 FF 00 F0 ; far jmp F000:FFD0
116 // 0, 0, 0, 0, 0, 0, 0, 0, 0, ; Reserved bytes
117 // 0, 0 ; Checksum Padding
137 UINT8 m64kRecoveryStartupApDataArray
[SIZEOF_STARTUP_DATA_ARRAY
] = {
139 // EB CE ; jmp short ($-0x30)
140 // ; (from offset 0x0 to offset 0xFFD0)
141 // 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ; Reserved bytes
142 // 0, 0 ; Checksum Padding
163 CAP_INFO mCapDataInfo
;
164 BOOLEAN mIsLargeFfs
= FALSE
;
166 EFI_PHYSICAL_ADDRESS mFvBaseAddress
[0x10];
167 UINT32 mFvBaseAddressNumber
= 0;
171 IN MEMORY_FILE
*InfFile
,
178 This function parses a FV.INF file and copies info into a FV_INFO structure.
182 InfFile Memory file image.
183 FvInfo Information read from INF file.
187 EFI_SUCCESS INF file information successfully retrieved.
188 EFI_ABORTED INF file has an invalid format.
189 EFI_NOT_FOUND A required string was not found in the INF file.
192 CHAR8 Value
[MAX_LONG_FILE_PATH
];
200 // Read the FV base address
202 if (!mFvDataInfo
.BaseAddressSet
) {
203 Status
= FindToken (InfFile
, OPTIONS_SECTION_STRING
, EFI_FV_BASE_ADDRESS_STRING
, 0, Value
);
204 if (Status
== EFI_SUCCESS
) {
206 // Get the base address
208 Status
= AsciiStringToUint64 (Value
, FALSE
, &Value64
);
209 if (EFI_ERROR (Status
)) {
210 Error (NULL
, 0, 2000, "Invalid parameter", "%s = %s", EFI_FV_BASE_ADDRESS_STRING
, Value
);
213 DebugMsg (NULL
, 0, 9, "rebase address", "%s = %s", EFI_FV_BASE_ADDRESS_STRING
, Value
);
215 FvInfo
->BaseAddress
= Value64
;
216 FvInfo
->BaseAddressSet
= TRUE
;
221 // Read the FV File System Guid
223 if (!FvInfo
->FvFileSystemGuidSet
) {
224 Status
= FindToken (InfFile
, OPTIONS_SECTION_STRING
, EFI_FV_FILESYSTEMGUID_STRING
, 0, Value
);
225 if (Status
== EFI_SUCCESS
) {
227 // Get the guid value
229 Status
= StringToGuid (Value
, &GuidValue
);
230 if (EFI_ERROR (Status
)) {
231 Error (NULL
, 0, 2000, "Invalid parameter", "%s = %s", EFI_FV_FILESYSTEMGUID_STRING
, Value
);
234 memcpy (&FvInfo
->FvFileSystemGuid
, &GuidValue
, sizeof (EFI_GUID
));
235 FvInfo
->FvFileSystemGuidSet
= TRUE
;
240 // Read the FV Extension Header File Name
242 Status
= FindToken (InfFile
, ATTRIBUTES_SECTION_STRING
, EFI_FV_EXT_HEADER_FILE_NAME
, 0, Value
);
243 if (Status
== EFI_SUCCESS
) {
244 strcpy (FvInfo
->FvExtHeaderFile
, Value
);
248 // Read the FV file name
250 Status
= FindToken (InfFile
, OPTIONS_SECTION_STRING
, EFI_FV_FILE_NAME_STRING
, 0, Value
);
251 if (Status
== EFI_SUCCESS
) {
253 // copy the file name
255 strcpy (FvInfo
->FvName
, Value
);
261 for (Index
= 0; Index
< sizeof (mFvbAttributeName
)/sizeof (CHAR8
*); Index
++) {
262 if ((mFvbAttributeName
[Index
] != NULL
) && \
263 (FindToken (InfFile
, ATTRIBUTES_SECTION_STRING
, mFvbAttributeName
[Index
], 0, Value
) == EFI_SUCCESS
)) {
264 if ((strcmp (Value
, TRUE_STRING
) == 0) || (strcmp (Value
, ONE_STRING
) == 0)) {
265 FvInfo
->FvAttributes
|= 1 << Index
;
266 } else if ((strcmp (Value
, FALSE_STRING
) != 0) && (strcmp (Value
, ZERO_STRING
) != 0)) {
267 Error (NULL
, 0, 2000, "Invalid parameter", "%s expected %s | %s", mFvbAttributeName
[Index
], TRUE_STRING
, FALSE_STRING
);
276 for (Index
= 0; Index
< sizeof (mFvbAlignmentName
)/sizeof (CHAR8
*); Index
++) {
277 if (FindToken (InfFile
, ATTRIBUTES_SECTION_STRING
, mFvbAlignmentName
[Index
], 0, Value
) == EFI_SUCCESS
) {
278 if (strcmp (Value
, TRUE_STRING
) == 0) {
279 FvInfo
->FvAttributes
|= Index
<< 16;
280 DebugMsg (NULL
, 0, 9, "FV file alignment", "Align = %s", mFvbAlignmentName
[Index
]);
287 // Read weak alignment flag
289 Status
= FindToken (InfFile
, ATTRIBUTES_SECTION_STRING
, EFI_FV_WEAK_ALIGNMENT_STRING
, 0, Value
);
290 if (Status
== EFI_SUCCESS
) {
291 if ((strcmp (Value
, TRUE_STRING
) == 0) || (strcmp (Value
, ONE_STRING
) == 0)) {
292 FvInfo
->FvAttributes
|= EFI_FVB2_WEAK_ALIGNMENT
;
293 } else if ((strcmp (Value
, FALSE_STRING
) != 0) && (strcmp (Value
, ZERO_STRING
) != 0)) {
294 Error (NULL
, 0, 2000, "Invalid parameter", "Weak alignment value expected one of TRUE, FALSE, 1 or 0.");
302 for (Index
= 0; Index
< MAX_NUMBER_OF_FV_BLOCKS
; Index
++) {
303 if (FvInfo
->FvBlocks
[Index
].Length
== 0) {
307 Status
= FindToken (InfFile
, OPTIONS_SECTION_STRING
, EFI_BLOCK_SIZE_STRING
, Index
, Value
);
309 if (Status
== EFI_SUCCESS
) {
311 // Update the size of block
313 Status
= AsciiStringToUint64 (Value
, FALSE
, &Value64
);
314 if (EFI_ERROR (Status
)) {
315 Error (NULL
, 0, 2000, "Invalid parameter", "%s = %s", EFI_BLOCK_SIZE_STRING
, Value
);
319 FvInfo
->FvBlocks
[Index
].Length
= (UINT32
) Value64
;
320 DebugMsg (NULL
, 0, 9, "FV Block Size", "%s = %s", EFI_BLOCK_SIZE_STRING
, Value
);
323 // If there is no blocks size, but there is the number of block, then we have a mismatched pair
324 // and should return an error.
326 Status
= FindToken (InfFile
, OPTIONS_SECTION_STRING
, EFI_NUM_BLOCKS_STRING
, Index
, Value
);
327 if (!EFI_ERROR (Status
)) {
328 Error (NULL
, 0, 2000, "Invalid parameter", "both %s and %s must be specified.", EFI_NUM_BLOCKS_STRING
, EFI_BLOCK_SIZE_STRING
);
339 // Read blocks number
341 Status
= FindToken (InfFile
, OPTIONS_SECTION_STRING
, EFI_NUM_BLOCKS_STRING
, Index
, Value
);
343 if (Status
== EFI_SUCCESS
) {
345 // Update the number of blocks
347 Status
= AsciiStringToUint64 (Value
, FALSE
, &Value64
);
348 if (EFI_ERROR (Status
)) {
349 Error (NULL
, 0, 2000, "Invalid parameter", "%s = %s", EFI_NUM_BLOCKS_STRING
, Value
);
353 FvInfo
->FvBlocks
[Index
].NumBlocks
= (UINT32
) Value64
;
354 DebugMsg (NULL
, 0, 9, "FV Block Number", "%s = %s", EFI_NUM_BLOCKS_STRING
, Value
);
360 Error (NULL
, 0, 2001, "Missing required argument", "block size.");
368 for (Number
= 0; Number
< MAX_NUMBER_OF_FILES_IN_FV
; Number
++) {
369 if (FvInfo
->FvFiles
[Number
][0] == '\0') {
374 for (Index
= 0; Number
+ Index
< MAX_NUMBER_OF_FILES_IN_FV
; Index
++) {
376 // Read the FFS file list
378 Status
= FindToken (InfFile
, FILES_SECTION_STRING
, EFI_FILE_NAME_STRING
, Index
, Value
);
380 if (Status
== EFI_SUCCESS
) {
384 strcpy (FvInfo
->FvFiles
[Number
+ Index
], Value
);
385 DebugMsg (NULL
, 0, 9, "FV component file", "the %uth name is %s", (unsigned) Index
, Value
);
391 if ((Index
+ Number
) == 0) {
392 Warning (NULL
, 0, 0, "FV components are not specified.", NULL
);
400 IN EFI_FFS_FILE_HEADER
*FfsFile
,
401 IN EFI_FIRMWARE_VOLUME_HEADER
*FvHeader
407 This function changes the FFS file attributes based on the erase polarity
408 of the FV. Update the reserved bits of State to EFI_FVB2_ERASE_POLARITY.
421 if (FvHeader
->Attributes
& EFI_FVB2_ERASE_POLARITY
) {
422 FfsFile
->State
= (UINT8
)~(FfsFile
->State
);
423 // FfsFile->State |= ~(UINT8) EFI_FILE_ALL_STATE_BITS;
429 IN EFI_FFS_FILE_HEADER
*FfsFile
,
430 IN OUT UINT32
*Alignment
436 This function determines the alignment of the FFS input file from the file
441 FfsFile FFS file to parse
442 Alignment The minimum required alignment offset of the FFS file
446 EFI_SUCCESS The function completed successfully.
447 EFI_INVALID_PARAMETER One of the input parameters was invalid.
448 EFI_ABORTED An error occurred.
453 // Verify input parameters.
455 if (FfsFile
== NULL
|| Alignment
== NULL
) {
456 return EFI_INVALID_PARAMETER
;
459 switch ((FfsFile
->Attributes
>> 3) & 0x07) {
464 //if bit 1 have set, 128K byte alignment
466 if (FfsFile
->Attributes
& FFS_ATTRIB_DATA_ALIGNMENT2
) {
476 //if bit 1 have set, 256K byte alignment
478 if (FfsFile
->Attributes
& FFS_ATTRIB_DATA_ALIGNMENT2
) {
487 // 128 byte alignment
488 //if bit 1 have set, 512K byte alignment
490 if (FfsFile
->Attributes
& FFS_ATTRIB_DATA_ALIGNMENT2
) {
499 // 512 byte alignment
500 //if bit 1 have set, 1M byte alignment
502 if (FfsFile
->Attributes
& FFS_ATTRIB_DATA_ALIGNMENT2
) {
512 //if bit 1 have set, 2M byte alignment
514 if (FfsFile
->Attributes
& FFS_ATTRIB_DATA_ALIGNMENT2
) {
524 //if bit 1 have set, 4M byte alignment
526 if (FfsFile
->Attributes
& FFS_ATTRIB_DATA_ALIGNMENT2
) {
535 // 32K byte alignment
536 //if bit 1 have set , 8M byte alignment
538 if (FfsFile
->Attributes
& FFS_ATTRIB_DATA_ALIGNMENT2
) {
547 // 64K byte alignment
548 //if bit 1 have set, 16M alignment
550 if (FfsFile
->Attributes
& FFS_ATTRIB_DATA_ALIGNMENT2
) {
566 IN OUT MEMORY_FILE
*FvImage
,
567 IN UINT32 DataAlignment
,
569 IN EFI_FIRMWARE_VOLUME_EXT_HEADER
*ExtHeader
,
570 IN UINT32 NextFfsSize
576 This function adds a pad file to the FV image if it required to align the
577 data of the next file.
581 FvImage The memory image of the FV to add it to.
582 The current offset must be valid.
583 DataAlignment The data alignment of the next FFS file.
584 FvEnd End of the empty data in FvImage.
585 ExtHeader PI FvExtHeader Optional
589 EFI_SUCCESS The function completed successfully.
590 EFI_INVALID_PARAMETER One of the input parameters was invalid.
591 EFI_OUT_OF_RESOURCES Insufficient resources exist in the FV to complete
596 EFI_FFS_FILE_HEADER
*PadFile
;
598 UINT32 NextFfsHeaderSize
;
599 UINT32 CurFfsHeaderSize
;
603 CurFfsHeaderSize
= sizeof (EFI_FFS_FILE_HEADER
);
605 // Verify input parameters.
607 if (FvImage
== NULL
) {
608 return EFI_INVALID_PARAMETER
;
612 // Calculate the pad file size
616 // Append extension header size
618 if (ExtHeader
!= NULL
) {
619 PadFileSize
= ExtHeader
->ExtHeaderSize
;
620 if (PadFileSize
+ sizeof (EFI_FFS_FILE_HEADER
) >= MAX_FFS_SIZE
) {
621 CurFfsHeaderSize
= sizeof (EFI_FFS_FILE_HEADER2
);
623 PadFileSize
+= CurFfsHeaderSize
;
625 NextFfsHeaderSize
= sizeof (EFI_FFS_FILE_HEADER
);
626 if (NextFfsSize
>= MAX_FFS_SIZE
) {
627 NextFfsHeaderSize
= sizeof (EFI_FFS_FILE_HEADER2
);
630 // Check if a pad file is necessary
632 if (((UINTN
) FvImage
->CurrentFilePointer
- (UINTN
) FvImage
->FileImage
+ NextFfsHeaderSize
) % DataAlignment
== 0) {
635 PadFileSize
= (UINTN
) FvImage
->CurrentFilePointer
- (UINTN
) FvImage
->FileImage
+ sizeof (EFI_FFS_FILE_HEADER
) + NextFfsHeaderSize
;
637 // Add whatever it takes to get to the next aligned address
639 while ((PadFileSize
% DataAlignment
) != 0) {
643 // Subtract the next file header size
645 PadFileSize
-= NextFfsHeaderSize
;
647 // Subtract the starting offset to get size
649 PadFileSize
-= (UINTN
) FvImage
->CurrentFilePointer
- (UINTN
) FvImage
->FileImage
;
653 // Verify that we have enough space for the file header
655 if (((UINTN
) FvImage
->CurrentFilePointer
+ PadFileSize
) > (UINTN
) FvEnd
) {
656 return EFI_OUT_OF_RESOURCES
;
660 // Write pad file header
662 PadFile
= (EFI_FFS_FILE_HEADER
*) FvImage
->CurrentFilePointer
;
665 // Write PadFile FFS header with PadType, don't need to set PAD file guid in its header.
667 PadFile
->Type
= EFI_FV_FILETYPE_FFS_PAD
;
668 PadFile
->Attributes
= 0;
671 // Write pad file size (calculated size minus next file header size)
673 if (PadFileSize
>= MAX_FFS_SIZE
) {
674 memset(PadFile
->Size
, 0, sizeof(UINT8
) * 3);
675 ((EFI_FFS_FILE_HEADER2
*)PadFile
)->ExtendedSize
= PadFileSize
;
676 PadFile
->Attributes
|= FFS_ATTRIB_LARGE_FILE
;
678 PadFile
->Size
[0] = (UINT8
) (PadFileSize
& 0xFF);
679 PadFile
->Size
[1] = (UINT8
) ((PadFileSize
>> 8) & 0xFF);
680 PadFile
->Size
[2] = (UINT8
) ((PadFileSize
>> 16) & 0xFF);
684 // Fill in checksums and state, they must be 0 for checksumming.
686 PadFile
->IntegrityCheck
.Checksum
.Header
= 0;
687 PadFile
->IntegrityCheck
.Checksum
.File
= 0;
689 PadFile
->IntegrityCheck
.Checksum
.Header
= CalculateChecksum8 ((UINT8
*) PadFile
, CurFfsHeaderSize
);
690 PadFile
->IntegrityCheck
.Checksum
.File
= FFS_FIXED_CHECKSUM
;
692 PadFile
->State
= EFI_FILE_HEADER_CONSTRUCTION
| EFI_FILE_HEADER_VALID
| EFI_FILE_DATA_VALID
;
694 (EFI_FFS_FILE_HEADER
*) PadFile
,
695 (EFI_FIRMWARE_VOLUME_HEADER
*) FvImage
->FileImage
699 // Update the current FV pointer
701 FvImage
->CurrentFilePointer
+= PadFileSize
;
703 if (ExtHeader
!= NULL
) {
705 // Copy Fv Extension Header and Set Fv Extension header offset
707 if (ExtHeader
->ExtHeaderSize
> sizeof (EFI_FIRMWARE_VOLUME_EXT_HEADER
)) {
708 for (Index
= sizeof (EFI_FIRMWARE_VOLUME_EXT_HEADER
); Index
< ExtHeader
->ExtHeaderSize
;) {
709 if (((EFI_FIRMWARE_VOLUME_EXT_ENTRY
*)((UINT8
*)ExtHeader
+ Index
))-> ExtEntryType
== EFI_FV_EXT_TYPE_USED_SIZE_TYPE
) {
711 ((EFI_FIRMWARE_VOLUME_EXT_ENTRY_USED_SIZE_TYPE
*)((UINT8
*)ExtHeader
+ Index
))->UsedSize
= mFvTotalSize
;
713 ((EFI_FIRMWARE_VOLUME_EXT_ENTRY_USED_SIZE_TYPE
*)((UINT8
*)ExtHeader
+ Index
))->UsedSize
= mFvTakenSize
;
717 Index
+= ((EFI_FIRMWARE_VOLUME_EXT_ENTRY
*)((UINT8
*)ExtHeader
+ Index
))-> ExtEntrySize
;
720 memcpy ((UINT8
*)PadFile
+ CurFfsHeaderSize
, ExtHeader
, ExtHeader
->ExtHeaderSize
);
721 ((EFI_FIRMWARE_VOLUME_HEADER
*) FvImage
->FileImage
)->ExtHeaderOffset
= (UINT16
) ((UINTN
) ((UINT8
*)PadFile
+ CurFfsHeaderSize
) - (UINTN
) FvImage
->FileImage
);
723 // Make next file start at QWord Boundary
725 while (((UINTN
) FvImage
->CurrentFilePointer
& (EFI_FFS_FILE_HEADER_ALIGNMENT
- 1)) != 0) {
726 FvImage
->CurrentFilePointer
++;
735 IN EFI_FFS_FILE_HEADER
*FileBuffer
741 This function checks the header to validate if it is a VTF file
745 FileBuffer Buffer in which content of a file has been read.
749 TRUE If this is a VTF file
750 FALSE If this is not a VTF file
754 if (!memcmp (&FileBuffer
->Name
, &mEfiFirmwareVolumeTopFileGuid
, sizeof (EFI_GUID
))) {
763 IN OUT
FILE *FvMapFile
,
765 IN EFI_FFS_FILE_HEADER
*FfsFile
,
766 IN EFI_PHYSICAL_ADDRESS ImageBaseAddress
,
767 IN PE_COFF_LOADER_IMAGE_CONTEXT
*pImageContext
773 This function gets the basic debug information (entrypoint, baseaddress, .text, .data section base address)
774 from PE/COFF image and abstracts Pe Map file information and add them into FvMap file for Debug.
778 FvMapFile A pointer to FvMap File
779 FileName Ffs File PathName
780 FfsFile A pointer to Ffs file image.
781 ImageBaseAddress PeImage Base Address.
782 pImageContext Image Context Information.
786 EFI_SUCCESS Added required map information.
790 CHAR8 PeMapFileName
[MAX_LONG_FILE_PATH
];
792 CHAR8 FileGuidName
[MAX_LINE_LEN
];
794 CHAR8 Line
[MAX_LINE_LEN
];
795 CHAR8 KeyWord
[MAX_LINE_LEN
];
796 CHAR8 KeyWord2
[MAX_LINE_LEN
];
797 CHAR8 FunctionName
[MAX_LINE_LEN
];
798 EFI_PHYSICAL_ADDRESS FunctionAddress
;
800 CHAR8 FunctionTypeName
[MAX_LINE_LEN
];
802 UINT32 AddressOfEntryPoint
;
804 EFI_IMAGE_OPTIONAL_HEADER_UNION
*ImgHdr
;
805 EFI_TE_IMAGE_HEADER
*TEImageHeader
;
806 EFI_IMAGE_SECTION_HEADER
*SectionHeader
;
807 long long TempLongAddress
;
808 UINT32 TextVirtualAddress
;
809 UINT32 DataVirtualAddress
;
810 EFI_PHYSICAL_ADDRESS LinkTimeBaseAddress
;
814 // Init local variable
818 // Print FileGuid to string buffer.
820 PrintGuidToBuffer (&FfsFile
->Name
, (UINT8
*)FileGuidName
, MAX_LINE_LEN
, TRUE
);
823 // Construct Map file Name
825 if (strlen (FileName
) >= MAX_LONG_FILE_PATH
) {
828 strncpy (PeMapFileName
, FileName
, MAX_LONG_FILE_PATH
- 1);
829 PeMapFileName
[MAX_LONG_FILE_PATH
- 1] = 0;
832 // Change '\\' to '/', unified path format.
834 Cptr
= PeMapFileName
;
835 while (*Cptr
!= '\0') {
837 *Cptr
= FILE_SEP_CHAR
;
845 Cptr
= PeMapFileName
+ strlen (PeMapFileName
);
846 while ((*Cptr
!= '.') && (Cptr
>= PeMapFileName
)) {
849 if (Cptr
< PeMapFileName
) {
850 return EFI_NOT_FOUND
;
862 while ((*Cptr
!= FILE_SEP_CHAR
) && (Cptr
>= PeMapFileName
)) {
866 if (strlen (Cptr
+ 1) >= MAX_LINE_LEN
) {
869 strncpy (KeyWord
, Cptr
+ 1, MAX_LINE_LEN
- 1);
870 KeyWord
[MAX_LINE_LEN
- 1] = 0;
874 // AddressOfEntryPoint and Offset in Image
876 if (!pImageContext
->IsTeImage
) {
877 ImgHdr
= (EFI_IMAGE_OPTIONAL_HEADER_UNION
*) ((UINT8
*) pImageContext
->Handle
+ pImageContext
->PeCoffHeaderOffset
);
878 AddressOfEntryPoint
= ImgHdr
->Pe32
.OptionalHeader
.AddressOfEntryPoint
;
880 SectionHeader
= (EFI_IMAGE_SECTION_HEADER
*) (
883 sizeof (EFI_IMAGE_FILE_HEADER
) +
884 ImgHdr
->Pe32
.FileHeader
.SizeOfOptionalHeader
886 Index
= ImgHdr
->Pe32
.FileHeader
.NumberOfSections
;
888 TEImageHeader
= (EFI_TE_IMAGE_HEADER
*) pImageContext
->Handle
;
889 AddressOfEntryPoint
= TEImageHeader
->AddressOfEntryPoint
;
890 Offset
= TEImageHeader
->StrippedSize
- sizeof (EFI_TE_IMAGE_HEADER
);
891 SectionHeader
= (EFI_IMAGE_SECTION_HEADER
*) (TEImageHeader
+ 1);
892 Index
= TEImageHeader
->NumberOfSections
;
896 // module information output
898 if (ImageBaseAddress
== 0) {
899 fprintf (FvMapFile
, "%s (dummy) (", KeyWord
);
900 fprintf (FvMapFile
, "BaseAddress=%010llx, ", (unsigned long long) ImageBaseAddress
);
902 fprintf (FvMapFile
, "%s (Fixed Flash Address, ", KeyWord
);
903 fprintf (FvMapFile
, "BaseAddress=0x%010llx, ", (unsigned long long) (ImageBaseAddress
+ Offset
));
906 fprintf (FvMapFile
, "EntryPoint=0x%010llx", (unsigned long long) (ImageBaseAddress
+ AddressOfEntryPoint
));
907 fprintf (FvMapFile
, ")\n");
909 fprintf (FvMapFile
, "(GUID=%s", FileGuidName
);
910 TextVirtualAddress
= 0;
911 DataVirtualAddress
= 0;
912 for (; Index
> 0; Index
--, SectionHeader
++) {
913 if (stricmp ((CHAR8
*)SectionHeader
->Name
, ".text") == 0) {
914 TextVirtualAddress
= SectionHeader
->VirtualAddress
;
915 } else if (stricmp ((CHAR8
*)SectionHeader
->Name
, ".data") == 0) {
916 DataVirtualAddress
= SectionHeader
->VirtualAddress
;
917 } else if (stricmp ((CHAR8
*)SectionHeader
->Name
, ".sdata") == 0) {
918 DataVirtualAddress
= SectionHeader
->VirtualAddress
;
921 fprintf (FvMapFile
, " .textbaseaddress=0x%010llx", (unsigned long long) (ImageBaseAddress
+ TextVirtualAddress
));
922 fprintf (FvMapFile
, " .databaseaddress=0x%010llx", (unsigned long long) (ImageBaseAddress
+ DataVirtualAddress
));
923 fprintf (FvMapFile
, ")\n\n");
928 PeMapFile
= fopen (LongFilePath (PeMapFileName
), "r");
929 if (PeMapFile
== NULL
) {
930 // fprintf (stdout, "can't open %s file to reading\n", PeMapFileName);
933 VerboseMsg ("The map file is %s", PeMapFileName
);
936 // Output Functions information into Fv Map file
938 LinkTimeBaseAddress
= 0;
940 while (fgets (Line
, MAX_LINE_LEN
, PeMapFile
) != NULL
) {
944 if (Line
[0] == 0x0a) {
949 // By Address and Static keyword
951 if (FunctionType
== 0) {
952 sscanf (Line
, "%s", KeyWord
);
953 if (stricmp (KeyWord
, "Address") == 0) {
954 sscanf (Line
, "%s %s", KeyWord
, KeyWord2
);
955 if (stricmp (KeyWord2
, "Size") == 0) {
964 fgets (Line
, MAX_LINE_LEN
, PeMapFile
);
965 } else if (stricmp (KeyWord
, "Static") == 0) {
967 // static function list
970 fgets (Line
, MAX_LINE_LEN
, PeMapFile
);
971 } else if (stricmp (KeyWord
, "Preferred") ==0) {
972 sscanf (Line
+ strlen (" Preferred load address is"), "%llx", &TempLongAddress
);
973 LinkTimeBaseAddress
= (UINT64
) TempLongAddress
;
978 // Printf Function Information
980 if (FunctionType
== 1) {
982 sscanf (Line
, "%llx %s %s %s", &TempLongAddress
, KeyWord
, KeyWord2
, FunctionTypeName
);
983 FunctionAddress
= (UINT64
) TempLongAddress
;
984 if (FunctionTypeName
[0] == '_' ) {
985 fprintf (FvMapFile
, " 0x%010llx ", (unsigned long long) (ImageBaseAddress
+ FunctionAddress
- LinkTimeBaseAddress
));
986 fprintf (FvMapFile
, "%s\n", FunctionTypeName
);
989 sscanf (Line
, "%s %s %llx %s", KeyWord
, FunctionName
, &TempLongAddress
, FunctionTypeName
);
990 FunctionAddress
= (UINT64
) TempLongAddress
;
991 if (FunctionTypeName
[1] == '\0' && (FunctionTypeName
[0] == 'f' || FunctionTypeName
[0] == 'F')) {
992 fprintf (FvMapFile
, " 0x%010llx ", (unsigned long long) (ImageBaseAddress
+ FunctionAddress
- LinkTimeBaseAddress
));
993 fprintf (FvMapFile
, "%s\n", FunctionName
);
996 } else if (FunctionType
== 2) {
997 sscanf (Line
, "%s %s %llx %s", KeyWord
, FunctionName
, &TempLongAddress
, FunctionTypeName
);
998 FunctionAddress
= (UINT64
) TempLongAddress
;
999 if (FunctionTypeName
[1] == '\0' && (FunctionTypeName
[0] == 'f' || FunctionTypeName
[0] == 'F')) {
1000 fprintf (FvMapFile
, " 0x%010llx ", (unsigned long long) (ImageBaseAddress
+ FunctionAddress
- LinkTimeBaseAddress
));
1001 fprintf (FvMapFile
, "%s\n", FunctionName
);
1008 fprintf (FvMapFile
, "\n\n");
1016 AdjustInternalFfsPadding (
1017 IN OUT EFI_FFS_FILE_HEADER
*FfsFile
,
1018 IN OUT MEMORY_FILE
*FvImage
,
1020 IN OUT UINTN
*FileSize
1024 Routine Description:
1026 This function looks for a dedicated alignment padding section in the FFS, and
1027 shrinks it to the size required to line up subsequent sections correctly.
1031 FfsFile A pointer to Ffs file image.
1032 FvImage The memory image of the FV to adjust it to.
1033 Alignment Current file alignment
1034 FileSize Reference to a variable holding the size of the FFS file
1038 TRUE Padding section was found and updated successfully
1043 EFI_FILE_SECTION_POINTER PadSection
;
1046 UINT32 FfsHeaderLength
;
1047 UINT32 FfsFileLength
;
1050 EFI_FFS_INTEGRITY_CHECK
*IntegrityCheck
;
1053 // Figure out the misalignment: all FFS sections are aligned relative to the
1054 // start of the FFS payload, so use that as the base of the misalignment
1057 FfsHeaderLength
= GetFfsHeaderLength(FfsFile
);
1058 Misalignment
= (UINTN
) FvImage
->CurrentFilePointer
-
1059 (UINTN
) FvImage
->FileImage
+ FfsHeaderLength
;
1060 Misalignment
&= Alignment
- 1;
1061 if (Misalignment
== 0) {
1062 // Nothing to do, return success
1067 // We only apply this optimization to FFS files with the FIXED attribute set,
1068 // since the FFS will not be loadable at arbitrary offsets anymore after
1069 // we adjust the size of the padding section.
1071 if ((FfsFile
->Attributes
& FFS_ATTRIB_FIXED
) == 0) {
1076 // Look for a dedicated padding section that we can adjust to compensate
1077 // for the misalignment. If such a padding section exists, it precedes all
1078 // sections with alignment requirements, and so the adjustment will correct
1081 Status
= GetSectionByType (FfsFile
, EFI_SECTION_FREEFORM_SUBTYPE_GUID
, 1,
1083 if (EFI_ERROR (Status
) ||
1084 CompareGuid (&PadSection
.FreeformSubtypeSection
->SubTypeGuid
,
1085 &mEfiFfsSectionAlignmentPaddingGuid
) != 0) {
1090 // Find out if the size of the padding section is sufficient to compensate
1091 // for the misalignment.
1093 PadSize
= GetSectionFileLength (PadSection
.CommonHeader
);
1094 if (Misalignment
> PadSize
- sizeof (EFI_FREEFORM_SUBTYPE_GUID_SECTION
)) {
1099 // Move the remainder of the FFS file towards the front, and adjust the
1100 // file size output parameter.
1102 Remainder
= (UINT8
*) PadSection
.CommonHeader
+ PadSize
;
1103 memmove (Remainder
- Misalignment
, Remainder
,
1104 *FileSize
- (UINTN
) (Remainder
- (UINTN
) FfsFile
));
1105 *FileSize
-= Misalignment
;
1108 // Update the padding section's length with the new values. Note that the
1109 // padding is always < 64 KB, so we can ignore EFI_COMMON_SECTION_HEADER2
1112 PadSize
-= Misalignment
;
1113 PadSection
.CommonHeader
->Size
[0] = (UINT8
) (PadSize
& 0xff);
1114 PadSection
.CommonHeader
->Size
[1] = (UINT8
) ((PadSize
& 0xff00) >> 8);
1115 PadSection
.CommonHeader
->Size
[2] = (UINT8
) ((PadSize
& 0xff0000) >> 16);
1118 // Update the FFS header with the new overall length
1120 FfsFileLength
= GetFfsFileLength (FfsFile
) - Misalignment
;
1121 if (FfsHeaderLength
> sizeof(EFI_FFS_FILE_HEADER
)) {
1122 ((EFI_FFS_FILE_HEADER2
*)FfsFile
)->ExtendedSize
= FfsFileLength
;
1124 FfsFile
->Size
[0] = (UINT8
) (FfsFileLength
& 0x000000FF);
1125 FfsFile
->Size
[1] = (UINT8
) ((FfsFileLength
& 0x0000FF00) >> 8);
1126 FfsFile
->Size
[2] = (UINT8
) ((FfsFileLength
& 0x00FF0000) >> 16);
1130 // Clear the alignment bits: these have become meaningless now that we have
1131 // adjusted the padding section.
1133 FfsFile
->Attributes
&= ~(FFS_ATTRIB_DATA_ALIGNMENT
| FFS_ATTRIB_DATA_ALIGNMENT2
);
1136 // Recalculate the FFS header checksum. Instead of setting Header and State
1137 // both to zero, set Header to (UINT8)(-State) so State preserves its original
1140 IntegrityCheck
= &FfsFile
->IntegrityCheck
;
1141 IntegrityCheck
->Checksum
.Header
= (UINT8
) (0x100 - FfsFile
->State
);
1142 IntegrityCheck
->Checksum
.File
= 0;
1144 IntegrityCheck
->Checksum
.Header
= CalculateChecksum8 (
1145 (UINT8
*) FfsFile
, FfsHeaderLength
);
1147 if (FfsFile
->Attributes
& FFS_ATTRIB_CHECKSUM
) {
1149 // Ffs header checksum = zero, so only need to calculate ffs body.
1151 IntegrityCheck
->Checksum
.File
= CalculateChecksum8 (
1152 (UINT8
*) FfsFile
+ FfsHeaderLength
,
1153 FfsFileLength
- FfsHeaderLength
);
1155 IntegrityCheck
->Checksum
.File
= FFS_FIXED_CHECKSUM
;
1163 IN OUT MEMORY_FILE
*FvImage
,
1166 IN OUT EFI_FFS_FILE_HEADER
**VtfFileImage
,
1168 IN
FILE *FvReportFile
1172 Routine Description:
1174 This function adds a file to the FV image. The file will pad to the
1175 appropriate alignment if required.
1179 FvImage The memory image of the FV to add it to. The current offset
1181 FvInfo Pointer to information about the FV.
1182 Index The file in the FvInfo file list to add.
1183 VtfFileImage A pointer to the VTF file within the FvImage. If this is equal
1184 to the end of the FvImage then no VTF previously found.
1185 FvMapFile Pointer to FvMap File
1186 FvReportFile Pointer to FvReport File
1190 EFI_SUCCESS The function completed successfully.
1191 EFI_INVALID_PARAMETER One of the input parameters was invalid.
1192 EFI_ABORTED An error occurred.
1193 EFI_OUT_OF_RESOURCES Insufficient resources exist to complete the add.
1201 UINT32 CurrentFileAlignment
;
1204 UINT8 FileGuidString
[PRINTED_GUID_BUFFER_SIZE
];
1208 // Verify input parameters.
1210 if (FvImage
== NULL
|| FvInfo
== NULL
|| FvInfo
->FvFiles
[Index
][0] == 0 || VtfFileImage
== NULL
) {
1211 return EFI_INVALID_PARAMETER
;
1215 // Read the file to add
1217 NewFile
= fopen (LongFilePath (FvInfo
->FvFiles
[Index
]), "rb");
1219 if (NewFile
== NULL
) {
1220 Error (NULL
, 0, 0001, "Error opening file", FvInfo
->FvFiles
[Index
]);
1225 // Get the file size
1227 FileSize
= _filelength (fileno (NewFile
));
1230 // Read the file into a buffer
1232 FileBuffer
= malloc (FileSize
);
1233 if (FileBuffer
== NULL
) {
1235 Error (NULL
, 0, 4001, "Resource", "memory cannot be allocated!");
1236 return EFI_OUT_OF_RESOURCES
;
1239 NumBytesRead
= fread (FileBuffer
, sizeof (UINT8
), FileSize
, NewFile
);
1242 // Done with the file, from this point on we will just use the buffer read.
1247 // Verify read successful
1249 if (NumBytesRead
!= sizeof (UINT8
) * FileSize
) {
1251 Error (NULL
, 0, 0004, "Error reading file", FvInfo
->FvFiles
[Index
]);
1256 // For None PI Ffs file, directly add them into FvImage.
1258 if (!FvInfo
->IsPiFvImage
) {
1259 memcpy (FvImage
->CurrentFilePointer
, FileBuffer
, FileSize
);
1260 if (FvInfo
->SizeofFvFiles
[Index
] > FileSize
) {
1261 FvImage
->CurrentFilePointer
+= FvInfo
->SizeofFvFiles
[Index
];
1263 FvImage
->CurrentFilePointer
+= FileSize
;
1271 Status
= VerifyFfsFile ((EFI_FFS_FILE_HEADER
*)FileBuffer
);
1272 if (EFI_ERROR (Status
)) {
1274 Error (NULL
, 0, 3000, "Invalid", "%s is not a valid FFS file.", FvInfo
->FvFiles
[Index
]);
1275 return EFI_INVALID_PARAMETER
;
1279 // Verify space exists to add the file
1281 if (FileSize
> (UINTN
) ((UINTN
) *VtfFileImage
- (UINTN
) FvImage
->CurrentFilePointer
)) {
1283 Error (NULL
, 0, 4002, "Resource", "FV space is full, not enough room to add file %s.", FvInfo
->FvFiles
[Index
]);
1284 return EFI_OUT_OF_RESOURCES
;
1288 // Verify the input file is the duplicated file in this Fv image
1290 for (Index1
= 0; Index1
< Index
; Index1
++) {
1291 if (CompareGuid ((EFI_GUID
*) FileBuffer
, &mFileGuidArray
[Index1
]) == 0) {
1292 Error (NULL
, 0, 2000, "Invalid parameter", "the %dth file and %uth file have the same file GUID.", (unsigned) Index1
+ 1, (unsigned) Index
+ 1);
1293 PrintGuid ((EFI_GUID
*) FileBuffer
);
1295 return EFI_INVALID_PARAMETER
;
1298 CopyMem (&mFileGuidArray
[Index
], FileBuffer
, sizeof (EFI_GUID
));
1301 // Update the file state based on polarity of the FV.
1303 UpdateFfsFileState (
1304 (EFI_FFS_FILE_HEADER
*) FileBuffer
,
1305 (EFI_FIRMWARE_VOLUME_HEADER
*) FvImage
->FileImage
1309 // Check if alignment is required
1311 ReadFfsAlignment ((EFI_FFS_FILE_HEADER
*) FileBuffer
, &CurrentFileAlignment
);
1314 // Find the largest alignment of all the FFS files in the FV
1316 if (CurrentFileAlignment
> MaxFfsAlignment
) {
1317 MaxFfsAlignment
= CurrentFileAlignment
;
1320 // If we have a VTF file, add it at the top.
1322 if (IsVtfFile ((EFI_FFS_FILE_HEADER
*) FileBuffer
)) {
1323 if ((UINTN
) *VtfFileImage
== (UINTN
) FvImage
->Eof
) {
1325 // No previous VTF, add this one.
1327 *VtfFileImage
= (EFI_FFS_FILE_HEADER
*) (UINTN
) ((UINTN
) FvImage
->FileImage
+ FvInfo
->Size
- FileSize
);
1329 // Sanity check. The file MUST align appropriately
1331 if (((UINTN
) *VtfFileImage
+ GetFfsHeaderLength((EFI_FFS_FILE_HEADER
*)FileBuffer
) - (UINTN
) FvImage
->FileImage
) % (1 << CurrentFileAlignment
)) {
1332 Error (NULL
, 0, 3000, "Invalid", "VTF file cannot be aligned on a %u-byte boundary.", (unsigned) (1 << CurrentFileAlignment
));
1337 // Rebase the PE or TE image in FileBuffer of FFS file for XIP
1338 // Rebase for the debug genfvmap tool
1340 Status
= FfsRebase (FvInfo
, FvInfo
->FvFiles
[Index
], (EFI_FFS_FILE_HEADER
*) FileBuffer
, (UINTN
) *VtfFileImage
- (UINTN
) FvImage
->FileImage
, FvMapFile
);
1341 if (EFI_ERROR (Status
)) {
1342 Error (NULL
, 0, 3000, "Invalid", "Could not rebase %s.", FvInfo
->FvFiles
[Index
]);
1348 memcpy (*VtfFileImage
, FileBuffer
, FileSize
);
1350 PrintGuidToBuffer ((EFI_GUID
*) FileBuffer
, FileGuidString
, sizeof (FileGuidString
), TRUE
);
1351 fprintf (FvReportFile
, "0x%08X %s\n", (unsigned)(UINTN
) (((UINT8
*)*VtfFileImage
) - (UINTN
)FvImage
->FileImage
), FileGuidString
);
1354 DebugMsg (NULL
, 0, 9, "Add VTF FFS file in FV image", NULL
);
1358 // Already found a VTF file.
1360 Error (NULL
, 0, 3000, "Invalid", "multiple VTF files are not permitted within a single FV.");
1367 // Add pad file if necessary
1369 if (!AdjustInternalFfsPadding ((EFI_FFS_FILE_HEADER
*) FileBuffer
, FvImage
,
1370 1 << CurrentFileAlignment
, &FileSize
)) {
1371 Status
= AddPadFile (FvImage
, 1 << CurrentFileAlignment
, *VtfFileImage
, NULL
, FileSize
);
1372 if (EFI_ERROR (Status
)) {
1373 Error (NULL
, 0, 4002, "Resource", "FV space is full, could not add pad file for data alignment property.");
1381 if ((UINTN
) (FvImage
->CurrentFilePointer
+ FileSize
) <= (UINTN
) (*VtfFileImage
)) {
1383 // Rebase the PE or TE image in FileBuffer of FFS file for XIP.
1384 // Rebase Bs and Rt drivers for the debug genfvmap tool.
1386 Status
= FfsRebase (FvInfo
, FvInfo
->FvFiles
[Index
], (EFI_FFS_FILE_HEADER
*) FileBuffer
, (UINTN
) FvImage
->CurrentFilePointer
- (UINTN
) FvImage
->FileImage
, FvMapFile
);
1387 if (EFI_ERROR (Status
)) {
1388 Error (NULL
, 0, 3000, "Invalid", "Could not rebase %s.", FvInfo
->FvFiles
[Index
]);
1394 memcpy (FvImage
->CurrentFilePointer
, FileBuffer
, FileSize
);
1395 PrintGuidToBuffer ((EFI_GUID
*) FileBuffer
, FileGuidString
, sizeof (FileGuidString
), TRUE
);
1396 fprintf (FvReportFile
, "0x%08X %s\n", (unsigned) (FvImage
->CurrentFilePointer
- FvImage
->FileImage
), FileGuidString
);
1397 FvImage
->CurrentFilePointer
+= FileSize
;
1399 Error (NULL
, 0, 4002, "Resource", "FV space is full, cannot add file %s.", FvInfo
->FvFiles
[Index
]);
1404 // Make next file start at QWord Boundary
1406 while (((UINTN
) FvImage
->CurrentFilePointer
& (EFI_FFS_FILE_HEADER_ALIGNMENT
- 1)) != 0) {
1407 FvImage
->CurrentFilePointer
++;
1412 // Free allocated memory.
1421 IN MEMORY_FILE
*FvImage
,
1422 IN EFI_FFS_FILE_HEADER
*VtfFileImage
1426 Routine Description:
1428 This function places a pad file between the last file in the FV and the VTF
1429 file if the VTF file exists.
1433 FvImage Memory file for the FV memory image
1434 VtfFileImage The address of the VTF file. If this is the end of the FV
1435 image, no VTF exists and no pad file is needed.
1439 EFI_SUCCESS Completed successfully.
1440 EFI_INVALID_PARAMETER One of the input parameters was NULL.
1444 EFI_FFS_FILE_HEADER
*PadFile
;
1446 UINT32 FfsHeaderSize
;
1449 // If there is no VTF or the VTF naturally follows the previous file without a
1450 // pad file, then there's nothing to do
1452 if ((UINTN
) VtfFileImage
== (UINTN
) FvImage
->Eof
|| \
1453 ((UINTN
) VtfFileImage
== (UINTN
) FvImage
->CurrentFilePointer
)) {
1457 if ((UINTN
) VtfFileImage
< (UINTN
) FvImage
->CurrentFilePointer
) {
1458 return EFI_INVALID_PARAMETER
;
1462 // Pad file starts at beginning of free space
1464 PadFile
= (EFI_FFS_FILE_HEADER
*) FvImage
->CurrentFilePointer
;
1467 // write PadFile FFS header with PadType, don't need to set PAD file guid in its header.
1469 PadFile
->Type
= EFI_FV_FILETYPE_FFS_PAD
;
1470 PadFile
->Attributes
= 0;
1473 // FileSize includes the EFI_FFS_FILE_HEADER
1475 FileSize
= (UINTN
) VtfFileImage
- (UINTN
) FvImage
->CurrentFilePointer
;
1476 if (FileSize
>= MAX_FFS_SIZE
) {
1477 PadFile
->Attributes
|= FFS_ATTRIB_LARGE_FILE
;
1478 memset(PadFile
->Size
, 0, sizeof(UINT8
) * 3);
1479 ((EFI_FFS_FILE_HEADER2
*)PadFile
)->ExtendedSize
= FileSize
;
1480 FfsHeaderSize
= sizeof(EFI_FFS_FILE_HEADER2
);
1483 PadFile
->Size
[0] = (UINT8
) (FileSize
& 0x000000FF);
1484 PadFile
->Size
[1] = (UINT8
) ((FileSize
& 0x0000FF00) >> 8);
1485 PadFile
->Size
[2] = (UINT8
) ((FileSize
& 0x00FF0000) >> 16);
1486 FfsHeaderSize
= sizeof(EFI_FFS_FILE_HEADER
);
1490 // Fill in checksums and state, must be zero during checksum calculation.
1492 PadFile
->IntegrityCheck
.Checksum
.Header
= 0;
1493 PadFile
->IntegrityCheck
.Checksum
.File
= 0;
1495 PadFile
->IntegrityCheck
.Checksum
.Header
= CalculateChecksum8 ((UINT8
*) PadFile
, FfsHeaderSize
);
1496 PadFile
->IntegrityCheck
.Checksum
.File
= FFS_FIXED_CHECKSUM
;
1498 PadFile
->State
= EFI_FILE_HEADER_CONSTRUCTION
| EFI_FILE_HEADER_VALID
| EFI_FILE_DATA_VALID
;
1500 UpdateFfsFileState (
1501 (EFI_FFS_FILE_HEADER
*) PadFile
,
1502 (EFI_FIRMWARE_VOLUME_HEADER
*) FvImage
->FileImage
1505 // Update the current FV pointer
1507 FvImage
->CurrentFilePointer
= FvImage
->Eof
;
1514 IN MEMORY_FILE
*FvImage
,
1516 IN EFI_FFS_FILE_HEADER
*VtfFile
1520 Routine Description:
1522 This parses the FV looking for the PEI core and then plugs the address into
1523 the SALE_ENTRY point of the BSF/VTF for IPF and does BUGBUG TBD action to
1524 complete an IA32 Bootstrap FV.
1528 FvImage Memory file for the FV memory image
1529 FvInfo Information read from INF file.
1530 VtfFile Pointer to the VTF file in the FV image.
1534 EFI_SUCCESS Function Completed successfully.
1535 EFI_ABORTED Error encountered.
1536 EFI_INVALID_PARAMETER A required parameter was NULL.
1537 EFI_NOT_FOUND PEI Core file not found.
1541 EFI_FFS_FILE_HEADER
*PeiCoreFile
;
1542 EFI_FFS_FILE_HEADER
*SecCoreFile
;
1544 EFI_FILE_SECTION_POINTER Pe32Section
;
1548 EFI_PHYSICAL_ADDRESS PeiCorePhysicalAddress
;
1549 EFI_PHYSICAL_ADDRESS SecCorePhysicalAddress
;
1550 INT32 Ia32SecEntryOffset
;
1551 UINT32
*Ia32ResetAddressPtr
;
1553 UINT8
*BytePointer2
;
1554 UINT16
*WordPointer
;
1558 EFI_FFS_FILE_STATE SavedState
;
1559 BOOLEAN Vtf0Detected
;
1560 UINT32 FfsHeaderSize
;
1561 UINT32 SecHeaderSize
;
1564 // Verify input parameters
1566 if (FvImage
== NULL
|| FvInfo
== NULL
|| VtfFile
== NULL
) {
1567 return EFI_INVALID_PARAMETER
;
1570 // Initialize FV library
1572 InitializeFvLib (FvImage
->FileImage
, FvInfo
->Size
);
1577 Status
= VerifyFfsFile (VtfFile
);
1578 if (EFI_ERROR (Status
)) {
1579 return EFI_INVALID_PARAMETER
;
1583 (((UINTN
)FvImage
->Eof
- (UINTN
)FvImage
->FileImage
) >=
1584 IA32_X64_VTF_SIGNATURE_OFFSET
) &&
1585 (*(UINT32
*)(VOID
*)((UINTN
) FvImage
->Eof
-
1586 IA32_X64_VTF_SIGNATURE_OFFSET
) ==
1587 IA32_X64_VTF0_SIGNATURE
)
1589 Vtf0Detected
= TRUE
;
1591 Vtf0Detected
= FALSE
;
1595 // Find the Sec Core
1597 Status
= GetFileByType (EFI_FV_FILETYPE_SECURITY_CORE
, 1, &SecCoreFile
);
1598 if (EFI_ERROR (Status
) || SecCoreFile
== NULL
) {
1601 // If the SEC core file is not found, but the VTF-0 signature
1602 // is found, we'll treat it as a VTF-0 'Volume Top File'.
1603 // This means no modifications are required to the VTF.
1608 Error (NULL
, 0, 3000, "Invalid", "could not find the SEC core file in the FV.");
1612 // Sec Core found, now find PE32 section
1614 Status
= GetSectionByType (SecCoreFile
, EFI_SECTION_PE32
, 1, &Pe32Section
);
1615 if (Status
== EFI_NOT_FOUND
) {
1616 Status
= GetSectionByType (SecCoreFile
, EFI_SECTION_TE
, 1, &Pe32Section
);
1619 if (EFI_ERROR (Status
)) {
1620 Error (NULL
, 0, 3000, "Invalid", "could not find a PE32 section in the SEC core file.");
1624 SecHeaderSize
= GetSectionHeaderLength(Pe32Section
.CommonHeader
);
1625 Status
= GetPe32Info (
1626 (VOID
*) ((UINTN
) Pe32Section
.Pe32Section
+ SecHeaderSize
),
1632 if (EFI_ERROR (Status
)) {
1633 Error (NULL
, 0, 3000, "Invalid", "could not get the PE32 entry point for the SEC core.");
1639 (MachineType
== EFI_IMAGE_MACHINE_IA32
||
1640 MachineType
== EFI_IMAGE_MACHINE_X64
)
1643 // If the SEC core code is IA32 or X64 and the VTF-0 signature
1644 // is found, we'll treat it as a VTF-0 'Volume Top File'.
1645 // This means no modifications are required to the VTF.
1651 // Physical address is FV base + offset of PE32 + offset of the entry point
1653 SecCorePhysicalAddress
= FvInfo
->BaseAddress
;
1654 SecCorePhysicalAddress
+= (UINTN
) Pe32Section
.Pe32Section
+ SecHeaderSize
- (UINTN
) FvImage
->FileImage
;
1655 SecCorePhysicalAddress
+= EntryPoint
;
1656 DebugMsg (NULL
, 0, 9, "SecCore physical entry point address", "Address = 0x%llX", (unsigned long long) SecCorePhysicalAddress
);
1659 // Find the PEI Core
1661 PeiCorePhysicalAddress
= 0;
1662 Status
= GetFileByType (EFI_FV_FILETYPE_PEI_CORE
, 1, &PeiCoreFile
);
1663 if (!EFI_ERROR (Status
) && (PeiCoreFile
!= NULL
)) {
1665 // PEI Core found, now find PE32 or TE section
1667 Status
= GetSectionByType (PeiCoreFile
, EFI_SECTION_PE32
, 1, &Pe32Section
);
1668 if (Status
== EFI_NOT_FOUND
) {
1669 Status
= GetSectionByType (PeiCoreFile
, EFI_SECTION_TE
, 1, &Pe32Section
);
1672 if (EFI_ERROR (Status
)) {
1673 Error (NULL
, 0, 3000, "Invalid", "could not find either a PE32 or a TE section in PEI core file.");
1677 SecHeaderSize
= GetSectionHeaderLength(Pe32Section
.CommonHeader
);
1678 Status
= GetPe32Info (
1679 (VOID
*) ((UINTN
) Pe32Section
.Pe32Section
+ SecHeaderSize
),
1685 if (EFI_ERROR (Status
)) {
1686 Error (NULL
, 0, 3000, "Invalid", "could not get the PE32 entry point for the PEI core.");
1690 // Physical address is FV base + offset of PE32 + offset of the entry point
1692 PeiCorePhysicalAddress
= FvInfo
->BaseAddress
;
1693 PeiCorePhysicalAddress
+= (UINTN
) Pe32Section
.Pe32Section
+ SecHeaderSize
- (UINTN
) FvImage
->FileImage
;
1694 PeiCorePhysicalAddress
+= EntryPoint
;
1695 DebugMsg (NULL
, 0, 9, "PeiCore physical entry point address", "Address = 0x%llX", (unsigned long long) PeiCorePhysicalAddress
);
1698 if (MachineType
== EFI_IMAGE_MACHINE_IA32
|| MachineType
== EFI_IMAGE_MACHINE_X64
) {
1699 if (PeiCorePhysicalAddress
!= 0) {
1701 // Get the location to update
1703 Ia32ResetAddressPtr
= (UINT32
*) ((UINTN
) FvImage
->Eof
- IA32_PEI_CORE_ENTRY_OFFSET
);
1706 // Write lower 32 bits of physical address for Pei Core entry
1708 *Ia32ResetAddressPtr
= (UINT32
) PeiCorePhysicalAddress
;
1711 // Write SecCore Entry point relative address into the jmp instruction in reset vector.
1713 Ia32ResetAddressPtr
= (UINT32
*) ((UINTN
) FvImage
->Eof
- IA32_SEC_CORE_ENTRY_OFFSET
);
1715 Ia32SecEntryOffset
= (INT32
) (SecCorePhysicalAddress
- (FV_IMAGES_TOP_ADDRESS
- IA32_SEC_CORE_ENTRY_OFFSET
+ 2));
1716 if (Ia32SecEntryOffset
<= -65536) {
1717 Error (NULL
, 0, 3000, "Invalid", "The SEC EXE file size is too large, it must be less than 64K.");
1718 return STATUS_ERROR
;
1721 *(UINT16
*) Ia32ResetAddressPtr
= (UINT16
) Ia32SecEntryOffset
;
1724 // Update the BFV base address
1726 Ia32ResetAddressPtr
= (UINT32
*) ((UINTN
) FvImage
->Eof
- 4);
1727 *Ia32ResetAddressPtr
= (UINT32
) (FvInfo
->BaseAddress
);
1728 DebugMsg (NULL
, 0, 9, "update BFV base address in the top FV image", "BFV base address = 0x%llX.", (unsigned long long) FvInfo
->BaseAddress
);
1731 // Update the Startup AP in the FVH header block ZeroVector region.
1733 BytePointer
= (UINT8
*) ((UINTN
) FvImage
->FileImage
);
1734 if (FvInfo
->Size
<= 0x10000) {
1735 BytePointer2
= m64kRecoveryStartupApDataArray
;
1736 } else if (FvInfo
->Size
<= 0x20000) {
1737 BytePointer2
= m128kRecoveryStartupApDataArray
;
1739 BytePointer2
= m128kRecoveryStartupApDataArray
;
1741 // Find the position to place Ap reset vector, the offset
1742 // between the position and the end of Fvrecovery.fv file
1743 // should not exceed 128kB to prevent Ap reset vector from
1744 // outside legacy E and F segment
1746 Status
= FindApResetVectorPosition (FvImage
, &BytePointer
);
1747 if (EFI_ERROR (Status
)) {
1748 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.");
1753 for (Index
= 0; Index
< SIZEOF_STARTUP_DATA_ARRAY
; Index
++) {
1754 BytePointer
[Index
] = BytePointer2
[Index
];
1757 // Calculate the checksum
1760 WordPointer
= (UINT16
*) (BytePointer
);
1761 for (Index
= 0; Index
< SIZEOF_STARTUP_DATA_ARRAY
/ 2; Index
++) {
1762 CheckSum
= (UINT16
) (CheckSum
+ ((UINT16
) *WordPointer
));
1766 // Update the checksum field
1768 WordPointer
= (UINT16
*) (BytePointer
+ SIZEOF_STARTUP_DATA_ARRAY
- 2);
1769 *WordPointer
= (UINT16
) (0x10000 - (UINT32
) CheckSum
);
1772 // IpiVector at the 4k aligned address in the top 2 blocks in the PEI FV.
1774 IpiVector
= (UINT32
) (FV_IMAGES_TOP_ADDRESS
- ((UINTN
) FvImage
->Eof
- (UINTN
) BytePointer
));
1775 DebugMsg (NULL
, 0, 9, "Startup AP Vector address", "IpiVector at 0x%X", (unsigned) IpiVector
);
1776 if ((IpiVector
& 0xFFF) != 0) {
1777 Error (NULL
, 0, 3000, "Invalid", "Startup AP Vector address are not 4K aligned, because the FV size is not 4K aligned");
1780 IpiVector
= IpiVector
>> 12;
1781 IpiVector
= IpiVector
& 0xFF;
1784 // Write IPI Vector at Offset FvrecoveryFileSize - 8
1786 Ia32ResetAddressPtr
= (UINT32
*) ((UINTN
) FvImage
->Eof
- 8);
1787 *Ia32ResetAddressPtr
= IpiVector
;
1788 } else if (MachineType
== EFI_IMAGE_MACHINE_ARMT
) {
1790 // Since the ARM reset vector is in the FV Header you really don't need a
1791 // Volume Top File, but if you have one for some reason don't crash...
1793 } else if (MachineType
== EFI_IMAGE_MACHINE_AARCH64
) {
1795 // Since the AArch64 reset vector is in the FV Header you really don't need a
1796 // Volume Top File, but if you have one for some reason don't crash...
1799 Error (NULL
, 0, 3000, "Invalid", "machine type=0x%X in PEI core.", MachineType
);
1804 // Now update file checksum
1806 SavedState
= VtfFile
->State
;
1807 VtfFile
->IntegrityCheck
.Checksum
.File
= 0;
1809 if (VtfFile
->Attributes
& FFS_ATTRIB_CHECKSUM
) {
1810 FfsHeaderSize
= GetFfsHeaderLength(VtfFile
);
1811 VtfFile
->IntegrityCheck
.Checksum
.File
= CalculateChecksum8 (
1812 (UINT8
*) ((UINT8
*)VtfFile
+ FfsHeaderSize
),
1813 GetFfsFileLength (VtfFile
) - FfsHeaderSize
1816 VtfFile
->IntegrityCheck
.Checksum
.File
= FFS_FIXED_CHECKSUM
;
1819 VtfFile
->State
= SavedState
;
1826 IN VOID
*FvImageBuffer
,
1828 IN EFI_FV_FILETYPE FileType
,
1829 OUT EFI_FILE_SECTION_POINTER
*Pe32Section
1833 Routine Description:
1835 Recursively searches the FV for the FFS file of specified type (typically
1836 SEC or PEI core) and extracts the PE32 section for further processing.
1840 FvImageBuffer Buffer containing FV data
1841 FvSize Size of the FV
1842 FileType Type of FFS file to search for
1843 Pe32Section PE32 section pointer when FFS file is found.
1847 EFI_SUCCESS Function Completed successfully.
1848 EFI_ABORTED Error encountered.
1849 EFI_INVALID_PARAMETER A required parameter was NULL.
1850 EFI_NOT_FOUND Core file not found.
1855 EFI_FIRMWARE_VOLUME_HEADER
*OrigFvHeader
;
1856 UINT32 OrigFvLength
;
1857 EFI_FFS_FILE_HEADER
*CoreFfsFile
;
1858 UINTN FvImageFileCount
;
1859 EFI_FFS_FILE_HEADER
*FvImageFile
;
1860 UINTN EncapFvSectionCount
;
1861 EFI_FILE_SECTION_POINTER EncapFvSection
;
1862 EFI_FIRMWARE_VOLUME_HEADER
*EncapsulatedFvHeader
;
1864 if (Pe32Section
== NULL
) {
1865 return EFI_INVALID_PARAMETER
;
1869 // Initialize FV library, saving previous values
1871 OrigFvHeader
= (EFI_FIRMWARE_VOLUME_HEADER
*)NULL
;
1872 GetFvHeader (&OrigFvHeader
, &OrigFvLength
);
1873 InitializeFvLib(FvImageBuffer
, (UINT32
)FvSize
);
1876 // First see if we can obtain the file directly in outer FV
1878 Status
= GetFileByType(FileType
, 1, &CoreFfsFile
);
1879 if (!EFI_ERROR(Status
) && (CoreFfsFile
!= NULL
) ) {
1882 // Core found, now find PE32 or TE section
1884 Status
= GetSectionByType(CoreFfsFile
, EFI_SECTION_PE32
, 1, Pe32Section
);
1885 if (EFI_ERROR(Status
)) {
1886 Status
= GetSectionByType(CoreFfsFile
, EFI_SECTION_TE
, 1, Pe32Section
);
1889 if (EFI_ERROR(Status
)) {
1890 Error(NULL
, 0, 3000, "Invalid", "could not find a PE32 section in the core file.");
1895 // Core PE/TE section, found, return
1897 Status
= EFI_SUCCESS
;
1902 // File was not found, look for FV Image file
1905 // iterate through all FV image files in outer FV
1906 for (FvImageFileCount
= 1;; FvImageFileCount
++) {
1908 Status
= GetFileByType(EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE
, FvImageFileCount
, &FvImageFile
);
1910 if (EFI_ERROR(Status
) || (FvImageFile
== NULL
) ) {
1911 // exit FV image file loop, no more found
1915 // Found an fv image file, look for an FV image section. The PI spec does not
1916 // preclude multiple FV image sections so we loop accordingly.
1917 for (EncapFvSectionCount
= 1;; EncapFvSectionCount
++) {
1919 // Look for the next FV image section. The section search code will
1920 // iterate into encapsulation sections. For example, it will iterate
1921 // into an EFI_SECTION_GUID_DEFINED encapsulation section to find the
1922 // EFI_SECTION_FIRMWARE_VOLUME_IMAGE sections contained therein.
1923 Status
= GetSectionByType(FvImageFile
, EFI_SECTION_FIRMWARE_VOLUME_IMAGE
, EncapFvSectionCount
, &EncapFvSection
);
1925 if (EFI_ERROR(Status
)) {
1926 // exit section inner loop, no more found
1930 EncapsulatedFvHeader
= (EFI_FIRMWARE_VOLUME_HEADER
*)((UINT8
*)EncapFvSection
.FVImageSection
+ GetSectionHeaderLength(EncapFvSection
.FVImageSection
));
1932 // recurse to search the encapsulated FV for this core file type
1933 Status
= FindCorePeSection(EncapsulatedFvHeader
, EncapsulatedFvHeader
->FvLength
, FileType
, Pe32Section
);
1935 if (!EFI_ERROR(Status
)) {
1936 // we found the core in the capsulated image, success
1940 } // end encapsulated fv image section loop
1941 } // end fv image file loop
1943 // core was not found
1944 Status
= EFI_NOT_FOUND
;
1948 // restore FV lib values
1949 if(OrigFvHeader
!= NULL
) {
1950 InitializeFvLib(OrigFvHeader
, OrigFvLength
);
1958 IN EFI_FILE_SECTION_POINTER Pe32Section
,
1959 OUT UINT16
*CoreMachineType
1963 Routine Description:
1965 Returns the machine type of a P32 image, typically SEC or PEI core.
1969 Pe32Section PE32 section data
1970 CoreMachineType The extracted machine type
1974 EFI_SUCCESS Function Completed successfully.
1975 EFI_ABORTED Error encountered.
1976 EFI_INVALID_PARAMETER A required parameter was NULL.
1984 if (CoreMachineType
== NULL
) {
1985 return EFI_INVALID_PARAMETER
;
1988 Status
= GetPe32Info(
1989 (VOID
*)((UINTN
)Pe32Section
.Pe32Section
+ GetSectionHeaderLength(Pe32Section
.CommonHeader
)),
1994 if (EFI_ERROR(Status
)) {
1995 Error(NULL
, 0, 3000, "Invalid", "could not get the PE32 machine type for the core.");
2003 GetCoreEntryPointAddress(
2004 IN VOID
*FvImageBuffer
,
2006 IN EFI_FILE_SECTION_POINTER Pe32Section
,
2007 OUT EFI_PHYSICAL_ADDRESS
*CoreEntryAddress
2011 Routine Description:
2013 Returns the physical address of the core (SEC or PEI) entry point.
2017 FvImageBuffer Pointer to buffer containing FV data
2018 FvInfo Info for the parent FV
2019 Pe32Section PE32 section data
2020 CoreEntryAddress The extracted core entry physical address
2024 EFI_SUCCESS Function Completed successfully.
2025 EFI_ABORTED Error encountered.
2026 EFI_INVALID_PARAMETER A required parameter was NULL.
2034 EFI_PHYSICAL_ADDRESS EntryPhysicalAddress
;
2036 if (CoreEntryAddress
== NULL
) {
2037 return EFI_INVALID_PARAMETER
;
2040 Status
= GetPe32Info(
2041 (VOID
*)((UINTN
)Pe32Section
.Pe32Section
+ GetSectionHeaderLength(Pe32Section
.CommonHeader
)),
2046 if (EFI_ERROR(Status
)) {
2047 Error(NULL
, 0, 3000, "Invalid", "could not get the PE32 entry point for the core.");
2052 // Physical address is FV base + offset of PE32 + offset of the entry point
2054 EntryPhysicalAddress
= FvInfo
->BaseAddress
;
2055 EntryPhysicalAddress
+= (UINTN
)Pe32Section
.Pe32Section
+ GetSectionHeaderLength(Pe32Section
.CommonHeader
) - (UINTN
)FvImageBuffer
;
2056 EntryPhysicalAddress
+= EntryPoint
;
2058 *CoreEntryAddress
= EntryPhysicalAddress
;
2064 UpdateArmResetVectorIfNeeded (
2065 IN MEMORY_FILE
*FvImage
,
2070 Routine Description:
2071 This parses the FV looking for SEC and patches that address into the
2072 beginning of the FV header.
2074 For ARM32 the reset vector is at 0x00000000 or 0xFFFF0000.
2075 For AArch64 the reset vector is at 0x00000000.
2077 This would commonly map to the first entry in the ROM.
2087 We support two schemes on ARM.
2088 1) Beginning of the FV is the reset vector
2089 2) Reset vector is data bytes FDF file and that code branches to reset vector
2090 in the beginning of the FV (fixed size offset).
2092 Need to have the jump for the reset vector at location zero.
2093 We also need to store the address or PEI (if it exists).
2094 We stub out a return from interrupt in case the debugger
2095 is using SWI (not done for AArch64, not enough space in struct).
2096 The optional entry to the common exception handler is
2097 to support full featured exception handling from ROM and is currently
2098 not support by this tool.
2101 FvImage Memory file for the FV memory image
2102 FvInfo Information read from INF file.
2106 EFI_SUCCESS Function Completed successfully.
2107 EFI_ABORTED Error encountered.
2108 EFI_INVALID_PARAMETER A required parameter was NULL.
2109 EFI_NOT_FOUND PEI Core file not found.
2114 EFI_FILE_SECTION_POINTER SecPe32
;
2115 EFI_FILE_SECTION_POINTER PeiPe32
;
2116 BOOLEAN UpdateVectorSec
= FALSE
;
2117 BOOLEAN UpdateVectorPei
= FALSE
;
2118 UINT16 MachineType
= 0;
2119 EFI_PHYSICAL_ADDRESS SecCoreEntryAddress
= 0;
2120 UINT16 PeiMachineType
= 0;
2121 EFI_PHYSICAL_ADDRESS PeiCoreEntryAddress
= 0;
2124 // Verify input parameters
2126 if (FvImage
== NULL
|| FvInfo
== NULL
) {
2127 return EFI_INVALID_PARAMETER
;
2131 // Locate an SEC Core instance and if found extract the machine type and entry point address
2133 Status
= FindCorePeSection(FvImage
->FileImage
, FvInfo
->Size
, EFI_FV_FILETYPE_SECURITY_CORE
, &SecPe32
);
2134 if (!EFI_ERROR(Status
)) {
2136 Status
= GetCoreMachineType(SecPe32
, &MachineType
);
2137 if (EFI_ERROR(Status
)) {
2138 Error(NULL
, 0, 3000, "Invalid", "Could not get the PE32 machine type for SEC Core.");
2142 Status
= GetCoreEntryPointAddress(FvImage
->FileImage
, FvInfo
, SecPe32
, &SecCoreEntryAddress
);
2143 if (EFI_ERROR(Status
)) {
2144 Error(NULL
, 0, 3000, "Invalid", "Could not get the PE32 entry point address for SEC Core.");
2148 VerboseMsg("UpdateArmResetVectorIfNeeded found SEC core entry at 0x%llx", (unsigned long long)SecCoreEntryAddress
);
2149 UpdateVectorSec
= TRUE
;
2153 // Locate a PEI Core instance and if found extract the machine type and entry point address
2155 Status
= FindCorePeSection(FvImage
->FileImage
, FvInfo
->Size
, EFI_FV_FILETYPE_PEI_CORE
, &PeiPe32
);
2156 if (!EFI_ERROR(Status
)) {
2158 Status
= GetCoreMachineType(PeiPe32
, &PeiMachineType
);
2159 if (EFI_ERROR(Status
)) {
2160 Error(NULL
, 0, 3000, "Invalid", "Could not get the PE32 machine type for PEI Core.");
2164 Status
= GetCoreEntryPointAddress(FvImage
->FileImage
, FvInfo
, PeiPe32
, &PeiCoreEntryAddress
);
2165 if (EFI_ERROR(Status
)) {
2166 Error(NULL
, 0, 3000, "Invalid", "Could not get the PE32 entry point address for PEI Core.");
2170 VerboseMsg("UpdateArmResetVectorIfNeeded found PEI core entry at 0x%llx", (unsigned long long)PeiCoreEntryAddress
);
2172 // if we previously found an SEC Core make sure machine types match
2173 if (UpdateVectorSec
&& (MachineType
!= PeiMachineType
)) {
2174 Error(NULL
, 0, 3000, "Invalid", "SEC and PEI machine types do not match, can't update reset vector");
2178 MachineType
= PeiMachineType
;
2181 UpdateVectorPei
= TRUE
;
2184 if (!UpdateVectorSec
&& !UpdateVectorPei
) {
2188 if (MachineType
== EFI_IMAGE_MACHINE_ARMT
) {
2189 // ARM: Array of 4 UINT32s:
2190 // 0 - is branch relative to SEC entry point
2191 // 1 - PEI Entry Point
2192 // 2 - movs pc,lr for a SWI handler
2193 // 3 - Place holder for Common Exception Handler
2194 UINT32 ResetVector
[4];
2196 memset(ResetVector
, 0, sizeof (ResetVector
));
2198 // if we found an SEC core entry point then generate a branch instruction
2199 // to it and populate a debugger SWI entry as well
2200 if (UpdateVectorSec
) {
2202 VerboseMsg("UpdateArmResetVectorIfNeeded updating ARM SEC vector");
2204 // B SecEntryPoint - signed_immed_24 part +/-32MB offset
2205 // on ARM, the PC is always 8 ahead, so we're not really jumping from the base address, but from base address + 8
2206 ResetVector
[0] = (INT32
)(SecCoreEntryAddress
- FvInfo
->BaseAddress
- 8) >> 2;
2208 if (ResetVector
[0] > 0x00FFFFFF) {
2209 Error(NULL
, 0, 3000, "Invalid", "SEC Entry point must be within 32MB of the start of the FV");
2213 // Add opcode for an unconditional branch with no link. i.e.: " B SecEntryPoint"
2214 ResetVector
[0] |= ARMT_UNCONDITIONAL_JUMP_INSTRUCTION
;
2216 // SWI handler movs pc,lr. Just in case a debugger uses SWI
2217 ResetVector
[2] = 0xE1B0F07E;
2219 // Place holder to support a common interrupt handler from ROM.
2220 // Currently not supported. For this to be used the reset vector would not be in this FV
2221 // and the exception vectors would be hard coded in the ROM and just through this address
2222 // to find a common handler in the a module in the FV.
2226 // if a PEI core entry was found place its address in the vector area
2227 if (UpdateVectorPei
) {
2229 VerboseMsg("UpdateArmResetVectorIfNeeded updating ARM PEI address");
2231 // Address of PEI Core, if we have one
2232 ResetVector
[1] = (UINT32
)PeiCoreEntryAddress
;
2236 // Copy to the beginning of the FV
2238 memcpy(FvImage
->FileImage
, ResetVector
, sizeof (ResetVector
));
2240 } else if (MachineType
== EFI_IMAGE_MACHINE_AARCH64
) {
2241 // AArch64: Used as UINT64 ResetVector[2]
2242 // 0 - is branch relative to SEC entry point
2243 // 1 - PEI Entry Point
2244 UINT64 ResetVector
[2];
2246 memset(ResetVector
, 0, sizeof (ResetVector
));
2249 ARMT above has an entry in ResetVector[2] for SWI. The way we are using the ResetVector
2250 array at the moment, for AArch64, does not allow us space for this as the header only
2251 allows for a fixed amount of bytes at the start. If we are sure that UEFI will live
2252 within the first 4GB of addressable RAM we could potentially adopt the same ResetVector
2253 layout as above. But for the moment we replace the four 32bit vectors with two 64bit
2254 vectors in the same area of the Image heasder. This allows UEFI to start from a 64bit
2258 // if we found an SEC core entry point then generate a branch instruction to it
2259 if (UpdateVectorSec
) {
2261 VerboseMsg("UpdateArmResetVectorIfNeeded updating AArch64 SEC vector");
2263 ResetVector
[0] = (UINT64
)(SecCoreEntryAddress
- FvInfo
->BaseAddress
) >> 2;
2265 // B SecEntryPoint - signed_immed_26 part +/-128MB offset
2266 if (ResetVector
[0] > 0x03FFFFFF) {
2267 Error(NULL
, 0, 3000, "Invalid", "SEC Entry point must be within 128MB of the start of the FV");
2270 // Add opcode for an unconditional branch with no link. i.e.: " B SecEntryPoint"
2271 ResetVector
[0] |= ARM64_UNCONDITIONAL_JUMP_INSTRUCTION
;
2274 // if a PEI core entry was found place its address in the vector area
2275 if (UpdateVectorPei
) {
2277 VerboseMsg("UpdateArmResetVectorIfNeeded updating AArch64 PEI address");
2279 // Address of PEI Core, if we have one
2280 ResetVector
[1] = (UINT64
)PeiCoreEntryAddress
;
2284 // Copy to the beginning of the FV
2286 memcpy(FvImage
->FileImage
, ResetVector
, sizeof (ResetVector
));
2289 Error(NULL
, 0, 3000, "Invalid", "Unknown machine type");
2297 UpdateRiscvResetVectorIfNeeded (
2298 MEMORY_FILE
*FvImage
,
2303 Routine Description:
2304 This parses the FV looking for SEC and patches that address into the
2305 beginning of the FV header.
2307 For RISC-V ISA, the reset vector is at 0xfff~ff00h or 200h
2310 FvImage Memory file for the FV memory image/
2311 FvInfo Information read from INF file.
2315 EFI_SUCCESS Function Completed successfully.
2316 EFI_ABORTED Error encountered.
2317 EFI_INVALID_PARAMETER A required parameter was NULL.
2318 EFI_NOT_FOUND PEI Core file not found.
2324 EFI_FILE_SECTION_POINTER SecPe32
;
2325 EFI_PHYSICAL_ADDRESS SecCoreEntryAddress
;
2332 // Verify input parameters
2334 if (FvImage
== NULL
|| FvInfo
== NULL
) {
2335 return EFI_INVALID_PARAMETER
;
2338 // Initialize FV library
2340 InitializeFvLib (FvImage
->FileImage
, FvInfo
->Size
);
2343 // Find the Sec Core
2345 Status
= FindCorePeSection(FvImage
->FileImage
, FvInfo
->Size
, EFI_FV_FILETYPE_SECURITY_CORE
, &SecPe32
);
2346 if(EFI_ERROR(Status
)) {
2347 printf("skip because Secutiry Core not found\n");
2351 DebugMsg (NULL
, 0, 9, "Update SEC core in FV Header", NULL
);
2353 Status
= GetCoreMachineType(SecPe32
, &MachineType
);
2354 if(EFI_ERROR(Status
)) {
2355 Error(NULL
, 0, 3000, "Invalid", "Could not get the PE32 machine type for SEC core.");
2359 if (MachineType
!= EFI_IMAGE_MACHINE_RISCV64
) {
2360 Error(NULL
, 0, 3000, "Invalid", "Could not update SEC core because Machine type is not RiscV.");
2364 Status
= GetCoreEntryPointAddress(FvImage
->FileImage
, FvInfo
, SecPe32
, &SecCoreEntryAddress
);
2365 if(EFI_ERROR(Status
)) {
2366 Error(NULL
, 0, 3000, "Invalid", "Could not get the PE32 entry point address for SEC Core.");
2370 VerboseMsg("SecCore entry point Address = 0x%llX", (unsigned long long) SecCoreEntryAddress
);
2371 VerboseMsg("BaseAddress = 0x%llX", (unsigned long long) FvInfo
->BaseAddress
);
2372 bSecCore
= (UINT32
)(SecCoreEntryAddress
- FvInfo
->BaseAddress
);
2373 VerboseMsg("offset = 0x%llX", bSecCore
);
2375 if(bSecCore
> 0x0fffff) {
2376 Error(NULL
, 0, 3000, "Invalid", "SEC Entry point must be within 1MB of start of the FV");
2383 bSecCore
= (tmp
&0x100000)<<11; //imm[20] at bit[31]
2384 bSecCore
|= (tmp
&0x0007FE)<<20; //imm[10:1] at bit[30:21]
2385 bSecCore
|= (tmp
&0x000800)<<9; //imm[11] at bit[20]
2386 bSecCore
|= (tmp
&0x0FF000); //imm[19:12] at bit[19:12]
2387 bSecCore
|= 0x6F; //JAL opcode
2389 memcpy(FvImage
->FileImage
, &bSecCore
, sizeof(bSecCore
));
2397 OUT UINT32
*EntryPoint
,
2398 OUT UINT32
*BaseOfCode
,
2399 OUT UINT16
*MachineType
2403 Routine Description:
2405 Retrieves the PE32 entry point offset and machine type from PE image or TeImage.
2406 See EfiImage.h for machine types. The entry point offset is from the beginning
2407 of the PE32 buffer passed in.
2411 Pe32 Beginning of the PE32.
2412 EntryPoint Offset from the beginning of the PE32 to the image entry point.
2413 BaseOfCode Base address of code.
2414 MachineType Magic number for the machine type.
2418 EFI_SUCCESS Function completed successfully.
2419 EFI_ABORTED Error encountered.
2420 EFI_INVALID_PARAMETER A required parameter was NULL.
2421 EFI_UNSUPPORTED The operation is unsupported.
2425 EFI_IMAGE_DOS_HEADER
*DosHeader
;
2426 EFI_IMAGE_OPTIONAL_HEADER_UNION
*ImgHdr
;
2427 EFI_TE_IMAGE_HEADER
*TeHeader
;
2430 // Verify input parameters
2433 return EFI_INVALID_PARAMETER
;
2437 // First check whether it is one TE Image.
2439 TeHeader
= (EFI_TE_IMAGE_HEADER
*) Pe32
;
2440 if (TeHeader
->Signature
== EFI_TE_IMAGE_HEADER_SIGNATURE
) {
2442 // By TeImage Header to get output
2444 *EntryPoint
= TeHeader
->AddressOfEntryPoint
+ sizeof (EFI_TE_IMAGE_HEADER
) - TeHeader
->StrippedSize
;
2445 *BaseOfCode
= TeHeader
->BaseOfCode
+ sizeof (EFI_TE_IMAGE_HEADER
) - TeHeader
->StrippedSize
;
2446 *MachineType
= TeHeader
->Machine
;
2450 // Then check whether
2451 // First is the DOS header
2453 DosHeader
= (EFI_IMAGE_DOS_HEADER
*) Pe32
;
2456 // Verify DOS header is expected
2458 if (DosHeader
->e_magic
!= EFI_IMAGE_DOS_SIGNATURE
) {
2459 Error (NULL
, 0, 3000, "Invalid", "Unknown magic number in the DOS header, 0x%04X.", DosHeader
->e_magic
);
2460 return EFI_UNSUPPORTED
;
2463 // Immediately following is the NT header.
2465 ImgHdr
= (EFI_IMAGE_OPTIONAL_HEADER_UNION
*) ((UINTN
) Pe32
+ DosHeader
->e_lfanew
);
2468 // Verify NT header is expected
2470 if (ImgHdr
->Pe32
.Signature
!= EFI_IMAGE_NT_SIGNATURE
) {
2471 Error (NULL
, 0, 3000, "Invalid", "Unrecognized image signature 0x%08X.", (unsigned) ImgHdr
->Pe32
.Signature
);
2472 return EFI_UNSUPPORTED
;
2477 *EntryPoint
= ImgHdr
->Pe32
.OptionalHeader
.AddressOfEntryPoint
;
2478 *BaseOfCode
= ImgHdr
->Pe32
.OptionalHeader
.BaseOfCode
;
2479 *MachineType
= ImgHdr
->Pe32
.FileHeader
.Machine
;
2483 // Verify machine type is supported
2485 if ((*MachineType
!= EFI_IMAGE_MACHINE_IA32
) && (*MachineType
!= EFI_IMAGE_MACHINE_X64
) && (*MachineType
!= EFI_IMAGE_MACHINE_EBC
) &&
2486 (*MachineType
!= EFI_IMAGE_MACHINE_ARMT
) && (*MachineType
!= EFI_IMAGE_MACHINE_AARCH64
) &&
2487 (*MachineType
!= EFI_IMAGE_MACHINE_RISCV64
)) {
2488 Error (NULL
, 0, 3000, "Invalid", "Unrecognized machine type in the PE32 file.");
2489 return EFI_UNSUPPORTED
;
2497 IN CHAR8
*InfFileImage
,
2498 IN UINTN InfFileSize
,
2499 IN CHAR8
*FvFileName
,
2500 IN CHAR8
*MapFileName
2504 Routine Description:
2506 This is the main function which will be called from application.
2510 InfFileImage Buffer containing the INF file contents.
2511 InfFileSize Size of the contents of the InfFileImage buffer.
2512 FvFileName Requested name for the FV file.
2513 MapFileName Fv map file to log fv driver information.
2517 EFI_SUCCESS Function completed successfully.
2518 EFI_OUT_OF_RESOURCES Could not allocate required resources.
2519 EFI_ABORTED Error encountered.
2520 EFI_INVALID_PARAMETER A required parameter was NULL.
2525 MEMORY_FILE InfMemoryFile
;
2526 MEMORY_FILE FvImageMemoryFile
;
2528 EFI_FIRMWARE_VOLUME_HEADER
*FvHeader
;
2529 EFI_FFS_FILE_HEADER
*VtfFileImage
;
2530 UINT8
*FvBufferHeader
; // to make sure fvimage header 8 type alignment.
2536 EFI_FIRMWARE_VOLUME_EXT_HEADER
*FvExtHeader
;
2537 FILE *FvExtHeaderFile
;
2539 CHAR8
*FvReportName
;
2542 FvBufferHeader
= NULL
;
2546 FvReportName
= NULL
;
2547 FvReportFile
= NULL
;
2549 if (InfFileImage
!= NULL
) {
2551 // Initialize file structures
2553 InfMemoryFile
.FileImage
= InfFileImage
;
2554 InfMemoryFile
.CurrentFilePointer
= InfFileImage
;
2555 InfMemoryFile
.Eof
= InfFileImage
+ InfFileSize
;
2558 // Parse the FV inf file for header information
2560 Status
= ParseFvInf (&InfMemoryFile
, &mFvDataInfo
);
2561 if (EFI_ERROR (Status
)) {
2562 Error (NULL
, 0, 0003, "Error parsing file", "the input FV INF file.");
2568 // Update the file name return values
2570 if (FvFileName
== NULL
&& mFvDataInfo
.FvName
[0] != '\0') {
2571 FvFileName
= mFvDataInfo
.FvName
;
2574 if (FvFileName
== NULL
) {
2575 Error (NULL
, 0, 1001, "Missing option", "Output file name");
2579 if (mFvDataInfo
.FvBlocks
[0].Length
== 0) {
2580 Error (NULL
, 0, 1001, "Missing required argument", "Block Size");
2585 // Debug message Fv File System Guid
2587 if (mFvDataInfo
.FvFileSystemGuidSet
) {
2588 DebugMsg (NULL
, 0, 9, "FV File System Guid", "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X",
2589 (unsigned) mFvDataInfo
.FvFileSystemGuid
.Data1
,
2590 mFvDataInfo
.FvFileSystemGuid
.Data2
,
2591 mFvDataInfo
.FvFileSystemGuid
.Data3
,
2592 mFvDataInfo
.FvFileSystemGuid
.Data4
[0],
2593 mFvDataInfo
.FvFileSystemGuid
.Data4
[1],
2594 mFvDataInfo
.FvFileSystemGuid
.Data4
[2],
2595 mFvDataInfo
.FvFileSystemGuid
.Data4
[3],
2596 mFvDataInfo
.FvFileSystemGuid
.Data4
[4],
2597 mFvDataInfo
.FvFileSystemGuid
.Data4
[5],
2598 mFvDataInfo
.FvFileSystemGuid
.Data4
[6],
2599 mFvDataInfo
.FvFileSystemGuid
.Data4
[7]);
2603 // Add PI FV extension header
2606 FvExtHeaderFile
= NULL
;
2607 if (mFvDataInfo
.FvExtHeaderFile
[0] != 0) {
2609 // Open the FV Extension Header file
2611 FvExtHeaderFile
= fopen (LongFilePath (mFvDataInfo
.FvExtHeaderFile
), "rb");
2612 if (FvExtHeaderFile
== NULL
) {
2613 Error (NULL
, 0, 0001, "Error opening file", mFvDataInfo
.FvExtHeaderFile
);
2618 // Get the file size
2620 FileSize
= _filelength (fileno (FvExtHeaderFile
));
2623 // Allocate a buffer for the FV Extension Header
2625 FvExtHeader
= malloc(FileSize
);
2626 if (FvExtHeader
== NULL
) {
2627 fclose (FvExtHeaderFile
);
2628 return EFI_OUT_OF_RESOURCES
;
2632 // Read the FV Extension Header
2634 fread (FvExtHeader
, sizeof (UINT8
), FileSize
, FvExtHeaderFile
);
2635 fclose (FvExtHeaderFile
);
2638 // See if there is an override for the FV Name GUID
2640 if (mFvDataInfo
.FvNameGuidSet
) {
2641 memcpy (&FvExtHeader
->FvName
, &mFvDataInfo
.FvNameGuid
, sizeof (EFI_GUID
));
2643 memcpy (&mFvDataInfo
.FvNameGuid
, &FvExtHeader
->FvName
, sizeof (EFI_GUID
));
2644 mFvDataInfo
.FvNameGuidSet
= TRUE
;
2645 } else if (mFvDataInfo
.FvNameGuidSet
) {
2647 // Allocate a buffer for the FV Extension Header
2649 FvExtHeader
= malloc(sizeof (EFI_FIRMWARE_VOLUME_EXT_HEADER
));
2650 if (FvExtHeader
== NULL
) {
2651 return EFI_OUT_OF_RESOURCES
;
2653 memcpy (&FvExtHeader
->FvName
, &mFvDataInfo
.FvNameGuid
, sizeof (EFI_GUID
));
2654 FvExtHeader
->ExtHeaderSize
= sizeof (EFI_FIRMWARE_VOLUME_EXT_HEADER
);
2658 // Debug message Fv Name Guid
2660 if (mFvDataInfo
.FvNameGuidSet
) {
2661 DebugMsg (NULL
, 0, 9, "FV Name Guid", "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X",
2662 (unsigned) mFvDataInfo
.FvNameGuid
.Data1
,
2663 mFvDataInfo
.FvNameGuid
.Data2
,
2664 mFvDataInfo
.FvNameGuid
.Data3
,
2665 mFvDataInfo
.FvNameGuid
.Data4
[0],
2666 mFvDataInfo
.FvNameGuid
.Data4
[1],
2667 mFvDataInfo
.FvNameGuid
.Data4
[2],
2668 mFvDataInfo
.FvNameGuid
.Data4
[3],
2669 mFvDataInfo
.FvNameGuid
.Data4
[4],
2670 mFvDataInfo
.FvNameGuid
.Data4
[5],
2671 mFvDataInfo
.FvNameGuid
.Data4
[6],
2672 mFvDataInfo
.FvNameGuid
.Data4
[7]);
2675 if (CompareGuid (&mFvDataInfo
.FvFileSystemGuid
, &mEfiFirmwareFileSystem2Guid
) == 0 ||
2676 CompareGuid (&mFvDataInfo
.FvFileSystemGuid
, &mEfiFirmwareFileSystem3Guid
) == 0) {
2677 mFvDataInfo
.IsPiFvImage
= TRUE
;
2681 // FvMap file to log the function address of all modules in one Fvimage
2683 if (MapFileName
!= NULL
) {
2684 if (strlen (MapFileName
) > MAX_LONG_FILE_PATH
- 1) {
2685 Error (NULL
, 0, 1003, "Invalid option value", "MapFileName %s is too long!", MapFileName
);
2686 Status
= EFI_ABORTED
;
2690 FvMapName
= malloc (strlen (MapFileName
) + 1);
2691 if (FvMapName
== NULL
) {
2692 Error (NULL
, 0, 4001, "Resource", "memory cannot be allocated!");
2693 Status
= EFI_OUT_OF_RESOURCES
;
2697 strcpy (FvMapName
, MapFileName
);
2699 if (strlen (FvFileName
) + strlen (".map") > MAX_LONG_FILE_PATH
- 1) {
2700 Error (NULL
, 0, 1003, "Invalid option value", "FvFileName %s is too long!", FvFileName
);
2701 Status
= EFI_ABORTED
;
2705 FvMapName
= malloc (strlen (FvFileName
) + strlen (".map") + 1);
2706 if (FvMapName
== NULL
) {
2707 Error (NULL
, 0, 4001, "Resource", "memory cannot be allocated!");
2708 Status
= EFI_OUT_OF_RESOURCES
;
2712 strcpy (FvMapName
, FvFileName
);
2713 strcat (FvMapName
, ".map");
2715 VerboseMsg ("FV Map file name is %s", FvMapName
);
2718 // FvReport file to log the FV information in one Fvimage
2720 if (strlen (FvFileName
) + strlen (".txt") > MAX_LONG_FILE_PATH
- 1) {
2721 Error (NULL
, 0, 1003, "Invalid option value", "FvFileName %s is too long!", FvFileName
);
2722 Status
= EFI_ABORTED
;
2726 FvReportName
= malloc (strlen (FvFileName
) + strlen (".txt") + 1);
2727 if (FvReportName
== NULL
) {
2728 Error (NULL
, 0, 4001, "Resource", "memory cannot be allocated!");
2729 Status
= EFI_OUT_OF_RESOURCES
;
2733 strcpy (FvReportName
, FvFileName
);
2734 strcat (FvReportName
, ".txt");
2737 // Calculate the FV size and Update Fv Size based on the actual FFS files.
2738 // And Update mFvDataInfo data.
2740 Status
= CalculateFvSize (&mFvDataInfo
);
2741 if (EFI_ERROR (Status
)) {
2744 VerboseMsg ("the generated FV image size is %u bytes", (unsigned) mFvDataInfo
.Size
);
2747 // support fv image and empty fv image
2749 FvImageSize
= mFvDataInfo
.Size
;
2752 // Allocate the FV, assure FvImage Header 8 byte alignment
2754 FvBufferHeader
= malloc (FvImageSize
+ sizeof (UINT64
));
2755 if (FvBufferHeader
== NULL
) {
2756 Status
= EFI_OUT_OF_RESOURCES
;
2759 FvImage
= (UINT8
*) (((UINTN
) FvBufferHeader
+ 7) & ~7);
2762 // Initialize the FV to the erase polarity
2764 if (mFvDataInfo
.FvAttributes
== 0) {
2766 // Set Default Fv Attribute
2768 mFvDataInfo
.FvAttributes
= FV_DEFAULT_ATTRIBUTE
;
2770 if (mFvDataInfo
.FvAttributes
& EFI_FVB2_ERASE_POLARITY
) {
2771 memset (FvImage
, -1, FvImageSize
);
2773 memset (FvImage
, 0, FvImageSize
);
2777 // Initialize FV header
2779 FvHeader
= (EFI_FIRMWARE_VOLUME_HEADER
*) FvImage
;
2782 // Initialize the zero vector to all zeros.
2784 memset (FvHeader
->ZeroVector
, 0, 16);
2787 // Copy the Fv file system GUID
2789 memcpy (&FvHeader
->FileSystemGuid
, &mFvDataInfo
.FvFileSystemGuid
, sizeof (EFI_GUID
));
2791 FvHeader
->FvLength
= FvImageSize
;
2792 FvHeader
->Signature
= EFI_FVH_SIGNATURE
;
2793 FvHeader
->Attributes
= mFvDataInfo
.FvAttributes
;
2794 FvHeader
->Revision
= EFI_FVH_REVISION
;
2795 FvHeader
->ExtHeaderOffset
= 0;
2796 FvHeader
->Reserved
[0] = 0;
2799 // Copy firmware block map
2801 for (Index
= 0; mFvDataInfo
.FvBlocks
[Index
].Length
!= 0; Index
++) {
2802 FvHeader
->BlockMap
[Index
].NumBlocks
= mFvDataInfo
.FvBlocks
[Index
].NumBlocks
;
2803 FvHeader
->BlockMap
[Index
].Length
= mFvDataInfo
.FvBlocks
[Index
].Length
;
2807 // Add block map terminator
2809 FvHeader
->BlockMap
[Index
].NumBlocks
= 0;
2810 FvHeader
->BlockMap
[Index
].Length
= 0;
2813 // Complete the header
2815 FvHeader
->HeaderLength
= (UINT16
) (((UINTN
) &(FvHeader
->BlockMap
[Index
+ 1])) - (UINTN
) FvImage
);
2816 FvHeader
->Checksum
= 0;
2817 FvHeader
->Checksum
= CalculateChecksum16 ((UINT16
*) FvHeader
, FvHeader
->HeaderLength
/ sizeof (UINT16
));
2820 // If there is no FFS file, generate one empty FV
2822 if (mFvDataInfo
.FvFiles
[0][0] == 0 && !mFvDataInfo
.FvNameGuidSet
) {
2827 // Initialize our "file" view of the buffer
2829 FvImageMemoryFile
.FileImage
= (CHAR8
*)FvImage
;
2830 FvImageMemoryFile
.CurrentFilePointer
= (CHAR8
*)FvImage
+ FvHeader
->HeaderLength
;
2831 FvImageMemoryFile
.Eof
= (CHAR8
*)FvImage
+ FvImageSize
;
2834 // Initialize the FV library.
2836 InitializeFvLib (FvImageMemoryFile
.FileImage
, FvImageSize
);
2839 // Initialize the VTF file address.
2841 VtfFileImage
= (EFI_FFS_FILE_HEADER
*) FvImageMemoryFile
.Eof
;
2846 FvMapFile
= fopen (LongFilePath (FvMapName
), "w");
2847 if (FvMapFile
== NULL
) {
2848 Error (NULL
, 0, 0001, "Error opening file", FvMapName
);
2849 Status
= EFI_ABORTED
;
2854 // Open FvReport file
2856 FvReportFile
= fopen (LongFilePath (FvReportName
), "w");
2857 if (FvReportFile
== NULL
) {
2858 Error (NULL
, 0, 0001, "Error opening file", FvReportName
);
2859 Status
= EFI_ABORTED
;
2863 // record FV size information into FvMap file.
2865 if (mFvTotalSize
!= 0) {
2866 fprintf (FvMapFile
, EFI_FV_TOTAL_SIZE_STRING
);
2867 fprintf (FvMapFile
, " = 0x%x\n", (unsigned) mFvTotalSize
);
2869 if (mFvTakenSize
!= 0) {
2870 fprintf (FvMapFile
, EFI_FV_TAKEN_SIZE_STRING
);
2871 fprintf (FvMapFile
, " = 0x%x\n", (unsigned) mFvTakenSize
);
2873 if (mFvTotalSize
!= 0 && mFvTakenSize
!= 0) {
2874 fprintf (FvMapFile
, EFI_FV_SPACE_SIZE_STRING
);
2875 fprintf (FvMapFile
, " = 0x%x\n\n", (unsigned) (mFvTotalSize
- mFvTakenSize
));
2879 // record FV size information to FvReportFile.
2881 fprintf (FvReportFile
, "%s = 0x%x\n", EFI_FV_TOTAL_SIZE_STRING
, (unsigned) mFvTotalSize
);
2882 fprintf (FvReportFile
, "%s = 0x%x\n", EFI_FV_TAKEN_SIZE_STRING
, (unsigned) mFvTakenSize
);
2885 // Add PI FV extension header
2887 if (FvExtHeader
!= NULL
) {
2889 // Add FV Extended Header contents to the FV as a PAD file
2891 AddPadFile (&FvImageMemoryFile
, 4, VtfFileImage
, FvExtHeader
, 0);
2894 // Fv Extension header change update Fv Header Check sum
2896 FvHeader
->Checksum
= 0;
2897 FvHeader
->Checksum
= CalculateChecksum16 ((UINT16
*) FvHeader
, FvHeader
->HeaderLength
/ sizeof (UINT16
));
2903 for (Index
= 0; mFvDataInfo
.FvFiles
[Index
][0] != 0; Index
++) {
2907 Status
= AddFile (&FvImageMemoryFile
, &mFvDataInfo
, Index
, &VtfFileImage
, FvMapFile
, FvReportFile
);
2910 // Exit if error detected while adding the file
2912 if (EFI_ERROR (Status
)) {
2918 // If there is a VTF file, some special actions need to occur.
2920 if ((UINTN
) VtfFileImage
!= (UINTN
) FvImageMemoryFile
.Eof
) {
2922 // Pad from the end of the last file to the beginning of the VTF file.
2923 // If the left space is less than sizeof (EFI_FFS_FILE_HEADER)?
2925 Status
= PadFvImage (&FvImageMemoryFile
, VtfFileImage
);
2926 if (EFI_ERROR (Status
)) {
2927 Error (NULL
, 0, 4002, "Resource", "FV space is full, cannot add pad file between the last file and the VTF file.");
2931 if (!mArm
&& !mRiscV
) {
2933 // Update reset vector (SALE_ENTRY for IPF)
2934 // Now for IA32 and IA64 platform, the fv which has bsf file must have the
2935 // EndAddress of 0xFFFFFFFF (unless the section was rebased).
2936 // Thus, only this type fv needs to update the reset vector.
2937 // If the PEI Core is found, the VTF file will probably get
2938 // corrupted by updating the entry point.
2940 if (mFvDataInfo
.ForceRebase
== 1 ||
2941 (mFvDataInfo
.BaseAddress
+ mFvDataInfo
.Size
) == FV_IMAGES_TOP_ADDRESS
) {
2942 Status
= UpdateResetVector (&FvImageMemoryFile
, &mFvDataInfo
, VtfFileImage
);
2943 if (EFI_ERROR(Status
)) {
2944 Error (NULL
, 0, 3000, "Invalid", "Could not update the reset vector.");
2947 DebugMsg (NULL
, 0, 9, "Update Reset vector in VTF file", NULL
);
2953 Status
= UpdateArmResetVectorIfNeeded (&FvImageMemoryFile
, &mFvDataInfo
);
2954 if (EFI_ERROR (Status
)) {
2955 Error (NULL
, 0, 3000, "Invalid", "Could not update the reset vector.");
2960 // Update Checksum for FvHeader
2962 FvHeader
->Checksum
= 0;
2963 FvHeader
->Checksum
= CalculateChecksum16 ((UINT16
*) FvHeader
, FvHeader
->HeaderLength
/ sizeof (UINT16
));
2968 // Update RISCV reset vector.
2970 Status
= UpdateRiscvResetVectorIfNeeded (&FvImageMemoryFile
, &mFvDataInfo
);
2971 if (EFI_ERROR (Status
)) {
2972 Error (NULL
, 0, 3000, "Invalid", "Could not update the reset vector for RISC-V.");
2976 // Update Checksum for FvHeader
2978 FvHeader
->Checksum
= 0;
2979 FvHeader
->Checksum
= CalculateChecksum16 ((UINT16
*) FvHeader
, FvHeader
->HeaderLength
/ sizeof (UINT16
));
2983 // Update FV Alignment attribute to the largest alignment of all the FFS files in the FV
2985 if (((FvHeader
->Attributes
& EFI_FVB2_WEAK_ALIGNMENT
) != EFI_FVB2_WEAK_ALIGNMENT
) &&
2986 (((FvHeader
->Attributes
& EFI_FVB2_ALIGNMENT
) >> 16)) < MaxFfsAlignment
) {
2987 FvHeader
->Attributes
= ((MaxFfsAlignment
<< 16) | (FvHeader
->Attributes
& 0xFFFF));
2989 // Update Checksum for FvHeader
2991 FvHeader
->Checksum
= 0;
2992 FvHeader
->Checksum
= CalculateChecksum16 ((UINT16
*) FvHeader
, FvHeader
->HeaderLength
/ sizeof (UINT16
));
2996 // If there are large FFS in FV, the file system GUID should set to system 3 GUID.
2998 if (mIsLargeFfs
&& CompareGuid (&FvHeader
->FileSystemGuid
, &mEfiFirmwareFileSystem2Guid
) == 0) {
2999 memcpy (&FvHeader
->FileSystemGuid
, &mEfiFirmwareFileSystem3Guid
, sizeof (EFI_GUID
));
3000 FvHeader
->Checksum
= 0;
3001 FvHeader
->Checksum
= CalculateChecksum16 ((UINT16
*) FvHeader
, FvHeader
->HeaderLength
/ sizeof (UINT16
));
3008 FvFile
= fopen (LongFilePath (FvFileName
), "wb");
3009 if (FvFile
== NULL
) {
3010 Error (NULL
, 0, 0001, "Error opening file", FvFileName
);
3011 Status
= EFI_ABORTED
;
3015 if (fwrite (FvImage
, 1, FvImageSize
, FvFile
) != FvImageSize
) {
3016 Error (NULL
, 0, 0002, "Error writing file", FvFileName
);
3017 Status
= EFI_ABORTED
;
3022 if (FvBufferHeader
!= NULL
) {
3023 free (FvBufferHeader
);
3026 if (FvExtHeader
!= NULL
) {
3030 if (FvMapName
!= NULL
) {
3034 if (FvReportName
!= NULL
) {
3035 free (FvReportName
);
3038 if (FvFile
!= NULL
) {
3043 if (FvMapFile
!= NULL
) {
3048 if (FvReportFile
!= NULL
) {
3049 fflush (FvReportFile
);
3050 fclose (FvReportFile
);
3056 UpdatePeiCoreEntryInFit (
3057 IN FIT_TABLE
*FitTablePtr
,
3058 IN UINT64 PeiCorePhysicalAddress
3062 Routine Description:
3064 This function is used to update the Pei Core address in FIT, this can be used by Sec core to pass control from
3069 FitTablePtr - The pointer of FIT_TABLE.
3070 PeiCorePhysicalAddress - The address of Pei Core entry.
3074 EFI_SUCCESS - The PEI_CORE FIT entry was updated successfully.
3075 EFI_NOT_FOUND - Not found the PEI_CORE FIT entry.
3079 FIT_TABLE
*TmpFitPtr
;
3081 UINTN NumFitComponents
;
3083 TmpFitPtr
= FitTablePtr
;
3084 NumFitComponents
= TmpFitPtr
->CompSize
;
3086 for (Index
= 0; Index
< NumFitComponents
; Index
++) {
3087 if ((TmpFitPtr
->CvAndType
& FIT_TYPE_MASK
) == COMP_TYPE_FIT_PEICORE
) {
3088 TmpFitPtr
->CompAddress
= PeiCorePhysicalAddress
;
3095 return EFI_NOT_FOUND
;
3100 IN FIT_TABLE
*FitTablePtr
3104 Routine Description:
3106 This function is used to update the checksum for FIT.
3111 FitTablePtr - The pointer of FIT_TABLE.
3119 if ((FitTablePtr
->CvAndType
& CHECKSUM_BIT_MASK
) >> 7) {
3120 FitTablePtr
->CheckSum
= 0;
3121 FitTablePtr
->CheckSum
= CalculateChecksum8 ((UINT8
*) FitTablePtr
, FitTablePtr
->CompSize
* 16);
3130 Routine Description:
3131 Calculate the FV size and Update Fv Size based on the actual FFS files.
3132 And Update FvInfo data.
3135 FvInfoPtr - The pointer to FV_INFO structure.
3138 EFI_ABORTED - Ffs Image Error
3139 EFI_SUCCESS - Successfully update FvSize
3142 UINTN CurrentOffset
;
3146 UINTN FvExtendHeaderSize
;
3147 UINT32 FfsAlignment
;
3148 UINT32 FfsHeaderSize
;
3149 EFI_FFS_FILE_HEADER FfsHeader
;
3152 FvExtendHeaderSize
= 0;
3158 // Compute size for easy access later
3160 FvInfoPtr
->Size
= 0;
3161 for (Index
= 0; FvInfoPtr
->FvBlocks
[Index
].NumBlocks
> 0 && FvInfoPtr
->FvBlocks
[Index
].Length
> 0; Index
++) {
3162 FvInfoPtr
->Size
+= FvInfoPtr
->FvBlocks
[Index
].NumBlocks
* FvInfoPtr
->FvBlocks
[Index
].Length
;
3166 // Calculate the required sizes for all FFS files.
3168 CurrentOffset
= sizeof (EFI_FIRMWARE_VOLUME_HEADER
);
3170 for (Index
= 1;; Index
++) {
3171 CurrentOffset
+= sizeof (EFI_FV_BLOCK_MAP_ENTRY
);
3172 if (FvInfoPtr
->FvBlocks
[Index
].NumBlocks
== 0 || FvInfoPtr
->FvBlocks
[Index
].Length
== 0) {
3178 // Calculate PI extension header
3180 if (mFvDataInfo
.FvExtHeaderFile
[0] != '\0') {
3181 fpin
= fopen (LongFilePath (mFvDataInfo
.FvExtHeaderFile
), "rb");
3183 Error (NULL
, 0, 0001, "Error opening file", mFvDataInfo
.FvExtHeaderFile
);
3186 FvExtendHeaderSize
= _filelength (fileno (fpin
));
3188 if (sizeof (EFI_FFS_FILE_HEADER
) + FvExtendHeaderSize
>= MAX_FFS_SIZE
) {
3189 CurrentOffset
+= sizeof (EFI_FFS_FILE_HEADER2
) + FvExtendHeaderSize
;
3192 CurrentOffset
+= sizeof (EFI_FFS_FILE_HEADER
) + FvExtendHeaderSize
;
3194 CurrentOffset
= (CurrentOffset
+ 7) & (~7);
3195 } else if (mFvDataInfo
.FvNameGuidSet
) {
3196 CurrentOffset
+= sizeof (EFI_FFS_FILE_HEADER
) + sizeof (EFI_FIRMWARE_VOLUME_EXT_HEADER
);
3197 CurrentOffset
= (CurrentOffset
+ 7) & (~7);
3201 // Accumulate every FFS file size.
3203 for (Index
= 0; FvInfoPtr
->FvFiles
[Index
][0] != 0; Index
++) {
3208 fpin
= fopen (LongFilePath (FvInfoPtr
->FvFiles
[Index
]), "rb");
3210 Error (NULL
, 0, 0001, "Error opening file", FvInfoPtr
->FvFiles
[Index
]);
3214 // Get the file size
3216 FfsFileSize
= _filelength (fileno (fpin
));
3217 if (FfsFileSize
>= MAX_FFS_SIZE
) {
3218 FfsHeaderSize
= sizeof(EFI_FFS_FILE_HEADER2
);
3221 FfsHeaderSize
= sizeof(EFI_FFS_FILE_HEADER
);
3224 // Read Ffs File header
3226 fread (&FfsHeader
, sizeof (UINT8
), sizeof (EFI_FFS_FILE_HEADER
), fpin
);
3232 if (FvInfoPtr
->IsPiFvImage
) {
3234 // Check whether this ffs file is vtf file
3236 if (IsVtfFile (&FfsHeader
)) {
3239 // One Fv image can't have two vtf files.
3241 Error (NULL
, 0, 3000,"Invalid", "One Fv image can't have two vtf files.");
3245 VtfFileSize
= FfsFileSize
;
3250 // Get the alignment of FFS file
3252 ReadFfsAlignment (&FfsHeader
, &FfsAlignment
);
3253 FfsAlignment
= 1 << FfsAlignment
;
3257 if (((CurrentOffset
+ FfsHeaderSize
) % FfsAlignment
) != 0) {
3259 // Only EFI_FFS_FILE_HEADER is needed for a pad section.
3261 CurrentOffset
= (CurrentOffset
+ FfsHeaderSize
+ sizeof(EFI_FFS_FILE_HEADER
) + FfsAlignment
- 1) & ~(FfsAlignment
- 1);
3262 CurrentOffset
-= FfsHeaderSize
;
3267 // Add ffs file size
3269 if (FvInfoPtr
->SizeofFvFiles
[Index
] > FfsFileSize
) {
3270 CurrentOffset
+= FvInfoPtr
->SizeofFvFiles
[Index
];
3272 CurrentOffset
+= FfsFileSize
;
3276 // Make next ffs file start at QWord Boundary
3278 if (FvInfoPtr
->IsPiFvImage
) {
3279 CurrentOffset
= (CurrentOffset
+ EFI_FFS_FILE_HEADER_ALIGNMENT
- 1) & ~(EFI_FFS_FILE_HEADER_ALIGNMENT
- 1);
3282 CurrentOffset
+= VtfFileSize
;
3283 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
);
3285 if (FvInfoPtr
->Size
== 0) {
3287 // Update FvInfo data
3289 FvInfoPtr
->FvBlocks
[0].NumBlocks
= CurrentOffset
/ FvInfoPtr
->FvBlocks
[0].Length
+ ((CurrentOffset
% FvInfoPtr
->FvBlocks
[0].Length
)?1:0);
3290 FvInfoPtr
->Size
= FvInfoPtr
->FvBlocks
[0].NumBlocks
* FvInfoPtr
->FvBlocks
[0].Length
;
3291 FvInfoPtr
->FvBlocks
[1].NumBlocks
= 0;
3292 FvInfoPtr
->FvBlocks
[1].Length
= 0;
3293 } else if (FvInfoPtr
->Size
< CurrentOffset
) {
3297 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
);
3298 return EFI_INVALID_PARAMETER
;
3302 // Set Fv Size Information
3304 mFvTotalSize
= FvInfoPtr
->Size
;
3305 mFvTakenSize
= CurrentOffset
;
3311 FfsRebaseImageRead (
3312 IN VOID
*FileHandle
,
3313 IN UINTN FileOffset
,
3314 IN OUT UINT32
*ReadSize
,
3319 Routine Description:
3321 Support routine for the PE/COFF Loader that reads a buffer from a PE/COFF file
3325 FileHandle - The handle to the PE/COFF file
3327 FileOffset - The offset, in bytes, into the file to read
3329 ReadSize - The number of bytes to read from the file starting at FileOffset
3331 Buffer - A pointer to the buffer to read the data into.
3335 EFI_SUCCESS - ReadSize bytes of data were read into Buffer from the PE/COFF file starting at FileOffset
3339 CHAR8
*Destination8
;
3343 Destination8
= Buffer
;
3344 Source8
= (CHAR8
*) ((UINTN
) FileHandle
+ FileOffset
);
3347 *(Destination8
++) = *(Source8
++);
3356 IN EFI_FFS_FILE_HEADER
*FfsFile
,
3361 Routine Description:
3363 This function gets all child FvImages in the input FfsFile, and records
3364 their base address to the parent image.
3367 FvInfo A pointer to FV_INFO structure.
3368 FfsFile A pointer to Ffs file image that may contain FvImage.
3369 XipOffset The offset address to the parent FvImage base.
3373 EFI_SUCCESS Base address of child Fv image is recorded.
3378 EFI_FILE_SECTION_POINTER SubFvSection
;
3379 EFI_FIRMWARE_VOLUME_HEADER
*SubFvImageHeader
;
3380 EFI_PHYSICAL_ADDRESS SubFvBaseAddress
;
3381 EFI_FILE_SECTION_POINTER CorePe32
;
3384 for (Index
= 1;; Index
++) {
3388 Status
= GetSectionByType (FfsFile
, EFI_SECTION_FIRMWARE_VOLUME_IMAGE
, Index
, &SubFvSection
);
3389 if (EFI_ERROR (Status
)) {
3392 SubFvImageHeader
= (EFI_FIRMWARE_VOLUME_HEADER
*) ((UINT8
*) SubFvSection
.FVImageSection
+ GetSectionHeaderLength(SubFvSection
.FVImageSection
));
3395 // See if there's an SEC core in the child FV
3396 Status
= FindCorePeSection(SubFvImageHeader
, SubFvImageHeader
->FvLength
, EFI_FV_FILETYPE_SECURITY_CORE
, &CorePe32
);
3398 // if we couldn't find the SEC core, look for a PEI core
3399 if (EFI_ERROR(Status
)) {
3400 Status
= FindCorePeSection(SubFvImageHeader
, SubFvImageHeader
->FvLength
, EFI_FV_FILETYPE_PEI_CORE
, &CorePe32
);
3403 if (!EFI_ERROR(Status
)) {
3404 Status
= GetCoreMachineType(CorePe32
, &MachineType
);
3405 if (EFI_ERROR(Status
)) {
3406 Error(NULL
, 0, 3000, "Invalid", "Could not get the PE32 machine type for SEC/PEI Core.");
3410 // machine type is ARM, set a flag so ARM reset vector processing occurs
3411 if ((MachineType
== EFI_IMAGE_MACHINE_ARMT
) || (MachineType
== EFI_IMAGE_MACHINE_AARCH64
)) {
3412 VerboseMsg("Located ARM/AArch64 SEC/PEI core in child FV");
3420 SubFvBaseAddress
= FvInfo
->BaseAddress
+ (UINTN
) SubFvImageHeader
- (UINTN
) FfsFile
+ XipOffset
;
3421 mFvBaseAddress
[mFvBaseAddressNumber
++ ] = SubFvBaseAddress
;
3429 IN OUT FV_INFO
*FvInfo
,
3431 IN OUT EFI_FFS_FILE_HEADER
*FfsFile
,
3437 Routine Description:
3439 This function determines if a file is XIP and should be rebased. It will
3440 rebase any PE32 sections found in the file using the base address.
3444 FvInfo A pointer to FV_INFO structure.
3445 FileName Ffs File PathName
3446 FfsFile A pointer to Ffs file image.
3447 XipOffset The offset address to use for rebasing the XIP file image.
3448 FvMapFile FvMapFile to record the function address in one Fvimage
3452 EFI_SUCCESS The image was properly rebased.
3453 EFI_INVALID_PARAMETER An input parameter is invalid.
3454 EFI_ABORTED An error occurred while rebasing the input file image.
3455 EFI_OUT_OF_RESOURCES Could not allocate a required resource.
3456 EFI_NOT_FOUND No compressed sections could be found.
3461 PE_COFF_LOADER_IMAGE_CONTEXT ImageContext
;
3462 PE_COFF_LOADER_IMAGE_CONTEXT OrigImageContext
;
3463 EFI_PHYSICAL_ADDRESS XipBase
;
3464 EFI_PHYSICAL_ADDRESS NewPe32BaseAddress
;
3466 EFI_FILE_SECTION_POINTER CurrentPe32Section
;
3467 EFI_FFS_FILE_STATE SavedState
;
3468 EFI_IMAGE_OPTIONAL_HEADER_UNION
*ImgHdr
;
3469 EFI_TE_IMAGE_HEADER
*TEImageHeader
;
3470 UINT8
*MemoryImagePointer
;
3471 EFI_IMAGE_SECTION_HEADER
*SectionHeader
;
3472 CHAR8 PeFileName
[MAX_LONG_FILE_PATH
];
3475 UINT8
*PeFileBuffer
;
3478 UINT32 FfsHeaderSize
;
3479 UINT32 CurSecHdrSize
;
3482 MemoryImagePointer
= NULL
;
3483 TEImageHeader
= NULL
;
3485 SectionHeader
= NULL
;
3488 PeFileBuffer
= NULL
;
3491 // Don't need to relocate image when BaseAddress is zero and no ForceRebase Flag specified.
3493 if ((FvInfo
->BaseAddress
== 0) && (FvInfo
->ForceRebase
== -1)) {
3498 // If ForceRebase Flag specified to FALSE, will always not take rebase action.
3500 if (FvInfo
->ForceRebase
== 0) {
3505 XipBase
= FvInfo
->BaseAddress
+ XipOffset
;
3508 // We only process files potentially containing PE32 sections.
3510 switch (FfsFile
->Type
) {
3511 case EFI_FV_FILETYPE_SECURITY_CORE
:
3512 case EFI_FV_FILETYPE_PEI_CORE
:
3513 case EFI_FV_FILETYPE_PEIM
:
3514 case EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER
:
3515 case EFI_FV_FILETYPE_DRIVER
:
3516 case EFI_FV_FILETYPE_DXE_CORE
:
3518 case EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE
:
3520 // Rebase the inside FvImage.
3522 GetChildFvFromFfs (FvInfo
, FfsFile
, XipOffset
);
3525 // Search PE/TE section in FV sectin.
3532 FfsHeaderSize
= GetFfsHeaderLength(FfsFile
);
3534 // Rebase each PE32 section
3536 Status
= EFI_SUCCESS
;
3537 for (Index
= 1;; Index
++) {
3541 NewPe32BaseAddress
= 0;
3546 Status
= GetSectionByType (FfsFile
, EFI_SECTION_PE32
, Index
, &CurrentPe32Section
);
3547 if (EFI_ERROR (Status
)) {
3550 CurSecHdrSize
= GetSectionHeaderLength(CurrentPe32Section
.CommonHeader
);
3553 // Initialize context
3555 memset (&ImageContext
, 0, sizeof (ImageContext
));
3556 ImageContext
.Handle
= (VOID
*) ((UINTN
) CurrentPe32Section
.Pe32Section
+ CurSecHdrSize
);
3557 ImageContext
.ImageRead
= (PE_COFF_LOADER_READ_FILE
) FfsRebaseImageRead
;
3558 Status
= PeCoffLoaderGetImageInfo (&ImageContext
);
3559 if (EFI_ERROR (Status
)) {
3560 Error (NULL
, 0, 3000, "Invalid PeImage", "The input file is %s and the return status is %x", FileName
, (int) Status
);
3564 if ( (ImageContext
.Machine
== EFI_IMAGE_MACHINE_ARMT
) ||
3565 (ImageContext
.Machine
== EFI_IMAGE_MACHINE_AARCH64
) ) {
3569 if (ImageContext
.Machine
== EFI_IMAGE_MACHINE_RISCV64
) {
3574 // Keep Image Context for PE image in FV
3576 memcpy (&OrigImageContext
, &ImageContext
, sizeof (ImageContext
));
3579 // Get File PdbPointer
3581 PdbPointer
= PeCoffLoaderGetPdbPointer (ImageContext
.Handle
);
3584 // Get PeHeader pointer
3586 ImgHdr
= (EFI_IMAGE_OPTIONAL_HEADER_UNION
*)((UINTN
) CurrentPe32Section
.Pe32Section
+ CurSecHdrSize
+ ImageContext
.PeCoffHeaderOffset
);
3589 // Calculate the PE32 base address, based on file type
3591 switch (FfsFile
->Type
) {
3592 case EFI_FV_FILETYPE_SECURITY_CORE
:
3593 case EFI_FV_FILETYPE_PEI_CORE
:
3594 case EFI_FV_FILETYPE_PEIM
:
3595 case EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER
:
3597 // Check if section-alignment and file-alignment match or not
3599 if ((ImgHdr
->Pe32
.OptionalHeader
.SectionAlignment
!= ImgHdr
->Pe32
.OptionalHeader
.FileAlignment
)) {
3601 // Xip module has the same section alignment and file alignment.
3603 Error (NULL
, 0, 3000, "Invalid", "PE image Section-Alignment and File-Alignment do not match : %s.", FileName
);
3607 // PeImage has no reloc section. It will try to get reloc data from the original EFI image.
3609 if (ImageContext
.RelocationsStripped
) {
3611 // Construct the original efi file Name
3613 if (strlen (FileName
) >= MAX_LONG_FILE_PATH
) {
3614 Error (NULL
, 0, 2000, "Invalid", "The file name %s is too long.", FileName
);
3617 strncpy (PeFileName
, FileName
, MAX_LONG_FILE_PATH
- 1);
3618 PeFileName
[MAX_LONG_FILE_PATH
- 1] = 0;
3619 Cptr
= PeFileName
+ strlen (PeFileName
);
3620 while (*Cptr
!= '.') {
3624 Error (NULL
, 0, 3000, "Invalid", "The file %s has no .reloc section.", FileName
);
3632 PeFile
= fopen (LongFilePath (PeFileName
), "rb");
3633 if (PeFile
== NULL
) {
3634 Warning (NULL
, 0, 0, "Invalid", "The file %s has no .reloc section.", FileName
);
3635 //Error (NULL, 0, 3000, "Invalid", "The file %s has no .reloc section.", FileName);
3636 //return EFI_ABORTED;
3640 // Get the file size
3642 PeFileSize
= _filelength (fileno (PeFile
));
3643 PeFileBuffer
= (UINT8
*) malloc (PeFileSize
);
3644 if (PeFileBuffer
== NULL
) {
3646 Error (NULL
, 0, 4001, "Resource", "memory cannot be allocated on rebase of %s", FileName
);
3647 return EFI_OUT_OF_RESOURCES
;
3652 fread (PeFileBuffer
, sizeof (UINT8
), PeFileSize
, PeFile
);
3658 // Handle pointer to the original efi image.
3660 ImageContext
.Handle
= PeFileBuffer
;
3661 Status
= PeCoffLoaderGetImageInfo (&ImageContext
);
3662 if (EFI_ERROR (Status
)) {
3663 Error (NULL
, 0, 3000, "Invalid PeImage", "The input file is %s and the return status is %x", FileName
, (int) Status
);
3666 ImageContext
.RelocationsStripped
= FALSE
;
3669 NewPe32BaseAddress
= XipBase
+ (UINTN
) CurrentPe32Section
.Pe32Section
+ CurSecHdrSize
- (UINTN
)FfsFile
;
3672 case EFI_FV_FILETYPE_DRIVER
:
3673 case EFI_FV_FILETYPE_DXE_CORE
:
3675 // Check if section-alignment and file-alignment match or not
3677 if ((ImgHdr
->Pe32
.OptionalHeader
.SectionAlignment
!= ImgHdr
->Pe32
.OptionalHeader
.FileAlignment
)) {
3679 // Xip module has the same section alignment and file alignment.
3681 Error (NULL
, 0, 3000, "Invalid", "PE image Section-Alignment and File-Alignment do not match : %s.", FileName
);
3684 NewPe32BaseAddress
= XipBase
+ (UINTN
) CurrentPe32Section
.Pe32Section
+ CurSecHdrSize
- (UINTN
)FfsFile
;
3689 // Not supported file type
3695 // Relocation doesn't exist
3697 if (ImageContext
.RelocationsStripped
) {
3698 Warning (NULL
, 0, 0, "Invalid", "The file %s has no .reloc section.", FileName
);
3703 // Relocation exist and rebase
3706 // Load and Relocate Image Data
3708 MemoryImagePointer
= (UINT8
*) malloc ((UINTN
) ImageContext
.ImageSize
+ ImageContext
.SectionAlignment
);
3709 if (MemoryImagePointer
== NULL
) {
3710 Error (NULL
, 0, 4001, "Resource", "memory cannot be allocated on rebase of %s", FileName
);
3711 return EFI_OUT_OF_RESOURCES
;
3713 memset ((VOID
*) MemoryImagePointer
, 0, (UINTN
) ImageContext
.ImageSize
+ ImageContext
.SectionAlignment
);
3714 ImageContext
.ImageAddress
= ((UINTN
) MemoryImagePointer
+ ImageContext
.SectionAlignment
- 1) & (~((UINTN
) ImageContext
.SectionAlignment
- 1));
3716 Status
= PeCoffLoaderLoadImage (&ImageContext
);
3717 if (EFI_ERROR (Status
)) {
3718 Error (NULL
, 0, 3000, "Invalid", "LocateImage() call failed on rebase of %s", FileName
);
3719 free ((VOID
*) MemoryImagePointer
);
3723 ImageContext
.DestinationAddress
= NewPe32BaseAddress
;
3724 Status
= PeCoffLoaderRelocateImage (&ImageContext
);
3725 if (EFI_ERROR (Status
)) {
3726 Error (NULL
, 0, 3000, "Invalid", "RelocateImage() call failed on rebase of %s Status=%d", FileName
, Status
);
3727 free ((VOID
*) MemoryImagePointer
);
3732 // Copy Relocated data to raw image file.
3734 SectionHeader
= (EFI_IMAGE_SECTION_HEADER
*) (
3737 sizeof (EFI_IMAGE_FILE_HEADER
) +
3738 ImgHdr
->Pe32
.FileHeader
.SizeOfOptionalHeader
3741 for (Index
= 0; Index
< ImgHdr
->Pe32
.FileHeader
.NumberOfSections
; Index
++, SectionHeader
++) {
3743 (UINT8
*) CurrentPe32Section
.Pe32Section
+ CurSecHdrSize
+ SectionHeader
->PointerToRawData
,
3744 (VOID
*) (UINTN
) (ImageContext
.ImageAddress
+ SectionHeader
->VirtualAddress
),
3745 SectionHeader
->SizeOfRawData
3749 free ((VOID
*) MemoryImagePointer
);
3750 MemoryImagePointer
= NULL
;
3751 if (PeFileBuffer
!= NULL
) {
3752 free (PeFileBuffer
);
3753 PeFileBuffer
= NULL
;
3757 // Update Image Base Address
3759 if (ImgHdr
->Pe32
.OptionalHeader
.Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
3760 ImgHdr
->Pe32
.OptionalHeader
.ImageBase
= (UINT32
) NewPe32BaseAddress
;
3761 } else if (ImgHdr
->Pe32Plus
.OptionalHeader
.Magic
== EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC
) {
3762 ImgHdr
->Pe32Plus
.OptionalHeader
.ImageBase
= NewPe32BaseAddress
;
3764 Error (NULL
, 0, 3000, "Invalid", "unknown PE magic signature %X in PE32 image %s",
3765 ImgHdr
->Pe32
.OptionalHeader
.Magic
,
3772 // Now update file checksum
3774 if (FfsFile
->Attributes
& FFS_ATTRIB_CHECKSUM
) {
3775 SavedState
= FfsFile
->State
;
3776 FfsFile
->IntegrityCheck
.Checksum
.File
= 0;
3778 FfsFile
->IntegrityCheck
.Checksum
.File
= CalculateChecksum8 (
3779 (UINT8
*) ((UINT8
*)FfsFile
+ FfsHeaderSize
),
3780 GetFfsFileLength (FfsFile
) - FfsHeaderSize
3782 FfsFile
->State
= SavedState
;
3786 // Get this module function address from ModulePeMapFile and add them into FvMap file
3790 // Default use FileName as map file path
3792 if (PdbPointer
== NULL
) {
3793 PdbPointer
= FileName
;
3796 WriteMapFile (FvMapFile
, PdbPointer
, FfsFile
, NewPe32BaseAddress
, &OrigImageContext
);
3799 if (FfsFile
->Type
!= EFI_FV_FILETYPE_SECURITY_CORE
&&
3800 FfsFile
->Type
!= EFI_FV_FILETYPE_PEI_CORE
&&
3801 FfsFile
->Type
!= EFI_FV_FILETYPE_PEIM
&&
3802 FfsFile
->Type
!= EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER
&&
3803 FfsFile
->Type
!= EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE
3806 // Only Peim code may have a TE section
3812 // Now process TE sections
3814 for (Index
= 1;; Index
++) {
3815 NewPe32BaseAddress
= 0;
3820 Status
= GetSectionByType (FfsFile
, EFI_SECTION_TE
, Index
, &CurrentPe32Section
);
3821 if (EFI_ERROR (Status
)) {
3825 CurSecHdrSize
= GetSectionHeaderLength(CurrentPe32Section
.CommonHeader
);
3828 // Calculate the TE base address, the FFS file base plus the offset of the TE section less the size stripped off
3831 TEImageHeader
= (EFI_TE_IMAGE_HEADER
*) ((UINT8
*) CurrentPe32Section
.Pe32Section
+ CurSecHdrSize
);
3834 // Initialize context, load image info.
3836 memset (&ImageContext
, 0, sizeof (ImageContext
));
3837 ImageContext
.Handle
= (VOID
*) TEImageHeader
;
3838 ImageContext
.ImageRead
= (PE_COFF_LOADER_READ_FILE
) FfsRebaseImageRead
;
3839 Status
= PeCoffLoaderGetImageInfo (&ImageContext
);
3840 if (EFI_ERROR (Status
)) {
3841 Error (NULL
, 0, 3000, "Invalid TeImage", "The input file is %s and the return status is %x", FileName
, (int) Status
);
3845 if ( (ImageContext
.Machine
== EFI_IMAGE_MACHINE_ARMT
) ||
3846 (ImageContext
.Machine
== EFI_IMAGE_MACHINE_AARCH64
) ) {
3851 // Keep Image Context for TE image in FV
3853 memcpy (&OrigImageContext
, &ImageContext
, sizeof (ImageContext
));
3856 // Get File PdbPointer
3858 PdbPointer
= PeCoffLoaderGetPdbPointer (ImageContext
.Handle
);
3861 // Set new rebased address.
3863 NewPe32BaseAddress
= XipBase
+ (UINTN
) TEImageHeader
+ sizeof (EFI_TE_IMAGE_HEADER
) \
3864 - TEImageHeader
->StrippedSize
- (UINTN
) FfsFile
;
3867 // if reloc is stripped, try to get the original efi image to get reloc info.
3869 if (ImageContext
.RelocationsStripped
) {
3871 // Construct the original efi file name
3873 if (strlen (FileName
) >= MAX_LONG_FILE_PATH
) {
3874 Error (NULL
, 0, 2000, "Invalid", "The file name %s is too long.", FileName
);
3877 strncpy (PeFileName
, FileName
, MAX_LONG_FILE_PATH
- 1);
3878 PeFileName
[MAX_LONG_FILE_PATH
- 1] = 0;
3879 Cptr
= PeFileName
+ strlen (PeFileName
);
3880 while (*Cptr
!= '.') {
3885 Error (NULL
, 0, 3000, "Invalid", "The file %s has no .reloc section.", FileName
);
3894 PeFile
= fopen (LongFilePath (PeFileName
), "rb");
3895 if (PeFile
== NULL
) {
3896 Warning (NULL
, 0, 0, "Invalid", "The file %s has no .reloc section.", FileName
);
3897 //Error (NULL, 0, 3000, "Invalid", "The file %s has no .reloc section.", FileName);
3898 //return EFI_ABORTED;
3901 // Get the file size
3903 PeFileSize
= _filelength (fileno (PeFile
));
3904 PeFileBuffer
= (UINT8
*) malloc (PeFileSize
);
3905 if (PeFileBuffer
== NULL
) {
3907 Error (NULL
, 0, 4001, "Resource", "memory cannot be allocated on rebase of %s", FileName
);
3908 return EFI_OUT_OF_RESOURCES
;
3913 fread (PeFileBuffer
, sizeof (UINT8
), PeFileSize
, PeFile
);
3919 // Append reloc section into TeImage
3921 ImageContext
.Handle
= PeFileBuffer
;
3922 Status
= PeCoffLoaderGetImageInfo (&ImageContext
);
3923 if (EFI_ERROR (Status
)) {
3924 Error (NULL
, 0, 3000, "Invalid TeImage", "The input file is %s and the return status is %x", FileName
, (int) Status
);
3927 ImageContext
.RelocationsStripped
= FALSE
;
3931 // Relocation doesn't exist
3933 if (ImageContext
.RelocationsStripped
) {
3934 Warning (NULL
, 0, 0, "Invalid", "The file %s has no .reloc section.", FileName
);
3939 // Relocation exist and rebase
3942 // Load and Relocate Image Data
3944 MemoryImagePointer
= (UINT8
*) malloc ((UINTN
) ImageContext
.ImageSize
+ ImageContext
.SectionAlignment
);
3945 if (MemoryImagePointer
== NULL
) {
3946 Error (NULL
, 0, 4001, "Resource", "memory cannot be allocated on rebase of %s", FileName
);
3947 return EFI_OUT_OF_RESOURCES
;
3949 memset ((VOID
*) MemoryImagePointer
, 0, (UINTN
) ImageContext
.ImageSize
+ ImageContext
.SectionAlignment
);
3950 ImageContext
.ImageAddress
= ((UINTN
) MemoryImagePointer
+ ImageContext
.SectionAlignment
- 1) & (~((UINTN
) ImageContext
.SectionAlignment
- 1));
3952 Status
= PeCoffLoaderLoadImage (&ImageContext
);
3953 if (EFI_ERROR (Status
)) {
3954 Error (NULL
, 0, 3000, "Invalid", "LocateImage() call failed on rebase of %s", FileName
);
3955 free ((VOID
*) MemoryImagePointer
);
3959 // Reloacate TeImage
3961 ImageContext
.DestinationAddress
= NewPe32BaseAddress
;
3962 Status
= PeCoffLoaderRelocateImage (&ImageContext
);
3963 if (EFI_ERROR (Status
)) {
3964 Error (NULL
, 0, 3000, "Invalid", "RelocateImage() call failed on rebase of TE image %s", FileName
);
3965 free ((VOID
*) MemoryImagePointer
);
3970 // Copy the relocated image into raw image file.
3972 SectionHeader
= (EFI_IMAGE_SECTION_HEADER
*) (TEImageHeader
+ 1);
3973 for (Index
= 0; Index
< TEImageHeader
->NumberOfSections
; Index
++, SectionHeader
++) {
3974 if (!ImageContext
.IsTeImage
) {
3976 (UINT8
*) TEImageHeader
+ sizeof (EFI_TE_IMAGE_HEADER
) - TEImageHeader
->StrippedSize
+ SectionHeader
->PointerToRawData
,
3977 (VOID
*) (UINTN
) (ImageContext
.ImageAddress
+ SectionHeader
->VirtualAddress
),
3978 SectionHeader
->SizeOfRawData
3982 (UINT8
*) TEImageHeader
+ sizeof (EFI_TE_IMAGE_HEADER
) - TEImageHeader
->StrippedSize
+ SectionHeader
->PointerToRawData
,
3983 (VOID
*) (UINTN
) (ImageContext
.ImageAddress
+ sizeof (EFI_TE_IMAGE_HEADER
) - TEImageHeader
->StrippedSize
+ SectionHeader
->VirtualAddress
),
3984 SectionHeader
->SizeOfRawData
3990 // Free the allocated memory resource
3992 free ((VOID
*) MemoryImagePointer
);
3993 MemoryImagePointer
= NULL
;
3994 if (PeFileBuffer
!= NULL
) {
3995 free (PeFileBuffer
);
3996 PeFileBuffer
= NULL
;
4000 // Update Image Base Address
4002 TEImageHeader
->ImageBase
= NewPe32BaseAddress
;
4005 // Now update file checksum
4007 if (FfsFile
->Attributes
& FFS_ATTRIB_CHECKSUM
) {
4008 SavedState
= FfsFile
->State
;
4009 FfsFile
->IntegrityCheck
.Checksum
.File
= 0;
4011 FfsFile
->IntegrityCheck
.Checksum
.File
= CalculateChecksum8 (
4012 (UINT8
*)((UINT8
*)FfsFile
+ FfsHeaderSize
),
4013 GetFfsFileLength (FfsFile
) - FfsHeaderSize
4015 FfsFile
->State
= SavedState
;
4018 // Get this module function address from ModulePeMapFile and add them into FvMap file
4022 // Default use FileName as map file path
4024 if (PdbPointer
== NULL
) {
4025 PdbPointer
= FileName
;
4041 FindApResetVectorPosition (
4042 IN MEMORY_FILE
*FvImage
,
4047 Routine Description:
4049 Find the position in this FvImage to place Ap reset vector.
4053 FvImage Memory file for the FV memory image.
4054 Pointer Pointer to pointer to position.
4058 EFI_NOT_FOUND - No satisfied position is found.
4059 EFI_SUCCESS - The suitable position is return.
4063 EFI_FFS_FILE_HEADER
*PadFile
;
4069 for (Index
= 1; ;Index
++) {
4071 // Find Pad File to add ApResetVector info
4073 Status
= GetFileByType (EFI_FV_FILETYPE_FFS_PAD
, Index
, &PadFile
);
4074 if (EFI_ERROR (Status
) || (PadFile
== NULL
)) {
4076 // No Pad file to be found.
4081 // Get Pad file size.
4083 FileLength
= GetFfsFileLength(PadFile
);
4084 FileLength
= (FileLength
+ EFI_FFS_FILE_HEADER_ALIGNMENT
- 1) & ~(EFI_FFS_FILE_HEADER_ALIGNMENT
- 1);
4086 // FixPoint must be align on 0x1000 relative to FvImage Header
4088 FixPoint
= (UINT8
*) PadFile
+ GetFfsHeaderLength(PadFile
);
4089 FixPoint
= FixPoint
+ 0x1000 - (((UINTN
) FixPoint
- (UINTN
) FvImage
->FileImage
) & 0xFFF);
4091 // FixPoint be larger at the last place of one fv image.
4093 while (((UINTN
) FixPoint
+ SIZEOF_STARTUP_DATA_ARRAY
- (UINTN
) PadFile
) <= FileLength
) {
4098 if ((UINTN
) FixPoint
< ((UINTN
) PadFile
+ GetFfsHeaderLength(PadFile
))) {
4100 // No alignment FixPoint in this Pad File.
4105 if ((UINTN
) FvImage
->Eof
- (UINTN
)FixPoint
<= 0x20000) {
4107 // Find the position to place ApResetVector
4109 *Pointer
= FixPoint
;
4114 return EFI_NOT_FOUND
;
4119 IN MEMORY_FILE
*InfFile
,
4120 OUT CAP_INFO
*CapInfo
4124 Routine Description:
4126 This function parses a Cap.INF file and copies info into a CAP_INFO structure.
4130 InfFile Memory file image.
4131 CapInfo Information read from INF file.
4135 EFI_SUCCESS INF file information successfully retrieved.
4136 EFI_ABORTED INF file has an invalid format.
4137 EFI_NOT_FOUND A required string was not found in the INF file.
4140 CHAR8 Value
[MAX_LONG_FILE_PATH
];
4142 UINTN Index
, Number
;
4146 // Initialize Cap info
4148 // memset (CapInfo, 0, sizeof (CAP_INFO));
4152 // Read the Capsule Guid
4154 Status
= FindToken (InfFile
, OPTIONS_SECTION_STRING
, EFI_CAPSULE_GUID_STRING
, 0, Value
);
4155 if (Status
== EFI_SUCCESS
) {
4157 // Get the Capsule Guid
4159 Status
= StringToGuid (Value
, &CapInfo
->CapGuid
);
4160 if (EFI_ERROR (Status
)) {
4161 Error (NULL
, 0, 2000, "Invalid parameter", "%s = %s", EFI_CAPSULE_GUID_STRING
, Value
);
4164 DebugMsg (NULL
, 0, 9, "Capsule Guid", "%s = %s", EFI_CAPSULE_GUID_STRING
, Value
);
4168 // Read the Capsule Header Size
4170 Status
= FindToken (InfFile
, OPTIONS_SECTION_STRING
, EFI_CAPSULE_HEADER_SIZE_STRING
, 0, Value
);
4171 if (Status
== EFI_SUCCESS
) {
4172 Status
= AsciiStringToUint64 (Value
, FALSE
, &Value64
);
4173 if (EFI_ERROR (Status
)) {
4174 Error (NULL
, 0, 2000, "Invalid parameter", "%s = %s", EFI_CAPSULE_HEADER_SIZE_STRING
, Value
);
4177 CapInfo
->HeaderSize
= (UINT32
) Value64
;
4178 DebugMsg (NULL
, 0, 9, "Capsule Header size", "%s = %s", EFI_CAPSULE_HEADER_SIZE_STRING
, Value
);
4182 // Read the Capsule Flag
4184 Status
= FindToken (InfFile
, OPTIONS_SECTION_STRING
, EFI_CAPSULE_FLAGS_STRING
, 0, Value
);
4185 if (Status
== EFI_SUCCESS
) {
4186 if (strstr (Value
, "PopulateSystemTable") != NULL
) {
4187 CapInfo
->Flags
|= CAPSULE_FLAGS_PERSIST_ACROSS_RESET
| CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE
;
4188 if (strstr (Value
, "InitiateReset") != NULL
) {
4189 CapInfo
->Flags
|= CAPSULE_FLAGS_INITIATE_RESET
;
4191 } else if (strstr (Value
, "PersistAcrossReset") != NULL
) {
4192 CapInfo
->Flags
|= CAPSULE_FLAGS_PERSIST_ACROSS_RESET
;
4193 if (strstr (Value
, "InitiateReset") != NULL
) {
4194 CapInfo
->Flags
|= CAPSULE_FLAGS_INITIATE_RESET
;
4197 Error (NULL
, 0, 2000, "Invalid parameter", "invalid Flag setting for %s.", EFI_CAPSULE_FLAGS_STRING
);
4200 DebugMsg (NULL
, 0, 9, "Capsule Flag", Value
);
4203 Status
= FindToken (InfFile
, OPTIONS_SECTION_STRING
, EFI_OEM_CAPSULE_FLAGS_STRING
, 0, Value
);
4204 if (Status
== EFI_SUCCESS
) {
4205 Status
= AsciiStringToUint64 (Value
, FALSE
, &Value64
);
4206 if (EFI_ERROR (Status
) || Value64
> 0xffff) {
4207 Error (NULL
, 0, 2000, "Invalid parameter",
4208 "invalid Flag setting for %s. Must be integer value between 0x0000 and 0xffff.",
4209 EFI_OEM_CAPSULE_FLAGS_STRING
);
4212 CapInfo
->Flags
|= Value64
;
4213 DebugMsg (NULL
, 0, 9, "Capsule Extend Flag", Value
);
4217 // Read Capsule File name
4219 Status
= FindToken (InfFile
, OPTIONS_SECTION_STRING
, EFI_FILE_NAME_STRING
, 0, Value
);
4220 if (Status
== EFI_SUCCESS
) {
4222 // Get output file name
4224 strcpy (CapInfo
->CapName
, Value
);
4228 // Read the Capsule FileImage
4231 for (Index
= 0; Index
< MAX_NUMBER_OF_FILES_IN_CAP
; Index
++) {
4232 if (CapInfo
->CapFiles
[Index
][0] != '\0') {
4236 // Read the capsule file name
4238 Status
= FindToken (InfFile
, FILES_SECTION_STRING
, EFI_FILE_NAME_STRING
, Number
++, Value
);
4240 if (Status
== EFI_SUCCESS
) {
4244 strcpy (CapInfo
->CapFiles
[Index
], Value
);
4245 DebugMsg (NULL
, 0, 9, "Capsule component file", "the %uth file name is %s", (unsigned) Index
, CapInfo
->CapFiles
[Index
]);
4252 Warning (NULL
, 0, 0, "Capsule components are not specified.", NULL
);
4260 IN CHAR8
*InfFileImage
,
4261 IN UINTN InfFileSize
,
4262 IN CHAR8
*CapFileName
4266 Routine Description:
4268 This is the main function which will be called from application to create UEFI Capsule image.
4272 InfFileImage Buffer containing the INF file contents.
4273 InfFileSize Size of the contents of the InfFileImage buffer.
4274 CapFileName Requested name for the Cap file.
4278 EFI_SUCCESS Function completed successfully.
4279 EFI_OUT_OF_RESOURCES Could not allocate required resources.
4280 EFI_ABORTED Error encountered.
4281 EFI_INVALID_PARAMETER A required parameter was NULL.
4287 EFI_CAPSULE_HEADER
*CapsuleHeader
;
4288 MEMORY_FILE InfMemoryFile
;
4294 if (InfFileImage
!= NULL
) {
4296 // Initialize file structures
4298 InfMemoryFile
.FileImage
= InfFileImage
;
4299 InfMemoryFile
.CurrentFilePointer
= InfFileImage
;
4300 InfMemoryFile
.Eof
= InfFileImage
+ InfFileSize
;
4303 // Parse the Cap inf file for header information
4305 Status
= ParseCapInf (&InfMemoryFile
, &mCapDataInfo
);
4306 if (Status
!= EFI_SUCCESS
) {
4311 if (mCapDataInfo
.HeaderSize
== 0) {
4313 // make header size align 16 bytes.
4315 mCapDataInfo
.HeaderSize
= sizeof (EFI_CAPSULE_HEADER
);
4316 mCapDataInfo
.HeaderSize
= (mCapDataInfo
.HeaderSize
+ 0xF) & ~0xF;
4319 if (mCapDataInfo
.HeaderSize
< sizeof (EFI_CAPSULE_HEADER
)) {
4320 Error (NULL
, 0, 2000, "Invalid parameter", "The specified HeaderSize cannot be less than the size of EFI_CAPSULE_HEADER.");
4321 return EFI_INVALID_PARAMETER
;
4324 if (CapFileName
== NULL
&& mCapDataInfo
.CapName
[0] != '\0') {
4325 CapFileName
= mCapDataInfo
.CapName
;
4328 if (CapFileName
== NULL
) {
4329 Error (NULL
, 0, 2001, "Missing required argument", "Output Capsule file name");
4330 return EFI_INVALID_PARAMETER
;
4334 // Set Default Capsule Guid value
4336 if (CompareGuid (&mCapDataInfo
.CapGuid
, &mZeroGuid
) == 0) {
4337 memcpy (&mCapDataInfo
.CapGuid
, &mDefaultCapsuleGuid
, sizeof (EFI_GUID
));
4340 // Calculate the size of capsule image.
4344 CapSize
= mCapDataInfo
.HeaderSize
;
4345 while (mCapDataInfo
.CapFiles
[Index
][0] != '\0') {
4346 fpin
= fopen (LongFilePath (mCapDataInfo
.CapFiles
[Index
]), "rb");
4348 Error (NULL
, 0, 0001, "Error opening file", mCapDataInfo
.CapFiles
[Index
]);
4351 FileSize
= _filelength (fileno (fpin
));
4352 CapSize
+= FileSize
;
4358 // Allocate buffer for capsule image.
4360 CapBuffer
= (UINT8
*) malloc (CapSize
);
4361 if (CapBuffer
== NULL
) {
4362 Error (NULL
, 0, 4001, "Resource", "memory cannot be allocated for creating the capsule.");
4363 return EFI_OUT_OF_RESOURCES
;
4367 // Initialize the capsule header to zero
4369 memset (CapBuffer
, 0, mCapDataInfo
.HeaderSize
);
4372 // create capsule header and get capsule body
4374 CapsuleHeader
= (EFI_CAPSULE_HEADER
*) CapBuffer
;
4375 memcpy (&CapsuleHeader
->CapsuleGuid
, &mCapDataInfo
.CapGuid
, sizeof (EFI_GUID
));
4376 CapsuleHeader
->HeaderSize
= mCapDataInfo
.HeaderSize
;
4377 CapsuleHeader
->Flags
= mCapDataInfo
.Flags
;
4378 CapsuleHeader
->CapsuleImageSize
= CapSize
;
4382 CapSize
= CapsuleHeader
->HeaderSize
;
4383 while (mCapDataInfo
.CapFiles
[Index
][0] != '\0') {
4384 fpin
= fopen (LongFilePath (mCapDataInfo
.CapFiles
[Index
]), "rb");
4386 Error (NULL
, 0, 0001, "Error opening file", mCapDataInfo
.CapFiles
[Index
]);
4390 FileSize
= _filelength (fileno (fpin
));
4391 fread (CapBuffer
+ CapSize
, 1, FileSize
, fpin
);
4394 CapSize
+= FileSize
;
4398 // write capsule data into the output file
4400 fpout
= fopen (LongFilePath (CapFileName
), "wb");
4401 if (fpout
== NULL
) {
4402 Error (NULL
, 0, 0001, "Error opening file", CapFileName
);
4407 fwrite (CapBuffer
, 1, CapSize
, fpout
);
4411 VerboseMsg ("The size of the generated capsule image is %u bytes", (unsigned) CapSize
);