[edk2-devel] [PATCH v3 2/2] UefiPayloadPkg: Add FIT support

brucex.wang@intel.com posted 2 patches 10 months, 1 week ago
[edk2-devel] [PATCH v3 2/2] UefiPayloadPkg: Add FIT support
Posted by brucex.wang@intel.com 10 months, 1 week ago
From: "Brucex.Wang" <brucex.wang@intel.com>

Provide Fit format for UniversalPayload, developer can use argument
"--Fit" to build UniversalPayload.fit

Cc: Guo Dong <guo.dong@intel.com>
Cc: Sean Rhodes <sean@starlabs.systems>
Cc: James Lu <james.lu@intel.com>
Cc: Gua Guo <gua.guo@intel.com>

Signed-off-by: BruceX Wang <brucex.wang@intel.com>
---
 .../Include/Guid/UniversalPayloadBase.h       |  19 +
 UefiPayloadPkg/PayloadLoaderPeim/FitLib.h     |  60 ++
 .../PayloadLoaderPeim/FitLib/FitLib.c         | 127 ++++
 .../PayloadLoaderPeim/FitPayloadLoaderPeim.c  | 150 ++++
 .../FitPayloadLoaderPeim.inf                  |  59 ++
 UefiPayloadPkg/Readme.md                      | 189 +++++
 UefiPayloadPkg/Tools/MkFitImage.py            | 272 ++++++++
 .../FitUniversalPayloadEntry.c                | 654 ++++++++++++++++++
 .../FitUniversalPayloadEntry.inf              |  98 +++
 UefiPayloadPkg/UefiPayloadPkg.dec             |   3 +
 UefiPayloadPkg/UefiPayloadPkg.dsc             |  27 +-
 UefiPayloadPkg/UniversalPayloadBuild.py       | 328 ++++++---
 12 files changed, 1890 insertions(+), 96 deletions(-)
 create mode 100644 UefiPayloadPkg/Include/Guid/UniversalPayloadBase.h
 create mode 100644 UefiPayloadPkg/PayloadLoaderPeim/FitLib.h
 create mode 100644 UefiPayloadPkg/PayloadLoaderPeim/FitLib/FitLib.c
 create mode 100644 UefiPayloadPkg/PayloadLoaderPeim/FitPayloadLoaderPeim.c
 create mode 100644 UefiPayloadPkg/PayloadLoaderPeim/FitPayloadLoaderPeim.inf
 create mode 100644 UefiPayloadPkg/Readme.md
 create mode 100644 UefiPayloadPkg/Tools/MkFitImage.py
 create mode 100644 UefiPayloadPkg/UefiPayloadEntry/FitUniversalPayloadEntry.c
 create mode 100644 UefiPayloadPkg/UefiPayloadEntry/FitUniversalPayloadEntry.inf

