[edk2-devel] [Patch v3 2/3] BaseTools: Add a tool FCE

Liming Gao liming.gao at intel.com
Mon Jul 1 11:27:30 UTC 2019


From: Shenglei Zhang <shenglei.zhang at intel.com>

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 at intel.com>
Cc: Liming Gao <liming.gao at intel.com>
Signed-off-by: Shenglei Zhang <shenglei.zhang at intel.com>
Reviewed-by: Bob Feng <bob.c.feng at intel.com>
---
 BaseTools/Source/C/FCE/BinaryCreate.c           |  216 +
 BaseTools/Source/C/FCE/BinaryParse.c            | 1326 +++++
 BaseTools/Source/C/FCE/Common.c                 | 2183 ++++++++
 BaseTools/Source/C/FCE/Expression.c             | 2367 +++++++++
 BaseTools/Source/C/FCE/Fce.c                    | 6449 +++++++++++++++++++++++
 BaseTools/Source/C/FCE/IfrParse.c               | 4836 +++++++++++++++++
 BaseTools/Source/C/FCE/MonotonicBasedVariable.c |  874 +++
 BaseTools/Source/C/FCE/TimeBasedVariable.c      |  878 +++
 BaseTools/Source/C/FCE/Variable.c               | 1091 ++++
 BaseTools/BinWrappers/PosixLike/FCE             |   29 +
 BaseTools/Source/C/FCE/BinaryCreate.h           |  157 +
 BaseTools/Source/C/FCE/BinaryParse.h            |  187 +
 BaseTools/Source/C/FCE/Common.h                 |  999 ++++
 BaseTools/Source/C/FCE/Fce.h                    |  447 ++
 BaseTools/Source/C/FCE/GNUmakefile              |   55 +
 BaseTools/Source/C/FCE/IfrParse.h               |  789 +++
 BaseTools/Source/C/FCE/Makefile                 |   19 +
 BaseTools/Source/C/FCE/MonotonicBasedVariable.h |  162 +
 BaseTools/Source/C/FCE/TimeBasedVariable.h      |  166 +
 BaseTools/Source/C/FCE/Variable.h               |  154 +
 BaseTools/Source/C/FCE/VariableCommon.h         |   55 +
 BaseTools/Source/C/GNUmakefile                  |    3 +-
 BaseTools/Source/C/Makefile                     |    3 +-
 23 files changed, 23443 insertions(+), 2 deletions(-)
 create mode 100644 BaseTools/Source/C/FCE/BinaryCreate.c
 create mode 100644 BaseTools/Source/C/FCE/BinaryParse.c
 create mode 100644 BaseTools/Source/C/FCE/Common.c
 create mode 100644 BaseTools/Source/C/FCE/Expression.c
 create mode 100644 BaseTools/Source/C/FCE/Fce.c
 create mode 100644 BaseTools/Source/C/FCE/IfrParse.c
 create mode 100644 BaseTools/Source/C/FCE/MonotonicBasedVariable.c
 create mode 100644 BaseTools/Source/C/FCE/TimeBasedVariable.c
 create mode 100644 BaseTools/Source/C/FCE/Variable.c
 create mode 100755 BaseTools/BinWrappers/PosixLike/FCE
 create mode 100644 BaseTools/Source/C/FCE/BinaryCreate.h
 create mode 100644 BaseTools/Source/C/FCE/BinaryParse.h
 create mode 100644 BaseTools/Source/C/FCE/Common.h
 create mode 100644 BaseTools/Source/C/FCE/Fce.h
 create mode 100644 BaseTools/Source/C/FCE/GNUmakefile
 create mode 100644 BaseTools/Source/C/FCE/IfrParse.h
 create mode 100644 BaseTools/Source/C/FCE/Makefile
 create mode 100644 BaseTools/Source/C/FCE/MonotonicBasedVariable.h
 create mode 100644 BaseTools/Source/C/FCE/TimeBasedVariable.h
 create mode 100644 BaseTools/Source/C/FCE/Variable.h
 create mode 100644 BaseTools/Source/C/FCE/VariableCommon.h

