]> git.proxmox.com Git - mirror_edk2.git/blobdiff - BaseTools/Source/C/GenFfs/GenFfs.c
BaseTools: use set instead of list for a variable to be used with in
[mirror_edk2.git] / BaseTools / Source / C / GenFfs / GenFfs.c
index 765c0b27da73606908a9d50e8438a659cdb37ed2..eb40c30ea7b523152d3e22c3cdf49f5de93b089c 100644 (file)
@@ -1,6 +1,7 @@
-/**\r
+/** @file\r
+This file contains functions required to generate a Firmware File System file.\r
 \r
-Copyright (c) 2004 - 2014, Intel Corporation. All rights reserved.<BR>\r
+Copyright (c) 2004 - 2017, 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
@@ -9,17 +10,15 @@ http://opensource.org/licenses/bsd-license.php
 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
 \r
-Module Name:\r
-\r
-  GenFfs.c\r
-\r
-Abstract:\r
-\r
-  This file contains functions required to generate a Firmware File System\r
-  file.\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
@@ -27,10 +26,13 @@ Abstract:
 #include <Common/UefiBaseTypes.h>\r
 #include <Common/PiFirmwareFile.h>\r
 #include <IndustryStandard/PeImage.h>\r
+#include <Guid/FfsSectionAlignmentPadding.h>\r
 \r
 #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
@@ -50,22 +52,29 @@ 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
 Version (\r
@@ -119,7 +128,7 @@ Returns:
   //\r
   // Copyright declaration\r
   // \r
-  fprintf (stdout, "Copyright (c) 2007 - 2014, Intel Corporation. All rights reserved.\n\n");\r
+  fprintf (stdout, "Copyright (c) 2007 - 2017, Intel Corporation. All rights reserved.\n\n");\r
 \r
   //\r
   // Details Option\r
@@ -135,6 +144,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
@@ -145,13 +156,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
@@ -169,7 +183,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
@@ -238,13 +252,14 @@ Returns:
 STATIC\r
 EFI_STATUS\r
 GetSectionContents (\r
-  IN  CHAR8   **InputFileName,\r
-  IN  UINT32  *InputFileAlign,\r
-  IN  UINT32  InputFileNum,\r
-  OUT UINT8   *FileBuffer,\r
-  OUT UINT32  *BufferLength,\r
-  OUT UINT32  *MaxAlignment,\r
-  OUT UINT8   *PESectionNum\r
+  IN  CHAR8                     **InputFileName,\r
+  IN  UINT32                    *InputFileAlign,\r
+  IN  UINT32                    InputFileNum,\r
+  IN  EFI_FFS_FILE_ATTRIBUTES   FfsAttrib,\r
+  OUT UINT8                     *FileBuffer,\r
+  OUT UINT32                    *BufferLength,\r
+  OUT UINT32                    *MaxAlignment,\r
+  OUT UINT8                     *PESectionNum\r
   )\r
 /*++\r
         \r
@@ -278,22 +293,24 @@ Returns:
   EFI_BUFFER_TOO_SMALL FileBuffer is not enough to contain all file data.\r
 --*/\r
 {\r
-  UINT32                     Size;\r
-  UINT32                     Offset;\r
-  UINT32                     FileSize;\r
-  UINT32                     Index;\r
-  FILE                       *InFile;\r
-  EFI_COMMON_SECTION_HEADER  *SectHeader;\r
-  EFI_COMMON_SECTION_HEADER2 TempSectHeader;\r
-  EFI_TE_IMAGE_HEADER        TeHeader;\r
-  UINT32                     TeOffset;\r
-  EFI_GUID_DEFINED_SECTION   GuidSectHeader;\r
-  EFI_GUID_DEFINED_SECTION2  GuidSectHeader2;\r
-  UINT32                     HeaderSize;\r
-\r
-  Size          = 0;\r
-  Offset        = 0;\r
-  TeOffset      = 0;\r
+  UINT32                              Size;\r
+  UINT32                              Offset;\r
+  UINT32                              FileSize;\r
+  UINT32                              Index;\r
+  FILE                                *InFile;\r
+  EFI_FREEFORM_SUBTYPE_GUID_SECTION   *SectHeader;\r
+  EFI_COMMON_SECTION_HEADER2          TempSectHeader;\r
+  EFI_TE_IMAGE_HEADER                 TeHeader;\r
+  UINT32                              TeOffset;\r
+  EFI_GUID_DEFINED_SECTION            GuidSectHeader;\r
+  EFI_GUID_DEFINED_SECTION2           GuidSectHeader2;\r
+  UINT32                              HeaderSize;\r
+  UINT32                              MaxEncounteredAlignment;\r
+\r
+  Size                    = 0;\r
+  Offset                  = 0;\r
+  TeOffset                = 0;\r
+  MaxEncounteredAlignment = 1;\r
 \r
   //\r
   // Go through our array of file names and copy their contents\r
@@ -307,13 +324,6 @@ Returns:
       Size++;\r
     }\r
     \r
