public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
* [edk2-platform patch 0/6] Add tools FMMT FCE and FitGen
@ 2019-06-21  1:26 Zhang, Shenglei
  2019-06-21  1:26 ` [edk2-platform patch 1/6] Platform\Tools: Add a tool FMMT Zhang, Shenglei
                   ` (6 more replies)
  0 siblings, 7 replies; 15+ messages in thread
From: Zhang, Shenglei @ 2019-06-21  1:26 UTC (permalink / raw)
  To: devel; +Cc: Bob Feng, Liming Gao

Add FMMT and FCE into Platform/Intel/Tools.
Add FitGen into Silicon/Intel/Tools.
https://bugzilla.tianocore.org/show_bug.cgi?id=1847
https://bugzilla.tianocore.org/show_bug.cgi?id=1848
https://bugzilla.tianocore.org/show_bug.cgi?id=1849

Cc: Bob Feng <bob.c.feng@intel.com>
Cc: Liming Gao <liming.gao@intel.com>
Shenglei Zhang (6):
  Platform/Tools: Add a tool FMMT
  Platform/Tools: Add a tool BfmLib
  BaseTools/FCE: Add a tool FCE
  Platform/Tools: Add top level Makefile and GNUMakefile
  Silicon/Tools: Add a tool FitGen
  Silicon/Tools: Add top level Makefile and GNUMakefile

 Platform/Intel/Tools/BfmLib/BfmLib.c          | 4355 +++++++++++
 Platform/Intel/Tools/BfmLib/BinFileManager.c  | 1024 +++
 Platform/Intel/Tools/BfmLib/BinFileManager.h  |  439 ++
 Platform/Intel/Tools/BfmLib/GNUmakefile       |   15 +
 Platform/Intel/Tools/BfmLib/Makefile          |   17 +
 Platform/Intel/Tools/FCE/BinaryCreate.c       |  216 +
 Platform/Intel/Tools/FCE/BinaryCreate.h       |  157 +
 Platform/Intel/Tools/FCE/BinaryParse.c        | 1326 ++++
 Platform/Intel/Tools/FCE/BinaryParse.h        |  187 +
 Platform/Intel/Tools/FCE/Common.c             | 2183 ++++++
 Platform/Intel/Tools/FCE/Common.h             |  999 +++
 Platform/Intel/Tools/FCE/Expression.c         | 2367 ++++++
 Platform/Intel/Tools/FCE/Fce.c                | 6449 +++++++++++++++++
 Platform/Intel/Tools/FCE/Fce.h                |  447 ++
 Platform/Intel/Tools/FCE/GNUmakefile          |   22 +
 Platform/Intel/Tools/FCE/IfrParse.c           | 4836 ++++++++++++
 Platform/Intel/Tools/FCE/IfrParse.h           |  789 ++
 Platform/Intel/Tools/FCE/Makefile             |   19 +
 .../Intel/Tools/FCE/MonotonicBasedVariable.c  |  874 +++
 .../Intel/Tools/FCE/MonotonicBasedVariable.h  |  162 +
 Platform/Intel/Tools/FCE/TimeBasedVariable.c  |  878 +++
 Platform/Intel/Tools/FCE/TimeBasedVariable.h  |  166 +
 Platform/Intel/Tools/FCE/Variable.c           | 1091 +++
 Platform/Intel/Tools/FCE/Variable.h           |  154 +
 Platform/Intel/Tools/FCE/VariableCommon.h     |   55 +
 .../Tools/FMMT/FirmwareModuleManagement.c     | 2559 +++++++
 .../Tools/FMMT/FirmwareModuleManagement.h     |  479 ++
 Platform/Intel/Tools/FMMT/FmmtConf.ini        |    6 +
 Platform/Intel/Tools/FMMT/FmmtLib.c           | 5051 +++++++++++++
 Platform/Intel/Tools/FMMT/GNUmakefile         |   16 +
 Platform/Intel/Tools/FMMT/Makefile            |   17 +
 Platform/Intel/Tools/FMMT/Rebase.c            |  846 +++
 Platform/Intel/Tools/FMMT/Rebase.h            |   31 +
 Platform/Intel/Tools/GNUmakefile              |   30 +
 Platform/Intel/Tools/Makefile                 |   33 +
 Silicon/Intel/Tools/FitGen/FitGen.c           | 3137 ++++++++
 Silicon/Intel/Tools/FitGen/FitGen.h           |   48 +
 Silicon/Intel/Tools/FitGen/GNUmakefile        |   16 +
 Silicon/Intel/Tools/FitGen/Makefile           |   17 +
 Silicon/Intel/Tools/GNUmakefile               |   34 +
 Silicon/Intel/Tools/Makefile                  |   31 +
 41 files changed, 41578 insertions(+)
 create mode 100644 Platform/Intel/Tools/BfmLib/BfmLib.c
 create mode 100644 Platform/Intel/Tools/BfmLib/BinFileManager.c
 create mode 100644 Platform/Intel/Tools/BfmLib/BinFileManager.h
 create mode 100644 Platform/Intel/Tools/BfmLib/GNUmakefile
 create mode 100644 Platform/Intel/Tools/BfmLib/Makefile
 create mode 100644 Platform/Intel/Tools/FCE/BinaryCreate.c
 create mode 100644 Platform/Intel/Tools/FCE/BinaryCreate.h
 create mode 100644 Platform/Intel/Tools/FCE/BinaryParse.c
 create mode 100644 Platform/Intel/Tools/FCE/BinaryParse.h
 create mode 100644 Platform/Intel/Tools/FCE/Common.c
 create mode 100644 Platform/Intel/Tools/FCE/Common.h
 create mode 100644 Platform/Intel/Tools/FCE/Expression.c
 create mode 100644 Platform/Intel/Tools/FCE/Fce.c
 create mode 100644 Platform/Intel/Tools/FCE/Fce.h
 create mode 100644 Platform/Intel/Tools/FCE/GNUmakefile
 create mode 100644 Platform/Intel/Tools/FCE/IfrParse.c
 create mode 100644 Platform/Intel/Tools/FCE/IfrParse.h
 create mode 100644 Platform/Intel/Tools/FCE/Makefile
 create mode 100644 Platform/Intel/Tools/FCE/MonotonicBasedVariable.c
 create mode 100644 Platform/Intel/Tools/FCE/MonotonicBasedVariable.h
 create mode 100644 Platform/Intel/Tools/FCE/TimeBasedVariable.c
 create mode 100644 Platform/Intel/Tools/FCE/TimeBasedVariable.h
 create mode 100644 Platform/Intel/Tools/FCE/Variable.c
 create mode 100644 Platform/Intel/Tools/FCE/Variable.h
 create mode 100644 Platform/Intel/Tools/FCE/VariableCommon.h
 create mode 100644 Platform/Intel/Tools/FMMT/FirmwareModuleManagement.c
 create mode 100644 Platform/Intel/Tools/FMMT/FirmwareModuleManagement.h
 create mode 100644 Platform/Intel/Tools/FMMT/FmmtConf.ini
 create mode 100644 Platform/Intel/Tools/FMMT/FmmtLib.c
 create mode 100644 Platform/Intel/Tools/FMMT/GNUmakefile
 create mode 100644 Platform/Intel/Tools/FMMT/Makefile
 create mode 100644 Platform/Intel/Tools/FMMT/Rebase.c
 create mode 100644 Platform/Intel/Tools/FMMT/Rebase.h
 create mode 100644 Platform/Intel/Tools/GNUmakefile
 create mode 100644 Platform/Intel/Tools/Makefile
 create mode 100644 Silicon/Intel/Tools/FitGen/FitGen.c
 create mode 100644 Silicon/Intel/Tools/FitGen/FitGen.h
 create mode 100644 Silicon/Intel/Tools/FitGen/GNUmakefile
 create mode 100644 Silicon/Intel/Tools/FitGen/Makefile
 create mode 100644 Silicon/Intel/Tools/GNUmakefile
 create mode 100644 Silicon/Intel/Tools/Makefile

-- 
2.18.0.windows.1


^ permalink raw reply	[flat|nested] 15+ messages in thread

* [edk2-platform patch 1/6] Platform\Tools: Add a tool FMMT
  2019-06-21  1:26 [edk2-platform patch 0/6] Add tools FMMT FCE and FitGen Zhang, Shenglei
@ 2019-06-21  1:26 ` Zhang, Shenglei
  2019-06-21  1:26 ` [edk2-platform patch 2/6] Platform\Tools: Add a tool BfmLib Zhang, Shenglei
                   ` (5 subsequent siblings)
  6 siblings, 0 replies; 15+ messages in thread
From: Zhang, Shenglei @ 2019-06-21  1:26 UTC (permalink / raw)
  To: devel; +Cc: Bob Feng, Liming Gao

FMMT is a tool to enable removal, addition and replacement of
FFS files in FD image binaries.
https://bugzilla.tianocore.org/show_bug.cgi?id=1847

Cc: Bob Feng <bob.c.feng@intel.com>
Cc: Liming Gao <liming.gao@intel.com>
Signed-off-by: Shenglei Zhang <shenglei.zhang@intel.com>
---
 .../Tools/FMMT/FirmwareModuleManagement.c     | 2559 +++++++++
 .../Tools/FMMT/FirmwareModuleManagement.h     |  479 ++
 Platform/Intel/Tools/FMMT/FmmtConf.ini        |    6 +
 Platform/Intel/Tools/FMMT/FmmtLib.c           | 5051 +++++++++++++++++
 Platform/Intel/Tools/FMMT/GNUmakefile         |   16 +
 Platform/Intel/Tools/FMMT/Makefile            |   17 +
 Platform/Intel/Tools/FMMT/Rebase.c            |  846 +++
 Platform/Intel/Tools/FMMT/Rebase.h            |   31 +
 8 files changed, 9005 insertions(+)
 create mode 100644 Platform/Intel/Tools/FMMT/FirmwareModuleManagement.c
 create mode 100644 Platform/Intel/Tools/FMMT/FirmwareModuleManagement.h
 create mode 100644 Platform/Intel/Tools/FMMT/FmmtConf.ini
 create mode 100644 Platform/Intel/Tools/FMMT/FmmtLib.c
 create mode 100644 Platform/Intel/Tools/FMMT/GNUmakefile
 create mode 100644 Platform/Intel/Tools/FMMT/Makefile
 create mode 100644 Platform/Intel/Tools/FMMT/Rebase.c
 create mode 100644 Platform/Intel/Tools/FMMT/Rebase.h

diff --git a/Platform/Intel/Tools/FMMT/FirmwareModuleManagement.c b/Platform/Intel/Tools/FMMT/FirmwareModuleManagement.c
new file mode 100644
index 0000000000..63ae3c45a4
--- /dev/null
+++ b/Platform/Intel/Tools/FMMT/FirmwareModuleManagement.c
@@ -0,0 +1,2559 @@
+/** @file
+
+ FMMT main routine.
+
+Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "FirmwareModuleManagement.h"
+#include "Rebase.h"
+#include <stdlib.h>
+#include <wchar.h>
+
+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 <input-binary-file>\n\
+            View each FV and the named files within each FV.\n");
+
+  //
+  // Command Line for Delete entire FV
+  //
+  fprintf (stdout, "  -d <input-binary-file> <FV-id> <output-binary-file>\n\
+            Delete the entire FV in an FD binary\n");
+
+  //
+  // Command Line for Delete file from FV
+  //
+  fprintf (stdout, "  -d <input-binary-file> <FV-id> <File-Name> [<FV-id> <File-Name> ...] <output-binary-file>\n\
+            Delete a file (or files) from the firmware volume in an FD binary\n");
+
+  //
+  // Command Line for Add
+  //
+  fprintf (stdout, "  -a <input-binary-file> <FV-id> <NewFilePath> [<FV-id> <NewFilePath> ...] <output-binary-file>\n\
+            Add a file (or files) to the firmware volume in an FD binary\n");
+
+  //
+  // Command Line for Replace
+  //
+  fprintf (stdout, "  -r <input-binary-file> <FV-id> <File-Name> <NewFilePath> [<FV-id> <File-Name> <NewFilePath> ...] <output-binary-file>\n\
+            The replace command combines the functionality of remove and add into a single operation.\n");
+
+  fprintf (stdout, "\nNote:\n");
+  fprintf (stdout, "  <FV-id> 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; i<len; ++i){
+        p = head;
+        for(j=0; j<len-i; j++){
+            if(p->SubLevel < 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 <input-binary-file>", 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 <input-binary-file> 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 <input-binary-file> 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 <input-binary-file> 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 <input-binary-file> 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/Platform/Intel/Tools/FMMT/FirmwareModuleManagement.h b/Platform/Intel/Tools/FMMT/FirmwareModuleManagement.h
new file mode 100644
index 0000000000..ec8e3eaba0
--- /dev/null
+++ b/Platform/Intel/Tools/FMMT/FirmwareModuleManagement.h
@@ -0,0 +1,479 @@
+/** @file
+
+ Structures and functions declaration.
+
+ Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef    _BIN_FILE_MANAGER_
+#define    _BIN_FILE_MANAGER_
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#ifdef __GNUC__
+#include <unistd.h>
+#else
+#include <io.h>
+#include <direct.h>
+#endif
+#include <FvLib.h>
+#include <Common/UefiBaseTypes.h>
+#include <Common/PiFirmwareVolume.h>
+#include <Common/PiFirmwareFile.h>
+#include <Protocol/GuidedSectionExtraction.h>
+
+#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/Platform/Intel/Tools/FMMT/FmmtConf.ini b/Platform/Intel/Tools/FMMT/FmmtConf.ini
new file mode 100644
index 0000000000..36135116b3
--- /dev/null
+++ b/Platform/Intel/Tools/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/Platform/Intel/Tools/FMMT/FmmtLib.c b/Platform/Intel/Tools/FMMT/FmmtLib.c
new file mode 100644
index 0000000000..f87042114b
--- /dev/null
+++ b/Platform/Intel/Tools/FMMT/FmmtLib.c
@@ -0,0 +1,5051 @@
+/** @file
+
+ Library to parse and generate FV image.
+
+ Copyright (c)  2019, Intel Corporation. All rights reserved.<BR>
+ 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/Platform/Intel/Tools/FMMT/GNUmakefile b/Platform/Intel/Tools/FMMT/GNUmakefile
new file mode 100644
index 0000000000..911d747451
--- /dev/null
+++ b/Platform/Intel/Tools/FMMT/GNUmakefile
@@ -0,0 +1,16 @@
+## @file
+# GNU/Linux makefile for 'FMMT' module build.
+#
+# Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+MAKEROOT ?= $(EDK_TOOLS_PATH)/Source/C
+
+APPNAME = FMMT
+
+LIBS = -lCommon
+
+OBJECTS = FmmtLib.o Rebase.o FirmwareModuleManagement.o
+
+include $(MAKEROOT)/Makefiles/app.makefile
+
diff --git a/Platform/Intel/Tools/FMMT/Makefile b/Platform/Intel/Tools/FMMT/Makefile
new file mode 100644
index 0000000000..1a96e0e27f
--- /dev/null
+++ b/Platform/Intel/Tools/FMMT/Makefile
@@ -0,0 +1,17 @@
+## @file
+# Windows makefile for 'FMMT' module build.
+#
+# Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+
+!INCLUDE $(EDK_TOOLS_PATH)\Source\C\Makefiles\ms.common
+
+APPNAME = FMMT
+
+LIBS = $(LIB_PATH)\Common.lib
+
+OBJECTS = FirmwareModuleManagement.obj FmmtLib.obj Rebase.obj
+
+!INCLUDE $(EDK_TOOLS_PATH)\Source\C\Makefiles\ms.app
+
diff --git a/Platform/Intel/Tools/FMMT/Rebase.c b/Platform/Intel/Tools/FMMT/Rebase.c
new file mode 100644
index 0000000000..d32217d18c
--- /dev/null
+++ b/Platform/Intel/Tools/FMMT/Rebase.c
@@ -0,0 +1,846 @@
+/** @file
+
+ Library to rebase PE image.
+
+Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "Rebase.h"
+#include <stdio.h>
+#include <stdlib.h>
+#ifdef __GNUC__
+#include <unistd.h>
+#else
+#include <io.h>
+#include <direct.h>
+#endif
+#include <PeCoffLib.h>
+#include <CommonLib.h>
+#include <IndustryStandard/PeImage.h>
+#include <FvLib.h>
+#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/Platform/Intel/Tools/FMMT/Rebase.h b/Platform/Intel/Tools/FMMT/Rebase.h
new file mode 100644
index 0000000000..57604a357f
--- /dev/null
+++ b/Platform/Intel/Tools/FMMT/Rebase.h
@@ -0,0 +1,31 @@
+/** @file  Rebase.h
+
+ Library to rebase PE image.
+
+ Copyright (c)  2019, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _FMMT_REBASE_H
+#define _FMMT_REBASE_H
+
+#include <Common/UefiBaseTypes.h>
+#include <Common/PiFirmwareFile.h>
+
+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
-- 
2.18.0.windows.1


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [edk2-platform patch 2/6] Platform\Tools: Add a tool BfmLib
  2019-06-21  1:26 [edk2-platform patch 0/6] Add tools FMMT FCE and FitGen Zhang, Shenglei
  2019-06-21  1:26 ` [edk2-platform patch 1/6] Platform\Tools: Add a tool FMMT Zhang, Shenglei
@ 2019-06-21  1:26 ` Zhang, Shenglei
  2019-06-21  1:26 ` [edk2-platform patch 3/6] BaseTools\FCE: Add a tool FCE Zhang, Shenglei
                   ` (4 subsequent siblings)
  6 siblings, 0 replies; 15+ messages in thread
From: Zhang, Shenglei @ 2019-06-21  1:26 UTC (permalink / raw)
  To: devel; +Cc: Bob Feng, Liming Gao

BmfLib is added for FCE tool.
https://bugzilla.tianocore.org/show_bug.cgi?id=1848

Cc: Bob Feng <bob.c.feng@intel.com>
Cc: Liming Gao <liming.gao@intel.com>
Signed-off-by: Shenglei Zhang <shenglei.zhang@intel.com>
---
 Platform/Intel/Tools/BfmLib/BfmLib.c         | 4355 ++++++++++++++++++
 Platform/Intel/Tools/BfmLib/BinFileManager.c | 1024 ++++
 Platform/Intel/Tools/BfmLib/BinFileManager.h |  439 ++
 Platform/Intel/Tools/BfmLib/GNUmakefile      |   15 +
 Platform/Intel/Tools/BfmLib/Makefile         |   17 +
 5 files changed, 5850 insertions(+)
 create mode 100644 Platform/Intel/Tools/BfmLib/BfmLib.c
 create mode 100644 Platform/Intel/Tools/BfmLib/BinFileManager.c
 create mode 100644 Platform/Intel/Tools/BfmLib/BinFileManager.h
 create mode 100644 Platform/Intel/Tools/BfmLib/GNUmakefile
 create mode 100644 Platform/Intel/Tools/BfmLib/Makefile

diff --git a/Platform/Intel/Tools/BfmLib/BfmLib.c b/Platform/Intel/Tools/BfmLib/BfmLib.c
new file mode 100644
index 0000000000..9dedda3da2
--- /dev/null
+++ b/Platform/Intel/Tools/BfmLib/BfmLib.c
@@ -0,0 +1,4355 @@
+/** @file
+
+ Library to process EFI image.
+
+ Copyright (c) 2011-2019, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "BinFileManager.h"
+
+#define EFI_TEST_FFS_ATTRIBUTES_BIT(FvbAttributes, TestAttributes, Bit) \
+    ( \
+      (BOOLEAN) ( \
+          (FvbAttributes & EFI_FVB2_ERASE_POLARITY) ? (((~TestAttributes) & Bit) == Bit) : ((TestAttributes & Bit) == Bit) \
+        ) \
+    )
+
+#ifndef __GNUC__
+#define DECODE_STR           "%s -d -o \"%s\" \"%s\" > NUL"
+#define ENCODE_STR           "%s -e \"%s\" -o \"%s\" > NUL"
+#define GENSEC_COMPRESSION   "GenSec -s %s -c %s  \"%s\" -o \"%s\" > NUL"
+#define GENSEC_GUID          "GenSec -s %s -r PROCESSING_REQUIRED -g %s \"%s\" -o \"%s\" > NUL"
+#define GENSEC_STR           "GenSec -s %s \"%s\" -o \"%s\" > NUL"
+#define GENSEC_ALIGN         "GenSec --sectionalign 16 \"%s\" -o \"%s\" > NUL"
+#define GENFV_STR            "GenFv -i \"%s\" -o \"%s\" > NUL"
+#define GENFV_FVGUID         "GenFv -i \"%s\" -o \"%s\" --FvNameGuid %s > NUL"
+#define GENFV_FFS            "GenFv -f \"%s\" -g %s -o \"%s\" > NUL"
+#define GENFFS_STR           "GenFfs -t %s -i \"%s\" -g %s -o \"%s\" > NUL"
+#define GENFFS_FIX           "GenFfs -t %s -i \"%s\" -g %s -x -o \"%s\" > NUL"
+#else
+#define DECODE_STR           "%s -d -o \"%s\" \"%s\" > /dev/null"
+#define ENCODE_STR           "%s -e \"%s\" -o \"%s\" > /dev/null"
+#define GENSEC_COMPRESSION   "GenSec -s %s -c %s  \"%s\" -o \"%s\" > /dev/null"
+#define GENSEC_GUID          "GenSec -s %s -r PROCESSING_REQUIRED -g %s \"%s\" -o \"%s\" > /dev/null"
+#define GENSEC_STR           "GenSec -s %s \"%s\" -o \"%s\" > /dev/null"
+#define GENSEC_ALIGN         "GenSec --sectionalign 16 \"%s\" -o \"%s\" > /dev/null"
+#define GENFV_STR            "GenFv -i \"%s\" -o \"%s\" > /dev/null"
+#define GENFV_FVGUID         "GenFv -i \"%s\" -o \"%s\" --FvNameGuid %s > /dev/null"
+#define GENFV_FFS            "GenFv -f \"%s\" -g %s -o \"%s\" > /dev/null"
+#define GENFFS_STR           "GenFfs -t %s -i \"%s\" -g %s -o \"%s\" > /dev/null"
+#define GENFFS_FIX           "GenFfs -t %s -i \"%s\" -g %s -x -o \"%s\" > /dev/null"
+#endif
+
+#define DECODE_STR_ERR       "%s -d -o \"%s\" \"%s\" "
+#define ENCODE_STR_ERR       "%s -e \"%s\" -o \"%s\" "
+
+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 };
+extern     CHAR8*      mGuidToolDefinition;
+UINT32     PadSizeOfBfv;
+
+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
+ };
+
+FV_INFORMATION *
+LibInitializeFvStruct (
+  FV_INFORMATION *Fv
+)
+{
+  UINT32     Index;
+
+  if (Fv == NULL) {
+    return NULL;
+  }
+
+  memset (Fv, '\0', sizeof (FV_INFORMATION));
+
+  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);
+
+    Fv->FfsAttuibutes[Index].IsLeaf               = TRUE;
+    Fv->FfsAttuibutes[Index].TotalSectionNum      = 0;
+  }
+
+  Fv->PatchData = NULL;
+  Fv->EncapData = NULL;
+  Fv->FvNext = NULL;
+  Fv->FvLevel   = 0;
+  Fv->IsBfvFlag = FALSE;
+  Fv->IsInputFvFlag = FALSE;
+
+  return Fv;
+}
+
+/**
+  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;
+}
+
+EFI_STATUS
+LibFindFvInFd (
+  IN     FILE             *InputFile,
+  IN OUT FIRMWARE_DEVICE  **FdData
+)
+{
+  FIRMWARE_DEVICE             *LocalFdData;
+  UINT16                      Index;
+  CHAR8                       Ffs2Guid[16];
+  CHAR8                       SignatureCheck[4];
+  CHAR8                       Signature[5] = "_FVH";
+  FV_INFORMATION              *CurrentFv;
+  FV_INFORMATION              *NewFoundFv;
+  BOOLEAN                     FirstMatch;
+  UINT32                      FdSize;
+  UINT16                      FvCount;
+  VOID                        *FdBuffer;
+  VOID                        *FdBufferOri;
+  UINT32                      Count;
+
+
+  CurrentFv      = NULL;
+  NewFoundFv     = NULL;
+  FdBuffer       = NULL;
+  FdBufferOri    = NULL;
+  FirstMatch     = TRUE;
+  Index          = 0;
+  FdSize         = 0;
+  FvCount        = 0;
+  Count          = 0;
+  LocalFdData    = NULL;
+
+  if (InputFile == NULL) {
+    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 *) calloc (sizeof (FIRMWARE_DEVICE), sizeof(UINT8));
+  if (LocalFdData == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+  LocalFdData->Fv = (FV_INFORMATION *)  calloc (sizeof (FV_INFORMATION), sizeof(UINT8));
+  if (LocalFdData->Fv == NULL) {
+    free (LocalFdData);
+    return EFI_OUT_OF_RESOURCES;
+  }
+  LibInitializeFvStruct (LocalFdData->Fv);
+
+  //
+  // Readout the FD file data to buffer.
+  //
+  FdBuffer = malloc (FdSize);
+
+  if (FdBuffer == NULL) {
+    free (LocalFdData->Fv);
+    free (LocalFdData);
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  if (fread (FdBuffer, 1, FdSize, InputFile) != FdSize) {
+    free (LocalFdData->Fv);
+    free (LocalFdData);
+    free (FdBuffer);
+    return EFI_ABORTED;
+  }
+
+  FdBufferOri = FdBuffer;
+
+  for (Count=0; Count < FdSize - 4; Count++) {
+    //
+    // Copy 4 bytes of fd data to check the _FVH signature
+    //
+    memcpy (SignatureCheck, FdBuffer, 4);
+    FdBuffer =(UINT8 *)FdBuffer + 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.
+      // Turn back 28 bytes to find the GUID.
+      //
+      FdBuffer = (UINT8 *)FdBuffer - 28;
+      memcpy (Ffs2Guid, FdBuffer, 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;
+          }
+        }
+    }
+
+      //
+      // Point to the original address
+      //
+      FdBuffer = (UINT8 *)FdBuffer + 28;
+
+      //
+      // Here we found an FV.
+      //
+      if (Index == 16) {
+        if (FirstMatch) {
+          LocalFdData->Fv->ImageAddress = (UINTN)((UINT8 *)FdBuffer - (UINT8 *)FdBufferOri) - 0x2c;
+          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 (NULL == NewFoundFv) {
+              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) - 0x2c;
+
+            //
+            // 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 ++;
+        Index = 0;
+      }
+
+    }
+
+    //
+    // We need to turn back 3 bytes.
+    //
+    FdBuffer = (UINT8 *)FdBuffer - 3;
+  }
+
+  LocalFdData->Size = FdSize;
+
+  *FdData = LocalFdData;
+
+  free (FdBufferOri);
+
+  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) {
+    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;
+}
+
+/**
+
+  Expands the 3 byte size commonly used in Firmware Volume data structures
+
+  @param[in]    Size - Address of the 3 byte array representing the size
+
+  @return       UINT32
+
+**/
+UINT32
+FvBufExpand3ByteSize (
+  IN VOID* Size
+  )
+{
+  return (((UINT8*)Size)[2] << 16) +
+         (((UINT8*)Size)[1] << 8) +
+         ((UINT8*)Size)[0];
+}
+
+/**
+
+  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;
+}
+/**
+
+  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;
+}
+
+/*
+  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;
+  CHAR8                       TempBuf[_MAX_PATH];
+
+  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) {
+    printf ("The directory is too long \n");
+    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 (NULL == FfsFileName) {
+    return EFI_ABORTED;
+  }
+  memset (FfsFileName, '\0', _MAX_PATH);
+  FfsFileSize = GetFfsFileLength ((EFI_FFS_FILE_HEADER *) CurrentFile);
+
+  sprintf (
+    TempBuf,
+    "-Num%d-%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X-Level%d",
+    *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
+  );
+  if (strlen (TempDir) + strlen (OS_SEP_STR) + strlen (TEMP_DIR_NAME) + strlen(TempBuf) > _MAX_PATH - 1) {
+    free(FfsFileName);
+    printf ("The directory is too long \n");
+    return EFI_ABORTED;
+  }
+  strcpy (FfsFileName, TempDir);
+  strncat (FfsFileName, OS_SEP_STR, _MAX_PATH - strlen (FfsFileName) - 1);
+  strncat (FfsFileName, CurrentFv->FvName, _MAX_PATH - strlen (FfsFileName) - 1);
+  strncat (FfsFileName, TempBuf, _MAX_PATH - strlen (FfsFileName) - 1);
+
+  memcpy (CurrentFv->FfsAttuibutes[*FfsCount].FfsName, FfsFileName, strlen(FfsFileName));
+
+  //
+  // Update current FFS files file state.
+  //
+  if (ErasePolarity) {
+    CurrentFile->State = (UINT8)~(CurrentFile->State);
+  }
+
+  FfsFile = fopen (FfsFileName, "wb+");
+  if (FfsFile == NULL) {
+    free(FfsFileName);
+    return EFI_ABORTED;
+  }
+
+  if (fwrite (CurrentFile, 1, FfsFileSize, FfsFile) != FfsFileSize) {
+     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;
+}
+
+
+BOOLEAN
+LibCheckPadFfsContainFvNameGuid (
+  IN     FV_INFORMATION            *CurrentFv,
+  IN     EFI_FFS_FILE_HEADER2      *CurrentFile
+)
+{
+  UINT32                      FfsFileSize;
+  UINT32                      FfsDataSize;
+  EFI_GUID                    *FfsData;
+  ENCAP_INFO_DATA             *LocalEncapData;
+
+  LocalEncapData = NULL;
+
+  FfsFileSize = GetFfsFileLength ((EFI_FFS_FILE_HEADER *) CurrentFile);
+  FfsDataSize = FfsFileSize - GetFfsHeaderLength  ((EFI_FFS_FILE_HEADER *) CurrentFile);
+  FfsData     = (EFI_GUID *) ((INT8 *)CurrentFile + GetFfsHeaderLength  ((EFI_FFS_FILE_HEADER *) CurrentFile));
+
+  if (FfsDataSize == 0) {
+    return TRUE;
+  }
+
+  LocalEncapData = CurrentFv->EncapData;
+
+  do {
+    if (LocalEncapData->FvExtHeader != NULL) {
+      if (CompareGuid(FfsData, &LocalEncapData->FvExtHeader->FvName) == 0) {
+        return TRUE;
+      }
+    }
+    LocalEncapData = LocalEncapData->NextNode;
+  } while (LocalEncapData->NextNode != NULL);
+
+  return FALSE;
+}
+
+BOOLEAN
+LibCheckPadFfsNotNull (
+  IN     EFI_FFS_FILE_HEADER2       *CurrentFile
+)
+{
+  UINT32                      FfsFileSize;
+  UINT32                      FfsDataSize;
+  INT8                        *FfsData;
+
+  FfsFileSize = GetFfsFileLength ((EFI_FFS_FILE_HEADER *) CurrentFile);
+  FfsDataSize = FfsFileSize - GetFfsHeaderLength  ((EFI_FFS_FILE_HEADER *) CurrentFile);
+  FfsData     = (INT8 *)CurrentFile + GetFfsHeaderLength  ((EFI_FFS_FILE_HEADER *) CurrentFile);
+
+  if (FfsDataSize == 0) {
+    return FALSE;
+  }
+
+  while (FfsDataSize > 0) {
+    if (((FfsData[FfsDataSize-1]) & 0xFF) != 0xFF) {
+      return TRUE;
+    }
+    FfsDataSize--;
+  }
+
+  return FALSE;
+}
+
+/**
+  Find a maximum length of free space in PAD FFS of Bfv.
+
+  @PadFfsHeader - The header of PAD FFS file
+
+  @return The length of free space
+
+**/
+UINT32
+GetBfvMaxFreeSpace (
+  IN EFI_FFS_FILE_HEADER2  *PadFfsHeader
+  )
+{
+   UINT32    FfsSize;
+   UINT32    Count;
+   UINT32    Index;
+   UINT32    MaxSize;
+   UINT32    HeaderSize;
+
+   Index   = 0;
+   MaxSize = 0;
+
+   if (PadFfsHeader == NULL) {
+     return MaxSize;
+   }
+
+   FfsSize    = GetFfsFileLength ((EFI_FFS_FILE_HEADER *) PadFfsHeader);
+   HeaderSize = GetFfsHeaderLength  ((EFI_FFS_FILE_HEADER *) PadFfsHeader);
+
+    for (Count = HeaderSize; Count < FfsSize; Count++) {
+      if (((((INT8 *)PadFfsHeader)[Count]) & 0xFF) == 0xFF) {
+        Index++;
+      } else {
+        if (Index > MaxSize) {
+          MaxSize = Index;
+        }
+        Index = 0;
+      }
+    }
+    return MaxSize;
+}
+
+
+/**
+
+  Get the Offset and data of PAD FFS file in FV file.
+  This function should be only called for find an PAD FFS contain additional data
+  (usually will contain FIT table data or reset vector.)
+
+   BFV:
+   ----------------------      <- Low
+  |                      |
+  |                      |
+   -----------------------
+  |       FFSs ...       |
+   -----------------------
+  |                      |
+  |                      |
+   -----------------------
+  |     PAD FFS file     |
+  |                      |
+  |      reset vector    |
+  |                      |
+  |      FIT table       |
+   -----------------------
+  |      SEC CORE        |     <- High
+   -----------------------
+
+**/
+
+EFI_STATUS
+LibFindResetVectorAndFitTableData(
+  IN     EFI_FIRMWARE_VOLUME_HEADER  *FvImage,
+  IN     EFI_FFS_FILE_HEADER2        *CurrentFile,
+  IN OUT FV_INFORMATION              *CurrentFv
+)
+{
+  UINT32          Count1;
+  UINT32          Count2;
+  UINT32          FfsFileSize;
+  BOOLEAN         FfsFoundFlag;
+  UINT32          FfsOffset;
+  UINT32          DataOffset;
+  UINT32          HeaderSize;
+  PATCH_DATA_PAD_FFS *LocalPatchData;
+
+  FfsFileSize    = 0;
+  Count1         = 0;
+  Count2         = 0;
+  FfsOffset      = 0;
+  DataOffset     = 0;
+  FfsFoundFlag   = FALSE;
+  LocalPatchData = NULL;
+
+  if (CurrentFv == NULL || CurrentFile == NULL || FvImage == NULL) {
+    return EFI_ABORTED;
+  }
+
+  FfsFileSize = GetFfsFileLength ((EFI_FFS_FILE_HEADER *) CurrentFile);
+  HeaderSize  = GetFfsHeaderLength  ((EFI_FFS_FILE_HEADER *) CurrentFile);
+
+  for (Count1=0; Count1 < (FvImage->FvLength - FfsFileSize); Count1 ++) {
+    for (Count2=0; Count2 < FfsFileSize; Count2 ++) {
+      if (((INT8*)FvImage)[Count1 + Count2] != ((INT8 *) CurrentFile)[Count2]){
+        break;
+      }
+    }
+    if (Count2 == FfsFileSize) {
+      FfsFoundFlag = TRUE;
+      FfsOffset = Count1;
+      break;
+    }
+  }
+
+  if (FfsFoundFlag) {
+    //
+    // Find data in FFS file;
+    // Will skip FFS header;
+    //
+    for (Count1 = HeaderSize; Count1 < FfsFileSize; Count1++) {
+      if (((((INT8 *)CurrentFile)[Count1]) & 0xFF) != 0xFF) {
+        DataOffset = FfsOffset + Count1;
+        break;
+      }
+    }
+
+    if (CurrentFv->PatchData == NULL) {
+      //
+      // First time found data.
+      //
+      CurrentFv->PatchData = (PATCH_DATA_PAD_FFS *) malloc (sizeof (PATCH_DATA_PAD_FFS));
+      if (CurrentFv->PatchData == NULL) {
+        return EFI_ABORTED;
+      }
+
+      CurrentFv->PatchData->Offset = DataOffset;
+      CurrentFv->PatchData->Data = malloc(FfsFileSize - Count1);
+      CurrentFv->PatchData->Length = FfsFileSize - Count1;
+      CurrentFv->PatchData->NextNode = NULL;
+
+      if (CurrentFv->PatchData->Data == NULL) {
+        return EFI_ABORTED;
+      }
+
+      memcpy (CurrentFv->PatchData->Data, (INT8 *)CurrentFile + Count1, FfsFileSize - Count1);
+    } else {
+      LocalPatchData = CurrentFv->PatchData;
+
+      while (LocalPatchData->NextNode != NULL) {
+        LocalPatchData = LocalPatchData->NextNode;
+      }
+
+      LocalPatchData = (PATCH_DATA_PAD_FFS *) malloc (sizeof (PATCH_DATA_PAD_FFS));
+
+      if (LocalPatchData == NULL) {
+        return EFI_ABORTED;
+      }
+
+      LocalPatchData->Offset = DataOffset;
+      LocalPatchData->Data = malloc(FfsFileSize - Count1);
+      LocalPatchData->Length = FfsFileSize - Count1;
+      LocalPatchData->NextNode = NULL;
+
+      if (LocalPatchData->Data == NULL) {
+        free (LocalPatchData);
+        return EFI_ABORTED;
+      }
+
+      memcpy (LocalPatchData->Data, (INT8 *)CurrentFile + Count1, FfsFileSize - Count1);
+      while (CurrentFv->PatchData->NextNode != NULL) {
+        CurrentFv->PatchData = CurrentFv->PatchData->NextNode;
+      }
+      CurrentFv->PatchData->NextNode = LocalPatchData;
+    }
+
+  } else {
+    return EFI_ABORTED;
+  }
+
+  return EFI_SUCCESS;
+}
+
+/*
+  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 (NULL == RetStr) {
+    return NULL;
+  }
+
+  memset (RetStr , '\0', Count + 1);
+
+  for (Index=0; Index <= Count -1; Index ++) {
+    RetStr[Index] = ' ';
+  }
+
+  return RetStr;
+
+}
+
+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,
+  UINT32                 *FfsCount,
+  BOOLEAN                ViewFlag,
+  BOOLEAN                ErasePolarity,
+  BOOLEAN                FfsGeneratedFlag
+  )
+{
+  UINT32              ParsedLength;
+  UINT8               *Ptr;
+  UINT32              SectionLength;
+  UINT32              UiSectionLength;
+  EFI_SECTION_TYPE    Type;
+  EFI_STATUS          Status;
+  CHAR8               *ExtractionTool;
+  CHAR8               *ToolInputFile;
+  CHAR8               *ToolOutputFile;
+  CHAR8               *SystemCommand;
+  UINT8               *ToolOutputBuffer;
+  UINT32              ToolOutputLength;
+  CHAR16              *UIName;
+  UINT32              UINameSize;
+  BOOLEAN             HasDepexSection;
+  UINT32              NumberOfSections;
+  BOOLEAN             IsFfsGenerated;
+  ENCAP_INFO_DATA     *LocalEncapData;
+  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;
+  CHAR8               *UIFileName;
+  CHAR8               *ToolInputFileName;
+  CHAR8               *ToolOutputFileName;
+
+  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;
+  ToolOutputBuffer           = NULL;
+  UIName                     = NULL;
+  LocalEncapData             = NULL;
+  BlankChar                  = NULL;
+  UncompressedBuffer         = NULL;
+  CompressedBuffer           = NULL;
+  ScratchBuffer              = NULL;
+  TempDir                    = NULL;
+  ToolInputFileFullName      = NULL;
+  ToolOutputFileFullName     = NULL;
+  ToolInputFileName          = NULL;
+  ToolOutputFileName         = NULL;
+  HasDepexSection            = FALSE;
+  IsFfsGenerated             = FfsGeneratedFlag;
+  EncapDataNeedUpdata        = TRUE;
+  LargeHeaderOffset          = 0;
+
+
+  while (ParsedLength < BufferLength) {
+    Ptr           = SectionBuffer + ParsedLength;
+
+    SectionLength = FvBufExpand3ByteSize (((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;
+
+      //
+      // Put in encapsulate data information.
+      //
+      LocalEncapData = CurrentFv->EncapData;
+      while (LocalEncapData->NextNode != NULL) {
+        if (LocalEncapData->Level == Level) {
+          EncapDataNeedUpdata = FALSE;
+          break;
+        }
+        LocalEncapData = LocalEncapData->NextNode;
+      }
+
+      if (EncapDataNeedUpdata) {
+        //
+        // Put in this is an FFS with FV section
+        //
+        LocalEncapData = CurrentFv->EncapData;
+        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) {
+          return EFI_ABORTED;
+        }
+
+        LocalEncapData        = LocalEncapData->NextNode;
+
+        LocalEncapData->Level = Level;
+        LocalEncapData->Type  = BFM_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;
+      }
+
+      Status = LibGetFvInfo ((UINT8*)((EFI_FIRMWARE_VOLUME_IMAGE_SECTION*)Ptr + 1) + LargeHeaderOffset, CurrentFv, FvName, Level, FfsCount, ViewFlag, TRUE);
+      if (EFI_ERROR (Status)) {
+        return EFI_SECTION_ERROR;
+      }
+      break;
+
+    case EFI_SECTION_COMPRESSION:
+      Level ++;
+      NumberOfSections ++;
+
+      EncapDataNeedUpdata = TRUE;
+      //
+      // Put in encapsulate data information.
+      //
+      LocalEncapData = CurrentFv->EncapData;
+      while (LocalEncapData->NextNode != NULL) {
+        if (LocalEncapData->Level == Level) {
+          EncapDataNeedUpdata = FALSE;
+          break;
+        }
+        LocalEncapData = LocalEncapData->NextNode;
+      }
+
+      if (EncapDataNeedUpdata) {
+        //
+        // Put in this is an FFS with FV section
+        //
+        LocalEncapData = CurrentFv->EncapData;
+        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) {
+          return EFI_ABORTED;
+          }
+
+        LocalEncapData        = LocalEncapData->NextNode;
+
+        LocalEncapData->Level = Level;
+        LocalEncapData->Type  = BFM_ENCAP_TREE_COMPRESS_SECTION;
+
+        //
+        // Store the compress type
+        //
+        LocalEncapData->Data     = malloc (sizeof (UINT8));
+
+        if (LocalEncapData->Data == NULL) {
+          return EFI_OUT_OF_RESOURCES;
+        }
+
+        *(UINT8 *)LocalEncapData->Data     = ((EFI_COMPRESSION_SECTION *) (Ptr + LargeHeaderOffset))->CompressionType;
+        LocalEncapData->FvExtHeader = NULL;
+        LocalEncapData->NextNode = 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) {
+
+        if (CompressedLength != UncompressedLength) {
+          printf ("Error. File is not compressed, but the compressed length does not match the uncompressed length.\n");
+          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)) {
+          return EFI_SECTION_ERROR;
+        }
+
+        if (DstSize != UncompressedLength) {
+          return EFI_SECTION_ERROR;
+        }
+
+        ScratchBuffer       = malloc (ScratchSize);
+        if (ScratchBuffer == NULL) {
+          return EFI_OUT_OF_RESOURCES;
+        }
+        UncompressedBuffer  = malloc (UncompressedLength);
+
+        if (UncompressedBuffer == 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)) {
+          free (UncompressedBuffer);
+          return EFI_SECTION_ERROR;
+        }
+      } else {
+        return EFI_SECTION_ERROR;
+      }
+
+      Status = LibParseSection (  UncompressedBuffer,
+                                  UncompressedLength,
+                                  CurrentFv,
+                                  FvName,
+                                  CurrentFile,
+                                  Level,
+                                  FfsCount,
+                                  ViewFlag,
+                                  ErasePolarity,
+                                  IsFfsGenerated);
+
+      if (CompressionType == EFI_STANDARD_COMPRESSION) {
+        //
+        // We need to deallocate Buffer
+        //
+        free (UncompressedBuffer);
+      }
+
+      if (EFI_ERROR (Status)) {
+        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 = CurrentFv->EncapData;
+      while (LocalEncapData->NextNode != NULL) {
+        if (LocalEncapData->Level == Level) {
+          EncapDataNeedUpdata = FALSE;
+          break;
+        }
+        LocalEncapData = LocalEncapData->NextNode;
+      }
+      if (EncapDataNeedUpdata)  {
+
+        //
+        // Put in this is an FFS with FV section
+        //
+        LocalEncapData = CurrentFv->EncapData;
+        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) {
+          return EFI_ABORTED;
+        }
+
+        LocalEncapData        = LocalEncapData->NextNode;
+
+        LocalEncapData->Level = Level;
+        LocalEncapData->Type  = BFM_ENCAP_TREE_GUIDED_SECTION;
+
+        //
+        // We don't need additional data for encapsulate this FFS but type.
+        //
+
+        LocalEncapData->Data     = (EFI_GUID *) malloc (sizeof (EFI_GUID));
+
+        if (LocalEncapData->Data == NULL) {
+          return EFI_ABORTED;
+        }
+
+    memcpy (LocalEncapData->Data, &((EFI_GUID_DEFINED_SECTION *) (Ptr + LargeHeaderOffset))->SectionDefinitionGuid, sizeof (EFI_GUID));
+
+        LocalEncapData->FvExtHeader = NULL;
+        LocalEncapData->NextNode = NULL;
+      }
+
+      CurrentFv->FfsAttuibutes[*FfsCount].IsLeaf = FALSE;
+
+      ExtractionTool =
+        LookupGuidedSectionToolPath (
+          mParsedGuidedSectionTools,
+          &((EFI_GUID_DEFINED_SECTION *) (Ptr + LargeHeaderOffset))->SectionDefinitionGuid
+          );
+
+      if ((((EFI_GUID_DEFINED_SECTION *) (Ptr + LargeHeaderOffset))->Attributes & EFI_GUIDED_SECTION_PROCESSING_REQUIRED) == 0) {
+        //
+        // Not require process, directly gets data.
+        //
+        Status = LibParseSection (
+          Ptr + ((EFI_GUID_DEFINED_SECTION *) (Ptr + LargeHeaderOffset))->DataOffset,
+          SectionLength - ((EFI_GUID_DEFINED_SECTION *) (Ptr + LargeHeaderOffset))->DataOffset,
+          CurrentFv,
+          FvName,
+          CurrentFile,
+          Level,
+          FfsCount,
+          ViewFlag,
+          ErasePolarity,
+          IsFfsGenerated
+          );
+        if (ExtractionTool != NULL) {
+          free (ExtractionTool);
+          ExtractionTool = NULL;
+        }
+        if (EFI_ERROR (Status)) {
+          return EFI_SECTION_ERROR;
+        }
+      } else if (ExtractionTool != NULL) {
+
+        TempDir = getcwd (NULL, _MAX_PATH);
+        if (strlen (TempDir) + strlen (OS_SEP_STR) + strlen (TEMP_DIR_NAME) > _MAX_PATH - 1) {
+          printf ("The directory is too long \n");
+          free (ExtractionTool);
+          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);
+
+        ToolInputFile  = GenTempFile ();
+        ToolOutputFile = GenTempFile ();
+        ToolInputFileName = strrchr(ToolInputFile, OS_SEP);
+        ToolOutputFileName = strrchr(ToolOutputFile, OS_SEP);
+
+        ToolInputFileFullName   = malloc (strlen("%s%s") + strlen(TempDir) + strlen(ToolInputFileName) + 1);
+        if (ToolInputFileFullName == NULL) {
+          free (ExtractionTool);
+          free (ToolInputFile);
+          free (ToolOutputFile);
+          return EFI_OUT_OF_RESOURCES;
+        }
+        ToolOutputFileFullName  = malloc (strlen("%s%s") + strlen(TempDir) + strlen(ToolOutputFileName) + 1);
+        if (ToolOutputFileFullName == NULL) {
+          free (ToolInputFileFullName);
+          free (ExtractionTool);
+          free (ToolInputFile);
+          free (ToolOutputFile);
+          return EFI_OUT_OF_RESOURCES;
+        }
+
+        sprintf (ToolInputFileFullName, "%s%s", TempDir, ToolInputFileName);
+        sprintf (ToolOutputFileFullName, "%s%s", TempDir, ToolOutputFileName);
+
+        //
+        // Construction 'system' command string
+        //
+        SystemCommand = malloc (
+          strlen (DECODE_STR) +
+          strlen (ExtractionTool) +
+          strlen (ToolInputFileFullName) +
+          strlen (ToolOutputFileFullName) +
+          1
+          );
+        if (SystemCommand == NULL) {
+          free (ToolInputFile);
+          free (ToolOutputFile);
+          free (ToolInputFileFullName);
+          free (ToolOutputFileFullName);
+          free (ExtractionTool);
+          return EFI_OUT_OF_RESOURCES;
+        }
+        sprintf (
+          SystemCommand,
+          DECODE_STR,
+          ExtractionTool,
+          ToolOutputFileFullName,
+          ToolInputFileFullName
+          );
+
+        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)) {
+          free(SystemCommand);
+          free (ToolOutputFileFullName);
+          free (ToolOutputFile);
+          remove (ToolInputFileFullName);
+          free (ToolInputFile);
+          free (ToolInputFileFullName);
+          return EFI_SECTION_ERROR;
+        }
+
+        if (system (SystemCommand) != EFI_SUCCESS) {
+          SystemCommand = malloc (
+            strlen (DECODE_STR_ERR) +
+            strlen (ExtractionTool) +
+            strlen (ToolInputFileFullName) +
+            strlen (ToolOutputFileFullName) +
+            1
+            );
+          if (SystemCommand == NULL) {
+            free (ExtractionTool);
+            LibRmDir (TempDir);
+            remove (ToolInputFileFullName);
+            free (ToolInputFile);
+            free (ToolInputFileFullName);
+            free (ToolOutputFileFullName);
+            free (ToolOutputFile);
+            return EFI_OUT_OF_RESOURCES;
+          }
+          sprintf (
+            SystemCommand,
+            DECODE_STR_ERR,
+            ExtractionTool,
+            ToolOutputFileFullName,
+            ToolInputFileFullName
+            );
+          system (SystemCommand);
+          printf("Command failed: %s\n", SystemCommand);
+          free (ExtractionTool);
+          ExtractionTool = NULL;
+          LibRmDir (TempDir);
+          free(SystemCommand);
+          remove (ToolInputFileFullName);
+          free (ToolInputFile);
+          free (ToolInputFileFullName);
+          free (ToolOutputFileFullName);
+          free (ToolOutputFile);
+          return EFI_ABORTED;
+        }
+        free (ExtractionTool);
+        ExtractionTool = NULL;
+        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)) {
+          return EFI_SECTION_ERROR;
+        }
+
+        Status = LibParseSection (
+                  ToolOutputBuffer,
+                  ToolOutputLength,
+                  CurrentFv,
+                  FvName,
+                  CurrentFile,
+                  Level,
+                  FfsCount,
+                  ViewFlag,
+                  ErasePolarity,
+                  IsFfsGenerated
+                  );
+        if (EFI_ERROR (Status)) {
+          return EFI_SECTION_ERROR;
+        }
+      } else {
+        //
+        // We don't know how to parse it now.
+        //
+        if (ExtractionTool != NULL) {
+          free (ExtractionTool);
+          ExtractionTool = NULL;
+        }
+        printf("  EFI_SECTION_GUID_DEFINED cannot be parsed at this time. Tool to decode this section should have been defined in %s file.\n", 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;
+      break;
+    case EFI_SECTION_DXE_DEPEX:
+      NumberOfSections ++;
+      CurrentFv->FfsAttuibutes[*FfsCount].Level = Level;
+      HasDepexSection = TRUE;
+      break;
+    case EFI_SECTION_SMM_DEPEX:
+      NumberOfSections ++;
+      CurrentFv->FfsAttuibutes[*FfsCount].Level = Level;
+      HasDepexSection = TRUE;
+      break;
+
+    case EFI_SECTION_USER_INTERFACE:
+      NumberOfSections ++;
+      CurrentFv->FfsAttuibutes[*FfsCount].Level = Level;
+
+      UiSectionLength = FvBufExpand3ByteSize (((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 {
+        return EFI_ABORTED;
+      }
+
+      BlankChar = LibConstructBlankChar( CurrentFv->FvLevel * 2);
+      if (BlankChar == NULL) {
+        free (UIName);
+        return EFI_ABORTED;
+      }
+
+      if (ViewFlag) {
+        UIFileName = malloc (UINameSize + 2);
+        if (UIFileName == NULL) {
+          free(BlankChar);
+          free(UIName);
+          return EFI_OUT_OF_RESOURCES;
+        }
+        Unicode2AsciiString (UIName, UIFileName);
+        fprintf(stdout, "%sFile \"%s\"\n", BlankChar, UIFileName);
+        free(UIFileName);
+      }
+
+      free (BlankChar);
+      BlankChar = NULL;
+
+      //
+      // If Ffs file has been generated, then the FfsCount should decrease 1.
+      //
+      if (IsFfsGenerated) {
+        memcpy (CurrentFv->FfsAttuibutes[*FfsCount -1].UiName, UIName, UINameSize);
+      } else {
+        memcpy (CurrentFv->FfsAttuibutes[*FfsCount].UiName, UIName, 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) {
+    return EFI_SECTION_ERROR;
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+
+  Add function description
+
+  FvImage       -  add argument description
+  FileHeader    -  add argument description
+  ErasePolarity -  add argument description
+
+  EFI_SUCCESS -  Add description for return value
+  EFI_ABORTED -  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,
+  UINT32                      *FfsCount,
+  BOOLEAN                     ViewFlag
+  )
+{
+  UINT32              FileLength;
+  UINT8               FileState;
+  UINT8               Checksum;
+  EFI_FFS_FILE_HEADER2 BlankHeader;
+  EFI_STATUS          Status;
+  ENCAP_INFO_DATA     *LocalEncapData;
+  BOOLEAN             EncapDataNeedUpdateFlag;
+  UINT32              FfsFileHeaderSize;
+
+  Status = EFI_SUCCESS;
+
+  LocalEncapData  = NULL;
+  EncapDataNeedUpdateFlag = TRUE;
+
+  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);
+
+  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) {
+      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) {
+        return EFI_ABORTED;
+      }
+    } else {
+      if (CurrentFile->IntegrityCheck.Checksum.File != FFS_FIXED_CHECKSUM) {
+        return EFI_ABORTED;
+      }
+    }
+  } else {
+    return EFI_ABORTED;
+  }
+
+  Level += 1;
+
+  if (CurrentFile->Type != EFI_FV_FILETYPE_ALL) {
+
+    //
+    // Put in encapsulate data information.
+    //
+    LocalEncapData = CurrentFv->EncapData;
+    while (LocalEncapData->NextNode != NULL) {
+      if (LocalEncapData->Level == Level) {
+        EncapDataNeedUpdateFlag = FALSE;
+        break;
+      }
+      LocalEncapData = LocalEncapData->NextNode;
+    }
+
+    if (EncapDataNeedUpdateFlag) {
+      //
+      // Construct the new ENCAP_DATA
+      //
+      LocalEncapData->NextNode = (ENCAP_INFO_DATA *) malloc (sizeof (ENCAP_INFO_DATA));
+
+      if (LocalEncapData->NextNode == NULL) {
+        printf ("Out of resource, memory allocation failed. \n");
+        return EFI_ABORTED;
+      }
+
+      LocalEncapData        = LocalEncapData->NextNode;
+
+      LocalEncapData->Level = Level;
+      LocalEncapData->Type  = BFM_ENCAP_TREE_FFS;
+      LocalEncapData->FvExtHeader = NULL;
+
+      //
+      // Store the header of FFS file.
+      //
+      LocalEncapData->Data     = malloc (FfsFileHeaderSize);
+      if (LocalEncapData->Data == NULL) {
+        printf ("Out of resource, memory allocation failed. \n");
+        return EFI_ABORTED;
+      }
+
+      memcpy (LocalEncapData->Data, CurrentFile, FfsFileHeaderSize);
+
+      LocalEncapData->NextNode = NULL;
+    }
+
+    if ( CurrentFile->Type == EFI_FV_FILETYPE_FREEFORM ){
+      CurrentFv->FfsAttuibutes[*FfsCount].Level = Level;
+      if (!ViewFlag) {
+        LibGenFfsFile(CurrentFile, CurrentFv, FvName, Level, FfsCount, ErasePolarity);
+      }
+    }else 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_SECURITY_CORE){
+      CurrentFv->FfsAttuibutes[*FfsCount].Level = Level;
+      //
+      // If an FV contain SECCORE, this FV will be considered as BFV.
+      //
+      CurrentFv->IsBfvFlag = TRUE;
+      if (!ViewFlag){
+        LibGenFfsFile(CurrentFile, CurrentFv, FvName, Level, FfsCount, ErasePolarity);
+      }
+    } else if( CurrentFile->Type == EFI_FV_FILETYPE_FFS_PAD){
+      //
+      // First check whether the FFS file contain FvExtended FvNameGuid information.
+      //
+      if (!LibCheckPadFfsContainFvNameGuid (CurrentFv, CurrentFile)) {
+        //
+        // Then check whether the PAD file have no additional data or not.
+        //
+        if (LibCheckPadFfsNotNull (CurrentFile)) {
+          CurrentFv->FfsAttuibutes[*FfsCount].Level = Level;
+          //
+          // Get the size of PAD in BFV
+          //
+          PadSizeOfBfv = GetBfvMaxFreeSpace (CurrentFile);
+          if (!ViewFlag){
+            //
+            //LibGenFfsFile(CurrentFile, CurrentFv, FvName, Level, FfsCount, ErasePolarity);
+            //
+            Status = LibFindResetVectorAndFitTableData (FvImage, CurrentFile, CurrentFv);
+            if (EFI_ERROR (Status)) {
+              printf ("Find reset vector and FIT table data failed. \n");
+              return EFI_ABORTED;
+            }
+          }
+        }
+      }
+    } else {
+      //
+      // All other files have sections
+      //
+      Status = LibParseSection (
+       (UINT8 *) ((UINTN) CurrentFile + FfsFileHeaderSize),
+        FileLength - FfsFileHeaderSize,
+        CurrentFv,
+        FvName,
+        CurrentFile,
+        Level,
+        FfsCount,
+        ViewFlag,
+        ErasePolarity,
+        FALSE
+        );
+    }
+    if (EFI_ERROR (Status)) {
+      printf ("Error while parse the FFS file.\n");
+      return EFI_ABORTED;
+    }
+  }
+
+  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     UINT32                       *FfsCount,
+  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;
+
+  NumberOfFiles  = 0;
+  Key            = 0;
+  LocalEncapData = NULL;
+  CurrentFile    = NULL;
+
+  Level += 1;
+  CurrentFv->FvLevel += 1;
+
+  Status = FvBufGetSize (Fv, &FvSize);
+
+  ErasePolarity = (((EFI_FIRMWARE_VOLUME_HEADER*)Fv)->Attributes & EFI_FVB2_ERASE_POLARITY) ? TRUE : FALSE;
+
+  if (!IsChildFv) {
+    //
+    // Write FV header information into CurrentFv struct.
+    //
+    CurrentFv->FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *) malloc (sizeof (EFI_FIRMWARE_VOLUME_HEADER));
+
+    if (CurrentFv->FvHeader == NULL) {
+      return EFI_ABORTED;
+    }
+
+    //
+    // Get the FV Header information
+    //
+    memcpy (CurrentFv->FvHeader, Fv, sizeof (EFI_FIRMWARE_VOLUME_HEADER));
+    CurrentFv->FvExtHeader = NULL;
+
+    //
+    // Exist Extend FV header.
+    //
+    if (CurrentFv->FvHeader->ExtHeaderOffset != 0){
+      CurrentFv->FvExtHeader = (EFI_FIRMWARE_VOLUME_EXT_HEADER *) malloc (sizeof (EFI_FIRMWARE_VOLUME_EXT_HEADER));
+
+      if (CurrentFv->FvExtHeader == NULL) {
+        printf ("Out of resource, memory allocation failed. \n");
+        return EFI_ABORTED;
+      }
+
+      //
+      // Get the FV extended Header information
+      //
+      memcpy (CurrentFv->FvExtHeader, (VOID *)((UINTN)Fv + CurrentFv->FvHeader->ExtHeaderOffset), sizeof (EFI_FIRMWARE_VOLUME_EXT_HEADER));
+      if (mFvGuidIsSet) {
+        if (CompareGuid (&CurrentFv->FvExtHeader->FvName, &mFvNameGuid) == 0) {
+          CurrentFv->IsInputFvFlag = TRUE;
+        }
+      }
+
+    }
+
+  }
+
+  //
+  // Put encapsulate information into structure.
+  //
+  if (CurrentFv->EncapData == NULL && !IsChildFv) {
+    //
+    // First time in, the root FV
+    //
+    CurrentFv->EncapData = (ENCAP_INFO_DATA *) malloc (sizeof (ENCAP_INFO_DATA));
+
+    if (CurrentFv->EncapData == NULL) {
+      return EFI_ABORTED;
+    }
+    CurrentFv->EncapData->FvExtHeader = NULL;
+    CurrentFv->EncapData->Level = Level;
+    CurrentFv->EncapData->Type  = BFM_ENCAP_TREE_FV;
+    CurrentFv->EncapData->Data  = (EFI_FIRMWARE_VOLUME_HEADER *) malloc (sizeof (EFI_FIRMWARE_VOLUME_HEADER));
+
+    if (CurrentFv->EncapData->Data == 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) {
+        printf ("Out of resource, memory allocation failed. \n");
+        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);
+      if (mFvGuidIsSet) {
+        if (CompareGuid (&CurrentFv->EncapData->FvExtHeader->FvName, &mFvNameGuid) == 0) {
+          CurrentFv->IsInputFvFlag = TRUE;
+        }
+      }
+
+    }
+
+    CurrentFv->EncapData->NextNode  = NULL;
+
+  } else if (CurrentFv->EncapData == NULL) {
+    return EFI_ABORTED;
+  } else if (IsChildFv) {
+
+      LocalEncapData = CurrentFv->EncapData;
+
+      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) {
+        return EFI_ABORTED;
+      }
+
+      LocalEncapData           = LocalEncapData->NextNode;
+
+      LocalEncapData->Level = Level;
+      LocalEncapData->Type  = BFM_ENCAP_TREE_FV;
+      LocalEncapData->Data  = (EFI_FIRMWARE_VOLUME_HEADER *) malloc (sizeof (EFI_FIRMWARE_VOLUME_HEADER));
+      LocalEncapData->FvExtHeader = NULL;
+
+      if (LocalEncapData->Data == 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) {
+          printf ("Out of resource, memory allocation failed. \n");
+          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;
+
+  }
+
+
+  //
+  // Get the first file
+  //
+  Status = FvBufFindNextFile (Fv, &Key, (VOID **) &CurrentFile);
+  if (Status == EFI_NOT_FOUND) {
+    CurrentFile = NULL;
+  } else if (EFI_ERROR (Status)) {
+    printf ("Failed to find the first file from Fv. \n");
+    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;
+
+    //
+    // Display info about this file
+    //
+    Status = LibGetFileInfo (Fv, CurrentFile, ErasePolarity, CurrentFv, FvName, Level, FfsCount, ViewFlag);
+    if (EFI_ERROR (Status)) {
+      return Status;
+    }
+
+    //
+    // Get the next file
+    //
+    Status = FvBufFindNextFile (Fv, &Key, (VOID **) &CurrentFile);
+    if (Status == EFI_NOT_FOUND) {
+      CurrentFile = NULL;
+    } else if (EFI_ERROR (Status)) {
+      return Status;
+    }
+  }
+
+  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) {
+    printf ("The directory is too long \n");
+    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) {
+    printf ("The directory is too long \n");
+    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) {
+    printf ("The directory is too long \n");
+    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;
+}
+
+
+/**
+
+  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;
+}
+
+/**
+  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*                 SystemCommand;
+
+  SystemCommand             = NULL;
+
+  if (FileIn   == NULL ||
+      ToolName == NULL ||
+      FileOut  == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  SystemCommand = malloc (
+    strlen (ENCODE_STR) +
+    strlen (FileIn)  +
+    strlen (ToolName)  +
+    strlen (FileOut)  +
+    1
+    );
+
+  if (NULL == SystemCommand) {
+    return EFI_ABORTED;
+  }
+
+  sprintf (
+    SystemCommand,
+    ENCODE_STR,
+    ToolName,
+    FileIn,
+    FileOut
+    );
+
+  if (system (SystemCommand) != EFI_SUCCESS) {
+    SystemCommand = malloc (
+      strlen (ENCODE_STR_ERR) +
+      strlen (FileIn)  +
+      strlen (ToolName)  +
+      strlen (FileOut)  +
+      1
+      );
+    if (NULL == SystemCommand) {
+      return EFI_ABORTED;
+    }
+    sprintf (
+      SystemCommand,
+      ENCODE_STR_ERR,
+      ToolName,
+      FileIn,
+      FileOut
+      );
+    system (SystemCommand);
+    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 ("Out of resource, memory allocation failed. \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 write data to %p file. \n", (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_FV_BLOCK_MAP_ENTRY  *BlockMap,
+  IN     FILE*                   InfFile,
+  IN     BOOLEAN                 IsRootFv
+)
+{
+  CHAR8     *LocalStr;
+  CHAR8     *BlockSize;
+  CHAR8     *NumOfBlocks;
+
+  LocalStr     = NULL;
+  BlockSize    = NULL;
+  NumOfBlocks  = NULL;
+
+  if (BlockMap == 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);
+  BlockSize   = (CHAR8 *) malloc (128);
+  NumOfBlocks = (CHAR8 *) malloc (128);
+
+  if (LocalStr    == NULL ||
+      BlockSize   == NULL ||
+      NumOfBlocks == NULL) {
+    if (LocalStr != NULL) {
+      free (LocalStr);
+    }
+    if (BlockSize != NULL) {
+      free (BlockSize);
+    }
+    if (NumOfBlocks != NULL) {
+      free (NumOfBlocks);
+    }
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  memset (LocalStr, '\0', 1024);
+  memset (BlockSize, '\0', 128);
+  memset (NumOfBlocks, '\0', 128);
+
+  strncat (LocalStr, "[options] \n", sizeof("[Options] \n"));
+
+  sprintf (BlockSize, "EFI_BLOCK_SIZE  = 0x%x \n", BlockMap->Length);
+  strncat (LocalStr, BlockSize, strlen(BlockSize));
+
+  if (IsRootFv) {
+  sprintf (NumOfBlocks, "EFI_NUM_BLOCKS  = 0x%x \n", BlockMap->NumBlocks);
+  strncat (LocalStr, NumOfBlocks, strlen(NumOfBlocks));
+  }
+
+  if (fwrite (LocalStr, 1, (size_t) strlen (LocalStr), InfFile) != (size_t) strlen (LocalStr)) {
+    free (LocalStr);
+    free (BlockSize);
+    free (NumOfBlocks);
+    return EFI_ABORTED;
+  }
+
+  free (LocalStr);
+  free (BlockSize);
+  free (NumOfBlocks);
+
+  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 ("Out of resource, memory allocation failed. \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 write data to %p file. \n", (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 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 CHAR8*     CompressType        OPTIONAL
+  )
+{
+  CHAR8*                 SystemCommand;
+  SystemCommand             = NULL;
+
+  //
+  // Call GenSec tool to generate FFS section.
+  //
+
+  //
+  // -s SectionType.
+  //
+  if (Type != 0) {
+    switch (Type) {
+      //
+      // Process compression section
+      //
+      case EFI_SECTION_COMPRESSION:
+        SystemCommand = malloc (
+          strlen (GENSEC_COMPRESSION) +
+          strlen (mSectionTypeName[Type]) +
+          strlen (CompressType) +
+          strlen (InputFilePath) +
+          strlen (OutputFilePath) +
+          1
+          );
+        if (NULL == SystemCommand) {
+          return EFI_OUT_OF_RESOURCES;
+        }
+        sprintf (
+          SystemCommand,
+          GENSEC_COMPRESSION,
+          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:
+        SystemCommand = malloc (
+          strlen (GENSEC_GUID) +
+          strlen (mSectionTypeName[Type]) +
+          strlen (GuidToolGuid) +
+          strlen (InputFilePath) +
+          strlen (OutputFilePath) +
+          1
+          );
+        if (NULL == SystemCommand) {
+          return EFI_OUT_OF_RESOURCES;
+        }
+        sprintf (
+          SystemCommand,
+          GENSEC_GUID,
+          mSectionTypeName[Type],
+          GuidToolGuid,
+          InputFilePath,
+          OutputFilePath
+          );
+        if (system (SystemCommand) != EFI_SUCCESS) {
+          free(SystemCommand);
+          return EFI_ABORTED;
+        }
+        free(SystemCommand);
+        break;
+
+      case EFI_SECTION_FIRMWARE_VOLUME_IMAGE:
+        SystemCommand = malloc (
+          strlen (GENSEC_STR) +
+          strlen (mSectionTypeName[Type]) +
+          strlen (InputFilePath) +
+          strlen (OutputFilePath) +
+          1
+          );
+        if (NULL == SystemCommand) {
+          return EFI_OUT_OF_RESOURCES;
+        }
+        sprintf (
+          SystemCommand,
+          GENSEC_STR,
+          mSectionTypeName[Type],
+          InputFilePath,
+          OutputFilePath
+          );
+        if (system (SystemCommand) != EFI_SUCCESS) {
+          free(SystemCommand);
+          return EFI_ABORTED;
+        }
+        free(SystemCommand);
+        break;
+
+      case EFI_SECTION_RAW:
+        SystemCommand = malloc (
+          strlen (GENSEC_STR) +
+          strlen (mSectionTypeName[Type]) +
+          strlen (InputFilePath) +
+          strlen (OutputFilePath) +
+          1
+          );
+        if (NULL == SystemCommand) {
+          return EFI_OUT_OF_RESOURCES;
+        }
+        sprintf (
+          SystemCommand,
+          GENSEC_STR,
+          mSectionTypeName[Type],
+          InputFilePath,
+          OutputFilePath
+          );
+        if (system (SystemCommand) != EFI_SUCCESS) {
+          free(SystemCommand);
+          return EFI_ABORTED;
+        }
+        free(SystemCommand);
+        break;
+
+      default:
+        printf ("Please specify the section type while call GenSec tool.\n");
+        return EFI_UNSUPPORTED;
+    }
+  } else {
+    //
+    // Create Dummy section.
+    //
+    SystemCommand = malloc (
+      strlen (GENSEC_ALIGN) +
+      strlen (InputFilePath) +
+      strlen (OutputFilePath) +
+      1
+      );
+    if (NULL == SystemCommand) {
+      return EFI_OUT_OF_RESOURCES;
+    }
+    sprintf (
+      SystemCommand,
+      GENSEC_ALIGN,
+      InputFilePath,
+      OutputFilePath
+      );
+    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
+  )
+{
+
+  CHAR8*                 SystemCommand;
+  CHAR8*                 FfsGuid = "8c8ce578-8a3d-4f1c-9935-896185c32dd3";
+
+  SystemCommand             = NULL;
+
+  if (OutputFilePath  == NULL ||
+      InfFilePath     == NULL ) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if (InfFilePath != NULL) {
+    if (FvGuidName == NULL) {
+      SystemCommand = malloc (
+        strlen (GENFV_STR) +
+        strlen (InfFilePath)   +
+        strlen (OutputFilePath)  +
+        1
+        );
+      if (NULL == SystemCommand) {
+        return EFI_OUT_OF_RESOURCES;
+      }
+
+      sprintf (
+        SystemCommand,
+        GENFV_STR,
+        InfFilePath,          // -i
+        OutputFilePath        // -o
+        );
+
+      if (system (SystemCommand) != EFI_SUCCESS) {
+        free(SystemCommand);
+        return EFI_ABORTED;
+      }
+      free(SystemCommand);
+    } else {
+      //
+      // Have FvGuidName in it.
+      //
+      SystemCommand = malloc (
+        strlen (GENFV_FVGUID) +
+        strlen (InfFilePath)   +
+        strlen (OutputFilePath)  +
+        strlen (FvGuidName) +
+        1
+        );
+       if (NULL == SystemCommand) {
+        return EFI_OUT_OF_RESOURCES;
+      }
+
+      sprintf (
+        SystemCommand,
+        GENFV_FVGUID,
+        InfFilePath,          // -i
+        OutputFilePath,       // -o
+        FvGuidName            // FvNameGuid
+        );
+      if (system (SystemCommand) != EFI_SUCCESS) {
+        free(SystemCommand);
+        return EFI_ABORTED;
+      }
+      free(SystemCommand);
+
+    }
+  }
+
+  if (InputFFSs != NULL) {
+    SystemCommand = malloc (
+      strlen (GENFV_FFS) +
+      strlen (InputFFSs)   +
+      strlen (FfsGuid)         +
+      strlen (OutputFilePath)  +
+      100
+      );
+    if (NULL == SystemCommand) {
+      return EFI_OUT_OF_RESOURCES;
+    }
+
+    sprintf (
+      SystemCommand,
+      GENFV_FFS,
+      InputFFSs,              // -f
+      FfsGuid,                // -g
+      OutputFilePath          // -o
+      );
+    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 *
+LibBfmGuidToStr (
+  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 UINT32     SectionAlign
+  )
+{
+  CHAR8*                 SystemCommand;
+  CHAR8*                 GuidStr;
+
+  SystemCommand             = NULL;
+  GuidStr                   = NULL;
+
+  GuidStr  = LibBfmGuidToStr(&FileGuid);
+
+  if (NULL == GuidStr) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  if (Type == EFI_FV_FILETYPE_RAW) {
+    SystemCommand = malloc (
+      strlen (GENFFS_STR) +
+      strlen (mFfsFileType[Type]) +
+      strlen (InputFilePath) +
+      strlen (GuidStr) +
+      strlen (OutputFilePath) +
+      1
+      );
+    if (NULL == SystemCommand) {
+      free (GuidStr);
+      return EFI_OUT_OF_RESOURCES;
+    }
+    sprintf (
+      SystemCommand,
+      GENFFS_STR,
+      mFfsFileType[Type],     // -t
+      InputFilePath,          // -i
+      GuidStr,                // -g
+      OutputFilePath          // -o
+      );
+
+    if (system (SystemCommand) != EFI_SUCCESS) {
+      free(SystemCommand);
+      free (GuidStr);
+      return EFI_ABORTED;
+    }
+    free(SystemCommand);
+
+  } else {
+    //
+    // -t  Type
+    // -i  InputFilePath
+    // -o  OutPutFilePath
+    // -g  FileGuid
+    // -x  Fixed
+    // -n  SectionAlign
+    //
+    if (Fixed) {
+      SystemCommand = malloc (
+        strlen (GENFFS_FIX) +
+        strlen (mFfsFileType[Type]) +
+        strlen (InputFilePath) +
+        strlen (GuidStr) +
+        strlen (OutputFilePath) +
+        1
+        );
+      if (NULL == SystemCommand) {
+        free (GuidStr);
+        return EFI_OUT_OF_RESOURCES;
+      }
+      sprintf (
+        SystemCommand,
+        GENFFS_FIX,
+        mFfsFileType[Type],     // -t
+        InputFilePath,          // -i
+        GuidStr,                // -g
+        OutputFilePath          // -o
+        );
+      if (system (SystemCommand) != EFI_SUCCESS) {
+        free(SystemCommand);
+        free (GuidStr);
+        return EFI_ABORTED;
+      }
+      free(SystemCommand);
+    } else {
+      SystemCommand = malloc (
+        strlen (GENFFS_STR) +
+        strlen (mFfsFileType[Type]) +
+        strlen (InputFilePath) +
+        strlen (GuidStr) +
+        strlen (OutputFilePath) +
+        1
+        );
+      if (NULL == SystemCommand) {
+        free (GuidStr);
+        return EFI_OUT_OF_RESOURCES;
+      }
+      sprintf (
+        SystemCommand,
+        GENFFS_STR,
+        mFfsFileType[Type],     // -t
+        InputFilePath,          // -i
+        GuidStr,                // -g
+        OutputFilePath          // -o
+        );
+      if (system (SystemCommand) != EFI_SUCCESS) {
+        free(SystemCommand);
+        free (GuidStr);
+        return EFI_ABORTED;
+      }
+      free(SystemCommand);
+    }
+  }
+  free (GuidStr);
+  return EFI_SUCCESS;
+}
+
+EFI_STATUS
+LibCreateNewFdCopy(
+  IN CHAR8*    OldFd,
+  IN CHAR8*    NewFd
+)
+{
+  CHAR8*                 SystemCommand;
+  SystemCommand             = NULL;
+
+
+  if (OldFd == NULL ||
+      NewFd    == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  //
+  // Create a copy the new file.
+  //
+
+  SystemCommand = malloc (
+    strlen (COPY_STR) +
+    strlen (OldFd)     +
+    strlen (NewFd)  +
+    1
+    );
+   if (NULL == SystemCommand) {
+     return EFI_OUT_OF_RESOURCES;
+   }
+
+  sprintf (
+    SystemCommand,
+    COPY_STR,
+    OldFd,
+    NewFd
+    );
+
+  if (system (SystemCommand) != EFI_SUCCESS) {
+    free(SystemCommand);
+    return EFI_ABORTED;
+  }
+  free(SystemCommand);
+
+  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 (NULL == RetStr) {
+    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 (NULL == SystemCommand) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  sprintf (
+    SystemCommand,
+    RMDIR_STR,
+    DirName
+    );
+
+  if (system (SystemCommand) != EFI_SUCCESS) {
+    free(SystemCommand);
+    return EFI_ABORTED;
+  }
+  free(SystemCommand);
+
+  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
+LibBfmDeleteFile(
+  IN   CHAR8    *FileName
+)
+{
+  CHAR8*                 SystemCommand;
+
+  SystemCommand             = NULL;
+
+
+  if (FileName == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+
+  //
+  // Delete a file.
+  //
+  SystemCommand = malloc (
+    strlen (DEL_STR) +
+    strlen (FileName)     +
+    1
+    );
+  if (NULL == SystemCommand) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+  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
+LibBfmFreeFd (
+  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;
+
+  if (TempFv->FvHeader != NULL) {
+      free (TempFv->FvHeader);
+  }
+    if (TempFv->FvExtHeader != NULL) {
+      free (TempFv->FvExtHeader);
+    }
+
+    //
+    // 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;
+  CHAR8                       *TemString;
+  EFI_STATUS                  Status;
+
+  UnCompressFile     = NULL;
+  CompressedFile     = NULL;
+  UnCompressedBuffer = NULL;
+  CompressedBuffer   = NULL;
+  TempName           = NULL;
+  TemDir             = NULL;
+  TemString          = 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);
+    if (strlen (TemDir) + strlen (OS_SEP_STR) + strlen (TEMP_DIR_NAME) > _MAX_PATH - 1) {
+      printf ("The directory is too long \n");
+      fclose (UnCompressFile);
+      return EFI_ABORTED;
+    }
+    strncat (TemDir, OS_SEP_STR, _MAX_PATH - strlen (TemDir) - 1);
+    strncat (TemDir, TEMP_DIR_NAME, _MAX_PATH - strlen (TemDir) - 1);
+    TemString = GenTempFile ();
+    TempName= LibFilenameStrExtended (strrchr(TemString, OS_SEP), TemDir, "comp");
+    free (TemString);
+    TemString = NULL;
+    if (TempName == NULL) {
+      fclose(UnCompressFile);
+      return EFI_ABORTED;
+    }
+
+    CompressedFile = fopen (TempName, "wb+");
+    if (CompressedFile == NULL) {
+      printf ("Error while open file %s \n", TempName);
+      fclose(UnCompressFile);
+      free (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 ("Out of resource, memory allocation failed. \n");
+      fclose (CompressedFile);
+      fclose(UnCompressFile);
+      free (TempName);
+      return EFI_OUT_OF_RESOURCES;
+    }
+
+    CompressedBuffer = malloc (UnCompressedSize);
+
+    if (CompressedBuffer == NULL) {
+      printf ("Out of resource, memory allocation failed. \n");
+      free (UnCompressedBuffer);
+      fclose (CompressedFile);
+      fclose(UnCompressFile);
+      free (TempName);
+      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");
+        free (UnCompressedBuffer);
+        free (CompressedBuffer);
+        fclose (CompressedFile);
+        fclose(UnCompressFile);
+        free (TempName);
+        return EFI_ABORTED;
+      }
+
+      if (CompressedSize > UnCompressedSize) {
+        printf("Error while do compress operation! \n");
+        free (UnCompressedBuffer);
+        free (CompressedBuffer);
+        fclose (CompressedFile);
+        fclose(UnCompressFile);
+        free (TempName);
+        return EFI_ABORTED;
+      }
+    } else {
+      printf("Error while reading file %s! \n", InputFileName);
+      free (UnCompressedBuffer);
+      free (CompressedBuffer);
+      fclose (CompressedFile);
+      fclose(UnCompressFile);
+      free (TempName);
+      return EFI_ABORTED;
+    }
+
+    //
+    // Write the compressed data into output file
+    //
+    if (fwrite (CompressedBuffer, 1, (size_t) CompressedSize, CompressedFile) != (size_t) CompressedSize) {
+      printf ("Error while writing %s file. \n", OutPutFileName);
+      free (UnCompressedBuffer);
+      free (CompressedBuffer);
+      fclose(UnCompressFile);
+      fclose (CompressedFile);
+      free (TempName);
+      return EFI_ABORTED;
+    }
+
+    fclose(UnCompressFile);
+    fclose (CompressedFile);
+    free (UnCompressedBuffer);
+    free (CompressedBuffer);
+
+    //
+    // Call GenSec tool to generate the compressed section.
+    //
+    LibCreateFfsSection(TempName, NULL, EFI_SECTION_COMPRESSION, OutPutFileName, NULL, NULL, NULL, "PI_STD");
+    free (TempName);
+    TempName = NULL;
+
+  } else if (CompressionType == EFI_NOT_COMPRESSED) {
+
+    LibCreateFfsSection(InputFileName, NULL, EFI_SECTION_COMPRESSION, OutPutFileName, NULL, NULL, NULL, "PI_NONE");
+
+  } else {
+    printf ("Error while generate compressed section, unknown compression type! \n");
+    return EFI_INVALID_PARAMETER;
+  }
+  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 ( "Fail to allocate memory. \n");
+          if (Tool != NULL) {
+            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;
+}
+
+EFI_STATUS
+LibLocateFvViaFvId (
+  IN     FIRMWARE_DEVICE     *FdData,
+  IN     CHAR8               *FvId,
+  IN OUT FV_INFORMATION      **FvInFd
+)
+{
+  UINT8                       FvIndex1;
+  UINT8                       FvIndex2;
+  BOOLEAN                     FvFoundFlag;
+
+  FvIndex1                    = 0;
+  FvIndex2                    = 0;
+  FvFoundFlag                 = FALSE;
+
+  if (FdData == NULL || FvId == NULL) {
+    printf ( "Error while find FV in FD. \n");
+    return EFI_INVALID_PARAMETER;
+  }
+
+  *FvInFd = FdData->Fv;
+
+  FvIndex1 = (UINT8) atoi (FvId + 2);
+
+  while (FvInFd != NULL) {
+    if (((*FvInFd)->FvName) != NULL) {
+      FvIndex2 = (UINT8) atoi ((*FvInFd)->FvName + 2);
+
+      if ((FvIndex2 <= FvIndex1) && (((*FvInFd)->FvLevel + FvIndex2) -1 >= FvIndex1)) {
+        FvFoundFlag = TRUE;
+        break;
+      }
+      if ((*FvInFd)->FvNext == 0) {
+        break;
+      }
+      *FvInFd = (*FvInFd)->FvNext;
+    }
+  }
+
+  //
+  // The specified FV id has issue, can not find the FV in FD.
+  //
+  if (!FvFoundFlag) {
+    printf ( "Error while find FV in FD. \n");
+    return EFI_ABORTED;
+  }
+
+  return EFI_SUCCESS;
+
+}
+
+
+EFI_STATUS
+LibPatchResetVectorAndFitTableData (
+IN CHAR8                      *OutputFileName,
+IN PATCH_DATA_PAD_FFS         *PatchData
+)
+{
+  FILE*           NewFvFile;
+  UINT64          NewFvLength;
+  UINT8           *Buffer;
+  UINT32          Count;
+
+
+  Count           = 0;
+  Buffer          = NULL;
+  NewFvFile       = NULL;
+
+  if (OutputFileName == NULL || PatchData == NULL) {
+    return EFI_ABORTED;
+  }
+
+  NewFvFile = fopen (OutputFileName, "rb+");
+  if (NewFvFile == NULL) {
+    return EFI_ABORTED;
+  }
+
+  fseek(NewFvFile, 0, SEEK_SET);
+  fseek(NewFvFile, 0, SEEK_END);
+
+  NewFvLength = ftell(NewFvFile);
+
+  do {
+
+    //
+    // The FV length should larger than Offset.
+    //
+    if (NewFvLength < PatchData->Offset) {
+      fclose (NewFvFile);
+      return EFI_ABORTED;
+    }
+
+    fseek(NewFvFile,PatchData->Offset,SEEK_SET);
+
+    Buffer = (UINT8 *) malloc (PatchData->Length);
+
+    if (Buffer == NULL) {
+      fclose (NewFvFile);
+      return EFI_ABORTED;
+    }
+
+    if (fread (Buffer, 1, (size_t) PatchData->Length, NewFvFile) != (size_t)  PatchData->Length) {
+      fclose (NewFvFile);
+      free(Buffer);
+      return EFI_ABORTED;
+    }
+
+    //
+    // The area used to patch data should be filled by 0xff.
+    //
+    for (Count = 0; Count< PatchData->Length; Count++) {
+      if (Buffer[Count] != 0xff){
+        fclose (NewFvFile);
+        free(Buffer);
+        return EFI_ABORTED;
+      }
+    }
+
+    free(Buffer);
+
+    fseek(NewFvFile,PatchData->Offset,SEEK_SET);
+
+    if (fwrite (PatchData->Data, 1, (size_t) PatchData->Length, NewFvFile) != (size_t) PatchData->Length) {
+      fclose (NewFvFile);
+      return EFI_ABORTED;
+    }
+
+    PatchData = PatchData->NextNode;
+  } while (PatchData != NULL);
+
+  fclose (NewFvFile);
+
+  return EFI_SUCCESS;
+}
+
+EFI_STATUS
+LibEncapNewFvFile(
+  IN     FV_INFORMATION              *FvInFd,
+  IN     CHAR8                       *TemDir,
+  OUT    CHAR8                       **OutputFile
+)
+{
+  EFI_STATUS                  Status;
+  UINT32                      ParentType;
+  UINT8                       ParentLevel;
+  UINT32                      Type;
+  UINT8                       Level;
+  CHAR8                       *InfFileName;
+  FILE                        *InfFile;
+  ENCAP_INFO_DATA             *LocalEncapData;
+  BOOLEAN                     FfsFoundFlag;
+  UINT32                      Index;
+  CHAR8                       *ExtractionTool;
+  BOOLEAN                     IsLastLevelFfs;
+  BOOLEAN                     IsLeafFlagIgnore;
+  BOOLEAN                     FirstInFlag;
+  CHAR8                       *InputFileName;
+  CHAR8                       *OutputFileName;
+  CHAR8                       *FvGuidName;
+
+  Index                       = 0;
+  ParentType                  = 0;
+  ParentLevel                 = 0;
+  Type                        = 0;
+  Level                       = 0;
+  FfsFoundFlag                = FALSE;
+  ExtractionTool              = NULL;
+  InputFileName               = NULL;
+  OutputFileName              = NULL;
+  IsLastLevelFfs              = TRUE;
+  IsLeafFlagIgnore            = FALSE;
+  FirstInFlag                 = TRUE;
+  FvGuidName                  = NULL;
+
+  //
+  // Encapsulate from the lowest FFS file level.
+  //
+  LocalEncapData = FvInFd->EncapData;
+  Level = LocalEncapData->Level;
+  Type  = LocalEncapData->Type;
+
+  //
+  // Get FV Name GUID
+  //
+
+  while (LocalEncapData != NULL) {
+    //
+    // Has changed.
+    //
+    if (LocalEncapData->Level > Level) {
+      if (LocalEncapData->Type == BFM_ENCAP_TREE_FFS) {
+        ParentLevel = Level;
+        ParentType  = Type;
+      }
+
+      Level       = LocalEncapData->Level;
+      Type        = LocalEncapData->Type;
+    }
+
+    if (LocalEncapData->NextNode != NULL) {
+      LocalEncapData = LocalEncapData->NextNode;
+    } else {
+      break;
+    }
+  }
+
+  do {
+    switch (ParentType) {
+      case BFM_ENCAP_TREE_FV:
+
+        //
+        // Generate FV.inf attributes.
+        //
+        InfFileName = LibFilenameStrExtended (strrchr(GenTempFile (), OS_SEP), TemDir, "inf");
+
+        InfFile = fopen (InfFileName, "wt+");
+
+        if (InfFile == NULL) {
+          printf ("Could not open inf file %s to store FV information. \n", InfFileName);
+          return EFI_ABORTED;
+        }
+
+        LocalEncapData = FvInFd->EncapData;
+        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) {
+            printf ("Out of resource, memory allocation failed. \n");
+            fclose (InfFile);
+            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)->BlockMap, InfFile, TRUE);
+        } else {
+          Status = LibFvHeaderOptionToStr(((EFI_FIRMWARE_VOLUME_HEADER *)LocalEncapData->Data)->BlockMap, InfFile, FALSE);
+        }
+
+
+        if (EFI_ERROR (Status)) {
+          printf ("Generate FV INF file [Options] section failed.\n");
+          fclose (InfFile);
+          if (FvGuidName != NULL) {
+            free (FvGuidName);
+          }
+          return Status;
+        }
+
+        Status = LibFvHeaderAttributeToStr(((EFI_FIRMWARE_VOLUME_HEADER *)LocalEncapData->Data)->Attributes, InfFile);
+
+        if (EFI_ERROR (Status)) {
+          printf ("Generate FV header attribute failed.\n");
+          if (FvGuidName != NULL) {
+            free (FvGuidName);
+          }
+          fclose (InfFile);
+          return Status;
+        }
+      if (LocalEncapData->FvExtHeader != NULL) {
+        Status = LibGenExtFile(LocalEncapData->FvExtHeader, InfFile);
+        if (FvGuidName != NULL) {
+          free (FvGuidName);
+        }
+        if (EFI_ERROR(Status)) {
+          printf("Generate FV EXT header failed.\n");
+          fclose (InfFile);
+          return Status;
+        }
+        FvGuidName = NULL;
+      }
+
+        //
+        // Found FFSs from Fv structure.
+        //
+        FfsFoundFlag = FALSE;
+        for (Index = 0; Index <= FvInFd->FfsNumbers; Index++) {
+
+          //
+          // 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) {
+              Status = LibAddFfsFileToFvInf (FvInFd->FfsAttuibutes[Index].FfsName, InfFile, TRUE);
+
+              if (EFI_ERROR (Status)) {
+                printf ("Error while generate FV inf file [files] section. \n");
+                fclose (InfFile);
+                return Status;
+              }
+
+              FvInFd->FfsAttuibutes[Index].Level = 0;
+              FirstInFlag = FALSE;
+              } else {
+                Status = LibAddFfsFileToFvInf (FvInFd->FfsAttuibutes[Index].FfsName, InfFile, FALSE);
+
+                if (EFI_ERROR (Status)) {
+                  printf ("Error while generate FV inf file [files] section. \n");
+                  fclose (InfFile);
+                  return Status;
+                }
+
+                FvInFd->FfsAttuibutes[Index].Level = 0;
+              }
+            FfsFoundFlag = TRUE;
+            }
+            //
+            // Also add the sub FV
+            //
+            if (FvInFd->FfsAttuibutes[Index].Level - 1 == ParentLevel+ 1) {
+              LocalEncapData = FvInFd->EncapData;
+              while (LocalEncapData->NextNode != NULL) {
+                if (LocalEncapData->Level == ParentLevel + 2) {
+                  break;
+                }
+                LocalEncapData = LocalEncapData->NextNode;
+              }
+
+              if (LocalEncapData->Type == BFM_ENCAP_TREE_GUIDED_SECTION) {
+                Status = LibAddFfsFileToFvInf (FvInFd->FfsAttuibutes[Index].FfsName, InfFile, FALSE);
+
+                if (EFI_ERROR (Status)) {
+                  printf ("Error while generate FV inf file [files] section.\n");
+                  fclose (InfFile);
+                  return Status;
+                }
+
+                FvInFd->FfsAttuibutes[Index].Level = 0;
+              }
+
+            }
+          }
+
+        IsLastLevelFfs = FALSE;
+        FirstInFlag = TRUE;
+        if (!FfsFoundFlag) {
+          Status = LibAddFfsFileToFvInf (OutputFileName, InfFile, TRUE);
+          if (EFI_ERROR (Status)) {
+            printf ("Error while generate FV inf file [files] section.\n");
+            fclose (InfFile);
+            return Status;
+          }
+        }
+        /*
+        if (OutputFileName != NULL && FfsFoundFlag) {
+          Status = LibAddFfsFileToFvInf (OutputFileName, InfFile, FALSE);
+
+          if (EFI_ERROR (Status)) {
+            //Error ("FMMT", 0, 0004, "error while encapsulate FD Image", "Generate FV inf file [files] section failed!");
+            return Status;
+          }
+        }
+        */
+        //
+        // Create FV
+        //
+        fclose (InfFile);
+        OutputFileName= LibFilenameStrExtended (strrchr(GenTempFile (), OS_SEP), TemDir, "FV");
+        Status = LibEncapsulateFfsToFv (InfFileName, NULL, OutputFileName, FvGuidName);
+        if (FvGuidName != NULL) {
+          free (FvGuidName);
+        }
+        if (EFI_ERROR (Status)) {
+          return Status;
+        }
+
+        //
+        // Patch FIT Table Data or reset vector data if exist.
+        //
+        if ((FvInFd->PatchData != NULL) && (1 == ParentLevel)) {
+          Status = LibPatchResetVectorAndFitTableData(OutputFileName, FvInFd->PatchData);
+          if (EFI_ERROR (Status)) {
+            printf ("Error while patch FIT Table Data or reset vector data. \n");
+            return Status;
+          }
+        }
+
+        break;
+      case BFM_ENCAP_TREE_FFS:
+        if (OutputFileName != NULL) {
+          InputFileName  = OutputFileName;
+          OutputFileName= LibFilenameStrExtended (strrchr(GenTempFile (), OS_SEP), TemDir, "ffs");
+
+          LocalEncapData = FvInFd->EncapData;
+          while (LocalEncapData->NextNode != NULL) {
+            if (LocalEncapData->Level == Level) {
+              break;
+            }
+            LocalEncapData = LocalEncapData->NextNode;
+          }
+
+          Status = LibEncapSectionFileToFFS(EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE, InputFileName, OutputFileName, ((EFI_FFS_FILE_HEADER *)LocalEncapData->Data)->Name, FALSE, 0);
+
+          if (EFI_ERROR (Status)) {
+            printf ("Error while generate FFS file. \n");
+            return Status;
+          }
+        }
+        break;
+      case BFM_ENCAP_TREE_GUIDED_SECTION:
+        //
+        // Create the guided section original data, do compress operation.
+        //
+        InputFileName  = OutputFileName;
+        OutputFileName= LibFilenameStrExtended (strrchr(GenTempFile (), OS_SEP), TemDir, "compressed");
+
+        //
+        // Use the guided section header guid to find out compress application name.
+        //
+        LocalEncapData = FvInFd->EncapData;
+        while (LocalEncapData->NextNode != NULL) {
+          if (LocalEncapData->Level == ParentLevel) {
+            break;
+          }
+          LocalEncapData = LocalEncapData->NextNode;
+        }
+
+        ExtractionTool =
+          LookupGuidedSectionToolPath (
+            mParsedGuidedSectionTools,
+            (EFI_GUID *)LocalEncapData->Data
+            );
+
+        Status = LibCreateGuidedSectionOriginalData (InputFileName, ExtractionTool, OutputFileName);
+
+        if (EFI_ERROR (Status)) {
+          printf ("Error while compress guided data. \n");
+          return Status;
+        }
+
+        InputFileName  = OutputFileName;
+        OutputFileName= LibFilenameStrExtended (strrchr(GenTempFile (), OS_SEP), TemDir, "guided");
+
+        Status = LibCreateFfsSection(InputFileName, NULL, EFI_SECTION_GUID_DEFINED, OutputFileName, NULL, NULL, LibBfmGuidToStr((EFI_GUID *)LocalEncapData->Data), NULL);
+
+        if (EFI_ERROR (Status)) {
+          printf ("Error while generate guided section. \n");
+          return Status;
+        }
+
+        break;
+      case BFM_ENCAP_TREE_COMPRESS_SECTION:
+        if (OutputFileName != NULL) {
+          InputFileName  = OutputFileName;
+
+          OutputFileName= LibFilenameStrExtended (strrchr(GenTempFile (), OS_SEP), TemDir, "comsec");
+
+          LocalEncapData = FvInFd->EncapData;
+          while (LocalEncapData->NextNode != NULL) {
+            if (LocalEncapData->Level == ParentLevel) {
+              break;
+            }
+            LocalEncapData = LocalEncapData->NextNode;
+          }
+
+          Status = LibGenCompressedSection (InputFileName, OutputFileName, *(UINT8 *)(LocalEncapData->Data));
+
+          if (EFI_ERROR (Status)) {
+            printf ("Error while generate compressed section. \n");
+            return Status;
+          }
+        }
+        break;
+      case BFM_ENCAP_TREE_FV_SECTION:
+        InputFileName  = OutputFileName;
+        OutputFileName= LibFilenameStrExtended (strrchr(GenTempFile (), OS_SEP), TemDir, "sec");
+
+        Status = LibCreateFfsSection(InputFileName, NULL, EFI_SECTION_FIRMWARE_VOLUME_IMAGE, OutputFileName, NULL, NULL, NULL, NULL);
+
+        if (EFI_ERROR (Status)) {
+          printf ("Error while generate FV section. \n");
+          return Status;
+        }
+
+        InputFileName  = OutputFileName;
+        OutputFileName= LibFilenameStrExtended (strrchr(GenTempFile (), OS_SEP), TemDir, "sec");
+
+        //
+        // Make it alignment.
+        //
+        Status = LibCreateFfsSection(InputFileName, NULL, 0, OutputFileName, NULL, NULL, NULL, NULL);
+
+        if (EFI_ERROR (Status)) {
+          printf ("Error while generate FV section. \n");
+          return Status;
+        }
+
+        break;
+      default:
+        printf("Don't know how to encapsulate the FD file! \n");
+        return EFI_ABORTED;
+    }
+
+
+    //
+    // Find next level and encapsulate type
+    //
+    ParentLevel -= 1;
+    LocalEncapData = FvInFd->EncapData;
+    while (LocalEncapData->NextNode != NULL) {
+      if (LocalEncapData->Level == ParentLevel) {
+        ParentType = LocalEncapData->Type;
+        break;
+      }
+      LocalEncapData = LocalEncapData->NextNode;
+    }
+  } while (ParentLevel != 0);
+
+
+  *OutputFile = OutputFileName;
+
+  return EFI_SUCCESS;
+
+}
+
+EFI_STATUS
+LibLocateBfv(
+  IN     FIRMWARE_DEVICE             *FdData,
+  IN OUT CHAR8                       **FvId,
+  IN OUT FV_INFORMATION              **FvInFd
+)
+{
+  UINT8                       FvIndex1;
+  UINT8                       FvIndex2;
+  BOOLEAN                     FvFoundFlag;
+
+  FvIndex1                    = 0;
+  FvIndex2                    = 0;
+  FvFoundFlag                 = FALSE;
+
+  if (FdData == NULL || FvId == NULL || FvInFd == NULL) {
+    return EFI_ABORTED;
+  }
+
+  *FvId = (*FvInFd)->FvName;
+
+  FvIndex1 = (UINT8) atoi ((*FvInFd)->FvName + 2);
+
+  *FvInFd = FdData->Fv;
+
+  while (FvInFd != NULL) {
+    if (((*FvInFd)->FvName) != NULL) {
+      FvIndex2 = (UINT8) atoi ((*FvInFd)->FvName + 2);
+
+      if ((FvIndex2 <= FvIndex1) && (((*FvInFd)->FvLevel + FvIndex2) -1 >= FvIndex1)) {
+        FvFoundFlag = TRUE;
+        break;
+      }
+      if ((*FvInFd)->FvNext == 0) {
+        break;
+      }
+      *FvInFd = (*FvInFd)->FvNext;
+    }
+  }
+
+  //
+  // The specified FV id has issue, can not find the FV in FD.
+  //
+  if (!FvFoundFlag) {
+    return EFI_ABORTED;
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+
+  Get the length of a file.
+
+  @param[in]      FileName      The name of a file.
+
+  @retval         The length of file.
+
+**/
+UINT64
+GetFileSize (
+  IN  CHAR8    *FileName
+)
+{
+  FILE*        File;
+  UINT64       Length;
+
+  File = NULL;
+
+  if (FileName == NULL) {
+    return 0;
+  }
+  File = fopen(FileName, "r");
+
+  if (File == NULL) {
+    return 0;
+  }
+  fseek(File, 0L, SEEK_END);
+  Length = ftell(File);
+  fclose(File);
+
+  return Length;
+}
+
+/**
+
+  Get the length of BFV PAD file.
+
+  @retval         The length of PAD file.
+
+**/
+UINT32
+GetBfvPadSize (
+  VOID
+)
+{
+  return PadSizeOfBfv;
+}
+
diff --git a/Platform/Intel/Tools/BfmLib/BinFileManager.c b/Platform/Intel/Tools/BfmLib/BinFileManager.c
new file mode 100644
index 0000000000..8c8b67bd37
--- /dev/null
+++ b/Platform/Intel/Tools/BfmLib/BinFileManager.c
@@ -0,0 +1,1024 @@
+/** @file
+
+ The main entry of BFM tool.
+
+ Copyright (c) 2011-2019, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "BinFileManager.h"
+
+BOOLEAN     mFvGuidIsSet = FALSE;
+EFI_GUID    mFvNameGuid  = {0};
+CHAR8*      mFvNameGuidString = NULL;
+CHAR8*      mGuidToolDefinition     = "GuidToolDefinitionConf.ini";
+
+//
+// Store GUIDed Section guid->tool mapping
+//
+EFI_HANDLE mParsedGuidedSectionTools = NULL;
+
+
+/**
+  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;
+}
+
+/**
+
+  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
+BfmImageView (
+  IN     CHAR8*           FdInName,
+  IN     CHAR8*           FvName,
+  IN     BOOLEAN          ViewFlag,
+  IN     FIRMWARE_DEVICE  **FdData
+)
+{
+  EFI_STATUS                  Status;
+  FIRMWARE_DEVICE             *LocalFdData;
+  FV_INFORMATION              *CurrentFv;
+  FILE                        *InputFile;
+  UINT32                      FvSize;
+  UINTN                       BytesRead;
+  EFI_FIRMWARE_VOLUME_HEADER  *FvImage;
+  UINT32                      FfsCount;
+  UINT8                       FvCount;
+  UINT8                       LastFvNumber;
+
+  LocalFdData    = NULL;
+  CurrentFv      = NULL;
+  FvImage        = NULL;
+  FvSize         = 0;
+  BytesRead      = 0;
+  FfsCount       = 0;
+  FvCount        = 0;
+  LastFvNumber   = 0;
+
+  //
+  // Check the FD file name/path.
+  //
+  if (FdInName == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  //
+  // Open the file containing the FV
+  //
+  InputFile = fopen (FdInName, "rb");
+  if (InputFile == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  Status = LibFindFvInFd (InputFile, &LocalFdData);
+
+  if (EFI_ERROR(Status)) {
+    fclose (InputFile);
+    return EFI_ABORTED;
+  }
+
+  CurrentFv = LocalFdData->Fv;
+
+  do {
+
+    memset (CurrentFv->FvName, '\0', _MAX_PATH);
+
+    if (LastFvNumber == 0) {
+      sprintf (CurrentFv->FvName, "FV%d", LastFvNumber);
+    } else {
+      sprintf (CurrentFv->FvName, "FV%d", LastFvNumber);
+    }
+
+    //
+    // Determine size of FV
+    //
+    if (fseek (InputFile, CurrentFv->ImageAddress, SEEK_SET) != 0) {
+      fclose (InputFile);
+      LibBfmFreeFd( LocalFdData);
+      return EFI_ABORTED;
+    }
+
+    Status = LibGetFvSize(InputFile, &FvSize);
+    if (EFI_ERROR (Status)) {
+      fclose (InputFile);
+      return EFI_ABORTED;
+    }
+
+    //
+    // 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) {
+      fclose (InputFile);
+      LibBfmFreeFd( LocalFdData);
+      return EFI_ABORTED;
+    }
+
+    BytesRead = fread (FvImage, 1, FvSize, InputFile);
+    if ((unsigned int) BytesRead != FvSize) {
+      free (FvImage);
+      fclose (InputFile);
+      LibBfmFreeFd( LocalFdData);
+      return EFI_ABORTED;
+    }
+
+    //
+    // Collect FV information each by each.
+    //
+    Status = LibGetFvInfo (FvImage, CurrentFv, FvName, 0, &FfsCount, ViewFlag, FALSE);
+    free (FvImage);
+    FvImage = NULL;
+    if (EFI_ERROR (Status)) {
+      fclose (InputFile);
+      LibBfmFreeFd( LocalFdData);
+      return Status;
+    }
+    FvCount = CurrentFv->FvLevel;
+    LastFvNumber = LastFvNumber+FvCount;
+
+    FfsCount = 0;
+
+    CurrentFv = CurrentFv->FvNext;
+
+  } while (CurrentFv != NULL);
+
+  if (!ViewFlag) {
+    *FdData = LocalFdData;
+  } else {
+    LibBfmFreeFd( LocalFdData);
+  }
+
+  fclose (InputFile);
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Add an FFS file into a specify FV.
+
+  @param[in]   FdInName     Input FD binary/image file name;
+  @param[in]   NewFile      The name of the file add in;
+  @param[in]   FdOutName    Name of output fd file.
+
+  @retval      EFI_SUCCESS
+  @retval      EFI_INVALID_PARAMETER
+  @retval      EFI_ABORTED
+
+**/
+EFI_STATUS
+BfmImageAdd (
+  IN     CHAR8*  FdInName,
+  IN     CHAR8*  NewFile,
+  IN     CHAR8*  FdOutName
+)
+{
+  EFI_STATUS                  Status;
+  FIRMWARE_DEVICE             *FdData;
+  FV_INFORMATION              *FvInFd;
+  ENCAP_INFO_DATA             *LocalEncapData;
+  ENCAP_INFO_DATA             *LocalEncapDataTemp;
+  FILE*                       NewFdFile;
+  FILE*                       NewFvFile;
+  UINT64                      NewFvLength;
+  UINT64                      NewFfsLength;
+  VOID*                       Buffer;
+  CHAR8                       *TemDir;
+  UINT8                       FvEncapLevel;
+  UINT8                       NewAddedFfsLevel;
+  BOOLEAN                     FfsLevelFoundFlag;
+  CHAR8                       *OutputFileName;
+  CHAR8                       *FvId;
+  BOOLEAN                     FirstInFlag;
+  BOOLEAN                     FvGuidExisted;
+
+  NewFvLength                 = 0;
+  FvEncapLevel                = 0;
+  NewAddedFfsLevel            = 0;
+
+  FfsLevelFoundFlag           = FALSE;
+  FirstInFlag                 = TRUE;
+  FdData                      = NULL;
+  FvInFd                      = NULL;
+  LocalEncapData              = NULL;
+  NewFdFile                   = NULL;
+  NewFvFile                   = NULL;
+  Buffer                      = NULL;
+  TemDir                      = NULL;
+  LocalEncapDataTemp          = NULL;
+  OutputFileName              = NULL;
+  FvId                        = NULL;
+  FvGuidExisted               = FALSE;
+
+  //
+  // Get the size of ffs file to be inserted.
+  //
+  NewFfsLength = GetFileSize(NewFile);
+
+  Status = BfmImageView (FdInName, NULL, FALSE, &FdData);
+
+  if (EFI_ERROR (Status)) {
+    printf ("Error while parse %s FD image.\n", FdInName);
+    return Status;
+  }
+  //
+  // Check the FvGuid whether exists or not when the BIOS hasn't default setting.
+  // If the FV image with -g GUID can't be found, the storage is still saved into the BFV and report warning message.
+  //
+  FvInFd = FdData->Fv;
+  do {
+    if (mFvGuidIsSet && FvInFd->IsInputFvFlag) {
+      FvGuidExisted = TRUE;
+    break;
+    }
+    FvInFd = FvInFd->FvNext;
+  } while (FvInFd != NULL);
+
+  if (mFvGuidIsSet && !FvGuidExisted) {
+    printf ("Fv image with the specified FV Name Guid %s can't be found in current FD.\n", mFvNameGuidString);
+    LibBfmFreeFd(FdData);
+    return EFI_ABORTED;
+  }
+  //
+  // Iterate to write FFS to each BFV.
+  //
+  FvInFd = FdData->Fv;
+  do {
+    if ((FvGuidExisted && mFvGuidIsSet && FvInFd->IsInputFvFlag) || ((!FvGuidExisted || (!mFvGuidIsSet)) && FvInFd->IsBfvFlag)) {
+
+      Status = LibLocateBfv (FdData, &FvId, &FvInFd);
+
+      if (EFI_ERROR (Status)) {
+        printf("Error while locate BFV from FD.\n");
+        LibBfmFreeFd(FdData);
+        return Status;
+      }
+
+      //
+      // Determine the new added ffs file level in the FV.
+      //
+      LocalEncapData = FvInFd->EncapData;
+
+      while (LocalEncapData != NULL && !FfsLevelFoundFlag ) {
+        if (LocalEncapData->Type == BFM_ENCAP_TREE_FV) {
+          if (FvEncapLevel == ((UINT8) atoi (FvId + 2) - (UINT8) atoi (FvInFd->FvName + 2))) {
+            //
+            // Found the FFS level in this FV.
+            //
+            LocalEncapDataTemp = LocalEncapData;
+            while (LocalEncapDataTemp != NULL) {
+              if (LocalEncapDataTemp->Type == BFM_ENCAP_TREE_FFS) {
+                NewAddedFfsLevel  = LocalEncapDataTemp->Level;
+                FfsLevelFoundFlag = TRUE;
+                break;
+              }
+              if (LocalEncapDataTemp->NextNode != NULL) {
+                LocalEncapDataTemp = LocalEncapDataTemp->NextNode;
+              } else {
+                break;
+              }
+            }
+          }
+          FvEncapLevel ++;
+        }
+
+        if (LocalEncapData->NextNode == NULL) {
+          break;
+        } else {
+          LocalEncapData = LocalEncapData->NextNode;
+        }
+      }
+
+      //
+      // Add the new file into FV.
+      //
+      FvInFd->FfsNumbers += 1;
+      if (strlen (NewFile) > _MAX_PATH - 1) {
+        printf ("The NewFile name is too long \n");
+        LibBfmFreeFd(FdData);
+        return EFI_ABORTED;
+      }
+      strncpy (FvInFd->FfsAttuibutes[FvInFd->FfsNumbers].FfsName, NewFile, _MAX_PATH - 1);
+      FvInFd->FfsAttuibutes[FvInFd->FfsNumbers].FfsName[_MAX_PATH - 1] = 0;
+      FvInFd->FfsAttuibutes[FvInFd->FfsNumbers].Level   = NewAddedFfsLevel;
+
+      TemDir = getcwd (NULL, _MAX_PATH);
+      if (strlen (TemDir) + strlen (OS_SEP_STR) + strlen (TEMP_DIR_NAME) > _MAX_PATH - 1) {
+        printf ("The directory is too long \n");
+        LibBfmFreeFd(FdData);
+        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);
+      Status = LibEncapNewFvFile (FvInFd, TemDir, &OutputFileName);
+
+      if (EFI_ERROR (Status)) {
+        printf("Error. The boot firmware volume (BFV) has only the spare space 0x%lx bytes. But the default setting data takes 0x%llx bytes, which can't be inserted into BFV. \n",(unsigned long) GetBfvPadSize (), (unsigned long long)NewFfsLength);
+        LibBfmFreeFd(FdData);
+        return Status;
+      }
+
+      if (FirstInFlag) {
+        //
+        // Write New Fv file into the NewFd file.
+        //
+        Status = LibCreateNewFdCopy (FdInName, FdOutName);
+        if (EFI_ERROR (Status)) {
+          printf("Error while copy from %s to %s file. \n", FdInName, FdOutName);
+          LibBfmFreeFd(FdData);
+          return Status;
+        }
+        FirstInFlag = FALSE;
+      }
+
+      NewFdFile = fopen (FdOutName, "rb+");
+      if (NewFdFile == NULL) {
+        printf("Error while create FD file %s. \n", FdOutName);
+        LibBfmFreeFd(FdData);
+        return EFI_ABORTED;
+      }
+
+      NewFvFile = fopen (OutputFileName, "rb+");
+
+      if (NewFvFile == NULL) {
+        printf("Error while create Fv file %s. \n", OutputFileName);
+        fclose(NewFdFile);
+        LibBfmFreeFd(FdData);
+        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)  {
+        printf ("Error while allocate resource! \n");
+        fclose(NewFdFile);
+        fclose(NewFvFile);
+        LibBfmFreeFd(FdData);
+        return EFI_ABORTED;
+      }
+
+      if (fread (Buffer, 1, (size_t) NewFvLength, NewFvFile) != (size_t) NewFvLength) {
+        printf("Error while reading Fv file %s. \n", OutputFileName);
+        free (Buffer);
+        fclose(NewFdFile);
+        fclose(NewFvFile);
+        LibBfmFreeFd(FdData);
+        return EFI_ABORTED;
+      }
+
+      fseek(NewFdFile, FvInFd->ImageAddress, SEEK_SET);
+      fseek(NewFdFile, FvInFd->ImageAddress, SEEK_SET);
+
+      if (NewFvLength <= FvInFd->FvHeader->FvLength) {
+        if (fwrite (Buffer, 1, (size_t) NewFvLength, NewFdFile) != (size_t) NewFvLength) {
+          printf("Error while writing FD file %s. \n", FdOutName);
+          fclose(NewFdFile);
+          fclose (NewFvFile);
+          free (Buffer);
+          LibBfmFreeFd(FdData);
+          return EFI_ABORTED;
+        }
+      } else {
+        printf("Error. The new size of BFV is 0x%llx bytes, which is larger than the previous size of BFV 0x%llx bytes. \n", (unsigned long long) NewFvLength, (unsigned long long) FvInFd->FvHeader->FvLength);
+        free (Buffer);
+        fclose(NewFdFile);
+        fclose(NewFvFile);
+        LibBfmFreeFd(FdData);
+        return EFI_ABORTED;
+      }
+
+      fclose(NewFdFile);
+      fclose(NewFvFile);
+      free (Buffer);
+      Buffer = NULL;
+
+    }
+    FvInFd = FvInFd->FvNext;
+  } while (FvInFd != NULL);
+
+
+  LibBfmFreeFd(FdData);
+
+  if (TemDir == NULL) {
+    if (mFvGuidIsSet) {
+      printf ("Fv image with the specified FV Name Guid %s can't be found.\n", mFvNameGuidString);
+    } else {
+      printf ("BFV image can't be found.\n");
+    }
+    return EFI_NOT_FOUND;
+  }
+
+  Status = LibRmDir (TemDir);
+
+  if (EFI_ERROR (Status)) {
+    printf("Error while remove temporary directory. \n");
+    return Status;
+  }
+
+  return EFI_SUCCESS;
+}
+
+
+/**
+  Replace an FFS file into a specify FV.
+
+  @param[in]   FdInName     Input FD binary/image file name;
+  @param[in]   NewFile      The name of the file add in;
+  @param[in]   FdOutName    Name of output fd file.
+
+  @retval      EFI_SUCCESS
+  @retval      EFI_INVALID_PARAMETER
+  @retval      EFI_ABORTED
+
+**/
+EFI_STATUS
+BfmImageReplace (
+  IN     CHAR8*  FdInName,
+  IN     CHAR8*  NewFile,
+  IN     CHAR8*  FdOutName
+)
+{
+  EFI_STATUS                  Status;
+  FIRMWARE_DEVICE             *FdData;
+  FV_INFORMATION              *FvInFd;
+  FILE*                       NewFdFile;
+  FILE*                       NewFvFile;
+  UINT64                      NewFvLength;
+  UINT64                      NewFfsLength;
+  VOID*                       Buffer;
+  CHAR8                       *TemDir;
+  CHAR8                       *OutputFileName;
+  CHAR8                       *FvId;
+  BOOLEAN                     FirstInFlag;
+  UINT32                      Index;
+  BOOLEAN                     FvToBeUpdate;
+  BOOLEAN                     FdIsUpdate;
+  ENCAP_INFO_DATA             *LocalEncapData;
+  ENCAP_INFO_DATA             *LocalEncapDataTemp;
+  UINT8                       FvEncapLevel;
+  UINT8                       NewAddedFfsLevel;
+  BOOLEAN                     FfsLevelFoundFlag;
+  EFI_GUID                    EfiNewAddToBfvGuid;
+  FILE*                       FfsFile;
+  UINTN                       BytesRead;
+  BOOLEAN                     ReplaceSameFv;
+  BOOLEAN                     FvGuidExisted;
+
+  NewFvLength                 = 0;
+  FdIsUpdate                  = FALSE;
+  FirstInFlag                 = TRUE;
+  FdData                      = NULL;
+  FvInFd                      = NULL;
+  NewFdFile                   = NULL;
+  NewFvFile                   = NULL;
+  Buffer                      = NULL;
+  TemDir                      = NULL;
+  OutputFileName              = NULL;
+  FvId                        = NULL;
+  FfsFile                     = NULL;
+  BytesRead                   = 0;
+  ReplaceSameFv               = FALSE;
+  FvGuidExisted               = FALSE;
+
+  //
+  // Get the size of ffs file to be inserted.
+  //
+  NewFfsLength = GetFileSize(NewFile);
+  //
+  // Get FFS GUID
+  //
+  FfsFile = fopen (NewFile, "rb");
+  if (FfsFile == NULL) {
+    printf ("Error while read %s.\n", NewFile);
+  return EFI_ABORTED;
+  }
+  fseek (FfsFile, 0, SEEK_SET);
+  BytesRead = fread (&EfiNewAddToBfvGuid, 1, sizeof(EFI_GUID), FfsFile);
+  fclose (FfsFile);
+  if (BytesRead != sizeof(EFI_GUID)) {
+    printf ("Error while read the GUID from %s.\n", NewFile);
+  return EFI_ABORTED;
+  }
+  Status = BfmImageView (FdInName, NULL, FALSE, &FdData);
+
+  if (EFI_ERROR (Status)) {
+    printf ("Error while parse %s FD image.\n", FdInName);
+    return Status;
+  }
+
+  //
+  // Check the FvGuid whether exists or not when the BIOS has default setting.
+  // 1.  No option means the storage is saved into the same FV image.
+  // 2.  The FV image with -g GUID can't be found. The storage is still saved into the same FV image and report warning message.
+  //
+  if (!mFvGuidIsSet) {
+    ReplaceSameFv = TRUE;
+  }
+  FvInFd = FdData->Fv;
+  do {
+    if (mFvGuidIsSet && FvInFd->IsInputFvFlag) {
+      FvGuidExisted = TRUE;
+    break;
+    }
+    FvInFd = FvInFd->FvNext;
+  } while (FvInFd != NULL);
+
+  if (mFvGuidIsSet && !FvGuidExisted) {
+    printf ("Fv image with the specified FV Name Guid %s can't be found in current FD.\n", mFvNameGuidString);
+    ReplaceSameFv = TRUE;
+    LibBfmFreeFd(FdData);
+    return EFI_ABORTED;
+  }
+  //
+  // Interate to insert or replace default setting to Fv
+  //
+  FvInFd = FdData->Fv;
+  do {
+    FvToBeUpdate = FALSE;
+    if (mFvGuidIsSet && FvInFd->IsInputFvFlag) {
+      FvToBeUpdate = TRUE;
+    }
+
+    Status = LibLocateBfv (FdData, &FvId, &FvInFd);
+
+    if (EFI_ERROR (Status)) {
+      printf("Error while locate BFV from FD.\n");
+      LibBfmFreeFd(FdData);
+      return Status;
+    }
+
+    Index = 0;
+    while (Index <= FvInFd->FfsNumbers) {
+      //
+      // Locate the multi-platform ffs in Fv and then replace or delete it.
+      //
+      if (!CompareGuid(&FvInFd->FfsHeader[Index].Name, &EfiNewAddToBfvGuid)) {
+      if (ReplaceSameFv) {
+      FvToBeUpdate = TRUE;
+      }
+        break;
+      }
+      Index ++;
+    }
+
+    if (FvToBeUpdate || (Index <= FvInFd->FfsNumbers)) {
+      if (FvToBeUpdate) {
+        FdIsUpdate = TRUE;
+        if (Index <= FvInFd->FfsNumbers) {
+          //
+          // Override original default data by New File
+          //
+          if (strlen (NewFile) > _MAX_PATH - 1) {
+            printf ("The NewFile name is too long \n");
+            LibBfmFreeFd(FdData);
+            return EFI_ABORTED;
+          }
+          strncpy (FvInFd->FfsAttuibutes[Index].FfsName, NewFile, _MAX_PATH - 1);
+          FvInFd->FfsAttuibutes[Index].FfsName[_MAX_PATH - 1] = 0;
+        } else {
+          FfsLevelFoundFlag           = FALSE;
+          FvEncapLevel                = 0;
+          NewAddedFfsLevel            = 0;
+          //
+          // Determine the new added ffs file level in the FV.
+          //
+          LocalEncapData = FvInFd->EncapData;
+
+          while (LocalEncapData != NULL && !FfsLevelFoundFlag ) {
+            if (LocalEncapData->Type == BFM_ENCAP_TREE_FV) {
+              if (FvEncapLevel == ((UINT8) atoi (FvId + 2) - (UINT8) atoi (FvInFd->FvName + 2))) {
+                //
+                // Found the FFS level in this FV.
+                //
+                LocalEncapDataTemp = LocalEncapData;
+                while (LocalEncapDataTemp != NULL) {
+                  if (LocalEncapDataTemp->Type == BFM_ENCAP_TREE_FFS) {
+                    NewAddedFfsLevel  = LocalEncapDataTemp->Level;
+                    FfsLevelFoundFlag = TRUE;
+                    break;
+                  }
+                  if (LocalEncapDataTemp->NextNode != NULL) {
+                    LocalEncapDataTemp = LocalEncapDataTemp->NextNode;
+                  } else {
+                    break;
+                  }
+                }
+              }
+              FvEncapLevel ++;
+            }
+
+            if (LocalEncapData->NextNode == NULL) {
+              break;
+            } else {
+              LocalEncapData = LocalEncapData->NextNode;
+            }
+          }
+
+          //
+          // Add the new file into FV.
+          //
+          FvInFd->FfsNumbers += 1;
+          memcpy (FvInFd->FfsAttuibutes[FvInFd->FfsNumbers].FfsName, NewFile, _MAX_PATH);
+          FvInFd->FfsAttuibutes[FvInFd->FfsNumbers].Level   = NewAddedFfsLevel;
+        }
+      } else {
+        //
+        // Remove original default data from FV.
+        //
+        FvInFd->FfsAttuibutes[Index].FfsName[0] = '\0';
+      }
+
+      if (TemDir == NULL) {
+        TemDir = getcwd (NULL, _MAX_PATH);
+        if (strlen (TemDir) + strlen (OS_SEP_STR)+ strlen (TEMP_DIR_NAME) > _MAX_PATH - 1) {
+          printf ("The directory is too long \n");
+          LibBfmFreeFd(FdData);
+          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);
+      }
+
+      Status = LibEncapNewFvFile (FvInFd, TemDir, &OutputFileName);
+
+      if (EFI_ERROR (Status)) {
+        printf("Error. The boot firmware volume (BFV) has only the spare space 0x%lx bytes. But the default setting data takes 0x%llx bytes, which can't be inserted into BFV. \n", (unsigned long) GetBfvPadSize (), (unsigned long long) NewFfsLength);
+        LibBfmFreeFd(FdData);
+        return Status;
+      }
+
+      if (FirstInFlag) {
+        //
+        // Write New Fv file into the NewFd file.
+        //
+        Status = LibCreateNewFdCopy (FdInName, FdOutName);
+        if (EFI_ERROR (Status)) {
+          printf("Error while copy from %s to %s file. \n", FdInName, FdOutName);
+          LibBfmFreeFd(FdData);
+          return Status;
+        }
+        FirstInFlag = FALSE;
+      }
+
+      NewFdFile = fopen (FdOutName, "rb+");
+      if (NewFdFile == NULL) {
+        printf("Error while create FD file %s. \n", FdOutName);
+        LibBfmFreeFd(FdData);
+        return EFI_ABORTED;
+      }
+
+      NewFvFile = fopen (OutputFileName, "rb+");
+
+      if (NewFvFile == NULL) {
+        printf("Error while create Fv file %s. \n", OutputFileName);
+        LibBfmFreeFd(FdData);
+        fclose (NewFdFile);
+        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)  {
+        LibBfmFreeFd(FdData);
+        fclose (NewFdFile);
+        fclose (NewFvFile);
+        return EFI_ABORTED;
+      }
+
+      if (fread (Buffer, 1, (size_t) NewFvLength, NewFvFile) != (size_t) NewFvLength) {
+        printf("Error while read Fv file %s. \n", OutputFileName);
+        LibBfmFreeFd(FdData);
+        free (Buffer);
+        fclose (NewFdFile);
+        fclose (NewFvFile);
+        return EFI_ABORTED;
+      }
+
+      fseek(NewFdFile, FvInFd->ImageAddress, SEEK_SET);
+      fseek(NewFdFile, FvInFd->ImageAddress, SEEK_SET);
+
+      if (NewFvLength <= FvInFd->FvHeader->FvLength) {
+        if (fwrite (Buffer, 1, (size_t) NewFvLength, NewFdFile) != (size_t) NewFvLength) {
+          printf("Error while write FD file %s. \n", FdOutName);
+          fclose(NewFdFile);
+          fclose (NewFvFile);
+          LibBfmFreeFd(FdData);
+          free (Buffer);
+          return EFI_ABORTED;
+        }
+      } else {
+        printf("Error. The new size of BFV is 0x%llx bytes, which is larger than the previous size of BFV 0x%llx bytes. \n", (unsigned long long) NewFvLength, (unsigned long long) FvInFd->FvHeader->FvLength);
+        free (Buffer);
+        LibBfmFreeFd(FdData);
+        fclose (NewFdFile);
+        fclose (NewFvFile);
+        return EFI_ABORTED;
+      }
+
+      fclose(NewFdFile);
+      fclose(NewFvFile);
+      free (Buffer);
+      Buffer = NULL;
+
+    }
+    FvInFd = FvInFd->FvNext;
+  } while (FvInFd != NULL);
+
+  LibBfmFreeFd(FdData);
+
+  if (TemDir == NULL || !FdIsUpdate) {
+    if (mFvGuidIsSet) {
+      printf ("Fv image with the specified FV Name Guid %s can't be found.\n", mFvNameGuidString);
+    } else {
+      printf ("BFV image can't be found.\n");
+    }
+    return EFI_NOT_FOUND;
+  }
+
+  Status = LibRmDir (TemDir);
+
+  if (EFI_ERROR (Status)) {
+    printf("Error while remove temporary directory. \n");
+    return Status;
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+
+  The main entry of BFM tool.
+
+**/
+int main(
+  int      Argc,
+  char     *Argv[]
+)
+{
+  EFI_STATUS                    Status;
+  FIRMWARE_DEVICE               *FdData;
+  CHAR8                         *InFilePath;
+  CHAR8                         FullGuidToolDefinition[_MAX_PATH];
+  CHAR8                         *FileName;
+  UINTN                         FileNameIndex;
+  CHAR8                         *PathList;
+  UINTN                         EnvLen;
+  CHAR8                         *NewPathList;
+
+  FdData                      = NULL;
+  PathList                    = NULL;
+  NewPathList                 = NULL;
+  EnvLen                      = 0;
+
+  if (Argc <= 1) {
+    return -1;
+  }
+  FileName = Argv[0];
+  //
+  // Save, skip filename arg
+  //
+  Argc--;
+  Argv++;
+
+  if ((stricmp(Argv[0], "-v") == 0)) {
+    //
+    // Check the revison of BfmLib
+    // BfmLib -v
+    //
+    printf("%s\n", __BUILD_VERSION);
+    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
+  //
+  // Get the same path with the application itself
+  //
+  if (strlen (FileName) > _MAX_PATH - 1) {
+    Error (NULL, 0, 2000, "Parameter: Input file name 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 of BfmLib comes from the '%s'. \n", InFilePath);
+    mParsedGuidedSectionTools = ParseGuidedSectionToolsFile (InFilePath);
+    free (InFilePath);
+  } else {
+    //
+    // Use the pre-defined standard guided tools.
+    //
+  printf ("\nThe Guid Tool Definition of BfmLib comes from the build-in default configuration. \n");
+    mParsedGuidedSectionTools = LibPreDefinedGuidedTools ();
+  }
+
+  //
+  // BfmLib -e FdName.Fd
+  //
+  if ((stricmp(Argv[0], "-e") == 0)) {
+
+    if (Argc != 2) {
+      return -1;
+    }
+    //
+    // Extract FFS files.
+    //
+    Status = BfmImageView (Argv[1], NULL, FALSE, &FdData);
+
+    if (EFI_ERROR (Status)) {
+      return -1;
+    }
+
+    if (FdData == NULL) {
+      return -1;
+    }
+
+    LibBfmFreeFd(FdData);
+
+  } else if ((stricmp(Argv[0], "-i") == 0)) {
+    //
+    // Insert FFS files to BFV
+    // BfmLib -i InFdName.Fd FfsName.ffs OutFdName.Fd -g FvNameGuid
+    //
+    if (Argc == 6) {
+      mFvGuidIsSet      = TRUE;
+      mFvNameGuidString = Argv[5];
+      StringToGuid (Argv[5], &mFvNameGuid);
+      Argc -= 2;
+    }
+    if (Argc != 4) {
+      return -1;
+    }
+    Status = BfmImageAdd(Argv[1], Argv[2], Argv[3]);
+
+    if (EFI_ERROR (Status)) {
+      return -1;
+    }
+
+  } else if ((stricmp(Argv[0], "-r") == 0)) {
+    //
+    // Replace FFS files in BFV
+    // BfmLib -r InFdName.Fd FfsName.ffs OutFdName.Fd -g FvNameGuid
+    //
+    if (Argc == 6) {
+      mFvGuidIsSet      = TRUE;
+      mFvNameGuidString = Argv[5];
+      StringToGuid (Argv[5], &mFvNameGuid);
+      Argc -= 2;
+    }
+    if (Argc != 4) {
+      return -1;
+    }
+    Status = BfmImageReplace (Argv[1], Argv[2], Argv[3]);
+
+    if (EFI_ERROR (Status)) {
+      return -1;
+    }
+
+  } else {
+    //
+    // Invalid parameter.
+    //
+    return -1;
+  }
+
+  return 1;
+}
+
diff --git a/Platform/Intel/Tools/BfmLib/BinFileManager.h b/Platform/Intel/Tools/BfmLib/BinFileManager.h
new file mode 100644
index 0000000000..ea27f2e8f2
--- /dev/null
+++ b/Platform/Intel/Tools/BfmLib/BinFileManager.h
@@ -0,0 +1,439 @@
+/** @file
+
+ The header of BinFileManager.c.
+
+Copyright (c) 2011-2019, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef    _BIN_FILE_MANAGER_
+#define    _BIN_FILE_MANAGER_
+
+#ifdef __GNUC__
+#include <unistd.h>
+#else
+#include <io.h>
+#include <direct.h>
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <FvLib.h>
+#include <Common/UefiBaseTypes.h>
+#include <Common/PiFirmwareVolume.h>
+#include <Common/PiFirmwareFile.h>
+
+#include "CommonLib.h"
+#include "EfiUtilityMsgs.h"
+#include "ParseGuidedSectionTools.h"
+#include "StringFuncs.h"
+#include "Compress.h"
+#include "Decompress.h"
+#include "ParseInf.h"
+
+#ifndef _MAX_PATH
+#define _MAX_PATH 500
+#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 TEMP_DIR_NAME              "Temp"
+#define UTILITY_NAME               "Binary File Manager (BFM)"
+#define UTILITY_SHORT_NAME         "BFM"
+#define UTILITY_MAJOR_VERSION      0
+#define UTILITY_MINOR_VERSION      1
+#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 BFM_ENCAP_TYPE;
+
+#define MAX_LEVEL_IN_FV_FILE  32
+
+//
+// Types of BFM_ENCAP_TREENODE_TYPE
+//
+#define BFM_ENCAP_TREE_FV                    0x1
+#define BFM_ENCAP_TREE_FFS                   0x2
+#define BFM_ENCAP_TREE_GUIDED_SECTION        0x3
+#define BFM_ENCAP_TREE_COMPRESS_SECTION      0x4
+#define BFM_ENCAP_TREE_FV_SECTION            0x5
+
+extern EFI_HANDLE mParsedGuidedSectionTools;
+extern BOOLEAN     mFvGuidIsSet;
+extern EFI_GUID    mFvNameGuid;
+
+//
+// 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];
+
+  //
+  // 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];
+
+}FFS_ATTRIBUTES;
+
+
+typedef struct __ENCAP_INFO_DATA{
+  //
+  // Now Level
+  //
+  UINT8                      Level;
+
+  //
+  // Encapsulate type.
+  //
+  BFM_ENCAP_TYPE             Type;
+
+  //
+  // Data, if it's FV, should be FV header.
+  //
+  VOID                       *Data;
+
+  //
+  // if FV ExtHeaderOffset not to zero, should also have FvExtHeader information
+  //
+  EFI_FIRMWARE_VOLUME_EXT_HEADER *FvExtHeader;
+
+
+  //
+  // Next node.
+  //
+  struct __ENCAP_INFO_DATA   *NextNode;
+}ENCAP_INFO_DATA;
+
+
+//
+// Contain Offset and Data for PAD FFS contain reset vector or FIT data.
+//
+typedef struct _PATCH_DATA_PAD_FFS {
+  //
+  // The offset of data relative to FV start address;
+  //
+  UINT32                          Offset;
+  //
+  // Data
+  //
+  VOID                            *Data;
+  //
+  // Length of Data
+  //
+  UINT32                          Length;
+  //
+  // Next node.
+  //
+  struct _PATCH_DATA_PAD_FFS      *NextNode;
+} PATCH_DATA_PAD_FFS;
+
+
+//
+// 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;
+  PATCH_DATA_PAD_FFS         *PatchData;
+  BOOLEAN                    IsBfvFlag;
+  BOOLEAN                    IsInputFvFlag;
+
+} FV_INFORMATION;
+
+typedef struct _FIRMWARE_DEVICE {
+  ///
+  /// Size of FD file
+  ///
+  UINT32                   Size;
+  FV_INFORMATION           *Fv;
+} FIRMWARE_DEVICE;
+
+VOID
+Usage (
+  VOID
+);
+
+
+CHAR8 *
+GenTempFile (
+  VOID
+);
+
+EFI_STATUS
+LibFindFvInFd (
+  IN     FILE             *InputFile,
+  IN OUT FIRMWARE_DEVICE  **FdData
+);
+
+/**
+
+   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     UINT32                       *FfsCount,
+  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
+  );
+
+EFI_STATUS
+LibCreateNewFdCopy(
+  IN CHAR8*    OldFd,
+  IN CHAR8*    NewFd
+  );
+
+/**
+  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
+  );
+
+
+/**
+
+  Free the whole Fd data structure.
+
+  @param[in]  Fd  The pointer point to the Fd data structure.
+
+**/
+VOID
+LibBfmFreeFd (
+  FIRMWARE_DEVICE *Fd
+);
+
+EFI_HANDLE
+LibPreDefinedGuidedTools (
+  VOID
+);
+
+EFI_STATUS
+LibEncapNewFvFile(
+  IN     FV_INFORMATION              *FvInFd,
+  IN     CHAR8                       *TemDir,
+  OUT    CHAR8                       **OutputFile
+);
+
+EFI_STATUS
+LibLocateBfv(
+  IN     FIRMWARE_DEVICE             *FdData,
+  IN OUT CHAR8                       **FvId,
+  IN OUT FV_INFORMATION              **FvInFd
+);
+
+/**
+
+  Get the length of a file.
+
+  @param[in]      FileName      The name of a file.
+
+  @retval         The length of file.
+
+**/
+UINT64
+GetFileSize (
+  IN  CHAR8    *FileName
+);
+
+/**
+
+  Get the length of BFV PAD file.
+
+  @retval         The length of PAD file.
+
+**/
+UINT32
+GetBfvPadSize (
+  VOID
+);
+#endif
diff --git a/Platform/Intel/Tools/BfmLib/GNUmakefile b/Platform/Intel/Tools/BfmLib/GNUmakefile
new file mode 100644
index 0000000000..bd88c58afe
--- /dev/null
+++ b/Platform/Intel/Tools/BfmLib/GNUmakefile
@@ -0,0 +1,15 @@
+## @file
+# GNU/Linux makefile for 'BfmLib' module build.
+#
+# Copyright (c) 2011-2019, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+MAKEROOT ?= $(EDK_TOOLS_PATH)/Source/C
+
+APPNAME = BfmLib
+
+LIBS = -lCommon
+
+OBJECTS = BinFileManager.o BfmLib.o
+
+include $(MAKEROOT)/Makefiles/app.makefile
diff --git a/Platform/Intel/Tools/BfmLib/Makefile b/Platform/Intel/Tools/BfmLib/Makefile
new file mode 100644
index 0000000000..0d10f4ff2d
--- /dev/null
+++ b/Platform/Intel/Tools/BfmLib/Makefile
@@ -0,0 +1,17 @@
+## @file
+#
+# Windows makefile for 'BfmLib' module build.
+#
+# Copyright (c) 2011-2019, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent#
+##
+!INCLUDE $(EDK_TOOLS_PATH)\Source\C\Makefiles\ms.common
+
+APPNAME = BfmLib
+
+LIBS = $(LIB_PATH)\Common.lib
+
+OBJECTS = BinFileManager.obj BfmLib.obj
+
+!INCLUDE $(EDK_TOOLS_PATH)\Source\C\Makefiles\ms.app
+
-- 
2.18.0.windows.1


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [edk2-platform patch 3/6] BaseTools\FCE: Add a tool FCE
  2019-06-21  1:26 [edk2-platform patch 0/6] Add tools FMMT FCE and FitGen Zhang, Shenglei
  2019-06-21  1:26 ` [edk2-platform patch 1/6] Platform\Tools: Add a tool FMMT Zhang, Shenglei
  2019-06-21  1:26 ` [edk2-platform patch 2/6] Platform\Tools: Add a tool BfmLib Zhang, Shenglei
@ 2019-06-21  1:26 ` Zhang, Shenglei
  2019-06-21  1:26 ` [edk2-platform patch 4/6] Platform\Tools: Add top level Makefile and GNUMakefile Zhang, Shenglei
                   ` (3 subsequent siblings)
  6 siblings, 0 replies; 15+ messages in thread
From: Zhang, Shenglei @ 2019-06-21  1:26 UTC (permalink / raw)
  To: devel; +Cc: Bob Feng, Liming Gao

FCE is a tool to retrieve and change HII configuration data in
Firmware Device(*.fd) files.
https://bugzilla.tianocore.org/show_bug.cgi?id=1848

Cc: Bob Feng <bob.c.feng@intel.com>
Cc: Liming Gao <liming.gao@intel.com>
Signed-off-by: Shenglei Zhang <shenglei.zhang@intel.com>
---
 Platform/Intel/Tools/FCE/BinaryCreate.c       |  216 +
 Platform/Intel/Tools/FCE/BinaryCreate.h       |  157 +
 Platform/Intel/Tools/FCE/BinaryParse.c        | 1326 ++++
 Platform/Intel/Tools/FCE/BinaryParse.h        |  187 +
 Platform/Intel/Tools/FCE/Common.c             | 2183 ++++++
 Platform/Intel/Tools/FCE/Common.h             |  999 +++
 Platform/Intel/Tools/FCE/Expression.c         | 2367 ++++++
 Platform/Intel/Tools/FCE/Fce.c                | 6449 +++++++++++++++++
 Platform/Intel/Tools/FCE/Fce.h                |  447 ++
 Platform/Intel/Tools/FCE/GNUmakefile          |   22 +
 Platform/Intel/Tools/FCE/IfrParse.c           | 4836 ++++++++++++
 Platform/Intel/Tools/FCE/IfrParse.h           |  789 ++
 Platform/Intel/Tools/FCE/Makefile             |   19 +
 .../Intel/Tools/FCE/MonotonicBasedVariable.c  |  874 +++
 .../Intel/Tools/FCE/MonotonicBasedVariable.h  |  162 +
 Platform/Intel/Tools/FCE/TimeBasedVariable.c  |  878 +++
 Platform/Intel/Tools/FCE/TimeBasedVariable.h  |  166 +
 Platform/Intel/Tools/FCE/Variable.c           | 1091 +++
 Platform/Intel/Tools/FCE/Variable.h           |  154 +
 Platform/Intel/Tools/FCE/VariableCommon.h     |   55 +
 20 files changed, 23377 insertions(+)
 create mode 100644 Platform/Intel/Tools/FCE/BinaryCreate.c
 create mode 100644 Platform/Intel/Tools/FCE/BinaryCreate.h
 create mode 100644 Platform/Intel/Tools/FCE/BinaryParse.c
 create mode 100644 Platform/Intel/Tools/FCE/BinaryParse.h
 create mode 100644 Platform/Intel/Tools/FCE/Common.c
 create mode 100644 Platform/Intel/Tools/FCE/Common.h
 create mode 100644 Platform/Intel/Tools/FCE/Expression.c
 create mode 100644 Platform/Intel/Tools/FCE/Fce.c
 create mode 100644 Platform/Intel/Tools/FCE/Fce.h
 create mode 100644 Platform/Intel/Tools/FCE/GNUmakefile
 create mode 100644 Platform/Intel/Tools/FCE/IfrParse.c
 create mode 100644 Platform/Intel/Tools/FCE/IfrParse.h
 create mode 100644 Platform/Intel/Tools/FCE/Makefile
 create mode 100644 Platform/Intel/Tools/FCE/MonotonicBasedVariable.c
 create mode 100644 Platform/Intel/Tools/FCE/MonotonicBasedVariable.h
 create mode 100644 Platform/Intel/Tools/FCE/TimeBasedVariable.c
 create mode 100644 Platform/Intel/Tools/FCE/TimeBasedVariable.h
 create mode 100644 Platform/Intel/Tools/FCE/Variable.c
 create mode 100644 Platform/Intel/Tools/FCE/Variable.h
 create mode 100644 Platform/Intel/Tools/FCE/VariableCommon.h

diff --git a/Platform/Intel/Tools/FCE/BinaryCreate.c b/Platform/Intel/Tools/FCE/BinaryCreate.c
new file mode 100644
index 0000000000..2f36bc2ef3
--- /dev/null
+++ b/Platform/Intel/Tools/FCE/BinaryCreate.c
@@ -0,0 +1,216 @@
+/** @file
+
+ The API to create the binary.
+
+ Copyright (c) 2011-2019, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "BinaryCreate.h"
+#ifndef __GNUC__
+#define GENSEC_RAW      "GenSec -s %s \"%s\" -o \"%s\" > NUL"
+#else
+#define GENSEC_RAW      "GenSec -s %s \"%s\" -o \"%s\" > /dev/null"
+#endif
+
+//
+// The guid is to for FFS of BFV.
+//
+EFI_GUID gEfiFfsBfvForMultiPlatformGuid = EFI_FFS_BFV_FOR_MULTIPLATFORM_GUID;
+EFI_GUID gEfiFfsBfvForMultiPlatformGuid2 = EFI_FFS_BFV_FOR_MULTIPLATFORM_GUID2;
+
+/**
+  Convert a GUID to a string.
+
+  @param[in]   Guid    Pointer to GUID to print.
+
+  @return The string after convert.
+**/
+static
+CHAR8 *
+LibBfmGuidToStr (
+  IN  EFI_GUID  *Guid
+)
+{
+  CHAR8 * Buffer;
+
+  Buffer = NULL;
+
+  if (Guid == NULL) {
+    return NULL;
+  }
+
+  Buffer = (CHAR8 *) malloc (36 + 1);
+
+  if (Buffer == NULL) {
+    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;
+}
+
+/**
+  Create the Ras section in FFS
+
+  @param[in]   InputFilePath   .efi file, it's optional unless process PE/TE section.
+  @param[in]   OutputFilePath  .te or .pe file
+
+  @retval EFI_SUCCESS
+
+**/
+EFI_STATUS
+CreateRawSection (
+  IN CHAR8*     InputFilePath,
+  IN CHAR8*     OutputFilePath
+  )
+{
+  INT32        ReturnValue;
+  CHAR8*       SystemCommand;
+
+  SystemCommand             = NULL;
+  SystemCommand = malloc (
+    strlen (GENSEC_RAW) +
+    strlen ("EFI_SECTION_RAW") +
+    strlen (InputFilePath) +
+    strlen (OutputFilePath) +
+    1
+  );
+  if (NULL == SystemCommand) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+  sprintf (
+    SystemCommand,
+    GENSEC_RAW,
+    "EFI_SECTION_RAW",
+    InputFilePath,
+    OutputFilePath
+  );
+  ReturnValue = system (SystemCommand);
+  free(SystemCommand);
+
+  if (ReturnValue != 0) {
+    printf ("Error. Call GenSec failed.\n");
+    return EFI_ABORTED;
+  }
+  return EFI_SUCCESS;
+}
+
+/**
+  Create the Ras type of FFS
+
+  @param[in]   InputFilePath   .efi file, it's optional unless process PE/TE section.
+  @param[in]   OutputFilePath  .te or .pe file
+
+  @retval EFI_SUCCESS
+
+**/
+EFI_STATUS
+CreateRawFfs (
+  IN CHAR8**    InputFilePaths,
+  IN CHAR8*     OutputFilePath,
+  IN BOOLEAN    SizeOptimized
+  )
+{
+  INT32        ReturnValue;
+  CHAR8*       SystemCommandFormatString;
+  CHAR8*       SystemCommand;
+  CHAR8*       GuidStr;
+  CHAR8*       FilePathFormatStr;
+  CHAR8*       FilePathStr;
+  UINT32       Index;
+  UINT32       StrLen;
+  UINT32       Size;
+
+  SystemCommand    = NULL;
+  GuidStr          = NULL;
+  FilePathStr      = NULL;
+  StrLen           = 0;
+
+  FilePathFormatStr = " -i \"";
+
+  for (Index = 0; InputFilePaths[Index] != NULL; Index++) {
+    Size = strlen (FilePathFormatStr) + strlen (InputFilePaths[Index]) + 2; // 2 menas "" "
+    if (FilePathStr == NULL) {
+      FilePathStr = malloc (Size);
+      if (NULL == FilePathStr) {
+        return EFI_OUT_OF_RESOURCES;
+      }
+    } else {
+      FilePathStr = realloc (FilePathStr, StrLen + Size);
+      if (NULL == FilePathStr) {
+        return EFI_OUT_OF_RESOURCES;
+      }
+    }
+    memset (FilePathStr + StrLen, ' ', Size);
+    memcpy (FilePathStr + StrLen, FilePathFormatStr, strlen(FilePathFormatStr));
+    memcpy(FilePathStr + StrLen + strlen(FilePathFormatStr), InputFilePaths[Index], strlen(InputFilePaths[Index]));
+    StrLen += Size;
+    *(FilePathStr + StrLen - 2) = '\"';
+  }
+   if (FilePathStr == NULL) {
+    return EFI_ABORTED;
+  }
+  *(FilePathStr + StrLen - 1)= '\0';
+
+
+  if (SizeOptimized) {
+    GuidStr = LibBfmGuidToStr(&gEfiFfsBfvForMultiPlatformGuid2);
+  } else {
+    GuidStr  = LibBfmGuidToStr(&gEfiFfsBfvForMultiPlatformGuid);
+  }
+  if (NULL == GuidStr) {
+    free (FilePathStr);
+    return EFI_OUT_OF_RESOURCES;
+  }
+  SystemCommandFormatString = "GenFfs -t %s %s -g %s -o \"%s\"";
+  SystemCommand = malloc (
+    strlen (SystemCommandFormatString) +
+    strlen ("EFI_FV_FILETYPE_FREEFORM") +
+    strlen (FilePathStr) +
+    strlen (GuidStr) +
+    strlen (OutputFilePath) +
+    1
+    );
+  if (NULL == SystemCommand) {
+    free (GuidStr);
+    free (FilePathStr);
+    return EFI_OUT_OF_RESOURCES;
+  }
+  sprintf (
+    SystemCommand,
+    "GenFfs -t %s %s -g %s -o \"%s\"",
+    "EFI_FV_FILETYPE_FREEFORM",// -t
+    FilePathStr,               // -i
+    GuidStr,                   // -g
+    OutputFilePath             // -o
+    );
+  ReturnValue = system (SystemCommand);
+  free(SystemCommand);
+  free (FilePathStr);
+  free (GuidStr);
+
+  if (ReturnValue != 0) {
+    printf ("Error. Call GenFfs failed.\n");
+    return EFI_ABORTED;
+  }
+  return EFI_SUCCESS;
+}
+
diff --git a/Platform/Intel/Tools/FCE/BinaryCreate.h b/Platform/Intel/Tools/FCE/BinaryCreate.h
new file mode 100644
index 0000000000..0e2f22599e
--- /dev/null
+++ b/Platform/Intel/Tools/FCE/BinaryCreate.h
@@ -0,0 +1,157 @@
+/** @file
+
+ The API to create the binary.
+
+ Copyright (c) 2011-2019, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _BINARY_CREATE_H_
+#define _BINARY_CREATE_H_ 1
+
+#include <FvLib.h>
+#include "Compress.h"
+#include "Decompress.h"
+#include "CommonLib.h"
+#include "EfiUtilityMsgs.h"
+#include "FirmwareVolumeBufferLib.h"
+#include "OsPath.h"
+#include "ParseGuidedSectionTools.h"
+#include "StringFuncs.h"
+#include "ParseInf.h"
+#include <Common/UefiBaseTypes.h>
+#include <Common/UefiInternalFormRepresentation.h>
+#include <Common/UefiCapsule.h>
+#include <Common/PiFirmwareFile.h>
+#include <Common/PiFirmwareVolume.h>
+#include <Guid/PiFirmwareFileSystem.h>
+#include <IndustryStandard/PeImage.h>
+#include <Protocol/GuidedSectionExtraction.h>
+
+//1AE42876-008F-4161-B2B7-1C0D15C5EF43
+#define EFI_FFS_BFV_FOR_MULTIPLATFORM_GUID \
+  { 0x1ae42876, 0x008f, 0x4161, { 0xb2, 0xb7, 0x1c, 0xd, 0x15, 0xc5, 0xef, 0x43 }}
+
+extern EFI_GUID gEfiFfsBfvForMultiPlatformGuid;
+
+// {003E7B41-98A2-4BE2-B27A-6C30C7655225}
+#define EFI_FFS_BFV_FOR_MULTIPLATFORM_GUID2 \
+  { 0x3e7b41, 0x98a2, 0x4be2, { 0xb2, 0x7a, 0x6c, 0x30, 0xc7, 0x65, 0x52, 0x25 }}
+
+extern EFI_GUID gEfiFfsBfvForMultiPlatformGuid2;
+
+typedef UINT64 SKU_ID;
+
+typedef struct {
+  UINT32 Offset:24;
+  UINT32 Value:8;
+} PCD_DATA_DELTA;
+
+typedef struct {
+  SKU_ID SkuId;
+  UINT16 DefaultId;
+  UINT8  Reserved[6];
+} PCD_DEFAULT_INFO;
+
+typedef struct {
+  //
+  // Full size, it must be at 8 byte alignment.
+  //
+  UINT32 DataSize;
+  //
+  // HeaderSize includes HeaderSize fields and DefaultInfo arrays
+  //
+  UINT32 HeaderSize;
+  //
+  // DefaultInfo arrays those have the same default setting.
+  //
+  PCD_DEFAULT_INFO DefaultInfo[1];
+  //
+  // Default data is stored as variable storage or the array of DATA_DELTA.
+  //
+} PCD_DEFAULT_DATA;
+
+#define PCD_NV_STORE_DEFAULT_BUFFER_SIGNATURE SIGNATURE_32('N', 'S', 'D', 'B')
+
+typedef struct {
+  //
+  // PCD_NV_STORE_DEFAULT_BUFFER_SIGNATURE
+  //
+  UINT32    Signature;
+  //
+  // Length of the taken default buffer
+  //
+  UINT32    Length;
+  //
+  // Length of the total reserved buffer
+  //
+  UINT32    MaxLength;
+  //
+  // Reserved for 8 byte alignment
+  //
+  UINT32    Reserved;
+  // one or more PCD_DEFAULT_DATA
+} PCD_NV_STORE_DEFAULT_BUFFER_HEADER;
+
+//
+// NvStoreDefaultValueBuffer layout:
+// +-------------------------------------+
+// | PCD_NV_STORE_DEFAULT_BUFFER_HEADER  |
+// +-------------------------------------+
+// | PCD_DEFAULT_DATA (DEFAULT, Standard)|
+// +-------------------------------------+
+// | PCD_DATA_DELTA   (DEFAULT, Standard)|
+// +-------------------------------------+
+// | ......                              |
+// +-------------------------------------+
+// | PCD_DEFAULT_DATA (SKU A, Standard)  |
+// +-------------------------------------+
+// | PCD_DATA_DELTA   (SKU A, Standard)  |
+// +-------------------------------------+
+// | ......                              |
+// +-------------------------------------+
+//
+
+#pragma pack(1)
+
+typedef struct {
+  UINT16 Offset;
+  UINT8  Value;
+} DATA_DELTA;
+
+#pragma pack()
+
+/**
+  Create the Ras section in FFS
+
+  @param[in]   InputFilePath   The input file path and name.
+  @param[in]   OutputFilePath  The output file path and name.
+
+  @retval EFI_SUCCESS
+
+**/
+EFI_STATUS
+CreateRawSection (
+  IN CHAR8*     InputFilePath,
+  IN CHAR8*     OutputFilePath
+  );
+
+/**
+  Create the Ras type of FFS
+
+  @param[in]   InputFilePath   .efi file, it's optional unless process PE/TE section.
+  @param[in]   OutputFilePath  .te or .pe file
+
+  @retval EFI_SUCCESS
+
+**/
+EFI_STATUS
+CreateRawFfs (
+  IN CHAR8**    InputFilePaths,
+  IN CHAR8*     OutputFilePath,
+  IN BOOLEAN    SizeOptimized
+  );
+
+#endif
+
diff --git a/Platform/Intel/Tools/FCE/BinaryParse.c b/Platform/Intel/Tools/FCE/BinaryParse.c
new file mode 100644
index 0000000000..e9f8ee6826
--- /dev/null
+++ b/Platform/Intel/Tools/FCE/BinaryParse.c
@@ -0,0 +1,1326 @@
+/** @file
+
+ The API to parse the binary.
+
+ Copyright (c) 2011-2019, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __GNUC__
+#include "windows.h"
+#else
+#include <sys/types.h>
+#include <dirent.h>
+#include <unistd.h>
+#endif
+#include "BinaryParse.h"
+#include "BinaryCreate.h"
+#include "VariableCommon.h"
+#include "FirmwareVolumeBufferLib.h"
+
+extern G_EFI_FD_INFO  gEfiFdInfo;
+extern EFI_HANDLE     mParsedGuidedSectionTools;
+extern CHAR8          mInputFdName[MAX_FILENAME_LEN];
+
+//
+// The Guid to sign the position of Vfr and Uni array in FV
+//
+EFI_GUID  gVfrArrayAttractGuid                         = EFI_VFR_ATTRACT_GUID;
+EFI_GUID  gUniStrArrayAttractGuid                      = EFI_UNI_STR_ATTRACT_GUID;
+EFI_GUID  gEfiSystemNvDataFvGuid                       = EFI_SYSTEM_NVDATA_FV_GUID;
+EFI_GUID  gEfiCrc32GuidedSectionExtractionProtocolGuid = EFI_CRC32_GUIDED_SECTION_EXTRACTION_PROTOCOL_GUID;
+
+/**
+  Converts a three byte length value into a UINT32.
+
+  @param  ThreeByteLength   Pointer to the first of the 3 byte length.
+
+  @retval  Length           Size of the section
+
+**/
+static
+UINT32
+Get3ByteLength (
+  IN UINT8     *ThreeByteLength
+  )
+{
+  UINT32  Length;
+
+  Length = 0;
+
+  if (ThreeByteLength == NULL) {
+    return 0;
+  }
+
+  Length  = *((UINT32 *) ThreeByteLength);
+  Length  = Length & 0x00FFFFFF;
+
+  return Length;
+}
+
+/**
+  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;
+}
+
+/**
+  Check whether exist the same Ifr FFS. If not existed, return TRUE.
+
+  @param[in]   FfsImage   The pointer to the binary.
+  @param[in]   FileSize   The size of binary.
+
+  @return The string after convert.
+**/
+static
+BOOLEAN
+NotExistSameFfsIfr (
+  IN  VOID     *FfsImage
+)
+{
+  UINT32  Index;
+
+  Index = 0;
+
+  while (gEfiFdInfo.FfsArray[Index] != NULL) {
+    if (memcmp (gEfiFdInfo.FfsArray[Index], FfsImage, sizeof (EFI_GUID)) == 0) {
+      return FALSE;
+    }
+    Index++;
+  }
+  return TRUE;
+}
+
+/**
+  This function returns the next larger size that meets the alignment
+  requirement specified.
+
+  @param  ActualSize        The size.
+  @param  Alignment         The desired alignment.
+
+  @retval The Occupied length
+
+**/
+static
+UINT32
+GetOccupiedSize (
+  IN UINT32  ActualSize,
+  IN UINT32  Alignment
+  )
+{
+  UINT32  OccupiedSize;
+
+  OccupiedSize = ActualSize;
+  while ((OccupiedSize & (Alignment - 1)) != 0) {
+    OccupiedSize++;
+  }
+
+  return OccupiedSize;
+}
+
+
+/**
+  Parses FFS Sections, and remove the FFS headers. Tis function olny handle one efi in this FFS.
+
+  @param  SectionBuffer     The section base address
+  @param  BufferLength      The length of FFS.
+  @param  EfiBufferHeader   The structure dual pointer to the efi informations
+
+  @retval  EFI_SUCCESS      The application exited normally.
+  @retval  EFI_ABORTED       An error occurred.
+
+**/
+EFI_STATUS
+ParseSection (
+  IN      BOOLEAN              IsFfsOrEfi,
+  IN OUT  UINT8                *SectionBuffer,
+  IN      UINT32               BufferLength,
+  IN OUT  EFI_SECTION_STRUCT   **EfiBufferHeader
+  )
+{
+  UINT32              ParsedLength;
+  EFI_SECTION_TYPE    Type;
+  UINT8               *Ptr;
+  UINT32              SectionLength;
+  UINT8               *CompressedBuffer;
+  UINT32              CompressedLength;
+  UINT8               *UncompressedBuffer;
+  UINT32              UncompressedLength;
+  UINT8               CompressionType;
+  DECOMPRESS_FUNCTION DecompressFunction;
+  GETINFO_FUNCTION    GetInfoFunction;
+  UINT32              ScratchSize;
+  UINT8               *ScratchBuffer;
+  EFI_STATUS          Status;
+  UINT32              DstSize;
+  CHAR8               *ExtractionTool;
+  CHAR8               *ToolInputFile;
+  CHAR8               *ToolOutputFile;
+  CHAR8               *SystemCommandFormatString;
+  CHAR8               *SystemCommand;
+  UINT8               *ToolOutputBuffer;
+  UINT32              ToolOutputLength;
+  BOOLEAN             HasDepexSection;
+
+  Ptr                       = NULL;
+  SectionLength             = 0;
+  CompressedBuffer          = NULL;
+  CompressedLength          = 0;
+  UncompressedBuffer        = NULL;
+  UncompressedLength        = 0;
+  CompressionType           = 0;
+  ScratchSize               = 0;
+  ScratchBuffer             = NULL;
+  Status                    = EFI_SUCCESS;
+  DstSize                   = 0;
+  ExtractionTool            = NULL;
+  ToolInputFile             = NULL;
+  ToolOutputFile            = NULL;
+  SystemCommandFormatString = NULL;
+  SystemCommand             = NULL;
+
+  //
+  // Jump the FFS header
+  //
+  if (IsFfsOrEfi) {
+    SectionBuffer = SectionBuffer + sizeof (EFI_FFS_FILE_HEADER);
+    BufferLength  = BufferLength - sizeof (EFI_FFS_FILE_HEADER);
+  }
+  ParsedLength     = 0;
+  HasDepexSection  = FALSE;
+  ExtractionTool   = NULL;
+  ToolOutputLength = 0;
+  ToolOutputBuffer = NULL;
+
+  (*EfiBufferHeader)->Length = BufferLength;
+
+  while (ParsedLength < BufferLength) {
+    Ptr           = SectionBuffer + ParsedLength;
+
+    SectionLength = Get3ByteLength (((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;
+    }
+
+    switch (Type) {
+
+    case EFI_SECTION_PE32:
+    case EFI_SECTION_TE:
+      //
+      //Got the correct address
+      //
+     (*EfiBufferHeader)->BufferBase = (UINTN)(Ptr + sizeof (EFI_COMMON_SECTION_HEADER));
+      return EFI_SUCCESS;
+
+    case EFI_SECTION_RAW:
+    case EFI_SECTION_PIC:
+       break;
+
+    case EFI_SECTION_USER_INTERFACE:
+      HasDepexSection = FALSE;
+      break;
+
+    case EFI_SECTION_FIRMWARE_VOLUME_IMAGE:
+    case EFI_SECTION_COMPATIBILITY16:
+    case EFI_SECTION_FREEFORM_SUBTYPE_GUID:
+      break;
+
+    case EFI_SECTION_PEI_DEPEX:
+    case EFI_SECTION_DXE_DEPEX:
+    case EFI_SECTION_SMM_DEPEX:
+      HasDepexSection = TRUE;
+      break;
+
+    case EFI_SECTION_VERSION:
+      break;
+    case EFI_SECTION_COMPRESSION:
+      UncompressedBuffer  = NULL;
+      CompressedLength    = SectionLength - sizeof (EFI_COMPRESSION_SECTION);
+      UncompressedLength  = ((EFI_COMPRESSION_SECTION *) Ptr)->UncompressedLength;
+      CompressionType     = ((EFI_COMPRESSION_SECTION *) Ptr)->CompressionType;
+
+      if (CompressionType == EFI_NOT_COMPRESSED) {
+        if (CompressedLength != UncompressedLength) {
+          Error (
+            NULL,
+            0,
+            0,
+            "file is not compressed, but the compressed length does not match the uncompressed length",
+            NULL
+            );
+          return EFI_ABORTED;
+        }
+
+        UncompressedBuffer = Ptr + sizeof (EFI_COMPRESSION_SECTION);
+      } else if (CompressionType == EFI_STANDARD_COMPRESSION) {
+        GetInfoFunction     = EfiGetInfo;
+        DecompressFunction  = EfiDecompress;
+        CompressedBuffer  = Ptr + sizeof (EFI_COMPRESSION_SECTION);
+
+        Status = GetInfoFunction (
+                   CompressedBuffer,
+                   CompressedLength,
+                   &DstSize,
+                   &ScratchSize
+                   );
+        if (EFI_ERROR (Status)) {
+          Error (NULL, 0, 0003, "error getting compression info from compression section", NULL);
+          return EFI_ABORTED;
+        }
+
+        if (DstSize != UncompressedLength) {
+          Error (NULL, 0, 0003, "compression error in the compression section", NULL);
+          return EFI_ABORTED;
+        }
+
+        ScratchBuffer       = malloc (ScratchSize);
+        if (ScratchBuffer == NULL) {
+          return EFI_ABORTED;
+        }
+        UncompressedBuffer  = malloc (UncompressedLength);
+        if (UncompressedBuffer == NULL) {
+          free (ScratchBuffer);
+          return EFI_ABORTED;
+        }
+        memset (UncompressedBuffer, 0, UncompressedLength);
+
+        Status = DecompressFunction (
+                   CompressedBuffer,
+                   CompressedLength,
+                   UncompressedBuffer,
+                   UncompressedLength,
+                   ScratchBuffer,
+                   ScratchSize
+                  );
+        free (ScratchBuffer);
+        if (Status != EFI_SUCCESS) {
+          Error (NULL, 0, 0003, "decompress failed", NULL);
+          free (UncompressedBuffer);
+          return EFI_ABORTED;
+        }
+      } else {
+        Error (NULL, 0, 0003, "unrecognized compression type", "type 0x%X", CompressionType);
+        return EFI_ABORTED;
+      }
+
+      Status = ParseSection (FALSE, UncompressedBuffer, UncompressedLength, EfiBufferHeader);
+      if (Status != EFI_SUCCESS) {
+        Error (NULL, 0, 0003, "failed to parse section", NULL);
+        free (UncompressedBuffer);
+        UncompressedBuffer = NULL;
+      } else {
+        return EFI_SUCCESS;
+      }
+      //
+      // Store the allocate memory address for UncompressedBuffer
+      //
+      if (UncompressedBuffer != NULL) {
+        (*EfiBufferHeader)->UncompressedBuffer[(*EfiBufferHeader)->UnCompressIndex] = (UINTN) UncompressedBuffer;
+        (*EfiBufferHeader)->UnCompressIndex = (*EfiBufferHeader)->UnCompressIndex + 1;
+      }
+      break;
+
+    case EFI_SECTION_GUID_DEFINED:
+      //
+      // Decompress failed, and then check for CRC32 sections which we can handle internally if needed.
+      // Maybe this section is no-compressed.
+      //
+      if (!CompareGuid (
+           &((EFI_GUID_DEFINED_SECTION *) Ptr)->SectionDefinitionGuid,
+           &gEfiCrc32GuidedSectionExtractionProtocolGuid
+           )) {
+        //
+        // CRC32 guided section
+        //
+        Status = ParseSection (
+                   FALSE,
+                   SectionBuffer + ((EFI_GUID_DEFINED_SECTION *) Ptr)->DataOffset,
+                   BufferLength - ((EFI_GUID_DEFINED_SECTION *) Ptr)->DataOffset,
+                   EfiBufferHeader
+                  );
+        if (EFI_ERROR (Status)) {
+          Error (NULL, 0, 0003, "parse of CRC32 GUIDED section failed", NULL);
+          return EFI_ABORTED;
+        } else {
+          return EFI_SUCCESS;
+        }
+      } else {
+        ExtractionTool = LookupGuidedSectionToolPath (
+                           mParsedGuidedSectionTools,
+                           &((EFI_GUID_DEFINED_SECTION *) Ptr)->SectionDefinitionGuid
+                           );
+
+        if (ExtractionTool != NULL) {
+          ToolInputFile  = GenTempFile ();
+          ToolOutputFile = GenTempFile ();
+          //
+          // Construction 'system' command string
+          //
+          SystemCommandFormatString = "%s -d -o \"%s\" \"%s\"";
+          SystemCommand = malloc (
+                            strlen (SystemCommandFormatString) \
+                            + strlen (ExtractionTool)          \
+                            + strlen (ToolInputFile)           \
+                            + strlen (ToolOutputFile)          \
+                            + 1
+                            );
+          if (SystemCommand == NULL) {
+            free (ExtractionTool);
+            free (ToolInputFile);
+            free (ToolOutputFile);
+            return EFI_ABORTED;
+          }
+          sprintf (
+            SystemCommand,
+            "%s -d -o \"%s\" \"%s\"",
+            ExtractionTool,
+            ToolOutputFile,
+            ToolInputFile
+            );
+          free (ExtractionTool);
+
+          Status = PutFileImage (
+                     ToolInputFile,
+                     (CHAR8*) Ptr + ((EFI_GUID_DEFINED_SECTION *) Ptr)->DataOffset,
+                     SectionLength - ((EFI_GUID_DEFINED_SECTION *) Ptr)->DataOffset
+                   );
+
+          if (HasDepexSection) {
+            HasDepexSection = FALSE;
+          }
+
+          system (SystemCommand);
+          remove (ToolInputFile);
+          free (ToolInputFile);
+          ToolInputFile = NULL;
+          free (SystemCommand);
+          SystemCommand = NULL;
+
+          if (EFI_ERROR (Status)) {
+            Error ("FCE", 0, 0004, "unable to decoded GUIDED section", NULL);
+            free (ToolOutputFile);
+            return EFI_ABORTED;
+          }
+
+          Status = GetFileImage (
+                     ToolOutputFile,
+                     (CHAR8 **)&ToolOutputBuffer,
+                     &ToolOutputLength
+                    );
+          remove (ToolOutputFile);
+          free (ToolOutputFile);
+          ToolOutputFile = NULL;
+          if (EFI_ERROR (Status)) {
+            return EFI_ABORTED;
+          }
+        }
+        Status = ParseSection (
+                  FALSE,
+                  ToolOutputBuffer,
+                  ToolOutputLength,
+                  EfiBufferHeader
+                  );
+        if (EFI_ERROR (Status)) {
+          Error (NULL, 0, 0003, "parse of decoded GUIDED section failed", NULL);
+          return EFI_ABORTED;
+        }
+      }
+      break;
+
+    default:
+      ;
+    }
+    ParsedLength += SectionLength;
+    //
+    // We make then next section begin on a 4-byte boundary
+    //
+    ParsedLength = GetOccupiedSize (ParsedLength, 4);
+  }
+
+  return EFI_ABORTED;
+}
+
+static
+BOOLEAN
+GetNextOffset (
+  IN UINT8 *Data,
+  IN EFI_GUID *Guid,
+  IN UINTN Len,
+  IN OUT UINTN *Offset
+  )
+{
+  UINTN NextOffset;
+  if (*Offset >= Len || Len - *Offset <= sizeof (EFI_GUID)) {
+    return FALSE;
+  }
+
+  for (NextOffset = *Offset; NextOffset < Len - sizeof (EFI_GUID); NextOffset++) {
+    if (CompareGuid(Guid, (EFI_GUID*)(Data + NextOffset)) == 0) {
+      *Offset = NextOffset + sizeof(EFI_GUID);
+      return TRUE;
+    }
+  }
+  return FALSE;
+}
+
+/**
+  Get the address by Guid.
+
+  Parse the FFS image, and find the GUID address.There may be some Guids matching the
+  searched Guid.
+
+  @param Fv                     the Pointer to the image.
+  @param Guid                   The Guid need to find.
+  @param Offset                 The dual Pointer to the offset.
+  @param NumOfMatchGuid         The number of matching Guid offset.
+
+  @retval EFI_SUCCESS           The Search was complete successfully
+  @return EFI_ABORTED           An error occurred
+**/
+EFI_STATUS
+GetAddressByGuid (
+  IN  VOID        *Fv,
+  IN  EFI_GUID    *Guid,
+  IN  UINTN       Len,
+  OUT UINTN       **Offset,
+  OUT UINT8       *NumOfMatchGuid
+  )
+{
+  VOID        *LocalFv;
+  UINT8       Flag;
+
+  EFI_RAW_SECTION* Section;
+  UINT8       *RawData;
+  VOID*       SectionStart;
+  UINTN       NextOffset;
+  UINTN       Key;
+  UINTN       TotalSectionsSize;
+  UINTN       SecLen;
+  UINTN       SecHdr;
+  EFI_STATUS  Status;
+
+  if( (Fv == NULL) || (Fv == NULL) || (Guid == NULL) || Len == 0 ){
+    return EFI_ABORTED;
+  }
+
+  LocalFv         = Fv;
+  Flag            = 0;
+  Section         = NULL;
+  Key             = 0;
+
+  if (NumOfMatchGuid != NULL) {
+    *NumOfMatchGuid = 0;
+  }
+
+  SectionStart = (VOID*)((UINTN)LocalFv + FvBufGetFfsHeaderSize(LocalFv));
+  TotalSectionsSize = Len - FvBufGetFfsHeaderSize(LocalFv);
+  while (TRUE) {
+    Status = FvBufFindNextSection (
+               SectionStart,
+               TotalSectionsSize,
+               &Key,
+               (VOID **)&Section
+               );
+    if (Section == NULL || EFI_ERROR (Status)) {
+      break;
+    }
+
+    if (EFI_SECTION_RAW == Section->Type) {
+      if ((*(UINT32 *)Section->Size & 0xffffff) == 0xffffff) {
+        SecLen = ((EFI_RAW_SECTION2 *)Section)->ExtendedSize;
+        SecHdr = sizeof(EFI_RAW_SECTION2);
+      } else {
+        SecLen = *(UINT32 *)Section->Size & 0xffffff;
+        SecHdr = sizeof(EFI_RAW_SECTION);
+      }
+      if (SecLen <= SecHdr || SecLen - SecHdr < sizeof(EFI_GUID)) {
+        continue;
+      }
+      RawData = (UINT8 *)Section + SecHdr;
+      NextOffset = 0;
+      while (GetNextOffset(RawData, Guid, SecLen - SecHdr, &NextOffset)) {
+        Flag = 1;
+        if ((NumOfMatchGuid != NULL) && (Offset != NULL)) {
+          if (*NumOfMatchGuid == 0) {
+            *Offset = malloc (sizeof (UINTN) * MAX_MATCH_GUID_NUM);
+            if (*Offset == NULL) {
+              return EFI_ABORTED;
+            }
+            memset (*Offset, 0, sizeof (UINTN) * MAX_MATCH_GUID_NUM);
+          }
+          *(*Offset + *NumOfMatchGuid) = NextOffset + (RawData - (UINT8 *)Fv);
+          (*NumOfMatchGuid)++;
+        } else {
+          return EFI_SUCCESS;
+        }
+      }
+    }
+  }
+
+  if( Flag == 0 ) {
+    return EFI_ABORTED;
+  }
+  return EFI_SUCCESS;
+}
+
+/**
+  Search the VfrBin Base address.
+
+  According the known GUID gVfrArrayAttractGuid to get the base address from FFS.
+
+  @param Fv                    the Pointer to the FFS
+  @param EfiAddr               the Pointer to the EFI in FFS
+  @param Length                the length of Fv
+  @param Offset                the Pointer to the Addr (Offset)
+  @param NumOfMachingOffset    the number of Addr (Offset)
+
+  @retval EFI_SUCCESS          Get the address successfully.
+**/
+EFI_STATUS
+SearchVfrBinInFFS (
+   IN  VOID      *Fv,
+   IN  VOID      *EfiAddr,
+   IN  UINTN     Length,
+   OUT UINTN    **Offset,
+   OUT UINT8     *NumOfMachingOffset
+  )
+{
+  UINTN        Index;
+  EFI_STATUS   Status;
+  UINTN        VirOffValue;
+
+  Index       = 0;
+  Status      = EFI_SUCCESS;
+  VirOffValue = 0;
+
+  if ((Fv == NULL) || (Offset == NULL)) {
+    return EFI_ABORTED;
+  }
+  Status = GetAddressByGuid (
+             Fv,
+             &gVfrArrayAttractGuid,
+             Length,
+             Offset,
+             NumOfMachingOffset
+             );
+  if (Status != EFI_SUCCESS) {
+    return EFI_ABORTED;
+  }
+
+  while (Index < *NumOfMachingOffset) {
+    //
+    // Got the virOffset after the GUID
+    //
+    VirOffValue = *(UINTN *)((UINTN)Fv + *(*Offset + Index));
+    //
+    //Transfer the offset to the VA address. One modules may own more VfrBin address.
+    //
+    *(*Offset + Index) = (UINTN) EfiAddr + VirOffValue;
+    Index++;
+  }
+  return EFI_SUCCESS;
+}
+
+/**
+  Search the UniBin Base address.
+
+  According the known GUID gUniStrArrayAttractGuid to get the base address from FFS.
+
+  @param Fv                    the Pointer to the FFS
+  @param EfiAddr               the Pointer to the EFI in FFS
+  @param Length                the length of Fv
+  @param Offset                the Pointer to the Addr (Offset)
+
+  @retval Base address         Get the address successfully.
+**/
+EFI_STATUS
+SearchUniBinInFFS (
+   IN VOID      *Fv,
+   IN  VOID     *EfiAddr,
+   IN  UINTN    Length,
+   OUT UINTN    **Offset
+  )
+{
+  UINT8        NumOfMachingOffset;
+  EFI_STATUS   Status;
+  UINTN        VirOffValue;
+
+  NumOfMachingOffset = 0;
+  Status             = EFI_SUCCESS;
+  VirOffValue        = 0;
+
+  if ((Fv == NULL) || (Offset == NULL)) {
+    return EFI_ABORTED;
+  }
+  Status = GetAddressByGuid (
+             Fv,
+             &gUniStrArrayAttractGuid,
+             Length,
+             Offset,
+             &NumOfMachingOffset
+             );
+  if (Status != EFI_SUCCESS) {
+    return EFI_ABORTED;
+  }
+  //
+  //Transfer the offset to the VA address. There is only one UniArray in one modules.
+  //
+  if (NumOfMachingOffset == 1) {
+    VirOffValue  = *(UINTN *)((UINTN)Fv + **Offset);
+    **Offset     = (UINTN) EfiAddr + VirOffValue;
+  } else {
+    printf ("Error. Find more than 1 UniBin in FFS.\n");
+    return EFI_ABORTED;
+  }
+
+  return EFI_SUCCESS;
+}
+
+EFI_STATUS
+SearchNvStoreDatabaseInFd(
+  IN VOID     *Fv,
+  IN UINTN    length
+  )
+{
+  EFI_STATUS   Status;
+  UINTN        Offset;
+  PCD_NV_STORE_DEFAULT_BUFFER_HEADER *NvStoreHeader;
+  Status = EFI_SUCCESS;
+  Offset = 0;
+  if (Fv == NULL) {
+    printf ("The FV is NULL.");
+    return EFI_ABORTED;
+  }
+  while (Offset < (length - sizeof(PCD_NV_STORE_DEFAULT_BUFFER_HEADER))){
+    NvStoreHeader = (PCD_NV_STORE_DEFAULT_BUFFER_HEADER *)((UINT8*)Fv + Offset);
+    if (NvStoreHeader->Signature == PCD_NV_STORE_DEFAULT_BUFFER_SIGNATURE) {
+      gEfiFdInfo.ExistNvStoreDatabase = TRUE;
+      gEfiFdInfo.NvStoreDatabase = (UINT8 *) NvStoreHeader;
+      break;
+    }
+    Offset++;
+  }
+  if (Offset == (length - sizeof(PCD_NV_STORE_DEFAULT_BUFFER_HEADER)) || gEfiFdInfo.ExistNvStoreDatabase != TRUE) {
+    //printf ("Not found the PcdNvStoreDefaultValueBuffer\n");
+    return Status;
+  }
+  return Status;
+}
+
+/**
+  Get the address by Guid.
+
+  Parse the FD image, and find the GUID address.There may be some Guids matching the
+  searched Guid.
+
+  @param Fv                     the Pointer to the image.
+  @param Guid                   The Guid need to find.
+  @param Offset                 The dual Pointer to the offset.
+  @param NumOfMatchGuid         The number of matching Guid offset.
+
+  @retval EFI_SUCCESS           The Search was complete successfully
+  @return EFI_ABORTED           An error occurred
+**/
+EFI_STATUS
+GetVariableAddressByGuid (
+  IN  VOID        *Fv,
+  IN  EFI_GUID    *Guid,
+  IN  UINTN       Len,
+  OUT UINTN       **Offset,
+  OUT UINT8       *NumOfMatchGuid
+  )
+{
+  UINTN       NextOffset;
+  UINT8       Flag;
+
+  if( (Fv == NULL) || (Fv == NULL) || (Guid == NULL) ){
+    return EFI_ABORTED;
+  }
+
+  Flag            = 0;
+  NextOffset      = 0;
+
+  if (NumOfMatchGuid != NULL) {
+    *NumOfMatchGuid = 0;
+  }
+  while (GetNextOffset(Fv, Guid, Len, &NextOffset)) {
+    Flag = 1;
+    if (NumOfMatchGuid != NULL && Offset != NULL) {
+      if (*NumOfMatchGuid == 0) {
+        *Offset = malloc (sizeof (UINTN) * MAX_MATCH_GUID_NUM);
+        if (*Offset == NULL) {
+          return EFI_ABORTED;
+        }
+        memset (*Offset, 0, sizeof (UINTN) * MAX_MATCH_GUID_NUM);
+      }
+      *(*Offset + *NumOfMatchGuid) = NextOffset;
+      (*NumOfMatchGuid)++;
+    } else {
+      return EFI_SUCCESS;
+    }
+  }
+
+  if( Flag == 0 ) {
+    return EFI_ABORTED;
+  }
+  return EFI_SUCCESS;
+}
+
+/**
+  Search the EFI Variable Base address.
+
+  According the known GUID gEfiSystemNvDataFvGuid to get the base address from FFS.
+
+  @param Fv                    the Pointer to the FFS
+  @param Length                the length of Fv
+  @param Offset                the Pointer to the Addr (Offset)
+  @param NumOfMachingOffset    the number of IFR array in one FFS
+
+  @retval EFI_SUCCESS          Get the address successfully.
+  @retval EFI_ABORTED          An error occured.
+**/
+EFI_STATUS
+SearchEfiVarInFFS (
+   IN VOID      *Fv,
+   IN  UINTN     Length,
+   OUT UINTN    **Offset,
+   OUT UINT8    *NumOfMachingOffset
+  )
+{
+  EFI_STATUS   Status;
+  UINT8        Index;
+
+  Status = EFI_SUCCESS;
+  Index  = 0;
+
+  if ((Fv == NULL) || (Offset == NULL)) {
+    printf ("The FV or offset is NULL.");
+    return EFI_ABORTED;
+  }
+  Status = GetVariableAddressByGuid (
+             Fv,
+             &gEfiSystemNvDataFvGuid,
+             Length,
+             Offset,
+             NumOfMachingOffset
+             );
+  if (Status != EFI_SUCCESS) {
+    return EFI_ABORTED;
+  }
+  //
+  //Transfer the offset to the VA address.
+  //
+  while (Index < *NumOfMachingOffset) {
+    *(*Offset + Index) = (UINTN) Fv + *(*Offset + Index);
+    Index++;
+  }
+  return EFI_SUCCESS;
+}
+
+/**
+  Parse the Ffs header to get the size.
+
+  @param  InputFile             The pointer to the input file
+  @param  FvSize                The pointer to the file size
+
+  @return EFI_SUCCESS           Get the file size successfully
+**/
+EFI_STATUS
+ReadFfsHeader (
+  IN   FILE       *InputFile,
+  OUT  UINT32     *FvSize
+  )
+{
+  EFI_FFS_FILE_HEADER         FfsHeader;
+  EFI_FV_FILETYPE             Type;
+
+  //
+  // Check input parameters
+  //
+  if ((InputFile == NULL) || (FvSize == NULL)) {
+    return EFI_ABORTED;
+  }
+  //
+  // Read the header
+  //
+  fread (
+    &FfsHeader,
+    sizeof (EFI_FFS_FILE_HEADER),
+    1,
+    InputFile
+    );
+  Type    = FfsHeader.Type;
+
+  if (Type == EFI_FV_FILETYPE_DRIVER) {
+    *FvSize = *(UINT32 *)FfsHeader.Size & 0xffffff;
+  } else if (Type == EFI_FV_FILETYPE_APPLICATION) {
+    *FvSize = *(UINT32 *)FfsHeader.Size & 0xffffff;
+  } else if (Type == EFI_FV_FILETYPE_FREEFORM) {
+    *FvSize = *(UINT32 *)FfsHeader.Size & 0xffffff;
+  } else {
+    return EFI_ABORTED;
+  }
+  return EFI_SUCCESS;
+}
+
+/*
+  Read the length of the whole FD
+
+  This function determines the size of the FV.
+
+  @param   InputFile        The file that contains the FV image.
+  @param   FvSize           The size of the FV.
+
+  @retval  EFI_SUCCESS      The application exited normally.
+  @retval  EFI_ABORTED      An error occurred.
+
+**/
+static
+EFI_STATUS
+ReadFdHeader (
+  IN FILE       *InputFile,
+  OUT UINT32    *FvSize
+  )
+{
+  //
+  // Check input parameters
+  //
+  if ((InputFile == NULL) || (FvSize == NULL)) {
+    return EFI_ABORTED;
+  }
+  *FvSize = 0;
+  //
+  // Get the total size of FD file (Fixed the length)
+  //
+  fseek(InputFile,0,SEEK_END);
+  *FvSize = ftell(InputFile);
+  fseek(InputFile,0,SEEK_SET);
+
+  if (*FvSize == 0) {
+    return EFI_ABORTED;
+  }
+  return EFI_SUCCESS;
+}
+
+/**
+  Read the file to memory.
+
+  @param   InputFile        The file that contains the FV image.
+  @param   Size             The size of the file.
+
+  @retval The pointer to the begining position of memory.
+**/
+VOID *
+ReadFileToMemory (
+  IN CHAR8      *FileName,
+  OUT UINT32    *Size
+  )
+{
+  FILE                          *InFile;
+  VOID                          *Address;
+  UINT32                        BytesRead;
+  EFI_STATUS                    Status;
+
+  InFile          = NULL;
+  Address         = NULL;
+  BytesRead       = 0;
+  Status          = EFI_SUCCESS;
+
+  InFile = fopen (FileName,"rb");
+  if (InFile == NULL) {
+    return NULL;
+  }
+  //
+  // Determine the size of FV
+  //
+  Status = ReadFdHeader (InFile, Size);
+  if (Status != EFI_SUCCESS) {
+    fclose (InFile);
+    return NULL;
+  }
+  //
+  // Allocate a buffer for the FV image
+  //
+  Address = malloc (*Size);
+  if (Address == NULL) {
+    fclose (InFile);
+    return NULL;
+  }
+  memset (Address, 0, *Size);
+  //
+  // Seek to the start of the image, then read the entire FV to the buffer
+  //
+  fseek (InFile, 0, SEEK_SET);
+  BytesRead = fread (Address, 1, *Size, InFile);
+  fclose (InFile);
+  if ((UINTN) BytesRead != *Size) {
+    free (Address);
+    return NULL;
+  }
+  return Address;
+}
+
+/**
+  Search the EFI variables address in Fd.
+
+  Open and read the *.fd to the memory, initialize the global structure.
+  Update the EFI variables addr and the begining position of memory.
+
+  @retval EFI_SUCCESS          Get the address successfully.
+**/
+EFI_STATUS
+GetEfiVariablesAddr (
+  BOOLEAN UqiIsSet
+  )
+{
+  VOID                          *FdImage;
+  UINT32                        FdSize;
+  EFI_STATUS                    Status;
+  UINTN                         *EfiVarAddr;
+  UINT8                         NumOfMachingVar;
+  UINT32                        Index;
+  BOOLEAN                       GotFlag;
+  EFI_FIRMWARE_VOLUME_HEADER    *Variable;
+  BOOLEAN                       AuthencitatedMonotonicOrNot;
+  BOOLEAN                       AuthencitatedBasedTimeOrNot;
+  BOOLEAN                       NormalOrNot;
+
+  FdImage         = NULL;
+  FdSize          = 0;
+  Status          = EFI_SUCCESS;
+  EfiVarAddr      = NULL;
+  NumOfMachingVar = 0;
+  Index           = 0;
+  GotFlag         = TRUE;
+  Variable        = NULL;
+
+  FdImage = ReadFileToMemory (mInputFdName, &FdSize);
+  if (FdImage == NULL) {
+    return EFI_ABORTED;
+  }
+  if (!UqiIsSet) {
+    Status = SearchNvStoreDatabaseInFd(FdImage, FdSize);
+    if (EFI_ERROR (Status)) {
+      return EFI_ABORTED;
+    }
+  }
+  Status = SearchEfiVarInFFS (
+             FdImage,
+             FdSize,
+             &EfiVarAddr,
+             &NumOfMachingVar
+             );
+  if (EFI_ERROR (Status)) {
+    return EFI_ABORTED;
+  }
+  //
+  // Check the signature "_FVH"
+  //
+  Index       = 0;
+  GotFlag     = FALSE;
+
+  while (Index < NumOfMachingVar) {
+    Variable = (EFI_FIRMWARE_VOLUME_HEADER *)(*(EfiVarAddr + Index) - 0x20);
+    if (Variable->Signature == 0x4856465F) {
+      AuthencitatedMonotonicOrNot  = CheckMonotonicBasedVarStore ((UINT8 *)Variable + Variable->HeaderLength);
+      AuthencitatedBasedTimeOrNot  = CheckTimeBasedVarStoreOrNot ((UINT8 *)Variable + Variable->HeaderLength);
+      NormalOrNot                  = CheckNormalVarStoreOrNot ((UINT8 *)Variable + Variable->HeaderLength);
+      if (AuthencitatedMonotonicOrNot || AuthencitatedBasedTimeOrNot || NormalOrNot) {
+        GotFlag = TRUE;
+        gEfiFdInfo.EfiVariableAddr = (UINTN)Variable;
+        break;
+      }
+    }
+    Index++;
+  }
+  free (EfiVarAddr);
+  if (!GotFlag) {
+    return EFI_ABORTED;
+  }
+  gEfiFdInfo.Fd              = FdImage;
+  gEfiFdInfo.FdSize          = FdSize;
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Pick up the FFS which includes IFR section.
+
+  Parse all FFS extracted by BfmLib, and save all which includes IFR
+  Binary to gEfiFdInfo structure.
+
+  @retval EFI_SUCCESS          Get the address successfully.
+  @retval EFI_BUFFER_TOO_SMALL Memory can't be allocated.
+  @retval EFI_ABORTED          Read FFS Failed.
+**/
+EFI_STATUS
+FindFileInFolder (
+  IN   CHAR8    *FolderName,
+  OUT  BOOLEAN  *ExistStorageInBfv,
+  OUT  BOOLEAN  *SizeOptimized
+)
+{
+  CHAR8           *FileName;
+  CHAR8           *CurFolderName;
+  EFI_STATUS      Status;
+  UINTN           MaxFileNameLen;
+  UINTN           Index;
+  CHAR8           FileNameArry[MAX_FILENAME_LEN];
+  FILE            *FfsFile;
+  UINTN           FileSize;
+  VOID            *FfsImage;
+  UINTN           BytesRead;
+#ifndef __GNUC__
+  HANDLE          FindHandle;
+  WIN32_FIND_DATA FindFileData;
+#else
+  struct dirent *pDirent;
+  DIR *pDir;
+#endif
+
+  FileName       = NULL;
+  CurFolderName  = NULL;
+  Status         = EFI_SUCCESS;
+  MaxFileNameLen = 0;
+  Index          = 0;
+  FileSize       = 0;
+  BytesRead      = 0;
+  FfsImage       = NULL;
+  FfsFile        = NULL;
+
+  MaxFileNameLen = strlen (FolderName) + MAX_FILENAME_LEN;
+  CurFolderName  = (CHAR8 *)calloc(
+                     strlen (FolderName) + strlen (OS_SEP_STR) + strlen ("*.*")+ 1,
+                     sizeof(CHAR8)
+                     );
+  if (CurFolderName == NULL) {
+    return EFI_BUFFER_TOO_SMALL;
+  }
+  strcpy (CurFolderName, FolderName);
+  strcat (CurFolderName, OS_SEP_STR);
+  strcat (CurFolderName, "*.*");
+  FileName = (CHAR8 *)calloc(
+               MaxFileNameLen,
+               sizeof(CHAR8)
+               );
+  if (FileName == NULL) {
+    free (CurFolderName);
+    return EFI_BUFFER_TOO_SMALL;
+  }
+
+#ifndef __GNUC__
+  if((FindHandle = FindFirstFile(CurFolderName, &FindFileData)) != INVALID_HANDLE_VALUE){
+    do {
+      memset (FileName, 0, MaxFileNameLen);
+      if ((strcmp (FindFileData.cFileName, ".") == 0)
+      || (strcmp (FindFileData.cFileName, "..") == 0)
+      ) {
+        continue;
+      }
+      if (strlen(FolderName) + strlen ("\\") + strlen (FindFileData.cFileName) > MAX_FILENAME_LEN - 1) {
+        Status = EFI_ABORTED;
+        goto Done;
+      }
+      snprintf (FileNameArry, MAX_FILENAME_LEN, "%s%c%s", FolderName, OS_SEP, FindFileData.cFileName);
+      FfsFile = fopen (FileNameArry, "rb");
+      if (FfsFile == NULL) {
+        Status = EFI_ABORTED;
+        goto Done;
+      }
+      Status = ReadFfsHeader (FfsFile, (UINT32 *)&FileSize);
+      if (EFI_ERROR (Status)) {
+        fclose (FfsFile);
+        Status  = EFI_SUCCESS;
+        continue;
+      }
+      //
+      // Allocate a buffer for the FFS file
+      //
+      FfsImage = malloc (FileSize);
+      if (FfsImage == NULL) {
+        fclose (FfsFile);
+        Status = EFI_BUFFER_TOO_SMALL;
+        goto Done;
+      }
+      //
+      // Seek to the start of the image, then read the entire FV to the buffer
+      //
+      fseek (FfsFile, 0, SEEK_SET);
+      BytesRead = fread (FfsImage, 1, FileSize, FfsFile);
+      fclose (FfsFile);
+
+      if ((UINTN) BytesRead != FileSize) {
+        free (FfsImage);
+        Status = EFI_ABORTED;
+        goto Done;
+      }
+      //
+      // Check whether exists the storage ffs in BFV for multi-platform mode
+      //
+      if (CompareGuid(&gEfiFfsBfvForMultiPlatformGuid,(EFI_GUID *) FfsImage) == 0) {
+        *ExistStorageInBfv            = TRUE;
+      *SizeOptimized                = FALSE;
+        gEfiFdInfo.StorageFfsInBfv    = FfsImage;
+        continue;
+      }
+    //
+      // Check whether exists the optimized storage ffs in BFV for multi-platform mode
+      //
+      if (CompareGuid(&gEfiFfsBfvForMultiPlatformGuid2,(EFI_GUID *) FfsImage) == 0) {
+        *ExistStorageInBfv            = TRUE;
+    *SizeOptimized                = TRUE;
+        gEfiFdInfo.StorageFfsInBfv    = FfsImage;
+        continue;
+      }
+      //
+      // Check whether current FFS includes IFR
+      //
+      Status = GetAddressByGuid (
+                 FfsImage,
+                 &gVfrArrayAttractGuid,
+                 FileSize,
+                 NULL,
+                 NULL
+                );
+      if (EFI_ERROR (Status)) {
+        free (FfsImage);
+        Status  = EFI_SUCCESS;
+      } else {
+       //
+       // Check whether existed same IFR binary. If existed, not insert the new one.
+       //
+       if (NotExistSameFfsIfr (FfsImage)) {
+         gEfiFdInfo.FfsArray[Index] = FfsImage;
+         gEfiFdInfo.Length[Index++] = FileSize;
+       }
+      }
+
+    } while (FindNextFile (FindHandle, &FindFileData));
+    FindClose(FindHandle);
+  } else {
+    Status = EFI_ABORTED;
+    goto Done;
+  }
+
+Done:
+  free (CurFolderName);
+  free (FileName);
+
+#else
+  if((pDir = opendir(FolderName)) != NULL){
+    while ((pDirent = readdir(pDir)) != NULL){
+      memset (FileName, 0, MaxFileNameLen);
+      if ((strcmp (pDirent->d_name, ".") == 0)
+      || (strcmp (pDirent->d_name, "..") == 0)
+      ) {
+        continue;
+      }
+      sprintf (FileNameArry, "%s%c%s", FolderName, OS_SEP, pDirent->d_name);
+      FfsFile = fopen (FileNameArry, "rb");
+      Status = ReadFfsHeader (FfsFile, (UINT32 *)&FileSize);
+      if (EFI_ERROR (Status)) {
+        fclose (FfsFile);
+        Status  = EFI_SUCCESS;
+        continue;
+      }
+      //
+      // Allocate a buffer for the FFS file
+      //
+      FfsImage = malloc (FileSize);
+      if (FfsImage == NULL) {
+        fclose (FfsFile);
+        Status = EFI_BUFFER_TOO_SMALL;
+        goto Done;
+      }
+      //
+      // Seek to the start of the image, then read the entire FV to the buffer
+      //
+      fseek (FfsFile, 0, SEEK_SET);
+      BytesRead = fread (FfsImage, 1, FileSize, FfsFile);
+      fclose (FfsFile);
+
+      if ((UINTN) BytesRead != FileSize) {
+        free (FfsImage);
+        Status = EFI_ABORTED;
+        goto Done;
+      }
+      //
+      // Check whether exists the storage ffs in BFV for multi-platform mode
+      //
+      if (CompareGuid(&gEfiFfsBfvForMultiPlatformGuid,(EFI_GUID *) FfsImage) == 0) {
+        *ExistStorageInBfv            = TRUE;
+        *SizeOptimized                = FALSE;
+        gEfiFdInfo.StorageFfsInBfv    = FfsImage;
+        continue;
+      }
+      //
+      // Check whether exists the optimized storage ffs in BFV for multi-platform mode
+      //
+      if (CompareGuid(&gEfiFfsBfvForMultiPlatformGuid2,(EFI_GUID *) FfsImage) == 0) {
+        *ExistStorageInBfv            = TRUE;
+        *SizeOptimized                = TRUE;
+        gEfiFdInfo.StorageFfsInBfv    = FfsImage;
+        continue;
+      }
+      //
+      // Check whether current FFS includes IFR
+      //
+      Status = GetAddressByGuid (
+                 FfsImage,
+                 &gVfrArrayAttractGuid,
+                 FileSize,
+                 NULL,
+                 NULL
+                );
+      if (EFI_ERROR (Status)) {
+        free (FfsImage);
+        Status  = EFI_SUCCESS;
+      } else {
+       //
+       // Check whether existed same IFR binary. If existed, not insert the new one.
+       //
+       if (NotExistSameFfsIfr (FfsImage)) {
+         gEfiFdInfo.FfsArray[Index] = FfsImage;
+         gEfiFdInfo.Length[Index++] = FileSize;
+       }
+      }
+
+    }
+    closedir(pDir);
+  } else {
+    Status = EFI_ABORTED;
+    goto Done;
+  }
+
+Done:
+  free (CurFolderName);
+  free (FileName);
+#endif
+  return Status;
+}
+
diff --git a/Platform/Intel/Tools/FCE/BinaryParse.h b/Platform/Intel/Tools/FCE/BinaryParse.h
new file mode 100644
index 0000000000..a3995b8b79
--- /dev/null
+++ b/Platform/Intel/Tools/FCE/BinaryParse.h
@@ -0,0 +1,187 @@
+/** @file
+
+ The API to parse the binary.
+
+ Copyright (c) 2011-2019, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+#ifndef _BINARY_PARSE_H_
+#define _BINARY_PARSE_H_ 1
+
+#include <FvLib.h>
+#include "Compress.h"
+#include "Decompress.h"
+#include "CommonLib.h"
+#include "EfiUtilityMsgs.h"
+#include "FirmwareVolumeBufferLib.h"
+#include "OsPath.h"
+#include "ParseGuidedSectionTools.h"
+#include "StringFuncs.h"
+#include "ParseInf.h"
+#include <Common/UefiBaseTypes.h>
+#include <Common/UefiInternalFormRepresentation.h>
+#include <Common/UefiCapsule.h>
+#include <Common/PiFirmwareFile.h>
+#include <Common/PiFirmwareVolume.h>
+#include <Guid/PiFirmwareFileSystem.h>
+#include <IndustryStandard/PeImage.h>
+#include <Protocol/GuidedSectionExtraction.h>
+
+#ifdef __GNUC__
+#define OS_SEP        '/'
+#define OS_SEP_STR    "/"
+#else
+#define OS_SEP        '\\'
+#define OS_SEP_STR    "\\"
+#endif
+
+#if defined(_MSC_VER) && _MSC_VER < 1900
+#define snprintf _snprintf
+#endif
+
+#define TEMP_DIR_NAME                  "Temp"
+#define MAX_FILENAME_LEN               200
+#define MAX_MATCH_GUID_NUM             100
+#define MAX_EFI_IN_FFS_NUM             100
+
+typedef struct {
+  VOID       *Fd;
+  UINT32     FdSize;
+  UINTN      EfiVariableAddr;
+  UINTN      Length[MAX_EFI_IN_FFS_NUM];
+  VOID      *FfsArray[MAX_EFI_IN_FFS_NUM];
+  VOID      *StorageFfsInBfv;
+  VOID      *NvStoreDatabase;
+  BOOLEAN   ExistNvStoreDatabase;
+} G_EFI_FD_INFO;
+
+///
+///Define the structure for th sections
+///
+typedef struct {
+  UINTN      BufferBase;
+  UINTN      UncompressedBuffer[MAX_EFI_IN_FFS_NUM];
+  UINTN      Length;
+  UINT8      UnCompressIndex;
+} EFI_SECTION_STRUCT;
+
+// {d0bc7cb4-6a47-495f-aa11-710746da06a2}
+#define EFI_VFR_ATTRACT_GUID \
+{ 0xd0bc7cb4, 0x6a47, 0x495f, { 0xaa, 0x11, 0x71, 0x7, 0x46, 0xda, 0x6, 0xa2 } }
+
+// {8913C5E0-33F6-4d86-9BF1-43EF89FC0666}
+#define EFI_UNI_STR_ATTRACT_GUID \
+{ 0x8913c5e0, 0x33f6, 0x4d86, { 0x9b, 0xf1, 0x43, 0xef, 0x89, 0xfc, 0x6, 0x66 } }
+
+// {FFF12B8D-7696-4C8B-A985-2747075B4F50}
+#define EFI_SYSTEM_NVDATA_FV_GUID  \
+{ 0xFFF12B8D, 0x7696, 0x4C8B, { 0xA9, 0x85, 0x27, 0x47, 0x07, 0x5B, 0x4F, 0x50 }}
+
+/**
+  Parses FFS Sections, and remove the FFS headers. Tis function olny handle one efi in this FFS.
+
+  @param  SectionBuffer     The section base address
+  @param  BufferLength      The length of FFS.
+  @param  EfiBufferHeader   The structure dual pointer to the efi informations
+
+  @retval  EFI_SUCCESS      The application exited normally.
+  @retval  EFI_ABORTED       An error occurred.
+
+**/
+EFI_STATUS
+ParseSection (
+  IN      BOOLEAN              IsFfsOrEfi,
+  IN OUT  UINT8                *SectionBuffer,
+  IN      UINT32               BufferLength,
+  IN OUT  EFI_SECTION_STRUCT   **EfiBufferHeader
+  );
+
+/**
+  Search the VfrBin Base address.
+
+  According the known GUID gVfrArrayAttractGuid to get the base address from FFS.
+
+  @param Fv                    the Pointer to the FFS
+  @param EfiAddr               the Pointer to the EFI in FFS
+  @param Length                the length of Fv
+  @param Offset                the Pointer to the Addr (Offset)
+  @param NumOfMachingOffset    the number of Addr (Offset)
+
+  @retval EFI_SUCCESS          Get the address successfully.
+**/
+EFI_STATUS
+SearchVfrBinInFFS (
+   IN  VOID      *Fv,
+   IN  VOID      *EfiAddr,
+   IN  UINTN     Length,
+   OUT UINTN    **Offset,
+   OUT UINT8     *NumOfMachingOffset
+  );
+
+/**
+  Search the UniBin Base address.
+
+  According the known GUID gUniStrArrayAttractGuid to get the base address from FFS.
+
+  @param Fv                    the Pointer to the FFS
+  @param EfiAddr               the Pointer to the EFI in FFS
+  @param Length                the length of Fv
+  @param Offset                the Pointer to the Addr (Offset)
+
+  @retval Base address         Get the address successfully.
+**/
+EFI_STATUS
+SearchUniBinInFFS (
+   IN VOID      *Fv,
+   IN  VOID     *EfiAddr,
+   IN  UINTN    Length,
+   OUT UINTN    **Offset
+  );
+
+/**
+  Read the file to memory.
+
+  @param   InputFile        The file that contains the FV image.
+  @param   Size             The size of the file.
+
+  @retval The pointer to the begining position of memory.
+**/
+VOID *
+ReadFileToMemory (
+  IN CHAR8      *FileName,
+  OUT UINT32    *Size
+  );
+
+/**
+  Search the EFI variables address in Fd.
+
+  Open and read the *.fd to the memory, initialize the global structure.
+  Update the EFI variables addr and the begining position of memory.
+
+  @retval EFI_SUCCESS          Get the address successfully.
+**/
+EFI_STATUS
+GetEfiVariablesAddr (
+  BOOLEAN UqiIsSet
+  );
+
+/**
+  Pick up the FFS which includes IFR section.
+
+  Parse all FFS extracted by BfmLib, and save all which includes IFR
+  Binary to gEfiFdInfo structure.
+
+  @retval EFI_SUCCESS          Get the address successfully.
+  @retval EFI_BUFFER_TOO_SMALL Memory can't be allocated.
+  @retval EFI_ABORTED          Read FFS Failed.
+**/
+EFI_STATUS
+FindFileInFolder (
+  IN   CHAR8    *FolderName,
+  OUT  BOOLEAN  *ExistStorageInBfv,
+  OUT  BOOLEAN  *SizeOptimized
+);
+
+#endif
+
diff --git a/Platform/Intel/Tools/FCE/Common.c b/Platform/Intel/Tools/FCE/Common.c
new file mode 100644
index 0000000000..9b14a24a9b
--- /dev/null
+++ b/Platform/Intel/Tools/FCE/Common.c
@@ -0,0 +1,2183 @@
+/** @file
+
+ Common library.
+
+ Copyright (c) 2011-2019, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+#include "Common.h"
+
+#define WARNING_STATUS_NUMBER         4
+#define ERROR_STATUS_NUMBER           24
+
+CONST CHAR8 mHexStr[] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
+
+CONST CHAR8 *mStatusString[] = {
+  "Success",                      //  RETURN_SUCCESS                = 0
+  "Warning Unknown Glyph",        //  RETURN_WARN_UNKNOWN_GLYPH     = 1
+  "Warning Delete Failure",       //  RETURN_WARN_DELETE_FAILURE    = 2
+  "Warning Write Failure",        //  RETURN_WARN_WRITE_FAILURE     = 3
+  "Warning Buffer Too Small",     //  RETURN_WARN_BUFFER_TOO_SMALL  = 4
+  "Load Error",                   //  RETURN_LOAD_ERROR             = 1  | MAX_BIT
+  "Invalid Parameter",            //  RETURN_INVALID_PARAMETER      = 2  | MAX_BIT
+  "Unsupported",                  //  RETURN_UNSUPPORTED            = 3  | MAX_BIT
+  "Bad Buffer Size",              //  RETURN_BAD_BUFFER_SIZE        = 4  | MAX_BIT
+  "Buffer Too Small",             //  RETURN_BUFFER_TOO_SMALL,      = 5  | MAX_BIT
+  "Not Ready",                    //  RETURN_NOT_READY              = 6  | MAX_BIT
+  "Device Error",                 //  RETURN_DEVICE_ERROR           = 7  | MAX_BIT
+  "Write Protected",              //  RETURN_WRITE_PROTECTED        = 8  | MAX_BIT
+  "Out of Resources",             //  RETURN_OUT_OF_RESOURCES       = 9  | MAX_BIT
+  "Volume Corrupt",               //  RETURN_VOLUME_CORRUPTED       = 10 | MAX_BIT
+  "Volume Full",                  //  RETURN_VOLUME_FULL            = 11 | MAX_BIT
+  "No Media",                     //  RETURN_NO_MEDIA               = 12 | MAX_BIT
+  "Media changed",                //  RETURN_MEDIA_CHANGED          = 13 | MAX_BIT
+  "Not Found",                    //  RETURN_NOT_FOUND              = 14 | MAX_BIT
+  "Access Denied",                //  RETURN_ACCESS_DENIED          = 15 | MAX_BIT
+  "No Response",                  //  RETURN_NO_RESPONSE            = 16 | MAX_BIT
+  "No mapping",                   //  RETURN_NO_MAPPING             = 17 | MAX_BIT
+  "Time out",                     //  RETURN_TIMEOUT                = 18 | MAX_BIT
+  "Not started",                  //  RETURN_NOT_STARTED            = 19 | MAX_BIT
+  "Already started",              //  RETURN_ALREADY_STARTED        = 20 | MAX_BIT
+  "Aborted",                      //  RETURN_ABORTED                = 21 | MAX_BIT
+  "ICMP Error",                   //  RETURN_ICMP_ERROR             = 22 | MAX_BIT
+  "TFTP Error",                   //  RETURN_TFTP_ERROR             = 23 | MAX_BIT
+  "Protocol Error"                //  RETURN_PROTOCOL_ERROR         = 24 | MAX_BIT
+};
+
+/**
+  Copies one Null-terminated Unicode string to another Null-terminated Unicode
+  string and returns the new Unicode string.
+
+  This function copies the contents of the Unicode string Source to the Unicode
+  string Destination, and returns Destination. If Source and Destination
+  overlap, then the results are undefined.
+
+  If Destination is NULL, then return NULL.
+  If Destination is not aligned on a 16-bit boundary, then return NULL.
+
+  @param  Destination A pointer to a Null-terminated Unicode string.
+  @param  Source      A pointer to a Null-terminated Unicode string.
+
+  @return Destination.
+
+**/
+CHAR16 *
+StrCpy (
+  OUT     CHAR16                    *Destination,
+  IN      CONST CHAR16              *Source
+  )
+{
+  CHAR16                            *ReturnValue;
+
+  ReturnValue = NULL;
+
+  if ((Destination == NULL) || ((UINTN) Destination % 2 != 0)) {
+    return NULL;
+  }
+
+  ReturnValue = Destination;
+  while (*Source != 0) {
+    *(Destination++) = *(Source++);
+  }
+  *Destination = 0;
+  return ReturnValue;
+}
+
+/**
+  Returns the length of a Null-terminated Unicode string.
+
+  This function returns the number of Unicode characters in the Null-terminated
+  Unicode string specified by String.
+
+  If String is NULL, then return 0.
+
+  @param  String  A pointer to a Null-terminated Unicode string.
+
+  @return The length of String.
+
+**/
+UINTN
+FceStrLen (
+  IN      CONST CHAR16              *String
+  )
+{
+  UINTN           Length;
+
+  if (String == NULL) {
+    return 0;
+  }
+  for (Length = 0; *String != L'\0'; String++, Length++) {
+    ;
+  }
+  return Length;
+}
+
+/**
+  Returns the size of a Null-terminated Unicode string in bytes, including the
+  Null terminator.
+
+  This function returns the size, in bytes, of the Null-terminated Unicode string
+  specified by String.
+
+  If String is NULL, then ASSERT().
+  If String is not aligned on a 16-bit boundary, then ASSERT().
+  If PcdMaximumUnicodeStringLength is not zero, and String contains more than
+  PcdMaximumUnicodeStringLength Unicode characters, not including the
+  Null-terminator, then ASSERT().
+
+  @param  String  A pointer to a Null-terminated Unicode string.
+
+  @return The size of String.
+
+**/
+UINTN
+FceStrSize (
+  IN      CONST CHAR16              *String
+  )
+{
+  return (FceStrLen (String) + 1) * sizeof (*String);
+}
+
+/**
+  Compares two Null-terminated Unicode strings, and returns the difference
+  between the first mismatched Unicode characters.
+
+  This function compares the Null-terminated Unicode string FirstString to the
+  Null-terminated Unicode string SecondString. If FirstString is identical to
+  SecondString, then 0 is returned. Otherwise, the value returned is the first
+  mismatched Unicode character in SecondString subtracted from the first
+  mismatched Unicode character in FirstString.
+
+  @param  FirstString   A pointer to a Null-terminated Unicode string.
+  @param  SecondString  A pointer to a Null-terminated Unicode string.
+
+  @retval 0      FirstString is identical to SecondString.
+  @return others FirstString is not identical to SecondString.
+
+**/
+INTN
+FceStrCmp (
+  IN      CONST CHAR16              *FirstString,
+  IN      CONST CHAR16              *SecondString
+  )
+{
+  while ((*FirstString != L'\0') && (*FirstString == *SecondString)) {
+    FirstString++;
+    SecondString++;
+  }
+  return *FirstString - *SecondString;
+}
+
+/**
+  Concatenates one Null-terminated Unicode string to another Null-terminated
+  Unicode string, and returns the concatenated Unicode string.
+
+  This function concatenates two Null-terminated Unicode strings. The contents
+  of Null-terminated Unicode string Source are concatenated to the end of
+  Null-terminated Unicode string Destination. The Null-terminated concatenated
+  Unicode String is returned. If Source and Destination overlap, then the
+  results are undefined.
+
+  If Destination is NULL, then ASSERT().
+  If Destination is not aligned on a 16-bit boundary, then ASSERT().
+  If Source is NULL, then ASSERT().
+  If Source is not aligned on a 16-bit boundary, then ASSERT().
+  If Source and Destination overlap, then ASSERT().
+  If PcdMaximumUnicodeStringLength is not zero, and Destination contains more
+  than PcdMaximumUnicodeStringLength Unicode characters, not including the
+  Null-terminator, then ASSERT().
+  If PcdMaximumUnicodeStringLength is not zero, and Source contains more than
+  PcdMaximumUnicodeStringLength Unicode characters, not including the
+  Null-terminator, then ASSERT().
+  If PcdMaximumUnicodeStringLength is not zero, and concatenating Destination
+  and Source results in a Unicode string with more than
+  PcdMaximumUnicodeStringLength Unicode characters, not including the
+  Null-terminator, then ASSERT().
+
+  @param  Destination A pointer to a Null-terminated Unicode string.
+  @param  Source      A pointer to a Null-terminated Unicode string.
+
+  @return Destination.
+
+**/
+CHAR16 *
+StrCat (
+  IN OUT  CHAR16                    *Destination,
+  IN      CONST CHAR16              *Source
+  )
+{
+  StrCpy (Destination + FceStrLen (Destination), Source);
+
+  //
+  // Size of the resulting string should never be zero.
+  // PcdMaximumUnicodeStringLength is tested inside FceStrLen().
+  //
+  ASSERT (FceStrSize (Destination) != 0);
+  return Destination;
+}
+
+/**
+  Returns the first occurrence of a Null-terminated Unicode sub-string
+  in a Null-terminated Unicode string.
+
+  This function scans the contents of the Null-terminated Unicode string
+  specified by String and returns the first occurrence of SearchString.
+  If SearchString is not found in String, then NULL is returned.  If
+  the length of SearchString is zero, then String is
+  returned.
+
+  If String is NULL, then ASSERT().
+  If String is not aligned on a 16-bit boundary, then ASSERT().
+  If SearchString is NULL, then ASSERT().
+  If SearchString is not aligned on a 16-bit boundary, then ASSERT().
+
+  If PcdMaximumUnicodeStringLength is not zero, and SearchString
+  or String contains more than PcdMaximumUnicodeStringLength Unicode
+  characters, not including the Null-terminator, then ASSERT().
+
+  @param  String          A pointer to a Null-terminated Unicode string.
+  @param  SearchString    A pointer to a Null-terminated Unicode string to search for.
+
+  @retval NULL            If the SearchString does not appear in String.
+  @return others          If there is a match.
+
+**/
+CHAR16 *
+StrStr (
+  IN      CONST CHAR16              *String,
+  IN      CONST CHAR16              *SearchString
+  )
+{
+  CONST CHAR16 *FirstMatch;
+  CONST CHAR16 *SearchStringTmp;
+
+  //
+  // ASSERT both strings are less long than PcdMaximumUnicodeStringLength.
+  // Length tests are performed inside FceStrLen().
+  //
+  ASSERT (FceStrSize (String) != 0);
+  ASSERT (FceStrSize (SearchString) != 0);
+
+  if (*SearchString == L'\0') {
+    return (CHAR16 *) String;
+  }
+
+  while (*String != L'\0') {
+    SearchStringTmp = SearchString;
+    FirstMatch = String;
+
+    while ((*String == *SearchStringTmp)
+            && (*String != L'\0')) {
+      String++;
+      SearchStringTmp++;
+    }
+
+    if (*SearchStringTmp == L'\0') {
+      return (CHAR16 *) FirstMatch;
+    }
+
+    if (*String == L'\0') {
+      return NULL;
+    }
+
+    String = FirstMatch + 1;
+  }
+
+  return NULL;
+}
+
+/**
+  Convert one Null-terminated ASCII string to a Null-terminated
+  Unicode string and returns the Unicode string.
+
+  This function converts the contents of the ASCII string Source to the Unicode
+  string Destination, and returns Destination.  The function terminates the
+  Unicode string Destination by appending a Null-terminator character at the end.
+  The caller is responsible to make sure Destination points to a buffer with size
+  equal or greater than ((AsciiStrLen (Source) + 1) * sizeof (CHAR16)) in bytes.
+
+  @param  Source        A pointer to a Null-terminated ASCII string.
+  @param  Destination   A pointer to a Null-terminated Unicode string.
+
+  @return Destination.
+  @return NULL          If Destination or Source is NULL, return NULL.
+
+**/
+CHAR16 *
+AsciiStrToUnicodeStr (
+  IN      CONST CHAR8               *Source,
+  OUT     CHAR16                    *Destination
+  )
+{
+  CHAR16                            *ReturnValue;
+
+  ReturnValue = NULL;
+
+  if ((Destination == NULL) || (Source == NULL) || (strlen (Source) == 0)) {
+    return NULL;
+  }
+  ReturnValue = Destination;
+  while (*Source != '\0') {
+    *(Destination++) = (CHAR16) *(Source++);
+  }
+  //
+  // End the Destination with a NULL.
+  //
+  *Destination = '\0';
+
+  return ReturnValue;
+}
+
+/**
+  Internal function that convert a number to a string in Buffer.
+
+  Print worker function that converts a decimal or hexadecimal number to an ASCII string in Buffer.
+
+  @param  Buffer    Location to place the ASCII string of Value.
+  @param  Value     The value to convert to a Decimal or Hexadecimal string in Buffer.
+  @param  Radix     Radix of the value
+
+  @return A pointer to the end of buffer filled with ASCII string.
+
+**/
+CHAR8 *
+BasePrintLibValueToString (
+  IN OUT CHAR8  *Buffer,
+  IN INT64      Value,
+  IN UINTN      Radix
+  )
+{
+  UINT32  Remainder;
+
+  //
+  // Loop to convert one digit at a time in reverse order
+  //
+  *Buffer = 0;
+  do {
+    Value = (INT64)DivU64x32Remainder ((UINT64)Value, (UINT32)Radix, &Remainder);
+    *(++Buffer) = mHexStr[Remainder];
+  } while (Value != 0);
+
+  //
+  // Return pointer of the end of filled buffer.
+  //
+  return Buffer;
+}
+
+/**
+  Reads a 16-bit value from memory that may be unaligned.
+
+  This function returns the 16-bit value pointed to by Buffer. The function
+  guarantees that the read operation does not produce an alignment fault.
+
+  If the Buffer is NULL, then ASSERT().
+
+  @param  Buffer  A pointer to a 16-bit value that may be unaligned.
+
+  @return The 16-bit value read from Buffer.
+
+**/
+UINT16
+FceReadUnaligned16 (
+  IN CONST UINT16              *Buffer
+  )
+{
+  ASSERT (Buffer != NULL);
+
+  return *Buffer;
+}
+
+/**
+  Reads a 32-bit value from memory that may be unaligned.
+
+  This function returns the 32-bit value pointed to by Buffer. The function
+  guarantees that the read operation does not produce an alignment fault.
+
+  If the Buffer is NULL, then ASSERT().
+
+  @param  Buffer  A pointer to a 32-bit value that may be unaligned.
+
+  @return The 32-bit value read from Buffer.
+
+**/
+UINT32
+ReadUnaligned32 (
+  IN CONST UINT32              *Buffer
+  )
+{
+  ASSERT (Buffer != NULL);
+
+  return *Buffer;
+}
+
+/**
+  Internal function that places the character into the Buffer.
+
+  Internal function that places ASCII or Unicode character into the Buffer.
+
+  @param  Buffer      The buffer to place the Unicode or ASCII string.
+  @param  EndBuffer   The end of the input Buffer. No characters will be
+                      placed after that.
+  @param  Length      The count of character to be placed into Buffer.
+                      (Negative value indicates no buffer fill.)
+  @param  Character   The character to be placed into Buffer.
+  @param  Increment   The character increment in Buffer.
+
+  @return Buffer.
+
+**/
+CHAR8 *
+BasePrintLibFillBuffer (
+  OUT CHAR8   *Buffer,
+  IN  CHAR8   *EndBuffer,
+  IN  INTN    Length,
+  IN  UINTN   Character,
+  IN  INTN    Increment
+  )
+{
+  INTN  Index;
+
+  for (Index = 0; Index < Length && Buffer < EndBuffer; Index++) {
+    *Buffer = (CHAR8) Character;
+    if (Increment != 1) {
+      *(Buffer + 1) = (CHAR8)(Character >> 8);
+    }
+    Buffer += Increment;
+  }
+
+  return Buffer;
+}
+
+/**
+  Worker function that produces a Null-terminated string in an output buffer
+  based on a Null-terminated format string and a VA_LIST argument list.
+
+  VSPrint function to process format and place the results in Buffer. Since a
+  VA_LIST is used this routine allows the nesting of Vararg routines. Thus
+  this is the main print working routine.
+
+  If COUNT_ONLY_NO_PRINT is set in Flags, Buffer will not be modified at all.
+
+  @param[out] Buffer          The character buffer to print the results of the
+                              parsing of Format into.
+  @param[in]  BufferSize      The maximum number of characters to put into
+                              buffer.
+  @param[in]  Flags           Initial flags value.
+                              Can only have FORMAT_UNICODE, OUTPUT_UNICODE,
+                              and COUNT_ONLY_NO_PRINT set.
+  @param[in]  Format          A Null-terminated format string.
+  @param[in]  VaListMarker    VA_LIST style variable argument list consumed by
+                              processing Format.
+  @param[in]  BaseListMarker  BASE_LIST style variable argument list consumed
+                              by processing Format.
+
+  @return The number of characters printed not including the Null-terminator.
+          If COUNT_ONLY_NO_PRINT was set returns the same, but without any
+          modification to Buffer.
+
+**/
+UINTN
+BasePrintLibSPrintMarker (
+  OUT CHAR8        *Buffer,
+  IN  UINTN        BufferSize,
+  IN  UINTN        Flags,
+  IN  CONST CHAR8  *Format,
+  IN  VA_LIST      VaListMarker,   OPTIONAL
+  IN  BASE_LIST    BaseListMarker  OPTIONAL
+  )
+{
+  CHAR8             *OriginalBuffer;
+  CHAR8             *EndBuffer;
+  CHAR8             ValueBuffer[MAXIMUM_VALUE_CHARACTERS];
+  UINT32            BytesPerOutputCharacter;
+  UINTN             BytesPerFormatCharacter;
+  UINTN             FormatMask;
+  UINTN             FormatCharacter;
+  UINTN             Width;
+  UINTN             Precision;
+  INT64             Value;
+  CONST CHAR8       *ArgumentString;
+  UINTN             Character;
+  EFI_GUID          *TmpGuid;
+  TIME              *TmpTime;
+  UINTN             Count;
+  UINTN             ArgumentMask;
+  INTN              BytesPerArgumentCharacter;
+  UINTN             ArgumentCharacter;
+  BOOLEAN           Done;
+  UINTN             Index;
+  CHAR8             Prefix;
+  BOOLEAN           ZeroPad;
+  BOOLEAN           Comma;
+  UINTN             Digits;
+  UINTN             Radix;
+  RETURN_STATUS     Status;
+  UINT32            GuidData1;
+  UINT16            GuidData2;
+  UINT16            GuidData3;
+  UINTN             LengthToReturn;
+
+  //
+  // If you change this code be sure to match the 2 versions of this function.
+  // Nearly identical logic is found in the BasePrintLib and
+  // DxePrintLibPrint2Protocol (both PrintLib instances).
+  //
+
+  if ((Flags & COUNT_ONLY_NO_PRINT) != 0) {
+    if (BufferSize == 0) {
+      Buffer = NULL;
+    }
+  } else {
+    //
+    // We can run without a Buffer for counting only.
+    //
+    if (BufferSize == 0) {
+      return 0;
+    }
+    ASSERT (Buffer != NULL);
+  }
+
+  if ((Flags & OUTPUT_UNICODE) != 0) {
+    BytesPerOutputCharacter = 2;
+  } else {
+    BytesPerOutputCharacter = 1;
+  }
+
+  LengthToReturn = 0;
+
+  //
+  // Reserve space for the Null terminator.
+  //
+  BufferSize--;
+  OriginalBuffer = Buffer;
+
+  //
+  // Set the tag for the end of the input Buffer.
+  //
+  EndBuffer      = Buffer + BufferSize * BytesPerOutputCharacter;
+
+  if ((Flags & FORMAT_UNICODE) != 0) {
+    //
+    // Make sure format string cannot contain more than PcdMaximumUnicodeStringLength
+    // Unicode characters if PcdMaximumUnicodeStringLength is not zero.
+    //
+    ASSERT (FceStrSize ((CHAR16 *) Format) != 0);
+    BytesPerFormatCharacter = 2;
+    FormatMask = 0xffff;
+  } else {
+    //
+    // Make sure format string cannot contain more than PcdMaximumAsciiStringLength
+    // Ascii characters if PcdMaximumAsciiStringLength is not zero.
+    //
+    ASSERT (strlen (Format) + 1 != 0);
+    BytesPerFormatCharacter = 1;
+    FormatMask = 0xff;
+  }
+
+  //
+  // Get the first character from the format string
+  //
+  FormatCharacter = ((*Format & 0xff) | (*(Format + 1) << 8)) & FormatMask;
+
+  //
+  // Loop until the end of the format string is reached or the output buffer is full
+  //
+  while (FormatCharacter != 0 && Buffer < EndBuffer) {
+    //
+    // Clear all the flag bits except those that may have been passed in
+    //
+    Flags &= (OUTPUT_UNICODE | FORMAT_UNICODE | COUNT_ONLY_NO_PRINT);
+
+    //
+    // Set the default width to zero, and the default precision to 1
+    //
+    Width     = 0;
+    Precision = 1;
+    Prefix    = 0;
+    Comma     = FALSE;
+    ZeroPad   = FALSE;
+    Count     = 0;
+    Digits    = 0;
+
+    switch (FormatCharacter) {
+    case '%':
+      //
+      // Parse Flags and Width
+      //
+      for (Done = FALSE; !Done; ) {
+        Format += BytesPerFormatCharacter;
+        FormatCharacter = ((*Format & 0xff) | (*(Format + 1) << 8)) & FormatMask;
+        switch (FormatCharacter) {
+        case '.':
+          Flags |= PRECISION;
+          break;
+        case '-':
+          Flags |= LEFT_JUSTIFY;
+          break;
+        case '+':
+          Flags |= PREFIX_SIGN;
+          break;
+        case ' ':
+          Flags |= PREFIX_BLANK;
+          break;
+        case ',':
+          Flags |= COMMA_TYPE;
+          break;
+        case 'L':
+        case 'l':
+          Flags |= LONG_TYPE;
+          break;
+        case '*':
+          if ((Flags & PRECISION) == 0) {
+            Flags |= PAD_TO_WIDTH;
+            if (BaseListMarker == NULL) {
+              Width = VA_ARG (VaListMarker, UINTN);
+            } else {
+              Width = BASE_ARG (BaseListMarker, UINTN);
+            }
+          } else {
+            if (BaseListMarker == NULL) {
+              Precision = VA_ARG (VaListMarker, UINTN);
+            } else {
+              Precision = BASE_ARG (BaseListMarker, UINTN);
+            }
+          }
+          break;
+        case '0':
+          if ((Flags & PRECISION) == 0) {
+            Flags |= PREFIX_ZERO;
+          }
+        case '1':
+        case '2':
+        case '3':
+        case '4':
+        case '5':
+        case '6':
+        case '7':
+        case '8':
+        case '9':
+          for (Count = 0; ((FormatCharacter >= '0') &&  (FormatCharacter <= '9')); ){
+            Count = (Count * 10) + FormatCharacter - '0';
+            Format += BytesPerFormatCharacter;
+            FormatCharacter = ((*Format & 0xff) | (*(Format + 1) << 8)) & FormatMask;
+          }
+          Format -= BytesPerFormatCharacter;
+          if ((Flags & PRECISION) == 0) {
+            Flags |= PAD_TO_WIDTH;
+            Width = Count;
+          } else {
+            Precision = Count;
+          }
+          break;
+
+        case '\0':
+          //
+          // Make no output if Format string terminates unexpectedly when
+          // looking up for flag, width, precision and type.
+          //
+          Format   -= BytesPerFormatCharacter;
+          Precision = 0;
+          //
+          // break skipped on purpose.
+          //
+        default:
+          Done = TRUE;
+          break;
+        }
+      }
+
+      //
+      // Handle each argument type
+      //
+      switch (FormatCharacter) {
+      case 'p':
+        //
+        // Flag space, +, 0, L & l are invalid for type p.
+        //
+        Flags &= ~(PREFIX_BLANK | PREFIX_SIGN | PREFIX_ZERO | LONG_TYPE);
+        if (sizeof (VOID *) > 4) {
+          Flags |= LONG_TYPE;
+        }
+      case 'X':
+        Flags |= PREFIX_ZERO;
+        //
+        // break skipped on purpose
+        //
+      case 'x':
+        Flags |= RADIX_HEX;
+        //
+        // break skipped on purpose
+        //
+      case 'd':
+        if ((Flags & LONG_TYPE) == 0) {
+          //
+          // 'd','x', and 'X' that are not preceded by 'l' or 'L' are assumed to be type "int".
+          // This assumption is made so the format string definition is compatible with the ANSI C
+          // Specification for formatted strings.  It is recommended that the Base Types be used
+          // everywhere, but in this one case, compliance with ANSI C is more important, and
+          // provides an implementation that is compatible with that largest possible set of CPU
+          // architectures.  This is why the type "int" is used in this one case.
+          //
+          if (BaseListMarker == NULL) {
+            Value = VA_ARG (VaListMarker, int);
+          } else {
+            Value = BASE_ARG (BaseListMarker, int);
+          }
+        } else {
+          if (BaseListMarker == NULL) {
+            Value = VA_ARG (VaListMarker, INT64);
+          } else {
+            Value = BASE_ARG (BaseListMarker, INT64);
+          }
+        }
+        if ((Flags & PREFIX_BLANK) != 0) {
+          Prefix = ' ';
+        }
+        if ((Flags & PREFIX_SIGN) != 0) {
+          Prefix = '+';
+        }
+        if ((Flags & COMMA_TYPE) != 0) {
+          Comma = TRUE;
+        }
+        if ((Flags & RADIX_HEX) == 0) {
+          Radix = 10;
+          if (Comma) {
+            Flags &= (~PREFIX_ZERO);
+            Precision = 1;
+          }
+          if (Value < 0) {
+            Flags |= PREFIX_SIGN;
+            Prefix = '-';
+            Value = -Value;
+          }
+        } else {
+          Radix = 16;
+          Comma = FALSE;
+          if ((Flags & LONG_TYPE) == 0 && Value < 0) {
+            //
+            // 'd','x', and 'X' that are not preceded by 'l' or 'L' are assumed to be type "int".
+            // This assumption is made so the format string definition is compatible with the ANSI C
+            // Specification for formatted strings.  It is recommended that the Base Types be used
+            // everywhere, but in this one case, compliance with ANSI C is more important, and
+            // provides an implementation that is compatible with that largest possible set of CPU
+            // architectures.  This is why the type "unsigned int" is used in this one case.
+            //
+            Value = (unsigned int)Value;
+          }
+        }
+        //
+        // Convert Value to a reversed string
+        //
+        Count = BasePrintLibValueToString (ValueBuffer, Value, Radix) - ValueBuffer;
+        if (Value == 0 && Precision == 0) {
+          Count = 0;
+        }
+        ArgumentString = (CHAR8 *)ValueBuffer + Count;
+
+        Digits = Count % 3;
+        if (Digits != 0) {
+          Digits = 3 - Digits;
+        }
+        if (Comma && Count != 0) {
+          Count += ((Count - 1) / 3);
+        }
+        if (Prefix != 0) {
+          Count++;
+          Precision++;
+        }
+        Flags |= ARGUMENT_REVERSED;
+        ZeroPad = TRUE;
+        if ((Flags & PREFIX_ZERO) != 0) {
+          if ((Flags & LEFT_JUSTIFY) == 0) {
+            if ((Flags & PAD_TO_WIDTH) != 0) {
+              if ((Flags & PRECISION) == 0) {
+                Precision = Width;
+              }
+            }
+          }
+        }
+        break;
+
+      case 's':
+      case 'S':
+        Flags |= ARGUMENT_UNICODE;
+        //
+        // break skipped on purpose
+        //
+      case 'a':
+        if (BaseListMarker == NULL) {
+          ArgumentString = VA_ARG (VaListMarker, CHAR8 *);
+        } else {
+          ArgumentString = BASE_ARG (BaseListMarker, CHAR8 *);
+        }
+        if (ArgumentString == NULL) {
+          Flags &= (~ARGUMENT_UNICODE);
+          ArgumentString = "<null string>";
+        }
+        //
+        // Set the default precision for string to be zero if not specified.
+        //
+        if ((Flags & PRECISION) == 0) {
+          Precision = 0;
+        }
+        break;
+
+      case 'c':
+        if (BaseListMarker == NULL) {
+          Character = VA_ARG (VaListMarker, UINTN) & 0xffff;
+        } else {
+          Character = BASE_ARG (BaseListMarker, UINTN) & 0xffff;
+        }
+        ArgumentString = (CHAR8 *)&Character;
+        Flags |= ARGUMENT_UNICODE;
+        break;
+
+      case 'g':
+        if (BaseListMarker == NULL) {
+          TmpGuid = VA_ARG (VaListMarker, EFI_GUID *);
+        } else {
+          TmpGuid = BASE_ARG (BaseListMarker, EFI_GUID *);
+        }
+        if (TmpGuid == NULL) {
+          ArgumentString = "<null guid>";
+        } else {
+          GuidData1 = ReadUnaligned32 (&(TmpGuid->Data1));
+          GuidData2 = FceReadUnaligned16 (&(TmpGuid->Data2));
+          GuidData3 = FceReadUnaligned16 (&(TmpGuid->Data3));
+          BasePrintLibSPrint (
+            ValueBuffer,
+            MAXIMUM_VALUE_CHARACTERS,
+            0,
+            "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
+            GuidData1,
+            GuidData2,
+            GuidData3,
+            TmpGuid->Data4[0],
+            TmpGuid->Data4[1],
+            TmpGuid->Data4[2],
+            TmpGuid->Data4[3],
+            TmpGuid->Data4[4],
+            TmpGuid->Data4[5],
+            TmpGuid->Data4[6],
+            TmpGuid->Data4[7]
+            );
+          ArgumentString = ValueBuffer;
+        }
+        break;
+
+      case 't':
+        if (BaseListMarker == NULL) {
+          TmpTime = VA_ARG (VaListMarker, TIME *);
+        } else {
+          TmpTime = BASE_ARG (BaseListMarker, TIME *);
+        }
+        if (TmpTime == NULL) {
+          ArgumentString = "<null time>";
+        } else {
+          BasePrintLibSPrint (
+            ValueBuffer,
+            MAXIMUM_VALUE_CHARACTERS,
+            0,
+            "%02d/%02d/%04d  %02d:%02d",
+            TmpTime->Month,
+            TmpTime->Day,
+            TmpTime->Year,
+            TmpTime->Hour,
+            TmpTime->Minute
+            );
+          ArgumentString = ValueBuffer;
+        }
+        break;
+
+      case 'r':
+        if (BaseListMarker == NULL) {
+          Status = VA_ARG (VaListMarker, RETURN_STATUS);
+        } else {
+          Status = BASE_ARG (BaseListMarker, RETURN_STATUS);
+        }
+        ArgumentString = ValueBuffer;
+        if (RETURN_ERROR (Status)) {
+          //
+          // Clear error bit
+          //
+          Index = Status & ~MAX_BIT;
+          if (Index > 0 && Index <= ERROR_STATUS_NUMBER) {
+            ArgumentString = mStatusString [Index + WARNING_STATUS_NUMBER];
+          }
+        } else {
+          Index = Status;
+          if (Index <= WARNING_STATUS_NUMBER) {
+            ArgumentString = mStatusString [Index];
+          }
+        }
+        if (ArgumentString == ValueBuffer) {
+          BasePrintLibSPrint ((CHAR8 *) ValueBuffer, MAXIMUM_VALUE_CHARACTERS, 0, "%08X", Status);
+        }
+        break;
+
+      case '\r':
+        Format += BytesPerFormatCharacter;
+        FormatCharacter = ((*Format & 0xff) | (*(Format + 1) << 8)) & FormatMask;
+        if (FormatCharacter == '\n') {
+          //
+          // Translate '\r\n' to '\r\n'
+          //
+          ArgumentString = "\r\n";
+        } else {
+          //
+          // Translate '\r' to '\r'
+          //
+          ArgumentString = "\r";
+          Format   -= BytesPerFormatCharacter;
+        }
+        break;
+
+      case '\n':
+        //
+        // Translate '\n' to '\r\n' and '\n\r' to '\r\n'
+        //
+        ArgumentString = "\r\n";
+        Format += BytesPerFormatCharacter;
+        FormatCharacter = ((*Format & 0xff) | (*(Format + 1) << 8)) & FormatMask;
+        if (FormatCharacter != '\r') {
+          Format   -= BytesPerFormatCharacter;
+        }
+        break;
+
+      case '%':
+      default:
+        //
+        // if the type is '%' or unknown, then print it to the screen
+        //
+        ArgumentString = (CHAR8 *)&FormatCharacter;
+        Flags |= ARGUMENT_UNICODE;
+        break;
+      }
+      break;
+
+    case '\r':
+      Format += BytesPerFormatCharacter;
+      FormatCharacter = ((*Format & 0xff) | (*(Format + 1) << 8)) & FormatMask;
+      if (FormatCharacter == '\n') {
+        //
+        // Translate '\r\n' to '\r\n'
+        //
+        ArgumentString = "\r\n";
+      } else {
+        //
+        // Translate '\r' to '\r'
+        //
+        ArgumentString = "\r";
+        Format   -= BytesPerFormatCharacter;
+      }
+      break;
+
+    case '\n':
+      //
+      // Translate '\n' to '\r\n' and '\n\r' to '\r\n'
+      //
+      ArgumentString = "\r\n";
+      Format += BytesPerFormatCharacter;
+      FormatCharacter = ((*Format & 0xff) | (*(Format + 1) << 8)) & FormatMask;
+      if (FormatCharacter != '\r') {
+        Format   -= BytesPerFormatCharacter;
+      }
+      break;
+
+    default:
+      ArgumentString = (CHAR8 *)&FormatCharacter;
+      Flags |= ARGUMENT_UNICODE;
+      break;
+    }
+
+    //
+    // Retrieve the ArgumentString attriubutes
+    //
+    if ((Flags & ARGUMENT_UNICODE) != 0) {
+      ArgumentMask = 0xffff;
+      BytesPerArgumentCharacter = 2;
+    } else {
+      ArgumentMask = 0xff;
+      BytesPerArgumentCharacter = 1;
+    }
+    if ((Flags & ARGUMENT_REVERSED) != 0) {
+      BytesPerArgumentCharacter = -BytesPerArgumentCharacter;
+    } else {
+      //
+      // Compute the number of characters in ArgumentString and store it in Count
+      // ArgumentString is either null-terminated, or it contains Precision characters
+      //
+      for (Count = 0; Count < Precision || ((Flags & PRECISION) == 0); Count++) {
+        ArgumentCharacter = ((ArgumentString[Count * BytesPerArgumentCharacter] & 0xff) | ((ArgumentString[Count * BytesPerArgumentCharacter + 1]) << 8)) & ArgumentMask;
+        if (ArgumentCharacter == 0) {
+          break;
+        }
+      }
+    }
+
+    if (Precision < Count) {
+      Precision = Count;
+    }
+
+    //
+    // Pad before the string
+    //
+    if ((Flags & (PAD_TO_WIDTH | LEFT_JUSTIFY)) == (PAD_TO_WIDTH)) {
+      LengthToReturn += ((Width - Precision) * BytesPerOutputCharacter);
+      if ((Flags & COUNT_ONLY_NO_PRINT) == 0 && Buffer != NULL) {
+        Buffer = BasePrintLibFillBuffer (Buffer, EndBuffer, Width - Precision, ' ', BytesPerOutputCharacter);
+      }
+    }
+
+    if (ZeroPad) {
+      if (Prefix != 0) {
+        LengthToReturn += (1 * BytesPerOutputCharacter);
+        if ((Flags & COUNT_ONLY_NO_PRINT) == 0 && Buffer != NULL) {
+          Buffer = BasePrintLibFillBuffer (Buffer, EndBuffer, 1, Prefix, BytesPerOutputCharacter);
+        }
+      }
+      LengthToReturn += ((Precision - Count) * BytesPerOutputCharacter);
+      if ((Flags & COUNT_ONLY_NO_PRINT) == 0 && Buffer != NULL) {
+        Buffer = BasePrintLibFillBuffer (Buffer, EndBuffer, Precision - Count, '0', BytesPerOutputCharacter);
+      }
+    } else {
+      LengthToReturn += ((Precision - Count) * BytesPerOutputCharacter);
+      if ((Flags & COUNT_ONLY_NO_PRINT) == 0 && Buffer != NULL) {
+        Buffer = BasePrintLibFillBuffer (Buffer, EndBuffer, Precision - Count, ' ', BytesPerOutputCharacter);
+      }
+      if (Prefix != 0) {
+        LengthToReturn += (1 * BytesPerOutputCharacter);
+        if ((Flags & COUNT_ONLY_NO_PRINT) == 0 && Buffer != NULL) {
+          Buffer = BasePrintLibFillBuffer (Buffer, EndBuffer, 1, Prefix, BytesPerOutputCharacter);
+        }
+      }
+    }
+
+    //
+    // Output the Prefix character if it is present
+    //
+    Index = 0;
+    if (Prefix != 0) {
+      Index++;
+    }
+
+    //
+    // Copy the string into the output buffer performing the required type conversions
+    //
+    while (Index < Count) {
+      ArgumentCharacter = ((*ArgumentString & 0xff) | (*(ArgumentString + 1) << 8)) & ArgumentMask;
+
+      LengthToReturn += (1 * BytesPerOutputCharacter);
+      if ((Flags & COUNT_ONLY_NO_PRINT) == 0 && Buffer != NULL) {
+        Buffer = BasePrintLibFillBuffer (Buffer, EndBuffer, 1, ArgumentCharacter, BytesPerOutputCharacter);
+      }
+      ArgumentString    += BytesPerArgumentCharacter;
+      Index++;
+      if (Comma) {
+        Digits++;
+        if (Digits == 3) {
+          Digits = 0;
+          Index++;
+          if (Index < Count) {
+            LengthToReturn += (1 * BytesPerOutputCharacter);
+            if ((Flags & COUNT_ONLY_NO_PRINT) == 0 && Buffer != NULL) {
+              Buffer = BasePrintLibFillBuffer (Buffer, EndBuffer, 1, ',', BytesPerOutputCharacter);
+            }
+          }
+        }
+      }
+    }
+
+    //
+    // Pad after the string
+    //
+    if ((Flags & (PAD_TO_WIDTH | LEFT_JUSTIFY)) == (PAD_TO_WIDTH | LEFT_JUSTIFY)) {
+      LengthToReturn += ((Width - Precision) * BytesPerOutputCharacter);
+      if ((Flags & COUNT_ONLY_NO_PRINT) == 0 && Buffer != NULL) {
+        Buffer = BasePrintLibFillBuffer (Buffer, EndBuffer, Width - Precision, ' ', BytesPerOutputCharacter);
+      }
+    }
+
+    //
+    // Get the next character from the format string
+    //
+    Format += BytesPerFormatCharacter;
+
+    //
+    // Get the next character from the format string
+    //
+    FormatCharacter = ((*Format & 0xff) | (*(Format + 1) << 8)) & FormatMask;
+  }
+
+  if ((Flags & COUNT_ONLY_NO_PRINT) != 0) {
+    return (LengthToReturn / BytesPerOutputCharacter);
+  }
+
+  ASSERT (Buffer != NULL);
+  //
+  // Null terminate the Unicode or ASCII string
+  //
+  BasePrintLibFillBuffer (Buffer, EndBuffer + BytesPerOutputCharacter, 1, 0, BytesPerOutputCharacter);
+  //
+  // Make sure output buffer cannot contain more than PcdMaximumUnicodeStringLength
+  // Unicode characters if PcdMaximumUnicodeStringLength is not zero.
+  //
+  ASSERT ((((Flags & OUTPUT_UNICODE) == 0)) || (FceStrSize ((CHAR16 *) OriginalBuffer) != 0));
+  //
+  // Make sure output buffer cannot contain more than PcdMaximumAsciiStringLength
+  // ASCII characters if PcdMaximumAsciiStringLength is not zero.
+  //
+  ASSERT ((((Flags & OUTPUT_UNICODE) != 0)) || ((strlen (OriginalBuffer) + 1) != 0));
+
+  return ((Buffer - OriginalBuffer) / BytesPerOutputCharacter);
+}
+
+/**
+  Worker function that produces a Null-terminated string in an output buffer
+  based on a Null-terminated format string and variable argument list.
+
+  VSPrint function to process format and place the results in Buffer. Since a
+  VA_LIST is used this routine allows the nesting of Vararg routines. Thus
+  this is the main print working routine
+
+  @param  StartOfBuffer The character buffer to print the results of the parsing
+                        of Format into.
+  @param  BufferSize    The maximum number of characters to put into buffer.
+                        Zero means no limit.
+  @param  Flags         Initial flags value.
+                        Can only have FORMAT_UNICODE and OUTPUT_UNICODE set
+  @param  FormatString  A Null-terminated format string.
+  @param  ...           The variable argument list.
+
+  @return The number of characters printed.
+
+**/
+UINTN
+BasePrintLibSPrint (
+  OUT CHAR8        *StartOfBuffer,
+  IN  UINTN        BufferSize,
+  IN  UINTN        Flags,
+  IN  CONST CHAR8  *FormatString,
+  ...
+  )
+{
+  VA_LIST  Marker;
+
+  VA_START (Marker, FormatString);
+  return BasePrintLibSPrintMarker (StartOfBuffer, BufferSize, Flags, FormatString, Marker, NULL);
+}
+
+/**
+  Produces a Null-terminated Unicode string in an output buffer based on
+  a Null-terminated Unicode format string and a VA_LIST argument list
+
+  Produces a Null-terminated Unicode string in the output buffer specified by StartOfBuffer
+  and BufferSize.
+  The Unicode string is produced by parsing the format string specified by FormatString.
+  Arguments are pulled from the variable argument list specified by Marker based on the
+  contents of the format string.
+  The number of Unicode characters in the produced output buffer is returned not including
+  the Null-terminator.
+  If BufferSize is 0 or 1, then no output buffer is produced and 0 is returned.
+
+  If BufferSize > 1 and StartOfBuffer is NULL, then ASSERT().
+  If BufferSize > 1 and StartOfBuffer is not aligned on a 16-bit boundary, then ASSERT().
+  If BufferSize > 1 and FormatString is NULL, then ASSERT().
+  If BufferSize > 1 and FormatString is not aligned on a 16-bit boundary, then ASSERT().
+  If PcdMaximumUnicodeStringLength is not zero, and FormatString contains more than
+  PcdMaximumUnicodeStringLength Unicode characters not including the Null-terminator, then
+  ASSERT().
+  If PcdMaximumUnicodeStringLength is not zero, and produced Null-terminated Unicode string
+  contains more than PcdMaximumUnicodeStringLength Unicode characters not including the
+  Null-terminator, then ASSERT().
+
+  @param  StartOfBuffer   A pointer to the output buffer for the produced Null-terminated
+                          Unicode string.
+  @param  BufferSize      The size, in bytes, of the output buffer specified by StartOfBuffer.
+  @param  FormatString    A Null-terminated Unicode format string.
+  @param  Marker          VA_LIST marker for the variable argument list.
+
+  @return The number of Unicode characters in the produced output buffer not including the
+          Null-terminator.
+
+**/
+UINTN
+UnicodeVSPrint (
+  OUT CHAR16        *StartOfBuffer,
+  IN  UINTN         BufferSize,
+  IN  CONST CHAR16  *FormatString,
+  IN  VA_LIST       Marker
+  )
+{
+  ASSERT_UNICODE_BUFFER (StartOfBuffer);
+  ASSERT_UNICODE_BUFFER (FormatString);
+  return BasePrintLibSPrintMarker ((CHAR8 *)StartOfBuffer, BufferSize >> 1, FORMAT_UNICODE | OUTPUT_UNICODE, (CHAR8 *)FormatString, Marker, NULL);
+}
+
+/**
+  Produces a Null-terminated Unicode string in an output buffer based on a Null-terminated
+  Unicode format string and variable argument list.
+
+  Produces a Null-terminated Unicode string in the output buffer specified by StartOfBuffer
+  and BufferSize.
+  The Unicode string is produced by parsing the format string specified by FormatString.
+  Arguments are pulled from the variable argument list based on the contents of the format string.
+  The number of Unicode characters in the produced output buffer is returned not including
+  the Null-terminator.
+  If BufferSize is 0 or 1, then no output buffer is produced and 0 is returned.
+
+  If BufferSize > 1 and StartOfBuffer is NULL, then ASSERT().
+  If BufferSize > 1 and StartOfBuffer is not aligned on a 16-bit boundary, then ASSERT().
+  If BufferSize > 1 and FormatString is NULL, then ASSERT().
+  If BufferSize > 1 and FormatString is not aligned on a 16-bit boundary, then ASSERT().
+  If PcdMaximumUnicodeStringLength is not zero, and FormatString contains more than
+  PcdMaximumUnicodeStringLength Unicode characters not including the Null-terminator, then
+  ASSERT().
+  If PcdMaximumUnicodeStringLength is not zero, and produced Null-terminated Unicode string
+  contains more than PcdMaximumUnicodeStringLength Unicode characters not including the
+  Null-terminator, then ASSERT().
+
+  @param  StartOfBuffer   A pointer to the output buffer for the produced Null-terminated
+                          Unicode string.
+  @param  BufferSize      The size, in bytes, of the output buffer specified by StartOfBuffer.
+  @param  FormatString    A Null-terminated Unicode format string.
+  @param  ...             Variable argument list whose contents are accessed based on the
+                          format string specified by FormatString.
+
+  @return The number of Unicode characters in the produced output buffer not including the
+          Null-terminator.
+
+**/
+UINTN
+UnicodeSPrint (
+  OUT CHAR16        *StartOfBuffer,
+  IN  UINTN         BufferSize,
+  IN  CONST CHAR16  *FormatString,
+  ...
+  )
+{
+  VA_LIST Marker;
+
+  VA_START (Marker, FormatString);
+  return UnicodeVSPrint (StartOfBuffer, BufferSize, FormatString, Marker);
+}
+
+/**
+  Convert a Null-terminated Unicode string to a Null-terminated
+  ASCII string and returns the ASCII string.
+
+  This function converts the content of the Unicode string Source
+  to the ASCII string Destination by copying the lower 8 bits of
+  each Unicode character. It returns Destination. The function terminates
+  the ASCII string Destination  by appending a Null-terminator character
+  at the end. The caller is responsible to make sure Destination points
+  to a buffer with size equal or greater than (FceStrLen (Source) + 1) in bytes.
+
+  If Destination is NULL, then ASSERT().
+  If Source is NULL, then ASSERT().
+  If Source is not aligned on a 16-bit boundary, then ASSERT().
+  If Source and Destination overlap, then ASSERT().
+
+  If any Unicode characters in Source contain non-zero value in
+  the upper 8 bits, then ASSERT().
+
+  @param  Source        Pointer to a Null-terminated Unicode string.
+  @param  Destination   Pointer to a Null-terminated ASCII string.
+
+  @reture Destination
+
+**/
+CHAR8 *
+UnicodeStrToAsciiStr (
+  IN      CONST CHAR16             *Source,
+  OUT           CHAR8              *Destination
+  )
+{
+  CHAR8          *ReturnValue;
+
+  ReturnValue = Destination;
+  assert (Destination != NULL);
+  assert (Source != NULL);
+  assert (((UINTN) Source & 0x01) == 0);
+
+  while (*Source != L'\0') {
+    //
+    // If any Unicode characters in Source contain
+    // non-zero value in the upper 8 bits, then ASSERT().
+    //
+    assert (*Source < 0x100);
+    *(ReturnValue++) = (CHAR8) *(Source++);
+  }
+
+  *ReturnValue = '\0';
+
+  return Destination;
+}
+
+/**
+  Allocate new memory and then copy the Unicode string Source to Destination.
+
+  @param  Dest                   Location to copy string
+  @param  Src                    String to copy
+
+**/
+VOID
+NewStringCpy (
+  IN OUT CHAR16       **Dest,
+  IN CHAR16           *Src
+  )
+{
+  if (*Dest != NULL) {
+    FreePool (*Dest);
+  }
+  *Dest = FceAllocateCopyPool (FceStrSize (Src), Src);
+  ASSERT (*Dest != NULL);
+}
+
+/**
+  Check if a Unicode character is a decimal character.
+
+  This internal function checks if a Unicode character is a
+  decimal character. The valid decimal character is from
+  L'0' to L'9'.
+
+  @param  Char  The character to check against.
+
+  @retval TRUE  If the Char is a decmial character.
+  @retval FALSE If the Char is not a decmial character.
+
+**/
+BOOLEAN
+FceInternalIsDecimalDigitCharacter (
+  IN      CHAR16                    Char
+  )
+{
+  return (BOOLEAN) ((Char >= L'0') && (Char <= L'9'));
+}
+
+/**
+  Convert a Unicode character to upper case only if
+  it maps to a valid small-case ASCII character.
+
+  This internal function only deal with Unicode character
+  which maps to a valid small-case ASCII character, i.e.
+  L'a' to L'z'. For other Unicode character, the input character
+  is returned directly.
+
+  @param  Char  The character to convert.
+
+  @retval LowerCharacter   If the Char is with range L'a' to L'z'.
+  @retval Unchanged        Otherwise.
+
+**/
+CHAR16
+FceInternalCharToUpper (
+  IN      CHAR16                    Char
+  )
+{
+  if ((Char >= L'a') && (Char <= L'z')) {
+    return (CHAR16) (Char - (L'a' - L'A'));
+  }
+
+  return Char;
+}
+
+/**
+  Convert a Unicode character to numerical value.
+
+  This internal function only deal with Unicode character
+  which maps to a valid hexadecimal ASII character, i.e.
+  L'0' to L'9', L'a' to L'f' or L'A' to L'F'. For other
+  Unicode character, the value returned does not make sense.
+
+  @param  Char  The character to convert.
+
+  @return The numerical value converted.
+
+**/
+UINTN
+FceInternalHexCharToUintn (
+  IN      CHAR16                    Char
+  )
+{
+  if (FceInternalIsDecimalDigitCharacter (Char)) {
+    return Char - L'0';
+  }
+
+  return (UINTN) (10 + FceInternalCharToUpper (Char) - L'A');
+}
+
+/**
+  Check if a Unicode character is a hexadecimal character.
+
+  This internal function checks if a Unicode character is a
+  decimal character.  The valid hexadecimal character is
+  L'0' to L'9', L'a' to L'f', or L'A' to L'F'.
+
+
+  @param  Char  The character to check against.
+
+  @retval TRUE  If the Char is a hexadecmial character.
+  @retval FALSE If the Char is not a hexadecmial character.
+
+**/
+BOOLEAN
+FceInternalIsHexaDecimalDigitCharacter (
+  IN      CHAR16                    Char
+  )
+{
+
+  return (BOOLEAN) (FceInternalIsDecimalDigitCharacter (Char) ||
+    ((Char >= L'A') && (Char <= L'F')) ||
+    ((Char >= L'a') && (Char <= L'f')));
+}
+
+
+/**
+  Convert a Null-terminated Unicode decimal string to a value of
+  type UINT64.
+
+  This function returns a value of type UINT64 by interpreting the contents
+  of the Unicode string specified by String as a decimal number. The format
+  of the input Unicode string String is:
+
+                  [spaces] [decimal digits].
+
+  The valid decimal digit character is in the range [0-9]. The
+  function will ignore the pad space, which includes spaces or
+  tab characters, before [decimal digits]. The running zero in the
+  beginning of [decimal digits] will be ignored. Then, the function
+  stops at the first character that is a not a valid decimal character
+  or a Null-terminator, whichever one comes first.
+
+  If String is NULL, then ASSERT().
+  If String is not aligned in a 16-bit boundary, then ASSERT().
+  If String has only pad spaces, then 0 is returned.
+  If String has no pad spaces or valid decimal digits,
+  then 0 is returned.
+  If the number represented by String overflows according
+  to the range defined by UINT64, then ASSERT().
+
+  If PcdMaximumUnicodeStringLength is not zero, and String contains
+  more than PcdMaximumUnicodeStringLength Unicode characters, not including
+  the Null-terminator, then ASSERT().
+
+  @param  String          A pointer to a Null-terminated Unicode string.
+
+  @retval Value translated from String.
+
+**/
+UINT64
+FceStrDecimalToUint64 (
+  IN      CONST CHAR16              *String
+  )
+{
+  UINT64     Result;
+
+  //
+  // ASSERT String is less long than PcdMaximumUnicodeStringLength.
+  // Length tests are performed inside FceStrLen().
+  //
+  ASSERT (FceStrSize (String) != 0);
+
+  //
+  // Ignore the pad spaces (space or tab)
+  //
+  while ((*String == L' ') || (*String == L'\t')) {
+    String++;
+  }
+
+  //
+  // Ignore leading Zeros after the spaces
+  //
+  while (*String == L'0') {
+    String++;
+  }
+
+  Result = 0;
+
+  while (FceInternalIsDecimalDigitCharacter (*String)) {
+    //
+    // If the number represented by String overflows according
+    // to the range defined by UINTN, then ASSERT().
+    //
+    ASSERT (Result <= DivU64x32 (((UINT64) ~0) - (*String - L'0') , 10));
+
+    Result = MultU64x32 (Result, 10) + (*String - L'0');
+    String++;
+  }
+
+  return Result;
+}
+
+
+/**
+  Convert a Null-terminated Unicode hexadecimal string to a value of type UINT64.
+
+  This function returns a value of type UINT64 by interpreting the contents
+  of the Unicode string specified by String as a hexadecimal number.
+  The format of the input Unicode string String is
+
+                  [spaces][zeros][x][hexadecimal digits].
+
+  The valid hexadecimal digit character is in the range [0-9], [a-f] and [A-F].
+  The prefix "0x" is optional. Both "x" and "X" is allowed in "0x" prefix.
+  If "x" appears in the input string, it must be prefixed with at least one 0.
+  The function will ignore the pad space, which includes spaces or tab characters,
+  before [zeros], [x] or [hexadecimal digit]. The running zero before [x] or
+  [hexadecimal digit] will be ignored. Then, the decoding starts after [x] or the
+  first valid hexadecimal digit. Then, the function stops at the first character that is
+  a not a valid hexadecimal character or NULL, whichever one comes first.
+
+  If String is NULL, then ASSERT().
+  If String is not aligned in a 16-bit boundary, then ASSERT().
+  If String has only pad spaces, then zero is returned.
+  If String has no leading pad spaces, leading zeros or valid hexadecimal digits,
+  then zero is returned.
+  If the number represented by String overflows according to the range defined by
+  UINT64, then ASSERT().
+
+  If PcdMaximumUnicodeStringLength is not zero, and String contains more than
+  PcdMaximumUnicodeStringLength Unicode characters, not including the Null-terminator,
+  then ASSERT().
+
+  @param  String          A pointer to a Null-terminated Unicode string.
+
+  @retval Value translated from String.
+
+**/
+UINT64
+FceStrHexToUint64 (
+  IN      CONST CHAR16             *String
+  )
+{
+  UINT64    Result;
+
+  //
+  // ASSERT String is less long than PcdMaximumUnicodeStringLength.
+  // Length tests are performed inside FceStrLen().
+  //
+  ASSERT (FceStrSize (String) != 0);
+
+  //
+  // Ignore the pad spaces (space or tab)
+  //
+  while ((*String == L' ') || (*String == L'\t')) {
+    String++;
+  }
+
+  //
+  // Ignore leading Zeros after the spaces
+  //
+  while (*String == L'0') {
+    String++;
+  }
+
+  if (FceInternalCharToUpper (*String) == L'X') {
+    ASSERT (*(String - 1) == L'0');
+    if (*(String - 1) != L'0') {
+      return 0;
+    }
+    //
+    // Skip the 'X'
+    //
+    String++;
+  }
+
+  Result = 0;
+
+  while (FceInternalIsHexaDecimalDigitCharacter (*String)) {
+    //
+    // If the Hex Number represented by String overflows according
+    // to the range defined by UINTN, then ASSERT().
+    //
+    ASSERT (Result <= RShiftU64 (((UINT64) ~0) - FceInternalHexCharToUintn (*String) , 4));
+
+    Result = LShiftU64 (Result, 4);
+    Result = Result + FceInternalHexCharToUintn (*String);
+    String++;
+  }
+
+  return Result;
+}
+
+
+CHAR16
+ToUpper (
+  CHAR16  a
+  )
+{
+  if (('a' <= a) && (a <= 'z')) {
+    return (CHAR16) (a - 0x20);
+  } else {
+    return a;
+  }
+}
+
+CHAR16
+ToLower (
+  CHAR16  a
+  )
+{
+  if (('A' <= a) && (a <= 'Z')) {
+    return (CHAR16) (a + 0x20);
+  } else {
+    return a;
+  }
+}
+
+/**
+  Performs a case-insensitive comparison between a Null-terminated
+  Unicode pattern string and a Null-terminated Unicode string.
+
+  @param  String   - A pointer to a Null-terminated Unicode string.
+  @param  Pattern  - A pointer to a Null-terminated Unicode pattern string.
+
+
+  @retval TRUE     - Pattern was found in String.
+  @retval FALSE    - Pattern was not found in String.
+
+**/
+BOOLEAN
+MetaiMatch (
+  IN CHAR16                           *String,
+  IN CHAR16                           *Pattern
+  )
+{
+  CHAR16  c;
+  CHAR16  p;
+
+  assert (String != NULL);
+  assert (Pattern != NULL);
+
+  for (;;) {
+    p     = *Pattern;
+    Pattern += 1;
+
+    if (p == 0) {
+      //
+      // End of pattern.  If end of string, TRUE match
+      //
+      if (*String) {
+        return FALSE;
+      } else {
+        return TRUE;
+      }
+
+    } else {
+
+      c = *String;
+      if (ToUpper (c) != ToUpper (p)) {
+        return FALSE;
+      }
+
+      String += 1;
+
+    }
+
+  }
+
+}
+/**
+  Multiplies a 64-bit unsigned integer by a 32-bit unsigned integer and
+  generates a 64-bit unsigned result.
+
+  This function multiplies the 64-bit unsigned value Multiplicand by the 32-bit
+  unsigned value Multiplier and generates a 64-bit unsigned result. This 64-
+  bit unsigned result is returned.
+
+  @param  Multiplicand  A 64-bit unsigned value.
+  @param  Multiplier    A 32-bit unsigned value.
+
+  @return Multiplicand * Multiplier.
+
+**/
+UINT64
+MultU64x32 (
+  IN      UINT64                    Multiplicand,
+  IN      UINT32                    Multiplier
+  )
+{
+  return Multiplicand * Multiplier;
+}
+
+/**
+  Divides a 64-bit unsigned integer by a 32-bit unsigned integer and generates
+  a 64-bit unsigned result.
+
+  This function divides the 64-bit unsigned value Dividend by the 32-bit
+  unsigned value Divisor and generates a 64-bit unsigned quotient. This
+  function returns the 64-bit unsigned quotient.
+
+  If Divisor is 0, then ASSERT().
+
+  @param  Dividend  A 64-bit unsigned value.
+  @param  Divisor   A 32-bit unsigned value.
+
+  @return Dividend / Divisor
+
+**/
+UINT64
+DivU64x32 (
+  IN      UINT64                    Dividend,
+  IN      UINT32                    Divisor
+  )
+{
+  ASSERT (Divisor != 0);
+  return Dividend / Divisor;
+}
+
+/**
+  Shifts a 64-bit integer left between 0 and 63 bits. The low bits are filled
+  with zeros. The shifted value is returned.
+
+  This function shifts the 64-bit value Operand to the left by Count bits. The
+  low Count bits are set to zero. The shifted value is returned.
+
+  If Count is greater than 63, then ASSERT().
+
+  @param  Operand The 64-bit operand to shift left.
+  @param  Count   The number of bits to shift left.
+
+  @return Operand << Count.
+
+**/
+UINT64
+LShiftU64 (
+  IN      UINT64                    Operand,
+  IN      UINTN                     Count
+  )
+{
+  ASSERT (Count < 64);
+  return Operand << Count;
+}
+
+/**
+  Shifts a 64-bit integer right between 0 and 63 bits. This high bits are
+  filled with zeros. The shifted value is returned.
+
+  This function shifts the 64-bit value Operand to the right by Count bits. The
+  high Count bits are set to zero. The shifted value is returned.
+
+  If Count is greater than 63, then ASSERT().
+
+  @param  Operand The 64-bit operand to shift right.
+  @param  Count   The number of bits to shift right.
+
+  @return Operand >> Count.
+
+**/
+UINT64
+RShiftU64 (
+  IN      UINT64                    Operand,
+  IN      UINTN                     Count
+  )
+
+{
+  ASSERT (Count < 64);
+  return Operand >> Count;
+}
+
+
+/**
+  Divides a 64-bit unsigned integer by a 32-bit unsigned integer and generates
+  a 64-bit unsigned result and an optional 32-bit unsigned remainder.
+
+  This function divides the 64-bit unsigned value Dividend by the 32-bit
+  unsigned value Divisor and generates a 64-bit unsigned quotient. If Remainder
+  is not NULL, then the 32-bit unsigned remainder is returned in Remainder.
+  This function returns the 64-bit unsigned quotient.
+
+  If Divisor is 0, then ASSERT().
+
+  @param  Dividend  A 64-bit unsigned value.
+  @param  Divisor   A 32-bit unsigned value.
+  @param  Remainder A pointer to a 32-bit unsigned value. This parameter is
+                    optional and may be NULL.
+
+  @return Dividend / Divisor
+
+**/
+UINT64
+DivU64x32Remainder (
+  IN      UINT64                    Dividend,
+  IN      UINT32                    Divisor,
+  OUT     UINT32                    *Remainder
+  )
+{
+  ASSERT (Divisor != 0);
+
+  if (Remainder != NULL) {
+    *Remainder = (UINT32)(Dividend % Divisor);
+  }
+  return Dividend / Divisor;
+}
+
+/**
+  Copies a buffer to an allocated buffer.
+
+  Allocates the number bytes specified by AllocationSize, copies allocationSize bytes
+  from Buffer to the newly allocated buffer, and returns a pointer to the allocated
+  buffer.  If AllocationSize is 0, then a valid buffer of 0 size is returned.  If there
+  is not enough memory remaining to satisfy the request, then NULL is returned.
+
+  If Buffer is NULL, then ASSERT().
+
+  @param  AllocationSize        The number of bytes to allocate and zero.
+  @param  Buffer                The buffer to copy to the allocated buffer.
+
+  @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+FceAllocateCopyPool (
+  IN UINTN       AllocationSize,
+  IN CONST VOID  *Buffer
+  )
+{
+  VOID  *Memory;
+
+  Memory = NULL;
+
+  if ((Buffer == NULL) || (AllocationSize == 0)) {
+    return Memory;
+  }
+
+  Memory = calloc (AllocationSize, sizeof (CHAR8));
+  if (Memory != NULL) {
+     Memory = memcpy (Memory, Buffer, AllocationSize);
+  }
+  return Memory;
+}
+
+/**
+  Initializes the head node of a doubly-linked list, and returns the pointer to
+  the head node of the doubly-linked list.
+
+  Initializes the forward and backward links of a new linked list. After
+  initializing a linked list with this function, the other linked list
+  functions may be used to add and remove nodes from the linked list. It is up
+  to the caller of this function to allocate the memory for ListHead.
+
+  If ListHead is NULL, then ASSERT().
+
+  @param  ListHead  A pointer to the head node of a new doubly-linked list.
+
+  @return ListHead
+
+**/
+LIST_ENTRY *
+InitializeListHead (
+  IN OUT  LIST_ENTRY                *ListHead
+  )
+
+{
+  assert (ListHead != NULL);
+
+  ListHead->ForwardLink = ListHead;
+  ListHead->BackLink = ListHead;
+  return ListHead;
+}
+
+/**
+  Adds a node to the beginning of a doubly-linked list, and returns the pointer
+  to the head node of the doubly-linked list.
+
+  Adds the node Entry at the beginning of the doubly-linked list denoted by
+  ListHead, and returns ListHead.
+
+  If ListHead is NULL, then ASSERT().
+  If Entry is NULL, then ASSERT().
+  If ListHead was not initialized with INTIALIZE_LIST_HEAD_VARIABLE() or
+  InitializeListHead(), then ASSERT().
+  If PcdMaximumLinkedListLenth is not zero, and prior to insertion the number
+  of nodes in ListHead, including the ListHead node, is greater than or
+  equal to PcdMaximumLinkedListLength, then ASSERT().
+
+  @param  ListHead  A pointer to the head node of a doubly-linked list.
+  @param  Entry     A pointer to a node that is to be inserted at the beginning
+                    of a doubly-linked list.
+
+  @return ListHead
+
+**/
+LIST_ENTRY *
+InsertHeadList (
+  IN OUT  LIST_ENTRY                *ListHead,
+  IN OUT  LIST_ENTRY                *Entry
+  )
+{
+  assert ((ListHead != NULL) && (Entry != NULL));
+
+  Entry->ForwardLink = ListHead->ForwardLink;
+  Entry->BackLink = ListHead;
+  Entry->ForwardLink->BackLink = Entry;
+  ListHead->ForwardLink = Entry;
+  return ListHead;
+}
+
+/**
+  Adds a node to the end of a doubly-linked list, and returns the pointer to
+  the head node of the doubly-linked list.
+
+  Adds the node Entry to the end of the doubly-linked list denoted by ListHead,
+  and returns ListHead.
+
+  If ListHead is NULL, then ASSERT().
+  If Entry is NULL, then ASSERT().
+  If ListHead was not initialized with INTIALIZE_LIST_HEAD_VARIABLE() or
+  InitializeListHead(), then ASSERT().
+  If PcdMaximumLinkedListLenth is not zero, and prior to insertion the number
+  of nodes in ListHead, including the ListHead node, is greater than or
+  equal to PcdMaximumLinkedListLength, then ASSERT().
+
+  @param  ListHead  A pointer to the head node of a doubly-linked list.
+  @param  Entry     A pointer to a node that is to be added at the end of the
+                    doubly-linked list.
+
+  @return ListHead
+
+**/
+LIST_ENTRY *
+InsertTailList (
+  IN OUT  LIST_ENTRY                *ListHead,
+  IN OUT  LIST_ENTRY                *Entry
+  )
+{
+  assert ((ListHead != NULL) && (Entry != NULL));
+
+  Entry->ForwardLink = ListHead;
+  Entry->BackLink = ListHead->BackLink;
+  Entry->BackLink->ForwardLink = Entry;
+  ListHead->BackLink = Entry;
+  return ListHead;
+}
+
+/**
+  Retrieves the first node of a doubly-linked list.
+
+  Returns the first node of a doubly-linked list.  List must have been
+  initialized with INTIALIZE_LIST_HEAD_VARIABLE() or InitializeListHead().
+  If List is empty, then List is returned.
+
+  If List is NULL, then ASSERT().
+  If List was not initialized with INTIALIZE_LIST_HEAD_VARIABLE() or
+  InitializeListHead(), then ASSERT().
+  If PcdMaximumLinkedListLenth is not zero, and the number of nodes
+  in List, including the List node, is greater than or equal to
+  PcdMaximumLinkedListLength, then ASSERT().
+
+  @param  List  A pointer to the head node of a doubly-linked list.
+
+  @return The first node of a doubly-linked list.
+  @retval NULL  The list is empty.
+
+**/
+LIST_ENTRY *
+GetFirstNode (
+  IN      CONST LIST_ENTRY          *List
+  )
+{
+  assert (List != NULL);
+
+  return List->ForwardLink;
+}
+
+/**
+  Retrieves the next node of a doubly-linked list.
+
+  Returns the node of a doubly-linked list that follows Node.
+  List must have been initialized with INTIALIZE_LIST_HEAD_VARIABLE()
+  or InitializeListHead().  If List is empty, then List is returned.
+
+  If List is NULL, then ASSERT().
+  If Node is NULL, then ASSERT().
+  If List was not initialized with INTIALIZE_LIST_HEAD_VARIABLE() or
+  InitializeListHead(), then ASSERT().
+  If PcdMaximumLinkedListLenth is not zero, and List contains more than
+  PcdMaximumLinkedListLenth nodes, then ASSERT().
+  If PcdVerifyNodeInList is TRUE and Node is not a node in List, then ASSERT().
+
+  @param  List  A pointer to the head node of a doubly-linked list.
+  @param  Node  A pointer to a node in the doubly-linked list.
+
+  @return A pointer to the next node if one exists. Otherwise List is returned.
+
+**/
+LIST_ENTRY *
+GetNextNode (
+  IN      CONST LIST_ENTRY          *List,
+  IN      CONST LIST_ENTRY          *Node
+  )
+{
+  assert ((List != NULL) && (Node != NULL));
+
+  return Node->ForwardLink;
+}
+
+/**
+  Retrieves the previous node of a doubly-linked list.
+
+  Returns the node of a doubly-linked list that precedes Node.
+  List must have been initialized with INTIALIZE_LIST_HEAD_VARIABLE()
+  or InitializeListHead().  If List is empty, then List is returned.
+
+  If List is NULL, then ASSERT().
+  If Node is NULL, then ASSERT().
+  If List was not initialized with INTIALIZE_LIST_HEAD_VARIABLE() or
+  InitializeListHead(), then ASSERT().
+  If PcdMaximumLinkedListLenth is not zero, and List contains more than
+  PcdMaximumLinkedListLenth nodes, then ASSERT().
+  If PcdVerifyNodeInList is TRUE and Node is not a node in List, then ASSERT().
+
+  @param  List  A pointer to the head node of a doubly-linked list.
+  @param  Node  A pointer to a node in the doubly-linked list.
+
+  @return A pointer to the previous node if one exists. Otherwise List is returned.
+
+**/
+LIST_ENTRY *
+GetPreviousNode (
+  IN      CONST LIST_ENTRY          *List,
+  IN      CONST LIST_ENTRY          *Node
+  )
+{
+  assert ((List != NULL) && (Node != NULL));
+
+  return Node->BackLink;
+}
+
+/**
+  Checks to see if a doubly-linked list is empty or not.
+
+  Checks to see if the doubly-linked list is empty. If the linked list contains
+  zero nodes, this function returns TRUE. Otherwise, it returns FALSE.
+
+  If ListHead is NULL, then ASSERT().
+  If ListHead was not initialized with INTIALIZE_LIST_HEAD_VARIABLE() or
+  InitializeListHead(), then ASSERT().
+  If PcdMaximumLinkedListLenth is not zero, and the number of nodes
+  in List, including the List node, is greater than or equal to
+  PcdMaximumLinkedListLength, then ASSERT().
+
+  @param  ListHead  A pointer to the head node of a doubly-linked list.
+
+  @retval TRUE  The linked list is empty.
+  @retval FALSE The linked list is not empty.
+
+**/
+BOOLEAN
+IsListEmpty (
+  IN      CONST LIST_ENTRY          *ListHead
+  )
+{
+  assert (ListHead != NULL);
+
+  return (BOOLEAN)(ListHead->ForwardLink == ListHead);
+}
+
+/**
+  Determines if a node in a doubly-linked list is the head node of a the same
+  doubly-linked list.  This function is typically used to terminate a loop that
+  traverses all the nodes in a doubly-linked list starting with the head node.
+
+  Returns TRUE if Node is equal to List.  Returns FALSE if Node is one of the
+  nodes in the doubly-linked list specified by List.  List must have been
+  initialized with INTIALIZE_LIST_HEAD_VARIABLE() or InitializeListHead().
+
+  If List is NULL, then ASSERT().
+  If Node is NULL, then ASSERT().
+  If List was not initialized with INTIALIZE_LIST_HEAD_VARIABLE() or InitializeListHead(),
+  then ASSERT().
+  If PcdMaximumLinkedListLenth is not zero, and the number of nodes
+  in List, including the List node, is greater than or equal to
+  PcdMaximumLinkedListLength, then ASSERT().
+  If PcdVerifyNodeInList is TRUE and Node is not a node in List and Node is not
+  equal to List, then ASSERT().
+
+  @param  List  A pointer to the head node of a doubly-linked list.
+  @param  Node  A pointer to a node in the doubly-linked list.
+
+  @retval TRUE  Node is the head of the doubly-linked list pointed by List.
+  @retval FALSE Node is not the head of the doubly-linked list pointed by List.
+
+**/
+BOOLEAN
+IsNull (
+  IN      CONST LIST_ENTRY          *List,
+  IN      CONST LIST_ENTRY          *Node
+  )
+{
+  assert ((List != NULL) && (Node != NULL));
+
+  return (BOOLEAN)(Node == List);
+}
+
+/**
+  Determines if a node the last node in a doubly-linked list.
+
+  Returns TRUE if Node is the last node in the doubly-linked list specified by
+  List. Otherwise, FALSE is returned. List must have been initialized with
+  INTIALIZE_LIST_HEAD_VARIABLE() or InitializeListHead().
+
+  If List is NULL, then ASSERT().
+  If Node is NULL, then ASSERT().
+  If List was not initialized with INTIALIZE_LIST_HEAD_VARIABLE() or
+  InitializeListHead(), then ASSERT().
+  If PcdMaximumLinkedListLenth is not zero, and the number of nodes
+  in List, including the List node, is greater than or equal to
+  PcdMaximumLinkedListLength, then ASSERT().
+  If PcdVerifyNodeInList is TRUE and Node is not a node in List, then ASSERT().
+
+  @param  List  A pointer to the head node of a doubly-linked list.
+  @param  Node  A pointer to a node in the doubly-linked list.
+
+  @retval TRUE  Node is the last node in the linked list.
+  @retval FALSE Node is not the last node in the linked list.
+
+**/
+BOOLEAN
+IsNodeAtEnd (
+  IN      CONST LIST_ENTRY          *List,
+  IN      CONST LIST_ENTRY          *Node
+  )
+{
+  assert ((List != NULL) && (Node != NULL));
+
+  return (BOOLEAN)(!IsNull (List, Node) && (List->BackLink == Node));
+}
+
+/**
+  Removes a node from a doubly-linked list, and returns the node that follows
+  the removed node.
+
+  Removes the node Entry from a doubly-linked list. It is up to the caller of
+  this function to release the memory used by this node if that is required. On
+  exit, the node following Entry in the doubly-linked list is returned. If
+  Entry is the only node in the linked list, then the head node of the linked
+  list is returned.
+
+  If Entry is NULL, then ASSERT().
+  If Entry is the head node of an empty list, then ASSERT().
+  If PcdMaximumLinkedListLength is not zero, and the number of nodes in the
+  linked list containing Entry, including the Entry node, is greater than
+  or equal to PcdMaximumLinkedListLength, then ASSERT().
+
+  @param  Entry A pointer to a node in a linked list.
+
+  @return Entry.
+
+**/
+LIST_ENTRY *
+RemoveEntryList (
+  IN      CONST LIST_ENTRY          *Entry
+  )
+{
+  assert (!IsListEmpty (Entry));
+
+  Entry->ForwardLink->BackLink = Entry->BackLink;
+  Entry->BackLink->ForwardLink = Entry->ForwardLink;
+  return Entry->ForwardLink;
+}
+
diff --git a/Platform/Intel/Tools/FCE/Common.h b/Platform/Intel/Tools/FCE/Common.h
new file mode 100644
index 0000000000..6b21974878
--- /dev/null
+++ b/Platform/Intel/Tools/FCE/Common.h
@@ -0,0 +1,999 @@
+/** @file
+
+ Common library.
+
+ Copyright (c) 2011-2019, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+#ifndef _COMMON_LIB_H_
+#define _COMMON_LIB_H_
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#ifdef __GNUC__
+#include <unistd.h>
+#else
+#include <io.h>
+#include <direct.h>
+#endif
+#include <ctype.h>
+#include <assert.h>
+#include <math.h>
+#include "CommonLib.h"
+#include <Common/UefiBaseTypes.h>
+
+#define MAX_QUI_PARAM_LEN              2000
+#define ERROR_INFO_LENGTH              400
+#define MAX_STR_LEN_FOR_PICK_UQI       200
+#define MAX_PLATFORM_DEFAULT_ID_NUM    1000
+#define _MAX_BUILD_VERSION             100
+#define _MAXIMUM_SECTION_FILE_NUM      1000
+
+#ifndef _MAX_PATH
+#define _MAX_PATH 500
+#endif
+
+///
+/// Variable attributes.
+///
+#define EFI_VARIABLE_NON_VOLATILE       0x00000001
+#define EFI_VARIABLE_BOOTSERVICE_ACCESS 0x00000002
+#define EFI_VARIABLE_RUNTIME_ACCESS     0x00000004
+
+///
+/// This attribute is identified by the mnemonic 'HR'
+/// elsewhere in this specification.
+///
+#define EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS   0x00000010
+
+#define VARSTORE_LIST_TYPE         0x0000000000000001ULL
+#define EFI_VARSTORE_LIST_TYPE     0x0000000000000002ULL
+#define PLATFORM_DEFAULT_ID_TYPE   0x0000000000000004ULL
+#define UQI_LIST_TYPE              0x0000000000000008ULL
+#define HII_OBJ_LIST_TYPE          0x0000000000000010ULL
+
+///
+/// LIST_ENTRY structure definition.
+///
+typedef struct _LIST_ENTRY {
+  struct _LIST_ENTRY  *ForwardLink;
+  struct _LIST_ENTRY  *BackLink;
+} LIST_ENTRY;
+
+#define CR(Record, TYPE, Field, TestSignature)  ((TYPE *) ((CHAR8 *) (Record) - (CHAR8 *) &(((TYPE *) 0)->Field)))
+#define AllocateZeroPool(a)  calloc(a, sizeof (CHAR8))
+#define FreePool(a) free(a)
+#define CopyMem(a, b, c)  memcpy(a, b, c)
+#define ZeroMem(a, b) memset(a, 0, b)
+#define CompareMem(a, b, c)  memcmp(a, b, c)
+#define AllocatePool(a)  malloc(a)
+
+/**
+  Returns a 16-bit signature built from 2 ASCII characters.
+
+  This macro returns a 16-bit value built from the two ASCII characters specified
+  by A and B.
+
+  @param  A    The first ASCII character.
+  @param  B    The second ASCII character.
+
+  @return A 16-bit value built from the two ASCII characters specified by A and B.
+
+**/
+#define SIGNATURE_16(A, B)        ((A) | (B << 8))
+
+/**
+  Returns a 32-bit signature built from 4 ASCII characters.
+
+  This macro returns a 32-bit value built from the four ASCII characters specified
+  by A, B, C, and D.
+
+  @param  A    The first ASCII character.
+  @param  B    The second ASCII character.
+  @param  C    The third ASCII character.
+  @param  D    The fourth ASCII character.
+
+  @return A 32-bit value built from the two ASCII characters specified by A, B,
+          C and D.
+
+**/
+#define SIGNATURE_32(A, B, C, D)  (SIGNATURE_16 (A, B) | (SIGNATURE_16 (C, D) << 16))
+
+#define ASSERT_UNICODE_BUFFER(Buffer) ASSERT ((((UINTN) (Buffer)) & 0x01) == 0)
+
+/**
+  Returns an argument of a specified type from a variable argument list and updates
+  the pointer to the variable argument list to point to the next argument.
+
+  This function returns an argument of the type specified by TYPE from the beginning
+  of the variable argument list specified by Marker.  Marker is then updated to point
+  to the next argument in the variable argument list.  The method for computing the
+  pointer to the next argument in the argument list is CPU specific following the EFIAPI ABI.
+
+  @param   Marker   The pointer to the beginning of a variable argument list.
+  @param   TYPE     The type of argument to retrieve from the beginning
+                    of the variable argument list.
+
+  @return  An argument of the type specified by TYPE.
+
+**/
+#define BASE_ARG(Marker, TYPE)   (*(TYPE *) ((Marker += _BASE_INT_SIZE_OF (TYPE)) - _BASE_INT_SIZE_OF (TYPE)))
+
+///
+/// Define the maximum number of characters that are required to
+/// encode with a NULL terminator a decimal, hexadecimal, GUID,
+/// or TIME value.
+///
+///  Maximum Length Decimal String     = 28
+///    "-9,223,372,036,854,775,808"
+///  Maximum Length Hexadecimal String = 17
+///    "FFFFFFFFFFFFFFFF"
+///  Maximum Length GUID               = 37
+///    "00000000-0000-0000-0000-000000000000"
+///  Maximum Length TIME               = 18
+///    "12/12/2006  12:12"
+///
+#define MAXIMUM_VALUE_CHARACTERS  38
+
+///
+/// Pointer to the start of a variable argument list stored in a memory buffer. Same as UINT8 *.
+///
+typedef UINTN  *BASE_LIST;
+
+/**
+  Returns the size of a data type in sizeof(UINTN) units rounded up to the nearest UINTN boundary.
+
+  @param  TYPE  The date type to determine the size of.
+
+  @return The size of TYPE in sizeof (UINTN) units rounded up to the nearest UINTN boundary.
+**/
+#define _BASE_INT_SIZE_OF(TYPE) ((sizeof (TYPE) + sizeof (UINTN) - 1) / sizeof (UINTN))
+
+//
+// Print primitives
+//
+#define PREFIX_SIGN           BIT1
+#define PREFIX_BLANK          BIT2
+#define LONG_TYPE             BIT4
+#define OUTPUT_UNICODE        BIT6
+#define FORMAT_UNICODE        BIT8
+#define PAD_TO_WIDTH          BIT9
+#define ARGUMENT_UNICODE      BIT10
+#define PRECISION             BIT11
+#define ARGUMENT_REVERSED     BIT12
+#define COUNT_ONLY_NO_PRINT   BIT13
+
+///
+/// Flags bitmask values use in UnicodeValueToString() and
+/// AsciiValueToString()
+///
+#define LEFT_JUSTIFY      0x01
+#define COMMA_TYPE        0x08
+#define PREFIX_ZERO       0x20
+#define RADIX_HEX         0x80
+
+//
+// Record date and time information
+//
+typedef struct {
+  UINT16  Year;
+  UINT8   Month;
+  UINT8   Day;
+  UINT8   Hour;
+  UINT8   Minute;
+  UINT8   Second;
+  UINT8   Pad1;
+  UINT32  Nanosecond;
+  INT16   TimeZone;
+  UINT8   Daylight;
+  UINT8   Pad2;
+} TIME;
+
+
+/**
+  Copies one Null-terminated Unicode string to another Null-terminated Unicode
+  string and returns the new Unicode string.
+
+  This function copies the contents of the Unicode string Source to the Unicode
+  string Destination, and returns Destination. If Source and Destination
+  overlap, then the results are undefined.
+
+  If Destination is NULL, then return NULL.
+  If Destination is not aligned on a 16-bit boundary, then return NULL.
+
+  @param  Destination A pointer to a Null-terminated Unicode string.
+  @param  Source      A pointer to a Null-terminated Unicode string.
+
+  @return Destination.
+
+**/
+CHAR16 *
+StrCpy (
+  OUT     CHAR16                    *Destination,
+  IN      CONST CHAR16              *Source
+  );
+
+/**
+  Returns the length of a Null-terminated Unicode string.
+
+  This function returns the number of Unicode characters in the Null-terminated
+  Unicode string specified by String.
+
+  If String is NULL, then return 0.
+
+  @param  String  A pointer to a Null-terminated Unicode string.
+
+  @return The length of String.
+
+**/
+UINTN
+FceStrLen (
+  IN      CONST CHAR16              *String
+  );
+
+/**
+  Returns the size of a Null-terminated Unicode string in bytes, including the
+  Null terminator.
+
+  This function returns the size, in bytes, of the Null-terminated Unicode string
+  specified by String.
+
+  If String is NULL, then ASSERT().
+  If String is not aligned on a 16-bit boundary, then ASSERT().
+  If PcdMaximumUnicodeStringLength is not zero, and String contains more than
+  PcdMaximumUnicodeStringLength Unicode characters, not including the
+  Null-terminator, then ASSERT().
+
+  @param  String  A pointer to a Null-terminated Unicode string.
+
+  @return The size of String.
+
+**/
+UINTN
+FceStrSize (
+  IN      CONST CHAR16              *String
+  );
+
+/**
+  Compares two Null-terminated Unicode strings, and returns the difference
+  between the first mismatched Unicode characters.
+
+  This function compares the Null-terminated Unicode string FirstString to the
+  Null-terminated Unicode string SecondString. If FirstString is identical to
+  SecondString, then 0 is returned. Otherwise, the value returned is the first
+  mismatched Unicode character in SecondString subtracted from the first
+  mismatched Unicode character in FirstString.
+
+  @param  FirstString   A pointer to a Null-terminated Unicode string.
+  @param  SecondString  A pointer to a Null-terminated Unicode string.
+
+  @retval 0      FirstString is identical to SecondString.
+  @return others FirstString is not identical to SecondString.
+
+**/
+INTN
+FceStrCmp (
+  IN      CONST CHAR16              *FirstString,
+  IN      CONST CHAR16              *SecondString
+  );
+
+/**
+  Concatenates one Null-terminated Unicode string to another Null-terminated
+  Unicode string, and returns the concatenated Unicode string.
+
+  This function concatenates two Null-terminated Unicode strings. The contents
+  of Null-terminated Unicode string Source are concatenated to the end of
+  Null-terminated Unicode string Destination. The Null-terminated concatenated
+  Unicode String is returned. If Source and Destination overlap, then the
+  results are undefined.
+
+  If Destination is NULL, then ASSERT().
+  If Destination is not aligned on a 16-bit boundary, then ASSERT().
+  If Source is NULL, then ASSERT().
+  If Source is not aligned on a 16-bit boundary, then ASSERT().
+  If Source and Destination overlap, then ASSERT().
+  If PcdMaximumUnicodeStringLength is not zero, and Destination contains more
+  than PcdMaximumUnicodeStringLength Unicode characters, not including the
+  Null-terminator, then ASSERT().
+  If PcdMaximumUnicodeStringLength is not zero, and Source contains more than
+  PcdMaximumUnicodeStringLength Unicode characters, not including the
+  Null-terminator, then ASSERT().
+  If PcdMaximumUnicodeStringLength is not zero, and concatenating Destination
+  and Source results in a Unicode string with more than
+  PcdMaximumUnicodeStringLength Unicode characters, not including the
+  Null-terminator, then ASSERT().
+
+  @param  Destination A pointer to a Null-terminated Unicode string.
+  @param  Source      A pointer to a Null-terminated Unicode string.
+
+  @return Destination.
+
+**/
+CHAR16 *
+StrCat (
+  IN OUT  CHAR16                    *Destination,
+  IN      CONST CHAR16              *Source
+  );
+
+/**
+  Returns the first occurrence of a Null-terminated Unicode sub-string
+  in a Null-terminated Unicode string.
+
+  This function scans the contents of the Null-terminated Unicode string
+  specified by String and returns the first occurrence of SearchString.
+  If SearchString is not found in String, then NULL is returned.  If
+  the length of SearchString is zero, then String is
+  returned.
+
+  If String is NULL, then ASSERT().
+  If String is not aligned on a 16-bit boundary, then ASSERT().
+  If SearchString is NULL, then ASSERT().
+  If SearchString is not aligned on a 16-bit boundary, then ASSERT().
+
+  If PcdMaximumUnicodeStringLength is not zero, and SearchString
+  or String contains more than PcdMaximumUnicodeStringLength Unicode
+  characters, not including the Null-terminator, then ASSERT().
+
+  @param  String          A pointer to a Null-terminated Unicode string.
+  @param  SearchString    A pointer to a Null-terminated Unicode string to search for.
+
+  @retval NULL            If the SearchString does not appear in String.
+  @return others          If there is a match.
+
+**/
+CHAR16 *
+StrStr (
+  IN      CONST CHAR16              *String,
+  IN      CONST CHAR16              *SearchString
+  );
+
+/**
+  Convert a Null-terminated Unicode decimal string to a value of
+  type UINT64.
+
+  This function returns a value of type UINT64 by interpreting the contents
+  of the Unicode string specified by String as a decimal number. The format
+  of the input Unicode string String is:
+
+                  [spaces] [decimal digits].
+
+  The valid decimal digit character is in the range [0-9]. The
+  function will ignore the pad space, which includes spaces or
+  tab characters, before [decimal digits]. The running zero in the
+  beginning of [decimal digits] will be ignored. Then, the function
+  stops at the first character that is a not a valid decimal character
+  or a Null-terminator, whichever one comes first.
+
+  If String is NULL, then ASSERT().
+  If String is not aligned in a 16-bit boundary, then ASSERT().
+  If String has only pad spaces, then 0 is returned.
+  If String has no pad spaces or valid decimal digits,
+  then 0 is returned.
+  If the number represented by String overflows according
+  to the range defined by UINT64, then ASSERT().
+
+  If PcdMaximumUnicodeStringLength is not zero, and String contains
+  more than PcdMaximumUnicodeStringLength Unicode characters, not including
+  the Null-terminator, then ASSERT().
+
+  @param  String          A pointer to a Null-terminated Unicode string.
+
+  @retval Value translated from String.
+
+**/
+UINT64
+FceStrDecimalToUint64 (
+  IN      CONST CHAR16              *String
+  );
+
+
+/**
+  Convert one Null-terminated ASCII string to a Null-terminated
+  Unicode string and returns the Unicode string.
+
+  This function converts the contents of the ASCII string Source to the Unicode
+  string Destination, and returns Destination.  The function terminates the
+  Unicode string Destination by appending a Null-terminator character at the end.
+  The caller is responsible to make sure Destination points to a buffer with size
+  equal or greater than ((AsciiStrLen (Source) + 1) * sizeof (CHAR16)) in bytes.
+
+  @param  Source        A pointer to a Null-terminated ASCII string.
+  @param  Destination   A pointer to a Null-terminated Unicode string.
+
+  @return Destination.
+  @return NULL          If Destination or Source is NULL, return NULL.
+
+**/
+CHAR16 *
+AsciiStrToUnicodeStr (
+  IN      CONST CHAR8               *Source,
+  OUT     CHAR16                    *Destination
+  );
+
+/**
+  Worker function that produces a Null-terminated string in an output buffer
+  based on a Null-terminated format string and variable argument list.
+
+  VSPrint function to process format and place the results in Buffer. Since a
+  VA_LIST is used this routine allows the nesting of Vararg routines. Thus
+  this is the main print working routine
+
+  @param  StartOfBuffer The character buffer to print the results of the parsing
+                        of Format into.
+  @param  BufferSize    The maximum number of characters to put into buffer.
+                        Zero means no limit.
+  @param  Flags         Initial flags value.
+                        Can only have FORMAT_UNICODE and OUTPUT_UNICODE set
+  @param  FormatString  A Null-terminated format string.
+  @param  ...           The variable argument list.
+
+  @return The number of characters printed.
+
+**/
+UINTN
+BasePrintLibSPrint (
+  OUT CHAR8        *StartOfBuffer,
+  IN  UINTN        BufferSize,
+  IN  UINTN        Flags,
+  IN  CONST CHAR8  *FormatString,
+  ...
+  );
+
+/**
+  Produces a Null-terminated Unicode string in an output buffer based on a Null-terminated
+  Unicode format string and variable argument list.
+
+  Produces a Null-terminated Unicode string in the output buffer specified by StartOfBuffer
+  and BufferSize.
+  The Unicode string is produced by parsing the format string specified by FormatString.
+  Arguments are pulled from the variable argument list based on the contents of the format string.
+  The number of Unicode characters in the produced output buffer is returned not including
+  the Null-terminator.
+  If BufferSize is 0 or 1, then no output buffer is produced and 0 is returned.
+
+  If BufferSize > 1 and StartOfBuffer is NULL, then ASSERT().
+  If BufferSize > 1 and StartOfBuffer is not aligned on a 16-bit boundary, then ASSERT().
+  If BufferSize > 1 and FormatString is NULL, then ASSERT().
+  If BufferSize > 1 and FormatString is not aligned on a 16-bit boundary, then ASSERT().
+  If PcdMaximumUnicodeStringLength is not zero, and FormatString contains more than
+  PcdMaximumUnicodeStringLength Unicode characters not including the Null-terminator, then
+  ASSERT().
+  If PcdMaximumUnicodeStringLength is not zero, and produced Null-terminated Unicode string
+  contains more than PcdMaximumUnicodeStringLength Unicode characters not including the
+  Null-terminator, then ASSERT().
+
+  @param  StartOfBuffer   A pointer to the output buffer for the produced Null-terminated
+                          Unicode string.
+  @param  BufferSize      The size, in bytes, of the output buffer specified by StartOfBuffer.
+  @param  FormatString    A Null-terminated Unicode format string.
+  @param  ...             Variable argument list whose contents are accessed based on the
+                          format string specified by FormatString.
+
+  @return The number of Unicode characters in the produced output buffer not including the
+          Null-terminator.
+
+**/
+UINTN
+UnicodeSPrint (
+  OUT CHAR16        *StartOfBuffer,
+  IN  UINTN         BufferSize,
+  IN  CONST CHAR16  *FormatString,
+  ...
+  );
+
+/**
+  Convert a Null-terminated Unicode string to a Null-terminated
+  ASCII string and returns the ASCII string.
+
+  This function converts the content of the Unicode string Source
+  to the ASCII string Destination by copying the lower 8 bits of
+  each Unicode character. It returns Destination. The function terminates
+  the ASCII string Destination  by appending a Null-terminator character
+  at the end. The caller is responsible to make sure Destination points
+  to a buffer with size equal or greater than (FceStrLen (Source) + 1) in bytes.
+
+  If Destination is NULL, then ASSERT().
+  If Source is NULL, then ASSERT().
+  If Source is not aligned on a 16-bit boundary, then ASSERT().
+  If Source and Destination overlap, then ASSERT().
+
+  If any Unicode characters in Source contain non-zero value in
+  the upper 8 bits, then ASSERT().
+
+  @param  Source        Pointer to a Null-terminated Unicode string.
+  @param  Destination   Pointer to a Null-terminated ASCII string.
+
+  @reture Destination
+
+**/
+CHAR8 *
+UnicodeStrToAsciiStr (
+  IN      CONST CHAR16             *Source,
+  OUT           CHAR8              *Destination
+  );
+
+/**
+  Allocate new memory and then copy the Unicode string Source to Destination.
+
+  @param  Dest                   Location to copy string
+  @param  Src                    String to copy
+
+**/
+VOID
+NewStringCpy (
+  IN OUT CHAR16       **Dest,
+  IN CHAR16           *Src
+  );
+
+/**
+  Convert a Null-terminated Unicode hexadecimal string to a value of type UINT64.
+
+  This function returns a value of type UINT64 by interpreting the contents
+  of the Unicode string specified by String as a hexadecimal number.
+  The format of the input Unicode string String is
+
+                  [spaces][zeros][x][hexadecimal digits].
+
+  The valid hexadecimal digit character is in the range [0-9], [a-f] and [A-F].
+  The prefix "0x" is optional. Both "x" and "X" is allowed in "0x" prefix.
+  If "x" appears in the input string, it must be prefixed with at least one 0.
+  The function will ignore the pad space, which includes spaces or tab characters,
+  before [zeros], [x] or [hexadecimal digit]. The running zero before [x] or
+  [hexadecimal digit] will be ignored. Then, the decoding starts after [x] or the
+  first valid hexadecimal digit. Then, the function stops at the first character that is
+  a not a valid hexadecimal character or NULL, whichever one comes first.
+
+  If String is NULL, then ASSERT().
+  If String is not aligned in a 16-bit boundary, then ASSERT().
+  If String has only pad spaces, then zero is returned.
+  If String has no leading pad spaces, leading zeros or valid hexadecimal digits,
+  then zero is returned.
+  If the number represented by String overflows according to the range defined by
+  UINT64, then ASSERT().
+
+  If PcdMaximumUnicodeStringLength is not zero, and String contains more than
+  PcdMaximumUnicodeStringLength Unicode characters, not including the Null-terminator,
+  then ASSERT().
+
+  @param  String          A pointer to a Null-terminated Unicode string.
+
+  @retval Value translated from String.
+
+**/
+UINT64
+FceStrHexToUint64 (
+  IN      CONST CHAR16             *String
+  );
+
+
+CHAR16
+ToUpper (
+  CHAR16  a
+  );
+
+CHAR16
+ToLower (
+  CHAR16  a
+  );
+
+/**
+  Performs a case-insensitive comparison between a Null-terminated
+  Unicode pattern string and a Null-terminated Unicode string.
+
+  @param  String   - A pointer to a Null-terminated Unicode string.
+  @param  Pattern  - A pointer to a Null-terminated Unicode pattern string.
+
+
+  @retval TRUE     - Pattern was found in String.
+  @retval FALSE    - Pattern was not found in String.
+
+**/
+BOOLEAN
+MetaiMatch (
+  IN CHAR16                           *String,
+  IN CHAR16                           *Pattern
+  );
+
+/**
+  Multiplies a 64-bit unsigned integer by a 32-bit unsigned integer and
+  generates a 64-bit unsigned result.
+
+  This function multiplies the 64-bit unsigned value Multiplicand by the 32-bit
+  unsigned value Multiplier and generates a 64-bit unsigned result. This 64-
+  bit unsigned result is returned.
+
+  @param  Multiplicand  A 64-bit unsigned value.
+  @param  Multiplier    A 32-bit unsigned value.
+
+  @return Multiplicand * Multiplier.
+
+**/
+UINT64
+MultU64x32 (
+  IN      UINT64                    Multiplicand,
+  IN      UINT32                    Multiplier
+  );
+
+/**
+  Divides a 64-bit unsigned integer by a 32-bit unsigned integer and generates
+  a 64-bit unsigned result.
+
+  This function divides the 64-bit unsigned value Dividend by the 32-bit
+  unsigned value Divisor and generates a 64-bit unsigned quotient. This
+  function returns the 64-bit unsigned quotient.
+
+  If Divisor is 0, then ASSERT().
+
+  @param  Dividend  A 64-bit unsigned value.
+  @param  Divisor   A 32-bit unsigned value.
+
+  @return Dividend / Divisor
+
+**/
+UINT64
+DivU64x32 (
+  IN      UINT64                    Dividend,
+  IN      UINT32                    Divisor
+  );
+
+/**
+  Shifts a 64-bit integer left between 0 and 63 bits. The low bits are filled
+  with zeros. The shifted value is returned.
+
+  This function shifts the 64-bit value Operand to the left by Count bits. The
+  low Count bits are set to zero. The shifted value is returned.
+
+  If Count is greater than 63, then ASSERT().
+
+  @param  Operand The 64-bit operand to shift left.
+  @param  Count   The number of bits to shift left.
+
+  @return Operand << Count.
+
+**/
+UINT64
+LShiftU64 (
+  IN      UINT64                    Operand,
+  IN      UINTN                     Count
+  );
+
+/**
+  Shifts a 64-bit integer right between 0 and 63 bits. This high bits are
+  filled with zeros. The shifted value is returned.
+
+  This function shifts the 64-bit value Operand to the right by Count bits. The
+  high Count bits are set to zero. The shifted value is returned.
+
+  If Count is greater than 63, then ASSERT().
+
+  @param  Operand The 64-bit operand to shift right.
+  @param  Count   The number of bits to shift right.
+
+  @return Operand >> Count.
+
+**/
+UINT64
+RShiftU64 (
+  IN      UINT64                    Operand,
+  IN      UINTN                     Count
+  );
+
+
+/**
+  Divides a 64-bit unsigned integer by a 32-bit unsigned integer and generates
+  a 64-bit unsigned result and an optional 32-bit unsigned remainder.
+
+  This function divides the 64-bit unsigned value Dividend by the 32-bit
+  unsigned value Divisor and generates a 64-bit unsigned quotient. If Remainder
+  is not NULL, then the 32-bit unsigned remainder is returned in Remainder.
+  This function returns the 64-bit unsigned quotient.
+
+  If Divisor is 0, then ASSERT().
+
+  @param  Dividend  A 64-bit unsigned value.
+  @param  Divisor   A 32-bit unsigned value.
+  @param  Remainder A pointer to a 32-bit unsigned value. This parameter is
+                    optional and may be NULL.
+
+  @return Dividend / Divisor
+
+**/
+UINT64
+DivU64x32Remainder (
+  IN      UINT64                    Dividend,
+  IN      UINT32                    Divisor,
+  OUT     UINT32                    *Remainder
+  );
+
+/**
+  Copies a buffer to an allocated buffer.
+
+  Allocates the number bytes specified by AllocationSize, copies allocationSize bytes
+  from Buffer to the newly allocated buffer, and returns a pointer to the allocated
+  buffer.  If AllocationSize is 0, then a valid buffer of 0 size is returned.  If there
+  is not enough memory remaining to satisfy the request, then NULL is returned.
+
+  If Buffer is NULL, then ASSERT().
+
+  @param  AllocationSize        The number of bytes to allocate and zero.
+  @param  Buffer                The buffer to copy to the allocated buffer.
+
+  @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+FceAllocateCopyPool (
+  IN UINTN       AllocationSize,
+  IN CONST VOID  *Buffer
+  );
+
+/**
+  Initializes the head node of a doubly-linked list, and returns the pointer to
+  the head node of the doubly-linked list.
+
+  Initializes the forward and backward links of a new linked list. After
+  initializing a linked list with this function, the other linked list
+  functions may be used to add and remove nodes from the linked list. It is up
+  to the caller of this function to allocate the memory for ListHead.
+
+  If ListHead is NULL, then ASSERT().
+
+  @param  ListHead  A pointer to the head node of a new doubly-linked list.
+
+  @return ListHead
+
+**/
+LIST_ENTRY *
+InitializeListHead (
+  IN OUT  LIST_ENTRY                *ListHead
+  );
+
+/**
+  Adds a node to the beginning of a doubly-linked list, and returns the pointer
+  to the head node of the doubly-linked list.
+
+  Adds the node Entry at the beginning of the doubly-linked list denoted by
+  ListHead, and returns ListHead.
+
+  If ListHead is NULL, then ASSERT().
+  If Entry is NULL, then ASSERT().
+  If ListHead was not initialized with INTIALIZE_LIST_HEAD_VARIABLE() or
+  InitializeListHead(), then ASSERT().
+  If PcdMaximumLinkedListLenth is not zero, and prior to insertion the number
+  of nodes in ListHead, including the ListHead node, is greater than or
+  equal to PcdMaximumLinkedListLength, then ASSERT().
+
+  @param  ListHead  A pointer to the head node of a doubly-linked list.
+  @param  Entry     A pointer to a node that is to be inserted at the beginning
+                    of a doubly-linked list.
+
+  @return ListHead
+
+**/
+LIST_ENTRY *
+InsertHeadList (
+  IN OUT  LIST_ENTRY                *ListHead,
+  IN OUT  LIST_ENTRY                *Entry
+  );
+
+/**
+  Adds a node to the end of a doubly-linked list, and returns the pointer to
+  the head node of the doubly-linked list.
+
+  Adds the node Entry to the end of the doubly-linked list denoted by ListHead,
+  and returns ListHead.
+
+  If ListHead is NULL, then ASSERT().
+  If Entry is NULL, then ASSERT().
+  If ListHead was not initialized with INTIALIZE_LIST_HEAD_VARIABLE() or
+  InitializeListHead(), then ASSERT().
+  If PcdMaximumLinkedListLenth is not zero, and prior to insertion the number
+  of nodes in ListHead, including the ListHead node, is greater than or
+  equal to PcdMaximumLinkedListLength, then ASSERT().
+
+  @param  ListHead  A pointer to the head node of a doubly-linked list.
+  @param  Entry     A pointer to a node that is to be added at the end of the
+                    doubly-linked list.
+
+  @return ListHead
+
+**/
+LIST_ENTRY *
+InsertTailList (
+  IN OUT  LIST_ENTRY                *ListHead,
+  IN OUT  LIST_ENTRY                *Entry
+  );
+
+/**
+  Retrieves the first node of a doubly-linked list.
+
+  Returns the first node of a doubly-linked list.  List must have been
+  initialized with INTIALIZE_LIST_HEAD_VARIABLE() or InitializeListHead().
+  If List is empty, then List is returned.
+
+  If List is NULL, then ASSERT().
+  If List was not initialized with INTIALIZE_LIST_HEAD_VARIABLE() or
+  InitializeListHead(), then ASSERT().
+  If PcdMaximumLinkedListLenth is not zero, and the number of nodes
+  in List, including the List node, is greater than or equal to
+  PcdMaximumLinkedListLength, then ASSERT().
+
+  @param  List  A pointer to the head node of a doubly-linked list.
+
+  @return The first node of a doubly-linked list.
+  @retval NULL  The list is empty.
+
+**/
+LIST_ENTRY *
+GetFirstNode (
+  IN      CONST LIST_ENTRY          *List
+  );
+
+/**
+  Retrieves the next node of a doubly-linked list.
+
+  Returns the node of a doubly-linked list that follows Node.
+  List must have been initialized with INTIALIZE_LIST_HEAD_VARIABLE()
+  or InitializeListHead().  If List is empty, then List is returned.
+
+  If List is NULL, then ASSERT().
+  If Node is NULL, then ASSERT().
+  If List was not initialized with INTIALIZE_LIST_HEAD_VARIABLE() or
+  InitializeListHead(), then ASSERT().
+  If PcdMaximumLinkedListLenth is not zero, and List contains more than
+  PcdMaximumLinkedListLenth nodes, then ASSERT().
+  If PcdVerifyNodeInList is TRUE and Node is not a node in List, then ASSERT().
+
+  @param  List  A pointer to the head node of a doubly-linked list.
+  @param  Node  A pointer to a node in the doubly-linked list.
+
+  @return A pointer to the next node if one exists. Otherwise List is returned.
+
+**/
+LIST_ENTRY *
+GetNextNode (
+  IN      CONST LIST_ENTRY          *List,
+  IN      CONST LIST_ENTRY          *Node
+  );
+
+/**
+  Retrieves the previous node of a doubly-linked list.
+
+  Returns the node of a doubly-linked list that precedes Node.
+  List must have been initialized with INTIALIZE_LIST_HEAD_VARIABLE()
+  or InitializeListHead().  If List is empty, then List is returned.
+
+  If List is NULL, then ASSERT().
+  If Node is NULL, then ASSERT().
+  If List was not initialized with INTIALIZE_LIST_HEAD_VARIABLE() or
+  InitializeListHead(), then ASSERT().
+  If PcdMaximumLinkedListLenth is not zero, and List contains more than
+  PcdMaximumLinkedListLenth nodes, then ASSERT().
+  If PcdVerifyNodeInList is TRUE and Node is not a node in List, then ASSERT().
+
+  @param  List  A pointer to the head node of a doubly-linked list.
+  @param  Node  A pointer to a node in the doubly-linked list.
+
+  @return A pointer to the previous node if one exists. Otherwise List is returned.
+
+**/
+LIST_ENTRY *
+GetPreviousNode (
+  IN      CONST LIST_ENTRY          *List,
+  IN      CONST LIST_ENTRY          *Node
+  );
+
+/**
+  Checks to see if a doubly-linked list is empty or not.
+
+  Checks to see if the doubly-linked list is empty. If the linked list contains
+  zero nodes, this function returns TRUE. Otherwise, it returns FALSE.
+
+  If ListHead is NULL, then ASSERT().
+  If ListHead was not initialized with INTIALIZE_LIST_HEAD_VARIABLE() or
+  InitializeListHead(), then ASSERT().
+  If PcdMaximumLinkedListLenth is not zero, and the number of nodes
+  in List, including the List node, is greater than or equal to
+  PcdMaximumLinkedListLength, then ASSERT().
+
+  @param  ListHead  A pointer to the head node of a doubly-linked list.
+
+  @retval TRUE  The linked list is empty.
+  @retval FALSE The linked list is not empty.
+
+**/
+BOOLEAN
+IsListEmpty (
+  IN      CONST LIST_ENTRY          *ListHead
+  );
+
+/**
+  Determines if a node in a doubly-linked list is the head node of a the same
+  doubly-linked list.  This function is typically used to terminate a loop that
+  traverses all the nodes in a doubly-linked list starting with the head node.
+
+  Returns TRUE if Node is equal to List.  Returns FALSE if Node is one of the
+  nodes in the doubly-linked list specified by List.  List must have been
+  initialized with INTIALIZE_LIST_HEAD_VARIABLE() or InitializeListHead().
+
+  If List is NULL, then ASSERT().
+  If Node is NULL, then ASSERT().
+  If List was not initialized with INTIALIZE_LIST_HEAD_VARIABLE() or InitializeListHead(),
+  then ASSERT().
+  If PcdMaximumLinkedListLenth is not zero, and the number of nodes
+  in List, including the List node, is greater than or equal to
+  PcdMaximumLinkedListLength, then ASSERT().
+  If PcdVerifyNodeInList is TRUE and Node is not a node in List and Node is not
+  equal to List, then ASSERT().
+
+  @param  List  A pointer to the head node of a doubly-linked list.
+  @param  Node  A pointer to a node in the doubly-linked list.
+
+  @retval TRUE  Node is the head of the doubly-linked list pointed by List.
+  @retval FALSE Node is not the head of the doubly-linked list pointed by List.
+
+**/
+BOOLEAN
+IsNull (
+  IN      CONST LIST_ENTRY          *List,
+  IN      CONST LIST_ENTRY          *Node
+  );
+
+/**
+  Determines if a node the last node in a doubly-linked list.
+
+  Returns TRUE if Node is the last node in the doubly-linked list specified by
+  List. Otherwise, FALSE is returned. List must have been initialized with
+  INTIALIZE_LIST_HEAD_VARIABLE() or InitializeListHead().
+
+  If List is NULL, then ASSERT().
+  If Node is NULL, then ASSERT().
+  If List was not initialized with INTIALIZE_LIST_HEAD_VARIABLE() or
+  InitializeListHead(), then ASSERT().
+  If PcdMaximumLinkedListLenth is not zero, and the number of nodes
+  in List, including the List node, is greater than or equal to
+  PcdMaximumLinkedListLength, then ASSERT().
+  If PcdVerifyNodeInList is TRUE and Node is not a node in List, then ASSERT().
+
+  @param  List  A pointer to the head node of a doubly-linked list.
+  @param  Node  A pointer to a node in the doubly-linked list.
+
+  @retval TRUE  Node is the last node in the linked list.
+  @retval FALSE Node is not the last node in the linked list.
+
+**/
+BOOLEAN
+IsNodeAtEnd (
+  IN      CONST LIST_ENTRY          *List,
+  IN      CONST LIST_ENTRY          *Node
+  );
+
+/**
+  Removes a node from a doubly-linked list, and returns the node that follows
+  the removed node.
+
+  Removes the node Entry from a doubly-linked list. It is up to the caller of
+  this function to release the memory used by this node if that is required. On
+  exit, the node following Entry in the doubly-linked list is returned. If
+  Entry is the only node in the linked list, then the head node of the linked
+  list is returned.
+
+  If Entry is NULL, then ASSERT().
+  If Entry is the head node of an empty list, then ASSERT().
+  If PcdMaximumLinkedListLength is not zero, and the number of nodes in the
+  linked list containing Entry, including the Entry node, is greater than
+  or equal to PcdMaximumLinkedListLength, then ASSERT().
+
+  @param  Entry A pointer to a node in a linked list.
+
+  @return Entry.
+
+**/
+LIST_ENTRY *
+RemoveEntryList (
+  IN      CONST LIST_ENTRY          *Entry
+  );
+
+#endif
diff --git a/Platform/Intel/Tools/FCE/Expression.c b/Platform/Intel/Tools/FCE/Expression.c
new file mode 100644
index 0000000000..34b310d97f
--- /dev/null
+++ b/Platform/Intel/Tools/FCE/Expression.c
@@ -0,0 +1,2367 @@
+/** @file
+
+ Utility functions for expression evaluation.
+
+ Copyright (c) 2011-2019, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "IfrParse.h"
+
+#define gEmptyString L""
+//
+// Global stack used to evaluate boolean expresions
+//
+EFI_HII_VALUE *mOpCodeScopeStack = NULL;
+EFI_HII_VALUE *mOpCodeScopeStackEnd = NULL;
+EFI_HII_VALUE *mOpCodeScopeStackPointer = NULL;
+
+EFI_HII_VALUE *mExpressionEvaluationStack = NULL;
+EFI_HII_VALUE *mExpressionEvaluationStackEnd = NULL;
+EFI_HII_VALUE *mExpressionEvaluationStackPointer = NULL;
+UINTN         mExpressionEvaluationStackOffset = 0;
+
+EFI_HII_VALUE *mCurrentExpressionStack = NULL;
+EFI_HII_VALUE *mCurrentExpressionEnd = NULL;
+EFI_HII_VALUE *mCurrentExpressionPointer = NULL;
+
+EFI_HII_VALUE *mMapExpressionListStack = NULL;
+EFI_HII_VALUE *mMapExpressionListEnd = NULL;
+EFI_HII_VALUE *mMapExpressionListPointer = NULL;
+
+/**
+  Get Value for given Name from a NameValue Storage.
+
+  @param  Storage                The NameValue Storage.
+  @param  Name                   The Name.
+  @param  Value                  The retured Value.
+
+  @retval EFI_SUCCESS            Value found for given Name.
+  @retval EFI_NOT_FOUND          No such Name found in NameValue storage.
+
+**/
+EFI_STATUS
+GetValueByName (
+  IN FORMSET_STORAGE         *Storage,
+  IN CHAR16                  *Name,
+  IN OUT CHAR16              **Value
+  )
+{
+  LIST_ENTRY              *Link;
+  NAME_VALUE_NODE         *Node;
+
+  *Value = NULL;
+
+  Link = GetFirstNode (&Storage->NameValueListHead);
+  while (!IsNull (&Storage->NameValueListHead, Link)) {
+    Node = NAME_VALUE_NODE_FROM_LINK (Link);
+
+    if (FceStrCmp (Name, Node->Name) == 0) {
+      NewStringCpy (Value, Node->EditValue);
+      return EFI_SUCCESS;
+    }
+
+    Link = GetNextNode (&Storage->NameValueListHead, Link);
+  }
+
+  return EFI_NOT_FOUND;
+}
+
+/**
+  Grow size of the stack.
+
+  This is an internal function.
+
+  @param  Stack                  On input: old stack; On output: new stack
+  @param  StackPtr               On input: old stack pointer; On output: new stack
+                                 pointer
+  @param  StackEnd               On input: old stack end; On output: new stack end
+
+  @retval EFI_SUCCESS            Grow stack success.
+  @retval EFI_OUT_OF_RESOURCES   No enough memory for stack space.
+
+**/
+EFI_STATUS
+GrowStack (
+  IN OUT EFI_HII_VALUE  **Stack,
+  IN OUT EFI_HII_VALUE  **StackPtr,
+  IN OUT EFI_HII_VALUE  **StackEnd
+  )
+{
+  UINTN           Size;
+  EFI_HII_VALUE  *NewStack;
+
+  Size = EXPRESSION_STACK_SIZE_INCREMENT;
+  if (*StackPtr != NULL) {
+    Size = Size + (*StackEnd - *Stack);
+  }
+
+  NewStack = AllocatePool (Size * sizeof (EFI_HII_VALUE));
+  if (NewStack == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  if (*StackPtr != NULL) {
+    //
+    // Copy from Old Stack to the New Stack
+    //
+    CopyMem (
+      NewStack,
+      *Stack,
+      (*StackEnd - *Stack) * sizeof (EFI_HII_VALUE)
+      );
+
+    //
+    // Free The Old Stack
+    //
+    FreePool (*Stack);
+  }
+
+  //
+  // Make the Stack pointer point to the old data in the new stack
+  //
+  *StackPtr = NewStack + (*StackPtr - *Stack);
+  *Stack    = NewStack;
+  *StackEnd = NewStack + Size;
+
+  return EFI_SUCCESS;
+}
+
+
+/**
+  Push an element onto the Boolean Stack.
+
+  @param  Stack                  On input: old stack; On output: new stack
+  @param  StackPtr               On input: old stack pointer; On output: new stack
+                                 pointer
+  @param  StackEnd               On input: old stack end; On output: new stack end
+  @param  Data                   Data to push.
+
+  @retval EFI_SUCCESS            Push stack success.
+
+**/
+EFI_STATUS
+PushStack (
+  IN OUT EFI_HII_VALUE       **Stack,
+  IN OUT EFI_HII_VALUE       **StackPtr,
+  IN OUT EFI_HII_VALUE       **StackEnd,
+  IN EFI_HII_VALUE           *Data
+  )
+{
+  EFI_STATUS  Status;
+
+  //
+  // Check for a stack overflow condition
+  //
+  if (*StackPtr >= *StackEnd) {
+    //
+    // Grow the stack
+    //
+    Status = GrowStack (Stack, StackPtr, StackEnd);
+    if (EFI_ERROR (Status)) {
+      return Status;
+    }
+  }
+
+  //
+  // Push the item onto the stack
+  //
+  CopyMem (*StackPtr, Data, sizeof (EFI_HII_VALUE));
+  *StackPtr = *StackPtr + 1;
+
+  return EFI_SUCCESS;
+}
+
+
+/**
+  Pop an element from the stack.
+
+  @param  Stack                  On input: old stack
+  @param  StackPtr               On input: old stack pointer; On output: new stack pointer
+  @param  Data                   Data to pop.
+
+  @retval EFI_SUCCESS            The value was popped onto the stack.
+  @retval EFI_ACCESS_DENIED      The pop operation underflowed the stack
+
+**/
+EFI_STATUS
+PopStack (
+  IN  EFI_HII_VALUE          *Stack,
+  IN OUT EFI_HII_VALUE       **StackPtr,
+  OUT EFI_HII_VALUE          *Data
+  )
+{
+  //
+  // Check for a stack underflow condition
+  //
+  if (*StackPtr == Stack) {
+    return EFI_ACCESS_DENIED;
+  }
+
+  //
+  // Pop the item off the stack
+  //
+  *StackPtr = *StackPtr - 1;
+  CopyMem (Data, *StackPtr, sizeof (EFI_HII_VALUE));
+  return EFI_SUCCESS;
+}
+
+
+/**
+  Reset stack pointer to begin of the stack.
+
+**/
+VOID
+ResetCurrentExpressionStack (
+  VOID
+  )
+{
+  mCurrentExpressionPointer = mCurrentExpressionStack;
+}
+
+
+/**
+  Push current expression onto the Stack
+
+  @param  Pointer                Pointer to current expression.
+
+  @retval EFI_SUCCESS            The value was pushed onto the stack.
+  @retval EFI_OUT_OF_RESOURCES   There is not enough system memory to grow the stack.
+
+**/
+EFI_STATUS
+PushCurrentExpression (
+  IN VOID  *Pointer
+  )
+{
+  EFI_HII_VALUE  Data;
+
+  Data.Type = EFI_IFR_TYPE_NUM_SIZE_64;
+  Data.Value.u64 = (UINT64) (UINTN) Pointer;
+
+  return PushStack (
+    &mCurrentExpressionStack,
+    &mCurrentExpressionPointer,
+    &mCurrentExpressionEnd,
+    &Data
+    );
+}
+
+
+/**
+  Pop current expression from the Stack
+
+  @param  Pointer                Pointer to current expression to be pop.
+
+  @retval EFI_SUCCESS            The value was pushed onto the stack.
+  @retval EFI_OUT_OF_RESOURCES   There is not enough system memory to grow the stack.
+
+**/
+EFI_STATUS
+PopCurrentExpression (
+  OUT VOID    **Pointer
+  )
+{
+  EFI_STATUS     Status;
+  EFI_HII_VALUE  Data;
+
+  Status = PopStack (
+    mCurrentExpressionStack,
+    &mCurrentExpressionPointer,
+    &Data
+    );
+
+  *Pointer = (VOID *) (UINTN) Data.Value.u64;
+
+  return Status;
+}
+
+/**
+  Reset stack pointer to begin of the stack.
+
+**/
+VOID
+ResetMapExpressionListStack (
+  VOID
+  )
+{
+  mMapExpressionListPointer = mMapExpressionListStack;
+}
+
+
+/**
+  Push the list of map expression onto the Stack
+
+  @param  Pointer                Pointer to the list of map expression to be pushed.
+
+  @retval EFI_SUCCESS            The value was pushed onto the stack.
+  @retval EFI_OUT_OF_RESOURCES   There is not enough system memory to grow the stack.
+
+**/
+EFI_STATUS
+PushMapExpressionList (
+  IN VOID  *Pointer
+  )
+{
+  EFI_HII_VALUE  Data;
+
+  Data.Type = EFI_IFR_TYPE_NUM_SIZE_64;
+  Data.Value.u64 = (UINT64) (UINTN) Pointer;
+
+  return PushStack (
+    &mMapExpressionListStack,
+    &mMapExpressionListPointer,
+    &mMapExpressionListEnd,
+    &Data
+    );
+}
+
+
+/**
+  Pop the list of map expression from the Stack
+
+  @param  Pointer                Pointer to the list of map expression to be pop.
+
+  @retval EFI_SUCCESS            The value was pushed onto the stack.
+  @retval EFI_OUT_OF_RESOURCES   There is not enough system memory to grow the stack.
+
+**/
+EFI_STATUS
+PopMapExpressionList (
+  OUT VOID    **Pointer
+  )
+{
+  EFI_STATUS     Status;
+  EFI_HII_VALUE  Data;
+
+  Status = PopStack (
+    mMapExpressionListStack,
+    &mMapExpressionListPointer,
+    &Data
+    );
+
+  *Pointer = (VOID *) (UINTN) Data.Value.u64;
+
+  return Status;
+}
+
+/**
+  Reset stack pointer to begin of the stack.
+
+**/
+VOID
+ResetScopeStack (
+  VOID
+  )
+{
+  mOpCodeScopeStackPointer = mOpCodeScopeStack;
+}
+
+
+/**
+  Push an Operand onto the Stack
+
+  @param  Operand                Operand to push.
+
+  @retval EFI_SUCCESS            The value was pushed onto the stack.
+  @retval EFI_OUT_OF_RESOURCES   There is not enough system memory to grow the
+                                 stack.
+
+**/
+EFI_STATUS
+PushScope (
+  IN UINT8   Operand
+  )
+{
+  EFI_HII_VALUE  Data;
+
+  Data.Type = EFI_IFR_TYPE_NUM_SIZE_8;
+  Data.Value.u8 = Operand;
+
+  return PushStack (
+           &mOpCodeScopeStack,
+           &mOpCodeScopeStackPointer,
+           &mOpCodeScopeStackEnd,
+           &Data
+           );
+}
+
+
+/**
+  Pop an Operand from the Stack
+
+  @param  Operand                Operand to pop.
+
+  @retval EFI_SUCCESS            The value was pushed onto the stack.
+  @retval EFI_OUT_OF_RESOURCES   There is not enough system memory to grow the
+                                 stack.
+
+**/
+EFI_STATUS
+PopScope (
+  OUT UINT8     *Operand
+  )
+{
+  EFI_STATUS     Status;
+  EFI_HII_VALUE  Data;
+
+  Status = PopStack (
+             mOpCodeScopeStack,
+             &mOpCodeScopeStackPointer,
+             &Data
+             );
+
+  *Operand = Data.Value.u8;
+
+  return Status;
+}
+
+
+/**
+  Push an Expression value onto the Stack
+
+  @param  Value                  Expression value to push.
+
+  @retval EFI_SUCCESS            The value was pushed onto the stack.
+  @retval EFI_OUT_OF_RESOURCES   There is not enough system memory to grow the
+                                 stack.
+
+**/
+EFI_STATUS
+PushExpression (
+  IN EFI_HII_VALUE  *Value
+  )
+{
+  return PushStack (
+           &mExpressionEvaluationStack,
+           &mExpressionEvaluationStackPointer,
+           &mExpressionEvaluationStackEnd,
+           Value
+           );
+}
+
+
+/**
+  Pop an Expression value from the stack.
+
+  @param  Value                  Expression value to pop.
+
+  @retval EFI_SUCCESS            The value was popped onto the stack.
+  @retval EFI_ACCESS_DENIED      The pop operation underflowed the stack
+
+**/
+EFI_STATUS
+PopExpression (
+  OUT EFI_HII_VALUE  *Value
+  )
+{
+  return PopStack (
+           mExpressionEvaluationStack + mExpressionEvaluationStackOffset,
+           &mExpressionEvaluationStackPointer,
+           Value
+           );
+}
+
+/**
+  Get current stack offset from stack start.
+
+  @return Stack offset to stack start.
+**/
+UINTN
+SaveExpressionEvaluationStackOffset (
+  )
+{
+  UINTN TempStackOffset;
+  TempStackOffset = mExpressionEvaluationStackOffset;
+  mExpressionEvaluationStackOffset = mExpressionEvaluationStackPointer - mExpressionEvaluationStack;
+  return TempStackOffset;
+}
+
+/**
+  Restore stack offset based on input stack offset
+
+  @param  StackOffset  Offset to stack start.
+
+**/
+VOID
+RestoreExpressionEvaluationStackOffset (
+  UINTN StackOffset
+  )
+{
+  mExpressionEvaluationStackOffset = StackOffset;
+}
+
+
+/**
+  Search a Question in Form scope using its QuestionId.
+
+  @param  Form                   The form which contains this Question.
+  @param  QuestionId             Id of this Question.
+
+  @retval Pointer                The Question.
+  @retval NULL                   Specified Question not found in the form.
+
+**/
+FORM_BROWSER_STATEMENT *
+IdToQuestion2 (
+  IN FORM_BROWSER_FORM  *Form,
+  IN UINT16             QuestionId
+  )
+{
+  LIST_ENTRY              *Link;
+  FORM_BROWSER_STATEMENT  *Question;
+
+  if (QuestionId == 0) {
+    //
+    // The value of zero is reserved
+    //
+    return NULL;
+  }
+
+  Link = GetFirstNode (&Form->StatementListHead);
+  while (!IsNull (&Form->StatementListHead, Link)) {
+    Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link);
+
+    if (Question->QuestionId == QuestionId) {
+      return Question;
+    }
+
+    Link = GetNextNode (&Form->StatementListHead, Link);
+  }
+
+  return NULL;
+}
+
+
+/**
+  Search a Question in Formset scope using its QuestionId.
+
+  @param  FormSet                The formset which contains this form.
+  @param  Form                   The form which contains this Question.
+  @param  QuestionId             Id of this Question.
+
+  @retval Pointer                The Question.
+  @retval NULL                   Specified Question not found in the form.
+
+**/
+FORM_BROWSER_STATEMENT *
+IdToQuestion (
+  IN FORM_BROWSER_FORMSET  *FormSet,
+  IN FORM_BROWSER_FORM     *Form,
+  IN UINT16                QuestionId
+  )
+{
+  LIST_ENTRY              *Link;
+  FORM_BROWSER_STATEMENT  *Question;
+
+  //
+  // Search in the form scope first
+  //
+  Question = IdToQuestion2 (Form, QuestionId);
+  if (Question != NULL) {
+    return Question;
+  }
+
+  //
+  // Search in the formset scope
+  //
+  Link = GetFirstNode (&FormSet->FormListHead);
+  while (!IsNull (&FormSet->FormListHead, Link)) {
+    Form = FORM_BROWSER_FORM_FROM_LINK (Link);
+
+    Question = IdToQuestion2 (Form, QuestionId);
+    if (Question != NULL) {
+      return Question;
+    }
+
+    Link = GetNextNode (&FormSet->FormListHead, Link);
+  }
+
+  return NULL;
+}
+
+
+/**
+  Get Expression given its RuleId.
+
+  @param  Form                   The form which contains this Expression.
+  @param  RuleId                 Id of this Expression.
+
+  @retval Pointer                The Expression.
+  @retval NULL                   Specified Expression not found in the form.
+
+**/
+FORM_EXPRESSION *
+RuleIdToExpression (
+  IN FORM_BROWSER_FORM  *Form,
+  IN UINT8              RuleId
+  )
+{
+  LIST_ENTRY       *Link;
+  FORM_EXPRESSION  *Expression;
+
+  Link = GetFirstNode (&Form->ExpressionListHead);
+  while (!IsNull (&Form->ExpressionListHead, Link)) {
+    Expression = FORM_EXPRESSION_FROM_LINK (Link);
+
+    if ((Expression->Type == EFI_HII_EXPRESSION_RULE) && (Expression->RuleId == RuleId)) {
+      return Expression;
+    }
+
+    Link = GetNextNode (&Form->ExpressionListHead, Link);
+  }
+
+  return NULL;
+}
+
+/**
+  Convert the input Unicode character to upper.
+
+  @param String  Th Unicode character to be converted.
+
+**/
+VOID
+IfrStrToUpper (
+  IN CHAR16                   *String
+  )
+{
+  while (*String != 0) {
+    if ((*String >= 'a') && (*String <= 'z')) {
+      *String = (UINT16) ((*String) & ((UINT16) ~0x20));
+    }
+    String++;
+  }
+}
+
+/**
+  Evaluate opcode EFI_IFR_TO_STRING.
+
+  @param  FormSet                Formset which contains this opcode.
+  @param  Format                 String format in EFI_IFR_TO_STRING.
+  @param  Result                 Evaluation result for this opcode.
+
+  @retval EFI_SUCCESS            Opcode evaluation success.
+  @retval Other                  Opcode evaluation failed.
+
+**/
+EFI_STATUS
+IfrToString (
+  IN FORM_BROWSER_FORMSET  *FormSet,
+  IN UINT8                 Format,
+  OUT  EFI_HII_VALUE       *Result
+  )
+{
+  EFI_STATUS     Status;
+  EFI_HII_VALUE  Value;
+  CHAR16         *PrintFormat;
+  CHAR16         Buffer[MAXIMUM_VALUE_CHARACTERS];
+  UINTN          BufferSize;
+
+  Status = PopExpression (&Value);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  switch (Value.Type) {
+  case EFI_IFR_TYPE_NUM_SIZE_8:
+  case EFI_IFR_TYPE_NUM_SIZE_16:
+  case EFI_IFR_TYPE_NUM_SIZE_32:
+  case EFI_IFR_TYPE_NUM_SIZE_64:
+    BufferSize = MAXIMUM_VALUE_CHARACTERS * sizeof (CHAR16);
+    switch (Format) {
+    case EFI_IFR_STRING_UNSIGNED_DEC:
+    case EFI_IFR_STRING_SIGNED_DEC:
+      PrintFormat = L"%ld";
+      break;
+
+    case EFI_IFR_STRING_LOWERCASE_HEX:
+      PrintFormat = L"%lx";
+      break;
+
+    case EFI_IFR_STRING_UPPERCASE_HEX:
+      PrintFormat = L"%lX";
+      break;
+
+    default:
+      return EFI_UNSUPPORTED;
+    }
+    UnicodeSPrint (Buffer, BufferSize, PrintFormat, Value.Value.u64);
+    break;
+
+  case EFI_IFR_TYPE_STRING:
+    CopyMem (Result, &Value, sizeof (EFI_HII_VALUE));
+    return EFI_SUCCESS;
+
+  case EFI_IFR_TYPE_BOOLEAN:
+    break;
+
+  default:
+    return EFI_UNSUPPORTED;
+  }
+
+  Result->Type = EFI_IFR_TYPE_STRING;
+  //Result->Value.string = NewString (String, FormSet->HiiHandle);
+  return EFI_SUCCESS;
+}
+
+/**
+  Evaluate opcode EFI_IFR_TO_UINT.
+
+  @param  FormSet                Formset which contains this opcode.
+  @param  Result                 Evaluation result for this opcode.
+
+  @retval EFI_SUCCESS            Opcode evaluation success.
+  @retval Other                  Opcode evaluation failed.
+
+**/
+EFI_STATUS
+IfrToUint (
+  IN FORM_BROWSER_FORMSET  *FormSet,
+  OUT  EFI_HII_VALUE       *Result
+  )
+{
+  EFI_STATUS     Status;
+  EFI_HII_VALUE  Value;
+  CHAR16         *String;
+  CHAR16         *StringPtr;
+
+  Status = PopExpression (&Value);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  if (Value.Type >= EFI_IFR_TYPE_OTHER) {
+    return EFI_UNSUPPORTED;
+  }
+
+  Status = EFI_SUCCESS;
+  if (Value.Type == EFI_IFR_TYPE_STRING) {
+    String = GetToken (Value.Value.string, FormSet->UnicodeBinary);
+    if (String == NULL) {
+      return EFI_NOT_FOUND;
+    }
+
+    IfrStrToUpper (String);
+    StringPtr = StrStr (String, L"0X");
+    if (StringPtr != NULL) {
+      //
+      // Hex string
+      //
+      Result->Value.u64 = FceStrHexToUint64 (String);
+    } else {
+      //
+      // decimal string
+      //
+      Result->Value.u64 = FceStrDecimalToUint64 (String);
+    }
+    FreePool (String);
+  } else {
+    CopyMem (Result, &Value, sizeof (EFI_HII_VALUE));
+  }
+
+  Result->Type = EFI_IFR_TYPE_NUM_SIZE_64;
+  return Status;
+}
+
+/**
+  Evaluate opcode EFI_IFR_CATENATE.
+
+  @param  FormSet                Formset which contains this opcode.
+  @param  Result                 Evaluation result for this opcode.
+
+  @retval EFI_SUCCESS            Opcode evaluation success.
+  @retval Other                  Opcode evaluation failed.
+
+**/
+EFI_STATUS
+IfrCatenate (
+  IN FORM_BROWSER_FORMSET  *FormSet,
+  OUT  EFI_HII_VALUE       *Result
+  )
+{
+  EFI_STATUS     Status;
+  EFI_HII_VALUE  Value;
+  CHAR16         *String[2];
+  UINTN          Index;
+  CHAR16         *StringPtr;
+  UINTN          Size;
+
+  //
+  // String[0] - The second string
+  // String[1] - The first string
+  //
+  String[0] = NULL;
+  String[1] = NULL;
+  StringPtr = NULL;
+  Status = EFI_SUCCESS;
+
+  for (Index = 0; Index < 2; Index++) {
+    Status = PopExpression (&Value);
+    if (EFI_ERROR (Status)) {
+      goto Done;
+    }
+
+    if (Value.Type != EFI_IFR_TYPE_STRING) {
+      Status = EFI_UNSUPPORTED;
+      goto Done;
+    }
+
+    String[Index] = GetToken (Value.Value.string, FormSet->UnicodeBinary);
+    if (String[Index] == NULL) {
+      Status = EFI_NOT_FOUND;
+      goto Done;
+    }
+  }
+
+  Size = FceStrSize (String[0]);
+  StringPtr= AllocatePool (FceStrSize (String[1]) + Size);
+  ASSERT (StringPtr != NULL);
+  StrCpy (StringPtr, String[1]);
+  StrCat (StringPtr, String[0]);
+
+  Result->Type = EFI_IFR_TYPE_STRING;
+  //Result->Value.string = NewString (StringPtr, FormSet->HiiHandle);
+
+Done:
+  if (String[0] != NULL) {
+    FreePool (String[0]);
+  }
+  if (String[1] != NULL) {
+    FreePool (String[1]);
+  }
+  if (StringPtr != NULL) {
+    FreePool (StringPtr);
+  }
+
+  return Status;
+}
+
+/**
+  Evaluate opcode EFI_IFR_MATCH.
+
+  @param  FormSet                Formset which contains this opcode.
+  @param  Result                 Evaluation result for this opcode.
+
+  @retval EFI_SUCCESS            Opcode evaluation success.
+  @retval Other                  Opcode evaluation failed.
+
+**/
+EFI_STATUS
+IfrMatch (
+  IN FORM_BROWSER_FORMSET  *FormSet,
+  OUT  EFI_HII_VALUE       *Result
+  )
+{
+  EFI_STATUS     Status;
+  EFI_HII_VALUE  Value;
+  CHAR16         *String[2];
+  UINTN          Index;
+
+  //
+  // String[0] - The string to search
+  // String[1] - pattern
+  //
+  String[0] = NULL;
+  String[1] = NULL;
+  Status = EFI_SUCCESS;
+  for (Index = 0; Index < 2; Index++) {
+    Status = PopExpression (&Value);
+    if (EFI_ERROR (Status)) {
+      goto Done;
+    }
+
+    if (Value.Type != EFI_IFR_TYPE_STRING) {
+      Status = EFI_UNSUPPORTED;
+      goto Done;
+    }
+
+    String[Index] = GetToken (Value.Value.string, FormSet->UnicodeBinary);
+    if (String [Index] == NULL) {
+      Status = EFI_NOT_FOUND;
+      goto Done;
+    }
+  }
+
+  Result->Type = EFI_IFR_TYPE_BOOLEAN;
+  Result->Value.b = MetaiMatch (String[0], String[1]);
+
+Done:
+  if (String[0] != NULL) {
+    FreePool (String[0]);
+  }
+  if (String[1] != NULL) {
+    FreePool (String[1]);
+  }
+
+  return Status;
+}
+
+
+/**
+  Evaluate opcode EFI_IFR_FIND.
+
+  @param  FormSet                Formset which contains this opcode.
+  @param  Format                 Case sensitive or insensitive.
+  @param  Result                 Evaluation result for this opcode.
+
+  @retval EFI_SUCCESS            Opcode evaluation success.
+  @retval Other                  Opcode evaluation failed.
+
+**/
+EFI_STATUS
+IfrFind (
+  IN FORM_BROWSER_FORMSET  *FormSet,
+  IN UINT8                 Format,
+  OUT  EFI_HII_VALUE       *Result
+  )
+{
+  EFI_STATUS     Status;
+  EFI_HII_VALUE  Value;
+  CHAR16         *String[2];
+  UINTN          Base;
+  CHAR16         *StringPtr;
+  UINTN          Index;
+
+  if (Format > EFI_IFR_FF_CASE_INSENSITIVE) {
+    return EFI_UNSUPPORTED;
+  }
+
+  Status = PopExpression (&Value);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+  if (Value.Type > EFI_IFR_TYPE_NUM_SIZE_64) {
+    return EFI_UNSUPPORTED;
+  }
+  Base = (UINTN) Value.Value.u64;
+
+  //
+  // String[0] - sub-string
+  // String[1] - The string to search
+  //
+  String[0] = NULL;
+  String[1] = NULL;
+  for (Index = 0; Index < 2; Index++) {
+    Status = PopExpression (&Value);
+    if (EFI_ERROR (Status)) {
+      goto Done;
+    }
+
+    if (Value.Type != EFI_IFR_TYPE_STRING) {
+      Status = EFI_UNSUPPORTED;
+      goto Done;
+    }
+
+    String[Index] = GetToken (Value.Value.string, FormSet->UnicodeBinary);
+    if (String[Index] == NULL) {
+      Status = EFI_NOT_FOUND;
+      goto Done;
+    }
+
+    if (Format == EFI_IFR_FF_CASE_INSENSITIVE) {
+      //
+      // Case insensitive, convert both string to upper case
+      //
+      IfrStrToUpper (String[Index]);
+    }
+  }
+
+  Result->Type = EFI_IFR_TYPE_NUM_SIZE_64;
+  if (Base >= FceStrLen (String[1])) {
+    Result->Value.u64 = 0xFFFFFFFFFFFFFFFFULL;
+  } else {
+    StringPtr = StrStr (String[1] + Base, String[0]);
+    Result->Value.u64 = (StringPtr == NULL) ? 0xFFFFFFFFFFFFFFFFULL : (StringPtr - String[1]);
+  }
+
+Done:
+  if (String[0] != NULL) {
+    FreePool (String[0]);
+  }
+  if (String[1] != NULL) {
+    FreePool (String[1]);
+  }
+
+  return Status;
+}
+
+
+/**
+  Evaluate opcode EFI_IFR_MID.
+
+  @param  FormSet                Formset which contains this opcode.
+  @param  Result                 Evaluation result for this opcode.
+
+  @retval EFI_SUCCESS            Opcode evaluation success.
+  @retval Other                  Opcode evaluation failed.
+
+**/
+EFI_STATUS
+IfrMid (
+  IN FORM_BROWSER_FORMSET  *FormSet,
+  OUT  EFI_HII_VALUE       *Result
+  )
+{
+  EFI_STATUS     Status;
+  EFI_HII_VALUE  Value;
+  CHAR16         *String;
+  UINTN          Base;
+  UINTN          Length;
+  CHAR16         *SubString;
+
+  Status = PopExpression (&Value);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+  if (Value.Type > EFI_IFR_TYPE_NUM_SIZE_64) {
+    return EFI_UNSUPPORTED;
+  }
+  Length = (UINTN) Value.Value.u64;
+
+  Status = PopExpression (&Value);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+  if (Value.Type > EFI_IFR_TYPE_NUM_SIZE_64) {
+    return EFI_UNSUPPORTED;
+  }
+  Base = (UINTN) Value.Value.u64;
+
+  Status = PopExpression (&Value);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+  if (Value.Type != EFI_IFR_TYPE_STRING) {
+    return EFI_UNSUPPORTED;
+  }
+  String = GetToken (Value.Value.string, FormSet->UnicodeBinary);
+  if (String == NULL) {
+    return EFI_NOT_FOUND;
+  }
+
+  if ((Length == 0) || (Base >= FceStrLen (String))) {
+    SubString = gEmptyString;
+  } else {
+    SubString = String + Base;
+    if ((Base + Length) < FceStrLen (String)) {
+      SubString[Length] = L'\0';
+    }
+  }
+
+  Result->Type = EFI_IFR_TYPE_STRING;
+  //Result->Value.string = NewString (SubString, FormSet->HiiHandle);
+
+  FreePool (String);
+
+  return Status;
+}
+
+/**
+  Evaluate opcode EFI_IFR_TOKEN.
+
+  @param  FormSet                Formset which contains this opcode.
+  @param  Result                 Evaluation result for this opcode.
+
+  @retval EFI_SUCCESS            Opcode evaluation success.
+  @retval Other                  Opcode evaluation failed.
+
+**/
+EFI_STATUS
+IfrToken (
+  IN FORM_BROWSER_FORMSET  *FormSet,
+  OUT  EFI_HII_VALUE       *Result
+  )
+{
+  EFI_STATUS     Status;
+  EFI_HII_VALUE  Value;
+  CHAR16         *String[2];
+  UINTN          Count;
+  CHAR16         *Delimiter;
+  CHAR16         *SubString;
+  CHAR16         *StringPtr;
+  UINTN          Index;
+
+  Status = PopExpression (&Value);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+  if (Value.Type > EFI_IFR_TYPE_NUM_SIZE_64) {
+    return EFI_UNSUPPORTED;
+  }
+  Count = (UINTN) Value.Value.u64;
+
+  //
+  // String[0] - Delimiter
+  // String[1] - The string to search
+  //
+  String[0] = NULL;
+  String[1] = NULL;
+  for (Index = 0; Index < 2; Index++) {
+    Status = PopExpression (&Value);
+    if (EFI_ERROR (Status)) {
+      goto Done;
+    }
+
+    if (Value.Type != EFI_IFR_TYPE_STRING) {
+      Status = EFI_UNSUPPORTED;
+      goto Done;
+    }
+
+    String[Index] = GetToken (Value.Value.string, FormSet->UnicodeBinary);
+    if (String[Index] == NULL) {
+      Status = EFI_NOT_FOUND;
+      goto Done;
+    }
+  }
+
+  Delimiter = String[0];
+  SubString = String[1];
+  while (Count > 0) {
+    SubString = StrStr (SubString, Delimiter);
+    if (SubString != NULL) {
+      //
+      // Skip over the delimiter
+      //
+      SubString = SubString + FceStrLen (Delimiter);
+    } else {
+      break;
+    }
+    Count--;
+  }
+
+  if (SubString == NULL) {
+    //
+    // nth delimited sub-string not found, push an empty string
+    //
+    SubString = gEmptyString;
+  } else {
+    //
+    // Put a NULL terminator for nth delimited sub-string
+    //
+    StringPtr = StrStr (SubString, Delimiter);
+    if (StringPtr != NULL) {
+      *StringPtr = L'\0';
+    }
+  }
+
+  Result->Type = EFI_IFR_TYPE_STRING;
+  //Result->Value.string = NewString (SubString, FormSet->HiiHandle);
+
+Done:
+  if (String[0] != NULL) {
+    FreePool (String[0]);
+  }
+  if (String[1] != NULL) {
+    FreePool (String[1]);
+  }
+
+  return Status;
+}
+
+
+/**
+  Evaluate opcode EFI_IFR_SPAN.
+
+  @param  FormSet                Formset which contains this opcode.
+  @param  Flags                  FIRST_MATCHING or FIRST_NON_MATCHING.
+  @param  Result                 Evaluation result for this opcode.
+
+  @retval EFI_SUCCESS            Opcode evaluation success.
+  @retval Other                  Opcode evaluation failed.
+
+**/
+EFI_STATUS
+IfrSpan (
+  IN FORM_BROWSER_FORMSET  *FormSet,
+  IN UINT8                 Flags,
+  OUT  EFI_HII_VALUE       *Result
+  )
+{
+  EFI_STATUS     Status;
+  EFI_HII_VALUE  Value;
+  CHAR16         *String[2];
+  CHAR16         *Charset;
+  UINTN          Base;
+  UINTN          Index;
+  CHAR16         *StringPtr;
+  BOOLEAN        Found;
+
+  Status = PopExpression (&Value);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+  if (Value.Type > EFI_IFR_TYPE_NUM_SIZE_64) {
+    return EFI_UNSUPPORTED;
+  }
+  Base = (UINTN) Value.Value.u64;
+
+  //
+  // String[0] - Charset
+  // String[1] - The string to search
+  //
+  String[0] = NULL;
+  String[1] = NULL;
+  for (Index = 0; Index < 2; Index++) {
+    Status = PopExpression (&Value);
+    if (EFI_ERROR (Status)) {
+      goto Done;
+    }
+
+    if (Value.Type != EFI_IFR_TYPE_STRING) {
+      Status = EFI_UNSUPPORTED;
+      goto Done;
+    }
+
+    String[Index] = GetToken (Value.Value.string, FormSet->UnicodeBinary);
+    if (String [Index] == NULL) {
+      Status = EFI_NOT_FOUND;
+      goto Done;
+    }
+  }
+
+  if (Base >= FceStrLen (String[1])) {
+    Status = EFI_UNSUPPORTED;
+    goto Done;
+  }
+
+  Found = FALSE;
+  StringPtr = String[1] + Base;
+  Charset = String[0];
+  while (*StringPtr != 0 && !Found) {
+    Index = 0;
+    while (Charset[Index] != 0) {
+      if ((*StringPtr >= Charset[Index]) && (*StringPtr <= Charset[Index + 1])) {
+        if (Flags == EFI_IFR_FLAGS_FIRST_MATCHING) {
+          Found = TRUE;
+          break;
+        }
+      } else {
+        if (Flags == EFI_IFR_FLAGS_FIRST_NON_MATCHING) {
+          Found = TRUE;
+          break;
+        }
+      }
+      //
+      // Skip characters pair representing low-end of a range and high-end of a range
+      //
+      Index += 2;
+    }
+
+    if (!Found) {
+      StringPtr++;
+    }
+  }
+
+  Result->Type = EFI_IFR_TYPE_NUM_SIZE_64;
+  Result->Value.u64 = StringPtr - String[1];
+
+Done:
+  if (String[0] != NULL) {
+    FreePool (String[0]);
+  }
+  if (String[1] != NULL) {
+    FreePool (String[1]);
+  }
+
+  return Status;
+}
+
+
+/**
+  Zero extend integer/boolean/date/time to UINT64 for comparing.
+
+  @param  Value                  HII Value to be converted.
+
+**/
+VOID
+ExtendValueToU64 (
+  IN  EFI_HII_VALUE   *Value
+  )
+{
+  UINT64  Temp;
+
+  Temp = 0;
+  switch (Value->Type) {
+  case EFI_IFR_TYPE_NUM_SIZE_8:
+    Temp = Value->Value.u8;
+    break;
+
+  case EFI_IFR_TYPE_NUM_SIZE_16:
+    Temp = Value->Value.u16;
+    break;
+
+  case EFI_IFR_TYPE_NUM_SIZE_32:
+    Temp = Value->Value.u32;
+    break;
+
+  case EFI_IFR_TYPE_BOOLEAN:
+    Temp = Value->Value.b;
+    break;
+
+  case EFI_IFR_TYPE_TIME:
+    Temp = Value->Value.u32 & 0xffffff;
+    break;
+
+  case EFI_IFR_TYPE_DATE:
+    Temp = Value->Value.u32;
+    break;
+
+  default:
+    return;
+  }
+
+  Value->Value.u64 = Temp;
+}
+
+
+/**
+  Compare two Hii value.
+
+  @param  Value1                 Expression value to compare on left-hand.
+  @param  Value2                 Expression value to compare on right-hand.
+  @param  FormSet                The pointer to the Formset.
+
+  @retval EFI_INVALID_PARAMETER  Could not perform compare on two values.
+  @retval 0                      Two operators equal.
+  @return Positive value if Value1 is greater than Value2.
+  @retval Negative value if Value1 is less than Value2.
+
+**/
+INTN
+CompareHiiValue (
+  IN  EFI_HII_VALUE        *Value1,
+  IN  EFI_HII_VALUE        *Value2,
+  IN FORM_BROWSER_FORMSET  *FormSet
+  )
+{
+  INTN    Result;
+  INT64   Temp64;
+  CHAR16  *Str1;
+  CHAR16  *Str2;
+
+  if ((Value1->Type >= EFI_IFR_TYPE_OTHER) || (Value2->Type >= EFI_IFR_TYPE_OTHER) ) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if ((Value1->Type == EFI_IFR_TYPE_STRING) || (Value2->Type == EFI_IFR_TYPE_STRING) ) {
+    if (Value1->Type != Value2->Type) {
+      //
+      // Both Operator should be type of String
+      //
+      return EFI_INVALID_PARAMETER;
+    }
+
+    if ((Value1->Value.string == 0) || (Value2->Value.string == 0)) {
+      //
+      // StringId 0 is reserved
+      //
+      return EFI_INVALID_PARAMETER;
+    }
+
+    if (Value1->Value.string == Value2->Value.string) {
+      return 0;
+    }
+
+    Str1 = GetToken (Value1->Value.string, FormSet->UnicodeBinary);
+    if (Str1 == NULL) {
+      //
+      // String not found
+      //
+      return EFI_INVALID_PARAMETER;
+    }
+
+    Str2 = GetToken (Value2->Value.string, FormSet->UnicodeBinary);
+    if (Str2 == NULL) {
+      FreePool (Str1);
+      return EFI_INVALID_PARAMETER;
+    }
+
+    Result = FceStrCmp (Str1, Str2);
+
+    FreePool (Str1);
+    FreePool (Str2);
+
+    return Result;
+  }
+
+  //
+  // Take remain types(integer, boolean, date/time) as integer
+  //
+  Temp64 = (INT64) (Value1->Value.u64 - Value2->Value.u64);
+  if (Temp64 > 0) {
+    Result = 1;
+  } else if (Temp64 < 0) {
+    Result = -1;
+  } else {
+    Result = 0;
+  }
+
+  return Result;
+}
+
+/**
+  Tell whether this Operand is an constant Expression or not
+
+  @param  Operand                Operand of an IFR OpCode.
+
+  @retval TRUE                   This is an Expression OpCode.
+  @retval FALSE                  Not an Expression OpCode.
+
+**/
+BOOLEAN
+IsConstantExpressionOpCode (
+  IN UINT8              Operand
+  )
+{
+  if ((Operand == EFI_IFR_EQ_ID_VAL_OP)      ||
+      (Operand == EFI_IFR_EQ_ID_ID_OP)       ||
+      (Operand == EFI_IFR_EQ_ID_VAL_LIST_OP )||
+      (Operand == EFI_IFR_QUESTION_REF1_OP)  ||
+      (Operand == EFI_IFR_QUESTION_REF2_OP)  ||
+      (Operand == EFI_IFR_QUESTION_REF3_OP)  ||
+      (Operand == EFI_IFR_THIS_OP )          ||
+      (Operand == EFI_IFR_SECURITY_OP)       ||
+      (Operand == EFI_IFR_GET_OP)            ||
+      (Operand == EFI_IFR_SET_OP)
+      ) {
+    return FALSE;
+  } else {
+    return TRUE;
+  }
+}
+
+/**
+  Update the HiiValue of question from its variable.
+
+  @param  FormSet        FormSet associated with this expression.
+  @param  Question       The pointer to the Question
+
+  @return EFI_SUCCESS
+  @return EFI_NOT_FOUND
+**/
+EFI_STATUS
+UpdateHiiValue (
+  IN     FORM_BROWSER_FORMSET     *FormSet,
+  IN     FORM_BROWSER_STATEMENT   *Question
+  )
+{
+  EFI_STATUS              Status;
+  FORMSET_STORAGE         *VarList;
+  UINT8                   *VarBuffer;
+  EFI_HII_VALUE           *HiiValue;
+
+  Status   = EFI_SUCCESS;
+  HiiValue = &Question->HiiValue;
+
+  Status = SearchVarStorage (
+             Question,
+             NULL,
+             Question->VarStoreInfo.VarOffset,
+             FormSet->StorageListHead,
+             (CHAR8 **)&VarBuffer,
+             &VarList
+             );
+    if (EFI_ERROR(Status)) {
+      return Status;
+    }
+    if (Question->QuestionReferToBitField) {
+      GetBitsQuestionValue (Question, VarBuffer, &HiiValue->Value.u32);
+    } else {
+      CopyMem (&HiiValue->Value.u64, VarBuffer, Question->StorageWidth);
+    }
+    return Status;
+}
+/**
+  Evaluate the result of a HII expression.
+
+  If Expression is NULL, then ASSERT.
+
+  @param  FormSet                FormSet associated with this expression.
+  @param  Form                   Form associated with this expression.
+  @param  Expression             Expression to be evaluated.
+  @param  ConstantExpression     The pointer to the flag of constant expression. If constant, will return TRUE.
+
+  @retval EFI_SUCCESS            The expression evaluated successfuly
+  @retval EFI_NOT_FOUND          The Question which referenced by a QuestionId
+                                 could not be found.
+  @retval EFI_OUT_OF_RESOURCES   There is not enough system memory to grow the
+                                 stack.
+  @retval EFI_ACCESS_DENIED      The pop operation underflowed the stack
+  @retval EFI_INVALID_PARAMETER  Syntax error with the Expression
+
+**/
+EFI_STATUS
+EvaluateExpression (
+  IN FORM_BROWSER_FORMSET  *FormSet,
+  IN FORM_BROWSER_FORM     *Form,
+  IN OUT FORM_EXPRESSION   *Expression,
+  IN OUT BOOLEAN           *ConstantExpression
+  )
+{
+  EFI_STATUS              Status;
+  LIST_ENTRY              *Link;
+  EXPRESSION_OPCODE       *OpCode;
+  FORM_BROWSER_STATEMENT  *Question;
+  FORM_BROWSER_STATEMENT  *Question2;
+  UINT16                  Index;
+  EFI_HII_VALUE           Data1;
+  EFI_HII_VALUE           Data2;
+  EFI_HII_VALUE           Data3;
+  FORM_EXPRESSION         *RuleExpression;
+  EFI_HII_VALUE           *Value;
+  INTN                    Result;
+  CHAR16                  *StrPtr;
+  UINT32                  TempValue;
+  LIST_ENTRY              *SubExpressionLink;
+  FORM_EXPRESSION         *SubExpression;
+  UINTN                   StackOffset;
+  UINTN                   TempLength;
+  CHAR16                  TempStr[5];
+  UINT8                   DigitUint8;
+  UINT8                   *TempBuffer;
+
+  //
+  // Save current stack offset.
+  //
+  StackOffset = SaveExpressionEvaluationStackOffset ();
+
+  ASSERT (Expression != NULL);
+  Expression->Result.Type = EFI_IFR_TYPE_OTHER;
+
+  Link = GetFirstNode (&Expression->OpCodeListHead);
+  while (!IsNull (&Expression->OpCodeListHead, Link)) {
+    OpCode = EXPRESSION_OPCODE_FROM_LINK (Link);
+
+    Link = GetNextNode (&Expression->OpCodeListHead, Link);
+
+    ZeroMem (&Data1, sizeof (EFI_HII_VALUE));
+    ZeroMem (&Data2, sizeof (EFI_HII_VALUE));
+    ZeroMem (&Data3, sizeof (EFI_HII_VALUE));
+
+    Value = &Data3;
+    Value->Type = EFI_IFR_TYPE_BOOLEAN;
+    Status = EFI_SUCCESS;
+
+    //
+    // Check whether it is a constant expression or not
+    //
+    if (*ConstantExpression) {
+      *ConstantExpression = IsConstantExpressionOpCode (OpCode->Operand);
+    }
+
+    switch (OpCode->Operand) {
+    //
+    // Built-in functions
+    //
+    case EFI_IFR_EQ_ID_VAL_OP:
+      Question = IdToQuestion (FormSet, Form, OpCode->QuestionId);
+      if (Question == NULL) {
+        Status = EFI_NOT_FOUND;
+        goto Done;
+      }
+      UpdateHiiValue (FormSet, Question);
+      Result = CompareHiiValue (&Question->HiiValue, &OpCode->Value, FormSet);
+      if ((EFI_STATUS)Result == EFI_INVALID_PARAMETER) {
+        Status = EFI_INVALID_PARAMETER;
+        goto Done;
+      }
+      Value->Value.b = (BOOLEAN) ((Result == 0) ? TRUE : FALSE);
+      break;
+
+    case EFI_IFR_EQ_ID_ID_OP:
+      Question = IdToQuestion (FormSet, Form, OpCode->QuestionId);
+      if (Question == NULL) {
+        Status = EFI_NOT_FOUND;
+        goto Done;
+      }
+
+      Question2 = IdToQuestion (FormSet, Form, OpCode->QuestionId2);
+      if (Question2 == NULL) {
+        Status = EFI_NOT_FOUND;
+        goto Done;
+      }
+      UpdateHiiValue (FormSet, Question);
+      UpdateHiiValue (FormSet, Question2);
+      Result = CompareHiiValue (&Question->HiiValue, &Question2->HiiValue, FormSet);
+      if ((EFI_STATUS)Result == EFI_INVALID_PARAMETER) {
+        Status = EFI_INVALID_PARAMETER;
+        goto Done;
+      }
+      Value->Value.b = (BOOLEAN) ((Result == 0) ? TRUE : FALSE);
+      break;
+
+    case EFI_IFR_EQ_ID_VAL_LIST_OP:
+
+      Question = IdToQuestion (FormSet, Form, OpCode->QuestionId);
+      if (Question == NULL) {
+        Status = EFI_NOT_FOUND;
+        goto Done;
+      }
+      UpdateHiiValue (FormSet, Question);
+      Value->Value.b = FALSE;
+      for (Index =0; Index < OpCode->ListLength; Index++) {
+        if (Question->HiiValue.Value.u16 == OpCode->ValueList[Index]) {
+          Value->Value.b = TRUE;
+          break;
+        }
+      }
+      break;
+
+    case EFI_IFR_DUP_OP:
+      Status = PopExpression (Value);
+      if (EFI_ERROR (Status)) {
+        goto Done;
+      }
+
+      Status = PushExpression (Value);
+      break;
+
+    case EFI_IFR_QUESTION_REF1_OP:
+    case EFI_IFR_THIS_OP:
+      Question = IdToQuestion (FormSet, Form, OpCode->QuestionId);
+      if (Question == NULL) {
+        Status = EFI_NOT_FOUND;
+        goto Done;
+      }
+      UpdateHiiValue (FormSet, Question);
+      Value = &Question->HiiValue;
+      break;
+
+    case EFI_IFR_SECURITY_OP:
+      //
+      // Do nothing, as no need for static scaning
+      //
+      break;
+
+    case EFI_IFR_GET_OP:
+      //
+      // Get Value from VarStore buffer, EFI VarStore, Name/Value VarStore.
+      //
+      Value->Type = EFI_IFR_TYPE_UNDEFINED;
+      Value->Value.u8 = 0;
+      if (OpCode->VarStorage != NULL) {
+        switch (OpCode->VarStorage->Type) {
+        case EFI_IFR_VARSTORE_OP:
+      //
+          // Get value from Buffer
+          //
+          Value->Type = OpCode->ValueType;
+          CopyMem (&Value->Value, OpCode->VarStorage->Buffer + OpCode->VarStoreInfo.VarOffset, OpCode->ValueWidth);
+      break;
+
+        case EFI_IFR_VARSTORE_EFI_OP:
+          //
+          // Get value from Buffer
+          //
+      if (OpCode->VarStorage->NewEfiVarstore) {
+            Value->Type = OpCode->ValueType;
+            CopyMem (&Value->Value, OpCode->VarStorage->Buffer + OpCode->VarStoreInfo.VarOffset, OpCode->ValueWidth);
+      } else {
+        CopyMem (&Value->Value, OpCode->VarStorage->Buffer, OpCode->ValueWidth);
+      }
+
+
+      break;
+        case EFI_HII_VARSTORE_NAME_VALUE:
+          if (OpCode->ValueType != EFI_IFR_TYPE_STRING) {
+            //
+            // Get value from string except for STRING value.
+            //
+            Status = GetValueByName (OpCode->VarStorage, OpCode->ValueName, &StrPtr);
+            if (!EFI_ERROR (Status)) {
+              ASSERT (StrPtr != NULL);
+              TempLength = FceStrLen (StrPtr);
+              if (OpCode->ValueWidth >= ((TempLength + 1) / 2)) {
+                Value->Type = OpCode->ValueType;
+                TempBuffer = (UINT8 *) &Value->Value;
+                ZeroMem (TempStr, sizeof (TempStr));
+                for (Index = 0; Index < TempLength; Index ++) {
+                  TempStr[0] = StrPtr[TempLength - Index - 1];
+                  DigitUint8 = (UINT8) FceStrHexToUint64 (TempStr);
+                  if ((Index & 1) == 0) {
+                    TempBuffer [Index/2] = DigitUint8;
+                  } else {
+                    TempBuffer [Index/2] = (UINT8) ((DigitUint8 << 4) + TempBuffer [Index/2]);
+                  }
+                }
+              }
+              free (StrPtr);
+              StrPtr = NULL;
+            }
+          }
+          break;
+        default:
+          //
+          // Not recognize storage.
+          //
+          Status = EFI_UNSUPPORTED;
+          goto Done;
+        }
+      }
+
+      break;
+
+    case EFI_IFR_QUESTION_REF3_OP:
+      if (OpCode->DevicePath == 0) {
+        //
+        // EFI_IFR_QUESTION_REF3
+        // Pop an expression from the expression stack
+        //
+        Status = PopExpression (Value);
+        if (EFI_ERROR (Status)) {
+          goto Done;
+        }
+
+        //
+        // Validate the expression value
+        //
+        if ((Value->Type > EFI_IFR_TYPE_NUM_SIZE_64) || (Value->Value.u64 > 0xffff)) {
+          Status = EFI_NOT_FOUND;
+          goto Done;
+        }
+
+        Question = IdToQuestion (FormSet, Form, Value->Value.u16);
+        if (Question == NULL) {
+          Status = EFI_NOT_FOUND;
+          goto Done;
+        }
+
+        //
+        // push the questions' value on to the expression stack
+        //
+        Value = &Question->HiiValue;
+      } else {
+        //
+        // BUGBUG: push 0 for EFI_IFR_QUESTION_REF3_2 and EFI_IFR_QUESTION_REF3_3,
+        // since it is impractical to evaluate the value of a Question in another
+        // Hii Package list.
+        //
+        ZeroMem (Value, sizeof (EFI_HII_VALUE));
+      }
+      break;
+
+    case EFI_IFR_RULE_REF_OP:
+      //
+      // Find expression for this rule
+      //
+      RuleExpression = RuleIdToExpression (Form, OpCode->RuleId);
+      if (RuleExpression == NULL) {
+        Status = EFI_NOT_FOUND;
+        goto Done;
+      }
+
+      //
+      // Evaluate this rule expression
+      //
+      Status = EvaluateExpression (FormSet, Form, RuleExpression, ConstantExpression);
+      if (EFI_ERROR (Status)) {
+        goto Done;
+      }
+
+      Value = &RuleExpression->Result;
+      break;
+
+    case EFI_IFR_STRING_REF1_OP:
+      Value->Type = EFI_IFR_TYPE_STRING;
+      Value->Value.string = OpCode->Value.Value.string;
+      break;
+
+    //
+    // Constant
+    //
+    case EFI_IFR_TRUE_OP:
+    case EFI_IFR_FALSE_OP:
+    case EFI_IFR_ONE_OP:
+    case EFI_IFR_ONES_OP:
+    case EFI_IFR_UINT8_OP:
+    case EFI_IFR_UINT16_OP:
+    case EFI_IFR_UINT32_OP:
+    case EFI_IFR_UINT64_OP:
+    case EFI_IFR_UNDEFINED_OP:
+    case EFI_IFR_VERSION_OP:
+    case EFI_IFR_ZERO_OP:
+      Value = &OpCode->Value;
+      break;
+
+    //
+    // unary-op
+    //
+    case EFI_IFR_LENGTH_OP:
+      Status = PopExpression (Value);
+      if (EFI_ERROR (Status)) {
+        goto Done;
+      }
+      if (Value->Type != EFI_IFR_TYPE_STRING) {
+        Status = EFI_INVALID_PARAMETER;
+        goto Done;
+      }
+
+      StrPtr = GetToken (Value->Value.string, FormSet->UnicodeBinary);
+      if (StrPtr == NULL) {
+        Status = EFI_INVALID_PARAMETER;
+        goto Done;
+      }
+
+      Value->Type = EFI_IFR_TYPE_NUM_SIZE_64;
+      Value->Value.u64 = FceStrLen (StrPtr);
+      FreePool (StrPtr);
+      break;
+
+    case EFI_IFR_NOT_OP:
+      Status = PopExpression (Value);
+      if (EFI_ERROR (Status)) {
+        goto Done;
+      }
+      if (Value->Type != EFI_IFR_TYPE_BOOLEAN) {
+        Status = EFI_INVALID_PARAMETER;
+        goto Done;
+      }
+      Value->Value.b = (BOOLEAN) (!Value->Value.b);
+      break;
+
+    case EFI_IFR_QUESTION_REF2_OP:
+      //
+      // Pop an expression from the expression stack
+      //
+      Status = PopExpression (Value);
+      if (EFI_ERROR (Status)) {
+        goto Done;
+      }
+
+      //
+      // Validate the expression value
+      //
+      if ((Value->Type > EFI_IFR_TYPE_NUM_SIZE_64) || (Value->Value.u64 > 0xffff)) {
+        Status = EFI_NOT_FOUND;
+        goto Done;
+      }
+
+      Question = IdToQuestion (FormSet, Form, Value->Value.u16);
+      if (Question == NULL) {
+        Status = EFI_NOT_FOUND;
+        goto Done;
+      }
+
+      Value = &Question->HiiValue;
+      break;
+
+    case EFI_IFR_STRING_REF2_OP:
+      //
+      // Pop an expression from the expression stack
+      //
+      Status = PopExpression (Value);
+      if (EFI_ERROR (Status)) {
+        goto Done;
+      }
+
+      //
+      // Validate the expression value
+      //
+      if ((Value->Type > EFI_IFR_TYPE_NUM_SIZE_64) || (Value->Value.u64 > 0xffff)) {
+        Status = EFI_NOT_FOUND;
+        goto Done;
+      }
+
+      Value->Type = EFI_IFR_TYPE_STRING;
+      StrPtr = GetToken (Value->Value.u16, FormSet->UnicodeBinary);
+      if (StrPtr == NULL) {
+        //
+        // If String not exit, push an empty string
+        //
+        //Value->Value.string = NewString (gEmptyString, FormSet->HiiHandle);
+      } else {
+        Index = (UINT16) Value->Value.u64;
+        Value->Value.string = Index;
+        FreePool (StrPtr);
+      }
+      break;
+
+    case EFI_IFR_TO_BOOLEAN_OP:
+        //
+        // Pop an expression from the expression stack
+        //
+        Status = PopExpression (Value);
+        if (EFI_ERROR (Status)) {
+          goto Done;
+        }
+
+        //
+        // Convert an expression to a Boolean
+        //
+        if (Value->Type <= EFI_IFR_TYPE_DATE) {
+          //
+          // When converting from an unsigned integer, zero will be converted to
+          // FALSE and any other value will be converted to TRUE.
+          //
+          Value->Value.b = (BOOLEAN) (Value->Value.u64 != 0);
+
+          Value->Type = EFI_IFR_TYPE_BOOLEAN;
+        } else if (Value->Type == EFI_IFR_TYPE_STRING) {
+          //
+          // When converting from a string, if case-insensitive compare
+          // with "true" is True, then push True. If a case-insensitive compare
+          // with "false" is True, then push False. Otherwise, push Undefined.
+          //
+          StrPtr = GetToken (Value->Value.string, FormSet->UnicodeBinary);
+          if (StrPtr == NULL) {
+            Status = EFI_INVALID_PARAMETER;
+            goto Done;
+          }
+
+          IfrStrToUpper (StrPtr);
+          if (FceStrCmp (StrPtr, L"TRUE") == 0){
+            Value->Value.b = TRUE;
+          } else if (FceStrCmp (StrPtr, L"FALSE") == 0) {
+            Value->Value.b = FALSE;
+          } else {
+            Status = EFI_INVALID_PARAMETER;
+            FreePool (StrPtr);
+            goto Done;
+          }
+          FreePool (StrPtr);
+          Value->Type = EFI_IFR_TYPE_BOOLEAN;
+        }
+      break;
+
+    case EFI_IFR_TO_STRING_OP:
+      //Status = IfrToString (FormSet, OpCode->Format, Value);
+      break;
+
+    case EFI_IFR_TO_UINT_OP:
+      Status = IfrToUint (FormSet, Value);
+      break;
+
+    case EFI_IFR_TO_LOWER_OP:
+    case EFI_IFR_TO_UPPER_OP:
+
+      Status = PopExpression (Value);
+      if (EFI_ERROR (Status)) {
+        goto Done;
+      }
+
+      if (Value->Type != EFI_IFR_TYPE_STRING) {
+        Status = EFI_UNSUPPORTED;
+        goto Done;
+      }
+
+      StrPtr = GetToken (Value->Value.string, FormSet->UnicodeBinary);
+      if (StrPtr == NULL) {
+        Status = EFI_NOT_FOUND;
+        goto Done;
+      }
+      //
+      // Do nothing here, as these two Opcode are to change or update the String Package
+      //
+      FreePool (StrPtr);
+      break;
+
+    case EFI_IFR_BITWISE_NOT_OP:
+      //
+      // Pop an expression from the expression stack
+      //
+      Status = PopExpression (Value);
+      if (EFI_ERROR (Status)) {
+        goto Done;
+      }
+      if (Value->Type > EFI_IFR_TYPE_DATE) {
+        Status = EFI_INVALID_PARAMETER;
+        goto Done;
+      }
+
+      Value->Type = EFI_IFR_TYPE_NUM_SIZE_64;
+      Value->Value.u64 = ~Value->Value.u64;
+      break;
+
+    case EFI_IFR_SET_OP:
+      //
+      // Pop an expression from the expression stack
+      //
+      Status = PopExpression (Value);
+      if (EFI_ERROR (Status)) {
+        goto Done;
+      }
+      Data1.Type = EFI_IFR_TYPE_BOOLEAN;
+      Data1.Value.b = FALSE;
+      //
+      // Not support SetOpcode for static scaning
+      //
+      if (OpCode->VarStorage != NULL) {
+        switch (OpCode->VarStorage->Type) {
+
+      case EFI_IFR_VARSTORE_OP:
+         CopyMem (OpCode->VarStorage->Buffer + OpCode->VarStoreInfo.VarOffset, &Value->Value, OpCode->ValueWidth);
+           Data1.Value.b = TRUE;
+       break;
+        case EFI_IFR_VARSTORE_EFI_OP:
+       if (OpCode->VarStorage->NewEfiVarstore) {
+              CopyMem (OpCode->VarStorage->Buffer + OpCode->VarStoreInfo.VarOffset, &Value->Value, OpCode->ValueWidth);
+              Data1.Value.b = TRUE;
+        } else {
+          CopyMem (OpCode->VarStorage->Buffer, &Value->Value, OpCode->ValueWidth);
+          Data1.Value.b = TRUE;
+        }
+          break;
+        case EFI_HII_VARSTORE_NAME_VALUE:
+
+          break;
+          break;
+        default:
+          //
+          // Not recognize storage.
+          //
+          Status = EFI_UNSUPPORTED;
+          goto Done;
+          break;
+        }
+        Value = &Data1;
+      }
+      break;
+
+    //
+    // binary-op
+    //
+    case EFI_IFR_ADD_OP:
+    case EFI_IFR_SUBTRACT_OP:
+    case EFI_IFR_MULTIPLY_OP:
+    case EFI_IFR_DIVIDE_OP:
+    case EFI_IFR_MODULO_OP:
+    case EFI_IFR_BITWISE_AND_OP:
+    case EFI_IFR_BITWISE_OR_OP:
+    case EFI_IFR_SHIFT_LEFT_OP:
+    case EFI_IFR_SHIFT_RIGHT_OP:
+      //
+      // Pop an expression from the expression stack
+      //
+      Status = PopExpression (&Data2);
+      if (EFI_ERROR (Status)) {
+        goto Done;
+      }
+      if (Data2.Type > EFI_IFR_TYPE_DATE) {
+        Status = EFI_INVALID_PARAMETER;
+        goto Done;
+      }
+
+      //
+      // Pop another expression from the expression stack
+      //
+      Status = PopExpression (&Data1);
+      if (EFI_ERROR (Status)) {
+        goto Done;
+      }
+      if (Data1.Type > EFI_IFR_TYPE_DATE) {
+        Status = EFI_INVALID_PARAMETER;
+        goto Done;
+      }
+
+      Value->Type = EFI_IFR_TYPE_NUM_SIZE_64;
+
+      switch (OpCode->Operand) {
+        case EFI_IFR_ADD_OP:
+          Value->Value.u64 = Data1.Value.u64 + Data2.Value.u64;
+          break;
+
+        case EFI_IFR_SUBTRACT_OP:
+          Value->Value.u64 = Data1.Value.u64 - Data2.Value.u64;
+          break;
+
+        case EFI_IFR_MULTIPLY_OP:
+          Value->Value.u64 = MultU64x32 (Data1.Value.u64, (UINT32) Data2.Value.u64);
+          break;
+
+        case EFI_IFR_DIVIDE_OP:
+          Value->Value.u64 = DivU64x32 (Data1.Value.u64, (UINT32) Data2.Value.u64);
+          break;
+
+        case EFI_IFR_MODULO_OP:
+          DivU64x32Remainder  (Data1.Value.u64, (UINT32) Data2.Value.u64, &TempValue);
+          Value->Value.u64 = TempValue;
+          break;
+
+        case EFI_IFR_BITWISE_AND_OP:
+          Value->Value.u64 = Data1.Value.u64 & Data2.Value.u64;
+          break;
+
+        case EFI_IFR_BITWISE_OR_OP:
+          Value->Value.u64 = Data1.Value.u64 | Data2.Value.u64;
+          break;
+
+        case EFI_IFR_SHIFT_LEFT_OP:
+          Value->Value.u64 = LShiftU64 (Data1.Value.u64, (UINTN) Data2.Value.u64);
+          break;
+
+        case EFI_IFR_SHIFT_RIGHT_OP:
+          Value->Value.u64 = RShiftU64 (Data1.Value.u64, (UINTN) Data2.Value.u64);
+          break;
+
+        default:
+          break;
+      }
+      break;
+
+    case EFI_IFR_AND_OP:
+    case EFI_IFR_OR_OP:
+      //
+      // Two Boolean operator
+      //
+      Status = PopExpression (&Data2);
+      if (EFI_ERROR (Status)) {
+        goto Done;
+      }
+      if (Data2.Type != EFI_IFR_TYPE_BOOLEAN) {
+        Status = EFI_INVALID_PARAMETER;
+        goto Done;
+      }
+
+      //
+      // Pop another expression from the expression stack
+      //
+      Status = PopExpression (&Data1);
+      if (EFI_ERROR (Status)) {
+        goto Done;
+      }
+      if (Data1.Type != EFI_IFR_TYPE_BOOLEAN) {
+        Status = EFI_INVALID_PARAMETER;
+        goto Done;
+      }
+
+      if (OpCode->Operand == EFI_IFR_AND_OP) {
+        Value->Value.b = (BOOLEAN) (Data1.Value.b && Data2.Value.b);
+      } else {
+        Value->Value.b = (BOOLEAN) (Data1.Value.b || Data2.Value.b);
+      }
+      break;
+
+    case EFI_IFR_EQUAL_OP:
+    case EFI_IFR_NOT_EQUAL_OP:
+    case EFI_IFR_GREATER_EQUAL_OP:
+    case EFI_IFR_GREATER_THAN_OP:
+    case EFI_IFR_LESS_EQUAL_OP:
+    case EFI_IFR_LESS_THAN_OP:
+      //
+      // Compare two integer, string, boolean or date/time
+      //
+      Status = PopExpression (&Data2);
+      if (EFI_ERROR (Status)) {
+        goto Done;
+      }
+      if ((Data2.Type > EFI_IFR_TYPE_BOOLEAN) && (Data2.Type != EFI_IFR_TYPE_STRING)) {
+        Status = EFI_INVALID_PARAMETER;
+        goto Done;
+      }
+
+      //
+      // Pop another expression from the expression stack
+      //
+      Status = PopExpression (&Data1);
+      if (EFI_ERROR (Status)) {
+        goto Done;
+      }
+
+      Result = CompareHiiValue (&Data1, &Data2, FormSet);
+      if ((EFI_STATUS)Result == EFI_INVALID_PARAMETER) {
+        Status = EFI_INVALID_PARAMETER;
+        goto Done;
+      }
+
+      switch (OpCode->Operand) {
+      case EFI_IFR_EQUAL_OP:
+        Value->Value.b = (BOOLEAN) ((Result == 0) ? TRUE : FALSE);
+        break;
+
+      case EFI_IFR_NOT_EQUAL_OP:
+        Value->Value.b = (BOOLEAN) ((Result != 0) ? TRUE : FALSE);
+        break;
+
+      case EFI_IFR_GREATER_EQUAL_OP:
+        Value->Value.b = (BOOLEAN) ((Result >= 0) ? TRUE : FALSE);
+        break;
+
+      case EFI_IFR_GREATER_THAN_OP:
+        Value->Value.b = (BOOLEAN) ((Result > 0) ? TRUE : FALSE);
+        break;
+
+      case EFI_IFR_LESS_EQUAL_OP:
+        Value->Value.b = (BOOLEAN) ((Result <= 0) ? TRUE : FALSE);
+        break;
+
+      case EFI_IFR_LESS_THAN_OP:
+        Value->Value.b = (BOOLEAN) ((Result < 0) ? TRUE : FALSE);
+        break;
+
+      default:
+        break;
+      }
+      break;
+
+    case EFI_IFR_MATCH_OP:
+      Status = IfrMatch (FormSet, Value);
+      break;
+
+    case EFI_IFR_CATENATE_OP:
+      Status = IfrCatenate (FormSet, Value);
+      break;
+
+    //
+    // ternary-op
+    //
+    case EFI_IFR_CONDITIONAL_OP:
+      //
+      // Pop third expression from the expression stack
+      //
+      Status = PopExpression (&Data3);
+      if (EFI_ERROR (Status)) {
+        goto Done;
+      }
+
+      //
+      // Pop second expression from the expression stack
+      //
+      Status = PopExpression (&Data2);
+      if (EFI_ERROR (Status)) {
+        goto Done;
+      }
+
+      //
+      // Pop first expression from the expression stack
+      //
+      Status = PopExpression (&Data1);
+      if (EFI_ERROR (Status)) {
+        goto Done;
+      }
+      if (Data1.Type != EFI_IFR_TYPE_BOOLEAN) {
+        Status = EFI_INVALID_PARAMETER;
+        goto Done;
+      }
+
+      if (Data1.Value.b) {
+        Value = &Data3;
+      } else {
+        Value = &Data2;
+      }
+      break;
+
+    case EFI_IFR_FIND_OP:
+      Status = IfrFind (FormSet, OpCode->Format, Value);
+      break;
+
+    case EFI_IFR_MID_OP:
+      Status = IfrMid (FormSet, Value);
+      break;
+
+    case EFI_IFR_TOKEN_OP:
+      Status = IfrToken (FormSet, Value);
+      break;
+
+    case EFI_IFR_SPAN_OP:
+      Status = IfrSpan (FormSet, OpCode->Flags, Value);
+      break;
+
+    case EFI_IFR_MAP_OP:
+      //
+      // Pop the check value
+      //
+      Status = PopExpression (&Data1);
+      if (EFI_ERROR (Status)) {
+        goto Done;
+      }
+      //
+      // Check MapExpression list is valid.
+      //
+      if (OpCode->MapExpressionList.ForwardLink == NULL) {
+        Status = EFI_INVALID_PARAMETER;
+        goto Done;
+      }
+      //
+      // Go through map expression list.
+      //
+      SubExpressionLink = GetFirstNode(&OpCode->MapExpressionList);
+      while (!IsNull (&OpCode->MapExpressionList, SubExpressionLink)) {
+        SubExpression = FORM_EXPRESSION_FROM_LINK (SubExpressionLink);
+        //
+        // Evaluate the first expression in this pair.
+        //
+        Status = EvaluateExpression (FormSet, Form, SubExpression, ConstantExpression);
+        if (EFI_ERROR (Status)) {
+          goto Done;
+        }
+        //
+        // Compare the expression value with current value
+        //
+        if (CompareHiiValue (&Data1, &SubExpression->Result, FormSet) == 0) {
+          //
+          // Try get the map value.
+          //
+          SubExpressionLink = GetNextNode (&OpCode->MapExpressionList, SubExpressionLink);
+          if (IsNull (&OpCode->MapExpressionList, SubExpressionLink)) {
+            Status = EFI_INVALID_PARAMETER;
+            goto Done;
+          }
+          SubExpression = FORM_EXPRESSION_FROM_LINK (SubExpressionLink);
+          Status = EvaluateExpression (FormSet, Form, SubExpression, ConstantExpression);
+          if (EFI_ERROR (Status)) {
+            goto Done;
+          }
+          Value = &SubExpression->Result;
+          break;
+        }
+        //
+        // Skip the second expression on this pair.
+        //
+        SubExpressionLink = GetNextNode (&OpCode->MapExpressionList, SubExpressionLink);
+        if (IsNull (&OpCode->MapExpressionList, SubExpressionLink)) {
+          Status = EFI_INVALID_PARAMETER;
+          goto Done;
+        }
+        //
+        // Goto the first expression on next pair.
+        //
+        SubExpressionLink = GetNextNode (&OpCode->MapExpressionList, SubExpressionLink);
+      }
+
+      //
+      // No map value is found.
+      //
+      if (IsNull (&OpCode->MapExpressionList, SubExpressionLink)) {
+        Value->Type = EFI_IFR_TYPE_UNDEFINED;
+        Value->Value.u8 = 0;
+      }
+      break;
+
+    default:
+      break;
+    }
+    if (EFI_ERROR (Status)) {
+      goto Done;
+    }
+
+    Status = PushExpression (Value);
+    if (EFI_ERROR (Status)) {
+      goto Done;
+    }
+  }
+
+  //
+  // Pop the final result from expression stack
+  //
+  Value = &Data1;
+  Status = PopExpression (Value);
+  if (EFI_ERROR (Status)) {
+    goto Done;
+  }
+
+  //
+  // After evaluating an expression, there should be only one value left on the expression stack
+  //
+  if (PopExpression (Value) != EFI_ACCESS_DENIED) {
+    Status = EFI_INVALID_PARAMETER;
+  }
+
+Done:
+  RestoreExpressionEvaluationStackOffset (StackOffset);
+  if (!EFI_ERROR (Status)) {
+    CopyMem (&Expression->Result, Value, sizeof (EFI_HII_VALUE));
+  }
+
+  return Status;
+}
diff --git a/Platform/Intel/Tools/FCE/Fce.c b/Platform/Intel/Tools/FCE/Fce.c
new file mode 100644
index 0000000000..1845c508b5
--- /dev/null
+++ b/Platform/Intel/Tools/FCE/Fce.c
@@ -0,0 +1,6449 @@
+/** @file
+
+ FCE is a tool which enables developers to retrieve and change HII configuration ("Setup")
+ data in Firmware Device files (".fd" files).
+
+ Copyright (c) 2011-2019, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "Fce.h"
+
+#ifndef __GNUC__
+#define COPY_STR      "copy \"%s\" \"%s\" > NUL"
+#define RMDIR_STR     "rmdir /S /Q \"%s\" > NUL"
+#define DEL_STR       "del \"%s\" > NUL"
+#else
+#define COPY_STR      "cp \"%s\" \"%s\" > /dev/null"
+#define RMDIR_STR     "rm -r \"%s\" > /dev/null"
+#define DEL_STR       "rm \"%s\" > /dev/null"
+#endif
+
+//
+// Utility global variables
+//
+OPERATION_TYPE  Operations;
+
+CHAR8  mInputFdName[MAX_FILENAME_LEN];
+CHAR8  mOutputFdName[MAX_FILENAME_LEN];
+CHAR8  mOutTxtName[MAX_FILENAME_LEN];
+CHAR8  mSetupTxtName[MAX_FILENAME_LEN];
+
+CHAR8* mUtilityFilename        = NULL;
+UINT32 mEfiVariableAddr        = 0;
+
+UQI_PARAM_LIST           *mUqiList = NULL;
+UQI_PARAM_LIST           *mLastUqiList = NULL;
+LIST_ENTRY               mVarListEntry;
+LIST_ENTRY               mBfvVarListEntry;
+LIST_ENTRY               mAllVarListEntry;
+LIST_ENTRY               mFormSetListEntry;
+
+//
+// Store GUIDed Section guid->tool mapping
+//
+EFI_HANDLE mParsedGuidedSectionTools = NULL;
+
+CHAR8*     mGuidToolDefinition       = "GuidToolDefinitionConf.ini";
+
+//
+//gFfsArray is used to store all the FFS informations of Fd
+//
+G_EFI_FD_INFO               gEfiFdInfo;
+//
+//mMultiPlatformParam is used to store the structures about multi-platform support
+//
+MULTI_PLATFORM_PARAMETERS   mMultiPlatformParam;
+
+UINT32                      mFormSetOrderRead;
+UINT32                      mFormSetOrderParse;
+
+CHAR8             mFullGuidToolDefinitionDir[_MAX_PATH];
+
+CHAR8             *mFvNameGuidString = NULL;
+
+/**
+  Check the revision of BfmLib. If not matched, return an error.
+
+  @retval  EFI_SUCCESS         If revision matched, return EFI_SUCCESS.
+  @retval  EFI_UNSUPPORTED     Other cases.
+**/
+static
+EFI_STATUS
+CheckBfmLibRevision (
+  VOID
+  )
+{
+  CHAR8          *SystemCommandFormatString;
+  CHAR8          *SystemCommand;
+  CHAR8          *TempSystemCommand;
+  CHAR8          *Revision;
+  FILE           *FileHandle;
+  CHAR8          RevisionStr[_MAX_BUILD_VERSION];
+  UINT32         Len;
+
+  SystemCommandFormatString = NULL;
+  SystemCommand             = NULL;
+  TempSystemCommand         = NULL;
+  Revision                  = "Revision.txt";
+
+  memset (RevisionStr, 0, _MAX_BUILD_VERSION);
+
+  //
+  // Construction 'system' command string
+  //
+  SystemCommandFormatString = "BfmLib -v > %s";
+  SystemCommand = malloc (
+                    strlen (SystemCommandFormatString) + strlen (Revision) + 1
+                  );
+  if (SystemCommand == NULL) {
+    return EFI_UNSUPPORTED;
+  }
+  sprintf (
+    SystemCommand,
+    "BfmLib -v > %s",
+    Revision
+    );
+
+  if (mFullGuidToolDefinitionDir[0] != 0) {
+    TempSystemCommand = SystemCommand;
+    SystemCommand = malloc (
+                    strlen (mFullGuidToolDefinitionDir) + strlen (OS_SEP_STR) + strlen (SystemCommandFormatString) + strlen (Revision) + 1
+                  );
+
+    if (SystemCommand == NULL) {
+      free (TempSystemCommand);
+      return EFI_UNSUPPORTED;
+    }
+    strcpy (SystemCommand, mFullGuidToolDefinitionDir);
+    strcat (SystemCommand, OS_SEP_STR);
+    strcat (SystemCommand, TempSystemCommand);
+    free (TempSystemCommand);
+  }
+
+  system (SystemCommand);
+  free (SystemCommand);
+  FileHandle = fopen (Revision, "r");
+  if (FileHandle == NULL) {
+    printf ("Error. Read the revision file of BfmLib failed.\n");
+    return EFI_ABORTED;
+  }
+  fgets(RevisionStr, _MAX_BUILD_VERSION, FileHandle);
+  Len = strlen(RevisionStr);
+  if (RevisionStr[Len - 1] == '\n') {
+    RevisionStr[Len - 1] = 0;
+  }
+  fclose (FileHandle);
+  remove (Revision);
+
+  if (strlen (RevisionStr) > _MAX_BUILD_VERSION - 1) {
+    printf ("The revision string is too long");
+    return EFI_UNSUPPORTED;
+  }
+  if (strcmp (RevisionStr, __BUILD_VERSION) == 0) {
+    return EFI_SUCCESS;
+  }
+  return EFI_UNSUPPORTED;
+}
+
+/**
+  Transfer the Ascii string to the Dec Number
+
+  @param   InStr          The Ascii string.
+
+  @retval  DecNum         Return the Dec number.
+**/
+static
+UINT64
+StrToDec (
+  IN  CHAR8     *InStr
+  )
+{
+  UINT8   Index;
+  UINTN   DecNum;
+  UINTN   Temp;
+
+  Index   = 0;
+  DecNum  = 0;
+  Temp    = 0;
+
+  if (InStr == NULL) {
+    return (UINT64)-1;
+  }
+  while (Index < strlen (InStr)) {
+
+    if ((*(InStr + Index) >= '0') && (*(InStr + Index) <= '9')) {
+      Temp = *(InStr + Index) - '0';
+    } else if ((*(InStr + Index) >= 'a') && (*(InStr + Index) <= 'f')) {
+      Temp = *(InStr + Index) - 'a' + 10;
+    } else if ((*(InStr + Index) >= 'A') && (*(InStr + Index) <= 'F')) {
+      Temp = *(InStr + Index) - 'A' + 10;
+    }
+    DecNum = DecNum + Temp * (UINTN) pow (16, strlen (InStr) - Index - 1);
+    Index++;
+  }
+  return DecNum;
+}
+/**
+  Check whether there are some errors in uqi parameters of One_of
+
+  @param Question      The pointer to the question Node.
+  @param UqiValue      The value of One_of.
+
+  @retval TRUE          If existed error, return TRUE;
+  @return FALSE         Otherwise, return FALSE;
+**/
+static
+BOOLEAN
+CheckOneOfParamError (
+  IN CONST FORM_BROWSER_STATEMENT   *Question,
+  IN       UINT64                   UqiValue
+  )
+{
+  LIST_ENTRY           *Link;
+  QUESTION_OPTION      *Option;
+  UINT64               Value;
+
+  Link   = NULL;
+  Option = NULL;
+  Value  = 0;
+
+  Link = GetFirstNode (&Question->OptionListHead);
+  while (!IsNull (&Question->OptionListHead, Link)) {
+    Option = QUESTION_OPTION_FROM_LINK (Link);
+    Value  = 0;
+    CopyMem (&Value, &Option->Value.Value.u64, Question->StorageWidth);
+    if (Value == UqiValue) {
+      return FALSE;
+    }
+    Link = GetNextNode (&Question->OptionListHead, Link);
+  }
+
+  return TRUE;
+}
+
+/**
+  Check whether there are some errors in uqi parameters of Orderlist
+
+  @param HiiObjList     The pointer to the Hii Object Node.
+  @param UqiValue       The pointer to the Uqi parameter.
+
+  @retval TRUE          If existed error, return TRUE;
+  @return FALSE         Otherwise, return FALSE;
+**/
+static
+BOOLEAN
+CheckOrderParamError (
+  IN CONST FORM_BROWSER_STATEMENT   *Question,
+  IN       CHAR8                    *UqiValue
+  )
+{
+  UINT8    MaxNum;
+  MaxNum     = UqiValue[0];
+
+  if (MaxNum != (UINT8)(Question->MaxContainers)) {
+    return TRUE;
+  }
+
+  return FALSE;
+}
+
+/**
+  Writes a Unicode string
+
+  @param  Package        A pointer to the Unicode string.
+
+  @return NULL
+**/
+static
+VOID
+WriteUnicodeStr (
+  IN     CHAR16              *pcString
+  )
+{
+  UINTN  Index;
+
+  if (pcString == NULL) {
+    return;
+  }
+
+  for (Index = 0; pcString[Index] != 0; Index++) {
+    printf("%c", pcString[Index] & 0x00FF);
+  }
+}
+
+/**
+  Parse and set the quick configure information by the command line.
+
+  Read the UQI Config information from command line directly, and then compare it with the value in VarList.
+  Update the Update flag in Varlist.
+
+  @param  CurUqiList           The pointer to the current uqi
+  @param  DefaultId            The default Id.
+  @param  PlatformId           The platform Id.
+  @param  CurQuestion          The pointer to the matched question
+
+  @retval EFI_SUCCESS       It was complete successfully
+  @retval EFI_UNSUPPORTED   Update a read-only value
+  @return EFI_ABORTED       An error occurred
+**/
+static
+EFI_STATUS
+SetUqiParametersWithQuestion (
+  IN  UQI_PARAM_LIST   *CurUqiList,
+  IN  UINT16           DefaultId,
+  IN  UINT64           PlatformId,
+  IN  FORM_BROWSER_STATEMENT *CurQuestion
+  )
+{
+  FORMSET_STORAGE         *VarList;
+  BOOLEAN                 IsFound;
+  UINT8                   *ValueAddrOfVar;
+  UINT16                  Index;
+  UINT64                  QuestionValue;
+  UINT64                  UqiValue;
+  EFI_STATUS              Status;
+  CHAR8                   *ErrorStr;
+  FORM_BROWSER_FORMSET    *FormSet;
+  LIST_ENTRY              *FormSetLink;
+  UINT64                  CurValue;
+
+  VarList        = NULL;
+  Index          = 0;
+  ValueAddrOfVar = NULL;
+  QuestionValue  = 0;
+  UqiValue       = 0;
+  ErrorStr       = NULL;
+  Status         = EFI_SUCCESS;
+  FormSet        = NULL;
+  FormSetLink    = NULL;
+  CurValue       = 0;
+
+  //
+  // Search the Variable List by VarStoreId and Offset
+  //
+  IsFound  = FALSE;
+  FormSetLink = GetFirstNode (&mFormSetListEntry);
+  while (!IsNull (&mFormSetListEntry, FormSetLink)) {
+    FormSet = FORM_BROWSER_FORMSET_FROM_LINK (FormSetLink);
+    Status = SearchVarStorage (
+               CurQuestion,
+               NULL,
+               CurQuestion->VarStoreInfo.VarOffset,
+               FormSet->StorageListHead,
+              (CHAR8 **) &ValueAddrOfVar,
+               &VarList
+             );
+
+    if (!EFI_ERROR (Status)) {
+      IsFound = TRUE;
+      break;
+    }
+    FormSetLink = GetNextNode (&mFormSetListEntry, FormSetLink);
+  }
+
+  if (!IsFound) {
+    if (CurUqiList->Header.ScriptsLine == 0) {
+      printf ("Error. The question in the command line doesn't store value by EFI_VARSTORE_IFR or EFI_VARSTORE_IFR_EFI.\n");
+    } else {
+      printf ("Error. The question in the line %d of script doesn't store value by EFI_VARSTORE_IFR or EFI_VARSTORE_IFR_EFI.\n", CurUqiList->Header.ScriptsLine);
+    }
+    return EFI_ABORTED;
+  }
+
+  //
+  // Check the length of variable value
+  //
+  if (CurQuestion->QuestionReferToBitField) {
+    GetBitsQuestionValue (CurQuestion, ValueAddrOfVar, (UINT32*)&QuestionValue);
+  } else {
+    switch (CurQuestion->StorageWidth) {
+
+      case sizeof (UINT8):
+        QuestionValue  = *(UINT8 *)ValueAddrOfVar;
+        break;
+
+      case sizeof (UINT16):
+        QuestionValue  = *(UINT16 *)ValueAddrOfVar;
+        break;
+
+      case sizeof (UINT32):
+        QuestionValue  = *(UINT32 *)ValueAddrOfVar;
+        break;
+
+      case sizeof (UINT64):
+        QuestionValue  = *(UINT64 *)ValueAddrOfVar;
+        break;
+
+      default:
+      //
+      // The storage width of ORDERED_LIST may not be any type above.
+      //
+        ;
+        break;
+    }
+  }
+  UqiValue = *(UINT64 *)CurUqiList->Header.Value;
+  CurUqiList->SameOrNot = TRUE;
+
+  //
+  // Check and set the checkbox value
+  //
+  if (CurQuestion->Operand == EFI_IFR_CHECKBOX_OP) {
+    if ((UqiValue != 0) && (UqiValue != 1)) {
+      CurUqiList->ErrorOrNot = TRUE;
+      CurUqiList->SameOrNot  = FALSE;
+      CurUqiList->Error      = malloc (ERROR_INFO_LENGTH * sizeof (CHAR8));
+      if (CurUqiList->Error == NULL) {
+        printf ("Fail to allocate memory!\n");
+        return EFI_ABORTED;
+      }
+      memset (CurUqiList->Error, 0, ERROR_INFO_LENGTH);
+      sprintf (CurUqiList->Error, "Error. The updated value of CHECKBOX 0x%llx is invalid.\n", (unsigned long long) UqiValue);
+      if (CurQuestion->QuestionReferToBitField) {
+        GetBitsQuestionValue (CurQuestion, ValueAddrOfVar, (UINT32*)CurUqiList->Header.DiffValue);
+      } else {
+        memcpy (
+          CurUqiList->Header.DiffValue,
+          ValueAddrOfVar,
+          CurQuestion->StorageWidth
+         );
+      }
+    } else {
+      if (QuestionValue != UqiValue) {
+        if (CurQuestion->QuestionReferToBitField) {
+          GetBitsQuestionValue (CurQuestion, ValueAddrOfVar, (UINT32*)CurUqiList->Header.DiffValue);
+          SetBitsQuestionValue (CurQuestion, ValueAddrOfVar, *(UINT32*)CurUqiList->Header.Value);
+        } else {
+          memcpy (
+            CurUqiList->Header.DiffValue,
+            ValueAddrOfVar,
+            CurQuestion->StorageWidth
+            );
+          memcpy (
+            ValueAddrOfVar,
+            CurUqiList->Header.Value,
+            CurQuestion->StorageWidth
+            );
+        }
+        CurUqiList->SameOrNot   = FALSE;
+      }
+    }
+  }
+  if (CurQuestion->Operand == EFI_IFR_STRING_OP) {
+   if ((FceStrLen((wchar_t *)CurUqiList->Header.Value) + 1) * 2 > CurQuestion->StorageWidth) {
+     CurUqiList->ErrorOrNot = TRUE;
+     CurUqiList->Error = malloc (ERROR_INFO_LENGTH * sizeof (CHAR8));
+      if (CurUqiList->Error == NULL) {
+        printf ("Fail to allocate memory!\n");
+        return EFI_ABORTED;
+      }
+     memset (CurUqiList->Error, 0, ERROR_INFO_LENGTH);
+     sprintf (CurUqiList->Error, "Error. The updated value of STRING exceed its Size.\n");
+     memcpy (
+        CurUqiList->Header.DiffValue,
+        ValueAddrOfVar,
+        CurQuestion->StorageWidth
+      );
+   } else {
+     if (memcmp((CHAR8 *)CurUqiList->Header.Value, ValueAddrOfVar, CurQuestion->StorageWidth) != 0) {
+       memcpy(
+          CurUqiList->Header.DiffValue,
+          ValueAddrOfVar,
+          CurQuestion->StorageWidth
+          );
+       memcpy(
+          ValueAddrOfVar,
+          CurUqiList->Header.Value,
+          CurQuestion->StorageWidth
+          );
+       CurUqiList->SameOrNot = FALSE;
+     }
+    }
+  }
+  //
+  // Check and set the NUMERIC value
+  //
+  if (CurQuestion->Operand == EFI_IFR_NUMERIC_OP) {
+    if ((UqiValue < CurQuestion->Minimum) || (UqiValue > CurQuestion->Maximum)) {
+      CurUqiList->ErrorOrNot = TRUE;
+      CurUqiList->SameOrNot  = FALSE;
+      CurUqiList->Error = malloc (ERROR_INFO_LENGTH * sizeof (CHAR8));
+      if (CurUqiList->Error == NULL) {
+        printf ("Fail to allocate memory!\n");
+        return EFI_ABORTED;
+      }
+      memset (CurUqiList->Error, 0, ERROR_INFO_LENGTH);
+      sprintf (CurUqiList->Error, "Error. The updated value of NUMERIC 0x%llx is invalid.\n", (unsigned long long) UqiValue);
+      if (CurQuestion->QuestionReferToBitField) {
+        GetBitsQuestionValue (CurQuestion, ValueAddrOfVar, (UINT32*)CurUqiList->Header.DiffValue);
+      } else {
+        memcpy (
+          CurUqiList->Header.DiffValue,
+          ValueAddrOfVar,
+          CurQuestion->StorageWidth
+        );
+      }
+    } else {
+      if (QuestionValue != UqiValue) {
+        if (CurQuestion->QuestionReferToBitField) {
+          GetBitsQuestionValue (CurQuestion, ValueAddrOfVar, (UINT32*)CurUqiList->Header.DiffValue);
+          SetBitsQuestionValue (CurQuestion, ValueAddrOfVar, *(UINT32*)CurUqiList->Header.Value);
+        } else {
+          memcpy (
+          CurUqiList->Header.DiffValue,
+            ValueAddrOfVar,
+            CurQuestion->StorageWidth
+            );
+          memcpy (
+            ValueAddrOfVar,
+            CurUqiList->Header.Value,
+            CurQuestion->StorageWidth
+            );
+        }
+        CurUqiList->SameOrNot = FALSE;
+      }
+    }
+  }
+  //
+  // Check and set the ONE_OF value
+  //
+  if (CurQuestion->Operand == EFI_IFR_ONE_OF_OP) {
+    if (CheckOneOfParamError (CurQuestion, UqiValue)) {
+      CurUqiList->ErrorOrNot = TRUE;
+      CurUqiList->SameOrNot  = FALSE;
+      CurUqiList->Error = malloc (ERROR_INFO_LENGTH * sizeof (CHAR8));
+      if (CurUqiList->Error == NULL) {
+        printf ("Fail to allocate memory!\n");
+        return EFI_ABORTED;
+      }
+      memset (CurUqiList->Error, 0, ERROR_INFO_LENGTH);
+      sprintf (CurUqiList->Error, "Error. The updated ONE_OF value 0x%llx is invalid.\n", (unsigned long long) UqiValue);
+      if (CurQuestion->QuestionReferToBitField) {
+        GetBitsQuestionValue (CurQuestion, ValueAddrOfVar, (UINT32*)CurUqiList->Header.DiffValue);
+      } else {
+        memcpy (
+          CurUqiList->Header.DiffValue,
+          ValueAddrOfVar,
+          CurQuestion->StorageWidth
+        );
+      }
+    } else {
+      if (QuestionValue != UqiValue) {
+        if (CurQuestion->QuestionReferToBitField) {
+          GetBitsQuestionValue (CurQuestion, ValueAddrOfVar, (UINT32*)CurUqiList->Header.DiffValue);
+          SetBitsQuestionValue (CurQuestion, ValueAddrOfVar, *(UINT32*)CurUqiList->Header.Value);
+        } else {
+          memcpy (
+            CurUqiList->Header.DiffValue,
+            ValueAddrOfVar,
+            CurQuestion->StorageWidth
+            );
+          memcpy (
+            ValueAddrOfVar,
+            CurUqiList->Header.Value,
+            CurQuestion->StorageWidth
+            );
+        }
+        CurUqiList->SameOrNot   = FALSE;
+      }
+    }
+  }
+  //
+  // Check and set the ORDER_LIST value
+  //
+  if (CurQuestion->Operand == EFI_IFR_ORDERED_LIST_OP) {
+    //
+    // Synchronize the MaxContainers value
+    //
+    *CurUqiList->Header.DiffValue = (UINT8)CurQuestion->MaxContainers;
+
+    if (CheckOrderParamError (CurQuestion, (CHAR8 *)CurUqiList->Header.Value)) {
+
+      CurUqiList->ErrorOrNot = TRUE;
+      CurUqiList->SameOrNot  = FALSE;
+      CurUqiList->Error = malloc (ERROR_INFO_LENGTH * sizeof (CHAR8));
+      if (CurUqiList->Error == NULL) {
+        printf ("Fail to allocate memory!\n");
+        return EFI_ABORTED;
+      }
+      memset (CurUqiList->Error, 0, ERROR_INFO_LENGTH);
+
+      ErrorStr = CurUqiList->Error;
+      sprintf (ErrorStr, "Error. The updated NORDERED_LIST value ");
+      ErrorStr = ErrorStr + strlen ("Error. The updated NORDERED_LIST value ");
+
+      for (Index = 0; Index < CurQuestion->StorageWidth; Index++) {
+        sprintf (ErrorStr, "%02x ", *(CurUqiList->Header.Value + Index + 1));
+        ErrorStr +=3;
+      }
+      sprintf (ErrorStr, "is invalid.\n");
+      memcpy (
+        CurUqiList->Header.DiffValue + 1,
+        ValueAddrOfVar,
+        CurQuestion->StorageWidth
+      );
+    } else {
+      for (Index = 0; Index < CurQuestion->StorageWidth/CurQuestion->MaxContainers; Index++) {
+        CurValue = 0;
+        memcpy (
+           &CurValue,
+          (ValueAddrOfVar + Index * CurQuestion->StorageWidth/CurQuestion->MaxContainers),
+           CurQuestion->StorageWidth/CurQuestion->MaxContainers
+        );
+        if (CurValue != *((UINT64 *)CurUqiList->Header.Value + Index + 1)) {
+          CurUqiList->SameOrNot   = FALSE;
+          break;
+        }
+      }
+      if (!CurUqiList->SameOrNot) {
+        memcpy (
+          CurUqiList->Header.DiffValue + 1,
+          ValueAddrOfVar,
+          CurQuestion->StorageWidth
+        );
+        for (Index = 0; Index < CurQuestion->MaxContainers; Index++) {
+          switch (CurQuestion->StorageWidth/CurQuestion->MaxContainers) {
+
+          case sizeof (UINT8):
+            *((UINT8 *)ValueAddrOfVar + Index) = *(UINT8 *)((UINT64 *)CurUqiList->Header.Value + 1 + Index);
+            break;
+
+          case sizeof (UINT16):
+            *((UINT16 *)ValueAddrOfVar + Index) = *(UINT16 *)((UINT64 *)CurUqiList->Header.Value + 1 + Index);
+            break;
+
+          case sizeof (UINT32):
+            *((UINT32 *)ValueAddrOfVar + Index) = *(UINT32 *)((UINT64 *)CurUqiList->Header.Value + 1 + Index);
+            break;
+
+          case sizeof (UINT64):
+            *((UINT64 *)ValueAddrOfVar + Index) = *((UINT64 *)CurUqiList->Header.Value + 1 + Index);
+            break;
+
+          default:
+            *((UINT8 *)ValueAddrOfVar + Index) = *(UINT8 *)((UINT64 *)CurUqiList->Header.Value + 1 + Index);
+            break;
+          }
+        }
+        //
+        // Update the vaule of ORDERED_LIST according to its size
+        //
+        CurUqiList->Header.Value = (UINT8 *)((UINT64 *)CurUqiList->Header.Value);
+        memcpy (
+          CurUqiList->Header.Value + 1,
+          ValueAddrOfVar,
+          CurQuestion->StorageWidth
+          );
+      }
+    }
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Parse and set the quick configure information by the command line.
+
+  Read the UQI Config information from command line directly, and then compare it with the value in VarList.
+  Update the Update flag in Varlist.
+
+  @param  UqiList              The pointer to the uqi list
+  @param  DefaultId            The default Id.
+  @param  PlatformId           The platform Id.
+
+  @retval EFI_SUCCESS       It was complete successfully
+  @retval EFI_UNSUPPORTED   Update a read-only value
+  @return EFI_ABORTED       An error occurred
+**/
+static
+EFI_STATUS
+SetUqiParameters (
+  IN  UQI_PARAM_LIST   *UqiList,
+  IN  UINT16           DefaultId,
+  IN  UINT64           PlatformId
+  )
+{
+  FORM_BROWSER_FORMSET    *FormSet;
+  LIST_ENTRY              *FormSetLink;
+  FORM_BROWSER_FORM       *Form;
+  LIST_ENTRY              *FormLink;
+  FORM_BROWSER_STATEMENT  *Question;
+  LIST_ENTRY              *QuestionLink;
+  LIST_ENTRY              *FormSetEntryListHead;
+  UQI_PARAM_LIST          *CurUqiList;
+
+  FormSet      = NULL;
+  FormSetLink  = NULL;
+  Form         = NULL;
+  FormLink     = NULL;
+  Question     = NULL;
+  QuestionLink = NULL;
+  FormSetEntryListHead = &mFormSetListEntry;
+
+  FormSetLink = GetFirstNode (FormSetEntryListHead);
+  while (!IsNull (FormSetEntryListHead, FormSetLink)) {
+    FormSet = FORM_BROWSER_FORMSET_FROM_LINK (FormSetLink);
+    //
+    // Parse all forms in formset
+    //
+    FormLink = GetFirstNode (&FormSet->FormListHead);
+
+    while (!IsNull (&FormSet->FormListHead, FormLink)) {
+      Form = FORM_BROWSER_FORM_FROM_LINK (FormLink);
+      //
+      // Parse five kinds of Questions in Form
+      //
+      QuestionLink = GetFirstNode (&Form->StatementListHead);
+
+      while (!IsNull (&Form->StatementListHead, QuestionLink)) {
+        Question = FORM_BROWSER_STATEMENT_FROM_LINK (QuestionLink);
+        QuestionLink = GetNextNode (&Form->StatementListHead, QuestionLink);
+        //
+        // Parse five kinds of Questions in Form
+        //
+        if ((Question->Operand == EFI_IFR_ONE_OF_OP)
+          || (Question->Operand == EFI_IFR_NUMERIC_OP)
+          || (Question->Operand == EFI_IFR_CHECKBOX_OP)
+          || (Question->Operand == EFI_IFR_ORDERED_LIST_OP)
+          || (Question->Operand == EFI_IFR_STRING_OP)
+          ) {
+          if (mMultiPlatformParam.MultiPlatformOrNot) {
+            //
+            // Only compare the valid EFI_IFR_VARSTORE_EFI_OP in multi-platform mode
+            //
+            if (Question->Type != EFI_IFR_VARSTORE_EFI_OP) {
+              continue;
+            }
+            if ((Question->Type == EFI_IFR_VARSTORE_EFI_OP)
+              && Question->NewEfiVarstore
+              && ((Question->Attributes & EFI_VARIABLE_NON_VOLATILE) == 0)) {
+              continue;
+            }
+          }
+
+          CurUqiList = UqiList;
+          while (CurUqiList != NULL) {
+            if ((PlatformId == CurUqiList->Header.PlatformId[0])
+              && (DefaultId == CurUqiList->Header.DefaultId[0])
+              && CompareUqiHeader (&(Question->Uqi), &(CurUqiList->Header))
+              ) {
+              //
+              // Add further check to avoid a case that there are many options with a
+              // same UQI (en-Us), but always returns the first one.
+              //
+              if (!CurUqiList->ParseOrNot) {
+                CurUqiList->ParseOrNot = TRUE;
+                break;
+              }
+            }
+            CurUqiList = CurUqiList->Next;
+          }
+          if (CurUqiList != NULL) {
+            SetUqiParametersWithQuestion (CurUqiList, DefaultId, PlatformId, Question);
+          }
+        }
+      }
+      FormLink = GetNextNode (&FormSet->FormListHead, FormLink);
+    }
+    FormSetLink = GetNextNode (FormSetEntryListHead, FormSetLink);
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Set question value per UqiList.
+
+  @param  UqiList              The pointer to the uqi list
+  @param  DefaultId            The default Id.
+  @param  PlatformId           The platform Id.
+**/
+VOID
+SetUqiParametersMultiMode (
+  IN  UQI_PARAM_LIST   *UqiList,
+  IN  UINT16           DefaultId,
+  IN  UINT64           PlatformId
+  )
+{
+  UQI_PARAM_LIST   *CurUqiList;
+
+  CurUqiList = UqiList;
+  while (CurUqiList != NULL) {
+    if ((CurUqiList->ParseOrNot == FALSE)
+      && (PlatformId == CurUqiList->Header.PlatformId[0])
+      && (DefaultId == CurUqiList->Header.DefaultId[0])
+      ) {
+      CurUqiList->ParseOrNot = TRUE;
+      if (CurUqiList->Header.Question != NULL) {
+        SetUqiParametersWithQuestion (CurUqiList, DefaultId, PlatformId, CurUqiList->Header.Question);
+      }
+    }
+    CurUqiList = CurUqiList->Next;
+  }
+}
+
+/**
+  Find the matched question for each UQI string in UqiList
+
+**/
+EFI_STATUS
+ScanUqiFullList (
+  IN  UQI_PARAM_LIST   *UqiList
+  )
+{
+  FORM_BROWSER_FORMSET    *FormSet;
+  LIST_ENTRY              *FormSetLink;
+  FORM_BROWSER_FORM       *Form;
+  LIST_ENTRY              *FormLink;
+  FORM_BROWSER_STATEMENT  *Question;
+  LIST_ENTRY              *QuestionLink;
+  LIST_ENTRY              *FormSetEntryListHead;
+  UQI_PARAM_LIST          *CurUqiList;
+  UINT64           PlatformId;
+  UINT16           DefaultId;
+
+  if (UqiList == NULL) {
+    return EFI_SUCCESS;
+  }
+  FormSet      = NULL;
+  FormSetLink  = NULL;
+  Form         = NULL;
+  FormLink     = NULL;
+  Question     = NULL;
+  QuestionLink = NULL;
+  FormSetEntryListHead = &mFormSetListEntry;
+
+  FormSetLink = FormSetEntryListHead->ForwardLink;
+  while (FormSetEntryListHead != FormSetLink) {
+    FormSet = FORM_BROWSER_FORMSET_FROM_LINK (FormSetLink);
+    //
+    // Parse all forms in formset
+    //
+    FormLink = FormSet->FormListHead.ForwardLink;
+
+    while (&FormSet->FormListHead != FormLink) {
+      Form = FORM_BROWSER_FORM_FROM_LINK (FormLink);
+      //
+      // Parse five kinds of Questions in Form
+      //
+      QuestionLink = Form->StatementListHead.ForwardLink;
+
+      while (&Form->StatementListHead != QuestionLink) {
+        Question = FORM_BROWSER_STATEMENT_FROM_LINK (QuestionLink);
+        QuestionLink = QuestionLink->ForwardLink;
+        //
+        // Parse five kinds of Questions in Form
+        //
+        if ((Question->Operand == EFI_IFR_ONE_OF_OP)
+          || (Question->Operand == EFI_IFR_NUMERIC_OP)
+          || (Question->Operand == EFI_IFR_CHECKBOX_OP)
+          || (Question->Operand == EFI_IFR_ORDERED_LIST_OP)
+          || (Question->Operand == EFI_IFR_STRING_OP)
+          ) {
+          //
+          // Only compare the valid EFI_IFR_VARSTORE_EFI_OP in multi-platform mode
+          //
+          if (Question->Type != EFI_IFR_VARSTORE_EFI_OP) {
+            continue;
+          } else if (Question->NewEfiVarstore
+            && ((Question->Attributes & EFI_VARIABLE_NON_VOLATILE) == 0)) {
+            continue;
+          }
+
+          CurUqiList = UqiList;
+          PlatformId = 0xFFFFFFFF;
+          DefaultId  = 0xFFFF;
+          while (CurUqiList != NULL) {
+            if ((CurUqiList->Header.Question == NULL)
+              && CompareUqiHeader (&(Question->Uqi), &(CurUqiList->Header))
+              && ((PlatformId != CurUqiList->Header.PlatformId[0]) || (DefaultId != CurUqiList->Header.DefaultId[0]))
+              ) {
+              CurUqiList->Header.Question = Question;
+              PlatformId = CurUqiList->Header.PlatformId[0];
+              DefaultId  = CurUqiList->Header.DefaultId[0];
+            }
+            CurUqiList = CurUqiList->Next;
+          }
+        }
+      }
+      FormLink = FormLink->ForwardLink;
+    }
+    FormSetLink = FormSetLink->ForwardLink;
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Create and insert the UQI Node to the UQI parameter list.
+
+  @retval  Node address              If successed, return the node address.
+  @retval  NULL                      An error occurred.
+
+**/
+static
+UQI_PARAM_LIST *
+CreateInsertUqiNode (
+  )
+{
+  UQI_PARAM_LIST    *Node;
+
+  Node = (UQI_PARAM_LIST *) malloc (sizeof (UQI_PARAM_LIST));
+  if (Node == NULL) {
+    return NULL;
+  }
+  memset (Node, 0, sizeof (UQI_PARAM_LIST));
+
+  if (mUqiList == NULL) {
+    mUqiList = Node;
+  } else {
+    mLastUqiList->Next = Node;
+  }
+
+  mLastUqiList = Node;
+  return Node;
+}
+/**
+  Parse the first part of QUI string
+
+  @param  **argv[]                   The dual array pointer to the parameters.
+  @param  Number                     The pointer to the number of the first character of UQI.
+  @param  Buffer                     The buffer to store the first part of UQI.
+
+  @retval  EFI_SUCCESS               Parse the QUI parameters successfully.
+  @retval  EFI_INVALID_PARAMETER     An error occurred.
+
+**/
+static
+EFI_STATUS
+ParseFirstpartOfUqi (
+  IN     CHAR8          **argv[],
+  OUT    UINT32         *Number,
+  OUT    UINT16          **Buffer
+  )
+{
+  UINT32   Index;
+
+  Index = 0;
+
+  *Number = (UINT32)StrToDec ((*argv)[0]);
+
+  if ((*Number <= 0) || (*Number > MAX_QUI_PARAM_LEN)) {
+    printf ("Error. Invalid UQI.\n");
+    return EFI_INVALID_PARAMETER;
+  }
+
+  *Buffer = malloc ((*Number + 1) * sizeof (CHAR16));
+  assert (*Buffer != NULL);
+  memset (*Buffer, 0, (*Number + 1) * sizeof (CHAR16));
+
+  for (Index = 0; Index < *Number; Index++) {
+    if (StrToDec ((*argv)[Index]) > 0xff) {
+      printf ("Error. Invalid UQI.\n");
+      return EFI_INVALID_PARAMETER;
+    }
+  *(*Buffer + Index) = (UINT16)StrToDec ((*argv)[Index + 1]);
+ }
+  return EFI_SUCCESS;
+}
+
+/**
+  Parse the QUI input parameters from the command line
+
+  @param  argc                       The pointer to the number of input parameters.
+  @param  **argv[]                   The dual array pointer to the parameters.
+
+  @retval  EFI_SUCCESS               Parse the QUI parameters successfully.
+  @retval  EFI_INVALID_PARAMETER     An error occurred.
+
+**/
+static
+EFI_STATUS
+ParseUqiParam (
+  IN  UINT32         *argc,
+  IN  CHAR8          **argv[]
+  )
+{
+  UINT32          Index;
+  UQI_PARAM_LIST  *UqiNode;
+  EFI_STATUS      Status;
+
+  Index   = 0;
+  UqiNode = NULL;
+
+  if (*argc < 4) {
+    printf ("Error. The correct command is 'FCE updateq -i <infd> -o <outfd> <UQI> <Question Type> <Value>'.\n");
+    return EFI_INVALID_PARAMETER;
+  }
+
+  UqiNode = CreateInsertUqiNode ();
+  assert (UqiNode != NULL);
+
+  UqiNode->Header.DefaultId  = (UINT16 *) calloc (1, sizeof (UINT16));
+  UqiNode->Header.PlatformId = (UINT64 *) calloc (1, sizeof (UINT64));
+
+  Status = ParseFirstpartOfUqi (argv, &(UqiNode->Header.HexNum), &(UqiNode->Header.Data));
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+  *argc -= (UqiNode->Header.HexNum + 1);
+  *argv += UqiNode->Header.HexNum + 1;
+  //
+  // Parse the TYPE and value
+  //
+  if (strcmp ("ONE_OF", (*argv)[0]) == 0) {
+    UqiNode->Header.Type = ONE_OF;
+  } else if (strcmp ("NUMERIC", (*argv)[0]) == 0) {
+    UqiNode->Header.Type = NUMERIC;
+  } else if (strcmp ("CHECKBOX", (*argv)[0]) == 0) {
+    UqiNode->Header.Type = CHECKBOX;
+  } else if (strcmp ("STRING", (*argv)[0]) == 0) {
+    UqiNode->Header.Type = STRING;
+  } else if (strcmp ("ORDERED_LIST", (*argv)[0]) == 0) {
+    UqiNode->Header.Type = ORDERED_LIST;
+  } else {
+    printf ("Error. The correct command is 'FCE updateq -i <infd> -o <outfd> <UQI> <Question Type> <Value>'.\n");
+    return EFI_INVALID_PARAMETER;
+  }
+  *argc -= 1;
+  *argv += 1;
+  //
+  // Get the value according to the type of questions.
+  //
+  switch (UqiNode->Header.Type) {
+
+  case ONE_OF:
+  case NUMERIC:
+  case CHECKBOX:
+    UqiNode->Header.Value    = malloc (sizeof (UINT64));
+    if (UqiNode->Header.Value == NULL) {
+      printf ("Fali to allocate memory!\n");
+      return EFI_OUT_OF_RESOURCES;
+    }
+    memset (UqiNode->Header.Value, 0, sizeof (UINT64));
+
+    UqiNode->Header.DiffValue    = malloc (sizeof (UINT64));
+    if (UqiNode->Header.DiffValue == NULL) {
+      printf ("Fali to allocate memory!\n");
+      return EFI_OUT_OF_RESOURCES;
+    }
+    memset (
+      UqiNode->Header.DiffValue,
+      0,
+      sizeof (UINT64)
+      );
+    *(UINT64 *)(UqiNode->Header.Value) = (UINT64)StrToDec ((*argv)[0]);
+    break;
+
+  case ORDERED_LIST:
+    UqiNode->Header.Value    = malloc (((UINTN)StrToDec ((*argv)[0]) + 1) * sizeof (UINT64));
+    if (UqiNode->Header.Value == NULL) {
+      printf ("Fali to allocate memory!\n");
+      return EFI_OUT_OF_RESOURCES;
+    }
+    memset (
+      UqiNode->Header.Value,
+      0,
+      (UINTN)StrToDec(((*argv)[0]) + 1) * sizeof (UINT64)
+      );
+
+    UqiNode->Header.DiffValue    = malloc (((UINTN)StrToDec ((*argv)[0]) + 1) * sizeof (UINT64));
+    if (UqiNode->Header.DiffValue == NULL) {
+      printf ("Fali to allocate memory!\n");
+      return EFI_OUT_OF_RESOURCES;
+    }
+    memset (
+      UqiNode->Header.DiffValue,
+      0,
+      (UINTN)(StrToDec ((*argv)[0]) + 1) * sizeof (UINT64)
+      );
+
+    *UqiNode->Header.Value = (UINT8)StrToDec ((*argv)[0]);
+    for (Index = 1; Index <= StrToDec ((*argv)[0]); Index++) {
+      *((UINT64 *)UqiNode->Header.Value + Index) = StrToDec ((*argv)[Index]);
+    }
+    *argc -= (UINTN)StrToDec ((*argv)[0]);
+    *argv += (UINTN)StrToDec ((*argv)[0]);
+    break;
+
+  default:
+    break;
+  }
+
+  *argc -= 1;
+  *argv += 1;
+
+  if (*argc > 0) {
+    printf ("Error. The correct command is 'FCE updateq -i <infd> -o <outfd> <UQI> <Question Type> <Value>'.\n");
+    return EFI_INVALID_PARAMETER;
+  }
+  return EFI_SUCCESS;
+}
+/**
+  Parse the input Fd file, and get the file name according to the FILETYPE.
+
+  @param  FdName             The Name of Fd file
+  @param  FILETYPE           The type of Fd file
+
+  @return EFI_SUCCESS        Get the file name successfully
+  @return EFI_ABORTED        An error occurred.
+**/
+static
+EFI_STATUS
+ParseInFile (
+  IN CHAR8    *FdName,
+  IN FILETYPE Type
+)
+{
+  FILE      *Fptr;
+
+  Fptr  = NULL;
+
+  if ((Type == INFD) && ((FdName == NULL) || (Fptr = fopen (FdName, "r")) == NULL)) {
+    if (FdName != NULL) {
+      printf ("Error: The <infd> file doesn't exist '%s'\n", FdName);
+    }
+    return EFI_ABORTED;
+  }
+  if ((Type == OUTFD) && (FdName == NULL) ) {
+    printf ("Error: The <Outfd> name is NULL.\n");
+    return EFI_ABORTED;
+  }
+  if ((Type == SETUPTXT) && (FdName == NULL) ) {
+    printf ("Error: The <script> name is NULL.\n");
+    return EFI_ABORTED;
+  }
+  if (strlen (FdName) > MAX_FILENAME_LEN - 1) {
+    printf ("Error: The <fd> name is too long.\n");
+    if (Fptr != NULL) {
+      fclose (Fptr);
+    }
+    return EFI_ABORTED;
+  }
+  //
+  // Get and copy the file name
+  //
+  if (Type == INFD) {
+    strncpy (mInputFdName, FdName, MAX_FILENAME_LEN - 1);
+    mInputFdName[MAX_FILENAME_LEN - 1] = 0;
+  }
+  if (Type == OUTFD) {
+    strncpy (mOutputFdName, FdName, MAX_FILENAME_LEN - 1);
+    mOutputFdName[MAX_FILENAME_LEN - 1] = 0;
+  }
+  if (Type == OUTTXT) {
+    strncpy (mOutTxtName, FdName, MAX_FILENAME_LEN - 1);
+    mOutTxtName[MAX_FILENAME_LEN - 1] = 0;
+  }
+  if (Type == SETUPTXT) {
+    strncpy (mSetupTxtName, FdName, MAX_FILENAME_LEN - 1);
+    mSetupTxtName[MAX_FILENAME_LEN - 1] = 0;
+  }
+  if (Fptr != NULL) {
+    fclose (Fptr);
+  }
+  return EFI_SUCCESS;
+}
+/**
+  Print the usage of this tools.
+
+  @return NULL
+**/
+static
+VOID
+Usage (
+  VOID
+  )
+{
+  //
+  // Print utility header
+  //
+  printf ("\nIntel(R) Firmware Configuration Editor. (Intel(R) %s) Version %d.%d. %s.\n\n",
+    UTILITY_NAME,
+    UTILITY_MAJOR_VERSION,
+    UTILITY_MINOR_VERSION,
+  __BUILD_VERSION
+    );
+  //
+  // Copyright declaration
+  //
+  fprintf (stdout, "Copyright (c) 2010-2018, Intel Corporation. All rights reserved.\n\n");
+  //
+  // Summary usage
+  //
+  fprintf (stdout, "The tool enables you to retrieve and change HII configuration (Setup) data in \n");
+  fprintf (stdout, "Firmware Device files.\n");
+  fprintf (stdout, "\nUsage: \n");
+  fprintf (stdout, "    FCE  [read    -i <infd>  [<PlatformId UQI>] ['>' <script>]] \n");
+  fprintf (stdout, "    FCE  [update  -i <infd>  [<PlatformId UQI>|-s <script>] -o <outfd>\n");
+  fprintf (stdout, "               [--remove|--ignore] [-g <FvNameGuid>]] [-a]\n");
+  fprintf (stdout, "    FCE  [verify  -i <infd>  -s <script>] \n");
+  fprintf (stdout, "    FCE  [updateq -i <infd>  -o <outfd> <UQI> <Question Type> <Value>] \n");
+  fprintf (stdout, "    FCE  [[help] | [-?]] \n");
+  fprintf (stdout, "\n");
+
+  fprintf (stdout, "Options:\n");
+  fprintf (stdout, "    read             Extract the HII data from the <infd> file. \n");
+  fprintf (stdout, "    update           Update the HII data to the <outfd> file. \n");
+  fprintf (stdout, "    verify           Verify the current platform configuration. \n");
+  fprintf (stdout, "    updateq          Update the current platform configuration by command line.\n");
+  fprintf (stdout, "                     updateq only supports common mode.\n");
+  fprintf (stdout, "    help             Display the help information.\n");
+
+  fprintf (stdout, "    <infd>           The name of a existing Firmware Device binary file input. \n");
+  fprintf (stdout, "    <PlatformId UQI> The UQI is required in multi-platform mode to represent a \n");
+  fprintf (stdout, "                     PlatformId question from the VFR files used during binary \n");
+  fprintf (stdout, "                     image creation. It must not be used for common mode. \n");
+  fprintf (stdout, "    <outfd>          The name of a Firmware Device binary file output. \n");
+  fprintf (stdout, "    <script>         The name of a configure scripts.\n");
+  fprintf (stdout, "    <UQI>            A hex number followed by an array of hex numbers. \n");
+  fprintf (stdout, "    <Question Type>  One of ORDERED_LIST, ONE_OF, NUMERIC, STRING or CHECKBOX. \n");
+  fprintf (stdout, "    <Value>          A single hex number, if the <Question Type> is ONE_OF,\n");
+  fprintf (stdout, "                     NUMERIC, or CHECKBOX. Or a single hex number containing \n");
+  fprintf (stdout, "                     the array size followed by an array of that length of hex\n");
+  fprintf (stdout, "                     numbers, if the <Question Type> is ORDERED_LIST. \n");
+  fprintf (stdout, "    <FvNameGuid>     GuidValue is one specific FvName guid value.\n");
+  fprintf (stdout, "                     Its format is xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx.\n");
+  fprintf (stdout, "    -i               Import an existing FD file <infd>. \n");
+  fprintf (stdout, "    -o               Create the new FD with the changes made. \n");
+  fprintf (stdout, "    -s               Import config scripts. \n");
+  fprintf (stdout, "     >               Redirect the output to a scripts. \n");
+  fprintf (stdout, "    -?               Display the help information. \n");
+  fprintf (stdout, "    --remove         If one or more of the settings that are updated also \n");
+  fprintf (stdout, "                     exists in NV RAM, remove them only in multi-platform mode.\n");
+  fprintf (stdout, "    --ignore         If one or more of the settings that are updated also \n");
+  fprintf (stdout, "                     existsin NV RAM, ignore them only in multi-platform mode.\n");
+  fprintf (stdout, "    -g               Specify the FV image to store the multi-platform default \n");
+  fprintf (stdout, "                     setting. If it is missing, the multi-platform default \n");
+  fprintf (stdout, "                     will be inserted into BFV image.\n");
+  fprintf (stdout, "    -a               Specify this tool to choose the smaller size between two \n");
+  fprintf (stdout, "                     different storage formats in NV RAM. It's only vaild in \n");
+  fprintf (stdout, "                     multi-platform mode. \n");
+  fprintf (stdout, "\n");
+
+  fprintf (stdout, "Mode:\n");
+  fprintf (stdout, "    Common           Extract the HII data from IFR binary and update it to the \n");
+  fprintf (stdout, "                     EFI variable. \n");
+  fprintf (stdout, "    Multi-platform   The default value depends on the PlatformId and DefaultId \n");
+  fprintf (stdout, "                     described in the VFR files. This tool will create the \n");
+  fprintf (stdout, "                     binary file to store default settings at build time for \n");
+  fprintf (stdout, "                     different platforms and modes adding all default settings \n");
+  fprintf (stdout, "                     into BFV as one FFS.\n");
+
+  fprintf (stdout, "\n");
+}
+
+/**
+  Parse the command line parameters
+
+  @param   argc                      The pointer to number of input parameters.
+  @param   *argv[]                   The pointer to the parameters.
+
+  @retval  EFI_SUCCESS               Parse the parameters successfully.
+  @retval  EFI_INVALID_PARAMETER     An error occurred.
+
+**/
+static
+EFI_STATUS
+ParseCommmadLine (
+  IN     UINTN          argc,
+  IN     CHAR8          *argv[]
+  )
+{
+  EFI_STATUS     Status;
+  UINT8          Index;
+  UINT8          IndexParamI;
+  UINT8          IndexParamS;
+  UINT8          IndexParamO;
+  UINT8          IndexParamRemove;
+  UINT8          IndexParamIgnore;
+  UINT8          IndexParamOptimize;
+  EFI_GUID       FvNameGuid;
+
+  Status      = EFI_SUCCESS;
+  Index       = 0;
+  IndexParamI = 0;
+  IndexParamO = 0;
+  IndexParamS = 0;
+  IndexParamRemove = 0;
+  IndexParamIgnore = 0;
+  IndexParamOptimize                     = 0;
+  mMultiPlatformParam.SizeOptimizedParam = FALSE;
+  //
+  // Check for only own one operations
+  //
+  if (argc == 0) {
+    Usage ();
+    Status = EFI_INVALID_PARAMETER;
+    goto Done;
+  }
+  if (
+    argc == 1                           \
+    && ((stricmp(argv[0], "read") == 0)   \
+    || (stricmp(argv[0], "update") == 0)  \
+    || (stricmp(argv[0], "updateq") == 0) \
+    || (stricmp(argv[0], "verify") == 0) )
+    ) {
+      printf ("Error:  Some parameters have been lost. Please correct. \n");
+      Usage ();
+      Status = EFI_INVALID_PARAMETER;
+      goto Done;
+   }
+
+  while (argc > 0) {
+    if (stricmp(argv[0], "read") == 0) {
+      Operations = READ;
+      argc--;
+      argv++;
+
+      if (argc < 2) {
+        printf ("Error. The correct command is 'FCE read -i <infd>'. \n");
+        Usage ();
+        Status = EFI_INVALID_PARAMETER;
+        goto Done;
+      }
+      //
+      // Get input FD file name.
+      //
+      if (stricmp (argv[0], "-i") == 0) {
+        Status = ParseInFile (argv[1], INFD);
+        if (EFI_ERROR (Status)) {
+          goto Done;
+        }
+        argc -= 2;
+        argv += 2;
+      }
+     //
+     // Parse the QUI parameters
+     //
+     if (argc > 2) {
+       Status = ParseFirstpartOfUqi (&argv, &(mMultiPlatformParam.Uqi.HexNum), &(mMultiPlatformParam.Uqi.Data));
+       mMultiPlatformParam.MultiPlatformOrNot = TRUE;
+       if (EFI_ERROR (Status)) {
+         goto Done;
+       }
+     }
+     break;
+
+    } else if (stricmp(argv[0], "update") == 0) {
+      //
+      // Update the config file to Fd
+      //
+      Operations = UPDATE;
+      argc--;
+      argv++;
+
+      if (argc < 4) {
+        printf ("Error. The correct command is 'FCE update -i <infd> [<PlatformId UQI>|-s <script>] -o <outfd>' \n");
+        Usage ();
+        Status = EFI_INVALID_PARAMETER;
+        goto Done;
+      }
+
+      continue;
+    } else if (stricmp(argv[0], "verify") == 0) {
+      //
+      // 3. Parse the command line "FCE verify -i <infd> -s <script>"
+      //
+      Operations = VERIFY;
+      argc--;
+      argv++;
+
+      if (argc < 4) {
+        printf ("Error. The correct command is 'FCE verify -i <infd> -s <script>'\n");
+        Usage ();
+        Status = EFI_INVALID_PARAMETER;
+        goto Done;
+      }
+
+      continue;
+    } else if (stricmp(argv[0], "updateq") == 0) {
+      //
+      // Parse the command line "FCE updateq -i <infd> -o<outfd> <UQI> <Question Type> <Value>"
+      //
+      argc--;
+      argv++;
+
+      //
+      // Get input/output FD file name.
+      //
+      Index = 2;
+      while ((Index > 0) && (argc > 1)) {
+        if (stricmp (argv[0], "-i") == 0) {
+          Status = ParseInFile (argv[1], INFD);
+          if (EFI_ERROR (Status)) {
+            goto Done;
+          }
+          argc -= 2;
+          argv += 2;
+          Index--;
+          IndexParamI++;
+          continue;
+        }
+
+        if (stricmp (argv[0], "-o") == 0) {
+          Status = ParseInFile (argv[1], OUTFD);
+          if (EFI_ERROR (Status)) {
+            goto Done;
+          }
+          argc -= 2;
+          argv += 2;
+          Index--;
+          IndexParamO++;
+          continue;
+        }
+        if (
+         (argc >= 1) \
+         && (stricmp(argv[0], "-o") != 0) \
+         && (stricmp(argv[0], "-i") != 0)
+          ) {
+          printf ("Error. The correct command is 'FCE updateq -i <infd> -o <outfd> <UQI> <Question Type> <Value>' \n");
+          Usage();
+          Status = EFI_INVALID_PARAMETER;
+          goto Done;
+        }
+      }
+
+      if (Index != 0) {
+        printf ("Error. The correct command is 'FCE updateq -i <infd> -o <outfd> <UQI> <Question Type> <Value>' \n");
+        Usage ();
+        Status = EFI_INVALID_PARAMETER;
+        goto Done;
+      }
+
+      //
+      // Parse the QUI parameters
+      //
+      Status = ParseUqiParam ((UINT32 *)&argc,&argv);
+      if (EFI_ERROR (Status)) {
+        goto Done;
+      }
+      Operations = UPDATEQ;
+      break;
+    }
+
+    if (stricmp (argv[0], "-i") == 0) {
+      Status = ParseInFile (argv[1], INFD);
+      if (EFI_ERROR (Status)) {
+        goto Done;
+      }
+      argc -= 2;
+      argv += 2;
+      IndexParamI++;
+      continue;
+    }
+
+    if (stricmp (argv[0], "-o") == 0) {
+      Status = ParseInFile (argv[1], OUTFD);
+      if (EFI_ERROR (Status)) {
+        goto Done;
+      }
+      argc -= 2;
+      argv += 2;
+      IndexParamO++;
+      continue;
+    }
+
+    if (stricmp (argv[0], "-s") == 0) {
+      Status = ParseInFile (argv[1], SETUPTXT);
+      if (EFI_ERROR (Status)) {
+        goto Done;
+      }
+      argc -= 2;
+      argv += 2;
+      IndexParamS++;
+      continue;
+    }
+
+    if (stricmp (argv[0], "-g") == 0) {
+      Status = StringToGuid (argv[1], &FvNameGuid);
+      if (EFI_ERROR (Status)) {
+        printf ("Error: Invalid parameters for -g option in command line. \n");
+        Usage();
+        goto Done;
+      }
+      mFvNameGuidString = argv[1];
+      argc -= 2;
+      argv += 2;
+      continue;
+    }
+
+    if (stricmp (argv[0], "-a") == 0) {
+      argc -= 1;
+      argv += 1;
+      IndexParamOptimize++;
+      mMultiPlatformParam.SizeOptimizedParam = TRUE;
+      continue;
+    }
+
+    if (stricmp (argv[0], "--remove") == 0) {
+      argc -= 1;
+      argv += 1;
+      IndexParamRemove++;
+      Operations = UPDATE_REMOVE;
+      continue;
+    }
+
+    if (stricmp (argv[0], "--ignore") == 0) {
+      argc -= 1;
+      argv += 1;
+      IndexParamIgnore++;
+      Operations = UPDATE_IGNORE;
+      continue;
+    }
+
+    if ((stricmp(argv[0], "help") == 0) || (stricmp(argv[0], "-?") == 0)) {
+
+      Usage();
+      Status = EFI_INVALID_PARAMETER;
+      goto Done;
+    }
+    //
+    // Operations should not be none
+    //
+    if ( Operations == NONE ) {
+      printf ("Error. Only support read/update/verify/updateq mode. \n");
+      Usage();
+      Status = EFI_INVALID_PARAMETER;
+      goto Done;
+    }
+
+    if (Operations == UPDATE) {
+      Status = ParseFirstpartOfUqi (&argv, &(mMultiPlatformParam.Uqi.HexNum), &(mMultiPlatformParam.Uqi.Data));
+      if (!EFI_ERROR (Status)) {
+        mMultiPlatformParam.MultiPlatformOrNot = TRUE;
+        argc = argc - mMultiPlatformParam.Uqi.HexNum - 1;
+        argv = argv + mMultiPlatformParam.Uqi.HexNum + 1;
+        continue;
+      }
+    }
+
+    if (
+      (argc >= 1) \
+      && (stricmp(argv[0], "-?") != 0)
+      && (stricmp(argv[0], "help") != 0)
+      && (stricmp(argv[0], "verify") != 0)
+      && (stricmp(argv[0], "read") != 0)
+      && (stricmp(argv[0], "update") != 0)
+      && (stricmp(argv[0], "updateq") != 0)
+      && (stricmp(argv[0], "-o") != 0)
+      && (stricmp(argv[0], "-i") != 0)
+      && (stricmp(argv[0], "-s") != 0)
+      && (stricmp(argv[0], "-a") != 0)
+      && (stricmp(argv[0], "-g") != 0)
+      && (stricmp(argv[0], "--remove") != 0)
+      && (stricmp(argv[0], "--ignore") != 0)
+      ) {
+      printf ("Error: Invalid parameters exist in command line. \n");
+      Usage();
+      Status = EFI_INVALID_PARAMETER;
+      goto Done;
+    }
+  }
+  //
+  // Check the repeated parameters in command line, such as "-i -i"
+  //
+  if (
+    (IndexParamI > 1)
+    || (IndexParamO > 1)
+    || (IndexParamS > 1)
+    || (IndexParamOptimize > 1)
+    || (IndexParamRemove > 1)
+    || (IndexParamIgnore > 1)
+    ) {
+    printf ("Error:  Redundant parameters exist in command line.\n");
+    Usage();
+    Status = EFI_INVALID_PARAMETER;
+    goto Done;
+  }
+  //
+  // Check improper parameters in command line, such as "FCE read -i -s"
+  //
+  if (
+    ((Operations == READ) && ((IndexParamO >= 1) || (IndexParamS >= 1) || (IndexParamRemove >= 1) || (IndexParamIgnore >= 1))) \
+    || ((Operations == VERIFY) && ((IndexParamO >= 1) || (IndexParamRemove >= 1) || (IndexParamIgnore >= 1))) \
+    || ((Operations == UPDATEQ) && ((IndexParamS >= 1) || (IndexParamRemove >= 1) || (IndexParamIgnore >= 1))) \
+    || ((Operations == UPDATE) && ((IndexParamRemove >= 1) && (IndexParamIgnore >= 1)))
+    || ((Operations != UPDATE && Operations != UPDATE_REMOVE && Operations != UPDATE_IGNORE) && ((IndexParamOptimize >= 1) || (mFvNameGuidString != NULL)))
+   ) {
+    printf ("Error:  Improper parameters exist in command line. \n");
+    Usage();
+    Status = EFI_INVALID_PARAMETER;
+    goto Done;
+  }
+Done:
+  return Status;
+}
+
+/**
+  Check whether exists the valid variables in NvStorage or not.
+
+  @retval TRUE      If existed, return TRUE.
+  @retval FALSE     Others
+**/
+static
+BOOLEAN
+ExistEfiVarOrNot (
+  IN  LIST_ENTRY  *StorageListHead
+  )
+{
+   EFI_FIRMWARE_VOLUME_HEADER   *VarAddr;
+   BOOLEAN                      Existed;
+   VOID                         *VariableStoreHeader;
+   BOOLEAN                      AuthencitatedMonotonicOrNot;
+   BOOLEAN                      AuthencitatedBasedTimeOrNot;
+
+   VarAddr                     = (EFI_FIRMWARE_VOLUME_HEADER   *) gEfiFdInfo.EfiVariableAddr;
+   VariableStoreHeader         = (VOID *)((CHAR8 *)VarAddr + VarAddr->HeaderLength);
+   AuthencitatedMonotonicOrNot = FALSE;
+   AuthencitatedBasedTimeOrNot = FALSE;
+   Existed                     = TRUE;
+   //
+   // Judge the layout of NV by gEfiVariableGuid
+   //
+   AuthencitatedMonotonicOrNot  = CheckMonotonicBasedVarStore (VariableStoreHeader);
+   AuthencitatedBasedTimeOrNot  = CheckTimeBasedVarStoreOrNot (VariableStoreHeader);
+
+   if (AuthencitatedMonotonicOrNot) {
+     //
+     // Check the Monotonic based authenticate variable
+     //
+     Existed = ExistMonotonicBasedEfiVarOrNot (StorageListHead);
+   } else if (AuthencitatedBasedTimeOrNot){
+     //
+     // Check the Time Sample authenticate variable
+     //
+     Existed = ExistTimeBasedEfiVarOrNot (StorageListHead);
+   } else {
+     //
+     // Check the normal variable
+     //
+     Existed = ExistNormalEfiVarOrNot (StorageListHead);
+   }
+
+   return Existed;
+}
+
+/**
+  Exchange the data between Efi variable and the data of VarList
+
+  If VarToList is TRUE, copy the efi variable data to the VarList; Otherwise,
+  update the data from varlist to efi variable.
+
+  @param VarToList         The flag to control the direction of exchange.
+  @param StorageListHead   Decide which variale list be updated
+
+  @retval EFI_SUCCESS      Get the address successfully.
+**/
+static
+EFI_STATUS
+EfiVarAndListExchange (
+  IN BOOLEAN      VarToList,
+  IN  LIST_ENTRY  *StorageListHead
+  )
+{
+   EFI_FIRMWARE_VOLUME_HEADER   *VarAddr;
+   EFI_STATUS                   Status;
+   VOID                         *VariableStoreHeader;
+   BOOLEAN                      AuthencitatedMonotonicOrNot;
+   BOOLEAN                      AuthencitatedBasedTimeOrNot;
+
+   Status                      = EFI_ABORTED;
+   VarAddr                     = (EFI_FIRMWARE_VOLUME_HEADER   *) gEfiFdInfo.EfiVariableAddr;
+   VariableStoreHeader         = (VOID *)((CHAR8 *)VarAddr + VarAddr->HeaderLength);
+   AuthencitatedMonotonicOrNot = FALSE;
+   AuthencitatedBasedTimeOrNot = FALSE;
+   //
+   // Judge the layout of NV by gEfiVariableGuid
+   //
+   AuthencitatedMonotonicOrNot  = CheckMonotonicBasedVarStore (VariableStoreHeader);
+   AuthencitatedBasedTimeOrNot  = CheckTimeBasedVarStoreOrNot (VariableStoreHeader);
+
+   if (AuthencitatedMonotonicOrNot) {
+     //
+     // Update the Monotonic based authenticate variable
+     //
+     Status = SynAuthEfiVariable (VarToList, StorageListHead);
+   } else if (AuthencitatedBasedTimeOrNot){
+     //
+     // Update the Time Sample authenticate variable
+     //
+     Status = SynAuthEfiVariableBasedTime (VarToList, StorageListHead);
+   } else {
+     //
+     // Update the normal variable
+     //
+     Status = SynEfiVariable (VarToList, StorageListHead);
+   }
+
+   return Status;
+}
+
+/**
+  Check the layout of NvStorage and remove the variable from Efi variable
+
+  Found the variable with the same name in StorageListHead and remove it.
+
+  @param StorageListHead   Decide which variale list be removed.
+
+  @retval EFI_SUCCESS      Remove the variables successfully.
+**/
+static
+EFI_STATUS
+RemoveEfiVar (
+  IN  LIST_ENTRY  *StorageListHead
+  )
+{
+   EFI_FIRMWARE_VOLUME_HEADER   *VarAddr;
+   EFI_STATUS                   Status;
+   VOID                         *VariableStoreHeader;
+   BOOLEAN                      AuthencitatedMonotonicOrNot;
+   BOOLEAN                      AuthencitatedBasedTimeOrNot;
+
+   Status                      = EFI_ABORTED;
+   VarAddr                     = (EFI_FIRMWARE_VOLUME_HEADER   *) gEfiFdInfo.EfiVariableAddr;
+   VariableStoreHeader         = (VOID *)((CHAR8 *)VarAddr + VarAddr->HeaderLength);
+   AuthencitatedMonotonicOrNot = FALSE;
+   AuthencitatedBasedTimeOrNot = FALSE;
+   //
+   // Judge the layout of NV by gEfiVariableGuid
+   //
+   AuthencitatedMonotonicOrNot  = CheckMonotonicBasedVarStore (VariableStoreHeader);
+   AuthencitatedBasedTimeOrNot  = CheckTimeBasedVarStoreOrNot (VariableStoreHeader);
+
+   if (AuthencitatedMonotonicOrNot) {
+     //
+     // Update the Monotonic based authenticate variable
+     //
+     Status = RemoveAuthEfiVariable (StorageListHead);
+   } else if (AuthencitatedBasedTimeOrNot){
+     //
+     // Update the Time Sample authenticate variable
+     //
+     Status = RemoveAuthEfiVariableBasedTime (StorageListHead);
+   } else {
+     //
+     // Update the normal variable
+     //
+     Status = RemoveNormalEfiVariable (StorageListHead);
+   }
+
+   return Status;
+}
+
+/**
+  Parse the all formset in one VfrBin.
+
+  Parse all questions, variables and expression in VfrBin, and store
+  it in Formset and Form.
+
+  @param BaseAddr           The pointer to the array of VfrBin base address.
+  @param UniBinBaseAddress  The pointer to one Uni string base address.
+
+  @retval EFI_SUCCESS       The Search was complete successfully
+  @return EFI_ABORTED       An error occurred
+**/
+static
+EFI_STATUS
+ParseFormSetInVfrBin (
+  IN  UINTN     **BaseAddr,
+  IN  UINTN     *UniBinBaseAddress,
+  IN  UINT8     Index
+  )
+{
+  UINT32                PackageLength;
+  EFI_STATUS            Status;
+  FORM_BROWSER_FORMSET  *FormSet;
+  UINT8                 *IfrBinaryData;
+  EFI_IFR_OP_HEADER     *IfrOpHdr;
+  UINT32                IfrOffset;
+
+  PackageLength = 0;
+  Status        = EFI_SUCCESS;
+  FormSet       = NULL;
+  IfrBinaryData = NULL;
+  IfrOpHdr      = NULL;
+
+  //
+  // The first 4 Bytes of VfrBin is used to record the Array Length
+  // The header of VfrBin is, ARRAY LENGTH:4 Bytes, PACKAGE HEADER:4 Bytes (2 Bytes for Len, and the other for Type)
+  //
+  PackageLength = *(UINT32 *)*(BaseAddr + Index) - 4;
+  IfrBinaryData   = (UINT8 *)*(BaseAddr + Index) + 4;
+
+  //
+  // Go through the form package to parse OpCode one by one.
+  //
+  IfrOffset       = sizeof (EFI_HII_PACKAGE_HEADER);
+
+  while (IfrOffset < PackageLength) {
+    //
+    // Search the Formset in VfrBin
+    //
+    IfrOpHdr  = (EFI_IFR_OP_HEADER *) (IfrBinaryData + IfrOffset);
+
+    if (IfrOpHdr->OpCode == EFI_IFR_FORM_SET_OP) {
+      FormSet = calloc (sizeof (FORM_BROWSER_FORMSET), sizeof (CHAR8));
+      if (FormSet == NULL) {
+        return EFI_ABORTED;
+      }
+      FormSet->IfrBinaryData   = IfrBinaryData + IfrOffset;
+      FormSet->UnicodeBinary   = (UINT8 *) UniBinBaseAddress;
+      //
+      //This length will be corrected in ParseOpCodes function.
+      //
+      FormSet->IfrBinaryLength = PackageLength - IfrOffset;
+      //
+      // Parse opcodes in the formset IFR binary.
+      //
+      Status = ParseOpCodes (FormSet);
+      if (EFI_ERROR (Status)) {
+        DestroyAllStorage (FormSet->StorageListHead);
+        DestroyFormSet (FormSet);
+        return EFI_ABORTED;
+      }
+      IfrOffset += FormSet->IfrBinaryLength;
+      FormSet->EnUsStringList.StringInfoList = calloc (sizeof (STRING_INFO), STRING_NUMBER);
+      FormSet->EnUsStringList.CachedIdNum = 0;
+      FormSet->EnUsStringList.MaxIdNum = STRING_NUMBER;
+      FormSet->UqiStringList.StringInfoList = calloc (sizeof (STRING_INFO), STRING_NUMBER);
+      FormSet->UqiStringList.CachedIdNum = 0;
+      FormSet->UqiStringList.MaxIdNum = STRING_NUMBER;
+      //
+      // Insert the FormSet to mFormSet
+      //
+      InsertTailList (&mFormSetListEntry, &FormSet->Link);
+    } else {
+      IfrOffset += IfrOpHdr->Length;
+    }
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Store all defaultId to mMultiPlatformParam.
+
+  The mMultiPlatformParam.DefaultId[0] is used to store standard default.
+
+  @param DefaultId      The current defaultID.
+
+  @retval EFI_SUCCESS   It was complete successfully
+  @return EFI_ABORTED   An error occurred
+**/
+VOID
+StoreAllDefaultId (
+  IN  UINT16   DefaultId
+)
+{
+  UINT32            Index;
+
+  if ((mMultiPlatformParam.DefaultIdNum == 0) && (DefaultId != 0)) {
+      mMultiPlatformParam.DefaultId[0] = DefaultId;
+      mMultiPlatformParam.DefaultIdNum++;
+      return;
+  }
+  //
+  // Only store the different value to mMultiPlatformParam.DefaultId[1] - mMultiPlatformParam.DefaultId[n]
+  //
+  for (Index = 0; Index < mMultiPlatformParam.DefaultIdNum; Index++) {
+    if (mMultiPlatformParam.DefaultId[Index] == DefaultId) {
+      return;
+    }
+  }
+  mMultiPlatformParam.DefaultId[Index] = DefaultId;
+  mMultiPlatformParam.DefaultIdNum++;
+}
+
+/**
+  Read all defaultId and platformId from binary.
+
+  @param  Binary        The pointer to the bianry
+  @param  Storage       The pointer to the Storage
+**/
+VOID
+ReadDefaultAndPlatformIdFromBfv (
+  IN  UINT8             *Binary,
+  IN  FORMSET_STORAGE   *Storage
+)
+{
+  UINT16   Length;
+  UINT16   Size;
+  UINT32   Index;
+
+  Length = *(UINT16 *)Binary - sizeof (UINT16);
+  Index  = 0;
+  Size   = 0;
+
+  Binary = Binary + sizeof (UINT16);
+
+  for (Size = 0; Size < Length; Size += sizeof (UINT16) + mMultiPlatformParam.PlatformIdWidth, Index++) {
+    Storage->DefaultId[Index] = *(UINT16 *)(Binary + Size);
+    memcpy (&Storage->PlatformId[Index], (Binary + Size + sizeof (UINT16)), mMultiPlatformParam.PlatformIdWidth);
+  }
+  Storage->DefaultPlatformIdNum = Index - 1;
+}
+
+/**
+  Store all defaultId and platformId to binary.
+
+  @param  Binary        The pointer to the bianry
+  @param  Storage       The pointer to the Storage
+
+  @retval Length        Return the length of the header
+**/
+UINT32
+WriteDefaultAndPlatformId (
+  IN  UINT8             *Binary,
+  IN  FORMSET_STORAGE   *Storage
+)
+{
+  UINT16   Length;
+  UINT32   Index;
+  UINT8    *Buffer;
+
+  Length = 0;
+  Buffer = Binary;
+
+  Buffer = Buffer + sizeof (CHAR16);
+
+  for (Index = 0; Index <= Storage->DefaultPlatformIdNum; Index++) {
+    *(UINT16 *)Buffer = Storage->DefaultId[Index];
+    Buffer = Buffer + sizeof (CHAR16);
+    memcpy (Buffer, &Storage->PlatformId[Index], mMultiPlatformParam.PlatformIdWidth);
+    Buffer = Buffer + mMultiPlatformParam.PlatformIdWidth;
+  }
+  Length = (UINT16) (Buffer - Binary);
+  //
+  // Record the offset to the first two bytes
+  //
+  *(UINT16 *)Binary = Length;
+
+  return Length;
+}
+
+/**
+  Store all defaultId and platformId to binary.
+
+  @param  Binary        The pointer to the bianry
+  @param  Storage       The pointer to the Storage
+
+  @retval Length        Return the length of the header
+**/
+UINT32
+WriteNvStoreDefaultAndPlatformId (
+  IN  UINT8             *Binary,
+  IN  FORMSET_STORAGE   *Storage
+)
+{
+  UINT16   Length;
+  UINT32   Index;
+  UINT8    *Buffer;
+
+  Length = 0;
+  Buffer = Binary + 8;
+
+  for (Index = 0; Index <= Storage->DefaultPlatformIdNum; Index++) {
+    *(UINT64 *)Buffer = Storage->PlatformId[Index];
+    Buffer = Buffer + sizeof(UINT64);
+    *(UINT16 *)Buffer = Storage->DefaultId[Index];
+    Buffer = Buffer + sizeof(UINT16);
+    // for Resered
+    Buffer = Buffer + 6;
+  }
+  Length = (UINT16) (Buffer - Binary - 8);
+  // for Header size
+  Length += 4;
+  return Length;
+}
+
+/**
+  Read the platformId from questions.
+
+  @retval EFI_SUCCESS   It was complete successfully.
+  @return EFI_ABORTED   An error occurred.
+**/
+EFI_STATUS
+ReadPlaformId (
+  IN  FORM_BROWSER_STATEMENT  *CurQuestion
+)
+{
+  UINT16           Index;
+  UINT64           IdValue;
+  LIST_ENTRY       *Link;
+  QUESTION_OPTION  *Option;
+  UINT64           Step;
+
+  Index            = 0;
+  IdValue          = 0;
+  Step             = 0;
+  //
+  // Check whether it is the question of paltform Id
+  //
+  if (!CompareUqiHeader (&(CurQuestion->Uqi), &(mMultiPlatformParam.Uqi))) {
+    return EFI_ABORTED;
+  }
+  //
+  // Copy the Question with platform to mMultiPlatformParam
+  //
+  memcpy (&mMultiPlatformParam.PlatformIdQuestion, CurQuestion, sizeof (FORM_BROWSER_STATEMENT));
+  mMultiPlatformParam.Question = CurQuestion;
+  //
+  // Pick up the value of NUMERIC and ONE_OF from current question and fill it in mMultiPlatformParam
+  //
+  mMultiPlatformParam.PlatformIdWidth = CurQuestion->StorageWidth;
+
+  if (CurQuestion->Operand == EFI_IFR_NUMERIC_OP) {
+    Index = 0;
+    if (CurQuestion->Step == 0) {
+      Step  = 1;
+    } else {
+      Step  = CurQuestion->Step;
+    }
+    for (IdValue = CurQuestion->Minimum; IdValue < CurQuestion->Maximum; IdValue += Step) {
+      mMultiPlatformParam.PlatformId[Index++] = (UINT64)IdValue;
+    }
+  }
+
+  if (CurQuestion->Operand == EFI_IFR_ONE_OF_OP) {
+    Index = 0;
+
+    Link = GetFirstNode (&CurQuestion->OptionListHead);
+    while (!IsNull (&CurQuestion->OptionListHead, Link)) {
+      Option = QUESTION_OPTION_FROM_LINK (Link);
+      mMultiPlatformParam.PlatformId[Index++] = Option->Value.Value.u64;
+      Link = GetNextNode (&CurQuestion->OptionListHead, Link);
+    }
+  }
+
+  if (Index >= MAX_PLATFORM_DEFAULT_ID_NUM) {
+    return EFI_ABORTED;
+  }
+  mMultiPlatformParam.PlatformIdNum = Index;
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Clear the buffer of Storage list.
+
+  @param StorageListHead The pointer to the entry of the storage list
+  @param DefaultId       The default Id for multi-platform support
+  @param PlatformId      The platform Id for multi-platform support
+
+  @retval NULL
+**/
+VOID
+ClearStorageEntryList (
+  IN  LIST_ENTRY   *StorageListHead,
+  IN  UINT16       DefaultId,
+  IN  UINT64       PlatformId
+  )
+{
+
+  LIST_ENTRY        *StorageLink;
+  FORMSET_STORAGE   *Storage;
+
+  Storage = NULL;
+
+  StorageLink = GetFirstNode (StorageListHead);
+
+  while (!IsNull (StorageListHead, StorageLink)) {
+    Storage = FORMSET_STORAGE_FROM_LINK (StorageLink);
+    if (Storage != NULL) {
+      memset (Storage->Buffer, 0x0, Storage->Size);
+      Storage->DefaultId[0]   = DefaultId;
+      Storage->PlatformId[0] = PlatformId;
+      Storage->DefaultPlatformIdNum = 0;
+    }
+    StorageLink = GetNextNode (StorageListHead, StorageLink);
+  }
+}
+
+/**
+  Append the platformid and default to the variables of CurDefaultId and CurPlatformId
+
+  @param  StorageListHead     The pointer to the storage list
+  @param  CurDefaultId        The default Id for multi-platform mode
+  @param  CurPlatformId       The platform Id for multi-platform mode
+  @param  DefaultId           The default Id for multi-platform mode
+  @param  PlatformId          The platform Id for multi-platform mode
+
+  @retval NULL
+**/
+VOID
+AppendIdToVariables (
+  IN  LIST_ENTRY   *StorageListHead,
+  IN  UINT16       CurDefaultId,
+  IN  UINT64       CurPlatformId,
+  IN  UINT16       DefaultId,
+  IN  UINT64       PlatformId
+)
+{
+  LIST_ENTRY        *StorageLink;
+  FORMSET_STORAGE   *Storage;
+
+  Storage          = NULL;
+
+  StorageLink = GetFirstNode (StorageListHead);
+
+  while (!IsNull (StorageListHead, StorageLink)) {
+    Storage = FORMSET_STORAGE_FROM_LINK (StorageLink);
+
+    if ((Storage->DefaultId[0] == CurDefaultId)
+      && (Storage->PlatformId[0] == CurPlatformId)
+      ) {
+      ++Storage->DefaultPlatformIdNum;
+      Storage->DefaultId[Storage->DefaultPlatformIdNum]  = DefaultId;
+      Storage->PlatformId[Storage->DefaultPlatformIdNum] = PlatformId;
+    }
+
+    StorageLink = GetNextNode (StorageListHead, StorageLink);
+  }
+}
+
+
+/**
+  Check whether StorageListHead2 is included in StorageListHead1
+
+  @param  StorageListHead1    The pointer to the entry of storage list
+  @param  StorageListHead2    The pointer to the entry of storage list
+  @param  DefaultId           The default Id for multi-platform mode
+  @param  PlatformId          The platform Id for multi-platform mode
+
+  @retval TRUE        Totally included.
+  @return FALSE       Other cases.
+**/
+BOOLEAN
+ComparePartSameVariableList (
+  IN   LIST_ENTRY   *StorageListHead1,
+  IN   LIST_ENTRY   *StorageListHead2,
+  OUT  UINT16       *DefaultId,
+  OUT  UINT64       *PlatformId
+)
+{
+  LIST_ENTRY        *StorageLink;
+  LIST_ENTRY        *TempStorageHead;
+  LIST_ENTRY        *TempStorageLink;
+  LIST_ENTRY        *TempStorageHead2;
+  LIST_ENTRY        *TempStorageLink2;
+  FORMSET_STORAGE   *Storage;
+  FORMSET_STORAGE   *TempStorage;
+  FORMSET_STORAGE   *TempStorage2;
+  UINT16            CurDefaultId;
+  UINT64            CurPlatformId;
+  UINT32            VariableNum;
+  UINT32            Index;
+
+  StorageLink      = NULL;
+  TempStorageHead  = NULL;
+  TempStorageLink  = NULL;
+  TempStorageHead2 = NULL;
+  TempStorageLink2 = NULL;
+  Storage          = NULL;
+  TempStorage      = NULL;
+  TempStorage2     = NULL;
+  CurDefaultId     = 0;
+  CurPlatformId    = 0;
+  VariableNum      = 0;
+  Index            = 0;
+  TempStorageHead  = StorageListHead1;
+
+
+  //
+  // Get the number of variables in StorageListHead2;
+  //
+  StorageLink = GetFirstNode (StorageListHead2);
+
+  while (!IsNull (StorageListHead2, StorageLink)) {
+    Storage = FORMSET_STORAGE_FROM_LINK (StorageLink);
+    //
+    // For multi-platform support, only need to calcuate the type of EFI_IFR_VARSTORE_EFI_OP.
+    //
+    if (mMultiPlatformParam.MultiPlatformOrNot &&
+        (Storage->Type == EFI_IFR_VARSTORE_EFI_OP) && (Storage->Name != NULL) && (Storage->NewEfiVarstore) &&
+        ((Storage->Attributes & EFI_VARIABLE_NON_VOLATILE) == EFI_VARIABLE_NON_VOLATILE)) {
+      VariableNum++;
+    }
+    StorageLink = GetNextNode (StorageListHead2, StorageLink);
+  }
+  //
+  // Parse every variables in StorageListHead1 and compare with ones in StorageListHead2
+  // Only all variables in StorageListHead2 are included in StorageListHead1, return TRUE.
+  //
+  StorageLink = GetFirstNode (StorageListHead1);
+
+  while (!IsNull (StorageListHead1, StorageLink)) {
+    Storage = FORMSET_STORAGE_FROM_LINK (StorageLink);
+    //
+    // Get specified DefaultId and PlatformId firstly
+    //
+    CurDefaultId  = Storage->DefaultId[0];
+    CurPlatformId = Storage->PlatformId[0];
+    Index         = 0;
+    //
+    // Compare all variables under same defaultId and platformId
+    //
+    TempStorageLink = GetFirstNode (TempStorageHead);
+    while (!IsNull (TempStorageHead, TempStorageLink)) {
+      TempStorage = FORMSET_STORAGE_FROM_LINK (TempStorageLink);
+      if ((TempStorage->DefaultId[0] == CurDefaultId)
+        && (TempStorage->PlatformId[0] == CurPlatformId)
+        && (TempStorage->Name != NULL)
+        && (TempStorage->Type == EFI_IFR_VARSTORE_EFI_OP)
+        && (TempStorage->NewEfiVarstore)
+        && ((TempStorage->Attributes & EFI_VARIABLE_NON_VOLATILE) == EFI_VARIABLE_NON_VOLATILE)
+        ) {
+        //
+        //Search the matched variable by Guid and name in StorageListHead2
+        //
+        TempStorageHead2 = StorageListHead2;
+        TempStorageLink2 = GetFirstNode (TempStorageHead2);
+
+        while (!IsNull (TempStorageHead2, TempStorageLink2)) {
+          TempStorage2     = FORMSET_STORAGE_FROM_LINK (TempStorageLink2);
+          if ((TempStorage2->Name != NULL)
+            && (TempStorage2->Type == EFI_IFR_VARSTORE_EFI_OP)
+            && (TempStorage2->NewEfiVarstore)
+            && ((TempStorage2->Attributes & EFI_VARIABLE_NON_VOLATILE) == EFI_VARIABLE_NON_VOLATILE)
+            && !FceStrCmp (TempStorage->Name, TempStorage2->Name)
+            && !CompareGuid(&TempStorage->Guid, &TempStorage2->Guid)
+            ) {
+            if (CompareMem (TempStorage->Buffer, TempStorage2->Buffer, TempStorage->Size) == 0) {
+              Index++;
+            }
+          }
+          TempStorageLink2 = GetNextNode (TempStorageHead2, TempStorageLink2);
+        }
+      }
+      TempStorageLink = GetNextNode (TempStorageHead, TempStorageLink);
+    }
+    //
+    // Check the matched variable number
+    //
+    if (Index == VariableNum) {
+      *DefaultId  = CurDefaultId;
+      *PlatformId = CurPlatformId;
+      return TRUE;
+    }
+    StorageLink = GetNextNode (StorageListHead1, StorageLink);
+  }
+  return FALSE;
+}
+
+/**
+  Check whether the defaultId and platformId mathched the variable or not
+
+  @param  Storage             The pointer to the storage
+  @param  DefaultId           The default Id for multi-platform mode
+  @param  PlatformId          The platform Id for multi-platform mode
+
+  @retval TRUE    Not Matched.
+  @return FALSE   Matched any one
+**/
+BOOLEAN
+NotEqualAnyIdOfStorage (
+IN  FORMSET_STORAGE   *Storage,
+IN  UINT16            DefaultId,
+IN  UINT64            PlatformId
+)
+{
+  UINT32  Index;
+
+  for (Index = 0; Index <= Storage->DefaultPlatformIdNum; Index++) {
+    if ((Storage->DefaultId[Index] == DefaultId)
+      &&(Storage->PlatformId[Index] == PlatformId)
+      ) {
+      return FALSE;
+    }
+  }
+  return TRUE;
+}
+
+/**
+  Copy Stroage from StorageListHead2 to StorageListHead1
+
+  @param  NewStorageListHead  The pointer to the entry of storage list
+  @param  OldStorageListHead  The pointer to the entry of storage list
+  @param  DefaultId           The default Id for multi-platform mode
+  @param  PlatformId          The platform Id for multi-platform mode
+  @param  AssignIdOrNot       If True, assign the platform Id and default Id to storage;
+                              Or else, only copy the variables under the specified platform
+                              Id and default to the other list.
+  @param  Mode                The operation of mode
+
+  @retval EFI_SUCCESS   It was complete successfully
+  @return EFI_ABORTED   An error occurred
+**/
+EFI_STATUS
+BuildVariableList (
+  IN  LIST_ENTRY     *NewStorageListHead,
+  IN  LIST_ENTRY     *OldStorageListHead,
+  IN  UINT16         DefaultId,
+  IN  UINT64         PlatformId,
+  IN  BOOLEAN        AssignIdOrNot,
+  IN  OPERATION_TYPE Mode
+)
+{
+  LIST_ENTRY        *StorageLink;
+  LIST_ENTRY        *NameValueLink;
+  FORMSET_STORAGE   *Storage;
+  FORMSET_STORAGE   *StorageCopy;
+  IN  LIST_ENTRY    *StorageListHead1;
+  IN  LIST_ENTRY    *StorageListHead2;
+  NAME_VALUE_NODE   *NameValueNode;
+  NAME_VALUE_NODE   *CopyNameValueNode;
+
+  Storage          = NULL;
+  NameValueNode    = NULL;
+  StorageListHead1 = NewStorageListHead;
+  StorageListHead2 = OldStorageListHead;
+
+  StorageLink = GetFirstNode (StorageListHead2);
+
+  while (!IsNull (StorageListHead2, StorageLink)) {
+    Storage = FORMSET_STORAGE_FROM_LINK (StorageLink);
+
+    if ((Storage->Type == EFI_IFR_VARSTORE_EFI_OP)
+      ||(Storage->Type == EFI_IFR_VARSTORE_OP)
+      ) {
+      //
+      // Only support EfiVarStore in Multi-Platform mode, and the attribute must be EFI_VARIABLE_NON_VOLATILE
+      //
+      if (mMultiPlatformParam.MultiPlatformOrNot) {
+        if (Storage->Type == EFI_IFR_VARSTORE_OP) {
+          StorageLink = GetNextNode (StorageListHead2, StorageLink);
+          continue;
+        }
+        if ((Storage->Type == EFI_IFR_VARSTORE_EFI_OP)
+          && Storage->NewEfiVarstore
+          && ((Storage->Attributes & EFI_VARIABLE_NON_VOLATILE) == 0)
+          ) {
+          StorageLink = GetNextNode (StorageListHead2, StorageLink);
+          continue;
+        }
+        if (AssignIdOrNot) {
+          Storage->DefaultId[0]  = DefaultId;
+          Storage->PlatformId[0] = PlatformId;
+        } else {
+          //
+          //only copy the variables under the specified platform Id and default to the other list.
+          //
+          if ((Mode == VERIFY) && (NotEqualAnyIdOfStorage (Storage, DefaultId, PlatformId))) {
+            StorageLink = GetNextNode (StorageListHead2, StorageLink);
+            continue;
+          } else if ((Mode != VERIFY) && (Storage->DefaultId[0] != DefaultId || Storage->PlatformId[0] != PlatformId) ) {
+            StorageLink = GetNextNode (StorageListHead2, StorageLink);
+            continue;
+          }
+        }
+      }
+      //
+      // Copy Storage Node
+      //
+      if (Storage->Name == NULL) {
+        return EFI_ABORTED;
+      }
+      StorageCopy     = NULL;
+      StorageCopy     = calloc (sizeof (FORMSET_STORAGE), sizeof (CHAR8));
+      if (StorageCopy == NULL) {
+        printf ("Memory allocation failed.\n");
+        return EFI_ABORTED;
+      }
+      memcpy (StorageCopy, Storage, sizeof (FORMSET_STORAGE));
+
+      if (Mode == VERIFY) {
+        StorageCopy->DefaultId[0]  = DefaultId;
+        StorageCopy->PlatformId[0] = PlatformId;
+      }
+      //
+      //Set the flags for sorting out the variables
+      //
+      StorageCopy->Skip = FALSE;
+
+      StorageCopy->Name = NULL;
+      StorageCopy->Name = calloc (FceStrLen (Storage->Name) + 1, sizeof (CHAR16));
+      if (StorageCopy->Name == NULL) {
+        printf ("Memory allocation failed.\n");
+        free (StorageCopy);
+        return EFI_ABORTED;
+      }
+      StrCpy (StorageCopy->Name, Storage->Name);
+
+      StorageCopy->Buffer = NULL;
+      StorageCopy->Buffer = calloc (Storage->Size, sizeof (CHAR8));
+      if (StorageCopy->Buffer == NULL) {
+        free (StorageCopy->Name);
+        free (StorageCopy);
+        printf ("Memory allocation failed.\n");
+        return EFI_ABORTED;
+      }
+      CopyMem (StorageCopy->Buffer, Storage->Buffer, Storage->Size);
+      //
+      // Copy NameValue list of storage node
+      //
+      InitializeListHead (&StorageCopy->NameValueListHead);
+
+      NameValueLink = GetFirstNode (&Storage->NameValueListHead);
+
+      while (!IsNull (&Storage->NameValueListHead, NameValueLink)) {
+
+        NameValueNode     = NAME_VALUE_NODE_FROM_LINK (NameValueLink);
+        CopyNameValueNode = NULL;
+        CopyNameValueNode = calloc (sizeof (NAME_VALUE_NODE), sizeof (CHAR8));
+        if (CopyNameValueNode == NULL) {
+          free (StorageCopy->Name);
+          free (StorageCopy->Buffer);
+          free (StorageCopy);
+          printf ("Memory allocation failed.\n");
+          return EFI_ABORTED;
+        }
+        memcpy (CopyNameValueNode, NameValueNode, sizeof (NAME_VALUE_NODE));
+
+        CopyNameValueNode->Name      = NULL;
+        CopyNameValueNode->Value     = NULL;
+        CopyNameValueNode->EditValue = NULL;
+
+        CopyNameValueNode->Name      = calloc (FceStrLen (NameValueNode->Name) + 1, sizeof (CHAR16));
+        CopyNameValueNode->Value     = calloc (FceStrLen (NameValueNode->Value) + 1, sizeof (CHAR16));
+        CopyNameValueNode->EditValue = calloc (FceStrLen (NameValueNode->EditValue) + 1, sizeof (CHAR16));
+        if ((CopyNameValueNode->Name == NULL)
+          || (CopyNameValueNode->Value == NULL)
+          || (CopyNameValueNode->EditValue == NULL)
+          ) {
+          free (StorageCopy->Name);
+          free (StorageCopy->Buffer);
+          free (StorageCopy);
+          if (CopyNameValueNode->Name != NULL) {
+            free (CopyNameValueNode->Name );
+          }
+          if (CopyNameValueNode->Value != NULL) {
+            free (CopyNameValueNode->Value);
+          }
+          if (CopyNameValueNode->EditValue != NULL) {
+            free (CopyNameValueNode->EditValue);
+          }
+          free (CopyNameValueNode);
+          printf ("Memory allocation failed.\n");
+          return EFI_ABORTED;
+        }
+        StrCpy (CopyNameValueNode->Name, NameValueNode->Name);
+        StrCpy (CopyNameValueNode->Value, NameValueNode->Value);
+        StrCpy (CopyNameValueNode->EditValue, NameValueNode->EditValue);
+        //
+        // Insert it to StorageCopy->NameValueListHead
+        //
+        InsertTailList(&StorageCopy->NameValueListHead,&CopyNameValueNode->Link);
+        NameValueLink = GetNextNode (&Storage->NameValueListHead, NameValueLink);
+      }
+
+      //
+      // Insert it to StorageListHead1
+      //
+      InsertTailList(StorageListHead1,&StorageCopy->Link);
+    }
+    StorageLink = GetNextNode (StorageListHead2, StorageLink);
+  }
+  return EFI_SUCCESS;
+}
+
+/**
+  Check whether the current defaultId and platfrom is equal to the first one of one
+  group of defaultId and platformId which have the same variable data.
+
+  @param DefaultId      The default Id
+  @param PlatformId     The platform Id
+
+  @retval TRUE          If not equal to the first defaultId and platformId, return TRUE
+  @return EFI_ABORTED   Others
+**/
+BOOLEAN
+NoTheKeyIdOfGroup (
+  IN  UINT16   DefaultId,
+  IN  UINT64   PlatformId
+  )
+{
+  UINT32   Index;
+
+  for (Index = 0; Index < mMultiPlatformParam.KeyIdNum; Index++) {
+    if (
+      (DefaultId == mMultiPlatformParam.KeyDefaultId[Index])
+      && (PlatformId == mMultiPlatformParam.KeyPlatformId[Index])
+      ) {
+      return FALSE;
+    }
+  }
+  return TRUE;
+}
+
+/**
+  Evaluate the value in all formset according to the defaultId and platformId.
+
+  If not the multi-platform mode, the defaultId is 0. In this case, the
+  platform Id will be the default value of that question.
+
+  @param UpdateMode     It will be TRUE in update Mode
+
+  @retval EFI_SUCCESS   It was complete successfully
+  @return EFI_ABORTED   An error occurred
+**/
+EFI_STATUS
+EvaluateTheValueInFormset (
+  IN  BOOLEAN  UpdateMode
+  )
+{
+  EFI_STATUS              Status;
+  UINT16                  DefaultId;
+  UINT64                  PlatformId;
+  UINT16                  CurDefaultId;
+  UINT64                  CurPlatformId;
+  UINT16                  DefaultIndex;
+  UINT16                  PlatformIndex;
+  UINT32                  Index;
+  UQI_PARAM_LIST          *CurUqiList;
+
+  Status        = EFI_SUCCESS;
+
+  if (mMultiPlatformParam.MultiPlatformOrNot) {
+    ScanUqiFullList (mUqiList);
+
+    //
+    // Multi-platform mode support
+    //
+    for (DefaultIndex = 0; DefaultIndex < mMultiPlatformParam.DefaultIdNum; DefaultIndex++) {
+      for (PlatformIndex = 0; PlatformIndex < mMultiPlatformParam.PlatformIdNum; PlatformIndex++) {
+        DefaultId  = mMultiPlatformParam.DefaultId[DefaultIndex];
+        PlatformId = mMultiPlatformParam.PlatformId[PlatformIndex];
+        //
+        //Only parse one time, if a group of defaultId and platformId which have the same variable
+        // Take the first one as a key Id of a group
+        //
+        if (UpdateMode && NoTheKeyIdOfGroup (DefaultId, PlatformId)) {
+          continue;
+        }
+        //
+        // Initialize the Storage of mVarListEntry
+        //
+        ClearStorageEntryList (&mVarListEntry, DefaultId, PlatformId);
+
+        Status = ExtractDefault (
+                   NULL,
+                   NULL,
+                   DefaultId,
+                   PlatformId,
+                   SystemLevel
+                 );
+        if (EFI_ERROR (Status)) {
+          return EFI_ABORTED;
+        }
+        //
+        // Clear the platformId as 0 after calculation.
+        //
+        Status = AssignThePlatformId (0);
+        if (EFI_ERROR (Status)) {
+          printf ("Failed to clear the platformid.\n");
+          return Status;
+        }
+        //
+        // Update the value from script file
+        //
+        if (UpdateMode) {
+          SetUqiParametersMultiMode (mUqiList,DefaultId, PlatformId);
+        }
+        //
+        // If not existed the same variables in mAllVarListEntry, insert the new ones.
+        // Or else, only add the defaultId and platformId to the former one.
+        //
+        if (ComparePartSameVariableList (&mAllVarListEntry, &mVarListEntry, &CurDefaultId, &CurPlatformId)) {
+          AppendIdToVariables (&mAllVarListEntry, CurDefaultId, CurPlatformId, DefaultId, PlatformId);
+        } else {
+          //
+          // Copy Stroage from mVarListEntry to mAllVarListEntry and assign the defaultId and platformId as well
+          //
+          Status = BuildVariableList (&mAllVarListEntry, &mVarListEntry, DefaultId, PlatformId, TRUE, UPDATE);
+          if (EFI_ERROR (Status)) {
+            return EFI_ABORTED;
+          }
+          //
+          // In update mode, add the other defaultId and platform of a group to the variale list
+          //
+          if (UpdateMode) {
+            CurUqiList = mUqiList;
+
+            while (CurUqiList != NULL) {
+              if ((DefaultId == CurUqiList->Header.DefaultId[0])
+                && (PlatformId == CurUqiList->Header.PlatformId[0])
+                ) {
+                break;
+              }
+              CurUqiList = CurUqiList->Next;
+            }
+
+            if (CurUqiList == NULL) {
+              return EFI_ABORTED;
+            }
+
+            for (Index = 1; Index < CurUqiList->Header.IdNum; Index++) {
+              CurDefaultId  =  CurUqiList->Header.DefaultId[Index];
+              CurPlatformId =  CurUqiList->Header.PlatformId[Index];
+              AppendIdToVariables (&mAllVarListEntry, DefaultId, PlatformId, CurDefaultId, CurPlatformId);
+            }
+          }
+        }
+      }
+    }
+  } else {
+      //
+      // General mode
+      //
+      Status = ExtractDefault (
+                 NULL,
+                 NULL,
+                 0,
+                 0,
+                 SystemLevel
+               );
+      if (EFI_ERROR (Status)) {
+        return EFI_ABORTED;
+      }
+      //
+      // If existed the variable in NvStorage, copy them to mVarListEntry.
+      // Synchronize the default value from the EFI variable zone to variable list
+      //
+      Status = EfiVarAndListExchange (TRUE, &mVarListEntry);
+      if (Status == EFI_INVALID_PARAMETER) {
+        Status = EFI_ABORTED;
+        return Status;
+      }
+      //
+      // Update the value from script file
+      //
+      if (UpdateMode) {
+        Status = SetUqiParameters (mUqiList,0, 0);
+        if (EFI_ERROR (Status)) {
+          return EFI_ABORTED;
+        }
+      }
+      //
+      // Copy Stroage from mVarListEntry to mAllVarListEntry
+      //
+      Status = BuildVariableList (&mAllVarListEntry, &mVarListEntry, 0, 0, TRUE, UPDATE);
+      if (EFI_ERROR (Status)) {
+        return EFI_ABORTED;
+      }
+    }
+  return EFI_SUCCESS;
+}
+
+/**
+  Check and compare the value between the script file and variable from BFV.
+
+  It's used in the update operation of multi-plaform mode.
+
+  @retval EFI_SUCCESS   It was complete successfully
+  @return EFI_ABORTED   An error occurred
+**/
+static
+EFI_STATUS
+CheckValueUpdateList (
+  VOID
+  )
+{
+  UINT16              DefaultId;
+  UINT64              PlatformId;
+  UINT16              DefaultIndex;
+  UINT16              PlatformIndex;
+  EFI_STATUS          Status;
+  FORMSET_STORAGE     *Storage;
+  LIST_ENTRY          *StorageLink;
+  UINT16              PreDefaultId;
+  UINT64              PrePlatformId;
+
+  Storage             = NULL;
+  PreDefaultId        = 0xFFFF;
+  PrePlatformId       = 0xFFFFFFFFFFFFFFFF;
+
+  ScanUqiFullList (mUqiList);
+  if (gEfiFdInfo.ExistNvStoreDatabase) {
+    StorageLink = GetFirstNode (&mBfvVarListEntry);
+    while (!IsNull (&mBfvVarListEntry, StorageLink)) {
+      Storage = FORMSET_STORAGE_FROM_LINK (StorageLink);
+      if (PreDefaultId == Storage->DefaultId[0] && PrePlatformId == Storage->PlatformId[0]) {
+        StorageLink = GetNextNode (&mBfvVarListEntry, StorageLink);
+        continue;
+      } else {
+        PreDefaultId = Storage->DefaultId[0];
+        PrePlatformId = Storage->PlatformId[0];
+      }
+      DefaultId = PreDefaultId;
+      PlatformId = PrePlatformId;
+        //
+        //Only parse one time, if a group of defaultId and platformId which have the same variable
+        // Take the first one as a key Id of a group
+        //
+        if (NoTheKeyIdOfGroup (DefaultId, PlatformId)) {
+          continue;
+        }
+        //
+        // Copy Stroage from mBfvVarListEntry to mVarListEntry. The mVarListEntry was attached to
+        // the FormSet->StorageListHead.
+        //
+        DestroyAllStorage (&mVarListEntry);
+        Status = BuildVariableList (&mVarListEntry, &mBfvVarListEntry, DefaultId, PlatformId, FALSE, UPDATE);
+        if (EFI_ERROR (Status)) {
+          return EFI_ABORTED;
+        }
+        SetUqiParametersMultiMode (mUqiList,DefaultId, PlatformId);
+        //
+        // Copy Stroage from mVarListEntry to mAllVarListEntry and assign the defaultId and platformId as well
+        //
+        Status = BuildVariableList (&mAllVarListEntry, &mVarListEntry, DefaultId, PlatformId, TRUE, UPDATE);
+        if (EFI_ERROR (Status)) {
+          return EFI_ABORTED;
+        }
+        StorageLink = GetNextNode (&mBfvVarListEntry, StorageLink);
+     }
+  } else {
+    for (DefaultIndex = 0; DefaultIndex < mMultiPlatformParam.DefaultIdNum; DefaultIndex++) {
+      for (PlatformIndex = 0; PlatformIndex < mMultiPlatformParam.PlatformIdNum; PlatformIndex++) {
+        DefaultId  = mMultiPlatformParam.DefaultId[DefaultIndex];
+        PlatformId = mMultiPlatformParam.PlatformId[PlatformIndex];
+        //
+        //Only parse one time, if a group of defaultId and platformId which have the same variable
+        // Take the first one as a key Id of a group
+        //
+        if (NoTheKeyIdOfGroup (DefaultId, PlatformId)) {
+          continue;
+        }
+        //
+        // Copy Stroage from mBfvVarListEntry to mVarListEntry. The mVarListEntry was attached to
+        // the FormSet->StorageListHead.
+        //
+        DestroyAllStorage (&mVarListEntry);
+        Status = BuildVariableList (&mVarListEntry, &mBfvVarListEntry, DefaultId, PlatformId, FALSE, UPDATE);
+        if (EFI_ERROR (Status)) {
+          return EFI_ABORTED;
+        }
+        SetUqiParametersMultiMode (mUqiList,DefaultId, PlatformId);
+        //
+        // Copy Stroage from mVarListEntry to mAllVarListEntry and assign the defaultId and platformId as well
+        //
+        Status = BuildVariableList (&mAllVarListEntry, &mVarListEntry, DefaultId, PlatformId, TRUE, UPDATE);
+        if (EFI_ERROR (Status)) {
+          return EFI_ABORTED;
+        }
+      }
+    }
+  }
+   return EFI_SUCCESS;
+}
+/**
+  Read defaultId and platformId from the whole FD, and store these two values to mMultiPlatformParam.
+
+  If not multi-platform mode, only return EFI_ABORTED.
+
+  @param Fv             the Pointer to the FFS
+  @param Length         the length of FFS
+
+  @retval EFI_SUCCESS   It was complete successfully
+  @return EFI_ABORTED   An error occurred
+**/
+static
+EFI_STATUS
+ReadAllIfrToFromset (
+  IN VOID      *Fv,
+  IN UINTN     Length
+  )
+{
+  UINT8               NumberofMachingVfrBin;
+  UINTN               *VfrBinBaseAddress;
+  UINTN               *UniBinBaseAddress;
+  EFI_STATUS          Status;
+  UINT8               Index;
+  EFI_SECTION_STRUCT  *EfiBufferHeader;
+  VOID                *EfiAddr;
+
+  NumberofMachingVfrBin = 0;
+  VfrBinBaseAddress     = NULL;
+  UniBinBaseAddress     = NULL;
+  Status                = EFI_SUCCESS;
+  EfiBufferHeader       = NULL;
+  EfiAddr               = NULL;
+
+  //
+  // Locate the efi base address
+  //
+  EfiBufferHeader = malloc (sizeof (EFI_SECTION_STRUCT));
+  if (EfiBufferHeader == NULL) {
+    return EFI_ABORTED;
+  }
+  memset (
+    EfiBufferHeader,
+    0,
+    sizeof (EFI_SECTION_STRUCT)
+    );
+
+  Status = ParseSection (
+             TRUE,
+             (UINT8 *)Fv,
+             Length,
+             &EfiBufferHeader
+             );
+  if (Status != EFI_SUCCESS) {
+    Status = EFI_ABORTED;
+    goto Done;
+  }
+
+  EfiAddr = (VOID *)EfiBufferHeader->BufferBase;
+  //
+  //Search the Offset at the end of FFS, whatever it is compressed or not
+  //
+  Status = SearchVfrBinInFFS (Fv, EfiAddr, Length, &VfrBinBaseAddress, &NumberofMachingVfrBin);
+  if (Status != EFI_SUCCESS) {
+    Status = EFI_ABORTED;
+    goto Done;
+  }
+  Status = SearchUniBinInFFS (
+             Fv,
+             EfiAddr,
+             Length,
+             &UniBinBaseAddress
+             );
+  if (Status != EFI_SUCCESS) {
+    Status = EFI_ABORTED;
+    goto Done;
+  }
+  //
+  // Read all Ifr information into Formset and Form structure
+  //
+  for (Index = 0; Index < NumberofMachingVfrBin; Index++) {
+    if ((EfiBufferHeader->BufferBase + EfiBufferHeader->Length) < *(VfrBinBaseAddress + Index)
+      || (EfiBufferHeader->BufferBase + EfiBufferHeader->Length) < *UniBinBaseAddress
+    ) {
+      printf ("Failed to locate Ifr data from efi by the offset.\n");
+      Status = EFI_ABORTED;
+      goto Done;
+    }
+    Status = ParseFormSetInVfrBin (
+               (UINTN **)VfrBinBaseAddress,
+               (UINTN *)*UniBinBaseAddress,
+               Index
+             );
+    if (EFI_ERROR (Status)) {
+      Status = EFI_ABORTED;
+      goto Done;
+    }
+  }
+
+Done:
+  //
+  // Free the memory which stores the offset
+  //
+  if (VfrBinBaseAddress != NULL) {
+    free (VfrBinBaseAddress);
+  }
+  if (UniBinBaseAddress != NULL) {
+    free (UniBinBaseAddress);
+  }
+  //
+  // Free the memory for uncompressed space in section
+  //
+  for (Index = 0; Index < EfiBufferHeader->UnCompressIndex; Index++) {
+    if ((VOID *)EfiBufferHeader->UncompressedBuffer[Index] != NULL) {
+      free ((VOID *)EfiBufferHeader->UncompressedBuffer[Index]);
+    }
+  }
+  return Status;
+}
+
+/**
+  Get next questions of four kinds in FormSet list.
+
+  If not one kinds of ONE_OF CHECK_BOX ORDER_LIST and NUMERIC, continue to parse next question.
+  If parse to the end of questions, return NULL.
+
+  @param FormSetEntryListHead  the pointer to the LIST_ENTRY
+  @param OrderOfQuestion       the order of question
+
+  @retval If succeed, return the pointer to the question
+  @return NULL
+**/
+FORM_BROWSER_STATEMENT *
+GetNextQuestion (
+  IN     LIST_ENTRY     *FormSetEntryListHead,
+  IN OUT UINT32         *OrderOfQuestion
+  )
+{
+  FORM_BROWSER_FORMSET    *FormSet;
+  LIST_ENTRY              *FormSetLink;
+  FORM_BROWSER_FORM       *Form;
+  LIST_ENTRY              *FormLink;
+  FORM_BROWSER_STATEMENT  *Question;
+  LIST_ENTRY              *QuestionLink;
+  UINT32                  Index;
+
+  FormSet      = NULL;
+  FormSetLink  = NULL;
+  Form         = NULL;
+  FormLink     = NULL;
+  Question     = NULL;
+  QuestionLink = NULL;
+  Index        = 0;
+
+  FormSetLink = GetFirstNode (FormSetEntryListHead);
+  while (!IsNull (FormSetEntryListHead, FormSetLink)) {
+    FormSet = FORM_BROWSER_FORMSET_FROM_LINK (FormSetLink);
+    //
+    // Parse all forms in formset
+    //
+    FormLink = GetFirstNode (&FormSet->FormListHead);
+
+    while (!IsNull (&FormSet->FormListHead, FormLink)) {
+      Form = FORM_BROWSER_FORM_FROM_LINK (FormLink);
+      //
+      // Parse five kinds of Questions in Form
+      //
+      QuestionLink = GetFirstNode (&Form->StatementListHead);
+
+      while (!IsNull (&Form->StatementListHead, QuestionLink)) {
+        Question = FORM_BROWSER_STATEMENT_FROM_LINK (QuestionLink);
+        //
+        // Parse five kinds of Questions in Form
+        //
+        if ((Question->Operand == EFI_IFR_ONE_OF_OP)
+          || (Question->Operand == EFI_IFR_NUMERIC_OP)
+          || (Question->Operand == EFI_IFR_CHECKBOX_OP)
+          || (Question->Operand == EFI_IFR_ORDERED_LIST_OP)
+          || (Question->Operand == EFI_IFR_STRING_OP)
+          ) {
+          if (*OrderOfQuestion == Index++) {
+            (*OrderOfQuestion)++;
+            return Question;
+          }
+        }
+        QuestionLink = GetNextNode (&Form->StatementListHead, QuestionLink);
+      }
+
+      FormLink = GetNextNode (&FormSet->FormListHead, FormLink);
+    }
+    FormSetLink = GetNextNode (FormSetEntryListHead, FormSetLink);
+  }
+  return NULL;
+}
+
+/**
+  Read defaultId and platformId from the whole FD, and store these two values to mMultiPlatformParam.
+
+  If not multi-platform mode, only return EFI_ABORTED.
+
+  @param Fv             the Pointer to the FFS
+  @param Length         the length of FFS
+
+  @retval EFI_SUCCESS   It was complete successfully
+  @return EFI_ABORTED   An error occurred
+**/
+static
+EFI_STATUS
+ReadDefaultAndPlatformId (
+  IN  LIST_ENTRY     *FormSetEntryListHead
+  )
+{
+  EFI_STATUS              Status;
+  FORM_BROWSER_FORMSET    *FormSet;
+  LIST_ENTRY              *FormLink;
+  FORMSET_DEFAULTSTORE    *DefaultStore;
+  LIST_ENTRY              *DefaultStoreLink;
+  FORM_BROWSER_STATEMENT  *CurQuestion;
+  UINT32                  MatchedNum;
+  UINT32                  QuestionOrder;
+
+  Status                = EFI_SUCCESS;
+  CurQuestion           = NULL;
+  MatchedNum            = 0;
+  QuestionOrder         = 0;
+  //
+  //Check whether it is the Multi-Platform solution or not
+  //
+  if (!mMultiPlatformParam.MultiPlatformOrNot) {
+    Status = EFI_SUCCESS;
+    goto Done;
+  }
+  //
+  // Read defaultId from FormSet List
+  //
+  FormLink = GetFirstNode (FormSetEntryListHead);
+  while (!IsNull (FormSetEntryListHead, FormLink)) {
+    FormSet = FORM_BROWSER_FORMSET_FROM_LINK (FormLink);
+    //
+    // Parse Default Store in formset
+    //
+    DefaultStoreLink = GetFirstNode (&FormSet->DefaultStoreListHead);
+
+    while (!IsNull (&FormSet->DefaultStoreListHead, DefaultStoreLink)) {
+      DefaultStore = FORMSET_DEFAULTSTORE_FROM_LINK (DefaultStoreLink);
+      StoreAllDefaultId (DefaultStore->DefaultId);
+      DefaultStoreLink = GetNextNode (&FormSet->DefaultStoreListHead, DefaultStoreLink);
+    }
+    FormLink = GetNextNode (FormSetEntryListHead, FormLink);
+  }
+
+  //
+  //Read the platformId from FormSetList
+  //
+  while ((CurQuestion = GetNextQuestion (FormSetEntryListHead, &QuestionOrder)) != NULL) {
+    Status = ReadPlaformId (CurQuestion);
+    if (!EFI_ERROR (Status)) {
+      MatchedNum++;
+    }
+  }
+
+  if (MatchedNum == 0) {
+    printf ("There are no questions included in the platformid in the FD.");
+    Status = EFI_ABORTED;
+  } else if (MatchedNum > 1) {
+    printf ("There are %d questions included in the platformid in the FD.", MatchedNum);
+    Status = EFI_ABORTED;
+  } else {
+    Status = EFI_SUCCESS;
+  }
+
+Done:
+
+   return Status;
+}
+
+/**
+  Read the first two bytes to check whether it is Ascii or UCS2.
+
+  @param  ScriptFile   Pointer to the script file.
+
+  @reture TRUE         If ascii, return TRUE
+  @reture FALSE        Others, return FALSE.
+
+**/
+FILE_TYPE
+IsAsciiOrUcs2 (
+  IN   FILE    *ScriptFile
+  )
+{
+  CHAR16    FirstTwoBytes;
+
+  fread(&FirstTwoBytes, 1, 2, ScriptFile);
+
+  if (FirstTwoBytes == BigUnicodeFileTag) {
+    return BIG_UCS2;
+  } else if (FirstTwoBytes == LittleUnicodeFileTag) {
+    return LITTLE_UCS2;
+  } else {
+    return ASCII;
+  }
+}
+
+/**
+  Read Unicode characters and transfer it to ASCII.
+
+  @param  ScriptFile   The pointer to the script file.
+  @param  Type         The type of BigUCS2 or LittleUCS2
+
+  @return              The ASCII characters
+
+**/
+CHAR8 *
+ReadUcs2ToStr (
+  IN OUT  FILE       *ScriptFile,
+  IN      FILE_TYPE  Type
+)
+{
+  CHAR16    TempChar16;
+  CHAR16    TempChar8;
+  CHAR8     *StrChar8;
+  UINTN     Index;
+  BOOLEAN   FirstParse;
+
+  TempChar16 = L'\0';
+  TempChar8  = '\0';
+  StrChar8   = NULL;
+  Index      = 0;
+  FirstParse = TRUE;
+
+  if (ScriptFile == NULL) {
+    return NULL;
+  }
+  StrChar8 = calloc (MAX_STR_LEN_FOR_PICK_UQI, sizeof (CHAR8));
+  assert (StrChar8);
+
+  for (Index = 0; Index < MAX_STR_LEN_FOR_PICK_UQI; Index++) {
+    //
+    // The first parse should skip the 0x0020 (BigUCS2) or 0x2000 (LittleUCS2)
+    //
+    if (FirstParse) {
+      do {
+        fread(&TempChar16, sizeof (CHAR16), 1, ScriptFile);
+      } while ((TempChar16 == 0x0020) || (TempChar16 == 0x2000));
+      FirstParse = FALSE;
+    } else {
+      fread(&TempChar16, sizeof (CHAR16), 1, ScriptFile);
+    }
+    //
+    // Read until break the "Space"
+    //
+    if ((TempChar16 == 0x0020) || (TempChar16 == 0x2000)) {
+      break;
+    }
+    if (Type == BIG_UCS2) {
+      TempChar8 = (CHAR8)TempChar16;
+    } else {
+      TempChar8 = (CHAR8)(TempChar16 >> 8);
+    }
+    memcpy (StrChar8 + Index, &TempChar8, 0x1);
+  }
+  if (Index == MAX_STR_LEN_FOR_PICK_UQI) {
+    free (StrChar8);
+    return  NULL;
+  }
+  *(StrChar8 + Index) = '\0';
+
+  return StrChar8;
+}
+
+/**
+  Read Unicode characters and transfer it to ASCII.
+
+  @param  AsciiStr     The pointer to the Ascii string. It may inlcudes blank space.
+  @param  IdArray      The pointer to the array of Id.
+
+  @return              The number of default or platform Id
+
+**/
+static
+UINT16
+GetNumFromAsciiString (
+  IN       CHAR8      *AsciiStr,
+  IN OUT   UINT64     *IdArray
+)
+{
+  UINT16   Index1;
+  UINT16   Index2;
+  UINT16   NumofId;
+  CHAR8    CharArray[16];
+  BOOLEAN  ExistedValue;
+
+  Index1       = 0;
+  Index2       = 0;
+  NumofId      = 0;
+  ExistedValue = FALSE;
+
+  while (*(AsciiStr + Index1) != '\n') {
+
+    Index2       = 0;
+    ExistedValue = FALSE;
+    memset (CharArray, 0, 16);
+    for (; *(AsciiStr + Index1) == ' '; Index1++);
+    for (; (*(AsciiStr + Index1) != ' ') && (*(AsciiStr + Index1) != '\n'); Index1++) {
+      assert (Index2 <= 15);
+      *(CharArray + Index2++) = *(AsciiStr + Index1);
+      ExistedValue = TRUE;
+    }
+    if (ExistedValue && (*(AsciiStr + Index1 - 1) != '\n')) {
+      sscanf(CharArray, "%lld", (long long *)&IdArray[NumofId++]);
+    }
+  }
+  return NumofId;
+}
+
+/**
+  Parse the script file to build the linked list of question structures.
+
+  Pick up the UQI information and save it to the UqiList. The current scripts
+  could be Ascii or UCS2 (Little or Big Mode).
+
+  @param  ScriptFile   The pointer to the script file.
+
+  @return EFI_SUCCESS
+  @return EFI_INVALID_PARAMETER  ScriptFile is NULL
+
+**/
+static
+EFI_STATUS
+PickUpUqiFromScript (
+  IN     FILE            *ScriptFile
+  )
+{
+  CHAR8           TempChar;
+  BOOLEAN         InQuote;
+  CHAR16          TempChar16;
+  UINT32          UqiSize;
+  CHAR16          *UqiBuffer;
+  CHAR8           Type[32];
+  UINT16          Index;
+  UQI_PARAM_LIST  *UqiNode;
+  UINTN           MaxContainers;
+  UINT32          ScriptsLine;
+  FILE_TYPE       AsciiOrUcs2;
+  CHAR8           *Char8Str;
+  CHAR8           DefaultIdStr[30];
+  CHAR8           PlatformIdStr[30];
+  CHAR8           PlatformUqi[30];
+  UINT16          Index1;
+  UINT16          Index2;
+  UINT16          Index3;
+  UINT16          Index4;
+  UINT16          Index5;
+  BOOLEAN         ReadDefaultId;
+  BOOLEAN         ReadPlatformId;
+  BOOLEAN         ReadPlatformIdUqi;
+  UINT64          DefaultId[MAX_PLATFORM_DEFAULT_ID_NUM];
+  UINT64          PlatformId[MAX_PLATFORM_DEFAULT_ID_NUM];
+  UINT16          DefaultIdNum;
+  UINT16          PlatformIdNum;
+  UINT8           Array[MAX_PLATFORM_DEFAULT_ID_NUM * MAX_PLATFORM_DEFAULT_ID_NUM];
+  UINT16          IdStart;
+  UINT16          IdEnd;
+
+  Char8Str          = NULL;
+  ScriptsLine       = 0;
+  AsciiOrUcs2       = ASCII;
+  Index1            = 0;
+  Index2            = 0;
+  Index3            = 0;
+  Index4            = 0;
+  Index5            = 0;
+  ReadDefaultId     = FALSE;
+  ReadPlatformId    = FALSE;
+  ReadPlatformIdUqi = FALSE;
+  DefaultIdNum      = 1;
+  PlatformIdNum     = 1;
+  InQuote           = FALSE;
+
+  memset (DefaultId,  0, MAX_PLATFORM_DEFAULT_ID_NUM * sizeof (UINT64));
+  memset (PlatformId, 0, MAX_PLATFORM_DEFAULT_ID_NUM * sizeof (UINT64));
+  memcpy (DefaultIdStr, "/ FCEKEY DEFAULT_ID:",  strlen ("/ FCEKEY DEFAULT_ID:") + 1);
+  memcpy (PlatformIdStr,"/FCEKEY PLATFORM_ID:",  strlen ("/FCEKEY PLATFORM_ID:") + 1);
+  memcpy (PlatformUqi,  "/FCEKEY PLATFORM_UQI:", strlen ("/FCEKEY PLATFORM_UQI:") + 1);
+
+  if (ScriptFile == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+  //
+  // Check the file type
+  //
+  AsciiOrUcs2 = IsAsciiOrUcs2 (ScriptFile);
+  if (AsciiOrUcs2 == ASCII) {
+    fseek (ScriptFile, 0, SEEK_SET);
+  }
+
+  while(!feof(ScriptFile)) {
+    //
+    //  Reset local data
+    //
+    TempChar      = '\0';
+    TempChar16    = L'\0';
+    UqiSize       = 0;
+    UqiBuffer     = NULL;
+    MaxContainers = 0;
+    UqiNode       = NULL;
+    memset(Type, 0, 32);
+    //
+    //  Read first character of the line to find the line type
+    //
+    if (AsciiOrUcs2 == ASCII) {
+      fread(&TempChar, sizeof (CHAR8), 1, ScriptFile);
+    } else {
+      fread(&TempChar16, sizeof (CHAR16), 1, ScriptFile);
+      if (AsciiOrUcs2 == BIG_UCS2) {
+        TempChar = (CHAR8)TempChar16;
+      } else {
+        TempChar = (CHAR8)(TempChar16 >> 8);
+      }
+    }
+    //
+    // Take "\n\r" one line
+    //
+     if (TempChar != 0x0d) {
+       ScriptsLine++;
+     }
+    switch (TempChar) {
+
+    case 'Q':
+      //
+      //  Process question line
+      //
+      //  Read size of UQI string
+      //
+      if (AsciiOrUcs2 == ASCII) {
+        fscanf(ScriptFile, " %x", (INT32 *)&UqiSize);
+      } else {
+        Char8Str = ReadUcs2ToStr (ScriptFile, AsciiOrUcs2);
+        if (Char8Str == NULL) {
+          return EFI_ABORTED;
+        }
+        sscanf(Char8Str, " %x", (INT32 *)&UqiSize);
+        if (Char8Str != NULL) {
+          free (Char8Str);
+          Char8Str = NULL;
+        }
+      }
+      if (UqiSize > MAX_INPUT_ALLOCATE_SIZE) {
+        return EFI_ABORTED;
+      }
+      if (UqiSize == 0) {
+        do {
+          if (AsciiOrUcs2 == ASCII) {
+            fread(&TempChar, sizeof (CHAR8), 1, ScriptFile);
+          } else {
+            fread(&TempChar16, sizeof (CHAR16), 1, ScriptFile);
+            if (AsciiOrUcs2 == BIG_UCS2) {
+              TempChar = (CHAR8)TempChar16;
+            } else {
+              TempChar = (CHAR8)(TempChar16 >> 8);
+            }
+          }
+        } while((TempChar != '\n') && !feof(ScriptFile));
+        break;
+      }
+      //
+      //  Malloc buffer for string size + null termination
+      //
+      UqiBuffer = (CHAR16 *)calloc(UqiSize + 1, sizeof(CHAR16));
+
+      if (UqiBuffer == NULL) {
+        printf("Error. Unable to allocate 0x%04lx bytes for UQI string -- FAILURE\n", (unsigned long)((UqiSize + 1) * sizeof(CHAR16)));
+        break;
+      }
+      //
+      //  Read UQI string
+      //
+      for (Index = 0; Index < UqiSize; Index++) {
+        if (AsciiOrUcs2 == ASCII) {
+          fscanf(ScriptFile, " %hx", (short *)&(UqiBuffer[Index]));
+        } else {
+          Char8Str = ReadUcs2ToStr (ScriptFile, AsciiOrUcs2);
+          if (Char8Str == NULL) {
+            free (UqiBuffer );
+            return EFI_ABORTED;
+          }
+          sscanf(Char8Str, " %hx", (short *)&(UqiBuffer[Index]));
+          if (Char8Str != NULL) {
+            free (Char8Str);
+            Char8Str = NULL;
+          }
+        }
+      }
+      //
+      //  Set null termination
+      //
+      UqiBuffer[Index] = 0;
+      //
+      //  Read question type
+      //
+      if (AsciiOrUcs2 == ASCII) {
+        fscanf(ScriptFile, "%31s", Type);
+      } else {
+        Char8Str = ReadUcs2ToStr (ScriptFile, AsciiOrUcs2);
+        if (Char8Str == NULL) {
+          free (UqiBuffer);
+          return EFI_ABORTED;
+        }
+        sscanf(Char8Str, " %31s", Type);
+        if (Char8Str != NULL) {
+          free (Char8Str);
+          Char8Str = NULL;
+        }
+      }
+      if (stricmp(Type, "ONE_OF") == 0) {
+        UqiNode = CreateInsertUqiNode ();
+        if (UqiNode == NULL) {
+          free (UqiBuffer);
+          return EFI_ABORTED;
+        }
+        UqiNode->Header.Type       = ONE_OF;
+        UqiNode->Header.HexNum     = UqiSize;
+        UqiNode->Header.Data       = UqiBuffer;
+        UqiNode->Header.Value      = (UINT8 *)calloc(1, sizeof(UINT64));
+        UqiNode->Header.DiffValue  = (UINT8 *)calloc(1, sizeof(UINT64));
+        UqiNode->Header.IdNum      = PlatformIdNum;
+        UqiNode->Header.DefaultId  = (UINT16 *)calloc (PlatformIdNum, sizeof (UINT16));
+        if (UqiNode->Header.DefaultId == NULL) {
+          printf("Fail to allocate memory");
+          return EFI_OUT_OF_RESOURCES;
+        }
+        UqiNode->Header.PlatformId = (UINT64 *)calloc (PlatformIdNum, sizeof (UINT64));
+        if (UqiNode->Header.PlatformId == NULL) {
+          printf("Fail to allocate memory");
+          return EFI_OUT_OF_RESOURCES;
+        }
+        for (Index5 = 0; Index5 < PlatformIdNum; Index5++) {
+          UqiNode->Header.DefaultId[Index5] = (UINT16)DefaultId[Index5];
+        }
+        memcpy (UqiNode->Header.PlatformId, PlatformId, PlatformIdNum * sizeof (UINT64));
+
+        if (AsciiOrUcs2 == ASCII) {
+          fscanf(ScriptFile, " %llx", (long long *)UqiNode->Header.Value);
+        } else {
+          Char8Str = ReadUcs2ToStr (ScriptFile, AsciiOrUcs2);
+          if (Char8Str == NULL) {
+            return EFI_ABORTED;
+          }
+          sscanf(Char8Str, " %llx", (long long *)UqiNode->Header.Value);
+          if (Char8Str != NULL) {
+            free (Char8Str);
+            Char8Str = NULL;
+          }
+        }
+
+      } else if (stricmp(Type, "CHECKBOX") == 0) {
+        UqiNode = CreateInsertUqiNode ();
+        if (UqiNode == NULL) {
+          free (UqiBuffer);
+          return EFI_ABORTED;
+        }
+        UqiNode->Header.Type       = CHECKBOX;
+        UqiNode->Header.HexNum     = UqiSize;
+        UqiNode->Header.Data       = UqiBuffer;
+        UqiNode->Header.Value      = (UINT8 *)calloc(1, sizeof(UINT64));
+        UqiNode->Header.DiffValue  = (UINT8 *)calloc(1, sizeof(UINT64));
+        UqiNode->Header.IdNum      = PlatformIdNum;
+        UqiNode->Header.DefaultId  = (UINT16 *)calloc (PlatformIdNum, sizeof (UINT16));
+        if (UqiNode->Header.DefaultId == NULL) {
+          printf ("Fali to allocate memory!\n");
+          return EFI_OUT_OF_RESOURCES;
+        }
+        UqiNode->Header.PlatformId = (UINT64 *)calloc (PlatformIdNum, sizeof (UINT64));
+        if (UqiNode->Header.PlatformId == NULL) {
+          printf ("Fali to allocate memory!\n");
+          return EFI_OUT_OF_RESOURCES;
+        }
+        for (Index5 = 0; Index5 < PlatformIdNum; Index5++) {
+          UqiNode->Header.DefaultId[Index5] = (UINT16)DefaultId[Index5];
+        }
+        memcpy (UqiNode->Header.PlatformId, PlatformId, PlatformIdNum * sizeof (UINT64));
+
+        if (AsciiOrUcs2 == ASCII) {
+          fscanf(ScriptFile, " %llx", (long long *)UqiNode->Header.Value);
+        } else {
+          Char8Str = ReadUcs2ToStr (ScriptFile, AsciiOrUcs2);
+          if (Char8Str == NULL) {
+            return EFI_ABORTED;
+          }
+          sscanf(Char8Str, " %llx", (long long *)UqiNode->Header.Value);
+          if (Char8Str != NULL) {
+            free (Char8Str);
+            Char8Str = NULL;
+          }
+        }
+
+      } else if (stricmp(Type, "STRING") == 0) {
+        UqiNode = CreateInsertUqiNode ();
+        if (UqiNode == NULL) {
+          free (UqiBuffer);
+          return EFI_ABORTED;
+        }
+
+        UqiNode->Header.Type       = STRING;
+        UqiNode->Header.HexNum     = UqiSize;
+        UqiNode->Header.Data       = UqiBuffer;
+        UqiNode->Header.Value      = (UINT8 *)calloc(MAX_INPUT_ALLOCATE_SIZE, sizeof(CHAR16));
+        UqiNode->Header.DiffValue  = (UINT8 *)calloc(MAX_INPUT_ALLOCATE_SIZE, sizeof(CHAR16));
+        if (UqiNode->Header.Value == NULL) {
+          printf ("Fali to allocate memory!\n");
+          return EFI_OUT_OF_RESOURCES;
+        }
+        if (UqiNode->Header.DiffValue == NULL) {
+          printf ("Fali to allocate memory!\n");
+          return EFI_OUT_OF_RESOURCES;
+        }
+        UqiNode->Header.IdNum      = PlatformIdNum;
+        UqiNode->Header.DefaultId  = (UINT16 *)calloc (PlatformIdNum, sizeof (UINT16));
+        if (UqiNode->Header.DefaultId == NULL) {
+          printf ("Fali to allocate memory!\n");
+          return EFI_OUT_OF_RESOURCES;
+        }
+        UqiNode->Header.PlatformId = (UINT64 *)calloc (PlatformIdNum, sizeof (UINT64));
+        if (UqiNode->Header.PlatformId == NULL) {
+          printf ("Fali to allocate memory!\n");
+          return EFI_OUT_OF_RESOURCES;
+        }
+        for (Index5 = 0; Index5 < PlatformIdNum; Index5++) {
+          UqiNode->Header.DefaultId[Index5] = (UINT16)DefaultId[Index5];
+        }
+        memcpy (UqiNode->Header.PlatformId, PlatformId, PlatformIdNum * sizeof (UINT64));
+       InQuote = FALSE;
+       IdStart = 0;
+       IdEnd = 0;
+        for (Index = 0; Index < MAX_INPUT_ALLOCATE_SIZE; Index ++) {
+          if (AsciiOrUcs2 == ASCII) {
+            fread(&TempChar, sizeof (CHAR8), 1, ScriptFile);
+          } else {
+            fread(&TempChar16, sizeof (CHAR16), 1, ScriptFile);
+            if (AsciiOrUcs2 == BIG_UCS2) {
+              TempChar = (CHAR8)TempChar16;
+            } else {
+              TempChar = (CHAR8)(TempChar16 >> 8);
+            }
+          }
+         if (TempChar == '\"') {
+             if (InQuote == TRUE) {
+                 InQuote = FALSE;
+                 IdEnd = Index;
+             } else {
+                 InQuote = TRUE;
+                 IdStart = Index;
+             }
+         }
+          if (Index > IdStart) {
+             if (InQuote == FALSE) {
+                 break;
+             }
+             *(UqiNode->Header.Value + Index - IdStart -1) = TempChar;
+             Index ++;
+          }
+
+        }
+       if (IdEnd < IdStart) {
+           printf("The STRING is not end with \" character!\n");
+           return EFI_ABORTED;
+       }
+       if (IdStart == 0) {
+           printf("The STRING is not start with \" character!\n");
+           return EFI_ABORTED;
+       }
+
+      } else if (stricmp(Type, "NUMERIC") == 0) {
+        UqiNode = CreateInsertUqiNode ();
+        if (UqiNode == NULL) {
+          free (UqiBuffer);
+          return EFI_ABORTED;
+        }
+        UqiNode->Header.Type       = NUMERIC;
+        UqiNode->Header.HexNum     = UqiSize;
+        UqiNode->Header.Data       = UqiBuffer;
+        UqiNode->Header.Value      = (UINT8 *)calloc(1, sizeof(UINT64));
+        UqiNode->Header.DiffValue  = (UINT8 *)calloc(1, sizeof(UINT64));
+        UqiNode->Header.IdNum      = PlatformIdNum;
+        UqiNode->Header.DefaultId  = (UINT16 *)calloc (PlatformIdNum, sizeof (UINT16));
+        if (UqiNode->Header.DefaultId == NULL) {
+          printf ("Fali to allocate memory!\n");
+          return EFI_OUT_OF_RESOURCES;
+        }
+        UqiNode->Header.PlatformId = (UINT64 *)calloc (PlatformIdNum, sizeof (UINT64));
+        if (UqiNode->Header.PlatformId == NULL) {
+          printf ("Fali to allocate memory!\n");
+          return EFI_OUT_OF_RESOURCES;
+        }
+        for (Index5 = 0; Index5 < PlatformIdNum; Index5++) {
+          UqiNode->Header.DefaultId[Index5] = (UINT16)DefaultId[Index5];
+        }
+        memcpy (UqiNode->Header.PlatformId, PlatformId, PlatformIdNum * sizeof (UINT64));
+
+        if (AsciiOrUcs2 == ASCII) {
+          fscanf(ScriptFile, " %llx", (long long *)UqiNode->Header.Value);
+        } else {
+          Char8Str = ReadUcs2ToStr (ScriptFile, AsciiOrUcs2);
+          if (Char8Str == NULL) {
+            return EFI_ABORTED;
+          }
+          sscanf(Char8Str, " %llx", (long long *)UqiNode->Header.Value);
+          if (Char8Str != NULL) {
+            free (Char8Str);
+            Char8Str = NULL;
+          }
+        }
+
+      } else if (stricmp(Type, "ORDERED_LIST") == 0) {
+        UqiNode = CreateInsertUqiNode ();
+        if (UqiNode == NULL) {
+          free (UqiBuffer);
+          return EFI_ABORTED;
+        }
+        UqiNode->Header.Type       = ORDERED_LIST;
+        UqiNode->Header.HexNum     = UqiSize;
+        UqiNode->Header.Data       = UqiBuffer;
+        UqiNode->Header.IdNum      = PlatformIdNum;
+        UqiNode->Header.DefaultId  = (UINT16 *)calloc (PlatformIdNum, sizeof (UINT16));
+        if (UqiNode->Header.DefaultId == NULL) {
+          printf ("Fali to allocate memory!\n");
+          return EFI_OUT_OF_RESOURCES;
+        }
+        UqiNode->Header.PlatformId = (UINT64 *)calloc (PlatformIdNum, sizeof (UINT64));
+        if (UqiNode->Header.PlatformId == NULL) {
+          printf ("Fali to allocate memory!\n");
+          return EFI_OUT_OF_RESOURCES;
+        }
+        for (Index5 = 0; Index5 < PlatformIdNum; Index5++) {
+          UqiNode->Header.DefaultId[Index5] = (UINT16)DefaultId[Index5];
+        }
+        memcpy (UqiNode->Header.PlatformId, PlatformId, PlatformIdNum * sizeof (UINT64));
+
+        if (AsciiOrUcs2 == ASCII) {
+          fscanf(ScriptFile, " %x", (INT32 *)&MaxContainers);
+        } else {
+          Char8Str = ReadUcs2ToStr (ScriptFile, AsciiOrUcs2);
+          if (Char8Str == NULL) {
+            return EFI_ABORTED;
+          }
+          sscanf(Char8Str, " %x", (INT32 *)&MaxContainers);
+          if (Char8Str != NULL) {
+            free (Char8Str);
+            Char8Str = NULL;
+          }
+        }
+        if (MaxContainers > MAX_INPUT_ALLOCATE_SIZE) {
+          return EFI_ABORTED;
+        }
+        UqiNode->Header.Value      = (UINT8 *)calloc(MaxContainers + 1, sizeof(UINT64));
+        if (UqiNode->Header.Value == NULL) {
+          printf ("Fali to allocate memory!\n");
+          return EFI_OUT_OF_RESOURCES;
+        }
+        UqiNode->Header.DiffValue  = (UINT8 *)calloc(MaxContainers + 1, sizeof(UINT64));
+        if (UqiNode->Header.DiffValue == NULL) {
+          printf ("Fali to allocate memory!\n");
+          return EFI_OUT_OF_RESOURCES;
+        }
+        *UqiNode->Header.Value     = (UINT8) MaxContainers;
+        *UqiNode->Header.DiffValue = (UINT8) MaxContainers;
+
+        for (Index = 1; Index <= MaxContainers; Index++) {
+          if (*(UqiNode->Header.Value + Index) == '/') {
+            printf ("Error.  Failed to parse the value of ORDERED_LIST.\n");
+            return EFI_INVALID_PARAMETER;
+          }
+          if (AsciiOrUcs2 == ASCII) {
+            fscanf(ScriptFile, " %llx", ((long long *)UqiNode->Header.Value + Index));
+          } else {
+            Char8Str = ReadUcs2ToStr (ScriptFile, AsciiOrUcs2);
+            if (Char8Str == NULL) {
+              return EFI_ABORTED;
+            }
+            sscanf(Char8Str, " %llx", ((long long *)UqiNode->Header.Value + Index));
+            if (Char8Str != NULL) {
+              free (Char8Str);
+              Char8Str = NULL;
+            }
+          }
+        }
+
+      } else {
+        //
+        //  Unknown type
+        //
+        //  Free UQI buffer before skipping to next line
+        //
+        free(UqiBuffer);
+        UqiBuffer = NULL;
+        printf ("Error.  Invalid parameters exist in scripts line %d", ScriptsLine);
+        return EFI_ABORTED;
+      }
+      UqiNode->Header.ScriptsLine = ScriptsLine;
+      //
+      //  Skip to next line
+      //
+      do {
+        if (AsciiOrUcs2 == ASCII) {
+          fread(&TempChar, sizeof (CHAR8), 1, ScriptFile);
+        } else {
+          fread(&TempChar16, sizeof (CHAR16), 1, ScriptFile);
+          if (AsciiOrUcs2 == BIG_UCS2) {
+            TempChar = (CHAR8)TempChar16;
+          } else {
+            TempChar = (CHAR8)(TempChar16 >> 8);
+          }
+        }
+      } while((TempChar != '\n') && !feof(ScriptFile));
+      break;
+
+    case '\n':
+    case '\r':
+      //
+      //  Newline, skip to next character
+      //
+      break;
+
+     case '/':
+      //
+      // Get the value of PlatformId and DefaultId from comments
+      //
+      do {
+        if (AsciiOrUcs2 == ASCII) {
+          fread(&TempChar, sizeof (CHAR8), 1, ScriptFile);
+        } else {
+          fread(&TempChar16, sizeof (CHAR16), 1, ScriptFile);
+          if (AsciiOrUcs2 == BIG_UCS2) {
+             TempChar = (CHAR8)TempChar16;
+           } else {
+             TempChar = (CHAR8)(TempChar16 >> 8);
+           }
+        }
+        //
+        //"/ DefaultId :"
+        //
+        if (!ReadDefaultId) {
+          if (TempChar == DefaultIdStr[Index1]) {
+            Index1++;
+          } else {
+            Index1 = 0;
+          }
+          if (Index1 == strlen (DefaultIdStr)) {
+            Index1        = 0;
+            Index3        = 0;
+            memset (Array, 0, MAX_PLATFORM_DEFAULT_ID_NUM * MAX_PLATFORM_DEFAULT_ID_NUM);
+            ReadDefaultId = TRUE;
+            mMultiPlatformParam.MultiPlatformOrNot = TRUE;
+          }
+        } else if (ReadDefaultId) {
+          if (TempChar == '\n') {
+            ReadDefaultId = FALSE;
+            Array[Index3] = TempChar;
+            DefaultIdNum  = GetNumFromAsciiString ((CHAR8 *)Array, DefaultId);
+            mMultiPlatformParam.KeyDefaultId[mMultiPlatformParam.KeyIdNum] = (UINT16)DefaultId[0];
+          } else {
+            Array[Index3++] = TempChar;
+          }
+        }
+        //
+        //"/ PlatformId:"
+        //
+        if (!ReadPlatformId) {
+          if (TempChar == PlatformIdStr[Index2]) {
+            Index2++;
+          } else {
+            Index2 = 0;
+          }
+          if (Index2 == strlen (PlatformIdStr)) {
+            Index2         = 0;
+            Index3         = 0;
+            memset (Array, 0, MAX_PLATFORM_DEFAULT_ID_NUM * MAX_PLATFORM_DEFAULT_ID_NUM);
+            ReadPlatformId = TRUE;
+          }
+        } else if (ReadPlatformId) {
+          if (TempChar == '\n') {
+            ReadPlatformId = FALSE;
+            Array[Index3]  = TempChar;
+            PlatformIdNum  = GetNumFromAsciiString ((CHAR8 *)Array, PlatformId);
+            //
+            // Take the first defaultid an platformid as the key of this group
+            //
+            mMultiPlatformParam.KeyPlatformId[mMultiPlatformParam.KeyIdNum++] = PlatformId[0];
+            assert (DefaultIdNum == PlatformIdNum);
+          } else {
+            Array[Index3++] = TempChar;
+          }
+        }
+        //
+        //"/ PlatformIdUqi:"
+        //
+        if (!ReadPlatformIdUqi) {
+          if (TempChar == PlatformUqi[Index4]) {
+            Index4++;
+          } else {
+            Index4 = 0;
+          }
+          if (Index4 == strlen (PlatformUqi)) {
+            Index4         = 0;
+            Index3         = 0;
+            memset (Array, 0, MAX_PLATFORM_DEFAULT_ID_NUM * MAX_PLATFORM_DEFAULT_ID_NUM);
+            ReadPlatformIdUqi = TRUE;
+          }
+        } else if (ReadPlatformIdUqi) {
+          if (mMultiPlatformParam.Uqi.HexNum > 0) {
+            continue;
+          }
+          //
+          //  Read size of UQI string
+          //
+          if (AsciiOrUcs2 == ASCII) {
+            fscanf(ScriptFile, " %x", (INT32 *)&mMultiPlatformParam.Uqi.HexNum);
+          } else {
+            Char8Str = ReadUcs2ToStr (ScriptFile, AsciiOrUcs2);
+            if (Char8Str == NULL) {
+              return EFI_ABORTED;
+            }
+            sscanf(Char8Str, " %x", (INT32 *)&mMultiPlatformParam.Uqi.HexNum);
+            if (Char8Str != NULL) {
+              free (Char8Str);
+              Char8Str = NULL;
+            }
+          }
+          if (mMultiPlatformParam.Uqi.HexNum > MAX_INPUT_ALLOCATE_SIZE) {
+            return EFI_ABORTED;
+          }
+          //
+          //  Malloc buffer for string size + null termination
+          //
+          if (mMultiPlatformParam.Uqi.Data != NULL) {
+            free (mMultiPlatformParam.Uqi.Data);
+            mMultiPlatformParam.Uqi.Data = NULL;
+          }
+          mMultiPlatformParam.Uqi.Data = (CHAR16 *)calloc(mMultiPlatformParam.Uqi.HexNum + 1, sizeof(CHAR16));
+
+          if (mMultiPlatformParam.Uqi.Data == NULL) {
+            printf("Error. Unable to allocate 0x%04zx bytes for UQI string -- FAILURE\n", (mMultiPlatformParam.Uqi.HexNum + 1) * sizeof(CHAR16));
+            break;
+          }
+          //
+          //  Read UQI string
+          //
+          for (Index = 0; Index < mMultiPlatformParam.Uqi.HexNum; Index++) {
+            if (AsciiOrUcs2 == ASCII) {
+              fscanf(ScriptFile, " %hx", (short *)&(mMultiPlatformParam.Uqi.Data[Index]));
+            } else {
+              Char8Str = ReadUcs2ToStr (ScriptFile, AsciiOrUcs2);
+              if (Char8Str == NULL) {
+                return EFI_ABORTED;
+              }
+              sscanf(Char8Str, " %hx", (short *)&(mMultiPlatformParam.Uqi.Data[Index]));
+              if (Char8Str != NULL) {
+                free (Char8Str);
+                Char8Str = NULL;
+              }
+            }
+          }
+          //
+          //  Set null termination
+          //
+          mMultiPlatformParam.Uqi.Data[Index] = 0;
+          ReadPlatformIdUqi = FALSE;
+        }
+
+      } while((TempChar != '\n') && !feof(ScriptFile));
+      break;
+      //
+      // To do: Get and set DefaultId and PlatformId here!
+      //
+     default:
+      //
+      //  Comment or garbage, skip to next line
+      //
+       do {
+         if (AsciiOrUcs2 == ASCII) {
+           fread(&TempChar, sizeof (CHAR8), 1, ScriptFile);
+         } else {
+           fread(&TempChar16, sizeof (CHAR16), 1, ScriptFile);
+           if (AsciiOrUcs2 == BIG_UCS2) {
+              TempChar = (CHAR8)TempChar16;
+            } else {
+              TempChar = (CHAR8)(TempChar16 >> 8);
+            }
+         }
+       } while((TempChar != '\n') && !feof(ScriptFile));
+       break;
+    }
+  }
+  return EFI_SUCCESS;
+}
+
+/**
+  Get the offset of file name from the whole path.
+
+  @param  NameStr    The whole file path.
+
+  @retval Offset     Return the offset of file name in path
+**/
+static
+UINTN
+GetOffsetOfFileName (
+  IN CHAR8   *NameStr
+  )
+{
+  CHAR8       *Str;
+  UINTN       Index;
+  UINTN       CurIndex;
+
+  Index    = 0;
+  CurIndex = 0;
+  Str      = NameStr;
+
+  if (NameStr == NULL) {
+    return 0;
+  }
+  while (*Str != '\0') {
+    if (*Str == OS_SEP) {
+      CurIndex = Index;
+    }
+    Str++;
+    Index++;
+  }
+  if (*(NameStr + CurIndex) == OS_SEP) {
+    return CurIndex + 1;
+  } else {
+    return 0;
+  }
+}
+/**
+  Print the questions which is updated to the current platform successfully.
+
+  Parse the Uqi List, and print it till break NULL.
+
+  @param  List          Pointer to a List.
+
+  @retval EFI_SUCCESS   The Print was complete successfully
+  @return EFI_ABORTED   An error occurred
+**/
+static
+VOID
+PrintUpdateListInfo (
+  IN UQI_PARAM_LIST   *UqiList
+  )
+{
+  UINT32           Index;
+  UINT32           Index1;
+  UINT32           Index2;
+  UQI_PARAM_LIST   *CurList;
+
+  Index1   = 0;
+  Index2   = 0;
+  Index    = 0;
+  CurList  = UqiList;
+
+  printf ("\n\n                            -- Update List --                         ");
+
+  while (CurList != NULL) {
+    if (!CurList->ErrorOrNot && CurList->ParseOrNot && !CurList->SameOrNot) {
+      ++Index;
+      printf ("\n\n[Script line %d] Update No.%d:\n", CurList->Header.ScriptsLine, ++Index1);
+      printf ("Q  %04x ", CurList->Header.HexNum);
+      for (Index2 = 0; Index2 < CurList->Header.HexNum; Index2++) {
+        printf ("%04x ", CurList->Header.Data[Index2]);
+      }
+      if (CurList->Header.Type == ORDERED_LIST) {
+        printf ("ORDERED_LIST ");
+      } else if (CurList->Header.Type == CHECKBOX) {
+        printf ("CHECKBOX ");
+      } else if (CurList->Header.Type == ONE_OF) {
+        printf ("ONE_OF ");
+      } else if (CurList->Header.Type == NUMERIC) {
+        printf ("NUMERIC ");
+      } else if (CurList->Header.Type == STRING) {
+        printf ("STRING ");
+      } else {
+        printf ("UNKNOWN ");
+      }
+      //
+      //Print the value of scripts
+      //
+      printf ("\n[ Update Value From: ");
+      if (CurList->Header.Type == ORDERED_LIST) {
+        for (Index2 = 0; Index2 <= *(CurList->Header.DiffValue); Index2++) {
+          printf ("%02x ", *(CurList->Header.DiffValue + Index2));
+        }
+      } else if (CurList->Header.Type == STRING) {
+        printf("\"");
+        WriteUnicodeStr((CHAR16 *)CurList->Header.DiffValue);
+        printf("\"");
+      } else {
+        printf ("%llx ", *(unsigned long long*)(UINT64 *)CurList->Header.DiffValue);
+      }
+      //
+      //Print the value of current platform
+      //
+      printf (" To: ");
+      if (CurList->Header.Type == ORDERED_LIST) {
+        for (Index2 = 0; Index2 <= *(CurList->Header.Value); Index2++) {
+          printf ("%02x ", *(CurList->Header.Value + Index2));
+        }
+      } else if (CurList->Header.Type == STRING) {
+        printf("\"");
+        WriteUnicodeStr((CHAR16 *)CurList->Header.Value);
+        printf("\"");
+      } else {
+        printf ("%llx ", *(unsigned long long*)(UINT64 *)CurList->Header.Value);
+      }
+      printf ("]");
+    }
+    CurList = CurList->Next;
+  }
+  if (Index > 1) {
+    printf ("\n\n\n[Results]: %d questions have been updated successfully in total. \n", Index);
+  } else {
+    printf ("\n\n\n[Results]: %d question has been updated successfully in total. \n", Index);
+  }
+}
+
+
+/**
+  Print the error, when update questions.
+
+  Parse the Uqi List, and print it till break NULL.
+
+  @param  List          The Pointer to a List.
+
+**/
+static
+BOOLEAN
+PrintErrorInfo (
+  IN UQI_PARAM_LIST   *UqiList
+  )
+{
+  UINT32           Index1;
+  UINT32           Index2;
+  UINT32           Index;
+  UQI_PARAM_LIST   *CurList;
+  BOOLEAN          IsError;
+
+  Index1   = 0;
+  Index2   = 0;
+  Index    = 0;
+  CurList  = UqiList;
+  IsError  = FALSE;
+
+  while (CurList != NULL) {
+    if (CurList->ErrorOrNot && CurList->ParseOrNot) {
+      IsError  = TRUE;
+      ++Index;
+      printf ("\n\n[Script line %d] Error Information No.%d:\n", CurList->Header.ScriptsLine, ++Index1);
+      printf ("Q  %04x ", CurList->Header.HexNum);
+      for (Index2 = 0; Index2 < CurList->Header.HexNum; Index2++) {
+        printf ("%04x ", CurList->Header.Data[Index2]);
+      }
+      if (CurList->Header.Type == ORDERED_LIST) {
+        printf ("ORDERED_LIST ");
+      } else if (CurList->Header.Type == CHECKBOX) {
+        printf ("CHECKBOX ");
+      } else if (CurList->Header.Type == ONE_OF) {
+        printf ("ONE_OF ");
+      } else if (CurList->Header.Type == NUMERIC) {
+        printf ("NUMERIC ");
+      } else if (CurList->Header.Type == STRING) {
+        printf ("STRING ");
+      } else {
+        printf ("UNKNOWN ");
+      }
+      //
+      //Print the Input value of scripts
+      //
+      if (CurList->Header.Type == ORDERED_LIST) {
+        for (Index2 = 0; Index2 <= *CurList->Header.Value; Index2++) {
+          printf ("%02x ", *(CurList->Header.Value + Index2));
+        }
+      } else if (CurList->Header.Type == STRING) {
+        printf("\"");
+        WriteUnicodeStr((CHAR16 *)CurList->Header.Value);
+        printf("\"");
+      } else {
+        printf ("%llx ", *(unsigned long long*)(UINT64 *)CurList->Header.Value);
+      }
+      //
+      //Print the Error information
+      //
+      if (CurList->Error != NULL) {
+        printf ("\n%s ", CurList->Error);
+      }
+    }
+    CurList = CurList->Next;
+  }
+  if (IsError) {
+    if (Index > 1) {
+      printf ("\n\n[Results]: Occurred %d errors during the update process. \n", Index);
+    } else {
+      printf ("\n\n[Results]: Occurred %d error during the update process. \n", Index);
+    }
+  }
+  return IsError;
+}
+
+/**
+  Any questions that exist in both the script and the current platform and have
+  different values will be logged to the screen.
+
+  Parse the Uqi List, and print it till break NULL.
+
+  @param  List          Pointer to a List.
+
+  @retval EFI_SUCCESS   The Print was complete successfully
+  @return EFI_ABORTED   An error occurreds
+**/
+static
+VOID
+PrintVerifiedListInfo (
+  IN UQI_PARAM_LIST   *UqiList
+  )
+{
+  UINT32           Index1;
+  UINT32           Index2;
+  UINT32           Index3;
+  UINT32           Index;
+  UQI_PARAM_LIST   *CurList;
+  UINT32           StrLen;
+  UINT32           StrLen1;
+  UINT32           StrLen2;
+
+  Index1   = 0;
+  Index2   = 0;
+  Index    = 0;
+  StrLen   = 0;
+  CurList  = UqiList;
+
+  StrLen1  = strlen (mSetupTxtName + GetOffsetOfFileName (mSetupTxtName));
+  StrLen2  = strlen (mInputFdName + GetOffsetOfFileName (mInputFdName));
+
+  StrLen   = (StrLen1 > StrLen2) ? StrLen1:StrLen2;
+
+  printf ("\n\n                            -- Different List --                         ");
+
+  while (CurList != NULL) {
+    if (!CurList->SameOrNot && CurList->ParseOrNot) {
+      ++Index;
+      printf ("\n\n[Script line %d] Difference No.%d:", CurList->Header.ScriptsLine, ++Index1);
+      printf ("\n[%s", mSetupTxtName + GetOffsetOfFileName (mSetupTxtName));
+      for (Index3 = 0; Index3 < StrLen - StrLen1; Index3++) {
+        printf (" ");
+      }
+      printf ("]:");
+      printf (" Q  %04x ", CurList->Header.HexNum);
+      for (Index2 = 0; Index2 < CurList->Header.HexNum; Index2++) {
+        printf ("%04x ", CurList->Header.Data[Index2]);
+      }
+      if (CurList->Header.Type == ORDERED_LIST) {
+        printf ("ORDERED_LIST ");
+      } else if (CurList->Header.Type == CHECKBOX) {
+        printf ("CHECKBOX ");
+      } else if (CurList->Header.Type == ONE_OF) {
+        printf ("ONE_OF ");
+      } else if (CurList->Header.Type == NUMERIC) {
+        printf ("NUMERIC ");
+      } else if (CurList->Header.Type == STRING) {
+        printf ("STRING ");
+      } else {
+        printf ("UNKNOWN ");
+      }
+      //
+      //Print the Input value of scripts
+      //
+      if (CurList->Header.Type == ORDERED_LIST) {
+        for (Index2 = 0; Index2 <= *(CurList->Header.Value); Index2++) {
+          printf ("%02x ", *(CurList->Header.Value + Index2));
+        }
+      } else if (CurList->Header.Type == STRING) {
+        printf("\"");
+        WriteUnicodeStr((CHAR16 *)CurList->Header.Value);
+        printf("\"");
+      } else {
+        printf ("%llx ", *(unsigned long long*)(UINT64 *)CurList->Header.Value);
+      }
+      //
+      //Print the value of current platform
+      //
+      printf ("\n[%s", mInputFdName + GetOffsetOfFileName (mInputFdName));
+      for (Index3 = 0; Index3 < StrLen - StrLen2; Index3++) {
+        printf (" ");
+      }
+      printf ("]:");
+      printf (" Q  %04x ", CurList->Header.HexNum);
+      for (Index2 = 0; Index2 < CurList->Header.HexNum; Index2++) {
+        printf ("%04x ", CurList->Header.Data[Index2]);
+      }
+      if (CurList->Header.Type == ORDERED_LIST) {
+        printf ("ORDERED_LIST ");
+      } else if (CurList->Header.Type == CHECKBOX) {
+        printf ("CHECKBOX ");
+      } else if (CurList->Header.Type == ONE_OF) {
+        printf ("ONE_OF ");
+      } else if (CurList->Header.Type == NUMERIC) {
+        printf ("NUMERIC ");
+      } else if (CurList->Header.Type == STRING) {
+        printf ("STRING ");
+      } else {
+        printf ("UNKNOWN ");
+      }
+      if (CurList->Header.Type == ORDERED_LIST) {
+        for (Index2 = 0; Index2 <= *(CurList->Header.DiffValue); Index2++) {
+          printf ("%02x ", *(CurList->Header.DiffValue + Index2));
+        }
+      } else if (CurList->Header.Type == STRING) {
+        printf("\"");
+        WriteUnicodeStr((CHAR16 *)CurList->Header.DiffValue);
+        printf("\"");
+      } else {
+        printf ("%llx ", *(unsigned long long*)(UINT64 *)CurList->Header.DiffValue);
+      }
+    }
+    CurList = CurList->Next;
+  }
+  if (Index > 1) {
+    printf (
+      "\n\n\n[Results]: There are %d differences between '%s' and '%s' in total.\n\n\n",
+      Index,
+      mSetupTxtName + GetOffsetOfFileName (mSetupTxtName),
+      mInputFdName + GetOffsetOfFileName (mInputFdName)
+      );
+  } else {
+    printf (
+      "\n\n\n[Results]: There is %d difference between '%s' and '%s' in total.\n\n\n",
+      Index,
+      mSetupTxtName + GetOffsetOfFileName (mSetupTxtName),
+      mInputFdName + GetOffsetOfFileName (mInputFdName)
+     );
+  }
+}
+
+/**
+  Insert Uqi object to the end of unidirection List.
+
+  @param  InList           The Pointer to the current object
+  @param  UqiListEntry     The pointer to the entry of UqiList
+
+  @return EFI_SUCCESS
+**/
+EFI_STATUS
+InsertUnidirectionList (
+  IN     UQI_PARAM_LIST  *InList,
+  IN     UQI_PARAM_LIST  **UqiListEntry
+  )
+{
+  UQI_PARAM_LIST **UqiCurList;
+  UQI_PARAM_LIST *UqiNext;
+
+  UqiCurList = NULL;
+  UqiNext    = NULL;
+
+  if (UqiListEntry == NULL) {
+    return EFI_ABORTED;
+  }
+  //
+  // Insert to Uqi Node to UqiList
+  //
+  UqiCurList = UqiListEntry;
+  UqiNext    = *UqiCurList;
+  if (UqiNext == NULL) {
+    //
+    //Insert is the first node as node header
+    //
+    *UqiCurList = InList;
+  } else {
+    while ((UqiNext != NULL) && (UqiNext->Next != NULL)) {
+      UqiNext = UqiNext->Next;
+    }
+    UqiNext->Next = InList;
+  }
+  return EFI_SUCCESS;
+}
+
+/**
+  Free variable unidirection List.
+
+  @param  UqiListEntry     The pointer to the entry of UqiList
+
+  @return EFI_SUCCESS
+**/
+EFI_STATUS
+FreeUnidirectionList (
+  IN     UQI_PARAM_LIST  *UqiListEntry
+  )
+{
+  UQI_PARAM_LIST  *Next;
+
+  Next = NULL;
+  //
+  // Free Uqi List
+  //
+  while (UqiListEntry != NULL) {
+    Next = UqiListEntry->Next;
+    if (UqiListEntry->Header.Value != NULL) {
+      free (UqiListEntry->Header.Value);
+    }
+    if (UqiListEntry->Header.DiffValue != NULL) {
+      free (UqiListEntry->Header.DiffValue);
+    }
+    if (UqiListEntry->Header.Data != NULL) {
+      free (UqiListEntry->Header.Data);
+    }
+    if (UqiListEntry->Header.DefaultId != NULL) {
+      free (UqiListEntry->Header.DefaultId);
+    }
+    if (UqiListEntry->Header.PlatformId != NULL) {
+      free (UqiListEntry->Header.PlatformId);
+    }
+    if (UqiListEntry->Error != NULL) {
+      free (UqiListEntry->Error);
+    }
+    free (UqiListEntry);
+    UqiListEntry = Next;
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Delete a directory and files in it.
+
+  @param   DirName   Name of the directory need to be deleted.
+
+  @return EFI_INVALID_PARAMETER
+  @return EFI_SUCCESS
+**/
+static
+EFI_STATUS
+LibRmDir (
+  IN  CHAR8*  DirName
+)
+{
+  CHAR8*          SystemCommand;
+
+  SystemCommand             = NULL;
+
+  if (DirName == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  //
+  // Delete a directory and files in it.
+  //
+
+  SystemCommand = malloc (
+    strlen (RMDIR_STR) +
+    strlen (DirName)     +
+    1
+    );
+  if (SystemCommand == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  sprintf (
+    SystemCommand,
+    RMDIR_STR,
+    DirName
+    );
+
+  system (SystemCommand);
+  free(SystemCommand);
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Pick up the FFS from the FD image.
+
+  Call BfmLib to get all FFS in one FD image, and save all which includes IFR
+  Binary to gEfiFdInfo structure.
+
+  @retval EFI_SUCCESS          Get the address successfully.
+**/
+static
+EFI_STATUS
+PickUpFfsFromFd (
+  VOID
+  )
+{
+  CHAR8          *SystemCommandFormatString;
+  CHAR8          *SystemCommand;
+  CHAR8          *TempSystemCommand;
+  CHAR8          *TemDir;
+  EFI_STATUS     Status;
+  INT32          ReturnValue;
+
+  Status                    = EFI_SUCCESS;
+  SystemCommandFormatString = NULL;
+  SystemCommand             = NULL;
+  TempSystemCommand         = NULL;
+  TemDir                    = NULL;
+  ReturnValue               = 0;
+
+  memset (&gEfiFdInfo, 0, sizeof (G_EFI_FD_INFO));
+  //
+  // Construction 'system' command string
+  //
+  SystemCommandFormatString = "BfmLib -e \"%s\" ";
+
+  SystemCommand = malloc (
+                    strlen (SystemCommandFormatString) + strlen (mInputFdName) + 1
+                  );
+
+  if (SystemCommand == NULL) {
+    printf ("Fail to allocate memory.\n");
+    return EFI_ABORTED;
+  }
+
+  sprintf (
+    SystemCommand,
+    "BfmLib -e \"%s\" ",
+    mInputFdName
+    );
+
+  if (mFullGuidToolDefinitionDir[0] != 0) {
+    TempSystemCommand = SystemCommand;
+    SystemCommand = malloc (
+                    strlen (mFullGuidToolDefinitionDir) + strlen (OS_SEP_STR) + strlen (TempSystemCommand) + 1
+                  );
+
+    if (SystemCommand == NULL) {
+      free (TempSystemCommand);
+      return EFI_UNSUPPORTED;
+    }
+    strcpy (SystemCommand, mFullGuidToolDefinitionDir);
+    strcat (SystemCommand, OS_SEP_STR);
+    strcat (SystemCommand, TempSystemCommand);
+    free (TempSystemCommand);
+
+  }
+
+  //
+  // Call BfmLib to get all FFS in Temp folder of current path
+  //
+  ReturnValue = system (SystemCommand);
+  free (SystemCommand);
+  if (ReturnValue == -1) {
+    printf ("Error. Call BfmLib failed.\n");
+    return EFI_ABORTED;
+  }
+  //
+  //Pick up the FFS which is interrelated with the IFR binary.
+  //
+  TemDir = getcwd (NULL, _MAX_PATH);
+  if (strlen (TemDir) + strlen (OS_SEP_STR) + strlen (TEMP_DIR_NAME)> _MAX_PATH - 1) {
+    printf ("The directory is too long \n");
+    return EFI_ABORTED;
+  }
+  strncat (TemDir, OS_SEP_STR, _MAX_PATH - strlen (TemDir) - 1);
+  strncat (TemDir, TEMP_DIR_NAME, _MAX_PATH - strlen (TemDir) - 1);
+  mMultiPlatformParam.ExistStorageFfsInBfv = FALSE;
+  Status = FindFileInFolder (TemDir, &mMultiPlatformParam.ExistStorageFfsInBfv, &mMultiPlatformParam.SizeOptimized);
+
+  return Status;
+}
+
+#define BUILD_IN_TOOL_COUNT 4
+/**
+  Generate pre-defined guided tools data.
+
+  @return  An EFI_HANDLE contain guided tools data.
+
+**/
+static
+EFI_HANDLE
+PreDefinedGuidedTools (
+  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;
+
+  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 ( "Fail to allocate memory. \n");
+          if (Tool != NULL) {
+            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;
+}
+
+/**
+  Read all storages under a specified platformId and defaultId from BFV.
+
+  @param  Binary            The pointer to the buffer of binary.
+  @param  StorageListEntry  The pointer to the storage list.
+
+  @return length          The length of storage
+**/
+UINT32
+ReadStorageFromBinary (
+  IN  UINT8             *Binary,
+  IN  LIST_ENTRY        *StorageListEntry
+  )
+{
+  UINT32                       Length;
+  UINT8                        *DataBase;
+  BOOLEAN                      AuthencitatedMonotonicOrNot;
+  BOOLEAN                      AuthencitatedBasedTimeOrNot;
+
+  Length                      = 0;
+  AuthencitatedMonotonicOrNot = FALSE;
+  AuthencitatedBasedTimeOrNot = FALSE;
+  DataBase                    = Binary + sizeof (EFI_COMMON_SECTION_HEADER);
+  //
+  // Judge the layout of NV by Variable Guid
+  //
+  AuthencitatedMonotonicOrNot  = CheckMonotonicBasedVarStore ((VOID *)(DataBase + *(UINT16 *)DataBase));
+  AuthencitatedBasedTimeOrNot  = CheckTimeBasedVarStoreOrNot ((VOID *)(DataBase + *(UINT16 *)DataBase));
+
+  if (AuthencitatedMonotonicOrNot) {
+    //
+    // Read variable with Monotonic based layout from binary
+    //
+    Length = ReadMonotonicBasedVariableToList (Binary, StorageListEntry);
+  } else if (AuthencitatedBasedTimeOrNot){
+    //
+    // Read variable with time-based layout from binary
+    //
+    Length = ReadTimeBasedVariableToList (Binary, StorageListEntry);
+  } else {
+    //
+    // Read variable with normal layout from binary
+    //
+    Length = ReadVariableToList (Binary, StorageListEntry);
+  }
+
+  return Length;
+}
+
+/**
+  Insert one storage to the raw bianry, and return its length.
+
+  @param  Storage         The pointer to a storage in storage list.
+  @param  Binary          The pointer to the buffer of binary.
+
+  @return length          The length of storage
+**/
+UINT32
+PutStorageToBinary (
+  IN  FORMSET_STORAGE   *Storage,
+  IN  UINT8             *Binary,
+  IN  LIST_ENTRY        *StorageListEntry
+  )
+{
+  EFI_FIRMWARE_VOLUME_HEADER   *VarAddr;
+  UINT32                       Length;
+  UINT32                       Index;
+  UINT8                        *BinaryBeginning;
+  FORMSET_STORAGE              *CurStorage;
+  LIST_ENTRY                   *StorageLink;
+  VOID                         *VariableStoreHeader;
+  BOOLEAN                      AuthencitatedMonotonicOrNot;
+  BOOLEAN                      AuthencitatedBasedTimeOrNot;
+
+  VarAddr                     = (EFI_FIRMWARE_VOLUME_HEADER   *) gEfiFdInfo.EfiVariableAddr;
+  Length                      = 0;
+  Index                       = 0;
+  BinaryBeginning             = Binary;
+  VariableStoreHeader         = (VOID *)((CHAR8 *)VarAddr + VarAddr->HeaderLength);
+  AuthencitatedMonotonicOrNot = FALSE;
+  AuthencitatedBasedTimeOrNot = FALSE;
+  //
+  // Judge the layout of NV by gEfiVariableGuid
+  //
+  AuthencitatedMonotonicOrNot  = CheckMonotonicBasedVarStore (VariableStoreHeader);
+  AuthencitatedBasedTimeOrNot  = CheckTimeBasedVarStoreOrNot (VariableStoreHeader);
+  //
+  // Build the binary for BFV
+  //
+  StorageLink = GetFirstNode (StorageListEntry);
+
+  while (!IsNull (StorageListEntry, StorageLink)) {
+    CurStorage = FORMSET_STORAGE_FROM_LINK (StorageLink);
+    if ((CurStorage->DefaultId[0] == Storage->DefaultId[0])
+      && (CurStorage->PlatformId[0] == Storage->PlatformId[0])
+      && !CurStorage->Skip
+      ) {
+      CurStorage->Skip = TRUE;
+
+      if (AuthencitatedMonotonicOrNot) {
+        //
+        // Copy variable with Monotonic based layout to binary
+        //
+        Length = CopyMonotonicBasedVariableToBinary (CurStorage, BinaryBeginning, Index);
+      } else if (AuthencitatedBasedTimeOrNot){
+        //
+        // Copy variable with time-based layout to binary
+        //
+        Length = CopyTimeBasedVariableToBinary (CurStorage, BinaryBeginning, Index);
+      } else {
+        //
+        // Copy variable with normall layout to binary
+        //
+        Length = CopyVariableToBinary (CurStorage, BinaryBeginning, Index);
+      }
+      Index++;
+    }
+    StorageLink = GetNextNode (StorageListEntry, StorageLink);
+  }
+  //
+  // Fix the length of storage header under a specified DefaultId and PlatformId
+  //
+  if (AuthencitatedMonotonicOrNot) {
+    FixMontonicVariableHeaderSize (BinaryBeginning, Length);
+  } else if (AuthencitatedBasedTimeOrNot){
+    FixBasedTimeVariableHeaderSize (BinaryBeginning, Length);
+  } else {
+    FixVariableHeaderSize (BinaryBeginning, Length);
+  }
+  return Length;
+}
+
+/**
+  Insert one storage to Fd's NvStoreDatabase, and return its length.
+
+  @param  Storage         The pointer to a storage in storage list.
+  @param  Binary          The pointer to the buffer of binary.
+
+  @return length          The length of storage
+**/
+UINT32
+PutStorageToNvStoreBinary (
+  IN  FORMSET_STORAGE   *Storage,
+  IN  UINT8             *Binary,
+  IN  LIST_ENTRY        *StorageListEntry
+  )
+{
+  UINT32                       Length;
+  UINT32                       Index;
+  UINT8                        *BinaryBeginning;
+  FORMSET_STORAGE              *CurStorage;
+  LIST_ENTRY                   *StorageLink;
+
+  Length                      = 0;
+  Index                       = 0;
+  BinaryBeginning             = Binary;
+  //
+  // Build the binary for NvStorDatabase
+  //
+  StorageLink = GetFirstNode (StorageListEntry);
+  while (!IsNull (StorageListEntry, StorageLink)) {
+    CurStorage = FORMSET_STORAGE_FROM_LINK (StorageLink);
+    if ((CurStorage->PlatformId[0] == Storage->PlatformId[0])
+      && (CurStorage->DefaultId[0] == Storage->DefaultId[0])
+      && !CurStorage->Skip
+      ) {
+      CurStorage->Skip = TRUE;
+      Length = CopyVariableToNvStoreBinary (CurStorage, BinaryBeginning, Index);
+      Index++;
+    }
+    StorageLink = GetNextNode (StorageListEntry, StorageLink);
+  }
+  // Alignment
+  Length = (Length + 3) & ~3;
+  FixNvStoreVariableHeaderSize (BinaryBeginning, Length);
+  return Length;
+}
+
+/**
+  Optimize the Delta binary size based on the default setting binary, and
+  create a new binary with new size on the Storage.ffs.
+
+  @param  DefaultBinary         The pointer to a default setting binary
+  @param  DefaultHeaderLen      The header lenght of default setting binary
+  @param  DeltaBinary           The pointer to a delta setting binary
+  @param  CurrentSize           The size of current delta data.
+
+  @return length          The length of new storage
+**/
+UINT32
+OptimizeStorageDeltaData (
+  IN      UINT8             *DefaultBinary,
+  IN      UINT8             *CurrentBinary,
+  IN  OUT UINT8             *DeltaBinary,
+  IN      UINT32            CurrentSize
+  )
+{
+  UINT32         Size;
+  UINT16         Index;
+  UINT32         DefaultHeaderSize;
+  UINT32         DeltaHeaderSize;
+  UINT32         AlignSize;
+  PCD_DATA_DELTA   DeltaData;
+  DefaultHeaderSize = ((PCD_DEFAULT_DATA *)DefaultBinary)->HeaderSize + 4;
+  DeltaHeaderSize   = ((PCD_DEFAULT_DATA *)CurrentBinary)->HeaderSize + 4;
+  //
+  // Copy the Delta Header directly
+  //
+  Size = DeltaHeaderSize;
+  memcpy (DeltaBinary, CurrentBinary, Size);
+  //
+  // Compare the delta data and optimize the size
+  //
+  for (Index = 0; Index < CurrentSize - DeltaHeaderSize; Index++) {
+    if (*(DefaultBinary + DefaultHeaderSize + Index) != *(CurrentBinary + DeltaHeaderSize + Index)) {
+      DeltaData.Offset = Index;
+      DeltaData.Value  = *(CurrentBinary + DeltaHeaderSize + Index);
+      memcpy (DeltaBinary + Size, &DeltaData, sizeof (DeltaData));
+      Size = Size + sizeof(DeltaData);
+    }
+  }
+  *(UINT32 *)DeltaBinary = Size;
+  AlignSize = (Size + 7) & ~7;
+  //set Alignment data 0x00
+  for (Index = 0; Index < AlignSize - Size; Index++){
+    *(DeltaBinary + Size + Index) = 0x0;
+  }
+  return Size;
+}
+
+/**
+  Optimize the Delta binary size based on the default setting binary, and
+  create a new binary with new size on the Storage.ffs.
+
+  @param  DefaultBinary         The pointer to a default setting binary
+  @param  DefaultHeaderLen      The header lenght of default setting binary
+  @param  DeltaBinary           The pointer to a delta setting binary
+  @param  CurrentSize           The size of current delta data.
+
+  @return length          The length of new storage
+**/
+UINT32
+OptimizeStorageSection (
+  IN      UINT8             *DefaultBinary,
+  IN      UINT8             *CurrentBinary,
+  IN  OUT UINT8             *DeltaBinary,
+  IN      UINT32            CurrentSize
+  )
+{
+  UINT32         Size;
+  UINT16         Index;
+  UINT32         DefaultHeaderSize;
+  UINT32         DeltaHeaderSize;
+  DATA_DELTA     DeltaData;
+
+  DefaultHeaderSize = *(UINT16 *)DefaultBinary;
+  DeltaHeaderSize   = *(UINT16 *)CurrentBinary;
+
+  //
+  // Copy the Delta Header directly
+  //
+  Size = DeltaHeaderSize;
+  memcpy (DeltaBinary, CurrentBinary, Size);
+  //
+  // Compare the delta data and optimize the size
+  //
+  for (Index = 0; Index < CurrentSize - DeltaHeaderSize; Index++) {
+    if (*(DefaultBinary + DefaultHeaderSize + Index) != *(CurrentBinary + DeltaHeaderSize + Index)) {
+    DeltaData.Offset = Index;
+    DeltaData.Value  = *(CurrentBinary + DeltaHeaderSize + Index);
+    memcpy (DeltaBinary + Size, &DeltaData, sizeof (DeltaData));
+    Size = Size + sizeof(DeltaData);
+    }
+  }
+  return Size;
+}
+
+/**
+  Create the storage section and copy it to memory.
+
+  @param  Buffer       The pointer to the buffer
+  @param  Size         The size of input buffer.
+
+  @return the new size
+**/
+UINT32
+CreateStorageSection (
+  IN OUT  UINT8   *Buffer,
+  IN      UINT32  Size,
+  IN      CHAR8   *FileName
+)
+{
+  FILE            *BinaryFd;
+  UINTN           BytesWrite;
+  UINT32          SectionSize;
+
+  BinaryFd   = NULL;
+  //
+  // Create the raw section files in FFS
+  //
+  BinaryFd = fopen (FileName, "wb+");
+  if (BinaryFd == NULL) {
+    printf ("Error. Failed to create the raw data section.\n");
+    return 0;
+  }
+  fseek (BinaryFd, 0, SEEK_SET);
+  BytesWrite = fwrite (Buffer, sizeof (CHAR8), Size, BinaryFd);
+  fclose (BinaryFd);
+  if (BytesWrite != Size) {
+    printf ("Error. Failed to write the raw data section.\n");
+    return 0;
+  }
+  CreateRawSection (FileName, FileName);
+
+  BinaryFd = fopen (FileName, "rb");
+  if (BinaryFd == NULL) {
+    printf ("Error. Failed to open the raw data section.\n");
+    return 0;
+  }
+  fseek (BinaryFd, 0, SEEK_SET);
+  BytesWrite = fread (Buffer, sizeof (CHAR8), (Size + sizeof (EFI_COMMON_SECTION_HEADER)), BinaryFd);
+  fclose (BinaryFd);
+  if (BytesWrite != (Size + sizeof (EFI_COMMON_SECTION_HEADER))) {
+    printf ("Error. Failed to read the raw data section.\n");
+    return 0;
+  }
+
+  SectionSize = FvBufExpand3ByteSize (((EFI_COMMON_SECTION_HEADER *)Buffer)->Size);
+  return SectionSize;
+}
+
+/**
+  Read NvStoreDataBase and insert it to the Storage list.
+
+  @param  InputFdName     The pointer to the input fd name.
+  @param  VarListEntry    The pointer to the variable list.
+
+  @return EFI_INVALID_PARAMETER
+  @return EFI_SUCCESS
+**/
+EFI_STATUS
+ReadStorageFromNvStoreDatabase (
+  IN  LIST_ENTRY  *VarListEntry
+)
+{
+
+  UINT8               *Binary;
+  UINT8               *FullBinary;
+  UINT8               *VarDataBinary;
+  UINT8               *PreVarDataBinary;
+  UINT8               *DataBase;
+  PCD_DEFAULT_DATA      *DeltaVarStoreHeader;
+  PCD_DEFAULT_DATA    *PrePcdDefaultData;
+  UINT8               *DeltaData;
+  UINT32              DeltaSize;
+  UINT32              DataSize;
+  UINT32              HeaderSize;
+  UINT32              BinaryLength;
+  UINT32              Size;
+  UINT32              PreVarDataSize;
+  PCD_NV_STORE_DEFAULT_BUFFER_HEADER *NvStoreHeader;
+  UINT32              Offset;
+  UINT32              Value;
+  UINT32              Index;
+
+  BinaryLength              = 0;
+  Binary                    = NULL;
+  FullBinary                = NULL;
+  DataBase                  = NULL;
+  DeltaVarStoreHeader       = NULL;
+  PreVarDataBinary          = NULL;
+  PreVarDataSize            = 0;
+  DeltaSize                 = 0;
+  Size                      = sizeof (PCD_NV_STORE_DEFAULT_BUFFER_HEADER);
+  VarDataBinary             = NULL;
+
+  //
+  // Check whether the FD has included the storage FFS
+  //
+  //if (!mMultiPlatformParam.ExistStorageFfsInBfv) {
+  //  return EFI_ABORTED;
+  //}
+  NvStoreHeader    = (PCD_NV_STORE_DEFAULT_BUFFER_HEADER *)gEfiFdInfo.NvStoreDatabase;
+  BinaryLength     = NvStoreHeader->Length;
+  Binary       = (UINT8 *)gEfiFdInfo.NvStoreDatabase;
+  //
+  // If detect size optimized format, transfer it to normal format
+  // before parse it
+  //
+  if (mMultiPlatformParam.SizeOptimized) {
+    FullBinary = calloc(gEfiFdInfo.FdSize, sizeof(UINT8));
+    if (FullBinary == NULL) {
+      printf ("Error. Memory allocation failed.\n");
+      return EFI_ABORTED;
+    }
+  }
+  while (Size < BinaryLength) {
+    DataBase = Binary + Size;
+    DataSize = *(UINT32 *)DataBase;
+    if (Size == sizeof (PCD_NV_STORE_DEFAULT_BUFFER_HEADER)) {
+      PrePcdDefaultData = (PCD_DEFAULT_DATA *) DataBase;
+      HeaderSize = PrePcdDefaultData->HeaderSize;
+      PreVarDataSize   = DataSize - 4 - HeaderSize;
+      VarDataBinary    = malloc(DataSize);
+      if (VarDataBinary == NULL) {
+        printf ("Error. Memory allocation failed.\n");
+        return EFI_ABORTED;
+      }
+      memcpy (VarDataBinary, DataBase, DataSize);
+      PreVarDataBinary = malloc(DataSize - 4 - HeaderSize);
+      if (PreVarDataBinary == NULL) {
+        printf ("Error. Memory allocation failed.\n");
+        return EFI_ABORTED;
+      }
+      memcpy (PreVarDataBinary, DataBase + 4 + HeaderSize , DataSize - 4 - HeaderSize);
+    } else {
+      DeltaVarStoreHeader = (PCD_DEFAULT_DATA *)DataBase;
+      DeltaSize           = DeltaVarStoreHeader->DataSize;
+      HeaderSize     = DeltaVarStoreHeader->HeaderSize;
+      DeltaData           = (UINT8*) DeltaVarStoreHeader;
+
+    VarDataBinary = malloc(PreVarDataSize + HeaderSize + 4);
+    if (VarDataBinary == NULL) {
+        printf ("Error. Memory allocation failed.\n");
+        return EFI_ABORTED;
+      }
+      //
+      // Copy the default setting data
+      //
+      memcpy (VarDataBinary, DataBase, HeaderSize + 4);
+      memcpy (VarDataBinary + HeaderSize + 4, PreVarDataBinary, PreVarDataSize);
+      //
+      // Merge the delta data with default setting to get the full delta data
+      //
+      for (Index = 0; Index < (DeltaSize - HeaderSize - 4)/sizeof(PCD_DATA_DELTA); Index++) {
+        Offset = ((PCD_DATA_DELTA *)(DeltaData + HeaderSize + 4 + Index * sizeof(PCD_DATA_DELTA)))->Offset;
+        Value  = ((PCD_DATA_DELTA *)(DeltaData + HeaderSize + 4 + Index * sizeof(PCD_DATA_DELTA)))->Value;
+        if (*(VarDataBinary + HeaderSize + 4 + Offset) != Value) {
+          *(VarDataBinary + HeaderSize + 4 + Offset) = (UINT8)Value;
+        }
+      }
+    }
+    //
+    // Store the Variable Data to VarListEntry
+    //
+
+    ReadNvStoreVariableToList(VarDataBinary, VarListEntry);
+    Size += (DataSize + 7) & ~7;
+  }
+
+  if (VarDataBinary != NULL) {
+    free (VarDataBinary);
+  }
+  return EFI_SUCCESS;
+}
+
+/**
+  Read FFS from BFV and insert it to the Storage list.
+
+  @param  InputFdName     The pointer to the input fd name.
+  @param  VarListEntry    The pointer to the variable list.
+
+  @return EFI_INVALID_PARAMETER
+  @return EFI_SUCCESS
+**/
+EFI_STATUS
+ReadStorageFromBfv (
+  IN  LIST_ENTRY  *VarListEntry
+)
+{
+
+  UINT8               *Binary;
+  UINT8               *FullBinary;
+  UINT8               *DataBase;
+  UINT8               *PreVarStoreHeader;
+  DATA_DELTA          *DeltaVarStoreHeader;
+  UINT8               *DeltaData;
+  UINT32              PreDataSize;
+  UINT32              DeltaSize;
+  UINT32              BinaryLength;
+  UINT32              Size;
+  UINT32              SectionSize;
+  UINT32              FullSectionLen;
+  UINT32              FullSectionSize;
+  EFI_FFS_FILE_HEADER *FfsHeader;
+  UINT16              Offset;
+  UINT8               Value;
+  UINT32              Index;
+  CHAR8               *SectionName;
+
+  BinaryLength              = 0;
+  Binary                    = NULL;
+  FullBinary                = NULL;
+  DataBase                  = NULL;
+  PreVarStoreHeader         = NULL;
+  DeltaVarStoreHeader       = NULL;
+  PreDataSize               = 0;
+  DeltaSize                 = 0;
+  FullSectionSize           = 0;
+  Size                      = sizeof (EFI_FFS_FILE_HEADER);
+  FfsHeader                 = NULL;
+  FullSectionLen            = 0;
+  SectionName               = NULL;
+
+  SectionName = getcwd(NULL, _MAX_PATH);
+  if (strlen (SectionName) + 2 * strlen (OS_SEP_STR) + strlen ("Temp") + strlen ("TempSection.sec") >
+      _MAX_PATH - 1) {
+    printf ("Error. The current path is too long.\n");
+    return EFI_INVALID_PARAMETER;
+  }
+
+  sprintf (SectionName + strlen (SectionName), "%cTemp%cTempSection.sec", OS_SEP, OS_SEP);
+  //
+  // Check whether the FD has included the storage FFS
+  //
+  if (!mMultiPlatformParam.ExistStorageFfsInBfv) {
+    return EFI_ABORTED;
+  }
+  FfsHeader    = (EFI_FFS_FILE_HEADER *)gEfiFdInfo.StorageFfsInBfv;
+  BinaryLength = FvBufExpand3ByteSize (FfsHeader->Size);
+  Binary       = (UINT8 *)FfsHeader;
+  //
+  // If detect size optimized format, transfer it to normal format
+  // before parse it
+  //
+  if (mMultiPlatformParam.SizeOptimized) {
+    FullBinary = calloc(gEfiFdInfo.FdSize, sizeof(UINT8));
+  if (FullBinary == NULL) {
+      printf ("Error. Memory allocation failed.\n");
+      return EFI_ABORTED;
+  }
+  while (Size < BinaryLength) {
+    SectionSize = FvBufExpand3ByteSize (((EFI_COMMON_SECTION_HEADER *)(Binary + Size))->Size);
+    DataBase    = Binary + Size + sizeof (EFI_COMMON_SECTION_HEADER);
+    if (Size == sizeof (EFI_FFS_FILE_HEADER)) {
+      PreVarStoreHeader     = DataBase + *(UINT16 *)DataBase;
+    PreDataSize           = SectionSize - (*(UINT16 *)DataBase + sizeof(EFI_COMMON_SECTION_HEADER));
+      memcpy (FullBinary, DataBase, SectionSize - sizeof(EFI_COMMON_SECTION_HEADER));
+    FullSectionLen        = CreateStorageSection (FullBinary, *(UINT16 *)DataBase + PreDataSize, SectionName);
+    } else {
+    DeltaVarStoreHeader = (DATA_DELTA *)(DataBase + *(UINT16 *)DataBase);
+    DeltaSize           = *(UINT16 *)DataBase + PreDataSize;
+    DeltaData           = FullBinary + FullSectionSize + *(UINT16 *)DataBase;
+    //
+    // Copy the DefaultId and PlatformId directly
+    //
+      memcpy (FullBinary + FullSectionSize, DataBase, *(UINT16 *)DataBase);
+    //
+    // Copy the default setting data
+    //
+    memcpy (DeltaData, PreVarStoreHeader, PreDataSize);
+    //
+    // Merge the delta data with default setting to get the full delta data
+    //
+    for (Index = 0; Index < (SectionSize - *(UINT16 *)DataBase - sizeof(EFI_COMMON_SECTION_HEADER))/sizeof(DATA_DELTA); Index++) {
+      Offset = (DeltaVarStoreHeader + Index)->Offset;
+      Value  = (DeltaVarStoreHeader + Index)->Value;
+      if (*(DeltaData + Offset) != Value) {
+        *(DeltaData + Offset) = Value;
+      }
+    }
+    FullSectionLen = CreateStorageSection (FullBinary + FullSectionSize, DeltaSize, SectionName);
+    }
+    //
+    // Store the previous binary information
+    //
+    DataBase              = FullBinary + FullSectionSize + sizeof (EFI_COMMON_SECTION_HEADER);
+    PreVarStoreHeader     = DataBase + *(UINT16 *)DataBase;
+
+    Size                 += (SectionSize + 3) & ~3;
+    FullSectionSize      += (FullSectionLen + 3) & ~3;;
+  }
+  //
+  // Update to the new size
+  //
+    BinaryLength = FullSectionSize;
+  Binary       = FullBinary;
+  Size         = 0;
+  }
+
+  //
+  // Read the storage from BFV and insert to storage list
+  //
+  while (Size < BinaryLength) {
+    SectionSize = ReadStorageFromBinary ((Binary + Size), VarListEntry);
+  Size += (SectionSize + 3) & ~3;
+  }
+  if (FullBinary != NULL) {
+    free (FullBinary);
+  }
+
+  return EFI_SUCCESS;
+}
+
+#define SIZE_64K 0x10000
+
+/**
+  Create the storage and insert it to BFV by calling BfmLib.
+
+  @param  InputFdName     The pointer to the input fd name.
+  @param  OutputFdName    The pointer to the input fd name.
+  @param  VarListEntry    The pointer to the variable list.
+
+  @return EFI_INVALID_PARAMETER
+  @return EFI_SUCCESS
+**/
+EFI_STATUS
+InsertBinaryToBfv (
+  IN  CHAR8       *InputFdName,
+  IN  CHAR8       *OutputFdName,
+  IN  LIST_ENTRY  *VarListEntry
+)
+{
+  UINT8             *Binary;
+  UINT8             *PreBinary;
+  UINT32            BinaryLength;
+  UINT32            PreBinaryLength;
+  UINT32            OptimizedBinaryLength;
+  UINT32            Size;
+  UINT32            OptimizedSize;
+  EFI_STATUS        Status;
+  LIST_ENTRY        *StorageLink;
+  FORMSET_STORAGE   *Storage;
+  CHAR8             *SystemCommandFormatString;
+  CHAR8             *SectionNameFormatString;
+  CHAR8             *SystemCommand;
+  CHAR8             *TempSystemCommand;
+  INT32             ReturnValue;
+  CHAR8             *FileName;
+  BOOLEAN           SizeOptimizedFlag;
+  CHAR8             *SectionName[_MAXIMUM_SECTION_FILE_NUM];
+  UINT32            Index;
+  CHAR8             *TemDir;
+  //
+  // Workaround for static code checkers.
+  // Ensures the size of 'IndexStr' can hold all the digits of an unsigned
+  // 32-bit integer.
+  //
+  CHAR8             IndexStr[16];
+
+  BinaryLength              = 0;
+  PreBinaryLength           = 0;
+  Storage                   = NULL;
+  StorageLink               = NULL;
+  Binary                    = NULL;
+  PreBinary                 = NULL;
+  Size                      = 0;
+  OptimizedSize             = 0;
+  Status                    = EFI_SUCCESS;
+  SystemCommandFormatString = NULL;
+  SectionNameFormatString   = NULL;
+  SystemCommand             = NULL;
+  TempSystemCommand         = NULL;
+  SizeOptimizedFlag         = FALSE;
+  Index                     = 0;
+  FileName                  = NULL;
+
+  TemDir = getcwd (NULL, _MAX_PATH);
+  SectionNameFormatString = "%s%cTemp%c%s.sec";
+
+  memset (SectionName, 0, _MAXIMUM_SECTION_FILE_NUM * sizeof(CHAR8 *));
+  FileName = malloc (strlen (TemDir) + 1 + strlen ("Storage.ffs") + 1);
+  if (FileName == NULL) {
+    printf ("Error. Memory allocation failed.\n");
+    Status = EFI_ABORTED;
+    goto Done;
+  }
+  sprintf (FileName, "%s%cStorage.ffs", TemDir, OS_SEP);
+  //
+  // Allocate the buffer which is the same with the input FD
+  //
+  Binary = malloc (SIZE_64K);
+  if (Binary == NULL) {
+    printf ("Error. Memory allocation failed.\n");
+    Status = EFI_ABORTED;
+    goto Done;
+  }
+  PreBinary = malloc (SIZE_64K);
+  if (PreBinary == NULL) {
+    printf ("Error. Memory allocation failed.\n");
+    Status = EFI_ABORTED;
+    goto Done;
+  }
+  //
+  // If already existed a Storage.ffs in FD, keep the same format when execute update operation whatever input -a or not -a options.
+  //
+  if (mMultiPlatformParam.SizeOptimized
+    || (!mMultiPlatformParam.ExistStorageFfsInBfv && mMultiPlatformParam.SizeOptimizedParam)
+    ) {
+    SizeOptimizedFlag = TRUE;
+  } else if (mMultiPlatformParam.ExistStorageFfsInBfv && mMultiPlatformParam.SizeOptimizedParam && !mMultiPlatformParam.SizeOptimized) {
+    printf ("\nWarning. The \"-a\" parameter is ignored.\n");
+  }
+  //
+  // Build the binary for BFV
+  //
+  StorageLink           = GetFirstNode (VarListEntry);
+
+  while (!IsNull (VarListEntry, StorageLink)) {
+    Storage = FORMSET_STORAGE_FROM_LINK (StorageLink);
+    if (!Storage->Skip) {
+    //
+    // Assign the section name under the Temp directory
+    //
+      sprintf (IndexStr, "%d", Index);
+    SectionName[Index] = calloc (
+                      strlen (SectionNameFormatString) + strlen (TemDir) + strlen(IndexStr) + 1,
+                      sizeof(CHAR8)
+                    );
+    if (SectionName[Index] == NULL) {
+        printf ("Error. Memory allocation failed.\n");
+        Status = EFI_ABORTED;
+        goto Done;
+      }
+    sprintf (
+        SectionName[Index],
+        "%s%cTemp%c%s.sec",
+        TemDir,
+        OS_SEP,
+        OS_SEP,
+        IndexStr
+      );
+    memset(Binary, 0, SIZE_64K);
+      Size = PutStorageToBinary (Storage, Binary, VarListEntry);
+      assert (Size < SIZE_64K);
+    //
+    // Re-calculate the storage section by size optimization
+    //
+      if (PreBinaryLength != 0 && SizeOptimizedFlag) {
+    OptimizedSize = OptimizeStorageSection (
+                    PreBinary + sizeof (EFI_COMMON_SECTION_HEADER),
+                          Binary,
+                    PreBinary + PreBinaryLength,
+                    Size
+                  );
+    if (OptimizedSize == 0) {
+        printf ("Error. Failed to optimize the storage section.\n");
+          Status = EFI_ABORTED;
+          goto Done;
+    }
+      }
+    //
+    // Create the raw section with normal format
+    //
+      assert (Size < SIZE_64K - sizeof (EFI_COMMON_SECTION_HEADER));
+    BinaryLength = CreateStorageSection (Binary, Size, SectionName[Index]);
+      if (BinaryLength == 0) {
+      printf ("Error. Failed to create the storage section.\n");
+        Status = EFI_ABORTED;
+        goto Done;
+      }
+      assert (BinaryLength < SIZE_64K);
+
+    //
+    // Create the raw section with optimized format
+    //
+      if (PreBinaryLength != 0 && SizeOptimizedFlag) {
+      OptimizedBinaryLength = CreateStorageSection (PreBinary + PreBinaryLength, OptimizedSize, SectionName[Index]);
+        if (OptimizedBinaryLength == 0) {
+        printf ("Error. Failed to create the storage section.\n");
+          Status = EFI_ABORTED;
+          goto Done;
+        }
+      }
+      PreBinaryLength = BinaryLength;
+    memcpy (PreBinary, Binary, PreBinaryLength);
+    Index++;
+    }
+    StorageLink = GetNextNode (VarListEntry, StorageLink);
+  }
+  //
+  // Create the raw ffs by GenFfs
+  //
+  CreateRawFfs (&SectionName[0], FileName, SizeOptimizedFlag);
+
+  //
+  // Call BfmLib to insert this binary into the BFV of FD.
+  //
+  //
+  // Construction 'system' command string
+  //
+  if (mMultiPlatformParam.ExistStorageFfsInBfv) {
+    if (mFvNameGuidString != NULL) {
+      SystemCommandFormatString = "BfmLib -r \"%s\" \"%s\" \"%s\" -g %s";
+      SystemCommand = malloc (
+                      strlen (SystemCommandFormatString) + strlen (mInputFdName) + strlen (mOutputFdName) + strlen (FileName) + strlen (mFvNameGuidString) + 1
+                    );
+      if (SystemCommand == NULL) {
+        Status = EFI_ABORTED;
+        goto Done;
+      }
+      sprintf (
+        SystemCommand,
+        "BfmLib -r \"%s\" \"%s\" \"%s\" -g %s",
+        mInputFdName,
+        FileName,
+        mOutputFdName,
+        mFvNameGuidString
+        );
+    } else {
+      SystemCommandFormatString = "BfmLib -r \"%s\" \"%s\" \"%s\"";
+      SystemCommand = malloc (
+                      strlen (SystemCommandFormatString) + strlen (mInputFdName) + strlen (mOutputFdName) + strlen (FileName) + 1
+                    );
+      if (SystemCommand == NULL) {
+        Status = EFI_ABORTED;
+        goto Done;
+      }
+      sprintf (
+        SystemCommand,
+        "BfmLib -r \"%s\" \"%s\" \"%s\"",
+        mInputFdName,
+        FileName,
+        mOutputFdName
+        );
+    }
+  } else {
+    if (mFvNameGuidString != NULL) {
+      SystemCommandFormatString = "BfmLib -i \"%s\" \"%s\" \"%s\" -g %s";
+      SystemCommand = malloc (
+                      strlen (SystemCommandFormatString) + strlen (mInputFdName) + strlen (mOutputFdName) + strlen (FileName) + strlen (mFvNameGuidString) + 1
+                    );
+      if (SystemCommand == NULL) {
+        Status = EFI_ABORTED;
+        goto Done;
+      }
+      sprintf (
+        SystemCommand,
+        "BfmLib -i \"%s\" \"%s\" \"%s\" -g %s",
+        mInputFdName,
+        FileName,
+        mOutputFdName,
+        mFvNameGuidString
+        );
+    } else {
+      SystemCommandFormatString = "BfmLib -i \"%s\" \"%s\" \"%s\"";
+      SystemCommand = malloc (
+                      strlen (SystemCommandFormatString) + strlen (mInputFdName) + strlen (mOutputFdName) + strlen (FileName) + 1
+                    );
+      if (SystemCommand == NULL) {
+        Status = EFI_ABORTED;
+        goto Done;
+      }
+      sprintf (
+        SystemCommand,
+        "BfmLib -i \"%s\" \"%s\" \"%s\"",
+        mInputFdName,
+        FileName,
+        mOutputFdName
+        );
+    }
+  }
+
+  if (mFullGuidToolDefinitionDir[0] != 0) {
+    TempSystemCommand = SystemCommand;
+    SystemCommand = malloc (
+                    strlen (mFullGuidToolDefinitionDir) + strlen ("\\") + strlen (TempSystemCommand ) + 1
+                  );
+
+    if (SystemCommand == NULL) {
+      free (TempSystemCommand);
+      goto Done;
+    }
+    strcpy (SystemCommand, mFullGuidToolDefinitionDir);
+    strcat (SystemCommand, OS_SEP_STR);
+    strcat (SystemCommand, TempSystemCommand);
+    free (TempSystemCommand);
+  }
+
+  ReturnValue = system (SystemCommand);
+  free (SystemCommand);
+  remove (FileName);
+  if (ReturnValue == -1) {
+    Status = EFI_ABORTED;
+  }
+Done:
+  for (Index = 0; SectionName[Index] != NULL; Index++) {
+    free (SectionName[Index]);
+  }
+  if (PreBinary != NULL) {
+    free (PreBinary);
+  }
+  if (Binary) {
+    free (Binary);
+  }
+  return Status;
+}
+
+/**
+  Create the storage and insert it to NvStoreDatabase.
+
+  @param  InputFdName     The pointer to the input fd name.
+  @param  OutputFdName    The pointer to the input fd name.
+  @param  VarListEntry    The pointer to the variable list.
+
+  @return EFI_INVALID_PARAMETER
+  @return EFI_SUCCESS
+**/
+EFI_STATUS
+InsertBinaryToNvStoreDatabase (
+  IN  CHAR8       *InputFdName,
+  IN  CHAR8       *OutputFdName,
+  IN  LIST_ENTRY  *VarListEntry
+)
+{
+  UINT8             *Binary;
+  UINT8             *PreBinary;
+  UINT8             *NvStoreDatabaseBuffer;
+  UINT32            PreBinaryLength;
+  UINT32            Size;
+  UINT32            NvStoreDatabaseSize;
+  UINT32            OptimizedSize;
+  EFI_STATUS        Status;
+  LIST_ENTRY        *StorageLink;
+  FORMSET_STORAGE   *Storage;
+  BOOLEAN           SizeOptimizedFlag;
+  PCD_NV_STORE_DEFAULT_BUFFER_HEADER  *NvStoreBufferHeader;
+  PCD_DEFAULT_DATA  *PcdDefaultData;
+
+  //
+  // Workaround for static code checkers.
+  // Ensures the size of 'IndexStr' can hold all the digits of an unsigned
+  // 32-bit integer.
+  //
+
+  PreBinaryLength           = 0;
+  Storage                   = NULL;
+  StorageLink               = NULL;
+  Binary                    = NULL;
+  PreBinary                 = NULL;
+  NvStoreDatabaseBuffer     = NULL;
+  PcdDefaultData            = NULL;
+  Size                      = 0;
+  NvStoreDatabaseSize       = 0;
+  OptimizedSize             = 0;
+  Status                    = EFI_SUCCESS;
+  SizeOptimizedFlag         = FALSE;
+
+  //
+  // Allocate the buffer which is the same with the input FD
+  //
+
+  Binary = malloc (SIZE_64K);
+  if (Binary == NULL) {
+    printf ("Error. Memory allocation failed.\n");
+    Status = EFI_ABORTED;
+    goto Done;
+  }
+  NvStoreBufferHeader = (PCD_NV_STORE_DEFAULT_BUFFER_HEADER *) gEfiFdInfo.NvStoreDatabase;
+  NvStoreDatabaseBuffer = malloc (NvStoreBufferHeader->MaxLength);
+  if (NvStoreDatabaseBuffer == NULL) {
+    printf ("Error. Memory allocation failed.\n");
+    Status = EFI_ABORTED;
+    goto Done;
+  }
+  memcpy(NvStoreDatabaseBuffer, gEfiFdInfo.NvStoreDatabase, NvStoreBufferHeader->MaxLength);
+  PreBinary = malloc (SIZE_64K);
+  if (PreBinary == NULL) {
+    printf ("Error. Memory allocation failed.\n");
+    Status = EFI_ABORTED;
+    goto Done;
+  }
+
+  if (gEfiFdInfo.ExistNvStoreDatabase) {
+    SizeOptimizedFlag = TRUE;
+  } else {
+    Status = EFI_ABORTED;
+    goto Done;
+  }
+  //
+  // Build the binary for BFV
+  //
+  StorageLink           = GetFirstNode (VarListEntry);
+  while (!IsNull (VarListEntry, StorageLink)) {
+    Storage = FORMSET_STORAGE_FROM_LINK (StorageLink);
+    if (!Storage->Skip) {
+      memset(Binary, 0, SIZE_64K);
+      Size = PutStorageToNvStoreBinary (Storage, Binary, VarListEntry);
+      assert (Size < SIZE_64K);
+      //
+      // Re-calculate the storage section by size optimization
+      //
+      if (PreBinaryLength != 0 && SizeOptimizedFlag) {
+         OptimizedSize = OptimizeStorageDeltaData (
+                  PreBinary,
+                  Binary,
+                  NvStoreDatabaseBuffer + NvStoreDatabaseSize,
+                  Size
+                  );
+         if (OptimizedSize == 0) {
+           printf ("Error. Failed to optimize the storage section.\n");
+           Status = EFI_ABORTED;
+           goto Done;
+         }
+         //Alignment
+         OptimizedSize = (OptimizedSize + 7) & ~7;
+         NvStoreDatabaseSize += OptimizedSize;
+      } else {
+        //Alignment
+        Size = (Size + 7) & ~7;
+        PcdDefaultData = (PCD_DEFAULT_DATA *)Binary;
+        memcpy(NvStoreDatabaseBuffer + sizeof(PCD_NV_STORE_DEFAULT_BUFFER_HEADER), Binary, Size + PcdDefaultData->HeaderSize + 4 );
+        PreBinaryLength = Size  + PcdDefaultData->HeaderSize + 4;
+        NvStoreDatabaseSize = sizeof(PCD_NV_STORE_DEFAULT_BUFFER_HEADER) + PreBinaryLength;
+        memcpy(PreBinary, Binary, PreBinaryLength);
+      }
+    }
+    StorageLink = GetNextNode (VarListEntry, StorageLink);
+  }
+  if (NvStoreBufferHeader->Length != NvStoreDatabaseSize) {
+    ((PCD_NV_STORE_DEFAULT_BUFFER_HEADER *)NvStoreDatabaseBuffer)->Length = NvStoreDatabaseSize;
+    }
+  memcpy(gEfiFdInfo.NvStoreDatabase, NvStoreDatabaseBuffer, NvStoreDatabaseSize);
+
+Done:
+  DestroyAllStorage (&mAllVarListEntry);
+  if (PreBinary != NULL) {
+    free (PreBinary);
+  }
+  if (Binary) {
+    free (Binary);
+  }
+  return Status;
+}
+
+extern UINT32 mMaxCount;
+extern UINT32 mCount;
+extern CHAR8  *mStringBuffer;
+
+/**
+  Read the HII configure file from all FFS
+
+  @retval EFI_SUCCESS       It was complete successfully
+  @return EFI_ABORTED       An error occurred
+**/
+static
+EFI_STATUS
+ReadCongFile (
+  VOID
+  )
+{
+  EFI_STATUS     Status;
+  UINT32         Index;
+  UINT16         DefaultIndex;
+  UINT16         PlatformIndex;
+  UINT16         PreDefaultId;
+  UINT64         PrePlatformId;
+  LIST_ENTRY     NewStorageListHead;
+  BOOLEAN        BfvOverried;
+  FORMSET_STORAGE *Storage;
+  LIST_ENTRY      *StorageLink;
+
+  Storage        = NULL;
+  Status         = EFI_SUCCESS;
+  BfvOverried    = FALSE;
+  Index          = 0;
+  PreDefaultId   = 0xFFFF;
+  PrePlatformId  = 0xFFFFFFFFFFFFFFFF;
+  //
+  // Read all Ifr information to Formset list
+  //
+  for (Index = 0; (gEfiFdInfo.FfsArray[Index] != NULL) && (gEfiFdInfo.Length[Index] != 0); Index++) {
+    Status = ReadAllIfrToFromset (
+               gEfiFdInfo.FfsArray[Index],
+               gEfiFdInfo.Length[Index]
+               );
+    if (EFI_ERROR (Status)) {
+      return EFI_ABORTED;
+    }
+  }
+  //
+  // Read defaultId and platformId
+  //
+  if (!gEfiFdInfo.ExistNvStoreDatabase) {
+    Status = ReadDefaultAndPlatformId (&mFormSetListEntry);
+    if (EFI_ERROR (Status)) {
+      return EFI_ABORTED;
+    }
+  }
+  //
+  // If existed the variable data in BFV, abstract them to a variable list.
+  // If not exsited, just skip it.
+  //
+  if (mMultiPlatformParam.MultiPlatformOrNot) {
+    if (gEfiFdInfo.ExistNvStoreDatabase) {
+      Status = ReadStorageFromNvStoreDatabase(&mBfvVarListEntry);
+    } else {
+      Status = ReadStorageFromBfv (&mBfvVarListEntry);
+    }
+    if (!EFI_ERROR (Status)) {
+      BfvOverried = TRUE;
+    }
+  }
+    //
+    // If not existed the storage data in BFV, evaluate the
+    // default value according to the defaultId and platformId
+    // Or else, skip it.
+    //
+  if (!BfvOverried) {
+    Status = EvaluateTheValueInFormset (FALSE);
+    if (EFI_ERROR (Status)) {
+      return EFI_ABORTED;
+    }
+  }
+
+  //
+  // Output the question and value information on screen
+  //
+  if (mMultiPlatformParam.MultiPlatformOrNot) {
+    //
+    // Multi-platform mode support
+    //
+    if (gEfiFdInfo.ExistNvStoreDatabase) {
+      StorageLink = GetFirstNode (&mBfvVarListEntry);
+      while (!IsNull (&mBfvVarListEntry, StorageLink)) {
+        Storage = FORMSET_STORAGE_FROM_LINK (StorageLink);
+        if (PreDefaultId == Storage->DefaultId[0] && PrePlatformId == Storage->PlatformId[0]) {
+          StorageLink = GetNextNode (&mBfvVarListEntry, StorageLink);
+          continue;
+        } else {
+          PreDefaultId = Storage->DefaultId[0];
+          PrePlatformId = Storage->PlatformId[0];
+        }
+        InitializeListHead(&NewStorageListHead);
+        //
+        // Use the varaible stroage list from BFV
+        //
+        Status = BuildVariableList(
+                       &NewStorageListHead,
+                       &mBfvVarListEntry,
+                       Storage->DefaultId[0],
+                       Storage->PlatformId[0],
+                       FALSE,
+                       READ
+                     );
+
+        if (EFI_ERROR (Status)) {
+          DestroyAllStorage (&NewStorageListHead);
+          return EFI_ABORTED;
+        }
+        if (IsListEmpty (&NewStorageListHead)) {
+          continue;
+        }
+        Status = PrintInfoInAllFormset (&mFormSetListEntry, &NewStorageListHead);
+        if (EFI_ERROR (Status)) {
+          DestroyAllStorage (&NewStorageListHead);
+          return EFI_ABORTED;
+        }
+        DestroyAllStorage (&NewStorageListHead);
+        StorageLink = GetNextNode (&mBfvVarListEntry, StorageLink);
+      }
+    } else {
+      for (DefaultIndex = 0; DefaultIndex < mMultiPlatformParam.DefaultIdNum; DefaultIndex++) {
+        for (PlatformIndex = 0; PlatformIndex < mMultiPlatformParam.PlatformIdNum; PlatformIndex++) {
+          InitializeListHead(&NewStorageListHead);
+          if (BfvOverried) {
+            //
+            // Use the varaible stroage list from BFV
+            //
+            Status = BuildVariableList(
+                       &NewStorageListHead,
+                       &mBfvVarListEntry,
+                       mMultiPlatformParam.DefaultId[DefaultIndex],
+                       mMultiPlatformParam.PlatformId[PlatformIndex],
+                       FALSE,
+                       READ
+                     );
+           } else {
+             //
+             // Use the varaible storage list from IFR
+             //
+             Status = BuildVariableList(
+                       &NewStorageListHead,
+                       &mAllVarListEntry,
+                       mMultiPlatformParam.DefaultId[DefaultIndex],
+                       mMultiPlatformParam.PlatformId[PlatformIndex],
+                       FALSE,
+                       READ
+                     );
+           }
+          if (EFI_ERROR (Status)) {
+            DestroyAllStorage (&NewStorageListHead);
+            return EFI_ABORTED;
+          }
+          if (IsListEmpty (&NewStorageListHead)) {
+            continue;
+          }
+          Status = PrintInfoInAllFormset (&mFormSetListEntry, &NewStorageListHead);
+          if (EFI_ERROR (Status)) {
+            DestroyAllStorage (&NewStorageListHead);
+            return EFI_ABORTED;
+          }
+          DestroyAllStorage (&NewStorageListHead);
+        }
+      }
+    }
+  } else {
+    Status = PrintInfoInAllFormset (&mFormSetListEntry, &mAllVarListEntry);
+    if (EFI_ERROR (Status)) {
+      return EFI_ABORTED;
+    }
+  }
+
+  return Status;
+}
+
+/**
+  Update the HII setup value.
+
+  Read the Config information from config file, and then compare it with the current FFS.
+  Record the different value to EFI variable.
+
+  @param Fv             the Pointer to the FFS
+  @param Length         the length of FFS
+
+  @retval EFI_SUCCESS       It was complete successfully
+  @return EFI_ABORTED       An error occurred
+**/
+static
+EFI_STATUS
+UpdateCongFile (
+  VOID
+  )
+{
+  EFI_STATUS     Status;
+  UINT32         Index;
+  BOOLEAN        BfvOverried;
+
+  Status         = EFI_SUCCESS;
+  BfvOverried    = FALSE;
+  Index          = 0;
+  //
+  // Read all Ifr information to Formset list
+  //
+  for (Index = 0; (gEfiFdInfo.FfsArray[Index] != NULL) && (gEfiFdInfo.Length[Index] != 0); Index++) {
+    Status = ReadAllIfrToFromset (
+               gEfiFdInfo.FfsArray[Index],
+               gEfiFdInfo.Length[Index]
+               );
+    if (EFI_ERROR (Status)) {
+      return EFI_ABORTED;
+    }
+  }
+  //
+  // Read defaultId and platformId
+  //
+  if (!gEfiFdInfo.ExistNvStoreDatabase) {
+    Status = ReadDefaultAndPlatformId (&mFormSetListEntry);
+    if (EFI_ERROR (Status)) {
+      return EFI_ABORTED;
+    }
+  }
+  //
+  // If existed the variable data in BFV, abstract them to a variable list.
+  // If not exsited, just skip it.
+  //
+  if (mMultiPlatformParam.MultiPlatformOrNot) {
+    if (gEfiFdInfo.ExistNvStoreDatabase) {
+      Status = ReadStorageFromNvStoreDatabase (&mBfvVarListEntry);
+    } else {
+      Status = ReadStorageFromBfv (&mBfvVarListEntry);
+    }
+    if (!EFI_ERROR (Status)) {
+      BfvOverried = TRUE;
+    }
+  }
+  if (mMultiPlatformParam.MultiPlatformOrNot && BfvOverried) {
+    if (mUqiList == NULL) {
+      return EFI_SUCCESS;
+    }
+    Status = CheckValueUpdateList ();
+    if (EFI_ERROR (Status)) {
+      return EFI_ABORTED;
+    }
+  } else {
+    //
+    // Evaluate the default value according to the defaultId and platformId
+    //
+    if (mUqiList == NULL) {
+      Status = EvaluateTheValueInFormset (FALSE);
+    } else {
+      Status = EvaluateTheValueInFormset (TRUE);
+    }
+    if (EFI_ERROR (Status)) {
+      return EFI_ABORTED;
+    }
+  }
+  //
+  // print error information in UQI list
+  //
+  if (PrintErrorInfo (mUqiList)) {
+    return EFI_ABORTED;
+  }
+  //
+  // Output the variable information to BFV in multi-platform mode
+  // Or write it to the Nvstrage in general mode
+  //
+  if (mMultiPlatformParam.MultiPlatformOrNot) {
+    if (ExistEfiVarOrNot (&mAllVarListEntry) && Operations == UPDATE) {
+      printf ("Error. Please use --remove or --ignore to update the variable storage for an FD with variables in its NvStorage.\n");
+      return EFI_ABORTED;
+    }
+  } else {
+    //
+    // Sync the data from List data to efi variable.
+    //
+    Status = EfiVarAndListExchange (FALSE, &mAllVarListEntry);
+    if (Status == EFI_OUT_OF_RESOURCES) {
+      printf ("Error. There is no available space in efi variable. \n");
+      return EFI_ABORTED;
+    }
+    if (Status == EFI_INVALID_PARAMETER) {
+      return EFI_ABORTED;
+    }
+  }
+
+  PrintUpdateListInfo (mUqiList);
+
+  return Status;
+}
+
+/**
+  Quick Update the HII setup value.
+
+  Read the Config information from command line directly, and then compare it with the current FFS.
+  Record the different value to EFI variable.
+
+  @retval EFI_SUCCESS   It was complete successfully
+  @return EFI_ABORTED   An error occurred
+**/
+
+EFI_STATUS
+QuickUpdateCongFile (
+  VOID
+  )
+{
+  EFI_STATUS     Status;
+  UINT32         Index;
+
+  Status         = EFI_SUCCESS;
+  Index          = 0;
+
+  if (mMultiPlatformParam.MultiPlatformOrNot) {
+    printf ("Error. The quick update operation is not supported in multi-platform mode.\n");
+    return EFI_ABORTED;
+  }
+  //
+  // Check whether the FD has included the storage FFS
+  //
+  if (mMultiPlatformParam.ExistStorageFfsInBfv) {
+    printf ("Error. Variable storage exists in BFV of Fd. This is generated in multi-platform mode.\n");
+    printf ("Error. The quick update operation is not supported in multi-platform mode.\n");
+    return EFI_ABORTED;
+  }
+  //
+  // Read all Ifr information to Formset list
+  //
+  for (Index = 0; (gEfiFdInfo.FfsArray[Index] != NULL) && (gEfiFdInfo.Length[Index] != 0); Index++) {
+    Status = ReadAllIfrToFromset (
+               gEfiFdInfo.FfsArray[Index],
+               gEfiFdInfo.Length[Index]
+               );
+    if (EFI_ERROR (Status)) {
+      return EFI_ABORTED;
+    }
+  }
+  //
+  // Evaluate the default value according to the defaultId and platformId
+  //
+  Status = EvaluateTheValueInFormset (TRUE);
+  if (EFI_ERROR (Status)) {
+    return EFI_ABORTED;
+  }
+  //
+  // print error information in UQI list
+  //
+  if (PrintErrorInfo (mUqiList)) {
+    return EFI_ABORTED;
+  }
+  //
+  // Sync the data from mAllVarListEntry data to efi variable.
+  //
+  Status = EfiVarAndListExchange (FALSE, &mAllVarListEntry);
+  if (Status == EFI_OUT_OF_RESOURCES) {
+    printf ("Error. There is no available space in Nvstorage. \n");
+    return EFI_ABORTED;
+  }
+  if (Status == EFI_INVALID_PARAMETER) {
+    return EFI_ABORTED;
+  }
+
+  PrintUpdateListInfo (mUqiList);
+
+  return Status;
+}
+
+/**
+  Check the HII setup value.
+
+  Read the Config information from config file, and then compare it with the current FFS.
+  Print the different values on screen.
+
+  @retval EFI_SUCCESS       It was complete successfully
+  @return EFI_ABORTED       An error occurred
+**/
+static
+EFI_STATUS
+CheckCongFile (
+  VOID
+  )
+{
+  EFI_STATUS     Status;
+  UINT32         Index;
+  UINT16         DefaultIndex;
+  UINT16         PlatformIndex;
+  UINT16         DefaultId;
+  UINT64         PlatformId;
+
+  Status         = EFI_SUCCESS;
+  Index          = 0;
+  DefaultIndex   = 0;
+  PlatformIndex  = 0;
+  DefaultId      = 0;
+  PlatformId     = 0;
+  //
+  // Read all Ifr information to Formset list
+  //
+  for (Index = 0; (gEfiFdInfo.FfsArray[Index] != NULL) && (gEfiFdInfo.Length[Index] != 0); Index++) {
+    Status = ReadAllIfrToFromset (
+               gEfiFdInfo.FfsArray[Index],
+               gEfiFdInfo.Length[Index]
+               );
+    if (EFI_ERROR (Status)) {
+      return EFI_ABORTED;
+    }
+  }
+  //
+  // Read defaultId and platformId
+  //
+  Status = ReadDefaultAndPlatformId (&mFormSetListEntry);
+  if (EFI_ERROR (Status)) {
+    return EFI_ABORTED;
+  }
+  //
+  // Read the config data from BFV in multi-platform mode
+  //
+  if (mMultiPlatformParam.MultiPlatformOrNot) {
+    Status = ReadStorageFromBfv (&mAllVarListEntry);
+    if (EFI_ERROR (Status)) {
+      printf ("Error. No storage variable data exists in BFV.\n");
+      return EFI_ABORTED;
+    }
+  }
+
+  if (mMultiPlatformParam.MultiPlatformOrNot) {
+    ScanUqiFullList (mUqiList);
+
+    //
+    // Multi-platform mode support
+    //
+    for (DefaultIndex = 0; DefaultIndex < mMultiPlatformParam.DefaultIdNum; DefaultIndex++) {
+      for (PlatformIndex = 0; PlatformIndex < mMultiPlatformParam.PlatformIdNum; PlatformIndex++) {
+        DefaultId  = mMultiPlatformParam.DefaultId[DefaultIndex];
+        PlatformId = mMultiPlatformParam.PlatformId[PlatformIndex];
+        //
+        //Only parse one time, if a group of defaultId and platformId which have the same variable
+        // Take the first one as a key Id of a group
+        //
+        if (NoTheKeyIdOfGroup (DefaultId, PlatformId)) {
+          continue;
+        }
+
+        InitializeListHead(&mVarListEntry);
+        Status = BuildVariableList(
+                   &mVarListEntry,
+                   &mAllVarListEntry,
+                   DefaultId,
+                   PlatformId,
+                   FALSE,
+                   VERIFY
+                   );
+        if (EFI_ERROR (Status)) {
+          return EFI_ABORTED;
+        }
+        if (IsListEmpty (&mVarListEntry)) {
+          continue;
+        }
+        SetUqiParametersMultiMode (mUqiList, DefaultId, PlatformId);
+        DestroyAllStorage (&mVarListEntry);
+      }
+    }
+  } else {
+    //
+    // General mode
+    //
+    Status = ExtractDefault (
+               NULL,
+               NULL,
+               0,
+               0,
+               SystemLevel
+             );
+    if (EFI_ERROR (Status)) {
+      return EFI_ABORTED;
+    }
+    //
+    // If existed the variable in NvStorage, copy them to mVarListEntry.
+    // Synchronize the default value from the EFI variable zone to variable list
+    //
+    Status = EfiVarAndListExchange (TRUE, &mVarListEntry);
+    if (Status == EFI_INVALID_PARAMETER) {
+      Status = EFI_ABORTED;
+      return Status;
+    }
+    //
+    // Update the value from script file
+    //
+    Status = SetUqiParameters (mUqiList,0, 0);
+    if (EFI_ERROR (Status)) {
+      return EFI_ABORTED;
+    }
+    //
+    // Copy Stroage from mVarListEntry to mAllVarListEntry
+    //
+    Status = BuildVariableList (&mAllVarListEntry, &mVarListEntry, 0, 0, TRUE, VERIFY);
+    if (EFI_ERROR (Status)) {
+      return EFI_ABORTED;
+    }
+  }
+  PrintVerifiedListInfo (mUqiList);
+  return Status;
+}
+
+/**
+  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;
+}
+
+/**
+  FCE application entry point
+
+  @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.
+  @retval  2       An error about check occurred.
+
+**/
+int
+main (
+  int       argc,
+  char      *argv[]
+  )
+{
+  EFI_STATUS        Status;
+  FILE              *OutputFd;
+  FILE              *ScriptFile;
+  UINTN             BytesWrite;
+  UINTN             Index;
+  CHAR8             *TemDir;
+  BOOLEAN           IsFileExist;
+  CHAR8             FullGuidToolDefinition[_MAX_PATH];
+  CHAR8             *PathList;
+  UINTN             EnvLen;
+  CHAR8             *NewPathList;
+  UINTN             FileNameIndex;
+  CHAR8             *InFilePath;
+  BOOLEAN           UqiIsSet;
+
+  Status             = EFI_SUCCESS;
+  OutputFd           = NULL;
+  ScriptFile         = NULL;
+  Operations         = NONE;
+  BytesWrite         = 0;
+  Index              = 0;
+  TemDir             = NULL;
+  mFormSetOrderRead  = 0;
+  mFormSetOrderParse = 0;
+  IsFileExist        = TRUE;
+  PathList           = NULL;
+  NewPathList        = NULL;
+  EnvLen             = 0;
+  UqiIsSet           = FALSE;
+
+  TemDir = getcwd (NULL, _MAX_PATH);
+  if (strlen (TemDir) + strlen (OS_SEP_STR) + strlen (TEMP_DIR_NAME) > _MAX_PATH - 1) {
+    printf ("The directory is too long \n");
+    return FAIL;
+  }
+  strncat (TemDir, OS_SEP_STR, _MAX_PATH - strlen (TemDir) - 1);
+  strncat (TemDir, TEMP_DIR_NAME, _MAX_PATH - strlen (TemDir) - 1);
+  memset (&mMultiPlatformParam, 0, sizeof (MULTI_PLATFORM_PARAMETERS));
+
+  SetUtilityName (UTILITY_NAME);
+  //
+  // 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, and then skip filename arg
+  //
+  mUtilityFilename = argv[0];
+  argc--;
+  argv++;
+  //
+  // Get the same path with the application itself
+  //
+  if (strlen (mUtilityFilename) > _MAX_PATH - 1) {
+    Error (NULL, 0, 2000, "Parameter: The input file name is too long", NULL);
+    return FAIL;
+  }
+  strncpy (FullGuidToolDefinition, mUtilityFilename, _MAX_PATH - 1);
+  FullGuidToolDefinition[_MAX_PATH - 1] = 0;
+  FileNameIndex = strlen (FullGuidToolDefinition);
+  while (FileNameIndex != 0) {
+    FileNameIndex --;
+    if (FullGuidToolDefinition[FileNameIndex] == OS_SEP) {
+    FullGuidToolDefinition[FileNameIndex] = 0;
+      strcpy (mFullGuidToolDefinitionDir, FullGuidToolDefinition);
+      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 FAIL;
+  }
+  EnvLen = strlen(PathList);
+  NewPathList  = (char *)calloc(
+                     strlen (".")
+                     + strlen (";")
+                     + strlen (mFullGuidToolDefinitionDir)
+                     + 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", ".", mFullGuidToolDefinitionDir, PathList);
+#else
+  sprintf (NewPathList, "%s:%s:%s", ".", mFullGuidToolDefinitionDir, 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 = PreDefinedGuidedTools ();
+  }
+  //
+  // Parse the command line
+  //
+  strcpy (mSetupTxtName, "NoSetupFile");
+  Status = ParseCommmadLine (argc,argv);
+  if (EFI_ERROR (Status)) {
+    return FAIL;
+  }
+  //
+  // Print utility header
+  //
+  printf ("\nIntel(R) Firmware Configuration Editor. (Intel(R) %s) Version %d.%d. %s.\n\n",
+    UTILITY_NAME,
+    UTILITY_MAJOR_VERSION,
+    UTILITY_MINOR_VERSION,
+    __BUILD_VERSION
+    );
+  //
+  // Check the revision of BfmLib
+  //
+  Status = CheckBfmLibRevision ();
+  if (EFI_ERROR (Status)) {
+    printf ("Please use the correct revision of BfmLib %s. \n", __BUILD_VERSION);
+    return FAIL;
+  }
+  if (strcmp (mSetupTxtName, "NoSetupFile")) {
+    ScriptFile = fopen (mSetupTxtName, "r");
+    if (ScriptFile == NULL) {
+      printf ("Error. Cannot open the script file.\n");
+      return FAIL;
+    }
+    Status = PickUpUqiFromScript (ScriptFile);
+    if (EFI_ERROR (Status)) {
+      fclose (ScriptFile);
+      IsFileExist = FALSE;
+      goto Done;
+    }
+    fclose (ScriptFile);
+  }
+  if (!mMultiPlatformParam.MultiPlatformOrNot
+    && (Operations == UPDATE_REMOVE || Operations == UPDATE_IGNORE)
+    ) {
+    printf ("Error. --remove and --ignore cannot be used in normal mode.\n");
+    Status      = FAIL;
+    goto Done;
+  }
+
+   if (access (TemDir, 0) != -1) {
+    LibRmDir (TemDir);
+   }
+
+  //
+  // Initialize the variables
+  //
+  Status = PickUpFfsFromFd ();
+  if (EFI_ERROR (Status)) {
+    printf ("Error. Invalid FD file.\n");
+    IsFileExist = FALSE;
+    Status      = FAIL;
+    goto Done;
+  }
+  if (gEfiFdInfo.FfsArray[0] == NULL) {
+    printf ("Error. Cannot find any HII offset in current FD files, please check the BaseTools.\n");
+    Status  = FAIL;
+    goto Done;
+  }
+  //
+  //Config the global variables
+  //
+  if (mMultiPlatformParam.Uqi.Data != NULL) {
+    UqiIsSet = TRUE;
+  }
+  Status = GetEfiVariablesAddr (UqiIsSet);
+  if (EFI_ERROR (Status)) {
+    printf ("Error. Cannot locate the EFI variable zone in FD.\n");
+    Status = FAIL;
+    goto Done;
+  }
+  if (gEfiFdInfo.ExistNvStoreDatabase && !mMultiPlatformParam.MultiPlatformOrNot) {
+    mMultiPlatformParam.MultiPlatformOrNot = TRUE;
+  }
+  //
+  // Initialize the FormSet and VarList List
+  //
+  InitializeListHead (&mFormSetListEntry);
+  InitializeListHead (&mVarListEntry);
+  InitializeListHead (&mBfvVarListEntry);
+  InitializeListHead (&mAllVarListEntry);
+
+  mStringBuffer = malloc (mMaxCount);
+  if (mStringBuffer == NULL) {
+    printf ("Fali to allocate memory!\n");
+    Status = FAIL;
+    goto Done;
+  }
+
+  //
+  // Decide how to deal with the Fd
+  //
+  switch (Operations) {
+
+  case READ:
+    printf ("\nStart the Read Mode:\n");
+    Status = ReadCongFile ();
+    if (EFI_ERROR (Status)) {
+      Status = FAIL;
+    }
+    break;
+
+  case UPDATE:
+  case UPDATE_REMOVE:
+  case UPDATE_IGNORE:
+    printf ("\nStart the Update Mode:\n");
+    Status = UpdateCongFile ();
+    if (EFI_ERROR (Status)) {
+      Status = FAIL;
+    }
+    break;
+
+  case VERIFY:
+    printf ("\nStart the Verify Mode:\n");
+    Status = CheckCongFile ();
+    if (EFI_ERROR (Status)) {
+      Status = VR_FAIL;
+    }
+    break;
+
+  case UPDATEQ:
+    printf ("\nStart the Update Quick Mode:\n");
+    Status = QuickUpdateCongFile ();
+    if (EFI_ERROR (Status)) {
+      Status = FAIL;
+    }
+    break;
+
+  default:
+    break;
+  }
+
+  if (mCount > 0) {
+    mStringBuffer[mCount] = '\0';
+    fwrite (mStringBuffer, sizeof (CHAR8), mCount, stdout);
+  }
+  free (mStringBuffer);
+
+  if (Status != SUCCESS) {
+    goto Done;
+  }
+  //
+  // If multi-platform mode, insert the variables to BFV
+  //
+  if (mMultiPlatformParam.MultiPlatformOrNot
+    && (IsListEmpty (&mAllVarListEntry) == FALSE)
+    &&((Operations == UPDATE) || (Operations == UPDATE_REMOVE) || (Operations == UPDATE_IGNORE) || (Operations == UPDATEQ))
+    ) {
+    IsFileExist = FALSE;
+    if (gEfiFdInfo.ExistNvStoreDatabase) {
+      Status = InsertBinaryToNvStoreDatabase (mInputFdName, mOutputFdName, &mAllVarListEntry);
+    } else {
+      Status = InsertBinaryToBfv (mInputFdName, mOutputFdName, &mAllVarListEntry);
+    }
+    if (EFI_ERROR (Status)) {
+      goto Done;
+    }
+    //
+    // Remove the variables in NvStorage in multi-platform mode by user specified requirement
+    //
+    if (Operations == UPDATE_REMOVE) {
+      if (gEfiFdInfo.Fd != NULL) {
+        free (gEfiFdInfo.Fd);
+      }
+      gEfiFdInfo.Fd = ReadFileToMemory (mOutputFdName, &gEfiFdInfo.FdSize);
+      if (gEfiFdInfo.Fd == NULL) {
+        Status = EFI_ABORTED;
+      } else {
+        Status = RemoveEfiVar (&mAllVarListEntry);
+      }
+      if (EFI_ERROR (Status)) {
+        printf ("Error. Failed to remove the variable from NVRAM.\n");
+        Status = FAIL;
+        goto Done;
+      }
+    }
+  }
+
+  if (
+  (!mMultiPlatformParam.MultiPlatformOrNot &&((Operations == UPDATE) || (Operations == UPDATEQ)))
+  || (mMultiPlatformParam.MultiPlatformOrNot && (Operations == UPDATE_REMOVE || ((Operations == UPDATE) && IsListEmpty (&mAllVarListEntry))))
+    ) {
+    OutputFd = fopen (mOutputFdName, "wb+");
+    if (OutputFd == NULL) {
+      printf ("Error. Failed to create the output FD file.\n");
+      Status = FAIL;
+      goto Done;
+    }
+    fseek (OutputFd, 0, SEEK_SET);
+    BytesWrite = fwrite (gEfiFdInfo.Fd, sizeof (CHAR8), gEfiFdInfo.FdSize, OutputFd);
+    fclose (OutputFd);
+    if (BytesWrite != gEfiFdInfo.FdSize) {
+      printf ("Error. Failed to create the FD image. \n");
+      Status = FAIL;
+      goto Done;
+    }
+  }
+  if ((Operations == UPDATE) || (Operations == UPDATE_REMOVE) || (Operations == UPDATE_IGNORE) || (Operations == UPDATEQ)) {
+    printf ("\nCongratulations. The output Fd file '%s' has been completed successfully.\n", mOutputFdName);
+  }
+Done:
+  //
+  // Delete the temporary directory and files
+  //
+  if (IsFileExist) {
+    LibRmDir (TemDir);
+  }
+  //
+  // Clean up
+  //
+  if (gEfiFdInfo.Fd != NULL) {
+    free (gEfiFdInfo.Fd);
+  }
+
+  if (mMultiPlatformParam.Uqi.Value != NULL) {
+    free (mMultiPlatformParam.Uqi.Value);
+  }
+  if (mMultiPlatformParam.Uqi.Data != NULL) {
+    free (mMultiPlatformParam.Uqi.Data);
+  }
+  while (gEfiFdInfo.FfsArray[Index] != NULL) {
+    free (gEfiFdInfo.FfsArray[Index++]);
+  }
+
+  DestroyAllFormSet (&mFormSetListEntry);
+  DestroyAllStorage (&mVarListEntry);
+  DestroyAllStorage (&mBfvVarListEntry);
+  DestroyAllStorage (&mAllVarListEntry);
+  FreeUnidirectionList (mUqiList);
+
+  return Status;
+}
+
diff --git a/Platform/Intel/Tools/FCE/Fce.h b/Platform/Intel/Tools/FCE/Fce.h
new file mode 100644
index 0000000000..32cc3a1ccc
--- /dev/null
+++ b/Platform/Intel/Tools/FCE/Fce.h
@@ -0,0 +1,447 @@
+/** @file
+
+ FCE is a tool which enables developers to retrieve and change HII configuration ("Setup")
+ data in Firmware Device files (".fd" files).
+
+ Copyright (c) 2011-2019, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _FCE_H_
+#define _FCE_H_ 1
+
+//#define NDEBUG
+
+#include "Common.h"
+#include "IfrParse.h"
+#include "VariableCommon.h"
+#include "BinaryParse.h"
+#include "BinaryCreate.h"
+///
+/// Utility global variables
+///
+#define UTILITY_MAJOR_VERSION      0
+#define UTILITY_MINOR_VERSION      34
+
+#define UTILITY_NAME               "FCE"
+
+#define SUCCESS                    0
+#define FAIL                       1
+#define VR_FAIL                    2
+#define MAX_INPUT_ALLOCATE_SIZE    256
+
+///
+/// The type of file input and operations
+///
+typedef enum {
+  INFD,
+  OUTFD,
+  OUTTXT,
+  SETUPTXT
+} FILETYPE;
+
+typedef enum {
+  NONE,
+  READ,
+  UPDATE,
+  UPDATE_REMOVE,
+  UPDATE_IGNORE,
+  VERIFY,
+  UPDATEQ
+} OPERATION_TYPE;
+
+typedef struct _GUID_SEC_TOOL_ENTRY {
+  EFI_GUID                     Guid;
+  CHAR8*                       Name;
+  CHAR8*                       Path;
+  struct _GUID_SEC_TOOL_ENTRY  *Next;
+} GUID_SEC_TOOL_ENTRY;
+
+///
+/// The tag for use in identifying UNICODE files.
+/// If the file is UNICODE, the first 16 bits of the file will equal this value.
+///
+enum {
+  BigUnicodeFileTag    = 0xFEFF,
+  LittleUnicodeFileTag = 0xFFFE
+};
+
+typedef enum {
+  ASCII,
+  BIG_UCS2,
+  LITTLE_UCS2
+} FILE_TYPE;
+
+/**
+  Exchange the data between Efi variable and the data of VarList when the
+  variable use the authenticated variable header
+
+  If VarToList is TRUE, copy the efi variable data to the VarList; Otherwise,
+  update the data from varlist to efi variable.
+
+  @param VarToList          The flag to control the direction of exchange.
+   @param StorageListHead   Decide which variale list be updated
+
+  @retval EFI_SUCCESS           Get the address successfully.
+  @retval EFI_OUT_OF_RESOURCES  No available in the EFI variable zone.
+  @retval EFI_INVALID_PARAMETER Invalid variable name.
+**/
+EFI_STATUS
+SynAuthEfiVariable (
+  IN  BOOLEAN     VarToList,
+  IN  LIST_ENTRY  *StorageListHead
+  );
+
+/**
+  Remove the variable from Efi variable
+
+  Found the variable with the same name in StorageListHead and remove it.
+
+  @param StorageListHead   Decide which variale list be removed.
+
+  @retval EFI_SUCCESS      Remove the variables successfully.
+**/
+EFI_STATUS
+RemoveAuthEfiVariable (
+  IN  LIST_ENTRY  *StorageListHead
+  );
+
+/**
+  Exchange the data between Efi variable and the data of VarList when the
+  variable use the time stamp authenticated variable header
+
+  If VarToList is TRUE, copy the efi variable data to the VarList; Otherwise,
+  update the data from varlist to efi variable.
+
+  @param VarToList              The flag to control the direction of exchange.
+  @param StorageListHead        Decide which variale list be updated
+
+  @retval EFI_SUCCESS           Get the address successfully.
+  @retval EFI_OUT_OF_RESOURCES  No available in the EFI variable zone.
+  @retval EFI_INVALID_PARAMETER Invalid variable name.
+**/
+
+EFI_STATUS
+SynAuthEfiVariableBasedTime (
+  IN  BOOLEAN     VarToList,
+  IN  LIST_ENTRY  *StorageListHead
+  );
+
+/**
+  Remove the variable from Efi variable
+
+  Found the variable with the same name in StorageListHead and remove it.
+
+  @param StorageListHead   Decide which variale list be removed.
+
+  @retval EFI_SUCCESS      Remove the variables successfully.
+**/
+EFI_STATUS
+RemoveAuthEfiVariableBasedTime (
+  IN  LIST_ENTRY  *StorageListHead
+  );
+
+/**
+  Exchange the data between Efi variable and the data of VarList when the
+  variable use the authenticated variable header
+
+  If VarToList is TRUE, copy the efi variable data to the VarList; Otherwise,
+  update the data from varlist to efi variable.
+
+  @param VarToList         The flag to control the direction of exchange.
+  @param StorageListHead   Decide which variale list be updated
+
+  @retval EFI_SUCCESS           Get the address successfully.
+  @retval EFI_OUT_OF_RESOURCES  No available in the EFI variable zone.
+**/
+
+EFI_STATUS
+SynEfiVariable (
+  IN  BOOLEAN     VarToList,
+  IN  LIST_ENTRY  *StorageListHead
+  );
+
+/**
+  Remove the variable from Efi variable
+
+  Found the variable with the same name in StorageListHead and remove it.
+
+  @param StorageListHead   Decide which variale list be removed.
+
+  @retval EFI_SUCCESS      Remove the variables successfully.
+**/
+EFI_STATUS
+RemoveNormalEfiVariable (
+  IN  LIST_ENTRY  *StorageListHead
+  );
+
+/**
+  Read all defaultId and platformId from binary.
+
+  @param  Binary        The pointer to the bianry
+  @param  Storage       The pointer to the Storage
+**/
+VOID
+ReadDefaultAndPlatformIdFromBfv (
+  IN  UINT8             *Binary,
+  IN  FORMSET_STORAGE   *Storage
+);
+
+/**
+  Store all defaultId and platformId to binary.
+
+  @param  Binary        The pointer to the bianry
+  @param  Storage       The pointer to the Storage
+
+  @retval Length        Return the length of the header
+**/
+
+UINT32
+WriteDefaultAndPlatformId (
+  IN  UINT8             *Binary,
+  IN  FORMSET_STORAGE   *Storage
+);
+
+/**
+  Store all defaultId and platformId to binary.
+
+  @param  Binary        The pointer to the bianry
+  @param  Storage       The pointer to the Storage
+
+  @retval Length        Return the length of the header
+**/
+UINT32
+WriteNvStoreDefaultAndPlatformId (
+  IN  UINT8             *Binary,
+  IN  FORMSET_STORAGE   *Storage
+);
+
+/**
+  Copy variable to binary in multi-platform mode
+
+  @param  Storage           The pointer to a storage in storage list.
+  @param  StorageBeginning  The pointer to the beginning of storage under specifed platformId and defaultId
+  @param  Index             The number of the storage. If the Index is 0, record the variable header to
+                            the binary. Or else, only record the storage.
+
+  @return length          The length of storage
+**/
+UINT32
+CopyVariableToBinary (
+  IN      FORMSET_STORAGE   *Storage,
+  IN OUT  UINT8             *StorageBeginning,
+  IN      UINT32            Index
+  );
+
+/**
+  Copy variable to binary in multi-platform mode
+
+  @param  Storage           The pointer to a storage in storage list.
+  @param  StorageBeginning  The pointer to the beginning of storage under specifed platformId and defaultId
+  @param  Index             The number of the storage. If the Index is 0, record the variable header to
+                            the binary. Or else, only record the storage.
+
+  @return length          The length of storage
+**/
+UINT32
+CopyVariableToNvStoreBinary (
+  IN      FORMSET_STORAGE   *Storage,
+  IN OUT  UINT8             *StorageBeginning,
+  IN      UINT32            Index
+  );
+
+
+/**
+  Read variable to storage list in multi-platform mode
+
+  @param  Binary            The pointer to the header of storage under specifed platformId and defaultId
+  @param  StorageListEntry  The pointer to the storage list.
+
+  @return length          The length of storage
+**/
+
+UINT32
+ReadNvStoreVariableToList (
+  IN      UINT8             *Binary,
+  IN      LIST_ENTRY        *StorageListEntry
+  );
+
+/**
+  Read variable to storage list in multi-platform mode
+
+  @param  Binary            The pointer to the header of storage under specifed platformId and defaultId
+  @param  StorageListEntry  The pointer to the storage list.
+
+  @return length          The length of storage
+**/
+UINT32
+ReadVariableToList (
+  IN      UINT8             *Binary,
+  IN      LIST_ENTRY        *StorageListEntry
+  );
+
+/**
+  Check whether exists the valid normal variables in NvStorage or not.
+
+  @retval TRUE      If existed, return TRUE.
+  @retval FALSE     Others
+**/
+BOOLEAN
+ExistNormalEfiVarOrNot (
+  IN  LIST_ENTRY  *StorageListHead
+  );
+
+/**
+  Fix the size of variable header.
+
+  @param  Binary            The pointer to the header of storage under specifed platformId and defaultId
+  @param  Length            The length of binary.
+
+**/
+VOID
+FixVariableHeaderSize (
+  IN  UINT8   *BinaryBeginning,
+  IN  UINT32  Length
+  );
+
+/**
+  Fix the size of variable header.
+
+  @param  Binary            The pointer to the header of storage under specifed platformId and defaultId
+  @param  Length            The length of binary.
+
+**/
+
+VOID
+FixNvStoreVariableHeaderSize (
+  IN  UINT8   *BinaryBeginning,
+  IN  UINT32  Length
+  );
+/**
+  Copy time-based authenticated variable to binary in multi-platform mode
+
+  @param  Storage           The pointer to a storage in storage list.
+  @param  StorageBeginning  The pointer to the beginning of storage under specifed platformId and defaultId
+  @param  Index             The number of the storage. If the Index is 0, record the variable header to
+                            the binary. Or else, only record the storage.
+  @return length            The length of storage
+**/
+UINT32
+CopyTimeBasedVariableToBinary (
+  IN      FORMSET_STORAGE   *Storage,
+  IN OUT  UINT8             *StorageBeginning,
+  IN      UINT32            Index
+  );
+
+/**
+  Read time-based authenticated variable to storage list in multi-platform mode
+
+  @param  Binary            The pointer to the header of storage under specifed platformId and defaultId
+  @param  StorageListEntry  The pointer to the storage list.
+
+  @return length          The length of storage
+**/
+UINT32
+ReadTimeBasedVariableToList (
+  IN      UINT8             *Binary,
+  IN      LIST_ENTRY        *StorageListEntry
+  );
+
+/**
+  Check whether exists the valid time-based variables in NvStorage or not.
+
+  @retval TRUE      If existed, return TRUE.
+  @retval FALSE     Others
+**/
+BOOLEAN
+ExistTimeBasedEfiVarOrNot (
+  IN  LIST_ENTRY  *StorageListHead
+  );
+
+/**
+  Fix the size of time-based variable header.
+
+  @param  Binary            The pointer to the header of storage under specifed platformId and defaultId
+  @param  Length            The length of binary.
+
+**/
+VOID
+FixBasedTimeVariableHeaderSize (
+  IN  UINT8   *BinaryBeginning,
+  IN  UINT32  Length
+  );
+
+/**
+  Copy Monotonic-Based authenticated variable to binary in multi-platform mode
+
+  @param  Storage           The pointer to a storage in storage list.
+  @param  StorageBeginning  The pointer to the beginning of storage under specifed platformId and defaultId
+  @param  Index             The number of the storage. If the Index is 0, record the variable header to
+                            the binary. Or else, only record the storage.
+
+  @return length            The length of storage
+**/
+UINT32
+CopyMonotonicBasedVariableToBinary (
+  IN      FORMSET_STORAGE   *Storage,
+  IN OUT  UINT8             *StorageBeginning,
+  IN      UINT32            Index
+  );
+
+/**
+  Read Monotonic-based authenticated variable to storage list in multi-platform mode
+
+  @param  Binary            The pointer to the header of storage under specifed platformId and defaultId
+  @param  StorageListEntry  The pointer to the storage list.
+
+  @return length          The length of storage
+**/
+UINT32
+ReadMonotonicBasedVariableToList (
+  IN      UINT8             *Binary,
+  IN      LIST_ENTRY        *StorageListEntry
+  );
+
+/**
+  Check whether exists the valid MonotonicBased variables in NvStorage or not.
+
+  @retval TRUE      If existed, return TRUE.
+  @retval FALSE     Others
+**/
+BOOLEAN
+ExistMonotonicBasedEfiVarOrNot (
+  IN  LIST_ENTRY  *StorageListHead
+  );
+
+/**
+  Fix the size of montonic variable header.
+
+  @param  Binary            The pointer to the header of storage under specifed platformId and defaultId
+  @param  Length            The length of binary.
+
+**/
+VOID
+FixMontonicVariableHeaderSize (
+  IN  UINT8   *BinaryBeginning,
+  IN  UINT32  Length
+  );
+
+/**
+  FCE application entry point
+
+  @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.
+  @retval  2       An error about check occurred.
+
+**/
+int
+main (
+  int       argc,
+  char      *argv[]
+  );
+
+#endif
diff --git a/Platform/Intel/Tools/FCE/GNUmakefile b/Platform/Intel/Tools/FCE/GNUmakefile
new file mode 100644
index 0000000000..0ef0cb1c4b
--- /dev/null
+++ b/Platform/Intel/Tools/FCE/GNUmakefile
@@ -0,0 +1,22 @@
+##@file
+#
+# GNU makefile for 'FCE' module build.
+#
+# Copyright (c) 2011-2019, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+##
+
+export ARCH
+export HOST_ARCH=$(ARCH)
+
+MAKEROOT ?= $(EDK_TOOLS_PATH)/Source/C
+
+APPNAME = FCE
+
+OBJECTS = Fce.o Variable.o TimeBasedVariable.o MonotonicBasedVariable.o IfrParse.o Common.o BinaryParse.o BinaryCreate.o Expression.o
+
+include $(MAKEROOT)/Makefiles/app.makefile
+
+LIBS = -lCommon -lm
+
+
diff --git a/Platform/Intel/Tools/FCE/IfrParse.c b/Platform/Intel/Tools/FCE/IfrParse.c
new file mode 100644
index 0000000000..2f5a87baf3
--- /dev/null
+++ b/Platform/Intel/Tools/FCE/IfrParse.c
@@ -0,0 +1,4836 @@
+/** @file
+
+ Parser for IFR binary encoding.
+
+ Copyright (c) 2011-2019, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "IfrParse.h"
+
+#ifndef EDKII_IFR_BIT_VARSTORE_GUID
+#define EDKII_IFR_BIT_VARSTORE_GUID \
+  {0x82DDD68B, 0x9163, 0x4187, {0x9B, 0x27, 0x20, 0xA8, 0xFD, 0x60 ,0xA7, 0x1D}}
+#endif
+
+#ifndef EDKII_IFR_NUMERIC_SIZE_BIT
+#define EDKII_IFR_NUMERIC_SIZE_BIT  0x3F
+#endif
+
+UINT16           mStatementIndex;
+UINT16           mExpressionOpCodeIndex;
+
+BOOLEAN          mInScopeSubtitle;
+BOOLEAN          mInScopeSuppress;
+BOOLEAN          mInScopeGrayOut;
+BOOLEAN          mInScopeDisable;
+FORM_EXPRESSION  *mSuppressExpression;
+FORM_EXPRESSION  *mGrayOutExpression;
+FORM_EXPRESSION  *mDisableExpression;
+
+extern MULTI_PLATFORM_PARAMETERS   mMultiPlatformParam;
+extern LIST_ENTRY                  mVarListEntry;
+extern LIST_ENTRY                  mFormSetListEntry;
+extern UINT32                      mFormSetOrderParse;
+
+#define FORM_SET_GUID_PREFIX    "Form Set GUID: "
+#define EFI_GUID_FORMAT         "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x"
+
+UINT32 mMaxCount = 0x100000;
+UINT32 mCount = 0;
+CHAR8  *mStringBuffer = NULL;
+static EFI_GUID gEdkiiIfrBitVarGuid = EDKII_IFR_BIT_VARSTORE_GUID;
+
+/**
+  Produces a Null-terminated ASCII string in mStringBuffer based on a Null-terminated
+  ASCII format string and variable argument list.
+
+  @param  FormatString    A null-terminated ASCII format string.
+  @param  ...             The variable argument list whose contents are accessed based on the
+                          format string specified by FormatString.
+**/
+VOID
+StringPrint (
+  CHAR8 *FormatString,
+  ...
+)
+{
+  va_list Marker;
+  INT32   Count;
+
+  va_start (Marker, FormatString);
+  Count = vsprintf (mStringBuffer + mCount, FormatString, Marker);
+  mCount = mCount + Count;
+  va_end (Marker);
+  if (mCount + 0x400 > mMaxCount) {
+    mStringBuffer[mCount] = '\0';
+    fwrite (mStringBuffer, sizeof (CHAR8), mCount, stdout);
+    mCount = 0;
+  }
+}
+
+/**
+  Print the information of questions.
+
+  @param  FormSet     The pointer to the formset.
+  @param  FormSet     The pointer to the form.
+  @param  Question    The pointer to the question.
+  @param  PrintOrNot  Decide whether print or not.
+
+  @return NULL.
+
+**/
+static
+VOID
+PrintQuestion (
+  IN  FORM_BROWSER_FORMSET    *FormSet,
+  IN  FORM_BROWSER_FORM       *Form,
+  IN  FORM_BROWSER_STATEMENT  *Question,
+  IN  BOOLEAN                  PrintOrNot
+  );
+
+/**
+  Writes a Unicode string specified by iStringToken and iLanguage to the script file (converted to ASCII).
+
+  @param  Package        A pointer to the Unicode string.
+
+  @return NULL
+
+**/
+static
+VOID
+LogUnicodeString (
+  IN     CHAR16              *pcString
+  )
+{
+  UINTN  Index;
+
+  if (pcString == NULL) {
+    return;
+  }
+  //
+  // replace the 0x0D to 0x20, because if the pcString has 0D 0A, then after print it,
+  // different editor may have different format
+  //
+  for (Index = 0; pcString[Index] != 0; Index++) {
+    if (pcString[Index] == 0x0D) {
+       pcString[Index] = 0x20;
+    }
+
+    StringPrint("%c", pcString[Index] & 0x00FF);
+  }
+}
+
+/**
+  Writes a UQIL Unicode string specified by iStringToken to the script file as an array of 16-bit integers in ASCII.
+
+  @param  Package        A pointer to the Unicode string.
+
+  @return NULL
+
+**/
+static
+VOID
+LogUqi (
+  IN     CHAR16              *pcString
+  )
+{
+  UINT16         Index;
+  //
+  //  Find the UNICODE string length (in CHAR16)
+  //
+  for (Index = 0; pcString[Index] != 0; Index++);
+  //
+  //  Write each word as a hex integer
+  //
+  for (Index = 0; pcString[Index] != 0; Index++) {
+    StringPrint("%04X ", pcString[Index]);
+  }
+}
+
+/**
+  Get the question value with bit field from the buffer.
+
+  @param  Question        The question refer to bit field.
+  @param  Buffer          The buffer which the question value get from.
+  @param  Value           Retun the value.
+
+**/
+VOID
+GetBitsQuestionValue(
+  IN  FORM_BROWSER_STATEMENT *Question,
+  IN  UINT8                  *Buffer,
+  OUT UINT32                 *Value
+  )
+{
+  UINT32        PreBits;
+  UINT32        Mask;
+
+  PreBits = Question->BitVarOffset - Question->VarStoreInfo.VarOffset * 8;
+  Mask = (1<< Question->BitStorageWidth) -1;
+
+  *Value = *(UINT32*)Buffer;
+  (*Value) >>= PreBits;
+  (*Value) &= Mask;
+}
+
+/**
+  Set the question value with bit field to the buffer.
+
+  @param  Question        The question refer to bit field.
+  @param  Buffer          The buffer which the question value set to.
+  @param  Value           The value need to set.
+
+**/
+VOID
+SetBitsQuestionValue (
+  IN     FORM_BROWSER_STATEMENT *Question,
+  IN OUT UINT8                  *Buffer,
+  IN     UINT32                 Value
+  )
+{
+  UINT32        PreBits;
+  UINT32        Mask;
+  UINT32        TmpValue;
+
+  PreBits = Question->BitVarOffset - Question->VarStoreInfo.VarOffset * 8;
+  Value <<= PreBits;
+  Mask = (1<< Question->BitStorageWidth) -1;
+  Mask <<= PreBits;
+
+  TmpValue = *(UINT32*)(Buffer);
+  TmpValue = (TmpValue & (~Mask)) | Value;
+  CopyMem ((UINT32*)Buffer, &TmpValue, sizeof (UINT32));
+}
+
+/**
+  Print the current value of the specified question.
+
+  @param  Question       The pointer to question
+
+  @return EFI_SUCCESS
+**/
+static
+EFI_STATUS
+LogIfrValue (
+  IN  FORM_BROWSER_FORMSET     *FormSet,
+  IN  FORM_BROWSER_STATEMENT   *Question
+  )
+{
+  EFI_STATUS          Status;
+  FORMSET_STORAGE     *VarList;
+  UINT8               *VarBuffer;
+  UINT32              Value;
+
+  VarBuffer    = NULL;
+
+  Status = SearchVarStorage (
+             Question,
+             NULL,
+             Question->VarStoreInfo.VarOffset,
+             FormSet->StorageListHead,
+             (CHAR8 **)&VarBuffer,
+             &VarList
+             );
+
+  if (EFI_ERROR (Status)) {
+    StringPrint("\nCouldn't read current variable data.");
+    return EFI_ABORTED;
+  }
+  //
+  //  Log the Value
+  //
+  if (
+    (Question->VarStoreInfo.VarOffset > VarList->Size)   \
+    && (VarList->Type == EFI_IFR_VARSTORE_OP)
+    ) {
+    StringPrint("0000 // Offset larger than Variable Size -- FAILURE");
+  } else if (
+    (Question->VarStoreInfo.VarOffset > VarList->Size) \
+    && (VarList->Type == EFI_IFR_VARSTORE_EFI_OP)       \
+    && VarList->NewEfiVarstore
+    ) {
+    StringPrint("0000 // Offset larger than Variable Size -- FAILURE");
+  }  else if (
+    (Question->StorageWidth > VarList->Size)           \
+    && (VarList->Type == EFI_IFR_VARSTORE_EFI_OP)      \
+    && !VarList->NewEfiVarstore
+    ) {
+    StringPrint("0000 // Offset larger than Variable Size -- FAILURE");
+  } else {
+    if (Question->QuestionReferToBitField) {
+      GetBitsQuestionValue (Question, VarBuffer, &Value);
+      VarBuffer = (UINT8*)(&Value);
+    }
+    switch (Question->StorageWidth) {
+
+    case sizeof (UINT8):
+      StringPrint("%02X", (*(UINT8 *)VarBuffer) & 0xFF);
+      break;
+
+    case sizeof (UINT16):
+      StringPrint("%04X", (*(UINT16 *)VarBuffer) & 0xFFFF);
+      break;
+
+    case sizeof (UINT32):
+      StringPrint("%08X", (*(UINT32 *)VarBuffer) & 0xFFFFFFFF);
+      break;
+
+    case sizeof (UINT64):
+      StringPrint("%016llX", *((UINT64 *)VarBuffer));
+      break;
+
+    default:
+      StringPrint("0000 // Width > 16 is not supported -- FAILURE");
+      break;
+    }
+  }
+  return EFI_SUCCESS;
+}
+
+/**
+  Print the current value of the STRING question.
+
+  @param  Question       The pointer to question
+
+  @return EFI_SUCCESS
+**/
+static
+EFI_STATUS
+LogIfrValueStr (
+  IN  FORM_BROWSER_FORMSET     *FormSet,
+  IN  FORM_BROWSER_STATEMENT   *Question
+  )
+{
+  EFI_STATUS          Status;
+  FORMSET_STORAGE     *VarList;
+  UINT8               *VarBuffer;
+
+  VarBuffer = NULL;
+  Status = SearchVarStorage (
+             Question,
+             NULL,
+             Question->VarStoreInfo.VarOffset,
+             FormSet->StorageListHead,
+             (CHAR8 **)&VarBuffer,
+             &VarList
+             );
+
+  if (EFI_ERROR (Status)) {
+    StringPrint("\nCouldn't read current variable data.");
+    return EFI_ABORTED;
+  }
+
+  //
+  //  Log the Value
+  //
+  if (
+    (Question->VarStoreInfo.VarOffset > VarList->Size)   \
+    && (VarList->Type == EFI_IFR_VARSTORE_OP)
+    ) {
+    StringPrint("0000 // Offset larger than Variable Size -- FAILURE");
+  } else if (
+    (Question->VarStoreInfo.VarOffset > VarList->Size) \
+    && (VarList->Type == EFI_IFR_VARSTORE_EFI_OP)       \
+    && VarList->NewEfiVarstore
+    ) {
+    StringPrint("0000 // Offset larger than Variable Size -- FAILURE");
+  }  else if (
+    (Question->StorageWidth > VarList->Size)           \
+    && (VarList->Type == EFI_IFR_VARSTORE_EFI_OP)      \
+    && !VarList->NewEfiVarstore
+    ) {
+    StringPrint("0000 // Offset larger than Variable Size -- FAILURE");
+  } else {
+      StringPrint("\"");
+      LogUnicodeString((CHAR16 *)VarBuffer);
+      StringPrint("\"");
+  }
+  return EFI_SUCCESS;
+}
+
+/**
+  Print the current values of an Ordered List question.
+
+  @param  Question       The pointer to question
+  @param  MaxEntries       The max number of options
+  @param  VarList          The dual pointer to the Node of VarList
+
+  @return EFI_SUCCESS
+**/
+static
+EFI_STATUS
+LogIfrValueList (
+  IN  FORM_BROWSER_FORMSET     *FormSet,
+  IN  FORM_BROWSER_STATEMENT   *Question
+  )
+{
+  EFI_STATUS          Status;
+  FORMSET_STORAGE     *VarList;
+  UINT8               CurrentEntry;
+  UINT8               *VarBuffer;
+
+  CurrentEntry = 0;
+  VarBuffer    = NULL;
+
+  Status = SearchVarStorage (
+             Question,
+             NULL,
+             Question->VarStoreInfo.VarOffset,
+             FormSet->StorageListHead,
+             (CHAR8 **)&VarBuffer,
+             &VarList
+             );
+
+  if (EFI_ERROR (Status)) {
+    StringPrint("\nCouldn't read current variable data.");
+    return EFI_ABORTED;
+  }
+  //
+  // Log the value
+  //
+  if (
+    ((Question->VarStoreInfo.VarOffset +  Question->MaxContainers) > VarList->Size)   \
+    && (VarList->Type == EFI_IFR_VARSTORE_OP)
+    ) {
+    StringPrint("0000 // Offset larger than Variable Size -- FAILURE");
+  } else if (
+    (Question->MaxContainers > VarList->Size) \
+    && (VarList->Type == EFI_IFR_VARSTORE_EFI_OP)
+    ) {
+    StringPrint("0000 // Offset larger than Variable Size -- FAILURE");
+  } else {
+    for (CurrentEntry = 0; CurrentEntry < Question->MaxContainers; CurrentEntry++) {
+
+      switch (Question->StorageWidth/Question->MaxContainers){
+
+      case 1:
+        StringPrint("%02X ", VarBuffer[CurrentEntry]);
+        break;
+
+      case 2:
+        StringPrint("%04X ", *((UINT16 *)VarBuffer + CurrentEntry));
+        break;
+
+      case 4:
+        StringPrint("%08X ", *((UINT32 *)VarBuffer + CurrentEntry));
+        break;
+
+      case 8:
+        StringPrint("%016llX ", *((UINT64 *)VarBuffer + CurrentEntry));
+        break;
+
+      default:
+        StringPrint("%02X ", VarBuffer[CurrentEntry]);
+      }
+    }
+  }
+  return EFI_SUCCESS;
+}
+
+/**
+  Compare two Uqi parameters
+
+  @param UqiParm1       The pointer to the first Uqi parameter.
+  @param UqiParm2       The pointer to the second Uqi parameter.
+
+  @retval TRUE          If these two Uqi parameters are the same, return TRUE;
+  @return FALSE         Otherwise, return FALSE;
+**/
+BOOLEAN
+CompareUqiHeader (
+  IN  CONST UQI_HEADER  *UqiParm1,
+  IN  CONST UQI_HEADER  *UqiParm2
+  )
+{
+  INT32    Index;
+
+  if (UqiParm1->HexNum != UqiParm2->HexNum) {
+    return FALSE;
+  }
+
+  for (Index = UqiParm1->HexNum - 1; Index >= 0; Index--) {
+    if (UqiParm1->Data[Index] != UqiParm2->Data[Index]) {
+      return FALSE;
+    }
+  }
+
+  return TRUE;
+}
+
+
+/**
+  Check whether existed a same variable in the LIST_ENTRY.
+
+  @param  CurVarList        A pointer to a variable node.
+
+  @return Pointer          If existed the same variable, return the pointer to the Node.
+  @return NULL              Otherwise, return FALSE
+
+**/
+static
+FORMSET_STORAGE *
+NotSameVariableInVarList (
+  IN  LIST_ENTRY         *VariableListEntry,
+  IN  FORMSET_STORAGE    *StorageNode
+  )
+{
+  FORMSET_STORAGE    *CurNode;
+  LIST_ENTRY         *Link;
+  LIST_ENTRY         *StorageListHead;
+
+  StorageListHead       =  VariableListEntry;
+  CurNode               = NULL;
+
+  //
+  // Find Storage for this Question
+  //
+  Link = GetFirstNode (StorageListHead);
+  while (!IsNull (StorageListHead, Link)) {
+    CurNode = FORMSET_STORAGE_FROM_LINK (Link);
+
+    if (!CompareGuid (&StorageNode->Guid, &CurNode->Guid)   \
+      && (CurNode->Name != NULL)                            \
+      && (StorageNode->Name != NULL)                        \
+      && !FceStrCmp (StorageNode->Name, CurNode->Name)         \
+      && (StorageNode - CurNode != 0)
+      ) {
+      //
+      // If not multi-plaform support mode, take VarStore as the EfiVarStore. So If there are
+      // two variables with same guid same name, but different type, we will take as the same
+      // in general mode
+      //
+      if (mMultiPlatformParam.MultiPlatformOrNot && (CurNode->Type == StorageNode->Type)) {
+        //
+        // If matched, get the address of EFI_IFR_VARSTORE data.
+        //
+        return CurNode;
+        break;
+      } else if (!mMultiPlatformParam.MultiPlatformOrNot) {
+        return CurNode;
+        break;
+      }
+    }
+    Link = GetNextNode (StorageListHead, Link);
+  }
+  return NULL;
+}
+
+/**
+  Get the UniString by the offset.
+
+  @param  UniPackge         A pointer to the beginning of Null-terminated Unicode string Array.
+  @param  CurUniPackge      A pointer to the current position of Null-terminated Unicode string Array.
+  @param  VarDefaultNameId  The string ID.
+  @param  CurOrDefaultLang  Use the current language or the default language.
+  @param  VarDefaultName    return the name string.
+
+  @return EFI_SUCCESS
+  @return EFI_INVALID_PARAMETER
+  @return EFI_NOT_FOUND
+**/
+static
+EFI_STATUS
+GetStringByOffset (
+  IN     UINT8               *UniPackge,
+  IN     UINT8               *CurUniPackge,
+  IN     UINT16              VarDefaultNameId,
+  IN     BOOLEAN             CurOrDefaultLang,
+  IN OUT CHAR16              **VarDefaultName
+  )
+{
+  UINT8                          *HiiStringHeader;
+  UINT32                         Offset;
+  UINT32                         Count;
+  UINT32                         Index;
+  EFI_HII_STRING_BLOCK           *Block;
+  VOID                           *ThisBlock;
+
+  assert ((UniPackge != NULL) && (CurUniPackge != NULL));
+
+  HiiStringHeader  = NULL;
+  Offset           = 1;
+  Count            = 0;
+  Block            = NULL;
+  ThisBlock        = NULL;
+
+  if (VarDefaultNameId == 0) {
+    return EFI_INVALID_PARAMETER;
+  }
+  if (CurOrDefaultLang) {
+    HiiStringHeader = CurUniPackge;
+  } else {
+    HiiStringHeader  = UniPackge + 4;
+  }
+
+  Block = (EFI_HII_STRING_BLOCK *)((UINT8*)HiiStringHeader + ((EFI_HII_STRING_PACKAGE_HDR *)HiiStringHeader)->HdrSize);
+  //
+  // Search the matched String in specificated language package by the Offset
+  //
+  while( Block->BlockType != EFI_HII_SIBT_END ) {
+    switch (Block->BlockType) {
+    case EFI_HII_SIBT_STRING_SCSU:
+      ThisBlock = (VOID *)Block;
+      for (Index = 0 ; ((EFI_HII_SIBT_STRING_SCSU_BLOCK *)ThisBlock)->StringText[Index] != 0 ; Index++) ;
+      Block = (EFI_HII_STRING_BLOCK *)&((EFI_HII_SIBT_STRING_SCSU_BLOCK *)ThisBlock)->StringText[Index + 1];
+      break;
+
+    case EFI_HII_SIBT_STRING_SCSU_FONT:
+      ThisBlock = (VOID *)Block;
+      for (Index = 0 ; ((EFI_HII_SIBT_STRING_SCSU_FONT_BLOCK *)ThisBlock)->StringText[Index] != 0 ; Index++) ;
+      Block = (EFI_HII_STRING_BLOCK *)(((EFI_HII_SIBT_STRING_SCSU_FONT_BLOCK *)ThisBlock) + 1);
+      break;
+
+    case EFI_HII_SIBT_STRINGS_SCSU:
+      ThisBlock = (VOID *)Block;
+      for( Count= ((EFI_HII_SIBT_STRINGS_SCSU_BLOCK *)ThisBlock)->StringCount, Index = 0 ; Count; Count--, Index++ ) {
+        for ( ; ((EFI_HII_SIBT_STRINGS_SCSU_BLOCK *)ThisBlock)->StringText[Index] != 0 ; Index++) ;
+      }
+      Block = (EFI_HII_STRING_BLOCK *)&((EFI_HII_SIBT_STRINGS_SCSU_BLOCK *)ThisBlock)->StringText[Index];
+      break;
+
+    case EFI_HII_SIBT_STRINGS_SCSU_FONT:
+      ThisBlock = (VOID *)Block;
+      for( Count = ((EFI_HII_SIBT_STRINGS_SCSU_FONT_BLOCK *)ThisBlock)->StringCount, Index = 0 ; Count; Count--, Index++ ) ;
+      Block = (EFI_HII_STRING_BLOCK *) & ((EFI_HII_SIBT_STRINGS_SCSU_FONT_BLOCK *)ThisBlock)->StringText[Index];
+      break;
+
+    case EFI_HII_SIBT_STRING_UCS2:
+      ThisBlock = (VOID *)Block;
+      if (Offset == VarDefaultNameId)  {
+      *VarDefaultName = malloc ((FceStrLen ((CHAR16 *) ((EFI_HII_SIBT_STRING_UCS2_BLOCK *)ThisBlock)->StringText) + 1) * sizeof (CHAR16));
+      if (*VarDefaultName == NULL) {
+        printf ("Fail to allocate memory");
+        return EFI_OUT_OF_RESOURCES;
+      }
+      memset (
+        *VarDefaultName,
+        0,
+        (FceStrLen ((CHAR16 *) ((EFI_HII_SIBT_STRING_UCS2_BLOCK *)ThisBlock)->StringText) + 1) * sizeof (CHAR16)
+      );
+      StrCpy (
+        *VarDefaultName,
+        (CHAR16 *) ((EFI_HII_SIBT_STRING_UCS2_BLOCK *) ThisBlock)->StringText
+      );
+      return EFI_SUCCESS;
+    }
+
+      for (Index = 0 ; ((EFI_HII_SIBT_STRING_UCS2_BLOCK *)ThisBlock)->StringText[Index] != 0 ; Index++) ;
+      Block = (EFI_HII_STRING_BLOCK *) & ((EFI_HII_SIBT_STRING_UCS2_BLOCK *) ThisBlock)->StringText[Index + 1];
+      Offset += 1;
+      break;
+
+    case EFI_HII_SIBT_STRING_UCS2_FONT:
+      ThisBlock = (VOID *)Block;
+      for (Index = 0 ; ((EFI_HII_SIBT_STRING_UCS2_FONT_BLOCK *) ThisBlock)->StringText[Index] != 0 ; Index++) ;
+      Block = (EFI_HII_STRING_BLOCK *)& ((EFI_HII_SIBT_STRING_UCS2_FONT_BLOCK *) ThisBlock)->StringText[Index + 1];
+      break;
+
+    case EFI_HII_SIBT_STRINGS_UCS2:
+      ThisBlock = (VOID *)Block;
+      for( Count = ((EFI_HII_SIBT_STRINGS_UCS2_BLOCK *)ThisBlock)->StringCount, Index = 0 ; Count; Count--, Index++ ) {
+        for ( ; ((EFI_HII_SIBT_STRINGS_UCS2_BLOCK *) ThisBlock)->StringText[Index] != 0 ; Index++) ;
+      }
+      Block = (EFI_HII_STRING_BLOCK *) & ((EFI_HII_SIBT_STRINGS_UCS2_BLOCK *) ThisBlock)->StringText[Index];
+      break;
+
+    case EFI_HII_SIBT_STRINGS_UCS2_FONT:
+      ThisBlock = (VOID *)Block;
+      for( Count= ((EFI_HII_SIBT_STRINGS_UCS2_FONT_BLOCK *) ThisBlock)->StringCount, Index = 0 ; Count ; Count--, Index++ ) {
+        for ( ; ((EFI_HII_SIBT_STRINGS_UCS2_FONT_BLOCK *) ThisBlock)->StringText[Index] != 0 ; Index++) ;
+      }
+      Block = (EFI_HII_STRING_BLOCK *) & ((EFI_HII_SIBT_STRINGS_UCS2_FONT_BLOCK *)ThisBlock)->StringText[Index];
+      break;
+
+     case EFI_HII_SIBT_DUPLICATE:
+       ThisBlock = (VOID *)Block;
+       Block = (EFI_HII_STRING_BLOCK *)((EFI_HII_SIBT_DUPLICATE_BLOCK *) ThisBlock + 1);
+       break;
+
+     case EFI_HII_SIBT_SKIP2:
+       ThisBlock = (VOID *)Block;
+       Offset += ((EFI_HII_SIBT_SKIP2_BLOCK *) ThisBlock)->SkipCount;
+       Block = (EFI_HII_STRING_BLOCK *)( (EFI_HII_SIBT_SKIP2_BLOCK *) ThisBlock + 1);
+       break;
+
+     case EFI_HII_SIBT_SKIP1:
+       ThisBlock = (VOID *)Block;
+       Offset += ((EFI_HII_SIBT_SKIP1_BLOCK *) ThisBlock)->SkipCount;
+       Block = (EFI_HII_STRING_BLOCK *)((EFI_HII_SIBT_SKIP1_BLOCK *)ThisBlock + 1);
+       break;
+
+     case EFI_HII_SIBT_EXT1:
+       ThisBlock = (VOID *)Block;
+       Block = (EFI_HII_STRING_BLOCK *)((UINT8*)ThisBlock + ((EFI_HII_SIBT_EXT1_BLOCK *) ThisBlock)->Length);
+       break;
+
+     case EFI_HII_SIBT_EXT2:
+       ThisBlock = (VOID *)Block;
+       Block = (EFI_HII_STRING_BLOCK *)((UINT8*)ThisBlock + ((EFI_HII_SIBT_EXT2_BLOCK *) ThisBlock)->Length);
+       break;
+
+     case EFI_HII_SIBT_EXT4:
+       ThisBlock = (VOID *)Block;
+       Block = (EFI_HII_STRING_BLOCK *)((UINT8*)ThisBlock + ((EFI_HII_SIBT_EXT4_BLOCK *)ThisBlock)->Length);
+       break;
+
+     case EFI_HII_SIBT_FONT:
+       ThisBlock = (VOID *)Block;
+       for (Index = 0 ; ((EFI_HII_SIBT_FONT_BLOCK *) ThisBlock)->FontName[Index] != 0 ; Index++) ;
+       Block = (EFI_HII_STRING_BLOCK *)& ((EFI_HII_SIBT_FONT_BLOCK *) ThisBlock)->FontName[Index + 1];
+       break;
+
+     default:
+       StringPrint("Unhandled type = 0x%x\n", Block->BlockType);
+     }
+   }
+
+  return EFI_NOT_FOUND;
+}
+
+/**
+  Parse the UniString to get the string information.
+
+  @param  CachedStringList  A pointer to cached string list
+  @param  UniPackge         A pointer to a Null-terminated Unicode string Array.
+  @param  VarDefaultNameId  The string ID.
+  @param  Language          The language, en-US UQI or eng.
+  @param  VarDefaultName    return the name string.
+
+  @return EFI_SUCCESS       If get the name string successfully
+  @return EFI_NOT_FOUND       An error occurred.
+  @return EFI_INVALID_PARAMETER
+
+**/
+EFI_STATUS
+FindDefaultName (
+  IN     FORMSET_STRING_LIST *CachedStringList,
+  IN     UINT8               *UniPackge,
+  IN     UINT16              VarDefaultNameId,
+  IN     LANGUAGE            Language,
+  IN OUT CHAR16              **VarDefaultName
+  )
+{
+  CHAR8          *UniPackgeEnd;
+  CHAR8          *UniBin;
+  CHAR8          LangStr[10];
+  BOOLEAN        IsFound;
+  EFI_STATUS     Status;
+  EFI_STRING_ID  Index;
+  STRING_INFO    *TempBuffer;
+
+  UniBin     = NULL;
+  IsFound    = FALSE;
+  Status     = EFI_NOT_FOUND;
+
+  UniBin       = (CHAR8 *) UniPackge + 4;
+  UniPackgeEnd = (CHAR8 *) UniPackge + *(UINT32 *)UniPackge;
+
+  //
+  //Handle with the invalid usage "STRING_TOKEN(0)"
+  //
+  if (VarDefaultNameId == 0) {
+    *VarDefaultName = L"";
+    return EFI_SUCCESS;
+  }
+
+  if (CachedStringList != NULL) {
+    for (Index = 0; Index < CachedStringList->CachedIdNum; Index ++) {
+      if (VarDefaultNameId == CachedStringList->StringInfoList[Index].StringId) {
+        *VarDefaultName = CachedStringList->StringInfoList[Index].String;
+        return EFI_SUCCESS;
+      }
+    }
+  }
+
+  switch (Language) {
+
+  case UQI:
+    strcpy (LangStr, "uqi");
+    break;
+
+  case EN_US:
+    strcpy (LangStr, "en-US");
+    break;
+
+  case ENG:
+    strcpy (LangStr, "eng");
+    break;
+
+  default:
+    strcpy (LangStr, "en-US");
+    break;
+  }
+  IsFound    = FALSE;
+
+  if (((EFI_HII_PACKAGE_HEADER *)UniBin)->Type == EFI_HII_PACKAGE_STRINGS) {
+    //
+    // Search the specified language package
+    //
+    while ((UniBin < UniPackgeEnd) && ((EFI_HII_PACKAGE_HEADER *)UniBin)->Type == EFI_HII_PACKAGE_STRINGS) {
+      if (strcmp (((EFI_HII_STRING_PACKAGE_HDR *)UniBin)->Language, LangStr) == 0) {
+        IsFound = TRUE;
+        break;
+      }
+      UniBin += ((EFI_HII_STRING_PACKAGE_HDR *)UniBin)->Header.Length;
+    }
+    //
+    //If not find the string ID, use the en eng or en-US instead.
+    //
+    if (!IsFound) {
+      UniBin     = (CHAR8 *) UniPackge + 4;
+
+      while ((UniBin < UniPackgeEnd) && ((EFI_HII_PACKAGE_HEADER *)UniBin)->Type == EFI_HII_PACKAGE_STRINGS) {
+        if ((strcmp (((EFI_HII_STRING_PACKAGE_HDR *)UniBin)->Language, "en") == 0)    \
+          || (strcmp (((EFI_HII_STRING_PACKAGE_HDR *)UniBin)->Language, "en-US") == 0) \
+          || (strcmp (((EFI_HII_STRING_PACKAGE_HDR *)UniBin)->Language, "eng") == 0)   \
+          ) {
+          IsFound = TRUE;
+          break;
+        }
+        UniBin += ((EFI_HII_STRING_PACKAGE_HDR *)UniBin)->Header.Length;
+      }
+    }
+     //
+     //If not still find the string ID, use the first one instead.
+     //
+     Status = GetStringByOffset (
+                UniPackge,
+                (UINT8 *)UniBin,
+                VarDefaultNameId,
+                IsFound,
+                VarDefaultName
+                );
+     if (!EFI_ERROR (Status)) {
+       goto Done;
+     }
+    //
+    //If not find the specified string in UQI package, we use the en en-us eng or uqi insteadly
+    //
+    IsFound    = FALSE;
+    UniBin     = (CHAR8 *) UniPackge + 4;
+
+    while ((UniBin < UniPackgeEnd) && ((EFI_HII_PACKAGE_HEADER *)UniBin)->Type == EFI_HII_PACKAGE_STRINGS) {
+      if (strcmp (((EFI_HII_STRING_PACKAGE_HDR *)UniBin)->Language, "en") == 0) {
+        IsFound = TRUE;
+        break;
+      }
+      UniBin += ((EFI_HII_STRING_PACKAGE_HDR *)UniBin)->Header.Length;
+    }
+    Status = GetStringByOffset (
+              UniPackge,
+              (UINT8 *)UniBin,
+              VarDefaultNameId,
+              IsFound,
+              VarDefaultName
+              );
+    if (!EFI_ERROR (Status)) {
+      goto Done;
+    }
+
+    IsFound    = FALSE;
+    UniBin     = (CHAR8 *) UniPackge + 4;
+
+    while ((UniBin < UniPackgeEnd) && ((EFI_HII_PACKAGE_HEADER *)UniBin)->Type == EFI_HII_PACKAGE_STRINGS) {
+      if (strcmp (((EFI_HII_STRING_PACKAGE_HDR *)UniBin)->Language, "en-US") == 0) {
+        IsFound = TRUE;
+        break;
+      }
+      UniBin += ((EFI_HII_STRING_PACKAGE_HDR *)UniBin)->Header.Length;
+    }
+    Status = GetStringByOffset (
+              UniPackge,
+              (UINT8 *)UniBin,
+              VarDefaultNameId,
+              IsFound,
+              VarDefaultName
+              );
+    if (!EFI_ERROR (Status)) {
+      goto Done;
+    }
+
+    IsFound    = FALSE;
+    UniBin     = (CHAR8 *) UniPackge + 4;
+
+    while ((UniBin < UniPackgeEnd) && ((EFI_HII_PACKAGE_HEADER *)UniBin)->Type == EFI_HII_PACKAGE_STRINGS) {
+      if (strcmp (((EFI_HII_STRING_PACKAGE_HDR *)UniBin)->Language, "eng") == 0) {
+        IsFound = TRUE;
+        break;
+      }
+      UniBin += ((EFI_HII_STRING_PACKAGE_HDR *)UniBin)->Header.Length;
+    }
+    Status = GetStringByOffset (
+              UniPackge,
+              (UINT8 *)UniBin,
+              VarDefaultNameId,
+              IsFound,
+              VarDefaultName
+              );
+    if (!EFI_ERROR (Status)) {
+      goto Done;
+    }
+
+    IsFound    = FALSE;
+    UniBin     = (CHAR8 *) UniPackge + 4;
+
+    while ((UniBin < UniPackgeEnd) && ((EFI_HII_PACKAGE_HEADER *)UniBin)->Type == EFI_HII_PACKAGE_STRINGS) {
+      if (strcmp (((EFI_HII_STRING_PACKAGE_HDR *)UniBin)->Language, "uqi") == 0) {
+        IsFound = TRUE;
+        break;
+      }
+      UniBin += ((EFI_HII_STRING_PACKAGE_HDR *)UniBin)->Header.Length;
+    }
+    Status = GetStringByOffset (
+              UniPackge,
+              (UINT8 *)UniBin,
+              VarDefaultNameId,
+              IsFound,
+              VarDefaultName
+              );
+    if (!EFI_ERROR (Status)) {
+      goto Done;
+    }
+  }
+
+Done:
+  if (EFI_ERROR (Status)) {
+    *VarDefaultName = NULL;
+    return EFI_NOT_FOUND;
+  }
+
+  if (CachedStringList != NULL) {
+    if (CachedStringList->CachedIdNum >= CachedStringList->MaxIdNum) {
+      TempBuffer = calloc (sizeof (STRING_INFO), CachedStringList->MaxIdNum + STRING_NUMBER);
+      if (TempBuffer == NULL) {
+        printf ("Fail to allocate memory! \n");
+        free (*VarDefaultName);
+        *VarDefaultName = NULL;
+        return EFI_OUT_OF_RESOURCES;
+      }
+      CopyMem (TempBuffer, CachedStringList->StringInfoList, sizeof (STRING_INFO) * CachedStringList->MaxIdNum);
+      FreePool (CachedStringList->StringInfoList);
+      CachedStringList->StringInfoList = TempBuffer;
+      CachedStringList->MaxIdNum = CachedStringList->MaxIdNum + STRING_NUMBER;
+    }
+    CachedStringList->StringInfoList[CachedStringList->CachedIdNum].StringId = VarDefaultNameId;
+    CachedStringList->StringInfoList[CachedStringList->CachedIdNum].String   = *VarDefaultName;
+    CachedStringList->CachedIdNum ++;
+  }
+  return EFI_SUCCESS;
+}
+
+/**
+  Get the variable Guid and Name by the variableId and FormSetOrder.
+
+  @param  FormSet        The pointer to the formset.
+  @param  FormSet        The pointer to the form.
+  @param  ListEntry      The pointer to the LIST_ENTRY.
+
+  @return EFI_SUCCESS
+  @return EFI_NOT_FOUND  If not find the the variable, or the variable doesn't belong to EfiVarStore or VarStore.
+**/
+static
+EFI_STATUS
+GetGuidNameByVariableId (
+  IN       FORM_BROWSER_FORMSET    *FormSet,
+  IN  OUT  FORM_BROWSER_STATEMENT  *Question,
+  IN       LIST_ENTRY              *ListEntry
+  )
+{
+  FORMSET_STORAGE    *CurNode;
+  LIST_ENTRY         *Link;
+  LIST_ENTRY         *StorageListHead;
+  EFI_STATUS         Status;
+  CHAR16             *EfiVariableName;
+
+  StorageListHead       = ListEntry;
+  CurNode               = NULL;
+  Status                = EFI_SUCCESS;
+  EfiVariableName       = NULL;
+
+  Link = GetFirstNode (StorageListHead);
+  while (!IsNull (StorageListHead, Link)) {
+    CurNode = FORMSET_STORAGE_FROM_LINK (Link);
+
+    if ((FormSet->FormSetOrder == CurNode->FormSetOrder) \
+      && (Question->VarStoreId == CurNode->VarStoreId)
+      ) {
+      //
+      // Copy type to question to avoid the case that EfiVarStore and VarStore have the same Guid and name.
+      //
+      Question->Type           = CurNode->Type;
+      Question->NewEfiVarstore = CurNode->NewEfiVarstore;
+      Question->Attributes     = CurNode->Attributes;
+
+      if (CurNode->Type == EFI_IFR_VARSTORE_EFI_OP) {
+        CopyMem (&Question->Guid, &CurNode->Guid, sizeof (EFI_GUID));
+        //
+        // If the first time to access the old EfiVarStore, need to sync the variable name
+        //
+        if (!CurNode->NewEfiVarstore) {
+          if (CurNode->Buffer == NULL) {
+            CurNode->Buffer = malloc (Question->StorageWidth);
+          }
+          if (CurNode->Name == NULL) {
+            Status  = FindDefaultName (
+                      &(FormSet->EnUsStringList),
+                      FormSet->UnicodeBinary,
+                      Question->VarStoreInfo.VarName,
+                      EN_US,
+                      &EfiVariableName
+                     );
+            if (EFI_ERROR(Status)) {
+              return Status;
+            }
+            CurNode->Name = EfiVariableName;
+          }
+          if (CurNode->Size == 0) {
+            CurNode->Size = Question->StorageWidth;
+          }
+        }
+        //
+        // Check whether the Efivariable variable name is valid.
+        //
+         if ((CurNode->Name == NULL) || (FceStrLen (CurNode->Name) == 0)) {
+          StringPrint ("Error. The variable name of question is NULL. Its UQI is: ");
+          StringPrint("Q %04X ", Question->Uqi.HexNum);
+          LogUqi (Question->Uqi.Data);
+          StringPrint ("\n");
+          return EFI_ABORTED;
+        }
+        if (Question->VariableName == NULL) {
+          Question->VariableName = (CHAR16 *) malloc (2 * (FceStrLen ((CONST CHAR16 *)CurNode->Name) + 1));
+          if (Question->VariableName == NULL) {
+           return EFI_ABORTED;
+          }
+        }
+        StrCpy (Question->VariableName, CurNode->Name);
+
+        return EFI_SUCCESS;
+
+      } else if (CurNode->Type == EFI_IFR_VARSTORE_OP) {
+        CopyMem (&Question->Guid, &CurNode->Guid, sizeof (EFI_GUID));
+        if (Question->VariableName == NULL) {
+          Question->VariableName = (CHAR16 *) malloc (2 * (FceStrLen ((CONST CHAR16 *)CurNode->Name) + 1));
+          if (Question->VariableName == NULL) {
+           return EFI_ABORTED;
+          }
+        }
+        //
+        // Check whether the variable variable name is valid.
+        //
+         if ((CurNode->Name == NULL) || (FceStrLen (CurNode->Name) == 0)) {
+          StringPrint ("Error. The variable name of question is NULL. UQI:");
+          StringPrint("Q %04X ", Question->Uqi.HexNum);
+          LogUqi (Question->Uqi.Data);
+          StringPrint ("\n");
+          return EFI_ABORTED;
+        }
+        StrCpy (Question->VariableName, CurNode->Name);
+        return EFI_SUCCESS;
+      }
+    }
+    Link = GetNextNode (StorageListHead, Link);
+  }
+  return EFI_NOT_FOUND;
+}
+
+/**
+  Search the variable list according to the variable Guid and name, and return the pointer
+  of that Node.
+
+  @param  HiiObjList       The pointer to the Question
+  @param  VarName          The EFI variable name need to be updated to VarList
+  @param  Offset           The offset of the variable
+  @param  StorageListHead  The pointer to the LIST_ENTRY of Storage
+  @param  Vaue             The value in that value offset of the variable
+  @param  VarList          The dual pointer of Varlist
+
+  @return EFI_SUCCESS
+  @return EFI_NOT_FOUND
+**/
+EFI_STATUS
+SearchVarStorage (
+  IN     FORM_BROWSER_STATEMENT   *Question,
+  IN     CHAR16*                  VarName,
+  IN     UINT32                   Offset,
+  IN     LIST_ENTRY               *StorageListHead,
+  IN OUT CHAR8                    **Value,
+  IN OUT FORMSET_STORAGE          **VarList
+  )
+{
+  FORMSET_STORAGE   *CurNode;
+  LIST_ENTRY        *Link;
+  BOOLEAN           FindOrNot;
+
+  CurNode         = NULL;
+  FindOrNot       = FALSE;
+  *VarList        = NULL;
+  //
+  // Find Storage for this Question
+  //
+  Link = GetFirstNode (StorageListHead);
+  while (!IsNull (StorageListHead, Link)) {
+    CurNode = FORMSET_STORAGE_FROM_LINK (Link);
+    //
+    // Deal with the old EfiVarstore before UEFI2.31
+    //
+    if (!CompareGuid (&Question->Guid, &CurNode->Guid)          \
+      && (CurNode->Type == EFI_IFR_VARSTORE_EFI_OP)             \
+      && !CurNode->NewEfiVarstore                               \
+      && (Question->VariableName != NULL)                       \
+      && (CurNode->Name != NULL)                                \
+      && !FceStrCmp(Question->VariableName, CurNode->Name)
+      ) {
+      //
+      // If not multi-plaform support mode, take VarStore as the EfiVarStore. So If there are
+      // two variables with same guid same name, but different type, we will take as the same
+      // in general mode
+      //
+      if (mMultiPlatformParam.MultiPlatformOrNot && (CurNode->Type == Question->Type)) {
+        //
+        // check whether exist a old EFI_IFR_VARSTORE_EFI or not.
+        //
+        *Value = (CHAR8 *)CurNode->Buffer;
+        *VarList = CurNode;
+        FindOrNot  = TRUE;
+        break;
+      } else if (!mMultiPlatformParam.MultiPlatformOrNot) {
+        //
+        // check whether exist a old EFI_IFR_VARSTORE_EFI or not.
+        //
+        *Value = (CHAR8 *)CurNode->Buffer;
+        *VarList = CurNode;
+        FindOrNot  = TRUE;
+        break;
+      }
+    }
+
+    if (!CompareGuid (&Question->Guid, &CurNode->Guid)           \
+      && (CurNode->Name != NULL)                                   \
+      && (Question->VariableName != NULL)                          \
+      && !FceStrCmp(Question->VariableName, CurNode->Name)
+      ) {
+      //
+      // If not multi-plaform support mode, take VarStore as the EfiVarStore. So If there are
+      // two variables with same guid same name, but different type, we will take as the same
+      // in general mode
+      //
+      if (mMultiPlatformParam.MultiPlatformOrNot && (CurNode->Type == Question->Type)) {
+        //
+        // If matched, get the address of EFI_IFR_VARSTORE data.
+        //
+        *Value     = (CHAR8 *)(CurNode->Buffer + Offset);
+        *VarList   = CurNode;
+        FindOrNot  = TRUE;
+        break;
+      } else if (!mMultiPlatformParam.MultiPlatformOrNot) {
+        //
+        // If matched, get the address of EFI_IFR_VARSTORE data.
+        //
+        *Value     = (CHAR8 *)(CurNode->Buffer + Offset);
+        *VarList   = CurNode;
+        FindOrNot  = TRUE;
+        break;
+      }
+    }
+    Link = GetNextNode (StorageListHead, Link);
+  }
+  if (!FindOrNot) {
+    return EFI_NOT_FOUND;
+  }
+  return EFI_SUCCESS;
+}
+
+/**
+  Get the string based on the StringId and HII Package List Handle.
+
+  @param  Token                  The String's ID.
+  @param  HiiHandle              The package list in the HII database to search for
+                                 the specified string.
+
+  @return The output string.
+
+**/
+CHAR16 *
+GetToken (
+  IN  EFI_STRING_ID                Token,
+  IN  UINT8                        *UniPackge
+  )
+{
+  CHAR16      *VarDefaultName;
+  EFI_STATUS  Status;
+
+  Status = EFI_SUCCESS;
+
+  if (UniPackge == NULL) {
+    return NULL;
+  }
+
+  Status  = FindDefaultName (
+              NULL,
+              UniPackge,
+              Token,
+              EN_US,
+              &VarDefaultName
+              );
+  if (EFI_ERROR (Status)) {
+    return NULL;
+  }
+
+  return VarDefaultName;
+}
+
+/**
+  Initialize Statement header members.
+
+  @param  OpCodeData             Pointer of the raw OpCode data.
+  @param  FormSet                Pointer of the current FormSe.
+  @param  Form                   Pointer of the current Form.
+
+  @return The Statement.
+
+**/
+FORM_BROWSER_STATEMENT *
+CreateStatement (
+  IN UINT8                        *OpCodeData,
+  IN OUT FORM_BROWSER_FORMSET     *FormSet,
+  IN OUT FORM_BROWSER_FORM        *Form
+  )
+{
+  FORM_BROWSER_STATEMENT    *Statement;
+  EFI_IFR_STATEMENT_HEADER  *StatementHdr;
+
+  if (Form == NULL) {
+    //
+    // We are currently not in a Form Scope, so just skip this Statement
+    //
+    return NULL;
+  }
+
+  Statement = &FormSet->StatementBuffer[mStatementIndex];
+  mStatementIndex++;
+
+  InitializeListHead (&Statement->DefaultListHead);
+  InitializeListHead (&Statement->OptionListHead);
+  InitializeListHead (&Statement->InconsistentListHead);
+  InitializeListHead (&Statement->NoSubmitListHead);
+  InitializeListHead (&Statement->WarningListHead);
+
+  Statement->Signature = FORM_BROWSER_STATEMENT_SIGNATURE;
+
+  Statement->Operand = ((EFI_IFR_OP_HEADER *) OpCodeData)->OpCode;
+  Statement->QuestionReferToBitField = FALSE;
+
+  StatementHdr = (EFI_IFR_STATEMENT_HEADER *) (OpCodeData + sizeof (EFI_IFR_OP_HEADER));
+  CopyMem (&Statement->Prompt, &StatementHdr->Prompt, sizeof (EFI_STRING_ID));
+  CopyMem (&Statement->Help, &StatementHdr->Help, sizeof (EFI_STRING_ID));
+
+  if (mInScopeSuppress) {
+    Statement->SuppressExpression = mSuppressExpression;
+  }
+
+  if (mInScopeGrayOut) {
+    Statement->GrayOutExpression = mGrayOutExpression;
+  }
+
+
+  if (mInScopeDisable) {
+    Statement->DisableExpression = mDisableExpression;
+  }
+
+  Statement->InSubtitle = mInScopeSubtitle;
+
+  //
+  // Insert this Statement into current Form
+  //
+  InsertTailList (&Form->StatementListHead, &Statement->Link);
+
+  return Statement;
+}
+
+/**
+  Initialize Question's members.
+
+  @param  OpCodeData             Pointer of the raw OpCode data.
+  @param  FormSet                Pointer of the current FormSet.
+  @param  Form                   Pointer of the current Form.
+
+  @return The Question.
+
+**/
+FORM_BROWSER_STATEMENT *
+CreateQuestion (
+  IN UINT8                        *OpCodeData,
+  IN OUT FORM_BROWSER_FORMSET     *FormSet,
+  IN OUT FORM_BROWSER_FORM        *Form
+  )
+{
+  FORM_BROWSER_STATEMENT   *Statement;
+  EFI_IFR_QUESTION_HEADER  *QuestionHdr;
+  LIST_ENTRY               *Link;
+  FORMSET_STORAGE          *Storage;
+  NAME_VALUE_NODE          *NameValueNode;
+
+  Statement = CreateStatement (OpCodeData, FormSet, Form);
+  if (Statement == NULL) {
+    return NULL;
+  }
+
+  QuestionHdr = (EFI_IFR_QUESTION_HEADER *) (OpCodeData + sizeof (EFI_IFR_OP_HEADER));
+  CopyMem (&Statement->QuestionId, &QuestionHdr->QuestionId, sizeof (EFI_QUESTION_ID));
+  CopyMem (&Statement->VarStoreId, &QuestionHdr->VarStoreId, sizeof (EFI_VARSTORE_ID));
+  CopyMem (&Statement->VarStoreInfo.VarOffset, &QuestionHdr->VarStoreInfo.VarOffset, sizeof (UINT16));
+
+  Statement->QuestionFlags = QuestionHdr->Flags;
+
+  Statement->FormSetOrder = mFormSetOrderParse;
+
+  if (Statement->VarStoreId == 0) {
+    //
+    // VarStoreId of zero indicates no variable storage
+    //
+    return Statement;
+  }
+
+  //
+  // Find Storage for this Question
+  //
+  Link = GetFirstNode (FormSet->StorageListHead);
+  while (!IsNull (FormSet->StorageListHead, Link)) {
+    Storage = FORMSET_STORAGE_FROM_LINK (Link);
+
+    if ((Storage->VarStoreId == Statement->VarStoreId)
+      && (Storage->FormSetOrder == Statement->FormSetOrder)) {
+      Statement->Storage = Storage;
+      break;
+    }
+
+    Link = GetNextNode (FormSet->StorageListHead, Link);
+  }
+  ASSERT (Statement->Storage != NULL);
+
+  if (Statement->Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) {
+    Statement->VariableName = GetToken (Statement->VarStoreInfo.VarName, FormSet->UnicodeBinary);
+    ASSERT (Statement->VariableName != NULL);
+    //
+    // Insert to Name/Value varstore list
+    //
+    NameValueNode = AllocateZeroPool (sizeof (NAME_VALUE_NODE));
+    ASSERT (NameValueNode != NULL);
+    NameValueNode->Signature = NAME_VALUE_NODE_SIGNATURE;
+    NameValueNode->Name = FceAllocateCopyPool (FceStrSize (Statement->VariableName), Statement->VariableName);
+    ASSERT (NameValueNode->Name != NULL);
+    NameValueNode->Value = AllocateZeroPool (0x10);
+    ASSERT (NameValueNode->Value != NULL);
+    NameValueNode->EditValue = AllocateZeroPool (0x10);
+    ASSERT (NameValueNode->EditValue != NULL);
+
+    InsertTailList (&Statement->Storage->NameValueListHead, &NameValueNode->Link);
+  }
+
+  return Statement;
+}
+
+
+/**
+  Allocate a FORM_EXPRESSION node.
+
+  @param  Form                   The Form associated with this Expression
+
+  @return Pointer to a FORM_EXPRESSION data structure.
+
+**/
+FORM_EXPRESSION *
+CreateExpression (
+  IN OUT FORM_BROWSER_FORM        *Form
+  )
+{
+  FORM_EXPRESSION  *Expression;
+
+  Expression = AllocateZeroPool (sizeof (FORM_EXPRESSION));
+  ASSERT (Expression != NULL);
+  Expression->Signature = FORM_EXPRESSION_SIGNATURE;
+  InitializeListHead (&Expression->OpCodeListHead);
+
+  return Expression;
+}
+
+
+/**
+  Allocate a FORMSET_STORAGE data structure and insert to FormSet Storage List.
+
+  @param  FormSet                Pointer of the current FormSet
+
+  @return Pointer to a FORMSET_STORAGE data structure.
+
+**/
+FORMSET_STORAGE *
+CreateStorage (
+  IN FORM_BROWSER_FORMSET  *FormSet
+  )
+{
+  FORMSET_STORAGE  *Storage;
+
+  Storage = AllocateZeroPool (sizeof (FORMSET_STORAGE));
+  ASSERT (Storage != NULL);
+  Storage->Signature = FORMSET_STORAGE_SIGNATURE;
+  InitializeListHead (&Storage->NameValueListHead);
+  InsertTailList (FormSet->StorageListHead, &Storage->Link);
+
+  return Storage;
+}
+
+/**
+  Free resources of a Expression.
+
+  @param  FormSet                Pointer of the Expression
+
+**/
+VOID
+DestroyExpression (
+  IN FORM_EXPRESSION   *Expression
+  )
+{
+  LIST_ENTRY         *Link;
+  EXPRESSION_OPCODE  *OpCode;
+  LIST_ENTRY         *SubExpressionLink;
+  FORM_EXPRESSION    *SubExpression;
+
+  while (!IsListEmpty (&Expression->OpCodeListHead)) {
+    Link = GetFirstNode (&Expression->OpCodeListHead);
+    OpCode = EXPRESSION_OPCODE_FROM_LINK (Link);
+    RemoveEntryList (&OpCode->Link);
+
+    if (OpCode->ValueList != NULL) {
+      FreePool (OpCode->ValueList);
+    }
+
+    if (OpCode->ValueName != NULL) {
+      FreePool (OpCode->ValueName);
+    }
+
+    if (OpCode->MapExpressionList.ForwardLink != NULL) {
+      while (!IsListEmpty (&OpCode->MapExpressionList)) {
+        SubExpressionLink = GetFirstNode(&OpCode->MapExpressionList);
+        SubExpression     = FORM_EXPRESSION_FROM_LINK (SubExpressionLink);
+        RemoveEntryList(&SubExpression->Link);
+        DestroyExpression (SubExpression);
+      }
+    }
+  }
+
+  //
+  // Free this Expression
+  //
+  FreePool (Expression);
+}
+
+
+/**
+  Free resources of a storage.
+
+  @param  Storage                Pointer of the storage
+
+**/
+VOID
+DestroyStorage (
+  IN FORMSET_STORAGE   *Storage
+  )
+{
+  LIST_ENTRY         *Link;
+  NAME_VALUE_NODE    *NameValueNode;
+
+  if (Storage == NULL) {
+    return;
+  }
+
+  if (Storage->Name != NULL) {
+    FreePool (Storage->Name);
+  }
+  if (Storage->Buffer != NULL) {
+    FreePool (Storage->Buffer);
+  }
+
+  while (!IsListEmpty (&Storage->NameValueListHead)) {
+    Link = GetFirstNode (&Storage->NameValueListHead);
+    NameValueNode = NAME_VALUE_NODE_FROM_LINK (Link);
+    RemoveEntryList (&NameValueNode->Link);
+
+    if (NameValueNode->Name != NULL) {
+      FreePool (NameValueNode->Name);
+    }
+    if (NameValueNode->Value != NULL) {
+      FreePool (NameValueNode->Value);
+    }
+    if (NameValueNode->EditValue != NULL) {
+      FreePool (NameValueNode->EditValue);
+    }
+    FreePool (NameValueNode);
+  }
+
+  FreePool (Storage);
+  Storage = NULL;
+}
+
+/**
+  Free resources allocated for all Storage in an LIST_ENTRY.
+
+  @param  FormSet                Pointer of the FormSet
+
+**/
+VOID
+DestroyAllStorage (
+  IN LIST_ENTRY    *StorageEntryListHead
+  )
+{
+  LIST_ENTRY              *Link;
+  FORMSET_STORAGE         *Storage;
+  //
+  // Parse Fromset one by one
+  //
+  if (StorageEntryListHead->ForwardLink != NULL) {
+    while (!IsListEmpty (StorageEntryListHead)) {
+      Link = GetFirstNode (StorageEntryListHead);
+      Storage = FORMSET_STORAGE_FROM_LINK (Link);
+      RemoveEntryList (&Storage->Link);
+
+      DestroyStorage (Storage);
+    }
+  }
+  StorageEntryListHead = NULL;
+}
+
+/**
+  Free resources of a Statement.
+
+  @param  FormSet                Pointer of the FormSet
+  @param  Statement              Pointer of the Statement
+
+**/
+VOID
+DestroyStatement (
+  IN     FORM_BROWSER_FORMSET    *FormSet,
+  IN OUT FORM_BROWSER_STATEMENT  *Statement
+  )
+{
+  LIST_ENTRY        *Link;
+  QUESTION_DEFAULT  *Default;
+  QUESTION_OPTION   *Option;
+  FORM_EXPRESSION   *Expression;
+
+  //
+  // Free Default value List
+  //
+  while (!IsListEmpty (&Statement->DefaultListHead)) {
+    Link = GetFirstNode (&Statement->DefaultListHead);
+    Default = QUESTION_DEFAULT_FROM_LINK (Link);
+    RemoveEntryList (&Default->Link);
+
+    if (Default->Value.Buffer != NULL) {
+      FreePool(Default->Value.Buffer);
+    }
+    FreePool (Default);
+  }
+
+  //
+  // Free Options List
+  //
+  while (!IsListEmpty (&Statement->OptionListHead)) {
+    Link = GetFirstNode (&Statement->OptionListHead);
+    Option = QUESTION_OPTION_FROM_LINK (Link);
+    RemoveEntryList (&Option->Link);
+
+    FreePool (Option);
+  }
+
+  //
+  // Free Inconsistent List
+  //
+  while (!IsListEmpty (&Statement->InconsistentListHead)) {
+    Link = GetFirstNode (&Statement->InconsistentListHead);
+    Expression = FORM_EXPRESSION_FROM_LINK (Link);
+    RemoveEntryList (&Expression->Link);
+
+    DestroyExpression (Expression);
+  }
+
+  //
+  // Free NoSubmit List
+  //
+  while (!IsListEmpty (&Statement->NoSubmitListHead)) {
+    Link = GetFirstNode (&Statement->NoSubmitListHead);
+    Expression = FORM_EXPRESSION_FROM_LINK (Link);
+    RemoveEntryList (&Expression->Link);
+
+    DestroyExpression (Expression);
+  }
+
+  //
+  // Free WarningIf List
+  //
+  while (!IsListEmpty (&Statement->WarningListHead)) {
+    Link = GetFirstNode (&Statement->WarningListHead);
+    Expression = FORM_EXPRESSION_FROM_LINK (Link);
+    RemoveEntryList (&Expression->Link);
+
+    DestroyExpression (Expression);
+  }
+  if (Statement->VariableName != NULL) {
+    FreePool (Statement->VariableName);
+  }
+  if (Statement->BufferValue != NULL) {
+    FreePool (Statement->BufferValue);
+  }
+}
+
+/**
+  Free resources of a Form.
+
+  @param  FormSet                Pointer of the FormSet
+  @param  Form                   Pointer of the Form.
+
+**/
+VOID
+DestroyForm (
+  IN     FORM_BROWSER_FORMSET  *FormSet,
+  IN OUT FORM_BROWSER_FORM     *Form
+  )
+{
+  LIST_ENTRY              *Link;
+  FORM_EXPRESSION         *Expression;
+  FORM_BROWSER_STATEMENT  *Statement;
+
+  //
+  // Free Form Expressions
+  //
+  while (!IsListEmpty (&Form->ExpressionListHead)) {
+    Link = GetFirstNode (&Form->ExpressionListHead);
+    Expression = FORM_EXPRESSION_FROM_LINK (Link);
+    RemoveEntryList (&Expression->Link);
+
+    DestroyExpression (Expression);
+  }
+
+  //
+  // Free Statements/Questions
+  //
+  while (!IsListEmpty (&Form->StatementListHead)) {
+    Link = GetFirstNode (&Form->StatementListHead);
+    Statement = FORM_BROWSER_STATEMENT_FROM_LINK (Link);
+    RemoveEntryList (&Statement->Link);
+
+    DestroyStatement (FormSet, Statement);
+  }
+
+  //
+  // Free this Form
+  //
+  FreePool (Form);
+}
+
+
+/**
+  Free resources allocated for a FormSet.
+
+  @param  FormSet                Pointer of the FormSet
+
+**/
+VOID
+DestroyFormSet (
+  IN FORM_BROWSER_FORMSET  *FormSet
+  )
+{
+  LIST_ENTRY            *Link;
+  FORMSET_DEFAULTSTORE  *DefaultStore;
+  FORM_EXPRESSION       *Expression;
+  FORM_BROWSER_FORM     *Form;
+  UINT16                Index;
+
+  //
+  // Free FormSet Default Store
+  //
+  if (FormSet->DefaultStoreListHead.ForwardLink != NULL) {
+    while (!IsListEmpty (&FormSet->DefaultStoreListHead)) {
+      Link = GetFirstNode (&FormSet->DefaultStoreListHead);
+      DefaultStore = FORMSET_DEFAULTSTORE_FROM_LINK (Link);
+      RemoveEntryList (&DefaultStore->Link);
+
+      FreePool (DefaultStore);
+    }
+  }
+
+  //
+  // Free Formset Expressions
+  //
+  while (!IsListEmpty (&FormSet->ExpressionListHead)) {
+    Link = GetFirstNode (&FormSet->ExpressionListHead);
+    Expression = FORM_EXPRESSION_FROM_LINK (Link);
+    RemoveEntryList (&Expression->Link);
+
+    DestroyExpression (Expression);
+  }
+
+  //
+  // Free Forms
+  //
+  if (FormSet->FormListHead.ForwardLink != NULL) {
+    while (!IsListEmpty (&FormSet->FormListHead)) {
+      Link = GetFirstNode (&FormSet->FormListHead);
+      Form = FORM_BROWSER_FORM_FROM_LINK (Link);
+      RemoveEntryList (&Form->Link);
+
+      DestroyForm (FormSet, Form);
+    }
+  }
+
+  if (FormSet->StatementBuffer != NULL) {
+    FreePool (FormSet->StatementBuffer);
+  }
+  if (FormSet->ExpressionBuffer != NULL) {
+    FreePool (FormSet->ExpressionBuffer);
+  }
+  if (FormSet->EnUsStringList.StringInfoList != NULL) {
+    for (Index = 0; Index < FormSet->EnUsStringList.CachedIdNum; Index ++) {
+      FreePool (FormSet->EnUsStringList.StringInfoList[Index].String);
+    }
+    FreePool (FormSet->EnUsStringList.StringInfoList);
+  }
+  if (FormSet->UqiStringList.StringInfoList != NULL) {
+    for (Index = 0; Index < FormSet->UqiStringList.CachedIdNum; Index ++) {
+      FreePool (FormSet->UqiStringList.StringInfoList[Index].String);
+    }
+    FreePool (FormSet->UqiStringList.StringInfoList);
+  }
+
+  FreePool (FormSet);
+}
+
+/**
+  Free resources allocated for all FormSet in an LIST_ENTRY.
+
+  @param  FormSet                Pointer of the FormSet
+
+**/
+VOID
+DestroyAllFormSet (
+  IN LIST_ENTRY    *FormSetEntryListHead
+  )
+{
+  LIST_ENTRY              *Link;
+  FORM_BROWSER_FORMSET    *FormSet;
+  //
+  // Parse Fromset one by one
+  //
+  if (FormSetEntryListHead->ForwardLink != NULL) {
+    while (!IsListEmpty (FormSetEntryListHead)) {
+      Link = GetFirstNode (FormSetEntryListHead);
+      FormSet = FORM_BROWSER_FORMSET_FROM_LINK (Link);
+      RemoveEntryList (&FormSet->Link);
+      DestroyFormSet (FormSet);
+    }
+  }
+}
+
+/**
+  Tell whether this Operand is an Expression OpCode or not
+
+  @param  Operand                Operand of an IFR OpCode.
+
+  @retval TRUE                   This is an Expression OpCode.
+  @retval FALSE                  Not an Expression OpCode.
+
+**/
+BOOLEAN
+IsExpressionOpCode (
+  IN UINT8              Operand
+  )
+{
+  if (((Operand >= EFI_IFR_EQ_ID_VAL_OP) && (Operand <= EFI_IFR_NOT_OP)) ||
+      ((Operand >= EFI_IFR_MATCH_OP) && (Operand <= EFI_IFR_SET_OP))  ||
+      ((Operand >= EFI_IFR_EQUAL_OP) && (Operand <= EFI_IFR_SPAN_OP)) ||
+      (Operand == EFI_IFR_CATENATE_OP) ||
+      (Operand == EFI_IFR_TO_LOWER_OP) ||
+      (Operand == EFI_IFR_TO_UPPER_OP) ||
+      (Operand == EFI_IFR_MAP_OP)      ||
+      (Operand == EFI_IFR_VERSION_OP)  ||
+      (Operand == EFI_IFR_SECURITY_OP)) {
+    return TRUE;
+  } else {
+    return FALSE;
+  }
+}
+
+
+/**
+  Calculate number of Statemens(Questions) and Expression OpCodes.
+
+  @param  FormSet                The FormSet to be counted.
+  @param  NumberOfStatement      Number of Statemens(Questions)
+  @param  NumberOfExpression     Number of Expression OpCodes
+
+**/
+VOID
+CountOpCodes (
+  IN  FORM_BROWSER_FORMSET  *FormSet,
+  IN OUT  UINT16            *NumberOfStatement,
+  IN OUT  UINT16            *NumberOfExpression
+  )
+{
+  UINT16  StatementCount;
+  UINT16  ExpressionCount;
+  UINT8   *OpCodeData;
+  UINTN   Offset;
+  UINTN   OpCodeLen;
+
+  Offset = 0;
+  StatementCount = 0;
+  ExpressionCount = 0;
+
+  while (Offset < FormSet->IfrBinaryLength) {
+    OpCodeData = FormSet->IfrBinaryData + Offset;
+    OpCodeLen = ((EFI_IFR_OP_HEADER *) OpCodeData)->Length;
+    Offset += OpCodeLen;
+
+    if (IsExpressionOpCode (((EFI_IFR_OP_HEADER *) OpCodeData)->OpCode)) {
+      ExpressionCount++;
+    } else {
+      StatementCount++;
+    }
+  }
+
+  *NumberOfStatement = StatementCount;
+  *NumberOfExpression = ExpressionCount;
+}
+
+
+
+/**
+  Parse opcodes in the formset IFR binary.
+
+  @param  FormSet                Pointer of the FormSet data structure.
+
+  @retval EFI_SUCCESS            Opcode parse success.
+  @retval Other                  Opcode parse fail.
+
+**/
+EFI_STATUS
+ParseOpCodes (
+  IN FORM_BROWSER_FORMSET              *FormSet
+  )
+{
+  EFI_STATUS              Status;
+  UINT16                  Index;
+  FORM_BROWSER_FORM       *CurrentForm;
+  FORM_BROWSER_STATEMENT  *CurrentStatement;
+  EXPRESSION_OPCODE       *ExpressionOpCode;
+  FORM_EXPRESSION         *CurrentExpression;
+  UINT8                   Operand;
+  UINT8                   Scope;
+  UINTN                   OpCodeOffset;
+  UINTN                   OpCodeLength;
+  UINT8                   *OpCodeData;
+  UINT8                   ScopeOpCode;
+  FORMSET_STORAGE         *Storage;
+  FORMSET_STORAGE         *TempStorage;
+  FORMSET_DEFAULTSTORE    *DefaultStore;
+  QUESTION_DEFAULT        *CurrentDefault;
+  QUESTION_OPTION         *CurrentOption;
+  UINT8                   Width;
+  CHAR8                   *AsciiString;
+  UINT16                  NumberOfStatement;
+  UINT16                  NumberOfExpression;
+  BOOLEAN                 SuppressForQuestion;
+  BOOLEAN                 SuppressForOption;
+  BOOLEAN                 InScopeOptionSuppress;
+  FORM_EXPRESSION         *OptionSuppressExpression;
+  BOOLEAN                 InScopeFormSuppress;
+  FORM_EXPRESSION         *FormSuppressExpression;
+  UINT16                  DepthOfDisable;
+  BOOLEAN                 OpCodeDisabled;
+  BOOLEAN                 SingleOpCodeExpression;
+  BOOLEAN                 InScopeDefault;
+  EFI_HII_VALUE           *Value;
+  UINT8                   MapScopeDepth;
+  LIST_ENTRY              *Link;
+  FORMSET_STORAGE         *VarStorage;
+  LIST_ENTRY              *MapExpressionList;
+  EFI_VARSTORE_ID         TempVarstoreId;
+  BOOLEAN                 ConstantFlag;
+  FORMSET_DEFAULTSTORE    *PreDefaultStore;
+  LIST_ENTRY              *DefaultLink;
+  BOOLEAN                 HaveInserted;
+  BOOLEAN                 BitFieldStorage;
+  UINT16                  TotalBits;
+
+  mInScopeSubtitle         = FALSE;
+  SuppressForQuestion      = FALSE;
+  SuppressForOption        = FALSE;
+  InScopeFormSuppress      = FALSE;
+  mInScopeSuppress         = FALSE;
+  InScopeOptionSuppress    = FALSE;
+  mInScopeGrayOut          = FALSE;
+  mInScopeDisable          = FALSE;
+  DepthOfDisable           = 0;
+  OpCodeDisabled           = FALSE;
+  SingleOpCodeExpression   = FALSE;
+  InScopeDefault           = FALSE;
+  CurrentExpression        = NULL;
+  CurrentDefault           = NULL;
+  CurrentOption            = NULL;
+  OptionSuppressExpression = NULL;
+  FormSuppressExpression   = NULL;
+  MapScopeDepth            = 0;
+  Link                     = NULL;
+  VarStorage               = NULL;
+  MapExpressionList        = NULL;
+  TempVarstoreId           = 0;
+  ConstantFlag             = TRUE;
+  BitFieldStorage          = FALSE;
+
+  //
+  // Get the number of Statements and Expressions
+  //
+  CountOpCodes (FormSet, &NumberOfStatement, &NumberOfExpression);
+
+  mStatementIndex = 0;
+  FormSet->StatementBuffer = AllocateZeroPool (NumberOfStatement * sizeof (FORM_BROWSER_STATEMENT));
+  if (FormSet->StatementBuffer == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  mExpressionOpCodeIndex = 0;
+  FormSet->ExpressionBuffer = AllocateZeroPool (NumberOfExpression * sizeof (EXPRESSION_OPCODE));
+  if (FormSet->ExpressionBuffer == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  FormSet->StorageListHead = &mVarListEntry;
+  InitializeListHead (&FormSet->DefaultStoreListHead);
+  InitializeListHead (&FormSet->FormListHead);
+  InitializeListHead (&FormSet->ExpressionListHead);
+  ResetCurrentExpressionStack ();
+  ResetMapExpressionListStack ();
+
+  CurrentForm = NULL;
+  CurrentStatement = NULL;
+
+  ResetScopeStack ();
+
+  OpCodeOffset = 0;
+  while (OpCodeOffset < FormSet->IfrBinaryLength) {
+    OpCodeData = FormSet->IfrBinaryData + OpCodeOffset;
+
+    OpCodeLength = ((EFI_IFR_OP_HEADER *) OpCodeData)->Length;
+    OpCodeOffset += OpCodeLength;
+    Operand = ((EFI_IFR_OP_HEADER *) OpCodeData)->OpCode;
+    Scope = ((EFI_IFR_OP_HEADER *) OpCodeData)->Scope;
+
+    //
+    // If scope bit set, push onto scope stack
+    //
+    if (Scope != 0) {
+      PushScope (Operand);
+    }
+
+    if (OpCodeDisabled) {
+      //
+      // DisableIf Expression is evaluated to be TRUE, try to find its end.
+      // Here only cares the EFI_IFR_DISABLE_IF and EFI_IFR_END
+      //
+      if (Operand == EFI_IFR_DISABLE_IF_OP) {
+        DepthOfDisable++;
+      } else if (Operand == EFI_IFR_END_OP) {
+        Status = PopScope (&ScopeOpCode);
+        if (EFI_ERROR (Status)) {
+          return Status;
+        }
+
+        if (ScopeOpCode == EFI_IFR_DISABLE_IF_OP) {
+          if (DepthOfDisable == 0) {
+            mInScopeDisable = FALSE;
+            OpCodeDisabled = FALSE;
+          } else {
+            DepthOfDisable--;
+          }
+        }
+      }
+      continue;
+    }
+
+    if (IsExpressionOpCode (Operand)) {
+      ExpressionOpCode = &FormSet->ExpressionBuffer[mExpressionOpCodeIndex];
+      mExpressionOpCodeIndex++;
+
+      ExpressionOpCode->Signature = EXPRESSION_OPCODE_SIGNATURE;
+      ExpressionOpCode->Operand = Operand;
+      Value = &ExpressionOpCode->Value;
+
+      switch (Operand) {
+      case EFI_IFR_EQ_ID_VAL_OP:
+        CopyMem (&ExpressionOpCode->QuestionId, &((EFI_IFR_EQ_ID_VAL *) OpCodeData)->QuestionId, sizeof (EFI_QUESTION_ID));
+
+        Value->Type = EFI_IFR_TYPE_NUM_SIZE_16;
+        CopyMem (&Value->Value.u16, &((EFI_IFR_EQ_ID_VAL *) OpCodeData)->Value, sizeof (UINT16));
+        break;
+
+      case EFI_IFR_EQ_ID_ID_OP:
+        CopyMem (&ExpressionOpCode->QuestionId, &((EFI_IFR_EQ_ID_ID *) OpCodeData)->QuestionId1, sizeof (EFI_QUESTION_ID));
+        CopyMem (&ExpressionOpCode->QuestionId2, &((EFI_IFR_EQ_ID_ID *) OpCodeData)->QuestionId2, sizeof (EFI_QUESTION_ID));
+        break;
+
+      case EFI_IFR_EQ_ID_VAL_LIST_OP:
+        CopyMem (&ExpressionOpCode->QuestionId, &((EFI_IFR_EQ_ID_VAL_LIST *) OpCodeData)->QuestionId, sizeof (EFI_QUESTION_ID));
+        CopyMem (&ExpressionOpCode->ListLength, &((EFI_IFR_EQ_ID_VAL_LIST *) OpCodeData)->ListLength, sizeof (UINT16));
+        ExpressionOpCode->ValueList = FceAllocateCopyPool (ExpressionOpCode->ListLength * sizeof (UINT16), &((EFI_IFR_EQ_ID_VAL_LIST *) OpCodeData)->ValueList);
+        break;
+
+      case EFI_IFR_TO_STRING_OP:
+      case EFI_IFR_FIND_OP:
+        ExpressionOpCode->Format = (( EFI_IFR_TO_STRING *) OpCodeData)->Format;
+        break;
+
+      case EFI_IFR_STRING_REF1_OP:
+        Value->Type = EFI_IFR_TYPE_STRING;
+        CopyMem (&Value->Value.string, &(( EFI_IFR_STRING_REF1 *) OpCodeData)->StringId, sizeof (EFI_STRING_ID));
+        break;
+
+      case EFI_IFR_RULE_REF_OP:
+        ExpressionOpCode->RuleId = (( EFI_IFR_RULE_REF *) OpCodeData)->RuleId;
+        break;
+
+      case EFI_IFR_SPAN_OP:
+        ExpressionOpCode->Flags = (( EFI_IFR_SPAN *) OpCodeData)->Flags;
+        break;
+
+      case EFI_IFR_THIS_OP:
+        ASSERT (CurrentStatement != NULL);
+        ExpressionOpCode->QuestionId = CurrentStatement->QuestionId;
+        break;
+
+      case EFI_IFR_SECURITY_OP:
+        CopyMem (&ExpressionOpCode->Guid, &((EFI_IFR_SECURITY *) OpCodeData)->Permissions, sizeof (EFI_GUID));
+        break;
+
+      case EFI_IFR_GET_OP:
+      case EFI_IFR_SET_OP:
+        CopyMem (&TempVarstoreId, &((EFI_IFR_GET *) OpCodeData)->VarStoreId, sizeof (TempVarstoreId));
+        if (TempVarstoreId != 0) {
+          if (FormSet->StorageListHead->ForwardLink != NULL) {
+            Link = GetFirstNode (FormSet->StorageListHead);
+            while (!IsNull (FormSet->StorageListHead, Link)) {
+              VarStorage = FORMSET_STORAGE_FROM_LINK (Link);
+              if (VarStorage->VarStoreId == ((EFI_IFR_GET *) OpCodeData)->VarStoreId) {
+                ExpressionOpCode->VarStorage = VarStorage;
+                break;
+              }
+              Link = GetNextNode (FormSet->StorageListHead, Link);
+            }
+          }
+          if (ExpressionOpCode->VarStorage == NULL) {
+            //
+            // VarStorage is not found.
+            //
+            return EFI_INVALID_PARAMETER;
+          }
+        }
+        ExpressionOpCode->ValueType = ((EFI_IFR_GET *) OpCodeData)->VarStoreType;
+        switch (ExpressionOpCode->ValueType) {
+        case EFI_IFR_TYPE_BOOLEAN:
+        case EFI_IFR_TYPE_NUM_SIZE_8:
+          ExpressionOpCode->ValueWidth = 1;
+          break;
+
+        case EFI_IFR_TYPE_NUM_SIZE_16:
+        case EFI_IFR_TYPE_STRING:
+          ExpressionOpCode->ValueWidth = 2;
+          break;
+
+        case EFI_IFR_TYPE_NUM_SIZE_32:
+          ExpressionOpCode->ValueWidth = 4;
+          break;
+
+        case EFI_IFR_TYPE_NUM_SIZE_64:
+          ExpressionOpCode->ValueWidth = 8;
+          break;
+
+        case EFI_IFR_TYPE_DATE:
+          ExpressionOpCode->ValueWidth = (UINT8) sizeof (EFI_IFR_DATE);
+          break;
+
+        case EFI_IFR_TYPE_TIME:
+          ExpressionOpCode->ValueWidth = (UINT8) sizeof (EFI_IFR_TIME);
+          break;
+
+        case EFI_IFR_TYPE_REF:
+          ExpressionOpCode->ValueWidth = (UINT8) sizeof (EFI_IFR_REF);
+          break;
+
+        case EFI_IFR_TYPE_OTHER:
+        case EFI_IFR_TYPE_UNDEFINED:
+        case EFI_IFR_TYPE_ACTION:
+        case EFI_IFR_TYPE_BUFFER:
+        default:
+          //
+          // Invalid value type for Get/Set opcode.
+          //
+          return EFI_INVALID_PARAMETER;
+        }
+        CopyMem (&ExpressionOpCode->VarStoreInfo.VarName,   &((EFI_IFR_GET *) OpCodeData)->VarStoreInfo.VarName,   sizeof (EFI_STRING_ID));
+        CopyMem (&ExpressionOpCode->VarStoreInfo.VarOffset, &((EFI_IFR_GET *) OpCodeData)->VarStoreInfo.VarOffset, sizeof (UINT16));
+        if ((ExpressionOpCode->VarStorage != NULL) &&
+            ((ExpressionOpCode->VarStorage->Type == EFI_HII_VARSTORE_NAME_VALUE)
+            || ((ExpressionOpCode->VarStorage->Type == EFI_IFR_VARSTORE_EFI_OP) && !ExpressionOpCode->VarStorage->NewEfiVarstore))
+             ) {
+          ExpressionOpCode->ValueName = GetToken (ExpressionOpCode->VarStoreInfo.VarName, FormSet->UnicodeBinary);
+          if (ExpressionOpCode->ValueName == NULL) {
+            //
+            // String ID is invalid.
+            //
+            return EFI_INVALID_PARAMETER;
+          }
+        }
+        break;
+
+      case EFI_IFR_QUESTION_REF1_OP:
+        CopyMem (&ExpressionOpCode->QuestionId, &((EFI_IFR_EQ_ID_VAL_LIST *) OpCodeData)->QuestionId, sizeof (EFI_QUESTION_ID));
+        break;
+
+      case EFI_IFR_QUESTION_REF3_OP:
+        if (OpCodeLength >= sizeof (EFI_IFR_QUESTION_REF3_2)) {
+          CopyMem (&ExpressionOpCode->DevicePath, &(( EFI_IFR_QUESTION_REF3_2 *) OpCodeData)->DevicePath, sizeof (EFI_STRING_ID));
+
+          if (OpCodeLength >= sizeof (EFI_IFR_QUESTION_REF3_3)) {
+            CopyMem (&ExpressionOpCode->Guid, &(( EFI_IFR_QUESTION_REF3_3 *) OpCodeData)->Guid, sizeof (EFI_GUID));
+          }
+        }
+        break;
+
+      //
+      // constant
+      //
+      case EFI_IFR_TRUE_OP:
+        Value->Type = EFI_IFR_TYPE_BOOLEAN;
+        Value->Value.b = TRUE;
+        break;
+
+      case EFI_IFR_FALSE_OP:
+        Value->Type = EFI_IFR_TYPE_BOOLEAN;
+        Value->Value.b = FALSE;
+        break;
+
+      case EFI_IFR_ONE_OP:
+        Value->Type = EFI_IFR_TYPE_NUM_SIZE_8;
+        Value->Value.u8 = 1;
+        break;
+
+      case EFI_IFR_ZERO_OP:
+        Value->Type = EFI_IFR_TYPE_NUM_SIZE_8;
+        Value->Value.u8 = 0;
+        break;
+
+      case EFI_IFR_ONES_OP:
+        Value->Type = EFI_IFR_TYPE_NUM_SIZE_64;
+        Value->Value.u64 = 0xffffffffffffffffULL;
+        break;
+
+      case EFI_IFR_UINT8_OP:
+        Value->Type = EFI_IFR_TYPE_NUM_SIZE_8;
+        Value->Value.u8 = (( EFI_IFR_UINT8 *) OpCodeData)->Value;
+        break;
+
+      case EFI_IFR_UINT16_OP:
+        Value->Type = EFI_IFR_TYPE_NUM_SIZE_16;
+        CopyMem (&Value->Value.u16, &(( EFI_IFR_UINT16 *) OpCodeData)->Value, sizeof (UINT16));
+        break;
+
+      case EFI_IFR_UINT32_OP:
+        Value->Type = EFI_IFR_TYPE_NUM_SIZE_32;
+        CopyMem (&Value->Value.u32, &(( EFI_IFR_UINT32 *) OpCodeData)->Value, sizeof (UINT32));
+        break;
+
+      case EFI_IFR_UINT64_OP:
+        Value->Type = EFI_IFR_TYPE_NUM_SIZE_64;
+        CopyMem (&Value->Value.u64, &(( EFI_IFR_UINT64 *) OpCodeData)->Value, sizeof (UINT64));
+        break;
+
+      case EFI_IFR_UNDEFINED_OP:
+        Value->Type = EFI_IFR_TYPE_UNDEFINED;
+        break;
+
+      case EFI_IFR_VERSION_OP:
+        Value->Type = EFI_IFR_TYPE_NUM_SIZE_16;
+        break;
+
+      default:
+        break;
+      }
+      //
+      // Create sub expression nested in MAP opcode
+      //
+      if ((CurrentExpression == NULL) && (MapScopeDepth > 0)) {
+        CurrentExpression = CreateExpression (CurrentForm);
+        ASSERT (MapExpressionList != NULL);
+        InsertTailList (MapExpressionList, &CurrentExpression->Link);
+        if (Scope == 0) {
+          SingleOpCodeExpression = TRUE;
+        }
+      }
+      ASSERT (CurrentExpression != NULL);
+      InsertTailList (&CurrentExpression->OpCodeListHead, &ExpressionOpCode->Link);
+      if (Operand == EFI_IFR_MAP_OP) {
+        //
+        // Store current Map Expression List.
+        //
+        if (MapExpressionList != NULL) {
+          PushMapExpressionList (MapExpressionList);
+        }
+        //
+        // Initialize new Map Expression List.
+        //
+        MapExpressionList = &ExpressionOpCode->MapExpressionList;
+        InitializeListHead (MapExpressionList);
+        //
+        // Store current expression.
+        //
+        PushCurrentExpression (CurrentExpression);
+        CurrentExpression = NULL;
+        MapScopeDepth ++;
+      } else if (SingleOpCodeExpression) {
+        //
+        // There are two cases to indicate the end of an Expression:
+        // for single OpCode expression: one Expression OpCode
+        // for expression consists of more than one OpCode: EFI_IFR_END
+        //
+        SingleOpCodeExpression = FALSE;
+
+        if (mInScopeDisable && (CurrentForm == NULL)) {
+          //
+          // This is DisableIf expression for Form, it should be a constant expression
+          //
+          ConstantFlag = TRUE;
+          Status = EvaluateExpression (FormSet, CurrentForm, CurrentExpression, &ConstantFlag);
+          if (EFI_ERROR (Status)) {
+            return Status;
+          }
+
+          if (CurrentExpression->Result.Type != EFI_IFR_TYPE_BOOLEAN) {
+            return EFI_INVALID_PARAMETER;
+          }
+          if (!ConstantFlag) {
+            StringPrint ("WARNING. The DisableIf expression for Form should be a constant expression.\n");
+          }
+          OpCodeDisabled = CurrentExpression->Result.Value.b;
+        }
+
+        CurrentExpression = NULL;
+      }
+
+      continue;
+    }
+
+    //
+    // Parse the Opcode
+    //
+    switch (Operand) {
+
+    case EFI_IFR_FORM_SET_OP:
+
+      CopyMem (&FormSet->FormSetTitle, &((EFI_IFR_FORM_SET *) OpCodeData)->FormSetTitle, sizeof (EFI_STRING_ID));
+      CopyMem (&FormSet->Help,         &((EFI_IFR_FORM_SET *) OpCodeData)->Help,         sizeof (EFI_STRING_ID));
+      CopyMem (&FormSet->Guid,         &((EFI_IFR_FORM_SET *) OpCodeData)->Guid,         sizeof (EFI_GUID));
+
+      if (OpCodeLength > OFFSET_OF (EFI_IFR_FORM_SET, Flags)) {
+        //
+        // The formset OpCode contains ClassGuid
+        //
+        FormSet->NumberOfClassGuid = (UINT8) (((EFI_IFR_FORM_SET *) OpCodeData)->Flags & 0x3);
+        CopyMem (FormSet->ClassGuid, OpCodeData + sizeof (EFI_IFR_FORM_SET), FormSet->NumberOfClassGuid * sizeof (EFI_GUID));
+      }
+      FormSet->FormSetOrder = ++mFormSetOrderParse;
+      break;
+
+    case EFI_IFR_FORM_OP:
+    case EFI_IFR_FORM_MAP_OP:
+      //
+      // Create a new Form for this FormSet
+      //
+      CurrentForm = AllocateZeroPool (sizeof (FORM_BROWSER_FORM));
+      ASSERT (CurrentForm != NULL);
+      CurrentForm->Signature = FORM_BROWSER_FORM_SIGNATURE;
+      InitializeListHead (&CurrentForm->ExpressionListHead);
+      InitializeListHead (&CurrentForm->StatementListHead);
+
+      CurrentForm->FormType = STANDARD_MAP_FORM_TYPE;
+      CopyMem (&CurrentForm->FormId,    &((EFI_IFR_FORM *) OpCodeData)->FormId,    sizeof (UINT16));
+      CopyMem (&CurrentForm->FormTitle, &((EFI_IFR_FORM *) OpCodeData)->FormTitle, sizeof (EFI_STRING_ID));
+
+      if (InScopeFormSuppress) {
+        //
+        // Form is inside of suppressif
+        //
+        CurrentForm->SuppressExpression = FormSuppressExpression;
+      }
+
+      if (Scope != 0) {
+        //
+        // Enter scope of a Form, suppressif will be used for Question or Option
+        //
+        SuppressForQuestion = TRUE;
+      }
+
+      //
+      // Insert into Form list of this FormSet
+      //
+      InsertTailList (&FormSet->FormListHead, &CurrentForm->Link);
+      break;
+    //
+    // Storage
+    //
+    case EFI_IFR_VARSTORE_OP:
+      //
+      // Create a buffer Storage for this FormSet
+      //
+
+      Storage = CreateStorage (FormSet);
+      Storage->Type = EFI_IFR_VARSTORE_OP;
+
+      CopyMem (&Storage->VarStoreId, &((EFI_IFR_VARSTORE *) OpCodeData)->VarStoreId, sizeof (EFI_VARSTORE_ID));
+      CopyMem (&Storage->Guid,       &((EFI_IFR_VARSTORE *) OpCodeData)->Guid,       sizeof (EFI_GUID));
+      CopyMem (&Storage->Size,       &((EFI_IFR_VARSTORE *) OpCodeData)->Size,       sizeof (UINT16));
+
+      Storage->Buffer = AllocateZeroPool (Storage->Size);
+
+      AsciiString = (CHAR8 *) ((EFI_IFR_VARSTORE *) OpCodeData)->Name;
+      Storage->Name = AllocateZeroPool ((strlen (AsciiString) + 1) * 2);
+      ASSERT (Storage->Name != NULL);
+      for (Index = 0; AsciiString[Index] != 0; Index++) {
+        Storage->Name[Index] = (CHAR16) AsciiString[Index];
+      }
+      Storage->FormSetOrder = mFormSetOrderParse;
+
+      //
+      // If not existed the same variable in StorageList, insert the new one. Or else, use the old one.
+      // If these two variales have the same Guid name but different size, report an error.
+      //
+      if ((TempStorage = NotSameVariableInVarList (FormSet->StorageListHead, Storage)) != NULL) {
+        if (Storage->Size != TempStorage->Size) {
+           StringPrint ("Error. Two modules found with VarStore variables with same name %S and GUID %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x, but with different sizes %d and %d.\n",
+           Storage->Name,
+           Storage->Guid.Data1,
+           Storage->Guid.Data2,
+           Storage->Guid.Data3,
+           Storage->Guid.Data4[0],
+           Storage->Guid.Data4[1],
+           Storage->Guid.Data4[2],
+           Storage->Guid.Data4[3],
+           Storage->Guid.Data4[4],
+           Storage->Guid.Data4[5],
+           Storage->Guid.Data4[6],
+           Storage->Guid.Data4[7],
+           Storage->Size,
+           TempStorage->Size
+           );
+          return EFI_ABORTED;
+        }
+        //
+        // Update the VarStoreId for current question to get the variable guid and name information
+        //
+        TempStorage->VarStoreId   = Storage->VarStoreId;
+        TempStorage->FormSetOrder = Storage->FormSetOrder;
+        RemoveEntryList (&Storage->Link);
+        DestroyStorage(Storage);
+      }
+      break;
+
+    case EFI_IFR_VARSTORE_NAME_VALUE_OP:
+      //
+      // Create a name/value Storage for this FormSet
+      //
+      Storage = CreateStorage (FormSet);
+      Storage->Type = EFI_HII_VARSTORE_NAME_VALUE;
+
+      CopyMem (&Storage->VarStoreId, &((EFI_IFR_VARSTORE_NAME_VALUE *) OpCodeData)->VarStoreId, sizeof (EFI_VARSTORE_ID));
+      CopyMem (&Storage->Guid,       &((EFI_IFR_VARSTORE_NAME_VALUE *) OpCodeData)->Guid,       sizeof (EFI_GUID));
+
+      Storage->FormSetOrder = mFormSetOrderParse;
+      break;
+
+    case EFI_IFR_VARSTORE_EFI_OP:
+      //
+      // Create a EFI variable Storage for this FormSet
+      //
+      Storage = CreateStorage (FormSet);
+      Storage->Type = EFI_IFR_VARSTORE_EFI_OP;
+      CopyMem (&Storage->VarStoreId, &((EFI_IFR_VARSTORE_EFI *) OpCodeData)->VarStoreId, sizeof (EFI_VARSTORE_ID));
+      CopyMem (&Storage->Guid,       &((EFI_IFR_VARSTORE_EFI *) OpCodeData)->Guid,       sizeof (EFI_GUID));
+      CopyMem (&Storage->Attributes, &((EFI_IFR_VARSTORE_EFI *) OpCodeData)->Attributes, sizeof (UINT32));
+      //
+      // Check whether the EfiVarStore before UEFI2.31 or not
+      //
+      Storage->Size             = sizeof (EFI_IFR_VARSTORE_EFI_OLD);
+      if (((EFI_IFR_VARSTORE_EFI *) OpCodeData)->Header.Length == sizeof (EFI_IFR_VARSTORE_EFI_OLD)) {
+        Storage->NewEfiVarstore   = FALSE;
+        Storage->Size             = 0;
+        Storage->Buffer           = NULL;
+        Storage->Name             = NULL;
+        Storage->Size             = 0;
+      } else {
+        //
+        // EfiVarStore structure for UEFI2.31
+        //
+        Storage->NewEfiVarstore   = TRUE;
+        CopyMem (&Storage->Size, &((EFI_IFR_VARSTORE_EFI *) OpCodeData)->Size, sizeof (UINT16));
+
+        Storage->Buffer = AllocateZeroPool (Storage->Size);
+        AsciiString = (CHAR8 *) ((EFI_IFR_VARSTORE_EFI *) OpCodeData)->Name;
+        Storage->Name = AllocateZeroPool ((strlen (AsciiString) + 1) * 2);
+        ASSERT (Storage->Name != NULL);
+        for (Index = 0; AsciiString[Index] != 0; Index++) {
+          Storage->Name[Index] = (CHAR16) AsciiString[Index];
+        }
+      }
+      Storage->FormSetOrder = mFormSetOrderParse;
+      //
+      // If not existed the same variable in StorageList, insert the new one. Or else, use the old one.
+      // If these two variales have the same Guid name but different size, report an error.
+      //
+      if ((TempStorage = NotSameVariableInVarList (FormSet->StorageListHead, Storage)) != NULL) {
+        if (Storage->Size != TempStorage->Size) {
+          StringPrint ("Error. Two modules found with EfiVarStore variables with same name %S and GUID %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x, but different sizes %d and %d.\n",
+          Storage->Name,
+          Storage->Guid.Data1,
+          Storage->Guid.Data2,
+          Storage->Guid.Data3,
+          Storage->Guid.Data4[0],
+          Storage->Guid.Data4[1],
+          Storage->Guid.Data4[2],
+          Storage->Guid.Data4[3],
+          Storage->Guid.Data4[4],
+          Storage->Guid.Data4[5],
+          Storage->Guid.Data4[6],
+          Storage->Guid.Data4[7],
+          Storage->Size,
+          TempStorage->Size
+          );
+          return EFI_ABORTED;
+        }
+        //
+        // Update the VarStoreId for current question to get the variable guid and name information
+        //
+        TempStorage->VarStoreId   = Storage->VarStoreId;
+        TempStorage->FormSetOrder = Storage->FormSetOrder;
+        RemoveEntryList (&Storage->Link);
+        DestroyStorage( Storage);
+      }
+      break;
+
+    //
+    // DefaultStore
+    //
+    case EFI_IFR_DEFAULTSTORE_OP:
+      HaveInserted = FALSE;
+      DefaultStore = AllocateZeroPool (sizeof (FORMSET_DEFAULTSTORE));
+      ASSERT (DefaultStore != NULL);
+      DefaultStore->Signature = FORMSET_DEFAULTSTORE_SIGNATURE;
+
+      CopyMem (&DefaultStore->DefaultId,   &((EFI_IFR_DEFAULTSTORE *) OpCodeData)->DefaultId,   sizeof (UINT16));
+      CopyMem (&DefaultStore->DefaultName, &((EFI_IFR_DEFAULTSTORE *) OpCodeData)->DefaultName, sizeof (EFI_STRING_ID));
+
+      //
+      // Insert it to the DefaultStore list of this Formset with ascending order.
+      //
+      if (!IsListEmpty (&FormSet->DefaultStoreListHead)) {
+        DefaultLink = GetFirstNode (&FormSet->DefaultStoreListHead);
+        while (!IsNull (&FormSet->DefaultStoreListHead, DefaultLink)) {
+          PreDefaultStore = FORMSET_DEFAULTSTORE_FROM_LINK(DefaultLink);
+          DefaultLink = GetNextNode (&FormSet->DefaultStoreListHead, DefaultLink);
+          if (DefaultStore->DefaultId < PreDefaultStore->DefaultId) {
+            InsertTailList (&PreDefaultStore->Link, &DefaultStore->Link);
+            HaveInserted = TRUE;
+            break;
+          }
+        }
+      }
+      if (!HaveInserted) {
+        InsertTailList (&FormSet->DefaultStoreListHead, &DefaultStore->Link);
+      }
+      break;
+
+    //
+    // Statements
+    //
+    case EFI_IFR_SUBTITLE_OP:
+      CurrentStatement = CreateStatement (OpCodeData, FormSet, CurrentForm);
+      ASSERT (CurrentStatement != NULL);
+
+      CurrentStatement->Flags = ((EFI_IFR_SUBTITLE *) OpCodeData)->Flags;
+
+      if (Scope != 0) {
+        mInScopeSubtitle = TRUE;
+      }
+      break;
+
+    case EFI_IFR_TEXT_OP:
+      CurrentStatement = CreateStatement (OpCodeData, FormSet, CurrentForm);
+      ASSERT (CurrentStatement != NULL);
+
+      CopyMem (&CurrentStatement->TextTwo, &((EFI_IFR_TEXT *) OpCodeData)->TextTwo, sizeof (EFI_STRING_ID));
+      break;
+
+    case EFI_IFR_RESET_BUTTON_OP:
+      CurrentStatement = CreateStatement (OpCodeData, FormSet, CurrentForm);
+      ASSERT (CurrentStatement != NULL);
+      CopyMem (&CurrentStatement->DefaultId, &((EFI_IFR_RESET_BUTTON *) OpCodeData)->DefaultId, sizeof (EFI_DEFAULT_ID));
+      break;
+
+    //
+    // Questions
+    //
+    case EFI_IFR_ACTION_OP:
+      CurrentStatement = CreateQuestion (OpCodeData, FormSet, CurrentForm);
+      ASSERT (CurrentStatement != NULL);
+      CurrentStatement->HiiValue.Type = EFI_IFR_TYPE_ACTION;
+      //
+      // No need to deal with the EFI_IFR_ACTION
+      //
+      break;
+
+    case EFI_IFR_REF_OP:
+      CurrentStatement = CreateQuestion (OpCodeData, FormSet, CurrentForm);
+      ASSERT (CurrentStatement != NULL);
+      Value = &CurrentStatement->HiiValue;
+      Value->Type = EFI_IFR_TYPE_REF;
+      if (OpCodeLength >= sizeof (EFI_IFR_REF)) {
+        CopyMem (&Value->Value.ref.FormId, &((EFI_IFR_REF *) OpCodeData)->FormId, sizeof (EFI_FORM_ID));
+
+        if (OpCodeLength >= sizeof (EFI_IFR_REF2)) {
+          CopyMem (&Value->Value.ref.QuestionId, &((EFI_IFR_REF2 *) OpCodeData)->QuestionId, sizeof (EFI_QUESTION_ID));
+
+          if (OpCodeLength >= sizeof (EFI_IFR_REF3)) {
+            CopyMem (&Value->Value.ref.FormSetGuid, &((EFI_IFR_REF3 *) OpCodeData)->FormSetId, sizeof (EFI_GUID));
+
+            if (OpCodeLength >= sizeof (EFI_IFR_REF4)) {
+              CopyMem (&Value->Value.ref.DevicePath, &((EFI_IFR_REF4 *) OpCodeData)->DevicePath, sizeof (EFI_STRING_ID));
+            }
+          }
+        }
+      }
+      CurrentStatement->StorageWidth = (UINT16) sizeof (EFI_HII_REF);
+      break;
+
+    case EFI_IFR_ONE_OF_OP:
+    case EFI_IFR_NUMERIC_OP:
+      CurrentStatement = CreateQuestion (OpCodeData, FormSet, CurrentForm);
+      ASSERT(CurrentStatement != NULL);
+
+      CurrentStatement->Flags = ((EFI_IFR_ONE_OF *) OpCodeData)->Flags;
+      Value = &CurrentStatement->HiiValue;
+
+      if (BitFieldStorage) {
+        //
+        // Get the bit var store info (bit/byte offset, bit/byte offset)
+        //
+        CurrentStatement->QuestionReferToBitField = TRUE;
+        CurrentStatement->BitStorageWidth = CurrentStatement->Flags & EDKII_IFR_NUMERIC_SIZE_BIT;
+        CurrentStatement->BitVarOffset = CurrentStatement->VarStoreInfo.VarOffset;
+        CurrentStatement->VarStoreInfo.VarOffset = CurrentStatement->BitVarOffset / 8;
+        TotalBits = CurrentStatement->BitVarOffset % 8 + CurrentStatement->BitStorageWidth;
+        CurrentStatement->StorageWidth = (TotalBits % 8 == 0? TotalBits / 8: TotalBits / 8 + 1);
+        //
+        // Get the Minimum/Maximum/Step value(Note: bit field type has been stored as UINT32 type)
+        //
+        CurrentStatement->Minimum = ((EFI_IFR_NUMERIC *) OpCodeData)->data.u32.MinValue;
+        CurrentStatement->Maximum = ((EFI_IFR_NUMERIC *) OpCodeData)->data.u32.MaxValue;
+        CurrentStatement->Step    = ((EFI_IFR_NUMERIC *) OpCodeData)->data.u32.Step;
+      } else {
+        switch (CurrentStatement->Flags & EFI_IFR_NUMERIC_SIZE) {
+        case EFI_IFR_NUMERIC_SIZE_1:
+          CurrentStatement->Minimum = ((EFI_IFR_NUMERIC *) OpCodeData)->data.u8.MinValue;
+          CurrentStatement->Maximum = ((EFI_IFR_NUMERIC *) OpCodeData)->data.u8.MaxValue;
+          CurrentStatement->Step    = ((EFI_IFR_NUMERIC *) OpCodeData)->data.u8.Step;
+          CurrentStatement->StorageWidth = (UINT16) sizeof (UINT8);
+          Value->Type = EFI_IFR_TYPE_NUM_SIZE_8;
+          break;
+
+        case EFI_IFR_NUMERIC_SIZE_2:
+          CopyMem (&CurrentStatement->Minimum, &((EFI_IFR_NUMERIC *) OpCodeData)->data.u16.MinValue, sizeof (UINT16));
+          CopyMem (&CurrentStatement->Maximum, &((EFI_IFR_NUMERIC *) OpCodeData)->data.u16.MaxValue, sizeof (UINT16));
+          CopyMem (&CurrentStatement->Step,    &((EFI_IFR_NUMERIC *) OpCodeData)->data.u16.Step,     sizeof (UINT16));
+          CurrentStatement->StorageWidth = (UINT16) sizeof (UINT16);
+          Value->Type = EFI_IFR_TYPE_NUM_SIZE_16;
+          break;
+
+        case EFI_IFR_NUMERIC_SIZE_4:
+          CopyMem (&CurrentStatement->Minimum, &((EFI_IFR_NUMERIC *) OpCodeData)->data.u32.MinValue, sizeof (UINT32));
+          CopyMem (&CurrentStatement->Maximum, &((EFI_IFR_NUMERIC *) OpCodeData)->data.u32.MaxValue, sizeof (UINT32));
+          CopyMem (&CurrentStatement->Step,    &((EFI_IFR_NUMERIC *) OpCodeData)->data.u32.Step,     sizeof (UINT32));
+          CurrentStatement->StorageWidth = (UINT16) sizeof (UINT32);
+          Value->Type = EFI_IFR_TYPE_NUM_SIZE_32;
+          break;
+
+        case EFI_IFR_NUMERIC_SIZE_8:
+          CopyMem (&CurrentStatement->Minimum, &((EFI_IFR_NUMERIC *) OpCodeData)->data.u64.MinValue, sizeof (UINT64));
+          CopyMem (&CurrentStatement->Maximum, &((EFI_IFR_NUMERIC *) OpCodeData)->data.u64.MaxValue, sizeof (UINT64));
+          CopyMem (&CurrentStatement->Step,    &((EFI_IFR_NUMERIC *) OpCodeData)->data.u64.Step,     sizeof (UINT64));
+          CurrentStatement->StorageWidth = (UINT16) sizeof (UINT64);
+          Value->Type = EFI_IFR_TYPE_NUM_SIZE_64;
+          break;
+
+        default:
+          break;
+        }
+      }
+      if ((Operand == EFI_IFR_ONE_OF_OP) && (Scope != 0)) {
+        SuppressForOption = TRUE;
+      }
+      //
+      // Get the UQI information
+      //
+      PrintQuestion(FormSet, CurrentForm, CurrentStatement, FALSE);
+      //
+      // Exchange the Guid and name information between VarList and Question List
+      //
+      Status = GetGuidNameByVariableId (FormSet, CurrentStatement, FormSet->StorageListHead);
+      //
+      // Remove the question which isn't stored by EfiVarStore or VarStore
+      //
+      if (EFI_ERROR (Status)) {
+        RemoveEntryList (&CurrentStatement->Link);
+        DestroyStatement (FormSet, CurrentStatement);
+      }
+      break;
+
+    case EFI_IFR_ORDERED_LIST_OP:
+      CurrentStatement = CreateQuestion (OpCodeData, FormSet, CurrentForm);
+      ASSERT(CurrentStatement != NULL);
+
+      CurrentStatement->Flags = ((EFI_IFR_ORDERED_LIST *) OpCodeData)->Flags;
+      CurrentStatement->MaxContainers = ((EFI_IFR_ORDERED_LIST *) OpCodeData)->MaxContainers;
+
+      CurrentStatement->HiiValue.Type = EFI_IFR_TYPE_BUFFER;
+      CurrentStatement->BufferValue   = NULL;
+      if (Scope != 0) {
+        SuppressForOption = TRUE;
+      }
+      //
+      // Get the UQI information
+      //
+      PrintQuestion(FormSet, CurrentForm, CurrentStatement, FALSE);
+      //
+      // Exchange the Guid and name information between VarList and Question List
+      //
+      Status = GetGuidNameByVariableId (FormSet, CurrentStatement, FormSet->StorageListHead);
+      //
+      // Remove the question which isn't stored by EfiVarStore or VarStore
+      //
+      if (EFI_ERROR (Status)) {
+        RemoveEntryList (&CurrentStatement->Link);
+        DestroyStatement (FormSet, CurrentStatement);
+      }
+
+      break;
+
+    case EFI_IFR_CHECKBOX_OP:
+      CurrentStatement = CreateQuestion (OpCodeData, FormSet, CurrentForm);
+      ASSERT(CurrentStatement != NULL);
+
+      CurrentStatement->Flags = ((EFI_IFR_CHECKBOX *) OpCodeData)->Flags;
+      CurrentStatement->StorageWidth  = (UINT16) sizeof (BOOLEAN);
+      CurrentStatement->HiiValue.Type = EFI_IFR_TYPE_BOOLEAN;
+
+      if (BitFieldStorage) {
+        //
+        // Get the bit var store info (bit/byte offset, bit/byte width)
+        //
+        CurrentStatement->QuestionReferToBitField = TRUE;
+        CurrentStatement->BitStorageWidth = 1;
+        CurrentStatement->BitVarOffset = CurrentStatement->VarStoreInfo.VarOffset;
+        CurrentStatement->VarStoreInfo.VarOffset = CurrentStatement->BitVarOffset / 8;
+        TotalBits = CurrentStatement->BitVarOffset % 8 + CurrentStatement->BitStorageWidth;
+        CurrentStatement->StorageWidth = (TotalBits % 8 == 0? TotalBits / 8: TotalBits / 8 + 1);
+      }
+      //
+      // Get the UQI information
+      //
+      PrintQuestion(FormSet, CurrentForm, CurrentStatement, FALSE);
+      //
+      // Exchange the Guid and name information between VarList and Question List
+      //
+      Status = GetGuidNameByVariableId (FormSet, CurrentStatement, FormSet->StorageListHead);
+      //
+      // Remove the question which isn't stored by EfiVarStore or VarStore
+      //
+      if (EFI_ERROR (Status)) {
+        RemoveEntryList (&CurrentStatement->Link);
+        DestroyStatement (FormSet, CurrentStatement);
+      }
+
+      break;
+
+    case EFI_IFR_STRING_OP:
+      CurrentStatement = CreateQuestion (OpCodeData, FormSet, CurrentForm);
+      ASSERT (CurrentStatement != NULL);
+      //
+      // MinSize is the minimum number of characters that can be accepted for this opcode,
+      // MaxSize is the maximum number of characters that can be accepted for this opcode.
+      // The characters are stored as Unicode, so the storage width should multiply 2.
+      //
+      CurrentStatement->Minimum = ((EFI_IFR_STRING *) OpCodeData)->MinSize;
+      CurrentStatement->Maximum = ((EFI_IFR_STRING *) OpCodeData)->MaxSize;
+      CurrentStatement->StorageWidth = (UINT16)((UINTN) CurrentStatement->Maximum * sizeof (CHAR16));
+      CurrentStatement->Flags = ((EFI_IFR_STRING *) OpCodeData)->Flags;
+
+      CurrentStatement->HiiValue.Type = EFI_IFR_TYPE_STRING;
+      CurrentStatement->BufferValue = AllocateZeroPool (CurrentStatement->StorageWidth + sizeof (CHAR16));
+      //
+      // Get the UQI information
+      //
+      PrintQuestion(FormSet, CurrentForm, CurrentStatement, FALSE);
+      //
+      // Exchange the Guid and name information between VarList and Question List
+      //
+      Status = GetGuidNameByVariableId (FormSet, CurrentStatement, FormSet->StorageListHead);
+      //
+      // Remove the question which isn't stored by EfiVarStore or VarStore
+      //
+      if (EFI_ERROR (Status)) {
+        RemoveEntryList (&CurrentStatement->Link);
+        DestroyStatement (FormSet, CurrentStatement);
+      }
+
+      break;
+
+    case EFI_IFR_PASSWORD_OP:
+      CurrentStatement = CreateQuestion (OpCodeData, FormSet, CurrentForm);
+      ASSERT (CurrentStatement != NULL);
+      //
+      // MinSize is the minimum number of characters that can be accepted for this opcode,
+      // MaxSize is the maximum number of characters that can be accepted for this opcode.
+      // The characters are stored as Unicode, so the storage width should multiply 2.
+      //
+      CopyMem (&CurrentStatement->Minimum, &((EFI_IFR_PASSWORD *) OpCodeData)->MinSize, sizeof (UINT16));
+      CopyMem (&CurrentStatement->Maximum, &((EFI_IFR_PASSWORD *) OpCodeData)->MaxSize, sizeof (UINT16));
+      CurrentStatement->StorageWidth = (UINT16)((UINTN) CurrentStatement->Maximum * sizeof (CHAR16));
+
+      CurrentStatement->HiiValue.Type = EFI_IFR_TYPE_STRING;
+      CurrentStatement->BufferValue = AllocateZeroPool ((CurrentStatement->StorageWidth + sizeof (CHAR16)));
+      break;
+
+    case EFI_IFR_DATE_OP:
+      CurrentStatement = CreateQuestion (OpCodeData, FormSet, CurrentForm);
+      ASSERT(CurrentStatement != NULL);
+
+      CurrentStatement->Flags = ((EFI_IFR_DATE *) OpCodeData)->Flags;
+      CurrentStatement->HiiValue.Type = EFI_IFR_TYPE_DATE;
+
+      if ((CurrentStatement->Flags & EFI_QF_DATE_STORAGE) == QF_DATE_STORAGE_NORMAL) {
+        CurrentStatement->StorageWidth = (UINT16) sizeof (EFI_HII_DATE);
+      } else {
+        //
+        // Don't assign storage for RTC type of date/time
+        //
+        CurrentStatement->Storage = NULL;
+        CurrentStatement->StorageWidth = 0;
+      }
+      break;
+
+    case EFI_IFR_TIME_OP:
+      CurrentStatement = CreateQuestion (OpCodeData, FormSet, CurrentForm);
+      ASSERT(CurrentStatement != NULL);
+
+      CurrentStatement->Flags = ((EFI_IFR_TIME *) OpCodeData)->Flags;
+      CurrentStatement->HiiValue.Type = EFI_IFR_TYPE_TIME;
+
+      if ((CurrentStatement->Flags & QF_TIME_STORAGE) == QF_TIME_STORAGE_NORMAL) {
+        CurrentStatement->StorageWidth = (UINT16) sizeof (EFI_HII_TIME);
+      } else {
+        //
+        // Don't assign storage for RTC type of date/time
+        //
+        CurrentStatement->Storage = NULL;
+        CurrentStatement->StorageWidth = 0;
+      }
+      break;
+
+    //
+    // Default
+    //
+    case EFI_IFR_DEFAULT_OP:
+      //
+      // EFI_IFR_DEFAULT appear in scope of a Question,
+      // It creates a default value for the current question.
+      // A Question may have more than one Default value which have different default types.
+      //
+      CurrentDefault = AllocateZeroPool (sizeof (QUESTION_DEFAULT));
+      ASSERT (CurrentDefault != NULL);
+      CurrentDefault->Signature = QUESTION_DEFAULT_SIGNATURE;
+
+      CurrentDefault->Value.Type = ((EFI_IFR_DEFAULT *) OpCodeData)->Type;
+      CopyMem (&CurrentDefault->DefaultId, &((EFI_IFR_DEFAULT *) OpCodeData)->DefaultId, sizeof (UINT16));
+      if (CurrentDefault->Value.Type == EFI_IFR_TYPE_BUFFER) {
+        CurrentDefault->Value.BufferLen = (UINT16)(OpCodeLength - OFFSET_OF(EFI_IFR_DEFAULT, Value));
+        CurrentDefault->Value.Buffer = FceAllocateCopyPool(CurrentDefault->Value.BufferLen, &((EFI_IFR_DEFAULT *)OpCodeData)->Value);
+        ASSERT(CurrentDefault->Value.Buffer != NULL);
+      } else {
+        CopyMem(&CurrentDefault->Value.Value, &((EFI_IFR_DEFAULT *)OpCodeData)->Value, OpCodeLength - OFFSET_OF(EFI_IFR_DEFAULT, Value));
+        ExtendValueToU64(&CurrentDefault->Value);
+      }
+
+      //
+      // Insert to Default Value list of current Question
+      //
+      InsertTailList (&CurrentStatement->DefaultListHead, &CurrentDefault->Link);
+
+      if (Scope != 0) {
+        InScopeDefault = TRUE;
+      }
+      break;
+
+    //
+    // Option
+    //
+    case EFI_IFR_ONE_OF_OPTION_OP:
+      ASSERT (CurrentStatement != NULL);
+      if (CurrentStatement->Operand == EFI_IFR_ORDERED_LIST_OP &&
+        ((((EFI_IFR_ONE_OF_OPTION *)OpCodeData)->Flags & (EFI_IFR_OPTION_DEFAULT | EFI_IFR_OPTION_DEFAULT_MFG)) != 0)) {
+        //
+        // It's keep the default value for ordered list opcode.
+        //
+        CurrentDefault = AllocateZeroPool(sizeof (QUESTION_DEFAULT));
+        ASSERT(CurrentDefault != NULL);
+        CurrentDefault->Signature = QUESTION_DEFAULT_SIGNATURE;
+
+        CurrentDefault->Value.Type = EFI_IFR_TYPE_BUFFER;
+        if ((((EFI_IFR_ONE_OF_OPTION *)OpCodeData)->Flags & EFI_IFR_OPTION_DEFAULT) != 0) {
+          CurrentDefault->DefaultId = EFI_HII_DEFAULT_CLASS_STANDARD;
+        } else {
+          CurrentDefault->DefaultId = EFI_HII_DEFAULT_CLASS_MANUFACTURING;
+        }
+
+        CurrentDefault->Value.BufferLen = (UINT16)(OpCodeLength - OFFSET_OF(EFI_IFR_ONE_OF_OPTION, Value));
+        CurrentDefault->Value.Buffer = FceAllocateCopyPool(CurrentDefault->Value.BufferLen, &((EFI_IFR_ONE_OF_OPTION *)OpCodeData)->Value);
+        ASSERT(CurrentDefault->Value.Buffer != NULL);
+
+        //
+        // Insert to Default Value list of current Question
+        //
+        InsertTailList(&CurrentStatement->DefaultListHead, &CurrentDefault->Link);
+        break;
+      }
+      //
+      // EFI_IFR_ONE_OF_OPTION appear in scope of a Question.
+      // It create a selection for use in current Question.
+      //
+      CurrentOption = AllocateZeroPool (sizeof (QUESTION_OPTION));
+      ASSERT (CurrentOption != NULL);
+      CurrentOption->Signature = QUESTION_OPTION_SIGNATURE;
+
+      CurrentOption->Flags = ((EFI_IFR_ONE_OF_OPTION *) OpCodeData)->Flags;
+      CurrentOption->Value.Type = ((EFI_IFR_ONE_OF_OPTION *) OpCodeData)->Type;
+      CopyMem (&CurrentOption->Text, &((EFI_IFR_ONE_OF_OPTION *) OpCodeData)->Option, sizeof (EFI_STRING_ID));
+      CopyMem (&CurrentOption->Value.Value, &((EFI_IFR_ONE_OF_OPTION *) OpCodeData)->Value, OpCodeLength - OFFSET_OF (EFI_IFR_ONE_OF_OPTION, Value));
+      ExtendValueToU64 (&CurrentOption->Value);
+
+      if (InScopeOptionSuppress) {
+        CurrentOption->SuppressExpression = OptionSuppressExpression;
+      }
+
+      //
+      // Insert to Option list of current Question
+      //
+      InsertTailList (&CurrentStatement->OptionListHead, &CurrentOption->Link);
+
+      //
+      // Now we know the Storage width of nested Ordered List
+      //
+      if ((CurrentStatement->Operand == EFI_IFR_ORDERED_LIST_OP) && (CurrentStatement->BufferValue == NULL)) {
+        Width = 1;
+        switch (CurrentOption->Value.Type) {
+        case EFI_IFR_TYPE_NUM_SIZE_8:
+          Width = 1;
+          break;
+
+        case EFI_IFR_TYPE_NUM_SIZE_16:
+          Width = 2;
+          break;
+
+        case EFI_IFR_TYPE_NUM_SIZE_32:
+          Width = 4;
+          break;
+
+        case EFI_IFR_TYPE_NUM_SIZE_64:
+          Width = 8;
+          break;
+
+        default:
+          //
+          // Invalid type for Ordered List
+          //
+          break;
+        }
+
+        CurrentStatement->StorageWidth = (UINT16) (CurrentStatement->MaxContainers * Width);
+        CurrentStatement->BufferValue = AllocateZeroPool (CurrentStatement->StorageWidth);
+        CurrentStatement->ValueType = CurrentOption->Value.Type;
+        if (CurrentStatement->HiiValue.Type == EFI_IFR_TYPE_BUFFER) {
+          CurrentStatement->HiiValue.Buffer = CurrentStatement->BufferValue;
+          CurrentStatement->HiiValue.BufferLen = CurrentStatement->StorageWidth;
+        }
+      }
+      break;
+
+    //
+    // Conditional
+    //
+    case EFI_IFR_NO_SUBMIT_IF_OP:
+    case EFI_IFR_INCONSISTENT_IF_OP:
+      //
+      // Create an Expression node
+      //
+      CurrentExpression = CreateExpression (CurrentForm);
+      CopyMem (&CurrentExpression->Error, &((EFI_IFR_INCONSISTENT_IF *) OpCodeData)->Error, sizeof (EFI_STRING_ID));
+
+      if (Operand == EFI_IFR_NO_SUBMIT_IF_OP) {
+        CurrentExpression->Type = EFI_HII_EXPRESSION_NO_SUBMIT_IF;
+        InsertTailList (&CurrentStatement->NoSubmitListHead, &CurrentExpression->Link);
+      } else {
+        CurrentExpression->Type = EFI_HII_EXPRESSION_INCONSISTENT_IF;
+        InsertTailList (&CurrentStatement->InconsistentListHead, &CurrentExpression->Link);
+      }
+      //
+      // Take a look at next OpCode to see whether current expression consists
+      // of single OpCode
+      //
+      if (((EFI_IFR_OP_HEADER *) (OpCodeData + OpCodeLength))->Scope == 0) {
+        SingleOpCodeExpression = TRUE;
+      }
+      break;
+
+    case EFI_IFR_WARNING_IF_OP:
+      //
+      // Create an Expression node
+      //
+      CurrentExpression = CreateExpression (CurrentForm);
+      CopyMem (&CurrentExpression->Error, &((EFI_IFR_WARNING_IF *) OpCodeData)->Warning, sizeof (EFI_STRING_ID));
+      CurrentExpression->TimeOut = ((EFI_IFR_WARNING_IF *) OpCodeData)->TimeOut;
+      CurrentExpression->Type    = EFI_HII_EXPRESSION_WARNING_IF;
+      InsertTailList (&CurrentStatement->WarningListHead, &CurrentExpression->Link);
+
+      //
+      // Take a look at next OpCode to see whether current expression consists
+      // of single OpCode
+      //
+      if (((EFI_IFR_OP_HEADER *) (OpCodeData + OpCodeLength))->Scope == 0) {
+        SingleOpCodeExpression = TRUE;
+      }
+      break;
+
+    case EFI_IFR_SUPPRESS_IF_OP:
+      //
+      // Question and Option will appear in scope of this OpCode
+      //
+      CurrentExpression = CreateExpression (CurrentForm);
+      CurrentExpression->Type = EFI_HII_EXPRESSION_SUPPRESS_IF;
+
+      if (CurrentForm == NULL) {
+        InsertTailList (&FormSet->ExpressionListHead, &CurrentExpression->Link);
+      } else {
+        InsertTailList (&CurrentForm->ExpressionListHead, &CurrentExpression->Link);
+      }
+
+      if (SuppressForOption) {
+        InScopeOptionSuppress = TRUE;
+        OptionSuppressExpression = CurrentExpression;
+      } else if (SuppressForQuestion) {
+        mInScopeSuppress = TRUE;
+        mSuppressExpression = CurrentExpression;
+      } else {
+        InScopeFormSuppress = TRUE;
+        FormSuppressExpression = CurrentExpression;
+      }
+      //
+      // Take a look at next OpCode to see whether current expression consists
+      // of single OpCode
+      //
+      if (((EFI_IFR_OP_HEADER *) (OpCodeData + OpCodeLength))->Scope == 0) {
+        SingleOpCodeExpression = TRUE;
+      }
+      break;
+
+    case EFI_IFR_GRAY_OUT_IF_OP:
+      //
+      // Questions will appear in scope of this OpCode
+      //
+      CurrentExpression = CreateExpression (CurrentForm);
+      CurrentExpression->Type = EFI_HII_EXPRESSION_GRAY_OUT_IF;
+      InsertTailList (&CurrentForm->ExpressionListHead, &CurrentExpression->Link);
+
+      mInScopeGrayOut = TRUE;
+      mGrayOutExpression = CurrentExpression;
+
+      //
+      // Take a look at next OpCode to see whether current expression consists
+      // of single OpCode
+      //
+      if (((EFI_IFR_OP_HEADER *) (OpCodeData + OpCodeLength))->Scope == 0) {
+        SingleOpCodeExpression = TRUE;
+      }
+      break;
+
+    case EFI_IFR_DISABLE_IF_OP:
+      //
+      // The DisableIf expression should only rely on constant, so it could be
+      // evaluated at initialization and it will not be queued
+      //
+      CurrentExpression = AllocateZeroPool (sizeof (FORM_EXPRESSION));
+      ASSERT (CurrentExpression != NULL);
+      CurrentExpression->Signature = FORM_EXPRESSION_SIGNATURE;
+      CurrentExpression->Type = EFI_HII_EXPRESSION_DISABLE_IF;
+      InitializeListHead (&CurrentExpression->OpCodeListHead);
+
+      if (CurrentForm != NULL) {
+        //
+        // This is DisableIf for Question, enqueue it to Form expression list
+        //
+        InsertTailList (&CurrentForm->ExpressionListHead, &CurrentExpression->Link);
+      }
+
+      mDisableExpression = CurrentExpression;
+      mInScopeDisable    = TRUE;
+      OpCodeDisabled     = FALSE;
+
+      //
+      // Take a look at next OpCode to see whether current expression consists
+      // of single OpCode
+      //
+      if (((EFI_IFR_OP_HEADER *) (OpCodeData + OpCodeLength))->Scope == 0) {
+        SingleOpCodeExpression = TRUE;
+      }
+      break;
+
+    //
+    // Expression
+    //
+    case EFI_IFR_VALUE_OP:
+      CurrentExpression = CreateExpression (CurrentForm);
+      CurrentExpression->Type = EFI_HII_EXPRESSION_VALUE;
+      InsertTailList (&CurrentForm->ExpressionListHead, &CurrentExpression->Link);
+
+      if (InScopeDefault) {
+        //
+        // Used for default (EFI_IFR_DEFAULT)
+        //
+        CurrentDefault->ValueExpression = CurrentExpression;
+      } else {
+        //
+        // If used for a question, then the question will be read-only
+        //
+        //
+        // Make sure CurrentStatement is not NULL.
+        // If it is NULL, 1) ParseOpCodes functions may parse the IFR wrongly. Or 2) the IFR
+        // file is wrongly generated by tools such as VFR Compiler. There may be a bug in VFR Compiler.
+        //
+        ASSERT (CurrentStatement != NULL);
+        CurrentStatement->ValueExpression = CurrentExpression;
+      }
+
+      //
+      // Take a look at next OpCode to see whether current expression consists
+      // of single OpCode
+      //
+      if (((EFI_IFR_OP_HEADER *) (OpCodeData + OpCodeLength))->Scope == 0) {
+        SingleOpCodeExpression = TRUE;
+      }
+      break;
+
+    case EFI_IFR_RULE_OP:
+      CurrentExpression = CreateExpression (CurrentForm);
+      CurrentExpression->Type = EFI_HII_EXPRESSION_RULE;
+
+      CurrentExpression->RuleId = ((EFI_IFR_RULE *) OpCodeData)->RuleId;
+      InsertTailList (&CurrentForm->ExpressionListHead, &CurrentExpression->Link);
+
+      //
+      // Take a look at next OpCode to see whether current expression consists
+      // of single OpCode
+      //
+      if (((EFI_IFR_OP_HEADER *) (OpCodeData + OpCodeLength))->Scope == 0) {
+        SingleOpCodeExpression = TRUE;
+      }
+      break;
+
+    case EFI_IFR_READ_OP:
+      CurrentExpression = CreateExpression (CurrentForm);
+      CurrentExpression->Type = EFI_HII_EXPRESSION_READ;
+      InsertTailList (&CurrentForm->ExpressionListHead, &CurrentExpression->Link);
+
+      //
+      // Make sure CurrentStatement is not NULL.
+      // If it is NULL, 1) ParseOpCodes functions may parse the IFR wrongly. Or 2) the IFR
+      // file is wrongly generated by tools such as VFR Compiler. There may be a bug in VFR Compiler.
+      //
+      ASSERT (CurrentStatement != NULL);
+      CurrentStatement->ReadExpression = CurrentExpression;
+
+      //
+      // Take a look at next OpCode to see whether current expression consists
+      // of single OpCode
+      //
+      if (((EFI_IFR_OP_HEADER *) (OpCodeData + OpCodeLength))->Scope == 0) {
+        SingleOpCodeExpression = TRUE;
+      }
+      break;
+
+    case EFI_IFR_WRITE_OP:
+      CurrentExpression = CreateExpression (CurrentForm);
+      CurrentExpression->Type = EFI_HII_EXPRESSION_WRITE;
+      InsertTailList (&CurrentForm->ExpressionListHead, &CurrentExpression->Link);
+
+      //
+      // Make sure CurrentStatement is not NULL.
+      // If it is NULL, 1) ParseOpCodes functions may parse the IFR wrongly. Or 2) the IFR
+      // file is wrongly generated by tools such as VFR Compiler. There may be a bug in VFR Compiler.
+      //
+      ASSERT (CurrentStatement != NULL);
+      CurrentStatement->WriteExpression = CurrentExpression;
+
+      //
+      // Take a look at next OpCode to see whether current expression consists
+      // of single OpCode
+      //
+      if (((EFI_IFR_OP_HEADER *) (OpCodeData + OpCodeLength))->Scope == 0) {
+        SingleOpCodeExpression = TRUE;
+      }
+      break;
+
+    //
+    // Image
+    //
+    case EFI_IFR_IMAGE_OP:
+      //
+      // Get ScopeOpcode from top of stack
+      //
+      PopScope (&ScopeOpCode);
+      PushScope (ScopeOpCode);
+
+      switch (ScopeOpCode) {
+      case EFI_IFR_FORM_SET_OP:
+        break;
+
+      case EFI_IFR_FORM_OP:
+      case EFI_IFR_FORM_MAP_OP:
+        ASSERT (CurrentForm != NULL);
+        break;
+
+      case EFI_IFR_ONE_OF_OPTION_OP:
+        break;
+
+      default:
+        //
+        // Make sure CurrentStatement is not NULL.
+        // If it is NULL, 1) ParseOpCodes functions may parse the IFR wrongly. Or 2) the IFR
+        // file is wrongly generated by tools such as VFR Compiler.
+        //
+        ASSERT (CurrentStatement != NULL);
+        break;
+      }
+      break;
+
+    //
+    // Refresh
+    //
+    case EFI_IFR_REFRESH_OP:
+      break;
+
+    //
+    // Refresh guid.
+    //
+    case EFI_IFR_REFRESH_ID_OP:
+      break;
+
+    //
+    // Modal tag
+    //
+    case EFI_IFR_MODAL_TAG_OP:
+      break;
+
+    //
+    // Vendor specific
+    //
+    case EFI_IFR_GUID_OP:
+      if (CompareGuid ((EFI_GUID *)(OpCodeData + sizeof (EFI_IFR_OP_HEADER)), &gEdkiiIfrBitVarGuid)==0) {
+        Scope = 0;
+        BitFieldStorage = TRUE;
+      }
+      break;
+
+    //
+    // Scope End
+    //
+    case EFI_IFR_END_OP:
+      BitFieldStorage = FALSE;
+      Status = PopScope (&ScopeOpCode);
+      if (EFI_ERROR (Status)) {
+        ResetScopeStack ();
+        return Status;
+      }
+
+      switch (ScopeOpCode) {
+      case EFI_IFR_FORM_SET_OP:
+        //
+        // End of FormSet, update FormSet IFR binary length
+        // to stop parsing substantial OpCodes
+        //
+        FormSet->IfrBinaryLength = OpCodeOffset;
+        break;
+
+      case EFI_IFR_FORM_OP:
+      case EFI_IFR_FORM_MAP_OP:
+        //
+        // End of Form
+        //
+        CurrentForm = NULL;
+        SuppressForQuestion = FALSE;
+        break;
+
+      case EFI_IFR_ONE_OF_OPTION_OP:
+        //
+        // End of Option
+        //
+        CurrentOption = NULL;
+        break;
+
+      case EFI_IFR_SUBTITLE_OP:
+        mInScopeSubtitle = FALSE;
+        break;
+
+      case EFI_IFR_NO_SUBMIT_IF_OP:
+      case EFI_IFR_INCONSISTENT_IF_OP:
+      case EFI_IFR_WARNING_IF_OP:
+        //
+        // Ignore end of EFI_IFR_NO_SUBMIT_IF and EFI_IFR_INCONSISTENT_IF
+        //
+        break;
+
+      case EFI_IFR_SUPPRESS_IF_OP:
+        if (SuppressForOption) {
+          InScopeOptionSuppress = FALSE;
+        } else if (SuppressForQuestion) {
+          mInScopeSuppress = FALSE;
+        } else {
+          InScopeFormSuppress = FALSE;
+        }
+        break;
+
+      case EFI_IFR_GRAY_OUT_IF_OP:
+        mInScopeGrayOut = FALSE;
+        break;
+
+      case EFI_IFR_DISABLE_IF_OP:
+        mInScopeDisable = FALSE;
+        OpCodeDisabled  = FALSE;
+        break;
+
+      case EFI_IFR_ONE_OF_OP:
+      case EFI_IFR_ORDERED_LIST_OP:
+        SuppressForOption = FALSE;
+        break;
+
+      case EFI_IFR_DEFAULT_OP:
+        InScopeDefault = FALSE;
+        break;
+
+      case EFI_IFR_MAP_OP:
+        //
+        // Get current Map Expression List.
+        //
+        Status = PopMapExpressionList ((VOID **) &MapExpressionList);
+        if (Status == EFI_ACCESS_DENIED) {
+          MapExpressionList = NULL;
+        }
+        //
+        // Get current expression.
+        //
+        Status = PopCurrentExpression ((VOID **) &CurrentExpression);
+        ASSERT (!EFI_ERROR (Status));
+        ASSERT (MapScopeDepth > 0);
+        MapScopeDepth --;
+        break;
+
+      default:
+        if (IsExpressionOpCode (ScopeOpCode)) {
+          if (mInScopeDisable && (CurrentForm == NULL)) {
+            //
+            // This is DisableIf expression for Form, it should be a constant expression
+            //
+            ASSERT (CurrentExpression != NULL);
+            ConstantFlag = TRUE;
+            Status = EvaluateExpression (FormSet, CurrentForm, CurrentExpression, &ConstantFlag);
+            if (EFI_ERROR (Status)) {
+              return Status;
+            }
+            if (CurrentExpression->Result.Type != EFI_IFR_TYPE_BOOLEAN) {
+              return EFI_INVALID_PARAMETER;
+            }
+            if (!ConstantFlag) {
+              StringPrint ("WARNING. The DisableIf expression for Form should be a constant expression.\n");
+            }
+            OpCodeDisabled = CurrentExpression->Result.Value.b;
+            //
+            // DisableIf Expression is only used once and not queued, free it
+            //
+            DestroyExpression (CurrentExpression);
+          }
+
+          //
+          // End of current Expression
+          //
+          CurrentExpression = NULL;
+        }
+        break;
+      }
+      break;
+
+    default:
+      break;
+    }
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Search an Option of a Question by its value.
+
+  @param  Question               The Question
+  @param  OptionValue            Value for Option to be searched.
+
+  @retval Pointer                Pointer to the found Option.
+  @retval NULL                   Option not found.
+
+**/
+QUESTION_OPTION *
+ValueToOption (
+  IN FORM_BROWSER_FORMSET     *FormSet,
+  IN FORM_BROWSER_STATEMENT   *Question,
+  IN EFI_HII_VALUE            *OptionValue
+  )
+{
+  LIST_ENTRY       *Link;
+  QUESTION_OPTION  *Option;
+
+  Link = GetFirstNode (&Question->OptionListHead);
+  while (!IsNull (&Question->OptionListHead, Link)) {
+    Option = QUESTION_OPTION_FROM_LINK (Link);
+
+    if (CompareHiiValue (&Option->Value, OptionValue, FormSet) == 0) {
+      return Option;
+    }
+
+    Link = GetNextNode (&Question->OptionListHead, Link);
+  }
+
+  return NULL;
+}
+
+/**
+  Set value of a data element in an Array by its Index.
+
+  @param  Array                  The data array.
+  @param  Type                   Type of the data in this array.
+  @param  Index                  Zero based index for data in this array.
+  @param  Value                  The value to be set.
+
+**/
+VOID
+SetArrayData (
+  IN VOID                     *Array,
+  IN UINT8                    Type,
+  IN UINTN                    Index,
+  IN UINT64                   Value
+  )
+{
+
+  ASSERT (Array != NULL);
+
+  switch (Type) {
+  case EFI_IFR_TYPE_NUM_SIZE_8:
+    *(((UINT8 *) Array) + Index) = (UINT8) Value;
+    break;
+
+  case EFI_IFR_TYPE_NUM_SIZE_16:
+    *(((UINT16 *) Array) + Index) = (UINT16) Value;
+    break;
+
+  case EFI_IFR_TYPE_NUM_SIZE_32:
+    *(((UINT32 *) Array) + Index) = (UINT32) Value;
+    break;
+
+  case EFI_IFR_TYPE_NUM_SIZE_64:
+    *(((UINT64 *) Array) + Index) = (UINT64) Value;
+    break;
+
+  default:
+    break;
+  }
+}
+
+/**
+  Reset Question of five kinds to its default value.
+
+  @param  FormSet                The form set.
+  @param  Form                   The form.
+  @param  Question               The question.
+  @param  DefaultId              The default Id.
+  @param  DefaultId              The platform Id.
+
+  @retval EFI_SUCCESS            Question is reset to default value.
+
+**/
+EFI_STATUS
+GetQuestionDefault (
+  IN FORM_BROWSER_FORMSET             *FormSet,
+  IN FORM_BROWSER_FORM                *Form,
+  IN FORM_BROWSER_STATEMENT           *Question,
+  IN UINT16                           DefaultId,
+  IN UINT64                           PlatformId
+  )
+{
+  EFI_STATUS              Status;
+  LIST_ENTRY              *Link;
+  QUESTION_DEFAULT        *Default;
+  QUESTION_OPTION         *Option;
+  EFI_HII_VALUE           *HiiValue;
+  UINT8                   Index;
+  FORMSET_STORAGE         *VarList;
+  UINT8                   *VarBuffer;
+  BOOLEAN                 ConstantFlag;
+  UINT16                  OriginalDefaultId;
+  FORMSET_DEFAULTSTORE    *DefaultStore;
+  LIST_ENTRY              *DefaultLink;
+  CHAR16                  *VarDefaultName;
+
+  VarDefaultName  = NULL;
+  Status          = EFI_SUCCESS;
+  ConstantFlag    = TRUE;
+  OriginalDefaultId  = DefaultId;
+  DefaultLink        = GetFirstNode (&FormSet->DefaultStoreListHead);
+
+  //
+  // Statement don't have storage, skip them
+  //
+  if (Question->QuestionId == 0) {
+    return EFI_NOT_FOUND;
+  }
+  //
+  // Return if no any kinds of
+  //
+  if ((Question->Operand != EFI_IFR_CHECKBOX_OP)
+    && (Question->Operand != EFI_IFR_ONE_OF_OP)
+    && (Question->Operand != EFI_IFR_ORDERED_LIST_OP)
+    && (Question->Operand != EFI_IFR_NUMERIC_OP)
+    && (Question->Operand != EFI_IFR_STRING_OP)
+    ) {
+    return EFI_ABORTED;
+  }
+  //
+  // Search the variable for this question (Compatible with the old EfiVarStore before UEFI2.31)
+  //
+
+  //
+  //VarStoreInfoDepending on the type of variable store selected,
+  //this contains either a 16-bit Buffer Storage offset (VarOffset)
+  //or a Name/Value or EFI Variable name (VarName).
+  //
+  Status = SearchVarStorage (
+             Question,
+             NULL,
+             Question->VarStoreInfo.VarOffset,
+             FormSet->StorageListHead,
+             (CHAR8 **)&VarBuffer,
+             &VarList
+             );
+  if (EFI_ERROR(Status)) {
+    return Status;
+  }
+  //
+  // There are three ways to specify default value for a Question:
+  //  1, use nested EFI_IFR_DEFAULT
+  //  2, set flags of EFI_ONE_OF_OPTION (provide Standard and Manufacturing default)
+  //  3, set flags of EFI_IFR_CHECKBOX (provide Standard and Manufacturing default) (lowest priority)
+  //
+ReGetDefault:
+  HiiValue = &Question->HiiValue;
+  //
+  // EFI_IFR_DEFAULT has highest priority
+  //
+  if (!IsListEmpty (&Question->DefaultListHead)) {
+    Link = GetFirstNode (&Question->DefaultListHead);
+    while (!IsNull (&Question->DefaultListHead, Link)) {
+      Default = QUESTION_DEFAULT_FROM_LINK (Link);
+
+      if (Default->DefaultId == DefaultId) {
+        if (Default->ValueExpression != NULL) {
+          //
+          // Default is provided by an Expression, evaluate it
+          //
+          Status = EvaluateExpression (FormSet, Form, Default->ValueExpression, &ConstantFlag);
+          if (EFI_ERROR (Status)) {
+            return Status;
+          }
+
+          if (Default->ValueExpression->Result.Type == EFI_IFR_TYPE_BUFFER) {
+            if (Question->StorageWidth > Default->ValueExpression->Result.BufferLen) {
+              CopyMem(Question->HiiValue.Buffer, Default->ValueExpression->Result.Buffer, Default->ValueExpression->Result.BufferLen);
+              Question->HiiValue.BufferLen = Default->ValueExpression->Result.BufferLen;
+            } else {
+              CopyMem(Question->HiiValue.Buffer, Default->ValueExpression->Result.Buffer, Question->StorageWidth);
+              Question->HiiValue.BufferLen = Question->StorageWidth;
+            }
+            FreePool(Default->ValueExpression->Result.Buffer);
+          }
+          HiiValue->Type = Default->ValueExpression->Result.Type;
+          CopyMem(&HiiValue->Value, &Default->ValueExpression->Result.Value, sizeof (EFI_IFR_TYPE_VALUE));
+        } else {
+          //
+          // Default value is embedded in EFI_IFR_DEFAULT
+          //
+          if (Default->Value.Type == EFI_IFR_TYPE_BUFFER) {
+            CopyMem(HiiValue->Buffer, Default->Value.Buffer, Default->Value.BufferLen);
+          } else {
+            CopyMem(HiiValue, &Default->Value, sizeof (EFI_HII_VALUE));
+          }
+        }
+        if (Default->Value.Type == EFI_IFR_TYPE_BUFFER) {
+          CopyMem(VarBuffer, HiiValue->Buffer, HiiValue->BufferLen);
+        } else if (HiiValue->Type == EFI_IFR_TYPE_STRING){
+          Status = FindDefaultName (
+                 &(FormSet->EnUsStringList),
+                 FormSet->UnicodeBinary,
+                 HiiValue->Value.string,
+                 EN_US,
+                 &VarDefaultName
+                 );
+          if (VarDefaultName == NULL) {
+            return EFI_NOT_FOUND;
+          }
+          if (Question->StorageWidth > FceStrSize(VarDefaultName)) {
+            ZeroMem (VarBuffer, Question->StorageWidth);
+            CopyMem (VarBuffer, VarDefaultName, FceStrSize(VarDefaultName));
+          } else {
+            CopyMem (VarBuffer, VarDefaultName, Question->StorageWidth);
+          }
+        } else {
+          if (Question->QuestionReferToBitField) {
+            SetBitsQuestionValue(Question, VarBuffer, HiiValue->Value.u32);
+          } else {
+            CopyMem(VarBuffer, &HiiValue->Value.u64, Question->StorageWidth);
+          }
+        }
+        return EFI_SUCCESS;
+      }
+      if (Default->DefaultId == DefaultId) {
+          return EFI_SUCCESS;
+       }
+      Link = GetNextNode (&Question->DefaultListHead, Link);
+    }
+  }
+
+  if (HiiValue->Buffer == NULL) {
+    ZeroMem (HiiValue, sizeof (EFI_HII_VALUE));
+  }
+
+  //
+  // EFI_ONE_OF_OPTION
+  //
+  if ((Question->Operand == EFI_IFR_ONE_OF_OP) && !IsListEmpty (&Question->OptionListHead)) {
+    if (DefaultId <= EFI_HII_DEFAULT_CLASS_MANUFACTURING)  {
+      //
+      // OneOfOption could only provide Standard and Manufacturing default
+      //
+      Link = GetFirstNode (&Question->OptionListHead);
+      while (!IsNull (&Question->OptionListHead, Link)) {
+        Option = QUESTION_OPTION_FROM_LINK (Link);
+
+        if (((DefaultId == EFI_HII_DEFAULT_CLASS_STANDARD) && ((Option->Flags & EFI_IFR_OPTION_DEFAULT) != 0)) ||
+            ((DefaultId == EFI_HII_DEFAULT_CLASS_MANUFACTURING) && ((Option->Flags & EFI_IFR_OPTION_DEFAULT_MFG) != 0))
+           ) {
+          CopyMem (HiiValue, &Option->Value, sizeof (EFI_HII_VALUE));
+          if (Question->QuestionReferToBitField) {
+            SetBitsQuestionValue(Question, VarBuffer, HiiValue->Value.u32);
+          } else {
+            CopyMem (VarBuffer, &HiiValue->Value.u64, Question->StorageWidth);
+          }
+          return EFI_SUCCESS;
+        }
+
+        Link = GetNextNode (&Question->OptionListHead, Link);
+      }
+    }
+  }
+
+  //
+  // EFI_IFR_CHECKBOX - lowest priority
+  //
+  if (Question->Operand == EFI_IFR_CHECKBOX_OP) {
+    if (DefaultId <= EFI_HII_DEFAULT_CLASS_MANUFACTURING)  {
+      //
+      // Checkbox could only provide Standard and Manufacturing default
+      //
+      if (((DefaultId == EFI_HII_DEFAULT_CLASS_STANDARD) && ((Question->Flags & EFI_IFR_CHECKBOX_DEFAULT) != 0)) ||
+          ((DefaultId == EFI_HII_DEFAULT_CLASS_MANUFACTURING) && ((Question->Flags & EFI_IFR_CHECKBOX_DEFAULT_MFG) != 0))
+         ) {
+        HiiValue->Value.b = TRUE;
+        if (Question->QuestionReferToBitField) {
+          SetBitsQuestionValue(Question, VarBuffer, HiiValue->Value.u32);
+        } else {
+          CopyMem (VarBuffer, &HiiValue->Value.u64, Question->StorageWidth);
+        }
+        return EFI_SUCCESS;
+      }
+    }
+  }
+
+  //
+  // For question without default value for current default Id, we try to re-get the default value form other default id in the DefaultStoreList.
+  // If get, will exit the function, if not, will choose next default id in the DefaultStoreList.
+  // The default id in DefaultStoreList are in ascending order to make sure choose the smallest default id every time.
+  //
+  while (!IsNull(&FormSet->DefaultStoreListHead, DefaultLink)) {
+    DefaultStore = FORMSET_DEFAULTSTORE_FROM_LINK(DefaultLink);
+    DefaultLink = GetNextNode (&FormSet->DefaultStoreListHead,DefaultLink);
+    DefaultId = DefaultStore->DefaultId;
+    if (DefaultId == OriginalDefaultId) {
+      continue;
+    }
+    goto ReGetDefault;
+  }
+
+  //
+  // For Questions without default
+  //
+  Status = EFI_NOT_FOUND;
+  switch (Question->Operand) {
+  case EFI_IFR_CHECKBOX_OP:
+    HiiValue->Value.b = FALSE;
+    if (Question->QuestionReferToBitField) {
+      SetBitsQuestionValue(Question, VarBuffer, HiiValue->Value.u32);
+    } else {
+      CopyMem (VarBuffer, &HiiValue->Value.u64, Question->StorageWidth);
+    }
+    break;
+
+  case EFI_IFR_NUMERIC_OP:
+    //
+    // Take minimum value as numeric default value
+    //
+    if ((HiiValue->Value.u64 < Question->Minimum) || (HiiValue->Value.u64 > Question->Maximum)) {
+      HiiValue->Value.u64 = Question->Minimum;
+      if (Question->QuestionReferToBitField) {
+        SetBitsQuestionValue(Question, VarBuffer, HiiValue->Value.u32);
+      } else {
+        CopyMem (VarBuffer, &HiiValue->Value.u64, Question->StorageWidth);
+      }
+      return EFI_SUCCESS;
+    }
+    break;
+
+  case EFI_IFR_ONE_OF_OP:
+    //
+    // Take first oneof option as oneof's default value
+    //
+    if (ValueToOption (FormSet, Question, HiiValue) == NULL) {
+      Link = GetFirstNode (&Question->OptionListHead);
+      if (!IsNull (&Question->OptionListHead, Link)) {
+        Option = QUESTION_OPTION_FROM_LINK (Link);
+        CopyMem (HiiValue, &Option->Value, sizeof (EFI_HII_VALUE));
+        if (Question->QuestionReferToBitField) {
+          SetBitsQuestionValue(Question, VarBuffer, HiiValue->Value.u32);
+        } else {
+          CopyMem (VarBuffer, &HiiValue->Value.u64, Question->StorageWidth);
+        }
+        return EFI_SUCCESS;
+      }
+    }
+    break;
+
+  case EFI_IFR_ORDERED_LIST_OP:
+    //
+    // Take option sequence in IFR as ordered list's default value
+    //
+    Index = 0;
+    Link = GetFirstNode (&Question->OptionListHead);
+    while (!IsNull (&Question->OptionListHead, Link)) {
+      Option = QUESTION_OPTION_FROM_LINK (Link);
+
+      SetArrayData (Question->BufferValue, Question->ValueType, Index, Option->Value.Value.u64);
+      SetArrayData (VarBuffer, Question->ValueType, Index, Option->Value.Value.u64);
+
+      Index++;
+      if (Index >= Question->MaxContainers) {
+        break;
+      }
+
+      Link = GetNextNode (&Question->OptionListHead, Link);
+    }
+    break;
+
+  default:
+    break;
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Set the value to the variable of platformId question.
+
+  @param  PlatformId             The form set.
+
+  @retval EFI_SUCCESS            Set successfully.
+
+**/
+EFI_STATUS
+AssignThePlatformId (
+  IN  UINT64   PlatformId
+  )
+{
+  EFI_STATUS          Status;
+  FORMSET_STORAGE     *VarList;
+  UINT8               *VarBuffer;
+
+  Status       = EFI_SUCCESS;
+  VarBuffer    = NULL;
+  //
+  // Set the Storage
+  //
+  Status = SearchVarStorage (
+             &mMultiPlatformParam.PlatformIdQuestion,
+             NULL,
+             mMultiPlatformParam.PlatformIdQuestion.VarStoreInfo.VarOffset,
+             &mVarListEntry,
+             (CHAR8 **)&VarBuffer,
+             &VarList
+             );
+  if (EFI_ERROR(Status)) {
+    return Status;
+  }
+  CopyMem (VarBuffer, &PlatformId, mMultiPlatformParam.PlatformIdWidth);
+  //
+  // Set the  HIIvalue of this questions
+  //
+  CopyMem (&mMultiPlatformParam.Question->HiiValue.Value.u64, &PlatformId, mMultiPlatformParam.PlatformIdWidth);
+
+  switch (mMultiPlatformParam.PlatformIdWidth) {
+    case sizeof (UINT8):
+      mMultiPlatformParam.Question->HiiValue.Type = EFI_IFR_TYPE_NUM_SIZE_8;
+      break;
+
+    case sizeof (UINT16):
+      mMultiPlatformParam.Question->HiiValue.Type = EFI_IFR_TYPE_NUM_SIZE_16;
+      break;
+
+    case sizeof (UINT32):
+      mMultiPlatformParam.Question->HiiValue.Type = EFI_IFR_TYPE_NUM_SIZE_32;
+      break;
+
+    case sizeof (UINT64):
+      mMultiPlatformParam.Question->HiiValue.Type = EFI_IFR_TYPE_NUM_SIZE_64;
+      break;
+
+    default:
+      mMultiPlatformParam.Question->HiiValue.Type = EFI_IFR_TYPE_NUM_SIZE_64;
+   }
+  return EFI_SUCCESS;
+}
+/**
+  Reset Questions to their default value in a Form, Formset or System.
+
+  @param  FormSet                FormSet data structure.
+  @param  Form                   Form data structure.
+  @param  DefaultId              The default Id
+  @param  PlatformId             The platform Id
+  @param  SettingScope           Setting Scope for Default action.
+
+  @retval EFI_SUCCESS            The function completed successfully.
+  @retval EFI_UNSUPPORTED        Unsupport SettingScope.
+
+**/
+EFI_STATUS
+ExtractDefault (
+  IN FORM_BROWSER_FORMSET             *FormSet,
+  IN FORM_BROWSER_FORM                *Form,
+  IN UINT16                           DefaultId,
+  IN UINT64                           PlatformId,
+  IN BROWSER_SETTING_SCOPE            SettingScope
+  )
+{
+  EFI_STATUS              Status;
+  LIST_ENTRY              *FormLink;
+  LIST_ENTRY              *Link;
+  LIST_ENTRY              *FormSetEntryListHead;
+  FORM_BROWSER_STATEMENT  *Question;
+  //
+  // Check the supported setting level.
+  //
+  if (SettingScope >= MaxLevel) {
+    return EFI_UNSUPPORTED;
+  }
+
+  if (SettingScope == FormLevel) {
+    //
+    // Extract Form default
+    //
+    Link = GetFirstNode (&Form->StatementListHead);
+    while (!IsNull (&Form->StatementListHead, Link)) {
+      Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link);
+      Link = GetNextNode (&Form->StatementListHead, Link);
+      //
+      // Re-set the platformId before calcuate the platformId of every question to avoid over-written.
+      //
+      if (mMultiPlatformParam.MultiPlatformOrNot) {
+        Status = AssignThePlatformId (PlatformId);
+        if (EFI_ERROR (Status)) {
+          StringPrint ("Error. Failed to assign the platformId.\n");
+          return Status;
+        }
+      }
+      //
+      // Reset Question to its default value, and store the default to variable
+      //
+      Status = GetQuestionDefault (FormSet, Form, Question, DefaultId, PlatformId);
+      if (EFI_ERROR (Status)) {
+        continue;
+      }
+    }
+  } else if (SettingScope == FormSetLevel) {
+    FormLink = GetFirstNode (&FormSet->FormListHead);
+    while (!IsNull (&FormSet->FormListHead, FormLink)) {
+      Form = FORM_BROWSER_FORM_FROM_LINK (FormLink);
+      ExtractDefault (FormSet, Form, DefaultId, PlatformId, FormLevel);
+      FormLink = GetNextNode (&FormSet->FormListHead, FormLink);
+    }
+  } else if (SettingScope == SystemLevel) {
+    //
+    // Parse Fromset one by one
+    //
+    FormSetEntryListHead = &mFormSetListEntry;
+
+    FormLink = GetFirstNode (FormSetEntryListHead);
+    while (!IsNull (FormSetEntryListHead, FormLink)) {
+      FormSet = FORM_BROWSER_FORMSET_FROM_LINK (FormLink);
+      ExtractDefault (FormSet, NULL, DefaultId, PlatformId, FormSetLevel);
+      FormLink = GetNextNode (FormSetEntryListHead, FormLink);
+    }
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Check whether existed the UQI in Current Unicode String.
+
+  @param  UniPackge         A pointer to a Null-terminated Unicode string Array.
+
+  @return TRUE              If find the uqi, return TRUE
+  @return FALSE             Otherwise, return FALSE
+
+**/
+static
+BOOLEAN
+IsUqiOrNot (
+  IN  UINT8  *UniPackge
+  )
+{
+  CHAR8          *UniBin;
+  UINTN          UniLength;
+  UINTN          Index;
+  BOOLEAN        FindIt;
+
+  UniBin     = (CHAR8 *) UniPackge + 4;
+  Index      = 4;
+  FindIt     = FALSE;
+  UniLength  = *(UINT32 *) UniPackge;
+
+  if (((EFI_HII_PACKAGE_HEADER *)UniBin)->Type == EFI_HII_PACKAGE_STRINGS) {
+    //
+    // Search the uqi language
+    //
+    while ((Index < UniLength) && ((EFI_HII_PACKAGE_HEADER *)UniBin)->Type == EFI_HII_PACKAGE_STRINGS){
+      if (!strcmp (((EFI_HII_STRING_PACKAGE_HDR *)UniBin)->Language, "uqi")) {
+        FindIt = TRUE;
+        break;
+      }
+      Index = Index + ((EFI_HII_STRING_PACKAGE_HDR *)UniBin)->Header.Length;
+      UniBin += ((EFI_HII_STRING_PACKAGE_HDR *)UniBin)->Header.Length;
+    }
+  }
+  return FindIt;
+}
+
+ /**
+  Returns Length of UQI string (in CHAR16) (not including null termination).
+
+  @param  UniPackge         A pointer to a UQI string.
+
+  @return Number            Length of UQIL string (in words) or 0
+
+**/
+static
+UINT16
+GetUqiNum (
+  IN     CHAR16        *UniString
+  )
+{
+  UINT16              Number;
+
+  if (UniString == NULL) {
+    return 0;
+  }
+  for (Number = 0; UniString[Number] != 0; Number++) {
+    ;
+  }
+  return Number;
+}
+
+/**
+  Print the formset title information.
+
+  @param  FormSet    The pointer to the formset.
+
+  @return NULL.
+
+**/
+static
+VOID
+StringPrintormSetTitle (
+  IN  FORM_BROWSER_FORMSET  *FormSet
+  )
+{
+  CHAR16      *VarDefaultName;
+  EFI_STATUS  Status;
+
+  VarDefaultName = NULL;
+
+  StringPrint("\n\n// Form Set: ");
+
+  Status  = FindDefaultName (
+              &(FormSet->EnUsStringList),
+              FormSet->UnicodeBinary,
+              FormSet->FormSetTitle,
+              EN_US,
+              &VarDefaultName
+             );
+  assert (!EFI_ERROR (Status));
+  LogUnicodeString (VarDefaultName);
+
+  StringPrint("\n// %s",FORM_SET_GUID_PREFIX);
+  StringPrint(
+    EFI_GUID_FORMAT,
+    FormSet->Guid.Data1,   FormSet->Guid.Data2,
+    FormSet->Guid.Data3,   FormSet->Guid.Data4[0],
+    FormSet->Guid.Data4[1],FormSet->Guid.Data4[2],
+    FormSet->Guid.Data4[3],FormSet->Guid.Data4[4],
+    FormSet->Guid.Data4[5],FormSet->Guid.Data4[6],
+    FormSet->Guid.Data4[7]);
+  StringPrint("\n");
+
+  if (&(FormSet->EnUsStringList) == NULL && VarDefaultName != NULL && FormSet->FormSetTitle != 0) {
+    free (VarDefaultName);
+    VarDefaultName = NULL;
+  }
+}
+
+/**
+  Print the formset title information.
+
+  @param  FormSet    The pointer to the formset.
+  @param  Question   The pointer to the question of ONE_OF.
+
+  @return NULL.
+
+**/
+static
+EFI_STATUS
+PrintOneOfOptions (
+  IN  FORM_BROWSER_FORMSET    *FormSet,
+  IN  FORM_BROWSER_STATEMENT  *Question
+  )
+{
+  LIST_ENTRY       *Link;
+  QUESTION_OPTION  *Option;
+  CHAR16           *VarDefaultName;
+  EFI_STATUS       Status;
+
+  Status = EFI_SUCCESS;
+  VarDefaultName = NULL;
+
+  if ((Question->Operand != EFI_IFR_ONE_OF_OP)
+    && (Question->Operand != EFI_IFR_ORDERED_LIST_OP)
+    ) {
+    return EFI_ABORTED;
+  }
+
+  Link = GetFirstNode (&Question->OptionListHead);
+  while (!IsNull (&Question->OptionListHead, Link)) {
+    Option = QUESTION_OPTION_FROM_LINK (Link);
+    if (Question->QuestionReferToBitField) {
+      StringPrint("// %08X = ", Option->Value.Value.u32);
+    } else {
+      switch(Option->Value.Type) {
+
+        case EFI_IFR_TYPE_NUM_SIZE_8:
+          StringPrint("// %02X = ", Option->Value.Value.u8);
+          break;
+
+        case EFI_IFR_TYPE_NUM_SIZE_16:
+          StringPrint("// %04X = ", Option->Value.Value.u16);
+          break;
+
+        case EFI_IFR_TYPE_NUM_SIZE_32:
+          StringPrint("// %08X = ", Option->Value.Value.u32);
+          break;
+
+        case EFI_IFR_TYPE_NUM_SIZE_64:
+          StringPrint("// %016llX = ", Option->Value.Value.u64);
+          break;
+
+        case EFI_IFR_TYPE_BOOLEAN:
+          StringPrint("// %X = ", Option->Value.Value.b);
+          break;
+
+        case EFI_IFR_TYPE_STRING:
+          StringPrint("// %X = ", Option->Value.Value.string);
+          break;
+
+        default:
+          break;
+        }
+      }
+    Status = FindDefaultName (
+               &(FormSet->EnUsStringList),
+               FormSet->UnicodeBinary,
+               Option->Text,
+               EN_US,
+               &VarDefaultName
+               );
+
+    LogUnicodeString (VarDefaultName);
+    StringPrint("\n");
+    if (&(FormSet->EnUsStringList) == NULL && VarDefaultName != NULL && Option->Text != 0) {
+      free (VarDefaultName);
+      VarDefaultName = NULL;
+    }
+    Link = GetNextNode (&Question->OptionListHead, Link);
+  }
+  return Status;
+}
+
+/**
+  Print the form title information.
+
+  @param  FormSet    The pointer to the formset.
+  @param  FormSet    The pointer to the form.
+
+  @return NULL.
+
+**/
+static
+VOID
+StringPrintormTitle (
+  IN  FORM_BROWSER_FORMSET  *FormSet,
+  IN  FORM_BROWSER_FORM     *Form
+  )
+{
+  CHAR16      *VarDefaultName;
+  EFI_STATUS  Status;
+
+  VarDefaultName = NULL;
+
+  StringPrint("\n// Form: ");
+  Status  = FindDefaultName (
+              &(FormSet->EnUsStringList),
+              FormSet->UnicodeBinary,
+              Form->FormTitle,
+              EN_US,
+              &VarDefaultName
+             );
+  assert (!EFI_ERROR (Status));
+
+  LogUnicodeString (VarDefaultName);
+  StringPrint("\n");
+
+  if (&(FormSet->EnUsStringList) == NULL && VarDefaultName != NULL && Form->FormTitle != 0) {
+    free (VarDefaultName);
+    VarDefaultName  = NULL;
+  }
+
+}
+
+/**
+  Print the information of questions.
+
+  @param  FormSet     The pointer to the formset.
+  @param  FormSet     The pointer to the form.
+  @param  Question    The pointer to the question.
+  @param  PrintOrNot  Decide whether print or not.
+
+  @return NULL.
+
+**/
+static
+VOID
+PrintQuestion (
+  IN  FORM_BROWSER_FORMSET    *FormSet,
+  IN  FORM_BROWSER_FORM       *Form,
+  IN  FORM_BROWSER_STATEMENT  *Question,
+  IN  BOOLEAN                  PrintOrNot
+  )
+{
+  EFI_STATUS       Status;
+  CHAR16           *VarDefaultName;
+  UINT16           UqiStringLength;
+  BOOLEAN          HaveUQIlanguage;
+
+  Status           = EFI_SUCCESS;
+  VarDefaultName   = NULL;
+  UqiStringLength  = 0;
+
+  HaveUQIlanguage = IsUqiOrNot (FormSet->UnicodeBinary);
+
+  switch (Question->Operand) {
+
+  case EFI_IFR_SUBTITLE_OP:
+  if (PrintOrNot) {
+    Status  = FindDefaultName (
+                &(FormSet->EnUsStringList),
+                FormSet->UnicodeBinary,
+                Question->Prompt,
+                EN_US,
+                &VarDefaultName
+                );
+    assert (!EFI_ERROR (Status));
+    if ((VarDefaultName != NULL) && (FceStrCmp (VarDefaultName, L"") != 0)) {
+      StringPrint("// Subtitle: ");
+      StringPrint("// ");
+      LogUnicodeString (VarDefaultName);
+      StringPrint("\n");
+    }
+  }
+    break;
+
+  case EFI_IFR_ONE_OF_OP:
+
+    if( HaveUQIlanguage ) {
+      Status = FindDefaultName (
+                 &(FormSet->UqiStringList),
+                 FormSet->UnicodeBinary,
+                 Question->Prompt,
+                 UQI,
+                 &VarDefaultName
+                 );
+      assert (!EFI_ERROR (Status));
+
+      UqiStringLength = GetUqiNum (VarDefaultName);
+      if (PrintOrNot) {
+        if (UqiStringLength > 0) {
+          StringPrint("\nQ %04X ", UqiStringLength);
+          LogUqi(VarDefaultName);
+        } else {
+          StringPrint("\n// [No UQI] ");
+        }
+      }
+    } else {
+      Status       = FindDefaultName (
+                       &(FormSet->EnUsStringList),
+                       FormSet->UnicodeBinary,
+                       Question->Prompt,
+                       EN_US,
+                       &VarDefaultName
+                     );
+      assert (!EFI_ERROR (Status));
+      UqiStringLength = GetUqiNum (VarDefaultName);
+
+      if (PrintOrNot) {
+        if (UqiStringLength > 0) {
+          StringPrint("\nQ %04X ", UqiStringLength);
+          LogUqi(VarDefaultName);
+        } else {
+          StringPrint("\n// [No UQI] ");
+        }
+      }
+    }
+    //
+    //Record the UQi to the Question
+    //
+    Question->Uqi.HexNum = UqiStringLength;
+    Question->Uqi.Data   = VarDefaultName;
+    Question->Uqi.Type   = ONE_OF;
+
+    if (PrintOrNot) {
+      StringPrint("ONE_OF ");
+
+      LogIfrValue (
+        FormSet,
+        Question
+        );
+      StringPrint(" // ");
+      Status       = FindDefaultName (
+                       &(FormSet->EnUsStringList),
+                       FormSet->UnicodeBinary,
+                       Question->Prompt,
+                       EN_US,
+                       &VarDefaultName
+                       );
+      assert (!EFI_ERROR (Status));
+      LogUnicodeString (VarDefaultName);
+      StringPrint("\n");
+      //
+      // Print ONE_OF_OPTION
+      //
+      PrintOneOfOptions (FormSet, Question);
+    }
+    break;
+
+  case EFI_IFR_CHECKBOX_OP:
+
+    if( HaveUQIlanguage ) {
+      Status = FindDefaultName (
+                 &(FormSet->UqiStringList),
+                 FormSet->UnicodeBinary,
+                 Question->Prompt,
+                 UQI,
+                 &VarDefaultName
+                 );
+      assert (!EFI_ERROR (Status));
+
+      UqiStringLength = GetUqiNum (VarDefaultName);
+      if (PrintOrNot) {
+        if (UqiStringLength > 0) {
+          StringPrint("\nQ %04X ", UqiStringLength);
+          LogUqi(VarDefaultName);
+        } else {
+          StringPrint("\n// [No UQI] ");
+        }
+      }
+    } else {
+      Status = FindDefaultName (
+                 &(FormSet->EnUsStringList),
+                 FormSet->UnicodeBinary,
+                 Question->Prompt,
+                 EN_US,
+                 &VarDefaultName
+                 );
+      assert (!EFI_ERROR (Status));
+
+      UqiStringLength = GetUqiNum (VarDefaultName);
+
+      if (PrintOrNot) {
+        if (UqiStringLength > 0) {
+          StringPrint("\nQ %04X ", UqiStringLength);
+          LogUqi(VarDefaultName);
+        } else {
+          StringPrint("\n// [No UQI] ");
+        }
+      }
+    }
+    //
+    //Record the UQi to the HiiObjList
+    //
+    Question->Uqi.HexNum = UqiStringLength;
+    Question->Uqi.Data   = VarDefaultName;
+    Question->Uqi.Type   = CHECKBOX;
+    if (PrintOrNot) {
+      StringPrint("CHECKBOX ");
+      LogIfrValue (
+        FormSet,
+        Question
+        );
+      StringPrint(" // ");
+      Status = FindDefaultName (
+                 &(FormSet->EnUsStringList),
+                 FormSet->UnicodeBinary,
+                 Question->Prompt,
+                 EN_US,
+                 &VarDefaultName
+                 );
+      assert (!EFI_ERROR (Status));
+      LogUnicodeString (VarDefaultName);
+      StringPrint("\n");
+      StringPrint("// 0 = Unchecked\n");
+      StringPrint("// 1 = Checked\n");
+    }
+    break;
+
+  case EFI_IFR_STRING_OP:
+    if( HaveUQIlanguage ) {
+      Status = FindDefaultName (
+                 &(FormSet->UqiStringList),
+                 FormSet->UnicodeBinary,
+                 Question->Prompt,
+                 UQI,
+                 &VarDefaultName
+                 );
+      assert (!EFI_ERROR (Status));
+
+      UqiStringLength = GetUqiNum (VarDefaultName);
+      if (PrintOrNot) {
+        if (UqiStringLength > 0) {
+          StringPrint("\nQ %04X ", UqiStringLength);
+          LogUqi(VarDefaultName);
+        } else {
+          StringPrint("\n// [No UQI] ");
+        }
+      }
+    } else {
+      Status = FindDefaultName (
+                 &(FormSet->EnUsStringList),
+                 FormSet->UnicodeBinary,
+                 Question->Prompt,
+                 EN_US,
+                 &VarDefaultName
+                 );
+      assert (!EFI_ERROR (Status));
+
+      UqiStringLength = GetUqiNum (VarDefaultName);
+
+      if (PrintOrNot) {
+        if (UqiStringLength > 0) {
+          StringPrint("\nQ %04X ", UqiStringLength);
+          LogUqi(VarDefaultName);
+        } else {
+          StringPrint("\n// [No UQI] ");
+        }
+      }
+    }
+    //
+    //Record the UQi to the HiiObjList
+    //
+    Question->Uqi.HexNum = UqiStringLength;
+    Question->Uqi.Data   = VarDefaultName;
+    Question->Uqi.Type   = STRING;
+    if (PrintOrNot) {
+      StringPrint("STRING ");
+      LogIfrValueStr (
+        FormSet,
+        Question
+        );
+      StringPrint(" // ");
+      Status = FindDefaultName (
+                 &(FormSet->EnUsStringList),
+                 FormSet->UnicodeBinary,
+                 Question->Prompt,
+                 EN_US,
+                 &VarDefaultName
+                 );
+      assert (!EFI_ERROR (Status));
+      LogUnicodeString (VarDefaultName);
+      StringPrint("\n");
+    }
+    break;
+
+  case EFI_IFR_NUMERIC_OP:
+
+    if( HaveUQIlanguage ) {
+      Status = FindDefaultName (
+                 &(FormSet->UqiStringList),
+                 FormSet->UnicodeBinary,
+                 Question->Prompt,
+                 UQI,
+                 &VarDefaultName
+                 );
+      assert (!EFI_ERROR (Status));
+
+      UqiStringLength = GetUqiNum (VarDefaultName);
+      if (PrintOrNot) {
+        if (UqiStringLength > 0) {
+          StringPrint("\nQ %04X ", UqiStringLength);
+          LogUqi(VarDefaultName);
+        } else {
+          StringPrint("\n// [No UQI] ");
+        }
+      }
+    } else {
+      Status = FindDefaultName (
+                 &(FormSet->EnUsStringList),
+                 FormSet->UnicodeBinary,
+                 Question->Prompt,
+                 EN_US,
+                 &VarDefaultName
+                 );
+      assert (!EFI_ERROR (Status));
+
+      UqiStringLength = GetUqiNum (VarDefaultName);
+      if (PrintOrNot) {
+        if (UqiStringLength > 0) {
+          StringPrint("\nQ %04X ", UqiStringLength);
+          LogUqi(VarDefaultName);
+        } else {
+          StringPrint("\n// [No UQI] ");
+        }
+      }
+    }
+    //
+    //Record the UQi to the HiiObjList
+    //
+    Question->Uqi.HexNum = UqiStringLength;
+    Question->Uqi.Data   = VarDefaultName;
+    Question->Uqi.Type   = NUMERIC;
+    if (PrintOrNot) {
+      StringPrint("NUMERIC ");
+      LogIfrValue (
+        FormSet,
+        Question
+      );
+      StringPrint(" // ");
+      Status = FindDefaultName (
+                 &(FormSet->EnUsStringList),
+                 FormSet->UnicodeBinary,
+                 Question->Prompt,
+                 EN_US,
+                 &VarDefaultName
+                 );
+      assert (!EFI_ERROR (Status));
+      LogUnicodeString (VarDefaultName);
+      StringPrint("\n");
+
+      if (Question->QuestionReferToBitField) {
+        StringPrint("// Minimum = %08llX \n", Question->Minimum);
+        StringPrint("// Maximum = %08llX \n", Question->Maximum);
+        StringPrint("// Step    = %08llX \n", Question->Step);
+      } else {
+        switch (Question->StorageWidth) {
+
+        case sizeof (UINT8):
+          StringPrint("// Minimum = %02llX \n", Question->Minimum);
+          StringPrint("// Maximum = %02llX \n", Question->Maximum);
+          StringPrint("// Step    = %02llX \n", Question->Step);
+          break;
+
+        case sizeof (UINT16):
+          StringPrint("// Minimum = %04llX \n", Question->Minimum);
+          StringPrint("// Maximum = %04llX \n", Question->Maximum);
+          StringPrint("// Step    = %04llX \n", Question->Step);
+          break;
+
+        case sizeof (UINT32):
+          StringPrint("// Minimum = %08llX \n", Question->Minimum);
+          StringPrint("// Maximum = %08llX \n", Question->Maximum);
+          StringPrint("// Step    = %08llX \n", Question->Step);
+          break;
+
+        case sizeof (UINT64):
+          StringPrint("// Minimum = %016llX \n", Question->Minimum);
+          StringPrint("// Maximum = %016llX \n", Question->Maximum);
+          StringPrint("// Step    = %016llX \n", Question->Step);
+          break;
+
+        default:
+          StringPrint("0000 // Width > 16 is not supported -- FAILURE");
+          break;
+        }
+      }
+    }
+    break;
+
+  case EFI_IFR_ORDERED_LIST_OP:
+
+    if( HaveUQIlanguage ) {
+      Status = FindDefaultName (
+                 &(FormSet->UqiStringList),
+                 FormSet->UnicodeBinary,
+                 Question->Prompt,
+                 UQI,
+                 &VarDefaultName
+                 );
+      assert (!EFI_ERROR (Status));
+      UqiStringLength = GetUqiNum (VarDefaultName);
+
+      if (PrintOrNot) {
+        if (UqiStringLength > 0) {
+          StringPrint("\nQ %04X ", UqiStringLength);
+          LogUqi(VarDefaultName);
+        } else {
+          StringPrint("\n// [No UQI] ");
+        }
+      }
+    } else {
+      Status = FindDefaultName (
+                 &(FormSet->EnUsStringList),
+                 FormSet->UnicodeBinary,
+                 Question->Prompt,
+                 EN_US,
+                 &VarDefaultName
+                 );
+
+      assert (!EFI_ERROR (Status));
+
+      UqiStringLength = GetUqiNum (VarDefaultName);
+      if (PrintOrNot) {
+        if (UqiStringLength > 0) {
+          StringPrint("\nQ %04X ", UqiStringLength);
+          LogUqi(VarDefaultName);
+        } else {
+          StringPrint("\n// [No UQI] ");
+        }
+      }
+    }
+    //
+    //Record the UQi to the HiiObjList
+    //
+    Question->Uqi.HexNum = UqiStringLength;
+    Question->Uqi.Data   = VarDefaultName;
+    Question->Uqi.Type   = ORDERED_LIST;
+
+    if (PrintOrNot) {
+      StringPrint("ORDERED_LIST %04X ", Question->MaxContainers);
+
+      LogIfrValueList (
+        FormSet,
+        Question
+        );
+      StringPrint(" // ");
+      Status = FindDefaultName (
+                 &(FormSet->EnUsStringList),
+                 FormSet->UnicodeBinary,
+                 Question->Prompt,
+                 EN_US,
+                 &VarDefaultName
+                 );
+      assert (!EFI_ERROR (Status));
+      LogUnicodeString (VarDefaultName);
+      StringPrint("\n");
+    }
+    //
+    // Print ONE_OF_OPTION
+    //
+    PrintOneOfOptions (FormSet, Question);
+    break;
+
+  default:
+    break;
+  }
+
+  if (&(FormSet->EnUsStringList) == NULL &&VarDefaultName != NULL && Question->Prompt != 0) {
+    free (VarDefaultName);
+    VarDefaultName = NULL;
+  }
+
+  if (PrintOrNot && Question->Storage) {
+    StringPrint("// size = 0x%x", Question->StorageWidth);
+    StringPrint("\n// offset = 0x%x", Question->VarStoreInfo.VarOffset);
+    StringPrint("\n// name = ");
+    LogUnicodeString(Question->VariableName);
+    StringPrint("\n// guid = ");
+    StringPrint(
+      EFI_GUID_FORMAT,
+      Question->Guid.Data1,   Question->Guid.Data2,
+      Question->Guid.Data3,   Question->Guid.Data4[0],
+      Question->Guid.Data4[1],Question->Guid.Data4[2],
+      Question->Guid.Data4[3],Question->Guid.Data4[4],
+      Question->Guid.Data4[5],Question->Guid.Data4[6],
+      Question->Guid.Data4[7]
+    );
+    StringPrint("\n// attribute = 0x%x", Question->Attributes);
+    StringPrint("\n// help = ");
+    Status = FindDefaultName (
+               &(FormSet->EnUsStringList),
+               FormSet->UnicodeBinary,
+               Question->Help,
+               EN_US,
+               &VarDefaultName
+               );
+    assert (!EFI_ERROR (Status));
+    LogUnicodeString (VarDefaultName);
+    StringPrint("\n");
+    if (&(FormSet->EnUsStringList) == NULL &&VarDefaultName != NULL && Question->Help != 0) {
+      free (VarDefaultName);
+      VarDefaultName = NULL;
+    }
+  }
+
+}
+
+/**
+  Check whether current Formset or Form is NULL. If no valid questions, return FASLE.
+
+  @param  FormSet     The pointer to the formset.
+  @param  FormSet     The pointer to the form.
+  @param  IsFormSet   FormSet or Form.
+
+  @retval TRUE
+  @return FALSE
+**/
+BOOLEAN
+CheckFormSetOrFormNull (
+  IN  FORM_BROWSER_FORMSET    *FormSet,
+  IN  FORM_BROWSER_FORM       *Form,
+  IN  BOOLEAN                  IsFormSet
+  )
+{
+  LIST_ENTRY              *FormLink;
+  FORM_BROWSER_STATEMENT  *Question;
+  LIST_ENTRY              *QuestionLink;
+
+  FormLink     = NULL;
+  Question     = NULL;
+  QuestionLink = NULL;
+
+  //
+  // Parse all forms in formset
+  //
+  if (IsFormSet) {
+    FormLink = GetFirstNode (&FormSet->FormListHead);
+
+    while (!IsNull (&FormSet->FormListHead, FormLink)) {
+      Form = FORM_BROWSER_FORM_FROM_LINK (FormLink);
+      //
+      // Parse five kinds of Questions in Form
+      //
+      QuestionLink = GetFirstNode (&Form->StatementListHead);
+
+      while (!IsNull (&Form->StatementListHead, QuestionLink)) {
+        Question = FORM_BROWSER_STATEMENT_FROM_LINK (QuestionLink);
+        //
+        // Parse five kinds of Questions in Form
+        //
+        if ((Question->Operand == EFI_IFR_ONE_OF_OP)
+          || (Question->Operand == EFI_IFR_NUMERIC_OP)
+          || (Question->Operand == EFI_IFR_CHECKBOX_OP)
+          || (Question->Operand == EFI_IFR_ORDERED_LIST_OP)
+          || (Question->Operand == EFI_IFR_STRING_OP)
+          ) {
+          if (mMultiPlatformParam.MultiPlatformOrNot) {
+            //
+            // Only compare the valid EFI_IFR_VARSTORE_EFI_OP in multi-platform mode
+            //
+            if (Question->Type != EFI_IFR_VARSTORE_EFI_OP) {
+              QuestionLink = GetNextNode (&Form->StatementListHead, QuestionLink);
+              continue;
+            }
+            if (Question->Type == EFI_IFR_VARSTORE_EFI_OP
+              && Question->NewEfiVarstore
+              && ((Question->Attributes & EFI_VARIABLE_NON_VOLATILE) == 0)) {
+              QuestionLink = GetNextNode (&Form->StatementListHead, QuestionLink);
+              continue;
+            }
+          }
+          //
+          //If invalid variable type, skip it.
+          //
+           if ((Question->Type != EFI_IFR_VARSTORE_EFI_OP)
+             && (Question->Type != EFI_IFR_VARSTORE_OP)) {
+             QuestionLink = GetNextNode (&Form->StatementListHead, QuestionLink);
+             continue;
+          }
+          return TRUE;
+        }
+        QuestionLink = GetNextNode (&Form->StatementListHead, QuestionLink);
+      }
+
+      FormLink = GetNextNode (&FormSet->FormListHead, FormLink);
+    }
+ } else {
+   //
+   // Parse five kinds of Questions in Form
+   //
+   QuestionLink = GetFirstNode (&Form->StatementListHead);
+
+   while (!IsNull (&Form->StatementListHead, QuestionLink)) {
+     Question = FORM_BROWSER_STATEMENT_FROM_LINK (QuestionLink);
+     //
+     // Parse five kinds of Questions in Form
+     //
+     if ((Question->Operand == EFI_IFR_ONE_OF_OP)
+       || (Question->Operand == EFI_IFR_NUMERIC_OP)
+       || (Question->Operand == EFI_IFR_CHECKBOX_OP)
+       || (Question->Operand == EFI_IFR_ORDERED_LIST_OP)
+       || (Question->Operand == EFI_IFR_STRING_OP)
+       ) {
+       if (mMultiPlatformParam.MultiPlatformOrNot) {
+         //
+         // Only compare the valid EFI_IFR_VARSTORE_EFI_OP in multi-platform mode
+         //
+         if (Question->Type != EFI_IFR_VARSTORE_EFI_OP) {
+           QuestionLink = GetNextNode (&Form->StatementListHead, QuestionLink);
+           continue;
+         }
+         if ((Question->Type == EFI_IFR_VARSTORE_EFI_OP)
+           && Question->NewEfiVarstore
+           && ((Question->Attributes & EFI_VARIABLE_NON_VOLATILE) == 0)) {
+           QuestionLink = GetNextNode (&Form->StatementListHead, QuestionLink);
+           continue;
+         }
+       }
+       //
+       //If invalid variable type, skip it.
+       //
+       if ((Question->Type != EFI_IFR_VARSTORE_EFI_OP)
+         && (Question->Type != EFI_IFR_VARSTORE_OP)) {
+         QuestionLink = GetNextNode (&Form->StatementListHead, QuestionLink);
+         continue;
+       }
+       return TRUE;
+     }
+     QuestionLink = GetNextNode (&Form->StatementListHead, QuestionLink);
+   }
+ }
+ return FALSE;
+}
+
+/**
+  Print all ONE_OF ORDER_LIST NUMERIC STRING and CHECKBOX in all fromsets.
+
+  @param Formset        The pointer to the entry of the fromset list
+  @param Formset        The pointer to the entry of the storage list
+
+  @retval EFI_SUCCESS   It was complete successfully
+  @return EFI_ABORTED   An error occurred
+**/
+EFI_STATUS
+PrintInfoInAllFormset (
+  IN LIST_ENTRY      *FormSetEntryListHead,
+  IN LIST_ENTRY      *StorageEntryListHead
+  )
+{
+  EFI_STATUS              Status;
+  FORM_BROWSER_FORMSET    *FormSet;
+  LIST_ENTRY              *FormSetLink;
+  LIST_ENTRY              *FormLink;
+  FORM_BROWSER_FORM       *Form;
+  FORM_BROWSER_STATEMENT  *Question;
+  LIST_ENTRY              *QuestionLink;
+  FORMSET_STORAGE         *Storage;
+  CHAR8                   *VarBuffer;
+  LIST_ENTRY              *TempStorageLink;
+  UINT32                  Index;
+  BOOLEAN                 Skip;
+  BOOLEAN                 ConstantFlag;
+
+  Status          = EFI_SUCCESS;
+  FormSet         = NULL;
+  FormSetLink     = NULL;
+  FormLink        = NULL;
+  Form            = NULL;
+  Question        = NULL;
+  QuestionLink    = NULL;
+  Storage         = NULL;
+  VarBuffer       = NULL;
+  TempStorageLink = NULL;
+  Index           = 0;
+  Skip            = FALSE;
+  ConstantFlag    = TRUE;
+  //
+  // Print platformId, defaultId and platformIdUqi
+  //
+  if (mMultiPlatformParam.MultiPlatformOrNot) {
+    StringPrint("\n\n// FCEKEY DEFAULT_ID:");
+    TempStorageLink = GetFirstNode (StorageEntryListHead);
+    Storage = FORMSET_STORAGE_FROM_LINK (TempStorageLink);
+    for (Index = 0; Index <= Storage->DefaultPlatformIdNum; Index++) {
+      StringPrint (" %4d", Storage->DefaultId[Index]);
+    }
+    StringPrint("\n\n//FCEKEY PLATFORM_ID:");
+    for (Index = 0; Index <= Storage->DefaultPlatformIdNum; Index++) {
+      StringPrint (" %4lld", Storage->PlatformId[Index]);
+    }
+    if (mMultiPlatformParam.Uqi.Data != NULL) {
+      StringPrint("\n\n//FCEKEY PLATFORM_UQI:");
+      StringPrint(" %04X ", mMultiPlatformParam.Uqi.HexNum);
+      LogUqi(mMultiPlatformParam.Uqi.Data);
+    }
+  }
+  FormSetLink = GetFirstNode (FormSetEntryListHead);
+  while (!IsNull (FormSetEntryListHead, FormSetLink)) {
+    FormSet = FORM_BROWSER_FORMSET_FROM_LINK (FormSetLink);
+    //
+    //Assign the new storage list
+    //
+    FormSet->StorageListHead = StorageEntryListHead;
+
+    if (CheckFormSetOrFormNull (FormSet, NULL, TRUE)) {
+      StringPrintormSetTitle (FormSet);
+    } else {
+      FormSetLink = GetNextNode (FormSetEntryListHead, FormSetLink);
+      continue;
+    }
+    //
+    // Parse all forms in formset
+    //
+    FormLink = GetFirstNode (&FormSet->FormListHead);
+
+    while (!IsNull (&FormSet->FormListHead, FormLink)) {
+      Form = FORM_BROWSER_FORM_FROM_LINK (FormLink);
+
+      if (CheckFormSetOrFormNull (NULL, Form, FALSE)) {
+        StringPrintormTitle(FormSet,Form);
+      } else {
+        FormLink = GetNextNode (&FormSet->FormListHead, FormLink);
+        continue;
+      }
+      //
+      // Parse five kinds of Questions in Form
+      //
+      QuestionLink = GetFirstNode (&Form->StatementListHead);
+
+      while (!IsNull (&Form->StatementListHead, QuestionLink)) {
+        Question = FORM_BROWSER_STATEMENT_FROM_LINK (QuestionLink);
+        //
+        // Parse five kinds of Questions in Form
+        //
+        if ((Question->Operand == EFI_IFR_ONE_OF_OP)
+          || (Question->Operand == EFI_IFR_NUMERIC_OP)
+          || (Question->Operand == EFI_IFR_CHECKBOX_OP)
+          || (Question->Operand == EFI_IFR_ORDERED_LIST_OP)
+          || (Question->Operand == EFI_IFR_SUBTITLE_OP)
+          || (Question->Operand == EFI_IFR_STRING_OP)
+          ) {
+          Skip = FALSE;
+
+          //
+          //Only output the questions stored by EFI_IFR_VARSTORE_EFI_OP.
+          //
+          if (mMultiPlatformParam.MultiPlatformOrNot
+            && (Question->Operand != EFI_IFR_SUBTITLE_OP)
+            ) {
+            Status = SearchVarStorage (
+                       Question,
+                       NULL,
+                       Question->VarStoreInfo.VarOffset,
+                       StorageEntryListHead,
+                       (CHAR8 **)&VarBuffer,
+                       &Storage
+                     );
+
+            if (EFI_ERROR (Status)) {
+              Skip = TRUE;
+            }
+          }
+          //
+          // If Question is constant expression and "disabledIf True", don't output it.
+          //
+          ConstantFlag    = TRUE;
+          if (!Skip && (Question->DisableExpression != NULL)) {
+            Status = EvaluateExpression (FormSet, Form, Question->DisableExpression, &ConstantFlag);
+            if (!EFI_ERROR (Status) && Question->DisableExpression->Result.Value.b && ConstantFlag) {
+              Skip = TRUE;
+            }
+          }
+
+          if (!Skip) {
+            PrintQuestion(FormSet, Form, Question, TRUE);
+          }
+        }
+        QuestionLink = GetNextNode (&Form->StatementListHead, QuestionLink);
+      }
+
+      FormLink = GetNextNode (&FormSet->FormListHead, FormLink);
+    }
+    FormSetLink = GetNextNode (FormSetEntryListHead, FormSetLink);
+  }
+
+  return EFI_SUCCESS;
+}
+
diff --git a/Platform/Intel/Tools/FCE/IfrParse.h b/Platform/Intel/Tools/FCE/IfrParse.h
new file mode 100644
index 0000000000..29a878a191
--- /dev/null
+++ b/Platform/Intel/Tools/FCE/IfrParse.h
@@ -0,0 +1,789 @@
+/** @file
+
+ Parser for IFR binary encoding.
+
+ Copyright (c) 2011-2019, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _IFR_PARSE_H_
+#define _IFR_PARSE_H_
+
+#include "Common.h"
+#include <Common/UefiInternalFormRepresentation.h>
+#include <Common/MdeModuleHii.h>
+
+//
+// Scope for Browser action. It may be Form, FormSet or System level.
+//
+typedef enum {
+  FormLevel,
+  FormSetLevel,
+  SystemLevel,
+  MaxLevel
+} BROWSER_SETTING_SCOPE;
+
+///
+///Old EFI_IFR_VARSTORE_EFI structure to complible with UEFI 2.3
+///
+typedef struct _EFI_IFR_VARSTORE_EFI_OLD {
+  EFI_IFR_OP_HEADER        Header;
+  EFI_VARSTORE_ID          VarStoreId;
+  EFI_GUID                 Guid;
+  UINT32                   Attributes;
+} EFI_IFR_VARSTORE_EFI_OLD;
+
+///
+/// The languages used in HII DB
+///
+typedef enum {
+  UQI,
+  EN_US,
+  ENG
+} LANGUAGE;
+
+///
+/// Define the structure for the parameters of Uqi and Uqi List
+///
+typedef struct _FORM_BROWSER_STATEMENT FORM_BROWSER_STATEMENT;
+
+typedef enum {
+  ONE_OF,
+  NUMERIC,
+  CHECKBOX,
+  STRING,
+  ORDERED_LIST
+} QUEST_TYPE;
+
+typedef struct {
+  UINT16      *DefaultId;
+  UINT64      *PlatformId;
+  UINT32      IdNum;
+  UINT32      HexNum;
+  QUEST_TYPE  Type;
+  CHAR16      *Data;
+  UINT8       *Value;
+  UINT8       *DiffValue;
+  UINT32      ScriptsLine;
+  FORM_BROWSER_STATEMENT *Question;
+} UQI_HEADER;
+
+typedef struct _UQI_PARAM_LIST {
+  struct _UQI_PARAM_LIST   *Next;
+  UQI_HEADER               Header;
+  BOOLEAN                  ParseOrNot;
+  BOOLEAN                  SameOrNot;
+  BOOLEAN                  ErrorOrNot;
+  CHAR8                    *Error;
+} UQI_PARAM_LIST;
+
+//
+// Incremental size of stack for expression
+//
+#define EXPRESSION_STACK_SIZE_INCREMENT    0x100
+
+//
+// IFR relative definition
+//
+#define EFI_HII_EXPRESSION_INCONSISTENT_IF   0
+#define EFI_HII_EXPRESSION_NO_SUBMIT_IF      1
+#define EFI_HII_EXPRESSION_GRAY_OUT_IF       2
+#define EFI_HII_EXPRESSION_SUPPRESS_IF       3
+#define EFI_HII_EXPRESSION_DISABLE_IF        4
+#define EFI_HII_EXPRESSION_VALUE             5
+#define EFI_HII_EXPRESSION_RULE              6
+#define EFI_HII_EXPRESSION_READ              7
+#define EFI_HII_EXPRESSION_WRITE             8
+#define EFI_HII_EXPRESSION_WARNING_IF        9
+
+#define EFI_HII_VARSTORE_BUFFER              0
+#define EFI_HII_VARSTORE_NAME_VALUE          1
+#define EFI_HII_VARSTORE_EFI_VARIABLE        2
+#define EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER 3
+
+#define FORM_INCONSISTENT_VALIDATION         0
+#define FORM_NO_SUBMIT_VALIDATION            1
+
+typedef struct {
+  //
+  // HII Data Type
+  //
+  UINT8               Type;
+  //
+  // Buffer Data and Length if Type is EFI_IFR_TYPE_BUFFER or EFI_IFR_TYPE_STRING
+  //
+  UINT8               *Buffer;
+  UINT16              BufferLen;
+  EFI_IFR_TYPE_VALUE  Value;
+} EFI_HII_VALUE;
+
+#define NAME_VALUE_NODE_SIGNATURE  SIGNATURE_32 ('N', 'V', 'S', 'T')
+
+typedef struct {
+  UINTN            Signature;
+  LIST_ENTRY       Link;
+  CHAR16           *Name;
+  CHAR16           *Value;
+  CHAR16           *EditValue;
+} NAME_VALUE_NODE;
+
+#define NAME_VALUE_NODE_FROM_LINK(a)  CR (a, NAME_VALUE_NODE, Link, NAME_VALUE_NODE_SIGNATURE)
+
+#define FORMSET_STORAGE_SIGNATURE  SIGNATURE_32 ('F', 'S', 'T', 'G')
+
+typedef struct {
+  UINTN            Signature;
+  LIST_ENTRY       Link;
+
+  UINT16           DefaultId[MAX_PLATFORM_DEFAULT_ID_NUM];
+  UINT64           PlatformId[MAX_PLATFORM_DEFAULT_ID_NUM];
+  UINT32           DefaultPlatformIdNum;
+  UINT32           FormSetOrder;
+
+  BOOLEAN          NewEfiVarstore; //EfiVarStore for UEFI 2.31 or not
+  BOOLEAN          Skip;           //Flag for sorting out the variables
+
+  UINT8            Type;           // Storage type
+
+  UINT16           VarStoreId;
+  EFI_GUID         Guid;
+
+  CHAR16           *Name;          // For EFI_IFR_VARSTORE
+  UINT16           Size;
+  UINT8            *Buffer;
+
+  LIST_ENTRY       NameValueListHead; // List of NAME_VALUE_NODE
+
+  UINT32           Attributes;     // For EFI_IFR_VARSTORE_EFI: EFI Variable attribute
+} FORMSET_STORAGE;
+
+#define FORMSET_STORAGE_FROM_LINK(a)  CR (a, FORMSET_STORAGE, Link, FORMSET_STORAGE_SIGNATURE)
+
+typedef union {
+  EFI_STRING_ID         VarName;
+  UINT16                VarOffset;
+} VAR_STORE_INFO;
+
+#define EXPRESSION_OPCODE_SIGNATURE  SIGNATURE_32 ('E', 'X', 'O', 'P')
+
+typedef struct {
+  UINTN             Signature;
+  LIST_ENTRY        Link;
+
+  UINT8             Operand;
+
+  UINT8             Format;      // For EFI_IFR_TO_STRING, EFI_IFR_FIND
+  UINT8             Flags;       // For EFI_IFR_SPAN
+  UINT8             RuleId;      // For EFI_IFR_RULE_REF
+
+  EFI_HII_VALUE     Value;       // For EFI_IFR_EQ_ID_VAL, EFI_IFR_UINT64, EFI_IFR_UINT32, EFI_IFR_UINT16, EFI_IFR_UINT8, EFI_IFR_STRING_REF1
+
+  EFI_QUESTION_ID   QuestionId;  // For EFI_IFR_EQ_ID_ID, EFI_IFR_EQ_ID_VAL_LIST, EFI_IFR_QUESTION_REF1
+  EFI_QUESTION_ID   QuestionId2;
+
+  UINT16            ListLength;  // For EFI_IFR_EQ_ID_VAL_LIST
+  UINT16            *ValueList;
+
+  EFI_STRING_ID     DevicePath;  // For EFI_IFR_QUESTION_REF3_2, EFI_IFR_QUESTION_REF3_3
+  EFI_GUID          Guid;
+
+  FORMSET_STORAGE   *VarStorage; // For EFI_IFR_SET, EFI_IFR_GET
+  VAR_STORE_INFO    VarStoreInfo;// For EFI_IFR_SET, EFI_IFR_GET
+  UINT8             ValueType;   // For EFI_IFR_SET, EFI_IFR_GET
+  UINT8             ValueWidth;  // For EFI_IFR_SET, EFI_IFR_GET
+  CHAR16            *ValueName;  // For EFI_IFR_SET, EFI_IFR_GET
+  LIST_ENTRY        MapExpressionList;   // nested expressions inside of Map opcode.
+} EXPRESSION_OPCODE;
+
+#define EXPRESSION_OPCODE_FROM_LINK(a)  CR (a, EXPRESSION_OPCODE, Link, EXPRESSION_OPCODE_SIGNATURE)
+
+#define FORM_EXPRESSION_SIGNATURE  SIGNATURE_32 ('F', 'E', 'X', 'P')
+
+typedef struct {
+  UINTN             Signature;
+  LIST_ENTRY        Link;
+
+  UINT8             Type;            // Type for this expression
+
+  UINT8             RuleId;          // For EFI_IFR_RULE only
+  EFI_STRING_ID     Error;           // For EFI_IFR_NO_SUBMIT_IF, EFI_IFR_INCONSISTENT_IF only
+
+  EFI_HII_VALUE     Result;          // Expression evaluation result
+  UINT8             TimeOut;         // For EFI_IFR_WARNING_IF
+
+  LIST_ENTRY        OpCodeListHead;  // OpCodes consist of this expression (EXPRESSION_OPCODE)
+} FORM_EXPRESSION;
+
+#define FORM_EXPRESSION_FROM_LINK(a)  CR (a, FORM_EXPRESSION, Link, FORM_EXPRESSION_SIGNATURE)
+
+#define QUESTION_DEFAULT_SIGNATURE  SIGNATURE_32 ('Q', 'D', 'F', 'T')
+
+typedef struct {
+  UINTN               Signature;
+  LIST_ENTRY          Link;
+
+  UINT16              DefaultId;
+  EFI_HII_VALUE       Value;              // Default value
+
+  FORM_EXPRESSION     *ValueExpression;   // Not-NULL indicates default value is provided by EFI_IFR_VALUE
+} QUESTION_DEFAULT;
+
+#define QUESTION_DEFAULT_FROM_LINK(a)  CR (a, QUESTION_DEFAULT, Link, QUESTION_DEFAULT_SIGNATURE)
+
+#define QUESTION_OPTION_SIGNATURE  SIGNATURE_32 ('Q', 'O', 'P', 'T')
+
+typedef struct {
+  UINTN               Signature;
+  LIST_ENTRY          Link;
+
+  EFI_STRING_ID       Text;
+  UINT8               Flags;
+  EFI_HII_VALUE       Value;
+
+  FORM_EXPRESSION     *SuppressExpression; // Non-NULL indicates nested inside of SuppressIf
+} QUESTION_OPTION;
+
+#define QUESTION_OPTION_FROM_LINK(a)  CR (a, QUESTION_OPTION, Link, QUESTION_OPTION_SIGNATURE)
+
+#define FORM_BROWSER_STATEMENT_SIGNATURE  SIGNATURE_32 ('F', 'S', 'T', 'A')
+
+struct _FORM_BROWSER_STATEMENT {
+  UINTN                 Signature;
+  LIST_ENTRY            Link;
+  UINT8                 Operand;          // The operand (first byte) of this Statement or Question
+
+  UQI_HEADER            Uqi;
+  UINT32                FormSetOrder;
+  EFI_GUID              Guid;
+  UINT8                 Type;           // Storage type
+  BOOLEAN               NewEfiVarstore; //EfiVarStore for UEFI 2.31 or not
+  UINT32                Attributes;     // For EFI_IFR_VARSTORE_EFI: EFI Variable attribute
+  BOOLEAN               QuestionReferToBitField;// Whether the question is stored in a bit field.
+  //
+  // Statement Header
+  //
+  EFI_STRING_ID         Prompt;
+  EFI_STRING_ID         Help;
+  EFI_STRING_ID         TextTwo;          // For EFI_IFR_TEXT
+
+  //
+  // Question Header
+  //
+  EFI_QUESTION_ID       QuestionId;       // The value of zero is reserved
+  EFI_VARSTORE_ID       VarStoreId;       // A value of zero indicates no variable storage
+  FORMSET_STORAGE       *Storage;
+  VAR_STORE_INFO        VarStoreInfo;
+  UINT16                StorageWidth;
+  UINT16                BitStorageWidth;
+  UINT16                BitVarOffset;
+  UINT8                 QuestionFlags;
+  CHAR16                *VariableName;    // Name/Value or EFI Variable name
+
+  EFI_HII_VALUE         HiiValue;         // Edit copy for checkbox, numberic, oneof
+  UINT8                 *BufferValue;     // Edit copy for string, password, orderedlist
+  UINT8                 ValueType;        // Data type for orderedlist value array
+
+  //
+  // OpCode specific members
+  //
+  UINT8                 Flags;            // for EFI_IFR_CHECKBOX, EFI_IFR_DATE, EFI_IFR_NUMERIC, EFI_IFR_ONE_OF,
+                                          // EFI_IFR_ORDERED_LIST, EFI_IFR_STRING,EFI_IFR_SUBTITLE,EFI_IFR_TIME, EFI_IFR_BANNER
+  UINT8                 MaxContainers;    // for EFI_IFR_ORDERED_LIST
+
+  UINT16                BannerLineNumber; // for EFI_IFR_BANNER, 1-based line number
+
+  UINT64                Minimum;          // for EFI_IFR_ONE_OF/EFI_IFR_NUMERIC, it's Min/Max value
+  UINT64                Maximum;          // for EFI_IFR_STRING/EFI_IFR_PASSWORD, it's Min/Max length
+  UINT64                Step;
+
+  EFI_DEFAULT_ID        DefaultId;        // for EFI_IFR_RESET_BUTTON
+  EFI_GUID              RefreshGuid;      // for EFI_IFR_REFRESH_ID
+
+  //
+  // Get from IFR parsing
+  //
+  FORM_EXPRESSION       *ValueExpression;    // nested EFI_IFR_VALUE, provide Question value and indicate Question is ReadOnly
+  LIST_ENTRY            DefaultListHead;     // nested EFI_IFR_DEFAULT list (QUESTION_DEFAULT), provide default values
+  LIST_ENTRY            OptionListHead;      // nested EFI_IFR_ONE_OF_OPTION list (QUESTION_OPTION)
+
+  EFI_IMAGE_ID          ImageId;             // nested EFI_IFR_IMAGE
+  UINT8                 RefreshInterval;     // nested EFI_IFR_REFRESH, refresh interval(in seconds) for Question value, 0 means no refresh
+  BOOLEAN               InSubtitle;          // nesting inside of EFI_IFR_SUBTITLE
+
+  LIST_ENTRY            InconsistentListHead;// nested inconsistent expression list (FORM_EXPRESSION)
+  LIST_ENTRY            NoSubmitListHead;    // nested nosubmit expression list (FORM_EXPRESSION)
+  LIST_ENTRY            WarningListHead;     // nested warning expression list (FORM_EXPRESSION)
+  FORM_EXPRESSION       *GrayOutExpression;  // nesting inside of GrayOutIf
+  FORM_EXPRESSION       *SuppressExpression; // nesting inside of SuppressIf
+  FORM_EXPRESSION       *DisableExpression;  // nesting inside of DisableIf
+
+  FORM_EXPRESSION       *ReadExpression;     // nested EFI_IFR_READ, provide this question value by read expression.
+  FORM_EXPRESSION       *WriteExpression;    // nested EFI_IFR_WRITE, evaluate write expression after this question value is set.
+};
+
+#define FORM_BROWSER_STATEMENT_FROM_LINK(a)  CR (a, FORM_BROWSER_STATEMENT, Link, FORM_BROWSER_STATEMENT_SIGNATURE)
+
+#define FORM_BROWSER_FORM_SIGNATURE  SIGNATURE_32 ('F', 'F', 'R', 'M')
+#define STANDARD_MAP_FORM_TYPE 0x01
+
+typedef struct {
+  UINTN             Signature;
+  LIST_ENTRY        Link;
+
+  UINT16            FormId;               // FormId of normal form or formmap form.
+  EFI_STRING_ID     FormTitle;            // FormTile of normal form, or FormMapMethod title of formmap form.
+  UINT16            FormType;             // Specific form type for the different form.
+
+ BOOLEAN            ModalForm;            // Whether this is a modal form.
+  LIST_ENTRY        ExpressionListHead;   // List of Expressions (FORM_EXPRESSION)
+  LIST_ENTRY        StatementListHead;    // List of Statements and Questions (FORM_BROWSER_STATEMENT)
+  FORM_EXPRESSION   *SuppressExpression;  // nesting inside of SuppressIf
+} FORM_BROWSER_FORM;
+
+#define FORM_BROWSER_FORM_FROM_LINK(a)  CR (a, FORM_BROWSER_FORM, Link, FORM_BROWSER_FORM_SIGNATURE)
+
+#define FORMSET_DEFAULTSTORE_SIGNATURE  SIGNATURE_32 ('F', 'D', 'F', 'S')
+
+typedef struct {
+  UINTN            Signature;
+  LIST_ENTRY       Link;
+
+  UINT16           DefaultId;
+  EFI_STRING_ID    DefaultName;
+} FORMSET_DEFAULTSTORE;
+
+#define STRING_NUMBER 100
+
+typedef struct {
+  EFI_STRING_ID    StringId;
+  CHAR16           *String;
+} STRING_INFO;
+
+typedef struct {
+  EFI_STRING_ID    CachedIdNum;
+  EFI_STRING_ID    MaxIdNum;
+  STRING_INFO      *StringInfoList;
+} FORMSET_STRING_LIST;
+
+#define FORMSET_DEFAULTSTORE_FROM_LINK(a)  CR (a, FORMSET_DEFAULTSTORE, Link, FORMSET_DEFAULTSTORE_SIGNATURE)
+
+#define FORM_BROWSER_FORMSET_SIGNATURE  SIGNATURE_32 ('F', 'B', 'F', 'S')
+
+typedef struct {
+  UINTN                           Signature;
+  LIST_ENTRY                      Link;
+
+  UINT32                          FormSetOrder;
+
+  UINTN                           IfrBinaryLength;
+  UINT8                           *IfrBinaryData;
+  UINT8                           *UnicodeBinary;
+
+  EFI_GUID                        Guid;
+  EFI_STRING_ID                   FormSetTitle;
+  EFI_STRING_ID                   Help;
+  UINT8                           NumberOfClassGuid;
+  EFI_GUID                        ClassGuid[3];         // Up to three ClassGuid
+  UINT16                          Class;                // Tiano extended Class code
+  UINT16                          SubClass;             // Tiano extended Subclass code
+
+  FORM_BROWSER_STATEMENT          *StatementBuffer;     // Buffer for all Statements and Questions
+  EXPRESSION_OPCODE               *ExpressionBuffer;    // Buffer for all Expression OpCode
+
+  LIST_ENTRY                      *StorageListHead;      // Storage list (FORMSET_STORAGE)
+  LIST_ENTRY                      DefaultStoreListHead; // DefaultStore list (FORMSET_DEFAULTSTORE)
+  LIST_ENTRY                      FormListHead;         // Form list (FORM_BROWSER_FORM)
+  LIST_ENTRY                      ExpressionListHead;   // List of Expressions (FORM_EXPRESSION)
+  FORMSET_STRING_LIST             EnUsStringList;      // Cache EN_US English list
+  FORMSET_STRING_LIST             UqiStringList;       // Cache EN_US English list
+} FORM_BROWSER_FORMSET;
+
+#define FORM_BROWSER_FORMSET_FROM_LINK(a)  CR (a, FORM_BROWSER_FORMSET, Link, FORM_BROWSER_FORMSET_SIGNATURE)
+
+///
+/// Structure for multi-platform support
+///
+typedef struct {
+  UINT16                 DefaultId[MAX_PLATFORM_DEFAULT_ID_NUM];
+  UINT16                 DefaultIdNum;
+  UINT64                 PlatformId[MAX_PLATFORM_DEFAULT_ID_NUM];
+  UINT16                 PlatformIdNum;
+  UINT16                 KeyDefaultId[MAX_PLATFORM_DEFAULT_ID_NUM];
+  UINT64                 KeyPlatformId[MAX_PLATFORM_DEFAULT_ID_NUM];
+  UINT16                 KeyIdNum;
+  FORM_BROWSER_STATEMENT PlatformIdQuestion;
+  FORM_BROWSER_STATEMENT *Question;
+  UINT16                 PlatformIdWidth;
+  UQI_HEADER             Uqi;
+  BOOLEAN                MultiPlatformOrNot;
+  BOOLEAN                ExistStorageFfsInBfv;
+  BOOLEAN                SizeOptimized;
+  BOOLEAN                SizeOptimizedParam;
+} MULTI_PLATFORM_PARAMETERS;
+
+/**
+  Search the variable list according to the variable Guid and name, and return the pointer
+  of that Node.
+
+  @param  HiiObjList       The pointer to the Question
+  @param  VarName          The EFI variable name need to be updated to VarList
+  @param  Offset           The offset of the variable
+  @param  StorageListHead  The pointer to the LIST_ENTRY of Storage
+  @param  Vaue             The value in that value offset of the variable
+  @param  VarList          The dual pointer of Varlist
+
+  @return EFI_SUCCESS
+**/
+EFI_STATUS
+SearchVarStorage (
+  IN     FORM_BROWSER_STATEMENT   *Question,
+  IN     CHAR16*                  VarName,
+  IN     UINT32                   Offset,
+  IN     LIST_ENTRY               *StorageListHead,
+  IN OUT CHAR8                    **Value,
+  IN OUT FORMSET_STORAGE          **VarList
+  );
+
+/**
+  Get the string based on the StringId and HII Package List Handle.
+
+  @param  Token                  The String's ID.
+  @param  HiiHandle              The package list in the HII database to search for
+                                 the specified string.
+
+  @return The output string.
+
+**/
+CHAR16 *
+GetToken (
+  IN  EFI_STRING_ID                Token,
+  IN  UINT8                        *UniPackge
+  );
+
+/**
+  Free resources allocated for all Storage in an LIST_ENTRY.
+
+  @param  FormSet                Pointer of the FormSet
+
+**/
+VOID
+DestroyAllStorage (
+  IN LIST_ENTRY    *StorageEntryListHead
+  );
+
+
+/**
+  Free resources allocated for a FormSet.
+
+  @param  FormSet                Pointer of the FormSet
+
+**/
+VOID
+DestroyFormSet (
+  IN FORM_BROWSER_FORMSET  *FormSet
+  );
+
+
+/**
+  Free resources allocated for all FormSet in an LIST_ENTRY.
+
+  @param  FormSet                Pointer of the FormSet
+
+**/
+VOID
+DestroyAllFormSet (
+  IN LIST_ENTRY    *FormSetEntryListHead
+  );
+
+/**
+  Parse opcodes in the formset IFR binary.
+
+  @param  FormSet                Pointer of the FormSet data structure.
+
+  @retval EFI_SUCCESS            Opcode parse success.
+  @retval Other                  Opcode parse fail.
+
+**/
+EFI_STATUS
+ParseOpCodes (
+  IN FORM_BROWSER_FORMSET        *FormSet
+  );
+
+/**
+  Set the value to the variable of platformId question.
+
+  @param  PlatformId             The form set.
+
+  @retval EFI_SUCCESS            Set successfully.
+
+**/
+EFI_STATUS
+AssignThePlatformId (
+  IN  UINT64   PlatformId
+  );
+
+
+/**
+  Reset Questions to their default value in a Form, Formset or System.
+
+  @param  FormSet                FormSet data structure.
+  @param  Form                   Form data structure.
+  @param  DefaultId              The default Id
+  @param  PlatformId             The platform Id
+  @param  SettingScope           Setting Scope for Default action.
+
+  @retval EFI_SUCCESS            The function completed successfully.
+  @retval EFI_UNSUPPORTED        Unsupport SettingScope.
+
+**/
+EFI_STATUS
+ExtractDefault (
+  IN FORM_BROWSER_FORMSET             *FormSet,
+  IN FORM_BROWSER_FORM                *Form,
+  IN UINT16                           DefaultId,
+  IN UINT64                           PlatformId,
+  IN BROWSER_SETTING_SCOPE            SettingScope
+  );
+
+
+/**
+  Reset stack pointer to begin of the stack.
+
+**/
+VOID
+ResetCurrentExpressionStack (
+  VOID
+  );
+
+
+/**
+  Push current expression onto the Stack
+
+  @param  Pointer                Pointer to current expression.
+
+  @retval EFI_SUCCESS            The value was pushed onto the stack.
+  @retval EFI_OUT_OF_RESOURCES   There is not enough system memory to grow the stack.
+
+**/
+EFI_STATUS
+PushCurrentExpression (
+  IN VOID  *Pointer
+  );
+
+
+/**
+  Pop current expression from the Stack
+
+  @param  Pointer                Pointer to current expression to be pop.
+
+  @retval EFI_SUCCESS            The value was pushed onto the stack.
+  @retval EFI_OUT_OF_RESOURCES   There is not enough system memory to grow the stack.
+
+**/
+EFI_STATUS
+PopCurrentExpression (
+  OUT VOID    **Pointer
+  );
+
+/**
+  Reset stack pointer to begin of the stack.
+
+**/
+VOID
+ResetMapExpressionListStack (
+  VOID
+  );
+
+
+/**
+  Push the list of map expression onto the Stack
+
+  @param  Pointer                Pointer to the list of map expression to be pushed.
+
+  @retval EFI_SUCCESS            The value was pushed onto the stack.
+  @retval EFI_OUT_OF_RESOURCES   There is not enough system memory to grow the stack.
+
+**/
+EFI_STATUS
+PushMapExpressionList (
+  IN VOID  *Pointer
+  );
+
+
+/**
+  Pop the list of map expression from the Stack
+
+  @param  Pointer                Pointer to the list of map expression to be pop.
+
+  @retval EFI_SUCCESS            The value was pushed onto the stack.
+  @retval EFI_OUT_OF_RESOURCES   There is not enough system memory to grow the stack.
+
+**/
+EFI_STATUS
+PopMapExpressionList (
+  OUT VOID    **Pointer
+  );
+
+/**
+  Reset stack pointer to begin of the stack.
+
+**/
+VOID
+ResetScopeStack (
+  VOID
+  );
+
+
+/**
+  Push an Operand onto the Stack
+
+  @param  Operand                Operand to push.
+
+  @retval EFI_SUCCESS            The value was pushed onto the stack.
+  @retval EFI_OUT_OF_RESOURCES   There is not enough system memory to grow the
+                                 stack.
+
+**/
+EFI_STATUS
+PushScope (
+  IN UINT8   Operand
+  );
+
+
+/**
+  Pop an Operand from the Stack
+
+  @param  Operand                Operand to pop.
+
+  @retval EFI_SUCCESS            The value was pushed onto the stack.
+  @retval EFI_OUT_OF_RESOURCES   There is not enough system memory to grow the
+                                 stack.
+
+**/
+EFI_STATUS
+PopScope (
+  OUT UINT8     *Operand
+  );
+
+
+/**
+  Zero extend integer/boolean/date/time to UINT64 for comparing.
+
+  @param  Value                  HII Value to be converted.
+
+**/
+VOID
+ExtendValueToU64 (
+  IN  EFI_HII_VALUE   *Value
+  );
+
+
+/**
+  Compare two Hii value.
+
+  @param  Value1                 Expression value to compare on left-hand.
+  @param  Value2                 Expression value to compare on right-hand.
+
+  @retval EFI_INVALID_PARAMETER  Could not perform compare on two values.
+  @retval 0                      Two operators equal.
+  @return Positive value if Value1 is greater than Value2.
+  @retval Negative value if Value1 is less than Value2.
+
+**/
+INTN
+CompareHiiValue (
+  IN  EFI_HII_VALUE        *Value1,
+  IN  EFI_HII_VALUE        *Value2,
+  IN FORM_BROWSER_FORMSET  *FormSet
+  );
+
+/**
+  Evaluate the result of a HII expression.
+
+  If Expression is NULL, then ASSERT.
+
+  @param  FormSet                FormSet associated with this expression.
+  @param  Form                   Form associated with this expression.
+  @param  Expression             Expression to be evaluated.
+  @param  ConstantExpression     The pointer to the flag of constant expression. If constant, will return TRUE.
+
+  @retval EFI_SUCCESS            The expression evaluated successfuly
+  @retval EFI_NOT_FOUND          The Question which referenced by a QuestionId
+                                 could not be found.
+  @retval EFI_OUT_OF_RESOURCES   There is not enough system memory to grow the
+                                 stack.
+  @retval EFI_ACCESS_DENIED      The pop operation underflowed the stack
+  @retval EFI_INVALID_PARAMETER  Syntax error with the Expression
+
+**/
+EFI_STATUS
+EvaluateExpression (
+  IN FORM_BROWSER_FORMSET  *FormSet,
+  IN FORM_BROWSER_FORM     *Form,
+  IN OUT FORM_EXPRESSION   *Expression,
+  IN OUT BOOLEAN           *ConstantExpression
+  );
+
+/**
+  Compare two Uqi parameters
+
+  @param UqiParm1       The pointer to the first Uqi parameter.
+  @param UqiParm2       The pointer to the second Uqi parameter.
+
+  @retval TRUE          If these two Uqi parameters are the same, return TRUE;
+  @return FALSE         Otherwise, return FALSE;
+**/
+BOOLEAN
+CompareUqiHeader (
+  IN  CONST UQI_HEADER  *UqiParm1,
+  IN  CONST UQI_HEADER  *UqiParm2
+  );
+
+
+/**
+  Print all ONE_OF ORDER_LIST NUMERIC STRING and CHECKBOX in all fromsets.
+
+  @param Formset        The pointer to the entry of the fromset list
+  @param Formset        The pointer to the entry of the storage list
+
+  @retval EFI_SUCCESS   It was complete successfully
+  @return EFI_ABORTED   An error occurred
+**/
+EFI_STATUS
+PrintInfoInAllFormset (
+  IN LIST_ENTRY      *FormSetEntryListHead,
+  IN LIST_ENTRY      *StorageEntryListHead
+  );
+
+ /**
+  Get the question value with bit field from the buffer.
+
+  @param  Question        The question refer to bit field.
+  @param  Buffer          The buffer which the question value get from.
+  @param  Value           Retun the value.
+
+**/
+VOID
+GetBitsQuestionValue(
+  IN  FORM_BROWSER_STATEMENT *Question,
+  IN  UINT8                  *Buffer,
+  OUT UINT32                 *Value
+  );
+
+/**
+  Set the question value with bit field to the buffer.
+
+  @param  Question        The question refer to bit field.
+  @param  Buffer          The buffer which the question value set to.
+  @param  Value           The value need to set.
+
+**/
+VOID
+SetBitsQuestionValue (
+  IN FORM_BROWSER_STATEMENT *Question,
+  IN UINT8                  *Buffer,
+  IN UINT32                 Value
+  );
+
+#endif
diff --git a/Platform/Intel/Tools/FCE/Makefile b/Platform/Intel/Tools/FCE/Makefile
new file mode 100644
index 0000000000..c8a025e27f
--- /dev/null
+++ b/Platform/Intel/Tools/FCE/Makefile
@@ -0,0 +1,19 @@
+## @file
+#
+# Windows makefile for 'FCE' module build.
+#
+# Copyright (c) 2011-2019, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+!INCLUDE $(EDK_TOOLS_PATH)\Source\C\Makefiles\ms.common
+
+APPNAME = FCE
+
+LIBS = $(LIB_PATH)\Common.lib
+
+OBJECTS =  Fce.obj Variable.obj TimeBasedVariable.obj MonotonicBasedVariable.obj IfrParse.obj Common.obj BinaryParse.obj BinaryCreate.obj Expression.obj
+
+!INCLUDE $(EDK_TOOLS_PATH)\Source\C\Makefiles\ms.app
+
diff --git a/Platform/Intel/Tools/FCE/MonotonicBasedVariable.c b/Platform/Intel/Tools/FCE/MonotonicBasedVariable.c
new file mode 100644
index 0000000000..9d35bffab6
--- /dev/null
+++ b/Platform/Intel/Tools/FCE/MonotonicBasedVariable.c
@@ -0,0 +1,874 @@
+/** @file
+
+ Read and edit the authenticated variables.
+
+ Copyright (c) 2011-2019, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "Fce.h"
+#include "MonotonicBasedVariable.h"
+
+extern LIST_ENTRY                  mAllVarListEntry;
+extern MULTI_PLATFORM_PARAMETERS   mMultiPlatformParam;
+extern G_EFI_FD_INFO               gEfiFdInfo;
+EFI_GUID  gEfiAuthenticatedVariableGuid     = EFI_AUTHENTICATED_VARIABLE_GUID;
+/**
+
+  Gets the pointer to the first variable header in given variable store area.
+
+  @param VarStoreHeader  Pointer to the Variable Store Header.
+
+  @return Pointer to the first variable header.
+
+**/
+static
+VARIABLE_HEADER *
+GetStartPointer (
+  IN VARIABLE_STORE_HEADER       *VarStoreHeader
+  )
+{
+  //
+  // The end of variable store.
+  //
+  return (VARIABLE_HEADER *) HEADER_ALIGN (VarStoreHeader + 1);
+}
+
+/**
+
+  Gets the pointer to the end of the variable storage area.
+
+  This function gets pointer to the end of the variable storage
+  area, according to the input variable store header.
+
+  @param VarStoreHeader  Pointer to the Variable Store Header.
+
+  @return Pointer to the end of the variable storage area.
+
+**/
+static
+VARIABLE_HEADER *
+GetEndPointer (
+  IN VARIABLE_STORE_HEADER       *VarStoreHeader
+  )
+{
+  //
+  // The end of variable store
+  //
+  return (VARIABLE_HEADER *) HEADER_ALIGN ((UINTN) VarStoreHeader + VarStoreHeader->Size);
+}
+
+
+/**
+
+  This code checks if variable header is valid or not.
+
+  @param Variable        Pointer to the Variable Header.
+
+  @retval TRUE           Variable header is valid.
+  @retval FALSE          Variable header is not valid.
+
+**/
+static
+BOOLEAN
+IsValidVariableHeader (
+  IN  VARIABLE_HEADER   *Variable
+  )
+{
+  if ((Variable == NULL) || (Variable->StartId != VARIABLE_DATA)) {
+    return FALSE;
+  }
+
+  return TRUE;
+}
+
+/**
+
+  This code gets the size of name of variable.
+
+  @param Variable        Pointer to the Variable Header.
+
+  @return UINTN          Size of variable in bytes.
+
+**/
+static
+UINTN
+NameSizeOfVariable (
+  IN  VARIABLE_HEADER   *Variable
+  )
+{
+  if ((Variable->State    == (UINT8) (-1)) ||
+      (Variable->DataSize == (UINT32) (-1)) ||
+      (Variable->NameSize == (UINT32) (-1)) ||
+      (Variable->Attributes == (UINT32) (-1))
+      ) {
+    return 0;
+  }
+  return (UINTN) Variable->NameSize;
+}
+
+/**
+
+  This code gets the size of variable data.
+
+  @param Variable        Pointer to the Variable Header.
+
+  @return Size of variable in bytes.
+
+**/
+static
+UINTN
+DataSizeOfVariable (
+  IN  VARIABLE_HEADER   *Variable
+  )
+{
+  if ((Variable->State    == (UINT8)  (-1)) ||
+      (Variable->DataSize == (UINT32) (-1)) ||
+      (Variable->NameSize == (UINT32) (-1)) ||
+      (Variable->Attributes == (UINT32) (-1))
+      ) {
+    return 0;
+  }
+  return (UINTN) Variable->DataSize;
+}
+
+/**
+
+  This code gets the pointer to the variable name.
+
+  @param Variable        Pointer to the Variable Header.
+
+  @return Pointer to Variable Name which is Unicode encoding.
+
+**/
+static
+CHAR16 *
+GetVariableNamePtr (
+  IN  VARIABLE_HEADER   *Variable
+  )
+{
+  return (CHAR16 *) (Variable + 1);
+}
+
+/**
+
+  This code gets the pointer to the variable data.
+
+  @param Variable        Pointer to the Variable Header.
+
+  @return Pointer to Variable Data.
+
+**/
+static
+UINT8 *
+GetVariableDataPtr (
+  IN  VARIABLE_HEADER   *Variable
+  )
+{
+  UINTN Value;
+
+  //
+  // Be careful about pad size for alignment.
+  //
+  Value =  (UINTN) GetVariableNamePtr (Variable);
+  Value += NameSizeOfVariable (Variable);
+  Value += GET_PAD_SIZE (NameSizeOfVariable (Variable));
+
+  return (UINT8 *) Value;
+}
+
+/**
+
+  This code gets the pointer to the next variable header.
+
+  @param Variable        Pointer to the Variable Header.
+
+  @return Pointer to next variable header.
+
+**/
+static
+VARIABLE_HEADER *
+GetNextVariablePtr (
+  IN  VARIABLE_HEADER   *Variable
+  )
+{
+  UINTN Value;
+
+  if (!IsValidVariableHeader (Variable)) {
+    return NULL;
+  }
+
+  Value =  (UINTN) GetVariableDataPtr (Variable);
+  Value += DataSizeOfVariable (Variable);
+  Value += GET_PAD_SIZE (DataSizeOfVariable (Variable));
+
+  //
+  // Be careful about pad size for alignment.
+  //
+  return (VARIABLE_HEADER *) HEADER_ALIGN (Value);
+}
+
+/**
+  Search and get a free space in the EFI variable zone
+
+  @param VariableStoreHeader       The start of a EFI variable zone.
+  @param VarListSize               The size of a variables needs to be allocated.
+  @param FreeBeginVar              The dual pointer to the free NV space.
+
+  @retval EFI_SUCCESS              Return the beginning of a free variable space.
+  @retval RETURN_BUFFER_TOO_SMALL  Failed.
+**/
+static
+EFI_STATUS
+GetVariableVar (
+  IN      VARIABLE_STORE_HEADER  *VariableStoreHeader,
+  IN      UINT32                 VarListSize,
+  IN OUT  CHAR8                  **FreeBeginVar
+)
+{
+  BOOLEAN          Flag;
+  VARIABLE_HEADER  *Variable;
+  VARIABLE_HEADER  *EndOfVariable;
+  CHAR8            *BeginVar;
+
+  BeginVar      = NULL;
+  Flag          = FALSE;
+  Variable      = NULL;
+  EndOfVariable = NULL;
+  *FreeBeginVar = NULL;
+
+  if (VariableStoreHeader == NULL) {
+    *FreeBeginVar = NULL;
+    return RETURN_INVALID_PARAMETER;
+  }
+  Variable      = GetStartPointer (VariableStoreHeader);
+  EndOfVariable = GetEndPointer(VariableStoreHeader);
+  //
+  //Search the beginning of free NV
+  //
+  while (Variable != EndOfVariable) {
+    BeginVar = (CHAR8 *)Variable;
+    Variable = GetNextVariablePtr (Variable);
+    if (Variable == NULL) {
+      Flag = TRUE;
+      break;
+    }
+  }
+  //
+  // Check whether the free space is more than what we want
+  //
+  if ((CHAR8 *)BeginVar + VarListSize > (CHAR8 *)EndOfVariable) {
+    return RETURN_BUFFER_TOO_SMALL;
+  }
+  //
+  // If not find the available space, return NULL
+  //
+  if (!Flag) {
+    return RETURN_BUFFER_TOO_SMALL;
+  }
+  *FreeBeginVar = BeginVar;
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Search whether the variable in VarList has existed in current NV.
+
+  Parse the FFS or Fd image, and find the valid variable pointer.
+
+  @param VariableStoreHeader    The start of a EFI variable zone.
+  @param VarList                The pointer to the VarList
+
+  @retval address               If the variable existed in current NV, return address
+  @return NULL                  Otherwise, return NULL
+**/
+static
+VARIABLE_HEADER  *
+FindVariableInNv (
+  IN     VARIABLE_STORE_HEADER  *VariableStoreHeader,
+  IN     FORMSET_STORAGE        *Storage
+  )
+{
+  BOOLEAN          Flag;
+  VARIABLE_HEADER  *Variable;
+  VARIABLE_HEADER  *EndOfVariable;
+  CHAR16           *VariableName;
+
+  Flag            = FALSE;
+  Variable        = NULL;
+  EndOfVariable   = NULL;
+  VariableName    = NULL;
+
+  if ((VariableStoreHeader == NULL) || (Storage == NULL) || (Storage->Name == NULL)) {
+    return NULL;
+  }
+  Variable      = GetStartPointer (VariableStoreHeader);
+  EndOfVariable = GetEndPointer(VariableStoreHeader);
+  //
+  // Parse and compare the variable in the NV space one by one
+  //
+  while ((Variable != EndOfVariable) && (Variable != NULL)) {
+    VariableName = (CHAR16 *)((CHAR8 *)Variable + sizeof (VARIABLE_HEADER));
+    if (!CompareGuid (&Variable->VendorGuid, &Storage->Guid) \
+      && !FceStrCmp (Storage->Name, VariableName) \
+      && (Variable->State == VAR_ADDED)) {
+      Flag = TRUE;
+      break;
+    }
+    Variable = GetNextVariablePtr (Variable);
+  }
+  if (!Flag) {
+    return NULL;
+  }
+  return Variable;
+}
+
+/**
+  Exchange the data between Efi variable and the data of VarList when the
+  variable use the authenticated variable header
+
+  If VarToList is TRUE, copy the efi variable data to the VarList; Otherwise,
+  update the data from varlist to efi variable.
+
+  @param VarToList          The flag to control the direction of exchange.
+  @param StorageListHead    Decide which variale list be updated
+
+  @retval EFI_SUCCESS           Get the address successfully.
+  @retval EFI_OUT_OF_RESOURCES  No available in the EFI variable zone.
+  @retval EFI_INVALID_PARAMETER Invalid variable name.
+**/
+EFI_STATUS
+SynAuthEfiVariable (
+  IN  BOOLEAN     VarToList,
+  IN  LIST_ENTRY  *StorageListHead
+  )
+{
+  EFI_FIRMWARE_VOLUME_HEADER    *VarAddr;
+  LIST_ENTRY                    *StorageLink;
+  FORMSET_STORAGE               *Storage;
+  EFI_STATUS                    Status;
+  CHAR8                         *NewAvailableAddr;
+  CHAR8                         *DataBase;
+  VARIABLE_HEADER               *VariableHeader;
+  VARIABLE_STORE_HEADER         *VariableStoreHeader;
+  UINTN                         VarNameSize;
+
+  Status              = EFI_SUCCESS;
+  DataBase            = NULL;
+  NewAvailableAddr    = NULL;
+  VarNameSize         = 0;
+  VariableHeader      = NULL;
+  VarAddr             = (EFI_FIRMWARE_VOLUME_HEADER   *) gEfiFdInfo.EfiVariableAddr;
+  VariableStoreHeader = (VARIABLE_STORE_HEADER *)((CHAR8 *)VarAddr + VarAddr->HeaderLength);
+  //
+  //Parse the variable range, and check whether there is some existed ones.
+  //
+  StorageLink = GetFirstNode (StorageListHead);
+  while (!IsNull (StorageListHead, StorageLink)) {
+    Storage = FORMSET_STORAGE_FROM_LINK (StorageLink);
+     //
+     // Ignore the invalid varlist node
+     //
+     if (Storage->Buffer == NULL) {
+      StorageLink = GetNextNode (StorageListHead, StorageLink);
+      continue;
+     }
+     //
+     // Report error, if the variable name is invalid.
+     //
+     if ((Storage->Name == NULL) || (FceStrLen(Storage->Name) == 0)) {
+       printf ("Error. One variable name is NULL. Its GUID is: ");
+       PrintGuid(&(Storage->Guid));
+       return EFI_INVALID_PARAMETER;
+     }
+     VariableHeader = FindVariableInNv (
+                        VariableStoreHeader,
+                        Storage
+                        );
+
+   if (VarToList) {
+     //
+     //Copy the data from NV to the VarList.
+     //
+     if (VariableHeader != NULL) {
+       if (Storage->Buffer == NULL) {
+         Storage->Buffer = calloc (Storage->Size, sizeof (CHAR8));
+         ASSERT (Storage->Buffer != NULL);
+       }
+       //
+       // The variable in VarList is CHAR8, but in the EFI variable is CHAR16.
+       //
+       DataBase    = (CHAR8 *)GetVariableDataPtr (VariableHeader);
+       memcpy (
+         Storage->Buffer,
+         (VOID *) DataBase,
+         Storage->Size
+        );
+      }
+    } else {
+       //
+       //If existed, copy the List data to the variable in NV directly. If not found, create a new one.
+       //
+       VarNameSize = 2 * (FceStrLen (Storage->Name) + 1);
+       //
+       //If this variable has existed in current FD, the data in VarList has
+       // been updated, and this variable is not authenticated type, then
+       // update it from VarList to the FD.
+       //
+       if ((VariableHeader != NULL)    \
+         && (Storage->Buffer != NULL)
+         ) {
+         if (!(VariableHeader->Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS)) {
+           DataBase = (CHAR8 *)GetVariableDataPtr (VariableHeader);
+           memcpy (
+             (VOID *) DataBase,
+             Storage->Buffer,
+             Storage->Size
+           );
+         } else {
+           printf ("Error. Not support to update authenticated variables.\n");
+           return EFI_INVALID_PARAMETER;
+         }
+       } else if ((VariableHeader == NULL) && (Storage->Buffer != NULL)){
+       //
+         //If EfiVarstore is not EFI_VARIABLE_NON_VOLATILE, only skip it.
+         //
+         if (Storage->NewEfiVarstore
+           && ((Storage->Attributes & EFI_VARIABLE_NON_VOLATILE) == 0)
+         ) {
+          StorageLink = GetNextNode (StorageListHead, StorageLink);
+          continue;
+         }
+         //
+         // Try to get the available zone from the efi variables
+         //
+         Status = GetVariableVar (
+                    VariableStoreHeader,
+                    Storage->Size + sizeof (VARIABLE_HEADER),
+                    &NewAvailableAddr
+                    );
+
+         if (!EFI_ERROR (Status)) {
+           //
+           // Create the authenticated variable header
+           //
+           VariableHeader                  = (VARIABLE_HEADER *) NewAvailableAddr;
+           VariableHeader->StartId         = VARIABLE_DATA;
+           VariableHeader->State           = VAR_ADDED;
+           VariableHeader->Reserved        = 0x0;
+           VariableHeader->MonotonicCount  = 0x0;
+           VariableHeader->PubKeyIndex     = 0x0;
+           if (Storage->NewEfiVarstore) {
+             VariableHeader->Attributes = Storage->Attributes;
+           } else {
+             VariableHeader->Attributes      = EFI_VARIABLE_NON_VOLATILE|EFI_VARIABLE_BOOTSERVICE_ACCESS|EFI_VARIABLE_RUNTIME_ACCESS;
+           }
+           VariableHeader->NameSize        = VarNameSize;
+           VariableHeader->DataSize   = Storage->Size;
+           //
+           //Copy the Guid, variable name, and data in sequence.
+           //
+           memcpy (
+             (VOID *)&(VariableHeader->VendorGuid),
+             &(Storage->Guid),
+             sizeof (EFI_GUID)
+             );
+           NewAvailableAddr = NewAvailableAddr + sizeof (VARIABLE_HEADER);
+           memcpy (
+             (VOID *) NewAvailableAddr,
+              Storage->Name,
+              VarNameSize
+              );
+
+           NewAvailableAddr = NewAvailableAddr + VarNameSize + GET_PAD_SIZE (VarNameSize);
+           memcpy (
+             (VOID *) NewAvailableAddr,
+             Storage->Buffer,
+             Storage->Size * sizeof (CHAR8)
+             );
+         } else {
+           printf ("Error. No available space in NV ram.\n");
+           return EFI_OUT_OF_RESOURCES;
+         }
+       }
+    }
+    StorageLink = GetNextNode (StorageListHead, StorageLink);
+  }
+  return Status;
+}
+
+/**
+  Remove the variable from Efi variable
+
+  Found the variable with the same name in StorageListHead and remove it.
+
+  @param StorageListHead   Decide which variale list be removed.
+
+  @retval EFI_SUCCESS      Remove the variables successfully.
+**/
+EFI_STATUS
+RemoveAuthEfiVariable (
+  IN  LIST_ENTRY  *StorageListHead
+  )
+{
+  EFI_FIRMWARE_VOLUME_HEADER    *VarAddr;
+  LIST_ENTRY                    *StorageLink;
+  FORMSET_STORAGE               *Storage;
+  VARIABLE_HEADER               *VariableHeader;
+  VARIABLE_STORE_HEADER         *VariableStoreHeader;
+
+  VariableHeader      = NULL;
+  VarAddr             = (EFI_FIRMWARE_VOLUME_HEADER   *) gEfiFdInfo.EfiVariableAddr;
+  VariableStoreHeader = (VARIABLE_STORE_HEADER *)((CHAR8 *)VarAddr + VarAddr->HeaderLength);
+  //
+  //Parse the variable range, and check whether there is some existed ones.
+  //
+  StorageLink = GetFirstNode (StorageListHead);
+  while (!IsNull (StorageListHead, StorageLink)) {
+    Storage = FORMSET_STORAGE_FROM_LINK (StorageLink);
+    //
+    // Ignore the invalid varlist node
+    //
+    if (Storage->Buffer == NULL) {
+      StorageLink = GetNextNode (StorageListHead, StorageLink);
+      continue;
+    }
+    //
+    // Report error, if the variable name is invalid.
+    //
+    if ((Storage->Name == NULL) || (FceStrLen(Storage->Name) == 0)) {
+      printf ("Error. One variable name is NULL. Its GUID is: ");
+      PrintGuid(&(Storage->Guid));
+      return EFI_INVALID_PARAMETER;
+    }
+    VariableHeader = FindVariableInNv (
+                       VariableStoreHeader,
+                       Storage
+                       );
+    if (VariableHeader != NULL) {
+      VariableHeader->State = VAR_DELETED;
+    }
+    StorageLink = GetNextNode (StorageListHead, StorageLink);
+  }
+  return EFI_SUCCESS;
+}
+
+/**
+  Check the store variable is Monotonic based authenticated or not
+
+  @param VarToList     The pointer to the header of Variable Store.
+
+  @retval TRUE         If authenticated, return TRUE.
+  @retval FALSE        Otherwise, return FALSE.
+**/
+
+BOOLEAN
+CheckMonotonicBasedVarStore (
+  IN VOID  *VariableStoreHeader
+  )
+{
+  if (!CompareGuid (
+    &gEfiAuthenticatedVariableGuid,
+    &((VARIABLE_STORE_HEADER *)VariableStoreHeader)->Signature)
+    ) {
+    return TRUE;
+  } else {
+    return FALSE;
+  }
+}
+
+/**
+  Copy Monotonic-Based authenticated variable to binary in multi-platform mode
+
+  @param  Storage           The pointer to a storage in storage list.
+  @param  StorageBeginning  The pointer to the beginning of storage under specifed platformId and defaultId
+  @param  Index             The number of the storage. If the Index is 0, record the variable header to
+                            the binary. Or else, only record the storage.
+
+  @return length          The length of storage
+**/
+UINT32
+CopyMonotonicBasedVariableToBinary (
+  IN      FORMSET_STORAGE   *Storage,
+  IN OUT  UINT8             *StorageBeginning,
+  IN      UINT32            Index
+  )
+{
+  EFI_STATUS                    Status;
+  CHAR8                         *NewAvailableAddr;
+  VARIABLE_HEADER               *VariableHeader;
+  VARIABLE_STORE_HEADER         *VariableStoreHeader;
+  UINTN                         VarNameSize;
+  UINT32                        HeaderLength;
+
+  Status              = EFI_SUCCESS;
+  NewAvailableAddr    = NULL;
+  VarNameSize         = 0;
+  HeaderLength        = 0;
+  VariableHeader      = NULL;
+  VariableStoreHeader = NULL;
+
+  if ((Storage->Name == NULL) || (FceStrLen(Storage->Name) == 0)) {
+    printf ("Error. One variable name is NULL. Its GUID is: ");
+    PrintGuid(&(Storage->Guid));
+    return 0;
+  }
+  //
+  // If the first storage under one specified platformId and defaultId, create the variable header
+  //
+  if (Index == 0) {
+    HeaderLength = WriteDefaultAndPlatformId (StorageBeginning, Storage);
+    VariableStoreHeader = (VARIABLE_STORE_HEADER *) (StorageBeginning + HeaderLength);
+    //
+    //Create the Variable Storage header
+    //
+    memcpy (&(VariableStoreHeader->Signature), &gEfiAuthenticatedVariableGuid, sizeof (EFI_GUID));
+    VariableStoreHeader->Format = 0x5A;
+    VariableStoreHeader->State  = 0xFE;
+    //
+    //Assign a big size here. It will be fixed after the storage under a specifed platformId and defaultId are all written.
+    //
+    VariableStoreHeader->Size   = gEfiFdInfo.FdSize;
+  }
+  VariableStoreHeader = (VARIABLE_STORE_HEADER *) (StorageBeginning + *(UINT16 *)StorageBeginning);
+
+  Status = GetVariableVar (
+             VariableStoreHeader,
+             Storage->Size + sizeof (VARIABLE_HEADER),
+             &NewAvailableAddr
+           );
+  if (EFI_ERROR (Status)) {
+    return FAIL;
+  }
+  //
+  // Create the variable header
+  //
+  VarNameSize                = 2 * (FceStrLen (Storage->Name) + 1);
+  VariableHeader             = (VARIABLE_HEADER *) NewAvailableAddr;
+  VariableHeader->StartId    = VARIABLE_DATA;
+  VariableHeader->State      = VAR_ADDED;
+  VariableHeader->Reserved   = 0x0;
+  VariableHeader->MonotonicCount  = 0x0;
+  VariableHeader->PubKeyIndex     = 0x0;
+
+  if (Storage->NewEfiVarstore) {
+    VariableHeader->Attributes = Storage->Attributes;
+  } else {
+    VariableHeader->Attributes = EFI_VARIABLE_NON_VOLATILE|EFI_VARIABLE_BOOTSERVICE_ACCESS|EFI_VARIABLE_RUNTIME_ACCESS;
+  }
+  VariableHeader->NameSize   = VarNameSize;
+  VariableHeader->DataSize   = Storage->Size;
+  //
+  //Copy the Guid, variable name, and data in sequence.
+  //
+  memcpy (
+    (VOID *)&(VariableHeader->VendorGuid),
+    &(Storage->Guid),
+    sizeof (EFI_GUID)
+  );
+  NewAvailableAddr = NewAvailableAddr + sizeof (VARIABLE_HEADER);
+  memcpy (
+    (VOID *) NewAvailableAddr,
+    Storage->Name,
+    VarNameSize
+  );
+
+  NewAvailableAddr = NewAvailableAddr + VarNameSize + GET_PAD_SIZE (VarNameSize);
+  memcpy (
+    (VOID *) NewAvailableAddr,
+    Storage->Buffer,
+    Storage->Size * sizeof (CHAR8)
+  );
+
+
+  //
+  // Return the length which is from the beginning of Binary
+  //
+  return ((UINT32) ((UINT8*)NewAvailableAddr - StorageBeginning) + Storage->Size);
+}
+
+
+/**
+  Read Monotonic-based authenticated variable to storage list in multi-platform mode
+
+  @param  Binary            The pointer to the header of storage under specifed platformId and defaultId
+  @param  StorageListEntry  The pointer to the storage list.
+
+  @return length          The length of storage
+**/
+UINT32
+ReadMonotonicBasedVariableToList (
+  IN      UINT8             *Binary,
+  IN      LIST_ENTRY        *StorageListEntry
+  )
+{
+  VARIABLE_HEADER               *EndOfVariable;
+  VARIABLE_HEADER               *Variable;
+  VARIABLE_STORE_HEADER         *VariableStoreHeader;
+  FORMSET_STORAGE               *Storage;
+  BOOLEAN                       ReadIdHeaderFlag;
+  UINT32                        Length;
+  EFI_COMMON_SECTION_HEADER     *SectionHeader;
+  UINT8                         *DataBase;
+  static UINT16                 PreDefaultId[MAX_PLATFORM_DEFAULT_ID_NUM];
+  static UINT64                 PrePlatformId[MAX_PLATFORM_DEFAULT_ID_NUM];
+
+  VariableStoreHeader = NULL;
+  Variable            = NULL;
+  ReadIdHeaderFlag    = TRUE;
+  Length              = 0;
+  SectionHeader       = (EFI_COMMON_SECTION_HEADER *)Binary;
+  DataBase            = Binary + sizeof (EFI_COMMON_SECTION_HEADER);
+  VariableStoreHeader = (VARIABLE_STORE_HEADER *) (DataBase + *(UINT16 *)DataBase);
+  EndOfVariable       = GetEndPointer(VariableStoreHeader);
+
+  for (Variable = GetStartPointer (VariableStoreHeader);
+    Length < VariableStoreHeader->Size;
+    Length += sizeof (VARIABLE_HEADER) + Variable->NameSize + Variable->DataSize
+  ) {
+    //
+    // Create the storage
+    //
+    Storage = NULL;
+    Storage = calloc (sizeof (FORMSET_STORAGE), sizeof (CHAR8));
+    if (Storage == NULL) {
+      printf ("Allocate memory failed.\n");
+      return FAIL;
+    }
+    //
+    // If access the first storage, read the platformId and defaultId
+    //
+    if (ReadIdHeaderFlag) {
+      ReadDefaultAndPlatformIdFromBfv (DataBase, Storage);
+      Length += sizeof (VARIABLE_HEADER) + Variable->NameSize + Variable->DataSize;
+      ReadIdHeaderFlag = FALSE;
+      memcpy (PreDefaultId, Storage->DefaultId, MAX_PLATFORM_DEFAULT_ID_NUM * sizeof (UINT16));
+      memcpy (PrePlatformId, Storage->PlatformId, MAX_PLATFORM_DEFAULT_ID_NUM * sizeof (UINT64));
+    } else {
+      //
+      // Store the DefaultId and PlatformId collected from the header to Storage.
+      //
+      memcpy (Storage->DefaultId, PreDefaultId, MAX_PLATFORM_DEFAULT_ID_NUM * sizeof (UINT16));
+      memcpy (Storage->PlatformId, PrePlatformId, MAX_PLATFORM_DEFAULT_ID_NUM * sizeof (UINT64));
+    }
+    Storage->Attributes     = Variable->Attributes;
+    Storage->Size           = (UINT16)Variable->DataSize;
+    Storage->Name           = calloc (Variable->NameSize, sizeof (UINT8));
+    ASSERT (Storage->Name != NULL);
+    Storage->Buffer         = calloc (Variable->DataSize, sizeof (UINT8));
+    ASSERT (Storage->Buffer != NULL);
+    memcpy (
+      &(Storage->Guid),
+      &(Variable->VendorGuid),
+      sizeof (EFI_GUID)
+    );
+    memcpy (
+      Storage->Name,
+      (UINT8 *)Variable + sizeof (VARIABLE_HEADER),
+      Variable->NameSize
+    );
+    memcpy (
+      Storage->Buffer,
+      (UINT8 *)Variable + sizeof (VARIABLE_HEADER) + Variable->NameSize + GET_PAD_SIZE (Variable->NameSize),
+      Storage->Size * sizeof (CHAR8)
+    );
+    //
+    // Assigned the value for comparison in verify mode
+    //
+    Storage->Type           = EFI_IFR_VARSTORE_EFI_OP;
+    Storage->NewEfiVarstore = TRUE;
+    InitializeListHead (&Storage->NameValueListHead);
+
+    InsertTailList(StorageListEntry, &Storage->Link);
+    //
+    // If the last variable, exit.
+    //
+    if (Variable == EndOfVariable) {
+      break;
+    }
+
+    Variable = GetNextVariablePtr (Variable);
+    assert (Variable != NULL);
+  }
+  //
+  // Return the length which is from the beginning of Binary
+  //
+  Length = FvBufExpand3ByteSize (SectionHeader->Size);
+
+  return Length;
+}
+
+/**
+  Check whether exists the valid MonotonicBased variables in NvStorage or not.
+
+  @retval TRUE      If existed, return TRUE.
+  @retval FALSE     Others
+**/
+BOOLEAN
+ExistMonotonicBasedEfiVarOrNot (
+  IN  LIST_ENTRY  *StorageListHead
+  )
+{
+  EFI_FIRMWARE_VOLUME_HEADER    *VarAddr;
+  LIST_ENTRY                    *StorageLink;
+  FORMSET_STORAGE               *Storage;
+  VARIABLE_HEADER               *VariableHeader;
+  VARIABLE_STORE_HEADER         *VariableStoreHeader;
+
+  VariableHeader      = NULL;
+  VarAddr             = (EFI_FIRMWARE_VOLUME_HEADER   *) gEfiFdInfo.EfiVariableAddr;
+  VariableStoreHeader = (VARIABLE_STORE_HEADER *)((CHAR8 *)VarAddr + VarAddr->HeaderLength);
+  //
+  //Parse the variable range, and check whether there is some existed ones.
+  //
+  StorageLink = GetFirstNode (StorageListHead);
+  while (!IsNull (StorageListHead, StorageLink)) {
+    Storage = FORMSET_STORAGE_FROM_LINK (StorageLink);
+    //
+    // Ignore the invalid varlist node
+    //
+    if ((Storage->Buffer == NULL)
+      || (Storage->Name == NULL)
+      || (FceStrLen(Storage->Name) == 0)
+      ) {
+     StorageLink = GetNextNode (StorageListHead, StorageLink);
+     continue;
+    }
+    //
+    // Report error, if the variable name is invalid.
+    //
+    if ((Storage->Name == NULL) || (FceStrLen(Storage->Name) == 0)) {
+      StorageLink = GetNextNode (StorageListHead, StorageLink);
+     continue;
+    }
+    VariableHeader = FindVariableInNv (
+                       VariableStoreHeader,
+                       Storage
+                     );
+
+    if ((VariableHeader != NULL)) {
+       return TRUE;
+    }
+    StorageLink = GetNextNode (StorageListHead, StorageLink);
+  }
+  return FALSE;
+}
+/**
+  Fix the size of montonic variable header.
+
+  @param  Binary            The pointer to the header of storage under specifed platformId and defaultId
+  @param  Length            The length of binary.
+
+**/
+VOID
+FixMontonicVariableHeaderSize (
+  IN  UINT8   *BinaryBeginning,
+  IN  UINT32  Length
+  )
+{
+  VARIABLE_STORE_HEADER         *VariableStoreHeader;
+
+  VariableStoreHeader       = (VARIABLE_STORE_HEADER *) (BinaryBeginning + *(UINT16 *)BinaryBeginning);
+  VariableStoreHeader->Size =  Length -  *(UINT16 *)BinaryBeginning;
+}
diff --git a/Platform/Intel/Tools/FCE/MonotonicBasedVariable.h b/Platform/Intel/Tools/FCE/MonotonicBasedVariable.h
new file mode 100644
index 0000000000..11fc51ed38
--- /dev/null
+++ b/Platform/Intel/Tools/FCE/MonotonicBasedVariable.h
@@ -0,0 +1,162 @@
+/** @file
+
+ The header of MonotonicBasedVariable.c.
+
+ Copyright (c) 2011-2019, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __AUTHENTICATED_VARIABLE_FORMAT_H__
+#define __AUTHENTICATED_VARIABLE_FORMAT_H__
+
+#define EFI_AUTHENTICATED_VARIABLE_GUID \
+  { 0x515fa686, 0xb06e, 0x4550, { 0x91, 0x12, 0x38, 0x2b, 0xf1, 0x6, 0x7b, 0xfb }}
+
+extern EFI_GUID gEfiAuthenticatedVariableGuid;
+
+///
+/// Alignment of variable name and data, according to the architecture:
+/// * For IA-32 and Intel(R) 64 architectures: 1
+/// * For IA-64 architecture: 8
+///
+#if defined (MDE_CPU_IPF)
+#define ALIGNMENT         8
+#else
+#define ALIGNMENT         1
+#endif
+
+///
+/// GET_PAD_SIZE calculates the miminal pad bytes needed to make the current pad size satisfy the alignment requirement.
+///
+#if (ALIGNMENT == 1)
+#define GET_PAD_SIZE(a) (0)
+#else
+#define GET_PAD_SIZE(a) (((~a) + 1) & (ALIGNMENT - 1))
+#endif
+
+///
+/// Alignment of Variable Data Header in Variable Store region
+///
+#define HEADER_ALIGNMENT  4
+#define HEADER_ALIGN(Header)  (((UINTN) (Header) + HEADER_ALIGNMENT - 1) & (~(HEADER_ALIGNMENT - 1)))
+
+///
+/// Status of Variable Store Region
+///
+typedef enum {
+  EfiRaw,
+  EfiValid,
+  EfiInvalid,
+  EfiUnknown
+} VARIABLE_STORE_STATUS;
+
+#pragma pack(1)
+
+#define VARIABLE_STORE_SIGNATURE  EFI_VARIABLE_GUID
+
+///
+/// Variable Store Header Format and State
+///
+#define VARIABLE_STORE_FORMATTED          0x5a
+#define VARIABLE_STORE_HEALTHY            0xfe
+
+///
+/// Variable Store region header
+///
+typedef struct {
+  ///
+  /// Variable store region signature.
+  ///
+  EFI_GUID  Signature;
+  ///
+  /// Size of entire variable store,
+  /// including size of variable store header but not including the size of FvHeader.
+  ///
+  UINT32  Size;
+  ///
+  /// Variable region format state.
+  ///
+  UINT8   Format;
+  ///
+  /// Variable region healthy state.
+  ///
+  UINT8   State;
+  UINT16  Reserved;
+  UINT32  Reserved1;
+} VARIABLE_STORE_HEADER;
+
+///
+/// Variable data start flag.
+///
+#define VARIABLE_DATA                     0x55AA
+
+///
+/// Variable State flags
+///
+#define VAR_IN_DELETED_TRANSITION     0xfe  ///< Variable is in obsolete transition
+#define VAR_DELETED                   0xfd  ///< Variable is obsolete
+#define VAR_HEADER_VALID_ONLY         0x7f  ///< Variable header has been valid
+#define VAR_ADDED                     0x3f  ///< Variable has been completely added
+
+///
+/// Single Variable Data Header Structure.
+///
+typedef struct {
+  ///
+  /// Variable Data Start Flag.
+  ///
+  UINT16      StartId;
+  ///
+  /// Variable State defined above.
+  ///
+  UINT8       State;
+  UINT8       Reserved;
+  ///
+  /// Attributes of variable defined in UEFI spec
+  ///
+  UINT32      Attributes;
+  ///
+  /// Associated monotonic count value against replay attack.
+  ///
+  UINT64      MonotonicCount;
+  ///
+  /// Index of associated public key in database.
+  ///
+  UINT32      PubKeyIndex;
+  ///
+  /// Size of variable null-terminated Unicode string name.
+  ///
+  UINT32      NameSize;
+  ///
+  /// Size of the variable data without this header.
+  ///
+  UINT32      DataSize;
+  ///
+  /// A unique identifier for the vendor that produces and consumes this varaible.
+  ///
+  EFI_GUID    VendorGuid;
+} VARIABLE_HEADER;
+
+#pragma pack()
+
+typedef struct _VARIABLE_INFO_ENTRY  VARIABLE_INFO_ENTRY;
+
+///
+/// This structure contains the variable list that is put in EFI system table.
+/// The variable driver collects all variables that were used at boot service time and produces this list.
+/// This is an optional feature to dump all used variables in shell environment.
+///
+struct _VARIABLE_INFO_ENTRY {
+  VARIABLE_INFO_ENTRY *Next;       ///< Pointer to next entry.
+  EFI_GUID            VendorGuid;  ///< Guid of Variable.
+  CHAR16              *Name;       ///< Name of Variable.
+  UINT32              Attributes;  ///< Attributes of variable defined in UEFI spec.
+  UINT32              ReadCount;   ///< Number of times to read this variable.
+  UINT32              WriteCount;  ///< Number of times to write this variable.
+  UINT32              DeleteCount; ///< Number of times to delete this variable.
+  UINT32              CacheCount;  ///< Number of times that cache hits this variable.
+  BOOLEAN             Volatile;    ///< TRUE if volatile, FALSE if non-volatile.
+};
+
+#endif // _EFI_VARIABLE_H_
diff --git a/Platform/Intel/Tools/FCE/TimeBasedVariable.c b/Platform/Intel/Tools/FCE/TimeBasedVariable.c
new file mode 100644
index 0000000000..e21c61dde9
--- /dev/null
+++ b/Platform/Intel/Tools/FCE/TimeBasedVariable.c
@@ -0,0 +1,878 @@
+/** @file
+
+ Read and edit the time-base authenticated variables.
+
+ Copyright (c) 2011-2019, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "Fce.h"
+#include "TimeBasedVariable.h"
+
+extern LIST_ENTRY                  mAllVarListEntry;
+extern MULTI_PLATFORM_PARAMETERS   mMultiPlatformParam;
+extern G_EFI_FD_INFO               gEfiFdInfo;
+
+EFI_GUID  gEfiAuthenticatedVariableBasedTimeGuid     = EFI_AUTHENTICATED_VARIABLE_BASED_TIME_GUID;
+/**
+
+  Gets the pointer to the first variable header in given variable store area.
+
+  @param VarStoreHeader  Pointer to the Variable Store Header.
+
+  @return Pointer to the first variable header.
+
+**/
+static
+VARIABLE_HEADER *
+GetStartPointer (
+  IN VARIABLE_STORE_HEADER       *VarStoreHeader
+  )
+{
+  //
+  // The end of variable store.
+  //
+  return (VARIABLE_HEADER *) HEADER_ALIGN (VarStoreHeader + 1);
+}
+
+/**
+
+  Gets the pointer to the end of the variable storage area.
+
+  This function gets pointer to the end of the variable storage
+  area, according to the input variable store header.
+
+  @param VarStoreHeader  Pointer to the Variable Store Header.
+
+  @return Pointer to the end of the variable storage area.
+
+**/
+static
+VARIABLE_HEADER *
+GetEndPointer (
+  IN VARIABLE_STORE_HEADER       *VarStoreHeader
+  )
+{
+  //
+  // The end of variable store
+  //
+  return (VARIABLE_HEADER *) HEADER_ALIGN ((UINTN) VarStoreHeader + VarStoreHeader->Size);
+}
+
+
+/**
+
+  This code checks if variable header is valid or not.
+
+  @param Variable        Pointer to the Variable Header.
+
+  @retval TRUE           Variable header is valid.
+  @retval FALSE          Variable header is not valid.
+
+**/
+static
+BOOLEAN
+IsValidVariableHeader (
+  IN  VARIABLE_HEADER   *Variable
+  )
+{
+  if ((Variable == NULL) || (Variable->StartId != VARIABLE_DATA)) {
+    return FALSE;
+  }
+
+  return TRUE;
+}
+
+/**
+
+  This code gets the size of name of variable.
+
+  @param Variable        Pointer to the Variable Header.
+
+  @return UINTN          Size of variable in bytes.
+
+**/
+static
+UINTN
+NameSizeOfVariable (
+  IN  VARIABLE_HEADER   *Variable
+  )
+{
+  if ((Variable->State    == (UINT8) (-1))  ||
+      (Variable->DataSize == (UINT32) (-1)) ||
+      (Variable->NameSize == (UINT32) (-1)) ||
+      (Variable->Attributes == (UINT32) (-1))
+      ) {
+    return 0;
+  }
+  return (UINTN) Variable->NameSize;
+}
+
+/**
+
+  This code gets the size of variable data.
+
+  @param Variable        Pointer to the Variable Header.
+
+  @return Size of variable in bytes.
+
+**/
+static
+UINTN
+DataSizeOfVariable (
+  IN  VARIABLE_HEADER   *Variable
+  )
+{
+  if ((Variable->State    == (UINT8)  (-1)) ||
+      (Variable->DataSize == (UINT32) (-1)) ||
+      (Variable->NameSize == (UINT32) (-1)) ||
+      (Variable->Attributes == (UINT32) (-1))
+      ) {
+    return 0;
+  }
+  return (UINTN) Variable->DataSize;
+}
+
+/**
+
+  This code gets the pointer to the variable name.
+
+  @param Variable        Pointer to the Variable Header.
+
+  @return Pointer to Variable Name which is Unicode encoding.
+
+**/
+static
+CHAR16 *
+GetVariableNamePtr (
+  IN  VARIABLE_HEADER   *Variable
+  )
+{
+  return (CHAR16 *) (Variable + 1);
+}
+
+/**
+
+  This code gets the pointer to the variable data.
+
+  @param Variable        Pointer to the Variable Header.
+
+  @return Pointer to Variable Data.
+
+**/
+static
+UINT8 *
+GetVariableDataPtr (
+  IN  VARIABLE_HEADER   *Variable
+  )
+{
+  UINTN Value;
+
+  //
+  // Be careful about pad size for alignment.
+  //
+  Value =  (UINTN) GetVariableNamePtr (Variable);
+  Value += NameSizeOfVariable (Variable);
+  Value += GET_PAD_SIZE (NameSizeOfVariable (Variable));
+
+  return (UINT8 *) Value;
+}
+
+/**
+
+  This code gets the pointer to the next variable header.
+
+  @param Variable        Pointer to the Variable Header.
+
+  @return Pointer to next variable header.
+
+**/
+static
+VARIABLE_HEADER *
+GetNextVariablePtr (
+  IN  VARIABLE_HEADER   *Variable
+  )
+{
+  UINTN Value;
+
+  if (!IsValidVariableHeader (Variable)) {
+    return NULL;
+  }
+
+  Value =  (UINTN) GetVariableDataPtr (Variable);
+  Value += DataSizeOfVariable (Variable);
+  Value += GET_PAD_SIZE (DataSizeOfVariable (Variable));
+
+  //
+  // Be careful about pad size for alignment.
+  //
+  return (VARIABLE_HEADER *) HEADER_ALIGN (Value);
+}
+
+/**
+  Search and get a free space in the EFI variable zone
+
+  @param VariableStoreHeader       The start of a EFI variable zone.
+  @param VarListSize               The size of a variables needs to be allocated.
+  @param FreeBeginVar              The dual pointer to the free NV space.
+
+  @retval EFI_SUCCESS              Return the beginning of a free variable space.
+  @retval RETURN_BUFFER_TOO_SMALL  Failed.
+**/
+static
+EFI_STATUS
+GetVariableVar (
+  IN      VARIABLE_STORE_HEADER  *VariableStoreHeader,
+  IN      UINT32                 VarListSize,
+  IN OUT  CHAR8                  **FreeBeginVar
+)
+{
+  BOOLEAN          Flag;
+  VARIABLE_HEADER  *Variable;
+  VARIABLE_HEADER  *EndOfVariable;
+  CHAR8            *BeginVar;
+
+  BeginVar      = NULL;
+  Flag          = FALSE;
+  Variable      = NULL;
+  EndOfVariable = NULL;
+  *FreeBeginVar = NULL;
+
+  if (VariableStoreHeader == NULL) {
+    *FreeBeginVar = NULL;
+    return RETURN_INVALID_PARAMETER;
+  }
+  Variable      = GetStartPointer (VariableStoreHeader);
+  EndOfVariable = GetEndPointer(VariableStoreHeader);
+  //
+  //Search the beginning of free NV
+  //
+  while (Variable != EndOfVariable) {
+    BeginVar = (CHAR8 *)Variable;
+    Variable = GetNextVariablePtr (Variable);
+    if (Variable == NULL) {
+      Flag = TRUE;
+      break;
+    }
+  }
+  //
+  // Check whether the free space is more than what we want
+  //
+  if ((CHAR8 *)BeginVar + VarListSize > (CHAR8 *)EndOfVariable) {
+    return RETURN_BUFFER_TOO_SMALL;
+  }
+  //
+  // If not find the available space, return NULL
+  //
+  if (!Flag) {
+    return RETURN_BUFFER_TOO_SMALL;
+  }
+  *FreeBeginVar = BeginVar;
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Search whether the variable in VarList has existed in current NV.
+
+  Parse the FFS or Fd image, and find the valid variable pointer.
+
+  @param VariableStoreHeader    The start of a EFI variable zone.
+  @param VarList                The pointer to the VarList
+
+  @retval address               If the variable existed in current NV, return address
+  @return NULL                  Otherwise, return NULL
+**/
+static
+VARIABLE_HEADER  *
+FindVariableInNv (
+  IN     VARIABLE_STORE_HEADER  *VariableStoreHeader,
+  IN     FORMSET_STORAGE        *Storage
+  )
+{
+  BOOLEAN          Flag;
+  VARIABLE_HEADER  *Variable;
+  VARIABLE_HEADER  *EndOfVariable;
+  CHAR16           *VariableName;
+
+  Flag            = FALSE;
+  Variable        = NULL;
+  EndOfVariable   = NULL;
+  VariableName    = NULL;
+
+  if ((VariableStoreHeader == NULL) || (Storage == NULL) || (Storage->Name == NULL)) {
+    return NULL;
+  }
+  Variable      = GetStartPointer (VariableStoreHeader);
+  EndOfVariable = GetEndPointer(VariableStoreHeader);
+  //
+  // Parse and compare the variable in the NV space one by one
+  //
+  while ((Variable != EndOfVariable) && (Variable != NULL)) {
+    VariableName = (CHAR16 *)((CHAR8 *)Variable + sizeof (VARIABLE_HEADER));
+    if (!CompareGuid (&Variable->VendorGuid, &Storage->Guid) \
+      && !FceStrCmp (Storage->Name, VariableName) \
+      && (Variable->State == VAR_ADDED)
+      ) {
+      Flag = TRUE;
+      break;
+    }
+    Variable = GetNextVariablePtr (Variable);
+  }
+  if (!Flag) {
+    return NULL;
+  }
+  return Variable;
+}
+/**
+  Exchange the data between Efi variable and the data of VarList when the
+  variable use the time stamp authenticated variable header
+
+  If VarToList is TRUE, copy the efi variable data to the VarList; Otherwise,
+  update the data from varlist to efi variable.
+
+  @param VarToList              The flag to control the direction of exchange.
+  @param StorageListHead        Decide which variale list be updated
+
+  @retval EFI_SUCCESS           Get the address successfully.
+  @retval EFI_OUT_OF_RESOURCES  No available in the EFI variable zone.
+  @retval EFI_INVALID_PARAMETER Invalid variable name.
+**/
+
+EFI_STATUS
+SynAuthEfiVariableBasedTime (
+  IN  BOOLEAN     VarToList,
+  IN  LIST_ENTRY  *StorageListHead
+  )
+{
+  EFI_FIRMWARE_VOLUME_HEADER    *VarAddr;
+  LIST_ENTRY                    *StorageLink;
+  FORMSET_STORAGE               *Storage;
+  EFI_STATUS                    Status;
+  CHAR8                         *NewAvailableAddr;
+  CHAR8                         *DataBase;
+  VARIABLE_HEADER               *VariableHeader;
+  VARIABLE_STORE_HEADER         *VariableStoreHeader;
+  UINTN                         VarNameSize;
+
+  Status              = EFI_SUCCESS;
+  DataBase            = NULL;
+  NewAvailableAddr    = NULL;
+  VarNameSize         = 0;
+  VariableHeader      = NULL;
+  VarAddr             = (EFI_FIRMWARE_VOLUME_HEADER   *) gEfiFdInfo.EfiVariableAddr;
+  VariableStoreHeader = (VARIABLE_STORE_HEADER *)((CHAR8 *)VarAddr + VarAddr->HeaderLength);
+  //
+  //Parse the variable range, and check whether there is some existed ones.
+  //
+  StorageLink = GetFirstNode (StorageListHead);
+  while (!IsNull (StorageListHead, StorageLink)) {
+    Storage = FORMSET_STORAGE_FROM_LINK (StorageLink);
+     //
+     // Ignore the invalid varlist node
+     //
+     if (Storage->Buffer == NULL) {
+      StorageLink = GetNextNode (StorageListHead, StorageLink);
+      continue;
+     }
+     //
+     // Report error, if the variable name is invalid.
+     //
+     if ((Storage->Name == NULL) || (FceStrLen(Storage->Name) == 0)) {
+       printf ("Error. One variable name is NULL. Its GUID is: ");
+       PrintGuid(&(Storage->Guid));
+       return EFI_INVALID_PARAMETER;
+     }
+     VariableHeader = FindVariableInNv (
+                        VariableStoreHeader,
+                        Storage
+                        );
+
+   if (VarToList) {
+     //
+     //Copy the data from NV to the VarList.
+     //
+     if (VariableHeader != NULL) {
+       if (Storage->Buffer == NULL) {
+         Storage->Buffer = calloc (Storage->Size, sizeof (CHAR8));
+         ASSERT (Storage->Buffer != NULL);
+       }
+       //
+       // The variable in VarList is CHAR8, but in the EFI variable is CHAR16.
+       //
+       DataBase    = (CHAR8 *)GetVariableDataPtr (VariableHeader);
+       memcpy (
+         Storage->Buffer,
+         (VOID *) DataBase,
+         Storage->Size
+        );
+      }
+    } else {
+       //
+       //If existed, copy the List data to the variable in NV directly. If not found, create a new one.
+       //
+       VarNameSize = 2 * (FceStrLen (Storage->Name) + 1);
+       //
+       //If this variable has existed in current FD, the data in VarList has
+       // been updated, and this variable is not authenticated type, then
+       // update it from VarList to the FD.
+       //
+       if ((VariableHeader != NULL)    \
+         && (Storage->Buffer != NULL)
+         ) {
+         if (!(VariableHeader->Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS)) {
+           DataBase = (CHAR8 *)GetVariableDataPtr (VariableHeader);
+           memcpy (
+             (VOID *) DataBase,
+             Storage->Buffer,
+             Storage->Size
+           );
+         } else {
+           printf ("Error. Not support to update authenticated variables.\n");
+           return EFI_INVALID_PARAMETER;
+         }
+       } else if ((VariableHeader == NULL) && (Storage->Buffer != NULL)){
+         //
+         //If EfiVarstore is not EFI_VARIABLE_NON_VOLATILE, only skip it.
+         //
+         if (Storage->NewEfiVarstore
+           && ((Storage->Attributes & EFI_VARIABLE_NON_VOLATILE) == 0)
+         ) {
+          StorageLink = GetNextNode (StorageListHead, StorageLink);
+          continue;
+         }
+         //
+         // Try to get the available zone from the efi variables
+         //
+         Status = GetVariableVar (
+                    VariableStoreHeader,
+                    Storage->Size + sizeof (VARIABLE_HEADER),
+                    &NewAvailableAddr
+                    );
+
+         if (!EFI_ERROR (Status)) {
+           //
+           // Create the authenticated variable header
+           //
+           VariableHeader                  = (VARIABLE_HEADER *) NewAvailableAddr;
+           VariableHeader->StartId         = VARIABLE_DATA;
+           VariableHeader->State           = VAR_ADDED;
+           VariableHeader->Reserved        = 0x0;
+           VariableHeader->MonotonicCount  = 0x0;
+           memset (&(VariableHeader->TimeStamp), 0, sizeof (EFI_TIME));
+           VariableHeader->PubKeyIndex     = 0x0;
+           if (Storage->NewEfiVarstore) {
+             VariableHeader->Attributes = Storage->Attributes;
+           } else {
+             VariableHeader->Attributes      = EFI_VARIABLE_NON_VOLATILE|EFI_VARIABLE_BOOTSERVICE_ACCESS|EFI_VARIABLE_RUNTIME_ACCESS;
+           }
+           VariableHeader->NameSize        = VarNameSize;
+           VariableHeader->DataSize   = Storage->Size;
+           //
+           //Copy the Guid, variable name, and data in sequence.
+           //
+           memcpy (
+             (VOID *)&(VariableHeader->VendorGuid),
+             &(Storage->Guid),
+             sizeof (EFI_GUID)
+             );
+           NewAvailableAddr = NewAvailableAddr + sizeof (VARIABLE_HEADER);
+           memcpy (
+             (VOID *) NewAvailableAddr,
+              Storage->Name,
+              VarNameSize
+              );
+
+           NewAvailableAddr = NewAvailableAddr + VarNameSize + GET_PAD_SIZE (VarNameSize);
+           memcpy (
+             (VOID *) NewAvailableAddr,
+             Storage->Buffer,
+             Storage->Size * sizeof (CHAR8)
+             );
+         } else {
+           printf ("Error. No available space in NV ram.\n");
+           return EFI_OUT_OF_RESOURCES;
+         }
+       }
+    }
+    StorageLink = GetNextNode (StorageListHead, StorageLink);
+  }
+  return Status;
+}
+
+/**
+  Remove the variable from Efi variable
+
+  Found the variable with the same name in StorageListHead and remove it.
+
+  @param StorageListHead   Decide which variale list be removed.
+
+  @retval EFI_SUCCESS      Remove the variables successfully.
+**/
+EFI_STATUS
+RemoveAuthEfiVariableBasedTime (
+  IN  LIST_ENTRY  *StorageListHead
+  )
+{
+  EFI_FIRMWARE_VOLUME_HEADER    *VarAddr;
+  LIST_ENTRY                    *StorageLink;
+  FORMSET_STORAGE               *Storage;
+  VARIABLE_HEADER               *VariableHeader;
+  VARIABLE_STORE_HEADER         *VariableStoreHeader;
+
+  VariableHeader      = NULL;
+  VarAddr             = (EFI_FIRMWARE_VOLUME_HEADER   *) gEfiFdInfo.EfiVariableAddr;
+  VariableStoreHeader = (VARIABLE_STORE_HEADER *)((CHAR8 *)VarAddr + VarAddr->HeaderLength);
+  //
+  //Parse the variable range, and check whether there is some existed ones.
+  //
+  StorageLink = GetFirstNode (StorageListHead);
+  while (!IsNull (StorageListHead, StorageLink)) {
+    Storage = FORMSET_STORAGE_FROM_LINK (StorageLink);
+    //
+    // Ignore the invalid varlist node
+    //
+    if (Storage->Buffer == NULL) {
+      StorageLink = GetNextNode (StorageListHead, StorageLink);
+      continue;
+    }
+    //
+    // Report error, if the variable name is invalid.
+    //
+    if ((Storage->Name == NULL) || (FceStrLen(Storage->Name) == 0)) {
+      printf ("Error. One variable name is NULL. Its GUID is: ");
+      PrintGuid(&(Storage->Guid));
+      return EFI_INVALID_PARAMETER;
+    }
+    VariableHeader = FindVariableInNv (
+                       VariableStoreHeader,
+                       Storage
+                       );
+    if (VariableHeader != NULL) {
+      VariableHeader->State = VAR_DELETED;
+    }
+    StorageLink = GetNextNode (StorageListHead, StorageLink);
+  }
+  return EFI_SUCCESS;
+}
+
+/**
+  Check the store variable is Time stamp authenticated or not
+
+  @param VarToList     The pointer to the header of Variable Store.
+
+  @retval TRUE         If authenticated, return TRUE.
+  @retval FALSE        Otherwise, return FALSE.
+**/
+
+BOOLEAN
+CheckTimeBasedVarStoreOrNot (
+  IN VOID  *VariableStoreHeader
+  )
+{
+  if (!CompareGuid (
+    &gEfiAuthenticatedVariableBasedTimeGuid,
+    &((VARIABLE_STORE_HEADER *)VariableStoreHeader)->Signature)
+    ) {
+    return TRUE;
+  } else {
+    return FALSE;
+  }
+}
+
+/**
+  Copy time-based authenticated variable to binary in multi-platform mode
+
+  @param  Storage           The pointer to a storage in storage list.
+  @param  StorageBeginning  The pointer to the beginning of storage under specifed platformId and defaultId
+  @param  Index             The number of the storage. If the Index is 0, record the variable header to
+                            the binary. Or else, only record the storage.
+
+  @return length          The length of storage
+**/
+UINT32
+CopyTimeBasedVariableToBinary (
+  IN      FORMSET_STORAGE   *Storage,
+  IN OUT  UINT8             *StorageBeginning,
+  IN      UINT32            Index
+  )
+{
+  EFI_STATUS                    Status;
+  CHAR8                         *NewAvailableAddr;
+  VARIABLE_HEADER               *VariableHeader;
+  VARIABLE_STORE_HEADER         *VariableStoreHeader;
+  UINTN                         VarNameSize;
+  UINT32                        HeaderLength;
+
+  Status              = EFI_SUCCESS;
+  NewAvailableAddr    = NULL;
+  VarNameSize         = 0;
+  HeaderLength        = 0;
+  VariableHeader      = NULL;
+  VariableStoreHeader = NULL;
+
+  if ((Storage->Name == NULL) || (FceStrLen(Storage->Name) == 0)) {
+    printf ("Error. One variable name is NULL. Its GUID is: ");
+    PrintGuid(&(Storage->Guid));
+    return 0;
+  }
+  //
+  // If the first storage under one specified platformId and defaultId, create the variable header
+  //
+  if (Index == 0) {
+    HeaderLength = WriteDefaultAndPlatformId (StorageBeginning, Storage);
+    VariableStoreHeader = (VARIABLE_STORE_HEADER *) (StorageBeginning + HeaderLength);
+    //
+    //Create the Variable Storage header
+    //
+    memcpy (&(VariableStoreHeader->Signature), &gEfiAuthenticatedVariableBasedTimeGuid, sizeof (EFI_GUID));
+    VariableStoreHeader->Format = 0x5A;
+    VariableStoreHeader->State  = 0xFE;
+    //
+    //Assign a big size here. It will be fixed after the storage under a specifed platformId and defaultId are all written.
+    //
+    VariableStoreHeader->Size   = gEfiFdInfo.FdSize;
+  }
+
+  VariableStoreHeader = (VARIABLE_STORE_HEADER *) (StorageBeginning + *(UINT16 *)StorageBeginning);
+
+  Status = GetVariableVar (
+             VariableStoreHeader,
+             Storage->Size + sizeof (VARIABLE_HEADER),
+             &NewAvailableAddr
+           );
+
+  if (EFI_ERROR (Status)) {
+    return FAIL;
+  }
+  //
+  // Create the variable header
+  //
+  VarNameSize                = 2 * (FceStrLen (Storage->Name) + 1);
+  VariableHeader             = (VARIABLE_HEADER *) NewAvailableAddr;
+  VariableHeader->StartId    = VARIABLE_DATA;
+  VariableHeader->State      = VAR_ADDED;
+  VariableHeader->Reserved   = 0x0;
+  VariableHeader->MonotonicCount  = 0x0;
+  memset (&(VariableHeader->TimeStamp), 0, sizeof (EFI_TIME));
+  VariableHeader->PubKeyIndex     = 0x0;
+
+  if (Storage->NewEfiVarstore) {
+    VariableHeader->Attributes = Storage->Attributes;
+  } else {
+    VariableHeader->Attributes = EFI_VARIABLE_NON_VOLATILE|EFI_VARIABLE_BOOTSERVICE_ACCESS|EFI_VARIABLE_RUNTIME_ACCESS;
+  }
+  VariableHeader->NameSize   = VarNameSize;
+  VariableHeader->DataSize   = Storage->Size;
+  //
+  //Copy the Guid, variable name, and data in sequence.
+  //
+  memcpy (
+    (VOID *)&(VariableHeader->VendorGuid),
+    &(Storage->Guid),
+    sizeof (EFI_GUID)
+  );
+  NewAvailableAddr = NewAvailableAddr + sizeof (VARIABLE_HEADER);
+  memcpy (
+    (VOID *) NewAvailableAddr,
+    Storage->Name,
+    VarNameSize
+  );
+
+  NewAvailableAddr = NewAvailableAddr + VarNameSize + GET_PAD_SIZE (VarNameSize);
+  memcpy (
+    (VOID *) NewAvailableAddr,
+    Storage->Buffer,
+    Storage->Size * sizeof (CHAR8)
+  );
+  //
+  // Return the length which is from the beginning of Binary
+  //
+  return ((UINT32) ((UINT8*)NewAvailableAddr - StorageBeginning) + Storage->Size);
+}
+
+/**
+  Read time-based authenticated variable to storage list in multi-platform mode
+
+  @param  Binary            The pointer to the header of storage under specifed platformId and defaultId
+  @param  StorageListEntry  The pointer to the storage list.
+
+  @return length          The length of storage
+**/
+UINT32
+ReadTimeBasedVariableToList (
+  IN      UINT8             *Binary,
+  IN      LIST_ENTRY        *StorageListEntry
+  )
+{
+  VARIABLE_HEADER               *EndOfVariable;
+  VARIABLE_HEADER               *Variable;
+  VARIABLE_STORE_HEADER         *VariableStoreHeader;
+  FORMSET_STORAGE               *Storage;
+  BOOLEAN                       ReadIdHeaderFlag;
+  UINT32                        Length;
+  EFI_COMMON_SECTION_HEADER     *SectionHeader;
+  UINT8                         *DataBase;
+  static UINT16                 PreDefaultId[MAX_PLATFORM_DEFAULT_ID_NUM];
+  static UINT64                 PrePlatformId[MAX_PLATFORM_DEFAULT_ID_NUM];
+
+  VariableStoreHeader = NULL;
+  Variable            = NULL;
+  ReadIdHeaderFlag    = TRUE;
+  Length              = 0;
+  SectionHeader       = (EFI_COMMON_SECTION_HEADER *)Binary;
+  DataBase            = Binary + sizeof (EFI_COMMON_SECTION_HEADER);
+  VariableStoreHeader = (VARIABLE_STORE_HEADER *) (DataBase + *(UINT16 *)DataBase);
+  EndOfVariable       = GetEndPointer(VariableStoreHeader);
+
+  for (Variable = GetStartPointer (VariableStoreHeader);
+    Length < VariableStoreHeader->Size;
+    Length += sizeof (VARIABLE_HEADER) + Variable->NameSize + Variable->DataSize
+  ) {
+    //
+    // Create the storage
+    //
+    Storage = NULL;
+    Storage = calloc (sizeof (FORMSET_STORAGE), sizeof (CHAR8));
+    if (Storage == NULL) {
+      printf ("Allocate memory failed.\n");
+      return FAIL;
+    }
+    //
+    // If access the first storage, read the platformId and defaultId
+    //
+    if (ReadIdHeaderFlag) {
+      ReadDefaultAndPlatformIdFromBfv (DataBase, Storage);
+      Length += sizeof (VARIABLE_HEADER) + Variable->NameSize + Variable->DataSize;
+      ReadIdHeaderFlag = FALSE;
+      memcpy (PreDefaultId, Storage->DefaultId, MAX_PLATFORM_DEFAULT_ID_NUM * sizeof (UINT16));
+      memcpy (PrePlatformId, Storage->PlatformId, MAX_PLATFORM_DEFAULT_ID_NUM * sizeof (UINT64));
+    } else {
+      //
+      // Store the DefaultId and PlatformId collected from the header to Storage.
+      //
+      memcpy (Storage->DefaultId, PreDefaultId, MAX_PLATFORM_DEFAULT_ID_NUM * sizeof (UINT16));
+      memcpy (Storage->PlatformId, PrePlatformId, MAX_PLATFORM_DEFAULT_ID_NUM * sizeof (UINT64));
+    }
+    Storage->Attributes     = Variable->Attributes;
+    Storage->Size           = (UINT16)Variable->DataSize;
+    Storage->Name           = calloc (Variable->NameSize, sizeof (UINT8));
+    ASSERT (Storage->Name != NULL);
+    Storage->Buffer         = calloc (Variable->DataSize, sizeof (UINT8));
+    ASSERT (Storage->Buffer != NULL);
+    memcpy (
+      &(Storage->Guid),
+      &(Variable->VendorGuid),
+      sizeof (EFI_GUID)
+    );
+    memcpy (
+      Storage->Name,
+      (UINT8 *)Variable + sizeof (VARIABLE_HEADER),
+      Variable->NameSize
+    );
+    memcpy (
+      Storage->Buffer,
+      (UINT8 *)Variable + sizeof (VARIABLE_HEADER) + Variable->NameSize + GET_PAD_SIZE (Variable->NameSize),
+      Storage->Size * sizeof (CHAR8)
+    );
+    //
+    // Assigned the value for comparison in verify mode
+    //
+    Storage->Type           = EFI_IFR_VARSTORE_EFI_OP;
+    Storage->NewEfiVarstore = TRUE;
+    InitializeListHead (&Storage->NameValueListHead);
+
+    InsertTailList(StorageListEntry, &Storage->Link);
+    //
+    // If the last variable, exit.
+    //
+    if (Variable == EndOfVariable) {
+      break;
+    }
+
+    Variable = GetNextVariablePtr (Variable);
+    assert (Variable != NULL);
+  }
+  //
+  // Return the length which is from the beginning of Binary
+  //
+  Length = FvBufExpand3ByteSize (SectionHeader->Size);
+
+  return Length;
+}
+
+/**
+  Check whether exists the valid time-based variables in NvStorage or not.
+
+  @retval TRUE      If existed, return TRUE.
+  @retval FALSE     Others
+**/
+BOOLEAN
+ExistTimeBasedEfiVarOrNot (
+  IN  LIST_ENTRY  *StorageListHead
+  )
+{
+  EFI_FIRMWARE_VOLUME_HEADER    *VarAddr;
+  LIST_ENTRY                    *StorageLink;
+  FORMSET_STORAGE               *Storage;
+  VARIABLE_HEADER               *VariableHeader;
+  VARIABLE_STORE_HEADER         *VariableStoreHeader;
+
+  VariableHeader      = NULL;
+  VarAddr             = (EFI_FIRMWARE_VOLUME_HEADER   *) gEfiFdInfo.EfiVariableAddr;
+  VariableStoreHeader = (VARIABLE_STORE_HEADER *)((CHAR8 *)VarAddr + VarAddr->HeaderLength);
+  //
+  //Parse the variable range, and check whether there is some existed ones.
+  //
+  StorageLink = GetFirstNode (StorageListHead);
+  while (!IsNull (StorageListHead, StorageLink)) {
+    Storage = FORMSET_STORAGE_FROM_LINK (StorageLink);
+    //
+    // Ignore the invalid varlist node
+    //
+    if ((Storage->Buffer == NULL)
+      || (Storage->Name == NULL)
+      || (FceStrLen(Storage->Name) == 0)
+      ) {
+     StorageLink = GetNextNode (StorageListHead, StorageLink);
+     continue;
+    }
+    //
+    // Report error, if the variable name is invalid.
+    //
+    if ((Storage->Name == NULL) || (FceStrLen(Storage->Name) == 0)) {
+      StorageLink = GetNextNode (StorageListHead, StorageLink);
+     continue;
+    }
+    VariableHeader = FindVariableInNv (
+                       VariableStoreHeader,
+                       Storage
+                     );
+
+    if ((VariableHeader != NULL)) {
+       return TRUE;
+    }
+    StorageLink = GetNextNode (StorageListHead, StorageLink);
+  }
+  return FALSE;
+}
+
+/**
+  Fix the size of time-based variable header.
+
+  @param  Binary            The pointer to the header of storage under specifed platformId and defaultId
+  @param  Length            The length of binary.
+
+**/
+VOID
+FixBasedTimeVariableHeaderSize (
+  IN  UINT8   *BinaryBeginning,
+  IN  UINT32  Length
+  )
+{
+  VARIABLE_STORE_HEADER         *VariableStoreHeader;
+
+  VariableStoreHeader       = (VARIABLE_STORE_HEADER *) (BinaryBeginning + *(UINT16 *)BinaryBeginning);
+  VariableStoreHeader->Size =  Length -  *(UINT16 *)BinaryBeginning;
+}
diff --git a/Platform/Intel/Tools/FCE/TimeBasedVariable.h b/Platform/Intel/Tools/FCE/TimeBasedVariable.h
new file mode 100644
index 0000000000..3ffd939443
--- /dev/null
+++ b/Platform/Intel/Tools/FCE/TimeBasedVariable.h
@@ -0,0 +1,166 @@
+/** @file
+
+ The header of TimeBasedVariable.c.
+
+ Copyright (c) 2011-2019, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __AUTHENTICATED_VARIABLE_FORMAT_BASED_TIME_H__
+#define __AUTHENTICATED_VARIABLE_FORMAT_BASED_TIME_H__
+
+#define EFI_AUTHENTICATED_VARIABLE_BASED_TIME_GUID \
+  { 0xaaf32c78, 0x947b, 0x439a, { 0xa1, 0x80, 0x2e, 0x14, 0x4e, 0xc3, 0x77, 0x92 } }
+
+extern EFI_GUID gEfiAuthenticatedVariableBasedTimeGuid;
+
+///
+/// Alignment of variable name and data, according to the architecture:
+/// * For IA-32 and Intel(R) 64 architectures: 1
+/// * For IA-64 architecture: 8
+///
+#if defined (MDE_CPU_IPF)
+#define ALIGNMENT         8
+#else
+#define ALIGNMENT         1
+#endif
+
+///
+/// GET_PAD_SIZE calculates the miminal pad bytes needed to make the current pad size satisfy the alignment requirement.
+///
+#if (ALIGNMENT == 1)
+#define GET_PAD_SIZE(a) (0)
+#else
+#define GET_PAD_SIZE(a) (((~a) + 1) & (ALIGNMENT - 1))
+#endif
+
+///
+/// Alignment of Variable Data Header in Variable Store region
+///
+#define HEADER_ALIGNMENT  4
+#define HEADER_ALIGN(Header)  (((UINTN) (Header) + HEADER_ALIGNMENT - 1) & (~(HEADER_ALIGNMENT - 1)))
+
+///
+/// Status of Variable Store Region
+///
+typedef enum {
+  EfiRaw,
+  EfiValid,
+  EfiInvalid,
+  EfiUnknown
+} VARIABLE_STORE_STATUS;
+
+#pragma pack(1)
+
+#define VARIABLE_STORE_SIGNATURE  EFI_VARIABLE_GUID
+
+///
+/// Variable Store Header Format and State
+///
+#define VARIABLE_STORE_FORMATTED          0x5a
+#define VARIABLE_STORE_HEALTHY            0xfe
+
+///
+/// Variable Store region header
+///
+typedef struct {
+  ///
+  /// Variable store region signature.
+  ///
+  EFI_GUID  Signature;
+  ///
+  /// Size of entire variable store,
+  /// including size of variable store header but not including the size of FvHeader.
+  ///
+  UINT32  Size;
+  ///
+  /// Variable region format state.
+  ///
+  UINT8   Format;
+  ///
+  /// Variable region healthy state.
+  ///
+  UINT8   State;
+  UINT16  Reserved;
+  UINT32  Reserved1;
+} VARIABLE_STORE_HEADER;
+
+///
+/// Variable data start flag.
+///
+#define VARIABLE_DATA                     0x55AA
+
+///
+/// Variable State flags
+///
+#define VAR_IN_DELETED_TRANSITION     0xfe  ///< Variable is in obsolete transition
+#define VAR_DELETED                   0xfd  ///< Variable is obsolete
+#define VAR_HEADER_VALID_ONLY         0x7f  ///< Variable header has been valid
+#define VAR_ADDED                     0x3f  ///< Variable has been completely added
+
+///
+/// Single Variable Data Header Structure.
+///
+typedef struct {
+  ///
+  /// Variable Data Start Flag.
+  ///
+  UINT16      StartId;
+  ///
+  /// Variable State defined above.
+  ///
+  UINT8       State;
+  UINT8       Reserved;
+  ///
+  /// Attributes of variable defined in UEFI spec
+  ///
+  UINT32      Attributes;
+  ///
+  /// Associated monotonic count value against replay attack.
+  ///
+  UINT64      MonotonicCount;
+  ///
+  /// Associated TimeStamp value against replay attack.
+  ///
+  EFI_TIME    TimeStamp;
+  ///
+  /// Index of associated public key in database.
+  ///
+  UINT32      PubKeyIndex;
+  ///
+  /// Size of variable null-terminated Unicode string name.
+  ///
+  UINT32      NameSize;
+  ///
+  /// Size of the variable data without this header.
+  ///
+  UINT32      DataSize;
+  ///
+  /// A unique identifier for the vendor that produces and consumes this varaible.
+  ///
+  EFI_GUID    VendorGuid;
+} VARIABLE_HEADER;
+
+#pragma pack()
+
+typedef struct _VARIABLE_INFO_ENTRY  VARIABLE_INFO_ENTRY;
+
+///
+/// This structure contains the variable list that is put in EFI system table.
+/// The variable driver collects all variables that were used at boot service time and produces this list.
+/// This is an optional feature to dump all used variables in shell environment.
+///
+struct _VARIABLE_INFO_ENTRY {
+  VARIABLE_INFO_ENTRY *Next;       ///< Pointer to next entry.
+  EFI_GUID            VendorGuid;  ///< Guid of Variable.
+  CHAR16              *Name;       ///< Name of Variable.
+  UINT32              Attributes;  ///< Attributes of variable defined in UEFI spec.
+  UINT32              ReadCount;   ///< Number of times to read this variable.
+  UINT32              WriteCount;  ///< Number of times to write this variable.
+  UINT32              DeleteCount; ///< Number of times to delete this variable.
+  UINT32              CacheCount;  ///< Number of times that cache hits this variable.
+  BOOLEAN             Volatile;    ///< TRUE if volatile, FALSE if non-volatile.
+};
+
+#endif // _EFI_VARIABLE_H_
diff --git a/Platform/Intel/Tools/FCE/Variable.c b/Platform/Intel/Tools/FCE/Variable.c
new file mode 100644
index 0000000000..5c92060309
--- /dev/null
+++ b/Platform/Intel/Tools/FCE/Variable.c
@@ -0,0 +1,1091 @@
+/** @file
+
+ Read and edit the EFI variable.
+
+ Copyright (c) 2011-2019, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "Fce.h"
+#include "Variable.h"
+
+extern LIST_ENTRY                  mAllVarListEntry;
+extern MULTI_PLATFORM_PARAMETERS   mMultiPlatformParam;
+extern G_EFI_FD_INFO               gEfiFdInfo;
+
+EFI_GUID  gEfiVariableGuid     = EFI_VARIABLE_GUID;
+/**
+
+  Gets the pointer to the first variable header in given variable store area.
+
+  @param VarStoreHeader  Pointer to the Variable Store Header.
+
+  @return Pointer to the first variable header.
+
+**/
+static
+VARIABLE_HEADER *
+GetStartPointer (
+  IN VARIABLE_STORE_HEADER       *VarStoreHeader
+  )
+{
+  //
+  // The end of variable store.
+  //
+  return (VARIABLE_HEADER *) HEADER_ALIGN (VarStoreHeader + 1);
+}
+
+/**
+
+  Gets the pointer to the end of the variable storage area.
+
+  This function gets pointer to the end of the variable storage
+  area, according to the input variable store header.
+
+  @param VarStoreHeader  Pointer to the Variable Store Header.
+
+  @return Pointer to the end of the variable storage area.
+
+**/
+static
+VARIABLE_HEADER *
+GetEndPointer (
+  IN VARIABLE_STORE_HEADER       *VarStoreHeader
+  )
+{
+  //
+  // The end of variable store
+  //
+  return (VARIABLE_HEADER *) HEADER_ALIGN ((UINTN) VarStoreHeader + VarStoreHeader->Size);
+}
+
+
+/**
+
+  This code checks if variable header is valid or not.
+
+  @param Variable        Pointer to the Variable Header.
+
+  @retval TRUE           Variable header is valid.
+  @retval FALSE          Variable header is not valid.
+
+**/
+static
+BOOLEAN
+IsValidVariableHeader (
+  IN  VARIABLE_HEADER   *Variable
+  )
+{
+  if ((Variable == NULL) || (Variable->StartId != VARIABLE_DATA)) {
+    return FALSE;
+  }
+
+  return TRUE;
+}
+
+/**
+
+  This code gets the size of name of variable.
+
+  @param Variable        Pointer to the Variable Header.
+
+  @return UINTN          Size of variable in bytes.
+
+**/
+static
+UINTN
+NameSizeOfVariable (
+  IN  VARIABLE_HEADER   *Variable
+  )
+{
+  if ((Variable->State    == (UINT8) (-1)) ||
+      (Variable->DataSize == (UINT32) (-1)) ||
+      (Variable->NameSize == (UINT32) (-1)) ||
+      (Variable->Attributes == (UINT32) (-1))
+      ) {
+    return 0;
+  }
+  return (UINTN) Variable->NameSize;
+}
+
+/**
+
+  This code gets the size of variable data.
+
+  @param Variable        Pointer to the Variable Header.
+
+  @return Size of variable in bytes.
+
+**/
+static
+UINTN
+DataSizeOfVariable (
+  IN  VARIABLE_HEADER   *Variable
+  )
+{
+  if ((Variable->State    == (UINT8)  (-1)) ||
+      (Variable->DataSize == (UINT32) (-1)) ||
+      (Variable->NameSize == (UINT32) (-1)) ||
+      (Variable->Attributes == (UINT32) (-1))
+      ) {
+    return 0;
+  }
+  return (UINTN) Variable->DataSize;
+}
+
+/**
+
+  This code gets the pointer to the variable name.
+
+  @param Variable        Pointer to the Variable Header.
+
+  @return Pointer to Variable Name which is Unicode encoding.
+
+**/
+static
+CHAR16 *
+GetVariableNamePtr (
+  IN  VARIABLE_HEADER   *Variable
+  )
+{
+
+  return (CHAR16 *) (Variable + 1);
+}
+
+/**
+
+  This code gets the pointer to the variable data.
+
+  @param Variable        Pointer to the Variable Header.
+
+  @return Pointer to Variable Data.
+
+**/
+static
+UINT8 *
+GetVariableDataPtr (
+  IN  VARIABLE_HEADER   *Variable
+  )
+{
+  UINTN Value;
+
+  //
+  // Be careful about pad size for alignment.
+  //
+  Value =  (UINTN) GetVariableNamePtr (Variable);
+  Value += NameSizeOfVariable (Variable);
+  Value += GET_PAD_SIZE (NameSizeOfVariable (Variable));
+
+  return (UINT8 *) Value;
+}
+
+/**
+
+  This code gets the pointer to the next variable header.
+
+  @param Variable        Pointer to the Variable Header.
+
+  @return Pointer to next variable header.
+
+**/
+static
+VARIABLE_HEADER *
+GetNextVariablePtr (
+  IN  VARIABLE_HEADER   *Variable
+  )
+{
+  UINTN Value;
+
+  if (!IsValidVariableHeader (Variable)) {
+    return NULL;
+  }
+
+  Value =  (UINTN) GetVariableDataPtr (Variable);
+  Value += DataSizeOfVariable (Variable);
+  Value += GET_PAD_SIZE (DataSizeOfVariable (Variable));
+
+  //
+  // Be careful about pad size for alignment.
+  //
+  return (VARIABLE_HEADER *) HEADER_ALIGN (Value);
+}
+
+/**
+  Search and get a free space in the EFI variable zone
+
+  @param VariableStoreHeader       The start of a EFI variable zone.
+  @param VarListSize               The size of a variables needs to be allocated.
+  @param FreeBeginVar              The dual pointer to the free NV space.
+
+  @retval EFI_SUCCESS              Return the beginning of a free variable space.
+  @retval RETURN_BUFFER_TOO_SMALL  Failed.
+**/
+static
+EFI_STATUS
+GetVariableVar (
+  IN      VARIABLE_STORE_HEADER  *VariableStoreHeader,
+  IN      UINT32                 VarListSize,
+  IN OUT  CHAR8                  **FreeBeginVar
+)
+{
+  BOOLEAN          Flag;
+  VARIABLE_HEADER  *Variable;
+  VARIABLE_HEADER  *EndOfVariable;
+  CHAR8            *BeginVar;
+
+  BeginVar      = NULL;
+  Flag          = FALSE;
+  Variable      = NULL;
+  EndOfVariable = NULL;
+  *FreeBeginVar = NULL;
+
+  if (VariableStoreHeader == NULL) {
+    *FreeBeginVar = NULL;
+    return RETURN_INVALID_PARAMETER;
+  }
+  Variable      = GetStartPointer (VariableStoreHeader);
+  EndOfVariable = GetEndPointer(VariableStoreHeader);
+  //
+  //Search the beginning of free NV
+  //
+  while (Variable != EndOfVariable) {
+    BeginVar = (CHAR8 *)Variable;
+    Variable = GetNextVariablePtr (Variable);
+    if (Variable == NULL) {
+      Flag = TRUE;
+      break;
+    }
+  }
+  //
+  // Check whether the free space is more than what we want
+  //
+  if ((CHAR8 *)BeginVar + VarListSize > (CHAR8 *)EndOfVariable) {
+    return RETURN_BUFFER_TOO_SMALL;
+  }
+  //
+  // If not find the available space, return NULL
+  //
+  if (!Flag) {
+    return RETURN_BUFFER_TOO_SMALL;
+  }
+  *FreeBeginVar = BeginVar;
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Search whether the variable in VarList has existed in current NV.
+
+  Parse the FFS or Fd image, and find the valid variable pointer.
+
+  @param VariableStoreHeader    The start of a EFI variable zone.
+  @param VarList                The pointer to the VarList
+
+  @retval address               If the variable existed in current NV, return address
+  @return NULL                  Otherwise, return NULL
+**/
+static
+VARIABLE_HEADER  *
+FindVariableInNv (
+  IN     VARIABLE_STORE_HEADER  *VariableStoreHeader,
+  IN     FORMSET_STORAGE        *Storage
+  )
+{
+  BOOLEAN          Flag;
+  VARIABLE_HEADER  *Variable;
+  VARIABLE_HEADER  *EndOfVariable;
+  CHAR16           *VariableName;
+
+  Flag            = FALSE;
+  Variable        = NULL;
+  EndOfVariable   = NULL;
+  VariableName    = NULL;
+
+  if ((VariableStoreHeader == NULL) || (Storage == NULL) || (Storage->Name == NULL)) {
+    return NULL;
+  }
+  Variable      = GetStartPointer (VariableStoreHeader);
+  EndOfVariable = GetEndPointer(VariableStoreHeader);
+  //
+  // Parse and compare the variable in the NV space one by one
+  //
+  while ((Variable != EndOfVariable) && (Variable != NULL)) {
+    VariableName = (CHAR16 *)((CHAR8 *)Variable + sizeof (VARIABLE_HEADER));
+    if (!CompareGuid (&Variable->VendorGuid, &Storage->Guid) \
+      && !FceStrCmp (Storage->Name, VariableName) \
+      && (Variable->State == VAR_ADDED)) {
+      Flag = TRUE;
+      break;
+    }
+    Variable = GetNextVariablePtr (Variable);
+  }
+  if (!Flag) {
+    return NULL;
+  }
+  return Variable;
+}
+/**
+  Exchange the data between Efi variable and the data of VarList when the
+  variable use the authenticated variable header
+
+  If VarToList is TRUE, copy the efi variable data to the VarList; Otherwise,
+  update the data from varlist to efi variable.
+
+  @param VarToList         The flag to control the direction of exchange.
+  @param StorageListHead   Decide which variale list be updated
+
+  @retval EFI_SUCCESS           Get the address successfully.
+  @retval EFI_OUT_OF_RESOURCES  No available in the EFI variable zone.
+**/
+
+EFI_STATUS
+SynEfiVariable (
+  IN  BOOLEAN     VarToList,
+  IN  LIST_ENTRY  *StorageListHead
+  )
+{
+  EFI_FIRMWARE_VOLUME_HEADER    *VarAddr;
+  LIST_ENTRY                    *StorageLink;
+  FORMSET_STORAGE               *Storage;
+  EFI_STATUS                    Status;
+  CHAR8                         *NewAvailableAddr;
+  CHAR8                         *DataBase;
+  VARIABLE_HEADER               *VariableHeader;
+  VARIABLE_STORE_HEADER         *VariableStoreHeader;
+  UINTN                         VarNameSize;
+
+  Status              = EFI_SUCCESS;
+  DataBase            = NULL;
+  NewAvailableAddr    = NULL;
+  VarNameSize         = 0;
+  VariableHeader      = NULL;
+  VarAddr             = (EFI_FIRMWARE_VOLUME_HEADER   *) gEfiFdInfo.EfiVariableAddr;
+  VariableStoreHeader = (VARIABLE_STORE_HEADER *)((CHAR8 *)VarAddr + VarAddr->HeaderLength);
+  //
+  //Parse the variable range, and check whether there is some existed ones.
+  //
+  StorageLink = GetFirstNode (StorageListHead);
+  while (!IsNull (StorageListHead, StorageLink)) {
+    Storage = FORMSET_STORAGE_FROM_LINK (StorageLink);
+     //
+     // Ignore the invalid varlist node
+     //
+     if (Storage->Buffer == NULL) {
+      StorageLink = GetNextNode (StorageListHead, StorageLink);
+      continue;
+     }
+     //
+     // Report error, if the variable name is invalid.
+     //
+     if ((Storage->Name == NULL) || (FceStrLen(Storage->Name) == 0)) {
+       printf ("Error. One variable name is NULL. Its GUID is: ");
+       PrintGuid(&(Storage->Guid));
+       return EFI_INVALID_PARAMETER;
+     }
+     VariableHeader = FindVariableInNv (
+                        VariableStoreHeader,
+                        Storage
+                        );
+
+    if (VarToList) {
+     //
+     //Copy the data from NV to the VarList.
+     //
+     if (VariableHeader != NULL) {
+       if (Storage->Buffer == NULL) {
+         Storage->Buffer = calloc (Storage->Size, sizeof (CHAR8));
+         ASSERT (Storage->Buffer != NULL);
+       }
+       DataBase    = (CHAR8*)GetVariableDataPtr (VariableHeader);
+       memcpy (
+         Storage->Buffer,
+         (VOID *) DataBase,
+         Storage->Size
+        );
+      }
+    } else {
+       //
+       //If existed, copy the List data to the variable in NV directly. If not found, create a new one.
+       //
+       VarNameSize = 2 * (FceStrLen (Storage->Name) + 1);
+       //
+       //If this variable has existed in current FD, the data in VarList has
+       // been updated, and this variable is not authenticated type, then
+       // update it from VarList to the FD.
+       //
+       if ((VariableHeader != NULL)    \
+         && (Storage->Buffer != NULL)
+         ) {
+           DataBase = (CHAR8*)GetVariableDataPtr (VariableHeader);
+           memcpy (
+             (VOID *) DataBase,
+             Storage->Buffer,
+             Storage->Size
+           );
+       } else if ((VariableHeader == NULL) && (Storage->Buffer != NULL)){
+         //
+         //If EfiVarstore is not EFI_VARIABLE_NON_VOLATILE, only skip it.
+         //
+         if (Storage->NewEfiVarstore
+           && ((Storage->Attributes & EFI_VARIABLE_NON_VOLATILE) == 0)
+         ) {
+          StorageLink = GetNextNode (StorageListHead, StorageLink);
+          continue;
+         }
+         //
+         // Try to get the available zone from the efi variables
+         //
+         Status = GetVariableVar (
+                    VariableStoreHeader,
+                    Storage->Size + sizeof (VARIABLE_HEADER),
+                    &NewAvailableAddr
+                    );
+
+         if (!EFI_ERROR (Status)) {
+           //
+           // Create the variable header
+           //
+           VariableHeader             = (VARIABLE_HEADER *) NewAvailableAddr;
+           VariableHeader->StartId    = VARIABLE_DATA;
+           VariableHeader->State      = VAR_ADDED;
+           VariableHeader->Reserved   = 0x0;
+           if (Storage->NewEfiVarstore) {
+             VariableHeader->Attributes = Storage->Attributes;
+           } else {
+             VariableHeader->Attributes = EFI_VARIABLE_NON_VOLATILE|EFI_VARIABLE_BOOTSERVICE_ACCESS|EFI_VARIABLE_RUNTIME_ACCESS;
+           }
+           VariableHeader->NameSize   = VarNameSize;
+           VariableHeader->DataSize   = Storage->Size;
+           //
+           //Copy the Guid, variable name, and data in sequence.
+           //
+           memcpy (
+             (VOID *)&(VariableHeader->VendorGuid),
+             &(Storage->Guid),
+             sizeof (EFI_GUID)
+             );
+           NewAvailableAddr = NewAvailableAddr + sizeof (VARIABLE_HEADER);
+           memcpy (
+             (VOID *) NewAvailableAddr,
+              Storage->Name,
+              VarNameSize
+              );
+
+           NewAvailableAddr = NewAvailableAddr + VarNameSize + GET_PAD_SIZE (VarNameSize);
+           memcpy (
+             (VOID *) NewAvailableAddr,
+             Storage->Buffer,
+             Storage->Size * sizeof (CHAR8)
+             );
+         } else {
+           printf ("Error. No available space in NV ram.\n");
+           return EFI_OUT_OF_RESOURCES;
+         }
+       }
+    }
+    StorageLink = GetNextNode (StorageListHead, StorageLink);
+  }
+  return Status;
+}
+
+/**
+  Remove the variable from Efi variable
+
+  Found the variable with the same name in StorageListHead and remove it.
+
+  @param StorageListHead   Decide which variale list be removed.
+
+  @retval EFI_SUCCESS      Remove the variables successfully.
+**/
+EFI_STATUS
+RemoveNormalEfiVariable (
+  IN  LIST_ENTRY  *StorageListHead
+  )
+{
+  EFI_FIRMWARE_VOLUME_HEADER    *VarAddr;
+  LIST_ENTRY                    *StorageLink;
+  FORMSET_STORAGE               *Storage;
+  VARIABLE_HEADER               *VariableHeader;
+  VARIABLE_STORE_HEADER         *VariableStoreHeader;
+
+  VariableHeader      = NULL;
+  VarAddr             = (EFI_FIRMWARE_VOLUME_HEADER   *) gEfiFdInfo.EfiVariableAddr;
+  VariableStoreHeader = (VARIABLE_STORE_HEADER *)((CHAR8 *)VarAddr + VarAddr->HeaderLength);
+  //
+  //Parse the variable range, and check whether there is some existed ones.
+  //
+  StorageLink = GetFirstNode (StorageListHead);
+  while (!IsNull (StorageListHead, StorageLink)) {
+    Storage = FORMSET_STORAGE_FROM_LINK (StorageLink);
+    //
+    // Ignore the invalid varlist node
+    //
+    if (Storage->Buffer == NULL) {
+      StorageLink = GetNextNode (StorageListHead, StorageLink);
+      continue;
+    }
+    //
+    // Report error, if the variable name is invalid.
+    //
+    if ((Storage->Name == NULL) || (FceStrLen(Storage->Name) == 0)) {
+      printf ("Error. One variable name is NULL. Its GUID is: ");
+      PrintGuid(&(Storage->Guid));
+      return EFI_INVALID_PARAMETER;
+    }
+    VariableHeader = FindVariableInNv (
+                       VariableStoreHeader,
+                       Storage
+                       );
+    if (VariableHeader != NULL) {
+      VariableHeader->State = VAR_DELETED;
+    }
+    StorageLink = GetNextNode (StorageListHead, StorageLink);
+  }
+  return EFI_SUCCESS;
+}
+
+/**
+  Check the store variable is no-authenticated or not
+
+  @param VarToList     The pointer to the header of Variable Store.
+
+  @retval TRUE         If no-authenticated, return TRUE.
+  @retval FALSE        Otherwise, return FALSE.
+**/
+
+BOOLEAN
+CheckNormalVarStoreOrNot (
+  IN VOID  *VariableStoreHeader
+  )
+{
+  if (!CompareGuid (
+    &gEfiVariableGuid,
+    &((VARIABLE_STORE_HEADER *)VariableStoreHeader)->Signature)
+    ) {
+    return TRUE;
+  } else {
+    return FALSE;
+  }
+}
+
+/**
+  Copy variable to binary in multi-platform mode
+
+  @param  Storage           The pointer to a storage in storage list.
+  @param  StorageBeginning  The pointer to the beginning of storage under specifed platformId and defaultId
+  @param  Index             The number of the storage. If the Index is 0, record the variable header to
+                            the binary. Or else, only record the storage.
+
+  @return length          The length of storage
+**/
+UINT32
+CopyVariableToBinary (
+  IN      FORMSET_STORAGE   *Storage,
+  IN OUT  UINT8             *StorageBeginning,
+  IN      UINT32            Index
+  )
+{
+  EFI_STATUS                    Status;
+  CHAR8                         *NewAvailableAddr;
+  VARIABLE_HEADER               *VariableHeader;
+  VARIABLE_STORE_HEADER         *VariableStoreHeader;
+  UINTN                         VarNameSize;
+  UINT32                        HeaderLength;
+
+  Status              = EFI_SUCCESS;
+  NewAvailableAddr    = NULL;
+  VarNameSize         = 0;
+  HeaderLength        = 0;
+  VariableHeader      = NULL;
+  VariableStoreHeader = NULL;
+
+  if ((Storage->Name == NULL) || (FceStrLen(Storage->Name) == 0)) {
+    printf ("Error. One variable name is NULL. Its GUID is: ");
+    PrintGuid(&(Storage->Guid));
+    return 0;
+  }
+  //
+  // If the first storage under one specified platformId and defaultId, create the variable header
+  //
+  if (Index == 0) {
+    HeaderLength = WriteDefaultAndPlatformId (StorageBeginning, Storage);
+    VariableStoreHeader = (VARIABLE_STORE_HEADER *) (StorageBeginning + HeaderLength);
+    //
+    //Create the Variable Storage header
+    //
+    memcpy (&(VariableStoreHeader->Signature), &gEfiVariableGuid, sizeof (EFI_GUID));
+    VariableStoreHeader->Format = 0x5A;
+    VariableStoreHeader->State  = 0xFE;
+    //
+    //Assign a big size here. It will be fixed after the storage under a specifed platformId and defaultId are all written.
+    //
+    VariableStoreHeader->Size   = gEfiFdInfo.FdSize;
+  }
+
+  VariableStoreHeader = (VARIABLE_STORE_HEADER *) (StorageBeginning + *(UINT16 *)StorageBeginning);
+
+  Status = GetVariableVar (
+             VariableStoreHeader,
+             Storage->Size + sizeof (VARIABLE_HEADER),
+             &NewAvailableAddr
+           );
+  if (EFI_ERROR (Status)) {
+    return FAIL;
+  }
+  //
+  // Create the variable header
+  //
+  VarNameSize                = 2 * (FceStrLen (Storage->Name) + 1);
+  VariableHeader             = (VARIABLE_HEADER *) NewAvailableAddr;
+  VariableHeader->StartId    = VARIABLE_DATA;
+  VariableHeader->State      = VAR_ADDED;
+  VariableHeader->Reserved   = 0x0;
+  if (Storage->NewEfiVarstore) {
+    VariableHeader->Attributes = Storage->Attributes;
+  } else {
+    VariableHeader->Attributes = EFI_VARIABLE_NON_VOLATILE|EFI_VARIABLE_BOOTSERVICE_ACCESS|EFI_VARIABLE_RUNTIME_ACCESS;
+  }
+  VariableHeader->NameSize   = VarNameSize;
+  VariableHeader->DataSize   = Storage->Size;
+  //
+  //Copy the Guid, variable name, and data in sequence.
+  //
+  memcpy (
+    (VOID *)&(VariableHeader->VendorGuid),
+    &(Storage->Guid),
+    sizeof (EFI_GUID)
+  );
+  NewAvailableAddr = NewAvailableAddr + sizeof (VARIABLE_HEADER);
+  memcpy (
+    (VOID *) NewAvailableAddr,
+    Storage->Name,
+    VarNameSize
+  );
+
+  NewAvailableAddr = NewAvailableAddr + VarNameSize + GET_PAD_SIZE (VarNameSize);
+  memcpy (
+    (VOID *) NewAvailableAddr,
+    Storage->Buffer,
+    Storage->Size * sizeof (CHAR8)
+  );
+  //
+  // Return the length which is from the beginning of Binary
+  //
+  return ((UINT32) ((UINT8*)NewAvailableAddr - StorageBeginning) + Storage->Size);
+}
+/**
+  Copy variable to binary in multi-platform mode
+
+  @param  Storage           The pointer to a storage in storage list.
+  @param  StorageBeginning  The pointer to the beginning of storage under specifed platformId and defaultId
+  @param  Index             The number of the storage. If the Index is 0, record the variable header to
+                            the binary. Or else, only record the storage.
+
+  @return length          The length of storage
+**/
+UINT32
+CopyVariableToNvStoreBinary (
+  IN      FORMSET_STORAGE   *Storage,
+  IN OUT  UINT8             *StorageBeginning,
+  IN      UINT32            Index
+  )
+{
+  EFI_STATUS                    Status;
+  CHAR8                         *NewAvailableAddr;
+  VARIABLE_HEADER               *VariableHeader;
+  VARIABLE_STORE_HEADER         *VariableStoreHeader;
+  UINTN                         VarNameSize;
+  UINT32                        HeaderLength;
+  PCD_DEFAULT_DATA              *PcdDefaultDataHeader;
+
+  Status              = EFI_SUCCESS;
+  NewAvailableAddr    = NULL;
+  VarNameSize         = 0;
+  HeaderLength        = 0;
+  VariableHeader      = NULL;
+  VariableStoreHeader = NULL;
+
+  if ((Storage->Name == NULL) || (FceStrLen(Storage->Name) == 0)) {
+    printf ("Error. One variable name is NULL. Its GUID is: ");
+    PrintGuid(&(Storage->Guid));
+    return 0;
+  }
+  //
+  // If the first storage under one specified platformId and defaultId, create the variable header
+  //
+  if (Index == 0) {
+    HeaderLength = WriteNvStoreDefaultAndPlatformId (StorageBeginning, Storage);
+    PcdDefaultDataHeader = (PCD_DEFAULT_DATA *)StorageBeginning;
+    PcdDefaultDataHeader->HeaderSize = HeaderLength;
+    VariableStoreHeader = (VARIABLE_STORE_HEADER *) (StorageBeginning + HeaderLength + 4);
+    //
+    //Create the Variable Storage header
+    //
+    memcpy (&(VariableStoreHeader->Signature), &gEfiVariableGuid, sizeof (EFI_GUID));
+    VariableStoreHeader->Format = 0x5A;
+    VariableStoreHeader->State  = 0xFE;
+    //
+    //Assign a big size here. It will be fixed after the storage under a specifed platformId and defaultId are all written.
+    //
+    VariableStoreHeader->Size   = gEfiFdInfo.FdSize;
+  }
+  PcdDefaultDataHeader = (PCD_DEFAULT_DATA *)StorageBeginning;
+  VariableStoreHeader = (VARIABLE_STORE_HEADER *) (StorageBeginning + PcdDefaultDataHeader->HeaderSize + 4);
+  Status = GetVariableVar (
+             VariableStoreHeader,
+             Storage->Size + sizeof (VARIABLE_HEADER),
+             &NewAvailableAddr
+           );
+  if (EFI_ERROR (Status)) {
+    return FAIL;
+  }
+  //
+  // Create the variable header
+  //
+  VarNameSize                = 2 * (FceStrLen (Storage->Name) + 1);
+  VariableHeader             = (VARIABLE_HEADER *) NewAvailableAddr;
+  VariableHeader->StartId    = VARIABLE_DATA;
+  VariableHeader->State      = VAR_ADDED;
+  VariableHeader->Reserved   = 0x0;
+  if (Storage->NewEfiVarstore) {
+    VariableHeader->Attributes = Storage->Attributes;
+  } else {
+    VariableHeader->Attributes = EFI_VARIABLE_NON_VOLATILE|EFI_VARIABLE_BOOTSERVICE_ACCESS|EFI_VARIABLE_RUNTIME_ACCESS;
+  }
+  VariableHeader->NameSize   = VarNameSize;
+  VariableHeader->DataSize   = Storage->Size;
+  //
+  //Copy the Guid, variable name, and data in sequence.
+  //
+  memcpy (
+    (VOID *)&(VariableHeader->VendorGuid),
+    &(Storage->Guid),
+    sizeof (EFI_GUID)
+  );
+
+  NewAvailableAddr = NewAvailableAddr + sizeof (VARIABLE_HEADER);
+  memcpy (
+    (VOID *) NewAvailableAddr,
+    Storage->Name,
+    VarNameSize
+  );
+
+  NewAvailableAddr = NewAvailableAddr + VarNameSize + GET_PAD_SIZE (VarNameSize);
+  memcpy (
+    (VOID *) NewAvailableAddr,
+    Storage->Buffer,
+    Storage->Size * sizeof (CHAR8)
+  );
+  //
+  // Return the length which is from the beginning of Binary
+  //
+  return ((UINT32) ((UINT8*)NewAvailableAddr - StorageBeginning - PcdDefaultDataHeader->HeaderSize - 4) + Storage->Size);
+}
+/**
+  Read variable to storage list in multi-platform mode
+
+  @param  Binary            The pointer to the header of storage under specifed platformId and defaultId
+  @param  StorageListEntry  The pointer to the storage list.
+
+  @return length          The length of storage
+**/
+UINT32
+ReadNvStoreVariableToList (
+  IN      UINT8             *Binary,
+  IN      LIST_ENTRY        *StorageListEntry
+  )
+{
+  VARIABLE_HEADER               *EndOfVariable;
+  VARIABLE_HEADER               *Variable;
+  VARIABLE_STORE_HEADER         *VariableStoreHeader;
+  FORMSET_STORAGE               *Storage;
+  UINT32                        Length;
+  PCD_DEFAULT_DATA             *PcdDefaultData;
+  UINT8                         *DataBase;
+  static UINT16                 PreDefaultId;
+  static UINT64                 PrePlatformId;
+
+  VariableStoreHeader = NULL;
+  Variable            = NULL;
+  Length              = 0;
+  DataBase            = Binary;
+
+  PcdDefaultData      = (PCD_DEFAULT_DATA *)DataBase;
+  PrePlatformId       = PcdDefaultData->DefaultInfo[0].SkuId;
+  PreDefaultId        = PcdDefaultData->DefaultInfo[0].DefaultId;
+  VariableStoreHeader = (VARIABLE_STORE_HEADER *) (DataBase + PcdDefaultData->HeaderSize + 4);
+  EndOfVariable       = GetEndPointer(VariableStoreHeader);
+
+  for (Variable = GetStartPointer (VariableStoreHeader);
+    Length < VariableStoreHeader->Size;
+    Length += sizeof (VARIABLE_HEADER) + Variable->NameSize + Variable->DataSize
+  ) {
+    //
+    // Create the storage
+    //
+    Storage = NULL;
+    Storage = calloc (sizeof (FORMSET_STORAGE), sizeof (CHAR8));
+    if (Storage == NULL) {
+      printf ("Allocate memory failed.\n");
+      return FAIL;
+    }
+    //
+    // Store the DefaultId and PlatformId collected from the header to Storage.
+    //
+    Storage->DefaultId[0] = PreDefaultId;
+    Storage->PlatformId[0] = PrePlatformId;
+    Storage->DefaultPlatformIdNum = 0;
+
+    Storage->Attributes     = Variable->Attributes;
+    Storage->Size           = (UINT16)Variable->DataSize;
+    Storage->Name           = calloc (Variable->NameSize, sizeof (UINT8));
+    ASSERT (Storage->Name != NULL);
+    Storage->Buffer         = calloc (Variable->DataSize, sizeof (UINT8));
+    ASSERT (Storage->Buffer != NULL);
+    memcpy (
+      &(Storage->Guid),
+      &(Variable->VendorGuid),
+      sizeof (EFI_GUID)
+    );
+    memcpy (
+      Storage->Name,
+      (UINT8 *)Variable + sizeof (VARIABLE_HEADER),
+      Variable->NameSize
+    );
+    memcpy (
+      Storage->Buffer,
+      (UINT8 *)Variable + sizeof (VARIABLE_HEADER) + Variable->NameSize + GET_PAD_SIZE (Variable->NameSize),
+      Storage->Size * sizeof (CHAR8)
+    );
+    //
+    // Assigned the value for comparison in verify mode
+    //
+    Storage->Type           = EFI_IFR_VARSTORE_EFI_OP;
+    Storage->NewEfiVarstore = TRUE;
+    InitializeListHead (&Storage->NameValueListHead);
+
+    InsertTailList(StorageListEntry, &Storage->Link);
+    //
+    // If the last variable, exit.
+    //
+    if (Variable == EndOfVariable) {
+      break;
+    }
+
+    Variable = GetNextVariablePtr (Variable);
+    assert (Variable != NULL);
+    if (!IsValidVariableHeader(Variable)) {
+      break;
+    }
+  }
+
+  return Length;
+}
+/**
+  Read variable to storage list in multi-platform mode
+
+  @param  Binary            The pointer to the header of storage under specifed platformId and defaultId
+  @param  StorageListEntry  The pointer to the storage list.
+
+  @return length          The length of storage
+**/
+UINT32
+ReadVariableToList (
+  IN      UINT8             *Binary,
+  IN      LIST_ENTRY        *StorageListEntry
+  )
+{
+  VARIABLE_HEADER               *EndOfVariable;
+  VARIABLE_HEADER               *Variable;
+  VARIABLE_STORE_HEADER         *VariableStoreHeader;
+  FORMSET_STORAGE               *Storage;
+  BOOLEAN                       ReadIdHeaderFlag;
+  UINT32                        Length;
+  EFI_COMMON_SECTION_HEADER     *SectionHeader;
+  UINT8                         *DataBase;
+  static UINT16                 PreDefaultId[MAX_PLATFORM_DEFAULT_ID_NUM];
+  static UINT64                 PrePlatformId[MAX_PLATFORM_DEFAULT_ID_NUM];
+
+  VariableStoreHeader = NULL;
+  Variable            = NULL;
+  ReadIdHeaderFlag    = TRUE;
+  Length              = 0;
+  SectionHeader       = (EFI_COMMON_SECTION_HEADER *)Binary;
+  DataBase            = Binary + sizeof (EFI_COMMON_SECTION_HEADER);
+  VariableStoreHeader = (VARIABLE_STORE_HEADER *) (DataBase + *(UINT16 *)DataBase);
+  EndOfVariable       = GetEndPointer(VariableStoreHeader);
+
+  for (Variable = GetStartPointer (VariableStoreHeader);
+    Length < VariableStoreHeader->Size;
+    Length += sizeof (VARIABLE_HEADER) + Variable->NameSize + Variable->DataSize
+  ) {
+    //
+    // Create the storage
+    //
+    Storage = NULL;
+    Storage = calloc (sizeof (FORMSET_STORAGE), sizeof (CHAR8));
+    if (Storage == NULL) {
+      printf ("Allocate memory failed.\n");
+      return FAIL;
+    }
+    //
+    // If access the first storage, read the platformId and defaultId
+    //
+    if (ReadIdHeaderFlag) {
+      ReadDefaultAndPlatformIdFromBfv (DataBase, Storage);
+      Length += sizeof (VARIABLE_HEADER) + Variable->NameSize + Variable->DataSize;
+      ReadIdHeaderFlag = FALSE;
+      memcpy (PreDefaultId, Storage->DefaultId, MAX_PLATFORM_DEFAULT_ID_NUM * sizeof (UINT16));
+      memcpy (PrePlatformId, Storage->PlatformId, MAX_PLATFORM_DEFAULT_ID_NUM * sizeof (UINT64));
+    } else {
+      //
+      // Store the DefaultId and PlatformId collected from the header to Storage.
+      //
+      memcpy (Storage->DefaultId, PreDefaultId, MAX_PLATFORM_DEFAULT_ID_NUM * sizeof (UINT16));
+      memcpy (Storage->PlatformId, PrePlatformId, MAX_PLATFORM_DEFAULT_ID_NUM * sizeof (UINT64));
+    }
+    Storage->Attributes     = Variable->Attributes;
+    Storage->Size           = (UINT16)Variable->DataSize;
+    Storage->Name           = calloc (Variable->NameSize, sizeof (UINT8));
+    ASSERT (Storage->Name != NULL);
+    Storage->Buffer         = calloc (Variable->DataSize, sizeof (UINT8));
+    ASSERT (Storage->Buffer != NULL);
+    memcpy (
+      &(Storage->Guid),
+      &(Variable->VendorGuid),
+      sizeof (EFI_GUID)
+    );
+    memcpy (
+      Storage->Name,
+      (UINT8 *)Variable + sizeof (VARIABLE_HEADER),
+      Variable->NameSize
+    );
+    memcpy (
+      Storage->Buffer,
+      (UINT8 *)Variable + sizeof (VARIABLE_HEADER) + Variable->NameSize + GET_PAD_SIZE (Variable->NameSize),
+      Storage->Size * sizeof (CHAR8)
+    );
+    //
+    // Assigned the value for comparison in verify mode
+    //
+    Storage->Type           = EFI_IFR_VARSTORE_EFI_OP;
+    Storage->NewEfiVarstore = TRUE;
+    InitializeListHead (&Storage->NameValueListHead);
+
+    InsertTailList(StorageListEntry, &Storage->Link);
+    //
+    // If the last variable, exit.
+    //
+    if (Variable == EndOfVariable) {
+      break;
+    }
+
+    Variable = GetNextVariablePtr (Variable);
+    assert (Variable != NULL);
+  }
+  //
+  // Return the length which is from the beginning of Binary
+  //
+  Length = FvBufExpand3ByteSize (SectionHeader->Size);
+
+  return Length;
+}
+
+/**
+  Check whether exists the valid normal variables in NvStorage or not.
+
+  @retval TRUE      If existed, return TRUE.
+  @retval FALSE     Others
+**/
+BOOLEAN
+ExistNormalEfiVarOrNot (
+  IN  LIST_ENTRY  *StorageListHead
+  )
+{
+  EFI_FIRMWARE_VOLUME_HEADER    *VarAddr;
+  LIST_ENTRY                    *StorageLink;
+  FORMSET_STORAGE               *Storage;
+  VARIABLE_HEADER               *VariableHeader;
+  VARIABLE_STORE_HEADER         *VariableStoreHeader;
+
+  VariableHeader      = NULL;
+  VarAddr             = (EFI_FIRMWARE_VOLUME_HEADER   *) gEfiFdInfo.EfiVariableAddr;
+  VariableStoreHeader = (VARIABLE_STORE_HEADER *)((CHAR8 *)VarAddr + VarAddr->HeaderLength);
+  //
+  //Parse the variable range, and check whether there is some existed ones.
+  //
+  StorageLink = GetFirstNode (StorageListHead);
+  while (!IsNull (StorageListHead, StorageLink)) {
+    Storage = FORMSET_STORAGE_FROM_LINK (StorageLink);
+    //
+    // Ignore the invalid varlist node
+    //
+    if ((Storage->Buffer == NULL)
+      || (Storage->Name == NULL)
+      || (FceStrLen(Storage->Name) == 0)
+      ) {
+     StorageLink = GetNextNode (StorageListHead, StorageLink);
+     continue;
+    }
+    //
+    // Report error, if the variable name is invalid.
+    //
+    if ((Storage->Name == NULL) || (FceStrLen(Storage->Name) == 0)) {
+      StorageLink = GetNextNode (StorageListHead, StorageLink);
+     continue;
+    }
+    VariableHeader = FindVariableInNv (
+                       VariableStoreHeader,
+                       Storage
+                     );
+
+    if ((VariableHeader != NULL)) {
+       return TRUE;
+    }
+    StorageLink = GetNextNode (StorageListHead, StorageLink);
+  }
+  return FALSE;
+}
+
+/**
+  Fix the size of variable header.
+
+  @param  Binary            The pointer to the header of storage under specifed platformId and defaultId
+  @param  Length            The length of binary.
+
+**/
+VOID
+FixVariableHeaderSize (
+  IN  UINT8   *BinaryBeginning,
+  IN  UINT32  Length
+  )
+{
+  VARIABLE_STORE_HEADER         *VariableStoreHeader;
+
+  VariableStoreHeader       = (VARIABLE_STORE_HEADER *) (BinaryBeginning + *(UINT16 *)BinaryBeginning);
+  VariableStoreHeader->Size =  Length -  *(UINT16 *)BinaryBeginning;
+}
+
+/**
+  Fix the size of variable header.
+
+  @param  Binary            The pointer to the header of storage under specifed platformId and defaultId
+  @param  Length            The length of binary.
+
+**/
+VOID
+FixNvStoreVariableHeaderSize (
+  IN  UINT8   *BinaryBeginning,
+  IN  UINT32  Length
+  )
+{
+  VARIABLE_STORE_HEADER         *VariableStoreHeader;
+  PCD_DEFAULT_DATA              *PcdDefaultDataHeader;
+
+  PcdDefaultDataHeader      = (PCD_DEFAULT_DATA *)(BinaryBeginning);
+  VariableStoreHeader       = (VARIABLE_STORE_HEADER *) (BinaryBeginning + PcdDefaultDataHeader->HeaderSize + 4);
+  VariableStoreHeader->Size = Length;
+  PcdDefaultDataHeader->DataSize = VariableStoreHeader->Size + PcdDefaultDataHeader->HeaderSize + 4;
+}
+
diff --git a/Platform/Intel/Tools/FCE/Variable.h b/Platform/Intel/Tools/FCE/Variable.h
new file mode 100644
index 0000000000..35b88e045c
--- /dev/null
+++ b/Platform/Intel/Tools/FCE/Variable.h
@@ -0,0 +1,154 @@
+/** @file
+
+ The header of Variable.c.
+
+ Copyright (c) 2011-2019, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __VARIABLE_FORMAT_H__
+#define __VARIABLE_FORMAT_H__
+
+#define EFI_VARIABLE_GUID \
+  { 0xddcf3616, 0x3275, 0x4164, { 0x98, 0xb6, 0xfe, 0x85, 0x70, 0x7f, 0xfe, 0x7d } }
+
+extern EFI_GUID gEfiVariableGuid;
+
+///
+/// Alignment of variable name and data, according to the architecture:
+/// * For IA-32 and Intel(R) 64 architectures: 1.
+/// * For IA-64 architecture: 8.
+///
+#if defined (MDE_CPU_IPF)
+#define ALIGNMENT         8
+#else
+#define ALIGNMENT         1
+#endif
+
+///
+/// GET_PAD_SIZE calculates the miminal pad bytes needed to make the current pad size satisfy the alignment requirement.
+///
+#if (ALIGNMENT == 1)
+#define GET_PAD_SIZE(a) (0)
+#else
+#define GET_PAD_SIZE(a) (((~a) + 1) & (ALIGNMENT - 1))
+#endif
+
+///
+/// Alignment of Variable Data Header in Variable Store region.
+///
+#define HEADER_ALIGNMENT  4
+#define HEADER_ALIGN(Header)  (((UINTN) (Header) + HEADER_ALIGNMENT - 1) & (~(HEADER_ALIGNMENT - 1)))
+
+///
+/// Status of Variable Store Region.
+///
+typedef enum {
+  EfiRaw,
+  EfiValid,
+  EfiInvalid,
+  EfiUnknown
+} VARIABLE_STORE_STATUS;
+
+#pragma pack(1)
+
+#define VARIABLE_STORE_SIGNATURE  EFI_VARIABLE_GUID
+
+///
+/// Variable Store Header Format and State.
+///
+#define VARIABLE_STORE_FORMATTED          0x5a
+#define VARIABLE_STORE_HEALTHY            0xfe
+
+///
+/// Variable Store region header.
+///
+typedef struct {
+  ///
+  /// Variable store region signature.
+  ///
+  EFI_GUID  Signature;
+  ///
+  /// Size of entire variable store,
+  /// including size of variable store header but not including the size of FvHeader.
+  ///
+  UINT32  Size;
+  ///
+  /// Variable region format state.
+  ///
+  UINT8   Format;
+  ///
+  /// Variable region healthy state.
+  ///
+  UINT8   State;
+  UINT16  Reserved;
+  UINT32  Reserved1;
+} VARIABLE_STORE_HEADER;
+
+///
+/// Variable data start flag.
+///
+#define VARIABLE_DATA                     0x55AA
+
+///
+/// Variable State flags.
+///
+#define VAR_IN_DELETED_TRANSITION     0xfe  ///< Variable is in obsolete transition.
+#define VAR_DELETED                   0xfd  ///< Variable is obsolete.
+#define VAR_HEADER_VALID_ONLY         0x7f  ///< Variable header has been valid.
+#define VAR_ADDED                     0x3f  ///< Variable has been completely added.
+
+///
+/// Single Variable Data Header Structure.
+///
+typedef struct {
+  ///
+  /// Variable Data Start Flag.
+  ///
+  UINT16      StartId;
+  ///
+  /// Variable State defined above.
+  ///
+  UINT8       State;
+  UINT8       Reserved;
+  ///
+  /// Attributes of variable defined in UEFI specification.
+  ///
+  UINT32      Attributes;
+  ///
+  /// Size of variable null-terminated Unicode string name.
+  ///
+  UINT32      NameSize;
+  ///
+  /// Size of the variable data without this header.
+  ///
+  UINT32      DataSize;
+  ///
+  /// A unique identifier for the vendor that produces and consumes this varaible.
+  ///
+  EFI_GUID    VendorGuid;
+} VARIABLE_HEADER;
+
+#pragma pack()
+
+typedef struct _VARIABLE_INFO_ENTRY  VARIABLE_INFO_ENTRY;
+
+///
+/// This structure contains the variable list that is put in EFI system table.
+/// The variable driver collects all variables that were used at boot service time and produces this list.
+/// This is an optional feature to dump all used variables in shell environment.
+///
+struct _VARIABLE_INFO_ENTRY {
+  VARIABLE_INFO_ENTRY *Next;       ///< Pointer to next entry.
+  EFI_GUID            VendorGuid;  ///< Guid of Variable.
+  CHAR16              *Name;       ///< Name of Variable.
+  UINT32              Attributes;  ///< Attributes of variable defined in UEFI specification.
+  UINT32              ReadCount;   ///< Number of times to read this variable.
+  UINT32              WriteCount;  ///< Number of times to write this variable.
+  UINT32              DeleteCount; ///< Number of times to delete this variable.
+  UINT32              CacheCount;  ///< Number of times that cache hits this variable.
+  BOOLEAN             Volatile;    ///< TRUE if volatile, FALSE if non-volatile.
+};
+
+#endif // _EFI_VARIABLE_H_
diff --git a/Platform/Intel/Tools/FCE/VariableCommon.h b/Platform/Intel/Tools/FCE/VariableCommon.h
new file mode 100644
index 0000000000..7389902076
--- /dev/null
+++ b/Platform/Intel/Tools/FCE/VariableCommon.h
@@ -0,0 +1,55 @@
+/** @file
+
+ The header of common Variable.c TimeBasedVariable.c and MonotonicBasedVariable.c.
+
+ Copyright (c) 2011-2019, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __VARIABLE_COMMON_H__
+#define __VARIABLE_COMMON_H__
+
+/**
+  Check the store variable is no-authenticated or not
+
+  @param VarToList     The pointer to the header of Variable Store.
+
+  @retval TRUE         If no-authenticated, return TRUE.
+  @retval FALSE        Otherwise, return FALSE.
+**/
+
+BOOLEAN
+CheckNormalVarStoreOrNot (
+  IN VOID  *VariableStoreHeader
+  );
+/**
+  Check the store variable is Monotonic based authenticated or not
+
+  @param VarToList     The pointer to the header of Variable Store.
+
+  @retval TRUE         If authenticated, return TRUE.
+  @retval FALSE        Otherwise, return FALSE.
+**/
+
+BOOLEAN
+CheckMonotonicBasedVarStore (
+  IN VOID  *VariableStoreHeader
+  );
+
+/**
+  Check the store variable is Time stamp authenticated or not
+
+  @param VarToList     The pointer to the header of Variable Store.
+
+  @retval TRUE         If authenticated, return TRUE.
+  @retval FALSE        Otherwise, return FALSE.
+**/
+BOOLEAN
+CheckTimeBasedVarStoreOrNot (
+  IN VOID  *VariableStoreHeader
+  );
+
+
+
+#endif // _EFI_VARIABLE_COMMON_H_
-- 
2.18.0.windows.1


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [edk2-platform patch 4/6] Platform\Tools: Add top level Makefile and GNUMakefile
  2019-06-21  1:26 [edk2-platform patch 0/6] Add tools FMMT FCE and FitGen Zhang, Shenglei
                   ` (2 preceding siblings ...)
  2019-06-21  1:26 ` [edk2-platform patch 3/6] BaseTools\FCE: Add a tool FCE Zhang, Shenglei
@ 2019-06-21  1:26 ` Zhang, Shenglei
  2019-06-21  1:26 ` [edk2-platform patch 5/6] Silicon\Tools: Add a tool FitGen Zhang, Shenglei
                   ` (2 subsequent siblings)
  6 siblings, 0 replies; 15+ messages in thread
From: Zhang, Shenglei @ 2019-06-21  1:26 UTC (permalink / raw)
  To: devel; +Cc: Bob Feng, Liming Gao

Add FMMT, BfmLib and FCE into Makefile and GNUMakefile.

Cc: Bob Feng <bob.c.feng@intel.com>
Cc: Liming Gao <liming.gao@intel.com>
Signed-off-by: Shenglei Zhang <shenglei.zhang@intel.com>
---
 Platform/Intel/Tools/GNUmakefile | 30 +++++++++++++++++++++++++++++
 Platform/Intel/Tools/Makefile    | 33 ++++++++++++++++++++++++++++++++
 2 files changed, 63 insertions(+)
 create mode 100644 Platform/Intel/Tools/GNUmakefile
 create mode 100644 Platform/Intel/Tools/Makefile

diff --git a/Platform/Intel/Tools/GNUmakefile b/Platform/Intel/Tools/GNUmakefile
new file mode 100644
index 0000000000..195b72d9af
--- /dev/null
+++ b/Platform/Intel/Tools/GNUmakefile
@@ -0,0 +1,30 @@
+##@file
+# GNUmakefile for building C utilities.
+#
+# Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+MAKEROOT = $(EDK_TOOLS_PATH)/Source/C
+
+APPLICATIONS = \
+  BfmLib \
+  FCE \
+  FMMT \
+
+SUBDIRS := $(APPLICATIONS)
+
+$(APPLICATIONS): $(MAKEROOT)/bin
+
+.PHONY: subdirs $(SUBDIRS)
+subdirs: $(SUBDIRS)
+$(SUBDIRS):
+    $(MAKE) -C $@
+
+.PHONY: $(patsubst %,%-clean,$(sort $(SUBDIRS)))
+$(patsubst %,%-clean,$(sort $(SUBDIRS))):
+    -$(MAKE) -C $(@:-clean=) clean
+
+clean: $(patsubst %,%-clean,$(sort $(SUBDIRS)))
+
diff --git a/Platform/Intel/Tools/Makefile b/Platform/Intel/Tools/Makefile
new file mode 100644
index 0000000000..3472b0e6f0
--- /dev/null
+++ b/Platform/Intel/Tools/Makefile
@@ -0,0 +1,33 @@
+##@file
+# makefile for building C utilities.
+#
+# Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+!INCLUDE $(EDK_TOOLS_PATH)\Source\C\Makefiles\ms.common
+
+APPLICATIONS = \
+  BfmLib \
+  FCE\
+  FMMT\
+
+all: $(APPLICATIONS)
+    @echo.
+    @echo ######################
+    @echo # Build executables
+    @echo ######################
+    @if not exist $(BIN_PATH) mkdir $(BIN_PATH)
+    @$(EDK_TOOLS_PATH)\Source\C\Makefiles\NmakeSubdirs.bat all $**
+
+.PHONY: clean
+clean: $(APPLICATIONS)
+  @$(EDK_TOOLS_PATH)\Source\C\Makefiles\NmakeSubdirs.bat clean $**
+
+.PHONY: cleanall
+cleanall: $(APPLICATIONS)
+  @$(EDK_TOOLS_PATH)\Source\C\Makefiles\NmakeSubdirs.bat cleanall $**
+
+!INCLUDE $(EDK_TOOLS_PATH)\Source\C\Makefiles\ms.rule
+
-- 
2.18.0.windows.1


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [edk2-platform patch 5/6] Silicon\Tools: Add a tool FitGen
  2019-06-21  1:26 [edk2-platform patch 0/6] Add tools FMMT FCE and FitGen Zhang, Shenglei
                   ` (3 preceding siblings ...)
  2019-06-21  1:26 ` [edk2-platform patch 4/6] Platform\Tools: Add top level Makefile and GNUMakefile Zhang, Shenglei
@ 2019-06-21  1:26 ` Zhang, Shenglei
  2019-06-26  2:03   ` [edk2-devel] " Liming Gao
  2019-06-21  1:26 ` [edk2-platform patch 6/6] Silicon\Tools: Add top level Makefile and GNUMakefile Zhang, Shenglei
  2019-06-21  2:25 ` [edk2-devel] [edk2-platform patch 0/6] Add tools FMMT FCE and FitGen Yao, Jiewen
  6 siblings, 1 reply; 15+ messages in thread
From: Zhang, Shenglei @ 2019-06-21  1:26 UTC (permalink / raw)
  To: devel; +Cc: Bob Feng, Liming Gao

The utility of this tool is part of build process for IA32/X64 FD.
It generates FIT table.
https://bugzilla.tianocore.org/show_bug.cgi?id=1849

Cc: Bob Feng <bob.c.feng@intel.com>
Cc: Liming Gao <liming.gao@intel.com>
Signed-off-by: Shenglei Zhang <shenglei.zhang@intel.com>
---
 Silicon/Intel/Tools/FitGen/FitGen.c    | 3137 ++++++++++++++++++++++++
 Silicon/Intel/Tools/FitGen/FitGen.h    |   48 +
 Silicon/Intel/Tools/FitGen/GNUmakefile |   16 +
 Silicon/Intel/Tools/FitGen/Makefile    |   17 +
 4 files changed, 3218 insertions(+)
 create mode 100644 Silicon/Intel/Tools/FitGen/FitGen.c
 create mode 100644 Silicon/Intel/Tools/FitGen/FitGen.h
 create mode 100644 Silicon/Intel/Tools/FitGen/GNUmakefile
 create mode 100644 Silicon/Intel/Tools/FitGen/Makefile

diff --git a/Silicon/Intel/Tools/FitGen/FitGen.c b/Silicon/Intel/Tools/FitGen/FitGen.c
new file mode 100644
index 0000000000..faf9880060
--- /dev/null
+++ b/Silicon/Intel/Tools/FitGen/FitGen.c
@@ -0,0 +1,3137 @@
+/**@file
+This utility is part of build process for IA32/X64 FD.
+It generates FIT table.
+
+Copyright (c) 2010-2019, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "FitGen.h"
+
+//
+// FIT spec
+//
+#pragma pack (1)
+typedef struct {
+  UINT64     Address;
+  UINT8      Size[3];
+  UINT8      Rsvd;
+  UINT16     Version;
+  UINT8      Type:7;
+  UINT8      C_V:1;
+  UINT8      Checksum;
+} FIRMWARE_INTERFACE_TABLE_ENTRY;
+
+//
+// Struct for policy
+//
+typedef struct {
+  UINT16     IndexPort;
+  UINT16     DataPort;
+  UINT8      Width;
+  UINT8      Bit;
+  UINT16     Index;
+  UINT8      Size[3];
+  UINT8      Rsvd;
+  UINT16     Version; // == 0
+  UINT8      Type:7;
+  UINT8      C_V:1;
+  UINT8      Checksum;
+} FIRMWARE_INTERFACE_TABLE_ENTRY_PORT;
+
+#define FIT_ALIGNMENT          0x3F // 0xF is required previously, but if we need exclude FIT, we must set 64 bytes alignment.
+#define BIOS_MODULE_ALIGNMENT  0x3F  // 64 bytes for AnC
+#define MICROCODE_ALIGNMENT    0x7FF
+
+#define ACM_PKCS_1_5_RSA_SIGNATURE_SHA256_SIZE          256
+#define ACM_PKCS_1_5_RSA_SIGNATURE_SHA384_SIZE          384
+
+#define ACM_HEADER_VERSION_3  (3 << 16)
+#define ACM_MODULE_TYPE_CHIPSET_ACM                     2
+#define ACM_MODULE_SUBTYPE_CAPABLE_OF_EXECUTE_AT_RESET  0x1
+#define ACM_MODULE_SUBTYPE_ANC_MODULE                   0x2
+#define ACM_MODULE_FLAG_PREPRODUCTION                   0x4000
+#define ACM_MODULE_FLAG_DEBUG_SIGN                      0x8000
+
+
+typedef struct {
+  UINT16     ModuleType;
+  UINT16     ModuleSubType;
+  UINT32     HeaderLen;
+  UINT32     HeaderVersion;
+  UINT16     ChipsetID;
+  UINT16     Flags;
+  UINT32     ModuleVendor;
+  UINT32     Date;
+  UINT32     Size;
+  UINT16     TxtSvn;
+  UINT16     SeSvn;
+  UINT32     CodeControl;
+  UINT32     ErrorEntryPoint;
+  UINT32     GDTLimit;
+  UINT32     GDTBasePtr;
+  UINT32     SegSel;
+  UINT32     EntryPoint;
+  UINT8      Rsvd2[64];
+  UINT32     KeySize; // 64
+  UINT32     ScratchSize; // 2 * KeySize + 15
+//UINT8      RSAPubKey[64 * 4]; // KeySize * 4
+//UINT32     RSAPubExp;
+//UINT8      RSASig[256];
+  // End of AC module header
+//UINT8      Scratch[(64 * 2 + 15) * 4]; // ScratchSize * 4
+  // User Area
+//UINT8      UserArea[1];
+} ACM_FORMAT;
+
+#define CHIPSET_ACM_INFORMATION_TABLE_VERSION_3  0x03
+#define CHIPSET_ACM_INFORMATION_TABLE_VERSION_4  0x04
+
+#define CHIPSET_ACM_INFORMATION_TABLE_VERSION    CHIPSET_ACM_INFORMATION_TABLE_VERSION_3
+
+#define CHIPSET_ACM_INFORMATION_TABLE_GUID_V03 \
+  { 0x7FC03AAA, 0x18DB46A7, 0x8F69AC2E, 0x5A7F418D }
+
+#define CHIPSET_ACM_TYPE_BIOS   0
+#define CHIPSET_ACM_TYPE_SINIT  1
+
+typedef struct {
+  UINT32    Guid0;
+  UINT32    Guid1;
+  UINT32    Guid2;
+  UINT32    Guid3;
+} ACM_GUID;
+
+typedef struct {
+  ACM_GUID   Guid;
+  UINT8      ChipsetACMType;
+  UINT8      Version;
+  UINT16     Length;
+  UINT32     ChipsetIDList;
+  UINT32     OsSinitTableVer;
+  UINT32     MinMleHeaderVer;
+//#if (CHIPSET_ACM_INFORMATION_TABLE_VERSION >= CHIPSET_ACM_INFORMATION_TABLE_VERSION_3)
+  UINT32     Capabilities;
+  UINT8      AcmVersion;
+  UINT8      AcmRevision[3];
+//#if (CHIPSET_ACM_INFORMATION_TABLE_VERSION >= CHIPSET_ACM_INFORMATION_TABLE_VERSION_4)
+  UINT32     ProcessorIDList;
+//#endif
+//#endif
+} CHIPSET_ACM_INFORMATION_TABLE;
+
+#define ACM_CHIPSET_ID_REVISION_ID_MAKE  0x1
+
+typedef struct {
+  UINT32     Flags;
+  UINT16     VendorID;
+  UINT16     DeviceID;
+  UINT16     RevisionID;
+  UINT8      Reserved[6];
+} ACM_CHIPSET_ID;
+
+typedef struct {
+  UINT32           Count;
+  ACM_CHIPSET_ID   ChipsetID[1];
+} CHIPSET_ID_LIST;
+
+typedef struct {
+  UINT32     FMS;
+  UINT32     FMSMask;
+  UINT64     PlatformID;
+  UINT64     PlatformMask;
+} ACM_PROCESSOR_ID;
+
+typedef struct {
+  UINT32           Count;
+  ACM_PROCESSOR_ID ProcessorID[1];
+} PROCESSOR_ID_LIST;
+
+#pragma pack ()
+
+
+ACM_GUID mChipsetAcmInformationTableGuid03 = CHIPSET_ACM_INFORMATION_TABLE_GUID_V03;
+
+
+//
+// BIOS INFO data structure
+// This is self contained data structure for BIOS info
+//
+#pragma pack (1)
+#define BIOS_INFO_SIGNATURE  SIGNATURE_64 ('$', 'B', 'I', 'O', 'S', 'I', 'F', '$')
+typedef struct {
+  UINT64            Signature;
+  UINT32            EntryCount;
+  UINT32            Reserved;
+//BIOS_INFO_STRUCT  Struct[EntryCount];
+} BIOS_INFO_HEADER;
+
+//
+// BIOS_INFO_STRUCT attributes
+// bits[0:3] means general attributes
+// bits[4:7] means type specific attributes
+//
+#define BIOS_INFO_STRUCT_ATTRIBUTE_GENERAL_EXCLUDE_FROM_FIT  0x01
+#define BIOS_INFO_STRUCT_ATTRIBUTE_MICROCODE_WHOLE_REGION    0x10
+#define BIOS_INFO_STRUCT_ATTRIBUTE_BIOS_POST_IBB             0x10
+
+typedef struct {
+  //
+  // FitTable entry type
+  //
+  UINT8    Type;
+  //
+  // BIOS_INFO_STRUCT attributes
+  //
+  UINT8    Attributes;
+  //
+  // FitTable entry version
+  //
+  UINT16   Version;
+  //
+  // FitTable entry real size
+  //
+  UINT32   Size;
+  //
+  // FitTable entry address
+  //
+  UINT64   Address;
+} BIOS_INFO_STRUCT;
+
+#pragma pack ()
+
+#define MAX_BIOS_MODULE_ENTRY  0x20
+#define MAX_MICROCODE_ENTRY    0x20
+#define MAX_OPTIONAL_ENTRY     0x20
+#define MAX_PORT_ENTRY         0x20
+
+#define DEFAULT_FIT_TABLE_POINTER_OFFSET  0x40
+#define DEFAULT_FIT_ENTRY_VERSION         0x0100
+
+#define MEMORY_TO_FLASH(FileBuffer, FvBuffer, FvSize)  \
+                 (UINTN)(0x100000000 - ((UINTN)(FvBuffer) + (UINTN)(FvSize) - (UINTN)(FileBuffer)))
+#define FLASH_TO_MEMORY(Address, FvBuffer, FvSize)  \
+                 (VOID *)(UINTN)((UINTN)(FvBuffer) + (UINTN)(FvSize) - (0x100000000 - (UINTN)(Address)))
+
+#define FIT_TABLE_TYPE_HEADER                 0
+#define FIT_TABLE_TYPE_MICROCODE              1
+#define FIT_TABLE_TYPE_STARTUP_ACM            2
+#define FIT_TABLE_TYPE_BIOS_MODULE            7
+#define FIT_TABLE_TYPE_TPM_POLICY             8
+#define FIT_TABLE_TYPE_BIOS_POLICY            9
+#define FIT_TABLE_TYPE_TXT_POLICY             10
+#define FIT_TABLE_TYPE_KEY_MANIFEST           11
+#define FIT_TABLE_TYPE_BOOT_POLICY_MANIFEST   12
+#define FIT_TABLE_TYPE_BIOS_DATA_AREA         13
+#define FIT_TABLE_TYPE_CSE_SECURE_BOOT        16
+
+typedef struct {
+  UINT32  Type;
+  UINT32  Address;
+  UINT32  Size;
+  UINT32  Version; // Used by OptionalModule and PortModule only
+} FIT_TABLE_CONTEXT_ENTRY;
+
+typedef struct {
+  BOOLEAN                    Clear;
+  UINT32                     FitTablePointerOffset;
+  UINT32                     FitTablePointerOffset2;
+  UINT32                     FitEntryNumber;
+  UINT32                     BiosModuleNumber;
+  UINT32                     MicrocodeNumber;
+  UINT32                     OptionalModuleNumber;
+  UINT32                     PortModuleNumber;
+  UINT32                     GlobalVersion;
+  UINT32                     FitHeaderVersion;
+  FIT_TABLE_CONTEXT_ENTRY    StartupAcm;
+  UINT32                     StartupAcmVersion;
+  FIT_TABLE_CONTEXT_ENTRY    BiosModule[MAX_BIOS_MODULE_ENTRY];
+  UINT32                     BiosModuleVersion;
+  FIT_TABLE_CONTEXT_ENTRY    Microcode[MAX_MICROCODE_ENTRY];
+  BOOLEAN                    MicrocodeAlignment;
+  UINT32                     MicrocodeVersion;
+  FIT_TABLE_CONTEXT_ENTRY    OptionalModule[MAX_OPTIONAL_ENTRY];
+  FIT_TABLE_CONTEXT_ENTRY    PortModule[MAX_PORT_ENTRY];
+} FIT_TABLE_CONTEXT;
+
+FIT_TABLE_CONTEXT   gFitTableContext = {0};
+
+unsigned int
+xtoi (
+  char  *str
+  );
+
+VOID
+PrintUtilityInfo (
+  VOID
+  )
+/*++
+
+Routine Description:
+
+  Displays the standard utility information to STDOUT
+
+Arguments:
+
+  None
+
+Returns:
+
+  None
+
+--*/
+{
+  printf (
+    "%s - Tiano IA32/X64 FIT table generation Utility."" Version %i.%i\n\n",
+    UTILITY_NAME,
+    UTILITY_MAJOR_VERSION,
+    UTILITY_MINOR_VERSION
+    );
+}
+
+VOID
+PrintUsage (
+  VOID
+  )
+/*++
+
+Routine Description:
+
+  Displays the utility usage syntax to STDOUT
+
+Arguments:
+
+  None
+
+Returns:
+
+  None
+
+--*/
+{
+  printf ("Usage (generate): %s [-D] InputFvRecoveryFile OutputFvRecoveryFile\n"
+          "\t[-V <FitEntryDefaultVersion>]\n"
+          "\t[-F <FitTablePointerOffset>] [-F <FitTablePointerOffset>] [-V <FitHeaderVersion>]\n"
+          "\t[-NA]\n"
+          "\t[-CLEAR]\n"
+          "\t[-I <BiosInfoGuid>]\n"
+          "\t[-S <StartupAcmAddress StartupAcmSize>|<StartupAcmGuid>] [-V <StartupAcmVersion>]\n"
+          "\t[-B <BiosModuleAddress BiosModuleSize>] [-B ...] [-V <BiosModuleVersion>]\n"
+          "\t[-M <MicrocodeAddress MicrocodeSize>] [-M ...]|[-U <MicrocodeFv MicrocodeBase>|<MicrocodeRegionOffset MicrocodeRegionSize>|<MicrocodeGuid>] [-V <MicrocodeVersion>]\n"
+          "\t[-O RecordType <RecordDataAddress RecordDataSize>|<RESERVE RecordDataSize>|<RecordDataGuid>|<RecordBinFile> [-V <RecordVersion>]] [-O ... [-V ...]]\n"
+          "\t[-P RecordType <IndexPort DataPort Width Bit Index> [-V <RecordVersion>]] [-P ... [-V ...]]\n"
+          , UTILITY_NAME);
+  printf ("  Where:\n");
+  printf ("\t-D                     - It is FD file instead of FV file. (The tool will search FV file)\n");
+  printf ("\tInputFvRecoveryFile    - Name of the input FvRecovery.fv file.\n");
+  printf ("\tOutputFvRecoveryFile   - Name of the output FvRecovery.fv file.\n");
+  printf ("\tFitTablePointerOffset  - FIT table pointer offset. 0x%x as default. 0x18 for current soon to be obsoleted CPUs. User can set both.\n", DEFAULT_FIT_TABLE_POINTER_OFFSET);
+  printf ("\tBiosInfoGuid           - Guid of BiosInfo Module. If this module exists, StartupAcm/Bios/Microcode can be optional.\n");
+  printf ("\tStartupAcmAddress      - Address of StartupAcm.\n");
+  printf ("\tStartupAcmSize         - Size of StartupAcm.\n");
+  printf ("\tStartupAcmGuid         - Guid of StartupAcm Module, if StartupAcm is in a BiosModule, it will be excluded form that.\n");
+  printf ("\tBiosModuleAddress      - Address of BiosModule. User should ensure there is no overlap.\n");
+  printf ("\tBiosModuleSize         - Size of BiosModule.\n");
+  printf ("\tMicrocodeAddress       - Address of Microcode.\n");
+  printf ("\tMicrocodeSize          - Size of Microcode.\n");
+  printf ("\tMicrocodeFv            - Name of Microcode.fv file.\n");
+  printf ("\tMicrocodeBase          - The base address of Microcode.fv in final FD image.\n");
+  printf ("\tMicrocodeRegionOffset  - Offset of Microcode region in input FD image.\n");
+  printf ("\tMicrocodeRegionSize    - Size of Microcode region in input FD image.\n");
+  printf ("\tMicrocodeGuid          - Guid of Microcode Module.\n");
+  printf ("\t-NA                    - No 0x800 aligned Microcode requirement. No -NA means Microcode is 0x800 aligned.\n");
+  printf ("\tRecordType             - FIT entry record type. User should ensure it is ordered.\n");
+  printf ("\tRecordDataAddress      - FIT entry record data address.\n");
+  printf ("\tRecordDataSize         - FIT entry record data size.\n");
+  printf ("\tRecordDataGuid         - FIT entry record data GUID.\n");
+  printf ("\tRecordBinFile          - FIT entry record data binary file.\n");
+  printf ("\tFitEntryDefaultVersion - The default version for all FIT table entries. 0x%04x is used if this is not specified.\n", DEFAULT_FIT_ENTRY_VERSION);
+  printf ("\tFitHeaderVersion       - The version for FIT header. (Override default version)\n");
+  printf ("\tStartupAcmVersion      - The version for StartupAcm. (Override default version)\n");
+  printf ("\tBiosModuleVersion      - The version for BiosModule. (Override default version)\n");
+  printf ("\tMicrocodeVersion       - The version for Microcode. (Override default version)\n");
+  printf ("\tRecordVersion          - The version for Record. (Override default version)\n");
+  printf ("\tIndexPort              - The Index Port Number.\n");
+  printf ("\tDataPort               - The Data Port Number.\n");
+  printf ("\tWidth                  - The Width of the port.\n");
+  printf ("\tBit                    - The Bit Number of the port.\n");
+  printf ("\tIndex                  - The Index Number of the port.\n");
+  printf ("\nUsage (view): %s [-view] InputFile -F <FitTablePointerOffset>\n", UTILITY_NAME);
+  printf ("  Where:\n");
+  printf ("\tInputFile              - Name of the input file.\n");
+  printf ("\tFitTablePointerOffset  - FIT table pointer offset from end of file. 0x%x as default.\n", DEFAULT_FIT_TABLE_POINTER_OFFSET);
+  printf ("\nTool return values:\n");
+  printf ("\tSTATUS_SUCCESS=%d, STATUS_WARNING=%d, STATUS_ERROR=%d\n", STATUS_SUCCESS, STATUS_WARNING, STATUS_ERROR);
+}
+
+VOID *
+SetMem (
+  OUT     VOID                      *Buffer,
+  IN      UINTN                     Length,
+  IN      UINT8                     Value
+  )
+{
+  //
+  // Declare the local variables that actually move the data elements as
+  // volatile to prevent the optimizer from replacing this function with
+  // the intrinsic memset()
+  //
+  volatile UINT8                    *Pointer;
+
+  Pointer = (UINT8*)Buffer;
+  while (Length-- > 0) {
+    *(Pointer++) = Value;
+  }
+  return Buffer;
+}
+
+STATUS
+ReadInputFile (
+  IN CHAR8    *FileName,
+  OUT UINT8   **FileData,
+  OUT UINT32  *FileSize,
+  OUT UINT8   **FileBufferRaw OPTIONAL
+  )
+/*++
+
+Routine Description:
+
+  Read input file
+
+Arguments:
+
+  FileName      - The input file name
+  FileData      - The input file data, the memory is aligned.
+  FileSize      - The input file size
+  FileBufferRaw - The memory to hold input file data. The caller must free the memory.
+
+Returns:
+
+  STATUS_SUCCESS - The file found and data read
+  STATUS_ERROR   - The file data is not read
+  STATUS_WARNING - The file is not found
+
+--*/
+{
+  FILE                        *FpIn;
+  UINT32                      TempResult;
+
+  //
+  // Open the Input FvRecovery.fv file
+  //
+  if ((FpIn = fopen (FileName, "rb")) == NULL) {
+    //
+    // Return WARNING, let caller make decision
+    //
+//    Error (NULL, 0, 0, "Unable to open file", FileName);
+    return STATUS_WARNING;
+  }
+  //
+  // Get the Input FvRecovery.fv file size
+  //
+  fseek (FpIn, 0, SEEK_END);
+  *FileSize = ftell (FpIn);
+  //
+  // Read the contents of input file to memory buffer
+  //
+  if (FileBufferRaw != NULL) {
+    *FileBufferRaw = (UINT8 *) malloc (*FileSize + 0x10000);
+    if (NULL == *FileBufferRaw) {
+      Error (NULL, 0, 0, "No sufficient memory to allocate!", NULL);
+      fclose (FpIn);
+      return STATUS_ERROR;
+    }
+    TempResult = 0x10000 - (UINT32) ((UINTN)*FileBufferRaw & 0x0FFFF);
+    *FileData = (UINT8 *)((UINTN)*FileBufferRaw + TempResult);
+  } else {
+    *FileData = (UINT8 *) malloc (*FileSize);
+     if (NULL == *FileData) {
+      Error (NULL, 0, 0, "No sufficient memory to allocate!", NULL);
+      fclose (FpIn);
+      return STATUS_ERROR;
+    }
+  }
+  fseek (FpIn, 0, SEEK_SET);
+  TempResult = fread (*FileData, 1, *FileSize, FpIn);
+  if (TempResult != *FileSize) {
+    Error (NULL, 0, 0, "Read input file error!", NULL);
+    if (FileBufferRaw != NULL) {
+      free ((VOID *)*FileBufferRaw);
+    } else {
+      free ((VOID *)*FileData);
+    }
+    fclose (FpIn);
+    return STATUS_ERROR;
+  }
+
+  //
+  // Close the input FvRecovery.fv file
+  //
+  fclose (FpIn);
+
+  return STATUS_SUCCESS;
+}
+
+UINT8 *
+FindNextFvHeader (
+  IN UINT8 *FileBuffer,
+  IN UINTN  FileLength
+  )
+/*++
+
+  Routine Description:
+    Find next FvHeader in the FileBuffer
+
+  Parameters:
+    FileBuffer        -   The start FileBuffer which needs to be searched
+    FileLength        -   The whole File Length.
+  Return:
+    FvHeader          -   The FvHeader is found successfully.
+    NULL              -   The FvHeader is not found.
+
+--*/
+{
+  UINT8                       *FileHeader;
+  EFI_FIRMWARE_VOLUME_HEADER  *FvHeader;
+  UINT16                      FileChecksum;
+
+  FileHeader = FileBuffer;
+  for (; (UINTN)FileBuffer < (UINTN)FileHeader + FileLength; FileBuffer += 8) {
+    FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *)FileBuffer;
+    if (FvHeader->Signature == EFI_FVH_SIGNATURE) {
+      //
+      // potential candidate
+      //
+
+      //
+      // Check checksum
+      //
+      if (FvHeader->FvLength > FileLength) {
+        continue;
+      }
+      if (FvHeader->HeaderLength >= FileLength) {
+        continue;
+      }
+      FileChecksum = CalculateChecksum16 ((UINT16 *)FileBuffer, FvHeader->HeaderLength / sizeof (UINT16));
+      if (FileChecksum != 0) {
+        continue;
+      }
+
+      //
+      // Check revision and reserved field
+      //
+#if (PI_SPECIFICATION_VERSION < 0x00010000)
+      if ((FvHeader->Revision == EFI_FVH_REVISION) &&
+          (FvHeader->Reserved[0] == 0) &&
+          (FvHeader->Reserved[1] == 0) &&
+          (FvHeader->Reserved[2] == 0) ){
+        return FileBuffer;
+      }
+#else
+      if ((FvHeader->Revision == EFI_FVH_PI_REVISION) &&
+          (FvHeader->Reserved[0] == 0) ){
+        return FileBuffer;
+      }
+#endif
+    }
+  }
+
+  return NULL;
+}
+
+UINT8  *
+FindFileFromFvByGuid (
+  IN UINT8     *FvBuffer,
+  IN UINT32    FvSize,
+  IN EFI_GUID  *Guid,
+  OUT UINT32   *FileSize
+  )
+/*++
+
+Routine Description:
+
+  Find File with GUID in an FV
+
+Arguments:
+
+  FvBuffer       - FV binary buffer
+  FvSize         - FV size
+  Guid           - File GUID value to be searched
+  FileSize       - Guid File size
+
+Returns:
+
+  FileLocation   - Guid File location.
+  NULL           - Guid File is not found.
+
+--*/
+{
+  EFI_FIRMWARE_VOLUME_HEADER  *FvHeader;
+  EFI_FFS_FILE_HEADER         *FileHeader;
+  UINT64                      FvLength;
+  EFI_GUID                    *TempGuid;
+  UINT8                       *FixPoint;
+  UINT32                      Offset;
+  UINT32                      FileLength;
+  UINT32                      FileOccupiedSize;
+
+  //
+  // Find the FFS file
+  //
+  FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *)FindNextFvHeader (FvBuffer, FvSize);
+  if (NULL == FvHeader) {
+    return NULL;
+  }
+  while (TRUE) {
+    FvLength         = FvHeader->FvLength;
+
+    //
+    // Prepare to walk the FV image
+    //
+    InitializeFvLib (FvHeader, (UINT32)FvLength);
+
+    FileHeader       = (EFI_FFS_FILE_HEADER *)((UINTN)FvHeader + FvHeader->HeaderLength);
+    Offset           = (UINT32) (UINTN) FileHeader - (UINT32) (UINTN) FvHeader;
+
+    while (Offset < FvLength) {
+      TempGuid = (EFI_GUID *)&(FileHeader->Name);
+      FileLength = (*(UINT32 *)(FileHeader->Size)) & 0x00FFFFFF;
+      FileOccupiedSize = GETOCCUPIEDSIZE(FileLength, 8);
+      if ((CompareGuid (TempGuid, Guid)) == 0) {
+        //
+        // Good! Find it.
+        //
+        FixPoint = ((UINT8 *)FileHeader + sizeof(EFI_FFS_FILE_HEADER));
+        //
+        // Find the position of file module, the offset
+        // between the position and the end of FvRecovery.fv file
+        // should not exceed 128kB to prevent reset vector from
+        // outside legacy E and F segment
+        //
+        if ((UINTN)FvHeader + FvLength - (UINTN)FixPoint > 0x20000) {
+  //        printf ("WARNING: The position of file module is not in E and F segment!\n");
+  //        return NULL;
+        }
+        *FileSize = FileLength - sizeof(EFI_FFS_FILE_HEADER);
+  #if (PI_SPECIFICATION_VERSION < 0x00010000)
+        if (FileHeader->Attributes & FFS_ATTRIB_TAIL_PRESENT) {
+          *FileSize -= sizeof(EFI_FFS_FILE_TAIL);
+        }
+  #endif
+        return FixPoint;
+      }
+      FileHeader = (EFI_FFS_FILE_HEADER *)((UINTN)FileHeader + FileOccupiedSize);
+      Offset = (UINT32) (UINTN) FileHeader - (UINT32) (UINTN) FvHeader;
+    }
+
+    //
+    // Not found, check next FV
+    //
+    if ((UINTN)FvBuffer + FvSize > (UINTN)FvHeader + FvLength) {
+      FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *)FindNextFvHeader ((UINT8 *)FvHeader + (UINTN)FvLength, (UINTN)FvBuffer + FvSize - ((UINTN)FvHeader + (UINTN)FvLength));
+      if (FvHeader == NULL) {
+        break;
+      }
+    } else {
+      break;
+    }
+  }
+
+  //
+  // Not found
+  //
+  return NULL;
+}
+
+BOOLEAN
+IsGuidData (
+  IN CHAR8     *StringData,
+  OUT EFI_GUID *Guid
+  )
+/*++
+
+Routine Description:
+
+  Check whether a string is a GUID
+
+Arguments:
+
+  StringData  - the String
+  Guid        - Guid to hold the value
+
+Returns:
+
+  TRUE  - StringData is a GUID, and Guid field is filled.
+  FALSE - StringData is not a GUID
+
+--*/
+{
+  if (strlen (StringData) != strlen ("00000000-0000-0000-0000-000000000000")) {
+    return FALSE;
+  }
+  if ((StringData[8] != '-') ||
+      (StringData[13] != '-') ||
+      (StringData[18] != '-') ||
+      (StringData[23] != '-') ) {
+    return FALSE;
+  }
+
+  StringToGuid (StringData, Guid);
+
+  return TRUE;
+}
+
+VOID
+CheckOverlap (
+  IN UINT32 Address,
+  IN UINT32 Size
+  )
+{
+  INTN  Index;
+
+  for (Index = 0; Index < (INTN)gFitTableContext.BiosModuleNumber; Index ++) {
+    if ((gFitTableContext.BiosModule[Index].Address <= Address) &&
+        ((gFitTableContext.BiosModule[Index].Size - Size) >= (Address - gFitTableContext.BiosModule[Index].Address))) {
+      UINT32  TempSize;
+      INT32   SubIndex;
+
+      //
+      // Found overlap, split BiosModuleEntry
+      // Currently only support StartupAcm in 1 BiosModule. It does not support StartupAcm across 2 BiosModule or more.
+      //
+      if (gFitTableContext.BiosModuleNumber >= MAX_BIOS_MODULE_ENTRY) {
+        Error (NULL, 0, 0, "Too many Bios Module!", NULL);
+        return ;
+      }
+
+      if (Address != gFitTableContext.BiosModule[Index].Address) {
+        //
+        // Skip the entry whose start address is same as StartupAcm
+        //
+        gFitTableContext.BiosModule[gFitTableContext.BiosModuleNumber].Type    = FIT_TABLE_TYPE_BIOS_MODULE;
+        gFitTableContext.BiosModule[gFitTableContext.BiosModuleNumber].Address = gFitTableContext.BiosModule[Index].Address;
+        gFitTableContext.BiosModule[gFitTableContext.BiosModuleNumber].Size    = Address - gFitTableContext.BiosModule[Index].Address;
+        gFitTableContext.BiosModuleNumber ++;
+        gFitTableContext.FitEntryNumber++;
+      }
+
+      TempSize = gFitTableContext.BiosModule[Index].Address + gFitTableContext.BiosModule[Index].Size;
+      gFitTableContext.BiosModule[Index].Address = Address + Size;
+      gFitTableContext.BiosModule[Index].Size    = TempSize - gFitTableContext.BiosModule[Index].Address;
+
+      if (gFitTableContext.BiosModule[Index].Size == 0) {
+        //
+        // remove the entry if size is 0
+        //
+        for (SubIndex = Index; SubIndex < (INTN)gFitTableContext.BiosModuleNumber - 1; SubIndex ++) {
+          gFitTableContext.BiosModule[SubIndex].Address = gFitTableContext.BiosModule[SubIndex + 1].Address;
+          gFitTableContext.BiosModule[SubIndex].Size    = gFitTableContext.BiosModule[SubIndex + 1].Size;
+        }
+        gFitTableContext.BiosModuleNumber --;
+        gFitTableContext.FitEntryNumber--;
+      }
+      break;
+    }
+  }
+}
+
+UINT32
+GetFitEntryNumber (
+  IN INTN   argc,
+  IN CHAR8  **argv,
+  IN UINT8  *FdBuffer,
+  IN UINT32 FdSize
+  )
+/*++
+
+Routine Description:
+
+  Get FIT entry number and fill global FIT table context, from argument
+
+Arguments:
+
+  argc           - Number of command line parameters.
+  argv           - Array of pointers to parameter strings.
+  FdBuffer       - FD binary buffer
+  FdSize         - FD size
+
+Returns:
+
+  FitEntryNumber - The FIT entry number
+  0              - Argument parse fail
+
+*/
+{
+  EFI_GUID  Guid;
+  INTN      Index;
+  UINT8     *FileBuffer;
+  UINT32    FileSize;
+  UINT32    Type;
+  UINT8     *MicrocodeFileBuffer;
+  UINT8     *MicrocodeFileBufferRaw;
+  UINT32    MicrocodeFileSize;
+  UINT32    MicrocodeBase;
+  UINT32    MicrocodeSize;
+  UINT8     *MicrocodeBuffer;
+  UINT32    MicrocodeRegionOffset;
+  UINT32    MicrocodeRegionSize;
+  STATUS    Status;
+  EFI_FIRMWARE_VOLUME_HEADER  *FvHeader;
+  UINTN                       FitEntryNumber;
+  BOOLEAN                     BiosInfoExist;
+  BIOS_INFO_HEADER            *BiosInfo;
+  BIOS_INFO_STRUCT            *BiosInfoStruct;
+  UINTN                       BiosInfoIndex;
+
+  //
+  // Init index
+  //
+  Index = 3;
+  if (((strcmp (argv[1], "-D") == 0) ||
+       (strcmp (argv[1], "-d") == 0)) ) {
+    Index ++;
+  }
+
+  //
+  // Fill Global Version
+  //
+  if ((Index + 1 >= argc) ||
+      ((strcmp (argv[Index], "-V") != 0) &&
+       (strcmp (argv[Index], "-v") != 0)) ) {
+    gFitTableContext.GlobalVersion = DEFAULT_FIT_ENTRY_VERSION;
+  } else {
+    gFitTableContext.GlobalVersion = xtoi (argv[Index + 1]);
+    Index += 2;
+  }
+
+  //
+  // 0. FIT Header
+  //
+  gFitTableContext.FitEntryNumber = 1;
+  if ((Index + 1 >= argc) ||
+      ((strcmp (argv[Index], "-F") != 0) &&
+       (strcmp (argv[Index], "-f") != 0)) ) {
+    //
+    // Use default address
+    //
+    gFitTableContext.FitTablePointerOffset = DEFAULT_FIT_TABLE_POINTER_OFFSET;
+  } else {
+    //
+    // Get offset from parameter
+    //
+    gFitTableContext.FitTablePointerOffset = xtoi (argv[Index + 1]);
+    Index += 2;
+  }
+
+  //
+  // 0.1 FIT Header 2
+  //
+  if ((Index + 1 >= argc) ||
+      ((strcmp (argv[Index], "-F") != 0) &&
+       (strcmp (argv[Index], "-f") != 0)) ) {
+    //
+    // Bypass
+    //
+    gFitTableContext.FitTablePointerOffset2 = 0;
+  } else {
+    //
+    // Get offset from parameter
+    //
+    gFitTableContext.FitTablePointerOffset2 = xtoi (argv[Index + 1]);
+    Index += 2;
+  }
+
+  //
+  // 0.2 FIT Header version
+  //
+  if ((Index + 1 >= argc) ||
+      ((strcmp (argv[Index], "-V") != 0) &&
+       (strcmp (argv[Index], "-v") != 0)) ) {
+    //
+    // Bypass
+    //
+    gFitTableContext.FitHeaderVersion = gFitTableContext.GlobalVersion;
+  } else {
+    //
+    // Get offset from parameter
+    //
+    gFitTableContext.FitHeaderVersion = xtoi (argv[Index + 1]);
+    Index += 2;
+  }
+
+  //
+  // 0.3 Microcode alignment
+  //
+  if ((Index >= argc) ||
+      ((strcmp (argv[Index], "-NA") != 0) &&
+       (strcmp (argv[Index], "-na") != 0)) ) {
+    //
+    // by pass
+    //
+    gFitTableContext.MicrocodeAlignment = TRUE;
+  } else {
+    //
+    // no alignment
+    //
+    gFitTableContext.MicrocodeAlignment = FALSE;
+    Index += 1;
+  }
+
+  //
+  // 0.4 Clear FIT table related memory
+  //
+  if ((Index >= argc) ||
+      ((strcmp (argv[Index], "-CLEAR") != 0) &&
+       (strcmp (argv[Index], "-clear") != 0)) ) {
+    //
+    // by pass
+    //
+    gFitTableContext.Clear = FALSE;
+  } else {
+    //
+    // Clear FIT table
+    //
+    gFitTableContext.Clear = TRUE;
+    //
+    // Do not parse any more
+    //
+    return 0;
+  }
+
+  //
+  // 0.5 BiosInfo
+  //
+  if ((Index + 1 >= argc) ||
+      ((strcmp (argv[Index], "-I") != 0) &&
+       (strcmp (argv[Index], "-i") != 0)) ) {
+    //
+    // Bypass
+    //
+    BiosInfoExist = FALSE;
+  } else {
+    //
+    // Get offset from parameter
+    //
+    BiosInfoExist = TRUE;
+    if (IsGuidData (argv[Index + 1], &Guid)) {
+      FileBuffer = FindFileFromFvByGuid (FdBuffer, FdSize, &Guid, &FileSize);
+      if (FileBuffer == NULL) {
+        Error (NULL, 0, 0, "-I Parameter incorrect, GUID not found!", "%s", argv[Index + 1]);
+        // not found
+        return 0;
+      }
+      BiosInfo = (BIOS_INFO_HEADER *)FileBuffer;
+      for (BiosInfoIndex = 0; BiosInfoIndex < FileSize; BiosInfoIndex++) {
+        if (((BIOS_INFO_HEADER *)(FileBuffer + BiosInfoIndex))->Signature == BIOS_INFO_SIGNATURE) {
+          BiosInfo = (BIOS_INFO_HEADER *)(FileBuffer + BiosInfoIndex);
+        }
+      }
+      if (BiosInfo->Signature != BIOS_INFO_SIGNATURE) {
+        Error (NULL, 0, 0, "-I Parameter incorrect, Signature Error!", NULL);
+        // not found
+        return 0;
+      }
+      BiosInfoStruct = (BIOS_INFO_STRUCT *)(BiosInfo + 1);
+
+      for (BiosInfoIndex = 0; BiosInfoIndex < BiosInfo->EntryCount; BiosInfoIndex++) {
+        if ((BiosInfoStruct[BiosInfoIndex].Attributes & BIOS_INFO_STRUCT_ATTRIBUTE_GENERAL_EXCLUDE_FROM_FIT) != 0) {
+          continue;
+        }
+        switch (BiosInfoStruct[BiosInfoIndex].Type) {
+        case FIT_TABLE_TYPE_HEADER:
+          Error (NULL, 0, 0, "-I Parameter incorrect, Header Type unsupported!", NULL);
+          return 0;
+        case FIT_TABLE_TYPE_STARTUP_ACM:
+          if (gFitTableContext.StartupAcm.Type != 0) {
+            Error (NULL, 0, 0, "-I Parameter incorrect, Duplicated StartupAcm!", NULL);
+            return 0;
+          }
+          gFitTableContext.StartupAcm.Type    = FIT_TABLE_TYPE_STARTUP_ACM;
+          gFitTableContext.StartupAcm.Address = (UINT32)BiosInfoStruct[BiosInfoIndex].Address;
+          gFitTableContext.StartupAcm.Size    = (UINT32)BiosInfoStruct[BiosInfoIndex].Size;
+          gFitTableContext.StartupAcmVersion  = BiosInfoStruct[BiosInfoIndex].Version;
+          gFitTableContext.FitEntryNumber ++;
+          break;
+        case FIT_TABLE_TYPE_BIOS_MODULE:
+          if ((BiosInfoStruct[BiosInfoIndex].Attributes & BIOS_INFO_STRUCT_ATTRIBUTE_BIOS_POST_IBB) != 0) {
+            continue;
+          }
+          if (gFitTableContext.BiosModuleNumber >= MAX_BIOS_MODULE_ENTRY) {
+            Error (NULL, 0, 0, "-I Parameter incorrect, Too many Bios Module!", NULL);
+            return 0;
+          }
+          gFitTableContext.BiosModule[gFitTableContext.BiosModuleNumber].Type    = FIT_TABLE_TYPE_BIOS_MODULE;
+          gFitTableContext.BiosModule[gFitTableContext.BiosModuleNumber].Address = (UINT32)BiosInfoStruct[BiosInfoIndex].Address;
+          gFitTableContext.BiosModule[gFitTableContext.BiosModuleNumber].Size    = (UINT32)BiosInfoStruct[BiosInfoIndex].Size;
+          gFitTableContext.BiosModuleVersion = BiosInfoStruct[BiosInfoIndex].Version;
+          gFitTableContext.BiosModuleNumber ++;
+          gFitTableContext.FitEntryNumber ++;
+          break;
+        case FIT_TABLE_TYPE_MICROCODE:
+          if ((BiosInfoStruct[BiosInfoIndex].Attributes & BIOS_INFO_STRUCT_ATTRIBUTE_MICROCODE_WHOLE_REGION) == 0) {
+            if (gFitTableContext.MicrocodeNumber >= MAX_MICROCODE_ENTRY) {
+              Error (NULL, 0, 0, "-I Parameter incorrect, Too many Microcode!", NULL);
+              return 0;
+            }
+            gFitTableContext.Microcode[gFitTableContext.MicrocodeNumber].Type    = FIT_TABLE_TYPE_MICROCODE;
+            gFitTableContext.Microcode[gFitTableContext.MicrocodeNumber].Address = (UINT32)BiosInfoStruct[BiosInfoIndex].Address;
+            gFitTableContext.Microcode[gFitTableContext.MicrocodeNumber].Size    = (UINT32)BiosInfoStruct[BiosInfoIndex].Size;
+            gFitTableContext.MicrocodeVersion = BiosInfoStruct[BiosInfoIndex].Version;
+            gFitTableContext.MicrocodeNumber++;
+            gFitTableContext.FitEntryNumber++;
+          } else {
+            MicrocodeRegionOffset = (UINT32)BiosInfoStruct[BiosInfoIndex].Address;
+            MicrocodeRegionSize   = (UINT32)BiosInfoStruct[BiosInfoIndex].Size;
+            if (MicrocodeRegionOffset == 0) {
+              Error (NULL, 0, 0, "-I Parameter incorrect, MicrocodeRegionOffset is 0", NULL);
+              return 0;
+            }
+            if (MicrocodeRegionSize == 0) {
+              Error (NULL, 0, 0, "-I Parameter incorrect, MicrocodeRegionSize is 0", NULL);
+              return 0;
+            }
+            if (MicrocodeRegionSize > FdSize) {
+              Error (NULL, 0, 0, "-I Parameter incorrect, MicrocodeRegionSize too large", NULL);
+              return 0;
+            }
+
+            MicrocodeFileBuffer = FLASH_TO_MEMORY (MicrocodeRegionOffset, FdBuffer, FdSize);
+            MicrocodeFileSize = MicrocodeRegionSize;
+            MicrocodeBase = MicrocodeRegionOffset;
+
+            FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *)MicrocodeFileBuffer;
+            if (FvHeader->Signature == EFI_FVH_SIGNATURE) {
+              // Skip FV header + FFS header
+              MicrocodeBuffer = MicrocodeFileBuffer + sizeof(EFI_FIRMWARE_VOLUME_HEADER) + sizeof(EFI_FV_BLOCK_MAP_ENTRY) + sizeof(EFI_FFS_FILE_HEADER);
+            } else {
+              MicrocodeBuffer = MicrocodeFileBuffer;
+            }
+            while ((UINT32)(MicrocodeBuffer - MicrocodeFileBuffer) < MicrocodeFileSize) {
+              if (*(UINT32 *)(MicrocodeBuffer) != 0x1) { // HeaderVersion
+                break;
+              }
+              if (*(UINT32 *)(MicrocodeBuffer + 20) != 0x1) { // LoaderVersion
+                break;
+              }
+              if (*(UINT32 *)(MicrocodeBuffer + 28) == 0) { // DataSize
+                MicrocodeSize = 2048;
+              } else {
+                //
+                // MCU might be put at 2KB alignment, if so, we need to adjust the size as 2KB alignment.
+                //
+                if (gFitTableContext.MicrocodeAlignment) {
+                  MicrocodeSize = (*(UINT32 *)(MicrocodeBuffer + 32) + MICROCODE_ALIGNMENT) & ~MICROCODE_ALIGNMENT;
+                } else {
+                  MicrocodeSize = (*(UINT32 *)(MicrocodeBuffer + 32));
+                }
+              }
+
+              //
+              // Add Microcode
+              //
+              if (gFitTableContext.MicrocodeNumber >= MAX_MICROCODE_ENTRY) {
+                printf ("-I Parameter incorrect, Too many Microcode!\n");
+                return 0;
+              }
+              gFitTableContext.Microcode[gFitTableContext.MicrocodeNumber].Type = FIT_TABLE_TYPE_MICROCODE;
+              gFitTableContext.Microcode[gFitTableContext.MicrocodeNumber].Address = MicrocodeBase + ((UINT32) (UINTN) MicrocodeBuffer - (UINT32) (UINTN) MicrocodeFileBuffer);
+              gFitTableContext.Microcode[gFitTableContext.MicrocodeNumber].Size = MicrocodeSize;
+              gFitTableContext.MicrocodeNumber++;
+              gFitTableContext.FitEntryNumber++;
+
+              MicrocodeBuffer += MicrocodeSize;
+            }
+          }
+          break;
+        case FIT_TABLE_TYPE_TPM_POLICY:
+        case FIT_TABLE_TYPE_BIOS_POLICY:
+        case FIT_TABLE_TYPE_TXT_POLICY:
+        case FIT_TABLE_TYPE_KEY_MANIFEST:
+        case FIT_TABLE_TYPE_BOOT_POLICY_MANIFEST:
+        case FIT_TABLE_TYPE_BIOS_DATA_AREA:
+        case FIT_TABLE_TYPE_CSE_SECURE_BOOT:
+        default :
+          if (BiosInfoStruct[BiosInfoIndex].Version != 0) {
+            if (gFitTableContext.OptionalModuleNumber >= MAX_OPTIONAL_ENTRY) {
+              Error (NULL, 0, 0, "-I Parameter incorrect, Too many Optional Module!", NULL);
+              return 0;
+            }
+            gFitTableContext.OptionalModule[gFitTableContext.OptionalModuleNumber].Type    = BiosInfoStruct[BiosInfoIndex].Type;
+            gFitTableContext.OptionalModule[gFitTableContext.OptionalModuleNumber].Address = (UINT32)BiosInfoStruct[BiosInfoIndex].Address;
+            gFitTableContext.OptionalModule[gFitTableContext.OptionalModuleNumber].Size    = (UINT32)BiosInfoStruct[BiosInfoIndex].Size;
+            gFitTableContext.OptionalModule[gFitTableContext.OptionalModuleNumber].Version = BiosInfoStruct[BiosInfoIndex].Version;
+            gFitTableContext.OptionalModuleNumber++;
+            gFitTableContext.FitEntryNumber++;
+          } else {
+            if (gFitTableContext.PortModuleNumber >= MAX_PORT_ENTRY) {
+              Error (NULL, 0, 0, "-I Parameter incorrect, Too many Port Module!", NULL);
+              return 0;
+            }
+            gFitTableContext.PortModule[gFitTableContext.PortModuleNumber].Type    = BiosInfoStruct[BiosInfoIndex].Type;
+            gFitTableContext.PortModule[gFitTableContext.PortModuleNumber].Address = (UINT32)BiosInfoStruct[BiosInfoIndex].Address;
+            gFitTableContext.PortModule[gFitTableContext.PortModuleNumber].Size    = (UINT32)(BiosInfoStruct[BiosInfoIndex].Address >> 32);
+            gFitTableContext.PortModule[gFitTableContext.PortModuleNumber].Version = BiosInfoStruct[BiosInfoIndex].Version;
+            gFitTableContext.PortModuleNumber++;
+            gFitTableContext.FitEntryNumber++;
+          }
+          break;
+        }
+      }
+
+    } else {
+      Error (NULL, 0, 0, "-I Parameter incorrect, expect GUID!", NULL);
+      return 0;
+    }
+    Index += 2;
+  }
+
+  //
+  // 1. StartupAcm
+  //
+  do {
+    if ((Index + 1 >= argc) ||
+        ((strcmp (argv[Index], "-S") != 0) &&
+         (strcmp (argv[Index], "-s") != 0)) ) {
+      if (BiosInfoExist && (gFitTableContext.StartupAcm.Type == FIT_TABLE_TYPE_STARTUP_ACM)) {
+        break;
+      }
+//      Error (NULL, 0, 0, "-S Parameter incorrect, expect -S!", NULL);
+//      return 0;
+      printf ("-S not found. WARNING!\n");
+      break;
+    }
+    if (IsGuidData (argv[Index + 1], &Guid)) {
+      FileBuffer = FindFileFromFvByGuid (FdBuffer, FdSize, &Guid, &FileSize);
+      if (FileBuffer == NULL) {
+        Error (NULL, 0, 0, "-S Parameter incorrect, GUID not found!", "%s", argv[Index + 1]);
+        // not found
+        return 0;
+      }
+      FileBuffer = (UINT8 *)MEMORY_TO_FLASH (FileBuffer, FdBuffer, FdSize);
+      Index += 2;
+    } else {
+      if (Index + 2 >= argc) {
+        Error (NULL, 0, 0, "-S Parameter incorrect, expect Address Size!", NULL);
+        return 0;
+      }
+      FileBuffer = (UINT8 *) (UINTN) xtoi (argv[Index + 1]);
+      FileSize = xtoi (argv[Index + 2]);
+      Index += 3;
+    }
+    if (gFitTableContext.StartupAcm.Type != 0) {
+      Error (NULL, 0, 0, "-S Parameter incorrect, Duplicated StartupAcm!", NULL);
+      return 0;
+    }
+    gFitTableContext.StartupAcm.Type = FIT_TABLE_TYPE_STARTUP_ACM;
+    gFitTableContext.StartupAcm.Address = (UINT32) (UINTN) FileBuffer;
+    gFitTableContext.StartupAcm.Size = FileSize;
+    gFitTableContext.FitEntryNumber ++;
+
+    //
+    // 1.1 StartupAcm version
+    //
+    if ((Index + 1 >= argc) ||
+        ((strcmp (argv[Index], "-V") != 0) &&
+         (strcmp (argv[Index], "-v") != 0)) ) {
+      //
+      // Bypass
+      //
+      gFitTableContext.StartupAcmVersion = gFitTableContext.GlobalVersion;
+    } else {
+      //
+      // Get offset from parameter
+      //
+      gFitTableContext.StartupAcmVersion = xtoi (argv[Index + 1]);
+      Index += 2;
+    }
+  } while (FALSE);
+
+  //
+  // 2. BiosModule
+  //
+  do {
+    if ((Index + 2 >= argc) ||
+        ((strcmp (argv[Index], "-B") != 0) &&
+         (strcmp (argv[Index], "-b") != 0)) ) {
+      if (BiosInfoExist && (gFitTableContext.BiosModuleNumber != 0)) {
+        break;
+      }
+//      Error (NULL, 0, 0, "-B Parameter incorrect, expect -B!", NULL);
+//      return 0;
+      printf ("-B not found. WARNING!\n");
+      break;
+    }
+
+    FileBuffer = (UINT8 *) (UINTN) xtoi (argv[Index + 1]);
+    FileSize = xtoi (argv[Index + 2]);
+    gFitTableContext.BiosModule[gFitTableContext.BiosModuleNumber].Type = FIT_TABLE_TYPE_BIOS_MODULE;
+    gFitTableContext.BiosModule[gFitTableContext.BiosModuleNumber].Address = (UINT32) (UINTN) FileBuffer;
+    gFitTableContext.BiosModule[gFitTableContext.BiosModuleNumber].Size = FileSize;
+    gFitTableContext.BiosModuleNumber ++;
+    gFitTableContext.FitEntryNumber ++;
+
+    while (TRUE) {
+      Index += 3;
+      if (Index + 2 >= argc) {
+        break;
+      }
+      if ((strcmp (argv[Index], "-B") != 0) &&
+          (strcmp (argv[Index], "-b") != 0) ) {
+        break;
+      }
+      if (gFitTableContext.BiosModuleNumber >= MAX_BIOS_MODULE_ENTRY) {
+        Error (NULL, 0, 0, "-B Parameter incorrect, Too many Bios Module!", NULL);
+        return 0;
+      }
+      FileBuffer = (UINT8 *) (UINTN) xtoi (argv[Index + 1]);
+      FileSize = xtoi (argv[Index + 2]);
+      gFitTableContext.BiosModule[gFitTableContext.BiosModuleNumber].Type = FIT_TABLE_TYPE_BIOS_MODULE;
+      gFitTableContext.BiosModule[gFitTableContext.BiosModuleNumber].Address = (UINT32) (UINTN) FileBuffer;
+      gFitTableContext.BiosModule[gFitTableContext.BiosModuleNumber].Size = FileSize;
+      gFitTableContext.BiosModuleNumber ++;
+      gFitTableContext.FitEntryNumber++;
+    }
+
+    //
+    // 2.1 BiosModule version
+    //
+    if ((Index + 1 >= argc) ||
+        ((strcmp (argv[Index], "-V") != 0) &&
+         (strcmp (argv[Index], "-v") != 0)) ) {
+      //
+      // Bypass
+      //
+      gFitTableContext.BiosModuleVersion = gFitTableContext.GlobalVersion;
+    } else {
+      //
+      // Get offset from parameter
+      //
+      gFitTableContext.BiosModuleVersion = xtoi (argv[Index + 1]);
+      Index += 2;
+    }
+  } while (FALSE);
+
+  //
+  // 3. Microcode
+  //
+  while (TRUE) {
+    if (Index + 1 >= argc) {
+      break;
+    }
+    if ((strcmp (argv[Index], "-M") != 0) &&
+        (strcmp (argv[Index], "-m") != 0) ) {
+      break;
+    }
+    if (IsGuidData (argv[Index + 2], &Guid)) {
+      Error (NULL, 0, 0, "-M Parameter incorrect, GUID unsupported!", NULL);
+      return 0;
+    } else {
+      if (Index + 2 >= argc) {
+        break;
+      }
+      FileBuffer = (UINT8 *) (UINTN) xtoi (argv[Index + 1]);
+      FileSize = xtoi (argv[Index + 2]);
+      Index += 3;
+    }
+    if (gFitTableContext.MicrocodeNumber >= MAX_MICROCODE_ENTRY) {
+      Error (NULL, 0, 0, "-M Parameter incorrect, Too many Microcode!", NULL);
+      return 0;
+    }
+    gFitTableContext.Microcode[gFitTableContext.MicrocodeNumber].Type = FIT_TABLE_TYPE_MICROCODE;
+    gFitTableContext.Microcode[gFitTableContext.MicrocodeNumber].Address = (UINT32) (UINTN) FileBuffer;
+    gFitTableContext.Microcode[gFitTableContext.MicrocodeNumber].Size = FileSize;
+    gFitTableContext.MicrocodeNumber++;
+    gFitTableContext.FitEntryNumber++;
+  }
+
+  //
+  // 3.1 MicrocodeFv
+  //
+  while (TRUE) {
+    if (Index + 1 >= argc) {
+      break;
+    }
+    if ((strcmp (argv[Index], "-U") != 0) &&
+        (strcmp (argv[Index], "-u") != 0) ) {
+      break;
+    }
+    //
+    // Get Fv
+    //
+    if (IsGuidData (argv[Index + 1], &Guid)) {
+      MicrocodeFileBuffer = FindFileFromFvByGuid (FdBuffer, FdSize, &Guid, &MicrocodeFileSize);
+      if (MicrocodeFileBuffer == NULL) {
+        Error (NULL, 0, 0, "-U Parameter incorrect, GUID not found!", "%s", argv[Index + 1]);
+        // not found
+        return 0;
+      }
+      Index += 2;
+
+      MicrocodeBuffer = MicrocodeFileBuffer;
+      MicrocodeFileBufferRaw = NULL;
+      MicrocodeRegionOffset = MEMORY_TO_FLASH (MicrocodeFileBuffer, FdBuffer, FdSize);
+      MicrocodeRegionSize   = 0;
+      MicrocodeBase = MicrocodeRegionOffset;
+
+    } else {
+      if (Index + 2 >= argc) {
+        break;
+      }
+      Status = ReadInputFile (argv[Index + 1], &MicrocodeFileBuffer, &MicrocodeFileSize, &MicrocodeFileBufferRaw);
+      if (Status != STATUS_SUCCESS) {
+        MicrocodeRegionOffset = xtoi (argv[Index + 1]);
+        MicrocodeRegionSize   = xtoi (argv[Index + 2]);
+
+        if (MicrocodeRegionOffset == 0) {
+          Error (NULL, 0, 0, "-U Parameter incorrect, MicrocodeRegionOffset is 0, or unable to open file", "%s", argv[Index + 1]);
+          return 0;
+        }
+        if (MicrocodeRegionSize == 0) {
+          Error (NULL, 0, 0, "-U Parameter incorrect, MicrocodeRegionSize is 0", NULL);
+          return 0;
+        }
+        if (MicrocodeRegionSize > FdSize) {
+          Error (NULL, 0, 0, "-U Parameter incorrect, MicrocodeRegionSize too large", NULL);
+          return 0;
+        }
+
+        Index += 3;
+
+        MicrocodeFileBufferRaw = NULL;
+        MicrocodeFileBuffer = FLASH_TO_MEMORY (MicrocodeRegionOffset, FdBuffer, FdSize);
+        MicrocodeFileSize = MicrocodeRegionSize;
+        MicrocodeBase = MicrocodeRegionOffset;
+
+        FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *)MicrocodeFileBuffer;
+        if (FvHeader->Signature == EFI_FVH_SIGNATURE) {
+          // Skip FV header + FFS header
+          MicrocodeBuffer = MicrocodeFileBuffer + sizeof(EFI_FIRMWARE_VOLUME_HEADER) + sizeof(EFI_FV_BLOCK_MAP_ENTRY) + sizeof(EFI_FFS_FILE_HEADER);
+        } else {
+          MicrocodeBuffer = MicrocodeFileBuffer;
+        }
+      } else {
+        MicrocodeBase = xtoi (argv[Index + 2]);
+        Index += 3;
+        MicrocodeRegionOffset = 0;
+        MicrocodeRegionSize   = 0;
+
+        FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *)MicrocodeFileBuffer;
+        if (FvHeader->Signature == EFI_FVH_SIGNATURE) {
+          // Skip FV header + FFS header
+          MicrocodeBuffer = MicrocodeFileBuffer + sizeof(EFI_FIRMWARE_VOLUME_HEADER) + sizeof(EFI_FV_BLOCK_MAP_ENTRY) + sizeof(EFI_FFS_FILE_HEADER);
+        } else {
+          MicrocodeBuffer = MicrocodeFileBuffer;
+        }
+      }
+    }
+    while ((UINT32)(MicrocodeBuffer - MicrocodeFileBuffer) < MicrocodeFileSize) {
+      if (*(UINT32 *)(MicrocodeBuffer) != 0x1) { // HeaderVersion
+        break;
+      }
+      if (*(UINT32 *)(MicrocodeBuffer + 20) != 0x1) { // LoaderVersion
+        break;
+      }
+      if (*(UINT32 *)(MicrocodeBuffer + 28) == 0) { // DataSize
+        MicrocodeSize = 2048;
+      } else {
+        //
+        // MCU might be put at 2KB alignment, if so, we need to adjust the size as 2KB alignment.
+        //
+        if (gFitTableContext.MicrocodeAlignment) {
+          MicrocodeSize = (*(UINT32 *)(MicrocodeBuffer + 32) + MICROCODE_ALIGNMENT) & ~MICROCODE_ALIGNMENT;
+        } else {
+          MicrocodeSize = (*(UINT32 *)(MicrocodeBuffer + 32));
+        }
+      }
+
+      //
+      // Add Microcode
+      //
+      if (gFitTableContext.MicrocodeNumber >= MAX_MICROCODE_ENTRY) {
+        printf ("-U Parameter incorrect, Too many Microcode!\n");
+        return 0;
+      }
+      gFitTableContext.Microcode[gFitTableContext.MicrocodeNumber].Type = FIT_TABLE_TYPE_MICROCODE;
+      gFitTableContext.Microcode[gFitTableContext.MicrocodeNumber].Address = MicrocodeBase + ((UINT32) (UINTN) MicrocodeBuffer - (UINT32) (UINTN) MicrocodeFileBuffer);
+      gFitTableContext.Microcode[gFitTableContext.MicrocodeNumber].Size = MicrocodeSize;
+      gFitTableContext.MicrocodeNumber++;
+      gFitTableContext.FitEntryNumber++;
+
+      MicrocodeBuffer += MicrocodeSize;
+    }
+
+    if (MicrocodeFileBufferRaw != NULL) {
+      free ((VOID *)MicrocodeFileBufferRaw);
+      MicrocodeFileBufferRaw = NULL;
+    }
+  }
+
+  //
+  // 3.3 Microcode version
+  //
+  if ((Index + 1 >= argc) ||
+      ((strcmp (argv[Index], "-V") != 0) &&
+       (strcmp (argv[Index], "-v") != 0)) ) {
+    //
+    // Bypass
+    //
+    gFitTableContext.MicrocodeVersion = gFitTableContext.GlobalVersion;
+  } else {
+    //
+    // Get offset from parameter
+    //
+    gFitTableContext.MicrocodeVersion = xtoi (argv[Index + 1]);
+    Index += 2;
+  }
+
+  //
+  // 4. Optional type
+  //
+  while (TRUE) {
+    if (Index + 2 >= argc) {
+      break;
+    }
+    if ((strcmp (argv[Index], "-O") != 0) &&
+        (strcmp (argv[Index], "-o") != 0) ) {
+      break;
+    }
+    Type = xtoi (argv[Index + 1]);
+    //
+    // 1st, try GUID
+    //
+    if (IsGuidData (argv[Index + 2], &Guid)) {
+      FileBuffer = FindFileFromFvByGuid (FdBuffer, FdSize, &Guid, &FileSize);
+      if (FileBuffer == NULL) {
+        Error (NULL, 0, 0, "-O Parameter incorrect, GUID not found!", "%s", argv[Index + 2]);
+        // not found
+        return 0;
+      }
+      if (FileSize >= 0x80000000) {
+        Error (NULL, 0, 0, "-O Parameter incorrect, FileSize too large!", NULL);
+        return 0;
+      }
+      FileBuffer = (UINT8 *)MEMORY_TO_FLASH (FileBuffer, FdBuffer, FdSize);
+      Index += 3;
+    } else {
+      //
+      // 2nd, try file
+      //
+      Status = ReadInputFile (argv[Index + 2], &FileBuffer, &FileSize, NULL);
+      if (Status == STATUS_SUCCESS) {
+        if (FileSize >= 0x80000000) {
+          Error (NULL, 0, 0, "-O Parameter incorrect, FileSize too large!", NULL);
+          free (FileBuffer);
+          return 0;
+        }
+        //
+        // Set the most significant bit
+        // It means the data in memory, not in flash yet.
+        // Assume the file size should < 2G.
+        //
+        FileSize |= 0x80000000;
+        Index += 3;
+      } else {
+        //
+        // 3rd, try <RESERVE, Length>
+        //
+        if (Index + 3 >= argc) {
+          break;
+        }
+        if ((strcmp (argv[Index + 2], "RESERVE") == 0) ||
+            (strcmp (argv[Index + 2], "reserve") == 0)) {
+          FileSize = xtoi (argv[Index + 3]);
+          if (FileSize >= 0x80000000) {
+            Error (NULL, 0, 0, "-O Parameter incorrect, FileSize too large!", NULL);
+            return 0;
+          }
+          FileBuffer = malloc (FileSize);
+          if (FileBuffer == NULL) {
+            Error (NULL, 0, 0, "No sufficient memory to allocate!", NULL);
+            return 0;
+          }
+          SetMem (FileBuffer, FileSize, 0xFF);
+          //
+          // Set the most significant bit
+          // It means the data in memory, not in flash yet.
+          // Assume the file size should < 2G.
+          //
+          FileSize |= 0x80000000;
+          Index += 4;
+        } else {
+          //
+          // 4th, try <Address, Length>
+          //
+          if (Index + 3 >= argc) {
+            break;
+          }
+          FileBuffer = (UINT8 *) (UINTN) xtoi (argv[Index + 2]);
+          FileSize = xtoi (argv[Index + 3]);
+          if (FileSize >= 0x80000000) {
+            Error (NULL, 0, 0, "-O Parameter incorrect, FileSize too large!", NULL);
+            return 0;
+          }
+          Index += 4;
+        }
+      }
+    }
+    if (gFitTableContext.OptionalModuleNumber >= MAX_OPTIONAL_ENTRY) {
+      Error (NULL, 0, 0, "-O Parameter incorrect, Too many Optional Module!", NULL);
+      free (FileBuffer);
+      return 0;
+    }
+    gFitTableContext.OptionalModule[gFitTableContext.OptionalModuleNumber].Type = Type;
+    gFitTableContext.OptionalModule[gFitTableContext.OptionalModuleNumber].Address = (UINT32) (UINTN) FileBuffer;
+    gFitTableContext.OptionalModule[gFitTableContext.OptionalModuleNumber].Size = FileSize;
+
+    //
+    // 4.1 Optional Module version
+    //
+    if ((Index + 1 >= argc) ||
+        ((strcmp (argv[Index], "-V") != 0) &&
+         (strcmp (argv[Index], "-v") != 0)) ) {
+      //
+      // Bypass
+      //
+      gFitTableContext.OptionalModule[gFitTableContext.OptionalModuleNumber].Version = gFitTableContext.GlobalVersion;
+    } else {
+      //
+      // Get offset from parameter
+      //
+      gFitTableContext.OptionalModule[gFitTableContext.OptionalModuleNumber].Version = xtoi (argv[Index + 1]);
+      Index += 2;
+    }
+
+    gFitTableContext.OptionalModuleNumber ++;
+    gFitTableContext.FitEntryNumber++;
+  }
+
+  //
+  // 5. Port type
+  //
+  while (TRUE) {
+    if (Index + 6 >= argc) {
+      break;
+    }
+    if ((strcmp (argv[Index], "-P") != 0) &&
+        (strcmp (argv[Index], "-p") != 0) ) {
+      break;
+    }
+
+    Type = xtoi (argv[Index + 1]);
+    if (gFitTableContext.PortModuleNumber >= MAX_PORT_ENTRY) {
+      printf ("-P Parameter incorrect, Too many Port Module!\n");
+      return 0;
+    }
+
+    gFitTableContext.PortModule[gFitTableContext.PortModuleNumber].Type = Type;
+    gFitTableContext.PortModule[gFitTableContext.PortModuleNumber].Address = (UINT16)xtoi (argv[Index + 2]) + ((UINT16)xtoi (argv[Index + 3]) << 16);
+    gFitTableContext.PortModule[gFitTableContext.PortModuleNumber].Size = (UINT8)xtoi (argv[Index + 4]) + ((UINT8)xtoi (argv[Index + 5]) << 8) + ((UINT16)xtoi (argv[Index + 6]) << 16);
+    Index += 7;
+
+    //
+    // 5.1 Port Module version
+    //
+    if ((Index + 1 >= argc) ||
+        ((strcmp (argv[Index], "-V") != 0) &&
+         (strcmp (argv[Index], "-v") != 0)) ) {
+      //
+      // Bypass
+      //
+      gFitTableContext.PortModule[gFitTableContext.PortModuleNumber].Version = 0;
+    } else {
+      //
+      // Get offset from parameter
+      //
+      gFitTableContext.PortModule[gFitTableContext.PortModuleNumber].Version = xtoi (argv[Index + 1]);
+      Index += 2;
+    }
+
+    gFitTableContext.PortModuleNumber++;
+    gFitTableContext.FitEntryNumber++;
+  }
+
+  //
+  // Final: Check StartupAcm in BiosModule.
+  //
+  CheckOverlap (gFitTableContext.StartupAcm.Address, gFitTableContext.StartupAcm.Size);
+  FitEntryNumber = gFitTableContext.FitEntryNumber;
+  for (Index = 0; Index < (INTN)gFitTableContext.OptionalModuleNumber; Index++) {
+    if ((gFitTableContext.OptionalModule[Index].Type == FIT_TABLE_TYPE_BIOS_POLICY) ||
+        (gFitTableContext.OptionalModule[Index].Type == FIT_TABLE_TYPE_KEY_MANIFEST) ||
+        (gFitTableContext.OptionalModule[Index].Type == FIT_TABLE_TYPE_BOOT_POLICY_MANIFEST) ||
+        (gFitTableContext.OptionalModule[Index].Type == FIT_TABLE_TYPE_BIOS_DATA_AREA) ||
+        (gFitTableContext.OptionalModule[Index].Type == FIT_TABLE_TYPE_CSE_SECURE_BOOT)) {
+      // NOTE: It might be virtual address now. Just put a place holder.
+      FitEntryNumber ++;
+    }
+  }
+
+  return FitEntryNumber;
+}
+
+VOID *
+FindSpaceSkipApVector (
+  IN UINT8     *FvBuffer,
+  IN UINT8     *Address,
+  IN UINTN     Size
+  )
+/*++
+
+Routine Description:
+
+  No enough space - it might happen that it is occupied by AP wake vector.
+  Last chance - skip this and search again.
+
+Arguments:
+
+  FvBuffer       - FvRecovery binary buffer
+  Address        - Address to be searched from
+  Size           - Size need to be filled
+
+Returns:
+
+  FitTableOffset - The FIT table offset
+  NULL           - No enough space for FIT table
+
+*/
+{
+  UINT8        *ApVector;
+  UINT8        *NewAddress;
+  UINTN        Index;
+
+  ApVector = (UINT8 *)((UINTN)Address & ~0xFFF);
+  if ((UINTN)ApVector <= (UINTN)FvBuffer) {
+    return NULL;
+  }
+
+  NewAddress = (UINT8 *)(ApVector - Size);
+  for (Index = 0; Index < Size; Index ++) {
+    if (NewAddress[Index] != 0xFF) {
+      return NULL;
+    }
+  }
+  return NewAddress;
+}
+
+VOID *
+GetFreeSpaceFromFv (
+  IN UINT8     *FvBuffer,
+  IN UINT32    FvSize,
+  IN UINT32    FitEntryNumber
+  )
+/*++
+
+Routine Description:
+
+  Get free space for FIT table from FvRecovery
+
+Arguments:
+
+  FvBuffer       - FvRecovery binary buffer
+  FvSize         - FvRecovery size
+  FitEntryNumber - The FIT entry number
+
+Returns:
+
+  FitTableOffset - The offset of FIT table in FvRecovery file
+  NULL           - Free space not found
+
+--*/
+{
+  UINT8       *FitTableOffset;
+  INTN        Index;
+  INTN        SubIndex;
+  UINT8       *OptionalModuleAddress;
+  EFI_GUID    VTFGuid = EFI_FFS_VOLUME_TOP_FILE_GUID;
+  UINT32      AlignedSize;
+  UINT32      FitTableSize;
+
+  EFI_FIRMWARE_VOLUME_HEADER  *FvHeader;
+  EFI_FFS_FILE_HEADER         *FileHeader;
+  UINT64                      FvLength;
+  UINT32                      Offset;
+  UINT32                      FileLength;
+  UINT32                      FileOccupiedSize;
+
+  //
+  // Check 4G - FitTablePointerOffset
+  //
+  if ((*(UINT64 *)(FvBuffer + FvSize - gFitTableContext.FitTablePointerOffset) != 0xFFFFFFFFFFFFFFFFull) &&
+      (*(UINT64 *)(FvBuffer + FvSize - gFitTableContext.FitTablePointerOffset) != 0) &&
+      (*(UINT64 *)(FvBuffer + FvSize - gFitTableContext.FitTablePointerOffset) != 0xEEEEEEEEEEEEEEEEull)) {
+    Error (NULL, 0, 0, "4G - FitTablePointerOffset is occupied!", NULL);
+    return NULL;
+  }
+  if (gFitTableContext.FitTablePointerOffset2 != 0) {
+    if ((*(UINT64 *)(FvBuffer + FvSize - gFitTableContext.FitTablePointerOffset2) != 0xFFFFFFFFFFFFFFFFull) &&
+        (*(UINT64 *)(FvBuffer + FvSize - gFitTableContext.FitTablePointerOffset2) != 0) &&
+        (*(UINT64 *)(FvBuffer + FvSize - gFitTableContext.FitTablePointerOffset2) != 0xEEEEEEEEEEEEEEEEull)) {
+      Error (NULL, 0, 0, "4G - FitTablePointerOffset is occupied!", NULL);
+      return NULL;
+    }
+  }
+
+  //
+  // Get EFI_FFS_VOLUME_TOP_FILE_GUID location
+  //
+  FitTableOffset = NULL;
+
+  FvHeader         = (EFI_FIRMWARE_VOLUME_HEADER *)FvBuffer;
+  FvLength         = FvHeader->FvLength;
+  FileHeader       = (EFI_FFS_FILE_HEADER *)(FvBuffer + FvHeader->HeaderLength);
+  Offset           = (UINTN)FileHeader - (UINTN)FvBuffer;
+
+  while (Offset < FvLength) {
+    FileLength = (*(UINT32 *)(FileHeader->Size)) & 0x00FFFFFF;
+    FileOccupiedSize = GETOCCUPIEDSIZE(FileLength, 8);
+    if ((CompareGuid (&(FileHeader->Name), &VTFGuid)) == 0) {
+      // find it
+      FitTableOffset = (UINT8 *)FileHeader;
+      break;
+    }
+    FileHeader = (EFI_FFS_FILE_HEADER *)((UINTN)FileHeader + FileOccupiedSize);
+    Offset = (UINTN)FileHeader - (UINTN)FvBuffer;
+  }
+
+  if (FitTableOffset == NULL) {
+    Error (NULL, 0, 0, "EFI_FFS_VOLUME_TOP_FILE_GUID not found!", NULL);
+    return NULL;
+  }
+
+  FitTableSize = FitEntryNumber * sizeof(FIRMWARE_INTERFACE_TABLE_ENTRY);
+  FitTableSize += FIT_ALIGNMENT;
+  FitTableSize &= ~FIT_ALIGNMENT;
+
+  FitTableOffset = (UINT8 *)((UINTN)FitTableOffset & ~FIT_ALIGNMENT);
+  FitTableOffset = (UINT8 *)(FitTableOffset - FitTableSize);
+
+  //
+  // Check it
+  //
+  for (Index = 0; Index < (INTN)(FitTableSize); Index ++) {
+    if (FitTableOffset[Index] != 0xFF) {
+      //
+      // No enough space - it might happen that it is occupied by AP wake vector.
+      // Last chance - skip this and search again.
+      //
+      FitTableOffset = FindSpaceSkipApVector (FvBuffer, &FitTableOffset[Index], FitTableSize);
+      if (FitTableOffset == NULL) {
+        Error (NULL, 0, 0, "No enough space for FIT table!", NULL);
+        return NULL;
+      }
+    }
+  }
+
+  //
+  // Check space for Optional module
+  //
+  OptionalModuleAddress = FitTableOffset;
+  for (Index = 0; Index < (INTN)gFitTableContext.OptionalModuleNumber; Index++) {
+    AlignedSize = gFitTableContext.OptionalModule[Index].Size;
+    if ((gFitTableContext.OptionalModule[Index].Size & 0x80000000) != 0) {
+
+      //
+      // Need copy binary to file.
+      //
+      gFitTableContext.OptionalModule[Index].Size &= ~0x80000000;
+
+      AlignedSize = gFitTableContext.OptionalModule[Index].Size;
+      if ((gFitTableContext.OptionalModule[Index].Type == FIT_TABLE_TYPE_BIOS_POLICY) ||
+          (gFitTableContext.OptionalModule[Index].Type == FIT_TABLE_TYPE_KEY_MANIFEST) ||
+          (gFitTableContext.OptionalModule[Index].Type == FIT_TABLE_TYPE_BOOT_POLICY_MANIFEST) ||
+          (gFitTableContext.OptionalModule[Index].Type == FIT_TABLE_TYPE_BIOS_DATA_AREA) ||
+          (gFitTableContext.OptionalModule[Index].Type == FIT_TABLE_TYPE_CSE_SECURE_BOOT)) {
+        // Let it 64 byte align
+        AlignedSize += BIOS_MODULE_ALIGNMENT;
+        AlignedSize &= ~BIOS_MODULE_ALIGNMENT;
+      }
+
+      OptionalModuleAddress -= AlignedSize;
+
+      if ((gFitTableContext.OptionalModule[Index].Type == FIT_TABLE_TYPE_BIOS_POLICY) ||
+          (gFitTableContext.OptionalModule[Index].Type == FIT_TABLE_TYPE_KEY_MANIFEST) ||
+          (gFitTableContext.OptionalModule[Index].Type == FIT_TABLE_TYPE_BOOT_POLICY_MANIFEST) ||
+          (gFitTableContext.OptionalModule[Index].Type == FIT_TABLE_TYPE_BIOS_DATA_AREA) ||
+          (gFitTableContext.OptionalModule[Index].Type == FIT_TABLE_TYPE_CSE_SECURE_BOOT)) {
+        // Let it 64 byte align
+        OptionalModuleAddress = (UINT8 *)((UINTN)OptionalModuleAddress & ~BIOS_MODULE_ALIGNMENT);
+      }
+
+      for (SubIndex = 0; SubIndex < (INTN)(AlignedSize); SubIndex ++) {
+        if (OptionalModuleAddress[SubIndex] != 0xFF) {
+          //
+          // No enough space - it might happen that it is occupied by AP wake vector.
+          // Last chance - skip this and search again.
+          //
+          OptionalModuleAddress = FindSpaceSkipApVector (FvBuffer, &OptionalModuleAddress[SubIndex], AlignedSize);
+          if (OptionalModuleAddress == NULL) {
+            Error (NULL, 0, 0, "No enough space for OptionalModule!", NULL);
+            return NULL;
+          }
+        }
+      }
+      memcpy (OptionalModuleAddress, (VOID *) (UINTN) gFitTableContext.OptionalModule[Index].Address, gFitTableContext.OptionalModule[Index].Size);
+      free ((VOID *) (UINTN) gFitTableContext.OptionalModule[Index].Address);
+      gFitTableContext.OptionalModule[Index].Address = MEMORY_TO_FLASH (OptionalModuleAddress, FvBuffer, FvSize);
+    }
+    //
+    // Final: Check BiosPolicyData in BiosModule.
+    //
+    if ((gFitTableContext.OptionalModule[Index].Type == FIT_TABLE_TYPE_BIOS_POLICY) ||
+        (gFitTableContext.OptionalModule[Index].Type == FIT_TABLE_TYPE_KEY_MANIFEST) ||
+        (gFitTableContext.OptionalModule[Index].Type == FIT_TABLE_TYPE_BOOT_POLICY_MANIFEST) ||
+        (gFitTableContext.OptionalModule[Index].Type == FIT_TABLE_TYPE_BIOS_DATA_AREA) ||
+        (gFitTableContext.OptionalModule[Index].Type == FIT_TABLE_TYPE_CSE_SECURE_BOOT)) {
+      CheckOverlap (gFitTableContext.OptionalModule[Index].Address, AlignedSize);
+    }
+  }
+
+  return FitTableOffset;
+}
+
+VOID
+PrintFitData (
+  VOID
+  )
+/*++
+
+Routine Description:
+
+  Output FIT table information
+
+Arguments:
+
+  None
+
+Returns:
+
+  None
+
+--*/
+{
+  UINT32                          Index;
+
+  printf ("FIT Table Pointer Offset: 0x%x\n", gFitTableContext.FitTablePointerOffset);
+  if (gFitTableContext.FitTablePointerOffset2 != 0) {
+    printf ("FIT Table Pointer Offset: 0x%x\n", gFitTableContext.FitTablePointerOffset2);
+  }
+  printf ("Total FIT Entry number: 0x%x\n", gFitTableContext.FitEntryNumber);
+  printf ("FitHeader version: 0x%04x\n", gFitTableContext.FitHeaderVersion);
+  if (gFitTableContext.StartupAcm.Address != 0) {
+    printf ("StartupAcm - (0x%08x, 0x%08x, 0x%04x)\n", gFitTableContext.StartupAcm.Address, gFitTableContext.StartupAcm.Size, gFitTableContext.StartupAcmVersion);
+  }
+  for (Index = 0; Index < gFitTableContext.BiosModuleNumber; Index++) {
+    printf ("BiosModule[%d] - (0x%08x, 0x%08x, 0x%04x)\n", Index, gFitTableContext.BiosModule[Index].Address, gFitTableContext.BiosModule[Index].Size, gFitTableContext.BiosModuleVersion);
+  }
+  for (Index = 0; Index < gFitTableContext.MicrocodeNumber; Index++) {
+    printf ("Microcode[%d] - (0x%08x, 0x%08x, 0x%04x)\n", Index, gFitTableContext.Microcode[Index].Address, gFitTableContext.Microcode[Index].Size, gFitTableContext.MicrocodeVersion);
+  }
+  for (Index = 0; Index < gFitTableContext.OptionalModuleNumber; Index++) {
+    printf ("OptionalModule[%d] - (0x%08x, 0x%08x, 0x%02x, 0x%04x)\n", Index, gFitTableContext.OptionalModule[Index].Address, gFitTableContext.OptionalModule[Index].Size, gFitTableContext.OptionalModule[Index].Type, gFitTableContext.OptionalModule[Index].Version);
+  }
+  for (Index = 0; Index < gFitTableContext.PortModuleNumber; Index++) {
+    printf ("PortModule[%d] - (0x%04x, 0x%04x, 0x%02x, 0x%02x, 0x%04x, 0x%02x, 0x%04x)\n", Index,
+      (UINT16)gFitTableContext.PortModule[Index].Address, (UINT16)(gFitTableContext.PortModule[Index].Address >> 16),
+      (UINT8)gFitTableContext.PortModule[Index].Size, (UINT8)(gFitTableContext.PortModule[Index].Size >> 8), (UINT16)(gFitTableContext.PortModule[Index].Size >> 16),
+      gFitTableContext.PortModule[Index].Type, gFitTableContext.PortModule[Index].Version);
+  }
+
+  printf ("\n");
+  return ;
+}
+
+CHAR8 *mFitTypeStr[] = {
+  "           ",
+  "MICROCODE  ",
+  "STARTUP_ACM",
+  "           ",
+  "           ",
+  "           ",
+  "           ",
+  "BIOS_MODULE",
+  "TPM_POLICY ",
+  "BIOS_POLICY",
+  "TXT_POLICY ",
+  "KEYMANIFEST",
+  "BP_MANIFEST",
+  "BIOS_DATA_A",
+  " ",
+  " ",
+  "CSE_SECUREB"
+};
+
+CHAR8  mFitSignature[] = "'_FIT_   ' ";
+CHAR8  mFitSignatureInHeader[] = "'        ' ";
+CHAR8 *
+FitTypeToStr (
+  IN FIRMWARE_INTERFACE_TABLE_ENTRY  *FitEntry
+  )
+/*++
+
+Routine Description:
+
+  Convert FitEntry type to a string
+
+Arguments:
+
+  FitEntry - Fit entry
+
+Returns:
+
+  String
+
+--*/
+{
+  if (FitEntry->Type == FIT_TABLE_TYPE_HEADER) {
+    CopyMem (&mFitSignatureInHeader[1], &FitEntry->Address, sizeof(FitEntry->Address));
+    return mFitSignatureInHeader;
+  }
+  if (FitEntry->Type < sizeof (mFitTypeStr)/sizeof(mFitTypeStr[0])) {
+    return mFitTypeStr[FitEntry->Type];
+  } else {
+    return "           ";
+  }
+}
+
+VOID
+PrintFitTable (
+  IN UINT8                       *FvBuffer,
+  IN UINT32                      FvSize
+  )
+/*++
+
+Routine Description:
+
+  Print Fit table in flash image
+
+Arguments:
+
+  FvBuffer       - FvRecovery binary buffer
+  FvSize         - FvRecovery size
+
+Returns:
+
+  None
+
+--*/
+{
+  FIRMWARE_INTERFACE_TABLE_ENTRY  *FitEntry;
+  UINT32                          EntryNum;
+  UINT32                          Index;
+  UINT32                          FitTableOffset;
+  FIRMWARE_INTERFACE_TABLE_ENTRY_PORT   *FitEntryPort;
+
+  printf ("##############\n");
+  printf ("# FIT Table: #\n");
+  printf ("##############\n");
+
+  printf ("FIT Pointer Offset: 0x%x\n", gFitTableContext.FitTablePointerOffset);
+  FitTableOffset = *(UINT32 *)(FvBuffer + FvSize - gFitTableContext.FitTablePointerOffset);
+  printf ("FIT Table Address:  0x%x\n", FitTableOffset);
+  FitEntry = (FIRMWARE_INTERFACE_TABLE_ENTRY *)FLASH_TO_MEMORY(FitTableOffset, FvBuffer, FvSize);
+
+  //
+  // Check FitEntry is 16 byte aligned
+  //
+  if (((UINTN)FitEntry & 0xF) != 0) {
+    printf("ERROR: invalid FitEntry address 0x%X!\n", (UINT32) (UINTN) FitEntry);
+    return;
+  }
+
+  EntryNum = *(UINT32 *)(&FitEntry[0].Size[0]) & 0xFFFFFF;
+  printf ("====== ================ ====== ======== ============== ==== ======== (====== ==== ====== ==== ======)\n");
+  printf ("Index:      Address      Size  Version       Type      C_V  Checksum (Index  Data Width  Bit  Offset)\n");
+  printf ("====== ================ ====== ======== ============== ==== ======== (====== ==== ====== ==== ======)\n");
+  for (Index = 0; Index < EntryNum; Index++) {
+    printf (" %02d:   %016llx %06x   %04x   %02x-%s  %02x     %02x   ",
+      Index,
+      (unsigned long long) FitEntry[Index].Address,
+      *(UINT32 *)(&FitEntry[Index].Size[0]) & 0xFFFFFF,
+      FitEntry[Index].Version,
+      FitEntry[Index].Type,
+      FitTypeToStr(&FitEntry[Index]),
+      FitEntry[Index].C_V,
+      FitEntry[Index].Checksum
+      );
+
+    if (Index == 0) {
+      if (FitEntry[Index].Type != FIT_TABLE_TYPE_HEADER) {
+        printf("ERROR: FIT Entry 0 is not Header Type %d!\n", FIT_TABLE_TYPE_HEADER);
+        return;
+      }
+      if (strcmp(mFitSignatureInHeader, mFitSignature) != 0) {
+        printf("ERROR: FIT Entry 0 signature invalid (%s, expected %s)!\n", mFitSignatureInHeader, mFitSignature);
+        return;
+      }
+
+    }
+
+    switch (FitEntry[Index].Type) {
+    case FIT_TABLE_TYPE_TPM_POLICY:
+    case FIT_TABLE_TYPE_TXT_POLICY:
+      if (FitEntry[Index].Version == 0) {
+        FitEntryPort = (FIRMWARE_INTERFACE_TABLE_ENTRY_PORT *)&FitEntry[Index];
+        printf (" ( %04x  %04x   %02x    %02x   %04x )\n",
+          FitEntryPort->IndexPort,
+          FitEntryPort->DataPort,
+          FitEntryPort->Width,
+          FitEntryPort->Bit,
+          FitEntryPort->Index
+          );
+        break;
+      }
+      // Not Port Configure, pass through
+    default:
+      printf ("\n");
+      break;
+    }
+  }
+  printf ("====== ================ ====== ======== ============== ==== ======== (====== ==== ====== ==== ======)\n");
+  printf ("Index:      Address      Size  Version       Type      C_V  Checksum (Index  Data Width  Bit  Offset)\n");
+  printf ("====== ================ ====== ======== ============== ==== ======== (====== ==== ====== ==== ======)\n");
+}
+
+/**
+
+  This function dump raw data.
+
+  @param  Data  raw data
+  @param  Size  raw data size
+
+**/
+VOID
+DumpData (
+  IN UINT8  *Data,
+  IN UINT32 Size
+  )
+{
+  UINT32 Index;
+  for (Index = 0; Index < Size; Index++) {
+    printf ("%02x", Data[Index]);
+  }
+}
+
+/**
+
+  This function dump raw data with colume format.
+
+  @param  Data  raw data
+  @param  Size  raw data size
+
+**/
+VOID
+DumpHex (
+  IN UINT8  *Data,
+  IN UINT32 Size
+  )
+{
+  UINT32  Index;
+  UINT32  Count;
+  UINT32  Left;
+
+#define COLUME_SIZE  (16 * 2)
+
+  Count = Size / COLUME_SIZE;
+  Left  = Size % COLUME_SIZE;
+  for (Index = 0; Index < Count; Index++) {
+    printf ("%04x: ", Index * COLUME_SIZE);
+    DumpData (Data + Index * COLUME_SIZE, COLUME_SIZE);
+    printf ("\n");
+  }
+
+  if (Left != 0) {
+    printf ("%04x: ", Index * COLUME_SIZE);
+    DumpData (Data + Index * COLUME_SIZE, Left);
+    printf ("\n");
+  }
+}
+
+//
+// This table defines the ACM type string
+//
+CHAR8 *mAcmTypeStr[] = {
+  "BIOS ACM",
+  "SINIT ACM",
+};
+
+//
+// This table defines the ACM capability string
+//
+CHAR8 *mCapabilityStr[] = {
+  "GETSEC[WAKEUP] for RLP   ",
+  "MONITOR address for RLP  ",
+  "ECX for MLE PageTable    ",
+  "STM support              ",
+};
+
+VOID
+DumpAcm (
+  IN ACM_FORMAT                    *Acm
+  )
+/*++
+
+Routine Description:
+
+  DumpAcm information
+
+Arguments:
+
+  Acm       - ACM buffer
+
+Returns:
+
+  None
+
+--*/
+{
+  CHIPSET_ACM_INFORMATION_TABLE *ChipsetAcmInformationTable;
+  CHIPSET_ID_LIST               *ChipsetIdList;
+  PROCESSOR_ID_LIST             *ProcessorIdList;
+  UINT32                        Index;
+  UINT8                         *Buffer;
+
+  printf (
+    "*****************************************************************************\n"
+    "*         ACM                                                               *\n"
+    "*****************************************************************************\n"
+    );
+
+  printf ("ACM: (%08x)\n", (UINT32) (UINTN) Acm);
+  printf ("  ModuleType                 - %04x\n", Acm->ModuleType);
+  if (Acm->ModuleType == ACM_MODULE_TYPE_CHIPSET_ACM) {
+    printf ("    Chipset ACM\n");
+  }
+  printf ("  ModuleSubType              - %04x\n", Acm->ModuleSubType);
+  if ((Acm->ModuleSubType & ACM_MODULE_SUBTYPE_CAPABLE_OF_EXECUTE_AT_RESET) != 0) {
+    printf ("    Capable of be Executed at Reset\n");
+  }
+  if ((Acm->ModuleSubType & ACM_MODULE_SUBTYPE_ANC_MODULE) != 0) {
+    printf ("    AnC Module\n");
+  }
+  printf ("  HeaderLen                  - %08x\n", Acm->HeaderLen);
+  printf ("  HeaderVersion              - %08x\n", Acm->HeaderVersion);
+  printf ("  ChipsetID                  - %04x\n", Acm->ChipsetID);
+  printf ("  Flags                      - %04x\n", Acm->Flags);
+  printf ("    PreProduction            - %04x\n", Acm->Flags & ACM_MODULE_FLAG_PREPRODUCTION);
+  printf ("    Debug Signed             - %04x\n", Acm->Flags & ACM_MODULE_FLAG_DEBUG_SIGN);
+  printf ("  ModuleVendor               - %08x\n", Acm->ModuleVendor);
+  printf ("  Date                       - %08x\n", Acm->Date);
+  printf ("  Size                       - %08x\n", Acm->Size);
+  printf ("  TxtSvn                     - %04x\n", Acm->TxtSvn);
+  printf ("  SeSvn                      - %04x\n", Acm->SeSvn);
+  printf ("  CodeControl                - %08x\n", Acm->CodeControl);
+  printf ("  ErrorEntryPoint            - %08x\n", Acm->ErrorEntryPoint);
+  printf ("  GDTLimit                   - %08x\n", Acm->GDTLimit);
+  printf ("  GDTBasePtr                 - %08x\n", Acm->GDTBasePtr);
+  printf ("  SegSel                     - %08x\n", Acm->SegSel);
+  printf ("  EntryPoint                 - %08x\n", Acm->EntryPoint);
+  printf ("  KeySize                    - %08x\n", Acm->KeySize);
+  printf ("  ScratchSize                - %08x\n", Acm->ScratchSize);
+
+  Buffer = (UINT8 *)(Acm + 1);
+  printf ("  RSAPubKey                  - \n");
+  DumpHex (Buffer, Acm->KeySize * 4);
+  printf ("\n");
+  Buffer += Acm->KeySize * 4;
+
+  if (Acm->HeaderVersion == ACM_HEADER_VERSION_3) {
+    printf ("  RSASig                     - \n");
+    DumpHex (Buffer, ACM_PKCS_1_5_RSA_SIGNATURE_SHA384_SIZE); // PKCS #1.5 RSA Signature
+    printf ("\n");
+    Buffer += ACM_PKCS_1_5_RSA_SIGNATURE_SHA384_SIZE;
+  } else {
+    printf ("  RSAPubExp                  - %08x\n", *(UINT32 *)Buffer);
+    Buffer += 4;
+
+    printf ("  RSASig                     - \n");
+    DumpHex (Buffer, ACM_PKCS_1_5_RSA_SIGNATURE_SHA256_SIZE); // PKCS #1.5 RSA Signature
+    printf ("\n");
+    Buffer += ACM_PKCS_1_5_RSA_SIGNATURE_SHA256_SIZE;
+  }
+  Buffer += Acm->ScratchSize * 4;
+
+  if ((Acm->ModuleSubType & ACM_MODULE_SUBTYPE_ANC_MODULE) == 0) {
+    ChipsetAcmInformationTable = (CHIPSET_ACM_INFORMATION_TABLE *)Buffer;
+    printf ("Chipset ACM info:\n");
+    printf (
+      "  Guid                       - {%08x-%08x-%08x-%08x}\n",
+      ChipsetAcmInformationTable->Guid.Guid0,
+      ChipsetAcmInformationTable->Guid.Guid1,
+      ChipsetAcmInformationTable->Guid.Guid2,
+      ChipsetAcmInformationTable->Guid.Guid3
+      );
+    printf ("  ChipsetACMType             - %02x\n", ChipsetAcmInformationTable->ChipsetACMType);
+    if (ChipsetAcmInformationTable->ChipsetACMType < sizeof(mAcmTypeStr)/sizeof(mAcmTypeStr[0])) {
+      printf ("    %s\n", mAcmTypeStr[ChipsetAcmInformationTable->ChipsetACMType]);
+    }
+    printf ("  Version                    - %02x\n", ChipsetAcmInformationTable->Version);
+    printf ("  Length                     - %04x\n", ChipsetAcmInformationTable->Length);
+    printf ("  ChipsetIDList              - %08x\n", ChipsetAcmInformationTable->ChipsetIDList);
+    printf ("  OsSinitTableVer            - %08x\n", ChipsetAcmInformationTable->OsSinitTableVer);
+    printf ("  MinMleHeaderVer            - %08x\n", ChipsetAcmInformationTable->MinMleHeaderVer);
+    if (ChipsetAcmInformationTable->Version >= CHIPSET_ACM_INFORMATION_TABLE_VERSION_3) {
+      printf ("  Capabilities               - %08x\n", ChipsetAcmInformationTable->Capabilities);
+      for (Index = 0; Index < sizeof(mCapabilityStr)/sizeof(mCapabilityStr[0]); Index++) {
+        if (mCapabilityStr[Index] == NULL) {
+          continue;
+        }
+        printf (
+          "    %s- %08x\n",
+          mCapabilityStr[Index],
+          (ChipsetAcmInformationTable->Capabilities & (1 << Index))
+          );
+      }
+      printf ("  AcmVersion                 - %02x\n", ChipsetAcmInformationTable->AcmVersion);
+      printf ("  AcmRevision                - %02x.%02x.%02x\n", ChipsetAcmInformationTable->AcmRevision[0], ChipsetAcmInformationTable->AcmRevision[1], ChipsetAcmInformationTable->AcmRevision[2]);
+    }
+    if (ChipsetAcmInformationTable->Version >= CHIPSET_ACM_INFORMATION_TABLE_VERSION_4) {
+      printf ("  ProcessorIDList            - %08x\n", ChipsetAcmInformationTable->ProcessorIDList);
+    }
+
+    ChipsetIdList = (CHIPSET_ID_LIST *)((UINTN)Acm + ChipsetAcmInformationTable->ChipsetIDList);
+    printf ("Chipset ID List info:\n");
+    printf ("  Count                      - %08x\n", ChipsetIdList->Count);
+    for (Index = 0; Index < ChipsetIdList->Count; Index++) {
+      printf ("  ID[%d]:\n", Index);
+      printf ("    Flags                    - %08x\n", ChipsetIdList->ChipsetID[Index].Flags);
+      printf ("      RevisionIdMask         - %08x\n", ChipsetIdList->ChipsetID[Index].Flags & ACM_CHIPSET_ID_REVISION_ID_MAKE);
+      printf ("    VendorID                 - %04x\n", ChipsetIdList->ChipsetID[Index].VendorID);
+      printf ("    DeviceID                 - %04x\n", ChipsetIdList->ChipsetID[Index].DeviceID);
+      printf ("    RevisionID               - %04x\n", ChipsetIdList->ChipsetID[Index].RevisionID);
+    }
+    if (ChipsetAcmInformationTable->Version < CHIPSET_ACM_INFORMATION_TABLE_VERSION_4) {
+      goto End;
+    }
+    ProcessorIdList = (PROCESSOR_ID_LIST *)((UINTN)Acm + ChipsetAcmInformationTable->ProcessorIDList);
+    printf ("Processor ID List info:\n");
+    printf ("  Count                      - %08x\n", ProcessorIdList->Count);
+    for (Index = 0; Index < ProcessorIdList->Count; Index++) {
+      printf ("  ID[%d]:\n", Index);
+      printf ("    FMS                      - %08x\n", ProcessorIdList->ProcessorID[Index].FMS);
+      printf ("    FMSMask                  - %08x\n", ProcessorIdList->ProcessorID[Index].FMSMask);
+      printf ("    PlatformID               - %016llx\n", (unsigned long long) ProcessorIdList->ProcessorID[Index].PlatformID);
+      printf ("    PlatformMask             - %016llx\n", (unsigned long long) ProcessorIdList->ProcessorID[Index].PlatformMask);
+    }
+  }
+
+End:
+  printf (
+    "*****************************************************************************\n\n"
+    );
+}
+
+BOOLEAN
+CheckAcm (
+  IN ACM_FORMAT                        *Acm,
+  IN UINTN                             AcmMaxSize
+  )
+/*++
+
+Routine Description:
+
+  Check Acm information
+
+Arguments:
+
+  Acm        - ACM buffer
+  AcmMaxSize - ACM max size
+
+Returns:
+
+  TRUE  - ACM is valid
+  FALSE - ACM is invalid
+
+--*/
+{
+  CHIPSET_ACM_INFORMATION_TABLE *ChipsetAcmInformationTable;
+  CHIPSET_ID_LIST               *ChipsetIdList;
+  PROCESSOR_ID_LIST             *ProcessorIdList;
+  UINT8                         *Buffer;
+
+  if (Acm->ModuleType != ACM_MODULE_TYPE_CHIPSET_ACM) {
+    printf ("ACM invalid : ModuleType!\n");
+    return FALSE;
+  }
+  if (Acm->Size * 4 > AcmMaxSize) {
+    printf ("ACM invalid : Size!\n");
+    return FALSE;
+  }
+
+  Buffer = (UINT8 *)(Acm + 1);
+  Buffer += Acm->KeySize * 4;
+  if (Acm->HeaderVersion == ACM_HEADER_VERSION_3) {
+    Buffer += ACM_PKCS_1_5_RSA_SIGNATURE_SHA384_SIZE;
+  } else {
+    Buffer += 4;
+    Buffer += ACM_PKCS_1_5_RSA_SIGNATURE_SHA256_SIZE;
+  }
+  Buffer += Acm->ScratchSize * 4;
+
+  if ((Acm->ModuleSubType & ACM_MODULE_SUBTYPE_ANC_MODULE) == 0) {
+    ChipsetAcmInformationTable = (CHIPSET_ACM_INFORMATION_TABLE *)Buffer;
+    if ((UINTN)ChipsetAcmInformationTable >= (UINTN)Acm + AcmMaxSize) {
+      printf ("ACM invalid : ChipsetAcmInformationTable!\n");
+      return FALSE;
+    }
+
+    if (CompareGuid ((EFI_GUID *)&ChipsetAcmInformationTable->Guid, (EFI_GUID *)&mChipsetAcmInformationTableGuid03) != 0) {
+      printf ("ACM invalid : ChipsetACMGuid!\n");
+      return FALSE;
+    }
+    if (ChipsetAcmInformationTable->ChipsetACMType != CHIPSET_ACM_TYPE_BIOS) {
+      printf ("ACM invalid : ChipsetACMType!\n");
+      return FALSE;
+    }
+    if (ChipsetAcmInformationTable->Version < CHIPSET_ACM_INFORMATION_TABLE_VERSION_3) {
+      printf ("ACM invalid : ChipsetACMVersion!\n");
+      return FALSE;
+    }
+    if ((UINTN)ChipsetAcmInformationTable + ChipsetAcmInformationTable->Length > (UINTN)Acm + AcmMaxSize) {
+      printf ("ACM invalid : ChipsetACMLength!\n");
+      return FALSE;
+    }
+
+    if (ChipsetAcmInformationTable->ChipsetIDList >= AcmMaxSize) {
+      printf ("ACM invalid : ChipsetACMChipsetIDList!\n");
+      return FALSE;
+    }
+    ChipsetIdList = (CHIPSET_ID_LIST *)((UINTN)Acm + ChipsetAcmInformationTable->ChipsetIDList);
+    if (ChipsetIdList->Count == 0) {
+      printf ("ACM invalid : ChipsetACMChipsetIDListCount!\n");
+      return FALSE;
+    }
+    if (ChipsetAcmInformationTable->ChipsetIDList + sizeof(CHIPSET_ID_LIST) + (ChipsetIdList->Count - 1) * sizeof(ACM_CHIPSET_ID) > AcmMaxSize) {
+      printf ("ACM invalid : ChipsetACMChipsetIDList!\n");
+      return FALSE;
+    }
+
+    if (ChipsetAcmInformationTable->Version < CHIPSET_ACM_INFORMATION_TABLE_VERSION_4) {
+      goto End;
+    }
+
+    if (ChipsetAcmInformationTable->ProcessorIDList >= AcmMaxSize) {
+      printf ("ACM invalid : ChipsetACMProcessorIDList!\n");
+      return FALSE;
+    }
+    ProcessorIdList = (PROCESSOR_ID_LIST *)((UINTN)Acm + ChipsetAcmInformationTable->ProcessorIDList);
+    if (ProcessorIdList->Count == 0) {
+      printf ("ACM invalid : ChipsetACMProcessorIdListCount!\n");
+      return FALSE;
+    }
+    if (ChipsetAcmInformationTable->ChipsetIDList + sizeof(PROCESSOR_ID_LIST) + (ChipsetIdList->Count - 1) * sizeof(ACM_PROCESSOR_ID) > AcmMaxSize) {
+      printf ("ACM invalid : ChipsetACMProcessorIdList!\n");
+      return FALSE;
+    }
+  }
+
+End:
+
+  return TRUE;
+}
+
+VOID
+FillFitTable (
+  IN UINT8     *FvBuffer,
+  IN UINT32    FvSize,
+  IN UINT8     *FitTableOffset
+  )
+/*++
+
+Routine Description:
+
+  Fill the FIT table information to FvRecovery
+
+Arguments:
+
+  FvBuffer       - FvRecovery binary buffer
+  FvSize         - FvRecovery size
+  FitTableOffset - The offset of FIT table in FvRecovery file
+
+Returns:
+
+  None
+
+--*/
+{
+  FIRMWARE_INTERFACE_TABLE_ENTRY *FitEntry;
+  UINT32                          FitIndex;
+  UINT32                          Index;
+  UINT8                           Checksum;
+  UINTN                           SubIndex;
+  FIT_TABLE_CONTEXT_ENTRY         TempContextEntry;
+  FIRMWARE_INTERFACE_TABLE_ENTRY  TempTableEntry;
+
+  //
+  // 1. FitPointer
+  //
+  *(UINT64 *)(FvBuffer + FvSize - gFitTableContext.FitTablePointerOffset) = (UINT64)(UINTN)MEMORY_TO_FLASH (FitTableOffset, FvBuffer, FvSize);
+  if (gFitTableContext.FitTablePointerOffset2 != 0) {
+    *(UINT64 *)(FvBuffer + FvSize - gFitTableContext.FitTablePointerOffset2) = (UINT64)(UINTN)MEMORY_TO_FLASH (FitTableOffset, FvBuffer, FvSize);
+  }
+
+  FitEntry = (FIRMWARE_INTERFACE_TABLE_ENTRY *)FitTableOffset;
+  FitIndex = 0;
+
+  //
+  // 2. FitHeader
+  //
+  FitEntry[FitIndex].Address             = *(UINT64 *)"_FIT_   ";
+  *(UINT32 *)&FitEntry[FitIndex].Size[0] = gFitTableContext.FitEntryNumber;
+  FitEntry[FitIndex].Version             = (UINT16)gFitTableContext.FitHeaderVersion;
+  FitEntry[FitIndex].Type                = FIT_TABLE_TYPE_HEADER;
+  FitEntry[FitIndex].C_V                 = 1;
+  //
+  // Checksum will be updated later...
+  //
+  FitEntry[FitIndex].Checksum            = 0;
+
+  //
+  // 3. Microcode
+  //
+  FitIndex++;
+  for (Index = 0; Index < gFitTableContext.MicrocodeNumber; Index++) {
+    FitEntry[FitIndex].Address             = gFitTableContext.Microcode[Index].Address;
+    *(UINT32 *)&FitEntry[FitIndex].Size[0] = 0; //gFitTableContext.Microcode[Index].Size / 16;
+    FitEntry[FitIndex].Version             = (UINT16)gFitTableContext.MicrocodeVersion;
+    FitEntry[FitIndex].Type                = FIT_TABLE_TYPE_MICROCODE;
+    FitEntry[FitIndex].C_V                 = 0;
+    FitEntry[FitIndex].Checksum            = 0;
+    FitIndex++;
+  }
+
+  //
+  // 4. StartupAcm
+  //
+  if (gFitTableContext.StartupAcm.Address != 0) {
+    FitEntry[FitIndex].Address             = gFitTableContext.StartupAcm.Address;
+    *(UINT32 *)&FitEntry[FitIndex].Size[0] = 0; //gFitTableContext.StartupAcm.Size / 16;
+    FitEntry[FitIndex].Version             = (UINT16)gFitTableContext.StartupAcmVersion;
+    FitEntry[FitIndex].Type                = FIT_TABLE_TYPE_STARTUP_ACM;
+    FitEntry[FitIndex].C_V                 = 0;
+    FitEntry[FitIndex].Checksum            = 0;
+    FitIndex++;
+  }
+
+  //
+  // 5. BiosModule
+  //
+  //
+  // BiosModule segments order needs to be put from low addresss to high for Btg requirement
+  //
+  if (gFitTableContext.BiosModuleNumber > 1) {
+    for (Index = 0; Index < (UINTN)gFitTableContext.BiosModuleNumber - 1; Index++){
+      for (SubIndex = 0; SubIndex < gFitTableContext.BiosModuleNumber - Index - 1; SubIndex++) {
+        if (gFitTableContext.BiosModule[SubIndex].Address > gFitTableContext.BiosModule[SubIndex + 1].Address) {
+          CopyMem (&TempContextEntry, &gFitTableContext.BiosModule[SubIndex], sizeof(FIT_TABLE_CONTEXT_ENTRY));
+          CopyMem (&gFitTableContext.BiosModule[SubIndex], &gFitTableContext.BiosModule[SubIndex + 1], sizeof(FIT_TABLE_CONTEXT_ENTRY));
+          CopyMem (&gFitTableContext.BiosModule[SubIndex + 1], &TempContextEntry, sizeof(FIT_TABLE_CONTEXT_ENTRY));
+        }
+      }
+    }
+  }
+  for (Index = 0; Index < gFitTableContext.BiosModuleNumber; Index++) {
+    FitEntry[FitIndex].Address             = gFitTableContext.BiosModule[Index].Address;
+    *(UINT32 *)&FitEntry[FitIndex].Size[0] = gFitTableContext.BiosModule[Index].Size / 16;
+    FitEntry[FitIndex].Version             = (UINT16)gFitTableContext.BiosModuleVersion;
+    FitEntry[FitIndex].Type                = FIT_TABLE_TYPE_BIOS_MODULE;
+    FitEntry[FitIndex].C_V                 = 0;
+    FitEntry[FitIndex].Checksum            = 0;
+    FitIndex++;
+  }
+
+  //
+  // 6. Optional module
+  //
+  for (Index = 0; Index < gFitTableContext.OptionalModuleNumber; Index++) {
+    FitEntry[FitIndex].Address             = gFitTableContext.OptionalModule[Index].Address;
+    *(UINT32 *)&FitEntry[FitIndex].Size[0] = gFitTableContext.OptionalModule[Index].Size;
+    FitEntry[FitIndex].Version             = (UINT16)gFitTableContext.OptionalModule[Index].Version;
+    FitEntry[FitIndex].Type                = (UINT8)gFitTableContext.OptionalModule[Index].Type;
+    FitEntry[FitIndex].C_V                 = 0;
+    FitEntry[FitIndex].Checksum            = 0;
+    FitIndex++;
+  }
+
+  //
+  // 7. Port module
+  //
+  for (Index = 0; Index < gFitTableContext.PortModuleNumber; Index++) {
+    FitEntry[FitIndex].Address             = gFitTableContext.PortModule[Index].Address + ((UINT64)gFitTableContext.PortModule[Index].Size << 32);
+    *(UINT32 *)&FitEntry[FitIndex].Size[0] = 0;
+    FitEntry[FitIndex].Version             = (UINT16)gFitTableContext.PortModule[Index].Version;
+    FitEntry[FitIndex].Type                = (UINT8)gFitTableContext.PortModule[Index].Type;
+    FitEntry[FitIndex].C_V                 = 0;
+    FitEntry[FitIndex].Checksum            = 0;
+    FitIndex++;
+  }
+
+  //
+  // The FIT records must always be arranged in the ascending order of their type attribute in the FIT.
+  //
+  for (Index = 0; Index < (UINTN)FitIndex - 1; Index++){
+    for (SubIndex = 0; SubIndex < FitIndex - Index - 1; SubIndex++) {
+      if (FitEntry[SubIndex].Type > FitEntry[SubIndex + 1].Type) {
+        CopyMem (&TempTableEntry, &FitEntry[SubIndex], sizeof(FIRMWARE_INTERFACE_TABLE_ENTRY));
+        CopyMem (&FitEntry[SubIndex], &FitEntry[SubIndex + 1], sizeof(FIRMWARE_INTERFACE_TABLE_ENTRY));
+        CopyMem (&FitEntry[SubIndex + 1], &TempTableEntry, sizeof(FIRMWARE_INTERFACE_TABLE_ENTRY));
+      }
+    }
+  }
+
+  //
+  // Update FIT header signature as final step
+  //
+  Checksum = CalculateChecksum8 ((UINT8 *)&FitEntry[0], sizeof (FIRMWARE_INTERFACE_TABLE_ENTRY) * FitIndex);
+  FitEntry[0].Checksum = Checksum;
+}
+
+VOID
+ClearFitTable (
+  IN UINT8     *FvBuffer,
+  IN UINT32    FvSize
+  )
+/*++
+
+Routine Description:
+
+  Clear the FIT table information to Fvrecovery
+
+Arguments:
+
+  FvBuffer       - Fvrecovery binary buffer
+  FvSize         - Fvrecovery size
+
+Returns:
+
+  None
+
+--*/
+{
+  FIRMWARE_INTERFACE_TABLE_ENTRY *FitEntry;
+  UINT32                          EntryNum;
+  UINT32                          FitIndex;
+  UINT64                          FitTablePointer;
+  UINT8                           *Buffer;
+  UINT32                          BufferSize;
+
+  FitTablePointer = *(UINT64 *)(FvBuffer + FvSize - gFitTableContext.FitTablePointerOffset);
+  FitEntry = (FIRMWARE_INTERFACE_TABLE_ENTRY *)FLASH_TO_MEMORY (FitTablePointer, FvBuffer, FvSize);
+
+  //
+  // Clear FIT pointer
+  //
+  *(UINT64 *)(FvBuffer + FvSize - gFitTableContext.FitTablePointerOffset) = 0xEEEEEEEEEEEEEEEEull;
+  if (gFitTableContext.FitTablePointerOffset2 != 0) {
+    *(UINT64 *)(FvBuffer + FvSize - gFitTableContext.FitTablePointerOffset2) = 0xEEEEEEEEEEEEEEEEull;
+  }
+
+  //
+  // Clear FIT table
+  //
+  EntryNum = *(UINT32 *)(&FitEntry[0].Size[0]) & 0xFFFFFF;
+  for (FitIndex = 0; FitIndex < EntryNum; FitIndex++) {
+    switch (FitEntry[FitIndex].Type) {
+    case FIT_TABLE_TYPE_BIOS_POLICY:
+    case FIT_TABLE_TYPE_KEY_MANIFEST:
+    case FIT_TABLE_TYPE_BOOT_POLICY_MANIFEST:
+    case FIT_TABLE_TYPE_BIOS_DATA_AREA:
+    case FIT_TABLE_TYPE_CSE_SECURE_BOOT:
+      //
+      // Clear FIT table data buffer
+      //
+      Buffer = FLASH_TO_MEMORY (FitEntry[FitIndex].Address, FvBuffer, FvSize);
+      BufferSize = (*(UINT32 *)FitEntry[FitIndex].Size) & 0xFFFFFF;
+      SetMem (Buffer, BufferSize, 0xFF);
+      break;
+    default:
+      break;
+    }
+    //
+    // Clear FIT table itself
+    //
+    SetMem (&FitEntry[FitIndex], sizeof(FitEntry[FitIndex]), 0xFF);
+  }
+}
+
+STATUS
+WriteOutputFile (
+  IN CHAR8   *FileName,
+  IN UINT8   *FileData,
+  IN UINT32  FileSize
+  )
+/*++
+
+Routine Description:
+
+  Read input file
+
+Arguments:
+
+  FileName      - The input file name
+  FileData      - The input file data
+  FileSize      - The input file size
+
+Returns:
+
+  STATUS_SUCCESS - Write file data successfully
+  STATUS_ERROR   - The file data is not written
+
+--*/
+{
+  FILE                        *FpOut;
+
+  //
+  // Open the output FvRecovery.fv file
+  //
+  if ((FpOut = fopen (FileName, "w+b")) == NULL) {
+    Error (NULL, 0, 0, "Unable to open file", "%s", FileName);
+    return STATUS_ERROR;
+  }
+  //
+  // Write the output FvRecovery.fv file
+  //
+  if ((fwrite (FileData, 1, FileSize, FpOut)) != FileSize) {
+    Error (NULL, 0, 0, "Write output file error!", NULL);
+    fclose (FpOut);
+    return STATUS_ERROR;
+  }
+
+  //
+  // Close the output FvRecovery.fv file
+  //
+  fclose (FpOut);
+
+  return STATUS_SUCCESS;
+}
+
+UINT32
+GetFvRecoveryInfoFromFd (
+  IN UINT8                       *FdBuffer,
+  IN UINT32                      FdFileSize,
+  OUT UINT8                      **FvRecovery
+  )
+/*++
+
+Routine Description:
+
+  Get FvRecovery information from Fd file.
+
+Arguments:
+
+  FdBuffer     - Fd file buffer.
+  FdFileSize   - Fd file size.
+  FvRecovery   - FvRecovery pointer in Fd file buffer
+
+Returns:
+  FvRecovery file size
+
+--*/
+{
+  UINT8                         *FileBuffer = NULL;
+  UINT32                        FvRecoveryFileSize =0;
+  EFI_GUID                      VTFGuid = EFI_FFS_VOLUME_TOP_FILE_GUID;
+  UINT32                        FvLength;
+  UINT32                        FileLength;
+
+  *FvRecovery = NULL;
+  FileBuffer = FindNextFvHeader (FdBuffer, FdFileSize);
+  if (FileBuffer == NULL) {
+    return 0;
+  }
+
+  while ((UINTN)FileBuffer < (UINTN)FdBuffer + FdFileSize) {
+    FvLength         = (UINT32)((EFI_FIRMWARE_VOLUME_HEADER *)FileBuffer)->FvLength;
+
+    if (FindFileFromFvByGuid (FileBuffer, FvLength, &VTFGuid, &FileLength) != NULL) {
+      //
+      // Found the VTF
+      //
+      FvRecoveryFileSize = FvLength;
+      *FvRecovery = FileBuffer;
+    }
+
+    //
+    // Next fv
+    //
+    FileBuffer = (UINT8 *)FileBuffer + FvLength;
+    if ((UINTN)FileBuffer >= (UINTN)FdBuffer + FdFileSize) {
+      break;
+    }
+    FileBuffer = FindNextFvHeader (FileBuffer, (UINTN)FdBuffer + FdFileSize - (UINTN)FileBuffer);
+    if (FileBuffer == NULL) {
+      break;
+    }
+
+  }
+
+  //
+  // Return
+  //
+  return FvRecoveryFileSize;
+}
+
+UINT32
+GetFitEntryInfo (
+  IN UINT8     *FvBuffer,
+  IN UINT32    FvSize
+  )
+/*++
+
+Routine Description:
+
+  Fill the FIT table information to Fvrecovery
+
+Arguments:
+
+  FvBuffer       - Fvrecovery binary buffer
+  FvSize         - Fvrecovery size
+
+Returns:
+
+  0 - Fit Table not found
+
+--*/
+{
+  FIRMWARE_INTERFACE_TABLE_ENTRY *FitEntry;
+  UINT32                          FitIndex;
+  UINT32                          FitTableOffset;
+
+  //
+  // 1. FitPointer
+  //
+  if (gFitTableContext.FitTablePointerOffset == 0) {
+    gFitTableContext.FitTablePointerOffset = DEFAULT_FIT_TABLE_POINTER_OFFSET;
+  }
+  gFitTableContext.FitTablePointerOffset2 = 0;
+
+  FitTableOffset = *(UINT32 *)(FvBuffer + FvSize - gFitTableContext.FitTablePointerOffset);
+
+  FitEntry = (FIRMWARE_INTERFACE_TABLE_ENTRY *)FLASH_TO_MEMORY(FitTableOffset, FvBuffer, FvSize);
+  FitIndex = 0;
+
+  //
+  // 2. FitHeader
+  //
+  if (FitEntry[FitIndex].Address != *(UINT64 *)"_FIT_   ") {
+    return 0;
+  }
+  if (FitEntry[FitIndex].Type != FIT_TABLE_TYPE_HEADER) {
+    return 0;
+  }
+  gFitTableContext.FitEntryNumber = *(UINT32 *)&FitEntry[FitIndex].Size[0];
+  gFitTableContext.FitHeaderVersion = FitEntry[FitIndex].Version;
+
+  //
+  // 3. FitEntry
+  //
+  FitIndex++;
+  for (; FitIndex < gFitTableContext.FitEntryNumber; FitIndex++) {
+    switch (FitEntry[FitIndex].Type) {
+    case FIT_TABLE_TYPE_MICROCODE:
+      gFitTableContext.Microcode[gFitTableContext.MicrocodeNumber].Address = (UINT32)FitEntry[FitIndex].Address;
+      gFitTableContext.MicrocodeVersion                                    = FitEntry[FitIndex].Version;
+      gFitTableContext.MicrocodeNumber ++;
+      break;
+    case FIT_TABLE_TYPE_STARTUP_ACM:
+      gFitTableContext.StartupAcm.Address = (UINT32)FitEntry[FitIndex].Address;
+      gFitTableContext.StartupAcmVersion  = FitEntry[FitIndex].Version;
+      break;
+    case FIT_TABLE_TYPE_BIOS_MODULE:
+      gFitTableContext.BiosModule[gFitTableContext.BiosModuleNumber].Address = (UINT32)FitEntry[FitIndex].Address;
+      gFitTableContext.BiosModule[gFitTableContext.BiosModuleNumber].Size    = *(UINT32 *)&FitEntry[FitIndex].Size[0] * 16;
+      gFitTableContext.BiosModuleVersion                                     = FitEntry[FitIndex].Version;
+      gFitTableContext.BiosModuleNumber ++;
+      break;
+    case FIT_TABLE_TYPE_TPM_POLICY:
+    case FIT_TABLE_TYPE_TXT_POLICY:
+      if (FitEntry[FitIndex].Version == 0) {
+        gFitTableContext.PortModule[gFitTableContext.PortModuleNumber].Address = (UINT32)FitEntry[FitIndex].Address;
+        gFitTableContext.PortModule[gFitTableContext.PortModuleNumber].Size    = (UINT32)(FitEntry[FitIndex].Address >> 32);
+        gFitTableContext.PortModule[gFitTableContext.PortModuleNumber].Version = FitEntry[FitIndex].Version;
+        gFitTableContext.PortModule[gFitTableContext.PortModuleNumber].Type    = FitEntry[FitIndex].Type;
+        gFitTableContext.PortModuleNumber ++;
+        break;
+      }
+      // Not Port Configure, pass through
+    default: // Others
+      gFitTableContext.OptionalModule[gFitTableContext.OptionalModuleNumber].Address = (UINT32)FitEntry[FitIndex].Address;
+      gFitTableContext.OptionalModule[gFitTableContext.OptionalModuleNumber].Size    = *(UINT32 *)&FitEntry[FitIndex].Size[0];
+      gFitTableContext.OptionalModule[gFitTableContext.OptionalModuleNumber].Version = FitEntry[FitIndex].Version;
+      gFitTableContext.OptionalModule[gFitTableContext.OptionalModuleNumber].Type    = FitEntry[FitIndex].Type;
+      gFitTableContext.OptionalModuleNumber ++;
+      break;
+    }
+  }
+
+  return gFitTableContext.FitEntryNumber;
+}
+
+STATUS
+FitGen (
+  IN INTN   argc,
+  IN CHAR8  **argv
+  )
+/*++
+
+Routine Description:
+
+  Main function for FitGen.
+
+Arguments:
+
+  argc - Number of command line parameters.
+  argv - Array of pointers to parameter strings.
+
+Returns:
+  STATUS_SUCCESS - Utility exits successfully.
+  STATUS_ERROR   - Some error occurred during execution.
+
+--*/
+{
+  UINT32                      FvRecoveryFileSize;
+  UINT8                       *FileBuffer;
+  UINT8                       *FileBufferRaw;
+  UINTN                       FitEntryNumber;
+  UINT8                       *FitTableOffset;
+  STATUS                      Status;
+  UINT32                      FitTableSize;
+
+  BOOLEAN                     IsFv;
+  UINT8                       *FdFileBuffer;
+  UINT32                      FdFileSize;
+
+  UINT8                       *AcmBuffer;
+
+  //
+  // Step 0: Check FV or FD
+  //
+  if (((strcmp (argv[1], "-D") == 0) ||
+       (strcmp (argv[1], "-d") == 0)) ) {
+    IsFv = FALSE;
+  } else {
+    IsFv = TRUE;
+  }
+
+  //
+  // Step 1: Read InputFvRecovery.fv data
+  //
+  if (IsFv) {
+    Status = ReadInputFile (argv[1], &FileBuffer, &FvRecoveryFileSize, &FileBufferRaw);
+    if (Status != STATUS_SUCCESS) {
+      Error (NULL, 0, 0, "Unable to open file", "%s", argv[1]);
+      goto exitFunc;
+    }
+    FdFileBuffer = FileBuffer;
+    FdFileSize = FvRecoveryFileSize;
+  } else {
+    Status = ReadInputFile (argv[2], &FdFileBuffer, &FdFileSize, &FileBufferRaw);
+    if (Status != STATUS_SUCCESS) {
+      Error (NULL, 0, 0, "Unable to open file", "%s", argv[2]);
+      goto exitFunc;
+    }
+
+    //
+    // Get Fvrecovery information
+    //
+    FvRecoveryFileSize = GetFvRecoveryInfoFromFd (FdFileBuffer, FdFileSize, &FileBuffer);
+    if ((FvRecoveryFileSize == 0) || (FileBuffer == NULL)) {
+      Error (NULL, 0, 0, "FvRecovery not found in Fd file!", NULL);
+      Status = STATUS_ERROR;
+      goto exitFunc;
+    }
+  }
+
+  //
+  // Step 2: Calculate FIT entry number.
+  //
+  FitEntryNumber = GetFitEntryNumber (argc, argv, FdFileBuffer, FdFileSize);
+  if (!gFitTableContext.Clear) {
+    if (FitEntryNumber == 0) {
+      Status = STATUS_ERROR;
+      goto exitFunc;
+    }
+
+    //
+    // For debug
+    //
+    PrintFitData ();
+
+    //
+    // Add 1 more FitEntry as place holder, because we need exclude FIT table itself
+    //
+    FitEntryNumber++;
+
+    //
+    // Step 3: Get enough space in FvRecovery.fv
+    //
+    FitTableOffset = GetFreeSpaceFromFv (FileBuffer, FvRecoveryFileSize, FitEntryNumber);
+    if (FitTableOffset == NULL) {
+      return STATUS_ERROR;
+    }
+    FitTableSize = FitEntryNumber * sizeof(FIRMWARE_INTERFACE_TABLE_ENTRY);
+    FitTableSize += FIT_ALIGNMENT;
+    FitTableSize &= ~FIT_ALIGNMENT;
+
+    CheckOverlap (
+      MEMORY_TO_FLASH (FitTableOffset, FdFileBuffer, FdFileSize),
+      FitTableSize
+      );
+
+    //
+    // Get ACM buffer
+    //
+    if (gFitTableContext.StartupAcm.Address != 0) {
+      AcmBuffer = FLASH_TO_MEMORY(gFitTableContext.StartupAcm.Address, FdFileBuffer, FdFileSize);
+      if ((AcmBuffer < FdFileBuffer) || (AcmBuffer + gFitTableContext.StartupAcm.Size > FdFileBuffer + FdFileSize)) {
+        printf ("ACM out of range - can not validate it\n");
+        AcmBuffer = NULL;
+      }
+
+      if (AcmBuffer != NULL) {
+        if (CheckAcm ((ACM_FORMAT *)AcmBuffer, gFitTableContext.StartupAcm.Size)) {
+          DumpAcm ((ACM_FORMAT *)AcmBuffer);
+        } else {
+          Status = STATUS_ERROR;
+          goto exitFunc;
+        }
+      }
+
+    }
+
+    //
+    // Step 4: Fill the FIT table one by one
+    //
+    FillFitTable (FdFileBuffer, FdFileSize, FitTableOffset);
+
+    //
+    // For debug
+    //
+    PrintFitTable (FdFileBuffer, FdFileSize);
+  } else {
+    printf ("Clear FIT table ...\n");
+    //
+    // Step 3: Get FIT table info
+    //
+    FitEntryNumber = GetFitEntryInfo (FdFileBuffer, FdFileSize);
+    if (FitEntryNumber == 0) {
+      Error (NULL, 0, 0, "No FIT table found", NULL);
+      return STATUS_ERROR;
+    }
+
+    //
+    // For debug
+    //
+    PrintFitTable (FdFileBuffer, FdFileSize);
+
+    //
+    // Step 4: Clear FIT table
+    //
+    ClearFitTable (FdFileBuffer, FdFileSize);
+    printf ("Clear FIT table Done!\n");
+  }
+
+  //
+  // Step 5: Write OutputFvRecovery.fv data
+  //
+  if (IsFv) {
+    Status = WriteOutputFile (argv[2], FileBuffer, FvRecoveryFileSize);
+  } else {
+    Status = WriteOutputFile (argv[3], FdFileBuffer, FdFileSize);
+  }
+
+exitFunc:
+  if (FileBufferRaw != NULL) {
+    free ((VOID *)FileBufferRaw);
+  }
+  return Status;
+}
+
+STATUS
+FitView (
+  IN INTN   argc,
+  IN CHAR8  **argv
+  )
+/*++
+
+Routine Description:
+
+  View function for FitGen.
+
+Arguments:
+
+  argc - Number of command line parameters.
+  argv - Array of pointers to parameter strings.
+
+Returns:
+  STATUS_SUCCESS - Utility exits successfully.
+  STATUS_ERROR   - Some error occurred during execution.
+
+--*/
+{
+  UINT32                      FvRecoveryFileSize;
+  UINT8                       *FileBuffer;
+  UINT8                       *FileBufferRaw = NULL;
+  STATUS                      Status;
+
+  //
+  // Step 1: Read input file
+  //
+  Status = ReadInputFile (argv[2], &FileBuffer, &FvRecoveryFileSize, &FileBufferRaw);
+  if (Status != STATUS_SUCCESS) {
+    Error (NULL, 0, 0, "Unable to open file", "%s", argv[2]);
+    goto exitFunc;
+  }
+
+  // no -f option, use default FIT pointer offset
+  if (argc == 3) {
+    //
+    // Use default address
+    //
+    gFitTableContext.FitTablePointerOffset = DEFAULT_FIT_TABLE_POINTER_OFFSET;
+  } else if (stricmp (argv[3], "-f") == 0) {
+    if (argc == 5) {
+      //
+      // Get offset from parameter
+      //
+      gFitTableContext.FitTablePointerOffset = xtoi (argv[3 + 1]);
+    } else {
+      Error (NULL, 0, 0, "FIT offset not specified!", NULL);
+      goto exitFunc;
+    }
+  } else {
+    Error (NULL, 0, 0, "Invalid view option: ", "%s", argv[3]);
+    goto exitFunc;
+  }
+
+  //
+  // For debug
+  //
+  PrintFitTable (FileBuffer, FvRecoveryFileSize);
+
+exitFunc:
+  if (FileBufferRaw != NULL) {
+    free ((VOID *)FileBufferRaw);
+  }
+  return Status;
+}
+
+int
+main (
+  int   argc,
+  char  **argv
+  )
+/*++
+
+Routine Description:
+
+  Main function.
+
+Arguments:
+
+  argc - Number of command line parameters.
+  argv - Array of pointers to parameter strings.
+
+Returns:
+  STATUS_SUCCESS - Utility exits successfully.
+  STATUS_ERROR   - Some error occurred during execution.
+
+--*/
+{
+  SetUtilityName (UTILITY_NAME);
+
+  //
+  // Display utility information
+  //
+  PrintUtilityInfo ();
+
+  //
+  // Verify the correct number of arguments
+  //
+  if (argc >= MIN_VIEW_ARGS && stricmp (argv[1], "-view") == 0) {
+    return FitView (argc, argv);
+  } else if (argc >= MIN_ARGS) {
+    return FitGen (argc, argv);
+  } else {
+    Error (NULL, 0, 0, "invalid number of input parameters specified", NULL);
+    PrintUsage ();
+    return STATUS_ERROR;
+  }
+}
+
+unsigned int
+xtoi (
+  char  *str
+  )
+/*++
+
+Routine Description:
+
+  Convert hex string to uint
+
+Arguments:
+
+  str  -  The string
+
+Returns:
+
+--*/
+{
+  unsigned int u;
+  char         c;
+  unsigned int m;
+
+  if (str == NULL) {
+    return 0;
+  }
+
+  m = (unsigned int) -1 >> 4;
+  //
+  // skip preceeding white space
+  //
+  while (*str && *str == ' ') {
+    str += 1;
+  }
+  //
+  // skip preceeding zeros
+  //
+  while (*str && *str == '0') {
+    str += 1;
+  }
+  //
+  // skip preceeding x/X character
+  //
+  if (*str && (*str == 'x' || *str == 'X')) {
+    str += 1;
+  }
+  //
+  // convert hex digits
+  //
+  u = 0;
+  c = *(str++);
+  while (c) {
+    if (c >= 'a' && c <= 'f') {
+      c -= 'a' - 'A';
+    }
+
+    if ((c >= '0' && c <= '9') || (c >= 'A' && c <= 'F')) {
+      if (u > m) {
+        return (unsigned int) -1;
+      }
+
+      u = (u << 4) | (c - (c >= 'A' ? 'A' - 10 : '0'));
+    } else {
+      //
+      // Let application exit immediately
+      //
+      Error (NULL, 0, 0, "Hex value is expected!", NULL);
+      exit (0);
+      break;
+    }
+
+    c = *(str++);
+  }
+
+  return u;
+}
+
diff --git a/Silicon/Intel/Tools/FitGen/FitGen.h b/Silicon/Intel/Tools/FitGen/FitGen.h
new file mode 100644
index 0000000000..9bd3f6824b
--- /dev/null
+++ b/Silicon/Intel/Tools/FitGen/FitGen.h
@@ -0,0 +1,48 @@
+/**@file
+Definitions for the FitGen utility.
+
+Copyright (c) 2010-2019, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _FIT_GEN_H
+#define _FIT_GEN_H
+
+#include <stdio.h>
+#include <stdlib.h>
+#define PI_SPECIFICATION_VERSION  0x00010000
+#define EFI_FVH_PI_REVISION       EFI_FVH_REVISION
+#include <Common/UefiBaseTypes.h>
+#include <Common/PiFirmwareFile.h>
+#include <Common/PiFirmwareVolume.h>
+#include <Guid/PiFirmwareFileSystem.h>
+#include "EfiUtilityMsgs.c"
+#include "CommonLib.h"
+#include "ParseInf.h"
+#include "FvLib.h"
+
+//
+// Utility Name
+//
+#define UTILITY_NAME  "FitGen"
+
+//
+// Utility version information
+//
+#define UTILITY_MAJOR_VERSION 0
+#define UTILITY_MINOR_VERSION 56
+#define UTILITY_DATE          __DATE__
+
+//
+// The minimum number of arguments accepted from the command line.
+//
+#define MIN_VIEW_ARGS   3
+#define MIN_ARGS        4
+#define BUF_SIZE        (8 * 1024)
+
+#define GETOCCUPIEDSIZE(ActualSize, Alignment) \
+  (ActualSize) + (((Alignment) - ((ActualSize) & ((Alignment) - 1))) & ((Alignment) - 1))
+;
+
+#endif
diff --git a/Silicon/Intel/Tools/FitGen/GNUmakefile b/Silicon/Intel/Tools/FitGen/GNUmakefile
new file mode 100644
index 0000000000..00a99bb0c7
--- /dev/null
+++ b/Silicon/Intel/Tools/FitGen/GNUmakefile
@@ -0,0 +1,16 @@
+# @file
+# GNUmakefile for building the FitGen utility.
+#
+# Copyright (c) 2010-2019, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+MAKEROOT ?= $(EDK_TOOLS_PATH)/Source/C
+
+APPNAME = FitGen
+
+OBJECTS = FitGen.o
+
+include $(MAKEROOT)/Makefiles/app.makefile
+
+LIBS = -lCommon
+
diff --git a/Silicon/Intel/Tools/FitGen/Makefile b/Silicon/Intel/Tools/FitGen/Makefile
new file mode 100644
index 0000000000..fd286b26be
--- /dev/null
+++ b/Silicon/Intel/Tools/FitGen/Makefile
@@ -0,0 +1,17 @@
+# @file
+# makefile for building the FitGen utility.
+#
+# Copyright (c) 2010-2019, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+
+!INCLUDE $(EDK_TOOLS_PATH)\Source\C\Makefiles\ms.common
+
+APPNAME = FitGen
+
+LIBS = $(LIB_PATH)\Common.lib
+
+OBJECTS = FitGen.obj
+
+!INCLUDE $(EDK_TOOLS_PATH)\Source\C\Makefiles\ms.app
+
-- 
2.18.0.windows.1


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [edk2-platform patch 6/6] Silicon\Tools: Add top level Makefile and GNUMakefile
  2019-06-21  1:26 [edk2-platform patch 0/6] Add tools FMMT FCE and FitGen Zhang, Shenglei
                   ` (4 preceding siblings ...)
  2019-06-21  1:26 ` [edk2-platform patch 5/6] Silicon\Tools: Add a tool FitGen Zhang, Shenglei
@ 2019-06-21  1:26 ` Zhang, Shenglei
  2019-06-26  2:04   ` Liming Gao
  2019-06-21  2:25 ` [edk2-devel] [edk2-platform patch 0/6] Add tools FMMT FCE and FitGen Yao, Jiewen
  6 siblings, 1 reply; 15+ messages in thread
From: Zhang, Shenglei @ 2019-06-21  1:26 UTC (permalink / raw)
  To: devel; +Cc: Bob Feng, Liming Gao

Add FitGen into Makefile and GNUMakefile.

Cc: Bob Feng <bob.c.feng@intel.com>
Cc: Liming Gao <liming.gao@intel.com>
Signed-off-by: Shenglei Zhang <shenglei.zhang@intel.com>
---
 Silicon/Intel/Tools/GNUmakefile | 34 +++++++++++++++++++++++++++++++++
 Silicon/Intel/Tools/Makefile    | 31 ++++++++++++++++++++++++++++++
 2 files changed, 65 insertions(+)
 create mode 100644 Silicon/Intel/Tools/GNUmakefile
 create mode 100644 Silicon/Intel/Tools/Makefile

diff --git a/Silicon/Intel/Tools/GNUmakefile b/Silicon/Intel/Tools/GNUmakefile
new file mode 100644
index 0000000000..77cfc62250
--- /dev/null
+++ b/Silicon/Intel/Tools/GNUmakefile
@@ -0,0 +1,34 @@
+## @file
+#  GNUmakefile for building C utilities.
+#
+#  Copyright (c) 2018, Intel Corporation. All rights reserved.<BR>
+#  This software and associated documentation (if any) is furnished
+#  under a license and may only be used or copied in accordance
+#  with the terms of the license. Except as permitted by such
+#  license, no part of this software or documentation may be
+#  reproduced, stored in a retrieval system, or transmitted in any
+#  form or by any means without the express written consent of
+#  Intel Corporation.
+#
+##
+
+MAKEROOT = $(EDK_TOOLS_PATH)/Source/C
+
+APPLICATIONS = \
+  FitGen \
+
+SUBDIRS := $(APPLICATIONS)
+
+$(APPLICATIONS): $(MAKEROOT)/bin
+
+.PHONY: subdirs $(SUBDIRS)
+subdirs: $(SUBDIRS)
+$(SUBDIRS):
+    $(MAKE) -C $@
+
+.PHONY: $(patsubst %,%-clean,$(sort $(SUBDIRS)))
+$(patsubst %,%-clean,$(sort $(SUBDIRS))):
+    -$(MAKE) -C $(@:-clean=) clean
+
+clean: $(patsubst %,%-clean,$(sort $(SUBDIRS)))
+
diff --git a/Silicon/Intel/Tools/Makefile b/Silicon/Intel/Tools/Makefile
new file mode 100644
index 0000000000..e52c95b7b5
--- /dev/null
+++ b/Silicon/Intel/Tools/Makefile
@@ -0,0 +1,31 @@
+## @file
+#  makefile for building C utilities.
+#
+#  Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+#  SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+!INCLUDE $(EDK_TOOLS_PATH)\Source\C\Makefiles\ms.common
+
+APPLICATIONS = \
+  FitGen \
+
+all: $(APPLICATIONS)
+    @echo.
+    @echo ######################
+    @echo # Build executables
+    @echo ######################
+    @if not exist $(BIN_PATH) mkdir $(BIN_PATH)
+    @$(EDK_TOOLS_PATH)\Source\C\Makefiles\NmakeSubdirs.bat all $**
+
+.PHONY: clean
+clean: $(APPLICATIONS)
+  @$(EDK_TOOLS_PATH)\Source\C\Makefiles\NmakeSubdirs.bat clean $**
+
+.PHONY: cleanall
+cleanall: $(APPLICATIONS)
+  @$(EDK_TOOLS_PATH)\Source\C\Makefiles\NmakeSubdirs.bat cleanall $**
+
+!INCLUDE $(EDK_TOOLS_PATH)\Source\C\Makefiles\ms.rule
+
-- 
2.18.0.windows.1


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* Re: [edk2-devel] [edk2-platform patch 0/6] Add tools FMMT FCE and FitGen
  2019-06-21  1:26 [edk2-platform patch 0/6] Add tools FMMT FCE and FitGen Zhang, Shenglei
                   ` (5 preceding siblings ...)
  2019-06-21  1:26 ` [edk2-platform patch 6/6] Silicon\Tools: Add top level Makefile and GNUMakefile Zhang, Shenglei
@ 2019-06-21  2:25 ` Yao, Jiewen
  2019-06-21  2:31   ` Liming Gao
  6 siblings, 1 reply; 15+ messages in thread
From: Yao, Jiewen @ 2019-06-21  2:25 UTC (permalink / raw)
  To: devel@edk2.groups.io, Zhang, Shenglei
  Cc: Feng, Bob C, Gao, Liming, Yao, Jiewen

HI
I saw some conflict:
=========
BaseTools/FCE: Add a tool FCE
Add FMMT and FCE into Platform/Intel/Tools.
=========

I agree that FitGet goes to Intel silicon.

Should we put both FCE/FMMT to BaseTools?

Thank you
Yao Jiewen


> -----Original Message-----
> From: devel@edk2.groups.io [mailto:devel@edk2.groups.io] On Behalf Of
> Zhang, Shenglei
> Sent: Friday, June 21, 2019 9:27 AM
> To: devel@edk2.groups.io
> Cc: Feng, Bob C <bob.c.feng@intel.com>; Gao, Liming
> <liming.gao@intel.com>
> Subject: [edk2-devel] [edk2-platform patch 0/6] Add tools FMMT FCE and
> FitGen
> 
> Add FMMT and FCE into Platform/Intel/Tools.
> Add FitGen into Silicon/Intel/Tools.
> https://bugzilla.tianocore.org/show_bug.cgi?id=1847
> https://bugzilla.tianocore.org/show_bug.cgi?id=1848
> https://bugzilla.tianocore.org/show_bug.cgi?id=1849
> 
> Cc: Bob Feng <bob.c.feng@intel.com>
> Cc: Liming Gao <liming.gao@intel.com>
> Shenglei Zhang (6):
>   Platform/Tools: Add a tool FMMT
>   Platform/Tools: Add a tool BfmLib
>   BaseTools/FCE: Add a tool FCE
>   Platform/Tools: Add top level Makefile and GNUMakefile
>   Silicon/Tools: Add a tool FitGen
>   Silicon/Tools: Add top level Makefile and GNUMakefile
> 
>  Platform/Intel/Tools/BfmLib/BfmLib.c          | 4355 +++++++++++
>  Platform/Intel/Tools/BfmLib/BinFileManager.c  | 1024 +++
>  Platform/Intel/Tools/BfmLib/BinFileManager.h  |  439 ++
>  Platform/Intel/Tools/BfmLib/GNUmakefile       |   15 +
>  Platform/Intel/Tools/BfmLib/Makefile          |   17 +
>  Platform/Intel/Tools/FCE/BinaryCreate.c       |  216 +
>  Platform/Intel/Tools/FCE/BinaryCreate.h       |  157 +
>  Platform/Intel/Tools/FCE/BinaryParse.c        | 1326 ++++
>  Platform/Intel/Tools/FCE/BinaryParse.h        |  187 +
>  Platform/Intel/Tools/FCE/Common.c             | 2183 ++++++
>  Platform/Intel/Tools/FCE/Common.h             |  999 +++
>  Platform/Intel/Tools/FCE/Expression.c         | 2367 ++++++
>  Platform/Intel/Tools/FCE/Fce.c                | 6449
> +++++++++++++++++
>  Platform/Intel/Tools/FCE/Fce.h                |  447 ++
>  Platform/Intel/Tools/FCE/GNUmakefile          |   22 +
>  Platform/Intel/Tools/FCE/IfrParse.c           | 4836 ++++++++++++
>  Platform/Intel/Tools/FCE/IfrParse.h           |  789 ++
>  Platform/Intel/Tools/FCE/Makefile             |   19 +
>  .../Intel/Tools/FCE/MonotonicBasedVariable.c  |  874 +++
>  .../Intel/Tools/FCE/MonotonicBasedVariable.h  |  162 +
>  Platform/Intel/Tools/FCE/TimeBasedVariable.c  |  878 +++
>  Platform/Intel/Tools/FCE/TimeBasedVariable.h  |  166 +
>  Platform/Intel/Tools/FCE/Variable.c           | 1091 +++
>  Platform/Intel/Tools/FCE/Variable.h           |  154 +
>  Platform/Intel/Tools/FCE/VariableCommon.h     |   55 +
>  .../Tools/FMMT/FirmwareModuleManagement.c     | 2559 +++++++
>  .../Tools/FMMT/FirmwareModuleManagement.h     |  479 ++
>  Platform/Intel/Tools/FMMT/FmmtConf.ini        |    6 +
>  Platform/Intel/Tools/FMMT/FmmtLib.c           | 5051
> +++++++++++++
>  Platform/Intel/Tools/FMMT/GNUmakefile         |   16 +
>  Platform/Intel/Tools/FMMT/Makefile            |   17 +
>  Platform/Intel/Tools/FMMT/Rebase.c            |  846 +++
>  Platform/Intel/Tools/FMMT/Rebase.h            |   31 +
>  Platform/Intel/Tools/GNUmakefile              |   30 +
>  Platform/Intel/Tools/Makefile                 |   33 +
>  Silicon/Intel/Tools/FitGen/FitGen.c           | 3137 ++++++++
>  Silicon/Intel/Tools/FitGen/FitGen.h           |   48 +
>  Silicon/Intel/Tools/FitGen/GNUmakefile        |   16 +
>  Silicon/Intel/Tools/FitGen/Makefile           |   17 +
>  Silicon/Intel/Tools/GNUmakefile               |   34 +
>  Silicon/Intel/Tools/Makefile                  |   31 +
>  41 files changed, 41578 insertions(+)
>  create mode 100644 Platform/Intel/Tools/BfmLib/BfmLib.c
>  create mode 100644 Platform/Intel/Tools/BfmLib/BinFileManager.c
>  create mode 100644 Platform/Intel/Tools/BfmLib/BinFileManager.h
>  create mode 100644 Platform/Intel/Tools/BfmLib/GNUmakefile
>  create mode 100644 Platform/Intel/Tools/BfmLib/Makefile
>  create mode 100644 Platform/Intel/Tools/FCE/BinaryCreate.c
>  create mode 100644 Platform/Intel/Tools/FCE/BinaryCreate.h
>  create mode 100644 Platform/Intel/Tools/FCE/BinaryParse.c
>  create mode 100644 Platform/Intel/Tools/FCE/BinaryParse.h
>  create mode 100644 Platform/Intel/Tools/FCE/Common.c
>  create mode 100644 Platform/Intel/Tools/FCE/Common.h
>  create mode 100644 Platform/Intel/Tools/FCE/Expression.c
>  create mode 100644 Platform/Intel/Tools/FCE/Fce.c
>  create mode 100644 Platform/Intel/Tools/FCE/Fce.h
>  create mode 100644 Platform/Intel/Tools/FCE/GNUmakefile
>  create mode 100644 Platform/Intel/Tools/FCE/IfrParse.c
>  create mode 100644 Platform/Intel/Tools/FCE/IfrParse.h
>  create mode 100644 Platform/Intel/Tools/FCE/Makefile
>  create mode 100644 Platform/Intel/Tools/FCE/MonotonicBasedVariable.c
>  create mode 100644 Platform/Intel/Tools/FCE/MonotonicBasedVariable.h
>  create mode 100644 Platform/Intel/Tools/FCE/TimeBasedVariable.c
>  create mode 100644 Platform/Intel/Tools/FCE/TimeBasedVariable.h
>  create mode 100644 Platform/Intel/Tools/FCE/Variable.c
>  create mode 100644 Platform/Intel/Tools/FCE/Variable.h
>  create mode 100644 Platform/Intel/Tools/FCE/VariableCommon.h
>  create mode 100644
> Platform/Intel/Tools/FMMT/FirmwareModuleManagement.c
>  create mode 100644
> Platform/Intel/Tools/FMMT/FirmwareModuleManagement.h
>  create mode 100644 Platform/Intel/Tools/FMMT/FmmtConf.ini
>  create mode 100644 Platform/Intel/Tools/FMMT/FmmtLib.c
>  create mode 100644 Platform/Intel/Tools/FMMT/GNUmakefile
>  create mode 100644 Platform/Intel/Tools/FMMT/Makefile
>  create mode 100644 Platform/Intel/Tools/FMMT/Rebase.c
>  create mode 100644 Platform/Intel/Tools/FMMT/Rebase.h
>  create mode 100644 Platform/Intel/Tools/GNUmakefile
>  create mode 100644 Platform/Intel/Tools/Makefile
>  create mode 100644 Silicon/Intel/Tools/FitGen/FitGen.c
>  create mode 100644 Silicon/Intel/Tools/FitGen/FitGen.h
>  create mode 100644 Silicon/Intel/Tools/FitGen/GNUmakefile
>  create mode 100644 Silicon/Intel/Tools/FitGen/Makefile
>  create mode 100644 Silicon/Intel/Tools/GNUmakefile
>  create mode 100644 Silicon/Intel/Tools/Makefile
> 
> --
> 2.18.0.windows.1
> 
> 
> 


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [edk2-devel] [edk2-platform patch 0/6] Add tools FMMT FCE and FitGen
  2019-06-21  2:25 ` [edk2-devel] [edk2-platform patch 0/6] Add tools FMMT FCE and FitGen Yao, Jiewen
@ 2019-06-21  2:31   ` Liming Gao
  2019-06-21  3:34     ` Yao, Jiewen
  0 siblings, 1 reply; 15+ messages in thread
From: Liming Gao @ 2019-06-21  2:31 UTC (permalink / raw)
  To: Yao, Jiewen, devel@edk2.groups.io, Zhang, Shenglei; +Cc: Feng, Bob C

Jiewen:
  I give the comments https://edk2.groups.io/g/devel/message/42545?p=,,,20,0,0,0::Created,,FMMT,20,2,0,32013143 for the patch BaseTools/FCE: Add a tool FCE

  I give new proposal https://edk2.groups.io/g/devel/message/42546 for those tools.

Thanks
Liming
> -----Original Message-----
> From: Yao, Jiewen
> Sent: Friday, June 21, 2019 10:26 AM
> To: devel@edk2.groups.io; Zhang, Shenglei <shenglei.zhang@intel.com>
> Cc: Feng, Bob C <bob.c.feng@intel.com>; Gao, Liming <liming.gao@intel.com>; Yao, Jiewen <jiewen.yao@intel.com>
> Subject: RE: [edk2-devel] [edk2-platform patch 0/6] Add tools FMMT FCE and FitGen
> 
> HI
> I saw some conflict:
> =========
> BaseTools/FCE: Add a tool FCE
> Add FMMT and FCE into Platform/Intel/Tools.
> =========
> 
> I agree that FitGet goes to Intel silicon.
> 
> Should we put both FCE/FMMT to BaseTools?
> 
> Thank you
> Yao Jiewen
> 
> 
> > -----Original Message-----
> > From: devel@edk2.groups.io [mailto:devel@edk2.groups.io] On Behalf Of
> > Zhang, Shenglei
> > Sent: Friday, June 21, 2019 9:27 AM
> > To: devel@edk2.groups.io
> > Cc: Feng, Bob C <bob.c.feng@intel.com>; Gao, Liming
> > <liming.gao@intel.com>
> > Subject: [edk2-devel] [edk2-platform patch 0/6] Add tools FMMT FCE and
> > FitGen
> >
> > Add FMMT and FCE into Platform/Intel/Tools.
> > Add FitGen into Silicon/Intel/Tools.
> > https://bugzilla.tianocore.org/show_bug.cgi?id=1847
> > https://bugzilla.tianocore.org/show_bug.cgi?id=1848
> > https://bugzilla.tianocore.org/show_bug.cgi?id=1849
> >
> > Cc: Bob Feng <bob.c.feng@intel.com>
> > Cc: Liming Gao <liming.gao@intel.com>
> > Shenglei Zhang (6):
> >   Platform/Tools: Add a tool FMMT
> >   Platform/Tools: Add a tool BfmLib
> >   BaseTools/FCE: Add a tool FCE
> >   Platform/Tools: Add top level Makefile and GNUMakefile
> >   Silicon/Tools: Add a tool FitGen
> >   Silicon/Tools: Add top level Makefile and GNUMakefile
> >
> >  Platform/Intel/Tools/BfmLib/BfmLib.c          | 4355 +++++++++++
> >  Platform/Intel/Tools/BfmLib/BinFileManager.c  | 1024 +++
> >  Platform/Intel/Tools/BfmLib/BinFileManager.h  |  439 ++
> >  Platform/Intel/Tools/BfmLib/GNUmakefile       |   15 +
> >  Platform/Intel/Tools/BfmLib/Makefile          |   17 +
> >  Platform/Intel/Tools/FCE/BinaryCreate.c       |  216 +
> >  Platform/Intel/Tools/FCE/BinaryCreate.h       |  157 +
> >  Platform/Intel/Tools/FCE/BinaryParse.c        | 1326 ++++
> >  Platform/Intel/Tools/FCE/BinaryParse.h        |  187 +
> >  Platform/Intel/Tools/FCE/Common.c             | 2183 ++++++
> >  Platform/Intel/Tools/FCE/Common.h             |  999 +++
> >  Platform/Intel/Tools/FCE/Expression.c         | 2367 ++++++
> >  Platform/Intel/Tools/FCE/Fce.c                | 6449
> > +++++++++++++++++
> >  Platform/Intel/Tools/FCE/Fce.h                |  447 ++
> >  Platform/Intel/Tools/FCE/GNUmakefile          |   22 +
> >  Platform/Intel/Tools/FCE/IfrParse.c           | 4836 ++++++++++++
> >  Platform/Intel/Tools/FCE/IfrParse.h           |  789 ++
> >  Platform/Intel/Tools/FCE/Makefile             |   19 +
> >  .../Intel/Tools/FCE/MonotonicBasedVariable.c  |  874 +++
> >  .../Intel/Tools/FCE/MonotonicBasedVariable.h  |  162 +
> >  Platform/Intel/Tools/FCE/TimeBasedVariable.c  |  878 +++
> >  Platform/Intel/Tools/FCE/TimeBasedVariable.h  |  166 +
> >  Platform/Intel/Tools/FCE/Variable.c           | 1091 +++
> >  Platform/Intel/Tools/FCE/Variable.h           |  154 +
> >  Platform/Intel/Tools/FCE/VariableCommon.h     |   55 +
> >  .../Tools/FMMT/FirmwareModuleManagement.c     | 2559 +++++++
> >  .../Tools/FMMT/FirmwareModuleManagement.h     |  479 ++
> >  Platform/Intel/Tools/FMMT/FmmtConf.ini        |    6 +
> >  Platform/Intel/Tools/FMMT/FmmtLib.c           | 5051
> > +++++++++++++
> >  Platform/Intel/Tools/FMMT/GNUmakefile         |   16 +
> >  Platform/Intel/Tools/FMMT/Makefile            |   17 +
> >  Platform/Intel/Tools/FMMT/Rebase.c            |  846 +++
> >  Platform/Intel/Tools/FMMT/Rebase.h            |   31 +
> >  Platform/Intel/Tools/GNUmakefile              |   30 +
> >  Platform/Intel/Tools/Makefile                 |   33 +
> >  Silicon/Intel/Tools/FitGen/FitGen.c           | 3137 ++++++++
> >  Silicon/Intel/Tools/FitGen/FitGen.h           |   48 +
> >  Silicon/Intel/Tools/FitGen/GNUmakefile        |   16 +
> >  Silicon/Intel/Tools/FitGen/Makefile           |   17 +
> >  Silicon/Intel/Tools/GNUmakefile               |   34 +
> >  Silicon/Intel/Tools/Makefile                  |   31 +
> >  41 files changed, 41578 insertions(+)
> >  create mode 100644 Platform/Intel/Tools/BfmLib/BfmLib.c
> >  create mode 100644 Platform/Intel/Tools/BfmLib/BinFileManager.c
> >  create mode 100644 Platform/Intel/Tools/BfmLib/BinFileManager.h
> >  create mode 100644 Platform/Intel/Tools/BfmLib/GNUmakefile
> >  create mode 100644 Platform/Intel/Tools/BfmLib/Makefile
> >  create mode 100644 Platform/Intel/Tools/FCE/BinaryCreate.c
> >  create mode 100644 Platform/Intel/Tools/FCE/BinaryCreate.h
> >  create mode 100644 Platform/Intel/Tools/FCE/BinaryParse.c
> >  create mode 100644 Platform/Intel/Tools/FCE/BinaryParse.h
> >  create mode 100644 Platform/Intel/Tools/FCE/Common.c
> >  create mode 100644 Platform/Intel/Tools/FCE/Common.h
> >  create mode 100644 Platform/Intel/Tools/FCE/Expression.c
> >  create mode 100644 Platform/Intel/Tools/FCE/Fce.c
> >  create mode 100644 Platform/Intel/Tools/FCE/Fce.h
> >  create mode 100644 Platform/Intel/Tools/FCE/GNUmakefile
> >  create mode 100644 Platform/Intel/Tools/FCE/IfrParse.c
> >  create mode 100644 Platform/Intel/Tools/FCE/IfrParse.h
> >  create mode 100644 Platform/Intel/Tools/FCE/Makefile
> >  create mode 100644 Platform/Intel/Tools/FCE/MonotonicBasedVariable.c
> >  create mode 100644 Platform/Intel/Tools/FCE/MonotonicBasedVariable.h
> >  create mode 100644 Platform/Intel/Tools/FCE/TimeBasedVariable.c
> >  create mode 100644 Platform/Intel/Tools/FCE/TimeBasedVariable.h
> >  create mode 100644 Platform/Intel/Tools/FCE/Variable.c
> >  create mode 100644 Platform/Intel/Tools/FCE/Variable.h
> >  create mode 100644 Platform/Intel/Tools/FCE/VariableCommon.h
> >  create mode 100644
> > Platform/Intel/Tools/FMMT/FirmwareModuleManagement.c
> >  create mode 100644
> > Platform/Intel/Tools/FMMT/FirmwareModuleManagement.h
> >  create mode 100644 Platform/Intel/Tools/FMMT/FmmtConf.ini
> >  create mode 100644 Platform/Intel/Tools/FMMT/FmmtLib.c
> >  create mode 100644 Platform/Intel/Tools/FMMT/GNUmakefile
> >  create mode 100644 Platform/Intel/Tools/FMMT/Makefile
> >  create mode 100644 Platform/Intel/Tools/FMMT/Rebase.c
> >  create mode 100644 Platform/Intel/Tools/FMMT/Rebase.h
> >  create mode 100644 Platform/Intel/Tools/GNUmakefile
> >  create mode 100644 Platform/Intel/Tools/Makefile
> >  create mode 100644 Silicon/Intel/Tools/FitGen/FitGen.c
> >  create mode 100644 Silicon/Intel/Tools/FitGen/FitGen.h
> >  create mode 100644 Silicon/Intel/Tools/FitGen/GNUmakefile
> >  create mode 100644 Silicon/Intel/Tools/FitGen/Makefile
> >  create mode 100644 Silicon/Intel/Tools/GNUmakefile
> >  create mode 100644 Silicon/Intel/Tools/Makefile
> >
> > --
> > 2.18.0.windows.1
> >
> >
> > 


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [edk2-devel] [edk2-platform patch 0/6] Add tools FMMT FCE and FitGen
  2019-06-21  2:31   ` Liming Gao
@ 2019-06-21  3:34     ` Yao, Jiewen
  2019-06-25 14:09       ` Liming Gao
  0 siblings, 1 reply; 15+ messages in thread
From: Yao, Jiewen @ 2019-06-21  3:34 UTC (permalink / raw)
  To: Gao, Liming, devel@edk2.groups.io, Zhang, Shenglei; +Cc: Feng, Bob C

Sorry, I missed the first mail.
I saw there is no V2 tag in this series, so I think it is the first mail. My apology.

I have no concern on FitGen - it is Intel only. You can check in at first.
FMMT/FCE is common. I think BaseTools is more proper place.

"It is not validated" - it seems a weird justification to me.
Or does it mean, for any future feature Intel/ARM people contribute, we should treat Platform package as the first choice, just because the it is cross validated?

May I understand more on the rule we have today on what goes to EDK2 repo and what goes to EDK2-PLATFORM repo?

Thank you
Yao Jiewen


> -----Original Message-----
> From: Gao, Liming
> Sent: Friday, June 21, 2019 10:31 AM
> To: Yao, Jiewen <jiewen.yao@intel.com>; devel@edk2.groups.io; Zhang,
> Shenglei <shenglei.zhang@intel.com>
> Cc: Feng, Bob C <bob.c.feng@intel.com>
> Subject: RE: [edk2-devel] [edk2-platform patch 0/6] Add tools FMMT FCE
> and FitGen
> 
> Jiewen:
>   I give the comments
> https://edk2.groups.io/g/devel/message/42545?p=,,,20,0,0,0::Created,,FM
> MT,20,2,0,32013143 for the patch BaseTools/FCE: Add a tool FCE
> 
>   I give new proposal https://edk2.groups.io/g/devel/message/42546 for
> those tools.
> 
> Thanks
> Liming
> > -----Original Message-----
> > From: Yao, Jiewen
> > Sent: Friday, June 21, 2019 10:26 AM
> > To: devel@edk2.groups.io; Zhang, Shenglei <shenglei.zhang@intel.com>
> > Cc: Feng, Bob C <bob.c.feng@intel.com>; Gao, Liming
> <liming.gao@intel.com>; Yao, Jiewen <jiewen.yao@intel.com>
> > Subject: RE: [edk2-devel] [edk2-platform patch 0/6] Add tools FMMT FCE
> and FitGen
> >
> > HI
> > I saw some conflict:
> > =========
> > BaseTools/FCE: Add a tool FCE
> > Add FMMT and FCE into Platform/Intel/Tools.
> > =========
> >
> > I agree that FitGet goes to Intel silicon.
> >
> > Should we put both FCE/FMMT to BaseTools?
> >
> > Thank you
> > Yao Jiewen
> >
> >
> > > -----Original Message-----
> > > From: devel@edk2.groups.io [mailto:devel@edk2.groups.io] On Behalf
> Of
> > > Zhang, Shenglei
> > > Sent: Friday, June 21, 2019 9:27 AM
> > > To: devel@edk2.groups.io
> > > Cc: Feng, Bob C <bob.c.feng@intel.com>; Gao, Liming
> > > <liming.gao@intel.com>
> > > Subject: [edk2-devel] [edk2-platform patch 0/6] Add tools FMMT FCE and
> > > FitGen
> > >
> > > Add FMMT and FCE into Platform/Intel/Tools.
> > > Add FitGen into Silicon/Intel/Tools.
> > > https://bugzilla.tianocore.org/show_bug.cgi?id=1847
> > > https://bugzilla.tianocore.org/show_bug.cgi?id=1848
> > > https://bugzilla.tianocore.org/show_bug.cgi?id=1849
> > >
> > > Cc: Bob Feng <bob.c.feng@intel.com>
> > > Cc: Liming Gao <liming.gao@intel.com>
> > > Shenglei Zhang (6):
> > >   Platform/Tools: Add a tool FMMT
> > >   Platform/Tools: Add a tool BfmLib
> > >   BaseTools/FCE: Add a tool FCE
> > >   Platform/Tools: Add top level Makefile and GNUMakefile
> > >   Silicon/Tools: Add a tool FitGen
> > >   Silicon/Tools: Add top level Makefile and GNUMakefile
> > >
> > >  Platform/Intel/Tools/BfmLib/BfmLib.c          | 4355 +++++++++++
> > >  Platform/Intel/Tools/BfmLib/BinFileManager.c  | 1024 +++
> > >  Platform/Intel/Tools/BfmLib/BinFileManager.h  |  439 ++
> > >  Platform/Intel/Tools/BfmLib/GNUmakefile       |   15 +
> > >  Platform/Intel/Tools/BfmLib/Makefile          |   17 +
> > >  Platform/Intel/Tools/FCE/BinaryCreate.c       |  216 +
> > >  Platform/Intel/Tools/FCE/BinaryCreate.h       |  157 +
> > >  Platform/Intel/Tools/FCE/BinaryParse.c        | 1326 ++++
> > >  Platform/Intel/Tools/FCE/BinaryParse.h        |  187 +
> > >  Platform/Intel/Tools/FCE/Common.c             | 2183 ++++++
> > >  Platform/Intel/Tools/FCE/Common.h             |  999 +++
> > >  Platform/Intel/Tools/FCE/Expression.c         | 2367 ++++++
> > >  Platform/Intel/Tools/FCE/Fce.c                | 6449
> > > +++++++++++++++++
> > >  Platform/Intel/Tools/FCE/Fce.h                |  447 ++
> > >  Platform/Intel/Tools/FCE/GNUmakefile          |   22 +
> > >  Platform/Intel/Tools/FCE/IfrParse.c           | 4836 ++++++++++++
> > >  Platform/Intel/Tools/FCE/IfrParse.h           |  789 ++
> > >  Platform/Intel/Tools/FCE/Makefile             |   19 +
> > >  .../Intel/Tools/FCE/MonotonicBasedVariable.c  |  874 +++
> > >  .../Intel/Tools/FCE/MonotonicBasedVariable.h  |  162 +
> > >  Platform/Intel/Tools/FCE/TimeBasedVariable.c  |  878 +++
> > >  Platform/Intel/Tools/FCE/TimeBasedVariable.h  |  166 +
> > >  Platform/Intel/Tools/FCE/Variable.c           | 1091 +++
> > >  Platform/Intel/Tools/FCE/Variable.h           |  154 +
> > >  Platform/Intel/Tools/FCE/VariableCommon.h     |   55 +
> > >  .../Tools/FMMT/FirmwareModuleManagement.c     | 2559 +++++++
> > >  .../Tools/FMMT/FirmwareModuleManagement.h     |  479 ++
> > >  Platform/Intel/Tools/FMMT/FmmtConf.ini        |    6 +
> > >  Platform/Intel/Tools/FMMT/FmmtLib.c           | 5051
> > > +++++++++++++
> > >  Platform/Intel/Tools/FMMT/GNUmakefile         |   16 +
> > >  Platform/Intel/Tools/FMMT/Makefile            |   17 +
> > >  Platform/Intel/Tools/FMMT/Rebase.c            |  846 +++
> > >  Platform/Intel/Tools/FMMT/Rebase.h            |   31 +
> > >  Platform/Intel/Tools/GNUmakefile              |   30 +
> > >  Platform/Intel/Tools/Makefile                 |   33 +
> > >  Silicon/Intel/Tools/FitGen/FitGen.c           | 3137 ++++++++
> > >  Silicon/Intel/Tools/FitGen/FitGen.h           |   48 +
> > >  Silicon/Intel/Tools/FitGen/GNUmakefile        |   16 +
> > >  Silicon/Intel/Tools/FitGen/Makefile           |   17 +
> > >  Silicon/Intel/Tools/GNUmakefile               |   34 +
> > >  Silicon/Intel/Tools/Makefile                  |   31 +
> > >  41 files changed, 41578 insertions(+)
> > >  create mode 100644 Platform/Intel/Tools/BfmLib/BfmLib.c
> > >  create mode 100644 Platform/Intel/Tools/BfmLib/BinFileManager.c
> > >  create mode 100644 Platform/Intel/Tools/BfmLib/BinFileManager.h
> > >  create mode 100644 Platform/Intel/Tools/BfmLib/GNUmakefile
> > >  create mode 100644 Platform/Intel/Tools/BfmLib/Makefile
> > >  create mode 100644 Platform/Intel/Tools/FCE/BinaryCreate.c
> > >  create mode 100644 Platform/Intel/Tools/FCE/BinaryCreate.h
> > >  create mode 100644 Platform/Intel/Tools/FCE/BinaryParse.c
> > >  create mode 100644 Platform/Intel/Tools/FCE/BinaryParse.h
> > >  create mode 100644 Platform/Intel/Tools/FCE/Common.c
> > >  create mode 100644 Platform/Intel/Tools/FCE/Common.h
> > >  create mode 100644 Platform/Intel/Tools/FCE/Expression.c
> > >  create mode 100644 Platform/Intel/Tools/FCE/Fce.c
> > >  create mode 100644 Platform/Intel/Tools/FCE/Fce.h
> > >  create mode 100644 Platform/Intel/Tools/FCE/GNUmakefile
> > >  create mode 100644 Platform/Intel/Tools/FCE/IfrParse.c
> > >  create mode 100644 Platform/Intel/Tools/FCE/IfrParse.h
> > >  create mode 100644 Platform/Intel/Tools/FCE/Makefile
> > >  create mode 100644
> Platform/Intel/Tools/FCE/MonotonicBasedVariable.c
> > >  create mode 100644
> Platform/Intel/Tools/FCE/MonotonicBasedVariable.h
> > >  create mode 100644 Platform/Intel/Tools/FCE/TimeBasedVariable.c
> > >  create mode 100644 Platform/Intel/Tools/FCE/TimeBasedVariable.h
> > >  create mode 100644 Platform/Intel/Tools/FCE/Variable.c
> > >  create mode 100644 Platform/Intel/Tools/FCE/Variable.h
> > >  create mode 100644 Platform/Intel/Tools/FCE/VariableCommon.h
> > >  create mode 100644
> > > Platform/Intel/Tools/FMMT/FirmwareModuleManagement.c
> > >  create mode 100644
> > > Platform/Intel/Tools/FMMT/FirmwareModuleManagement.h
> > >  create mode 100644 Platform/Intel/Tools/FMMT/FmmtConf.ini
> > >  create mode 100644 Platform/Intel/Tools/FMMT/FmmtLib.c
> > >  create mode 100644 Platform/Intel/Tools/FMMT/GNUmakefile
> > >  create mode 100644 Platform/Intel/Tools/FMMT/Makefile
> > >  create mode 100644 Platform/Intel/Tools/FMMT/Rebase.c
> > >  create mode 100644 Platform/Intel/Tools/FMMT/Rebase.h
> > >  create mode 100644 Platform/Intel/Tools/GNUmakefile
> > >  create mode 100644 Platform/Intel/Tools/Makefile
> > >  create mode 100644 Silicon/Intel/Tools/FitGen/FitGen.c
> > >  create mode 100644 Silicon/Intel/Tools/FitGen/FitGen.h
> > >  create mode 100644 Silicon/Intel/Tools/FitGen/GNUmakefile
> > >  create mode 100644 Silicon/Intel/Tools/FitGen/Makefile
> > >  create mode 100644 Silicon/Intel/Tools/GNUmakefile
> > >  create mode 100644 Silicon/Intel/Tools/Makefile
> > >
> > > --
> > > 2.18.0.windows.1
> > >
> > >
> > > 


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [edk2-devel] [edk2-platform patch 0/6] Add tools FMMT FCE and FitGen
  2019-06-21  3:34     ` Yao, Jiewen
@ 2019-06-25 14:09       ` Liming Gao
  2019-06-25 14:14         ` Yao, Jiewen
  0 siblings, 1 reply; 15+ messages in thread
From: Liming Gao @ 2019-06-25 14:09 UTC (permalink / raw)
  To: Yao, Jiewen, devel@edk2.groups.io, Zhang, Shenglei,
	ard.biesheuvel@linaro.org, leif.lindholm@linaro.org
  Cc: Feng, Bob C

Jiewen:
  For FCE/FMMT C tools, I only compile them on X64 Linux OS. I don't compile them on ARM or AARCH64 Linux OS for ARM native build. Now, edk2 BaseTools C tools top level Makefile supports ARM, AARCH64, IA32 and X64. If they don't pass build on ARM native Linux OS, this change will bring the break for some user. If we can avoid the break, I agree to add them into edk2 BaseTools. 

Ard: 
  I have no ARM or AARCH64 Linux OS. Could you help compile FCE/FMMT tools in ARM or AARCH64 Linux OS? These patches are in https://github.com/shenglei10/edk2/commits/movetool. After pick those patches, you just need to type make in BaseTools directory and compile all C tools. FCE/FMMT are common tools to update FD/FV image binaries. FMMT is a tool to enable removal, addition and replacement of FFS files in FD image binaries. FCE is a tool to retrieve and change HII configuration data as the default NV variable in Firmware Device(*.fd) files. They are used in post build step to replace FFS or insert the default NV storage in FD image.

Thanks
Liming
> -----Original Message-----
> From: Yao, Jiewen
> Sent: Friday, June 21, 2019 11:34 AM
> To: Gao, Liming <liming.gao@intel.com>; devel@edk2.groups.io; Zhang, Shenglei <shenglei.zhang@intel.com>
> Cc: Feng, Bob C <bob.c.feng@intel.com>
> Subject: RE: [edk2-devel] [edk2-platform patch 0/6] Add tools FMMT FCE and FitGen
> 
> Sorry, I missed the first mail.
> I saw there is no V2 tag in this series, so I think it is the first mail. My apology.
> 
> I have no concern on FitGen - it is Intel only. You can check in at first.
> FMMT/FCE is common. I think BaseTools is more proper place.
> 
> "It is not validated" - it seems a weird justification to me.
> Or does it mean, for any future feature Intel/ARM people contribute, we should treat Platform package as the first choice, just because the
> it is cross validated?
> 
> May I understand more on the rule we have today on what goes to EDK2 repo and what goes to EDK2-PLATFORM repo?
> 
> Thank you
> Yao Jiewen
> 
> 
> > -----Original Message-----
> > From: Gao, Liming
> > Sent: Friday, June 21, 2019 10:31 AM
> > To: Yao, Jiewen <jiewen.yao@intel.com>; devel@edk2.groups.io; Zhang,
> > Shenglei <shenglei.zhang@intel.com>
> > Cc: Feng, Bob C <bob.c.feng@intel.com>
> > Subject: RE: [edk2-devel] [edk2-platform patch 0/6] Add tools FMMT FCE
> > and FitGen
> >
> > Jiewen:
> >   I give the comments
> > https://edk2.groups.io/g/devel/message/42545?p=,,,20,0,0,0::Created,,FM
> > MT,20,2,0,32013143 for the patch BaseTools/FCE: Add a tool FCE
> >
> >   I give new proposal https://edk2.groups.io/g/devel/message/42546 for
> > those tools.
> >
> > Thanks
> > Liming
> > > -----Original Message-----
> > > From: Yao, Jiewen
> > > Sent: Friday, June 21, 2019 10:26 AM
> > > To: devel@edk2.groups.io; Zhang, Shenglei <shenglei.zhang@intel.com>
> > > Cc: Feng, Bob C <bob.c.feng@intel.com>; Gao, Liming
> > <liming.gao@intel.com>; Yao, Jiewen <jiewen.yao@intel.com>
> > > Subject: RE: [edk2-devel] [edk2-platform patch 0/6] Add tools FMMT FCE
> > and FitGen
> > >
> > > HI
> > > I saw some conflict:
> > > =========
> > > BaseTools/FCE: Add a tool FCE
> > > Add FMMT and FCE into Platform/Intel/Tools.
> > > =========
> > >
> > > I agree that FitGet goes to Intel silicon.
> > >
> > > Should we put both FCE/FMMT to BaseTools?
> > >
> > > Thank you
> > > Yao Jiewen
> > >
> > >
> > > > -----Original Message-----
> > > > From: devel@edk2.groups.io [mailto:devel@edk2.groups.io] On Behalf
> > Of
> > > > Zhang, Shenglei
> > > > Sent: Friday, June 21, 2019 9:27 AM
> > > > To: devel@edk2.groups.io
> > > > Cc: Feng, Bob C <bob.c.feng@intel.com>; Gao, Liming
> > > > <liming.gao@intel.com>
> > > > Subject: [edk2-devel] [edk2-platform patch 0/6] Add tools FMMT FCE and
> > > > FitGen
> > > >
> > > > Add FMMT and FCE into Platform/Intel/Tools.
> > > > Add FitGen into Silicon/Intel/Tools.
> > > > https://bugzilla.tianocore.org/show_bug.cgi?id=1847
> > > > https://bugzilla.tianocore.org/show_bug.cgi?id=1848
> > > > https://bugzilla.tianocore.org/show_bug.cgi?id=1849
> > > >
> > > > Cc: Bob Feng <bob.c.feng@intel.com>
> > > > Cc: Liming Gao <liming.gao@intel.com>
> > > > Shenglei Zhang (6):
> > > >   Platform/Tools: Add a tool FMMT
> > > >   Platform/Tools: Add a tool BfmLib
> > > >   BaseTools/FCE: Add a tool FCE
> > > >   Platform/Tools: Add top level Makefile and GNUMakefile
> > > >   Silicon/Tools: Add a tool FitGen
> > > >   Silicon/Tools: Add top level Makefile and GNUMakefile
> > > >
> > > >  Platform/Intel/Tools/BfmLib/BfmLib.c          | 4355 +++++++++++
> > > >  Platform/Intel/Tools/BfmLib/BinFileManager.c  | 1024 +++
> > > >  Platform/Intel/Tools/BfmLib/BinFileManager.h  |  439 ++
> > > >  Platform/Intel/Tools/BfmLib/GNUmakefile       |   15 +
> > > >  Platform/Intel/Tools/BfmLib/Makefile          |   17 +
> > > >  Platform/Intel/Tools/FCE/BinaryCreate.c       |  216 +
> > > >  Platform/Intel/Tools/FCE/BinaryCreate.h       |  157 +
> > > >  Platform/Intel/Tools/FCE/BinaryParse.c        | 1326 ++++
> > > >  Platform/Intel/Tools/FCE/BinaryParse.h        |  187 +
> > > >  Platform/Intel/Tools/FCE/Common.c             | 2183 ++++++
> > > >  Platform/Intel/Tools/FCE/Common.h             |  999 +++
> > > >  Platform/Intel/Tools/FCE/Expression.c         | 2367 ++++++
> > > >  Platform/Intel/Tools/FCE/Fce.c                | 6449
> > > > +++++++++++++++++
> > > >  Platform/Intel/Tools/FCE/Fce.h                |  447 ++
> > > >  Platform/Intel/Tools/FCE/GNUmakefile          |   22 +
> > > >  Platform/Intel/Tools/FCE/IfrParse.c           | 4836 ++++++++++++
> > > >  Platform/Intel/Tools/FCE/IfrParse.h           |  789 ++
> > > >  Platform/Intel/Tools/FCE/Makefile             |   19 +
> > > >  .../Intel/Tools/FCE/MonotonicBasedVariable.c  |  874 +++
> > > >  .../Intel/Tools/FCE/MonotonicBasedVariable.h  |  162 +
> > > >  Platform/Intel/Tools/FCE/TimeBasedVariable.c  |  878 +++
> > > >  Platform/Intel/Tools/FCE/TimeBasedVariable.h  |  166 +
> > > >  Platform/Intel/Tools/FCE/Variable.c           | 1091 +++
> > > >  Platform/Intel/Tools/FCE/Variable.h           |  154 +
> > > >  Platform/Intel/Tools/FCE/VariableCommon.h     |   55 +
> > > >  .../Tools/FMMT/FirmwareModuleManagement.c     | 2559 +++++++
> > > >  .../Tools/FMMT/FirmwareModuleManagement.h     |  479 ++
> > > >  Platform/Intel/Tools/FMMT/FmmtConf.ini        |    6 +
> > > >  Platform/Intel/Tools/FMMT/FmmtLib.c           | 5051
> > > > +++++++++++++
> > > >  Platform/Intel/Tools/FMMT/GNUmakefile         |   16 +
> > > >  Platform/Intel/Tools/FMMT/Makefile            |   17 +
> > > >  Platform/Intel/Tools/FMMT/Rebase.c            |  846 +++
> > > >  Platform/Intel/Tools/FMMT/Rebase.h            |   31 +
> > > >  Platform/Intel/Tools/GNUmakefile              |   30 +
> > > >  Platform/Intel/Tools/Makefile                 |   33 +
> > > >  Silicon/Intel/Tools/FitGen/FitGen.c           | 3137 ++++++++
> > > >  Silicon/Intel/Tools/FitGen/FitGen.h           |   48 +
> > > >  Silicon/Intel/Tools/FitGen/GNUmakefile        |   16 +
> > > >  Silicon/Intel/Tools/FitGen/Makefile           |   17 +
> > > >  Silicon/Intel/Tools/GNUmakefile               |   34 +
> > > >  Silicon/Intel/Tools/Makefile                  |   31 +
> > > >  41 files changed, 41578 insertions(+)
> > > >  create mode 100644 Platform/Intel/Tools/BfmLib/BfmLib.c
> > > >  create mode 100644 Platform/Intel/Tools/BfmLib/BinFileManager.c
> > > >  create mode 100644 Platform/Intel/Tools/BfmLib/BinFileManager.h
> > > >  create mode 100644 Platform/Intel/Tools/BfmLib/GNUmakefile
> > > >  create mode 100644 Platform/Intel/Tools/BfmLib/Makefile
> > > >  create mode 100644 Platform/Intel/Tools/FCE/BinaryCreate.c
> > > >  create mode 100644 Platform/Intel/Tools/FCE/BinaryCreate.h
> > > >  create mode 100644 Platform/Intel/Tools/FCE/BinaryParse.c
> > > >  create mode 100644 Platform/Intel/Tools/FCE/BinaryParse.h
> > > >  create mode 100644 Platform/Intel/Tools/FCE/Common.c
> > > >  create mode 100644 Platform/Intel/Tools/FCE/Common.h
> > > >  create mode 100644 Platform/Intel/Tools/FCE/Expression.c
> > > >  create mode 100644 Platform/Intel/Tools/FCE/Fce.c
> > > >  create mode 100644 Platform/Intel/Tools/FCE/Fce.h
> > > >  create mode 100644 Platform/Intel/Tools/FCE/GNUmakefile
> > > >  create mode 100644 Platform/Intel/Tools/FCE/IfrParse.c
> > > >  create mode 100644 Platform/Intel/Tools/FCE/IfrParse.h
> > > >  create mode 100644 Platform/Intel/Tools/FCE/Makefile
> > > >  create mode 100644
> > Platform/Intel/Tools/FCE/MonotonicBasedVariable.c
> > > >  create mode 100644
> > Platform/Intel/Tools/FCE/MonotonicBasedVariable.h
> > > >  create mode 100644 Platform/Intel/Tools/FCE/TimeBasedVariable.c
> > > >  create mode 100644 Platform/Intel/Tools/FCE/TimeBasedVariable.h
> > > >  create mode 100644 Platform/Intel/Tools/FCE/Variable.c
> > > >  create mode 100644 Platform/Intel/Tools/FCE/Variable.h
> > > >  create mode 100644 Platform/Intel/Tools/FCE/VariableCommon.h
> > > >  create mode 100644
> > > > Platform/Intel/Tools/FMMT/FirmwareModuleManagement.c
> > > >  create mode 100644
> > > > Platform/Intel/Tools/FMMT/FirmwareModuleManagement.h
> > > >  create mode 100644 Platform/Intel/Tools/FMMT/FmmtConf.ini
> > > >  create mode 100644 Platform/Intel/Tools/FMMT/FmmtLib.c
> > > >  create mode 100644 Platform/Intel/Tools/FMMT/GNUmakefile
> > > >  create mode 100644 Platform/Intel/Tools/FMMT/Makefile
> > > >  create mode 100644 Platform/Intel/Tools/FMMT/Rebase.c
> > > >  create mode 100644 Platform/Intel/Tools/FMMT/Rebase.h
> > > >  create mode 100644 Platform/Intel/Tools/GNUmakefile
> > > >  create mode 100644 Platform/Intel/Tools/Makefile
> > > >  create mode 100644 Silicon/Intel/Tools/FitGen/FitGen.c
> > > >  create mode 100644 Silicon/Intel/Tools/FitGen/FitGen.h
> > > >  create mode 100644 Silicon/Intel/Tools/FitGen/GNUmakefile
> > > >  create mode 100644 Silicon/Intel/Tools/FitGen/Makefile
> > > >  create mode 100644 Silicon/Intel/Tools/GNUmakefile
> > > >  create mode 100644 Silicon/Intel/Tools/Makefile
> > > >
> > > > --
> > > > 2.18.0.windows.1
> > > >
> > > >
> > > > 


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [edk2-devel] [edk2-platform patch 0/6] Add tools FMMT FCE and FitGen
  2019-06-25 14:09       ` Liming Gao
@ 2019-06-25 14:14         ` Yao, Jiewen
  2019-06-25 15:20           ` Liming Gao
  0 siblings, 1 reply; 15+ messages in thread
From: Yao, Jiewen @ 2019-06-25 14:14 UTC (permalink / raw)
  To: Gao, Liming, devel@edk2.groups.io, Zhang, Shenglei,
	ard.biesheuvel@linaro.org, leif.lindholm@linaro.org
  Cc: Feng, Bob C

Thanks Liming.

I would treat that as *a general help request* to validate the BaseTool update on ARM/AARCH64 Linux OS.

If we can have Ard or any other ARM person to help validate a new base tool patch, that will be great.

In this case, it is about the new added FCE or FMMT.
In the future, maybe we have other C-tool update.

Should we add them to CC list in any tool patch?


Thank you
Yao Jiewen

> -----Original Message-----
> From: Gao, Liming
> Sent: Tuesday, June 25, 2019 10:09 PM
> To: Yao, Jiewen <jiewen.yao@intel.com>; devel@edk2.groups.io; Zhang,
> Shenglei <shenglei.zhang@intel.com>; ard.biesheuvel@linaro.org;
> leif.lindholm@linaro.org
> Cc: Feng, Bob C <bob.c.feng@intel.com>
> Subject: RE: [edk2-devel] [edk2-platform patch 0/6] Add tools FMMT FCE
> and FitGen
> 
> Jiewen:
>   For FCE/FMMT C tools, I only compile them on X64 Linux OS. I don't
> compile them on ARM or AARCH64 Linux OS for ARM native build. Now,
> edk2 BaseTools C tools top level Makefile supports ARM, AARCH64, IA32 and
> X64. If they don't pass build on ARM native Linux OS, this change will bring
> the break for some user. If we can avoid the break, I agree to add them into
> edk2 BaseTools.
> 
> Ard:
>   I have no ARM or AARCH64 Linux OS. Could you help compile FCE/FMMT
> tools in ARM or AARCH64 Linux OS? These patches are in
> https://github.com/shenglei10/edk2/commits/movetool. After pick those
> patches, you just need to type make in BaseTools directory and compile all C
> tools. FCE/FMMT are common tools to update FD/FV image binaries. FMMT
> is a tool to enable removal, addition and replacement of FFS files in FD
> image binaries. FCE is a tool to retrieve and change HII configuration data as
> the default NV variable in Firmware Device(*.fd) files. They are used in post
> build step to replace FFS or insert the default NV storage in FD image.
> 
> Thanks
> Liming
> > -----Original Message-----
> > From: Yao, Jiewen
> > Sent: Friday, June 21, 2019 11:34 AM
> > To: Gao, Liming <liming.gao@intel.com>; devel@edk2.groups.io; Zhang,
> Shenglei <shenglei.zhang@intel.com>
> > Cc: Feng, Bob C <bob.c.feng@intel.com>
> > Subject: RE: [edk2-devel] [edk2-platform patch 0/6] Add tools FMMT FCE
> and FitGen
> >
> > Sorry, I missed the first mail.
> > I saw there is no V2 tag in this series, so I think it is the first mail. My
> apology.
> >
> > I have no concern on FitGen - it is Intel only. You can check in at first.
> > FMMT/FCE is common. I think BaseTools is more proper place.
> >
> > "It is not validated" - it seems a weird justification to me.
> > Or does it mean, for any future feature Intel/ARM people contribute, we
> should treat Platform package as the first choice, just because the
> > it is cross validated?
> >
> > May I understand more on the rule we have today on what goes to EDK2
> repo and what goes to EDK2-PLATFORM repo?
> >
> > Thank you
> > Yao Jiewen
> >
> >
> > > -----Original Message-----
> > > From: Gao, Liming
> > > Sent: Friday, June 21, 2019 10:31 AM
> > > To: Yao, Jiewen <jiewen.yao@intel.com>; devel@edk2.groups.io; Zhang,
> > > Shenglei <shenglei.zhang@intel.com>
> > > Cc: Feng, Bob C <bob.c.feng@intel.com>
> > > Subject: RE: [edk2-devel] [edk2-platform patch 0/6] Add tools FMMT FCE
> > > and FitGen
> > >
> > > Jiewen:
> > >   I give the comments
> > >
> https://edk2.groups.io/g/devel/message/42545?p=,,,20,0,0,0::Created,,FM
> > > MT,20,2,0,32013143 for the patch BaseTools/FCE: Add a tool FCE
> > >
> > >   I give new proposal https://edk2.groups.io/g/devel/message/42546
> for
> > > those tools.
> > >
> > > Thanks
> > > Liming
> > > > -----Original Message-----
> > > > From: Yao, Jiewen
> > > > Sent: Friday, June 21, 2019 10:26 AM
> > > > To: devel@edk2.groups.io; Zhang, Shenglei
> <shenglei.zhang@intel.com>
> > > > Cc: Feng, Bob C <bob.c.feng@intel.com>; Gao, Liming
> > > <liming.gao@intel.com>; Yao, Jiewen <jiewen.yao@intel.com>
> > > > Subject: RE: [edk2-devel] [edk2-platform patch 0/6] Add tools FMMT
> FCE
> > > and FitGen
> > > >
> > > > HI
> > > > I saw some conflict:
> > > > =========
> > > > BaseTools/FCE: Add a tool FCE
> > > > Add FMMT and FCE into Platform/Intel/Tools.
> > > > =========
> > > >
> > > > I agree that FitGet goes to Intel silicon.
> > > >
> > > > Should we put both FCE/FMMT to BaseTools?
> > > >
> > > > Thank you
> > > > Yao Jiewen
> > > >
> > > >
> > > > > -----Original Message-----
> > > > > From: devel@edk2.groups.io [mailto:devel@edk2.groups.io] On
> Behalf
> > > Of
> > > > > Zhang, Shenglei
> > > > > Sent: Friday, June 21, 2019 9:27 AM
> > > > > To: devel@edk2.groups.io
> > > > > Cc: Feng, Bob C <bob.c.feng@intel.com>; Gao, Liming
> > > > > <liming.gao@intel.com>
> > > > > Subject: [edk2-devel] [edk2-platform patch 0/6] Add tools FMMT FCE
> and
> > > > > FitGen
> > > > >
> > > > > Add FMMT and FCE into Platform/Intel/Tools.
> > > > > Add FitGen into Silicon/Intel/Tools.
> > > > > https://bugzilla.tianocore.org/show_bug.cgi?id=1847
> > > > > https://bugzilla.tianocore.org/show_bug.cgi?id=1848
> > > > > https://bugzilla.tianocore.org/show_bug.cgi?id=1849
> > > > >
> > > > > Cc: Bob Feng <bob.c.feng@intel.com>
> > > > > Cc: Liming Gao <liming.gao@intel.com>
> > > > > Shenglei Zhang (6):
> > > > >   Platform/Tools: Add a tool FMMT
> > > > >   Platform/Tools: Add a tool BfmLib
> > > > >   BaseTools/FCE: Add a tool FCE
> > > > >   Platform/Tools: Add top level Makefile and GNUMakefile
> > > > >   Silicon/Tools: Add a tool FitGen
> > > > >   Silicon/Tools: Add top level Makefile and GNUMakefile
> > > > >
> > > > >  Platform/Intel/Tools/BfmLib/BfmLib.c          | 4355
> +++++++++++
> > > > >  Platform/Intel/Tools/BfmLib/BinFileManager.c  | 1024 +++
> > > > >  Platform/Intel/Tools/BfmLib/BinFileManager.h  |  439 ++
> > > > >  Platform/Intel/Tools/BfmLib/GNUmakefile       |   15 +
> > > > >  Platform/Intel/Tools/BfmLib/Makefile          |   17 +
> > > > >  Platform/Intel/Tools/FCE/BinaryCreate.c       |  216 +
> > > > >  Platform/Intel/Tools/FCE/BinaryCreate.h       |  157 +
> > > > >  Platform/Intel/Tools/FCE/BinaryParse.c        | 1326 ++++
> > > > >  Platform/Intel/Tools/FCE/BinaryParse.h        |  187 +
> > > > >  Platform/Intel/Tools/FCE/Common.c             | 2183 ++++++
> > > > >  Platform/Intel/Tools/FCE/Common.h             |  999 +++
> > > > >  Platform/Intel/Tools/FCE/Expression.c         | 2367 ++++++
> > > > >  Platform/Intel/Tools/FCE/Fce.c                | 6449
> > > > > +++++++++++++++++
> > > > >  Platform/Intel/Tools/FCE/Fce.h                |  447 ++
> > > > >  Platform/Intel/Tools/FCE/GNUmakefile          |   22 +
> > > > >  Platform/Intel/Tools/FCE/IfrParse.c           | 4836
> ++++++++++++
> > > > >  Platform/Intel/Tools/FCE/IfrParse.h           |  789 ++
> > > > >  Platform/Intel/Tools/FCE/Makefile             |   19 +
> > > > >  .../Intel/Tools/FCE/MonotonicBasedVariable.c  |  874 +++
> > > > >  .../Intel/Tools/FCE/MonotonicBasedVariable.h  |  162 +
> > > > >  Platform/Intel/Tools/FCE/TimeBasedVariable.c  |  878 +++
> > > > >  Platform/Intel/Tools/FCE/TimeBasedVariable.h  |  166 +
> > > > >  Platform/Intel/Tools/FCE/Variable.c           | 1091 +++
> > > > >  Platform/Intel/Tools/FCE/Variable.h           |  154 +
> > > > >  Platform/Intel/Tools/FCE/VariableCommon.h     |   55 +
> > > > >  .../Tools/FMMT/FirmwareModuleManagement.c     | 2559
> +++++++
> > > > >  .../Tools/FMMT/FirmwareModuleManagement.h     |  479 ++
> > > > >  Platform/Intel/Tools/FMMT/FmmtConf.ini        |    6 +
> > > > >  Platform/Intel/Tools/FMMT/FmmtLib.c           | 5051
> > > > > +++++++++++++
> > > > >  Platform/Intel/Tools/FMMT/GNUmakefile         |   16 +
> > > > >  Platform/Intel/Tools/FMMT/Makefile            |   17 +
> > > > >  Platform/Intel/Tools/FMMT/Rebase.c            |  846 +++
> > > > >  Platform/Intel/Tools/FMMT/Rebase.h            |   31 +
> > > > >  Platform/Intel/Tools/GNUmakefile              |   30 +
> > > > >  Platform/Intel/Tools/Makefile                 |   33 +
> > > > >  Silicon/Intel/Tools/FitGen/FitGen.c           | 3137 ++++++++
> > > > >  Silicon/Intel/Tools/FitGen/FitGen.h           |   48 +
> > > > >  Silicon/Intel/Tools/FitGen/GNUmakefile        |   16 +
> > > > >  Silicon/Intel/Tools/FitGen/Makefile           |   17 +
> > > > >  Silicon/Intel/Tools/GNUmakefile               |   34 +
> > > > >  Silicon/Intel/Tools/Makefile                  |   31 +
> > > > >  41 files changed, 41578 insertions(+)
> > > > >  create mode 100644 Platform/Intel/Tools/BfmLib/BfmLib.c
> > > > >  create mode 100644
> Platform/Intel/Tools/BfmLib/BinFileManager.c
> > > > >  create mode 100644
> Platform/Intel/Tools/BfmLib/BinFileManager.h
> > > > >  create mode 100644 Platform/Intel/Tools/BfmLib/GNUmakefile
> > > > >  create mode 100644 Platform/Intel/Tools/BfmLib/Makefile
> > > > >  create mode 100644 Platform/Intel/Tools/FCE/BinaryCreate.c
> > > > >  create mode 100644 Platform/Intel/Tools/FCE/BinaryCreate.h
> > > > >  create mode 100644 Platform/Intel/Tools/FCE/BinaryParse.c
> > > > >  create mode 100644 Platform/Intel/Tools/FCE/BinaryParse.h
> > > > >  create mode 100644 Platform/Intel/Tools/FCE/Common.c
> > > > >  create mode 100644 Platform/Intel/Tools/FCE/Common.h
> > > > >  create mode 100644 Platform/Intel/Tools/FCE/Expression.c
> > > > >  create mode 100644 Platform/Intel/Tools/FCE/Fce.c
> > > > >  create mode 100644 Platform/Intel/Tools/FCE/Fce.h
> > > > >  create mode 100644 Platform/Intel/Tools/FCE/GNUmakefile
> > > > >  create mode 100644 Platform/Intel/Tools/FCE/IfrParse.c
> > > > >  create mode 100644 Platform/Intel/Tools/FCE/IfrParse.h
> > > > >  create mode 100644 Platform/Intel/Tools/FCE/Makefile
> > > > >  create mode 100644
> > > Platform/Intel/Tools/FCE/MonotonicBasedVariable.c
> > > > >  create mode 100644
> > > Platform/Intel/Tools/FCE/MonotonicBasedVariable.h
> > > > >  create mode 100644
> Platform/Intel/Tools/FCE/TimeBasedVariable.c
> > > > >  create mode 100644
> Platform/Intel/Tools/FCE/TimeBasedVariable.h
> > > > >  create mode 100644 Platform/Intel/Tools/FCE/Variable.c
> > > > >  create mode 100644 Platform/Intel/Tools/FCE/Variable.h
> > > > >  create mode 100644 Platform/Intel/Tools/FCE/VariableCommon.h
> > > > >  create mode 100644
> > > > > Platform/Intel/Tools/FMMT/FirmwareModuleManagement.c
> > > > >  create mode 100644
> > > > > Platform/Intel/Tools/FMMT/FirmwareModuleManagement.h
> > > > >  create mode 100644 Platform/Intel/Tools/FMMT/FmmtConf.ini
> > > > >  create mode 100644 Platform/Intel/Tools/FMMT/FmmtLib.c
> > > > >  create mode 100644 Platform/Intel/Tools/FMMT/GNUmakefile
> > > > >  create mode 100644 Platform/Intel/Tools/FMMT/Makefile
> > > > >  create mode 100644 Platform/Intel/Tools/FMMT/Rebase.c
> > > > >  create mode 100644 Platform/Intel/Tools/FMMT/Rebase.h
> > > > >  create mode 100644 Platform/Intel/Tools/GNUmakefile
> > > > >  create mode 100644 Platform/Intel/Tools/Makefile
> > > > >  create mode 100644 Silicon/Intel/Tools/FitGen/FitGen.c
> > > > >  create mode 100644 Silicon/Intel/Tools/FitGen/FitGen.h
> > > > >  create mode 100644 Silicon/Intel/Tools/FitGen/GNUmakefile
> > > > >  create mode 100644 Silicon/Intel/Tools/FitGen/Makefile
> > > > >  create mode 100644 Silicon/Intel/Tools/GNUmakefile
> > > > >  create mode 100644 Silicon/Intel/Tools/Makefile
> > > > >
> > > > > --
> > > > > 2.18.0.windows.1
> > > > >
> > > > >
> > > > > 


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [edk2-devel] [edk2-platform patch 0/6] Add tools FMMT FCE and FitGen
  2019-06-25 14:14         ` Yao, Jiewen
@ 2019-06-25 15:20           ` Liming Gao
  0 siblings, 0 replies; 15+ messages in thread
From: Liming Gao @ 2019-06-25 15:20 UTC (permalink / raw)
  To: Yao, Jiewen, devel@edk2.groups.io, Zhang, Shenglei,
	ard.biesheuvel@linaro.org, leif.lindholm@linaro.org
  Cc: Feng, Bob C, Gao, Liming

Jiewen:

Thanks
Liming
> -----Original Message-----
> From: Yao, Jiewen
> Sent: Tuesday, June 25, 2019 10:15 PM
> To: Gao, Liming <liming.gao@intel.com>; devel@edk2.groups.io; Zhang, Shenglei <shenglei.zhang@intel.com>; ard.biesheuvel@linaro.org;
> leif.lindholm@linaro.org
> Cc: Feng, Bob C <bob.c.feng@intel.com>
> Subject: RE: [edk2-devel] [edk2-platform patch 0/6] Add tools FMMT FCE and FitGen
> 
> Thanks Liming.
> 
> I would treat that as *a general help request* to validate the BaseTool update on ARM/AARCH64 Linux OS.
> 

Yes. This is a help request. 

> If we can have Ard or any other ARM person to help validate a new base tool patch, that will be great.
> 
> In this case, it is about the new added FCE or FMMT.
> In the future, maybe we have other C-tool update.
> 
> Should we add them to CC list in any tool patch?
> 

FCE and FMMT are new tools with lots of source code. If they meet with the compile failure, it may take more effort to fix them. 
So, I want to verify them before submit the patches. If the code change is not big, the developer can fix the error quickly 
after the code is submitted. That's also fine to verify the change after submit. 

Thanks
Liming
> 
> Thank you
> Yao Jiewen
> 
> > -----Original Message-----
> > From: Gao, Liming
> > Sent: Tuesday, June 25, 2019 10:09 PM
> > To: Yao, Jiewen <jiewen.yao@intel.com>; devel@edk2.groups.io; Zhang,
> > Shenglei <shenglei.zhang@intel.com>; ard.biesheuvel@linaro.org;
> > leif.lindholm@linaro.org
> > Cc: Feng, Bob C <bob.c.feng@intel.com>
> > Subject: RE: [edk2-devel] [edk2-platform patch 0/6] Add tools FMMT FCE
> > and FitGen
> >
> > Jiewen:
> >   For FCE/FMMT C tools, I only compile them on X64 Linux OS. I don't
> > compile them on ARM or AARCH64 Linux OS for ARM native build. Now,
> > edk2 BaseTools C tools top level Makefile supports ARM, AARCH64, IA32 and
> > X64. If they don't pass build on ARM native Linux OS, this change will bring
> > the break for some user. If we can avoid the break, I agree to add them into
> > edk2 BaseTools.
> >
> > Ard:
> >   I have no ARM or AARCH64 Linux OS. Could you help compile FCE/FMMT
> > tools in ARM or AARCH64 Linux OS? These patches are in
> > https://github.com/shenglei10/edk2/commits/movetool. After pick those
> > patches, you just need to type make in BaseTools directory and compile all C
> > tools. FCE/FMMT are common tools to update FD/FV image binaries. FMMT
> > is a tool to enable removal, addition and replacement of FFS files in FD
> > image binaries. FCE is a tool to retrieve and change HII configuration data as
> > the default NV variable in Firmware Device(*.fd) files. They are used in post
> > build step to replace FFS or insert the default NV storage in FD image.
> >
> > Thanks
> > Liming
> > > -----Original Message-----
> > > From: Yao, Jiewen
> > > Sent: Friday, June 21, 2019 11:34 AM
> > > To: Gao, Liming <liming.gao@intel.com>; devel@edk2.groups.io; Zhang,
> > Shenglei <shenglei.zhang@intel.com>
> > > Cc: Feng, Bob C <bob.c.feng@intel.com>
> > > Subject: RE: [edk2-devel] [edk2-platform patch 0/6] Add tools FMMT FCE
> > and FitGen
> > >
> > > Sorry, I missed the first mail.
> > > I saw there is no V2 tag in this series, so I think it is the first mail. My
> > apology.
> > >
> > > I have no concern on FitGen - it is Intel only. You can check in at first.
> > > FMMT/FCE is common. I think BaseTools is more proper place.
> > >
> > > "It is not validated" - it seems a weird justification to me.
> > > Or does it mean, for any future feature Intel/ARM people contribute, we
> > should treat Platform package as the first choice, just because the
> > > it is cross validated?
> > >
> > > May I understand more on the rule we have today on what goes to EDK2
> > repo and what goes to EDK2-PLATFORM repo?
> > >
> > > Thank you
> > > Yao Jiewen
> > >
> > >
> > > > -----Original Message-----
> > > > From: Gao, Liming
> > > > Sent: Friday, June 21, 2019 10:31 AM
> > > > To: Yao, Jiewen <jiewen.yao@intel.com>; devel@edk2.groups.io; Zhang,
> > > > Shenglei <shenglei.zhang@intel.com>
> > > > Cc: Feng, Bob C <bob.c.feng@intel.com>
> > > > Subject: RE: [edk2-devel] [edk2-platform patch 0/6] Add tools FMMT FCE
> > > > and FitGen
> > > >
> > > > Jiewen:
> > > >   I give the comments
> > > >
> > https://edk2.groups.io/g/devel/message/42545?p=,,,20,0,0,0::Created,,FM
> > > > MT,20,2,0,32013143 for the patch BaseTools/FCE: Add a tool FCE
> > > >
> > > >   I give new proposal https://edk2.groups.io/g/devel/message/42546
> > for
> > > > those tools.
> > > >
> > > > Thanks
> > > > Liming
> > > > > -----Original Message-----
> > > > > From: Yao, Jiewen
> > > > > Sent: Friday, June 21, 2019 10:26 AM
> > > > > To: devel@edk2.groups.io; Zhang, Shenglei
> > <shenglei.zhang@intel.com>
> > > > > Cc: Feng, Bob C <bob.c.feng@intel.com>; Gao, Liming
> > > > <liming.gao@intel.com>; Yao, Jiewen <jiewen.yao@intel.com>
> > > > > Subject: RE: [edk2-devel] [edk2-platform patch 0/6] Add tools FMMT
> > FCE
> > > > and FitGen
> > > > >
> > > > > HI
> > > > > I saw some conflict:
> > > > > =========
> > > > > BaseTools/FCE: Add a tool FCE
> > > > > Add FMMT and FCE into Platform/Intel/Tools.
> > > > > =========
> > > > >
> > > > > I agree that FitGet goes to Intel silicon.
> > > > >
> > > > > Should we put both FCE/FMMT to BaseTools?
> > > > >
> > > > > Thank you
> > > > > Yao Jiewen
> > > > >
> > > > >
> > > > > > -----Original Message-----
> > > > > > From: devel@edk2.groups.io [mailto:devel@edk2.groups.io] On
> > Behalf
> > > > Of
> > > > > > Zhang, Shenglei
> > > > > > Sent: Friday, June 21, 2019 9:27 AM
> > > > > > To: devel@edk2.groups.io
> > > > > > Cc: Feng, Bob C <bob.c.feng@intel.com>; Gao, Liming
> > > > > > <liming.gao@intel.com>
> > > > > > Subject: [edk2-devel] [edk2-platform patch 0/6] Add tools FMMT FCE
> > and
> > > > > > FitGen
> > > > > >
> > > > > > Add FMMT and FCE into Platform/Intel/Tools.
> > > > > > Add FitGen into Silicon/Intel/Tools.
> > > > > > https://bugzilla.tianocore.org/show_bug.cgi?id=1847
> > > > > > https://bugzilla.tianocore.org/show_bug.cgi?id=1848
> > > > > > https://bugzilla.tianocore.org/show_bug.cgi?id=1849
> > > > > >
> > > > > > Cc: Bob Feng <bob.c.feng@intel.com>
> > > > > > Cc: Liming Gao <liming.gao@intel.com>
> > > > > > Shenglei Zhang (6):
> > > > > >   Platform/Tools: Add a tool FMMT
> > > > > >   Platform/Tools: Add a tool BfmLib
> > > > > >   BaseTools/FCE: Add a tool FCE
> > > > > >   Platform/Tools: Add top level Makefile and GNUMakefile
> > > > > >   Silicon/Tools: Add a tool FitGen
> > > > > >   Silicon/Tools: Add top level Makefile and GNUMakefile
> > > > > >
> > > > > >  Platform/Intel/Tools/BfmLib/BfmLib.c          | 4355
> > +++++++++++
> > > > > >  Platform/Intel/Tools/BfmLib/BinFileManager.c  | 1024 +++
> > > > > >  Platform/Intel/Tools/BfmLib/BinFileManager.h  |  439 ++
> > > > > >  Platform/Intel/Tools/BfmLib/GNUmakefile       |   15 +
> > > > > >  Platform/Intel/Tools/BfmLib/Makefile          |   17 +
> > > > > >  Platform/Intel/Tools/FCE/BinaryCreate.c       |  216 +
> > > > > >  Platform/Intel/Tools/FCE/BinaryCreate.h       |  157 +
> > > > > >  Platform/Intel/Tools/FCE/BinaryParse.c        | 1326 ++++
> > > > > >  Platform/Intel/Tools/FCE/BinaryParse.h        |  187 +
> > > > > >  Platform/Intel/Tools/FCE/Common.c             | 2183 ++++++
> > > > > >  Platform/Intel/Tools/FCE/Common.h             |  999 +++
> > > > > >  Platform/Intel/Tools/FCE/Expression.c         | 2367 ++++++
> > > > > >  Platform/Intel/Tools/FCE/Fce.c                | 6449
> > > > > > +++++++++++++++++
> > > > > >  Platform/Intel/Tools/FCE/Fce.h                |  447 ++
> > > > > >  Platform/Intel/Tools/FCE/GNUmakefile          |   22 +
> > > > > >  Platform/Intel/Tools/FCE/IfrParse.c           | 4836
> > ++++++++++++
> > > > > >  Platform/Intel/Tools/FCE/IfrParse.h           |  789 ++
> > > > > >  Platform/Intel/Tools/FCE/Makefile             |   19 +
> > > > > >  .../Intel/Tools/FCE/MonotonicBasedVariable.c  |  874 +++
> > > > > >  .../Intel/Tools/FCE/MonotonicBasedVariable.h  |  162 +
> > > > > >  Platform/Intel/Tools/FCE/TimeBasedVariable.c  |  878 +++
> > > > > >  Platform/Intel/Tools/FCE/TimeBasedVariable.h  |  166 +
> > > > > >  Platform/Intel/Tools/FCE/Variable.c           | 1091 +++
> > > > > >  Platform/Intel/Tools/FCE/Variable.h           |  154 +
> > > > > >  Platform/Intel/Tools/FCE/VariableCommon.h     |   55 +
> > > > > >  .../Tools/FMMT/FirmwareModuleManagement.c     | 2559
> > +++++++
> > > > > >  .../Tools/FMMT/FirmwareModuleManagement.h     |  479 ++
> > > > > >  Platform/Intel/Tools/FMMT/FmmtConf.ini        |    6 +
> > > > > >  Platform/Intel/Tools/FMMT/FmmtLib.c           | 5051
> > > > > > +++++++++++++
> > > > > >  Platform/Intel/Tools/FMMT/GNUmakefile         |   16 +
> > > > > >  Platform/Intel/Tools/FMMT/Makefile            |   17 +
> > > > > >  Platform/Intel/Tools/FMMT/Rebase.c            |  846 +++
> > > > > >  Platform/Intel/Tools/FMMT/Rebase.h            |   31 +
> > > > > >  Platform/Intel/Tools/GNUmakefile              |   30 +
> > > > > >  Platform/Intel/Tools/Makefile                 |   33 +
> > > > > >  Silicon/Intel/Tools/FitGen/FitGen.c           | 3137 ++++++++
> > > > > >  Silicon/Intel/Tools/FitGen/FitGen.h           |   48 +
> > > > > >  Silicon/Intel/Tools/FitGen/GNUmakefile        |   16 +
> > > > > >  Silicon/Intel/Tools/FitGen/Makefile           |   17 +
> > > > > >  Silicon/Intel/Tools/GNUmakefile               |   34 +
> > > > > >  Silicon/Intel/Tools/Makefile                  |   31 +
> > > > > >  41 files changed, 41578 insertions(+)
> > > > > >  create mode 100644 Platform/Intel/Tools/BfmLib/BfmLib.c
> > > > > >  create mode 100644
> > Platform/Intel/Tools/BfmLib/BinFileManager.c
> > > > > >  create mode 100644
> > Platform/Intel/Tools/BfmLib/BinFileManager.h
> > > > > >  create mode 100644 Platform/Intel/Tools/BfmLib/GNUmakefile
> > > > > >  create mode 100644 Platform/Intel/Tools/BfmLib/Makefile
> > > > > >  create mode 100644 Platform/Intel/Tools/FCE/BinaryCreate.c
> > > > > >  create mode 100644 Platform/Intel/Tools/FCE/BinaryCreate.h
> > > > > >  create mode 100644 Platform/Intel/Tools/FCE/BinaryParse.c
> > > > > >  create mode 100644 Platform/Intel/Tools/FCE/BinaryParse.h
> > > > > >  create mode 100644 Platform/Intel/Tools/FCE/Common.c
> > > > > >  create mode 100644 Platform/Intel/Tools/FCE/Common.h
> > > > > >  create mode 100644 Platform/Intel/Tools/FCE/Expression.c
> > > > > >  create mode 100644 Platform/Intel/Tools/FCE/Fce.c
> > > > > >  create mode 100644 Platform/Intel/Tools/FCE/Fce.h
> > > > > >  create mode 100644 Platform/Intel/Tools/FCE/GNUmakefile
> > > > > >  create mode 100644 Platform/Intel/Tools/FCE/IfrParse.c
> > > > > >  create mode 100644 Platform/Intel/Tools/FCE/IfrParse.h
> > > > > >  create mode 100644 Platform/Intel/Tools/FCE/Makefile
> > > > > >  create mode 100644
> > > > Platform/Intel/Tools/FCE/MonotonicBasedVariable.c
> > > > > >  create mode 100644
> > > > Platform/Intel/Tools/FCE/MonotonicBasedVariable.h
> > > > > >  create mode 100644
> > Platform/Intel/Tools/FCE/TimeBasedVariable.c
> > > > > >  create mode 100644
> > Platform/Intel/Tools/FCE/TimeBasedVariable.h
> > > > > >  create mode 100644 Platform/Intel/Tools/FCE/Variable.c
> > > > > >  create mode 100644 Platform/Intel/Tools/FCE/Variable.h
> > > > > >  create mode 100644 Platform/Intel/Tools/FCE/VariableCommon.h
> > > > > >  create mode 100644
> > > > > > Platform/Intel/Tools/FMMT/FirmwareModuleManagement.c
> > > > > >  create mode 100644
> > > > > > Platform/Intel/Tools/FMMT/FirmwareModuleManagement.h
> > > > > >  create mode 100644 Platform/Intel/Tools/FMMT/FmmtConf.ini
> > > > > >  create mode 100644 Platform/Intel/Tools/FMMT/FmmtLib.c
> > > > > >  create mode 100644 Platform/Intel/Tools/FMMT/GNUmakefile
> > > > > >  create mode 100644 Platform/Intel/Tools/FMMT/Makefile
> > > > > >  create mode 100644 Platform/Intel/Tools/FMMT/Rebase.c
> > > > > >  create mode 100644 Platform/Intel/Tools/FMMT/Rebase.h
> > > > > >  create mode 100644 Platform/Intel/Tools/GNUmakefile
> > > > > >  create mode 100644 Platform/Intel/Tools/Makefile
> > > > > >  create mode 100644 Silicon/Intel/Tools/FitGen/FitGen.c
> > > > > >  create mode 100644 Silicon/Intel/Tools/FitGen/FitGen.h
> > > > > >  create mode 100644 Silicon/Intel/Tools/FitGen/GNUmakefile
> > > > > >  create mode 100644 Silicon/Intel/Tools/FitGen/Makefile
> > > > > >  create mode 100644 Silicon/Intel/Tools/GNUmakefile
> > > > > >  create mode 100644 Silicon/Intel/Tools/Makefile
> > > > > >
> > > > > > --
> > > > > > 2.18.0.windows.1
> > > > > >
> > > > > >
> > > > > > 


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [edk2-devel] [edk2-platform patch 5/6] Silicon\Tools: Add a tool FitGen
  2019-06-21  1:26 ` [edk2-platform patch 5/6] Silicon\Tools: Add a tool FitGen Zhang, Shenglei
@ 2019-06-26  2:03   ` Liming Gao
  0 siblings, 0 replies; 15+ messages in thread
From: Liming Gao @ 2019-06-26  2:03 UTC (permalink / raw)
  To: devel@edk2.groups.io, Zhang, Shenglei; +Cc: Feng, Bob C

Shenglei:
  The patch is good to me. Reviewed-by: Liming Gao <liming.gao@intel.com>

Thanks
Liming
>-----Original Message-----
>From: devel@edk2.groups.io [mailto:devel@edk2.groups.io] On Behalf Of
>Zhang, Shenglei
>Sent: Friday, June 21, 2019 9:27 AM
>To: devel@edk2.groups.io
>Cc: Feng, Bob C <bob.c.feng@intel.com>; Gao, Liming <liming.gao@intel.com>
>Subject: [edk2-devel] [edk2-platform patch 5/6] Silicon\Tools: Add a tool
>FitGen
>
>The utility of this tool is part of build process for IA32/X64 FD.
>It generates FIT table.
>https://bugzilla.tianocore.org/show_bug.cgi?id=1849
>
>Cc: Bob Feng <bob.c.feng@intel.com>
>Cc: Liming Gao <liming.gao@intel.com>
>Signed-off-by: Shenglei Zhang <shenglei.zhang@intel.com>
>---
> Silicon/Intel/Tools/FitGen/FitGen.c    | 3137 ++++++++++++++++++++++++
> Silicon/Intel/Tools/FitGen/FitGen.h    |   48 +
> Silicon/Intel/Tools/FitGen/GNUmakefile |   16 +
> Silicon/Intel/Tools/FitGen/Makefile    |   17 +
> 4 files changed, 3218 insertions(+)
> create mode 100644 Silicon/Intel/Tools/FitGen/FitGen.c
> create mode 100644 Silicon/Intel/Tools/FitGen/FitGen.h
> create mode 100644 Silicon/Intel/Tools/FitGen/GNUmakefile
> create mode 100644 Silicon/Intel/Tools/FitGen/Makefile
>
>diff --git a/Silicon/Intel/Tools/FitGen/FitGen.c
>b/Silicon/Intel/Tools/FitGen/FitGen.c
>new file mode 100644
>index 0000000000..faf9880060
>--- /dev/null
>+++ b/Silicon/Intel/Tools/FitGen/FitGen.c
>@@ -0,0 +1,3137 @@
>+/**@file
>+This utility is part of build process for IA32/X64 FD.
>+It generates FIT table.
>+
>+Copyright (c) 2010-2019, Intel Corporation. All rights reserved.<BR>
>+SPDX-License-Identifier: BSD-2-Clause-Patent
>+
>+**/
>+
>+#include "FitGen.h"
>+
>+//
>+// FIT spec
>+//
>+#pragma pack (1)
>+typedef struct {
>+  UINT64     Address;
>+  UINT8      Size[3];
>+  UINT8      Rsvd;
>+  UINT16     Version;
>+  UINT8      Type:7;
>+  UINT8      C_V:1;
>+  UINT8      Checksum;
>+} FIRMWARE_INTERFACE_TABLE_ENTRY;
>+
>+//
>+// Struct for policy
>+//
>+typedef struct {
>+  UINT16     IndexPort;
>+  UINT16     DataPort;
>+  UINT8      Width;
>+  UINT8      Bit;
>+  UINT16     Index;
>+  UINT8      Size[3];
>+  UINT8      Rsvd;
>+  UINT16     Version; // == 0
>+  UINT8      Type:7;
>+  UINT8      C_V:1;
>+  UINT8      Checksum;
>+} FIRMWARE_INTERFACE_TABLE_ENTRY_PORT;
>+
>+#define FIT_ALIGNMENT          0x3F // 0xF is required previously, but if we
>need exclude FIT, we must set 64 bytes alignment.
>+#define BIOS_MODULE_ALIGNMENT  0x3F  // 64 bytes for AnC
>+#define MICROCODE_ALIGNMENT    0x7FF
>+
>+#define ACM_PKCS_1_5_RSA_SIGNATURE_SHA256_SIZE          256
>+#define ACM_PKCS_1_5_RSA_SIGNATURE_SHA384_SIZE          384
>+
>+#define ACM_HEADER_VERSION_3  (3 << 16)
>+#define ACM_MODULE_TYPE_CHIPSET_ACM                     2
>+#define ACM_MODULE_SUBTYPE_CAPABLE_OF_EXECUTE_AT_RESET  0x1
>+#define ACM_MODULE_SUBTYPE_ANC_MODULE                   0x2
>+#define ACM_MODULE_FLAG_PREPRODUCTION                   0x4000
>+#define ACM_MODULE_FLAG_DEBUG_SIGN                      0x8000
>+
>+
>+typedef struct {
>+  UINT16     ModuleType;
>+  UINT16     ModuleSubType;
>+  UINT32     HeaderLen;
>+  UINT32     HeaderVersion;
>+  UINT16     ChipsetID;
>+  UINT16     Flags;
>+  UINT32     ModuleVendor;
>+  UINT32     Date;
>+  UINT32     Size;
>+  UINT16     TxtSvn;
>+  UINT16     SeSvn;
>+  UINT32     CodeControl;
>+  UINT32     ErrorEntryPoint;
>+  UINT32     GDTLimit;
>+  UINT32     GDTBasePtr;
>+  UINT32     SegSel;
>+  UINT32     EntryPoint;
>+  UINT8      Rsvd2[64];
>+  UINT32     KeySize; // 64
>+  UINT32     ScratchSize; // 2 * KeySize + 15
>+//UINT8      RSAPubKey[64 * 4]; // KeySize * 4
>+//UINT32     RSAPubExp;
>+//UINT8      RSASig[256];
>+  // End of AC module header
>+//UINT8      Scratch[(64 * 2 + 15) * 4]; // ScratchSize * 4
>+  // User Area
>+//UINT8      UserArea[1];
>+} ACM_FORMAT;
>+
>+#define CHIPSET_ACM_INFORMATION_TABLE_VERSION_3  0x03
>+#define CHIPSET_ACM_INFORMATION_TABLE_VERSION_4  0x04
>+
>+#define CHIPSET_ACM_INFORMATION_TABLE_VERSION
>CHIPSET_ACM_INFORMATION_TABLE_VERSION_3
>+
>+#define CHIPSET_ACM_INFORMATION_TABLE_GUID_V03 \
>+  { 0x7FC03AAA, 0x18DB46A7, 0x8F69AC2E, 0x5A7F418D }
>+
>+#define CHIPSET_ACM_TYPE_BIOS   0
>+#define CHIPSET_ACM_TYPE_SINIT  1
>+
>+typedef struct {
>+  UINT32    Guid0;
>+  UINT32    Guid1;
>+  UINT32    Guid2;
>+  UINT32    Guid3;
>+} ACM_GUID;
>+
>+typedef struct {
>+  ACM_GUID   Guid;
>+  UINT8      ChipsetACMType;
>+  UINT8      Version;
>+  UINT16     Length;
>+  UINT32     ChipsetIDList;
>+  UINT32     OsSinitTableVer;
>+  UINT32     MinMleHeaderVer;
>+//#if (CHIPSET_ACM_INFORMATION_TABLE_VERSION >=
>CHIPSET_ACM_INFORMATION_TABLE_VERSION_3)
>+  UINT32     Capabilities;
>+  UINT8      AcmVersion;
>+  UINT8      AcmRevision[3];
>+//#if (CHIPSET_ACM_INFORMATION_TABLE_VERSION >=
>CHIPSET_ACM_INFORMATION_TABLE_VERSION_4)
>+  UINT32     ProcessorIDList;
>+//#endif
>+//#endif
>+} CHIPSET_ACM_INFORMATION_TABLE;
>+
>+#define ACM_CHIPSET_ID_REVISION_ID_MAKE  0x1
>+
>+typedef struct {
>+  UINT32     Flags;
>+  UINT16     VendorID;
>+  UINT16     DeviceID;
>+  UINT16     RevisionID;
>+  UINT8      Reserved[6];
>+} ACM_CHIPSET_ID;
>+
>+typedef struct {
>+  UINT32           Count;
>+  ACM_CHIPSET_ID   ChipsetID[1];
>+} CHIPSET_ID_LIST;
>+
>+typedef struct {
>+  UINT32     FMS;
>+  UINT32     FMSMask;
>+  UINT64     PlatformID;
>+  UINT64     PlatformMask;
>+} ACM_PROCESSOR_ID;
>+
>+typedef struct {
>+  UINT32           Count;
>+  ACM_PROCESSOR_ID ProcessorID[1];
>+} PROCESSOR_ID_LIST;
>+
>+#pragma pack ()
>+
>+
>+ACM_GUID mChipsetAcmInformationTableGuid03 =
>CHIPSET_ACM_INFORMATION_TABLE_GUID_V03;
>+
>+
>+//
>+// BIOS INFO data structure
>+// This is self contained data structure for BIOS info
>+//
>+#pragma pack (1)
>+#define BIOS_INFO_SIGNATURE  SIGNATURE_64 ('$', 'B', 'I', 'O', 'S', 'I', 'F', '$')
>+typedef struct {
>+  UINT64            Signature;
>+  UINT32            EntryCount;
>+  UINT32            Reserved;
>+//BIOS_INFO_STRUCT  Struct[EntryCount];
>+} BIOS_INFO_HEADER;
>+
>+//
>+// BIOS_INFO_STRUCT attributes
>+// bits[0:3] means general attributes
>+// bits[4:7] means type specific attributes
>+//
>+#define BIOS_INFO_STRUCT_ATTRIBUTE_GENERAL_EXCLUDE_FROM_FIT
>0x01
>+#define BIOS_INFO_STRUCT_ATTRIBUTE_MICROCODE_WHOLE_REGION
>0x10
>+#define BIOS_INFO_STRUCT_ATTRIBUTE_BIOS_POST_IBB             0x10
>+
>+typedef struct {
>+  //
>+  // FitTable entry type
>+  //
>+  UINT8    Type;
>+  //
>+  // BIOS_INFO_STRUCT attributes
>+  //
>+  UINT8    Attributes;
>+  //
>+  // FitTable entry version
>+  //
>+  UINT16   Version;
>+  //
>+  // FitTable entry real size
>+  //
>+  UINT32   Size;
>+  //
>+  // FitTable entry address
>+  //
>+  UINT64   Address;
>+} BIOS_INFO_STRUCT;
>+
>+#pragma pack ()
>+
>+#define MAX_BIOS_MODULE_ENTRY  0x20
>+#define MAX_MICROCODE_ENTRY    0x20
>+#define MAX_OPTIONAL_ENTRY     0x20
>+#define MAX_PORT_ENTRY         0x20
>+
>+#define DEFAULT_FIT_TABLE_POINTER_OFFSET  0x40
>+#define DEFAULT_FIT_ENTRY_VERSION         0x0100
>+
>+#define MEMORY_TO_FLASH(FileBuffer, FvBuffer, FvSize)  \
>+                 (UINTN)(0x100000000 - ((UINTN)(FvBuffer) + (UINTN)(FvSize) -
>(UINTN)(FileBuffer)))
>+#define FLASH_TO_MEMORY(Address, FvBuffer, FvSize)  \
>+                 (VOID *)(UINTN)((UINTN)(FvBuffer) + (UINTN)(FvSize) -
>(0x100000000 - (UINTN)(Address)))
>+
>+#define FIT_TABLE_TYPE_HEADER                 0
>+#define FIT_TABLE_TYPE_MICROCODE              1
>+#define FIT_TABLE_TYPE_STARTUP_ACM            2
>+#define FIT_TABLE_TYPE_BIOS_MODULE            7
>+#define FIT_TABLE_TYPE_TPM_POLICY             8
>+#define FIT_TABLE_TYPE_BIOS_POLICY            9
>+#define FIT_TABLE_TYPE_TXT_POLICY             10
>+#define FIT_TABLE_TYPE_KEY_MANIFEST           11
>+#define FIT_TABLE_TYPE_BOOT_POLICY_MANIFEST   12
>+#define FIT_TABLE_TYPE_BIOS_DATA_AREA         13
>+#define FIT_TABLE_TYPE_CSE_SECURE_BOOT        16
>+
>+typedef struct {
>+  UINT32  Type;
>+  UINT32  Address;
>+  UINT32  Size;
>+  UINT32  Version; // Used by OptionalModule and PortModule only
>+} FIT_TABLE_CONTEXT_ENTRY;
>+
>+typedef struct {
>+  BOOLEAN                    Clear;
>+  UINT32                     FitTablePointerOffset;
>+  UINT32                     FitTablePointerOffset2;
>+  UINT32                     FitEntryNumber;
>+  UINT32                     BiosModuleNumber;
>+  UINT32                     MicrocodeNumber;
>+  UINT32                     OptionalModuleNumber;
>+  UINT32                     PortModuleNumber;
>+  UINT32                     GlobalVersion;
>+  UINT32                     FitHeaderVersion;
>+  FIT_TABLE_CONTEXT_ENTRY    StartupAcm;
>+  UINT32                     StartupAcmVersion;
>+  FIT_TABLE_CONTEXT_ENTRY    BiosModule[MAX_BIOS_MODULE_ENTRY];
>+  UINT32                     BiosModuleVersion;
>+  FIT_TABLE_CONTEXT_ENTRY    Microcode[MAX_MICROCODE_ENTRY];
>+  BOOLEAN                    MicrocodeAlignment;
>+  UINT32                     MicrocodeVersion;
>+  FIT_TABLE_CONTEXT_ENTRY    OptionalModule[MAX_OPTIONAL_ENTRY];
>+  FIT_TABLE_CONTEXT_ENTRY    PortModule[MAX_PORT_ENTRY];
>+} FIT_TABLE_CONTEXT;
>+
>+FIT_TABLE_CONTEXT   gFitTableContext = {0};
>+
>+unsigned int
>+xtoi (
>+  char  *str
>+  );
>+
>+VOID
>+PrintUtilityInfo (
>+  VOID
>+  )
>+/*++
>+
>+Routine Description:
>+
>+  Displays the standard utility information to STDOUT
>+
>+Arguments:
>+
>+  None
>+
>+Returns:
>+
>+  None
>+
>+--*/
>+{
>+  printf (
>+    "%s - Tiano IA32/X64 FIT table generation Utility."" Version %i.%i\n\n",
>+    UTILITY_NAME,
>+    UTILITY_MAJOR_VERSION,
>+    UTILITY_MINOR_VERSION
>+    );
>+}
>+
>+VOID
>+PrintUsage (
>+  VOID
>+  )
>+/*++
>+
>+Routine Description:
>+
>+  Displays the utility usage syntax to STDOUT
>+
>+Arguments:
>+
>+  None
>+
>+Returns:
>+
>+  None
>+
>+--*/
>+{
>+  printf ("Usage (generate): %s [-D] InputFvRecoveryFile
>OutputFvRecoveryFile\n"
>+          "\t[-V <FitEntryDefaultVersion>]\n"
>+          "\t[-F <FitTablePointerOffset>] [-F <FitTablePointerOffset>] [-V
><FitHeaderVersion>]\n"
>+          "\t[-NA]\n"
>+          "\t[-CLEAR]\n"
>+          "\t[-I <BiosInfoGuid>]\n"
>+          "\t[-S <StartupAcmAddress StartupAcmSize>|<StartupAcmGuid>] [-V
><StartupAcmVersion>]\n"
>+          "\t[-B <BiosModuleAddress BiosModuleSize>] [-B ...] [-V
><BiosModuleVersion>]\n"
>+          "\t[-M <MicrocodeAddress MicrocodeSize>] [-M ...]|[-U <MicrocodeFv
>MicrocodeBase>|<MicrocodeRegionOffset
>MicrocodeRegionSize>|<MicrocodeGuid>] [-V <MicrocodeVersion>]\n"
>+          "\t[-O RecordType <RecordDataAddress RecordDataSize>|<RESERVE
>RecordDataSize>|<RecordDataGuid>|<RecordBinFile> [-V <RecordVersion>]]
>[-O ... [-V ...]]\n"
>+          "\t[-P RecordType <IndexPort DataPort Width Bit Index> [-V
><RecordVersion>]] [-P ... [-V ...]]\n"
>+          , UTILITY_NAME);
>+  printf ("  Where:\n");
>+  printf ("\t-D                     - It is FD file instead of FV file. (The tool will search FV
>file)\n");
>+  printf ("\tInputFvRecoveryFile    - Name of the input FvRecovery.fv file.\n");
>+  printf ("\tOutputFvRecoveryFile   - Name of the output FvRecovery.fv
>file.\n");
>+  printf ("\tFitTablePointerOffset  - FIT table pointer offset. 0x%x as default.
>0x18 for current soon to be obsoleted CPUs. User can set both.\n",
>DEFAULT_FIT_TABLE_POINTER_OFFSET);
>+  printf ("\tBiosInfoGuid           - Guid of BiosInfo Module. If this module exists,
>StartupAcm/Bios/Microcode can be optional.\n");
>+  printf ("\tStartupAcmAddress      - Address of StartupAcm.\n");
>+  printf ("\tStartupAcmSize         - Size of StartupAcm.\n");
>+  printf ("\tStartupAcmGuid         - Guid of StartupAcm Module, if StartupAcm
>is in a BiosModule, it will be excluded form that.\n");
>+  printf ("\tBiosModuleAddress      - Address of BiosModule. User should
>ensure there is no overlap.\n");
>+  printf ("\tBiosModuleSize         - Size of BiosModule.\n");
>+  printf ("\tMicrocodeAddress       - Address of Microcode.\n");
>+  printf ("\tMicrocodeSize          - Size of Microcode.\n");
>+  printf ("\tMicrocodeFv            - Name of Microcode.fv file.\n");
>+  printf ("\tMicrocodeBase          - The base address of Microcode.fv in final FD
>image.\n");
>+  printf ("\tMicrocodeRegionOffset  - Offset of Microcode region in input FD
>image.\n");
>+  printf ("\tMicrocodeRegionSize    - Size of Microcode region in input FD
>image.\n");
>+  printf ("\tMicrocodeGuid          - Guid of Microcode Module.\n");
>+  printf ("\t-NA                    - No 0x800 aligned Microcode requirement. No -NA
>means Microcode is 0x800 aligned.\n");
>+  printf ("\tRecordType             - FIT entry record type. User should ensure it is
>ordered.\n");
>+  printf ("\tRecordDataAddress      - FIT entry record data address.\n");
>+  printf ("\tRecordDataSize         - FIT entry record data size.\n");
>+  printf ("\tRecordDataGuid         - FIT entry record data GUID.\n");
>+  printf ("\tRecordBinFile          - FIT entry record data binary file.\n");
>+  printf ("\tFitEntryDefaultVersion - The default version for all FIT table
>entries. 0x%04x is used if this is not specified.\n",
>DEFAULT_FIT_ENTRY_VERSION);
>+  printf ("\tFitHeaderVersion       - The version for FIT header. (Override
>default version)\n");
>+  printf ("\tStartupAcmVersion      - The version for StartupAcm. (Override
>default version)\n");
>+  printf ("\tBiosModuleVersion      - The version for BiosModule. (Override
>default version)\n");
>+  printf ("\tMicrocodeVersion       - The version for Microcode. (Override
>default version)\n");
>+  printf ("\tRecordVersion          - The version for Record. (Override default
>version)\n");
>+  printf ("\tIndexPort              - The Index Port Number.\n");
>+  printf ("\tDataPort               - The Data Port Number.\n");
>+  printf ("\tWidth                  - The Width of the port.\n");
>+  printf ("\tBit                    - The Bit Number of the port.\n");
>+  printf ("\tIndex                  - The Index Number of the port.\n");
>+  printf ("\nUsage (view): %s [-view] InputFile -F <FitTablePointerOffset>\n",
>UTILITY_NAME);
>+  printf ("  Where:\n");
>+  printf ("\tInputFile              - Name of the input file.\n");
>+  printf ("\tFitTablePointerOffset  - FIT table pointer offset from end of file.
>0x%x as default.\n", DEFAULT_FIT_TABLE_POINTER_OFFSET);
>+  printf ("\nTool return values:\n");
>+  printf ("\tSTATUS_SUCCESS=%d, STATUS_WARNING=%d,
>STATUS_ERROR=%d\n", STATUS_SUCCESS, STATUS_WARNING,
>STATUS_ERROR);
>+}
>+
>+VOID *
>+SetMem (
>+  OUT     VOID                      *Buffer,
>+  IN      UINTN                     Length,
>+  IN      UINT8                     Value
>+  )
>+{
>+  //
>+  // Declare the local variables that actually move the data elements as
>+  // volatile to prevent the optimizer from replacing this function with
>+  // the intrinsic memset()
>+  //
>+  volatile UINT8                    *Pointer;
>+
>+  Pointer = (UINT8*)Buffer;
>+  while (Length-- > 0) {
>+    *(Pointer++) = Value;
>+  }
>+  return Buffer;
>+}
>+
>+STATUS
>+ReadInputFile (
>+  IN CHAR8    *FileName,
>+  OUT UINT8   **FileData,
>+  OUT UINT32  *FileSize,
>+  OUT UINT8   **FileBufferRaw OPTIONAL
>+  )
>+/*++
>+
>+Routine Description:
>+
>+  Read input file
>+
>+Arguments:
>+
>+  FileName      - The input file name
>+  FileData      - The input file data, the memory is aligned.
>+  FileSize      - The input file size
>+  FileBufferRaw - The memory to hold input file data. The caller must free the
>memory.
>+
>+Returns:
>+
>+  STATUS_SUCCESS - The file found and data read
>+  STATUS_ERROR   - The file data is not read
>+  STATUS_WARNING - The file is not found
>+
>+--*/
>+{
>+  FILE                        *FpIn;
>+  UINT32                      TempResult;
>+
>+  //
>+  // Open the Input FvRecovery.fv file
>+  //
>+  if ((FpIn = fopen (FileName, "rb")) == NULL) {
>+    //
>+    // Return WARNING, let caller make decision
>+    //
>+//    Error (NULL, 0, 0, "Unable to open file", FileName);
>+    return STATUS_WARNING;
>+  }
>+  //
>+  // Get the Input FvRecovery.fv file size
>+  //
>+  fseek (FpIn, 0, SEEK_END);
>+  *FileSize = ftell (FpIn);
>+  //
>+  // Read the contents of input file to memory buffer
>+  //
>+  if (FileBufferRaw != NULL) {
>+    *FileBufferRaw = (UINT8 *) malloc (*FileSize + 0x10000);
>+    if (NULL == *FileBufferRaw) {
>+      Error (NULL, 0, 0, "No sufficient memory to allocate!", NULL);
>+      fclose (FpIn);
>+      return STATUS_ERROR;
>+    }
>+    TempResult = 0x10000 - (UINT32) ((UINTN)*FileBufferRaw & 0x0FFFF);
>+    *FileData = (UINT8 *)((UINTN)*FileBufferRaw + TempResult);
>+  } else {
>+    *FileData = (UINT8 *) malloc (*FileSize);
>+     if (NULL == *FileData) {
>+      Error (NULL, 0, 0, "No sufficient memory to allocate!", NULL);
>+      fclose (FpIn);
>+      return STATUS_ERROR;
>+    }
>+  }
>+  fseek (FpIn, 0, SEEK_SET);
>+  TempResult = fread (*FileData, 1, *FileSize, FpIn);
>+  if (TempResult != *FileSize) {
>+    Error (NULL, 0, 0, "Read input file error!", NULL);
>+    if (FileBufferRaw != NULL) {
>+      free ((VOID *)*FileBufferRaw);
>+    } else {
>+      free ((VOID *)*FileData);
>+    }
>+    fclose (FpIn);
>+    return STATUS_ERROR;
>+  }
>+
>+  //
>+  // Close the input FvRecovery.fv file
>+  //
>+  fclose (FpIn);
>+
>+  return STATUS_SUCCESS;
>+}
>+
>+UINT8 *
>+FindNextFvHeader (
>+  IN UINT8 *FileBuffer,
>+  IN UINTN  FileLength
>+  )
>+/*++
>+
>+  Routine Description:
>+    Find next FvHeader in the FileBuffer
>+
>+  Parameters:
>+    FileBuffer        -   The start FileBuffer which needs to be searched
>+    FileLength        -   The whole File Length.
>+  Return:
>+    FvHeader          -   The FvHeader is found successfully.
>+    NULL              -   The FvHeader is not found.
>+
>+--*/
>+{
>+  UINT8                       *FileHeader;
>+  EFI_FIRMWARE_VOLUME_HEADER  *FvHeader;
>+  UINT16                      FileChecksum;
>+
>+  FileHeader = FileBuffer;
>+  for (; (UINTN)FileBuffer < (UINTN)FileHeader + FileLength; FileBuffer += 8) {
>+    FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *)FileBuffer;
>+    if (FvHeader->Signature == EFI_FVH_SIGNATURE) {
>+      //
>+      // potential candidate
>+      //
>+
>+      //
>+      // Check checksum
>+      //
>+      if (FvHeader->FvLength > FileLength) {
>+        continue;
>+      }
>+      if (FvHeader->HeaderLength >= FileLength) {
>+        continue;
>+      }
>+      FileChecksum = CalculateChecksum16 ((UINT16 *)FileBuffer, FvHeader-
>>HeaderLength / sizeof (UINT16));
>+      if (FileChecksum != 0) {
>+        continue;
>+      }
>+
>+      //
>+      // Check revision and reserved field
>+      //
>+#if (PI_SPECIFICATION_VERSION < 0x00010000)
>+      if ((FvHeader->Revision == EFI_FVH_REVISION) &&
>+          (FvHeader->Reserved[0] == 0) &&
>+          (FvHeader->Reserved[1] == 0) &&
>+          (FvHeader->Reserved[2] == 0) ){
>+        return FileBuffer;
>+      }
>+#else
>+      if ((FvHeader->Revision == EFI_FVH_PI_REVISION) &&
>+          (FvHeader->Reserved[0] == 0) ){
>+        return FileBuffer;
>+      }
>+#endif
>+    }
>+  }
>+
>+  return NULL;
>+}
>+
>+UINT8  *
>+FindFileFromFvByGuid (
>+  IN UINT8     *FvBuffer,
>+  IN UINT32    FvSize,
>+  IN EFI_GUID  *Guid,
>+  OUT UINT32   *FileSize
>+  )
>+/*++
>+
>+Routine Description:
>+
>+  Find File with GUID in an FV
>+
>+Arguments:
>+
>+  FvBuffer       - FV binary buffer
>+  FvSize         - FV size
>+  Guid           - File GUID value to be searched
>+  FileSize       - Guid File size
>+
>+Returns:
>+
>+  FileLocation   - Guid File location.
>+  NULL           - Guid File is not found.
>+
>+--*/
>+{
>+  EFI_FIRMWARE_VOLUME_HEADER  *FvHeader;
>+  EFI_FFS_FILE_HEADER         *FileHeader;
>+  UINT64                      FvLength;
>+  EFI_GUID                    *TempGuid;
>+  UINT8                       *FixPoint;
>+  UINT32                      Offset;
>+  UINT32                      FileLength;
>+  UINT32                      FileOccupiedSize;
>+
>+  //
>+  // Find the FFS file
>+  //
>+  FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *)FindNextFvHeader
>(FvBuffer, FvSize);
>+  if (NULL == FvHeader) {
>+    return NULL;
>+  }
>+  while (TRUE) {
>+    FvLength         = FvHeader->FvLength;
>+
>+    //
>+    // Prepare to walk the FV image
>+    //
>+    InitializeFvLib (FvHeader, (UINT32)FvLength);
>+
>+    FileHeader       = (EFI_FFS_FILE_HEADER *)((UINTN)FvHeader + FvHeader-
>>HeaderLength);
>+    Offset           = (UINT32) (UINTN) FileHeader - (UINT32) (UINTN) FvHeader;
>+
>+    while (Offset < FvLength) {
>+      TempGuid = (EFI_GUID *)&(FileHeader->Name);
>+      FileLength = (*(UINT32 *)(FileHeader->Size)) & 0x00FFFFFF;
>+      FileOccupiedSize = GETOCCUPIEDSIZE(FileLength, 8);
>+      if ((CompareGuid (TempGuid, Guid)) == 0) {
>+        //
>+        // Good! Find it.
>+        //
>+        FixPoint = ((UINT8 *)FileHeader + sizeof(EFI_FFS_FILE_HEADER));
>+        //
>+        // Find the position of file module, the offset
>+        // between the position and the end of FvRecovery.fv file
>+        // should not exceed 128kB to prevent reset vector from
>+        // outside legacy E and F segment
>+        //
>+        if ((UINTN)FvHeader + FvLength - (UINTN)FixPoint > 0x20000) {
>+  //        printf ("WARNING: The position of file module is not in E and F
>segment!\n");
>+  //        return NULL;
>+        }
>+        *FileSize = FileLength - sizeof(EFI_FFS_FILE_HEADER);
>+  #if (PI_SPECIFICATION_VERSION < 0x00010000)
>+        if (FileHeader->Attributes & FFS_ATTRIB_TAIL_PRESENT) {
>+          *FileSize -= sizeof(EFI_FFS_FILE_TAIL);
>+        }
>+  #endif
>+        return FixPoint;
>+      }
>+      FileHeader = (EFI_FFS_FILE_HEADER *)((UINTN)FileHeader +
>FileOccupiedSize);
>+      Offset = (UINT32) (UINTN) FileHeader - (UINT32) (UINTN) FvHeader;
>+    }
>+
>+    //
>+    // Not found, check next FV
>+    //
>+    if ((UINTN)FvBuffer + FvSize > (UINTN)FvHeader + FvLength) {
>+      FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *)FindNextFvHeader
>((UINT8 *)FvHeader + (UINTN)FvLength, (UINTN)FvBuffer + FvSize -
>((UINTN)FvHeader + (UINTN)FvLength));
>+      if (FvHeader == NULL) {
>+        break;
>+      }
>+    } else {
>+      break;
>+    }
>+  }
>+
>+  //
>+  // Not found
>+  //
>+  return NULL;
>+}
>+
>+BOOLEAN
>+IsGuidData (
>+  IN CHAR8     *StringData,
>+  OUT EFI_GUID *Guid
>+  )
>+/*++
>+
>+Routine Description:
>+
>+  Check whether a string is a GUID
>+
>+Arguments:
>+
>+  StringData  - the String
>+  Guid        - Guid to hold the value
>+
>+Returns:
>+
>+  TRUE  - StringData is a GUID, and Guid field is filled.
>+  FALSE - StringData is not a GUID
>+
>+--*/
>+{
>+  if (strlen (StringData) != strlen ("00000000-0000-0000-0000-000000000000"))
>{
>+    return FALSE;
>+  }
>+  if ((StringData[8] != '-') ||
>+      (StringData[13] != '-') ||
>+      (StringData[18] != '-') ||
>+      (StringData[23] != '-') ) {
>+    return FALSE;
>+  }
>+
>+  StringToGuid (StringData, Guid);
>+
>+  return TRUE;
>+}
>+
>+VOID
>+CheckOverlap (
>+  IN UINT32 Address,
>+  IN UINT32 Size
>+  )
>+{
>+  INTN  Index;
>+
>+  for (Index = 0; Index < (INTN)gFitTableContext.BiosModuleNumber; Index
>++) {
>+    if ((gFitTableContext.BiosModule[Index].Address <= Address) &&
>+        ((gFitTableContext.BiosModule[Index].Size - Size) >= (Address -
>gFitTableContext.BiosModule[Index].Address))) {
>+      UINT32  TempSize;
>+      INT32   SubIndex;
>+
>+      //
>+      // Found overlap, split BiosModuleEntry
>+      // Currently only support StartupAcm in 1 BiosModule. It does not
>support StartupAcm across 2 BiosModule or more.
>+      //
>+      if (gFitTableContext.BiosModuleNumber >= MAX_BIOS_MODULE_ENTRY)
>{
>+        Error (NULL, 0, 0, "Too many Bios Module!", NULL);
>+        return ;
>+      }
>+
>+      if (Address != gFitTableContext.BiosModule[Index].Address) {
>+        //
>+        // Skip the entry whose start address is same as StartupAcm
>+        //
>+
>gFitTableContext.BiosModule[gFitTableContext.BiosModuleNumber].Type
>= FIT_TABLE_TYPE_BIOS_MODULE;
>+
>gFitTableContext.BiosModule[gFitTableContext.BiosModuleNumber].Addres
>s = gFitTableContext.BiosModule[Index].Address;
>+
>gFitTableContext.BiosModule[gFitTableContext.BiosModuleNumber].Size    =
>Address - gFitTableContext.BiosModule[Index].Address;
>+        gFitTableContext.BiosModuleNumber ++;
>+        gFitTableContext.FitEntryNumber++;
>+      }
>+
>+      TempSize = gFitTableContext.BiosModule[Index].Address +
>gFitTableContext.BiosModule[Index].Size;
>+      gFitTableContext.BiosModule[Index].Address = Address + Size;
>+      gFitTableContext.BiosModule[Index].Size    = TempSize -
>gFitTableContext.BiosModule[Index].Address;
>+
>+      if (gFitTableContext.BiosModule[Index].Size == 0) {
>+        //
>+        // remove the entry if size is 0
>+        //
>+        for (SubIndex = Index; SubIndex <
>(INTN)gFitTableContext.BiosModuleNumber - 1; SubIndex ++) {
>+          gFitTableContext.BiosModule[SubIndex].Address =
>gFitTableContext.BiosModule[SubIndex + 1].Address;
>+          gFitTableContext.BiosModule[SubIndex].Size    =
>gFitTableContext.BiosModule[SubIndex + 1].Size;
>+        }
>+        gFitTableContext.BiosModuleNumber --;
>+        gFitTableContext.FitEntryNumber--;
>+      }
>+      break;
>+    }
>+  }
>+}
>+
>+UINT32
>+GetFitEntryNumber (
>+  IN INTN   argc,
>+  IN CHAR8  **argv,
>+  IN UINT8  *FdBuffer,
>+  IN UINT32 FdSize
>+  )
>+/*++
>+
>+Routine Description:
>+
>+  Get FIT entry number and fill global FIT table context, from argument
>+
>+Arguments:
>+
>+  argc           - Number of command line parameters.
>+  argv           - Array of pointers to parameter strings.
>+  FdBuffer       - FD binary buffer
>+  FdSize         - FD size
>+
>+Returns:
>+
>+  FitEntryNumber - The FIT entry number
>+  0              - Argument parse fail
>+
>+*/
>+{
>+  EFI_GUID  Guid;
>+  INTN      Index;
>+  UINT8     *FileBuffer;
>+  UINT32    FileSize;
>+  UINT32    Type;
>+  UINT8     *MicrocodeFileBuffer;
>+  UINT8     *MicrocodeFileBufferRaw;
>+  UINT32    MicrocodeFileSize;
>+  UINT32    MicrocodeBase;
>+  UINT32    MicrocodeSize;
>+  UINT8     *MicrocodeBuffer;
>+  UINT32    MicrocodeRegionOffset;
>+  UINT32    MicrocodeRegionSize;
>+  STATUS    Status;
>+  EFI_FIRMWARE_VOLUME_HEADER  *FvHeader;
>+  UINTN                       FitEntryNumber;
>+  BOOLEAN                     BiosInfoExist;
>+  BIOS_INFO_HEADER            *BiosInfo;
>+  BIOS_INFO_STRUCT            *BiosInfoStruct;
>+  UINTN                       BiosInfoIndex;
>+
>+  //
>+  // Init index
>+  //
>+  Index = 3;
>+  if (((strcmp (argv[1], "-D") == 0) ||
>+       (strcmp (argv[1], "-d") == 0)) ) {
>+    Index ++;
>+  }
>+
>+  //
>+  // Fill Global Version
>+  //
>+  if ((Index + 1 >= argc) ||
>+      ((strcmp (argv[Index], "-V") != 0) &&
>+       (strcmp (argv[Index], "-v") != 0)) ) {
>+    gFitTableContext.GlobalVersion = DEFAULT_FIT_ENTRY_VERSION;
>+  } else {
>+    gFitTableContext.GlobalVersion = xtoi (argv[Index + 1]);
>+    Index += 2;
>+  }
>+
>+  //
>+  // 0. FIT Header
>+  //
>+  gFitTableContext.FitEntryNumber = 1;
>+  if ((Index + 1 >= argc) ||
>+      ((strcmp (argv[Index], "-F") != 0) &&
>+       (strcmp (argv[Index], "-f") != 0)) ) {
>+    //
>+    // Use default address
>+    //
>+    gFitTableContext.FitTablePointerOffset =
>DEFAULT_FIT_TABLE_POINTER_OFFSET;
>+  } else {
>+    //
>+    // Get offset from parameter
>+    //
>+    gFitTableContext.FitTablePointerOffset = xtoi (argv[Index + 1]);
>+    Index += 2;
>+  }
>+
>+  //
>+  // 0.1 FIT Header 2
>+  //
>+  if ((Index + 1 >= argc) ||
>+      ((strcmp (argv[Index], "-F") != 0) &&
>+       (strcmp (argv[Index], "-f") != 0)) ) {
>+    //
>+    // Bypass
>+    //
>+    gFitTableContext.FitTablePointerOffset2 = 0;
>+  } else {
>+    //
>+    // Get offset from parameter
>+    //
>+    gFitTableContext.FitTablePointerOffset2 = xtoi (argv[Index + 1]);
>+    Index += 2;
>+  }
>+
>+  //
>+  // 0.2 FIT Header version
>+  //
>+  if ((Index + 1 >= argc) ||
>+      ((strcmp (argv[Index], "-V") != 0) &&
>+       (strcmp (argv[Index], "-v") != 0)) ) {
>+    //
>+    // Bypass
>+    //
>+    gFitTableContext.FitHeaderVersion = gFitTableContext.GlobalVersion;
>+  } else {
>+    //
>+    // Get offset from parameter
>+    //
>+    gFitTableContext.FitHeaderVersion = xtoi (argv[Index + 1]);
>+    Index += 2;
>+  }
>+
>+  //
>+  // 0.3 Microcode alignment
>+  //
>+  if ((Index >= argc) ||
>+      ((strcmp (argv[Index], "-NA") != 0) &&
>+       (strcmp (argv[Index], "-na") != 0)) ) {
>+    //
>+    // by pass
>+    //
>+    gFitTableContext.MicrocodeAlignment = TRUE;
>+  } else {
>+    //
>+    // no alignment
>+    //
>+    gFitTableContext.MicrocodeAlignment = FALSE;
>+    Index += 1;
>+  }
>+
>+  //
>+  // 0.4 Clear FIT table related memory
>+  //
>+  if ((Index >= argc) ||
>+      ((strcmp (argv[Index], "-CLEAR") != 0) &&
>+       (strcmp (argv[Index], "-clear") != 0)) ) {
>+    //
>+    // by pass
>+    //
>+    gFitTableContext.Clear = FALSE;
>+  } else {
>+    //
>+    // Clear FIT table
>+    //
>+    gFitTableContext.Clear = TRUE;
>+    //
>+    // Do not parse any more
>+    //
>+    return 0;
>+  }
>+
>+  //
>+  // 0.5 BiosInfo
>+  //
>+  if ((Index + 1 >= argc) ||
>+      ((strcmp (argv[Index], "-I") != 0) &&
>+       (strcmp (argv[Index], "-i") != 0)) ) {
>+    //
>+    // Bypass
>+    //
>+    BiosInfoExist = FALSE;
>+  } else {
>+    //
>+    // Get offset from parameter
>+    //
>+    BiosInfoExist = TRUE;
>+    if (IsGuidData (argv[Index + 1], &Guid)) {
>+      FileBuffer = FindFileFromFvByGuid (FdBuffer, FdSize, &Guid, &FileSize);
>+      if (FileBuffer == NULL) {
>+        Error (NULL, 0, 0, "-I Parameter incorrect, GUID not found!", "%s",
>argv[Index + 1]);
>+        // not found
>+        return 0;
>+      }
>+      BiosInfo = (BIOS_INFO_HEADER *)FileBuffer;
>+      for (BiosInfoIndex = 0; BiosInfoIndex < FileSize; BiosInfoIndex++) {
>+        if (((BIOS_INFO_HEADER *)(FileBuffer + BiosInfoIndex))->Signature ==
>BIOS_INFO_SIGNATURE) {
>+          BiosInfo = (BIOS_INFO_HEADER *)(FileBuffer + BiosInfoIndex);
>+        }
>+      }
>+      if (BiosInfo->Signature != BIOS_INFO_SIGNATURE) {
>+        Error (NULL, 0, 0, "-I Parameter incorrect, Signature Error!", NULL);
>+        // not found
>+        return 0;
>+      }
>+      BiosInfoStruct = (BIOS_INFO_STRUCT *)(BiosInfo + 1);
>+
>+      for (BiosInfoIndex = 0; BiosInfoIndex < BiosInfo->EntryCount;
>BiosInfoIndex++) {
>+        if ((BiosInfoStruct[BiosInfoIndex].Attributes &
>BIOS_INFO_STRUCT_ATTRIBUTE_GENERAL_EXCLUDE_FROM_FIT) != 0) {
>+          continue;
>+        }
>+        switch (BiosInfoStruct[BiosInfoIndex].Type) {
>+        case FIT_TABLE_TYPE_HEADER:
>+          Error (NULL, 0, 0, "-I Parameter incorrect, Header Type unsupported!",
>NULL);
>+          return 0;
>+        case FIT_TABLE_TYPE_STARTUP_ACM:
>+          if (gFitTableContext.StartupAcm.Type != 0) {
>+            Error (NULL, 0, 0, "-I Parameter incorrect, Duplicated StartupAcm!",
>NULL);
>+            return 0;
>+          }
>+          gFitTableContext.StartupAcm.Type    =
>FIT_TABLE_TYPE_STARTUP_ACM;
>+          gFitTableContext.StartupAcm.Address =
>(UINT32)BiosInfoStruct[BiosInfoIndex].Address;
>+          gFitTableContext.StartupAcm.Size    =
>(UINT32)BiosInfoStruct[BiosInfoIndex].Size;
>+          gFitTableContext.StartupAcmVersion  =
>BiosInfoStruct[BiosInfoIndex].Version;
>+          gFitTableContext.FitEntryNumber ++;
>+          break;
>+        case FIT_TABLE_TYPE_BIOS_MODULE:
>+          if ((BiosInfoStruct[BiosInfoIndex].Attributes &
>BIOS_INFO_STRUCT_ATTRIBUTE_BIOS_POST_IBB) != 0) {
>+            continue;
>+          }
>+          if (gFitTableContext.BiosModuleNumber >=
>MAX_BIOS_MODULE_ENTRY) {
>+            Error (NULL, 0, 0, "-I Parameter incorrect, Too many Bios Module!",
>NULL);
>+            return 0;
>+          }
>+
>gFitTableContext.BiosModule[gFitTableContext.BiosModuleNumber].Type
>= FIT_TABLE_TYPE_BIOS_MODULE;
>+
>gFitTableContext.BiosModule[gFitTableContext.BiosModuleNumber].Addres
>s = (UINT32)BiosInfoStruct[BiosInfoIndex].Address;
>+
>gFitTableContext.BiosModule[gFitTableContext.BiosModuleNumber].Size    =
>(UINT32)BiosInfoStruct[BiosInfoIndex].Size;
>+          gFitTableContext.BiosModuleVersion =
>BiosInfoStruct[BiosInfoIndex].Version;
>+          gFitTableContext.BiosModuleNumber ++;
>+          gFitTableContext.FitEntryNumber ++;
>+          break;
>+        case FIT_TABLE_TYPE_MICROCODE:
>+          if ((BiosInfoStruct[BiosInfoIndex].Attributes &
>BIOS_INFO_STRUCT_ATTRIBUTE_MICROCODE_WHOLE_REGION) == 0) {
>+            if (gFitTableContext.MicrocodeNumber >= MAX_MICROCODE_ENTRY)
>{
>+              Error (NULL, 0, 0, "-I Parameter incorrect, Too many Microcode!",
>NULL);
>+              return 0;
>+            }
>+
>gFitTableContext.Microcode[gFitTableContext.MicrocodeNumber].Type    =
>FIT_TABLE_TYPE_MICROCODE;
>+
>gFitTableContext.Microcode[gFitTableContext.MicrocodeNumber].Address =
>(UINT32)BiosInfoStruct[BiosInfoIndex].Address;
>+
>gFitTableContext.Microcode[gFitTableContext.MicrocodeNumber].Size    =
>(UINT32)BiosInfoStruct[BiosInfoIndex].Size;
>+            gFitTableContext.MicrocodeVersion =
>BiosInfoStruct[BiosInfoIndex].Version;
>+            gFitTableContext.MicrocodeNumber++;
>+            gFitTableContext.FitEntryNumber++;
>+          } else {
>+            MicrocodeRegionOffset =
>(UINT32)BiosInfoStruct[BiosInfoIndex].Address;
>+            MicrocodeRegionSize   = (UINT32)BiosInfoStruct[BiosInfoIndex].Size;
>+            if (MicrocodeRegionOffset == 0) {
>+              Error (NULL, 0, 0, "-I Parameter incorrect, MicrocodeRegionOffset is 0",
>NULL);
>+              return 0;
>+            }
>+            if (MicrocodeRegionSize == 0) {
>+              Error (NULL, 0, 0, "-I Parameter incorrect, MicrocodeRegionSize is 0",
>NULL);
>+              return 0;
>+            }
>+            if (MicrocodeRegionSize > FdSize) {
>+              Error (NULL, 0, 0, "-I Parameter incorrect, MicrocodeRegionSize too
>large", NULL);
>+              return 0;
>+            }
>+
>+            MicrocodeFileBuffer = FLASH_TO_MEMORY (MicrocodeRegionOffset,
>FdBuffer, FdSize);
>+            MicrocodeFileSize = MicrocodeRegionSize;
>+            MicrocodeBase = MicrocodeRegionOffset;
>+
>+            FvHeader = (EFI_FIRMWARE_VOLUME_HEADER
>*)MicrocodeFileBuffer;
>+            if (FvHeader->Signature == EFI_FVH_SIGNATURE) {
>+              // Skip FV header + FFS header
>+              MicrocodeBuffer = MicrocodeFileBuffer +
>sizeof(EFI_FIRMWARE_VOLUME_HEADER) +
>sizeof(EFI_FV_BLOCK_MAP_ENTRY) + sizeof(EFI_FFS_FILE_HEADER);
>+            } else {
>+              MicrocodeBuffer = MicrocodeFileBuffer;
>+            }
>+            while ((UINT32)(MicrocodeBuffer - MicrocodeFileBuffer) <
>MicrocodeFileSize) {
>+              if (*(UINT32 *)(MicrocodeBuffer) != 0x1) { // HeaderVersion
>+                break;
>+              }
>+              if (*(UINT32 *)(MicrocodeBuffer + 20) != 0x1) { // LoaderVersion
>+                break;
>+              }
>+              if (*(UINT32 *)(MicrocodeBuffer + 28) == 0) { // DataSize
>+                MicrocodeSize = 2048;
>+              } else {
>+                //
>+                // MCU might be put at 2KB alignment, if so, we need to adjust the
>size as 2KB alignment.
>+                //
>+                if (gFitTableContext.MicrocodeAlignment) {
>+                  MicrocodeSize = (*(UINT32 *)(MicrocodeBuffer + 32) +
>MICROCODE_ALIGNMENT) & ~MICROCODE_ALIGNMENT;
>+                } else {
>+                  MicrocodeSize = (*(UINT32 *)(MicrocodeBuffer + 32));
>+                }
>+              }
>+
>+              //
>+              // Add Microcode
>+              //
>+              if (gFitTableContext.MicrocodeNumber >= MAX_MICROCODE_ENTRY)
>{
>+                printf ("-I Parameter incorrect, Too many Microcode!\n");
>+                return 0;
>+              }
>+
>gFitTableContext.Microcode[gFitTableContext.MicrocodeNumber].Type =
>FIT_TABLE_TYPE_MICROCODE;
>+
>gFitTableContext.Microcode[gFitTableContext.MicrocodeNumber].Address =
>MicrocodeBase + ((UINT32) (UINTN) MicrocodeBuffer - (UINT32) (UINTN)
>MicrocodeFileBuffer);
>+
>gFitTableContext.Microcode[gFitTableContext.MicrocodeNumber].Size =
>MicrocodeSize;
>+              gFitTableContext.MicrocodeNumber++;
>+              gFitTableContext.FitEntryNumber++;
>+
>+              MicrocodeBuffer += MicrocodeSize;
>+            }
>+          }
>+          break;
>+        case FIT_TABLE_TYPE_TPM_POLICY:
>+        case FIT_TABLE_TYPE_BIOS_POLICY:
>+        case FIT_TABLE_TYPE_TXT_POLICY:
>+        case FIT_TABLE_TYPE_KEY_MANIFEST:
>+        case FIT_TABLE_TYPE_BOOT_POLICY_MANIFEST:
>+        case FIT_TABLE_TYPE_BIOS_DATA_AREA:
>+        case FIT_TABLE_TYPE_CSE_SECURE_BOOT:
>+        default :
>+          if (BiosInfoStruct[BiosInfoIndex].Version != 0) {
>+            if (gFitTableContext.OptionalModuleNumber >=
>MAX_OPTIONAL_ENTRY) {
>+              Error (NULL, 0, 0, "-I Parameter incorrect, Too many Optional
>Module!", NULL);
>+              return 0;
>+            }
>+
>gFitTableContext.OptionalModule[gFitTableContext.OptionalModuleNumber
>].Type    = BiosInfoStruct[BiosInfoIndex].Type;
>+
>gFitTableContext.OptionalModule[gFitTableContext.OptionalModuleNumber
>].Address = (UINT32)BiosInfoStruct[BiosInfoIndex].Address;
>+
>gFitTableContext.OptionalModule[gFitTableContext.OptionalModuleNumber
>].Size    = (UINT32)BiosInfoStruct[BiosInfoIndex].Size;
>+
>gFitTableContext.OptionalModule[gFitTableContext.OptionalModuleNumber
>].Version = BiosInfoStruct[BiosInfoIndex].Version;
>+            gFitTableContext.OptionalModuleNumber++;
>+            gFitTableContext.FitEntryNumber++;
>+          } else {
>+            if (gFitTableContext.PortModuleNumber >= MAX_PORT_ENTRY) {
>+              Error (NULL, 0, 0, "-I Parameter incorrect, Too many Port Module!",
>NULL);
>+              return 0;
>+            }
>+
>gFitTableContext.PortModule[gFitTableContext.PortModuleNumber].Type
>= BiosInfoStruct[BiosInfoIndex].Type;
>+
>gFitTableContext.PortModule[gFitTableContext.PortModuleNumber].Addres
>s = (UINT32)BiosInfoStruct[BiosInfoIndex].Address;
>+
>gFitTableContext.PortModule[gFitTableContext.PortModuleNumber].Size    =
>(UINT32)(BiosInfoStruct[BiosInfoIndex].Address >> 32);
>+
>gFitTableContext.PortModule[gFitTableContext.PortModuleNumber].Version
>= BiosInfoStruct[BiosInfoIndex].Version;
>+            gFitTableContext.PortModuleNumber++;
>+            gFitTableContext.FitEntryNumber++;
>+          }
>+          break;
>+        }
>+      }
>+
>+    } else {
>+      Error (NULL, 0, 0, "-I Parameter incorrect, expect GUID!", NULL);
>+      return 0;
>+    }
>+    Index += 2;
>+  }
>+
>+  //
>+  // 1. StartupAcm
>+  //
>+  do {
>+    if ((Index + 1 >= argc) ||
>+        ((strcmp (argv[Index], "-S") != 0) &&
>+         (strcmp (argv[Index], "-s") != 0)) ) {
>+      if (BiosInfoExist && (gFitTableContext.StartupAcm.Type ==
>FIT_TABLE_TYPE_STARTUP_ACM)) {
>+        break;
>+      }
>+//      Error (NULL, 0, 0, "-S Parameter incorrect, expect -S!", NULL);
>+//      return 0;
>+      printf ("-S not found. WARNING!\n");
>+      break;
>+    }
>+    if (IsGuidData (argv[Index + 1], &Guid)) {
>+      FileBuffer = FindFileFromFvByGuid (FdBuffer, FdSize, &Guid, &FileSize);
>+      if (FileBuffer == NULL) {
>+        Error (NULL, 0, 0, "-S Parameter incorrect, GUID not found!", "%s",
>argv[Index + 1]);
>+        // not found
>+        return 0;
>+      }
>+      FileBuffer = (UINT8 *)MEMORY_TO_FLASH (FileBuffer, FdBuffer, FdSize);
>+      Index += 2;
>+    } else {
>+      if (Index + 2 >= argc) {
>+        Error (NULL, 0, 0, "-S Parameter incorrect, expect Address Size!", NULL);
>+        return 0;
>+      }
>+      FileBuffer = (UINT8 *) (UINTN) xtoi (argv[Index + 1]);
>+      FileSize = xtoi (argv[Index + 2]);
>+      Index += 3;
>+    }
>+    if (gFitTableContext.StartupAcm.Type != 0) {
>+      Error (NULL, 0, 0, "-S Parameter incorrect, Duplicated StartupAcm!", NULL);
>+      return 0;
>+    }
>+    gFitTableContext.StartupAcm.Type = FIT_TABLE_TYPE_STARTUP_ACM;
>+    gFitTableContext.StartupAcm.Address = (UINT32) (UINTN) FileBuffer;
>+    gFitTableContext.StartupAcm.Size = FileSize;
>+    gFitTableContext.FitEntryNumber ++;
>+
>+    //
>+    // 1.1 StartupAcm version
>+    //
>+    if ((Index + 1 >= argc) ||
>+        ((strcmp (argv[Index], "-V") != 0) &&
>+         (strcmp (argv[Index], "-v") != 0)) ) {
>+      //
>+      // Bypass
>+      //
>+      gFitTableContext.StartupAcmVersion = gFitTableContext.GlobalVersion;
>+    } else {
>+      //
>+      // Get offset from parameter
>+      //
>+      gFitTableContext.StartupAcmVersion = xtoi (argv[Index + 1]);
>+      Index += 2;
>+    }
>+  } while (FALSE);
>+
>+  //
>+  // 2. BiosModule
>+  //
>+  do {
>+    if ((Index + 2 >= argc) ||
>+        ((strcmp (argv[Index], "-B") != 0) &&
>+         (strcmp (argv[Index], "-b") != 0)) ) {
>+      if (BiosInfoExist && (gFitTableContext.BiosModuleNumber != 0)) {
>+        break;
>+      }
>+//      Error (NULL, 0, 0, "-B Parameter incorrect, expect -B!", NULL);
>+//      return 0;
>+      printf ("-B not found. WARNING!\n");
>+      break;
>+    }
>+
>+    FileBuffer = (UINT8 *) (UINTN) xtoi (argv[Index + 1]);
>+    FileSize = xtoi (argv[Index + 2]);
>+
>gFitTableContext.BiosModule[gFitTableContext.BiosModuleNumber].Type =
>FIT_TABLE_TYPE_BIOS_MODULE;
>+
>gFitTableContext.BiosModule[gFitTableContext.BiosModuleNumber].Addres
>s = (UINT32) (UINTN) FileBuffer;
>+    gFitTableContext.BiosModule[gFitTableContext.BiosModuleNumber].Size
>= FileSize;
>+    gFitTableContext.BiosModuleNumber ++;
>+    gFitTableContext.FitEntryNumber ++;
>+
>+    while (TRUE) {
>+      Index += 3;
>+      if (Index + 2 >= argc) {
>+        break;
>+      }
>+      if ((strcmp (argv[Index], "-B") != 0) &&
>+          (strcmp (argv[Index], "-b") != 0) ) {
>+        break;
>+      }
>+      if (gFitTableContext.BiosModuleNumber >= MAX_BIOS_MODULE_ENTRY)
>{
>+        Error (NULL, 0, 0, "-B Parameter incorrect, Too many Bios Module!",
>NULL);
>+        return 0;
>+      }
>+      FileBuffer = (UINT8 *) (UINTN) xtoi (argv[Index + 1]);
>+      FileSize = xtoi (argv[Index + 2]);
>+
>gFitTableContext.BiosModule[gFitTableContext.BiosModuleNumber].Type =
>FIT_TABLE_TYPE_BIOS_MODULE;
>+
>gFitTableContext.BiosModule[gFitTableContext.BiosModuleNumber].Addres
>s = (UINT32) (UINTN) FileBuffer;
>+
>gFitTableContext.BiosModule[gFitTableContext.BiosModuleNumber].Size =
>FileSize;
>+      gFitTableContext.BiosModuleNumber ++;
>+      gFitTableContext.FitEntryNumber++;
>+    }
>+
>+    //
>+    // 2.1 BiosModule version
>+    //
>+    if ((Index + 1 >= argc) ||
>+        ((strcmp (argv[Index], "-V") != 0) &&
>+         (strcmp (argv[Index], "-v") != 0)) ) {
>+      //
>+      // Bypass
>+      //
>+      gFitTableContext.BiosModuleVersion = gFitTableContext.GlobalVersion;
>+    } else {
>+      //
>+      // Get offset from parameter
>+      //
>+      gFitTableContext.BiosModuleVersion = xtoi (argv[Index + 1]);
>+      Index += 2;
>+    }
>+  } while (FALSE);
>+
>+  //
>+  // 3. Microcode
>+  //
>+  while (TRUE) {
>+    if (Index + 1 >= argc) {
>+      break;
>+    }
>+    if ((strcmp (argv[Index], "-M") != 0) &&
>+        (strcmp (argv[Index], "-m") != 0) ) {
>+      break;
>+    }
>+    if (IsGuidData (argv[Index + 2], &Guid)) {
>+      Error (NULL, 0, 0, "-M Parameter incorrect, GUID unsupported!", NULL);
>+      return 0;
>+    } else {
>+      if (Index + 2 >= argc) {
>+        break;
>+      }
>+      FileBuffer = (UINT8 *) (UINTN) xtoi (argv[Index + 1]);
>+      FileSize = xtoi (argv[Index + 2]);
>+      Index += 3;
>+    }
>+    if (gFitTableContext.MicrocodeNumber >= MAX_MICROCODE_ENTRY) {
>+      Error (NULL, 0, 0, "-M Parameter incorrect, Too many Microcode!", NULL);
>+      return 0;
>+    }
>+    gFitTableContext.Microcode[gFitTableContext.MicrocodeNumber].Type =
>FIT_TABLE_TYPE_MICROCODE;
>+
>gFitTableContext.Microcode[gFitTableContext.MicrocodeNumber].Address =
>(UINT32) (UINTN) FileBuffer;
>+    gFitTableContext.Microcode[gFitTableContext.MicrocodeNumber].Size =
>FileSize;
>+    gFitTableContext.MicrocodeNumber++;
>+    gFitTableContext.FitEntryNumber++;
>+  }
>+
>+  //
>+  // 3.1 MicrocodeFv
>+  //
>+  while (TRUE) {
>+    if (Index + 1 >= argc) {
>+      break;
>+    }
>+    if ((strcmp (argv[Index], "-U") != 0) &&
>+        (strcmp (argv[Index], "-u") != 0) ) {
>+      break;
>+    }
>+    //
>+    // Get Fv
>+    //
>+    if (IsGuidData (argv[Index + 1], &Guid)) {
>+      MicrocodeFileBuffer = FindFileFromFvByGuid (FdBuffer, FdSize, &Guid,
>&MicrocodeFileSize);
>+      if (MicrocodeFileBuffer == NULL) {
>+        Error (NULL, 0, 0, "-U Parameter incorrect, GUID not found!", "%s",
>argv[Index + 1]);
>+        // not found
>+        return 0;
>+      }
>+      Index += 2;
>+
>+      MicrocodeBuffer = MicrocodeFileBuffer;
>+      MicrocodeFileBufferRaw = NULL;
>+      MicrocodeRegionOffset = MEMORY_TO_FLASH (MicrocodeFileBuffer,
>FdBuffer, FdSize);
>+      MicrocodeRegionSize   = 0;
>+      MicrocodeBase = MicrocodeRegionOffset;
>+
>+    } else {
>+      if (Index + 2 >= argc) {
>+        break;
>+      }
>+      Status = ReadInputFile (argv[Index + 1], &MicrocodeFileBuffer,
>&MicrocodeFileSize, &MicrocodeFileBufferRaw);
>+      if (Status != STATUS_SUCCESS) {
>+        MicrocodeRegionOffset = xtoi (argv[Index + 1]);
>+        MicrocodeRegionSize   = xtoi (argv[Index + 2]);
>+
>+        if (MicrocodeRegionOffset == 0) {
>+          Error (NULL, 0, 0, "-U Parameter incorrect, MicrocodeRegionOffset is 0,
>or unable to open file", "%s", argv[Index + 1]);
>+          return 0;
>+        }
>+        if (MicrocodeRegionSize == 0) {
>+          Error (NULL, 0, 0, "-U Parameter incorrect, MicrocodeRegionSize is 0",
>NULL);
>+          return 0;
>+        }
>+        if (MicrocodeRegionSize > FdSize) {
>+          Error (NULL, 0, 0, "-U Parameter incorrect, MicrocodeRegionSize too
>large", NULL);
>+          return 0;
>+        }
>+
>+        Index += 3;
>+
>+        MicrocodeFileBufferRaw = NULL;
>+        MicrocodeFileBuffer = FLASH_TO_MEMORY (MicrocodeRegionOffset,
>FdBuffer, FdSize);
>+        MicrocodeFileSize = MicrocodeRegionSize;
>+        MicrocodeBase = MicrocodeRegionOffset;
>+
>+        FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *)MicrocodeFileBuffer;
>+        if (FvHeader->Signature == EFI_FVH_SIGNATURE) {
>+          // Skip FV header + FFS header
>+          MicrocodeBuffer = MicrocodeFileBuffer +
>sizeof(EFI_FIRMWARE_VOLUME_HEADER) +
>sizeof(EFI_FV_BLOCK_MAP_ENTRY) + sizeof(EFI_FFS_FILE_HEADER);
>+        } else {
>+          MicrocodeBuffer = MicrocodeFileBuffer;
>+        }
>+      } else {
>+        MicrocodeBase = xtoi (argv[Index + 2]);
>+        Index += 3;
>+        MicrocodeRegionOffset = 0;
>+        MicrocodeRegionSize   = 0;
>+
>+        FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *)MicrocodeFileBuffer;
>+        if (FvHeader->Signature == EFI_FVH_SIGNATURE) {
>+          // Skip FV header + FFS header
>+          MicrocodeBuffer = MicrocodeFileBuffer +
>sizeof(EFI_FIRMWARE_VOLUME_HEADER) +
>sizeof(EFI_FV_BLOCK_MAP_ENTRY) + sizeof(EFI_FFS_FILE_HEADER);
>+        } else {
>+          MicrocodeBuffer = MicrocodeFileBuffer;
>+        }
>+      }
>+    }
>+    while ((UINT32)(MicrocodeBuffer - MicrocodeFileBuffer) <
>MicrocodeFileSize) {
>+      if (*(UINT32 *)(MicrocodeBuffer) != 0x1) { // HeaderVersion
>+        break;
>+      }
>+      if (*(UINT32 *)(MicrocodeBuffer + 20) != 0x1) { // LoaderVersion
>+        break;
>+      }
>+      if (*(UINT32 *)(MicrocodeBuffer + 28) == 0) { // DataSize
>+        MicrocodeSize = 2048;
>+      } else {
>+        //
>+        // MCU might be put at 2KB alignment, if so, we need to adjust the size
>as 2KB alignment.
>+        //
>+        if (gFitTableContext.MicrocodeAlignment) {
>+          MicrocodeSize = (*(UINT32 *)(MicrocodeBuffer + 32) +
>MICROCODE_ALIGNMENT) & ~MICROCODE_ALIGNMENT;
>+        } else {
>+          MicrocodeSize = (*(UINT32 *)(MicrocodeBuffer + 32));
>+        }
>+      }
>+
>+      //
>+      // Add Microcode
>+      //
>+      if (gFitTableContext.MicrocodeNumber >= MAX_MICROCODE_ENTRY) {
>+        printf ("-U Parameter incorrect, Too many Microcode!\n");
>+        return 0;
>+      }
>+      gFitTableContext.Microcode[gFitTableContext.MicrocodeNumber].Type
>= FIT_TABLE_TYPE_MICROCODE;
>+
>gFitTableContext.Microcode[gFitTableContext.MicrocodeNumber].Address =
>MicrocodeBase + ((UINT32) (UINTN) MicrocodeBuffer - (UINT32) (UINTN)
>MicrocodeFileBuffer);
>+      gFitTableContext.Microcode[gFitTableContext.MicrocodeNumber].Size =
>MicrocodeSize;
>+      gFitTableContext.MicrocodeNumber++;
>+      gFitTableContext.FitEntryNumber++;
>+
>+      MicrocodeBuffer += MicrocodeSize;
>+    }
>+
>+    if (MicrocodeFileBufferRaw != NULL) {
>+      free ((VOID *)MicrocodeFileBufferRaw);
>+      MicrocodeFileBufferRaw = NULL;
>+    }
>+  }
>+
>+  //
>+  // 3.3 Microcode version
>+  //
>+  if ((Index + 1 >= argc) ||
>+      ((strcmp (argv[Index], "-V") != 0) &&
>+       (strcmp (argv[Index], "-v") != 0)) ) {
>+    //
>+    // Bypass
>+    //
>+    gFitTableContext.MicrocodeVersion = gFitTableContext.GlobalVersion;
>+  } else {
>+    //
>+    // Get offset from parameter
>+    //
>+    gFitTableContext.MicrocodeVersion = xtoi (argv[Index + 1]);
>+    Index += 2;
>+  }
>+
>+  //
>+  // 4. Optional type
>+  //
>+  while (TRUE) {
>+    if (Index + 2 >= argc) {
>+      break;
>+    }
>+    if ((strcmp (argv[Index], "-O") != 0) &&
>+        (strcmp (argv[Index], "-o") != 0) ) {
>+      break;
>+    }
>+    Type = xtoi (argv[Index + 1]);
>+    //
>+    // 1st, try GUID
>+    //
>+    if (IsGuidData (argv[Index + 2], &Guid)) {
>+      FileBuffer = FindFileFromFvByGuid (FdBuffer, FdSize, &Guid, &FileSize);
>+      if (FileBuffer == NULL) {
>+        Error (NULL, 0, 0, "-O Parameter incorrect, GUID not found!", "%s",
>argv[Index + 2]);
>+        // not found
>+        return 0;
>+      }
>+      if (FileSize >= 0x80000000) {
>+        Error (NULL, 0, 0, "-O Parameter incorrect, FileSize too large!", NULL);
>+        return 0;
>+      }
>+      FileBuffer = (UINT8 *)MEMORY_TO_FLASH (FileBuffer, FdBuffer, FdSize);
>+      Index += 3;
>+    } else {
>+      //
>+      // 2nd, try file
>+      //
>+      Status = ReadInputFile (argv[Index + 2], &FileBuffer, &FileSize, NULL);
>+      if (Status == STATUS_SUCCESS) {
>+        if (FileSize >= 0x80000000) {
>+          Error (NULL, 0, 0, "-O Parameter incorrect, FileSize too large!", NULL);
>+          free (FileBuffer);
>+          return 0;
>+        }
>+        //
>+        // Set the most significant bit
>+        // It means the data in memory, not in flash yet.
>+        // Assume the file size should < 2G.
>+        //
>+        FileSize |= 0x80000000;
>+        Index += 3;
>+      } else {
>+        //
>+        // 3rd, try <RESERVE, Length>
>+        //
>+        if (Index + 3 >= argc) {
>+          break;
>+        }
>+        if ((strcmp (argv[Index + 2], "RESERVE") == 0) ||
>+            (strcmp (argv[Index + 2], "reserve") == 0)) {
>+          FileSize = xtoi (argv[Index + 3]);
>+          if (FileSize >= 0x80000000) {
>+            Error (NULL, 0, 0, "-O Parameter incorrect, FileSize too large!", NULL);
>+            return 0;
>+          }
>+          FileBuffer = malloc (FileSize);
>+          if (FileBuffer == NULL) {
>+            Error (NULL, 0, 0, "No sufficient memory to allocate!", NULL);
>+            return 0;
>+          }
>+          SetMem (FileBuffer, FileSize, 0xFF);
>+          //
>+          // Set the most significant bit
>+          // It means the data in memory, not in flash yet.
>+          // Assume the file size should < 2G.
>+          //
>+          FileSize |= 0x80000000;
>+          Index += 4;
>+        } else {
>+          //
>+          // 4th, try <Address, Length>
>+          //
>+          if (Index + 3 >= argc) {
>+            break;
>+          }
>+          FileBuffer = (UINT8 *) (UINTN) xtoi (argv[Index + 2]);
>+          FileSize = xtoi (argv[Index + 3]);
>+          if (FileSize >= 0x80000000) {
>+            Error (NULL, 0, 0, "-O Parameter incorrect, FileSize too large!", NULL);
>+            return 0;
>+          }
>+          Index += 4;
>+        }
>+      }
>+    }
>+    if (gFitTableContext.OptionalModuleNumber >= MAX_OPTIONAL_ENTRY)
>{
>+      Error (NULL, 0, 0, "-O Parameter incorrect, Too many Optional Module!",
>NULL);
>+      free (FileBuffer);
>+      return 0;
>+    }
>+
>gFitTableContext.OptionalModule[gFitTableContext.OptionalModuleNumber
>].Type = Type;
>+
>gFitTableContext.OptionalModule[gFitTableContext.OptionalModuleNumber
>].Address = (UINT32) (UINTN) FileBuffer;
>+
>gFitTableContext.OptionalModule[gFitTableContext.OptionalModuleNumber
>].Size = FileSize;
>+
>+    //
>+    // 4.1 Optional Module version
>+    //
>+    if ((Index + 1 >= argc) ||
>+        ((strcmp (argv[Index], "-V") != 0) &&
>+         (strcmp (argv[Index], "-v") != 0)) ) {
>+      //
>+      // Bypass
>+      //
>+
>gFitTableContext.OptionalModule[gFitTableContext.OptionalModuleNumber
>].Version = gFitTableContext.GlobalVersion;
>+    } else {
>+      //
>+      // Get offset from parameter
>+      //
>+
>gFitTableContext.OptionalModule[gFitTableContext.OptionalModuleNumber
>].Version = xtoi (argv[Index + 1]);
>+      Index += 2;
>+    }
>+
>+    gFitTableContext.OptionalModuleNumber ++;
>+    gFitTableContext.FitEntryNumber++;
>+  }
>+
>+  //
>+  // 5. Port type
>+  //
>+  while (TRUE) {
>+    if (Index + 6 >= argc) {
>+      break;
>+    }
>+    if ((strcmp (argv[Index], "-P") != 0) &&
>+        (strcmp (argv[Index], "-p") != 0) ) {
>+      break;
>+    }
>+
>+    Type = xtoi (argv[Index + 1]);
>+    if (gFitTableContext.PortModuleNumber >= MAX_PORT_ENTRY) {
>+      printf ("-P Parameter incorrect, Too many Port Module!\n");
>+      return 0;
>+    }
>+
>+
>gFitTableContext.PortModule[gFitTableContext.PortModuleNumber].Type =
>Type;
>+
>gFitTableContext.PortModule[gFitTableContext.PortModuleNumber].Addres
>s = (UINT16)xtoi (argv[Index + 2]) + ((UINT16)xtoi (argv[Index + 3]) << 16);
>+    gFitTableContext.PortModule[gFitTableContext.PortModuleNumber].Size
>= (UINT8)xtoi (argv[Index + 4]) + ((UINT8)xtoi (argv[Index + 5]) << 8) +
>((UINT16)xtoi (argv[Index + 6]) << 16);
>+    Index += 7;
>+
>+    //
>+    // 5.1 Port Module version
>+    //
>+    if ((Index + 1 >= argc) ||
>+        ((strcmp (argv[Index], "-V") != 0) &&
>+         (strcmp (argv[Index], "-v") != 0)) ) {
>+      //
>+      // Bypass
>+      //
>+
>gFitTableContext.PortModule[gFitTableContext.PortModuleNumber].Version
>= 0;
>+    } else {
>+      //
>+      // Get offset from parameter
>+      //
>+
>gFitTableContext.PortModule[gFitTableContext.PortModuleNumber].Version
>= xtoi (argv[Index + 1]);
>+      Index += 2;
>+    }
>+
>+    gFitTableContext.PortModuleNumber++;
>+    gFitTableContext.FitEntryNumber++;
>+  }
>+
>+  //
>+  // Final: Check StartupAcm in BiosModule.
>+  //
>+  CheckOverlap (gFitTableContext.StartupAcm.Address,
>gFitTableContext.StartupAcm.Size);
>+  FitEntryNumber = gFitTableContext.FitEntryNumber;
>+  for (Index = 0; Index < (INTN)gFitTableContext.OptionalModuleNumber;
>Index++) {
>+    if ((gFitTableContext.OptionalModule[Index].Type ==
>FIT_TABLE_TYPE_BIOS_POLICY) ||
>+        (gFitTableContext.OptionalModule[Index].Type ==
>FIT_TABLE_TYPE_KEY_MANIFEST) ||
>+        (gFitTableContext.OptionalModule[Index].Type ==
>FIT_TABLE_TYPE_BOOT_POLICY_MANIFEST) ||
>+        (gFitTableContext.OptionalModule[Index].Type ==
>FIT_TABLE_TYPE_BIOS_DATA_AREA) ||
>+        (gFitTableContext.OptionalModule[Index].Type ==
>FIT_TABLE_TYPE_CSE_SECURE_BOOT)) {
>+      // NOTE: It might be virtual address now. Just put a place holder.
>+      FitEntryNumber ++;
>+    }
>+  }
>+
>+  return FitEntryNumber;
>+}
>+
>+VOID *
>+FindSpaceSkipApVector (
>+  IN UINT8     *FvBuffer,
>+  IN UINT8     *Address,
>+  IN UINTN     Size
>+  )
>+/*++
>+
>+Routine Description:
>+
>+  No enough space - it might happen that it is occupied by AP wake vector.
>+  Last chance - skip this and search again.
>+
>+Arguments:
>+
>+  FvBuffer       - FvRecovery binary buffer
>+  Address        - Address to be searched from
>+  Size           - Size need to be filled
>+
>+Returns:
>+
>+  FitTableOffset - The FIT table offset
>+  NULL           - No enough space for FIT table
>+
>+*/
>+{
>+  UINT8        *ApVector;
>+  UINT8        *NewAddress;
>+  UINTN        Index;
>+
>+  ApVector = (UINT8 *)((UINTN)Address & ~0xFFF);
>+  if ((UINTN)ApVector <= (UINTN)FvBuffer) {
>+    return NULL;
>+  }
>+
>+  NewAddress = (UINT8 *)(ApVector - Size);
>+  for (Index = 0; Index < Size; Index ++) {
>+    if (NewAddress[Index] != 0xFF) {
>+      return NULL;
>+    }
>+  }
>+  return NewAddress;
>+}
>+
>+VOID *
>+GetFreeSpaceFromFv (
>+  IN UINT8     *FvBuffer,
>+  IN UINT32    FvSize,
>+  IN UINT32    FitEntryNumber
>+  )
>+/*++
>+
>+Routine Description:
>+
>+  Get free space for FIT table from FvRecovery
>+
>+Arguments:
>+
>+  FvBuffer       - FvRecovery binary buffer
>+  FvSize         - FvRecovery size
>+  FitEntryNumber - The FIT entry number
>+
>+Returns:
>+
>+  FitTableOffset - The offset of FIT table in FvRecovery file
>+  NULL           - Free space not found
>+
>+--*/
>+{
>+  UINT8       *FitTableOffset;
>+  INTN        Index;
>+  INTN        SubIndex;
>+  UINT8       *OptionalModuleAddress;
>+  EFI_GUID    VTFGuid = EFI_FFS_VOLUME_TOP_FILE_GUID;
>+  UINT32      AlignedSize;
>+  UINT32      FitTableSize;
>+
>+  EFI_FIRMWARE_VOLUME_HEADER  *FvHeader;
>+  EFI_FFS_FILE_HEADER         *FileHeader;
>+  UINT64                      FvLength;
>+  UINT32                      Offset;
>+  UINT32                      FileLength;
>+  UINT32                      FileOccupiedSize;
>+
>+  //
>+  // Check 4G - FitTablePointerOffset
>+  //
>+  if ((*(UINT64 *)(FvBuffer + FvSize -
>gFitTableContext.FitTablePointerOffset) != 0xFFFFFFFFFFFFFFFFull) &&
>+      (*(UINT64 *)(FvBuffer + FvSize -
>gFitTableContext.FitTablePointerOffset) != 0) &&
>+      (*(UINT64 *)(FvBuffer + FvSize -
>gFitTableContext.FitTablePointerOffset) != 0xEEEEEEEEEEEEEEEEull)) {
>+    Error (NULL, 0, 0, "4G - FitTablePointerOffset is occupied!", NULL);
>+    return NULL;
>+  }
>+  if (gFitTableContext.FitTablePointerOffset2 != 0) {
>+    if ((*(UINT64 *)(FvBuffer + FvSize -
>gFitTableContext.FitTablePointerOffset2) != 0xFFFFFFFFFFFFFFFFull) &&
>+        (*(UINT64 *)(FvBuffer + FvSize -
>gFitTableContext.FitTablePointerOffset2) != 0) &&
>+        (*(UINT64 *)(FvBuffer + FvSize -
>gFitTableContext.FitTablePointerOffset2) != 0xEEEEEEEEEEEEEEEEull)) {
>+      Error (NULL, 0, 0, "4G - FitTablePointerOffset is occupied!", NULL);
>+      return NULL;
>+    }
>+  }
>+
>+  //
>+  // Get EFI_FFS_VOLUME_TOP_FILE_GUID location
>+  //
>+  FitTableOffset = NULL;
>+
>+  FvHeader         = (EFI_FIRMWARE_VOLUME_HEADER *)FvBuffer;
>+  FvLength         = FvHeader->FvLength;
>+  FileHeader       = (EFI_FFS_FILE_HEADER *)(FvBuffer + FvHeader-
>>HeaderLength);
>+  Offset           = (UINTN)FileHeader - (UINTN)FvBuffer;
>+
>+  while (Offset < FvLength) {
>+    FileLength = (*(UINT32 *)(FileHeader->Size)) & 0x00FFFFFF;
>+    FileOccupiedSize = GETOCCUPIEDSIZE(FileLength, 8);
>+    if ((CompareGuid (&(FileHeader->Name), &VTFGuid)) == 0) {
>+      // find it
>+      FitTableOffset = (UINT8 *)FileHeader;
>+      break;
>+    }
>+    FileHeader = (EFI_FFS_FILE_HEADER *)((UINTN)FileHeader +
>FileOccupiedSize);
>+    Offset = (UINTN)FileHeader - (UINTN)FvBuffer;
>+  }
>+
>+  if (FitTableOffset == NULL) {
>+    Error (NULL, 0, 0, "EFI_FFS_VOLUME_TOP_FILE_GUID not found!", NULL);
>+    return NULL;
>+  }
>+
>+  FitTableSize = FitEntryNumber *
>sizeof(FIRMWARE_INTERFACE_TABLE_ENTRY);
>+  FitTableSize += FIT_ALIGNMENT;
>+  FitTableSize &= ~FIT_ALIGNMENT;
>+
>+  FitTableOffset = (UINT8 *)((UINTN)FitTableOffset & ~FIT_ALIGNMENT);
>+  FitTableOffset = (UINT8 *)(FitTableOffset - FitTableSize);
>+
>+  //
>+  // Check it
>+  //
>+  for (Index = 0; Index < (INTN)(FitTableSize); Index ++) {
>+    if (FitTableOffset[Index] != 0xFF) {
>+      //
>+      // No enough space - it might happen that it is occupied by AP wake
>vector.
>+      // Last chance - skip this and search again.
>+      //
>+      FitTableOffset = FindSpaceSkipApVector (FvBuffer,
>&FitTableOffset[Index], FitTableSize);
>+      if (FitTableOffset == NULL) {
>+        Error (NULL, 0, 0, "No enough space for FIT table!", NULL);
>+        return NULL;
>+      }
>+    }
>+  }
>+
>+  //
>+  // Check space for Optional module
>+  //
>+  OptionalModuleAddress = FitTableOffset;
>+  for (Index = 0; Index < (INTN)gFitTableContext.OptionalModuleNumber;
>Index++) {
>+    AlignedSize = gFitTableContext.OptionalModule[Index].Size;
>+    if ((gFitTableContext.OptionalModule[Index].Size & 0x80000000) != 0) {
>+
>+      //
>+      // Need copy binary to file.
>+      //
>+      gFitTableContext.OptionalModule[Index].Size &= ~0x80000000;
>+
>+      AlignedSize = gFitTableContext.OptionalModule[Index].Size;
>+      if ((gFitTableContext.OptionalModule[Index].Type ==
>FIT_TABLE_TYPE_BIOS_POLICY) ||
>+          (gFitTableContext.OptionalModule[Index].Type ==
>FIT_TABLE_TYPE_KEY_MANIFEST) ||
>+          (gFitTableContext.OptionalModule[Index].Type ==
>FIT_TABLE_TYPE_BOOT_POLICY_MANIFEST) ||
>+          (gFitTableContext.OptionalModule[Index].Type ==
>FIT_TABLE_TYPE_BIOS_DATA_AREA) ||
>+          (gFitTableContext.OptionalModule[Index].Type ==
>FIT_TABLE_TYPE_CSE_SECURE_BOOT)) {
>+        // Let it 64 byte align
>+        AlignedSize += BIOS_MODULE_ALIGNMENT;
>+        AlignedSize &= ~BIOS_MODULE_ALIGNMENT;
>+      }
>+
>+      OptionalModuleAddress -= AlignedSize;
>+
>+      if ((gFitTableContext.OptionalModule[Index].Type ==
>FIT_TABLE_TYPE_BIOS_POLICY) ||
>+          (gFitTableContext.OptionalModule[Index].Type ==
>FIT_TABLE_TYPE_KEY_MANIFEST) ||
>+          (gFitTableContext.OptionalModule[Index].Type ==
>FIT_TABLE_TYPE_BOOT_POLICY_MANIFEST) ||
>+          (gFitTableContext.OptionalModule[Index].Type ==
>FIT_TABLE_TYPE_BIOS_DATA_AREA) ||
>+          (gFitTableContext.OptionalModule[Index].Type ==
>FIT_TABLE_TYPE_CSE_SECURE_BOOT)) {
>+        // Let it 64 byte align
>+        OptionalModuleAddress = (UINT8 *)((UINTN)OptionalModuleAddress &
>~BIOS_MODULE_ALIGNMENT);
>+      }
>+
>+      for (SubIndex = 0; SubIndex < (INTN)(AlignedSize); SubIndex ++) {
>+        if (OptionalModuleAddress[SubIndex] != 0xFF) {
>+          //
>+          // No enough space - it might happen that it is occupied by AP wake
>vector.
>+          // Last chance - skip this and search again.
>+          //
>+          OptionalModuleAddress = FindSpaceSkipApVector (FvBuffer,
>&OptionalModuleAddress[SubIndex], AlignedSize);
>+          if (OptionalModuleAddress == NULL) {
>+            Error (NULL, 0, 0, "No enough space for OptionalModule!", NULL);
>+            return NULL;
>+          }
>+        }
>+      }
>+      memcpy (OptionalModuleAddress, (VOID *) (UINTN)
>gFitTableContext.OptionalModule[Index].Address,
>gFitTableContext.OptionalModule[Index].Size);
>+      free ((VOID *) (UINTN)
>gFitTableContext.OptionalModule[Index].Address);
>+      gFitTableContext.OptionalModule[Index].Address = MEMORY_TO_FLASH
>(OptionalModuleAddress, FvBuffer, FvSize);
>+    }
>+    //
>+    // Final: Check BiosPolicyData in BiosModule.
>+    //
>+    if ((gFitTableContext.OptionalModule[Index].Type ==
>FIT_TABLE_TYPE_BIOS_POLICY) ||
>+        (gFitTableContext.OptionalModule[Index].Type ==
>FIT_TABLE_TYPE_KEY_MANIFEST) ||
>+        (gFitTableContext.OptionalModule[Index].Type ==
>FIT_TABLE_TYPE_BOOT_POLICY_MANIFEST) ||
>+        (gFitTableContext.OptionalModule[Index].Type ==
>FIT_TABLE_TYPE_BIOS_DATA_AREA) ||
>+        (gFitTableContext.OptionalModule[Index].Type ==
>FIT_TABLE_TYPE_CSE_SECURE_BOOT)) {
>+      CheckOverlap (gFitTableContext.OptionalModule[Index].Address,
>AlignedSize);
>+    }
>+  }
>+
>+  return FitTableOffset;
>+}
>+
>+VOID
>+PrintFitData (
>+  VOID
>+  )
>+/*++
>+
>+Routine Description:
>+
>+  Output FIT table information
>+
>+Arguments:
>+
>+  None
>+
>+Returns:
>+
>+  None
>+
>+--*/
>+{
>+  UINT32                          Index;
>+
>+  printf ("FIT Table Pointer Offset: 0x%x\n",
>gFitTableContext.FitTablePointerOffset);
>+  if (gFitTableContext.FitTablePointerOffset2 != 0) {
>+    printf ("FIT Table Pointer Offset: 0x%x\n",
>gFitTableContext.FitTablePointerOffset2);
>+  }
>+  printf ("Total FIT Entry number: 0x%x\n",
>gFitTableContext.FitEntryNumber);
>+  printf ("FitHeader version: 0x%04x\n", gFitTableContext.FitHeaderVersion);
>+  if (gFitTableContext.StartupAcm.Address != 0) {
>+    printf ("StartupAcm - (0x%08x, 0x%08x, 0x%04x)\n",
>gFitTableContext.StartupAcm.Address, gFitTableContext.StartupAcm.Size,
>gFitTableContext.StartupAcmVersion);
>+  }
>+  for (Index = 0; Index < gFitTableContext.BiosModuleNumber; Index++) {
>+    printf ("BiosModule[%d] - (0x%08x, 0x%08x, 0x%04x)\n", Index,
>gFitTableContext.BiosModule[Index].Address,
>gFitTableContext.BiosModule[Index].Size,
>gFitTableContext.BiosModuleVersion);
>+  }
>+  for (Index = 0; Index < gFitTableContext.MicrocodeNumber; Index++) {
>+    printf ("Microcode[%d] - (0x%08x, 0x%08x, 0x%04x)\n", Index,
>gFitTableContext.Microcode[Index].Address,
>gFitTableContext.Microcode[Index].Size,
>gFitTableContext.MicrocodeVersion);
>+  }
>+  for (Index = 0; Index < gFitTableContext.OptionalModuleNumber; Index++)
>{
>+    printf ("OptionalModule[%d] - (0x%08x, 0x%08x, 0x%02x, 0x%04x)\n",
>Index, gFitTableContext.OptionalModule[Index].Address,
>gFitTableContext.OptionalModule[Index].Size,
>gFitTableContext.OptionalModule[Index].Type,
>gFitTableContext.OptionalModule[Index].Version);
>+  }
>+  for (Index = 0; Index < gFitTableContext.PortModuleNumber; Index++) {
>+    printf ("PortModule[%d] - (0x%04x, 0x%04x, 0x%02x, 0x%02x, 0x%04x,
>0x%02x, 0x%04x)\n", Index,
>+      (UINT16)gFitTableContext.PortModule[Index].Address,
>(UINT16)(gFitTableContext.PortModule[Index].Address >> 16),
>+      (UINT8)gFitTableContext.PortModule[Index].Size,
>(UINT8)(gFitTableContext.PortModule[Index].Size >> 8),
>(UINT16)(gFitTableContext.PortModule[Index].Size >> 16),
>+      gFitTableContext.PortModule[Index].Type,
>gFitTableContext.PortModule[Index].Version);
>+  }
>+
>+  printf ("\n");
>+  return ;
>+}
>+
>+CHAR8 *mFitTypeStr[] = {
>+  "           ",
>+  "MICROCODE  ",
>+  "STARTUP_ACM",
>+  "           ",
>+  "           ",
>+  "           ",
>+  "           ",
>+  "BIOS_MODULE",
>+  "TPM_POLICY ",
>+  "BIOS_POLICY",
>+  "TXT_POLICY ",
>+  "KEYMANIFEST",
>+  "BP_MANIFEST",
>+  "BIOS_DATA_A",
>+  " ",
>+  " ",
>+  "CSE_SECUREB"
>+};
>+
>+CHAR8  mFitSignature[] = "'_FIT_   ' ";
>+CHAR8  mFitSignatureInHeader[] = "'        ' ";
>+CHAR8 *
>+FitTypeToStr (
>+  IN FIRMWARE_INTERFACE_TABLE_ENTRY  *FitEntry
>+  )
>+/*++
>+
>+Routine Description:
>+
>+  Convert FitEntry type to a string
>+
>+Arguments:
>+
>+  FitEntry - Fit entry
>+
>+Returns:
>+
>+  String
>+
>+--*/
>+{
>+  if (FitEntry->Type == FIT_TABLE_TYPE_HEADER) {
>+    CopyMem (&mFitSignatureInHeader[1], &FitEntry->Address,
>sizeof(FitEntry->Address));
>+    return mFitSignatureInHeader;
>+  }
>+  if (FitEntry->Type < sizeof (mFitTypeStr)/sizeof(mFitTypeStr[0])) {
>+    return mFitTypeStr[FitEntry->Type];
>+  } else {
>+    return "           ";
>+  }
>+}
>+
>+VOID
>+PrintFitTable (
>+  IN UINT8                       *FvBuffer,
>+  IN UINT32                      FvSize
>+  )
>+/*++
>+
>+Routine Description:
>+
>+  Print Fit table in flash image
>+
>+Arguments:
>+
>+  FvBuffer       - FvRecovery binary buffer
>+  FvSize         - FvRecovery size
>+
>+Returns:
>+
>+  None
>+
>+--*/
>+{
>+  FIRMWARE_INTERFACE_TABLE_ENTRY  *FitEntry;
>+  UINT32                          EntryNum;
>+  UINT32                          Index;
>+  UINT32                          FitTableOffset;
>+  FIRMWARE_INTERFACE_TABLE_ENTRY_PORT   *FitEntryPort;
>+
>+  printf ("##############\n");
>+  printf ("# FIT Table: #\n");
>+  printf ("##############\n");
>+
>+  printf ("FIT Pointer Offset: 0x%x\n",
>gFitTableContext.FitTablePointerOffset);
>+  FitTableOffset = *(UINT32 *)(FvBuffer + FvSize -
>gFitTableContext.FitTablePointerOffset);
>+  printf ("FIT Table Address:  0x%x\n", FitTableOffset);
>+  FitEntry = (FIRMWARE_INTERFACE_TABLE_ENTRY
>*)FLASH_TO_MEMORY(FitTableOffset, FvBuffer, FvSize);
>+
>+  //
>+  // Check FitEntry is 16 byte aligned
>+  //
>+  if (((UINTN)FitEntry & 0xF) != 0) {
>+    printf("ERROR: invalid FitEntry address 0x%X!\n", (UINT32) (UINTN)
>FitEntry);
>+    return;
>+  }
>+
>+  EntryNum = *(UINT32 *)(&FitEntry[0].Size[0]) & 0xFFFFFF;
>+  printf ("====== ================ ====== ======== ==============
>==== ======== (====== ==== ====== ==== ======)\n");
>+  printf ("Index:      Address      Size  Version       Type      C_V  Checksum (Index
>Data Width  Bit  Offset)\n");
>+  printf ("====== ================ ====== ======== ==============
>==== ======== (====== ==== ====== ==== ======)\n");
>+  for (Index = 0; Index < EntryNum; Index++) {
>+    printf (" %02d:   %016llx %06x   %04x   %02x-%s  %02x     %02x   ",
>+      Index,
>+      (unsigned long long) FitEntry[Index].Address,
>+      *(UINT32 *)(&FitEntry[Index].Size[0]) & 0xFFFFFF,
>+      FitEntry[Index].Version,
>+      FitEntry[Index].Type,
>+      FitTypeToStr(&FitEntry[Index]),
>+      FitEntry[Index].C_V,
>+      FitEntry[Index].Checksum
>+      );
>+
>+    if (Index == 0) {
>+      if (FitEntry[Index].Type != FIT_TABLE_TYPE_HEADER) {
>+        printf("ERROR: FIT Entry 0 is not Header Type %d!\n",
>FIT_TABLE_TYPE_HEADER);
>+        return;
>+      }
>+      if (strcmp(mFitSignatureInHeader, mFitSignature) != 0) {
>+        printf("ERROR: FIT Entry 0 signature invalid (%s, expected %s)!\n",
>mFitSignatureInHeader, mFitSignature);
>+        return;
>+      }
>+
>+    }
>+
>+    switch (FitEntry[Index].Type) {
>+    case FIT_TABLE_TYPE_TPM_POLICY:
>+    case FIT_TABLE_TYPE_TXT_POLICY:
>+      if (FitEntry[Index].Version == 0) {
>+        FitEntryPort = (FIRMWARE_INTERFACE_TABLE_ENTRY_PORT
>*)&FitEntry[Index];
>+        printf (" ( %04x  %04x   %02x    %02x   %04x )\n",
>+          FitEntryPort->IndexPort,
>+          FitEntryPort->DataPort,
>+          FitEntryPort->Width,
>+          FitEntryPort->Bit,
>+          FitEntryPort->Index
>+          );
>+        break;
>+      }
>+      // Not Port Configure, pass through
>+    default:
>+      printf ("\n");
>+      break;
>+    }
>+  }
>+  printf ("====== ================ ====== ======== ==============
>==== ======== (====== ==== ====== ==== ======)\n");
>+  printf ("Index:      Address      Size  Version       Type      C_V  Checksum (Index
>Data Width  Bit  Offset)\n");
>+  printf ("====== ================ ====== ======== ==============
>==== ======== (====== ==== ====== ==== ======)\n");
>+}
>+
>+/**
>+
>+  This function dump raw data.
>+
>+  @param  Data  raw data
>+  @param  Size  raw data size
>+
>+**/
>+VOID
>+DumpData (
>+  IN UINT8  *Data,
>+  IN UINT32 Size
>+  )
>+{
>+  UINT32 Index;
>+  for (Index = 0; Index < Size; Index++) {
>+    printf ("%02x", Data[Index]);
>+  }
>+}
>+
>+/**
>+
>+  This function dump raw data with colume format.
>+
>+  @param  Data  raw data
>+  @param  Size  raw data size
>+
>+**/
>+VOID
>+DumpHex (
>+  IN UINT8  *Data,
>+  IN UINT32 Size
>+  )
>+{
>+  UINT32  Index;
>+  UINT32  Count;
>+  UINT32  Left;
>+
>+#define COLUME_SIZE  (16 * 2)
>+
>+  Count = Size / COLUME_SIZE;
>+  Left  = Size % COLUME_SIZE;
>+  for (Index = 0; Index < Count; Index++) {
>+    printf ("%04x: ", Index * COLUME_SIZE);
>+    DumpData (Data + Index * COLUME_SIZE, COLUME_SIZE);
>+    printf ("\n");
>+  }
>+
>+  if (Left != 0) {
>+    printf ("%04x: ", Index * COLUME_SIZE);
>+    DumpData (Data + Index * COLUME_SIZE, Left);
>+    printf ("\n");
>+  }
>+}
>+
>+//
>+// This table defines the ACM type string
>+//
>+CHAR8 *mAcmTypeStr[] = {
>+  "BIOS ACM",
>+  "SINIT ACM",
>+};
>+
>+//
>+// This table defines the ACM capability string
>+//
>+CHAR8 *mCapabilityStr[] = {
>+  "GETSEC[WAKEUP] for RLP   ",
>+  "MONITOR address for RLP  ",
>+  "ECX for MLE PageTable    ",
>+  "STM support              ",
>+};
>+
>+VOID
>+DumpAcm (
>+  IN ACM_FORMAT                    *Acm
>+  )
>+/*++
>+
>+Routine Description:
>+
>+  DumpAcm information
>+
>+Arguments:
>+
>+  Acm       - ACM buffer
>+
>+Returns:
>+
>+  None
>+
>+--*/
>+{
>+  CHIPSET_ACM_INFORMATION_TABLE *ChipsetAcmInformationTable;
>+  CHIPSET_ID_LIST               *ChipsetIdList;
>+  PROCESSOR_ID_LIST             *ProcessorIdList;
>+  UINT32                        Index;
>+  UINT8                         *Buffer;
>+
>+  printf (
>+
>"**********************************************************
>*******************\n"
>+    "*         ACM                                                               *\n"
>+
>"**********************************************************
>*******************\n"
>+    );
>+
>+  printf ("ACM: (%08x)\n", (UINT32) (UINTN) Acm);
>+  printf ("  ModuleType                 - %04x\n", Acm->ModuleType);
>+  if (Acm->ModuleType == ACM_MODULE_TYPE_CHIPSET_ACM) {
>+    printf ("    Chipset ACM\n");
>+  }
>+  printf ("  ModuleSubType              - %04x\n", Acm->ModuleSubType);
>+  if ((Acm->ModuleSubType &
>ACM_MODULE_SUBTYPE_CAPABLE_OF_EXECUTE_AT_RESET) != 0) {
>+    printf ("    Capable of be Executed at Reset\n");
>+  }
>+  if ((Acm->ModuleSubType & ACM_MODULE_SUBTYPE_ANC_MODULE) != 0)
>{
>+    printf ("    AnC Module\n");
>+  }
>+  printf ("  HeaderLen                  - %08x\n", Acm->HeaderLen);
>+  printf ("  HeaderVersion              - %08x\n", Acm->HeaderVersion);
>+  printf ("  ChipsetID                  - %04x\n", Acm->ChipsetID);
>+  printf ("  Flags                      - %04x\n", Acm->Flags);
>+  printf ("    PreProduction            - %04x\n", Acm->Flags &
>ACM_MODULE_FLAG_PREPRODUCTION);
>+  printf ("    Debug Signed             - %04x\n", Acm->Flags &
>ACM_MODULE_FLAG_DEBUG_SIGN);
>+  printf ("  ModuleVendor               - %08x\n", Acm->ModuleVendor);
>+  printf ("  Date                       - %08x\n", Acm->Date);
>+  printf ("  Size                       - %08x\n", Acm->Size);
>+  printf ("  TxtSvn                     - %04x\n", Acm->TxtSvn);
>+  printf ("  SeSvn                      - %04x\n", Acm->SeSvn);
>+  printf ("  CodeControl                - %08x\n", Acm->CodeControl);
>+  printf ("  ErrorEntryPoint            - %08x\n", Acm->ErrorEntryPoint);
>+  printf ("  GDTLimit                   - %08x\n", Acm->GDTLimit);
>+  printf ("  GDTBasePtr                 - %08x\n", Acm->GDTBasePtr);
>+  printf ("  SegSel                     - %08x\n", Acm->SegSel);
>+  printf ("  EntryPoint                 - %08x\n", Acm->EntryPoint);
>+  printf ("  KeySize                    - %08x\n", Acm->KeySize);
>+  printf ("  ScratchSize                - %08x\n", Acm->ScratchSize);
>+
>+  Buffer = (UINT8 *)(Acm + 1);
>+  printf ("  RSAPubKey                  - \n");
>+  DumpHex (Buffer, Acm->KeySize * 4);
>+  printf ("\n");
>+  Buffer += Acm->KeySize * 4;
>+
>+  if (Acm->HeaderVersion == ACM_HEADER_VERSION_3) {
>+    printf ("  RSASig                     - \n");
>+    DumpHex (Buffer, ACM_PKCS_1_5_RSA_SIGNATURE_SHA384_SIZE); //
>PKCS #1.5 RSA Signature
>+    printf ("\n");
>+    Buffer += ACM_PKCS_1_5_RSA_SIGNATURE_SHA384_SIZE;
>+  } else {
>+    printf ("  RSAPubExp                  - %08x\n", *(UINT32 *)Buffer);
>+    Buffer += 4;
>+
>+    printf ("  RSASig                     - \n");
>+    DumpHex (Buffer, ACM_PKCS_1_5_RSA_SIGNATURE_SHA256_SIZE); //
>PKCS #1.5 RSA Signature
>+    printf ("\n");
>+    Buffer += ACM_PKCS_1_5_RSA_SIGNATURE_SHA256_SIZE;
>+  }
>+  Buffer += Acm->ScratchSize * 4;
>+
>+  if ((Acm->ModuleSubType & ACM_MODULE_SUBTYPE_ANC_MODULE) ==
>0) {
>+    ChipsetAcmInformationTable = (CHIPSET_ACM_INFORMATION_TABLE
>*)Buffer;
>+    printf ("Chipset ACM info:\n");
>+    printf (
>+      "  Guid                       - {%08x-%08x-%08x-%08x}\n",
>+      ChipsetAcmInformationTable->Guid.Guid0,
>+      ChipsetAcmInformationTable->Guid.Guid1,
>+      ChipsetAcmInformationTable->Guid.Guid2,
>+      ChipsetAcmInformationTable->Guid.Guid3
>+      );
>+    printf ("  ChipsetACMType             - %02x\n", ChipsetAcmInformationTable-
>>ChipsetACMType);
>+    if (ChipsetAcmInformationTable->ChipsetACMType <
>sizeof(mAcmTypeStr)/sizeof(mAcmTypeStr[0])) {
>+      printf ("    %s\n", mAcmTypeStr[ChipsetAcmInformationTable-
>>ChipsetACMType]);
>+    }
>+    printf ("  Version                    - %02x\n", ChipsetAcmInformationTable-
>>Version);
>+    printf ("  Length                     - %04x\n", ChipsetAcmInformationTable-
>>Length);
>+    printf ("  ChipsetIDList              - %08x\n", ChipsetAcmInformationTable-
>>ChipsetIDList);
>+    printf ("  OsSinitTableVer            - %08x\n", ChipsetAcmInformationTable-
>>OsSinitTableVer);
>+    printf ("  MinMleHeaderVer            - %08x\n", ChipsetAcmInformationTable-
>>MinMleHeaderVer);
>+    if (ChipsetAcmInformationTable->Version >=
>CHIPSET_ACM_INFORMATION_TABLE_VERSION_3) {
>+      printf ("  Capabilities               - %08x\n", ChipsetAcmInformationTable-
>>Capabilities);
>+      for (Index = 0; Index < sizeof(mCapabilityStr)/sizeof(mCapabilityStr[0]);
>Index++) {
>+        if (mCapabilityStr[Index] == NULL) {
>+          continue;
>+        }
>+        printf (
>+          "    %s- %08x\n",
>+          mCapabilityStr[Index],
>+          (ChipsetAcmInformationTable->Capabilities & (1 << Index))
>+          );
>+      }
>+      printf ("  AcmVersion                 - %02x\n", ChipsetAcmInformationTable-
>>AcmVersion);
>+      printf ("  AcmRevision                - %02x.%02x.%02x\n",
>ChipsetAcmInformationTable->AcmRevision[0],
>ChipsetAcmInformationTable->AcmRevision[1],
>ChipsetAcmInformationTable->AcmRevision[2]);
>+    }
>+    if (ChipsetAcmInformationTable->Version >=
>CHIPSET_ACM_INFORMATION_TABLE_VERSION_4) {
>+      printf ("  ProcessorIDList            - %08x\n", ChipsetAcmInformationTable-
>>ProcessorIDList);
>+    }
>+
>+    ChipsetIdList = (CHIPSET_ID_LIST *)((UINTN)Acm +
>ChipsetAcmInformationTable->ChipsetIDList);
>+    printf ("Chipset ID List info:\n");
>+    printf ("  Count                      - %08x\n", ChipsetIdList->Count);
>+    for (Index = 0; Index < ChipsetIdList->Count; Index++) {
>+      printf ("  ID[%d]:\n", Index);
>+      printf ("    Flags                    - %08x\n", ChipsetIdList-
>>ChipsetID[Index].Flags);
>+      printf ("      RevisionIdMask         - %08x\n", ChipsetIdList-
>>ChipsetID[Index].Flags & ACM_CHIPSET_ID_REVISION_ID_MAKE);
>+      printf ("    VendorID                 - %04x\n", ChipsetIdList-
>>ChipsetID[Index].VendorID);
>+      printf ("    DeviceID                 - %04x\n", ChipsetIdList-
>>ChipsetID[Index].DeviceID);
>+      printf ("    RevisionID               - %04x\n", ChipsetIdList-
>>ChipsetID[Index].RevisionID);
>+    }
>+    if (ChipsetAcmInformationTable->Version <
>CHIPSET_ACM_INFORMATION_TABLE_VERSION_4) {
>+      goto End;
>+    }
>+    ProcessorIdList = (PROCESSOR_ID_LIST *)((UINTN)Acm +
>ChipsetAcmInformationTable->ProcessorIDList);
>+    printf ("Processor ID List info:\n");
>+    printf ("  Count                      - %08x\n", ProcessorIdList->Count);
>+    for (Index = 0; Index < ProcessorIdList->Count; Index++) {
>+      printf ("  ID[%d]:\n", Index);
>+      printf ("    FMS                      - %08x\n", ProcessorIdList-
>>ProcessorID[Index].FMS);
>+      printf ("    FMSMask                  - %08x\n", ProcessorIdList-
>>ProcessorID[Index].FMSMask);
>+      printf ("    PlatformID               - %016llx\n", (unsigned long long)
>ProcessorIdList->ProcessorID[Index].PlatformID);
>+      printf ("    PlatformMask             - %016llx\n", (unsigned long long)
>ProcessorIdList->ProcessorID[Index].PlatformMask);
>+    }
>+  }
>+
>+End:
>+  printf (
>+
>"**********************************************************
>*******************\n\n"
>+    );
>+}
>+
>+BOOLEAN
>+CheckAcm (
>+  IN ACM_FORMAT                        *Acm,
>+  IN UINTN                             AcmMaxSize
>+  )
>+/*++
>+
>+Routine Description:
>+
>+  Check Acm information
>+
>+Arguments:
>+
>+  Acm        - ACM buffer
>+  AcmMaxSize - ACM max size
>+
>+Returns:
>+
>+  TRUE  - ACM is valid
>+  FALSE - ACM is invalid
>+
>+--*/
>+{
>+  CHIPSET_ACM_INFORMATION_TABLE *ChipsetAcmInformationTable;
>+  CHIPSET_ID_LIST               *ChipsetIdList;
>+  PROCESSOR_ID_LIST             *ProcessorIdList;
>+  UINT8                         *Buffer;
>+
>+  if (Acm->ModuleType != ACM_MODULE_TYPE_CHIPSET_ACM) {
>+    printf ("ACM invalid : ModuleType!\n");
>+    return FALSE;
>+  }
>+  if (Acm->Size * 4 > AcmMaxSize) {
>+    printf ("ACM invalid : Size!\n");
>+    return FALSE;
>+  }
>+
>+  Buffer = (UINT8 *)(Acm + 1);
>+  Buffer += Acm->KeySize * 4;
>+  if (Acm->HeaderVersion == ACM_HEADER_VERSION_3) {
>+    Buffer += ACM_PKCS_1_5_RSA_SIGNATURE_SHA384_SIZE;
>+  } else {
>+    Buffer += 4;
>+    Buffer += ACM_PKCS_1_5_RSA_SIGNATURE_SHA256_SIZE;
>+  }
>+  Buffer += Acm->ScratchSize * 4;
>+
>+  if ((Acm->ModuleSubType & ACM_MODULE_SUBTYPE_ANC_MODULE) ==
>0) {
>+    ChipsetAcmInformationTable = (CHIPSET_ACM_INFORMATION_TABLE
>*)Buffer;
>+    if ((UINTN)ChipsetAcmInformationTable >= (UINTN)Acm + AcmMaxSize) {
>+      printf ("ACM invalid : ChipsetAcmInformationTable!\n");
>+      return FALSE;
>+    }
>+
>+    if (CompareGuid ((EFI_GUID *)&ChipsetAcmInformationTable->Guid,
>(EFI_GUID *)&mChipsetAcmInformationTableGuid03) != 0) {
>+      printf ("ACM invalid : ChipsetACMGuid!\n");
>+      return FALSE;
>+    }
>+    if (ChipsetAcmInformationTable->ChipsetACMType !=
>CHIPSET_ACM_TYPE_BIOS) {
>+      printf ("ACM invalid : ChipsetACMType!\n");
>+      return FALSE;
>+    }
>+    if (ChipsetAcmInformationTable->Version <
>CHIPSET_ACM_INFORMATION_TABLE_VERSION_3) {
>+      printf ("ACM invalid : ChipsetACMVersion!\n");
>+      return FALSE;
>+    }
>+    if ((UINTN)ChipsetAcmInformationTable + ChipsetAcmInformationTable-
>>Length > (UINTN)Acm + AcmMaxSize) {
>+      printf ("ACM invalid : ChipsetACMLength!\n");
>+      return FALSE;
>+    }
>+
>+    if (ChipsetAcmInformationTable->ChipsetIDList >= AcmMaxSize) {
>+      printf ("ACM invalid : ChipsetACMChipsetIDList!\n");
>+      return FALSE;
>+    }
>+    ChipsetIdList = (CHIPSET_ID_LIST *)((UINTN)Acm +
>ChipsetAcmInformationTable->ChipsetIDList);
>+    if (ChipsetIdList->Count == 0) {
>+      printf ("ACM invalid : ChipsetACMChipsetIDListCount!\n");
>+      return FALSE;
>+    }
>+    if (ChipsetAcmInformationTable->ChipsetIDList + sizeof(CHIPSET_ID_LIST)
>+ (ChipsetIdList->Count - 1) * sizeof(ACM_CHIPSET_ID) > AcmMaxSize) {
>+      printf ("ACM invalid : ChipsetACMChipsetIDList!\n");
>+      return FALSE;
>+    }
>+
>+    if (ChipsetAcmInformationTable->Version <
>CHIPSET_ACM_INFORMATION_TABLE_VERSION_4) {
>+      goto End;
>+    }
>+
>+    if (ChipsetAcmInformationTable->ProcessorIDList >= AcmMaxSize) {
>+      printf ("ACM invalid : ChipsetACMProcessorIDList!\n");
>+      return FALSE;
>+    }
>+    ProcessorIdList = (PROCESSOR_ID_LIST *)((UINTN)Acm +
>ChipsetAcmInformationTable->ProcessorIDList);
>+    if (ProcessorIdList->Count == 0) {
>+      printf ("ACM invalid : ChipsetACMProcessorIdListCount!\n");
>+      return FALSE;
>+    }
>+    if (ChipsetAcmInformationTable->ChipsetIDList +
>sizeof(PROCESSOR_ID_LIST) + (ChipsetIdList->Count - 1) *
>sizeof(ACM_PROCESSOR_ID) > AcmMaxSize) {
>+      printf ("ACM invalid : ChipsetACMProcessorIdList!\n");
>+      return FALSE;
>+    }
>+  }
>+
>+End:
>+
>+  return TRUE;
>+}
>+
>+VOID
>+FillFitTable (
>+  IN UINT8     *FvBuffer,
>+  IN UINT32    FvSize,
>+  IN UINT8     *FitTableOffset
>+  )
>+/*++
>+
>+Routine Description:
>+
>+  Fill the FIT table information to FvRecovery
>+
>+Arguments:
>+
>+  FvBuffer       - FvRecovery binary buffer
>+  FvSize         - FvRecovery size
>+  FitTableOffset - The offset of FIT table in FvRecovery file
>+
>+Returns:
>+
>+  None
>+
>+--*/
>+{
>+  FIRMWARE_INTERFACE_TABLE_ENTRY *FitEntry;
>+  UINT32                          FitIndex;
>+  UINT32                          Index;
>+  UINT8                           Checksum;
>+  UINTN                           SubIndex;
>+  FIT_TABLE_CONTEXT_ENTRY         TempContextEntry;
>+  FIRMWARE_INTERFACE_TABLE_ENTRY  TempTableEntry;
>+
>+  //
>+  // 1. FitPointer
>+  //
>+  *(UINT64 *)(FvBuffer + FvSize - gFitTableContext.FitTablePointerOffset) =
>(UINT64)(UINTN)MEMORY_TO_FLASH (FitTableOffset, FvBuffer, FvSize);
>+  if (gFitTableContext.FitTablePointerOffset2 != 0) {
>+    *(UINT64 *)(FvBuffer + FvSize - gFitTableContext.FitTablePointerOffset2)
>= (UINT64)(UINTN)MEMORY_TO_FLASH (FitTableOffset, FvBuffer, FvSize);
>+  }
>+
>+  FitEntry = (FIRMWARE_INTERFACE_TABLE_ENTRY *)FitTableOffset;
>+  FitIndex = 0;
>+
>+  //
>+  // 2. FitHeader
>+  //
>+  FitEntry[FitIndex].Address             = *(UINT64 *)"_FIT_   ";
>+  *(UINT32 *)&FitEntry[FitIndex].Size[0] = gFitTableContext.FitEntryNumber;
>+  FitEntry[FitIndex].Version             =
>(UINT16)gFitTableContext.FitHeaderVersion;
>+  FitEntry[FitIndex].Type                = FIT_TABLE_TYPE_HEADER;
>+  FitEntry[FitIndex].C_V                 = 1;
>+  //
>+  // Checksum will be updated later...
>+  //
>+  FitEntry[FitIndex].Checksum            = 0;
>+
>+  //
>+  // 3. Microcode
>+  //
>+  FitIndex++;
>+  for (Index = 0; Index < gFitTableContext.MicrocodeNumber; Index++) {
>+    FitEntry[FitIndex].Address             =
>gFitTableContext.Microcode[Index].Address;
>+    *(UINT32 *)&FitEntry[FitIndex].Size[0] = 0;
>//gFitTableContext.Microcode[Index].Size / 16;
>+    FitEntry[FitIndex].Version             =
>(UINT16)gFitTableContext.MicrocodeVersion;
>+    FitEntry[FitIndex].Type                = FIT_TABLE_TYPE_MICROCODE;
>+    FitEntry[FitIndex].C_V                 = 0;
>+    FitEntry[FitIndex].Checksum            = 0;
>+    FitIndex++;
>+  }
>+
>+  //
>+  // 4. StartupAcm
>+  //
>+  if (gFitTableContext.StartupAcm.Address != 0) {
>+    FitEntry[FitIndex].Address             = gFitTableContext.StartupAcm.Address;
>+    *(UINT32 *)&FitEntry[FitIndex].Size[0] = 0;
>//gFitTableContext.StartupAcm.Size / 16;
>+    FitEntry[FitIndex].Version             =
>(UINT16)gFitTableContext.StartupAcmVersion;
>+    FitEntry[FitIndex].Type                = FIT_TABLE_TYPE_STARTUP_ACM;
>+    FitEntry[FitIndex].C_V                 = 0;
>+    FitEntry[FitIndex].Checksum            = 0;
>+    FitIndex++;
>+  }
>+
>+  //
>+  // 5. BiosModule
>+  //
>+  //
>+  // BiosModule segments order needs to be put from low addresss to high
>for Btg requirement
>+  //
>+  if (gFitTableContext.BiosModuleNumber > 1) {
>+    for (Index = 0; Index < (UINTN)gFitTableContext.BiosModuleNumber - 1;
>Index++){
>+      for (SubIndex = 0; SubIndex < gFitTableContext.BiosModuleNumber -
>Index - 1; SubIndex++) {
>+        if (gFitTableContext.BiosModule[SubIndex].Address >
>gFitTableContext.BiosModule[SubIndex + 1].Address) {
>+          CopyMem (&TempContextEntry,
>&gFitTableContext.BiosModule[SubIndex],
>sizeof(FIT_TABLE_CONTEXT_ENTRY));
>+          CopyMem (&gFitTableContext.BiosModule[SubIndex],
>&gFitTableContext.BiosModule[SubIndex + 1],
>sizeof(FIT_TABLE_CONTEXT_ENTRY));
>+          CopyMem (&gFitTableContext.BiosModule[SubIndex + 1],
>&TempContextEntry, sizeof(FIT_TABLE_CONTEXT_ENTRY));
>+        }
>+      }
>+    }
>+  }
>+  for (Index = 0; Index < gFitTableContext.BiosModuleNumber; Index++) {
>+    FitEntry[FitIndex].Address             =
>gFitTableContext.BiosModule[Index].Address;
>+    *(UINT32 *)&FitEntry[FitIndex].Size[0] =
>gFitTableContext.BiosModule[Index].Size / 16;
>+    FitEntry[FitIndex].Version             =
>(UINT16)gFitTableContext.BiosModuleVersion;
>+    FitEntry[FitIndex].Type                = FIT_TABLE_TYPE_BIOS_MODULE;
>+    FitEntry[FitIndex].C_V                 = 0;
>+    FitEntry[FitIndex].Checksum            = 0;
>+    FitIndex++;
>+  }
>+
>+  //
>+  // 6. Optional module
>+  //
>+  for (Index = 0; Index < gFitTableContext.OptionalModuleNumber; Index++)
>{
>+    FitEntry[FitIndex].Address             =
>gFitTableContext.OptionalModule[Index].Address;
>+    *(UINT32 *)&FitEntry[FitIndex].Size[0] =
>gFitTableContext.OptionalModule[Index].Size;
>+    FitEntry[FitIndex].Version             =
>(UINT16)gFitTableContext.OptionalModule[Index].Version;
>+    FitEntry[FitIndex].Type                =
>(UINT8)gFitTableContext.OptionalModule[Index].Type;
>+    FitEntry[FitIndex].C_V                 = 0;
>+    FitEntry[FitIndex].Checksum            = 0;
>+    FitIndex++;
>+  }
>+
>+  //
>+  // 7. Port module
>+  //
>+  for (Index = 0; Index < gFitTableContext.PortModuleNumber; Index++) {
>+    FitEntry[FitIndex].Address             =
>gFitTableContext.PortModule[Index].Address +
>((UINT64)gFitTableContext.PortModule[Index].Size << 32);
>+    *(UINT32 *)&FitEntry[FitIndex].Size[0] = 0;
>+    FitEntry[FitIndex].Version             =
>(UINT16)gFitTableContext.PortModule[Index].Version;
>+    FitEntry[FitIndex].Type                =
>(UINT8)gFitTableContext.PortModule[Index].Type;
>+    FitEntry[FitIndex].C_V                 = 0;
>+    FitEntry[FitIndex].Checksum            = 0;
>+    FitIndex++;
>+  }
>+
>+  //
>+  // The FIT records must always be arranged in the ascending order of their
>type attribute in the FIT.
>+  //
>+  for (Index = 0; Index < (UINTN)FitIndex - 1; Index++){
>+    for (SubIndex = 0; SubIndex < FitIndex - Index - 1; SubIndex++) {
>+      if (FitEntry[SubIndex].Type > FitEntry[SubIndex + 1].Type) {
>+        CopyMem (&TempTableEntry, &FitEntry[SubIndex],
>sizeof(FIRMWARE_INTERFACE_TABLE_ENTRY));
>+        CopyMem (&FitEntry[SubIndex], &FitEntry[SubIndex + 1],
>sizeof(FIRMWARE_INTERFACE_TABLE_ENTRY));
>+        CopyMem (&FitEntry[SubIndex + 1], &TempTableEntry,
>sizeof(FIRMWARE_INTERFACE_TABLE_ENTRY));
>+      }
>+    }
>+  }
>+
>+  //
>+  // Update FIT header signature as final step
>+  //
>+  Checksum = CalculateChecksum8 ((UINT8 *)&FitEntry[0], sizeof
>(FIRMWARE_INTERFACE_TABLE_ENTRY) * FitIndex);
>+  FitEntry[0].Checksum = Checksum;
>+}
>+
>+VOID
>+ClearFitTable (
>+  IN UINT8     *FvBuffer,
>+  IN UINT32    FvSize
>+  )
>+/*++
>+
>+Routine Description:
>+
>+  Clear the FIT table information to Fvrecovery
>+
>+Arguments:
>+
>+  FvBuffer       - Fvrecovery binary buffer
>+  FvSize         - Fvrecovery size
>+
>+Returns:
>+
>+  None
>+
>+--*/
>+{
>+  FIRMWARE_INTERFACE_TABLE_ENTRY *FitEntry;
>+  UINT32                          EntryNum;
>+  UINT32                          FitIndex;
>+  UINT64                          FitTablePointer;
>+  UINT8                           *Buffer;
>+  UINT32                          BufferSize;
>+
>+  FitTablePointer = *(UINT64 *)(FvBuffer + FvSize -
>gFitTableContext.FitTablePointerOffset);
>+  FitEntry = (FIRMWARE_INTERFACE_TABLE_ENTRY *)FLASH_TO_MEMORY
>(FitTablePointer, FvBuffer, FvSize);
>+
>+  //
>+  // Clear FIT pointer
>+  //
>+  *(UINT64 *)(FvBuffer + FvSize - gFitTableContext.FitTablePointerOffset) =
>0xEEEEEEEEEEEEEEEEull;
>+  if (gFitTableContext.FitTablePointerOffset2 != 0) {
>+    *(UINT64 *)(FvBuffer + FvSize - gFitTableContext.FitTablePointerOffset2)
>= 0xEEEEEEEEEEEEEEEEull;
>+  }
>+
>+  //
>+  // Clear FIT table
>+  //
>+  EntryNum = *(UINT32 *)(&FitEntry[0].Size[0]) & 0xFFFFFF;
>+  for (FitIndex = 0; FitIndex < EntryNum; FitIndex++) {
>+    switch (FitEntry[FitIndex].Type) {
>+    case FIT_TABLE_TYPE_BIOS_POLICY:
>+    case FIT_TABLE_TYPE_KEY_MANIFEST:
>+    case FIT_TABLE_TYPE_BOOT_POLICY_MANIFEST:
>+    case FIT_TABLE_TYPE_BIOS_DATA_AREA:
>+    case FIT_TABLE_TYPE_CSE_SECURE_BOOT:
>+      //
>+      // Clear FIT table data buffer
>+      //
>+      Buffer = FLASH_TO_MEMORY (FitEntry[FitIndex].Address, FvBuffer,
>FvSize);
>+      BufferSize = (*(UINT32 *)FitEntry[FitIndex].Size) & 0xFFFFFF;
>+      SetMem (Buffer, BufferSize, 0xFF);
>+      break;
>+    default:
>+      break;
>+    }
>+    //
>+    // Clear FIT table itself
>+    //
>+    SetMem (&FitEntry[FitIndex], sizeof(FitEntry[FitIndex]), 0xFF);
>+  }
>+}
>+
>+STATUS
>+WriteOutputFile (
>+  IN CHAR8   *FileName,
>+  IN UINT8   *FileData,
>+  IN UINT32  FileSize
>+  )
>+/*++
>+
>+Routine Description:
>+
>+  Read input file
>+
>+Arguments:
>+
>+  FileName      - The input file name
>+  FileData      - The input file data
>+  FileSize      - The input file size
>+
>+Returns:
>+
>+  STATUS_SUCCESS - Write file data successfully
>+  STATUS_ERROR   - The file data is not written
>+
>+--*/
>+{
>+  FILE                        *FpOut;
>+
>+  //
>+  // Open the output FvRecovery.fv file
>+  //
>+  if ((FpOut = fopen (FileName, "w+b")) == NULL) {
>+    Error (NULL, 0, 0, "Unable to open file", "%s", FileName);
>+    return STATUS_ERROR;
>+  }
>+  //
>+  // Write the output FvRecovery.fv file
>+  //
>+  if ((fwrite (FileData, 1, FileSize, FpOut)) != FileSize) {
>+    Error (NULL, 0, 0, "Write output file error!", NULL);
>+    fclose (FpOut);
>+    return STATUS_ERROR;
>+  }
>+
>+  //
>+  // Close the output FvRecovery.fv file
>+  //
>+  fclose (FpOut);
>+
>+  return STATUS_SUCCESS;
>+}
>+
>+UINT32
>+GetFvRecoveryInfoFromFd (
>+  IN UINT8                       *FdBuffer,
>+  IN UINT32                      FdFileSize,
>+  OUT UINT8                      **FvRecovery
>+  )
>+/*++
>+
>+Routine Description:
>+
>+  Get FvRecovery information from Fd file.
>+
>+Arguments:
>+
>+  FdBuffer     - Fd file buffer.
>+  FdFileSize   - Fd file size.
>+  FvRecovery   - FvRecovery pointer in Fd file buffer
>+
>+Returns:
>+  FvRecovery file size
>+
>+--*/
>+{
>+  UINT8                         *FileBuffer = NULL;
>+  UINT32                        FvRecoveryFileSize =0;
>+  EFI_GUID                      VTFGuid = EFI_FFS_VOLUME_TOP_FILE_GUID;
>+  UINT32                        FvLength;
>+  UINT32                        FileLength;
>+
>+  *FvRecovery = NULL;
>+  FileBuffer = FindNextFvHeader (FdBuffer, FdFileSize);
>+  if (FileBuffer == NULL) {
>+    return 0;
>+  }
>+
>+  while ((UINTN)FileBuffer < (UINTN)FdBuffer + FdFileSize) {
>+    FvLength         = (UINT32)((EFI_FIRMWARE_VOLUME_HEADER
>*)FileBuffer)->FvLength;
>+
>+    if (FindFileFromFvByGuid (FileBuffer, FvLength, &VTFGuid, &FileLength) !=
>NULL) {
>+      //
>+      // Found the VTF
>+      //
>+      FvRecoveryFileSize = FvLength;
>+      *FvRecovery = FileBuffer;
>+    }
>+
>+    //
>+    // Next fv
>+    //
>+    FileBuffer = (UINT8 *)FileBuffer + FvLength;
>+    if ((UINTN)FileBuffer >= (UINTN)FdBuffer + FdFileSize) {
>+      break;
>+    }
>+    FileBuffer = FindNextFvHeader (FileBuffer, (UINTN)FdBuffer + FdFileSize -
>(UINTN)FileBuffer);
>+    if (FileBuffer == NULL) {
>+      break;
>+    }
>+
>+  }
>+
>+  //
>+  // Return
>+  //
>+  return FvRecoveryFileSize;
>+}
>+
>+UINT32
>+GetFitEntryInfo (
>+  IN UINT8     *FvBuffer,
>+  IN UINT32    FvSize
>+  )
>+/*++
>+
>+Routine Description:
>+
>+  Fill the FIT table information to Fvrecovery
>+
>+Arguments:
>+
>+  FvBuffer       - Fvrecovery binary buffer
>+  FvSize         - Fvrecovery size
>+
>+Returns:
>+
>+  0 - Fit Table not found
>+
>+--*/
>+{
>+  FIRMWARE_INTERFACE_TABLE_ENTRY *FitEntry;
>+  UINT32                          FitIndex;
>+  UINT32                          FitTableOffset;
>+
>+  //
>+  // 1. FitPointer
>+  //
>+  if (gFitTableContext.FitTablePointerOffset == 0) {
>+    gFitTableContext.FitTablePointerOffset =
>DEFAULT_FIT_TABLE_POINTER_OFFSET;
>+  }
>+  gFitTableContext.FitTablePointerOffset2 = 0;
>+
>+  FitTableOffset = *(UINT32 *)(FvBuffer + FvSize -
>gFitTableContext.FitTablePointerOffset);
>+
>+  FitEntry = (FIRMWARE_INTERFACE_TABLE_ENTRY
>*)FLASH_TO_MEMORY(FitTableOffset, FvBuffer, FvSize);
>+  FitIndex = 0;
>+
>+  //
>+  // 2. FitHeader
>+  //
>+  if (FitEntry[FitIndex].Address != *(UINT64 *)"_FIT_   ") {
>+    return 0;
>+  }
>+  if (FitEntry[FitIndex].Type != FIT_TABLE_TYPE_HEADER) {
>+    return 0;
>+  }
>+  gFitTableContext.FitEntryNumber = *(UINT32 *)&FitEntry[FitIndex].Size[0];
>+  gFitTableContext.FitHeaderVersion = FitEntry[FitIndex].Version;
>+
>+  //
>+  // 3. FitEntry
>+  //
>+  FitIndex++;
>+  for (; FitIndex < gFitTableContext.FitEntryNumber; FitIndex++) {
>+    switch (FitEntry[FitIndex].Type) {
>+    case FIT_TABLE_TYPE_MICROCODE:
>+
>gFitTableContext.Microcode[gFitTableContext.MicrocodeNumber].Address =
>(UINT32)FitEntry[FitIndex].Address;
>+      gFitTableContext.MicrocodeVersion                                    =
>FitEntry[FitIndex].Version;
>+      gFitTableContext.MicrocodeNumber ++;
>+      break;
>+    case FIT_TABLE_TYPE_STARTUP_ACM:
>+      gFitTableContext.StartupAcm.Address =
>(UINT32)FitEntry[FitIndex].Address;
>+      gFitTableContext.StartupAcmVersion  = FitEntry[FitIndex].Version;
>+      break;
>+    case FIT_TABLE_TYPE_BIOS_MODULE:
>+
>gFitTableContext.BiosModule[gFitTableContext.BiosModuleNumber].Addres
>s = (UINT32)FitEntry[FitIndex].Address;
>+
>gFitTableContext.BiosModule[gFitTableContext.BiosModuleNumber].Size    =
>*(UINT32 *)&FitEntry[FitIndex].Size[0] * 16;
>+      gFitTableContext.BiosModuleVersion                                     =
>FitEntry[FitIndex].Version;
>+      gFitTableContext.BiosModuleNumber ++;
>+      break;
>+    case FIT_TABLE_TYPE_TPM_POLICY:
>+    case FIT_TABLE_TYPE_TXT_POLICY:
>+      if (FitEntry[FitIndex].Version == 0) {
>+
>gFitTableContext.PortModule[gFitTableContext.PortModuleNumber].Addres
>s = (UINT32)FitEntry[FitIndex].Address;
>+
>gFitTableContext.PortModule[gFitTableContext.PortModuleNumber].Size    =
>(UINT32)(FitEntry[FitIndex].Address >> 32);
>+
>gFitTableContext.PortModule[gFitTableContext.PortModuleNumber].Version
>= FitEntry[FitIndex].Version;
>+
>gFitTableContext.PortModule[gFitTableContext.PortModuleNumber].Type
>= FitEntry[FitIndex].Type;
>+        gFitTableContext.PortModuleNumber ++;
>+        break;
>+      }
>+      // Not Port Configure, pass through
>+    default: // Others
>+
>gFitTableContext.OptionalModule[gFitTableContext.OptionalModuleNumber
>].Address = (UINT32)FitEntry[FitIndex].Address;
>+
>gFitTableContext.OptionalModule[gFitTableContext.OptionalModuleNumber
>].Size    = *(UINT32 *)&FitEntry[FitIndex].Size[0];
>+
>gFitTableContext.OptionalModule[gFitTableContext.OptionalModuleNumber
>].Version = FitEntry[FitIndex].Version;
>+
>gFitTableContext.OptionalModule[gFitTableContext.OptionalModuleNumber
>].Type    = FitEntry[FitIndex].Type;
>+      gFitTableContext.OptionalModuleNumber ++;
>+      break;
>+    }
>+  }
>+
>+  return gFitTableContext.FitEntryNumber;
>+}
>+
>+STATUS
>+FitGen (
>+  IN INTN   argc,
>+  IN CHAR8  **argv
>+  )
>+/*++
>+
>+Routine Description:
>+
>+  Main function for FitGen.
>+
>+Arguments:
>+
>+  argc - Number of command line parameters.
>+  argv - Array of pointers to parameter strings.
>+
>+Returns:
>+  STATUS_SUCCESS - Utility exits successfully.
>+  STATUS_ERROR   - Some error occurred during execution.
>+
>+--*/
>+{
>+  UINT32                      FvRecoveryFileSize;
>+  UINT8                       *FileBuffer;
>+  UINT8                       *FileBufferRaw;
>+  UINTN                       FitEntryNumber;
>+  UINT8                       *FitTableOffset;
>+  STATUS                      Status;
>+  UINT32                      FitTableSize;
>+
>+  BOOLEAN                     IsFv;
>+  UINT8                       *FdFileBuffer;
>+  UINT32                      FdFileSize;
>+
>+  UINT8                       *AcmBuffer;
>+
>+  //
>+  // Step 0: Check FV or FD
>+  //
>+  if (((strcmp (argv[1], "-D") == 0) ||
>+       (strcmp (argv[1], "-d") == 0)) ) {
>+    IsFv = FALSE;
>+  } else {
>+    IsFv = TRUE;
>+  }
>+
>+  //
>+  // Step 1: Read InputFvRecovery.fv data
>+  //
>+  if (IsFv) {
>+    Status = ReadInputFile (argv[1], &FileBuffer, &FvRecoveryFileSize,
>&FileBufferRaw);
>+    if (Status != STATUS_SUCCESS) {
>+      Error (NULL, 0, 0, "Unable to open file", "%s", argv[1]);
>+      goto exitFunc;
>+    }
>+    FdFileBuffer = FileBuffer;
>+    FdFileSize = FvRecoveryFileSize;
>+  } else {
>+    Status = ReadInputFile (argv[2], &FdFileBuffer, &FdFileSize,
>&FileBufferRaw);
>+    if (Status != STATUS_SUCCESS) {
>+      Error (NULL, 0, 0, "Unable to open file", "%s", argv[2]);
>+      goto exitFunc;
>+    }
>+
>+    //
>+    // Get Fvrecovery information
>+    //
>+    FvRecoveryFileSize = GetFvRecoveryInfoFromFd (FdFileBuffer, FdFileSize,
>&FileBuffer);
>+    if ((FvRecoveryFileSize == 0) || (FileBuffer == NULL)) {
>+      Error (NULL, 0, 0, "FvRecovery not found in Fd file!", NULL);
>+      Status = STATUS_ERROR;
>+      goto exitFunc;
>+    }
>+  }
>+
>+  //
>+  // Step 2: Calculate FIT entry number.
>+  //
>+  FitEntryNumber = GetFitEntryNumber (argc, argv, FdFileBuffer, FdFileSize);
>+  if (!gFitTableContext.Clear) {
>+    if (FitEntryNumber == 0) {
>+      Status = STATUS_ERROR;
>+      goto exitFunc;
>+    }
>+
>+    //
>+    // For debug
>+    //
>+    PrintFitData ();
>+
>+    //
>+    // Add 1 more FitEntry as place holder, because we need exclude FIT table
>itself
>+    //
>+    FitEntryNumber++;
>+
>+    //
>+    // Step 3: Get enough space in FvRecovery.fv
>+    //
>+    FitTableOffset = GetFreeSpaceFromFv (FileBuffer, FvRecoveryFileSize,
>FitEntryNumber);
>+    if (FitTableOffset == NULL) {
>+      return STATUS_ERROR;
>+    }
>+    FitTableSize = FitEntryNumber *
>sizeof(FIRMWARE_INTERFACE_TABLE_ENTRY);
>+    FitTableSize += FIT_ALIGNMENT;
>+    FitTableSize &= ~FIT_ALIGNMENT;
>+
>+    CheckOverlap (
>+      MEMORY_TO_FLASH (FitTableOffset, FdFileBuffer, FdFileSize),
>+      FitTableSize
>+      );
>+
>+    //
>+    // Get ACM buffer
>+    //
>+    if (gFitTableContext.StartupAcm.Address != 0) {
>+      AcmBuffer = FLASH_TO_MEMORY(gFitTableContext.StartupAcm.Address,
>FdFileBuffer, FdFileSize);
>+      if ((AcmBuffer < FdFileBuffer) || (AcmBuffer +
>gFitTableContext.StartupAcm.Size > FdFileBuffer + FdFileSize)) {
>+        printf ("ACM out of range - can not validate it\n");
>+        AcmBuffer = NULL;
>+      }
>+
>+      if (AcmBuffer != NULL) {
>+        if (CheckAcm ((ACM_FORMAT *)AcmBuffer,
>gFitTableContext.StartupAcm.Size)) {
>+          DumpAcm ((ACM_FORMAT *)AcmBuffer);
>+        } else {
>+          Status = STATUS_ERROR;
>+          goto exitFunc;
>+        }
>+      }
>+
>+    }
>+
>+    //
>+    // Step 4: Fill the FIT table one by one
>+    //
>+    FillFitTable (FdFileBuffer, FdFileSize, FitTableOffset);
>+
>+    //
>+    // For debug
>+    //
>+    PrintFitTable (FdFileBuffer, FdFileSize);
>+  } else {
>+    printf ("Clear FIT table ...\n");
>+    //
>+    // Step 3: Get FIT table info
>+    //
>+    FitEntryNumber = GetFitEntryInfo (FdFileBuffer, FdFileSize);
>+    if (FitEntryNumber == 0) {
>+      Error (NULL, 0, 0, "No FIT table found", NULL);
>+      return STATUS_ERROR;
>+    }
>+
>+    //
>+    // For debug
>+    //
>+    PrintFitTable (FdFileBuffer, FdFileSize);
>+
>+    //
>+    // Step 4: Clear FIT table
>+    //
>+    ClearFitTable (FdFileBuffer, FdFileSize);
>+    printf ("Clear FIT table Done!\n");
>+  }
>+
>+  //
>+  // Step 5: Write OutputFvRecovery.fv data
>+  //
>+  if (IsFv) {
>+    Status = WriteOutputFile (argv[2], FileBuffer, FvRecoveryFileSize);
>+  } else {
>+    Status = WriteOutputFile (argv[3], FdFileBuffer, FdFileSize);
>+  }
>+
>+exitFunc:
>+  if (FileBufferRaw != NULL) {
>+    free ((VOID *)FileBufferRaw);
>+  }
>+  return Status;
>+}
>+
>+STATUS
>+FitView (
>+  IN INTN   argc,
>+  IN CHAR8  **argv
>+  )
>+/*++
>+
>+Routine Description:
>+
>+  View function for FitGen.
>+
>+Arguments:
>+
>+  argc - Number of command line parameters.
>+  argv - Array of pointers to parameter strings.
>+
>+Returns:
>+  STATUS_SUCCESS - Utility exits successfully.
>+  STATUS_ERROR   - Some error occurred during execution.
>+
>+--*/
>+{
>+  UINT32                      FvRecoveryFileSize;
>+  UINT8                       *FileBuffer;
>+  UINT8                       *FileBufferRaw = NULL;
>+  STATUS                      Status;
>+
>+  //
>+  // Step 1: Read input file
>+  //
>+  Status = ReadInputFile (argv[2], &FileBuffer, &FvRecoveryFileSize,
>&FileBufferRaw);
>+  if (Status != STATUS_SUCCESS) {
>+    Error (NULL, 0, 0, "Unable to open file", "%s", argv[2]);
>+    goto exitFunc;
>+  }
>+
>+  // no -f option, use default FIT pointer offset
>+  if (argc == 3) {
>+    //
>+    // Use default address
>+    //
>+    gFitTableContext.FitTablePointerOffset =
>DEFAULT_FIT_TABLE_POINTER_OFFSET;
>+  } else if (stricmp (argv[3], "-f") == 0) {
>+    if (argc == 5) {
>+      //
>+      // Get offset from parameter
>+      //
>+      gFitTableContext.FitTablePointerOffset = xtoi (argv[3 + 1]);
>+    } else {
>+      Error (NULL, 0, 0, "FIT offset not specified!", NULL);
>+      goto exitFunc;
>+    }
>+  } else {
>+    Error (NULL, 0, 0, "Invalid view option: ", "%s", argv[3]);
>+    goto exitFunc;
>+  }
>+
>+  //
>+  // For debug
>+  //
>+  PrintFitTable (FileBuffer, FvRecoveryFileSize);
>+
>+exitFunc:
>+  if (FileBufferRaw != NULL) {
>+    free ((VOID *)FileBufferRaw);
>+  }
>+  return Status;
>+}
>+
>+int
>+main (
>+  int   argc,
>+  char  **argv
>+  )
>+/*++
>+
>+Routine Description:
>+
>+  Main function.
>+
>+Arguments:
>+
>+  argc - Number of command line parameters.
>+  argv - Array of pointers to parameter strings.
>+
>+Returns:
>+  STATUS_SUCCESS - Utility exits successfully.
>+  STATUS_ERROR   - Some error occurred during execution.
>+
>+--*/
>+{
>+  SetUtilityName (UTILITY_NAME);
>+
>+  //
>+  // Display utility information
>+  //
>+  PrintUtilityInfo ();
>+
>+  //
>+  // Verify the correct number of arguments
>+  //
>+  if (argc >= MIN_VIEW_ARGS && stricmp (argv[1], "-view") == 0) {
>+    return FitView (argc, argv);
>+  } else if (argc >= MIN_ARGS) {
>+    return FitGen (argc, argv);
>+  } else {
>+    Error (NULL, 0, 0, "invalid number of input parameters specified", NULL);
>+    PrintUsage ();
>+    return STATUS_ERROR;
>+  }
>+}
>+
>+unsigned int
>+xtoi (
>+  char  *str
>+  )
>+/*++
>+
>+Routine Description:
>+
>+  Convert hex string to uint
>+
>+Arguments:
>+
>+  str  -  The string
>+
>+Returns:
>+
>+--*/
>+{
>+  unsigned int u;
>+  char         c;
>+  unsigned int m;
>+
>+  if (str == NULL) {
>+    return 0;
>+  }
>+
>+  m = (unsigned int) -1 >> 4;
>+  //
>+  // skip preceeding white space
>+  //
>+  while (*str && *str == ' ') {
>+    str += 1;
>+  }
>+  //
>+  // skip preceeding zeros
>+  //
>+  while (*str && *str == '0') {
>+    str += 1;
>+  }
>+  //
>+  // skip preceeding x/X character
>+  //
>+  if (*str && (*str == 'x' || *str == 'X')) {
>+    str += 1;
>+  }
>+  //
>+  // convert hex digits
>+  //
>+  u = 0;
>+  c = *(str++);
>+  while (c) {
>+    if (c >= 'a' && c <= 'f') {
>+      c -= 'a' - 'A';
>+    }
>+
>+    if ((c >= '0' && c <= '9') || (c >= 'A' && c <= 'F')) {
>+      if (u > m) {
>+        return (unsigned int) -1;
>+      }
>+
>+      u = (u << 4) | (c - (c >= 'A' ? 'A' - 10 : '0'));
>+    } else {
>+      //
>+      // Let application exit immediately
>+      //
>+      Error (NULL, 0, 0, "Hex value is expected!", NULL);
>+      exit (0);
>+      break;
>+    }
>+
>+    c = *(str++);
>+  }
>+
>+  return u;
>+}
>+
>diff --git a/Silicon/Intel/Tools/FitGen/FitGen.h
>b/Silicon/Intel/Tools/FitGen/FitGen.h
>new file mode 100644
>index 0000000000..9bd3f6824b
>--- /dev/null
>+++ b/Silicon/Intel/Tools/FitGen/FitGen.h
>@@ -0,0 +1,48 @@
>+/**@file
>+Definitions for the FitGen utility.
>+
>+Copyright (c) 2010-2019, Intel Corporation. All rights reserved.<BR>
>+SPDX-License-Identifier: BSD-2-Clause-Patent
>+
>+**/
>+
>+#ifndef _FIT_GEN_H
>+#define _FIT_GEN_H
>+
>+#include <stdio.h>
>+#include <stdlib.h>
>+#define PI_SPECIFICATION_VERSION  0x00010000
>+#define EFI_FVH_PI_REVISION       EFI_FVH_REVISION
>+#include <Common/UefiBaseTypes.h>
>+#include <Common/PiFirmwareFile.h>
>+#include <Common/PiFirmwareVolume.h>
>+#include <Guid/PiFirmwareFileSystem.h>
>+#include "EfiUtilityMsgs.c"
>+#include "CommonLib.h"
>+#include "ParseInf.h"
>+#include "FvLib.h"
>+
>+//
>+// Utility Name
>+//
>+#define UTILITY_NAME  "FitGen"
>+
>+//
>+// Utility version information
>+//
>+#define UTILITY_MAJOR_VERSION 0
>+#define UTILITY_MINOR_VERSION 56
>+#define UTILITY_DATE          __DATE__
>+
>+//
>+// The minimum number of arguments accepted from the command line.
>+//
>+#define MIN_VIEW_ARGS   3
>+#define MIN_ARGS        4
>+#define BUF_SIZE        (8 * 1024)
>+
>+#define GETOCCUPIEDSIZE(ActualSize, Alignment) \
>+  (ActualSize) + (((Alignment) - ((ActualSize) & ((Alignment) - 1))) &
>((Alignment) - 1))
>+;
>+
>+#endif
>diff --git a/Silicon/Intel/Tools/FitGen/GNUmakefile
>b/Silicon/Intel/Tools/FitGen/GNUmakefile
>new file mode 100644
>index 0000000000..00a99bb0c7
>--- /dev/null
>+++ b/Silicon/Intel/Tools/FitGen/GNUmakefile
>@@ -0,0 +1,16 @@
>+# @file
>+# GNUmakefile for building the FitGen utility.
>+#
>+# Copyright (c) 2010-2019, Intel Corporation. All rights reserved.<BR>
>+# SPDX-License-Identifier: BSD-2-Clause-Patent
>+#
>+MAKEROOT ?= $(EDK_TOOLS_PATH)/Source/C
>+
>+APPNAME = FitGen
>+
>+OBJECTS = FitGen.o
>+
>+include $(MAKEROOT)/Makefiles/app.makefile
>+
>+LIBS = -lCommon
>+
>diff --git a/Silicon/Intel/Tools/FitGen/Makefile
>b/Silicon/Intel/Tools/FitGen/Makefile
>new file mode 100644
>index 0000000000..fd286b26be
>--- /dev/null
>+++ b/Silicon/Intel/Tools/FitGen/Makefile
>@@ -0,0 +1,17 @@
>+# @file
>+# makefile for building the FitGen utility.
>+#
>+# Copyright (c) 2010-2019, Intel Corporation. All rights reserved.<BR>
>+# SPDX-License-Identifier: BSD-2-Clause-Patent
>+#
>+
>+!INCLUDE $(EDK_TOOLS_PATH)\Source\C\Makefiles\ms.common
>+
>+APPNAME = FitGen
>+
>+LIBS = $(LIB_PATH)\Common.lib
>+
>+OBJECTS = FitGen.obj
>+
>+!INCLUDE $(EDK_TOOLS_PATH)\Source\C\Makefiles\ms.app
>+
>--
>2.18.0.windows.1
>
>
>


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [edk2-platform patch 6/6] Silicon\Tools: Add top level Makefile and GNUMakefile
  2019-06-21  1:26 ` [edk2-platform patch 6/6] Silicon\Tools: Add top level Makefile and GNUMakefile Zhang, Shenglei
@ 2019-06-26  2:04   ` Liming Gao
  0 siblings, 0 replies; 15+ messages in thread
From: Liming Gao @ 2019-06-26  2:04 UTC (permalink / raw)
  To: Zhang, Shenglei, devel@edk2.groups.io; +Cc: Feng, Bob C

Shenglei:
  See my comments. 

Thanks
Liming
>-----Original Message-----
>From: Zhang, Shenglei
>Sent: Friday, June 21, 2019 9:27 AM
>To: devel@edk2.groups.io
>Cc: Feng, Bob C <bob.c.feng@intel.com>; Gao, Liming <liming.gao@intel.com>
>Subject: [edk2-platform patch 6/6] Silicon\Tools: Add top level Makefile and
>GNUMakefile
>
>Add FitGen into Makefile and GNUMakefile.
>
>Cc: Bob Feng <bob.c.feng@intel.com>
>Cc: Liming Gao <liming.gao@intel.com>
>Signed-off-by: Shenglei Zhang <shenglei.zhang@intel.com>
>---
> Silicon/Intel/Tools/GNUmakefile | 34
>+++++++++++++++++++++++++++++++++
> Silicon/Intel/Tools/Makefile    | 31 ++++++++++++++++++++++++++++++
> 2 files changed, 65 insertions(+)
> create mode 100644 Silicon/Intel/Tools/GNUmakefile
> create mode 100644 Silicon/Intel/Tools/Makefile
>
>diff --git a/Silicon/Intel/Tools/GNUmakefile
>b/Silicon/Intel/Tools/GNUmakefile
>new file mode 100644
>index 0000000000..77cfc62250
>--- /dev/null
>+++ b/Silicon/Intel/Tools/GNUmakefile
>@@ -0,0 +1,34 @@
>+## @file
>+#  GNUmakefile for building C utilities.
>+#
>+#  Copyright (c) 2018, Intel Corporation. All rights reserved.<BR>
>+#  This software and associated documentation (if any) is furnished
>+#  under a license and may only be used or copied in accordance
>+#  with the terms of the license. Except as permitted by such
>+#  license, no part of this software or documentation may be
>+#  reproduced, stored in a retrieval system, or transmitted in any
>+#  form or by any means without the express written consent of
>+#  Intel Corporation.
>+#
>+##

Please update license for BSD + Patent. 

Thanks
Liming

>+
>+MAKEROOT = $(EDK_TOOLS_PATH)/Source/C
>+
>+APPLICATIONS = \
>+  FitGen \
>+
>+SUBDIRS := $(APPLICATIONS)
>+
>+$(APPLICATIONS): $(MAKEROOT)/bin
>+
>+.PHONY: subdirs $(SUBDIRS)
>+subdirs: $(SUBDIRS)
>+$(SUBDIRS):
>+    $(MAKE) -C $@
>+
>+.PHONY: $(patsubst %,%-clean,$(sort $(SUBDIRS)))
>+$(patsubst %,%-clean,$(sort $(SUBDIRS))):
>+    -$(MAKE) -C $(@:-clean=) clean
>+
>+clean: $(patsubst %,%-clean,$(sort $(SUBDIRS)))
>+
>diff --git a/Silicon/Intel/Tools/Makefile b/Silicon/Intel/Tools/Makefile
>new file mode 100644
>index 0000000000..e52c95b7b5
>--- /dev/null
>+++ b/Silicon/Intel/Tools/Makefile
>@@ -0,0 +1,31 @@
>+## @file
>+#  makefile for building C utilities.
>+#
>+#  Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
>+#  SPDX-License-Identifier: BSD-2-Clause-Patent
>+#
>+##
>+
>+!INCLUDE $(EDK_TOOLS_PATH)\Source\C\Makefiles\ms.common
>+
>+APPLICATIONS = \
>+  FitGen \
>+
>+all: $(APPLICATIONS)
>+    @echo.
>+    @echo ######################
>+    @echo # Build executables
>+    @echo ######################
>+    @if not exist $(BIN_PATH) mkdir $(BIN_PATH)
>+    @$(EDK_TOOLS_PATH)\Source\C\Makefiles\NmakeSubdirs.bat all $**
>+
>+.PHONY: clean
>+clean: $(APPLICATIONS)
>+  @$(EDK_TOOLS_PATH)\Source\C\Makefiles\NmakeSubdirs.bat clean $**
>+
>+.PHONY: cleanall
>+cleanall: $(APPLICATIONS)
>+  @$(EDK_TOOLS_PATH)\Source\C\Makefiles\NmakeSubdirs.bat cleanall
>$**
>+
>+!INCLUDE $(EDK_TOOLS_PATH)\Source\C\Makefiles\ms.rule
>+
>--
>2.18.0.windows.1


^ permalink raw reply	[flat|nested] 15+ messages in thread

end of thread, other threads:[~2019-06-26  2:04 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2019-06-21  1:26 [edk2-platform patch 0/6] Add tools FMMT FCE and FitGen Zhang, Shenglei
2019-06-21  1:26 ` [edk2-platform patch 1/6] Platform\Tools: Add a tool FMMT Zhang, Shenglei
2019-06-21  1:26 ` [edk2-platform patch 2/6] Platform\Tools: Add a tool BfmLib Zhang, Shenglei
2019-06-21  1:26 ` [edk2-platform patch 3/6] BaseTools\FCE: Add a tool FCE Zhang, Shenglei
2019-06-21  1:26 ` [edk2-platform patch 4/6] Platform\Tools: Add top level Makefile and GNUMakefile Zhang, Shenglei
2019-06-21  1:26 ` [edk2-platform patch 5/6] Silicon\Tools: Add a tool FitGen Zhang, Shenglei
2019-06-26  2:03   ` [edk2-devel] " Liming Gao
2019-06-21  1:26 ` [edk2-platform patch 6/6] Silicon\Tools: Add top level Makefile and GNUMakefile Zhang, Shenglei
2019-06-26  2:04   ` Liming Gao
2019-06-21  2:25 ` [edk2-devel] [edk2-platform patch 0/6] Add tools FMMT FCE and FitGen Yao, Jiewen
2019-06-21  2:31   ` Liming Gao
2019-06-21  3:34     ` Yao, Jiewen
2019-06-25 14:09       ` Liming Gao
2019-06-25 14:14         ` Yao, Jiewen
2019-06-25 15:20           ` Liming Gao

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox