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 \