]> git.proxmox.com Git - mirror_edk2.git/blobdiff - BaseTools/Source/C/GenFfs/GenFfs.c
BaseTools: Replace BSD License with BSD+Patent License
[mirror_edk2.git] / BaseTools / Source / C / GenFfs / GenFfs.c
index 78e5097fb487db9eefbaae062be7bc0ec63d8016..7a2a04c0ac9fd440624df78b463b36b713080975 100644 (file)
@@ -1,17 +1,18 @@
 /** @file\r
 This file contains functions required to generate a Firmware File System file.\r
 \r
-Copyright (c) 2004 - 2016, Intel Corporation. All rights reserved.<BR>\r
-This program and the accompanying materials                          \r
-are licensed and made available under the terms and conditions of the BSD License         \r
-which accompanies this distribution.  The full text of the license may be found at        \r
-http://opensource.org/licenses/bsd-license.php                                            \r
-                                                                                          \r
-THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,                     \r
-WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.             \r
+Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>\r
+SPDX-License-Identifier: BSD-2-Clause-Patent\r
 \r
 **/\r
 \r
+#ifndef __GNUC__\r
+#include <windows.h>\r
+#include <io.h>\r
+#include <sys/types.h>\r
+#include <sys/stat.h>\r
+#endif\r
+\r
 #include <stdio.h>\r
 #include <stdlib.h>\r
 #include <string.h>\r
@@ -24,6 +25,8 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 #include "CommonLib.h"\r
 #include "ParseInf.h"\r
 #include "EfiUtilityMsgs.h"\r
+#include "FvLib.h"\r
+#include "PeCoffLib.h"\r
 \r
 #define UTILITY_NAME            "GenFfs"\r
 #define UTILITY_MAJOR_VERSION   0\r
@@ -43,26 +46,31 @@ STATIC CHAR8 *mFfsFileType[] = {
   "EFI_FV_FILETYPE_SMM",                  // 0x0A\r
   "EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE",// 0x0B\r
   "EFI_FV_FILETYPE_COMBINED_SMM_DXE",     // 0x0C\r
-  "EFI_FV_FILETYPE_SMM_CORE"              // 0x0D\r
- };\r
+  "EFI_FV_FILETYPE_SMM_CORE",             // 0x0D\r
+  "EFI_FV_FILETYPE_MM_STANDALONE",        // 0x0E\r
+  "EFI_FV_FILETYPE_MM_CORE_STANDALONE"    // 0x0F\r
+};\r
 \r
 STATIC CHAR8 *mAlignName[] = {\r
   "1", "2", "4", "8", "16", "32", "64", "128", "256", "512",\r
-  "1K", "2K", "4K", "8K", "16K", "32K", "64K"\r
+  "1K", "2K", "4K", "8K", "16K", "32K", "64K", "128K", "256K",\r
+  "512K", "1M", "2M", "4M", "8M", "16M"\r
  };\r
 \r
 STATIC CHAR8 *mFfsValidAlignName[] = {\r
-  "8", "16", "128", "512", "1K", "4K", "32K", "64K"\r
+  "8", "16", "128", "512", "1K", "4K", "32K", "64K", "128K","256K",\r
+  "512K", "1M", "2M", "4M", "8M", "16M"\r
  };\r
 \r
-STATIC UINT32 mFfsValidAlign[] = {0, 8, 16, 128, 512, 1024, 4096, 32768, 65536};\r
+STATIC UINT32 mFfsValidAlign[] = {0, 8, 16, 128, 512, 1024, 4096, 32768, 65536, 131072, 262144,\r
+                                  524288, 1048576, 2097152, 4194304, 8388608, 16777216};\r
 \r
 STATIC EFI_GUID mZeroGuid = {0};\r
 \r
 STATIC EFI_GUID mEfiFfsSectionAlignmentPaddingGuid = EFI_FFS_SECTION_ALIGNMENT_PADDING_GUID;\r
 \r
 STATIC\r
-VOID \r
+VOID\r
 Version (\r
   VOID\r
   )\r
@@ -75,12 +83,12 @@ Routine Description:
 Arguments:\r
 \r
   None\r
-  \r
+\r
 Returns:\r
 \r
   None\r
