From 30fdf1140b8d1ce93f3821d986fa165552023440 Mon Sep 17 00:00:00 2001 From: lgao4 Date: Fri, 17 Jul 2009 09:10:31 +0000 Subject: Check In tool source code based on Build tool project revision r1655. git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@8964 6f19259b-4bc3-4df7-8a09-765794883524 --- BaseTools/Source/C/GenFfs/GNUmakefile | 11 + BaseTools/Source/C/GenFfs/GenFfs.c | 897 ++++++++++++++++++++++++++++++++++ BaseTools/Source/C/GenFfs/Makefile | 10 + 3 files changed, 918 insertions(+) create mode 100644 BaseTools/Source/C/GenFfs/GNUmakefile create mode 100644 BaseTools/Source/C/GenFfs/GenFfs.c create mode 100644 BaseTools/Source/C/GenFfs/Makefile (limited to 'BaseTools/Source/C/GenFfs') diff --git a/BaseTools/Source/C/GenFfs/GNUmakefile b/BaseTools/Source/C/GenFfs/GNUmakefile new file mode 100644 index 0000000000..df431b49e8 --- /dev/null +++ b/BaseTools/Source/C/GenFfs/GNUmakefile @@ -0,0 +1,11 @@ +ARCH ?= IA32 +MAKEROOT ?= .. + +APPNAME = GenFfs + +OBJECTS = GenFfs.o + +include $(MAKEROOT)/Makefiles/app.makefile + +LIBS = -lCommon + diff --git a/BaseTools/Source/C/GenFfs/GenFfs.c b/BaseTools/Source/C/GenFfs/GenFfs.c new file mode 100644 index 0000000000..e8cd09e947 --- /dev/null +++ b/BaseTools/Source/C/GenFfs/GenFfs.c @@ -0,0 +1,897 @@ +/** + +Copyright (c) 2004-2008, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + GenFfs.c + +Abstract: + + This file contains functions required to generate a Firmware File System + file. + +**/ + +#include +#include +#include + +#include +#include +#include + +#include "CommonLib.h" +#include "ParseInf.h" +#include "EfiUtilityMsgs.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 + }; + +STATIC CHAR8 *mAlignName[] = { + "1", "2", "4", "8", "16", "32", "64", "128", "256", "512", + "1K", "2K", "4K", "8K", "16K", "32K", "64K" + }; + +STATIC CHAR8 *mFfsValidAlignName[] = { + "8", "16", "128", "512", "1K", "4K", "32K", "64K" + }; + +STATIC UINT32 mFfsValidAlign[] = {0, 8, 16, 128, 512, 1024, 4096, 32768, 65536}; + +STATIC EFI_GUID mZeroGuid = {0}; + +STATIC +VOID +Version ( + VOID + ) +/*++ + +Routine Description: + + Print out version information for this utility. + +Arguments: + + None + +Returns: + + None + +--*/ +{ + fprintf (stdout, "%s Version %d.%d\n", UTILITY_NAME, UTILITY_MAJOR_VERSION, UTILITY_MINOR_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, 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_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"); + fprintf (stdout, " -i SectionFile, --sectionfile SectionFile\n\ + Section file will be contained in this FFS file.\n"); + fprintf (stdout, " -n SectionAlign, --sectionalign SectionAlign\n\ + SectionAlign points to section alignment, which support\n\ + the alignment scope 1~64K. It is specified together\n\ + with sectionfile to point its 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~64K). + +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, + 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_COMMON_SECTION_HEADER *SectHeader; + EFI_COMMON_SECTION_HEADER TempSectHeader; + EFI_TE_IMAGE_HEADER TeHeader; + UINT32 TeOffset; + + Size = 0; + Offset = 0; + TeOffset = 0; + + // + // 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++; + } + + // + // Get the Max alignment of all input file datas + // + if (*MaxAlignment < InputFileAlign [Index]) { + *MaxAlignment = InputFileAlign [Index]; + } + + // + // Open file and read contents + // + InFile = fopen (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 %d bytes", InputFileName[Index], FileSize); + + // + // Check this section is Te/Pe section, and Calculate the numbers of Te/Pe section. + // + TeOffset = 0; + fread (&TempSectHeader, 1, sizeof (TempSectHeader), 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_COMPRESSION || + TempSectHeader.Type == EFI_SECTION_GUID_DEFINED || + 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 raw 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 + sizeof (EFI_COMMON_SECTION_HEADER) + TeOffset) % InputFileAlign [Index]) != 0)) { + Offset = (Size + 2 * sizeof (EFI_COMMON_SECTION_HEADER) + TeOffset + InputFileAlign [Index] - 1) & ~(InputFileAlign [Index] - 1); + Offset = Offset - Size - sizeof (EFI_COMMON_SECTION_HEADER) - TeOffset; + + if (FileBuffer != NULL && ((Size + Offset) < *BufferLength)) { + SectHeader = (EFI_COMMON_SECTION_HEADER *) (FileBuffer + Size); + SectHeader->Type = EFI_SECTION_RAW; + SectHeader->Size[0] = (UINT8) (Offset & 0xff); + SectHeader->Size[1] = (UINT8) ((Offset & 0xff00) >> 8); + SectHeader->Size[2] = (UINT8) ((Offset & 0xff0000) >> 16); + } + DebugMsg (NULL, 0, 9, "Pad raw section for section data alignment", + "Pad Raw section size is %d", Offset); + + Size = Size + Offset; + } + + // + // 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; + } + + // + // Set the actual length of the data. + // + if (Size > *BufferLength) { + *BufferLength = Size; + return EFI_BUFFER_TOO_SMALL; + } else { + *BufferLength = Size; + return EFI_SUCCESS; + } +} + +int +main ( + INT32 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_HEADER FfsFileHeader; + FILE *FfsFile; + UINT32 Index; + UINT64 LogLevel; + UINT8 PeSectionNum; + + // + // 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], "-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; + } + + // + // 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)) { + 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", 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", argv[0]); + goto Finish; + } + + VerboseMsg ("%s tool start.", UTILITY_NAME); + + // + // Check the complete input paramters. + // + 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", + 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 %d", Index, InputFileName[Index], InputFileAlign[Index]); + } + + // + // Calculate the size of all input section files. + // + Status = GetSectionContents ( + InputFileName, + InputFileAlign, + InputFileNum, + 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 %d 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, + FileBuffer, + &FileSize, + &MaxAlignment, + &PeSectionNum + ); + } + + if (EFI_ERROR (Status)) { + goto Finish; + } + + // + // Create Ffs file header. + // + memset (&FfsFileHeader, 0, sizeof (EFI_FFS_FILE_HEADER)); + 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 %d", 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 genreated FFS file is %d", mFfsValidAlign [FfsAlign + 1]); + FfsFileHeader.Attributes = FfsAttrib | (FfsAlign << 3); + + // + // Now FileSize includes the EFI_FFS_FILE_HEADER + // + FileSize += sizeof (EFI_FFS_FILE_HEADER); + VerboseMsg ("the size of the genreated FFS file is %d bytes", FileSize); + FfsFileHeader.Size[0] = (UINT8) (FileSize & 0xFF); + FfsFileHeader.Size[1] = (UINT8) ((FileSize & 0xFF00) >> 8); + FfsFileHeader.Size[2] = (UINT8) ((FileSize & 0xFF0000) >> 16); + // + // 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, + sizeof (EFI_FFS_FILE_HEADER) + ); + + if (FfsFileHeader.Attributes & FFS_ATTRIB_CHECKSUM) { + // + // Ffs header checksum = zero, so only need to calculate ffs body. + // + FfsFileHeader.IntegrityCheck.Checksum.File = CalculateChecksum8 ( + FileBuffer, + FileSize - sizeof (EFI_FFS_FILE_HEADER) + ); + } 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. + // + remove(OutputFileName); + FfsFile = fopen (OutputFileName, "wb"); + if (FfsFile == NULL) { + Error (NULL, 0, 0001, "Error opening file", OutputFileName); + goto Finish; + } + // + // write header + // + fwrite (&FfsFileHeader, 1, sizeof (FfsFileHeader), FfsFile); + // + // write data + // + fwrite (FileBuffer, 1, FileSize - sizeof (EFI_FFS_FILE_HEADER), 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 (); +} diff --git a/BaseTools/Source/C/GenFfs/Makefile b/BaseTools/Source/C/GenFfs/Makefile new file mode 100644 index 0000000000..060cd03209 --- /dev/null +++ b/BaseTools/Source/C/GenFfs/Makefile @@ -0,0 +1,10 @@ +!INCLUDE ..\Makefiles\ms.common + +APPNAME = GenFfs + +LIBS = $(LIB_PATH)\Common.lib + +OBJECTS = GenFfs.obj + +!INCLUDE ..\Makefiles\ms.app + -- cgit v1.2.3