2 This file contains functions required to generate a Firmware File System file.
4 Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
12 #include <sys/types.h>
24 #include <Common/UefiBaseTypes.h>
25 #include <Common/PiFirmwareFile.h>
26 #include <IndustryStandard/PeImage.h>
27 #include <Guid/FfsSectionAlignmentPadding.h>
29 #include "CommonLib.h"
31 #include "EfiUtilityMsgs.h"
33 #include "PeCoffLib.h"
35 #define UTILITY_NAME "GenFfs"
36 #define UTILITY_MAJOR_VERSION 0
37 #define UTILITY_MINOR_VERSION 1
39 STATIC CHAR8
*mFfsFileType
[] = {
41 "EFI_FV_FILETYPE_RAW", // 0x01
42 "EFI_FV_FILETYPE_FREEFORM", // 0x02
43 "EFI_FV_FILETYPE_SECURITY_CORE", // 0x03
44 "EFI_FV_FILETYPE_PEI_CORE", // 0x04
45 "EFI_FV_FILETYPE_DXE_CORE", // 0x05
46 "EFI_FV_FILETYPE_PEIM", // 0x06
47 "EFI_FV_FILETYPE_DRIVER", // 0x07
48 "EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER", // 0x08
49 "EFI_FV_FILETYPE_APPLICATION", // 0x09
50 "EFI_FV_FILETYPE_SMM", // 0x0A
51 "EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE",// 0x0B
52 "EFI_FV_FILETYPE_COMBINED_SMM_DXE", // 0x0C
53 "EFI_FV_FILETYPE_SMM_CORE", // 0x0D
54 "EFI_FV_FILETYPE_MM_STANDALONE", // 0x0E
55 "EFI_FV_FILETYPE_MM_CORE_STANDALONE" // 0x0F
58 STATIC CHAR8
*mAlignName
[] = {
59 "1", "2", "4", "8", "16", "32", "64", "128", "256", "512",
60 "1K", "2K", "4K", "8K", "16K", "32K", "64K", "128K", "256K",
61 "512K", "1M", "2M", "4M", "8M", "16M"
64 STATIC CHAR8
*mFfsValidAlignName
[] = {
65 "8", "16", "128", "512", "1K", "4K", "32K", "64K", "128K","256K",
66 "512K", "1M", "2M", "4M", "8M", "16M"
69 STATIC UINT32 mFfsValidAlign
[] = {0, 8, 16, 128, 512, 1024, 4096, 32768, 65536, 131072, 262144,
70 524288, 1048576, 2097152, 4194304, 8388608, 16777216};
72 STATIC EFI_GUID mZeroGuid
= {0};
74 STATIC EFI_GUID mEfiFfsSectionAlignmentPaddingGuid
= EFI_FFS_SECTION_ALIGNMENT_PADDING_GUID
;
85 Print out version information for this utility.
97 fprintf (stdout
, "%s Version %d.%d %s \n", UTILITY_NAME
, UTILITY_MAJOR_VERSION
, UTILITY_MINOR_VERSION
, __BUILD_VERSION
);
109 Print Error / Help message.
124 fprintf (stdout
, "\nUsage: %s [options]\n\n", UTILITY_NAME
);
127 // Copyright declaration
129 fprintf (stdout
, "Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.\n\n");
134 fprintf (stdout
, "Options:\n");
135 fprintf (stdout
, " -o FileName, --outputfile FileName\n\
136 File is FFS file to be created.\n");
137 fprintf (stdout
, " -t Type, --filetype Type\n\
138 Type is one FV file type defined in PI spec, which is\n\
139 EFI_FV_FILETYPE_RAW, EFI_FV_FILETYPE_FREEFORM,\n\
140 EFI_FV_FILETYPE_SECURITY_CORE, EFI_FV_FILETYPE_PEIM,\n\
141 EFI_FV_FILETYPE_PEI_CORE, EFI_FV_FILETYPE_DXE_CORE,\n\
142 EFI_FV_FILETYPE_DRIVER, EFI_FV_FILETYPE_APPLICATION,\n\
143 EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER,\n\
144 EFI_FV_FILETYPE_SMM, EFI_FV_FILETYPE_SMM_CORE,\n\
145 EFI_FV_FILETYPE_MM_STANDALONE,\n\
146 EFI_FV_FILETYPE_MM_CORE_STANDALONE,\n\
147 EFI_FV_FILETYPE_COMBINED_SMM_DXE, \n\
148 EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE.\n");
149 fprintf (stdout
, " -g FileGuid, --fileguid FileGuid\n\
150 FileGuid is one module guid.\n\
151 Its format is xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx\n");
152 fprintf (stdout
, " -x, --fixed Indicates that the file may not be moved\n\
153 from its present location.\n");
154 fprintf (stdout
, " -s, --checksum Indicates to calculate file checksum.\n");
155 fprintf (stdout
, " -a FileAlign, --align FileAlign\n\
156 FileAlign points to file alignment, which only support\n\
157 the following align: 1,2,4,8,16,128,512,1K,4K,32K,64K\n\
158 128K,256K,512K,1M,2M,4M,8M,16M\n");
159 fprintf (stdout
, " -i SectionFile, --sectionfile SectionFile\n\
160 Section file will be contained in this FFS file.\n");
161 fprintf (stdout
, " -oi SectionFile, --optionalsectionfile SectionFile\n\
162 If the Section file exists, it will be contained in this FFS file, otherwise, it will be ignored.\n");
163 fprintf (stdout
, " -n SectionAlign, --sectionalign SectionAlign\n\
164 SectionAlign points to section alignment, which support\n\
165 the alignment scope 0~16M. If SectionAlign is specified\n\
166 as 0, tool get alignment value from SectionFile. It is\n\
167 specified together with sectionfile to point its\n\
168 alignment in FFS file.\n");
169 fprintf (stdout
, " -v, --verbose Turn on verbose output with informational messages.\n");
170 fprintf (stdout
, " -q, --quiet Disable all messages except key message and fatal error\n");
171 fprintf (stdout
, " -d, --debug level Enable debug messages, at input debug level.\n");
172 fprintf (stdout
, " --version Show program's version number and exit.\n");
173 fprintf (stdout
, " -h, --help Show this help message and exit.\n");
179 IN CHAR8
*AlignBuffer
,
180 OUT UINT32
*AlignNumber
186 Converts Align String to align value (1~16M).
190 AlignBuffer - Pointer to Align string.
191 AlignNumber - Pointer to Align value.
195 EFI_SUCCESS Successfully convert align string to align value.
196 EFI_INVALID_PARAMETER Align string is invalid or align value is not in scope.
204 if (AlignBuffer
== NULL
) {
205 return EFI_INVALID_PARAMETER
;
207 for (Index
= 0; Index
< sizeof (mAlignName
) / sizeof (CHAR8
*); Index
++) {
208 if (stricmp (AlignBuffer
, mAlignName
[Index
]) == 0) {
209 *AlignNumber
= 1 << Index
;
213 return EFI_INVALID_PARAMETER
;
225 Converts File Type String to value. EFI_FV_FILETYPE_ALL indicates that an
226 unrecognized file type was specified.
230 String - File type string
240 if (String
== NULL
) {
241 return EFI_FV_FILETYPE_ALL
;
244 for (Index
= 0; Index
< sizeof (mFfsFileType
) / sizeof (CHAR8
*); Index
++) {
245 if (mFfsFileType
[Index
] != NULL
&& (stricmp (String
, mFfsFileType
[Index
]) == 0)) {
249 return EFI_FV_FILETYPE_ALL
;
255 IN CHAR8
**InputFileName
,
256 IN UINT32
*InputFileAlign
,
257 IN UINT32 InputFileNum
,
258 IN EFI_FFS_FILE_ATTRIBUTES FfsAttrib
,
259 OUT UINT8
*FileBuffer
,
260 OUT UINT32
*BufferLength
,
261 OUT UINT32
*MaxAlignment
,
262 OUT UINT8
*PESectionNum
268 Get the contents of all section files specified in InputFileName
273 InputFileName - Name of the input file.
275 InputFileAlign - Alignment required by the input file data.
277 InputFileNum - Number of input files. Should be at least 1.
279 FileBuffer - Output buffer to contain data
281 BufferLength - On input, this is size of the FileBuffer.
282 On output, this is the actual length of the data.
284 MaxAlignment - The max alignment required by all the input file datas.
286 PeSectionNum - Calculate the number of Pe/Te Section in this FFS file.
290 EFI_SUCCESS on successful return
291 EFI_INVALID_PARAMETER if InputFileNum is less than 1 or BufferLength point is NULL.
292 EFI_ABORTED if unable to open input file.
293 EFI_BUFFER_TOO_SMALL FileBuffer is not enough to contain all file data.
301 EFI_FREEFORM_SUBTYPE_GUID_SECTION
*SectHeader
;
302 EFI_COMMON_SECTION_HEADER2 TempSectHeader
;
303 EFI_TE_IMAGE_HEADER TeHeader
;
305 EFI_GUID_DEFINED_SECTION GuidSectHeader
;
306 EFI_GUID_DEFINED_SECTION2 GuidSectHeader2
;
308 UINT32 MaxEncounteredAlignment
;
313 MaxEncounteredAlignment
= 1;
316 // Go through our array of file names and copy their contents
317 // to the output buffer.
319 for (Index
= 0; Index
< InputFileNum
; Index
++) {
321 // make sure section ends on a DWORD boundary
323 while ((Size
& 0x03) != 0) {
328 // Open file and read contents
330 InFile
= fopen (LongFilePath (InputFileName
[Index
]), "rb");
331 if (InFile
== NULL
) {
332 Error (NULL
, 0, 0001, "Error opening file", InputFileName
[Index
]);
336 fseek (InFile
, 0, SEEK_END
);
337 FileSize
= ftell (InFile
);
338 fseek (InFile
, 0, SEEK_SET
);
339 DebugMsg (NULL
, 0, 9, "Input section files",
340 "the input section name is %s and the size is %u bytes", InputFileName
[Index
], (unsigned) FileSize
);
343 // Check this section is Te/Pe section, and Calculate the numbers of Te/Pe section.
346 if (FileSize
>= MAX_FFS_SIZE
) {
347 HeaderSize
= sizeof (EFI_COMMON_SECTION_HEADER2
);
349 HeaderSize
= sizeof (EFI_COMMON_SECTION_HEADER
);
351 fread (&TempSectHeader
, 1, HeaderSize
, InFile
);
352 if (TempSectHeader
.Type
== EFI_SECTION_TE
) {
354 fread (&TeHeader
, 1, sizeof (TeHeader
), InFile
);
355 if (TeHeader
.Signature
== EFI_TE_IMAGE_HEADER_SIGNATURE
) {
356 TeOffset
= TeHeader
.StrippedSize
- sizeof (TeHeader
);
358 } else if (TempSectHeader
.Type
== EFI_SECTION_PE32
) {
360 } else if (TempSectHeader
.Type
== EFI_SECTION_GUID_DEFINED
) {
361 fseek (InFile
, 0, SEEK_SET
);
362 if (FileSize
>= MAX_SECTION_SIZE
) {
363 fread (&GuidSectHeader2
, 1, sizeof (GuidSectHeader2
), InFile
);
364 if ((GuidSectHeader2
.Attributes
& EFI_GUIDED_SECTION_PROCESSING_REQUIRED
) == 0) {
365 HeaderSize
= GuidSectHeader2
.DataOffset
;
368 fread (&GuidSectHeader
, 1, sizeof (GuidSectHeader
), InFile
);
369 if ((GuidSectHeader
.Attributes
& EFI_GUIDED_SECTION_PROCESSING_REQUIRED
) == 0) {
370 HeaderSize
= GuidSectHeader
.DataOffset
;
374 } else if (TempSectHeader
.Type
== EFI_SECTION_COMPRESSION
||
375 TempSectHeader
.Type
== EFI_SECTION_FIRMWARE_VOLUME_IMAGE
) {
377 // for the encapsulated section, assume it contains Pe/Te section
382 fseek (InFile
, 0, SEEK_SET
);
385 // Revert TeOffset to the converse value relative to Alignment
386 // This is to assure the original PeImage Header at Alignment.
388 if ((TeOffset
!= 0) && (InputFileAlign
[Index
] != 0)) {
389 TeOffset
= InputFileAlign
[Index
] - (TeOffset
% InputFileAlign
[Index
]);
390 TeOffset
= TeOffset
% InputFileAlign
[Index
];
394 // make sure section data meet its alignment requirement by adding one pad section.
395 // But the different sections have the different section header. Necessary or not?
396 // Based on section type to adjust offset? Todo
398 if ((InputFileAlign
[Index
] != 0) && (((Size
+ HeaderSize
+ TeOffset
) % InputFileAlign
[Index
]) != 0)) {
399 Offset
= (Size
+ sizeof (EFI_COMMON_SECTION_HEADER
) + HeaderSize
+ TeOffset
+ InputFileAlign
[Index
] - 1) & ~(InputFileAlign
[Index
] - 1);
400 Offset
= Offset
- Size
- HeaderSize
- TeOffset
;
402 if (FileBuffer
!= NULL
&& ((Size
+ Offset
) < *BufferLength
)) {
404 // The maximal alignment is 64K, the raw section size must be less than 0xffffff
406 memset (FileBuffer
+ Size
, 0, Offset
);
407 SectHeader
= (EFI_FREEFORM_SUBTYPE_GUID_SECTION
*) (FileBuffer
+ Size
);
408 SectHeader
->CommonHeader
.Size
[0] = (UINT8
) (Offset
& 0xff);
409 SectHeader
->CommonHeader
.Size
[1] = (UINT8
) ((Offset
& 0xff00) >> 8);
410 SectHeader
->CommonHeader
.Size
[2] = (UINT8
) ((Offset
& 0xff0000) >> 16);
413 // Only add a special reducible padding section if
414 // - this FFS has the FFS_ATTRIB_FIXED attribute,
415 // - none of the preceding sections have alignment requirements,
416 // - the size of the padding is sufficient for the
417 // EFI_SECTION_FREEFORM_SUBTYPE_GUID header.
419 if ((FfsAttrib
& FFS_ATTRIB_FIXED
) != 0 &&
420 MaxEncounteredAlignment
<= 1 &&
421 Offset
>= sizeof (EFI_FREEFORM_SUBTYPE_GUID_SECTION
)) {
422 SectHeader
->CommonHeader
.Type
= EFI_SECTION_FREEFORM_SUBTYPE_GUID
;
423 SectHeader
->SubTypeGuid
= mEfiFfsSectionAlignmentPaddingGuid
;
425 SectHeader
->CommonHeader
.Type
= EFI_SECTION_RAW
;
428 DebugMsg (NULL
, 0, 9, "Pad raw section for section data alignment",
429 "Pad Raw section size is %u", (unsigned) Offset
);
431 Size
= Size
+ Offset
;
435 // Get the Max alignment of all input file datas
437 if (MaxEncounteredAlignment
< InputFileAlign
[Index
]) {
438 MaxEncounteredAlignment
= InputFileAlign
[Index
];
442 // Now read the contents of the file into the buffer
443 // Buffer must be enough to contain the file content.
445 if ((FileSize
> 0) && (FileBuffer
!= NULL
) && ((Size
+ FileSize
) <= *BufferLength
)) {
446 if (fread (FileBuffer
+ Size
, (size_t) FileSize
, 1, InFile
) != 1) {
447 Error (NULL
, 0, 0004, "Error reading file", InputFileName
[Index
]);
457 *MaxAlignment
= MaxEncounteredAlignment
;
460 // Set the actual length of the data.
462 if (Size
> *BufferLength
) {
463 *BufferLength
= Size
;
464 return EFI_BUFFER_TOO_SMALL
;
466 *BufferLength
= Size
;
475 IN OUT UINT32
*ReadSize
,
482 Support routine for the PE/COFF Loader that reads a buffer from a PE/COFF file
486 FileHandle - The handle to the PE/COFF file
488 FileOffset - The offset, in bytes, into the file to read
490 ReadSize - The number of bytes to read from the file starting at FileOffset
492 Buffer - A pointer to the buffer to read the data into.
496 EFI_SUCCESS - ReadSize bytes of data were read into Buffer from the PE/COFF file starting at FileOffset
504 Destination8
= Buffer
;
505 Source8
= (CHAR8
*) ((UINTN
) FileHandle
+ FileOffset
);
508 *(Destination8
++) = *(Source8
++);
516 GetAlignmentFromFile(char *InFile
, UINT32
*Alignment
)
518 InFile is input file for getting alignment
525 UINT32 CurSecHdrSize
;
526 PE_COFF_LOADER_IMAGE_CONTEXT ImageContext
;
527 EFI_COMMON_SECTION_HEADER
*CommonHeader
;
534 memset (&ImageContext
, 0, sizeof (ImageContext
));
536 InFileHandle
= fopen(LongFilePath(InFile
), "rb");
537 if (InFileHandle
== NULL
){
538 Error (NULL
, 0, 0001, "Error opening file", InFile
);
541 PeFileSize
= _filelength (fileno(InFileHandle
));
542 PeFileBuffer
= (UINT8
*) malloc (PeFileSize
);
543 if (PeFileBuffer
== NULL
) {
544 fclose (InFileHandle
);
545 Error(NULL
, 0, 4001, "Resource", "memory cannot be allocated for %s", InFile
);
546 return EFI_OUT_OF_RESOURCES
;
548 fread (PeFileBuffer
, sizeof (UINT8
), PeFileSize
, InFileHandle
);
549 fclose (InFileHandle
);
550 CommonHeader
= (EFI_COMMON_SECTION_HEADER
*) PeFileBuffer
;
551 CurSecHdrSize
= GetSectionHeaderLength(CommonHeader
);
552 ImageContext
.Handle
= (VOID
*) ((UINTN
)PeFileBuffer
+ CurSecHdrSize
);
553 ImageContext
.ImageRead
= (PE_COFF_LOADER_READ_FILE
)FfsRebaseImageRead
;
554 Status
= PeCoffLoaderGetImageInfo(&ImageContext
);
555 if (EFI_ERROR (Status
)) {
556 Error (NULL
, 0, 3000, "Invalid PeImage", "The input file is %s and return status is %x", InFile
, (int) Status
);
559 *Alignment
= ImageContext
.SectionAlignment
;
560 // Free the allocated memory resource
561 if (PeFileBuffer
!= NULL
) {
581 argc - Number of command line parameters.
582 argv - Array of pointers to parameter strings.
585 STATUS_SUCCESS - Utility exits successfully.
586 STATUS_ERROR - Some error occurred during execution.
591 EFI_FFS_FILE_ATTRIBUTES FfsAttrib
;
593 EFI_FV_FILETYPE FfsFiletype
;
594 CHAR8
*OutputFileName
;
595 EFI_GUID FileGuid
= {0};
597 UINT32
*InputFileAlign
;
598 CHAR8
**InputFileName
;
602 EFI_FFS_FILE_HEADER2 FfsFileHeader
;
610 // Workaround for static code checkers.
611 // Ensures the size of 'AlignmentBuffer' can hold all the digits of an
612 // unsigned 32-bit integer plus the size unit character.
614 CHAR8 AlignmentBuffer
[16];
617 // Init local variables
623 FfsFiletype
= EFI_FV_FILETYPE_ALL
;
624 OutputFileName
= NULL
;
626 InputFileName
= NULL
;
627 InputFileAlign
= NULL
;
632 Status
= EFI_SUCCESS
;
635 SetUtilityName (UTILITY_NAME
);
638 Error (NULL
, 0, 1001, "Missing options", "no options input");
644 // Parse command line
649 if ((stricmp (argv
[0], "-h") == 0) || (stricmp (argv
[0], "--help") == 0)) {
652 return STATUS_SUCCESS
;
655 if (stricmp (argv
[0], "--version") == 0) {
657 return STATUS_SUCCESS
;
661 if ((stricmp (argv
[0], "-t") == 0) || (stricmp (argv
[0], "--filetype") == 0)) {
662 if (argv
[1] == NULL
|| argv
[1][0] == '-') {
663 Error (NULL
, 0, 1003, "Invalid option value", "file type is missing for -t option");
666 FfsFiletype
= StringToType (argv
[1]);
667 if (FfsFiletype
== EFI_FV_FILETYPE_ALL
) {
668 Error (NULL
, 0, 1003, "Invalid option value", "%s is not a valid file type", argv
[1]);
676 if ((stricmp (argv
[0], "-o") == 0) || (stricmp (argv
[0], "--outputfile") == 0)) {
677 if (argv
[1] == NULL
|| argv
[1][0] == '-') {
678 Error (NULL
, 0, 1003, "Invalid option value", "Output file is missing for -o option");
681 OutputFileName
= argv
[1];
687 if ((stricmp (argv
[0], "-g") == 0) || (stricmp (argv
[0], "--fileguid") == 0)) {
688 Status
= StringToGuid (argv
[1], &FileGuid
);
689 if (EFI_ERROR (Status
)) {
690 Error (NULL
, 0, 1003, "Invalid option value", "%s = %s", argv
[0], argv
[1]);
698 if ((stricmp (argv
[0], "-x") == 0) || (stricmp (argv
[0], "--fixed") == 0)) {
699 FfsAttrib
|= FFS_ATTRIB_FIXED
;
705 if ((stricmp (argv
[0], "-s") == 0) || (stricmp (argv
[0], "--checksum") == 0)) {
706 FfsAttrib
|= FFS_ATTRIB_CHECKSUM
;
712 if ((stricmp (argv
[0], "-a") == 0) || (stricmp (argv
[0], "--align") == 0)) {
713 if (argv
[1] == NULL
|| argv
[1][0] == '-') {
714 Error (NULL
, 0, 1003, "Invalid option value", "Align value is missing for -a option");
717 for (Index
= 0; Index
< sizeof (mFfsValidAlignName
) / sizeof (CHAR8
*); Index
++) {
718 if (stricmp (argv
[1], mFfsValidAlignName
[Index
]) == 0) {
722 if (Index
== sizeof (mFfsValidAlignName
) / sizeof (CHAR8
*)) {
723 if ((stricmp (argv
[1], "1") == 0) || (stricmp (argv
[1], "2") == 0) || (stricmp (argv
[1], "4") == 0)) {
725 // 1, 2, 4 byte alignment same to 8 byte alignment
729 Error (NULL
, 0, 1003, "Invalid option value", "%s = %s", argv
[0], argv
[1]);
739 if ((stricmp (argv
[0], "-oi") == 0) || (stricmp (argv
[0], "--optionalsectionfile") == 0) || (stricmp (argv
[0], "-i") == 0) || (stricmp (argv
[0], "--sectionfile") == 0)) {
741 // Get Input file name and its alignment
743 if (argv
[1] == NULL
|| argv
[1][0] == '-') {
744 Error (NULL
, 0, 1003, "Invalid option value", "input section file is missing for -i option");
747 if ((stricmp (argv
[0], "-oi") == 0) || (stricmp (argv
[0], "--optionalsectionfile") == 0) ){
748 if (-1 == access(argv
[1] , 0)){
749 Warning(NULL
, 0, 0001, "File is not found.", argv
[1]);
756 // Allocate Input file name buffer and its alignment buffer.
758 if ((InputFileNum
== 0) && (InputFileName
== NULL
)) {
759 InputFileName
= (CHAR8
**) malloc (MAXIMUM_INPUT_FILE_NUM
* sizeof (CHAR8
*));
760 if (InputFileName
== NULL
) {
761 Error (NULL
, 0, 4001, "Resource", "memory cannot be allocated!");
764 memset (InputFileName
, 0, (MAXIMUM_INPUT_FILE_NUM
* sizeof (CHAR8
*)));
766 InputFileAlign
= (UINT32
*) malloc (MAXIMUM_INPUT_FILE_NUM
* sizeof (UINT32
));
767 if (InputFileAlign
== NULL
) {
768 Error (NULL
, 0, 4001, "Resource", "memory cannot be allocated!");
769 free (InputFileName
);
772 memset (InputFileAlign
, 0, MAXIMUM_INPUT_FILE_NUM
* sizeof (UINT32
));
773 } else if (InputFileNum
% MAXIMUM_INPUT_FILE_NUM
== 0) {
775 // InputFileName and alignment buffer too small, need to realloc
777 InputFileName
= (CHAR8
**) realloc (
779 (InputFileNum
+ MAXIMUM_INPUT_FILE_NUM
) * sizeof (CHAR8
*)
782 if (InputFileName
== NULL
) {
783 Error (NULL
, 0, 4001, "Resource", "memory cannot be allocated!");
784 free (InputFileAlign
);
787 memset (&(InputFileName
[InputFileNum
]), 0, (MAXIMUM_INPUT_FILE_NUM
* sizeof (CHAR8
*)));
789 InputFileAlign
= (UINT32
*) realloc (
791 (InputFileNum
+ MAXIMUM_INPUT_FILE_NUM
) * sizeof (UINT32
)
794 if (InputFileAlign
== NULL
) {
795 Error (NULL
, 0, 4001, "Resource", "memory cannot be allocated!");
796 free (InputFileName
);
799 memset (&(InputFileAlign
[InputFileNum
]), 0, (MAXIMUM_INPUT_FILE_NUM
* sizeof (UINT32
)));
802 InputFileName
[InputFileNum
] = argv
[1];
812 // Section File alignment requirement
814 if ((stricmp (argv
[0], "-n") == 0) || (stricmp (argv
[0], "--sectionalign") == 0)) {
815 if ((argv
[1] != NULL
) && (stricmp("0", argv
[1]) == 0)) {
816 Status
= GetAlignmentFromFile(InputFileName
[InputFileNum
], &Alignment
);
817 if (EFI_ERROR(Status
)) {
818 Error (NULL
, 0, 1003, "Fail to get Alignment from %s", InputFileName
[InputFileNum
]);
821 if (Alignment
< 0x400){
822 sprintf (AlignmentBuffer
, "%d", Alignment
);
824 else if (Alignment
>= 0x100000) {
825 sprintf (AlignmentBuffer
, "%dM", Alignment
/0x100000);
828 sprintf (AlignmentBuffer
, "%dK", Alignment
/0x400);
830 Status
= StringtoAlignment (AlignmentBuffer
, &(InputFileAlign
[InputFileNum
]));
833 Status
= StringtoAlignment (argv
[1], &(InputFileAlign
[InputFileNum
]));
835 if (EFI_ERROR (Status
)) {
836 Error (NULL
, 0, 1003, "Invalid option value", "%s = %s", argv
[0], argv
[1]);
846 if ((stricmp (argv
[0], "-n") == 0) || (stricmp (argv
[0], "--sectionalign") == 0)) {
847 Error (NULL
, 0, 1000, "Unknown option", "SectionAlign option must be specified with section file.");
851 if ((stricmp (argv
[0], "-v") == 0) || (stricmp (argv
[0], "--verbose") == 0)) {
852 SetPrintLevel (VERBOSE_LOG_LEVEL
);
853 VerboseMsg ("Verbose output Mode Set!");
859 if ((stricmp (argv
[0], "-q") == 0) || (stricmp (argv
[0], "--quiet") == 0)) {
860 SetPrintLevel (KEY_LOG_LEVEL
);
861 KeyMsg ("Quiet output Mode Set!");
867 if ((stricmp (argv
[0], "-d") == 0) || (stricmp (argv
[0], "--debug") == 0)) {
868 Status
= AsciiStringToUint64 (argv
[1], FALSE
, &LogLevel
);
869 if (EFI_ERROR (Status
)) {
870 Error (NULL
, 0, 1003, "Invalid option value", "%s = %s", argv
[0], argv
[1]);
874 Error (NULL
, 0, 1003, "Invalid option value", "Debug Level range is 0-9, current input level is %d", (int) LogLevel
);
877 SetPrintLevel (LogLevel
);
878 DebugMsg (NULL
, 0, 9, "Debug Mode Set", "Debug Output Mode Level %s is set!", argv
[1]);
884 Error (NULL
, 0, 1000, "Unknown option", "%s", argv
[0]);
888 VerboseMsg ("%s tool start.", UTILITY_NAME
);
891 // Check the complete input parameters.
893 if (FfsFiletype
== EFI_FV_FILETYPE_ALL
) {
894 Error (NULL
, 0, 1001, "Missing option", "filetype");
898 if (CompareGuid (&FileGuid
, &mZeroGuid
) == 0) {
899 Error (NULL
, 0, 1001, "Missing option", "fileguid");
903 if (InputFileNum
== 0) {
904 Error (NULL
, 0, 1001, "Missing option", "Input files");
909 // Output input parameter information
911 VerboseMsg ("Fv File type is %s", mFfsFileType
[FfsFiletype
]);
912 VerboseMsg ("Output file name is %s", OutputFileName
);
913 VerboseMsg ("FFS File Guid is %08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X",
914 (unsigned) FileGuid
.Data1
,
925 if ((FfsAttrib
& FFS_ATTRIB_FIXED
) != 0) {
926 VerboseMsg ("FFS File has the fixed file attribute");
928 if ((FfsAttrib
& FFS_ATTRIB_CHECKSUM
) != 0) {
929 VerboseMsg ("FFS File requires the checksum of the whole file");
931 VerboseMsg ("FFS file alignment is %s", mFfsValidAlignName
[FfsAlign
]);
932 for (Index
= 0; Index
< InputFileNum
; Index
++) {
933 if (InputFileAlign
[Index
] == 0) {
935 // Minimum alignment is 1 byte.
937 InputFileAlign
[Index
] = 1;
939 VerboseMsg ("the %dth input section name is %s and section alignment is %u", Index
, InputFileName
[Index
], (unsigned) InputFileAlign
[Index
]);
943 // Calculate the size of all input section files.
945 Status
= GetSectionContents (
956 if ((FfsFiletype
== EFI_FV_FILETYPE_SECURITY_CORE
||
957 FfsFiletype
== EFI_FV_FILETYPE_PEI_CORE
||
958 FfsFiletype
== EFI_FV_FILETYPE_DXE_CORE
) && (PeSectionNum
!= 1)) {
959 Error (NULL
, 0, 2000, "Invalid parameter", "Fv File type %s must have one and only one Pe or Te section, but %u Pe/Te section are input", mFfsFileType
[FfsFiletype
], PeSectionNum
);
963 if ((FfsFiletype
== EFI_FV_FILETYPE_PEIM
||
964 FfsFiletype
== EFI_FV_FILETYPE_DRIVER
||
965 FfsFiletype
== EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER
||
966 FfsFiletype
== EFI_FV_FILETYPE_APPLICATION
) && (PeSectionNum
< 1)) {
967 Error (NULL
, 0, 2000, "Invalid parameter", "Fv File type %s must have at least one Pe or Te section, but no Pe/Te section is input", mFfsFileType
[FfsFiletype
]);
971 if (Status
== EFI_BUFFER_TOO_SMALL
) {
972 FileBuffer
= (UINT8
*) malloc (FileSize
);
973 if (FileBuffer
== NULL
) {
974 Error (NULL
, 0, 4001, "Resource", "memory cannot be allocated!");
977 memset (FileBuffer
, 0, FileSize
);
980 // read all input file contents into a buffer
982 Status
= GetSectionContents (
994 if (EFI_ERROR (Status
)) {
998 if (FileBuffer
== NULL
&& FileSize
!= 0) {
999 Error (NULL
, 0, 4001, "Resource", "memory cannot be allocated!");
1004 // Create Ffs file header.
1006 memset (&FfsFileHeader
, 0, sizeof (EFI_FFS_FILE_HEADER2
));
1007 memcpy (&FfsFileHeader
.Name
, &FileGuid
, sizeof (EFI_GUID
));
1008 FfsFileHeader
.Type
= FfsFiletype
;
1010 // Update FFS Alignment based on the max alignment required by input section files
1012 VerboseMsg ("the max alignment of all input sections is %u", (unsigned) MaxAlignment
);
1013 for (Index
= 0; Index
< sizeof (mFfsValidAlign
) / sizeof (UINT32
) - 1; Index
++) {
1014 if ((MaxAlignment
> mFfsValidAlign
[Index
]) && (MaxAlignment
<= mFfsValidAlign
[Index
+ 1])) {
1018 if (FfsAlign
< Index
) {
1021 VerboseMsg ("the alignment of the generated FFS file is %u", (unsigned) mFfsValidAlign
[FfsAlign
+ 1]);
1024 // Now FileSize includes the EFI_FFS_FILE_HEADER
1026 if (FileSize
+ sizeof (EFI_FFS_FILE_HEADER
) >= MAX_FFS_SIZE
) {
1027 HeaderSize
= sizeof (EFI_FFS_FILE_HEADER2
);
1028 FileSize
+= sizeof (EFI_FFS_FILE_HEADER2
);
1029 FfsFileHeader
.ExtendedSize
= FileSize
;
1030 memset(FfsFileHeader
.Size
, 0, sizeof (UINT8
) * 3);
1031 FfsAttrib
|= FFS_ATTRIB_LARGE_FILE
;
1033 HeaderSize
= sizeof (EFI_FFS_FILE_HEADER
);
1034 FileSize
+= sizeof (EFI_FFS_FILE_HEADER
);
1035 FfsFileHeader
.Size
[0] = (UINT8
) (FileSize
& 0xFF);
1036 FfsFileHeader
.Size
[1] = (UINT8
) ((FileSize
& 0xFF00) >> 8);
1037 FfsFileHeader
.Size
[2] = (UINT8
) ((FileSize
& 0xFF0000) >> 16);
1039 VerboseMsg ("the size of the generated FFS file is %u bytes", (unsigned) FileSize
);
1041 //FfsAlign larger than 7, set FFS_ATTRIB_DATA_ALIGNMENT2
1043 FfsFileHeader
.Attributes
= (EFI_FFS_FILE_ATTRIBUTES
) (FfsAttrib
| (FfsAlign
<< 3));
1045 FfsFileHeader
.Attributes
= (EFI_FFS_FILE_ATTRIBUTES
) (FfsAttrib
| ((FfsAlign
& 0x7) << 3) | FFS_ATTRIB_DATA_ALIGNMENT2
);
1049 // Fill in checksums and state, these must be zero for checksumming
1051 // FileHeader.IntegrityCheck.Checksum.Header = 0;
1052 // FileHeader.IntegrityCheck.Checksum.File = 0;
1053 // FileHeader.State = 0;
1055 FfsFileHeader
.IntegrityCheck
.Checksum
.Header
= CalculateChecksum8 (
1056 (UINT8
*) &FfsFileHeader
,
1060 if (FfsFileHeader
.Attributes
& FFS_ATTRIB_CHECKSUM
) {
1062 // Ffs header checksum = zero, so only need to calculate ffs body.
1064 FfsFileHeader
.IntegrityCheck
.Checksum
.File
= CalculateChecksum8 (
1066 FileSize
- HeaderSize
1069 FfsFileHeader
.IntegrityCheck
.Checksum
.File
= FFS_FIXED_CHECKSUM
;
1072 FfsFileHeader
.State
= EFI_FILE_HEADER_CONSTRUCTION
| EFI_FILE_HEADER_VALID
| EFI_FILE_DATA_VALID
;
1075 // Open output file to write ffs data.
1077 if (OutputFileName
!= NULL
) {
1078 remove(OutputFileName
);
1079 FfsFile
= fopen (LongFilePath (OutputFileName
), "wb");
1080 if (FfsFile
== NULL
) {
1081 Error (NULL
, 0, 0001, "Error opening file", OutputFileName
);
1087 fwrite (&FfsFileHeader
, 1, HeaderSize
, FfsFile
);
1091 if (FileBuffer
!= NULL
) {
1092 fwrite (FileBuffer
, 1, FileSize
- HeaderSize
, FfsFile
);
1099 if (InputFileName
!= NULL
) {
1100 free (InputFileName
);
1102 if (InputFileAlign
!= NULL
) {
1103 free (InputFileAlign
);
1105 if (FileBuffer
!= NULL
) {
1109 // If any errors were reported via the standard error reporting
1110 // routines, then the status has been saved. Get the value and
1111 // return it to the caller.
1113 VerboseMsg ("%s tool done with return code is 0x%x.", UTILITY_NAME
, GetUtilityStatus ());
1115 return GetUtilityStatus ();