/** @file | |
This file contains functions required to generate a boot strap file (BSF) also | |
known as the Volume Top File (VTF) | |
Copyright (c) 1999 - 2016, 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. | |
**/ | |
// | |
// | |
// | |
#include <FvLib.h> | |
#include <Common/UefiBaseTypes.h> | |
#include "GenVtf.h" | |
#include <Guid/PiFirmwareFileSystem.h> | |
#include "CommonLib.h" | |
#include "EfiUtilityMsgs.h" | |
// | |
// Global variables | |
// | |
UINTN SectionOptionFlag = 0; | |
UINTN SectionCompFlag = 0; | |
UINT64 DebugLevel; | |
BOOLEAN DebugMode; | |
BOOLEAN QuietMode = FALSE; | |
BOOLEAN VTF_OUTPUT = FALSE; | |
CHAR8 *OutFileName1; | |
CHAR8 *OutFileName2; | |
CHAR8 *SymFileName; | |
CHAR8 **TokenStr; | |
CHAR8 **OrgStrTokPtr; | |
PARSED_VTF_INFO *FileListPtr; | |
PARSED_VTF_INFO *FileListHeadPtr; | |
VOID *Vtf1Buffer; | |
VOID *Vtf1EndBuffer; | |
VOID *Vtf2Buffer; | |
VOID *Vtf2EndBuffer; | |
UINTN ValidLineNum = 0; | |
UINTN ValidFFDFileListNum = 0; | |
// | |
// Section Description and their number of occurences in *.INF file | |
// | |
UINTN NumFvFiles = 0; | |
UINTN SectionOptionNum = 0; | |
// | |
// Global flag which will check for VTF Present, if yes then will be used | |
// to decide about adding FFS header to pad data | |
// | |
BOOLEAN VTFPresent = FALSE; | |
BOOLEAN SecondVTF = FALSE; | |
// | |
// Address related information | |
// | |
UINT64 Fv1BaseAddress = 0; | |
UINT64 Fv2BaseAddress = 0; | |
UINT64 Fv1EndAddress = 0; | |
UINT64 Fv2EndAddress = 0; | |
UINT32 Vtf1TotalSize = SIZE_TO_OFFSET_PAL_A_END; | |
UINT64 Vtf1LastStartAddress = 0; | |
UINT32 Vtf2TotalSize = 0; | |
UINT64 Vtf2LastStartAddress = 0; | |
UINT32 BufferToTop = 0; | |
// | |
// IA32 Reset Vector Bin name | |
// | |
CHAR8 IA32BinFile[FILE_NAME_SIZE]; | |
// | |
// Function Implementations | |
// | |
EFI_STATUS | |
ConvertVersionInfo ( | |
IN CHAR8 *Str, | |
IN OUT UINT8 *MajorVer, | |
IN OUT UINT8 *MinorVer | |
) | |
/*++ | |
Routine Description: | |
This function split version to major version and minor version | |
Arguments: | |
Str - String representing in form XX.XX | |
MajorVer - The major version | |
MinorVer - The minor version | |
Returns: | |
EFI_SUCCESS - The function completed successfully. | |
--*/ | |
{ | |
CHAR8 TemStr[5] = "0000"; | |
int Major; | |
int Minor; | |
UINTN Length; | |
Major = 0; | |
Minor = 0; | |
if (strstr (Str, ".") != NULL) { | |
sscanf ( | |
Str, | |
"%02x.%02x", | |
&Major, | |
&Minor | |
); | |
} else { | |
Length = strlen(Str); | |
if (Length < 4) { | |
strncpy (TemStr + 4 - Length, Str, Length); | |
} else { | |
strncpy (TemStr, Str + Length - 4, 4); | |
} | |
sscanf ( | |
TemStr, | |
"%02x%02x", | |
&Major, | |
&Minor | |
); | |
} | |
*MajorVer = (UINT8) Major; | |
*MinorVer = (UINT8) Minor; | |
return EFI_SUCCESS; | |
} | |
VOID | |
TrimLine ( | |
IN CHAR8 *Line | |
) | |
/*++ | |
Routine Description: | |
This function cleans up the line by removing all whitespace and | |
comments | |
Arguments: | |
Line - The pointer of the string | |
Returns: | |
None | |
--*/ | |
{ | |
CHAR8 TmpLine[FILE_NAME_SIZE]; | |
CHAR8 Char; | |
CHAR8 *Ptr0; | |
UINTN Index; | |
UINTN Index2; | |
// | |
// Change '#' to '//' for Comment style | |
// | |
if (((Ptr0 = strchr (Line, '#')) != NULL) || ((Ptr0 = strstr (Line, "//")) != NULL)) { | |
Line[Ptr0 - Line] = 0; | |
} | |
// | |
// Initialize counters | |
// | |
Index = 0; | |
Index2 = 0; | |
while ((Char = Line[Index]) != 0) { | |
if ((Char != ' ') && (Char != '\t') && (Char != '\n') && (Char != '\r')) { | |
TmpLine[Index2++] = Char; | |
} | |
Index++; | |
} | |
TmpLine[Index2] = 0; | |
strcpy (Line, TmpLine); | |
} | |
VOID | |
ValidLineCount ( | |
IN FILE *Fp | |
) | |
/*++ | |
Routine Description: | |
This function calculated number of valid lines in a input file. | |
Arguments: | |
Fp - Pointer to a file handle which has been opened. | |
Returns: | |
None | |
--*/ | |
{ | |
CHAR8 Buff[FILE_NAME_SIZE]; | |
while (fgets(Buff, sizeof (Buff), Fp)) { | |
TrimLine (Buff); | |
if (Buff[0] == 0) { | |
continue; | |
} | |
ValidLineNum++; | |
} | |
} | |
EFI_STATUS | |
ParseInputFile ( | |
IN FILE *Fp | |
) | |
/*++ | |
Routine Description: | |
This function parses the input file and tokenize the string | |
Arguments: | |
Fp - Pointer to a file handle which has been opened. | |
Returns: | |
None | |
--*/ | |
{ | |
CHAR8 *Token; | |
CHAR8 Buff[FILE_NAME_SIZE + 1]; | |
CHAR8 Delimit[] = "="; | |
Buff [FILE_NAME_SIZE] = '\0'; | |
Token = NULL; | |
while (fgets (Buff, FILE_NAME_SIZE, Fp) != NULL) { | |
TrimLine (Buff); | |
if (Buff[0] == 0) { | |
continue; | |
} | |
Token = strtok (Buff, Delimit); | |
while (Token != NULL) { | |
strcpy (*TokenStr, Token); | |
TokenStr ++; | |
Token = strtok (NULL, Delimit); | |
} | |
} | |
return EFI_SUCCESS; | |
} | |
EFI_STATUS | |
InitializeComps ( | |
VOID | |
) | |
/*++ | |
Routine Description: | |
This function initializes the relevant global variable which is being | |
used to store the information retrieved from INF file. This also initializes | |
the VTF symbol file. | |
Arguments: | |
None | |
Returns: | |
EFI_SUCCESS - The function completed successfully | |
EFI_OUT_OF_RESOURCES - Malloc failed. | |
--*/ | |
{ | |
FileListPtr = malloc (sizeof (PARSED_VTF_INFO)); | |
if (FileListPtr == NULL) { | |
return EFI_OUT_OF_RESOURCES; | |
} | |
FileListHeadPtr = FileListPtr; | |
memset (FileListPtr, 0, sizeof (PARSED_VTF_INFO)); | |
FileListPtr->NextVtfInfo = NULL; | |
remove (SymFileName); | |
return EFI_SUCCESS; | |
} | |
VOID | |
ParseAndUpdateComponents ( | |
IN PARSED_VTF_INFO *VtfInfo | |
) | |
/*++ | |
Routine Description: | |
This function initializes the relevant global variable which is being | |
used to store the information retrieved from INF file. | |
Arguments: | |
VtfInfo - A pointer to the VTF Info Structure | |
Returns: | |
None | |
--*/ | |
{ | |
UINT64 StringValue; | |
while (*TokenStr != NULL && (strnicmp (*TokenStr, "COMP_NAME", 9) != 0)) { | |
if (strnicmp (*TokenStr, "COMP_LOC", 8) == 0) { | |
TokenStr++; | |
if (strnicmp (*TokenStr, "F", 1) == 0) { | |
VtfInfo->LocationType = FIRST_VTF; | |
} else if (strnicmp (*TokenStr, "S", 1) == 0) { | |
VtfInfo->LocationType = SECOND_VTF; | |
} else { | |
VtfInfo->LocationType = NONE; | |
} | |
} else if (strnicmp (*TokenStr, "COMP_TYPE", 9) == 0) { | |
TokenStr++; | |
if (AsciiStringToUint64 (*TokenStr, FALSE, &StringValue) != EFI_SUCCESS) { | |
Error (NULL, 0, 5001, "Cannot get: \"0x%s\".", *TokenStr); | |
return ; | |
} | |
VtfInfo->CompType = (UINT8) StringValue; | |
} else if (strnicmp (*TokenStr, "COMP_VER", 8) == 0) { | |
TokenStr++; | |
if (strnicmp (*TokenStr, "-", 1) == 0) { | |
VtfInfo->VersionPresent = FALSE; | |
VtfInfo->MajorVer = 0; | |
VtfInfo->MinorVer = 0; | |
} else { | |
VtfInfo->VersionPresent = TRUE; | |
ConvertVersionInfo (*TokenStr, &VtfInfo->MajorVer, &VtfInfo->MinorVer); | |
} | |
} else if (strnicmp (*TokenStr, "COMP_BIN", 8) == 0) { | |
TokenStr++; | |
strcpy (VtfInfo->CompBinName, *TokenStr); | |
} else if (strnicmp (*TokenStr, "COMP_SYM", 8) == 0) { | |
TokenStr++; | |
strcpy (VtfInfo->CompSymName, *TokenStr); | |
} else if (strnicmp (*TokenStr, "COMP_SIZE", 9) == 0) { | |
TokenStr++; | |
if (strnicmp (*TokenStr, "-", 1) == 0) { | |
VtfInfo->PreferredSize = FALSE; | |
VtfInfo->CompSize = 0; | |
} else { | |
VtfInfo->PreferredSize = TRUE; | |
if (AsciiStringToUint64 (*TokenStr, FALSE, &StringValue) != EFI_SUCCESS) { | |
Error (NULL, 0, 5001, "Parse error", "Cannot get: %s.", TokenStr); | |
return ; | |
} | |
VtfInfo->CompSize = (UINTN) StringValue; | |
} | |
} else if (strnicmp (*TokenStr, "COMP_CS", 7) == 0) { | |
TokenStr++; | |
if (strnicmp (*TokenStr, "1", 1) == 0) { | |
VtfInfo->CheckSumRequired = 1; | |
} else if (strnicmp (*TokenStr, "0", 1) == 0) { | |
VtfInfo->CheckSumRequired = 0; | |
} else { | |
Error (NULL, 0, 3000, "Invaild", "Bad value in INF file required field: Checksum, the value must be '0' or '1'."); | |
} | |
} | |
TokenStr++; | |
if (*TokenStr == NULL) { | |
break; | |
} | |
} | |
} | |
VOID | |
InitializeInFileInfo ( | |
VOID | |
) | |
/*++ | |
Routine Description: | |
This function intializes the relevant global variable which is being | |
used to store the information retrieved from INF file. | |
Arguments: | |
NONE | |
Returns: | |
NONE | |
--*/ | |
{ | |
SectionOptionFlag = 0; | |
SectionCompFlag = 0; | |
TokenStr = OrgStrTokPtr; | |
while (*TokenStr != NULL) { | |
if (strnicmp (*TokenStr, "[OPTIONS]", 9) == 0) { | |
SectionOptionFlag = 1; | |
SectionCompFlag = 0; | |
} | |
if (strnicmp (*TokenStr, "[COMPONENTS]", 12) == 0) { | |
if (FileListPtr == NULL) { | |
FileListPtr = FileListHeadPtr; | |
} | |
SectionCompFlag = 1; | |
SectionOptionFlag = 0; | |
TokenStr++; | |
} | |
if (SectionOptionFlag) { | |
if (stricmp (*TokenStr, "IA32_RST_BIN") == 0) { | |
TokenStr++; | |
strcpy (IA32BinFile, *TokenStr); | |
} | |
} | |
if (SectionCompFlag) { | |
if (stricmp (*TokenStr, "COMP_NAME") == 0) { | |
TokenStr++; | |
strcpy (FileListPtr->CompName, *TokenStr); | |
TokenStr++; | |
ParseAndUpdateComponents (FileListPtr); | |
} | |
if (*TokenStr != NULL) { | |
FileListPtr->NextVtfInfo = malloc (sizeof (PARSED_VTF_INFO)); | |
if (FileListPtr->NextVtfInfo == NULL) { | |
Error (NULL, 0, 4003, "Resource", "Out of memory resources.", NULL); | |
break; | |
} | |
FileListPtr = FileListPtr->NextVtfInfo; | |
memset (FileListPtr, 0, sizeof (PARSED_VTF_INFO)); | |
FileListPtr->NextVtfInfo = NULL; | |
continue; | |
} else { | |
break; | |
} | |
} | |
TokenStr++; | |
} | |
} | |
EFI_STATUS | |
GetVtfRelatedInfoFromInfFile ( | |
IN FILE *FilePointer | |
) | |
/*++ | |
Routine Description: | |
This function reads the input file, parse it and create a list of tokens | |
which is parsed and used, to intialize the data related to VTF | |
Arguments: | |
FileName - FileName which needed to be read to parse data | |
Returns: | |
EFI_ABORTED - Error in opening file | |
EFI_INVALID_PARAMETER - File doesn't contain any valid information | |
EFI_OUT_OF_RESOURCES - Malloc Failed | |
EFI_SUCCESS - The function completed successfully | |
--*/ | |
{ | |
FILE *Fp; | |
UINTN Index; | |
UINTN Index1; | |
EFI_STATUS Status; | |
Status = EFI_SUCCESS; | |
Fp = FilePointer; | |
if (Fp == NULL) { | |
Error (NULL, 0, 2000, "Invalid parameter", "BSF INF file is invalid!"); | |
return EFI_ABORTED; | |
} | |
ValidLineCount (Fp); | |
if (ValidLineNum == 0) { | |
Error (NULL, 0, 2000, "Invalid parameter", "File does not contain any valid information!"); | |
return EFI_INVALID_PARAMETER; | |
} | |
TokenStr = (CHAR8 **) malloc (sizeof (UINTN) * (2 * ValidLineNum + 1)); | |
if (TokenStr == NULL) { | |
return EFI_OUT_OF_RESOURCES; | |
} | |
memset (TokenStr, 0, (sizeof (UINTN) * (2 * ValidLineNum + 1))); | |
OrgStrTokPtr = TokenStr; | |
for (Index = 0; Index < (2 * ValidLineNum); Index++) { | |
*TokenStr = (CHAR8*)malloc (sizeof (CHAR8) * FILE_NAME_SIZE); | |
if (*TokenStr == NULL) { | |
Status = EFI_OUT_OF_RESOURCES; | |
goto ParseFileError; | |
} | |
memset (*TokenStr, 0, FILE_NAME_SIZE); | |
TokenStr++; | |
} | |
TokenStr = OrgStrTokPtr; | |
fseek (Fp, 0L, SEEK_SET); | |
Status = InitializeComps (); | |
if (Status != EFI_SUCCESS) { | |
goto ParseFileError; | |
} | |
Status = ParseInputFile (Fp); | |
if (Status != EFI_SUCCESS) { | |
goto ParseFileError; | |
} | |
InitializeInFileInfo (); | |
ParseFileError: | |
for (Index1 = 0; Index1 < Index; Index1 ++) { | |
free (OrgStrTokPtr[Index1]); | |
} | |
free (OrgStrTokPtr); | |
return Status; | |
} | |
VOID | |
GetRelativeAddressInVtfBuffer ( | |
IN UINT64 Address, | |
IN OUT UINTN *RelativeAddress, | |
IN LOC_TYPE LocType | |
) | |
/*++ | |
Routine Description: | |
This function checks for the address alignmnet for specified data boundary. In | |
case the address is not aligned, it returns FALSE and the amount of data in | |
terms of byte needed to adjust to get the boundary alignmnet. If data is | |
aligned, TRUE will be returned. | |
Arguments: | |
Address - The address of the flash map space | |
RelativeAddress - The relative address of the Buffer | |
LocType - The type of the VTF | |
Returns: | |
--*/ | |
{ | |
UINT64 TempAddress; | |
UINT8 *LocalBuff; | |
if (LocType == FIRST_VTF) { | |
LocalBuff = (UINT8 *) Vtf1EndBuffer; | |
TempAddress = Fv1EndAddress - Address; | |
*RelativeAddress = (UINTN) LocalBuff - (UINTN) TempAddress; | |
} else { | |
LocalBuff = (UINT8 *) Vtf2EndBuffer; | |
TempAddress = Fv2EndAddress - Address; | |
*RelativeAddress = (UINTN) LocalBuff - (UINTN) TempAddress; | |
} | |
} | |
EFI_STATUS | |
GetComponentVersionInfo ( | |
IN OUT PARSED_VTF_INFO *VtfInfo, | |
IN UINT8 *Buffer | |
) | |
/*++ | |
Routine Description: | |
This function will extract the version information from File | |
Arguments: | |
VtfInfo - A Pointer to the VTF Info Structure | |
Buffer - A Pointer to type UINT8 | |
Returns: | |
EFI_SUCCESS - The function completed successfully | |
EFI_INVALID_PARAMETER - The parameter is invalid | |
--*/ | |
{ | |
UINT16 VersionInfo; | |
EFI_STATUS Status; | |
switch (VtfInfo->CompType) { | |
case COMP_TYPE_FIT_PAL_A: | |
case COMP_TYPE_FIT_PAL_B: | |
memcpy (&VersionInfo, (Buffer + 8), sizeof (UINT16)); | |
VtfInfo->MajorVer = (UINT8) ((VersionInfo & 0xFF00) >> 8); | |
VtfInfo->MinorVer = (UINT8) (VersionInfo & 0x00FF); | |
Status = EFI_SUCCESS; | |
break; | |
default: | |
Status = EFI_INVALID_PARAMETER; | |
break; | |
} | |
return Status; | |
} | |
BOOLEAN | |
CheckAddressAlignment ( | |
IN UINT64 Address, | |
IN UINT64 AlignmentData, | |
IN OUT UINT64 *AlignAdjustByte | |
) | |
/*++ | |
Routine Description: | |
This function checks for the address alignmnet for specified data boundary. In | |
case the address is not aligned, it returns FALSE and the amount of data in | |
terms of byte needed to adjust to get the boundary alignmnet. If data is | |
aligned, TRUE will be returned. | |
Arguments: | |
Address - Pointer to buffer containing byte data of component. | |
AlignmentData - DataSize for which address needed to be aligned | |
AlignAdjustByte - Number of bytes needed to adjust alignment. | |
Returns: | |
TRUE - Address is aligned to specific data size boundary | |
FALSE - Address in not aligned to specified data size boundary | |
- Add/Subtract AlignAdjustByte to aling the address. | |
--*/ | |
{ | |
// | |
// Check if the assigned address is on address boundary. If not, it will | |
// return the remaining byte required to adjust the address for specified | |
// address boundary | |
// | |
*AlignAdjustByte = (Address % AlignmentData); | |
if (*AlignAdjustByte == 0) { | |
return TRUE; | |
} else { | |
return FALSE; | |
} | |
} | |
EFI_STATUS | |
GetFitTableStartAddress ( | |
IN OUT FIT_TABLE **FitTable | |
) | |
/*++ | |
Routine Description: | |
Get the FIT table start address in VTF Buffer | |
Arguments: | |
FitTable - Pointer to available fit table where new component can be added | |
Returns: | |
EFI_SUCCESS - The function completed successfully | |
--*/ | |
{ | |
UINT64 FitTableAdd; | |
UINT64 FitTableAddOffset; | |
UINTN RelativeAddress; | |
// | |
// Read the Fit Table address from Itanium-based address map. | |
// | |
FitTableAddOffset = Fv1EndAddress - (SIZE_IA32_RESET_VECT + SIZE_SALE_ENTRY_POINT + SIZE_FIT_TABLE_ADD); | |
// | |
// Translate this Itanium-based address in terms of local buffer address which | |
// contains the image for Boot Strapped File. The relative address will be | |
// the address of fit table VTF buffer. | |
// | |
GetRelativeAddressInVtfBuffer (FitTableAddOffset, &RelativeAddress, FIRST_VTF); | |
FitTableAdd = *(UINTN *) RelativeAddress; | |
// | |
// The FitTableAdd is the extracted Itanium based address pointing to FIT | |
// table. The relative address will return its actual location in VTF | |
// Buffer. | |
// | |
GetRelativeAddressInVtfBuffer (FitTableAdd, &RelativeAddress, FIRST_VTF); | |
*FitTable = (FIT_TABLE *) RelativeAddress; | |
return EFI_SUCCESS; | |
} | |
EFI_STATUS | |
GetNextAvailableFitPtr ( | |
IN FIT_TABLE **FitPtr | |
) | |
/*++ | |
Routine Description: | |
Get the FIT table address and locate the free space in fit where we can add | |
new component. In this process, this function locates the fit table using | |
Fit pointer in Itanium-based address map (as per Intel?Itanium(TM) SAL spec) | |
and locate the available location in FIT table to be used by new components. | |
If there are any Fit table which areg not being used contains ComponentType | |
field as 0x7F. If needed we can change this and spec this out. | |
Arguments: | |
FitPtr - Pointer to available fit table where new component can be added | |
Returns: | |
EFI_SUCCESS - The function completed successfully | |
--*/ | |
{ | |
FIT_TABLE *TmpFitPtr; | |
UINT64 FitTableAdd; | |
UINT64 FitTableAddOffset; | |
UINTN Index; | |
UINTN NumFitComponents; | |
UINTN RelativeAddress; | |
// | |
// Read the Fit Table address from Itanium-based address map. | |
// | |
FitTableAddOffset = Fv1EndAddress - (SIZE_IA32_RESET_VECT + SIZE_SALE_ENTRY_POINT + SIZE_FIT_TABLE_ADD); | |
// | |
// Translate this Itanium-based address in terms of local buffer address which | |
// contains the image for Boot Strapped File. The relative address will be | |
// the address of fit table VTF buffer. | |
// | |
GetRelativeAddressInVtfBuffer (FitTableAddOffset, &RelativeAddress, FIRST_VTF); | |
FitTableAdd = *(UINTN *) RelativeAddress; | |
// | |
// The FitTableAdd is the extracted Itanium based address pointing to FIT | |
// table. The relative address will return its actual location in VTF | |
// Buffer. | |
// | |
GetRelativeAddressInVtfBuffer (FitTableAdd, &RelativeAddress, FIRST_VTF); | |
TmpFitPtr = (FIT_TABLE *) RelativeAddress; | |
NumFitComponents = TmpFitPtr->CompSize; | |
*FitPtr = NULL; | |
for (Index = 0; Index < NumFitComponents; Index++) { | |
if ((TmpFitPtr->CvAndType & FIT_TYPE_MASK) == COMP_TYPE_FIT_UNUSED) { | |
*FitPtr = TmpFitPtr; | |
break; | |
} | |
TmpFitPtr++; | |
} | |
return EFI_SUCCESS; | |
} | |
int | |
CompareItems ( | |
IN const VOID *Arg1, | |
IN const VOID *Arg2 | |
) | |
/*++ | |
Routine Description: | |
This function is used by qsort to sort the FIT table based upon Component | |
Type in their incresing order. | |
Arguments: | |
Arg1 - Pointer to Arg1 | |
Arg2 - Pointer to Arg2 | |
Returns: | |
None | |
--*/ | |
{ | |
if ((((FIT_TABLE *) Arg1)->CvAndType & FIT_TYPE_MASK) > (((FIT_TABLE *) Arg2)->CvAndType & FIT_TYPE_MASK)) { | |
return 1; | |
} else if ((((FIT_TABLE *) Arg1)->CvAndType & FIT_TYPE_MASK) < (((FIT_TABLE *) Arg2)->CvAndType & FIT_TYPE_MASK)) { | |
return -1; | |
} else { | |
return 0; | |
} | |
} | |
VOID | |
SortFitTable ( | |
IN VOID | |
) | |
/*++ | |
Routine Description: | |
This function is used by qsort to sort the FIT table based upon Component | |
Type in their incresing order. | |
Arguments: | |
VOID | |
Returns: | |
None | |
--*/ | |
{ | |
FIT_TABLE *FitTable; | |
FIT_TABLE *TmpFitPtr; | |
UINTN NumFitComponents; | |
UINTN Index; | |
GetFitTableStartAddress (&FitTable); | |
TmpFitPtr = FitTable; | |
NumFitComponents = 0; | |
for (Index = 0; Index < FitTable->CompSize; Index++) { | |
if ((TmpFitPtr->CvAndType & FIT_TYPE_MASK) != COMP_TYPE_FIT_UNUSED) { | |
NumFitComponents += 1; | |
} | |
TmpFitPtr++; | |
} | |
qsort ((VOID *) FitTable, NumFitComponents, sizeof (FIT_TABLE), CompareItems); | |
} | |
VOID | |
UpdateFitEntryForFwVolume ( | |
IN UINT64 Size | |
) | |
/*++ | |
Routine Description: | |
This function updates the information about Firmware Volume in FIT TABLE. | |
This FIT table has to be immediately below the PAL_A Start and it contains | |
component type and address information. Other information can't be | |
created this time so we would need to fix it up.. | |
Arguments: | |
Size - Firmware Volume Size | |
Returns: | |
VOID | |
--*/ | |
{ | |
FIT_TABLE *CompFitPtr; | |
UINTN RelativeAddress; | |
// | |
// FV Fit table will be located at PAL_A Startaddress - 16 byte location | |
// | |
Vtf1LastStartAddress -= 0x10; | |
Vtf1TotalSize += 0x10; | |
GetRelativeAddressInVtfBuffer (Vtf1LastStartAddress, &RelativeAddress, FIRST_VTF); | |
CompFitPtr = (FIT_TABLE *) RelativeAddress; | |
CompFitPtr->CompAddress = Fv1BaseAddress; | |
// | |
// Since we don't have any information about its location in Firmware Volume, | |
// initialize address to 0. This will be updated once Firmware Volume is | |
// being build and its current address will be fixed in FIT table. Currently | |
// we haven't implemented it so far and working on architectural clarafication | |
// | |
// | |
// Firmware Volume Size in 16 byte block | |
// | |
CompFitPtr->CompSize = ((UINT32) Size) / 16; | |
// | |
// Since Firmware Volume does not exist by the time we create this FIT info | |
// this should be fixedup from Firmware Volume creation tool. We haven't | |
// worked out a method so far. | |
// | |
CompFitPtr->CompVersion = MAKE_VERSION (0, 0); | |
// | |
// Since we don't have any info about this file, we are making sure that | |
// checksum is not needed. | |
// | |
CompFitPtr->CvAndType = CV_N_TYPE (0, COMP_TYPE_FIT_FV_BOOT); | |
// | |
// Since non VTF component will reside outside the VTF, we will not have its | |
// binary image while creating VTF, hence we will not perform checksum at | |
// this time. Once Firmware Volume is being created which will contain this | |
// VTF, it will fix the FIT table for all the non VTF component and hence | |
// checksum | |
// | |
CompFitPtr->CheckSum = 0; | |
} | |
EFI_STATUS | |
UpdateFitEntryForNonVTFComp ( | |
IN PARSED_VTF_INFO *VtfInfo | |
) | |
/*++ | |
Routine Description: | |
This function updates the information about non VTF component in FIT TABLE. | |
Since non VTF componets binaries are not part of VTF binary, we would still | |
be required to update its location information in Firmware Volume, inside | |
FIT table. | |
Arguments: | |
VtfInfo - Pointer to VTF Info Structure | |
Returns: | |
EFI_ABORTED - The function fails to update the component in FIT | |
EFI_SUCCESS - The function completed successfully | |
--*/ | |
{ | |
FIT_TABLE *CompFitPtr; | |
// | |
// Scan the FIT table for available space | |
// | |
GetNextAvailableFitPtr (&CompFitPtr); | |
if (CompFitPtr == NULL) { | |
Error (NULL, 0, 5003, "Invalid", "Can't update this component in FIT"); | |
return EFI_ABORTED; | |
} | |
// | |
// Since we don't have any information about its location in Firmware Volume, | |
// initialize address to 0. This will be updated once Firmware Volume is | |
// being build and its current address will be fixed in FIT table | |
// | |
CompFitPtr->CompAddress = 0; | |
CompFitPtr->CompSize = VtfInfo->CompSize; | |
CompFitPtr->CompVersion = MAKE_VERSION (VtfInfo->MajorVer, VtfInfo->MinorVer); | |
CompFitPtr->CvAndType = CV_N_TYPE (VtfInfo->CheckSumRequired, VtfInfo->CompType); | |
// | |
// Since non VTF component will reside outside the VTF, we will not have its | |
// binary image while creating VTF, hence we will not perform checksum at | |
// this time. Once Firmware Volume is being created which will contain this | |
// VTF, it will fix the FIT table for all the non VTF component and hence | |
// checksum | |
// | |
CompFitPtr->CheckSum = 0; | |
// | |
// Fit Type is FV_BOOT which means Firmware Volume, we initialize this to base | |
// address of Firmware Volume in which this VTF will be attached. | |
// | |
if ((CompFitPtr->CvAndType & 0x7F) == COMP_TYPE_FIT_FV_BOOT) { | |
CompFitPtr->CompAddress = Fv1BaseAddress; | |
} | |
return EFI_SUCCESS; | |
} | |
// | |
// !!!WARNING | |
// This function is updating the SALE_ENTRY in Itanium address space as per SAL | |
// spec. SALE_ENTRY is being read from SYM file of PEICORE. Once the PEI | |
// CORE moves in Firmware Volume, we would need to modify this function to be | |
// used with a API which will detect PEICORE component while building Firmware | |
// Volume and update its entry in FIT table as well as in Itanium address space | |
// as per Intel?Itanium(TM) SAL address space | |
// | |
EFI_STATUS | |
UpdateEntryPoint ( | |
IN PARSED_VTF_INFO *VtfInfo, | |
IN UINT64 *CompStartAddress | |
) | |
/*++ | |
Routine Description: | |
This function updated the architectural entry point in IPF, SALE_ENTRY. | |
Arguments: | |
VtfInfo - Pointer to VTF Info Structure | |
CompStartAddress - Pointer to Component Start Address | |
Returns: | |
EFI_INVALID_PARAMETER - The parameter is invalid | |
EFI_OUT_OF_RESOURCES - Resource can not be allocated | |
EFI_SUCCESS - The function completed successfully | |
--*/ | |
{ | |
UINTN RelativeAddress; | |
UINT64 SalEntryAdd; | |
FILE *Fp; | |
UINTN Offset; | |
CHAR8 Buff[FILE_NAME_SIZE]; | |
CHAR8 Buff1[10]; | |
CHAR8 Buff2[10]; | |
CHAR8 OffsetStr[30]; | |
CHAR8 Buff3[10]; | |
CHAR8 Buff4[10]; | |
CHAR8 Buff5[10]; | |
CHAR8 Token[50]; | |
CHAR8 *FormatString; | |
INTN FormatLength; | |
Fp = fopen (LongFilePath (VtfInfo->CompSymName), "rb"); | |
if (Fp == NULL) { | |
Error (NULL, 0, 0001, "Error opening file", VtfInfo->CompSymName); | |
return EFI_INVALID_PARAMETER; | |
} | |
// | |
// Generate the format string for fscanf | |
// | |
FormatLength = snprintf ( | |
NULL, | |
0, | |
"%%%us %%%us %%%us %%%us %%%us %%%us %%%us", | |
(unsigned) sizeof (Buff1) - 1, | |
(unsigned) sizeof (Buff2) - 1, | |
(unsigned) sizeof (OffsetStr) - 1, | |
(unsigned) sizeof (Buff3) - 1, | |
(unsigned) sizeof (Buff4) - 1, | |
(unsigned) sizeof (Buff5) - 1, | |
(unsigned) sizeof (Token) - 1 | |
) + 1; | |
FormatString = (CHAR8 *) malloc (FormatLength); | |
if (FormatString == NULL) { | |
fclose (Fp); | |
Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!"); | |
return EFI_OUT_OF_RESOURCES; | |
} | |
snprintf ( | |
FormatString, | |
FormatLength, | |
"%%%us %%%us %%%us %%%us %%%us %%%us %%%us", | |
(unsigned) sizeof (Buff1) - 1, | |
(unsigned) sizeof (Buff2) - 1, | |
(unsigned) sizeof (OffsetStr) - 1, | |
(unsigned) sizeof (Buff3) - 1, | |
(unsigned) sizeof (Buff4) - 1, | |
(unsigned) sizeof (Buff5) - 1, | |
(unsigned) sizeof (Token) - 1 | |
); | |
while (fgets (Buff, sizeof (Buff), Fp) != NULL) { | |
fscanf ( | |
Fp, | |
FormatString, | |
Buff1, | |
Buff2, | |
OffsetStr, | |
Buff3, | |
Buff4, | |
Buff5, | |
Token | |
); | |
if (strnicmp (Token, "SALE_ENTRY", 10) == 0) { | |
break; | |
} | |
} | |
Offset = strtoul (OffsetStr, NULL, 16); | |
*CompStartAddress += Offset; | |
SalEntryAdd = Fv1EndAddress - (SIZE_IA32_RESET_VECT + SIZE_SALE_ENTRY_POINT); | |
GetRelativeAddressInVtfBuffer (SalEntryAdd, &RelativeAddress, FIRST_VTF); | |
memcpy ((VOID *) RelativeAddress, (VOID *) CompStartAddress, sizeof (UINT64)); | |
if (FormatString != NULL) { | |
free (FormatString); | |
} | |
if (Fp != NULL) { | |
fclose (Fp); | |
} | |
return EFI_SUCCESS; | |
} | |
EFI_STATUS | |
CreateAndUpdateComponent ( | |
IN PARSED_VTF_INFO *VtfInfo | |
) | |
/*++ | |
Routine Description: | |
This function reads the binary file for each components and update them | |
in VTF Buffer as well as in FIT table. If the component is located in non | |
VTF area, only the FIT table address will be updated | |
Arguments: | |
VtfInfo - Pointer to Parsed Info | |
Returns: | |
EFI_SUCCESS - The function completed successful | |
EFI_ABORTED - Aborted due to one of the many reasons like: | |
(a) Component Size greater than the specified size. | |
(b) Error opening files. | |
(c) Fail to get the FIT table address. | |
EFI_INVALID_PARAMETER Value returned from call to UpdateEntryPoint() | |
EFI_OUT_OF_RESOURCES Memory allocation failure. | |
--*/ | |
{ | |
EFI_STATUS Status; | |
UINT64 CompStartAddress; | |
UINT64 FileSize; | |
UINT64 NumAdjustByte; | |
UINT8 *Buffer; | |
FILE *Fp; | |
FIT_TABLE *CompFitPtr; | |
BOOLEAN Aligncheck; | |
if (VtfInfo->LocationType == NONE) { | |
UpdateFitEntryForNonVTFComp (VtfInfo); | |
return EFI_SUCCESS; | |
} | |
Fp = fopen (LongFilePath (VtfInfo->CompBinName), "rb"); | |
if (Fp == NULL) { | |
Error (NULL, 0, 0001, "Error opening file", VtfInfo->CompBinName); | |
return EFI_ABORTED; | |
} | |
FileSize = _filelength (fileno (Fp)); | |
if ((VtfInfo->CompType == COMP_TYPE_FIT_PAL_B) || (VtfInfo->CompType == COMP_TYPE_FIT_PAL_A_SPECIFIC)) { | |
// | |
// BUGBUG: Satish to correct | |
// | |
FileSize -= SIZE_OF_PAL_HEADER; | |
} | |
if (VtfInfo->PreferredSize) { | |
if (FileSize > VtfInfo->CompSize) { | |
fclose (Fp); | |
Error (NULL, 0, 2000, "Invalid parameter", "The component size is more than specified size."); | |
return EFI_ABORTED; | |
} | |
FileSize = VtfInfo->CompSize; | |
} | |
Buffer = malloc ((UINTN) FileSize); | |
if (Buffer == NULL) { | |
fclose (Fp); | |
return EFI_OUT_OF_RESOURCES; | |
} | |
memset (Buffer, 0, (UINTN) FileSize); | |
if ((VtfInfo->CompType == COMP_TYPE_FIT_PAL_B) || (VtfInfo->CompType == COMP_TYPE_FIT_PAL_A_SPECIFIC)) { | |
// | |
// Read first 64 bytes of PAL header and use it to find version info | |
// | |
fread (Buffer, sizeof (UINT8), SIZE_OF_PAL_HEADER, Fp); | |
// | |
// PAL header contains the version info. Currently, we will use the header | |
// to read version info and then discard. | |
// | |
if (!VtfInfo->VersionPresent) { | |
GetComponentVersionInfo (VtfInfo, Buffer); | |
} | |
} | |
fread (Buffer, sizeof (UINT8), (UINTN) FileSize, Fp); | |
fclose (Fp); | |
// | |
// If it is non PAL_B component, pass the entire buffer to get the version | |
// info and implement any specific case inside GetComponentVersionInfo. | |
// | |
if (VtfInfo->CompType != COMP_TYPE_FIT_PAL_B) { | |
if (!VtfInfo->VersionPresent) { | |
GetComponentVersionInfo (VtfInfo, Buffer); | |
} | |
} | |
if (VtfInfo->LocationType == SECOND_VTF) { | |
CompStartAddress = (Vtf2LastStartAddress - FileSize); | |
} else { | |
CompStartAddress = (Vtf1LastStartAddress - FileSize); | |
} | |
if (VtfInfo->CompType == COMP_TYPE_FIT_PAL_B) { | |
Aligncheck = CheckAddressAlignment (CompStartAddress, 32 * 1024, &NumAdjustByte); | |
} else { | |
Aligncheck = CheckAddressAlignment (CompStartAddress, 8, &NumAdjustByte); | |
} | |
if (!Aligncheck) { | |
CompStartAddress -= NumAdjustByte; | |
} | |
if (VtfInfo->LocationType == SECOND_VTF && SecondVTF == TRUE) { | |
Vtf2LastStartAddress = CompStartAddress; | |
Vtf2TotalSize += (UINT32) (FileSize + NumAdjustByte); | |
Status = UpdateVtfBuffer (CompStartAddress, Buffer, FileSize, SECOND_VTF); | |
} else if (VtfInfo->LocationType == FIRST_VTF) { | |
Vtf1LastStartAddress = CompStartAddress; | |
Vtf1TotalSize += (UINT32) (FileSize + NumAdjustByte); | |
Status = UpdateVtfBuffer (CompStartAddress, Buffer, FileSize, FIRST_VTF); | |
} else { | |
free (Buffer); | |
Error (NULL, 0, 2000,"Invalid Parameter", "There's component in second VTF so second BaseAddress and Size must be specified!"); | |
return EFI_INVALID_PARAMETER; | |
} | |
if (EFI_ERROR (Status)) { | |
free (Buffer); | |
return EFI_ABORTED; | |
} | |
GetNextAvailableFitPtr (&CompFitPtr); | |
if (CompFitPtr == NULL) { | |
free (Buffer); | |
return EFI_ABORTED; | |
} | |
CompFitPtr->CompAddress = CompStartAddress | IPF_CACHE_BIT; | |
if ((FileSize % 16) != 0) { | |
free (Buffer); | |
Error (NULL, 0, 2000, "Invalid parameter", "Binary FileSize must be a multiple of 16."); | |
return EFI_INVALID_PARAMETER; | |
} | |
//assert ((FileSize % 16) == 0); | |
CompFitPtr->CompSize = (UINT32) (FileSize / 16); | |
CompFitPtr->CompVersion = MAKE_VERSION (VtfInfo->MajorVer, VtfInfo->MinorVer); | |
CompFitPtr->CvAndType = CV_N_TYPE (VtfInfo->CheckSumRequired, VtfInfo->CompType); | |
if (VtfInfo->CheckSumRequired) { | |
CompFitPtr->CheckSum = 0; | |
CompFitPtr->CheckSum = CalculateChecksum8 (Buffer, (UINTN) FileSize); | |
} | |
// | |
// Free the buffer | |
// | |
if (Buffer) { | |
free (Buffer); | |
} | |
// | |
// Update the SYM file for this component based on it's start address. | |
// | |
Status = UpdateSymFile (CompStartAddress, SymFileName, VtfInfo->CompSymName, FileSize); | |
if (EFI_ERROR (Status)) { | |
// | |
// At this time, SYM files are not required, so continue on error. | |
// | |
} | |
// !!!!!!!!!!!!!!!!!!!!! | |
// BUGBUG: | |
// This part of the code is a temporary line since PEICORE is going to be inside | |
// VTF till we work out how to determine the SALE_ENTRY through it. We will need | |
// to clarify so many related questions | |
// !!!!!!!!!!!!!!!!!!!!!!! | |
if (VtfInfo->CompType == COMP_TYPE_FIT_PEICORE) { | |
Status = UpdateEntryPoint (VtfInfo, &CompStartAddress); | |
} | |
return Status; | |
} | |
EFI_STATUS | |
CreateAndUpdatePAL_A ( | |
IN PARSED_VTF_INFO *VtfInfo | |
) | |
/*++ | |
Routine Description: | |
This function reads the binary file for each components and update them | |
in VTF Buffer as well as FIT table | |
Arguments: | |
VtfInfo - Pointer to Parsed Info | |
Returns: | |
EFI_ABORTED - Due to one of the following reasons: | |
(a)Error Opening File | |
(b)The PAL_A Size is more than specified size status | |
One of the values mentioned below returned from | |
call to UpdateSymFile | |
EFI_SUCCESS - The function completed successfully. | |
EFI_INVALID_PARAMETER - One of the input parameters was invalid. | |
EFI_ABORTED - An error occurred.UpdateSymFile | |
EFI_OUT_OF_RESOURCES - Memory allocation failed. | |
--*/ | |
{ | |
EFI_STATUS Status; | |
UINT64 PalStartAddress; | |
UINT64 AbsAddress; | |
UINTN RelativeAddress; | |
UINT64 FileSize; | |
UINT8 *Buffer; | |
FILE *Fp; | |
FIT_TABLE *PalFitPtr; | |
Fp = fopen (LongFilePath (VtfInfo->CompBinName), "rb"); | |
if (Fp == NULL) { | |
Error (NULL, 0, 0001, "Error opening file", VtfInfo->CompBinName); | |
return EFI_ABORTED; | |
} | |
FileSize = _filelength (fileno (Fp)); | |
if (FileSize < 64) { | |
fclose (Fp); | |
Error (NULL, 0, 2000, "Invalid parameter", "PAL_A bin header is 64 bytes, so the Bin size must be larger than 64 bytes!"); | |
return EFI_INVALID_PARAMETER; | |
} | |
FileSize -= SIZE_OF_PAL_HEADER; | |
if (VtfInfo->PreferredSize) { | |
if (FileSize > VtfInfo->CompSize) { | |
fclose (Fp); | |
Error (NULL, 0, 2000, "Invalid parameter", "The PAL_A Size is more than the specified size."); | |
return EFI_ABORTED; | |
} | |
FileSize = VtfInfo->CompSize; | |
} | |
Buffer = malloc ((UINTN) FileSize); | |
if (Buffer == NULL) { | |
fclose (Fp); | |
return EFI_OUT_OF_RESOURCES; | |
} | |
memset (Buffer, 0, (UINTN) FileSize); | |
// | |
// Read, Get version Info and discard the PAL header. | |
// | |
fread (Buffer, sizeof (UINT8), SIZE_OF_PAL_HEADER, Fp); | |
// | |
// Extract the version info from header of PAL_A. Once done, discrad this buffer | |
// | |
if (!VtfInfo->VersionPresent) { | |
GetComponentVersionInfo (VtfInfo, Buffer); | |
} | |
// | |
// Read PAL_A file in a buffer | |
// | |
fread (Buffer, sizeof (UINT8), (UINTN) FileSize, Fp); | |
fclose (Fp); | |
PalStartAddress = Fv1EndAddress - (SIZE_TO_OFFSET_PAL_A_END + FileSize); | |
Vtf1LastStartAddress = PalStartAddress; | |
Vtf1TotalSize += (UINT32) FileSize; | |
Status = UpdateVtfBuffer (PalStartAddress, Buffer, FileSize, FIRST_VTF); | |
AbsAddress = Fv1EndAddress - SIZE_TO_PAL_A_FIT; | |
GetRelativeAddressInVtfBuffer (AbsAddress, &RelativeAddress, FIRST_VTF); | |
PalFitPtr = (FIT_TABLE *) RelativeAddress; | |
PalFitPtr->CompAddress = PalStartAddress | IPF_CACHE_BIT; | |
//assert ((FileSize % 16) == 0); | |
if ((FileSize % 16) != 0) { | |
free (Buffer); | |
Error (NULL, 0, 2000, "Invalid parameter", "Binary FileSize must be a multiple of 16."); | |
return EFI_INVALID_PARAMETER; | |
} | |
PalFitPtr->CompSize = (UINT32) (FileSize / 16); | |
PalFitPtr->CompVersion = MAKE_VERSION (VtfInfo->MajorVer, VtfInfo->MinorVer); | |
PalFitPtr->CvAndType = CV_N_TYPE (VtfInfo->CheckSumRequired, VtfInfo->CompType); | |
if (VtfInfo->CheckSumRequired) { | |
PalFitPtr->CheckSum = 0; | |
PalFitPtr->CheckSum = CalculateChecksum8 (Buffer, (UINTN) FileSize); | |
} | |
if (Buffer) { | |
free (Buffer); | |
} | |
// | |
// Update the SYM file for this component based on it's start address. | |
// | |
Status = UpdateSymFile (PalStartAddress, SymFileName, VtfInfo->CompSymName, FileSize); | |
if (EFI_ERROR (Status)) { | |
// | |
// At this time, SYM files are not required, so continue on error. | |
// | |
} | |
return Status; | |
} | |
EFI_STATUS | |
CreateFitTableAndInitialize ( | |
IN PARSED_VTF_INFO *VtfInfo | |
) | |
/*++ | |
Routine Description: | |
This function creates and intializes FIT table which would be used to | |
add component info inside this | |
Arguments: | |
VtfInfo - Pointer to Parsed Info | |
Returns: | |
EFI_ABORTED - Aborted due to no size information | |
EFI_SUCCESS - The function completed successfully | |
--*/ | |
{ | |
UINT64 PalFitTableAdd; | |
UINT64 FitTableAdd; | |
UINT64 FitTableAddressOffset; | |
FIT_TABLE *PalFitPtr; | |
FIT_TABLE *FitStartPtr; | |
UINTN NumFitComp; | |
UINTN RelativeAddress; | |
UINTN Index; | |
if (!VtfInfo->PreferredSize) { | |
Error (NULL, 0, 2000, "Invalid parameter", "FIT could not be allocated because there is no size information."); | |
return EFI_ABORTED; | |
} | |
if ((VtfInfo->CompSize % 16) != 0) { | |
Error (NULL, 0, 2000, "Invalid parameter", "Invalid FIT Table Size, it is not a multiple of 16 bytes. Please correct the size."); | |
} | |
PalFitTableAdd = Fv1EndAddress - SIZE_TO_PAL_A_FIT; | |
GetRelativeAddressInVtfBuffer (PalFitTableAdd, &RelativeAddress, FIRST_VTF); | |
PalFitPtr = (FIT_TABLE *) RelativeAddress; | |
PalFitTableAdd = (PalFitPtr->CompAddress - VtfInfo->CompSize); | |
FitTableAdd = (PalFitPtr->CompAddress - 0x10) - VtfInfo->CompSize; | |
FitTableAddressOffset = Fv1EndAddress - (SIZE_IA32_RESET_VECT + SIZE_SALE_ENTRY_POINT + SIZE_FIT_TABLE_ADD); | |
GetRelativeAddressInVtfBuffer (FitTableAddressOffset, &RelativeAddress, FIRST_VTF); | |
*(UINT64 *) RelativeAddress = FitTableAdd; | |
GetRelativeAddressInVtfBuffer (FitTableAdd, &RelativeAddress, FIRST_VTF); | |
// | |
// Update Fit Table with FIT Signature and FIT info in first 16 bytes. | |
// | |
FitStartPtr = (FIT_TABLE *) RelativeAddress; | |
strncpy ((CHAR8 *) &FitStartPtr->CompAddress, FIT_SIGNATURE, 8); // "_FIT_ " | |
assert (((VtfInfo->CompSize & 0x00FFFFFF) % 16) == 0); | |
FitStartPtr->CompSize = (VtfInfo->CompSize & 0x00FFFFFF) / 16; | |
FitStartPtr->CompVersion = MAKE_VERSION (VtfInfo->MajorVer, VtfInfo->MinorVer); | |
// | |
// BUGBUG: If a checksum is required, add code to checksum the FIT table. Also | |
// determine what to do for things like the FV component that aren't easily checksummed. | |
// The checksum will be done once we are done with all the componet update in the FIT | |
// table | |
// | |
FitStartPtr->CvAndType = CV_N_TYPE (VtfInfo->CheckSumRequired, VtfInfo->CompType); | |
NumFitComp = FitStartPtr->CompSize; | |
FitStartPtr++; | |
// | |
// Intialize remaining FIT table space to UNUSED fit component type | |
// so that when we need to create a FIT entry for a component, we can | |
// locate a free one and use it. | |
// | |
for (Index = 0; Index < (NumFitComp - 1); Index++) { | |
FitStartPtr->CvAndType = 0x7F; // Initialize all with UNUSED | |
FitStartPtr++; | |
} | |
Vtf1TotalSize += VtfInfo->CompSize; | |
Vtf1LastStartAddress -= VtfInfo->CompSize; | |
return EFI_SUCCESS; | |
} | |
EFI_STATUS | |
WriteVtfBinary ( | |
IN CHAR8 *FileName, | |
IN UINT32 VtfSize, | |
IN LOC_TYPE LocType | |
) | |
/*++ | |
Routine Description: | |
Write Firmware Volume from memory to a file. | |
Arguments: | |
FileName - Output File Name which needed to be created/ | |
VtfSize - FileSize | |
LocType - The type of the VTF | |
Returns: | |
EFI_ABORTED - Returned due to one of the following resons: | |
(a) Error Opening File | |
(b) Failing to copy buffers | |
EFI_SUCCESS - The fuction completes successfully | |
--*/ | |
{ | |
FILE *Fp; | |
UINTN NumByte; | |
VOID *VtfBuffer; | |
UINTN RelativeAddress; | |
if (LocType == FIRST_VTF) { | |
GetRelativeAddressInVtfBuffer (Vtf1LastStartAddress, &RelativeAddress, FIRST_VTF); | |
VtfBuffer = (VOID *) RelativeAddress; | |
} else { | |
GetRelativeAddressInVtfBuffer (Vtf2LastStartAddress, &RelativeAddress, SECOND_VTF); | |
VtfBuffer = (VOID *) RelativeAddress; | |
} | |
Fp = fopen (LongFilePath (FileName), "wb"); | |
if (Fp == NULL) { | |
Error (NULL, 0, 0001, "Error opening file", FileName); | |
return EFI_ABORTED; | |
} | |
NumByte = fwrite (VtfBuffer, sizeof (UINT8), (UINTN) VtfSize, Fp); | |
if (Fp) { | |
fclose (Fp); | |
} | |
if (NumByte != (sizeof (UINT8) * VtfSize)) { | |
Error (NULL, 0, 0002, "Error writing file", FileName); | |
return EFI_ABORTED; | |
} | |
return EFI_SUCCESS; | |
} | |
EFI_STATUS | |
UpdateVtfBuffer ( | |
IN UINT64 StartAddress, | |
IN UINT8 *Buffer, | |
IN UINT64 DataSize, | |
IN LOC_TYPE LocType | |
) | |
/*++ | |
Routine Description: | |
Update the Firmware Volume Buffer with requested buffer data | |
Arguments: | |
StartAddress - StartAddress in buffer. This number will automatically | |
point to right address in buffer where data needed | |
to be updated. | |
Buffer - Buffer pointer from data will be copied to memory mapped buffer. | |
DataSize - Size of the data needed to be copied. | |
LocType - The type of the VTF: First or Second | |
Returns: | |
EFI_ABORTED - The input parameter is error | |
EFI_SUCCESS - The function completed successfully | |
--*/ | |
{ | |
UINT8 *LocalBufferPtrToWrite; | |
if (LocType == FIRST_VTF) { | |
if ((StartAddress | IPF_CACHE_BIT) < (Vtf1LastStartAddress | IPF_CACHE_BIT)) { | |
Error (NULL, 0, 2000, "Invalid parameter", "Start Address is less than the VTF start address."); | |
return EFI_ABORTED; | |
} | |
LocalBufferPtrToWrite = (UINT8 *) Vtf1EndBuffer; | |
LocalBufferPtrToWrite -= (Fv1EndAddress - StartAddress); | |
} else { | |
if ((StartAddress | IPF_CACHE_BIT) < (Vtf2LastStartAddress | IPF_CACHE_BIT)) { | |
Error (NULL, 0, 2000, "Invalid parameter", "Error StartAddress"); | |
return EFI_ABORTED; | |
} | |
LocalBufferPtrToWrite = (UINT8 *) Vtf2EndBuffer; | |
LocalBufferPtrToWrite -= (Fv2EndAddress - StartAddress); | |
} | |
memcpy (LocalBufferPtrToWrite, Buffer, (UINTN) DataSize); | |
return EFI_SUCCESS; | |
} | |
EFI_STATUS | |
UpdateFfsHeader ( | |
IN UINT32 TotalVtfSize, | |
IN LOC_TYPE LocType | |
) | |
/*++ | |
Routine Description: | |
Update the Firmware Volume Buffer with requested buffer data | |
Arguments: | |
TotalVtfSize - Size of the VTF | |
Fileoffset - The start of the file relative to the start of the FV. | |
LocType - The type of the VTF | |
Returns: | |
EFI_SUCCESS - The function completed successfully | |
EFI_INVALID_PARAMETER - The Ffs File Header Pointer is NULL | |
--*/ | |
{ | |
EFI_FFS_FILE_HEADER *FileHeader; | |
UINTN RelativeAddress; | |
EFI_GUID EfiFirmwareVolumeTopFileGuid = EFI_FFS_VOLUME_TOP_FILE_GUID; | |
// | |
// Find the VTF file header location | |
// | |
if (LocType == FIRST_VTF) { | |
GetRelativeAddressInVtfBuffer (Vtf1LastStartAddress, &RelativeAddress, FIRST_VTF); | |
FileHeader = (EFI_FFS_FILE_HEADER *) RelativeAddress; | |
} else { | |
GetRelativeAddressInVtfBuffer (Vtf2LastStartAddress, &RelativeAddress, SECOND_VTF); | |
FileHeader = (EFI_FFS_FILE_HEADER *) RelativeAddress; | |
} | |
if (FileHeader == NULL) { | |
return EFI_INVALID_PARAMETER; | |
} | |
// | |
// write header | |
// | |
memset (FileHeader, 0, sizeof (EFI_FFS_FILE_HEADER)); | |
memcpy (&FileHeader->Name, &EfiFirmwareVolumeTopFileGuid, sizeof (EFI_GUID)); | |
FileHeader->Type = EFI_FV_FILETYPE_RAW; | |
FileHeader->Attributes = FFS_ATTRIB_CHECKSUM; | |
// | |
// Now FileSize includes the EFI_FFS_FILE_HEADER | |
// | |
FileHeader->Size[0] = (UINT8) (TotalVtfSize & 0x000000FF); | |
FileHeader->Size[1] = (UINT8) ((TotalVtfSize & 0x0000FF00) >> 8); | |
FileHeader->Size[2] = (UINT8) ((TotalVtfSize & 0x00FF0000) >> 16); | |
// | |
// Fill in checksums and state, all three must be zero for the checksums. | |
// | |
FileHeader->IntegrityCheck.Checksum.Header = 0; | |
FileHeader->IntegrityCheck.Checksum.File = 0; | |
FileHeader->State = 0; | |
FileHeader->IntegrityCheck.Checksum.Header = CalculateChecksum8 ((UINT8 *) FileHeader, sizeof (EFI_FFS_FILE_HEADER)); | |
FileHeader->IntegrityCheck.Checksum.File = CalculateChecksum8 ((UINT8 *) (FileHeader + 1), TotalVtfSize - sizeof (EFI_FFS_FILE_HEADER)); | |
FileHeader->State = EFI_FILE_HEADER_CONSTRUCTION | EFI_FILE_HEADER_VALID | EFI_FILE_DATA_VALID; | |
return EFI_SUCCESS; | |
} | |
EFI_STATUS | |
ValidateAddressAndSize ( | |
IN UINT64 BaseAddress, | |
IN UINT64 FwVolSize | |
) | |
/*++ | |
Routine Description: | |
Update the Firmware Volume Buffer with requested buffer data | |
Arguments: | |
BaseAddress - Base address for the Fw Volume. | |
FwVolSize - Total Size of the FwVolume to which VTF will be attached.. | |
Returns: | |
EFI_SUCCESS - The function completed successfully | |
EFI_UNSUPPORTED - The input parameter is error | |
--*/ | |
{ | |
if ((FwVolSize > 0x40) && ((BaseAddress + FwVolSize) % 8 == 0)) { | |
return EFI_SUCCESS; | |
} | |
return EFI_UNSUPPORTED; | |
} | |
EFI_STATUS | |
UpdateIA32ResetVector ( | |
IN CHAR8 *FileName, | |
IN UINT64 FirstFwVSize | |
) | |
/*++ | |
Routine Description: | |
Update the 16 byte IA32 Reset vector to maintain the compatibility | |
Arguments: | |
FileName - Binary file name which contains the IA32 Reset vector info.. | |
FirstFwVSize - Total Size of the FwVolume to which VTF will be attached.. | |
Returns: | |
EFI_SUCCESS - The function completed successfully | |
EFI_ABORTED - Invalid File Size | |
EFI_INVALID_PARAMETER - Bad File Name | |
EFI_OUT_OF_RESOURCES - Memory allocation failed. | |
--*/ | |
{ | |
UINT8 *Buffer; | |
UINT8 *LocalVtfBuffer; | |
UINTN FileSize; | |
FILE *Fp; | |
if (!strcmp (FileName, "")) { | |
return EFI_INVALID_PARAMETER; | |
} | |
Fp = fopen (LongFilePath (FileName), "rb"); | |
if (Fp == NULL) { | |
Error (NULL, 0, 0001, "Error opening file", FileName); | |
return EFI_ABORTED; | |
} | |
FileSize = _filelength (fileno (Fp)); | |
if (FileSize > 16) { | |
fclose (Fp); | |
return EFI_ABORTED; | |
} | |
Buffer = malloc (FileSize); | |
if (Buffer == NULL) { | |
fclose (Fp); | |
return EFI_OUT_OF_RESOURCES; | |
} | |
fread (Buffer, sizeof (UINT8), FileSize, Fp); | |
LocalVtfBuffer = (UINT8 *) Vtf1EndBuffer - SIZE_IA32_RESET_VECT; | |
memcpy (LocalVtfBuffer, Buffer, FileSize); | |
if (Buffer) { | |
free (Buffer); | |
} | |
if (Fp != NULL) { | |
fclose (Fp); | |
} | |
return EFI_SUCCESS; | |
} | |
VOID | |
CleanUpMemory ( | |
VOID | |
) | |
/*++ | |
Routine Description: | |
This function cleans up any allocated buffer | |
Arguments: | |
NONE | |
Returns: | |
NONE | |
--*/ | |
{ | |
PARSED_VTF_INFO *TempFileListPtr; | |
if (Vtf1Buffer) { | |
free (Vtf1Buffer); | |
} | |
if (Vtf2Buffer) { | |
free (Vtf2Buffer); | |
} | |
// | |
// Cleanup the buffer which was allocated to read the file names from FV.INF | |
// | |
FileListPtr = FileListHeadPtr; | |
while (FileListPtr != NULL) { | |
TempFileListPtr = FileListPtr->NextVtfInfo; | |
free (FileListPtr); | |
FileListPtr = TempFileListPtr; | |
} | |
} | |
EFI_STATUS | |
ProcessAndCreateVtf ( | |
IN UINT64 Size | |
) | |
/*++ | |
Routine Description: | |
This function process the link list created during INF file parsing | |
and create component in VTF and updates its info in FIT table | |
Arguments: | |
Size - Size of the Firmware Volume of which, this VTF belongs to. | |
Returns: | |
EFI_UNSUPPORTED - Unknown FIT type | |
EFI_SUCCESS - The function completed successfully | |
--*/ | |
{ | |
EFI_STATUS Status; | |
PARSED_VTF_INFO *ParsedInfoPtr; | |
Status = EFI_SUCCESS; | |
ParsedInfoPtr = FileListHeadPtr; | |
while (ParsedInfoPtr != NULL) { | |
switch (ParsedInfoPtr->CompType) { | |
// | |
// COMP_TYPE_FIT_HEADER is a special case, hence handle it here | |
// | |
case COMP_TYPE_FIT_HEADER: | |
//COMP_TYPE_FIT_HEADER 0x00 | |
Status = CreateFitTableAndInitialize (ParsedInfoPtr); | |
break; | |
// | |
// COMP_TYPE_FIT_PAL_A is a special case, hence handle it here | |
// | |
case COMP_TYPE_FIT_PAL_A: | |
//COMP_TYPE_FIT_PAL_A 0x0F | |
Status = CreateAndUpdatePAL_A (ParsedInfoPtr); | |
// | |
// Based on VTF specification, once the PAL_A component has been written, | |
// update the Firmware Volume info as FIT table. This will be utilized | |
// to extract the Firmware Volume Start address where this VTF will be | |
// of part. | |
// | |
if (Status == EFI_SUCCESS) { | |
UpdateFitEntryForFwVolume (Size); | |
} | |
break; | |
case COMP_TYPE_FIT_FV_BOOT: | |
//COMP_TYPE_FIT_FV_BOOT 0x7E | |
// | |
// Since FIT entry for Firmware Volume has been created and it is | |
// located at (PAL_A start - 16 byte). So we will not process any | |
// Firmware Volume related entry from INF file | |
// | |
Status = EFI_SUCCESS; | |
break; | |
default: | |
// | |
// Any other component type should be handled here. This will create the | |
// image in specified VTF and create appropriate entry about this | |
// component in FIT Entry. | |
// | |
Status = CreateAndUpdateComponent (ParsedInfoPtr); | |
if (EFI_ERROR (Status)) { | |
Error (NULL, 0, 0002, "Error updating component", ParsedInfoPtr->CompName); | |
return EFI_ABORTED; | |
} else { | |
break;} | |
} | |
ParsedInfoPtr = ParsedInfoPtr->NextVtfInfo; | |
} | |
return Status; | |
} | |
EFI_STATUS | |
GenerateVtfImage ( | |
IN UINT64 StartAddress1, | |
IN UINT64 Size1, | |
IN UINT64 StartAddress2, | |
IN UINT64 Size2, | |
IN FILE *fp | |
) | |
/*++ | |
Routine Description: | |
This is the main function which will be called from application. | |
Arguments: | |
StartAddress1 - The start address of the first VTF | |
Size1 - The size of the first VTF | |
StartAddress2 - The start address of the second VTF | |
Size2 - The size of the second VTF | |
fp - The pointer to BSF inf file | |
Returns: | |
EFI_OUT_OF_RESOURCES - Can not allocate memory | |
The return value can be any of the values | |
returned by the calls to following functions: | |
GetVtfRelatedInfoFromInfFile | |
ProcessAndCreateVtf | |
UpdateIA32ResetVector | |
UpdateFfsHeader | |
WriteVtfBinary | |
--*/ | |
{ | |
EFI_STATUS Status; | |
FILE *VtfFP; | |
Status = EFI_UNSUPPORTED; | |
VtfFP = fp; | |
if (StartAddress2 == 0) { | |
SecondVTF = FALSE; | |
} else { | |
SecondVTF = TRUE; | |
} | |
Fv1BaseAddress = StartAddress1; | |
Fv1EndAddress = Fv1BaseAddress + Size1; | |
if (Fv1EndAddress != 0x100000000ULL || Size1 < 0x100000) { | |
Error (NULL, 0, 2000, "Invalid parameter", "Error BaseAddress and Size parameters!"); | |
if (Size1 < 0x100000) { | |
Error (NULL, 0, 2000, "Invalid parameter", "The FwVolumeSize must be larger than 1M!"); | |
} else if (SecondVTF != TRUE) { | |
Error (NULL, 0, 2000, "Invalid parameter", "BaseAddress + FwVolumeSize must equal 0x100000000!"); | |
} | |
Usage(); | |
return EFI_INVALID_PARAMETER; | |
} | |
// | |
// The image buffer for the First VTF | |
// | |
Vtf1Buffer = malloc ((UINTN) Size1); | |
if (Vtf1Buffer == NULL) { | |
Error (NULL, 0, 4001, "Resource", "Not enough resources available to create memory mapped file for the Boot Strap File!"); | |
return EFI_OUT_OF_RESOURCES; | |
} | |
memset (Vtf1Buffer, 0x00, (UINTN) Size1); | |
Vtf1EndBuffer = (UINT8 *) Vtf1Buffer + Size1; | |
Vtf1LastStartAddress = Fv1EndAddress | IPF_CACHE_BIT; | |
if (SecondVTF) { | |
Fv2BaseAddress = StartAddress2; | |
Fv2EndAddress = Fv2BaseAddress + Size2; | |
if (Fv2EndAddress != StartAddress1) { | |
Error (NULL, 0, 2000, "Invalid parameter", "Error BaseAddress and Size parameters!"); | |
if (SecondVTF == TRUE) { | |
Error (NULL, 0, 2000, "Invalid parameter", "FirstBaseAddress + FirstFwVolumeSize must equal 0x100000000!"); | |
Error (NULL, 0, 2000, "Invalid parameter", "SecondBaseAddress + SecondFwVolumeSize must equal FirstBaseAddress!"); | |
} | |
Usage(); | |
return EFI_INVALID_PARAMETER; | |
} | |
// | |
// The image buffer for the second VTF | |
// | |
Vtf2Buffer = malloc ((UINTN) Size2); | |
if (Vtf2Buffer == NULL) { | |
Error (NULL, 0, 4001, "Resource", "Not enough resources available to create memory mapped file for the Boot Strap File!"); | |
return EFI_OUT_OF_RESOURCES; | |
} | |
memset (Vtf2Buffer, 0x00, (UINTN) Size2); | |
Vtf2EndBuffer = (UINT8 *) Vtf2Buffer + Size2; | |
Vtf2LastStartAddress = Fv2EndAddress | IPF_CACHE_BIT; | |
} | |
Status = GetVtfRelatedInfoFromInfFile (VtfFP); | |
if (Status != EFI_SUCCESS) { | |
Error (NULL, 0, 0003, "Error parsing file", "the input file."); | |
CleanUpMemory (); | |
return Status; | |
} | |
Status = ProcessAndCreateVtf (Size1); | |
if (Status != EFI_SUCCESS) { | |
CleanUpMemory (); | |
return Status; | |
} | |
if (SectionOptionFlag) { | |
Status = UpdateIA32ResetVector (IA32BinFile, Vtf1TotalSize); | |
if (Status != EFI_SUCCESS) { | |
CleanUpMemory (); | |
return Status; | |
} | |
} | |
// | |
// Re arrange the FIT Table for Ascending order of their FIT Type.. | |
// | |
SortFitTable (); | |
// | |
// All components have been updated in FIT table. Now perform the FIT table | |
// checksum. The following function will check if Checksum is required, | |
// if yes, then it will perform the checksum otherwise not. | |
// | |
CalculateFitTableChecksum (); | |
// | |
// Write the FFS header | |
// | |
Vtf1TotalSize += sizeof (EFI_FFS_FILE_HEADER); | |
Vtf1LastStartAddress -= sizeof (EFI_FFS_FILE_HEADER); | |
Status = UpdateFfsHeader (Vtf1TotalSize, FIRST_VTF); | |
if (Status != EFI_SUCCESS) { | |
CleanUpMemory (); | |
return Status; | |
} | |
// | |
// Update the VTF buffer into specified VTF binary file | |
// | |
Status = WriteVtfBinary (OutFileName1, Vtf1TotalSize, FIRST_VTF); | |
if (SecondVTF) { | |
Vtf2TotalSize += sizeof (EFI_FFS_FILE_HEADER); | |
Vtf2LastStartAddress -= sizeof (EFI_FFS_FILE_HEADER); | |
Status = UpdateFfsHeader (Vtf2TotalSize, SECOND_VTF); | |
if (Status != EFI_SUCCESS) { | |
CleanUpMemory (); | |
return Status; | |
} | |
// | |
// Update the VTF buffer into specified VTF binary file | |
// | |
Status = WriteVtfBinary (OutFileName2, Vtf2TotalSize, SECOND_VTF); | |
} | |
CleanUpMemory (); | |
return Status; | |
} | |
EFI_STATUS | |
PeimFixupInFitTable ( | |
IN UINT64 StartAddress | |
) | |
/*++ | |
Routine Description: | |
This function is an entry point to fixup SAL-E entry point. | |
Arguments: | |
StartAddress - StartAddress for PEIM..... | |
Returns: | |
EFI_SUCCESS - The function completed successfully | |
EFI_ABORTED - Error Opening File | |
EFI_OUT_OF_RESOURCES - System out of resources for memory allocation. | |
--*/ | |
{ | |
EFI_STATUS Status; | |
FILE *Fp; | |
UINT64 *StartAddressPtr; | |
UINTN FirstFwVSize; | |
StartAddressPtr = malloc (sizeof (UINT64)); | |
if (StartAddressPtr == NULL) { | |
return EFI_OUT_OF_RESOURCES; | |
} | |
*StartAddressPtr = StartAddress; | |
Fp = fopen (LongFilePath (OutFileName1), "rb"); | |
if (Fp == NULL) { | |
Error (NULL, 0, 0001, "Error opening file", OutFileName1); | |
if (StartAddressPtr) { | |
free (StartAddressPtr); | |
} | |
return EFI_ABORTED; | |
} | |
FirstFwVSize = _filelength (fileno (Fp)); | |
fseek (Fp, (long) (FirstFwVSize - (UINTN) (SIZE_IA32_RESET_VECT + SIZE_SALE_ENTRY_POINT)), SEEK_SET); | |
fwrite ((VOID *) StartAddressPtr, sizeof (UINT64), 1, Fp); | |
if (Fp) { | |
fclose (Fp); | |
} | |
if (StartAddressPtr) { | |
free (StartAddressPtr); | |
} | |
Status = EFI_SUCCESS; | |
return Status; | |
} | |
EFI_STATUS | |
UpdateSymFile ( | |
IN UINT64 BaseAddress, | |
IN CHAR8 *DestFileName, | |
IN CHAR8 *SourceFileName, | |
IN UINT64 FileSize | |
) | |
/*++ | |
Routine Description: | |
This function adds the SYM tokens in the source file to the destination file. | |
The SYM tokens are updated to reflect the base address. | |
Arguments: | |
BaseAddress - The base address for the new SYM tokens. | |
DestFileName - The destination file. | |
SourceFileName - The source file. | |
FileSize - Size of bin file. | |
Returns: | |
EFI_SUCCESS - The function completed successfully. | |
EFI_INVALID_PARAMETER - One of the input parameters was invalid. | |
EFI_ABORTED - An error occurred. | |
--*/ | |
{ | |
FILE *SourceFile; | |
FILE *DestFile; | |
CHAR8 Buffer[MAX_LONG_FILE_PATH]; | |
CHAR8 Type[MAX_LONG_FILE_PATH]; | |
CHAR8 Address[MAX_LONG_FILE_PATH]; | |
CHAR8 Section[MAX_LONG_FILE_PATH]; | |
CHAR8 Token[MAX_LONG_FILE_PATH]; | |
CHAR8 BaseToken[MAX_LONG_FILE_PATH]; | |
CHAR8 *FormatString; | |
INTN FormatLength; | |
UINT64 TokenAddress; | |
long StartLocation; | |
// | |
// Verify input parameters. | |
// | |
if (BaseAddress == 0 || DestFileName == NULL || SourceFileName == NULL) { | |
return EFI_INVALID_PARAMETER; | |
} | |
// | |
// Open the source file | |
// | |
SourceFile = fopen (LongFilePath (SourceFileName), "r"); | |
if (SourceFile == NULL) { | |
// | |
// SYM files are not required. | |
// | |
return EFI_SUCCESS; | |
} | |
// | |
// Use the file name minus extension as the base for tokens | |
// | |
strcpy (BaseToken, SourceFileName); | |
strtok (BaseToken, ". \t\n"); | |
strcat (BaseToken, "__"); | |
// | |
// Open the destination file | |
// | |
DestFile = fopen (LongFilePath (DestFileName), "a+"); | |
if (DestFile == NULL) { | |
fclose (SourceFile); | |
Error (NULL, 0, 0001, "Error opening file", DestFileName); | |
return EFI_ABORTED; | |
} | |
// | |
// If this is the beginning of the output file, write the symbol format info. | |
// | |
if (fseek (DestFile, 0, SEEK_END) != 0) { | |
fclose (SourceFile); | |
fclose (DestFile); | |
Error (NULL, 0, 2000, "Invalid parameter", "not at the beginning of the output file."); | |
return EFI_ABORTED; | |
} | |
StartLocation = ftell (DestFile); | |
if (StartLocation == 0) { | |
fprintf (DestFile, "TEXTSYM format | V1.0\n"); | |
} else if (StartLocation == -1) { | |
fclose (SourceFile); | |
fclose (DestFile); | |
Error (NULL, 0, 2000, "Invalid parameter", "StartLocation error"); | |
return EFI_ABORTED; | |
} | |
// | |
// Read the first line | |
// | |
if (fgets (Buffer, MAX_LONG_FILE_PATH, SourceFile) == NULL) { | |
Buffer[0] = 0; | |
} | |
// | |
// Make sure it matches the expected sym format | |
// | |
if (strcmp (Buffer, "TEXTSYM format | V1.0\n")) { | |
fclose (SourceFile); | |
fclose (DestFile); | |
Error (NULL, 0, 2000, "Invalid parameter", "The symbol file does not match the expected TEXTSYM format (V1.0.)"); | |
return EFI_ABORTED; | |
} | |
// | |
// Generate the format string for fscanf | |
// | |
FormatLength = snprintf ( | |
NULL, | |
0, | |
"%%%us | %%%us | %%%us | %%%us\n", | |
(unsigned) sizeof (Type) - 1, | |
(unsigned) sizeof (Address) - 1, | |
(unsigned) sizeof (Section) - 1, | |
(unsigned) sizeof (Token) - 1 | |
) + 1; | |
FormatString = (CHAR8 *) malloc (FormatLength); | |
if (FormatString == NULL) { | |
fclose (SourceFile); | |
fclose (DestFile); | |
Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!"); | |
return EFI_ABORTED; | |
} | |
snprintf ( | |
FormatString, | |
FormatLength, | |
"%%%us | %%%us | %%%us | %%%us\n", | |
(unsigned) sizeof (Type) - 1, | |
(unsigned) sizeof (Address) - 1, | |
(unsigned) sizeof (Section) - 1, | |
(unsigned) sizeof (Token) - 1 | |
); | |
// | |
// Read in the file | |
// | |
while (feof (SourceFile) == 0) { | |
// | |
// Read a line | |
// | |
if (fscanf (SourceFile, FormatString, Type, Address, Section, Token) == 4) { | |
// | |
// Get the token address | |
// | |
AsciiStringToUint64 (Address, TRUE, &TokenAddress); | |
if (TokenAddress > FileSize) { | |
// | |
// Symbol offset larger than FileSize. This Symbol can't be in Bin file. Don't print them. | |
// | |
break; | |
} | |
// | |
// Add the base address, the size of the FFS file header and the size of the peim header. | |
// | |
TokenAddress += BaseAddress &~IPF_CACHE_BIT; | |
fprintf (DestFile, "%s | %016llX | ", Type, (unsigned long long) TokenAddress); | |
fprintf (DestFile, "%s | %s\n %s\n", Section, Token, BaseToken); | |
} | |
} | |
free (FormatString); | |
fclose (SourceFile); | |
fclose (DestFile); | |
return EFI_SUCCESS; | |
} | |
EFI_STATUS | |
CalculateFitTableChecksum ( | |
VOID | |
) | |
/*++ | |
Routine Description: | |
This function will perform byte checksum on the FIT table, if the the checksum required | |
field is set to CheckSum required. If the checksum is not required then checksum byte | |
will have value as 0;. | |
Arguments: | |
NONE | |
Returns: | |
Status - Value returned by call to CalculateChecksum8 () | |
EFI_SUCCESS - The function completed successfully | |
--*/ | |
{ | |
FIT_TABLE *TmpFitPtr; | |
UINT64 FitTableAdd; | |
UINT64 FitTableAddOffset; | |
UINTN RelativeAddress; | |
UINTN Size; | |
// | |
// Read the Fit Table address from Itanium-based address map. | |
// | |
FitTableAddOffset = Fv1EndAddress - (SIZE_IA32_RESET_VECT + SIZE_SALE_ENTRY_POINT + SIZE_FIT_TABLE_ADD); | |
// | |
// Translate this Itanium-based address in terms of local buffer address which | |
// contains the image for Boot Strapped File | |
// | |
GetRelativeAddressInVtfBuffer (FitTableAddOffset, &RelativeAddress, FIRST_VTF); | |
FitTableAdd = *(UINTN *) RelativeAddress; | |
GetRelativeAddressInVtfBuffer (FitTableAdd, &RelativeAddress, FIRST_VTF); | |
TmpFitPtr = (FIT_TABLE *) RelativeAddress; | |
Size = TmpFitPtr->CompSize * 16; | |
if ((TmpFitPtr->CvAndType & CHECKSUM_BIT_MASK) >> 7) { | |
TmpFitPtr->CheckSum = 0; | |
TmpFitPtr->CheckSum = CalculateChecksum8 ((UINT8 *) TmpFitPtr, Size); | |
} else { | |
TmpFitPtr->CheckSum = 0; | |
} | |
return EFI_SUCCESS; | |
} | |
VOID | |
Version ( | |
VOID | |
) | |
/*++ | |
Routine Description: | |
Displays the standard utility information to SDTOUT | |
Arguments: | |
None | |
Returns: | |
None | |
--*/ | |
{ | |
fprintf (stdout, "%s Version %d.%d %s \n", UTILITY_NAME, UTILITY_MAJOR_VERSION, UTILITY_MINOR_VERSION, __BUILD_VERSION); | |
} | |
VOID | |
Usage ( | |
VOID | |
) | |
/*++ | |
Routine Description: | |
Displays the utility usage syntax to STDOUT | |
Arguments: | |
None | |
Returns: | |
None | |
--*/ | |
{ | |
// | |
// Summary usage | |
// | |
fprintf (stdout, "Usage: %s [options] <-f input_file> <-r BaseAddress> <-s FwVolumeSize>\n\n", UTILITY_NAME); | |
// | |
// Copyright declaration | |
// | |
fprintf (stdout, "Copyright (c) 2007 - 2014, Intel Corporation. All rights reserved.\n\n"); | |
// | |
// Details Option | |
// | |
fprintf (stdout, "Options:\n"); | |
fprintf (stdout, " -f Input_file, --filename Input_file\n\ | |
Input_file is name of the BS Image INF file\n"); | |
fprintf (stdout, " -r BaseAddress, --baseaddr BaseAddress\n\ | |
BaseAddress is the starting address of Firmware Volume\n\ | |
where Boot Strapped Image will reside.\n"); | |
fprintf (stdout, " -s FwVolumeSize, --size FwVolumeSize\n\ | |
FwVolumeSize is the size of Firmware Volume.\n"); | |
fprintf (stdout, " -o FileName, --output FileName\n\ | |
File will be created to store the ouput content.\n"); | |
fprintf (stdout, " -v, --verbose Turn on verbose output with informational messages.\n"); | |
fprintf (stdout, " --version Show program's version number and exit.\n"); | |
fprintf (stdout, " -h, --help Show this help message and exit.\n"); | |
fprintf (stdout, " -q, --quiet Disable all messages except FATAL ERRORS.\n"); | |
fprintf (stdout, " -d, --debug [#, 0-9] Enable debug messages at level #.\n"); | |
} | |
int | |
main ( | |
IN int argc, | |
IN char **argv | |
) | |
/*++ | |
Routine Description: | |
This utility uses GenVtf.dll to build a Boot Strap File Image which will be | |
part of firmware volume image. | |
Arguments: | |
argc - The count of the parameters | |
argv - The parameters | |
Returns: | |
0 - No error conditions detected. | |
1 - One or more of the input parameters is invalid. | |
2 - A resource required by the utility was unavailable. | |
- Most commonly this will be memory allocation or file creation. | |
3 - GenFvImage.dll could not be loaded. | |
4 - Error executing the GenFvImage dll. | |
5 - Now this tool does not support the IA32 platform | |
--*/ | |
{ | |
UINT8 Index; | |
UINT64 StartAddress1; | |
UINT64 StartAddress2; | |
UINT64 FwVolSize1; | |
UINT64 FwVolSize2; | |
BOOLEAN FirstRoundO; | |
BOOLEAN FirstRoundB; | |
BOOLEAN FirstRoundS; | |
EFI_STATUS Status; | |
FILE *VtfFP; | |
CHAR8 *VtfFileName; | |
SetUtilityName (UTILITY_NAME); | |
// | |
// Initialize variables | |
// | |
StartAddress1 = 0; | |
StartAddress2 = 0; | |
FwVolSize1 = 0; | |
FwVolSize2 = 0; | |
FirstRoundB = TRUE; | |
FirstRoundS = TRUE; | |
FirstRoundO = TRUE; | |
DebugMode = FALSE; | |
OutFileName1 = NULL; | |
OutFileName2 = NULL; | |
VtfFP = NULL; | |
DebugLevel = 0; | |
// | |
// Verify the correct number of arguments | |
// | |
if (argc == 1) { | |
Usage(); | |
return 0; | |
} | |
if ((strcmp(argv[1], "-h") == 0) || (strcmp(argv[1], "--help") == 0)) { | |
Usage(); | |
return 0; | |
} | |
if ((strcmp(argv[1], "--version") == 0)) { | |
Version(); | |
return 0; | |
} | |
// | |
// Parse the command line arguments | |
// | |
for (Index = 1; Index < argc; Index += 2) { | |
if ((stricmp (argv[Index], "-o") == 0) || (stricmp (argv[Index], "--output") == 0)) { | |
if (argv[Index + 1] == NULL || argv[Index + 1][0] == '-') { | |
Error (NULL, 0, 1003, "Invalid option value", "Output file is missing for -o option"); | |
goto ERROR; | |
} | |
// | |
// Get the output file name | |
// | |
VTF_OUTPUT = TRUE; | |
if (FirstRoundO) { | |
// | |
// It's the first output file name | |
// | |
OutFileName1 = (CHAR8 *)argv[Index+1]; | |
FirstRoundO = FALSE; | |
} else { | |
// | |
//It's the second output file name | |
// | |
OutFileName2 = (CHAR8 *)argv[Index+1]; | |
} | |
continue; | |
} | |
if ((stricmp (argv[Index], "-f") == 0) || (stricmp (argv[Index], "--filename") == 0)) { | |
if (argv[Index + 1] == NULL || argv[Index + 1][0] == '-') { | |
Error (NULL, 0, 1003, "Invalid option value", "BS Image INF file is missing for -f option"); | |
goto ERROR; | |
} | |
// | |
// Get the input VTF file name | |
// | |
VtfFileName = argv[Index+1]; | |
if (VtfFP != NULL) { | |
// | |
// VTF file name has been given previously, override with the new value | |
// | |
fclose (VtfFP); | |
} | |
VtfFP = fopen (LongFilePath (VtfFileName), "rb"); | |
if (VtfFP == NULL) { | |
Error (NULL, 0, 0001, "Error opening file", VtfFileName); | |
goto ERROR; | |
} | |
continue; | |
} | |
if ((stricmp (argv[Index], "-r") == 0) || (stricmp (argv[Index], "--baseaddr") == 0)) { | |
if (FirstRoundB) { | |
Status = AsciiStringToUint64 (argv[Index + 1], FALSE, &StartAddress1); | |
FirstRoundB = FALSE; | |
} else { | |
Status = AsciiStringToUint64 (argv[Index + 1], FALSE, &StartAddress2); | |
} | |
if (Status != EFI_SUCCESS) { | |
Error (NULL, 0, 2000, "Invalid option value", "%s is Bad FV start address.", argv[Index + 1]); | |
goto ERROR; | |
} | |
continue; | |
} | |
if ((stricmp (argv[Index], "-s") == 0) || (stricmp (argv[Index], "--size") == 0)) { | |
if (FirstRoundS) { | |
Status = AsciiStringToUint64 (argv[Index + 1], FALSE, &FwVolSize1); | |
FirstRoundS = FALSE; | |
} else { | |
Status = AsciiStringToUint64 (argv[Index + 1], FALSE, &FwVolSize2); | |
SecondVTF = TRUE; | |
} | |
if (Status != EFI_SUCCESS) { | |
Error (NULL, 0, 2000, "Invalid option value", "%s is Bad FV size.", argv[Index + 1]); | |
goto ERROR; | |
} | |
continue; | |
} | |
if ((stricmp (argv[Index], "-v") == 0) || (stricmp (argv[Index], "--verbose") == 0)) { | |
VerboseMode = TRUE; | |
Index--; | |
continue; | |
} | |
if ((stricmp (argv[Index], "-q") == 0) || (stricmp (argv[Index], "--quiet") == 0)) { | |
QuietMode = TRUE; | |
Index--; | |
continue; | |
} | |
if ((stricmp (argv[Index], "-d") == 0) || (stricmp (argv[Index], "--debug") == 0)) { | |
// | |
// debug level specified | |
// | |
Status = AsciiStringToUint64(argv[Index + 1], FALSE, &DebugLevel); | |
if (EFI_ERROR (Status)) { | |
Error (NULL, 0, 1003, "Invalid option value", "%s = %s", argv[Index], argv[Index + 1]); | |
goto ERROR; | |
} | |
if (DebugLevel > 9) { | |
Error (NULL, 0, 2000, "Invalid option value", "Unrecognized argument %s.", argv[Index + 1]); | |
goto ERROR; | |
} | |
if((DebugLevel <= 9) &&(DebugLevel >= 5)) { | |
DebugMode = TRUE; | |
} else { | |
DebugMode = FALSE; | |
} | |
continue; | |
} | |
Error (NULL, 0, 2000, "Invalid parameter", "Unrecognized argument %s.", argv[Index]); | |
goto ERROR; | |
} | |
if (VtfFP == NULL) { | |
Error (NULL, 0, 2000, "Invalid parameter", "No BS Image INF file is specified"); | |
goto ERROR; | |
} | |
if (FirstRoundB) { | |
Error (NULL, 0, 2000, "Invalid parameter", "No FV base address is specified"); | |
goto ERROR; | |
} | |
if (FirstRoundS) { | |
Error (NULL, 0, 2000, "Invalid parameter", "No FV Size is specified"); | |
goto ERROR; | |
} | |
// | |
// All Parameters has been parsed, now set the message print level | |
// | |
if (QuietMode) { | |
SetPrintLevel(40); | |
} else if (VerboseMode) { | |
SetPrintLevel(15); | |
} else if (DebugMode) { | |
SetPrintLevel(DebugLevel); | |
} | |
if (VerboseMode) { | |
VerboseMsg("%s tool start.\n", UTILITY_NAME); | |
} | |
if (VTF_OUTPUT == FALSE) { | |
if (SecondVTF == TRUE) { | |
OutFileName1 = VTF_OUTPUT_FILE1; | |
OutFileName2 = VTF_OUTPUT_FILE2; | |
} else { | |
OutFileName1 = VTF_OUTPUT_FILE1; | |
} | |
SymFileName = VTF_SYM_FILE; | |
} else { | |
assert (OutFileName1); | |
INTN OutFileNameLen = strlen(OutFileName1); | |
INTN NewIndex; | |
for (NewIndex = OutFileNameLen; NewIndex > 0; --NewIndex) { | |
if (OutFileName1[NewIndex] == '/' || OutFileName1[NewIndex] == '\\') { | |
break; | |
} | |
} | |
if (NewIndex == 0) { | |
SymFileName = VTF_SYM_FILE; | |
} else { | |
INTN SymFileNameLen = NewIndex + 1 + strlen(VTF_SYM_FILE); | |
SymFileName = malloc(SymFileNameLen + 1); | |
if (SymFileName == NULL) { | |
Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!"); | |
goto ERROR; | |
} | |
memcpy(SymFileName, OutFileName1, NewIndex + 1); | |
memcpy(SymFileName + NewIndex + 1, VTF_SYM_FILE, strlen(VTF_SYM_FILE)); | |
SymFileName[SymFileNameLen] = '\0'; | |
} | |
if (DebugMode) { | |
DebugMsg(UTILITY_NAME, 0, DebugLevel, SymFileName, NULL); | |
} | |
} | |
// | |
// Call the GenVtfImage | |
// | |
if (DebugMode) { | |
DebugMsg(UTILITY_NAME, 0, DebugLevel, "Start to generate the VTF image\n", NULL); | |
} | |
Status = GenerateVtfImage (StartAddress1, FwVolSize1, StartAddress2, FwVolSize2, VtfFP); | |
if (EFI_ERROR (Status)) { | |
switch (Status) { | |
case EFI_INVALID_PARAMETER: | |
Error (NULL, 0, 2000, "Invalid parameter", "Invalid parameter passed to GenVtf function."); | |
break; | |
case EFI_ABORTED: | |
Error (NULL, 0, 3000, "Invalid", "Error detected while creating the file image."); | |
break; | |
case EFI_OUT_OF_RESOURCES: | |
Error (NULL, 0, 4002, "Resource", "GenVtfImage function could not allocate required resources."); | |
break; | |
case EFI_VOLUME_CORRUPTED: | |
Error (NULL, 0, 3000, "Invalid", "No base address was specified."); | |
break; | |
default: | |
Error (NULL, 0, 3000, "Invalid", "GenVtfImage function returned unknown status %x.", (int) Status ); | |
break; | |
} | |
} | |
ERROR: | |
if (VtfFP != NULL) { | |
fclose (VtfFP); | |
} | |
if (DebugMode) { | |
DebugMsg(UTILITY_NAME, 0, DebugLevel, "VTF image generated successful\n", NULL); | |
} | |
if (VerboseMode) { | |
VerboseMsg("%s tool done with return code is 0x%x.\n", UTILITY_NAME, GetUtilityStatus ()); | |
} | |
return GetUtilityStatus(); | |
} |