/*++ 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 #include #include "GenBsfImage.h" #include #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; }