From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail02.groups.io (mail02.groups.io [66.175.222.108]) by spool.mail.gandi.net (Postfix) with ESMTPS id D3DE0AC14A7 for ; Mon, 18 Sep 2023 15:17:52 +0000 (UTC) DKIM-Signature: a=rsa-sha256; bh=BoqcTzzm3NlqsmE10mbTigrTjyOfD/OC+JIoUroPVnE=; c=relaxed/simple; d=groups.io; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References:MIME-Version:Precedence:List-Subscribe:List-Help:Sender:List-Id:Mailing-List:Delivered-To:Reply-To:List-Unsubscribe-Post:List-Unsubscribe:Content-Transfer-Encoding; s=20140610; t=1695050271; v=1; b=AXegcVHsFxHsQ0zqmYCoi6+Ue5Gp7TK3Ai11glj0nZrk1Swtgm2WM2yXKxZjdKVJhQ9CzASw 31mqsZedhoiXbGTT1Mf/ixOE1t9+y9pNnr08t9z2gskpq0pv+WtgP51rzHxyWY3L1oaHH3A22Zg O3f2EqtW1Y7wdiUfoTUCJ15c= X-Received: by 127.0.0.2 with SMTP id crtfYY7687511xIWqAuTMZbo; Mon, 18 Sep 2023 08:17:51 -0700 X-Received: from mgamail.intel.com (mgamail.intel.com [134.134.136.20]) by mx.groups.io with SMTP id smtpd.web10.45867.1695019380756545437 for ; Sun, 17 Sep 2023 23:43:00 -0700 X-IronPort-AV: E=McAfee;i="6600,9927,10836"; a="369906090" X-IronPort-AV: E=Sophos;i="6.02,155,1688454000"; d="scan'208";a="369906090" X-Received: from orsmga004.jf.intel.com ([10.7.209.38]) by orsmga101.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 17 Sep 2023 23:42:49 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=McAfee;i="6600,9927,10836"; a="869450552" X-IronPort-AV: E=Sophos;i="6.02,155,1688454000"; d="scan'208";a="869450552" X-Received: from juichenx-mobl3.gar.corp.intel.com ([10.227.107.41]) by orsmga004.jf.intel.com with ESMTP; 17 Sep 2023 23:42:47 -0700 From: brucex.wang@intel.com To: devel@edk2.groups.io Cc: brucex.wang@intel.com, Guo Dong , Sean Rhodes , James Lu , Gua Guo Subject: [edk2-devel] [PATCH v4 4/4] UefiPayloadPkg: Add FIT support Date: Mon, 18 Sep 2023 14:42:34 +0800 Message-Id: <20230918064235.1440-5-brucex.wang@intel.com> In-Reply-To: <20230918064235.1440-1-brucex.wang@intel.com> References: <20230918064235.1440-1-brucex.wang@intel.com> MIME-Version: 1.0 Precedence: Bulk List-Subscribe: List-Help: Sender: devel@edk2.groups.io List-Id: Mailing-List: list devel@edk2.groups.io; contact devel+owner@edk2.groups.io Reply-To: devel@edk2.groups.io,brucex.wang@intel.com List-Unsubscribe-Post: List-Unsubscribe=One-Click List-Unsubscribe: X-Gm-Message-State: tPFC6pjzVwt1cFSJhgJLYaw4x7686176AA= Content-Transfer-Encoding: quoted-printable X-GND-Status: LEGIT Authentication-Results: spool.mail.gandi.net; dkim=pass header.d=groups.io header.s=20140610 header.b=AXegcVHs; dmarc=fail reason="SPF not aligned (relaxed), DKIM not aligned (relaxed)" header.from=intel.com (policy=none); spf=pass (spool.mail.gandi.net: domain of bounce@groups.io designates 66.175.222.108 as permitted sender) smtp.mailfrom=bounce@groups.io From: "Brucex.Wang" Provide Fit format for UniversalPayload, developer can use argument "--Fit" to build UniversalPayload.fit Cc: Guo Dong Cc: Sean Rhodes Cc: James Lu Cc: Gua Guo Signed-off-by: BruceX Wang --- .../Include/Guid/UniversalPayloadBase.h | 19 + UefiPayloadPkg/PayloadLoaderPeim/FitLib.h | 60 ++ .../PayloadLoaderPeim/FitLib/FitLib.c | 127 ++++ .../PayloadLoaderPeim/FitPayloadLoaderPeim.c | 150 ++++ .../FitPayloadLoaderPeim.inf | 59 ++ UefiPayloadPkg/Readme.md | 189 +++++ UefiPayloadPkg/Tools/MkFitImage.py | 272 ++++++++ .../FitUniversalPayloadEntry.c | 654 ++++++++++++++++++ .../FitUniversalPayloadEntry.inf | 98 +++ UefiPayloadPkg/UefiPayloadPkg.dec | 3 + UefiPayloadPkg/UefiPayloadPkg.dsc | 27 +- UefiPayloadPkg/UniversalPayloadBuild.py | 328 ++++++--- 12 files changed, 1890 insertions(+), 96 deletions(-) create mode 100644 UefiPayloadPkg/Include/Guid/UniversalPayloadBase.h create mode 100644 UefiPayloadPkg/PayloadLoaderPeim/FitLib.h create mode 100644 UefiPayloadPkg/PayloadLoaderPeim/FitLib/FitLib.c create mode 100644 UefiPayloadPkg/PayloadLoaderPeim/FitPayloadLoaderPeim.c create mode 100644 UefiPayloadPkg/PayloadLoaderPeim/FitPayloadLoaderPeim.i= nf create mode 100644 UefiPayloadPkg/Readme.md create mode 100644 UefiPayloadPkg/Tools/MkFitImage.py create mode 100644 UefiPayloadPkg/UefiPayloadEntry/FitUniversalPayloadEntr= y.c create mode 100644 UefiPayloadPkg/UefiPayloadEntry/FitUniversalPayloadEntr= y.inf diff --git a/UefiPayloadPkg/Include/Guid/UniversalPayloadBase.h b/UefiPaylo= adPkg/Include/Guid/UniversalPayloadBase.h new file mode 100644 index 0000000000..60f2aa37dd --- /dev/null +++ b/UefiPayloadPkg/Include/Guid/UniversalPayloadBase.h @@ -0,0 +1,19 @@ +/** @file=0D + Universal Payload general definitions.=0D +=0D +Copyright (c) 2023, Intel Corporation. All rights reserved.
=0D +SPDX-License-Identifier: BSD-2-Clause-Patent=0D +=0D +**/=0D +=0D +#ifndef UNIVERSAL_PAYLOAD_BASE_H_=0D +#define UNIVERSAL_PAYLOAD_BASE_H_=0D +=0D +extern GUID gUniversalPayloadBaseGuid;=0D +=0D +typedef struct {=0D + UNIVERSAL_PAYLOAD_GENERIC_HEADER Header;=0D + EFI_PHYSICAL_ADDRESS Entry;=0D +} UNIVERSAL_PAYLOAD_BASE;=0D +=0D +#endif // UNIVERSAL_PAYLOAD_BASE_H_=0D diff --git a/UefiPayloadPkg/PayloadLoaderPeim/FitLib.h b/UefiPayloadPkg/Pay= loadLoaderPeim/FitLib.h new file mode 100644 index 0000000000..0514d675a6 --- /dev/null +++ b/UefiPayloadPkg/PayloadLoaderPeim/FitLib.h @@ -0,0 +1,60 @@ +/** @file=0D + FIT Load Image Support=0D +Copyright (c) 2023, Intel Corporation. All rights reserved.
=0D +SPDX-License-Identifier: BSD-2-Clause-Patent=0D +**/=0D +=0D +#ifndef FIT_LIB_H_=0D +#define FIT_LIB_H_=0D +=0D +#include =0D +#include =0D +#include =0D +=0D +typedef struct {=0D + UINT64 RelocateType;=0D + UINT64 Offset;=0D +} FIT_RELOCATE_ITEM;=0D +=0D +typedef struct {=0D + EFI_PHYSICAL_ADDRESS ImageBase;=0D + EFI_PHYSICAL_ADDRESS PayloadBaseAddress;=0D + UINT64 PayloadSize;=0D + UINTN PayloadEntryOffset;=0D + UINTN PayloadEntrySize;=0D + EFI_PHYSICAL_ADDRESS PayloadEntryPoint;=0D + UINTN RelocateTableOffset;=0D + UINTN RelocateTableCount;=0D + EFI_PHYSICAL_ADDRESS PayloadLoadAddress;=0D +} FIT_IMAGE_CONTEXT;=0D +=0D +typedef struct {=0D + UINT8 *Name;=0D + UINT32 Offset;=0D +} PROPERTY_DATA;=0D +=0D +#define IMAGE_BASE_OFFSET OFFSET_OF (FIT_IMAGE_CONTEXT, ImageB= ase)=0D +#define PAYLOAD_BASE_ADDR_OFFSET OFFSET_OF (FIT_IMAGE_CONTEXT, Payloa= dBaseAddress)=0D +#define PAYLOAD_BASE_SIZE_OFFSET OFFSET_OF (FIT_IMAGE_CONTEXT, Payloa= dSize)=0D +#define PAYLOAD_ENTRY_OFFSET_OFFSET OFFSET_OF (FIT_IMAGE_CONTEXT, Payloa= dEntryOffset)=0D +#define PAYLOAD_ENTRY_SIZE_OFFSET OFFSET_OF (FIT_IMAGE_CONTEXT, Payloa= dEntrySize)=0D +#define PAYLOAD_ENTRY_POINT_OFFSET OFFSET_OF (FIT_IMAGE_CONTEXT, Payloa= dEntryPoint)=0D +#define RELOCATE_TABLE_OFFSET_OFFSET OFFSET_OF (FIT_IMAGE_CONTEXT, Reloca= teTableOffset)=0D +#define RELOCATE_TABLE_COUNT_OFFSET OFFSET_OF (FIT_IMAGE_CONTEXT, Reloca= teTableCount)=0D +#define PAYLOAD_LOAD_ADDR_OFFSET OFFSET_OF (FIT_IMAGE_CONTEXT, Payloa= dLoadAddress)=0D +=0D +/**=0D + Parse the FIT image info.=0D + @param[in] ImageBase Memory address of an image.=0D + @param[out] Context The FIT image context pointer.=0D + @retval EFI_UNSUPPORTED Unsupported binary type.=0D + @retval EFI_SUCCESS FIT binary is loaded successfully.=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +ParseFitImage (=0D + IN VOID *ImageBase,=0D + OUT FIT_IMAGE_CONTEXT *Context=0D + );=0D +=0D +#endif=0D diff --git a/UefiPayloadPkg/PayloadLoaderPeim/FitLib/FitLib.c b/UefiPayload= Pkg/PayloadLoaderPeim/FitLib/FitLib.c new file mode 100644 index 0000000000..9d1d8a4f61 --- /dev/null +++ b/UefiPayloadPkg/PayloadLoaderPeim/FitLib/FitLib.c @@ -0,0 +1,127 @@ +/** @file=0D + FIT Load Image Support=0D +Copyright (c) 2023, Intel Corporation. All rights reserved.
=0D +SPDX-License-Identifier: BSD-2-Clause-Patent=0D +**/=0D +=0D +#include "FitLib.h"=0D +=0D +PROPERTY_DATA PropertyData32List[] =3D {=0D + { "data-offset", PAYLOAD_ENTRY_OFFSET_OFFSET },=0D + { "data-size", PAYLOAD_ENTRY_SIZE_OFFSET },=0D + { "reloc-start", RELOCATE_TABLE_OFFSET_OFFSET }=0D +};=0D +=0D +PROPERTY_DATA PropertyData64List[] =3D {=0D + { "entry-start", PAYLOAD_ENTRY_POINT_OFFSET },=0D + { "load", PAYLOAD_LOAD_ADDR_OFFSET }=0D +};=0D +=0D +/**=0D + Parse the target firmware image info in FIT.=0D + @param[in] Fdt Memory address of a fdt.=0D + @param[in] Firmware Target name of an image.=0D + @param[out] Context The FIT image context pointer.=0D + @retval EFI_NOT_FOUND FIT node dose not find.=0D + @retval EFI_SUCCESS FIT binary is loaded successfully.=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +FitParseFirmwarePropertyData (=0D + IN VOID *Fdt,=0D + IN CHAR8 *Firmware,=0D + OUT FIT_IMAGE_CONTEXT *Context=0D + )=0D +{=0D + CONST FDT_PROPERTY *PropertyPtr;=0D + INT32 ImageNode;=0D + INT32 TianoNode;=0D + INT32 TempLen;=0D + UINT32 *Data32;=0D + UINT64 *Data64;=0D + UINT32 *ContextOffset32;=0D + UINT64 *ContextOffset64;=0D + INT32 Index;=0D +=0D + ImageNode =3D FdtSubnodeOffsetNameLen (Fdt, 0, "images", (INT32)AsciiStr= Len ("images"));=0D + if (ImageNode <=3D 0) {=0D + return EFI_NOT_FOUND;=0D + }=0D +=0D + TianoNode =3D FdtSubnodeOffsetNameLen (Fdt, ImageNode, Firmware, (INT32)= AsciiStrLen (Firmware));=0D + if (TianoNode <=3D 0) {=0D + return EFI_NOT_FOUND;=0D + }=0D +=0D + for (Index =3D 0; Index < sizeof (PropertyData32List) / sizeof (PROPERTY= _DATA); Index++) {=0D + PropertyPtr =3D FdtGetProperty (Fdt, TianoNode, PropertyData32Lis= t[Index].Name, &TempLen);=0D + Data32 =3D (UINT32 *)(PropertyPtr->Data);=0D + ContextOffset32 =3D (UINT32 *)((UINTN)Context + PropertyData32List[In= dex].Offset);=0D + *ContextOffset32 =3D Fdt32ToCpu (*Data32);=0D + }=0D +=0D + for (Index =3D 0; Index < sizeof (PropertyData64List)/sizeof (PROPERTY_D= ATA); Index++) {=0D + PropertyPtr =3D FdtGetProperty (Fdt, TianoNode, PropertyData64Lis= t[Index].Name, &TempLen);=0D + Data64 =3D (UINT64 *)(PropertyPtr->Data);=0D + ContextOffset64 =3D (UINT64 *)((UINTN)Context + PropertyData64List[In= dex].Offset);=0D + *ContextOffset64 =3D Fdt64ToCpu (*Data64);=0D + }=0D +=0D + return EFI_SUCCESS;=0D +}=0D +=0D +/**=0D + Parse the FIT image info.=0D + @param[in] ImageBase Memory address of an image.=0D + @param[out] Context The FIT image context pointer.=0D + @retval EFI_UNSUPPORTED Unsupported binary type.=0D + @retval EFI_SUCCESS FIT binary is loaded successfully.=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +ParseFitImage (=0D + IN VOID *ImageBase,=0D + OUT FIT_IMAGE_CONTEXT *Context=0D + )=0D +{=0D + VOID *Fdt;=0D + INT32 ConfigNode;=0D + INT32 Config1Node;=0D + CONST FDT_PROPERTY *PropertyPtr;=0D + INT32 TempLen;=0D + UINT32 *Data32;=0D + UINT64 Value;=0D + EFI_STATUS Status;=0D + UINTN UplSize;=0D + CHAR8 *Firmware;=0D +=0D + Status =3D FdtCheckHeader (ImageBase);=0D + if (EFI_ERROR (Status)) {=0D + return EFI_UNSUPPORTED;=0D + }=0D +=0D + Fdt =3D ImageBase;=0D + PropertyPtr =3D FdtGetProperty (Fdt, 0, "size", &TempLen);=0D + Data32 =3D (UINT32 *)(PropertyPtr->Data);=0D + UplSize =3D Value =3D Fdt32ToCpu (*Data32);=0D + ConfigNode =3D FdtSubnodeOffsetNameLen (Fdt, 0, "configurations", (INT3= 2)AsciiStrLen ("configurations"));=0D + if (ConfigNode <=3D 0) {=0D + return EFI_NOT_FOUND;=0D + }=0D +=0D + Config1Node =3D FdtSubnodeOffsetNameLen (Fdt, ConfigNode, "conf-1", (INT= 32)AsciiStrLen ("conf-1"));=0D + if (Config1Node <=3D 0) {=0D + return EFI_NOT_FOUND;=0D + }=0D +=0D + PropertyPtr =3D FdtGetProperty (Fdt, Config1Node, "firmware", &TempLen);= =0D + Firmware =3D (CHAR8 *)(PropertyPtr->Data);=0D +=0D + FitParseFirmwarePropertyData (Fdt, Firmware, Context);=0D +=0D + Context->ImageBase =3D (EFI_PHYSICAL_ADDRESS)ImageBase;=0D + Context->PayloadSize =3D UplSize;=0D + Context->RelocateTableCount =3D (Context->PayloadEntrySize - (Context->R= elocateTableOffset - Context->PayloadEntryOffset)) / sizeof (FIT_RELOCATE_I= TEM);=0D +=0D + return EFI_SUCCESS;=0D +}=0D diff --git a/UefiPayloadPkg/PayloadLoaderPeim/FitPayloadLoaderPeim.c b/Uefi= PayloadPkg/PayloadLoaderPeim/FitPayloadLoaderPeim.c new file mode 100644 index 0000000000..de33d49bd1 --- /dev/null +++ b/UefiPayloadPkg/PayloadLoaderPeim/FitPayloadLoaderPeim.c @@ -0,0 +1,150 @@ +/** @file=0D + FIT Load Image Support=0D +Copyright (c) 2023, Intel Corporation. All rights reserved.
=0D +SPDX-License-Identifier: BSD-2-Clause-Patent=0D +**/=0D +=0D +#include =0D +#include =0D +#include =0D +#include =0D +=0D +#include =0D +=0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +=0D +#include "FitLib.h"=0D +=0D +/**=0D + The wrapper function of PeiLoadImageLoadImage().=0D + @param This - Pointer to EFI_PEI_LOAD_FILE_PPI.=0D + @param FileHandle - Pointer to the FFS file header of the image.=0D + @param ImageAddressArg - Pointer to PE/TE image.=0D + @param ImageSizeArg - Size of PE/TE image.=0D + @param EntryPoint - Pointer to entry point of specified image file = for output.=0D + @param AuthenticationState - Pointer to attestation authentication state= of image.=0D + @return Status of PeiLoadImageLoadImage().=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +PeiLoadFileLoadPayload (=0D + IN CONST EFI_PEI_LOAD_FILE_PPI *This,=0D + IN EFI_PEI_FILE_HANDLE FileHandle,=0D + OUT EFI_PHYSICAL_ADDRESS *ImageAddressArg OPTIONAL,=0D + OUT UINT64 *ImageSizeArg OPTIONAL,=0D + OUT EFI_PHYSICAL_ADDRESS *EntryPoint,=0D + OUT UINT32 *AuthenticationState=0D + )=0D +{=0D + EFI_STATUS Status;=0D + FIT_IMAGE_CONTEXT Context;=0D + UINTN Instance;=0D + VOID *Binary;=0D + FIT_RELOCATE_ITEM *RelocateTable;=0D + UNIVERSAL_PAYLOAD_BASE *PayloadBase;=0D + UINTN Length;=0D + UINTN Delta;=0D + UINTN Index;=0D +=0D + Instance =3D 0;=0D + do {=0D + Status =3D PeiServicesFfsFindSectionData3 (EFI_SECTION_RAW, Instance++= , FileHandle, &Binary, AuthenticationState);=0D + if (EFI_ERROR (Status)) {=0D + return Status;=0D + }=0D +=0D + ZeroMem (&Context, sizeof (Context));=0D + Status =3D ParseFitImage (Binary, &Context);=0D + } while (EFI_ERROR (Status));=0D +=0D + if (EFI_ERROR (Status)) {=0D + ASSERT_EFI_ERROR (Status);=0D + return Status;=0D + }=0D +=0D + DEBUG ((=0D + DEBUG_INFO,=0D + "Before Rebase Payload File Base: 0x%08x, File Size: 0x%08X, EntryPoin= t: 0x%08x\n",=0D + Context.PayloadBaseAddress,=0D + Context.PayloadSize,=0D + Context.PayloadEntryPoint=0D + ));=0D + Context.PayloadBaseAddress =3D (EFI_PHYSICAL_ADDRESS)AllocatePages (EFI_= SIZE_TO_PAGES (Context.PayloadSize));=0D +=0D + RelocateTable =3D (FIT_RELOCATE_ITEM *)(UINTN)(Context.PayloadBaseAddres= s + Context.RelocateTableOffset);=0D + CopyMem ((VOID *)Context.PayloadBaseAddress, Binary, Context.PayloadSize= );=0D +=0D + if (Context.PayloadBaseAddress > Context.PayloadLoadAddress) {=0D + Delta =3D Context.PayloadBaseAddress - Context.Pa= yloadLoadAddress;=0D + Context.PayloadEntryPoint +=3D Delta;=0D + for (Index =3D 0; Index < Context.RelocateTableCount; Index++) {=0D + if ((RelocateTable[Index].RelocateType =3D=3D 10) || (RelocateTable[= Index].RelocateType =3D=3D 3)) {=0D + *((UINT64 *)(Context.PayloadBaseAddress + RelocateTable[Index].Off= set)) =3D *((UINT64 *)(Context.PayloadBaseAddress + RelocateTable[Index].Of= fset)) + Delta;=0D + }=0D + }=0D + } else {=0D + Delta =3D Context.PayloadLoadAddress - Context.Pa= yloadBaseAddress;=0D + Context.PayloadEntryPoint -=3D Delta;=0D + for (Index =3D 0; Index < Context.RelocateTableCount; Index++) {=0D + if ((RelocateTable[Index].RelocateType =3D=3D 10) || (RelocateTable[= Index].RelocateType =3D=3D 3)) {=0D + *((UINT64 *)(Context.PayloadBaseAddress + RelocateTable[Index].Off= set)) =3D *((UINT64 *)(Context.PayloadBaseAddress + RelocateTable[Index].Of= fset)) - Delta;=0D + }=0D + }=0D + }=0D +=0D + DEBUG ((=0D + DEBUG_INFO,=0D + "After Rebase Payload File Base: 0x%08x, File Size: 0x%08X, EntryPoint= : 0x%08x\n",=0D + Context.PayloadBaseAddress,=0D + Context.PayloadSize,=0D + Context.PayloadEntryPoint=0D + ));=0D +=0D + Length =3D sizeof (UNIVERSAL_PAYLOAD_BASE);=0D + PayloadBase =3D BuildGuidHob (=0D + &gUniversalPayloadBaseGuid,=0D + Length=0D + );=0D + PayloadBase->Entry =3D (EFI_PHYSICAL_ADDRESS)Context.ImageBase;=0D +=0D + *ImageAddressArg =3D Context.PayloadBaseAddress;=0D + *ImageSizeArg =3D Context.PayloadSize;=0D + *EntryPoint =3D Context.PayloadEntryPoint;=0D +=0D + return EFI_SUCCESS;=0D +}=0D +=0D +EFI_PEI_LOAD_FILE_PPI mPeiLoadFilePpi =3D {=0D + PeiLoadFileLoadPayload=0D +};=0D +=0D +EFI_PEI_PPI_DESCRIPTOR gPpiLoadFilePpiList =3D {=0D + (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),=0D + &gEfiPeiLoadFilePpiGuid,=0D + &mPeiLoadFilePpi=0D +};=0D +=0D +/**=0D + Install Pei Load File PPI.=0D + @param FileHandle Handle of the file being invoked.=0D + @param PeiServices Describes the list of possible PEI Services.=0D + @retval EFI_SUCESS The entry point executes successfully.=0D + @retval Others Some error occurs during the execution of this funct= ion.=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +InitializeFitPayloadLoaderPeim (=0D + IN EFI_PEI_FILE_HANDLE FileHandle,=0D + IN CONST EFI_PEI_SERVICES **PeiServices=0D + )=0D +{=0D + EFI_STATUS Status;=0D +=0D + Status =3D PeiServicesInstallPpi (&gPpiLoadFilePpiList);=0D +=0D + return Status;=0D +}=0D diff --git a/UefiPayloadPkg/PayloadLoaderPeim/FitPayloadLoaderPeim.inf b/Ue= fiPayloadPkg/PayloadLoaderPeim/FitPayloadLoaderPeim.inf new file mode 100644 index 0000000000..cd0cb186e1 --- /dev/null +++ b/UefiPayloadPkg/PayloadLoaderPeim/FitPayloadLoaderPeim.inf @@ -0,0 +1,59 @@ +## @file=0D +# Produce LoadFile PPI for payload loading.=0D +#=0D +# Copyright (c) 2023, Intel Corporation. All rights reserved.
=0D +#=0D +# SPDX-License-Identifier: BSD-2-Clause-Patent=0D +#=0D +##=0D +=0D +[Defines]=0D + INF_VERSION =3D 0x00010005=0D + BASE_NAME =3D FitPayloadLoaderPeim=0D + FILE_GUID =3D 55AC82C8-FC17-4C56-BCDA-990BB0A73E41= =0D + MODULE_TYPE =3D PEIM=0D + VERSION_STRING =3D 1.0=0D +=0D + ENTRY_POINT =3D InitializeFitPayloadLoaderPeim=0D +=0D +#=0D +# The following information is for reference only and not required by the = build tools.=0D +#=0D +# VALID_ARCHITECTURES =3D IA32 X64=0D +#=0D +=0D +[Sources]=0D + FitPayloadLoaderPeim.c=0D + FitLib.h=0D + FitLib/FitLib.c=0D +=0D +[Packages]=0D + MdePkg/MdePkg.dec=0D + MdeModulePkg/MdeModulePkg.dec=0D + PcAtChipsetPkg/PcAtChipsetPkg.dec=0D + UefiPayloadPkg/UefiPayloadPkg.dec=0D +=0D +[LibraryClasses]=0D + PcdLib=0D + MemoryAllocationLib=0D + BaseMemoryLib=0D + PeiServicesLib=0D + HobLib=0D + BaseLib=0D + PeimEntryPoint=0D + DebugLib=0D + FdtLib=0D +=0D +[Ppis]=0D + gEfiPeiLoadFilePpiGuid ## PRODUCES=0D +=0D +[Pcd]=0D + gPcAtChipsetPkgTokenSpaceGuid.PcdRtcIndexRegister=0D + gPcAtChipsetPkgTokenSpaceGuid.PcdRtcTargetRegister=0D +=0D +[Guids]=0D + gUniversalPayloadExtraDataGuid ## PRODUCES=0D + gUniversalPayloadBaseGuid ## PRODUCES=0D +=0D +[Depex]=0D + TRUE=0D diff --git a/UefiPayloadPkg/Readme.md b/UefiPayloadPkg/Readme.md new file mode 100644 index 0000000000..cb7f39b3f7 --- /dev/null +++ b/UefiPayloadPkg/Readme.md @@ -0,0 +1,189 @@ +# UefiPayloadPkg=0D +Provide UEFI Universal Payload for different bootloader to generate EFI en= vironment=0D +=0D +# Spec=0D +UniversalPayload URL: https://universalscalablefirmware.github.io/document= ation/2_universal_payload.html=0D +UniversalPayload URL: https://universalpayload.github.io/spec/=0D +ELF Format URL: https://refspecs.linuxfoundation.org/elf/elf.pdf=0D +FIT Format URL: https://universalpayload.github.io/spec/chapter2-payload-i= mage-format.html=0D +=0D +# Uefi UniversalPayload Format=0D + | Binary Format | HandOffPayload - HOB |=0D + |---------------|----------------------|=0D + | ELF | V (Default) |=0D + | FIT | V |=0D +=0D +# Binary Format=0D + - ELF=0D + ```=0D + + +-----------------------+=0D + | | UniversalPayloadEntry | <----------- UefiPayloadPkg= \UefiPayloadEntry\UniversalPayloadEntry.c:_ModuleEntryPoint (HOB)=0D + | +-----------------------+=0D + | | .upld_info | patch it directly=0D + ELF Format | +-----------------------+=0D + | | .upld.uefi_fv | patch it directly=0D + | +-----------------------+=0D + | | .upld.bds_fv | patch it directly=0D + | +-----------------------+=0D + | | .upld._fv | patch it directly=0D + + +-----------------------+=0D + ```=0D +=0D + - FIT=0D + ```=0D + + +-----------------------+=0D + FIT Data | | FIT Header | <----------- Generate by py= libfdt=0D + + +-----------------------+=0D + PECOFF Format | | UniversalPayloadEntry | <----------- UefiPayloadPkg= \UefiPayloadEntry\FitUniversalPayloadEntry.c:_ModuleEntryPoint (HOB)=0D + + +-----------------------+=0D + Relocate Data | | reloc-start |=0D + + +-----------------------+=0D + | | uefi_fv | patch it directly=0D + | +-----------------------+=0D + Multi Binary | | bds_fv | patch it directly=0D + | +-----------------------+=0D + | | afp_xxx_fv | patch it directly=0D + | +-----------------------+=0D + | | afp_xxx_fv | patch it directly=0D + + +-----------------------+=0D + ```=0D +=0D +# Environment=0D + - ELF=0D + ```=0D + Download and install https://github.com/llvm/llvm-project/releases/tag= /llvmorg-10.0.1=0D + ```=0D + - FIT=0D + - Windows=0D + ```powershell=0D + Set-ExecutionPolicy Bypass -Scope Process -Force; [System.Net.Servic= ePointManager]::SecurityProtocol =3D [System.Net.ServicePointManager]::Secu= rityProtocol -bor 3072; iex ((New-Object System.Net.WebClient).DownloadStri= ng('https://chocolatey.org/install.ps1'))=0D + choco install dtc-msys2=0D + pip3 install pefile=0D + pip3 install swig=0D + pip3 install pylibfdt=0D + ```=0D + - Ubuntu=0D + ```bash=0D + sudo apt install -y u-boot-tools=0D + pip3 install pefile=0D + pip3 install swig=0D + pip3 install pylibfdt=0D + ```=0D +# How to build UEFI UniversalPayload=0D + - Windows=0D + - edksetup Rebuild=0D + - Linux=0D + - make -C BaseTools=0D + - source edksetup.sh=0D +=0D + - UniversalPayload.elf=0D + - python UefiPayloadPkg/UniversalPayloadBuild.py -t =0D + - llvm-objdump -h Build/UefiPayloadPkgX64/UniversalPayload.elf=0D +=0D + - UniversalPayload.fit=0D + - python UefiPayloadPkg/UniversalPayloadBuild.py -t -= -Fit=0D + - fdtdump Build/UefiPayloadPkgX64/UniversalPayload.fit=0D +=0D +# Edk2boot + UefiUniversalPayload=0D +ELF Edk2boot use below way to support compress and sign.=0D +=0D +- ELF Behavior - Edk2boot + UefiUniversalPayload.elf=0D + ```=0D + Boot Flow=0D + +-----------------------------------------------------------------------= --------------+------------------------------------------------------------= -----------------------------------------------+-------------------+=0D + | Platform Init = | Universal Loader Interface = | OS |=0D + +-----------------------------------------------------------------------= --------------+------------------------------------------------------------= -----------------------------------------------+-------------------+=0D + = = HOBs=0D + SEC -> PEI -> DXE -> DXE IPL -> UefiPayloadPkg\PayloadLoaderPeim\Payload= LoaderPeim.c --------------------------------------------------------------= ----------------------> Load UniversalPayload.elf -> Operation System=0D +=0D +=0D + | Platform Initialize - Edk2 = = | UniversalPayload - Edk2 = |=0D + +-----------------------------------------------------------------------= ---------------------------------------------------------------------------= -----------------------------------------------+---------------------------= -----+=0D +=0D + Binary Format=0D +=0D + +-------------------+=0D + | BIOS.rom |=0D + +-------------------+=0D + | Other Firmware |=0D + +-------------------+=0D + | ... | FMMT = = UniversalPayloadBuild.py=0D + +-------------------+<----------------+-----------------------+ GenFfs = +-----------------------+ Rsa2048Sha256 Sign +-----------------------+ = LzmaCompress +----------------------+ GenSec +---------------------------= -----+=0D + | | | EDK2 FFS Header |<--------= ---| Rsa2048Sha256 Hash |<--------------------| UniversalPayload.lzma |<= --------------| EDK2 SEC Header |<--------| UniversalPayload.elf = |=0D + | RAW Data | +-----------------------+ = +-----------------------+ +-----------------------+ = +----------------------+ +---------------------------= -----+=0D + | | | Rsa2048Sha256 Hash | = | UniversalPayload.lzma | = | UniversalPayload.elf | | upld_info = |=0D + | | +-----------------------+ = +-----------------------+ = +----------------------+ +---------------------------= -----+=0D + | | | UniversalPayload.lzma | = = | upld_info | | upld.uefi_fv = |=0D + +-------------------+<----------------+-----------------------+ = = +----------------------+ +---------------------------= -----+=0D + | ... | = = | upld.uefi_fv | | upld.bds_fv = |=0D + +-------------------+ = = +----------------------+ +---------------------------= -----+=0D + | Other Firmware | = = | upld.bds_fv | | upld.AFP1 = |=0D + +-------------------+ = = +----------------------+ +---------------------------= -----+=0D + = = | upld.AFP1 | | upld.AFP2 = |=0D + = = +----------------------+ +---------------------------= -----+=0D + = = | upld.AFP2 | | ... = |=0D + = = +----------------------+ +---------------------------= -----+=0D + = = | ... | | upld.AFPn = |=0D + = = +----------------------+ +---------------------------= -----+=0D + = = | upld.AFPn |=0D + = = +----------------------+=0D + ```=0D +=0D +FIT Edk2boot use below way to support compress and sign=0D +- FIT Behavior - Edk2boot + UefiUniversalPayload.fit=0D + ```=0D + Boot Flow=0D + +-----------------------------------------------------------------------= --------------+------------------------------------------------------------= ------------+-------------------+=0D + | Platform Init = | Universal Loader Interface = | OS |=0D + +-----------------------------------------------------------------------= --------------+------------------------------------------------------------= ------------+-------------------+=0D + = HOBs=0D + SEC -> PEI -> DXE -> DXE IPL -> *UefiPayloadPkg\PayloadLoaderPeim\Payloa= dLoaderPeim.c ----------------------------------------------> Load Universa= lPayload.fit -> Operation System=0D +=0D + Binary Format=0D +=0D + | Platform Initialize - Edk2 = | UniversalPayload - Ed= k2 (UniversalPayloadBuild.py --Fit) |=0D + +-----------------------------------------------------------------------= ----------------------------------------------------+----------------------= -------------------------------------------------------------------+=0D +=0D + +-------------------+=0D + | BIOS.rom |=0D + +-------------------+=0D + | Other Firmware |=0D + +-------------------+=0D + | ... | FMMT = UniversalPayloadBuild.= py --Fit tianocore -> data-offset=0D + +-------------------+<----------------+--------------------------------+= GenFfs +--------------------------------+ GenSec +----------------------= ----------+ tianocore -> reloc-start +--------------------------+=0D + | | | EDK2 FFS Header |= <--------| EDK2 SEC Header |<--------| FIT Header = |<-------------------------| UniversalPayload.pecoff |=0D + | | +--------------------------------+= +--------------------------------+ | description =3D "Uefi= Payload"; | +--------------------------+=0D + | | | EDK2 SEC Header |= | FIT Header | | ... = |=0D + | RAW Data | +--------------------------------+= | | | images { = | uefi-fv -> data-offset +--------------------------+=0D + | | | FIT Header |= | | | tianocore {...}; = |<-------------------------| uefi_fv |=0D + | | | |= +--------------------------------+ | uefi-fv {...}; = | bds-fv -> data-offset +--------------------------+=0D + | | | |= | tianocore -> data | | bds-fv {...}; = |<-------------------------| bds_fv |=0D + | | +--------------------------------+= +--------------------------------+ | afp1-fv {...}; = | AFP1 -> data-offset +--------------------------+=0D + | | | tianocore -> data |= | tianocore -> reloc-start | | ... = |<-------------------------| AFP1 |=0D + | | +--------------------------------+= +--------------------------------+ | afpn-fv {...}; = | AFP2 -> data-offset +--------------------------+=0D + | | | tianocore -> reloc-start |= | uefi-fv -> data | | } = |<-------------------------| AFP2 |=0D + | | +--------------------------------+= +--------------------------------+ | configurations { = | ... +--------------------------+=0D + | | | uefi-fv -> data |= | bds-fv -> data | | conf-1 {...} = |<-------------------------| ... |=0D + | | +--------------------------------+= +--------------------------------+ | } = | AFPn -> data-offset +--------------------------+=0D + | | | bds-fv -> data |= | AFP1-fv -> data | | = |<-------------------------| AFPn |=0D + | | +--------------------------------+= +--------------------------------+ | = | +--------------------------+=0D + | | | AFP1-fv -> data |= | AFP2-fv -> data | | = |=0D + | | +--------------------------------+= +--------------------------------+ +----------------------= ----------+=0D + | | | AFP2-fv -> data |= | ... | | tianocore -> data = |=0D + | | +--------------------------------+= +--------------------------------+ +----------------------= ----------+=0D + | | | ... |= | AFPn-fv -> data | | tianocore -> reloc-st= art |=0D + | | +--------------------------------+= +--------------------------------+ +----------------------= ----------+=0D + | | | AFPn-fv -> data |= | uefi-fv -> data = |=0D + +-------------------+<----------------+--------------------------------+= +----------------------= ----------+=0D + | ... | = | bds-fv -> data = |=0D + +-------------------+ = +----------------------= ----------+=0D + | Other Firmware | = | AFP1-fv -> data = |=0D + +-------------------+ = +----------------------= ----------+=0D + = | AFP2-fv -> data = |=0D + = +----------------------= ----------+=0D + = | ... = |=0D + = +----------------------= ----------+=0D + = | AFPn-fv -> data = |=0D + = +----------------------= ----------+=0D +=0D + ```=0D diff --git a/UefiPayloadPkg/Tools/MkFitImage.py b/UefiPayloadPkg/Tools/MkFi= tImage.py new file mode 100644 index 0000000000..82ab933d6d --- /dev/null +++ b/UefiPayloadPkg/Tools/MkFitImage.py @@ -0,0 +1,272 @@ +## @file=0D +# This file is a script to build fit image.=0D +# It generate a dtb header and combine a binary file after this header.=0D +#=0D +# Copyright (c) 2023, Intel Corporation. All rights reserved.
=0D +# SPDX-License-Identifier: BSD-2-Clause-Patent=0D +##=0D +=0D +from os.path import exists=0D +import libfdt=0D +from ctypes import *=0D +import time=0D +=0D +class FIT_IMAGE_INFO_HEADER:=0D + """Class for user setting data to use MakeFitImage()=0D + """=0D + _pack_ =3D 1=0D + _fields_ =3D [=0D + ('Compatible', str),=0D + ('UplVersion', int),=0D + ('Description', str),=0D + ('Type', str),=0D + ('Arch', str),=0D + ('Compression', str),=0D + ('Revision', int),=0D + ('BuildType', str),=0D + ('Capabilities', str),=0D + ('Producer', str),=0D + ('ImageId', str),=0D + ('DataOffset', int),=0D + ('DataSize', int),=0D + ('RelocStart', int),=0D + ('LoadAddr', int),=0D + ('Entry', int),=0D + ('Binary', str),=0D + ('TargetPath', str),=0D + ('UefifvPath', str),=0D + ('BdsfvPath', str),=0D + ('NetworkfvPath', str),=0D + ('Project', str),=0D + ]=0D +=0D + def __init__(self):=0D + self.Compatible =3D 'universal-payload'=0D + self.UplVersion =3D 0x0100=0D + self.TargetPath =3D 'mkimage.fit'=0D +=0D +def CreatFdt(Fdt):=0D + FdtEmptyTree =3D libfdt.fdt_create_empty_tree(Fdt, len(Fdt))=0D + if FdtEmptyTree !=3D 0:=0D + print('\n- Failed - Create Fdt failed!')=0D + return False=0D + return True=0D +=0D +def BuildConfNode(Fdt, ParentNode, MultiImage):=0D + ConfNode1 =3D libfdt.fdt_add_subnode(Fdt, ParentNode, 'conf-1')=0D +=0D + libfdt.fdt_setprop(Fdt, ConfNode1, 'require-fit', b'', 0)=0D + libfdt.fdt_setprop(Fdt, ConfNode1, 'firmware', bytes('tianocore', 'utf= -8'), len('tianocore') + 1)=0D +=0D +def BuildFvImageNode(Fdt, InfoHeader, ParentNode, DataOffset, DataSize, De= scription):=0D + libfdt.fdt_setprop_u32(Fdt, ParentNode, 'data-size', DataSize)=0D + libfdt.fdt_setprop_u32(Fdt, ParentNode, 'data-offset', DataOffset)=0D + libfdt.fdt_setprop(Fdt, ParentNode, 'compression', bytes('none', = 'utf-8'), len('none') + 1)=0D + libfdt.fdt_setprop(Fdt, ParentNode, 'project ', bytes('tianocore', = 'utf-8'), len('tianocore') + 1)=0D + libfdt.fdt_setprop(Fdt, ParentNode, 'arch', bytes('x86_64', = 'utf-8'), len('x86_64') + 1)=0D + libfdt.fdt_setprop(Fdt, ParentNode, 'type', bytes('flat-binary'= , 'utf-8'), len('flat-binary') + 1)=0D + libfdt.fdt_setprop(Fdt, ParentNode, 'description', bytes(Description, = 'utf-8'), len(Description) + 1)=0D +=0D +def BuildTianoImageNode(Fdt, InfoHeader, ParentNode, DataOffset, DataSize,= Description):=0D + #=0D + # Set 'load' and 'data-offset' to reserve the memory first.=0D + # They would be set again when Fdt completes or this function parses t= arget binary file.=0D + #=0D + if InfoHeader.LoadAddr is not None:=0D + libfdt.fdt_setprop_u64(Fdt, ParentNode, 'load', InfoHeader.LoadAdd= r)=0D + if InfoHeader.Entry is not None:=0D + libfdt.fdt_setprop_u64(Fdt, ParentNode, 'entry-start', InfoHeader.= Entry)=0D + if InfoHeader.RelocStart is not None:=0D + libfdt.fdt_setprop_u32(Fdt, ParentNode, 'reloc-start', InfoHeader.= RelocStart)=0D + if InfoHeader.DataSize is not None:=0D + libfdt.fdt_setprop_u32(Fdt, ParentNode, 'data-size', DataSize)=0D + if InfoHeader.DataOffset is not None:=0D + libfdt.fdt_setprop_u32(Fdt, ParentNode, 'data-offset', DataOffset)= =0D + if InfoHeader.Producer is not None:=0D + libfdt.fdt_setprop(Fdt, ParentNode, 'producer ', bytes(InfoHeader.= Producer, 'utf-8'), len(InfoHeader.Producer) + 1)=0D + if InfoHeader.Capabilities is not None:=0D + CapStrs =3D ','.join(InfoHeader.Capabilities)=0D + libfdt.fdt_setprop(Fdt, ParentNode, 'capabilities ', bytes(CapStrs= , 'utf-8'), len(CapStrs) + 1)=0D + if InfoHeader.Type is not None:=0D + libfdt.fdt_setprop(Fdt, ParentNode, 'type ', bytes(InfoHeader.Type= , 'utf-8'), len(InfoHeader.Type) + 1)=0D + if InfoHeader.Arch is not None:=0D + libfdt.fdt_setprop(Fdt, ParentNode, 'arch ', bytes(InfoHeader.Arch= , 'utf-8'), len(InfoHeader.Arch) + 1)=0D + if InfoHeader.Project is not None:=0D + libfdt.fdt_setprop(Fdt, ParentNode, 'project ', bytes(InfoHeader.P= roject, 'utf-8'), len(InfoHeader.Project) + 1)=0D + if InfoHeader.Description is not None:=0D + libfdt.fdt_setprop(Fdt, ParentNode, 'description', bytes(Descripti= on, 'utf-8'), len(Description) + 1)=0D +=0D +#=0D +# The subnode would be inserted from bottom to top of structure block.=0D +#=0D +def BuildFitImage(Fdt, InfoHeader):=0D + MultiImage =3D [=0D + ["tianocore", InfoHeader.Binary, BuildTianoImageNode , In= foHeader.Description, None, 0 ],=0D + ["uefi-fv", InfoHeader.UefifvPath, BuildFvImageNode, "U= EFI Firmware Volume", None, 0 ],=0D + ["bds-fv", InfoHeader.BdsfvPath, BuildFvImageNode , "B= DS Firmware Volume", None, 0 ],=0D + ["network-fv", InfoHeader.NetworkfvPath, BuildFvImageNode , "N= etwork Firmware Volume", None, 0 ],=0D + ]=0D +=0D + #=0D + # Set basic information=0D + #=0D + libfdt.fdt_setprop_u32(Fdt, 0, 'build-revision ', InfoHeader.Revision)= =0D + libfdt.fdt_setprop_u32(Fdt, 0, 'spec-version', InfoHeader.UplVersion)= =0D +=0D + #=0D + # Build configurations node=0D + #=0D + ConfNode =3D libfdt.fdt_add_subnode(Fdt, 0, 'configurations')=0D + BuildConfNode(Fdt, ConfNode, MultiImage)=0D +=0D + # Build image=0D + DataOffset =3D InfoHeader.DataOffset=0D + for Index in range (0, len (MultiImage)):=0D + _, Path, _, _, _, _ =3D MultiImage[Index]=0D + if exists(Path) =3D=3D 1:=0D + TempBinary =3D open(Path, 'rb')=0D + BinaryData =3D TempBinary.read()=0D + TempBinary.close()=0D + MultiImage[Index][-2] =3D BinaryData=0D + MultiImage[Index][-1] =3D DataOffset=0D + DataOffset +=3D len (BinaryData)=0D + libfdt.fdt_setprop_u32(Fdt, 0, 'size', DataOffset)=0D + posix_time =3D int(time.time())=0D + libfdt.fdt_setprop_u32(Fdt, 0, 'timestamp', posix_time)=0D + DescriptionFit =3D 'Uefi OS Loader'=0D + libfdt.fdt_setprop(Fdt, 0, 'description', bytes(DescriptionFit, 'utf-8= '), len(DescriptionFit) + 1)=0D +=0D + ImageNode =3D libfdt.fdt_add_subnode(Fdt, 0, 'images')=0D + for Item in reversed (MultiImage):=0D + Name, Path, BuildFvNode, Description, BinaryData, DataOffset =3D I= tem=0D + FvNode =3D libfdt.fdt_add_subnode(Fdt, ImageNode, Name)=0D + BuildFvNode (Fdt, InfoHeader, FvNode, DataOffset, len(BinaryData),= Description)=0D +=0D + #=0D + # Create new image file and combine all binary.=0D + #=0D + DtbFile =3D open(InfoHeader.TargetPath, "wb")=0D + DtbFile.truncate()=0D + DtbFile.write(Fdt)=0D + for Item in MultiImage:=0D + _, _, _, _, BinaryData, _ =3D Item=0D + DtbFile.write(BinaryData)=0D + DtbFile.close()=0D +=0D + return True=0D +=0D +def MakeFitImage(InfoHeader):=0D + #=0D + # Allocate fdt byte array.=0D + #=0D + Fdt =3D bytearray(InfoHeader.DataOffset)=0D +=0D + #=0D + # Create fdt empty tree.=0D + #=0D + if CreatFdt(Fdt) is False:=0D + return False=0D +=0D + #=0D + # Parse args to build fit image.=0D + #=0D + return BuildFitImage(Fdt, InfoHeader)=0D +=0D +def ReplaceFv (UplBinary, SectionFvFile, SectionName):=0D + try:=0D + #=0D + # Get Original Multi Fv=0D + #=0D + with open (UplBinary, "rb") as File:=0D + Dtb =3D File.read ()=0D + Fit =3D libfdt.Fdt (Dtb)=0D + NewFitHeader =3D bytearray(Dtb[0:Fit.totalsize()])=0D + FitSize =3D len(Dtb)=0D +=0D + LoadablesList =3D []=0D + ImagesNode =3D libfdt.fdt_subnode_offset(NewFitHeader, 0, 'imag= es')=0D + FvNode =3D libfdt.fdt_subnode_offset(NewFitHeader, ImagesNo= de, 'uefi-fv')=0D + NodeDepth =3D libfdt.fdt_node_depth (NewFitHeader, ImagesNode)= =0D + node_name =3D libfdt.fdt_get_name(NewFitHeader, FvNode)=0D + FvNode =3D libfdt.fdt_next_node(NewFitHeader, FvNode, NodeD= epth)=0D +=0D + while node_name[0][-2:] =3D=3D 'fv':=0D + LoadablesList.append (node_name[0])=0D + node_name =3D libfdt.fdt_get_name(NewFitHeader, FvNode[0])=0D + FvNode =3D libfdt.fdt_next_node(NewFitHeader, FvNode[0], NodeD= epth)=0D + #=0D + # Get current Fit Binary FV data=0D + #=0D + MultiFvList =3D []=0D + for Item in LoadablesList:=0D + ImageNode =3D libfdt.fdt_subnode_offset(NewFitHeader, Image= sNode, Item)=0D + ImageOffset =3D int.from_bytes (libfdt.fdt_getprop (NewFitHea= der, ImageNode, 'data-offset')[0], 'big')=0D + ImageSize =3D int.from_bytes (libfdt.fdt_getprop (NewFitHea= der, ImageNode, 'data-size')[0], 'big')=0D + MultiFvList.append ([Item, Dtb[ImageOffset:ImageOffset + Image= Size]])=0D +=0D + IsFvExist =3D False=0D + for Index in range (0, len (MultiFvList)):=0D + if MultiFvList[Index][0] =3D=3D SectionName:=0D + with open (SectionFvFile, 'rb') as File:=0D + MultiFvList[Index][1] =3D File.read ()=0D + ImageNode =3D libfdt.fdt_subnode_offset(NewFitHeader, = ImagesNode, SectionName)=0D + ImageSize =3D int.from_bytes (libfdt.fdt_getprop (NewF= itHeader, ImageNode, 'data-size')[0], 'big')=0D + ReplaceOffset =3D int.from_bytes (libfdt.fdt_getprop (NewF= itHeader, ImageNode, 'data-offset')[0], 'big')=0D + OffsetDelta =3D len(MultiFvList[Index][1]) - ImageSize=0D + FitSize +=3D OffsetDelta=0D + IsFvExist =3D True=0D + libfdt.fdt_setprop_u32(NewFitHeader, ImageNode, 'data-size= ', len(MultiFvList[Index][1]))=0D +=0D + #=0D + # Update new fit header=0D + #=0D + ImagesNode =3D libfdt.fdt_subnode_offset(NewFitHeader, 0, 'images'= )=0D + if (IsFvExist =3D=3D False):=0D + with open (SectionFvFile, 'rb') as File:=0D + SectionFvFileBinary =3D File.read ()=0D + MultiFvList.append ([SectionName, SectionFvFileBinary])=0D + FvNode =3D libfdt.fdt_add_subnode(NewFitHeader, ImagesNode, Se= ctionName)=0D + BuildFvImageNode (NewFitHeader, None, FvNode, FitSize, len(Sec= tionFvFileBinary), SectionName + " Firmware Volume")=0D + FitSize +=3D len(SectionFvFileBinary)=0D + else:=0D + for Index in range (0, len (MultiFvList)):=0D + ImageNode =3D libfdt.fdt_subnode_offset(NewFitHeader, I= magesNode, MultiFvList[Index][0])=0D + ImageOffset =3D int.from_bytes (libfdt.fdt_getprop (NewFi= tHeader, ImageNode, 'data-offset')[0], 'big')=0D + if ImageOffset > ReplaceOffset:=0D + libfdt.fdt_setprop_u32(NewFitHeader, ImageNode, 'data-= offset', ImageOffset + OffsetDelta)=0D +=0D + ConfNodes =3D libfdt.fdt_subnode_offset(NewFitHeader, 0, 'conf= igurations')=0D + libfdt.fdt_setprop(NewFitHeader, ConfNodes, 'default ', bytes('con= f-1', 'utf-8'), len('conf-1') + 1)=0D + ConfNode =3D libfdt.fdt_subnode_offset(NewFitHeader, ConfNode= s, 'conf-1')=0D +=0D + libfdt.fdt_setprop_u32(NewFitHeader, 0, 'size', FitSize)=0D +=0D + #=0D + # Generate new fit image=0D + #=0D + ImagesNode =3D libfdt.fdt_subnode_offset(NewFitHeader, 0, 'imag= es')=0D + TianoNode =3D libfdt.fdt_subnode_offset(NewFitHeader, ImagesNo= de, 'tianocore')=0D + TianoOffset =3D int.from_bytes (libfdt.fdt_getprop (NewFitHeader= , TianoNode, 'data-offset')[0], 'big')=0D + TianoSize =3D int.from_bytes (libfdt.fdt_getprop (NewFitHeader= , TianoNode, 'data-size')[0], 'big')=0D + TianoBinary =3D Dtb[TianoOffset:TianoOffset + TianoSize]=0D +=0D + print("\nGenerate new fit image:")=0D + NewUplBinary =3D bytearray(FitSize)=0D + print("Update fit header\t to 0x0\t\t ~ " + str(hex(len(NewFitHead= er))))=0D + NewUplBinary[:len(NewFitHeader)] =3D NewFitHeader=0D + print("Update tiano image\t to " + str(hex(len(NewFitHeader))) + "= \t ~ " + str(hex(len(NewFitHeader) + len(TianoBinary))))=0D + NewUplBinary[len(NewFitHeader):len(NewFitHeader) + len(TianoBinary= )] =3D TianoBinary=0D + for Index in range (0, len (MultiFvList)):=0D + ImageNode =3D libfdt.fdt_subnode_offset(NewFitHeader, Images= Node, MultiFvList[Index][0])=0D + ImageOffset =3D int.from_bytes (libfdt.fdt_getprop (NewFitHead= er, ImageNode, 'data-offset')[0], 'big')=0D + ImageSize =3D int.from_bytes (libfdt.fdt_getprop (NewFitHead= er, ImageNode, 'data-size')[0], 'big')=0D + NewUplBinary[ImageOffset:ImageOffset + ImageSize] =3D MultiFvL= ist[Index][1]=0D + print("Update " + MultiFvList[Index][0] + "\t\t to " + str(hex= (ImageOffset)) + "\t ~ " + str(hex(ImageOffset + ImageSize)))=0D +=0D + with open (UplBinary, "wb") as File:=0D + File.write (NewUplBinary)=0D +=0D + return 0=0D + except Exception as Ex:=0D + print(Ex)=0D + return 1=0D diff --git a/UefiPayloadPkg/UefiPayloadEntry/FitUniversalPayloadEntry.c b/U= efiPayloadPkg/UefiPayloadEntry/FitUniversalPayloadEntry.c new file mode 100644 index 0000000000..ad04ad7eb9 --- /dev/null +++ b/UefiPayloadPkg/UefiPayloadEntry/FitUniversalPayloadEntry.c @@ -0,0 +1,654 @@ +/** @file=0D + Copyright (c) 2023, Intel Corporation. All rights reserved.
=0D + SPDX-License-Identifier: BSD-2-Clause-Patent=0D +**/=0D +=0D +#include "UefiPayloadEntry.h"=0D +#include =0D +#include =0D +=0D +#define MEMORY_ATTRIBUTE_MASK (EFI_RESOURCE_ATTRIBUTE_PRESENT = | \=0D + EFI_RESOURCE_ATTRIBUTE_INITIALIZED = | \=0D + EFI_RESOURCE_ATTRIBUTE_TESTED = | \=0D + EFI_RESOURCE_ATTRIBUTE_READ_PROTECT= ED | \=0D + EFI_RESOURCE_ATTRIBUTE_WRITE_PROTEC= TED | \=0D + EFI_RESOURCE_ATTRIBUTE_EXECUTION_PR= OTECTED | \=0D + EFI_RESOURCE_ATTRIBUTE_READ_ONLY_PR= OTECTED | \=0D + EFI_RESOURCE_ATTRIBUTE_16_BIT_IO = | \=0D + EFI_RESOURCE_ATTRIBUTE_32_BIT_IO = | \=0D + EFI_RESOURCE_ATTRIBUTE_64_BIT_IO = | \=0D + EFI_RESOURCE_ATTRIBUTE_PERSISTENT = )=0D +=0D +#define TESTED_MEMORY_ATTRIBUTES (EFI_RESOURCE_ATTRIBUTE_PRESENT | = \=0D + EFI_RESOURCE_ATTRIBUTE_INITIALIZED = | \=0D + EFI_RESOURCE_ATTRIBUTE_TESTED = )=0D +=0D +extern VOID *mHobList;=0D +=0D +CHAR8 *mLineBuffer =3D NULL;=0D +=0D +/**=0D + Print all HOBs info from the HOB list.=0D + @return The pointer to the HOB list.=0D +**/=0D +VOID=0D +PrintHob (=0D + IN CONST VOID *HobStart=0D + );=0D +=0D +/**=0D + Find the first substring.=0D + @param String Point to the string where to find the substring.=0D + @param CharSet Point to the string to be found.=0D +**/=0D +UINTN=0D +EFIAPI=0D +AsciiStrSpn (=0D + IN CHAR8 *String,=0D + IN CHAR8 *CharSet=0D + )=0D +{=0D + UINTN Count;=0D + CHAR8 *Str1;=0D + CHAR8 *Str2;=0D +=0D + Count =3D 0;=0D +=0D + for (Str1 =3D String; *Str1 !=3D L'\0'; Str1++) {=0D + for (Str2 =3D CharSet; *Str2 !=3D L'\0'; Str2++) {=0D + if (*Str1 =3D=3D *Str2) {=0D + break;=0D + }=0D + }=0D +=0D + if (*Str2 =3D=3D L'\0') {=0D + return Count;=0D + }=0D +=0D + Count++;=0D + }=0D +=0D + return Count;=0D +}=0D +=0D +/**=0D + Searches a string for the first occurrence of a character contained in a= =0D + specified buffer.=0D + @param String Point to the string where to find the substring.=0D + @param CharSet Point to the string to be found.=0D +**/=0D +CHAR8 *=0D +EFIAPI=0D +AsciiStrBrk (=0D + IN CHAR8 *String,=0D + IN CHAR8 *CharSet=0D + )=0D +{=0D + CHAR8 *Str1;=0D + CHAR8 *Str2;=0D +=0D + for (Str1 =3D String; *Str1 !=3D L'\0'; Str1++) {=0D + for (Str2 =3D CharSet; *Str2 !=3D L'\0'; Str2++) {=0D + if (*Str1 =3D=3D *Str2) {=0D + return (CHAR8 *)Str1;=0D + }=0D + }=0D + }=0D +=0D + return NULL;=0D +}=0D +=0D +/**=0D + Find the next token after one or more specified characters.=0D + @param String Point to the string where to find the substring.=0D + @param CharSet Point to the string to be found.=0D +**/=0D +CHAR8 *=0D +EFIAPI=0D +AsciiStrTokenLine (=0D + IN CHAR8 *String OPTIONAL,=0D + IN CHAR8 *CharSet=0D + )=0D +{=0D + CHAR8 *Begin;=0D + CHAR8 *End;=0D +=0D + Begin =3D (String =3D=3D NULL) ? mLineBuffer : String;=0D + if (Begin =3D=3D NULL) {=0D + return NULL;=0D + }=0D +=0D + Begin +=3D AsciiStrSpn (Begin, CharSet);=0D + if (*Begin =3D=3D L'\0') {=0D + mLineBuffer =3D NULL;=0D + return NULL;=0D + }=0D +=0D + End =3D AsciiStrBrk (Begin, CharSet);=0D + if ((End !=3D NULL) && (*End !=3D L'\0')) {=0D + *End =3D L'\0';=0D + End++;=0D + }=0D +=0D + mLineBuffer =3D End;=0D + return Begin;=0D +}=0D +=0D +/**=0D + Some bootloader may pass a pcd database, and UPL also contain a PCD data= base.=0D + Dxe PCD driver has the assumption that the two PCD database can be caten= ated and=0D + the local token number should be successive.=0D + This function will fix up the UPL PCD database to meet that assumption.= =0D + @param[in] DxeFv The FV where to find the Universal PCD databa= se.=0D + @retval EFI_SUCCESS If it completed successfully.=0D + @retval other Failed to fix up.=0D +**/=0D +EFI_STATUS=0D +FixUpPcdDatabase (=0D + IN EFI_FIRMWARE_VOLUME_HEADER *DxeFv=0D + )=0D +{=0D + EFI_STATUS Status;=0D + EFI_FFS_FILE_HEADER *FileHeader;=0D + VOID *PcdRawData;=0D + PEI_PCD_DATABASE *PeiDatabase;=0D + PEI_PCD_DATABASE *UplDatabase;=0D + EFI_HOB_GUID_TYPE *GuidHob;=0D + DYNAMICEX_MAPPING *ExMapTable;=0D + UINTN Index;=0D +=0D + GuidHob =3D GetFirstGuidHob (&gPcdDataBaseHobGuid);=0D + if (GuidHob =3D=3D NULL) {=0D + //=0D + // No fix-up is needed.=0D + //=0D + return EFI_SUCCESS;=0D + }=0D +=0D + PeiDatabase =3D (PEI_PCD_DATABASE *)GET_GUID_HOB_DATA (GuidHob);=0D + DEBUG ((DEBUG_INFO, "Find the Pei PCD data base, the total local token n= umber is %d\n", PeiDatabase->LocalTokenCount));=0D +=0D + Status =3D FvFindFileByTypeGuid (DxeFv, EFI_FV_FILETYPE_DRIVER, PcdGetPt= r (PcdPcdDriverFile), &FileHeader);=0D + ASSERT_EFI_ERROR (Status);=0D + if (EFI_ERROR (Status)) {=0D + return Status;=0D + }=0D +=0D + Status =3D FileFindSection (FileHeader, EFI_SECTION_RAW, &PcdRawData);=0D + ASSERT_EFI_ERROR (Status);=0D + if (EFI_ERROR (Status)) {=0D + return Status;=0D + }=0D +=0D + UplDatabase =3D (PEI_PCD_DATABASE *)PcdRawData;=0D + ExMapTable =3D (DYNAMICEX_MAPPING *)(UINTN)((UINTN)PcdRawData + UplData= base->ExMapTableOffset);=0D +=0D + for (Index =3D 0; Index < UplDatabase->ExTokenCount; Index++) {=0D + ExMapTable[Index].TokenNumber +=3D PeiDatabase->LocalTokenCount;=0D + }=0D +=0D + DEBUG ((DEBUG_INFO, "Fix up UPL PCD database successfully\n"));=0D + return EFI_SUCCESS;=0D +}=0D +=0D +/**=0D + Add HOB into HOB list=0D + @param[in] Hob The HOB to be added into the HOB list.=0D +**/=0D +VOID=0D +AddNewHob (=0D + IN EFI_PEI_HOB_POINTERS *Hob=0D + )=0D +{=0D + EFI_PEI_HOB_POINTERS NewHob;=0D +=0D + if (Hob->Raw =3D=3D NULL) {=0D + return;=0D + }=0D +=0D + NewHob.Header =3D CreateHob (Hob->Header->HobType, Hob->Header->HobLengt= h);=0D +=0D + if (NewHob.Header !=3D NULL) {=0D + CopyMem (NewHob.Header + 1, Hob->Header + 1, Hob->Header->HobLength - = sizeof (EFI_HOB_GENERIC_HEADER));=0D + }=0D +}=0D +=0D +/**=0D + Found the Resource Descriptor HOB that contains a range (Base, Top)=0D + @param[in] HobList Hob start address=0D + @param[in] Base Memory start address=0D + @param[in] Top Memory end address.=0D + @retval The pointer to the Resource Descriptor HOB.=0D +**/=0D +EFI_HOB_RESOURCE_DESCRIPTOR *=0D +FindResourceDescriptorByRange (=0D + IN VOID *HobList,=0D + IN EFI_PHYSICAL_ADDRESS Base,=0D + IN EFI_PHYSICAL_ADDRESS Top=0D + )=0D +{=0D + EFI_PEI_HOB_POINTERS Hob;=0D + EFI_HOB_RESOURCE_DESCRIPTOR *ResourceHob;=0D +=0D + for (Hob.Raw =3D (UINT8 *)HobList; !END_OF_HOB_LIST (Hob); Hob.Raw =3D G= ET_NEXT_HOB (Hob)) {=0D + //=0D + // Skip all HOBs except Resource Descriptor HOBs=0D + //=0D + if (GET_HOB_TYPE (Hob) !=3D EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {=0D + continue;=0D + }=0D +=0D + //=0D + // Skip Resource Descriptor HOBs that do not describe tested system me= mory=0D + //=0D + ResourceHob =3D Hob.ResourceDescriptor;=0D + if (ResourceHob->ResourceType !=3D EFI_RESOURCE_SYSTEM_MEMORY) {=0D + continue;=0D + }=0D +=0D + if ((ResourceHob->ResourceAttribute & MEMORY_ATTRIBUTE_MASK) !=3D TEST= ED_MEMORY_ATTRIBUTES) {=0D + continue;=0D + }=0D +=0D + //=0D + // Skip Resource Descriptor HOBs that do not contain the PHIT range Ef= iFreeMemoryBottom..EfiFreeMemoryTop=0D + //=0D + if (Base < ResourceHob->PhysicalStart) {=0D + continue;=0D + }=0D +=0D + if (Top > (ResourceHob->PhysicalStart + ResourceHob->ResourceLength)) = {=0D + continue;=0D + }=0D +=0D + return ResourceHob;=0D + }=0D +=0D + return NULL;=0D +}=0D +=0D +/**=0D + Find the highest below 4G memory resource descriptor, except the input R= esource Descriptor.=0D + @param[in] HobList Hob start address=0D + @param[in] MinimalNeededSize Minimal needed size.=0D + @param[in] ExceptResourceHob Ignore this Resource Descriptor.=0D + @retval The pointer to the Resource Descriptor HOB.=0D +**/=0D +EFI_HOB_RESOURCE_DESCRIPTOR *=0D +FindAnotherHighestBelow4GResourceDescriptor (=0D + IN VOID *HobList,=0D + IN UINTN MinimalNeededSize,=0D + IN EFI_HOB_RESOURCE_DESCRIPTOR *ExceptResourceHob=0D + )=0D +{=0D + EFI_PEI_HOB_POINTERS Hob;=0D + EFI_HOB_RESOURCE_DESCRIPTOR *ResourceHob;=0D + EFI_HOB_RESOURCE_DESCRIPTOR *ReturnResourceHob;=0D +=0D + ReturnResourceHob =3D NULL;=0D +=0D + for (Hob.Raw =3D (UINT8 *)HobList; !END_OF_HOB_LIST (Hob); Hob.Raw =3D G= ET_NEXT_HOB (Hob)) {=0D + //=0D + // Skip all HOBs except Resource Descriptor HOBs=0D + //=0D + if (GET_HOB_TYPE (Hob) !=3D EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {=0D + continue;=0D + }=0D +=0D + //=0D + // Skip Resource Descriptor HOBs that do not describe tested system me= mory=0D + //=0D + ResourceHob =3D Hob.ResourceDescriptor;=0D + if (ResourceHob->ResourceType !=3D EFI_RESOURCE_SYSTEM_MEMORY) {=0D + continue;=0D + }=0D +=0D + if ((ResourceHob->ResourceAttribute & MEMORY_ATTRIBUTE_MASK) !=3D TEST= ED_MEMORY_ATTRIBUTES) {=0D + continue;=0D + }=0D +=0D + //=0D + // Skip if the Resource Descriptor HOB equals to ExceptResourceHob=0D + //=0D + if (ResourceHob =3D=3D ExceptResourceHob) {=0D + continue;=0D + }=0D +=0D + //=0D + // Skip Resource Descriptor HOBs that are beyond 4G=0D + //=0D + if ((ResourceHob->PhysicalStart + ResourceHob->ResourceLength) > BASE_= 4GB) {=0D + continue;=0D + }=0D +=0D + //=0D + // Skip Resource Descriptor HOBs that are too small=0D + //=0D + if (ResourceHob->ResourceLength < MinimalNeededSize) {=0D + continue;=0D + }=0D +=0D + //=0D + // Return the topest Resource Descriptor=0D + //=0D + if (ReturnResourceHob =3D=3D NULL) {=0D + ReturnResourceHob =3D ResourceHob;=0D + } else {=0D + if (ReturnResourceHob->PhysicalStart < ResourceHob->PhysicalStart) {= =0D + ReturnResourceHob =3D ResourceHob;=0D + }=0D + }=0D + }=0D +=0D + return ReturnResourceHob;=0D +}=0D +=0D +/**=0D + Check the HOB and decide if it is need inside Payload=0D + Payload maintainer may make decision which HOB is need or needn't=0D + Then add the check logic in the function.=0D + @param[in] Hob The HOB to check=0D + @retval TRUE If HOB is need inside Payload=0D + @retval FALSE If HOB is needn't inside Payload=0D +**/=0D +BOOLEAN=0D +IsHobNeed (=0D + EFI_PEI_HOB_POINTERS Hob=0D + )=0D +{=0D + if (Hob.Header->HobType =3D=3D EFI_HOB_TYPE_HANDOFF) {=0D + return FALSE;=0D + }=0D +=0D + if (Hob.Header->HobType =3D=3D EFI_HOB_TYPE_MEMORY_ALLOCATION) {=0D + if (CompareGuid (&Hob.MemoryAllocationModule->MemoryAllocationHeader.N= ame, &gEfiHobMemoryAllocModuleGuid)) {=0D + return FALSE;=0D + }=0D + }=0D +=0D + // Arrive here mean the HOB is need=0D + return TRUE;=0D +}=0D +=0D +/**=0D + It will build Fv HOBs based on information from bootloaders.=0D + @param[out] DxeFv The pointer to the DXE FV in memory.=0D + @retval EFI_SUCCESS If it completed successfully.=0D + @retval EFI_NOT_FOUND If it failed to find node in fit image.=0D + @retval Others If it failed to build required HOBs.=0D +**/=0D +EFI_STATUS=0D +BuildFitLoadablesFvHob (=0D + OUT EFI_FIRMWARE_VOLUME_HEADER **DxeFv=0D + )=0D +{=0D + EFI_STATUS Status;=0D + VOID *Fdt;=0D + UINT8 *GuidHob;=0D + UNIVERSAL_PAYLOAD_BASE *PayloadBase;=0D + INT32 ConfigNode;=0D + INT32 Config1Node;=0D + INT32 ImageNode;=0D + INT32 FvNode;=0D + INT32 Depth;=0D + CONST FDT_PROPERTY *PropertyPtr;=0D + INT32 TempLen;=0D + CONST CHAR8 *Fvname;=0D + UINT32 DataOffset;=0D + UINT32 DataSize;=0D + UINT32 *Data32;=0D +=0D + GuidHob =3D GetFirstGuidHob (&gUniversalPayloadBaseGuid);=0D + if (GuidHob !=3D NULL) {=0D + PayloadBase =3D (UNIVERSAL_PAYLOAD_BASE *)GET_GUID_HOB_DATA (GuidHob);= =0D + Fdt =3D (VOID *)(UINTN)PayloadBase->Entry;=0D + DEBUG ((DEBUG_INFO, "PayloadBase Entry =3D 0x%08x\n", PayloadBase->Ent= ry));=0D + }=0D +=0D + Status =3D FdtCheckHeader (Fdt);=0D + if (EFI_ERROR (Status)) {=0D + return EFI_UNSUPPORTED;=0D + }=0D +=0D + ConfigNode =3D FdtSubnodeOffsetNameLen (Fdt, 0, "configurations", (INT32= )AsciiStrLen ("configurations"));=0D + if (ConfigNode <=3D 0) {=0D + return EFI_NOT_FOUND;=0D + }=0D +=0D + Config1Node =3D FdtSubnodeOffsetNameLen (Fdt, ConfigNode, "conf-1", (INT= 32)AsciiStrLen ("conf-1"));=0D + if (Config1Node <=3D 0) {=0D + return EFI_NOT_FOUND;=0D + }=0D +=0D + ImageNode =3D FdtSubnodeOffsetNameLen (Fdt, 0, "images", (INT32)AsciiStr= Len ("images"));=0D + if (ImageNode <=3D 0) {=0D + return EFI_NOT_FOUND;=0D + }=0D +=0D + FvNode =3D FdtSubnodeOffsetNameLen (Fdt, ImageNode, "tianocore", (INT32)= AsciiStrLen ("tianocore"));=0D + Depth =3D FdtNodeDepth (Fdt, FvNode);=0D + FvNode =3D FdtNextNode (Fdt, FvNode, &Depth);=0D + Fvname =3D FdtGetName (Fdt, FvNode, &TempLen);=0D + while ((AsciiStrCmp ((Fvname + AsciiStrLen (Fvname) - 2), "fv") =3D=3D 0= )) {=0D + if (FvNode <=3D 0) {=0D + return EFI_NOT_FOUND;=0D + }=0D +=0D + PropertyPtr =3D FdtGetProperty (Fdt, FvNode, "data-offset", &TempLen);= =0D + Data32 =3D (UINT32 *)(PropertyPtr->Data);=0D + DataOffset =3D SwapBytes32 (*Data32);=0D +=0D + PropertyPtr =3D FdtGetProperty (Fdt, FvNode, "data-size", &TempLen);=0D + Data32 =3D (UINT32 *)(PropertyPtr->Data);=0D + DataSize =3D SwapBytes32 (*Data32);=0D +=0D + if (AsciiStrCmp (Fvname, "uefi-fv") =3D=3D 0) {=0D + *DxeFv =3D (EFI_FIRMWARE_VOLUME_HEADER *)((UINTN)PayloadBase->Entry = + (UINTN)DataOffset);=0D + ASSERT ((*DxeFv)->FvLength =3D=3D DataSize);=0D + } else {=0D + BuildFvHob (((UINTN)PayloadBase->Entry + (UINTN)DataOffset), DataSiz= e);=0D + }=0D +=0D + DEBUG ((=0D + DEBUG_INFO,=0D + "UPL Multiple fv[%a], Base=3D0x%08x, size=3D0x%08x\n",=0D + Fvname,=0D + ((UINTN)PayloadBase->Entry + (UINTN)DataOffset),=0D + DataSize,=0D + DataOffset=0D + ));=0D + Depth =3D FdtNodeDepth (Fdt, FvNode);=0D + FvNode =3D FdtNextNode (Fdt, FvNode, &Depth);=0D + Fvname =3D FdtGetName (Fdt, FvNode, &TempLen);=0D + }=0D +=0D + return EFI_SUCCESS;=0D +}=0D +=0D +/**=0D + It will build HOBs based on information from bootloaders.=0D + @param[in] BootloaderParameter The starting memory address of bootloa= der parameter block.=0D + @param[out] DxeFv The pointer to the DXE FV in memory.=0D + @retval EFI_SUCCESS If it completed successfully.=0D + @retval Others If it failed to build required HOBs.=0D +**/=0D +EFI_STATUS=0D +BuildHobs (=0D + IN UINTN BootloaderParameter,=0D + OUT EFI_FIRMWARE_VOLUME_HEADER **DxeFv=0D + )=0D +{=0D + EFI_PEI_HOB_POINTERS Hob;=0D + UINTN MinimalNeededSize;=0D + EFI_PHYSICAL_ADDRESS FreeMemoryBottom;=0D + EFI_PHYSICAL_ADDRESS FreeMemoryTop;=0D + EFI_PHYSICAL_ADDRESS MemoryBottom;=0D + EFI_PHYSICAL_ADDRESS MemoryTop;=0D + EFI_HOB_RESOURCE_DESCRIPTOR *PhitResourceHob;=0D + EFI_HOB_RESOURCE_DESCRIPTOR *ResourceHob;=0D + UINT8 *GuidHob;=0D + EFI_HOB_FIRMWARE_VOLUME *FvHob;=0D + UNIVERSAL_PAYLOAD_ACPI_TABLE *AcpiTable;=0D + ACPI_BOARD_INFO *AcpiBoardInfo;=0D + EFI_HOB_HANDOFF_INFO_TABLE *HobInfo;=0D +=0D + Hob.Raw =3D (UINT8 *)BootloaderParameter;=0D + MinimalNeededSize =3D FixedPcdGet32 (PcdSystemMemoryUefiRegionSize);=0D +=0D + ASSERT (Hob.Raw !=3D NULL);=0D + ASSERT ((UINTN)Hob.HandoffInformationTable->EfiFreeMemoryTop =3D=3D Hob.= HandoffInformationTable->EfiFreeMemoryTop);=0D + ASSERT ((UINTN)Hob.HandoffInformationTable->EfiMemoryTop =3D=3D Hob.Hand= offInformationTable->EfiMemoryTop);=0D + ASSERT ((UINTN)Hob.HandoffInformationTable->EfiFreeMemoryBottom =3D=3D H= ob.HandoffInformationTable->EfiFreeMemoryBottom);=0D + ASSERT ((UINTN)Hob.HandoffInformationTable->EfiMemoryBottom =3D=3D Hob.H= andoffInformationTable->EfiMemoryBottom);=0D +=0D + //=0D + // Try to find Resource Descriptor HOB that contains Hob range EfiMemory= Bottom..EfiMemoryTop=0D + //=0D + PhitResourceHob =3D FindResourceDescriptorByRange (Hob.Raw, Hob.HandoffI= nformationTable->EfiMemoryBottom, Hob.HandoffInformationTable->EfiMemoryTop= );=0D + if (PhitResourceHob =3D=3D NULL) {=0D + //=0D + // Boot loader's Phit Hob is not in an available Resource Descriptor, = find another Resource Descriptor for new Phit Hob=0D + //=0D + ResourceHob =3D FindAnotherHighestBelow4GResourceDescriptor (Hob.Raw, = MinimalNeededSize, NULL);=0D + if (ResourceHob =3D=3D NULL) {=0D + return EFI_NOT_FOUND;=0D + }=0D +=0D + MemoryBottom =3D ResourceHob->PhysicalStart + ResourceHob->Resourc= eLength - MinimalNeededSize;=0D + FreeMemoryBottom =3D MemoryBottom;=0D + FreeMemoryTop =3D ResourceHob->PhysicalStart + ResourceHob->Resourc= eLength;=0D + MemoryTop =3D FreeMemoryTop;=0D + } else if (PhitResourceHob->PhysicalStart + PhitResourceHob->ResourceLen= gth - Hob.HandoffInformationTable->EfiMemoryTop >=3D MinimalNeededSize) {=0D + //=0D + // New availiable Memory range in new hob is right above memory top in= old hob.=0D + //=0D + MemoryBottom =3D Hob.HandoffInformationTable->EfiFreeMemoryTop;=0D + FreeMemoryBottom =3D Hob.HandoffInformationTable->EfiMemoryTop;=0D + FreeMemoryTop =3D FreeMemoryBottom + MinimalNeededSize;=0D + MemoryTop =3D FreeMemoryTop;=0D + } else if (Hob.HandoffInformationTable->EfiMemoryBottom - PhitResourceHo= b->PhysicalStart >=3D MinimalNeededSize) {=0D + //=0D + // New availiable Memory range in new hob is right below memory bottom= in old hob.=0D + //=0D + MemoryBottom =3D Hob.HandoffInformationTable->EfiMemoryBottom - Mi= nimalNeededSize;=0D + FreeMemoryBottom =3D MemoryBottom;=0D + FreeMemoryTop =3D Hob.HandoffInformationTable->EfiMemoryBottom;=0D + MemoryTop =3D Hob.HandoffInformationTable->EfiMemoryTop;=0D + } else {=0D + //=0D + // In the Resource Descriptor HOB contains boot loader Hob, there is n= o enough free memory size for payload hob=0D + // Find another Resource Descriptor Hob=0D + //=0D + ResourceHob =3D FindAnotherHighestBelow4GResourceDescriptor (Hob.Raw, = MinimalNeededSize, PhitResourceHob);=0D + if (ResourceHob =3D=3D NULL) {=0D + return EFI_NOT_FOUND;=0D + }=0D +=0D + MemoryBottom =3D ResourceHob->PhysicalStart + ResourceHob->Resourc= eLength - MinimalNeededSize;=0D + FreeMemoryBottom =3D MemoryBottom;=0D + FreeMemoryTop =3D ResourceHob->PhysicalStart + ResourceHob->Resourc= eLength;=0D + MemoryTop =3D FreeMemoryTop;=0D + }=0D +=0D + HobInfo =3D HobConstructor ((VOID *)(UINTN)MemoryBottom, (VOID= *)(UINTN)MemoryTop, (VOID *)(UINTN)FreeMemoryBottom, (VOID *)(UINTN)FreeMe= moryTop);=0D + HobInfo->BootMode =3D Hob.HandoffInformationTable->BootMode;=0D + //=0D + // From now on, mHobList will point to the new Hob range.=0D + //=0D +=0D + //=0D + // Create an empty FvHob for the DXE FV that contains DXE core.=0D + //=0D + BuildFvHob ((EFI_PHYSICAL_ADDRESS)0, 0);=0D + //=0D + // Since payload created new Hob, move all hobs except PHIT from boot lo= ader hob list.=0D + //=0D + while (!END_OF_HOB_LIST (Hob)) {=0D + if (IsHobNeed (Hob)) {=0D + // Add this hob to payload HOB=0D + AddNewHob (&Hob);=0D + }=0D +=0D + Hob.Raw =3D GET_NEXT_HOB (Hob);=0D + }=0D +=0D + BuildFitLoadablesFvHob (DxeFv);=0D +=0D + //=0D + // Create guid hob for acpi board information=0D + //=0D + GuidHob =3D GetFirstGuidHob (&gUniversalPayloadAcpiTableGuid);=0D + if (GuidHob !=3D NULL) {=0D + AcpiTable =3D (UNIVERSAL_PAYLOAD_ACPI_TABLE *)GET_GUID_HOB_DATA (GuidH= ob);=0D + GuidHob =3D GetFirstGuidHob (&gUefiAcpiBoardInfoGuid);=0D + if (GuidHob =3D=3D NULL) {=0D + AcpiBoardInfo =3D BuildHobFromAcpi ((UINT64)AcpiTable->Rsdp);=0D + ASSERT (AcpiBoardInfo !=3D NULL);=0D + }=0D + }=0D +=0D + //=0D + // Update DXE FV information to first fv hob in the hob list, which=0D + // is the empty FvHob created before.=0D + //=0D + FvHob =3D GetFirstHob (EFI_HOB_TYPE_FV);=0D + FvHob->BaseAddress =3D (EFI_PHYSICAL_ADDRESS)(UINTN)*DxeFv;=0D + FvHob->Length =3D (*DxeFv)->FvLength;=0D + return EFI_SUCCESS;=0D +}=0D +=0D +/**=0D + Entry point to the C language phase of UEFI payload.=0D + @param[in] BootloaderParameter The starting address of bootloader p= arameter block.=0D + @retval It will not return if SUCCESS, and return error when passin= g bootloader parameter.=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +_ModuleEntryPoint (=0D + IN UINTN BootloaderParameter=0D + )=0D +{=0D + EFI_STATUS Status;=0D + PHYSICAL_ADDRESS DxeCoreEntryPoint;=0D + EFI_PEI_HOB_POINTERS Hob;=0D + EFI_FIRMWARE_VOLUME_HEADER *DxeFv;=0D +=0D + mHobList =3D (VOID *)BootloaderParameter;=0D + DxeFv =3D NULL;=0D + // Call constructor for all libraries=0D + ProcessLibraryConstructorList ();=0D +=0D + DEBUG ((DEBUG_INFO, "Entering Universal Payload...\n"));=0D + DEBUG ((DEBUG_INFO, "sizeof(UINTN) =3D 0x%x\n", sizeof (UINTN)));=0D +=0D + DEBUG_CODE (=0D + //=0D + // Dump the Hobs from boot loader=0D + //=0D + PrintHob (mHobList);=0D + );=0D +=0D + // Initialize floating point operating environment to be compliant with = UEFI spec.=0D + InitializeFloatingPointUnits ();=0D +=0D + // Build HOB based on information from Bootloader=0D + Status =3D BuildHobs (BootloaderParameter, &DxeFv);=0D + ASSERT_EFI_ERROR (Status);=0D +=0D + FixUpPcdDatabase (DxeFv);=0D + Status =3D UniversalLoadDxeCore (DxeFv, &DxeCoreEntryPoint);=0D + ASSERT_EFI_ERROR (Status);=0D +=0D + //=0D + // Mask off all legacy 8259 interrupt sources=0D + //=0D + IoWrite8 (LEGACY_8259_MASK_REGISTER_MASTER, 0xFF);=0D + IoWrite8 (LEGACY_8259_MASK_REGISTER_SLAVE, 0xFF);=0D +=0D + Hob.HandoffInformationTable =3D (EFI_HOB_HANDOFF_INFO_TABLE *)GetFirstHo= b (EFI_HOB_TYPE_HANDOFF);=0D + HandOffToDxeCore (DxeCoreEntryPoint, Hob);=0D +=0D + // Should not get here=0D + CpuDeadLoop ();=0D + return EFI_SUCCESS;=0D +}=0D diff --git a/UefiPayloadPkg/UefiPayloadEntry/FitUniversalPayloadEntry.inf b= /UefiPayloadPkg/UefiPayloadEntry/FitUniversalPayloadEntry.inf new file mode 100644 index 0000000000..01fb3aceb3 --- /dev/null +++ b/UefiPayloadPkg/UefiPayloadEntry/FitUniversalPayloadEntry.inf @@ -0,0 +1,98 @@ +## @file=0D +# This is the first module for UEFI payload.=0D +#=0D +# Copyright (c) 2023, Intel Corporation. All rights reserved.
=0D +#=0D +# SPDX-License-Identifier: BSD-2-Clause-Patent=0D +#=0D +##=0D +=0D +[Defines]=0D + INF_VERSION =3D 0x00010005=0D + BASE_NAME =3D FitUniversalPayloadEntry=0D + FILE_GUID =3D CED5A8A9-B6EA-4D5A-8689-577EE88566CF= =0D + MODULE_TYPE =3D SEC=0D + VERSION_STRING =3D 1.0=0D +=0D +#=0D +# The following information is for reference only and not required by the = build tools.=0D +#=0D +# VALID_ARCHITECTURES =3D IA32 X64=0D +#=0D +=0D +[Sources]=0D + FitUniversalPayloadEntry.c=0D + LoadDxeCore.c=0D + MemoryAllocation.c=0D + PrintHob.c=0D + AcpiTable.c=0D +=0D +[Sources.Ia32]=0D + X64/VirtualMemory.h=0D + X64/VirtualMemory.c=0D + Ia32/DxeLoadFunc.c=0D + Ia32/IdtVectorAsm.nasm=0D +=0D +[Sources.X64]=0D + X64/VirtualMemory.h=0D + X64/VirtualMemory.c=0D + X64/DxeLoadFunc.c=0D +=0D +[Packages]=0D + MdePkg/MdePkg.dec=0D + MdeModulePkg/MdeModulePkg.dec=0D + UefiCpuPkg/UefiCpuPkg.dec=0D + UefiPayloadPkg/UefiPayloadPkg.dec=0D +=0D +[LibraryClasses]=0D + BaseMemoryLib=0D + DebugLib=0D + BaseLib=0D + SerialPortLib=0D + IoLib=0D + HobLib=0D + PeCoffLib=0D + CpuLib=0D + FdtLib=0D +=0D +[Guids]=0D + gEfiMemoryTypeInformationGuid=0D + gEfiFirmwareFileSystem2Guid=0D + gEfiGraphicsInfoHobGuid=0D + gEfiGraphicsDeviceInfoHobGuid=0D + gUefiAcpiBoardInfoGuid=0D + gEfiSmbiosTableGuid=0D + gUefiSerialPortInfoGuid=0D + gUniversalPayloadExtraDataGuid=0D + gUniversalPayloadBaseGuid=0D + gPcdDataBaseHobGuid=0D + gUniversalPayloadSmbiosTableGuid=0D + gEfiHobMemoryAllocBspStoreGuid=0D + gUniversalPayloadAcpiTableGuid=0D + gUniversalPayloadPciRootBridgeInfoGuid=0D + gUniversalPayloadSmbios3TableGuid=0D +=0D +[FeaturePcd.IA32]=0D + gEfiMdeModulePkgTokenSpaceGuid.PcdDxeIplSwitchToLongMode ## CONSUME= S=0D +=0D +[FeaturePcd.X64]=0D + gEfiMdeModulePkgTokenSpaceGuid.PcdDxeIplBuildPageTables ## CONSUME= S=0D +=0D +=0D +[Pcd.IA32,Pcd.X64]=0D + gUefiPayloadPkgTokenSpaceGuid.PcdPcdDriverFile=0D + gEfiMdeModulePkgTokenSpaceGuid.PcdUse1GPageTable ##= SOMETIMES_CONSUMES=0D + gEfiMdeModulePkgTokenSpaceGuid.PcdPteMemoryEncryptionAddressOrMask ##= CONSUMES=0D + gEfiMdeModulePkgTokenSpaceGuid.PcdNullPointerDetectionPropertyMask ##= CONSUMES=0D + gEfiMdeModulePkgTokenSpaceGuid.PcdHeapGuardPropertyMask ##= CONSUMES=0D + gEfiMdeModulePkgTokenSpaceGuid.PcdCpuStackGuard ##= CONSUMES=0D + gEfiMdeModulePkgTokenSpaceGuid.PcdGhcbBase ##= CONSUMES=0D + gEfiMdeModulePkgTokenSpaceGuid.PcdGhcbSize ##= CONSUMES=0D +=0D + gUefiPayloadPkgTokenSpaceGuid.PcdPayloadFdMemBase=0D + gUefiPayloadPkgTokenSpaceGuid.PcdPayloadFdMemSize=0D + gUefiPayloadPkgTokenSpaceGuid.PcdSystemMemoryUefiRegionSize=0D +=0D + gEfiMdeModulePkgTokenSpaceGuid.PcdSetNxForStack ## SOMETIM= ES_CONSUMES=0D + gEfiMdeModulePkgTokenSpaceGuid.PcdDxeNxMemoryProtectionPolicy ## SOMETIM= ES_CONSUMES=0D + gEfiMdeModulePkgTokenSpaceGuid.PcdImageProtectionPolicy ## SOMETIM= ES_CONSUMES=0D diff --git a/UefiPayloadPkg/UefiPayloadPkg.dec b/UefiPayloadPkg/UefiPayload= Pkg.dec index e2e4a79db3..2f1fd82487 100644 --- a/UefiPayloadPkg/UefiPayloadPkg.dec +++ b/UefiPayloadPkg/UefiPayloadPkg.dec @@ -24,6 +24,9 @@ #=0D gUefiPayloadPkgTokenSpaceGuid =3D {0x1d127ea, 0xf6f1, 0x4ef6, {0x94, 0x= 15, 0x8a, 0x0, 0x0, 0x93, 0xf8, 0x9d}}=0D =0D + ## Include/Guid/UniversalPayloadBase.h=0D + gUniversalPayloadBaseGuid =3D { 0x03d4c61d, 0x2713, 0x4ec5, {0xa1, 0xcc,= 0x88, 0x3b, 0xe9, 0xdc, 0x18, 0xe5 } }=0D +=0D #=0D # Gop Temp=0D #=0D diff --git a/UefiPayloadPkg/UefiPayloadPkg.dsc b/UefiPayloadPkg/UefiPayload= Pkg.dsc index 47812048dd..af9308ef8e 100644 --- a/UefiPayloadPkg/UefiPayloadPkg.dsc +++ b/UefiPayloadPkg/UefiPayloadPkg.dsc @@ -30,7 +30,6 @@ DEFINE PS2_KEYBOARD_ENABLE =3D FALSE=0D DEFINE RAM_DISK_ENABLE =3D FALSE=0D DEFINE SIO_BUS_ENABLE =3D FALSE=0D - DEFINE UNIVERSAL_PAYLOAD =3D FALSE=0D DEFINE SECURITY_STUB_ENABLE =3D TRUE=0D DEFINE SMM_SUPPORT =3D FALSE=0D DEFINE PLATFORM_BOOT_TIMEOUT =3D 3=0D @@ -44,6 +43,14 @@ DEFINE BOOTSPLASH_IMAGE =3D FALSE=0D DEFINE NVME_ENABLE =3D TRUE=0D DEFINE CAPSULE_SUPPORT =3D FALSE=0D + #=0D + # Setup Universal Payload=0D + #=0D + # ELF: Build UniversalPayload file as UniversalPayload.elf=0D + # FIT: Build UniversalPayload file as UniversalPayload.fit=0D + #=0D + DEFINE UNIVERSAL_PAYLOAD =3D FALSE=0D + DEFINE UNIVERSAL_PAYLOAD_FORMAT =3D ELF=0D =0D #=0D # NULL: NullMemoryTestDxe=0D @@ -311,7 +318,7 @@ VariableFlashInfoLib|MdeModulePkg/Library/BaseVariableFlashInfoLib/BaseV= ariableFlashInfoLib.inf=0D CcExitLib|UefiCpuPkg/Library/CcExitLibNull/CcExitLibNull.inf=0D ReportStatusCodeLib|MdeModulePkg/Library/DxeReportStatusCodeLib/DxeRepor= tStatusCodeLib.inf=0D -=0D + FdtLib|MdePkg/Library/BaseFdtLib/BaseFdtLib.inf=0D [LibraryClasses.common]=0D !if $(BOOTSPLASH_IMAGE)=0D SafeIntLib|MdePkg/Library/BaseSafeIntLib/BaseSafeIntLib.inf=0D @@ -600,14 +607,26 @@ !if "IA32" in "$(ARCH)"=0D [Components.IA32]=0D !if $(UNIVERSAL_PAYLOAD) =3D=3D TRUE=0D - UefiPayloadPkg/UefiPayloadEntry/UniversalPayloadEntry.inf=0D + !if $(UNIVERSAL_PAYLOAD_FORMAT) =3D=3D "ELF"=0D + UefiPayloadPkg/UefiPayloadEntry/UniversalPayloadEntry.inf=0D + !elseif $(UNIVERSAL_PAYLOAD_FORMAT) =3D=3D "FIT"=0D + UefiPayloadPkg/UefiPayloadEntry/FitUniversalPayloadEntry.inf=0D + !else=0D + UefiPayloadPkg/UefiPayloadEntry/UefiPayloadEntry.inf=0D + !endif=0D !else=0D UefiPayloadPkg/UefiPayloadEntry/UefiPayloadEntry.inf=0D !endif=0D !else=0D [Components.X64]=0D !if $(UNIVERSAL_PAYLOAD) =3D=3D TRUE=0D - UefiPayloadPkg/UefiPayloadEntry/UniversalPayloadEntry.inf=0D + !if $(UNIVERSAL_PAYLOAD_FORMAT) =3D=3D "ELF"=0D + UefiPayloadPkg/UefiPayloadEntry/UniversalPayloadEntry.inf=0D + !elseif $(UNIVERSAL_PAYLOAD_FORMAT) =3D=3D "FIT"=0D + UefiPayloadPkg/UefiPayloadEntry/FitUniversalPayloadEntry.inf=0D + !else=0D + UefiPayloadPkg/UefiPayloadEntry/UefiPayloadEntry.inf=0D + !endif=0D !else=0D UefiPayloadPkg/UefiPayloadEntry/UefiPayloadEntry.inf=0D !endif=0D diff --git a/UefiPayloadPkg/UniversalPayloadBuild.py b/UefiPayloadPkg/Unive= rsalPayloadBuild.py index 47f37b3377..9a83fc9e44 100644 --- a/UefiPayloadPkg/UniversalPayloadBuild.py +++ b/UefiPayloadPkg/UniversalPayloadBuild.py @@ -10,10 +10,22 @@ import subprocess import os=0D import shutil=0D import sys=0D +import pathlib=0D from ctypes import *=0D -from Tools.ElfFv import ReplaceFv=0D +=0D sys.dont_write_bytecode =3D True=0D =0D +class bcolors:=0D + HEADER =3D '\033[95m'=0D + OKBLUE =3D '\033[94m'=0D + OKCYAN =3D '\033[96m'=0D + OKGREEN =3D '\033[92m'=0D + WARNING =3D '\033[93m'=0D + FAIL =3D '\033[91m'=0D + ENDC =3D '\033[0m'=0D + BOLD =3D '\033[1m'=0D + UNDERLINE =3D '\033[4m'=0D +=0D class UPLD_INFO_HEADER(LittleEndianStructure):=0D _pack_ =3D 1=0D _fields_ =3D [=0D @@ -36,40 +48,114 @@ class UPLD_INFO_HEADER(LittleEndianStructure): self.ImageId =3D b'UEFI'=0D self.ProducerId =3D b'INTEL'=0D =0D -def BuildUniversalPayload(Args):=0D - def RunCommand(cmd):=0D - print(cmd)=0D - p =3D subprocess.Popen(cmd, shell=3DTrue, stdout=3Dsubprocess.PIPE= , stderr=3Dsubprocess.STDOUT,cwd=3Dos.environ['WORKSPACE'])=0D - while True:=0D - line =3D p.stdout.readline()=0D - if not line:=0D - break=0D - print(line.strip().decode(errors=3D'ignore'))=0D -=0D - p.communicate()=0D - if p.returncode !=3D 0:=0D - print("- Failed - error happened when run command: %s"%cmd)=0D - raise Exception("ERROR: when run command: %s"%cmd)=0D +def ValidateSpecRevision (Argument):=0D + try:=0D + (MajorStr, MinorStr) =3D Argument.split('.')=0D + except:=0D + raise argparse.ArgumentTypeError ('{} is not a valid SpecRevision = format (Major[8-bits].Minor[8-bits]).'.format (Argument))=0D + #=0D + # Spec Revision Bits 15 : 8 - Major Version. Bits 7 : 0 - Minor Versio= n.=0D + #=0D + if len(MinorStr) > 0 and len(MinorStr) < 3:=0D + try:=0D + Minor =3D int(MinorStr, 16) if len(MinorStr) =3D=3D 2 else (in= t(MinorStr, 16) << 4)=0D + except:=0D + raise argparse.ArgumentTypeError ('{} Minor version of SpecRev= ision is not a valid integer value.'.format (Argument))=0D + else:=0D + raise argparse.ArgumentTypeError ('{} is not a valid SpecRevision = format (Major[8-bits].Minor[8-bits]).'.format (Argument))=0D +=0D + if len(MajorStr) > 0 and len(MajorStr) < 3:=0D + try:=0D + Major =3D int(MajorStr, 16)=0D + except:=0D + raise argparse.ArgumentTypeError ('{} Major version of SpecRev= ision is not a valid integer value.'.format (Argument))=0D + else:=0D + raise argparse.ArgumentTypeError ('{} is not a valid SpecRevision = format (Major[8-bits].Minor[8-bits]).'.format (Argument))=0D +=0D + return int('0x{0:02x}{1:02x}'.format(Major, Minor), 0)=0D +=0D +def Validate32BitInteger (Argument):=0D + try:=0D + Value =3D int (Argument, 0)=0D + except:=0D + raise argparse.ArgumentTypeError ('{} is not a valid integer value= .'.format (Argument))=0D + if Value < 0:=0D + raise argparse.ArgumentTypeError ('{} is a negative value.'.format= (Argument))=0D + if Value > 0xffffffff:=0D + raise argparse.ArgumentTypeError ('{} is larger than 32-bits.'.for= mat (Argument))=0D + return Value=0D =0D +def ValidateAddFv (Argument):=0D + Value =3D Argument.split ("=3D")=0D + if len (Value) !=3D 2:=0D + raise argparse.ArgumentTypeError ('{} is incorrect format with "xx= x_fv=3Dxxx.fv"'.format (Argument))=0D + if Value[0][-3:] !=3D "_fv":=0D + raise argparse.ArgumentTypeError ('{} is incorrect format with "xx= x_fv=3Dxxx.fv"'.format (Argument))=0D + if Value[1][-3:].lower () !=3D ".fv":=0D + raise argparse.ArgumentTypeError ('{} is incorrect format with "xx= x_fv=3Dxxx.fv"'.format (Argument))=0D + if os.path.exists (Value[1]) =3D=3D False:=0D + raise argparse.ArgumentTypeError ('File {} is not found.'.format (= Value[1]))=0D + return Value=0D +=0D +def RunCommand(cmd):=0D + print(cmd)=0D + p =3D subprocess.Popen(cmd, shell=3DTrue, stdout=3Dsubprocess.PIPE, st= derr=3Dsubprocess.STDOUT,cwd=3Dos.environ['WORKSPACE'])=0D + while True:=0D + line =3D p.stdout.readline()=0D + if not line:=0D + break=0D + print(line.strip().decode(errors=3D'ignore'))=0D +=0D + p.communicate()=0D + if p.returncode !=3D 0:=0D + print("- Failed - error happened when run command: %s"%cmd)=0D + raise Exception("ERROR: when run command: %s"%cmd)=0D +=0D +def BuildUniversalPayload(Args):=0D BuildTarget =3D Args.Target=0D ToolChain =3D Args.ToolChain=0D Quiet =3D "--quiet" if Args.Quiet else ""=0D - ElfToolChain =3D 'CLANGDWARF'=0D - BuildDir =3D os.path.join(os.environ['WORKSPACE'], os.path.normpat= h("Build/UefiPayloadPkgX64"))=0D - BuildModule =3D ""=0D - BuildArch =3D ""=0D =0D + if Args.Fit =3D=3D True:=0D + PayloadEntryToolChain =3D ToolChain=0D + Args.Macro.append("UNIVERSAL_PAYLOAD_FORMAT=3DFIT")=0D + UpldEntryFile =3D "FitUniversalPayloadEntry"=0D + else:=0D + PayloadEntryToolChain =3D 'CLANGDWARF'=0D + Args.Macro.append("UNIVERSAL_PAYLOAD_FORMAT=3DELF")=0D + UpldEntryFile =3D "UniversalPayloadEntry"=0D +=0D + BuildDir =3D os.path.join(os.environ['WORKSPACE'], os.path.normpat= h("Build/UefiPayloadPkgX64"))=0D if Args.Arch =3D=3D 'X64':=0D BuildArch =3D "X64"=0D - EntryOutputDir =3D os.path.join(BuildDir, "{}_{}".format (BuildTar= get, ElfToolChain), os.path.normpath("X64/UefiPayloadPkg/UefiPayloadEntry/U= niversalPayloadEntry/DEBUG/UniversalPayloadEntry.dll"))=0D + FitArch =3D "x86_64"=0D + ObjCopyFlag =3D "elf64-x86-64"=0D + EntryOutputDir =3D os.path.join(BuildDir, "{}_{}".format (BuildTar= get, PayloadEntryToolChain), os.path.normpath("X64/UefiPayloadPkg/UefiPaylo= adEntry/{}/DEBUG/{}.dll".format (UpldEntryFile, UpldEntryFile)))=0D else:=0D BuildArch =3D "IA32 -a X64"=0D - EntryOutputDir =3D os.path.join(BuildDir, "{}_{}".format (BuildTar= get, ElfToolChain), os.path.normpath("IA32/UefiPayloadPkg/UefiPayloadEntry/= UniversalPayloadEntry/DEBUG/UniversalPayloadEntry.dll"))=0D + FitArch =3D "x86"=0D + ObjCopyFlag =3D "elf32-i386"=0D + EntryOutputDir =3D os.path.join(BuildDir, "{}_{}".format (BuildTar= get, PayloadEntryToolChain), os.path.normpath("IA32/UefiPayloadPkg/UefiPayl= oadEntry/{}/DEBUG/{}.dll".format (UpldEntryFile, UpldEntryFile)))=0D =0D + EntryModuleInf =3D os.path.normpath("UefiPayloadPkg/UefiPayloadEntry/{= }.inf".format (UpldEntryFile))=0D DscPath =3D os.path.normpath("UefiPayloadPkg/UefiPayloadPkg.dsc")=0D + DxeFvOutputDir =3D os.path.join(BuildDir, "{}_{}".format (BuildTarget,= ToolChain), os.path.normpath("FV/DXEFV.Fv"))=0D + BdsFvOutputDir =3D os.path.join(BuildDir, "{}_{}".format (BuildTarget,= ToolChain), os.path.normpath("FV/BDSFV.Fv"))=0D + NetworkFvOutputDir =3D os.path.join(BuildDir, "{}_{}".format (BuildTar= get, ToolChain), os.path.normpath("FV/NETWORKFV.Fv"))=0D + PayloadReportPath =3D os.path.join(BuildDir, "UefiUniversalPayload.txt= ")=0D ModuleReportPath =3D os.path.join(BuildDir, "UefiUniversalPayloadEntry= .txt")=0D UpldInfoFile =3D os.path.join(BuildDir, "UniversalPayloadInfo.bin")=0D =0D + if "CLANG_BIN" in os.environ:=0D + LlvmObjcopyPath =3D os.path.join(os.environ["CLANG_BIN"], "llvm-ob= jcopy")=0D + else:=0D + LlvmObjcopyPath =3D "llvm-objcopy"=0D + try:=0D + RunCommand('"%s" --version'%LlvmObjcopyPath)=0D + except:=0D + print("- Failed - Please check if LLVM is installed or if CLANG_BI= N is set correctly")=0D + sys.exit(1)=0D +=0D Pcds =3D ""=0D if (Args.pcd !=3D None):=0D for PcdItem in Args.pcd:=0D @@ -84,7 +170,6 @@ def BuildUniversalPayload(Args): # Building DXE core and DXE drivers as DXEFV.=0D #=0D if Args.BuildEntryOnly =3D=3D False:=0D - PayloadReportPath =3D os.path.join(BuildDir, "UefiUniversalPayload= .txt")=0D BuildPayload =3D "build -p {} -b {} -a X64 -t {} -y {} {}".format = (DscPath, BuildTarget, ToolChain, PayloadReportPath, Quiet)=0D BuildPayload +=3D Pcds=0D BuildPayload +=3D Defines=0D @@ -93,94 +178,138 @@ def BuildUniversalPayload(Args): # Building Universal Payload entry.=0D #=0D if Args.PreBuildUplBinary is None:=0D - EntryModuleInf =3D os.path.normpath("UefiPayloadPkg/UefiPayloadEnt= ry/UniversalPayloadEntry.inf")=0D - BuildModule =3D "build -p {} -b {} -a {} -m {} -t {} -y {} {}".for= mat (DscPath, BuildTarget, BuildArch, EntryModuleInf, ElfToolChain, ModuleR= eportPath, Quiet)=0D + BuildModule =3D "build -p {} -b {} -a {} -m {} -t {} -y {} {}".for= mat (DscPath, BuildTarget, BuildArch, EntryModuleInf, PayloadEntryToolChain= , ModuleReportPath, Quiet)=0D BuildModule +=3D Pcds=0D BuildModule +=3D Defines=0D RunCommand(BuildModule)=0D =0D if Args.PreBuildUplBinary is not None:=0D - EntryOutputDir =3D os.path.join(BuildDir, "UniversalPayload.elf")= =0D + if Args.Fit =3D=3D False:=0D + EntryOutputDir =3D os.path.join(BuildDir, "UniversalPayload.el= f")=0D + else:=0D + EntryOutputDir =3D os.path.join(BuildDir, "UniversalPayload.fi= t")=0D shutil.copy (os.path.abspath(Args.PreBuildUplBinary), EntryOutputD= ir)=0D =0D #=0D - # Buid Universal Payload Information Section ".upld_info"=0D + # Build Universal Payload Information Section ".upld_info"=0D #=0D - upld_info_hdr =3D UPLD_INFO_HEADER()=0D - upld_info_hdr.SpecRevision =3D Args.SpecRevision=0D - upld_info_hdr.Revision =3D Args.Revision=0D - upld_info_hdr.ProducerId =3D Args.ProducerId.encode()[:16]=0D - upld_info_hdr.ImageId =3D Args.ImageId.encode()[:16]=0D - upld_info_hdr.Attribute |=3D 1 if BuildTarget =3D=3D "DEBUG" else 0= =0D - fp =3D open(UpldInfoFile, 'wb')=0D - fp.write(bytearray(upld_info_hdr))=0D - fp.close()=0D + if Args.Fit =3D=3D False:=0D + upld_info_hdr =3D UPLD_INFO_HEADER()=0D + upld_info_hdr.SpecRevision =3D Args.SpecRevision=0D + upld_info_hdr.Revision =3D Args.Revision=0D + upld_info_hdr.ProducerId =3D Args.ProducerId.encode()[:16]=0D + upld_info_hdr.ImageId =3D Args.ImageId.encode()[:16]=0D + upld_info_hdr.Attribute |=3D 1 if BuildTarget =3D=3D "DEBUG" else = 0=0D + fp =3D open(UpldInfoFile, 'wb')=0D + fp.write(bytearray(upld_info_hdr))=0D + fp.close()=0D +=0D + if Args.BuildEntryOnly =3D=3D False:=0D + import Tools.ElfFv as ElfFv=0D + ElfFv.ReplaceFv (EntryOutputDir, UpldInfoFile, '.upld_info', A= lignment =3D 4)=0D + if Args.Fit =3D=3D False:=0D + shutil.copy (EntryOutputDir, os.path.join(BuildDir, 'UniversalPayl= oad.elf'))=0D + else:=0D + shutil.copy (EntryOutputDir, os.path.join(BuildDir, 'UniversalPayl= oad.fit'))=0D =0D MultiFvList =3D []=0D if Args.BuildEntryOnly =3D=3D False:=0D MultiFvList =3D [=0D - ['uefi_fv', os.path.join(BuildDir, "{}_{}".format (BuildTar= get, ToolChain), os.path.normpath("FV/DXEFV.Fv")) ],=0D - ['bds_fv', os.path.join(BuildDir, "{}_{}".format (BuildTar= get, ToolChain), os.path.normpath("FV/BDSFV.Fv")) ],=0D - ['network_fv', os.path.join(BuildDir, "{}_{}".format (BuildTar= get, ToolChain), os.path.normpath("FV/NETWORKFV.Fv")) ],=0D + ['uefi_fv', os.path.join(BuildDir, "{}_{}".format (Buil= dTarget, ToolChain), os.path.normpath("FV/DXEFV.Fv")) ],=0D + ['bds_fv', os.path.join(BuildDir, "{}_{}".format (Buil= dTarget, ToolChain), os.path.normpath("FV/BDSFV.Fv")) ],=0D + ['network_fv', os.path.join(BuildDir, "{}_{}".format (Buil= dTarget, ToolChain), os.path.normpath("FV/NETWORKFV.Fv"))],=0D ]=0D - AddSectionName =3D '.upld_info'=0D - ReplaceFv (EntryOutputDir, UpldInfoFile, AddSectionName, Alignment= =3D 4)=0D =0D - if Args.PreBuildUplBinary is None:=0D - shutil.copy (EntryOutputDir, os.path.join(BuildDir, 'UniversalPayl= oad.elf'))=0D =0D - return MultiFvList, os.path.join(BuildDir, 'UniversalPayload.elf')=0D + if Args.Fit =3D=3D True:=0D + import Tools.MkFitImage as MkFitImage=0D + import pefile=0D + fit_image_info_header =3D MkFitImage.FIT_IMAGE_INFO_= HEADER()=0D + fit_image_info_header.Description =3D 'Uefi Universal Payload'=0D + fit_image_info_header.UplVersion =3D Args.SpecRevision=0D + fit_image_info_header.Type =3D 'flat-binary'=0D + fit_image_info_header.Arch =3D FitArch=0D + fit_image_info_header.Compression =3D 'none'=0D + fit_image_info_header.Revision =3D Args.Revision=0D + fit_image_info_header.BuildType =3D Args.Target.lower()=0D + fit_image_info_header.Capabilities =3D None=0D + fit_image_info_header.Producer =3D Args.ProducerId.lower()=0D + fit_image_info_header.ImageId =3D Args.ImageId.lower()=0D + fit_image_info_header.Binary =3D os.path.join(BuildDir, 'Un= iversalPayload.fit')=0D + fit_image_info_header.TargetPath =3D os.path.join(BuildDir, 'Un= iversalPayload.fit')=0D + fit_image_info_header.UefifvPath =3D DxeFvOutputDir=0D + fit_image_info_header.BdsfvPath =3D BdsFvOutputDir=0D + fit_image_info_header.NetworkfvPath =3D NetworkFvOutputDir=0D + fit_image_info_header.DataOffset =3D 0x1000=0D + fit_image_info_header.LoadAddr =3D Args.LoadAddress=0D + fit_image_info_header.Project =3D 'tianocore'=0D +=0D + TargetRebaseFile =3D fit_image_info_header.Binary.replace (pathlib= .Path(fit_image_info_header.Binary).suffix, ".pecoff")=0D + TargetRebaseEntryFile =3D fit_image_info_header.Binary.replace (pa= thlib.Path(fit_image_info_header.Binary).suffix, ".entry")=0D +=0D =0D -def main():=0D - def ValidateSpecRevision (Argument):=0D - try:=0D - (MajorStr, MinorStr) =3D Argument.split('.')=0D - except:=0D - raise argparse.ArgumentTypeError ('{} is not a valid SpecRevis= ion format (Major[8-bits].Minor[8-bits]).'.format (Argument))=0D #=0D - # Spec Revision Bits 15 : 8 - Major Version. Bits 7 : 0 - Minor Ve= rsion.=0D + # Rebase PECOFF to load address=0D #=0D - if len(MinorStr) > 0 and len(MinorStr) < 3:=0D - try:=0D - Minor =3D int(MinorStr, 16) if len(MinorStr) =3D=3D 2 else= (int(MinorStr, 16) << 4)=0D - except:=0D - raise argparse.ArgumentTypeError ('{} Minor version of Spe= cRevision is not a valid integer value.'.format (Argument))=0D - else:=0D - raise argparse.ArgumentTypeError ('{} is not a valid SpecRevis= ion format (Major[8-bits].Minor[8-bits]).'.format (Argument))=0D + RunCommand (=0D + "GenFw -e SEC -o {} {}".format (=0D + TargetRebaseFile,=0D + fit_image_info_header.Binary=0D + ))=0D + RunCommand (=0D + "GenFw --rebase 0x{:02X} -o {} {} ".format (=0D + fit_image_info_header.LoadAddr + fit_image_info_header.DataO= ffset,=0D + TargetRebaseFile,=0D + TargetRebaseFile,=0D + ))=0D =0D - if len(MajorStr) > 0 and len(MajorStr) < 3:=0D - try:=0D - Major =3D int(MajorStr, 16)=0D - except:=0D - raise argparse.ArgumentTypeError ('{} Major version of Spe= cRevision is not a valid integer value.'.format (Argument))=0D - else:=0D - raise argparse.ArgumentTypeError ('{} is not a valid SpecRevis= ion format (Major[8-bits].Minor[8-bits]).'.format (Argument))=0D + #=0D + # Open PECOFF relocation table binary.=0D + #=0D + RelocBinary =3D b''=0D + PeCoff =3D pefile.PE (TargetRebaseFile)=0D + for reloc in PeCoff.DIRECTORY_ENTRY_BASERELOC:=0D + for entry in reloc.entries:=0D + if (entry.type =3D=3D 0):=0D + continue=0D + Type =3D entry.type=0D + Offset =3D entry.rva + fit_image_info_header.DataOffset=0D + RelocBinary +=3D Type.to_bytes (8, 'little') + Offset.to_b= ytes (8, 'little')=0D + RelocBinary +=3D b'\x00' * (0x1000 - (len(RelocBinary) % 0x1000))= =0D =0D - return int('0x{0:02x}{1:02x}'.format(Major, Minor), 0)=0D + #=0D + # Output UniversalPayload.entry=0D + #=0D + TempBinary =3D open (TargetRebaseFile, 'rb')=0D + TianoBinary =3D TempBinary.read ()=0D + TempBinary.close ()=0D =0D - def Validate32BitInteger (Argument):=0D - try:=0D - Value =3D int (Argument, 0)=0D - except:=0D - raise argparse.ArgumentTypeError ('{} is not a valid integer v= alue.'.format (Argument))=0D - if Value < 0:=0D - raise argparse.ArgumentTypeError ('{} is a negative value.'.fo= rmat (Argument))=0D - if Value > 0xffffffff:=0D - raise argparse.ArgumentTypeError ('{} is larger than 32-bits.'= .format (Argument))=0D - return Value=0D -=0D - def ValidateAddFv (Argument):=0D - Value =3D Argument.split ("=3D")=0D - if len (Value) !=3D 2:=0D - raise argparse.ArgumentTypeError ('{} is incorrect format with= "xxx_fv=3Dxxx.fv"'.format (Argument))=0D - if Value[0][-3:] !=3D "_fv":=0D - raise argparse.ArgumentTypeError ('{} is incorrect format with= "xxx_fv=3Dxxx.fv"'.format (Argument))=0D - if Value[1][-3:].lower () !=3D ".fv":=0D - raise argparse.ArgumentTypeError ('{} is incorrect format with= "xxx_fv=3Dxxx.fv"'.format (Argument))=0D - if os.path.exists (Value[1]) =3D=3D False:=0D - raise argparse.ArgumentTypeError ('File {} is not found.'.form= at (Value[1]))=0D - return Value=0D + TianoEntryBinary =3D TianoBinary + RelocBinary=0D + TianoEntryBinary +=3D (b'\x00' * (0x1000 - (len(TianoBinary) % 0x1= 000)))=0D + TianoEntryBinarySize =3D len (TianoEntryBinary)=0D +=0D + TempBinary =3D open(TargetRebaseEntryFile, "wb")=0D + TempBinary.truncate()=0D + TempBinary.write(TianoEntryBinary)=0D + TempBinary.close()=0D +=0D + #=0D + # Calculate entry and update relocation table start address and da= ta-size.=0D + #=0D + fit_image_info_header.Entry =3D PeCoff.OPTIONAL_HEADER.ImageB= ase + PeCoff.OPTIONAL_HEADER.AddressOfEntryPoint=0D + fit_image_info_header.RelocStart =3D fit_image_info_header.DataOff= set + len(TianoBinary)=0D + fit_image_info_header.DataSize =3D TianoEntryBinarySize=0D + fit_image_info_header.Binary =3D TargetRebaseEntryFile=0D +=0D + if MkFitImage.MakeFitImage(fit_image_info_header) is True:=0D + print('\nSuccessfully build Fit Image')=0D + else:=0D + sys.exit(1)=0D + return MultiFvList, os.path.join(BuildDir, 'UniversalPayload.fit')= =0D + else:=0D + return MultiFvList, os.path.join(BuildDir, 'UniversalPayload.elf')= =0D =0D +def main():=0D parser =3D argparse.ArgumentParser(description=3D'For building Univers= al Payload')=0D parser.add_argument('-t', '--ToolChain')=0D parser.add_argument('-b', '--Target', default=3D'DEBUG')=0D @@ -192,13 +321,16 @@ def main(): parser.add_argument("-s", "--SpecRevision", type=3DValidateSpecRevisio= n, default =3D'0.7', help=3D'Indicates compliance with a revision of this s= pecification in the BCD format.')=0D parser.add_argument("-r", "--Revision", type=3DValidate32BitInteger, d= efault =3D'0x0000010105', help=3D'Revision of the Payload binary. Major.Min= or.Revision.Build')=0D parser.add_argument("-o", "--ProducerId", default =3D'INTEL', help=3D'= A null-terminated OEM-supplied string that identifies the payload producer = (16 bytes maximal).')=0D + parser.add_argument("-e", "--BuildEntryOnly", action=3D'store_true', h= elp=3D'Build UniversalPayload Entry file')=0D + parser.add_argument("-pb", "--PreBuildUplBinary", default=3DNone, help= =3D'Specify the UniversalPayload file')=0D parser.add_argument("-sk", "--SkipBuild", action=3D'store_true', help= =3D'Skip UniversalPayload build')=0D parser.add_argument("-af", "--AddFv", type=3DValidateAddFv, action=3D'= append', help=3D'Add or replace specific FV into payload, Ex: uefi_fv=3DXXX= .fv')=0D - command_group =3D parser.add_mutually_exclusive_group()=0D - command_group.add_argument("-e", "--BuildEntryOnly", action=3D'store_t= rue', help=3D'Build UniversalPayload Entry file')=0D - command_group.add_argument("-pb", "--PreBuildUplBinary", default=3DNon= e, help=3D'Specify the UniversalPayload file')=0D + parser.add_argument("-f", "--Fit", action=3D'store_true', help=3D'Buil= d UniversalPayload file as UniversalPayload.fit', default=3DFalse)=0D + parser.add_argument('-l', "--LoadAddress", type=3Dint, help=3D'Specify= payload load address', default =3D0x000800000)=0D +=0D args =3D parser.parse_args()=0D =0D +=0D MultiFvList =3D []=0D UniversalPayloadBinary =3D args.PreBuildUplBinary=0D if (args.SkipBuild =3D=3D False):=0D @@ -208,12 +340,24 @@ def main(): for (SectionName, SectionFvFile) in args.AddFv:=0D MultiFvList.append ([SectionName, SectionFvFile])=0D =0D + def ReplaceFv (UplBinary, SectionFvFile, SectionName):=0D + print (bcolors.OKGREEN + "Patch {}=3D{} into {}".format (SectionNa= me, SectionFvFile, UplBinary) + bcolors.ENDC)=0D + if (args.Fit =3D=3D False):=0D + import Tools.ElfFv as ElfFv=0D + return ElfFv.ReplaceFv (UplBinary, SectionFvFile, '.upld.{}'.f= ormat (SectionName))=0D + else:=0D + import Tools.MkFitImage as MkFitImage=0D + return MkFitImage.ReplaceFv (UplBinary, SectionFvFile, Section= Name)=0D +=0D if (UniversalPayloadBinary !=3D None):=0D for (SectionName, SectionFvFile) in MultiFvList:=0D if os.path.exists (SectionFvFile) =3D=3D False:=0D continue=0D - print ("Patch {}=3D{} into {}".format (SectionName, SectionFvF= ile, UniversalPayloadBinary))=0D - ReplaceFv (UniversalPayloadBinary, SectionFvFile, '.upld.{}'.f= ormat (SectionName))=0D +=0D + status =3D ReplaceFv (UniversalPayloadBinary, SectionFvFile, S= ectionName.replace ("_", "-"))=0D + if status !=3D 0:=0D + print (bcolors.FAIL + "[Fail] Patch {}=3D{}".format (Secti= onName, SectionFvFile) + bcolors.ENDC)=0D + return status=0D =0D print ("\nSuccessfully build Universal Payload")=0D =0D --=20 2.39.1.windows.1 -=-=-=-=-=-=-=-=-=-=-=- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#108792): https://edk2.groups.io/g/devel/message/108792 Mute This Topic: https://groups.io/mt/101435620/7686176 Group Owner: devel+owner@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io] -=-=-=-=-=-=-=-=-=-=-=-