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

brucex.wang@intel.com posted 2 patches 10 months ago
There is a newer version of this series
[edk2-devel] [PATCH v2 2/2] UefiPayloadPkg: Add FIT support
Posted by brucex.wang@intel.com 10 months 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       |  21 +
 UefiPayloadPkg/PayloadLoaderPeim/FitLib.h     |  60 ++
 .../PayloadLoaderPeim/FitLib/FitLib.c         | 127 ++++
 .../PayloadLoaderPeim/FitPayloadLoaderPeim.c  | 150 ++++
 .../FitPayloadLoaderPeim.inf                  |  59 ++
 UefiPayloadPkg/Readme.md                      | 191 +++++
 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, 1894 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..31c9ec0bfb
--- /dev/null
+++ b/UefiPayloadPkg/Include/Guid/UniversalPayloadBase.h
@@ -0,0 +1,21 @@
+/** @file
+  Universal Payload general definitions.
+
+Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+  @par Revision Reference:
+    - Universal Payload Specification 0.75 (https://universalpayload.github.io/documentation/)
+**/
+
+#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..3c5dacbb65
--- /dev/null
+++ b/UefiPayloadPkg/PayloadLoaderPeim/FitPayloadLoaderPeim.c
@@ -0,0 +1,150 @@
+/** @file
+  ELF Load Image Support
+Copyright (c) 2021, 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..acb0e09f68
--- /dev/null
+++ b/UefiPayloadPkg/PayloadLoaderPeim/FitPayloadLoaderPeim.inf
@@ -0,0 +1,59 @@
+## @file
+#  Produce LoadFile PPI for payload loading.
+#
+#  Copyright (c) 2021, 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..616a5dd467
--- /dev/null
+++ b/UefiPayloadPkg/Readme.md
@@ -0,0 +1,191 @@
+# UefiPayloadPkg
+Provide UEFI Universal Payload for different bootloader to generate EFI environment
+
+# Spec
+
+UniversalPayload URL: https://universalscalablefirmware.github.io/documentation/2_universal_payload.html
+
+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..a53d988627
--- /dev/null
+++ b/UefiPayloadPkg/UefiPayloadEntry/FitUniversalPayloadEntry.c
@@ -0,0 +1,654 @@
+/** @file
+  Copyright (c) 2021, 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..a7d1a8c9e5
--- /dev/null
+++ b/UefiPayloadPkg/UefiPayloadEntry/FitUniversalPayloadEntry.inf
@@ -0,0 +1,98 @@
+## @file
+#  This is the first module for UEFI payload.
+#
+#  Copyright (c) 2021, 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.1.windows.1



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#108718): https://edk2.groups.io/g/devel/message/108718
Mute This Topic: https://groups.io/mt/101378805/1787277
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [importer@patchew.org]
-=-=-=-=-=-=-=-=-=-=-=-
Re: [edk2-devel] [PATCH v2 2/2] UefiPayloadPkg: Add FIT support
Posted by Lu, James 10 months ago
Reviewed-by: James Lu <james.lu@intel.com>


Thanks,
James

-----Original Message-----
From: Wang, BruceX <brucex.wang@intel.com> 
Sent: Friday, September 15, 2023 4:58 PM
To: devel@edk2.groups.io
Cc: Wang, BruceX <brucex.wang@intel.com>; Dong, Guo <guo.dong@intel.com>; Rhodes, Sean <sean@starlabs.systems>; Lu, James <james.lu@intel.com>; Guo, Gua <gua.guo@intel.com>
Subject: [PATCH v2 2/2] UefiPayloadPkg: Add FIT support

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       |  21 +
 UefiPayloadPkg/PayloadLoaderPeim/FitLib.h     |  60 ++
 .../PayloadLoaderPeim/FitLib/FitLib.c         | 127 ++++
 .../PayloadLoaderPeim/FitPayloadLoaderPeim.c  | 150 ++++
 .../FitPayloadLoaderPeim.inf                  |  59 ++
 UefiPayloadPkg/Readme.md                      | 191 +++++
 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, 1894 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..31c9ec0bfb
--- /dev/null
+++ b/UefiPayloadPkg/Include/Guid/UniversalPayloadBase.h
@@ -0,0 +1,21 @@
+/** @file

+  Universal Payload general definitions.

+

+Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>

+SPDX-License-Identifier: BSD-2-Clause-Patent

+

+  @par Revision Reference:

+    - Universal Payload Specification 0.75 (https://universalpayload.github.io/documentation/)

+**/

+

