blob: a294a2eea3f25579b28df5231f749dfe2e0ed275 [file] [log] [blame]
/*++
Copyright (c) 1999 - 2006, Intel Corporation. All rights reserved
This software and associated documentation (if any) is furnished
under a license and may only be used or copied in accordance
with the terms of the license. Except as permitted by such
license, no part of this software or documentation may be
reproduced, stored in a retrieval system, or transmitted in any
form or by any means without the express written consent of
Intel Corporation.
Module Name:
GenBsfImage.c
Abstract:
This file contains functions required to generate a boot strap file (BSF)
also known as the Volume Top File (VTF)
--*/
//
// Module Coded to EFI 2.0 Coding Conventions
//
#include <FvLib.h>
#include <Common/UefiBaseTypes.h>
#include "GenBsfImage.h"
#include <Guid/FirmwareFileSystem.h>
#include "CommonLib.h"
//
// Global variables
//
EFI_GUID Bsf1NameGuid = EFI_IPF_VTF1_GUID
EFI_GUID Bsf2NameGuid = EFI_IPF_VTF2_GUID
CHAR8 **TokenStr;
CHAR8 **OrgStrTokPtr;
PARSED_BSF_INFO *FileListPtr;
PARSED_BSF_INFO *FileListHeadPtr;
VOID *Bsf1Buffer;
VOID *Bsf1EndBuffer;
VOID *Bsf2Buffer;
VOID *Bsf2EndBuffer;
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 BSF Present, if yes then will be used
// to decide about adding FFS header to pad data
//
BOOLEAN BSFPresent = FALSE;
//
// Address related information
//
UINT64 Fv1BaseAddress = 0;
UINT64 Fv2BaseAddress = 0;
UINT64 Fv1EndAddress = 0;
UINT64 Fv2EndAddress = 0;
UINT32 Bsf1TotalSize = SIZE_TO_OFFSET_PAL_A_END;
UINT64 Bsf1LastStartAddress = 0;
UINT32 Bsf2TotalSize = 0;
UINT64 Bsf2LastStartAddress = 0;
UINT32 BufferToTop = 0;
//
// IA32 Reset Vector Bin name
//
CHAR8 IA32BinFile[FILE_NAME_SIZE];
//
// Function Implementations
//
VOID
BuildTokenList (
IN CHAR8 *Token
)
/*++
Routine Description:
This function builds the token list in an array which will be parsed later
Arguments:
Token - The pointer of string
Returns:
None
--*/
{
strcpy (*TokenStr, Token);
TokenStr++;
}
EFI_STATUS
ConvertVersionInfo (
IN CHAR8 *Str,
IN OUT UINT8 *MajorVer,
IN OUT UINT8 *MinorVer
)
/*++
Routine Description:
This function converts GUID string to GUID
Arguments:
Str - String representing in form XX.XX
MajorVer - The major vertion
MinorVer - The minor vertion
Returns:
EFI_SUCCESS - The fuction completed successfully.
--*/
{
CHAR8 StrPtr[40];
CHAR8 *Token;
UINTN Length;
UINTN Major;
UINTN Minor;
Major = 0;
Minor = 0;
memset (StrPtr, 0, 40);
Token = strtok (Str, ".");
while (Token != NULL) {
strcat (StrPtr, Token);
Token = strtok (NULL, ".");
}
Length = strlen (StrPtr);
sscanf (
StrPtr,
"%01x%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')) {
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++;
}
}
VOID
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];
CHAR8 OrgLine[FILE_NAME_SIZE];
CHAR8 Str[FILE_NAME_SIZE];
CHAR8 Delimit[] = "=";
while (fgets (Buff, sizeof (Buff), Fp) != NULL) {
strcpy (OrgLine, Buff);
TrimLine (Buff);
if (Buff[0] == 0) {
continue;
}
Token = strtok (Buff, Delimit);
while (Token != NULL) {
strcpy (Str, Token);
BuildTokenList (Str);
Token = strtok (NULL, Delimit);
}
}
}
EFI_STATUS
InitializeComps (
VOID
)
/*++
Routine Description:
This function intializes the relevant global variable which is being
used to store the information retrieved from INF file. This also initializes
the BSF symbol file.
Arguments:
None
Returns:
EFI_SUCCESS - The function completed successfully
EFI_OUT_OF_RESOURCES - Malloc failed.
--*/
{
FileListPtr = malloc (sizeof (PARSED_BSF_INFO));
if (FileListPtr == NULL) {
return EFI_OUT_OF_RESOURCES;
}
FileListHeadPtr = FileListPtr;
memset (FileListPtr, 0, sizeof (PARSED_BSF_INFO));
FileListPtr->NextBsfInfo = NULL;
remove (BSF_SYM_FILE);
return EFI_SUCCESS;
}
VOID
ParseAndUpdateComponents (
IN PARSED_BSF_INFO *BsfInfo
)
/*++
Routine Description:
This function intializes the relevant global variable which is being
used to store the information retrieved from INF file.
Arguments:
BsfInfo - A pointer to the BSF Info Structure
Returns:
None
--*/
{
UINT64 StringValue;
while (*TokenStr != NULL && (_stricmp (*TokenStr, "COMP_NAME") != 0)) {
if (_stricmp (*TokenStr, "COMP_LOC") == 0) {
TokenStr++;
if (_stricmp (*TokenStr, "F") == 0) {
BsfInfo->LocationType = FIRST_VTF;
} else if (_stricmp (*TokenStr, "S") == 0) {
BsfInfo->LocationType = SECOND_VTF;
} else {
BsfInfo->LocationType = NONE;
printf ("\nERROR: Unknown location for component %s", BsfInfo->CompName);
}
} else if (_stricmp (*TokenStr, "COMP_TYPE") == 0) {
TokenStr++;
if (AsciiStringToUint64 (*TokenStr, FALSE, &StringValue) != EFI_SUCCESS) {
printf ("\nERROR: Could not read a numeric value from \"%s\".", TokenStr);
return ;
}
BsfInfo->CompType = (UINT8) StringValue;
} else if (_stricmp (*TokenStr, "COMP_VER") == 0) {
TokenStr++;
if (_stricmp (*TokenStr, "-") == 0) {
BsfInfo->VersionPresent = FALSE;
BsfInfo->MajorVer = 0;
BsfInfo->MinorVer = 0;
} else {
BsfInfo->VersionPresent = TRUE;
ConvertVersionInfo (*TokenStr, &BsfInfo->MajorVer, &BsfInfo->MinorVer);
}
} else if (_stricmp (*TokenStr, "COMP_BIN") == 0) {
TokenStr++;
strcpy (BsfInfo->CompBinName, *TokenStr);
} else if (_stricmp (*TokenStr, "COMP_SYM") == 0) {
TokenStr++;
strcpy (BsfInfo->CompSymName, *TokenStr);
} else if (_stricmp (*TokenStr, "COMP_SIZE") == 0) {
TokenStr++;
if (_stricmp (*TokenStr, "-") == 0) {
BsfInfo->PreferredSize = FALSE;
BsfInfo->CompSize = 0;
} else {
BsfInfo->PreferredSize = TRUE;
if (AsciiStringToUint64 (*TokenStr, FALSE, &StringValue) != EFI_SUCCESS) {
printf ("\nERROR: Could not read a numeric value from \"%s\".", TokenStr);
return ;
}
BsfInfo->CompSize = (UINTN) StringValue;
}
} else if (_stricmp (*TokenStr, "COMP_CS") == 0) {
TokenStr++;
if (_stricmp (*TokenStr, "1") == 0) {
BsfInfo->CheckSumRequired = 1;
} else if (_stricmp (*TokenStr, "0") == 0) {
BsfInfo->CheckSumRequired = 0;
} else {
printf ("\nERROR: Bad information in INF file about Checksum required field");
}
}
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
--*/
{
UINTN SectionOptionFlag;
UINTN SectionCompFlag;
SectionOptionFlag = 0;
SectionCompFlag = 0;
TokenStr = OrgStrTokPtr;
while (*TokenStr != NULL) {
if (_stricmp (*TokenStr, "[OPTIONS]") == 0) {
SectionOptionFlag = 1;
SectionCompFlag = 0;
}
if (_stricmp (*TokenStr, "[COMPONENTS]") == 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->NextBsfInfo = malloc (sizeof (PARSED_BSF_INFO));
if (FileListPtr->NextBsfInfo == NULL) {
printf ("Error: Out of memory resources.\n");
break;
}
FileListPtr = FileListPtr->NextBsfInfo;
memset (FileListPtr, 0, sizeof (PARSED_BSF_INFO));
FileListPtr->NextBsfInfo = NULL;
continue;
} else {
break;
}
}
TokenStr++;
}
}
EFI_STATUS
GetBsfRelatedInfoFromInfFile (
IN CHAR8 *FileName
)
/*++
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 BSF
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 informations
EFI_OUT_OF_RESOURCES - Malloc Failed
EFI_SUCCESS - The function completed successfully
--*/
{
FILE *Fp;
UINTN Index;
EFI_STATUS Status;
Fp = fopen (FileName, "r");
if (Fp == NULL) {
printf ("\nERROR: Error in opening %s file\n", FileName);
return EFI_ABORTED;
}
ValidLineCount (Fp);
if (ValidLineNum == 0) {
printf ("\nERROR: File doesn't contain any valid informations");
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) {
free (OrgStrTokPtr);
return EFI_OUT_OF_RESOURCES;
}
memset (*TokenStr, 0, FILE_NAME_SIZE);
// free (*TokenStr);
TokenStr++;
}
TokenStr = NULL;
TokenStr = OrgStrTokPtr;
fseek (Fp, 0L, SEEK_SET);
Status = InitializeComps ();
if (Status != EFI_SUCCESS) {
free (OrgStrTokPtr);
return Status;
}
ParseInputFile (Fp);
InitializeInFileInfo ();
if (Fp) {
fclose (Fp);
}
free (OrgStrTokPtr);
return EFI_SUCCESS;
}
VOID
GetRelativeAddressInBsfBuffer (
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 BSF
Returns:
--*/
{
UINT64 TempAddress;
UINT8 *LocalBuff;
if (LocType == FIRST_VTF) {
LocalBuff = (UINT8 *) Bsf1EndBuffer;
TempAddress = Fv1EndAddress - Address;
*RelativeAddress = (UINTN) LocalBuff - (UINTN) TempAddress;
} else {
LocalBuff = (UINT8 *) Bsf2EndBuffer;
TempAddress = Fv2EndAddress - Address;
*RelativeAddress = (UINTN) LocalBuff - (UINTN) TempAddress;
}
}
EFI_STATUS
GetComponentVersionInfo (
IN OUT PARSED_BSF_INFO *BsfInfo,
IN UINT8 *Buffer
)
/*++
Routine Description:
This function will extract the version information from File
Arguments:
BsfInfo - A Pointer to the BSF 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 (BsfInfo->CompType) {
case COMP_TYPE_FIT_PAL_A:
case COMP_TYPE_FIT_PAL_B:
memcpy (&VersionInfo, (Buffer + 8), sizeof (UINT16));
BsfInfo->MajorVer = (UINT8) ((VersionInfo & 0xFF00) >> 8);
BsfInfo->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 BSF 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 BSF buffer.
//
GetRelativeAddressInBsfBuffer (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 BSF
// Buffer.
//
GetRelativeAddressInBsfBuffer (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 BSF buffer.
//
GetRelativeAddressInBsfBuffer (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 BSF
// Buffer.
//
GetRelativeAddressInBsfBuffer (FitTableAdd, &RelativeAddress, FIRST_VTF);
TmpFitPtr = (FIT_TABLE *) RelativeAddress;
NumFitComponents = TmpFitPtr->CompSize;
for (Index = 0; Index < NumFitComponents; Index++) {
if ((TmpFitPtr->CvAndType & FIT_TYPE_MASK) == COMP_TYPE_FIT_UNUSED) {
*FitPtr = TmpFitPtr;
break;
}
TmpFitPtr++;
}
return EFI_SUCCESS;
}
INTN
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 informations 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
//
Bsf1LastStartAddress -= 0x10;
Bsf1TotalSize += 0x10;
GetRelativeAddressInBsfBuffer (Bsf1LastStartAddress, &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 BSF component will reside outside the BSF, we will not have its
// binary image while creating BSF, hence we will not perform checksum at
// this time. Once Firmware Volume is being created which will contain this
// BSF, it will fix the FIT table for all the non BSF component and hence
// checksum
//
CompFitPtr->CheckSum = 0;
}
EFI_STATUS
UpdateFitEntryForNonBSFComp (
IN PARSED_BSF_INFO *BsfInfo
)
/*++
Routine Description:
This function updates the information about non BSF component in FIT TABLE.
Since non BSF componets binaries are not part of BSF binary, we would still
be required to update its location information in Firmware Volume, inside
FIT table.
Arguments:
BsfInfo - Pointer to BSF 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) {
printf ("\nERROR: 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 = BsfInfo->CompSize;
CompFitPtr->CompVersion = MAKE_VERSION (BsfInfo->MajorVer, BsfInfo->MinorVer);
CompFitPtr->CvAndType = CV_N_TYPE (BsfInfo->CheckSumRequired, BsfInfo->CompType);
//
// Since non BSF component will reside outside the BSF, we will not have its
// binary image while creating BSF, hence we will not perform checksum at
// this time. Once Firmware Volume is being created which will contain this
// BSF, it will fix the FIT table for all the non BSF 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 BSF 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_BSF_INFO *BsfInfo,
IN UINT64 *CompStartAddress
)
/*++
Routine Description:
This function updated the architectural entry point in IPF, SALE_ENTRY.
Arguments:
BsfInfo - Pointer to BSF Info Structure
CompStartAddress - Pointer to Component Start Address
Returns:
EFI_INVALID_PARAMETER - The parameter is invalid
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];
Fp = fopen (BsfInfo->CompSymName, "r+b");
if (Fp == NULL) {
printf ("\nERROR: Error in opening file");
return EFI_INVALID_PARAMETER;
}
while (fgets (Buff, sizeof (Buff), Fp) != NULL) {
fscanf (
Fp,
"%s %s %s %s %s %s %s",
&Buff1,
&Buff2,
&OffsetStr,
&Buff3,
&Buff4,
&Buff5,
&Token
);
if (_stricmp (Token, "SALE_ENTRY") == 0) {
break;
}
}
Offset = strtoul (OffsetStr, NULL, 16);
*CompStartAddress += Offset;
SalEntryAdd = Fv1EndAddress - (SIZE_IA32_RESET_VECT + SIZE_SALE_ENTRY_POINT);
GetRelativeAddressInBsfBuffer (SalEntryAdd, &RelativeAddress, FIRST_VTF);
memcpy ((VOID *) RelativeAddress, (VOID *) CompStartAddress, sizeof (UINT64));
return EFI_SUCCESS;
}
EFI_STATUS
CreateAndUpdateComponent (
IN PARSED_BSF_INFO *BsfInfo
)
/*++
Routine Description:
This function reads the binary file for each components and update them
in BSF Buffer as well as in FIT table. If the component is located in non
BSF area, only the FIT table address will be updated
Arguments:
BsfInfo - 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.
EFI_INVALID_PARAMETER Value returned from call to UpdateEntryPoint()
EFI_OUT_OF_RESOURCES Memory allocation failure.
--*/
{
EFI_STATUS Status;
UINT64 CompStartAddress;
UINT64 FileSize;
UINT64 NumByteRead;
UINT64 NumAdjustByte;
UINT8 *Buffer;
FILE *Fp;
FIT_TABLE *CompFitPtr;
BOOLEAN Aligncheck;
if (BsfInfo->LocationType == NONE) {
UpdateFitEntryForNonBSFComp (BsfInfo);
return EFI_SUCCESS;
}
Fp = fopen (BsfInfo->CompBinName, "r+b");
if (Fp == NULL) {
printf ("\nERROR: Opening file %s", BsfInfo->CompBinName);
return EFI_ABORTED;
}
FileSize = _filelength (fileno (Fp));
if ((BsfInfo->CompType == COMP_TYPE_FIT_PAL_B) || (BsfInfo->CompType == COMP_TYPE_FIT_PAL_A_SPECIFIC)) {
//
// BUGBUG: Satish to correct
//
FileSize -= SIZE_OF_PAL_HEADER;
}
if (BsfInfo->PreferredSize) {
if (FileSize > BsfInfo->CompSize) {
printf ("\nERROR: The component size is more than specified size");
return EFI_ABORTED;
}
FileSize = BsfInfo->CompSize;
}
Buffer = malloc ((UINTN) FileSize);
if (Buffer == NULL) {
return EFI_OUT_OF_RESOURCES;
}
memset (Buffer, 0, (UINTN) FileSize);
if ((BsfInfo->CompType == COMP_TYPE_FIT_PAL_B) || (BsfInfo->CompType == COMP_TYPE_FIT_PAL_A_SPECIFIC)) {
//
// Read first 64 bytes of PAL header and use it to find version info
//
NumByteRead = 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 (!BsfInfo->VersionPresent) {
GetComponentVersionInfo (BsfInfo, Buffer);
}
}
NumByteRead = 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 (BsfInfo->CompType != COMP_TYPE_FIT_PAL_B) {
if (!BsfInfo->VersionPresent) {
GetComponentVersionInfo (BsfInfo, Buffer);
}
}
if (BsfInfo->LocationType == SECOND_VTF) {
CompStartAddress = (Bsf2LastStartAddress - FileSize);
} else {
CompStartAddress = (Bsf1LastStartAddress - FileSize);
}
if (BsfInfo->CompType == COMP_TYPE_FIT_PAL_B) {
Aligncheck = CheckAddressAlignment (CompStartAddress, 32 * 1024, &NumAdjustByte);
} else {
Aligncheck = CheckAddressAlignment (CompStartAddress, 8, &NumAdjustByte);
}
if (!Aligncheck) {
CompStartAddress -= NumAdjustByte;
}
if (BsfInfo->LocationType == SECOND_VTF) {
Bsf2LastStartAddress = CompStartAddress;
Bsf2TotalSize += (UINT32) (FileSize + NumAdjustByte);
Status = UpdateBsfBuffer (CompStartAddress, Buffer, FileSize, SECOND_VTF);
} else {
Bsf1LastStartAddress = CompStartAddress;
Bsf1TotalSize += (UINT32) (FileSize + NumAdjustByte);
Status = UpdateBsfBuffer (CompStartAddress, Buffer, FileSize, FIRST_VTF);
}
if (EFI_ERROR (Status)) {
return EFI_ABORTED;
}
GetNextAvailableFitPtr (&CompFitPtr);
CompFitPtr->CompAddress = CompStartAddress | IPF_CACHE_BIT;
assert ((FileSize % 16) == 0);
CompFitPtr->CompSize = (UINT32) (FileSize / 16);
CompFitPtr->CompVersion = MAKE_VERSION (BsfInfo->MajorVer, BsfInfo->MinorVer);
CompFitPtr->CvAndType = CV_N_TYPE (BsfInfo->CheckSumRequired, BsfInfo->CompType);
if (BsfInfo->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, BSF_SYM_FILE, BsfInfo->CompSymName);
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
// BSF till we work out how to determine the SALE_ENTRY through it. We will need
// to clarify so many related questions
// !!!!!!!!!!!!!!!!!!!!!!!
if (BsfInfo->CompType == COMP_TYPE_FIT_PEICORE) {
Status = UpdateEntryPoint (BsfInfo, &CompStartAddress);
}
return Status;
}
EFI_STATUS
CreateAndUpdatePAL_A (
IN PARSED_BSF_INFO *BsfInfo
)
/*++
Routine Description:
This function reads the binary file for each components and update them
in BSF Buffer as well as FIT table
Arguments:
BsfInfo - 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;
UINT64 NumByteRead;
UINT8 *Buffer;
FILE *Fp;
FIT_TABLE *PalFitPtr;
Fp = fopen (BsfInfo->CompBinName, "r+b");
if (Fp == NULL) {
printf ("\nERROR: Opening file %s", BsfInfo->CompBinName);
return EFI_ABORTED;
}
FileSize = _filelength (fileno (Fp));
FileSize -= SIZE_OF_PAL_HEADER;
if (BsfInfo->PreferredSize) {
if (FileSize > BsfInfo->CompSize) {
printf ("\nERROR: The PAL_A Size is more than specified size");
return EFI_ABORTED;
}
FileSize = BsfInfo->CompSize;
}
Buffer = malloc ((UINTN) FileSize);
if (Buffer == NULL) {
return EFI_OUT_OF_RESOURCES;
}
memset (Buffer, 0, (UINTN) FileSize);
//
// Read, Get version Info and discard the PAL header.
//
NumByteRead = fread (Buffer, sizeof (UINT8), SIZE_OF_PAL_HEADER, Fp);
//
// Extract the version info from header of PAL_A. Once done, discrad this buffer
//
if (!BsfInfo->VersionPresent) {
GetComponentVersionInfo (BsfInfo, Buffer);
}
//
// Read PAL_A file in a buffer
//
NumByteRead = fread (Buffer, sizeof (UINT8), (UINTN) FileSize, Fp);
fclose (Fp);
PalStartAddress = Fv1EndAddress - (SIZE_TO_OFFSET_PAL_A_END + FileSize);
Bsf1LastStartAddress = PalStartAddress;
Bsf1TotalSize += (UINT32) FileSize;
Status = UpdateBsfBuffer (PalStartAddress, Buffer, FileSize, FIRST_VTF);
AbsAddress = Fv1EndAddress - SIZE_TO_PAL_A_FIT;
GetRelativeAddressInBsfBuffer (AbsAddress, &RelativeAddress, FIRST_VTF);
PalFitPtr = (FIT_TABLE *) RelativeAddress;
PalFitPtr->CompAddress = PalStartAddress | IPF_CACHE_BIT;
assert ((FileSize % 16) == 0);
PalFitPtr->CompSize = (UINT32) (FileSize / 16);
PalFitPtr->CompVersion = MAKE_VERSION (BsfInfo->MajorVer, BsfInfo->MinorVer);
PalFitPtr->CvAndType = CV_N_TYPE (BsfInfo->CheckSumRequired, BsfInfo->CompType);
if (BsfInfo->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, BSF_SYM_FILE, BsfInfo->CompSymName);
if (EFI_ERROR (Status)) {
//
// At this time, SYM files are not required, so continue on error.
//
}
return Status;
}
EFI_STATUS
CreateFitTableAndInitialize (
IN PARSED_BSF_INFO *BsfInfo
)
/*++
Routine Description:
This function creates and intializes FIT table which would be used to
add component info inside this
Arguments:
BsfInfo - 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 (!BsfInfo->PreferredSize) {
printf ("\nERROR: FIT could not be allocated becuase there are no size information");
return EFI_ABORTED;
}
if ((BsfInfo->CompSize % 16) != 0) {
printf ("\nERROR: Invalid Fit Table Size, not multiple of 16 bytes. Please correct the size");
}
PalFitTableAdd = Fv1EndAddress - SIZE_TO_PAL_A_FIT;
GetRelativeAddressInBsfBuffer (PalFitTableAdd, &RelativeAddress, FIRST_VTF);
PalFitPtr = (FIT_TABLE *) RelativeAddress;
PalFitTableAdd = (PalFitPtr->CompAddress - BsfInfo->CompSize);
FitTableAdd = (PalFitPtr->CompAddress - 0x10) - BsfInfo->CompSize;
FitTableAddressOffset = Fv1EndAddress - (SIZE_IA32_RESET_VECT + SIZE_SALE_ENTRY_POINT + SIZE_FIT_TABLE_ADD);
GetRelativeAddressInBsfBuffer (FitTableAddressOffset, &RelativeAddress, FIRST_VTF);
*(UINT64 *) RelativeAddress = FitTableAdd;
GetRelativeAddressInBsfBuffer (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 (((BsfInfo->CompSize & 0x00FFFFFF) % 16) == 0);
FitStartPtr->CompSize = (BsfInfo->CompSize & 0x00FFFFFF) / 16;
FitStartPtr->CompVersion = MAKE_VERSION (BsfInfo->MajorVer, BsfInfo->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 (BsfInfo->CheckSumRequired, BsfInfo->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++;
}
Bsf1TotalSize += BsfInfo->CompSize;
Bsf1LastStartAddress -= BsfInfo->CompSize;
return EFI_SUCCESS;
}
EFI_STATUS
WriteBsfBinary (
IN CHAR8 *FileName,
IN UINT32 BsfSize,
IN LOC_TYPE LocType
)
/*++
Routine Description:
Write Firmware Volume from memory to a file.
Arguments:
FileName - Output File Name which needed to be created/
BsfSize - FileSize
LocType - The type of the BSF
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 *BsfBuffer;
UINTN RelativeAddress;
if (LocType == FIRST_VTF) {
GetRelativeAddressInBsfBuffer (Bsf1LastStartAddress, &RelativeAddress, FIRST_VTF);
BsfBuffer = (VOID *) RelativeAddress;
} else {
GetRelativeAddressInBsfBuffer (Bsf2LastStartAddress, &RelativeAddress, SECOND_VTF);
BsfBuffer = (VOID *) RelativeAddress;
}
Fp = fopen (FileName, "w+b");
if (Fp == NULL) {
printf ("Error in opening file %s\n", FileName);
return EFI_ABORTED;
}
NumByte = fwrite (BsfBuffer, sizeof (UINT8), (UINTN) BsfSize, Fp);
if (Fp) {
fclose (Fp);
}
if (NumByte != (sizeof (UINT8) * BsfSize)) {
printf ("\nERROR: Could not copy buffer into file %s ", FileName);
return EFI_ABORTED;
}
return EFI_SUCCESS;
}
EFI_STATUS
UpdateBsfBuffer (
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 BSF
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) < (Bsf1LastStartAddress | IPF_CACHE_BIT)) {
printf ("ERROR: Start Address is less then the BSF start address\n");
return EFI_ABORTED;
}
LocalBufferPtrToWrite = (UINT8 *) Bsf1EndBuffer;
LocalBufferPtrToWrite -= (Fv1EndAddress - StartAddress);
} else {
if ((StartAddress | IPF_CACHE_BIT) < (Bsf2LastStartAddress | IPF_CACHE_BIT)) {
printf ("ERROR: Start Address is less then the BSF start address\n");
return EFI_ABORTED;
}
LocalBufferPtrToWrite = (UINT8 *) Bsf2EndBuffer;
LocalBufferPtrToWrite -= (Fv2EndAddress - StartAddress);
}
memcpy (LocalBufferPtrToWrite, Buffer, (UINTN) DataSize);
return EFI_SUCCESS;
}
EFI_STATUS
UpdateFfsHeader (
IN UINT32 TotalBsfSize,
IN LOC_TYPE LocType
)
/*++
Routine Description:
Update the Firmware Volume Buffer with requested buffer data
Arguments:
TotalBsfSize - Size of the BSF
Fileoffset - The start of the file relative to the start of the FV.
LocType - The type of the BSF
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 BSF file header location
//
if (LocType == FIRST_VTF) {
GetRelativeAddressInBsfBuffer (Bsf1LastStartAddress, &RelativeAddress, FIRST_VTF);
FileHeader = (EFI_FFS_FILE_HEADER *) RelativeAddress;
} else {
GetRelativeAddressInBsfBuffer (Bsf2LastStartAddress, &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_FREEFORM;
FileHeader->Attributes = FFS_ATTRIB_CHECKSUM;
//
// Now FileSize includes the EFI_FFS_FILE_HEADER
//
FileHeader->Size[0] = (UINT8) (TotalBsfSize & 0x000000FF);
FileHeader->Size[1] = (UINT8) ((TotalBsfSize & 0x0000FF00) >> 8);
FileHeader->Size[2] = (UINT8) ((TotalBsfSize & 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, TotalBsfSize);
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 BSF will be attached..
Returns:
EFI_SUCCESS - The function completed successfully
EFI_UNSUPPORTED - The input parameter is error
--*/
{
if ((BaseAddress >= 0) && (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 BSF 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 *LocalBsfBuffer;
UINTN FileSize;
UINTN NumByteRead;
FILE *Fp;
if (!strcmp (FileName, "")) {
return EFI_INVALID_PARAMETER;
}
Fp = fopen (FileName, "r+b");
if (Fp == NULL) {
printf ("\nERROR: Unable to open the file %s", FileName);
}
FileSize = _filelength (fileno (Fp));
if (FileSize > 16) {
return EFI_ABORTED;
}
Buffer = malloc (FileSize);
if (Buffer == NULL) {
return EFI_OUT_OF_RESOURCES;
}
NumByteRead = fread (Buffer, sizeof (UINT8), FileSize, Fp);
LocalBsfBuffer = (UINT8 *) Bsf1EndBuffer - SIZE_IA32_RESET_VECT;
memcpy (LocalBsfBuffer, Buffer, FileSize);
if (Buffer) {
free (Buffer);
}
return EFI_SUCCESS;
}
VOID
CleanUpMemory (
VOID
)
/*++
Routine Description:
This function cleans up any allocated buffer
Arguments:
NONE
Returns:
NONE
--*/
{
PARSED_BSF_INFO *TempFileListPtr;
if (Bsf1Buffer) {
free (Bsf1Buffer);
}
if (Bsf2Buffer) {
free (Bsf2Buffer);
}
//
// Cleanup the buffer which was allocated to read the file names from FV.INF
//
FileListPtr = FileListHeadPtr;
while (FileListPtr != NULL) {
TempFileListPtr = FileListPtr->NextBsfInfo;
free (FileListPtr);
FileListPtr = TempFileListPtr;
}
}
EFI_STATUS
ProcessAndCreateBsf (
IN UINT64 Size
)
/*++
Routine Description:
This function process the link list created during INF file parsing
and create component in BSF and updates its info in FIT table
Arguments:
Size - Size of the Firmware Volume of which, this BSF belongs to.
Returns:
EFI_UNSUPPORTED - Unknown FIT type
EFI_SUCCESS - The function completed successfully
--*/
{
EFI_STATUS Status;
PARSED_BSF_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:
Status = CreateFitTableAndInitialize (ParsedInfoPtr);
break;
//
// COMP_TYPE_FIT_PAL_A is a special case, hence handle it here
//
case COMP_TYPE_FIT_PAL_A:
Status = CreateAndUpdatePAL_A (ParsedInfoPtr);
//
// Based on BSF 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 BSF will be
// of part.
//
if (Status == EFI_SUCCESS) {
UpdateFitEntryForFwVolume (Size);
}
break;
case COMP_TYPE_FIT_FV_BOOT:
//
// 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 BSF and create appropriate entry about this
// component in FIT Entry.
//
Status = CreateAndUpdateComponent (ParsedInfoPtr);
if (EFI_ERROR (Status)) {
printf ("ERROR: Updating %s component.\n", ParsedInfoPtr->CompName);
}
break;
}
ParsedInfoPtr = ParsedInfoPtr->NextBsfInfo;
}
return Status;
}
EFI_STATUS
GenerateBsfImage (
IN UINT64 StartAddress1,
IN UINT64 Size1,
IN UINT64 StartAddress2,
IN UINT64 Size2
)
/*++
Routine Description:
This is the main function which will be called from application.
Arguments:
StartAddress1 - The start address of the first BSF
Size1 - The size of the first BSF
StartAddress2 - The start address of the second BSF
Size2 - The size of the second BSF
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:
GetBsfRelatedInfoFromInfFile
ProcessAndCreateBsf
UpdateIA32ResetVector
UpdateFfsHeader
WriteBsfBinary
--*/
{
EFI_STATUS Status;
CHAR8 OutFileName1[FILE_NAME_SIZE];
CHAR8 OutFileName2[FILE_NAME_SIZE];
BOOLEAN SecondBSF;
Status = EFI_UNSUPPORTED;
if (StartAddress2 == 0) {
SecondBSF = FALSE;
} else {
SecondBSF = TRUE;
}
Fv1BaseAddress = StartAddress1;
Fv1EndAddress = Fv1BaseAddress + Size1;
memset (OutFileName1, 0, FILE_NAME_SIZE);
sprintf (
OutFileName1,
"%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x-%s",
Bsf1NameGuid.Data1,
Bsf1NameGuid.Data2,
Bsf1NameGuid.Data3,
Bsf1NameGuid.Data4[0],
Bsf1NameGuid.Data4[1],
Bsf1NameGuid.Data4[2],
Bsf1NameGuid.Data4[3],
Bsf1NameGuid.Data4[4],
Bsf1NameGuid.Data4[5],
Bsf1NameGuid.Data4[6],
Bsf1NameGuid.Data4[7],
BSF_OUTPUT_FILE
);
//
// The image buffer for the First BSF
//
Bsf1Buffer = malloc ((UINTN) Size1);
if (Bsf1Buffer == NULL) {
printf ("\nERROR: Not enough resource to create memory mapped file for Boot Strap File");
return EFI_OUT_OF_RESOURCES;
}
memset (Bsf1Buffer, 0x00, (UINTN) Size1);
Bsf1EndBuffer = (UINT8 *) Bsf1Buffer + Size1;
Bsf1LastStartAddress = Fv1EndAddress | IPF_CACHE_BIT;
if (SecondBSF) {
Fv2BaseAddress = StartAddress2;
Fv2EndAddress = Fv2BaseAddress + Size2;
memset (OutFileName2, 0, FILE_NAME_SIZE);
sprintf (
OutFileName2,
"%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x-%s",
Bsf2NameGuid.Data1,
Bsf2NameGuid.Data2,
Bsf2NameGuid.Data3,
Bsf2NameGuid.Data4[0],
Bsf2NameGuid.Data4[1],
Bsf2NameGuid.Data4[2],
Bsf2NameGuid.Data4[3],
Bsf2NameGuid.Data4[4],
Bsf2NameGuid.Data4[5],
Bsf2NameGuid.Data4[6],
Bsf2NameGuid.Data4[7],
BSF_OUTPUT_FILE
);
//
// The image buffer for the second BSF
//
Bsf2Buffer = malloc ((UINTN) Size2);
if (Bsf2Buffer == NULL) {
printf ("\nERROR: Not enough resource to create memory mapped file for Boot Strap File");
return EFI_OUT_OF_RESOURCES;
}
memset (Bsf2Buffer, 0x00, (UINTN) Size2);
Bsf2EndBuffer = (UINT8 *) Bsf2Buffer + Size2;
Bsf2LastStartAddress = Fv2EndAddress | IPF_CACHE_BIT;
}
Status = GetBsfRelatedInfoFromInfFile (BSF_INPUT_FILE);
if (Status != EFI_SUCCESS) {
printf ("\nERROR: Error in parsing input file");
CleanUpMemory ();
return Status;
}
Status = ProcessAndCreateBsf (Size1);
if (Status != EFI_SUCCESS) {
CleanUpMemory ();
return Status;
}
Status = UpdateIA32ResetVector (IA32BinFile, Bsf1TotalSize);
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
//
Bsf1TotalSize += sizeof (EFI_FFS_FILE_HEADER);
Bsf1LastStartAddress -= sizeof (EFI_FFS_FILE_HEADER);
Status = UpdateFfsHeader (Bsf1TotalSize, FIRST_VTF);
if (Status != EFI_SUCCESS) {
CleanUpMemory ();
return Status;
}
//
// Update the BSF buffer into specified BSF binary file
//
Status = WriteBsfBinary (OutFileName1, Bsf1TotalSize, FIRST_VTF);
if (SecondBSF) {
Bsf2TotalSize += sizeof (EFI_FFS_FILE_HEADER);
Bsf2LastStartAddress -= sizeof (EFI_FFS_FILE_HEADER);
Status = UpdateFfsHeader (Bsf2TotalSize, SECOND_VTF);
if (Status != EFI_SUCCESS) {
CleanUpMemory ();
return Status;
}
//
// Update the BSF buffer into specified BSF binary file
//
Status = WriteBsfBinary (OutFileName2, Bsf2TotalSize, SECOND_VTF);
}
CleanUpMemory ();
printf ("\n");
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;
UINTN NumByte;
CHAR8 OutFileName1[FILE_NAME_SIZE];
StartAddressPtr = malloc (sizeof (UINT64));
if (StartAddressPtr == NULL) {
return EFI_OUT_OF_RESOURCES;
}
*StartAddressPtr = StartAddress;
memset (OutFileName1, 0, FILE_NAME_SIZE);
sprintf (
OutFileName1,
"%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x-%s",
Bsf1NameGuid.Data1,
Bsf1NameGuid.Data2,
Bsf1NameGuid.Data3,
Bsf1NameGuid.Data4[0],
Bsf1NameGuid.Data4[1],
Bsf1NameGuid.Data4[2],
Bsf1NameGuid.Data4[3],
Bsf1NameGuid.Data4[4],
Bsf1NameGuid.Data4[5],
Bsf1NameGuid.Data4[6],
Bsf1NameGuid.Data4[7],
BSF_OUTPUT_FILE
);
Fp = fopen (OutFileName1, "r+b");
if (Fp == NULL) {
printf ("\nERROR: Error opening file ");
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);
NumByte = fwrite ((VOID *) StartAddressPtr, sizeof (UINT64), 1, Fp);
if (Fp) {
fclose (Fp);
}
if (StartAddressPtr) {
free (StartAddressPtr);
}
printf ("\n");
Status = EFI_SUCCESS;
return Status;
}
EFI_STATUS
UpdateSymFile (
IN UINT64 BaseAddress,
IN CHAR8 *DestFileName,
IN CHAR8 *SourceFileName
)
/*++
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.
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_PATH];
CHAR8 Type[_MAX_PATH];
CHAR8 Address[_MAX_PATH];
CHAR8 Section[_MAX_PATH];
CHAR8 Token[_MAX_PATH];
CHAR8 BaseToken[_MAX_PATH];
UINT64 TokenAddress;
long StartLocation;
//
// Verify input parameters.
//
if (BaseAddress == 0 || DestFileName == NULL || SourceFileName == NULL) {
return EFI_INVALID_PARAMETER;
}
//
// Open the source file
//
SourceFile = fopen (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 (DestFileName, "a+");
if (DestFile == NULL) {
fclose (SourceFile);
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);
return EFI_ABORTED;
}
StartLocation = ftell (DestFile);
if (StartLocation == 0) {
fprintf (DestFile, "TEXTSYM format | V1.0\n");
} else if (StartLocation == -1) {
fclose (SourceFile);
fclose (DestFile);
return EFI_ABORTED;
}
//
// Read the first line
//
if (fgets (Buffer, _MAX_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);
return EFI_ABORTED;
}
//
// Read in the file
//
while (feof (SourceFile) == 0) {
//
// Read a line
//
if (fscanf (SourceFile, "%s | %s | %s | %s\n", Type, Address, Section, Token) == 4) {
//
// Get the token address
//
AsciiStringToUint64 (Address, TRUE, &TokenAddress);
//
// 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 | %016I64X | %s | %s%s\n", Type, TokenAddress, Section, BaseToken, Token);
}
}
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
//
GetRelativeAddressInBsfBuffer (FitTableAddOffset, &RelativeAddress, FIRST_VTF);
FitTableAdd = *(UINTN *) RelativeAddress;
GetRelativeAddressInBsfBuffer (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
--*/
{
printf (
"%s, EFI 2.0 BootStrap File Generation Utility. Version %i.%i.\n",
UTILITY_NAME,
UTILITY_MAJOR_VERSION,
UTILITY_MINOR_VERSION
);
}
VOID
Usage (
VOID
)
/*++
Routine Description:
Displays the utility usage syntax to STDOUT
Arguments:
None
Returns:
None
--*/
{
Version();
printf (
"\nUsage: %s -B BaseAddress -S FwVolumeSize\n",
UTILITY_NAME
);
printf (" Where:\n");
printf (" BaseAddress is the starting address of Firmware Volume where Boot\n");
printf (" Strapped Image will reside.\n");
printf (" FwVolumeSize is the size of Firmware Volume.\n");
}
EFI_STATUS
main (
IN UINTN argc,
IN CHAR8 **argv
)
/*++
Routine Description:
This utility uses GenBsfImage.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 FirstRoundB;
BOOLEAN FirstRoundS;
EFI_STATUS Status;
BOOLEAN IsIA32;
//
// Verify the correct number of IA32 arguments
//
IsIA32 = FALSE;
if (argc == IA32_ARGS) {
//
// Now this tool is not used for IA32 platform, if it will be used in future,
// the IA32-specific functions need to be updated and verified, the updating can
// refer to IPF relevant functions)
//
printf ("ERROR: Now this tool does not support the IA32 platform!\n");
printf ("ERROR: And the IA32-specific functions need to be updated and verified!\n");
return 5;
/*
StartAddress1 = 0;
IsIA32 = TRUE;
//
// Parse the command line arguments
//
for (Index = 1; Index < IA32_ARGS; Index += 2) {
//
// Make sure argument pair begin with - or /
//
if (argv[Index][0] != '-' && argv[Index][0] != '/') {
Usage ();
printf ("ERROR: Argument pair must begin with \"-\" or \"/\"\n");
return 1;
}
//
// Make sure argument specifier is only one letter
//
if (argv[Index][2] != 0) {
Usage ();
printf ("ERROR: Unrecognized argument \"%s\".\n", argv[Index]);
return 1;
}
//
// Determine argument to read
//
switch (argv[Index][1]) {
case 't':
case 'T':
Status = AsciiStringToUint64 (argv[Index + 1], FALSE, &StartAddress1);
if (Status != EFI_SUCCESS) {
printf ("\nERROR: Bad start of address \"%s\"\n", argv[Index + 1]);
return 1;
}
break;
default:
Usage ();
printf ("Unrecognized IA32 argument \"%s\".\n", argv[Index]);
IsIA32 = FALSE;
break;
}
}
if (IsIA32) {
//
// Call the GenBsfImage
//
Status = Generate32BsfImage (StartAddress1);
if (EFI_ERROR(Status)) {
switch (Status) {
case EFI_INVALID_PARAMETER:
printf ("\nERROR: Invalid parameter passed to GenBsfImage function .\n");
break;
case EFI_ABORTED:
printf ("\nERROR: Error detected while creating the file image.\n");
break;
case EFI_OUT_OF_RESOURCES:
printf ("\nERROR: GenBsfImage function could not allocate required resources.\n");
break;
case EFI_VOLUME_CORRUPTED:
printf ("\nERROR: No base address was specified \n");
break;
default:
printf ("\nERROR: GenBsfImage function returned unknown status %X.\n", Status);
break;
}
return 2;
}
return 0;
}
*/
}
//
// Verify the correct number of arguments
//
if (argc == 1) {
Usage();
return 1;
}
if ((strcmp(argv[1], "-h") == 0) || (strcmp(argv[1], "--help") == 0) ||
(strcmp(argv[1], "-?") == 0) || (strcmp(argv[1], "/?") == 0)) {
Usage();
return 1;
}
if ((strcmp(argv[1], "-V") == 0) || (strcmp(argv[1], "--version") == 0)) {
Version();
return 1;
}
if (argc != ONE_BSF_ARGS && argc != TWO_BSF_ARGS) {
Usage ();
return 1;
}
//
// Initialize variables
//
StartAddress1 = 0;
StartAddress2 = 0;
FwVolSize1 = 0;
FwVolSize2 = 0;
FirstRoundB = TRUE;
FirstRoundS = TRUE;
//
// Parse the command line arguments
//
for (Index = 1; Index < argc; Index += 2) {
//
// Make sure argument pair begin with - or /
//
if (argv[Index][0] != '-' && argv[Index][0] != '/') {
Usage ();
printf ("ERROR: Argument pair must begin with \"-\" or \"/\"\n");
return 1;
}
//
// Make sure argument specifier is only one letter
//
if (argv[Index][2] != 0) {
Usage ();
printf ("ERROR: Unrecognized argument \"%s\".\n", argv[Index]);
return 1;
}
//
// Determine argument to read
//
switch (argv[Index][1]) {
case 'B':
case 'b':
if (FirstRoundB) {
Status = AsciiStringToUint64 (argv[Index + 1], FALSE, &StartAddress1);
FirstRoundB = FALSE;
} else {
Status = AsciiStringToUint64 (argv[Index + 1], FALSE, &StartAddress2);
}
if (Status != EFI_SUCCESS) {
printf ("\nERROR: Bad start of address \"%s\"\n", argv[Index + 1]);
return 1;
}
break;
case 'S':
case 's':
if (FirstRoundS) {
Status = AsciiStringToUint64 (argv[Index + 1], FALSE, &FwVolSize1);
FirstRoundS = FALSE;
} else {
Status = AsciiStringToUint64 (argv[Index + 1], FALSE, &FwVolSize2);
}
if (Status != EFI_SUCCESS) {
printf ("\nERROR: Bad size \"%s\"\n", argv[Index + 1]);
return 1;
}
break;
default:
Usage ();
printf ("ERROR: Unrecognized argument \"%s\".\n", argv[Index]);
return 1;
break;
}
}
//
// Call the GenBsfImage
//
Status = GenerateBsfImage (StartAddress1, FwVolSize1, StartAddress2, FwVolSize2);
if (EFI_ERROR (Status)) {
switch (Status) {
case EFI_INVALID_PARAMETER:
printf ("\nERROR: Invalid parameter passed to GenBsfImage function .\n");
break;
case EFI_ABORTED:
printf ("\nERROR: Error detected while creating the file image.\n");
break;
case EFI_OUT_OF_RESOURCES:
printf ("\nERROR: GenBsfImage function could not allocate required resources.\n");
break;
case EFI_VOLUME_CORRUPTED:
printf ("\nERROR: No base address was specified \n");
break;
default:
printf ("\nERROR: GenBsfImage function returned unknown status %X.\n", Status);
break;
}
return 2;
}
return 0;
}
EFI_STATUS
Generate32BsfImage (
IN UINT64 BootFileStartAddress
)
/*++
Routine Description:
This is the main IA32 function which will be called from application.
(Now this tool is not used for IA32 platform, if it will be used in future,
the relative functions need to be updated, the updating can refer to IPF
functions)
Arguments:
BootFileStartAddress - Top Address of Boot File
Returns:
The return value can be any of the values
returned by the calls to following functions:
Get32BsfRelatedInfoFromInfFile
CreateBsfBuffer
ProcessAndCreate32Bsf
Update32FfsHeader
WriteBsfBinary
--*/
{
EFI_STATUS Status;
UINT32 BsfSize;
CHAR8 OutFileName[FILE_NAME_SIZE];
EFI_GUID BsfNameGuid = EFI_IA32_BOOT_STRAP_GUID;
Status = EFI_UNSUPPORTED;
memset (OutFileName, 0, FILE_NAME_SIZE);
sprintf (
OutFileName, "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x-%s",
BsfNameGuid.Data1,
BsfNameGuid.Data2,
BsfNameGuid.Data3,
BsfNameGuid.Data4[0],
BsfNameGuid.Data4[1],
BsfNameGuid.Data4[2],
BsfNameGuid.Data4[3],
BsfNameGuid.Data4[4],
BsfNameGuid.Data4[5],
BsfNameGuid.Data4[6],
BsfNameGuid.Data4[7],
BSF_OUTPUT_FILE
);
Status = Get32BsfRelatedInfoFromInfFile (BSF_INPUT_FILE);
if (Status != EFI_SUCCESS) {
printf ("\nERROR: Error in parsing input file");
CleanUpMemory ();
return Status;
}
if (GetTotal32BsfSize (&BsfSize) == EFI_SUCCESS) {
Bsf1Buffer = malloc ((UINTN) BsfSize);
if (Bsf1Buffer == NULL) {
printf ("\nERROR: Not enough resource to create memory mapped file for Boot Strap File");
CleanUpMemory ();
return EFI_OUT_OF_RESOURCES;
}
memset (Bsf1Buffer, 0x00, (UINTN) BsfSize);
} else {
printf ("\nERROR: Could not get BSF size.");
CleanUpMemory ();
return EFI_ABORTED;
}
//
//VTF must align properly
//
Bsf1LastStartAddress = BootFileStartAddress - BsfSize;
Bsf1LastStartAddress = Bsf1LastStartAddress & -8;
BsfSize = (UINT32)BootFileStartAddress - (UINT32)Bsf1LastStartAddress;
Bsf1LastStartAddress = BsfSize;
BufferToTop = (UINT32)BootFileStartAddress - BsfSize;
Status = ProcessAndCreate32Bsf (BsfSize);
if (Status != EFI_SUCCESS) {
CleanUpMemory();
return Status;
}
//
// Write the FFS header
//
Status = Update32FfsHeader (BsfSize);
if (Status != EFI_SUCCESS) {
CleanUpMemory();
return Status;
}
//
// Calculate the Start address of this BSF
//
Bsf1Buffer = (UINT8 *)Bsf1Buffer + Bsf1LastStartAddress;
//
// Update the BSF buffer into specified BSF binary file
//
Status = WriteBsfBinary (OutFileName, BsfSize - (UINT32)Bsf1LastStartAddress, FIRST_VTF);
if (Status != EFI_SUCCESS) {
CleanUpMemory();
return Status;
}
Status = Write32SoftFit (IA32_SOFT_FIT, FileListHeadPtr);
if (Status != EFI_SUCCESS) {
CleanUpMemory();
return Status;
}
CleanUpMemory ();
printf ("\n");
return Status;
}
EFI_STATUS
GetTotal32BsfSize(
IN UINT32 *BsfSize
)
/*++
Routine Description:
This function calculates total size for IA32 BSF which would be needed to create
the buffer. This will be done using Passed Info link list and looking for the
size of the components which belong to BSF. The addtional file header is accounted.
Arguments:
BSFSize - Pointer to the size of IA32 BSF
Returns:
EFI_ABORTED - Returned due to one of the following resons:
(a) Error Opening File
EFI_SUCCESS - The fuction completes successfully
--*/
{
PARSED_BSF_INFO *BsfInfo;
FILE *Fp;
UINT32 Alignment;
*BsfSize = 0;
Alignment = 0;
BsfInfo = FileListHeadPtr;
while (BsfInfo != NULL) {
if (BsfInfo->LocationType != SECOND_VTF) {
if ( BsfInfo->Align ) {
//
// Create additional align to compensate for component boundary requirements
//
Alignment = 1 << BsfInfo->Align;
*BsfSize += Alignment;
}
if (BsfInfo->PreferredSize) {
*BsfSize += BsfInfo->CompSize;
} else {
Fp = fopen (BsfInfo->CompBinName,"r+b");
if (Fp == NULL) {
printf ("\nERROR: Error in opening file %s", BsfInfo->CompBinName);
return EFI_ABORTED;
}
*BsfSize += _filelength (fileno (Fp));
if (Fp) {
fclose (Fp);
}
}
}
BsfInfo = BsfInfo->NextBsfInfo;
}
//
// Add file header space
//
*BsfSize += sizeof (EFI_FFS_FILE_HEADER);
//
// Create additional to IA32 Seccore section header
//
*BsfSize += sizeof (EFI_COMMON_SECTION_HEADER);
return EFI_SUCCESS;
}
EFI_STATUS
ProcessAndCreate32Bsf (
IN UINT64 Size
)
/*++
Routine Description:
This function process the link list created during INF file parsing
and create component in IA32 BSF
Arguments:
Size - Size of the Firmware Volume of which, this BSF belongs to.
Returns:
EFI_UNSUPPORTED - Unknown component type
EFI_SUCCESS - The function completed successfully
--*/
{
EFI_STATUS Status;
PARSED_BSF_INFO *ParsedInfoPtr;
Status = EFI_SUCCESS;
ParsedInfoPtr = FileListHeadPtr;
while (ParsedInfoPtr != NULL) {
switch (ParsedInfoPtr->CompType) {
case COMP_TYPE_SECCORE:
Status = CreateAndUpdateSeccore (ParsedInfoPtr);
break;
default:
//
// Any other component type should be handled here. This will create the
// image in specified BSF
//
Status = CreateAndUpdate32Component (ParsedInfoPtr);
if (EFI_ERROR(Status)) {
printf ("ERROR: Updating %s component.\n", ParsedInfoPtr->CompName);
}
break;
}
ParsedInfoPtr = ParsedInfoPtr->NextBsfInfo;
}
return Status;
}
EFI_STATUS
CreateAndUpdateSeccore (
IN PARSED_BSF_INFO *BsfInfo
)
/*++
Routine Description:
This function reads the binary file for seccore and update them
in IA32 BSF Buffer
Arguments:
BsfInfo - 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.
--*/
{
UINT8 *SecbinStartAddress;
UINT8 *SecfileStartAddress;
UINT32 FileSize;
UINT64 NumByteRead;
UINT8 *Buffer;
FILE *Fp;
UINT64 TotalLength;
EFI_COMMON_SECTION_HEADER *SecHeader;
Fp = fopen (BsfInfo->CompBinName, "r+b");
if (Fp == NULL) {
printf ("\nERROR: Opening file %s", BsfInfo->CompBinName);
return EFI_ABORTED;
}
FileSize = _filelength (fileno (Fp));
if (BsfInfo->PreferredSize) {
if (FileSize > BsfInfo->CompSize) {
printf("\nERROR: The Seccore Size is more than specified size");
return EFI_ABORTED;
}
FileSize = BsfInfo->CompSize;
}
BsfInfo->CompSize = FileSize;
Buffer = malloc ((UINTN) FileSize);
if (Buffer == NULL) {
return EFI_OUT_OF_RESOURCES;
}
memset (Buffer, 0, (UINTN) FileSize);
//
// Read seccore in a buffer
//
NumByteRead = fread (Buffer, sizeof (UINT8), (UINTN) FileSize, Fp);
fclose (Fp);
SecfileStartAddress = (UINT8 *) Bsf1Buffer + Bsf1LastStartAddress - FileSize - sizeof (EFI_COMMON_SECTION_HEADER);
if (SecfileStartAddress == NULL) {
return EFI_INVALID_PARAMETER;
}
SecbinStartAddress = SecfileStartAddress + sizeof (EFI_COMMON_SECTION_HEADER);
BsfInfo->CompPreferredAddress = Bsf1LastStartAddress - FileSize + BufferToTop;
//
// write section header
//
memset (SecfileStartAddress, 0, sizeof (EFI_COMMON_SECTION_HEADER));
SecHeader = (EFI_COMMON_SECTION_HEADER *) SecfileStartAddress;
SecHeader->Type = EFI_SECTION_RAW;
TotalLength = sizeof (EFI_COMMON_SECTION_HEADER) + (UINT64) FileSize;
memcpy (SecHeader->Size, &TotalLength, 3);
//
// write seccore
//
memcpy (SecbinStartAddress, Buffer, (UINTN) FileSize);
if (Buffer) {
free (Buffer);
}
Bsf1LastStartAddress = SecfileStartAddress - (UINT8 *) Bsf1Buffer;
return EFI_SUCCESS;
}
EFI_STATUS
CreateAndUpdate32Component (
IN PARSED_BSF_INFO *BsfInfo
)
/*++
Routine Description:
This function reads the binary file for each components. Add it at aligned address.
Arguments:
BsfInfo - 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.
EFI_INVALID_PARAMETER - Value returned from call to UpdateEntryPoint()
EFI_OUT_OF_RESOURCES - Memory allocation failed.
--*/
{
UINT64 CompStartAddress;
UINT32 FileSize;
UINT64 NumByteRead;
UINT8 *Buffer;
FILE *Fp;
UINT8 *LocalBufferPtrToWrite;
UINT64 Alignment;
Fp = fopen (BsfInfo->CompBinName, "r+b");
if (Fp == NULL) {
printf("\nERROR: Opening file %s", BsfInfo->CompBinName);
return EFI_ABORTED;
}
FileSize = _filelength (fileno (Fp));
if (BsfInfo->PreferredSize) {
if (FileSize > BsfInfo->CompSize) {
printf("\nERROR: The component size is more than specified size");
return EFI_ABORTED;
}
FileSize = BsfInfo->CompSize;
}
BsfInfo->CompSize = FileSize;
Buffer = malloc ((UINTN) FileSize);
if (Buffer == NULL) {
return EFI_OUT_OF_RESOURCES;
}
memset (Buffer,0, (UINTN) FileSize);
NumByteRead = fread (Buffer, sizeof (UINT8), (UINTN) FileSize, Fp);
fclose (Fp);
CompStartAddress = Bsf1LastStartAddress - FileSize + BufferToTop;
if (BsfInfo->Align) {
//
// Create additional align to compensate for component boundary requirements
//
Alignment = 0 - (1 << BsfInfo->Align);
CompStartAddress = CompStartAddress & Alignment;
}
BsfInfo->CompPreferredAddress = CompStartAddress;
//
// write bin
//
LocalBufferPtrToWrite = (UINT8 *) Bsf1Buffer;
Bsf1LastStartAddress = CompStartAddress - BufferToTop;
LocalBufferPtrToWrite += Bsf1LastStartAddress;
memcpy (LocalBufferPtrToWrite, Buffer, (UINTN) FileSize);
Bsf1LastStartAddress = CompStartAddress - BufferToTop;
//
// Free the buffer
//
if (Buffer) {
free (Buffer);
}
return EFI_SUCCESS;
}
EFI_STATUS
Update32FfsHeader(
IN UINT32 BsfSize
)
/*++
Routine Description:
Update the Firmware Volume Buffer with requested buffer data
Arguments:
BsfSize - Size of the IA32 BSF
Returns:
EFI_SUCCESS - The function completed successfully
EFI_INVALID_PARAMETER - The Ffs File Header Pointer is NULL
--*/
{
EFI_FFS_FILE_HEADER *FileHeader;
UINT32 TotalBsfSize;
EFI_GUID EfiFirmwareVolumeTopFileGuid = EFI_FFS_VOLUME_TOP_FILE_GUID;
//
// Find the BSF file header location, the bsf file must be 8 bytes aligned
//
Bsf1LastStartAddress -= sizeof (EFI_FFS_FILE_HEADER);
Bsf1LastStartAddress += BufferToTop;
Bsf1LastStartAddress = Bsf1LastStartAddress & -8;
Bsf1LastStartAddress -= BufferToTop;
FileHeader = (EFI_FFS_FILE_HEADER*)((UINT8*)Bsf1Buffer + Bsf1LastStartAddress);
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_FREEFORM;
FileHeader->Attributes = FFS_ATTRIB_CHECKSUM;
//
// Now FileSize includes the EFI_FFS_FILE_HEADER
//
TotalBsfSize = BsfSize - (UINT32)Bsf1LastStartAddress;
FileHeader->Size[0] = (UINT8) (TotalBsfSize & 0x000000FF);
FileHeader->Size[1] = (UINT8) ((TotalBsfSize & 0x0000FF00) >> 8);
FileHeader->Size[2] = (UINT8) ((TotalBsfSize & 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, TotalBsfSize);
FileHeader->State = EFI_FILE_HEADER_CONSTRUCTION | EFI_FILE_HEADER_VALID | EFI_FILE_DATA_VALID;
return EFI_SUCCESS;
}
EFI_STATUS
Get32BsfRelatedInfoFromInfFile (
IN CHAR8 *FileName
)
/*++
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 IA32 BSF
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 informations
EFI_OUT_OF_RESOURCES Malloc Failed
EFI_SUCCESS The function completed successfully
--*/
{
FILE *Fp;
UINTN Index;
EFI_STATUS Status;
Fp = fopen (FileName, "r");
if (Fp == NULL) {
printf ("\nERROR: Error in opening %s file\n", FileName);
return EFI_ABORTED;
}
ValidLineCount (Fp);
if (ValidLineNum == 0) {
printf ("\nERROR: File doesn't contain any valid informations");
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) {
free (OrgStrTokPtr);
return EFI_OUT_OF_RESOURCES;
}
memset (*TokenStr, 0, FILE_NAME_SIZE);
// free (*TokenStr);
TokenStr++;
}
TokenStr = NULL;
TokenStr = OrgStrTokPtr;
fseek (Fp, 0L, SEEK_SET);
Status = InitializeComps();
if (Status != EFI_SUCCESS) {
free (TokenStr);
return Status;
}
ParseInputFile (Fp);
Initialize32InFileInfo ();
if (Fp) {
fclose (Fp);
}
free (TokenStr);
return EFI_SUCCESS;
}
VOID
Initialize32InFileInfo (
VOID
)
/*++
Routine Description:
This function intializes the relevant global variable which is being
used to store the information retrieved from IA32 INF file.
Arguments:
NONE
Returns:
NONE
--*/
{
UINTN SectionOptionFlag;
UINTN SectionCompFlag;
SectionOptionFlag =0 ;
SectionCompFlag = 0;
TokenStr = OrgStrTokPtr;
while (*TokenStr != NULL) {
if (_stricmp (*TokenStr, "[OPTIONS]") == 0) {
SectionOptionFlag = 1;
SectionCompFlag = 0;
}
if (_stricmp (*TokenStr, "[COMPONENTS]") == 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++;
ParseAndUpdate32Components (FileListPtr);
}
if (*TokenStr != NULL) {
FileListPtr->NextBsfInfo = malloc (sizeof (PARSED_BSF_INFO));
if (FileListPtr->NextBsfInfo == NULL) {
printf ("Error: Out of memory resources.\n");
break;
}
FileListPtr = FileListPtr->NextBsfInfo;
memset (FileListPtr, 0, sizeof(PARSED_BSF_INFO));
FileListPtr->NextBsfInfo = NULL;
continue;
} else {
break;
}
}
TokenStr++;
}
}
VOID
ParseAndUpdate32Components (
IN PARSED_BSF_INFO *BsfInfo
)
/*++
Routine Description:
This function intializes the relevant global variable which is being
used to store the information retrieved from INF file.
Arguments:
BsfInfo - A pointer to the BSF Info Structure
Returns:
None
--*/
{
UINT64 StringValue;
UINT64 AlignStringValue;
while (*TokenStr != NULL && (_stricmp (*TokenStr, "COMP_NAME") != 0)) {
if (_stricmp (*TokenStr, "COMP_LOC") == 0) {
TokenStr++;
if (_stricmp (*TokenStr, "B") == 0) {
BsfInfo->LocationType = FIRST_VTF;
} else if (_stricmp (*TokenStr, "N") == 0) {
BsfInfo->LocationType = SECOND_VTF;
} else {
BsfInfo->LocationType = NONE;
printf ("\nERROR: Unknown location for component %s", BsfInfo->CompName);
}
} else if (_stricmp (*TokenStr, "COMP_TYPE") == 0) {
TokenStr++;
if (AsciiStringToUint64 (*TokenStr, FALSE, &StringValue) != EFI_SUCCESS) {
printf ("\nERROR: Could not read a numeric value from \"%s\".", TokenStr);
return;
}
BsfInfo->CompType = (UINT8) StringValue;
} else if (_stricmp (*TokenStr, "COMP_VER") == 0) {
TokenStr++;
if (_stricmp (*TokenStr, "-") == 0) {
BsfInfo->VersionPresent = FALSE;
BsfInfo->MajorVer = 0;
BsfInfo->MinorVer = 0;
} else {
BsfInfo->VersionPresent = TRUE;
ConvertVersionInfo (*TokenStr, &BsfInfo->MajorVer, &BsfInfo->MinorVer);
}
} else if (_stricmp (*TokenStr, "COMP_BIN") == 0) {
TokenStr++;
strcpy (BsfInfo->CompBinName, *TokenStr);
} else if (_stricmp (*TokenStr, "COMP_SYM") == 0) {
TokenStr++;
strcpy (BsfInfo->CompSymName, *TokenStr);
} else if (_stricmp (*TokenStr, "COMP_SIZE") == 0) {
TokenStr++;
if (_stricmp (*TokenStr, "-") == 0) {
BsfInfo->PreferredSize = FALSE;
BsfInfo->CompSize = 0;
} else {
BsfInfo->PreferredSize = TRUE;
if (AsciiStringToUint64 (*TokenStr, FALSE, &StringValue) != EFI_SUCCESS) {
printf ("\nERROR: Could not read a numeric value from \"%s\".", TokenStr);
return;
}
BsfInfo->CompSize = (UINTN) StringValue;
}
} else if (_stricmp (*TokenStr, "COMP_CS") == 0) {
TokenStr++;
if (_stricmp (*TokenStr, "1") == 0) {
BsfInfo->CheckSumRequired = 1;
} else if (_stricmp (*TokenStr, "0") == 0) {
BsfInfo->CheckSumRequired = 0;
} else {
printf ("\nERROR: Bad information in INF file about Checksum required field");
}
} else if (_stricmp (*TokenStr, "COMP_ALIGN") == 0) {
TokenStr++;
if (AsciiStringToUint64 (*TokenStr, FALSE, &AlignStringValue) != EFI_SUCCESS) {
printf ("\nERROR: Could not read a numeric value from \"%s\".", TokenStr);
return;
}
if (AlignStringValue >= 0) {
BsfInfo->Align = (UINT32) AlignStringValue;
} else {
printf ("\nERROR: invalid align \"%s\".", AlignStringValue);
return;
}
}
TokenStr++;
if (*TokenStr == NULL) {
break;
}
}
}
EFI_STATUS
Write32SoftFit(
IN CHAR8 *FileName,
IN PARSED_BSF_INFO *BsfInfo
)
/*++
Routine Description:
Write IA32 Firmware Volume component address from memory to a file.
Arguments:
FileName Output File Name which needed to be created/
BsfInfo Parsed info link
Returns:
EFI_ABORTED - Returned due to one of the following resons:
(a) Error Opening File
(b) Failing to copy buffers
EFI_SUCCESS - The function completes successfully
--*/
{
FILE *Fp;
Fp = fopen (FileName, "w+t");
if (Fp == NULL) {
printf ("Error in opening file %s\n", FileName);
return EFI_ABORTED;
}
while (BsfInfo != NULL) {
if (strlen (BsfInfo->CompName) != 0) {
fprintf (Fp, "\n%s\n", BsfInfo->CompName);
} else {
fprintf (Fp, "\n%s\n", "Name not available");
}
fprintf (Fp, "%d\n", BsfInfo->CompPreferredAddress);
fprintf (Fp, "%d\n", BsfInfo->CompSize);
fprintf (Fp, "%d\n", BsfInfo->Align);
BsfInfo = BsfInfo->NextBsfInfo;
}
if (Fp) {
fclose (Fp);
}
return EFI_SUCCESS;
}