diff --git a/BaseTools/Source/C/FCE/BinaryCreate.c b/BaseTools/Source/C/FCE/BinaryCreate.c
new file mode 100644
index 0000000000..2f36bc2ef3
--- /dev/null
+++ b/BaseTools/Source/C/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/BaseTools/Source/C/FCE/BinaryParse.c b/BaseTools/Source/C/FCE/BinaryParse.c
new file mode 100644
index 0000000000..e9f8ee6826
--- /dev/null
+++ b/BaseTools/Source/C/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/BaseTools/Source/C/FCE/Common.c b/BaseTools/Source/C/FCE/Common.c
new file mode 100644
index 0000000000..9b14a24a9b
--- /dev/null
+++ b/BaseTools/Source/C/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/BaseTools/Source/C/FCE/Expression.c b/BaseTools/Source/C/FCE/Expression.c
new file mode 100644
index 0000000000..34b310d97f
--- /dev/null
+++ b/BaseTools/Source/C/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/BaseTools/Source/C/FCE/Fce.c b/BaseTools/Source/C/FCE/Fce.c
new file mode 100644
index 0000000000..1845c508b5
--- /dev/null
+++ b/BaseTools/Source/C/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/BaseTools/Source/C/FCE/IfrParse.c b/BaseTools/Source/C/FCE/IfrParse.c
new file mode 100644
index 0000000000..2f5a87baf3
--- /dev/null
+++ b/BaseTools/Source/C/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/BaseTools/Source/C/FCE/MonotonicBasedVariable.c b/BaseTools/Source/C/FCE/MonotonicBasedVariable.c
new file mode 100644
index 0000000000..9d35bffab6
--- /dev/null
+++ b/BaseTools/Source/C/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/BaseTools/Source/C/FCE/TimeBasedVariable.c b/BaseTools/Source/C/FCE/TimeBasedVariable.c
new file mode 100644
index 0000000000..e21c61dde9
--- /dev/null
+++ b/BaseTools/Source/C/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/BaseTools/Source/C/FCE/Variable.c b/BaseTools/Source/C/FCE/Variable.c
new file mode 100644
index 0000000000..5c92060309
--- /dev/null
+++ b/BaseTools/Source/C/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/BaseTools/BinWrappers/PosixLike/FCE b/BaseTools/BinWrappers/PosixLike/FCE
new file mode 100755
index 0000000000..a244ecc095
--- /dev/null
+++ b/BaseTools/BinWrappers/PosixLike/FCE
@@ -0,0 +1,29 @@
+#!/usr/bin/env bash
+
+full_cmd=${BASH_SOURCE:-$0} # see http://mywiki.wooledge.org/BashFAQ/028 for a discussion of why $0 is not a good choice here
+dir=$(dirname "$full_cmd")
+cmd=${full_cmd##*/}
+
+if [ -n "$WORKSPACE" ] && [ -e "$WORKSPACE/Conf/BaseToolsCBinaries" ]
+then
+  exec "$WORKSPACE/Conf/BaseToolsCBinaries/$cmd"
+elif [ -n "$WORKSPACE" ] && [ -e "$EDK_TOOLS_PATH/Source/C" ]
+then
+  if [ ! -e "$EDK_TOOLS_PATH/Source/C/bin/$cmd" ]
+  then
+    echo "BaseTools C Tool binary was not found ($cmd)"
+    echo "You may need to run:"
+    echo "  make -C $EDK_TOOLS_PATH/Source/C"
+  else
+    exec "$EDK_TOOLS_PATH/Source/C/bin/$cmd" "$@"
+  fi
+elif [ -e "$dir/../../Source/C/bin/$cmd" ]
+then
+  exec "$dir/../../Source/C/bin/$cmd" "$@"
+else
+  echo "Unable to find the real '$cmd' to run"
+  echo "This message was printed by"
+  echo "  $0"
+  exit 127
+fi
+
diff --git a/BaseTools/Source/C/FCE/BinaryCreate.h b/BaseTools/Source/C/FCE/BinaryCreate.h
new file mode 100644
index 0000000000..0e2f22599e
--- /dev/null
+++ b/BaseTools/Source/C/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/BaseTools/Source/C/FCE/BinaryParse.h b/BaseTools/Source/C/FCE/BinaryParse.h
new file mode 100644
index 0000000000..a3995b8b79
--- /dev/null
+++ b/BaseTools/Source/C/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/BaseTools/Source/C/FCE/Common.h b/BaseTools/Source/C/FCE/Common.h
new file mode 100644
index 0000000000..6b21974878
--- /dev/null
+++ b/BaseTools/Source/C/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/BaseTools/Source/C/FCE/Fce.h b/BaseTools/Source/C/FCE/Fce.h
new file mode 100644
index 0000000000..32cc3a1ccc
--- /dev/null
+++ b/BaseTools/Source/C/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/BaseTools/Source/C/FCE/GNUmakefile b/BaseTools/Source/C/FCE/GNUmakefile
new file mode 100644
index 0000000000..3e1b6a85e2
--- /dev/null
+++ b/BaseTools/Source/C/FCE/GNUmakefile
@@ -0,0 +1,55 @@
+## @file GNUmakefile
+#
+# GNU makefile for 'FCE' module build.
+#
+# Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution.  The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+
+ifndef ARCH
+  #
+  # If ARCH is not defined, then we use 'uname -m' to attempt
+  # try to figure out the appropriate ARCH.
+  #
+  uname_m = $(shell uname -m)
+  $(info Attempting to detect ARCH from 'uname -m': $(uname_m))
+  ifneq (,$(strip $(filter $(uname_m), x86_64 amd64)))
+    ARCH=X64
+  endif
+  ifeq ($(patsubst i%86,IA32,$(uname_m)),IA32)
+    ARCH=IA32
+  endif
+  ifneq (,$(findstring aarch64,$(uname_m)))
+    ARCH=AARCH64
+  endif
+  ifneq (,$(findstring arm,$(uname_m)))
+    ARCH=ARM
+  endif
+  ifndef ARCH
+    $(info Could not detected ARCH from uname results)
+    $(error ARCH is not defined!)
+  endif
+  $(info Detected ARCH of $(ARCH) using uname.)
+endif
+
+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/BaseTools/Source/C/FCE/IfrParse.h b/BaseTools/Source/C/FCE/IfrParse.h
new file mode 100644
index 0000000000..29a878a191
--- /dev/null
+++ b/BaseTools/Source/C/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/BaseTools/Source/C/FCE/Makefile b/BaseTools/Source/C/FCE/Makefile
new file mode 100644
index 0000000000..cc33a42a42
--- /dev/null
+++ b/BaseTools/Source/C/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/BaseTools/Source/C/FCE/MonotonicBasedVariable.h b/BaseTools/Source/C/FCE/MonotonicBasedVariable.h
new file mode 100644
index 0000000000..11fc51ed38
--- /dev/null
+++ b/BaseTools/Source/C/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/BaseTools/Source/C/FCE/TimeBasedVariable.h b/BaseTools/Source/C/FCE/TimeBasedVariable.h
new file mode 100644
index 0000000000..3ffd939443
--- /dev/null
+++ b/BaseTools/Source/C/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/BaseTools/Source/C/FCE/Variable.h b/BaseTools/Source/C/FCE/Variable.h
new file mode 100644
index 0000000000..35b88e045c
--- /dev/null
+++ b/BaseTools/Source/C/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/BaseTools/Source/C/FCE/VariableCommon.h b/BaseTools/Source/C/FCE/VariableCommon.h
new file mode 100644
index 0000000000..7389902076
--- /dev/null
+++ b/BaseTools/Source/C/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_
diff --git a/BaseTools/Source/C/GNUmakefile b/BaseTools/Source/C/GNUmakefile
index 824f0306e6..990c6d0a82 100644
--- a/BaseTools/Source/C/GNUmakefile
+++ b/BaseTools/Source/C/GNUmakefile
@@ -1,7 +1,7 @@
 ## @file
 #  GNU/Linux makefile for C tools build.
 #
-#  Copyright (c) 2007 - 2017, Intel Corporation. All rights reserved.<BR>
+#  Copyright (c) 2007 - 2019, Intel Corporation. All rights reserved.<BR>
 #
 #  SPDX-License-Identifier: BSD-2-Clause-Patent
 #
@@ -49,6 +49,7 @@ APPLICATIONS = \
   VfrCompile \
   BfmLib \
   EfiRom \
+  FCE \
   GenFfs \
   GenFv \
   GenFw \
diff --git a/BaseTools/Source/C/Makefile b/BaseTools/Source/C/Makefile
index a6d39eb864..357e8b9003 100644
--- a/BaseTools/Source/C/Makefile
+++ b/BaseTools/Source/C/Makefile
@@ -1,7 +1,7 @@
 ## @file
 # Windows makefile for C tools build.
 #
-# Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
+# Copyright (c) 2009 - 2019, Intel Corporation. All rights reserved.<BR>
 # SPDX-License-Identifier: BSD-2-Clause-Patent
 #
 HOST_ARCH = IA32
@@ -14,6 +14,7 @@ APPLICATIONS = \
   BrotliCompress \
   BfmLib \
   EfiRom \
+  FCE \
   GenCrc32 \
   GenFfs \
   GenFv \
-- 
2.13.0.windows.1


-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.

View/Reply Online (#43122): https://edk2.groups.io/g/devel/message/43122
Mute This Topic: https://groups.io/mt/32270352/1813853
Group Owner: devel+owner at edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub  [edk2-devel-archive at redhat.com]
-=-=-=-=-=-=-=-=-=-=-=-




More information about the edk2-devel-archive mailing list