+#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..3c5dacbb65
--- /dev/null
+++ b/UefiPayloadPkg/PayloadLoaderPeim/FitPayloadLoaderPeim.c
@@ -0,0 +1,150 @@
+/** @file

+  ELF Load Image Support

+Copyright (c) 2021, 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..acb0e09f68
--- /dev/null
+++ b/UefiPayloadPkg/PayloadLoaderPeim/FitPayloadLoaderPeim.inf
@@ -0,0 +1,59 @@
+## @file

+#  Produce LoadFile PPI for payload loading.

+#

+#  Copyright (c) 2021, 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..616a5dd467
--- /dev/null
+++ b/UefiPayloadPkg/Readme.md
@@ -0,0 +1,191 @@
+# UefiPayloadPkg

+Provide UEFI Universal Payload for different bootloader to generate EFI environment

+

+# Spec

+

+UniversalPayload URL: https://universalscalablefirmware.github.io/documentation/2_universal_payload.html

+

+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..a53d988627
--- /dev/null
+++ b/UefiPayloadPkg/UefiPayloadEntry/FitUniversalPayloadEntry.c
@@ -0,0 +1,654 @@
+/** @file

+  Copyright (c) 2021, 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..a7d1a8c9e5
--- /dev/null
+++ b/UefiPayloadPkg/UefiPayloadEntry/FitUniversalPayloadEntry.inf
@@ -0,0 +1,98 @@
+## @file

+#  This is the first module for UEFI payload.

+#

+#  Copyright (c) 2021, 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.1.windows.1



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#108701): https://edk2.groups.io/g/devel/message/108701
Mute This Topic: https://groups.io/mt/101375948/1787277
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [importer@patchew.org]
-=-=-=-=-=-=-=-=-=-=-=-
Re: [edk2-devel] [PATCH v2 2/2] UefiPayloadPkg: Add FIT support
Posted by Guo, Gua 10 months ago
Reviewed-by: Gua Guo <gua.guo@intel.com>

-----Original Message-----
From: Wang, BruceX <brucex.wang@intel.com> 
Sent: Friday, September 15, 2023 4:58 PM
To: devel@edk2.groups.io
Cc: Wang, BruceX <brucex.wang@intel.com>; Dong, Guo <guo.dong@intel.com>; Rhodes, Sean <sean@starlabs.systems>; Lu, James <james.lu@intel.com>; Guo, Gua <gua.guo@intel.com>
Subject: [PATCH v2 2/2] UefiPayloadPkg: Add FIT support

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       |  21 +
 UefiPayloadPkg/PayloadLoaderPeim/FitLib.h     |  60 ++
 .../PayloadLoaderPeim/FitLib/FitLib.c         | 127 ++++
 .../PayloadLoaderPeim/FitPayloadLoaderPeim.c  | 150 ++++
 .../FitPayloadLoaderPeim.inf                  |  59 ++
 UefiPayloadPkg/Readme.md                      | 191 +++++
 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, 1894 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..31c9ec0bfb
--- /dev/null
+++ b/UefiPayloadPkg/Include/Guid/UniversalPayloadBase.h
@@ -0,0 +1,21 @@
+/** @file

+  Universal Payload general definitions.

+

+Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>

+SPDX-License-Identifier: BSD-2-Clause-Patent

+

+  @par Revision Reference:

+    - Universal Payload Specification 0.75 (https://universalpayload.github.io/documentation/)

+**/

+

