3 Copyright (c) 2004 - 2009, 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
;
164 IN MEMORY_FILE
*InfFile
,
171 This function parses a FV.INF file and copies info into a FV_INFO structure.
175 InfFile Memory file image.
176 FvInfo Information read from INF file.
180 EFI_SUCCESS INF file information successfully retrieved.
181 EFI_ABORTED INF file has an invalid format.
182 EFI_NOT_FOUND A required string was not found in the INF file.
185 CHAR8 Value
[_MAX_PATH
];
193 // Read the FV base address
195 if (!mFvDataInfo
.BaseAddressSet
) {
196 Status
= FindToken (InfFile
, OPTIONS_SECTION_STRING
, EFI_FV_BASE_ADDRESS_STRING
, 0, Value
);
197 if (Status
== EFI_SUCCESS
) {
199 // Get the base address
201 Status
= AsciiStringToUint64 (Value
, FALSE
, &Value64
);
202 if (EFI_ERROR (Status
)) {
203 Error (NULL
, 0, 2000, "Invalid parameter", "%s = %s", EFI_FV_BASE_ADDRESS_STRING
, Value
);
206 DebugMsg (NULL
, 0, 9, "rebase address", "%s = %s", EFI_FV_BASE_ADDRESS_STRING
, Value
);
208 FvInfo
->BaseAddress
= Value64
;
213 // Read the FV File System Guid
215 if (!FvInfo
->FvFileSystemGuidSet
) {
216 Status
= FindToken (InfFile
, OPTIONS_SECTION_STRING
, EFI_FV_FILESYSTEMGUID_STRING
, 0, Value
);
217 if (Status
== EFI_SUCCESS
) {
219 // Get the guid value
221 Status
= StringToGuid (Value
, &GuidValue
);
222 if (EFI_ERROR (Status
)) {
223 Error (NULL
, 0, 2000, "Invalid parameter", "%s = %s", EFI_FV_FILESYSTEMGUID_STRING
, Value
);
226 memcpy (&FvInfo
->FvFileSystemGuid
, &GuidValue
, sizeof (EFI_GUID
));
227 FvInfo
->FvFileSystemGuidSet
= TRUE
;
232 // Read the FV Name Guid
234 if (!FvInfo
->FvNameGuidSet
) {
235 Status
= FindToken (InfFile
, ATTRIBUTES_SECTION_STRING
, EFI_FV_NAMEGUID_STRING
, 0, Value
);
236 if (Status
== EFI_SUCCESS
) {
238 // Get the guid value
240 Status
= StringToGuid (Value
, &GuidValue
);
241 if (EFI_ERROR (Status
)) {
242 Error (NULL
, 0, 2000, "Invalid parameter", "%s = %s", EFI_FV_NAMEGUID_STRING
, Value
);
245 memcpy (&FvInfo
->FvNameGuid
, &GuidValue
, sizeof (EFI_GUID
));
246 FvInfo
->FvNameGuidSet
= TRUE
;
251 // Read the FV file name
253 Status
= FindToken (InfFile
, OPTIONS_SECTION_STRING
, EFI_FV_FILE_NAME_STRING
, 0, Value
);
254 if (Status
== EFI_SUCCESS
) {
256 // copy the file name
258 strcpy (FvInfo
->FvName
, Value
);
264 for (Index
= 0; Index
< sizeof (mFvbAttributeName
)/sizeof (CHAR8
*); Index
++) {
265 if ((mFvbAttributeName
[Index
] != NULL
) && \
266 (FindToken (InfFile
, ATTRIBUTES_SECTION_STRING
, mFvbAttributeName
[Index
], 0, Value
) == EFI_SUCCESS
)) {
267 if ((strcmp (Value
, TRUE_STRING
) == 0) || (strcmp (Value
, ONE_STRING
) == 0)) {
268 FvInfo
->FvAttributes
|= 1 << Index
;
269 } else if ((strcmp (Value
, FALSE_STRING
) != 0) && (strcmp (Value
, ZERO_STRING
) != 0)) {
270 Error (NULL
, 0, 2000, "Invalid parameter", "%s expected %s | %s", mFvbAttributeName
[Index
], TRUE_STRING
, FALSE_STRING
);
279 for (Index
= 0; Index
< sizeof (mFvbAlignmentName
)/sizeof (CHAR8
*); Index
++) {
280 if (FindToken (InfFile
, ATTRIBUTES_SECTION_STRING
, mFvbAlignmentName
[Index
], 0, Value
) == EFI_SUCCESS
) {
281 if (strcmp (Value
, TRUE_STRING
) == 0) {
282 FvInfo
->FvAttributes
|= Index
<< 16;
283 DebugMsg (NULL
, 0, 9, "FV file alignment", "Align = %s", mFvbAlignmentName
[Index
]);
292 for (Index
= 0; Index
< MAX_NUMBER_OF_FV_BLOCKS
; Index
++) {
293 if (FvInfo
->FvBlocks
[Index
].Length
== 0) {
297 Status
= FindToken (InfFile
, OPTIONS_SECTION_STRING
, EFI_BLOCK_SIZE_STRING
, Index
, Value
);
299 if (Status
== EFI_SUCCESS
) {
301 // Update the size of block
303 Status
= AsciiStringToUint64 (Value
, FALSE
, &Value64
);
304 if (EFI_ERROR (Status
)) {
305 Error (NULL
, 0, 2000, "Invalid parameter", "%s = %s", EFI_BLOCK_SIZE_STRING
, Value
);
309 FvInfo
->FvBlocks
[Index
].Length
= (UINT32
) Value64
;
310 DebugMsg (NULL
, 0, 9, "FV Block Size", "%s = %s", EFI_BLOCK_SIZE_STRING
, Value
);
313 // If there is no blocks size, but there is the number of block, then we have a mismatched pair
314 // and should return an error.
316 Status
= FindToken (InfFile
, OPTIONS_SECTION_STRING
, EFI_NUM_BLOCKS_STRING
, Index
, Value
);
317 if (!EFI_ERROR (Status
)) {
318 Error (NULL
, 0, 2000, "Invalid parameter", "both %s and %s must be specified.", EFI_NUM_BLOCKS_STRING
, EFI_BLOCK_SIZE_STRING
);
329 // Read blocks number
331 Status
= FindToken (InfFile
, OPTIONS_SECTION_STRING
, EFI_NUM_BLOCKS_STRING
, Index
, Value
);
333 if (Status
== EFI_SUCCESS
) {
335 // Update the number of blocks
337 Status
= AsciiStringToUint64 (Value
, FALSE
, &Value64
);
338 if (EFI_ERROR (Status
)) {
339 Error (NULL
, 0, 2000, "Invalid parameter", "%s = %s", EFI_NUM_BLOCKS_STRING
, Value
);
343 FvInfo
->FvBlocks
[Index
].NumBlocks
= (UINT32
) Value64
;
344 DebugMsg (NULL
, 0, 9, "FV Block Number", "%s = %s", EFI_NUM_BLOCKS_STRING
, Value
);
350 Error (NULL
, 0, 2001, "Missing required argument", "block size.");
358 for (Number
= 0; Number
< MAX_NUMBER_OF_FILES_IN_FV
; Number
++) {
359 if (FvInfo
->FvFiles
[Number
][0] == '\0') {
364 for (Index
= 0; Index
< MAX_NUMBER_OF_FILES_IN_FV
; Index
++) {
366 // Read the FFS file list
368 Status
= FindToken (InfFile
, FILES_SECTION_STRING
, EFI_FILE_NAME_STRING
, Index
, Value
);
370 if (Status
== EFI_SUCCESS
) {
374 strcpy (FvInfo
->FvFiles
[Number
+ Index
], Value
);
375 DebugMsg (NULL
, 0, 9, "FV component file", "the %uth name is %s", (unsigned) Index
, Value
);
381 if ((Index
+ Number
) == 0) {
382 Warning (NULL
, 0, 0, "FV components are not specified.", NULL
);
390 IN EFI_FFS_FILE_HEADER
*FfsFile
,
391 IN EFI_FIRMWARE_VOLUME_HEADER
*FvHeader
397 This function changes the FFS file attributes based on the erase polarity
398 of the FV. Update the reserved bits of State to EFI_FVB2_ERASE_POLARITY.
411 if (FvHeader
->Attributes
& EFI_FVB2_ERASE_POLARITY
) {
412 FfsFile
->State
= (UINT8
)~(FfsFile
->State
);
413 // FfsFile->State |= ~(UINT8) EFI_FILE_ALL_STATE_BITS;
419 IN EFI_FFS_FILE_HEADER
*FfsFile
,
420 IN OUT UINT32
*Alignment
426 This function determines the alignment of the FFS input file from the file
431 FfsFile FFS file to parse
432 Alignment The minimum required alignment offset of the FFS file
436 EFI_SUCCESS The function completed successfully.
437 EFI_INVALID_PARAMETER One of the input parameters was invalid.
438 EFI_ABORTED An error occurred.
443 // Verify input parameters.
445 if (FfsFile
== NULL
|| Alignment
== NULL
) {
446 return EFI_INVALID_PARAMETER
;
449 switch ((FfsFile
->Attributes
>> 3) & 0x07) {
453 // 8 byte alignment, mini alignment requirement for FFS file.
467 // 128 byte alignment
474 // 512 byte alignment
495 // 32K byte alignment
502 // 64K byte alignment
516 IN OUT MEMORY_FILE
*FvImage
,
517 IN UINT32 DataAlignment
,
519 IN EFI_FIRMWARE_VOLUME_EXT_HEADER
*ExtHeader
525 This function adds a pad file to the FV image if it required to align the
526 data of the next file.
530 FvImage The memory image of the FV to add it to.
531 The current offset must be valid.
532 DataAlignment The data alignment of the next FFS file.
533 FvEnd End of the empty data in FvImage.
534 ExtHeader PI FvExtHeader Optional
538 EFI_SUCCESS The function completed successfully.
539 EFI_INVALID_PARAMETER One of the input parameters was invalid.
540 EFI_OUT_OF_RESOURCES Insufficient resources exist in the FV to complete
545 EFI_FFS_FILE_HEADER
*PadFile
;
549 // Verify input parameters.
551 if (FvImage
== NULL
) {
552 return EFI_INVALID_PARAMETER
;
556 // Check if a pad file is necessary
558 if ((ExtHeader
== NULL
) && (((UINTN
) FvImage
->CurrentFilePointer
- (UINTN
) FvImage
->FileImage
+ sizeof (EFI_FFS_FILE_HEADER
)) % DataAlignment
== 0)) {
563 // Calculate the pad file size
566 // This is the earliest possible valid offset (current plus pad file header
567 // plus the next file header)
569 PadFileSize
= (UINTN
) FvImage
->CurrentFilePointer
- (UINTN
) FvImage
->FileImage
+ (sizeof (EFI_FFS_FILE_HEADER
) * 2);
572 // Add whatever it takes to get to the next aligned address
574 while ((PadFileSize
% DataAlignment
) != 0) {
578 // Subtract the next file header size
580 PadFileSize
-= sizeof (EFI_FFS_FILE_HEADER
);
583 // Subtract the starting offset to get size
585 PadFileSize
-= (UINTN
) FvImage
->CurrentFilePointer
- (UINTN
) FvImage
->FileImage
;
588 // Append extension header size
590 if (ExtHeader
!= NULL
) {
591 PadFileSize
= PadFileSize
+ ExtHeader
->ExtHeaderSize
;
595 // Verify that we have enough space for the file header
597 if (((UINTN
) FvImage
->CurrentFilePointer
+ PadFileSize
) > (UINTN
) FvEnd
) {
598 return EFI_OUT_OF_RESOURCES
;
602 // Write pad file header
604 PadFile
= (EFI_FFS_FILE_HEADER
*) FvImage
->CurrentFilePointer
;
607 // Write PadFile FFS header with PadType, don't need to set PAD file guid in its header.
609 PadFile
->Type
= EFI_FV_FILETYPE_FFS_PAD
;
610 PadFile
->Attributes
= 0;
613 // Write pad file size (calculated size minus next file header size)
615 PadFile
->Size
[0] = (UINT8
) (PadFileSize
& 0xFF);
616 PadFile
->Size
[1] = (UINT8
) ((PadFileSize
>> 8) & 0xFF);
617 PadFile
->Size
[2] = (UINT8
) ((PadFileSize
>> 16) & 0xFF);
620 // Fill in checksums and state, they must be 0 for checksumming.
622 PadFile
->IntegrityCheck
.Checksum
.Header
= 0;
623 PadFile
->IntegrityCheck
.Checksum
.File
= 0;
625 PadFile
->IntegrityCheck
.Checksum
.Header
= CalculateChecksum8 ((UINT8
*) PadFile
, sizeof (EFI_FFS_FILE_HEADER
));
626 PadFile
->IntegrityCheck
.Checksum
.File
= FFS_FIXED_CHECKSUM
;
628 PadFile
->State
= EFI_FILE_HEADER_CONSTRUCTION
| EFI_FILE_HEADER_VALID
| EFI_FILE_DATA_VALID
;
630 (EFI_FFS_FILE_HEADER
*) PadFile
,
631 (EFI_FIRMWARE_VOLUME_HEADER
*) FvImage
->FileImage
635 // Update the current FV pointer
637 FvImage
->CurrentFilePointer
+= PadFileSize
;
639 if (ExtHeader
!= NULL
) {
641 // Copy Fv Extension Header and Set Fv Extension header offset
643 memcpy (PadFile
+ 1, ExtHeader
, ExtHeader
->ExtHeaderSize
);
644 ((EFI_FIRMWARE_VOLUME_HEADER
*) FvImage
->FileImage
)->ExtHeaderOffset
= (UINT16
) ((UINTN
) (PadFile
+ 1) - (UINTN
) FvImage
->FileImage
);
646 // Make next file start at QWord Boundry
648 while (((UINTN
) FvImage
->CurrentFilePointer
& (EFI_FFS_FILE_HEADER_ALIGNMENT
- 1)) != 0) {
649 FvImage
->CurrentFilePointer
++;
658 IN EFI_FFS_FILE_HEADER
*FileBuffer
664 This function checks the header to validate if it is a VTF file
668 FileBuffer Buffer in which content of a file has been read.
672 TRUE If this is a VTF file
673 FALSE If this is not a VTF file
677 if (!memcmp (&FileBuffer
->Name
, &mEfiFirmwareVolumeTopFileGuid
, sizeof (EFI_GUID
))) {
686 IN OUT
FILE *FvMapFile
,
688 IN EFI_GUID
*FileGuidPtr
,
689 IN EFI_PHYSICAL_ADDRESS ImageBaseAddress
,
690 IN PE_COFF_LOADER_IMAGE_CONTEXT
*pImageContext
696 This function gets the basic debug information (entrypoint, baseaddress, .text, .data section base address)
697 from PE/COFF image and abstracts Pe Map file information and add them into FvMap file for Debug.
701 FvMapFile A pointer to FvMap File
702 FileName Ffs File PathName
703 FileGuidPtr Guid Value of Ffs file
704 ImageBaseAddress PeImage Base Address.
705 pImageContext Image Context Information.
709 EFI_SUCCESS Added required map information.
713 CHAR8 PeMapFileName
[_MAX_PATH
];
715 CHAR8 FileGuidName
[MAX_LINE_LEN
];
717 CHAR8 Line
[MAX_LINE_LEN
];
718 CHAR8 KeyWord
[MAX_LINE_LEN
];
719 CHAR8 FunctionName
[MAX_LINE_LEN
];
720 EFI_PHYSICAL_ADDRESS FunctionAddress
;
722 CHAR8 FunctionTypeName
[MAX_LINE_LEN
];
724 UINT32 AddressOfEntryPoint
;
726 EFI_IMAGE_OPTIONAL_HEADER_UNION
*ImgHdr
;
727 EFI_TE_IMAGE_HEADER
*TEImageHeader
;
728 EFI_IMAGE_SECTION_HEADER
*SectionHeader
;
729 unsigned long long TempLongAddress
;
731 // Init local variable
735 // Print FileGuid to string buffer.
737 PrintGuidToBuffer (FileGuidPtr
, (UINT8
*)FileGuidName
, MAX_LINE_LEN
, TRUE
);
740 // Construct Map file Name
742 strcpy (PeMapFileName
, FileName
);
745 // Change '\\' to '/', unified path format.
747 Cptr
= PeMapFileName
;
748 while (*Cptr
!= '\0') {
750 *Cptr
= FILE_SEP_CHAR
;
758 Cptr
= PeMapFileName
+ strlen (PeMapFileName
);
759 while ((*Cptr
!= '.') && (Cptr
>= PeMapFileName
)) {
762 if (Cptr
< PeMapFileName
) {
763 return EFI_NOT_FOUND
;
775 while ((*Cptr
!= FILE_SEP_CHAR
) && (Cptr
>= PeMapFileName
)) {
779 strcpy (KeyWord
, Cptr
+ 1);
783 // AddressOfEntryPoint and Offset in Image
785 if (!pImageContext
->IsTeImage
) {
786 ImgHdr
= (EFI_IMAGE_OPTIONAL_HEADER_UNION
*) ((UINT8
*) pImageContext
->Handle
+ pImageContext
->PeCoffHeaderOffset
);
787 AddressOfEntryPoint
= ImgHdr
->Pe32
.OptionalHeader
.AddressOfEntryPoint
;
789 SectionHeader
= (EFI_IMAGE_SECTION_HEADER
*) (
792 sizeof (EFI_IMAGE_FILE_HEADER
) +
793 ImgHdr
->Pe32
.FileHeader
.SizeOfOptionalHeader
795 Index
= ImgHdr
->Pe32
.FileHeader
.NumberOfSections
;
797 TEImageHeader
= (EFI_TE_IMAGE_HEADER
*) pImageContext
->Handle
;
798 AddressOfEntryPoint
= TEImageHeader
->AddressOfEntryPoint
;
799 Offset
= TEImageHeader
->StrippedSize
- sizeof (EFI_TE_IMAGE_HEADER
);
800 SectionHeader
= (EFI_IMAGE_SECTION_HEADER
*) (TEImageHeader
+ 1);
801 Index
= TEImageHeader
->NumberOfSections
;
805 // module information output
807 if (ImageBaseAddress
== 0) {
808 fprintf (FvMapFile
, "%s (dummy) (", KeyWord
);
809 fprintf (FvMapFile
, "BaseAddress=%08llx, ", (unsigned long long) ImageBaseAddress
);
811 fprintf (FvMapFile
, "%s (", KeyWord
);
812 fprintf (FvMapFile
, "BaseAddress=%08llx, ", (unsigned long long) (ImageBaseAddress
+ Offset
));
814 fprintf (FvMapFile
, "EntryPoint=%08llx, ", (unsigned long long) (ImageBaseAddress
+ AddressOfEntryPoint
));
815 fprintf (FvMapFile
, "GUID=%s", FileGuidName
);
816 fprintf (FvMapFile
, ")\n");
818 for (; Index
> 0; Index
--, SectionHeader
++) {
819 if (stricmp ((CHAR8
*)SectionHeader
->Name
, ".text") == 0) {
820 fprintf (FvMapFile
, ".textbaseaddress=%08llx ", (unsigned long long) (ImageBaseAddress
+ SectionHeader
->VirtualAddress
));
821 } else if (stricmp ((CHAR8
*)SectionHeader
->Name
, ".data") == 0) {
822 fprintf (FvMapFile
, ".databaseaddress=%08llx ", (unsigned long long) (ImageBaseAddress
+ SectionHeader
->VirtualAddress
));
825 fprintf (FvMapFile
, "\n\n");
830 PeMapFile
= fopen (PeMapFileName
, "r");
831 if (PeMapFile
== NULL
) {
832 // fprintf (stdout, "can't open %s file to reading\n", PeMapFileName);
835 VerboseMsg ("The map file is %s", PeMapFileName
);
838 // Output Functions information into Fv Map file
840 while (fgets (Line
, MAX_LINE_LEN
, PeMapFile
) != NULL
) {
844 if (Line
[0] == 0x0a) {
849 // By Address and Static keyword
851 if (FunctionType
== 0) {
852 sscanf (Line
, "%s", KeyWord
);
853 if (stricmp (KeyWord
, "Address") == 0) {
858 fgets (Line
, MAX_LINE_LEN
, PeMapFile
);
859 } else if (stricmp (KeyWord
, "Static") == 0) {
861 // static function list
864 fgets (Line
, MAX_LINE_LEN
, PeMapFile
);
869 // Printf Function Information
871 if (FunctionType
== 1) {
872 sscanf (Line
, "%s %s %llx %s", KeyWord
, FunctionName
, &TempLongAddress
, FunctionTypeName
);
873 FunctionAddress
= (UINT64
) TempLongAddress
;
874 if (FunctionTypeName
[1] == '\0' && (FunctionTypeName
[0] == 'f' || FunctionTypeName
[0] == 'F')) {
875 fprintf (FvMapFile
, " %016llx ", (unsigned long long) (ImageBaseAddress
+ FunctionAddress
));
876 fprintf (FvMapFile
, "(%08llx) F ", (unsigned long long) (FunctionAddress
- Offset
));
877 fprintf (FvMapFile
, "%s\n", FunctionName
);
879 fprintf (FvMapFile
, " %016llx ", (unsigned long long) (ImageBaseAddress
+ FunctionAddress
));
880 fprintf (FvMapFile
, "(%08llx) ", (unsigned long long) (FunctionAddress
- Offset
));
881 fprintf (FvMapFile
, "%s\n", FunctionName
);
883 } else if (FunctionType
== 2) {
884 sscanf (Line
, "%s %s %llx %s", KeyWord
, FunctionName
, &TempLongAddress
, FunctionTypeName
);
885 FunctionAddress
= (UINT64
) TempLongAddress
;
886 if (FunctionTypeName
[1] == '\0' && (FunctionTypeName
[0] == 'f' || FunctionTypeName
[0] == 'F')) {
887 fprintf (FvMapFile
, " %016llx ", (unsigned long long) (ImageBaseAddress
+ FunctionAddress
));
888 fprintf (FvMapFile
, "(%08llx) FS ", (unsigned long long) (FunctionAddress
- Offset
));
889 fprintf (FvMapFile
, "%s\n", FunctionName
);
891 fprintf (FvMapFile
, " %016llx ", (unsigned long long) (ImageBaseAddress
+ FunctionAddress
));
892 fprintf (FvMapFile
, "(%08llx) ", (unsigned long long) (FunctionAddress
- Offset
));
893 fprintf (FvMapFile
, "%s\n", FunctionName
);
900 fprintf (FvMapFile
, "\n\n");
908 IN OUT MEMORY_FILE
*FvImage
,
911 IN OUT EFI_FFS_FILE_HEADER
**VtfFileImage
,
918 This function adds a file to the FV image. The file will pad to the
919 appropriate alignment if required.
923 FvImage The memory image of the FV to add it to. The current offset
925 FvInfo Pointer to information about the FV.
926 Index The file in the FvInfo file list to add.
927 VtfFileImage A pointer to the VTF file within the FvImage. If this is equal
928 to the end of the FvImage then no VTF previously found.
929 FvMapFile Pointer to FvMap File
933 EFI_SUCCESS The function completed successfully.
934 EFI_INVALID_PARAMETER One of the input parameters was invalid.
935 EFI_ABORTED An error occurred.
936 EFI_OUT_OF_RESOURCES Insufficient resources exist to complete the add.
944 UINT32 CurrentFileAlignment
;
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 DebugMsg (NULL
, 0, 9, "Add VTF FFS file in FV image", NULL
);
1090 // Already found a VTF file.
1092 Error (NULL
, 0, 3000, "Invalid", "multiple VTF files are not permitted within a single FV.");
1099 // Add pad file if necessary
1101 Status
= AddPadFile (FvImage
, 1 << CurrentFileAlignment
, *VtfFileImage
, NULL
);
1102 if (EFI_ERROR (Status
)) {
1103 Error (NULL
, 0, 4002, "Resource", "FV space is full, could not add pad file for data alignment property.");
1110 if ((UINTN
) (FvImage
->CurrentFilePointer
+ FileSize
) <= (UINTN
) (*VtfFileImage
)) {
1112 // Rebase the PE or TE image in FileBuffer of FFS file for XIP.
1113 // Rebase Bs and Rt drivers for the debug genfvmap tool.
1115 FfsRebase (FvInfo
, FvInfo
->FvFiles
[Index
], (EFI_FFS_FILE_HEADER
*) FileBuffer
, (UINTN
) FvImage
->CurrentFilePointer
- (UINTN
) FvImage
->FileImage
, FvMapFile
);
1119 memcpy (FvImage
->CurrentFilePointer
, FileBuffer
, FileSize
);
1120 FvImage
->CurrentFilePointer
+= FileSize
;
1122 Error (NULL
, 0, 4002, "Resource", "FV space is full, cannot add file %s.", FvInfo
->FvFiles
[Index
]);
1127 // Make next file start at QWord Boundry
1129 while (((UINTN
) FvImage
->CurrentFilePointer
& (EFI_FFS_FILE_HEADER_ALIGNMENT
- 1)) != 0) {
1130 FvImage
->CurrentFilePointer
++;
1135 // Free allocated memory.
1144 IN MEMORY_FILE
*FvImage
,
1145 IN EFI_FFS_FILE_HEADER
*VtfFileImage
1149 Routine Description:
1151 This function places a pad file between the last file in the FV and the VTF
1152 file if the VTF file exists.
1156 FvImage Memory file for the FV memory image
1157 VtfFileImage The address of the VTF file. If this is the end of the FV
1158 image, no VTF exists and no pad file is needed.
1162 EFI_SUCCESS Completed successfully.
1163 EFI_INVALID_PARAMETER One of the input parameters was NULL.
1167 EFI_FFS_FILE_HEADER
*PadFile
;
1171 // If there is no VTF or the VTF naturally follows the previous file without a
1172 // pad file, then there's nothing to do
1174 if ((UINTN
) VtfFileImage
== (UINTN
) FvImage
->Eof
|| \
1175 ((UINTN
) VtfFileImage
== (UINTN
) FvImage
->CurrentFilePointer
)) {
1179 if ((UINTN
) VtfFileImage
< (UINTN
) FvImage
->CurrentFilePointer
) {
1180 return EFI_INVALID_PARAMETER
;
1184 // Pad file starts at beginning of free space
1186 PadFile
= (EFI_FFS_FILE_HEADER
*) FvImage
->CurrentFilePointer
;
1189 // write PadFile FFS header with PadType, don't need to set PAD file guid in its header.
1191 PadFile
->Type
= EFI_FV_FILETYPE_FFS_PAD
;
1192 PadFile
->Attributes
= 0;
1195 // FileSize includes the EFI_FFS_FILE_HEADER
1197 FileSize
= (UINTN
) VtfFileImage
- (UINTN
) FvImage
->CurrentFilePointer
;
1198 PadFile
->Size
[0] = (UINT8
) (FileSize
& 0x000000FF);
1199 PadFile
->Size
[1] = (UINT8
) ((FileSize
& 0x0000FF00) >> 8);
1200 PadFile
->Size
[2] = (UINT8
) ((FileSize
& 0x00FF0000) >> 16);
1203 // Fill in checksums and state, must be zero during checksum calculation.
1205 PadFile
->IntegrityCheck
.Checksum
.Header
= 0;
1206 PadFile
->IntegrityCheck
.Checksum
.File
= 0;
1208 PadFile
->IntegrityCheck
.Checksum
.Header
= CalculateChecksum8 ((UINT8
*) PadFile
, sizeof (EFI_FFS_FILE_HEADER
));
1209 PadFile
->IntegrityCheck
.Checksum
.File
= FFS_FIXED_CHECKSUM
;
1211 PadFile
->State
= EFI_FILE_HEADER_CONSTRUCTION
| EFI_FILE_HEADER_VALID
| EFI_FILE_DATA_VALID
;
1213 UpdateFfsFileState (
1214 (EFI_FFS_FILE_HEADER
*) PadFile
,
1215 (EFI_FIRMWARE_VOLUME_HEADER
*) FvImage
->FileImage
1218 // Update the current FV pointer
1220 FvImage
->CurrentFilePointer
= FvImage
->Eof
;
1227 IN MEMORY_FILE
*FvImage
,
1229 IN EFI_FFS_FILE_HEADER
*VtfFile
1233 Routine Description:
1235 This parses the FV looking for the PEI core and then plugs the address into
1236 the SALE_ENTRY point of the BSF/VTF for IPF and does BUGBUG TBD action to
1237 complete an IA32 Bootstrap FV.
1241 FvImage Memory file for the FV memory image
1242 FvInfo Information read from INF file.
1243 VtfFile Pointer to the VTF file in the FV image.
1247 EFI_SUCCESS Function Completed successfully.
1248 EFI_ABORTED Error encountered.
1249 EFI_INVALID_PARAMETER A required parameter was NULL.
1250 EFI_NOT_FOUND PEI Core file not found.
1254 EFI_FFS_FILE_HEADER
*PeiCoreFile
;
1255 EFI_FFS_FILE_HEADER
*SecCoreFile
;
1257 EFI_FILE_SECTION_POINTER Pe32Section
;
1261 EFI_PHYSICAL_ADDRESS PeiCorePhysicalAddress
;
1262 EFI_PHYSICAL_ADDRESS SecCorePhysicalAddress
;
1263 EFI_PHYSICAL_ADDRESS
*SecCoreEntryAddressPtr
;
1264 INT32 Ia32SecEntryOffset
;
1265 UINT32
*Ia32ResetAddressPtr
;
1267 UINT8
*BytePointer2
;
1268 UINT16
*WordPointer
;
1272 EFI_FFS_FILE_STATE SavedState
;
1274 FIT_TABLE
*FitTablePtr
;
1277 // Verify input parameters
1279 if (FvImage
== NULL
|| FvInfo
== NULL
|| VtfFile
== NULL
) {
1280 return EFI_INVALID_PARAMETER
;
1283 // Initialize FV library
1285 InitializeFvLib (FvImage
->FileImage
, FvInfo
->Size
);
1290 Status
= VerifyFfsFile (VtfFile
);
1291 if (EFI_ERROR (Status
)) {
1292 return EFI_INVALID_PARAMETER
;
1296 // Find the Sec Core
1298 Status
= GetFileByType (EFI_FV_FILETYPE_SECURITY_CORE
, 1, &SecCoreFile
);
1299 if (EFI_ERROR (Status
) || SecCoreFile
== NULL
) {
1300 Error (NULL
, 0, 3000, "Invalid", "could not find the SEC core file in the FV.");
1304 // Sec Core found, now find PE32 section
1306 Status
= GetSectionByType (SecCoreFile
, EFI_SECTION_PE32
, 1, &Pe32Section
);
1307 if (Status
== EFI_NOT_FOUND
) {
1308 Status
= GetSectionByType (SecCoreFile
, EFI_SECTION_TE
, 1, &Pe32Section
);
1311 if (EFI_ERROR (Status
)) {
1312 Error (NULL
, 0, 3000, "Invalid", "could not find a PE32 section in the SEC core file.");
1316 Status
= GetPe32Info (
1317 (VOID
*) ((UINTN
) Pe32Section
.Pe32Section
+ sizeof (EFI_SECTION_PE32
)),
1323 if (EFI_ERROR (Status
)) {
1324 Error (NULL
, 0, 3000, "Invalid", "could not get the PE32 entry point for the SEC core.");
1329 // Physical address is FV base + offset of PE32 + offset of the entry point
1331 SecCorePhysicalAddress
= FvInfo
->BaseAddress
;
1332 SecCorePhysicalAddress
+= (UINTN
) Pe32Section
.Pe32Section
+ sizeof (EFI_SECTION_PE32
) - (UINTN
) FvImage
->FileImage
;
1333 SecCorePhysicalAddress
+= EntryPoint
;
1334 DebugMsg (NULL
, 0, 9, "SecCore physical entry point address", "Address = 0x%llX", (unsigned long long) SecCorePhysicalAddress
);
1337 // Find the PEI Core
1339 Status
= GetFileByType (EFI_FV_FILETYPE_PEI_CORE
, 1, &PeiCoreFile
);
1340 if (EFI_ERROR (Status
) || PeiCoreFile
== NULL
) {
1341 Error (NULL
, 0, 3000, "Invalid", "could not find the PEI core in the FV.");
1345 // PEI Core found, now find PE32 or TE section
1347 Status
= GetSectionByType (PeiCoreFile
, EFI_SECTION_PE32
, 1, &Pe32Section
);
1348 if (Status
== EFI_NOT_FOUND
) {
1349 Status
= GetSectionByType (PeiCoreFile
, EFI_SECTION_TE
, 1, &Pe32Section
);
1352 if (EFI_ERROR (Status
)) {
1353 Error (NULL
, 0, 3000, "Invalid", "could not find either a PE32 or a TE section in PEI core file.");
1357 Status
= GetPe32Info (
1358 (VOID
*) ((UINTN
) Pe32Section
.Pe32Section
+ sizeof (EFI_SECTION_PE32
)),
1364 if (EFI_ERROR (Status
)) {
1365 Error (NULL
, 0, 3000, "Invalid", "could not get the PE32 entry point for the PEI core.");
1369 // Physical address is FV base + offset of PE32 + offset of the entry point
1371 PeiCorePhysicalAddress
= FvInfo
->BaseAddress
;
1372 PeiCorePhysicalAddress
+= (UINTN
) Pe32Section
.Pe32Section
+ sizeof (EFI_SECTION_PE32
) - (UINTN
) FvImage
->FileImage
;
1373 PeiCorePhysicalAddress
+= EntryPoint
;
1374 DebugMsg (NULL
, 0, 9, "PeiCore physical entry point address", "Address = 0x%llX", (unsigned long long) PeiCorePhysicalAddress
);
1376 if (MachineType
== EFI_IMAGE_MACHINE_IA64
) {
1378 // Update PEI_CORE address
1381 // Set the uncached attribute bit in the physical address
1383 PeiCorePhysicalAddress
|= 0x8000000000000000ULL
;
1386 // Check if address is aligned on a 16 byte boundary
1388 if (PeiCorePhysicalAddress
& 0xF) {
1389 Error (NULL
, 0, 3000, "Invalid",
1390 "PEI_CORE entry point is not aligned on a 16 byte boundary, address specified is %llXh.",
1391 (unsigned long long) PeiCorePhysicalAddress
1396 // First Get the FIT table address
1398 FitAddress
= (*(UINT64
*) (FvImage
->Eof
- IPF_FIT_ADDRESS_OFFSET
)) & 0xFFFFFFFF;
1400 FitTablePtr
= (FIT_TABLE
*) (FvImage
->FileImage
+ (FitAddress
- FvInfo
->BaseAddress
));
1402 Status
= UpdatePeiCoreEntryInFit (FitTablePtr
, PeiCorePhysicalAddress
);
1404 if (!EFI_ERROR (Status
)) {
1405 UpdateFitCheckSum (FitTablePtr
);
1409 // Update SEC_CORE address
1412 // Set the uncached attribute bit in the physical address
1414 SecCorePhysicalAddress
|= 0x8000000000000000ULL
;
1416 // Check if address is aligned on a 16 byte boundary
1418 if (SecCorePhysicalAddress
& 0xF) {
1419 Error (NULL
, 0, 3000, "Invalid",
1420 "SALE_ENTRY entry point is not aligned on a 16 byte boundary, address specified is %llXh.",
1421 (unsigned long long) SecCorePhysicalAddress
1426 // Update the address
1428 SecCoreEntryAddressPtr
= (EFI_PHYSICAL_ADDRESS
*) ((UINTN
) FvImage
->Eof
- IPF_SALE_ENTRY_ADDRESS_OFFSET
);
1429 *SecCoreEntryAddressPtr
= SecCorePhysicalAddress
;
1432 (MachineType
== EFI_IMAGE_MACHINE_IA32
||
1433 MachineType
== EFI_IMAGE_MACHINE_X64
) &&
1434 (((UINTN
)FvImage
->Eof
- (UINTN
)FvImage
->FileImage
) >= IA32_X64_VTF_SIGNATURE_OFFSET
) &&
1435 (*(UINT32
*)(VOID
*)((UINTN
) FvImage
->Eof
- IA32_X64_VTF_SIGNATURE_OFFSET
) ==
1436 IA32_X64_VTF0_SIGNATURE
)
1439 // If VTF-0 signature is found, then no modifications are needed.
1441 } else if (MachineType
== EFI_IMAGE_MACHINE_IA32
|| MachineType
== EFI_IMAGE_MACHINE_X64
) {
1443 // Get the location to update
1445 Ia32ResetAddressPtr
= (UINT32
*) ((UINTN
) FvImage
->Eof
- IA32_PEI_CORE_ENTRY_OFFSET
);
1448 // Write lower 32 bits of physical address for Pei Core entry
1450 *Ia32ResetAddressPtr
= (UINT32
) PeiCorePhysicalAddress
;
1453 // Write SecCore Entry point relative address into the jmp instruction in reset vector.
1455 Ia32ResetAddressPtr
= (UINT32
*) ((UINTN
) FvImage
->Eof
- IA32_SEC_CORE_ENTRY_OFFSET
);
1457 Ia32SecEntryOffset
= (INT32
) (SecCorePhysicalAddress
- (FV_IMAGES_TOP_ADDRESS
- IA32_SEC_CORE_ENTRY_OFFSET
+ 2));
1458 if (Ia32SecEntryOffset
<= -65536) {
1459 Error (NULL
, 0, 3000, "Invalid", "The SEC EXE file size is too large, it must be less than 64K.");
1460 return STATUS_ERROR
;
1463 *(UINT16
*) Ia32ResetAddressPtr
= (UINT16
) Ia32SecEntryOffset
;
1466 // Update the BFV base address
1468 Ia32ResetAddressPtr
= (UINT32
*) ((UINTN
) FvImage
->Eof
- 4);
1469 *Ia32ResetAddressPtr
= (UINT32
) (FvInfo
->BaseAddress
);
1470 DebugMsg (NULL
, 0, 9, "update BFV base address in the top FV image", "BFV base address = 0x%llX.", (unsigned long long) FvInfo
->BaseAddress
);
1473 // Update the Startup AP in the FVH header block ZeroVector region.
1475 BytePointer
= (UINT8
*) ((UINTN
) FvImage
->FileImage
);
1476 if (FvInfo
->Size
<= 0x10000) {
1477 BytePointer2
= m64kRecoveryStartupApDataArray
;
1478 } else if (FvInfo
->Size
<= 0x20000) {
1479 BytePointer2
= m128kRecoveryStartupApDataArray
;
1481 BytePointer2
= m128kRecoveryStartupApDataArray
;
1483 // Find the position to place Ap reset vector, the offset
1484 // between the position and the end of Fvrecovery.fv file
1485 // should not exceed 128kB to prevent Ap reset vector from
1486 // outside legacy E and F segment
1488 Status
= FindApResetVectorPosition (FvImage
, &BytePointer
);
1489 if (EFI_ERROR (Status
)) {
1490 Error (NULL
, 0, 3000, "Invalid", "Cannot find the appropriate location in FvImage to add Ap reset vector!");
1495 for (Index
= 0; Index
< SIZEOF_STARTUP_DATA_ARRAY
; Index
++) {
1496 BytePointer
[Index
] = BytePointer2
[Index
];
1499 // Calculate the checksum
1502 WordPointer
= (UINT16
*) (BytePointer
);
1503 for (Index
= 0; Index
< SIZEOF_STARTUP_DATA_ARRAY
/ 2; Index
++) {
1504 CheckSum
= (UINT16
) (CheckSum
+ ((UINT16
) *WordPointer
));
1508 // Update the checksum field
1510 WordPointer
= (UINT16
*) (BytePointer
+ SIZEOF_STARTUP_DATA_ARRAY
- 2);
1511 *WordPointer
= (UINT16
) (0x10000 - (UINT32
) CheckSum
);
1514 // IpiVector at the 4k aligned address in the top 2 blocks in the PEI FV.
1516 IpiVector
= (UINT32
) (FV_IMAGES_TOP_ADDRESS
- ((UINTN
) FvImage
->Eof
- (UINTN
) BytePointer
));
1517 DebugMsg (NULL
, 0, 9, "Startup AP Vector address", "IpiVector at 0x%X", (unsigned) IpiVector
);
1518 if ((IpiVector
& 0xFFF) != 0) {
1519 Error (NULL
, 0, 3000, "Invalid", "Startup AP Vector address are not 4K aligned, because the FV size is not 4K aligned");
1522 IpiVector
= IpiVector
>> 12;
1523 IpiVector
= IpiVector
& 0xFF;
1526 // Write IPI Vector at Offset FvrecoveryFileSize - 8
1528 Ia32ResetAddressPtr
= (UINT32
*) ((UINTN
) FvImage
->Eof
- 8);
1529 *Ia32ResetAddressPtr
= IpiVector
;
1530 } else if (MachineType
== EFI_IMAGE_MACHINE_ARMT
) {
1532 // Since the ARM reset vector is in the FV Header you really don't need a
1533 // Volume Top File, but if you have one for some reason don't crash...
1536 Error (NULL
, 0, 3000, "Invalid", "machine type=0x%X in PEI core.", MachineType
);
1541 // Now update file checksum
1543 SavedState
= VtfFile
->State
;
1544 VtfFile
->IntegrityCheck
.Checksum
.File
= 0;
1546 if (VtfFile
->Attributes
& FFS_ATTRIB_CHECKSUM
) {
1547 VtfFile
->IntegrityCheck
.Checksum
.File
= CalculateChecksum8 (
1549 GetLength (VtfFile
->Size
)
1552 VtfFile
->IntegrityCheck
.Checksum
.File
= FFS_FIXED_CHECKSUM
;
1555 VtfFile
->State
= SavedState
;
1562 UpdateArmResetVectorIfNeeded (
1563 IN MEMORY_FILE
*FvImage
,
1568 Routine Description:
1569 This parses the FV looking for SEC and patches that address into the
1570 beginning of the FV header.
1572 For ARM the reset vector is at 0x00000000 or 0xFFFF0000.
1573 This would commonly map to the first entry in the ROM.
1583 We support two schemes on ARM.
1584 1) Beginning of the FV is the reset vector
1585 2) Reset vector is data bytes FDF file and that code branches to reset vector
1586 in the beginning of the FV (fixed size offset).
1589 Need to have the jump for the reset vector at location zero.
1590 We also need to store the address or PEI (if it exists).
1591 We stub out a return from interrupt in case the debugger
1593 The optional entry to the common exception handler is
1594 to support full featured exception handling from ROM and is currently
1595 not support by this tool.
1598 FvImage Memory file for the FV memory image
1599 FvInfo Information read from INF file.
1603 EFI_SUCCESS Function Completed successfully.
1604 EFI_ABORTED Error encountered.
1605 EFI_INVALID_PARAMETER A required parameter was NULL.
1606 EFI_NOT_FOUND PEI Core file not found.
1610 EFI_FFS_FILE_HEADER
*PeiCoreFile
;
1611 EFI_FFS_FILE_HEADER
*SecCoreFile
;
1613 EFI_FILE_SECTION_POINTER Pe32Section
;
1617 EFI_PHYSICAL_ADDRESS PeiCorePhysicalAddress
;
1618 EFI_PHYSICAL_ADDRESS SecCorePhysicalAddress
;
1619 INT32 ResetVector
[4]; // 0 - is branch relative to SEC entry point
1620 // 1 - PEI Entry Point
1621 // 2 - movs pc,lr for a SWI handler
1622 // 3 - Place holder for Common Exception Handler
1625 // Verify input parameters
1627 if (FvImage
== NULL
|| FvInfo
== NULL
) {
1628 return EFI_INVALID_PARAMETER
;
1631 // Initialize FV library
1633 InitializeFvLib (FvImage
->FileImage
, FvInfo
->Size
);
1636 // Find the Sec Core
1638 Status
= GetFileByType (EFI_FV_FILETYPE_SECURITY_CORE
, 1, &SecCoreFile
);
1639 if (EFI_ERROR (Status
) || SecCoreFile
== NULL
) {
1641 // Maybe hardware does SEC job and we only have PEI Core?
1645 // Find the PEI Core. It may not exist if SEC loads DXE core directly
1647 PeiCorePhysicalAddress
= 0;
1648 Status
= GetFileByType (EFI_FV_FILETYPE_PEI_CORE
, 1, &PeiCoreFile
);
1649 if (!EFI_ERROR (Status
) && PeiCoreFile
!= NULL
) {
1651 // PEI Core found, now find PE32 or TE section
1653 Status
= GetSectionByType (PeiCoreFile
, EFI_SECTION_PE32
, 1, &Pe32Section
);
1654 if (Status
== EFI_NOT_FOUND
) {
1655 Status
= GetSectionByType (PeiCoreFile
, EFI_SECTION_TE
, 1, &Pe32Section
);
1658 if (EFI_ERROR (Status
)) {
1659 Error (NULL
, 0, 3000, "Invalid", "could not find either a PE32 or a TE section in PEI core file!");
1663 Status
= GetPe32Info (
1664 (VOID
*) ((UINTN
) Pe32Section
.Pe32Section
+ sizeof (EFI_SECTION_PE32
)),
1670 if (EFI_ERROR (Status
)) {
1671 Error (NULL
, 0, 3000, "Invalid", "could not get the PE32 entry point for the PEI core!");
1675 // Physical address is FV base + offset of PE32 + offset of the entry point
1677 PeiCorePhysicalAddress
= FvInfo
->BaseAddress
;
1678 PeiCorePhysicalAddress
+= (UINTN
) Pe32Section
.Pe32Section
+ sizeof (EFI_SECTION_PE32
) - (UINTN
) FvImage
->FileImage
;
1679 PeiCorePhysicalAddress
+= EntryPoint
;
1680 DebugMsg (NULL
, 0, 9, "PeiCore physical entry point address", "Address = 0x%llX", (unsigned long long) PeiCorePhysicalAddress
);
1682 if (MachineType
== EFI_IMAGE_MACHINE_ARMT
) {
1683 memset (ResetVector
, 0, sizeof (ResetVector
));
1684 // Address of PEI Core, if we have one
1685 ResetVector
[1] = (UINT32
)PeiCorePhysicalAddress
;
1689 // Copy to the beginning of the FV
1691 memcpy ((UINT8
*) ((UINTN
) FvImage
->FileImage
), ResetVector
, sizeof (ResetVector
));
1699 // Sec Core found, now find PE32 section
1701 Status
= GetSectionByType (SecCoreFile
, EFI_SECTION_PE32
, 1, &Pe32Section
);
1702 if (Status
== EFI_NOT_FOUND
) {
1703 Status
= GetSectionByType (SecCoreFile
, EFI_SECTION_TE
, 1, &Pe32Section
);
1706 if (EFI_ERROR (Status
)) {
1707 Error (NULL
, 0, 3000, "Invalid", "could not find a PE32 section in the SEC core file.");
1711 Status
= GetPe32Info (
1712 (VOID
*) ((UINTN
) Pe32Section
.Pe32Section
+ sizeof (EFI_SECTION_PE32
)),
1717 if (EFI_ERROR (Status
)) {
1718 Error (NULL
, 0, 3000, "Invalid", "could not get the PE32 entry point for the SEC core.");
1722 if (MachineType
!= EFI_IMAGE_MACHINE_ARMT
) {
1724 // If SEC is not ARM we have nothing to do
1730 // Physical address is FV base + offset of PE32 + offset of the entry point
1732 SecCorePhysicalAddress
= FvInfo
->BaseAddress
;
1733 SecCorePhysicalAddress
+= (UINTN
) Pe32Section
.Pe32Section
+ sizeof (EFI_SECTION_PE32
) - (UINTN
) FvImage
->FileImage
;
1734 SecCorePhysicalAddress
+= EntryPoint
;
1735 DebugMsg (NULL
, 0, 9, "SecCore physical entry point address", "Address = 0x%llX", (unsigned long long) SecCorePhysicalAddress
);
1738 // Find the PEI Core. It may not exist if SEC loads DXE core directly
1740 PeiCorePhysicalAddress
= 0;
1741 Status
= GetFileByType (EFI_FV_FILETYPE_PEI_CORE
, 1, &PeiCoreFile
);
1742 if (!EFI_ERROR (Status
) && PeiCoreFile
!= NULL
) {
1744 // PEI Core found, now find PE32 or TE section
1746 Status
= GetSectionByType (PeiCoreFile
, EFI_SECTION_PE32
, 1, &Pe32Section
);
1747 if (Status
== EFI_NOT_FOUND
) {
1748 Status
= GetSectionByType (PeiCoreFile
, EFI_SECTION_TE
, 1, &Pe32Section
);
1751 if (EFI_ERROR (Status
)) {
1752 Error (NULL
, 0, 3000, "Invalid", "could not find either a PE32 or a TE section in PEI core file!");
1756 Status
= GetPe32Info (
1757 (VOID
*) ((UINTN
) Pe32Section
.Pe32Section
+ sizeof (EFI_SECTION_PE32
)),
1763 if (EFI_ERROR (Status
)) {
1764 Error (NULL
, 0, 3000, "Invalid", "could not get the PE32 entry point for the PEI core!");
1768 // Physical address is FV base + offset of PE32 + offset of the entry point
1770 PeiCorePhysicalAddress
= FvInfo
->BaseAddress
;
1771 PeiCorePhysicalAddress
+= (UINTN
) Pe32Section
.Pe32Section
+ sizeof (EFI_SECTION_PE32
) - (UINTN
) FvImage
->FileImage
;
1772 PeiCorePhysicalAddress
+= EntryPoint
;
1773 DebugMsg (NULL
, 0, 9, "PeiCore physical entry point address", "Address = 0x%llX", (unsigned long long) PeiCorePhysicalAddress
);
1777 // B SecEntryPoint - signed_immed_24 part +/-32MB offset
1778 // on ARM, the PC is always 8 ahead, so we're not really jumping from the base address, but from base address + 8
1779 ResetVector
[0] = (INT32
)(SecCorePhysicalAddress
- FvInfo
->BaseAddress
- 8) >> 2;
1781 if (ResetVector
[0] > 0x00FFFFFF) {
1782 Error (NULL
, 0, 3000, "Invalid", "SEC Entry point must be within 32MB of the start of the FV");
1786 // Add opcode for an uncondional branch with no link. AKA B SecEntryPoint
1787 ResetVector
[0] |= 0xEA000000;
1790 // Address of PEI Core, if we have one
1791 ResetVector
[1] = (UINT32
)PeiCorePhysicalAddress
;
1793 // SWI handler movs pc,lr. Just in case a debugger uses SWI
1794 ResetVector
[2] = 0xE1B0F07E;
1796 // Place holder to support a common interrupt handler from ROM.
1797 // Currently not suppprted. For this to be used the reset vector would not be in this FV
1798 // and the exception vectors would be hard coded in the ROM and just through this address
1799 // to find a common handler in the a module in the FV.
1803 // Copy to the beginning of the FV
1805 memcpy ((UINT8
*) ((UINTN
) FvImage
->FileImage
), ResetVector
, sizeof (ResetVector
));
1807 DebugMsg (NULL
, 0, 9, "Update Reset vector in FV Header", NULL
);
1815 OUT UINT32
*EntryPoint
,
1816 OUT UINT32
*BaseOfCode
,
1817 OUT UINT16
*MachineType
1821 Routine Description:
1823 Retrieves the PE32 entry point offset and machine type from PE image or TeImage.
1824 See EfiImage.h for machine types. The entry point offset is from the beginning
1825 of the PE32 buffer passed in.
1829 Pe32 Beginning of the PE32.
1830 EntryPoint Offset from the beginning of the PE32 to the image entry point.
1831 BaseOfCode Base address of code.
1832 MachineType Magic number for the machine type.
1836 EFI_SUCCESS Function completed successfully.
1837 EFI_ABORTED Error encountered.
1838 EFI_INVALID_PARAMETER A required parameter was NULL.
1839 EFI_UNSUPPORTED The operation is unsupported.
1843 EFI_IMAGE_DOS_HEADER
*DosHeader
;
1844 EFI_IMAGE_OPTIONAL_HEADER_UNION
*ImgHdr
;
1845 EFI_TE_IMAGE_HEADER
*TeHeader
;
1848 // Verify input parameters
1851 return EFI_INVALID_PARAMETER
;
1855 // First check whether it is one TE Image.
1857 TeHeader
= (EFI_TE_IMAGE_HEADER
*) Pe32
;
1858 if (TeHeader
->Signature
== EFI_TE_IMAGE_HEADER_SIGNATURE
) {
1860 // By TeImage Header to get output
1862 *EntryPoint
= TeHeader
->AddressOfEntryPoint
+ sizeof (EFI_TE_IMAGE_HEADER
) - TeHeader
->StrippedSize
;
1863 *BaseOfCode
= TeHeader
->BaseOfCode
+ sizeof (EFI_TE_IMAGE_HEADER
) - TeHeader
->StrippedSize
;
1864 *MachineType
= TeHeader
->Machine
;
1868 // Then check whether
1869 // First is the DOS header
1871 DosHeader
= (EFI_IMAGE_DOS_HEADER
*) Pe32
;
1874 // Verify DOS header is expected
1876 if (DosHeader
->e_magic
!= EFI_IMAGE_DOS_SIGNATURE
) {
1877 Error (NULL
, 0, 3000, "Invalid", "Unknown magic number in the DOS header, 0x%04X.", DosHeader
->e_magic
);
1878 return EFI_UNSUPPORTED
;
1881 // Immediately following is the NT header.
1883 ImgHdr
= (EFI_IMAGE_OPTIONAL_HEADER_UNION
*) ((UINTN
) Pe32
+ DosHeader
->e_lfanew
);
1886 // Verify NT header is expected
1888 if (ImgHdr
->Pe32
.Signature
!= EFI_IMAGE_NT_SIGNATURE
) {
1889 Error (NULL
, 0, 3000, "Invalid", "Unrecognized image signature 0x%08X.", (unsigned) ImgHdr
->Pe32
.Signature
);
1890 return EFI_UNSUPPORTED
;
1895 *EntryPoint
= ImgHdr
->Pe32
.OptionalHeader
.AddressOfEntryPoint
;
1896 *BaseOfCode
= ImgHdr
->Pe32
.OptionalHeader
.BaseOfCode
;
1897 *MachineType
= ImgHdr
->Pe32
.FileHeader
.Machine
;
1901 // Verify machine type is supported
1903 if (*MachineType
!= EFI_IMAGE_MACHINE_IA32
&& *MachineType
!= EFI_IMAGE_MACHINE_IA64
&& *MachineType
!= EFI_IMAGE_MACHINE_X64
&& *MachineType
!= EFI_IMAGE_MACHINE_EBC
&&
1904 *MachineType
!= EFI_IMAGE_MACHINE_ARMT
) {
1905 Error (NULL
, 0, 3000, "Invalid", "Unrecognized machine type in the PE32 file.");
1906 return EFI_UNSUPPORTED
;
1914 IN CHAR8
*InfFileImage
,
1915 IN UINTN InfFileSize
,
1916 IN CHAR8
*FvFileName
,
1917 IN CHAR8
*MapFileName
1921 Routine Description:
1923 This is the main function which will be called from application.
1927 InfFileImage Buffer containing the INF file contents.
1928 InfFileSize Size of the contents of the InfFileImage buffer.
1929 FvFileName Requested name for the FV file.
1930 MapFileName Fv map file to log fv driver information.
1934 EFI_SUCCESS Function completed successfully.
1935 EFI_OUT_OF_RESOURCES Could not allocate required resources.
1936 EFI_ABORTED Error encountered.
1937 EFI_INVALID_PARAMETER A required parameter was NULL.
1942 MEMORY_FILE InfMemoryFile
;
1943 MEMORY_FILE FvImageMemoryFile
;
1945 EFI_FIRMWARE_VOLUME_HEADER
*FvHeader
;
1946 EFI_FFS_FILE_HEADER
*VtfFileImage
;
1947 UINT8
*FvBufferHeader
; // to make sure fvimage header 8 type alignment.
1951 CHAR8 FvMapName
[_MAX_PATH
];
1953 EFI_FIRMWARE_VOLUME_EXT_HEADER FvExtHeader
;
1955 FvBufferHeader
= NULL
;
1959 if (InfFileImage
!= NULL
) {
1961 // Initialize file structures
1963 InfMemoryFile
.FileImage
= InfFileImage
;
1964 InfMemoryFile
.CurrentFilePointer
= InfFileImage
;
1965 InfMemoryFile
.Eof
= InfFileImage
+ InfFileSize
;
1968 // Parse the FV inf file for header information
1970 Status
= ParseFvInf (&InfMemoryFile
, &mFvDataInfo
);
1971 if (EFI_ERROR (Status
)) {
1972 Error (NULL
, 0, 0003, "Error parsing file", "the input FV INF file.");
1978 // Update the file name return values
1980 if (FvFileName
== NULL
&& mFvDataInfo
.FvName
[0] != '\0') {
1981 FvFileName
= mFvDataInfo
.FvName
;
1984 if (FvFileName
== NULL
) {
1985 Error (NULL
, 0, 1001, "Missing option", "Output file name");
1989 if (mFvDataInfo
.FvBlocks
[0].Length
== 0) {
1990 Error (NULL
, 0, 1001, "Missing required argument", "Block Size");
1995 // Debug message Fv File System Guid
1997 if (mFvDataInfo
.FvFileSystemGuidSet
) {
1998 DebugMsg (NULL
, 0, 9, "FV File System Guid", "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X",
1999 (unsigned) mFvDataInfo
.FvFileSystemGuid
.Data1
,
2000 mFvDataInfo
.FvFileSystemGuid
.Data2
,
2001 mFvDataInfo
.FvFileSystemGuid
.Data3
,
2002 mFvDataInfo
.FvFileSystemGuid
.Data4
[0],
2003 mFvDataInfo
.FvFileSystemGuid
.Data4
[1],
2004 mFvDataInfo
.FvFileSystemGuid
.Data4
[2],
2005 mFvDataInfo
.FvFileSystemGuid
.Data4
[3],
2006 mFvDataInfo
.FvFileSystemGuid
.Data4
[4],
2007 mFvDataInfo
.FvFileSystemGuid
.Data4
[5],
2008 mFvDataInfo
.FvFileSystemGuid
.Data4
[6],
2009 mFvDataInfo
.FvFileSystemGuid
.Data4
[7]);
2012 // Debug message Fv Name Guid
2014 if (mFvDataInfo
.FvNameGuidSet
) {
2015 DebugMsg (NULL
, 0, 9, "FV Name Guid", "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X",
2016 (unsigned) mFvDataInfo
.FvNameGuid
.Data1
,
2017 mFvDataInfo
.FvNameGuid
.Data2
,
2018 mFvDataInfo
.FvNameGuid
.Data3
,
2019 mFvDataInfo
.FvNameGuid
.Data4
[0],
2020 mFvDataInfo
.FvNameGuid
.Data4
[1],
2021 mFvDataInfo
.FvNameGuid
.Data4
[2],
2022 mFvDataInfo
.FvNameGuid
.Data4
[3],
2023 mFvDataInfo
.FvNameGuid
.Data4
[4],
2024 mFvDataInfo
.FvNameGuid
.Data4
[5],
2025 mFvDataInfo
.FvNameGuid
.Data4
[6],
2026 mFvDataInfo
.FvNameGuid
.Data4
[7]);
2029 if (CompareGuid (&mFvDataInfo
.FvFileSystemGuid
, &mEfiFirmwareFileSystem2Guid
) == 0) {
2030 mFvDataInfo
.IsPiFvImage
= TRUE
;
2034 // FvMap file to log the function address of all modules in one Fvimage
2036 if (MapFileName
!= NULL
) {
2037 strcpy (FvMapName
, MapFileName
);
2039 strcpy (FvMapName
, FvFileName
);
2040 strcat (FvMapName
, ".map");
2042 VerboseMsg ("FV Map file name is %s", FvMapName
);
2045 // Calculate the FV size and Update Fv Size based on the actual FFS files.
2046 // And Update mFvDataInfo data.
2048 Status
= CalculateFvSize (&mFvDataInfo
);
2049 if (EFI_ERROR (Status
)) {
2052 VerboseMsg ("the generated FV image size is %u bytes", (unsigned) mFvDataInfo
.Size
);
2055 // support fv image and empty fv image
2057 FvImageSize
= mFvDataInfo
.Size
;
2060 // Allocate the FV, assure FvImage Header 8 byte alignment
2062 FvBufferHeader
= malloc (FvImageSize
+ sizeof (UINT64
));
2063 if (FvBufferHeader
== NULL
) {
2064 return EFI_OUT_OF_RESOURCES
;
2066 FvImage
= (UINT8
*) (((UINTN
) FvBufferHeader
+ 7) & ~7);
2069 // Initialize the FV to the erase polarity
2071 if (mFvDataInfo
.FvAttributes
== 0) {
2073 // Set Default Fv Attribute
2075 mFvDataInfo
.FvAttributes
= FV_DEFAULT_ATTRIBUTE
;
2077 if (mFvDataInfo
.FvAttributes
& EFI_FVB2_ERASE_POLARITY
) {
2078 memset (FvImage
, -1, FvImageSize
);
2080 memset (FvImage
, 0, FvImageSize
);
2084 // Initialize FV header
2086 FvHeader
= (EFI_FIRMWARE_VOLUME_HEADER
*) FvImage
;
2089 // Initialize the zero vector to all zeros.
2091 memset (FvHeader
->ZeroVector
, 0, 16);
2094 // Copy the Fv file system GUID
2096 memcpy (&FvHeader
->FileSystemGuid
, &mFvDataInfo
.FvFileSystemGuid
, sizeof (EFI_GUID
));
2098 FvHeader
->FvLength
= FvImageSize
;
2099 FvHeader
->Signature
= EFI_FVH_SIGNATURE
;
2100 FvHeader
->Attributes
= mFvDataInfo
.FvAttributes
;
2101 FvHeader
->Revision
= EFI_FVH_REVISION
;
2102 FvHeader
->ExtHeaderOffset
= 0;
2103 FvHeader
->Reserved
[0] = 0;
2106 // Copy firmware block map
2108 for (Index
= 0; mFvDataInfo
.FvBlocks
[Index
].Length
!= 0; Index
++) {
2109 FvHeader
->BlockMap
[Index
].NumBlocks
= mFvDataInfo
.FvBlocks
[Index
].NumBlocks
;
2110 FvHeader
->BlockMap
[Index
].Length
= mFvDataInfo
.FvBlocks
[Index
].Length
;
2114 // Add block map terminator
2116 FvHeader
->BlockMap
[Index
].NumBlocks
= 0;
2117 FvHeader
->BlockMap
[Index
].Length
= 0;
2120 // Complete the header
2122 FvHeader
->HeaderLength
= (UINT16
) (((UINTN
) &(FvHeader
->BlockMap
[Index
+ 1])) - (UINTN
) FvImage
);
2123 FvHeader
->Checksum
= 0;
2124 FvHeader
->Checksum
= CalculateChecksum16 ((UINT16
*) FvHeader
, FvHeader
->HeaderLength
/ sizeof (UINT16
));
2127 // If there is no FFS file, generate one empty FV
2129 if (mFvDataInfo
.FvFiles
[0][0] == 0 && !mFvDataInfo
.FvNameGuidSet
) {
2134 // Initialize our "file" view of the buffer
2136 FvImageMemoryFile
.FileImage
= (CHAR8
*)FvImage
;
2137 FvImageMemoryFile
.CurrentFilePointer
= (CHAR8
*)FvImage
+ FvHeader
->HeaderLength
;
2138 FvImageMemoryFile
.Eof
= (CHAR8
*)FvImage
+ FvImageSize
;
2141 // Initialize the FV library.
2143 InitializeFvLib (FvImageMemoryFile
.FileImage
, FvImageSize
);
2146 // Initialize the VTF file address.
2148 VtfFileImage
= (EFI_FFS_FILE_HEADER
*) FvImageMemoryFile
.Eof
;
2153 FvMapFile
= fopen (FvMapName
, "w");
2154 if (FvMapFile
== NULL
) {
2155 Error (NULL
, 0, 0001, "Error opening file", FvMapName
);
2160 // record FV size information into FvMap file.
2162 if (mFvTotalSize
!= 0) {
2163 fprintf (FvMapFile
, EFI_FV_TOTAL_SIZE_STRING
);
2164 fprintf (FvMapFile
, " = 0x%x\n", (unsigned) mFvTotalSize
);
2166 if (mFvTakenSize
!= 0) {
2167 fprintf (FvMapFile
, EFI_FV_TAKEN_SIZE_STRING
);
2168 fprintf (FvMapFile
, " = 0x%x\n", (unsigned) mFvTakenSize
);
2170 if (mFvTotalSize
!= 0 && mFvTakenSize
!= 0) {
2171 fprintf (FvMapFile
, EFI_FV_SPACE_SIZE_STRING
);
2172 fprintf (FvMapFile
, " = 0x%x\n\n", (unsigned) (mFvTotalSize
- mFvTakenSize
));
2176 // Set PI FV extension header
2178 if (mFvDataInfo
.FvNameGuidSet
) {
2179 memcpy (&FvExtHeader
.FvName
, &mFvDataInfo
.FvNameGuid
, sizeof (EFI_GUID
));
2180 FvExtHeader
.ExtHeaderSize
= sizeof (EFI_FIRMWARE_VOLUME_EXT_HEADER
);
2181 AddPadFile (&FvImageMemoryFile
, 4, VtfFileImage
, &FvExtHeader
);
2183 // Fv Extension header change update Fv Header Check sum
2185 FvHeader
->Checksum
= 0;
2186 FvHeader
->Checksum
= CalculateChecksum16 ((UINT16
*) FvHeader
, FvHeader
->HeaderLength
/ sizeof (UINT16
));
2192 for (Index
= 0; mFvDataInfo
.FvFiles
[Index
][0] != 0; Index
++) {
2196 Status
= AddFile (&FvImageMemoryFile
, &mFvDataInfo
, Index
, &VtfFileImage
, FvMapFile
);
2199 // Exit if error detected while adding the file
2201 if (EFI_ERROR (Status
)) {
2207 // If there is a VTF file, some special actions need to occur.
2209 if ((UINTN
) VtfFileImage
!= (UINTN
) FvImageMemoryFile
.Eof
) {
2211 // Pad from the end of the last file to the beginning of the VTF file.
2212 // If the left space is less than sizeof (EFI_FFS_FILE_HEADER)?
2214 Status
= PadFvImage (&FvImageMemoryFile
, VtfFileImage
);
2215 if (EFI_ERROR (Status
)) {
2216 Error (NULL
, 0, 4002, "Resource", "FV space is full, cannot add pad file between the last file and the VTF file.");
2221 // Update reset vector (SALE_ENTRY for IPF)
2222 // Now for IA32 and IA64 platform, the fv which has bsf file must have the
2223 // EndAddress of 0xFFFFFFFF. Thus, only this type fv needs to update the
2224 // reset vector. If the PEI Core is found, the VTF file will probably get
2225 // corrupted by updating the entry point.
2227 if ((mFvDataInfo
.BaseAddress
+ mFvDataInfo
.Size
) == FV_IMAGES_TOP_ADDRESS
) {
2228 Status
= UpdateResetVector (&FvImageMemoryFile
, &mFvDataInfo
, VtfFileImage
);
2229 if (EFI_ERROR(Status
)) {
2230 Error (NULL
, 0, 3000, "Invalid", "Could not update the reset vector.");
2233 DebugMsg (NULL
, 0, 9, "Update Reset vector in VTF file", NULL
);
2239 Status
= UpdateArmResetVectorIfNeeded (&FvImageMemoryFile
, &mFvDataInfo
);
2240 if (EFI_ERROR (Status
)) {
2241 Error (NULL
, 0, 3000, "Invalid", "Could not update the reset vector.");
2246 // Update Checksum for FvHeader
2248 FvHeader
->Checksum
= 0;
2249 FvHeader
->Checksum
= CalculateChecksum16 ((UINT16
*) FvHeader
, FvHeader
->HeaderLength
/ sizeof (UINT16
));
2253 // Update FV Alignment attribute to the largest alignment of all the FFS files in the FV
2255 if ((((FvHeader
->Attributes
& EFI_FVB2_ALIGNMENT
) >> 16)) < MaxFfsAlignment
) {
2256 FvHeader
->Attributes
= ((MaxFfsAlignment
<< 16) | (FvHeader
->Attributes
& 0xFFFF));
2258 // Update Checksum for FvHeader
2260 FvHeader
->Checksum
= 0;
2261 FvHeader
->Checksum
= CalculateChecksum16 ((UINT16
*) FvHeader
, FvHeader
->HeaderLength
/ sizeof (UINT16
));
2268 FvFile
= fopen (FvFileName
, "wb");
2269 if (FvFile
== NULL
) {
2270 Error (NULL
, 0, 0001, "Error opening file", FvFileName
);
2271 Status
= EFI_ABORTED
;
2275 if (fwrite (FvImage
, 1, FvImageSize
, FvFile
) != FvImageSize
) {
2276 Error (NULL
, 0, 0002, "Error writing file", FvFileName
);
2277 Status
= EFI_ABORTED
;
2282 if (FvBufferHeader
!= NULL
) {
2283 free (FvBufferHeader
);
2286 if (FvFile
!= NULL
) {
2290 if (FvMapFile
!= NULL
) {
2298 UpdatePeiCoreEntryInFit (
2299 IN FIT_TABLE
*FitTablePtr
,
2300 IN UINT64 PeiCorePhysicalAddress
2304 Routine Description:
2306 This function is used to update the Pei Core address in FIT, this can be used by Sec core to pass control from
2311 FitTablePtr - The pointer of FIT_TABLE.
2312 PeiCorePhysicalAddress - The address of Pei Core entry.
2316 EFI_SUCCESS - The PEI_CORE FIT entry was updated successfully.
2317 EFI_NOT_FOUND - Not found the PEI_CORE FIT entry.
2321 FIT_TABLE
*TmpFitPtr
;
2323 UINTN NumFitComponents
;
2325 TmpFitPtr
= FitTablePtr
;
2326 NumFitComponents
= TmpFitPtr
->CompSize
;
2328 for (Index
= 0; Index
< NumFitComponents
; Index
++) {
2329 if ((TmpFitPtr
->CvAndType
& FIT_TYPE_MASK
) == COMP_TYPE_FIT_PEICORE
) {
2330 TmpFitPtr
->CompAddress
= PeiCorePhysicalAddress
;
2337 return EFI_NOT_FOUND
;
2342 IN FIT_TABLE
*FitTablePtr
2346 Routine Description:
2348 This function is used to update the checksum for FIT.
2353 FitTablePtr - The pointer of FIT_TABLE.
2361 if ((FitTablePtr
->CvAndType
& CHECKSUM_BIT_MASK
) >> 7) {
2362 FitTablePtr
->CheckSum
= 0;
2363 FitTablePtr
->CheckSum
= CalculateChecksum8 ((UINT8
*) FitTablePtr
, FitTablePtr
->CompSize
* 16);
2372 Routine Description:
2373 Calculate the FV size and Update Fv Size based on the actual FFS files.
2374 And Update FvInfo data.
2377 FvInfoPtr - The pointer to FV_INFO structure.
2380 EFI_ABORTED - Ffs Image Error
2381 EFI_SUCCESS - Successfully update FvSize
2384 UINTN CurrentOffset
;
2388 UINT32 FfsAlignment
;
2389 EFI_FFS_FILE_HEADER FfsHeader
;
2390 BOOLEAN VtfFileFlag
;
2394 VtfFileFlag
= FALSE
;
2399 // Compute size for easy access later
2401 FvInfoPtr
->Size
= 0;
2402 for (Index
= 0; FvInfoPtr
->FvBlocks
[Index
].NumBlocks
> 0 && FvInfoPtr
->FvBlocks
[Index
].Length
> 0; Index
++) {
2403 FvInfoPtr
->Size
+= FvInfoPtr
->FvBlocks
[Index
].NumBlocks
* FvInfoPtr
->FvBlocks
[Index
].Length
;
2407 // Caculate the required sizes for all FFS files.
2409 CurrentOffset
= sizeof (EFI_FIRMWARE_VOLUME_HEADER
);
2411 for (Index
= 1;; Index
++) {
2412 CurrentOffset
+= sizeof (EFI_FV_BLOCK_MAP_ENTRY
);
2413 if (FvInfoPtr
->FvBlocks
[Index
].NumBlocks
== 0 || FvInfoPtr
->FvBlocks
[Index
].Length
== 0) {
2419 // Calculate PI extension header
2421 if (CompareGuid (&mFvDataInfo
.FvNameGuid
, &mZeroGuid
) != 0) {
2422 CurrentOffset
+= sizeof (EFI_FFS_FILE_HEADER
) + sizeof (EFI_FIRMWARE_VOLUME_EXT_HEADER
);
2423 CurrentOffset
= (CurrentOffset
+ 7) & (~7);
2427 // Accumlate every FFS file size.
2429 for (Index
= 0; FvInfoPtr
->FvFiles
[Index
][0] != 0; Index
++) {
2434 fpin
= fopen (FvInfoPtr
->FvFiles
[Index
], "rb");
2436 Error (NULL
, 0, 0001, "Error opening file", FvInfoPtr
->FvFiles
[Index
]);
2440 // Get the file size
2442 FfsFileSize
= _filelength (fileno (fpin
));
2444 // Read Ffs File header
2446 fread (&FfsHeader
, sizeof (UINT8
), sizeof (EFI_FFS_FILE_HEADER
), fpin
);
2452 if (FvInfoPtr
->IsPiFvImage
) {
2454 // Check whether this ffs file is vtf file
2456 if (IsVtfFile (&FfsHeader
)) {
2459 // One Fv image can't have two vtf files.
2464 VtfFileSize
= FfsFileSize
;
2469 // Get the alignment of FFS file
2471 ReadFfsAlignment (&FfsHeader
, &FfsAlignment
);
2472 FfsAlignment
= 1 << FfsAlignment
;
2476 if (((CurrentOffset
+ sizeof (EFI_FFS_FILE_HEADER
)) % FfsAlignment
) != 0) {
2477 CurrentOffset
= (CurrentOffset
+ sizeof (EFI_FFS_FILE_HEADER
) * 2 + FfsAlignment
- 1) & ~(FfsAlignment
- 1);
2478 CurrentOffset
-= sizeof (EFI_FFS_FILE_HEADER
);
2483 // Add ffs file size
2485 if (FvInfoPtr
->SizeofFvFiles
[Index
] > FfsFileSize
) {
2486 CurrentOffset
+= FvInfoPtr
->SizeofFvFiles
[Index
];
2488 CurrentOffset
+= FfsFileSize
;
2492 // Make next ffs file start at QWord Boundry
2494 if (FvInfoPtr
->IsPiFvImage
) {
2495 CurrentOffset
= (CurrentOffset
+ EFI_FFS_FILE_HEADER_ALIGNMENT
- 1) & ~(EFI_FFS_FILE_HEADER_ALIGNMENT
- 1);
2498 CurrentOffset
+= VtfFileSize
;
2499 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
);
2501 if (FvInfoPtr
->Size
== 0) {
2503 // Update FvInfo data
2505 FvInfoPtr
->FvBlocks
[0].NumBlocks
= CurrentOffset
/ FvInfoPtr
->FvBlocks
[0].Length
+ ((CurrentOffset
% FvInfoPtr
->FvBlocks
[0].Length
)?1:0);
2506 FvInfoPtr
->Size
= FvInfoPtr
->FvBlocks
[0].NumBlocks
* FvInfoPtr
->FvBlocks
[0].Length
;
2507 FvInfoPtr
->FvBlocks
[1].NumBlocks
= 0;
2508 FvInfoPtr
->FvBlocks
[1].Length
= 0;
2509 } else if (FvInfoPtr
->Size
< CurrentOffset
) {
2513 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
);
2514 return EFI_INVALID_PARAMETER
;
2518 // Set Fv Size Information
2520 mFvTotalSize
= FvInfoPtr
->Size
;
2521 mFvTakenSize
= CurrentOffset
;
2527 FfsRebaseImageRead (
2528 IN VOID
*FileHandle
,
2529 IN UINTN FileOffset
,
2530 IN OUT UINT32
*ReadSize
,
2535 Routine Description:
2537 Support routine for the PE/COFF Loader that reads a buffer from a PE/COFF file
2541 FileHandle - The handle to the PE/COFF file
2543 FileOffset - The offset, in bytes, into the file to read
2545 ReadSize - The number of bytes to read from the file starting at FileOffset
2547 Buffer - A pointer to the buffer to read the data into.
2551 EFI_SUCCESS - ReadSize bytes of data were read into Buffer from the PE/COFF file starting at FileOffset
2555 CHAR8
*Destination8
;
2559 Destination8
= Buffer
;
2560 Source8
= (CHAR8
*) ((UINTN
) FileHandle
+ FileOffset
);
2563 *(Destination8
++) = *(Source8
++);
2571 IN OUT FV_INFO
*FvInfo
,
2573 IN OUT EFI_FFS_FILE_HEADER
*FfsFile
,
2579 Routine Description:
2581 This function determines if a file is XIP and should be rebased. It will
2582 rebase any PE32 sections found in the file using the base address.
2586 FvInfo A pointer to FV_INFO struture.
2587 FileName Ffs File PathName
2588 FfsFile A pointer to Ffs file image.
2589 XipOffset The offset address to use for rebasing the XIP file image.
2590 FvMapFile FvMapFile to record the function address in one Fvimage
2594 EFI_SUCCESS The image was properly rebased.
2595 EFI_INVALID_PARAMETER An input parameter is invalid.
2596 EFI_ABORTED An error occurred while rebasing the input file image.
2597 EFI_OUT_OF_RESOURCES Could not allocate a required resource.
2598 EFI_NOT_FOUND No compressed sections could be found.
2603 PE_COFF_LOADER_IMAGE_CONTEXT ImageContext
;
2604 PE_COFF_LOADER_IMAGE_CONTEXT OrigImageContext
;
2605 EFI_PHYSICAL_ADDRESS XipBase
;
2606 EFI_PHYSICAL_ADDRESS NewPe32BaseAddress
;
2607 EFI_PHYSICAL_ADDRESS
*BaseToUpdate
;
2609 EFI_FILE_SECTION_POINTER CurrentPe32Section
;
2610 EFI_FFS_FILE_STATE SavedState
;
2611 EFI_IMAGE_OPTIONAL_HEADER_UNION
*ImgHdr
;
2612 EFI_TE_IMAGE_HEADER
*TEImageHeader
;
2614 UINT8
*MemoryImagePointer
;
2615 EFI_IMAGE_SECTION_HEADER
*SectionHeader
;
2616 CHAR8 PeFileName
[_MAX_PATH
];
2619 UINT8
*PeFileBuffer
;
2624 MemoryImagePointer
= NULL
;
2625 BaseToUpdate
= NULL
;
2626 TEImageHeader
= NULL
;
2628 SectionHeader
= NULL
;
2631 PeFileBuffer
= NULL
;
2634 // Check XipAddress, BootAddress and RuntimeAddress
2638 if (FvInfo
->BaseAddress
!= 0) {
2639 Flags
|= REBASE_XIP_FILE
;
2640 XipBase
= FvInfo
->BaseAddress
+ XipOffset
;
2642 if (FvInfo
->BootBaseAddress
!= 0) {
2643 Flags
|= REBASE_BOOTTIME_FILE
;
2645 if (FvInfo
->RuntimeBaseAddress
!= 0) {
2646 Flags
|= REBASE_RUNTIME_FILE
;
2650 // Don't Rebase this FFS.
2651 // Only copy the original map file into the FvMap file
2652 // for the image that is not required to be relocated.
2656 // We only process files potentially containing PE32 sections.
2658 switch (FfsFile
->Type
) {
2659 case EFI_FV_FILETYPE_SECURITY_CORE
:
2660 case EFI_FV_FILETYPE_PEI_CORE
:
2661 case EFI_FV_FILETYPE_PEIM
:
2662 case EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER
:
2663 case EFI_FV_FILETYPE_DRIVER
:
2664 case EFI_FV_FILETYPE_DXE_CORE
:
2670 // Rebase each PE32 section
2672 Status
= EFI_SUCCESS
;
2673 for (Index
= 1;; Index
++) {
2677 NewPe32BaseAddress
= 0;
2682 Status
= GetSectionByType (FfsFile
, EFI_SECTION_PE32
, Index
, &CurrentPe32Section
);
2683 if (EFI_ERROR (Status
)) {
2688 // Initialize context
2690 memset (&ImageContext
, 0, sizeof (ImageContext
));
2691 ImageContext
.Handle
= (VOID
*) ((UINTN
) CurrentPe32Section
.Pe32Section
+ sizeof (EFI_PE32_SECTION
));
2692 ImageContext
.ImageRead
= (PE_COFF_LOADER_READ_FILE
) FfsRebaseImageRead
;
2693 Status
= PeCoffLoaderGetImageInfo (&ImageContext
);
2694 if (EFI_ERROR (Status
)) {
2695 Error (NULL
, 0, 3000, "Invalid PeImage", "The input file is %s and the return status is %x", FileName
, (int) Status
);
2699 if (ImageContext
.Machine
== EFI_IMAGE_MACHINE_ARMT
) {
2704 // Keep Image Context for PE image in FV
2706 memcpy (&OrigImageContext
, &ImageContext
, sizeof (ImageContext
));
2709 // Get File PdbPointer
2711 PdbPointer
= PeCoffLoaderGetPdbPointer (ImageContext
.Handle
);
2714 // Get PeHeader pointer
2716 ImgHdr
= (EFI_IMAGE_OPTIONAL_HEADER_UNION
*)((UINTN
) CurrentPe32Section
.Pe32Section
+ sizeof (EFI_PE32_SECTION
) + ImageContext
.PeCoffHeaderOffset
);
2719 // Calculate the PE32 base address, based on file type
2721 switch (FfsFile
->Type
) {
2722 case EFI_FV_FILETYPE_SECURITY_CORE
:
2723 case EFI_FV_FILETYPE_PEI_CORE
:
2724 case EFI_FV_FILETYPE_PEIM
:
2725 case EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER
:
2726 if ((Flags
& REBASE_XIP_FILE
) == 0) {
2728 // We aren't relocating XIP code, so skip it.
2734 // Check if section-alignment and file-alignment match or not
2736 if ((ImgHdr
->Pe32
.OptionalHeader
.SectionAlignment
!= ImgHdr
->Pe32
.OptionalHeader
.FileAlignment
)) {
2738 // Xip module has the same section alignment and file alignment.
2740 Error (NULL
, 0, 3000, "Invalid", "Section-Alignment and File-Alignment do not match : %s.", FileName
);
2744 // PeImage has no reloc section. It will try to get reloc data from the original EFI image.
2746 if (ImageContext
.RelocationsStripped
) {
2748 // Construct the original efi file Name
2750 strcpy (PeFileName
, FileName
);
2751 Cptr
= PeFileName
+ strlen (PeFileName
);
2752 while (*Cptr
!= '.') {
2756 Error (NULL
, 0, 3000, "Invalid", "The file %s has no .reloc section.", FileName
);
2764 PeFile
= fopen (PeFileName
, "rb");
2765 if (PeFile
== NULL
) {
2766 Warning (NULL
, 0, 0, "Invalid", "The file %s has no .reloc section.", FileName
);
2767 //Error (NULL, 0, 3000, "Invalid", "The file %s has no .reloc section.", FileName);
2768 //return EFI_ABORTED;
2772 // Get the file size
2774 PeFileSize
= _filelength (fileno (PeFile
));
2775 PeFileBuffer
= (UINT8
*) malloc (PeFileSize
);
2776 if (PeFileBuffer
== NULL
) {
2777 Error (NULL
, 0, 4001, "Resource", "memory cannot be allocated on rebase of %s", FileName
);
2778 return EFI_OUT_OF_RESOURCES
;
2783 fread (PeFileBuffer
, sizeof (UINT8
), PeFileSize
, PeFile
);
2789 // Handle pointer to the original efi image.
2791 ImageContext
.Handle
= PeFileBuffer
;
2792 Status
= PeCoffLoaderGetImageInfo (&ImageContext
);
2793 if (EFI_ERROR (Status
)) {
2794 Error (NULL
, 0, 3000, "Invalid PeImage", "The input file is %s and the return status is %x", FileName
, (int) Status
);
2797 ImageContext
.RelocationsStripped
= FALSE
;
2800 NewPe32BaseAddress
= XipBase
+ (UINTN
) CurrentPe32Section
.Pe32Section
+ sizeof (EFI_PE32_SECTION
) - (UINTN
)FfsFile
;
2801 BaseToUpdate
= &XipBase
;
2804 case EFI_FV_FILETYPE_DRIVER
:
2805 case EFI_FV_FILETYPE_DXE_CORE
:
2806 switch (ImgHdr
->Pe32
.OptionalHeader
.Subsystem
) {
2807 case EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER
:
2808 if ((Flags
& REBASE_XIP_FILE
) == REBASE_XIP_FILE
) {
2810 // Check if section-alignment and file-alignment match or not
2812 if ((ImgHdr
->Pe32
.OptionalHeader
.SectionAlignment
!= ImgHdr
->Pe32
.OptionalHeader
.FileAlignment
)) {
2814 // Xip module has the same section alignment and file alignment.
2816 Error (NULL
, 0, 3000, "Invalid", "Section-Alignment and File-Alignment do not match : %s.", FileName
);
2819 NewPe32BaseAddress
= XipBase
+ (UINTN
) CurrentPe32Section
.Pe32Section
+ sizeof (EFI_PE32_SECTION
) - (UINTN
)FfsFile
;
2820 BaseToUpdate
= &XipBase
;
2821 } else if ((Flags
& REBASE_RUNTIME_FILE
) == REBASE_RUNTIME_FILE
) {
2823 // make sure image base address at the section alignment
2825 FvInfo
->RuntimeBaseAddress
= (FvInfo
->RuntimeBaseAddress
- ImageContext
.ImageSize
) & (~(ImageContext
.SectionAlignment
- 1));
2826 FvInfo
->RuntimeBaseAddress
= FvInfo
->RuntimeBaseAddress
& (~(EFI_PAGE_SIZE
- 1));
2827 NewPe32BaseAddress
= FvInfo
->RuntimeBaseAddress
;
2828 BaseToUpdate
= &(FvInfo
->RuntimeBaseAddress
);
2831 // RT drivers aren't supposed to be relocated
2839 // We treat all other subsystems the same as BS_DRIVER
2841 if ((Flags
& REBASE_XIP_FILE
) == REBASE_XIP_FILE
) {
2843 // Check if section-alignment and file-alignment match or not
2845 if ((ImgHdr
->Pe32
.OptionalHeader
.SectionAlignment
!= ImgHdr
->Pe32
.OptionalHeader
.FileAlignment
)) {
2847 // Xip module has the same section alignment and file alignment.
2849 Error (NULL
, 0, 3000, "Invalid", "Section-Alignment and File-Alignment do not match : %s.", FileName
);
2852 NewPe32BaseAddress
= XipBase
+ (UINTN
) CurrentPe32Section
.Pe32Section
+ sizeof (EFI_PE32_SECTION
) - (UINTN
)FfsFile
;
2853 BaseToUpdate
= &XipBase
;
2854 } else if ((Flags
& REBASE_BOOTTIME_FILE
) == REBASE_BOOTTIME_FILE
) {
2856 // make sure image base address at the Section and Page alignment
2858 FvInfo
->BootBaseAddress
= (FvInfo
->BootBaseAddress
- ImageContext
.ImageSize
) & (~(ImageContext
.SectionAlignment
- 1));
2859 FvInfo
->BootBaseAddress
= FvInfo
->BootBaseAddress
& (~(EFI_PAGE_SIZE
- 1));
2860 NewPe32BaseAddress
= FvInfo
->BootBaseAddress
;
2861 BaseToUpdate
= &(FvInfo
->BootBaseAddress
);
2864 // Skip all BS_DRIVER's
2874 // Not supported file type
2880 // Relocation exist and rebase
2882 if (!ImageContext
.RelocationsStripped
) {
2884 // Load and Relocate Image Data
2886 MemoryImagePointer
= (UINT8
*) malloc ((UINTN
) ImageContext
.ImageSize
+ ImageContext
.SectionAlignment
);
2887 if (MemoryImagePointer
== NULL
) {
2888 Error (NULL
, 0, 4001, "Resource", "memory cannot be allocated on rebase of %s", FileName
);
2889 return EFI_OUT_OF_RESOURCES
;
2891 memset ((VOID
*) MemoryImagePointer
, 0, (UINTN
) ImageContext
.ImageSize
+ ImageContext
.SectionAlignment
);
2892 ImageContext
.ImageAddress
= ((UINTN
) MemoryImagePointer
+ ImageContext
.SectionAlignment
- 1) & (~(ImageContext
.SectionAlignment
- 1));
2894 Status
= PeCoffLoaderLoadImage (&ImageContext
);
2895 if (EFI_ERROR (Status
)) {
2896 Error (NULL
, 0, 3000, "Invalid", "LocateImage() call failed on rebase of %s", FileName
);
2897 free ((VOID
*) MemoryImagePointer
);
2901 ImageContext
.DestinationAddress
= NewPe32BaseAddress
;
2902 Status
= PeCoffLoaderRelocateImage (&ImageContext
);
2903 if (EFI_ERROR (Status
)) {
2904 Error (NULL
, 0, 3000, "Invalid", "RelocateImage() call failed on rebase of %s", FileName
);
2905 free ((VOID
*) MemoryImagePointer
);
2910 // Copy Relocated data to raw image file.
2912 SectionHeader
= (EFI_IMAGE_SECTION_HEADER
*) (
2915 sizeof (EFI_IMAGE_FILE_HEADER
) +
2916 ImgHdr
->Pe32
.FileHeader
.SizeOfOptionalHeader
2919 for (Index
= 0; Index
< ImgHdr
->Pe32
.FileHeader
.NumberOfSections
; Index
++, SectionHeader
++) {
2921 (UINT8
*) CurrentPe32Section
.Pe32Section
+ sizeof (EFI_COMMON_SECTION_HEADER
) + SectionHeader
->PointerToRawData
,
2922 (VOID
*) (UINTN
) (ImageContext
.ImageAddress
+ SectionHeader
->VirtualAddress
),
2923 SectionHeader
->SizeOfRawData
2927 free ((VOID
*) MemoryImagePointer
);
2928 MemoryImagePointer
= NULL
;
2929 if (PeFileBuffer
!= NULL
) {
2930 free (PeFileBuffer
);
2931 PeFileBuffer
= NULL
;
2936 // Update Image Base Address
2938 if (ImgHdr
->Pe32
.OptionalHeader
.Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
2939 ImgHdr
->Pe32
.OptionalHeader
.ImageBase
= (UINT32
) NewPe32BaseAddress
;
2940 } else if (ImgHdr
->Pe32Plus
.OptionalHeader
.Magic
== EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC
) {
2941 ImgHdr
->Pe32Plus
.OptionalHeader
.ImageBase
= NewPe32BaseAddress
;
2943 Error (NULL
, 0, 3000, "Invalid", "unknown PE magic signature %X in PE32 image %s",
2944 ImgHdr
->Pe32
.OptionalHeader
.Magic
,
2951 // Update BASE address by add one page size.
2953 *BaseToUpdate
-= EFI_PAGE_SIZE
;
2956 // Now update file checksum
2958 if (FfsFile
->Attributes
& FFS_ATTRIB_CHECKSUM
) {
2959 SavedState
= FfsFile
->State
;
2960 FfsFile
->IntegrityCheck
.Checksum
.File
= 0;
2962 if (FfsFile
->Attributes
& FFS_ATTRIB_CHECKSUM
) {
2963 FfsFile
->IntegrityCheck
.Checksum
.File
= CalculateChecksum8 (
2965 GetLength (FfsFile
->Size
)
2968 FfsFile
->IntegrityCheck
.Checksum
.File
= FFS_FIXED_CHECKSUM
;
2971 FfsFile
->State
= SavedState
;
2975 // Get this module function address from ModulePeMapFile and add them into FvMap file
2979 // Default use FileName as map file path
2981 if (PdbPointer
== NULL
) {
2982 PdbPointer
= FileName
;
2985 WriteMapFile (FvMapFile
, PdbPointer
, (EFI_GUID
*) FfsFile
, NewPe32BaseAddress
, &OrigImageContext
);
2988 if (FfsFile
->Type
!= EFI_FV_FILETYPE_SECURITY_CORE
&&
2989 FfsFile
->Type
!= EFI_FV_FILETYPE_PEI_CORE
&&
2990 FfsFile
->Type
!= EFI_FV_FILETYPE_PEIM
&&
2991 FfsFile
->Type
!= EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER
2994 // Only Peim code may have a TE section
3000 // Now process TE sections
3002 for (Index
= 1;; Index
++) {
3003 NewPe32BaseAddress
= 0;
3008 Status
= GetSectionByType (FfsFile
, EFI_SECTION_TE
, Index
, &CurrentPe32Section
);
3009 if (EFI_ERROR (Status
)) {
3014 // Calculate the TE base address, the FFS file base plus the offset of the TE section less the size stripped off
3017 TEImageHeader
= (EFI_TE_IMAGE_HEADER
*) ((UINT8
*) CurrentPe32Section
.Pe32Section
+ sizeof (EFI_COMMON_SECTION_HEADER
));
3020 // Initialize context, load image info.
3022 memset (&ImageContext
, 0, sizeof (ImageContext
));
3023 ImageContext
.Handle
= (VOID
*) TEImageHeader
;
3024 ImageContext
.ImageRead
= (PE_COFF_LOADER_READ_FILE
) FfsRebaseImageRead
;
3025 Status
= PeCoffLoaderGetImageInfo (&ImageContext
);
3026 if (EFI_ERROR (Status
)) {
3027 Error (NULL
, 0, 3000, "Invalid TeImage", "The input file is %s and the return status is %x", FileName
, (int) Status
);
3031 if (ImageContext
.Machine
== EFI_IMAGE_MACHINE_ARMT
) {
3036 // Keep Image Context for TE image in FV
3038 memcpy (&OrigImageContext
, &ImageContext
, sizeof (ImageContext
));
3041 // Get File PdbPointer
3043 PdbPointer
= PeCoffLoaderGetPdbPointer (ImageContext
.Handle
);
3045 if ((Flags
& REBASE_XIP_FILE
) == 0) {
3047 // For none XIP PEIM module, their map info also are collected.
3053 // Set new rebased address.
3055 NewPe32BaseAddress
= XipBase
+ (UINTN
) TEImageHeader
+ sizeof (EFI_TE_IMAGE_HEADER
) \
3056 - TEImageHeader
->StrippedSize
- (UINTN
) FfsFile
;
3059 // if reloc is stripped, try to get the original efi image to get reloc info.
3061 if (ImageContext
.RelocationsStripped
== TRUE
) {
3063 // Construct the original efi file name
3065 strcpy (PeFileName
, FileName
);
3066 Cptr
= PeFileName
+ strlen (PeFileName
);
3067 while (*Cptr
!= '.') {
3072 Error (NULL
, 0, 3000, "Invalid", "The file %s has no .reloc section.", FileName
);
3081 PeFile
= fopen (PeFileName
, "rb");
3082 if (PeFile
== NULL
) {
3083 Warning (NULL
, 0, 0, "Invalid", "The file %s has no .reloc section.", FileName
);
3084 //Error (NULL, 0, 3000, "Invalid", "The file %s has no .reloc section.", FileName);
3085 //return EFI_ABORTED;
3088 // Get the file size
3090 PeFileSize
= _filelength (fileno (PeFile
));
3091 PeFileBuffer
= (UINT8
*) malloc (PeFileSize
);
3092 if (PeFileBuffer
== NULL
) {
3093 Error (NULL
, 0, 4001, "Resource", "memory cannot be allocated on rebase of %s", FileName
);
3094 return EFI_OUT_OF_RESOURCES
;
3099 fread (PeFileBuffer
, sizeof (UINT8
), PeFileSize
, PeFile
);
3105 // Append reloc section into TeImage
3107 ImageContext
.Handle
= PeFileBuffer
;
3108 Status
= PeCoffLoaderGetImageInfo (&ImageContext
);
3109 if (EFI_ERROR (Status
)) {
3110 Error (NULL
, 0, 3000, "Invalid TeImage", "The input file is %s and the return status is %x", FileName
, (int) Status
);
3113 ImageContext
.RelocationsStripped
= FALSE
;
3118 // Relocation exist and rebase
3120 if (!ImageContext
.RelocationsStripped
) {
3122 // Load and Relocate Image Data
3124 MemoryImagePointer
= (UINT8
*) malloc ((UINTN
) ImageContext
.ImageSize
+ ImageContext
.SectionAlignment
);
3125 if (MemoryImagePointer
== NULL
) {
3126 Error (NULL
, 0, 4001, "Resource", "memory cannot be allocated on rebase of %s", FileName
);
3127 return EFI_OUT_OF_RESOURCES
;
3129 memset ((VOID
*) MemoryImagePointer
, 0, (UINTN
) ImageContext
.ImageSize
+ ImageContext
.SectionAlignment
);
3130 ImageContext
.ImageAddress
= ((UINTN
) MemoryImagePointer
+ ImageContext
.SectionAlignment
- 1) & (~(ImageContext
.SectionAlignment
- 1));
3132 Status
= PeCoffLoaderLoadImage (&ImageContext
);
3133 if (EFI_ERROR (Status
)) {
3134 Error (NULL
, 0, 3000, "Invalid", "LocateImage() call failed on rebase of %s", FileName
);
3135 free ((VOID
*) MemoryImagePointer
);
3139 // Reloacate TeImage
3141 ImageContext
.DestinationAddress
= NewPe32BaseAddress
;
3142 Status
= PeCoffLoaderRelocateImage (&ImageContext
);
3143 if (EFI_ERROR (Status
)) {
3144 Error (NULL
, 0, 3000, "Invalid", "RelocateImage() call failed on rebase of TE image %s", FileName
);
3145 free ((VOID
*) MemoryImagePointer
);
3150 // Copy the relocated image into raw image file.
3152 SectionHeader
= (EFI_IMAGE_SECTION_HEADER
*) (TEImageHeader
+ 1);
3153 for (Index
= 0; Index
< TEImageHeader
->NumberOfSections
; Index
++, SectionHeader
++) {
3154 if (!ImageContext
.IsTeImage
) {
3156 (UINT8
*) TEImageHeader
+ sizeof (EFI_TE_IMAGE_HEADER
) - TEImageHeader
->StrippedSize
+ SectionHeader
->PointerToRawData
,
3157 (VOID
*) (UINTN
) (ImageContext
.ImageAddress
+ SectionHeader
->VirtualAddress
),
3158 SectionHeader
->SizeOfRawData
3162 (UINT8
*) TEImageHeader
+ sizeof (EFI_TE_IMAGE_HEADER
) - TEImageHeader
->StrippedSize
+ SectionHeader
->PointerToRawData
,
3163 (VOID
*) (UINTN
) (ImageContext
.ImageAddress
+ sizeof (EFI_TE_IMAGE_HEADER
) - TEImageHeader
->StrippedSize
+ SectionHeader
->VirtualAddress
),
3164 SectionHeader
->SizeOfRawData
3170 // Free the allocated memory resource
3172 free ((VOID
*) MemoryImagePointer
);
3173 MemoryImagePointer
= NULL
;
3174 if (PeFileBuffer
!= NULL
) {
3175 free (PeFileBuffer
);
3176 PeFileBuffer
= NULL
;
3181 // Update Image Base Address
3183 TEImageHeader
->ImageBase
= NewPe32BaseAddress
;
3186 // Now update file checksum
3188 if (FfsFile
->Attributes
& FFS_ATTRIB_CHECKSUM
) {
3189 SavedState
= FfsFile
->State
;
3190 FfsFile
->IntegrityCheck
.Checksum
.File
= 0;
3192 if (FfsFile
->Attributes
& FFS_ATTRIB_CHECKSUM
) {
3193 FfsFile
->IntegrityCheck
.Checksum
.File
= CalculateChecksum8 (
3195 GetLength (FfsFile
->Size
)
3198 FfsFile
->IntegrityCheck
.Checksum
.File
= FFS_FIXED_CHECKSUM
;
3201 FfsFile
->State
= SavedState
;
3204 // Get this module function address from ModulePeMapFile and add them into FvMap file
3208 // Default use FileName as map file path
3210 if (PdbPointer
== NULL
) {
3211 PdbPointer
= FileName
;
3217 (EFI_GUID
*) FfsFile
,
3227 FindApResetVectorPosition (
3228 IN MEMORY_FILE
*FvImage
,
3233 Routine Description:
3235 Find the position in this FvImage to place Ap reset vector.
3239 FvImage Memory file for the FV memory image.
3240 Pointer Pointer to pointer to position.
3244 EFI_NOT_FOUND - No satisfied position is found.
3245 EFI_SUCCESS - The suitable position is return.
3249 EFI_FFS_FILE_HEADER
*PadFile
;
3255 for (Index
= 1; ;Index
++) {
3257 // Find Pad File to add ApResetVector info
3259 Status
= GetFileByType (EFI_FV_FILETYPE_FFS_PAD
, Index
, &PadFile
);
3260 if (EFI_ERROR (Status
) || (PadFile
== NULL
)) {
3262 // No Pad file to be found.
3267 // Get Pad file size.
3269 FileLength
= (*(UINT32
*)(PadFile
->Size
)) & 0x00FFFFFF;
3270 FileLength
= (FileLength
+ EFI_FFS_FILE_HEADER_ALIGNMENT
- 1) & ~(EFI_FFS_FILE_HEADER_ALIGNMENT
- 1);
3272 // FixPoint must be align on 0x1000 relative to FvImage Header
3274 FixPoint
= (UINT8
*) PadFile
+ sizeof (EFI_FFS_FILE_HEADER
);
3275 FixPoint
= FixPoint
+ 0x1000 - (((UINTN
) FixPoint
- (UINTN
) FvImage
->FileImage
) & 0xFFF);
3277 // FixPoint be larger at the last place of one fv image.
3279 while (((UINTN
) FixPoint
+ SIZEOF_STARTUP_DATA_ARRAY
- (UINTN
) PadFile
) <= FileLength
) {
3284 if ((UINTN
) FixPoint
< ((UINTN
) PadFile
+ sizeof (EFI_FFS_FILE_HEADER
))) {
3286 // No alignment FixPoint in this Pad File.
3291 if ((UINTN
) FvImage
->Eof
- (UINTN
)FixPoint
<= 0x20000) {
3293 // Find the position to place ApResetVector
3295 *Pointer
= FixPoint
;
3300 return EFI_NOT_FOUND
;
3305 IN MEMORY_FILE
*InfFile
,
3306 OUT CAP_INFO
*CapInfo
3310 Routine Description:
3312 This function parses a Cap.INF file and copies info into a CAP_INFO structure.
3316 InfFile Memory file image.
3317 CapInfo Information read from INF file.
3321 EFI_SUCCESS INF file information successfully retrieved.
3322 EFI_ABORTED INF file has an invalid format.
3323 EFI_NOT_FOUND A required string was not found in the INF file.
3326 CHAR8 Value
[_MAX_PATH
];
3328 UINTN Index
, Number
;
3332 // Initialize Cap info
3334 // memset (CapInfo, 0, sizeof (CAP_INFO));
3338 // Read the Capsule Guid
3340 Status
= FindToken (InfFile
, OPTIONS_SECTION_STRING
, EFI_CAPSULE_GUID_STRING
, 0, Value
);
3341 if (Status
== EFI_SUCCESS
) {
3343 // Get the Capsule Guid
3345 Status
= StringToGuid (Value
, &CapInfo
->CapGuid
);
3346 if (EFI_ERROR (Status
)) {
3347 Error (NULL
, 0, 2000, "Invalid parameter", "%s = %s", EFI_CAPSULE_GUID_STRING
, Value
);
3350 DebugMsg (NULL
, 0, 9, "Capsule Guid", "%s = %s", EFI_CAPSULE_GUID_STRING
, Value
);
3354 // Read the Capsule Header Size
3356 Status
= FindToken (InfFile
, OPTIONS_SECTION_STRING
, EFI_CAPSULE_HEADER_SIZE_STRING
, 0, Value
);
3357 if (Status
== EFI_SUCCESS
) {
3358 Status
= AsciiStringToUint64 (Value
, FALSE
, &Value64
);
3359 if (EFI_ERROR (Status
)) {
3360 Error (NULL
, 0, 2000, "Invalid parameter", "%s = %s", EFI_CAPSULE_HEADER_SIZE_STRING
, Value
);
3363 CapInfo
->HeaderSize
= (UINT32
) Value64
;
3364 DebugMsg (NULL
, 0, 9, "Capsule Header size", "%s = %s", EFI_CAPSULE_HEADER_SIZE_STRING
, Value
);
3368 // Read the Capsule Flag
3370 Status
= FindToken (InfFile
, OPTIONS_SECTION_STRING
, EFI_CAPSULE_FLAGS_STRING
, 0, Value
);
3371 if (Status
== EFI_SUCCESS
) {
3372 if (strstr (Value
, "PopulateSystemTable") != NULL
) {
3373 CapInfo
->Flags
|= CAPSULE_FLAGS_PERSIST_ACROSS_RESET
| CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE
;
3374 if (strstr (Value
, "InitiateReset") != NULL
) {
3375 CapInfo
->Flags
|= CAPSULE_FLAGS_INITIATE_RESET
;
3377 } else if (strstr (Value
, "PersistAcrossReset") != NULL
) {
3378 CapInfo
->Flags
|= CAPSULE_FLAGS_PERSIST_ACROSS_RESET
;
3379 if (strstr (Value
, "InitiateReset") != NULL
) {
3380 CapInfo
->Flags
|= CAPSULE_FLAGS_INITIATE_RESET
;
3383 Error (NULL
, 0, 2000, "Invalid parameter", "invalid Flag setting for %s.", EFI_CAPSULE_FLAGS_STRING
);
3386 DebugMsg (NULL
, 0, 9, "Capsule Flag", Value
);
3390 // Read Capsule File name
3392 Status
= FindToken (InfFile
, OPTIONS_SECTION_STRING
, EFI_FILE_NAME_STRING
, 0, Value
);
3393 if (Status
== EFI_SUCCESS
) {
3395 // Get output file name
3397 strcpy (CapInfo
->CapName
, Value
);
3401 // Read the Capsule FileImage
3404 for (Index
= 0; Index
< MAX_NUMBER_OF_FILES_IN_CAP
; Index
++) {
3405 if (CapInfo
->CapFiles
[Index
][0] != '\0') {
3409 // Read the capsule file name
3411 Status
= FindToken (InfFile
, FILES_SECTION_STRING
, EFI_FILE_NAME_STRING
, Number
++, Value
);
3413 if (Status
== EFI_SUCCESS
) {
3417 strcpy (CapInfo
->CapFiles
[Index
], Value
);
3418 DebugMsg (NULL
, 0, 9, "Capsule component file", "the %uth file name is %s", (unsigned) Index
, CapInfo
->CapFiles
[Index
]);
3425 Warning (NULL
, 0, 0, "Capsule components are not specified.", NULL
);
3433 IN CHAR8
*InfFileImage
,
3434 IN UINTN InfFileSize
,
3435 IN CHAR8
*CapFileName
3439 Routine Description:
3441 This is the main function which will be called from application to create UEFI Capsule image.
3445 InfFileImage Buffer containing the INF file contents.
3446 InfFileSize Size of the contents of the InfFileImage buffer.
3447 CapFileName Requested name for the Cap file.
3451 EFI_SUCCESS Function completed successfully.
3452 EFI_OUT_OF_RESOURCES Could not allocate required resources.
3453 EFI_ABORTED Error encountered.
3454 EFI_INVALID_PARAMETER A required parameter was NULL.
3460 EFI_CAPSULE_HEADER
*CapsuleHeader
;
3461 MEMORY_FILE InfMemoryFile
;
3467 if (InfFileImage
!= NULL
) {
3469 // Initialize file structures
3471 InfMemoryFile
.FileImage
= InfFileImage
;
3472 InfMemoryFile
.CurrentFilePointer
= InfFileImage
;
3473 InfMemoryFile
.Eof
= InfFileImage
+ InfFileSize
;
3476 // Parse the Cap inf file for header information
3478 Status
= ParseCapInf (&InfMemoryFile
, &mCapDataInfo
);
3479 if (Status
!= EFI_SUCCESS
) {
3484 if (mCapDataInfo
.HeaderSize
== 0) {
3486 // make header size align 16 bytes.
3488 mCapDataInfo
.HeaderSize
= sizeof (EFI_CAPSULE_HEADER
);
3489 mCapDataInfo
.HeaderSize
= (mCapDataInfo
.HeaderSize
+ 0xF) & ~0xF;
3492 if (mCapDataInfo
.HeaderSize
< sizeof (EFI_CAPSULE_HEADER
)) {
3493 Error (NULL
, 0, 2000, "Invalid parameter", "The specified HeaderSize cannot be less than the size of EFI_CAPSULE_HEADER.");
3494 return EFI_INVALID_PARAMETER
;
3497 if (CapFileName
== NULL
&& mCapDataInfo
.CapName
[0] != '\0') {
3498 CapFileName
= mCapDataInfo
.CapName
;
3501 if (CapFileName
== NULL
) {
3502 Error (NULL
, 0, 2001, "Missing required argument", "Output Capsule file name");
3503 return EFI_INVALID_PARAMETER
;
3507 // Set Default Capsule Guid value
3509 if (CompareGuid (&mCapDataInfo
.CapGuid
, &mZeroGuid
) == 0) {
3510 memcpy (&mCapDataInfo
.CapGuid
, &mDefaultCapsuleGuid
, sizeof (EFI_GUID
));
3513 // Calculate the size of capsule image.
3517 CapSize
= mCapDataInfo
.HeaderSize
;
3518 while (mCapDataInfo
.CapFiles
[Index
][0] != '\0') {
3519 fpin
= fopen (mCapDataInfo
.CapFiles
[Index
], "rb");
3521 Error (NULL
, 0, 0001, "Error opening file", mCapDataInfo
.CapFiles
[Index
]);
3524 FileSize
= _filelength (fileno (fpin
));
3525 CapSize
+= FileSize
;
3531 // Allocate buffer for capsule image.
3533 CapBuffer
= (UINT8
*) malloc (CapSize
);
3534 if (CapBuffer
== NULL
) {
3535 Error (NULL
, 0, 4001, "Resource", "memory cannot be allocated for creating the capsule.");
3536 return EFI_OUT_OF_RESOURCES
;
3540 // Initialize the capsule header to zero
3542 memset (CapBuffer
, 0, mCapDataInfo
.HeaderSize
);
3545 // create capsule header and get capsule body
3547 CapsuleHeader
= (EFI_CAPSULE_HEADER
*) CapBuffer
;
3548 memcpy (&CapsuleHeader
->CapsuleGuid
, &mCapDataInfo
.CapGuid
, sizeof (EFI_GUID
));
3549 CapsuleHeader
->HeaderSize
= mCapDataInfo
.HeaderSize
;
3550 CapsuleHeader
->Flags
= mCapDataInfo
.Flags
;
3551 CapsuleHeader
->CapsuleImageSize
= CapSize
;
3555 CapSize
= CapsuleHeader
->HeaderSize
;
3556 while (mCapDataInfo
.CapFiles
[Index
][0] != '\0') {
3557 fpin
= fopen (mCapDataInfo
.CapFiles
[Index
], "rb");
3559 Error (NULL
, 0, 0001, "Error opening file", mCapDataInfo
.CapFiles
[Index
]);
3563 FileSize
= _filelength (fileno (fpin
));
3564 fread (CapBuffer
+ CapSize
, 1, FileSize
, fpin
);
3567 CapSize
+= FileSize
;
3571 // write capsule data into the output file
3573 fpout
= fopen (CapFileName
, "wb");
3574 if (fpout
== NULL
) {
3575 Error (NULL
, 0, 0001, "Error opening file", CapFileName
);
3580 fwrite (CapBuffer
, 1, CapSize
, fpout
);
3583 VerboseMsg ("The size of the generated capsule image is %u bytes", (unsigned) CapSize
);