/*++

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;
}
