3 Copyright (c) 2004 - 2010, Intel Corporation
4 All rights reserved. This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
18 This file contains the internal functions required to generate a Firmware Volume.
26 #include <uuid/uuid.h>
35 #include "GenFvInternalLib.h"
37 #include "PeCoffLib.h"
38 #include "WinNtInclude.h"
41 STATIC UINT32 MaxFfsAlignment
= 0;
43 EFI_GUID mEfiFirmwareVolumeTopFileGuid
= EFI_FFS_VOLUME_TOP_FILE_GUID
;
44 EFI_GUID mFileGuidArray
[MAX_NUMBER_OF_FILES_IN_FV
];
45 EFI_GUID mZeroGuid
= {0x0, 0x0, 0x0, {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}};
46 EFI_GUID mDefaultCapsuleGuid
= {0x3B6686BD, 0x0D76, 0x4030, { 0xB7, 0x0E, 0xB5, 0x51, 0x9E, 0x2F, 0xC5, 0xA0 }};
48 CHAR8
*mFvbAttributeName
[] = {
49 EFI_FVB2_READ_DISABLED_CAP_STRING
,
50 EFI_FVB2_READ_ENABLED_CAP_STRING
,
51 EFI_FVB2_READ_STATUS_STRING
,
52 EFI_FVB2_WRITE_DISABLED_CAP_STRING
,
53 EFI_FVB2_WRITE_ENABLED_CAP_STRING
,
54 EFI_FVB2_WRITE_STATUS_STRING
,
55 EFI_FVB2_LOCK_CAP_STRING
,
56 EFI_FVB2_LOCK_STATUS_STRING
,
58 EFI_FVB2_STICKY_WRITE_STRING
,
59 EFI_FVB2_MEMORY_MAPPED_STRING
,
60 EFI_FVB2_ERASE_POLARITY_STRING
,
61 EFI_FVB2_READ_LOCK_CAP_STRING
,
62 EFI_FVB2_READ_LOCK_STATUS_STRING
,
63 EFI_FVB2_WRITE_LOCK_CAP_STRING
,
64 EFI_FVB2_WRITE_LOCK_STATUS_STRING
67 CHAR8
*mFvbAlignmentName
[] = {
68 EFI_FVB2_ALIGNMENT_1_STRING
,
69 EFI_FVB2_ALIGNMENT_2_STRING
,
70 EFI_FVB2_ALIGNMENT_4_STRING
,
71 EFI_FVB2_ALIGNMENT_8_STRING
,
72 EFI_FVB2_ALIGNMENT_16_STRING
,
73 EFI_FVB2_ALIGNMENT_32_STRING
,
74 EFI_FVB2_ALIGNMENT_64_STRING
,
75 EFI_FVB2_ALIGNMENT_128_STRING
,
76 EFI_FVB2_ALIGNMENT_256_STRING
,
77 EFI_FVB2_ALIGNMENT_512_STRING
,
78 EFI_FVB2_ALIGNMENT_1K_STRING
,
79 EFI_FVB2_ALIGNMENT_2K_STRING
,
80 EFI_FVB2_ALIGNMENT_4K_STRING
,
81 EFI_FVB2_ALIGNMENT_8K_STRING
,
82 EFI_FVB2_ALIGNMENT_16K_STRING
,
83 EFI_FVB2_ALIGNMENT_32K_STRING
,
84 EFI_FVB2_ALIGNMENT_64K_STRING
,
85 EFI_FVB2_ALIGNMENT_128K_STRING
,
86 EFI_FVB2_ALIGNMENT_256K_STRING
,
87 EFI_FVB2_ALIGNMNET_512K_STRING
,
88 EFI_FVB2_ALIGNMENT_1M_STRING
,
89 EFI_FVB2_ALIGNMENT_2M_STRING
,
90 EFI_FVB2_ALIGNMENT_4M_STRING
,
91 EFI_FVB2_ALIGNMENT_8M_STRING
,
92 EFI_FVB2_ALIGNMENT_16M_STRING
,
93 EFI_FVB2_ALIGNMENT_32M_STRING
,
94 EFI_FVB2_ALIGNMENT_64M_STRING
,
95 EFI_FVB2_ALIGNMENT_128M_STRING
,
96 EFI_FVB2_ALIGNMENT_256M_STRING
,
97 EFI_FVB2_ALIGNMENT_512M_STRING
,
98 EFI_FVB2_ALIGNMENT_1G_STRING
,
99 EFI_FVB2_ALIGNMENT_2G_STRING
103 // This data array will be located at the base of the Firmware Volume Header (FVH)
104 // in the boot block. It must not exceed 14 bytes of code. The last 2 bytes
105 // will be used to keep the FVH checksum consistent.
106 // This code will be run in response to a starutp IPI for HT-enabled systems.
108 #define SIZEOF_STARTUP_DATA_ARRAY 0x10
110 UINT8 m128kRecoveryStartupApDataArray
[SIZEOF_STARTUP_DATA_ARRAY
] = {
112 // EA D0 FF 00 F0 ; far jmp F000:FFD0
113 // 0, 0, 0, 0, 0, 0, 0, 0, 0, ; Reserved bytes
114 // 0, 0 ; Checksum Padding
134 UINT8 m64kRecoveryStartupApDataArray
[SIZEOF_STARTUP_DATA_ARRAY
] = {
136 // EB CE ; jmp short ($-0x30)
137 // ; (from offset 0x0 to offset 0xFFD0)
138 // 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ; Reserved bytes
139 // 0, 0 ; Checksum Padding
160 CAP_INFO mCapDataInfo
;
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_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
;
216 // Read the FV File System Guid
218 if (!FvInfo
->FvFileSystemGuidSet
) {
219 Status
= FindToken (InfFile
, OPTIONS_SECTION_STRING
, EFI_FV_FILESYSTEMGUID_STRING
, 0, Value
);
220 if (Status
== EFI_SUCCESS
) {
222 // Get the guid value
224 Status
= StringToGuid (Value
, &GuidValue
);
225 if (EFI_ERROR (Status
)) {
226 Error (NULL
, 0, 2000, "Invalid parameter", "%s = %s", EFI_FV_FILESYSTEMGUID_STRING
, Value
);
229 memcpy (&FvInfo
->FvFileSystemGuid
, &GuidValue
, sizeof (EFI_GUID
));
230 FvInfo
->FvFileSystemGuidSet
= TRUE
;
235 // Read the FV Extension Header File Name
237 Status
= FindToken (InfFile
, ATTRIBUTES_SECTION_STRING
, EFI_FV_EXT_HEADER_FILE_NAME
, 0, Value
);
238 if (Status
== EFI_SUCCESS
) {
239 strcpy (FvInfo
->FvExtHeaderFile
, Value
);
243 // Read the FV file name
245 Status
= FindToken (InfFile
, OPTIONS_SECTION_STRING
, EFI_FV_FILE_NAME_STRING
, 0, Value
);
246 if (Status
== EFI_SUCCESS
) {
248 // copy the file name
250 strcpy (FvInfo
->FvName
, Value
);
256 for (Index
= 0; Index
< sizeof (mFvbAttributeName
)/sizeof (CHAR8
*); Index
++) {
257 if ((mFvbAttributeName
[Index
] != NULL
) && \
258 (FindToken (InfFile
, ATTRIBUTES_SECTION_STRING
, mFvbAttributeName
[Index
], 0, Value
) == EFI_SUCCESS
)) {
259 if ((strcmp (Value
, TRUE_STRING
) == 0) || (strcmp (Value
, ONE_STRING
) == 0)) {
260 FvInfo
->FvAttributes
|= 1 << Index
;
261 } else if ((strcmp (Value
, FALSE_STRING
) != 0) && (strcmp (Value
, ZERO_STRING
) != 0)) {
262 Error (NULL
, 0, 2000, "Invalid parameter", "%s expected %s | %s", mFvbAttributeName
[Index
], TRUE_STRING
, FALSE_STRING
);
271 for (Index
= 0; Index
< sizeof (mFvbAlignmentName
)/sizeof (CHAR8
*); Index
++) {
272 if (FindToken (InfFile
, ATTRIBUTES_SECTION_STRING
, mFvbAlignmentName
[Index
], 0, Value
) == EFI_SUCCESS
) {
273 if (strcmp (Value
, TRUE_STRING
) == 0) {
274 FvInfo
->FvAttributes
|= Index
<< 16;
275 DebugMsg (NULL
, 0, 9, "FV file alignment", "Align = %s", mFvbAlignmentName
[Index
]);
284 for (Index
= 0; Index
< MAX_NUMBER_OF_FV_BLOCKS
; Index
++) {
285 if (FvInfo
->FvBlocks
[Index
].Length
== 0) {
289 Status
= FindToken (InfFile
, OPTIONS_SECTION_STRING
, EFI_BLOCK_SIZE_STRING
, Index
, Value
);
291 if (Status
== EFI_SUCCESS
) {
293 // Update the size of block
295 Status
= AsciiStringToUint64 (Value
, FALSE
, &Value64
);
296 if (EFI_ERROR (Status
)) {
297 Error (NULL
, 0, 2000, "Invalid parameter", "%s = %s", EFI_BLOCK_SIZE_STRING
, Value
);
301 FvInfo
->FvBlocks
[Index
].Length
= (UINT32
) Value64
;
302 DebugMsg (NULL
, 0, 9, "FV Block Size", "%s = %s", EFI_BLOCK_SIZE_STRING
, Value
);
305 // If there is no blocks size, but there is the number of block, then we have a mismatched pair
306 // and should return an error.
308 Status
= FindToken (InfFile
, OPTIONS_SECTION_STRING
, EFI_NUM_BLOCKS_STRING
, Index
, Value
);
309 if (!EFI_ERROR (Status
)) {
310 Error (NULL
, 0, 2000, "Invalid parameter", "both %s and %s must be specified.", EFI_NUM_BLOCKS_STRING
, EFI_BLOCK_SIZE_STRING
);
321 // Read blocks number
323 Status
= FindToken (InfFile
, OPTIONS_SECTION_STRING
, EFI_NUM_BLOCKS_STRING
, Index
, Value
);
325 if (Status
== EFI_SUCCESS
) {
327 // Update the number of blocks
329 Status
= AsciiStringToUint64 (Value
, FALSE
, &Value64
);
330 if (EFI_ERROR (Status
)) {
331 Error (NULL
, 0, 2000, "Invalid parameter", "%s = %s", EFI_NUM_BLOCKS_STRING
, Value
);
335 FvInfo
->FvBlocks
[Index
].NumBlocks
= (UINT32
) Value64
;
336 DebugMsg (NULL
, 0, 9, "FV Block Number", "%s = %s", EFI_NUM_BLOCKS_STRING
, Value
);
342 Error (NULL
, 0, 2001, "Missing required argument", "block size.");
350 for (Number
= 0; Number
< MAX_NUMBER_OF_FILES_IN_FV
; Number
++) {
351 if (FvInfo
->FvFiles
[Number
][0] == '\0') {
356 for (Index
= 0; Index
< MAX_NUMBER_OF_FILES_IN_FV
; Index
++) {
358 // Read the FFS file list
360 Status
= FindToken (InfFile
, FILES_SECTION_STRING
, EFI_FILE_NAME_STRING
, Index
, Value
);
362 if (Status
== EFI_SUCCESS
) {
366 strcpy (FvInfo
->FvFiles
[Number
+ Index
], Value
);
367 DebugMsg (NULL
, 0, 9, "FV component file", "the %uth name is %s", (unsigned) Index
, Value
);
373 if ((Index
+ Number
) == 0) {
374 Warning (NULL
, 0, 0, "FV components are not specified.", NULL
);
382 IN EFI_FFS_FILE_HEADER
*FfsFile
,
383 IN EFI_FIRMWARE_VOLUME_HEADER
*FvHeader
389 This function changes the FFS file attributes based on the erase polarity
390 of the FV. Update the reserved bits of State to EFI_FVB2_ERASE_POLARITY.
403 if (FvHeader
->Attributes
& EFI_FVB2_ERASE_POLARITY
) {
404 FfsFile
->State
= (UINT8
)~(FfsFile
->State
);
405 // FfsFile->State |= ~(UINT8) EFI_FILE_ALL_STATE_BITS;
411 IN EFI_FFS_FILE_HEADER
*FfsFile
,
412 IN OUT UINT32
*Alignment
418 This function determines the alignment of the FFS input file from the file
423 FfsFile FFS file to parse
424 Alignment The minimum required alignment offset of the FFS file
428 EFI_SUCCESS The function completed successfully.
429 EFI_INVALID_PARAMETER One of the input parameters was invalid.
430 EFI_ABORTED An error occurred.
435 // Verify input parameters.
437 if (FfsFile
== NULL
|| Alignment
== NULL
) {
438 return EFI_INVALID_PARAMETER
;
441 switch ((FfsFile
->Attributes
>> 3) & 0x07) {
445 // 8 byte alignment, mini alignment requirement for FFS file.
459 // 128 byte alignment
466 // 512 byte alignment
487 // 32K byte alignment
494 // 64K byte alignment
508 IN OUT MEMORY_FILE
*FvImage
,
509 IN UINT32 DataAlignment
,
511 IN EFI_FIRMWARE_VOLUME_EXT_HEADER
*ExtHeader
517 This function adds a pad file to the FV image if it required to align the
518 data of the next file.
522 FvImage The memory image of the FV to add it to.
523 The current offset must be valid.
524 DataAlignment The data alignment of the next FFS file.
525 FvEnd End of the empty data in FvImage.
526 ExtHeader PI FvExtHeader Optional
530 EFI_SUCCESS The function completed successfully.
531 EFI_INVALID_PARAMETER One of the input parameters was invalid.
532 EFI_OUT_OF_RESOURCES Insufficient resources exist in the FV to complete
537 EFI_FFS_FILE_HEADER
*PadFile
;
541 // Verify input parameters.
543 if (FvImage
== NULL
) {
544 return EFI_INVALID_PARAMETER
;
548 // Check if a pad file is necessary
550 if ((ExtHeader
== NULL
) && (((UINTN
) FvImage
->CurrentFilePointer
- (UINTN
) FvImage
->FileImage
+ sizeof (EFI_FFS_FILE_HEADER
)) % DataAlignment
== 0)) {
555 // Calculate the pad file size
558 // This is the earliest possible valid offset (current plus pad file header
559 // plus the next file header)
561 PadFileSize
= (UINTN
) FvImage
->CurrentFilePointer
- (UINTN
) FvImage
->FileImage
+ (sizeof (EFI_FFS_FILE_HEADER
) * 2);
564 // Add whatever it takes to get to the next aligned address
566 while ((PadFileSize
% DataAlignment
) != 0) {
570 // Subtract the next file header size
572 PadFileSize
-= sizeof (EFI_FFS_FILE_HEADER
);
575 // Subtract the starting offset to get size
577 PadFileSize
-= (UINTN
) FvImage
->CurrentFilePointer
- (UINTN
) FvImage
->FileImage
;
580 // Append extension header size
582 if (ExtHeader
!= NULL
) {
583 PadFileSize
= PadFileSize
+ ExtHeader
->ExtHeaderSize
;
587 // Verify that we have enough space for the file header
589 if (((UINTN
) FvImage
->CurrentFilePointer
+ PadFileSize
) > (UINTN
) FvEnd
) {
590 return EFI_OUT_OF_RESOURCES
;
594 // Write pad file header
596 PadFile
= (EFI_FFS_FILE_HEADER
*) FvImage
->CurrentFilePointer
;
599 // Write PadFile FFS header with PadType, don't need to set PAD file guid in its header.
601 PadFile
->Type
= EFI_FV_FILETYPE_FFS_PAD
;
602 PadFile
->Attributes
= 0;
605 // Write pad file size (calculated size minus next file header size)
607 PadFile
->Size
[0] = (UINT8
) (PadFileSize
& 0xFF);
608 PadFile
->Size
[1] = (UINT8
) ((PadFileSize
>> 8) & 0xFF);
609 PadFile
->Size
[2] = (UINT8
) ((PadFileSize
>> 16) & 0xFF);
612 // Fill in checksums and state, they must be 0 for checksumming.
614 PadFile
->IntegrityCheck
.Checksum
.Header
= 0;
615 PadFile
->IntegrityCheck
.Checksum
.File
= 0;
617 PadFile
->IntegrityCheck
.Checksum
.Header
= CalculateChecksum8 ((UINT8
*) PadFile
, sizeof (EFI_FFS_FILE_HEADER
));
618 PadFile
->IntegrityCheck
.Checksum
.File
= FFS_FIXED_CHECKSUM
;
620 PadFile
->State
= EFI_FILE_HEADER_CONSTRUCTION
| EFI_FILE_HEADER_VALID
| EFI_FILE_DATA_VALID
;
622 (EFI_FFS_FILE_HEADER
*) PadFile
,
623 (EFI_FIRMWARE_VOLUME_HEADER
*) FvImage
->FileImage
627 // Update the current FV pointer
629 FvImage
->CurrentFilePointer
+= PadFileSize
;
631 if (ExtHeader
!= NULL
) {
633 // Copy Fv Extension Header and Set Fv Extension header offset
635 memcpy (PadFile
+ 1, ExtHeader
, ExtHeader
->ExtHeaderSize
);
636 ((EFI_FIRMWARE_VOLUME_HEADER
*) FvImage
->FileImage
)->ExtHeaderOffset
= (UINT16
) ((UINTN
) (PadFile
+ 1) - (UINTN
) FvImage
->FileImage
);
638 // Make next file start at QWord Boundry
640 while (((UINTN
) FvImage
->CurrentFilePointer
& (EFI_FFS_FILE_HEADER_ALIGNMENT
- 1)) != 0) {
641 FvImage
->CurrentFilePointer
++;
650 IN EFI_FFS_FILE_HEADER
*FileBuffer
656 This function checks the header to validate if it is a VTF file
660 FileBuffer Buffer in which content of a file has been read.
664 TRUE If this is a VTF file
665 FALSE If this is not a VTF file
669 if (!memcmp (&FileBuffer
->Name
, &mEfiFirmwareVolumeTopFileGuid
, sizeof (EFI_GUID
))) {
678 IN OUT
FILE *FvMapFile
,
680 IN EFI_GUID
*FileGuidPtr
,
681 IN EFI_PHYSICAL_ADDRESS ImageBaseAddress
,
682 IN PE_COFF_LOADER_IMAGE_CONTEXT
*pImageContext
688 This function gets the basic debug information (entrypoint, baseaddress, .text, .data section base address)
689 from PE/COFF image and abstracts Pe Map file information and add them into FvMap file for Debug.
693 FvMapFile A pointer to FvMap File
694 FileName Ffs File PathName
695 FileGuidPtr Guid Value of Ffs file
696 ImageBaseAddress PeImage Base Address.
697 pImageContext Image Context Information.
701 EFI_SUCCESS Added required map information.
705 CHAR8 PeMapFileName
[_MAX_PATH
];
707 CHAR8 FileGuidName
[MAX_LINE_LEN
];
709 CHAR8 Line
[MAX_LINE_LEN
];
710 CHAR8 KeyWord
[MAX_LINE_LEN
];
711 CHAR8 FunctionName
[MAX_LINE_LEN
];
712 EFI_PHYSICAL_ADDRESS FunctionAddress
;
714 CHAR8 FunctionTypeName
[MAX_LINE_LEN
];
716 UINT32 AddressOfEntryPoint
;
718 EFI_IMAGE_OPTIONAL_HEADER_UNION
*ImgHdr
;
719 EFI_TE_IMAGE_HEADER
*TEImageHeader
;
720 EFI_IMAGE_SECTION_HEADER
*SectionHeader
;
721 unsigned long long TempLongAddress
;
722 UINT32 TextVirtualAddress
;
723 UINT32 DataVirtualAddress
;
724 EFI_PHYSICAL_ADDRESS LinkTimeBaseAddress
;
728 // Init local variable
732 // Print FileGuid to string buffer.
734 PrintGuidToBuffer (FileGuidPtr
, (UINT8
*)FileGuidName
, MAX_LINE_LEN
, TRUE
);
737 // Construct Map file Name
739 strcpy (PeMapFileName
, FileName
);
742 // Change '\\' to '/', unified path format.
744 Cptr
= PeMapFileName
;
745 while (*Cptr
!= '\0') {
747 *Cptr
= FILE_SEP_CHAR
;
755 Cptr
= PeMapFileName
+ strlen (PeMapFileName
);
756 while ((*Cptr
!= '.') && (Cptr
>= PeMapFileName
)) {
759 if (Cptr
< PeMapFileName
) {
760 return EFI_NOT_FOUND
;
772 while ((*Cptr
!= FILE_SEP_CHAR
) && (Cptr
>= PeMapFileName
)) {
776 strcpy (KeyWord
, Cptr
+ 1);
780 // AddressOfEntryPoint and Offset in Image
782 if (!pImageContext
->IsTeImage
) {
783 ImgHdr
= (EFI_IMAGE_OPTIONAL_HEADER_UNION
*) ((UINT8
*) pImageContext
->Handle
+ pImageContext
->PeCoffHeaderOffset
);
784 AddressOfEntryPoint
= ImgHdr
->Pe32
.OptionalHeader
.AddressOfEntryPoint
;
786 SectionHeader
= (EFI_IMAGE_SECTION_HEADER
*) (
789 sizeof (EFI_IMAGE_FILE_HEADER
) +
790 ImgHdr
->Pe32
.FileHeader
.SizeOfOptionalHeader
792 Index
= ImgHdr
->Pe32
.FileHeader
.NumberOfSections
;
794 TEImageHeader
= (EFI_TE_IMAGE_HEADER
*) pImageContext
->Handle
;
795 AddressOfEntryPoint
= TEImageHeader
->AddressOfEntryPoint
;
796 Offset
= TEImageHeader
->StrippedSize
- sizeof (EFI_TE_IMAGE_HEADER
);
797 SectionHeader
= (EFI_IMAGE_SECTION_HEADER
*) (TEImageHeader
+ 1);
798 Index
= TEImageHeader
->NumberOfSections
;
802 // module information output
804 if (ImageBaseAddress
== 0) {
805 fprintf (FvMapFile
, "%s (dummy) (", KeyWord
);
806 fprintf (FvMapFile
, "BaseAddress=%010llx, ", (unsigned long long) ImageBaseAddress
);
808 fprintf (FvMapFile
, "%s (Fixed Flash Address, ", KeyWord
);
809 fprintf (FvMapFile
, "BaseAddress=0x%010llx, ", (unsigned long long) (ImageBaseAddress
+ Offset
));
811 fprintf (FvMapFile
, "EntryPoint=0x%010llx", (unsigned long long) (ImageBaseAddress
+ AddressOfEntryPoint
));
812 fprintf (FvMapFile
, ")\n");
814 fprintf (FvMapFile
, "(GUID=%s", FileGuidName
);
815 TextVirtualAddress
= 0;
816 DataVirtualAddress
= 0;
817 for (; Index
> 0; Index
--, SectionHeader
++) {
818 if (stricmp ((CHAR8
*)SectionHeader
->Name
, ".text") == 0) {
819 TextVirtualAddress
= SectionHeader
->VirtualAddress
;
820 } else if (stricmp ((CHAR8
*)SectionHeader
->Name
, ".data") == 0) {
821 DataVirtualAddress
= SectionHeader
->VirtualAddress
;
822 } else if (stricmp ((CHAR8
*)SectionHeader
->Name
, ".sdata") == 0) {
823 DataVirtualAddress
= SectionHeader
->VirtualAddress
;
826 fprintf (FvMapFile
, " .textbaseaddress=0x%010llx", (unsigned long long) (ImageBaseAddress
+ TextVirtualAddress
));
827 fprintf (FvMapFile
, " .databaseaddress=0x%010llx", (unsigned long long) (ImageBaseAddress
+ DataVirtualAddress
));
828 fprintf (FvMapFile
, ")\n\n");
833 PeMapFile
= fopen (PeMapFileName
, "r");
834 if (PeMapFile
== NULL
) {
835 // fprintf (stdout, "can't open %s file to reading\n", PeMapFileName);
838 VerboseMsg ("The map file is %s", PeMapFileName
);
841 // Output Functions information into Fv Map file
843 LinkTimeBaseAddress
= 0;
844 while (fgets (Line
, MAX_LINE_LEN
, PeMapFile
) != NULL
) {
848 if (Line
[0] == 0x0a) {
853 // By Address and Static keyword
855 if (FunctionType
== 0) {
856 sscanf (Line
, "%s", KeyWord
);
857 if (stricmp (KeyWord
, "Address") == 0) {
862 fgets (Line
, MAX_LINE_LEN
, PeMapFile
);
863 } else if (stricmp (KeyWord
, "Static") == 0) {
865 // static function list
868 fgets (Line
, MAX_LINE_LEN
, PeMapFile
);
869 } else if (stricmp (KeyWord
, "Preferred") ==0) {
870 sscanf (Line
+ strlen (" Preferred load address is"), "%llx", &TempLongAddress
);
871 LinkTimeBaseAddress
= (UINT64
) TempLongAddress
;
876 // Printf Function Information
878 if (FunctionType
== 1) {
879 sscanf (Line
, "%s %s %llx %s", KeyWord
, FunctionName
, &TempLongAddress
, FunctionTypeName
);
880 FunctionAddress
= (UINT64
) TempLongAddress
;
881 if (FunctionTypeName
[1] == '\0' && (FunctionTypeName
[0] == 'f' || FunctionTypeName
[0] == 'F')) {
882 fprintf (FvMapFile
, " 0x%010llx ", (unsigned long long) (ImageBaseAddress
+ FunctionAddress
- LinkTimeBaseAddress
));
883 fprintf (FvMapFile
, "%s\n", FunctionName
);
885 } else if (FunctionType
== 2) {
886 sscanf (Line
, "%s %s %llx %s", KeyWord
, FunctionName
, &TempLongAddress
, FunctionTypeName
);
887 FunctionAddress
= (UINT64
) TempLongAddress
;
888 if (FunctionTypeName
[1] == '\0' && (FunctionTypeName
[0] == 'f' || FunctionTypeName
[0] == 'F')) {
889 fprintf (FvMapFile
, " 0x%010llx ", (unsigned long long) (ImageBaseAddress
+ FunctionAddress
- LinkTimeBaseAddress
));
890 fprintf (FvMapFile
, "%s\n", FunctionName
);
897 fprintf (FvMapFile
, "\n\n");
905 IN OUT MEMORY_FILE
*FvImage
,
908 IN OUT EFI_FFS_FILE_HEADER
**VtfFileImage
,
910 IN
FILE *FvReportFile
916 This function adds a file to the FV image. The file will pad to the
917 appropriate alignment if required.
921 FvImage The memory image of the FV to add it to. The current offset
923 FvInfo Pointer to information about the FV.
924 Index The file in the FvInfo file list to add.
925 VtfFileImage A pointer to the VTF file within the FvImage. If this is equal
926 to the end of the FvImage then no VTF previously found.
927 FvMapFile Pointer to FvMap File
928 FvReportFile Pointer to FvReport File
932 EFI_SUCCESS The function completed successfully.
933 EFI_INVALID_PARAMETER One of the input parameters was invalid.
934 EFI_ABORTED An error occurred.
935 EFI_OUT_OF_RESOURCES Insufficient resources exist to complete the add.
943 UINT32 CurrentFileAlignment
;
946 UINT8 FileGuidString
[PRINTED_GUID_BUFFER_SIZE
];
950 // Verify input parameters.
952 if (FvImage
== NULL
|| FvInfo
== NULL
|| FvInfo
->FvFiles
[Index
][0] == 0 || VtfFileImage
== NULL
) {
953 return EFI_INVALID_PARAMETER
;
957 // Read the file to add
959 NewFile
= fopen (FvInfo
->FvFiles
[Index
], "rb");
961 if (NewFile
== NULL
) {
962 Error (NULL
, 0, 0001, "Error opening file", FvInfo
->FvFiles
[Index
]);
969 FileSize
= _filelength (fileno (NewFile
));
972 // Read the file into a buffer
974 FileBuffer
= malloc (FileSize
);
975 if (FileBuffer
== NULL
) {
976 Error (NULL
, 0, 4001, "Resouce", "memory cannot be allocated!");
977 return EFI_OUT_OF_RESOURCES
;
980 NumBytesRead
= fread (FileBuffer
, sizeof (UINT8
), FileSize
, NewFile
);
983 // Done with the file, from this point on we will just use the buffer read.
988 // Verify read successful
990 if (NumBytesRead
!= sizeof (UINT8
) * FileSize
) {
992 Error (NULL
, 0, 0004, "Error reading file", FvInfo
->FvFiles
[Index
]);
997 // For None PI Ffs file, directly add them into FvImage.
999 if (!FvInfo
->IsPiFvImage
) {
1000 memcpy (FvImage
->CurrentFilePointer
, FileBuffer
, FileSize
);
1001 if (FvInfo
->SizeofFvFiles
[Index
] > FileSize
) {
1002 FvImage
->CurrentFilePointer
+= FvInfo
->SizeofFvFiles
[Index
];
1004 FvImage
->CurrentFilePointer
+= FileSize
;
1012 Status
= VerifyFfsFile ((EFI_FFS_FILE_HEADER
*)FileBuffer
);
1013 if (EFI_ERROR (Status
)) {
1015 Error (NULL
, 0, 3000, "Invalid", "%s is a FFS file.", FvInfo
->FvFiles
[Index
]);
1016 return EFI_INVALID_PARAMETER
;
1020 // Verify space exists to add the file
1022 if (FileSize
> (UINTN
) ((UINTN
) *VtfFileImage
- (UINTN
) FvImage
->CurrentFilePointer
)) {
1024 Error (NULL
, 0, 4002, "Resource", "FV space is full, not enough room to add file %s.", FvInfo
->FvFiles
[Index
]);
1025 return EFI_OUT_OF_RESOURCES
;
1029 // Verify the input file is the duplicated file in this Fv image
1031 for (Index1
= 0; Index1
< Index
; Index1
++) {
1032 if (CompareGuid ((EFI_GUID
*) FileBuffer
, &mFileGuidArray
[Index1
]) == 0) {
1033 Error (NULL
, 0, 2000, "Invalid parameter", "the %dth file and %uth file have the same file GUID.", (unsigned) Index1
+ 1, (unsigned) Index
+ 1);
1034 PrintGuid ((EFI_GUID
*) FileBuffer
);
1035 return EFI_INVALID_PARAMETER
;
1038 CopyMem (&mFileGuidArray
[Index
], FileBuffer
, sizeof (EFI_GUID
));
1041 // Update the file state based on polarity of the FV.
1043 UpdateFfsFileState (
1044 (EFI_FFS_FILE_HEADER
*) FileBuffer
,
1045 (EFI_FIRMWARE_VOLUME_HEADER
*) FvImage
->FileImage
1049 // Check if alignment is required
1051 ReadFfsAlignment ((EFI_FFS_FILE_HEADER
*) FileBuffer
, &CurrentFileAlignment
);
1054 // Find the largest alignment of all the FFS files in the FV
1056 if (CurrentFileAlignment
> MaxFfsAlignment
) {
1057 MaxFfsAlignment
= CurrentFileAlignment
;
1060 // If we have a VTF file, add it at the top.
1062 if (IsVtfFile ((EFI_FFS_FILE_HEADER
*) FileBuffer
)) {
1063 if ((UINTN
) *VtfFileImage
== (UINTN
) FvImage
->Eof
) {
1065 // No previous VTF, add this one.
1067 *VtfFileImage
= (EFI_FFS_FILE_HEADER
*) (UINTN
) ((UINTN
) FvImage
->FileImage
+ FvInfo
->Size
- FileSize
);
1069 // Sanity check. The file MUST align appropriately
1071 if (((UINTN
) *VtfFileImage
+ sizeof (EFI_FFS_FILE_HEADER
) - (UINTN
) FvImage
->FileImage
) % (1 << CurrentFileAlignment
)) {
1072 Error (NULL
, 0, 3000, "Invalid", "VTF file cannot be aligned on a %u-byte boundary.", (unsigned) (1 << CurrentFileAlignment
));
1077 // Rebase the PE or TE image in FileBuffer of FFS file for XIP
1078 // Rebase for the debug genfvmap tool
1080 FfsRebase (FvInfo
, FvInfo
->FvFiles
[Index
], (EFI_FFS_FILE_HEADER
*) FileBuffer
, (UINTN
) *VtfFileImage
- (UINTN
) FvImage
->FileImage
, FvMapFile
);
1084 memcpy (*VtfFileImage
, FileBuffer
, FileSize
);
1086 PrintGuidToBuffer ((EFI_GUID
*) FileBuffer
, FileGuidString
, sizeof (FileGuidString
), TRUE
);
1087 fprintf (FvReportFile
, "0x%08X %s\n", (unsigned)(UINTN
) (((UINT8
*)*VtfFileImage
) - (UINTN
)FvImage
->FileImage
), FileGuidString
);
1090 DebugMsg (NULL
, 0, 9, "Add VTF FFS file in FV image", NULL
);
1094 // Already found a VTF file.
1096 Error (NULL
, 0, 3000, "Invalid", "multiple VTF files are not permitted within a single FV.");
1103 // Add pad file if necessary
1105 Status
= AddPadFile (FvImage
, 1 << CurrentFileAlignment
, *VtfFileImage
, NULL
);
1106 if (EFI_ERROR (Status
)) {
1107 Error (NULL
, 0, 4002, "Resource", "FV space is full, could not add pad file for data alignment property.");
1114 if ((UINTN
) (FvImage
->CurrentFilePointer
+ FileSize
) <= (UINTN
) (*VtfFileImage
)) {
1116 // Rebase the PE or TE image in FileBuffer of FFS file for XIP.
1117 // Rebase Bs and Rt drivers for the debug genfvmap tool.
1119 FfsRebase (FvInfo
, FvInfo
->FvFiles
[Index
], (EFI_FFS_FILE_HEADER
*) FileBuffer
, (UINTN
) FvImage
->CurrentFilePointer
- (UINTN
) FvImage
->FileImage
, FvMapFile
);
1123 memcpy (FvImage
->CurrentFilePointer
, FileBuffer
, FileSize
);
1124 PrintGuidToBuffer ((EFI_GUID
*) FileBuffer
, FileGuidString
, sizeof (FileGuidString
), TRUE
);
1125 fprintf (FvReportFile
, "0x%08X %s\n", (unsigned) (FvImage
->CurrentFilePointer
- FvImage
->FileImage
), FileGuidString
);
1126 FvImage
->CurrentFilePointer
+= FileSize
;
1128 Error (NULL
, 0, 4002, "Resource", "FV space is full, cannot add file %s.", FvInfo
->FvFiles
[Index
]);
1133 // Make next file start at QWord Boundry
1135 while (((UINTN
) FvImage
->CurrentFilePointer
& (EFI_FFS_FILE_HEADER_ALIGNMENT
- 1)) != 0) {
1136 FvImage
->CurrentFilePointer
++;
1141 // Free allocated memory.
1150 IN MEMORY_FILE
*FvImage
,
1151 IN EFI_FFS_FILE_HEADER
*VtfFileImage
1155 Routine Description:
1157 This function places a pad file between the last file in the FV and the VTF
1158 file if the VTF file exists.
1162 FvImage Memory file for the FV memory image
1163 VtfFileImage The address of the VTF file. If this is the end of the FV
1164 image, no VTF exists and no pad file is needed.
1168 EFI_SUCCESS Completed successfully.
1169 EFI_INVALID_PARAMETER One of the input parameters was NULL.
1173 EFI_FFS_FILE_HEADER
*PadFile
;
1177 // If there is no VTF or the VTF naturally follows the previous file without a
1178 // pad file, then there's nothing to do
1180 if ((UINTN
) VtfFileImage
== (UINTN
) FvImage
->Eof
|| \
1181 ((UINTN
) VtfFileImage
== (UINTN
) FvImage
->CurrentFilePointer
)) {
1185 if ((UINTN
) VtfFileImage
< (UINTN
) FvImage
->CurrentFilePointer
) {
1186 return EFI_INVALID_PARAMETER
;
1190 // Pad file starts at beginning of free space
1192 PadFile
= (EFI_FFS_FILE_HEADER
*) FvImage
->CurrentFilePointer
;
1195 // write PadFile FFS header with PadType, don't need to set PAD file guid in its header.
1197 PadFile
->Type
= EFI_FV_FILETYPE_FFS_PAD
;
1198 PadFile
->Attributes
= 0;
1201 // FileSize includes the EFI_FFS_FILE_HEADER
1203 FileSize
= (UINTN
) VtfFileImage
- (UINTN
) FvImage
->CurrentFilePointer
;
1204 PadFile
->Size
[0] = (UINT8
) (FileSize
& 0x000000FF);
1205 PadFile
->Size
[1] = (UINT8
) ((FileSize
& 0x0000FF00) >> 8);
1206 PadFile
->Size
[2] = (UINT8
) ((FileSize
& 0x00FF0000) >> 16);
1209 // Fill in checksums and state, must be zero during checksum calculation.
1211 PadFile
->IntegrityCheck
.Checksum
.Header
= 0;
1212 PadFile
->IntegrityCheck
.Checksum
.File
= 0;
1214 PadFile
->IntegrityCheck
.Checksum
.Header
= CalculateChecksum8 ((UINT8
*) PadFile
, sizeof (EFI_FFS_FILE_HEADER
));
1215 PadFile
->IntegrityCheck
.Checksum
.File
= FFS_FIXED_CHECKSUM
;
1217 PadFile
->State
= EFI_FILE_HEADER_CONSTRUCTION
| EFI_FILE_HEADER_VALID
| EFI_FILE_DATA_VALID
;
1219 UpdateFfsFileState (
1220 (EFI_FFS_FILE_HEADER
*) PadFile
,
1221 (EFI_FIRMWARE_VOLUME_HEADER
*) FvImage
->FileImage
1224 // Update the current FV pointer
1226 FvImage
->CurrentFilePointer
= FvImage
->Eof
;
1233 IN MEMORY_FILE
*FvImage
,
1235 IN EFI_FFS_FILE_HEADER
*VtfFile
1239 Routine Description:
1241 This parses the FV looking for the PEI core and then plugs the address into
1242 the SALE_ENTRY point of the BSF/VTF for IPF and does BUGBUG TBD action to
1243 complete an IA32 Bootstrap FV.
1247 FvImage Memory file for the FV memory image
1248 FvInfo Information read from INF file.
1249 VtfFile Pointer to the VTF file in the FV image.
1253 EFI_SUCCESS Function Completed successfully.
1254 EFI_ABORTED Error encountered.
1255 EFI_INVALID_PARAMETER A required parameter was NULL.
1256 EFI_NOT_FOUND PEI Core file not found.
1260 EFI_FFS_FILE_HEADER
*PeiCoreFile
;
1261 EFI_FFS_FILE_HEADER
*SecCoreFile
;
1263 EFI_FILE_SECTION_POINTER Pe32Section
;
1267 EFI_PHYSICAL_ADDRESS PeiCorePhysicalAddress
;
1268 EFI_PHYSICAL_ADDRESS SecCorePhysicalAddress
;
1269 EFI_PHYSICAL_ADDRESS
*SecCoreEntryAddressPtr
;
1270 INT32 Ia32SecEntryOffset
;
1271 UINT32
*Ia32ResetAddressPtr
;
1273 UINT8
*BytePointer2
;
1274 UINT16
*WordPointer
;
1278 EFI_FFS_FILE_STATE SavedState
;
1280 FIT_TABLE
*FitTablePtr
;
1281 BOOLEAN Vtf0Detected
;
1284 // Verify input parameters
1286 if (FvImage
== NULL
|| FvInfo
== NULL
|| VtfFile
== NULL
) {
1287 return EFI_INVALID_PARAMETER
;
1290 // Initialize FV library
1292 InitializeFvLib (FvImage
->FileImage
, FvInfo
->Size
);
1297 Status
= VerifyFfsFile (VtfFile
);
1298 if (EFI_ERROR (Status
)) {
1299 return EFI_INVALID_PARAMETER
;
1303 (((UINTN
)FvImage
->Eof
- (UINTN
)FvImage
->FileImage
) >=
1304 IA32_X64_VTF_SIGNATURE_OFFSET
) &&
1305 (*(UINT32
*)(VOID
*)((UINTN
) FvImage
->Eof
-
1306 IA32_X64_VTF_SIGNATURE_OFFSET
) ==
1307 IA32_X64_VTF0_SIGNATURE
)
1309 Vtf0Detected
= TRUE
;
1311 Vtf0Detected
= FALSE
;
1315 // Find the Sec Core
1317 Status
= GetFileByType (EFI_FV_FILETYPE_SECURITY_CORE
, 1, &SecCoreFile
);
1318 if (EFI_ERROR (Status
) || SecCoreFile
== NULL
) {
1321 // If the SEC core file is not found, but the VTF-0 signature
1322 // is found, we'll treat it as a VTF-0 'Volume Top File'.
1323 // This means no modifications are required to the VTF.
1328 Error (NULL
, 0, 3000, "Invalid", "could not find the SEC core file in the FV.");
1332 // Sec Core found, now find PE32 section
1334 Status
= GetSectionByType (SecCoreFile
, EFI_SECTION_PE32
, 1, &Pe32Section
);
1335 if (Status
== EFI_NOT_FOUND
) {
1336 Status
= GetSectionByType (SecCoreFile
, EFI_SECTION_TE
, 1, &Pe32Section
);
1339 if (EFI_ERROR (Status
)) {
1340 Error (NULL
, 0, 3000, "Invalid", "could not find a PE32 section in the SEC core file.");
1344 Status
= GetPe32Info (
1345 (VOID
*) ((UINTN
) Pe32Section
.Pe32Section
+ sizeof (EFI_SECTION_PE32
)),
1351 if (EFI_ERROR (Status
)) {
1352 Error (NULL
, 0, 3000, "Invalid", "could not get the PE32 entry point for the SEC core.");
1358 (MachineType
== EFI_IMAGE_MACHINE_IA32
||
1359 MachineType
== EFI_IMAGE_MACHINE_X64
)
1362 // If the SEC core code is IA32 or X64 and the VTF-0 signature
1363 // is found, we'll treat it as a VTF-0 'Volume Top File'.
1364 // This means no modifications are required to the VTF.
1370 // Physical address is FV base + offset of PE32 + offset of the entry point
1372 SecCorePhysicalAddress
= FvInfo
->BaseAddress
;
1373 SecCorePhysicalAddress
+= (UINTN
) Pe32Section
.Pe32Section
+ sizeof (EFI_SECTION_PE32
) - (UINTN
) FvImage
->FileImage
;
1374 SecCorePhysicalAddress
+= EntryPoint
;
1375 DebugMsg (NULL
, 0, 9, "SecCore physical entry point address", "Address = 0x%llX", (unsigned long long) SecCorePhysicalAddress
);
1378 // Find the PEI Core
1380 Status
= GetFileByType (EFI_FV_FILETYPE_PEI_CORE
, 1, &PeiCoreFile
);
1381 if (EFI_ERROR (Status
) || PeiCoreFile
== NULL
) {
1382 Error (NULL
, 0, 3000, "Invalid", "could not find the PEI core in the FV.");
1386 // PEI Core found, now find PE32 or TE section
1388 Status
= GetSectionByType (PeiCoreFile
, EFI_SECTION_PE32
, 1, &Pe32Section
);
1389 if (Status
== EFI_NOT_FOUND
) {
1390 Status
= GetSectionByType (PeiCoreFile
, EFI_SECTION_TE
, 1, &Pe32Section
);
1393 if (EFI_ERROR (Status
)) {
1394 Error (NULL
, 0, 3000, "Invalid", "could not find either a PE32 or a TE section in PEI core file.");
1398 Status
= GetPe32Info (
1399 (VOID
*) ((UINTN
) Pe32Section
.Pe32Section
+ sizeof (EFI_SECTION_PE32
)),
1405 if (EFI_ERROR (Status
)) {
1406 Error (NULL
, 0, 3000, "Invalid", "could not get the PE32 entry point for the PEI core.");
1410 // Physical address is FV base + offset of PE32 + offset of the entry point
1412 PeiCorePhysicalAddress
= FvInfo
->BaseAddress
;
1413 PeiCorePhysicalAddress
+= (UINTN
) Pe32Section
.Pe32Section
+ sizeof (EFI_SECTION_PE32
) - (UINTN
) FvImage
->FileImage
;
1414 PeiCorePhysicalAddress
+= EntryPoint
;
1415 DebugMsg (NULL
, 0, 9, "PeiCore physical entry point address", "Address = 0x%llX", (unsigned long long) PeiCorePhysicalAddress
);
1417 if (MachineType
== EFI_IMAGE_MACHINE_IA64
) {
1419 // Update PEI_CORE address
1422 // Set the uncached attribute bit in the physical address
1424 PeiCorePhysicalAddress
|= 0x8000000000000000ULL
;
1427 // Check if address is aligned on a 16 byte boundary
1429 if (PeiCorePhysicalAddress
& 0xF) {
1430 Error (NULL
, 0, 3000, "Invalid",
1431 "PEI_CORE entry point is not aligned on a 16 byte boundary, address specified is %llXh.",
1432 (unsigned long long) PeiCorePhysicalAddress
1437 // First Get the FIT table address
1439 FitAddress
= (*(UINT64
*) (FvImage
->Eof
- IPF_FIT_ADDRESS_OFFSET
)) & 0xFFFFFFFF;
1441 FitTablePtr
= (FIT_TABLE
*) (FvImage
->FileImage
+ (FitAddress
- FvInfo
->BaseAddress
));
1443 Status
= UpdatePeiCoreEntryInFit (FitTablePtr
, PeiCorePhysicalAddress
);
1445 if (!EFI_ERROR (Status
)) {
1446 UpdateFitCheckSum (FitTablePtr
);
1450 // Update SEC_CORE address
1453 // Set the uncached attribute bit in the physical address
1455 SecCorePhysicalAddress
|= 0x8000000000000000ULL
;
1457 // Check if address is aligned on a 16 byte boundary
1459 if (SecCorePhysicalAddress
& 0xF) {
1460 Error (NULL
, 0, 3000, "Invalid",
1461 "SALE_ENTRY entry point is not aligned on a 16 byte boundary, address specified is %llXh.",
1462 (unsigned long long) SecCorePhysicalAddress
1467 // Update the address
1469 SecCoreEntryAddressPtr
= (EFI_PHYSICAL_ADDRESS
*) ((UINTN
) FvImage
->Eof
- IPF_SALE_ENTRY_ADDRESS_OFFSET
);
1470 *SecCoreEntryAddressPtr
= SecCorePhysicalAddress
;
1472 } else if (MachineType
== EFI_IMAGE_MACHINE_IA32
|| MachineType
== EFI_IMAGE_MACHINE_X64
) {
1474 // Get the location to update
1476 Ia32ResetAddressPtr
= (UINT32
*) ((UINTN
) FvImage
->Eof
- IA32_PEI_CORE_ENTRY_OFFSET
);
1479 // Write lower 32 bits of physical address for Pei Core entry
1481 *Ia32ResetAddressPtr
= (UINT32
) PeiCorePhysicalAddress
;
1484 // Write SecCore Entry point relative address into the jmp instruction in reset vector.
1486 Ia32ResetAddressPtr
= (UINT32
*) ((UINTN
) FvImage
->Eof
- IA32_SEC_CORE_ENTRY_OFFSET
);
1488 Ia32SecEntryOffset
= (INT32
) (SecCorePhysicalAddress
- (FV_IMAGES_TOP_ADDRESS
- IA32_SEC_CORE_ENTRY_OFFSET
+ 2));
1489 if (Ia32SecEntryOffset
<= -65536) {
1490 Error (NULL
, 0, 3000, "Invalid", "The SEC EXE file size is too large, it must be less than 64K.");
1491 return STATUS_ERROR
;
1494 *(UINT16
*) Ia32ResetAddressPtr
= (UINT16
) Ia32SecEntryOffset
;
1497 // Update the BFV base address
1499 Ia32ResetAddressPtr
= (UINT32
*) ((UINTN
) FvImage
->Eof
- 4);
1500 *Ia32ResetAddressPtr
= (UINT32
) (FvInfo
->BaseAddress
);
1501 DebugMsg (NULL
, 0, 9, "update BFV base address in the top FV image", "BFV base address = 0x%llX.", (unsigned long long) FvInfo
->BaseAddress
);
1504 // Update the Startup AP in the FVH header block ZeroVector region.
1506 BytePointer
= (UINT8
*) ((UINTN
) FvImage
->FileImage
);
1507 if (FvInfo
->Size
<= 0x10000) {
1508 BytePointer2
= m64kRecoveryStartupApDataArray
;
1509 } else if (FvInfo
->Size
<= 0x20000) {
1510 BytePointer2
= m128kRecoveryStartupApDataArray
;
1512 BytePointer2
= m128kRecoveryStartupApDataArray
;
1514 // Find the position to place Ap reset vector, the offset
1515 // between the position and the end of Fvrecovery.fv file
1516 // should not exceed 128kB to prevent Ap reset vector from
1517 // outside legacy E and F segment
1519 Status
= FindApResetVectorPosition (FvImage
, &BytePointer
);
1520 if (EFI_ERROR (Status
)) {
1521 Error (NULL
, 0, 3000, "Invalid", "Cannot find the appropriate location in FvImage to add Ap reset vector!");
1526 for (Index
= 0; Index
< SIZEOF_STARTUP_DATA_ARRAY
; Index
++) {
1527 BytePointer
[Index
] = BytePointer2
[Index
];
1530 // Calculate the checksum
1533 WordPointer
= (UINT16
*) (BytePointer
);
1534 for (Index
= 0; Index
< SIZEOF_STARTUP_DATA_ARRAY
/ 2; Index
++) {
1535 CheckSum
= (UINT16
) (CheckSum
+ ((UINT16
) *WordPointer
));
1539 // Update the checksum field
1541 WordPointer
= (UINT16
*) (BytePointer
+ SIZEOF_STARTUP_DATA_ARRAY
- 2);
1542 *WordPointer
= (UINT16
) (0x10000 - (UINT32
) CheckSum
);
1545 // IpiVector at the 4k aligned address in the top 2 blocks in the PEI FV.
1547 IpiVector
= (UINT32
) (FV_IMAGES_TOP_ADDRESS
- ((UINTN
) FvImage
->Eof
- (UINTN
) BytePointer
));
1548 DebugMsg (NULL
, 0, 9, "Startup AP Vector address", "IpiVector at 0x%X", (unsigned) IpiVector
);
1549 if ((IpiVector
& 0xFFF) != 0) {
1550 Error (NULL
, 0, 3000, "Invalid", "Startup AP Vector address are not 4K aligned, because the FV size is not 4K aligned");
1553 IpiVector
= IpiVector
>> 12;
1554 IpiVector
= IpiVector
& 0xFF;
1557 // Write IPI Vector at Offset FvrecoveryFileSize - 8
1559 Ia32ResetAddressPtr
= (UINT32
*) ((UINTN
) FvImage
->Eof
- 8);
1560 *Ia32ResetAddressPtr
= IpiVector
;
1561 } else if (MachineType
== EFI_IMAGE_MACHINE_ARMT
) {
1563 // Since the ARM reset vector is in the FV Header you really don't need a
1564 // Volume Top File, but if you have one for some reason don't crash...
1567 Error (NULL
, 0, 3000, "Invalid", "machine type=0x%X in PEI core.", MachineType
);
1572 // Now update file checksum
1574 SavedState
= VtfFile
->State
;
1575 VtfFile
->IntegrityCheck
.Checksum
.File
= 0;
1577 if (VtfFile
->Attributes
& FFS_ATTRIB_CHECKSUM
) {
1578 VtfFile
->IntegrityCheck
.Checksum
.File
= CalculateChecksum8 (
1579 (UINT8
*) (VtfFile
+ 1),
1580 GetLength (VtfFile
->Size
) - sizeof (EFI_FFS_FILE_HEADER
)
1583 VtfFile
->IntegrityCheck
.Checksum
.File
= FFS_FIXED_CHECKSUM
;
1586 VtfFile
->State
= SavedState
;
1593 UpdateArmResetVectorIfNeeded (
1594 IN MEMORY_FILE
*FvImage
,
1599 Routine Description:
1600 This parses the FV looking for SEC and patches that address into the
1601 beginning of the FV header.
1603 For ARM the reset vector is at 0x00000000 or 0xFFFF0000.
1604 This would commonly map to the first entry in the ROM.
1614 We support two schemes on ARM.
1615 1) Beginning of the FV is the reset vector
1616 2) Reset vector is data bytes FDF file and that code branches to reset vector
1617 in the beginning of the FV (fixed size offset).
1620 Need to have the jump for the reset vector at location zero.
1621 We also need to store the address or PEI (if it exists).
1622 We stub out a return from interrupt in case the debugger
1624 The optional entry to the common exception handler is
1625 to support full featured exception handling from ROM and is currently
1626 not support by this tool.
1629 FvImage Memory file for the FV memory image
1630 FvInfo Information read from INF file.
1634 EFI_SUCCESS Function Completed successfully.
1635 EFI_ABORTED Error encountered.
1636 EFI_INVALID_PARAMETER A required parameter was NULL.
1637 EFI_NOT_FOUND PEI Core file not found.
1641 EFI_FFS_FILE_HEADER
*PeiCoreFile
;
1642 EFI_FFS_FILE_HEADER
*SecCoreFile
;
1644 EFI_FILE_SECTION_POINTER Pe32Section
;
1648 EFI_PHYSICAL_ADDRESS PeiCorePhysicalAddress
;
1649 EFI_PHYSICAL_ADDRESS SecCorePhysicalAddress
;
1650 INT32 ResetVector
[4]; // 0 - is branch relative to SEC entry point
1651 // 1 - PEI Entry Point
1652 // 2 - movs pc,lr for a SWI handler
1653 // 3 - Place holder for Common Exception Handler
1656 // Verify input parameters
1658 if (FvImage
== NULL
|| FvInfo
== NULL
) {
1659 return EFI_INVALID_PARAMETER
;
1662 // Initialize FV library
1664 InitializeFvLib (FvImage
->FileImage
, FvInfo
->Size
);
1667 // Find the Sec Core
1669 Status
= GetFileByType (EFI_FV_FILETYPE_SECURITY_CORE
, 1, &SecCoreFile
);
1670 if (EFI_ERROR (Status
) || SecCoreFile
== NULL
) {
1672 // Maybe hardware does SEC job and we only have PEI Core?
1676 // Find the PEI Core. It may not exist if SEC loads DXE core directly
1678 PeiCorePhysicalAddress
= 0;
1679 Status
= GetFileByType (EFI_FV_FILETYPE_PEI_CORE
, 1, &PeiCoreFile
);
1680 if (!EFI_ERROR (Status
) && PeiCoreFile
!= NULL
) {
1682 // PEI Core found, now find PE32 or TE section
1684 Status
= GetSectionByType (PeiCoreFile
, EFI_SECTION_PE32
, 1, &Pe32Section
);
1685 if (Status
== EFI_NOT_FOUND
) {
1686 Status
= GetSectionByType (PeiCoreFile
, EFI_SECTION_TE
, 1, &Pe32Section
);
1689 if (EFI_ERROR (Status
)) {
1690 Error (NULL
, 0, 3000, "Invalid", "could not find either a PE32 or a TE section in PEI core file!");
1694 Status
= GetPe32Info (
1695 (VOID
*) ((UINTN
) Pe32Section
.Pe32Section
+ sizeof (EFI_SECTION_PE32
)),
1701 if (EFI_ERROR (Status
)) {
1702 Error (NULL
, 0, 3000, "Invalid", "could not get the PE32 entry point for the PEI core!");
1706 // Physical address is FV base + offset of PE32 + offset of the entry point
1708 PeiCorePhysicalAddress
= FvInfo
->BaseAddress
;
1709 PeiCorePhysicalAddress
+= (UINTN
) Pe32Section
.Pe32Section
+ sizeof (EFI_SECTION_PE32
) - (UINTN
) FvImage
->FileImage
;
1710 PeiCorePhysicalAddress
+= EntryPoint
;
1711 DebugMsg (NULL
, 0, 9, "PeiCore physical entry point address", "Address = 0x%llX", (unsigned long long) PeiCorePhysicalAddress
);
1713 if (MachineType
== EFI_IMAGE_MACHINE_ARMT
) {
1714 memset (ResetVector
, 0, sizeof (ResetVector
));
1715 // Address of PEI Core, if we have one
1716 ResetVector
[1] = (UINT32
)PeiCorePhysicalAddress
;
1720 // Copy to the beginning of the FV
1722 memcpy ((UINT8
*) ((UINTN
) FvImage
->FileImage
), ResetVector
, sizeof (ResetVector
));
1730 // Sec Core found, now find PE32 section
1732 Status
= GetSectionByType (SecCoreFile
, EFI_SECTION_PE32
, 1, &Pe32Section
);
1733 if (Status
== EFI_NOT_FOUND
) {
1734 Status
= GetSectionByType (SecCoreFile
, EFI_SECTION_TE
, 1, &Pe32Section
);
1737 if (EFI_ERROR (Status
)) {
1738 Error (NULL
, 0, 3000, "Invalid", "could not find a PE32 section in the SEC core file.");
1742 Status
= GetPe32Info (
1743 (VOID
*) ((UINTN
) Pe32Section
.Pe32Section
+ sizeof (EFI_SECTION_PE32
)),
1748 if (EFI_ERROR (Status
)) {
1749 Error (NULL
, 0, 3000, "Invalid", "could not get the PE32 entry point for the SEC core.");
1753 if (MachineType
!= EFI_IMAGE_MACHINE_ARMT
) {
1755 // If SEC is not ARM we have nothing to do
1761 // Physical address is FV base + offset of PE32 + offset of the entry point
1763 SecCorePhysicalAddress
= FvInfo
->BaseAddress
;
1764 SecCorePhysicalAddress
+= (UINTN
) Pe32Section
.Pe32Section
+ sizeof (EFI_SECTION_PE32
) - (UINTN
) FvImage
->FileImage
;
1765 SecCorePhysicalAddress
+= EntryPoint
;
1766 DebugMsg (NULL
, 0, 9, "SecCore physical entry point address", "Address = 0x%llX", (unsigned long long) SecCorePhysicalAddress
);
1769 // Find the PEI Core. It may not exist if SEC loads DXE core directly
1771 PeiCorePhysicalAddress
= 0;
1772 Status
= GetFileByType (EFI_FV_FILETYPE_PEI_CORE
, 1, &PeiCoreFile
);
1773 if (!EFI_ERROR (Status
) && PeiCoreFile
!= NULL
) {
1775 // PEI Core found, now find PE32 or TE section
1777 Status
= GetSectionByType (PeiCoreFile
, EFI_SECTION_PE32
, 1, &Pe32Section
);
1778 if (Status
== EFI_NOT_FOUND
) {
1779 Status
= GetSectionByType (PeiCoreFile
, EFI_SECTION_TE
, 1, &Pe32Section
);
1782 if (EFI_ERROR (Status
)) {
1783 Error (NULL
, 0, 3000, "Invalid", "could not find either a PE32 or a TE section in PEI core file!");
1787 Status
= GetPe32Info (
1788 (VOID
*) ((UINTN
) Pe32Section
.Pe32Section
+ sizeof (EFI_SECTION_PE32
)),
1794 if (EFI_ERROR (Status
)) {
1795 Error (NULL
, 0, 3000, "Invalid", "could not get the PE32 entry point for the PEI core!");
1799 // Physical address is FV base + offset of PE32 + offset of the entry point
1801 PeiCorePhysicalAddress
= FvInfo
->BaseAddress
;
1802 PeiCorePhysicalAddress
+= (UINTN
) Pe32Section
.Pe32Section
+ sizeof (EFI_SECTION_PE32
) - (UINTN
) FvImage
->FileImage
;
1803 PeiCorePhysicalAddress
+= EntryPoint
;
1804 DebugMsg (NULL
, 0, 9, "PeiCore physical entry point address", "Address = 0x%llX", (unsigned long long) PeiCorePhysicalAddress
);
1808 // B SecEntryPoint - signed_immed_24 part +/-32MB offset
1809 // on ARM, the PC is always 8 ahead, so we're not really jumping from the base address, but from base address + 8
1810 ResetVector
[0] = (INT32
)(SecCorePhysicalAddress
- FvInfo
->BaseAddress
- 8) >> 2;
1812 if (ResetVector
[0] > 0x00FFFFFF) {
1813 Error (NULL
, 0, 3000, "Invalid", "SEC Entry point must be within 32MB of the start of the FV");
1817 // Add opcode for an uncondional branch with no link. AKA B SecEntryPoint
1818 ResetVector
[0] |= 0xEA000000;
1821 // Address of PEI Core, if we have one
1822 ResetVector
[1] = (UINT32
)PeiCorePhysicalAddress
;
1824 // SWI handler movs pc,lr. Just in case a debugger uses SWI
1825 ResetVector
[2] = 0xE1B0F07E;
1827 // Place holder to support a common interrupt handler from ROM.
1828 // Currently not suppprted. For this to be used the reset vector would not be in this FV
1829 // and the exception vectors would be hard coded in the ROM and just through this address
1830 // to find a common handler in the a module in the FV.
1834 // Copy to the beginning of the FV
1836 memcpy ((UINT8
*) ((UINTN
) FvImage
->FileImage
), ResetVector
, sizeof (ResetVector
));
1838 DebugMsg (NULL
, 0, 9, "Update Reset vector in FV Header", NULL
);
1846 OUT UINT32
*EntryPoint
,
1847 OUT UINT32
*BaseOfCode
,
1848 OUT UINT16
*MachineType
1852 Routine Description:
1854 Retrieves the PE32 entry point offset and machine type from PE image or TeImage.
1855 See EfiImage.h for machine types. The entry point offset is from the beginning
1856 of the PE32 buffer passed in.
1860 Pe32 Beginning of the PE32.
1861 EntryPoint Offset from the beginning of the PE32 to the image entry point.
1862 BaseOfCode Base address of code.
1863 MachineType Magic number for the machine type.
1867 EFI_SUCCESS Function completed successfully.
1868 EFI_ABORTED Error encountered.
1869 EFI_INVALID_PARAMETER A required parameter was NULL.
1870 EFI_UNSUPPORTED The operation is unsupported.
1874 EFI_IMAGE_DOS_HEADER
*DosHeader
;
1875 EFI_IMAGE_OPTIONAL_HEADER_UNION
*ImgHdr
;
1876 EFI_TE_IMAGE_HEADER
*TeHeader
;
1879 // Verify input parameters
1882 return EFI_INVALID_PARAMETER
;
1886 // First check whether it is one TE Image.
1888 TeHeader
= (EFI_TE_IMAGE_HEADER
*) Pe32
;
1889 if (TeHeader
->Signature
== EFI_TE_IMAGE_HEADER_SIGNATURE
) {
1891 // By TeImage Header to get output
1893 *EntryPoint
= TeHeader
->AddressOfEntryPoint
+ sizeof (EFI_TE_IMAGE_HEADER
) - TeHeader
->StrippedSize
;
1894 *BaseOfCode
= TeHeader
->BaseOfCode
+ sizeof (EFI_TE_IMAGE_HEADER
) - TeHeader
->StrippedSize
;
1895 *MachineType
= TeHeader
->Machine
;
1899 // Then check whether
1900 // First is the DOS header
1902 DosHeader
= (EFI_IMAGE_DOS_HEADER
*) Pe32
;
1905 // Verify DOS header is expected
1907 if (DosHeader
->e_magic
!= EFI_IMAGE_DOS_SIGNATURE
) {
1908 Error (NULL
, 0, 3000, "Invalid", "Unknown magic number in the DOS header, 0x%04X.", DosHeader
->e_magic
);
1909 return EFI_UNSUPPORTED
;
1912 // Immediately following is the NT header.
1914 ImgHdr
= (EFI_IMAGE_OPTIONAL_HEADER_UNION
*) ((UINTN
) Pe32
+ DosHeader
->e_lfanew
);
1917 // Verify NT header is expected
1919 if (ImgHdr
->Pe32
.Signature
!= EFI_IMAGE_NT_SIGNATURE
) {
1920 Error (NULL
, 0, 3000, "Invalid", "Unrecognized image signature 0x%08X.", (unsigned) ImgHdr
->Pe32
.Signature
);
1921 return EFI_UNSUPPORTED
;
1926 *EntryPoint
= ImgHdr
->Pe32
.OptionalHeader
.AddressOfEntryPoint
;
1927 *BaseOfCode
= ImgHdr
->Pe32
.OptionalHeader
.BaseOfCode
;
1928 *MachineType
= ImgHdr
->Pe32
.FileHeader
.Machine
;
1932 // Verify machine type is supported
1934 if (*MachineType
!= EFI_IMAGE_MACHINE_IA32
&& *MachineType
!= EFI_IMAGE_MACHINE_IA64
&& *MachineType
!= EFI_IMAGE_MACHINE_X64
&& *MachineType
!= EFI_IMAGE_MACHINE_EBC
&&
1935 *MachineType
!= EFI_IMAGE_MACHINE_ARMT
) {
1936 Error (NULL
, 0, 3000, "Invalid", "Unrecognized machine type in the PE32 file.");
1937 return EFI_UNSUPPORTED
;
1945 IN CHAR8
*InfFileImage
,
1946 IN UINTN InfFileSize
,
1947 IN CHAR8
*FvFileName
,
1948 IN CHAR8
*MapFileName
1952 Routine Description:
1954 This is the main function which will be called from application.
1958 InfFileImage Buffer containing the INF file contents.
1959 InfFileSize Size of the contents of the InfFileImage buffer.
1960 FvFileName Requested name for the FV file.
1961 MapFileName Fv map file to log fv driver information.
1965 EFI_SUCCESS Function completed successfully.
1966 EFI_OUT_OF_RESOURCES Could not allocate required resources.
1967 EFI_ABORTED Error encountered.
1968 EFI_INVALID_PARAMETER A required parameter was NULL.
1973 MEMORY_FILE InfMemoryFile
;
1974 MEMORY_FILE FvImageMemoryFile
;
1976 EFI_FIRMWARE_VOLUME_HEADER
*FvHeader
;
1977 EFI_FFS_FILE_HEADER
*VtfFileImage
;
1978 UINT8
*FvBufferHeader
; // to make sure fvimage header 8 type alignment.
1982 CHAR8 FvMapName
[_MAX_PATH
];
1984 EFI_FIRMWARE_VOLUME_EXT_HEADER
*FvExtHeader
;
1985 FILE *FvExtHeaderFile
;
1987 CHAR8 FvReportName
[_MAX_PATH
];
1990 FvBufferHeader
= NULL
;
1993 FvReportFile
= NULL
;
1995 if (InfFileImage
!= NULL
) {
1997 // Initialize file structures
1999 InfMemoryFile
.FileImage
= InfFileImage
;
2000 InfMemoryFile
.CurrentFilePointer
= InfFileImage
;
2001 InfMemoryFile
.Eof
= InfFileImage
+ InfFileSize
;
2004 // Parse the FV inf file for header information
2006 Status
= ParseFvInf (&InfMemoryFile
, &mFvDataInfo
);
2007 if (EFI_ERROR (Status
)) {
2008 Error (NULL
, 0, 0003, "Error parsing file", "the input FV INF file.");
2014 // Update the file name return values
2016 if (FvFileName
== NULL
&& mFvDataInfo
.FvName
[0] != '\0') {
2017 FvFileName
= mFvDataInfo
.FvName
;
2020 if (FvFileName
== NULL
) {
2021 Error (NULL
, 0, 1001, "Missing option", "Output file name");
2025 if (mFvDataInfo
.FvBlocks
[0].Length
== 0) {
2026 Error (NULL
, 0, 1001, "Missing required argument", "Block Size");
2031 // Debug message Fv File System Guid
2033 if (mFvDataInfo
.FvFileSystemGuidSet
) {
2034 DebugMsg (NULL
, 0, 9, "FV File System Guid", "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X",
2035 (unsigned) mFvDataInfo
.FvFileSystemGuid
.Data1
,
2036 mFvDataInfo
.FvFileSystemGuid
.Data2
,
2037 mFvDataInfo
.FvFileSystemGuid
.Data3
,
2038 mFvDataInfo
.FvFileSystemGuid
.Data4
[0],
2039 mFvDataInfo
.FvFileSystemGuid
.Data4
[1],
2040 mFvDataInfo
.FvFileSystemGuid
.Data4
[2],
2041 mFvDataInfo
.FvFileSystemGuid
.Data4
[3],
2042 mFvDataInfo
.FvFileSystemGuid
.Data4
[4],
2043 mFvDataInfo
.FvFileSystemGuid
.Data4
[5],
2044 mFvDataInfo
.FvFileSystemGuid
.Data4
[6],
2045 mFvDataInfo
.FvFileSystemGuid
.Data4
[7]);
2049 // Add PI FV extension header
2052 FvExtHeaderFile
= NULL
;
2053 if (mFvDataInfo
.FvExtHeaderFile
[0] != 0) {
2055 // Open the FV Extension Header file
2057 FvExtHeaderFile
= fopen (mFvDataInfo
.FvExtHeaderFile
, "rb");
2060 // Get the file size
2062 FileSize
= _filelength (fileno (FvExtHeaderFile
));
2065 // Allocate a buffer for the FV Extension Header
2067 FvExtHeader
= malloc(FileSize
);
2068 if (FvExtHeader
== NULL
) {
2069 fclose (FvExtHeaderFile
);
2070 return EFI_OUT_OF_RESOURCES
;
2074 // Read the FV Extension Header
2076 fread (FvExtHeader
, sizeof (UINT8
), FileSize
, FvExtHeaderFile
);
2077 fclose (FvExtHeaderFile
);
2080 // See if there is an override for the FV Name GUID
2082 if (mFvDataInfo
.FvNameGuidSet
) {
2083 memcpy (&FvExtHeader
->FvName
, &mFvDataInfo
.FvNameGuid
, sizeof (EFI_GUID
));
2085 memcpy (&mFvDataInfo
.FvNameGuid
, &FvExtHeader
->FvName
, sizeof (EFI_GUID
));
2086 mFvDataInfo
.FvNameGuidSet
= TRUE
;
2087 } else if (mFvDataInfo
.FvNameGuidSet
) {
2089 // Allocate a buffer for the FV Extension Header
2091 FvExtHeader
= malloc(sizeof (EFI_FIRMWARE_VOLUME_EXT_HEADER
));
2092 if (FvExtHeader
== NULL
) {
2093 return EFI_OUT_OF_RESOURCES
;
2095 memcpy (&FvExtHeader
->FvName
, &mFvDataInfo
.FvNameGuid
, sizeof (EFI_GUID
));
2096 FvExtHeader
->ExtHeaderSize
= sizeof (EFI_FIRMWARE_VOLUME_EXT_HEADER
);
2100 // Debug message Fv Name Guid
2102 if (mFvDataInfo
.FvNameGuidSet
) {
2103 DebugMsg (NULL
, 0, 9, "FV Name Guid", "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X",
2104 (unsigned) mFvDataInfo
.FvNameGuid
.Data1
,
2105 mFvDataInfo
.FvNameGuid
.Data2
,
2106 mFvDataInfo
.FvNameGuid
.Data3
,
2107 mFvDataInfo
.FvNameGuid
.Data4
[0],
2108 mFvDataInfo
.FvNameGuid
.Data4
[1],
2109 mFvDataInfo
.FvNameGuid
.Data4
[2],
2110 mFvDataInfo
.FvNameGuid
.Data4
[3],
2111 mFvDataInfo
.FvNameGuid
.Data4
[4],
2112 mFvDataInfo
.FvNameGuid
.Data4
[5],
2113 mFvDataInfo
.FvNameGuid
.Data4
[6],
2114 mFvDataInfo
.FvNameGuid
.Data4
[7]);
2117 if (CompareGuid (&mFvDataInfo
.FvFileSystemGuid
, &mEfiFirmwareFileSystem2Guid
) == 0) {
2118 mFvDataInfo
.IsPiFvImage
= TRUE
;
2122 // FvMap file to log the function address of all modules in one Fvimage
2124 if (MapFileName
!= NULL
) {
2125 strcpy (FvMapName
, MapFileName
);
2127 strcpy (FvMapName
, FvFileName
);
2128 strcat (FvMapName
, ".map");
2130 VerboseMsg ("FV Map file name is %s", FvMapName
);
2133 // FvReport file to log the FV information in one Fvimage
2135 strcpy (FvReportName
, FvFileName
);
2136 strcat (FvReportName
, ".txt");
2139 // Calculate the FV size and Update Fv Size based on the actual FFS files.
2140 // And Update mFvDataInfo data.
2142 Status
= CalculateFvSize (&mFvDataInfo
);
2143 if (EFI_ERROR (Status
)) {
2146 VerboseMsg ("the generated FV image size is %u bytes", (unsigned) mFvDataInfo
.Size
);
2149 // support fv image and empty fv image
2151 FvImageSize
= mFvDataInfo
.Size
;
2154 // Allocate the FV, assure FvImage Header 8 byte alignment
2156 FvBufferHeader
= malloc (FvImageSize
+ sizeof (UINT64
));
2157 if (FvBufferHeader
== NULL
) {
2158 return EFI_OUT_OF_RESOURCES
;
2160 FvImage
= (UINT8
*) (((UINTN
) FvBufferHeader
+ 7) & ~7);
2163 // Initialize the FV to the erase polarity
2165 if (mFvDataInfo
.FvAttributes
== 0) {
2167 // Set Default Fv Attribute
2169 mFvDataInfo
.FvAttributes
= FV_DEFAULT_ATTRIBUTE
;
2171 if (mFvDataInfo
.FvAttributes
& EFI_FVB2_ERASE_POLARITY
) {
2172 memset (FvImage
, -1, FvImageSize
);
2174 memset (FvImage
, 0, FvImageSize
);
2178 // Initialize FV header
2180 FvHeader
= (EFI_FIRMWARE_VOLUME_HEADER
*) FvImage
;
2183 // Initialize the zero vector to all zeros.
2185 memset (FvHeader
->ZeroVector
, 0, 16);
2188 // Copy the Fv file system GUID
2190 memcpy (&FvHeader
->FileSystemGuid
, &mFvDataInfo
.FvFileSystemGuid
, sizeof (EFI_GUID
));
2192 FvHeader
->FvLength
= FvImageSize
;
2193 FvHeader
->Signature
= EFI_FVH_SIGNATURE
;
2194 FvHeader
->Attributes
= mFvDataInfo
.FvAttributes
;
2195 FvHeader
->Revision
= EFI_FVH_REVISION
;
2196 FvHeader
->ExtHeaderOffset
= 0;
2197 FvHeader
->Reserved
[0] = 0;
2200 // Copy firmware block map
2202 for (Index
= 0; mFvDataInfo
.FvBlocks
[Index
].Length
!= 0; Index
++) {
2203 FvHeader
->BlockMap
[Index
].NumBlocks
= mFvDataInfo
.FvBlocks
[Index
].NumBlocks
;
2204 FvHeader
->BlockMap
[Index
].Length
= mFvDataInfo
.FvBlocks
[Index
].Length
;
2208 // Add block map terminator
2210 FvHeader
->BlockMap
[Index
].NumBlocks
= 0;
2211 FvHeader
->BlockMap
[Index
].Length
= 0;
2214 // Complete the header
2216 FvHeader
->HeaderLength
= (UINT16
) (((UINTN
) &(FvHeader
->BlockMap
[Index
+ 1])) - (UINTN
) FvImage
);
2217 FvHeader
->Checksum
= 0;
2218 FvHeader
->Checksum
= CalculateChecksum16 ((UINT16
*) FvHeader
, FvHeader
->HeaderLength
/ sizeof (UINT16
));
2221 // If there is no FFS file, generate one empty FV
2223 if (mFvDataInfo
.FvFiles
[0][0] == 0 && !mFvDataInfo
.FvNameGuidSet
) {
2228 // Initialize our "file" view of the buffer
2230 FvImageMemoryFile
.FileImage
= (CHAR8
*)FvImage
;
2231 FvImageMemoryFile
.CurrentFilePointer
= (CHAR8
*)FvImage
+ FvHeader
->HeaderLength
;
2232 FvImageMemoryFile
.Eof
= (CHAR8
*)FvImage
+ FvImageSize
;
2235 // Initialize the FV library.
2237 InitializeFvLib (FvImageMemoryFile
.FileImage
, FvImageSize
);
2240 // Initialize the VTF file address.
2242 VtfFileImage
= (EFI_FFS_FILE_HEADER
*) FvImageMemoryFile
.Eof
;
2247 FvMapFile
= fopen (FvMapName
, "w");
2248 if (FvMapFile
== NULL
) {
2249 Error (NULL
, 0, 0001, "Error opening file", FvMapName
);
2254 // Open FvReport file
2256 FvReportFile
= fopen(FvReportName
, "w");
2257 if (FvReportFile
== NULL
) {
2258 Error (NULL
, 0, 0001, "Error opening file", FvReportName
);
2262 // record FV size information into FvMap file.
2264 if (mFvTotalSize
!= 0) {
2265 fprintf (FvMapFile
, EFI_FV_TOTAL_SIZE_STRING
);
2266 fprintf (FvMapFile
, " = 0x%x\n", (unsigned) mFvTotalSize
);
2268 if (mFvTakenSize
!= 0) {
2269 fprintf (FvMapFile
, EFI_FV_TAKEN_SIZE_STRING
);
2270 fprintf (FvMapFile
, " = 0x%x\n", (unsigned) mFvTakenSize
);
2272 if (mFvTotalSize
!= 0 && mFvTakenSize
!= 0) {
2273 fprintf (FvMapFile
, EFI_FV_SPACE_SIZE_STRING
);
2274 fprintf (FvMapFile
, " = 0x%x\n\n", (unsigned) (mFvTotalSize
- mFvTakenSize
));
2278 // record FV size information to FvReportFile.
2280 fprintf (FvReportFile
, "%s = 0x%x\n", EFI_FV_TOTAL_SIZE_STRING
, (unsigned) mFvTotalSize
);
2281 fprintf (FvReportFile
, "%s = 0x%x\n", EFI_FV_TAKEN_SIZE_STRING
, (unsigned) mFvTakenSize
);
2284 // Add PI FV extension header
2286 if (FvExtHeader
!= NULL
) {
2288 // Add FV Extended Header contents to the FV as a PAD file
2290 AddPadFile (&FvImageMemoryFile
, 4, VtfFileImage
, FvExtHeader
);
2293 // Fv Extension header change update Fv Header Check sum
2295 FvHeader
->Checksum
= 0;
2296 FvHeader
->Checksum
= CalculateChecksum16 ((UINT16
*) FvHeader
, FvHeader
->HeaderLength
/ sizeof (UINT16
));
2302 for (Index
= 0; mFvDataInfo
.FvFiles
[Index
][0] != 0; Index
++) {
2306 Status
= AddFile (&FvImageMemoryFile
, &mFvDataInfo
, Index
, &VtfFileImage
, FvMapFile
, FvReportFile
);
2309 // Exit if error detected while adding the file
2311 if (EFI_ERROR (Status
)) {
2317 // If there is a VTF file, some special actions need to occur.
2319 if ((UINTN
) VtfFileImage
!= (UINTN
) FvImageMemoryFile
.Eof
) {
2321 // Pad from the end of the last file to the beginning of the VTF file.
2322 // If the left space is less than sizeof (EFI_FFS_FILE_HEADER)?
2324 Status
= PadFvImage (&FvImageMemoryFile
, VtfFileImage
);
2325 if (EFI_ERROR (Status
)) {
2326 Error (NULL
, 0, 4002, "Resource", "FV space is full, cannot add pad file between the last file and the VTF file.");
2331 // Update reset vector (SALE_ENTRY for IPF)
2332 // Now for IA32 and IA64 platform, the fv which has bsf file must have the
2333 // EndAddress of 0xFFFFFFFF. Thus, only this type fv needs to update the
2334 // reset vector. If the PEI Core is found, the VTF file will probably get
2335 // corrupted by updating the entry point.
2337 if ((mFvDataInfo
.BaseAddress
+ mFvDataInfo
.Size
) == FV_IMAGES_TOP_ADDRESS
) {
2338 Status
= UpdateResetVector (&FvImageMemoryFile
, &mFvDataInfo
, VtfFileImage
);
2339 if (EFI_ERROR(Status
)) {
2340 Error (NULL
, 0, 3000, "Invalid", "Could not update the reset vector.");
2343 DebugMsg (NULL
, 0, 9, "Update Reset vector in VTF file", NULL
);
2349 Status
= UpdateArmResetVectorIfNeeded (&FvImageMemoryFile
, &mFvDataInfo
);
2350 if (EFI_ERROR (Status
)) {
2351 Error (NULL
, 0, 3000, "Invalid", "Could not update the reset vector.");
2356 // Update Checksum for FvHeader
2358 FvHeader
->Checksum
= 0;
2359 FvHeader
->Checksum
= CalculateChecksum16 ((UINT16
*) FvHeader
, FvHeader
->HeaderLength
/ sizeof (UINT16
));
2363 // Update FV Alignment attribute to the largest alignment of all the FFS files in the FV
2365 if ((((FvHeader
->Attributes
& EFI_FVB2_ALIGNMENT
) >> 16)) < MaxFfsAlignment
) {
2366 FvHeader
->Attributes
= ((MaxFfsAlignment
<< 16) | (FvHeader
->Attributes
& 0xFFFF));
2368 // Update Checksum for FvHeader
2370 FvHeader
->Checksum
= 0;
2371 FvHeader
->Checksum
= CalculateChecksum16 ((UINT16
*) FvHeader
, FvHeader
->HeaderLength
/ sizeof (UINT16
));
2378 FvFile
= fopen (FvFileName
, "wb");
2379 if (FvFile
== NULL
) {
2380 Error (NULL
, 0, 0001, "Error opening file", FvFileName
);
2381 Status
= EFI_ABORTED
;
2385 if (fwrite (FvImage
, 1, FvImageSize
, FvFile
) != FvImageSize
) {
2386 Error (NULL
, 0, 0002, "Error writing file", FvFileName
);
2387 Status
= EFI_ABORTED
;
2392 if (FvBufferHeader
!= NULL
) {
2393 free (FvBufferHeader
);
2396 if (FvExtHeader
!= NULL
) {
2400 if (FvFile
!= NULL
) {
2405 if (FvMapFile
!= NULL
) {
2410 if (FvReportFile
!= NULL
) {
2411 fflush (FvReportFile
);
2412 fclose (FvReportFile
);
2418 UpdatePeiCoreEntryInFit (
2419 IN FIT_TABLE
*FitTablePtr
,
2420 IN UINT64 PeiCorePhysicalAddress
2424 Routine Description:
2426 This function is used to update the Pei Core address in FIT, this can be used by Sec core to pass control from
2431 FitTablePtr - The pointer of FIT_TABLE.
2432 PeiCorePhysicalAddress - The address of Pei Core entry.
2436 EFI_SUCCESS - The PEI_CORE FIT entry was updated successfully.
2437 EFI_NOT_FOUND - Not found the PEI_CORE FIT entry.
2441 FIT_TABLE
*TmpFitPtr
;
2443 UINTN NumFitComponents
;
2445 TmpFitPtr
= FitTablePtr
;
2446 NumFitComponents
= TmpFitPtr
->CompSize
;
2448 for (Index
= 0; Index
< NumFitComponents
; Index
++) {
2449 if ((TmpFitPtr
->CvAndType
& FIT_TYPE_MASK
) == COMP_TYPE_FIT_PEICORE
) {
2450 TmpFitPtr
->CompAddress
= PeiCorePhysicalAddress
;
2457 return EFI_NOT_FOUND
;
2462 IN FIT_TABLE
*FitTablePtr
2466 Routine Description:
2468 This function is used to update the checksum for FIT.
2473 FitTablePtr - The pointer of FIT_TABLE.
2481 if ((FitTablePtr
->CvAndType
& CHECKSUM_BIT_MASK
) >> 7) {
2482 FitTablePtr
->CheckSum
= 0;
2483 FitTablePtr
->CheckSum
= CalculateChecksum8 ((UINT8
*) FitTablePtr
, FitTablePtr
->CompSize
* 16);
2492 Routine Description:
2493 Calculate the FV size and Update Fv Size based on the actual FFS files.
2494 And Update FvInfo data.
2497 FvInfoPtr - The pointer to FV_INFO structure.
2500 EFI_ABORTED - Ffs Image Error
2501 EFI_SUCCESS - Successfully update FvSize
2504 UINTN CurrentOffset
;
2508 UINTN FvExtendHeaderSize
;
2509 UINT32 FfsAlignment
;
2510 EFI_FFS_FILE_HEADER FfsHeader
;
2511 BOOLEAN VtfFileFlag
;
2514 FvExtendHeaderSize
= 0;
2516 VtfFileFlag
= FALSE
;
2521 // Compute size for easy access later
2523 FvInfoPtr
->Size
= 0;
2524 for (Index
= 0; FvInfoPtr
->FvBlocks
[Index
].NumBlocks
> 0 && FvInfoPtr
->FvBlocks
[Index
].Length
> 0; Index
++) {
2525 FvInfoPtr
->Size
+= FvInfoPtr
->FvBlocks
[Index
].NumBlocks
* FvInfoPtr
->FvBlocks
[Index
].Length
;
2529 // Caculate the required sizes for all FFS files.
2531 CurrentOffset
= sizeof (EFI_FIRMWARE_VOLUME_HEADER
);
2533 for (Index
= 1;; Index
++) {
2534 CurrentOffset
+= sizeof (EFI_FV_BLOCK_MAP_ENTRY
);
2535 if (FvInfoPtr
->FvBlocks
[Index
].NumBlocks
== 0 || FvInfoPtr
->FvBlocks
[Index
].Length
== 0) {
2541 // Calculate PI extension header
2543 if (mFvDataInfo
.FvExtHeaderFile
[0] != '\0') {
2544 fpin
= fopen (mFvDataInfo
.FvExtHeaderFile
, "rb");
2546 Error (NULL
, 0, 0001, "Error opening file", mFvDataInfo
.FvExtHeaderFile
);
2549 FvExtendHeaderSize
= _filelength (fileno (fpin
));
2551 CurrentOffset
+= sizeof (EFI_FFS_FILE_HEADER
) + FvExtendHeaderSize
;
2552 CurrentOffset
= (CurrentOffset
+ 7) & (~7);
2553 } else if (mFvDataInfo
.FvNameGuidSet
) {
2554 CurrentOffset
+= sizeof (EFI_FFS_FILE_HEADER
) + sizeof (EFI_FIRMWARE_VOLUME_EXT_HEADER
);
2555 CurrentOffset
= (CurrentOffset
+ 7) & (~7);
2559 // Accumlate every FFS file size.
2561 for (Index
= 0; FvInfoPtr
->FvFiles
[Index
][0] != 0; Index
++) {
2566 fpin
= fopen (FvInfoPtr
->FvFiles
[Index
], "rb");
2568 Error (NULL
, 0, 0001, "Error opening file", FvInfoPtr
->FvFiles
[Index
]);
2572 // Get the file size
2574 FfsFileSize
= _filelength (fileno (fpin
));
2576 // Read Ffs File header
2578 fread (&FfsHeader
, sizeof (UINT8
), sizeof (EFI_FFS_FILE_HEADER
), fpin
);
2584 if (FvInfoPtr
->IsPiFvImage
) {
2586 // Check whether this ffs file is vtf file
2588 if (IsVtfFile (&FfsHeader
)) {
2591 // One Fv image can't have two vtf files.
2596 VtfFileSize
= FfsFileSize
;
2601 // Get the alignment of FFS file
2603 ReadFfsAlignment (&FfsHeader
, &FfsAlignment
);
2604 FfsAlignment
= 1 << FfsAlignment
;
2608 if (((CurrentOffset
+ sizeof (EFI_FFS_FILE_HEADER
)) % FfsAlignment
) != 0) {
2609 CurrentOffset
= (CurrentOffset
+ sizeof (EFI_FFS_FILE_HEADER
) * 2 + FfsAlignment
- 1) & ~(FfsAlignment
- 1);
2610 CurrentOffset
-= sizeof (EFI_FFS_FILE_HEADER
);
2615 // Add ffs file size
2617 if (FvInfoPtr
->SizeofFvFiles
[Index
] > FfsFileSize
) {
2618 CurrentOffset
+= FvInfoPtr
->SizeofFvFiles
[Index
];
2620 CurrentOffset
+= FfsFileSize
;
2624 // Make next ffs file start at QWord Boundry
2626 if (FvInfoPtr
->IsPiFvImage
) {
2627 CurrentOffset
= (CurrentOffset
+ EFI_FFS_FILE_HEADER_ALIGNMENT
- 1) & ~(EFI_FFS_FILE_HEADER_ALIGNMENT
- 1);
2630 CurrentOffset
+= VtfFileSize
;
2631 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
);
2633 if (FvInfoPtr
->Size
== 0) {
2635 // Update FvInfo data
2637 FvInfoPtr
->FvBlocks
[0].NumBlocks
= CurrentOffset
/ FvInfoPtr
->FvBlocks
[0].Length
+ ((CurrentOffset
% FvInfoPtr
->FvBlocks
[0].Length
)?1:0);
2638 FvInfoPtr
->Size
= FvInfoPtr
->FvBlocks
[0].NumBlocks
* FvInfoPtr
->FvBlocks
[0].Length
;
2639 FvInfoPtr
->FvBlocks
[1].NumBlocks
= 0;
2640 FvInfoPtr
->FvBlocks
[1].Length
= 0;
2641 } else if (FvInfoPtr
->Size
< CurrentOffset
) {
2645 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
);
2646 return EFI_INVALID_PARAMETER
;
2650 // Set Fv Size Information
2652 mFvTotalSize
= FvInfoPtr
->Size
;
2653 mFvTakenSize
= CurrentOffset
;
2659 FfsRebaseImageRead (
2660 IN VOID
*FileHandle
,
2661 IN UINTN FileOffset
,
2662 IN OUT UINT32
*ReadSize
,
2667 Routine Description:
2669 Support routine for the PE/COFF Loader that reads a buffer from a PE/COFF file
2673 FileHandle - The handle to the PE/COFF file
2675 FileOffset - The offset, in bytes, into the file to read
2677 ReadSize - The number of bytes to read from the file starting at FileOffset
2679 Buffer - A pointer to the buffer to read the data into.
2683 EFI_SUCCESS - ReadSize bytes of data were read into Buffer from the PE/COFF file starting at FileOffset
2687 CHAR8
*Destination8
;
2691 Destination8
= Buffer
;
2692 Source8
= (CHAR8
*) ((UINTN
) FileHandle
+ FileOffset
);
2695 *(Destination8
++) = *(Source8
++);
2704 IN EFI_FFS_FILE_HEADER
*FfsFile
,
2709 Routine Description:
2711 This function gets all child FvImages in the input FfsFile, and records
2712 their base address to the parent image.
2715 FvInfo A pointer to FV_INFO struture.
2716 FfsFile A pointer to Ffs file image that may contain FvImage.
2717 XipOffset The offset address to the parent FvImage base.
2721 EFI_SUCCESS Base address of child Fv image is recorded.
2726 EFI_FILE_SECTION_POINTER SubFvSection
;
2727 EFI_FIRMWARE_VOLUME_HEADER
*SubFvImageHeader
;
2728 EFI_PHYSICAL_ADDRESS SubFvBaseAddress
;
2730 for (Index
= 1;; Index
++) {
2734 Status
= GetSectionByType (FfsFile
, EFI_SECTION_FIRMWARE_VOLUME_IMAGE
, Index
, &SubFvSection
);
2735 if (EFI_ERROR (Status
)) {
2738 SubFvImageHeader
= (EFI_FIRMWARE_VOLUME_HEADER
*) ((UINT8
*) SubFvSection
.FVImageSection
+ sizeof (EFI_FIRMWARE_VOLUME_IMAGE_SECTION
));
2742 SubFvBaseAddress
= FvInfo
->BaseAddress
+ (UINTN
) SubFvImageHeader
- (UINTN
) FfsFile
+ XipOffset
;
2743 mFvBaseAddress
[mFvBaseAddressNumber
++ ] = SubFvBaseAddress
;
2751 IN OUT FV_INFO
*FvInfo
,
2753 IN OUT EFI_FFS_FILE_HEADER
*FfsFile
,
2759 Routine Description:
2761 This function determines if a file is XIP and should be rebased. It will
2762 rebase any PE32 sections found in the file using the base address.
2766 FvInfo A pointer to FV_INFO struture.
2767 FileName Ffs File PathName
2768 FfsFile A pointer to Ffs file image.
2769 XipOffset The offset address to use for rebasing the XIP file image.
2770 FvMapFile FvMapFile to record the function address in one Fvimage
2774 EFI_SUCCESS The image was properly rebased.
2775 EFI_INVALID_PARAMETER An input parameter is invalid.
2776 EFI_ABORTED An error occurred while rebasing the input file image.
2777 EFI_OUT_OF_RESOURCES Could not allocate a required resource.
2778 EFI_NOT_FOUND No compressed sections could be found.
2783 PE_COFF_LOADER_IMAGE_CONTEXT ImageContext
;
2784 PE_COFF_LOADER_IMAGE_CONTEXT OrigImageContext
;
2785 EFI_PHYSICAL_ADDRESS XipBase
;
2786 EFI_PHYSICAL_ADDRESS NewPe32BaseAddress
;
2787 EFI_PHYSICAL_ADDRESS
*BaseToUpdate
;
2789 EFI_FILE_SECTION_POINTER CurrentPe32Section
;
2790 EFI_FFS_FILE_STATE SavedState
;
2791 EFI_IMAGE_OPTIONAL_HEADER_UNION
*ImgHdr
;
2792 EFI_TE_IMAGE_HEADER
*TEImageHeader
;
2793 UINT8
*MemoryImagePointer
;
2794 EFI_IMAGE_SECTION_HEADER
*SectionHeader
;
2795 CHAR8 PeFileName
[_MAX_PATH
];
2798 UINT8
*PeFileBuffer
;
2803 MemoryImagePointer
= NULL
;
2804 BaseToUpdate
= NULL
;
2805 TEImageHeader
= NULL
;
2807 SectionHeader
= NULL
;
2810 PeFileBuffer
= NULL
;
2813 // Don't need to relocate image when BaseAddress is not set.
2815 if (FvInfo
->BaseAddress
== 0) {
2818 XipBase
= FvInfo
->BaseAddress
+ XipOffset
;
2821 // We only process files potentially containing PE32 sections.
2823 switch (FfsFile
->Type
) {
2824 case EFI_FV_FILETYPE_SECURITY_CORE
:
2825 case EFI_FV_FILETYPE_PEI_CORE
:
2826 case EFI_FV_FILETYPE_PEIM
:
2827 case EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER
:
2828 case EFI_FV_FILETYPE_DRIVER
:
2829 case EFI_FV_FILETYPE_DXE_CORE
:
2831 case EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE
:
2833 // Rebase the inside FvImage.
2835 GetChildFvFromFfs (FvInfo
, FfsFile
, XipOffset
);
2838 // Search PE/TE section in FV sectin.
2845 // Rebase each PE32 section
2847 Status
= EFI_SUCCESS
;
2848 for (Index
= 1;; Index
++) {
2852 NewPe32BaseAddress
= 0;
2857 Status
= GetSectionByType (FfsFile
, EFI_SECTION_PE32
, Index
, &CurrentPe32Section
);
2858 if (EFI_ERROR (Status
)) {
2863 // Initialize context
2865 memset (&ImageContext
, 0, sizeof (ImageContext
));
2866 ImageContext
.Handle
= (VOID
*) ((UINTN
) CurrentPe32Section
.Pe32Section
+ sizeof (EFI_PE32_SECTION
));
2867 ImageContext
.ImageRead
= (PE_COFF_LOADER_READ_FILE
) FfsRebaseImageRead
;
2868 Status
= PeCoffLoaderGetImageInfo (&ImageContext
);
2869 if (EFI_ERROR (Status
)) {
2870 Error (NULL
, 0, 3000, "Invalid PeImage", "The input file is %s and the return status is %x", FileName
, (int) Status
);
2874 if (ImageContext
.Machine
== EFI_IMAGE_MACHINE_ARMT
) {
2879 // Keep Image Context for PE image in FV
2881 memcpy (&OrigImageContext
, &ImageContext
, sizeof (ImageContext
));
2884 // Get File PdbPointer
2886 PdbPointer
= PeCoffLoaderGetPdbPointer (ImageContext
.Handle
);
2889 // Get PeHeader pointer
2891 ImgHdr
= (EFI_IMAGE_OPTIONAL_HEADER_UNION
*)((UINTN
) CurrentPe32Section
.Pe32Section
+ sizeof (EFI_PE32_SECTION
) + ImageContext
.PeCoffHeaderOffset
);
2894 // Calculate the PE32 base address, based on file type
2896 switch (FfsFile
->Type
) {
2897 case EFI_FV_FILETYPE_SECURITY_CORE
:
2898 case EFI_FV_FILETYPE_PEI_CORE
:
2899 case EFI_FV_FILETYPE_PEIM
:
2900 case EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER
:
2902 // Check if section-alignment and file-alignment match or not
2904 if ((ImgHdr
->Pe32
.OptionalHeader
.SectionAlignment
!= ImgHdr
->Pe32
.OptionalHeader
.FileAlignment
)) {
2906 // Xip module has the same section alignment and file alignment.
2908 Error (NULL
, 0, 3000, "Invalid", "Section-Alignment and File-Alignment do not match : %s.", FileName
);
2912 // PeImage has no reloc section. It will try to get reloc data from the original EFI image.
2914 if (ImageContext
.RelocationsStripped
) {
2916 // Construct the original efi file Name
2918 strcpy (PeFileName
, FileName
);
2919 Cptr
= PeFileName
+ strlen (PeFileName
);
2920 while (*Cptr
!= '.') {
2924 Error (NULL
, 0, 3000, "Invalid", "The file %s has no .reloc section.", FileName
);
2932 PeFile
= fopen (PeFileName
, "rb");
2933 if (PeFile
== NULL
) {
2934 Warning (NULL
, 0, 0, "Invalid", "The file %s has no .reloc section.", FileName
);
2935 //Error (NULL, 0, 3000, "Invalid", "The file %s has no .reloc section.", FileName);
2936 //return EFI_ABORTED;
2940 // Get the file size
2942 PeFileSize
= _filelength (fileno (PeFile
));
2943 PeFileBuffer
= (UINT8
*) malloc (PeFileSize
);
2944 if (PeFileBuffer
== NULL
) {
2945 Error (NULL
, 0, 4001, "Resource", "memory cannot be allocated on rebase of %s", FileName
);
2946 return EFI_OUT_OF_RESOURCES
;
2951 fread (PeFileBuffer
, sizeof (UINT8
), PeFileSize
, PeFile
);
2957 // Handle pointer to the original efi image.
2959 ImageContext
.Handle
= PeFileBuffer
;
2960 Status
= PeCoffLoaderGetImageInfo (&ImageContext
);
2961 if (EFI_ERROR (Status
)) {
2962 Error (NULL
, 0, 3000, "Invalid PeImage", "The input file is %s and the return status is %x", FileName
, (int) Status
);
2965 ImageContext
.RelocationsStripped
= FALSE
;
2968 NewPe32BaseAddress
= XipBase
+ (UINTN
) CurrentPe32Section
.Pe32Section
+ sizeof (EFI_PE32_SECTION
) - (UINTN
)FfsFile
;
2969 BaseToUpdate
= &XipBase
;
2972 case EFI_FV_FILETYPE_DRIVER
:
2973 case EFI_FV_FILETYPE_DXE_CORE
:
2975 // Check if section-alignment and file-alignment match or not
2977 if ((ImgHdr
->Pe32
.OptionalHeader
.SectionAlignment
!= ImgHdr
->Pe32
.OptionalHeader
.FileAlignment
)) {
2979 // Xip module has the same section alignment and file alignment.
2981 Error (NULL
, 0, 3000, "Invalid", "Section-Alignment and File-Alignment do not match : %s.", FileName
);
2984 NewPe32BaseAddress
= XipBase
+ (UINTN
) CurrentPe32Section
.Pe32Section
+ sizeof (EFI_PE32_SECTION
) - (UINTN
)FfsFile
;
2985 BaseToUpdate
= &XipBase
;
2990 // Not supported file type
2996 // Relocation doesn't exist
2998 if (ImageContext
.RelocationsStripped
) {
2999 Warning (NULL
, 0, 0, "Invalid", "The file %s has no .reloc section.", FileName
);
3004 // Relocation exist and rebase
3007 // Load and Relocate Image Data
3009 MemoryImagePointer
= (UINT8
*) malloc ((UINTN
) ImageContext
.ImageSize
+ ImageContext
.SectionAlignment
);
3010 if (MemoryImagePointer
== NULL
) {
3011 Error (NULL
, 0, 4001, "Resource", "memory cannot be allocated on rebase of %s", FileName
);
3012 return EFI_OUT_OF_RESOURCES
;
3014 memset ((VOID
*) MemoryImagePointer
, 0, (UINTN
) ImageContext
.ImageSize
+ ImageContext
.SectionAlignment
);
3015 ImageContext
.ImageAddress
= ((UINTN
) MemoryImagePointer
+ ImageContext
.SectionAlignment
- 1) & (~((INT64
)ImageContext
.SectionAlignment
- 1));
3017 Status
= PeCoffLoaderLoadImage (&ImageContext
);
3018 if (EFI_ERROR (Status
)) {
3019 Error (NULL
, 0, 3000, "Invalid", "LocateImage() call failed on rebase of %s", FileName
);
3020 free ((VOID
*) MemoryImagePointer
);
3024 ImageContext
.DestinationAddress
= NewPe32BaseAddress
;
3025 Status
= PeCoffLoaderRelocateImage (&ImageContext
);
3026 if (EFI_ERROR (Status
)) {
3027 Error (NULL
, 0, 3000, "Invalid", "RelocateImage() call failed on rebase of %s", FileName
);
3028 free ((VOID
*) MemoryImagePointer
);
3033 // Copy Relocated data to raw image file.
3035 SectionHeader
= (EFI_IMAGE_SECTION_HEADER
*) (
3038 sizeof (EFI_IMAGE_FILE_HEADER
) +
3039 ImgHdr
->Pe32
.FileHeader
.SizeOfOptionalHeader
3042 for (Index
= 0; Index
< ImgHdr
->Pe32
.FileHeader
.NumberOfSections
; Index
++, SectionHeader
++) {
3044 (UINT8
*) CurrentPe32Section
.Pe32Section
+ sizeof (EFI_COMMON_SECTION_HEADER
) + SectionHeader
->PointerToRawData
,
3045 (VOID
*) (UINTN
) (ImageContext
.ImageAddress
+ SectionHeader
->VirtualAddress
),
3046 SectionHeader
->SizeOfRawData
3050 free ((VOID
*) MemoryImagePointer
);
3051 MemoryImagePointer
= NULL
;
3052 if (PeFileBuffer
!= NULL
) {
3053 free (PeFileBuffer
);
3054 PeFileBuffer
= NULL
;
3058 // Update Image Base Address
3060 if (ImgHdr
->Pe32
.OptionalHeader
.Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
3061 ImgHdr
->Pe32
.OptionalHeader
.ImageBase
= (UINT32
) NewPe32BaseAddress
;
3062 } else if (ImgHdr
->Pe32Plus
.OptionalHeader
.Magic
== EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC
) {
3063 ImgHdr
->Pe32Plus
.OptionalHeader
.ImageBase
= NewPe32BaseAddress
;
3065 Error (NULL
, 0, 3000, "Invalid", "unknown PE magic signature %X in PE32 image %s",
3066 ImgHdr
->Pe32
.OptionalHeader
.Magic
,
3073 // Now update file checksum
3075 if (FfsFile
->Attributes
& FFS_ATTRIB_CHECKSUM
) {
3076 SavedState
= FfsFile
->State
;
3077 FfsFile
->IntegrityCheck
.Checksum
.File
= 0;
3079 FfsFile
->IntegrityCheck
.Checksum
.File
= CalculateChecksum8 (
3080 (UINT8
*) (FfsFile
+ 1),
3081 GetLength (FfsFile
->Size
) - sizeof (EFI_FFS_FILE_HEADER
)
3083 FfsFile
->State
= SavedState
;
3087 // Get this module function address from ModulePeMapFile and add them into FvMap file
3091 // Default use FileName as map file path
3093 if (PdbPointer
== NULL
) {
3094 PdbPointer
= FileName
;
3097 WriteMapFile (FvMapFile
, PdbPointer
, (EFI_GUID
*) FfsFile
, NewPe32BaseAddress
, &OrigImageContext
);
3100 if (FfsFile
->Type
!= EFI_FV_FILETYPE_SECURITY_CORE
&&
3101 FfsFile
->Type
!= EFI_FV_FILETYPE_PEI_CORE
&&
3102 FfsFile
->Type
!= EFI_FV_FILETYPE_PEIM
&&
3103 FfsFile
->Type
!= EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER
&&
3104 FfsFile
->Type
!= EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE
3107 // Only Peim code may have a TE section
3113 // Now process TE sections
3115 for (Index
= 1;; Index
++) {
3116 NewPe32BaseAddress
= 0;
3121 Status
= GetSectionByType (FfsFile
, EFI_SECTION_TE
, Index
, &CurrentPe32Section
);
3122 if (EFI_ERROR (Status
)) {
3127 // Calculate the TE base address, the FFS file base plus the offset of the TE section less the size stripped off
3130 TEImageHeader
= (EFI_TE_IMAGE_HEADER
*) ((UINT8
*) CurrentPe32Section
.Pe32Section
+ sizeof (EFI_COMMON_SECTION_HEADER
));
3133 // Initialize context, load image info.
3135 memset (&ImageContext
, 0, sizeof (ImageContext
));
3136 ImageContext
.Handle
= (VOID
*) TEImageHeader
;
3137 ImageContext
.ImageRead
= (PE_COFF_LOADER_READ_FILE
) FfsRebaseImageRead
;
3138 Status
= PeCoffLoaderGetImageInfo (&ImageContext
);
3139 if (EFI_ERROR (Status
)) {
3140 Error (NULL
, 0, 3000, "Invalid TeImage", "The input file is %s and the return status is %x", FileName
, (int) Status
);
3144 if (ImageContext
.Machine
== EFI_IMAGE_MACHINE_ARMT
) {
3149 // Keep Image Context for TE image in FV
3151 memcpy (&OrigImageContext
, &ImageContext
, sizeof (ImageContext
));
3154 // Get File PdbPointer
3156 PdbPointer
= PeCoffLoaderGetPdbPointer (ImageContext
.Handle
);
3159 // Set new rebased address.
3161 NewPe32BaseAddress
= XipBase
+ (UINTN
) TEImageHeader
+ sizeof (EFI_TE_IMAGE_HEADER
) \
3162 - TEImageHeader
->StrippedSize
- (UINTN
) FfsFile
;
3165 // if reloc is stripped, try to get the original efi image to get reloc info.
3167 if (ImageContext
.RelocationsStripped
) {
3169 // Construct the original efi file name
3171 strcpy (PeFileName
, FileName
);
3172 Cptr
= PeFileName
+ strlen (PeFileName
);
3173 while (*Cptr
!= '.') {
3178 Error (NULL
, 0, 3000, "Invalid", "The file %s has no .reloc section.", FileName
);
3187 PeFile
= fopen (PeFileName
, "rb");
3188 if (PeFile
== NULL
) {
3189 Warning (NULL
, 0, 0, "Invalid", "The file %s has no .reloc section.", FileName
);
3190 //Error (NULL, 0, 3000, "Invalid", "The file %s has no .reloc section.", FileName);
3191 //return EFI_ABORTED;
3194 // Get the file size
3196 PeFileSize
= _filelength (fileno (PeFile
));
3197 PeFileBuffer
= (UINT8
*) malloc (PeFileSize
);
3198 if (PeFileBuffer
== NULL
) {
3199 Error (NULL
, 0, 4001, "Resource", "memory cannot be allocated on rebase of %s", FileName
);
3200 return EFI_OUT_OF_RESOURCES
;
3205 fread (PeFileBuffer
, sizeof (UINT8
), PeFileSize
, PeFile
);
3211 // Append reloc section into TeImage
3213 ImageContext
.Handle
= PeFileBuffer
;
3214 Status
= PeCoffLoaderGetImageInfo (&ImageContext
);
3215 if (EFI_ERROR (Status
)) {
3216 Error (NULL
, 0, 3000, "Invalid TeImage", "The input file is %s and the return status is %x", FileName
, (int) Status
);
3219 ImageContext
.RelocationsStripped
= FALSE
;
3223 // Relocation doesn't exist
3225 if (ImageContext
.RelocationsStripped
) {
3226 Warning (NULL
, 0, 0, "Invalid", "The file %s has no .reloc section.", FileName
);
3231 // Relocation exist and rebase
3234 // Load and Relocate Image Data
3236 MemoryImagePointer
= (UINT8
*) malloc ((UINTN
) ImageContext
.ImageSize
+ ImageContext
.SectionAlignment
);
3237 if (MemoryImagePointer
== NULL
) {
3238 Error (NULL
, 0, 4001, "Resource", "memory cannot be allocated on rebase of %s", FileName
);
3239 return EFI_OUT_OF_RESOURCES
;
3241 memset ((VOID
*) MemoryImagePointer
, 0, (UINTN
) ImageContext
.ImageSize
+ ImageContext
.SectionAlignment
);
3242 ImageContext
.ImageAddress
= ((UINTN
) MemoryImagePointer
+ ImageContext
.SectionAlignment
- 1) & (~(ImageContext
.SectionAlignment
- 1));
3244 Status
= PeCoffLoaderLoadImage (&ImageContext
);
3245 if (EFI_ERROR (Status
)) {
3246 Error (NULL
, 0, 3000, "Invalid", "LocateImage() call failed on rebase of %s", FileName
);
3247 free ((VOID
*) MemoryImagePointer
);
3251 // Reloacate TeImage
3253 ImageContext
.DestinationAddress
= NewPe32BaseAddress
;
3254 Status
= PeCoffLoaderRelocateImage (&ImageContext
);
3255 if (EFI_ERROR (Status
)) {
3256 Error (NULL
, 0, 3000, "Invalid", "RelocateImage() call failed on rebase of TE image %s", FileName
);
3257 free ((VOID
*) MemoryImagePointer
);
3262 // Copy the relocated image into raw image file.
3264 SectionHeader
= (EFI_IMAGE_SECTION_HEADER
*) (TEImageHeader
+ 1);
3265 for (Index
= 0; Index
< TEImageHeader
->NumberOfSections
; Index
++, SectionHeader
++) {
3266 if (!ImageContext
.IsTeImage
) {
3268 (UINT8
*) TEImageHeader
+ sizeof (EFI_TE_IMAGE_HEADER
) - TEImageHeader
->StrippedSize
+ SectionHeader
->PointerToRawData
,
3269 (VOID
*) (UINTN
) (ImageContext
.ImageAddress
+ SectionHeader
->VirtualAddress
),
3270 SectionHeader
->SizeOfRawData
3274 (UINT8
*) TEImageHeader
+ sizeof (EFI_TE_IMAGE_HEADER
) - TEImageHeader
->StrippedSize
+ SectionHeader
->PointerToRawData
,
3275 (VOID
*) (UINTN
) (ImageContext
.ImageAddress
+ sizeof (EFI_TE_IMAGE_HEADER
) - TEImageHeader
->StrippedSize
+ SectionHeader
->VirtualAddress
),
3276 SectionHeader
->SizeOfRawData
3282 // Free the allocated memory resource
3284 free ((VOID
*) MemoryImagePointer
);
3285 MemoryImagePointer
= NULL
;
3286 if (PeFileBuffer
!= NULL
) {
3287 free (PeFileBuffer
);
3288 PeFileBuffer
= NULL
;
3292 // Update Image Base Address
3294 TEImageHeader
->ImageBase
= NewPe32BaseAddress
;
3297 // Now update file checksum
3299 if (FfsFile
->Attributes
& FFS_ATTRIB_CHECKSUM
) {
3300 SavedState
= FfsFile
->State
;
3301 FfsFile
->IntegrityCheck
.Checksum
.File
= 0;
3303 FfsFile
->IntegrityCheck
.Checksum
.File
= CalculateChecksum8 (
3304 (UINT8
*)(FfsFile
+ 1),
3305 GetLength (FfsFile
->Size
) - sizeof (EFI_FFS_FILE_HEADER
)
3307 FfsFile
->State
= SavedState
;
3310 // Get this module function address from ModulePeMapFile and add them into FvMap file
3314 // Default use FileName as map file path
3316 if (PdbPointer
== NULL
) {
3317 PdbPointer
= FileName
;
3323 (EFI_GUID
*) FfsFile
,
3333 FindApResetVectorPosition (
3334 IN MEMORY_FILE
*FvImage
,
3339 Routine Description:
3341 Find the position in this FvImage to place Ap reset vector.
3345 FvImage Memory file for the FV memory image.
3346 Pointer Pointer to pointer to position.
3350 EFI_NOT_FOUND - No satisfied position is found.
3351 EFI_SUCCESS - The suitable position is return.
3355 EFI_FFS_FILE_HEADER
*PadFile
;
3361 for (Index
= 1; ;Index
++) {
3363 // Find Pad File to add ApResetVector info
3365 Status
= GetFileByType (EFI_FV_FILETYPE_FFS_PAD
, Index
, &PadFile
);
3366 if (EFI_ERROR (Status
) || (PadFile
== NULL
)) {
3368 // No Pad file to be found.
3373 // Get Pad file size.
3375 FileLength
= (*(UINT32
*)(PadFile
->Size
)) & 0x00FFFFFF;
3376 FileLength
= (FileLength
+ EFI_FFS_FILE_HEADER_ALIGNMENT
- 1) & ~(EFI_FFS_FILE_HEADER_ALIGNMENT
- 1);
3378 // FixPoint must be align on 0x1000 relative to FvImage Header
3380 FixPoint
= (UINT8
*) PadFile
+ sizeof (EFI_FFS_FILE_HEADER
);
3381 FixPoint
= FixPoint
+ 0x1000 - (((UINTN
) FixPoint
- (UINTN
) FvImage
->FileImage
) & 0xFFF);
3383 // FixPoint be larger at the last place of one fv image.
3385 while (((UINTN
) FixPoint
+ SIZEOF_STARTUP_DATA_ARRAY
- (UINTN
) PadFile
) <= FileLength
) {
3390 if ((UINTN
) FixPoint
< ((UINTN
) PadFile
+ sizeof (EFI_FFS_FILE_HEADER
))) {
3392 // No alignment FixPoint in this Pad File.
3397 if ((UINTN
) FvImage
->Eof
- (UINTN
)FixPoint
<= 0x20000) {
3399 // Find the position to place ApResetVector
3401 *Pointer
= FixPoint
;
3406 return EFI_NOT_FOUND
;
3411 IN MEMORY_FILE
*InfFile
,
3412 OUT CAP_INFO
*CapInfo
3416 Routine Description:
3418 This function parses a Cap.INF file and copies info into a CAP_INFO structure.
3422 InfFile Memory file image.
3423 CapInfo Information read from INF file.
3427 EFI_SUCCESS INF file information successfully retrieved.
3428 EFI_ABORTED INF file has an invalid format.
3429 EFI_NOT_FOUND A required string was not found in the INF file.
3432 CHAR8 Value
[_MAX_PATH
];
3434 UINTN Index
, Number
;
3438 // Initialize Cap info
3440 // memset (CapInfo, 0, sizeof (CAP_INFO));
3444 // Read the Capsule Guid
3446 Status
= FindToken (InfFile
, OPTIONS_SECTION_STRING
, EFI_CAPSULE_GUID_STRING
, 0, Value
);
3447 if (Status
== EFI_SUCCESS
) {
3449 // Get the Capsule Guid
3451 Status
= StringToGuid (Value
, &CapInfo
->CapGuid
);
3452 if (EFI_ERROR (Status
)) {
3453 Error (NULL
, 0, 2000, "Invalid parameter", "%s = %s", EFI_CAPSULE_GUID_STRING
, Value
);
3456 DebugMsg (NULL
, 0, 9, "Capsule Guid", "%s = %s", EFI_CAPSULE_GUID_STRING
, Value
);
3460 // Read the Capsule Header Size
3462 Status
= FindToken (InfFile
, OPTIONS_SECTION_STRING
, EFI_CAPSULE_HEADER_SIZE_STRING
, 0, Value
);
3463 if (Status
== EFI_SUCCESS
) {
3464 Status
= AsciiStringToUint64 (Value
, FALSE
, &Value64
);
3465 if (EFI_ERROR (Status
)) {
3466 Error (NULL
, 0, 2000, "Invalid parameter", "%s = %s", EFI_CAPSULE_HEADER_SIZE_STRING
, Value
);
3469 CapInfo
->HeaderSize
= (UINT32
) Value64
;
3470 DebugMsg (NULL
, 0, 9, "Capsule Header size", "%s = %s", EFI_CAPSULE_HEADER_SIZE_STRING
, Value
);
3474 // Read the Capsule Flag
3476 Status
= FindToken (InfFile
, OPTIONS_SECTION_STRING
, EFI_CAPSULE_FLAGS_STRING
, 0, Value
);
3477 if (Status
== EFI_SUCCESS
) {
3478 if (strstr (Value
, "PopulateSystemTable") != NULL
) {
3479 CapInfo
->Flags
|= CAPSULE_FLAGS_PERSIST_ACROSS_RESET
| CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE
;
3480 if (strstr (Value
, "InitiateReset") != NULL
) {
3481 CapInfo
->Flags
|= CAPSULE_FLAGS_INITIATE_RESET
;
3483 } else if (strstr (Value
, "PersistAcrossReset") != NULL
) {
3484 CapInfo
->Flags
|= CAPSULE_FLAGS_PERSIST_ACROSS_RESET
;
3485 if (strstr (Value
, "InitiateReset") != NULL
) {
3486 CapInfo
->Flags
|= CAPSULE_FLAGS_INITIATE_RESET
;
3489 Error (NULL
, 0, 2000, "Invalid parameter", "invalid Flag setting for %s.", EFI_CAPSULE_FLAGS_STRING
);
3492 DebugMsg (NULL
, 0, 9, "Capsule Flag", Value
);
3496 // Read Capsule File name
3498 Status
= FindToken (InfFile
, OPTIONS_SECTION_STRING
, EFI_FILE_NAME_STRING
, 0, Value
);
3499 if (Status
== EFI_SUCCESS
) {
3501 // Get output file name
3503 strcpy (CapInfo
->CapName
, Value
);
3507 // Read the Capsule FileImage
3510 for (Index
= 0; Index
< MAX_NUMBER_OF_FILES_IN_CAP
; Index
++) {
3511 if (CapInfo
->CapFiles
[Index
][0] != '\0') {
3515 // Read the capsule file name
3517 Status
= FindToken (InfFile
, FILES_SECTION_STRING
, EFI_FILE_NAME_STRING
, Number
++, Value
);
3519 if (Status
== EFI_SUCCESS
) {
3523 strcpy (CapInfo
->CapFiles
[Index
], Value
);
3524 DebugMsg (NULL
, 0, 9, "Capsule component file", "the %uth file name is %s", (unsigned) Index
, CapInfo
->CapFiles
[Index
]);
3531 Warning (NULL
, 0, 0, "Capsule components are not specified.", NULL
);
3539 IN CHAR8
*InfFileImage
,
3540 IN UINTN InfFileSize
,
3541 IN CHAR8
*CapFileName
3545 Routine Description:
3547 This is the main function which will be called from application to create UEFI Capsule image.
3551 InfFileImage Buffer containing the INF file contents.
3552 InfFileSize Size of the contents of the InfFileImage buffer.
3553 CapFileName Requested name for the Cap file.
3557 EFI_SUCCESS Function completed successfully.
3558 EFI_OUT_OF_RESOURCES Could not allocate required resources.
3559 EFI_ABORTED Error encountered.
3560 EFI_INVALID_PARAMETER A required parameter was NULL.
3566 EFI_CAPSULE_HEADER
*CapsuleHeader
;
3567 MEMORY_FILE InfMemoryFile
;
3573 if (InfFileImage
!= NULL
) {
3575 // Initialize file structures
3577 InfMemoryFile
.FileImage
= InfFileImage
;
3578 InfMemoryFile
.CurrentFilePointer
= InfFileImage
;
3579 InfMemoryFile
.Eof
= InfFileImage
+ InfFileSize
;
3582 // Parse the Cap inf file for header information
3584 Status
= ParseCapInf (&InfMemoryFile
, &mCapDataInfo
);
3585 if (Status
!= EFI_SUCCESS
) {
3590 if (mCapDataInfo
.HeaderSize
== 0) {
3592 // make header size align 16 bytes.
3594 mCapDataInfo
.HeaderSize
= sizeof (EFI_CAPSULE_HEADER
);
3595 mCapDataInfo
.HeaderSize
= (mCapDataInfo
.HeaderSize
+ 0xF) & ~0xF;
3598 if (mCapDataInfo
.HeaderSize
< sizeof (EFI_CAPSULE_HEADER
)) {
3599 Error (NULL
, 0, 2000, "Invalid parameter", "The specified HeaderSize cannot be less than the size of EFI_CAPSULE_HEADER.");
3600 return EFI_INVALID_PARAMETER
;
3603 if (CapFileName
== NULL
&& mCapDataInfo
.CapName
[0] != '\0') {
3604 CapFileName
= mCapDataInfo
.CapName
;
3607 if (CapFileName
== NULL
) {
3608 Error (NULL
, 0, 2001, "Missing required argument", "Output Capsule file name");
3609 return EFI_INVALID_PARAMETER
;
3613 // Set Default Capsule Guid value
3615 if (CompareGuid (&mCapDataInfo
.CapGuid
, &mZeroGuid
) == 0) {
3616 memcpy (&mCapDataInfo
.CapGuid
, &mDefaultCapsuleGuid
, sizeof (EFI_GUID
));
3619 // Calculate the size of capsule image.
3623 CapSize
= mCapDataInfo
.HeaderSize
;
3624 while (mCapDataInfo
.CapFiles
[Index
][0] != '\0') {
3625 fpin
= fopen (mCapDataInfo
.CapFiles
[Index
], "rb");
3627 Error (NULL
, 0, 0001, "Error opening file", mCapDataInfo
.CapFiles
[Index
]);
3630 FileSize
= _filelength (fileno (fpin
));
3631 CapSize
+= FileSize
;
3637 // Allocate buffer for capsule image.
3639 CapBuffer
= (UINT8
*) malloc (CapSize
);
3640 if (CapBuffer
== NULL
) {
3641 Error (NULL
, 0, 4001, "Resource", "memory cannot be allocated for creating the capsule.");
3642 return EFI_OUT_OF_RESOURCES
;
3646 // Initialize the capsule header to zero
3648 memset (CapBuffer
, 0, mCapDataInfo
.HeaderSize
);
3651 // create capsule header and get capsule body
3653 CapsuleHeader
= (EFI_CAPSULE_HEADER
*) CapBuffer
;
3654 memcpy (&CapsuleHeader
->CapsuleGuid
, &mCapDataInfo
.CapGuid
, sizeof (EFI_GUID
));
3655 CapsuleHeader
->HeaderSize
= mCapDataInfo
.HeaderSize
;
3656 CapsuleHeader
->Flags
= mCapDataInfo
.Flags
;
3657 CapsuleHeader
->CapsuleImageSize
= CapSize
;
3661 CapSize
= CapsuleHeader
->HeaderSize
;
3662 while (mCapDataInfo
.CapFiles
[Index
][0] != '\0') {
3663 fpin
= fopen (mCapDataInfo
.CapFiles
[Index
], "rb");
3665 Error (NULL
, 0, 0001, "Error opening file", mCapDataInfo
.CapFiles
[Index
]);
3669 FileSize
= _filelength (fileno (fpin
));
3670 fread (CapBuffer
+ CapSize
, 1, FileSize
, fpin
);
3673 CapSize
+= FileSize
;
3677 // write capsule data into the output file
3679 fpout
= fopen (CapFileName
, "wb");
3680 if (fpout
== NULL
) {
3681 Error (NULL
, 0, 0001, "Error opening file", CapFileName
);
3686 fwrite (CapBuffer
, 1, CapSize
, fpout
);
3689 VerboseMsg ("The size of the generated capsule image is %u bytes", (unsigned) CapSize
);