3 Copyright (c) 2004 - 2011, Intel Corporation. All rights reserved.<BR>
4 Portions Copyright (c) 2011 - 2013, ARM Ltd. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
19 This file contains the internal functions required to generate a Firmware Volume.
27 #include <uuid/uuid.h>
36 #include "GenFvInternalLib.h"
38 #include "PeCoffLib.h"
39 #include "WinNtInclude.h"
42 STATIC UINT32 MaxFfsAlignment
= 0;
44 EFI_GUID mEfiFirmwareVolumeTopFileGuid
= EFI_FFS_VOLUME_TOP_FILE_GUID
;
45 EFI_GUID mFileGuidArray
[MAX_NUMBER_OF_FILES_IN_FV
];
46 EFI_GUID mZeroGuid
= {0x0, 0x0, 0x0, {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}};
47 EFI_GUID mDefaultCapsuleGuid
= {0x3B6686BD, 0x0D76, 0x4030, { 0xB7, 0x0E, 0xB5, 0x51, 0x9E, 0x2F, 0xC5, 0xA0 }};
49 CHAR8
*mFvbAttributeName
[] = {
50 EFI_FVB2_READ_DISABLED_CAP_STRING
,
51 EFI_FVB2_READ_ENABLED_CAP_STRING
,
52 EFI_FVB2_READ_STATUS_STRING
,
53 EFI_FVB2_WRITE_DISABLED_CAP_STRING
,
54 EFI_FVB2_WRITE_ENABLED_CAP_STRING
,
55 EFI_FVB2_WRITE_STATUS_STRING
,
56 EFI_FVB2_LOCK_CAP_STRING
,
57 EFI_FVB2_LOCK_STATUS_STRING
,
59 EFI_FVB2_STICKY_WRITE_STRING
,
60 EFI_FVB2_MEMORY_MAPPED_STRING
,
61 EFI_FVB2_ERASE_POLARITY_STRING
,
62 EFI_FVB2_READ_LOCK_CAP_STRING
,
63 EFI_FVB2_READ_LOCK_STATUS_STRING
,
64 EFI_FVB2_WRITE_LOCK_CAP_STRING
,
65 EFI_FVB2_WRITE_LOCK_STATUS_STRING
68 CHAR8
*mFvbAlignmentName
[] = {
69 EFI_FVB2_ALIGNMENT_1_STRING
,
70 EFI_FVB2_ALIGNMENT_2_STRING
,
71 EFI_FVB2_ALIGNMENT_4_STRING
,
72 EFI_FVB2_ALIGNMENT_8_STRING
,
73 EFI_FVB2_ALIGNMENT_16_STRING
,
74 EFI_FVB2_ALIGNMENT_32_STRING
,
75 EFI_FVB2_ALIGNMENT_64_STRING
,
76 EFI_FVB2_ALIGNMENT_128_STRING
,
77 EFI_FVB2_ALIGNMENT_256_STRING
,
78 EFI_FVB2_ALIGNMENT_512_STRING
,
79 EFI_FVB2_ALIGNMENT_1K_STRING
,
80 EFI_FVB2_ALIGNMENT_2K_STRING
,
81 EFI_FVB2_ALIGNMENT_4K_STRING
,
82 EFI_FVB2_ALIGNMENT_8K_STRING
,
83 EFI_FVB2_ALIGNMENT_16K_STRING
,
84 EFI_FVB2_ALIGNMENT_32K_STRING
,
85 EFI_FVB2_ALIGNMENT_64K_STRING
,
86 EFI_FVB2_ALIGNMENT_128K_STRING
,
87 EFI_FVB2_ALIGNMENT_256K_STRING
,
88 EFI_FVB2_ALIGNMENT_512K_STRING
,
89 EFI_FVB2_ALIGNMENT_1M_STRING
,
90 EFI_FVB2_ALIGNMENT_2M_STRING
,
91 EFI_FVB2_ALIGNMENT_4M_STRING
,
92 EFI_FVB2_ALIGNMENT_8M_STRING
,
93 EFI_FVB2_ALIGNMENT_16M_STRING
,
94 EFI_FVB2_ALIGNMENT_32M_STRING
,
95 EFI_FVB2_ALIGNMENT_64M_STRING
,
96 EFI_FVB2_ALIGNMENT_128M_STRING
,
97 EFI_FVB2_ALIGNMENT_256M_STRING
,
98 EFI_FVB2_ALIGNMENT_512M_STRING
,
99 EFI_FVB2_ALIGNMENT_1G_STRING
,
100 EFI_FVB2_ALIGNMENT_2G_STRING
104 // This data array will be located at the base of the Firmware Volume Header (FVH)
105 // in the boot block. It must not exceed 14 bytes of code. The last 2 bytes
106 // will be used to keep the FVH checksum consistent.
107 // This code will be run in response to a starutp IPI for HT-enabled systems.
109 #define SIZEOF_STARTUP_DATA_ARRAY 0x10
111 UINT8 m128kRecoveryStartupApDataArray
[SIZEOF_STARTUP_DATA_ARRAY
] = {
113 // EA D0 FF 00 F0 ; far jmp F000:FFD0
114 // 0, 0, 0, 0, 0, 0, 0, 0, 0, ; Reserved bytes
115 // 0, 0 ; Checksum Padding
135 UINT8 m64kRecoveryStartupApDataArray
[SIZEOF_STARTUP_DATA_ARRAY
] = {
137 // EB CE ; jmp short ($-0x30)
138 // ; (from offset 0x0 to offset 0xFFD0)
139 // 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ; Reserved bytes
140 // 0, 0 ; Checksum Padding
161 CAP_INFO mCapDataInfo
;
163 EFI_PHYSICAL_ADDRESS mFvBaseAddress
[0x10];
164 UINT32 mFvBaseAddressNumber
= 0;
168 IN MEMORY_FILE
*InfFile
,
175 This function parses a FV.INF file and copies info into a FV_INFO structure.
179 InfFile Memory file image.
180 FvInfo Information read from INF file.
184 EFI_SUCCESS INF file information successfully retrieved.
185 EFI_ABORTED INF file has an invalid format.
186 EFI_NOT_FOUND A required string was not found in the INF file.
189 CHAR8 Value
[_MAX_PATH
];
197 // Read the FV base address
199 if (!mFvDataInfo
.BaseAddressSet
) {
200 Status
= FindToken (InfFile
, OPTIONS_SECTION_STRING
, EFI_FV_BASE_ADDRESS_STRING
, 0, Value
);
201 if (Status
== EFI_SUCCESS
) {
203 // Get the base address
205 Status
= AsciiStringToUint64 (Value
, FALSE
, &Value64
);
206 if (EFI_ERROR (Status
)) {
207 Error (NULL
, 0, 2000, "Invalid parameter", "%s = %s", EFI_FV_BASE_ADDRESS_STRING
, Value
);
210 DebugMsg (NULL
, 0, 9, "rebase address", "%s = %s", EFI_FV_BASE_ADDRESS_STRING
, Value
);
212 FvInfo
->BaseAddress
= Value64
;
213 FvInfo
->BaseAddressSet
= TRUE
;
218 // Read the FV File System Guid
220 if (!FvInfo
->FvFileSystemGuidSet
) {
221 Status
= FindToken (InfFile
, OPTIONS_SECTION_STRING
, EFI_FV_FILESYSTEMGUID_STRING
, 0, Value
);
222 if (Status
== EFI_SUCCESS
) {
224 // Get the guid value
226 Status
= StringToGuid (Value
, &GuidValue
);
227 if (EFI_ERROR (Status
)) {
228 Error (NULL
, 0, 2000, "Invalid parameter", "%s = %s", EFI_FV_FILESYSTEMGUID_STRING
, Value
);
231 memcpy (&FvInfo
->FvFileSystemGuid
, &GuidValue
, sizeof (EFI_GUID
));
232 FvInfo
->FvFileSystemGuidSet
= TRUE
;
237 // Read the FV Extension Header File Name
239 Status
= FindToken (InfFile
, ATTRIBUTES_SECTION_STRING
, EFI_FV_EXT_HEADER_FILE_NAME
, 0, Value
);
240 if (Status
== EFI_SUCCESS
) {
241 strcpy (FvInfo
->FvExtHeaderFile
, Value
);
245 // Read the FV file name
247 Status
= FindToken (InfFile
, OPTIONS_SECTION_STRING
, EFI_FV_FILE_NAME_STRING
, 0, Value
);
248 if (Status
== EFI_SUCCESS
) {
250 // copy the file name
252 strcpy (FvInfo
->FvName
, Value
);
258 for (Index
= 0; Index
< sizeof (mFvbAttributeName
)/sizeof (CHAR8
*); Index
++) {
259 if ((mFvbAttributeName
[Index
] != NULL
) && \
260 (FindToken (InfFile
, ATTRIBUTES_SECTION_STRING
, mFvbAttributeName
[Index
], 0, Value
) == EFI_SUCCESS
)) {
261 if ((strcmp (Value
, TRUE_STRING
) == 0) || (strcmp (Value
, ONE_STRING
) == 0)) {
262 FvInfo
->FvAttributes
|= 1 << Index
;
263 } else if ((strcmp (Value
, FALSE_STRING
) != 0) && (strcmp (Value
, ZERO_STRING
) != 0)) {
264 Error (NULL
, 0, 2000, "Invalid parameter", "%s expected %s | %s", mFvbAttributeName
[Index
], TRUE_STRING
, FALSE_STRING
);
273 for (Index
= 0; Index
< sizeof (mFvbAlignmentName
)/sizeof (CHAR8
*); Index
++) {
274 if (FindToken (InfFile
, ATTRIBUTES_SECTION_STRING
, mFvbAlignmentName
[Index
], 0, Value
) == EFI_SUCCESS
) {
275 if (strcmp (Value
, TRUE_STRING
) == 0) {
276 FvInfo
->FvAttributes
|= Index
<< 16;
277 DebugMsg (NULL
, 0, 9, "FV file alignment", "Align = %s", mFvbAlignmentName
[Index
]);
286 for (Index
= 0; Index
< MAX_NUMBER_OF_FV_BLOCKS
; Index
++) {
287 if (FvInfo
->FvBlocks
[Index
].Length
== 0) {
291 Status
= FindToken (InfFile
, OPTIONS_SECTION_STRING
, EFI_BLOCK_SIZE_STRING
, Index
, Value
);
293 if (Status
== EFI_SUCCESS
) {
295 // Update the size of block
297 Status
= AsciiStringToUint64 (Value
, FALSE
, &Value64
);
298 if (EFI_ERROR (Status
)) {
299 Error (NULL
, 0, 2000, "Invalid parameter", "%s = %s", EFI_BLOCK_SIZE_STRING
, Value
);
303 FvInfo
->FvBlocks
[Index
].Length
= (UINT32
) Value64
;
304 DebugMsg (NULL
, 0, 9, "FV Block Size", "%s = %s", EFI_BLOCK_SIZE_STRING
, Value
);
307 // If there is no blocks size, but there is the number of block, then we have a mismatched pair
308 // and should return an error.
310 Status
= FindToken (InfFile
, OPTIONS_SECTION_STRING
, EFI_NUM_BLOCKS_STRING
, Index
, Value
);
311 if (!EFI_ERROR (Status
)) {
312 Error (NULL
, 0, 2000, "Invalid parameter", "both %s and %s must be specified.", EFI_NUM_BLOCKS_STRING
, EFI_BLOCK_SIZE_STRING
);
323 // Read blocks number
325 Status
= FindToken (InfFile
, OPTIONS_SECTION_STRING
, EFI_NUM_BLOCKS_STRING
, Index
, Value
);
327 if (Status
== EFI_SUCCESS
) {
329 // Update the number of blocks
331 Status
= AsciiStringToUint64 (Value
, FALSE
, &Value64
);
332 if (EFI_ERROR (Status
)) {
333 Error (NULL
, 0, 2000, "Invalid parameter", "%s = %s", EFI_NUM_BLOCKS_STRING
, Value
);
337 FvInfo
->FvBlocks
[Index
].NumBlocks
= (UINT32
) Value64
;
338 DebugMsg (NULL
, 0, 9, "FV Block Number", "%s = %s", EFI_NUM_BLOCKS_STRING
, Value
);
344 Error (NULL
, 0, 2001, "Missing required argument", "block size.");
352 for (Number
= 0; Number
< MAX_NUMBER_OF_FILES_IN_FV
; Number
++) {
353 if (FvInfo
->FvFiles
[Number
][0] == '\0') {
358 for (Index
= 0; Index
< MAX_NUMBER_OF_FILES_IN_FV
; Index
++) {
360 // Read the FFS file list
362 Status
= FindToken (InfFile
, FILES_SECTION_STRING
, EFI_FILE_NAME_STRING
, Index
, Value
);
364 if (Status
== EFI_SUCCESS
) {
368 strcpy (FvInfo
->FvFiles
[Number
+ Index
], Value
);
369 DebugMsg (NULL
, 0, 9, "FV component file", "the %uth name is %s", (unsigned) Index
, Value
);
375 if ((Index
+ Number
) == 0) {
376 Warning (NULL
, 0, 0, "FV components are not specified.", NULL
);
384 IN EFI_FFS_FILE_HEADER
*FfsFile
,
385 IN EFI_FIRMWARE_VOLUME_HEADER
*FvHeader
391 This function changes the FFS file attributes based on the erase polarity
392 of the FV. Update the reserved bits of State to EFI_FVB2_ERASE_POLARITY.
405 if (FvHeader
->Attributes
& EFI_FVB2_ERASE_POLARITY
) {
406 FfsFile
->State
= (UINT8
)~(FfsFile
->State
);
407 // FfsFile->State |= ~(UINT8) EFI_FILE_ALL_STATE_BITS;
413 IN EFI_FFS_FILE_HEADER
*FfsFile
,
414 IN OUT UINT32
*Alignment
420 This function determines the alignment of the FFS input file from the file
425 FfsFile FFS file to parse
426 Alignment The minimum required alignment offset of the FFS file
430 EFI_SUCCESS The function completed successfully.
431 EFI_INVALID_PARAMETER One of the input parameters was invalid.
432 EFI_ABORTED An error occurred.
437 // Verify input parameters.
439 if (FfsFile
== NULL
|| Alignment
== NULL
) {
440 return EFI_INVALID_PARAMETER
;
443 switch ((FfsFile
->Attributes
>> 3) & 0x07) {
447 // 8 byte alignment, mini alignment requirement for FFS file.
461 // 128 byte alignment
468 // 512 byte alignment
489 // 32K byte alignment
496 // 64K byte alignment
510 IN OUT MEMORY_FILE
*FvImage
,
511 IN UINT32 DataAlignment
,
513 IN EFI_FIRMWARE_VOLUME_EXT_HEADER
*ExtHeader
519 This function adds a pad file to the FV image if it required to align the
520 data of the next file.
524 FvImage The memory image of the FV to add it to.
525 The current offset must be valid.
526 DataAlignment The data alignment of the next FFS file.
527 FvEnd End of the empty data in FvImage.
528 ExtHeader PI FvExtHeader Optional
532 EFI_SUCCESS The function completed successfully.
533 EFI_INVALID_PARAMETER One of the input parameters was invalid.
534 EFI_OUT_OF_RESOURCES Insufficient resources exist in the FV to complete
539 EFI_FFS_FILE_HEADER
*PadFile
;
543 // Verify input parameters.
545 if (FvImage
== NULL
) {
546 return EFI_INVALID_PARAMETER
;
550 // Check if a pad file is necessary
552 if ((ExtHeader
== NULL
) && (((UINTN
) FvImage
->CurrentFilePointer
- (UINTN
) FvImage
->FileImage
+ sizeof (EFI_FFS_FILE_HEADER
)) % DataAlignment
== 0)) {
557 // Calculate the pad file size
560 // This is the earliest possible valid offset (current plus pad file header
561 // plus the next file header)
563 PadFileSize
= (UINTN
) FvImage
->CurrentFilePointer
- (UINTN
) FvImage
->FileImage
+ (sizeof (EFI_FFS_FILE_HEADER
) * 2);
566 // Add whatever it takes to get to the next aligned address
568 while ((PadFileSize
% DataAlignment
) != 0) {
572 // Subtract the next file header size
574 PadFileSize
-= sizeof (EFI_FFS_FILE_HEADER
);
577 // Subtract the starting offset to get size
579 PadFileSize
-= (UINTN
) FvImage
->CurrentFilePointer
- (UINTN
) FvImage
->FileImage
;
582 // Append extension header size
584 if (ExtHeader
!= NULL
) {
585 PadFileSize
= PadFileSize
+ ExtHeader
->ExtHeaderSize
;
589 // Verify that we have enough space for the file header
591 if (((UINTN
) FvImage
->CurrentFilePointer
+ PadFileSize
) > (UINTN
) FvEnd
) {
592 return EFI_OUT_OF_RESOURCES
;
596 // Write pad file header
598 PadFile
= (EFI_FFS_FILE_HEADER
*) FvImage
->CurrentFilePointer
;
601 // Write PadFile FFS header with PadType, don't need to set PAD file guid in its header.
603 PadFile
->Type
= EFI_FV_FILETYPE_FFS_PAD
;
604 PadFile
->Attributes
= 0;
607 // Write pad file size (calculated size minus next file header size)
609 PadFile
->Size
[0] = (UINT8
) (PadFileSize
& 0xFF);
610 PadFile
->Size
[1] = (UINT8
) ((PadFileSize
>> 8) & 0xFF);
611 PadFile
->Size
[2] = (UINT8
) ((PadFileSize
>> 16) & 0xFF);
614 // Fill in checksums and state, they must be 0 for checksumming.
616 PadFile
->IntegrityCheck
.Checksum
.Header
= 0;
617 PadFile
->IntegrityCheck
.Checksum
.File
= 0;
619 PadFile
->IntegrityCheck
.Checksum
.Header
= CalculateChecksum8 ((UINT8
*) PadFile
, sizeof (EFI_FFS_FILE_HEADER
));
620 PadFile
->IntegrityCheck
.Checksum
.File
= FFS_FIXED_CHECKSUM
;
622 PadFile
->State
= EFI_FILE_HEADER_CONSTRUCTION
| EFI_FILE_HEADER_VALID
| EFI_FILE_DATA_VALID
;
624 (EFI_FFS_FILE_HEADER
*) PadFile
,
625 (EFI_FIRMWARE_VOLUME_HEADER
*) FvImage
->FileImage
629 // Update the current FV pointer
631 FvImage
->CurrentFilePointer
+= PadFileSize
;
633 if (ExtHeader
!= NULL
) {
635 // Copy Fv Extension Header and Set Fv Extension header offset
637 memcpy (PadFile
+ 1, ExtHeader
, ExtHeader
->ExtHeaderSize
);
638 ((EFI_FIRMWARE_VOLUME_HEADER
*) FvImage
->FileImage
)->ExtHeaderOffset
= (UINT16
) ((UINTN
) (PadFile
+ 1) - (UINTN
) FvImage
->FileImage
);
640 // Make next file start at QWord Boundry
642 while (((UINTN
) FvImage
->CurrentFilePointer
& (EFI_FFS_FILE_HEADER_ALIGNMENT
- 1)) != 0) {
643 FvImage
->CurrentFilePointer
++;
652 IN EFI_FFS_FILE_HEADER
*FileBuffer
658 This function checks the header to validate if it is a VTF file
662 FileBuffer Buffer in which content of a file has been read.
666 TRUE If this is a VTF file
667 FALSE If this is not a VTF file
671 if (!memcmp (&FileBuffer
->Name
, &mEfiFirmwareVolumeTopFileGuid
, sizeof (EFI_GUID
))) {
680 IN OUT
FILE *FvMapFile
,
682 IN EFI_FFS_FILE_HEADER
*FfsFile
,
683 IN EFI_PHYSICAL_ADDRESS ImageBaseAddress
,
684 IN PE_COFF_LOADER_IMAGE_CONTEXT
*pImageContext
690 This function gets the basic debug information (entrypoint, baseaddress, .text, .data section base address)
691 from PE/COFF image and abstracts Pe Map file information and add them into FvMap file for Debug.
695 FvMapFile A pointer to FvMap File
696 FileName Ffs File PathName
697 FfsFile A pointer to Ffs file image.
698 ImageBaseAddress PeImage Base Address.
699 pImageContext Image Context Information.
703 EFI_SUCCESS Added required map information.
707 CHAR8 PeMapFileName
[_MAX_PATH
];
709 CHAR8 FileGuidName
[MAX_LINE_LEN
];
711 CHAR8 Line
[MAX_LINE_LEN
];
712 CHAR8 KeyWord
[MAX_LINE_LEN
];
713 CHAR8 FunctionName
[MAX_LINE_LEN
];
714 EFI_PHYSICAL_ADDRESS FunctionAddress
;
716 CHAR8 FunctionTypeName
[MAX_LINE_LEN
];
718 UINT32 AddressOfEntryPoint
;
720 EFI_IMAGE_OPTIONAL_HEADER_UNION
*ImgHdr
;
721 EFI_TE_IMAGE_HEADER
*TEImageHeader
;
722 EFI_IMAGE_SECTION_HEADER
*SectionHeader
;
723 unsigned long long TempLongAddress
;
724 UINT32 TextVirtualAddress
;
725 UINT32 DataVirtualAddress
;
726 EFI_PHYSICAL_ADDRESS LinkTimeBaseAddress
;
729 // Init local variable
733 // Print FileGuid to string buffer.
735 PrintGuidToBuffer (&FfsFile
->Name
, (UINT8
*)FileGuidName
, MAX_LINE_LEN
, TRUE
);
738 // Construct Map file Name
740 strcpy (PeMapFileName
, FileName
);
743 // Change '\\' to '/', unified path format.
745 Cptr
= PeMapFileName
;
746 while (*Cptr
!= '\0') {
748 *Cptr
= FILE_SEP_CHAR
;
756 Cptr
= PeMapFileName
+ strlen (PeMapFileName
);
757 while ((*Cptr
!= '.') && (Cptr
>= PeMapFileName
)) {
760 if (Cptr
< PeMapFileName
) {
761 return EFI_NOT_FOUND
;
773 while ((*Cptr
!= FILE_SEP_CHAR
) && (Cptr
>= PeMapFileName
)) {
777 strcpy (KeyWord
, Cptr
+ 1);
781 // AddressOfEntryPoint and Offset in Image
783 if (!pImageContext
->IsTeImage
) {
784 ImgHdr
= (EFI_IMAGE_OPTIONAL_HEADER_UNION
*) ((UINT8
*) pImageContext
->Handle
+ pImageContext
->PeCoffHeaderOffset
);
785 AddressOfEntryPoint
= ImgHdr
->Pe32
.OptionalHeader
.AddressOfEntryPoint
;
787 SectionHeader
= (EFI_IMAGE_SECTION_HEADER
*) (
790 sizeof (EFI_IMAGE_FILE_HEADER
) +
791 ImgHdr
->Pe32
.FileHeader
.SizeOfOptionalHeader
793 Index
= ImgHdr
->Pe32
.FileHeader
.NumberOfSections
;
795 TEImageHeader
= (EFI_TE_IMAGE_HEADER
*) pImageContext
->Handle
;
796 AddressOfEntryPoint
= TEImageHeader
->AddressOfEntryPoint
;
797 Offset
= TEImageHeader
->StrippedSize
- sizeof (EFI_TE_IMAGE_HEADER
);
798 SectionHeader
= (EFI_IMAGE_SECTION_HEADER
*) (TEImageHeader
+ 1);
799 Index
= TEImageHeader
->NumberOfSections
;
803 // module information output
805 if (ImageBaseAddress
== 0) {
806 fprintf (FvMapFile
, "%s (dummy) (", KeyWord
);
807 fprintf (FvMapFile
, "BaseAddress=%010llx, ", (unsigned long long) ImageBaseAddress
);
809 fprintf (FvMapFile
, "%s (Fixed Flash Address, ", KeyWord
);
810 fprintf (FvMapFile
, "BaseAddress=0x%010llx, ", (unsigned long long) (ImageBaseAddress
+ Offset
));
813 if (FfsFile
->Type
!= EFI_FV_FILETYPE_SECURITY_CORE
&& pImageContext
->Machine
== EFI_IMAGE_MACHINE_IA64
) {
815 // Process IPF PLABEL to get the real address after the image has been rebased.
816 // PLABEL structure is got by AddressOfEntryPoint offset to ImageBuffer stored in pImageContext->Handle.
818 fprintf (FvMapFile
, "EntryPoint=0x%010llx", (unsigned long long) (*(UINT64
*)((UINTN
) pImageContext
->Handle
+ (UINTN
) AddressOfEntryPoint
)));
820 fprintf (FvMapFile
, "EntryPoint=0x%010llx", (unsigned long long) (ImageBaseAddress
+ AddressOfEntryPoint
));
822 fprintf (FvMapFile
, ")\n");
824 fprintf (FvMapFile
, "(GUID=%s", FileGuidName
);
825 TextVirtualAddress
= 0;
826 DataVirtualAddress
= 0;
827 for (; Index
> 0; Index
--, SectionHeader
++) {
828 if (stricmp ((CHAR8
*)SectionHeader
->Name
, ".text") == 0) {
829 TextVirtualAddress
= SectionHeader
->VirtualAddress
;
830 } else if (stricmp ((CHAR8
*)SectionHeader
->Name
, ".data") == 0) {
831 DataVirtualAddress
= SectionHeader
->VirtualAddress
;
832 } else if (stricmp ((CHAR8
*)SectionHeader
->Name
, ".sdata") == 0) {
833 DataVirtualAddress
= SectionHeader
->VirtualAddress
;
836 fprintf (FvMapFile
, " .textbaseaddress=0x%010llx", (unsigned long long) (ImageBaseAddress
+ TextVirtualAddress
));
837 fprintf (FvMapFile
, " .databaseaddress=0x%010llx", (unsigned long long) (ImageBaseAddress
+ DataVirtualAddress
));
838 fprintf (FvMapFile
, ")\n\n");
843 PeMapFile
= fopen (PeMapFileName
, "r");
844 if (PeMapFile
== NULL
) {
845 // fprintf (stdout, "can't open %s file to reading\n", PeMapFileName);
848 VerboseMsg ("The map file is %s", PeMapFileName
);
851 // Output Functions information into Fv Map file
853 LinkTimeBaseAddress
= 0;
854 while (fgets (Line
, MAX_LINE_LEN
, PeMapFile
) != NULL
) {
858 if (Line
[0] == 0x0a) {
863 // By Address and Static keyword
865 if (FunctionType
== 0) {
866 sscanf (Line
, "%s", KeyWord
);
867 if (stricmp (KeyWord
, "Address") == 0) {
872 fgets (Line
, MAX_LINE_LEN
, PeMapFile
);
873 } else if (stricmp (KeyWord
, "Static") == 0) {
875 // static function list
878 fgets (Line
, MAX_LINE_LEN
, PeMapFile
);
879 } else if (stricmp (KeyWord
, "Preferred") ==0) {
880 sscanf (Line
+ strlen (" Preferred load address is"), "%llx", &TempLongAddress
);
881 LinkTimeBaseAddress
= (UINT64
) TempLongAddress
;
886 // Printf Function Information
888 if (FunctionType
== 1) {
889 sscanf (Line
, "%s %s %llx %s", KeyWord
, FunctionName
, &TempLongAddress
, FunctionTypeName
);
890 FunctionAddress
= (UINT64
) TempLongAddress
;
891 if (FunctionTypeName
[1] == '\0' && (FunctionTypeName
[0] == 'f' || FunctionTypeName
[0] == 'F')) {
892 fprintf (FvMapFile
, " 0x%010llx ", (unsigned long long) (ImageBaseAddress
+ FunctionAddress
- LinkTimeBaseAddress
));
893 fprintf (FvMapFile
, "%s\n", FunctionName
);
895 } else if (FunctionType
== 2) {
896 sscanf (Line
, "%s %s %llx %s", KeyWord
, FunctionName
, &TempLongAddress
, FunctionTypeName
);
897 FunctionAddress
= (UINT64
) TempLongAddress
;
898 if (FunctionTypeName
[1] == '\0' && (FunctionTypeName
[0] == 'f' || FunctionTypeName
[0] == 'F')) {
899 fprintf (FvMapFile
, " 0x%010llx ", (unsigned long long) (ImageBaseAddress
+ FunctionAddress
- LinkTimeBaseAddress
));
900 fprintf (FvMapFile
, "%s\n", FunctionName
);
907 fprintf (FvMapFile
, "\n\n");
915 IN OUT MEMORY_FILE
*FvImage
,
918 IN OUT EFI_FFS_FILE_HEADER
**VtfFileImage
,
920 IN
FILE *FvReportFile
926 This function adds a file to the FV image. The file will pad to the
927 appropriate alignment if required.
931 FvImage The memory image of the FV to add it to. The current offset
933 FvInfo Pointer to information about the FV.
934 Index The file in the FvInfo file list to add.
935 VtfFileImage A pointer to the VTF file within the FvImage. If this is equal
936 to the end of the FvImage then no VTF previously found.
937 FvMapFile Pointer to FvMap File
938 FvReportFile Pointer to FvReport File
942 EFI_SUCCESS The function completed successfully.
943 EFI_INVALID_PARAMETER One of the input parameters was invalid.
944 EFI_ABORTED An error occurred.
945 EFI_OUT_OF_RESOURCES Insufficient resources exist to complete the add.
953 UINT32 CurrentFileAlignment
;
956 UINT8 FileGuidString
[PRINTED_GUID_BUFFER_SIZE
];
960 // Verify input parameters.
962 if (FvImage
== NULL
|| FvInfo
== NULL
|| FvInfo
->FvFiles
[Index
][0] == 0 || VtfFileImage
== NULL
) {
963 return EFI_INVALID_PARAMETER
;
967 // Read the file to add
969 NewFile
= fopen (FvInfo
->FvFiles
[Index
], "rb");
971 if (NewFile
== NULL
) {
972 Error (NULL
, 0, 0001, "Error opening file", FvInfo
->FvFiles
[Index
]);
979 FileSize
= _filelength (fileno (NewFile
));
982 // Read the file into a buffer
984 FileBuffer
= malloc (FileSize
);
985 if (FileBuffer
== NULL
) {
986 Error (NULL
, 0, 4001, "Resouce", "memory cannot be allocated!");
987 return EFI_OUT_OF_RESOURCES
;
990 NumBytesRead
= fread (FileBuffer
, sizeof (UINT8
), FileSize
, NewFile
);
993 // Done with the file, from this point on we will just use the buffer read.
998 // Verify read successful
1000 if (NumBytesRead
!= sizeof (UINT8
) * FileSize
) {
1002 Error (NULL
, 0, 0004, "Error reading file", FvInfo
->FvFiles
[Index
]);
1007 // For None PI Ffs file, directly add them into FvImage.
1009 if (!FvInfo
->IsPiFvImage
) {
1010 memcpy (FvImage
->CurrentFilePointer
, FileBuffer
, FileSize
);
1011 if (FvInfo
->SizeofFvFiles
[Index
] > FileSize
) {
1012 FvImage
->CurrentFilePointer
+= FvInfo
->SizeofFvFiles
[Index
];
1014 FvImage
->CurrentFilePointer
+= FileSize
;
1022 Status
= VerifyFfsFile ((EFI_FFS_FILE_HEADER
*)FileBuffer
);
1023 if (EFI_ERROR (Status
)) {
1025 Error (NULL
, 0, 3000, "Invalid", "%s is not a valid FFS file.", FvInfo
->FvFiles
[Index
]);
1026 return EFI_INVALID_PARAMETER
;
1030 // Verify space exists to add the file
1032 if (FileSize
> (UINTN
) ((UINTN
) *VtfFileImage
- (UINTN
) FvImage
->CurrentFilePointer
)) {
1034 Error (NULL
, 0, 4002, "Resource", "FV space is full, not enough room to add file %s.", FvInfo
->FvFiles
[Index
]);
1035 return EFI_OUT_OF_RESOURCES
;
1039 // Verify the input file is the duplicated file in this Fv image
1041 for (Index1
= 0; Index1
< Index
; Index1
++) {
1042 if (CompareGuid ((EFI_GUID
*) FileBuffer
, &mFileGuidArray
[Index1
]) == 0) {
1043 Error (NULL
, 0, 2000, "Invalid parameter", "the %dth file and %uth file have the same file GUID.", (unsigned) Index1
+ 1, (unsigned) Index
+ 1);
1044 PrintGuid ((EFI_GUID
*) FileBuffer
);
1045 return EFI_INVALID_PARAMETER
;
1048 CopyMem (&mFileGuidArray
[Index
], FileBuffer
, sizeof (EFI_GUID
));
1051 // Update the file state based on polarity of the FV.
1053 UpdateFfsFileState (
1054 (EFI_FFS_FILE_HEADER
*) FileBuffer
,
1055 (EFI_FIRMWARE_VOLUME_HEADER
*) FvImage
->FileImage
1059 // Check if alignment is required
1061 ReadFfsAlignment ((EFI_FFS_FILE_HEADER
*) FileBuffer
, &CurrentFileAlignment
);
1064 // Find the largest alignment of all the FFS files in the FV
1066 if (CurrentFileAlignment
> MaxFfsAlignment
) {
1067 MaxFfsAlignment
= CurrentFileAlignment
;
1070 // If we have a VTF file, add it at the top.
1072 if (IsVtfFile ((EFI_FFS_FILE_HEADER
*) FileBuffer
)) {
1073 if ((UINTN
) *VtfFileImage
== (UINTN
) FvImage
->Eof
) {
1075 // No previous VTF, add this one.
1077 *VtfFileImage
= (EFI_FFS_FILE_HEADER
*) (UINTN
) ((UINTN
) FvImage
->FileImage
+ FvInfo
->Size
- FileSize
);
1079 // Sanity check. The file MUST align appropriately
1081 if (((UINTN
) *VtfFileImage
+ sizeof (EFI_FFS_FILE_HEADER
) - (UINTN
) FvImage
->FileImage
) % (1 << CurrentFileAlignment
)) {
1082 Error (NULL
, 0, 3000, "Invalid", "VTF file cannot be aligned on a %u-byte boundary.", (unsigned) (1 << CurrentFileAlignment
));
1087 // Rebase the PE or TE image in FileBuffer of FFS file for XIP
1088 // Rebase for the debug genfvmap tool
1090 Status
= FfsRebase (FvInfo
, FvInfo
->FvFiles
[Index
], (EFI_FFS_FILE_HEADER
*) FileBuffer
, (UINTN
) *VtfFileImage
- (UINTN
) FvImage
->FileImage
, FvMapFile
);
1091 if (EFI_ERROR (Status
)) {
1092 Error (NULL
, 0, 3000, "Invalid", "Could not rebase %s.", FvInfo
->FvFiles
[Index
]);
1098 memcpy (*VtfFileImage
, FileBuffer
, FileSize
);
1100 PrintGuidToBuffer ((EFI_GUID
*) FileBuffer
, FileGuidString
, sizeof (FileGuidString
), TRUE
);
1101 fprintf (FvReportFile
, "0x%08X %s\n", (unsigned)(UINTN
) (((UINT8
*)*VtfFileImage
) - (UINTN
)FvImage
->FileImage
), FileGuidString
);
1104 DebugMsg (NULL
, 0, 9, "Add VTF FFS file in FV image", NULL
);
1108 // Already found a VTF file.
1110 Error (NULL
, 0, 3000, "Invalid", "multiple VTF files are not permitted within a single FV.");
1117 // Add pad file if necessary
1119 Status
= AddPadFile (FvImage
, 1 << CurrentFileAlignment
, *VtfFileImage
, NULL
);
1120 if (EFI_ERROR (Status
)) {
1121 Error (NULL
, 0, 4002, "Resource", "FV space is full, could not add pad file for data alignment property.");
1128 if ((UINTN
) (FvImage
->CurrentFilePointer
+ FileSize
) <= (UINTN
) (*VtfFileImage
)) {
1130 // Rebase the PE or TE image in FileBuffer of FFS file for XIP.
1131 // Rebase Bs and Rt drivers for the debug genfvmap tool.
1133 Status
= FfsRebase (FvInfo
, FvInfo
->FvFiles
[Index
], (EFI_FFS_FILE_HEADER
*) FileBuffer
, (UINTN
) FvImage
->CurrentFilePointer
- (UINTN
) FvImage
->FileImage
, FvMapFile
);
1134 if (EFI_ERROR (Status
)) {
1135 Error (NULL
, 0, 3000, "Invalid", "Could not rebase %s.", FvInfo
->FvFiles
[Index
]);
1141 memcpy (FvImage
->CurrentFilePointer
, FileBuffer
, FileSize
);
1142 PrintGuidToBuffer ((EFI_GUID
*) FileBuffer
, FileGuidString
, sizeof (FileGuidString
), TRUE
);
1143 fprintf (FvReportFile
, "0x%08X %s\n", (unsigned) (FvImage
->CurrentFilePointer
- FvImage
->FileImage
), FileGuidString
);
1144 FvImage
->CurrentFilePointer
+= FileSize
;
1146 Error (NULL
, 0, 4002, "Resource", "FV space is full, cannot add file %s.", FvInfo
->FvFiles
[Index
]);
1151 // Make next file start at QWord Boundry
1153 while (((UINTN
) FvImage
->CurrentFilePointer
& (EFI_FFS_FILE_HEADER_ALIGNMENT
- 1)) != 0) {
1154 FvImage
->CurrentFilePointer
++;
1159 // Free allocated memory.
1168 IN MEMORY_FILE
*FvImage
,
1169 IN EFI_FFS_FILE_HEADER
*VtfFileImage
1173 Routine Description:
1175 This function places a pad file between the last file in the FV and the VTF
1176 file if the VTF file exists.
1180 FvImage Memory file for the FV memory image
1181 VtfFileImage The address of the VTF file. If this is the end of the FV
1182 image, no VTF exists and no pad file is needed.
1186 EFI_SUCCESS Completed successfully.
1187 EFI_INVALID_PARAMETER One of the input parameters was NULL.
1191 EFI_FFS_FILE_HEADER
*PadFile
;
1195 // If there is no VTF or the VTF naturally follows the previous file without a
1196 // pad file, then there's nothing to do
1198 if ((UINTN
) VtfFileImage
== (UINTN
) FvImage
->Eof
|| \
1199 ((UINTN
) VtfFileImage
== (UINTN
) FvImage
->CurrentFilePointer
)) {
1203 if ((UINTN
) VtfFileImage
< (UINTN
) FvImage
->CurrentFilePointer
) {
1204 return EFI_INVALID_PARAMETER
;
1208 // Pad file starts at beginning of free space
1210 PadFile
= (EFI_FFS_FILE_HEADER
*) FvImage
->CurrentFilePointer
;
1213 // write PadFile FFS header with PadType, don't need to set PAD file guid in its header.
1215 PadFile
->Type
= EFI_FV_FILETYPE_FFS_PAD
;
1216 PadFile
->Attributes
= 0;
1219 // FileSize includes the EFI_FFS_FILE_HEADER
1221 FileSize
= (UINTN
) VtfFileImage
- (UINTN
) FvImage
->CurrentFilePointer
;
1222 PadFile
->Size
[0] = (UINT8
) (FileSize
& 0x000000FF);
1223 PadFile
->Size
[1] = (UINT8
) ((FileSize
& 0x0000FF00) >> 8);
1224 PadFile
->Size
[2] = (UINT8
) ((FileSize
& 0x00FF0000) >> 16);
1227 // Fill in checksums and state, must be zero during checksum calculation.
1229 PadFile
->IntegrityCheck
.Checksum
.Header
= 0;
1230 PadFile
->IntegrityCheck
.Checksum
.File
= 0;
1232 PadFile
->IntegrityCheck
.Checksum
.Header
= CalculateChecksum8 ((UINT8
*) PadFile
, sizeof (EFI_FFS_FILE_HEADER
));
1233 PadFile
->IntegrityCheck
.Checksum
.File
= FFS_FIXED_CHECKSUM
;
1235 PadFile
->State
= EFI_FILE_HEADER_CONSTRUCTION
| EFI_FILE_HEADER_VALID
| EFI_FILE_DATA_VALID
;
1237 UpdateFfsFileState (
1238 (EFI_FFS_FILE_HEADER
*) PadFile
,
1239 (EFI_FIRMWARE_VOLUME_HEADER
*) FvImage
->FileImage
1242 // Update the current FV pointer
1244 FvImage
->CurrentFilePointer
= FvImage
->Eof
;
1251 IN MEMORY_FILE
*FvImage
,
1253 IN EFI_FFS_FILE_HEADER
*VtfFile
1257 Routine Description:
1259 This parses the FV looking for the PEI core and then plugs the address into
1260 the SALE_ENTRY point of the BSF/VTF for IPF and does BUGBUG TBD action to
1261 complete an IA32 Bootstrap FV.
1265 FvImage Memory file for the FV memory image
1266 FvInfo Information read from INF file.
1267 VtfFile Pointer to the VTF file in the FV image.
1271 EFI_SUCCESS Function Completed successfully.
1272 EFI_ABORTED Error encountered.
1273 EFI_INVALID_PARAMETER A required parameter was NULL.
1274 EFI_NOT_FOUND PEI Core file not found.
1278 EFI_FFS_FILE_HEADER
*PeiCoreFile
;
1279 EFI_FFS_FILE_HEADER
*SecCoreFile
;
1281 EFI_FILE_SECTION_POINTER Pe32Section
;
1285 EFI_PHYSICAL_ADDRESS PeiCorePhysicalAddress
;
1286 EFI_PHYSICAL_ADDRESS SecCorePhysicalAddress
;
1287 EFI_PHYSICAL_ADDRESS
*SecCoreEntryAddressPtr
;
1288 INT32 Ia32SecEntryOffset
;
1289 UINT32
*Ia32ResetAddressPtr
;
1291 UINT8
*BytePointer2
;
1292 UINT16
*WordPointer
;
1296 EFI_FFS_FILE_STATE SavedState
;
1298 FIT_TABLE
*FitTablePtr
;
1299 BOOLEAN Vtf0Detected
;
1302 // Verify input parameters
1304 if (FvImage
== NULL
|| FvInfo
== NULL
|| VtfFile
== NULL
) {
1305 return EFI_INVALID_PARAMETER
;
1308 // Initialize FV library
1310 InitializeFvLib (FvImage
->FileImage
, FvInfo
->Size
);
1315 Status
= VerifyFfsFile (VtfFile
);
1316 if (EFI_ERROR (Status
)) {
1317 return EFI_INVALID_PARAMETER
;
1321 (((UINTN
)FvImage
->Eof
- (UINTN
)FvImage
->FileImage
) >=
1322 IA32_X64_VTF_SIGNATURE_OFFSET
) &&
1323 (*(UINT32
*)(VOID
*)((UINTN
) FvImage
->Eof
-
1324 IA32_X64_VTF_SIGNATURE_OFFSET
) ==
1325 IA32_X64_VTF0_SIGNATURE
)
1327 Vtf0Detected
= TRUE
;
1329 Vtf0Detected
= FALSE
;
1333 // Find the Sec Core
1335 Status
= GetFileByType (EFI_FV_FILETYPE_SECURITY_CORE
, 1, &SecCoreFile
);
1336 if (EFI_ERROR (Status
) || SecCoreFile
== NULL
) {
1339 // If the SEC core file is not found, but the VTF-0 signature
1340 // is found, we'll treat it as a VTF-0 'Volume Top File'.
1341 // This means no modifications are required to the VTF.
1346 Error (NULL
, 0, 3000, "Invalid", "could not find the SEC core file in the FV.");
1350 // Sec Core found, now find PE32 section
1352 Status
= GetSectionByType (SecCoreFile
, EFI_SECTION_PE32
, 1, &Pe32Section
);
1353 if (Status
== EFI_NOT_FOUND
) {
1354 Status
= GetSectionByType (SecCoreFile
, EFI_SECTION_TE
, 1, &Pe32Section
);
1357 if (EFI_ERROR (Status
)) {
1358 Error (NULL
, 0, 3000, "Invalid", "could not find a PE32 section in the SEC core file.");
1362 Status
= GetPe32Info (
1363 (VOID
*) ((UINTN
) Pe32Section
.Pe32Section
+ sizeof (EFI_SECTION_PE32
)),
1369 if (EFI_ERROR (Status
)) {
1370 Error (NULL
, 0, 3000, "Invalid", "could not get the PE32 entry point for the SEC core.");
1376 (MachineType
== EFI_IMAGE_MACHINE_IA32
||
1377 MachineType
== EFI_IMAGE_MACHINE_X64
)
1380 // If the SEC core code is IA32 or X64 and the VTF-0 signature
1381 // is found, we'll treat it as a VTF-0 'Volume Top File'.
1382 // This means no modifications are required to the VTF.
1388 // Physical address is FV base + offset of PE32 + offset of the entry point
1390 SecCorePhysicalAddress
= FvInfo
->BaseAddress
;
1391 SecCorePhysicalAddress
+= (UINTN
) Pe32Section
.Pe32Section
+ sizeof (EFI_SECTION_PE32
) - (UINTN
) FvImage
->FileImage
;
1392 SecCorePhysicalAddress
+= EntryPoint
;
1393 DebugMsg (NULL
, 0, 9, "SecCore physical entry point address", "Address = 0x%llX", (unsigned long long) SecCorePhysicalAddress
);
1396 // Find the PEI Core
1398 Status
= GetFileByType (EFI_FV_FILETYPE_PEI_CORE
, 1, &PeiCoreFile
);
1399 if (EFI_ERROR (Status
) || PeiCoreFile
== NULL
) {
1400 Error (NULL
, 0, 3000, "Invalid", "could not find the PEI core in the FV.");
1404 // PEI Core found, now find PE32 or TE section
1406 Status
= GetSectionByType (PeiCoreFile
, EFI_SECTION_PE32
, 1, &Pe32Section
);
1407 if (Status
== EFI_NOT_FOUND
) {
1408 Status
= GetSectionByType (PeiCoreFile
, EFI_SECTION_TE
, 1, &Pe32Section
);
1411 if (EFI_ERROR (Status
)) {
1412 Error (NULL
, 0, 3000, "Invalid", "could not find either a PE32 or a TE section in PEI core file.");
1416 Status
= GetPe32Info (
1417 (VOID
*) ((UINTN
) Pe32Section
.Pe32Section
+ sizeof (EFI_SECTION_PE32
)),
1423 if (EFI_ERROR (Status
)) {
1424 Error (NULL
, 0, 3000, "Invalid", "could not get the PE32 entry point for the PEI core.");
1428 // Physical address is FV base + offset of PE32 + offset of the entry point
1430 PeiCorePhysicalAddress
= FvInfo
->BaseAddress
;
1431 PeiCorePhysicalAddress
+= (UINTN
) Pe32Section
.Pe32Section
+ sizeof (EFI_SECTION_PE32
) - (UINTN
) FvImage
->FileImage
;
1432 PeiCorePhysicalAddress
+= EntryPoint
;
1433 DebugMsg (NULL
, 0, 9, "PeiCore physical entry point address", "Address = 0x%llX", (unsigned long long) PeiCorePhysicalAddress
);
1435 if (MachineType
== EFI_IMAGE_MACHINE_IA64
) {
1437 // Update PEI_CORE address
1440 // Set the uncached attribute bit in the physical address
1442 PeiCorePhysicalAddress
|= 0x8000000000000000ULL
;
1445 // Check if address is aligned on a 16 byte boundary
1447 if (PeiCorePhysicalAddress
& 0xF) {
1448 Error (NULL
, 0, 3000, "Invalid",
1449 "PEI_CORE entry point is not aligned on a 16 byte boundary, address specified is %llXh.",
1450 (unsigned long long) PeiCorePhysicalAddress
1455 // First Get the FIT table address
1457 FitAddress
= (*(UINT64
*) (FvImage
->Eof
- IPF_FIT_ADDRESS_OFFSET
)) & 0xFFFFFFFF;
1459 FitTablePtr
= (FIT_TABLE
*) (FvImage
->FileImage
+ (FitAddress
- FvInfo
->BaseAddress
));
1461 Status
= UpdatePeiCoreEntryInFit (FitTablePtr
, PeiCorePhysicalAddress
);
1463 if (!EFI_ERROR (Status
)) {
1464 UpdateFitCheckSum (FitTablePtr
);
1468 // Update SEC_CORE address
1471 // Set the uncached attribute bit in the physical address
1473 SecCorePhysicalAddress
|= 0x8000000000000000ULL
;
1475 // Check if address is aligned on a 16 byte boundary
1477 if (SecCorePhysicalAddress
& 0xF) {
1478 Error (NULL
, 0, 3000, "Invalid",
1479 "SALE_ENTRY entry point is not aligned on a 16 byte boundary, address specified is %llXh.",
1480 (unsigned long long) SecCorePhysicalAddress
1485 // Update the address
1487 SecCoreEntryAddressPtr
= (EFI_PHYSICAL_ADDRESS
*) ((UINTN
) FvImage
->Eof
- IPF_SALE_ENTRY_ADDRESS_OFFSET
);
1488 *SecCoreEntryAddressPtr
= SecCorePhysicalAddress
;
1490 } else if (MachineType
== EFI_IMAGE_MACHINE_IA32
|| MachineType
== EFI_IMAGE_MACHINE_X64
) {
1492 // Get the location to update
1494 Ia32ResetAddressPtr
= (UINT32
*) ((UINTN
) FvImage
->Eof
- IA32_PEI_CORE_ENTRY_OFFSET
);
1497 // Write lower 32 bits of physical address for Pei Core entry
1499 *Ia32ResetAddressPtr
= (UINT32
) PeiCorePhysicalAddress
;
1502 // Write SecCore Entry point relative address into the jmp instruction in reset vector.
1504 Ia32ResetAddressPtr
= (UINT32
*) ((UINTN
) FvImage
->Eof
- IA32_SEC_CORE_ENTRY_OFFSET
);
1506 Ia32SecEntryOffset
= (INT32
) (SecCorePhysicalAddress
- (FV_IMAGES_TOP_ADDRESS
- IA32_SEC_CORE_ENTRY_OFFSET
+ 2));
1507 if (Ia32SecEntryOffset
<= -65536) {
1508 Error (NULL
, 0, 3000, "Invalid", "The SEC EXE file size is too large, it must be less than 64K.");
1509 return STATUS_ERROR
;
1512 *(UINT16
*) Ia32ResetAddressPtr
= (UINT16
) Ia32SecEntryOffset
;
1515 // Update the BFV base address
1517 Ia32ResetAddressPtr
= (UINT32
*) ((UINTN
) FvImage
->Eof
- 4);
1518 *Ia32ResetAddressPtr
= (UINT32
) (FvInfo
->BaseAddress
);
1519 DebugMsg (NULL
, 0, 9, "update BFV base address in the top FV image", "BFV base address = 0x%llX.", (unsigned long long) FvInfo
->BaseAddress
);
1522 // Update the Startup AP in the FVH header block ZeroVector region.
1524 BytePointer
= (UINT8
*) ((UINTN
) FvImage
->FileImage
);
1525 if (FvInfo
->Size
<= 0x10000) {
1526 BytePointer2
= m64kRecoveryStartupApDataArray
;
1527 } else if (FvInfo
->Size
<= 0x20000) {
1528 BytePointer2
= m128kRecoveryStartupApDataArray
;
1530 BytePointer2
= m128kRecoveryStartupApDataArray
;
1532 // Find the position to place Ap reset vector, the offset
1533 // between the position and the end of Fvrecovery.fv file
1534 // should not exceed 128kB to prevent Ap reset vector from
1535 // outside legacy E and F segment
1537 Status
= FindApResetVectorPosition (FvImage
, &BytePointer
);
1538 if (EFI_ERROR (Status
)) {
1539 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.");
1544 for (Index
= 0; Index
< SIZEOF_STARTUP_DATA_ARRAY
; Index
++) {
1545 BytePointer
[Index
] = BytePointer2
[Index
];
1548 // Calculate the checksum
1551 WordPointer
= (UINT16
*) (BytePointer
);
1552 for (Index
= 0; Index
< SIZEOF_STARTUP_DATA_ARRAY
/ 2; Index
++) {
1553 CheckSum
= (UINT16
) (CheckSum
+ ((UINT16
) *WordPointer
));
1557 // Update the checksum field
1559 WordPointer
= (UINT16
*) (BytePointer
+ SIZEOF_STARTUP_DATA_ARRAY
- 2);
1560 *WordPointer
= (UINT16
) (0x10000 - (UINT32
) CheckSum
);
1563 // IpiVector at the 4k aligned address in the top 2 blocks in the PEI FV.
1565 IpiVector
= (UINT32
) (FV_IMAGES_TOP_ADDRESS
- ((UINTN
) FvImage
->Eof
- (UINTN
) BytePointer
));
1566 DebugMsg (NULL
, 0, 9, "Startup AP Vector address", "IpiVector at 0x%X", (unsigned) IpiVector
);
1567 if ((IpiVector
& 0xFFF) != 0) {
1568 Error (NULL
, 0, 3000, "Invalid", "Startup AP Vector address are not 4K aligned, because the FV size is not 4K aligned");
1571 IpiVector
= IpiVector
>> 12;
1572 IpiVector
= IpiVector
& 0xFF;
1575 // Write IPI Vector at Offset FvrecoveryFileSize - 8
1577 Ia32ResetAddressPtr
= (UINT32
*) ((UINTN
) FvImage
->Eof
- 8);
1578 *Ia32ResetAddressPtr
= IpiVector
;
1579 } else if (MachineType
== EFI_IMAGE_MACHINE_ARMT
) {
1581 // Since the ARM reset vector is in the FV Header you really don't need a
1582 // Volume Top File, but if you have one for some reason don't crash...
1584 } else if (MachineType
== EFI_IMAGE_MACHINE_AARCH64
) {
1586 // Since the AArch64 reset vector is in the FV Header you really don't need a
1587 // Volume Top File, but if you have one for some reason don't crash...
1590 Error (NULL
, 0, 3000, "Invalid", "machine type=0x%X in PEI core.", MachineType
);
1595 // Now update file checksum
1597 SavedState
= VtfFile
->State
;
1598 VtfFile
->IntegrityCheck
.Checksum
.File
= 0;
1600 if (VtfFile
->Attributes
& FFS_ATTRIB_CHECKSUM
) {
1601 VtfFile
->IntegrityCheck
.Checksum
.File
= CalculateChecksum8 (
1602 (UINT8
*) (VtfFile
+ 1),
1603 GetLength (VtfFile
->Size
) - sizeof (EFI_FFS_FILE_HEADER
)
1606 VtfFile
->IntegrityCheck
.Checksum
.File
= FFS_FIXED_CHECKSUM
;
1609 VtfFile
->State
= SavedState
;
1616 UpdateArmResetVectorIfNeeded (
1617 IN MEMORY_FILE
*FvImage
,
1622 Routine Description:
1623 This parses the FV looking for SEC and patches that address into the
1624 beginning of the FV header.
1626 For ARM32 the reset vector is at 0x00000000 or 0xFFFF0000.
1627 For AArch64 the reset vector is at 0x00000000.
1629 This would commonly map to the first entry in the ROM.
1639 We support two schemes on ARM.
1640 1) Beginning of the FV is the reset vector
1641 2) Reset vector is data bytes FDF file and that code branches to reset vector
1642 in the beginning of the FV (fixed size offset).
1644 Need to have the jump for the reset vector at location zero.
1645 We also need to store the address or PEI (if it exists).
1646 We stub out a return from interrupt in case the debugger
1647 is using SWI (not done for AArch64, not enough space in struct).
1648 The optional entry to the common exception handler is
1649 to support full featured exception handling from ROM and is currently
1650 not support by this tool.
1653 FvImage Memory file for the FV memory image
1654 FvInfo Information read from INF file.
1658 EFI_SUCCESS Function Completed successfully.
1659 EFI_ABORTED Error encountered.
1660 EFI_INVALID_PARAMETER A required parameter was NULL.
1661 EFI_NOT_FOUND PEI Core file not found.
1665 EFI_FFS_FILE_HEADER
*PeiCoreFile
;
1666 EFI_FFS_FILE_HEADER
*SecCoreFile
;
1668 EFI_FILE_SECTION_POINTER Pe32Section
;
1672 EFI_PHYSICAL_ADDRESS PeiCorePhysicalAddress
;
1673 EFI_PHYSICAL_ADDRESS SecCorePhysicalAddress
;
1674 INT32 ResetVector
[4]; // ARM32:
1675 // 0 - is branch relative to SEC entry point
1676 // 1 - PEI Entry Point
1677 // 2 - movs pc,lr for a SWI handler
1678 // 3 - Place holder for Common Exception Handler
1679 // AArch64: Used as UINT64 ResetVector[2]
1680 // 0 - is branch relative to SEC entry point
1681 // 1 - PEI Entry Point
1684 // Verify input parameters
1686 if (FvImage
== NULL
|| FvInfo
== NULL
) {
1687 return EFI_INVALID_PARAMETER
;
1690 // Initialize FV library
1692 InitializeFvLib (FvImage
->FileImage
, FvInfo
->Size
);
1695 // Find the Sec Core
1697 Status
= GetFileByType (EFI_FV_FILETYPE_SECURITY_CORE
, 1, &SecCoreFile
);
1698 if (EFI_ERROR (Status
) || SecCoreFile
== NULL
) {
1700 // Maybe hardware does SEC job and we only have PEI Core?
1704 // Find the PEI Core. It may not exist if SEC loads DXE core directly
1706 PeiCorePhysicalAddress
= 0;
1707 Status
= GetFileByType (EFI_FV_FILETYPE_PEI_CORE
, 1, &PeiCoreFile
);
1708 if (!EFI_ERROR (Status
) && PeiCoreFile
!= NULL
) {
1710 // PEI Core found, now find PE32 or TE section
1712 Status
= GetSectionByType (PeiCoreFile
, EFI_SECTION_PE32
, 1, &Pe32Section
);
1713 if (Status
== EFI_NOT_FOUND
) {
1714 Status
= GetSectionByType (PeiCoreFile
, EFI_SECTION_TE
, 1, &Pe32Section
);
1717 if (EFI_ERROR (Status
)) {
1718 Error (NULL
, 0, 3000, "Invalid", "could not find either a PE32 or a TE section in PEI core file!");
1722 Status
= GetPe32Info (
1723 (VOID
*) ((UINTN
) Pe32Section
.Pe32Section
+ sizeof (EFI_SECTION_PE32
)),
1729 if (EFI_ERROR (Status
)) {
1730 Error (NULL
, 0, 3000, "Invalid", "could not get the PE32 entry point for the PEI core!");
1734 // Physical address is FV base + offset of PE32 + offset of the entry point
1736 PeiCorePhysicalAddress
= FvInfo
->BaseAddress
;
1737 PeiCorePhysicalAddress
+= (UINTN
) Pe32Section
.Pe32Section
+ sizeof (EFI_SECTION_PE32
) - (UINTN
) FvImage
->FileImage
;
1738 PeiCorePhysicalAddress
+= EntryPoint
;
1739 DebugMsg (NULL
, 0, 9, "PeiCore physical entry point address", "Address = 0x%llX", (unsigned long long) PeiCorePhysicalAddress
);
1741 if (MachineType
== EFI_IMAGE_MACHINE_ARMT
|| MachineType
== EFI_IMAGE_MACHINE_AARCH64
) {
1742 memset (ResetVector
, 0, sizeof (ResetVector
));
1743 // Address of PEI Core, if we have one
1744 ResetVector
[1] = (UINT32
)PeiCorePhysicalAddress
;
1748 // Copy to the beginning of the FV
1750 memcpy ((UINT8
*) ((UINTN
) FvImage
->FileImage
), ResetVector
, sizeof (ResetVector
));
1758 // Sec Core found, now find PE32 section
1760 Status
= GetSectionByType (SecCoreFile
, EFI_SECTION_PE32
, 1, &Pe32Section
);
1761 if (Status
== EFI_NOT_FOUND
) {
1762 Status
= GetSectionByType (SecCoreFile
, EFI_SECTION_TE
, 1, &Pe32Section
);
1765 if (EFI_ERROR (Status
)) {
1766 Error (NULL
, 0, 3000, "Invalid", "could not find a PE32 section in the SEC core file.");
1770 Status
= GetPe32Info (
1771 (VOID
*) ((UINTN
) Pe32Section
.Pe32Section
+ sizeof (EFI_SECTION_PE32
)),
1776 if (EFI_ERROR (Status
)) {
1777 Error (NULL
, 0, 3000, "Invalid", "could not get the PE32 entry point for the SEC core.");
1781 if ((MachineType
!= EFI_IMAGE_MACHINE_ARMT
) && (MachineType
!= EFI_IMAGE_MACHINE_AARCH64
)) {
1783 // If SEC is not ARM we have nothing to do
1789 // Physical address is FV base + offset of PE32 + offset of the entry point
1791 SecCorePhysicalAddress
= FvInfo
->BaseAddress
;
1792 SecCorePhysicalAddress
+= (UINTN
) Pe32Section
.Pe32Section
+ sizeof (EFI_SECTION_PE32
) - (UINTN
) FvImage
->FileImage
;
1793 SecCorePhysicalAddress
+= EntryPoint
;
1794 DebugMsg (NULL
, 0, 9, "SecCore physical entry point address", "Address = 0x%llX", (unsigned long long) SecCorePhysicalAddress
);
1797 // Find the PEI Core. It may not exist if SEC loads DXE core directly
1799 PeiCorePhysicalAddress
= 0;
1800 Status
= GetFileByType (EFI_FV_FILETYPE_PEI_CORE
, 1, &PeiCoreFile
);
1801 if (!EFI_ERROR (Status
) && PeiCoreFile
!= NULL
) {
1803 // PEI Core found, now find PE32 or TE section
1805 Status
= GetSectionByType (PeiCoreFile
, EFI_SECTION_PE32
, 1, &Pe32Section
);
1806 if (Status
== EFI_NOT_FOUND
) {
1807 Status
= GetSectionByType (PeiCoreFile
, EFI_SECTION_TE
, 1, &Pe32Section
);
1810 if (EFI_ERROR (Status
)) {
1811 Error (NULL
, 0, 3000, "Invalid", "could not find either a PE32 or a TE section in PEI core file!");
1815 Status
= GetPe32Info (
1816 (VOID
*) ((UINTN
) Pe32Section
.Pe32Section
+ sizeof (EFI_SECTION_PE32
)),
1822 if (EFI_ERROR (Status
)) {
1823 Error (NULL
, 0, 3000, "Invalid", "could not get the PE32 entry point for the PEI core!");
1827 // Physical address is FV base + offset of PE32 + offset of the entry point
1829 PeiCorePhysicalAddress
= FvInfo
->BaseAddress
;
1830 PeiCorePhysicalAddress
+= (UINTN
) Pe32Section
.Pe32Section
+ sizeof (EFI_SECTION_PE32
) - (UINTN
) FvImage
->FileImage
;
1831 PeiCorePhysicalAddress
+= EntryPoint
;
1832 DebugMsg (NULL
, 0, 9, "PeiCore physical entry point address", "Address = 0x%llX", (unsigned long long) PeiCorePhysicalAddress
);
1835 if (MachineType
== EFI_IMAGE_MACHINE_ARMT
) {
1836 // B SecEntryPoint - signed_immed_24 part +/-32MB offset
1837 // on ARM, the PC is always 8 ahead, so we're not really jumping from the base address, but from base address + 8
1838 ResetVector
[0] = (INT32
)(SecCorePhysicalAddress
- FvInfo
->BaseAddress
- 8) >> 2;
1840 if (ResetVector
[0] > 0x00FFFFFF) {
1841 Error (NULL
, 0, 3000, "Invalid", "SEC Entry point must be within 32MB of the start of the FV");
1845 // Add opcode for an uncondional branch with no link. AKA B SecEntryPoint
1846 ResetVector
[0] |= 0xEB000000;
1849 // Address of PEI Core, if we have one
1850 ResetVector
[1] = (UINT32
)PeiCorePhysicalAddress
;
1852 // SWI handler movs pc,lr. Just in case a debugger uses SWI
1853 ResetVector
[2] = 0xE1B0F07E;
1855 // Place holder to support a common interrupt handler from ROM.
1856 // Currently not suppprted. For this to be used the reset vector would not be in this FV
1857 // and the exception vectors would be hard coded in the ROM and just through this address
1858 // to find a common handler in the a module in the FV.
1860 } else if (MachineType
== EFI_IMAGE_MACHINE_AARCH64
) {
1863 ARMT above has an entry in ResetVector[2] for SWI. The way we are using the ResetVector
1864 array at the moment, for AArch64, does not allow us space for this as the header only
1865 allows for a fixed amount of bytes at the start. If we are sure that UEFI will live
1866 within the first 4GB of addressable RAM we could potensioally adopt the same ResetVector
1867 layout as above. But for the moment we replace the four 32bit vectors with two 64bit
1868 vectors in the same area of the Image heasder. This allows UEFI to start from a 64bit
1872 ((UINT64
*)ResetVector
)[0] = (UINT64
)(SecCorePhysicalAddress
- FvInfo
->BaseAddress
) >> 2;
1874 // B SecEntryPoint - signed_immed_26 part +/-128MB offset
1875 if ( ((UINT64
*)ResetVector
)[0] > 0x03FFFFFF) {
1876 Error (NULL
, 0, 3000, "Invalid", "SEC Entry point must be within 128MB of the start of the FV");
1879 // Add opcode for an uncondional branch with no link. AKA B SecEntryPoint
1880 ((UINT64
*)ResetVector
)[0] |= 0x14000000;
1882 // Address of PEI Core, if we have one
1883 ((UINT64
*)ResetVector
)[1] = (UINT64
)PeiCorePhysicalAddress
;
1886 Error (NULL
, 0, 3000, "Invalid", "Unknown ARM machine type");
1891 // Copy to the beginning of the FV
1893 memcpy ((UINT8
*) ((UINTN
) FvImage
->FileImage
), ResetVector
, sizeof (ResetVector
));
1895 DebugMsg (NULL
, 0, 9, "Update Reset vector in FV Header", NULL
);
1903 OUT UINT32
*EntryPoint
,
1904 OUT UINT32
*BaseOfCode
,
1905 OUT UINT16
*MachineType
1909 Routine Description:
1911 Retrieves the PE32 entry point offset and machine type from PE image or TeImage.
1912 See EfiImage.h for machine types. The entry point offset is from the beginning
1913 of the PE32 buffer passed in.
1917 Pe32 Beginning of the PE32.
1918 EntryPoint Offset from the beginning of the PE32 to the image entry point.
1919 BaseOfCode Base address of code.
1920 MachineType Magic number for the machine type.
1924 EFI_SUCCESS Function completed successfully.
1925 EFI_ABORTED Error encountered.
1926 EFI_INVALID_PARAMETER A required parameter was NULL.
1927 EFI_UNSUPPORTED The operation is unsupported.
1931 EFI_IMAGE_DOS_HEADER
*DosHeader
;
1932 EFI_IMAGE_OPTIONAL_HEADER_UNION
*ImgHdr
;
1933 EFI_TE_IMAGE_HEADER
*TeHeader
;
1936 // Verify input parameters
1939 return EFI_INVALID_PARAMETER
;
1943 // First check whether it is one TE Image.
1945 TeHeader
= (EFI_TE_IMAGE_HEADER
*) Pe32
;
1946 if (TeHeader
->Signature
== EFI_TE_IMAGE_HEADER_SIGNATURE
) {
1948 // By TeImage Header to get output
1950 *EntryPoint
= TeHeader
->AddressOfEntryPoint
+ sizeof (EFI_TE_IMAGE_HEADER
) - TeHeader
->StrippedSize
;
1951 *BaseOfCode
= TeHeader
->BaseOfCode
+ sizeof (EFI_TE_IMAGE_HEADER
) - TeHeader
->StrippedSize
;
1952 *MachineType
= TeHeader
->Machine
;
1956 // Then check whether
1957 // First is the DOS header
1959 DosHeader
= (EFI_IMAGE_DOS_HEADER
*) Pe32
;
1962 // Verify DOS header is expected
1964 if (DosHeader
->e_magic
!= EFI_IMAGE_DOS_SIGNATURE
) {
1965 Error (NULL
, 0, 3000, "Invalid", "Unknown magic number in the DOS header, 0x%04X.", DosHeader
->e_magic
);
1966 return EFI_UNSUPPORTED
;
1969 // Immediately following is the NT header.
1971 ImgHdr
= (EFI_IMAGE_OPTIONAL_HEADER_UNION
*) ((UINTN
) Pe32
+ DosHeader
->e_lfanew
);
1974 // Verify NT header is expected
1976 if (ImgHdr
->Pe32
.Signature
!= EFI_IMAGE_NT_SIGNATURE
) {
1977 Error (NULL
, 0, 3000, "Invalid", "Unrecognized image signature 0x%08X.", (unsigned) ImgHdr
->Pe32
.Signature
);
1978 return EFI_UNSUPPORTED
;
1983 *EntryPoint
= ImgHdr
->Pe32
.OptionalHeader
.AddressOfEntryPoint
;
1984 *BaseOfCode
= ImgHdr
->Pe32
.OptionalHeader
.BaseOfCode
;
1985 *MachineType
= ImgHdr
->Pe32
.FileHeader
.Machine
;
1989 // Verify machine type is supported
1991 if ((*MachineType
!= EFI_IMAGE_MACHINE_IA32
) && (*MachineType
!= EFI_IMAGE_MACHINE_IA64
) && (*MachineType
!= EFI_IMAGE_MACHINE_X64
) && (*MachineType
!= EFI_IMAGE_MACHINE_EBC
) &&
1992 (*MachineType
!= EFI_IMAGE_MACHINE_ARMT
) && (*MachineType
!= EFI_IMAGE_MACHINE_AARCH64
)) {
1993 Error (NULL
, 0, 3000, "Invalid", "Unrecognized machine type in the PE32 file.");
1994 return EFI_UNSUPPORTED
;
2002 IN CHAR8
*InfFileImage
,
2003 IN UINTN InfFileSize
,
2004 IN CHAR8
*FvFileName
,
2005 IN CHAR8
*MapFileName
2009 Routine Description:
2011 This is the main function which will be called from application.
2015 InfFileImage Buffer containing the INF file contents.
2016 InfFileSize Size of the contents of the InfFileImage buffer.
2017 FvFileName Requested name for the FV file.
2018 MapFileName Fv map file to log fv driver information.
2022 EFI_SUCCESS Function completed successfully.
2023 EFI_OUT_OF_RESOURCES Could not allocate required resources.
2024 EFI_ABORTED Error encountered.
2025 EFI_INVALID_PARAMETER A required parameter was NULL.
2030 MEMORY_FILE InfMemoryFile
;
2031 MEMORY_FILE FvImageMemoryFile
;
2033 EFI_FIRMWARE_VOLUME_HEADER
*FvHeader
;
2034 EFI_FFS_FILE_HEADER
*VtfFileImage
;
2035 UINT8
*FvBufferHeader
; // to make sure fvimage header 8 type alignment.
2039 CHAR8 FvMapName
[_MAX_PATH
];
2041 EFI_FIRMWARE_VOLUME_EXT_HEADER
*FvExtHeader
;
2042 FILE *FvExtHeaderFile
;
2044 CHAR8 FvReportName
[_MAX_PATH
];
2047 FvBufferHeader
= NULL
;
2050 FvReportFile
= NULL
;
2052 if (InfFileImage
!= NULL
) {
2054 // Initialize file structures
2056 InfMemoryFile
.FileImage
= InfFileImage
;
2057 InfMemoryFile
.CurrentFilePointer
= InfFileImage
;
2058 InfMemoryFile
.Eof
= InfFileImage
+ InfFileSize
;
2061 // Parse the FV inf file for header information
2063 Status
= ParseFvInf (&InfMemoryFile
, &mFvDataInfo
);
2064 if (EFI_ERROR (Status
)) {
2065 Error (NULL
, 0, 0003, "Error parsing file", "the input FV INF file.");
2071 // Update the file name return values
2073 if (FvFileName
== NULL
&& mFvDataInfo
.FvName
[0] != '\0') {
2074 FvFileName
= mFvDataInfo
.FvName
;
2077 if (FvFileName
== NULL
) {
2078 Error (NULL
, 0, 1001, "Missing option", "Output file name");
2082 if (mFvDataInfo
.FvBlocks
[0].Length
== 0) {
2083 Error (NULL
, 0, 1001, "Missing required argument", "Block Size");
2088 // Debug message Fv File System Guid
2090 if (mFvDataInfo
.FvFileSystemGuidSet
) {
2091 DebugMsg (NULL
, 0, 9, "FV File System Guid", "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X",
2092 (unsigned) mFvDataInfo
.FvFileSystemGuid
.Data1
,
2093 mFvDataInfo
.FvFileSystemGuid
.Data2
,
2094 mFvDataInfo
.FvFileSystemGuid
.Data3
,
2095 mFvDataInfo
.FvFileSystemGuid
.Data4
[0],
2096 mFvDataInfo
.FvFileSystemGuid
.Data4
[1],
2097 mFvDataInfo
.FvFileSystemGuid
.Data4
[2],
2098 mFvDataInfo
.FvFileSystemGuid
.Data4
[3],
2099 mFvDataInfo
.FvFileSystemGuid
.Data4
[4],
2100 mFvDataInfo
.FvFileSystemGuid
.Data4
[5],
2101 mFvDataInfo
.FvFileSystemGuid
.Data4
[6],
2102 mFvDataInfo
.FvFileSystemGuid
.Data4
[7]);
2106 // Add PI FV extension header
2109 FvExtHeaderFile
= NULL
;
2110 if (mFvDataInfo
.FvExtHeaderFile
[0] != 0) {
2112 // Open the FV Extension Header file
2114 FvExtHeaderFile
= fopen (mFvDataInfo
.FvExtHeaderFile
, "rb");
2117 // Get the file size
2119 FileSize
= _filelength (fileno (FvExtHeaderFile
));
2122 // Allocate a buffer for the FV Extension Header
2124 FvExtHeader
= malloc(FileSize
);
2125 if (FvExtHeader
== NULL
) {
2126 fclose (FvExtHeaderFile
);
2127 return EFI_OUT_OF_RESOURCES
;
2131 // Read the FV Extension Header
2133 fread (FvExtHeader
, sizeof (UINT8
), FileSize
, FvExtHeaderFile
);
2134 fclose (FvExtHeaderFile
);
2137 // See if there is an override for the FV Name GUID
2139 if (mFvDataInfo
.FvNameGuidSet
) {
2140 memcpy (&FvExtHeader
->FvName
, &mFvDataInfo
.FvNameGuid
, sizeof (EFI_GUID
));
2142 memcpy (&mFvDataInfo
.FvNameGuid
, &FvExtHeader
->FvName
, sizeof (EFI_GUID
));
2143 mFvDataInfo
.FvNameGuidSet
= TRUE
;
2144 } else if (mFvDataInfo
.FvNameGuidSet
) {
2146 // Allocate a buffer for the FV Extension Header
2148 FvExtHeader
= malloc(sizeof (EFI_FIRMWARE_VOLUME_EXT_HEADER
));
2149 if (FvExtHeader
== NULL
) {
2150 return EFI_OUT_OF_RESOURCES
;
2152 memcpy (&FvExtHeader
->FvName
, &mFvDataInfo
.FvNameGuid
, sizeof (EFI_GUID
));
2153 FvExtHeader
->ExtHeaderSize
= sizeof (EFI_FIRMWARE_VOLUME_EXT_HEADER
);
2157 // Debug message Fv Name Guid
2159 if (mFvDataInfo
.FvNameGuidSet
) {
2160 DebugMsg (NULL
, 0, 9, "FV Name Guid", "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X",
2161 (unsigned) mFvDataInfo
.FvNameGuid
.Data1
,
2162 mFvDataInfo
.FvNameGuid
.Data2
,
2163 mFvDataInfo
.FvNameGuid
.Data3
,
2164 mFvDataInfo
.FvNameGuid
.Data4
[0],
2165 mFvDataInfo
.FvNameGuid
.Data4
[1],
2166 mFvDataInfo
.FvNameGuid
.Data4
[2],
2167 mFvDataInfo
.FvNameGuid
.Data4
[3],
2168 mFvDataInfo
.FvNameGuid
.Data4
[4],
2169 mFvDataInfo
.FvNameGuid
.Data4
[5],
2170 mFvDataInfo
.FvNameGuid
.Data4
[6],
2171 mFvDataInfo
.FvNameGuid
.Data4
[7]);
2174 if (CompareGuid (&mFvDataInfo
.FvFileSystemGuid
, &mEfiFirmwareFileSystem2Guid
) == 0) {
2175 mFvDataInfo
.IsPiFvImage
= TRUE
;
2179 // FvMap file to log the function address of all modules in one Fvimage
2181 if (MapFileName
!= NULL
) {
2182 strcpy (FvMapName
, MapFileName
);
2184 strcpy (FvMapName
, FvFileName
);
2185 strcat (FvMapName
, ".map");
2187 VerboseMsg ("FV Map file name is %s", FvMapName
);
2190 // FvReport file to log the FV information in one Fvimage
2192 strcpy (FvReportName
, FvFileName
);
2193 strcat (FvReportName
, ".txt");
2196 // Calculate the FV size and Update Fv Size based on the actual FFS files.
2197 // And Update mFvDataInfo data.
2199 Status
= CalculateFvSize (&mFvDataInfo
);
2200 if (EFI_ERROR (Status
)) {
2203 VerboseMsg ("the generated FV image size is %u bytes", (unsigned) mFvDataInfo
.Size
);
2206 // support fv image and empty fv image
2208 FvImageSize
= mFvDataInfo
.Size
;
2211 // Allocate the FV, assure FvImage Header 8 byte alignment
2213 FvBufferHeader
= malloc (FvImageSize
+ sizeof (UINT64
));
2214 if (FvBufferHeader
== NULL
) {
2215 return EFI_OUT_OF_RESOURCES
;
2217 FvImage
= (UINT8
*) (((UINTN
) FvBufferHeader
+ 7) & ~7);
2220 // Initialize the FV to the erase polarity
2222 if (mFvDataInfo
.FvAttributes
== 0) {
2224 // Set Default Fv Attribute
2226 mFvDataInfo
.FvAttributes
= FV_DEFAULT_ATTRIBUTE
;
2228 if (mFvDataInfo
.FvAttributes
& EFI_FVB2_ERASE_POLARITY
) {
2229 memset (FvImage
, -1, FvImageSize
);
2231 memset (FvImage
, 0, FvImageSize
);
2235 // Initialize FV header
2237 FvHeader
= (EFI_FIRMWARE_VOLUME_HEADER
*) FvImage
;
2240 // Initialize the zero vector to all zeros.
2242 memset (FvHeader
->ZeroVector
, 0, 16);
2245 // Copy the Fv file system GUID
2247 memcpy (&FvHeader
->FileSystemGuid
, &mFvDataInfo
.FvFileSystemGuid
, sizeof (EFI_GUID
));
2249 FvHeader
->FvLength
= FvImageSize
;
2250 FvHeader
->Signature
= EFI_FVH_SIGNATURE
;
2251 FvHeader
->Attributes
= mFvDataInfo
.FvAttributes
;
2252 FvHeader
->Revision
= EFI_FVH_REVISION
;
2253 FvHeader
->ExtHeaderOffset
= 0;
2254 FvHeader
->Reserved
[0] = 0;
2257 // Copy firmware block map
2259 for (Index
= 0; mFvDataInfo
.FvBlocks
[Index
].Length
!= 0; Index
++) {
2260 FvHeader
->BlockMap
[Index
].NumBlocks
= mFvDataInfo
.FvBlocks
[Index
].NumBlocks
;
2261 FvHeader
->BlockMap
[Index
].Length
= mFvDataInfo
.FvBlocks
[Index
].Length
;
2265 // Add block map terminator
2267 FvHeader
->BlockMap
[Index
].NumBlocks
= 0;
2268 FvHeader
->BlockMap
[Index
].Length
= 0;
2271 // Complete the header
2273 FvHeader
->HeaderLength
= (UINT16
) (((UINTN
) &(FvHeader
->BlockMap
[Index
+ 1])) - (UINTN
) FvImage
);
2274 FvHeader
->Checksum
= 0;
2275 FvHeader
->Checksum
= CalculateChecksum16 ((UINT16
*) FvHeader
, FvHeader
->HeaderLength
/ sizeof (UINT16
));
2278 // If there is no FFS file, generate one empty FV
2280 if (mFvDataInfo
.FvFiles
[0][0] == 0 && !mFvDataInfo
.FvNameGuidSet
) {
2285 // Initialize our "file" view of the buffer
2287 FvImageMemoryFile
.FileImage
= (CHAR8
*)FvImage
;
2288 FvImageMemoryFile
.CurrentFilePointer
= (CHAR8
*)FvImage
+ FvHeader
->HeaderLength
;
2289 FvImageMemoryFile
.Eof
= (CHAR8
*)FvImage
+ FvImageSize
;
2292 // Initialize the FV library.
2294 InitializeFvLib (FvImageMemoryFile
.FileImage
, FvImageSize
);
2297 // Initialize the VTF file address.
2299 VtfFileImage
= (EFI_FFS_FILE_HEADER
*) FvImageMemoryFile
.Eof
;
2304 FvMapFile
= fopen (FvMapName
, "w");
2305 if (FvMapFile
== NULL
) {
2306 Error (NULL
, 0, 0001, "Error opening file", FvMapName
);
2311 // Open FvReport file
2313 FvReportFile
= fopen(FvReportName
, "w");
2314 if (FvReportFile
== NULL
) {
2315 Error (NULL
, 0, 0001, "Error opening file", FvReportName
);
2319 // record FV size information into FvMap file.
2321 if (mFvTotalSize
!= 0) {
2322 fprintf (FvMapFile
, EFI_FV_TOTAL_SIZE_STRING
);
2323 fprintf (FvMapFile
, " = 0x%x\n", (unsigned) mFvTotalSize
);
2325 if (mFvTakenSize
!= 0) {
2326 fprintf (FvMapFile
, EFI_FV_TAKEN_SIZE_STRING
);
2327 fprintf (FvMapFile
, " = 0x%x\n", (unsigned) mFvTakenSize
);
2329 if (mFvTotalSize
!= 0 && mFvTakenSize
!= 0) {
2330 fprintf (FvMapFile
, EFI_FV_SPACE_SIZE_STRING
);
2331 fprintf (FvMapFile
, " = 0x%x\n\n", (unsigned) (mFvTotalSize
- mFvTakenSize
));
2335 // record FV size information to FvReportFile.
2337 fprintf (FvReportFile
, "%s = 0x%x\n", EFI_FV_TOTAL_SIZE_STRING
, (unsigned) mFvTotalSize
);
2338 fprintf (FvReportFile
, "%s = 0x%x\n", EFI_FV_TAKEN_SIZE_STRING
, (unsigned) mFvTakenSize
);
2341 // Add PI FV extension header
2343 if (FvExtHeader
!= NULL
) {
2345 // Add FV Extended Header contents to the FV as a PAD file
2347 AddPadFile (&FvImageMemoryFile
, 4, VtfFileImage
, FvExtHeader
);
2350 // Fv Extension header change update Fv Header Check sum
2352 FvHeader
->Checksum
= 0;
2353 FvHeader
->Checksum
= CalculateChecksum16 ((UINT16
*) FvHeader
, FvHeader
->HeaderLength
/ sizeof (UINT16
));
2359 for (Index
= 0; mFvDataInfo
.FvFiles
[Index
][0] != 0; Index
++) {
2363 Status
= AddFile (&FvImageMemoryFile
, &mFvDataInfo
, Index
, &VtfFileImage
, FvMapFile
, FvReportFile
);
2366 // Exit if error detected while adding the file
2368 if (EFI_ERROR (Status
)) {
2374 // If there is a VTF file, some special actions need to occur.
2376 if ((UINTN
) VtfFileImage
!= (UINTN
) FvImageMemoryFile
.Eof
) {
2378 // Pad from the end of the last file to the beginning of the VTF file.
2379 // If the left space is less than sizeof (EFI_FFS_FILE_HEADER)?
2381 Status
= PadFvImage (&FvImageMemoryFile
, VtfFileImage
);
2382 if (EFI_ERROR (Status
)) {
2383 Error (NULL
, 0, 4002, "Resource", "FV space is full, cannot add pad file between the last file and the VTF file.");
2388 // Update reset vector (SALE_ENTRY for IPF)
2389 // Now for IA32 and IA64 platform, the fv which has bsf file must have the
2390 // EndAddress of 0xFFFFFFFF. Thus, only this type fv needs to update the
2391 // reset vector. If the PEI Core is found, the VTF file will probably get
2392 // corrupted by updating the entry point.
2394 if ((mFvDataInfo
.BaseAddress
+ mFvDataInfo
.Size
) == FV_IMAGES_TOP_ADDRESS
) {
2395 Status
= UpdateResetVector (&FvImageMemoryFile
, &mFvDataInfo
, VtfFileImage
);
2396 if (EFI_ERROR(Status
)) {
2397 Error (NULL
, 0, 3000, "Invalid", "Could not update the reset vector.");
2400 DebugMsg (NULL
, 0, 9, "Update Reset vector in VTF file", NULL
);
2406 Status
= UpdateArmResetVectorIfNeeded (&FvImageMemoryFile
, &mFvDataInfo
);
2407 if (EFI_ERROR (Status
)) {
2408 Error (NULL
, 0, 3000, "Invalid", "Could not update the reset vector.");
2413 // Update Checksum for FvHeader
2415 FvHeader
->Checksum
= 0;
2416 FvHeader
->Checksum
= CalculateChecksum16 ((UINT16
*) FvHeader
, FvHeader
->HeaderLength
/ sizeof (UINT16
));
2420 // Update FV Alignment attribute to the largest alignment of all the FFS files in the FV
2422 if ((((FvHeader
->Attributes
& EFI_FVB2_ALIGNMENT
) >> 16)) < MaxFfsAlignment
) {
2423 FvHeader
->Attributes
= ((MaxFfsAlignment
<< 16) | (FvHeader
->Attributes
& 0xFFFF));
2425 // Update Checksum for FvHeader
2427 FvHeader
->Checksum
= 0;
2428 FvHeader
->Checksum
= CalculateChecksum16 ((UINT16
*) FvHeader
, FvHeader
->HeaderLength
/ sizeof (UINT16
));
2435 FvFile
= fopen (FvFileName
, "wb");
2436 if (FvFile
== NULL
) {
2437 Error (NULL
, 0, 0001, "Error opening file", FvFileName
);
2438 Status
= EFI_ABORTED
;
2442 if (fwrite (FvImage
, 1, FvImageSize
, FvFile
) != FvImageSize
) {
2443 Error (NULL
, 0, 0002, "Error writing file", FvFileName
);
2444 Status
= EFI_ABORTED
;
2449 if (FvBufferHeader
!= NULL
) {
2450 free (FvBufferHeader
);
2453 if (FvExtHeader
!= NULL
) {
2457 if (FvFile
!= NULL
) {
2462 if (FvMapFile
!= NULL
) {
2467 if (FvReportFile
!= NULL
) {
2468 fflush (FvReportFile
);
2469 fclose (FvReportFile
);
2475 UpdatePeiCoreEntryInFit (
2476 IN FIT_TABLE
*FitTablePtr
,
2477 IN UINT64 PeiCorePhysicalAddress
2481 Routine Description:
2483 This function is used to update the Pei Core address in FIT, this can be used by Sec core to pass control from
2488 FitTablePtr - The pointer of FIT_TABLE.
2489 PeiCorePhysicalAddress - The address of Pei Core entry.
2493 EFI_SUCCESS - The PEI_CORE FIT entry was updated successfully.
2494 EFI_NOT_FOUND - Not found the PEI_CORE FIT entry.
2498 FIT_TABLE
*TmpFitPtr
;
2500 UINTN NumFitComponents
;
2502 TmpFitPtr
= FitTablePtr
;
2503 NumFitComponents
= TmpFitPtr
->CompSize
;
2505 for (Index
= 0; Index
< NumFitComponents
; Index
++) {
2506 if ((TmpFitPtr
->CvAndType
& FIT_TYPE_MASK
) == COMP_TYPE_FIT_PEICORE
) {
2507 TmpFitPtr
->CompAddress
= PeiCorePhysicalAddress
;
2514 return EFI_NOT_FOUND
;
2519 IN FIT_TABLE
*FitTablePtr
2523 Routine Description:
2525 This function is used to update the checksum for FIT.
2530 FitTablePtr - The pointer of FIT_TABLE.
2538 if ((FitTablePtr
->CvAndType
& CHECKSUM_BIT_MASK
) >> 7) {
2539 FitTablePtr
->CheckSum
= 0;
2540 FitTablePtr
->CheckSum
= CalculateChecksum8 ((UINT8
*) FitTablePtr
, FitTablePtr
->CompSize
* 16);
2549 Routine Description:
2550 Calculate the FV size and Update Fv Size based on the actual FFS files.
2551 And Update FvInfo data.
2554 FvInfoPtr - The pointer to FV_INFO structure.
2557 EFI_ABORTED - Ffs Image Error
2558 EFI_SUCCESS - Successfully update FvSize
2561 UINTN CurrentOffset
;
2565 UINTN FvExtendHeaderSize
;
2566 UINT32 FfsAlignment
;
2567 EFI_FFS_FILE_HEADER FfsHeader
;
2568 BOOLEAN VtfFileFlag
;
2571 FvExtendHeaderSize
= 0;
2573 VtfFileFlag
= FALSE
;
2578 // Compute size for easy access later
2580 FvInfoPtr
->Size
= 0;
2581 for (Index
= 0; FvInfoPtr
->FvBlocks
[Index
].NumBlocks
> 0 && FvInfoPtr
->FvBlocks
[Index
].Length
> 0; Index
++) {
2582 FvInfoPtr
->Size
+= FvInfoPtr
->FvBlocks
[Index
].NumBlocks
* FvInfoPtr
->FvBlocks
[Index
].Length
;
2586 // Caculate the required sizes for all FFS files.
2588 CurrentOffset
= sizeof (EFI_FIRMWARE_VOLUME_HEADER
);
2590 for (Index
= 1;; Index
++) {
2591 CurrentOffset
+= sizeof (EFI_FV_BLOCK_MAP_ENTRY
);
2592 if (FvInfoPtr
->FvBlocks
[Index
].NumBlocks
== 0 || FvInfoPtr
->FvBlocks
[Index
].Length
== 0) {
2598 // Calculate PI extension header
2600 if (mFvDataInfo
.FvExtHeaderFile
[0] != '\0') {
2601 fpin
= fopen (mFvDataInfo
.FvExtHeaderFile
, "rb");
2603 Error (NULL
, 0, 0001, "Error opening file", mFvDataInfo
.FvExtHeaderFile
);
2606 FvExtendHeaderSize
= _filelength (fileno (fpin
));
2608 CurrentOffset
+= sizeof (EFI_FFS_FILE_HEADER
) + FvExtendHeaderSize
;
2609 CurrentOffset
= (CurrentOffset
+ 7) & (~7);
2610 } else if (mFvDataInfo
.FvNameGuidSet
) {
2611 CurrentOffset
+= sizeof (EFI_FFS_FILE_HEADER
) + sizeof (EFI_FIRMWARE_VOLUME_EXT_HEADER
);
2612 CurrentOffset
= (CurrentOffset
+ 7) & (~7);
2616 // Accumlate every FFS file size.
2618 for (Index
= 0; FvInfoPtr
->FvFiles
[Index
][0] != 0; Index
++) {
2623 fpin
= fopen (FvInfoPtr
->FvFiles
[Index
], "rb");
2625 Error (NULL
, 0, 0001, "Error opening file", FvInfoPtr
->FvFiles
[Index
]);
2629 // Get the file size
2631 FfsFileSize
= _filelength (fileno (fpin
));
2633 // Read Ffs File header
2635 fread (&FfsHeader
, sizeof (UINT8
), sizeof (EFI_FFS_FILE_HEADER
), fpin
);
2641 if (FvInfoPtr
->IsPiFvImage
) {
2643 // Check whether this ffs file is vtf file
2645 if (IsVtfFile (&FfsHeader
)) {
2648 // One Fv image can't have two vtf files.
2653 VtfFileSize
= FfsFileSize
;
2658 // Get the alignment of FFS file
2660 ReadFfsAlignment (&FfsHeader
, &FfsAlignment
);
2661 FfsAlignment
= 1 << FfsAlignment
;
2665 if (((CurrentOffset
+ sizeof (EFI_FFS_FILE_HEADER
)) % FfsAlignment
) != 0) {
2666 CurrentOffset
= (CurrentOffset
+ sizeof (EFI_FFS_FILE_HEADER
) * 2 + FfsAlignment
- 1) & ~(FfsAlignment
- 1);
2667 CurrentOffset
-= sizeof (EFI_FFS_FILE_HEADER
);
2672 // Add ffs file size
2674 if (FvInfoPtr
->SizeofFvFiles
[Index
] > FfsFileSize
) {
2675 CurrentOffset
+= FvInfoPtr
->SizeofFvFiles
[Index
];
2677 CurrentOffset
+= FfsFileSize
;
2681 // Make next ffs file start at QWord Boundry
2683 if (FvInfoPtr
->IsPiFvImage
) {
2684 CurrentOffset
= (CurrentOffset
+ EFI_FFS_FILE_HEADER_ALIGNMENT
- 1) & ~(EFI_FFS_FILE_HEADER_ALIGNMENT
- 1);
2687 CurrentOffset
+= VtfFileSize
;
2688 DebugMsg (NULL
, 0, 9, "FvImage size", "The caculated fv image size is 0x%x and the current set fv image size is 0x%x", (unsigned) CurrentOffset
, (unsigned) FvInfoPtr
->Size
);
2690 if (FvInfoPtr
->Size
== 0) {
2692 // Update FvInfo data
2694 FvInfoPtr
->FvBlocks
[0].NumBlocks
= CurrentOffset
/ FvInfoPtr
->FvBlocks
[0].Length
+ ((CurrentOffset
% FvInfoPtr
->FvBlocks
[0].Length
)?1:0);
2695 FvInfoPtr
->Size
= FvInfoPtr
->FvBlocks
[0].NumBlocks
* FvInfoPtr
->FvBlocks
[0].Length
;
2696 FvInfoPtr
->FvBlocks
[1].NumBlocks
= 0;
2697 FvInfoPtr
->FvBlocks
[1].Length
= 0;
2698 } else if (FvInfoPtr
->Size
< CurrentOffset
) {
2702 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
);
2703 return EFI_INVALID_PARAMETER
;
2707 // Set Fv Size Information
2709 mFvTotalSize
= FvInfoPtr
->Size
;
2710 mFvTakenSize
= CurrentOffset
;
2716 FfsRebaseImageRead (
2717 IN VOID
*FileHandle
,
2718 IN UINTN FileOffset
,
2719 IN OUT UINT32
*ReadSize
,
2724 Routine Description:
2726 Support routine for the PE/COFF Loader that reads a buffer from a PE/COFF file
2730 FileHandle - The handle to the PE/COFF file
2732 FileOffset - The offset, in bytes, into the file to read
2734 ReadSize - The number of bytes to read from the file starting at FileOffset
2736 Buffer - A pointer to the buffer to read the data into.
2740 EFI_SUCCESS - ReadSize bytes of data were read into Buffer from the PE/COFF file starting at FileOffset
2744 CHAR8
*Destination8
;
2748 Destination8
= Buffer
;
2749 Source8
= (CHAR8
*) ((UINTN
) FileHandle
+ FileOffset
);
2752 *(Destination8
++) = *(Source8
++);
2761 IN EFI_FFS_FILE_HEADER
*FfsFile
,
2766 Routine Description:
2768 This function gets all child FvImages in the input FfsFile, and records
2769 their base address to the parent image.
2772 FvInfo A pointer to FV_INFO struture.
2773 FfsFile A pointer to Ffs file image that may contain FvImage.
2774 XipOffset The offset address to the parent FvImage base.
2778 EFI_SUCCESS Base address of child Fv image is recorded.
2783 EFI_FILE_SECTION_POINTER SubFvSection
;
2784 EFI_FIRMWARE_VOLUME_HEADER
*SubFvImageHeader
;
2785 EFI_PHYSICAL_ADDRESS SubFvBaseAddress
;
2787 for (Index
= 1;; Index
++) {
2791 Status
= GetSectionByType (FfsFile
, EFI_SECTION_FIRMWARE_VOLUME_IMAGE
, Index
, &SubFvSection
);
2792 if (EFI_ERROR (Status
)) {
2795 SubFvImageHeader
= (EFI_FIRMWARE_VOLUME_HEADER
*) ((UINT8
*) SubFvSection
.FVImageSection
+ sizeof (EFI_FIRMWARE_VOLUME_IMAGE_SECTION
));
2799 SubFvBaseAddress
= FvInfo
->BaseAddress
+ (UINTN
) SubFvImageHeader
- (UINTN
) FfsFile
+ XipOffset
;
2800 mFvBaseAddress
[mFvBaseAddressNumber
++ ] = SubFvBaseAddress
;
2808 IN OUT FV_INFO
*FvInfo
,
2810 IN OUT EFI_FFS_FILE_HEADER
*FfsFile
,
2816 Routine Description:
2818 This function determines if a file is XIP and should be rebased. It will
2819 rebase any PE32 sections found in the file using the base address.
2823 FvInfo A pointer to FV_INFO struture.
2824 FileName Ffs File PathName
2825 FfsFile A pointer to Ffs file image.
2826 XipOffset The offset address to use for rebasing the XIP file image.
2827 FvMapFile FvMapFile to record the function address in one Fvimage
2831 EFI_SUCCESS The image was properly rebased.
2832 EFI_INVALID_PARAMETER An input parameter is invalid.
2833 EFI_ABORTED An error occurred while rebasing the input file image.
2834 EFI_OUT_OF_RESOURCES Could not allocate a required resource.
2835 EFI_NOT_FOUND No compressed sections could be found.
2840 PE_COFF_LOADER_IMAGE_CONTEXT ImageContext
;
2841 PE_COFF_LOADER_IMAGE_CONTEXT OrigImageContext
;
2842 EFI_PHYSICAL_ADDRESS XipBase
;
2843 EFI_PHYSICAL_ADDRESS NewPe32BaseAddress
;
2845 EFI_FILE_SECTION_POINTER CurrentPe32Section
;
2846 EFI_FFS_FILE_STATE SavedState
;
2847 EFI_IMAGE_OPTIONAL_HEADER_UNION
*ImgHdr
;
2848 EFI_TE_IMAGE_HEADER
*TEImageHeader
;
2849 UINT8
*MemoryImagePointer
;
2850 EFI_IMAGE_SECTION_HEADER
*SectionHeader
;
2851 CHAR8 PeFileName
[_MAX_PATH
];
2854 UINT8
*PeFileBuffer
;
2859 MemoryImagePointer
= NULL
;
2860 TEImageHeader
= NULL
;
2862 SectionHeader
= NULL
;
2865 PeFileBuffer
= NULL
;
2868 // Don't need to relocate image when BaseAddress is zero and no ForceRebase Flag specified.
2870 if ((FvInfo
->BaseAddress
== 0) && (FvInfo
->ForceRebase
== -1)) {
2875 // If ForceRebase Flag specified to FALSE, will always not take rebase action.
2877 if (FvInfo
->ForceRebase
== 0) {
2882 XipBase
= FvInfo
->BaseAddress
+ XipOffset
;
2885 // We only process files potentially containing PE32 sections.
2887 switch (FfsFile
->Type
) {
2888 case EFI_FV_FILETYPE_SECURITY_CORE
:
2889 case EFI_FV_FILETYPE_PEI_CORE
:
2890 case EFI_FV_FILETYPE_PEIM
:
2891 case EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER
:
2892 case EFI_FV_FILETYPE_DRIVER
:
2893 case EFI_FV_FILETYPE_DXE_CORE
:
2895 case EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE
:
2897 // Rebase the inside FvImage.
2899 GetChildFvFromFfs (FvInfo
, FfsFile
, XipOffset
);
2902 // Search PE/TE section in FV sectin.
2909 // Rebase each PE32 section
2911 Status
= EFI_SUCCESS
;
2912 for (Index
= 1;; Index
++) {
2916 NewPe32BaseAddress
= 0;
2921 Status
= GetSectionByType (FfsFile
, EFI_SECTION_PE32
, Index
, &CurrentPe32Section
);
2922 if (EFI_ERROR (Status
)) {
2927 // Initialize context
2929 memset (&ImageContext
, 0, sizeof (ImageContext
));
2930 ImageContext
.Handle
= (VOID
*) ((UINTN
) CurrentPe32Section
.Pe32Section
+ sizeof (EFI_PE32_SECTION
));
2931 ImageContext
.ImageRead
= (PE_COFF_LOADER_READ_FILE
) FfsRebaseImageRead
;
2932 Status
= PeCoffLoaderGetImageInfo (&ImageContext
);
2933 if (EFI_ERROR (Status
)) {
2934 Error (NULL
, 0, 3000, "Invalid PeImage", "The input file is %s and the return status is %x", FileName
, (int) Status
);
2938 if ( (ImageContext
.Machine
== EFI_IMAGE_MACHINE_ARMT
) ||
2939 (ImageContext
.Machine
== EFI_IMAGE_MACHINE_AARCH64
) ) {
2944 // Keep Image Context for PE image in FV
2946 memcpy (&OrigImageContext
, &ImageContext
, sizeof (ImageContext
));
2949 // Get File PdbPointer
2951 PdbPointer
= PeCoffLoaderGetPdbPointer (ImageContext
.Handle
);
2954 // Get PeHeader pointer
2956 ImgHdr
= (EFI_IMAGE_OPTIONAL_HEADER_UNION
*)((UINTN
) CurrentPe32Section
.Pe32Section
+ sizeof (EFI_PE32_SECTION
) + ImageContext
.PeCoffHeaderOffset
);
2959 // Calculate the PE32 base address, based on file type
2961 switch (FfsFile
->Type
) {
2962 case EFI_FV_FILETYPE_SECURITY_CORE
:
2963 case EFI_FV_FILETYPE_PEI_CORE
:
2964 case EFI_FV_FILETYPE_PEIM
:
2965 case EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER
:
2967 // Check if section-alignment and file-alignment match or not
2969 if ((ImgHdr
->Pe32
.OptionalHeader
.SectionAlignment
!= ImgHdr
->Pe32
.OptionalHeader
.FileAlignment
)) {
2971 // Xip module has the same section alignment and file alignment.
2973 Error (NULL
, 0, 3000, "Invalid", "Section-Alignment and File-Alignment do not match : %s.", FileName
);
2977 // PeImage has no reloc section. It will try to get reloc data from the original EFI image.
2979 if (ImageContext
.RelocationsStripped
) {
2981 // Construct the original efi file Name
2983 strcpy (PeFileName
, FileName
);
2984 Cptr
= PeFileName
+ strlen (PeFileName
);
2985 while (*Cptr
!= '.') {
2989 Error (NULL
, 0, 3000, "Invalid", "The file %s has no .reloc section.", FileName
);
2997 PeFile
= fopen (PeFileName
, "rb");
2998 if (PeFile
== NULL
) {
2999 Warning (NULL
, 0, 0, "Invalid", "The file %s has no .reloc section.", FileName
);
3000 //Error (NULL, 0, 3000, "Invalid", "The file %s has no .reloc section.", FileName);
3001 //return EFI_ABORTED;
3005 // Get the file size
3007 PeFileSize
= _filelength (fileno (PeFile
));
3008 PeFileBuffer
= (UINT8
*) malloc (PeFileSize
);
3009 if (PeFileBuffer
== NULL
) {
3010 Error (NULL
, 0, 4001, "Resource", "memory cannot be allocated on rebase of %s", FileName
);
3011 return EFI_OUT_OF_RESOURCES
;
3016 fread (PeFileBuffer
, sizeof (UINT8
), PeFileSize
, PeFile
);
3022 // Handle pointer to the original efi image.
3024 ImageContext
.Handle
= PeFileBuffer
;
3025 Status
= PeCoffLoaderGetImageInfo (&ImageContext
);
3026 if (EFI_ERROR (Status
)) {
3027 Error (NULL
, 0, 3000, "Invalid PeImage", "The input file is %s and the return status is %x", FileName
, (int) Status
);
3030 ImageContext
.RelocationsStripped
= FALSE
;
3033 NewPe32BaseAddress
= XipBase
+ (UINTN
) CurrentPe32Section
.Pe32Section
+ sizeof (EFI_PE32_SECTION
) - (UINTN
)FfsFile
;
3036 case EFI_FV_FILETYPE_DRIVER
:
3037 case EFI_FV_FILETYPE_DXE_CORE
:
3039 // Check if section-alignment and file-alignment match or not
3041 if ((ImgHdr
->Pe32
.OptionalHeader
.SectionAlignment
!= ImgHdr
->Pe32
.OptionalHeader
.FileAlignment
)) {
3043 // Xip module has the same section alignment and file alignment.
3045 Error (NULL
, 0, 3000, "Invalid", "Section-Alignment and File-Alignment do not match : %s.", FileName
);
3048 NewPe32BaseAddress
= XipBase
+ (UINTN
) CurrentPe32Section
.Pe32Section
+ sizeof (EFI_PE32_SECTION
) - (UINTN
)FfsFile
;
3053 // Not supported file type
3059 // Relocation doesn't exist
3061 if (ImageContext
.RelocationsStripped
) {
3062 Warning (NULL
, 0, 0, "Invalid", "The file %s has no .reloc section.", FileName
);
3067 // Relocation exist and rebase
3070 // Load and Relocate Image Data
3072 MemoryImagePointer
= (UINT8
*) malloc ((UINTN
) ImageContext
.ImageSize
+ ImageContext
.SectionAlignment
);
3073 if (MemoryImagePointer
== NULL
) {
3074 Error (NULL
, 0, 4001, "Resource", "memory cannot be allocated on rebase of %s", FileName
);
3075 return EFI_OUT_OF_RESOURCES
;
3077 memset ((VOID
*) MemoryImagePointer
, 0, (UINTN
) ImageContext
.ImageSize
+ ImageContext
.SectionAlignment
);
3078 ImageContext
.ImageAddress
= ((UINTN
) MemoryImagePointer
+ ImageContext
.SectionAlignment
- 1) & (~((UINTN
) ImageContext
.SectionAlignment
- 1));
3080 Status
= PeCoffLoaderLoadImage (&ImageContext
);
3081 if (EFI_ERROR (Status
)) {
3082 Error (NULL
, 0, 3000, "Invalid", "LocateImage() call failed on rebase of %s", FileName
);
3083 free ((VOID
*) MemoryImagePointer
);
3087 ImageContext
.DestinationAddress
= NewPe32BaseAddress
;
3088 Status
= PeCoffLoaderRelocateImage (&ImageContext
);
3089 if (EFI_ERROR (Status
)) {
3090 Error (NULL
, 0, 3000, "Invalid", "RelocateImage() call failed on rebase of %s", FileName
);
3091 free ((VOID
*) MemoryImagePointer
);
3096 // Copy Relocated data to raw image file.
3098 SectionHeader
= (EFI_IMAGE_SECTION_HEADER
*) (
3101 sizeof (EFI_IMAGE_FILE_HEADER
) +
3102 ImgHdr
->Pe32
.FileHeader
.SizeOfOptionalHeader
3105 for (Index
= 0; Index
< ImgHdr
->Pe32
.FileHeader
.NumberOfSections
; Index
++, SectionHeader
++) {
3107 (UINT8
*) CurrentPe32Section
.Pe32Section
+ sizeof (EFI_COMMON_SECTION_HEADER
) + SectionHeader
->PointerToRawData
,
3108 (VOID
*) (UINTN
) (ImageContext
.ImageAddress
+ SectionHeader
->VirtualAddress
),
3109 SectionHeader
->SizeOfRawData
3113 free ((VOID
*) MemoryImagePointer
);
3114 MemoryImagePointer
= NULL
;
3115 if (PeFileBuffer
!= NULL
) {
3116 free (PeFileBuffer
);
3117 PeFileBuffer
= NULL
;
3121 // Update Image Base Address
3123 if (ImgHdr
->Pe32
.OptionalHeader
.Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
3124 ImgHdr
->Pe32
.OptionalHeader
.ImageBase
= (UINT32
) NewPe32BaseAddress
;
3125 } else if (ImgHdr
->Pe32Plus
.OptionalHeader
.Magic
== EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC
) {
3126 ImgHdr
->Pe32Plus
.OptionalHeader
.ImageBase
= NewPe32BaseAddress
;
3128 Error (NULL
, 0, 3000, "Invalid", "unknown PE magic signature %X in PE32 image %s",
3129 ImgHdr
->Pe32
.OptionalHeader
.Magic
,
3136 // Now update file checksum
3138 if (FfsFile
->Attributes
& FFS_ATTRIB_CHECKSUM
) {
3139 SavedState
= FfsFile
->State
;
3140 FfsFile
->IntegrityCheck
.Checksum
.File
= 0;
3142 FfsFile
->IntegrityCheck
.Checksum
.File
= CalculateChecksum8 (
3143 (UINT8
*) (FfsFile
+ 1),
3144 GetLength (FfsFile
->Size
) - sizeof (EFI_FFS_FILE_HEADER
)
3146 FfsFile
->State
= SavedState
;
3150 // Get this module function address from ModulePeMapFile and add them into FvMap file
3154 // Default use FileName as map file path
3156 if (PdbPointer
== NULL
) {
3157 PdbPointer
= FileName
;
3160 WriteMapFile (FvMapFile
, PdbPointer
, FfsFile
, NewPe32BaseAddress
, &OrigImageContext
);
3163 if (FfsFile
->Type
!= EFI_FV_FILETYPE_SECURITY_CORE
&&
3164 FfsFile
->Type
!= EFI_FV_FILETYPE_PEI_CORE
&&
3165 FfsFile
->Type
!= EFI_FV_FILETYPE_PEIM
&&
3166 FfsFile
->Type
!= EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER
&&
3167 FfsFile
->Type
!= EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE
3170 // Only Peim code may have a TE section
3176 // Now process TE sections
3178 for (Index
= 1;; Index
++) {
3179 NewPe32BaseAddress
= 0;
3184 Status
= GetSectionByType (FfsFile
, EFI_SECTION_TE
, Index
, &CurrentPe32Section
);
3185 if (EFI_ERROR (Status
)) {
3190 // Calculate the TE base address, the FFS file base plus the offset of the TE section less the size stripped off
3193 TEImageHeader
= (EFI_TE_IMAGE_HEADER
*) ((UINT8
*) CurrentPe32Section
.Pe32Section
+ sizeof (EFI_COMMON_SECTION_HEADER
));
3196 // Initialize context, load image info.
3198 memset (&ImageContext
, 0, sizeof (ImageContext
));
3199 ImageContext
.Handle
= (VOID
*) TEImageHeader
;
3200 ImageContext
.ImageRead
= (PE_COFF_LOADER_READ_FILE
) FfsRebaseImageRead
;
3201 Status
= PeCoffLoaderGetImageInfo (&ImageContext
);
3202 if (EFI_ERROR (Status
)) {
3203 Error (NULL
, 0, 3000, "Invalid TeImage", "The input file is %s and the return status is %x", FileName
, (int) Status
);
3207 if ( (ImageContext
.Machine
== EFI_IMAGE_MACHINE_ARMT
) ||
3208 (ImageContext
.Machine
== EFI_IMAGE_MACHINE_AARCH64
) ) {
3213 // Keep Image Context for TE image in FV
3215 memcpy (&OrigImageContext
, &ImageContext
, sizeof (ImageContext
));
3218 // Get File PdbPointer
3220 PdbPointer
= PeCoffLoaderGetPdbPointer (ImageContext
.Handle
);
3223 // Set new rebased address.
3225 NewPe32BaseAddress
= XipBase
+ (UINTN
) TEImageHeader
+ sizeof (EFI_TE_IMAGE_HEADER
) \
3226 - TEImageHeader
->StrippedSize
- (UINTN
) FfsFile
;
3229 // if reloc is stripped, try to get the original efi image to get reloc info.
3231 if (ImageContext
.RelocationsStripped
) {
3233 // Construct the original efi file name
3235 strcpy (PeFileName
, FileName
);
3236 Cptr
= PeFileName
+ strlen (PeFileName
);
3237 while (*Cptr
!= '.') {
3242 Error (NULL
, 0, 3000, "Invalid", "The file %s has no .reloc section.", FileName
);
3251 PeFile
= fopen (PeFileName
, "rb");
3252 if (PeFile
== NULL
) {
3253 Warning (NULL
, 0, 0, "Invalid", "The file %s has no .reloc section.", FileName
);
3254 //Error (NULL, 0, 3000, "Invalid", "The file %s has no .reloc section.", FileName);
3255 //return EFI_ABORTED;
3258 // Get the file size
3260 PeFileSize
= _filelength (fileno (PeFile
));
3261 PeFileBuffer
= (UINT8
*) malloc (PeFileSize
);
3262 if (PeFileBuffer
== NULL
) {
3263 Error (NULL
, 0, 4001, "Resource", "memory cannot be allocated on rebase of %s", FileName
);
3264 return EFI_OUT_OF_RESOURCES
;
3269 fread (PeFileBuffer
, sizeof (UINT8
), PeFileSize
, PeFile
);
3275 // Append reloc section into TeImage
3277 ImageContext
.Handle
= PeFileBuffer
;
3278 Status
= PeCoffLoaderGetImageInfo (&ImageContext
);
3279 if (EFI_ERROR (Status
)) {
3280 Error (NULL
, 0, 3000, "Invalid TeImage", "The input file is %s and the return status is %x", FileName
, (int) Status
);
3283 ImageContext
.RelocationsStripped
= FALSE
;
3287 // Relocation doesn't exist
3289 if (ImageContext
.RelocationsStripped
) {
3290 Warning (NULL
, 0, 0, "Invalid", "The file %s has no .reloc section.", FileName
);
3295 // Relocation exist and rebase
3298 // Load and Relocate Image Data
3300 MemoryImagePointer
= (UINT8
*) malloc ((UINTN
) ImageContext
.ImageSize
+ ImageContext
.SectionAlignment
);
3301 if (MemoryImagePointer
== NULL
) {
3302 Error (NULL
, 0, 4001, "Resource", "memory cannot be allocated on rebase of %s", FileName
);
3303 return EFI_OUT_OF_RESOURCES
;
3305 memset ((VOID
*) MemoryImagePointer
, 0, (UINTN
) ImageContext
.ImageSize
+ ImageContext
.SectionAlignment
);
3306 ImageContext
.ImageAddress
= ((UINTN
) MemoryImagePointer
+ ImageContext
.SectionAlignment
- 1) & (~((UINTN
) ImageContext
.SectionAlignment
- 1));
3308 Status
= PeCoffLoaderLoadImage (&ImageContext
);
3309 if (EFI_ERROR (Status
)) {
3310 Error (NULL
, 0, 3000, "Invalid", "LocateImage() call failed on rebase of %s", FileName
);
3311 free ((VOID
*) MemoryImagePointer
);
3315 // Reloacate TeImage
3317 ImageContext
.DestinationAddress
= NewPe32BaseAddress
;
3318 Status
= PeCoffLoaderRelocateImage (&ImageContext
);
3319 if (EFI_ERROR (Status
)) {
3320 Error (NULL
, 0, 3000, "Invalid", "RelocateImage() call failed on rebase of TE image %s", FileName
);
3321 free ((VOID
*) MemoryImagePointer
);
3326 // Copy the relocated image into raw image file.
3328 SectionHeader
= (EFI_IMAGE_SECTION_HEADER
*) (TEImageHeader
+ 1);
3329 for (Index
= 0; Index
< TEImageHeader
->NumberOfSections
; Index
++, SectionHeader
++) {
3330 if (!ImageContext
.IsTeImage
) {
3332 (UINT8
*) TEImageHeader
+ sizeof (EFI_TE_IMAGE_HEADER
) - TEImageHeader
->StrippedSize
+ SectionHeader
->PointerToRawData
,
3333 (VOID
*) (UINTN
) (ImageContext
.ImageAddress
+ SectionHeader
->VirtualAddress
),
3334 SectionHeader
->SizeOfRawData
3338 (UINT8
*) TEImageHeader
+ sizeof (EFI_TE_IMAGE_HEADER
) - TEImageHeader
->StrippedSize
+ SectionHeader
->PointerToRawData
,
3339 (VOID
*) (UINTN
) (ImageContext
.ImageAddress
+ sizeof (EFI_TE_IMAGE_HEADER
) - TEImageHeader
->StrippedSize
+ SectionHeader
->VirtualAddress
),
3340 SectionHeader
->SizeOfRawData
3346 // Free the allocated memory resource
3348 free ((VOID
*) MemoryImagePointer
);
3349 MemoryImagePointer
= NULL
;
3350 if (PeFileBuffer
!= NULL
) {
3351 free (PeFileBuffer
);
3352 PeFileBuffer
= NULL
;
3356 // Update Image Base Address
3358 TEImageHeader
->ImageBase
= NewPe32BaseAddress
;
3361 // Now update file checksum
3363 if (FfsFile
->Attributes
& FFS_ATTRIB_CHECKSUM
) {
3364 SavedState
= FfsFile
->State
;
3365 FfsFile
->IntegrityCheck
.Checksum
.File
= 0;
3367 FfsFile
->IntegrityCheck
.Checksum
.File
= CalculateChecksum8 (
3368 (UINT8
*)(FfsFile
+ 1),
3369 GetLength (FfsFile
->Size
) - sizeof (EFI_FFS_FILE_HEADER
)
3371 FfsFile
->State
= SavedState
;
3374 // Get this module function address from ModulePeMapFile and add them into FvMap file
3378 // Default use FileName as map file path
3380 if (PdbPointer
== NULL
) {
3381 PdbPointer
= FileName
;
3397 FindApResetVectorPosition (
3398 IN MEMORY_FILE
*FvImage
,
3403 Routine Description:
3405 Find the position in this FvImage to place Ap reset vector.
3409 FvImage Memory file for the FV memory image.
3410 Pointer Pointer to pointer to position.
3414 EFI_NOT_FOUND - No satisfied position is found.
3415 EFI_SUCCESS - The suitable position is return.
3419 EFI_FFS_FILE_HEADER
*PadFile
;
3425 for (Index
= 1; ;Index
++) {
3427 // Find Pad File to add ApResetVector info
3429 Status
= GetFileByType (EFI_FV_FILETYPE_FFS_PAD
, Index
, &PadFile
);
3430 if (EFI_ERROR (Status
) || (PadFile
== NULL
)) {
3432 // No Pad file to be found.
3437 // Get Pad file size.
3439 FileLength
= (*(UINT32
*)(PadFile
->Size
)) & 0x00FFFFFF;
3440 FileLength
= (FileLength
+ EFI_FFS_FILE_HEADER_ALIGNMENT
- 1) & ~(EFI_FFS_FILE_HEADER_ALIGNMENT
- 1);
3442 // FixPoint must be align on 0x1000 relative to FvImage Header
3444 FixPoint
= (UINT8
*) PadFile
+ sizeof (EFI_FFS_FILE_HEADER
);
3445 FixPoint
= FixPoint
+ 0x1000 - (((UINTN
) FixPoint
- (UINTN
) FvImage
->FileImage
) & 0xFFF);
3447 // FixPoint be larger at the last place of one fv image.
3449 while (((UINTN
) FixPoint
+ SIZEOF_STARTUP_DATA_ARRAY
- (UINTN
) PadFile
) <= FileLength
) {
3454 if ((UINTN
) FixPoint
< ((UINTN
) PadFile
+ sizeof (EFI_FFS_FILE_HEADER
))) {
3456 // No alignment FixPoint in this Pad File.
3461 if ((UINTN
) FvImage
->Eof
- (UINTN
)FixPoint
<= 0x20000) {
3463 // Find the position to place ApResetVector
3465 *Pointer
= FixPoint
;
3470 return EFI_NOT_FOUND
;
3475 IN MEMORY_FILE
*InfFile
,
3476 OUT CAP_INFO
*CapInfo
3480 Routine Description:
3482 This function parses a Cap.INF file and copies info into a CAP_INFO structure.
3486 InfFile Memory file image.
3487 CapInfo Information read from INF file.
3491 EFI_SUCCESS INF file information successfully retrieved.
3492 EFI_ABORTED INF file has an invalid format.
3493 EFI_NOT_FOUND A required string was not found in the INF file.
3496 CHAR8 Value
[_MAX_PATH
];
3498 UINTN Index
, Number
;
3502 // Initialize Cap info
3504 // memset (CapInfo, 0, sizeof (CAP_INFO));
3508 // Read the Capsule Guid
3510 Status
= FindToken (InfFile
, OPTIONS_SECTION_STRING
, EFI_CAPSULE_GUID_STRING
, 0, Value
);
3511 if (Status
== EFI_SUCCESS
) {
3513 // Get the Capsule Guid
3515 Status
= StringToGuid (Value
, &CapInfo
->CapGuid
);
3516 if (EFI_ERROR (Status
)) {
3517 Error (NULL
, 0, 2000, "Invalid parameter", "%s = %s", EFI_CAPSULE_GUID_STRING
, Value
);
3520 DebugMsg (NULL
, 0, 9, "Capsule Guid", "%s = %s", EFI_CAPSULE_GUID_STRING
, Value
);
3524 // Read the Capsule Header Size
3526 Status
= FindToken (InfFile
, OPTIONS_SECTION_STRING
, EFI_CAPSULE_HEADER_SIZE_STRING
, 0, Value
);
3527 if (Status
== EFI_SUCCESS
) {
3528 Status
= AsciiStringToUint64 (Value
, FALSE
, &Value64
);
3529 if (EFI_ERROR (Status
)) {
3530 Error (NULL
, 0, 2000, "Invalid parameter", "%s = %s", EFI_CAPSULE_HEADER_SIZE_STRING
, Value
);
3533 CapInfo
->HeaderSize
= (UINT32
) Value64
;
3534 DebugMsg (NULL
, 0, 9, "Capsule Header size", "%s = %s", EFI_CAPSULE_HEADER_SIZE_STRING
, Value
);
3538 // Read the Capsule Flag
3540 Status
= FindToken (InfFile
, OPTIONS_SECTION_STRING
, EFI_CAPSULE_FLAGS_STRING
, 0, Value
);
3541 if (Status
== EFI_SUCCESS
) {
3542 if (strstr (Value
, "PopulateSystemTable") != NULL
) {
3543 CapInfo
->Flags
|= CAPSULE_FLAGS_PERSIST_ACROSS_RESET
| CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE
;
3544 if (strstr (Value
, "InitiateReset") != NULL
) {
3545 CapInfo
->Flags
|= CAPSULE_FLAGS_INITIATE_RESET
;
3547 } else if (strstr (Value
, "PersistAcrossReset") != NULL
) {
3548 CapInfo
->Flags
|= CAPSULE_FLAGS_PERSIST_ACROSS_RESET
;
3549 if (strstr (Value
, "InitiateReset") != NULL
) {
3550 CapInfo
->Flags
|= CAPSULE_FLAGS_INITIATE_RESET
;
3553 Error (NULL
, 0, 2000, "Invalid parameter", "invalid Flag setting for %s.", EFI_CAPSULE_FLAGS_STRING
);
3556 DebugMsg (NULL
, 0, 9, "Capsule Flag", Value
);
3560 // Read Capsule File name
3562 Status
= FindToken (InfFile
, OPTIONS_SECTION_STRING
, EFI_FILE_NAME_STRING
, 0, Value
);
3563 if (Status
== EFI_SUCCESS
) {
3565 // Get output file name
3567 strcpy (CapInfo
->CapName
, Value
);
3571 // Read the Capsule FileImage
3574 for (Index
= 0; Index
< MAX_NUMBER_OF_FILES_IN_CAP
; Index
++) {
3575 if (CapInfo
->CapFiles
[Index
][0] != '\0') {
3579 // Read the capsule file name
3581 Status
= FindToken (InfFile
, FILES_SECTION_STRING
, EFI_FILE_NAME_STRING
, Number
++, Value
);
3583 if (Status
== EFI_SUCCESS
) {
3587 strcpy (CapInfo
->CapFiles
[Index
], Value
);
3588 DebugMsg (NULL
, 0, 9, "Capsule component file", "the %uth file name is %s", (unsigned) Index
, CapInfo
->CapFiles
[Index
]);
3595 Warning (NULL
, 0, 0, "Capsule components are not specified.", NULL
);
3603 IN CHAR8
*InfFileImage
,
3604 IN UINTN InfFileSize
,
3605 IN CHAR8
*CapFileName
3609 Routine Description:
3611 This is the main function which will be called from application to create UEFI Capsule image.
3615 InfFileImage Buffer containing the INF file contents.
3616 InfFileSize Size of the contents of the InfFileImage buffer.
3617 CapFileName Requested name for the Cap file.
3621 EFI_SUCCESS Function completed successfully.
3622 EFI_OUT_OF_RESOURCES Could not allocate required resources.
3623 EFI_ABORTED Error encountered.
3624 EFI_INVALID_PARAMETER A required parameter was NULL.
3630 EFI_CAPSULE_HEADER
*CapsuleHeader
;
3631 MEMORY_FILE InfMemoryFile
;
3637 if (InfFileImage
!= NULL
) {
3639 // Initialize file structures
3641 InfMemoryFile
.FileImage
= InfFileImage
;
3642 InfMemoryFile
.CurrentFilePointer
= InfFileImage
;
3643 InfMemoryFile
.Eof
= InfFileImage
+ InfFileSize
;
3646 // Parse the Cap inf file for header information
3648 Status
= ParseCapInf (&InfMemoryFile
, &mCapDataInfo
);
3649 if (Status
!= EFI_SUCCESS
) {
3654 if (mCapDataInfo
.HeaderSize
== 0) {
3656 // make header size align 16 bytes.
3658 mCapDataInfo
.HeaderSize
= sizeof (EFI_CAPSULE_HEADER
);
3659 mCapDataInfo
.HeaderSize
= (mCapDataInfo
.HeaderSize
+ 0xF) & ~0xF;
3662 if (mCapDataInfo
.HeaderSize
< sizeof (EFI_CAPSULE_HEADER
)) {
3663 Error (NULL
, 0, 2000, "Invalid parameter", "The specified HeaderSize cannot be less than the size of EFI_CAPSULE_HEADER.");
3664 return EFI_INVALID_PARAMETER
;
3667 if (CapFileName
== NULL
&& mCapDataInfo
.CapName
[0] != '\0') {
3668 CapFileName
= mCapDataInfo
.CapName
;
3671 if (CapFileName
== NULL
) {
3672 Error (NULL
, 0, 2001, "Missing required argument", "Output Capsule file name");
3673 return EFI_INVALID_PARAMETER
;
3677 // Set Default Capsule Guid value
3679 if (CompareGuid (&mCapDataInfo
.CapGuid
, &mZeroGuid
) == 0) {
3680 memcpy (&mCapDataInfo
.CapGuid
, &mDefaultCapsuleGuid
, sizeof (EFI_GUID
));
3683 // Calculate the size of capsule image.
3687 CapSize
= mCapDataInfo
.HeaderSize
;
3688 while (mCapDataInfo
.CapFiles
[Index
][0] != '\0') {
3689 fpin
= fopen (mCapDataInfo
.CapFiles
[Index
], "rb");
3691 Error (NULL
, 0, 0001, "Error opening file", mCapDataInfo
.CapFiles
[Index
]);
3694 FileSize
= _filelength (fileno (fpin
));
3695 CapSize
+= FileSize
;
3701 // Allocate buffer for capsule image.
3703 CapBuffer
= (UINT8
*) malloc (CapSize
);
3704 if (CapBuffer
== NULL
) {
3705 Error (NULL
, 0, 4001, "Resource", "memory cannot be allocated for creating the capsule.");
3706 return EFI_OUT_OF_RESOURCES
;
3710 // Initialize the capsule header to zero
3712 memset (CapBuffer
, 0, mCapDataInfo
.HeaderSize
);
3715 // create capsule header and get capsule body
3717 CapsuleHeader
= (EFI_CAPSULE_HEADER
*) CapBuffer
;
3718 memcpy (&CapsuleHeader
->CapsuleGuid
, &mCapDataInfo
.CapGuid
, sizeof (EFI_GUID
));
3719 CapsuleHeader
->HeaderSize
= mCapDataInfo
.HeaderSize
;
3720 CapsuleHeader
->Flags
= mCapDataInfo
.Flags
;
3721 CapsuleHeader
->CapsuleImageSize
= CapSize
;
3725 CapSize
= CapsuleHeader
->HeaderSize
;
3726 while (mCapDataInfo
.CapFiles
[Index
][0] != '\0') {
3727 fpin
= fopen (mCapDataInfo
.CapFiles
[Index
], "rb");
3729 Error (NULL
, 0, 0001, "Error opening file", mCapDataInfo
.CapFiles
[Index
]);
3733 FileSize
= _filelength (fileno (fpin
));
3734 fread (CapBuffer
+ CapSize
, 1, FileSize
, fpin
);
3737 CapSize
+= FileSize
;
3741 // write capsule data into the output file
3743 fpout
= fopen (CapFileName
, "wb");
3744 if (fpout
== NULL
) {
3745 Error (NULL
, 0, 0001, "Error opening file", CapFileName
);
3750 fwrite (CapBuffer
, 1, CapSize
, fpout
);
3753 VerboseMsg ("The size of the generated capsule image is %u bytes", (unsigned) CapSize
);