public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
From: "Zhang, Shenglei" <shenglei.zhang@intel.com>
To: devel@edk2.groups.io
Cc: Bob Feng <bob.c.feng@intel.com>, Liming Gao <liming.gao@intel.com>
Subject: [edk2-platform patch 5/6] Silicon\Tools: Add a tool FitGen
Date: Fri, 21 Jun 2019 09:26:42 +0800	[thread overview]
Message-ID: <20190621012643.9352-6-shenglei.zhang@intel.com> (raw)
In-Reply-To: <20190621012643.9352-1-shenglei.zhang@intel.com>

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

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

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


  parent reply	other threads:[~2019-06-21  1:27 UTC|newest]

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

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-list from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20190621012643.9352-6-shenglei.zhang@intel.com \
    --to=devel@edk2.groups.io \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox