]> git.proxmox.com Git - mirror_edk2.git/blobdiff - BaseTools/Source/C/GenFfs/GenFfs.c
BaseTools/GenFfs: add FFS file types for MM modules.
[mirror_edk2.git] / BaseTools / Source / C / GenFfs / GenFfs.c
index 12a3b2f18cb2eeb7f5b4856832346b64f33333a6..91632a90620b3e268a8e7b8250bf7f86ec9df148 100644 (file)
@@ -1,7 +1,8 @@
-/**\r
+/** @file\r
+This file contains functions required to generate a Firmware File System file.\r
 \r
-Copyright (c) 2004-2008, Intel Corporation                                                         \r
-All rights reserved. This program and the accompanying materials                          \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
@@ -9,15 +10,6 @@ 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
 #include <stdio.h>\r
@@ -27,6 +19,7 @@ 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
@@ -50,8 +43,10 @@ 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
@@ -66,6 +61,8 @@ STATIC UINT32 mFfsValidAlign[] = {0, 8, 16, 128, 512, 1024, 4096, 32768, 65536};
 \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
@@ -87,7 +84,7 @@ Returns:
   \r
 --*/ \r
 {\r
-  fprintf (stdout, "%s Version %d.%d\n", UTILITY_NAME, UTILITY_MAJOR_VERSION, UTILITY_MINOR_VERSION);\r
+  fprintf (stdout, "%s Version %d.%d %s \n", UTILITY_NAME, UTILITY_MAJOR_VERSION, UTILITY_MINOR_VERSION, __BUILD_VERSION);\r
 }\r
 \r
 STATIC\r
@@ -119,7 +116,7 @@ Returns:
   //\r
   // Copyright declaration\r
   // \r
-  fprintf (stdout, "Copyright (c) 2007, Intel Corporation. All rights reserved.\n\n");\r
+  fprintf (stdout, "Copyright (c) 2007 - 2014, Intel Corporation. All rights reserved.\n\n");\r
 \r
   //\r
   // Details Option\r
@@ -134,6 +131,10 @@ Returns:
                         EFI_FV_FILETYPE_PEI_CORE, EFI_FV_FILETYPE_DXE_CORE,\n\\r
                         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
                         FileGuid is one module guid.\n\\r
@@ -236,13 +237,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
@@ -276,19 +278,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_HEADER  TempSectHeader;\r
-  EFI_TE_IMAGE_HEADER        TeHeader;\r
-  UINT32                     TeOffset;\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
@@ -302,17 +309,10 @@ 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
-    InFile = fopen (InputFileName[Index], "rb");\r
+    InFile = fopen (LongFilePath (InputFileName[Index]), "rb");\r
     if (InFile == NULL) {\r
       Error (NULL, 0, 0001, "Error opening file", InputFileName[Index]);\r
       return EFI_ABORTED;\r
@@ -328,7 +328,12 @@ Returns:
     // Check this section is Te/Pe section, and Calculate the numbers of Te/Pe section.\r
     //\r
     TeOffset = 0;\r
-    fread (&TempSectHeader, 1, sizeof (TempSectHeader), InFile);\r
+    if (FileSize >= MAX_FFS_SIZE) {\r
+      HeaderSize = sizeof (EFI_COMMON_SECTION_HEADER2);\r
+    } else {\r
+      HeaderSize = sizeof (EFI_COMMON_SECTION_HEADER);\r
+    }\r
+    fread (&TempSectHeader, 1, HeaderSize, InFile);\r
     if (TempSectHeader.Type == EFI_SECTION_TE) {\r
       (*PESectionNum) ++;\r
       fread (&TeHeader, 1, sizeof (TeHeader), InFile);\r
@@ -337,8 +342,21 @@ Returns:
       }\r
     } else if (TempSectHeader.Type == EFI_SECTION_PE32) {\r
       (*PESectionNum) ++;\r
+    } else if (TempSectHeader.Type == EFI_SECTION_GUID_DEFINED) {\r
+      fseek (InFile, 0, SEEK_SET);\r
+      if (FileSize >= MAX_SECTION_SIZE) {\r
+        fread (&GuidSectHeader2, 1, sizeof (GuidSectHeader2), InFile);\r
+        if ((GuidSectHeader2.Attributes & EFI_GUIDED_SECTION_PROCESSING_REQUIRED) == 0) {\r
+          HeaderSize = GuidSectHeader2.DataOffset;\r
+        }\r
+      } else {\r
+        fread (&GuidSectHeader, 1, sizeof (GuidSectHeader), InFile);\r
+        if ((GuidSectHeader.Attributes & EFI_GUIDED_SECTION_PROCESSING_REQUIRED) == 0) {\r
+          HeaderSize = GuidSectHeader.DataOffset;\r
+        }\r
+      }\r
+      (*PESectionNum) ++;\r
     } else if (TempSectHeader.Type == EFI_SECTION_COMPRESSION || \r
-               TempSectHeader.Type == EFI_SECTION_GUID_DEFINED ||\r
                TempSectHeader.Type == EFI_SECTION_FIRMWARE_VOLUME_IMAGE) {\r
       //\r
       // for the encapsulated section, assume it contains Pe/Te section \r
@@ -356,22 +374,41 @@ Returns:
       TeOffset = InputFileAlign [Index] - (TeOffset % InputFileAlign [Index]);\r
       TeOffset = TeOffset % InputFileAlign [Index];\r
     }\r