diff --git a/UefiPayloadPkg/Include/Guid/UniversalPayloadBase.h b/UefiPayloadPkg/Include/Guid/UniversalPayloadBase.h
new file mode 100644
index 0000000000..60f2aa37dd
--- /dev/null
+++ b/UefiPayloadPkg/Include/Guid/UniversalPayloadBase.h
@@ -0,0 +1,19 @@
+/** @file
+  Universal Payload general definitions.
+
+Copyright (c) 2023, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef UNIVERSAL_PAYLOAD_BASE_H_
+#define UNIVERSAL_PAYLOAD_BASE_H_
+
+extern GUID  gUniversalPayloadBaseGuid;
+
+typedef struct {
+  UNIVERSAL_PAYLOAD_GENERIC_HEADER    Header;
+  EFI_PHYSICAL_ADDRESS                Entry;
+} UNIVERSAL_PAYLOAD_BASE;
+
+#endif // UNIVERSAL_PAYLOAD_BASE_H_
diff --git a/UefiPayloadPkg/PayloadLoaderPeim/FitLib.h b/UefiPayloadPkg/PayloadLoaderPeim/FitLib.h
new file mode 100644
index 0000000000..0514d675a6
--- /dev/null
+++ b/UefiPayloadPkg/PayloadLoaderPeim/FitLib.h
@@ -0,0 +1,60 @@
+/** @file
+  FIT Load Image Support
+Copyright (c) 2023, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#ifndef FIT_LIB_H_
+#define FIT_LIB_H_
+
+#include <PiPei.h>
+#include <Library/DebugLib.h>
+#include <Library/FdtLib.h>
+
+typedef struct {
+  UINT64    RelocateType;
+  UINT64    Offset;
+} FIT_RELOCATE_ITEM;
+
+typedef struct {
+  EFI_PHYSICAL_ADDRESS    ImageBase;
+  EFI_PHYSICAL_ADDRESS    PayloadBaseAddress;
+  UINT64                  PayloadSize;
+  UINTN                   PayloadEntryOffset;
+  UINTN                   PayloadEntrySize;
+  EFI_PHYSICAL_ADDRESS    PayloadEntryPoint;
+  UINTN                   RelocateTableOffset;
+  UINTN                   RelocateTableCount;
+  EFI_PHYSICAL_ADDRESS    PayloadLoadAddress;
+} FIT_IMAGE_CONTEXT;
+
+typedef struct {
+  UINT8     *Name;
+  UINT32    Offset;
+} PROPERTY_DATA;
+
+#define IMAGE_BASE_OFFSET             OFFSET_OF (FIT_IMAGE_CONTEXT, ImageBase)
+#define PAYLOAD_BASE_ADDR_OFFSET      OFFSET_OF (FIT_IMAGE_CONTEXT, PayloadBaseAddress)
+#define PAYLOAD_BASE_SIZE_OFFSET      OFFSET_OF (FIT_IMAGE_CONTEXT, PayloadSize)
+#define PAYLOAD_ENTRY_OFFSET_OFFSET   OFFSET_OF (FIT_IMAGE_CONTEXT, PayloadEntryOffset)
+#define PAYLOAD_ENTRY_SIZE_OFFSET     OFFSET_OF (FIT_IMAGE_CONTEXT, PayloadEntrySize)
+#define PAYLOAD_ENTRY_POINT_OFFSET    OFFSET_OF (FIT_IMAGE_CONTEXT, PayloadEntryPoint)
+#define RELOCATE_TABLE_OFFSET_OFFSET  OFFSET_OF (FIT_IMAGE_CONTEXT, RelocateTableOffset)
+#define RELOCATE_TABLE_COUNT_OFFSET   OFFSET_OF (FIT_IMAGE_CONTEXT, RelocateTableCount)
+#define PAYLOAD_LOAD_ADDR_OFFSET      OFFSET_OF (FIT_IMAGE_CONTEXT, PayloadLoadAddress)
+
+/**
+  Parse the FIT image info.
+  @param[in]  ImageBase      Memory address of an image.
+  @param[out] Context        The FIT image context pointer.
+  @retval EFI_UNSUPPORTED         Unsupported binary type.
+  @retval EFI_SUCCESS             FIT binary is loaded successfully.
+**/
+EFI_STATUS
+EFIAPI
+ParseFitImage (
+  IN   VOID               *ImageBase,
+  OUT  FIT_IMAGE_CONTEXT  *Context
+  );
+
+#endif
diff --git a/UefiPayloadPkg/PayloadLoaderPeim/FitLib/FitLib.c b/UefiPayloadPkg/PayloadLoaderPeim/FitLib/FitLib.c
new file mode 100644
index 0000000000..9d1d8a4f61
--- /dev/null
+++ b/UefiPayloadPkg/PayloadLoaderPeim/FitLib/FitLib.c
@@ -0,0 +1,127 @@
+/** @file
+  FIT Load Image Support
+Copyright (c) 2023, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include "FitLib.h"
+
+PROPERTY_DATA  PropertyData32List[] = {
+  { "data-offset", PAYLOAD_ENTRY_OFFSET_OFFSET  },
+  { "data-size",   PAYLOAD_ENTRY_SIZE_OFFSET    },
+  { "reloc-start", RELOCATE_TABLE_OFFSET_OFFSET }
+};
+
+PROPERTY_DATA  PropertyData64List[] = {
+  { "entry-start", PAYLOAD_ENTRY_POINT_OFFSET },
+  { "load",        PAYLOAD_LOAD_ADDR_OFFSET   }
+};
+
+/**
+  Parse the target firmware image info in FIT.
+  @param[in]  Fdt            Memory address of a fdt.
+  @param[in]  Firmware       Target name of an image.
+  @param[out] Context        The FIT image context pointer.
+  @retval EFI_NOT_FOUND      FIT node dose not find.
+  @retval EFI_SUCCESS        FIT binary is loaded successfully.
+**/
+EFI_STATUS
+EFIAPI
+FitParseFirmwarePropertyData (
+  IN   VOID               *Fdt,
+  IN   CHAR8              *Firmware,
+  OUT  FIT_IMAGE_CONTEXT  *Context
+  )
+{
+  CONST FDT_PROPERTY  *PropertyPtr;
+  INT32               ImageNode;
+  INT32               TianoNode;
+  INT32               TempLen;
+  UINT32              *Data32;
+  UINT64              *Data64;
+  UINT32              *ContextOffset32;
+  UINT64              *ContextOffset64;
+  INT32               Index;
+
+  ImageNode = FdtSubnodeOffsetNameLen (Fdt, 0, "images", (INT32)AsciiStrLen ("images"));
+  if (ImageNode <= 0) {
+    return EFI_NOT_FOUND;
+  }
+
+  TianoNode = FdtSubnodeOffsetNameLen (Fdt, ImageNode, Firmware, (INT32)AsciiStrLen (Firmware));
+  if (TianoNode <= 0) {
+    return EFI_NOT_FOUND;
+  }
+
+  for (Index = 0; Index < sizeof (PropertyData32List) / sizeof (PROPERTY_DATA); Index++) {
+    PropertyPtr      = FdtGetProperty (Fdt, TianoNode, PropertyData32List[Index].Name, &TempLen);
+    Data32           = (UINT32 *)(PropertyPtr->Data);
+    ContextOffset32  = (UINT32 *)((UINTN)Context + PropertyData32List[Index].Offset);
+    *ContextOffset32 = Fdt32ToCpu (*Data32);
+  }
+
+  for (Index = 0; Index < sizeof (PropertyData64List)/sizeof (PROPERTY_DATA); Index++) {
+    PropertyPtr      = FdtGetProperty (Fdt, TianoNode, PropertyData64List[Index].Name, &TempLen);
+    Data64           = (UINT64 *)(PropertyPtr->Data);
+    ContextOffset64  = (UINT64 *)((UINTN)Context + PropertyData64List[Index].Offset);
+    *ContextOffset64 = Fdt64ToCpu (*Data64);
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Parse the FIT image info.
+  @param[in]  ImageBase      Memory address of an image.
+  @param[out] Context        The FIT image context pointer.
+  @retval EFI_UNSUPPORTED         Unsupported binary type.
+  @retval EFI_SUCCESS             FIT binary is loaded successfully.
+**/
+EFI_STATUS
+EFIAPI
+ParseFitImage (
+  IN   VOID               *ImageBase,
+  OUT  FIT_IMAGE_CONTEXT  *Context
+  )
+{
+  VOID                *Fdt;
+  INT32               ConfigNode;
+  INT32               Config1Node;
+  CONST FDT_PROPERTY  *PropertyPtr;
+  INT32               TempLen;
+  UINT32              *Data32;
+  UINT64              Value;
+  EFI_STATUS          Status;
+  UINTN               UplSize;
+  CHAR8               *Firmware;
+
+  Status = FdtCheckHeader (ImageBase);
+  if (EFI_ERROR (Status)) {
+    return EFI_UNSUPPORTED;
+  }
+
+  Fdt         = ImageBase;
+  PropertyPtr = FdtGetProperty (Fdt, 0, "size", &TempLen);
+  Data32      = (UINT32 *)(PropertyPtr->Data);
+  UplSize     = Value = Fdt32ToCpu (*Data32);
+  ConfigNode  = FdtSubnodeOffsetNameLen (Fdt, 0, "configurations", (INT32)AsciiStrLen ("configurations"));
+  if (ConfigNode <= 0) {
+    return EFI_NOT_FOUND;
+  }
+
+  Config1Node = FdtSubnodeOffsetNameLen (Fdt, ConfigNode, "conf-1", (INT32)AsciiStrLen ("conf-1"));
+  if (Config1Node <= 0) {
+    return EFI_NOT_FOUND;
+  }
+
+  PropertyPtr = FdtGetProperty (Fdt, Config1Node, "firmware", &TempLen);
+  Firmware    = (CHAR8 *)(PropertyPtr->Data);
+
+  FitParseFirmwarePropertyData (Fdt, Firmware, Context);
+
+  Context->ImageBase          = (EFI_PHYSICAL_ADDRESS)ImageBase;
+  Context->PayloadSize        = UplSize;
+  Context->RelocateTableCount = (Context->PayloadEntrySize - (Context->RelocateTableOffset - Context->PayloadEntryOffset)) / sizeof (FIT_RELOCATE_ITEM);
+
+  return EFI_SUCCESS;
+}
diff --git a/UefiPayloadPkg/PayloadLoaderPeim/FitPayloadLoaderPeim.c b/UefiPayloadPkg/PayloadLoaderPeim/FitPayloadLoaderPeim.c
new file mode 100644
index 0000000000..de33d49bd1
--- /dev/null
+++ b/UefiPayloadPkg/PayloadLoaderPeim/FitPayloadLoaderPeim.c
@@ -0,0 +1,150 @@
+/** @file
+  FIT Load Image Support
+Copyright (c) 2023, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include <PiPei.h>
+#include <UniversalPayload/UniversalPayload.h>
+#include <Guid/UniversalPayloadBase.h>
+#include <UniversalPayload/ExtraData.h>
+
+#include <Ppi/LoadFile.h>
+
+#include <Library/DebugLib.h>
+#include <Library/HobLib.h>
+#include <Library/PeiServicesLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/BaseMemoryLib.h>
+
+#include "FitLib.h"
+
+/**
+  The wrapper function of PeiLoadImageLoadImage().
+  @param This            - Pointer to EFI_PEI_LOAD_FILE_PPI.
+  @param FileHandle      - Pointer to the FFS file header of the image.
+  @param ImageAddressArg - Pointer to PE/TE image.
+  @param ImageSizeArg    - Size of PE/TE image.
+  @param EntryPoint      - Pointer to entry point of specified image file for output.
+  @param AuthenticationState - Pointer to attestation authentication state of image.
+  @return Status of PeiLoadImageLoadImage().
+**/
+EFI_STATUS
+EFIAPI
+PeiLoadFileLoadPayload (
+  IN     CONST EFI_PEI_LOAD_FILE_PPI  *This,
+  IN     EFI_PEI_FILE_HANDLE          FileHandle,
+  OUT    EFI_PHYSICAL_ADDRESS         *ImageAddressArg   OPTIONAL,
+  OUT    UINT64                       *ImageSizeArg      OPTIONAL,
+  OUT    EFI_PHYSICAL_ADDRESS         *EntryPoint,
+  OUT    UINT32                       *AuthenticationState
+  )
+{
+  EFI_STATUS              Status;
+  FIT_IMAGE_CONTEXT       Context;
+  UINTN                   Instance;
+  VOID                    *Binary;
+  FIT_RELOCATE_ITEM       *RelocateTable;
+  UNIVERSAL_PAYLOAD_BASE  *PayloadBase;
+  UINTN                   Length;
+  UINTN                   Delta;
+  UINTN                   Index;
+
+  Instance = 0;
+  do {
+    Status = PeiServicesFfsFindSectionData3 (EFI_SECTION_RAW, Instance++, FileHandle, &Binary, AuthenticationState);
+    if (EFI_ERROR (Status)) {
+      return Status;
+    }
+
+    ZeroMem (&Context, sizeof (Context));
+    Status = ParseFitImage (Binary, &Context);
+  } while (EFI_ERROR (Status));
+
+  if (EFI_ERROR (Status)) {
+    ASSERT_EFI_ERROR (Status);
+    return Status;
+  }
+
+  DEBUG ((
+    DEBUG_INFO,
+    "Before Rebase Payload File Base: 0x%08x, File Size: 0x%08X, EntryPoint: 0x%08x\n",
+    Context.PayloadBaseAddress,
+    Context.PayloadSize,
+    Context.PayloadEntryPoint
+    ));
+  Context.PayloadBaseAddress = (EFI_PHYSICAL_ADDRESS)AllocatePages (EFI_SIZE_TO_PAGES (Context.PayloadSize));
+
+  RelocateTable = (FIT_RELOCATE_ITEM *)(UINTN)(Context.PayloadBaseAddress + Context.RelocateTableOffset);
+  CopyMem ((VOID *)Context.PayloadBaseAddress, Binary, Context.PayloadSize);
+
+  if (Context.PayloadBaseAddress > Context.PayloadLoadAddress) {
+    Delta                      = Context.PayloadBaseAddress - Context.PayloadLoadAddress;
+    Context.PayloadEntryPoint += Delta;
+    for (Index = 0; Index < Context.RelocateTableCount; Index++) {
+      if ((RelocateTable[Index].RelocateType == 10) || (RelocateTable[Index].RelocateType == 3)) {
+        *((UINT64 *)(Context.PayloadBaseAddress + RelocateTable[Index].Offset)) = *((UINT64 *)(Context.PayloadBaseAddress + RelocateTable[Index].Offset)) + Delta;
+      }
+    }
+  } else {
+    Delta                      = Context.PayloadLoadAddress - Context.PayloadBaseAddress;
+    Context.PayloadEntryPoint -= Delta;
+    for (Index = 0; Index < Context.RelocateTableCount; Index++) {
+      if ((RelocateTable[Index].RelocateType == 10) || (RelocateTable[Index].RelocateType == 3)) {
+        *((UINT64 *)(Context.PayloadBaseAddress + RelocateTable[Index].Offset)) = *((UINT64 *)(Context.PayloadBaseAddress + RelocateTable[Index].Offset)) - Delta;
+      }
+    }
+  }
+
+  DEBUG ((
+    DEBUG_INFO,
+    "After Rebase Payload File Base: 0x%08x, File Size: 0x%08X, EntryPoint: 0x%08x\n",
+    Context.PayloadBaseAddress,
+    Context.PayloadSize,
+    Context.PayloadEntryPoint
+    ));
+
+  Length      = sizeof (UNIVERSAL_PAYLOAD_BASE);
+  PayloadBase = BuildGuidHob (
+                  &gUniversalPayloadBaseGuid,
+                  Length
+                  );
+  PayloadBase->Entry = (EFI_PHYSICAL_ADDRESS)Context.ImageBase;
+
+  *ImageAddressArg = Context.PayloadBaseAddress;
+  *ImageSizeArg    = Context.PayloadSize;
+  *EntryPoint      = Context.PayloadEntryPoint;
+
+  return EFI_SUCCESS;
+}
+
+EFI_PEI_LOAD_FILE_PPI  mPeiLoadFilePpi = {
+  PeiLoadFileLoadPayload
+};
+
+EFI_PEI_PPI_DESCRIPTOR  gPpiLoadFilePpiList = {
+  (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
+  &gEfiPeiLoadFilePpiGuid,
+  &mPeiLoadFilePpi
+};
+
+/**
+  Install Pei Load File PPI.
+  @param  FileHandle  Handle of the file being invoked.
+  @param  PeiServices Describes the list of possible PEI Services.
+  @retval EFI_SUCESS  The entry point executes successfully.
+  @retval Others      Some error occurs during the execution of this function.
+**/
+EFI_STATUS
+EFIAPI
+InitializeFitPayloadLoaderPeim (
+  IN       EFI_PEI_FILE_HANDLE  FileHandle,
+  IN CONST EFI_PEI_SERVICES     **PeiServices
+  )
+{
+  EFI_STATUS  Status;
+
+  Status = PeiServicesInstallPpi (&gPpiLoadFilePpiList);
+
+  return Status;
+}
diff --git a/UefiPayloadPkg/PayloadLoaderPeim/FitPayloadLoaderPeim.inf b/UefiPayloadPkg/PayloadLoaderPeim/FitPayloadLoaderPeim.inf
new file mode 100644
index 0000000000..cd0cb186e1
--- /dev/null
+++ b/UefiPayloadPkg/PayloadLoaderPeim/FitPayloadLoaderPeim.inf
@@ -0,0 +1,59 @@
+## @file
+#  Produce LoadFile PPI for payload loading.
+#
+#  Copyright (c) 2023, Intel Corporation. All rights reserved.<BR>
+#
+#  SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+  INF_VERSION                    = 0x00010005
+  BASE_NAME                      = FitPayloadLoaderPeim
+  FILE_GUID                      = 55AC82C8-FC17-4C56-BCDA-990BB0A73E41
+  MODULE_TYPE                    = PEIM
+  VERSION_STRING                 = 1.0
+
+  ENTRY_POINT                    = InitializeFitPayloadLoaderPeim
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+#  VALID_ARCHITECTURES           = IA32 X64
+#
+
+[Sources]
+  FitPayloadLoaderPeim.c
+  FitLib.h
+  FitLib/FitLib.c
+
+[Packages]
+  MdePkg/MdePkg.dec
+  MdeModulePkg/MdeModulePkg.dec
+  PcAtChipsetPkg/PcAtChipsetPkg.dec
+  UefiPayloadPkg/UefiPayloadPkg.dec
+
+[LibraryClasses]
+  PcdLib
+  MemoryAllocationLib
+  BaseMemoryLib
+  PeiServicesLib
+  HobLib
+  BaseLib
+  PeimEntryPoint
+  DebugLib
+  FdtLib
+
+[Ppis]
+  gEfiPeiLoadFilePpiGuid                 ## PRODUCES
+
+[Pcd]
+  gPcAtChipsetPkgTokenSpaceGuid.PcdRtcIndexRegister
+  gPcAtChipsetPkgTokenSpaceGuid.PcdRtcTargetRegister
+
+[Guids]
+  gUniversalPayloadExtraDataGuid         ## PRODUCES
+  gUniversalPayloadBaseGuid              ## PRODUCES
+
+[Depex]
+  TRUE
diff --git a/UefiPayloadPkg/Readme.md b/UefiPayloadPkg/Readme.md
new file mode 100644
index 0000000000..cb7f39b3f7
--- /dev/null
+++ b/UefiPayloadPkg/Readme.md
@@ -0,0 +1,189 @@
+# UefiPayloadPkg
+Provide UEFI Universal Payload for different bootloader to generate EFI environment
+
+# Spec
+UniversalPayload URL: https://universalscalablefirmware.github.io/documentation/2_universal_payload.html
+UniversalPayload URL: https://universalpayload.github.io/spec/
+ELF Format URL: https://refspecs.linuxfoundation.org/elf/elf.pdf
+FIT Format URL: https://universalpayload.github.io/spec/chapter2-payload-image-format.html
+
+# Uefi UniversalPayload Format
+  | Binary Format | HandOffPayload - HOB |
+  |---------------|----------------------|
+  | ELF           | V (Default)          |
+  | FIT           | V                    |
+
+# Binary Format
+  - ELF
+    ```
+                  +  +-----------------------+
+                  |  | UniversalPayloadEntry | <----------- UefiPayloadPkg\UefiPayloadEntry\UniversalPayloadEntry.c:_ModuleEntryPoint (HOB)
+                  |  +-----------------------+
+                  |  | .upld_info            | patch it directly
+    ELF Format    |  +-----------------------+
+                  |  | .upld.uefi_fv         | patch it directly
+                  |  +-----------------------+
+                  |  | .upld.bds_fv          | patch it directly
+                  |  +-----------------------+
+                  |  | .upld.<afpx>_fv       | patch it directly
+                  +  +-----------------------+
+    ```
+
+  - FIT
+    ```
+                  +  +-----------------------+
+    FIT Data      |  | FIT Header            | <----------- Generate by pylibfdt
+                  +  +-----------------------+
+    PECOFF Format |  | UniversalPayloadEntry | <----------- UefiPayloadPkg\UefiPayloadEntry\FitUniversalPayloadEntry.c:_ModuleEntryPoint (HOB)
+                  +  +-----------------------+
+    Relocate Data |  | reloc-start           |
+                  +  +-----------------------+
+                  |  | uefi_fv               | patch it directly
+                  |  +-----------------------+
+    Multi Binary  |  | bds_fv                | patch it directly
+                  |  +-----------------------+
+                  |  | afp_xxx_fv            | patch it directly
+                  |  +-----------------------+
+                  |  | afp_xxx_fv            | patch it directly
+                  +  +-----------------------+
+    ```
+
+# Environment
+  - ELF
+    ```
+    Download and install https://github.com/llvm/llvm-project/releases/tag/llvmorg-10.0.1
+    ```
+  - FIT
+    - Windows
+      ```powershell
+      Set-ExecutionPolicy Bypass -Scope Process -Force; [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; iex ((New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1'))
+      choco install dtc-msys2
+      pip3 install pefile
+      pip3 install swig
+      pip3 install pylibfdt
+      ```
+    - Ubuntu
+      ```bash
+      sudo apt install -y u-boot-tools
+      pip3 install pefile
+      pip3 install swig
+      pip3 install pylibfdt
+      ```
+# How to build UEFI UniversalPayload
+  - Windows
+    - edksetup Rebuild
+  - Linux
+    - make -C BaseTools
+    - source edksetup.sh
+
+  - UniversalPayload.elf
+    - python UefiPayloadPkg/UniversalPayloadBuild.py -t <TOOL_CHAIN_TAG>
+    - llvm-objdump -h Build/UefiPayloadPkgX64/UniversalPayload.elf
+
+  - UniversalPayload.fit
+    - python UefiPayloadPkg/UniversalPayloadBuild.py -t <TOOL_CHAIN_TAG> --Fit
+    - fdtdump Build/UefiPayloadPkgX64/UniversalPayload.fit
+
+# Edk2boot + UefiUniversalPayload
+ELF Edk2boot use below way to support compress and sign.
+
+- ELF Behavior - Edk2boot + UefiUniversalPayload.elf
+  ```
+  Boot Flow
+  +-------------------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------+-------------------+
+  | Platform Init                                                                       | Universal Loader Interface                                                                                | OS                |
+  +-------------------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------+-------------------+
+                                                                                                                                                                     HOBs
+  SEC -> PEI -> DXE -> DXE IPL -> UefiPayloadPkg\PayloadLoaderPeim\PayloadLoaderPeim.c ------------------------------------------------------------------------------------> Load UniversalPayload.elf -> Operation System
+
+
+  | Platform Initialize - Edk2                                                                                                                                                                      | UniversalPayload - Edk2        |
+  +-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------+
+
+  Binary Format
+
+  +-------------------+
+  | BIOS.rom          |
+  +-------------------+
+  | Other Firmware    |
+  +-------------------+
+  | ...               |  FMMT                                                                                                                                                                        UniversalPayloadBuild.py
+  +-------------------+<----------------+-----------------------+  GenFfs    +-----------------------+  Rsa2048Sha256 Sign +-----------------------+  LzmaCompress +----------------------+  GenSec +--------------------------------+
+  |                   |                 | EDK2 FFS Header       |<-----------| Rsa2048Sha256 Hash    |<--------------------| UniversalPayload.lzma |<--------------| EDK2 SEC Header      |<--------| UniversalPayload.elf           |
+  | RAW Data          |                 +-----------------------+            +-----------------------+                     +-----------------------+               +----------------------+         +--------------------------------+
+  |                   |                 | Rsa2048Sha256 Hash    |            | UniversalPayload.lzma |                                                             | UniversalPayload.elf |         | upld_info                      |
+  |                   |                 +-----------------------+            +-----------------------+                                                             +----------------------+         +--------------------------------+
+  |                   |                 | UniversalPayload.lzma |                                                                                                  | upld_info            |         | upld.uefi_fv                   |
+  +-------------------+<----------------+-----------------------+                                                                                                  +----------------------+         +--------------------------------+
+  | ...               |                                                                                                                                            | upld.uefi_fv         |         | upld.bds_fv                    |
+  +-------------------+                                                                                                                                            +----------------------+         +--------------------------------+
+  | Other Firmware    |                                                                                                                                            | upld.bds_fv          |         | upld.AFP1                      |
+  +-------------------+                                                                                                                                            +----------------------+         +--------------------------------+
+                                                                                                                                                                   | upld.AFP1            |         | upld.AFP2                      |
+                                                                                                                                                                   +----------------------+         +--------------------------------+
+                                                                                                                                                                   | upld.AFP2            |         | ...                            |
+                                                                                                                                                                   +----------------------+         +--------------------------------+
+                                                                                                                                                                   | ...                  |         | upld.AFPn                      |
+                                                                                                                                                                   +----------------------+         +--------------------------------+
+                                                                                                                                                                   | upld.AFPn            |
+                                                                                                                                                                   +----------------------+
+  ```
+
+FIT Edk2boot use below way to support compress and sign
+- FIT Behavior - Edk2boot + UefiUniversalPayload.fit
+  ```
+  Boot Flow
+  +-------------------------------------------------------------------------------------+------------------------------------------------------------------------+-------------------+
+  | Platform Init                                                                       | Universal Loader Interface                                             | OS                |
+  +-------------------------------------------------------------------------------------+------------------------------------------------------------------------+-------------------+
+                                                                                                      HOBs
+  SEC -> PEI -> DXE -> DXE IPL -> *UefiPayloadPkg\PayloadLoaderPeim\PayloadLoaderPeim.c ----------------------------------------------> Load UniversalPayload.fit -> Operation System
+
+  Binary Format
+
+  | Platform Initialize - Edk2                                                                                                | UniversalPayload - Edk2 (UniversalPayloadBuild.py --Fit)                                |
+  +---------------------------------------------------------------------------------------------------------------------------+-----------------------------------------------------------------------------------------+
+
+  +-------------------+
+  | BIOS.rom          |
+  +-------------------+
+  | Other Firmware    |
+  +-------------------+
+  | ...               |  FMMT                                                                                                  UniversalPayloadBuild.py --Fit    tianocore -> data-offset
+  +-------------------+<----------------+--------------------------------+  GenFfs +--------------------------------+  GenSec +--------------------------------+ tianocore -> reloc-start +--------------------------+
+  |                   |                 | EDK2 FFS Header                |<--------| EDK2 SEC Header                |<--------| FIT Header                     |<-------------------------| UniversalPayload.pecoff  |
+  |                   |                 +--------------------------------+         +--------------------------------+         | description = "Uefi Payload";  |                          +--------------------------+
+  |                   |                 | EDK2 SEC Header                |         | FIT Header                     |         | ...                            |
+  | RAW Data          |                 +--------------------------------+         |                                |         | images {                       | uefi-fv -> data-offset   +--------------------------+
+  |                   |                 | FIT Header                     |         |                                |         |   tianocore {...};             |<-------------------------| uefi_fv                  |
+  |                   |                 |                                |         +--------------------------------+         |   uefi-fv {...};               | bds-fv -> data-offset    +--------------------------+
+  |                   |                 |                                |         | tianocore -> data              |         |   bds-fv {...};                |<-------------------------| bds_fv                   |
+  |                   |                 +--------------------------------+         +--------------------------------+         |   afp1-fv {...};               | AFP1 -> data-offset      +--------------------------+
+  |                   |                 | tianocore -> data              |         | tianocore -> reloc-start       |         |   ...                          |<-------------------------| AFP1                     |
+  |                   |                 +--------------------------------+         +--------------------------------+         |   afpn-fv {...};               | AFP2 -> data-offset      +--------------------------+
+  |                   |                 | tianocore -> reloc-start       |         | uefi-fv -> data                |         | }                              |<-------------------------| AFP2                     |
+  |                   |                 +--------------------------------+         +--------------------------------+         | configurations {               | ...                      +--------------------------+
+  |                   |                 | uefi-fv -> data                |         | bds-fv -> data                 |         |   conf-1 {...}                 |<-------------------------| ...                      |
+  |                   |                 +--------------------------------+         +--------------------------------+         | }                              | AFPn -> data-offset      +--------------------------+
+  |                   |                 | bds-fv -> data                 |         | AFP1-fv -> data                |         |                                |<-------------------------| AFPn                     |
+  |                   |                 +--------------------------------+         +--------------------------------+         |                                |                          +--------------------------+
+  |                   |                 | AFP1-fv -> data                |         | AFP2-fv -> data                |         |                                |
+  |                   |                 +--------------------------------+         +--------------------------------+         +--------------------------------+
+  |                   |                 | AFP2-fv -> data                |         | ...                            |         | tianocore -> data              |
+  |                   |                 +--------------------------------+         +--------------------------------+         +--------------------------------+
+  |                   |                 | ...                            |         | AFPn-fv -> data                |         | tianocore -> reloc-start       |
+  |                   |                 +--------------------------------+         +--------------------------------+         +--------------------------------+
+  |                   |                 | AFPn-fv -> data                |                                                    | uefi-fv -> data                |
+  +-------------------+<----------------+--------------------------------+                                                    +--------------------------------+
+  | ...               |                                                                                                       | bds-fv -> data                 |
+  +-------------------+                                                                                                       +--------------------------------+
+  | Other Firmware    |                                                                                                       | AFP1-fv -> data                |
+  +-------------------+                                                                                                       +--------------------------------+
+                                                                                                                              | AFP2-fv -> data                |
+                                                                                                                              +--------------------------------+
+                                                                                                                              | ...                            |
+                                                                                                                              +--------------------------------+
+                                                                                                                              | AFPn-fv -> data                |
+                                                                                                                              +--------------------------------+
+
+  ```
diff --git a/UefiPayloadPkg/Tools/MkFitImage.py b/UefiPayloadPkg/Tools/MkFitImage.py
new file mode 100644
index 0000000000..82ab933d6d
--- /dev/null
+++ b/UefiPayloadPkg/Tools/MkFitImage.py
@@ -0,0 +1,272 @@
+## @file
+# This file is a script to build fit image.
+# It generate a dtb header and combine a binary file after this header.
+#
+# Copyright (c) 2023, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+##
+
+from os.path import exists
+import libfdt
+from ctypes import *
+import time
+
+class FIT_IMAGE_INFO_HEADER:
+    """Class for user setting data to use MakeFitImage()
+    """
+    _pack_ = 1
+    _fields_ = [
+        ('Compatible',    str),
+        ('UplVersion',    int),
+        ('Description',   str),
+        ('Type',          str),
+        ('Arch',          str),
+        ('Compression',   str),
+        ('Revision',      int),
+        ('BuildType',     str),
+        ('Capabilities',  str),
+        ('Producer',      str),
+        ('ImageId',       str),
+        ('DataOffset',    int),
+        ('DataSize',      int),
+        ('RelocStart',    int),
+        ('LoadAddr',      int),
+        ('Entry',         int),
+        ('Binary',        str),
+        ('TargetPath',    str),
+        ('UefifvPath',    str),
+        ('BdsfvPath',     str),
+        ('NetworkfvPath', str),
+        ('Project',       str),
+        ]
+
+    def __init__(self):
+        self.Compatible     = 'universal-payload'
+        self.UplVersion     = 0x0100
+        self.TargetPath     = 'mkimage.fit'
+
+def CreatFdt(Fdt):
+    FdtEmptyTree = libfdt.fdt_create_empty_tree(Fdt, len(Fdt))
+    if FdtEmptyTree != 0:
+        print('\n- Failed - Create Fdt failed!')
+        return False
+    return True
+
+def BuildConfNode(Fdt, ParentNode, MultiImage):
+    ConfNode1     = libfdt.fdt_add_subnode(Fdt, ParentNode, 'conf-1')
+
+    libfdt.fdt_setprop(Fdt, ConfNode1, 'require-fit', b'', 0)
+    libfdt.fdt_setprop(Fdt, ConfNode1, 'firmware', bytes('tianocore', 'utf-8'), len('tianocore') + 1)
+
+def BuildFvImageNode(Fdt, InfoHeader, ParentNode, DataOffset, DataSize, Description):
+    libfdt.fdt_setprop_u32(Fdt, ParentNode, 'data-size', DataSize)
+    libfdt.fdt_setprop_u32(Fdt, ParentNode, 'data-offset', DataOffset)
+    libfdt.fdt_setprop(Fdt, ParentNode, 'compression', bytes('none',                'utf-8'), len('none') + 1)
+    libfdt.fdt_setprop(Fdt, ParentNode, 'project ',    bytes('tianocore',           'utf-8'), len('tianocore') + 1)
+    libfdt.fdt_setprop(Fdt, ParentNode, 'arch',        bytes('x86_64',              'utf-8'), len('x86_64') + 1)
+    libfdt.fdt_setprop(Fdt, ParentNode, 'type',        bytes('flat-binary',         'utf-8'), len('flat-binary') + 1)
+    libfdt.fdt_setprop(Fdt, ParentNode, 'description', bytes(Description,           'utf-8'), len(Description) + 1)
+
+def BuildTianoImageNode(Fdt, InfoHeader, ParentNode, DataOffset, DataSize, Description):
+    #
+    # Set 'load' and 'data-offset' to reserve the memory first.
+    # They would be set again when Fdt completes or this function parses target binary file.
+    #
+    if InfoHeader.LoadAddr is not None:
+        libfdt.fdt_setprop_u64(Fdt, ParentNode, 'load', InfoHeader.LoadAddr)
+    if InfoHeader.Entry is not None:
+        libfdt.fdt_setprop_u64(Fdt, ParentNode, 'entry-start', InfoHeader.Entry)
+    if InfoHeader.RelocStart is not None:
+        libfdt.fdt_setprop_u32(Fdt, ParentNode, 'reloc-start', InfoHeader.RelocStart)
+    if InfoHeader.DataSize is not None:
+       libfdt.fdt_setprop_u32(Fdt, ParentNode, 'data-size', DataSize)
+    if InfoHeader.DataOffset is not None:
+        libfdt.fdt_setprop_u32(Fdt, ParentNode, 'data-offset', DataOffset)
+    if InfoHeader.Producer is not None:
+        libfdt.fdt_setprop(Fdt, ParentNode, 'producer ', bytes(InfoHeader.Producer, 'utf-8'), len(InfoHeader.Producer) + 1)
+    if InfoHeader.Capabilities is not None:
+        CapStrs = ','.join(InfoHeader.Capabilities)
+        libfdt.fdt_setprop(Fdt, ParentNode, 'capabilities ', bytes(CapStrs, 'utf-8'), len(CapStrs) + 1)
+    if InfoHeader.Type is not None:
+        libfdt.fdt_setprop(Fdt, ParentNode, 'type ', bytes(InfoHeader.Type, 'utf-8'), len(InfoHeader.Type) + 1)
+    if InfoHeader.Arch is not None:
+        libfdt.fdt_setprop(Fdt, ParentNode, 'arch ', bytes(InfoHeader.Arch, 'utf-8'), len(InfoHeader.Arch) + 1)
+    if InfoHeader.Project is not None:
+        libfdt.fdt_setprop(Fdt, ParentNode, 'project ', bytes(InfoHeader.Project, 'utf-8'), len(InfoHeader.Project) + 1)
+    if InfoHeader.Description is not None:
+        libfdt.fdt_setprop(Fdt, ParentNode, 'description', bytes(Description, 'utf-8'), len(Description) + 1)
+
+#
+# The subnode would be inserted from bottom to top of structure block.
+#
+def BuildFitImage(Fdt, InfoHeader):
+    MultiImage = [
+        ["tianocore",   InfoHeader.Binary,        BuildTianoImageNode , InfoHeader.Description,     None, 0 ],
+        ["uefi-fv",     InfoHeader.UefifvPath,    BuildFvImageNode,     "UEFI Firmware Volume",     None, 0 ],
+        ["bds-fv",      InfoHeader.BdsfvPath,     BuildFvImageNode ,    "BDS Firmware Volume",      None, 0 ],
+        ["network-fv",  InfoHeader.NetworkfvPath, BuildFvImageNode ,    "Network Firmware Volume",  None, 0 ],
+    ]
+
+    #
+    # Set basic information
+    #
+    libfdt.fdt_setprop_u32(Fdt, 0, 'build-revision ', InfoHeader.Revision)
+    libfdt.fdt_setprop_u32(Fdt, 0, 'spec-version', InfoHeader.UplVersion)
+
+    #
+    # Build configurations node
+    #
+    ConfNode  = libfdt.fdt_add_subnode(Fdt, 0, 'configurations')
+    BuildConfNode(Fdt, ConfNode, MultiImage)
+
+    # Build image
+    DataOffset = InfoHeader.DataOffset
+    for Index in range (0, len (MultiImage)):
+        _, Path, _, _, _, _ = MultiImage[Index]
+        if exists(Path) == 1:
+            TempBinary = open(Path, 'rb')
+            BinaryData = TempBinary.read()
+            TempBinary.close()
+            MultiImage[Index][-2] = BinaryData
+            MultiImage[Index][-1] = DataOffset
+            DataOffset += len (BinaryData)
+    libfdt.fdt_setprop_u32(Fdt, 0, 'size', DataOffset)
+    posix_time = int(time.time())
+    libfdt.fdt_setprop_u32(Fdt, 0, 'timestamp', posix_time)
+    DescriptionFit = 'Uefi OS Loader'
+    libfdt.fdt_setprop(Fdt, 0, 'description', bytes(DescriptionFit, 'utf-8'), len(DescriptionFit) + 1)
+
+    ImageNode = libfdt.fdt_add_subnode(Fdt, 0, 'images')
+    for Item in reversed (MultiImage):
+        Name, Path, BuildFvNode, Description, BinaryData, DataOffset = Item
+        FvNode = libfdt.fdt_add_subnode(Fdt, ImageNode, Name)
+        BuildFvNode (Fdt, InfoHeader, FvNode, DataOffset, len(BinaryData), Description)
+
+    #
+    # Create new image file and combine all binary.
+    #
+    DtbFile = open(InfoHeader.TargetPath, "wb")
+    DtbFile.truncate()
+    DtbFile.write(Fdt)
+    for Item in MultiImage:
+        _, _, _, _, BinaryData, _ = Item
+        DtbFile.write(BinaryData)
+    DtbFile.close()
+
+    return True
+
+def MakeFitImage(InfoHeader):
+    #
+    # Allocate fdt byte array.
+    #
+    Fdt = bytearray(InfoHeader.DataOffset)
+
+    #
+    # Create fdt empty tree.
+    #
+    if CreatFdt(Fdt) is False:
+        return False
+
+    #
+    # Parse args to build fit image.
+    #
+    return BuildFitImage(Fdt, InfoHeader)
+
+def ReplaceFv (UplBinary, SectionFvFile, SectionName):
+    try:
+        #
+        # Get Original Multi Fv
+        #
+        with open (UplBinary, "rb") as File:
+            Dtb = File.read ()
+        Fit          = libfdt.Fdt (Dtb)
+        NewFitHeader = bytearray(Dtb[0:Fit.totalsize()])
+        FitSize      = len(Dtb)
+
+        LoadablesList = []
+        ImagesNode    = libfdt.fdt_subnode_offset(NewFitHeader, 0, 'images')
+        FvNode        = libfdt.fdt_subnode_offset(NewFitHeader, ImagesNode, 'uefi-fv')
+        NodeDepth     = libfdt.fdt_node_depth (NewFitHeader, ImagesNode)
+        node_name     = libfdt.fdt_get_name(NewFitHeader, FvNode)
+        FvNode        = libfdt.fdt_next_node(NewFitHeader, FvNode, NodeDepth)
+
+        while node_name[0][-2:] == 'fv':
+            LoadablesList.append (node_name[0])
+            node_name = libfdt.fdt_get_name(NewFitHeader, FvNode[0])
+            FvNode = libfdt.fdt_next_node(NewFitHeader, FvNode[0], NodeDepth)
+        #
+        # Get current Fit Binary FV data
+        #
+        MultiFvList = []
+        for Item in LoadablesList:
+            ImageNode    = libfdt.fdt_subnode_offset(NewFitHeader, ImagesNode, Item)
+            ImageOffset  = int.from_bytes (libfdt.fdt_getprop (NewFitHeader, ImageNode, 'data-offset')[0], 'big')
+            ImageSize    = int.from_bytes (libfdt.fdt_getprop (NewFitHeader, ImageNode, 'data-size')[0], 'big')
+            MultiFvList.append ([Item, Dtb[ImageOffset:ImageOffset + ImageSize]])
+
+        IsFvExist = False
+        for Index in range (0, len (MultiFvList)):
+            if MultiFvList[Index][0] == SectionName:
+                with open (SectionFvFile, 'rb') as File:
+                    MultiFvList[Index][1] = File.read ()
+                ImageNode     = libfdt.fdt_subnode_offset(NewFitHeader, ImagesNode, SectionName)
+                ImageSize     = int.from_bytes (libfdt.fdt_getprop (NewFitHeader, ImageNode, 'data-size')[0], 'big')
+                ReplaceOffset = int.from_bytes (libfdt.fdt_getprop (NewFitHeader, ImageNode, 'data-offset')[0], 'big')
+                OffsetDelta   = len(MultiFvList[Index][1]) - ImageSize
+                FitSize      += OffsetDelta
+                IsFvExist     = True
+                libfdt.fdt_setprop_u32(NewFitHeader, ImageNode, 'data-size', len(MultiFvList[Index][1]))
+
+        #
+        # Update new fit header
+        #
+        ImagesNode = libfdt.fdt_subnode_offset(NewFitHeader, 0, 'images')
+        if (IsFvExist == False):
+            with open (SectionFvFile, 'rb') as File:
+                SectionFvFileBinary = File.read ()
+            MultiFvList.append ([SectionName, SectionFvFileBinary])
+            FvNode = libfdt.fdt_add_subnode(NewFitHeader, ImagesNode, SectionName)
+            BuildFvImageNode (NewFitHeader, None, FvNode, FitSize, len(SectionFvFileBinary), SectionName + " Firmware Volume")
+            FitSize += len(SectionFvFileBinary)
+        else:
+            for Index in range (0, len (MultiFvList)):
+                ImageNode    = libfdt.fdt_subnode_offset(NewFitHeader, ImagesNode, MultiFvList[Index][0])
+                ImageOffset  = int.from_bytes (libfdt.fdt_getprop (NewFitHeader, ImageNode, 'data-offset')[0], 'big')
+                if ImageOffset > ReplaceOffset:
+                    libfdt.fdt_setprop_u32(NewFitHeader, ImageNode, 'data-offset', ImageOffset + OffsetDelta)
+
+        ConfNodes     = libfdt.fdt_subnode_offset(NewFitHeader, 0, 'configurations')
+        libfdt.fdt_setprop(NewFitHeader, ConfNodes, 'default ', bytes('conf-1', 'utf-8'), len('conf-1') + 1)
+        ConfNode      = libfdt.fdt_subnode_offset(NewFitHeader, ConfNodes, 'conf-1')
+
+        libfdt.fdt_setprop_u32(NewFitHeader, 0, 'size', FitSize)
+
+        #
+        # Generate new fit image
+        #
+        ImagesNode    = libfdt.fdt_subnode_offset(NewFitHeader, 0, 'images')
+        TianoNode     = libfdt.fdt_subnode_offset(NewFitHeader, ImagesNode, 'tianocore')
+        TianoOffset   = int.from_bytes (libfdt.fdt_getprop (NewFitHeader, TianoNode, 'data-offset')[0], 'big')
+        TianoSize     = int.from_bytes (libfdt.fdt_getprop (NewFitHeader, TianoNode, 'data-size')[0], 'big')
+        TianoBinary   = Dtb[TianoOffset:TianoOffset + TianoSize]
+
+        print("\nGenerate new fit image:")
+        NewUplBinary = bytearray(FitSize)
+        print("Update fit header\t to 0x0\t\t ~ " + str(hex(len(NewFitHeader))))
+        NewUplBinary[:len(NewFitHeader)] = NewFitHeader
+        print("Update tiano image\t to " + str(hex(len(NewFitHeader))) + "\t ~ " + str(hex(len(NewFitHeader) + len(TianoBinary))))
+        NewUplBinary[len(NewFitHeader):len(NewFitHeader) + len(TianoBinary)] = TianoBinary
+        for Index in range (0, len (MultiFvList)):
+            ImageNode   = libfdt.fdt_subnode_offset(NewFitHeader, ImagesNode, MultiFvList[Index][0])
+            ImageOffset = int.from_bytes (libfdt.fdt_getprop (NewFitHeader, ImageNode, 'data-offset')[0], 'big')
+            ImageSize   = int.from_bytes (libfdt.fdt_getprop (NewFitHeader, ImageNode, 'data-size')[0], 'big')
+            NewUplBinary[ImageOffset:ImageOffset + ImageSize] = MultiFvList[Index][1]
+            print("Update " + MultiFvList[Index][0] + "\t\t to " + str(hex(ImageOffset)) + "\t ~ " + str(hex(ImageOffset + ImageSize)))
+
+        with open (UplBinary, "wb") as File:
+            File.write (NewUplBinary)
+
+        return 0
+    except Exception as Ex:
+        print(Ex)
+        return 1
diff --git a/UefiPayloadPkg/UefiPayloadEntry/FitUniversalPayloadEntry.c b/UefiPayloadPkg/UefiPayloadEntry/FitUniversalPayloadEntry.c
new file mode 100644
index 0000000000..ad04ad7eb9
--- /dev/null
+++ b/UefiPayloadPkg/UefiPayloadEntry/FitUniversalPayloadEntry.c
@@ -0,0 +1,654 @@
+/** @file
+  Copyright (c) 2023, Intel Corporation. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include "UefiPayloadEntry.h"
+#include <Library/FdtLib.h>
+#include <Guid/UniversalPayloadBase.h>
+
+#define MEMORY_ATTRIBUTE_MASK  (EFI_RESOURCE_ATTRIBUTE_PRESENT             |        \
+                                       EFI_RESOURCE_ATTRIBUTE_INITIALIZED         | \
+                                       EFI_RESOURCE_ATTRIBUTE_TESTED              | \
+                                       EFI_RESOURCE_ATTRIBUTE_READ_PROTECTED      | \
+                                       EFI_RESOURCE_ATTRIBUTE_WRITE_PROTECTED     | \
+                                       EFI_RESOURCE_ATTRIBUTE_EXECUTION_PROTECTED | \
+                                       EFI_RESOURCE_ATTRIBUTE_READ_ONLY_PROTECTED | \
+                                       EFI_RESOURCE_ATTRIBUTE_16_BIT_IO           | \
+                                       EFI_RESOURCE_ATTRIBUTE_32_BIT_IO           | \
+                                       EFI_RESOURCE_ATTRIBUTE_64_BIT_IO           | \
+                                       EFI_RESOURCE_ATTRIBUTE_PERSISTENT          )
+
+#define TESTED_MEMORY_ATTRIBUTES  (EFI_RESOURCE_ATTRIBUTE_PRESENT     |     \
+                                       EFI_RESOURCE_ATTRIBUTE_INITIALIZED | \
+                                       EFI_RESOURCE_ATTRIBUTE_TESTED      )
+
+extern VOID  *mHobList;
+
+CHAR8  *mLineBuffer = NULL;
+
+/**
+  Print all HOBs info from the HOB list.
+  @return The pointer to the HOB list.
+**/
+VOID
+PrintHob (
+  IN CONST VOID  *HobStart
+  );
+
+/**
+  Find the first substring.
+  @param  String    Point to the string where to find the substring.
+  @param  CharSet   Point to the string to be found.
+**/
+UINTN
+EFIAPI
+AsciiStrSpn (
+  IN CHAR8  *String,
+  IN CHAR8  *CharSet
+  )
+{
+  UINTN  Count;
+  CHAR8  *Str1;
+  CHAR8  *Str2;
+
+  Count = 0;
+
+  for (Str1 = String; *Str1 != L'\0'; Str1++) {
+    for (Str2 = CharSet; *Str2 != L'\0'; Str2++) {
+      if (*Str1 == *Str2) {
+        break;
+      }
+    }
+
+    if (*Str2 == L'\0') {
+      return Count;
+    }
+
+    Count++;
+  }
+
+  return Count;
+}
+
+/**
+  Searches a string for the first occurrence of a character contained in a
+  specified buffer.
+  @param  String    Point to the string where to find the substring.
+  @param  CharSet   Point to the string to be found.
+**/
+CHAR8 *
+EFIAPI
+AsciiStrBrk (
+  IN CHAR8  *String,
+  IN CHAR8  *CharSet
+  )
+{
+  CHAR8  *Str1;
+  CHAR8  *Str2;
+
+  for (Str1 = String; *Str1 != L'\0'; Str1++) {
+    for (Str2 = CharSet; *Str2 != L'\0'; Str2++) {
+      if (*Str1 == *Str2) {
+        return (CHAR8 *)Str1;
+      }
+    }
+  }
+
+  return NULL;
+}
+
+/**
+  Find the next token after one or more specified characters.
+  @param  String    Point to the string where to find the substring.
+  @param  CharSet   Point to the string to be found.
+**/
+CHAR8 *
+EFIAPI
+AsciiStrTokenLine (
+  IN CHAR8  *String OPTIONAL,
+  IN CHAR8  *CharSet
+  )
+{
+  CHAR8  *Begin;
+  CHAR8  *End;
+
+  Begin = (String == NULL) ? mLineBuffer : String;
+  if (Begin == NULL) {
+    return NULL;
+  }
+
+  Begin += AsciiStrSpn (Begin, CharSet);
+  if (*Begin == L'\0') {
+    mLineBuffer = NULL;
+    return NULL;
+  }
+
+  End = AsciiStrBrk (Begin, CharSet);
+  if ((End != NULL) && (*End != L'\0')) {
+    *End = L'\0';
+    End++;
+  }
+
+  mLineBuffer = End;
+  return Begin;
+}
+
+/**
+  Some bootloader may pass a pcd database, and UPL also contain a PCD database.
+  Dxe PCD driver has the assumption that the two PCD database can be catenated and
+  the local token number should be successive.
+  This function will fix up the UPL PCD database to meet that assumption.
+  @param[in]   DxeFv         The FV where to find the Universal PCD database.
+  @retval EFI_SUCCESS        If it completed successfully.
+  @retval other              Failed to fix up.
+**/
+EFI_STATUS
+FixUpPcdDatabase (
+  IN  EFI_FIRMWARE_VOLUME_HEADER  *DxeFv
+  )
+{
+  EFI_STATUS           Status;
+  EFI_FFS_FILE_HEADER  *FileHeader;
+  VOID                 *PcdRawData;
+  PEI_PCD_DATABASE     *PeiDatabase;
+  PEI_PCD_DATABASE     *UplDatabase;
+  EFI_HOB_GUID_TYPE    *GuidHob;
+  DYNAMICEX_MAPPING    *ExMapTable;
+  UINTN                Index;
+
+  GuidHob = GetFirstGuidHob (&gPcdDataBaseHobGuid);
+  if (GuidHob == NULL) {
+    //
+    // No fix-up is needed.
+    //
+    return EFI_SUCCESS;
+  }
+
+  PeiDatabase = (PEI_PCD_DATABASE *)GET_GUID_HOB_DATA (GuidHob);
+  DEBUG ((DEBUG_INFO, "Find the Pei PCD data base, the total local token number is %d\n", PeiDatabase->LocalTokenCount));
+
+  Status = FvFindFileByTypeGuid (DxeFv, EFI_FV_FILETYPE_DRIVER, PcdGetPtr (PcdPcdDriverFile), &FileHeader);
+  ASSERT_EFI_ERROR (Status);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  Status = FileFindSection (FileHeader, EFI_SECTION_RAW, &PcdRawData);
+  ASSERT_EFI_ERROR (Status);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  UplDatabase = (PEI_PCD_DATABASE *)PcdRawData;
+  ExMapTable  = (DYNAMICEX_MAPPING *)(UINTN)((UINTN)PcdRawData + UplDatabase->ExMapTableOffset);
+
+  for (Index = 0; Index < UplDatabase->ExTokenCount; Index++) {
+    ExMapTable[Index].TokenNumber += PeiDatabase->LocalTokenCount;
+  }
+
+  DEBUG ((DEBUG_INFO, "Fix up UPL PCD database successfully\n"));
+  return EFI_SUCCESS;
+}
+
+/**
+  Add HOB into HOB list
+  @param[in]  Hob    The HOB to be added into the HOB list.
+**/
+VOID
+AddNewHob (
+  IN EFI_PEI_HOB_POINTERS  *Hob
+  )
+{
+  EFI_PEI_HOB_POINTERS  NewHob;
+
+  if (Hob->Raw == NULL) {
+    return;
+  }
+
+  NewHob.Header = CreateHob (Hob->Header->HobType, Hob->Header->HobLength);
+
+  if (NewHob.Header != NULL) {
+    CopyMem (NewHob.Header + 1, Hob->Header + 1, Hob->Header->HobLength - sizeof (EFI_HOB_GENERIC_HEADER));
+  }
+}
+
+/**
+  Found the Resource Descriptor HOB that contains a range (Base, Top)
+  @param[in] HobList    Hob start address
+  @param[in] Base       Memory start address
+  @param[in] Top        Memory end address.
+  @retval     The pointer to the Resource Descriptor HOB.
+**/
+EFI_HOB_RESOURCE_DESCRIPTOR *
+FindResourceDescriptorByRange (
+  IN VOID                  *HobList,
+  IN EFI_PHYSICAL_ADDRESS  Base,
+  IN EFI_PHYSICAL_ADDRESS  Top
+  )
+{
+  EFI_PEI_HOB_POINTERS         Hob;
+  EFI_HOB_RESOURCE_DESCRIPTOR  *ResourceHob;
+
+  for (Hob.Raw = (UINT8 *)HobList; !END_OF_HOB_LIST (Hob); Hob.Raw = GET_NEXT_HOB (Hob)) {
+    //
+    // Skip all HOBs except Resource Descriptor HOBs
+    //
+    if (GET_HOB_TYPE (Hob) != EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {
+      continue;
+    }
+
+    //
+    // Skip Resource Descriptor HOBs that do not describe tested system memory
+    //
+    ResourceHob = Hob.ResourceDescriptor;
+    if (ResourceHob->ResourceType != EFI_RESOURCE_SYSTEM_MEMORY) {
+      continue;
+    }
+
+    if ((ResourceHob->ResourceAttribute & MEMORY_ATTRIBUTE_MASK) != TESTED_MEMORY_ATTRIBUTES) {
+      continue;
+    }
+
+    //
+    // Skip Resource Descriptor HOBs that do not contain the PHIT range EfiFreeMemoryBottom..EfiFreeMemoryTop
+    //
+    if (Base < ResourceHob->PhysicalStart) {
+      continue;
+    }
+
+    if (Top > (ResourceHob->PhysicalStart + ResourceHob->ResourceLength)) {
+      continue;
+    }
+
+    return ResourceHob;
+  }
+
+  return NULL;
+}
+
+/**
+  Find the highest below 4G memory resource descriptor, except the input Resource Descriptor.
+  @param[in] HobList                 Hob start address
+  @param[in] MinimalNeededSize       Minimal needed size.
+  @param[in] ExceptResourceHob       Ignore this Resource Descriptor.
+  @retval     The pointer to the Resource Descriptor HOB.
+**/
+EFI_HOB_RESOURCE_DESCRIPTOR *
+FindAnotherHighestBelow4GResourceDescriptor (
+  IN VOID                         *HobList,
+  IN UINTN                        MinimalNeededSize,
+  IN EFI_HOB_RESOURCE_DESCRIPTOR  *ExceptResourceHob
+  )
+{
+  EFI_PEI_HOB_POINTERS         Hob;
+  EFI_HOB_RESOURCE_DESCRIPTOR  *ResourceHob;
+  EFI_HOB_RESOURCE_DESCRIPTOR  *ReturnResourceHob;
+
+  ReturnResourceHob = NULL;
+
+  for (Hob.Raw = (UINT8 *)HobList; !END_OF_HOB_LIST (Hob); Hob.Raw = GET_NEXT_HOB (Hob)) {
+    //
+    // Skip all HOBs except Resource Descriptor HOBs
+    //
+    if (GET_HOB_TYPE (Hob) != EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {
+      continue;
+    }
+
+    //
+    // Skip Resource Descriptor HOBs that do not describe tested system memory
+    //
+    ResourceHob = Hob.ResourceDescriptor;
+    if (ResourceHob->ResourceType != EFI_RESOURCE_SYSTEM_MEMORY) {
+      continue;
+    }
+
+    if ((ResourceHob->ResourceAttribute & MEMORY_ATTRIBUTE_MASK) != TESTED_MEMORY_ATTRIBUTES) {
+      continue;
+    }
+
+    //
+    // Skip if the Resource Descriptor HOB equals to ExceptResourceHob
+    //
+    if (ResourceHob == ExceptResourceHob) {
+      continue;
+    }
+
+    //
+    // Skip Resource Descriptor HOBs that are beyond 4G
+    //
+    if ((ResourceHob->PhysicalStart + ResourceHob->ResourceLength) > BASE_4GB) {
+      continue;
+    }
+
+    //
+    // Skip Resource Descriptor HOBs that are too small
+    //
+    if (ResourceHob->ResourceLength < MinimalNeededSize) {
+      continue;
+    }
+
+    //
+    // Return the topest Resource Descriptor
+    //
+    if (ReturnResourceHob == NULL) {
+      ReturnResourceHob = ResourceHob;
+    } else {
+      if (ReturnResourceHob->PhysicalStart < ResourceHob->PhysicalStart) {
+        ReturnResourceHob = ResourceHob;
+      }
+    }
+  }
+
+  return ReturnResourceHob;
+}
+
+/**
+  Check the HOB and decide if it is need inside Payload
+  Payload maintainer may make decision which HOB is need or needn't
+  Then add the check logic in the function.
+  @param[in] Hob The HOB to check
+  @retval TRUE  If HOB is need inside Payload
+  @retval FALSE If HOB is needn't inside Payload
+**/
+BOOLEAN
+IsHobNeed (
+  EFI_PEI_HOB_POINTERS  Hob
+  )
+{
+  if (Hob.Header->HobType == EFI_HOB_TYPE_HANDOFF) {
+    return FALSE;
+  }
+
+  if (Hob.Header->HobType == EFI_HOB_TYPE_MEMORY_ALLOCATION) {
+    if (CompareGuid (&Hob.MemoryAllocationModule->MemoryAllocationHeader.Name, &gEfiHobMemoryAllocModuleGuid)) {
+      return FALSE;
+    }
+  }
+
+  // Arrive here mean the HOB is need
+  return TRUE;
+}
+
+/**
+  It will build Fv HOBs based on information from bootloaders.
+  @param[out] DxeFv          The pointer to the DXE FV in memory.
+  @retval EFI_SUCCESS        If it completed successfully.
+  @retval EFI_NOT_FOUND      If it failed to find node in fit image.
+  @retval Others             If it failed to build required HOBs.
+**/
+EFI_STATUS
+BuildFitLoadablesFvHob (
+  OUT EFI_FIRMWARE_VOLUME_HEADER  **DxeFv
+  )
+{
+  EFI_STATUS              Status;
+  VOID                    *Fdt;
+  UINT8                   *GuidHob;
+  UNIVERSAL_PAYLOAD_BASE  *PayloadBase;
+  INT32                   ConfigNode;
+  INT32                   Config1Node;
+  INT32                   ImageNode;
+  INT32                   FvNode;
+  INT32                   Depth;
+  CONST FDT_PROPERTY      *PropertyPtr;
+  INT32                   TempLen;
+  CONST CHAR8             *Fvname;
+  UINT32                  DataOffset;
+  UINT32                  DataSize;
+  UINT32                  *Data32;
+
+  GuidHob = GetFirstGuidHob (&gUniversalPayloadBaseGuid);
+  if (GuidHob != NULL) {
+    PayloadBase = (UNIVERSAL_PAYLOAD_BASE *)GET_GUID_HOB_DATA (GuidHob);
+    Fdt         = (VOID *)(UINTN)PayloadBase->Entry;
+    DEBUG ((DEBUG_INFO, "PayloadBase Entry = 0x%08x\n", PayloadBase->Entry));
+  }
+
+  Status = FdtCheckHeader (Fdt);
+  if (EFI_ERROR (Status)) {
+    return EFI_UNSUPPORTED;
+  }
+
+  ConfigNode = FdtSubnodeOffsetNameLen (Fdt, 0, "configurations", (INT32)AsciiStrLen ("configurations"));
+  if (ConfigNode <= 0) {
+    return EFI_NOT_FOUND;
+  }
+
+  Config1Node = FdtSubnodeOffsetNameLen (Fdt, ConfigNode, "conf-1", (INT32)AsciiStrLen ("conf-1"));
+  if (Config1Node <= 0) {
+    return EFI_NOT_FOUND;
+  }
+
+  ImageNode = FdtSubnodeOffsetNameLen (Fdt, 0, "images", (INT32)AsciiStrLen ("images"));
+  if (ImageNode <= 0) {
+    return EFI_NOT_FOUND;
+  }
+
+  FvNode = FdtSubnodeOffsetNameLen (Fdt, ImageNode, "tianocore", (INT32)AsciiStrLen ("tianocore"));
+  Depth  = FdtNodeDepth (Fdt, FvNode);
+  FvNode = FdtNextNode (Fdt, FvNode, &Depth);
+  Fvname = FdtGetName (Fdt, FvNode, &TempLen);
+  while ((AsciiStrCmp ((Fvname + AsciiStrLen (Fvname) - 2), "fv") == 0)) {
+    if (FvNode <= 0) {
+      return EFI_NOT_FOUND;
+    }
+
+    PropertyPtr = FdtGetProperty (Fdt, FvNode, "data-offset", &TempLen);
+    Data32      = (UINT32 *)(PropertyPtr->Data);
+    DataOffset  = SwapBytes32 (*Data32);
+
+    PropertyPtr = FdtGetProperty (Fdt, FvNode, "data-size", &TempLen);
+    Data32      = (UINT32 *)(PropertyPtr->Data);
+    DataSize    = SwapBytes32 (*Data32);
+
+    if (AsciiStrCmp (Fvname, "uefi-fv") == 0) {
+      *DxeFv = (EFI_FIRMWARE_VOLUME_HEADER *)((UINTN)PayloadBase->Entry + (UINTN)DataOffset);
+      ASSERT ((*DxeFv)->FvLength == DataSize);
+    } else {
+      BuildFvHob (((UINTN)PayloadBase->Entry + (UINTN)DataOffset), DataSize);
+    }
+
+    DEBUG ((
+      DEBUG_INFO,
+      "UPL Multiple fv[%a], Base=0x%08x, size=0x%08x\n",
+      Fvname,
+      ((UINTN)PayloadBase->Entry + (UINTN)DataOffset),
+      DataSize,
+      DataOffset
+      ));
+    Depth  = FdtNodeDepth (Fdt, FvNode);
+    FvNode = FdtNextNode (Fdt, FvNode, &Depth);
+    Fvname = FdtGetName (Fdt, FvNode, &TempLen);
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  It will build HOBs based on information from bootloaders.
+  @param[in]  BootloaderParameter   The starting memory address of bootloader parameter block.
+  @param[out] DxeFv                 The pointer to the DXE FV in memory.
+  @retval EFI_SUCCESS        If it completed successfully.
+  @retval Others             If it failed to build required HOBs.
+**/
+EFI_STATUS
+BuildHobs (
+  IN  UINTN                       BootloaderParameter,
+  OUT EFI_FIRMWARE_VOLUME_HEADER  **DxeFv
+  )
+{
+  EFI_PEI_HOB_POINTERS          Hob;
+  UINTN                         MinimalNeededSize;
+  EFI_PHYSICAL_ADDRESS          FreeMemoryBottom;
+  EFI_PHYSICAL_ADDRESS          FreeMemoryTop;
+  EFI_PHYSICAL_ADDRESS          MemoryBottom;
+  EFI_PHYSICAL_ADDRESS          MemoryTop;
+  EFI_HOB_RESOURCE_DESCRIPTOR   *PhitResourceHob;
+  EFI_HOB_RESOURCE_DESCRIPTOR   *ResourceHob;
+  UINT8                         *GuidHob;
+  EFI_HOB_FIRMWARE_VOLUME       *FvHob;
+  UNIVERSAL_PAYLOAD_ACPI_TABLE  *AcpiTable;
+  ACPI_BOARD_INFO               *AcpiBoardInfo;
+  EFI_HOB_HANDOFF_INFO_TABLE    *HobInfo;
+
+  Hob.Raw           = (UINT8 *)BootloaderParameter;
+  MinimalNeededSize = FixedPcdGet32 (PcdSystemMemoryUefiRegionSize);
+
+  ASSERT (Hob.Raw != NULL);
+  ASSERT ((UINTN)Hob.HandoffInformationTable->EfiFreeMemoryTop == Hob.HandoffInformationTable->EfiFreeMemoryTop);
+  ASSERT ((UINTN)Hob.HandoffInformationTable->EfiMemoryTop == Hob.HandoffInformationTable->EfiMemoryTop);
+  ASSERT ((UINTN)Hob.HandoffInformationTable->EfiFreeMemoryBottom == Hob.HandoffInformationTable->EfiFreeMemoryBottom);
+  ASSERT ((UINTN)Hob.HandoffInformationTable->EfiMemoryBottom == Hob.HandoffInformationTable->EfiMemoryBottom);
+
+  //
+  // Try to find Resource Descriptor HOB that contains Hob range EfiMemoryBottom..EfiMemoryTop
+  //
+  PhitResourceHob = FindResourceDescriptorByRange (Hob.Raw, Hob.HandoffInformationTable->EfiMemoryBottom, Hob.HandoffInformationTable->EfiMemoryTop);
+  if (PhitResourceHob == NULL) {
+    //
+    // Boot loader's Phit Hob is not in an available Resource Descriptor, find another Resource Descriptor for new Phit Hob
+    //
+    ResourceHob = FindAnotherHighestBelow4GResourceDescriptor (Hob.Raw, MinimalNeededSize, NULL);
+    if (ResourceHob == NULL) {
+      return EFI_NOT_FOUND;
+    }
+
+    MemoryBottom     = ResourceHob->PhysicalStart + ResourceHob->ResourceLength - MinimalNeededSize;
+    FreeMemoryBottom = MemoryBottom;
+    FreeMemoryTop    = ResourceHob->PhysicalStart + ResourceHob->ResourceLength;
+    MemoryTop        = FreeMemoryTop;
+  } else if (PhitResourceHob->PhysicalStart + PhitResourceHob->ResourceLength - Hob.HandoffInformationTable->EfiMemoryTop >= MinimalNeededSize) {
+    //
+    // New availiable Memory range in new hob is right above memory top in old hob.
+    //
+    MemoryBottom     = Hob.HandoffInformationTable->EfiFreeMemoryTop;
+    FreeMemoryBottom = Hob.HandoffInformationTable->EfiMemoryTop;
+    FreeMemoryTop    = FreeMemoryBottom + MinimalNeededSize;
+    MemoryTop        = FreeMemoryTop;
+  } else if (Hob.HandoffInformationTable->EfiMemoryBottom - PhitResourceHob->PhysicalStart >= MinimalNeededSize) {
+    //
+    // New availiable Memory range in new hob is right below memory bottom in old hob.
+    //
+    MemoryBottom     = Hob.HandoffInformationTable->EfiMemoryBottom - MinimalNeededSize;
+    FreeMemoryBottom = MemoryBottom;
+    FreeMemoryTop    = Hob.HandoffInformationTable->EfiMemoryBottom;
+    MemoryTop        = Hob.HandoffInformationTable->EfiMemoryTop;
+  } else {
+    //
+    // In the Resource Descriptor HOB contains boot loader Hob, there is no enough free memory size for payload hob
+    // Find another Resource Descriptor Hob
+    //
+    ResourceHob = FindAnotherHighestBelow4GResourceDescriptor (Hob.Raw, MinimalNeededSize, PhitResourceHob);
+    if (ResourceHob == NULL) {
+      return EFI_NOT_FOUND;
+    }
+
+    MemoryBottom     = ResourceHob->PhysicalStart + ResourceHob->ResourceLength - MinimalNeededSize;
+    FreeMemoryBottom = MemoryBottom;
+    FreeMemoryTop    = ResourceHob->PhysicalStart + ResourceHob->ResourceLength;
+    MemoryTop        = FreeMemoryTop;
+  }
+
+  HobInfo           = HobConstructor ((VOID *)(UINTN)MemoryBottom, (VOID *)(UINTN)MemoryTop, (VOID *)(UINTN)FreeMemoryBottom, (VOID *)(UINTN)FreeMemoryTop);
+  HobInfo->BootMode = Hob.HandoffInformationTable->BootMode;
+  //
+  // From now on, mHobList will point to the new Hob range.
+  //
+
+  //
+  // Create an empty FvHob for the DXE FV that contains DXE core.
+  //
+  BuildFvHob ((EFI_PHYSICAL_ADDRESS)0, 0);
+  //
+  // Since payload created new Hob, move all hobs except PHIT from boot loader hob list.
+  //
+  while (!END_OF_HOB_LIST (Hob)) {
+    if (IsHobNeed (Hob)) {
+      // Add this hob to payload HOB
+      AddNewHob (&Hob);
+    }
+
+    Hob.Raw = GET_NEXT_HOB (Hob);
+  }
+
+  BuildFitLoadablesFvHob (DxeFv);
+
+  //
+  // Create guid hob for acpi board information
+  //
+  GuidHob = GetFirstGuidHob (&gUniversalPayloadAcpiTableGuid);
+  if (GuidHob != NULL) {
+    AcpiTable = (UNIVERSAL_PAYLOAD_ACPI_TABLE *)GET_GUID_HOB_DATA (GuidHob);
+    GuidHob   = GetFirstGuidHob (&gUefiAcpiBoardInfoGuid);
+    if (GuidHob == NULL) {
+      AcpiBoardInfo = BuildHobFromAcpi ((UINT64)AcpiTable->Rsdp);
+      ASSERT (AcpiBoardInfo != NULL);
+    }
+  }
+
+  //
+  // Update DXE FV information to first fv hob in the hob list, which
+  // is the empty FvHob created before.
+  //
+  FvHob              = GetFirstHob (EFI_HOB_TYPE_FV);
+  FvHob->BaseAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)*DxeFv;
+  FvHob->Length      = (*DxeFv)->FvLength;
+  return EFI_SUCCESS;
+}
+
+/**
+  Entry point to the C language phase of UEFI payload.
+  @param[in]   BootloaderParameter    The starting address of bootloader parameter block.
+  @retval      It will not return if SUCCESS, and return error when passing bootloader parameter.
+**/
+EFI_STATUS
+EFIAPI
+_ModuleEntryPoint (
+  IN UINTN  BootloaderParameter
+  )
+{
+  EFI_STATUS                  Status;
+  PHYSICAL_ADDRESS            DxeCoreEntryPoint;
+  EFI_PEI_HOB_POINTERS        Hob;
+  EFI_FIRMWARE_VOLUME_HEADER  *DxeFv;
+
+  mHobList = (VOID *)BootloaderParameter;
+  DxeFv    = NULL;
+  // Call constructor for all libraries
+  ProcessLibraryConstructorList ();
+
+  DEBUG ((DEBUG_INFO, "Entering Universal Payload...\n"));
+  DEBUG ((DEBUG_INFO, "sizeof(UINTN) = 0x%x\n", sizeof (UINTN)));
+
+  DEBUG_CODE (
+    //
+    // Dump the Hobs from boot loader
+    //
+    PrintHob (mHobList);
+    );
+
+  // Initialize floating point operating environment to be compliant with UEFI spec.
+  InitializeFloatingPointUnits ();
+
+  // Build HOB based on information from Bootloader
+  Status = BuildHobs (BootloaderParameter, &DxeFv);
+  ASSERT_EFI_ERROR (Status);
+
+  FixUpPcdDatabase (DxeFv);
+  Status = UniversalLoadDxeCore (DxeFv, &DxeCoreEntryPoint);
+  ASSERT_EFI_ERROR (Status);
+
+  //
+  // Mask off all legacy 8259 interrupt sources
+  //
+  IoWrite8 (LEGACY_8259_MASK_REGISTER_MASTER, 0xFF);
+  IoWrite8 (LEGACY_8259_MASK_REGISTER_SLAVE, 0xFF);
+
+  Hob.HandoffInformationTable = (EFI_HOB_HANDOFF_INFO_TABLE *)GetFirstHob (EFI_HOB_TYPE_HANDOFF);
+  HandOffToDxeCore (DxeCoreEntryPoint, Hob);
+
+  // Should not get here
+  CpuDeadLoop ();
+  return EFI_SUCCESS;
+}
diff --git a/UefiPayloadPkg/UefiPayloadEntry/FitUniversalPayloadEntry.inf b/UefiPayloadPkg/UefiPayloadEntry/FitUniversalPayloadEntry.inf
new file mode 100644
index 0000000000..01fb3aceb3
--- /dev/null
+++ b/UefiPayloadPkg/UefiPayloadEntry/FitUniversalPayloadEntry.inf
@@ -0,0 +1,98 @@
+## @file
+#  This is the first module for UEFI payload.
+#
+#  Copyright (c) 2023, Intel Corporation. All rights reserved.<BR>
+#
+#  SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+  INF_VERSION                    = 0x00010005
+  BASE_NAME                      = FitUniversalPayloadEntry
+  FILE_GUID                      = CED5A8A9-B6EA-4D5A-8689-577EE88566CF
+  MODULE_TYPE                    = SEC
+  VERSION_STRING                 = 1.0
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+#  VALID_ARCHITECTURES           = IA32 X64
+#
+
+[Sources]
+  FitUniversalPayloadEntry.c
+  LoadDxeCore.c
+  MemoryAllocation.c
+  PrintHob.c
+  AcpiTable.c
+
+[Sources.Ia32]
+  X64/VirtualMemory.h
+  X64/VirtualMemory.c
+  Ia32/DxeLoadFunc.c
+  Ia32/IdtVectorAsm.nasm
+
+[Sources.X64]
+  X64/VirtualMemory.h
+  X64/VirtualMemory.c
+  X64/DxeLoadFunc.c
+
+[Packages]
+  MdePkg/MdePkg.dec
+  MdeModulePkg/MdeModulePkg.dec
+  UefiCpuPkg/UefiCpuPkg.dec
+  UefiPayloadPkg/UefiPayloadPkg.dec
+
+[LibraryClasses]
+  BaseMemoryLib
+  DebugLib
+  BaseLib
+  SerialPortLib
+  IoLib
+  HobLib
+  PeCoffLib
+  CpuLib
+  FdtLib
+
+[Guids]
+  gEfiMemoryTypeInformationGuid
+  gEfiFirmwareFileSystem2Guid
+  gEfiGraphicsInfoHobGuid
+  gEfiGraphicsDeviceInfoHobGuid
+  gUefiAcpiBoardInfoGuid
+  gEfiSmbiosTableGuid
+  gUefiSerialPortInfoGuid
+  gUniversalPayloadExtraDataGuid
+  gUniversalPayloadBaseGuid
+  gPcdDataBaseHobGuid
+  gUniversalPayloadSmbiosTableGuid
+  gEfiHobMemoryAllocBspStoreGuid
+  gUniversalPayloadAcpiTableGuid
+  gUniversalPayloadPciRootBridgeInfoGuid
+  gUniversalPayloadSmbios3TableGuid
+
+[FeaturePcd.IA32]
+  gEfiMdeModulePkgTokenSpaceGuid.PcdDxeIplSwitchToLongMode      ## CONSUMES
+
+[FeaturePcd.X64]
+  gEfiMdeModulePkgTokenSpaceGuid.PcdDxeIplBuildPageTables       ## CONSUMES
+
+
+[Pcd.IA32,Pcd.X64]
+  gUefiPayloadPkgTokenSpaceGuid.PcdPcdDriverFile
+  gEfiMdeModulePkgTokenSpaceGuid.PcdUse1GPageTable                      ## SOMETIMES_CONSUMES
+  gEfiMdeModulePkgTokenSpaceGuid.PcdPteMemoryEncryptionAddressOrMask    ## CONSUMES
+  gEfiMdeModulePkgTokenSpaceGuid.PcdNullPointerDetectionPropertyMask    ## CONSUMES
+  gEfiMdeModulePkgTokenSpaceGuid.PcdHeapGuardPropertyMask               ## CONSUMES
+  gEfiMdeModulePkgTokenSpaceGuid.PcdCpuStackGuard                       ## CONSUMES
+  gEfiMdeModulePkgTokenSpaceGuid.PcdGhcbBase                            ## CONSUMES
+  gEfiMdeModulePkgTokenSpaceGuid.PcdGhcbSize                            ## CONSUMES
+
+  gUefiPayloadPkgTokenSpaceGuid.PcdPayloadFdMemBase
+  gUefiPayloadPkgTokenSpaceGuid.PcdPayloadFdMemSize
+  gUefiPayloadPkgTokenSpaceGuid.PcdSystemMemoryUefiRegionSize
+
+  gEfiMdeModulePkgTokenSpaceGuid.PcdSetNxForStack               ## SOMETIMES_CONSUMES
+  gEfiMdeModulePkgTokenSpaceGuid.PcdDxeNxMemoryProtectionPolicy ## SOMETIMES_CONSUMES
+  gEfiMdeModulePkgTokenSpaceGuid.PcdImageProtectionPolicy       ## SOMETIMES_CONSUMES
diff --git a/UefiPayloadPkg/UefiPayloadPkg.dec b/UefiPayloadPkg/UefiPayloadPkg.dec
index e2e4a79db3..2f1fd82487 100644
--- a/UefiPayloadPkg/UefiPayloadPkg.dec
+++ b/UefiPayloadPkg/UefiPayloadPkg.dec
@@ -24,6 +24,9 @@
   #
   gUefiPayloadPkgTokenSpaceGuid  = {0x1d127ea, 0xf6f1, 0x4ef6, {0x94, 0x15, 0x8a, 0x0, 0x0, 0x93, 0xf8, 0x9d}}
 
+  ## Include/Guid/UniversalPayloadBase.h
+  gUniversalPayloadBaseGuid = { 0x03d4c61d, 0x2713, 0x4ec5, {0xa1, 0xcc, 0x88, 0x3b, 0xe9, 0xdc, 0x18, 0xe5 } }
+
   #
   # Gop Temp
   #
diff --git a/UefiPayloadPkg/UefiPayloadPkg.dsc b/UefiPayloadPkg/UefiPayloadPkg.dsc
index 47812048dd..af9308ef8e 100644
--- a/UefiPayloadPkg/UefiPayloadPkg.dsc
+++ b/UefiPayloadPkg/UefiPayloadPkg.dsc
@@ -30,7 +30,6 @@
   DEFINE PS2_KEYBOARD_ENABLE          = FALSE
   DEFINE RAM_DISK_ENABLE              = FALSE
   DEFINE SIO_BUS_ENABLE               = FALSE
-  DEFINE UNIVERSAL_PAYLOAD            = FALSE
   DEFINE SECURITY_STUB_ENABLE         = TRUE
   DEFINE SMM_SUPPORT                  = FALSE
   DEFINE PLATFORM_BOOT_TIMEOUT        = 3
@@ -44,6 +43,14 @@
   DEFINE BOOTSPLASH_IMAGE             = FALSE
   DEFINE NVME_ENABLE                  = TRUE
   DEFINE CAPSULE_SUPPORT              = FALSE
+  #
+  # Setup Universal Payload
+  #
+  # ELF: Build UniversalPayload file as UniversalPayload.elf
+  # FIT: Build UniversalPayload file as UniversalPayload.fit
+  #
+  DEFINE UNIVERSAL_PAYLOAD            = FALSE
+  DEFINE UNIVERSAL_PAYLOAD_FORMAT     = ELF
 
   #
   # NULL:    NullMemoryTestDxe
@@ -311,7 +318,7 @@
   VariableFlashInfoLib|MdeModulePkg/Library/BaseVariableFlashInfoLib/BaseVariableFlashInfoLib.inf
   CcExitLib|UefiCpuPkg/Library/CcExitLibNull/CcExitLibNull.inf
   ReportStatusCodeLib|MdeModulePkg/Library/DxeReportStatusCodeLib/DxeReportStatusCodeLib.inf
-
+  FdtLib|MdePkg/Library/BaseFdtLib/BaseFdtLib.inf
 [LibraryClasses.common]
 !if $(BOOTSPLASH_IMAGE)
   SafeIntLib|MdePkg/Library/BaseSafeIntLib/BaseSafeIntLib.inf
@@ -600,14 +607,26 @@
 !if "IA32" in "$(ARCH)"
   [Components.IA32]
   !if $(UNIVERSAL_PAYLOAD) == TRUE
-    UefiPayloadPkg/UefiPayloadEntry/UniversalPayloadEntry.inf
+    !if $(UNIVERSAL_PAYLOAD_FORMAT) == "ELF"
+      UefiPayloadPkg/UefiPayloadEntry/UniversalPayloadEntry.inf
+    !elseif $(UNIVERSAL_PAYLOAD_FORMAT) == "FIT"
+      UefiPayloadPkg/UefiPayloadEntry/FitUniversalPayloadEntry.inf
+    !else
+      UefiPayloadPkg/UefiPayloadEntry/UefiPayloadEntry.inf
+    !endif
   !else
     UefiPayloadPkg/UefiPayloadEntry/UefiPayloadEntry.inf
   !endif
 !else
   [Components.X64]
   !if $(UNIVERSAL_PAYLOAD) == TRUE
-    UefiPayloadPkg/UefiPayloadEntry/UniversalPayloadEntry.inf
+    !if $(UNIVERSAL_PAYLOAD_FORMAT) == "ELF"
+      UefiPayloadPkg/UefiPayloadEntry/UniversalPayloadEntry.inf
+    !elseif $(UNIVERSAL_PAYLOAD_FORMAT) == "FIT"
+      UefiPayloadPkg/UefiPayloadEntry/FitUniversalPayloadEntry.inf
+    !else
+      UefiPayloadPkg/UefiPayloadEntry/UefiPayloadEntry.inf
+    !endif
   !else
     UefiPayloadPkg/UefiPayloadEntry/UefiPayloadEntry.inf
   !endif
diff --git a/UefiPayloadPkg/UniversalPayloadBuild.py b/UefiPayloadPkg/UniversalPayloadBuild.py
index 47f37b3377..9a83fc9e44 100644
--- a/UefiPayloadPkg/UniversalPayloadBuild.py
+++ b/UefiPayloadPkg/UniversalPayloadBuild.py
@@ -10,10 +10,22 @@ import subprocess
 import os
 import shutil
 import sys
+import pathlib
 from   ctypes import *
-from Tools.ElfFv import ReplaceFv
+
 sys.dont_write_bytecode = True
 
+class bcolors:
+    HEADER = '\033[95m'
+    OKBLUE = '\033[94m'
+    OKCYAN = '\033[96m'
+    OKGREEN = '\033[92m'
+    WARNING = '\033[93m'
+    FAIL = '\033[91m'
+    ENDC = '\033[0m'
+    BOLD = '\033[1m'
+    UNDERLINE = '\033[4m'
+
 class UPLD_INFO_HEADER(LittleEndianStructure):
     _pack_ = 1
     _fields_ = [
@@ -36,40 +48,114 @@ class UPLD_INFO_HEADER(LittleEndianStructure):
         self.ImageId        = b'UEFI'
         self.ProducerId     = b'INTEL'
 
-def BuildUniversalPayload(Args):
-    def RunCommand(cmd):
-        print(cmd)
-        p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT,cwd=os.environ['WORKSPACE'])
-        while True:
-            line = p.stdout.readline()
-            if not line:
-                break
-            print(line.strip().decode(errors='ignore'))
-
-        p.communicate()
-        if p.returncode != 0:
-            print("- Failed - error happened when run command: %s"%cmd)
-            raise Exception("ERROR: when run command: %s"%cmd)
+def ValidateSpecRevision (Argument):
+    try:
+        (MajorStr, MinorStr) = Argument.split('.')
+    except:
+        raise argparse.ArgumentTypeError ('{} is not a valid SpecRevision format (Major[8-bits].Minor[8-bits]).'.format (Argument))
+    #
+    # Spec Revision Bits 15 : 8 - Major Version. Bits 7 : 0 - Minor Version.
+    #
+    if len(MinorStr) > 0 and len(MinorStr) < 3:
+        try:
+            Minor = int(MinorStr, 16) if len(MinorStr) == 2 else (int(MinorStr, 16) << 4)
+        except:
+            raise argparse.ArgumentTypeError ('{} Minor version of SpecRevision is not a valid integer value.'.format (Argument))
+    else:
+        raise argparse.ArgumentTypeError ('{} is not a valid SpecRevision format (Major[8-bits].Minor[8-bits]).'.format (Argument))
+
+    if len(MajorStr) > 0 and len(MajorStr) < 3:
+        try:
+            Major = int(MajorStr, 16)
+        except:
+            raise argparse.ArgumentTypeError ('{} Major version of SpecRevision is not a valid integer value.'.format (Argument))
+    else:
+        raise argparse.ArgumentTypeError ('{} is not a valid SpecRevision format (Major[8-bits].Minor[8-bits]).'.format (Argument))
+
+    return int('0x{0:02x}{1:02x}'.format(Major, Minor), 0)
+
+def Validate32BitInteger (Argument):
+    try:
+        Value = int (Argument, 0)
+    except:
+        raise argparse.ArgumentTypeError ('{} is not a valid integer value.'.format (Argument))
+    if Value < 0:
+        raise argparse.ArgumentTypeError ('{} is a negative value.'.format (Argument))
+    if Value > 0xffffffff:
+        raise argparse.ArgumentTypeError ('{} is larger than 32-bits.'.format (Argument))
+    return Value
 
+def ValidateAddFv (Argument):
+    Value = Argument.split ("=")
+    if len (Value) != 2:
+        raise argparse.ArgumentTypeError ('{} is incorrect format with "xxx_fv=xxx.fv"'.format (Argument))
+    if Value[0][-3:] != "_fv":
+        raise argparse.ArgumentTypeError ('{} is incorrect format with "xxx_fv=xxx.fv"'.format (Argument))
+    if Value[1][-3:].lower () != ".fv":
+        raise argparse.ArgumentTypeError ('{} is incorrect format with "xxx_fv=xxx.fv"'.format (Argument))
+    if os.path.exists (Value[1]) == False:
+        raise argparse.ArgumentTypeError ('File {} is not found.'.format (Value[1]))
+    return Value
+
+def RunCommand(cmd):
+    print(cmd)
+    p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT,cwd=os.environ['WORKSPACE'])
+    while True:
+        line = p.stdout.readline()
+        if not line:
+            break
+        print(line.strip().decode(errors='ignore'))
+
+    p.communicate()
+    if p.returncode != 0:
+        print("- Failed - error happened when run command: %s"%cmd)
+        raise Exception("ERROR: when run command: %s"%cmd)
+
+def BuildUniversalPayload(Args):
     BuildTarget = Args.Target
     ToolChain = Args.ToolChain
     Quiet     = "--quiet"  if Args.Quiet else ""
-    ElfToolChain = 'CLANGDWARF'
-    BuildDir     = os.path.join(os.environ['WORKSPACE'], os.path.normpath("Build/UefiPayloadPkgX64"))
-    BuildModule = ""
-    BuildArch = ""
 
+    if Args.Fit == True:
+        PayloadEntryToolChain = ToolChain
+        Args.Macro.append("UNIVERSAL_PAYLOAD_FORMAT=FIT")
+        UpldEntryFile = "FitUniversalPayloadEntry"
+    else:
+        PayloadEntryToolChain = 'CLANGDWARF'
+        Args.Macro.append("UNIVERSAL_PAYLOAD_FORMAT=ELF")
+        UpldEntryFile = "UniversalPayloadEntry"
+
+    BuildDir     = os.path.join(os.environ['WORKSPACE'], os.path.normpath("Build/UefiPayloadPkgX64"))
     if Args.Arch == 'X64':
         BuildArch      = "X64"
-        EntryOutputDir = os.path.join(BuildDir, "{}_{}".format (BuildTarget, ElfToolChain), os.path.normpath("X64/UefiPayloadPkg/UefiPayloadEntry/UniversalPayloadEntry/DEBUG/UniversalPayloadEntry.dll"))
+        FitArch        = "x86_64"
+        ObjCopyFlag    = "elf64-x86-64"
+        EntryOutputDir = os.path.join(BuildDir, "{}_{}".format (BuildTarget, PayloadEntryToolChain), os.path.normpath("X64/UefiPayloadPkg/UefiPayloadEntry/{}/DEBUG/{}.dll".format (UpldEntryFile, UpldEntryFile)))
     else:
         BuildArch      = "IA32 -a X64"
-        EntryOutputDir = os.path.join(BuildDir, "{}_{}".format (BuildTarget, ElfToolChain), os.path.normpath("IA32/UefiPayloadPkg/UefiPayloadEntry/UniversalPayloadEntry/DEBUG/UniversalPayloadEntry.dll"))
+        FitArch        = "x86"
+        ObjCopyFlag    = "elf32-i386"
+        EntryOutputDir = os.path.join(BuildDir, "{}_{}".format (BuildTarget, PayloadEntryToolChain), os.path.normpath("IA32/UefiPayloadPkg/UefiPayloadEntry/{}/DEBUG/{}.dll".format (UpldEntryFile, UpldEntryFile)))
 
+    EntryModuleInf = os.path.normpath("UefiPayloadPkg/UefiPayloadEntry/{}.inf".format (UpldEntryFile))
     DscPath = os.path.normpath("UefiPayloadPkg/UefiPayloadPkg.dsc")
+    DxeFvOutputDir = os.path.join(BuildDir, "{}_{}".format (BuildTarget, ToolChain), os.path.normpath("FV/DXEFV.Fv"))
+    BdsFvOutputDir = os.path.join(BuildDir, "{}_{}".format (BuildTarget, ToolChain), os.path.normpath("FV/BDSFV.Fv"))
+    NetworkFvOutputDir = os.path.join(BuildDir, "{}_{}".format (BuildTarget, ToolChain), os.path.normpath("FV/NETWORKFV.Fv"))
+    PayloadReportPath = os.path.join(BuildDir, "UefiUniversalPayload.txt")
     ModuleReportPath = os.path.join(BuildDir, "UefiUniversalPayloadEntry.txt")
     UpldInfoFile = os.path.join(BuildDir, "UniversalPayloadInfo.bin")
 
+    if "CLANG_BIN" in os.environ:
+        LlvmObjcopyPath = os.path.join(os.environ["CLANG_BIN"], "llvm-objcopy")
+    else:
+        LlvmObjcopyPath = "llvm-objcopy"
+    try:
+        RunCommand('"%s" --version'%LlvmObjcopyPath)
+    except:
+        print("- Failed - Please check if LLVM is installed or if CLANG_BIN is set correctly")
+        sys.exit(1)
+
     Pcds = ""
     if (Args.pcd != None):
         for PcdItem in Args.pcd:
@@ -84,7 +170,6 @@ def BuildUniversalPayload(Args):
     # Building DXE core and DXE drivers as DXEFV.
     #
     if Args.BuildEntryOnly == False:
-        PayloadReportPath = os.path.join(BuildDir, "UefiUniversalPayload.txt")
         BuildPayload = "build -p {} -b {} -a X64 -t {} -y {} {}".format (DscPath, BuildTarget, ToolChain, PayloadReportPath, Quiet)
         BuildPayload += Pcds
         BuildPayload += Defines
@@ -93,94 +178,138 @@ def BuildUniversalPayload(Args):
     # Building Universal Payload entry.
     #
     if Args.PreBuildUplBinary is None:
-        EntryModuleInf = os.path.normpath("UefiPayloadPkg/UefiPayloadEntry/UniversalPayloadEntry.inf")
-        BuildModule = "build -p {} -b {} -a {} -m {} -t {} -y {} {}".format (DscPath, BuildTarget, BuildArch, EntryModuleInf, ElfToolChain, ModuleReportPath, Quiet)
+        BuildModule = "build -p {} -b {} -a {} -m {} -t {} -y {} {}".format (DscPath, BuildTarget, BuildArch, EntryModuleInf, PayloadEntryToolChain, ModuleReportPath, Quiet)
         BuildModule += Pcds
         BuildModule += Defines
         RunCommand(BuildModule)
 
     if Args.PreBuildUplBinary is not None:
-        EntryOutputDir = os.path.join(BuildDir, "UniversalPayload.elf")
+        if Args.Fit == False:
+            EntryOutputDir = os.path.join(BuildDir, "UniversalPayload.elf")
+        else:
+            EntryOutputDir = os.path.join(BuildDir, "UniversalPayload.fit")
         shutil.copy (os.path.abspath(Args.PreBuildUplBinary), EntryOutputDir)
 
     #
-    # Buid Universal Payload Information Section ".upld_info"
+    # Build Universal Payload Information Section ".upld_info"
     #
-    upld_info_hdr              = UPLD_INFO_HEADER()
-    upld_info_hdr.SpecRevision = Args.SpecRevision
-    upld_info_hdr.Revision     = Args.Revision
-    upld_info_hdr.ProducerId   = Args.ProducerId.encode()[:16]
-    upld_info_hdr.ImageId      = Args.ImageId.encode()[:16]
-    upld_info_hdr.Attribute   |= 1 if BuildTarget == "DEBUG" else 0
-    fp = open(UpldInfoFile, 'wb')
-    fp.write(bytearray(upld_info_hdr))
-    fp.close()
+    if Args.Fit == False:
+        upld_info_hdr = UPLD_INFO_HEADER()
+        upld_info_hdr.SpecRevision = Args.SpecRevision
+        upld_info_hdr.Revision = Args.Revision
+        upld_info_hdr.ProducerId = Args.ProducerId.encode()[:16]
+        upld_info_hdr.ImageId = Args.ImageId.encode()[:16]
+        upld_info_hdr.Attribute |= 1 if BuildTarget == "DEBUG" else 0
+        fp = open(UpldInfoFile, 'wb')
+        fp.write(bytearray(upld_info_hdr))
+        fp.close()
+
+        if Args.BuildEntryOnly == False:
+            import Tools.ElfFv as ElfFv
+            ElfFv.ReplaceFv (EntryOutputDir, UpldInfoFile, '.upld_info', Alignment = 4)
+    if Args.Fit == False:
+        shutil.copy (EntryOutputDir, os.path.join(BuildDir, 'UniversalPayload.elf'))
+    else:
+        shutil.copy (EntryOutputDir, os.path.join(BuildDir, 'UniversalPayload.fit'))
 
     MultiFvList = []
     if Args.BuildEntryOnly == False:
         MultiFvList = [
-            ['uefi_fv',    os.path.join(BuildDir, "{}_{}".format (BuildTarget, ToolChain), os.path.normpath("FV/DXEFV.Fv"))    ],
-            ['bds_fv',     os.path.join(BuildDir, "{}_{}".format (BuildTarget, ToolChain), os.path.normpath("FV/BDSFV.Fv"))    ],
-            ['network_fv', os.path.join(BuildDir, "{}_{}".format (BuildTarget, ToolChain), os.path.normpath("FV/NETWORKFV.Fv"))    ],
+            ['uefi_fv',        os.path.join(BuildDir, "{}_{}".format (BuildTarget, ToolChain), os.path.normpath("FV/DXEFV.Fv"))    ],
+            ['bds_fv',         os.path.join(BuildDir, "{}_{}".format (BuildTarget, ToolChain), os.path.normpath("FV/BDSFV.Fv"))    ],
+            ['network_fv',     os.path.join(BuildDir, "{}_{}".format (BuildTarget, ToolChain), os.path.normpath("FV/NETWORKFV.Fv"))],
         ]
-        AddSectionName = '.upld_info'
-        ReplaceFv (EntryOutputDir, UpldInfoFile, AddSectionName, Alignment = 4)
 
-    if Args.PreBuildUplBinary is None:
-        shutil.copy (EntryOutputDir, os.path.join(BuildDir, 'UniversalPayload.elf'))
 
-    return MultiFvList, os.path.join(BuildDir, 'UniversalPayload.elf')
+    if Args.Fit == True:
+        import Tools.MkFitImage as MkFitImage
+        import pefile
+        fit_image_info_header               = MkFitImage.FIT_IMAGE_INFO_HEADER()
+        fit_image_info_header.Description   = 'Uefi Universal Payload'
+        fit_image_info_header.UplVersion    = Args.SpecRevision
+        fit_image_info_header.Type          = 'flat-binary'
+        fit_image_info_header.Arch          = FitArch
+        fit_image_info_header.Compression   = 'none'
+        fit_image_info_header.Revision      = Args.Revision
+        fit_image_info_header.BuildType     = Args.Target.lower()
+        fit_image_info_header.Capabilities  = None
+        fit_image_info_header.Producer      = Args.ProducerId.lower()
+        fit_image_info_header.ImageId       = Args.ImageId.lower()
+        fit_image_info_header.Binary        = os.path.join(BuildDir, 'UniversalPayload.fit')
+        fit_image_info_header.TargetPath    = os.path.join(BuildDir, 'UniversalPayload.fit')
+        fit_image_info_header.UefifvPath    = DxeFvOutputDir
+        fit_image_info_header.BdsfvPath     = BdsFvOutputDir
+        fit_image_info_header.NetworkfvPath = NetworkFvOutputDir
+        fit_image_info_header.DataOffset    = 0x1000
+        fit_image_info_header.LoadAddr      = Args.LoadAddress
+        fit_image_info_header.Project       = 'tianocore'
+
+        TargetRebaseFile = fit_image_info_header.Binary.replace (pathlib.Path(fit_image_info_header.Binary).suffix, ".pecoff")
+        TargetRebaseEntryFile = fit_image_info_header.Binary.replace (pathlib.Path(fit_image_info_header.Binary).suffix, ".entry")
+
 
-def main():
-    def ValidateSpecRevision (Argument):
-        try:
-            (MajorStr, MinorStr) = Argument.split('.')
-        except:
-            raise argparse.ArgumentTypeError ('{} is not a valid SpecRevision format (Major[8-bits].Minor[8-bits]).'.format (Argument))
         #
-        # Spec Revision Bits 15 : 8 - Major Version. Bits 7 : 0 - Minor Version.
+        # Rebase PECOFF to load address
         #
-        if len(MinorStr) > 0 and len(MinorStr) < 3:
-            try:
-                Minor = int(MinorStr, 16) if len(MinorStr) == 2 else (int(MinorStr, 16) << 4)
-            except:
-                raise argparse.ArgumentTypeError ('{} Minor version of SpecRevision is not a valid integer value.'.format (Argument))
-        else:
-            raise argparse.ArgumentTypeError ('{} is not a valid SpecRevision format (Major[8-bits].Minor[8-bits]).'.format (Argument))
+        RunCommand (
+            "GenFw -e SEC -o {} {}".format (
+              TargetRebaseFile,
+              fit_image_info_header.Binary
+            ))
+        RunCommand (
+            "GenFw --rebase 0x{:02X} -o {} {} ".format (
+              fit_image_info_header.LoadAddr + fit_image_info_header.DataOffset,
+              TargetRebaseFile,
+              TargetRebaseFile,
+            ))
 
-        if len(MajorStr) > 0 and len(MajorStr) < 3:
-            try:
-                Major = int(MajorStr, 16)
-            except:
-                raise argparse.ArgumentTypeError ('{} Major version of SpecRevision is not a valid integer value.'.format (Argument))
-        else:
-            raise argparse.ArgumentTypeError ('{} is not a valid SpecRevision format (Major[8-bits].Minor[8-bits]).'.format (Argument))
+        #
+        # Open PECOFF relocation table binary.
+        #
+        RelocBinary     = b''
+        PeCoff = pefile.PE (TargetRebaseFile)
+        for reloc in PeCoff.DIRECTORY_ENTRY_BASERELOC:
+            for entry in reloc.entries:
+                if (entry.type == 0):
+                    continue
+                Type = entry.type
+                Offset = entry.rva + fit_image_info_header.DataOffset
+                RelocBinary += Type.to_bytes (8, 'little') + Offset.to_bytes (8, 'little')
+        RelocBinary += b'\x00' * (0x1000 - (len(RelocBinary) % 0x1000))
 
-        return int('0x{0:02x}{1:02x}'.format(Major, Minor), 0)
+        #
+        # Output UniversalPayload.entry
+        #
+        TempBinary = open (TargetRebaseFile, 'rb')
+        TianoBinary = TempBinary.read ()
+        TempBinary.close ()
 
-    def Validate32BitInteger (Argument):
-        try:
-            Value = int (Argument, 0)
-        except:
-            raise argparse.ArgumentTypeError ('{} is not a valid integer value.'.format (Argument))
-        if Value < 0:
-            raise argparse.ArgumentTypeError ('{} is a negative value.'.format (Argument))
-        if Value > 0xffffffff:
-            raise argparse.ArgumentTypeError ('{} is larger than 32-bits.'.format (Argument))
-        return Value
-
-    def ValidateAddFv (Argument):
-        Value = Argument.split ("=")
-        if len (Value) != 2:
-            raise argparse.ArgumentTypeError ('{} is incorrect format with "xxx_fv=xxx.fv"'.format (Argument))
-        if Value[0][-3:] != "_fv":
-            raise argparse.ArgumentTypeError ('{} is incorrect format with "xxx_fv=xxx.fv"'.format (Argument))
-        if Value[1][-3:].lower () != ".fv":
-            raise argparse.ArgumentTypeError ('{} is incorrect format with "xxx_fv=xxx.fv"'.format (Argument))
-        if os.path.exists (Value[1]) == False:
-            raise argparse.ArgumentTypeError ('File {} is not found.'.format (Value[1]))
-        return Value
+        TianoEntryBinary = TianoBinary + RelocBinary
+        TianoEntryBinary += (b'\x00' * (0x1000 - (len(TianoBinary) % 0x1000)))
+        TianoEntryBinarySize = len (TianoEntryBinary)
+
+        TempBinary = open(TargetRebaseEntryFile, "wb")
+        TempBinary.truncate()
+        TempBinary.write(TianoEntryBinary)
+        TempBinary.close()
+
+        #
+        # Calculate entry and update relocation table start address and data-size.
+        #
+        fit_image_info_header.Entry      = PeCoff.OPTIONAL_HEADER.ImageBase + PeCoff.OPTIONAL_HEADER.AddressOfEntryPoint
+        fit_image_info_header.RelocStart = fit_image_info_header.DataOffset + len(TianoBinary)
+        fit_image_info_header.DataSize   = TianoEntryBinarySize
+        fit_image_info_header.Binary     = TargetRebaseEntryFile
+
+        if MkFitImage.MakeFitImage(fit_image_info_header) is True:
+            print('\nSuccessfully build Fit Image')
+        else:
+            sys.exit(1)
+        return MultiFvList, os.path.join(BuildDir, 'UniversalPayload.fit')
+    else:
+        return MultiFvList, os.path.join(BuildDir, 'UniversalPayload.elf')
 
+def main():
     parser = argparse.ArgumentParser(description='For building Universal Payload')
     parser.add_argument('-t', '--ToolChain')
     parser.add_argument('-b', '--Target', default='DEBUG')
@@ -192,13 +321,16 @@ def main():
     parser.add_argument("-s", "--SpecRevision", type=ValidateSpecRevision, default ='0.7', help='Indicates compliance with a revision of this specification in the BCD format.')
     parser.add_argument("-r", "--Revision", type=Validate32BitInteger, default ='0x0000010105', help='Revision of the Payload binary. Major.Minor.Revision.Build')
     parser.add_argument("-o", "--ProducerId", default ='INTEL', help='A null-terminated OEM-supplied string that identifies the payload producer (16 bytes maximal).')
+    parser.add_argument("-e", "--BuildEntryOnly", action='store_true', help='Build UniversalPayload Entry file')
+    parser.add_argument("-pb", "--PreBuildUplBinary", default=None, help='Specify the UniversalPayload file')
     parser.add_argument("-sk", "--SkipBuild", action='store_true', help='Skip UniversalPayload build')
     parser.add_argument("-af", "--AddFv", type=ValidateAddFv, action='append', help='Add or replace specific FV into payload, Ex: uefi_fv=XXX.fv')
-    command_group = parser.add_mutually_exclusive_group()
-    command_group.add_argument("-e", "--BuildEntryOnly", action='store_true', help='Build UniversalPayload Entry file')
-    command_group.add_argument("-pb", "--PreBuildUplBinary", default=None, help='Specify the UniversalPayload file')
+    parser.add_argument("-f", "--Fit", action='store_true', help='Build UniversalPayload file as UniversalPayload.fit', default=False)
+    parser.add_argument('-l', "--LoadAddress", type=int, help='Specify payload load address', default =0x000800000)
+
     args = parser.parse_args()
 
+
     MultiFvList = []
     UniversalPayloadBinary = args.PreBuildUplBinary
     if (args.SkipBuild == False):
@@ -208,12 +340,24 @@ def main():
         for (SectionName, SectionFvFile) in args.AddFv:
             MultiFvList.append ([SectionName, SectionFvFile])
 
+    def ReplaceFv (UplBinary, SectionFvFile, SectionName):
+        print (bcolors.OKGREEN + "Patch {}={} into {}".format (SectionName, SectionFvFile, UplBinary) + bcolors.ENDC)
+        if (args.Fit == False):
+            import Tools.ElfFv as ElfFv
+            return ElfFv.ReplaceFv (UplBinary, SectionFvFile, '.upld.{}'.format (SectionName))
+        else:
+            import Tools.MkFitImage as MkFitImage
+            return MkFitImage.ReplaceFv (UplBinary, SectionFvFile, SectionName)
+
     if (UniversalPayloadBinary != None):
         for (SectionName, SectionFvFile) in MultiFvList:
             if os.path.exists (SectionFvFile) == False:
                 continue
-            print ("Patch {}={} into {}".format (SectionName, SectionFvFile, UniversalPayloadBinary))
-            ReplaceFv (UniversalPayloadBinary, SectionFvFile, '.upld.{}'.format (SectionName))
+
+            status = ReplaceFv (UniversalPayloadBinary, SectionFvFile, SectionName.replace ("_", "-"))
+            if status != 0:
+                print (bcolors.FAIL + "[Fail] Patch {}={}".format (SectionName, SectionFvFile) + bcolors.ENDC)
+                return status
 
     print ("\nSuccessfully build Universal Payload")
 
-- 
2.39.2.windows.1



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#108755): https://edk2.groups.io/g/devel/message/108755
Mute This Topic: https://groups.io/mt/101398212/1787277
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [importer@patchew.org]
-=-=-=-=-=-=-=-=-=-=-=-