+#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..3c5dacbb65
--- /dev/null
+++ b/UefiPayloadPkg/PayloadLoaderPeim/FitPayloadLoaderPeim.c
@@ -0,0 +1,150 @@
+/** @file

+  ELF Load Image Support

+Copyright (c) 2021, 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..acb0e09f68
--- /dev/null
+++ b/UefiPayloadPkg/PayloadLoaderPeim/FitPayloadLoaderPeim.inf
@@ -0,0 +1,59 @@
+## @file

+#  Produce LoadFile PPI for payload loading.

+#

+#  Copyright (c) 2021, 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..616a5dd467
--- /dev/null
+++ b/UefiPayloadPkg/Readme.md
@@ -0,0 +1,191 @@
+# UefiPayloadPkg

+Provide UEFI Universal Payload for different bootloader to generate EFI environment

+

+# Spec

+

+UniversalPayload URL: https://universalscalablefirmware.github.io/documentation/2_universal_payload.html

+

+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..a53d988627
--- /dev/null
+++ b/UefiPayloadPkg/UefiPayloadEntry/FitUniversalPayloadEntry.c
@@ -0,0 +1,654 @@
+/** @file

+  Copyright (c) 2021, 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..a7d1a8c9e5
--- /dev/null
+++ b/UefiPayloadPkg/UefiPayloadEntry/FitUniversalPayloadEntry.inf
@@ -0,0 +1,98 @@
+## @file

+#  This is the first module for UEFI payload.

+#

+#  Copyright (c) 2021, 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.1.windows.1



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#108699): https://edk2.groups.io/g/devel/message/108699
Mute This Topic: https://groups.io/mt/101375948/1787277
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [importer@patchew.org]
-=-=-=-=-=-=-=-=-=-=-=-
Re: [edk2-devel] [PATCH v2 2/2] UefiPayloadPkg: Add FIT support
Posted by Sheng Lean Tan 10 months ago
Hi,
It looks good to me, but could you help to update these 2 parts:
1. the copyright year should be 2023 instead of 2021?
2. the correct UPL spec website should be universalpayload.github.io/spec

Thanks,
Sheng

On Fri, 15 Sept 2023 at 11:02, Guo, Gua <gua.guo@intel.com> wrote:

> Reviewed-by: Gua Guo <gua.guo@intel.com>
>
> -----Original Message-----
> From: Wang, BruceX <brucex.wang@intel.com>
> Sent: Friday, September 15, 2023 4:58 PM
> To: devel@edk2.groups.io
> Cc: Wang, BruceX <brucex.wang@intel.com>; Dong, Guo <guo.dong@intel.com>;
> Rhodes, Sean <sean@starlabs.systems>; Lu, James <james.lu@intel.com>;
> Guo, Gua <gua.guo@intel.com>
> Subject: [PATCH v2 2/2] UefiPayloadPkg: Add FIT support
>
> 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       |  21 +
>  UefiPayloadPkg/PayloadLoaderPeim/FitLib.h     |  60 ++
>  .../PayloadLoaderPeim/FitLib/FitLib.c         | 127 ++++
>  .../PayloadLoaderPeim/FitPayloadLoaderPeim.c  | 150 ++++
>  .../FitPayloadLoaderPeim.inf                  |  59 ++
>  UefiPayloadPkg/Readme.md                      | 191 +++++
>  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, 1894 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..31c9ec0bfb
> --- /dev/null
> +++ b/UefiPayloadPkg/Include/Guid/UniversalPayloadBase.h
> @@ -0,0 +1,21 @@
> +/** @file
>
> +  Universal Payload general definitions.
>
> +
>
> +Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
>
> +SPDX-License-Identifier: BSD-2-Clause-Patent
>
> +
>
> +  @par Revision Reference:
>
> +    - Universal Payload Specification 0.75 (
> https://universalpayload.github.io/documentation/)
>
> +**/
>
> +
>
> +#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..3c5dacbb65
> --- /dev/null
> +++ b/UefiPayloadPkg/PayloadLoaderPeim/FitPayloadLoaderPeim.c
> @@ -0,0 +1,150 @@
> +/** @file
>
> +  ELF Load Image Support
>
> +Copyright (c) 2021, 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..acb0e09f68
> --- /dev/null
> +++ b/UefiPayloadPkg/PayloadLoaderPeim/FitPayloadLoaderPeim.inf
> @@ -0,0 +1,59 @@
> +## @file
>
> +#  Produce LoadFile PPI for payload loading.
>
> +#
>
> +#  Copyright (c) 2021, 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..616a5dd467
> --- /dev/null
> +++ b/UefiPayloadPkg/Readme.md
> @@ -0,0 +1,191 @@
> +# UefiPayloadPkg
>
> +Provide UEFI Universal Payload for different bootloader to generate EFI
> environment
>
> +
>
> +# Spec
>
> +
>
> +UniversalPayload URL:
> https://universalscalablefirmware.github.io/documentation/2_universal_payload.html
>
> +
>
> +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..a53d988627
> --- /dev/null
> +++ b/UefiPayloadPkg/UefiPayloadEntry/FitUniversalPayloadEntry.c
> @@ -0,0 +1,654 @@
> +/** @file
>
> +  Copyright (c) 2021, 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..a7d1a8c9e5
> --- /dev/null
> +++ b/UefiPayloadPkg/UefiPayloadEntry/FitUniversalPayloadEntry.inf
> @@ -0,0 +1,98 @@
> +## @file
>
> +#  This is the first module for UEFI payload.
>
> +#
>
> +#  Copyright (c) 2021, 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.1.windows.1
>
>
>
> 
>
>
>


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


Re: [edk2-devel] [PATCH v2 2/2] UefiPayloadPkg: Add FIT support
Posted by Sheng Lean Tan 10 months ago
The spec version should be v.8 instead of v.75


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