-    //\r
-    // Get the Max alignment of all input file datas\r
-    //\r
-    if (*MaxAlignment < InputFileAlign [Index]) {\r
-      *MaxAlignment = InputFileAlign [Index];\r
-    }\r
-\r
     // \r
     // Open file and read contents\r
     //\r
@@ -381,7 +391,7 @@ Returns:
     }\r
 \r
     //\r
-    // make sure section data meet its alignment requirement by adding one raw pad section.\r
+    // make sure section data meet its alignment requirement by adding one pad section.\r
     // But the different sections have the different section header. Necessary or not?\r
     // Based on section type to adjust offset? Todo\r
     //\r
@@ -394,11 +404,26 @@ Returns:
         // The maximal alignment is 64K, the raw section size must be less than 0xffffff\r
         //\r
         memset (FileBuffer + Size, 0, Offset);\r
-        SectHeader          = (EFI_COMMON_SECTION_HEADER *) (FileBuffer + Size);\r
-        SectHeader->Type    = EFI_SECTION_RAW;\r
-        SectHeader->Size[0] = (UINT8) (Offset & 0xff);\r
-        SectHeader->Size[1] = (UINT8) ((Offset & 0xff00) >> 8);\r
-        SectHeader->Size[2] = (UINT8) ((Offset & 0xff0000) >> 16);\r
+        SectHeader                        = (EFI_FREEFORM_SUBTYPE_GUID_SECTION *) (FileBuffer + Size);\r
+        SectHeader->CommonHeader.Size[0]  = (UINT8) (Offset & 0xff);\r
+        SectHeader->CommonHeader.Size[1]  = (UINT8) ((Offset & 0xff00) >> 8);\r
+        SectHeader->CommonHeader.Size[2]  = (UINT8) ((Offset & 0xff0000) >> 16);\r
+\r
+        //\r
+        // Only add a special reducible padding section if\r
+        // - this FFS has the FFS_ATTRIB_FIXED attribute,\r
+        // - none of the preceding sections have alignment requirements,\r
+        // - the size of the padding is sufficient for the\r
+        //   EFI_SECTION_FREEFORM_SUBTYPE_GUID header.\r
+        //\r
+        if ((FfsAttrib & FFS_ATTRIB_FIXED) != 0 &&\r
+            MaxEncounteredAlignment <= 1 &&\r
+            Offset >= sizeof (EFI_FREEFORM_SUBTYPE_GUID_SECTION)) {\r
+          SectHeader->CommonHeader.Type   = EFI_SECTION_FREEFORM_SUBTYPE_GUID;\r
+          SectHeader->SubTypeGuid         = mEfiFfsSectionAlignmentPaddingGuid;\r
+        } else {\r
+          SectHeader->CommonHeader.Type   = EFI_SECTION_RAW;\r
+        }\r
       }\r
       DebugMsg (NULL, 0, 9, "Pad raw section for section data alignment", \r
                 "Pad Raw section size is %u", (unsigned) Offset);\r
