2009-07-17 11:10:31 +02:00
/**
2010-05-18 07:04:32 +02:00
Copyright ( c ) 2004 - 2010 , Intel Corporation . All rights reserved . < BR >
This program and the accompanying materials
2009-07-17 11:10:31 +02:00
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 .
Module Name :
GenFfs . c
Abstract :
This file contains functions required to generate a Firmware File System
file .
* */
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
# include <Common/UefiBaseTypes.h>
# include <Common/PiFirmwareFile.h>
# include <IndustryStandard/PeImage.h>
# include "CommonLib.h"
# include "ParseInf.h"
# include "EfiUtilityMsgs.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
} ;
STATIC CHAR8 * mAlignName [ ] = {
" 1 " , " 2 " , " 4 " , " 8 " , " 16 " , " 32 " , " 64 " , " 128 " , " 256 " , " 512 " ,
" 1K " , " 2K " , " 4K " , " 8K " , " 16K " , " 32K " , " 64K "
} ;
STATIC CHAR8 * mFfsValidAlignName [ ] = {
" 8 " , " 16 " , " 128 " , " 512 " , " 1K " , " 4K " , " 32K " , " 64K "
} ;
STATIC UINT32 mFfsValidAlign [ ] = { 0 , 8 , 16 , 128 , 512 , 1024 , 4096 , 32768 , 65536 } ;
STATIC EFI_GUID mZeroGuid = { 0 } ;
STATIC
VOID
Version (
VOID
)
/*++
Routine Description :
Print out version information for this utility .
Arguments :
None
Returns :
None
- - */
{
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 ) ;
//
// Copyright declaration
//
2010-03-01 00:39:39 +01:00
fprintf ( stdout , " Copyright (c) 2007 - 2010, 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 \
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 \
the following align : 1 , 2 , 4 , 8 , 16 , 128 , 512 , 1 K , 4 K , 32 K , 64 K \ 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 1 ~ 64 K . It is specified together \ n \
with sectionfile to point its 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 ~ 64 K ) .
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 ,
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_COMMON_SECTION_HEADER * SectHeader ;
EFI_COMMON_SECTION_HEADER TempSectHeader ;
EFI_TE_IMAGE_HEADER TeHeader ;
UINT32 TeOffset ;
2010-03-01 00:39:39 +01:00
EFI_GUID_DEFINED_SECTION GuidSectHeader ;
UINT32 HeaderSize ;
2009-07-17 11:10:31 +02:00
Size = 0 ;
Offset = 0 ;
TeOffset = 0 ;
//
// 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 + + ;
}
//
// Get the Max alignment of all input file datas
//
if ( * MaxAlignment < InputFileAlign [ Index ] ) {
* MaxAlignment = InputFileAlign [ Index ] ;
}
//
// Open file and read contents
//
InFile = fopen ( 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 " ,
2009-09-11 05:14:43 +02:00
" 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 ;
2010-03-01 00:39:39 +01:00
HeaderSize = sizeof ( EFI_COMMON_SECTION_HEADER ) ;
2009-07-17 11:10:31 +02:00
fread ( & TempSectHeader , 1 , sizeof ( TempSectHeader ) , 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 ) + + ;
2010-03-01 00:39:39 +01:00
} else if ( TempSectHeader . Type = = EFI_SECTION_GUID_DEFINED ) {
fseek ( InFile , 0 , SEEK_SET ) ;
fread ( & GuidSectHeader , 1 , sizeof ( GuidSectHeader ) , InFile ) ;
if ( ( GuidSectHeader . Attributes & EFI_GUIDED_SECTION_PROCESSING_REQUIRED ) = = 0 ) {
HeaderSize = GuidSectHeader . DataOffset ;
}
( * PESectionNum ) + + ;
2009-07-17 11:10:31 +02:00
} 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 ] ;
}
2010-03-01 00:39:39 +01:00
2009-07-17 11:10:31 +02:00
//
// make sure section data meet its alignment requirement by adding one raw pad section.
// 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 ;
2009-07-17 11:10:31 +02:00
if ( FileBuffer ! = NULL & & ( ( Size + Offset ) < * BufferLength ) ) {
2010-03-01 00:39:39 +01:00
memset ( FileBuffer + Size , 0 , Offset ) ;
2009-07-17 11:10:31 +02:00
SectHeader = ( EFI_COMMON_SECTION_HEADER * ) ( FileBuffer + Size ) ;
SectHeader - > Type = EFI_SECTION_RAW ;
SectHeader - > Size [ 0 ] = ( UINT8 ) ( Offset & 0xff ) ;
SectHeader - > Size [ 1 ] = ( UINT8 ) ( ( Offset & 0xff00 ) > > 8 ) ;
SectHeader - > Size [ 2 ] = ( UINT8 ) ( ( Offset & 0xff0000 ) > > 16 ) ;
}
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 ;
}
//
// 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 ;
}
//
// Set the actual length of the data.
//
if ( Size > * BufferLength ) {
* BufferLength = Size ;
return EFI_BUFFER_TOO_SMALL ;
} else {
* BufferLength = Size ;
return EFI_SUCCESS ;
}
}
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 ;
EFI_FFS_FILE_HEADER FfsFileHeader ;
FILE * FfsFile ;
UINT32 Index ;
UINT64 LogLevel ;
UINT8 PeSectionNum ;
//
// 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 ) ) {
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 ) {
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 ;
}
Error ( NULL , 0 , 1000 , " Unknown option " , argv [ 0 ] ) ;
goto Finish ;
}
VerboseMsg ( " %s tool start. " , UTILITY_NAME ) ;
//
// Check the complete input paramters.
//
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 " ,
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
}
//
// Calculate the size of all input section files.
//
Status = GetSectionContents (
InputFileName ,
InputFileAlign ,
InputFileNum ,
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 ) ) {
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 ;
}
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 ,
FileBuffer ,
& FileSize ,
& MaxAlignment ,
& PeSectionNum
) ;
}
if ( EFI_ERROR ( Status ) ) {
goto Finish ;
}
//
// Create Ffs file header.
//
memset ( & FfsFileHeader , 0 , sizeof ( EFI_FFS_FILE_HEADER ) ) ;
memcpy ( & FfsFileHeader . Name , & FileGuid , sizeof ( EFI_GUID ) ) ;
FfsFileHeader . Type = FfsFiletype ;
//
// Update FFS Alignment based on the max alignment required by input section files
//
2009-09-11 05:14:43 +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 ;
}
2009-09-11 05:14:43 +02:00
VerboseMsg ( " the alignment of the generated FFS file is %u " , ( unsigned ) mFfsValidAlign [ FfsAlign + 1 ] ) ;
FfsFileHeader . Attributes = ( EFI_FFS_FILE_ATTRIBUTES ) ( FfsAttrib | ( FfsAlign < < 3 ) ) ;
2009-07-17 11:10:31 +02:00
//
// Now FileSize includes the EFI_FFS_FILE_HEADER
//
FileSize + = sizeof ( EFI_FFS_FILE_HEADER ) ;
2009-09-11 05:14:43 +02:00
VerboseMsg ( " the size of the generated FFS file is %u bytes " , ( unsigned ) FileSize ) ;
2009-07-17 11:10:31 +02:00
FfsFileHeader . Size [ 0 ] = ( UINT8 ) ( FileSize & 0xFF ) ;
FfsFileHeader . Size [ 1 ] = ( UINT8 ) ( ( FileSize & 0xFF00 ) > > 8 ) ;
FfsFileHeader . Size [ 2 ] = ( UINT8 ) ( ( FileSize & 0xFF0000 ) > > 16 ) ;
//
// 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 ,
sizeof ( EFI_FFS_FILE_HEADER )
) ;
if ( FfsFileHeader . Attributes & FFS_ATTRIB_CHECKSUM ) {
//
// Ffs header checksum = zero, so only need to calculate ffs body.
//
FfsFileHeader . IntegrityCheck . Checksum . File = CalculateChecksum8 (
FileBuffer ,
FileSize - sizeof ( EFI_FFS_FILE_HEADER )
) ;
} 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.
//
remove ( OutputFileName ) ;
FfsFile = fopen ( OutputFileName , " wb " ) ;
if ( FfsFile = = NULL ) {
Error ( NULL , 0 , 0001 , " Error opening file " , OutputFileName ) ;
goto Finish ;
}
//
// write header
//
fwrite ( & FfsFileHeader , 1 , sizeof ( FfsFileHeader ) , FfsFile ) ;
//
// write data
//
fwrite ( FileBuffer , 1 , FileSize - sizeof ( EFI_FFS_FILE_HEADER ) , 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 ( ) ;
}