mirror of
				https://github.com/acidanthera/audk.git
				synced 2025-10-25 17:23:53 +02:00 
			
		
		
		
	1. Do not use tab characters 2. No trailing white space in one line 3. All files must end with CRLF Contributed-under: TianoCore Contribution Agreement 1.1 Signed-off-by: Liming Gao <liming.gao@intel.com> Cc: Yonghong Zhu <yonghong.zhu@intel.com> Reviewed-by: Yonghong Zhu <yonghong.zhu@intel.com>
		
			
				
	
	
		
			1111 lines
		
	
	
		
			36 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1111 lines
		
	
	
		
			36 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /** @file
 | |
| This file contains functions required to generate a Firmware File System file.
 | |
| 
 | |
| Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>
 | |
| This program and the accompanying materials
 | |
| are licensed and made available under the terms and conditions of the BSD License
 | |
| which accompanies this distribution.  The full text of the license may be found at
 | |
| http://opensource.org/licenses/bsd-license.php
 | |
| 
 | |
| THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
 | |
| WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 | |
| 
 | |
| **/
 | |
| 
 | |
| #ifndef __GNUC__
 | |
| #include <windows.h>
 | |
| #include <io.h>
 | |
| #include <sys/types.h>
 | |
| #include <sys/stat.h>
 | |
| #endif
 | |
| 
 | |
| #include <stdio.h>
 | |
| #include <stdlib.h>
 | |
| #include <string.h>
 | |
| 
 | |
| #include <Common/UefiBaseTypes.h>
 | |
| #include <Common/PiFirmwareFile.h>
 | |
| #include <IndustryStandard/PeImage.h>
 | |
| #include <Guid/FfsSectionAlignmentPadding.h>
 | |
| 
 | |
| #include "CommonLib.h"
 | |
| #include "ParseInf.h"
 | |
| #include "EfiUtilityMsgs.h"
 | |
| #include "FvLib.h"
 | |
| #include "PeCoffLib.h"
 | |
| 
 | |
| #define UTILITY_NAME            "GenFfs"
 | |
| #define UTILITY_MAJOR_VERSION   0
 | |
| #define UTILITY_MINOR_VERSION   1
 | |
| 
 | |
| STATIC CHAR8 *mFfsFileType[] = {
 | |
|   NULL,                                   // 0x00
 | |
|   "EFI_FV_FILETYPE_RAW",                  // 0x01
 | |
|   "EFI_FV_FILETYPE_FREEFORM",             // 0x02
 | |
|   "EFI_FV_FILETYPE_SECURITY_CORE",        // 0x03
 | |
|   "EFI_FV_FILETYPE_PEI_CORE",             // 0x04
 | |
|   "EFI_FV_FILETYPE_DXE_CORE",             // 0x05
 | |
|   "EFI_FV_FILETYPE_PEIM",                 // 0x06
 | |
|   "EFI_FV_FILETYPE_DRIVER",               // 0x07
 | |
|   "EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER", // 0x08
 | |
|   "EFI_FV_FILETYPE_APPLICATION",          // 0x09
 | |
|   "EFI_FV_FILETYPE_SMM",                  // 0x0A
 | |
|   "EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE",// 0x0B
 | |
|   "EFI_FV_FILETYPE_COMBINED_SMM_DXE",     // 0x0C
 | |
|   "EFI_FV_FILETYPE_SMM_CORE",             // 0x0D
 | |
|   "EFI_FV_FILETYPE_MM_STANDALONE",        // 0x0E
 | |
|   "EFI_FV_FILETYPE_MM_CORE_STANDALONE"    // 0x0F
 | |
| };
 | |
| 
 | |
| STATIC CHAR8 *mAlignName[] = {
 | |
|   "1", "2", "4", "8", "16", "32", "64", "128", "256", "512",
 | |
|   "1K", "2K", "4K", "8K", "16K", "32K", "64K", "128K", "256K",
 | |
|   "512K", "1M", "2M", "4M", "8M", "16M"
 | |
|  };
 | |
| 
 | |
| STATIC CHAR8 *mFfsValidAlignName[] = {
 | |
|   "8", "16", "128", "512", "1K", "4K", "32K", "64K", "128K","256K",
 | |
|   "512K", "1M", "2M", "4M", "8M", "16M"
 | |
|  };
 | |
| 
 | |
| STATIC UINT32 mFfsValidAlign[] = {0, 8, 16, 128, 512, 1024, 4096, 32768, 65536, 131072, 262144,
 | |
|                                   524288, 1048576, 2097152, 4194304, 8388608, 16777216};
 | |
| 
 | |
| STATIC EFI_GUID mZeroGuid = {0};
 | |
| 
 | |
| STATIC EFI_GUID mEfiFfsSectionAlignmentPaddingGuid = EFI_FFS_SECTION_ALIGNMENT_PADDING_GUID;
 | |
| 
 | |
| STATIC
 | |
| VOID
 | |
| Version (
 | |
|   VOID
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
| 
 | |
|   Print out version information for this utility.
 | |
| 
 | |
| Arguments:
 | |
| 
 | |
|   None
 | |
| 
 | |
| Returns:
 | |
| 
 | |
|   None
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   fprintf (stdout, "%s Version %d.%d %s \n", UTILITY_NAME, UTILITY_MAJOR_VERSION, UTILITY_MINOR_VERSION, __BUILD_VERSION);
 | |
| }
 | |
| 
 | |
| STATIC
 | |
| VOID
 | |
