From nobody Sat May 11 17:31:25 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of groups.io designates 66.175.222.108 as permitted sender) client-ip=66.175.222.108; envelope-from=bounce+27952+106872+1787277+3901457@groups.io; helo=mail02.groups.io; Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of groups.io designates 66.175.222.108 as permitted sender) smtp.mailfrom=bounce+27952+106872+1787277+3901457@groups.io; dmarc=fail(p=none dis=none) header.from=intel.com ARC-Seal: i=1; a=rsa-sha256; t=1689174967; cv=none; d=zohomail.com; s=zohoarc; b=ai242vxrb+6HveMbVKi1WC01Wpk452+PR8zQn9ZEA4T6UHEzKro18yeQ12jrCkJbDz9bZfMpJZYZMsafD1Csi9CvFhB0qTkZZo9j70zjqs7aiRVpsGBAAU77Eg/UJqXhMvdIH73JLT6/uiPhnsbEfKMlCgz80lKwcZdNRd8oaso= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1689174967; h=Content-Transfer-Encoding:Cc:Date:From:List-Subscribe:List-Id:List-Help:List-Unsubscribe:MIME-Version:Message-ID:Reply-To:Sender:Subject:To; bh=z2bJJkwIAFrZ/cdOoI0ZyYb7vtvIqqOzotM8HnhDYhs=; b=Nu/4Oigh6cllQFdrlQTxkIz7claaHhpE5EHEkArzQ+Gi8kaj1+qrNznMMmglvpR5IwYQqeFHz1WMdatH7JthPPggG3316Qsdqq2P4qvwda11qijbd/r2QGJtJCF8gBTOl9dQBjGfZY6tbYpTR+E8wWFvIoDjKcl/F+pVz2JGePk= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of groups.io designates 66.175.222.108 as permitted sender) smtp.mailfrom=bounce+27952+106872+1787277+3901457@groups.io; dmarc=fail header.from= (p=none dis=none) Received: from mail02.groups.io (mail02.groups.io [66.175.222.108]) by mx.zohomail.com with SMTPS id 1689174967482420.84030132948317; Wed, 12 Jul 2023 08:16:07 -0700 (PDT) Return-Path: DKIM-Signature: a=rsa-sha256; bh=Cmq6R/r8hDM6hVoPoJbSYwre5iXx9rd3g2yWhKuUz4M=; c=relaxed/simple; d=groups.io; h=X-Received:X-Received:X-IronPort-AV:X-IronPort-AV:X-Received:X-ExtLoop1:X-IronPort-AV:X-IronPort-AV:X-Received:From:To:Cc:Subject:Date:Message-Id:MIME-Version:Precedence:List-Unsubscribe:List-Subscribe:List-Help:Sender:List-Id:Mailing-List:Delivered-To:Reply-To:X-Gm-Message-State:Content-Transfer-Encoding; s=20140610; t=1689174966; v=1; b=fErPBqOBSBq42ftfwvJNEP6HPAbwHVPD78qOO2F1rV1CZ5Nna89oC3goFONu1TukfJJVnYh7 heEonLyvO9FYoaalGeS+lzn0xkvrgJwuzxtADeONxa1EG54y0B4u5ebd8XhZK/98r8g58fwNR1x uERM9gUWUmO3iuZVcu0oUKd8= X-Received: by 127.0.0.2 with SMTP id UezmYY1788612xnS3eDYXOb3; Wed, 12 Jul 2023 08:16:06 -0700 X-Received: from mga07.intel.com (mga07.intel.com [134.134.136.100]) by mx.groups.io with SMTP id smtpd.web10.2671.1689149742704396421 for ; Wed, 12 Jul 2023 01:15:42 -0700 X-IronPort-AV: E=McAfee;i="6600,9927,10768"; a="430959130" X-IronPort-AV: E=Sophos;i="6.01,199,1684825200"; d="scan'208";a="430959130" X-Received: from fmsmga002.fm.intel.com ([10.253.24.26]) by orsmga105.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 12 Jul 2023 01:15:41 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=McAfee;i="6600,9927,10768"; a="835034228" X-IronPort-AV: E=Sophos;i="6.01,199,1684825200"; d="scan'208";a="835034228" X-Received: from unknown (HELO juichenx-mobl3.gar.corp.intel.com) ([10.227.107.35]) by fmsmga002.fm.intel.com with ESMTP; 12 Jul 2023 01:15:39 -0700 From: brucex.wang@intel.com To: devel@edk2.groups.io Cc: BruceX Wang , Guo Dong , Sean Rhodes , James Lu , Gua Guo Subject: [edk2-devel] [PATCH] UefiPayloadPkg: Add FIT support Date: Wed, 12 Jul 2023 16:15:34 +0800 Message-Id: <645afd507eaa521612a08a057c4cff8c6f66cbd9.1689149666.git.brucex.wang@intel.com> MIME-Version: 1.0 Precedence: Bulk List-Unsubscribe: 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 X-Gm-Message-State: nXBFFXkWWMHVQtgpv6w66Ahsx1787277AA= Content-Transfer-Encoding: quoted-printable X-ZohoMail-DKIM: pass (identity @groups.io) X-ZM-MESSAGEID: 1689174969595100015 Content-Type: text/plain; charset="utf-8" From: BruceX Wang Cc: Guo Dong Cc: Sean Rhodes Cc: James Lu Cc: Gua Guo Signed-off-by: BruceX Wang --- .../UniversalPayload/UniversalPayload.h | 6 +- MdeModulePkg/MdeModulePkg.dec | 3 + MdePkg/Include/Library/FdtLib.h | 17 + MdePkg/Library/BaseFdtLib/FdtLib.c | 21 + UefiPayloadPkg/PayloadLoaderPeim/FitLib.h | 60 ++ .../PayloadLoaderPeim/FitLib/FitLib.c | 127 ++++ .../PayloadLoaderPeim/FitPayloadLoaderPeim.c | 149 ++++ .../FitPayloadLoaderPeim.inf | 59 ++ UefiPayloadPkg/Readme.md | 208 ++++++ UefiPayloadPkg/Tools/MkFitImage.py | 273 ++++++++ .../FitUniversalPayloadEntry.c | 648 ++++++++++++++++++ .../FitUniversalPayloadEntry.inf | 99 +++ UefiPayloadPkg/UefiPayloadPkg.dsc | 26 +- UefiPayloadPkg/UniversalPayloadBuild.py | 320 ++++++--- 14 files changed, 1922 insertions(+), 94 deletions(-) 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/MdeModulePkg/Include/UniversalPayload/UniversalPayload.h b/Mde= ModulePkg/Include/UniversalPayload/UniversalPayload.h index bb40f240f6..ff77b01ef1 100644 --- a/MdeModulePkg/Include/UniversalPayload/UniversalPayload.h +++ b/MdeModulePkg/Include/UniversalPayload/UniversalPayload.h @@ -10,7 +10,7 @@ SPDX-License-Identifier: BSD-2-Clause-Patent =20 #ifndef UNIVERSAL_PAYLOAD_H_ #define UNIVERSAL_PAYLOAD_H_ - +extern GUID gUniversalPayloadBaseGuid; /** Main entry point to Universal Payload. =20 @@ -43,6 +43,10 @@ typedef struct { UINT16 Length; } UNIVERSAL_PAYLOAD_GENERIC_HEADER; =20 +typedef struct { + UNIVERSAL_PAYLOAD_GENERIC_HEADER Header; + EFI_PHYSICAL_ADDRESS Entry; +} UNIVERSAL_PAYLOAD_BASE; #pragma pack() =20 /** diff --git a/MdeModulePkg/MdeModulePkg.dec b/MdeModulePkg/MdeModulePkg.dec index d65dae18aa..7c00b20e8b 100644 --- a/MdeModulePkg/MdeModulePkg.dec +++ b/MdeModulePkg/MdeModulePkg.dec @@ -439,6 +439,9 @@ ## Include/UniversalPayload/SerialPortInfo.h gUniversalPayloadSerialPortInfoGuid =3D { 0xaa7e190d, 0xbe21, 0x4409, { = 0x8e, 0x67, 0xa2, 0xcd, 0xf, 0x61, 0xe1, 0x70 } } =20 + ## Include/UniversalPayload/UniversalPayload.h + gUniversalPayloadBaseGuid =3D { 0x03d4c61d, 0x2713, 0x4ec5, {0xa1, 0xcc,= 0x88, 0x3b, 0xe9, 0xdc, 0x18, 0xe5 } } + ## Include/Guid/TraceHubDebugInfoHob.h gTraceHubDebugInfoHobGuid =3D { 0xf88c9c23, 0x646c, 0x4f6c, { 0x8e, 0x3d= , 0x36, 0xa9, 0x43, 0xc1, 0x08, 0x35 } } =20 diff --git a/MdePkg/Include/Library/FdtLib.h b/MdePkg/Include/Library/FdtLi= b.h index cf5ceba9e9..4252778eda 100644 --- a/MdePkg/Include/Library/FdtLib.h +++ b/MdePkg/Include/Library/FdtLib.h @@ -398,4 +398,21 @@ FdtSetProp ( IN UINT32 Length ); =20 +/** + Returns the name of a given node. + + @param[in] Fdt The pointer to FDT blob. + @param[in] StrOffset structure block offset of the starting node. + @param[in] Length The pointer to an integer variable (will be ov= erwritten) or NULL + + @return The pointer to the node's name. + +**/ +CONST CHAR8 * +EFIAPI +FdtGetName ( + IN VOID *Fdt, + IN INT32 NodeOffset, + IN UINT32 *Length + ); #endif /* FDT_LIB_H_ */ diff --git a/MdePkg/Library/BaseFdtLib/FdtLib.c b/MdePkg/Library/BaseFdtLib= /FdtLib.c index 090b0b3fd4..6ac9a62f59 100644 --- a/MdePkg/Library/BaseFdtLib/FdtLib.c +++ b/MdePkg/Library/BaseFdtLib/FdtLib.c @@ -402,3 +402,24 @@ FdtSetProp ( { return fdt_setprop (Fdt, NodeOffset, Name, Value, (int)Length); } + +/** + Returns the name of a given node. + + @param[in] Fdt The pointer to FDT blob. + @param[in] StrOffset structure block offset of the starting node. + @param[in] Length The pointer to an integer variable (will be ov= erwritten) or NULL + + @return The pointer to the node's name. + +**/ +CONST CHAR8 * +EFIAPI +FdtGetName ( + IN VOID *Fdt, + IN INT32 NodeOffset, + IN UINT32 *Length + ) +{ + return fdt_get_name (Fdt, NodeOffset, Length); +} 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 + FIT Load Image Support +Copyright (c) 2023, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#ifndef FIT_LIB_H_ +#define FIT_LIB_H_ + +#include +#include +#include + +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, ImageB= ase) +#define PAYLOAD_BASE_ADDR_OFFSET OFFSET_OF (FIT_IMAGE_CONTEXT, Payloa= dBaseAddress) +#define PAYLOAD_BASE_SIZE_OFFSET OFFSET_OF (FIT_IMAGE_CONTEXT, Payloa= dSize) +#define PAYLOAD_ENTRY_OFFSET_OFFSET OFFSET_OF (FIT_IMAGE_CONTEXT, Payloa= dEntryOffset) +#define PAYLOAD_ENTRY_SIZE_OFFSET OFFSET_OF (FIT_IMAGE_CONTEXT, Payloa= dEntrySize) +#define PAYLOAD_ENTRY_POINT_OFFSET OFFSET_OF (FIT_IMAGE_CONTEXT, Payloa= dEntryPoint) +#define RELOCATE_TABLE_OFFSET_OFFSET OFFSET_OF (FIT_IMAGE_CONTEXT, Reloca= teTableOffset) +#define RELOCATE_TABLE_COUNT_OFFSET OFFSET_OF (FIT_IMAGE_CONTEXT, Reloca= teTableCount) +#define PAYLOAD_LOAD_ADDR_OFFSET OFFSET_OF (FIT_IMAGE_CONTEXT, Payloa= dLoadAddress) + +/** + 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/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 + FIT Load Image Support +Copyright (c) 2023, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include "FitLib.h" + +PROPERTY_DATA PropertyData32List[] =3D { + { "data-offset", PAYLOAD_ENTRY_OFFSET_OFFSET }, + { "data-size", PAYLOAD_ENTRY_SIZE_OFFSET }, + { "reloc-start", RELOCATE_TABLE_OFFSET_OFFSET } +}; + +PROPERTY_DATA PropertyData64List[] =3D { + { "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 =3D FdtSubnodeOffsetNameLen (Fdt, 0, "images", (INT32)AsciiStr= Len ("images")); + if (ImageNode <=3D 0) { + return EFI_NOT_FOUND; + } + + TianoNode =3D FdtSubnodeOffsetNameLen (Fdt, ImageNode, Firmware, (INT32)= AsciiStrLen (Firmware)); + if (TianoNode <=3D 0) { + return EFI_NOT_FOUND; + } + + for (Index =3D 0; Index < sizeof (PropertyData32List) / sizeof (PROPERTY= _DATA); Index++) { + PropertyPtr =3D FdtGetProperty (Fdt, TianoNode, PropertyData32Lis= t[Index].Name, &TempLen); + Data32 =3D (UINT32 *)(PropertyPtr->Data); + ContextOffset32 =3D (UINT32 *)((UINTN)Context + PropertyData32List[In= dex].Offset); + *ContextOffset32 =3D Fdt32ToCpu (*Data32); + } + + for (Index =3D 0; Index < sizeof (PropertyData64List)/sizeof (PROPERTY_D= ATA); Index++) { + PropertyPtr =3D FdtGetProperty (Fdt, TianoNode, PropertyData64Lis= t[Index].Name, &TempLen); + Data64 =3D (UINT64 *)(PropertyPtr->Data); + ContextOffset64 =3D (UINT64 *)((UINTN)Context + PropertyData64List[In= dex].Offset); + *ContextOffset64 =3D 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 =3D FdtCheckHeader (ImageBase); + if (EFI_ERROR (Status)) { + return EFI_UNSUPPORTED; + } + + Fdt =3D ImageBase; + PropertyPtr =3D FdtGetProperty (Fdt, 0, "size", &TempLen); + Data32 =3D (UINT32 *)(PropertyPtr->Data); + UplSize =3D Value =3D Fdt32ToCpu (*Data32); + ConfigNode =3D FdtSubnodeOffsetNameLen (Fdt, 0, "configurations", (INT3= 2)AsciiStrLen ("configurations")); + if (ConfigNode <=3D 0) { + return EFI_NOT_FOUND; + } + + Config1Node =3D FdtSubnodeOffsetNameLen (Fdt, ConfigNode, "conf-1", (INT= 32)AsciiStrLen ("conf-1")); + if (Config1Node <=3D 0) { + return EFI_NOT_FOUND; + } + + PropertyPtr =3D FdtGetProperty (Fdt, Config1Node, "firmware", &TempLen); + Firmware =3D (CHAR8 *)(PropertyPtr->Data); + + FitParseFirmwarePropertyData (Fdt, Firmware, Context); + + Context->ImageBase =3D (EFI_PHYSICAL_ADDRESS)ImageBase; + Context->PayloadSize =3D UplSize; + Context->RelocateTableCount =3D (Context->PayloadEntrySize - (Context->R= elocateTableOffset - Context->PayloadEntryOffset)) / sizeof (FIT_RELOCATE_I= TEM); + + return EFI_SUCCESS; +} diff --git a/UefiPayloadPkg/PayloadLoaderPeim/FitPayloadLoaderPeim.c b/Uefi= PayloadPkg/PayloadLoaderPeim/FitPayloadLoaderPeim.c new file mode 100644 index 0000000000..faf91d8de5 --- /dev/null +++ b/UefiPayloadPkg/PayloadLoaderPeim/FitPayloadLoaderPeim.c @@ -0,0 +1,149 @@ +/** @file + ELF Load Image Support +Copyright (c) 2021, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +#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 =3D 0; + do { + Status =3D PeiServicesFfsFindSectionData3 (EFI_SECTION_RAW, Instance++= , FileHandle, &Binary, AuthenticationState); + if (EFI_ERROR (Status)) { + return Status; + } + + ZeroMem (&Context, sizeof (Context)); + Status =3D 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, EntryPoin= t: 0x%08x\n", + Context.PayloadBaseAddress, + Context.PayloadSize, + Context.PayloadEntryPoint + )); + Context.PayloadBaseAddress =3D (EFI_PHYSICAL_ADDRESS)AllocatePages (EFI_= SIZE_TO_PAGES (Context.PayloadSize)); + + RelocateTable =3D (FIT_RELOCATE_ITEM *)(UINTN)(Context.PayloadBaseAddres= s + Context.RelocateTableOffset); + CopyMem ((VOID *)Context.PayloadBaseAddress, Binary, Context.PayloadSize= ); + + if (Context.PayloadBaseAddress > Context.PayloadLoadAddress) { + Delta =3D Context.PayloadBaseAddress - Context.Pa= yloadLoadAddress; + Context.PayloadEntryPoint +=3D Delta; + for (Index =3D 0; Index < Context.RelocateTableCount; Index++) { + if ((RelocateTable[Index].RelocateType =3D=3D 10) || (RelocateTable[= Index].RelocateType =3D=3D 3)) { + *((UINT64 *)(Context.PayloadBaseAddress + RelocateTable[Index].Off= set)) =3D *((UINT64 *)(Context.PayloadBaseAddress + RelocateTable[Index].Of= fset)) + Delta; + } + } + } else { + Delta =3D Context.PayloadLoadAddress - Context.Pa= yloadBaseAddress; + Context.PayloadEntryPoint -=3D Delta; + for (Index =3D 0; Index < Context.RelocateTableCount; Index++) { + if ((RelocateTable[Index].RelocateType =3D=3D 10) || (RelocateTable[= Index].RelocateType =3D=3D 3)) { + *((UINT64 *)(Context.PayloadBaseAddress + RelocateTable[Index].Off= set)) =3D *((UINT64 *)(Context.PayloadBaseAddress + RelocateTable[Index].Of= fset)) - 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 =3D sizeof (UNIVERSAL_PAYLOAD_BASE); + PayloadBase =3D BuildGuidHob ( + &gUniversalPayloadBaseGuid, + Length + ); + PayloadBase->Entry =3D (EFI_PHYSICAL_ADDRESS)Context.ImageBase; + + *ImageAddressArg =3D Context.PayloadBaseAddress; + *ImageSizeArg =3D Context.PayloadSize; + *EntryPoint =3D Context.PayloadEntryPoint; + + return EFI_SUCCESS; +} + +EFI_PEI_LOAD_FILE_PPI mPeiLoadFilePpi =3D { + PeiLoadFileLoadPayload +}; + +EFI_PEI_PPI_DESCRIPTOR gPpiLoadFilePpiList =3D { + (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 funct= ion. +**/ +EFI_STATUS +EFIAPI +InitializeFitPayloadLoaderPeim ( + IN EFI_PEI_FILE_HANDLE FileHandle, + IN CONST EFI_PEI_SERVICES **PeiServices + ) +{ + EFI_STATUS Status; + + Status =3D PeiServicesInstallPpi (&gPpiLoadFilePpiList); + + return Status; +} diff --git a/UefiPayloadPkg/PayloadLoaderPeim/FitPayloadLoaderPeim.inf b/Ue= fiPayloadPkg/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.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION =3D 0x00010005 + BASE_NAME =3D FitPayloadLoaderPeim + FILE_GUID =3D 55AC82C8-FC17-4C56-BCDA-990BB0A73E41 + MODULE_TYPE =3D PEIM + VERSION_STRING =3D 1.0 + + ENTRY_POINT =3D InitializeFitPayloadLoaderPeim + +# +# The following information is for reference only and not required by the = build tools. +# +# VALID_ARCHITECTURES =3D 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..21c15dec6d --- /dev/null +++ b/UefiPayloadPkg/Readme.md @@ -0,0 +1,208 @@ +# UefiPayloadPkg +Provide UEFI Universal Payload for different bootloader to generate EFI en= vironment + +# Spec +URL: https://docs.google.com/document/d/1WxEUlCsXpc17DkJhL3XVkOW7e_KIt_zcc= 9tQ1trOySg/ + +# Uefi UniversalPayload Format + | SpecRevision | Binary Format | HandOffPayload - HOB | HandOffPaylo= ad - FDT | + |------------------|---------------|----------------------|-------------= ---------| + | 0.7 | ELF | V (Default) | X = | + | 0.9 | ELF | V (Default) | V = | + | 1.0 | FIT | V | V (Default) = | + +# Binary Format + - SpecRevision - 0.7 + ``` + + +-----------------------+ + | | UniversalPayloadEntry | <----------- UefiPayloadPkg= \UefiPayloadEntry\UniversalPayloadEntry.c:_ModuleEntryPoint (HOB) + | +-----------------------+ + | | .upld_info | patch by llvm-objcopy + ELF Format | +-----------------------+ + | | .upld.uefi_fv | patch by llvm-objcopy + | +-----------------------+ + | | .upld.bds_fv | patch by llvm-objcopy + | +-----------------------+ + | | .upld._fv | patch by llvm-objcopy + + +-----------------------+ + ``` + + - SpecRevision - 0.9 + ``` + + +-----------------------+ + | | UniversalPayloadEntry | <----------- UefiPayloadPkg= \UefiPayloadEntry\UniversalPayloadEntry.c:_ModuleEntryPoint (HOB[Default] o= r FDT) + | +-----------------------+ + | | .upld_info | patch by llvm-objcopy + ELF Format | +-----------------------+ + | | .upld.uefi_fv | patch by llvm-objcopy + | +-----------------------+ + | | .upld.bds_fv | patch by llvm-objcopy + | +-----------------------+ + | | .upld._fv | patch by llvm-objcopy + + +-----------------------+ + ``` + + - SpecRevision - 1.0 + ``` + + +-----------------------+ + FIT Data | | FIT Header | <----------- Generate by py= libfdt + + +-----------------------+ + PECOFF Format | | UniversalPayloadEntry | <----------- UefiPayloadPkg= \UefiPayloadEntry\FitUniversalPayloadEntry.c:_ModuleEntryPoint (HOB or FDT[= Default]) + + +-----------------------+ + 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 + - SpecRevision - 0.7 + ``` + Download and install https://github.com/llvm/llvm-project/releases/tag= /llvmorg-10.0.1 + ``` + - SpecRevision - 0.9 + ``` + Download and install https://github.com/llvm/llvm-project/releases/tag= /llvmorg-10.0.1 + ``` + - SpecRevision - 1.0 + - Windows + ```powershell + 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')) + 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 + + - SpecRevision - 0.7 + - python UefiPayloadPkg/UniversalPayloadBuild.py -t -= s 0.7 + - llvm-objdump -h Build/UefiPayloadPkgX64/UniversalPayload.elf + - SpecRevision - 0.9 + - python UefiPayloadPkg/UniversalPayloadBuild.py -t -= s 0.9 + - llvm-objdump -h Build/UefiPayloadPkgX64/UniversalPayload.elf + - SpecRevision - 1.0 + - python UefiPayloadPkg/UniversalPayloadBuild.py -t -= s 1.0 + - fdtdump Build/UefiPayloadPkgX64/UniversalPayload.fit + +# Edk2boot + UefiUniversalPayload +Currently, Spec 0.7 Edk2boot use below way to support compress and sign. + +- Spec 0.7 Behavior - Edk2boot + UefiUniversalPayload.elf + ``` + Boot Flow + +-----------------------------------------------------------------------= --------------+------------------------------------------------------------= -----------------------------------------------+-------------------+ + | Platform Init = | Universal Loader Interface = | OS | + +-----------------------------------------------------------------------= --------------+------------------------------------------------------------= -----------------------------------------------+-------------------+ + = = HOBs + SEC -> PEI -> DXE -> DXE IPL -> UefiPayloadPkg\PayloadLoaderPeim\Payload= LoaderPeim.c --------------------------------------------------------------= ----------------------> Load UniversalPayload.elf -> Operation System + + + | Platform Initialize - Edk2 = = | UniversalPayload - Edk2 = | + +-----------------------------------------------------------------------= ---------------------------------------------------------------------------= -----------------------------------------------+---------------------------= -----+ + + Binary Format + + +-------------------+ + | BIOS.rom | + +-------------------+ + | Other Firmware | + +-------------------+ + | ... | FMMT = = UniversalPayloadBuild.py -s= 0.7 + +-------------------+<----------------+-----------------------+ 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 | + = = +----------------------+ + ``` + +Expected, Spec 1.0 Edk2boot use below way to support compress and sign +- Spec 1.0 Behavior - Edk2boot + UefiUniversalPayload.fit + ``` + Boot Flow + +-----------------------------------------------------------------------= --------------+------------------------------------------------------------= ------------+-------------------+ + | Platform Init = | Universal Loader Interface = | OS | + +-----------------------------------------------------------------------= --------------+------------------------------------------------------------= ------------+-------------------+ + = HOBs or *FDT[Default] + SEC -> PEI -> DXE -> DXE IPL -> *UefiPayloadPkg\PayloadLoaderPeim\Payloa= dLoaderPeim.c ----------------------------------------------> Load Universa= lPayload.fit -> Operation System + + Binary Format + + | Platform Initialize - Edk2 = | UniversalPayload - Ed= k2 (UniversalPayloadBuild.py -s 1.0) | + +-----------------------------------------------------------------------= ----------------------------------------------------+----------------------= -------------------------------------------------------------------+ + + +-------------------+ + | BIOS.rom | + +-------------------+ + | Other Firmware | + +-------------------+ + | ... | FMMT = UniversalPayloadBuild.= py -s 1.0 tianocore -> data-offset + +-------------------+<----------------+--------------------------------+= GenFfs +--------------------------------+ GenSec +----------------------= ----------+ tianocore -> reloc-start +--------------------------+ + | | | EDK2 FFS Header |= <--------| EDK2 SEC Header |<--------| FIT Header = |<-------------------------| UniversalPayload.pecoff | + | | +--------------------------------+= +--------------------------------+ | compatible=3D"univers= al-payload";| +--------------------------+ + | | | EDK2 SEC Header |= | FIT Header | | upl-version <0x0100>;= | + | 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-st= art | + | | +--------------------------------+= +--------------------------------+ +----------------------= ----------+ + | | | 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/MkFi= tImage.py new file mode 100644 index 0000000000..cbb083bca4 --- /dev/null +++ b/UefiPayloadPkg/Tools/MkFitImage.py @@ -0,0 +1,273 @@ +## @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.
+# 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_ =3D 1 + _fields_ =3D [ + ('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 =3D 'universal-payload' + self.UplVersion =3D 0x0100 + self.TargetPath =3D 'mkimage.fit' + +def CreatFdt(Fdt): + FdtEmptyTree =3D libfdt.fdt_create_empty_tree(Fdt, len(Fdt)) + if FdtEmptyTree !=3D 0: + print('\n- Failed - Create Fdt failed!') + return False + return True + +def BuildConfNode(Fdt, ParentNode, MultiImage): + ConfNode1 =3D libfdt.fdt_add_subnode(Fdt, ParentNode, 'conf-1') + + libfdt.fdt_setprop(Fdt, ConfNode1, 'firmware', bytes('tianocore', 'utf= -8'), len('tianocore') + 1) + +def BuildFvImageNode(Fdt, InfoHeader, ParentNode, DataOffset, DataSize, De= scription): + 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('lzma', = 'utf-8'), len('lzma') + 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 t= arget binary file. + # + if InfoHeader.LoadAddr is not None: + libfdt.fdt_setprop_u64(Fdt, ParentNode, 'load', InfoHeader.LoadAdd= r) + 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 =3D ','.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.P= roject, 'utf-8'), len(InfoHeader.Project) + 1) + if InfoHeader.Description is not None: + libfdt.fdt_setprop(Fdt, ParentNode, 'description', bytes(Descripti= on, 'utf-8'), len(Description) + 1) + +# +# The subnode would be inserted from bottom to top of structure block. +# +def BuildFitImage(Fdt, InfoHeader): + MultiImage =3D [ + ["tianocore", InfoHeader.Binary, BuildTianoImageNode , In= foHeader.Description, None, 0 ], + ["uefi-fv", InfoHeader.UefifvPath, BuildFvImageNode, "U= EFI Firmware Volume", None, 0 ], + ["bds-fv", InfoHeader.BdsfvPath, BuildFvImageNode , "B= DS Firmware Volume", None, 0 ], + ["network-fv", InfoHeader.NetworkfvPath, BuildFvImageNode , "N= etwork 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 =3D libfdt.fdt_add_subnode(Fdt, 0, 'configurations') + BuildConfNode(Fdt, ConfNode, MultiImage) + + # Build image + DataOffset =3D InfoHeader.DataOffset + for Index in range (0, len (MultiImage)): + _, Path, _, _, _, _ =3D MultiImage[Index] + if exists(Path) =3D=3D 1: + TempBinary =3D open(Path, 'rb') + BinaryData =3D TempBinary.read() + TempBinary.close() + MultiImage[Index][-2] =3D BinaryData + MultiImage[Index][-1] =3D DataOffset + DataOffset +=3D len (BinaryData) + libfdt.fdt_setprop_u32(Fdt, 0, 'size', DataOffset) + posix_time =3D int(time.time()) + libfdt.fdt_setprop_u32(Fdt, 0, 'timestamp', posix_time) + DescriptionFit =3D 'Uefi OS Loader' + libfdt.fdt_setprop(Fdt, 0, 'description', bytes(DescriptionFit, 'utf-8= '), len(DescriptionFit) + 1) + + ImageNode =3D libfdt.fdt_add_subnode(Fdt, 0, 'images') + for Item in reversed (MultiImage): + Name, Path, BuildFvNode, Description, BinaryData, DataOffset =3D I= tem + FvNode =3D libfdt.fdt_add_subnode(Fdt, ImageNode, Name) + BuildFvNode (Fdt, InfoHeader, FvNode, DataOffset, len(BinaryData),= Description) + + # + # Create new image file and combine all binary. + # + DtbFile =3D open(InfoHeader.TargetPath, "wb") + DtbFile.truncate() + DtbFile.write(Fdt) + for Item in MultiImage: + _, _, _, _, BinaryData, _ =3D Item + DtbFile.write(BinaryData) + DtbFile.close() + + return True + +def MakeFitImage(InfoHeader): + # + # Allocate fdt byte array. + # + Fdt =3D 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 =3D File.read () + Fit =3D libfdt.Fdt (Dtb) + NewFitHeader =3D bytearray(Dtb[0:Fit.totalsize()]) + FitSize =3D len(Dtb) + + if int.from_bytes (libfdt.fdt_getprop (NewFitHeader, 0, 'spec-vers= ion')[0], 'big') < 0x0100: + raise Exception ("UPL version is too low to support it.") + + LoadablesList =3D [] + ImagesNode =3D libfdt.fdt_subnode_offset(NewFitHeader, 0, 'imag= es') + FvNode =3D libfdt.fdt_subnode_offset(NewFitHeader, ImagesNo= de, 'uefi-fv') + NodeDepth =3D libfdt.fdt_node_depth (NewFitHeader, ImagesNode) + node_name =3D libfdt.fdt_get_name(NewFitHeader, FvNode) + FvNode =3D libfdt.fdt_next_node(NewFitHeader, FvNode, NodeD= epth) + + while node_name[0][-2:] =3D=3D 'fv': + LoadablesList.append (node_name[0]) + node_name =3D libfdt.fdt_get_name(NewFitHeader, FvNode[0]) + FvNode =3D libfdt.fdt_next_node(NewFitHeader, FvNode[0], NodeD= epth) + # + # Get current Fit Binary FV data + # + MultiFvList =3D [] + for Item in LoadablesList: + ImageNode =3D libfdt.fdt_subnode_offset(NewFitHeader, Image= sNode, Item) + ImageOffset =3D int.from_bytes (libfdt.fdt_getprop (NewFitHea= der, ImageNode, 'data-offset')[0], 'big') + ImageSize =3D int.from_bytes (libfdt.fdt_getprop (NewFitHea= der, ImageNode, 'data-size')[0], 'big') + MultiFvList.append ([Item, Dtb[ImageOffset:ImageOffset + Image= Size]]) + + IsFvExist =3D False + for Index in range (0, len (MultiFvList)): + if MultiFvList[Index][0] =3D=3D SectionName: + with open (SectionFvFile, 'rb') as File: + MultiFvList[Index][1] =3D File.read () + ImageNode =3D libfdt.fdt_subnode_offset(NewFitHeader, = ImagesNode, SectionName) + ImageSize =3D int.from_bytes (libfdt.fdt_getprop (NewF= itHeader, ImageNode, 'data-size')[0], 'big') + ReplaceOffset =3D int.from_bytes (libfdt.fdt_getprop (NewF= itHeader, ImageNode, 'data-offset')[0], 'big') + OffsetDelta =3D len(MultiFvList[Index][1]) - ImageSize + FitSize +=3D OffsetDelta + IsFvExist =3D True + libfdt.fdt_setprop_u32(NewFitHeader, ImageNode, 'data-size= ', len(MultiFvList[Index][1])) + + # + # Update new fit header + # + ImagesNode =3D libfdt.fdt_subnode_offset(NewFitHeader, 0, 'images') + if (IsFvExist =3D=3D False): + with open (SectionFvFile, 'rb') as File: + SectionFvFileBinary =3D File.read () + MultiFvList.append ([SectionName, SectionFvFileBinary]) + FvNode =3D libfdt.fdt_add_subnode(NewFitHeader, ImagesNode, Se= ctionName) + BuildFvImageNode (NewFitHeader, None, FvNode, FitSize, len(Sec= tionFvFileBinary), SectionName + " Firmware Volume") + FitSize +=3D len(SectionFvFileBinary) + else: + for Index in range (0, len (MultiFvList)): + ImageNode =3D libfdt.fdt_subnode_offset(NewFitHeader, I= magesNode, MultiFvList[Index][0]) + ImageOffset =3D int.from_bytes (libfdt.fdt_getprop (NewFi= tHeader, ImageNode, 'data-offset')[0], 'big') + if ImageOffset > ReplaceOffset: + libfdt.fdt_setprop_u32(NewFitHeader, ImageNode, 'data-= offset', ImageOffset + OffsetDelta) + + ConfNodes =3D libfdt.fdt_subnode_offset(NewFitHeader, 0, 'conf= igurations') + ConfNode =3D libfdt.fdt_subnode_offset(NewFitHeader, ConfNode= s, 'conf-1') + + libfdt.fdt_setprop_u32(NewFitHeader, 0, 'size', FitSize) + + # + # Generate new fit image + # + ImagesNode =3D libfdt.fdt_subnode_offset(NewFitHeader, 0, 'imag= es') + TianoNode =3D libfdt.fdt_subnode_offset(NewFitHeader, ImagesNo= de, 'tianocore') + TianoOffset =3D int.from_bytes (libfdt.fdt_getprop (NewFitHeader= , TianoNode, 'data-offset')[0], 'big') + TianoSize =3D int.from_bytes (libfdt.fdt_getprop (NewFitHeader= , TianoNode, 'data-size')[0], 'big') + TianoBinary =3D Dtb[TianoOffset:TianoOffset + TianoSize] + + print("\nGenerate new fit image:") + NewUplBinary =3D bytearray(FitSize) + print("Update fit header\t to 0x0\t\t ~ " + str(hex(len(NewFitHead= er)))) + NewUplBinary[:len(NewFitHeader)] =3D 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= )] =3D TianoBinary + for Index in range (0, len (MultiFvList)): + ImageNode =3D libfdt.fdt_subnode_offset(NewFitHeader, Images= Node, MultiFvList[Index][0]) + ImageOffset =3D int.from_bytes (libfdt.fdt_getprop (NewFitHead= er, ImageNode, 'data-offset')[0], 'big') + ImageSize =3D int.from_bytes (libfdt.fdt_getprop (NewFitHead= er, ImageNode, 'data-size')[0], 'big') + NewUplBinary[ImageOffset:ImageOffset + ImageSize] =3D MultiFvL= ist[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/U= efiPayloadPkg/UefiPayloadEntry/FitUniversalPayloadEntry.c new file mode 100644 index 0000000000..fea09bd8b5 --- /dev/null +++ b/UefiPayloadPkg/UefiPayloadEntry/FitUniversalPayloadEntry.c @@ -0,0 +1,648 @@ +/** @file + Copyright (c) 2021, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include "UefiPayloadEntry.h" +#include + +#define MEMORY_ATTRIBUTE_MASK (EFI_RESOURCE_ATTRIBUTE_PRESENT = | \ + EFI_RESOURCE_ATTRIBUTE_INITIALIZED = | \ + EFI_RESOURCE_ATTRIBUTE_TESTED = | \ + EFI_RESOURCE_ATTRIBUTE_READ_PROTECT= ED | \ + EFI_RESOURCE_ATTRIBUTE_WRITE_PROTEC= TED | \ + EFI_RESOURCE_ATTRIBUTE_EXECUTION_PR= OTECTED | \ + EFI_RESOURCE_ATTRIBUTE_READ_ONLY_PR= OTECTED | \ + 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 =3D 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 =3D 0; + + for (Str1 =3D String; *Str1 !=3D L'\0'; Str1++) { + for (Str2 =3D CharSet; *Str2 !=3D L'\0'; Str2++) { + if (*Str1 =3D=3D *Str2) { + break; + } + } + + if (*Str2 =3D=3D 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 =3D String; *Str1 !=3D L'\0'; Str1++) { + for (Str2 =3D CharSet; *Str2 !=3D L'\0'; Str2++) { + if (*Str1 =3D=3D *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 =3D (String =3D=3D NULL) ? mLineBuffer : String; + if (Begin =3D=3D NULL) { + return NULL; + } + + Begin +=3D AsciiStrSpn (Begin, CharSet); + if (*Begin =3D=3D L'\0') { + mLineBuffer =3D NULL; + return NULL; + } + + End =3D AsciiStrBrk (Begin, CharSet); + if ((End !=3D NULL) && (*End !=3D L'\0')) { + *End =3D L'\0'; + End++; + } + + mLineBuffer =3D End; + return Begin; +} + +/** + Some bootloader may pass a pcd database, and UPL also contain a PCD data= base. + Dxe PCD driver has the assumption that the two PCD database can be caten= ated 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 databa= se. + @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 =3D GetFirstGuidHob (&gPcdDataBaseHobGuid); + if (GuidHob =3D=3D NULL) { + // + // No fix-up is needed. + // + return EFI_SUCCESS; + } + + PeiDatabase =3D (PEI_PCD_DATABASE *)GET_GUID_HOB_DATA (GuidHob); + DEBUG ((DEBUG_INFO, "Find the Pei PCD data base, the total local token n= umber is %d\n", PeiDatabase->LocalTokenCount)); + + Status =3D FvFindFileByTypeGuid (DxeFv, EFI_FV_FILETYPE_DRIVER, PcdGetPt= r (PcdPcdDriverFile), &FileHeader); + ASSERT_EFI_ERROR (Status); + if (EFI_ERROR (Status)) { + return Status; + } + + Status =3D FileFindSection (FileHeader, EFI_SECTION_RAW, &PcdRawData); + ASSERT_EFI_ERROR (Status); + if (EFI_ERROR (Status)) { + return Status; + } + + UplDatabase =3D (PEI_PCD_DATABASE *)PcdRawData; + ExMapTable =3D (DYNAMICEX_MAPPING *)(UINTN)((UINTN)PcdRawData + UplData= base->ExMapTableOffset); + + for (Index =3D 0; Index < UplDatabase->ExTokenCount; Index++) { + ExMapTable[Index].TokenNumber +=3D 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 =3D=3D NULL) { + return; + } + + NewHob.Header =3D CreateHob (Hob->Header->HobType, Hob->Header->HobLengt= h); + + if (NewHob.Header !=3D 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 =3D (UINT8 *)HobList; !END_OF_HOB_LIST (Hob); Hob.Raw =3D G= ET_NEXT_HOB (Hob)) { + // + // Skip all HOBs except Resource Descriptor HOBs + // + if (GET_HOB_TYPE (Hob) !=3D EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) { + continue; + } + + // + // Skip Resource Descriptor HOBs that do not describe tested system me= mory + // + ResourceHob =3D Hob.ResourceDescriptor; + if (ResourceHob->ResourceType !=3D EFI_RESOURCE_SYSTEM_MEMORY) { + continue; + } + + if ((ResourceHob->ResourceAttribute & MEMORY_ATTRIBUTE_MASK) !=3D TEST= ED_MEMORY_ATTRIBUTES) { + continue; + } + + // + // Skip Resource Descriptor HOBs that do not contain the PHIT range Ef= iFreeMemoryBottom..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 R= esource 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 =3D NULL; + + for (Hob.Raw =3D (UINT8 *)HobList; !END_OF_HOB_LIST (Hob); Hob.Raw =3D G= ET_NEXT_HOB (Hob)) { + // + // Skip all HOBs except Resource Descriptor HOBs + // + if (GET_HOB_TYPE (Hob) !=3D EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) { + continue; + } + + // + // Skip Resource Descriptor HOBs that do not describe tested system me= mory + // + ResourceHob =3D Hob.ResourceDescriptor; + if (ResourceHob->ResourceType !=3D EFI_RESOURCE_SYSTEM_MEMORY) { + continue; + } + + if ((ResourceHob->ResourceAttribute & MEMORY_ATTRIBUTE_MASK) !=3D TEST= ED_MEMORY_ATTRIBUTES) { + continue; + } + + // + // Skip if the Resource Descriptor HOB equals to ExceptResourceHob + // + if (ResourceHob =3D=3D 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 =3D=3D NULL) { + ReturnResourceHob =3D ResourceHob; + } else { + if (ReturnResourceHob->PhysicalStart < ResourceHob->PhysicalStart) { + ReturnResourceHob =3D 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 =3D=3D EFI_HOB_TYPE_HANDOFF) { + return FALSE; + } + + if (Hob.Header->HobType =3D=3D EFI_HOB_TYPE_MEMORY_ALLOCATION) { + if (CompareGuid (&Hob.MemoryAllocationModule->MemoryAllocationHeader.N= ame, &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 =3D GetFirstGuidHob (&gUniversalPayloadBaseGuid); + if (GuidHob !=3D NULL) { + PayloadBase =3D (UNIVERSAL_PAYLOAD_BASE *)GET_GUID_HOB_DATA (GuidHob); + Fdt =3D (VOID *)(UINTN)PayloadBase->Entry; + DEBUG ((DEBUG_INFO, "PayloadBase Entry =3D 0x%08x\n", PayloadBase->Ent= ry)); + } + + Status =3D FdtCheckHeader (Fdt); + if (EFI_ERROR (Status)) { + return EFI_UNSUPPORTED; + } + + ConfigNode =3D FdtSubnodeOffsetNameLen (Fdt, 0, "configurations", (INT32= )AsciiStrLen ("configurations")); + if (ConfigNode <=3D 0) { + return EFI_NOT_FOUND; + } + + Config1Node =3D FdtSubnodeOffsetNameLen (Fdt, ConfigNode, "conf-1", (INT= 32)AsciiStrLen ("conf-1")); + if (Config1Node <=3D 0) { + return EFI_NOT_FOUND; + } + ImageNode =3D FdtSubnodeOffsetNameLen (Fdt, 0, "images", (INT32)AsciiS= trLen ("images")); + if (ImageNode <=3D 0) { + return EFI_NOT_FOUND; + } + FvNode =3D FdtSubnodeOffsetNameLen (Fdt, ImageNode, "tianocore", (INT32)= AsciiStrLen ("tianocore")); + Depth =3D FdtNodeDepth (Fdt, FvNode); + FvNode =3D FdtNextNode (Fdt, FvNode, &Depth); + Fvname =3D FdtGetName (Fdt, FvNode, &TempLen); + while ((AsciiStrCmp((Fvname + AsciiStrLen(Fvname) - 2), "fv") =3D=3D 0))= { + if (FvNode <=3D 0) { + return EFI_NOT_FOUND; + } + PropertyPtr =3D FdtGetProperty (Fdt, FvNode, "data-offset", &TempLen); + Data32 =3D (UINT32 *)(PropertyPtr->Data); + DataOffset =3D SwapBytes32 (*Data32); + + PropertyPtr =3D FdtGetProperty (Fdt, FvNode, "data-size", &TempLen); + Data32 =3D (UINT32 *)(PropertyPtr->Data); + DataSize =3D SwapBytes32 (*Data32); + + if (AsciiStrCmp (Fvname, "uefi-fv") =3D=3D 0) { + *DxeFv =3D (EFI_FIRMWARE_VOLUME_HEADER *)((UINTN)PayloadBase->Entry = + (UINTN)DataOffset); + ASSERT ((*DxeFv)->FvLength =3D=3D DataSize); + } else { + BuildFvHob (((UINTN)PayloadBase->Entry + (UINTN)DataOffset), DataSiz= e); + } + + DEBUG (( + DEBUG_INFO, + "UPL Multiple fv[%a], Base=3D0x%08x, size=3D0x%08x\n", + Fvname, + ((UINTN)PayloadBase->Entry + (UINTN)DataOffset), + DataSize, + DataOffset + )); + Depth =3D FdtNodeDepth (Fdt, FvNode); + FvNode =3D FdtNextNode (Fdt, FvNode, &Depth); + Fvname =3D FdtGetName (Fdt, FvNode, &TempLen); + } + return EFI_SUCCESS; +} + +/** + It will build HOBs based on information from bootloaders. + @param[in] BootloaderParameter The starting memory address of bootloa= der 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 =3D (UINT8 *)BootloaderParameter; + MinimalNeededSize =3D FixedPcdGet32 (PcdSystemMemoryUefiRegionSize); + + ASSERT (Hob.Raw !=3D NULL); + ASSERT ((UINTN)Hob.HandoffInformationTable->EfiFreeMemoryTop =3D=3D Hob.= HandoffInformationTable->EfiFreeMemoryTop); + ASSERT ((UINTN)Hob.HandoffInformationTable->EfiMemoryTop =3D=3D Hob.Hand= offInformationTable->EfiMemoryTop); + ASSERT ((UINTN)Hob.HandoffInformationTable->EfiFreeMemoryBottom =3D=3D H= ob.HandoffInformationTable->EfiFreeMemoryBottom); + ASSERT ((UINTN)Hob.HandoffInformationTable->EfiMemoryBottom =3D=3D Hob.H= andoffInformationTable->EfiMemoryBottom); + + // + // Try to find Resource Descriptor HOB that contains Hob range EfiMemory= Bottom..EfiMemoryTop + // + PhitResourceHob =3D FindResourceDescriptorByRange (Hob.Raw, Hob.HandoffI= nformationTable->EfiMemoryBottom, Hob.HandoffInformationTable->EfiMemoryTop= ); + if (PhitResourceHob =3D=3D NULL) { + // + // Boot loader's Phit Hob is not in an available Resource Descriptor, = find another Resource Descriptor for new Phit Hob + // + ResourceHob =3D FindAnotherHighestBelow4GResourceDescriptor (Hob.Raw, = MinimalNeededSize, NULL); + if (ResourceHob =3D=3D NULL) { + return EFI_NOT_FOUND; + } + + MemoryBottom =3D ResourceHob->PhysicalStart + ResourceHob->Resourc= eLength - MinimalNeededSize; + FreeMemoryBottom =3D MemoryBottom; + FreeMemoryTop =3D ResourceHob->PhysicalStart + ResourceHob->Resourc= eLength; + MemoryTop =3D FreeMemoryTop; + } else if (PhitResourceHob->PhysicalStart + PhitResourceHob->ResourceLen= gth - Hob.HandoffInformationTable->EfiMemoryTop >=3D MinimalNeededSize) { + // + // New availiable Memory range in new hob is right above memory top in= old hob. + // + MemoryBottom =3D Hob.HandoffInformationTable->EfiFreeMemoryTop; + FreeMemoryBottom =3D Hob.HandoffInformationTable->EfiMemoryTop; + FreeMemoryTop =3D FreeMemoryBottom + MinimalNeededSize; + MemoryTop =3D FreeMemoryTop; + } else if (Hob.HandoffInformationTable->EfiMemoryBottom - PhitResourceHo= b->PhysicalStart >=3D MinimalNeededSize) { + // + // New availiable Memory range in new hob is right below memory bottom= in old hob. + // + MemoryBottom =3D Hob.HandoffInformationTable->EfiMemoryBottom - Mi= nimalNeededSize; + FreeMemoryBottom =3D MemoryBottom; + FreeMemoryTop =3D Hob.HandoffInformationTable->EfiMemoryBottom; + MemoryTop =3D Hob.HandoffInformationTable->EfiMemoryTop; + } else { + // + // In the Resource Descriptor HOB contains boot loader Hob, there is n= o enough free memory size for payload hob + // Find another Resource Descriptor Hob + // + ResourceHob =3D FindAnotherHighestBelow4GResourceDescriptor (Hob.Raw, = MinimalNeededSize, PhitResourceHob); + if (ResourceHob =3D=3D NULL) { + return EFI_NOT_FOUND; + } + + MemoryBottom =3D ResourceHob->PhysicalStart + ResourceHob->Resourc= eLength - MinimalNeededSize; + FreeMemoryBottom =3D MemoryBottom; + FreeMemoryTop =3D ResourceHob->PhysicalStart + ResourceHob->Resourc= eLength; + MemoryTop =3D FreeMemoryTop; + } + + HobInfo =3D HobConstructor ((VOID *)(UINTN)MemoryBottom, (VOID= *)(UINTN)MemoryTop, (VOID *)(UINTN)FreeMemoryBottom, (VOID *)(UINTN)FreeMe= moryTop); + HobInfo->BootMode =3D 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 lo= ader hob list. + // + while (!END_OF_HOB_LIST (Hob)) { + if (IsHobNeed (Hob)) { + // Add this hob to payload HOB + AddNewHob (&Hob); + } + + Hob.Raw =3D GET_NEXT_HOB (Hob); + } + + BuildFitLoadablesFvHob (DxeFv); + + // + // Create guid hob for acpi board information + // + GuidHob =3D GetFirstGuidHob (&gUniversalPayloadAcpiTableGuid); + if (GuidHob !=3D NULL) { + AcpiTable =3D (UNIVERSAL_PAYLOAD_ACPI_TABLE *)GET_GUID_HOB_DATA (GuidH= ob); + GuidHob =3D GetFirstGuidHob (&gUefiAcpiBoardInfoGuid); + if (GuidHob =3D=3D NULL) { + AcpiBoardInfo =3D BuildHobFromAcpi ((UINT64)AcpiTable->Rsdp); + ASSERT (AcpiBoardInfo !=3D NULL); + } + } + + // + // Update DXE FV information to first fv hob in the hob list, which + // is the empty FvHob created before. + // + FvHob =3D GetFirstHob (EFI_HOB_TYPE_FV); + FvHob->BaseAddress =3D (EFI_PHYSICAL_ADDRESS)(UINTN)*DxeFv; + FvHob->Length =3D (*DxeFv)->FvLength; + return EFI_SUCCESS; +} + +/** + Entry point to the C language phase of UEFI payload. + @param[in] BootloaderParameter The starting address of bootloader p= arameter block. + @retval It will not return if SUCCESS, and return error when passin= g 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 =3D (VOID *)BootloaderParameter; + DxeFv =3D NULL; + // Call constructor for all libraries + ProcessLibraryConstructorList (); + + DEBUG ((DEBUG_INFO, "Entering Universal Payload...\n")); + DEBUG ((DEBUG_INFO, "sizeof(UINTN) =3D 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 =3D BuildHobs (BootloaderParameter, &DxeFv); + ASSERT_EFI_ERROR (Status); + + FixUpPcdDatabase (DxeFv); + Status =3D 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 =3D (EFI_HOB_HANDOFF_INFO_TABLE *)GetFirstHo= b (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..02f036005f --- /dev/null +++ b/UefiPayloadPkg/UefiPayloadEntry/FitUniversalPayloadEntry.inf @@ -0,0 +1,99 @@ +## @file +# This is the first module for UEFI payload. +# +# Copyright (c) 2021, Intel Corporation. All rights reserved.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION =3D 0x00010005 + BASE_NAME =3D FitUniversalPayloadEntry + FILE_GUID =3D CED5A8A9-B6EA-4D5A-8689-577EE88566CF + MODULE_TYPE =3D SEC + VERSION_STRING =3D 1.0 + +# +# The following information is for reference only and not required by the = build tools. +# +# VALID_ARCHITECTURES =3D 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 + gEdkiiBootManagerMenuFileGuid + +[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 ## SOMETIM= ES_CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdDxeNxMemoryProtectionPolicy ## SOMETIM= ES_CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdImageProtectionPolicy ## SOMETIM= ES_CONSUMES diff --git a/UefiPayloadPkg/UefiPayloadPkg.dsc b/UefiPayloadPkg/UefiPayload= Pkg.dsc index 47812048dd..5655c6409a 100644 --- a/UefiPayloadPkg/UefiPayloadPkg.dsc +++ b/UefiPayloadPkg/UefiPayloadPkg.dsc @@ -30,7 +30,6 @@ DEFINE PS2_KEYBOARD_ENABLE =3D FALSE DEFINE RAM_DISK_ENABLE =3D FALSE DEFINE SIO_BUS_ENABLE =3D FALSE - DEFINE UNIVERSAL_PAYLOAD =3D FALSE DEFINE SECURITY_STUB_ENABLE =3D TRUE DEFINE SMM_SUPPORT =3D FALSE DEFINE PLATFORM_BOOT_TIMEOUT =3D 3 @@ -44,6 +43,11 @@ DEFINE BOOTSPLASH_IMAGE =3D FALSE DEFINE NVME_ENABLE =3D TRUE DEFINE CAPSULE_SUPPORT =3D FALSE + # + # Setup Universal Payload + # + DEFINE UNIVERSAL_PAYLOAD =3D FALSE + DEFINE UNIVERSAL_PAYLOAD_FORMAT =3D ELF =20 # # NULL: NullMemoryTestDxe @@ -115,7 +119,7 @@ DEFINE VARIABLE_SUPPORT =3D EMU =20 DEFINE DISABLE_RESET_SYSTEM =3D FALSE - DEFINE NETWORK_DRIVER_ENABLE =3D FALSE + DEFINE NETWORK_DRIVER_ENABLE =3D TRUE =20 # Dfine the maximum size of the capsule image without a reset flag that = the platform can support. DEFINE MAX_SIZE_NON_POPULATE_CAPSULE =3D 0xa00000 @@ -311,7 +315,7 @@ VariableFlashInfoLib|MdeModulePkg/Library/BaseVariableFlashInfoLib/BaseV= ariableFlashInfoLib.inf CcExitLib|UefiCpuPkg/Library/CcExitLibNull/CcExitLibNull.inf ReportStatusCodeLib|MdeModulePkg/Library/DxeReportStatusCodeLib/DxeRepor= tStatusCodeLib.inf - + FdtLib|MdePkg/Library/BaseFdtLib/BaseFdtLib.inf [LibraryClasses.common] !if $(BOOTSPLASH_IMAGE) SafeIntLib|MdePkg/Library/BaseSafeIntLib/BaseSafeIntLib.inf @@ -600,14 +604,26 @@ !if "IA32" in "$(ARCH)" [Components.IA32] !if $(UNIVERSAL_PAYLOAD) =3D=3D TRUE - UefiPayloadPkg/UefiPayloadEntry/UniversalPayloadEntry.inf + !if $(UNIVERSAL_PAYLOAD_FORMAT) =3D=3D "ELF" + UefiPayloadPkg/UefiPayloadEntry/UniversalPayloadEntry.inf + !elseif $(UNIVERSAL_PAYLOAD_FORMAT) =3D=3D "FIT" + UefiPayloadPkg/UefiPayloadEntry/FitUniversalPayloadEntry.inf + !else + UefiPayloadPkg/UefiPayloadEntry/UefiPayloadEntry.inf + !endif !else UefiPayloadPkg/UefiPayloadEntry/UefiPayloadEntry.inf !endif !else [Components.X64] !if $(UNIVERSAL_PAYLOAD) =3D=3D TRUE - UefiPayloadPkg/UefiPayloadEntry/UniversalPayloadEntry.inf + !if $(UNIVERSAL_PAYLOAD_FORMAT) =3D=3D "ELF" + UefiPayloadPkg/UefiPayloadEntry/UniversalPayloadEntry.inf + !elseif $(UNIVERSAL_PAYLOAD_FORMAT) =3D=3D "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/Unive= rsalPayloadBuild.py index ecc25dad83..222bed28fc 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 =3D True =20 +class bcolors: + HEADER =3D '\033[95m' + OKBLUE =3D '\033[94m' + OKCYAN =3D '\033[96m' + OKGREEN =3D '\033[92m' + WARNING =3D '\033[93m' + FAIL =3D '\033[91m' + ENDC =3D '\033[0m' + BOLD =3D '\033[1m' + UNDERLINE =3D '\033[4m' + class UPLD_INFO_HEADER(LittleEndianStructure): _pack_ =3D 1 _fields_ =3D [ @@ -36,41 +48,116 @@ class UPLD_INFO_HEADER(LittleEndianStructure): self.ImageId =3D b'UEFI' self.ProducerId =3D b'INTEL' =20 -def BuildUniversalPayload(Args): - def RunCommand(cmd): - print(cmd) - p =3D subprocess.Popen(cmd, shell=3DTrue, stdout=3Dsubprocess.PIPE= , stderr=3Dsubprocess.STDOUT,cwd=3Dos.environ['WORKSPACE']) - while True: - line =3D p.stdout.readline() - if not line: - break - print(line.strip().decode(errors=3D'ignore')) - - p.communicate() - if p.returncode !=3D 0: - print("- Failed - error happened when run command: %s"%cmd) - raise Exception("ERROR: when run command: %s"%cmd) +def ValidateSpecRevision (Argument): + try: + (MajorStr, MinorStr) =3D 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 Versio= n. + # + if len(MinorStr) > 0 and len(MinorStr) < 3: + try: + Minor =3D int(MinorStr, 16) if len(MinorStr) =3D=3D 2 else (in= t(MinorStr, 16) << 4) + except: + raise argparse.ArgumentTypeError ('{} Minor version of SpecRev= ision 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 =3D int(MajorStr, 16) + except: + raise argparse.ArgumentTypeError ('{} Major version of SpecRev= ision 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) =20 +def Validate32BitInteger (Argument): + try: + Value =3D 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.'.for= mat (Argument)) + return Value + +def ValidateAddFv (Argument): + Value =3D Argument.split ("=3D") + if len (Value) !=3D 2: + raise argparse.ArgumentTypeError ('{} is incorrect format with "xx= x_fv=3Dxxx.fv"'.format (Argument)) + if Value[0][-3:] !=3D "_fv": + raise argparse.ArgumentTypeError ('{} is incorrect format with "xx= x_fv=3Dxxx.fv"'.format (Argument)) + if Value[1][-3:].lower () !=3D ".fv": + raise argparse.ArgumentTypeError ('{} is incorrect format with "xx= x_fv=3Dxxx.fv"'.format (Argument)) + if os.path.exists (Value[1]) =3D=3D False: + raise argparse.ArgumentTypeError ('File {} is not found.'.format (= Value[1])) + return Value + +def RunCommand(cmd): + print(cmd) + p =3D subprocess.Popen(cmd, shell=3DTrue, stdout=3Dsubprocess.PIPE, st= derr=3Dsubprocess.STDOUT,cwd=3Dos.environ['WORKSPACE']) + while True: + line =3D p.stdout.readline() + if not line: + break + print(line.strip().decode(errors=3D'ignore')) + + p.communicate() + if p.returncode !=3D 0: + print("- Failed - error happened when run command: %s"%cmd) + raise Exception("ERROR: when run command: %s"%cmd) + +def BuildUniversalPayload(Args): BuildTarget =3D Args.Target ToolChain =3D Args.ToolChain Quiet =3D "--quiet" if Args.Quiet else "" - ElfToolChain =3D 'CLANGDWARF' + + if Args.PayloadEntryFormat =3D=3D "pecoff": + PayloadEntryToolChain =3D ToolChain + Args.Macro.append("UNIVERSAL_PAYLOAD_FORMAT=3DFIT") + UpldEntryFile =3D "FitUniversalPayloadEntry" + else: + PayloadEntryToolChain =3D 'CLANGDWARF' + Args.Macro.append("UNIVERSAL_PAYLOAD_FORMAT=3DELF") + UpldEntryFile =3D "UniversalPayloadEntry" + BuildDir =3D os.path.join(os.environ['WORKSPACE'], os.path.normpat= h("Build/UefiPayloadPkgX64")) - BuildModule =3D "" - BuildArch =3D "" if Args.Arch =3D=3D 'X64': BuildArch =3D "X64" - EntryOutputDir =3D os.path.join(BuildDir, "{}_{}".format (BuildTar= get, ElfToolChain), os.path.normpath("X64/UefiPayloadPkg/UefiPayloadEntry/U= niversalPayloadEntry/DEBUG/UniversalPayloadEntry.dll")) + FitArch =3D "x86_64" + ObjCopyFlag =3D "elf64-x86-64" + EntryOutputDir =3D os.path.join(BuildDir, "{}_{}".format (BuildTar= get, PayloadEntryToolChain), os.path.normpath("X64/UefiPayloadPkg/UefiPaylo= adEntry/{}/DEBUG/{}.dll".format (UpldEntryFile, UpldEntryFile))) else: BuildArch =3D "IA32 -a X64" - EntryOutputDir =3D os.path.join(BuildDir, "{}_{}".format (BuildTar= get, ElfToolChain), os.path.normpath("IA32/UefiPayloadPkg/UefiPayloadEntry/= UniversalPayloadEntry/DEBUG/UniversalPayloadEntry.dll")) + FitArch =3D "x86" + ObjCopyFlag =3D "elf32-i386" + EntryOutputDir =3D os.path.join(BuildDir, "{}_{}".format (BuildTar= get, PayloadEntryToolChain), os.path.normpath("IA32/UefiPayloadPkg/UefiPayl= oadEntry/{}/DEBUG/{}.dll".format (UpldEntryFile, UpldEntryFile))) =20 if Args.PreBuildUplBinary is not None: EntryOutputDir =3D os.path.abspath(Args.PreBuildUplBinary) + EntryModuleInf =3D os.path.normpath("UefiPayloadPkg/UefiPayloadEntry/{= }.inf".format (UpldEntryFile)) DscPath =3D os.path.normpath("UefiPayloadPkg/UefiPayloadPkg.dsc") + DxeFvOutputDir =3D os.path.join(BuildDir, "{}_{}".format (BuildTarget,= ToolChain), os.path.normpath("FV/DXEFV.Fv")) + BdsFvOutputDir =3D os.path.join(BuildDir, "{}_{}".format (BuildTarget,= ToolChain), os.path.normpath("FV/BDSFV.Fv")) + NetworkFvOutputDir =3D os.path.join(BuildDir, "{}_{}".format (BuildTar= get, ToolChain), os.path.normpath("FV/NETWORKFV.Fv")) + PayloadReportPath =3D os.path.join(BuildDir, "UefiUniversalPayload.txt= ") ModuleReportPath =3D os.path.join(BuildDir, "UefiUniversalPayloadEntry= .txt") UpldInfoFile =3D os.path.join(BuildDir, "UniversalPayloadInfo.bin") =20 + if "CLANG_BIN" in os.environ: + LlvmObjcopyPath =3D os.path.join(os.environ["CLANG_BIN"], "llvm-ob= jcopy") + else: + LlvmObjcopyPath =3D "llvm-objcopy" + try: + RunCommand('"%s" --version'%LlvmObjcopyPath) + except: + print("- Failed - Please check if LLVM is installed or if CLANG_BI= N is set correctly") + sys.exit(1) + Pcds =3D "" if (Args.pcd !=3D None): for PcdItem in Args.pcd: @@ -85,7 +172,6 @@ def BuildUniversalPayload(Args): # Building DXE core and DXE drivers as DXEFV. # if Args.BuildEntryOnly =3D=3D False: - PayloadReportPath =3D os.path.join(BuildDir, "UefiUniversalPayload= .txt") BuildPayload =3D "build -p {} -b {} -a X64 -t {} -y {} {}".format = (DscPath, BuildTarget, ToolChain, PayloadReportPath, Quiet) BuildPayload +=3D Pcds BuildPayload +=3D Defines @@ -94,88 +180,126 @@ def BuildUniversalPayload(Args): # Building Universal Payload entry. # if Args.PreBuildUplBinary is None: - EntryModuleInf =3D os.path.normpath("UefiPayloadPkg/UefiPayloadEnt= ry/UniversalPayloadEntry.inf") - BuildModule =3D "build -p {} -b {} -a {} -m {} -t {} -y {} {}".for= mat (DscPath, BuildTarget, BuildArch, EntryModuleInf, ElfToolChain, ModuleR= eportPath, Quiet) + BuildModule =3D "build -p {} -b {} -a {} -m {} -t {} -y {} {}".for= mat (DscPath, BuildTarget, BuildArch, EntryModuleInf, PayloadEntryToolChain= , ModuleReportPath, Quiet) BuildModule +=3D Pcds BuildModule +=3D Defines RunCommand(BuildModule) # # Buid Universal Payload Information Section ".upld_info" # - upld_info_hdr =3D UPLD_INFO_HEADER() - upld_info_hdr.SpecRevision =3D Args.SpecRevision - upld_info_hdr.Revision =3D Args.Revision - upld_info_hdr.ProducerId =3D Args.ProducerId.encode()[:16] - upld_info_hdr.ImageId =3D Args.ImageId.encode()[:16] - upld_info_hdr.Attribute |=3D 1 if BuildTarget =3D=3D "DEBUG" else 0 - fp =3D open(UpldInfoFile, 'wb') - fp.write(bytearray(upld_info_hdr)) - fp.close() + if Args.SpecRevision < 0x0100: + upld_info_hdr =3D UPLD_INFO_HEADER() + upld_info_hdr.SpecRevision =3D Args.SpecRevision + upld_info_hdr.Revision =3D Args.Revision + upld_info_hdr.ProducerId =3D Args.ProducerId.encode()[:16] + upld_info_hdr.ImageId =3D Args.ImageId.encode()[:16] + upld_info_hdr.Attribute |=3D 1 if BuildTarget =3D=3D "DEBUG" else 0 + fp =3D open(UpldInfoFile, 'wb') + fp.write(bytearray(upld_info_hdr)) + fp.close() + + if Args.BuildEntryOnly =3D=3D False: + import Tools.ElfFv as ElfFv + ElfFv.ReplaceFv (EntryOutputDir, UpldInfoFile, '.upld_info', A= lignment =3D 4) + shutil.copy (EntryOutputDir, os.path.join(BuildDir, 'UniversalPayload.= {}'.format (Args.PayloadEntryFormat))) =20 MultiFvList =3D [] if Args.BuildEntryOnly =3D=3D False: MultiFvList =3D [ - ['uefi_fv', os.path.join(BuildDir, "{}_{}".format (BuildTar= get, ToolChain), os.path.normpath("FV/DXEFV.Fv")) ], - ['bds_fv', os.path.join(BuildDir, "{}_{}".format (BuildTar= get, ToolChain), os.path.normpath("FV/BDSFV.Fv")) ], - ['network_fv', os.path.join(BuildDir, "{}_{}".format (BuildTar= get, ToolChain), os.path.normpath("FV/NETWORKFV.Fv")) ], + ['uefi_fv', os.path.join(BuildDir, "{}_{}".format (Buil= dTarget, ToolChain), os.path.normpath("FV/DXEFV.Fv")) ], + ['bds_fv', os.path.join(BuildDir, "{}_{}".format (Buil= dTarget, ToolChain), os.path.normpath("FV/BDSFV.Fv")) ], + ['network_fv', os.path.join(BuildDir, "{}_{}".format (Buil= dTarget, ToolChain), os.path.normpath("FV/NETWORKFV.Fv"))], ] - AddSectionName =3D '.upld_info' - ReplaceFv (EntryOutputDir, UpldInfoFile, AddSectionName, Alignment= =3D 4) =20 - shutil.copy (EntryOutputDir, os.path.join(BuildDir, 'UniversalPayload.= elf')) =20 - return MultiFvList, os.path.join(BuildDir, 'UniversalPayload.elf') + if Args.SpecRevision >=3D 0x0100: + import Tools.MkFitImage as MkFitImage + import pefile + fit_image_info_header =3D MkFitImage.FIT_IMAGE_INFO_= HEADER() + fit_image_info_header.Description =3D 'Uefi Universal Payload' + fit_image_info_header.UplVersion =3D Args.SpecRevision + fit_image_info_header.Type =3D 'flat-binary' + fit_image_info_header.Arch =3D FitArch + fit_image_info_header.Compression =3D 'none' + fit_image_info_header.Revision =3D Args.Revision + fit_image_info_header.BuildType =3D Args.Target.lower() + fit_image_info_header.Capabilities =3D None + fit_image_info_header.Producer =3D Args.ProducerId.lower() + fit_image_info_header.ImageId =3D Args.ImageId.lower() + fit_image_info_header.Binary =3D os.path.join(BuildDir, 'Un= iversalPayload.{}'.format (Args.PayloadEntryFormat)) + fit_image_info_header.TargetPath =3D os.path.join(BuildDir, 'Un= iversalPayload.fit') + fit_image_info_header.UefifvPath =3D DxeFvOutputDir + fit_image_info_header.BdsfvPath =3D BdsFvOutputDir + fit_image_info_header.NetworkfvPath =3D NetworkFvOutputDir + fit_image_info_header.DataOffset =3D 0x1000 + fit_image_info_header.LoadAddr =3D Args.LoadAddress + fit_image_info_header.Project =3D 'tianocore' + + TargetRebaseFile =3D fit_image_info_header.Binary.replace (pathlib= .Path(fit_image_info_header.Binary).suffix, ".pecoff") + TargetRebaseEntryFile =3D fit_image_info_header.Binary.replace (pa= thlib.Path(fit_image_info_header.Binary).suffix, ".entry") + =20 -def main(): - def ValidateSpecRevision (Argument): - try: - (MajorStr, MinorStr) =3D Argument.split('.') - except: - raise argparse.ArgumentTypeError ('{} is not a valid SpecRevis= ion format (Major[8-bits].Minor[8-bits]).'.format (Argument)) # - # Spec Revision Bits 15 : 8 - Major Version. Bits 7 : 0 - Minor Ve= rsion. + # Rebase PECOFF to load address # - if len(MinorStr) > 0 and len(MinorStr) < 3: - try: - Minor =3D int(MinorStr, 16) if len(MinorStr) =3D=3D 2 else= (int(MinorStr, 16) << 4) - except: - raise argparse.ArgumentTypeError ('{} Minor version of Spe= cRevision is not a valid integer value.'.format (Argument)) - else: - raise argparse.ArgumentTypeError ('{} is not a valid SpecRevis= ion 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.DataO= ffset, + TargetRebaseFile, + TargetRebaseFile, + )) =20 - if len(MajorStr) > 0 and len(MajorStr) < 3: - try: - Major =3D int(MajorStr, 16) - except: - raise argparse.ArgumentTypeError ('{} Major version of Spe= cRevision is not a valid integer value.'.format (Argument)) - else: - raise argparse.ArgumentTypeError ('{} is not a valid SpecRevis= ion format (Major[8-bits].Minor[8-bits]).'.format (Argument)) + # + # Open PECOFF relocation table binary. + # + RelocBinary =3D b'' + PeCoff =3D pefile.PE (TargetRebaseFile) + for reloc in PeCoff.DIRECTORY_ENTRY_BASERELOC: + for entry in reloc.entries: + if (entry.type =3D=3D 0): + continue + Type =3D entry.type + Offset =3D entry.rva + fit_image_info_header.DataOffset + RelocBinary +=3D Type.to_bytes (8, 'little') + Offset.to_b= ytes (8, 'little') + RelocBinary +=3D b'\x00' * (0x1000 - (len(RelocBinary) % 0x1000)) =20 - return int('0x{0:02x}{1:02x}'.format(Major, Minor), 0) + # + # Output UniversalPayload.entry + # + TempBinary =3D open (TargetRebaseFile, 'rb') + TianoBinary =3D TempBinary.read () + TempBinary.close () =20 - def Validate32BitInteger (Argument): - try: - Value =3D int (Argument, 0) - except: - raise argparse.ArgumentTypeError ('{} is not a valid integer v= alue.'.format (Argument)) - if Value < 0: - raise argparse.ArgumentTypeError ('{} is a negative value.'.fo= rmat (Argument)) - if Value > 0xffffffff: - raise argparse.ArgumentTypeError ('{} is larger than 32-bits.'= .format (Argument)) - return Value - - def ValidateAddFv (Argument): - Value =3D Argument.split ("=3D") - if len (Value) !=3D 2: - raise argparse.ArgumentTypeError ('{} is incorrect format with= "xxx_fv=3Dxxx.fv"'.format (Argument)) - if Value[0][-3:] !=3D "_fv": - raise argparse.ArgumentTypeError ('{} is incorrect format with= "xxx_fv=3Dxxx.fv"'.format (Argument)) - if Value[1][-3:].lower () !=3D ".fv": - raise argparse.ArgumentTypeError ('{} is incorrect format with= "xxx_fv=3Dxxx.fv"'.format (Argument)) - if os.path.exists (Value[1]) =3D=3D False: - raise argparse.ArgumentTypeError ('File {} is not found.'.form= at (Value[1])) - return Value + TianoEntryBinary =3D TianoBinary + RelocBinary + TianoEntryBinary +=3D (b'\x00' * (0x1000 - (len(TianoBinary) % 0x1= 000))) + TianoEntryBinarySize =3D len (TianoEntryBinary) =20 + TempBinary =3D open(TargetRebaseEntryFile, "wb") + TempBinary.truncate() + TempBinary.write(TianoEntryBinary) + TempBinary.close() + + # + # Calculate entry and update relocation table start address and da= ta-size. + # + fit_image_info_header.Entry =3D PeCoff.OPTIONAL_HEADER.ImageB= ase + PeCoff.OPTIONAL_HEADER.AddressOfEntryPoint + fit_image_info_header.RelocStart =3D fit_image_info_header.DataOff= set + len(TianoBinary) + fit_image_info_header.DataSize =3D TianoEntryBinarySize + fit_image_info_header.Binary =3D TargetRebaseEntryFile + + if MkFitImage.MakeFitImage(fit_image_info_header) is True: + print('\nSuccessfully build Fit Image') + else: + sys.exit(1) + Args.PayloadEntryFormat =3D 'fit' + return MultiFvList, os.path.join(BuildDir, 'UniversalPayload.{}'.forma= t (Args.PayloadEntryFormat)) + +def main(): parser =3D argparse.ArgumentParser(description=3D'For building Univers= al Payload') parser.add_argument('-t', '--ToolChain') parser.add_argument('-b', '--Target', default=3D'DEBUG') @@ -187,12 +311,20 @@ 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.') parser.add_argument("-r", "--Revision", type=3DValidate32BitInteger, d= efault =3D'0x0000010105', help=3D'Revision of the Payload binary. Major.Min= or.Revision.Build') parser.add_argument("-o", "--ProducerId", default =3D'INTEL', help=3D'= A null-terminated OEM-supplied string that identifies the payload producer = (16 bytes maximal).') + parser.add_argument("-e", "--BuildEntryOnly", action=3D'store_true', h= elp=3D'Build UniversalPayload Entry file') + parser.add_argument("-pb", "--PreBuildUplBinary", default=3DNone, help= =3D'Specify the UniversalPayload file') parser.add_argument("-sk", "--SkipBuild", action=3D'store_true', help= =3D'Skip UniversalPayload build') parser.add_argument("-af", "--AddFv", type=3DValidateAddFv, action=3D'= append', help=3D'Add or replace specific FV into payload, Ex: uefi_fv=3DXXX= .fv') - command_group =3D parser.add_mutually_exclusive_group() - command_group.add_argument("-e", "--BuildEntryOnly", action=3D'store_t= rue', help=3D'Build UniversalPayload Entry file') - command_group.add_argument("-pb", "--PreBuildUplBinary", default=3DNon= e, help=3D'Specify the UniversalPayload file') + known_args, _ =3D parser.parse_known_args() + if (known_args.SpecRevision >=3D 0x0100): + parser.add_argument('--pecoff', dest=3D'PayloadEntryFormat', actio= n=3D'store_true', default=3DTrue) + parser.add_argument('-l', "--LoadAddress", type=3Dint, help=3D'Spe= cify payload load address', default =3D0x000800000) + args =3D parser.parse_args() + if (hasattr (args, 'PayloadEntryFormat') =3D=3D False): + args.PayloadEntryFormat =3D 'elf' + else: + args.PayloadEntryFormat =3D "pecoff" if args.PayloadEntryFormat = =3D=3D True else "elf" =20 MultiFvList =3D [] UniversalPayloadBinary =3D args.PreBuildUplBinary @@ -203,12 +335,24 @@ def main(): for (SectionName, SectionFvFile) in args.AddFv: MultiFvList.append ([SectionName, SectionFvFile]) =20 + def ReplaceFv (UplBinary, SectionFvFile, SectionName): + print (bcolors.OKGREEN + "Patch {}=3D{} into {}".format (SectionNa= me, SectionFvFile, UplBinary) + bcolors.ENDC) + if (args.SpecRevision < 0x0100): + import Tools.ElfFv as ElfFv + return ElfFv.ReplaceFv (UplBinary, SectionFvFile, '.upld.{}'.f= ormat (SectionName)) + else: + import Tools.MkFitImage as MkFitImage + return MkFitImage.ReplaceFv (UplBinary, SectionFvFile, Section= Name) + if (UniversalPayloadBinary !=3D None): for (SectionName, SectionFvFile) in MultiFvList: if os.path.exists (SectionFvFile) =3D=3D False: continue - print ("Patch {}=3D{} into {}".format (SectionName, SectionFvF= ile, UniversalPayloadBinary)) - ReplaceFv (UniversalPayloadBinary, SectionFvFile, '.upld.{}'.f= ormat (SectionName)) + + status =3D ReplaceFv (UniversalPayloadBinary, SectionFvFile, S= ectionName.replace ("_", "-")) + if status !=3D 0: + print (bcolors.FAIL + "[Fail] Patch {}=3D{}".format (Secti= onName, SectionFvFile) + bcolors.ENDC) + return status =20 print ("\nSuccessfully build Universal Payload") =20 --=20 2.39.1.windows.1 -=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#106872): https://edk2.groups.io/g/devel/message/106872 Mute This Topic: https://groups.io/mt/100101593/1787277 Group Owner: devel+owner@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [importer@patchew.org] -=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-