Reviewed-by: James Lu <james...@intel.com>

Thanks,
James

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

From: "Brucex.Wang" <brucex.w...@intel.com>

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

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

Signed-off-by: BruceX Wang <brucex.w...@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/21656
Group Owner: devel+ow...@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [arch...@mail-archive.com]
-=-=-=-=-=-=-=-=-=-=-=-


Reply via email to