2 This file contains the internal functions required to generate a Firmware Volume.
4 Copyright (c) 2004 - 2014, Intel Corporation. All rights reserved.<BR>
5 Portions Copyright (c) 2011 - 2013, ARM Ltd. All rights reserved.<BR>
6 This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution. The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
20 #if defined(__FreeBSD__)
22 #elif defined(__GNUC__)
23 #include <uuid/uuid.h>
34 #include "GenFvInternalLib.h"
36 #include "PeCoffLib.h"
37 #include "WinNtInclude.h"
40 STATIC UINT32 MaxFfsAlignment
= 0;
42 EFI_GUID mEfiFirmwareVolumeTopFileGuid
= EFI_FFS_VOLUME_TOP_FILE_GUID
;
43 EFI_GUID mFileGuidArray
[MAX_NUMBER_OF_FILES_IN_FV
];
44 EFI_GUID mZeroGuid
= {0x0, 0x0, 0x0, {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}};
45 EFI_GUID mDefaultCapsuleGuid
= {0x3B6686BD, 0x0D76, 0x4030, { 0xB7, 0x0E, 0xB5, 0x51, 0x9E, 0x2F, 0xC5, 0xA0 }};
47 CHAR8
*mFvbAttributeName
[] = {
48 EFI_FVB2_READ_DISABLED_CAP_STRING
,
49 EFI_FVB2_READ_ENABLED_CAP_STRING
,
50 EFI_FVB2_READ_STATUS_STRING
,
51 EFI_FVB2_WRITE_DISABLED_CAP_STRING
,
52 EFI_FVB2_WRITE_ENABLED_CAP_STRING
,
53 EFI_FVB2_WRITE_STATUS_STRING
,
54 EFI_FVB2_LOCK_CAP_STRING
,
55 EFI_FVB2_LOCK_STATUS_STRING
,
57 EFI_FVB2_STICKY_WRITE_STRING
,
58 EFI_FVB2_MEMORY_MAPPED_STRING
,
59 EFI_FVB2_ERASE_POLARITY_STRING
,
60 EFI_FVB2_READ_LOCK_CAP_STRING
,
61 EFI_FVB2_READ_LOCK_STATUS_STRING
,
62 EFI_FVB2_WRITE_LOCK_CAP_STRING
,
63 EFI_FVB2_WRITE_LOCK_STATUS_STRING
66 CHAR8
*mFvbAlignmentName
[] = {
67 EFI_FVB2_ALIGNMENT_1_STRING
,
68 EFI_FVB2_ALIGNMENT_2_STRING
,
69 EFI_FVB2_ALIGNMENT_4_STRING
,
70 EFI_FVB2_ALIGNMENT_8_STRING
,
71 EFI_FVB2_ALIGNMENT_16_STRING
,
72 EFI_FVB2_ALIGNMENT_32_STRING
,
73 EFI_FVB2_ALIGNMENT_64_STRING
,
74 EFI_FVB2_ALIGNMENT_128_STRING
,
75 EFI_FVB2_ALIGNMENT_256_STRING
,
76 EFI_FVB2_ALIGNMENT_512_STRING
,
77 EFI_FVB2_ALIGNMENT_1K_STRING
,
78 EFI_FVB2_ALIGNMENT_2K_STRING
,
79 EFI_FVB2_ALIGNMENT_4K_STRING
,
80 EFI_FVB2_ALIGNMENT_8K_STRING
,
81 EFI_FVB2_ALIGNMENT_16K_STRING
,
82 EFI_FVB2_ALIGNMENT_32K_STRING
,
83 EFI_FVB2_ALIGNMENT_64K_STRING
,
84 EFI_FVB2_ALIGNMENT_128K_STRING
,
85 EFI_FVB2_ALIGNMENT_256K_STRING
,
86 EFI_FVB2_ALIGNMENT_512K_STRING
,
87 EFI_FVB2_ALIGNMENT_1M_STRING
,
88 EFI_FVB2_ALIGNMENT_2M_STRING
,
89 EFI_FVB2_ALIGNMENT_4M_STRING
,
90 EFI_FVB2_ALIGNMENT_8M_STRING
,
91 EFI_FVB2_ALIGNMENT_16M_STRING
,
92 EFI_FVB2_ALIGNMENT_32M_STRING
,
93 EFI_FVB2_ALIGNMENT_64M_STRING
,
94 EFI_FVB2_ALIGNMENT_128M_STRING
,
95 EFI_FVB2_ALIGNMENT_256M_STRING
,
96 EFI_FVB2_ALIGNMENT_512M_STRING
,
97 EFI_FVB2_ALIGNMENT_1G_STRING
,
98 EFI_FVB2_ALIGNMENT_2G_STRING
102 // This data array will be located at the base of the Firmware Volume Header (FVH)
103 // in the boot block. It must not exceed 14 bytes of code. The last 2 bytes
104 // will be used to keep the FVH checksum consistent.
105 // This code will be run in response to a starutp IPI for HT-enabled systems.
107 #define SIZEOF_STARTUP_DATA_ARRAY 0x10
109 UINT8 m128kRecoveryStartupApDataArray
[SIZEOF_STARTUP_DATA_ARRAY
] = {
111 // EA D0 FF 00 F0 ; far jmp F000:FFD0
112 // 0, 0, 0, 0, 0, 0, 0, 0, 0, ; Reserved bytes
113 // 0, 0 ; Checksum Padding
133 UINT8 m64kRecoveryStartupApDataArray
[SIZEOF_STARTUP_DATA_ARRAY
] = {
135 // EB CE ; jmp short ($-0x30)
136 // ; (from offset 0x0 to offset 0xFFD0)
137 // 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ; Reserved bytes
138 // 0, 0 ; Checksum Padding
159 CAP_INFO mCapDataInfo
;
160 BOOLEAN mIsLargeFfs
= FALSE
;
162 EFI_PHYSICAL_ADDRESS mFvBaseAddress
[0x10];
163 UINT32 mFvBaseAddressNumber
= 0;
167 IN MEMORY_FILE
*InfFile
,
174 This function parses a FV.INF file and copies info into a FV_INFO structure.
178 InfFile Memory file image.
179 FvInfo Information read from INF file.
183 EFI_SUCCESS INF file information successfully retrieved.
184 EFI_ABORTED INF file has an invalid format.
185 EFI_NOT_FOUND A required string was not found in the INF file.
188 CHAR8 Value
[MAX_LONG_FILE_PATH
];
196 // Read the FV base address
198 if (!mFvDataInfo
.BaseAddressSet
) {
199 Status
= FindToken (InfFile
, OPTIONS_SECTION_STRING
, EFI_FV_BASE_ADDRESS_STRING
, 0, Value
);
200 if (Status
== EFI_SUCCESS
) {
202 // Get the base address
204 Status
= AsciiStringToUint64 (Value
, FALSE
, &Value64
);
205 if (EFI_ERROR (Status
)) {
206 Error (NULL
, 0, 2000, "Invalid parameter", "%s = %s", EFI_FV_BASE_ADDRESS_STRING
, Value
);
209 DebugMsg (NULL
, 0, 9, "rebase address", "%s = %s", EFI_FV_BASE_ADDRESS_STRING
, Value
);
211 FvInfo
->BaseAddress
= Value64
;
212 FvInfo
->BaseAddressSet
= TRUE
;
217 // Read the FV File System Guid
219 if (!FvInfo
->FvFileSystemGuidSet
) {
220 Status
= FindToken (InfFile
, OPTIONS_SECTION_STRING
, EFI_FV_FILESYSTEMGUID_STRING
, 0, Value
);
221 if (Status
== EFI_SUCCESS
) {
223 // Get the guid value
225 Status
= StringToGuid (Value
, &GuidValue
);
226 if (EFI_ERROR (Status
)) {
227 Error (NULL
, 0, 2000, "Invalid parameter", "%s = %s", EFI_FV_FILESYSTEMGUID_STRING
, Value
);
230 memcpy (&FvInfo
->FvFileSystemGuid
, &GuidValue
, sizeof (EFI_GUID
));
231 FvInfo
->FvFileSystemGuidSet
= TRUE
;
236 // Read the FV Extension Header File Name
238 Status
= FindToken (InfFile
, ATTRIBUTES_SECTION_STRING
, EFI_FV_EXT_HEADER_FILE_NAME
, 0, Value
);
239 if (Status
== EFI_SUCCESS
) {
240 strcpy (FvInfo
->FvExtHeaderFile
, Value
);
244 // Read the FV file name
246 Status
= FindToken (InfFile
, OPTIONS_SECTION_STRING
, EFI_FV_FILE_NAME_STRING
, 0, Value
);
247 if (Status
== EFI_SUCCESS
) {
249 // copy the file name
251 strcpy (FvInfo
->FvName
, Value
);
257 for (Index
= 0; Index
< sizeof (mFvbAttributeName
)/sizeof (CHAR8
*); Index
++) {
258 if ((mFvbAttributeName
[Index
] != NULL
) && \
259 (FindToken (InfFile
, ATTRIBUTES_SECTION_STRING
, mFvbAttributeName
[Index
], 0, Value
) == EFI_SUCCESS
)) {
260 if ((strcmp (Value
, TRUE_STRING
) == 0) || (strcmp (Value
, ONE_STRING
) == 0)) {
261 FvInfo
->FvAttributes
|= 1 << Index
;
262 } else if ((strcmp (Value
, FALSE_STRING
) != 0) && (strcmp (Value
, ZERO_STRING
) != 0)) {
263 Error (NULL
, 0, 2000, "Invalid parameter", "%s expected %s | %s", mFvbAttributeName
[Index
], TRUE_STRING
, FALSE_STRING
);
272 for (Index
= 0; Index
< sizeof (mFvbAlignmentName
)/sizeof (CHAR8
*); Index
++) {
273 if (FindToken (InfFile
, ATTRIBUTES_SECTION_STRING
, mFvbAlignmentName
[Index
], 0, Value
) == EFI_SUCCESS
) {
274 if (strcmp (Value
, TRUE_STRING
) == 0) {
275 FvInfo
->FvAttributes
|= Index
<< 16;
276 DebugMsg (NULL
, 0, 9, "FV file alignment", "Align = %s", mFvbAlignmentName
[Index
]);
283 // Read weak alignment flag
285 Status
= FindToken (InfFile
, ATTRIBUTES_SECTION_STRING
, EFI_FV_WEAK_ALIGNMENT_STRING
, 0, Value
);
286 if (Status
== EFI_SUCCESS
) {
287 if ((strcmp (Value
, TRUE_STRING
) == 0) || (strcmp (Value
, ONE_STRING
) == 0)) {
288 FvInfo
->FvAttributes
|= EFI_FVB2_WEAK_ALIGNMENT
;
289 } else if ((strcmp (Value
, FALSE_STRING
) != 0) && (strcmp (Value
, ZERO_STRING
) != 0)) {
290 Error (NULL
, 0, 2000, "Invalid parameter", "Weak alignment value expected one of TRUE, FALSE, 1 or 0.");
298 for (Index
= 0; Index
< MAX_NUMBER_OF_FV_BLOCKS
; Index
++) {
299 if (FvInfo
->FvBlocks
[Index
].Length
== 0) {
303 Status
= FindToken (InfFile
, OPTIONS_SECTION_STRING
, EFI_BLOCK_SIZE_STRING
, Index
, Value
);
305 if (Status
== EFI_SUCCESS
) {
307 // Update the size of block
309 Status
= AsciiStringToUint64 (Value
, FALSE
, &Value64
);
310 if (EFI_ERROR (Status
)) {
311 Error (NULL
, 0, 2000, "Invalid parameter", "%s = %s", EFI_BLOCK_SIZE_STRING
, Value
);
315 FvInfo
->FvBlocks
[Index
].Length
= (UINT32
) Value64
;
316 DebugMsg (NULL
, 0, 9, "FV Block Size", "%s = %s", EFI_BLOCK_SIZE_STRING
, Value
);
319 // If there is no blocks size, but there is the number of block, then we have a mismatched pair
320 // and should return an error.
322 Status
= FindToken (InfFile
, OPTIONS_SECTION_STRING
, EFI_NUM_BLOCKS_STRING
, Index
, Value
);
323 if (!EFI_ERROR (Status
)) {
324 Error (NULL
, 0, 2000, "Invalid parameter", "both %s and %s must be specified.", EFI_NUM_BLOCKS_STRING
, EFI_BLOCK_SIZE_STRING
);
335 // Read blocks number
337 Status
= FindToken (InfFile
, OPTIONS_SECTION_STRING
, EFI_NUM_BLOCKS_STRING
, Index
, Value
);
339 if (Status
== EFI_SUCCESS
) {
341 // Update the number of blocks
343 Status
= AsciiStringToUint64 (Value
, FALSE
, &Value64
);
344 if (EFI_ERROR (Status
)) {
345 Error (NULL
, 0, 2000, "Invalid parameter", "%s = %s", EFI_NUM_BLOCKS_STRING
, Value
);
349 FvInfo
->FvBlocks
[Index
].NumBlocks
= (UINT32
) Value64
;
350 DebugMsg (NULL
, 0, 9, "FV Block Number", "%s = %s", EFI_NUM_BLOCKS_STRING
, Value
);
356 Error (NULL
, 0, 2001, "Missing required argument", "block size.");
364 for (Number
= 0; Number
< MAX_NUMBER_OF_FILES_IN_FV
; Number
++) {
365 if (FvInfo
->FvFiles
[Number
][0] == '\0') {
370 for (Index
= 0; Index
< MAX_NUMBER_OF_FILES_IN_FV
; Index
++) {
372 // Read the FFS file list
374 Status
= FindToken (InfFile
, FILES_SECTION_STRING
, EFI_FILE_NAME_STRING
, Index
, Value
);
376 if (Status
== EFI_SUCCESS
) {
380 strcpy (FvInfo
->FvFiles
[Number
+ Index
], Value
);
381 DebugMsg (NULL
, 0, 9, "FV component file", "the %uth name is %s", (unsigned) Index
, Value
);
387 if ((Index
+ Number
) == 0) {
388 Warning (NULL
, 0, 0, "FV components are not specified.", NULL
);
396 IN EFI_FFS_FILE_HEADER
*FfsFile
,
397 IN EFI_FIRMWARE_VOLUME_HEADER
*FvHeader
403 This function changes the FFS file attributes based on the erase polarity
404 of the FV. Update the reserved bits of State to EFI_FVB2_ERASE_POLARITY.
417 if (FvHeader
->Attributes
& EFI_FVB2_ERASE_POLARITY
) {
418 FfsFile
->State
= (UINT8
)~(FfsFile
->State
);
419 // FfsFile->State |= ~(UINT8) EFI_FILE_ALL_STATE_BITS;
425 IN EFI_FFS_FILE_HEADER
*FfsFile
,
426 IN OUT UINT32
*Alignment
432 This function determines the alignment of the FFS input file from the file
437 FfsFile FFS file to parse
438 Alignment The minimum required alignment offset of the FFS file
442 EFI_SUCCESS The function completed successfully.
443 EFI_INVALID_PARAMETER One of the input parameters was invalid.
444 EFI_ABORTED An error occurred.
449 // Verify input parameters.
451 if (FfsFile
== NULL
|| Alignment
== NULL
) {
452 return EFI_INVALID_PARAMETER
;
455 switch ((FfsFile
->Attributes
>> 3) & 0x07) {
473 // 128 byte alignment
480 // 512 byte alignment
501 // 32K byte alignment
508 // 64K byte alignment
522 IN OUT MEMORY_FILE
*FvImage
,
523 IN UINT32 DataAlignment
,
525 IN EFI_FIRMWARE_VOLUME_EXT_HEADER
*ExtHeader
,
526 IN UINT32 NextFfsSize
532 This function adds a pad file to the FV image if it required to align the
533 data of the next file.
537 FvImage The memory image of the FV to add it to.
538 The current offset must be valid.
539 DataAlignment The data alignment of the next FFS file.
540 FvEnd End of the empty data in FvImage.
541 ExtHeader PI FvExtHeader Optional
545 EFI_SUCCESS The function completed successfully.
546 EFI_INVALID_PARAMETER One of the input parameters was invalid.
547 EFI_OUT_OF_RESOURCES Insufficient resources exist in the FV to complete
552 EFI_FFS_FILE_HEADER
*PadFile
;
554 UINT32 NextFfsHeaderSize
;
555 UINT32 CurFfsHeaderSize
;
557 CurFfsHeaderSize
= sizeof (EFI_FFS_FILE_HEADER
);
559 // Verify input parameters.
561 if (FvImage
== NULL
) {
562 return EFI_INVALID_PARAMETER
;
566 // Calculate the pad file size
570 // Append extension header size
572 if (ExtHeader
!= NULL
) {
573 PadFileSize
= ExtHeader
->ExtHeaderSize
;
574 if (PadFileSize
+ sizeof (EFI_FFS_FILE_HEADER
) >= MAX_FFS_SIZE
) {
575 CurFfsHeaderSize
= sizeof (EFI_FFS_FILE_HEADER2
);
577 PadFileSize
+= CurFfsHeaderSize
;
579 NextFfsHeaderSize
= sizeof (EFI_FFS_FILE_HEADER
);
580 if (NextFfsSize
>= MAX_FFS_SIZE
) {
581 NextFfsHeaderSize
= sizeof (EFI_FFS_FILE_HEADER2
);
584 // Check if a pad file is necessary
586 if (((UINTN
) FvImage
->CurrentFilePointer
- (UINTN
) FvImage
->FileImage
+ NextFfsHeaderSize
) % DataAlignment
== 0) {
589 PadFileSize
= (UINTN
) FvImage
->CurrentFilePointer
- (UINTN
) FvImage
->FileImage
+ sizeof (EFI_FFS_FILE_HEADER
) + NextFfsHeaderSize
;
591 // Add whatever it takes to get to the next aligned address
593 while ((PadFileSize
% DataAlignment
) != 0) {
597 // Subtract the next file header size
599 PadFileSize
-= NextFfsHeaderSize
;
601 // Subtract the starting offset to get size
603 PadFileSize
-= (UINTN
) FvImage
->CurrentFilePointer
- (UINTN
) FvImage
->FileImage
;
607 // Verify that we have enough space for the file header
609 if (((UINTN
) FvImage
->CurrentFilePointer
+ PadFileSize
) > (UINTN
) FvEnd
) {
610 return EFI_OUT_OF_RESOURCES
;
614 // Write pad file header
616 PadFile
= (EFI_FFS_FILE_HEADER
*) FvImage
->CurrentFilePointer
;
619 // Write PadFile FFS header with PadType, don't need to set PAD file guid in its header.
621 PadFile
->Type
= EFI_FV_FILETYPE_FFS_PAD
;
622 PadFile
->Attributes
= 0;
625 // Write pad file size (calculated size minus next file header size)
627 if (PadFileSize
>= MAX_FFS_SIZE
) {
628 memset(PadFile
->Size
, 0, sizeof(UINT8
) * 3);
629 ((EFI_FFS_FILE_HEADER2
*)PadFile
)->ExtendedSize
= PadFileSize
;
630 PadFile
->Attributes
|= FFS_ATTRIB_LARGE_FILE
;
632 PadFile
->Size
[0] = (UINT8
) (PadFileSize
& 0xFF);
633 PadFile
->Size
[1] = (UINT8
) ((PadFileSize
>> 8) & 0xFF);
634 PadFile
->Size
[2] = (UINT8
) ((PadFileSize
>> 16) & 0xFF);
638 // Fill in checksums and state, they must be 0 for checksumming.
640 PadFile
->IntegrityCheck
.Checksum
.Header
= 0;
641 PadFile
->IntegrityCheck
.Checksum
.File
= 0;
643 PadFile
->IntegrityCheck
.Checksum
.Header
= CalculateChecksum8 ((UINT8
*) PadFile
, CurFfsHeaderSize
);
644 PadFile
->IntegrityCheck
.Checksum
.File
= FFS_FIXED_CHECKSUM
;
646 PadFile
->State
= EFI_FILE_HEADER_CONSTRUCTION
| EFI_FILE_HEADER_VALID
| EFI_FILE_DATA_VALID
;
648 (EFI_FFS_FILE_HEADER
*) PadFile
,
649 (EFI_FIRMWARE_VOLUME_HEADER
*) FvImage
->FileImage
653 // Update the current FV pointer
655 FvImage
->CurrentFilePointer
+= PadFileSize
;
657 if (ExtHeader
!= NULL
) {
659 // Copy Fv Extension Header and Set Fv Extension header offset
661 memcpy ((UINT8
*)PadFile
+ CurFfsHeaderSize
, ExtHeader
, ExtHeader
->ExtHeaderSize
);
662 ((EFI_FIRMWARE_VOLUME_HEADER
*) FvImage
->FileImage
)->ExtHeaderOffset
= (UINT16
) ((UINTN
) ((UINT8
*)PadFile
+ CurFfsHeaderSize
) - (UINTN
) FvImage
->FileImage
);
664 // Make next file start at QWord Boundry
666 while (((UINTN
) FvImage
->CurrentFilePointer
& (EFI_FFS_FILE_HEADER_ALIGNMENT
- 1)) != 0) {
667 FvImage
->CurrentFilePointer
++;
676 IN EFI_FFS_FILE_HEADER
*FileBuffer
682 This function checks the header to validate if it is a VTF file
686 FileBuffer Buffer in which content of a file has been read.
690 TRUE If this is a VTF file
691 FALSE If this is not a VTF file
695 if (!memcmp (&FileBuffer
->Name
, &mEfiFirmwareVolumeTopFileGuid
, sizeof (EFI_GUID
))) {
704 IN OUT
FILE *FvMapFile
,
706 IN EFI_FFS_FILE_HEADER
*FfsFile
,
707 IN EFI_PHYSICAL_ADDRESS ImageBaseAddress
,
708 IN PE_COFF_LOADER_IMAGE_CONTEXT
*pImageContext
714 This function gets the basic debug information (entrypoint, baseaddress, .text, .data section base address)
715 from PE/COFF image and abstracts Pe Map file information and add them into FvMap file for Debug.
719 FvMapFile A pointer to FvMap File
720 FileName Ffs File PathName
721 FfsFile A pointer to Ffs file image.
722 ImageBaseAddress PeImage Base Address.
723 pImageContext Image Context Information.
727 EFI_SUCCESS Added required map information.
731 CHAR8 PeMapFileName
[MAX_LONG_FILE_PATH
];
733 CHAR8 FileGuidName
[MAX_LINE_LEN
];
735 CHAR8 Line
[MAX_LINE_LEN
];
736 CHAR8 KeyWord
[MAX_LINE_LEN
];
737 CHAR8 FunctionName
[MAX_LINE_LEN
];
738 EFI_PHYSICAL_ADDRESS FunctionAddress
;
740 CHAR8 FunctionTypeName
[MAX_LINE_LEN
];
742 UINT32 AddressOfEntryPoint
;
744 EFI_IMAGE_OPTIONAL_HEADER_UNION
*ImgHdr
;
745 EFI_TE_IMAGE_HEADER
*TEImageHeader
;
746 EFI_IMAGE_SECTION_HEADER
*SectionHeader
;
747 unsigned long long TempLongAddress
;
748 UINT32 TextVirtualAddress
;
749 UINT32 DataVirtualAddress
;
750 EFI_PHYSICAL_ADDRESS LinkTimeBaseAddress
;
753 // Init local variable
757 // Print FileGuid to string buffer.
759 PrintGuidToBuffer (&FfsFile
->Name
, (UINT8
*)FileGuidName
, MAX_LINE_LEN
, TRUE
);
762 // Construct Map file Name
764 strcpy (PeMapFileName
, FileName
);
767 // Change '\\' to '/', unified path format.
769 Cptr
= PeMapFileName
;
770 while (*Cptr
!= '\0') {
772 *Cptr
= FILE_SEP_CHAR
;
780 Cptr
= PeMapFileName
+ strlen (PeMapFileName
);
781 while ((*Cptr
!= '.') && (Cptr
>= PeMapFileName
)) {
784 if (Cptr
< PeMapFileName
) {
785 return EFI_NOT_FOUND
;
797 while ((*Cptr
!= FILE_SEP_CHAR
) && (Cptr
>= PeMapFileName
)) {
801 strcpy (KeyWord
, Cptr
+ 1);
805 // AddressOfEntryPoint and Offset in Image
807 if (!pImageContext
->IsTeImage
) {
808 ImgHdr
= (EFI_IMAGE_OPTIONAL_HEADER_UNION
*) ((UINT8
*) pImageContext
->Handle
+ pImageContext
->PeCoffHeaderOffset
);
809 AddressOfEntryPoint
= ImgHdr
->Pe32
.OptionalHeader
.AddressOfEntryPoint
;
811 SectionHeader
= (EFI_IMAGE_SECTION_HEADER
*) (
814 sizeof (EFI_IMAGE_FILE_HEADER
) +
815 ImgHdr
->Pe32
.FileHeader
.SizeOfOptionalHeader
817 Index
= ImgHdr
->Pe32
.FileHeader
.NumberOfSections
;
819 TEImageHeader
= (EFI_TE_IMAGE_HEADER
*) pImageContext
->Handle
;
820 AddressOfEntryPoint
= TEImageHeader
->AddressOfEntryPoint
;
821 Offset
= TEImageHeader
->StrippedSize
- sizeof (EFI_TE_IMAGE_HEADER
);
822 SectionHeader
= (EFI_IMAGE_SECTION_HEADER
*) (TEImageHeader
+ 1);
823 Index
= TEImageHeader
->NumberOfSections
;
827 // module information output
829 if (ImageBaseAddress
== 0) {
830 fprintf (FvMapFile
, "%s (dummy) (", KeyWord
);
831 fprintf (FvMapFile
, "BaseAddress=%010llx, ", (unsigned long long) ImageBaseAddress
);
833 fprintf (FvMapFile
, "%s (Fixed Flash Address, ", KeyWord
);
834 fprintf (FvMapFile
, "BaseAddress=0x%010llx, ", (unsigned long long) (ImageBaseAddress
+ Offset
));
837 if (FfsFile
->Type
!= EFI_FV_FILETYPE_SECURITY_CORE
&& pImageContext
->Machine
== EFI_IMAGE_MACHINE_IA64
) {
839 // Process IPF PLABEL to get the real address after the image has been rebased.
840 // PLABEL structure is got by AddressOfEntryPoint offset to ImageBuffer stored in pImageContext->Handle.
842 fprintf (FvMapFile
, "EntryPoint=0x%010llx", (unsigned long long) (*(UINT64
*)((UINTN
) pImageContext
->Handle
+ (UINTN
) AddressOfEntryPoint
)));
844 fprintf (FvMapFile
, "EntryPoint=0x%010llx", (unsigned long long) (ImageBaseAddress
+ AddressOfEntryPoint
));
846 fprintf (FvMapFile
, ")\n");
848 fprintf (FvMapFile
, "(GUID=%s", FileGuidName
);
849 TextVirtualAddress
= 0;
850 DataVirtualAddress
= 0;
851 for (; Index
> 0; Index
--, SectionHeader
++) {
852 if (stricmp ((CHAR8
*)SectionHeader
->Name
, ".text") == 0) {
853 TextVirtualAddress
= SectionHeader
->VirtualAddress
;
854 } else if (stricmp ((CHAR8
*)SectionHeader
->Name
, ".data") == 0) {
855 DataVirtualAddress
= SectionHeader
->VirtualAddress
;
856 } else if (stricmp ((CHAR8
*)SectionHeader
->Name
, ".sdata") == 0) {
857 DataVirtualAddress
= SectionHeader
->VirtualAddress
;
860 fprintf (FvMapFile
, " .textbaseaddress=0x%010llx", (unsigned long long) (ImageBaseAddress
+ TextVirtualAddress
));
861 fprintf (FvMapFile
, " .databaseaddress=0x%010llx", (unsigned long long) (ImageBaseAddress
+ DataVirtualAddress
));
862 fprintf (FvMapFile
, ")\n\n");
867 PeMapFile
= fopen (LongFilePath (PeMapFileName
), "r");
868 if (PeMapFile
== NULL
) {
869 // fprintf (stdout, "can't open %s file to reading\n", PeMapFileName);
872 VerboseMsg ("The map file is %s", PeMapFileName
);
875 // Output Functions information into Fv Map file
877 LinkTimeBaseAddress
= 0;
878 while (fgets (Line
, MAX_LINE_LEN
, PeMapFile
) != NULL
) {
882 if (Line
[0] == 0x0a) {
887 // By Address and Static keyword
889 if (FunctionType
== 0) {
890 sscanf (Line
, "%s", KeyWord
);
891 if (stricmp (KeyWord
, "Address") == 0) {
896 fgets (Line
, MAX_LINE_LEN
, PeMapFile
);
897 } else if (stricmp (KeyWord
, "Static") == 0) {
899 // static function list
902 fgets (Line
, MAX_LINE_LEN
, PeMapFile
);
903 } else if (stricmp (KeyWord
, "Preferred") ==0) {
904 sscanf (Line
+ strlen (" Preferred load address is"), "%llx", &TempLongAddress
);
905 LinkTimeBaseAddress
= (UINT64
) TempLongAddress
;
910 // Printf Function Information
912 if (FunctionType
== 1) {
913 sscanf (Line
, "%s %s %llx %s", KeyWord
, FunctionName
, &TempLongAddress
, FunctionTypeName
);
914 FunctionAddress
= (UINT64
) TempLongAddress
;
915 if (FunctionTypeName
[1] == '\0' && (FunctionTypeName
[0] == 'f' || FunctionTypeName
[0] == 'F')) {
916 fprintf (FvMapFile
, " 0x%010llx ", (unsigned long long) (ImageBaseAddress
+ FunctionAddress
- LinkTimeBaseAddress
));
917 fprintf (FvMapFile
, "%s\n", FunctionName
);
919 } else if (FunctionType
== 2) {
920 sscanf (Line
, "%s %s %llx %s", KeyWord
, FunctionName
, &TempLongAddress
, FunctionTypeName
);
921 FunctionAddress
= (UINT64
) TempLongAddress
;
922 if (FunctionTypeName
[1] == '\0' && (FunctionTypeName
[0] == 'f' || FunctionTypeName
[0] == 'F')) {
923 fprintf (FvMapFile
, " 0x%010llx ", (unsigned long long) (ImageBaseAddress
+ FunctionAddress
- LinkTimeBaseAddress
));
924 fprintf (FvMapFile
, "%s\n", FunctionName
);
931 fprintf (FvMapFile
, "\n\n");
939 IN OUT MEMORY_FILE
*FvImage
,
942 IN OUT EFI_FFS_FILE_HEADER
**VtfFileImage
,
944 IN
FILE *FvReportFile
950 This function adds a file to the FV image. The file will pad to the
951 appropriate alignment if required.
955 FvImage The memory image of the FV to add it to. The current offset
957 FvInfo Pointer to information about the FV.
958 Index The file in the FvInfo file list to add.
959 VtfFileImage A pointer to the VTF file within the FvImage. If this is equal
960 to the end of the FvImage then no VTF previously found.
961 FvMapFile Pointer to FvMap File
962 FvReportFile Pointer to FvReport File
966 EFI_SUCCESS The function completed successfully.
967 EFI_INVALID_PARAMETER One of the input parameters was invalid.
968 EFI_ABORTED An error occurred.
969 EFI_OUT_OF_RESOURCES Insufficient resources exist to complete the add.
977 UINT32 CurrentFileAlignment
;
980 UINT8 FileGuidString
[PRINTED_GUID_BUFFER_SIZE
];
984 // Verify input parameters.
986 if (FvImage
== NULL
|| FvInfo
== NULL
|| FvInfo
->FvFiles
[Index
][0] == 0 || VtfFileImage
== NULL
) {
987 return EFI_INVALID_PARAMETER
;
991 // Read the file to add
993 NewFile
= fopen (LongFilePath (FvInfo
->FvFiles
[Index
]), "rb");
995 if (NewFile
== NULL
) {
996 Error (NULL
, 0, 0001, "Error opening file", FvInfo
->FvFiles
[Index
]);
1001 // Get the file size
1003 FileSize
= _filelength (fileno (NewFile
));
1006 // Read the file into a buffer
1008 FileBuffer
= malloc (FileSize
);
1009 if (FileBuffer
== NULL
) {
1010 Error (NULL
, 0, 4001, "Resouce", "memory cannot be allocated!");
1011 return EFI_OUT_OF_RESOURCES
;
1014 NumBytesRead
= fread (FileBuffer
, sizeof (UINT8
), FileSize
, NewFile
);
1017 // Done with the file, from this point on we will just use the buffer read.
1022 // Verify read successful
1024 if (NumBytesRead
!= sizeof (UINT8
) * FileSize
) {
1026 Error (NULL
, 0, 0004, "Error reading file", FvInfo
->FvFiles
[Index
]);
1031 // For None PI Ffs file, directly add them into FvImage.
1033 if (!FvInfo
->IsPiFvImage
) {
1034 memcpy (FvImage
->CurrentFilePointer
, FileBuffer
, FileSize
);
1035 if (FvInfo
->SizeofFvFiles
[Index
] > FileSize
) {
1036 FvImage
->CurrentFilePointer
+= FvInfo
->SizeofFvFiles
[Index
];
1038 FvImage
->CurrentFilePointer
+= FileSize
;
1046 Status
= VerifyFfsFile ((EFI_FFS_FILE_HEADER
*)FileBuffer
);
1047 if (EFI_ERROR (Status
)) {
1049 Error (NULL
, 0, 3000, "Invalid", "%s is not a valid FFS file.", FvInfo
->FvFiles
[Index
]);
1050 return EFI_INVALID_PARAMETER
;
1054 // Verify space exists to add the file
1056 if (FileSize
> (UINTN
) ((UINTN
) *VtfFileImage
- (UINTN
) FvImage
->CurrentFilePointer
)) {
1058 Error (NULL
, 0, 4002, "Resource", "FV space is full, not enough room to add file %s.", FvInfo
->FvFiles
[Index
]);
1059 return EFI_OUT_OF_RESOURCES
;
1063 // Verify the input file is the duplicated file in this Fv image
1065 for (Index1
= 0; Index1
< Index
; Index1
++) {
1066 if (CompareGuid ((EFI_GUID
*) FileBuffer
, &mFileGuidArray
[Index1
]) == 0) {
1067 Error (NULL
, 0, 2000, "Invalid parameter", "the %dth file and %uth file have the same file GUID.", (unsigned) Index1
+ 1, (unsigned) Index
+ 1);
1068 PrintGuid ((EFI_GUID
*) FileBuffer
);
1069 return EFI_INVALID_PARAMETER
;
1072 CopyMem (&mFileGuidArray
[Index
], FileBuffer
, sizeof (EFI_GUID
));
1075 // Update the file state based on polarity of the FV.
1077 UpdateFfsFileState (
1078 (EFI_FFS_FILE_HEADER
*) FileBuffer
,
1079 (EFI_FIRMWARE_VOLUME_HEADER
*) FvImage
->FileImage
1083 // Check if alignment is required
1085 ReadFfsAlignment ((EFI_FFS_FILE_HEADER
*) FileBuffer
, &CurrentFileAlignment
);
1088 // Find the largest alignment of all the FFS files in the FV
1090 if (CurrentFileAlignment
> MaxFfsAlignment
) {
1091 MaxFfsAlignment
= CurrentFileAlignment
;
1094 // If we have a VTF file, add it at the top.
1096 if (IsVtfFile ((EFI_FFS_FILE_HEADER
*) FileBuffer
)) {
1097 if ((UINTN
) *VtfFileImage
== (UINTN
) FvImage
->Eof
) {
1099 // No previous VTF, add this one.
1101 *VtfFileImage
= (EFI_FFS_FILE_HEADER
*) (UINTN
) ((UINTN
) FvImage
->FileImage
+ FvInfo
->Size
- FileSize
);
1103 // Sanity check. The file MUST align appropriately
1105 if (((UINTN
) *VtfFileImage
+ GetFfsHeaderLength((EFI_FFS_FILE_HEADER
*)FileBuffer
) - (UINTN
) FvImage
->FileImage
) % (1 << CurrentFileAlignment
)) {
1106 Error (NULL
, 0, 3000, "Invalid", "VTF file cannot be aligned on a %u-byte boundary.", (unsigned) (1 << CurrentFileAlignment
));
1111 // Rebase the PE or TE image in FileBuffer of FFS file for XIP
1112 // Rebase for the debug genfvmap tool
1114 Status
= FfsRebase (FvInfo
, FvInfo
->FvFiles
[Index
], (EFI_FFS_FILE_HEADER
*) FileBuffer
, (UINTN
) *VtfFileImage
- (UINTN
) FvImage
->FileImage
, FvMapFile
);
1115 if (EFI_ERROR (Status
)) {
1116 Error (NULL
, 0, 3000, "Invalid", "Could not rebase %s.", FvInfo
->FvFiles
[Index
]);
1122 memcpy (*VtfFileImage
, FileBuffer
, FileSize
);
1124 PrintGuidToBuffer ((EFI_GUID
*) FileBuffer
, FileGuidString
, sizeof (FileGuidString
), TRUE
);
1125 fprintf (FvReportFile
, "0x%08X %s\n", (unsigned)(UINTN
) (((UINT8
*)*VtfFileImage
) - (UINTN
)FvImage
->FileImage
), FileGuidString
);
1128 DebugMsg (NULL
, 0, 9, "Add VTF FFS file in FV image", NULL
);
1132 // Already found a VTF file.
1134 Error (NULL
, 0, 3000, "Invalid", "multiple VTF files are not permitted within a single FV.");
1141 // Add pad file if necessary
1143 Status
= AddPadFile (FvImage
, 1 << CurrentFileAlignment
, *VtfFileImage
, NULL
, FileSize
);
1144 if (EFI_ERROR (Status
)) {
1145 Error (NULL
, 0, 4002, "Resource", "FV space is full, could not add pad file for data alignment property.");
1152 if ((UINTN
) (FvImage
->CurrentFilePointer
+ FileSize
) <= (UINTN
) (*VtfFileImage
)) {
1154 // Rebase the PE or TE image in FileBuffer of FFS file for XIP.
1155 // Rebase Bs and Rt drivers for the debug genfvmap tool.
1157 Status
= FfsRebase (FvInfo
, FvInfo
->FvFiles
[Index
], (EFI_FFS_FILE_HEADER
*) FileBuffer
, (UINTN
) FvImage
->CurrentFilePointer
- (UINTN
) FvImage
->FileImage
, FvMapFile
);
1158 if (EFI_ERROR (Status
)) {
1159 Error (NULL
, 0, 3000, "Invalid", "Could not rebase %s.", FvInfo
->FvFiles
[Index
]);
1165 memcpy (FvImage
->CurrentFilePointer
, FileBuffer
, FileSize
);
1166 PrintGuidToBuffer ((EFI_GUID
*) FileBuffer
, FileGuidString
, sizeof (FileGuidString
), TRUE
);
1167 fprintf (FvReportFile
, "0x%08X %s\n", (unsigned) (FvImage
->CurrentFilePointer
- FvImage
->FileImage
), FileGuidString
);
1168 FvImage
->CurrentFilePointer
+= FileSize
;
1170 Error (NULL
, 0, 4002, "Resource", "FV space is full, cannot add file %s.", FvInfo
->FvFiles
[Index
]);
1175 // Make next file start at QWord Boundry
1177 while (((UINTN
) FvImage
->CurrentFilePointer
& (EFI_FFS_FILE_HEADER_ALIGNMENT
- 1)) != 0) {
1178 FvImage
->CurrentFilePointer
++;
1183 // Free allocated memory.
1192 IN MEMORY_FILE
*FvImage
,
1193 IN EFI_FFS_FILE_HEADER
*VtfFileImage
1197 Routine Description:
1199 This function places a pad file between the last file in the FV and the VTF
1200 file if the VTF file exists.
1204 FvImage Memory file for the FV memory image
1205 VtfFileImage The address of the VTF file. If this is the end of the FV
1206 image, no VTF exists and no pad file is needed.
1210 EFI_SUCCESS Completed successfully.
1211 EFI_INVALID_PARAMETER One of the input parameters was NULL.
1215 EFI_FFS_FILE_HEADER
*PadFile
;
1217 UINT32 FfsHeaderSize
;
1220 // If there is no VTF or the VTF naturally follows the previous file without a
1221 // pad file, then there's nothing to do
1223 if ((UINTN
) VtfFileImage
== (UINTN
) FvImage
->Eof
|| \
1224 ((UINTN
) VtfFileImage
== (UINTN
) FvImage
->CurrentFilePointer
)) {
1228 if ((UINTN
) VtfFileImage
< (UINTN
) FvImage
->CurrentFilePointer
) {
1229 return EFI_INVALID_PARAMETER
;
1233 // Pad file starts at beginning of free space
1235 PadFile
= (EFI_FFS_FILE_HEADER
*) FvImage
->CurrentFilePointer
;
1238 // write PadFile FFS header with PadType, don't need to set PAD file guid in its header.
1240 PadFile
->Type
= EFI_FV_FILETYPE_FFS_PAD
;
1241 PadFile
->Attributes
= 0;
1244 // FileSize includes the EFI_FFS_FILE_HEADER
1246 FileSize
= (UINTN
) VtfFileImage
- (UINTN
) FvImage
->CurrentFilePointer
;
1247 if (FileSize
>= MAX_FFS_SIZE
) {
1248 PadFile
->Attributes
|= FFS_ATTRIB_LARGE_FILE
;
1249 memset(PadFile
->Size
, 0, sizeof(UINT8
) * 3);
1250 ((EFI_FFS_FILE_HEADER2
*)PadFile
)->ExtendedSize
= FileSize
;
1251 FfsHeaderSize
= sizeof(EFI_FFS_FILE_HEADER2
);
1254 PadFile
->Size
[0] = (UINT8
) (FileSize
& 0x000000FF);
1255 PadFile
->Size
[1] = (UINT8
) ((FileSize
& 0x0000FF00) >> 8);
1256 PadFile
->Size
[2] = (UINT8
) ((FileSize
& 0x00FF0000) >> 16);
1257 FfsHeaderSize
= sizeof(EFI_FFS_FILE_HEADER
);
1261 // Fill in checksums and state, must be zero during checksum calculation.
1263 PadFile
->IntegrityCheck
.Checksum
.Header
= 0;
1264 PadFile
->IntegrityCheck
.Checksum
.File
= 0;
1266 PadFile
->IntegrityCheck
.Checksum
.Header
= CalculateChecksum8 ((UINT8
*) PadFile
, FfsHeaderSize
);
1267 PadFile
->IntegrityCheck
.Checksum
.File
= FFS_FIXED_CHECKSUM
;
1269 PadFile
->State
= EFI_FILE_HEADER_CONSTRUCTION
| EFI_FILE_HEADER_VALID
| EFI_FILE_DATA_VALID
;
1271 UpdateFfsFileState (
1272 (EFI_FFS_FILE_HEADER
*) PadFile
,
1273 (EFI_FIRMWARE_VOLUME_HEADER
*) FvImage
->FileImage
1276 // Update the current FV pointer
1278 FvImage
->CurrentFilePointer
= FvImage
->Eof
;
1285 IN MEMORY_FILE
*FvImage
,
1287 IN EFI_FFS_FILE_HEADER
*VtfFile
1291 Routine Description:
1293 This parses the FV looking for the PEI core and then plugs the address into
1294 the SALE_ENTRY point of the BSF/VTF for IPF and does BUGBUG TBD action to
1295 complete an IA32 Bootstrap FV.
1299 FvImage Memory file for the FV memory image
1300 FvInfo Information read from INF file.
1301 VtfFile Pointer to the VTF file in the FV image.
1305 EFI_SUCCESS Function Completed successfully.
1306 EFI_ABORTED Error encountered.
1307 EFI_INVALID_PARAMETER A required parameter was NULL.
1308 EFI_NOT_FOUND PEI Core file not found.
1312 EFI_FFS_FILE_HEADER
*PeiCoreFile
;
1313 EFI_FFS_FILE_HEADER
*SecCoreFile
;
1315 EFI_FILE_SECTION_POINTER Pe32Section
;
1319 EFI_PHYSICAL_ADDRESS PeiCorePhysicalAddress
;
1320 EFI_PHYSICAL_ADDRESS SecCorePhysicalAddress
;
1321 EFI_PHYSICAL_ADDRESS
*SecCoreEntryAddressPtr
;
1322 INT32 Ia32SecEntryOffset
;
1323 UINT32
*Ia32ResetAddressPtr
;
1325 UINT8
*BytePointer2
;
1326 UINT16
*WordPointer
;
1330 EFI_FFS_FILE_STATE SavedState
;
1332 FIT_TABLE
*FitTablePtr
;
1333 BOOLEAN Vtf0Detected
;
1334 UINT32 FfsHeaderSize
;
1335 UINT32 SecHeaderSize
;
1338 // Verify input parameters
1340 if (FvImage
== NULL
|| FvInfo
== NULL
|| VtfFile
== NULL
) {
1341 return EFI_INVALID_PARAMETER
;
1344 // Initialize FV library
1346 InitializeFvLib (FvImage
->FileImage
, FvInfo
->Size
);
1351 Status
= VerifyFfsFile (VtfFile
);
1352 if (EFI_ERROR (Status
)) {
1353 return EFI_INVALID_PARAMETER
;
1357 (((UINTN
)FvImage
->Eof
- (UINTN
)FvImage
->FileImage
) >=
1358 IA32_X64_VTF_SIGNATURE_OFFSET
) &&
1359 (*(UINT32
*)(VOID
*)((UINTN
) FvImage
->Eof
-
1360 IA32_X64_VTF_SIGNATURE_OFFSET
) ==
1361 IA32_X64_VTF0_SIGNATURE
)
1363 Vtf0Detected
= TRUE
;
1365 Vtf0Detected
= FALSE
;
1369 // Find the Sec Core
1371 Status
= GetFileByType (EFI_FV_FILETYPE_SECURITY_CORE
, 1, &SecCoreFile
);
1372 if (EFI_ERROR (Status
) || SecCoreFile
== NULL
) {
1375 // If the SEC core file is not found, but the VTF-0 signature
1376 // is found, we'll treat it as a VTF-0 'Volume Top File'.
1377 // This means no modifications are required to the VTF.
1382 Error (NULL
, 0, 3000, "Invalid", "could not find the SEC core file in the FV.");
1386 // Sec Core found, now find PE32 section
1388 Status
= GetSectionByType (SecCoreFile
, EFI_SECTION_PE32
, 1, &Pe32Section
);
1389 if (Status
== EFI_NOT_FOUND
) {
1390 Status
= GetSectionByType (SecCoreFile
, EFI_SECTION_TE
, 1, &Pe32Section
);
1393 if (EFI_ERROR (Status
)) {
1394 Error (NULL
, 0, 3000, "Invalid", "could not find a PE32 section in the SEC core file.");
1398 SecHeaderSize
= GetSectionHeaderLength(Pe32Section
.CommonHeader
);
1399 Status
= GetPe32Info (
1400 (VOID
*) ((UINTN
) Pe32Section
.Pe32Section
+ SecHeaderSize
),
1406 if (EFI_ERROR (Status
)) {
1407 Error (NULL
, 0, 3000, "Invalid", "could not get the PE32 entry point for the SEC core.");
1413 (MachineType
== EFI_IMAGE_MACHINE_IA32
||
1414 MachineType
== EFI_IMAGE_MACHINE_X64
)
1417 // If the SEC core code is IA32 or X64 and the VTF-0 signature
1418 // is found, we'll treat it as a VTF-0 'Volume Top File'.
1419 // This means no modifications are required to the VTF.
1425 // Physical address is FV base + offset of PE32 + offset of the entry point
1427 SecCorePhysicalAddress
= FvInfo
->BaseAddress
;
1428 SecCorePhysicalAddress
+= (UINTN
) Pe32Section
.Pe32Section
+ SecHeaderSize
- (UINTN
) FvImage
->FileImage
;
1429 SecCorePhysicalAddress
+= EntryPoint
;
1430 DebugMsg (NULL
, 0, 9, "SecCore physical entry point address", "Address = 0x%llX", (unsigned long long) SecCorePhysicalAddress
);
1433 // Find the PEI Core
1435 Status
= GetFileByType (EFI_FV_FILETYPE_PEI_CORE
, 1, &PeiCoreFile
);
1436 if (EFI_ERROR (Status
) || PeiCoreFile
== NULL
) {
1437 Error (NULL
, 0, 3000, "Invalid", "could not find the PEI core in the FV.");
1441 // PEI Core found, now find PE32 or TE section
1443 Status
= GetSectionByType (PeiCoreFile
, EFI_SECTION_PE32
, 1, &Pe32Section
);
1444 if (Status
== EFI_NOT_FOUND
) {
1445 Status
= GetSectionByType (PeiCoreFile
, EFI_SECTION_TE
, 1, &Pe32Section
);
1448 if (EFI_ERROR (Status
)) {
1449 Error (NULL
, 0, 3000, "Invalid", "could not find either a PE32 or a TE section in PEI core file.");
1453 SecHeaderSize
= GetSectionHeaderLength(Pe32Section
.CommonHeader
);
1454 Status
= GetPe32Info (
1455 (VOID
*) ((UINTN
) Pe32Section
.Pe32Section
+ SecHeaderSize
),
1461 if (EFI_ERROR (Status
)) {
1462 Error (NULL
, 0, 3000, "Invalid", "could not get the PE32 entry point for the PEI core.");
1466 // Physical address is FV base + offset of PE32 + offset of the entry point
1468 PeiCorePhysicalAddress
= FvInfo
->BaseAddress
;
1469 PeiCorePhysicalAddress
+= (UINTN
) Pe32Section
.Pe32Section
+ SecHeaderSize
- (UINTN
) FvImage
->FileImage
;
1470 PeiCorePhysicalAddress
+= EntryPoint
;
1471 DebugMsg (NULL
, 0, 9, "PeiCore physical entry point address", "Address = 0x%llX", (unsigned long long) PeiCorePhysicalAddress
);
1473 if (MachineType
== EFI_IMAGE_MACHINE_IA64
) {
1475 // Update PEI_CORE address
1478 // Set the uncached attribute bit in the physical address
1480 PeiCorePhysicalAddress
|= 0x8000000000000000ULL
;
1483 // Check if address is aligned on a 16 byte boundary
1485 if (PeiCorePhysicalAddress
& 0xF) {
1486 Error (NULL
, 0, 3000, "Invalid",
1487 "PEI_CORE entry point is not aligned on a 16 byte boundary, address specified is %llXh.",
1488 (unsigned long long) PeiCorePhysicalAddress
1493 // First Get the FIT table address
1495 FitAddress
= (*(UINT64
*) (FvImage
->Eof
- IPF_FIT_ADDRESS_OFFSET
)) & 0xFFFFFFFF;
1497 FitTablePtr
= (FIT_TABLE
*) (FvImage
->FileImage
+ (FitAddress
- FvInfo
->BaseAddress
));
1499 Status
= UpdatePeiCoreEntryInFit (FitTablePtr
, PeiCorePhysicalAddress
);
1501 if (!EFI_ERROR (Status
)) {
1502 UpdateFitCheckSum (FitTablePtr
);
1506 // Update SEC_CORE address
1509 // Set the uncached attribute bit in the physical address
1511 SecCorePhysicalAddress
|= 0x8000000000000000ULL
;
1513 // Check if address is aligned on a 16 byte boundary
1515 if (SecCorePhysicalAddress
& 0xF) {
1516 Error (NULL
, 0, 3000, "Invalid",
1517 "SALE_ENTRY entry point is not aligned on a 16 byte boundary, address specified is %llXh.",
1518 (unsigned long long) SecCorePhysicalAddress
1523 // Update the address
1525 SecCoreEntryAddressPtr
= (EFI_PHYSICAL_ADDRESS
*) ((UINTN
) FvImage
->Eof
- IPF_SALE_ENTRY_ADDRESS_OFFSET
);
1526 *SecCoreEntryAddressPtr
= SecCorePhysicalAddress
;
1528 } else if (MachineType
== EFI_IMAGE_MACHINE_IA32
|| MachineType
== EFI_IMAGE_MACHINE_X64
) {
1530 // Get the location to update
1532 Ia32ResetAddressPtr
= (UINT32
*) ((UINTN
) FvImage
->Eof
- IA32_PEI_CORE_ENTRY_OFFSET
);
1535 // Write lower 32 bits of physical address for Pei Core entry
1537 *Ia32ResetAddressPtr
= (UINT32
) PeiCorePhysicalAddress
;
1540 // Write SecCore Entry point relative address into the jmp instruction in reset vector.
1542 Ia32ResetAddressPtr
= (UINT32
*) ((UINTN
) FvImage
->Eof
- IA32_SEC_CORE_ENTRY_OFFSET
);
1544 Ia32SecEntryOffset
= (INT32
) (SecCorePhysicalAddress
- (FV_IMAGES_TOP_ADDRESS
- IA32_SEC_CORE_ENTRY_OFFSET
+ 2));
1545 if (Ia32SecEntryOffset
<= -65536) {
1546 Error (NULL
, 0, 3000, "Invalid", "The SEC EXE file size is too large, it must be less than 64K.");
1547 return STATUS_ERROR
;
1550 *(UINT16
*) Ia32ResetAddressPtr
= (UINT16
) Ia32SecEntryOffset
;
1553 // Update the BFV base address
1555 Ia32ResetAddressPtr
= (UINT32
*) ((UINTN
) FvImage
->Eof
- 4);
1556 *Ia32ResetAddressPtr
= (UINT32
) (FvInfo
->BaseAddress
);
1557 DebugMsg (NULL
, 0, 9, "update BFV base address in the top FV image", "BFV base address = 0x%llX.", (unsigned long long) FvInfo
->BaseAddress
);
1560 // Update the Startup AP in the FVH header block ZeroVector region.
1562 BytePointer
= (UINT8
*) ((UINTN
) FvImage
->FileImage
);
1563 if (FvInfo
->Size
<= 0x10000) {
1564 BytePointer2
= m64kRecoveryStartupApDataArray
;
1565 } else if (FvInfo
->Size
<= 0x20000) {
1566 BytePointer2
= m128kRecoveryStartupApDataArray
;
1568 BytePointer2
= m128kRecoveryStartupApDataArray
;
1570 // Find the position to place Ap reset vector, the offset
1571 // between the position and the end of Fvrecovery.fv file
1572 // should not exceed 128kB to prevent Ap reset vector from
1573 // outside legacy E and F segment
1575 Status
= FindApResetVectorPosition (FvImage
, &BytePointer
);
1576 if (EFI_ERROR (Status
)) {
1577 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.");
1582 for (Index
= 0; Index
< SIZEOF_STARTUP_DATA_ARRAY
; Index
++) {
1583 BytePointer
[Index
] = BytePointer2
[Index
];
1586 // Calculate the checksum
1589 WordPointer
= (UINT16
*) (BytePointer
);
1590 for (Index
= 0; Index
< SIZEOF_STARTUP_DATA_ARRAY
/ 2; Index
++) {
1591 CheckSum
= (UINT16
) (CheckSum
+ ((UINT16
) *WordPointer
));
1595 // Update the checksum field
1597 WordPointer
= (UINT16
*) (BytePointer
+ SIZEOF_STARTUP_DATA_ARRAY
- 2);
1598 *WordPointer
= (UINT16
) (0x10000 - (UINT32
) CheckSum
);
1601 // IpiVector at the 4k aligned address in the top 2 blocks in the PEI FV.
1603 IpiVector
= (UINT32
) (FV_IMAGES_TOP_ADDRESS
- ((UINTN
) FvImage
->Eof
- (UINTN
) BytePointer
));
1604 DebugMsg (NULL
, 0, 9, "Startup AP Vector address", "IpiVector at 0x%X", (unsigned) IpiVector
);
1605 if ((IpiVector
& 0xFFF) != 0) {
1606 Error (NULL
, 0, 3000, "Invalid", "Startup AP Vector address are not 4K aligned, because the FV size is not 4K aligned");
1609 IpiVector
= IpiVector
>> 12;
1610 IpiVector
= IpiVector
& 0xFF;
1613 // Write IPI Vector at Offset FvrecoveryFileSize - 8
1615 Ia32ResetAddressPtr
= (UINT32
*) ((UINTN
) FvImage
->Eof
- 8);
1616 *Ia32ResetAddressPtr
= IpiVector
;
1617 } else if (MachineType
== EFI_IMAGE_MACHINE_ARMT
) {
1619 // Since the ARM reset vector is in the FV Header you really don't need a
1620 // Volume Top File, but if you have one for some reason don't crash...
1622 } else if (MachineType
== EFI_IMAGE_MACHINE_AARCH64
) {
1624 // Since the AArch64 reset vector is in the FV Header you really don't need a
1625 // Volume Top File, but if you have one for some reason don't crash...
1628 Error (NULL
, 0, 3000, "Invalid", "machine type=0x%X in PEI core.", MachineType
);
1633 // Now update file checksum
1635 SavedState
= VtfFile
->State
;
1636 VtfFile
->IntegrityCheck
.Checksum
.File
= 0;
1638 if (VtfFile
->Attributes
& FFS_ATTRIB_CHECKSUM
) {
1639 FfsHeaderSize
= GetFfsHeaderLength(VtfFile
);
1640 VtfFile
->IntegrityCheck
.Checksum
.File
= CalculateChecksum8 (
1641 (UINT8
*) ((UINT8
*)VtfFile
+ FfsHeaderSize
),
1642 GetFfsFileLength (VtfFile
) - FfsHeaderSize
1645 VtfFile
->IntegrityCheck
.Checksum
.File
= FFS_FIXED_CHECKSUM
;
1648 VtfFile
->State
= SavedState
;
1655 UpdateArmResetVectorIfNeeded (
1656 IN MEMORY_FILE
*FvImage
,
1661 Routine Description:
1662 This parses the FV looking for SEC and patches that address into the
1663 beginning of the FV header.
1665 For ARM32 the reset vector is at 0x00000000 or 0xFFFF0000.
1666 For AArch64 the reset vector is at 0x00000000.
1668 This would commonly map to the first entry in the ROM.
1678 We support two schemes on ARM.
1679 1) Beginning of the FV is the reset vector
1680 2) Reset vector is data bytes FDF file and that code branches to reset vector
1681 in the beginning of the FV (fixed size offset).
1683 Need to have the jump for the reset vector at location zero.
1684 We also need to store the address or PEI (if it exists).
1685 We stub out a return from interrupt in case the debugger
1686 is using SWI (not done for AArch64, not enough space in struct).
1687 The optional entry to the common exception handler is
1688 to support full featured exception handling from ROM and is currently
1689 not support by this tool.
1692 FvImage Memory file for the FV memory image
1693 FvInfo Information read from INF file.
1697 EFI_SUCCESS Function Completed successfully.
1698 EFI_ABORTED Error encountered.
1699 EFI_INVALID_PARAMETER A required parameter was NULL.
1700 EFI_NOT_FOUND PEI Core file not found.
1704 EFI_FFS_FILE_HEADER
*PeiCoreFile
;
1705 EFI_FFS_FILE_HEADER
*SecCoreFile
;
1707 EFI_FILE_SECTION_POINTER Pe32Section
;
1711 EFI_PHYSICAL_ADDRESS PeiCorePhysicalAddress
;
1712 EFI_PHYSICAL_ADDRESS SecCorePhysicalAddress
;
1713 INT32 ResetVector
[4]; // ARM32:
1714 // 0 - is branch relative to SEC entry point
1715 // 1 - PEI Entry Point
1716 // 2 - movs pc,lr for a SWI handler
1717 // 3 - Place holder for Common Exception Handler
1718 // AArch64: Used as UINT64 ResetVector[2]
1719 // 0 - is branch relative to SEC entry point
1720 // 1 - PEI Entry Point
1723 // Verify input parameters
1725 if (FvImage
== NULL
|| FvInfo
== NULL
) {
1726 return EFI_INVALID_PARAMETER
;
1729 // Initialize FV library
1731 InitializeFvLib (FvImage
->FileImage
, FvInfo
->Size
);
1734 // Find the Sec Core
1736 Status
= GetFileByType (EFI_FV_FILETYPE_SECURITY_CORE
, 1, &SecCoreFile
);
1737 if (EFI_ERROR (Status
) || SecCoreFile
== NULL
) {
1739 // Maybe hardware does SEC job and we only have PEI Core?
1743 // Find the PEI Core. It may not exist if SEC loads DXE core directly
1745 PeiCorePhysicalAddress
= 0;
1746 Status
= GetFileByType (EFI_FV_FILETYPE_PEI_CORE
, 1, &PeiCoreFile
);
1747 if (!EFI_ERROR (Status
) && PeiCoreFile
!= NULL
) {
1749 // PEI Core found, now find PE32 or TE section
1751 Status
= GetSectionByType (PeiCoreFile
, EFI_SECTION_PE32
, 1, &Pe32Section
);
1752 if (Status
== EFI_NOT_FOUND
) {
1753 Status
= GetSectionByType (PeiCoreFile
, EFI_SECTION_TE
, 1, &Pe32Section
);
1756 if (EFI_ERROR (Status
)) {
1757 Error (NULL
, 0, 3000, "Invalid", "could not find either a PE32 or a TE section in PEI core file!");
1761 Status
= GetPe32Info (
1762 (VOID
*) ((UINTN
) Pe32Section
.Pe32Section
+ GetSectionHeaderLength(Pe32Section
.CommonHeader
)),
1768 if (EFI_ERROR (Status
)) {
1769 Error (NULL
, 0, 3000, "Invalid", "could not get the PE32 entry point for the PEI core!");
1773 // Physical address is FV base + offset of PE32 + offset of the entry point
1775 PeiCorePhysicalAddress
= FvInfo
->BaseAddress
;
1776 PeiCorePhysicalAddress
+= (UINTN
) Pe32Section
.Pe32Section
+ GetSectionHeaderLength(Pe32Section
.CommonHeader
) - (UINTN
) FvImage
->FileImage
;
1777 PeiCorePhysicalAddress
+= EntryPoint
;
1778 DebugMsg (NULL
, 0, 9, "PeiCore physical entry point address", "Address = 0x%llX", (unsigned long long) PeiCorePhysicalAddress
);
1780 if (MachineType
== EFI_IMAGE_MACHINE_ARMT
|| MachineType
== EFI_IMAGE_MACHINE_AARCH64
) {
1781 memset (ResetVector
, 0, sizeof (ResetVector
));
1782 // Address of PEI Core, if we have one
1783 ResetVector
[1] = (UINT32
)PeiCorePhysicalAddress
;
1787 // Copy to the beginning of the FV
1789 memcpy ((UINT8
*) ((UINTN
) FvImage
->FileImage
), ResetVector
, sizeof (ResetVector
));
1797 // Sec Core found, now find PE32 section
1799 Status
= GetSectionByType (SecCoreFile
, EFI_SECTION_PE32
, 1, &Pe32Section
);
1800 if (Status
== EFI_NOT_FOUND
) {
1801 Status
= GetSectionByType (SecCoreFile
, EFI_SECTION_TE
, 1, &Pe32Section
);
1804 if (EFI_ERROR (Status
)) {
1805 Error (NULL
, 0, 3000, "Invalid", "could not find a PE32 section in the SEC core file.");
1809 Status
= GetPe32Info (
1810 (VOID
*) ((UINTN
) Pe32Section
.Pe32Section
+ GetSectionHeaderLength(Pe32Section
.CommonHeader
)),
1815 if (EFI_ERROR (Status
)) {
1816 Error (NULL
, 0, 3000, "Invalid", "could not get the PE32 entry point for the SEC core.");
1820 if ((MachineType
!= EFI_IMAGE_MACHINE_ARMT
) && (MachineType
!= EFI_IMAGE_MACHINE_AARCH64
)) {
1822 // If SEC is not ARM we have nothing to do
1828 // Physical address is FV base + offset of PE32 + offset of the entry point
1830 SecCorePhysicalAddress
= FvInfo
->BaseAddress
;
1831 SecCorePhysicalAddress
+= (UINTN
) Pe32Section
.Pe32Section
+ GetSectionHeaderLength(Pe32Section
.CommonHeader
) - (UINTN
) FvImage
->FileImage
;
1832 SecCorePhysicalAddress
+= EntryPoint
;
1833 DebugMsg (NULL
, 0, 9, "SecCore physical entry point address", "Address = 0x%llX", (unsigned long long) SecCorePhysicalAddress
);
1836 // Find the PEI Core. It may not exist if SEC loads DXE core directly
1838 PeiCorePhysicalAddress
= 0;
1839 Status
= GetFileByType (EFI_FV_FILETYPE_PEI_CORE
, 1, &PeiCoreFile
);
1840 if (!EFI_ERROR (Status
) && PeiCoreFile
!= NULL
) {
1842 // PEI Core found, now find PE32 or TE section
1844 Status
= GetSectionByType (PeiCoreFile
, EFI_SECTION_PE32
, 1, &Pe32Section
);
1845 if (Status
== EFI_NOT_FOUND
) {
1846 Status
= GetSectionByType (PeiCoreFile
, EFI_SECTION_TE
, 1, &Pe32Section
);
1849 if (EFI_ERROR (Status
)) {
1850 Error (NULL
, 0, 3000, "Invalid", "could not find either a PE32 or a TE section in PEI core file!");
1854 Status
= GetPe32Info (
1855 (VOID
*) ((UINTN
) Pe32Section
.Pe32Section
+ GetSectionHeaderLength(Pe32Section
.CommonHeader
)),
1861 if (EFI_ERROR (Status
)) {
1862 Error (NULL
, 0, 3000, "Invalid", "could not get the PE32 entry point for the PEI core!");
1866 // Physical address is FV base + offset of PE32 + offset of the entry point
1868 PeiCorePhysicalAddress
= FvInfo
->BaseAddress
;
1869 PeiCorePhysicalAddress
+= (UINTN
) Pe32Section
.Pe32Section
+ GetSectionHeaderLength(Pe32Section
.CommonHeader
) - (UINTN
) FvImage
->FileImage
;
1870 PeiCorePhysicalAddress
+= EntryPoint
;
1871 DebugMsg (NULL
, 0, 9, "PeiCore physical entry point address", "Address = 0x%llX", (unsigned long long) PeiCorePhysicalAddress
);
1874 if (MachineType
== EFI_IMAGE_MACHINE_ARMT
) {
1875 // B SecEntryPoint - signed_immed_24 part +/-32MB offset
1876 // on ARM, the PC is always 8 ahead, so we're not really jumping from the base address, but from base address + 8
1877 ResetVector
[0] = (INT32
)(SecCorePhysicalAddress
- FvInfo
->BaseAddress
- 8) >> 2;
1879 if (ResetVector
[0] > 0x00FFFFFF) {
1880 Error (NULL
, 0, 3000, "Invalid", "SEC Entry point must be within 32MB of the start of the FV");
1884 // Add opcode for an uncondional branch with no link. AKA B SecEntryPoint
1885 ResetVector
[0] |= 0xEB000000;
1888 // Address of PEI Core, if we have one
1889 ResetVector
[1] = (UINT32
)PeiCorePhysicalAddress
;
1891 // SWI handler movs pc,lr. Just in case a debugger uses SWI
1892 ResetVector
[2] = 0xE1B0F07E;
1894 // Place holder to support a common interrupt handler from ROM.
1895 // Currently not suppprted. For this to be used the reset vector would not be in this FV
1896 // and the exception vectors would be hard coded in the ROM and just through this address
1897 // to find a common handler in the a module in the FV.
1899 } else if (MachineType
== EFI_IMAGE_MACHINE_AARCH64
) {
1902 ARMT above has an entry in ResetVector[2] for SWI. The way we are using the ResetVector
1903 array at the moment, for AArch64, does not allow us space for this as the header only
1904 allows for a fixed amount of bytes at the start. If we are sure that UEFI will live
1905 within the first 4GB of addressable RAM we could potensioally adopt the same ResetVector
1906 layout as above. But for the moment we replace the four 32bit vectors with two 64bit
1907 vectors in the same area of the Image heasder. This allows UEFI to start from a 64bit
1911 ((UINT64
*)ResetVector
)[0] = (UINT64
)(SecCorePhysicalAddress
- FvInfo
->BaseAddress
) >> 2;
1913 // B SecEntryPoint - signed_immed_26 part +/-128MB offset
1914 if ( ((UINT64
*)ResetVector
)[0] > 0x03FFFFFF) {
1915 Error (NULL
, 0, 3000, "Invalid", "SEC Entry point must be within 128MB of the start of the FV");
1918 // Add opcode for an uncondional branch with no link. AKA B SecEntryPoint
1919 ((UINT64
*)ResetVector
)[0] |= 0x14000000;
1921 // Address of PEI Core, if we have one
1922 ((UINT64
*)ResetVector
)[1] = (UINT64
)PeiCorePhysicalAddress
;
1925 Error (NULL
, 0, 3000, "Invalid", "Unknown ARM machine type");
1930 // Copy to the beginning of the FV
1932 memcpy ((UINT8
*) ((UINTN
) FvImage
->FileImage
), ResetVector
, sizeof (ResetVector
));
1934 DebugMsg (NULL
, 0, 9, "Update Reset vector in FV Header", NULL
);
1942 OUT UINT32
*EntryPoint
,
1943 OUT UINT32
*BaseOfCode
,
1944 OUT UINT16
*MachineType
1948 Routine Description:
1950 Retrieves the PE32 entry point offset and machine type from PE image or TeImage.
1951 See EfiImage.h for machine types. The entry point offset is from the beginning
1952 of the PE32 buffer passed in.
1956 Pe32 Beginning of the PE32.
1957 EntryPoint Offset from the beginning of the PE32 to the image entry point.
1958 BaseOfCode Base address of code.
1959 MachineType Magic number for the machine type.
1963 EFI_SUCCESS Function completed successfully.
1964 EFI_ABORTED Error encountered.
1965 EFI_INVALID_PARAMETER A required parameter was NULL.
1966 EFI_UNSUPPORTED The operation is unsupported.
1970 EFI_IMAGE_DOS_HEADER
*DosHeader
;
1971 EFI_IMAGE_OPTIONAL_HEADER_UNION
*ImgHdr
;
1972 EFI_TE_IMAGE_HEADER
*TeHeader
;
1975 // Verify input parameters
1978 return EFI_INVALID_PARAMETER
;
1982 // First check whether it is one TE Image.
1984 TeHeader
= (EFI_TE_IMAGE_HEADER
*) Pe32
;
1985 if (TeHeader
->Signature
== EFI_TE_IMAGE_HEADER_SIGNATURE
) {
1987 // By TeImage Header to get output
1989 *EntryPoint
= TeHeader
->AddressOfEntryPoint
+ sizeof (EFI_TE_IMAGE_HEADER
) - TeHeader
->StrippedSize
;
1990 *BaseOfCode
= TeHeader
->BaseOfCode
+ sizeof (EFI_TE_IMAGE_HEADER
) - TeHeader
->StrippedSize
;
1991 *MachineType
= TeHeader
->Machine
;
1995 // Then check whether
1996 // First is the DOS header
1998 DosHeader
= (EFI_IMAGE_DOS_HEADER
*) Pe32
;
2001 // Verify DOS header is expected
2003 if (DosHeader
->e_magic
!= EFI_IMAGE_DOS_SIGNATURE
) {
2004 Error (NULL
, 0, 3000, "Invalid", "Unknown magic number in the DOS header, 0x%04X.", DosHeader
->e_magic
);
2005 return EFI_UNSUPPORTED
;
2008 // Immediately following is the NT header.
2010 ImgHdr
= (EFI_IMAGE_OPTIONAL_HEADER_UNION
*) ((UINTN
) Pe32
+ DosHeader
->e_lfanew
);
2013 // Verify NT header is expected
2015 if (ImgHdr
->Pe32
.Signature
!= EFI_IMAGE_NT_SIGNATURE
) {
2016 Error (NULL
, 0, 3000, "Invalid", "Unrecognized image signature 0x%08X.", (unsigned) ImgHdr
->Pe32
.Signature
);
2017 return EFI_UNSUPPORTED
;
2022 *EntryPoint
= ImgHdr
->Pe32
.OptionalHeader
.AddressOfEntryPoint
;
2023 *BaseOfCode
= ImgHdr
->Pe32
.OptionalHeader
.BaseOfCode
;
2024 *MachineType
= ImgHdr
->Pe32
.FileHeader
.Machine
;
2028 // Verify machine type is supported
2030 if ((*MachineType
!= EFI_IMAGE_MACHINE_IA32
) && (*MachineType
!= EFI_IMAGE_MACHINE_IA64
) && (*MachineType
!= EFI_IMAGE_MACHINE_X64
) && (*MachineType
!= EFI_IMAGE_MACHINE_EBC
) &&
2031 (*MachineType
!= EFI_IMAGE_MACHINE_ARMT
) && (*MachineType
!= EFI_IMAGE_MACHINE_AARCH64
)) {
2032 Error (NULL
, 0, 3000, "Invalid", "Unrecognized machine type in the PE32 file.");
2033 return EFI_UNSUPPORTED
;
2041 IN CHAR8
*InfFileImage
,
2042 IN UINTN InfFileSize
,
2043 IN CHAR8
*FvFileName
,
2044 IN CHAR8
*MapFileName
2048 Routine Description:
2050 This is the main function which will be called from application.
2054 InfFileImage Buffer containing the INF file contents.
2055 InfFileSize Size of the contents of the InfFileImage buffer.
2056 FvFileName Requested name for the FV file.
2057 MapFileName Fv map file to log fv driver information.
2061 EFI_SUCCESS Function completed successfully.
2062 EFI_OUT_OF_RESOURCES Could not allocate required resources.
2063 EFI_ABORTED Error encountered.
2064 EFI_INVALID_PARAMETER A required parameter was NULL.
2069 MEMORY_FILE InfMemoryFile
;
2070 MEMORY_FILE FvImageMemoryFile
;
2072 EFI_FIRMWARE_VOLUME_HEADER
*FvHeader
;
2073 EFI_FFS_FILE_HEADER
*VtfFileImage
;
2074 UINT8
*FvBufferHeader
; // to make sure fvimage header 8 type alignment.
2078 CHAR8 FvMapName
[MAX_LONG_FILE_PATH
];
2080 EFI_FIRMWARE_VOLUME_EXT_HEADER
*FvExtHeader
;
2081 FILE *FvExtHeaderFile
;
2083 CHAR8 FvReportName
[MAX_LONG_FILE_PATH
];
2086 FvBufferHeader
= NULL
;
2089 FvReportFile
= NULL
;
2091 if (InfFileImage
!= NULL
) {
2093 // Initialize file structures
2095 InfMemoryFile
.FileImage
= InfFileImage
;
2096 InfMemoryFile
.CurrentFilePointer
= InfFileImage
;
2097 InfMemoryFile
.Eof
= InfFileImage
+ InfFileSize
;
2100 // Parse the FV inf file for header information
2102 Status
= ParseFvInf (&InfMemoryFile
, &mFvDataInfo
);
2103 if (EFI_ERROR (Status
)) {
2104 Error (NULL
, 0, 0003, "Error parsing file", "the input FV INF file.");
2110 // Update the file name return values
2112 if (FvFileName
== NULL
&& mFvDataInfo
.FvName
[0] != '\0') {
2113 FvFileName
= mFvDataInfo
.FvName
;
2116 if (FvFileName
== NULL
) {
2117 Error (NULL
, 0, 1001, "Missing option", "Output file name");
2121 if (mFvDataInfo
.FvBlocks
[0].Length
== 0) {
2122 Error (NULL
, 0, 1001, "Missing required argument", "Block Size");
2127 // Debug message Fv File System Guid
2129 if (mFvDataInfo
.FvFileSystemGuidSet
) {
2130 DebugMsg (NULL
, 0, 9, "FV File System Guid", "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X",
2131 (unsigned) mFvDataInfo
.FvFileSystemGuid
.Data1
,
2132 mFvDataInfo
.FvFileSystemGuid
.Data2
,
2133 mFvDataInfo
.FvFileSystemGuid
.Data3
,
2134 mFvDataInfo
.FvFileSystemGuid
.Data4
[0],
2135 mFvDataInfo
.FvFileSystemGuid
.Data4
[1],
2136 mFvDataInfo
.FvFileSystemGuid
.Data4
[2],
2137 mFvDataInfo
.FvFileSystemGuid
.Data4
[3],
2138 mFvDataInfo
.FvFileSystemGuid
.Data4
[4],
2139 mFvDataInfo
.FvFileSystemGuid
.Data4
[5],
2140 mFvDataInfo
.FvFileSystemGuid
.Data4
[6],
2141 mFvDataInfo
.FvFileSystemGuid
.Data4
[7]);
2145 // Add PI FV extension header
2148 FvExtHeaderFile
= NULL
;
2149 if (mFvDataInfo
.FvExtHeaderFile
[0] != 0) {
2151 // Open the FV Extension Header file
2153 FvExtHeaderFile
= fopen (LongFilePath (mFvDataInfo
.FvExtHeaderFile
), "rb");
2156 // Get the file size
2158 FileSize
= _filelength (fileno (FvExtHeaderFile
));
2161 // Allocate a buffer for the FV Extension Header
2163 FvExtHeader
= malloc(FileSize
);
2164 if (FvExtHeader
== NULL
) {
2165 fclose (FvExtHeaderFile
);
2166 return EFI_OUT_OF_RESOURCES
;
2170 // Read the FV Extension Header
2172 fread (FvExtHeader
, sizeof (UINT8
), FileSize
, FvExtHeaderFile
);
2173 fclose (FvExtHeaderFile
);
2176 // See if there is an override for the FV Name GUID
2178 if (mFvDataInfo
.FvNameGuidSet
) {
2179 memcpy (&FvExtHeader
->FvName
, &mFvDataInfo
.FvNameGuid
, sizeof (EFI_GUID
));
2181 memcpy (&mFvDataInfo
.FvNameGuid
, &FvExtHeader
->FvName
, sizeof (EFI_GUID
));
2182 mFvDataInfo
.FvNameGuidSet
= TRUE
;
2183 } else if (mFvDataInfo
.FvNameGuidSet
) {
2185 // Allocate a buffer for the FV Extension Header
2187 FvExtHeader
= malloc(sizeof (EFI_FIRMWARE_VOLUME_EXT_HEADER
));
2188 if (FvExtHeader
== NULL
) {
2189 return EFI_OUT_OF_RESOURCES
;
2191 memcpy (&FvExtHeader
->FvName
, &mFvDataInfo
.FvNameGuid
, sizeof (EFI_GUID
));
2192 FvExtHeader
->ExtHeaderSize
= sizeof (EFI_FIRMWARE_VOLUME_EXT_HEADER
);
2196 // Debug message Fv Name Guid
2198 if (mFvDataInfo
.FvNameGuidSet
) {
2199 DebugMsg (NULL
, 0, 9, "FV Name Guid", "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X",
2200 (unsigned) mFvDataInfo
.FvNameGuid
.Data1
,
2201 mFvDataInfo
.FvNameGuid
.Data2
,
2202 mFvDataInfo
.FvNameGuid
.Data3
,
2203 mFvDataInfo
.FvNameGuid
.Data4
[0],
2204 mFvDataInfo
.FvNameGuid
.Data4
[1],
2205 mFvDataInfo
.FvNameGuid
.Data4
[2],
2206 mFvDataInfo
.FvNameGuid
.Data4
[3],
2207 mFvDataInfo
.FvNameGuid
.Data4
[4],
2208 mFvDataInfo
.FvNameGuid
.Data4
[5],
2209 mFvDataInfo
.FvNameGuid
.Data4
[6],
2210 mFvDataInfo
.FvNameGuid
.Data4
[7]);
2213 if (CompareGuid (&mFvDataInfo
.FvFileSystemGuid
, &mEfiFirmwareFileSystem2Guid
) == 0 ||
2214 CompareGuid (&mFvDataInfo
.FvFileSystemGuid
, &mEfiFirmwareFileSystem3Guid
) == 0) {
2215 mFvDataInfo
.IsPiFvImage
= TRUE
;
2219 // FvMap file to log the function address of all modules in one Fvimage
2221 if (MapFileName
!= NULL
) {
2222 strcpy (FvMapName
, MapFileName
);
2224 strcpy (FvMapName
, FvFileName
);
2225 strcat (FvMapName
, ".map");
2227 VerboseMsg ("FV Map file name is %s", FvMapName
);
2230 // FvReport file to log the FV information in one Fvimage
2232 strcpy (FvReportName
, FvFileName
);
2233 strcat (FvReportName
, ".txt");
2236 // Calculate the FV size and Update Fv Size based on the actual FFS files.
2237 // And Update mFvDataInfo data.
2239 Status
= CalculateFvSize (&mFvDataInfo
);
2240 if (EFI_ERROR (Status
)) {
2243 VerboseMsg ("the generated FV image size is %u bytes", (unsigned) mFvDataInfo
.Size
);
2246 // support fv image and empty fv image
2248 FvImageSize
= mFvDataInfo
.Size
;
2251 // Allocate the FV, assure FvImage Header 8 byte alignment
2253 FvBufferHeader
= malloc (FvImageSize
+ sizeof (UINT64
));
2254 if (FvBufferHeader
== NULL
) {
2255 return EFI_OUT_OF_RESOURCES
;
2257 FvImage
= (UINT8
*) (((UINTN
) FvBufferHeader
+ 7) & ~7);
2260 // Initialize the FV to the erase polarity
2262 if (mFvDataInfo
.FvAttributes
== 0) {
2264 // Set Default Fv Attribute
2266 mFvDataInfo
.FvAttributes
= FV_DEFAULT_ATTRIBUTE
;
2268 if (mFvDataInfo
.FvAttributes
& EFI_FVB2_ERASE_POLARITY
) {
2269 memset (FvImage
, -1, FvImageSize
);
2271 memset (FvImage
, 0, FvImageSize
);
2275 // Initialize FV header
2277 FvHeader
= (EFI_FIRMWARE_VOLUME_HEADER
*) FvImage
;
2280 // Initialize the zero vector to all zeros.
2282 memset (FvHeader
->ZeroVector
, 0, 16);
2285 // Copy the Fv file system GUID
2287 memcpy (&FvHeader
->FileSystemGuid
, &mFvDataInfo
.FvFileSystemGuid
, sizeof (EFI_GUID
));
2289 FvHeader
->FvLength
= FvImageSize
;
2290 FvHeader
->Signature
= EFI_FVH_SIGNATURE
;
2291 FvHeader
->Attributes
= mFvDataInfo
.FvAttributes
;
2292 FvHeader
->Revision
= EFI_FVH_REVISION
;
2293 FvHeader
->ExtHeaderOffset
= 0;
2294 FvHeader
->Reserved
[0] = 0;
2297 // Copy firmware block map
2299 for (Index
= 0; mFvDataInfo
.FvBlocks
[Index
].Length
!= 0; Index
++) {
2300 FvHeader
->BlockMap
[Index
].NumBlocks
= mFvDataInfo
.FvBlocks
[Index
].NumBlocks
;
2301 FvHeader
->BlockMap
[Index
].Length
= mFvDataInfo
.FvBlocks
[Index
].Length
;
2305 // Add block map terminator
2307 FvHeader
->BlockMap
[Index
].NumBlocks
= 0;
2308 FvHeader
->BlockMap
[Index
].Length
= 0;
2311 // Complete the header
2313 FvHeader
->HeaderLength
= (UINT16
) (((UINTN
) &(FvHeader
->BlockMap
[Index
+ 1])) - (UINTN
) FvImage
);
2314 FvHeader
->Checksum
= 0;
2315 FvHeader
->Checksum
= CalculateChecksum16 ((UINT16
*) FvHeader
, FvHeader
->HeaderLength
/ sizeof (UINT16
));
2318 // If there is no FFS file, generate one empty FV
2320 if (mFvDataInfo
.FvFiles
[0][0] == 0 && !mFvDataInfo
.FvNameGuidSet
) {
2325 // Initialize our "file" view of the buffer
2327 FvImageMemoryFile
.FileImage
= (CHAR8
*)FvImage
;
2328 FvImageMemoryFile
.CurrentFilePointer
= (CHAR8
*)FvImage
+ FvHeader
->HeaderLength
;
2329 FvImageMemoryFile
.Eof
= (CHAR8
*)FvImage
+ FvImageSize
;
2332 // Initialize the FV library.
2334 InitializeFvLib (FvImageMemoryFile
.FileImage
, FvImageSize
);
2337 // Initialize the VTF file address.
2339 VtfFileImage
= (EFI_FFS_FILE_HEADER
*) FvImageMemoryFile
.Eof
;
2344 FvMapFile
= fopen (LongFilePath (FvMapName
), "w");
2345 if (FvMapFile
== NULL
) {
2346 Error (NULL
, 0, 0001, "Error opening file", FvMapName
);
2351 // Open FvReport file
2353 FvReportFile
= fopen (LongFilePath (FvReportName
), "w");
2354 if (FvReportFile
== NULL
) {
2355 Error (NULL
, 0, 0001, "Error opening file", FvReportName
);
2359 // record FV size information into FvMap file.
2361 if (mFvTotalSize
!= 0) {
2362 fprintf (FvMapFile
, EFI_FV_TOTAL_SIZE_STRING
);
2363 fprintf (FvMapFile
, " = 0x%x\n", (unsigned) mFvTotalSize
);
2365 if (mFvTakenSize
!= 0) {
2366 fprintf (FvMapFile
, EFI_FV_TAKEN_SIZE_STRING
);
2367 fprintf (FvMapFile
, " = 0x%x\n", (unsigned) mFvTakenSize
);
2369 if (mFvTotalSize
!= 0 && mFvTakenSize
!= 0) {
2370 fprintf (FvMapFile
, EFI_FV_SPACE_SIZE_STRING
);
2371 fprintf (FvMapFile
, " = 0x%x\n\n", (unsigned) (mFvTotalSize
- mFvTakenSize
));
2375 // record FV size information to FvReportFile.
2377 fprintf (FvReportFile
, "%s = 0x%x\n", EFI_FV_TOTAL_SIZE_STRING
, (unsigned) mFvTotalSize
);
2378 fprintf (FvReportFile
, "%s = 0x%x\n", EFI_FV_TAKEN_SIZE_STRING
, (unsigned) mFvTakenSize
);
2381 // Add PI FV extension header
2383 if (FvExtHeader
!= NULL
) {
2385 // Add FV Extended Header contents to the FV as a PAD file
2387 AddPadFile (&FvImageMemoryFile
, 4, VtfFileImage
, FvExtHeader
, 0);
2390 // Fv Extension header change update Fv Header Check sum
2392 FvHeader
->Checksum
= 0;
2393 FvHeader
->Checksum
= CalculateChecksum16 ((UINT16
*) FvHeader
, FvHeader
->HeaderLength
/ sizeof (UINT16
));
2399 for (Index
= 0; mFvDataInfo
.FvFiles
[Index
][0] != 0; Index
++) {
2403 Status
= AddFile (&FvImageMemoryFile
, &mFvDataInfo
, Index
, &VtfFileImage
, FvMapFile
, FvReportFile
);
2406 // Exit if error detected while adding the file
2408 if (EFI_ERROR (Status
)) {
2414 // If there is a VTF file, some special actions need to occur.
2416 if ((UINTN
) VtfFileImage
!= (UINTN
) FvImageMemoryFile
.Eof
) {
2418 // Pad from the end of the last file to the beginning of the VTF file.
2419 // If the left space is less than sizeof (EFI_FFS_FILE_HEADER)?
2421 Status
= PadFvImage (&FvImageMemoryFile
, VtfFileImage
);
2422 if (EFI_ERROR (Status
)) {
2423 Error (NULL
, 0, 4002, "Resource", "FV space is full, cannot add pad file between the last file and the VTF file.");
2428 // Update reset vector (SALE_ENTRY for IPF)
2429 // Now for IA32 and IA64 platform, the fv which has bsf file must have the
2430 // EndAddress of 0xFFFFFFFF. Thus, only this type fv needs to update the
2431 // reset vector. If the PEI Core is found, the VTF file will probably get
2432 // corrupted by updating the entry point.
2434 if ((mFvDataInfo
.BaseAddress
+ mFvDataInfo
.Size
) == FV_IMAGES_TOP_ADDRESS
) {
2435 Status
= UpdateResetVector (&FvImageMemoryFile
, &mFvDataInfo
, VtfFileImage
);
2436 if (EFI_ERROR(Status
)) {
2437 Error (NULL
, 0, 3000, "Invalid", "Could not update the reset vector.");
2440 DebugMsg (NULL
, 0, 9, "Update Reset vector in VTF file", NULL
);
2446 Status
= UpdateArmResetVectorIfNeeded (&FvImageMemoryFile
, &mFvDataInfo
);
2447 if (EFI_ERROR (Status
)) {
2448 Error (NULL
, 0, 3000, "Invalid", "Could not update the reset vector.");
2453 // Update Checksum for FvHeader
2455 FvHeader
->Checksum
= 0;
2456 FvHeader
->Checksum
= CalculateChecksum16 ((UINT16
*) FvHeader
, FvHeader
->HeaderLength
/ sizeof (UINT16
));
2460 // Update FV Alignment attribute to the largest alignment of all the FFS files in the FV
2462 if (((FvHeader
->Attributes
& EFI_FVB2_WEAK_ALIGNMENT
) != EFI_FVB2_WEAK_ALIGNMENT
) &&
2463 (((FvHeader
->Attributes
& EFI_FVB2_ALIGNMENT
) >> 16)) < MaxFfsAlignment
) {
2464 FvHeader
->Attributes
= ((MaxFfsAlignment
<< 16) | (FvHeader
->Attributes
& 0xFFFF));
2466 // Update Checksum for FvHeader
2468 FvHeader
->Checksum
= 0;
2469 FvHeader
->Checksum
= CalculateChecksum16 ((UINT16
*) FvHeader
, FvHeader
->HeaderLength
/ sizeof (UINT16
));
2473 // If there are large FFS in FV, the file system GUID should set to system 3 GUID.
2475 if (mIsLargeFfs
&& CompareGuid (&FvHeader
->FileSystemGuid
, &mEfiFirmwareFileSystem2Guid
) == 0) {
2476 memcpy (&FvHeader
->FileSystemGuid
, &mEfiFirmwareFileSystem3Guid
, sizeof (EFI_GUID
));
2477 FvHeader
->Checksum
= 0;
2478 FvHeader
->Checksum
= CalculateChecksum16 ((UINT16
*) FvHeader
, FvHeader
->HeaderLength
/ sizeof (UINT16
));
2485 FvFile
= fopen (LongFilePath (FvFileName
), "wb");
2486 if (FvFile
== NULL
) {
2487 Error (NULL
, 0, 0001, "Error opening file", FvFileName
);
2488 Status
= EFI_ABORTED
;
2492 if (fwrite (FvImage
, 1, FvImageSize
, FvFile
) != FvImageSize
) {
2493 Error (NULL
, 0, 0002, "Error writing file", FvFileName
);
2494 Status
= EFI_ABORTED
;
2499 if (FvBufferHeader
!= NULL
) {
2500 free (FvBufferHeader
);
2503 if (FvExtHeader
!= NULL
) {
2507 if (FvFile
!= NULL
) {
2512 if (FvMapFile
!= NULL
) {
2517 if (FvReportFile
!= NULL
) {
2518 fflush (FvReportFile
);
2519 fclose (FvReportFile
);
2525 UpdatePeiCoreEntryInFit (
2526 IN FIT_TABLE
*FitTablePtr
,
2527 IN UINT64 PeiCorePhysicalAddress
2531 Routine Description:
2533 This function is used to update the Pei Core address in FIT, this can be used by Sec core to pass control from
2538 FitTablePtr - The pointer of FIT_TABLE.
2539 PeiCorePhysicalAddress - The address of Pei Core entry.
2543 EFI_SUCCESS - The PEI_CORE FIT entry was updated successfully.
2544 EFI_NOT_FOUND - Not found the PEI_CORE FIT entry.
2548 FIT_TABLE
*TmpFitPtr
;
2550 UINTN NumFitComponents
;
2552 TmpFitPtr
= FitTablePtr
;
2553 NumFitComponents
= TmpFitPtr
->CompSize
;
2555 for (Index
= 0; Index
< NumFitComponents
; Index
++) {
2556 if ((TmpFitPtr
->CvAndType
& FIT_TYPE_MASK
) == COMP_TYPE_FIT_PEICORE
) {
2557 TmpFitPtr
->CompAddress
= PeiCorePhysicalAddress
;
2564 return EFI_NOT_FOUND
;
2569 IN FIT_TABLE
*FitTablePtr
2573 Routine Description:
2575 This function is used to update the checksum for FIT.
2580 FitTablePtr - The pointer of FIT_TABLE.
2588 if ((FitTablePtr
->CvAndType
& CHECKSUM_BIT_MASK
) >> 7) {
2589 FitTablePtr
->CheckSum
= 0;
2590 FitTablePtr
->CheckSum
= CalculateChecksum8 ((UINT8
*) FitTablePtr
, FitTablePtr
->CompSize
* 16);
2599 Routine Description:
2600 Calculate the FV size and Update Fv Size based on the actual FFS files.
2601 And Update FvInfo data.
2604 FvInfoPtr - The pointer to FV_INFO structure.
2607 EFI_ABORTED - Ffs Image Error
2608 EFI_SUCCESS - Successfully update FvSize
2611 UINTN CurrentOffset
;
2615 UINTN FvExtendHeaderSize
;
2616 UINT32 FfsAlignment
;
2617 UINT32 FfsHeaderSize
;
2618 EFI_FFS_FILE_HEADER FfsHeader
;
2619 BOOLEAN VtfFileFlag
;
2622 FvExtendHeaderSize
= 0;
2624 VtfFileFlag
= FALSE
;
2629 // Compute size for easy access later
2631 FvInfoPtr
->Size
= 0;
2632 for (Index
= 0; FvInfoPtr
->FvBlocks
[Index
].NumBlocks
> 0 && FvInfoPtr
->FvBlocks
[Index
].Length
> 0; Index
++) {
2633 FvInfoPtr
->Size
+= FvInfoPtr
->FvBlocks
[Index
].NumBlocks
* FvInfoPtr
->FvBlocks
[Index
].Length
;
2637 // Caculate the required sizes for all FFS files.
2639 CurrentOffset
= sizeof (EFI_FIRMWARE_VOLUME_HEADER
);
2641 for (Index
= 1;; Index
++) {
2642 CurrentOffset
+= sizeof (EFI_FV_BLOCK_MAP_ENTRY
);
2643 if (FvInfoPtr
->FvBlocks
[Index
].NumBlocks
== 0 || FvInfoPtr
->FvBlocks
[Index
].Length
== 0) {
2649 // Calculate PI extension header
2651 if (mFvDataInfo
.FvExtHeaderFile
[0] != '\0') {
2652 fpin
= fopen (LongFilePath (mFvDataInfo
.FvExtHeaderFile
), "rb");
2654 Error (NULL
, 0, 0001, "Error opening file", mFvDataInfo
.FvExtHeaderFile
);
2657 FvExtendHeaderSize
= _filelength (fileno (fpin
));
2659 if (sizeof (EFI_FFS_FILE_HEADER
) + FvExtendHeaderSize
>= MAX_FFS_SIZE
) {
2660 CurrentOffset
+= sizeof (EFI_FFS_FILE_HEADER2
) + FvExtendHeaderSize
;
2663 CurrentOffset
+= sizeof (EFI_FFS_FILE_HEADER
) + FvExtendHeaderSize
;
2665 CurrentOffset
= (CurrentOffset
+ 7) & (~7);
2666 } else if (mFvDataInfo
.FvNameGuidSet
) {
2667 CurrentOffset
+= sizeof (EFI_FFS_FILE_HEADER
) + sizeof (EFI_FIRMWARE_VOLUME_EXT_HEADER
);
2668 CurrentOffset
= (CurrentOffset
+ 7) & (~7);
2672 // Accumlate every FFS file size.
2674 for (Index
= 0; FvInfoPtr
->FvFiles
[Index
][0] != 0; Index
++) {
2679 fpin
= fopen (LongFilePath (FvInfoPtr
->FvFiles
[Index
]), "rb");
2681 Error (NULL
, 0, 0001, "Error opening file", FvInfoPtr
->FvFiles
[Index
]);
2685 // Get the file size
2687 FfsFileSize
= _filelength (fileno (fpin
));
2688 if (FfsFileSize
>= MAX_FFS_SIZE
) {
2689 FfsHeaderSize
= sizeof(EFI_FFS_FILE_HEADER2
);
2692 FfsHeaderSize
= sizeof(EFI_FFS_FILE_HEADER
);
2695 // Read Ffs File header
2697 fread (&FfsHeader
, sizeof (UINT8
), sizeof (EFI_FFS_FILE_HEADER
), fpin
);
2703 if (FvInfoPtr
->IsPiFvImage
) {
2705 // Check whether this ffs file is vtf file
2707 if (IsVtfFile (&FfsHeader
)) {
2710 // One Fv image can't have two vtf files.
2715 VtfFileSize
= FfsFileSize
;
2720 // Get the alignment of FFS file
2722 ReadFfsAlignment (&FfsHeader
, &FfsAlignment
);
2723 FfsAlignment
= 1 << FfsAlignment
;
2727 if (((CurrentOffset
+ FfsHeaderSize
) % FfsAlignment
) != 0) {
2729 // Only EFI_FFS_FILE_HEADER is needed for a pad section.
2731 CurrentOffset
= (CurrentOffset
+ FfsHeaderSize
+ sizeof(EFI_FFS_FILE_HEADER
) + FfsAlignment
- 1) & ~(FfsAlignment
- 1);
2732 CurrentOffset
-= FfsHeaderSize
;
2737 // Add ffs file size
2739 if (FvInfoPtr
->SizeofFvFiles
[Index
] > FfsFileSize
) {
2740 CurrentOffset
+= FvInfoPtr
->SizeofFvFiles
[Index
];
2742 CurrentOffset
+= FfsFileSize
;
2746 // Make next ffs file start at QWord Boundry
2748 if (FvInfoPtr
->IsPiFvImage
) {
2749 CurrentOffset
= (CurrentOffset
+ EFI_FFS_FILE_HEADER_ALIGNMENT
- 1) & ~(EFI_FFS_FILE_HEADER_ALIGNMENT
- 1);
2752 CurrentOffset
+= VtfFileSize
;
2753 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
);
2755 if (FvInfoPtr
->Size
== 0) {
2757 // Update FvInfo data
2759 FvInfoPtr
->FvBlocks
[0].NumBlocks
= CurrentOffset
/ FvInfoPtr
->FvBlocks
[0].Length
+ ((CurrentOffset
% FvInfoPtr
->FvBlocks
[0].Length
)?1:0);
2760 FvInfoPtr
->Size
= FvInfoPtr
->FvBlocks
[0].NumBlocks
* FvInfoPtr
->FvBlocks
[0].Length
;
2761 FvInfoPtr
->FvBlocks
[1].NumBlocks
= 0;
2762 FvInfoPtr
->FvBlocks
[1].Length
= 0;
2763 } else if (FvInfoPtr
->Size
< CurrentOffset
) {
2767 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
);
2768 return EFI_INVALID_PARAMETER
;
2772 // Set Fv Size Information
2774 mFvTotalSize
= FvInfoPtr
->Size
;
2775 mFvTakenSize
= CurrentOffset
;
2781 FfsRebaseImageRead (
2782 IN VOID
*FileHandle
,
2783 IN UINTN FileOffset
,
2784 IN OUT UINT32
*ReadSize
,
2789 Routine Description:
2791 Support routine for the PE/COFF Loader that reads a buffer from a PE/COFF file
2795 FileHandle - The handle to the PE/COFF file
2797 FileOffset - The offset, in bytes, into the file to read
2799 ReadSize - The number of bytes to read from the file starting at FileOffset
2801 Buffer - A pointer to the buffer to read the data into.
2805 EFI_SUCCESS - ReadSize bytes of data were read into Buffer from the PE/COFF file starting at FileOffset
2809 CHAR8
*Destination8
;
2813 Destination8
= Buffer
;
2814 Source8
= (CHAR8
*) ((UINTN
) FileHandle
+ FileOffset
);
2817 *(Destination8
++) = *(Source8
++);
2826 IN EFI_FFS_FILE_HEADER
*FfsFile
,
2831 Routine Description:
2833 This function gets all child FvImages in the input FfsFile, and records
2834 their base address to the parent image.
2837 FvInfo A pointer to FV_INFO struture.
2838 FfsFile A pointer to Ffs file image that may contain FvImage.
2839 XipOffset The offset address to the parent FvImage base.
2843 EFI_SUCCESS Base address of child Fv image is recorded.
2848 EFI_FILE_SECTION_POINTER SubFvSection
;
2849 EFI_FIRMWARE_VOLUME_HEADER
*SubFvImageHeader
;
2850 EFI_PHYSICAL_ADDRESS SubFvBaseAddress
;
2852 for (Index
= 1;; Index
++) {
2856 Status
= GetSectionByType (FfsFile
, EFI_SECTION_FIRMWARE_VOLUME_IMAGE
, Index
, &SubFvSection
);
2857 if (EFI_ERROR (Status
)) {
2860 SubFvImageHeader
= (EFI_FIRMWARE_VOLUME_HEADER
*) ((UINT8
*) SubFvSection
.FVImageSection
+ GetSectionHeaderLength(SubFvSection
.FVImageSection
));
2864 SubFvBaseAddress
= FvInfo
->BaseAddress
+ (UINTN
) SubFvImageHeader
- (UINTN
) FfsFile
+ XipOffset
;
2865 mFvBaseAddress
[mFvBaseAddressNumber
++ ] = SubFvBaseAddress
;
2873 IN OUT FV_INFO
*FvInfo
,
2875 IN OUT EFI_FFS_FILE_HEADER
*FfsFile
,
2881 Routine Description:
2883 This function determines if a file is XIP and should be rebased. It will
2884 rebase any PE32 sections found in the file using the base address.
2888 FvInfo A pointer to FV_INFO struture.
2889 FileName Ffs File PathName
2890 FfsFile A pointer to Ffs file image.
2891 XipOffset The offset address to use for rebasing the XIP file image.
2892 FvMapFile FvMapFile to record the function address in one Fvimage
2896 EFI_SUCCESS The image was properly rebased.
2897 EFI_INVALID_PARAMETER An input parameter is invalid.
2898 EFI_ABORTED An error occurred while rebasing the input file image.
2899 EFI_OUT_OF_RESOURCES Could not allocate a required resource.
2900 EFI_NOT_FOUND No compressed sections could be found.
2905 PE_COFF_LOADER_IMAGE_CONTEXT ImageContext
;
2906 PE_COFF_LOADER_IMAGE_CONTEXT OrigImageContext
;
2907 EFI_PHYSICAL_ADDRESS XipBase
;
2908 EFI_PHYSICAL_ADDRESS NewPe32BaseAddress
;
2910 EFI_FILE_SECTION_POINTER CurrentPe32Section
;
2911 EFI_FFS_FILE_STATE SavedState
;
2912 EFI_IMAGE_OPTIONAL_HEADER_UNION
*ImgHdr
;
2913 EFI_TE_IMAGE_HEADER
*TEImageHeader
;
2914 UINT8
*MemoryImagePointer
;
2915 EFI_IMAGE_SECTION_HEADER
*SectionHeader
;
2916 CHAR8 PeFileName
[MAX_LONG_FILE_PATH
];
2919 UINT8
*PeFileBuffer
;
2922 UINT32 FfsHeaderSize
;
2923 UINT32 CurSecHdrSize
;
2926 MemoryImagePointer
= NULL
;
2927 TEImageHeader
= NULL
;
2929 SectionHeader
= NULL
;
2932 PeFileBuffer
= NULL
;
2935 // Don't need to relocate image when BaseAddress is zero and no ForceRebase Flag specified.
2937 if ((FvInfo
->BaseAddress
== 0) && (FvInfo
->ForceRebase
== -1)) {
2942 // If ForceRebase Flag specified to FALSE, will always not take rebase action.
2944 if (FvInfo
->ForceRebase
== 0) {
2949 XipBase
= FvInfo
->BaseAddress
+ XipOffset
;
2952 // We only process files potentially containing PE32 sections.
2954 switch (FfsFile
->Type
) {
2955 case EFI_FV_FILETYPE_SECURITY_CORE
:
2956 case EFI_FV_FILETYPE_PEI_CORE
:
2957 case EFI_FV_FILETYPE_PEIM
:
2958 case EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER
:
2959 case EFI_FV_FILETYPE_DRIVER
:
2960 case EFI_FV_FILETYPE_DXE_CORE
:
2962 case EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE
:
2964 // Rebase the inside FvImage.
2966 GetChildFvFromFfs (FvInfo
, FfsFile
, XipOffset
);
2969 // Search PE/TE section in FV sectin.
2976 FfsHeaderSize
= GetFfsHeaderLength(FfsFile
);
2978 // Rebase each PE32 section
2980 Status
= EFI_SUCCESS
;
2981 for (Index
= 1;; Index
++) {
2985 NewPe32BaseAddress
= 0;
2990 Status
= GetSectionByType (FfsFile
, EFI_SECTION_PE32
, Index
, &CurrentPe32Section
);
2991 if (EFI_ERROR (Status
)) {
2994 CurSecHdrSize
= GetSectionHeaderLength(CurrentPe32Section
.CommonHeader
);
2997 // Initialize context
2999 memset (&ImageContext
, 0, sizeof (ImageContext
));
3000 ImageContext
.Handle
= (VOID
*) ((UINTN
) CurrentPe32Section
.Pe32Section
+ CurSecHdrSize
);
3001 ImageContext
.ImageRead
= (PE_COFF_LOADER_READ_FILE
) FfsRebaseImageRead
;
3002 Status
= PeCoffLoaderGetImageInfo (&ImageContext
);
3003 if (EFI_ERROR (Status
)) {
3004 Error (NULL
, 0, 3000, "Invalid PeImage", "The input file is %s and the return status is %x", FileName
, (int) Status
);
3008 if ( (ImageContext
.Machine
== EFI_IMAGE_MACHINE_ARMT
) ||
3009 (ImageContext
.Machine
== EFI_IMAGE_MACHINE_AARCH64
) ) {
3014 // Keep Image Context for PE image in FV
3016 memcpy (&OrigImageContext
, &ImageContext
, sizeof (ImageContext
));
3019 // Get File PdbPointer
3021 PdbPointer
= PeCoffLoaderGetPdbPointer (ImageContext
.Handle
);
3024 // Get PeHeader pointer
3026 ImgHdr
= (EFI_IMAGE_OPTIONAL_HEADER_UNION
*)((UINTN
) CurrentPe32Section
.Pe32Section
+ CurSecHdrSize
+ ImageContext
.PeCoffHeaderOffset
);
3029 // Calculate the PE32 base address, based on file type
3031 switch (FfsFile
->Type
) {
3032 case EFI_FV_FILETYPE_SECURITY_CORE
:
3033 case EFI_FV_FILETYPE_PEI_CORE
:
3034 case EFI_FV_FILETYPE_PEIM
:
3035 case EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER
:
3037 // Check if section-alignment and file-alignment match or not
3039 if ((ImgHdr
->Pe32
.OptionalHeader
.SectionAlignment
!= ImgHdr
->Pe32
.OptionalHeader
.FileAlignment
)) {
3041 // Xip module has the same section alignment and file alignment.
3043 Error (NULL
, 0, 3000, "Invalid", "Section-Alignment and File-Alignment do not match : %s.", FileName
);
3047 // PeImage has no reloc section. It will try to get reloc data from the original EFI image.
3049 if (ImageContext
.RelocationsStripped
) {
3051 // Construct the original efi file Name
3053 strcpy (PeFileName
, FileName
);
3054 Cptr
= PeFileName
+ strlen (PeFileName
);
3055 while (*Cptr
!= '.') {
3059 Error (NULL
, 0, 3000, "Invalid", "The file %s has no .reloc section.", FileName
);
3067 PeFile
= fopen (LongFilePath (PeFileName
), "rb");
3068 if (PeFile
== NULL
) {
3069 Warning (NULL
, 0, 0, "Invalid", "The file %s has no .reloc section.", FileName
);
3070 //Error (NULL, 0, 3000, "Invalid", "The file %s has no .reloc section.", FileName);
3071 //return EFI_ABORTED;
3075 // Get the file size
3077 PeFileSize
= _filelength (fileno (PeFile
));
3078 PeFileBuffer
= (UINT8
*) malloc (PeFileSize
);
3079 if (PeFileBuffer
== NULL
) {
3080 Error (NULL
, 0, 4001, "Resource", "memory cannot be allocated on rebase of %s", FileName
);
3081 return EFI_OUT_OF_RESOURCES
;
3086 fread (PeFileBuffer
, sizeof (UINT8
), PeFileSize
, PeFile
);
3092 // Handle pointer to the original efi image.
3094 ImageContext
.Handle
= PeFileBuffer
;
3095 Status
= PeCoffLoaderGetImageInfo (&ImageContext
);
3096 if (EFI_ERROR (Status
)) {
3097 Error (NULL
, 0, 3000, "Invalid PeImage", "The input file is %s and the return status is %x", FileName
, (int) Status
);
3100 ImageContext
.RelocationsStripped
= FALSE
;
3103 NewPe32BaseAddress
= XipBase
+ (UINTN
) CurrentPe32Section
.Pe32Section
+ CurSecHdrSize
- (UINTN
)FfsFile
;
3106 case EFI_FV_FILETYPE_DRIVER
:
3107 case EFI_FV_FILETYPE_DXE_CORE
:
3109 // Check if section-alignment and file-alignment match or not
3111 if ((ImgHdr
->Pe32
.OptionalHeader
.SectionAlignment
!= ImgHdr
->Pe32
.OptionalHeader
.FileAlignment
)) {
3113 // Xip module has the same section alignment and file alignment.
3115 Error (NULL
, 0, 3000, "Invalid", "Section-Alignment and File-Alignment do not match : %s.", FileName
);
3118 NewPe32BaseAddress
= XipBase
+ (UINTN
) CurrentPe32Section
.Pe32Section
+ CurSecHdrSize
- (UINTN
)FfsFile
;
3123 // Not supported file type
3129 // Relocation doesn't exist
3131 if (ImageContext
.RelocationsStripped
) {
3132 Warning (NULL
, 0, 0, "Invalid", "The file %s has no .reloc section.", FileName
);
3137 // Relocation exist and rebase
3140 // Load and Relocate Image Data
3142 MemoryImagePointer
= (UINT8
*) malloc ((UINTN
) ImageContext
.ImageSize
+ ImageContext
.SectionAlignment
);
3143 if (MemoryImagePointer
== NULL
) {
3144 Error (NULL
, 0, 4001, "Resource", "memory cannot be allocated on rebase of %s", FileName
);
3145 return EFI_OUT_OF_RESOURCES
;
3147 memset ((VOID
*) MemoryImagePointer
, 0, (UINTN
) ImageContext
.ImageSize
+ ImageContext
.SectionAlignment
);
3148 ImageContext
.ImageAddress
= ((UINTN
) MemoryImagePointer
+ ImageContext
.SectionAlignment
- 1) & (~((UINTN
) ImageContext
.SectionAlignment
- 1));
3150 Status
= PeCoffLoaderLoadImage (&ImageContext
);
3151 if (EFI_ERROR (Status
)) {
3152 Error (NULL
, 0, 3000, "Invalid", "LocateImage() call failed on rebase of %s", FileName
);
3153 free ((VOID
*) MemoryImagePointer
);
3157 ImageContext
.DestinationAddress
= NewPe32BaseAddress
;
3158 Status
= PeCoffLoaderRelocateImage (&ImageContext
);
3159 if (EFI_ERROR (Status
)) {
3160 Error (NULL
, 0, 3000, "Invalid", "RelocateImage() call failed on rebase of %s", FileName
);
3161 free ((VOID
*) MemoryImagePointer
);
3166 // Copy Relocated data to raw image file.
3168 SectionHeader
= (EFI_IMAGE_SECTION_HEADER
*) (
3171 sizeof (EFI_IMAGE_FILE_HEADER
) +
3172 ImgHdr
->Pe32
.FileHeader
.SizeOfOptionalHeader
3175 for (Index
= 0; Index
< ImgHdr
->Pe32
.FileHeader
.NumberOfSections
; Index
++, SectionHeader
++) {
3177 (UINT8
*) CurrentPe32Section
.Pe32Section
+ CurSecHdrSize
+ SectionHeader
->PointerToRawData
,
3178 (VOID
*) (UINTN
) (ImageContext
.ImageAddress
+ SectionHeader
->VirtualAddress
),
3179 SectionHeader
->SizeOfRawData
3183 free ((VOID
*) MemoryImagePointer
);
3184 MemoryImagePointer
= NULL
;
3185 if (PeFileBuffer
!= NULL
) {
3186 free (PeFileBuffer
);
3187 PeFileBuffer
= NULL
;
3191 // Update Image Base Address
3193 if (ImgHdr
->Pe32
.OptionalHeader
.Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
3194 ImgHdr
->Pe32
.OptionalHeader
.ImageBase
= (UINT32
) NewPe32BaseAddress
;
3195 } else if (ImgHdr
->Pe32Plus
.OptionalHeader
.Magic
== EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC
) {
3196 ImgHdr
->Pe32Plus
.OptionalHeader
.ImageBase
= NewPe32BaseAddress
;
3198 Error (NULL
, 0, 3000, "Invalid", "unknown PE magic signature %X in PE32 image %s",
3199 ImgHdr
->Pe32
.OptionalHeader
.Magic
,
3206 // Now update file checksum
3208 if (FfsFile
->Attributes
& FFS_ATTRIB_CHECKSUM
) {
3209 SavedState
= FfsFile
->State
;
3210 FfsFile
->IntegrityCheck
.Checksum
.File
= 0;
3212 FfsFile
->IntegrityCheck
.Checksum
.File
= CalculateChecksum8 (
3213 (UINT8
*) ((UINT8
*)FfsFile
+ FfsHeaderSize
),
3214 GetFfsFileLength (FfsFile
) - FfsHeaderSize
3216 FfsFile
->State
= SavedState
;
3220 // Get this module function address from ModulePeMapFile and add them into FvMap file
3224 // Default use FileName as map file path
3226 if (PdbPointer
== NULL
) {
3227 PdbPointer
= FileName
;
3230 WriteMapFile (FvMapFile
, PdbPointer
, FfsFile
, NewPe32BaseAddress
, &OrigImageContext
);
3233 if (FfsFile
->Type
!= EFI_FV_FILETYPE_SECURITY_CORE
&&
3234 FfsFile
->Type
!= EFI_FV_FILETYPE_PEI_CORE
&&
3235 FfsFile
->Type
!= EFI_FV_FILETYPE_PEIM
&&
3236 FfsFile
->Type
!= EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER
&&
3237 FfsFile
->Type
!= EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE
3240 // Only Peim code may have a TE section
3246 // Now process TE sections
3248 for (Index
= 1;; Index
++) {
3249 NewPe32BaseAddress
= 0;
3254 Status
= GetSectionByType (FfsFile
, EFI_SECTION_TE
, Index
, &CurrentPe32Section
);
3255 if (EFI_ERROR (Status
)) {
3259 CurSecHdrSize
= GetSectionHeaderLength(CurrentPe32Section
.CommonHeader
);
3262 // Calculate the TE base address, the FFS file base plus the offset of the TE section less the size stripped off
3265 TEImageHeader
= (EFI_TE_IMAGE_HEADER
*) ((UINT8
*) CurrentPe32Section
.Pe32Section
+ CurSecHdrSize
);
3268 // Initialize context, load image info.
3270 memset (&ImageContext
, 0, sizeof (ImageContext
));
3271 ImageContext
.Handle
= (VOID
*) TEImageHeader
;
3272 ImageContext
.ImageRead
= (PE_COFF_LOADER_READ_FILE
) FfsRebaseImageRead
;
3273 Status
= PeCoffLoaderGetImageInfo (&ImageContext
);
3274 if (EFI_ERROR (Status
)) {
3275 Error (NULL
, 0, 3000, "Invalid TeImage", "The input file is %s and the return status is %x", FileName
, (int) Status
);
3279 if ( (ImageContext
.Machine
== EFI_IMAGE_MACHINE_ARMT
) ||
3280 (ImageContext
.Machine
== EFI_IMAGE_MACHINE_AARCH64
) ) {
3285 // Keep Image Context for TE image in FV
3287 memcpy (&OrigImageContext
, &ImageContext
, sizeof (ImageContext
));
3290 // Get File PdbPointer
3292 PdbPointer
= PeCoffLoaderGetPdbPointer (ImageContext
.Handle
);
3295 // Set new rebased address.
3297 NewPe32BaseAddress
= XipBase
+ (UINTN
) TEImageHeader
+ sizeof (EFI_TE_IMAGE_HEADER
) \
3298 - TEImageHeader
->StrippedSize
- (UINTN
) FfsFile
;
3301 // if reloc is stripped, try to get the original efi image to get reloc info.
3303 if (ImageContext
.RelocationsStripped
) {
3305 // Construct the original efi file name
3307 strcpy (PeFileName
, FileName
);
3308 Cptr
= PeFileName
+ strlen (PeFileName
);
3309 while (*Cptr
!= '.') {
3314 Error (NULL
, 0, 3000, "Invalid", "The file %s has no .reloc section.", FileName
);
3323 PeFile
= fopen (LongFilePath (PeFileName
), "rb");
3324 if (PeFile
== NULL
) {
3325 Warning (NULL
, 0, 0, "Invalid", "The file %s has no .reloc section.", FileName
);
3326 //Error (NULL, 0, 3000, "Invalid", "The file %s has no .reloc section.", FileName);
3327 //return EFI_ABORTED;
3330 // Get the file size
3332 PeFileSize
= _filelength (fileno (PeFile
));
3333 PeFileBuffer
= (UINT8
*) malloc (PeFileSize
);
3334 if (PeFileBuffer
== NULL
) {
3335 Error (NULL
, 0, 4001, "Resource", "memory cannot be allocated on rebase of %s", FileName
);
3336 return EFI_OUT_OF_RESOURCES
;
3341 fread (PeFileBuffer
, sizeof (UINT8
), PeFileSize
, PeFile
);
3347 // Append reloc section into TeImage
3349 ImageContext
.Handle
= PeFileBuffer
;
3350 Status
= PeCoffLoaderGetImageInfo (&ImageContext
);
3351 if (EFI_ERROR (Status
)) {
3352 Error (NULL
, 0, 3000, "Invalid TeImage", "The input file is %s and the return status is %x", FileName
, (int) Status
);
3355 ImageContext
.RelocationsStripped
= FALSE
;
3359 // Relocation doesn't exist
3361 if (ImageContext
.RelocationsStripped
) {
3362 Warning (NULL
, 0, 0, "Invalid", "The file %s has no .reloc section.", FileName
);
3367 // Relocation exist and rebase
3370 // Load and Relocate Image Data
3372 MemoryImagePointer
= (UINT8
*) malloc ((UINTN
) ImageContext
.ImageSize
+ ImageContext
.SectionAlignment
);
3373 if (MemoryImagePointer
== NULL
) {
3374 Error (NULL
, 0, 4001, "Resource", "memory cannot be allocated on rebase of %s", FileName
);
3375 return EFI_OUT_OF_RESOURCES
;
3377 memset ((VOID
*) MemoryImagePointer
, 0, (UINTN
) ImageContext
.ImageSize
+ ImageContext
.SectionAlignment
);
3378 ImageContext
.ImageAddress
= ((UINTN
) MemoryImagePointer
+ ImageContext
.SectionAlignment
- 1) & (~((UINTN
) ImageContext
.SectionAlignment
- 1));
3380 Status
= PeCoffLoaderLoadImage (&ImageContext
);
3381 if (EFI_ERROR (Status
)) {
3382 Error (NULL
, 0, 3000, "Invalid", "LocateImage() call failed on rebase of %s", FileName
);
3383 free ((VOID
*) MemoryImagePointer
);
3387 // Reloacate TeImage
3389 ImageContext
.DestinationAddress
= NewPe32BaseAddress
;
3390 Status
= PeCoffLoaderRelocateImage (&ImageContext
);
3391 if (EFI_ERROR (Status
)) {
3392 Error (NULL
, 0, 3000, "Invalid", "RelocateImage() call failed on rebase of TE image %s", FileName
);
3393 free ((VOID
*) MemoryImagePointer
);
3398 // Copy the relocated image into raw image file.
3400 SectionHeader
= (EFI_IMAGE_SECTION_HEADER
*) (TEImageHeader
+ 1);
3401 for (Index
= 0; Index
< TEImageHeader
->NumberOfSections
; Index
++, SectionHeader
++) {
3402 if (!ImageContext
.IsTeImage
) {
3404 (UINT8
*) TEImageHeader
+ sizeof (EFI_TE_IMAGE_HEADER
) - TEImageHeader
->StrippedSize
+ SectionHeader
->PointerToRawData
,
3405 (VOID
*) (UINTN
) (ImageContext
.ImageAddress
+ SectionHeader
->VirtualAddress
),
3406 SectionHeader
->SizeOfRawData
3410 (UINT8
*) TEImageHeader
+ sizeof (EFI_TE_IMAGE_HEADER
) - TEImageHeader
->StrippedSize
+ SectionHeader
->PointerToRawData
,
3411 (VOID
*) (UINTN
) (ImageContext
.ImageAddress
+ sizeof (EFI_TE_IMAGE_HEADER
) - TEImageHeader
->StrippedSize
+ SectionHeader
->VirtualAddress
),
3412 SectionHeader
->SizeOfRawData
3418 // Free the allocated memory resource
3420 free ((VOID
*) MemoryImagePointer
);
3421 MemoryImagePointer
= NULL
;
3422 if (PeFileBuffer
!= NULL
) {
3423 free (PeFileBuffer
);
3424 PeFileBuffer
= NULL
;
3428 // Update Image Base Address
3430 TEImageHeader
->ImageBase
= NewPe32BaseAddress
;
3433 // Now update file checksum
3435 if (FfsFile
->Attributes
& FFS_ATTRIB_CHECKSUM
) {
3436 SavedState
= FfsFile
->State
;
3437 FfsFile
->IntegrityCheck
.Checksum
.File
= 0;
3439 FfsFile
->IntegrityCheck
.Checksum
.File
= CalculateChecksum8 (
3440 (UINT8
*)((UINT8
*)FfsFile
+ FfsHeaderSize
),
3441 GetFfsFileLength (FfsFile
) - FfsHeaderSize
3443 FfsFile
->State
= SavedState
;
3446 // Get this module function address from ModulePeMapFile and add them into FvMap file
3450 // Default use FileName as map file path
3452 if (PdbPointer
== NULL
) {
3453 PdbPointer
= FileName
;
3469 FindApResetVectorPosition (
3470 IN MEMORY_FILE
*FvImage
,
3475 Routine Description:
3477 Find the position in this FvImage to place Ap reset vector.
3481 FvImage Memory file for the FV memory image.
3482 Pointer Pointer to pointer to position.
3486 EFI_NOT_FOUND - No satisfied position is found.
3487 EFI_SUCCESS - The suitable position is return.
3491 EFI_FFS_FILE_HEADER
*PadFile
;
3497 for (Index
= 1; ;Index
++) {
3499 // Find Pad File to add ApResetVector info
3501 Status
= GetFileByType (EFI_FV_FILETYPE_FFS_PAD
, Index
, &PadFile
);
3502 if (EFI_ERROR (Status
) || (PadFile
== NULL
)) {
3504 // No Pad file to be found.
3509 // Get Pad file size.
3511 FileLength
= GetFfsFileLength(PadFile
);
3512 FileLength
= (FileLength
+ EFI_FFS_FILE_HEADER_ALIGNMENT
- 1) & ~(EFI_FFS_FILE_HEADER_ALIGNMENT
- 1);
3514 // FixPoint must be align on 0x1000 relative to FvImage Header
3516 FixPoint
= (UINT8
*) PadFile
+ GetFfsHeaderLength(PadFile
);
3517 FixPoint
= FixPoint
+ 0x1000 - (((UINTN
) FixPoint
- (UINTN
) FvImage
->FileImage
) & 0xFFF);
3519 // FixPoint be larger at the last place of one fv image.
3521 while (((UINTN
) FixPoint
+ SIZEOF_STARTUP_DATA_ARRAY
- (UINTN
) PadFile
) <= FileLength
) {
3526 if ((UINTN
) FixPoint
< ((UINTN
) PadFile
+ GetFfsHeaderLength(PadFile
))) {
3528 // No alignment FixPoint in this Pad File.
3533 if ((UINTN
) FvImage
->Eof
- (UINTN
)FixPoint
<= 0x20000) {
3535 // Find the position to place ApResetVector
3537 *Pointer
= FixPoint
;
3542 return EFI_NOT_FOUND
;
3547 IN MEMORY_FILE
*InfFile
,
3548 OUT CAP_INFO
*CapInfo
3552 Routine Description:
3554 This function parses a Cap.INF file and copies info into a CAP_INFO structure.
3558 InfFile Memory file image.
3559 CapInfo Information read from INF file.
3563 EFI_SUCCESS INF file information successfully retrieved.
3564 EFI_ABORTED INF file has an invalid format.
3565 EFI_NOT_FOUND A required string was not found in the INF file.
3568 CHAR8 Value
[MAX_LONG_FILE_PATH
];
3570 UINTN Index
, Number
;
3574 // Initialize Cap info
3576 // memset (CapInfo, 0, sizeof (CAP_INFO));
3580 // Read the Capsule Guid
3582 Status
= FindToken (InfFile
, OPTIONS_SECTION_STRING
, EFI_CAPSULE_GUID_STRING
, 0, Value
);
3583 if (Status
== EFI_SUCCESS
) {
3585 // Get the Capsule Guid
3587 Status
= StringToGuid (Value
, &CapInfo
->CapGuid
);
3588 if (EFI_ERROR (Status
)) {
3589 Error (NULL
, 0, 2000, "Invalid parameter", "%s = %s", EFI_CAPSULE_GUID_STRING
, Value
);
3592 DebugMsg (NULL
, 0, 9, "Capsule Guid", "%s = %s", EFI_CAPSULE_GUID_STRING
, Value
);
3596 // Read the Capsule Header Size
3598 Status
= FindToken (InfFile
, OPTIONS_SECTION_STRING
, EFI_CAPSULE_HEADER_SIZE_STRING
, 0, Value
);
3599 if (Status
== EFI_SUCCESS
) {
3600 Status
= AsciiStringToUint64 (Value
, FALSE
, &Value64
);
3601 if (EFI_ERROR (Status
)) {
3602 Error (NULL
, 0, 2000, "Invalid parameter", "%s = %s", EFI_CAPSULE_HEADER_SIZE_STRING
, Value
);
3605 CapInfo
->HeaderSize
= (UINT32
) Value64
;
3606 DebugMsg (NULL
, 0, 9, "Capsule Header size", "%s = %s", EFI_CAPSULE_HEADER_SIZE_STRING
, Value
);
3610 // Read the Capsule Flag
3612 Status
= FindToken (InfFile
, OPTIONS_SECTION_STRING
, EFI_CAPSULE_FLAGS_STRING
, 0, Value
);
3613 if (Status
== EFI_SUCCESS
) {
3614 if (strstr (Value
, "PopulateSystemTable") != NULL
) {
3615 CapInfo
->Flags
|= CAPSULE_FLAGS_PERSIST_ACROSS_RESET
| CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE
;
3616 if (strstr (Value
, "InitiateReset") != NULL
) {
3617 CapInfo
->Flags
|= CAPSULE_FLAGS_INITIATE_RESET
;
3619 } else if (strstr (Value
, "PersistAcrossReset") != NULL
) {
3620 CapInfo
->Flags
|= CAPSULE_FLAGS_PERSIST_ACROSS_RESET
;
3621 if (strstr (Value
, "InitiateReset") != NULL
) {
3622 CapInfo
->Flags
|= CAPSULE_FLAGS_INITIATE_RESET
;
3625 Error (NULL
, 0, 2000, "Invalid parameter", "invalid Flag setting for %s.", EFI_CAPSULE_FLAGS_STRING
);
3628 DebugMsg (NULL
, 0, 9, "Capsule Flag", Value
);
3631 Status
= FindToken (InfFile
, OPTIONS_SECTION_STRING
, EFI_OEM_CAPSULE_FLAGS_STRING
, 0, Value
);
3632 if (Status
== EFI_SUCCESS
) {
3633 Status
= AsciiStringToUint64 (Value
, FALSE
, &Value64
);
3634 if (EFI_ERROR (Status
) || Value64
> 0xffff) {
3635 Error (NULL
, 0, 2000, "Invalid parameter",
3636 "invalid Flag setting for %s. Must be integer value between 0x0000 and 0xffff.",
3637 EFI_OEM_CAPSULE_FLAGS_STRING
);
3640 CapInfo
->Flags
|= Value64
;
3641 DebugMsg (NULL
, 0, 9, "Capsule Extend Flag", Value
);
3645 // Read Capsule File name
3647 Status
= FindToken (InfFile
, OPTIONS_SECTION_STRING
, EFI_FILE_NAME_STRING
, 0, Value
);
3648 if (Status
== EFI_SUCCESS
) {
3650 // Get output file name
3652 strcpy (CapInfo
->CapName
, Value
);
3656 // Read the Capsule FileImage
3659 for (Index
= 0; Index
< MAX_NUMBER_OF_FILES_IN_CAP
; Index
++) {
3660 if (CapInfo
->CapFiles
[Index
][0] != '\0') {
3664 // Read the capsule file name
3666 Status
= FindToken (InfFile
, FILES_SECTION_STRING
, EFI_FILE_NAME_STRING
, Number
++, Value
);
3668 if (Status
== EFI_SUCCESS
) {
3672 strcpy (CapInfo
->CapFiles
[Index
], Value
);
3673 DebugMsg (NULL
, 0, 9, "Capsule component file", "the %uth file name is %s", (unsigned) Index
, CapInfo
->CapFiles
[Index
]);
3680 Warning (NULL
, 0, 0, "Capsule components are not specified.", NULL
);
3688 IN CHAR8
*InfFileImage
,
3689 IN UINTN InfFileSize
,
3690 IN CHAR8
*CapFileName
3694 Routine Description:
3696 This is the main function which will be called from application to create UEFI Capsule image.
3700 InfFileImage Buffer containing the INF file contents.
3701 InfFileSize Size of the contents of the InfFileImage buffer.
3702 CapFileName Requested name for the Cap file.
3706 EFI_SUCCESS Function completed successfully.
3707 EFI_OUT_OF_RESOURCES Could not allocate required resources.
3708 EFI_ABORTED Error encountered.
3709 EFI_INVALID_PARAMETER A required parameter was NULL.
3715 EFI_CAPSULE_HEADER
*CapsuleHeader
;
3716 MEMORY_FILE InfMemoryFile
;
3722 if (InfFileImage
!= NULL
) {
3724 // Initialize file structures
3726 InfMemoryFile
.FileImage
= InfFileImage
;
3727 InfMemoryFile
.CurrentFilePointer
= InfFileImage
;
3728 InfMemoryFile
.Eof
= InfFileImage
+ InfFileSize
;
3731 // Parse the Cap inf file for header information
3733 Status
= ParseCapInf (&InfMemoryFile
, &mCapDataInfo
);
3734 if (Status
!= EFI_SUCCESS
) {
3739 if (mCapDataInfo
.HeaderSize
== 0) {
3741 // make header size align 16 bytes.
3743 mCapDataInfo
.HeaderSize
= sizeof (EFI_CAPSULE_HEADER
);
3744 mCapDataInfo
.HeaderSize
= (mCapDataInfo
.HeaderSize
+ 0xF) & ~0xF;
3747 if (mCapDataInfo
.HeaderSize
< sizeof (EFI_CAPSULE_HEADER
)) {
3748 Error (NULL
, 0, 2000, "Invalid parameter", "The specified HeaderSize cannot be less than the size of EFI_CAPSULE_HEADER.");
3749 return EFI_INVALID_PARAMETER
;
3752 if (CapFileName
== NULL
&& mCapDataInfo
.CapName
[0] != '\0') {
3753 CapFileName
= mCapDataInfo
.CapName
;
3756 if (CapFileName
== NULL
) {
3757 Error (NULL
, 0, 2001, "Missing required argument", "Output Capsule file name");
3758 return EFI_INVALID_PARAMETER
;
3762 // Set Default Capsule Guid value
3764 if (CompareGuid (&mCapDataInfo
.CapGuid
, &mZeroGuid
) == 0) {
3765 memcpy (&mCapDataInfo
.CapGuid
, &mDefaultCapsuleGuid
, sizeof (EFI_GUID
));
3768 // Calculate the size of capsule image.
3772 CapSize
= mCapDataInfo
.HeaderSize
;
3773 while (mCapDataInfo
.CapFiles
[Index
][0] != '\0') {
3774 fpin
= fopen (LongFilePath (mCapDataInfo
.CapFiles
[Index
]), "rb");
3776 Error (NULL
, 0, 0001, "Error opening file", mCapDataInfo
.CapFiles
[Index
]);
3779 FileSize
= _filelength (fileno (fpin
));
3780 CapSize
+= FileSize
;
3786 // Allocate buffer for capsule image.
3788 CapBuffer
= (UINT8
*) malloc (CapSize
);
3789 if (CapBuffer
== NULL
) {
3790 Error (NULL
, 0, 4001, "Resource", "memory cannot be allocated for creating the capsule.");
3791 return EFI_OUT_OF_RESOURCES
;
3795 // Initialize the capsule header to zero
3797 memset (CapBuffer
, 0, mCapDataInfo
.HeaderSize
);
3800 // create capsule header and get capsule body
3802 CapsuleHeader
= (EFI_CAPSULE_HEADER
*) CapBuffer
;
3803 memcpy (&CapsuleHeader
->CapsuleGuid
, &mCapDataInfo
.CapGuid
, sizeof (EFI_GUID
));
3804 CapsuleHeader
->HeaderSize
= mCapDataInfo
.HeaderSize
;
3805 CapsuleHeader
->Flags
= mCapDataInfo
.Flags
;
3806 CapsuleHeader
->CapsuleImageSize
= CapSize
;
3810 CapSize
= CapsuleHeader
->HeaderSize
;
3811 while (mCapDataInfo
.CapFiles
[Index
][0] != '\0') {
3812 fpin
= fopen (LongFilePath (mCapDataInfo
.CapFiles
[Index
]), "rb");
3814 Error (NULL
, 0, 0001, "Error opening file", mCapDataInfo
.CapFiles
[Index
]);
3818 FileSize
= _filelength (fileno (fpin
));
3819 fread (CapBuffer
+ CapSize
, 1, FileSize
, fpin
);
3822 CapSize
+= FileSize
;
3826 // write capsule data into the output file
3828 fpout
= fopen (LongFilePath (CapFileName
), "wb");
3829 if (fpout
== NULL
) {
3830 Error (NULL
, 0, 0001, "Error opening file", CapFileName
);
3835 fwrite (CapBuffer
, 1, CapSize
, fpout
);
3838 VerboseMsg ("The size of the generated capsule image is %u bytes", (unsigned) CapSize
);