-  \r
---*/ \r
+\r
+--*/\r
 {\r
   fprintf (stdout, "%s Version %d.%d %s \n", UTILITY_NAME, UTILITY_MAJOR_VERSION, UTILITY_MINOR_VERSION, __BUILD_VERSION);\r
 }\r
@@ -110,11 +118,11 @@ Returns:
   // Summary usage\r
   //\r
   fprintf (stdout, "\nUsage: %s [options]\n\n", UTILITY_NAME);\r
-  \r
+\r
   //\r
   // Copyright declaration\r
-  // \r
-  fprintf (stdout, "Copyright (c) 2007 - 2014, Intel Corporation. All rights reserved.\n\n");\r
+  //\r
+  fprintf (stdout, "Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.\n\n");\r
 \r
   //\r
   // Details Option\r
@@ -130,6 +138,8 @@ Returns:
                         EFI_FV_FILETYPE_DRIVER, EFI_FV_FILETYPE_APPLICATION,\n\\r
                         EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER,\n\\r
                         EFI_FV_FILETYPE_SMM, EFI_FV_FILETYPE_SMM_CORE,\n\\r
+                        EFI_FV_FILETYPE_MM_STANDALONE,\n\\r
+                        EFI_FV_FILETYPE_MM_CORE_STANDALONE,\n\\r
                         EFI_FV_FILETYPE_COMBINED_SMM_DXE, \n\\r
                         EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE.\n");\r
   fprintf (stdout, "  -g FileGuid, --fileguid FileGuid\n\\r
@@ -140,13 +150,16 @@ Returns:
   fprintf (stdout, "  -s, --checksum        Indicates to calculate file checksum.\n");\r
   fprintf (stdout, "  -a FileAlign, --align FileAlign\n\\r
                         FileAlign points to file alignment, which only support\n\\r
-                        the following align: 1,2,4,8,16,128,512,1K,4K,32K,64K\n");\r
+                        the following align: 1,2,4,8,16,128,512,1K,4K,32K,64K\n\\r
+                        128K,256K,512K,1M,2M,4M,8M,16M\n");\r
   fprintf (stdout, "  -i SectionFile, --sectionfile SectionFile\n\\r
                         Section file will be contained in this FFS file.\n");\r
   fprintf (stdout, "  -n SectionAlign, --sectionalign SectionAlign\n\\r
                         SectionAlign points to section alignment, which support\n\\r
-                        the alignment scope 1~64K. It is specified together\n\\r
-                        with sectionfile to point its alignment in FFS file.\n");\r
+                        the alignment scope 0~16M. If SectionAlign is specified\n\\r
+                        as 0, tool get alignment value from SectionFile. It is\n\\r
+                        specified together with sectionfile to point its\n\\r
+                        alignment in FFS file.\n");\r
   fprintf (stdout, "  -v, --verbose         Turn on verbose output with informational messages.\n");\r
   fprintf (stdout, "  -q, --quiet           Disable all messages except key message and fatal error\n");\r
   fprintf (stdout, "  -d, --debug level     Enable debug messages, at input debug level.\n");\r
@@ -164,7 +177,7 @@ StringtoAlignment (
 \r
 Routine Description:\r
 \r
-  Converts Align String to align value (1~64K). \r
+  Converts Align String to align value (1~16M).\r
 \r
 Arguments:\r
 \r
@@ -217,7 +230,7 @@ Returns:
 --*/\r
 {\r
   UINT8 Index = 0;\r
-  \r
+\r
   if (String == NULL) {\r
     return EFI_FV_FILETYPE_ALL;\r
   }\r
@@ -243,31 +256,31 @@ GetSectionContents (
   OUT UINT8                     *PESectionNum\r
   )\r
 /*++\r
-        \r
+\r
 Routine Description:\r
-           \r
+\r
   Get the contents of all section files specified in InputFileName\r
   into FileBuffer.\r
-            \r
+\r
 Arguments:\r
-               \r
+\r
   InputFileName  - Name of the input file.\r
-                \r
+\r
   InputFileAlign - Alignment required by the input file data.\r
 \r
   InputFileNum   - Number of input files. Should be at least 1.\r
 \r
   FileBuffer     - Output buffer to contain data\r
 \r
-  BufferLength   - On input, this is size of the FileBuffer. \r
+  BufferLength   - On input, this is size of the FileBuffer.\r
                    On output, this is the actual length of the data.\r
 \r
   MaxAlignment   - The max alignment required by all the input file datas.\r
-  \r
+\r
   PeSectionNum   - Calculate the number of Pe/Te Section in this FFS file.\r
 \r
 Returns:\r
-                       \r
+\r
   EFI_SUCCESS on successful return\r
   EFI_INVALID_PARAMETER if InputFileNum is less than 1 or BufferLength point is NULL.\r
   EFI_ABORTED if unable to open input file.\r
@@ -304,8 +317,8 @@ Returns:
     while ((Size & 0x03) != 0) {\r
       Size++;\r
     }\r
-    \r
-    // \r
+\r
+    //\r
     // Open file and read contents\r
     //\r
     InFile = fopen (LongFilePath (InputFileName[Index]), "rb");\r
@@ -317,8 +330,8 @@ Returns:
     fseek (InFile, 0, SEEK_END);\r
     FileSize = ftell (InFile);\r
     fseek (InFile, 0, SEEK_SET);\r
-    DebugMsg (NULL, 0, 9, "Input section files", \r
-              "the input section name is %s and the size is %u bytes", InputFileName[Index], (unsigned) FileSize); \r
+    DebugMsg (NULL, 0, 9, "Input section files",\r
+              "the input section name is %s and the size is %u bytes", InputFileName[Index], (unsigned) FileSize);\r
 \r
     //\r
     // Check this section is Te/Pe section, and Calculate the numbers of Te/Pe section.\r
@@ -352,10 +365,10 @@ Returns:
         }\r
       }\r
       (*PESectionNum) ++;\r
-    } else if (TempSectHeader.Type == EFI_SECTION_COMPRESSION || \r
+    } else if (TempSectHeader.Type == EFI_SECTION_COMPRESSION ||\r
                TempSectHeader.Type == EFI_SECTION_FIRMWARE_VOLUME_IMAGE) {\r
       //\r
-      // for the encapsulated section, assume it contains Pe/Te section \r
+      // for the encapsulated section, assume it contains Pe/Te section\r
       //\r
       (*PESectionNum) ++;\r
     }\r
@@ -379,7 +392,7 @@ Returns:
     if ((InputFileAlign [Index] != 0) && (((Size + HeaderSize + TeOffset) % InputFileAlign [Index]) != 0)) {\r
       Offset = (Size + sizeof (EFI_COMMON_SECTION_HEADER) + HeaderSize + TeOffset + InputFileAlign [Index] - 1) & ~(InputFileAlign [Index] - 1);\r
       Offset = Offset - Size - HeaderSize - TeOffset;\r
-       \r
+\r
       if (FileBuffer != NULL && ((Size + Offset) < *BufferLength)) {\r
         //\r
         // The maximal alignment is 64K, the raw section size must be less than 0xffffff\r
@@ -406,7 +419,7 @@ Returns:
           SectHeader->CommonHeader.Type   = EFI_SECTION_RAW;\r
         }\r
       }\r
-      DebugMsg (NULL, 0, 9, "Pad raw section for section data alignment", \r
+      DebugMsg (NULL, 0, 9, "Pad raw section for section data alignment",\r
                 "Pad Raw section size is %u", (unsigned) Offset);\r
 \r
       Size = Size + Offset;\r
@@ -449,6 +462,103 @@ Returns:
   }\r
 }\r
 \r
+EFI_STATUS\r
+FfsRebaseImageRead (\r
+    IN      VOID    *FileHandle,\r
+    IN      UINTN   FileOffset,\r
+    IN OUT  UINT32  *ReadSize,\r
+    OUT     VOID    *Buffer\r
+    )\r
+  /*++\r
+\r
+    Routine Description:\r
+\r
+    Support routine for the PE/COFF Loader that reads a buffer from a PE/COFF file\r
+\r
+    Arguments:\r
+\r
+   FileHandle - The handle to the PE/COFF file\r
+\r
+   FileOffset - The offset, in bytes, into the file to read\r
+\r
+   ReadSize   - The number of bytes to read from the file starting at FileOffset\r
+\r
+   Buffer     - A pointer to the buffer to read the data into.\r
+\r
+   Returns:\r
+\r
+   EFI_SUCCESS - ReadSize bytes of data were read into Buffer from the PE/COFF file starting at FileOffset\r
+\r
+   --*/\r
+{\r
+  CHAR8   *Destination8;\r
+  CHAR8   *Source8;\r
+  UINT32  Length;\r
+\r
+  Destination8  = Buffer;\r
+  Source8       = (CHAR8 *) ((UINTN) FileHandle + FileOffset);\r
+  Length        = *ReadSize;\r
+  while (Length--) {\r
+    *(Destination8++) = *(Source8++);\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+STATIC\r
+EFI_STATUS\r
+GetAlignmentFromFile(char *InFile, UINT32 *Alignment)\r
+  /*++\r
+    InFile is input file for getting alignment\r
+    return the alignment\r
+    --*/\r
+{\r
+  FILE                           *InFileHandle;\r
+  UINT8                          *PeFileBuffer;\r
+  UINTN                          PeFileSize;\r
+  UINT32                         CurSecHdrSize;\r
+  PE_COFF_LOADER_IMAGE_CONTEXT   ImageContext;\r
+  EFI_COMMON_SECTION_HEADER      *CommonHeader;\r
+  EFI_STATUS                     Status;\r
+\r
+  InFileHandle        = NULL;\r
+  PeFileBuffer        = NULL;\r
+  *Alignment          = 0;\r
+\r
+  memset (&ImageContext, 0, sizeof (ImageContext));\r
+\r
+  InFileHandle = fopen(LongFilePath(InFile), "rb");\r
+  if (InFileHandle == NULL){\r
+    Error (NULL, 0, 0001, "Error opening file", InFile);\r
+    return EFI_ABORTED;\r
+  }\r
+  PeFileSize = _filelength (fileno(InFileHandle));\r
+  PeFileBuffer = (UINT8 *) malloc (PeFileSize);\r
+  if (PeFileBuffer == NULL) {\r
+    fclose (InFileHandle);\r
+    Error(NULL, 0, 4001, "Resource", "memory cannot be allocated  of %s", InFileHandle);\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+  fread (PeFileBuffer, sizeof (UINT8), PeFileSize, InFileHandle);\r
+  fclose (InFileHandle);\r
+  CommonHeader = (EFI_COMMON_SECTION_HEADER *) PeFileBuffer;\r
+  CurSecHdrSize = GetSectionHeaderLength(CommonHeader);\r
+  ImageContext.Handle = (VOID *) ((UINTN)PeFileBuffer + CurSecHdrSize);\r
+  ImageContext.ImageRead = (PE_COFF_LOADER_READ_FILE)FfsRebaseImageRead;\r
+  Status               = PeCoffLoaderGetImageInfo(&ImageContext);\r
+  if (EFI_ERROR (Status)) {\r
+    Error (NULL, 0, 3000, "Invalid PeImage", "The input file is %s and return status is %x", InFile, (int) Status);\r
+    return Status;\r
+   }\r
+  *Alignment = ImageContext.SectionAlignment;\r
+  // Free the allocated memory resource\r
+  if (PeFileBuffer != NULL) {\r
+    free (PeFileBuffer);\r
+    PeFileBuffer = NULL;\r
+  }\r
+  return EFI_SUCCESS;\r
+}\r
+\r
 int\r
 main (\r
   int   argc,\r
@@ -489,13 +599,20 @@ Returns:
   UINT64                  LogLevel;\r
   UINT8                   PeSectionNum;\r
   UINT32                  HeaderSize;\r
-  \r
+  UINT32                  Alignment;\r
+  //\r
+  // Workaround for static code checkers.\r
+  // Ensures the size of 'AlignmentBuffer' can hold all the digits of an\r
+  // unsigned 32-bit integer plus the size unit character.\r
+  //\r
+  CHAR8                   AlignmentBuffer[16];\r
+\r
   //\r
   // Init local variables\r
   //\r
   LogLevel       = 0;\r
   Index          = 0;\r
-  FfsAttrib      = 0;  \r
+  FfsAttrib      = 0;\r
   FfsAlign       = 0;\r
   FfsFiletype    = EFI_FV_FILETYPE_ALL;\r
   OutputFileName = NULL;\r
@@ -526,12 +643,12 @@ Returns:
   if ((stricmp (argv[0], "-h") == 0) || (stricmp (argv[0], "--help") == 0)) {\r
     Version ();\r
     Usage ();\r
-    return STATUS_SUCCESS;    \r
+    return STATUS_SUCCESS;\r
   }\r
 \r
   if (stricmp (argv[0], "--version") == 0) {\r
     Version ();\r
-    return STATUS_SUCCESS;    \r
+    return STATUS_SUCCESS;\r
   }\r
 \r
   while (argc > 0) {\r
@@ -547,7 +664,7 @@ Returns:
       }\r
       argc -= 2;\r
       argv += 2;\r
-      continue; \r
+      continue;\r
     }\r
 \r
     if ((stricmp (argv[0], "-o") == 0) || (stricmp (argv[0], "--outputfile") == 0)) {\r
@@ -558,7 +675,7 @@ Returns:
       OutputFileName = argv[1];\r
       argc -= 2;\r
       argv += 2;\r
-      continue; \r
+      continue;\r
     }\r
 \r
     if ((stricmp (argv[0], "-g") == 0) || (stricmp (argv[0], "--fileguid") == 0)) {\r
@@ -632,7 +749,7 @@ Returns:
           return STATUS_ERROR;\r
         }\r
         memset (InputFileName, 0, (MAXIMUM_INPUT_FILE_NUM * sizeof (CHAR8 *)));\r
-        \r
+\r
         InputFileAlign = (UINT32 *) malloc (MAXIMUM_INPUT_FILE_NUM * sizeof (UINT32));\r
         if (InputFileAlign == NULL) {\r
           Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!");\r
@@ -648,7 +765,7 @@ Returns:
                                     InputFileName,\r
                                     (InputFileNum + MAXIMUM_INPUT_FILE_NUM) * sizeof (CHAR8 *)\r
                                     );\r
-  \r
+\r
         if (InputFileName == NULL) {\r
           Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!");\r
           free (InputFileAlign);\r
@@ -660,7 +777,7 @@ Returns:
                                     InputFileAlign,\r
                                     (InputFileNum + MAXIMUM_INPUT_FILE_NUM) * sizeof (UINT32)\r
                                     );\r
-  \r
+\r
         if (InputFileAlign == NULL) {\r
           Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!");\r
           free (InputFileName);\r
@@ -668,21 +785,41 @@ Returns:
         }\r
         memset (&(InputFileAlign[InputFileNum]), 0, (MAXIMUM_INPUT_FILE_NUM * sizeof (UINT32)));\r
       }\r
-  \r
+\r
       InputFileName[InputFileNum] = argv[1];\r
       argc -= 2;\r
       argv += 2;\r
 \r
       if (argc <= 0) {\r
-             InputFileNum ++;\r
+        InputFileNum ++;\r
         break;\r
       }\r
-      \r
+\r
       //\r
       // Section File alignment requirement\r
       //\r
       if ((stricmp (argv[0], "-n") == 0) || (stricmp (argv[0], "--sectionalign") == 0)) {\r
-        Status = StringtoAlignment (argv[1], &(InputFileAlign[InputFileNum]));\r
+        if ((argv[1] != NULL) && (stricmp("0", argv[1]) == 0)) {\r
+          Status = GetAlignmentFromFile(InputFileName[InputFileNum], &Alignment);\r
+          if (EFI_ERROR(Status)) {\r
+            Error (NULL, 0, 1003, "Fail to get Alignment from %s", InputFileName[InputFileNum]);\r
+            goto Finish;\r
+          }\r
+          if (Alignment < 0x400){\r
+            sprintf (AlignmentBuffer, "%d", Alignment);\r
+          }\r
+          else if (Alignment >= 0x400) {\r
+            if (Alignment >= 0x100000) {\r
+              sprintf (AlignmentBuffer, "%dM", Alignment/0x100000);\r
+            } else {\r
+              sprintf (AlignmentBuffer, "%dK", Alignment/0x400);\r
+            }\r
+          }\r
+          Status = StringtoAlignment (AlignmentBuffer, &(InputFileAlign[InputFileNum]));\r
+        }\r
+        else {\r
+          Status = StringtoAlignment (argv[1], &(InputFileAlign[InputFileNum]));\r
+        }\r
         if (EFI_ERROR (Status)) {\r
           Error (NULL, 0, 1003, "Invalid option value", "%s = %s", argv[0], argv[1]);\r
           goto Finish;\r
@@ -691,7 +828,7 @@ Returns:
         argv += 2;\r
       }\r
       InputFileNum ++;\r
-      continue; \r
+      continue;\r
     }\r
 \r
     if ((stricmp (argv[0], "-n") == 0) || (stricmp (argv[0], "--sectionalign") == 0)) {\r
@@ -732,7 +869,7 @@ Returns:
       continue;\r
     }\r
 \r
-    Error (NULL, 0, 1000, "Unknown option", argv[0]);\r
+    Error (NULL, 0, 1000, "Unknown option", "%s", argv[0]);\r
     goto Finish;\r
   }\r
 \r
@@ -743,25 +880,25 @@ Returns:
   //\r
   if (FfsFiletype == EFI_FV_FILETYPE_ALL) {\r
     Error (NULL, 0, 1001, "Missing option", "filetype");\r
-    goto Finish;      \r
+    goto Finish;\r
   }\r
 \r
   if (CompareGuid (&FileGuid, &mZeroGuid) == 0) {\r
     Error (NULL, 0, 1001, "Missing option", "fileguid");\r
-    goto Finish;    \r
+    goto Finish;\r
   }\r
 \r
   if (InputFileNum == 0) {\r
     Error (NULL, 0, 1001, "Missing option", "Input files");\r
     goto Finish;\r
   }\r
-  \r
+\r
   //\r
   // Output input parameter information\r
   //\r
   VerboseMsg ("Fv File type is %s", mFfsFileType [FfsFiletype]);\r
   VerboseMsg ("Output file name is %s", OutputFileName);\r
-  VerboseMsg ("FFS File Guid is %08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X", \r
+  VerboseMsg ("FFS File Guid is %08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X",\r
                 (unsigned) FileGuid.Data1,\r
                 FileGuid.Data2,\r
                 FileGuid.Data3,\r
@@ -789,10 +926,10 @@ Returns:
     }\r
     VerboseMsg ("the %dth input section name is %s and section alignment is %u", Index, InputFileName[Index], (unsigned) InputFileAlign[Index]);\r
   }\r
-  \r
+\r
   //\r
   // Calculate the size of all input section files.\r
-  //  \r
+  //\r
   Status = GetSectionContents (\r
              InputFileName,\r
              InputFileAlign,\r
@@ -803,20 +940,20 @@ Returns:
              &MaxAlignment,\r
              &PeSectionNum\r
              );\r
-  \r
-  if ((FfsFiletype == EFI_FV_FILETYPE_SECURITY_CORE || \r
+\r
+  if ((FfsFiletype == EFI_FV_FILETYPE_SECURITY_CORE ||\r
       FfsFiletype == EFI_FV_FILETYPE_PEI_CORE ||\r
       FfsFiletype == EFI_FV_FILETYPE_DXE_CORE) && (PeSectionNum != 1)) {\r
     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);\r
     goto Finish;\r
   }\r
-  \r
+\r
   if ((FfsFiletype == EFI_FV_FILETYPE_PEIM ||\r
       FfsFiletype == EFI_FV_FILETYPE_DRIVER ||\r
       FfsFiletype == EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER ||\r
       FfsFiletype == EFI_FV_FILETYPE_APPLICATION) && (PeSectionNum < 1)) {\r
     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]);\r
-    goto Finish;   \r
+    goto Finish;\r
   }\r
 \r
   if (Status == EFI_BUFFER_TOO_SMALL) {\r
@@ -826,7 +963,7 @@ Returns:
       goto Finish;\r
     }\r
     memset (FileBuffer, 0, FileSize);\r
-    \r
+\r
     //\r
     // read all input file contents into a buffer\r
     //\r
@@ -842,10 +979,15 @@ Returns:
                );\r
   }\r
 \r
-  if (EFI_ERROR (Status) || (FileBuffer == NULL)) {\r
+  if (EFI_ERROR (Status)) {\r
+    goto Finish;\r
+  }\r
+\r
+  if (FileBuffer == NULL && FileSize != 0) {\r
+    Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!");\r
     goto Finish;\r
   }\r
-  \r
+\r
   //\r
   // Create Ffs file header.\r
   //\r
@@ -853,9 +995,9 @@ Returns:
   memcpy (&FfsFileHeader.Name, &FileGuid, sizeof (EFI_GUID));\r
   FfsFileHeader.Type       = FfsFiletype;\r
   //\r
-  // Update FFS Alignment based on the max alignment required by input section files \r
+  // Update FFS Alignment based on the max alignment required by input section files\r
   //\r
-  VerboseMsg ("the max alignment of all input sections is %u", (unsigned) MaxAlignment); \r
+  VerboseMsg ("the max alignment of all input sections is %u", (unsigned) MaxAlignment);\r
   for (Index = 0; Index < sizeof (mFfsValidAlign) / sizeof (UINT32) - 1; Index ++) {\r
     if ((MaxAlignment > mFfsValidAlign [Index]) && (MaxAlignment <= mFfsValidAlign [Index + 1])) {\r
       break;\r
@@ -864,8 +1006,8 @@ Returns:
   if (FfsAlign < Index) {\r
     FfsAlign = Index;\r
   }\r
-  VerboseMsg ("the alignment of the generated FFS file is %u", (unsigned) mFfsValidAlign [FfsAlign + 1]);  \r
-  \r
+  VerboseMsg ("the alignment of the generated FFS file is %u", (unsigned) mFfsValidAlign [FfsAlign + 1]);\r
+\r
   //\r
   // Now FileSize includes the EFI_FFS_FILE_HEADER\r
   //\r
@@ -884,7 +1026,12 @@ Returns:
   }\r
   VerboseMsg ("the size of the generated FFS file is %u bytes", (unsigned) FileSize);\r
 \r
-  FfsFileHeader.Attributes = (EFI_FFS_FILE_ATTRIBUTES) (FfsAttrib | (FfsAlign << 3));\r
+  //FfsAlign larger than 7, set FFS_ATTRIB_DATA_ALIGNMENT2\r
+  if (FfsAlign < 8) {\r
+    FfsFileHeader.Attributes = (EFI_FFS_FILE_ATTRIBUTES) (FfsAttrib | (FfsAlign << 3));\r
+  } else {\r
+    FfsFileHeader.Attributes = (EFI_FFS_FILE_ATTRIBUTES) (FfsAttrib | ((FfsAlign & 0x7) << 3) | FFS_ATTRIB_DATA_ALIGNMENT2);\r
+  }\r
 \r
   //\r
   // Fill in checksums and state, these must be zero for checksumming\r
@@ -903,15 +1050,15 @@ Returns:
     // Ffs header checksum = zero, so only need to calculate ffs body.\r
     //\r
     FfsFileHeader.IntegrityCheck.Checksum.File = CalculateChecksum8 (\r
-                                                   FileBuffer, \r
+                                                   FileBuffer,\r
                                                    FileSize - HeaderSize\r
-                                                   );    \r
+                                                   );\r
   } else {\r
     FfsFileHeader.IntegrityCheck.Checksum.File = FFS_FIXED_CHECKSUM;\r
   }\r
 \r
   FfsFileHeader.State = EFI_FILE_HEADER_CONSTRUCTION | EFI_FILE_HEADER_VALID | EFI_FILE_DATA_VALID;\r
-  \r
+\r
   //\r
   // Open output file to write ffs data.\r
   //\r
@@ -929,7 +1076,9 @@ Returns:
     //\r
     // write data\r
     //\r
-    fwrite (FileBuffer, 1, FileSize - HeaderSize, FfsFile);\r
+    if (FileBuffer != NULL) {\r
+      fwrite (FileBuffer, 1, FileSize - HeaderSize, FfsFile);\r
+    }\r
 \r
     fclose (FfsFile);\r
   }\r