summaryrefslogtreecommitdiffstats
path: root/src/VBox/Devices/EFI/Firmware/BaseTools/Source/C/GenFfs/GenFfs.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/VBox/Devices/EFI/Firmware/BaseTools/Source/C/GenFfs/GenFfs.c')
-rw-r--r--src/VBox/Devices/EFI/Firmware/BaseTools/Source/C/GenFfs/GenFfs.c1120
1 files changed, 1120 insertions, 0 deletions
diff --git a/src/VBox/Devices/EFI/Firmware/BaseTools/Source/C/GenFfs/GenFfs.c b/src/VBox/Devices/EFI/Firmware/BaseTools/Source/C/GenFfs/GenFfs.c
new file mode 100644
index 00000000..28066c2b
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/BaseTools/Source/C/GenFfs/GenFfs.c
@@ -0,0 +1,1120 @@
+/** @file
+This file contains functions required to generate a Firmware File System file.
+
+Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __GNUC__
+# ifdef VBOX
+// RUNTIME_FUNCTION typedef conflicts; just use EFI headers
+# else
+#include <windows.h>
+# endif
+#include <io.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#endif
+
+#ifdef __GNUC__
+#include <unistd.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <Common/UefiBaseTypes.h>
+#include <Common/PiFirmwareFile.h>
+#include <IndustryStandard/PeImage.h>
+#include <Guid/FfsSectionAlignmentPadding.h>
+
+#include "CommonLib.h"
+#include "ParseInf.h"
+#include "EfiUtilityMsgs.h"
+#include "FvLib.h"
+#include "PeCoffLib.h"
+
+#define UTILITY_NAME "GenFfs"
+#define UTILITY_MAJOR_VERSION 0
+#define UTILITY_MINOR_VERSION 1
+
+STATIC CHAR8 *mFfsFileType[] = {
+ NULL, // 0x00
+ "EFI_FV_FILETYPE_RAW", // 0x01
+ "EFI_FV_FILETYPE_FREEFORM", // 0x02
+ "EFI_FV_FILETYPE_SECURITY_CORE", // 0x03
+ "EFI_FV_FILETYPE_PEI_CORE", // 0x04
+ "EFI_FV_FILETYPE_DXE_CORE", // 0x05
+ "EFI_FV_FILETYPE_PEIM", // 0x06
+ "EFI_FV_FILETYPE_DRIVER", // 0x07
+ "EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER", // 0x08
+ "EFI_FV_FILETYPE_APPLICATION", // 0x09
+ "EFI_FV_FILETYPE_SMM", // 0x0A
+ "EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE",// 0x0B
+ "EFI_FV_FILETYPE_COMBINED_SMM_DXE", // 0x0C
+ "EFI_FV_FILETYPE_SMM_CORE", // 0x0D
+ "EFI_FV_FILETYPE_MM_STANDALONE", // 0x0E
+ "EFI_FV_FILETYPE_MM_CORE_STANDALONE" // 0x0F
+};
+
+STATIC CHAR8 *mAlignName[] = {
+ "1", "2", "4", "8", "16", "32", "64", "128", "256", "512",
+ "1K", "2K", "4K", "8K", "16K", "32K", "64K", "128K", "256K",
+ "512K", "1M", "2M", "4M", "8M", "16M"
+ };
+
+STATIC CHAR8 *mFfsValidAlignName[] = {
+ "8", "16", "128", "512", "1K", "4K", "32K", "64K", "128K","256K",
+ "512K", "1M", "2M", "4M", "8M", "16M"
+ };
+
+STATIC UINT32 mFfsValidAlign[] = {0, 8, 16, 128, 512, 1024, 4096, 32768, 65536, 131072, 262144,
+ 524288, 1048576, 2097152, 4194304, 8388608, 16777216};
+
+STATIC EFI_GUID mZeroGuid = {0};
+
+STATIC EFI_GUID mEfiFfsSectionAlignmentPaddingGuid = EFI_FFS_SECTION_ALIGNMENT_PADDING_GUID;
+
+STATIC
+VOID
+Version (
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ Print out version information for this utility.
+
+Arguments:
+
+ None
+
+Returns:
+
+ None
+
+--*/
+{
+ fprintf (stdout, "%s Version %d.%d %s \n", UTILITY_NAME, UTILITY_MAJOR_VERSION, UTILITY_MINOR_VERSION, __BUILD_VERSION);
+}
+
+STATIC
+VOID
+Usage (
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ Print Error / Help message.
+
+Arguments:
+
+ VOID
+
+Returns:
+
+ None
+
+--*/
+{
+ //
+ // Summary usage
+ //
+ fprintf (stdout, "\nUsage: %s [options]\n\n", UTILITY_NAME);
+
+ //
+ // Copyright declaration
+ //
+ fprintf (stdout, "Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.\n\n");
+
+ //
+ // Details Option
+ //
+ fprintf (stdout, "Options:\n");
+ fprintf (stdout, " -o FileName, --outputfile FileName\n\
+ File is FFS file to be created.\n");
+ fprintf (stdout, " -t Type, --filetype Type\n\
+ Type is one FV file type defined in PI spec, which is\n\
+ EFI_FV_FILETYPE_RAW, EFI_FV_FILETYPE_FREEFORM,\n\
+ EFI_FV_FILETYPE_SECURITY_CORE, EFI_FV_FILETYPE_PEIM,\n\
+ EFI_FV_FILETYPE_PEI_CORE, EFI_FV_FILETYPE_DXE_CORE,\n\
+ EFI_FV_FILETYPE_DRIVER, EFI_FV_FILETYPE_APPLICATION,\n\
+ EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER,\n\
+ EFI_FV_FILETYPE_SMM, EFI_FV_FILETYPE_SMM_CORE,\n\
+ EFI_FV_FILETYPE_MM_STANDALONE,\n\
+ EFI_FV_FILETYPE_MM_CORE_STANDALONE,\n\
+ EFI_FV_FILETYPE_COMBINED_SMM_DXE, \n\
+ EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE.\n");
+ fprintf (stdout, " -g FileGuid, --fileguid FileGuid\n\
+ FileGuid is one module guid.\n\
+ Its format is xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx\n");
+ fprintf (stdout, " -x, --fixed Indicates that the file may not be moved\n\
+ from its present location.\n");
+ fprintf (stdout, " -s, --checksum Indicates to calculate file checksum.\n");
+ fprintf (stdout, " -a FileAlign, --align FileAlign\n\
+ FileAlign points to file alignment, which only support\n\
+ the following align: 1,2,4,8,16,128,512,1K,4K,32K,64K\n\
+ 128K,256K,512K,1M,2M,4M,8M,16M\n");
+ fprintf (stdout, " -i SectionFile, --sectionfile SectionFile\n\
+ Section file will be contained in this FFS file.\n");
+ fprintf (stdout, " -oi SectionFile, --optionalsectionfile SectionFile\n\
+ If the Section file exists, it will be contained in this FFS file, otherwise, it will be ignored.\n");
+ fprintf (stdout, " -n SectionAlign, --sectionalign SectionAlign\n\
+ SectionAlign points to section alignment, which support\n\
+ the alignment scope 0~16M. If SectionAlign is specified\n\
+ as 0, tool get alignment value from SectionFile. It is\n\
+ specified together with sectionfile to point its\n\
+ alignment in FFS file.\n");
+ fprintf (stdout, " -v, --verbose Turn on verbose output with informational messages.\n");
+ fprintf (stdout, " -q, --quiet Disable all messages except key message and fatal error\n");
+ fprintf (stdout, " -d, --debug level Enable debug messages, at input debug level.\n");
+ fprintf (stdout, " --version Show program's version number and exit.\n");
+ fprintf (stdout, " -h, --help Show this help message and exit.\n");
+}
+
+STATIC
+EFI_STATUS
+StringtoAlignment (
+ IN CHAR8 *AlignBuffer,
+ OUT UINT32 *AlignNumber
+ )
+/*++
+
+Routine Description:
+
+ Converts Align String to align value (1~16M).
+
+Arguments:
+
+ AlignBuffer - Pointer to Align string.
+ AlignNumber - Pointer to Align value.
+
+Returns:
+
+ EFI_SUCCESS Successfully convert align string to align value.
+ EFI_INVALID_PARAMETER Align string is invalid or align value is not in scope.
+
+--*/
+{
+ UINT32 Index = 0;
+ //
+ // Check AlignBuffer
+ //
+ if (AlignBuffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ for (Index = 0; Index < sizeof (mAlignName) / sizeof (CHAR8 *); Index ++) {
+ if (stricmp (AlignBuffer, mAlignName [Index]) == 0) {
+ *AlignNumber = 1 << Index;
+ return EFI_SUCCESS;
+ }
+ }
+ return EFI_INVALID_PARAMETER;
+}
+
+STATIC
+UINT8
+StringToType (
+ IN CHAR8 *String
+ )
+/*++
+
+Routine Description:
+
+ Converts File Type String to value. EFI_FV_FILETYPE_ALL indicates that an
+ unrecognized file type was specified.
+
+Arguments:
+
+ String - File type string
+
+Returns:
+
+ File Type Value
+
+--*/
+{
+ UINT8 Index = 0;
+
+ if (String == NULL) {
+ return EFI_FV_FILETYPE_ALL;
+ }
+
+ for (Index = 0; Index < sizeof (mFfsFileType) / sizeof (CHAR8 *); Index ++) {
+ if (mFfsFileType [Index] != NULL && (stricmp (String, mFfsFileType [Index]) == 0)) {
+ return Index;
+ }
+ }
+ return EFI_FV_FILETYPE_ALL;
+}
+
+STATIC
+EFI_STATUS
+GetSectionContents (
+ IN CHAR8 **InputFileName,
+ IN UINT32 *InputFileAlign,
+ IN UINT32 InputFileNum,
+ IN EFI_FFS_FILE_ATTRIBUTES FfsAttrib,
+ OUT UINT8 *FileBuffer,
+ OUT UINT32 *BufferLength,
+ OUT UINT32 *MaxAlignment,
+ OUT UINT8 *PESectionNum
+ )
+/*++
+
+Routine Description:
+
+ Get the contents of all section files specified in InputFileName
+ into FileBuffer.
+
+Arguments:
+
+ InputFileName - Name of the input file.
+
+ InputFileAlign - Alignment required by the input file data.
+
+ InputFileNum - Number of input files. Should be at least 1.
+
+ FileBuffer - Output buffer to contain data
+
+ BufferLength - On input, this is size of the FileBuffer.
+ On output, this is the actual length of the data.
+
+ MaxAlignment - The max alignment required by all the input file datas.
+
+ PeSectionNum - Calculate the number of Pe/Te Section in this FFS file.
+
+Returns:
+
+ EFI_SUCCESS on successful return
+ EFI_INVALID_PARAMETER if InputFileNum is less than 1 or BufferLength point is NULL.
+ EFI_ABORTED if unable to open input file.
+ EFI_BUFFER_TOO_SMALL FileBuffer is not enough to contain all file data.
+--*/
+{
+ UINT32 Size;
+ UINT32 Offset;
+ UINT32 FileSize;
+ UINT32 Index;
+ FILE *InFile;
+ EFI_FREEFORM_SUBTYPE_GUID_SECTION *SectHeader;
+ EFI_COMMON_SECTION_HEADER2 TempSectHeader;
+ EFI_TE_IMAGE_HEADER TeHeader;
+ UINT32 TeOffset;
+ EFI_GUID_DEFINED_SECTION GuidSectHeader;
+ EFI_GUID_DEFINED_SECTION2 GuidSectHeader2;
+ UINT32 HeaderSize;
+ UINT32 MaxEncounteredAlignment;
+
+ Size = 0;
+ Offset = 0;
+ TeOffset = 0;
+ MaxEncounteredAlignment = 1;
+
+ //
+ // Go through our array of file names and copy their contents
+ // to the output buffer.
+ //
+ for (Index = 0; Index < InputFileNum; Index++) {
+ //
+ // make sure section ends on a DWORD boundary
+ //
+ while ((Size & 0x03) != 0) {
+ Size++;
+ }
+
+ //
+ // Open file and read contents
+ //
+ InFile = fopen (LongFilePath (InputFileName[Index]), "rb");
+ if (InFile == NULL) {
+ Error (NULL, 0, 0001, "Error opening file", InputFileName[Index]);
+ return EFI_ABORTED;
+ }
+
+ fseek (InFile, 0, SEEK_END);
+ FileSize = ftell (InFile);
+ fseek (InFile, 0, SEEK_SET);
+ DebugMsg (NULL, 0, 9, "Input section files",
+ "the input section name is %s and the size is %u bytes", InputFileName[Index], (unsigned) FileSize);
+
+ //
+ // Check this section is Te/Pe section, and Calculate the numbers of Te/Pe section.
+ //
+ TeOffset = 0;
+ if (FileSize >= MAX_FFS_SIZE) {
+ HeaderSize = sizeof (EFI_COMMON_SECTION_HEADER2);
+ } else {
+ HeaderSize = sizeof (EFI_COMMON_SECTION_HEADER);
+ }
+ fread (&TempSectHeader, 1, HeaderSize, InFile);
+ if (TempSectHeader.Type == EFI_SECTION_TE) {
+ (*PESectionNum) ++;
+ fread (&TeHeader, 1, sizeof (TeHeader), InFile);
+ if (TeHeader.Signature == EFI_TE_IMAGE_HEADER_SIGNATURE) {
+ TeOffset = TeHeader.StrippedSize - sizeof (TeHeader);
+ }
+ } else if (TempSectHeader.Type == EFI_SECTION_PE32) {
+ (*PESectionNum) ++;
+ } else if (TempSectHeader.Type == EFI_SECTION_GUID_DEFINED) {
+ fseek (InFile, 0, SEEK_SET);
+ if (FileSize >= MAX_SECTION_SIZE) {
+ fread (&GuidSectHeader2, 1, sizeof (GuidSectHeader2), InFile);
+ if ((GuidSectHeader2.Attributes & EFI_GUIDED_SECTION_PROCESSING_REQUIRED) == 0) {
+ HeaderSize = GuidSectHeader2.DataOffset;
+ }
+ } else {
+ fread (&GuidSectHeader, 1, sizeof (GuidSectHeader), InFile);
+ if ((GuidSectHeader.Attributes & EFI_GUIDED_SECTION_PROCESSING_REQUIRED) == 0) {
+ HeaderSize = GuidSectHeader.DataOffset;
+ }
+ }
+ (*PESectionNum) ++;
+ } else if (TempSectHeader.Type == EFI_SECTION_COMPRESSION ||
+ TempSectHeader.Type == EFI_SECTION_FIRMWARE_VOLUME_IMAGE) {
+ //
+ // for the encapsulated section, assume it contains Pe/Te section
+ //
+ (*PESectionNum) ++;
+ }
+
+ fseek (InFile, 0, SEEK_SET);
+
+ //
+ // Revert TeOffset to the converse value relative to Alignment
+ // This is to assure the original PeImage Header at Alignment.
+ //
+ if ((TeOffset != 0) && (InputFileAlign [Index] != 0)) {
+ TeOffset = InputFileAlign [Index] - (TeOffset % InputFileAlign [Index]);
+ TeOffset = TeOffset % InputFileAlign [Index];
+ }
+
+ //
+ // make sure section data meet its alignment requirement by adding one pad section.
+ // But the different sections have the different section header. Necessary or not?
+ // Based on section type to adjust offset? Todo
+ //
+ if ((InputFileAlign [Index] != 0) && (((Size + HeaderSize + TeOffset) % InputFileAlign [Index]) != 0)) {
+ Offset = (Size + sizeof (EFI_COMMON_SECTION_HEADER) + HeaderSize + TeOffset + InputFileAlign [Index] - 1) & ~(InputFileAlign [Index] - 1);
+ Offset = Offset - Size - HeaderSize - TeOffset;
+
+ if (FileBuffer != NULL && ((Size + Offset) < *BufferLength)) {
+ //
+ // The maximal alignment is 64K, the raw section size must be less than 0xffffff
+ //
+ memset (FileBuffer + Size, 0, Offset);
+ SectHeader = (EFI_FREEFORM_SUBTYPE_GUID_SECTION *) (FileBuffer + Size);
+ SectHeader->CommonHeader.Size[0] = (UINT8) (Offset & 0xff);
+ SectHeader->CommonHeader.Size[1] = (UINT8) ((Offset & 0xff00) >> 8);
+ SectHeader->CommonHeader.Size[2] = (UINT8) ((Offset & 0xff0000) >> 16);
+
+ //
+ // Only add a special reducible padding section if
+ // - this FFS has the FFS_ATTRIB_FIXED attribute,
+ // - none of the preceding sections have alignment requirements,
+ // - the size of the padding is sufficient for the
+ // EFI_SECTION_FREEFORM_SUBTYPE_GUID header.
+ //
+ if ((FfsAttrib & FFS_ATTRIB_FIXED) != 0 &&
+ MaxEncounteredAlignment <= 1 &&
+ Offset >= sizeof (EFI_FREEFORM_SUBTYPE_GUID_SECTION)) {
+ SectHeader->CommonHeader.Type = EFI_SECTION_FREEFORM_SUBTYPE_GUID;
+ SectHeader->SubTypeGuid = mEfiFfsSectionAlignmentPaddingGuid;
+ } else {
+ SectHeader->CommonHeader.Type = EFI_SECTION_RAW;
+ }
+ }
+ DebugMsg (NULL, 0, 9, "Pad raw section for section data alignment",
+ "Pad Raw section size is %u", (unsigned) Offset);
+
+ Size = Size + Offset;
+ }
+
+ //
+ // Get the Max alignment of all input file datas
+ //
+ if (MaxEncounteredAlignment < InputFileAlign [Index]) {
+ MaxEncounteredAlignment = InputFileAlign [Index];
+ }
+
+ //
+ // Now read the contents of the file into the buffer
+ // Buffer must be enough to contain the file content.
+ //
+ if ((FileSize > 0) && (FileBuffer != NULL) && ((Size + FileSize) <= *BufferLength)) {
+ if (fread (FileBuffer + Size, (size_t) FileSize, 1, InFile) != 1) {
+ Error (NULL, 0, 0004, "Error reading file", InputFileName[Index]);
+ fclose (InFile);
+ return EFI_ABORTED;
+ }
+ }
+
+ fclose (InFile);
+ Size += FileSize;
+ }
+
+ *MaxAlignment = MaxEncounteredAlignment;
+
+ //
+ // Set the actual length of the data.
+ //
+ if (Size > *BufferLength) {
+ *BufferLength = Size;
+ return EFI_BUFFER_TOO_SMALL;
+ } else {
+ *BufferLength = Size;
+ return EFI_SUCCESS;
+ }
+}
+
+EFI_STATUS
+FfsRebaseImageRead (
+ IN VOID *FileHandle,
+ IN UINTN FileOffset,
+ IN OUT UINT32 *ReadSize,
+ OUT VOID *Buffer
+ )
+ /*++
+
+ Routine Description:
+
+ Support routine for the PE/COFF Loader that reads a buffer from a PE/COFF file
+
+ Arguments:
+
+ FileHandle - The handle to the PE/COFF file
+
+ FileOffset - The offset, in bytes, into the file to read
+
+ ReadSize - The number of bytes to read from the file starting at FileOffset
+
+ Buffer - A pointer to the buffer to read the data into.
+
+ Returns:
+
+ EFI_SUCCESS - ReadSize bytes of data were read into Buffer from the PE/COFF file starting at FileOffset
+
+ --*/
+{
+ CHAR8 *Destination8;
+ CHAR8 *Source8;
+ UINT32 Length;
+
+ Destination8 = Buffer;
+ Source8 = (CHAR8 *) ((UINTN) FileHandle + FileOffset);
+ Length = *ReadSize;
+ while (Length--) {
+ *(Destination8++) = *(Source8++);
+ }
+
+ return EFI_SUCCESS;
+}
+
+STATIC
+EFI_STATUS
+GetAlignmentFromFile(char *InFile, UINT32 *Alignment)
+ /*++
+ InFile is input file for getting alignment
+ return the alignment
+ --*/
+{
+ FILE *InFileHandle;
+ UINT8 *PeFileBuffer;
+ UINTN PeFileSize;
+ UINT32 CurSecHdrSize;
+ PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;
+ EFI_COMMON_SECTION_HEADER *CommonHeader;
+ EFI_STATUS Status;
+
+ InFileHandle = NULL;
+ PeFileBuffer = NULL;
+ *Alignment = 0;
+
+ memset (&ImageContext, 0, sizeof (ImageContext));
+
+ InFileHandle = fopen(LongFilePath(InFile), "rb");
+ if (InFileHandle == NULL){
+ Error (NULL, 0, 0001, "Error opening file", InFile);
+ return EFI_ABORTED;
+ }
+ PeFileSize = _filelength (fileno(InFileHandle));
+ PeFileBuffer = (UINT8 *) malloc (PeFileSize);
+ if (PeFileBuffer == NULL) {
+ fclose (InFileHandle);
+ Error(NULL, 0, 4001, "Resource", "memory cannot be allocated of %s", InFileHandle);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ fread (PeFileBuffer, sizeof (UINT8), PeFileSize, InFileHandle);
+ fclose (InFileHandle);
+ CommonHeader = (EFI_COMMON_SECTION_HEADER *) PeFileBuffer;
+ CurSecHdrSize = GetSectionHeaderLength(CommonHeader);
+ ImageContext.Handle = (VOID *) ((UINTN)PeFileBuffer + CurSecHdrSize);
+ ImageContext.ImageRead = (PE_COFF_LOADER_READ_FILE)FfsRebaseImageRead;
+ Status = PeCoffLoaderGetImageInfo(&ImageContext);
+ if (EFI_ERROR (Status)) {
+ Error (NULL, 0, 3000, "Invalid PeImage", "The input file is %s and return status is %x", InFile, (int) Status);
+ return Status;
+ }
+ *Alignment = ImageContext.SectionAlignment;
+ // Free the allocated memory resource
+ if (PeFileBuffer != NULL) {
+ free (PeFileBuffer);
+ PeFileBuffer = NULL;
+ }
+ return EFI_SUCCESS;
+}
+
+int
+main (
+ int argc,
+ CHAR8 *argv[]
+ )
+/*++
+
+Routine Description:
+
+ Main function.
+
+Arguments:
+
+ argc - Number of command line parameters.
+ argv - Array of pointers to parameter strings.
+
+Returns:
+ STATUS_SUCCESS - Utility exits successfully.
+ STATUS_ERROR - Some error occurred during execution.
+
+--*/
+{
+ EFI_STATUS Status;
+ EFI_FFS_FILE_ATTRIBUTES FfsAttrib;
+ UINT32 FfsAlign;
+ EFI_FV_FILETYPE FfsFiletype;
+ CHAR8 *OutputFileName;
+ EFI_GUID FileGuid = {0};
+ UINT32 InputFileNum;
+ UINT32 *InputFileAlign;
+ CHAR8 **InputFileName;
+ UINT8 *FileBuffer;
+ UINT32 FileSize;
+ UINT32 MaxAlignment;
+ EFI_FFS_FILE_HEADER2 FfsFileHeader;
+ FILE *FfsFile;
+ UINT32 Index;
+ UINT64 LogLevel;
+ UINT8 PeSectionNum;
+ UINT32 HeaderSize;
+ UINT32 Alignment;
+ //
+ // Workaround for static code checkers.
+ // Ensures the size of 'AlignmentBuffer' can hold all the digits of an
+ // unsigned 32-bit integer plus the size unit character.
+ //
+ CHAR8 AlignmentBuffer[16];
+
+ //
+ // Init local variables
+ //
+ LogLevel = 0;
+ Index = 0;
+ FfsAttrib = 0;
+ FfsAlign = 0;
+ FfsFiletype = EFI_FV_FILETYPE_ALL;
+ OutputFileName = NULL;
+ InputFileNum = 0;
+ InputFileName = NULL;
+ InputFileAlign = NULL;
+ FileBuffer = NULL;
+ FileSize = 0;
+ MaxAlignment = 1;
+ FfsFile = NULL;
+ Status = EFI_SUCCESS;
+ PeSectionNum = 0;
+
+ SetUtilityName (UTILITY_NAME);
+
+ if (argc == 1) {
+ Error (NULL, 0, 1001, "Missing options", "no options input");
+ Usage ();
+ return STATUS_ERROR;
+ }
+
+ //
+ // Parse command line
+ //
+ argc --;
+ argv ++;
+
+ if ((stricmp (argv[0], "-h") == 0) || (stricmp (argv[0], "--help") == 0)) {
+ Version ();
+ Usage ();
+ return STATUS_SUCCESS;
+ }
+
+ if (stricmp (argv[0], "--version") == 0) {
+ Version ();
+ return STATUS_SUCCESS;
+ }
+
+ while (argc > 0) {
+ if ((stricmp (argv[0], "-t") == 0) || (stricmp (argv[0], "--filetype") == 0)) {
+ if (argv[1] == NULL || argv[1][0] == '-') {
+ Error (NULL, 0, 1003, "Invalid option value", "file type is missing for -t option");
+ goto Finish;
+ }
+ FfsFiletype = StringToType (argv[1]);
+ if (FfsFiletype == EFI_FV_FILETYPE_ALL) {
+ Error (NULL, 0, 1003, "Invalid option value", "%s is not a valid file type", argv[1]);
+ goto Finish;
+ }
+ argc -= 2;
+ argv += 2;
+ continue;
+ }
+
+ if ((stricmp (argv[0], "-o") == 0) || (stricmp (argv[0], "--outputfile") == 0)) {
+ if (argv[1] == NULL || argv[1][0] == '-') {
+ Error (NULL, 0, 1003, "Invalid option value", "Output file is missing for -o option");
+ goto Finish;
+ }
+ OutputFileName = argv[1];
+ argc -= 2;
+ argv += 2;
+ continue;
+ }
+
+ if ((stricmp (argv[0], "-g") == 0) || (stricmp (argv[0], "--fileguid") == 0)) {
+ Status = StringToGuid (argv[1], &FileGuid);
+ if (EFI_ERROR (Status)) {
+ Error (NULL, 0, 1003, "Invalid option value", "%s = %s", argv[0], argv[1]);
+ goto Finish;
+ }
+ argc -= 2;
+ argv += 2;
+ continue;
+ }
+
+ if ((stricmp (argv[0], "-x") == 0) || (stricmp (argv[0], "--fixed") == 0)) {
+ FfsAttrib |= FFS_ATTRIB_FIXED;
+ argc -= 1;
+ argv += 1;
+ continue;
+ }
+
+ if ((stricmp (argv[0], "-s") == 0) || (stricmp (argv[0], "--checksum") == 0)) {
+ FfsAttrib |= FFS_ATTRIB_CHECKSUM;
+ argc -= 1;
+ argv += 1;
+ continue;
+ }
+
+ if ((stricmp (argv[0], "-a") == 0) || (stricmp (argv[0], "--align") == 0)) {
+ if (argv[1] == NULL || argv[1][0] == '-') {
+ Error (NULL, 0, 1003, "Invalid option value", "Align value is missing for -a option");
+ goto Finish;
+ }
+ for (Index = 0; Index < sizeof (mFfsValidAlignName) / sizeof (CHAR8 *); Index ++) {
+ if (stricmp (argv[1], mFfsValidAlignName[Index]) == 0) {
+ break;
+ }
+ }
+ if (Index == sizeof (mFfsValidAlignName) / sizeof (CHAR8 *)) {
+ if ((stricmp (argv[1], "1") == 0) || (stricmp (argv[1], "2") == 0) || (stricmp (argv[1], "4") == 0)) {
+ //
+ // 1, 2, 4 byte alignment same to 8 byte alignment
+ //
+ Index = 0;
+ } else {
+ Error (NULL, 0, 1003, "Invalid option value", "%s = %s", argv[0], argv[1]);
+ goto Finish;
+ }
+ }
+ FfsAlign = Index;
+ argc -= 2;
+ argv += 2;
+ continue;
+ }
+
+ if ((stricmp (argv[0], "-oi") == 0) || (stricmp (argv[0], "--optionalsectionfile") == 0) || (stricmp (argv[0], "-i") == 0) || (stricmp (argv[0], "--sectionfile") == 0)) {
+ //
+ // Get Input file name and its alignment
+ //
+ if (argv[1] == NULL || argv[1][0] == '-') {
+ Error (NULL, 0, 1003, "Invalid option value", "input section file is missing for -i option");
+ goto Finish;
+ }
+ if ((stricmp (argv[0], "-oi") == 0) || (stricmp (argv[0], "--optionalsectionfile") == 0) ){
+ if (-1 == access(argv[1] , 0)){
+ Warning(NULL, 0, 0001, "File is not found.", argv[1]);
+ argc -= 2;
+ argv += 2;
+ continue;
+ }
+ }
+ //
+ // Allocate Input file name buffer and its alignment buffer.
+ //
+ if ((InputFileNum == 0) && (InputFileName == NULL)) {
+ InputFileName = (CHAR8 **) malloc (MAXIMUM_INPUT_FILE_NUM * sizeof (CHAR8 *));
+ if (InputFileName == NULL) {
+ Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!");
+ return STATUS_ERROR;
+ }
+ memset (InputFileName, 0, (MAXIMUM_INPUT_FILE_NUM * sizeof (CHAR8 *)));
+
+ InputFileAlign = (UINT32 *) malloc (MAXIMUM_INPUT_FILE_NUM * sizeof (UINT32));
+ if (InputFileAlign == NULL) {
+ Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!");
+ free (InputFileName);
+ return STATUS_ERROR;
+ }
+ memset (InputFileAlign, 0, MAXIMUM_INPUT_FILE_NUM * sizeof (UINT32));
+ } else if (InputFileNum % MAXIMUM_INPUT_FILE_NUM == 0) {
+ //
+ // InputFileName and alignment buffer too small, need to realloc
+ //
+ InputFileName = (CHAR8 **) realloc (
+ InputFileName,
+ (InputFileNum + MAXIMUM_INPUT_FILE_NUM) * sizeof (CHAR8 *)
+ );
+
+ if (InputFileName == NULL) {
+ Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!");
+ free (InputFileAlign);
+ return STATUS_ERROR;
+ }
+ memset (&(InputFileName[InputFileNum]), 0, (MAXIMUM_INPUT_FILE_NUM * sizeof (CHAR8 *)));
+
+ InputFileAlign = (UINT32 *) realloc (
+ InputFileAlign,
+ (InputFileNum + MAXIMUM_INPUT_FILE_NUM) * sizeof (UINT32)
+ );
+
+ if (InputFileAlign == NULL) {
+ Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!");
+ free (InputFileName);
+ return STATUS_ERROR;
+ }
+ memset (&(InputFileAlign[InputFileNum]), 0, (MAXIMUM_INPUT_FILE_NUM * sizeof (UINT32)));
+ }
+
+ InputFileName[InputFileNum] = argv[1];
+ argc -= 2;
+ argv += 2;
+
+ if (argc <= 0) {
+ InputFileNum ++;
+ break;
+ }
+
+ //
+ // Section File alignment requirement
+ //
+ if ((stricmp (argv[0], "-n") == 0) || (stricmp (argv[0], "--sectionalign") == 0)) {
+ if ((argv[1] != NULL) && (stricmp("0", argv[1]) == 0)) {
+ Status = GetAlignmentFromFile(InputFileName[InputFileNum], &Alignment);
+ if (EFI_ERROR(Status)) {
+ Error (NULL, 0, 1003, "Fail to get Alignment from %s", InputFileName[InputFileNum]);
+ goto Finish;
+ }
+ if (Alignment < 0x400){
+ sprintf (AlignmentBuffer, "%d", Alignment);
+ }
+ else if (Alignment >= 0x100000) {
+ sprintf (AlignmentBuffer, "%dM", Alignment/0x100000);
+ }
+ else {
+ sprintf (AlignmentBuffer, "%dK", Alignment/0x400);
+ }
+ Status = StringtoAlignment (AlignmentBuffer, &(InputFileAlign[InputFileNum]));
+ }
+ else {
+ Status = StringtoAlignment (argv[1], &(InputFileAlign[InputFileNum]));
+ }
+ if (EFI_ERROR (Status)) {
+ Error (NULL, 0, 1003, "Invalid option value", "%s = %s", argv[0], argv[1]);
+ goto Finish;
+ }
+ argc -= 2;
+ argv += 2;
+ }
+ InputFileNum ++;
+ continue;
+ }
+
+ if ((stricmp (argv[0], "-n") == 0) || (stricmp (argv[0], "--sectionalign") == 0)) {
+ Error (NULL, 0, 1000, "Unknown option", "SectionAlign option must be specified with section file.");
+ goto Finish;
+ }
+
+ if ((stricmp (argv[0], "-v") == 0) || (stricmp (argv[0], "--verbose") == 0)) {
+ SetPrintLevel (VERBOSE_LOG_LEVEL);
+ VerboseMsg ("Verbose output Mode Set!");
+ argc --;
+ argv ++;
+ continue;
+ }
+
+ if ((stricmp (argv[0], "-q") == 0) || (stricmp (argv[0], "--quiet") == 0)) {
+ SetPrintLevel (KEY_LOG_LEVEL);
+ KeyMsg ("Quiet output Mode Set!");
+ argc --;
+ argv ++;
+ continue;
+ }
+
+ if ((stricmp (argv[0], "-d") == 0) || (stricmp (argv[0], "--debug") == 0)) {
+ Status = AsciiStringToUint64 (argv[1], FALSE, &LogLevel);
+ if (EFI_ERROR (Status)) {
+ Error (NULL, 0, 1003, "Invalid option value", "%s = %s", argv[0], argv[1]);
+ goto Finish;
+ }
+ if (LogLevel > 9) {
+ Error (NULL, 0, 1003, "Invalid option value", "Debug Level range is 0-9, current input level is %d", (int) LogLevel);
+ goto Finish;
+ }
+ SetPrintLevel (LogLevel);
+ DebugMsg (NULL, 0, 9, "Debug Mode Set", "Debug Output Mode Level %s is set!", argv[1]);
+ argc -= 2;
+ argv += 2;
+ continue;
+ }
+
+ Error (NULL, 0, 1000, "Unknown option", "%s", argv[0]);
+ goto Finish;
+ }
+
+ VerboseMsg ("%s tool start.", UTILITY_NAME);
+
+ //
+ // Check the complete input parameters.
+ //
+ if (FfsFiletype == EFI_FV_FILETYPE_ALL) {
+ Error (NULL, 0, 1001, "Missing option", "filetype");
+ goto Finish;
+ }
+
+ if (CompareGuid (&FileGuid, &mZeroGuid) == 0) {
+ Error (NULL, 0, 1001, "Missing option", "fileguid");
+ goto Finish;
+ }
+
+ if (InputFileNum == 0) {
+ Error (NULL, 0, 1001, "Missing option", "Input files");
+ goto Finish;
+ }
+
+ //
+ // Output input parameter information
+ //
+ VerboseMsg ("Fv File type is %s", mFfsFileType [FfsFiletype]);
+ VerboseMsg ("Output file name is %s", OutputFileName);
+ VerboseMsg ("FFS File Guid is %08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X",
+ (unsigned) FileGuid.Data1,
+ FileGuid.Data2,
+ FileGuid.Data3,
+ FileGuid.Data4[0],
+ FileGuid.Data4[1],
+ FileGuid.Data4[2],
+ FileGuid.Data4[3],
+ FileGuid.Data4[4],
+ FileGuid.Data4[5],
+ FileGuid.Data4[6],
+ FileGuid.Data4[7]);
+ if ((FfsAttrib & FFS_ATTRIB_FIXED) != 0) {
+ VerboseMsg ("FFS File has the fixed file attribute");
+ }
+ if ((FfsAttrib & FFS_ATTRIB_CHECKSUM) != 0) {
+ VerboseMsg ("FFS File requires the checksum of the whole file");
+ }
+ VerboseMsg ("FFS file alignment is %s", mFfsValidAlignName[FfsAlign]);
+ for (Index = 0; Index < InputFileNum; Index ++) {
+ if (InputFileAlign[Index] == 0) {
+ //
+ // Minimum alignment is 1 byte.
+ //
+ InputFileAlign[Index] = 1;
+ }
+ VerboseMsg ("the %dth input section name is %s and section alignment is %u", Index, InputFileName[Index], (unsigned) InputFileAlign[Index]);
+ }
+
+ //
+ // Calculate the size of all input section files.
+ //
+ Status = GetSectionContents (
+ InputFileName,
+ InputFileAlign,
+ InputFileNum,
+ FfsAttrib,
+ FileBuffer,
+ &FileSize,
+ &MaxAlignment,
+ &PeSectionNum
+ );
+
+ if ((FfsFiletype == EFI_FV_FILETYPE_SECURITY_CORE ||
+ FfsFiletype == EFI_FV_FILETYPE_PEI_CORE ||
+ FfsFiletype == EFI_FV_FILETYPE_DXE_CORE) && (PeSectionNum != 1)) {
+ 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);
+ goto Finish;
+ }
+
+ if ((FfsFiletype == EFI_FV_FILETYPE_PEIM ||
+ FfsFiletype == EFI_FV_FILETYPE_DRIVER ||
+ FfsFiletype == EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER ||
+ FfsFiletype == EFI_FV_FILETYPE_APPLICATION) && (PeSectionNum < 1)) {
+ 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]);
+ goto Finish;
+ }
+
+ if (Status == EFI_BUFFER_TOO_SMALL) {
+ FileBuffer = (UINT8 *) malloc (FileSize);
+ if (FileBuffer == NULL) {
+ Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!");
+ goto Finish;
+ }
+ memset (FileBuffer, 0, FileSize);
+
+ //
+ // read all input file contents into a buffer
+ //
+ Status = GetSectionContents (
+ InputFileName,
+ InputFileAlign,
+ InputFileNum,
+ FfsAttrib,
+ FileBuffer,
+ &FileSize,
+ &MaxAlignment,
+ &PeSectionNum
+ );
+ }
+
+ if (EFI_ERROR (Status)) {
+ goto Finish;
+ }
+
+ if (FileBuffer == NULL && FileSize != 0) {
+ Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!");
+ goto Finish;
+ }
+
+ //
+ // Create Ffs file header.
+ //
+ memset (&FfsFileHeader, 0, sizeof (EFI_FFS_FILE_HEADER2));
+ memcpy (&FfsFileHeader.Name, &FileGuid, sizeof (EFI_GUID));
+ FfsFileHeader.Type = FfsFiletype;
+ //
+ // Update FFS Alignment based on the max alignment required by input section files
+ //
+ VerboseMsg ("the max alignment of all input sections is %u", (unsigned) MaxAlignment);
+ for (Index = 0; Index < sizeof (mFfsValidAlign) / sizeof (UINT32) - 1; Index ++) {
+ if ((MaxAlignment > mFfsValidAlign [Index]) && (MaxAlignment <= mFfsValidAlign [Index + 1])) {
+ break;
+ }
+ }
+ if (FfsAlign < Index) {
+ FfsAlign = Index;
+ }
+ VerboseMsg ("the alignment of the generated FFS file is %u", (unsigned) mFfsValidAlign [FfsAlign + 1]);
+
+ //
+ // Now FileSize includes the EFI_FFS_FILE_HEADER
+ //
+ if (FileSize + sizeof (EFI_FFS_FILE_HEADER) >= MAX_FFS_SIZE) {
+ HeaderSize = sizeof (EFI_FFS_FILE_HEADER2);
+ FileSize += sizeof (EFI_FFS_FILE_HEADER2);
+ FfsFileHeader.ExtendedSize = FileSize;
+ memset(FfsFileHeader.Size, 0, sizeof (UINT8) * 3);
+ FfsAttrib |= FFS_ATTRIB_LARGE_FILE;
+ } else {
+ HeaderSize = sizeof (EFI_FFS_FILE_HEADER);
+ FileSize += sizeof (EFI_FFS_FILE_HEADER);
+ FfsFileHeader.Size[0] = (UINT8) (FileSize & 0xFF);
+ FfsFileHeader.Size[1] = (UINT8) ((FileSize & 0xFF00) >> 8);
+ FfsFileHeader.Size[2] = (UINT8) ((FileSize & 0xFF0000) >> 16);
+ }
+ VerboseMsg ("the size of the generated FFS file is %u bytes", (unsigned) FileSize);
+
+ //FfsAlign larger than 7, set FFS_ATTRIB_DATA_ALIGNMENT2
+ if (FfsAlign < 8) {
+ FfsFileHeader.Attributes = (EFI_FFS_FILE_ATTRIBUTES) (FfsAttrib | (FfsAlign << 3));
+ } else {
+ FfsFileHeader.Attributes = (EFI_FFS_FILE_ATTRIBUTES) (FfsAttrib | ((FfsAlign & 0x7) << 3) | FFS_ATTRIB_DATA_ALIGNMENT2);
+ }
+
+ //
+ // Fill in checksums and state, these must be zero for checksumming
+ //
+ // FileHeader.IntegrityCheck.Checksum.Header = 0;
+ // FileHeader.IntegrityCheck.Checksum.File = 0;
+ // FileHeader.State = 0;
+ //
+ FfsFileHeader.IntegrityCheck.Checksum.Header = CalculateChecksum8 (
+ (UINT8 *) &FfsFileHeader,
+ HeaderSize
+ );
+
+ if (FfsFileHeader.Attributes & FFS_ATTRIB_CHECKSUM) {
+ //
+ // Ffs header checksum = zero, so only need to calculate ffs body.
+ //
+ FfsFileHeader.IntegrityCheck.Checksum.File = CalculateChecksum8 (
+ FileBuffer,
+ FileSize - HeaderSize
+ );
+ } else {
+ FfsFileHeader.IntegrityCheck.Checksum.File = FFS_FIXED_CHECKSUM;
+ }
+
+ FfsFileHeader.State = EFI_FILE_HEADER_CONSTRUCTION | EFI_FILE_HEADER_VALID | EFI_FILE_DATA_VALID;
+
+ //
+ // Open output file to write ffs data.
+ //
+ if (OutputFileName != NULL) {
+ remove(OutputFileName);
+ FfsFile = fopen (LongFilePath (OutputFileName), "wb");
+ if (FfsFile == NULL) {
+ Error (NULL, 0, 0001, "Error opening file", OutputFileName);
+ goto Finish;
+ }
+ //
+ // write header
+ //
+ fwrite (&FfsFileHeader, 1, HeaderSize, FfsFile);
+ //
+ // write data
+ //
+ if (FileBuffer != NULL) {
+ fwrite (FileBuffer, 1, FileSize - HeaderSize, FfsFile);
+ }
+
+ fclose (FfsFile);
+ }
+
+Finish:
+ if (InputFileName != NULL) {
+ free (InputFileName);
+ }
+ if (InputFileAlign != NULL) {
+ free (InputFileAlign);
+ }
+ if (FileBuffer != NULL) {
+ free (FileBuffer);
+ }
+ //
+ // If any errors were reported via the standard error reporting
+ // routines, then the status has been saved. Get the value and
+ // return it to the caller.
+ //
+ VerboseMsg ("%s tool done with return code is 0x%x.", UTILITY_NAME, GetUtilityStatus ());
+
+ return GetUtilityStatus ();
+}