From 080981d72dcbb782ad73716c439639324b0aa4dd Mon Sep 17 00:00:00 2001 From: Shenglei Zhang Date: Tue, 28 May 2019 11:01:47 +0800 Subject: [PATCH] BaseTools/FMMT: Add a tool FMMT FMMT is a tool to enable removal, addition and replacement of FFS files in FD image binaries. https://bugzilla.tianocore.org/show_bug.cgi?id=1847 Cc: Bob Feng Cc: Liming Gao Signed-off-by: Shenglei Zhang Reviewed-by: Bob Feng --- BaseTools/BinWrappers/PosixLike/FMMT | 29 + .../Source/C/FMMT/FirmwareModuleManagement.c | 2559 +++++++++ .../Source/C/FMMT/FirmwareModuleManagement.h | 479 ++ BaseTools/Source/C/FMMT/FmmtConf.ini | 6 + BaseTools/Source/C/FMMT/FmmtLib.c | 5051 +++++++++++++++++ BaseTools/Source/C/FMMT/GNUmakefile | 16 + BaseTools/Source/C/FMMT/Makefile | 17 + BaseTools/Source/C/FMMT/Rebase.c | 846 +++ BaseTools/Source/C/FMMT/Rebase.h | 31 + BaseTools/Source/C/GNUmakefile | 1 + BaseTools/Source/C/Makefile | 1 + 11 files changed, 9036 insertions(+) create mode 100755 BaseTools/BinWrappers/PosixLike/FMMT create mode 100644 BaseTools/Source/C/FMMT/FirmwareModuleManagement.c create mode 100644 BaseTools/Source/C/FMMT/FirmwareModuleManagement.h create mode 100644 BaseTools/Source/C/FMMT/FmmtConf.ini create mode 100644 BaseTools/Source/C/FMMT/FmmtLib.c create mode 100644 BaseTools/Source/C/FMMT/GNUmakefile create mode 100644 BaseTools/Source/C/FMMT/Makefile create mode 100644 BaseTools/Source/C/FMMT/Rebase.c create mode 100644 BaseTools/Source/C/FMMT/Rebase.h diff --git a/BaseTools/BinWrappers/PosixLike/FMMT b/BaseTools/BinWrappers/PosixLike/FMMT new file mode 100755 index 0000000000..a244ecc095 --- /dev/null +++ b/BaseTools/BinWrappers/PosixLike/FMMT @@ -0,0 +1,29 @@ +#!/usr/bin/env bash + +full_cmd=${BASH_SOURCE:-$0} # see http://mywiki.wooledge.org/BashFAQ/028 for a discussion of why $0 is not a good choice here +dir=$(dirname "$full_cmd") +cmd=${full_cmd##*/} + +if [ -n "$WORKSPACE" ] && [ -e "$WORKSPACE/Conf/BaseToolsCBinaries" ] +then + exec "$WORKSPACE/Conf/BaseToolsCBinaries/$cmd" +elif [ -n "$WORKSPACE" ] && [ -e "$EDK_TOOLS_PATH/Source/C" ] +then + if [ ! -e "$EDK_TOOLS_PATH/Source/C/bin/$cmd" ] + then + echo "BaseTools C Tool binary was not found ($cmd)" + echo "You may need to run:" + echo " make -C $EDK_TOOLS_PATH/Source/C" + else + exec "$EDK_TOOLS_PATH/Source/C/bin/$cmd" "$@" + fi +elif [ -e "$dir/../../Source/C/bin/$cmd" ] +then + exec "$dir/../../Source/C/bin/$cmd" "$@" +else + echo "Unable to find the real '$cmd' to run" + echo "This message was printed by" + echo " $0" + exit 127 +fi + diff --git a/BaseTools/Source/C/FMMT/FirmwareModuleManagement.c b/BaseTools/Source/C/FMMT/FirmwareModuleManagement.c new file mode 100644 index 0000000000..63ae3c45a4 --- /dev/null +++ b/BaseTools/Source/C/FMMT/FirmwareModuleManagement.c @@ -0,0 +1,2559 @@ +/** @file + + FMMT main routine. + +Copyright (c) 2019, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "FirmwareModuleManagement.h" +#include "Rebase.h" +#include +#include + +CHAR8* mGuidToolDefinition = "FmmtConf.ini"; +extern EFI_FIRMWARE_VOLUME_HEADER *mFvHeader; +extern UINT32 mFvLength; + +// +// Store GUIDed Section guid->tool mapping +// +EFI_HANDLE mParsedGuidedSectionTools = NULL; +#define EFI_FFS_VOLUME_TOP_FILE_GUID \ +{ \ + 0x1BA0062E, 0xC779, 0x4582, { 0x85, 0x66, 0x33, 0x6A, 0xE8, 0xF7, 0x8F, 0x09 } \ +} +#define FSP_FFS_INFORMATION_FILE_GUID \ +{ 0x912740be, 0x2284, 0x4734, { 0xb9, 0x71, 0x84, 0xb0, 0x27, 0x35, 0x3f, 0x0c }}; + +static EFI_GUID mVTFGuid = EFI_FFS_VOLUME_TOP_FILE_GUID; +static EFI_GUID mFSPGuid = FSP_FFS_INFORMATION_FILE_GUID; + + +/** + +Routine Description: + + The Usage of FMMT tool. + +Arguments: + + None + +Returns: + + None + +**/ +VOID +Usage ( + VOID + ) +{ + // + // Summary usage + // + fprintf (stdout, "Usage: %s [options] \n\n", UTILITY_SHORT_NAME); + + // + // Copyright declaration + // + fprintf (stdout, "Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.\n\n"); + + // + // Details Option + // + fprintf (stdout, "Options:\n"); + + // + // Command Line for View + // + fprintf (stdout, " -v \n\ + View each FV and the named files within each FV.\n"); + + // + // Command Line for Delete entire FV + // + fprintf (stdout, " -d \n\ + Delete the entire FV in an FD binary\n"); + + // + // Command Line for Delete file from FV + // + fprintf (stdout, " -d [ ...] \n\ + Delete a file (or files) from the firmware volume in an FD binary\n"); + + // + // Command Line for Add + // + fprintf (stdout, " -a [ ...] \n\ + Add a file (or files) to the firmware volume in an FD binary\n"); + + // + // Command Line for Replace + // + fprintf (stdout, " -r [ ...] \n\ + The replace command combines the functionality of remove and add into a single operation.\n"); + + fprintf (stdout, "\nNote:\n"); + fprintf (stdout, " is the sequence of the firmware volume included in the FD image, it both support the sequentially format like FV0, FV1 and the FV's file guid value format.\n"); + return; +} + + +BOOLEAN +IsVtf(EFI_FFS_FILE_HEADER2* ffs) { + if (!memcmp(&ffs->Name, &mVTFGuid, sizeof (EFI_GUID))) { + return TRUE; + } else { + return FALSE; + } +} + +BOOLEAN +IsFsp(EFI_FFS_FILE_HEADER2* ffs) { + if (!memcmp(&ffs->Name, &mFSPGuid, sizeof (EFI_GUID))) { + return TRUE; + } else { + return FALSE; + } +} + +static +EFI_STATUS +GetBaseAddrFromVtf(FIRMWARE_DEVICE *FdData, CHAR8 *FvId, UINT64 *BaseAddr) { + EFI_STATUS Status; + FV_INFORMATION *CurrentFv; + FV_INFORMATION *FvInFd; + + Status = LibLocateFvViaFvId(FdData, FvId, &FvInFd); + if (EFI_ERROR(Status)) { + return Status; + } + + // + // Get bottom FV + // + CurrentFv = FdData->Fv; + while (CurrentFv->FvNext) { + CurrentFv = CurrentFv->FvNext; + } + if (CurrentFv->FfsNumbers > 0 && IsVtf(&CurrentFv->FfsHeader[CurrentFv->FfsNumbers])) { + // + // Found VTF at the top of FV + // Assume 4G address + // + *BaseAddr = 0x100000000 - (FdData->Size - FvInFd->ImageAddress); + return EFI_SUCCESS; + } + return EFI_NOT_FOUND; +} + +static +EFI_STATUS +GetBaseAddrFromFsp(FIRMWARE_DEVICE *FdData, CONST UINT8* FdBuffer, CHAR8 *FvId, UINT64 *BaseAddr) +{ + EFI_STATUS Status; + FV_INFORMATION *FvInFd; + FV_INFORMATION *CurrentFv; + FV_INFORMATION *FspFv; + UINT32 Offset; + UINT64 ImageSize; + UINT64 Size; + EFI_FFS_FILE_HEADER2 *CurrentFile; + BOOLEAN FspFound; + + Status = LibLocateFvViaFvId(FdData, FvId, &FvInFd); + if (EFI_ERROR(Status)) { + return Status; + } + + ImageSize = 0; + Size = 0; + FspFound = FALSE; + FspFv = NULL; + CurrentFv = FdData->Fv; + while (CurrentFv) { + if (CurrentFv->FfsNumbers > 0 && IsFsp(&CurrentFv->FfsHeader[0])) { + Offset = CurrentFv->ImageAddress + CurrentFv->FfsAttuibutes[0].Offset; + CurrentFile = (EFI_FFS_FILE_HEADER2 *)(FdBuffer + Offset); + // + // Skip FFS header + // + Offset += GetFfsHeaderLength((EFI_FFS_FILE_HEADER *)CurrentFile); + // + // Stip section header + // + Offset += GetSectionHeaderLength((EFI_COMMON_SECTION_HEADER *)(FdBuffer + Offset)); + // + // We have raw FSP here, and 24 is the image size + // + ImageSize = *((UINT32 *)(FdBuffer + Offset + 24)); + // + // 28 is the base address + // + *BaseAddr = *((UINT32 *)(FdBuffer + Offset + 28)); + FspFound = TRUE; + FspFv = CurrentFv; + } + if (CurrentFv == FvInFd){ + break; + } + CurrentFv = CurrentFv->FvNext; + } + if (!FspFound) { + return EFI_NOT_FOUND; + } + // + // Check if FSP binary contains this FV + // + while (FspFv != NULL) { + Size += FspFv->FvHeader->FvLength; + if (FspFv == FvInFd) { + break; + } + FspFv = FspFv->FvNext; + } + if (Size <= ImageSize) { + return EFI_SUCCESS; + } + + return EFI_NOT_FOUND; +} + +static +VOID +AddPadFile(EFI_FIRMWARE_VOLUME_HEADER *Fv, EFI_FFS_FILE_HEADER2 *PadFile, UINT32 PadFileSize) { + UINT32 hdrSize; + + if (Fv->Attributes & EFI_FVB2_ERASE_POLARITY) { + memset(PadFile, -1, PadFileSize); + } + else { + memset(PadFile, 0, PadFileSize); + } + PadFile->Type = EFI_FV_FILETYPE_FFS_PAD; + PadFile->Attributes = 0; + + // + // Write pad file size (calculated size minus next file header size) + // + if (PadFileSize >= MAX_FFS_SIZE) { + memset(PadFile->Size, 0, sizeof(UINT8)* 3); + ((EFI_FFS_FILE_HEADER2 *)PadFile)->ExtendedSize = PadFileSize; + PadFile->Attributes |= FFS_ATTRIB_LARGE_FILE; + hdrSize = sizeof(EFI_FFS_FILE_HEADER2); + } + else { + PadFile->Size[0] = (UINT8)(PadFileSize & 0xFF); + PadFile->Size[1] = (UINT8)((PadFileSize >> 8) & 0xFF); + PadFile->Size[2] = (UINT8)((PadFileSize >> 16) & 0xFF); + hdrSize = sizeof(EFI_FFS_FILE_HEADER); + } + + // + // Fill in checksums and state, they must be 0 for checksumming. + // + PadFile->IntegrityCheck.Checksum.Header = 0; + PadFile->IntegrityCheck.Checksum.File = 0; + PadFile->State = 0; + PadFile->IntegrityCheck.Checksum.Header = CalculateChecksum8((UINT8 *)PadFile, hdrSize); + PadFile->IntegrityCheck.Checksum.File = FFS_FIXED_CHECKSUM; + + PadFile->State = EFI_FILE_HEADER_CONSTRUCTION | EFI_FILE_HEADER_VALID | EFI_FILE_DATA_VALID; + if (Fv->Attributes & EFI_FVB2_ERASE_POLARITY) { + PadFile->State = (UINT8)~(PadFile->State); + } +} + +static +UINT8* ReadFileToBuffer(CONST CHAR8 *FdName, UINT32 *FdSize) { + FILE* file; + + UINT8 *FdBuffer = NULL; + + file = fopen(FdName, "rb"); + if (file == NULL) + return NULL; + + fseek(file, 0, SEEK_SET); + fseek(file, 0, SEEK_END); + *FdSize = ftell(file); + fseek(file, 0, SEEK_SET); + + FdBuffer = malloc(*FdSize); + if (FdBuffer == NULL) { + goto FAIL; + } + if (fread(FdBuffer, 1, *FdSize, file) != *FdSize) { + goto FAIL; + } + fclose(file); + return FdBuffer; +FAIL: + free(FdBuffer); + fclose(file); + return NULL; +} + +static UINT32 CalcuFfsSize(EFI_FIRMWARE_VOLUME_HEADER* Fv, CONST EFI_FFS_FILE_HEADER2 *Ffs) { + EFI_FFS_FILE_HEADER2 *NextFile; + UINTN FfsSize; + UINTN FvSize; + UINTN Offset; + + FfsSize = GetFfsFileLength((EFI_FFS_FILE_HEADER *)Ffs); + FfsSize += (UINT8 *)ALIGN_POINTER(((UINT8 *)Ffs + FfsSize), 8) - ((UINT8 *)Ffs + FfsSize); + FvBufGetSize(Fv, &FvSize); + Offset = (UINT8 *)Ffs - (UINT8 *)Fv; + if (Offset + FfsSize < FvSize) { + NextFile = (EFI_FFS_FILE_HEADER2 *)((UINT8 *)Ffs + FfsSize); + if (NextFile->Type == EFI_FV_FILETYPE_FFS_PAD) { + FfsSize += GetFfsFileLength((EFI_FFS_FILE_HEADER *)NextFile); + } + } + return FfsSize; +} + +static +EFI_STATUS +ReadFfsAlignment( +IN EFI_FFS_FILE_HEADER *FfsFile, +IN OUT UINT32 *Alignment +) +{ + // + // Verify input parameters. + // + if (FfsFile == NULL || Alignment == NULL) { + return EFI_INVALID_PARAMETER; + } + + switch ((FfsFile->Attributes >> 3) & 0x07) { + + case 0: + // + // 1 byte alignment + // + *Alignment = 0; + break; + + case 1: + // + // 16 byte alignment + // + *Alignment = 4; + break; + + case 2: + // + // 128 byte alignment + // + *Alignment = 7; + break; + + case 3: + // + // 512 byte alignment + // + *Alignment = 9; + break; + + case 4: + // + // 1K byte alignment + // + *Alignment = 10; + break; + + case 5: + // + // 4K byte alignment + // + *Alignment = 12; + break; + + case 6: + // + // 32K byte alignment + // + *Alignment = 15; + break; + + case 7: + // + // 64K byte alignment + // + *Alignment = 16; + break; + + default: + break; + } + + return EFI_SUCCESS; +} + +static +BOOLEAN +ReplaceFfs(EFI_FIRMWARE_VOLUME_HEADER* Fv, EFI_FFS_FILE_HEADER2 *InputFfs, EFI_FFS_FILE_HEADER2 *OldFfs) { + UINT32 FfsSize; + UINT32 NewFileSize; + UINT32 Offset; + UINT32 Align; + UINT32 HdrSize; + UINT32 PadSize; + EFI_FFS_FILE_HEADER2 *Pad; + + Align = 0; + PadSize = 0; + Pad = NULL; + ReadFfsAlignment((EFI_FFS_FILE_HEADER *)InputFfs, &Align); + Align = 1 << Align; + HdrSize = GetFfsHeaderLength((EFI_FFS_FILE_HEADER *)InputFfs); + + FfsSize = CalcuFfsSize(Fv, OldFfs); + // + // Align data + // + if ((((UINT8 *)OldFfs - (UINT8 *)Fv) + HdrSize) % Align != 0) { + PadSize = ((UINT8 *)OldFfs - (UINT8 *)Fv) + sizeof (EFI_FFS_FILE_HEADER)+HdrSize; + while (PadSize % Align != 0) { + PadSize++; + } + PadSize -= HdrSize; + PadSize -= ((UINT8 *)OldFfs - (UINT8 *)Fv); + if (FfsSize < PadSize) { + return FALSE; + } + FfsSize -= PadSize; + Pad = OldFfs; + OldFfs = (EFI_FFS_FILE_HEADER2 *)((UINT8 *)OldFfs + PadSize); + } + + NewFileSize = GetFfsFileLength((EFI_FFS_FILE_HEADER *)InputFfs); + Offset = (UINT8 *)ALIGN_POINTER(((UINT8 *)OldFfs + NewFileSize), 8) - ((UINT8 *)OldFfs + NewFileSize); + if (FfsSize >= NewFileSize && FfsSize - NewFileSize <= 7) { + memcpy(OldFfs, (UINT8 *)InputFfs, NewFileSize); + if (Fv->Attributes & EFI_FVB2_ERASE_POLARITY) { + memset((UINT8 *)OldFfs + NewFileSize, -1, FfsSize - NewFileSize); + } + else { + memset((UINT8 *)OldFfs + NewFileSize, 0, FfsSize - NewFileSize); + } + } + else if (FfsSize >= NewFileSize + sizeof(EFI_FFS_FILE_HEADER) + Offset) { + memcpy(OldFfs, (UINT8 *)InputFfs, NewFileSize); + AddPadFile( + Fv, + (EFI_FFS_FILE_HEADER2 *)((UINT8 *)OldFfs + NewFileSize + Offset), + FfsSize - NewFileSize - Offset + ); + } + else { + return FALSE; + } + if (Fv->Attributes & EFI_FVB2_ERASE_POLARITY) { + OldFfs->State = (UINT8)~(InputFfs->State); + } + if (PadSize != 0) { + AddPadFile(Fv, Pad, PadSize); + } + return TRUE; +} + +static + +EFI_STATUS +AddFfs(UINT8 *FdBuffer, UINT32 ImageAddress, EFI_FIRMWARE_VOLUME_HEADER* Fv, EFI_FFS_FILE_HEADER2 *InputFfs, UINT32 *OffsetAdded) { + UINTN FreeOffset; + UINTN Offset; + UINTN FfsSize; + EFI_STATUS Status; + EFI_FFS_FILE_HEADER2 *CurrentFile; + EFI_FFS_FILE_HEADER FreeHeader; + + if (Fv->Attributes & EFI_FVB2_ERASE_POLARITY) { + memset(&FreeHeader, -1, sizeof(EFI_FFS_FILE_HEADER)); + } + else { + memset(&FreeHeader, 0, sizeof(EFI_FFS_FILE_HEADER)); + } + + FfsSize = GetFfsFileLength((EFI_FFS_FILE_HEADER *)InputFfs); + + Offset = 0; + CurrentFile = NULL; + FreeOffset = 0; + do { + if (FreeOffset == 0 && memcmp(FdBuffer + ImageAddress + (UINTN)ALIGN_POINTER(Offset, 8), &FreeHeader, sizeof(EFI_FFS_FILE_HEADER)) == 0) { + // + // Offset of free FV space found + // + FreeOffset = (UINTN)ALIGN_POINTER(Offset, 8); + } + Status = FvBufFindNextFile(FdBuffer + ImageAddress, &Offset, (VOID **)&CurrentFile); + if (Status == EFI_NOT_FOUND) { + CurrentFile = NULL; + break; + } + else if (EFI_ERROR(Status)) { + return Status; + } + + if (CurrentFile != NULL && CurrentFile->Type == EFI_FV_FILETYPE_FFS_PAD && + ReplaceFfs(Fv, InputFfs, CurrentFile)) { + *OffsetAdded = (UINT8 *)CurrentFile - (FdBuffer + ImageAddress); + return EFI_SUCCESS; + } + } while (CurrentFile != NULL); + + if (FreeOffset != 0) { + if (Fv->FvLength - FreeOffset < FfsSize) { + return EFI_ABORTED; + } + if (Fv->Attributes & EFI_FVB2_ERASE_POLARITY) { + InputFfs->State = (UINT8)~(InputFfs->State); + } + memcpy(FdBuffer + ImageAddress + FreeOffset, InputFfs, FfsSize); + *OffsetAdded = FreeOffset; + return EFI_SUCCESS; + } + + return EFI_NOT_FOUND; +} + +static +EFI_STATUS +FindPreviousFile(VOID *Fv, VOID *CurrentFile, VOID **PreFile) { + EFI_STATUS Status; + VOID *File = NULL; + UINTN Offset = 0; + + do { + *PreFile = File; + Status = FvBufFindNextFile(Fv, &Offset, &File); + if (Status == EFI_NOT_FOUND) { + CurrentFile = NULL; + break; + } + else if (EFI_ERROR(Status)) { + return Status; + } + if (File == CurrentFile) { + return EFI_SUCCESS; + } + } while (CurrentFile != NULL); + *PreFile = NULL; + return Status; +} + +static +BOOLEAN +NeedNewPath(FV_INFORMATION *FvInFd, CHAR8 *FvId, UINT32 FileIndex, BOOLEAN IsAdd) { + UINT32 Index; + + Index = 0; + + if (strcmp(FvId, FvInFd->FvName) != 0) { + return FALSE; + } + if (IsAdd) { + return TRUE; + } + if (FvInFd->FfsAttuibutes[FileIndex].FvLevel != 1) { + return FALSE; + } + + for (Index = 0; Index <= FvInFd->FfsNumbers; Index++) { + if (FvInFd->FfsAttuibutes[Index].FvLevel != 1) { + continue; + } + switch (FvInFd->FfsHeader[Index].Type) { + case EFI_FV_FILETYPE_PEI_CORE: + case EFI_FV_FILETYPE_PEIM: + case EFI_FV_FILETYPE_SECURITY_CORE: + return TRUE; + } + } + return FALSE; +} + +static UINT32 FindFile(FV_INFORMATION *FvInFd, UINT8 FvLevel, CHAR8 *File, UINT32 *MatchIndex) { + UINT32 Index = 0; + CHAR16 *UIName; + CHAR16 *FfsUIName; + UINT32 FileNumber = 0; + + UIName = (CHAR16 *)malloc(_MAX_PATH); + if (NULL == UIName) { + return 0; + } + FfsUIName = (CHAR16 *)malloc(_MAX_PATH); + if (NULL == FfsUIName) { + free(UIName); + return 0; + } + LibAscii2Unicode(File, UIName); + for (Index = 0; Index <= FvInFd->FfsNumbers; Index++) { + // + // Compare the New File Name with UI Name of FFS + // NOTE: The UI Name is Unicode, but the New File Name is Ascii. + // + memcpy(FfsUIName, (CHAR16 *)(FvInFd->FfsAttuibutes[Index].UiName), _MAX_PATH); + + if (FvInFd->FfsAttuibutes[Index].UiNameSize > 0 && memcmp(UIName, FfsUIName, FvInFd->FfsAttuibutes[Index].UiNameSize) == 0) { + FileNumber += 1; + *MatchIndex = Index; + if (FileNumber > 1) { + break; + } + } + + } + free(UIName); + free(FfsUIName); + + return FileNumber; +} + +/** + Search the config file from the path list. + + Split the path from env PATH, and then search the cofig + file from these paths. The priority is from left to + right of PATH string. When met the first Config file, it + will break and return the pointer to the full file name. + + @param PathList the pointer to the path list. + @param FileName the pointer to the file name. + + @retval The pointer to the file name. + @return NULL An error occurred. +**/ +CHAR8 * +SearchConfigFromPathList ( + IN CHAR8 *PathList, + IN CHAR8 *FileName +) +{ + CHAR8 *CurDir; + CHAR8 *FileNamePath; + + CurDir = NULL; + FileNamePath = NULL; + +#ifndef __GNUC__ + CurDir = strtok (PathList,";"); +#else + CurDir = strtok (PathList,":"); +#endif + while (CurDir != NULL) { + FileNamePath = (char *)calloc( + strlen (CurDir) + strlen (OS_SEP_STR) +strlen (FileName) + 1, + sizeof(char) + ); + if (FileNamePath == NULL) { + return NULL; + } + sprintf(FileNamePath, "%s%c%s", CurDir, OS_SEP, FileName); + if (access (FileNamePath, 0) != -1) { + return FileNamePath; + } +#ifndef __GNUC__ + CurDir = strtok(NULL, ";"); +#else + CurDir = strtok(NULL, ":"); +#endif + free (FileNamePath); + FileNamePath = NULL; + } + return NULL; +} + +UINT32 lenList(FILENode* head){ + FILENode *p = head; + UINT32 sum=0; + if(head==NULL) return 0; + while(p!=NULL){ + sum+=1; + p=p->Next; + } + return sum; +} + +void sortList(FILENode* head){ + UINT32 len = lenList(head); + FILENode *p = head; + UINT32 i; + UINT32 j; + if(len==0) return; + for(i=1; iSubLevel < p->Next->SubLevel){ + CHAR8 *FileName = p->FileName; + UINT8 tmp = p->SubLevel; + p->SubLevel = p->Next->SubLevel; + p->Next->SubLevel = tmp; + p->FileName = p->Next->FileName; + p->Next->FileName = FileName; + } + p=p->Next; + } + } +} + +BOOLEAN +ParseSection ( + IN EFI_FFS_FILE_HEADER2 *InputFfs +) +{ + BOOLEAN UISectionFlag; + UINT32 SectionLength; + UINT32 ParsedLength; + UINT32 FfsFileSize; + UINT8 *Ptr; + EFI_SECTION_TYPE Type; + + UISectionFlag = FALSE; + Ptr = NULL; + SectionLength = 0; + ParsedLength = GetFfsHeaderLength((EFI_FFS_FILE_HEADER *)InputFfs); + FfsFileSize = GetFfsFileLength((EFI_FFS_FILE_HEADER *)InputFfs); + + while (ParsedLength < FfsFileSize) { + Ptr = (UINT8 *)InputFfs + ParsedLength; + SectionLength = GetLength (((EFI_COMMON_SECTION_HEADER *) Ptr)->Size); + Type = ((EFI_COMMON_SECTION_HEADER *) Ptr)->Type; + + // + // This is sort of an odd check, but is necessary because FFS files are + // padded to a QWORD boundary, meaning there is potentially a whole section + // header worth of 0xFF bytes. + // + if ((SectionLength == 0xffffff) && (Type == 0xff)) { + ParsedLength += 4; + continue; + } + if (Type == EFI_SECTION_USER_INTERFACE) { + UISectionFlag = TRUE; + break; + } + ParsedLength += SectionLength; + // + // We make then next section begin on a 4-byte boundary + // + ParsedLength = GetOccupiedSize (ParsedLength, 4); + } + return UISectionFlag; + +} + + +/** + + Show the FD image layout information. Only display the modules with UI name. + + @param[in] FdInName Input FD binary/image file name; + @param[in] FvName The FV ID in the FD file; + @param[in] ViewFlag Is this call for view or other operate(add/del/replace) + @param[in] FdData The Fd data structure store the FD information. + + @retval EFI_SUCCESS + @retval EFI_INVALID_PARAMETER + @retval EFI_ABORTED + +**/ +EFI_STATUS +FmmtImageView ( + IN CHAR8* FdInName, + IN CHAR8* FvName, + IN BOOLEAN ViewFlag, + IN FIRMWARE_DEVICE **FdData +) +{ + EFI_STATUS Status; + EFI_STATUS ErrorStatus; + FIRMWARE_DEVICE *LocalFdData; + FV_INFORMATION *CurrentFv; + FILE *InputFile; + UINT32 FvSize; + UINTN BytesRead; + EFI_FIRMWARE_VOLUME_HEADER *FvImage; + UINT32 FfsCount; + UINT8 FvCount; + CHAR8 *TemDir; + + LocalFdData = NULL; + CurrentFv = NULL; + FvImage = NULL; + TemDir = NULL; + FvSize = 0; + BytesRead = 0; + FfsCount = 0; + FvCount = 0; + ErrorStatus = EFI_SUCCESS; + + // + // Check the FD file name/path. + // + if (FdInName == NULL) { + Error("FMMT", 0, 1001, "Invalid parameter! Please specify ", FdInName); + Usage(); + return EFI_INVALID_PARAMETER; + } + + // + // Open the file containing the FV + // + InputFile = fopen (FdInName, "rb"); + if (InputFile == NULL) { + Error (NULL, 0, 0001, "Error opening the input file", FdInName); + return EFI_INVALID_PARAMETER; + } + + Status = LibFindFvInFd (InputFile, &LocalFdData); + + if (EFI_ERROR(Status)) { + Error("FMMT", 0, 1001, "Error while search FV in FD", ""); + fclose (InputFile); + return EFI_ABORTED; + } + + CurrentFv = LocalFdData->Fv; + + + do { + + memset (CurrentFv->FvName, '\0', _MAX_PATH); + + if (FvCount == 0) { + sprintf (CurrentFv->FvName, "FV%d", FvCount); + } else { + sprintf (CurrentFv->FvName, "FV%d", FvCount); + } + + // + // Determine size of FV + // + if (fseek (InputFile, CurrentFv->ImageAddress, SEEK_SET) != 0) { + Error (NULL, 0, 0003, "error parsing FV image", "%s FD file is invalid", InputFile); + fclose (InputFile); + ErrorStatus = EFI_ABORTED; + goto Done; + } + + Status = LibGetFvSize(InputFile, &FvSize); + if (EFI_ERROR (Status)) { + Error (NULL, 0, 0003, "error parsing FV image", "%s Header is invalid", InputFile); + fclose (InputFile); + ErrorStatus = EFI_ABORTED; + goto Done; + } + + // + // Seek to the start of the image, then read the entire FV to the buffer + // + fseek (InputFile, CurrentFv->ImageAddress, SEEK_SET); + + + FvImage = (EFI_FIRMWARE_VOLUME_HEADER *) malloc (FvSize); + + if (FvImage == NULL) { + Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL); + fclose (InputFile); + ErrorStatus = EFI_ABORTED; + goto Done; + } + + BytesRead = fread (FvImage, 1, FvSize, InputFile); + if ((unsigned int) BytesRead != FvSize) { + Error ("FMMT", 0, 0004, "error reading FvImage from", FdInName); + free (FvImage); + fclose (InputFile); + ErrorStatus = EFI_ABORTED; + goto Done; + } + + // + // Collect FV information each by each. + // + Status = LibGetFvInfo (FvImage, CurrentFv, FvName, 0, &CurrentFv->EncapData, &FfsCount, &FvCount, ViewFlag, FALSE); + if (FvImage != NULL) { + free (FvImage); + FvImage = NULL; + } + if (EFI_ERROR (Status)) { + Error ("FMMT", 0, 0004, "error while get information from FV %s", FvName); + ErrorStatus = Status; + // + // If the FV to be parsed error is the same with the input FV in add, replace and delete + // operation, abort the program directly. + // + if ((FvName != NULL) && ((CurrentFv->FvName) != NULL) && !strcmp(CurrentFv->FvName, FvName)) { + fclose (InputFile); + ErrorStatus = EFI_ABORTED; + goto Done; + } + } + + + FfsCount = 0; + + CurrentFv = CurrentFv->FvNext; + + } while (CurrentFv != NULL); + + fclose (InputFile); + + if (ViewFlag) { + + TemDir = getcwd (NULL, _MAX_PATH); + if (strlen (TemDir) + strlen(OS_SEP_STR) + strlen (TEMP_DIR_NAME) > _MAX_PATH - 1) { + Error("FMMT", 0, 1001, "The directory is too long.", ""); + ErrorStatus = EFI_ABORTED; + goto Done; + } + strncat (TemDir, OS_SEP_STR, _MAX_PATH - strlen(TemDir) - 1); + strncat (TemDir, TEMP_DIR_NAME, _MAX_PATH - strlen(TemDir) - 1); + + mkdir(TemDir, S_IRWXU | S_IRWXG | S_IRWXO); + + Status = LibRmDir (TemDir); + + if (EFI_ERROR (Status)) { + Error ("FMMT", 0, 0004, "error while encapsulate FD Image", "remove directory failed!"); + ErrorStatus = Status; + } + } +Done: + if (!ViewFlag) { + *FdData = LocalFdData; + } else { + LibFmmtFreeFd( LocalFdData); + } + return ErrorStatus; +} + +/** + Add FFS file into a specify FV. + + @param[in] FdInName Input FD binary/image file name; + @param[in] FileList The FV ID and FFS file Data; + @param[in] count The length of FileList; + @param[in] FdOutName Name of output FD binary/image file. + + @retval EFI_SUCCESS + @retval EFI_INVALID_PARAMETER + @retval EFI_ABORTED + +**/ +EFI_STATUS +FmmtImageAdd( + IN CHAR8* FdInName, + IN Data *FileList, + IN int count, + IN CHAR8* FdOutName +) +{ + EFI_STATUS Status; + FIRMWARE_DEVICE *FdData; + FV_INFORMATION *FvInFd; + FILE* NewFdFile; + FILE* NewFvFile; + UINT64 NewFvLength; + VOID* Buffer; + CHAR8 *TemDir; + UINT8 FvNumInFd; + UINT8 FvNumInFdCounter; + UINT8 NewAddedFfsLevel; + FFS_INFORMATION *OutputFileName; + UINT32 Index; + UINT32 EndId; + UINT8 *FdBuffer; + EFI_FIRMWARE_VOLUME_HEADER *Fv; + UINT32 FdSize; + EFI_FFS_FILE_HEADER2 *InputFfs; + UINT32 NewFileSize; + UINT64 BaseAddr; + UINT32 OffsetAdded; + int i; + int j; + Data *tmp; + CHAR8* FvId; + CHAR8* NewFile; + FILENode *NewFileNode; + BOOLEAN HasUISection; + HasUISection = FALSE; + Index = 0; + EndId = 0; + NewFvLength = 0; + FvNumInFd = 0; + FvNumInFdCounter = 0; + NewAddedFfsLevel = 0; + FdData = NULL; + FvInFd = NULL; + NewFdFile = NULL; + NewFvFile = NULL; + Buffer = NULL; + TemDir = NULL; + OutputFileName = NULL; + FvId = NULL; + NewFile = NULL; + + FdBuffer = NULL; + InputFfs = NULL; + BaseAddr = 0; + OffsetAdded = 0; + FdSize = 0; + + for (i = 0; i < count; i ++){ + tmp = FileList + i; + FvId = tmp->FvId; + FdData = tmp->FdData; + if (FdData == NULL) { + Status = FmmtImageView (FdInName, FvId, FALSE, &FdData); + if (EFI_ERROR (Status) && Status != EFI_UNSUPPORTED) { + Error ("FMMT", 0, 0004, "error while parsing FD Image", "Gathering FD information failed!"); + return Status; + } + if (FdData == NULL) { + Error ("FMMT", 0, 0004, "error while parsing FD Image", ""); + return EFI_ABORTED; + } + + Status = LibLocateFvViaFvId (FdData, FvId, &FvInFd); + if (EFI_ERROR (Status)) { + Error ("FMMT", 0, 0005, "error while locate FV in FD", ""); + return Status; + } + (FileList + i) -> FdData = FdData; + (FileList + i) -> FvInFd = FvInFd; + (FileList + i) -> FvLevel = FvInFd -> FvLevel; + } + } + + for (i = 0; i < count; i++) { + for (j = i + 1; j < count; j++){ + if (((FileList + i)->FvId == NULL) || ((FileList + j)->FvId == NULL)) { + continue; + } + if (strcmp((FileList + j)->FvId, (FileList + i)->FvInFd->FvName) == 0){ + NewFileNode = (FileList + j)->NewFile; + while (NewFileNode ->Next != NULL) { + NewFileNode = NewFileNode->Next; + } + NewFileNode->Next = (FileList + i)->NewFile; + (FileList + i)->FvId = NULL; + } + } + } + + for (i = 0; i < count; i ++){ + if ((FileList + i)->FvId == NULL) { + continue; + } + sortList ((FileList + i)-> NewFile); + } + + TemDir = getcwd(NULL, _MAX_PATH); + if (strlen (TemDir) + strlen(OS_SEP_STR) + strlen (TEMP_DIR_NAME) > _MAX_PATH - 1) { + Error("FMMT", 0, 1001, "The directory is too long.", ""); + return EFI_ABORTED; + } + strncat (TemDir, OS_SEP_STR, _MAX_PATH - strlen(TemDir) - 1); + strncat (TemDir, TEMP_DIR_NAME, _MAX_PATH - strlen(TemDir) - 1); + + if (FdBuffer == NULL) { + FdBuffer = ReadFileToBuffer(FdInName, &FdSize); + if (FdBuffer == NULL) { + Error("FMMT", 0, 0004, "error while adding file", "cannot read input file."); + return EFI_ABORTED; + } + } + + for (i = 0; i < count; i ++){ + tmp = FileList + i; + FvId = tmp->FvId; + if (FvId == NULL) { + continue; + } + FdData = tmp->FdData; + FvInFd = tmp->FvInFd; + NewFileNode =tmp->NewFile; + + NewFile = NewFileNode->FileName; + InputFfs = (EFI_FFS_FILE_HEADER2 *)ReadFileToBuffer(NewFile, &NewFileSize); + if (InputFfs == NULL) { + Error("FMMT", 0, 0004, "error while adding file", "cannot read input file."); + Status = EFI_ABORTED; + goto FAILED; + } + HasUISection = FALSE; + HasUISection = ParseSection(InputFfs); + if (!HasUISection) { + printf ("WARNING: The newly add file must have a user interface (UI) section, otherwise it cannot be deleted or replaced. \n"); + } + if (NeedNewPath(FvInFd, FvId, 0, TRUE)) { + do { + NewFile = NewFileNode->FileName; + // + // TODO: currently only root FV is handled + // + InputFfs = (EFI_FFS_FILE_HEADER2 *)ReadFileToBuffer(NewFile, &NewFileSize); + if (InputFfs == NULL) { + Error("FMMT", 0, 0004, "error while adding file", "cannot read input file."); + Status = EFI_ABORTED; + goto FAILED; + } + + Fv = (EFI_FIRMWARE_VOLUME_HEADER *)(FdBuffer + FvInFd->ImageAddress); + + Status = AddFfs(FdBuffer, FvInFd->ImageAddress, Fv, InputFfs, &OffsetAdded); + if (EFI_ERROR(Status)) { + Error("FMMT", 0, 0003, "error while adding file", "Not enough space to add FFS"); + goto FAILED; + } + // + // Calculate base address of Current FV + // + if (InputFfs->Type == EFI_FV_FILETYPE_PEIM || InputFfs->Type == EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE) { + Status = GetBaseAddrFromFsp(FdData, FdBuffer, FvId, &BaseAddr); + if (!EFI_ERROR(Status)) { + mFvHeader = FvInFd->FvHeader; + mFvLength = (UINT32)FvInFd->FvHeader->FvLength; + RebaseFfs(BaseAddr, NewFile, (EFI_FFS_FILE_HEADER *)(FdBuffer + FvInFd->ImageAddress + OffsetAdded), OffsetAdded); + } + else { + Status = GetBaseAddrFromVtf(FdData, FvId, &BaseAddr); + if (!EFI_ERROR(Status)) { + mFvHeader = FvInFd->FvHeader; + mFvLength = (UINT32)FvInFd->FvHeader->FvLength; + RebaseFfs(BaseAddr, NewFile, (EFI_FFS_FILE_HEADER *)(FdBuffer + FvInFd->ImageAddress + OffsetAdded), OffsetAdded); + } + } + } + NewFileNode = NewFileNode->Next; + free (InputFfs); + InputFfs = NULL; + } while (NewFileNode != NULL); + } else { + do { + NewFile = NewFileNode->FileName; + if (strlen (NewFile) > _MAX_PATH - 1) { + Error ("FMMT", 0, 2000, "error while adding file", "New file name is too long!"); + Status = EFI_ABORTED; + goto FAILED; + } + FvNumInFd = ((UINT8)atoi(FvId + 2) - (UINT8)atoi(FvInFd->FvName + 2)); + if (FvInFd->FfsNumbers == 0) { + NewAddedFfsLevel = FvInFd->FfsAttuibutes[0].Level; + } + for (Index = 0; Index <= FvInFd->FfsNumbers; Index++) { + if (FvInFd->FfsAttuibutes[Index].IsFvStart == 1) { + FvNumInFdCounter++; + } + if ( FvNumInFdCounter == FvNumInFd && FvInFd->FfsAttuibutes[Index].IsFvEnd == 1) { + NewAddedFfsLevel = FvInFd->FfsAttuibutes[Index].Level; + EndId = Index+1; + break; + } + if (FvInFd->FfsAttuibutes[Index].IsFvEnd == 1) { + FvNumInFdCounter--; + if (FvNumInFdCounter == 0) { + FvNumInFd--; + } + } + } + + // + // Add the new file into FV. + // + FvInFd->FfsNumbers += 1; + for (Index = FvInFd->FfsNumbers; Index > EndId; Index--) { + FvInFd->FfsAttuibutes[Index] = FvInFd->FfsAttuibutes[Index - 1]; + } + strncpy(FvInFd->FfsAttuibutes[EndId].FfsName, NewFile, _MAX_PATH - 1); + FvInFd->FfsAttuibutes[EndId].FfsName[_MAX_PATH - 1] = 0; + FvInFd->FfsAttuibutes[EndId].Level = NewAddedFfsLevel; + memset (&FvInFd->FfsAttuibutes[EndId].GuidName, '\0', sizeof(EFI_GUID)); + if (EndId > 0) { + FvInFd->FfsAttuibutes[EndId].FvLevel = FvInFd->FfsAttuibutes[EndId - 1].FvLevel; + FvInFd->FfsAttuibutes[EndId - 1].IsFvEnd = 0; + } + FvInFd->FfsAttuibutes[EndId].IsFvEnd = 1; + FvInFd->FfsAttuibutes[EndId].IsFvStart = 0; + NewFileNode = NewFileNode->Next; + } while (NewFileNode != NULL); + + mkdir(TemDir, S_IRWXU | S_IRWXG | S_IRWXO); + + Status = LibEncapNewFvFile (FvInFd, TemDir, NULL, 0, &OutputFileName); + if (EFI_ERROR (Status)) { + Error ("FMMT", 0, 0004, "error while encapsulate FD Image", "Make new FV file failed!"); + goto FAILED; + } + + NewFvFile = fopen (OutputFileName->FFSName, "rb+"); + if (NewFvFile == NULL) { + Error ("FMMT", 0, 0003, "error Open FV file", "cannot Create a new FD file."); + Status = EFI_ABORTED; + goto FAILED; + } + + fseek(NewFvFile,0,SEEK_SET); + fseek(NewFvFile,0,SEEK_END); + + NewFvLength = ftell(NewFvFile); + fseek(NewFvFile,0,SEEK_SET); + Buffer = malloc ((size_t)NewFvLength); + if (Buffer == NULL) { + Status = EFI_ABORTED; + fclose(NewFvFile); + goto FAILED; + } + + if (fread (Buffer, 1, (size_t) NewFvLength, NewFvFile) != (size_t) NewFvLength) { + Error ("FMMT", 0, 0003, "error reading FV file %s", OutputFileName->FFSName); + free (Buffer); + Status = EFI_ABORTED; + fclose(NewFvFile); + goto FAILED; + } + + if (NewFvLength <= FvInFd->FvHeader->FvLength) { + memcpy(FdBuffer+FvInFd->ImageAddress,Buffer,(size_t) NewFvLength); + } else { + Error ("FMMT", 0, 0004, "error writing FD file", "The add ffs file is too large."); + } + fclose(NewFvFile); + free(Buffer); + } + } + + Status = LibRmDir(TemDir); + if (EFI_ERROR(Status)) { + Error("FMMT", 0, 0004, "error while encapsulate FD Image", "remove directory failed!"); + goto FAILED; + } + + NewFdFile = fopen(FdOutName, "wb"); + if (NewFdFile == NULL) { + Error("FMMT", 0, 0004, "error while encapsulate FD Image", "Cannot open target FD file!"); + Status = EFI_ABORTED; + goto FAILED; + } + + fwrite(FdBuffer, 1, FdSize, NewFdFile); + fclose(NewFdFile); + free(FdBuffer); + free(InputFfs); + printf ("Create New FD file successfully. \n\nDone! \n"); + return EFI_SUCCESS; + + FAILED: + if (FdBuffer != NULL) { + free(FdBuffer); + } + if (InputFfs != NULL) { + free(InputFfs); + } + return Status; +} + +/** +Delete a root FV from FD. + +@param[in] FdInName Input FD binary/image file name; +@param[in] FvName FV name; +@param[in] FdOutName Name of output fd file. + +@retval EFI_SUCCESS +@retval EFI_INVALID_PARAMETER +@retval EFI_ABORTED + +**/ +EFI_STATUS +FmmtImageDeleteFv( + IN CHAR8* FdInName, + IN CHAR8* FvName, + IN CHAR8* FdOutName +) +{ + EFI_STATUS Status; + FV_INFORMATION *FvInFd; + FILE *NewFdFile; + CHAR8 *TemDir; + + UINT8 *FdBuffer = NULL; + UINT8 *FdBak = NULL; + UINT32 FdSize = 0; + + FIRMWARE_DEVICE *FdData = NULL; + + TemDir = getcwd(NULL, _MAX_PATH); + if (strlen (TemDir) + strlen(OS_SEP_STR) + strlen (TEMP_DIR_NAME) > _MAX_PATH - 1) { + Error("FMMT", 0, 1001, "The directory is too long.", ""); + return EFI_ABORTED; + } + strncat (TemDir, OS_SEP_STR, _MAX_PATH - strlen(TemDir) - 1); + strncat (TemDir, TEMP_DIR_NAME, _MAX_PATH - strlen(TemDir) - 1); + + Status = FmmtImageView(FdInName, NULL, FALSE, &FdData); + if (EFI_ERROR(Status) && Status != EFI_UNSUPPORTED) { + Error("FMMT", 0, 0004, "error while parsing FD Image", "Gathering FD information failed!"); + goto END; + } + if (FdData == NULL) { + Error("FMMT", 0, 0004, "error while parsing FD Image", ""); + Status = EFI_ABORTED; + goto END; + } + + FvInFd = FdData->Fv; + while (FvInFd) { + if (FvInFd->FvUiName && strcmp(FvInFd->FvUiName, FvName) == 0) { + break; + } + FvInFd = FvInFd->FvNext; + } + if (!FvInFd) { + Error("FMMT", 0, 0004, "error while deleting root FV", "Cannot find this FV!"); + Status = EFI_ABORTED; + goto END; + } + FdBuffer = ReadFileToBuffer(FdInName, &FdSize); + FdBak = FdBuffer; + if (FdBuffer == NULL) { + Error("FMMT", 0, 0004, "error while deleting root FV", "Cannot read FD file!"); + Status = EFI_ABORTED; + goto END; + } + + if (FvInFd->ImageAddress == 0) { + FdBuffer = FdBuffer + FvInFd->FvHeader->FvLength; + FdSize -= (UINT32)FvInFd->FvHeader->FvLength; + } else { + if (FvInFd->FvHeader->Attributes & EFI_FVB2_ERASE_POLARITY) { + memset(FdBuffer + FvInFd->ImageAddress, -1, (size_t)FvInFd->FvHeader->FvLength); + } + else { + memset(FdBuffer + FvInFd->ImageAddress, 0, (size_t)FvInFd->FvHeader->FvLength); + } + } + + NewFdFile = fopen(FdOutName, "wb"); + if (NewFdFile == NULL) { + Error("FMMT", 0, 0004, "error while deleting root FV", "Cannot open target FD file!"); + Status = EFI_ABORTED; + goto END; + } + fwrite(FdBuffer, 1, FdSize, NewFdFile); + fclose(NewFdFile); + + Status = LibRmDir(TemDir); + + if (EFI_ERROR(Status)) { + Error("FMMT", 0, 0004, "error while deleting root FV", "remove directory failed!"); + goto END; + } + + printf("Create New FD file successfully. \n\nDone! \n"); +END: + LibFmmtFreeFd(FdData); + free(FdBak); + return Status; +} + +/** + Delete an FFS file from a specify FV. + + @param[in] FdInName Input FD binary/image file name; + @param[in] FileList The FV ID and FFS file Data; + @param[in] count The length of FileList; + @param[in] FdOutName Name of output fd file. + + @retval EFI_SUCCESS + @retval EFI_INVALID_PARAMETER + @retval EFI_ABORTED + +**/ +EFI_STATUS +FmmtImageDelete ( + IN CHAR8* FdInName, + IN Data *FileList, + IN int count, + IN CHAR8* FdOutName +) +{ + EFI_STATUS Status; + FIRMWARE_DEVICE *FdData; + FV_INFORMATION *FvInFd; + UINT32 Index; + UINT32 FfsFoundFlag; + FFS_INFORMATION *OutputFileName; + FILE* NewFdFile; + FILE* NewFvFile; + UINT64 NewFvLength; + VOID* Buffer; + CHAR8 *TemDir; + UINT8 FvNumInFd; + UINT32 Offset; + UINT8 *FdBuffer; + EFI_FFS_FILE_HEADER2 *CurrentFile; + EFI_FFS_FILE_HEADER2 *PreFile; + Data *tmp; + CHAR8* FvId; + CHAR8* DelFile; + FILENode *OldFileNode; + int i; + UINT32 FfsSize; + UINT32 FdSize; + int j; + + FdSize = 0; + Index = 0; + NewFvLength = 0; + FfsFoundFlag = 0; + FdData = NULL; + FvInFd = NULL; + OutputFileName = NULL; + NewFdFile = NULL; + NewFvFile = NULL; + Buffer = NULL; + TemDir = NULL; + FvNumInFd = 0; + Offset = 0; + FdBuffer = NULL; + + for (i = 0; i < count; i ++){ + tmp = FileList + i; + FvId = tmp->FvId; + FdData = tmp->FdData; + if (FdData == NULL) { + Status = FmmtImageView (FdInName, FvId, FALSE, &FdData); + if (EFI_ERROR (Status) && Status != EFI_UNSUPPORTED) { + Error ("FMMT", 0, 0004, "error while parsing FD Image", "Gathering FD information failed!"); + return Status; + } + if (FdData == NULL) { + Error ("FMMT", 0, 0004, "error while parsing FD Image", ""); + return EFI_ABORTED; + } + + Status = LibLocateFvViaFvId (FdData, FvId, &FvInFd); + if (EFI_ERROR (Status)) { + Error ("FMMT", 0, 0005, "error while locate FV in FD", ""); + return Status; + } + (FileList + i) -> FdData = FdData; + (FileList + i) -> FvInFd = FvInFd; + (FileList + i) -> FvLevel = FvInFd -> FvLevel; + } + FvNumInFd = ((UINT8)atoi(FvId + 2) - (UINT8)atoi(FvInFd->FvName + 2)) + 1; + OldFileNode = tmp-> OldFile; + do { + DelFile = OldFileNode->FileName; + if (FvInFd == NULL) { + break; + } + FfsFoundFlag = FindFile(FvInFd, FvNumInFd, DelFile, &Index); + if (FfsFoundFlag) { + if (FfsFoundFlag > 1) { + printf("Duplicated file found in this FV, file name: %s\n", DelFile); + return EFI_ABORTED; + } + } else { + printf ("Could not found the FFS file from FD!, file name: %s\n", DelFile); + return EFI_ABORTED; + } + OldFileNode -> SubLevel = FvInFd -> FfsAttuibutes[Index].Level; + OldFileNode = OldFileNode->Next; + } while (OldFileNode != NULL); + } + + for (i = 0; i < count; i++) { + for (j = i + 1; j < count; j++) + { + if (((FileList + i)->FvId == NULL) || ((FileList + j)->FvId == NULL)) { + continue; + } + if (strcmp((FileList + j)->FvId, (FileList + i)->FvInFd->FvName) == 0){ + OldFileNode = (FileList + j)->OldFile; + while (OldFileNode ->Next != NULL) { + OldFileNode = OldFileNode->Next; + } + OldFileNode->Next = (FileList + i)->OldFile; + (FileList + i)->FvId = NULL; + } + } + } + + for (i = 0; i < count; i ++){ + if ((FileList + i)->FvId == NULL) { + continue; + } + sortList ((FileList + i)-> OldFile); + } + + TemDir = getcwd(NULL, _MAX_PATH); + if (strlen (TemDir) + strlen(OS_SEP_STR) + strlen (TEMP_DIR_NAME) > _MAX_PATH - 1) { + Error("FMMT", 0, 1001, "The directory is too long.", ""); + return EFI_ABORTED; + } + strncat (TemDir, OS_SEP_STR, _MAX_PATH - strlen(TemDir) - 1); + strncat (TemDir, TEMP_DIR_NAME, _MAX_PATH - strlen(TemDir) - 1); + + if (FdBuffer == NULL) { + FdBuffer = ReadFileToBuffer(FdInName, &FdSize); + if (FdBuffer == NULL) { + Error("FMMT", 0, 0004, "error while deleting file", "cannot read input file."); + return EFI_ABORTED; + } + } + + for (i = 0; i < count; i ++){ + tmp = FileList + i; + FvId = tmp->FvId; + if (FvId == NULL) { + continue; + } + FdData = tmp->FdData; + FvInFd = tmp->FvInFd; + FvNumInFd = ((UINT8)atoi(FvId + 2) - (UINT8)atoi(FvInFd->FvName + 2)) + 1; + OldFileNode = tmp->OldFile; + DelFile = OldFileNode -> FileName; + FfsFoundFlag = FindFile(FvInFd, FvNumInFd, DelFile, &Index); + if (FfsFoundFlag && NeedNewPath(FvInFd, FvId, Index, FALSE)) { + do { + DelFile = OldFileNode -> FileName; + FfsFoundFlag = FindFile(FvInFd, FvNumInFd, DelFile, &Index); + // + // TODO: currently only root FV is handled + // + Offset = FvInFd->ImageAddress + FvInFd->FfsAttuibutes[Index].Offset; + if (FdBuffer != NULL) { + CurrentFile = (EFI_FFS_FILE_HEADER2 *)(FdBuffer + Offset); + + FfsSize = CalcuFfsSize((EFI_FIRMWARE_VOLUME_HEADER *)(FdBuffer + FvInFd->ImageAddress), CurrentFile); + + FindPreviousFile((EFI_FIRMWARE_VOLUME_HEADER *)(FdBuffer + FvInFd->ImageAddress), CurrentFile, (VOID **) &PreFile); + if (PreFile != NULL && PreFile->Type == EFI_FV_FILETYPE_FFS_PAD) { + FfsSize += (UINT8 *)CurrentFile - (UINT8 *)PreFile; + CurrentFile = PreFile; + } + AddPadFile((EFI_FIRMWARE_VOLUME_HEADER *)(FdBuffer + FvInFd->ImageAddress), CurrentFile, FfsSize); + } + OldFileNode = OldFileNode -> Next; + } while (OldFileNode != NULL); + } else { + do { + DelFile = OldFileNode -> FileName; + FfsFoundFlag = FindFile(FvInFd, FvNumInFd, DelFile, &Index); + + if (FfsFoundFlag) { + // + // Delete this FFS file from Current FV structure. + // + Status = LibFmmtDeleteFile (FvInFd->FfsAttuibutes[Index].FfsName); + if (EFI_ERROR (Status)) { + Error ("FMMT", 0, 0004, "error while encapsulate FD Image", "Delete the specified file failed!"); + Error ("FMMT", 0, 0004, "Cannot find the file need to delete", "Please check the name of the file you want to delete!"); + goto FAILED; + } + + memset(FvInFd->FfsAttuibutes[Index].FfsName, '\0', _MAX_PATH); + FvInFd->FfsAttuibutes[Index].Level = 0xFF; + + // + // Since we can avoid to add NULL ffs file, at this time we don't need to decrease the FFS number. + // If decrease operation executed, we should adjust the ffs list. It will bring in more complex. + // + //FvInFd->FfsNumbers -= 1; + memset(FvInFd->FfsAttuibutes[Index].UiName, '\0', _MAX_PATH); + if (FvInFd->FfsAttuibutes[Index].FvLevel > 1) { + for (j = Index - 1; j >= 0; j--) { + if (FvInFd->FfsAttuibutes[j].FvLevel == FvInFd->FfsAttuibutes[Index].FvLevel - 1) { + break; + } + } + if (Index+1 <= FvInFd->FfsNumbers) { + if (FvInFd->FfsAttuibutes[Index+1].FvLevel == FvInFd->FfsAttuibutes[Index].FvLevel + 1) { + for (j = Index+1; j <= (signed)FvInFd->FfsNumbers; j++) { + if (FvInFd->FfsAttuibutes[j].FvLevel > FvInFd->FfsAttuibutes[Index].FvLevel) { + Status = LibFmmtDeleteFile(FvInFd->FfsAttuibutes[j].FfsName); + if (EFI_ERROR(Status)) { + Error("FMMT", 0, 0004, "error while encapsulate FD Image", "Delete the specified file failed!"); + return Status; + } + memset(FvInFd->FfsAttuibutes[j].FfsName, '\0', _MAX_PATH); + FvInFd->FfsAttuibutes[j].Level = 0xFF; + } + } + } + } + } + } else { + printf ("Could not found the FFS file from FD!, file name: %s\n", DelFile); + Status = EFI_ABORTED; + goto FAILED; + } + OldFileNode = OldFileNode -> Next; + + }while (OldFileNode != NULL); + + mkdir(TemDir, S_IRWXU | S_IRWXG | S_IRWXO); + + Status = LibEncapNewFvFile (FvInFd, TemDir, NULL, 0, &OutputFileName); + if (EFI_ERROR (Status)) { + Error ("FMMT", 0, 0004, "error while encapsulate FD Image", "Make new FV file failed!"); + goto FAILED; + } + + NewFvFile = fopen (OutputFileName->FFSName, "rb+"); + if (NewFvFile == NULL) { + Error ("FMMT", 0, 0003, "error Open FV file", "cannot Create a new FD file."); + Status = EFI_ABORTED; + goto FAILED; + } + + fseek(NewFvFile,0,SEEK_SET); + fseek(NewFvFile,0,SEEK_END); + + NewFvLength = ftell(NewFvFile); + fseek(NewFvFile,0,SEEK_SET); + Buffer = malloc ((size_t)NewFvLength); + if (Buffer == NULL) { + fclose(NewFvFile); + Status = EFI_ABORTED; + goto FAILED; + } + + if (fread (Buffer, 1, (size_t) NewFvLength, NewFvFile) != (size_t) NewFvLength) { + Error ("FMMT", 0, 0003, "error reading FV file %s", OutputFileName->FFSName); + fclose(NewFvFile); + free(Buffer); + Status = EFI_ABORTED; + goto FAILED; + } + memcpy(FdBuffer+FvInFd->ImageAddress,Buffer,(size_t) NewFvLength); + free(Buffer); + fclose(NewFvFile); + } + } + + Status = LibRmDir(TemDir); + if (EFI_ERROR(Status)) { + Error("FMMT", 0, 0004, "error while encapsulate FD Image", "remove directory failed!"); + goto FAILED; + } + + NewFdFile = fopen(FdOutName, "wb"); + if (NewFdFile == NULL) { + Error("FMMT", 0, 0004, "error while encapsulate FD Image", "Cannot open target FD file!"); + Status = EFI_ABORTED; + goto FAILED; + } + + fwrite(FdBuffer, 1, FdSize, NewFdFile); + fclose(NewFdFile); + free(FdBuffer); + printf("Create New FD file successfully. \n\nDone! \n"); + return EFI_SUCCESS; + + FAILED: + free(FdBuffer); + return Status; +} + +/** + Replace the exist FFS file with new one from a specify FV. + + @param[in] FdInName Input FD binary/image file name; + @param[in] FileList The FV ID and FFS file Data; + @param[in] count The length of FileList; + @param[in] FdOutName Name of output fd file. + + @retval EFI_SUCCESS + @retval EFI_INVALID_PARAMETER + @retval EFI_ABORTED + +**/ +EFI_STATUS +FmmtImageReplace ( + IN CHAR8* FdInName, + IN Data *FileList, + IN int count, + IN CHAR8* FdOutName +) +{ + EFI_STATUS Status; + FIRMWARE_DEVICE *FdData; + FV_INFORMATION *FvInFd; + UINT32 Index; + UINT32 FfsFoundFlag; + FFS_INFORMATION *OutputFileName; + FILE* NewFdFile; + FILE* NewFvFile; + UINT64 NewFvLength; + VOID* Buffer; + CHAR8 *TemDir; + UINT32 Offset; + UINT8 *FdBuffer; + UINT8 FvNumInFd; + EFI_FFS_FILE_HEADER2 *CurrentFile; + EFI_FIRMWARE_VOLUME_HEADER *Fv; + UINT32 FdSize; + EFI_FFS_FILE_HEADER2 *InputFfs; + UINT32 NewFileSize; + UINT32 PadFileSize; + UINT64 BaseAddr; + UINT32 OffsetAdded; + Data *tmp; + CHAR8* FvId; + CHAR8* OldFile; + CHAR8* NewFile; + int i; + int j; + FILENode *OldFileNode; + FILENode *NewFileNode; + BOOLEAN HasUISection; + HasUISection = FALSE; + Index = 0; + NewFvLength = 0; + FfsFoundFlag = 0; + FdData = NULL; + FvInFd = NULL; + OutputFileName = NULL; + NewFdFile = NULL; + NewFvFile = NULL; + Buffer = NULL; + TemDir = NULL; + Offset = 0; + FdBuffer = NULL; + InputFfs = NULL; + BaseAddr = 0; + OffsetAdded = 0; + FdSize = 0; + + for (i = 0; i < count; i ++){ + tmp = FileList + i; + FvId = tmp->FvId; + FdData = tmp->FdData; + if (FdData == NULL){ + Status = FmmtImageView(FdInName, FvId, FALSE, &FdData); + if (EFI_ERROR(Status) && Status != EFI_UNSUPPORTED) { + Error("FMMT", 0, 0004, "error while parsing FD Image", "Gathering information failed!"); + return Status; + } + + if (FdData == NULL) { + Error("FMMT", 0, 0004, "error while parsing FD Image", ""); + return EFI_ABORTED; + } + + Status = LibLocateFvViaFvId(FdData, FvId, &FvInFd); + if (EFI_ERROR(Status)) { + Error("FMMT", 0, 0005, "error while locate FV in FD", ""); + return Status; + } + (FileList + i) -> FdData = FdData; + (FileList + i) -> FvInFd = FvInFd; + (FileList + i) -> FvLevel = FvInFd -> FvLevel; + } + FvNumInFd = ((UINT8)atoi(FvId + 2) - (UINT8)atoi(FvInFd->FvName + 2)) + 1; + OldFileNode = tmp-> OldFile; + NewFileNode = tmp-> NewFile; + do { + OldFile = OldFileNode -> FileName; + NewFile = NewFileNode -> FileName; + if (FvInFd == NULL) { + break; + } + FfsFoundFlag = FindFile(FvInFd, FvNumInFd, OldFile, &Index); + + if (FfsFoundFlag) { + if (FfsFoundFlag > 1) { + printf("Duplicated file found in this FV, file name: %s\n", OldFile); + return EFI_ABORTED; + } + // + // Replace this FFS file with the new one. + // strcpy (FvInFd->FfsAttuibutes[Index].FfsName, NewFile); + } else { + printf ("Could not found the FFS file need to be replaced from FD! file name: %s\n", OldFile); + return EFI_ABORTED; + } + OldFileNode -> SubLevel = FvInFd -> FfsAttuibutes[Index].Level; + NewFileNode -> SubLevel = FvInFd -> FfsAttuibutes[Index].Level; + OldFileNode = OldFileNode->Next; + NewFileNode = NewFileNode->Next; + } while (OldFileNode != NULL && NewFileNode != NULL); + } + + for (i = 0; i < count; i++) { + for (j = i + 1; j < count; j++) + { + if (((FileList + i)->FvId == NULL) || ((FileList + j)->FvId == NULL)) { + continue; + } + if (strcmp((FileList + j)->FvId, (FileList + i)->FvInFd->FvName) == 0){ + OldFileNode = (FileList + j)->OldFile; + NewFileNode = (FileList + j)->NewFile; + while (OldFileNode->Next != NULL && NewFileNode->Next != NULL) { + OldFileNode = OldFileNode->Next; + NewFileNode = NewFileNode->Next; + } + OldFileNode->Next = (FileList + i)->OldFile; + NewFileNode->Next = (FileList + i)->NewFile; + (FileList + i)->FvId = NULL; + } + } + } + + for (i = 0; i < count; i ++){ + if ((FileList + i)->FvId == NULL) { + continue; + } + sortList ((FileList + i)-> OldFile); + sortList ((FileList + i)-> NewFile); + } + TemDir = getcwd (NULL, _MAX_PATH); + if (strlen (TemDir) + strlen(OS_SEP_STR) + strlen (TEMP_DIR_NAME) > _MAX_PATH - 1) { + Error("FMMT", 0, 1001, "The directory is too long.", ""); + return EFI_ABORTED; + } + strncat (TemDir, OS_SEP_STR, _MAX_PATH - strlen(TemDir) - 1); + strncat (TemDir, TEMP_DIR_NAME, _MAX_PATH - strlen(TemDir) - 1); + mkdir(TemDir, S_IRWXU | S_IRWXG | S_IRWXO); + if (FdBuffer == NULL) { + FdBuffer = ReadFileToBuffer(FdInName, &FdSize); + if (FdBuffer == NULL) { + Error("FMMT", 0, 0004, "error while replacing file", "cannot read input file."); + return EFI_ABORTED; + } + } + + for (i = 0; i < count; i ++){ + tmp = FileList + i; + FvId = tmp->FvId; + if (FvId == NULL) { + continue; + } + FdData = tmp->FdData; + FvInFd = tmp->FvInFd; + FvNumInFd = ((UINT8)atoi(FvId + 2) - (UINT8)atoi(FvInFd->FvName + 2)) + 1; + OldFileNode = tmp-> OldFile; + OldFile = OldFileNode -> FileName; + NewFileNode = tmp-> NewFile; + FfsFoundFlag = FindFile(FvInFd, FvNumInFd, OldFile, &Index); + + NewFile = NewFileNode->FileName; + InputFfs = (EFI_FFS_FILE_HEADER2 *)ReadFileToBuffer(NewFile, &NewFileSize); + if (InputFfs == NULL) { + Error("FMMT", 0, 0004, "error while replacing file", "cannot read input file."); + free (FdBuffer); + return EFI_ABORTED; + } + HasUISection = FALSE; + HasUISection = ParseSection(InputFfs); + if (!HasUISection) { + printf ("WARNING: The newly replace file must have a user interface (UI) section, otherwise it cannot be deleted or replaced. \n"); + } + if (FfsFoundFlag && NeedNewPath(FvInFd, FvId, Index, FALSE)) { + do { + OldFile = OldFileNode -> FileName; + NewFile = NewFileNode -> FileName; + FfsFoundFlag = FindFile(FvInFd, FvNumInFd, OldFile, &Index); + // + // TODO: currently only root FV is handled + // + InputFfs = (EFI_FFS_FILE_HEADER2 *)ReadFileToBuffer(NewFile, &NewFileSize); + if (InputFfs == NULL) { + Error("FMMT", 0, 0004, "error while replacing file", "cannot read input file."); + free (FdBuffer); + return EFI_ABORTED; + } + + Offset = FvInFd->ImageAddress + FvInFd->FfsAttuibutes[Index].Offset; + Fv = (EFI_FIRMWARE_VOLUME_HEADER *)(FdBuffer + FvInFd->ImageAddress); + OffsetAdded = FvInFd->FfsAttuibutes[Index].Offset; + + if (!ReplaceFfs(Fv, InputFfs, (EFI_FFS_FILE_HEADER2 *)(FdBuffer + Offset))) { + Status = AddFfs(FdBuffer, FvInFd->ImageAddress, Fv, InputFfs, &OffsetAdded); + if (EFI_ERROR(Status)) { + Error("FMMT", 0, 0003, "error while replacing file", "cannot add ffs"); + goto END; + } + // + // Set original FFS to PAD file + // + CurrentFile = (EFI_FFS_FILE_HEADER2 *)(FdBuffer + FvInFd->ImageAddress + FvInFd->FfsAttuibutes[Index].Offset); + PadFileSize = CalcuFfsSize(Fv, CurrentFile); + AddPadFile(Fv, CurrentFile, PadFileSize); + } + + // + // Calculate base address of Current FV + // + if (InputFfs->Type == EFI_FV_FILETYPE_PEIM || InputFfs->Type == EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE) { + Status = GetBaseAddrFromFsp(FdData, FdBuffer, FvId, &BaseAddr); + if (!EFI_ERROR(Status)) { + mFvHeader = FvInFd->FvHeader; + mFvLength = (UINT32)FvInFd->FvHeader->FvLength; + RebaseFfs(BaseAddr, NewFile, (EFI_FFS_FILE_HEADER *)(FdBuffer + FvInFd->ImageAddress + OffsetAdded), OffsetAdded); + } + else { + Status = GetBaseAddrFromVtf(FdData, FvId, &BaseAddr); + if (!EFI_ERROR(Status)) { + mFvHeader = FvInFd->FvHeader; + mFvLength = (UINT32)FvInFd->FvHeader->FvLength; + RebaseFfs(BaseAddr, NewFile, (EFI_FFS_FILE_HEADER *)(FdBuffer + FvInFd->ImageAddress + OffsetAdded), OffsetAdded); + } + } + } + OldFileNode = OldFileNode -> Next; + NewFileNode = NewFileNode -> Next; + free (InputFfs); + InputFfs = NULL; + } while (OldFileNode != NULL && NewFileNode!= NULL); + } else { + do { + OldFile = OldFileNode->FileName; + NewFile = NewFileNode->FileName; + FfsFoundFlag = FindFile(FvInFd, FvNumInFd, OldFile, &Index); + // + // Replace this FFS file with the new one. + // + if (strlen (NewFile) > _MAX_PATH - 1) { + Error ("FMMT", 0, 2000, "error while replacing file", "New file name is too long!"); + free (FdBuffer); + return EFI_ABORTED; + } + strncpy(FvInFd->FfsAttuibutes[Index].FfsName, NewFile, _MAX_PATH - 1); + FvInFd->FfsAttuibutes[Index].FfsName[_MAX_PATH - 1] = 0; + OldFileNode = OldFileNode->Next; + NewFileNode = NewFileNode->Next; + } while (OldFileNode != NULL && NewFileNode != NULL); + Status = LibEncapNewFvFile (FvInFd, TemDir, NULL, 0, &OutputFileName); + if (EFI_ERROR (Status)) { + Error ("FMMT", 0, 0004, "error while encapsulate FD Image", "Make new FV file failed!"); + free (FdBuffer); + return Status; + } + + NewFvFile = fopen (OutputFileName->FFSName, "rb+"); + if (NewFvFile == NULL) { + Error ("FMMT", 0, 0003, "error Open FV file", "cannot Create a new FD file."); + free (FdBuffer); + return EFI_ABORTED; + } + + fseek(NewFvFile,0,SEEK_SET); + fseek(NewFvFile,0,SEEK_END); + + NewFvLength = ftell(NewFvFile); + fseek(NewFvFile,0,SEEK_SET); + Buffer = malloc ((size_t)NewFvLength); + if (Buffer == NULL) { + fclose(NewFvFile); + free (FdBuffer); + return EFI_ABORTED; + } + + if (fread (Buffer, 1, (size_t) NewFvLength, NewFvFile) != (size_t) NewFvLength) { + Error ("FMMT", 0, 0003, "error reading FV file %s", OutputFileName->FFSName); + free(Buffer); + free (FdBuffer); + fclose(NewFvFile); + return EFI_ABORTED; + } + if (NewFvLength <= FvInFd->FvHeader->FvLength) { + memcpy(FdBuffer+FvInFd->ImageAddress,Buffer,(size_t) NewFvLength); + }else { + Error ("FMMT", 0, 0004, "error writing FD file", "The replace ffs file is too large."); + } + free(Buffer); + fclose(NewFvFile); + } + } + + Status = LibRmDir(TemDir); + if (EFI_ERROR(Status)) { + Error("FMMT", 0, 0004, "error while encapsulate FD Image", "remove directory failed!"); + } + + NewFdFile = fopen(FdOutName, "wb"); + if (NewFdFile == NULL) { + Error("FMMT", 0, 0004, "error while replacing file", "Cannot open target FD file!"); + Status = EFI_ABORTED; + goto END; + } + fwrite(FdBuffer, 1, FdSize, NewFdFile); + fclose(NewFdFile); + free(FdBuffer); + printf("Create New FD file successfully. \n\nDone! \n"); + return EFI_SUCCESS; + + END: + if (FdBuffer != NULL) { + free(FdBuffer); + } + if (InputFfs != NULL) { + free(InputFfs); + } + return EFI_ABORTED; +} + +/** + +The main entry of FMMT. + +@param argc The number of input parameters. +@param *argv[] The array pointer to the parameters. + +@retval 0 The application exited normally. +@retval 1 An error occurred. + +**/ +int main( + int Argc, + char *Argv[] +) +{ + EFI_STATUS Status; + CHAR8 *TemDir; + FILE *CheckFileExist; + CHAR8 *InFilePath; + CHAR8 FullGuidToolDefinition[_MAX_PATH]; + CHAR8 *FileName; + UINTN FileNameIndex; + CHAR8 *PathList; + UINTN EnvLen; + CHAR8 *NewPathList; + Data *FileData; + int index; + int count; + int exist; + int j; + FILENode *p; + FILENode *q; + + p = NULL; + q = NULL; + TemDir = NULL; + CheckFileExist = NULL; + PathList = NULL; + NewPathList = NULL; + EnvLen = 0; + count = 0; + exist = -1; + + TemDir = getcwd (NULL, _MAX_PATH); + if (strlen (TemDir) + strlen(OS_SEP_STR) + strlen (TEMP_DIR_NAME) > _MAX_PATH - 1) { + Error("FMMT", 0, 1001, "The directory is too long.", ""); + return 1; + } + strncat (TemDir, OS_SEP_STR, _MAX_PATH - strlen(TemDir) - 1); + strncat (TemDir, TEMP_DIR_NAME, _MAX_PATH - strlen(TemDir) - 1); + + // + // Print utility header + // + printf ("Intel(R) %s. Version %d.%d, %s. %s.\n", + UTILITY_NAME, + UTILITY_MAJOR_VERSION, + UTILITY_MINOR_VERSION, + __DATE__, + __BUILD_VERSION + ); + + // + // Should have more than 1 arguments. + // + if (Argc <= 1) { + Usage(); + return 1; + } + + // + // Workaroud: the first call to this function + // returns a file name ends with dot + // +#ifndef __GNUC__ + tmpnam (NULL); +#else + CHAR8 tmp[] = "/tmp/fileXXXXXX"; + UINTN Fdtmp; + Fdtmp = mkstemp(tmp); + close(Fdtmp); +#endif + + // + // Save, skip filename arg + // + FileName = Argv[0]; + Argc--; + Argv++; + + // + // Get the same path with the application itself + // + if (strlen (FileName) > _MAX_PATH - 1) { + Error ("FMMT", 0, 2000, "Parameter: The input filename is too long", NULL); + return 1; + } + strncpy (FullGuidToolDefinition, FileName, _MAX_PATH - 1); + FullGuidToolDefinition[_MAX_PATH - 1] = 0; + FileNameIndex = strlen (FullGuidToolDefinition); + while (FileNameIndex != 0) { + FileNameIndex --; + if (FullGuidToolDefinition[FileNameIndex] == OS_SEP) { + FullGuidToolDefinition[FileNameIndex] = 0; + break; + } + } + // + // Build the path list for Config file scan. The priority is below. + // 1. Scan the current path + // 2. Scan the same path with the application itself + // 3. Scan the current %PATH% of OS environment + // 4. Use the build-in default configuration + // + PathList = getenv("PATH"); + if (PathList == NULL) { + Error (NULL, 0, 1001, "Option: Environment variable 'PATH' does not exist", NULL); + return 1; + } + EnvLen = strlen(PathList); + NewPathList = (char *)calloc( + strlen (".") + + strlen (";") + + strlen (FullGuidToolDefinition) + + strlen (";") + + EnvLen + + 1, + sizeof(char) + ); + if (NewPathList == NULL) { + Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL); + PathList = NULL; + free (PathList); + return 1; + } +#ifndef __GNUC__ + sprintf (NewPathList, "%s;%s;%s", ".", FullGuidToolDefinition, PathList); +#else + sprintf (NewPathList, "%s:%s:%s", ".", FullGuidToolDefinition, PathList); +#endif + PathList = NULL; + free (PathList); + + // + // Load Guid Tools definition + // + InFilePath = SearchConfigFromPathList(NewPathList, mGuidToolDefinition); + free (NewPathList); + if (InFilePath != NULL) { + printf ("\nThe Guid Tool Definition comes from the '%s'. \n", InFilePath); + mParsedGuidedSectionTools = ParseGuidedSectionToolsFile (InFilePath); + free (InFilePath); + } else { + // + // Use the pre-defined standard guided tools. + // + printf ("\nThe Guid Tool Definition comes from the build-in default configuration. \n"); + mParsedGuidedSectionTools = LibPreDefinedGuidedTools (); + } + + if ((strcmp(Argv[0], "-v") == 0) || (strcmp(Argv[0], "-V") == 0)) { + // + // View the FD binary image information. + // + if (Argc <= 1) { + Error("FMMT", 0, 1001, "Invalid parameter, Please make sure the parameter is correct.", ""); + Usage (); + return 1; + } + + // + // Open the file containing the FV to check whether it exist or not + // + CheckFileExist = fopen (Argv[1], "rb"); + if (CheckFileExist == NULL) { + Error ("FMMT", 0, 0001, "Error opening the input binary file, Please make sure the exist!", Argv[1]); + return 1; + } + fclose(CheckFileExist); + + Status = FmmtImageView(Argv[1], NULL, TRUE, NULL); + + if (EFI_ERROR (Status)) { + Error("FMMT", 0, 1001, "Error while view the FD image file.", ""); + LibRmDir (TemDir); + return 1; + } + + } else if ((strcmp(Argv[0], "-d") == 0) || (strcmp(Argv[0], "-D") == 0)) { + // + // Delete some named FFS file from FD binary image. + // + if (!((Argc == 4) || ((Argc - 3) % 2 == 0))) { + Error("FMMT", 0, 1001, "Invalid parameter, Please make sure the parameter is correct.", ""); + Usage (); + return 1; + } + + // + // Open the file containing the FV to check whether it exist or not + // + CheckFileExist = fopen (Argv[1], "rb"); + if (CheckFileExist == NULL) { + Error ("FMMT", 0, 0001, "Error opening the input binary file, Please make sure the exist!", Argv[1]); + return 1; + } + fclose(CheckFileExist); + + if ((Argc - 3) % 2 == 0) { + FileData = malloc(sizeof (Data) * (Argc - 3)/2); + if (FileData == NULL) { + Error ("FMMT", 0, 4001, "Resource: Memory can't be allocated", NULL); + return 1; + } + for(index = 0; index < (Argc - 3)/2; index ++) { + p = malloc(sizeof (FILENode)); + if (p == NULL) { + Error ("FMMT", 0, 4001, "Resource: Memory can't be allocated", NULL); + free (FileData); + return 1; + } + p -> FileName = Argv[3 + index * 2]; + p -> SubLevel = 0; + exist = -1; + for (j = 0; j < count; j ++) { + if ((strcmp(Argv[2 + index * 2], (FileData + j) -> FvId) == 0)) { + exist = j; + break; + } + } + if (exist >= 0) { + p -> Next = (FileData + j) -> OldFile; + (FileData + j) -> OldFile = p; + } else { + (FileData + count) -> NewFile = NULL; + (FileData + count) -> FdData = NULL; + (FileData + count) -> FvLevel = 0; + (FileData + count) -> FvInFd = NULL; + (FileData + count) -> FvId = Argv[2 + index * 2];; + (FileData + count) -> OldFile = p; + p -> Next = NULL; + count ++; + } + } + + if (count <= 0) { + Error("FMMT", 0, 0004, "error while parsing FD Image", "Gathering information failed!"); + } + for (index = 0; index < count; index ++) { + for (j = index + 1; j < count; j ++) { + if ((strcmp((FileData + index)->FvId, (FileData + j)->FvId) < 0)) { + CHAR8 *tmp = (FileData + index)->FvId; + FILENode *t = (FileData + index)->OldFile; + (FileData + index)->FvId = (FileData + j)->FvId; + (FileData + index)-> OldFile = (FileData + j)->OldFile; + (FileData + j)-> OldFile = t; + (FileData + j)-> FvId = tmp; + } + } + } + + // + // Delete some FFS file + // + Status = FmmtImageDelete(Argv[1], FileData, count, Argv[Argc-1]); + for (index = 0; index < count; index ++) { + if ((FileData + index) ->NewFile != NULL) { + free ((FileData + index)->NewFile); + (FileData + index)->NewFile = NULL; + } + if ((FileData + index)->OldFile != NULL) { + free ((FileData + index)->OldFile); + (FileData + index)->OldFile = NULL; + } + } + for (index = 0; index < count; index ++) { + if ((FileData + index)->FdData != NULL) { + LibFmmtFreeFd ((FileData + index)->FdData); + } + } + free (FileData); + if (EFI_ERROR (Status)) { + Error("FMMT", 0, 1001, "Error while delete some named ffs file from the FD image file.", ""); + LibRmDir (TemDir); + return 1; + } + } else { + // + // Delete FV + // + Status = FmmtImageDeleteFv(Argv[1], Argv[2], Argv[3]); + if (EFI_ERROR (Status)) { + Error("FMMT", 0, 1001, "Error while delete the entire FV from the FD image file.", ""); + LibRmDir (TemDir); + return 1; + } + } + + } else if ((strcmp(Argv[0], "-a") == 0) || (strcmp(Argv[0], "-A") == 0)) { + // + // Add some named FFS file into FD binary image. + // + if ((Argc - 3 ) % 2 != 0) { + Error("FMMT", 0, 1001, "Invalid parameter, Please make sure the parameter is correct.", ""); + Usage (); + return 1; + } + + // + // Open the file containing the FV to check whether it exist or not + // + CheckFileExist = fopen (Argv[1], "rb"); + if (CheckFileExist == NULL) { + Error ("FMMT", 0, 0001, "Error opening the input binary file, Please make sure the exist!", Argv[1]); + return 1; + } + fclose(CheckFileExist); + + // + // Check whether the new added file exist or not. + // + for (index = 1; index < (Argc - 1) / 2; index ++) { + CheckFileExist = fopen(Argv[2 * index + 1], "rb"); + if (CheckFileExist == NULL) { + Error("FMMT", 0, 0001, "Could not open the new FFS file, Please make sure the new FFS file exist.", Argv[2 * index + 1]); + return 1; + } + fclose(CheckFileExist); + } + + FileData = malloc(sizeof (Data) * (Argc - 3)/2); + if (FileData == NULL) { + Error ("FMMT", 0, 4001, "Resource: Memory can't be allocated", NULL); + return 1; + } + for(index = 0; index < (Argc - 3)/2; index ++) { + p = malloc(sizeof (FILENode)); + if (p == NULL) { + Error ("FMMT", 0, 4001, "Resource: Memory can't be allocated", NULL); + free (FileData); + return 1; + } + p -> FileName = Argv[3 + index * 2]; + p -> SubLevel = 0; + exist = -1; + for (j = 0; j < count; j ++) { + if ((strcmp(Argv[2 + index * 2], (FileData + j) -> FvId) == 0)) { + exist = j; + break; + } + } + if (exist >= 0) { + p -> Next = (FileData + j) -> NewFile; + (FileData + j) -> NewFile = p; + } else { + (FileData + count) -> OldFile = NULL; + (FileData + count) -> FdData = NULL; + (FileData + count) -> FvLevel = 0; + (FileData + count) -> FvInFd = NULL; + (FileData + count) -> FvId = Argv[2 + index * 2]; + (FileData + count) -> NewFile = p; + p -> Next = NULL; + count ++; + } + } + + if (count <= 0) { + Error("FMMT", 0, 0004, "error while parsing FD Image", "Gathering information failed!"); + } + + for (index = 0; index < count; index ++) { + for (j = index + 1; j < count; j ++) { + if ((strcmp((FileData + index)->FvId, (FileData + j)->FvId) < 0)) { + CHAR8 *tmp = (FileData + index)->FvId; + FILENode *temp = (FileData + index)->NewFile; + (FileData + index)->FvId = (FileData + j)->FvId; + (FileData + index)-> NewFile = (FileData + j)->NewFile; + (FileData + j)-> NewFile = temp; + (FileData + j)-> FvId = tmp; + } + } + } + + Status = FmmtImageAdd(Argv[1], FileData, count, Argv[Argc-1]); + for (index = 0; index < count; index ++) { + if ((FileData + index)->NewFile != NULL) { + free ((FileData + index)->NewFile); + (FileData + index)->NewFile = NULL; + } + if ((FileData + index)->OldFile != NULL) { + free ((FileData + index)->OldFile); + (FileData + index)->OldFile = NULL; + } + } + for (index = 0; index < count; index ++) { + if ((FileData + index)->FdData != NULL) { + LibFmmtFreeFd ((FileData + index)->FdData); + } + } + free (FileData); + + if (EFI_ERROR (Status)) { + Error("FMMT", 0, 1001, "Error while add some named ffs file into the FD image file.", ""); + LibRmDir (TemDir); + return 1; + } + + } else if ((strcmp(Argv[0], "-r") == 0) || (strcmp(Argv[0], "-R") == 0)) { + // + // Replace some named FFS file in the FD binary. + // + if ((Argc - 3) % 3 != 0) { + Error("FMMT", 0, 1001, "Invalid parameter, Please make sure the parameter is correct.", ""); + Usage(); + return 1; + } + + // + // Open the file containing the FV to check whether it exist or not + // + CheckFileExist = fopen (Argv[1], "rb"); + if (CheckFileExist == NULL) { + Error ("FMMT", 0, 0001, "Error opening the input binary file, Please make sure the exist!", Argv[1]); + return 1; + } + fclose(CheckFileExist); + + // + // Check whether the new FFS file exist or not. + // + for (index = 1; index < Argc/3; index ++) { + CheckFileExist = fopen(Argv[3 * index + 1], "rb"); + if (CheckFileExist == NULL) { + Error ("FMMT", 0, 0001, "Could not open the new FFS file, Please make sure the new FFS file exist.", Argv[3 * index + 1]); + return 1; + } + fclose(CheckFileExist); + } + + FileData = malloc(sizeof (Data) * (Argc - 3)/3); + if (FileData == NULL) { + Error ("FMMT", 0, 4001, "Resource: Memory can't be allocated", NULL); + return 1; + } + for(index = 0; index < (Argc - 3)/3; index ++) { + p = malloc(sizeof (FILENode)); //p for old file + if (p == NULL) { + Error ("FMMT", 0, 4001, "Resource: Memory can't be allocated", NULL); + free (FileData); + return 1; + } + q = malloc(sizeof (FILENode)); //q for new file + if (q == NULL) { + Error ("FMMT", 0, 4001, "Resource: Memory can't be allocated", NULL); + free (FileData); + free (p); + return 1; + } + p -> FileName = Argv[3 + index * 3]; + q -> FileName = Argv[4 + index * 3]; + p -> SubLevel = 0; + q -> SubLevel = 0; + exist = -1; + for (j = 0; j < count; j ++) { + if ((strcmp(Argv[2 + index * 3], (FileData + j) -> FvId) == 0)) { + exist = j; + break; + } + } + if (exist >= 0) { + p -> Next = (FileData + j) -> OldFile; + (FileData + j) -> OldFile = p; + q -> Next = (FileData + j) -> NewFile; + (FileData + j) -> NewFile = q; + } else { + (FileData + count) -> FdData = NULL; + (FileData + count) -> FvLevel = 0; + (FileData + count) -> FvInFd = NULL; + (FileData + count) -> FvId = Argv[2 + index * 3];; + (FileData + count) -> OldFile = p; + (FileData + count) -> NewFile = q; + p -> Next = NULL; + q -> Next = NULL; + count ++; + } + } + + if (count <= 0) { + Error("FMMT", 0, 0004, "error while parsing FD Image", "Gathering information failed!"); + } + for (index = 0; index < count; index ++) { + for (j = index + 1; j < count; j ++) { + if ((strcmp((FileData + index)->FvId, (FileData + j)->FvId) < 0)) { + CHAR8 *tmp = (FileData + index)->FvId; + FILENode *Old = (FileData + index)->OldFile; + FILENode *New = (FileData + index)->NewFile; + (FileData + index)->FvId = (FileData + j)->FvId; + (FileData + index)->OldFile = (FileData + j)->OldFile; + (FileData + index)->NewFile = (FileData + j)->NewFile; + (FileData + j)->OldFile = Old; + (FileData + j)->NewFile = New; + (FileData + j)->FvId = tmp; + } + } + } + + Status = FmmtImageReplace(Argv[1], FileData, count, Argv[Argc-1]); + for (index = 0; index < count; index ++) { + if ((FileData + index)->NewFile != NULL) { + free ((FileData + index)->NewFile); + (FileData + index)->NewFile = NULL; + } + if ((FileData + index)->OldFile != NULL) { + free ((FileData + index)->OldFile); + (FileData + index)->OldFile = NULL; + } + } + for (index = 0; index < count; index ++) { + if ((FileData + index)->FdData != NULL) { + LibFmmtFreeFd ((FileData + index)->FdData); + } + } + free (FileData); + if (EFI_ERROR (Status)) { + Error("FMMT", 0, 1001, "Error while replace the named ffs file in the FD image file with the new ffs file.", ""); + LibRmDir (TemDir); + return 1; + } + + } else if ((strcmp(Argv[0], "-h") == 0) || (strcmp(Argv[0], "--help") == 0) || + (strcmp(Argv[0], "-?") == 0) || (strcmp(Argv[0], "/?") == 0)) { + // + // print help information to user. + // + Usage(); + + } else { + // + // Invalid parameter. + // + printf("\n"); + Error("FMMT", 0, 1001, "Invalid parameter", Argv[0]); + Usage(); + return 1; + } + + return 0; +} + diff --git a/BaseTools/Source/C/FMMT/FirmwareModuleManagement.h b/BaseTools/Source/C/FMMT/FirmwareModuleManagement.h new file mode 100644 index 0000000000..ec8e3eaba0 --- /dev/null +++ b/BaseTools/Source/C/FMMT/FirmwareModuleManagement.h @@ -0,0 +1,479 @@ +/** @file + + Structures and functions declaration. + + Copyright (c) 2019, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _BIN_FILE_MANAGER_ +#define _BIN_FILE_MANAGER_ + +#include +#include +#include +#ifdef __GNUC__ +#include +#else +#include +#include +#endif +#include +#include +#include +#include +#include + +#include "CommonLib.h" +#include "EfiUtilityMsgs.h" +#include "ParseInf.h" +#include "ParseGuidedSectionTools.h" +#include "StringFuncs.h" +#include "Compress.h" +#include "Decompress.h" + +#ifndef _MAX_PATH +#define _MAX_PATH 500 +#endif + +#if defined(_MSC_VER) && _MSC_VER < 1900 +#define snprintf _snprintf +#endif + +#ifdef __GNUC__ +#define OS_SEP '/' +#define OS_SEP_STR "/" +#define COPY_STR "cp \"%s\" \"%s\" > /dev/null" +#define RMDIR_STR "rm -r \"%s\" > /dev/null" +#define DEL_STR "rm \"%s\" > /dev/null" +#else +#define OS_SEP '\\' +#define OS_SEP_STR "\\" +#define COPY_STR "copy \"%s\" \"%s\" > NUL" +#define RMDIR_STR "rmdir /S /Q \"%s\" > NUL" +#define DEL_STR "del \"%s\" > NUL" +#endif + +#define UTILITY_NAME "Firmware Module Management Tool(FMMT)" +#define UTILITY_SHORT_NAME "FMMT" +#define UTILITY_MAJOR_VERSION 0 +#define UTILITY_MINOR_VERSION 23 +#define MAX_BASENAME_LEN 60 // not good to HardCode, but let's be reasonable +#define EFI_SECTION_ERROR EFIERR (100) +// +// The maximum number of Pad file guid entries. +// +#define MAX_NUMBER_OF_PAD_FILE_GUIDS 1024 + +// +// The maximum number of block map entries supported by the library +// +#define MAX_NUMBER_OF_FV_BLOCKS 100 + + +// +// The maximum number of sections in an FFS file. +// +#define MAX_NUMBER_OF_SECTION_IN_FFS 100 + +// +// The maximum number of files in the FV supported by the library +// +#define MAX_NUMBER_OF_FILES_IN_FV 1000 +#define MAX_NUMBER_OF_FILES_IN_CAP 1000 + + + +/// +/// If present, this must be the first and only opcode, +/// EFI_DEP_BEFORE is only used by DXE driver. +/// +#define EFI_DEP_BEFORE 0x00 + +/// +/// If present, this must be the first and only opcode, +/// EFI_DEP_AFTER is only used by DXE driver. +/// +#define EFI_DEP_AFTER 0x01 + +#define EFI_DEP_PUSH 0x02 +#define EFI_DEP_AND 0x03 +#define EFI_DEP_OR 0x04 +#define EFI_DEP_NOT 0x05 +#define EFI_DEP_TRUE 0x06 +#define EFI_DEP_FALSE 0x07 +#define EFI_DEP_END 0x08 + + +/// +/// If present, this must be the first opcode, +/// EFI_DEP_SOR is only used by DXE driver. +/// +#define EFI_DEP_SOR 0x09 + +// +// INF file strings +// +#define OPTIONS_SECTION_STRING "[options]" +#define ATTRIBUTES_SECTION_STRING "[attributes]" +#define FILES_SECTION_STRING "[files]" +#define FV_BASE_ADDRESS_STRING "[FV_BASE_ADDRESS]" + +// +// Options section +// +#define EFI_FV_BASE_ADDRESS_STRING "EFI_BASE_ADDRESS" +#define EFI_FV_FILE_NAME_STRING "EFI_FILE_NAME" +#define EFI_NUM_BLOCKS_STRING "EFI_NUM_BLOCKS" +#define EFI_BLOCK_SIZE_STRING "EFI_BLOCK_SIZE" +#define EFI_GUID_STRING "EFI_GUID" +#define EFI_FV_FILESYSTEMGUID_STRING "EFI_FV_GUID" +#define EFI_FV_NAMEGUID_STRING "EFI_FVNAME_GUID" +#define EFI_CAPSULE_GUID_STRING "EFI_CAPSULE_GUID" +#define EFI_CAPSULE_HEADER_SIZE_STRING "EFI_CAPSULE_HEADER_SIZE" +#define EFI_CAPSULE_FLAGS_STRING "EFI_CAPSULE_FLAGS" +#define EFI_CAPSULE_VERSION_STRING "EFI_CAPSULE_VERSION" + +#define EFI_FV_TOTAL_SIZE_STRING "EFI_FV_TOTAL_SIZE" +#define EFI_FV_TAKEN_SIZE_STRING "EFI_FV_TAKEN_SIZE" +#define EFI_FV_SPACE_SIZE_STRING "EFI_FV_SPACE_SIZE" + + +typedef UINT32 FMMT_ENCAP_TYPE; + +#define MAX_LEVEL_IN_FV_FILE 32 + +// +// Types of FMMT_ENCAP_TREENODE_TYPE +// +#define FMMT_ENCAP_TREE_FV 0x1 +#define FMMT_ENCAP_TREE_FFS 0x2 +#define FMMT_ENCAP_TREE_GUIDED_SECTION 0x3 +#define FMMT_ENCAP_TREE_COMPRESS_SECTION 0x4 +#define FMMT_ENCAP_TREE_FV_SECTION 0x5 + +extern EFI_HANDLE mParsedGuidedSectionTools; + + +#define TEMP_DIR_NAME "FmmtTemp" + +// +// Structure to keep a list of GUID-To-BaseNames +// +typedef struct _GUID_TO_BASENAME { + struct _GUID_TO_BASENAME *Next; + INT8 Guid[PRINTED_GUID_BUFFER_SIZE]; + INT8 BaseName[MAX_BASENAME_LEN]; +} GUID_TO_BASENAME; + + +typedef struct _GUID_SEC_TOOL_ENTRY { + EFI_GUID Guid; + CHAR8* Name; + CHAR8* Path; + struct _GUID_SEC_TOOL_ENTRY *Next; +} GUID_SEC_TOOL_ENTRY; + + +// +// Private data types +// +// +// Component information +// +typedef struct { + UINTN Size; + CHAR8 ComponentName[_MAX_PATH]; +} COMPONENT_INFO; + +typedef struct { + CHAR8 FfsName[_MAX_PATH]; + + // + // UI Name for this FFS file, if has. + // + CHAR16 UiName[_MAX_PATH]; + UINT32 UiNameSize; + // + // Total section number in this FFS. + // + UINT32 TotalSectionNum; + + // + // Describe the position of the FFS file. + // + UINT8 Level; + // + // If this FFS has no encapsulate section, this flag will set to True. + // + BOOLEAN IsLeaf; + // + // Section type for each section in FFS. + // + EFI_SECTION_TYPE SectionType[MAX_NUMBER_OF_SECTION_IN_FFS]; + // + // Offset relative to current FV + // + UINT32 Offset; + UINT8 FvLevel; + EFI_GUID GuidName; + UINT8 *Depex; + UINT32 DepexLen; + BOOLEAN IsHandle; + BOOLEAN IsFvStart; + BOOLEAN IsFvEnd; +}FFS_ATTRIBUTES; + + +typedef struct __ENCAP_INFO_DATA{ + // + // Now Level + // + UINT8 Level; + + // + // Encapsulate type. + // + FMMT_ENCAP_TYPE Type; + + // + // Data, if it's FV, should be FV header. + // + VOID *Data; + + // + //FvId, match FvId with FvGuidName. + // + UINT8 FvId; + + // + // if FV ExtHeaderOffset not to zero, should also have FvExtHeader information + // + EFI_FIRMWARE_VOLUME_EXT_HEADER *FvExtHeader; + + CHAR16 UiName[_MAX_PATH]; + UINT32 UiNameSize; + UINT8 *Depex; + UINT32 DepexLen; + + // + // Next node. + // + struct __ENCAP_INFO_DATA *NextNode; + + // + // Right node. + // + struct __ENCAP_INFO_DATA *RightNode; +} ENCAP_INFO_DATA; + +typedef struct _FFS_INFOMATION{ + CHAR8 *FFSName; + UINT32 InFvId; + UINT8 ParentLevel; + BOOLEAN IsFFS; + CHAR16 UiName[_MAX_PATH]; + UINT32 UiNameSize; + UINT8 *Depex; + UINT32 DepexLen; + BOOLEAN FfsFoundFlag; + struct _FFS_INFOMATION *Next; +} FFS_INFORMATION; + +// +// FV and capsule information holder +// +typedef struct _FV_INFOMATION{ + EFI_FIRMWARE_VOLUME_HEADER *FvHeader; + EFI_FIRMWARE_VOLUME_EXT_HEADER *FvExtHeader; + UINT32 ImageAddress; + UINT32 FfsNumbers; + CHAR8 FvName[_MAX_PATH]; + EFI_FV_BLOCK_MAP_ENTRY FvBlocks[MAX_NUMBER_OF_FV_BLOCKS]; + FFS_ATTRIBUTES FfsAttuibutes[MAX_NUMBER_OF_FILES_IN_FV]; + EFI_FFS_FILE_HEADER2 FfsHeader[MAX_NUMBER_OF_FILES_IN_FV]; + struct _FV_INFOMATION *FvNext; + ENCAP_INFO_DATA *EncapData; + UINT8 FvLevel; + CHAR8 *FvUiName; + UINT8 MulFvLevel; + CHAR8 AlignmentStr[16]; + FFS_INFORMATION *ChildFvFFS; +} FV_INFORMATION; + +typedef struct _FIRMWARE_DEVICE { + /// + /// Size of FD file + /// + UINT32 Size; + FV_INFORMATION *Fv; +} FIRMWARE_DEVICE; + +typedef struct _FILENode { + CHAR8 *FileName; + UINT8 SubLevel; + struct _FILENode *Next; +} FILENode; + +typedef struct { + CHAR8 *FvId; + FILENode *NewFile; + FILENode *OldFile; + FIRMWARE_DEVICE *FdData; + UINT8 FvLevel; + FV_INFORMATION *FvInFd; +} Data; + +EFI_STATUS +LibFindFvInFd ( + IN FILE *InputFile, + IN OUT FIRMWARE_DEVICE **FdData +); + +/** + + TODO: Add function description + + @param[in] Fv - Firmware Volume to get information from + + @return EFI_STATUS + +**/ +EFI_STATUS +LibGetFvInfo ( + IN VOID *Fv, + IN OUT FV_INFORMATION *CurrentFv, + IN CHAR8 *FvName, + IN UINT8 Level, + IN ENCAP_INFO_DATA **CurrentFvEncapData, + IN UINT32 *FfsCount, + IN OUT UINT8 *FvCount, + IN BOOLEAN ViewFlag, + IN BOOLEAN IsChildFv + ); + +/* + Get size info from FV file. + + @param[in] + @param[out] + + @retval + +*/ +EFI_STATUS +LibGetFvSize ( + IN FILE *InputFile, + OUT UINT32 *FvSize + ); + + /** + + This function returns the next larger size that meets the alignment + requirement specified. + + @param[in] ActualSize The size. + @param[in] Alignment The desired alignment. + + @retval EFI_SUCCESS Function completed successfully. + @retval EFI_ABORTED The function encountered an error. + +**/ +UINT32 +GetOccupiedSize ( + IN UINT32 ActualSize, + IN UINT32 Alignment + ); + +/** + Converts ASCII characters to Unicode. + Assumes that the Unicode characters are only these defined in the ASCII set. + + String - Pointer to string that is written to FILE. + UniString - Pointer to unicode string + + The address to the ASCII string - same as AsciiStr. + +**/ +VOID +LibAscii2Unicode ( + IN CHAR8 *String, + OUT CHAR16 *UniString + ); + +/** + Delete a directory and files in it. + + @param[in] DirName Name of the directory need to be deleted. + + @return EFI_INVALID_PARAMETER + @return EFI_SUCCESS +**/ +EFI_STATUS +LibRmDir ( + IN CHAR8* DirName + ); + +/** + Delete a file. + + @param[in] FileName Name of the file need to be deleted. + + @return EFI_INVALID_PARAMETER + @return EFI_SUCCESS +**/ +EFI_STATUS +LibFmmtDeleteFile( + IN CHAR8 *FileName +); + + +/** + + Free the whole Fd data structure. + + @param[in] Fd The pointer point to the Fd data structure. + +**/ +VOID +LibFmmtFreeFd ( + FIRMWARE_DEVICE *Fd +); + + +EFI_STATUS +LibEncapNewFvFile( + IN FV_INFORMATION *FvInFd, + IN CHAR8 *TemDir, + IN ENCAP_INFO_DATA *CurrentEncapData, + IN UINT32 Level_Break, + OUT FFS_INFORMATION **OutputFile +); + + +EFI_STATUS +LibLocateFvViaFvId ( + IN FIRMWARE_DEVICE *FdData, + IN CHAR8 *FvId, + IN OUT FV_INFORMATION **FvInFd +); + +EFI_HANDLE +LibPreDefinedGuidedTools ( + VOID +); + +EFI_STATUS +FvBufGetSize( +IN VOID *Fv, +OUT UINTN *Size +); + +EFI_STATUS +FvBufFindNextFile( +IN VOID *Fv, +IN OUT UINTN *Key, +OUT VOID **File +); +#endif diff --git a/BaseTools/Source/C/FMMT/FmmtConf.ini b/BaseTools/Source/C/FMMT/FmmtConf.ini new file mode 100644 index 0000000000..36135116b3 --- /dev/null +++ b/BaseTools/Source/C/FMMT/FmmtConf.ini @@ -0,0 +1,6 @@ +a31280ad-481e-41b6-95e8-127f4c984779 TIANO TianoCompress +ee4e5898-3914-4259-9d6e-dc7bd79403cf LZMA LzmaCompress +fc1bcdb0-7d31-49aa-936a-a4600d9dd083 CRC32 GenCrc32 +d42ae6bd-1352-4bfb-909a-ca72a6eae889 LZMAF86 LzmaF86Compress +3d532050-5cda-4fd0-879e-0f7f630d5afb BROTLI BrotliCompress + diff --git a/BaseTools/Source/C/FMMT/FmmtLib.c b/BaseTools/Source/C/FMMT/FmmtLib.c new file mode 100644 index 0000000000..f87042114b --- /dev/null +++ b/BaseTools/Source/C/FMMT/FmmtLib.c @@ -0,0 +1,5051 @@ +/** @file + + Library to parse and generate FV image. + + Copyright (c) 2019, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "FirmwareModuleManagement.h" + +#define EFI_TEST_FFS_ATTRIBUTES_BIT(FvbAttributes, TestAttributes, Bit) \ + ( \ + (BOOLEAN) ( \ + (FvbAttributes & EFI_FVB2_ERASE_POLARITY) ? (((~TestAttributes) & Bit) == Bit) : ((TestAttributes & Bit) == Bit) \ + ) \ + ) + +CHAR8 mFirmwareFileSystem2Guid[16] = {0x78, 0xE5, 0x8C, 0x8C, 0x3D, 0x8A, 0x1C, 0x4F, 0x99, 0x35, 0x89, 0x61, 0x85, 0xC3, 0x2D, 0xD3}; + +CHAR8 mFirmwareFileSystem3Guid[16] = {0x7A, 0xC0, 0x73, 0x54, 0xCB, 0x3D, 0xCA, 0x4D, 0xBD, 0x6F, 0x1E, 0x96, 0x89, 0xE7, 0x34, 0x9A }; + +EFI_GUID mEfiCrc32GuidedSectionExtractionProtocolGuid = EFI_CRC32_GUIDED_SECTION_EXTRACTION_PROTOCOL_GUID; +extern CHAR8* mGuidToolDefinition; + +static CHAR8 *mSectionTypeName[] = { + NULL, // 0x00 - reserved + "EFI_SECTION_COMPRESSION", // 0x01 + "EFI_SECTION_GUID_DEFINED", // 0x02 + NULL, // 0x03 - reserved + NULL, // 0x04 - reserved + NULL, // 0x05 - reserved + NULL, // 0x06 - reserved + NULL, // 0x07 - reserved + NULL, // 0x08 - reserved + NULL, // 0x09 - reserved + NULL, // 0x0A - reserved + NULL, // 0x0B - reserved + NULL, // 0x0C - reserved + NULL, // 0x0D - reserved + NULL, // 0x0E - reserved + NULL, // 0x0F - reserved + "EFI_SECTION_PE32", // 0x10 + "EFI_SECTION_PIC", // 0x11 + "EFI_SECTION_TE", // 0x12 + "EFI_SECTION_DXE_DEPEX", // 0x13 + "EFI_SECTION_VERSION", // 0x14 + "EFI_SECTION_USER_INTERFACE", // 0x15 + "EFI_SECTION_COMPATIBILITY16", // 0x16 + "EFI_SECTION_FIRMWARE_VOLUME_IMAGE", // 0x17 + "EFI_SECTION_FREEFORM_SUBTYPE_GUID", // 0x18 + "EFI_SECTION_RAW", // 0x19 + NULL, // 0x1A + "EFI_SECTION_PEI_DEPEX", // 0x1B + "EFI_SECTION_SMM_DEPEX" // 0x1C +}; + + +static CHAR8 *mFfsFileType[] = { + NULL, // 0x00 + "EFI_FV_FILETYPE_RAW", // 0x01 + "EFI_FV_FILETYPE_FREEFORM", // 0x02 + "EFI_FV_FILETYPE_SECURITY_CORE", // 0x03 + "EFI_FV_FILETYPE_PEI_CORE", // 0x04 + "EFI_FV_FILETYPE_DXE_CORE", // 0x05 + "EFI_FV_FILETYPE_PEIM", // 0x06 + "EFI_FV_FILETYPE_DRIVER", // 0x07 + "EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER", // 0x08 + "EFI_FV_FILETYPE_APPLICATION", // 0x09 + "EFI_FV_FILETYPE_SMM", // 0x0A + "EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE",// 0x0B + "EFI_FV_FILETYPE_COMBINED_SMM_DXE", // 0x0C + "EFI_FV_FILETYPE_SMM_CORE" // 0x0D + }; + +static CHAR8 *mGuidSectionAttr[] = { + "NONE", // 0x00 + "PROCESSING_REQUIRED", // 0x01 + "AUTH_STATUS_VALID" // 0x02 +}; + +static EFI_GUID mFvUiGuid = { + 0xA67DF1FA, 0x8DE8, 0x4E98, { + 0xAF, 0x09, 0x4B, 0xDF, 0x2E, 0xFF, 0xBC, 0x7C + } +}; + + +/** + Generate the unique template filename. +**/ +CHAR8 * +GenTempFile ( + VOID + ) +{ + CHAR8 *TemString; + TemString = NULL; +#ifndef __GNUC__ + TemString = CloneString (tmpnam (NULL)); +#else + CHAR8 tmp[] = "/tmp/fileXXXXXX"; + UINTN Fdtmp; + Fdtmp = mkstemp(tmp); + TemString = CloneString(tmp); + close(Fdtmp); +#endif + return TemString; +} + +static +EFI_STATUS +LibExtractFvUiName(CONST EFI_FIRMWARE_VOLUME_EXT_HEADER *FvExtHeader, CHAR8 **FvUiName) +{ + UINT8 *ExtEnd; + UINT32 ExtDataSize; + EFI_FIRMWARE_VOLUME_EXT_ENTRY *ExtEntry; + EFI_FIRMWARE_VOLUME_EXT_ENTRY_GUID_TYPE *GuidEntry; + + + ExtEnd = (UINT8 *)FvExtHeader + FvExtHeader->ExtHeaderSize; + ExtEntry = (EFI_FIRMWARE_VOLUME_EXT_ENTRY *)(FvExtHeader + 1); + while ((UINT8 *)ExtEntry < ExtEnd) { + // + // GUID type EXT + // + if (ExtEntry->ExtEntryType == 0x0002) { + GuidEntry = (EFI_FIRMWARE_VOLUME_EXT_ENTRY_GUID_TYPE *)ExtEntry; + if (memcmp(&GuidEntry->FormatType, &mFvUiGuid, sizeof(EFI_GUID)) == 0) { + ExtDataSize = ExtEntry->ExtEntrySize - (sizeof(EFI_GUID)+sizeof(*ExtEntry)); + *FvUiName = malloc(ExtDataSize + 1); + if (*FvUiName != NULL) { + memcpy(*FvUiName, (UINT8 *)GuidEntry + sizeof(EFI_GUID)+sizeof(*ExtEntry), ExtDataSize); + (*FvUiName)[ExtDataSize] = '\0'; + return EFI_SUCCESS; + } + } + } + + ExtEntry = (EFI_FIRMWARE_VOLUME_EXT_ENTRY *)((UINT8 *)ExtEntry + ExtEntry->ExtEntrySize); + } + return EFI_NOT_FOUND; +} + +FV_INFORMATION * +LibInitializeFvStruct ( + FV_INFORMATION *Fv +) +{ + UINT32 Index; + + if (Fv == NULL) { + return NULL; + } + + for (Index = 0; Index < MAX_NUMBER_OF_FILES_IN_FV; Index ++) { + memset (Fv->FfsAttuibutes[Index].FfsName, '\0', _MAX_PATH); + memset (Fv->FfsAttuibutes[Index].UiName, '\0', _MAX_PATH); + memset (&Fv->FfsAttuibutes[Index].GuidName, '\0', sizeof(EFI_GUID)); + Fv->FfsAttuibutes[Index].UiNameSize = 0; + Fv->FfsAttuibutes[Index].IsLeaf = TRUE; + Fv->FfsAttuibutes[Index].Level = 0xFF; + Fv->FfsAttuibutes[Index].TotalSectionNum = 0; + Fv->FfsAttuibutes[Index].Depex = NULL; + Fv->FfsAttuibutes[Index].DepexLen = 0; + Fv->FfsAttuibutes[Index].IsHandle = FALSE; + Fv->FfsAttuibutes[Index].IsFvStart = FALSE; + Fv->FfsAttuibutes[Index].IsFvEnd = FALSE; + } + + Fv->EncapData = NULL; + Fv->FvNext = NULL; + Fv->ChildFvFFS = NULL; + Fv->FvLevel = 0; + Fv->MulFvLevel = 1; + strcpy(Fv->AlignmentStr,"8"); + return Fv; +} + + +EFI_STATUS +LibFindFvInFd ( + IN FILE *InputFile, + IN OUT FIRMWARE_DEVICE **FdData +) +{ + FIRMWARE_DEVICE *LocalFdData; + UINT16 Index; + CHAR8 Ffs2Guid[16]; + CHAR8 SignatureCheck[5] = ""; + CHAR8 Signature[5] = "_FVH"; + FV_INFORMATION *CurrentFv; + FV_INFORMATION *NewFoundFv; + BOOLEAN FirstMatch; + UINT32 FdSize; + UINT16 FvCount; + UINT8 *FdBuffer; + UINT8 *FdBufferEnd; + UINT8 *FdBufferOri; + EFI_FIRMWARE_VOLUME_HEADER *FvHeader; + + CurrentFv = NULL; + NewFoundFv = NULL; + FdBuffer = NULL; + FdBufferOri = NULL; + FirstMatch = TRUE; + Index = 0; + FdSize = 0; + FvCount = 0; + LocalFdData = NULL; + + if (InputFile == NULL) { + Error ("FMMT", 0, 0001, "Error opening the input file", ""); + return EFI_ABORTED; + } + + // + // Find each FVs in the FD + // + + fseek(InputFile,0,SEEK_SET); + fseek(InputFile,0,SEEK_END); + + FdSize = ftell(InputFile); + + fseek(InputFile,0,SEEK_SET); + // + // Create an FD structure to store useful information. + // + LocalFdData = (FIRMWARE_DEVICE *) malloc (sizeof (FIRMWARE_DEVICE)); + if (LocalFdData == NULL) { + Error ("FMMT", 0, 0002, "Error searching FVs in the input fd", "Allocate memory error"); + return EFI_OUT_OF_RESOURCES; + } + LocalFdData->Fv = (FV_INFORMATION *) malloc (sizeof (FV_INFORMATION)); + if (LocalFdData->Fv == NULL) { + Error ("FMMT", 0, 0002, "Error searching FVs in the input fd", "Allocate memory error"); + free (LocalFdData); + return EFI_OUT_OF_RESOURCES; + } + + LibInitializeFvStruct (LocalFdData->Fv); + + // + // Readout the FD file data to buffer. + // + FdBuffer = malloc (FdSize); + + if (FdBuffer == NULL) { + Error ("FMMT", 0, 0002, "Error searching FVs in the input fd", "Allocate memory error"); + free (LocalFdData->Fv); + free (LocalFdData); + return EFI_OUT_OF_RESOURCES; + } + + if (fread (FdBuffer, 1, FdSize, InputFile) != FdSize) { + Error ("FMMT", 0, 0002, "Error searching FVs in the input fd", "Read FD file error!"); + free (LocalFdData->Fv); + free (LocalFdData); + free (FdBuffer); + return EFI_ABORTED; + } + + FdBufferOri = FdBuffer; + FdBufferEnd = FdBuffer + FdSize; + + while (FdBuffer <= FdBufferEnd - sizeof (EFI_FIRMWARE_VOLUME_HEADER)) { + FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *) FdBuffer; + // + // Copy 4 bytes of fd data to check the _FVH signature + // + memcpy (SignatureCheck, &FvHeader->Signature, 4); + + if (strncmp(SignatureCheck, Signature, 4) == 0){ + // + // Still need to determine the FileSystemGuid in EFI_FIRMWARE_VOLUME_HEADER equal to + // EFI_FIRMWARE_FILE_SYSTEM2_GUID or EFI_FIRMWARE_FILE_SYSTEM3_GUID. + // Turn back 28 bytes to find the GUID. + // + memcpy (Ffs2Guid, &FvHeader->FileSystemGuid, 16); + + // + // Compare GUID. + // + for (Index = 0; Index < 16; Index ++) { + if (Ffs2Guid[Index] != mFirmwareFileSystem2Guid[Index]) { + break; + } + } + if (Index != 16) { + for (Index = 0; Index < 16; Index ++) { + if (Ffs2Guid[Index] != mFirmwareFileSystem3Guid[Index]) { + break; + } + } + } + + // + // Here we found an FV. + // + if ((Index == 16) && ((FdBuffer + FvHeader->FvLength) <= FdBufferEnd)) { + if (FirstMatch) { + LocalFdData->Fv->ImageAddress = (UINTN)((UINT8 *)FdBuffer - (UINT8 *)FdBufferOri); + CurrentFv = LocalFdData->Fv; + CurrentFv->FvNext = NULL; + // + // Store the FV name by found sequence + // + sprintf(CurrentFv->FvName, "FV%d", FvCount); + + FirstMatch = FALSE; + } else { + NewFoundFv = (FV_INFORMATION *) malloc (sizeof (FV_INFORMATION)); + if (NewFoundFv == NULL) { + Error ("FMMT", 0, 0002, "Error searching FVs in the input fd", "Allocate memory error"); + free (LocalFdData->Fv); + free (LocalFdData); + free (FdBuffer); + return EFI_OUT_OF_RESOURCES; + } + + LibInitializeFvStruct (NewFoundFv); + + // + // Need to turn back 0x2c bytes + // + NewFoundFv->ImageAddress = (UINTN)((UINT8 *)FdBuffer - (UINT8 *)FdBufferOri); + + // + // Store the FV name by found sequence + // + sprintf(NewFoundFv->FvName, "FV%d", FvCount); + + // + // Value it to NULL for found FV usage. + // + NewFoundFv->FvNext = NULL; + CurrentFv->FvNext = NewFoundFv; + + // + // Make the CurrentFv point to next FV. + // + CurrentFv = CurrentFv->FvNext; + } + + FvCount ++; + FdBuffer = FdBuffer + FvHeader->FvLength; + } else { + FdBuffer ++; + } + + } else { + FdBuffer ++; + } + } + + LocalFdData->Size = FdSize; + + *FdData = LocalFdData; + + free (FdBufferOri); + + return EFI_SUCCESS; +} + +UINTN +GetFreeOffset ( + IN VOID *InputFv +) +{ + UINTN FreeOffset; + UINTN Offset; + EFI_STATUS Status; + EFI_FFS_FILE_HEADER2 *CurrentFile; + + Offset = 0; + CurrentFile = NULL; + FreeOffset = 0; + do { + FreeOffset = (UINTN)ALIGN_POINTER(Offset, 8); + Status = FvBufFindNextFile(InputFv, &Offset, (VOID **)&CurrentFile); + if (Status == EFI_NOT_FOUND) { + CurrentFile = NULL; + break; + } + else if (EFI_ERROR(Status)) { + return Status; + } + } while (CurrentFile != NULL); + + return FreeOffset; +} + +/* + Construct a set of blank chars based on the number. + + @param[in] Count The number of blank chars. + + @return A string contained the blank chars. + +*/ +CHAR8 * +LibConstructBlankChar ( + IN UINT8 Count +) +{ + CHAR8 *RetStr; + UINT8 Index; + + Index = 0; + RetStr = NULL; + + RetStr = (CHAR8 *) malloc (Count +1); + + if (RetStr == NULL) { + Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL); + return NULL; + } + + memset (RetStr , '\0', Count + 1); + + for (Index=0; Index <= Count -1; Index ++) { + RetStr[Index] = ' '; + } + + return RetStr; + +} + +/** + + This function determines the size of the FV and the erase polarity. The + erase polarity is the FALSE value for file state. + + + @param[in ] InputFile The file that contains the FV image. + @param[out] FvSize The size of the FV. + @param[out] ErasePolarity The FV erase polarity. + + @return EFI_SUCCESS Function completed successfully. + @return EFI_INVALID_PARAMETER A required parameter was NULL or is out of range. + @return EFI_ABORTED The function encountered an error. + +**/ +EFI_STATUS +LibReadFvHeader ( + IN VOID *InputFv, + IN BOOLEAN ViewFlag, + IN UINT8 FvLevel, + IN UINT8 FvCount, + IN CHAR8 *FvName + ) +{ + EFI_FIRMWARE_VOLUME_HEADER *VolumeHeader; + CHAR8 *BlankSpace; + CHAR8 *FvUiName; + EFI_FIRMWARE_VOLUME_EXT_HEADER *FvExtHeader; + + BlankSpace = NULL; + FvUiName = NULL; + + // + // Check input parameters + // + if (InputFv == NULL) { + Error (__FILE__, __LINE__, 0, "FMMT application error", "invalid parameter to function"); + return EFI_INVALID_PARAMETER; + } + + // + // Read the header + // + VolumeHeader = (EFI_FIRMWARE_VOLUME_HEADER *) InputFv; + + + BlankSpace = LibConstructBlankChar((FvLevel)*2); + + if (BlankSpace == NULL) { + Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL); + return EFI_OUT_OF_RESOURCES; + } + + + if (ViewFlag) { + if ((FvLevel -1) == 0) { + printf ("\n%s :\n", FvName); + } else { + printf ("%sChild FV named FV%d of %s\n", BlankSpace, FvCount, FvName); + } + } + + // + // Print FV header information + // + if (ViewFlag) { + printf ("\n%sAttributes: %X\n", BlankSpace, (unsigned) VolumeHeader->Attributes); + printf ("%sTotal Volume Size: 0x%08X\n", BlankSpace, (unsigned) VolumeHeader->FvLength); + printf ("%sFree Volume Size: 0x%08X\n", BlankSpace, (unsigned) (VolumeHeader->FvLength - GetFreeOffset(InputFv))); + } + + if (ViewFlag && VolumeHeader->ExtHeaderOffset != 0) { + FvExtHeader = (EFI_FIRMWARE_VOLUME_EXT_HEADER *)((UINT8 *)VolumeHeader + VolumeHeader->ExtHeaderOffset); + printf("%sFvNameGuid: %08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X\n", + BlankSpace, + FvExtHeader->FvName.Data1, + FvExtHeader->FvName.Data2, + FvExtHeader->FvName.Data3, + FvExtHeader->FvName.Data4[0], + FvExtHeader->FvName.Data4[1], + FvExtHeader->FvName.Data4[2], + FvExtHeader->FvName.Data4[3], + FvExtHeader->FvName.Data4[4], + FvExtHeader->FvName.Data4[5], + FvExtHeader->FvName.Data4[6], + FvExtHeader->FvName.Data4[7]); + LibExtractFvUiName(FvExtHeader, &FvUiName); + if (FvUiName != NULL && FvLevel == 1) { + printf("%sFV UI Name: %s\n\n", BlankSpace, FvUiName); + } + free(FvUiName); + } + free (BlankSpace); + return EFI_SUCCESS; +} + +/* + Get size info from FV file. + + @param[in] + @param[out] + + @retval + +*/ +EFI_STATUS +LibGetFvSize ( + IN FILE *InputFile, + OUT UINT32 *FvSize + ) +{ + + UINTN BytesRead; + UINT32 Size; + EFI_FV_BLOCK_MAP_ENTRY BlockMap; + + BytesRead = 0; + Size = 0; + + if (InputFile == NULL || FvSize == NULL) { + Error (__FILE__, __LINE__, 0, "FMMT application error", "invalid parameter to function"); + return EFI_INVALID_PARAMETER; + } + + fseek (InputFile, sizeof (EFI_FIRMWARE_VOLUME_HEADER) - sizeof (EFI_FV_BLOCK_MAP_ENTRY), SEEK_CUR); + do { + fread (&BlockMap, sizeof (EFI_FV_BLOCK_MAP_ENTRY), 1, InputFile); + BytesRead += sizeof (EFI_FV_BLOCK_MAP_ENTRY); + + if (BlockMap.NumBlocks != 0) { + Size += BlockMap.NumBlocks * BlockMap.Length; + } + } while (!(BlockMap.NumBlocks == 0 && BlockMap.Length == 0)); + + + *FvSize = Size; + + return EFI_SUCCESS; +} + +/** + + Clears out all files from the Fv buffer in memory + + @param[in] Fv - Address of the Fv in memory + + @return EFI_STATUS + +**/ +EFI_STATUS +FvBufGetSize ( + IN VOID *Fv, + OUT UINTN *Size + ) +{ + EFI_FIRMWARE_VOLUME_HEADER *hdr; + EFI_FV_BLOCK_MAP_ENTRY *blk; + + *Size = 0; + hdr = (EFI_FIRMWARE_VOLUME_HEADER*)Fv; + blk = hdr->BlockMap; + + while (blk->Length != 0 || blk->NumBlocks != 0) { + *Size = *Size + (blk->Length * blk->NumBlocks); + if (*Size >= 0x40000000) { + // + // If size is greater than 1GB, then assume it is corrupted + // + return EFI_VOLUME_CORRUPTED; + } + blk++; + } + + if (*Size == 0) { + // + // If size is 0, then assume the volume is corrupted + // + return EFI_VOLUME_CORRUPTED; + } + + return EFI_SUCCESS; +} + +/* + Generate the leaf FFS files. + +*/ +EFI_STATUS +LibGenFfsFile ( + EFI_FFS_FILE_HEADER2 *CurrentFile, + FV_INFORMATION *CurrentFv, + CHAR8 *FvName, + UINT8 Level, + UINT32 *FfsCount, + BOOLEAN ErasePolarity +) +{ + UINT32 FfsFileSize; + CHAR8 *FfsFileName; + FILE *FfsFile; + CHAR8 *TempDir; + + + FfsFileSize = 0; + FfsFileName = NULL; + FfsFile = NULL; + TempDir = NULL; + + TempDir = getcwd (NULL, _MAX_PATH); + if (strlen (TempDir) + strlen(OS_SEP_STR) + strlen (TEMP_DIR_NAME) > _MAX_PATH - 1) { + Error("FMMT", 0, 1001, "The directory is too long.", ""); + return EFI_ABORTED; + } + strncat (TempDir, OS_SEP_STR, _MAX_PATH - strlen(TempDir) - 1); + strncat (TempDir, TEMP_DIR_NAME, _MAX_PATH - strlen(TempDir) - 1); + + mkdir(TempDir, S_IRWXU | S_IRWXG | S_IRWXO); + + FfsFileName = (CHAR8 *) malloc (_MAX_PATH); + if (FfsFileName == NULL) { + Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL); + return EFI_ABORTED; + } + memset (FfsFileName, '\0', _MAX_PATH); + FfsFileSize = GetFfsFileLength ((EFI_FFS_FILE_HEADER *) CurrentFile); + sprintf ( + (CHAR8 *)FfsFileName, + "%s%cNum%d-%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X-Level%d", + TempDir, + OS_SEP, + *FfsCount, + (unsigned) CurrentFile->Name.Data1, + CurrentFile->Name.Data2, + CurrentFile->Name.Data3, + CurrentFile->Name.Data4[0], + CurrentFile->Name.Data4[1], + CurrentFile->Name.Data4[2], + CurrentFile->Name.Data4[3], + CurrentFile->Name.Data4[4], + CurrentFile->Name.Data4[5], + CurrentFile->Name.Data4[6], + CurrentFile->Name.Data4[7], + Level + ); + + memcpy (CurrentFv->FfsAttuibutes[*FfsCount].FfsName, FfsFileName, strlen(FfsFileName)); + memcpy (&CurrentFv->FfsAttuibutes[*FfsCount].GuidName, &CurrentFile->Name, sizeof(EFI_GUID)); + // + // Update current FFS files file state. + // + if (ErasePolarity) { + CurrentFile->State = (UINT8)~(CurrentFile->State); + } + + FfsFile = fopen (FfsFileName, "wb+"); + if (FfsFile == NULL) { + Error ("FMMT", 0, 0003, "error writing FFS file", "cannot Create a new ffs file."); + free(FfsFileName); + return EFI_ABORTED; + } + + if (fwrite (CurrentFile, 1, FfsFileSize, FfsFile) != FfsFileSize) { + Error ("FMMT", 0, 0004, "error writing FFS file", "cannot Create a new ffs file."); + fclose(FfsFile); + free(FfsFileName); + return EFI_ABORTED; + } + + fclose(FfsFile); + free(FfsFileName); + FfsFileName = NULL; + + CurrentFv->FfsNumbers = *FfsCount; + + *FfsCount += 1; + + if (ErasePolarity) { + CurrentFile->State = (UINT8)~(CurrentFile->State); + } + + return EFI_SUCCESS; +} + +VOID +Unicode2AsciiString ( + IN CHAR16 *Source, + OUT CHAR8 *Destination + ) + /*++ + + Routine Description: + + Convert a null-terminated unicode string to a null-terminated ascii string. + + Arguments: + + Source - The pointer to the null-terminated input unicode string. + Destination - The pointer to the null-terminated output ascii string. + + Returns: + + N/A + + --*/ +{ + while (*Source != '\0') { + *(Destination++) = (CHAR8) *(Source++); + } + // + // End the ascii with a NULL. + // + *Destination = '\0'; +} + + +/** + + Parses EFI Sections, if the view flag turn on, then will collect FFS section information + and extract FFS files. + + @param[in] SectionBuffer - Buffer containing the section to parse. + @param[in] BufferLength - Length of SectionBuffer + @param[in, out] CurrentFv + @param[in] FvName + @param[in] CurrentFile + @param[in] Level + @param[in, out] FfsCount + @param[in] ViewFlag + @param[in] ErasePolarity + + @retval EFI_SECTION_ERROR - Problem with section parsing. + (a) compression errors + (b) unrecognized section + @retval EFI_UNSUPPORTED - Do not know how to parse the section. + @retval EFI_SUCCESS - Section successfully parsed. + @retval EFI_OUT_OF_RESOURCES - Memory allocation failed. + +--*/ +EFI_STATUS +LibParseSection ( + UINT8 *SectionBuffer, + UINT32 BufferLength, + FV_INFORMATION *CurrentFv, + CHAR8 *FvName, + EFI_FFS_FILE_HEADER2 *CurrentFile, + UINT8 Level, + ENCAP_INFO_DATA **CurrentFvEncapData, + UINT8 FfsLevel, + UINT32 *FfsCount, + UINT8 *FvCount, + BOOLEAN ViewFlag, + BOOLEAN ErasePolarity, + BOOLEAN *IsFfsGenerated + ) +{ + UINT32 ParsedLength; + UINT8 *Ptr; + UINT32 SectionLength; + UINT32 UiSectionLength; + EFI_SECTION_TYPE Type; + EFI_STATUS Status; + CHAR8 *ExtractionTool; + CHAR8 *ToolInputFile; + CHAR8 *ToolOutputFile; + CHAR8 *SystemCommandFormatString; + CHAR8 *SystemCommand; + UINT8 *ToolOutputBuffer; + UINT32 ToolOutputLength; + CHAR16 *UIName; + UINT32 UINameSize; + BOOLEAN HasDepexSection; + UINT32 NumberOfSections; + ENCAP_INFO_DATA *LocalEncapData; + ENCAP_INFO_DATA *LocalEncapDataTemp; + CHAR8 *BlankChar; + UINT8 *UncompressedBuffer; + UINT32 UncompressedLength; + UINT8 *CompressedBuffer; + UINT32 CompressedLength; + UINT8 CompressionType; + DECOMPRESS_FUNCTION DecompressFunction; + GETINFO_FUNCTION GetInfoFunction; + UINT32 DstSize; + UINT32 ScratchSize; + UINT8 *ScratchBuffer; + BOOLEAN EncapDataNeedUpdata; + CHAR8 *TempDir; + CHAR8 *ToolInputFileFullName; + CHAR8 *ToolOutputFileFullName; + UINT8 LargeHeaderOffset; + UINT16 GuidAttr; + UINT16 DataOffset; + CHAR8 *UIFileName; + CHAR8 *ToolInputFileName; + CHAR8 *ToolOutputFileName; + + DataOffset = 0; + GuidAttr = 0; + ParsedLength = 0; + ToolOutputLength = 0; + UINameSize = 0; + NumberOfSections = 0; + UncompressedLength = 0; + CompressedLength = 0; + CompressionType = 0; + DstSize = 0; + ScratchSize = 0; + Ptr = NULL; + ExtractionTool = NULL; + ToolInputFile = NULL; + ToolOutputFile = NULL; + SystemCommand = NULL; + SystemCommandFormatString = NULL; + ToolOutputBuffer = NULL; + UIName = NULL; + LocalEncapData = NULL; + LocalEncapDataTemp = NULL; + BlankChar = NULL; + UncompressedBuffer = NULL; + CompressedBuffer = NULL; + ScratchBuffer = NULL; + TempDir = NULL; + ToolInputFileFullName = NULL; + ToolOutputFileFullName = NULL; + ToolInputFileName = NULL; + ToolOutputFileFullName = NULL; + HasDepexSection = FALSE; + EncapDataNeedUpdata = TRUE; + LargeHeaderOffset = 0; + + + while (ParsedLength < BufferLength) { + Ptr = SectionBuffer + ParsedLength; + + SectionLength = GetLength (((EFI_COMMON_SECTION_HEADER *) Ptr)->Size); + Type = ((EFI_COMMON_SECTION_HEADER *) Ptr)->Type; + + // + // This is sort of an odd check, but is necessary because FFS files are + // padded to a QWORD boundary, meaning there is potentially a whole section + // header worth of 0xFF bytes. + // + if (SectionLength == 0xffffff && Type == 0xff) { + ParsedLength += 4; + continue; + } + // + //If Size is 0xFFFFFF then ExtendedSize contains the size of the section. + // + if (SectionLength == 0xffffff) { + SectionLength = ((EFI_COMMON_SECTION_HEADER2 *) Ptr)->ExtendedSize; + LargeHeaderOffset = sizeof (EFI_COMMON_SECTION_HEADER2) - sizeof (EFI_COMMON_SECTION_HEADER); + } + + switch (Type) { + + case EFI_SECTION_FIRMWARE_VOLUME_IMAGE: + + EncapDataNeedUpdata = TRUE; + + Level ++; + NumberOfSections ++; + + CurrentFv->FfsAttuibutes[*FfsCount].IsLeaf = FALSE; + CurrentFv->FfsAttuibutes[*FfsCount].IsFvStart = TRUE; + // + // Put in encapsulate data information. + // + LocalEncapData = *CurrentFvEncapData; + if (LocalEncapData->NextNode != NULL) { + LocalEncapData = LocalEncapData->NextNode; + while (LocalEncapData->RightNode != NULL) { + LocalEncapData = LocalEncapData->RightNode; + } + } + + if (EncapDataNeedUpdata) { + // + // Put in this is an FFS with FV section + // + + // + // Construct the new ENCAP_DATA + // + LocalEncapData->NextNode = (ENCAP_INFO_DATA *) malloc (sizeof (ENCAP_INFO_DATA)); + + if (LocalEncapData->NextNode == NULL) { + Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL); + return EFI_ABORTED; + } + + LocalEncapData = LocalEncapData->NextNode; + + LocalEncapData->Level = Level; + LocalEncapData->Type = FMMT_ENCAP_TREE_FV_SECTION; + + // + // We don't need additional data for encapsulate this FFS but type. + // + LocalEncapData->Data = NULL; + LocalEncapData->FvExtHeader = NULL; + LocalEncapData->NextNode = NULL; + LocalEncapData->RightNode = NULL; + LocalEncapData->Depex = NULL; + LocalEncapData->DepexLen = 0; + LocalEncapData->UiNameSize = 0; + LocalEncapData->FvId = *FvCount; + } + + // + //save parent level FFS file's GUID name + // + LocalEncapDataTemp = CurrentFv->EncapData; + while (LocalEncapDataTemp->NextNode != NULL) { + if (LocalEncapDataTemp->Level == FfsLevel) { + while (LocalEncapDataTemp->RightNode != NULL) { + LocalEncapDataTemp = LocalEncapDataTemp->RightNode; + } + if (LocalEncapDataTemp != NULL && LocalEncapDataTemp->FvExtHeader == NULL) { + LocalEncapDataTemp->FvExtHeader = (EFI_FIRMWARE_VOLUME_EXT_HEADER *)malloc(sizeof(EFI_FIRMWARE_VOLUME_EXT_HEADER)); + if (LocalEncapDataTemp->FvExtHeader == NULL) { + Error(NULL, 0, 4001, "Resource: Memory can't be allocated", NULL); + return EFI_ABORTED; + } + + if (*FfsCount >= 1) { + if ((memcmp(&CurrentFv->FfsAttuibutes[*FfsCount - 1].GuidName, &(LocalEncapDataTemp->FvExtHeader->FvName), sizeof(EFI_GUID)) == 0)) { + memcpy(LocalEncapDataTemp->UiName, CurrentFv->FfsAttuibutes[*FfsCount - 1].UiName, _MAX_PATH); + LocalEncapDataTemp->UiNameSize = CurrentFv->FfsAttuibutes[*FfsCount - 1].UiNameSize; + LocalEncapDataTemp->DepexLen = CurrentFv->FfsAttuibutes[*FfsCount - 1].DepexLen; + LocalEncapDataTemp->Depex = malloc (LocalEncapDataTemp->DepexLen); + if (LocalEncapDataTemp->Depex == NULL) { + Error(NULL, 0, 4001, "Resource: Memory can't be allocated", NULL); + return EFI_ABORTED; + } + memcpy(LocalEncapDataTemp->Depex, CurrentFv->FfsAttuibutes[*FfsCount - 1].Depex, LocalEncapDataTemp->DepexLen); + } + } + } + break; + } + LocalEncapDataTemp = LocalEncapDataTemp->NextNode; + } + + Status = LibGetFvInfo ((UINT8*)((EFI_FIRMWARE_VOLUME_IMAGE_SECTION*)Ptr + 1) + LargeHeaderOffset, CurrentFv, FvName, Level, &LocalEncapData, FfsCount, FvCount, ViewFlag, TRUE); + if (EFI_ERROR (Status)) { + Error ("FMMT", 0, 0003, "printing of FV section contents failed", NULL); + return EFI_SECTION_ERROR; + } + if (*FfsCount >= 1) { + CurrentFv->FfsAttuibutes[*FfsCount -1].IsFvEnd = TRUE; + } + break; + + case EFI_SECTION_COMPRESSION: + Level ++; + NumberOfSections ++; + + EncapDataNeedUpdata = TRUE; + // + // Put in encapsulate data information. + // + LocalEncapData = *CurrentFvEncapData; + if (LocalEncapData->NextNode != NULL) { + EncapDataNeedUpdata = FALSE; + while (LocalEncapData->RightNode != NULL) { + LocalEncapData = LocalEncapData->RightNode; + } + } + + if (EncapDataNeedUpdata) { + // + // Put in this is an FFS with FV section + // + + // + // Construct the new ENCAP_DATA + // + LocalEncapData->NextNode = (ENCAP_INFO_DATA *) malloc (sizeof (ENCAP_INFO_DATA)); + + if (LocalEncapData->NextNode == NULL) { + Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL); + return EFI_ABORTED; + } + + LocalEncapData = LocalEncapData->NextNode; + + LocalEncapData->Level = Level; + LocalEncapData->Type = FMMT_ENCAP_TREE_COMPRESS_SECTION; + + // + // Store the compress type + // + LocalEncapData->Data = malloc (sizeof (UINT8)); + + if (LocalEncapData->Data == NULL) { + Error ("FMMT", 0, 0003, "Allocate memory failed", NULL); + return EFI_OUT_OF_RESOURCES; + } + + *(UINT8 *)LocalEncapData->Data = ((EFI_COMPRESSION_SECTION *) (Ptr + LargeHeaderOffset))->CompressionType; + LocalEncapData->FvExtHeader = NULL; + LocalEncapData->NextNode = NULL; + LocalEncapData->RightNode = NULL; + } else { + LocalEncapData->RightNode = (ENCAP_INFO_DATA *) malloc (sizeof (ENCAP_INFO_DATA)); + if (LocalEncapData->RightNode == NULL) { + Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL); + return EFI_ABORTED; + } + LocalEncapData = LocalEncapData->RightNode; + + LocalEncapData->Level = Level; + LocalEncapData->Type = FMMT_ENCAP_TREE_COMPRESS_SECTION; + + // + // Store the compress type + // + LocalEncapData->Data = malloc (sizeof (UINT8)); + + if (LocalEncapData->Data == NULL) { + Error ("FMMT", 0, 0003, "Allocate memory failed", NULL); + return EFI_OUT_OF_RESOURCES; + } + + *(UINT8 *)LocalEncapData->Data = ((EFI_COMPRESSION_SECTION *) (Ptr + LargeHeaderOffset))->CompressionType; + LocalEncapData->FvExtHeader = NULL; + LocalEncapData->NextNode = NULL; + LocalEncapData->RightNode = NULL; + + } + + // + // Process compressed section + // + CurrentFv->FfsAttuibutes[*FfsCount].IsLeaf = FALSE; + + UncompressedBuffer = NULL; + CompressedLength = SectionLength - sizeof (EFI_COMPRESSION_SECTION) - LargeHeaderOffset; + UncompressedLength = ((EFI_COMPRESSION_SECTION *) (Ptr + LargeHeaderOffset))->UncompressedLength; + CompressionType = ((EFI_COMPRESSION_SECTION *) (Ptr + LargeHeaderOffset))->CompressionType; + + if (CompressionType == EFI_NOT_COMPRESSED) { + //printf (" Compression Type: EFI_NOT_COMPRESSED\n"); + if (CompressedLength != UncompressedLength) { + Error ("FMMT", 0, 0, "file is not compressed, but the compressed length does not match the uncompressed length", NULL); + return EFI_SECTION_ERROR; + } + + UncompressedBuffer = Ptr + sizeof (EFI_COMPRESSION_SECTION) + LargeHeaderOffset; + } else if (CompressionType == EFI_STANDARD_COMPRESSION) { + GetInfoFunction = EfiGetInfo; + DecompressFunction = EfiDecompress; + + CompressedBuffer = Ptr + sizeof (EFI_COMPRESSION_SECTION) + LargeHeaderOffset; + + Status = GetInfoFunction (CompressedBuffer, CompressedLength, &DstSize, &ScratchSize); + if (EFI_ERROR (Status)) { + Error ("FMMT", 0, 0003, "error getting compression info from compression section", NULL); + return EFI_SECTION_ERROR; + } + + if (DstSize != UncompressedLength) { + Error ("FMMT", 0, 0003, "compression error in the compression section", NULL); + return EFI_SECTION_ERROR; + } + + ScratchBuffer = malloc (ScratchSize); + if (ScratchBuffer == NULL) { + Error ("FMMT", 0, 0003, "Allocate memory failed", NULL); + return EFI_OUT_OF_RESOURCES; + } + UncompressedBuffer = malloc (UncompressedLength); + if (UncompressedBuffer == NULL) { + Error ("FMMT", 0, 0003, "Allocate memory failed", NULL); + free (ScratchBuffer); + return EFI_OUT_OF_RESOURCES; + } + // + // Decompress the section. + // + Status = DecompressFunction ( + CompressedBuffer, + CompressedLength, + UncompressedBuffer, + UncompressedLength, + ScratchBuffer, + ScratchSize + ); + free (ScratchBuffer); + if (EFI_ERROR (Status)) { + Error ("FMMT", 0, 0003, "decompress failed", NULL); + free (UncompressedBuffer); + return EFI_SECTION_ERROR; + } + } else { + Error ("FMMT", 0, 0003, "unrecognized compression type", "type 0x%X", CompressionType); + return EFI_SECTION_ERROR; + } + + Status = LibParseSection ( UncompressedBuffer, + UncompressedLength, + CurrentFv, + FvName, + CurrentFile, + Level, + &LocalEncapData, + FfsLevel, + FfsCount, + FvCount, + ViewFlag, + ErasePolarity, + IsFfsGenerated); + + if (CompressionType == EFI_STANDARD_COMPRESSION) { + // + // We need to deallocate Buffer + // + free (UncompressedBuffer); + } + + if (EFI_ERROR (Status)) { + Error (NULL, 0, 0003, "failed to parse section", NULL); + return EFI_SECTION_ERROR; + } + + break; + + case EFI_SECTION_GUID_DEFINED: + // + // Process GUID defined + // looks up the appropriate tool to use for extracting + // a GUID defined FV section. + // + Level ++; + NumberOfSections++; + EncapDataNeedUpdata = TRUE; + // + // Put in encapsulate data information. + // + LocalEncapData = *CurrentFvEncapData; + if (LocalEncapData->NextNode != NULL) { + EncapDataNeedUpdata = FALSE; + while (LocalEncapData->RightNode != NULL) { + LocalEncapData = LocalEncapData->RightNode; + } + } + GuidAttr = ((EFI_GUID_DEFINED_SECTION *)(Ptr + LargeHeaderOffset))->Attributes; + DataOffset = ((EFI_GUID_DEFINED_SECTION *)(Ptr + LargeHeaderOffset))->DataOffset; + + if ((ViewFlag) && ((GuidAttr & EFI_GUIDED_SECTION_PROCESSING_REQUIRED) == 0)) { + ToolOutputBuffer = Ptr + DataOffset; + ToolOutputLength = SectionLength - DataOffset; + Status = LibParseSection( + ToolOutputBuffer, + ToolOutputLength, + CurrentFv, + FvName, + CurrentFile, + Level, + &LocalEncapData, + FfsLevel, + FfsCount, + FvCount, + ViewFlag, + ErasePolarity, + IsFfsGenerated + ); + if (EFI_ERROR(Status)) { + Error(NULL, 0, 0003, "parse of decoded GUIDED section failed", NULL); + return EFI_SECTION_ERROR; + } + break; + } + + if (EncapDataNeedUpdata) { + + // + // Put in this is an FFS with FV section + // + + // + // Construct the new ENCAP_DATA + // + LocalEncapData->NextNode = (ENCAP_INFO_DATA *) malloc (sizeof (ENCAP_INFO_DATA)); + + if (LocalEncapData->NextNode == NULL) { + Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL); + return EFI_ABORTED; + } + + LocalEncapData = LocalEncapData->NextNode; + + LocalEncapData->Level = Level; + LocalEncapData->Type = FMMT_ENCAP_TREE_GUIDED_SECTION; + LocalEncapData->Depex = NULL; + LocalEncapData->DepexLen = 0; + LocalEncapData->UiNameSize = 0; + // + // We don't need additional data for encapsulate this FFS but type. + // include DataOffset + Attributes + // + + LocalEncapData->Data = (EFI_GUID *) malloc (sizeof (EFI_GUID) + 4); + + if (LocalEncapData->Data == NULL) { + Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL); + return EFI_ABORTED; + } + + // + // include guid attribute and dataoffset + // + memcpy (LocalEncapData->Data, Ptr + LargeHeaderOffset + OFFSET_OF (EFI_GUID_DEFINED_SECTION, SectionDefinitionGuid), sizeof (EFI_GUID) + 4); + + LocalEncapData->FvExtHeader = NULL; + LocalEncapData->NextNode = NULL; + LocalEncapData->RightNode = NULL; + } else { + LocalEncapData->RightNode = (ENCAP_INFO_DATA *) malloc (sizeof (ENCAP_INFO_DATA)); + if (LocalEncapData->RightNode == NULL) { + Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL); + return EFI_ABORTED; + } + LocalEncapData = LocalEncapData->RightNode; + LocalEncapData->Level = Level; + LocalEncapData->Type = FMMT_ENCAP_TREE_GUIDED_SECTION; + LocalEncapData->Depex = NULL; + LocalEncapData->DepexLen = 0; + LocalEncapData->UiNameSize = 0; + // + // We don't need additional data for encapsulate this FFS but type. + // include DataOffset + Attributes + // + + LocalEncapData->Data = (EFI_GUID *) malloc (sizeof (EFI_GUID) + 4); + + if (LocalEncapData->Data == NULL) { + Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL); + return EFI_ABORTED; + } + + // + // include guid attribute and dataoffset + // + memcpy (LocalEncapData->Data, Ptr + LargeHeaderOffset + OFFSET_OF (EFI_GUID_DEFINED_SECTION, SectionDefinitionGuid), sizeof (EFI_GUID) + 4); + + LocalEncapData->FvExtHeader = NULL; + LocalEncapData->NextNode = NULL; + LocalEncapData->RightNode = NULL; + } + + CurrentFv->FfsAttuibutes[*FfsCount].IsLeaf = FALSE; + + ExtractionTool = + LookupGuidedSectionToolPath ( + mParsedGuidedSectionTools, + &((EFI_GUID_DEFINED_SECTION *) (Ptr + LargeHeaderOffset))->SectionDefinitionGuid + ); + + if (ExtractionTool != NULL && ((GuidAttr & EFI_GUIDED_SECTION_PROCESSING_REQUIRED) != 0)) { + + TempDir = getcwd (NULL, _MAX_PATH); + if (strlen (TempDir) + strlen(OS_SEP_STR) + strlen (TEMP_DIR_NAME) > _MAX_PATH - 1) { + Error("FMMT", 0, 1001, "The directory is too long.", ""); + free (ExtractionTool); + return EFI_SECTION_ERROR; + } + strncat (TempDir, OS_SEP_STR, _MAX_PATH - strlen(TempDir) - 1); + strncat (TempDir, TEMP_DIR_NAME, _MAX_PATH - strlen(TempDir) - 1); + mkdir(TempDir, S_IRWXU | S_IRWXG | S_IRWXO); + ToolInputFile = GenTempFile (); + if (ToolInputFile == NULL) { + Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL); + free (ExtractionTool); + return EFI_OUT_OF_RESOURCES; + } + ToolOutputFile = GenTempFile (); + if (ToolOutputFile == NULL) { + free (ToolInputFile); + Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL); + free (ExtractionTool); + return EFI_OUT_OF_RESOURCES; + } + ToolInputFileName = strrchr(ToolInputFile, OS_SEP); + if (ToolInputFileName == NULL) { + free (ToolInputFile); + free (ToolOutputFile); + free (ExtractionTool); + return EFI_ABORTED; + } + ToolOutputFileName = strrchr(ToolOutputFile, OS_SEP); + if (ToolOutputFileName == NULL) { + free (ToolInputFile); + free (ToolOutputFile); + free (ExtractionTool); + return EFI_ABORTED; + } + + ToolInputFileFullName = malloc (strlen("%s%s") + strlen(TempDir) + strlen(ToolInputFileName) + 1); + if (ToolInputFileFullName == NULL) { + free (ToolInputFile); + free (ToolOutputFile); + free (ExtractionTool); + Error ("FMMT", 0, 0003, "Allocate memory failed", NULL); + return EFI_OUT_OF_RESOURCES; + } + ToolOutputFileFullName = malloc (strlen("%s%s") + strlen(TempDir) + strlen(ToolOutputFileName) + 1); + + if (ToolOutputFileFullName == NULL) { + free (ToolInputFile); + free (ToolOutputFile); + free (ToolInputFileFullName); + free (ExtractionTool); + Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL); + return EFI_OUT_OF_RESOURCES; + } + + sprintf (ToolInputFileFullName, "%s%s", TempDir, ToolInputFileName); + sprintf (ToolOutputFileFullName, "%s%s", TempDir, ToolOutputFileName); + + // + // Construction 'system' command string + // + SystemCommandFormatString = "%s -d -o \"%s\" \"%s\""; + SystemCommand = malloc ( + strlen (SystemCommandFormatString) + + strlen (ExtractionTool) + + strlen (ToolInputFileFullName) + + strlen (ToolOutputFileFullName) + + 1 + ); + if (SystemCommand == NULL) { + free (ToolInputFile); + free (ToolOutputFile); + free (ToolInputFileFullName); + free (ToolOutputFileFullName); + free (ExtractionTool); + return EFI_ABORTED; + } + sprintf ( + SystemCommand, + "%s -d -o \"%s\" \"%s\"", + ExtractionTool, + ToolOutputFileFullName, + ToolInputFileFullName + ); + free (ExtractionTool); + ExtractionTool = NULL; + + Status = PutFileImage ( + ToolInputFileFullName, + (CHAR8*) Ptr + ((EFI_GUID_DEFINED_SECTION *) (Ptr + LargeHeaderOffset))->DataOffset, + SectionLength - ((EFI_GUID_DEFINED_SECTION *) (Ptr + LargeHeaderOffset))->DataOffset + ); + + if (HasDepexSection) { + HasDepexSection = FALSE; + } + + if (EFI_ERROR (Status)) { + Error ("FMMT", 0, 0004, "unable to decoded GUIDED section", NULL); + free (SystemCommand); + free (ToolInputFile); + free (ToolOutputFile); + free (ToolOutputFileFullName); + remove (ToolInputFileFullName); + free (ToolInputFileFullName); + return EFI_SECTION_ERROR; + } + + if (system (SystemCommand) != EFI_SUCCESS) { + printf("Command failed: %s\n", SystemCommand); + free (SystemCommand); + free (ToolInputFile); + free (ToolOutputFile); + free (ToolOutputFileFullName); + remove (ToolInputFileFullName); + free (ToolInputFileFullName); + return EFI_ABORTED; + } + free (SystemCommand); + remove (ToolInputFileFullName); + free (ToolInputFile); + free (ToolInputFileFullName); + ToolInputFile = NULL; + ToolInputFileFullName = NULL; + + + Status = GetFileImage ( + ToolOutputFileFullName, + (CHAR8 **)&ToolOutputBuffer, + &ToolOutputLength + ); + remove (ToolOutputFileFullName); + free (ToolOutputFile); + free (ToolOutputFileFullName); + ToolOutputFile = NULL; + ToolOutputFileFullName = NULL; + + if (EFI_ERROR (Status)) { + Error ("FMMT", 0, 0004, "unable to read decoded GUIDED section", NULL); + return EFI_SECTION_ERROR; + } + + Status = LibParseSection ( + ToolOutputBuffer, + ToolOutputLength, + CurrentFv, + FvName, + CurrentFile, + Level, + &LocalEncapData, + FfsLevel, + FfsCount, + FvCount, + ViewFlag, + ErasePolarity, + IsFfsGenerated + ); + if (EFI_ERROR (Status)) { + Error (NULL, 0, 0003, "parse of decoded GUIDED section failed", NULL); + return EFI_SECTION_ERROR; + } + } else if ((GuidAttr & EFI_GUIDED_SECTION_PROCESSING_REQUIRED) == 0){ + Status = LibParseSection ( + Ptr + ((EFI_GUID_DEFINED_SECTION *) (Ptr + LargeHeaderOffset))->DataOffset, + SectionLength - ((EFI_GUID_DEFINED_SECTION *) (Ptr + LargeHeaderOffset))->DataOffset, + CurrentFv, + FvName, + CurrentFile, + Level, + &LocalEncapData, + FfsLevel, + FfsCount, + FvCount, + ViewFlag, + ErasePolarity, + IsFfsGenerated + ); + if (ExtractionTool != NULL) { + free (ExtractionTool); + ExtractionTool = NULL; + } + if (EFI_ERROR (Status)) { + Error (NULL, 0, 0003, "parse of decoded GUIDED section failed", NULL); + return EFI_SECTION_ERROR; + } + }else { + // + // We don't know how to parse it now. + // + if (ExtractionTool != NULL) { + free (ExtractionTool); + ExtractionTool = NULL; + } + Error ("FMMT", 0, 0003, "Error parsing section", \ + "EFI_SECTION_GUID_DEFINED cannot be parsed at this time. Tool to decode this section should have been defined in %s file.", mGuidToolDefinition); + printf(" Its GUID is: "); + PrintGuid(&(((EFI_GUID_DEFINED_SECTION *)(Ptr + LargeHeaderOffset))->SectionDefinitionGuid)); + return EFI_UNSUPPORTED; + } + break; + + // + //Leaf sections + // + case EFI_SECTION_RAW: + NumberOfSections ++; + CurrentFv->FfsAttuibutes[*FfsCount].Level = Level; + if (!ViewFlag) { + if (!*IsFfsGenerated) { + LibGenFfsFile(CurrentFile, CurrentFv, FvName, Level, FfsCount, ErasePolarity); + *IsFfsGenerated = TRUE; + } + } + + break; + case EFI_SECTION_PE32: + NumberOfSections ++; + CurrentFv->FfsAttuibutes[*FfsCount].Level = Level; + if (!ViewFlag) { + if (!*IsFfsGenerated) { + LibGenFfsFile(CurrentFile, CurrentFv, FvName, Level, FfsCount, ErasePolarity); + *IsFfsGenerated = TRUE; + } + } + + break; + case EFI_SECTION_PIC: + NumberOfSections ++; + CurrentFv->FfsAttuibutes[*FfsCount].Level = Level; + if (!ViewFlag) { + if (!*IsFfsGenerated) { + LibGenFfsFile(CurrentFile, CurrentFv, FvName, Level, FfsCount, ErasePolarity); + *IsFfsGenerated = TRUE; + } + } + + break; + case EFI_SECTION_TE: + NumberOfSections ++; + CurrentFv->FfsAttuibutes[*FfsCount].Level = Level; + if (!ViewFlag) { + if (!*IsFfsGenerated) { + LibGenFfsFile(CurrentFile, CurrentFv, FvName, Level, FfsCount, ErasePolarity); + *IsFfsGenerated = TRUE; + } + } + break; + + case EFI_SECTION_COMPATIBILITY16: + NumberOfSections ++; + CurrentFv->FfsAttuibutes[*FfsCount].Level = Level; + if (!ViewFlag) { + if (!*IsFfsGenerated) { + LibGenFfsFile(CurrentFile, CurrentFv, FvName, Level, FfsCount, ErasePolarity); + *IsFfsGenerated = TRUE; + } + } + break; + + case EFI_SECTION_FREEFORM_SUBTYPE_GUID: + NumberOfSections ++; + CurrentFv->FfsAttuibutes[*FfsCount].Level = Level; + if (!ViewFlag) { + if (!*IsFfsGenerated) { + LibGenFfsFile(CurrentFile, CurrentFv, FvName, Level, FfsCount, ErasePolarity); + *IsFfsGenerated = TRUE; + } + } + break; + + case EFI_SECTION_VERSION: + NumberOfSections ++; + CurrentFv->FfsAttuibutes[*FfsCount].Level = Level; + break; + case EFI_SECTION_PEI_DEPEX: + NumberOfSections ++; + CurrentFv->FfsAttuibutes[*FfsCount].Level = Level; + HasDepexSection = TRUE; + CurrentFv->FfsAttuibutes[*FfsCount].Depex = malloc (SectionLength); + memcpy(CurrentFv->FfsAttuibutes[*FfsCount].Depex, Ptr, SectionLength); + CurrentFv->FfsAttuibutes[*FfsCount].DepexLen = SectionLength; + break; + case EFI_SECTION_DXE_DEPEX: + NumberOfSections ++; + CurrentFv->FfsAttuibutes[*FfsCount].Level = Level; + HasDepexSection = TRUE; + CurrentFv->FfsAttuibutes[*FfsCount].Depex = malloc (SectionLength); + memcpy(CurrentFv->FfsAttuibutes[*FfsCount].Depex, Ptr, SectionLength); + CurrentFv->FfsAttuibutes[*FfsCount].DepexLen = SectionLength; + break; + case EFI_SECTION_SMM_DEPEX: + NumberOfSections ++; + CurrentFv->FfsAttuibutes[*FfsCount].Level = Level; + HasDepexSection = TRUE; + CurrentFv->FfsAttuibutes[*FfsCount].Depex = malloc (SectionLength); + memcpy(CurrentFv->FfsAttuibutes[*FfsCount].Depex, Ptr, SectionLength); + CurrentFv->FfsAttuibutes[*FfsCount].DepexLen = SectionLength; + break; + + case EFI_SECTION_USER_INTERFACE: + NumberOfSections ++; + CurrentFv->FfsAttuibutes[*FfsCount].Level = Level; + + UiSectionLength = GetLength (((EFI_USER_INTERFACE_SECTION *) Ptr)->CommonHeader.Size); + if (UiSectionLength == 0xffffff) { + UiSectionLength = ((EFI_USER_INTERFACE_SECTION2 *) Ptr)->CommonHeader.ExtendedSize; + UINameSize = UiSectionLength - sizeof(EFI_COMMON_SECTION_HEADER2); + } else { + UINameSize = UiSectionLength - sizeof(EFI_COMMON_SECTION_HEADER); + } + + UIName = (CHAR16 *) malloc (UINameSize + 2); + if (UIName != NULL) { + memset (UIName, '\0', UINameSize + 2); + if (UiSectionLength >= 0xffffff) { + memcpy(UIName, ((EFI_USER_INTERFACE_SECTION2 *) Ptr)->FileNameString, UINameSize); + } else { + memcpy(UIName, ((EFI_USER_INTERFACE_SECTION *) Ptr)->FileNameString, UINameSize); + } + } else { + Error ("FMMT", 0, 0001, "Memory allocate error!", NULL); + return EFI_OUT_OF_RESOURCES; + } + + BlankChar = LibConstructBlankChar( CurrentFv->FvLevel * 2); + if (BlankChar == NULL) { + free(UIName); + return EFI_OUT_OF_RESOURCES; + } + + if (ViewFlag) { + UIFileName = malloc (UINameSize + 2); + if (UIFileName == NULL) { + Error ("FMMT", 0, 4001, "Memory allocation fail!", NULL); + free (UIName); + free (BlankChar); + return EFI_OUT_OF_RESOURCES; + } + Unicode2AsciiString (UIName, UIFileName); + fprintf(stdout, "%sFile \"%s\"\n", BlankChar, UIFileName); + free(UIFileName); + } + free (BlankChar); + + // + // If Ffs file has been generated, then the FfsCount should decrease 1. + // + if (*IsFfsGenerated) { + memcpy (CurrentFv->FfsAttuibutes[*FfsCount -1].UiName, UIName, UINameSize); + CurrentFv->FfsAttuibutes[*FfsCount -1].UiNameSize = UINameSize; + } else { + memcpy (CurrentFv->FfsAttuibutes[*FfsCount].UiName, UIName, UINameSize); + CurrentFv->FfsAttuibutes[*FfsCount].UiNameSize = UINameSize; + } + + HasDepexSection = FALSE; + free(UIName); + UINameSize = 0; + + break; + default: + break; + } + + ParsedLength += SectionLength; + // + // We make then next section begin on a 4-byte boundary + // + ParsedLength = GetOccupiedSize (ParsedLength, 4); + } + + if (ParsedLength < BufferLength) { + Error ("FMMT", 0, 0003, "sections do not completely fill the sectioned buffer being parsed", NULL); + return EFI_SECTION_ERROR; + } + + + return EFI_SUCCESS; +} + +/** + + Iterates through the files contained within the firmware volume + + @param[in] Fv - Address of the Fv in memory + @param[in] Key - Should be 0 to get the first file. After that, it should be + passed back in without modifying it's contents to retrieve + subsequent files. + @param[in] File- Output file pointer + File == NULL - invalid parameter + otherwise - *File will be update to the location of the file + + @return EFI_STATUS + EFI_NOT_FOUND + EFI_VOLUME_CORRUPTED + +**/ +EFI_STATUS +FvBufFindNextFile ( + IN VOID *Fv, + IN OUT UINTN *Key, + OUT VOID **File + ) +{ + EFI_FIRMWARE_VOLUME_HEADER *hdr; + EFI_FFS_FILE_HEADER *fhdr; + EFI_FIRMWARE_VOLUME_EXT_HEADER *FwVolExtHeader; + EFI_FVB_ATTRIBUTES_2 FvbAttributes; + UINTN fsize; + EFI_STATUS Status; + UINTN fvSize; + + hdr = (EFI_FIRMWARE_VOLUME_HEADER*)Fv; + fhdr = NULL; + + if (Fv == NULL) { + return EFI_INVALID_PARAMETER; + } + + Status = FvBufGetSize (Fv, &fvSize); + if (EFI_ERROR (Status)) { + return Status; + } + + if (*Key == 0) { + if (hdr->ExtHeaderOffset != 0) { + // + // Searching for files starts on an 8 byte aligned boundary after the end of the Extended Header if it exists. + // + FwVolExtHeader = (EFI_FIRMWARE_VOLUME_EXT_HEADER *)((UINT8 *)hdr + hdr->ExtHeaderOffset); + *Key = (UINTN)hdr->ExtHeaderOffset + FwVolExtHeader->ExtHeaderSize; + *Key = (UINTN)ALIGN_POINTER(*Key, 8); + } else { + *Key = hdr->HeaderLength; + } + } + + FvbAttributes = hdr->Attributes; + + for( + *Key = (UINTN)ALIGN_POINTER (*Key, 8); + (*Key + sizeof (*fhdr)) < fvSize; + *Key = (UINTN)ALIGN_POINTER (*Key, 8) + ) { + fhdr = (EFI_FFS_FILE_HEADER*) ((UINT8*)hdr + *Key); + fsize = GetFfsFileLength (fhdr); + if (!EFI_TEST_FFS_ATTRIBUTES_BIT( + FvbAttributes, + fhdr->State, + EFI_FILE_HEADER_VALID + ) || + EFI_TEST_FFS_ATTRIBUTES_BIT( + FvbAttributes, + fhdr->State, + EFI_FILE_HEADER_INVALID + ) + ) { + *Key = *Key + 1; + continue; + } else if( + EFI_TEST_FFS_ATTRIBUTES_BIT( + FvbAttributes, + fhdr->State, + EFI_FILE_MARKED_FOR_UPDATE + ) || + EFI_TEST_FFS_ATTRIBUTES_BIT( + FvbAttributes, + fhdr->State, + EFI_FILE_DELETED + ) + ) { + *Key = *Key + fsize; + continue; + } else if (EFI_TEST_FFS_ATTRIBUTES_BIT( + FvbAttributes, + fhdr->State, + EFI_FILE_DATA_VALID + ) + ) { + *File = (UINT8*)hdr + *Key; + *Key = *Key + fsize; + return EFI_SUCCESS; + } + + *Key = *Key + 1; + } + + return EFI_NOT_FOUND; +} + +/** + + TODO: Add function description + + FvImage - TODO: add argument description + FileHeader - TODO: add argument description + ErasePolarity - TODO: add argument description + + EFI_SUCCESS - TODO: Add description for return value + EFI_ABORTED - TODO: Add description for return value + +**/ +EFI_STATUS +LibGetFileInfo ( + EFI_FIRMWARE_VOLUME_HEADER *FvImage, + EFI_FFS_FILE_HEADER2 *CurrentFile, + BOOLEAN ErasePolarity, + FV_INFORMATION *CurrentFv, + CHAR8 *FvName, + UINT8 Level, + ENCAP_INFO_DATA **CurrentFvEncapData, + UINT32 *FfsCount, + UINT8 *FvCount, + BOOLEAN ViewFlag + ) +{ + UINT32 FileLength; + UINT8 FileState; + UINT8 Checksum; + EFI_FFS_FILE_HEADER2 BlankHeader; + EFI_STATUS Status; + UINT8 GuidBuffer[PRINTED_GUID_BUFFER_SIZE]; + ENCAP_INFO_DATA *LocalEncapData; + BOOLEAN EncapDataNeedUpdateFlag; + BOOLEAN IsGeneratedFfs; + UINT32 FfsFileHeaderSize; + + Status = EFI_SUCCESS; + + LocalEncapData = NULL; + EncapDataNeedUpdateFlag = TRUE; + IsGeneratedFfs = FALSE; + + FfsFileHeaderSize = GetFfsHeaderLength ((EFI_FFS_FILE_HEADER *) CurrentFile); + FileLength = GetFfsFileLength ((EFI_FFS_FILE_HEADER *) CurrentFile); + + // + // Check if we have free space + // + if (ErasePolarity) { + memset (&BlankHeader, -1, FfsFileHeaderSize); + } else { + memset (&BlankHeader, 0, FfsFileHeaderSize); + } + + // + // Is this FV blank? + // + if (memcmp (&BlankHeader, CurrentFile, FfsFileHeaderSize) == 0) { + return EFI_SUCCESS; + } + + // + // Print file information. + // + FileState = GetFileState (ErasePolarity, (EFI_FFS_FILE_HEADER *)CurrentFile); + PrintGuidToBuffer (&(CurrentFile->Name), GuidBuffer, PRINTED_GUID_BUFFER_SIZE, FALSE); + if (FileState == EFI_FILE_DATA_VALID) { + // + // Calculate header checksum + // + Checksum = CalculateSum8 ((UINT8 *) CurrentFile, FfsFileHeaderSize); + Checksum = (UINT8) (Checksum - CurrentFile->IntegrityCheck.Checksum.File); + Checksum = (UINT8) (Checksum - CurrentFile->State); + if (Checksum != 0) { + Error ("FMMT", 0, 0003, "error parsing FFS file", "FFS file with Guid %s has invalid header checksum", GuidBuffer); + return EFI_ABORTED; + } + + if (CurrentFile->Attributes & FFS_ATTRIB_CHECKSUM) { + // + // Calculate file checksum + // + Checksum = CalculateSum8 ((UINT8 *) ((UINTN)CurrentFile + FfsFileHeaderSize), FileLength - FfsFileHeaderSize); + Checksum = Checksum + CurrentFile->IntegrityCheck.Checksum.File; + if (Checksum != 0) { + Error ("FMMT", 0, 0003, "error parsing FFS file", "FFS file with Guid %s has invalid file checksum", GuidBuffer); + return EFI_ABORTED; + } + } else { + if (CurrentFile->IntegrityCheck.Checksum.File != FFS_FIXED_CHECKSUM) { + Error ("FMMT", 0, 0003, "error parsing FFS file", "FFS file with Guid %s has invalid header checksum -- not set to fixed value of 0xAA", GuidBuffer); + return EFI_ABORTED; + } + } + } else { + Error ("FMMT", 0, 0003, "error parsing FFS file", "FFS file with Guid %s has the invalid/unrecognized file state bits", GuidBuffer); + return EFI_ABORTED; + } + + Level += 1; + + if ((CurrentFile->Type != EFI_FV_FILETYPE_ALL) && (CurrentFile->Type != EFI_FV_FILETYPE_FFS_PAD)) { + + // + // Put in encapsulate data information. + // + LocalEncapData = *CurrentFvEncapData; + if (LocalEncapData->NextNode != NULL) { + LocalEncapData = LocalEncapData->NextNode; + EncapDataNeedUpdateFlag = FALSE; + while (LocalEncapData->RightNode != NULL) { + LocalEncapData = LocalEncapData->RightNode; + } + } + + if (EncapDataNeedUpdateFlag) { + // + // Construct the new ENCAP_DATA + // + LocalEncapData->NextNode = (ENCAP_INFO_DATA *) malloc (sizeof (ENCAP_INFO_DATA)); + + if (LocalEncapData->NextNode == NULL) { + Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL); + return EFI_ABORTED; + } + + LocalEncapData = LocalEncapData->NextNode; + + LocalEncapData->Level = Level; + LocalEncapData->Type = FMMT_ENCAP_TREE_FFS; + LocalEncapData->FvExtHeader = NULL; + LocalEncapData->Depex = NULL; + LocalEncapData->DepexLen = 0; + LocalEncapData->UiNameSize = 0; + // + // Store the header of FFS file. + // + LocalEncapData->Data = malloc (FfsFileHeaderSize); + if (LocalEncapData->Data == NULL) { + Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL); + return EFI_ABORTED; + } + + memcpy (LocalEncapData->Data, CurrentFile, FfsFileHeaderSize); + LocalEncapData->FvExtHeader = (EFI_FIRMWARE_VOLUME_EXT_HEADER *)malloc(sizeof(EFI_FIRMWARE_VOLUME_EXT_HEADER)); + if (LocalEncapData->FvExtHeader == NULL) { + Error(NULL, 0, 4001, "Resource: Memory can't be allocated", NULL); + return EFI_ABORTED; + } + LocalEncapData->FvExtHeader->FvName.Data1 = CurrentFile->Name.Data1; + LocalEncapData->FvExtHeader->FvName.Data2 = CurrentFile->Name.Data2; + LocalEncapData->FvExtHeader->FvName.Data3 = CurrentFile->Name.Data3; + LocalEncapData->FvExtHeader->FvName.Data4[0] = CurrentFile->Name.Data4[0]; + LocalEncapData->FvExtHeader->FvName.Data4[1] = CurrentFile->Name.Data4[1]; + LocalEncapData->FvExtHeader->FvName.Data4[2] = CurrentFile->Name.Data4[2]; + LocalEncapData->FvExtHeader->FvName.Data4[3] = CurrentFile->Name.Data4[3]; + LocalEncapData->FvExtHeader->FvName.Data4[4] = CurrentFile->Name.Data4[4]; + LocalEncapData->FvExtHeader->FvName.Data4[5] = CurrentFile->Name.Data4[5]; + LocalEncapData->FvExtHeader->FvName.Data4[6] = CurrentFile->Name.Data4[6]; + LocalEncapData->FvExtHeader->FvName.Data4[7] = CurrentFile->Name.Data4[7]; + LocalEncapData->NextNode = NULL; + LocalEncapData->RightNode = NULL; + }else{ + // + // Construct the new ENCAP_DATA + // + LocalEncapData->RightNode = (ENCAP_INFO_DATA *) malloc (sizeof (ENCAP_INFO_DATA)); + + if (LocalEncapData->RightNode == NULL) { + Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL); + return EFI_ABORTED; + } + + LocalEncapData = LocalEncapData->RightNode; + + LocalEncapData->Level = Level; + LocalEncapData->Type = FMMT_ENCAP_TREE_FFS; + LocalEncapData->FvExtHeader = NULL; + LocalEncapData->Depex = NULL; + LocalEncapData->DepexLen = 0; + LocalEncapData->UiNameSize = 0; + // + // Store the header of FFS file. + // + LocalEncapData->Data = malloc (FfsFileHeaderSize); + if (LocalEncapData->Data == NULL) { + Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL); + return EFI_ABORTED; + } + + memcpy (LocalEncapData->Data, CurrentFile, FfsFileHeaderSize); + LocalEncapData->FvExtHeader = (EFI_FIRMWARE_VOLUME_EXT_HEADER *)malloc(sizeof(EFI_FIRMWARE_VOLUME_EXT_HEADER)); + if (LocalEncapData->FvExtHeader == NULL) { + Error(NULL, 0, 4001, "Resource: Memory can't be allocated", NULL); + return EFI_ABORTED; + } + LocalEncapData->FvExtHeader->FvName.Data1 = CurrentFile->Name.Data1; + LocalEncapData->FvExtHeader->FvName.Data2 = CurrentFile->Name.Data2; + LocalEncapData->FvExtHeader->FvName.Data3 = CurrentFile->Name.Data3; + LocalEncapData->FvExtHeader->FvName.Data4[0] = CurrentFile->Name.Data4[0]; + LocalEncapData->FvExtHeader->FvName.Data4[1] = CurrentFile->Name.Data4[1]; + LocalEncapData->FvExtHeader->FvName.Data4[2] = CurrentFile->Name.Data4[2]; + LocalEncapData->FvExtHeader->FvName.Data4[3] = CurrentFile->Name.Data4[3]; + LocalEncapData->FvExtHeader->FvName.Data4[4] = CurrentFile->Name.Data4[4]; + LocalEncapData->FvExtHeader->FvName.Data4[5] = CurrentFile->Name.Data4[5]; + LocalEncapData->FvExtHeader->FvName.Data4[6] = CurrentFile->Name.Data4[6]; + LocalEncapData->FvExtHeader->FvName.Data4[7] = CurrentFile->Name.Data4[7]; + LocalEncapData->RightNode = NULL; + LocalEncapData->NextNode = NULL; + } + + if ( CurrentFile->Type == EFI_FV_FILETYPE_RAW){ + CurrentFv->FfsAttuibutes[*FfsCount].Level = Level; + if (!ViewFlag){ + LibGenFfsFile(CurrentFile, CurrentFv, FvName, Level, FfsCount, ErasePolarity); + } + } else if( CurrentFile->Type == EFI_FV_FILETYPE_FFS_PAD){ + //EFI_FV_FILETYPE_FFS_PAD + } else { + // + // All other files have sections + // + Status = LibParseSection ( + (UINT8 *) ((UINTN) CurrentFile + FfsFileHeaderSize), + FileLength - FfsFileHeaderSize, + CurrentFv, + FvName, + CurrentFile, + Level, + &LocalEncapData, + Level, + FfsCount, + FvCount, + ViewFlag, + ErasePolarity, + &IsGeneratedFfs + ); + } + if (EFI_ERROR (Status)) { + printf ("ERROR: Parsing the FFS file.\n"); + return Status; + } + } + + + return EFI_SUCCESS; +} + +/** + + Get firmware information. Including the FV headers, + + @param[in] Fv - Firmware Volume to get information from + + @return EFI_STATUS + +**/ +EFI_STATUS +LibGetFvInfo ( + IN VOID *Fv, + IN OUT FV_INFORMATION *CurrentFv, + IN CHAR8 *FvName, + IN UINT8 Level, + IN ENCAP_INFO_DATA **CurrentFvEncapData, + IN UINT32 *FfsCount, + IN OUT UINT8 *FvCount, + IN BOOLEAN ViewFlag, + IN BOOLEAN IsChildFv + ) +{ + EFI_STATUS Status; + UINTN NumberOfFiles; + BOOLEAN ErasePolarity; + UINTN FvSize; + EFI_FFS_FILE_HEADER2 *CurrentFile; + UINTN Key; + ENCAP_INFO_DATA *LocalEncapData; + EFI_FIRMWARE_VOLUME_EXT_HEADER *ExtHdrPtr; + EFI_FIRMWARE_VOLUME_HEADER *FvHdr; + + NumberOfFiles = 0; + Key = 0; + LocalEncapData = NULL; + CurrentFile = NULL; + FvHdr = (EFI_FIRMWARE_VOLUME_HEADER *)Fv; + + + Level += 1; + *FvCount += 1; + CurrentFv->FvLevel += 1; + + Status = FvBufGetSize (Fv, &FvSize); + + ErasePolarity = (((EFI_FIRMWARE_VOLUME_HEADER*)Fv)->Attributes & EFI_FVB2_ERASE_POLARITY) ? TRUE : FALSE; + + Status = LibReadFvHeader (Fv, ViewFlag, CurrentFv->FvLevel, *FvCount - 1, CurrentFv->FvName); + if (EFI_ERROR (Status)) { + Error (NULL, 0, 0003, "error parsing FV image", "Header is invalid"); + return EFI_ABORTED; + } + + if (!IsChildFv) { + // + // Write FV header information into CurrentFv struct. + // + CurrentFv->FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *) malloc (FvHdr->HeaderLength); + + if (CurrentFv->FvHeader == NULL) { + Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL); + return EFI_ABORTED; + } + + // + // Get the FV Header information + // + memcpy(CurrentFv->FvHeader, Fv, FvHdr->HeaderLength); + CurrentFv->FvExtHeader = NULL; + CurrentFv->FvUiName = NULL; + + // + // Exist Extend FV header. + // + if (CurrentFv->FvHeader->ExtHeaderOffset != 0){ + ExtHdrPtr = (VOID *)((UINTN)Fv + CurrentFv->FvHeader->ExtHeaderOffset); + CurrentFv->FvExtHeader = (EFI_FIRMWARE_VOLUME_EXT_HEADER *) malloc (ExtHdrPtr->ExtHeaderSize); + + if (CurrentFv->FvExtHeader == NULL) { + Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL); + return EFI_ABORTED; + } + + // + // Get the FV extended Header information + // + memcpy (CurrentFv->FvExtHeader, (VOID *)((UINTN)Fv + CurrentFv->FvHeader->ExtHeaderOffset), ExtHdrPtr->ExtHeaderSize); + LibExtractFvUiName(CurrentFv->FvExtHeader, &CurrentFv->FvUiName); + } + } + + // + // Put encapsulate information into structure. + // + LocalEncapData = *CurrentFvEncapData; + if (LocalEncapData == NULL && !IsChildFv) { + // + // First time in, the root FV + // + LocalEncapData = (ENCAP_INFO_DATA *) malloc (sizeof (ENCAP_INFO_DATA)); + CurrentFv->EncapData = LocalEncapData; + if (CurrentFv->EncapData == NULL) { + Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL); + return EFI_ABORTED; + } + + CurrentFv->EncapData->FvExtHeader = NULL; + CurrentFv->EncapData->Depex = NULL; + CurrentFv->EncapData->DepexLen = 0; + CurrentFv->EncapData->UiNameSize = 0; + CurrentFv->EncapData->Level = Level; + CurrentFv->EncapData->Type = FMMT_ENCAP_TREE_FV; + CurrentFv->EncapData->Data = (EFI_FIRMWARE_VOLUME_HEADER *) malloc (sizeof (EFI_FIRMWARE_VOLUME_HEADER)); + CurrentFv->EncapData->FvId = *FvCount; + + if (CurrentFv->EncapData->Data == NULL) { + Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL); + return EFI_ABORTED; + } + + memcpy (CurrentFv->EncapData->Data, Fv, sizeof (EFI_FIRMWARE_VOLUME_HEADER)); + + if (((EFI_FIRMWARE_VOLUME_HEADER *)(CurrentFv->EncapData->Data))->ExtHeaderOffset != 0) { + ExtHdrPtr = (VOID *)((UINTN)Fv + ((EFI_FIRMWARE_VOLUME_HEADER *)(CurrentFv->EncapData->Data))->ExtHeaderOffset); + CurrentFv->EncapData->FvExtHeader = (EFI_FIRMWARE_VOLUME_EXT_HEADER *) malloc (ExtHdrPtr->ExtHeaderSize); + + if (CurrentFv->EncapData->FvExtHeader == NULL) { + Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL); + return EFI_ABORTED; + } + + // + // Get the FV extended Header information + // + memcpy(CurrentFv->EncapData->FvExtHeader, (VOID *)((UINTN)Fv + ((EFI_FIRMWARE_VOLUME_HEADER *)(CurrentFv->EncapData->Data))->ExtHeaderOffset), ExtHdrPtr->ExtHeaderSize); + } + + CurrentFv->EncapData->NextNode = NULL; + CurrentFv->EncapData->RightNode = NULL; + } else if (LocalEncapData == NULL) { + return EFI_ABORTED; + } else if (IsChildFv) { + + LocalEncapData = *CurrentFvEncapData; + while (LocalEncapData->NextNode != NULL) { + LocalEncapData = LocalEncapData->NextNode; + } + + // + // Construct the new ENCAP_DATA + // + LocalEncapData->NextNode = (ENCAP_INFO_DATA *) malloc (sizeof (ENCAP_INFO_DATA)); + + if (LocalEncapData->NextNode == NULL) { + Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL); + return EFI_ABORTED; + } + + LocalEncapData = LocalEncapData->NextNode; + + LocalEncapData->Level = Level; + LocalEncapData->Type = FMMT_ENCAP_TREE_FV; + LocalEncapData->Data = (EFI_FIRMWARE_VOLUME_HEADER *) malloc (sizeof (EFI_FIRMWARE_VOLUME_HEADER)); + LocalEncapData->FvExtHeader = NULL; + LocalEncapData->Depex = NULL; + LocalEncapData->DepexLen = 0; + LocalEncapData->UiNameSize = 0; + LocalEncapData->FvId = *FvCount; + if (LocalEncapData->Data == NULL) { + Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL); + return EFI_ABORTED; + } + + memcpy (LocalEncapData->Data, Fv, sizeof (EFI_FIRMWARE_VOLUME_HEADER)); + + if (((EFI_FIRMWARE_VOLUME_HEADER *)(LocalEncapData->Data))->ExtHeaderOffset != 0) { + ExtHdrPtr = (VOID *)((UINTN)Fv + ((EFI_FIRMWARE_VOLUME_HEADER *)(LocalEncapData->Data))->ExtHeaderOffset); + LocalEncapData->FvExtHeader = (EFI_FIRMWARE_VOLUME_EXT_HEADER *)malloc(ExtHdrPtr->ExtHeaderSize); + + if (LocalEncapData->FvExtHeader == NULL) { + Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL); + return EFI_ABORTED; + } + + // + // Get the FV extended Header information + // + memcpy(LocalEncapData->FvExtHeader, (VOID *)((UINTN)Fv + ((EFI_FIRMWARE_VOLUME_HEADER *)(LocalEncapData->Data))->ExtHeaderOffset), ExtHdrPtr->ExtHeaderSize); + } + + LocalEncapData->NextNode = NULL; + LocalEncapData->RightNode = NULL; + + } + + + // + // Get the first file + // + Status = FvBufFindNextFile (Fv, &Key, (VOID **) &CurrentFile); + if (Status == EFI_NOT_FOUND) { + CurrentFile = NULL; + } else if (EFI_ERROR (Status)) { + Error ("FMMT", 0, 0003, "error parsing FV image", "cannot find the first file in the FV image"); + return Status; + } + + while (CurrentFile != NULL) { + + // + // Increment the number of files counter + // + NumberOfFiles++; + + // + // Store FFS file Header information + // + CurrentFv->FfsHeader[*FfsCount].Attributes = CurrentFile->Attributes; + CurrentFv->FfsHeader[*FfsCount].IntegrityCheck = CurrentFile->IntegrityCheck; + CurrentFv->FfsHeader[*FfsCount].Name = CurrentFile->Name; + CurrentFv->FfsHeader[*FfsCount].Size[0] = CurrentFile->Size[0]; + CurrentFv->FfsHeader[*FfsCount].Size[1] = CurrentFile->Size[1]; + CurrentFv->FfsHeader[*FfsCount].Size[2] = CurrentFile->Size[2]; + CurrentFv->FfsHeader[*FfsCount].State = CurrentFile->State; + CurrentFv->FfsHeader[*FfsCount].Type = CurrentFile->Type; + CurrentFv->FfsHeader[*FfsCount].ExtendedSize = CurrentFile->ExtendedSize; + CurrentFv->FfsAttuibutes[*FfsCount].Offset = Key - GetFfsFileLength ((EFI_FFS_FILE_HEADER *) CurrentFile); + + CurrentFv->FfsAttuibutes[*FfsCount].FvLevel = CurrentFv->FvLevel; + if (CurrentFv->FvLevel > CurrentFv->MulFvLevel) { + CurrentFv->MulFvLevel = CurrentFv->FvLevel; + } + // + // Display info about this file + // + Status = LibGetFileInfo (Fv, CurrentFile, ErasePolarity, CurrentFv, FvName, Level, &LocalEncapData, FfsCount, FvCount, ViewFlag); + if (EFI_ERROR (Status)) { + Error ("FMMT", 0, 0003, "error parsing FV image", "failed to parse a file in the FV"); + return Status; + } + + // + // Get the next file + // + Status = FvBufFindNextFile (Fv, &Key, (VOID **) &CurrentFile); + if (Status == EFI_NOT_FOUND) { + CurrentFile = NULL; + } else if (EFI_ERROR (Status)) { + Error ("FMMT", 0, 0003, "error parsing FV image", "cannot find the next file in the FV image"); + return Status; + } + } + + if (IsChildFv) { + if (CurrentFv->FvLevel > 1) { + CurrentFv->FvLevel -= 1; + } + } + return EFI_SUCCESS; +} + +/** + + This function returns the next larger size that meets the alignment + requirement specified. + + @param[in] ActualSize The size. + @param[in] Alignment The desired alignment. + + @retval EFI_SUCCESS Function completed successfully. + @retval EFI_ABORTED The function encountered an error. + +**/ +UINT32 +GetOccupiedSize ( + IN UINT32 ActualSize, + IN UINT32 Alignment + ) +{ + UINT32 OccupiedSize; + + OccupiedSize = ActualSize; + while ((OccupiedSize & (Alignment - 1)) != 0) { + OccupiedSize++; + } + + return OccupiedSize; +} + + + +EFI_STATUS +LibDeleteAndRenameFfs( + IN CHAR8* DeleteFile, + IN CHAR8* NewFile +) +{ + CHAR8* SystemCommand; + CHAR8* TemDir; + SystemCommand = NULL; + + if (DeleteFile == NULL || + NewFile == NULL) { + return EFI_INVALID_PARAMETER; + } + + // + // Delete the file of the specified extract FFS file. + // + SystemCommand = malloc ( + strlen (DEL_STR) + + strlen (DeleteFile) + + 1 + ); + if (SystemCommand == NULL) { + Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL); + return EFI_ABORTED; + } + + sprintf ( + SystemCommand, + DEL_STR, + DeleteFile + ); + + if (system (SystemCommand) != EFI_SUCCESS) { + free(SystemCommand); + return EFI_ABORTED; + } + free(SystemCommand); + + TemDir = getcwd (NULL, _MAX_PATH); + if (strlen (TemDir) + strlen(OS_SEP_STR) + strlen (TEMP_DIR_NAME) > _MAX_PATH - 1) { + Error("FMMT", 0, 1001, "The directory is too long.", ""); + return EFI_ABORTED; + } + strncat (TemDir, OS_SEP_STR, _MAX_PATH - strlen(TemDir) - 1); + strncat (TemDir, TEMP_DIR_NAME, _MAX_PATH - strlen(TemDir) - 1); + + mkdir(TemDir, S_IRWXU | S_IRWXG | S_IRWXO); + // + // Create a copy the new file. + // + + SystemCommand = malloc ( + strlen (COPY_STR) + + strlen (NewFile) + + strlen (DeleteFile) + + 1 + ); + if (SystemCommand == NULL) { + Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL); + return EFI_ABORTED; + } + + sprintf ( + SystemCommand, + COPY_STR, + NewFile, + DeleteFile + ); + + if (system (SystemCommand) != EFI_SUCCESS) { + free(SystemCommand); + return EFI_ABORTED; + } + free(SystemCommand); + + return EFI_SUCCESS; + +} + +/** + Converts ASCII characters to Unicode. + Assumes that the Unicode characters are only these defined in the ASCII set. + + String - Pointer to string that is written to FILE. + UniString - Pointer to unicode string + + The address to the ASCII string - same as AsciiStr. + +**/ +VOID +LibAscii2Unicode ( + IN CHAR8 *String, + OUT CHAR16 *UniString + ) +{ + while (*String != '\0') { + *(UniString++) = (CHAR16) *(String++); + } + // + // End the UniString with a NULL. + // + *UniString = '\0'; +} + + +EFI_STATUS +LibCreateGuidedSectionOriginalData( + IN CHAR8* FileIn, + IN CHAR8* ToolName, + IN CHAR8* FileOut +) +{ + CHAR8* SystemCommandFormatString; + CHAR8* SystemCommand; + + SystemCommandFormatString = NULL; + SystemCommand = NULL; + + if (FileIn == NULL || + ToolName == NULL || + FileOut == NULL) { + return EFI_INVALID_PARAMETER; + } + + // + // Delete the file of the specified extract FFS file. + // + SystemCommandFormatString = "%s -e \"%s\" -o \"%s\""; + + SystemCommand = malloc ( + strlen (SystemCommandFormatString) + + strlen (FileIn) + + strlen (ToolName) + + strlen (FileOut) + + 1 + ); + if (SystemCommand == NULL) { + Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL); + return EFI_ABORTED; + } + + sprintf ( + SystemCommand, + "%s -e \"%s\" -o \"%s\"", + ToolName, + FileIn, + FileOut + ); + + if (system (SystemCommand) != EFI_SUCCESS) { + printf("Command failed: %s\n", SystemCommand); + free(SystemCommand); + return EFI_ABORTED; + } + free(SystemCommand); + + return EFI_SUCCESS; +} + +/** + + This function convert the FV header's attribute to a string. The converted string + will be put into an INF file as the input of GenFV. + + @param[in] Attr FV header's attribute. + @param[out] InfFile InfFile contain FV header attribute information. + + @retval EFI_SUCCESS. + @retval EFI_INVLID_PARAMETER + @retval EFI_OUT_OF_RESOURCES + +**/ +EFI_STATUS +LibFvHeaderAttributeToStr ( + IN EFI_FVB_ATTRIBUTES_2 Attr, + IN FILE* InfFile +) +{ + CHAR8 *LocalStr; + + LocalStr = NULL; + + LocalStr = (CHAR8 *) malloc (1024 * 4); + + if (LocalStr == NULL) { + printf ("Memory allocate error!\n"); + return EFI_OUT_OF_RESOURCES; + } + + memset (LocalStr, '\0', 1024 * 4); + + if (Attr == 0 || InfFile == NULL) { + free (LocalStr); + return EFI_INVALID_PARAMETER; + } + + strncat (LocalStr, "[attributes] \n", sizeof("[attributes] \n")); + + if (Attr & EFI_FVB2_READ_DISABLED_CAP) { + strncat (LocalStr, "EFI_READ_DISABLED_CAP = TRUE \n", sizeof ("EFI_READ_DISABLED_CAP = TRUE \n")); + } + + if (Attr & EFI_FVB2_READ_ENABLED_CAP) { + strncat (LocalStr, "EFI_READ_ENABLED_CAP = TRUE \n", sizeof ("EFI_READ_ENABLED_CAP = TRUE \n")); + } + + if (Attr & EFI_FVB2_READ_STATUS) { + strncat (LocalStr, "EFI_READ_STATUS = TRUE \n", sizeof ("EFI_READ_STATUS = TRUE \n")); + } + + if (Attr & EFI_FVB2_WRITE_DISABLED_CAP) { + strncat (LocalStr, "EFI_WRITE_DISABLED_CAP = TRUE \n", sizeof ("EFI_WRITE_DISABLED_CAP = TRUE \n")); + } + + if (Attr & EFI_FVB2_WRITE_ENABLED_CAP) { + strncat (LocalStr, "EFI_WRITE_ENABLED_CAP = TRUE \n", sizeof ("EFI_WRITE_ENABLED_CAP = TRUE \n")); + } + + if (Attr & EFI_FVB2_WRITE_STATUS) { + strncat (LocalStr, "EFI_WRITE_STATUS = TRUE \n", sizeof ("EFI_WRITE_STATUS = TRUE \n")); + } + + if (Attr & EFI_FVB2_LOCK_CAP) { + strncat (LocalStr, "EFI_LOCK_CAP = TRUE \n", sizeof ("EFI_LOCK_CAP = TRUE \n")); + } + + if (Attr & EFI_FVB2_LOCK_STATUS) { + strncat (LocalStr, "EFI_LOCK_STATUS = TRUE \n", sizeof ("EFI_LOCK_STATUS = TRUE \n")); + } + + if (Attr & EFI_FVB2_STICKY_WRITE) { + strncat (LocalStr, "EFI_STICKY_WRITE = TRUE \n", sizeof ("EFI_STICKY_WRITE = TRUE \n")); + } + + if (Attr & EFI_FVB2_MEMORY_MAPPED) { + strncat (LocalStr, "EFI_MEMORY_MAPPED = TRUE \n", sizeof ("EFI_MEMORY_MAPPED = TRUE \n")); + } + + if (Attr & EFI_FVB2_ERASE_POLARITY) { + strncat (LocalStr, "EFI_ERASE_POLARITY = 1 \n", sizeof ("EFI_ERASE_POLARITY = 1 \n")); + } + + if (Attr & EFI_FVB2_READ_LOCK_CAP) { + strncat (LocalStr, "EFI_READ_LOCK_CAP = TRUE \n", sizeof ("EFI_READ_LOCK_CAP = TRUE \n")); + } + + if (Attr & EFI_FVB2_READ_LOCK_STATUS) { + strncat (LocalStr, "EFI_READ_LOCK_STATUS = TRUE \n", sizeof ("EFI_READ_LOCK_STATUS = TRUE \n")); + } + + if (Attr & EFI_FVB2_WRITE_LOCK_CAP) { + strncat (LocalStr, "EFI_WRITE_LOCK_CAP = TRUE \n", sizeof ("EFI_WRITE_LOCK_CAP = TRUE \n")); + } + + if (Attr & EFI_FVB2_WRITE_LOCK_STATUS) { + strncat (LocalStr, "EFI_WRITE_LOCK_STATUS = TRUE \n", sizeof ("EFI_WRITE_LOCK_STATUS = TRUE \n")); + } + + if (Attr & EFI_FVB2_LOCK_STATUS) { + strncat (LocalStr, "EFI_READ_LOCK_STATUS = TRUE \n", sizeof ("EFI_READ_LOCK_STATUS = TRUE \n")); + } + + // + // Alignment + // + if (Attr & EFI_FVB2_ALIGNMENT_1) { + strncat (LocalStr, "EFI_FVB2_ALIGNMENT_1 = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_1 = TRUE \n")); + } else if (Attr & EFI_FVB2_ALIGNMENT_2) { + strncat (LocalStr, "EFI_FVB2_ALIGNMENT_2 = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_2 = TRUE \n")); + } else if (Attr & EFI_FVB2_ALIGNMENT_4) { + strncat (LocalStr, "EFI_FVB2_ALIGNMENT_4 = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_4 = TRUE \n")); + } else if (Attr & EFI_FVB2_ALIGNMENT_8) { + strncat (LocalStr, "EFI_FVB2_ALIGNMENT_8 = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_8 = TRUE \n")); + } else if (Attr & EFI_FVB2_ALIGNMENT_16) { + strncat (LocalStr, "EFI_FVB2_ALIGNMENT_16 = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_16 = TRUE \n")); + } else if (Attr & EFI_FVB2_ALIGNMENT_32) { + strncat (LocalStr, "EFI_FVB2_ALIGNMENT_32 = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_32 = TRUE \n")); + } else if (Attr & EFI_FVB2_ALIGNMENT_64) { + strncat (LocalStr, "EFI_FVB2_ALIGNMENT_64 = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_64 = TRUE \n")); + } else if (Attr & EFI_FVB2_ALIGNMENT_128) { + strncat (LocalStr, "EFI_FVB2_ALIGNMENT_128 = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_128 = TRUE \n")); + } else if (Attr & EFI_FVB2_ALIGNMENT_256) { + strncat (LocalStr, "EFI_FVB2_ALIGNMENT_256 = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_256 = TRUE \n")); + } else if (Attr & EFI_FVB2_ALIGNMENT_512) { + strncat (LocalStr, "EFI_FVB2_ALIGNMENT_512 = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_512 = TRUE \n")); + } else if (Attr & EFI_FVB2_ALIGNMENT_1K) { + strncat (LocalStr, "EFI_FVB2_ALIGNMENT_1K = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_1K = TRUE \n")); + } else if (Attr & EFI_FVB2_ALIGNMENT_2K) { + strncat (LocalStr, "EFI_FVB2_ALIGNMENT_2K = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_2K = TRUE \n")); + } else if (Attr & EFI_FVB2_ALIGNMENT_4K) { + strncat (LocalStr, "EFI_FVB2_ALIGNMENT_4K = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_4K = TRUE \n")); + } else if (Attr & EFI_FVB2_ALIGNMENT_8K) { + strncat (LocalStr, "EFI_FVB2_ALIGNMENT_8K = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_8K = TRUE \n")); + } else if (Attr & EFI_FVB2_ALIGNMENT_16K) { + strncat (LocalStr, "EFI_FVB2_ALIGNMENT_16K = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_16K = TRUE \n")); + } else if (Attr & EFI_FVB2_ALIGNMENT_32K) { + strncat (LocalStr, "EFI_FVB2_ALIGNMENT_32K = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_32K = TRUE \n")); + } else if (Attr & EFI_FVB2_ALIGNMENT_64K) { + strncat (LocalStr, "EFI_FVB2_ALIGNMENT_64K = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_64K = TRUE \n")); + } else if (Attr & EFI_FVB2_ALIGNMENT_128K) { + strncat (LocalStr, "EFI_FVB2_ALIGNMENT_128K = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_128K = TRUE \n")); + } else if (Attr & EFI_FVB2_ALIGNMENT_256K) { + strncat (LocalStr, "EFI_FVB2_ALIGNMENT_256K = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_256K = TRUE \n")); + } else if (Attr & EFI_FVB2_ALIGNMENT_512K) { + strncat (LocalStr, "EFI_FVB2_ALIGNMENT_512K = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_512K = TRUE \n")); + } else if (Attr & EFI_FVB2_ALIGNMENT_1M) { + strncat (LocalStr, "EFI_FVB2_ALIGNMENT_1M = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_1M = TRUE \n")); + } else if (Attr & EFI_FVB2_ALIGNMENT_2M) { + strncat (LocalStr, "EFI_FVB2_ALIGNMENT_2M = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_2M = TRUE \n")); + } else if (Attr & EFI_FVB2_ALIGNMENT_4M) { + strncat (LocalStr, "EFI_FVB2_ALIGNMENT_4M = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_4M = TRUE \n")); + } else if (Attr & EFI_FVB2_ALIGNMENT_8M) { + strncat (LocalStr, "EFI_FVB2_ALIGNMENT_8M = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_8M = TRUE \n")); + } else if (Attr & EFI_FVB2_ALIGNMENT_16M) { + strncat (LocalStr, "EFI_FVB2_ALIGNMENT_16M = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_16M = TRUE \n")); + } else if (Attr & EFI_FVB2_ALIGNMENT_32M) { + strncat (LocalStr, "EFI_FVB2_ALIGNMENT_32M = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_32M = TRUE \n")); + } else if (Attr & EFI_FVB2_ALIGNMENT_64M) { + strncat (LocalStr, "EFI_FVB2_ALIGNMENT_64M = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_64M = TRUE \n")); + } else if (Attr & EFI_FVB2_ALIGNMENT_128M) { + strncat (LocalStr, "EFI_FVB2_ALIGNMENT_128M = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_128M = TRUE \n")); + } else if (Attr & EFI_FVB2_ALIGNMENT_256M) { + strncat (LocalStr, "EFI_FVB2_ALIGNMENT_256M = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_256M = TRUE \n")); + } else if (Attr & EFI_FVB2_ALIGNMENT_512M) { + strncat (LocalStr, "EFI_FVB2_ALIGNMENT_512M = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_512M = TRUE \n")); + } else if (Attr & EFI_FVB2_ALIGNMENT_1G) { + strncat (LocalStr, "EFI_FVB2_ALIGNMENT_1G = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_1G = TRUE \n")); + } else if (Attr & EFI_FVB2_ALIGNMENT_2G) { + strncat (LocalStr, "EFI_FVB2_ALIGNMENT_2G = TRUE \n", sizeof ("EFI_FVB2_ALIGNMENT_2G = TRUE \n")); + } + + if (fwrite (LocalStr, 1, (size_t) strlen (LocalStr), InfFile) != (size_t) strlen (LocalStr)) { + printf ("Error while writing data to %p file.", (void*)InfFile); + free (LocalStr); + return EFI_ABORTED; + } + + free (LocalStr); + + return EFI_SUCCESS; +} + + +/** + This function fill the FV inf files option field. + + @param[in] BlockMap FV header's attribute. + @param[out] InfFile InfFile contain FV header attribute information. + + @retval EFI_SUCCESS. + @retval EFI_INVLID_PARAMETER + +**/ +EFI_STATUS +LibFvHeaderOptionToStr ( + IN EFI_FIRMWARE_VOLUME_HEADER *FvHeader, + IN FILE* InfFile, + IN BOOLEAN IsRootFv +) +{ + CHAR8 *LocalStr; + CHAR8 *TempStr; + EFI_FV_BLOCK_MAP_ENTRY *BlockMap; + + LocalStr = NULL; + TempStr = NULL; + + if (FvHeader == NULL || InfFile == NULL) { + return EFI_INVALID_PARAMETER; + } + + // + // This section will not over 1024 bytes and each line will never over 128 bytes. + // + LocalStr = (CHAR8 *) malloc (1024); + TempStr = (CHAR8 *) malloc (128); + + if (LocalStr == NULL || + TempStr == NULL ) { + if (LocalStr != NULL) { + free (LocalStr); + } + if (TempStr != NULL) { + free (TempStr); + } + printf ("Memory allocate error! \n"); + return EFI_OUT_OF_RESOURCES; + } + + BlockMap = FvHeader->BlockMap; + memset (LocalStr, '\0', 1024); + memset (TempStr, '\0', 128); + + strncat (LocalStr, "[options] \n", sizeof("[Options] \n")); + + + snprintf (TempStr, 128, "EFI_BLOCK_SIZE = 0x%x \n", BlockMap->Length); + strncat (LocalStr, TempStr, strlen(TempStr)); + + if (IsRootFv) { + snprintf (TempStr, 128, "EFI_NUM_BLOCKS = 0x%x \n", BlockMap->NumBlocks); + strncat (LocalStr, TempStr, strlen(TempStr)); + } + + if (fwrite (LocalStr, 1, (size_t) strlen (LocalStr), InfFile) != (size_t) strlen (LocalStr)) { + printf ("Error while writing data to %p file.", (void*)InfFile); + free (LocalStr); + free (TempStr); + return EFI_ABORTED; + } + + free (LocalStr); + free (TempStr); + + return EFI_SUCCESS; +} + +/** + This function fill the FV inf files option field. + + @param[in] FfsName Ffs file path/name. + @param[out] InfFile InfFile contain FV header attribute information + @param[in] FirstIn Is the first time call this function? If yes, should create [files] section. + + @retval EFI_SUCCESS. + @retval EFI_INVLID_PARAMETER + +**/ +EFI_STATUS +LibAddFfsFileToFvInf ( + IN CHAR8 *FfsName, + IN FILE* InfFile, + IN BOOLEAN FirstIn +) +{ + + CHAR8 *LocalStr; + + LocalStr = NULL; + + if (FfsName == NULL || InfFile == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (strlen(FfsName) == 0) { + return EFI_SUCCESS; + } + + LocalStr = (CHAR8 *) malloc (_MAX_PATH); + + if (LocalStr == NULL) { + printf ("Memory allocate error! \n"); + return EFI_OUT_OF_RESOURCES; + } + + memset (LocalStr, '\0', _MAX_PATH); + + if (FirstIn) { + sprintf (LocalStr, "[files] \nEFI_FILE_NAME = %s \n", FfsName); + } else { + sprintf (LocalStr, "EFI_FILE_NAME = %s \n", FfsName); + } + + if (fwrite (LocalStr, 1, (size_t) strlen (LocalStr), InfFile) != (size_t) strlen (LocalStr)) { + printf ("Error while writing data to %p file.", (void*)InfFile); + free (LocalStr); + return EFI_ABORTED; + } + + free (LocalStr); + + return EFI_SUCCESS; +} + + +/** + Convert EFI file to PE or TE section + + @param[in] InputFilePath .efi file, it's optional unless process PE/TE section. + @param[in] Type PE or TE and UI/Version + @param[in] OutputFilePath .te or .pe file + @param[in] UiString String for generate UI section usage, this parameter is optional + unless Type is EFI_SECTION_USER_INTERFACE. + @param[in] VerString String for generate Version section usage, this parameter is optional + unless Type is EFI_SECTION_VERSION. + + @retval EFI_SUCCESS + +**/ +EFI_STATUS +LibCreateFfsSection ( + IN FV_INFORMATION *FvInFd, OPTIONAL + IN CHAR8* InputFilePath, OPTIONAL + IN CHAR8* Sections, OPTIONAL + IN UINT8 Type, + IN CHAR8* OutputFilePath, + IN CHAR8* UiString, OPTIONAL + IN CHAR8* VerString, OPTIONAL + IN CHAR8* GuidToolGuid, OPTIONAL + IN UINT16 GuidHeaderLength, + IN UINT16 GuidAttr, + IN CHAR8* CompressType OPTIONAL + ) +{ + //EFI_STATUS Status; + CHAR8* SystemCommandFormatString; + CHAR8* SystemCommand; + FILE *file; + UINT8 Buffer[4]; + int BitNum; + int Position; + UINT32 AlignmentValue; + // + // Workaround for static code checkers. + // Ensures the size of 'AlignmentStr' can hold all the digits of an + // unsigned 32-bit integer plus the size unit character. + // + char AlignmentStr[16]; + + SystemCommandFormatString = NULL; + SystemCommand = NULL; + strcpy(AlignmentStr,"1"); + // + // Call GenSec tool to generate FFS section. + // + + // + // -s SectionType. + // + if (Type != 0) { + switch (Type) { + // + // Process compression section + // + case EFI_SECTION_COMPRESSION: + SystemCommandFormatString = "GenSec -s %s -c %s \"%s\" -o \"%s\""; + SystemCommand = malloc ( + strlen (SystemCommandFormatString) + + strlen (mSectionTypeName[Type]) + + strlen (CompressType) + + strlen (InputFilePath) + + strlen (OutputFilePath) + + 1 + ); + if (SystemCommand == NULL) { + Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL); + return EFI_ABORTED; + } + sprintf ( + SystemCommand, + "GenSec -s %s -c %s \"%s\" -o \"%s\"", + mSectionTypeName[Type], + CompressType, + InputFilePath, + OutputFilePath + ); + + if (system (SystemCommand) != EFI_SUCCESS) { + free(SystemCommand); + return EFI_ABORTED; + } + free(SystemCommand); + break; + + // + // Process GUID defined section + // + case EFI_SECTION_GUID_DEFINED: + SystemCommandFormatString = "GenSec -s %s -g %s \"%s\" -o \"%s\" -r %s -r %s -l %d"; + SystemCommand = malloc ( + strlen (SystemCommandFormatString) + + strlen (mSectionTypeName[Type]) + + strlen (GuidToolGuid) + + strlen (InputFilePath) + + strlen (OutputFilePath) + + strlen (mGuidSectionAttr[GuidAttr&0x01]) + + strlen (mGuidSectionAttr[GuidAttr&0x02]) + + 4 + + 1 + ); + if (SystemCommand == NULL) { + Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL); + return EFI_ABORTED; + } + sprintf ( + SystemCommand, + "GenSec -s %s -g %s \"%s\" -o \"%s\" -r %s -r %s -l %d", + mSectionTypeName[Type], + GuidToolGuid, + InputFilePath, + OutputFilePath, + mGuidSectionAttr[GuidAttr&0x01], + mGuidSectionAttr[GuidAttr&0x02], + GuidHeaderLength + ); + + if (system (SystemCommand) != EFI_SUCCESS) { + free(SystemCommand); + return EFI_ABORTED; + } + free(SystemCommand); + break; + + case EFI_SECTION_FIRMWARE_VOLUME_IMAGE: + + SystemCommandFormatString = "GenSec -s %s \"%s\" -o \"%s\""; + SystemCommand = malloc ( + strlen (SystemCommandFormatString) + + strlen (mSectionTypeName[Type]) + + strlen (InputFilePath) + + strlen (OutputFilePath) + + 1 + ); + if (SystemCommand == NULL) { + Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL); + return EFI_ABORTED; + } + sprintf ( + SystemCommand, + "GenSec -s %s \"%s\" -o \"%s\"", + mSectionTypeName[Type], + InputFilePath, + OutputFilePath + ); + + if (system (SystemCommand) != EFI_SUCCESS) { + free(SystemCommand); + return EFI_ABORTED; + } + free(SystemCommand); + break; + + default: + Error ("FMMT", 0, 0003, "Please specify the section type while call GenSec tool.", NULL); + return EFI_UNSUPPORTED; + } + } else { + // + // Create Dummy section. + // + file = fopen(InputFilePath, "rb"); + if (file == NULL) { + Error(NULL, 0, 0001, "Error opening the file", InputFilePath); + return EFI_INVALID_PARAMETER; + } + // The Section Struct, 3 bits for Size, then 1 bit for Type + if (fread(Buffer, 1, (size_t)(4), file) != (size_t)(4)) { + fclose(file); + return EFI_ABORTED; + } + if (*(Buffer + 3) == EFI_SECTION_FIRMWARE_VOLUME_IMAGE) { + // The Section Struct, if size is not 0xFFFF, the length is 4 + Position = 4; + // If Size is 0xFFFFFF then ExtendedSize contains the size of the section + if ((*Buffer == 0xFF) && (*(Buffer + 1) == 0xFF) && (*(Buffer + 2) == 0xFF)) { + Position = 8; + } + //Per EFI_FIRMWARE_VOLUME_HEADER struct, 0x2E bit is EFI_FVB_ATTRIBUTES_2 attr + fseek(file, 0x2E + Position, SEEK_SET); + BitNum = fgetc(file); + AlignmentValue = 1 << (BitNum & 0x1F); + if (AlignmentValue >= 0x400){ + if (AlignmentValue >= 0x10000){ + strcpy(AlignmentStr,"64K"); + } + else{ + sprintf(AlignmentStr, "%d", AlignmentValue/0x400); + strcat(AlignmentStr, "K"); + } + } + else{ + sprintf(AlignmentStr, "%d", AlignmentValue); + } + strcpy(FvInFd->AlignmentStr, AlignmentStr); + } + fclose(file); + SystemCommandFormatString = "GenSec \"%s\" -o \"%s\" --sectionalign %s"; + SystemCommand = malloc ( + strlen (SystemCommandFormatString) + + strlen (InputFilePath) + + strlen (OutputFilePath) + + 4 + // Alignment maximum length + 1 + ); + if (SystemCommand == NULL) { + Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL); + return EFI_ABORTED; + } + sprintf ( + SystemCommand, + "GenSec \"%s\" -o \"%s\" --sectionalign %s", + InputFilePath, + OutputFilePath, + AlignmentStr + ); + + if (system (SystemCommand) != EFI_SUCCESS) { + free(SystemCommand); + return EFI_ABORTED; + } + free(SystemCommand); + + } + + return EFI_SUCCESS; +} + +/** + Encapsulate FFSs to FV + + @param[in] InputFilePath Section file will be read into this FFS file. This option is required. + @param[in] OutputFilePath The created PI firmware file name. This option is required. + @param[in] BlockSize BlockSize is one HEX or DEC format value required by FV image. + @param[in] FileTakeSize + + @retval EFI_SUCCESS + +**/ +EFI_STATUS +LibEncapsulateFfsToFv ( + IN CHAR8* InfFilePath, + IN CHAR8* InputFFSs, + IN CHAR8* OutputFilePath, + IN CHAR8* FvGuidName, + IN BOOLEAN IsLargeFile + ) +{ + + CHAR8* SystemCommandFormatString; + CHAR8* SystemCommand; + CHAR8* FfsGuid = "8c8ce578-8a3d-4f1c-9935-896185c32dd3"; + + if (IsLargeFile == TRUE) { + FfsGuid = "5473c07a-3dcb-4dca-bd6f-1e9689e7349a"; + } + + SystemCommandFormatString = NULL; + SystemCommand = NULL; + + if (OutputFilePath == NULL || + InfFilePath == NULL ) { + return EFI_INVALID_PARAMETER; + } + + if (InfFilePath != NULL) { + if (FvGuidName == NULL) { + SystemCommandFormatString = "GenFv -i \"%s\" -g %s -o \"%s\""; + + SystemCommand = malloc ( + strlen (SystemCommandFormatString) + + strlen (InfFilePath) + + strlen (FfsGuid) + + strlen (OutputFilePath) + + 1 + ); + if (SystemCommand == NULL) { + Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL); + return EFI_ABORTED; + } + sprintf ( + SystemCommand, + "GenFv -i \"%s\" -g %s -o \"%s\"", + InfFilePath, // -i + FfsGuid, // -g + OutputFilePath // -o + ); + + if (system (SystemCommand) != EFI_SUCCESS) { + free(SystemCommand); + return EFI_ABORTED; + } + + free(SystemCommand); + } else { + // + // Have FvGuidName in it. + // + SystemCommandFormatString = "GenFv -i \"%s\" -g %s -o \"%s\" --FvNameGuid %s"; + + SystemCommand = malloc ( + strlen (SystemCommandFormatString) + + strlen (InfFilePath) + + strlen (FfsGuid) + + strlen (OutputFilePath) + + strlen (FvGuidName) + + 1 + ); + if (SystemCommand == NULL) { + Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL); + return EFI_ABORTED; + } + sprintf ( + SystemCommand, + "GenFv -i \"%s\" -g %s -o \"%s\" --FvNameGuid %s", + InfFilePath, // -i + FfsGuid, // -g + OutputFilePath, // -o + FvGuidName // FvNameGuid + ); + + if (system (SystemCommand) != EFI_SUCCESS) { + free(SystemCommand); + return EFI_ABORTED; + } + free(SystemCommand); + + } + } + + return EFI_SUCCESS; +} + + +/** + + Convert a GUID to a string. + + + @param[in] Guid - Pointer to GUID to print. + + + @return The string after convert. + +**/ +CHAR8 * +LibFmmtGuidToStr ( + IN EFI_GUID *Guid +) +{ + CHAR8 * Buffer; + + Buffer = NULL; + + if (Guid == NULL) { + printf ("The guid is NULL while convert guid to string! \n"); + return NULL; + } + + Buffer = (CHAR8 *) malloc (36 + 1); + + if (Buffer == NULL) { + printf ("Error while allocate resource! \n"); + return NULL; + } + memset (Buffer, '\0', 36 + 1); + + sprintf ( + Buffer, + "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", + Guid->Data1, + Guid->Data2, + Guid->Data3, + Guid->Data4[0], + Guid->Data4[1], + Guid->Data4[2], + Guid->Data4[3], + Guid->Data4[4], + Guid->Data4[5], + Guid->Data4[6], + Guid->Data4[7] + ); + + return Buffer; +} + + +/** + Encapsulate an FFS section file to an FFS file. + + @param[in] Type Type is one FV file type defined in PI spec, which is one type of EFI_FV_FILETYPE_RAW, EFI_FV_FILETYPE_FREEFORM, + EFI_FV_FILETYPE_SECURITY_CORE, EFI_FV_FILETYPE_PEIM, EFI_FV_FILETYPE_PEI_CORE, EFI_FV_FILETYPE_DXE_CORE, + EFI_FV_FILETYPE_DRIVER, EFI_FV_FILETYPE_APPLICATION, EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER, + EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE. This option is required. + @param[in] InputFilePath Section file will be read into this FFS file. This option is required. + @param[in] OutputFilePath The created PI firmware file name. This option is required. + @param[in] FileGuid FileGuid is the unique identifier for this FFS file. This option is required. + @param[in] Fixed Set fixed attribute in FFS file header to indicate that the file may not be moved from its present location. + @param[in] SectionAlign FileAlign specifies FFS file alignment, which only support the following alignment: 8,16,128,512,1K,4K,32K,64K. + + @retval EFI_SUCCESS + +**/ +EFI_STATUS +LibEncapSectionFileToFFS ( + IN UINT8 Type, + IN CHAR8* InputFilePath, + IN CHAR8* OutputFilePath, + IN EFI_GUID FileGuid, + IN BOOLEAN Fixed, + IN CHAR8* SectionAlign + ) +{ + CHAR8* SystemCommandFormatString; + CHAR8* SystemCommand; + CHAR8* GuidStr; + + + SystemCommandFormatString = NULL; + SystemCommand = NULL; + GuidStr = NULL; + + GuidStr = LibFmmtGuidToStr(&FileGuid); + + if (GuidStr == NULL) { + return EFI_ABORTED; + } + + + // + // -t Type + // -i InputFilePath + // -o OutPutFilePath + // -g FileGuid + // -x Fixed + // -n SectionAlign + // + + if (Fixed) { + SystemCommandFormatString = "GenFfs -t %s -i \"%s\" -g %s -x -o \"%s\" -a %s"; + SystemCommand = malloc ( + strlen (SystemCommandFormatString) + + strlen (mFfsFileType[Type]) + + strlen (InputFilePath) + + strlen (GuidStr) + + strlen (OutputFilePath) + + 4 + + 1 + ); + if (SystemCommand == NULL) { + Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL); + free (GuidStr); + return EFI_ABORTED; + } + sprintf ( + SystemCommand, + "GenFfs -t %s -i \"%s\" -g %s -x -o \"%s\" -a %s", + mFfsFileType[Type], // -t + InputFilePath, // -i + GuidStr, // -g + OutputFilePath, // -o + SectionAlign + ); + + free (GuidStr); + if (system (SystemCommand) != EFI_SUCCESS) { + free(SystemCommand); + return EFI_ABORTED; + } + free(SystemCommand); + } else { + SystemCommandFormatString = "GenFfs -t %s -i \"%s\" -g %s -o \"%s\" -a %s"; + SystemCommand = malloc ( + strlen (SystemCommandFormatString) + + strlen (mFfsFileType[Type]) + + strlen (InputFilePath) + + strlen (GuidStr) + + strlen (OutputFilePath) + + 4 + + 1 + ); + if (SystemCommand == NULL) { + free (GuidStr); + Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL); + return EFI_ABORTED; + } + sprintf ( + SystemCommand, + "GenFfs -t %s -i \"%s\" -g %s -o \"%s\" -a %s", + mFfsFileType[Type], // -t + InputFilePath, // -i + GuidStr, // -g + OutputFilePath, // -o + SectionAlign + ); + + free (GuidStr); + if (system (SystemCommand) != EFI_SUCCESS) { + free(SystemCommand); + return EFI_ABORTED; + } + free(SystemCommand); + } + + + return EFI_SUCCESS; +} + +EFI_STATUS +LibCreateNewFdCopy( + IN CHAR8* OldFd, + IN CHAR8* NewFd +) +{ + + FILE* NewFdFile; + FILE* OldFdFile; + CHAR8 *NewFdDir; + CHAR8 *OldFdDir; + UINT64 FdLength; + UINT32 Count; + BOOLEAN UseNewDirFlag; + CHAR8 *Buffer; + + NewFdFile = NULL; + OldFdFile = NULL; + NewFdDir = NULL; + OldFdDir = NULL; + Count = 0; + UseNewDirFlag = FALSE; + + if (OldFd == NULL || + NewFd == NULL) { + return EFI_INVALID_PARAMETER; + } + + + NewFdDir = getcwd (NULL, _MAX_PATH); + + Count = strlen(NewFdDir); + + if (strlen(NewFd) > Count) { + + do { + if (NewFdDir[Count-1] == NewFd[Count-1]) { + Count--; + } else { + if (strlen(NewFdDir) + strlen (OS_SEP_STR) + strlen (NewFd) > _MAX_PATH -1) { + return EFI_ABORTED; + } + strncat (NewFdDir,OS_SEP_STR, _MAX_PATH - strlen (NewFdDir) -1); + strncat (NewFdDir,NewFd, _MAX_PATH - strlen (NewFdDir) -1); + UseNewDirFlag = TRUE; + break; + } + + } while (Count != 1); + + }else { + if (strlen(NewFdDir) + strlen (OS_SEP_STR) + strlen (NewFd) > _MAX_PATH -1) { + return EFI_ABORTED; + } + strncat (NewFdDir,OS_SEP_STR, _MAX_PATH - strlen (NewFdDir) -1); + strncat (NewFdDir,NewFd, _MAX_PATH - strlen (NewFdDir) -1); + UseNewDirFlag = TRUE; + } + + if (UseNewDirFlag) { + NewFdFile = fopen (NewFdDir, "wb+"); + if (NewFdFile == NULL) { + NewFdFile = fopen (NewFd, "wb+"); + } + } else { + NewFdFile = fopen (NewFd, "wb+"); + } + // support network path file + if (OldFd[0] == '\\' && OldFd[1] == '\\') { + OldFdFile = fopen (OldFd, "rb"); + } else { + UseNewDirFlag = FALSE; + + OldFdDir = getcwd (NULL, _MAX_PATH); + + Count = strlen(OldFdDir); + + if (strlen(OldFd) > Count) { + + do { + if (OldFdDir[Count-1] == OldFd[Count-1]) { + Count--; + } else { + if (strlen(OldFdDir) + strlen (OS_SEP_STR) + strlen (OldFd) > _MAX_PATH -1) { + if (NewFdFile != NULL) { + fclose(NewFdFile); + } + return EFI_ABORTED; + } + strncat (OldFdDir,OS_SEP_STR, _MAX_PATH - strlen (OldFdDir) -1); + strncat (OldFdDir,OldFd, _MAX_PATH - strlen (OldFdDir) -1); + UseNewDirFlag = TRUE; + break; + } + + } while (Count != 1); + + }else { + if (strlen(OldFdDir) + strlen (OS_SEP_STR) + strlen (OldFd) > _MAX_PATH -1) { + if (NewFdFile != NULL) { + fclose(NewFdFile); + } + return EFI_ABORTED; + } + strncat (OldFdDir,OS_SEP_STR, _MAX_PATH - strlen (OldFdDir) -1); + strncat (OldFdDir,OldFd, _MAX_PATH - strlen (OldFdDir) -1); + UseNewDirFlag = TRUE; + } + + if (UseNewDirFlag) { + OldFdFile = fopen (OldFdDir, "rb+"); + if (OldFdFile == NULL) { + OldFdFile = fopen (OldFd, "rb+"); + } + } else { + OldFdFile = fopen (OldFd, "rb+"); + } + } + + if (NewFdFile == NULL) { + Error ("FMMT", 0, 0003, "error Open FD file", "cannot Create a new FD file."); + if (OldFdFile != NULL) { + fclose (OldFdFile); + } + return EFI_ABORTED; + } + + if (OldFdFile == NULL) { + Error ("FMMT", 0, 0003, "error Open FD file", "cannot Create a new FD file."); + if (NewFdFile != NULL) { + fclose (NewFdFile); + } + return EFI_ABORTED; + } + + + fseek(OldFdFile,0,SEEK_SET); + fseek(OldFdFile,0,SEEK_END); + + FdLength = ftell(OldFdFile); + + fseek(OldFdFile,0,SEEK_SET); + fseek(NewFdFile,0,SEEK_SET); + + Buffer = malloc ((size_t)FdLength); + + if (Buffer == NULL) { + fclose(OldFdFile); + fclose(NewFdFile); + return EFI_ABORTED; + } + + if (fread (Buffer, 1, (size_t) FdLength, OldFdFile) != (size_t) FdLength) { + Error ("FMMT", 0, 0003, "error reading FD file %s", OldFd); + free (Buffer); + fclose(OldFdFile); + fclose(NewFdFile); + return EFI_ABORTED; + } + + if (fwrite (Buffer, 1, (size_t) FdLength, NewFdFile) != (size_t) FdLength) { + Error ("FMMT", 0, 0004, "error writing FD file", "cannot Create a new FD file."); + free (Buffer); + fclose(OldFdFile); + fclose(NewFdFile); + return EFI_ABORTED; + } + free (Buffer); + fclose(OldFdFile); + fclose (NewFdFile); + + return EFI_SUCCESS; +} + + +/** + This function will assemble the filename, directory and extend and return the combined string. + Like FileName = file1, Dir = c:\temp extend = txt, the output string will be: + c:\temp\file1.txt. + + @param[in] + @param[in] + @param[in] + + @retrun A string contain all the input information. + +**/ +CHAR8 * +LibFilenameStrExtended ( + IN CHAR8 *FileName, + IN CHAR8 *Dir, + IN CHAR8 *Extend +) +{ + CHAR8 *RetStr; + + RetStr = NULL; + + if (FileName == NULL) { + return NULL; + } + + if (Dir == NULL || Extend == NULL) { + return FileName; + } + + RetStr = (CHAR8 *) malloc (strlen (FileName) + + strlen (Dir) + + strlen (Extend) + + strlen ("%s%s.%s") + + 1); + if (RetStr == NULL) { + Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL); + return NULL; + } + + memset (RetStr, '\0', (strlen (FileName) + strlen (Dir) + strlen (Extend) + strlen ("%s%s.%s") + 1)); + + sprintf (RetStr, "%s%s.%s", Dir, FileName, Extend); + + return RetStr; +} + +/** + Delete a directory and files in it. + + @param[in] DirName Name of the directory need to be deleted. + + @return EFI_INVALID_PARAMETER + @return EFI_SUCCESS +**/ +EFI_STATUS +LibRmDir ( + IN CHAR8* DirName +) +{ + CHAR8* SystemCommand; + + SystemCommand = NULL; + + + if (DirName == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (access (DirName, 0) == -1){ + return EFI_SUCCESS; + } + + // + // Delete a directory and files in it. + // + + SystemCommand = malloc ( + strlen (RMDIR_STR) + + strlen (DirName) + + 1 + ); + if (SystemCommand == NULL) { + Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL); + return EFI_ABORTED; + } + + sprintf ( + SystemCommand, + RMDIR_STR, + DirName + ); + + if (system (SystemCommand) != EFI_SUCCESS) { + free(SystemCommand); + return EFI_ABORTED; + } + free(SystemCommand); + + return EFI_SUCCESS; +} + +EFI_STATUS +LibGenExtFile( +CONST EFI_FIRMWARE_VOLUME_EXT_HEADER *ExtPtr, +FILE *InfFile +) +{ + CHAR8 *TempDir; + FILE *ExtFile; + CHAR8 OutputExtFile[_MAX_PATH]; + CHAR8 Line[512]; + size_t Len; + + TempDir = NULL; + + TempDir = getcwd(NULL, _MAX_PATH); + if (strlen (TempDir) + strlen(OS_SEP_STR) + strlen (TEMP_DIR_NAME) > _MAX_PATH - 1) { + Error("FMMT", 0, 1001, "The directory is too long.", ""); + return EFI_ABORTED; + } + strncat (TempDir, OS_SEP_STR, _MAX_PATH - strlen (TempDir) -1); + strncat (TempDir, TEMP_DIR_NAME, _MAX_PATH - strlen (TempDir) -1); + + mkdir(TempDir, S_IRWXU | S_IRWXG | S_IRWXO); + + sprintf( + Line, + "%c%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X%d.ext", + OS_SEP, + (unsigned)ExtPtr->FvName.Data1, + ExtPtr->FvName.Data2, + ExtPtr->FvName.Data3, + ExtPtr->FvName.Data4[0], + ExtPtr->FvName.Data4[1], + ExtPtr->FvName.Data4[2], + ExtPtr->FvName.Data4[3], + ExtPtr->FvName.Data4[4], + ExtPtr->FvName.Data4[5], + ExtPtr->FvName.Data4[6], + ExtPtr->FvName.Data4[7], + ExtPtr->ExtHeaderSize + ); + if (strlen (TempDir) + strlen (Line) > _MAX_PATH - 1) { + Error("FMMT", 0, 1001, "The directory is too long.", ""); + return EFI_ABORTED; + } + strncpy (OutputExtFile, TempDir, _MAX_PATH - 1); + OutputExtFile[_MAX_PATH - 1] = 0; + strncat (OutputExtFile, Line, _MAX_PATH - strlen (OutputExtFile) - 1); + + + ExtFile = fopen(OutputExtFile, "wb+"); + if (ExtFile == NULL) { + return EFI_ABORTED; + } + + if (fwrite(ExtPtr, 1, ExtPtr->ExtHeaderSize, ExtFile) != ExtPtr->ExtHeaderSize) { + fclose(ExtFile); + return EFI_ABORTED; + } + + fclose(ExtFile); + + strcpy (Line, "EFI_FV_EXT_HEADER_FILE_NAME = "); + if (strlen (Line) + strlen (OutputExtFile) + 1 > sizeof(Line) / sizeof (CHAR8) - 1) { + Error("FMMT", 0, 1001, "The directory is too long.", ""); + return EFI_ABORTED; + } + strncat (Line, OutputExtFile, sizeof(Line) / sizeof (CHAR8) - strlen (Line) - 1); + strncat (Line, "\n", sizeof(Line) / sizeof (CHAR8) - strlen (Line) - 1); + Len = strlen(Line); + if (fwrite(Line, 1, Len, InfFile) != Len) { + return EFI_ABORTED; + } + + return EFI_SUCCESS; +} + +/** + Delete a file. + + @param[in] FileName Name of the file need to be deleted. + + @return EFI_INVALID_PARAMETER + @return EFI_SUCCESS +**/ +EFI_STATUS +LibFmmtDeleteFile( + IN CHAR8 *FileName +) +{ + CHAR8* SystemCommand; + CHAR8 *TemDir; + + SystemCommand = NULL; + TemDir = NULL; + + + if (FileName == NULL) { + return EFI_INVALID_PARAMETER; + } + + // if the FileName is not in TemDir, we don't need to delete. + TemDir = getcwd (NULL, _MAX_PATH); + if (*(TemDir + strlen(TemDir) - 1) == OS_SEP) { + *(TemDir + strlen(TemDir) - 1) = '\0'; + } + if (strlen (TemDir) + strlen (OS_SEP_STR) + strlen (TEMP_DIR_NAME) > _MAX_PATH - 1) { + Error (NULL, 0, 2000, "Path: The current path is too long.", NULL); + return EFI_ABORTED; + } + strncat (TemDir, OS_SEP_STR, _MAX_PATH - strlen (TemDir) - 1); + strncat (TemDir, TEMP_DIR_NAME, _MAX_PATH - strlen (TemDir) - 1); + if (strstr(FileName, TemDir) == NULL) { + return EFI_SUCCESS; + } + + // + // Delete a file + // + + SystemCommand = malloc ( + strlen (DEL_STR) + + strlen (FileName) + + 1 + ); + if (SystemCommand == NULL) { + Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL); + return EFI_ABORTED; + } + + sprintf ( + SystemCommand, + DEL_STR, + FileName + ); + + if (system (SystemCommand) != EFI_SUCCESS) { + free(SystemCommand); + return EFI_ABORTED; + } + free(SystemCommand); + + return EFI_SUCCESS; + +} + + +/** + + Free the whole Fd data structure. + + @param[in] Fd The pointer point to the Fd data structure. + +**/ +VOID +LibFmmtFreeFd ( + FIRMWARE_DEVICE *Fd + ) +{ + FV_INFORMATION *CurrentFv; + FV_INFORMATION *TempFv; + ENCAP_INFO_DATA *EncapData1; + ENCAP_INFO_DATA *EncapData2; + + CurrentFv = NULL; + TempFv = NULL; + EncapData1 = NULL; + EncapData2 = NULL; + + if (Fd == NULL) { + return; + } + + CurrentFv = Fd->Fv; + + do { + TempFv = CurrentFv; + CurrentFv = CurrentFv->FvNext; + + free (TempFv->FvHeader); + + if (TempFv->FvExtHeader != NULL) { + free (TempFv->FvExtHeader); + } + if (TempFv->FvUiName) { + free(TempFv->FvUiName); + } + + // + // Free encapsulate data; + // + EncapData1 = TempFv->EncapData; + + while (EncapData1 != NULL) { + + EncapData2 = EncapData1; + EncapData1 = EncapData1->NextNode; + + if (EncapData2->Data != NULL) { + free (EncapData2->Data); + } + if (EncapData2->FvExtHeader != NULL) { + free(EncapData2->FvExtHeader); + } + free (EncapData2); + EncapData2 = NULL; + } + + EncapData1 = NULL; + + free (TempFv); + TempFv = NULL; + + } while (CurrentFv != NULL); + + CurrentFv = NULL; + free (Fd); + Fd = NULL; + + return; +} + +/** + Generate the compressed section with specific type. + Type could be EFI_STANDARD_COMPRESSION or EFI_NOT_COMPRESSED + + @param[in] InputFileName File name of the raw data. + @param[in] OutPutFileName File name of the sectioned data. + @param[in] CompressionType The compression type. + + @return EFI_INVALID_PARAMETER + @return EFI_ABORTED + @return EFI_OUT_OF_RESOURCES + @return EFI_SUCCESS + +**/ +EFI_STATUS +LibGenCompressedSection ( + CHAR8 *InputFileName, + CHAR8 *OutPutFileName, + UINT8 CompressionType +) +{ + //FILE *UnCompressFile; + //FILE *CompressedFile; + //VOID *UnCompressedBuffer; + //VOID *CompressedBuffer; + //UINT32 UnCompressedSize; + //UINT32 CompressedSize; + //CHAR8 *TempName; + //CHAR8 *TemDir; + //EFI_STATUS Status; + + //UnCompressFile = NULL; + //CompressedFile = NULL; + //UnCompressedBuffer = NULL; + //CompressedBuffer = NULL; + //TempName = NULL; + //TemDir = NULL; + //UnCompressedSize = 0; + //CompressedSize = 0; + + if ( InputFileName == NULL || + OutPutFileName == NULL) { + printf ("Error while generate compressed section!\n"); + return EFI_INVALID_PARAMETER; + } + + if (CompressionType == EFI_STANDARD_COMPRESSION) { + /* + + UnCompressFile = fopen (InputFileName, "rb"); + if (UnCompressFile == NULL) { + printf ("Error while open file %s \n", InputFileName); + return EFI_ABORTED; + } + + TemDir = _getcwd (NULL, _MAX_PATH); + sprintf(TemDir, "%s\\%s", TemDir, TEMP_DIR_NAME); + + TempName= LibFilenameStrExtended (strrchr(CloneString (tmpnam (NULL)),'\\'), TemDir, "comp"); + + CompressedFile = fopen (TempName, "wb+"); + if (CompressedFile == NULL) { + printf ("Error while open file %s \n", TempName); + return EFI_ABORTED; + } + + // + // Get the original file size; + // + fseek(UnCompressFile,0,SEEK_SET); + fseek(UnCompressFile,0,SEEK_END); + + UnCompressedSize = ftell(UnCompressFile); + + fseek(UnCompressFile,0,SEEK_SET); + + UnCompressedBuffer = malloc (UnCompressedSize); + + if (UnCompressedBuffer == NULL) { + printf("Error while allocate memory! \n"); + return EFI_OUT_OF_RESOURCES; + } + + CompressedBuffer = malloc (UnCompressedSize); + + if (CompressedBuffer == NULL) { + printf("Error while allocate memory! \n"); + return EFI_OUT_OF_RESOURCES; + } + + if (fread (UnCompressedBuffer, 1, (size_t) UnCompressedSize, UnCompressFile) == (size_t) UnCompressedSize) { + CompressedSize = UnCompressedSize; + + Status = EfiCompress ( UnCompressedBuffer, + UnCompressedSize, + CompressedBuffer, + &CompressedSize); + + if (EFI_ERROR(Status)) { + printf("Error while do compress operation! \n"); + return EFI_ABORTED; + } + + if (CompressedSize > UnCompressedSize) { + printf("Error while do compress operation! \n"); + return EFI_ABORTED; + } + } else { + printf("Error while reading file %s! \n", InputFileName); + return EFI_ABORTED; + } + + // + // Write the compressed data into output file + // + if (fwrite (CompressedBuffer, 1, (size_t) CompressedSize, CompressedFile) != (size_t) CompressedSize) { + Error ("FMMT", 0, 0004, "error writing %s file", OutPutFileName); + fclose(UnCompressFile); + fclose (CompressedFile); + return EFI_ABORTED; + } + + fclose(UnCompressFile); + fclose (CompressedFile); + */ + + // + // Call GenSec tool to generate the compressed section. + // + LibCreateFfsSection(NULL, InputFileName, NULL, EFI_SECTION_COMPRESSION, OutPutFileName, NULL, NULL, NULL, 0, 0, "PI_STD"); + + } else if (CompressionType == EFI_NOT_COMPRESSED) { + + LibCreateFfsSection(NULL, InputFileName, NULL, EFI_SECTION_COMPRESSION, OutPutFileName, NULL, NULL, NULL, 0, 0, "PI_NONE"); + + } else { + printf ("Error while generate compressed section, unknown compression type! \n"); + return EFI_INVALID_PARAMETER; + } + + + return EFI_SUCCESS; +} + +EFI_STATUS +LibEncapNewFvFile( + IN FV_INFORMATION *FvInFd, + IN CHAR8 *TemDir, + IN ENCAP_INFO_DATA *CurrentEncapData, + IN UINT32 Level_Break, + OUT FFS_INFORMATION **OutputFile +) +{ + EFI_STATUS Status; + UINT32 ParentType; + UINT8 ParentLevel; + UINT32 Type; + UINT8 Level; + CHAR8 *InfFileName; + FILE *InfFile; + ENCAP_INFO_DATA *LocalEncapData; + ENCAP_INFO_DATA *LocalEncapDataTemp; + ENCAP_INFO_DATA *LocalEncapDataNext; + BOOLEAN FfsFoundFlag; + UINT32 Index; + UINT32 OuterIndex; + CHAR8 *ExtractionTool; + BOOLEAN IsLastLevelFfs; + BOOLEAN IsLeafFlagIgnore; + BOOLEAN FirstInFlag; + BOOLEAN OutputFileNameListFlag; + CHAR8 *InputFileName; + CHAR8 *OutputFileName; + FFS_INFORMATION *OutputFileNameList; + FFS_INFORMATION *ChildFileNameList; + FFS_INFORMATION *NewFileNameList; + CHAR8 *FvGuidName; + UINT16 GuidAttributes; + UINT16 GuidDataOffset; + BOOLEAN IsRootFv; + BOOLEAN IsLargeFile; + UINT32 EncapFvStart; + UINT32 EncapFvIndex; + CHAR8 *TmpFileName; + FILE *TmpFile; + FILE *InputFile; + FILE *OutFile; + UINT32 InputFileSize; + UINT32 OutputFileSize; + UINT32 LargeFileSize; + UINT8 *Buffer = NULL; + UINT8 SectionHeader[4] = { 0x00, 0x00, 0x00, 0x00 }; + UINT32 Id; + UINT32 SubFvId; + UINT32 header; + UINT8 AlignN; + UINT8 AlignV[1] = {0xFF}; + AlignN = 0; + Id = 0; + InputFileSize = 0; + EncapFvIndex = 0; + Index = 0; + OuterIndex = 0; + ParentType = 0; + ParentLevel = 0; + Type = 0; + Level = 0; + SubFvId = 0; + FfsFoundFlag = FALSE; + LocalEncapDataTemp = NULL; + LocalEncapDataNext = NULL; + ExtractionTool = NULL; + InputFileName = NULL; + OutputFileName = NULL; + IsLastLevelFfs = TRUE; + IsLeafFlagIgnore = FALSE; + FirstInFlag = TRUE; + FvGuidName = NULL; + OutputFileNameListFlag = TRUE; + IsLargeFile = FALSE; + OutputFileSize = 0; + LargeFileSize = 0x1000000; + + + OutputFileNameList = (FFS_INFORMATION *)malloc(sizeof(FV_INFORMATION)); + if (OutputFileNameList == NULL) { + Error ("FMMT", 0, 0004, "Out of resource, memory allocation failed! \n", ""); + return EFI_OUT_OF_RESOURCES; + } + OutputFileNameList->FFSName = NULL; + OutputFileNameList->InFvId = 0; + OutputFileNameList->IsFFS = FALSE; + OutputFileNameList->ParentLevel = 0; + OutputFileNameList->Next = NULL; + OutputFileNameList->UiNameSize = 0; + OutputFileNameList->Depex = NULL; + OutputFileNameList->DepexLen = 0; + OutputFileNameList->FfsFoundFlag = FALSE; + + ChildFileNameList = (FFS_INFORMATION *)malloc(sizeof(FV_INFORMATION)); + if (ChildFileNameList == NULL) { + Error ("FMMT", 0, 0004, "Out of resource, memory allocation failed! \n", ""); + return EFI_OUT_OF_RESOURCES; + } + ChildFileNameList->FFSName = NULL; + ChildFileNameList->InFvId = 0; + ChildFileNameList->ParentLevel = 0; + ChildFileNameList->Next = NULL; + ChildFileNameList->IsFFS = FALSE; + ChildFileNameList->UiNameSize = 0; + ChildFileNameList->Depex = NULL; + ChildFileNameList->DepexLen = 0; + ChildFileNameList->FfsFoundFlag = FALSE; + // + // Encapsulate from the lowest FFS file level. + // + LocalEncapData = CurrentEncapData; + if (LocalEncapData == NULL) { + LocalEncapData = FvInFd->EncapData; + } + Level = LocalEncapData->Level; + Type = LocalEncapData->Type; + + if (CurrentEncapData == NULL) { + LocalEncapData = FvInFd->EncapData; + while (LocalEncapData != NULL) { + if (LocalEncapData->Type == FMMT_ENCAP_TREE_FFS) { + LocalEncapDataTemp = LocalEncapData->RightNode; + while (LocalEncapDataTemp != NULL) { + LocalEncapDataNext = LocalEncapDataTemp->NextNode; + if (LocalEncapDataNext != NULL && LocalEncapDataNext->NextNode != NULL) { + + LibEncapNewFvFile(FvInFd, TemDir, LocalEncapDataTemp, 1, &ChildFileNameList); + ChildFileNameList->ParentLevel = LocalEncapDataTemp->Level -1; + if (FvInFd->ChildFvFFS == NULL) { + FvInFd->ChildFvFFS = ChildFileNameList; + } else { + NewFileNameList = FvInFd->ChildFvFFS; + while (NewFileNameList->Next != NULL) { + NewFileNameList = NewFileNameList->Next; + } + NewFileNameList->Next = ChildFileNameList; + } + } + LocalEncapDataTemp = LocalEncapDataTemp->RightNode; + } + } + + if (LocalEncapData->Level > Level) { + if (LocalEncapData->Type == FMMT_ENCAP_TREE_FFS) { + ParentLevel = Level; + ParentType = Type; + } + Level = LocalEncapData->Level; + Type = LocalEncapData->Type; + } + LocalEncapData = LocalEncapData->NextNode; + } + } else { + LocalEncapData = CurrentEncapData; + while (LocalEncapData != NULL) { + if (LocalEncapData->Level > Level) { + if (LocalEncapData->Type == FMMT_ENCAP_TREE_FFS) { + ParentLevel = Level; + ParentType = Type; + } + Level = LocalEncapData->Level; + Type = LocalEncapData->Type; + } + LocalEncapData = LocalEncapData->NextNode; + } + } + + do { + switch (ParentType) { + case FMMT_ENCAP_TREE_FV: + OutputFileNameListFlag = TRUE; + EncapFvStart = 0; + for(OuterIndex=0;OutputFileNameListFlag;OuterIndex++){ + // + // Generate FV.inf attributes. + // + InfFileName = LibFilenameStrExtended (strrchr(GenTempFile (),OS_SEP), TemDir, "inf"); + FirstInFlag = TRUE; + + InfFile = fopen (InfFileName, "wt+"); + + if (InfFile == NULL) { + Error ("FMMT", 0, 0004, "Could not open inf file %s to store FV information! \n", ""); + free (OutputFileNameList); + free (ChildFileNameList); + return EFI_ABORTED; + } + + if (CurrentEncapData == NULL) { + LocalEncapData = FvInFd->EncapData; + } else { + LocalEncapData = CurrentEncapData; + } + + while (LocalEncapData->NextNode != NULL) { + if (LocalEncapData->Level == ParentLevel) { + break; + } + LocalEncapData = LocalEncapData->NextNode; + } + + if (((EFI_FIRMWARE_VOLUME_HEADER *)(LocalEncapData->Data))->ExtHeaderOffset != 0) { + // + // FV GUID Name memory allocation + // + FvGuidName = (CHAR8 *) malloc (255); + + if (FvGuidName == NULL) { + Error ("FMMT", 0, 0004, "Out of resource, memory allocation failed! \n", ""); + fclose (InfFile); + free (OutputFileNameList); + free (ChildFileNameList); + return EFI_ABORTED; + } + + memset(FvGuidName, '\0', 255); + + sprintf( + FvGuidName, + "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X\n", + LocalEncapData->FvExtHeader->FvName.Data1, + LocalEncapData->FvExtHeader->FvName.Data2, + LocalEncapData->FvExtHeader->FvName.Data3, + LocalEncapData->FvExtHeader->FvName.Data4[0], + LocalEncapData->FvExtHeader->FvName.Data4[1], + LocalEncapData->FvExtHeader->FvName.Data4[2], + LocalEncapData->FvExtHeader->FvName.Data4[3], + LocalEncapData->FvExtHeader->FvName.Data4[4], + LocalEncapData->FvExtHeader->FvName.Data4[5], + LocalEncapData->FvExtHeader->FvName.Data4[6], + LocalEncapData->FvExtHeader->FvName.Data4[7] + ); + + } else { + FvGuidName = NULL; + } + + + if (ParentLevel == 1) { + Status = LibFvHeaderOptionToStr((EFI_FIRMWARE_VOLUME_HEADER *)LocalEncapData->Data, InfFile, TRUE); + } else { + Status = LibFvHeaderOptionToStr((EFI_FIRMWARE_VOLUME_HEADER *)LocalEncapData->Data, InfFile, FALSE); + } + + + if (EFI_ERROR (Status)) { + Error ("FMMT", 0, 0004, "error while encapsulate FD Image", "generate FV INF file [Options] section failed."); + fclose (InfFile); + free (OutputFileNameList); + free (ChildFileNameList); + return Status; + } + + Status = LibFvHeaderAttributeToStr(((EFI_FIRMWARE_VOLUME_HEADER *)LocalEncapData->Data)->Attributes, InfFile); + + if (EFI_ERROR (Status)) { + Error ("FMMT", 0, 0004, "error while encapsulate FD Image", "Generate FV header attribute failed"); + fclose (InfFile); + free (OutputFileNameList); + free (ChildFileNameList); + return Status; + } + if (LocalEncapData->FvExtHeader != NULL) { + Status = LibGenExtFile(LocalEncapData->FvExtHeader, InfFile); + if (EFI_ERROR(Status)) { + Error("FMMT", 0, 0004, "error while encapsulate FD Image", "Generate FV EXT header failed"); + fclose (InfFile); + free (OutputFileNameList); + free (ChildFileNameList); + return Status; + } + FvGuidName = NULL; + } + + if (CurrentEncapData != NULL) { + for (Index = 0; Index <= FvInFd->FfsNumbers; Index++) { + if ((memcmp(&FvInFd->FfsAttuibutes[Index].GuidName, &(CurrentEncapData->FvExtHeader->FvName), sizeof(EFI_GUID)) == 0)) { + SubFvId = Index; + break; + } + } + } + // + // Found FFSs from Fv structure. + // + FfsFoundFlag = FALSE; + IsRootFv = FALSE; + for (Index=0; Index <= FvInFd->FfsNumbers; Index++) { + if (OutputFileNameList != NULL && OutputFileNameList->FFSName != NULL && OutputFileNameList->IsFFS == FALSE){ + break; + } + if (OutputFileNameList != NULL && OutputFileNameList->FFSName != NULL && OutputFileNameList->IsFFS == TRUE){ + if (Index == EncapFvIndex) { + if (FirstInFlag) { + Status = LibAddFfsFileToFvInf (OutputFileNameList->FFSName, InfFile, TRUE); + FirstInFlag = FALSE; + } else { + Status = LibAddFfsFileToFvInf (OutputFileNameList->FFSName, InfFile, FALSE); + } + if (EFI_ERROR (Status)) { + Error ("FMMT", 0, 0004, "error while encapsulate FD Image", "Generate FV inf file [files] section failed!"); + fclose (InfFile); + free (OutputFileNameList); + free (ChildFileNameList); + return Status; + } + } + } + + NewFileNameList = FvInFd->ChildFvFFS; + while (NewFileNameList != NULL && NewFileNameList -> FFSName != NULL) { + if (NewFileNameList -> ParentLevel == ParentLevel && Index == NewFileNameList->InFvId && NewFileNameList->FfsFoundFlag==TRUE) { + if (FirstInFlag) { + Status = LibAddFfsFileToFvInf (NewFileNameList->FFSName, InfFile, TRUE); + FirstInFlag = FALSE; + } else { + Status = LibAddFfsFileToFvInf (NewFileNameList->FFSName, InfFile, FALSE); + } + if (EFI_ERROR (Status)) { + Error ("FMMT", 0, 0004, "error while encapsulate FD Image", "Generate FV inf file [files] section failed!"); + fclose (InfFile); + free (OutputFileNameList); + free (ChildFileNameList); + return Status; + } + } + NewFileNameList = NewFileNameList->Next; + } + + if (FvInFd->FfsAttuibutes[Index].IsHandle==TRUE) { + continue; + } + if (SubFvId > 0 && Index < SubFvId) { + continue; + } + + // + // For the last level FFS, the level below FFSs we should not care the IsLeaf Flag. + // + if (IsLastLevelFfs) { + IsLeafFlagIgnore = TRUE; + } else { + IsLeafFlagIgnore = FvInFd->FfsAttuibutes[Index].IsLeaf; + } + + if (FvInFd->FfsAttuibutes[Index].Level >= ParentLevel + 1 && IsLeafFlagIgnore) { + if (FirstInFlag) { + if (FvInFd->FfsAttuibutes[Index].Level < 0xFF) { + FfsFoundFlag = TRUE; + Status = LibAddFfsFileToFvInf (FvInFd->FfsAttuibutes[Index].FfsName, InfFile, TRUE); + FirstInFlag = FALSE; + FvInFd->FfsAttuibutes[Index].IsHandle=TRUE; + EncapFvStart = Index; + } + + if (EFI_ERROR (Status)) { + Error ("FMMT", 0, 0004, "error while encapsulate FD Image", "Generate FV inf file [files] section failed!"); + fclose (InfFile); + free (OutputFileNameList); + free (ChildFileNameList); + return Status; + } + if (Index == 0) { + // Root FV need to include all FFS files. + IsRootFv = TRUE; + } + } else { + if (FvInFd->FfsAttuibutes[Index].Level < 0xFF) { + FfsFoundFlag = TRUE; + Status = LibAddFfsFileToFvInf (FvInFd->FfsAttuibutes[Index].FfsName, InfFile, FALSE); + FvInFd->FfsAttuibutes[Index].IsHandle=TRUE; + } + + if (EFI_ERROR (Status)) { + Error ("FMMT", 0, 0004, "error while encapsulate FD Image", "Generate FV inf file [files] section failed!"); + fclose (InfFile); + free (OutputFileNameList); + free (ChildFileNameList); + return Status; + } + if (Index == 0) { + // Root FV need to include all FFS files. + IsRootFv = TRUE; + } + } + + + //avoid a FV contain too many ffs files + if ((!IsRootFv) && (FvInFd->FfsAttuibutes[Index].FvLevel <= FvInFd->MulFvLevel) && (FvInFd->FfsAttuibutes[Index+1].FvLevel <= FvInFd->MulFvLevel) && + (FvInFd->FfsAttuibutes[Index].FvLevel != FvInFd->FfsAttuibutes[Index+1].FvLevel) && (ParentLevel != 1) && (FvInFd->FfsAttuibutes[Index].Level != FvInFd->FfsAttuibutes[Index+1].Level) && + FvInFd->FfsAttuibutes[Index].Level != 0xFF && FvInFd->FfsAttuibutes[Index+1].Level != 0xFF && FvInFd->FfsAttuibutes[Index+1].Level != 0x0){ + FvInFd->FfsAttuibutes[Index].Level = 0; + break; + }else{ + if (FvInFd->FfsAttuibutes[Index].Level != 0xFF){ + FvInFd->FfsAttuibutes[Index].Level = 0; + } + } + + } + } + // The Fv may has multiple level (> 2), when it is in the FvLevel == 2, we set the IsLastLevelFfs Flag + if (Index <=FvInFd->FfsNumbers && FvInFd->FfsAttuibutes[Index].FvLevel <= FvInFd->MulFvLevel) { + if (FvInFd->FfsAttuibutes[Index].FvLevel == 2) { + IsLastLevelFfs = FALSE; + } + } + if (!FfsFoundFlag){ + OutputFileNameListFlag = FALSE; + if (OuterIndex > 0){ + fclose (InfFile); + break; + } + } + // + // Create FV + // + fclose (InfFile); + + EncapFvIndex = EncapFvStart; + + OutputFileName= LibFilenameStrExtended (strrchr(GenTempFile (), OS_SEP), TemDir, "FV"); + + Status = LibEncapsulateFfsToFv (InfFileName, NULL, OutputFileName, FvGuidName, IsLargeFile); + + if (EFI_ERROR (Status)) { + Error ("FMMT", 0, 0004, "error while encapsulate FD Image", "Generate FV failed!"); + free (OutputFileNameList); + free (ChildFileNameList); + return Status; + } + + OutputFileNameList->FFSName = (char *)malloc(strlen(OutputFileName)+1); + if (OutputFileNameList->FFSName == NULL) { + Error ("FMMT", 0, 0004, "Out of resource, memory allocation failed! \n", ""); + return EFI_OUT_OF_RESOURCES; + } + memcpy((char *)OutputFileNameList->FFSName, (char *)OutputFileName, strlen(OutputFileName)+1); + if (CurrentEncapData != NULL) { + OutputFileNameList->InFvId = EncapFvIndex; + if (EncapFvIndex > 0) { + memcpy(OutputFileNameList->UiName,FvInFd->FfsAttuibutes[EncapFvIndex - 1].UiName, FvInFd->FfsAttuibutes[EncapFvIndex - 1].UiNameSize); + OutputFileNameList->UiNameSize = FvInFd->FfsAttuibutes[EncapFvIndex - 1].UiNameSize; + OutputFileNameList->Depex = FvInFd->FfsAttuibutes[EncapFvIndex - 1].Depex; + OutputFileNameList->DepexLen = FvInFd->FfsAttuibutes[EncapFvIndex - 1].DepexLen; + OutputFileNameList->FfsFoundFlag = FfsFoundFlag; + } + } + } + break; + case FMMT_ENCAP_TREE_FFS: + + while(OutputFileNameList!= NULL && OutputFileNameList->FFSName != NULL){ + InputFileName = OutputFileNameList->FFSName; + OutputFileName= LibFilenameStrExtended (strrchr(GenTempFile (), OS_SEP), TemDir, "ffs"); + LocalEncapData = CurrentEncapData; + if (LocalEncapData == NULL) { + LocalEncapData = FvInFd->EncapData; + } + while (LocalEncapData->NextNode != NULL) { + if (LocalEncapData->Level == ParentLevel) { + for(;LocalEncapData->NextNode != NULL;) { + if(LocalEncapData->FvExtHeader != NULL) { + break; + } + LocalEncapData = LocalEncapData->NextNode; + } + break; + } + LocalEncapData = LocalEncapData->NextNode; + } + + if (LocalEncapData->FvExtHeader == NULL) { + Error ("FMMT", 0, 0004, "error while encapsulate FD Image", "Generate FFS file failed!"); + free (OutputFileNameList); + free (ChildFileNameList); + return EFI_ABORTED; + } + + if (OutputFileNameList->UiNameSize > 0) { + TmpFileName = LibFilenameStrExtended(strrchr(GenTempFile (), OS_SEP), TemDir, "tmp"); + TmpFile = fopen(TmpFileName, "wb+"); + if (TmpFile == NULL) { + Error("FMMT", 0, 0004, "Could not open tmp file %s to store UI section information! \n", ""); + free (OutputFileNameList); + free (ChildFileNameList); + return EFI_ABORTED; + } + header = (OutputFileNameList->UiNameSize+4) | (EFI_SECTION_USER_INTERFACE << 24); + Index = 0; + while (header) { + SectionHeader[Index] = header % 0x100; + header /= 0x100; + Index ++; + } + InputFile = fopen(InputFileName, "rb+"); + if (InputFile == NULL) { + Error("FMMT", 0, 0004, "Could not open input file %s! \n", ""); + fclose(TmpFile); + free (OutputFileNameList); + free (ChildFileNameList); + return EFI_ABORTED; + } + fseek(InputFile, 0, SEEK_SET); + fseek(InputFile, 0, SEEK_END); + InputFileSize = ftell(InputFile); + fseek(InputFile, 0, SEEK_SET); + + Buffer = malloc(InputFileSize+OutputFileNameList->UiNameSize+4); + memcpy(Buffer, (CHAR16 *)SectionHeader, 4); + memcpy(Buffer + 4, (CHAR16 *)(OutputFileNameList->UiName), OutputFileNameList->UiNameSize); + if (fread(Buffer+4+OutputFileNameList->UiNameSize, 1, InputFileSize, InputFile) != InputFileSize) { + Error("FMMT", 0, 0004, "Could not open sec file %s to add UI section information! \n", ""); + fclose(TmpFile); + fclose(InputFile); + free(Buffer); + free (OutputFileNameList); + free (ChildFileNameList); + return EFI_ABORTED; + } + fwrite(Buffer, 1, InputFileSize + OutputFileNameList->UiNameSize + 4, TmpFile); + free(Buffer); + fclose(TmpFile); + fclose(InputFile); + InputFileName = TmpFileName; + } + if (OutputFileNameList->DepexLen > 0) { + TmpFileName = LibFilenameStrExtended(strrchr(GenTempFile (), OS_SEP), TemDir, "tmp"); + TmpFile = fopen(TmpFileName, "wb+"); + if (TmpFile == NULL) { + Error("FMMT", 0, 0004, "Could not open tmp file %s to store Depex section information! \n", ""); + free (OutputFileNameList); + free (ChildFileNameList); + return EFI_ABORTED; + } + InputFile = fopen(InputFileName, "rb+"); + if (InputFile == NULL) { + Error("FMMT", 0, 0004, "Could not open input file %s! \n", ""); + fclose(TmpFile); + free (OutputFileNameList); + free (ChildFileNameList); + return EFI_ABORTED; + } + fseek(InputFile, 0, SEEK_SET); + fseek(InputFile, 0, SEEK_END); + InputFileSize = ftell(InputFile); + fseek(InputFile, 0, SEEK_SET); + // make sure the section is 4 byte align + if (OutputFileNameList->DepexLen % 4 != 0) { + AlignN = 4 - OutputFileNameList->DepexLen % 4; + } + Buffer = malloc(InputFileSize + OutputFileNameList->DepexLen + AlignN); + memcpy(Buffer, OutputFileNameList->Depex, OutputFileNameList->DepexLen); + if (AlignN != 0) { + for (Index = 0; Index < AlignN; Index ++) { + memcpy(Buffer + OutputFileNameList->DepexLen + Index, AlignV, 1); + } + } + if (fread(Buffer + OutputFileNameList->DepexLen + AlignN, 1, InputFileSize, InputFile) != InputFileSize) { + Error("FMMT", 0, 0004, "Could not open sec file %s to add Depex section information! \n", ""); + fclose(TmpFile); + fclose(InputFile); + free(Buffer); + free (OutputFileNameList); + free (ChildFileNameList); + return EFI_ABORTED; + } + fwrite(Buffer, 1, InputFileSize + OutputFileNameList->DepexLen + AlignN, TmpFile); + free(Buffer); + fclose(TmpFile); + fclose(InputFile); + InputFileName = TmpFileName; + } + for (Id = FvInFd->FfsNumbers; Id <= FvInFd->FfsNumbers; Id--) { + if ((memcmp(&FvInFd->FfsAttuibutes[Id].GuidName, &(LocalEncapData->FvExtHeader->FvName), sizeof(EFI_GUID)) == 0)){ + if (access(FvInFd->FfsAttuibutes[Id].FfsName, 0) != -1) { + Status = LibFmmtDeleteFile(FvInFd->FfsAttuibutes[Id].FfsName); + if (EFI_ERROR(Status)) { + Error("FMMT", 0, 0004, "error while encapsulate FD Image", "Delete the specified file failed!"); + free (OutputFileNameList); + free (ChildFileNameList); + return Status; + } + memset(FvInFd->FfsAttuibutes[Id].FfsName, '\0', _MAX_PATH); + FvInFd->FfsAttuibutes[Id].Level = 0xFF; + break; + } + } + } + if (LocalEncapData->NextNode != NULL) { + LocalEncapDataTemp = LocalEncapData->NextNode; + if ((LocalEncapDataTemp->Type == FMMT_ENCAP_TREE_GUIDED_SECTION) || (LocalEncapDataTemp->Type == FMMT_ENCAP_TREE_COMPRESS_SECTION)) { + Status = LibEncapSectionFileToFFS(EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE, InputFileName, OutputFileName, LocalEncapData->FvExtHeader->FvName, FALSE, "1"); + } + else{ + Status = LibEncapSectionFileToFFS(EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE, InputFileName, OutputFileName, LocalEncapData->FvExtHeader->FvName, FALSE, FvInFd->AlignmentStr); + } + } + else{ + Status = LibEncapSectionFileToFFS(EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE, InputFileName, OutputFileName, LocalEncapData->FvExtHeader->FvName, FALSE, FvInFd->AlignmentStr); + } + if (EFI_ERROR (Status)) { + Error ("FMMT", 0, 0004, "error while encapsulate FD Image", "Generate FFS file failed!"); + free (OutputFileNameList); + free (ChildFileNameList); + return Status; + } + free(LocalEncapData->FvExtHeader); + LocalEncapData->FvExtHeader = NULL; + OutputFileNameList->FFSName = (char *)malloc(strlen(OutputFileName)+1); + if (OutputFileNameList->FFSName == NULL) { + Error ("FMMT", 0, 0004, "Out of resource, memory allocation failed! \n", ""); + return EFI_OUT_OF_RESOURCES; + } + memcpy((char *)OutputFileNameList->FFSName, (char *)OutputFileName, strlen(OutputFileName)+1); + OutputFileNameList->IsFFS = TRUE; + if (OutputFileNameList->Next == NULL){ + break; + } + OutputFileNameList = OutputFileNameList->Next; + } + break; + case FMMT_ENCAP_TREE_GUIDED_SECTION: + while(OutputFileNameList!= NULL && OutputFileNameList->FFSName != NULL){ + // + // Create the guided section original data, do compress operation. + // + InputFileName = OutputFileNameList->FFSName; + OutputFileName= LibFilenameStrExtended (strrchr(GenTempFile (), OS_SEP), TemDir, "compressed"); + + // + // Use the guided section header guid to find out compress application name. + // + LocalEncapData = CurrentEncapData; + if (LocalEncapData == NULL) { + LocalEncapData = FvInFd->EncapData; + } + while (LocalEncapData->NextNode != NULL) { + if (LocalEncapData->Level == ParentLevel) { + break; + } + LocalEncapData = LocalEncapData->NextNode; + } + + ExtractionTool = + LookupGuidedSectionToolPath ( + mParsedGuidedSectionTools, + (EFI_GUID *)LocalEncapData->Data + ); + GuidDataOffset = *(UINT16 *) ((UINT8 *) LocalEncapData->Data + sizeof (EFI_GUID)); + GuidAttributes = *(UINT16 *) ((UINT8 *) LocalEncapData->Data + sizeof (EFI_GUID) + sizeof (UINT16)); + + Status = LibCreateGuidedSectionOriginalData (InputFileName, ExtractionTool, OutputFileName); + + if (EFI_ERROR (Status) || GuidDataOffset < sizeof (EFI_GUID_DEFINED_SECTION)) { + Error ("FMMT", 0, 0004, "error while encapsulate FD Image", "Compress guided data failed!"); + free (OutputFileNameList); + free (ChildFileNameList); + return Status; + } + + GuidDataOffset = GuidDataOffset - sizeof (EFI_GUID_DEFINED_SECTION); + InputFileName = OutputFileName; + OutputFileName= LibFilenameStrExtended (strrchr(GenTempFile (), OS_SEP), TemDir, "guided"); + + Status = LibCreateFfsSection(NULL, InputFileName, NULL, EFI_SECTION_GUID_DEFINED, OutputFileName, NULL, NULL, LibFmmtGuidToStr((EFI_GUID *)LocalEncapData->Data), GuidDataOffset, GuidAttributes, NULL); + OutFile = fopen(OutputFileName, "rb+"); + if (OutFile == NULL) { + Error("FMMT", 0, 0004, "Could not open the file %s! \n", ""); + free (OutputFileNameList); + free (ChildFileNameList); + return EFI_ABORTED; + } + fseek(OutFile, 0, SEEK_SET); + fseek(OutFile, 0, SEEK_END); + OutputFileSize = ftell(OutFile); + fclose(OutFile); + if (OutputFileSize > LargeFileSize) { + IsLargeFile = TRUE; + } + OutputFileNameList->FFSName = (char *)malloc(strlen(OutputFileName)+1); + if (OutputFileNameList->FFSName == NULL) { + Error ("FMMT", 0, 0004, "Out of resource, memory allocation failed! \n", ""); + return EFI_OUT_OF_RESOURCES; + } + memcpy((char *)OutputFileNameList->FFSName, (char *)OutputFileName, strlen(OutputFileName)+1); + + if (EFI_ERROR (Status)) { + Error ("FMMT", 0, 0004, "error while encapsulate FD Image", "Generate guided section failed!"); + free (OutputFileNameList); + free (ChildFileNameList); + return Status; + } + if (OutputFileNameList->Next == NULL){ + break; + } + OutputFileNameList = OutputFileNameList->Next; + } + break; + case FMMT_ENCAP_TREE_COMPRESS_SECTION: + while(OutputFileNameList!= NULL && OutputFileNameList->FFSName != NULL){ + InputFileName = OutputFileNameList->FFSName; + + OutputFileName= LibFilenameStrExtended (strrchr(GenTempFile (), OS_SEP), TemDir, "comsec"); + LocalEncapData = CurrentEncapData; + if (LocalEncapData == NULL) { + LocalEncapData = FvInFd->EncapData; + } + while (LocalEncapData->NextNode != NULL) { + if (LocalEncapData->Level == ParentLevel) { + break; + } + LocalEncapData = LocalEncapData->NextNode; + } + + Status = LibGenCompressedSection (InputFileName, OutputFileName, *(UINT8 *)(LocalEncapData->Data)); + OutputFileNameList->FFSName = (char *)malloc(strlen(OutputFileName)+1); + if (OutputFileNameList->FFSName == NULL) { + Error ("FMMT", 0, 0004, "Out of resource, memory allocation failed! \n", ""); + return EFI_OUT_OF_RESOURCES; + } + memcpy((char *)OutputFileNameList->FFSName, (char *)OutputFileName, strlen(OutputFileName)+1); + + if (EFI_ERROR (Status)) { + Error ("FMMT", 0, 0004, "error while encapsulate FD Image", "Generate compressed section failed!"); + free (OutputFileNameList); + free (ChildFileNameList); + return Status; + } + if (OutputFileNameList->Next == NULL){ + break; + } + OutputFileNameList = OutputFileNameList->Next; + } + break; + case FMMT_ENCAP_TREE_FV_SECTION: + while(OutputFileNameList!= NULL && OutputFileNameList->FFSName != NULL){ + InputFileName = OutputFileNameList->FFSName; + OutputFileName= LibFilenameStrExtended (strrchr(GenTempFile (), OS_SEP), TemDir, "sec"); + + Status = LibCreateFfsSection(NULL, InputFileName, NULL, EFI_SECTION_FIRMWARE_VOLUME_IMAGE, OutputFileName, NULL, NULL, NULL, 0, 0, NULL); + + if (EFI_ERROR (Status)) { + Error ("FMMT", 0, 0004, "error while encapsulate FD Image", "Generate FV section failed!"); + free (OutputFileNameList); + free (ChildFileNameList); + return Status; + } + + InputFileName = OutputFileName; + OutputFileName= LibFilenameStrExtended (strrchr(GenTempFile (), OS_SEP), TemDir, "sec"); + + // + // Make it alignment. + // + Status = LibCreateFfsSection(FvInFd, InputFileName, NULL, 0, OutputFileName, NULL, NULL, NULL, 0, 0, NULL); + OutFile = fopen(OutputFileName, "rb+"); + if (OutFile == NULL) { + Error("FMMT", 0, 0004, "Could not open the file %s! \n", ""); + free (OutputFileNameList); + free (ChildFileNameList); + return EFI_ABORTED; + } + fseek(OutFile, 0, SEEK_SET); + fseek(OutFile, 0, SEEK_END); + OutputFileSize = ftell(OutFile); + fclose(OutFile); + if (OutputFileSize > LargeFileSize) { + IsLargeFile = TRUE; + } + + OutputFileNameList->FFSName = (char *)malloc(strlen(OutputFileName)+1); + if (OutputFileNameList->FFSName == NULL) { + Error ("FMMT", 0, 0004, "Out of resource, memory allocation failed! \n", ""); + return EFI_OUT_OF_RESOURCES; + } + memcpy((char *)OutputFileNameList->FFSName, (char *)OutputFileName, strlen(OutputFileName)+1); + + if (EFI_ERROR (Status)) { + Error ("FMMT", 0, 0004, "error while encapsulate FD Image", "Generate FV section failed!"); + free (OutputFileNameList); + free (ChildFileNameList); + return Status; + } + if (OutputFileNameList->Next == NULL){ + break; + } + OutputFileNameList = OutputFileNameList->Next; + } + break; + default: + for (Id = FvInFd->FfsNumbers; Id <= FvInFd->FfsNumbers; Id--) { + if ((memcmp(&FvInFd->FfsAttuibutes[Id].GuidName, &(CurrentEncapData->FvExtHeader->FvName), sizeof(EFI_GUID)) == 0)){ + FvInFd->FfsAttuibutes[Id].IsHandle = TRUE; + memcpy(OutputFileNameList->UiName, FvInFd->FfsAttuibutes[Id].UiName, FvInFd->FfsAttuibutes[Id].UiNameSize); + OutputFileNameList->UiNameSize = FvInFd->FfsAttuibutes[Id].UiNameSize; + OutputFileNameList->FFSName = FvInFd->FfsAttuibutes[Id].FfsName; + OutputFileNameList->Depex = FvInFd->FfsAttuibutes[Id].Depex; + OutputFileNameList->DepexLen = FvInFd->FfsAttuibutes[Id].DepexLen; + OutputFileNameList->FfsFoundFlag = TRUE; + OutputFileNameList->IsFFS = TRUE; + OutputFileNameList->InFvId = Id; + *OutputFile = OutputFileNameList; + return EFI_SUCCESS; + } + } + } + + if (CurrentEncapData == NULL) { + LocalEncapData = FvInFd->EncapData; + } else { + if (OutputFileNameList != NULL && OutputFileNameList->FFSName != NULL && OutputFileNameList->IsFFS == TRUE) { + *OutputFile = OutputFileNameList; + return EFI_SUCCESS; + } + LocalEncapData = CurrentEncapData; + } + ParentLevel -= 1; + + while (LocalEncapData->NextNode != NULL) { + if (LocalEncapData->Level == ParentLevel) { + LocalEncapDataTemp = LocalEncapData->NextNode; + if ((LocalEncapDataTemp != NULL) && (LocalEncapDataTemp->Level == ParentLevel)) { + ParentType = LocalEncapDataTemp->Type; + break; + } + ParentType = LocalEncapData->Type; + break; + } + LocalEncapData = LocalEncapData->NextNode; + } + } while (ParentLevel != Level_Break); + + *OutputFile = OutputFileNameList; + return EFI_SUCCESS; + +} + +EFI_STATUS +LibFindFvInEncapData ( + ENCAP_INFO_DATA *EncapData, + UINT8 *Index +) +{ + ENCAP_INFO_DATA *LocalEncapData; + LocalEncapData = EncapData; + if (LocalEncapData == NULL) { + Error("FMMT", 0, 0005, "error while find FV in Encapulate buffer", "Invalid parameters."); + return EFI_INVALID_PARAMETER; + } + while (LocalEncapData != NULL) { + if (LocalEncapData->RightNode != NULL) { + LibFindFvInEncapData (LocalEncapData->RightNode, Index); + } + if (LocalEncapData->Type == FMMT_ENCAP_TREE_FV) { + (*Index)++; + } + LocalEncapData = LocalEncapData->NextNode; + } + return EFI_SUCCESS; +} + +EFI_STATUS +LibLocateFvViaFvId ( + IN FIRMWARE_DEVICE *FdData, + IN CHAR8 *FvId, + IN OUT FV_INFORMATION **FvInFd +) +{ + UINT8 FvIndex1; + UINT8 FvIndex2; + BOOLEAN FvFoundFlag; + CHAR8* FvGuidName; + ENCAP_INFO_DATA *LocalEncapData; + ENCAP_INFO_DATA *LocalEncapDataRight; + ENCAP_INFO_DATA *LocalEncapDataNext; + FvIndex1 = 0; + FvIndex2 = 0; + FvFoundFlag = FALSE; + FvGuidName = NULL; + LocalEncapDataNext = NULL; + LocalEncapDataRight = NULL; + + if (FdData == NULL || FvId == NULL || FvInFd == NULL || FdData->Fv == NULL) { + Error ("FMMT", 0, 0005, "error while find FV in FD", "Invalid parameters."); + return EFI_INVALID_PARAMETER; + } + + *FvInFd = FdData->Fv; + + if (strlen(FvId) < 3) { + Error ("FMMT", 0, 0005, "error while find FV in FD", "Invalid FvId, please double check the FvId. You can use view operate to get the FvId information!"); + return EFI_ABORTED; + } + + FvGuidName = (CHAR8 *) malloc (255); + if (FvGuidName == NULL) { + Error ("FMMT", 0, 0005, "Resource: Memory can't be allocated", NULL); + return EFI_ABORTED; + } + memset(FvGuidName, '\0', 255); + LocalEncapData = NULL; + + if (strlen(FvId) == 36) { + while (FvInFd != NULL) { + if (((*FvInFd)->FvExtHeader) != NULL) { + sprintf( + FvGuidName, + "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X", + (*FvInFd)->FvExtHeader->FvName.Data1, + (*FvInFd)->FvExtHeader->FvName.Data2, + (*FvInFd)->FvExtHeader->FvName.Data3, + (*FvInFd)->FvExtHeader->FvName.Data4[0], + (*FvInFd)->FvExtHeader->FvName.Data4[1], + (*FvInFd)->FvExtHeader->FvName.Data4[2], + (*FvInFd)->FvExtHeader->FvName.Data4[3], + (*FvInFd)->FvExtHeader->FvName.Data4[4], + (*FvInFd)->FvExtHeader->FvName.Data4[5], + (*FvInFd)->FvExtHeader->FvName.Data4[6], + (*FvInFd)->FvExtHeader->FvName.Data4[7]); + if (strcmp(FvGuidName, FvId) == 0) { + FvId = (*FvInFd)->FvName; + break; + } + } + if ((*FvInFd)->MulFvLevel > 1) { + LocalEncapData = (*FvInFd) -> EncapData; + LocalEncapData = LocalEncapData->NextNode; + while (LocalEncapData != NULL) { + if (LocalEncapData->RightNode != NULL) { + LocalEncapDataRight = LocalEncapData->RightNode; + while (LocalEncapDataRight !=NULL) { + if (LocalEncapDataRight->NextNode != NULL) { + LocalEncapDataNext = LocalEncapDataRight->NextNode; + while (LocalEncapDataNext != NULL) { + if (LocalEncapDataNext->Type == FMMT_ENCAP_TREE_FV) { + if (LocalEncapDataNext->FvExtHeader != NULL) { + sprintf( + FvGuidName, + "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X", + LocalEncapDataNext->FvExtHeader->FvName.Data1, + LocalEncapDataNext->FvExtHeader->FvName.Data2, + LocalEncapDataNext->FvExtHeader->FvName.Data3, + LocalEncapDataNext->FvExtHeader->FvName.Data4[0], + LocalEncapDataNext->FvExtHeader->FvName.Data4[1], + LocalEncapDataNext->FvExtHeader->FvName.Data4[2], + LocalEncapDataNext->FvExtHeader->FvName.Data4[3], + LocalEncapDataNext->FvExtHeader->FvName.Data4[4], + LocalEncapDataNext->FvExtHeader->FvName.Data4[5], + LocalEncapDataNext->FvExtHeader->FvName.Data4[6], + LocalEncapDataNext->FvExtHeader->FvName.Data4[7]); + if (strcmp(FvGuidName, FvId) == 0) + { + sprintf(FvId, "%s%d", "FV", LocalEncapDataNext->FvId - 1); + break; + } + + } + } + LocalEncapDataNext = LocalEncapDataNext->NextNode; + } + } + LocalEncapDataRight = LocalEncapDataRight->RightNode; + } + } + if (LocalEncapData->Type == FMMT_ENCAP_TREE_FV) { + if (LocalEncapData->FvExtHeader != NULL) { + sprintf( + FvGuidName, + "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X", + LocalEncapData->FvExtHeader->FvName.Data1, + LocalEncapData->FvExtHeader->FvName.Data2, + LocalEncapData->FvExtHeader->FvName.Data3, + LocalEncapData->FvExtHeader->FvName.Data4[0], + LocalEncapData->FvExtHeader->FvName.Data4[1], + LocalEncapData->FvExtHeader->FvName.Data4[2], + LocalEncapData->FvExtHeader->FvName.Data4[3], + LocalEncapData->FvExtHeader->FvName.Data4[4], + LocalEncapData->FvExtHeader->FvName.Data4[5], + LocalEncapData->FvExtHeader->FvName.Data4[6], + LocalEncapData->FvExtHeader->FvName.Data4[7]); + + if (strcmp(FvGuidName, FvId) == 0) { + sprintf(FvId, "%s%d", "FV", LocalEncapData->FvId - 1); + break; + } + } + } + LocalEncapData = LocalEncapData->NextNode; + } + } + if ((*FvInFd)->FvNext == 0) { + break; + } + *FvInFd = (*FvInFd)->FvNext; + } + } + *FvInFd = FdData->Fv; + FvIndex1 = (UINT8) atoi (FvId + 2); + + while (FvInFd != NULL) { + if (((*FvInFd)->FvName) != NULL) { + FvIndex2 = (UINT8) atoi ((*FvInFd)->FvName + 2); + LocalEncapData = (*FvInFd)->EncapData; + LibFindFvInEncapData (LocalEncapData, &FvIndex2); + + if ((FvIndex2 - 1 >= FvIndex1)) { + FvFoundFlag = TRUE; + break; + } + if ((*FvInFd)->FvNext == 0) { + break; + } + } + *FvInFd = (*FvInFd)->FvNext; + } + if (FvGuidName != NULL) { + free (FvGuidName); + } + // + // The specified FV id has issue, can not find the FV in FD. + // + if (!FvFoundFlag) { + Error ("FMMT", 0, 0005, "error while find FV in FD", "Invalid FvId, please double check the FvId. You can use view operate to get the FvId information!"); + return EFI_ABORTED; + } + + return EFI_SUCCESS; + +} + +#define BUILD_IN_TOOL_COUNT 4 + +EFI_HANDLE +LibPreDefinedGuidedTools ( + VOID +) +{ + EFI_GUID Guid; + STRING_LIST *Tool; + GUID_SEC_TOOL_ENTRY *FirstGuidTool; + GUID_SEC_TOOL_ENTRY *LastGuidTool; + GUID_SEC_TOOL_ENTRY *NewGuidTool; + UINT8 Index; + EFI_STATUS Status; + + CHAR8 PreDefinedGuidedTool[BUILD_IN_TOOL_COUNT][255] = { + "a31280ad-481e-41b6-95e8-127f4c984779 TIANO TianoCompress", + "ee4e5898-3914-4259-9d6e-dc7bd79403cf LZMA LzmaCompress", + "fc1bcdb0-7d31-49aa-936a-a4600d9dd083 CRC32 GenCrc32", + "3d532050-5cda-4fd0-879e-0f7f630d5afb BROTLI BrotliCompress" + }; + + Tool = NULL; + FirstGuidTool = NULL; + LastGuidTool = NULL; + NewGuidTool = NULL; + Index = 0; + + for (Index = 0; Index < BUILD_IN_TOOL_COUNT; Index++) { + Tool = SplitStringByWhitespace (PreDefinedGuidedTool[Index]); + if ((Tool != NULL) && + (Tool->Count == 3) + ) { + Status = StringToGuid (Tool->Strings[0], &Guid); + if (!EFI_ERROR (Status)) { + NewGuidTool = malloc (sizeof (GUID_SEC_TOOL_ENTRY)); + if (NewGuidTool != NULL) { + memcpy (&(NewGuidTool->Guid), &Guid, sizeof (Guid)); + NewGuidTool->Name = CloneString(Tool->Strings[1]); + NewGuidTool->Path = CloneString(Tool->Strings[2]); + NewGuidTool->Next = NULL; + } else { + printf ("Error while allocate resource! \n"); + FreeStringList (Tool); + return NULL; + } + if (FirstGuidTool == NULL) { + FirstGuidTool = NewGuidTool; + } else { + LastGuidTool->Next = NewGuidTool; + } + LastGuidTool = NewGuidTool; + } + } else { + fprintf (stdout, "Error"); + } + if (Tool != NULL) { + FreeStringList (Tool); + Tool = NULL; + } + } + return FirstGuidTool; +} diff --git a/BaseTools/Source/C/FMMT/GNUmakefile b/BaseTools/Source/C/FMMT/GNUmakefile new file mode 100644 index 0000000000..81b99f25db --- /dev/null +++ b/BaseTools/Source/C/FMMT/GNUmakefile @@ -0,0 +1,16 @@ +## @file +# GNU/Linux makefile for 'FMMT' module build. +# +# Copyright (c) 2019, Intel Corporation. All rights reserved.
+# SPDX-License-Identifier: BSD-2-Clause-Patent +# +MAKEROOT ?= .. + +APPNAME = FMMT + +LIBS = -lCommon + +OBJECTS = FmmtLib.o Rebase.o FirmwareModuleManagement.o + +include $(MAKEROOT)/Makefiles/app.makefile + diff --git a/BaseTools/Source/C/FMMT/Makefile b/BaseTools/Source/C/FMMT/Makefile new file mode 100644 index 0000000000..d6559d65fd --- /dev/null +++ b/BaseTools/Source/C/FMMT/Makefile @@ -0,0 +1,17 @@ +## @file +# Windows makefile for 'FMMT' module build. +# +# Copyright (c) 2019, Intel Corporation. All rights reserved.
+# SPDX-License-Identifier: BSD-2-Clause-Patent +# + +!INCLUDE ..\Makefiles\ms.common + +APPNAME = FMMT + +LIBS = $(LIB_PATH)\Common.lib + +OBJECTS = FirmwareModuleManagement.obj FmmtLib.obj Rebase.obj + +!INCLUDE ..\Makefiles\ms.app + diff --git a/BaseTools/Source/C/FMMT/Rebase.c b/BaseTools/Source/C/FMMT/Rebase.c new file mode 100644 index 0000000000..d32217d18c --- /dev/null +++ b/BaseTools/Source/C/FMMT/Rebase.c @@ -0,0 +1,846 @@ +/** @file + + Library to rebase PE image. + +Copyright (c) 2019, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "Rebase.h" +#include +#include +#ifdef __GNUC__ +#include +#else +#include +#include +#endif +#include +#include +#include +#include +#include "EfiUtilityMsgs.h" + +static +EFI_STATUS +FfsRebaseImageRead( +IN VOID *FileHandle, +IN UINTN FileOffset, +IN OUT UINT32 *ReadSize, +OUT VOID *Buffer +); + +EFI_STATUS +RebaseFfs( +IN OUT UINT64 BaseAddress, +IN CHAR8 *FileName, +IN OUT EFI_FFS_FILE_HEADER *FfsFile, +IN UINTN XipOffset +) +/*++ + +Routine Description: + +This function determines if a file is XIP and should be rebased. It will +rebase any PE32 sections found in the file using the base address. + +Arguments: + +FvInfo A pointer to FV_INFO struture. +FileName Ffs File PathName +FfsFile A pointer to Ffs file image. +XipOffset The offset address to use for rebasing the XIP file image. + +Returns: + +EFI_SUCCESS The image was properly rebased. +EFI_INVALID_PARAMETER An input parameter is invalid. +EFI_ABORTED An error occurred while rebasing the input file image. +EFI_OUT_OF_RESOURCES Could not allocate a required resource. +EFI_NOT_FOUND No compressed sections could be found. + +--*/ +{ + EFI_STATUS Status; + PE_COFF_LOADER_IMAGE_CONTEXT ImageContext; + PE_COFF_LOADER_IMAGE_CONTEXT OrigImageContext; + EFI_PHYSICAL_ADDRESS XipBase; + EFI_PHYSICAL_ADDRESS NewPe32BaseAddress; + UINTN Index; + EFI_FILE_SECTION_POINTER CurrentPe32Section; + EFI_FFS_FILE_STATE SavedState; + EFI_IMAGE_OPTIONAL_HEADER_UNION *ImgHdr; + EFI_TE_IMAGE_HEADER *TEImageHeader; + UINT8 *MemoryImagePointer; + EFI_IMAGE_SECTION_HEADER *SectionHeader; + CHAR8 PeFileName[MAX_LONG_FILE_PATH]; + CHAR8 *Cptr; + FILE *PeFile; + UINT8 *PeFileBuffer; + UINT32 PeFileSize; + CHAR8 *PdbPointer; + UINT32 FfsHeaderSize; + UINT32 CurSecHdrSize; + CHAR8 *LongFilePathName; + + Index = 0; + MemoryImagePointer = NULL; + TEImageHeader = NULL; + ImgHdr = NULL; + SectionHeader = NULL; + Cptr = NULL; + PeFile = NULL; + PeFileBuffer = NULL; + + // + // Don't need to relocate image when BaseAddress is zero and no ForceRebase Flag specified. + // + if (BaseAddress == 0) { + return EFI_SUCCESS; + } + + XipBase = BaseAddress + XipOffset; + + // + // We only process files potentially containing PE32 sections. + // + switch (FfsFile->Type) { + case EFI_FV_FILETYPE_SECURITY_CORE: + case EFI_FV_FILETYPE_PEI_CORE: + case EFI_FV_FILETYPE_PEIM: + case EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER: + case EFI_FV_FILETYPE_DRIVER: + case EFI_FV_FILETYPE_DXE_CORE: + break; + case EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE: + // + // Rebase the inside FvImage. + // + GetChildFvFromFfs (BaseAddress, FfsFile, XipOffset); + + // + // Search PE/TE section in FV sectin. + // + break; + default: + return EFI_SUCCESS; + } + + FfsHeaderSize = GetFfsHeaderLength(FfsFile); + // + // Rebase each PE32 section + // + Status = EFI_SUCCESS; + for (Index = 1;; Index++) { + // + // Init Value + // + NewPe32BaseAddress = 0; + + // + // Find Pe Image + // + Status = GetSectionByType(FfsFile, EFI_SECTION_PE32, Index, &CurrentPe32Section); + if (EFI_ERROR(Status)) { + break; + } + CurSecHdrSize = GetSectionHeaderLength(CurrentPe32Section.CommonHeader); + + // + // Initialize context + // + memset(&ImageContext, 0, sizeof (ImageContext)); + ImageContext.Handle = (VOID *)((UINTN)CurrentPe32Section.Pe32Section + CurSecHdrSize); + ImageContext.ImageRead = (PE_COFF_LOADER_READ_FILE)FfsRebaseImageRead; + Status = PeCoffLoaderGetImageInfo(&ImageContext); + if (EFI_ERROR(Status)) { + Error(NULL, 0, 3000, "Invalid PeImage", "The input file is %s and the return status is %x", FileName, (int)Status); + return Status; + } + + //if ((ImageContext.Machine == EFI_IMAGE_MACHINE_ARMT) || + // (ImageContext.Machine == EFI_IMAGE_MACHINE_AARCH64)) { + // mArm = TRUE; + //} + + // + // Keep Image Context for PE image in FV + // + memcpy(&OrigImageContext, &ImageContext, sizeof (ImageContext)); + + // + // Get File PdbPointer + // + PdbPointer = PeCoffLoaderGetPdbPointer(ImageContext.Handle); + if (PdbPointer == NULL) { + PdbPointer = FileName; + } + + // + // Get PeHeader pointer + // + ImgHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)((UINTN)CurrentPe32Section.Pe32Section + CurSecHdrSize + ImageContext.PeCoffHeaderOffset); + + // + // Calculate the PE32 base address, based on file type + // + switch (FfsFile->Type) { + case EFI_FV_FILETYPE_SECURITY_CORE: + case EFI_FV_FILETYPE_PEI_CORE: + case EFI_FV_FILETYPE_PEIM: + case EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER: + // + // Check if section-alignment and file-alignment match or not + // + if ((ImgHdr->Pe32.OptionalHeader.SectionAlignment != ImgHdr->Pe32.OptionalHeader.FileAlignment)) { + // + // Xip module has the same section alignment and file alignment. + // + Error(NULL, 0, 3000, "Invalid", "Section-Alignment and File-Alignment do not match : %s.", FileName); + return EFI_ABORTED; + } + // + // PeImage has no reloc section. It will try to get reloc data from the original EFI image. + // + if (ImageContext.RelocationsStripped) { + // + // Construct the original efi file Name + // + if (strlen (FileName) > MAX_LONG_FILE_PATH - 1) { + Error(NULL, 0, 3000, "Invalid", "The file name for %s is too long.", FileName); + return EFI_ABORTED; + } + strncpy(PeFileName, FileName, MAX_LONG_FILE_PATH - 1); + PeFileName[MAX_LONG_FILE_PATH - 1] = 0; + Cptr = PeFileName + strlen(PeFileName); + while (*Cptr != '.') { + Cptr--; + } + if (*Cptr != '.') { + Error(NULL, 0, 3000, "Invalid", "The file %s has no .reloc section.", FileName); + return EFI_ABORTED; + } + else { + *(Cptr + 1) = 'e'; + *(Cptr + 2) = 'f'; + *(Cptr + 3) = 'i'; + *(Cptr + 4) = '\0'; + } + LongFilePathName = LongFilePath(PeFileName); + if (LongFilePathName == NULL) { + Error(NULL, 0, 3000, "Invalid", "Fail to get long file path for file %s.", FileName); + return EFI_ABORTED; + } + PeFile = fopen(LongFilePathName, "rb"); + if (PeFile == NULL) { + Warning(NULL, 0, 0, "Invalid", "The file %s has no .reloc section.", FileName); + //Error (NULL, 0, 3000, "Invalid", "The file %s has no .reloc section.", FileName); + //return EFI_ABORTED; + break; + } + // + // Get the file size + // + PeFileSize = _filelength(fileno(PeFile)); + PeFileBuffer = (UINT8 *)malloc(PeFileSize); + if (PeFileBuffer == NULL) { + Error(NULL, 0, 4001, "Resource", "memory cannot be allocated on rebase of %s", FileName); + fclose(PeFile); + return EFI_OUT_OF_RESOURCES; + } + // + // Read Pe File + // + fread(PeFileBuffer, sizeof (UINT8), PeFileSize, PeFile); + // + // close file + // + fclose(PeFile); + // + // Handle pointer to the original efi image. + // + ImageContext.Handle = PeFileBuffer; + Status = PeCoffLoaderGetImageInfo(&ImageContext); + if (EFI_ERROR(Status)) { + Error(NULL, 0, 3000, "Invalid PeImage", "The input file is %s and the return status is %x", FileName, (int)Status); + return Status; + } + ImageContext.RelocationsStripped = FALSE; + } + + NewPe32BaseAddress = XipBase + (UINTN)CurrentPe32Section.Pe32Section + CurSecHdrSize - (UINTN)FfsFile; + break; + + case EFI_FV_FILETYPE_DRIVER: + case EFI_FV_FILETYPE_DXE_CORE: + // + // Check if section-alignment and file-alignment match or not + // + if ((ImgHdr->Pe32.OptionalHeader.SectionAlignment != ImgHdr->Pe32.OptionalHeader.FileAlignment)) { + // + // Xip module has the same section alignment and file alignment. + // + Error(NULL, 0, 3000, "Invalid", "Section-Alignment and File-Alignment do not match : %s.", FileName); + return EFI_ABORTED; + } + NewPe32BaseAddress = XipBase + (UINTN)CurrentPe32Section.Pe32Section + CurSecHdrSize - (UINTN)FfsFile; + break; + + default: + // + // Not supported file type + // + return EFI_SUCCESS; + } + + // + // Relocation doesn't exist + // + if (ImageContext.RelocationsStripped) { + Warning(NULL, 0, 0, "Invalid", "The file %s has no .reloc section.", FileName); + continue; + } + + // + // Relocation exist and rebase + // + // + // Load and Relocate Image Data + // + MemoryImagePointer = (UINT8 *)malloc((UINTN)ImageContext.ImageSize + ImageContext.SectionAlignment); + if (MemoryImagePointer == NULL) { + Error(NULL, 0, 4001, "Resource", "memory cannot be allocated on rebase of %s", FileName); + return EFI_OUT_OF_RESOURCES; + } + memset((VOID *)MemoryImagePointer, 0, (UINTN)ImageContext.ImageSize + ImageContext.SectionAlignment); + ImageContext.ImageAddress = ((UINTN)MemoryImagePointer + ImageContext.SectionAlignment - 1) & (~((UINTN)ImageContext.SectionAlignment - 1)); + + Status = PeCoffLoaderLoadImage(&ImageContext); + if (EFI_ERROR(Status)) { + Error(NULL, 0, 3000, "Invalid", "LocateImage() call failed on rebase of %s", FileName); + free((VOID *)MemoryImagePointer); + return Status; + } + + ImageContext.DestinationAddress = NewPe32BaseAddress; + Status = PeCoffLoaderRelocateImage(&ImageContext); + if (EFI_ERROR(Status)) { + Error(NULL, 0, 3000, "Invalid", "RelocateImage() call failed on rebase of %s", FileName); + free((VOID *)MemoryImagePointer); + return Status; + } + + // + // Copy Relocated data to raw image file. + // + SectionHeader = (EFI_IMAGE_SECTION_HEADER *)( + (UINTN)ImgHdr + + sizeof (UINT32)+ + sizeof (EFI_IMAGE_FILE_HEADER)+ + ImgHdr->Pe32.FileHeader.SizeOfOptionalHeader + ); + + for (Index = 0; Index < ImgHdr->Pe32.FileHeader.NumberOfSections; Index++, SectionHeader++) { + CopyMem( + (UINT8 *)CurrentPe32Section.Pe32Section + CurSecHdrSize + SectionHeader->PointerToRawData, + (VOID*)(UINTN)(ImageContext.ImageAddress + SectionHeader->VirtualAddress), + SectionHeader->SizeOfRawData + ); + } + + free((VOID *)MemoryImagePointer); + MemoryImagePointer = NULL; + if (PeFileBuffer != NULL) { + free(PeFileBuffer); + PeFileBuffer = NULL; + } + + // + // Update Image Base Address + // + if (ImgHdr->Pe32.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { + ImgHdr->Pe32.OptionalHeader.ImageBase = (UINT32)NewPe32BaseAddress; + } + else if (ImgHdr->Pe32Plus.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) { + ImgHdr->Pe32Plus.OptionalHeader.ImageBase = NewPe32BaseAddress; + } + else { + Error(NULL, 0, 3000, "Invalid", "unknown PE magic signature %X in PE32 image %s", + ImgHdr->Pe32.OptionalHeader.Magic, + FileName + ); + return EFI_ABORTED; + } + + // + // Now update file checksum + // + if (FfsFile->Attributes & FFS_ATTRIB_CHECKSUM) { + SavedState = FfsFile->State; + FfsFile->IntegrityCheck.Checksum.File = 0; + FfsFile->State = 0; + FfsFile->IntegrityCheck.Checksum.File = CalculateChecksum8( + (UINT8 *)((UINT8 *)FfsFile + FfsHeaderSize), + GetFfsFileLength(FfsFile) - FfsHeaderSize + ); + FfsFile->State = SavedState; + } + + } + + if (FfsFile->Type != EFI_FV_FILETYPE_SECURITY_CORE && + FfsFile->Type != EFI_FV_FILETYPE_PEI_CORE && + FfsFile->Type != EFI_FV_FILETYPE_PEIM && + FfsFile->Type != EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER && + FfsFile->Type != EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE + ) { + // + // Only Peim code may have a TE section + // + return EFI_SUCCESS; + } + + // + // Now process TE sections + // + for (Index = 1;; Index++) { + NewPe32BaseAddress = 0; + + // + // Find Te Image + // + Status = GetSectionByType(FfsFile, EFI_SECTION_TE, Index, &CurrentPe32Section); + if (EFI_ERROR(Status)) { + break; + } + + CurSecHdrSize = GetSectionHeaderLength(CurrentPe32Section.CommonHeader); + + // + // Calculate the TE base address, the FFS file base plus the offset of the TE section less the size stripped off + // by GenTEImage + // + TEImageHeader = (EFI_TE_IMAGE_HEADER *)((UINT8 *)CurrentPe32Section.Pe32Section + CurSecHdrSize); + + // + // Initialize context, load image info. + // + memset(&ImageContext, 0, sizeof (ImageContext)); + ImageContext.Handle = (VOID *)TEImageHeader; + ImageContext.ImageRead = (PE_COFF_LOADER_READ_FILE)FfsRebaseImageRead; + Status = PeCoffLoaderGetImageInfo(&ImageContext); + if (EFI_ERROR(Status)) { + Error(NULL, 0, 3000, "Invalid TeImage", "The input file is %s and the return status is %x", FileName, (int)Status); + return Status; + } + + //if ((ImageContext.Machine == EFI_IMAGE_MACHINE_ARMT) || + // (ImageContext.Machine == EFI_IMAGE_MACHINE_AARCH64)) { + // mArm = TRUE; + //} + + // + // Keep Image Context for TE image in FV + // + memcpy(&OrigImageContext, &ImageContext, sizeof (ImageContext)); + + // + // Get File PdbPointer + // + PdbPointer = PeCoffLoaderGetPdbPointer(ImageContext.Handle); + if (PdbPointer == NULL) { + PdbPointer = FileName; + } + // + // Set new rebased address. + // + NewPe32BaseAddress = XipBase + (UINTN)TEImageHeader + sizeof (EFI_TE_IMAGE_HEADER) \ + - TEImageHeader->StrippedSize - (UINTN)FfsFile; + + // + // if reloc is stripped, try to get the original efi image to get reloc info. + // + if (ImageContext.RelocationsStripped) { + // + // Construct the original efi file name + // + if (strlen (FileName) > MAX_LONG_FILE_PATH - 1) { + Error(NULL, 0, 3000, "Invalid", "The file name for %s is too long.", FileName); + return EFI_ABORTED; + } + strncpy(PeFileName, FileName, MAX_LONG_FILE_PATH - 1); + PeFileName[MAX_LONG_FILE_PATH - 1] = 0; + Cptr = PeFileName + strlen(PeFileName); + while (*Cptr != '.') { + Cptr--; + } + + if (*Cptr != '.') { + Error(NULL, 0, 3000, "Invalid", "The file %s has no .reloc section.", FileName); + return EFI_ABORTED; + } + else { + *(Cptr + 1) = 'e'; + *(Cptr + 2) = 'f'; + *(Cptr + 3) = 'i'; + *(Cptr + 4) = '\0'; + } + + LongFilePathName = LongFilePath(PeFileName); + if (LongFilePathName == NULL) { + Error(NULL, 0, 3000, "Invalid", "Fail to get long file path for file %s.", FileName); + return EFI_ABORTED; + } + PeFile = fopen(LongFilePathName, "rb"); + if (PeFile == NULL) { + Warning(NULL, 0, 0, "Invalid", "The file %s has no .reloc section.", FileName); + //Error (NULL, 0, 3000, "Invalid", "The file %s has no .reloc section.", FileName); + //return EFI_ABORTED; + } + else { + // + // Get the file size + // + PeFileSize = _filelength(fileno(PeFile)); + PeFileBuffer = (UINT8 *)malloc(PeFileSize); + if (PeFileBuffer == NULL) { + Error(NULL, 0, 4001, "Resource", "memory cannot be allocated on rebase of %s", FileName); + fclose(PeFile); + return EFI_OUT_OF_RESOURCES; + } + // + // Read Pe File + // + fread(PeFileBuffer, sizeof (UINT8), PeFileSize, PeFile); + // + // close file + // + fclose(PeFile); + // + // Append reloc section into TeImage + // + ImageContext.Handle = PeFileBuffer; + Status = PeCoffLoaderGetImageInfo(&ImageContext); + if (EFI_ERROR(Status)) { + Error(NULL, 0, 3000, "Invalid TeImage", "The input file is %s and the return status is %x", FileName, (int)Status); + return Status; + } + ImageContext.RelocationsStripped = FALSE; + } + } + // + // Relocation doesn't exist + // + if (ImageContext.RelocationsStripped) { + Warning(NULL, 0, 0, "Invalid", "The file %s has no .reloc section.", FileName); + continue; + } + + // + // Relocation exist and rebase + // + // + // Load and Relocate Image Data + // + MemoryImagePointer = (UINT8 *)malloc((UINTN)ImageContext.ImageSize + ImageContext.SectionAlignment); + if (MemoryImagePointer == NULL) { + Error(NULL, 0, 4001, "Resource", "memory cannot be allocated on rebase of %s", FileName); + return EFI_OUT_OF_RESOURCES; + } + memset((VOID *)MemoryImagePointer, 0, (UINTN)ImageContext.ImageSize + ImageContext.SectionAlignment); + ImageContext.ImageAddress = ((UINTN)MemoryImagePointer + ImageContext.SectionAlignment - 1) & (~((UINTN)ImageContext.SectionAlignment - 1)); + + Status = PeCoffLoaderLoadImage(&ImageContext); + if (EFI_ERROR(Status)) { + Error(NULL, 0, 3000, "Invalid", "LocateImage() call failed on rebase of %s", FileName); + free((VOID *)MemoryImagePointer); + return Status; + } + // + // Reloacate TeImage + // + ImageContext.DestinationAddress = NewPe32BaseAddress; + Status = PeCoffLoaderRelocateImage(&ImageContext); + if (EFI_ERROR(Status)) { + Error(NULL, 0, 3000, "Invalid", "RelocateImage() call failed on rebase of TE image %s", FileName); + free((VOID *)MemoryImagePointer); + return Status; + } + + // + // Copy the relocated image into raw image file. + // + SectionHeader = (EFI_IMAGE_SECTION_HEADER *)(TEImageHeader + 1); + for (Index = 0; Index < TEImageHeader->NumberOfSections; Index++, SectionHeader++) { + if (!ImageContext.IsTeImage) { + CopyMem( + (UINT8 *)TEImageHeader + sizeof (EFI_TE_IMAGE_HEADER)-TEImageHeader->StrippedSize + SectionHeader->PointerToRawData, + (VOID*)(UINTN)(ImageContext.ImageAddress + SectionHeader->VirtualAddress), + SectionHeader->SizeOfRawData + ); + } + else { + CopyMem( + (UINT8 *)TEImageHeader + sizeof (EFI_TE_IMAGE_HEADER)-TEImageHeader->StrippedSize + SectionHeader->PointerToRawData, + (VOID*)(UINTN)(ImageContext.ImageAddress + sizeof (EFI_TE_IMAGE_HEADER)-TEImageHeader->StrippedSize + SectionHeader->VirtualAddress), + SectionHeader->SizeOfRawData + ); + } + } + + // + // Free the allocated memory resource + // + free((VOID *)MemoryImagePointer); + MemoryImagePointer = NULL; + if (PeFileBuffer != NULL) { + free(PeFileBuffer); + PeFileBuffer = NULL; + } + + // + // Update Image Base Address + // + TEImageHeader->ImageBase = NewPe32BaseAddress; + + // + // Now update file checksum + // + if (FfsFile->Attributes & FFS_ATTRIB_CHECKSUM) { + SavedState = FfsFile->State; + FfsFile->IntegrityCheck.Checksum.File = 0; + FfsFile->State = 0; + FfsFile->IntegrityCheck.Checksum.File = CalculateChecksum8( + (UINT8 *)((UINT8 *)FfsFile + FfsHeaderSize), + GetFfsFileLength(FfsFile) - FfsHeaderSize + ); + FfsFile->State = SavedState; + } + } + + return EFI_SUCCESS; +} + +EFI_STATUS +FfsRebaseImageRead( +IN VOID *FileHandle, +IN UINTN FileOffset, +IN OUT UINT32 *ReadSize, +OUT VOID *Buffer +) +/*++ + +Routine Description: + +Support routine for the PE/COFF Loader that reads a buffer from a PE/COFF file + +Arguments: + +FileHandle - The handle to the PE/COFF file + +FileOffset - The offset, in bytes, into the file to read + +ReadSize - The number of bytes to read from the file starting at FileOffset + +Buffer - A pointer to the buffer to read the data into. + +Returns: + +EFI_SUCCESS - ReadSize bytes of data were read into Buffer from the PE/COFF file starting at FileOffset + +--*/ +{ + CHAR8 *Destination8; + CHAR8 *Source8; + UINT32 Length; + + Destination8 = Buffer; + Source8 = (CHAR8 *)((UINTN)FileHandle + FileOffset); + Length = *ReadSize; + while (Length--) { + *(Destination8++) = *(Source8++); + } + + return EFI_SUCCESS; +} + +EFI_STATUS +GetChildFvFromFfs ( + IN UINT64 BaseAddress, + IN EFI_FFS_FILE_HEADER *FfsFile, + IN UINTN XipOffset + ) +/*++ + +Routine Description: + + This function gets all child FvImages in the input FfsFile, and records + their base address to the parent image. + +Arguments: + FvInfo A pointer to FV_INFO struture. + FfsFile A pointer to Ffs file image that may contain FvImage. + XipOffset The offset address to the parent FvImage base. + +Returns: + + EFI_SUCCESS Base address of child Fv image is recorded. +--*/ +{ + EFI_STATUS Status; + UINTN Index; + EFI_FILE_SECTION_POINTER SubFvSection; + EFI_FIRMWARE_VOLUME_HEADER *SubFvImageHeader; + EFI_PHYSICAL_ADDRESS SubFvBaseAddress; + EFI_FIRMWARE_VOLUME_HEADER *OrigFvHeader; + UINT32 OrigFvLength; + EFI_PHYSICAL_ADDRESS OrigFvBaseAddress; + EFI_FFS_FILE_HEADER *CurrentFile; + + // + // Initialize FV library, saving previous values + // + OrigFvHeader = NULL; + GetFvHeader (&OrigFvHeader, &OrigFvLength); + OrigFvBaseAddress = BaseAddress; + for (Index = 1;; Index++) { + // + // Find FV section + // + Status = GetSectionByType (FfsFile, EFI_SECTION_FIRMWARE_VOLUME_IMAGE, Index, &SubFvSection); + if (EFI_ERROR (Status)) { + break; + } + SubFvImageHeader = (EFI_FIRMWARE_VOLUME_HEADER *) ((UINT8 *) SubFvSection.FVImageSection + GetSectionHeaderLength(SubFvSection.FVImageSection)); + + // + // Rebase on Flash + // + SubFvBaseAddress = OrigFvBaseAddress + (UINTN) SubFvImageHeader - (UINTN) FfsFile + XipOffset; + //mFvBaseAddress[mFvBaseAddressNumber ++ ] = SubFvBaseAddress; + BaseAddress = SubFvBaseAddress; + InitializeFvLib(SubFvImageHeader, (UINT32) SubFvImageHeader->FvLength); + + Status = GetNextFile (NULL, &CurrentFile); + if (EFI_ERROR (Status)) { + Error (NULL, 0, 0003, "error parsing FV image", "FFS file can't be found"); + continue; + } + while (CurrentFile) { + RebaseFfs (BaseAddress, "", CurrentFile, (UINTN) CurrentFile - (UINTN) SubFvImageHeader); + Status = GetNextFile (CurrentFile, &CurrentFile); + if (EFI_ERROR (Status)) { + break; + } + } + } + + BaseAddress = OrigFvBaseAddress; + if (OrigFvHeader != NULL) { + InitializeFvLib(OrigFvHeader, OrigFvLength); + } + + return EFI_SUCCESS; +} + +EFI_STATUS +GetPe32Info ( + IN UINT8 *Pe32, + OUT UINT32 *EntryPoint, + OUT UINT32 *BaseOfCode, + OUT UINT16 *MachineType + ) +/*++ + +Routine Description: + + Retrieves the PE32 entry point offset and machine type from PE image or TeImage. + See EfiImage.h for machine types. The entry point offset is from the beginning + of the PE32 buffer passed in. + +Arguments: + + Pe32 Beginning of the PE32. + EntryPoint Offset from the beginning of the PE32 to the image entry point. + BaseOfCode Base address of code. + MachineType Magic number for the machine type. + +Returns: + + EFI_SUCCESS Function completed successfully. + EFI_ABORTED Error encountered. + EFI_INVALID_PARAMETER A required parameter was NULL. + EFI_UNSUPPORTED The operation is unsupported. + +--*/ +{ + EFI_IMAGE_DOS_HEADER *DosHeader; + EFI_IMAGE_OPTIONAL_HEADER_UNION *ImgHdr; + EFI_TE_IMAGE_HEADER *TeHeader; + + // + // Verify input parameters + // + if (Pe32 == NULL) { + return EFI_INVALID_PARAMETER; + } + + // + // First check whether it is one TE Image. + // + TeHeader = (EFI_TE_IMAGE_HEADER *) Pe32; + if (TeHeader->Signature == EFI_TE_IMAGE_HEADER_SIGNATURE) { + // + // By TeImage Header to get output + // + *EntryPoint = TeHeader->AddressOfEntryPoint + sizeof (EFI_TE_IMAGE_HEADER) - TeHeader->StrippedSize; + *BaseOfCode = TeHeader->BaseOfCode + sizeof (EFI_TE_IMAGE_HEADER) - TeHeader->StrippedSize; + *MachineType = TeHeader->Machine; + } else { + + // + // Then check whether + // First is the DOS header + // + DosHeader = (EFI_IMAGE_DOS_HEADER *) Pe32; + + // + // Verify DOS header is expected + // + if (DosHeader->e_magic != EFI_IMAGE_DOS_SIGNATURE) { + Error (NULL, 0, 3000, "Invalid", "Unknown magic number in the DOS header, 0x%04X.", DosHeader->e_magic); + return EFI_UNSUPPORTED; + } + // + // Immediately following is the NT header. + // + ImgHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *) ((UINTN) Pe32 + DosHeader->e_lfanew); + + // + // Verify NT header is expected + // + if (ImgHdr->Pe32.Signature != EFI_IMAGE_NT_SIGNATURE) { + Error (NULL, 0, 3000, "Invalid", "Unrecognized image signature 0x%08X.", (unsigned) ImgHdr->Pe32.Signature); + return EFI_UNSUPPORTED; + } + // + // Get output + // + *EntryPoint = ImgHdr->Pe32.OptionalHeader.AddressOfEntryPoint; + *BaseOfCode = ImgHdr->Pe32.OptionalHeader.BaseOfCode; + *MachineType = ImgHdr->Pe32.FileHeader.Machine; + } + + // + // Verify machine type is supported + // + if ((*MachineType != EFI_IMAGE_MACHINE_IA32) && (*MachineType != EFI_IMAGE_MACHINE_X64) && (*MachineType != EFI_IMAGE_MACHINE_EBC) && + (*MachineType != EFI_IMAGE_MACHINE_ARMT) && (*MachineType != EFI_IMAGE_MACHINE_AARCH64)) { + Error (NULL, 0, 3000, "Invalid", "Unrecognized machine type in the PE32 file."); + return EFI_UNSUPPORTED; + } + + return EFI_SUCCESS; +} + diff --git a/BaseTools/Source/C/FMMT/Rebase.h b/BaseTools/Source/C/FMMT/Rebase.h new file mode 100644 index 0000000000..57604a357f --- /dev/null +++ b/BaseTools/Source/C/FMMT/Rebase.h @@ -0,0 +1,31 @@ +/** @file Rebase.h + + Library to rebase PE image. + + Copyright (c) 2019, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _FMMT_REBASE_H +#define _FMMT_REBASE_H + +#include +#include + +EFI_STATUS +RebaseFfs( +IN OUT UINT64 BaseAddress, +IN CHAR8 *FileName, +IN OUT EFI_FFS_FILE_HEADER *FfsFile, +IN UINTN XipOffset +); + +EFI_STATUS +GetChildFvFromFfs ( + IN UINT64 BaseAddress, + IN EFI_FFS_FILE_HEADER *FfsFile, + IN UINTN XipOffset +); + +#endif diff --git a/BaseTools/Source/C/GNUmakefile b/BaseTools/Source/C/GNUmakefile index 990c6d0a82..b99b5121f5 100644 --- a/BaseTools/Source/C/GNUmakefile +++ b/BaseTools/Source/C/GNUmakefile @@ -47,6 +47,7 @@ VFRAUTOGEN = VfrCompile/VfrLexer.h APPLICATIONS = \ BrotliCompress \ VfrCompile \ + FMMT \ BfmLib \ EfiRom \ FCE \ diff --git a/BaseTools/Source/C/Makefile b/BaseTools/Source/C/Makefile index 357e8b9003..4377ec5522 100644 --- a/BaseTools/Source/C/Makefile +++ b/BaseTools/Source/C/Makefile @@ -12,6 +12,7 @@ LIBRARIES = Common APPLICATIONS = \ VfrCompile \ BrotliCompress \ + FMMT \ BfmLib \ EfiRom \ FCE \