-     \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
-    if ((InputFileAlign [Index] != 0) && (((Size + sizeof (EFI_COMMON_SECTION_HEADER) + TeOffset) % InputFileAlign [Index]) != 0)) {\r
-      Offset = (Size + 2 * sizeof (EFI_COMMON_SECTION_HEADER) + TeOffset + InputFileAlign [Index] - 1) & ~(InputFileAlign [Index] - 1);\r
-      Offset = Offset - Size - sizeof (EFI_COMMON_SECTION_HEADER) - TeOffset;\r
+    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
       if (FileBuffer != NULL && ((Size + Offset) < *BufferLength)) {\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
+        //\r
+        // The maximal alignment is 64K, the raw section size must be less than 0xffffff\r
+        //\r
+        memset (FileBuffer + Size, 0, Offset);\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
@@ -379,6 +416,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
@@ -394,7 +438,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
@@ -441,11 +487,12 @@ Returns:
   UINT8                   *FileBuffer;\r
   UINT32                  FileSize;\r
   UINT32                  MaxAlignment;\r
-  EFI_FFS_FILE_HEADER     FfsFileHeader;\r
+  EFI_FFS_FILE_HEADER2    FfsFileHeader;\r
   FILE                    *FfsFile;\r
   UINT32                  Index;\r
   UINT64                  LogLevel;\r
   UINT8                   PeSectionNum;\r
+  UINT32                  HeaderSize;\r
   \r
   //\r
   // Init local variables\r
@@ -696,7 +743,7 @@ Returns:
   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
@@ -754,6 +801,7 @@ Returns:
              InputFileName,\r
              InputFileAlign,\r
              InputFileNum,\r
+             FfsAttrib,\r
              FileBuffer,\r
              &FileSize,\r
              &MaxAlignment,\r
@@ -790,6 +838,7 @@ Returns:
                InputFileName,\r
                InputFileAlign,\r
                InputFileNum,\r
+               FfsAttrib,\r
                FileBuffer,\r
                &FileSize,\r
                &MaxAlignment,\r
@@ -800,11 +849,16 @@ 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
   //\r
-  memset (&FfsFileHeader, 0, sizeof (EFI_FFS_FILE_HEADER));\r
+  memset (&FfsFileHeader, 0, sizeof (EFI_FFS_FILE_HEADER2));\r
   memcpy (&FfsFileHeader.Name, &FileGuid, sizeof (EFI_GUID));\r
   FfsFileHeader.Type       = FfsFiletype;\r
   //\r
@@ -820,16 +874,27 @@ Returns:
     FfsAlign = Index;\r
   }\r
   VerboseMsg ("the alignment of the generated FFS file is %u", (unsigned) mFfsValidAlign [FfsAlign + 1]);  \r
-  FfsFileHeader.Attributes = (EFI_FFS_FILE_ATTRIBUTES) (FfsAttrib | (FfsAlign << 3));\r
   \r
   //\r
   // Now FileSize includes the EFI_FFS_FILE_HEADER\r
   //\r
-  FileSize += sizeof (EFI_FFS_FILE_HEADER);\r
+  if (FileSize + sizeof (EFI_FFS_FILE_HEADER) >= MAX_FFS_SIZE) {\r
+    HeaderSize = sizeof (EFI_FFS_FILE_HEADER2);\r
+    FileSize += sizeof (EFI_FFS_FILE_HEADER2);\r
+    FfsFileHeader.ExtendedSize = FileSize;\r
+    memset(FfsFileHeader.Size, 0, sizeof (UINT8) * 3);\r
+    FfsAttrib |= FFS_ATTRIB_LARGE_FILE;\r
+  } else {\r
+    HeaderSize = sizeof (EFI_FFS_FILE_HEADER);\r
+    FileSize += sizeof (EFI_FFS_FILE_HEADER);\r
+    FfsFileHeader.Size[0]  = (UINT8) (FileSize & 0xFF);\r
+    FfsFileHeader.Size[1]  = (UINT8) ((FileSize & 0xFF00) >> 8);\r
+    FfsFileHeader.Size[2]  = (UINT8) ((FileSize & 0xFF0000) >> 16);\r
+  }\r
   VerboseMsg ("the size of the generated FFS file is %u bytes", (unsigned) FileSize);\r
-  FfsFileHeader.Size[0]  = (UINT8) (FileSize & 0xFF);\r
-  FfsFileHeader.Size[1]  = (UINT8) ((FileSize & 0xFF00) >> 8);\r
-  FfsFileHeader.Size[2]  = (UINT8) ((FileSize & 0xFF0000) >> 16);\r
+\r
+  FfsFileHeader.Attributes = (EFI_FFS_FILE_ATTRIBUTES) (FfsAttrib | (FfsAlign << 3));\r
+\r
   //\r
   // Fill in checksums and state, these must be zero for checksumming\r
   //\r
@@ -839,7 +904,7 @@ Returns:
   //\r
   FfsFileHeader.IntegrityCheck.Checksum.Header = CalculateChecksum8 (\r
                                                    (UINT8 *) &FfsFileHeader,\r
-                                                   sizeof (EFI_FFS_FILE_HEADER)\r
+                                                   HeaderSize\r
                                                    );\r
 \r
   if (FfsFileHeader.Attributes & FFS_ATTRIB_CHECKSUM) {\r
@@ -848,7 +913,7 @@ Returns:
     //\r
     FfsFileHeader.IntegrityCheck.Checksum.File = CalculateChecksum8 (\r
                                                    FileBuffer, \r
-                                                   FileSize - sizeof (EFI_FFS_FILE_HEADER)\r
+                                                   FileSize - HeaderSize\r
                                                    );    \r
   } else {\r
     FfsFileHeader.IntegrityCheck.Checksum.File = FFS_FIXED_CHECKSUM;\r
@@ -859,22 +924,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, sizeof (FfsFileHeader), FfsFile);\r
-  //\r
-  // write data\r
-  //\r
-  fwrite (FileBuffer, 1, FileSize - sizeof (EFI_FFS_FILE_HEADER), 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