2014-08-28 15:53:34 +02:00
/** @file
This file contains functions required to generate a Firmware File System file .
2009-07-17 11:10:31 +02:00
2018-07-05 11:40:04 +02:00
Copyright ( c ) 2004 - 2018 , Intel Corporation . All rights reserved . < BR >
2019-04-04 01:03:11 +02:00
SPDX - License - Identifier : BSD - 2 - Clause - Patent
2009-07-17 11:10:31 +02:00
* */
2017-09-29 01:53:30 +02:00
# ifndef __GNUC__
# include <windows.h>
# include <io.h>
# include <sys/types.h>
# include <sys/stat.h>
# endif
2019-04-03 04:17:02 +02:00
# ifdef __GNUC__
# include <unistd.h>
# endif
2009-07-17 11:10:31 +02:00
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
# include <Common/UefiBaseTypes.h>
# include <Common/PiFirmwareFile.h>
# include <IndustryStandard/PeImage.h>
2015-07-27 15:50:19 +02:00
# include <Guid/FfsSectionAlignmentPadding.h>
2009-07-17 11:10:31 +02:00
# include "CommonLib.h"
# include "ParseInf.h"
# include "EfiUtilityMsgs.h"
2017-09-29 01:53:30 +02:00
# include "FvLib.h"
# include "PeCoffLib.h"
2009-07-17 11:10:31 +02:00
# 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
2017-06-26 18:47:37 +02:00
" EFI_FV_FILETYPE_SMM_CORE " , // 0x0D
" EFI_FV_FILETYPE_MM_STANDALONE " , // 0x0E
" EFI_FV_FILETYPE_MM_CORE_STANDALONE " // 0x0F
} ;
2009-07-17 11:10:31 +02:00
STATIC CHAR8 * mAlignName [ ] = {
" 1 " , " 2 " , " 4 " , " 8 " , " 16 " , " 32 " , " 64 " , " 128 " , " 256 " , " 512 " ,
2017-09-20 08:10:04 +02:00
" 1K " , " 2K " , " 4K " , " 8K " , " 16K " , " 32K " , " 64K " , " 128K " , " 256K " ,
" 512K " , " 1M " , " 2M " , " 4M " , " 8M " , " 16M "
2009-07-17 11:10:31 +02:00
} ;
STATIC CHAR8 * mFfsValidAlignName [ ] = {
2017-09-20 08:10:04 +02:00
" 8 " , " 16 " , " 128 " , " 512 " , " 1K " , " 4K " , " 32K " , " 64K " , " 128K " , " 256K " ,
" 512K " , " 1M " , " 2M " , " 4M " , " 8M " , " 16M "
2009-07-17 11:10:31 +02:00
} ;
2017-09-20 08:10:04 +02:00
STATIC UINT32 mFfsValidAlign [ ] = { 0 , 8 , 16 , 128 , 512 , 1024 , 4096 , 32768 , 65536 , 131072 , 262144 ,
524288 , 1048576 , 2097152 , 4194304 , 8388608 , 16777216 } ;
2009-07-17 11:10:31 +02:00
STATIC EFI_GUID mZeroGuid = { 0 } ;
2015-07-27 15:50:19 +02:00
STATIC EFI_GUID mEfiFfsSectionAlignmentPaddingGuid = EFI_FFS_SECTION_ALIGNMENT_PADDING_GUID ;
2009-07-17 11:10:31 +02:00
STATIC
2018-07-05 11:40:04 +02:00
VOID
2009-07-17 11:10:31 +02:00
Version (
VOID
)
/*++
Routine Description :
Print out version information for this utility .
Arguments :
None
2018-07-05 11:40:04 +02:00
2009-07-17 11:10:31 +02:00
Returns :
None
2018-07-05 11:40:04 +02:00
- - */
2009-07-17 11:10:31 +02:00
{
2011-09-18 14:17:25 +02:00
fprintf ( stdout , " %s Version %d.%d %s \n " , UTILITY_NAME , UTILITY_MAJOR_VERSION , UTILITY_MINOR_VERSION , __BUILD_VERSION ) ;
2009-07-17 11:10:31 +02:00
}
STATIC
VOID
Usage (
VOID
)
/*++
Routine Description :
Print Error / Help message .
Arguments :
VOID
Returns :
None
- - */
{
//
// Summary usage
//
fprintf ( stdout , " \n Usage: %s [options] \n \n " , UTILITY_NAME ) ;
2018-07-05 11:40:04 +02:00
2009-07-17 11:10:31 +02:00
//
// Copyright declaration
2018-07-05 11:40:04 +02:00
//
fprintf ( stdout , " Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved. \n \n " ) ;
2009-07-17 11:10:31 +02:00
//
// 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 \
2009-11-09 12:47:35 +01:00
EFI_FV_FILETYPE_SMM , EFI_FV_FILETYPE_SMM_CORE , \ n \
2017-06-26 18:47:37 +02:00
EFI_FV_FILETYPE_MM_STANDALONE , \ n \
EFI_FV_FILETYPE_MM_CORE_STANDALONE , \ n \
2009-11-09 12:47:35 +01:00
EFI_FV_FILETYPE_COMBINED_SMM_DXE , \ n \
2009-07-17 11:10:31 +02:00
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 \
2017-09-20 08:10:04 +02:00
the following align : 1 , 2 , 4 , 8 , 16 , 128 , 512 , 1 K , 4 K , 32 K , 64 K \ n \
128 K , 256 K , 512 K , 1 M , 2 M , 4 M , 8 M , 16 M \ n " );
2009-07-17 11:10:31 +02:00
fprintf ( stdout , " -i SectionFile, --sectionfile SectionFile \n \
Section file will be contained in this FFS file . \ n " );
2019-04-03 04:17:02 +02:00
fprintf ( stdout , " -oi SectionFile, --optionalsectionfile SectionFile \n \
If the Section file exists , it will be contained in this FFS file , otherwise , it will be ignored . \ n " );
2009-07-17 11:10:31 +02:00
fprintf ( stdout , " -n SectionAlign, --sectionalign SectionAlign \n \
SectionAlign points to section alignment , which support \ n \
2017-09-29 01:53:30 +02:00
the alignment scope 0 ~ 16 M . 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 " );
2009-07-17 11:10:31 +02:00
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 :
2017-09-20 08:10:04 +02:00
Converts Align String to align value ( 1 ~ 16 M ) .
2009-07-17 11:10:31 +02:00
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 ;
2018-07-05 11:40:04 +02:00
2009-07-17 11:10:31 +02:00
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 (
2015-07-27 15:50:19 +02:00
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
2009-07-17 11:10:31 +02:00
)
/*++
2018-07-05 11:40:04 +02:00
2009-07-17 11:10:31 +02:00
Routine Description :
2018-07-05 11:40:04 +02:00
2009-07-17 11:10:31 +02:00
Get the contents of all section files specified in InputFileName
into FileBuffer .
2018-07-05 11:40:04 +02:00
2009-07-17 11:10:31 +02:00
Arguments :
2018-07-05 11:40:04 +02:00
2009-07-17 11:10:31 +02:00
InputFileName - Name of the input file .
2018-07-05 11:40:04 +02:00
2009-07-17 11:10:31 +02:00
InputFileAlign - Alignment required by the input file data .
InputFileNum - Number of input files . Should be at least 1.
FileBuffer - Output buffer to contain data
2018-07-05 11:40:04 +02:00
BufferLength - On input , this is size of the FileBuffer .
2009-07-17 11:10:31 +02:00
On output , this is the actual length of the data .
MaxAlignment - The max alignment required by all the input file datas .
2018-07-05 11:40:04 +02:00
2009-07-17 11:10:31 +02:00
PeSectionNum - Calculate the number of Pe / Te Section in this FFS file .
Returns :
2018-07-05 11:40:04 +02:00
2009-07-17 11:10:31 +02:00
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 .
- - */
{
2015-07-27 15:50:19 +02:00
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 ;
2009-07-17 11:10:31 +02:00
//
// 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 + + ;
}
2018-07-05 11:40:04 +02:00
//
2009-07-17 11:10:31 +02:00
// Open file and read contents
//
2014-08-15 05:06:48 +02:00
InFile = fopen ( LongFilePath ( InputFileName [ Index ] ) , " rb " ) ;
2009-07-17 11:10:31 +02:00
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 ) ;
2018-07-05 11:40:04 +02:00
DebugMsg ( NULL , 0 , 9 , " Input section files " ,
" the input section name is %s and the size is %u bytes " , InputFileName [ Index ] , ( unsigned ) FileSize ) ;
2009-07-17 11:10:31 +02:00
//
// Check this section is Te/Pe section, and Calculate the numbers of Te/Pe section.
//
TeOffset = 0 ;
2013-11-18 08:41:21 +01:00
if ( FileSize > = MAX_FFS_SIZE ) {
HeaderSize = sizeof ( EFI_COMMON_SECTION_HEADER2 ) ;
} else {
HeaderSize = sizeof ( EFI_COMMON_SECTION_HEADER ) ;
}
fread ( & TempSectHeader , 1 , HeaderSize , InFile ) ;
2009-07-17 11:10:31 +02:00
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 ) + + ;
2010-03-01 00:39:39 +01:00
} else if ( TempSectHeader . Type = = EFI_SECTION_GUID_DEFINED ) {
fseek ( InFile , 0 , SEEK_SET ) ;
2013-11-18 08:41:21 +01:00
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 ;
}
2010-03-01 00:39:39 +01:00
}
( * PESectionNum ) + + ;
2018-07-05 11:40:04 +02:00
} else if ( TempSectHeader . Type = = EFI_SECTION_COMPRESSION | |
2009-07-17 11:10:31 +02:00
TempSectHeader . Type = = EFI_SECTION_FIRMWARE_VOLUME_IMAGE ) {
//
2018-07-05 11:40:04 +02:00
// for the encapsulated section, assume it contains Pe/Te section
2009-07-17 11:10:31 +02:00
//
( * 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 ] ;
}
2010-03-01 00:39:39 +01:00
2009-07-17 11:10:31 +02:00
//
2015-07-27 15:50:19 +02:00
// make sure section data meet its alignment requirement by adding one pad section.
2009-07-17 11:10:31 +02:00
// But the different sections have the different section header. Necessary or not?
// Based on section type to adjust offset? Todo
//
2010-03-01 00:39:39 +01:00
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 ;
2018-07-05 11:40:04 +02:00
2009-07-17 11:10:31 +02:00
if ( FileBuffer ! = NULL & & ( ( Size + Offset ) < * BufferLength ) ) {
2013-11-18 08:41:21 +01:00
//
// The maximal alignment is 64K, the raw section size must be less than 0xffffff
//
2010-03-01 00:39:39 +01:00
memset ( FileBuffer + Size , 0 , Offset ) ;
2015-07-27 15:50:19 +02:00
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 ;
}
2009-07-17 11:10:31 +02:00
}
2018-07-05 11:40:04 +02:00
DebugMsg ( NULL , 0 , 9 , " Pad raw section for section data alignment " ,
2009-09-11 05:14:43 +02:00
" Pad Raw section size is %u " , ( unsigned ) Offset ) ;
2009-07-17 11:10:31 +02:00
Size = Size + Offset ;
}
2015-07-27 15:50:19 +02:00
//
// Get the Max alignment of all input file datas
//
if ( MaxEncounteredAlignment < InputFileAlign [ Index ] ) {
MaxEncounteredAlignment = InputFileAlign [ Index ] ;
}
2009-07-17 11:10:31 +02:00
//
// 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 ;
}
2015-07-27 15:50:19 +02:00
* MaxAlignment = MaxEncounteredAlignment ;
2009-07-17 11:10:31 +02:00
//
// Set the actual length of the data.
//
if ( Size > * BufferLength ) {
* BufferLength = Size ;
return EFI_BUFFER_TOO_SMALL ;
} else {
* BufferLength = Size ;
return EFI_SUCCESS ;
}
}
2017-09-29 01:53:30 +02:00
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 ;
2017-12-05 17:10:15 +01:00
* Alignment = 0 ;
2017-09-29 01:53:30 +02:00
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 ;
}
2009-07-17 11:10:31 +02:00
int
main (
2009-09-11 05:14:43 +02:00
int argc ,
2009-07-17 11:10:31 +02:00
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 ;
2013-11-18 08:41:21 +01:00
EFI_FFS_FILE_HEADER2 FfsFileHeader ;
2009-07-17 11:10:31 +02:00
FILE * FfsFile ;
UINT32 Index ;
UINT64 LogLevel ;
UINT8 PeSectionNum ;
2013-11-18 08:41:21 +01:00
UINT32 HeaderSize ;
2017-09-29 01:53:30 +02:00
UINT32 Alignment ;
2017-12-18 08:52:33 +01:00
//
// 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 ] ;
2018-07-05 11:40:04 +02:00
2009-07-17 11:10:31 +02:00
//
// Init local variables
//
LogLevel = 0 ;
Index = 0 ;
2018-07-05 11:40:04 +02:00
FfsAttrib = 0 ;
2009-07-17 11:10:31 +02:00
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 ( ) ;
2018-07-05 11:40:04 +02:00
return STATUS_SUCCESS ;
2009-07-17 11:10:31 +02:00
}
if ( stricmp ( argv [ 0 ] , " --version " ) = = 0 ) {
Version ( ) ;
2018-07-05 11:40:04 +02:00
return STATUS_SUCCESS ;
2009-07-17 11:10:31 +02:00
}
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 ;
2018-07-05 11:40:04 +02:00
continue ;
2009-07-17 11:10:31 +02:00
}
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 ;
2018-07-05 11:40:04 +02:00
continue ;
2009-07-17 11:10:31 +02:00
}
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 ;
}
2019-04-03 04:17:02 +02:00
if ( ( stricmp ( argv [ 0 ] , " -oi " ) = = 0 ) | | ( stricmp ( argv [ 0 ] , " --optionalsectionfile " ) = = 0 ) | | ( stricmp ( argv [ 0 ] , " -i " ) = = 0 ) | | ( stricmp ( argv [ 0 ] , " --sectionfile " ) = = 0 ) ) {
2009-07-17 11:10:31 +02:00
//
// 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 ;
}
2019-04-03 04:17:02 +02:00
if ( ( stricmp ( argv [ 0 ] , " -oi " ) = = 0 ) | | ( stricmp ( argv [ 0 ] , " --optionalsectionfile " ) = = 0 ) ) {
if ( - 1 = = access ( argv [ 1 ] , 0 ) ) {
Warning ( NULL , 0 , 0001 , " File is not found. " , argv [ 1 ] ) ;
argc - = 2 ;
argv + = 2 ;
continue ;
}
}
2009-07-17 11:10:31 +02:00
//
// 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 * ) ) ) ;
2018-07-05 11:40:04 +02:00
2009-07-17 11:10:31 +02:00
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 * )
) ;
2018-07-05 11:40:04 +02:00
2009-07-17 11:10:31 +02:00
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 )
) ;
2018-07-05 11:40:04 +02:00
2009-07-17 11:10:31 +02:00
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 ) ) ) ;
}
2018-07-05 11:40:04 +02:00
2009-07-17 11:10:31 +02:00
InputFileName [ InputFileNum ] = argv [ 1 ] ;
argc - = 2 ;
argv + = 2 ;
if ( argc < = 0 ) {
2018-07-05 11:40:04 +02:00
InputFileNum + + ;
2009-07-17 11:10:31 +02:00
break ;
}
2018-07-05 11:40:04 +02:00
2009-07-17 11:10:31 +02:00
//
// Section File alignment requirement
//
if ( ( stricmp ( argv [ 0 ] , " -n " ) = = 0 ) | | ( stricmp ( argv [ 0 ] , " --sectionalign " ) = = 0 ) ) {
2017-09-29 01:53:30 +02:00
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 ) ;
}
2020-12-15 07:30:46 +01:00
else if ( Alignment > = 0x100000 ) {
sprintf ( AlignmentBuffer , " %dM " , Alignment / 0x100000 ) ;
}
else {
sprintf ( AlignmentBuffer , " %dK " , Alignment / 0x400 ) ;
2017-09-29 01:53:30 +02:00
}
Status = StringtoAlignment ( AlignmentBuffer , & ( InputFileAlign [ InputFileNum ] ) ) ;
}
else {
Status = StringtoAlignment ( argv [ 1 ] , & ( InputFileAlign [ InputFileNum ] ) ) ;
}
2009-07-17 11:10:31 +02:00
if ( EFI_ERROR ( Status ) ) {
Error ( NULL , 0 , 1003 , " Invalid option value " , " %s = %s " , argv [ 0 ] , argv [ 1 ] ) ;
goto Finish ;
}
argc - = 2 ;
argv + = 2 ;
}
InputFileNum + + ;
2018-07-05 11:40:04 +02:00
continue ;
2009-07-17 11:10:31 +02:00
}
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 ) {
2009-09-11 05:14:43 +02:00
Error ( NULL , 0 , 1003 , " Invalid option value " , " Debug Level range is 0-9, current input level is %d " , ( int ) LogLevel ) ;
2009-07-17 11:10:31 +02:00
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 ;
}
2017-07-19 04:55:47 +02:00
Error ( NULL , 0 , 1000 , " Unknown option " , " %s " , argv [ 0 ] ) ;
2009-07-17 11:10:31 +02:00
goto Finish ;
}
VerboseMsg ( " %s tool start. " , UTILITY_NAME ) ;
//
2016-10-19 09:01:07 +02:00
// Check the complete input parameters.
2009-07-17 11:10:31 +02:00
//
if ( FfsFiletype = = EFI_FV_FILETYPE_ALL ) {
Error ( NULL , 0 , 1001 , " Missing option " , " filetype " ) ;
2018-07-05 11:40:04 +02:00
goto Finish ;
2009-07-17 11:10:31 +02:00
}
if ( CompareGuid ( & FileGuid , & mZeroGuid ) = = 0 ) {
Error ( NULL , 0 , 1001 , " Missing option " , " fileguid " ) ;
2018-07-05 11:40:04 +02:00
goto Finish ;
2009-07-17 11:10:31 +02:00
}
if ( InputFileNum = = 0 ) {
Error ( NULL , 0 , 1001 , " Missing option " , " Input files " ) ;
goto Finish ;
}
2018-07-05 11:40:04 +02:00
2009-07-17 11:10:31 +02:00
//
// Output input parameter information
//
VerboseMsg ( " Fv File type is %s " , mFfsFileType [ FfsFiletype ] ) ;
VerboseMsg ( " Output file name is %s " , OutputFileName ) ;
2018-07-05 11:40:04 +02:00
VerboseMsg ( " FFS File Guid is %08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X " ,
2009-09-11 05:14:43 +02:00
( unsigned ) FileGuid . Data1 ,
2009-07-17 11:10:31 +02:00
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 ;
}
2009-09-11 05:14:43 +02:00
VerboseMsg ( " the %dth input section name is %s and section alignment is %u " , Index , InputFileName [ Index ] , ( unsigned ) InputFileAlign [ Index ] ) ;
2009-07-17 11:10:31 +02:00
}
2018-07-05 11:40:04 +02:00
2009-07-17 11:10:31 +02:00
//
// Calculate the size of all input section files.
2018-07-05 11:40:04 +02:00
//
2009-07-17 11:10:31 +02:00
Status = GetSectionContents (
InputFileName ,
InputFileAlign ,
InputFileNum ,
2015-07-27 15:50:19 +02:00
FfsAttrib ,
2009-07-17 11:10:31 +02:00
FileBuffer ,
& FileSize ,
& MaxAlignment ,
& PeSectionNum
) ;
2018-07-05 11:40:04 +02:00
if ( ( FfsFiletype = = EFI_FV_FILETYPE_SECURITY_CORE | |
2009-07-17 11:10:31 +02:00
FfsFiletype = = EFI_FV_FILETYPE_PEI_CORE | |
FfsFiletype = = EFI_FV_FILETYPE_DXE_CORE ) & & ( PeSectionNum ! = 1 ) ) {
2009-09-11 05:14:43 +02:00
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 ) ;
2009-07-17 11:10:31 +02:00
goto Finish ;
}
2018-07-05 11:40:04 +02:00
2009-07-17 11:10:31 +02:00
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 ] ) ;
2018-07-05 11:40:04 +02:00
goto Finish ;
2009-07-17 11:10:31 +02:00
}
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 ) ;
2018-07-05 11:40:04 +02:00
2009-07-17 11:10:31 +02:00
//
// read all input file contents into a buffer
//
Status = GetSectionContents (
InputFileName ,
InputFileAlign ,
InputFileNum ,
2015-07-27 15:50:19 +02:00
FfsAttrib ,
2009-07-17 11:10:31 +02:00
FileBuffer ,
& FileSize ,
& MaxAlignment ,
& PeSectionNum
) ;
}
2016-11-09 16:00:01 +01:00
if ( EFI_ERROR ( Status ) ) {
goto Finish ;
}
if ( FileBuffer = = NULL & & FileSize ! = 0 ) {
Error ( NULL , 0 , 4001 , " Resource " , " memory cannot be allocated! " ) ;
2009-07-17 11:10:31 +02:00
goto Finish ;
}
2018-07-05 11:40:04 +02:00
2009-07-17 11:10:31 +02:00
//
// Create Ffs file header.
//
2013-11-18 08:41:21 +01:00
memset ( & FfsFileHeader , 0 , sizeof ( EFI_FFS_FILE_HEADER2 ) ) ;
2009-07-17 11:10:31 +02:00
memcpy ( & FfsFileHeader . Name , & FileGuid , sizeof ( EFI_GUID ) ) ;
FfsFileHeader . Type = FfsFiletype ;
//
2018-07-05 11:40:04 +02:00
// Update FFS Alignment based on the max alignment required by input section files
2009-07-17 11:10:31 +02:00
//
2018-07-05 11:40:04 +02:00
VerboseMsg ( " the max alignment of all input sections is %u " , ( unsigned ) MaxAlignment ) ;
2009-07-17 11:10:31 +02:00
for ( Index = 0 ; Index < sizeof ( mFfsValidAlign ) / sizeof ( UINT32 ) - 1 ; Index + + ) {
if ( ( MaxAlignment > mFfsValidAlign [ Index ] ) & & ( MaxAlignment < = mFfsValidAlign [ Index + 1 ] ) ) {
break ;
}
}
if ( FfsAlign < Index ) {
FfsAlign = Index ;
}
2018-07-05 11:40:04 +02:00
VerboseMsg ( " the alignment of the generated FFS file is %u " , ( unsigned ) mFfsValidAlign [ FfsAlign + 1 ] ) ;
2009-07-17 11:10:31 +02:00
//
// Now FileSize includes the EFI_FFS_FILE_HEADER
//
2013-11-18 08:41:21 +01:00
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 ) ;
}
2009-09-11 05:14:43 +02:00
VerboseMsg ( " the size of the generated FFS file is %u bytes " , ( unsigned ) FileSize ) ;
2013-11-18 08:41:21 +01:00
2017-09-20 08:10:04 +02:00
//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 ) ;
}
2013-11-18 08:41:21 +01:00
2009-07-17 11:10:31 +02:00
//
// 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 ,
2013-11-18 08:41:21 +01:00
HeaderSize
2009-07-17 11:10:31 +02:00
) ;
if ( FfsFileHeader . Attributes & FFS_ATTRIB_CHECKSUM ) {
//
// Ffs header checksum = zero, so only need to calculate ffs body.
//
FfsFileHeader . IntegrityCheck . Checksum . File = CalculateChecksum8 (
2018-07-05 11:40:04 +02:00
FileBuffer ,
2013-11-18 08:41:21 +01:00
FileSize - HeaderSize
2018-07-05 11:40:04 +02:00
) ;
2009-07-17 11:10:31 +02:00
} else {
FfsFileHeader . IntegrityCheck . Checksum . File = FFS_FIXED_CHECKSUM ;
}
FfsFileHeader . State = EFI_FILE_HEADER_CONSTRUCTION | EFI_FILE_HEADER_VALID | EFI_FILE_DATA_VALID ;
2018-07-05 11:40:04 +02:00
2009-07-17 11:10:31 +02:00
//
// Open output file to write ffs data.
//
2016-10-11 04:13:26 +02:00
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
//
2016-11-09 16:00:01 +01:00
if ( FileBuffer ! = NULL ) {
fwrite ( FileBuffer , 1 , FileSize - HeaderSize , FfsFile ) ;
}
2009-07-17 11:10:31 +02:00
2016-10-11 04:13:26 +02:00
fclose ( FfsFile ) ;
}
2009-07-17 11:10:31 +02:00
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 ( ) ;
}