Home | History | Annotate | Download | only in GenFfs
      1 /** @file
      2 This file contains functions required to generate a Firmware File System file.
      3 
      4 Copyright (c) 2004 - 2016, Intel Corporation. All rights reserved.<BR>
      5 This program and the accompanying materials
      6 are licensed and made available under the terms and conditions of the BSD License
      7 which accompanies this distribution.  The full text of the license may be found at
      8 http://opensource.org/licenses/bsd-license.php
      9 
     10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     12 
     13 **/
     14 
     15 #include <stdio.h>
     16 #include <stdlib.h>
     17 #include <string.h>
     18 
     19 #include <Common/UefiBaseTypes.h>
     20 #include <Common/PiFirmwareFile.h>
     21 #include <IndustryStandard/PeImage.h>
     22 #include <Guid/FfsSectionAlignmentPadding.h>
     23 
     24 #include "CommonLib.h"
     25 #include "ParseInf.h"
     26 #include "EfiUtilityMsgs.h"
     27 
     28 #define UTILITY_NAME            "GenFfs"
     29 #define UTILITY_MAJOR_VERSION   0
     30 #define UTILITY_MINOR_VERSION   1
     31 
     32 STATIC CHAR8 *mFfsFileType[] = {
     33   NULL,                                   // 0x00
     34   "EFI_FV_FILETYPE_RAW",                  // 0x01
     35   "EFI_FV_FILETYPE_FREEFORM",             // 0x02
     36   "EFI_FV_FILETYPE_SECURITY_CORE",        // 0x03
     37   "EFI_FV_FILETYPE_PEI_CORE",             // 0x04
     38   "EFI_FV_FILETYPE_DXE_CORE",             // 0x05
     39   "EFI_FV_FILETYPE_PEIM",                 // 0x06
     40   "EFI_FV_FILETYPE_DRIVER",               // 0x07
     41   "EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER", // 0x08
     42   "EFI_FV_FILETYPE_APPLICATION",          // 0x09
     43   "EFI_FV_FILETYPE_SMM",                  // 0x0A
     44   "EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE",// 0x0B
     45   "EFI_FV_FILETYPE_COMBINED_SMM_DXE",     // 0x0C
     46   "EFI_FV_FILETYPE_SMM_CORE"              // 0x0D
     47  };
     48 
     49 STATIC CHAR8 *mAlignName[] = {
     50   "1", "2", "4", "8", "16", "32", "64", "128", "256", "512",
     51   "1K", "2K", "4K", "8K", "16K", "32K", "64K"
     52  };
     53 
     54 STATIC CHAR8 *mFfsValidAlignName[] = {
     55   "8", "16", "128", "512", "1K", "4K", "32K", "64K"
     56  };
     57 
     58 STATIC UINT32 mFfsValidAlign[] = {0, 8, 16, 128, 512, 1024, 4096, 32768, 65536};
     59 
     60 STATIC EFI_GUID mZeroGuid = {0};
     61 
     62 STATIC EFI_GUID mEfiFfsSectionAlignmentPaddingGuid = EFI_FFS_SECTION_ALIGNMENT_PADDING_GUID;
     63 
     64 STATIC
     65 VOID
     66 Version (
     67   VOID
     68   )
     69 /*++
     70 
     71 Routine Description:
     72 
     73   Print out version information for this utility.
     74 
     75 Arguments:
     76 
     77   None
     78 
     79 Returns:
     80 
     81   None
     82 
     83 --*/
     84 {
     85   fprintf (stdout, "%s Version %d.%d %s \n", UTILITY_NAME, UTILITY_MAJOR_VERSION, UTILITY_MINOR_VERSION, __BUILD_VERSION);
     86 }
     87 
     88 STATIC
     89 VOID
     90 Usage (
     91   VOID
     92   )
     93 /*++
     94 
     95 Routine Description:
     96 
     97   Print Error / Help message.
     98 
     99 Arguments:
    100 
    101   VOID
    102 
    103 Returns:
    104 
    105   None
    106 
    107 --*/
    108 {
    109   //
    110   // Summary usage
    111   //
    112   fprintf (stdout, "\nUsage: %s [options]\n\n", UTILITY_NAME);
    113 
    114   //
    115   // Copyright declaration
    116   //
    117   fprintf (stdout, "Copyright (c) 2007 - 2014, Intel Corporation. All rights reserved.\n\n");
    118 
    119   //
    120   // Details Option
    121   //
    122   fprintf (stdout, "Options:\n");
    123   fprintf (stdout, "  -o FileName, --outputfile FileName\n\
    124                         File is FFS file to be created.\n");
    125   fprintf (stdout, "  -t Type, --filetype Type\n\
    126                         Type is one FV file type defined in PI spec, which is\n\
    127                         EFI_FV_FILETYPE_RAW, EFI_FV_FILETYPE_FREEFORM,\n\
    128                         EFI_FV_FILETYPE_SECURITY_CORE, EFI_FV_FILETYPE_PEIM,\n\
    129                         EFI_FV_FILETYPE_PEI_CORE, EFI_FV_FILETYPE_DXE_CORE,\n\
    130                         EFI_FV_FILETYPE_DRIVER, EFI_FV_FILETYPE_APPLICATION,\n\
    131                         EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER,\n\
    132                         EFI_FV_FILETYPE_SMM, EFI_FV_FILETYPE_SMM_CORE,\n\
    133                         EFI_FV_FILETYPE_COMBINED_SMM_DXE, \n\
    134                         EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE.\n");
    135   fprintf (stdout, "  -g FileGuid, --fileguid FileGuid\n\
    136                         FileGuid is one module guid.\n\
    137                         Its format is xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx\n");
    138   fprintf (stdout, "  -x, --fixed           Indicates that the file may not be moved\n\
    139                         from its present location.\n");
    140   fprintf (stdout, "  -s, --checksum        Indicates to calculate file checksum.\n");
    141   fprintf (stdout, "  -a FileAlign, --align FileAlign\n\
    142                         FileAlign points to file alignment, which only support\n\
    143                         the following align: 1,2,4,8,16,128,512,1K,4K,32K,64K\n");
    144   fprintf (stdout, "  -i SectionFile, --sectionfile SectionFile\n\
    145                         Section file will be contained in this FFS file.\n");
    146   fprintf (stdout, "  -n SectionAlign, --sectionalign SectionAlign\n\
    147                         SectionAlign points to section alignment, which support\n\
    148                         the alignment scope 1~64K. It is specified together\n\
    149                         with sectionfile to point its alignment in FFS file.\n");
    150   fprintf (stdout, "  -v, --verbose         Turn on verbose output with informational messages.\n");
    151   fprintf (stdout, "  -q, --quiet           Disable all messages except key message and fatal error\n");
    152   fprintf (stdout, "  -d, --debug level     Enable debug messages, at input debug level.\n");
    153   fprintf (stdout, "  --version             Show program's version number and exit.\n");
    154   fprintf (stdout, "  -h, --help            Show this help message and exit.\n");
    155 }
    156 
    157 STATIC
    158 EFI_STATUS
    159 StringtoAlignment (
    160   IN  CHAR8  *AlignBuffer,
    161   OUT UINT32 *AlignNumber
    162   )
    163 /*++
    164 
    165 Routine Description:
    166 
    167   Converts Align String to align value (1~64K).
    168 
    169 Arguments:
    170 
    171   AlignBuffer    - Pointer to Align string.
    172   AlignNumber    - Pointer to Align value.
    173 
    174 Returns:
    175 
    176   EFI_SUCCESS             Successfully convert align string to align value.
    177   EFI_INVALID_PARAMETER   Align string is invalid or align value is not in scope.
    178 
    179 --*/
    180 {
    181   UINT32 Index = 0;
    182   //
    183   // Check AlignBuffer
    184   //
    185   if (AlignBuffer == NULL) {
    186     return EFI_INVALID_PARAMETER;
    187   }
    188   for (Index = 0; Index < sizeof (mAlignName) / sizeof (CHAR8 *); Index ++) {
    189     if (stricmp (AlignBuffer, mAlignName [Index]) == 0) {
    190       *AlignNumber = 1 << Index;
    191       return EFI_SUCCESS;
    192     }
    193   }
    194   return EFI_INVALID_PARAMETER;
    195 }
    196 
    197 STATIC
    198 UINT8
    199 StringToType (
    200   IN CHAR8 *String
    201   )
    202 /*++
    203 
    204 Routine Description:
    205 
    206   Converts File Type String to value.  EFI_FV_FILETYPE_ALL indicates that an
    207   unrecognized file type was specified.
    208 
    209 Arguments:
    210 
    211   String    - File type string
    212 
    213 Returns:
    214 
    215   File Type Value
    216 
    217 --*/
    218 {
    219   UINT8 Index = 0;
    220 
    221   if (String == NULL) {
    222     return EFI_FV_FILETYPE_ALL;
    223   }
    224 
    225   for (Index = 0; Index < sizeof (mFfsFileType) / sizeof (CHAR8 *); Index ++) {
    226     if (mFfsFileType [Index] != NULL && (stricmp (String, mFfsFileType [Index]) == 0)) {
    227       return Index;
    228     }
    229   }
    230   return EFI_FV_FILETYPE_ALL;
    231 }
    232 
    233 STATIC
    234 EFI_STATUS
    235 GetSectionContents (
    236   IN  CHAR8                     **InputFileName,
    237   IN  UINT32                    *InputFileAlign,
    238   IN  UINT32                    InputFileNum,
    239   IN  EFI_FFS_FILE_ATTRIBUTES   FfsAttrib,
    240   OUT UINT8                     *FileBuffer,
    241   OUT UINT32                    *BufferLength,
    242   OUT UINT32                    *MaxAlignment,
    243   OUT UINT8                     *PESectionNum
    244   )
    245 /*++
    246 
    247 Routine Description:
    248 
    249   Get the contents of all section files specified in InputFileName
    250   into FileBuffer.
    251 
    252 Arguments:
    253 
    254   InputFileName  - Name of the input file.
    255 
    256   InputFileAlign - Alignment required by the input file data.
    257 
    258   InputFileNum   - Number of input files. Should be at least 1.
    259 
    260   FileBuffer     - Output buffer to contain data
    261 
    262   BufferLength   - On input, this is size of the FileBuffer.
    263                    On output, this is the actual length of the data.
    264 
    265   MaxAlignment   - The max alignment required by all the input file datas.
    266 
    267   PeSectionNum   - Calculate the number of Pe/Te Section in this FFS file.
    268 
    269 Returns:
    270 
    271   EFI_SUCCESS on successful return
    272   EFI_INVALID_PARAMETER if InputFileNum is less than 1 or BufferLength point is NULL.
    273   EFI_ABORTED if unable to open input file.
    274   EFI_BUFFER_TOO_SMALL FileBuffer is not enough to contain all file data.
    275 --*/
    276 {
    277   UINT32                              Size;
    278   UINT32                              Offset;
    279   UINT32                              FileSize;
    280   UINT32                              Index;
    281   FILE                                *InFile;
    282   EFI_FREEFORM_SUBTYPE_GUID_SECTION   *SectHeader;
    283   EFI_COMMON_SECTION_HEADER2          TempSectHeader;
    284   EFI_TE_IMAGE_HEADER                 TeHeader;
    285   UINT32                              TeOffset;
    286   EFI_GUID_DEFINED_SECTION            GuidSectHeader;
    287   EFI_GUID_DEFINED_SECTION2           GuidSectHeader2;
    288   UINT32                              HeaderSize;
    289   UINT32                              MaxEncounteredAlignment;
    290 
    291   Size                    = 0;
    292   Offset                  = 0;
    293   TeOffset                = 0;
    294   MaxEncounteredAlignment = 1;
    295 
    296   //
    297   // Go through our array of file names and copy their contents
    298   // to the output buffer.
    299   //
    300   for (Index = 0; Index < InputFileNum; Index++) {
    301     //
    302     // make sure section ends on a DWORD boundary
    303     //
    304     while ((Size & 0x03) != 0) {
    305       Size++;
    306     }
    307 
    308     //
    309     // Open file and read contents
    310     //
    311     InFile = fopen (LongFilePath (InputFileName[Index]), "rb");
    312     if (InFile == NULL) {
    313       Error (NULL, 0, 0001, "Error opening file", InputFileName[Index]);
    314       return EFI_ABORTED;
    315     }
    316 
    317     fseek (InFile, 0, SEEK_END);
    318     FileSize = ftell (InFile);
    319     fseek (InFile, 0, SEEK_SET);
    320     DebugMsg (NULL, 0, 9, "Input section files",
    321               "the input section name is %s and the size is %u bytes", InputFileName[Index], (unsigned) FileSize);
    322 
    323     //
    324     // Check this section is Te/Pe section, and Calculate the numbers of Te/Pe section.
    325     //
    326     TeOffset = 0;
    327     if (FileSize >= MAX_FFS_SIZE) {
    328       HeaderSize = sizeof (EFI_COMMON_SECTION_HEADER2);
    329     } else {
    330       HeaderSize = sizeof (EFI_COMMON_SECTION_HEADER);
    331     }
    332     fread (&TempSectHeader, 1, HeaderSize, InFile);
    333     if (TempSectHeader.Type == EFI_SECTION_TE) {
    334       (*PESectionNum) ++;
    335       fread (&TeHeader, 1, sizeof (TeHeader), InFile);
    336       if (TeHeader.Signature == EFI_TE_IMAGE_HEADER_SIGNATURE) {
    337         TeOffset = TeHeader.StrippedSize - sizeof (TeHeader);
    338       }
    339     } else if (TempSectHeader.Type == EFI_SECTION_PE32) {
    340       (*PESectionNum) ++;
    341     } else if (TempSectHeader.Type == EFI_SECTION_GUID_DEFINED) {
    342       fseek (InFile, 0, SEEK_SET);
    343       if (FileSize >= MAX_SECTION_SIZE) {
    344         fread (&GuidSectHeader2, 1, sizeof (GuidSectHeader2), InFile);
    345         if ((GuidSectHeader2.Attributes & EFI_GUIDED_SECTION_PROCESSING_REQUIRED) == 0) {
    346           HeaderSize = GuidSectHeader2.DataOffset;
    347         }
    348       } else {
    349         fread (&GuidSectHeader, 1, sizeof (GuidSectHeader), InFile);
    350         if ((GuidSectHeader.Attributes & EFI_GUIDED_SECTION_PROCESSING_REQUIRED) == 0) {
    351           HeaderSize = GuidSectHeader.DataOffset;
    352         }
    353       }
    354       (*PESectionNum) ++;
    355     } else if (TempSectHeader.Type == EFI_SECTION_COMPRESSION ||
    356                TempSectHeader.Type == EFI_SECTION_FIRMWARE_VOLUME_IMAGE) {
    357       //
    358       // for the encapsulated section, assume it contains Pe/Te section
    359       //
    360       (*PESectionNum) ++;
    361     }
    362 
    363     fseek (InFile, 0, SEEK_SET);
    364 
    365     //
    366     // Revert TeOffset to the converse value relative to Alignment
    367     // This is to assure the original PeImage Header at Alignment.
    368     //
    369     if ((TeOffset != 0) && (InputFileAlign [Index] != 0)) {
    370       TeOffset = InputFileAlign [Index] - (TeOffset % InputFileAlign [Index]);
    371       TeOffset = TeOffset % InputFileAlign [Index];
    372     }
    373 
    374     //
    375     // make sure section data meet its alignment requirement by adding one pad section.
    376     // But the different sections have the different section header. Necessary or not?
    377     // Based on section type to adjust offset? Todo
    378     //
    379     if ((InputFileAlign [Index] != 0) && (((Size + HeaderSize + TeOffset) % InputFileAlign [Index]) != 0)) {
    380       Offset = (Size + sizeof (EFI_COMMON_SECTION_HEADER) + HeaderSize + TeOffset + InputFileAlign [Index] - 1) & ~(InputFileAlign [Index] - 1);
    381       Offset = Offset - Size - HeaderSize - TeOffset;
    382 
    383       if (FileBuffer != NULL && ((Size + Offset) < *BufferLength)) {
    384         //
    385         // The maximal alignment is 64K, the raw section size must be less than 0xffffff
    386         //
    387         memset (FileBuffer + Size, 0, Offset);
    388         SectHeader                        = (EFI_FREEFORM_SUBTYPE_GUID_SECTION *) (FileBuffer + Size);
    389         SectHeader->CommonHeader.Size[0]  = (UINT8) (Offset & 0xff);
    390         SectHeader->CommonHeader.Size[1]  = (UINT8) ((Offset & 0xff00) >> 8);
    391         SectHeader->CommonHeader.Size[2]  = (UINT8) ((Offset & 0xff0000) >> 16);
    392 
    393         //
    394         // Only add a special reducible padding section if
    395         // - this FFS has the FFS_ATTRIB_FIXED attribute,
    396         // - none of the preceding sections have alignment requirements,
    397         // - the size of the padding is sufficient for the
    398         //   EFI_SECTION_FREEFORM_SUBTYPE_GUID header.
    399         //
    400         if ((FfsAttrib & FFS_ATTRIB_FIXED) != 0 &&
    401             MaxEncounteredAlignment <= 1 &&
    402             Offset >= sizeof (EFI_FREEFORM_SUBTYPE_GUID_SECTION)) {
    403           SectHeader->CommonHeader.Type   = EFI_SECTION_FREEFORM_SUBTYPE_GUID;
    404           SectHeader->SubTypeGuid         = mEfiFfsSectionAlignmentPaddingGuid;
    405         } else {
    406           SectHeader->CommonHeader.Type   = EFI_SECTION_RAW;
    407         }
    408       }
    409       DebugMsg (NULL, 0, 9, "Pad raw section for section data alignment",
    410                 "Pad Raw section size is %u", (unsigned) Offset);
    411 
    412       Size = Size + Offset;
    413     }
    414 
    415     //
    416     // Get the Max alignment of all input file datas
    417     //
    418     if (MaxEncounteredAlignment < InputFileAlign [Index]) {
    419       MaxEncounteredAlignment = InputFileAlign [Index];
    420     }
    421 
    422     //
    423     // Now read the contents of the file into the buffer
    424     // Buffer must be enough to contain the file content.
    425     //
    426     if ((FileSize > 0) && (FileBuffer != NULL) && ((Size + FileSize) <= *BufferLength)) {
    427       if (fread (FileBuffer + Size, (size_t) FileSize, 1, InFile) != 1) {
    428         Error (NULL, 0, 0004, "Error reading file", InputFileName[Index]);
    429         fclose (InFile);
    430         return EFI_ABORTED;
    431       }
    432     }
    433 
    434     fclose (InFile);
    435     Size += FileSize;
    436   }
    437 
    438   *MaxAlignment = MaxEncounteredAlignment;
    439 
    440   //
    441   // Set the actual length of the data.
    442   //
    443   if (Size > *BufferLength) {
    444     *BufferLength = Size;
    445     return EFI_BUFFER_TOO_SMALL;
    446   } else {
    447     *BufferLength = Size;
    448     return EFI_SUCCESS;
    449   }
    450 }
    451 
    452 int
    453 main (
    454   int   argc,
    455   CHAR8 *argv[]
    456   )
    457 /*++
    458 
    459 Routine Description:
    460 
    461   Main function.
    462 
    463 Arguments:
    464 
    465   argc - Number of command line parameters.
    466   argv - Array of pointers to parameter strings.
    467 
    468 Returns:
    469   STATUS_SUCCESS - Utility exits successfully.
    470   STATUS_ERROR   - Some error occurred during execution.
    471 
    472 --*/
    473 {
    474   EFI_STATUS              Status;
    475   EFI_FFS_FILE_ATTRIBUTES FfsAttrib;
    476   UINT32                  FfsAlign;
    477   EFI_FV_FILETYPE         FfsFiletype;
    478   CHAR8                   *OutputFileName;
    479   EFI_GUID                FileGuid = {0};
    480   UINT32                  InputFileNum;
    481   UINT32                  *InputFileAlign;
    482   CHAR8                   **InputFileName;
    483   UINT8                   *FileBuffer;
    484   UINT32                  FileSize;
    485   UINT32                  MaxAlignment;
    486   EFI_FFS_FILE_HEADER2    FfsFileHeader;
    487   FILE                    *FfsFile;
    488   UINT32                  Index;
    489   UINT64                  LogLevel;
    490   UINT8                   PeSectionNum;
    491   UINT32                  HeaderSize;
    492 
    493   //
    494   // Init local variables
    495   //
    496   LogLevel       = 0;
    497   Index          = 0;
    498   FfsAttrib      = 0;
    499   FfsAlign       = 0;
    500   FfsFiletype    = EFI_FV_FILETYPE_ALL;
    501   OutputFileName = NULL;
    502   InputFileNum   = 0;
    503   InputFileName  = NULL;
    504   InputFileAlign = NULL;
    505   FileBuffer     = NULL;
    506   FileSize       = 0;
    507   MaxAlignment   = 1;
    508   FfsFile        = NULL;
    509   Status         = EFI_SUCCESS;
    510   PeSectionNum   = 0;
    511 
    512   SetUtilityName (UTILITY_NAME);
    513 
    514   if (argc == 1) {
    515     Error (NULL, 0, 1001, "Missing options", "no options input");
    516     Usage ();
    517     return STATUS_ERROR;
    518   }
    519 
    520   //
    521   // Parse command line
    522   //
    523   argc --;
    524   argv ++;
    525 
    526   if ((stricmp (argv[0], "-h") == 0) || (stricmp (argv[0], "--help") == 0)) {
    527     Version ();
    528     Usage ();
    529     return STATUS_SUCCESS;
    530   }
    531 
    532   if (stricmp (argv[0], "--version") == 0) {
    533     Version ();
    534     return STATUS_SUCCESS;
    535   }
    536 
    537   while (argc > 0) {
    538     if ((stricmp (argv[0], "-t") == 0) || (stricmp (argv[0], "--filetype") == 0)) {
    539       if (argv[1] == NULL || argv[1][0] == '-') {
    540         Error (NULL, 0, 1003, "Invalid option value", "file type is missing for -t option");
    541         goto Finish;
    542       }
    543       FfsFiletype = StringToType (argv[1]);
    544       if (FfsFiletype == EFI_FV_FILETYPE_ALL) {
    545         Error (NULL, 0, 1003, "Invalid option value", "%s is not a valid file type", argv[1]);
    546         goto Finish;
    547       }
    548       argc -= 2;
    549       argv += 2;
    550       continue;
    551     }
    552 
    553     if ((stricmp (argv[0], "-o") == 0) || (stricmp (argv[0], "--outputfile") == 0)) {
    554       if (argv[1] == NULL || argv[1][0] == '-') {
    555         Error (NULL, 0, 1003, "Invalid option value", "Output file is missing for -o option");
    556         goto Finish;
    557       }
    558       OutputFileName = argv[1];
    559       argc -= 2;
    560       argv += 2;
    561       continue;
    562     }
    563 
    564     if ((stricmp (argv[0], "-g") == 0) || (stricmp (argv[0], "--fileguid") == 0)) {
    565       Status = StringToGuid (argv[1], &FileGuid);
    566       if (EFI_ERROR (Status)) {
    567         Error (NULL, 0, 1003, "Invalid option value", "%s = %s", argv[0], argv[1]);
    568         goto Finish;
    569       }
    570       argc -= 2;
    571       argv += 2;
    572       continue;
    573     }
    574 
    575     if ((stricmp (argv[0], "-x") == 0) || (stricmp (argv[0], "--fixed") == 0)) {
    576       FfsAttrib |= FFS_ATTRIB_FIXED;
    577       argc -= 1;
    578       argv += 1;
    579       continue;
    580     }
    581 
    582     if ((stricmp (argv[0], "-s") == 0) || (stricmp (argv[0], "--checksum") == 0)) {
    583       FfsAttrib |= FFS_ATTRIB_CHECKSUM;
    584       argc -= 1;
    585       argv += 1;
    586       continue;
    587     }
    588 
    589     if ((stricmp (argv[0], "-a") == 0) || (stricmp (argv[0], "--align") == 0)) {
    590       if (argv[1] == NULL || argv[1][0] == '-') {
    591         Error (NULL, 0, 1003, "Invalid option value", "Align value is missing for -a option");
    592         goto Finish;
    593       }
    594       for (Index = 0; Index < sizeof (mFfsValidAlignName) / sizeof (CHAR8 *); Index ++) {
    595         if (stricmp (argv[1], mFfsValidAlignName[Index]) == 0) {
    596           break;
    597         }
    598       }
    599       if (Index == sizeof (mFfsValidAlignName) / sizeof (CHAR8 *)) {
    600         if ((stricmp (argv[1], "1") == 0) || (stricmp (argv[1], "2") == 0) || (stricmp (argv[1], "4") == 0)) {
    601           //
    602           // 1, 2, 4 byte alignment same to 8 byte alignment
    603           //
    604           Index = 0;
    605         } else {
    606           Error (NULL, 0, 1003, "Invalid option value", "%s = %s", argv[0], argv[1]);
    607           goto Finish;
    608         }
    609       }
    610       FfsAlign = Index;
    611       argc -= 2;
    612       argv += 2;
    613       continue;
    614     }
    615 
    616     if ((stricmp (argv[0], "-i") == 0) || (stricmp (argv[0], "--sectionfile") == 0)) {
    617       //
    618       // Get Input file name and its alignment
    619       //
    620       if (argv[1] == NULL || argv[1][0] == '-') {
    621         Error (NULL, 0, 1003, "Invalid option value", "input section file is missing for -i option");
    622         goto Finish;
    623       }
    624 
    625       //
    626       // Allocate Input file name buffer and its alignment buffer.
    627       //
    628       if ((InputFileNum == 0) && (InputFileName == NULL)) {
    629         InputFileName = (CHAR8 **) malloc (MAXIMUM_INPUT_FILE_NUM * sizeof (CHAR8 *));
    630         if (InputFileName == NULL) {
    631           Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!");
    632           return STATUS_ERROR;
    633         }
    634         memset (InputFileName, 0, (MAXIMUM_INPUT_FILE_NUM * sizeof (CHAR8 *)));
    635 
    636         InputFileAlign = (UINT32 *) malloc (MAXIMUM_INPUT_FILE_NUM * sizeof (UINT32));
    637         if (InputFileAlign == NULL) {
    638           Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!");
    639           free (InputFileName);
    640           return STATUS_ERROR;
    641         }
    642         memset (InputFileAlign, 0, MAXIMUM_INPUT_FILE_NUM * sizeof (UINT32));
    643       } else if (InputFileNum % MAXIMUM_INPUT_FILE_NUM == 0) {
    644         //
    645         // InputFileName and alignment buffer too small, need to realloc
    646         //
    647         InputFileName = (CHAR8 **) realloc (
    648                                     InputFileName,
    649                                     (InputFileNum + MAXIMUM_INPUT_FILE_NUM) * sizeof (CHAR8 *)
    650                                     );
    651 
    652         if (InputFileName == NULL) {
    653           Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!");
    654           free (InputFileAlign);
    655           return STATUS_ERROR;
    656         }
    657         memset (&(InputFileName[InputFileNum]), 0, (MAXIMUM_INPUT_FILE_NUM * sizeof (CHAR8 *)));
    658 
    659         InputFileAlign = (UINT32 *) realloc (
    660                                     InputFileAlign,
    661                                     (InputFileNum + MAXIMUM_INPUT_FILE_NUM) * sizeof (UINT32)
    662                                     );
    663 
    664         if (InputFileAlign == NULL) {
    665           Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!");
    666           free (InputFileName);
    667           return STATUS_ERROR;
    668         }
    669         memset (&(InputFileAlign[InputFileNum]), 0, (MAXIMUM_INPUT_FILE_NUM * sizeof (UINT32)));
    670       }
    671 
    672       InputFileName[InputFileNum] = argv[1];
    673       argc -= 2;
    674       argv += 2;
    675 
    676       if (argc <= 0) {
    677 	      InputFileNum ++;
    678         break;
    679       }
    680 
    681       //
    682       // Section File alignment requirement
    683       //
    684       if ((stricmp (argv[0], "-n") == 0) || (stricmp (argv[0], "--sectionalign") == 0)) {
    685         Status = StringtoAlignment (argv[1], &(InputFileAlign[InputFileNum]));
    686         if (EFI_ERROR (Status)) {
    687           Error (NULL, 0, 1003, "Invalid option value", "%s = %s", argv[0], argv[1]);
    688           goto Finish;
    689         }
    690         argc -= 2;
    691         argv += 2;
    692       }
    693       InputFileNum ++;
    694       continue;
    695     }
    696 
    697     if ((stricmp (argv[0], "-n") == 0) || (stricmp (argv[0], "--sectionalign") == 0)) {
    698       Error (NULL, 0, 1000, "Unknown option", "SectionAlign option must be specified with section file.");
    699       goto Finish;
    700     }
    701 
    702     if ((stricmp (argv[0], "-v") == 0) || (stricmp (argv[0], "--verbose") == 0)) {
    703       SetPrintLevel (VERBOSE_LOG_LEVEL);
    704       VerboseMsg ("Verbose output Mode Set!");
    705       argc --;
    706       argv ++;
    707       continue;
    708     }
    709 
    710     if ((stricmp (argv[0], "-q") == 0) || (stricmp (argv[0], "--quiet") == 0)) {
    711       SetPrintLevel (KEY_LOG_LEVEL);
    712       KeyMsg ("Quiet output Mode Set!");
    713       argc --;
    714       argv ++;
    715       continue;
    716     }
    717 
    718     if ((stricmp (argv[0], "-d") == 0) || (stricmp (argv[0], "--debug") == 0)) {
    719       Status = AsciiStringToUint64 (argv[1], FALSE, &LogLevel);
    720       if (EFI_ERROR (Status)) {
    721         Error (NULL, 0, 1003, "Invalid option value", "%s = %s", argv[0], argv[1]);
    722         goto Finish;
    723       }
    724       if (LogLevel > 9) {
    725         Error (NULL, 0, 1003, "Invalid option value", "Debug Level range is 0-9, current input level is %d", (int) LogLevel);
    726         goto Finish;
    727       }
    728       SetPrintLevel (LogLevel);
    729       DebugMsg (NULL, 0, 9, "Debug Mode Set", "Debug Output Mode Level %s is set!", argv[1]);
    730       argc -= 2;
    731       argv += 2;
    732       continue;
    733     }
    734 
    735     Error (NULL, 0, 1000, "Unknown option", argv[0]);
    736     goto Finish;
    737   }
    738 
    739   VerboseMsg ("%s tool start.", UTILITY_NAME);
    740 
    741   //
    742   // Check the complete input parameters.
    743   //
    744   if (FfsFiletype == EFI_FV_FILETYPE_ALL) {
    745     Error (NULL, 0, 1001, "Missing option", "filetype");
    746     goto Finish;
    747   }
    748 
    749   if (CompareGuid (&FileGuid, &mZeroGuid) == 0) {
    750     Error (NULL, 0, 1001, "Missing option", "fileguid");
    751     goto Finish;
    752   }
    753 
    754   if (InputFileNum == 0) {
    755     Error (NULL, 0, 1001, "Missing option", "Input files");
    756     goto Finish;
    757   }
    758 
    759   //
    760   // Output input parameter information
    761   //
    762   VerboseMsg ("Fv File type is %s", mFfsFileType [FfsFiletype]);
    763   VerboseMsg ("Output file name is %s", OutputFileName);
    764   VerboseMsg ("FFS File Guid is %08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X",
    765                 (unsigned) FileGuid.Data1,
    766                 FileGuid.Data2,
    767                 FileGuid.Data3,
    768                 FileGuid.Data4[0],
    769                 FileGuid.Data4[1],
    770                 FileGuid.Data4[2],
    771                 FileGuid.Data4[3],
    772                 FileGuid.Data4[4],
    773                 FileGuid.Data4[5],
    774                 FileGuid.Data4[6],
    775                 FileGuid.Data4[7]);
    776   if ((FfsAttrib & FFS_ATTRIB_FIXED) != 0) {
    777     VerboseMsg ("FFS File has the fixed file attribute");
    778   }
    779   if ((FfsAttrib & FFS_ATTRIB_CHECKSUM) != 0) {
    780     VerboseMsg ("FFS File requires the checksum of the whole file");
    781   }
    782   VerboseMsg ("FFS file alignment is %s", mFfsValidAlignName[FfsAlign]);
    783   for (Index = 0; Index < InputFileNum; Index ++) {
    784     if (InputFileAlign[Index] == 0) {
    785       //
    786       // Minimum alignment is 1 byte.
    787       //
    788       InputFileAlign[Index] = 1;
    789     }
    790     VerboseMsg ("the %dth input section name is %s and section alignment is %u", Index, InputFileName[Index], (unsigned) InputFileAlign[Index]);
    791   }
    792 
    793   //
    794   // Calculate the size of all input section files.
    795   //
    796   Status = GetSectionContents (
    797              InputFileName,
    798              InputFileAlign,
    799              InputFileNum,
    800              FfsAttrib,
    801              FileBuffer,
    802              &FileSize,
    803              &MaxAlignment,
    804              &PeSectionNum
    805              );
    806 
    807   if ((FfsFiletype == EFI_FV_FILETYPE_SECURITY_CORE ||
    808       FfsFiletype == EFI_FV_FILETYPE_PEI_CORE ||
    809       FfsFiletype == EFI_FV_FILETYPE_DXE_CORE) && (PeSectionNum != 1)) {
    810     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);
    811     goto Finish;
    812   }
    813 
    814   if ((FfsFiletype == EFI_FV_FILETYPE_PEIM ||
    815       FfsFiletype == EFI_FV_FILETYPE_DRIVER ||
    816       FfsFiletype == EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER ||
    817       FfsFiletype == EFI_FV_FILETYPE_APPLICATION) && (PeSectionNum < 1)) {
    818     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]);
    819     goto Finish;
    820   }
    821 
    822   if (Status == EFI_BUFFER_TOO_SMALL) {
    823     FileBuffer = (UINT8 *) malloc (FileSize);
    824     if (FileBuffer == NULL) {
    825       Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!");
    826       goto Finish;
    827     }
    828     memset (FileBuffer, 0, FileSize);
    829 
    830     //
    831     // read all input file contents into a buffer
    832     //
    833     Status = GetSectionContents (
    834                InputFileName,
    835                InputFileAlign,
    836                InputFileNum,
    837                FfsAttrib,
    838                FileBuffer,
    839                &FileSize,
    840                &MaxAlignment,
    841                &PeSectionNum
    842                );
    843   }
    844 
    845   if (EFI_ERROR (Status)) {
    846     goto Finish;
    847   }
    848 
    849   if (FileBuffer == NULL && FileSize != 0) {
    850     Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!");
    851     goto Finish;
    852   }
    853 
    854   //
    855   // Create Ffs file header.
    856   //
    857   memset (&FfsFileHeader, 0, sizeof (EFI_FFS_FILE_HEADER2));
    858   memcpy (&FfsFileHeader.Name, &FileGuid, sizeof (EFI_GUID));
    859   FfsFileHeader.Type       = FfsFiletype;
    860   //
    861   // Update FFS Alignment based on the max alignment required by input section files
    862   //
    863   VerboseMsg ("the max alignment of all input sections is %u", (unsigned) MaxAlignment);
    864   for (Index = 0; Index < sizeof (mFfsValidAlign) / sizeof (UINT32) - 1; Index ++) {
    865     if ((MaxAlignment > mFfsValidAlign [Index]) && (MaxAlignment <= mFfsValidAlign [Index + 1])) {
    866       break;
    867     }
    868   }
    869   if (FfsAlign < Index) {
    870     FfsAlign = Index;
    871   }
    872   VerboseMsg ("the alignment of the generated FFS file is %u", (unsigned) mFfsValidAlign [FfsAlign + 1]);
    873 
    874   //
    875   // Now FileSize includes the EFI_FFS_FILE_HEADER
    876   //
    877   if (FileSize + sizeof (EFI_FFS_FILE_HEADER) >= MAX_FFS_SIZE) {
    878     HeaderSize = sizeof (EFI_FFS_FILE_HEADER2);
    879     FileSize += sizeof (EFI_FFS_FILE_HEADER2);
    880     FfsFileHeader.ExtendedSize = FileSize;
    881     memset(FfsFileHeader.Size, 0, sizeof (UINT8) * 3);
    882     FfsAttrib |= FFS_ATTRIB_LARGE_FILE;
    883   } else {
    884     HeaderSize = sizeof (EFI_FFS_FILE_HEADER);
    885     FileSize += sizeof (EFI_FFS_FILE_HEADER);
    886     FfsFileHeader.Size[0]  = (UINT8) (FileSize & 0xFF);
    887     FfsFileHeader.Size[1]  = (UINT8) ((FileSize & 0xFF00) >> 8);
    888     FfsFileHeader.Size[2]  = (UINT8) ((FileSize & 0xFF0000) >> 16);
    889   }
    890   VerboseMsg ("the size of the generated FFS file is %u bytes", (unsigned) FileSize);
    891 
    892   FfsFileHeader.Attributes = (EFI_FFS_FILE_ATTRIBUTES) (FfsAttrib | (FfsAlign << 3));
    893 
    894   //
    895   // Fill in checksums and state, these must be zero for checksumming
    896   //
    897   // FileHeader.IntegrityCheck.Checksum.Header = 0;
    898   // FileHeader.IntegrityCheck.Checksum.File = 0;
    899   // FileHeader.State = 0;
    900   //
    901   FfsFileHeader.IntegrityCheck.Checksum.Header = CalculateChecksum8 (
    902                                                    (UINT8 *) &FfsFileHeader,
    903                                                    HeaderSize
    904                                                    );
    905 
    906   if (FfsFileHeader.Attributes & FFS_ATTRIB_CHECKSUM) {
    907     //
    908     // Ffs header checksum = zero, so only need to calculate ffs body.
    909     //
    910     FfsFileHeader.IntegrityCheck.Checksum.File = CalculateChecksum8 (
    911                                                    FileBuffer,
    912                                                    FileSize - HeaderSize
    913                                                    );
    914   } else {
    915     FfsFileHeader.IntegrityCheck.Checksum.File = FFS_FIXED_CHECKSUM;
    916   }
    917 
    918   FfsFileHeader.State = EFI_FILE_HEADER_CONSTRUCTION | EFI_FILE_HEADER_VALID | EFI_FILE_DATA_VALID;
    919 
    920   //
    921   // Open output file to write ffs data.
    922   //
    923   if (OutputFileName != NULL) {
    924     remove(OutputFileName);
    925     FfsFile = fopen (LongFilePath (OutputFileName), "wb");
    926     if (FfsFile == NULL) {
    927       Error (NULL, 0, 0001, "Error opening file", OutputFileName);
    928       goto Finish;
    929     }
    930     //
    931     // write header
    932     //
    933     fwrite (&FfsFileHeader, 1, HeaderSize, FfsFile);
    934     //
    935     // write data
    936     //
    937     if (FileBuffer != NULL) {
    938       fwrite (FileBuffer, 1, FileSize - HeaderSize, FfsFile);
    939     }
    940 
    941     fclose (FfsFile);
    942   }
    943 
    944 Finish:
    945   if (InputFileName != NULL) {
    946     free (InputFileName);
    947   }
    948   if (InputFileAlign != NULL) {
    949     free (InputFileAlign);
    950   }
    951   if (FileBuffer != NULL) {
    952     free (FileBuffer);
    953   }
    954   //
    955   // If any errors were reported via the standard error reporting
    956   // routines, then the status has been saved. Get the value and
    957   // return it to the caller.
    958   //
    959   VerboseMsg ("%s tool done with return code is 0x%x.", UTILITY_NAME, GetUtilityStatus ());
    960 
    961   return GetUtilityStatus ();
    962 }
    963