@@ -406,6 +431,13 @@ Returns:
       Size = Size + Offset;\r
     }\r
 \r
+    //\r
+    // Get the Max alignment of all input file datas\r
+    //\r
+    if (MaxEncounteredAlignment < InputFileAlign [Index]) {\r
+      MaxEncounteredAlignment = InputFileAlign [Index];\r
+    }\r
+\r
     //\r
     // Now read the contents of the file into the buffer\r
     // Buffer must be enough to contain the file content.\r
@@ -421,7 +453,9 @@ Returns:
     fclose (InFile);\r
     Size += FileSize;\r
   }\r
-  \r
+\r
+  *MaxAlignment = MaxEncounteredAlignment;\r
+\r
   //\r
   // Set the actual length of the data.\r
   //\r
@@ -434,6 +468,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
@@ -474,6 +605,13 @@ Returns:
   UINT64                  LogLevel;\r
   UINT8                   PeSectionNum;\r
   UINT32                  HeaderSize;\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
@@ -667,7 +805,27 @@ Returns:
       // 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
@@ -717,14 +875,14 @@ 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
   VerboseMsg ("%s tool start.", UTILITY_NAME);\r
 \r
   //\r
-  // Check the complete input paramters.\r
+  // Check the complete input parameters.\r
   //\r
   if (FfsFiletype == EFI_FV_FILETYPE_ALL) {\r
     Error (NULL, 0, 1001, "Missing option", "filetype");\r
@@ -782,6 +940,7 @@ Returns:
              InputFileName,\r
              InputFileAlign,\r
              InputFileNum,\r
+             FfsAttrib,\r
              FileBuffer,\r
              &FileSize,\r
              &MaxAlignment,\r
@@ -818,6 +977,7 @@ Returns:
                InputFileName,\r
                InputFileAlign,\r
                InputFileNum,\r
+               FfsAttrib,\r
                FileBuffer,\r
                &FileSize,\r
                &MaxAlignment,\r
@@ -828,6 +988,11 @@ Returns:
   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
   // Create Ffs file header.\r
@@ -867,7 +1032,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
@@ -898,22 +1068,26 @@ Returns:
   //\r
   // Open output file to write ffs data.\r
   //\r
-  remove(OutputFileName);\r
-  FfsFile = fopen (OutputFileName, "wb");\r
-  if (FfsFile == NULL) {\r
-    Error (NULL, 0, 0001, "Error opening file", OutputFileName);\r
-    goto Finish;\r
-  }\r
-  //\r
-  // write header\r
-  //\r
-  fwrite (&FfsFileHeader, 1, HeaderSize, FfsFile);\r
-  //\r
-  // write data\r
-  //\r
-  fwrite (FileBuffer, 1, FileSize - HeaderSize, FfsFile);\r
+  if (OutputFileName != NULL) {\r
+    remove(OutputFileName);\r
+    FfsFile = fopen (LongFilePath (OutputFileName), "wb");\r
+    if (FfsFile == NULL) {\r
+      Error (NULL, 0, 0001, "Error opening file", OutputFileName);\r
+      goto Finish;\r
+    }\r
+    //\r
+    // write header\r
+    //\r
+    fwrite (&FfsFileHeader, 1, HeaderSize, FfsFile);\r
+    //\r
+    // write data\r
+    //\r
+    if (FileBuffer != NULL) {\r
+      fwrite (FileBuffer, 1, FileSize - HeaderSize, FfsFile);\r
+    }\r
 \r
-  fclose (FfsFile);\r
+    fclose (FfsFile);\r
+  }\r
 \r
 Finish:\r
   if (InputFileName != NULL) {\r