| Usage (
 | |
|   VOID
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
| 
 | |
|   Print Error / Help message.
 | |
| 
 | |
| Arguments:
 | |
| 
 | |
|   VOID
 | |
| 
 | |
| Returns:
 | |
| 
 | |
|   None
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   //
 | |
|   // Summary usage
 | |
|   //
 | |
|   fprintf (stdout, "\nUsage: %s [options]\n\n", UTILITY_NAME);
 | |
| 
 | |
|   //
 | |
|   // Copyright declaration
 | |
|   //
 | |
|   fprintf (stdout, "Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.\n\n");
 | |
| 
 | |
|   //
 | |
|   // Details Option
 | |
|   //
 | |
|   fprintf (stdout, "Options:\n");
 | |
|   fprintf (stdout, "  -o FileName, --outputfile FileName\n\
 | |
|                         File is FFS file to be created.\n");
 | |
|   fprintf (stdout, "  -t Type, --filetype Type\n\
 | |
|                         Type is one FV file type defined in PI spec, which is\n\
 | |
|                         EFI_FV_FILETYPE_RAW, EFI_FV_FILETYPE_FREEFORM,\n\
 | |
|                         EFI_FV_FILETYPE_SECURITY_CORE, EFI_FV_FILETYPE_PEIM,\n\
 | |
|                         EFI_FV_FILETYPE_PEI_CORE, EFI_FV_FILETYPE_DXE_CORE,\n\
 | |
|                         EFI_FV_FILETYPE_DRIVER, EFI_FV_FILETYPE_APPLICATION,\n\
 | |
|                         EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER,\n\
 | |
|                         EFI_FV_FILETYPE_SMM, EFI_FV_FILETYPE_SMM_CORE,\n\
 | |
|                         EFI_FV_FILETYPE_MM_STANDALONE,\n\
 | |
|                         EFI_FV_FILETYPE_MM_CORE_STANDALONE,\n\
 | |
|                         EFI_FV_FILETYPE_COMBINED_SMM_DXE, \n\
 | |
|                         EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE.\n");
 | |
|   fprintf (stdout, "  -g FileGuid, --fileguid FileGuid\n\
 | |
|                         FileGuid is one module guid.\n\
 | |
|                         Its format is xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx\n");
 | |
|   fprintf (stdout, "  -x, --fixed           Indicates that the file may not be moved\n\
 | |
|                         from its present location.\n");
 | |
|   fprintf (stdout, "  -s, --checksum        Indicates to calculate file checksum.\n");
 | |
|   fprintf (stdout, "  -a FileAlign, --align FileAlign\n\
 | |
|                         FileAlign points to file alignment, which only support\n\
 | |
|                         the following align: 1,2,4,8,16,128,512,1K,4K,32K,64K\n\
 | |
|                         128K,256K,512K,1M,2M,4M,8M,16M\n");
 | |
|   fprintf (stdout, "  -i SectionFile, --sectionfile SectionFile\n\
 | |
|                         Section file will be contained in this FFS file.\n");
 | |
|   fprintf (stdout, "  -n SectionAlign, --sectionalign SectionAlign\n\
 | |
|                         SectionAlign points to section alignment, which support\n\
 | |
|                         the alignment scope 0~16M. If SectionAlign is specified\n\
 | |
|                         as 0, tool get alignment value from SectionFile. It is\n\
 | |
|                         specified together with sectionfile to point its\n\
 | |
|                         alignment in FFS file.\n");
 | |
|   fprintf (stdout, "  -v, --verbose         Turn on verbose output with informational messages.\n");
 | |
|   fprintf (stdout, "  -q, --quiet           Disable all messages except key message and fatal error\n");
 | |
|   fprintf (stdout, "  -d, --debug level     Enable debug messages, at input debug level.\n");
 | |
|   fprintf (stdout, "  --version             Show program's version number and exit.\n");
 | |
|   fprintf (stdout, "  -h, --help            Show this help message and exit.\n");
 | |
| }
 | |
| 
 | |
| STATIC
 | |
| EFI_STATUS
 | |
| StringtoAlignment (
 | |
|   IN  CHAR8  *AlignBuffer,
 | |
|   OUT UINT32 *AlignNumber
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
| 
 | |
|   Converts Align String to align value (1~16M).
 | |
| 
 | |
| Arguments:
 | |
| 
 | |
|   AlignBuffer    - Pointer to Align string.
 | |
|   AlignNumber    - Pointer to Align value.
 | |
| 
 | |
| Returns:
 | |
| 
 | |
|   EFI_SUCCESS             Successfully convert align string to align value.
 | |
|   EFI_INVALID_PARAMETER   Align string is invalid or align value is not in scope.
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   UINT32 Index = 0;
 | |
|   //
 | |
|   // Check AlignBuffer
 | |
|   //
 | |
|   if (AlignBuffer == NULL) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
|   for (Index = 0; Index < sizeof (mAlignName) / sizeof (CHAR8 *); Index ++) {
 | |
|     if (stricmp (AlignBuffer, mAlignName [Index]) == 0) {
 | |
|       *AlignNumber = 1 << Index;
 | |
|       return EFI_SUCCESS;
 | |
|     }
 | |
|   }
 | |
|   return EFI_INVALID_PARAMETER;
 | |
| }
 | |
| 
 | |
| STATIC
 | |
| UINT8
 | |
| StringToType (
 | |
|   IN CHAR8 *String
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
| 
 | |
|   Converts File Type String to value.  EFI_FV_FILETYPE_ALL indicates that an
 | |
|   unrecognized file type was specified.
 | |
| 
 | |
| Arguments:
 | |
| 
 | |
|   String    - File type string
 | |
| 
 | |
| Returns:
 | |
| 
 | |
|   File Type Value
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   UINT8 Index = 0;
 | |
| 
 | |
|   if (String == NULL) {
 | |
|     return EFI_FV_FILETYPE_ALL;
 | |
|   }
 | |
| 
 | |
|   for (Index = 0; Index < sizeof (mFfsFileType) / sizeof (CHAR8 *); Index ++) {
 | |
|     if (mFfsFileType [Index] != NULL && (stricmp (String, mFfsFileType [Index]) == 0)) {
 | |
|       return Index;
 | |
|     }
 | |
|   }
 | |
|   return EFI_FV_FILETYPE_ALL;
 | |
| }
 | |
| 
 | |
| STATIC
 | |
| EFI_STATUS
 | |
| GetSectionContents (
 | |
|   IN  CHAR8                     **InputFileName,
 | |
|   IN  UINT32                    *InputFileAlign,
 | |
|   IN  UINT32                    InputFileNum,
 | |
|   IN  EFI_FFS_FILE_ATTRIBUTES   FfsAttrib,
 | |
|   OUT UINT8                     *FileBuffer,
 | |
|   OUT UINT32                    *BufferLength,
 | |
|   OUT UINT32                    *MaxAlignment,
 | |
|   OUT UINT8                     *PESectionNum
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
| 
 | |
|   Get the contents of all section files specified in InputFileName
 | |
|   into FileBuffer.
 | |
| 
 | |
| Arguments:
 | |
| 
 | |
|   InputFileName  - Name of the input file.
 | |
| 
 | |
|   InputFileAlign - Alignment required by the input file data.
 | |
| 
 | |
|   InputFileNum   - Number of input files. Should be at least 1.
 | |
| 
 | |
|   FileBuffer     - Output buffer to contain data
 | |
| 
 | |
|   BufferLength   - On input, this is size of the FileBuffer.
 | |
|                    On output, this is the actual length of the data.
 | |
| 
 | |
|   MaxAlignment   - The max alignment required by all the input file datas.
 | |
| 
 | |
|   PeSectionNum   - Calculate the number of Pe/Te Section in this FFS file.
 | |
| 
 | |
| Returns:
 | |
| 
 | |
|   EFI_SUCCESS on successful return
 | |
|   EFI_INVALID_PARAMETER if InputFileNum is less than 1 or BufferLength point is NULL.
 | |
|   EFI_ABORTED if unable to open input file.
 | |
|   EFI_BUFFER_TOO_SMALL FileBuffer is not enough to contain all file data.
 | |
| --*/
 | |
| {
 | |
|   UINT32                              Size;
 | |
|   UINT32                              Offset;
 | |
|   UINT32                              FileSize;
 | |
|   UINT32                              Index;
 | |
|   FILE                                *InFile;
 | |
|   EFI_FREEFORM_SUBTYPE_GUID_SECTION   *SectHeader;
 | |
|   EFI_COMMON_SECTION_HEADER2          TempSectHeader;
 | |
|   EFI_TE_IMAGE_HEADER                 TeHeader;
 | |
|   UINT32                              TeOffset;
 | |
|   EFI_GUID_DEFINED_SECTION            GuidSectHeader;
 | |
|   EFI_GUID_DEFINED_SECTION2           GuidSectHeader2;
 | |
|   UINT32                              HeaderSize;
 | |
|   UINT32                              MaxEncounteredAlignment;
 | |
| 
 | |
|   Size                    = 0;
 | |
|   Offset                  = 0;
 | |
|   TeOffset                = 0;
 | |
|   MaxEncounteredAlignment = 1;
 | |
| 
 | |
|   //
 | |
|   // Go through our array of file names and copy their contents
 | |
|   // to the output buffer.
 | |
|   //
 | |
|   for (Index = 0; Index < InputFileNum; Index++) {
 | |
|     //
 | |
|     // make sure section ends on a DWORD boundary
 | |
|     //
 | |
|     while ((Size & 0x03) != 0) {
 | |
|       Size++;
 | |
|     }
 | |
| 
 | |
|     //
 | |
|     // Open file and read contents
 | |
|     //
 | |
|     InFile = fopen (LongFilePath (InputFileName[Index]), "rb");
 | |
|     if (InFile == NULL) {
 | |
|       Error (NULL, 0, 0001, "Error opening file", InputFileName[Index]);
 | |
|       return EFI_ABORTED;
 | |
|     }
 | |
| 
 | |
|     fseek (InFile, 0, SEEK_END);
 | |
|     FileSize = ftell (InFile);
 | |
|     fseek (InFile, 0, SEEK_SET);
 | |
|     DebugMsg (NULL, 0, 9, "Input section files",
 | |
|               "the input section name is %s and the size is %u bytes", InputFileName[Index], (unsigned) FileSize);
 | |
| 
 | |
|     //
 | |
|     // Check this section is Te/Pe section, and Calculate the numbers of Te/Pe section.
 | |
|     //
 | |
|     TeOffset = 0;
 | |
|     if (FileSize >= MAX_FFS_SIZE) {
 | |
|       HeaderSize = sizeof (EFI_COMMON_SECTION_HEADER2);
 | |
|     } else {
 | |
|       HeaderSize = sizeof (EFI_COMMON_SECTION_HEADER);
 | |
|     }
 | |
|     fread (&TempSectHeader, 1, HeaderSize, InFile);
 | |
|     if (TempSectHeader.Type == EFI_SECTION_TE) {
 | |
|       (*PESectionNum) ++;
 | |
|       fread (&TeHeader, 1, sizeof (TeHeader), InFile);
 | |
|       if (TeHeader.Signature == EFI_TE_IMAGE_HEADER_SIGNATURE) {
 | |
|         TeOffset = TeHeader.StrippedSize - sizeof (TeHeader);
 | |
|       }
 | |
|     } else if (TempSectHeader.Type == EFI_SECTION_PE32) {
 | |
|       (*PESectionNum) ++;
 | |
|     } else if (TempSectHeader.Type == EFI_SECTION_GUID_DEFINED) {
 | |
|       fseek (InFile, 0, SEEK_SET);
 | |
|       if (FileSize >= MAX_SECTION_SIZE) {
 | |
|         fread (&GuidSectHeader2, 1, sizeof (GuidSectHeader2), InFile);
 | |
|         if ((GuidSectHeader2.Attributes & EFI_GUIDED_SECTION_PROCESSING_REQUIRED) == 0) {
 | |
|           HeaderSize = GuidSectHeader2.DataOffset;
 | |
|         }
 | |
|       } else {
 | |
|         fread (&GuidSectHeader, 1, sizeof (GuidSectHeader), InFile);
 | |
|         if ((GuidSectHeader.Attributes & EFI_GUIDED_SECTION_PROCESSING_REQUIRED) == 0) {
 | |
|           HeaderSize = GuidSectHeader.DataOffset;
 | |
|         }
 | |
|       }
 | |
|       (*PESectionNum) ++;
 | |
|     } else if (TempSectHeader.Type == EFI_SECTION_COMPRESSION ||
 | |
|                TempSectHeader.Type == EFI_SECTION_FIRMWARE_VOLUME_IMAGE) {
 | |
|       //
 | |
|       // for the encapsulated section, assume it contains Pe/Te section
 | |
|       //
 | |
|       (*PESectionNum) ++;
 | |
|     }
 | |
| 
 | |
|     fseek (InFile, 0, SEEK_SET);
 | |
| 
 | |
|     //
 | |
|     // Revert TeOffset to the converse value relative to Alignment
 | |
|     // This is to assure the original PeImage Header at Alignment.
 | |
|     //
 | |
|     if ((TeOffset != 0) && (InputFileAlign [Index] != 0)) {
 | |
|       TeOffset = InputFileAlign [Index] - (TeOffset % InputFileAlign [Index]);
 | |
|       TeOffset = TeOffset % InputFileAlign [Index];
 | |
|     }
 | |
| 
 | |
|     //
 | |
|     // make sure section data meet its alignment requirement by adding one pad section.
 | |
|     // But the different sections have the different section header. Necessary or not?
 | |
|     // Based on section type to adjust offset? Todo
 | |
|     //
 | |
|     if ((InputFileAlign [Index] != 0) && (((Size + HeaderSize + TeOffset) % InputFileAlign [Index]) != 0)) {
 | |
|       Offset = (Size + sizeof (EFI_COMMON_SECTION_HEADER) + HeaderSize + TeOffset + InputFileAlign [Index] - 1) & ~(InputFileAlign [Index] - 1);
 | |
|       Offset = Offset - Size - HeaderSize - TeOffset;
 | |
| 
 | |
|       if (FileBuffer != NULL && ((Size + Offset) < *BufferLength)) {
 | |
|         //
 | |
|         // The maximal alignment is 64K, the raw section size must be less than 0xffffff
 | |
|         //
 | |
|         memset (FileBuffer + Size, 0, Offset);
 | |
|         SectHeader                        = (EFI_FREEFORM_SUBTYPE_GUID_SECTION *) (FileBuffer + Size);
 | |
|         SectHeader->CommonHeader.Size[0]  = (UINT8) (Offset & 0xff);
 | |
|         SectHeader->CommonHeader.Size[1]  = (UINT8) ((Offset & 0xff00) >> 8);
 | |
|         SectHeader->CommonHeader.Size[2]  = (UINT8) ((Offset & 0xff0000) >> 16);
 | |
| 
 | |
|         //
 | |
|         // Only add a special reducible padding section if
 | |
|         // - this FFS has the FFS_ATTRIB_FIXED attribute,
 | |
|         // - none of the preceding sections have alignment requirements,
 | |
|         // - the size of the padding is sufficient for the
 | |
|         //   EFI_SECTION_FREEFORM_SUBTYPE_GUID header.
 | |
|         //
 | |
|         if ((FfsAttrib & FFS_ATTRIB_FIXED) != 0 &&
 | |
|             MaxEncounteredAlignment <= 1 &&
 | |
|             Offset >= sizeof (EFI_FREEFORM_SUBTYPE_GUID_SECTION)) {
 | |
|           SectHeader->CommonHeader.Type   = EFI_SECTION_FREEFORM_SUBTYPE_GUID;
 | |
|           SectHeader->SubTypeGuid         = mEfiFfsSectionAlignmentPaddingGuid;
 | |
|         } else {
 | |
|           SectHeader->CommonHeader.Type   = EFI_SECTION_RAW;
 | |
|         }
 | |
|       }
 | |
|       DebugMsg (NULL, 0, 9, "Pad raw section for section data alignment",
 | |
|                 "Pad Raw section size is %u", (unsigned) Offset);
 | |
| 
 | |
|       Size = Size + Offset;
 | |
|     }
 | |
| 
 | |
|     //
 | |
|     // Get the Max alignment of all input file datas
 | |
|     //
 | |
|     if (MaxEncounteredAlignment < InputFileAlign [Index]) {
 | |
|       MaxEncounteredAlignment = InputFileAlign [Index];
 | |
|     }
 | |
| 
 | |
|     //
 | |
|     // Now read the contents of the file into the buffer
 | |
|     // Buffer must be enough to contain the file content.
 | |
|     //
 | |
|     if ((FileSize > 0) && (FileBuffer != NULL) && ((Size + FileSize) <= *BufferLength)) {
 | |
|       if (fread (FileBuffer + Size, (size_t) FileSize, 1, InFile) != 1) {
 | |
|         Error (NULL, 0, 0004, "Error reading file", InputFileName[Index]);
 | |
|         fclose (InFile);
 | |
|         return EFI_ABORTED;
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     fclose (InFile);
 | |
|     Size += FileSize;
 | |
|   }
 | |
| 
 | |
|   *MaxAlignment = MaxEncounteredAlignment;
 | |
| 
 | |
|   //
 | |
|   // Set the actual length of the data.
 | |
|   //
 | |
|   if (Size > *BufferLength) {
 | |
|     *BufferLength = Size;
 | |
|     return EFI_BUFFER_TOO_SMALL;
 | |
|   } else {
 | |
|     *BufferLength = Size;
 | |
|     return EFI_SUCCESS;
 | |
|   }
 | |
| }
 | |
| 
 | |
| EFI_STATUS
 | |
| FfsRebaseImageRead (
 | |
|     IN      VOID    *FileHandle,
 | |
|     IN      UINTN   FileOffset,
 | |
|     IN OUT  UINT32  *ReadSize,
 | |
|     OUT     VOID    *Buffer
 | |
|     )
 | |
|   /*++
 | |
| 
 | |
|     Routine Description:
 | |
| 
 | |
|     Support routine for the PE/COFF Loader that reads a buffer from a PE/COFF file
 | |
| 
 | |
|     Arguments:
 | |
| 
 | |
|    FileHandle - The handle to the PE/COFF file
 | |
| 
 | |
|    FileOffset - The offset, in bytes, into the file to read
 | |
| 
 | |
|    ReadSize   - The number of bytes to read from the file starting at FileOffset
 | |
| 
 | |
|    Buffer     - A pointer to the buffer to read the data into.
 | |
| 
 | |
|    Returns:
 | |
| 
 | |
|    EFI_SUCCESS - ReadSize bytes of data were read into Buffer from the PE/COFF file starting at FileOffset
 | |
| 
 | |
|    --*/
 | |
| {
 | |
|   CHAR8   *Destination8;
 | |
|   CHAR8   *Source8;
 | |
|   UINT32  Length;
 | |
| 
 | |
|   Destination8  = Buffer;
 | |
|   Source8       = (CHAR8 *) ((UINTN) FileHandle + FileOffset);
 | |
|   Length        = *ReadSize;
 | |
|   while (Length--) {
 | |
|     *(Destination8++) = *(Source8++);
 | |
|   }
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| STATIC
 | |
| EFI_STATUS
 | |
| GetAlignmentFromFile(char *InFile, UINT32 *Alignment)
 | |
|   /*++
 | |
|     InFile is input file for getting alignment
 | |
|     return the alignment
 | |
|     --*/
 | |
| {
 | |
|   FILE                           *InFileHandle;
 | |
|   UINT8                          *PeFileBuffer;
 | |
|   UINTN                          PeFileSize;
 | |
|   UINT32                         CurSecHdrSize;
 | |
|   PE_COFF_LOADER_IMAGE_CONTEXT   ImageContext;
 | |
|   EFI_COMMON_SECTION_HEADER      *CommonHeader;
 | |
|   EFI_STATUS                     Status;
 | |
| 
 | |
|   InFileHandle        = NULL;
 | |
|   PeFileBuffer        = NULL;
 | |
|   *Alignment          = 0;
 | |
| 
 | |
|   memset (&ImageContext, 0, sizeof (ImageContext));
 | |
| 
 | |
|   InFileHandle = fopen(LongFilePath(InFile), "rb");
 | |
|   if (InFileHandle == NULL){
 | |
|     Error (NULL, 0, 0001, "Error opening file", InFile);
 | |
|     return EFI_ABORTED;
 | |
|   }
 | |
|   PeFileSize = _filelength (fileno(InFileHandle));
 | |
|   PeFileBuffer = (UINT8 *) malloc (PeFileSize);
 | |
|   if (PeFileBuffer == NULL) {
 | |
|     fclose (InFileHandle);
 | |
|     Error(NULL, 0, 4001, "Resource", "memory cannot be allocated  of %s", InFileHandle);
 | |
|     return EFI_OUT_OF_RESOURCES;
 | |
|   }
 | |
|   fread (PeFileBuffer, sizeof (UINT8), PeFileSize, InFileHandle);
 | |
|   fclose (InFileHandle);
 | |
|   CommonHeader = (EFI_COMMON_SECTION_HEADER *) PeFileBuffer;
 | |
|   CurSecHdrSize = GetSectionHeaderLength(CommonHeader);
 | |
|   ImageContext.Handle = (VOID *) ((UINTN)PeFileBuffer + CurSecHdrSize);
 | |
|   ImageContext.ImageRead = (PE_COFF_LOADER_READ_FILE)FfsRebaseImageRead;
 | |
|   Status               = PeCoffLoaderGetImageInfo(&ImageContext);
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     Error (NULL, 0, 3000, "Invalid PeImage", "The input file is %s and return status is %x", InFile, (int) Status);
 | |
|     return Status;
 | |
|    }
 | |
|   *Alignment = ImageContext.SectionAlignment;
 | |
|   // Free the allocated memory resource
 | |
|   if (PeFileBuffer != NULL) {
 | |
|     free (PeFileBuffer);
 | |
|     PeFileBuffer = NULL;
 | |
|   }
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| int
 | |
| main (
 | |
|   int   argc,
 | |
|   CHAR8 *argv[]
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
| 
 | |
|   Main function.
 | |
| 
 | |
| Arguments:
 | |
| 
 | |
|   argc - Number of command line parameters.
 | |
|   argv - Array of pointers to parameter strings.
 | |
| 
 | |
| Returns:
 | |
|   STATUS_SUCCESS - Utility exits successfully.
 | |
|   STATUS_ERROR   - Some error occurred during execution.
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   EFI_STATUS              Status;
 | |
|   EFI_FFS_FILE_ATTRIBUTES FfsAttrib;
 | |
|   UINT32                  FfsAlign;
 | |
|   EFI_FV_FILETYPE         FfsFiletype;
 | |
|   CHAR8                   *OutputFileName;
 | |
|   EFI_GUID                FileGuid = {0};
 | |
|   UINT32                  InputFileNum;
 | |
|   UINT32                  *InputFileAlign;
 | |
|   CHAR8                   **InputFileName;
 | |
|   UINT8                   *FileBuffer;
 | |
|   UINT32                  FileSize;
 | |
|   UINT32                  MaxAlignment;
 | |
|   EFI_FFS_FILE_HEADER2    FfsFileHeader;
 | |
|   FILE                    *FfsFile;
 | |
|   UINT32                  Index;
 | |
|   UINT64                  LogLevel;
 | |
|   UINT8                   PeSectionNum;
 | |
|   UINT32                  HeaderSize;
 | |
|   UINT32                  Alignment;
 | |
|   //
 | |
|   // Workaround for static code checkers.
 | |
|   // Ensures the size of 'AlignmentBuffer' can hold all the digits of an
 | |
|   // unsigned 32-bit integer plus the size unit character.
 | |
|   //
 | |
|   CHAR8                   AlignmentBuffer[16];
 | |
| 
 | |
|   //
 | |
|   // Init local variables
 | |
|   //
 | |
|   LogLevel       = 0;
 | |
|   Index          = 0;
 | |
|   FfsAttrib      = 0;
 | |
|   FfsAlign       = 0;
 | |
|   FfsFiletype    = EFI_FV_FILETYPE_ALL;
 | |
|   OutputFileName = NULL;
 | |
|   InputFileNum   = 0;
 | |
|   InputFileName  = NULL;
 | |
|   InputFileAlign = NULL;
 | |
|   FileBuffer     = NULL;
 | |
|   FileSize       = 0;
 | |
|   MaxAlignment   = 1;
 | |
|   FfsFile        = NULL;
 | |
|   Status         = EFI_SUCCESS;
 | |
|   PeSectionNum   = 0;
 | |
| 
 | |
|   SetUtilityName (UTILITY_NAME);
 | |
| 
 | |
|   if (argc == 1) {
 | |
|     Error (NULL, 0, 1001, "Missing options", "no options input");
 | |
|     Usage ();
 | |
|     return STATUS_ERROR;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Parse command line
 | |
|   //
 | |
|   argc --;
 | |
|   argv ++;
 | |
| 
 | |
|   if ((stricmp (argv[0], "-h") == 0) || (stricmp (argv[0], "--help") == 0)) {
 | |
|     Version ();
 | |
|     Usage ();
 | |
|     return STATUS_SUCCESS;
 | |
|   }
 | |
| 
 | |
|   if (stricmp (argv[0], "--version") == 0) {
 | |
|     Version ();
 | |
|     return STATUS_SUCCESS;
 | |
|   }
 | |
| 
 | |
|   while (argc > 0) {
 | |
|     if ((stricmp (argv[0], "-t") == 0) || (stricmp (argv[0], "--filetype") == 0)) {
 | |
|       if (argv[1] == NULL || argv[1][0] == '-') {
 | |
|         Error (NULL, 0, 1003, "Invalid option value", "file type is missing for -t option");
 | |
|         goto Finish;
 | |
|       }
 | |
|       FfsFiletype = StringToType (argv[1]);
 | |
|       if (FfsFiletype == EFI_FV_FILETYPE_ALL) {
 | |
|         Error (NULL, 0, 1003, "Invalid option value", "%s is not a valid file type", argv[1]);
 | |
|         goto Finish;
 | |
|       }
 | |
|       argc -= 2;
 | |
|       argv += 2;
 | |
|       continue;
 | |
|     }
 | |
| 
 | |
|     if ((stricmp (argv[0], "-o") == 0) || (stricmp (argv[0], "--outputfile") == 0)) {
 | |
|       if (argv[1] == NULL || argv[1][0] == '-') {
 | |
|         Error (NULL, 0, 1003, "Invalid option value", "Output file is missing for -o option");
 | |
|         goto Finish;
 | |
|       }
 | |
|       OutputFileName = argv[1];
 | |
|       argc -= 2;
 | |
|       argv += 2;
 | |
|       continue;
 | |
|     }
 | |
| 
 | |
|     if ((stricmp (argv[0], "-g") == 0) || (stricmp (argv[0], "--fileguid") == 0)) {
 | |
|       Status = StringToGuid (argv[1], &FileGuid);
 | |
|       if (EFI_ERROR (Status)) {
 | |
|         Error (NULL, 0, 1003, "Invalid option value", "%s = %s", argv[0], argv[1]);
 | |
|         goto Finish;
 | |
|       }
 | |
|       argc -= 2;
 | |
|       argv += 2;
 | |
|       continue;
 | |
|     }
 | |
| 
 | |
|     if ((stricmp (argv[0], "-x") == 0) || (stricmp (argv[0], "--fixed") == 0)) {
 | |
|       FfsAttrib |= FFS_ATTRIB_FIXED;
 | |
|       argc -= 1;
 | |
|       argv += 1;
 | |
|       continue;
 | |
|     }
 | |
| 
 | |
|     if ((stricmp (argv[0], "-s") == 0) || (stricmp (argv[0], "--checksum") == 0)) {
 | |
|       FfsAttrib |= FFS_ATTRIB_CHECKSUM;
 | |
|       argc -= 1;
 | |
|       argv += 1;
 | |
|       continue;
 | |
|     }
 | |
| 
 | |
|     if ((stricmp (argv[0], "-a") == 0) || (stricmp (argv[0], "--align") == 0)) {
 | |
|       if (argv[1] == NULL || argv[1][0] == '-') {
 | |
|         Error (NULL, 0, 1003, "Invalid option value", "Align value is missing for -a option");
 | |
|         goto Finish;
 | |
|       }
 | |
|       for (Index = 0; Index < sizeof (mFfsValidAlignName) / sizeof (CHAR8 *); Index ++) {
 | |
|         if (stricmp (argv[1], mFfsValidAlignName[Index]) == 0) {
 | |
|           break;
 | |
|         }
 | |
|       }
 | |
|       if (Index == sizeof (mFfsValidAlignName) / sizeof (CHAR8 *)) {
 | |
|         if ((stricmp (argv[1], "1") == 0) || (stricmp (argv[1], "2") == 0) || (stricmp (argv[1], "4") == 0)) {
 | |
|           //
 | |
|           // 1, 2, 4 byte alignment same to 8 byte alignment
 | |
|           //
 | |
|           Index = 0;
 | |
|         } else {
 | |
|           Error (NULL, 0, 1003, "Invalid option value", "%s = %s", argv[0], argv[1]);
 | |
|           goto Finish;
 | |
|         }
 | |
|       }
 | |
|       FfsAlign = Index;
 | |
|       argc -= 2;
 | |
|       argv += 2;
 | |
|       continue;
 | |
|     }
 | |
| 
 | |
|     if ((stricmp (argv[0], "-i") == 0) || (stricmp (argv[0], "--sectionfile") == 0)) {
 | |
|       //
 | |
|       // Get Input file name and its alignment
 | |
|       //
 | |
|       if (argv[1] == NULL || argv[1][0] == '-') {
 | |
|         Error (NULL, 0, 1003, "Invalid option value", "input section file is missing for -i option");
 | |
|         goto Finish;
 | |
|       }
 | |
| 
 | |
|       //
 | |
|       // Allocate Input file name buffer and its alignment buffer.
 | |
|       //
 | |
|       if ((InputFileNum == 0) && (InputFileName == NULL)) {
 | |
|         InputFileName = (CHAR8 **) malloc (MAXIMUM_INPUT_FILE_NUM * sizeof (CHAR8 *));
 | |
|         if (InputFileName == NULL) {
 | |
|           Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!");
 | |
|           return STATUS_ERROR;
 | |
|         }
 | |
|         memset (InputFileName, 0, (MAXIMUM_INPUT_FILE_NUM * sizeof (CHAR8 *)));
 | |
| 
 | |
|         InputFileAlign = (UINT32 *) malloc (MAXIMUM_INPUT_FILE_NUM * sizeof (UINT32));
 | |
|         if (InputFileAlign == NULL) {
 | |
|           Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!");
 | |
|           free (InputFileName);
 | |
|           return STATUS_ERROR;
 | |
|         }
 | |
|         memset (InputFileAlign, 0, MAXIMUM_INPUT_FILE_NUM * sizeof (UINT32));
 | |
|       } else if (InputFileNum % MAXIMUM_INPUT_FILE_NUM == 0) {
 | |
|         //
 | |
|         // InputFileName and alignment buffer too small, need to realloc
 | |
|         //
 | |
|         InputFileName = (CHAR8 **) realloc (
 | |
|                                     InputFileName,
 | |
|                                     (InputFileNum + MAXIMUM_INPUT_FILE_NUM) * sizeof (CHAR8 *)
 | |
|                                     );
 | |
| 
 | |
|         if (InputFileName == NULL) {
 | |
|           Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!");
 | |
|           free (InputFileAlign);
 | |
|           return STATUS_ERROR;
 | |
|         }
 | |
|         memset (&(InputFileName[InputFileNum]), 0, (MAXIMUM_INPUT_FILE_NUM * sizeof (CHAR8 *)));
 | |
| 
 | |
|         InputFileAlign = (UINT32 *) realloc (
 | |
|                                     InputFileAlign,
 | |
|                                     (InputFileNum + MAXIMUM_INPUT_FILE_NUM) * sizeof (UINT32)
 | |
|                                     );
 | |
| 
 | |
|         if (InputFileAlign == NULL) {
 | |
|           Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!");
 | |
|           free (InputFileName);
 | |
|           return STATUS_ERROR;
 | |
|         }
 | |
|         memset (&(InputFileAlign[InputFileNum]), 0, (MAXIMUM_INPUT_FILE_NUM * sizeof (UINT32)));
 | |
|       }
 | |
| 
 | |
|       InputFileName[InputFileNum] = argv[1];
 | |
|       argc -= 2;
 | |
|       argv += 2;
 | |
| 
 | |
|       if (argc <= 0) {
 | |
|         InputFileNum ++;
 | |
|         break;
 | |
|       }
 | |
| 
 | |
|       //
 | |
|       // Section File alignment requirement
 | |
|       //
 | |
|       if ((stricmp (argv[0], "-n") == 0) || (stricmp (argv[0], "--sectionalign") == 0)) {
 | |
|         if ((argv[1] != NULL) && (stricmp("0", argv[1]) == 0)) {
 | |
|           Status = GetAlignmentFromFile(InputFileName[InputFileNum], &Alignment);
 | |
|           if (EFI_ERROR(Status)) {
 | |
|             Error (NULL, 0, 1003, "Fail to get Alignment from %s", InputFileName[InputFileNum]);
 | |
|             goto Finish;
 | |
|           }
 | |
|           if (Alignment < 0x400){
 | |
|             sprintf (AlignmentBuffer, "%d", Alignment);
 | |
|           }
 | |
|           else if (Alignment >= 0x400) {
 | |
|             if (Alignment >= 0x100000) {
 | |
|               sprintf (AlignmentBuffer, "%dM", Alignment/0x100000);
 | |
|             } else {
 | |
|               sprintf (AlignmentBuffer, "%dK", Alignment/0x400);
 | |
|             }
 | |
|           }
 | |
|           Status = StringtoAlignment (AlignmentBuffer, &(InputFileAlign[InputFileNum]));
 | |
|         }
 | |
|         else {
 | |
|           Status = StringtoAlignment (argv[1], &(InputFileAlign[InputFileNum]));
 | |
|         }
 | |
|         if (EFI_ERROR (Status)) {
 | |
|           Error (NULL, 0, 1003, "Invalid option value", "%s = %s", argv[0], argv[1]);
 | |
|           goto Finish;
 | |
|         }
 | |
|         argc -= 2;
 | |
|         argv += 2;
 | |
|       }
 | |
|       InputFileNum ++;
 | |
|       continue;
 | |
|     }
 | |
| 
 | |
|     if ((stricmp (argv[0], "-n") == 0) || (stricmp (argv[0], "--sectionalign") == 0)) {
 | |
|       Error (NULL, 0, 1000, "Unknown option", "SectionAlign option must be specified with section file.");
 | |
|       goto Finish;
 | |
|     }
 | |
| 
 | |
|     if ((stricmp (argv[0], "-v") == 0) || (stricmp (argv[0], "--verbose") == 0)) {
 | |
|       SetPrintLevel (VERBOSE_LOG_LEVEL);
 | |
|       VerboseMsg ("Verbose output Mode Set!");
 | |
|       argc --;
 | |
|       argv ++;
 | |
|       continue;
 | |
|     }
 | |
| 
 | |
|     if ((stricmp (argv[0], "-q") == 0) || (stricmp (argv[0], "--quiet") == 0)) {
 | |
|       SetPrintLevel (KEY_LOG_LEVEL);
 | |
|       KeyMsg ("Quiet output Mode Set!");
 | |
|       argc --;
 | |
|       argv ++;
 | |
|       continue;
 | |
|     }
 | |
| 
 | |
|     if ((stricmp (argv[0], "-d") == 0) || (stricmp (argv[0], "--debug") == 0)) {
 | |
|       Status = AsciiStringToUint64 (argv[1], FALSE, &LogLevel);
 | |
|       if (EFI_ERROR (Status)) {
 | |
|         Error (NULL, 0, 1003, "Invalid option value", "%s = %s", argv[0], argv[1]);
 | |
|         goto Finish;
 | |
|       }
 | |
|       if (LogLevel > 9) {
 | |
|         Error (NULL, 0, 1003, "Invalid option value", "Debug Level range is 0-9, current input level is %d", (int) LogLevel);
 | |
|         goto Finish;
 | |
|       }
 | |
|       SetPrintLevel (LogLevel);
 | |
|       DebugMsg (NULL, 0, 9, "Debug Mode Set", "Debug Output Mode Level %s is set!", argv[1]);
 | |
|       argc -= 2;
 | |
|       argv += 2;
 | |
|       continue;
 | |
|     }
 | |
| 
 | |
|     Error (NULL, 0, 1000, "Unknown option", "%s", argv[0]);
 | |
|     goto Finish;
 | |
|   }
 | |
| 
 | |
|   VerboseMsg ("%s tool start.", UTILITY_NAME);
 | |
| 
 | |
|   //
 | |
|   // Check the complete input parameters.
 | |
|   //
 | |
|   if (FfsFiletype == EFI_FV_FILETYPE_ALL) {
 | |
|     Error (NULL, 0, 1001, "Missing option", "filetype");
 | |
|     goto Finish;
 | |
|   }
 | |
| 
 | |
|   if (CompareGuid (&FileGuid, &mZeroGuid) == 0) {
 | |
|     Error (NULL, 0, 1001, "Missing option", "fileguid");
 | |
|     goto Finish;
 | |
|   }
 | |
| 
 | |
|   if (InputFileNum == 0) {
 | |
|     Error (NULL, 0, 1001, "Missing option", "Input files");
 | |
|     goto Finish;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Output input parameter information
 | |
|   //
 | |
|   VerboseMsg ("Fv File type is %s", mFfsFileType [FfsFiletype]);
 | |
|   VerboseMsg ("Output file name is %s", OutputFileName);
 | |
|   VerboseMsg ("FFS File Guid is %08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X",
 | |
|                 (unsigned) FileGuid.Data1,
 | |
|                 FileGuid.Data2,
 | |
|                 FileGuid.Data3,
 | |
|                 FileGuid.Data4[0],
 | |
|                 FileGuid.Data4[1],
 | |
|                 FileGuid.Data4[2],
 | |
|                 FileGuid.Data4[3],
 | |
|                 FileGuid.Data4[4],
 | |
|                 FileGuid.Data4[5],
 | |
|                 FileGuid.Data4[6],
 | |
|                 FileGuid.Data4[7]);
 | |
|   if ((FfsAttrib & FFS_ATTRIB_FIXED) != 0) {
 | |
|     VerboseMsg ("FFS File has the fixed file attribute");
 | |
|   }
 | |
|   if ((FfsAttrib & FFS_ATTRIB_CHECKSUM) != 0) {
 | |
|     VerboseMsg ("FFS File requires the checksum of the whole file");
 | |
|   }
 | |
|   VerboseMsg ("FFS file alignment is %s", mFfsValidAlignName[FfsAlign]);
 | |
|   for (Index = 0; Index < InputFileNum; Index ++) {
 | |
|     if (InputFileAlign[Index] == 0) {
 | |
|       //
 | |
|       // Minimum alignment is 1 byte.
 | |
|       //
 | |
|       InputFileAlign[Index] = 1;
 | |
|     }
 | |
|     VerboseMsg ("the %dth input section name is %s and section alignment is %u", Index, InputFileName[Index], (unsigned) InputFileAlign[Index]);
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Calculate the size of all input section files.
 | |
|   //
 | |
|   Status = GetSectionContents (
 | |
|              InputFileName,
 | |
|              InputFileAlign,
 | |
|              InputFileNum,
 | |
|              FfsAttrib,
 | |
|              FileBuffer,
 | |
|              &FileSize,
 | |
|              &MaxAlignment,
 | |
|              &PeSectionNum
 | |
|              );
 | |
| 
 | |
|   if ((FfsFiletype == EFI_FV_FILETYPE_SECURITY_CORE ||
 | |
|       FfsFiletype == EFI_FV_FILETYPE_PEI_CORE ||
 | |
|       FfsFiletype == EFI_FV_FILETYPE_DXE_CORE) && (PeSectionNum != 1)) {
 | |
|     Error (NULL, 0, 2000, "Invalid parameter", "Fv File type %s must have one and only one Pe or Te section, but %u Pe/Te section are input", mFfsFileType [FfsFiletype], PeSectionNum);
 | |
|     goto Finish;
 | |
|   }
 | |
| 
 | |
|   if ((FfsFiletype == EFI_FV_FILETYPE_PEIM ||
 | |
|       FfsFiletype == EFI_FV_FILETYPE_DRIVER ||
 | |
|       FfsFiletype == EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER ||
 | |
|       FfsFiletype == EFI_FV_FILETYPE_APPLICATION) && (PeSectionNum < 1)) {
 | |
|     Error (NULL, 0, 2000, "Invalid parameter", "Fv File type %s must have at least one Pe or Te section, but no Pe/Te section is input", mFfsFileType [FfsFiletype]);
 | |
|     goto Finish;
 | |
|   }
 | |
| 
 | |
|   if (Status == EFI_BUFFER_TOO_SMALL) {
 | |
|     FileBuffer = (UINT8 *) malloc (FileSize);
 | |
|     if (FileBuffer == NULL) {
 | |
|       Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!");
 | |
|       goto Finish;
 | |
|     }
 | |
|     memset (FileBuffer, 0, FileSize);
 | |
| 
 | |
|     //
 | |
|     // read all input file contents into a buffer
 | |
|     //
 | |
|     Status = GetSectionContents (
 | |
|                InputFileName,
 | |
|                InputFileAlign,
 | |
|                InputFileNum,
 | |
|                FfsAttrib,
 | |
|                FileBuffer,
 | |
|                &FileSize,
 | |
|                &MaxAlignment,
 | |
|                &PeSectionNum
 | |
|                );
 | |
|   }
 | |
| 
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     goto Finish;
 | |
|   }
 | |
| 
 | |
|   if (FileBuffer == NULL && FileSize != 0) {
 | |
|     Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!");
 | |
|     goto Finish;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Create Ffs file header.
 | |
|   //
 | |
|   memset (&FfsFileHeader, 0, sizeof (EFI_FFS_FILE_HEADER2));
 | |
|   memcpy (&FfsFileHeader.Name, &FileGuid, sizeof (EFI_GUID));
 | |
|   FfsFileHeader.Type       = FfsFiletype;
 | |
|   //
 | |
|   // Update FFS Alignment based on the max alignment required by input section files
 | |
|   //
 | |
|   VerboseMsg ("the max alignment of all input sections is %u", (unsigned) MaxAlignment);
 | |
|   for (Index = 0; Index < sizeof (mFfsValidAlign) / sizeof (UINT32) - 1; Index ++) {
 | |
|     if ((MaxAlignment > mFfsValidAlign [Index]) && (MaxAlignment <= mFfsValidAlign [Index + 1])) {
 | |
|       break;
 | |
|     }
 | |
|   }
 | |
|   if (FfsAlign < Index) {
 | |
|     FfsAlign = Index;
 | |
|   }
 | |
|   VerboseMsg ("the alignment of the generated FFS file is %u", (unsigned) mFfsValidAlign [FfsAlign + 1]);
 | |
| 
 | |
|   //
 | |
|   // Now FileSize includes the EFI_FFS_FILE_HEADER
 | |
|   //
 | |
|   if (FileSize + sizeof (EFI_FFS_FILE_HEADER) >= MAX_FFS_SIZE) {
 | |
|     HeaderSize = sizeof (EFI_FFS_FILE_HEADER2);
 | |
|     FileSize += sizeof (EFI_FFS_FILE_HEADER2);
 | |
|     FfsFileHeader.ExtendedSize = FileSize;
 | |
|     memset(FfsFileHeader.Size, 0, sizeof (UINT8) * 3);
 | |
|     FfsAttrib |= FFS_ATTRIB_LARGE_FILE;
 | |
|   } else {
 | |
|     HeaderSize = sizeof (EFI_FFS_FILE_HEADER);
 | |
|     FileSize += sizeof (EFI_FFS_FILE_HEADER);
 | |
|     FfsFileHeader.Size[0]  = (UINT8) (FileSize & 0xFF);
 | |
|     FfsFileHeader.Size[1]  = (UINT8) ((FileSize & 0xFF00) >> 8);
 | |
|     FfsFileHeader.Size[2]  = (UINT8) ((FileSize & 0xFF0000) >> 16);
 | |
|   }
 | |
|   VerboseMsg ("the size of the generated FFS file is %u bytes", (unsigned) FileSize);
 | |
| 
 | |
|   //FfsAlign larger than 7, set FFS_ATTRIB_DATA_ALIGNMENT2
 | |
|   if (FfsAlign < 8) {
 | |
|     FfsFileHeader.Attributes = (EFI_FFS_FILE_ATTRIBUTES) (FfsAttrib | (FfsAlign << 3));
 | |
|   } else {
 | |
|     FfsFileHeader.Attributes = (EFI_FFS_FILE_ATTRIBUTES) (FfsAttrib | ((FfsAlign & 0x7) << 3) | FFS_ATTRIB_DATA_ALIGNMENT2);
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Fill in checksums and state, these must be zero for checksumming
 | |
|   //
 | |
|   // FileHeader.IntegrityCheck.Checksum.Header = 0;
 | |
|   // FileHeader.IntegrityCheck.Checksum.File = 0;
 | |
|   // FileHeader.State = 0;
 | |
|   //
 | |
|   FfsFileHeader.IntegrityCheck.Checksum.Header = CalculateChecksum8 (
 | |
|                                                    (UINT8 *) &FfsFileHeader,
 | |
|                                                    HeaderSize
 | |
|                                                    );
 | |
| 
 | |
|   if (FfsFileHeader.Attributes & FFS_ATTRIB_CHECKSUM) {
 | |
|     //
 | |
|     // Ffs header checksum = zero, so only need to calculate ffs body.
 | |
|     //
 | |
|     FfsFileHeader.IntegrityCheck.Checksum.File = CalculateChecksum8 (
 | |
|                                                    FileBuffer,
 | |
|                                                    FileSize - HeaderSize
 | |
|                                                    );
 | |
|   } else {
 | |
|     FfsFileHeader.IntegrityCheck.Checksum.File = FFS_FIXED_CHECKSUM;
 | |
|   }
 | |
| 
 | |
|   FfsFileHeader.State = EFI_FILE_HEADER_CONSTRUCTION | EFI_FILE_HEADER_VALID | EFI_FILE_DATA_VALID;
 | |
| 
 | |
|   //
 | |
|   // Open output file to write ffs data.
 | |
|   //
 | |
|   if (OutputFileName != NULL) {
 | |
|     remove(OutputFileName);
 | |
|     FfsFile = fopen (LongFilePath (OutputFileName), "wb");
 | |
|     if (FfsFile == NULL) {
 | |
|       Error (NULL, 0, 0001, "Error opening file", OutputFileName);
 | |
|       goto Finish;
 | |
|     }
 | |
|     //
 | |
|     // write header
 | |
|     //
 | |
|     fwrite (&FfsFileHeader, 1, HeaderSize, FfsFile);
 | |
|     //
 | |
|     // write data
 | |
|     //
 | |
|     if (FileBuffer != NULL) {
 | |
|       fwrite (FileBuffer, 1, FileSize - HeaderSize, FfsFile);
 | |
|     }
 | |
| 
 | |
|     fclose (FfsFile);
 | |
|   }
 | |
| 
 | |
| Finish:
 | |
|   if (InputFileName != NULL) {
 | |
|     free (InputFileName);
 | |
|   }
 | |
|   if (InputFileAlign != NULL) {
 | |
|     free (InputFileAlign);
 | |
|   }
 | |
|   if (FileBuffer != NULL) {
 | |
|     free (FileBuffer);
 | |
|   }
 | |
|   //
 | |
|   // If any errors were reported via the standard error reporting
 | |
|   // routines, then the status has been saved. Get the value and
 | |
|   // return it to the caller.
 | |
|   //
 | |
|   VerboseMsg ("%s tool done with return code is 0x%x.", UTILITY_NAME, GetUtilityStatus ());
 | |
| 
 | |
|   return GetUtilityStatus ();
 | |
| }
 |