:p
atchew
Login
From: BruceX Wang <brucex.wang@intel.com> Cc: Guo Dong <guo.dong@intel.com> Cc: Sean Rhodes <sean@starlabs.systems> Cc: James Lu <james.lu@intel.com> Cc: Gua Guo <gua.guo@intel.com> Signed-off-by: BruceX Wang <brucex.wang@intel.com> --- .../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.inf create mode 100644 UefiPayloadPkg/Readme.md create mode 100644 UefiPayloadPkg/Tools/MkFitImage.py create mode 100644 UefiPayloadPkg/UefiPayloadEntry/FitUniversalPayloadEntry.c create mode 100644 UefiPayloadPkg/UefiPayloadEntry/FitUniversalPayloadEntry.inf diff --git a/MdeModulePkg/Include/UniversalPayload/UniversalPayload.h b/MdeModulePkg/Include/UniversalPayload/UniversalPayload.h index XXXXXXX..XXXXXXX 100644 --- a/MdeModulePkg/Include/UniversalPayload/UniversalPayload.h +++ b/MdeModulePkg/Include/UniversalPayload/UniversalPayload.h @@ -XXX,XX +XXX,XX @@ SPDX-License-Identifier: BSD-2-Clause-Patent #ifndef UNIVERSAL_PAYLOAD_H_ #define UNIVERSAL_PAYLOAD_H_ - +extern GUID gUniversalPayloadBaseGuid; /** Main entry point to Universal Payload. @@ -XXX,XX +XXX,XX @@ typedef struct { UINT16 Length; } UNIVERSAL_PAYLOAD_GENERIC_HEADER; +typedef struct { + UNIVERSAL_PAYLOAD_GENERIC_HEADER Header; + EFI_PHYSICAL_ADDRESS Entry; +} UNIVERSAL_PAYLOAD_BASE; #pragma pack() /** diff --git a/MdeModulePkg/MdeModulePkg.dec b/MdeModulePkg/MdeModulePkg.dec index XXXXXXX..XXXXXXX 100644 --- a/MdeModulePkg/MdeModulePkg.dec +++ b/MdeModulePkg/MdeModulePkg.dec @@ -XXX,XX +XXX,XX @@ ## Include/UniversalPayload/SerialPortInfo.h gUniversalPayloadSerialPortInfoGuid = { 0xaa7e190d, 0xbe21, 0x4409, { 0x8e, 0x67, 0xa2, 0xcd, 0xf, 0x61, 0xe1, 0x70 } } + ## Include/UniversalPayload/UniversalPayload.h + gUniversalPayloadBaseGuid = { 0x03d4c61d, 0x2713, 0x4ec5, {0xa1, 0xcc, 0x88, 0x3b, 0xe9, 0xdc, 0x18, 0xe5 } } + ## Include/Guid/TraceHubDebugInfoHob.h gTraceHubDebugInfoHobGuid = { 0xf88c9c23, 0x646c, 0x4f6c, { 0x8e, 0x3d, 0x36, 0xa9, 0x43, 0xc1, 0x08, 0x35 } } diff --git a/MdePkg/Include/Library/FdtLib.h b/MdePkg/Include/Library/FdtLib.h index XXXXXXX..XXXXXXX 100644 --- a/MdePkg/Include/Library/FdtLib.h +++ b/MdePkg/Include/Library/FdtLib.h @@ -XXX,XX +XXX,XX @@ FdtSetProp ( IN UINT32 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 overwritten) 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 XXXXXXX..XXXXXXX 100644 --- a/MdePkg/Library/BaseFdtLib/FdtLib.c +++ b/MdePkg/Library/BaseFdtLib/FdtLib.c @@ -XXX,XX +XXX,XX @@ 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 overwritten) 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/PayloadLoaderPeim/FitLib.h new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/UefiPayloadPkg/PayloadLoaderPeim/FitLib.h @@ -XXX,XX +XXX,XX @@ +/** @file + FIT Load Image Support +Copyright (c) 2023, Intel Corporation. All rights reserved.<BR> +SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#ifndef FIT_LIB_H_ +#define FIT_LIB_H_ + +#include <PiPei.h> +#include <Library/DebugLib.h> +#include <Library/FdtLib.h> + +typedef struct { + UINT64 RelocateType; + UINT64 Offset; +} FIT_RELOCATE_ITEM; + +typedef struct { + EFI_PHYSICAL_ADDRESS ImageBase; + EFI_PHYSICAL_ADDRESS PayloadBaseAddress; + UINT64 PayloadSize; + UINTN PayloadEntryOffset; + UINTN PayloadEntrySize; + EFI_PHYSICAL_ADDRESS PayloadEntryPoint; + UINTN RelocateTableOffset; + UINTN RelocateTableCount; + EFI_PHYSICAL_ADDRESS PayloadLoadAddress; +} FIT_IMAGE_CONTEXT; + +typedef struct { + UINT8 *Name; + UINT32 Offset; +} PROPERTY_DATA; + +#define IMAGE_BASE_OFFSET OFFSET_OF (FIT_IMAGE_CONTEXT, ImageBase) +#define PAYLOAD_BASE_ADDR_OFFSET OFFSET_OF (FIT_IMAGE_CONTEXT, PayloadBaseAddress) +#define PAYLOAD_BASE_SIZE_OFFSET OFFSET_OF (FIT_IMAGE_CONTEXT, PayloadSize) +#define PAYLOAD_ENTRY_OFFSET_OFFSET OFFSET_OF (FIT_IMAGE_CONTEXT, PayloadEntryOffset) +#define PAYLOAD_ENTRY_SIZE_OFFSET OFFSET_OF (FIT_IMAGE_CONTEXT, PayloadEntrySize) +#define PAYLOAD_ENTRY_POINT_OFFSET OFFSET_OF (FIT_IMAGE_CONTEXT, PayloadEntryPoint) +#define RELOCATE_TABLE_OFFSET_OFFSET OFFSET_OF (FIT_IMAGE_CONTEXT, RelocateTableOffset) +#define RELOCATE_TABLE_COUNT_OFFSET OFFSET_OF (FIT_IMAGE_CONTEXT, RelocateTableCount) +#define PAYLOAD_LOAD_ADDR_OFFSET OFFSET_OF (FIT_IMAGE_CONTEXT, PayloadLoadAddress) + +/** + Parse the FIT image info. + @param[in] ImageBase Memory address of an image. + @param[out] Context The FIT image context pointer. + @retval EFI_UNSUPPORTED Unsupported binary type. + @retval EFI_SUCCESS FIT binary is loaded successfully. +**/ +EFI_STATUS +EFIAPI +ParseFitImage ( + IN VOID *ImageBase, + OUT FIT_IMAGE_CONTEXT *Context + ); + +#endif diff --git a/UefiPayloadPkg/PayloadLoaderPeim/FitLib/FitLib.c b/UefiPayloadPkg/PayloadLoaderPeim/FitLib/FitLib.c new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/UefiPayloadPkg/PayloadLoaderPeim/FitLib/FitLib.c @@ -XXX,XX +XXX,XX @@ +/** @file + FIT Load Image Support +Copyright (c) 2023, Intel Corporation. All rights reserved.<BR> +SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include "FitLib.h" + +PROPERTY_DATA PropertyData32List[] = { + { "data-offset", PAYLOAD_ENTRY_OFFSET_OFFSET }, + { "data-size", PAYLOAD_ENTRY_SIZE_OFFSET }, + { "reloc-start", RELOCATE_TABLE_OFFSET_OFFSET } +}; + +PROPERTY_DATA PropertyData64List[] = { + { "entry-start", PAYLOAD_ENTRY_POINT_OFFSET }, + { "load", PAYLOAD_LOAD_ADDR_OFFSET } +}; + +/** + Parse the target firmware image info in FIT. + @param[in] Fdt Memory address of a fdt. + @param[in] Firmware Target name of an image. + @param[out] Context The FIT image context pointer. + @retval EFI_NOT_FOUND FIT node dose not find. + @retval EFI_SUCCESS FIT binary is loaded successfully. +**/ +EFI_STATUS +EFIAPI +FitParseFirmwarePropertyData ( + IN VOID *Fdt, + IN CHAR8 *Firmware, + OUT FIT_IMAGE_CONTEXT *Context + ) +{ + CONST FDT_PROPERTY *PropertyPtr; + INT32 ImageNode; + INT32 TianoNode; + INT32 TempLen; + UINT32 *Data32; + UINT64 *Data64; + UINT32 *ContextOffset32; + UINT64 *ContextOffset64; + INT32 Index; + + ImageNode = FdtSubnodeOffsetNameLen (Fdt, 0, "images", (INT32)AsciiStrLen ("images")); + if (ImageNode <= 0) { + return EFI_NOT_FOUND; + } + + TianoNode = FdtSubnodeOffsetNameLen (Fdt, ImageNode, Firmware, (INT32)AsciiStrLen (Firmware)); + if (TianoNode <= 0) { + return EFI_NOT_FOUND; + } + + for (Index = 0; Index < sizeof (PropertyData32List) / sizeof (PROPERTY_DATA); Index++) { + PropertyPtr = FdtGetProperty (Fdt, TianoNode, PropertyData32List[Index].Name, &TempLen); + Data32 = (UINT32 *)(PropertyPtr->Data); + ContextOffset32 = (UINT32 *)((UINTN)Context + PropertyData32List[Index].Offset); + *ContextOffset32 = Fdt32ToCpu (*Data32); + } + + for (Index = 0; Index < sizeof (PropertyData64List)/sizeof (PROPERTY_DATA); Index++) { + PropertyPtr = FdtGetProperty (Fdt, TianoNode, PropertyData64List[Index].Name, &TempLen); + Data64 = (UINT64 *)(PropertyPtr->Data); + ContextOffset64 = (UINT64 *)((UINTN)Context + PropertyData64List[Index].Offset); + *ContextOffset64 = Fdt64ToCpu (*Data64); + } + + return EFI_SUCCESS; +} + +/** + Parse the FIT image info. + @param[in] ImageBase Memory address of an image. + @param[out] Context The FIT image context pointer. + @retval EFI_UNSUPPORTED Unsupported binary type. + @retval EFI_SUCCESS FIT binary is loaded successfully. +**/ +EFI_STATUS +EFIAPI +ParseFitImage ( + IN VOID *ImageBase, + OUT FIT_IMAGE_CONTEXT *Context + ) +{ + VOID *Fdt; + INT32 ConfigNode; + INT32 Config1Node; + CONST FDT_PROPERTY *PropertyPtr; + INT32 TempLen; + UINT32 *Data32; + UINT64 Value; + EFI_STATUS Status; + UINTN UplSize; + CHAR8 *Firmware; + + Status = FdtCheckHeader (ImageBase); + if (EFI_ERROR (Status)) { + return EFI_UNSUPPORTED; + } + + Fdt = ImageBase; + PropertyPtr = FdtGetProperty (Fdt, 0, "size", &TempLen); + Data32 = (UINT32 *)(PropertyPtr->Data); + UplSize = Value = Fdt32ToCpu (*Data32); + ConfigNode = FdtSubnodeOffsetNameLen (Fdt, 0, "configurations", (INT32)AsciiStrLen ("configurations")); + if (ConfigNode <= 0) { + return EFI_NOT_FOUND; + } + + Config1Node = FdtSubnodeOffsetNameLen (Fdt, ConfigNode, "conf-1", (INT32)AsciiStrLen ("conf-1")); + if (Config1Node <= 0) { + return EFI_NOT_FOUND; + } + + PropertyPtr = FdtGetProperty (Fdt, Config1Node, "firmware", &TempLen); + Firmware = (CHAR8 *)(PropertyPtr->Data); + + FitParseFirmwarePropertyData (Fdt, Firmware, Context); + + Context->ImageBase = (EFI_PHYSICAL_ADDRESS)ImageBase; + Context->PayloadSize = UplSize; + Context->RelocateTableCount = (Context->PayloadEntrySize - (Context->RelocateTableOffset - Context->PayloadEntryOffset)) / sizeof (FIT_RELOCATE_ITEM); + + return EFI_SUCCESS; +} diff --git a/UefiPayloadPkg/PayloadLoaderPeim/FitPayloadLoaderPeim.c b/UefiPayloadPkg/PayloadLoaderPeim/FitPayloadLoaderPeim.c new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/UefiPayloadPkg/PayloadLoaderPeim/FitPayloadLoaderPeim.c @@ -XXX,XX +XXX,XX @@ +/** @file + ELF Load Image Support +Copyright (c) 2021, Intel Corporation. All rights reserved.<BR> +SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include <PiPei.h> +#include <UniversalPayload/UniversalPayload.h> +#include <UniversalPayload/ExtraData.h> + +#include <Ppi/LoadFile.h> + +#include <Library/DebugLib.h> +#include <Library/HobLib.h> +#include <Library/PeiServicesLib.h> +#include <Library/MemoryAllocationLib.h> +#include <Library/BaseMemoryLib.h> + +#include "FitLib.h" + +/** + The wrapper function of PeiLoadImageLoadImage(). + @param This - Pointer to EFI_PEI_LOAD_FILE_PPI. + @param FileHandle - Pointer to the FFS file header of the image. + @param ImageAddressArg - Pointer to PE/TE image. + @param ImageSizeArg - Size of PE/TE image. + @param EntryPoint - Pointer to entry point of specified image file for output. + @param AuthenticationState - Pointer to attestation authentication state of image. + @return Status of PeiLoadImageLoadImage(). +**/ +EFI_STATUS +EFIAPI +PeiLoadFileLoadPayload ( + IN CONST EFI_PEI_LOAD_FILE_PPI *This, + IN EFI_PEI_FILE_HANDLE FileHandle, + OUT EFI_PHYSICAL_ADDRESS *ImageAddressArg OPTIONAL, + OUT UINT64 *ImageSizeArg OPTIONAL, + OUT EFI_PHYSICAL_ADDRESS *EntryPoint, + OUT UINT32 *AuthenticationState + ) +{ + EFI_STATUS Status; + FIT_IMAGE_CONTEXT Context; + UINTN Instance; + VOID *Binary; + FIT_RELOCATE_ITEM *RelocateTable; + UNIVERSAL_PAYLOAD_BASE *PayloadBase; + UINTN Length; + UINTN Delta; + UINTN Index; + + Instance = 0; + do { + Status = PeiServicesFfsFindSectionData3 (EFI_SECTION_RAW, Instance++, FileHandle, &Binary, AuthenticationState); + if (EFI_ERROR (Status)) { + return Status; + } + + ZeroMem (&Context, sizeof (Context)); + Status = ParseFitImage (Binary, &Context); + } while (EFI_ERROR (Status)); + + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + + DEBUG (( + DEBUG_INFO, + "Before Rebase Payload File Base: 0x%08x, File Size: 0x%08X, EntryPoint: 0x%08x\n", + Context.PayloadBaseAddress, + Context.PayloadSize, + Context.PayloadEntryPoint + )); + Context.PayloadBaseAddress = (EFI_PHYSICAL_ADDRESS)AllocatePages (EFI_SIZE_TO_PAGES (Context.PayloadSize)); + + RelocateTable = (FIT_RELOCATE_ITEM *)(UINTN)(Context.PayloadBaseAddress + Context.RelocateTableOffset); + CopyMem ((VOID *)Context.PayloadBaseAddress, Binary, Context.PayloadSize); + + if (Context.PayloadBaseAddress > Context.PayloadLoadAddress) { + Delta = Context.PayloadBaseAddress - Context.PayloadLoadAddress; + Context.PayloadEntryPoint += Delta; + for (Index = 0; Index < Context.RelocateTableCount; Index++) { + if ((RelocateTable[Index].RelocateType == 10) || (RelocateTable[Index].RelocateType == 3)) { + *((UINT64 *)(Context.PayloadBaseAddress + RelocateTable[Index].Offset)) = *((UINT64 *)(Context.PayloadBaseAddress + RelocateTable[Index].Offset)) + Delta; + } + } + } else { + Delta = Context.PayloadLoadAddress - Context.PayloadBaseAddress; + Context.PayloadEntryPoint -= Delta; + for (Index = 0; Index < Context.RelocateTableCount; Index++) { + if ((RelocateTable[Index].RelocateType == 10) || (RelocateTable[Index].RelocateType == 3)) { + *((UINT64 *)(Context.PayloadBaseAddress + RelocateTable[Index].Offset)) = *((UINT64 *)(Context.PayloadBaseAddress + RelocateTable[Index].Offset)) - Delta; + } + } + } + + DEBUG (( + DEBUG_INFO, + "After Rebase Payload File Base: 0x%08x, File Size: 0x%08X, EntryPoint: 0x%08x\n", + Context.PayloadBaseAddress, + Context.PayloadSize, + Context.PayloadEntryPoint + )); + + Length = sizeof (UNIVERSAL_PAYLOAD_BASE); + PayloadBase = BuildGuidHob ( + &gUniversalPayloadBaseGuid, + Length + ); + PayloadBase->Entry = (EFI_PHYSICAL_ADDRESS)Context.ImageBase; + + *ImageAddressArg = Context.PayloadBaseAddress; + *ImageSizeArg = Context.PayloadSize; + *EntryPoint = Context.PayloadEntryPoint; + + return EFI_SUCCESS; +} + +EFI_PEI_LOAD_FILE_PPI mPeiLoadFilePpi = { + PeiLoadFileLoadPayload +}; + +EFI_PEI_PPI_DESCRIPTOR gPpiLoadFilePpiList = { + (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST), + &gEfiPeiLoadFilePpiGuid, + &mPeiLoadFilePpi +}; + +/** + Install Pei Load File PPI. + @param FileHandle Handle of the file being invoked. + @param PeiServices Describes the list of possible PEI Services. + @retval EFI_SUCESS The entry point executes successfully. + @retval Others Some error occurs during the execution of this function. +**/ +EFI_STATUS +EFIAPI +InitializeFitPayloadLoaderPeim ( + IN EFI_PEI_FILE_HANDLE FileHandle, + IN CONST EFI_PEI_SERVICES **PeiServices + ) +{ + EFI_STATUS Status; + + Status = PeiServicesInstallPpi (&gPpiLoadFilePpiList); + + return Status; +} diff --git a/UefiPayloadPkg/PayloadLoaderPeim/FitPayloadLoaderPeim.inf b/UefiPayloadPkg/PayloadLoaderPeim/FitPayloadLoaderPeim.inf new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/UefiPayloadPkg/PayloadLoaderPeim/FitPayloadLoaderPeim.inf @@ -XXX,XX +XXX,XX @@ +## @file +# Produce LoadFile PPI for payload loading. +# +# Copyright (c) 2021, Intel Corporation. All rights reserved.<BR> +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = FitPayloadLoaderPeim + FILE_GUID = 55AC82C8-FC17-4C56-BCDA-990BB0A73E41 + MODULE_TYPE = PEIM + VERSION_STRING = 1.0 + + ENTRY_POINT = InitializeFitPayloadLoaderPeim + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 +# + +[Sources] + FitPayloadLoaderPeim.c + FitLib.h + FitLib/FitLib.c + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + PcAtChipsetPkg/PcAtChipsetPkg.dec + UefiPayloadPkg/UefiPayloadPkg.dec + +[LibraryClasses] + PcdLib + MemoryAllocationLib + BaseMemoryLib + PeiServicesLib + HobLib + BaseLib + PeimEntryPoint + DebugLib + FdtLib + +[Ppis] + gEfiPeiLoadFilePpiGuid ## PRODUCES + +[Pcd] + gPcAtChipsetPkgTokenSpaceGuid.PcdRtcIndexRegister + gPcAtChipsetPkgTokenSpaceGuid.PcdRtcTargetRegister + +[Guids] + gUniversalPayloadExtraDataGuid ## PRODUCES + gUniversalPayloadBaseGuid ## PRODUCES + +[Depex] + TRUE diff --git a/UefiPayloadPkg/Readme.md b/UefiPayloadPkg/Readme.md new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/UefiPayloadPkg/Readme.md @@ -XXX,XX +XXX,XX @@ +# UefiPayloadPkg +Provide UEFI Universal Payload for different bootloader to generate EFI environment + +# Spec +URL: https://docs.google.com/document/d/1WxEUlCsXpc17DkJhL3XVkOW7e_KIt_zcc9tQ1trOySg/ + +# Uefi UniversalPayload Format + | SpecRevision | Binary Format | HandOffPayload - HOB | HandOffPayload - 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.<afpx>_fv | patch by llvm-objcopy + + +-----------------------+ + ``` + + - SpecRevision - 0.9 + ``` + + +-----------------------+ + | | UniversalPayloadEntry | <----------- UefiPayloadPkg\UefiPayloadEntry\UniversalPayloadEntry.c:_ModuleEntryPoint (HOB[Default] or FDT) + | +-----------------------+ + | | .upld_info | patch by llvm-objcopy + ELF Format | +-----------------------+ + | | .upld.uefi_fv | patch by llvm-objcopy + | +-----------------------+ + | | .upld.bds_fv | patch by llvm-objcopy + | +-----------------------+ + | | .upld.<afpx>_fv | patch by llvm-objcopy + + +-----------------------+ + ``` + + - SpecRevision - 1.0 + ``` + + +-----------------------+ + FIT Data | | FIT Header | <----------- Generate by pylibfdt + + +-----------------------+ + 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.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; iex ((New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1')) + choco install dtc-msys2 + pip3 install pefile + pip3 install swig + pip3 install pylibfdt + ``` + - Ubuntu + ```bash + sudo apt install -y u-boot-tools + pip3 install pefile + pip3 install swig + pip3 install pylibfdt + ``` +# How to build UEFI UniversalPayload + - Windows + - edksetup Rebuild + - Linux + - make -C BaseTools + - source edksetup.sh + + - SpecRevision - 0.7 + - python UefiPayloadPkg/UniversalPayloadBuild.py -t <TOOL_CHAIN_TAG> -s 0.7 + - llvm-objdump -h Build/UefiPayloadPkgX64/UniversalPayload.elf + - SpecRevision - 0.9 + - python UefiPayloadPkg/UniversalPayloadBuild.py -t <TOOL_CHAIN_TAG> -s 0.9 + - llvm-objdump -h Build/UefiPayloadPkgX64/UniversalPayload.elf + - SpecRevision - 1.0 + - python UefiPayloadPkg/UniversalPayloadBuild.py -t <TOOL_CHAIN_TAG> -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\PayloadLoaderPeim.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\PayloadLoaderPeim.c ----------------------------------------------> Load UniversalPayload.fit -> Operation System + + Binary Format + + | Platform Initialize - Edk2 | UniversalPayload - Edk2 (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="universal-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-start | + | | +--------------------------------+ +--------------------------------+ +--------------------------------+ + | | | AFPn-fv -> data | | uefi-fv -> data | + +-------------------+<----------------+--------------------------------+ +--------------------------------+ + | ... | | bds-fv -> data | + +-------------------+ +--------------------------------+ + | Other Firmware | | AFP1-fv -> data | + +-------------------+ +--------------------------------+ + | AFP2-fv -> data | + +--------------------------------+ + | ... | + +--------------------------------+ + | AFPn-fv -> data | + +--------------------------------+ + + ``` diff --git a/UefiPayloadPkg/Tools/MkFitImage.py b/UefiPayloadPkg/Tools/MkFitImage.py new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/UefiPayloadPkg/Tools/MkFitImage.py @@ -XXX,XX +XXX,XX @@ +## @file +# This file is a script to build fit image. +# It generate a dtb header and combine a binary file after this header. +# +# Copyright (c) 2023, Intel Corporation. All rights reserved.<BR> +# SPDX-License-Identifier: BSD-2-Clause-Patent +## + +from os.path import exists +import libfdt +from ctypes import * +import time + +class FIT_IMAGE_INFO_HEADER: + """Class for user setting data to use MakeFitImage() + """ + _pack_ = 1 + _fields_ = [ + ('Compatible', str), + ('UplVersion', int), + ('Description', str), + ('Type', str), + ('Arch', str), + ('Compression', str), + ('Revision', int), + ('BuildType', str), + ('Capabilities', str), + ('Producer', str), + ('ImageId', str), + ('DataOffset', int), + ('DataSize', int), + ('RelocStart', int), + ('LoadAddr', int), + ('Entry', int), + ('Binary', str), + ('TargetPath', str), + ('UefifvPath', str), + ('BdsfvPath', str), + ('NetworkfvPath', str), + ('Project', str), + ] + + def __init__(self): + self.Compatible = 'universal-payload' + self.UplVersion = 0x0100 + self.TargetPath = 'mkimage.fit' + +def CreatFdt(Fdt): + FdtEmptyTree = libfdt.fdt_create_empty_tree(Fdt, len(Fdt)) + if FdtEmptyTree != 0: + print('\n- Failed - Create Fdt failed!') + return False + return True + +def BuildConfNode(Fdt, ParentNode, MultiImage): + ConfNode1 = libfdt.fdt_add_subnode(Fdt, ParentNode, 'conf-1') + + libfdt.fdt_setprop(Fdt, ConfNode1, 'firmware', bytes('tianocore', 'utf-8'), len('tianocore') + 1) + +def BuildFvImageNode(Fdt, InfoHeader, ParentNode, DataOffset, DataSize, Description): + libfdt.fdt_setprop_u32(Fdt, ParentNode, 'data-size', DataSize) + libfdt.fdt_setprop_u32(Fdt, ParentNode, 'data-offset', DataOffset) + libfdt.fdt_setprop(Fdt, ParentNode, 'compression', bytes('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 target binary file. + # + if InfoHeader.LoadAddr is not None: + libfdt.fdt_setprop_u64(Fdt, ParentNode, 'load', InfoHeader.LoadAddr) + if InfoHeader.Entry is not None: + libfdt.fdt_setprop_u64(Fdt, ParentNode, 'entry-start', InfoHeader.Entry) + if InfoHeader.RelocStart is not None: + libfdt.fdt_setprop_u32(Fdt, ParentNode, 'reloc-start', InfoHeader.RelocStart) + if InfoHeader.DataSize is not None: + libfdt.fdt_setprop_u32(Fdt, ParentNode, 'data-size', DataSize) + if InfoHeader.DataOffset is not None: + libfdt.fdt_setprop_u32(Fdt, ParentNode, 'data-offset', DataOffset) + if InfoHeader.Producer is not None: + libfdt.fdt_setprop(Fdt, ParentNode, 'producer ', bytes(InfoHeader.Producer, 'utf-8'), len(InfoHeader.Producer) + 1) + if InfoHeader.Capabilities is not None: + CapStrs = ','.join(InfoHeader.Capabilities) + libfdt.fdt_setprop(Fdt, ParentNode, 'capabilities ', bytes(CapStrs, 'utf-8'), len(CapStrs) + 1) + if InfoHeader.Type is not None: + libfdt.fdt_setprop(Fdt, ParentNode, 'type ', bytes(InfoHeader.Type, 'utf-8'), len(InfoHeader.Type) + 1) + if InfoHeader.Arch is not None: + libfdt.fdt_setprop(Fdt, ParentNode, 'arch ', bytes(InfoHeader.Arch, 'utf-8'), len(InfoHeader.Arch) + 1) + if InfoHeader.Project is not None: + libfdt.fdt_setprop(Fdt, ParentNode, 'project ', bytes(InfoHeader.Project, 'utf-8'), len(InfoHeader.Project) + 1) + if InfoHeader.Description is not None: + libfdt.fdt_setprop(Fdt, ParentNode, 'description', bytes(Description, 'utf-8'), len(Description) + 1) + +# +# The subnode would be inserted from bottom to top of structure block. +# +def BuildFitImage(Fdt, InfoHeader): + MultiImage = [ + ["tianocore", InfoHeader.Binary, BuildTianoImageNode , InfoHeader.Description, None, 0 ], + ["uefi-fv", InfoHeader.UefifvPath, BuildFvImageNode, "UEFI Firmware Volume", None, 0 ], + ["bds-fv", InfoHeader.BdsfvPath, BuildFvImageNode , "BDS Firmware Volume", None, 0 ], + ["network-fv", InfoHeader.NetworkfvPath, BuildFvImageNode , "Network Firmware Volume", None, 0 ], + ] + + # + # Set basic information + # + libfdt.fdt_setprop_u32(Fdt, 0, 'build-revision ', InfoHeader.Revision) + libfdt.fdt_setprop_u32(Fdt, 0, 'spec-version', InfoHeader.UplVersion) + + # + # Build configurations node + # + ConfNode = libfdt.fdt_add_subnode(Fdt, 0, 'configurations') + BuildConfNode(Fdt, ConfNode, MultiImage) + + # Build image + DataOffset = InfoHeader.DataOffset + for Index in range (0, len (MultiImage)): + _, Path, _, _, _, _ = MultiImage[Index] + if exists(Path) == 1: + TempBinary = open(Path, 'rb') + BinaryData = TempBinary.read() + TempBinary.close() + MultiImage[Index][-2] = BinaryData + MultiImage[Index][-1] = DataOffset + DataOffset += len (BinaryData) + libfdt.fdt_setprop_u32(Fdt, 0, 'size', DataOffset) + posix_time = int(time.time()) + libfdt.fdt_setprop_u32(Fdt, 0, 'timestamp', posix_time) + DescriptionFit = 'Uefi OS Loader' + libfdt.fdt_setprop(Fdt, 0, 'description', bytes(DescriptionFit, 'utf-8'), len(DescriptionFit) + 1) + + ImageNode = libfdt.fdt_add_subnode(Fdt, 0, 'images') + for Item in reversed (MultiImage): + Name, Path, BuildFvNode, Description, BinaryData, DataOffset = Item + FvNode = libfdt.fdt_add_subnode(Fdt, ImageNode, Name) + BuildFvNode (Fdt, InfoHeader, FvNode, DataOffset, len(BinaryData), Description) + + # + # Create new image file and combine all binary. + # + DtbFile = open(InfoHeader.TargetPath, "wb") + DtbFile.truncate() + DtbFile.write(Fdt) + for Item in MultiImage: + _, _, _, _, BinaryData, _ = Item + DtbFile.write(BinaryData) + DtbFile.close() + + return True + +def MakeFitImage(InfoHeader): + # + # Allocate fdt byte array. + # + Fdt = bytearray(InfoHeader.DataOffset) + + # + # Create fdt empty tree. + # + if CreatFdt(Fdt) is False: + return False + + # + # Parse args to build fit image. + # + return BuildFitImage(Fdt, InfoHeader) + +def ReplaceFv (UplBinary, SectionFvFile, SectionName): + try: + # + # Get Original Multi Fv + # + with open (UplBinary, "rb") as File: + Dtb = File.read () + Fit = libfdt.Fdt (Dtb) + NewFitHeader = bytearray(Dtb[0:Fit.totalsize()]) + FitSize = len(Dtb) + + if int.from_bytes (libfdt.fdt_getprop (NewFitHeader, 0, 'spec-version')[0], 'big') < 0x0100: + raise Exception ("UPL version is too low to support it.") + + LoadablesList = [] + ImagesNode = libfdt.fdt_subnode_offset(NewFitHeader, 0, 'images') + FvNode = libfdt.fdt_subnode_offset(NewFitHeader, ImagesNode, 'uefi-fv') + NodeDepth = libfdt.fdt_node_depth (NewFitHeader, ImagesNode) + node_name = libfdt.fdt_get_name(NewFitHeader, FvNode) + FvNode = libfdt.fdt_next_node(NewFitHeader, FvNode, NodeDepth) + + while node_name[0][-2:] == 'fv': + LoadablesList.append (node_name[0]) + node_name = libfdt.fdt_get_name(NewFitHeader, FvNode[0]) + FvNode = libfdt.fdt_next_node(NewFitHeader, FvNode[0], NodeDepth) + # + # Get current Fit Binary FV data + # + MultiFvList = [] + for Item in LoadablesList: + ImageNode = libfdt.fdt_subnode_offset(NewFitHeader, ImagesNode, Item) + ImageOffset = int.from_bytes (libfdt.fdt_getprop (NewFitHeader, ImageNode, 'data-offset')[0], 'big') + ImageSize = int.from_bytes (libfdt.fdt_getprop (NewFitHeader, ImageNode, 'data-size')[0], 'big') + MultiFvList.append ([Item, Dtb[ImageOffset:ImageOffset + ImageSize]]) + + IsFvExist = False + for Index in range (0, len (MultiFvList)): + if MultiFvList[Index][0] == SectionName: + with open (SectionFvFile, 'rb') as File: + MultiFvList[Index][1] = File.read () + ImageNode = libfdt.fdt_subnode_offset(NewFitHeader, ImagesNode, SectionName) + ImageSize = int.from_bytes (libfdt.fdt_getprop (NewFitHeader, ImageNode, 'data-size')[0], 'big') + ReplaceOffset = int.from_bytes (libfdt.fdt_getprop (NewFitHeader, ImageNode, 'data-offset')[0], 'big') + OffsetDelta = len(MultiFvList[Index][1]) - ImageSize + FitSize += OffsetDelta + IsFvExist = True + libfdt.fdt_setprop_u32(NewFitHeader, ImageNode, 'data-size', len(MultiFvList[Index][1])) + + # + # Update new fit header + # + ImagesNode = libfdt.fdt_subnode_offset(NewFitHeader, 0, 'images') + if (IsFvExist == False): + with open (SectionFvFile, 'rb') as File: + SectionFvFileBinary = File.read () + MultiFvList.append ([SectionName, SectionFvFileBinary]) + FvNode = libfdt.fdt_add_subnode(NewFitHeader, ImagesNode, SectionName) + BuildFvImageNode (NewFitHeader, None, FvNode, FitSize, len(SectionFvFileBinary), SectionName + " Firmware Volume") + FitSize += len(SectionFvFileBinary) + else: + for Index in range (0, len (MultiFvList)): + ImageNode = libfdt.fdt_subnode_offset(NewFitHeader, ImagesNode, MultiFvList[Index][0]) + ImageOffset = int.from_bytes (libfdt.fdt_getprop (NewFitHeader, ImageNode, 'data-offset')[0], 'big') + if ImageOffset > ReplaceOffset: + libfdt.fdt_setprop_u32(NewFitHeader, ImageNode, 'data-offset', ImageOffset + OffsetDelta) + + ConfNodes = libfdt.fdt_subnode_offset(NewFitHeader, 0, 'configurations') + ConfNode = libfdt.fdt_subnode_offset(NewFitHeader, ConfNodes, 'conf-1') + + libfdt.fdt_setprop_u32(NewFitHeader, 0, 'size', FitSize) + + # + # Generate new fit image + # + ImagesNode = libfdt.fdt_subnode_offset(NewFitHeader, 0, 'images') + TianoNode = libfdt.fdt_subnode_offset(NewFitHeader, ImagesNode, 'tianocore') + TianoOffset = int.from_bytes (libfdt.fdt_getprop (NewFitHeader, TianoNode, 'data-offset')[0], 'big') + TianoSize = int.from_bytes (libfdt.fdt_getprop (NewFitHeader, TianoNode, 'data-size')[0], 'big') + TianoBinary = Dtb[TianoOffset:TianoOffset + TianoSize] + + print("\nGenerate new fit image:") + NewUplBinary = bytearray(FitSize) + print("Update fit header\t to 0x0\t\t ~ " + str(hex(len(NewFitHeader)))) + NewUplBinary[:len(NewFitHeader)] = NewFitHeader + print("Update tiano image\t to " + str(hex(len(NewFitHeader))) + "\t ~ " + str(hex(len(NewFitHeader) + len(TianoBinary)))) + NewUplBinary[len(NewFitHeader):len(NewFitHeader) + len(TianoBinary)] = TianoBinary + for Index in range (0, len (MultiFvList)): + ImageNode = libfdt.fdt_subnode_offset(NewFitHeader, ImagesNode, MultiFvList[Index][0]) + ImageOffset = int.from_bytes (libfdt.fdt_getprop (NewFitHeader, ImageNode, 'data-offset')[0], 'big') + ImageSize = int.from_bytes (libfdt.fdt_getprop (NewFitHeader, ImageNode, 'data-size')[0], 'big') + NewUplBinary[ImageOffset:ImageOffset + ImageSize] = MultiFvList[Index][1] + print("Update " + MultiFvList[Index][0] + "\t\t to " + str(hex(ImageOffset)) + "\t ~ " + str(hex(ImageOffset + ImageSize))) + + with open (UplBinary, "wb") as File: + File.write (NewUplBinary) + + return 0 + except Exception as Ex: + print(Ex) + return 1 diff --git a/UefiPayloadPkg/UefiPayloadEntry/FitUniversalPayloadEntry.c b/UefiPayloadPkg/UefiPayloadEntry/FitUniversalPayloadEntry.c new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/UefiPayloadPkg/UefiPayloadEntry/FitUniversalPayloadEntry.c @@ -XXX,XX +XXX,XX @@ +/** @file + Copyright (c) 2021, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include "UefiPayloadEntry.h" +#include <Library/FdtLib.h> + +#define MEMORY_ATTRIBUTE_MASK (EFI_RESOURCE_ATTRIBUTE_PRESENT | \ + EFI_RESOURCE_ATTRIBUTE_INITIALIZED | \ + EFI_RESOURCE_ATTRIBUTE_TESTED | \ + EFI_RESOURCE_ATTRIBUTE_READ_PROTECTED | \ + EFI_RESOURCE_ATTRIBUTE_WRITE_PROTECTED | \ + EFI_RESOURCE_ATTRIBUTE_EXECUTION_PROTECTED | \ + EFI_RESOURCE_ATTRIBUTE_READ_ONLY_PROTECTED | \ + EFI_RESOURCE_ATTRIBUTE_16_BIT_IO | \ + EFI_RESOURCE_ATTRIBUTE_32_BIT_IO | \ + EFI_RESOURCE_ATTRIBUTE_64_BIT_IO | \ + EFI_RESOURCE_ATTRIBUTE_PERSISTENT ) + +#define TESTED_MEMORY_ATTRIBUTES (EFI_RESOURCE_ATTRIBUTE_PRESENT | \ + EFI_RESOURCE_ATTRIBUTE_INITIALIZED | \ + EFI_RESOURCE_ATTRIBUTE_TESTED ) + +extern VOID *mHobList; + +CHAR8 *mLineBuffer = NULL; + +/** + Print all HOBs info from the HOB list. + @return The pointer to the HOB list. +**/ +VOID +PrintHob ( + IN CONST VOID *HobStart + ); + +/** + Find the first substring. + @param String Point to the string where to find the substring. + @param CharSet Point to the string to be found. +**/ +UINTN +EFIAPI +AsciiStrSpn ( + IN CHAR8 *String, + IN CHAR8 *CharSet + ) +{ + UINTN Count; + CHAR8 *Str1; + CHAR8 *Str2; + + Count = 0; + + for (Str1 = String; *Str1 != L'\0'; Str1++) { + for (Str2 = CharSet; *Str2 != L'\0'; Str2++) { + if (*Str1 == *Str2) { + break; + } + } + + if (*Str2 == L'\0') { + return Count; + } + + Count++; + } + + return Count; +} + +/** + Searches a string for the first occurrence of a character contained in a + specified buffer. + @param String Point to the string where to find the substring. + @param CharSet Point to the string to be found. +**/ +CHAR8 * +EFIAPI +AsciiStrBrk ( + IN CHAR8 *String, + IN CHAR8 *CharSet + ) +{ + CHAR8 *Str1; + CHAR8 *Str2; + + for (Str1 = String; *Str1 != L'\0'; Str1++) { + for (Str2 = CharSet; *Str2 != L'\0'; Str2++) { + if (*Str1 == *Str2) { + return (CHAR8 *)Str1; + } + } + } + + return NULL; +} + +/** + Find the next token after one or more specified characters. + @param String Point to the string where to find the substring. + @param CharSet Point to the string to be found. +**/ +CHAR8 * +EFIAPI +AsciiStrTokenLine ( + IN CHAR8 *String OPTIONAL, + IN CHAR8 *CharSet + ) +{ + CHAR8 *Begin; + CHAR8 *End; + + Begin = (String == NULL) ? mLineBuffer : String; + if (Begin == NULL) { + return NULL; + } + + Begin += AsciiStrSpn (Begin, CharSet); + if (*Begin == L'\0') { + mLineBuffer = NULL; + return NULL; + } + + End = AsciiStrBrk (Begin, CharSet); + if ((End != NULL) && (*End != L'\0')) { + *End = L'\0'; + End++; + } + + mLineBuffer = End; + return Begin; +} + +/** + Some bootloader may pass a pcd database, and UPL also contain a PCD database. + Dxe PCD driver has the assumption that the two PCD database can be catenated and + the local token number should be successive. + This function will fix up the UPL PCD database to meet that assumption. + @param[in] DxeFv The FV where to find the Universal PCD database. + @retval EFI_SUCCESS If it completed successfully. + @retval other Failed to fix up. +**/ +EFI_STATUS +FixUpPcdDatabase ( + IN EFI_FIRMWARE_VOLUME_HEADER *DxeFv + ) +{ + EFI_STATUS Status; + EFI_FFS_FILE_HEADER *FileHeader; + VOID *PcdRawData; + PEI_PCD_DATABASE *PeiDatabase; + PEI_PCD_DATABASE *UplDatabase; + EFI_HOB_GUID_TYPE *GuidHob; + DYNAMICEX_MAPPING *ExMapTable; + UINTN Index; + + GuidHob = GetFirstGuidHob (&gPcdDataBaseHobGuid); + if (GuidHob == NULL) { + // + // No fix-up is needed. + // + return EFI_SUCCESS; + } + + PeiDatabase = (PEI_PCD_DATABASE *)GET_GUID_HOB_DATA (GuidHob); + DEBUG ((DEBUG_INFO, "Find the Pei PCD data base, the total local token number is %d\n", PeiDatabase->LocalTokenCount)); + + Status = FvFindFileByTypeGuid (DxeFv, EFI_FV_FILETYPE_DRIVER, PcdGetPtr (PcdPcdDriverFile), &FileHeader); + ASSERT_EFI_ERROR (Status); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = FileFindSection (FileHeader, EFI_SECTION_RAW, &PcdRawData); + ASSERT_EFI_ERROR (Status); + if (EFI_ERROR (Status)) { + return Status; + } + + UplDatabase = (PEI_PCD_DATABASE *)PcdRawData; + ExMapTable = (DYNAMICEX_MAPPING *)(UINTN)((UINTN)PcdRawData + UplDatabase->ExMapTableOffset); + + for (Index = 0; Index < UplDatabase->ExTokenCount; Index++) { + ExMapTable[Index].TokenNumber += PeiDatabase->LocalTokenCount; + } + + DEBUG ((DEBUG_INFO, "Fix up UPL PCD database successfully\n")); + return EFI_SUCCESS; +} + +/** + Add HOB into HOB list + @param[in] Hob The HOB to be added into the HOB list. +**/ +VOID +AddNewHob ( + IN EFI_PEI_HOB_POINTERS *Hob + ) +{ + EFI_PEI_HOB_POINTERS NewHob; + + if (Hob->Raw == NULL) { + return; + } + + NewHob.Header = CreateHob (Hob->Header->HobType, Hob->Header->HobLength); + + if (NewHob.Header != NULL) { + CopyMem (NewHob.Header + 1, Hob->Header + 1, Hob->Header->HobLength - sizeof (EFI_HOB_GENERIC_HEADER)); + } +} + +/** + Found the Resource Descriptor HOB that contains a range (Base, Top) + @param[in] HobList Hob start address + @param[in] Base Memory start address + @param[in] Top Memory end address. + @retval The pointer to the Resource Descriptor HOB. +**/ +EFI_HOB_RESOURCE_DESCRIPTOR * +FindResourceDescriptorByRange ( + IN VOID *HobList, + IN EFI_PHYSICAL_ADDRESS Base, + IN EFI_PHYSICAL_ADDRESS Top + ) +{ + EFI_PEI_HOB_POINTERS Hob; + EFI_HOB_RESOURCE_DESCRIPTOR *ResourceHob; + + for (Hob.Raw = (UINT8 *)HobList; !END_OF_HOB_LIST (Hob); Hob.Raw = GET_NEXT_HOB (Hob)) { + // + // Skip all HOBs except Resource Descriptor HOBs + // + if (GET_HOB_TYPE (Hob) != EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) { + continue; + } + + // + // Skip Resource Descriptor HOBs that do not describe tested system memory + // + ResourceHob = Hob.ResourceDescriptor; + if (ResourceHob->ResourceType != EFI_RESOURCE_SYSTEM_MEMORY) { + continue; + } + + if ((ResourceHob->ResourceAttribute & MEMORY_ATTRIBUTE_MASK) != TESTED_MEMORY_ATTRIBUTES) { + continue; + } + + // + // Skip Resource Descriptor HOBs that do not contain the PHIT range EfiFreeMemoryBottom..EfiFreeMemoryTop + // + if (Base < ResourceHob->PhysicalStart) { + continue; + } + + if (Top > (ResourceHob->PhysicalStart + ResourceHob->ResourceLength)) { + continue; + } + + return ResourceHob; + } + + return NULL; +} + +/** + Find the highest below 4G memory resource descriptor, except the input Resource Descriptor. + @param[in] HobList Hob start address + @param[in] MinimalNeededSize Minimal needed size. + @param[in] ExceptResourceHob Ignore this Resource Descriptor. + @retval The pointer to the Resource Descriptor HOB. +**/ +EFI_HOB_RESOURCE_DESCRIPTOR * +FindAnotherHighestBelow4GResourceDescriptor ( + IN VOID *HobList, + IN UINTN MinimalNeededSize, + IN EFI_HOB_RESOURCE_DESCRIPTOR *ExceptResourceHob + ) +{ + EFI_PEI_HOB_POINTERS Hob; + EFI_HOB_RESOURCE_DESCRIPTOR *ResourceHob; + EFI_HOB_RESOURCE_DESCRIPTOR *ReturnResourceHob; + + ReturnResourceHob = NULL; + + for (Hob.Raw = (UINT8 *)HobList; !END_OF_HOB_LIST (Hob); Hob.Raw = GET_NEXT_HOB (Hob)) { + // + // Skip all HOBs except Resource Descriptor HOBs + // + if (GET_HOB_TYPE (Hob) != EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) { + continue; + } + + // + // Skip Resource Descriptor HOBs that do not describe tested system memory + // + ResourceHob = Hob.ResourceDescriptor; + if (ResourceHob->ResourceType != EFI_RESOURCE_SYSTEM_MEMORY) { + continue; + } + + if ((ResourceHob->ResourceAttribute & MEMORY_ATTRIBUTE_MASK) != TESTED_MEMORY_ATTRIBUTES) { + continue; + } + + // + // Skip if the Resource Descriptor HOB equals to ExceptResourceHob + // + if (ResourceHob == ExceptResourceHob) { + continue; + } + + // + // Skip Resource Descriptor HOBs that are beyond 4G + // + if ((ResourceHob->PhysicalStart + ResourceHob->ResourceLength) > BASE_4GB) { + continue; + } + + // + // Skip Resource Descriptor HOBs that are too small + // + if (ResourceHob->ResourceLength < MinimalNeededSize) { + continue; + } + + // + // Return the topest Resource Descriptor + // + if (ReturnResourceHob == NULL) { + ReturnResourceHob = ResourceHob; + } else { + if (ReturnResourceHob->PhysicalStart < ResourceHob->PhysicalStart) { + ReturnResourceHob = ResourceHob; + } + } + } + + return ReturnResourceHob; +} + +/** + Check the HOB and decide if it is need inside Payload + Payload maintainer may make decision which HOB is need or needn't + Then add the check logic in the function. + @param[in] Hob The HOB to check + @retval TRUE If HOB is need inside Payload + @retval FALSE If HOB is needn't inside Payload +**/ +BOOLEAN +IsHobNeed ( + EFI_PEI_HOB_POINTERS Hob + ) +{ + if (Hob.Header->HobType == EFI_HOB_TYPE_HANDOFF) { + return FALSE; + } + + if (Hob.Header->HobType == EFI_HOB_TYPE_MEMORY_ALLOCATION) { + if (CompareGuid (&Hob.MemoryAllocationModule->MemoryAllocationHeader.Name, &gEfiHobMemoryAllocModuleGuid)) { + return FALSE; + } + } + + // Arrive here mean the HOB is need + return TRUE; +} + +/** + It will build Fv HOBs based on information from bootloaders. + @param[out] DxeFv The pointer to the DXE FV in memory. + @retval EFI_SUCCESS If it completed successfully. + @retval EFI_NOT_FOUND If it failed to find node in fit image. + @retval Others If it failed to build required HOBs. +**/ +EFI_STATUS +BuildFitLoadablesFvHob ( + OUT EFI_FIRMWARE_VOLUME_HEADER **DxeFv + ) +{ + EFI_STATUS Status; + VOID *Fdt; + UINT8 *GuidHob; + UNIVERSAL_PAYLOAD_BASE *PayloadBase; + INT32 ConfigNode; + INT32 Config1Node; + INT32 ImageNode; + INT32 FvNode; + INT32 Depth; + CONST FDT_PROPERTY *PropertyPtr; + INT32 TempLen; + CONST CHAR8 *Fvname; + UINT32 DataOffset; + UINT32 DataSize; + UINT32 *Data32; + GuidHob = GetFirstGuidHob (&gUniversalPayloadBaseGuid); + if (GuidHob != NULL) { + PayloadBase = (UNIVERSAL_PAYLOAD_BASE *)GET_GUID_HOB_DATA (GuidHob); + Fdt = (VOID *)(UINTN)PayloadBase->Entry; + DEBUG ((DEBUG_INFO, "PayloadBase Entry = 0x%08x\n", PayloadBase->Entry)); + } + + Status = FdtCheckHeader (Fdt); + if (EFI_ERROR (Status)) { + return EFI_UNSUPPORTED; + } + + ConfigNode = FdtSubnodeOffsetNameLen (Fdt, 0, "configurations", (INT32)AsciiStrLen ("configurations")); + if (ConfigNode <= 0) { + return EFI_NOT_FOUND; + } + + Config1Node = FdtSubnodeOffsetNameLen (Fdt, ConfigNode, "conf-1", (INT32)AsciiStrLen ("conf-1")); + if (Config1Node <= 0) { + return EFI_NOT_FOUND; + } + ImageNode = FdtSubnodeOffsetNameLen (Fdt, 0, "images", (INT32)AsciiStrLen ("images")); + if (ImageNode <= 0) { + return EFI_NOT_FOUND; + } + FvNode = FdtSubnodeOffsetNameLen (Fdt, ImageNode, "tianocore", (INT32)AsciiStrLen ("tianocore")); + Depth = FdtNodeDepth (Fdt, FvNode); + FvNode = FdtNextNode (Fdt, FvNode, &Depth); + Fvname = FdtGetName (Fdt, FvNode, &TempLen); + while ((AsciiStrCmp((Fvname + AsciiStrLen(Fvname) - 2), "fv") == 0)) { + if (FvNode <= 0) { + return EFI_NOT_FOUND; + } + PropertyPtr = FdtGetProperty (Fdt, FvNode, "data-offset", &TempLen); + Data32 = (UINT32 *)(PropertyPtr->Data); + DataOffset = SwapBytes32 (*Data32); + + PropertyPtr = FdtGetProperty (Fdt, FvNode, "data-size", &TempLen); + Data32 = (UINT32 *)(PropertyPtr->Data); + DataSize = SwapBytes32 (*Data32); + + if (AsciiStrCmp (Fvname, "uefi-fv") == 0) { + *DxeFv = (EFI_FIRMWARE_VOLUME_HEADER *)((UINTN)PayloadBase->Entry + (UINTN)DataOffset); + ASSERT ((*DxeFv)->FvLength == DataSize); + } else { + BuildFvHob (((UINTN)PayloadBase->Entry + (UINTN)DataOffset), DataSize); + } + + DEBUG (( + DEBUG_INFO, + "UPL Multiple fv[%a], Base=0x%08x, size=0x%08x\n", + Fvname, + ((UINTN)PayloadBase->Entry + (UINTN)DataOffset), + DataSize, + DataOffset + )); + Depth = FdtNodeDepth (Fdt, FvNode); + FvNode = FdtNextNode (Fdt, FvNode, &Depth); + Fvname = FdtGetName (Fdt, FvNode, &TempLen); + } + return EFI_SUCCESS; +} + +/** + It will build HOBs based on information from bootloaders. + @param[in] BootloaderParameter The starting memory address of bootloader parameter block. + @param[out] DxeFv The pointer to the DXE FV in memory. + @retval EFI_SUCCESS If it completed successfully. + @retval Others If it failed to build required HOBs. +**/ +EFI_STATUS +BuildHobs ( + IN UINTN BootloaderParameter, + OUT EFI_FIRMWARE_VOLUME_HEADER **DxeFv + ) +{ + EFI_PEI_HOB_POINTERS Hob; + UINTN MinimalNeededSize; + EFI_PHYSICAL_ADDRESS FreeMemoryBottom; + EFI_PHYSICAL_ADDRESS FreeMemoryTop; + EFI_PHYSICAL_ADDRESS MemoryBottom; + EFI_PHYSICAL_ADDRESS MemoryTop; + EFI_HOB_RESOURCE_DESCRIPTOR *PhitResourceHob; + EFI_HOB_RESOURCE_DESCRIPTOR *ResourceHob; + UINT8 *GuidHob; + EFI_HOB_FIRMWARE_VOLUME *FvHob; + UNIVERSAL_PAYLOAD_ACPI_TABLE *AcpiTable; + ACPI_BOARD_INFO *AcpiBoardInfo; + EFI_HOB_HANDOFF_INFO_TABLE *HobInfo; + + Hob.Raw = (UINT8 *)BootloaderParameter; + MinimalNeededSize = FixedPcdGet32 (PcdSystemMemoryUefiRegionSize); + + ASSERT (Hob.Raw != NULL); + ASSERT ((UINTN)Hob.HandoffInformationTable->EfiFreeMemoryTop == Hob.HandoffInformationTable->EfiFreeMemoryTop); + ASSERT ((UINTN)Hob.HandoffInformationTable->EfiMemoryTop == Hob.HandoffInformationTable->EfiMemoryTop); + ASSERT ((UINTN)Hob.HandoffInformationTable->EfiFreeMemoryBottom == Hob.HandoffInformationTable->EfiFreeMemoryBottom); + ASSERT ((UINTN)Hob.HandoffInformationTable->EfiMemoryBottom == Hob.HandoffInformationTable->EfiMemoryBottom); + + // + // Try to find Resource Descriptor HOB that contains Hob range EfiMemoryBottom..EfiMemoryTop + // + PhitResourceHob = FindResourceDescriptorByRange (Hob.Raw, Hob.HandoffInformationTable->EfiMemoryBottom, Hob.HandoffInformationTable->EfiMemoryTop); + if (PhitResourceHob == NULL) { + // + // Boot loader's Phit Hob is not in an available Resource Descriptor, find another Resource Descriptor for new Phit Hob + // + ResourceHob = FindAnotherHighestBelow4GResourceDescriptor (Hob.Raw, MinimalNeededSize, NULL); + if (ResourceHob == NULL) { + return EFI_NOT_FOUND; + } + + MemoryBottom = ResourceHob->PhysicalStart + ResourceHob->ResourceLength - MinimalNeededSize; + FreeMemoryBottom = MemoryBottom; + FreeMemoryTop = ResourceHob->PhysicalStart + ResourceHob->ResourceLength; + MemoryTop = FreeMemoryTop; + } else if (PhitResourceHob->PhysicalStart + PhitResourceHob->ResourceLength - Hob.HandoffInformationTable->EfiMemoryTop >= MinimalNeededSize) { + // + // New availiable Memory range in new hob is right above memory top in old hob. + // + MemoryBottom = Hob.HandoffInformationTable->EfiFreeMemoryTop; + FreeMemoryBottom = Hob.HandoffInformationTable->EfiMemoryTop; + FreeMemoryTop = FreeMemoryBottom + MinimalNeededSize; + MemoryTop = FreeMemoryTop; + } else if (Hob.HandoffInformationTable->EfiMemoryBottom - PhitResourceHob->PhysicalStart >= MinimalNeededSize) { + // + // New availiable Memory range in new hob is right below memory bottom in old hob. + // + MemoryBottom = Hob.HandoffInformationTable->EfiMemoryBottom - MinimalNeededSize; + FreeMemoryBottom = MemoryBottom; + FreeMemoryTop = Hob.HandoffInformationTable->EfiMemoryBottom; + MemoryTop = Hob.HandoffInformationTable->EfiMemoryTop; + } else { + // + // In the Resource Descriptor HOB contains boot loader Hob, there is no enough free memory size for payload hob + // Find another Resource Descriptor Hob + // + ResourceHob = FindAnotherHighestBelow4GResourceDescriptor (Hob.Raw, MinimalNeededSize, PhitResourceHob); + if (ResourceHob == NULL) { + return EFI_NOT_FOUND; + } + + MemoryBottom = ResourceHob->PhysicalStart + ResourceHob->ResourceLength - MinimalNeededSize; + FreeMemoryBottom = MemoryBottom; + FreeMemoryTop = ResourceHob->PhysicalStart + ResourceHob->ResourceLength; + MemoryTop = FreeMemoryTop; + } + + HobInfo = HobConstructor ((VOID *)(UINTN)MemoryBottom, (VOID *)(UINTN)MemoryTop, (VOID *)(UINTN)FreeMemoryBottom, (VOID *)(UINTN)FreeMemoryTop); + HobInfo->BootMode = Hob.HandoffInformationTable->BootMode; + // + // From now on, mHobList will point to the new Hob range. + // + + // + // Create an empty FvHob for the DXE FV that contains DXE core. + // + BuildFvHob ((EFI_PHYSICAL_ADDRESS)0, 0); + // + // Since payload created new Hob, move all hobs except PHIT from boot loader hob list. + // + while (!END_OF_HOB_LIST (Hob)) { + if (IsHobNeed (Hob)) { + // Add this hob to payload HOB + AddNewHob (&Hob); + } + + Hob.Raw = GET_NEXT_HOB (Hob); + } + + BuildFitLoadablesFvHob (DxeFv); + + // + // Create guid hob for acpi board information + // + GuidHob = GetFirstGuidHob (&gUniversalPayloadAcpiTableGuid); + if (GuidHob != NULL) { + AcpiTable = (UNIVERSAL_PAYLOAD_ACPI_TABLE *)GET_GUID_HOB_DATA (GuidHob); + GuidHob = GetFirstGuidHob (&gUefiAcpiBoardInfoGuid); + if (GuidHob == NULL) { + AcpiBoardInfo = BuildHobFromAcpi ((UINT64)AcpiTable->Rsdp); + ASSERT (AcpiBoardInfo != NULL); + } + } + + // + // Update DXE FV information to first fv hob in the hob list, which + // is the empty FvHob created before. + // + FvHob = GetFirstHob (EFI_HOB_TYPE_FV); + FvHob->BaseAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)*DxeFv; + FvHob->Length = (*DxeFv)->FvLength; + return EFI_SUCCESS; +} + +/** + Entry point to the C language phase of UEFI payload. + @param[in] BootloaderParameter The starting address of bootloader parameter block. + @retval It will not return if SUCCESS, and return error when passing bootloader parameter. +**/ +EFI_STATUS +EFIAPI +_ModuleEntryPoint ( + IN UINTN BootloaderParameter + ) +{ + EFI_STATUS Status; + PHYSICAL_ADDRESS DxeCoreEntryPoint; + EFI_PEI_HOB_POINTERS Hob; + EFI_FIRMWARE_VOLUME_HEADER *DxeFv; + + mHobList = (VOID *)BootloaderParameter; + DxeFv = NULL; + // Call constructor for all libraries + ProcessLibraryConstructorList (); + + DEBUG ((DEBUG_INFO, "Entering Universal Payload...\n")); + DEBUG ((DEBUG_INFO, "sizeof(UINTN) = 0x%x\n", sizeof (UINTN))); + + DEBUG_CODE ( + // + // Dump the Hobs from boot loader + // + PrintHob (mHobList); + ); + + // Initialize floating point operating environment to be compliant with UEFI spec. + InitializeFloatingPointUnits (); + + // Build HOB based on information from Bootloader + Status = BuildHobs (BootloaderParameter, &DxeFv); + ASSERT_EFI_ERROR (Status); + + FixUpPcdDatabase (DxeFv); + Status = UniversalLoadDxeCore (DxeFv, &DxeCoreEntryPoint); + ASSERT_EFI_ERROR (Status); + + // + // Mask off all legacy 8259 interrupt sources + // + IoWrite8 (LEGACY_8259_MASK_REGISTER_MASTER, 0xFF); + IoWrite8 (LEGACY_8259_MASK_REGISTER_SLAVE, 0xFF); + + Hob.HandoffInformationTable = (EFI_HOB_HANDOFF_INFO_TABLE *)GetFirstHob (EFI_HOB_TYPE_HANDOFF); + HandOffToDxeCore (DxeCoreEntryPoint, Hob); + + // Should not get here + CpuDeadLoop (); + return EFI_SUCCESS; +} diff --git a/UefiPayloadPkg/UefiPayloadEntry/FitUniversalPayloadEntry.inf b/UefiPayloadPkg/UefiPayloadEntry/FitUniversalPayloadEntry.inf new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/UefiPayloadPkg/UefiPayloadEntry/FitUniversalPayloadEntry.inf @@ -XXX,XX +XXX,XX @@ +## @file +# This is the first module for UEFI payload. +# +# Copyright (c) 2021, Intel Corporation. All rights reserved.<BR> +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = FitUniversalPayloadEntry + FILE_GUID = CED5A8A9-B6EA-4D5A-8689-577EE88566CF + MODULE_TYPE = SEC + VERSION_STRING = 1.0 + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 +# + +[Sources] + FitUniversalPayloadEntry.c + LoadDxeCore.c + MemoryAllocation.c + PrintHob.c + AcpiTable.c + +[Sources.Ia32] + X64/VirtualMemory.h + X64/VirtualMemory.c + Ia32/DxeLoadFunc.c + Ia32/IdtVectorAsm.nasm + +[Sources.X64] + X64/VirtualMemory.h + X64/VirtualMemory.c + X64/DxeLoadFunc.c + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + UefiCpuPkg/UefiCpuPkg.dec + UefiPayloadPkg/UefiPayloadPkg.dec + +[LibraryClasses] + BaseMemoryLib + DebugLib + BaseLib + SerialPortLib + IoLib + HobLib + PeCoffLib + CpuLib + FdtLib + +[Guids] + gEfiMemoryTypeInformationGuid + gEfiFirmwareFileSystem2Guid + gEfiGraphicsInfoHobGuid + gEfiGraphicsDeviceInfoHobGuid + gUefiAcpiBoardInfoGuid + gEfiSmbiosTableGuid + gUefiSerialPortInfoGuid + gUniversalPayloadExtraDataGuid + gUniversalPayloadBaseGuid + gPcdDataBaseHobGuid + gUniversalPayloadSmbiosTableGuid + gEfiHobMemoryAllocBspStoreGuid + gUniversalPayloadAcpiTableGuid + gUniversalPayloadPciRootBridgeInfoGuid + gUniversalPayloadSmbios3TableGuid + 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 ## SOMETIMES_CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdDxeNxMemoryProtectionPolicy ## SOMETIMES_CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdImageProtectionPolicy ## SOMETIMES_CONSUMES diff --git a/UefiPayloadPkg/UefiPayloadPkg.dsc b/UefiPayloadPkg/UefiPayloadPkg.dsc index XXXXXXX..XXXXXXX 100644 --- a/UefiPayloadPkg/UefiPayloadPkg.dsc +++ b/UefiPayloadPkg/UefiPayloadPkg.dsc @@ -XXX,XX +XXX,XX @@ DEFINE PS2_KEYBOARD_ENABLE = FALSE DEFINE RAM_DISK_ENABLE = FALSE DEFINE SIO_BUS_ENABLE = FALSE - DEFINE UNIVERSAL_PAYLOAD = FALSE DEFINE SECURITY_STUB_ENABLE = TRUE DEFINE SMM_SUPPORT = FALSE DEFINE PLATFORM_BOOT_TIMEOUT = 3 @@ -XXX,XX +XXX,XX @@ DEFINE BOOTSPLASH_IMAGE = FALSE DEFINE NVME_ENABLE = TRUE DEFINE CAPSULE_SUPPORT = FALSE + # + # Setup Universal Payload + # + DEFINE UNIVERSAL_PAYLOAD = FALSE + DEFINE UNIVERSAL_PAYLOAD_FORMAT = ELF # # NULL: NullMemoryTestDxe @@ -XXX,XX +XXX,XX @@ DEFINE VARIABLE_SUPPORT = EMU DEFINE DISABLE_RESET_SYSTEM = FALSE - DEFINE NETWORK_DRIVER_ENABLE = FALSE + DEFINE NETWORK_DRIVER_ENABLE = TRUE # Dfine the maximum size of the capsule image without a reset flag that the platform can support. DEFINE MAX_SIZE_NON_POPULATE_CAPSULE = 0xa00000 @@ -XXX,XX +XXX,XX @@ VariableFlashInfoLib|MdeModulePkg/Library/BaseVariableFlashInfoLib/BaseVariableFlashInfoLib.inf CcExitLib|UefiCpuPkg/Library/CcExitLibNull/CcExitLibNull.inf ReportStatusCodeLib|MdeModulePkg/Library/DxeReportStatusCodeLib/DxeReportStatusCodeLib.inf - + FdtLib|MdePkg/Library/BaseFdtLib/BaseFdtLib.inf [LibraryClasses.common] !if $(BOOTSPLASH_IMAGE) SafeIntLib|MdePkg/Library/BaseSafeIntLib/BaseSafeIntLib.inf @@ -XXX,XX +XXX,XX @@ !if "IA32" in "$(ARCH)" [Components.IA32] !if $(UNIVERSAL_PAYLOAD) == TRUE - UefiPayloadPkg/UefiPayloadEntry/UniversalPayloadEntry.inf + !if $(UNIVERSAL_PAYLOAD_FORMAT) == "ELF" + UefiPayloadPkg/UefiPayloadEntry/UniversalPayloadEntry.inf + !elseif $(UNIVERSAL_PAYLOAD_FORMAT) == "FIT" + UefiPayloadPkg/UefiPayloadEntry/FitUniversalPayloadEntry.inf + !else + UefiPayloadPkg/UefiPayloadEntry/UefiPayloadEntry.inf + !endif !else UefiPayloadPkg/UefiPayloadEntry/UefiPayloadEntry.inf !endif !else [Components.X64] !if $(UNIVERSAL_PAYLOAD) == TRUE - UefiPayloadPkg/UefiPayloadEntry/UniversalPayloadEntry.inf + !if $(UNIVERSAL_PAYLOAD_FORMAT) == "ELF" + UefiPayloadPkg/UefiPayloadEntry/UniversalPayloadEntry.inf + !elseif $(UNIVERSAL_PAYLOAD_FORMAT) == "FIT" + UefiPayloadPkg/UefiPayloadEntry/FitUniversalPayloadEntry.inf + !else + UefiPayloadPkg/UefiPayloadEntry/UefiPayloadEntry.inf + !endif !else UefiPayloadPkg/UefiPayloadEntry/UefiPayloadEntry.inf !endif diff --git a/UefiPayloadPkg/UniversalPayloadBuild.py b/UefiPayloadPkg/UniversalPayloadBuild.py index XXXXXXX..XXXXXXX 100644 --- a/UefiPayloadPkg/UniversalPayloadBuild.py +++ b/UefiPayloadPkg/UniversalPayloadBuild.py @@ -XXX,XX +XXX,XX @@ import subprocess import os import shutil import sys +import pathlib from ctypes import * -from Tools.ElfFv import ReplaceFv + sys.dont_write_bytecode = True +class bcolors: + HEADER = '\033[95m' + OKBLUE = '\033[94m' + OKCYAN = '\033[96m' + OKGREEN = '\033[92m' + WARNING = '\033[93m' + FAIL = '\033[91m' + ENDC = '\033[0m' + BOLD = '\033[1m' + UNDERLINE = '\033[4m' + class UPLD_INFO_HEADER(LittleEndianStructure): _pack_ = 1 _fields_ = [ @@ -XXX,XX +XXX,XX @@ class UPLD_INFO_HEADER(LittleEndianStructure): self.ImageId = b'UEFI' self.ProducerId = b'INTEL' -def BuildUniversalPayload(Args): - def RunCommand(cmd): - print(cmd) - p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT,cwd=os.environ['WORKSPACE']) - while True: - line = p.stdout.readline() - if not line: - break - print(line.strip().decode(errors='ignore')) - - p.communicate() - if p.returncode != 0: - print("- Failed - error happened when run command: %s"%cmd) - raise Exception("ERROR: when run command: %s"%cmd) +def ValidateSpecRevision (Argument): + try: + (MajorStr, MinorStr) = Argument.split('.') + except: + raise argparse.ArgumentTypeError ('{} is not a valid SpecRevision format (Major[8-bits].Minor[8-bits]).'.format (Argument)) + # + # Spec Revision Bits 15 : 8 - Major Version. Bits 7 : 0 - Minor Version. + # + if len(MinorStr) > 0 and len(MinorStr) < 3: + try: + Minor = int(MinorStr, 16) if len(MinorStr) == 2 else (int(MinorStr, 16) << 4) + except: + raise argparse.ArgumentTypeError ('{} Minor version of SpecRevision is not a valid integer value.'.format (Argument)) + else: + raise argparse.ArgumentTypeError ('{} is not a valid SpecRevision format (Major[8-bits].Minor[8-bits]).'.format (Argument)) + + if len(MajorStr) > 0 and len(MajorStr) < 3: + try: + Major = int(MajorStr, 16) + except: + raise argparse.ArgumentTypeError ('{} Major version of SpecRevision is not a valid integer value.'.format (Argument)) + else: + raise argparse.ArgumentTypeError ('{} is not a valid SpecRevision format (Major[8-bits].Minor[8-bits]).'.format (Argument)) + + return int('0x{0:02x}{1:02x}'.format(Major, Minor), 0) +def Validate32BitInteger (Argument): + try: + Value = int (Argument, 0) + except: + raise argparse.ArgumentTypeError ('{} is not a valid integer value.'.format (Argument)) + if Value < 0: + raise argparse.ArgumentTypeError ('{} is a negative value.'.format (Argument)) + if Value > 0xffffffff: + raise argparse.ArgumentTypeError ('{} is larger than 32-bits.'.format (Argument)) + return Value + +def ValidateAddFv (Argument): + Value = Argument.split ("=") + if len (Value) != 2: + raise argparse.ArgumentTypeError ('{} is incorrect format with "xxx_fv=xxx.fv"'.format (Argument)) + if Value[0][-3:] != "_fv": + raise argparse.ArgumentTypeError ('{} is incorrect format with "xxx_fv=xxx.fv"'.format (Argument)) + if Value[1][-3:].lower () != ".fv": + raise argparse.ArgumentTypeError ('{} is incorrect format with "xxx_fv=xxx.fv"'.format (Argument)) + if os.path.exists (Value[1]) == False: + raise argparse.ArgumentTypeError ('File {} is not found.'.format (Value[1])) + return Value + +def RunCommand(cmd): + print(cmd) + p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT,cwd=os.environ['WORKSPACE']) + while True: + line = p.stdout.readline() + if not line: + break + print(line.strip().decode(errors='ignore')) + + p.communicate() + if p.returncode != 0: + print("- Failed - error happened when run command: %s"%cmd) + raise Exception("ERROR: when run command: %s"%cmd) + +def BuildUniversalPayload(Args): BuildTarget = Args.Target ToolChain = Args.ToolChain Quiet = "--quiet" if Args.Quiet else "" - ElfToolChain = 'CLANGDWARF' + + if Args.PayloadEntryFormat == "pecoff": + PayloadEntryToolChain = ToolChain + Args.Macro.append("UNIVERSAL_PAYLOAD_FORMAT=FIT") + UpldEntryFile = "FitUniversalPayloadEntry" + else: + PayloadEntryToolChain = 'CLANGDWARF' + Args.Macro.append("UNIVERSAL_PAYLOAD_FORMAT=ELF") + UpldEntryFile = "UniversalPayloadEntry" + BuildDir = os.path.join(os.environ['WORKSPACE'], os.path.normpath("Build/UefiPayloadPkgX64")) - BuildModule = "" - BuildArch = "" if Args.Arch == 'X64': BuildArch = "X64" - EntryOutputDir = os.path.join(BuildDir, "{}_{}".format (BuildTarget, ElfToolChain), os.path.normpath("X64/UefiPayloadPkg/UefiPayloadEntry/UniversalPayloadEntry/DEBUG/UniversalPayloadEntry.dll")) + FitArch = "x86_64" + ObjCopyFlag = "elf64-x86-64" + EntryOutputDir = os.path.join(BuildDir, "{}_{}".format (BuildTarget, PayloadEntryToolChain), os.path.normpath("X64/UefiPayloadPkg/UefiPayloadEntry/{}/DEBUG/{}.dll".format (UpldEntryFile, UpldEntryFile))) else: BuildArch = "IA32 -a X64" - EntryOutputDir = os.path.join(BuildDir, "{}_{}".format (BuildTarget, ElfToolChain), os.path.normpath("IA32/UefiPayloadPkg/UefiPayloadEntry/UniversalPayloadEntry/DEBUG/UniversalPayloadEntry.dll")) + FitArch = "x86" + ObjCopyFlag = "elf32-i386" + EntryOutputDir = os.path.join(BuildDir, "{}_{}".format (BuildTarget, PayloadEntryToolChain), os.path.normpath("IA32/UefiPayloadPkg/UefiPayloadEntry/{}/DEBUG/{}.dll".format (UpldEntryFile, UpldEntryFile))) if Args.PreBuildUplBinary is not None: EntryOutputDir = os.path.abspath(Args.PreBuildUplBinary) + EntryModuleInf = os.path.normpath("UefiPayloadPkg/UefiPayloadEntry/{}.inf".format (UpldEntryFile)) DscPath = os.path.normpath("UefiPayloadPkg/UefiPayloadPkg.dsc") + DxeFvOutputDir = os.path.join(BuildDir, "{}_{}".format (BuildTarget, ToolChain), os.path.normpath("FV/DXEFV.Fv")) + BdsFvOutputDir = os.path.join(BuildDir, "{}_{}".format (BuildTarget, ToolChain), os.path.normpath("FV/BDSFV.Fv")) + NetworkFvOutputDir = os.path.join(BuildDir, "{}_{}".format (BuildTarget, ToolChain), os.path.normpath("FV/NETWORKFV.Fv")) + PayloadReportPath = os.path.join(BuildDir, "UefiUniversalPayload.txt") ModuleReportPath = os.path.join(BuildDir, "UefiUniversalPayloadEntry.txt") UpldInfoFile = os.path.join(BuildDir, "UniversalPayloadInfo.bin") + if "CLANG_BIN" in os.environ: + LlvmObjcopyPath = os.path.join(os.environ["CLANG_BIN"], "llvm-objcopy") + else: + LlvmObjcopyPath = "llvm-objcopy" + try: + RunCommand('"%s" --version'%LlvmObjcopyPath) + except: + print("- Failed - Please check if LLVM is installed or if CLANG_BIN is set correctly") + sys.exit(1) + Pcds = "" if (Args.pcd != None): for PcdItem in Args.pcd: @@ -XXX,XX +XXX,XX @@ def BuildUniversalPayload(Args): # Building DXE core and DXE drivers as DXEFV. # if Args.BuildEntryOnly == False: - PayloadReportPath = os.path.join(BuildDir, "UefiUniversalPayload.txt") BuildPayload = "build -p {} -b {} -a X64 -t {} -y {} {}".format (DscPath, BuildTarget, ToolChain, PayloadReportPath, Quiet) BuildPayload += Pcds BuildPayload += Defines @@ -XXX,XX +XXX,XX @@ def BuildUniversalPayload(Args): # Building Universal Payload entry. # if Args.PreBuildUplBinary is None: - EntryModuleInf = os.path.normpath("UefiPayloadPkg/UefiPayloadEntry/UniversalPayloadEntry.inf") - BuildModule = "build -p {} -b {} -a {} -m {} -t {} -y {} {}".format (DscPath, BuildTarget, BuildArch, EntryModuleInf, ElfToolChain, ModuleReportPath, Quiet) + BuildModule = "build -p {} -b {} -a {} -m {} -t {} -y {} {}".format (DscPath, BuildTarget, BuildArch, EntryModuleInf, PayloadEntryToolChain, ModuleReportPath, Quiet) BuildModule += Pcds BuildModule += Defines RunCommand(BuildModule) # # Buid Universal Payload Information Section ".upld_info" # - upld_info_hdr = UPLD_INFO_HEADER() - upld_info_hdr.SpecRevision = Args.SpecRevision - upld_info_hdr.Revision = Args.Revision - upld_info_hdr.ProducerId = Args.ProducerId.encode()[:16] - upld_info_hdr.ImageId = Args.ImageId.encode()[:16] - upld_info_hdr.Attribute |= 1 if BuildTarget == "DEBUG" else 0 - fp = open(UpldInfoFile, 'wb') - fp.write(bytearray(upld_info_hdr)) - fp.close() + if Args.SpecRevision < 0x0100: + upld_info_hdr = UPLD_INFO_HEADER() + upld_info_hdr.SpecRevision = Args.SpecRevision + upld_info_hdr.Revision = Args.Revision + upld_info_hdr.ProducerId = Args.ProducerId.encode()[:16] + upld_info_hdr.ImageId = Args.ImageId.encode()[:16] + upld_info_hdr.Attribute |= 1 if BuildTarget == "DEBUG" else 0 + fp = open(UpldInfoFile, 'wb') + fp.write(bytearray(upld_info_hdr)) + fp.close() + + if Args.BuildEntryOnly == False: + import Tools.ElfFv as ElfFv + ElfFv.ReplaceFv (EntryOutputDir, UpldInfoFile, '.upld_info', Alignment = 4) + shutil.copy (EntryOutputDir, os.path.join(BuildDir, 'UniversalPayload.{}'.format (Args.PayloadEntryFormat))) MultiFvList = [] if Args.BuildEntryOnly == False: MultiFvList = [ - ['uefi_fv', os.path.join(BuildDir, "{}_{}".format (BuildTarget, ToolChain), os.path.normpath("FV/DXEFV.Fv")) ], - ['bds_fv', os.path.join(BuildDir, "{}_{}".format (BuildTarget, ToolChain), os.path.normpath("FV/BDSFV.Fv")) ], - ['network_fv', os.path.join(BuildDir, "{}_{}".format (BuildTarget, ToolChain), os.path.normpath("FV/NETWORKFV.Fv")) ], + ['uefi_fv', os.path.join(BuildDir, "{}_{}".format (BuildTarget, ToolChain), os.path.normpath("FV/DXEFV.Fv")) ], + ['bds_fv', os.path.join(BuildDir, "{}_{}".format (BuildTarget, ToolChain), os.path.normpath("FV/BDSFV.Fv")) ], + ['network_fv', os.path.join(BuildDir, "{}_{}".format (BuildTarget, ToolChain), os.path.normpath("FV/NETWORKFV.Fv"))], ] - AddSectionName = '.upld_info' - ReplaceFv (EntryOutputDir, UpldInfoFile, AddSectionName, Alignment = 4) - shutil.copy (EntryOutputDir, os.path.join(BuildDir, 'UniversalPayload.elf')) - return MultiFvList, os.path.join(BuildDir, 'UniversalPayload.elf') + if Args.SpecRevision >= 0x0100: + import Tools.MkFitImage as MkFitImage + import pefile + fit_image_info_header = MkFitImage.FIT_IMAGE_INFO_HEADER() + fit_image_info_header.Description = 'Uefi Universal Payload' + fit_image_info_header.UplVersion = Args.SpecRevision + fit_image_info_header.Type = 'flat-binary' + fit_image_info_header.Arch = FitArch + fit_image_info_header.Compression = 'none' + fit_image_info_header.Revision = Args.Revision + fit_image_info_header.BuildType = Args.Target.lower() + fit_image_info_header.Capabilities = None + fit_image_info_header.Producer = Args.ProducerId.lower() + fit_image_info_header.ImageId = Args.ImageId.lower() + fit_image_info_header.Binary = os.path.join(BuildDir, 'UniversalPayload.{}'.format (Args.PayloadEntryFormat)) + fit_image_info_header.TargetPath = os.path.join(BuildDir, 'UniversalPayload.fit') + fit_image_info_header.UefifvPath = DxeFvOutputDir + fit_image_info_header.BdsfvPath = BdsFvOutputDir + fit_image_info_header.NetworkfvPath = NetworkFvOutputDir + fit_image_info_header.DataOffset = 0x1000 + fit_image_info_header.LoadAddr = Args.LoadAddress + fit_image_info_header.Project = 'tianocore' + + TargetRebaseFile = fit_image_info_header.Binary.replace (pathlib.Path(fit_image_info_header.Binary).suffix, ".pecoff") + TargetRebaseEntryFile = fit_image_info_header.Binary.replace (pathlib.Path(fit_image_info_header.Binary).suffix, ".entry") + -def main(): - def ValidateSpecRevision (Argument): - try: - (MajorStr, MinorStr) = Argument.split('.') - except: - raise argparse.ArgumentTypeError ('{} is not a valid SpecRevision format (Major[8-bits].Minor[8-bits]).'.format (Argument)) # - # Spec Revision Bits 15 : 8 - Major Version. Bits 7 : 0 - Minor Version. + # Rebase PECOFF to load address # - if len(MinorStr) > 0 and len(MinorStr) < 3: - try: - Minor = int(MinorStr, 16) if len(MinorStr) == 2 else (int(MinorStr, 16) << 4) - except: - raise argparse.ArgumentTypeError ('{} Minor version of SpecRevision is not a valid integer value.'.format (Argument)) - else: - raise argparse.ArgumentTypeError ('{} is not a valid SpecRevision format (Major[8-bits].Minor[8-bits]).'.format (Argument)) + RunCommand ( + "GenFw -e SEC -o {} {}".format ( + TargetRebaseFile, + fit_image_info_header.Binary + )) + RunCommand ( + "GenFw --rebase 0x{:02X} -o {} {} ".format ( + fit_image_info_header.LoadAddr + fit_image_info_header.DataOffset, + TargetRebaseFile, + TargetRebaseFile, + )) - if len(MajorStr) > 0 and len(MajorStr) < 3: - try: - Major = int(MajorStr, 16) - except: - raise argparse.ArgumentTypeError ('{} Major version of SpecRevision is not a valid integer value.'.format (Argument)) - else: - raise argparse.ArgumentTypeError ('{} is not a valid SpecRevision format (Major[8-bits].Minor[8-bits]).'.format (Argument)) + # + # Open PECOFF relocation table binary. + # + RelocBinary = b'' + PeCoff = pefile.PE (TargetRebaseFile) + for reloc in PeCoff.DIRECTORY_ENTRY_BASERELOC: + for entry in reloc.entries: + if (entry.type == 0): + continue + Type = entry.type + Offset = entry.rva + fit_image_info_header.DataOffset + RelocBinary += Type.to_bytes (8, 'little') + Offset.to_bytes (8, 'little') + RelocBinary += b'\x00' * (0x1000 - (len(RelocBinary) % 0x1000)) - return int('0x{0:02x}{1:02x}'.format(Major, Minor), 0) + # + # Output UniversalPayload.entry + # + TempBinary = open (TargetRebaseFile, 'rb') + TianoBinary = TempBinary.read () + TempBinary.close () - def Validate32BitInteger (Argument): - try: - Value = int (Argument, 0) - except: - raise argparse.ArgumentTypeError ('{} is not a valid integer value.'.format (Argument)) - if Value < 0: - raise argparse.ArgumentTypeError ('{} is a negative value.'.format (Argument)) - if Value > 0xffffffff: - raise argparse.ArgumentTypeError ('{} is larger than 32-bits.'.format (Argument)) - return Value - - def ValidateAddFv (Argument): - Value = Argument.split ("=") - if len (Value) != 2: - raise argparse.ArgumentTypeError ('{} is incorrect format with "xxx_fv=xxx.fv"'.format (Argument)) - if Value[0][-3:] != "_fv": - raise argparse.ArgumentTypeError ('{} is incorrect format with "xxx_fv=xxx.fv"'.format (Argument)) - if Value[1][-3:].lower () != ".fv": - raise argparse.ArgumentTypeError ('{} is incorrect format with "xxx_fv=xxx.fv"'.format (Argument)) - if os.path.exists (Value[1]) == False: - raise argparse.ArgumentTypeError ('File {} is not found.'.format (Value[1])) - return Value + TianoEntryBinary = TianoBinary + RelocBinary + TianoEntryBinary += (b'\x00' * (0x1000 - (len(TianoBinary) % 0x1000))) + TianoEntryBinarySize = len (TianoEntryBinary) + TempBinary = open(TargetRebaseEntryFile, "wb") + TempBinary.truncate() + TempBinary.write(TianoEntryBinary) + TempBinary.close() + + # + # Calculate entry and update relocation table start address and data-size. + # + fit_image_info_header.Entry = PeCoff.OPTIONAL_HEADER.ImageBase + PeCoff.OPTIONAL_HEADER.AddressOfEntryPoint + fit_image_info_header.RelocStart = fit_image_info_header.DataOffset + len(TianoBinary) + fit_image_info_header.DataSize = TianoEntryBinarySize + fit_image_info_header.Binary = TargetRebaseEntryFile + + if MkFitImage.MakeFitImage(fit_image_info_header) is True: + print('\nSuccessfully build Fit Image') + else: + sys.exit(1) + Args.PayloadEntryFormat = 'fit' + return MultiFvList, os.path.join(BuildDir, 'UniversalPayload.{}'.format (Args.PayloadEntryFormat)) + +def main(): parser = argparse.ArgumentParser(description='For building Universal Payload') parser.add_argument('-t', '--ToolChain') parser.add_argument('-b', '--Target', default='DEBUG') @@ -XXX,XX +XXX,XX @@ def main(): parser.add_argument("-s", "--SpecRevision", type=ValidateSpecRevision, default ='0.7', help='Indicates compliance with a revision of this specification in the BCD format.') parser.add_argument("-r", "--Revision", type=Validate32BitInteger, default ='0x0000010105', help='Revision of the Payload binary. Major.Minor.Revision.Build') parser.add_argument("-o", "--ProducerId", default ='INTEL', help='A null-terminated OEM-supplied string that identifies the payload producer (16 bytes maximal).') + parser.add_argument("-e", "--BuildEntryOnly", action='store_true', help='Build UniversalPayload Entry file') + parser.add_argument("-pb", "--PreBuildUplBinary", default=None, help='Specify the UniversalPayload file') parser.add_argument("-sk", "--SkipBuild", action='store_true', help='Skip UniversalPayload build') parser.add_argument("-af", "--AddFv", type=ValidateAddFv, action='append', help='Add or replace specific FV into payload, Ex: uefi_fv=XXX.fv') - command_group = parser.add_mutually_exclusive_group() - command_group.add_argument("-e", "--BuildEntryOnly", action='store_true', help='Build UniversalPayload Entry file') - command_group.add_argument("-pb", "--PreBuildUplBinary", default=None, help='Specify the UniversalPayload file') + known_args, _ = parser.parse_known_args() + if (known_args.SpecRevision >= 0x0100): + parser.add_argument('--pecoff', dest='PayloadEntryFormat', action='store_true', default=True) + parser.add_argument('-l', "--LoadAddress", type=int, help='Specify payload load address', default =0x000800000) + args = parser.parse_args() + if (hasattr (args, 'PayloadEntryFormat') == False): + args.PayloadEntryFormat = 'elf' + else: + args.PayloadEntryFormat = "pecoff" if args.PayloadEntryFormat == True else "elf" MultiFvList = [] UniversalPayloadBinary = args.PreBuildUplBinary @@ -XXX,XX +XXX,XX @@ def main(): for (SectionName, SectionFvFile) in args.AddFv: MultiFvList.append ([SectionName, SectionFvFile]) + def ReplaceFv (UplBinary, SectionFvFile, SectionName): + print (bcolors.OKGREEN + "Patch {}={} into {}".format (SectionName, SectionFvFile, UplBinary) + bcolors.ENDC) + if (args.SpecRevision < 0x0100): + import Tools.ElfFv as ElfFv + return ElfFv.ReplaceFv (UplBinary, SectionFvFile, '.upld.{}'.format (SectionName)) + else: + import Tools.MkFitImage as MkFitImage + return MkFitImage.ReplaceFv (UplBinary, SectionFvFile, SectionName) + if (UniversalPayloadBinary != None): for (SectionName, SectionFvFile) in MultiFvList: if os.path.exists (SectionFvFile) == False: continue - print ("Patch {}={} into {}".format (SectionName, SectionFvFile, UniversalPayloadBinary)) - ReplaceFv (UniversalPayloadBinary, SectionFvFile, '.upld.{}'.format (SectionName)) + + status = ReplaceFv (UniversalPayloadBinary, SectionFvFile, SectionName.replace ("_", "-")) + if status != 0: + print (bcolors.FAIL + "[Fail] Patch {}={}".format (SectionName, SectionFvFile) + bcolors.ENDC) + return status print ("\nSuccessfully build Universal Payload") -- 2.39.1.windows.1 -=-=-=-=-=-=-=-=-=-=-=- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#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] -=-=-=-=-=-=-=-=-=-=-=-
From: "Brucex.Wang" <brucex.wang@intel.com> V4: Fix Benny comment in patch mail. V3: Fix Lean Sheng comment in patch mail V2: Fix Gua and Chasel comment in PR V1: Initialize Version Brucex.Wang (2): MdePkg/BaseFdtLib: Add Fdt function. UefiPayloadPkg: Add FIT support Zhiguang Liu (2): OvmfPkg: Remove applicationProcessorEntryPoint UefiCpuPkg/ResetVector: Remove AP waking vector from ResetVector MdePkg/Include/Library/FdtLib.h | 34 + MdePkg/Library/BaseFdtLib/FdtLib.c | 40 ++ OvmfPkg/ResetVector/Ia16/ResetVectorVtf0.asm | 15 +- .../XenResetVector/Ia16/ResetVectorVtf0.asm | 16 +- UefiCpuPkg/ResetVector/Vtf0/Ia16/Init16.asm | 7 - .../ResetVector/Vtf0/Ia16/ResetVectorVtf0.asm | 15 +- .../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 ++++++--- 18 files changed, 1973 insertions(+), 140 deletions(-) create mode 100644 UefiPayloadPkg/Include/Guid/UniversalPayloadBase.h create mode 100644 UefiPayloadPkg/PayloadLoaderPeim/FitLib.h create mode 100644 UefiPayloadPkg/PayloadLoaderPeim/FitLib/FitLib.c create mode 100644 UefiPayloadPkg/PayloadLoaderPeim/FitPayloadLoaderPeim.c create mode 100644 UefiPayloadPkg/PayloadLoaderPeim/FitPayloadLoaderPeim.inf create mode 100644 UefiPayloadPkg/Readme.md create mode 100644 UefiPayloadPkg/Tools/MkFitImage.py create mode 100644 UefiPayloadPkg/UefiPayloadEntry/FitUniversalPayloadEntry.c create mode 100644 UefiPayloadPkg/UefiPayloadEntry/FitUniversalPayloadEntry.inf -- 2.39.1.windows.1 -=-=-=-=-=-=-=-=-=-=-=- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#108788): https://edk2.groups.io/g/devel/message/108788 Mute This Topic: https://groups.io/mt/101435612/1787277 Group Owner: devel+owner@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [importer@patchew.org] -=-=-=-=-=-=-=-=-=-=-=-
From: Zhiguang Liu <zhiguang.liu@intel.com> REF: https://bugzilla.tianocore.org/show_bug.cgi?id=4494 Current reset vector uses 0xffffffe0 as AP waking vector, and expects GenFv generates code aligned on a 4k boundary which will jump to this location. However, some issues are listed below 1. GenFV doesn't generate code as the comment expects, because GenFv assumes no modifications are required to the VTF-0 'Volume Top File'. 2. Even if removing VFT0 signature and let GenFv to modify, Genfv is hard-code using another flash address 0xffffffd0. 3. In the same patch series, AP waking vector code is removed from GenFv, because no such usage anymore. The existing of first two issues also approve the usage is not available for a long time. Therefore, remove AP waking vector related code. Cc: Ard Biesheuvel <ardb+tianocore@kernel.org> Cc: Jiewen Yao <jiewen.yao@intel.com> Cc: Jordan Justen <jordan.l.justen@intel.com> Cc: Gerd Hoffmann <kraxel@redhat.com> Cc: Anthony Perard <anthony.perard@citrix.com> Cc: Julien Grall <julien@xen.org> Reviewed-by: Ray Ni <ray.ni@intel.com> Acked-by: Anthony PERARD <anthony.perard@citrix.com> Signed-off-by: Zhiguang Liu <zhiguang.liu@intel.com> --- OvmfPkg/ResetVector/Ia16/ResetVectorVtf0.asm | 15 +++------------ OvmfPkg/XenResetVector/Ia16/ResetVectorVtf0.asm | 16 +++------------- 2 files changed, 6 insertions(+), 25 deletions(-) diff --git a/OvmfPkg/ResetVector/Ia16/ResetVectorVtf0.asm b/OvmfPkg/ResetVector/Ia16/ResetVectorVtf0.asm index XXXXXXX..XXXXXXX 100644 --- a/OvmfPkg/ResetVector/Ia16/ResetVectorVtf0.asm +++ b/OvmfPkg/ResetVector/Ia16/ResetVectorVtf0.asm @@ -XXX,XX +XXX,XX @@ guidedStructureEnd: ALIGN 16 -applicationProcessorEntryPoint: ; -; Application Processors entry point +; 0xffffffe0 ; -; GenFv generates code aligned on a 4k boundary which will jump to this -; location. (0xffffffe0) This allows the Local APIC Startup IPI to be -; used to wake up the application processors. -; - jmp EarlyApInitReal16 - -ALIGN 8 - - DD 0 + DD 0, 0, 0 ; -; The VTF signature +; The VTF signature (0xffffffec) ; ; VTF-0 means that the VTF (Volume Top File) code does not require ; any fixups. diff --git a/OvmfPkg/XenResetVector/Ia16/ResetVectorVtf0.asm b/OvmfPkg/XenResetVector/Ia16/ResetVectorVtf0.asm index XXXXXXX..XXXXXXX 100644 --- a/OvmfPkg/XenResetVector/Ia16/ResetVectorVtf0.asm +++ b/OvmfPkg/XenResetVector/Ia16/ResetVectorVtf0.asm @@ -XXX,XX +XXX,XX @@ xenPVHEntryPoint: BITS 16 ALIGN 16 - -applicationProcessorEntryPoint: -; -; Application Processors entry point ; -; GenFv generates code aligned on a 4k boundary which will jump to this -; location. (0xffffffe0) This allows the Local APIC Startup IPI to be -; used to wake up the application processors. +; 0xffffffe0 ; - jmp EarlyApInitReal16 - -ALIGN 8 - - DD 0 + DD 0, 0, 0 ; -; The VTF signature +; The VTF signature (0xffffffec) ; ; VTF-0 means that the VTF (Volume Top File) code does not require ; any fixups. -- 2.39.1.windows.1 -=-=-=-=-=-=-=-=-=-=-=- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#108789): https://edk2.groups.io/g/devel/message/108789 Mute This Topic: https://groups.io/mt/101435617/1787277 Group Owner: devel+owner@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [importer@patchew.org] -=-=-=-=-=-=-=-=-=-=-=-
From: Zhiguang Liu <zhiguang.liu@intel.com> REF: https://bugzilla.tianocore.org/show_bug.cgi?id=4494 Current reset vector uses 0xffffffe0 as AP waking vector, and expects GenFv generates code aligned on a 4k boundary which will jump to this location. However, some issues are listed below 1. GenFV doesn't generate code as the comment expects, because GenFv assumes no modifications are required to the VTF-0 'Volume Top File'. 2. Even if removing VFT0 signature and let GenFv to modify, Genfv is hard-code using another flash address 0xffffffd0. 3. In the same patch series, AP waking vector code is removed from GenFv, because no such usage anymore. The existing of first two issues also approve the usage is not available for a long time. Therefore, remove AP waking vector related code. Cc: Eric Dong <eric.dong@intel.com> Cc: Ray Ni <ray.ni@intel.com> Cc: Rahul Kumar <rahul1.kumar@intel.com> Cc: Gerd Hoffmann <kraxel@redhat.com> Reviewed-by: Ray Ni <ray.ni@intel.com> Signed-off-by: Zhiguang Liu <zhiguang.liu@intel.com> --- UefiCpuPkg/ResetVector/Vtf0/Ia16/Init16.asm | 7 ------- .../ResetVector/Vtf0/Ia16/ResetVectorVtf0.asm | 15 +++------------ 2 files changed, 3 insertions(+), 19 deletions(-) diff --git a/UefiCpuPkg/ResetVector/Vtf0/Ia16/Init16.asm b/UefiCpuPkg/ResetVector/Vtf0/Ia16/Init16.asm index XXXXXXX..XXXXXXX 100644 --- a/UefiCpuPkg/ResetVector/Vtf0/Ia16/Init16.asm +++ b/UefiCpuPkg/ResetVector/Vtf0/Ia16/Init16.asm @@ -XXX,XX +XXX,XX @@ EarlyBspInitReal16: mov di, 'BP' jmp short Main16 -; -; @param[out] DI 'AP' to indicate application processor -; -EarlyApInitReal16: - mov di, 'AP' - jmp short Main16 - ; ; Modified: EAX ; diff --git a/UefiCpuPkg/ResetVector/Vtf0/Ia16/ResetVectorVtf0.asm b/UefiCpuPkg/ResetVector/Vtf0/Ia16/ResetVectorVtf0.asm index XXXXXXX..XXXXXXX 100644 --- a/UefiCpuPkg/ResetVector/Vtf0/Ia16/ResetVectorVtf0.asm +++ b/UefiCpuPkg/ResetVector/Vtf0/Ia16/ResetVectorVtf0.asm @@ -XXX,XX +XXX,XX @@ ALIGN 16 TIMES (0x1000 - 0x20) DB 0 %endif -applicationProcessorEntryPoint: ; -; Application Processors entry point +; 0xffffffe0 ; -; GenFv generates code aligned on a 4k boundary which will jump to this -; location. (0xffffffe0) This allows the Local APIC Startup IPI to be -; used to wake up the application processors. -; - jmp EarlyApInitReal16 - -ALIGN 8 - - DD 0 + DD 0, 0, 0 ; -; The VTF signature +; The VTF signature (0xffffffec) ; ; VTF-0 means that the VTF (Volume Top File) code does not require ; any fixups. -- 2.39.1.windows.1 -=-=-=-=-=-=-=-=-=-=-=- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#108790): https://edk2.groups.io/g/devel/message/108790 Mute This Topic: https://groups.io/mt/101435618/1787277 Group Owner: devel+owner@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [importer@patchew.org] -=-=-=-=-=-=-=-=-=-=-=-
From: "Brucex.Wang" <brucex.wang@intel.com> Add FdtGetName() and FdtNodeDepth() function. Cc: Benny Lin <benny.lin@intel.com> Cc: Gua Guo <gua.guo@intel.com> Cc: Chasel Chiu <chasel.chiu@intel.com> Cc: James Lu <james.lu@intel.com> Signed-off-by: BruceX Wang <brucex.wang@intel.com> --- MdePkg/Include/Library/FdtLib.h | 34 +++++++++++++++++++++++++ MdePkg/Library/BaseFdtLib/FdtLib.c | 40 ++++++++++++++++++++++++++++++ 2 files changed, 74 insertions(+) diff --git a/MdePkg/Include/Library/FdtLib.h b/MdePkg/Include/Library/FdtLib.h index XXXXXXX..XXXXXXX 100644 --- a/MdePkg/Include/Library/FdtLib.h +++ b/MdePkg/Include/Library/FdtLib.h @@ -XXX,XX +XXX,XX @@ FdtSetProp ( IN UINT32 Length ); +/** + Returns the name of a given node. + + @param[in] Fdt The pointer to FDT blob. + @param[in] NodeOffse Offset of node to check. + @param[in] Length The pointer to an integer variable (will be overwritten) or NULL. + + @return The pointer to the node's name. + +**/ +CONST CHAR8 * +EFIAPI +FdtGetName ( + IN VOID *Fdt, + IN INT32 NodeOffset, + IN UINT32 *Length + ); + +/** + FdtNodeDepth() finds the depth of a given node. The root node + has depth 0, its immediate subnodes depth 1 and so forth. + + @param[in] Fdt The pointer to FDT blob. + @param[in] NodeOffset Offset of node to check. + + @return Depth of the node at NodeOffset. +**/ +INT32 +EFIAPI +FdtNodeDepth ( + IN CONST VOID *Fdt, + IN INT32 NodeOffset + ); + #endif /* FDT_LIB_H_ */ diff --git a/MdePkg/Library/BaseFdtLib/FdtLib.c b/MdePkg/Library/BaseFdtLib/FdtLib.c index XXXXXXX..XXXXXXX 100644 --- a/MdePkg/Library/BaseFdtLib/FdtLib.c +++ b/MdePkg/Library/BaseFdtLib/FdtLib.c @@ -XXX,XX +XXX,XX @@ 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] NodeOffset Offset of node to check. + @param[in] Length The pointer to an integer variable (will be overwritten) 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, (int *)Length); +} + +/** + FdtNodeDepth() finds the depth of a given node. The root node + has depth 0, its immediate subnodes depth 1 and so forth. + + @param[in] Fdt The pointer to FDT blob. + @param[in] NodeOffset Offset of node to check. + + @returns Depth of the node at NodeOffset. +**/ +INT32 +EFIAPI +FdtNodeDepth ( + IN CONST VOID *Fdt, + IN INT32 NodeOffset + ) +{ + return fdt_node_depth (Fdt, NodeOffset); +} -- 2.39.1.windows.1 -=-=-=-=-=-=-=-=-=-=-=- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#108791): https://edk2.groups.io/g/devel/message/108791 Mute This Topic: https://groups.io/mt/101435619/1787277 Group Owner: devel+owner@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [importer@patchew.org] -=-=-=-=-=-=-=-=-=-=-=-
From: "Brucex.Wang" <brucex.wang@intel.com> Provide Fit format for UniversalPayload, developer can use argument "--Fit" to build UniversalPayload.fit Cc: Guo Dong <guo.dong@intel.com> Cc: Sean Rhodes <sean@starlabs.systems> Cc: James Lu <james.lu@intel.com> Cc: Gua Guo <gua.guo@intel.com> Signed-off-by: BruceX Wang <brucex.wang@intel.com> --- .../Include/Guid/UniversalPayloadBase.h | 19 + UefiPayloadPkg/PayloadLoaderPeim/FitLib.h | 60 ++ .../PayloadLoaderPeim/FitLib/FitLib.c | 127 ++++ .../PayloadLoaderPeim/FitPayloadLoaderPeim.c | 150 ++++ .../FitPayloadLoaderPeim.inf | 59 ++ UefiPayloadPkg/Readme.md | 189 +++++ UefiPayloadPkg/Tools/MkFitImage.py | 272 ++++++++ .../FitUniversalPayloadEntry.c | 654 ++++++++++++++++++ .../FitUniversalPayloadEntry.inf | 98 +++ UefiPayloadPkg/UefiPayloadPkg.dec | 3 + UefiPayloadPkg/UefiPayloadPkg.dsc | 27 +- UefiPayloadPkg/UniversalPayloadBuild.py | 328 ++++++--- 12 files changed, 1890 insertions(+), 96 deletions(-) create mode 100644 UefiPayloadPkg/Include/Guid/UniversalPayloadBase.h create mode 100644 UefiPayloadPkg/PayloadLoaderPeim/FitLib.h create mode 100644 UefiPayloadPkg/PayloadLoaderPeim/FitLib/FitLib.c create mode 100644 UefiPayloadPkg/PayloadLoaderPeim/FitPayloadLoaderPeim.c create mode 100644 UefiPayloadPkg/PayloadLoaderPeim/FitPayloadLoaderPeim.inf create mode 100644 UefiPayloadPkg/Readme.md create mode 100644 UefiPayloadPkg/Tools/MkFitImage.py create mode 100644 UefiPayloadPkg/UefiPayloadEntry/FitUniversalPayloadEntry.c create mode 100644 UefiPayloadPkg/UefiPayloadEntry/FitUniversalPayloadEntry.inf diff --git a/UefiPayloadPkg/Include/Guid/UniversalPayloadBase.h b/UefiPayloadPkg/Include/Guid/UniversalPayloadBase.h new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/UefiPayloadPkg/Include/Guid/UniversalPayloadBase.h @@ -XXX,XX +XXX,XX @@ +/** @file + Universal Payload general definitions. + +Copyright (c) 2023, Intel Corporation. All rights reserved.<BR> +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef UNIVERSAL_PAYLOAD_BASE_H_ +#define UNIVERSAL_PAYLOAD_BASE_H_ + +extern GUID gUniversalPayloadBaseGuid; + +typedef struct { + UNIVERSAL_PAYLOAD_GENERIC_HEADER Header; + EFI_PHYSICAL_ADDRESS Entry; +} UNIVERSAL_PAYLOAD_BASE; + +#endif // UNIVERSAL_PAYLOAD_BASE_H_ diff --git a/UefiPayloadPkg/PayloadLoaderPeim/FitLib.h b/UefiPayloadPkg/PayloadLoaderPeim/FitLib.h new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/UefiPayloadPkg/PayloadLoaderPeim/FitLib.h @@ -XXX,XX +XXX,XX @@ +/** @file + FIT Load Image Support +Copyright (c) 2023, Intel Corporation. All rights reserved.<BR> +SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#ifndef FIT_LIB_H_ +#define FIT_LIB_H_ + +#include <PiPei.h> +#include <Library/DebugLib.h> +#include <Library/FdtLib.h> + +typedef struct { + UINT64 RelocateType; + UINT64 Offset; +} FIT_RELOCATE_ITEM; + +typedef struct { + EFI_PHYSICAL_ADDRESS ImageBase; + EFI_PHYSICAL_ADDRESS PayloadBaseAddress; + UINT64 PayloadSize; + UINTN PayloadEntryOffset; + UINTN PayloadEntrySize; + EFI_PHYSICAL_ADDRESS PayloadEntryPoint; + UINTN RelocateTableOffset; + UINTN RelocateTableCount; + EFI_PHYSICAL_ADDRESS PayloadLoadAddress; +} FIT_IMAGE_CONTEXT; + +typedef struct { + UINT8 *Name; + UINT32 Offset; +} PROPERTY_DATA; + +#define IMAGE_BASE_OFFSET OFFSET_OF (FIT_IMAGE_CONTEXT, ImageBase) +#define PAYLOAD_BASE_ADDR_OFFSET OFFSET_OF (FIT_IMAGE_CONTEXT, PayloadBaseAddress) +#define PAYLOAD_BASE_SIZE_OFFSET OFFSET_OF (FIT_IMAGE_CONTEXT, PayloadSize) +#define PAYLOAD_ENTRY_OFFSET_OFFSET OFFSET_OF (FIT_IMAGE_CONTEXT, PayloadEntryOffset) +#define PAYLOAD_ENTRY_SIZE_OFFSET OFFSET_OF (FIT_IMAGE_CONTEXT, PayloadEntrySize) +#define PAYLOAD_ENTRY_POINT_OFFSET OFFSET_OF (FIT_IMAGE_CONTEXT, PayloadEntryPoint) +#define RELOCATE_TABLE_OFFSET_OFFSET OFFSET_OF (FIT_IMAGE_CONTEXT, RelocateTableOffset) +#define RELOCATE_TABLE_COUNT_OFFSET OFFSET_OF (FIT_IMAGE_CONTEXT, RelocateTableCount) +#define PAYLOAD_LOAD_ADDR_OFFSET OFFSET_OF (FIT_IMAGE_CONTEXT, PayloadLoadAddress) + +/** + Parse the FIT image info. + @param[in] ImageBase Memory address of an image. + @param[out] Context The FIT image context pointer. + @retval EFI_UNSUPPORTED Unsupported binary type. + @retval EFI_SUCCESS FIT binary is loaded successfully. +**/ +EFI_STATUS +EFIAPI +ParseFitImage ( + IN VOID *ImageBase, + OUT FIT_IMAGE_CONTEXT *Context + ); + +#endif diff --git a/UefiPayloadPkg/PayloadLoaderPeim/FitLib/FitLib.c b/UefiPayloadPkg/PayloadLoaderPeim/FitLib/FitLib.c new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/UefiPayloadPkg/PayloadLoaderPeim/FitLib/FitLib.c @@ -XXX,XX +XXX,XX @@ +/** @file + FIT Load Image Support +Copyright (c) 2023, Intel Corporation. All rights reserved.<BR> +SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include "FitLib.h" + +PROPERTY_DATA PropertyData32List[] = { + { "data-offset", PAYLOAD_ENTRY_OFFSET_OFFSET }, + { "data-size", PAYLOAD_ENTRY_SIZE_OFFSET }, + { "reloc-start", RELOCATE_TABLE_OFFSET_OFFSET } +}; + +PROPERTY_DATA PropertyData64List[] = { + { "entry-start", PAYLOAD_ENTRY_POINT_OFFSET }, + { "load", PAYLOAD_LOAD_ADDR_OFFSET } +}; + +/** + Parse the target firmware image info in FIT. + @param[in] Fdt Memory address of a fdt. + @param[in] Firmware Target name of an image. + @param[out] Context The FIT image context pointer. + @retval EFI_NOT_FOUND FIT node dose not find. + @retval EFI_SUCCESS FIT binary is loaded successfully. +**/ +EFI_STATUS +EFIAPI +FitParseFirmwarePropertyData ( + IN VOID *Fdt, + IN CHAR8 *Firmware, + OUT FIT_IMAGE_CONTEXT *Context + ) +{ + CONST FDT_PROPERTY *PropertyPtr; + INT32 ImageNode; + INT32 TianoNode; + INT32 TempLen; + UINT32 *Data32; + UINT64 *Data64; + UINT32 *ContextOffset32; + UINT64 *ContextOffset64; + INT32 Index; + + ImageNode = FdtSubnodeOffsetNameLen (Fdt, 0, "images", (INT32)AsciiStrLen ("images")); + if (ImageNode <= 0) { + return EFI_NOT_FOUND; + } + + TianoNode = FdtSubnodeOffsetNameLen (Fdt, ImageNode, Firmware, (INT32)AsciiStrLen (Firmware)); + if (TianoNode <= 0) { + return EFI_NOT_FOUND; + } + + for (Index = 0; Index < sizeof (PropertyData32List) / sizeof (PROPERTY_DATA); Index++) { + PropertyPtr = FdtGetProperty (Fdt, TianoNode, PropertyData32List[Index].Name, &TempLen); + Data32 = (UINT32 *)(PropertyPtr->Data); + ContextOffset32 = (UINT32 *)((UINTN)Context + PropertyData32List[Index].Offset); + *ContextOffset32 = Fdt32ToCpu (*Data32); + } + + for (Index = 0; Index < sizeof (PropertyData64List)/sizeof (PROPERTY_DATA); Index++) { + PropertyPtr = FdtGetProperty (Fdt, TianoNode, PropertyData64List[Index].Name, &TempLen); + Data64 = (UINT64 *)(PropertyPtr->Data); + ContextOffset64 = (UINT64 *)((UINTN)Context + PropertyData64List[Index].Offset); + *ContextOffset64 = Fdt64ToCpu (*Data64); + } + + return EFI_SUCCESS; +} + +/** + Parse the FIT image info. + @param[in] ImageBase Memory address of an image. + @param[out] Context The FIT image context pointer. + @retval EFI_UNSUPPORTED Unsupported binary type. + @retval EFI_SUCCESS FIT binary is loaded successfully. +**/ +EFI_STATUS +EFIAPI +ParseFitImage ( + IN VOID *ImageBase, + OUT FIT_IMAGE_CONTEXT *Context + ) +{ + VOID *Fdt; + INT32 ConfigNode; + INT32 Config1Node; + CONST FDT_PROPERTY *PropertyPtr; + INT32 TempLen; + UINT32 *Data32; + UINT64 Value; + EFI_STATUS Status; + UINTN UplSize; + CHAR8 *Firmware; + + Status = FdtCheckHeader (ImageBase); + if (EFI_ERROR (Status)) { + return EFI_UNSUPPORTED; + } + + Fdt = ImageBase; + PropertyPtr = FdtGetProperty (Fdt, 0, "size", &TempLen); + Data32 = (UINT32 *)(PropertyPtr->Data); + UplSize = Value = Fdt32ToCpu (*Data32); + ConfigNode = FdtSubnodeOffsetNameLen (Fdt, 0, "configurations", (INT32)AsciiStrLen ("configurations")); + if (ConfigNode <= 0) { + return EFI_NOT_FOUND; + } + + Config1Node = FdtSubnodeOffsetNameLen (Fdt, ConfigNode, "conf-1", (INT32)AsciiStrLen ("conf-1")); + if (Config1Node <= 0) { + return EFI_NOT_FOUND; + } + + PropertyPtr = FdtGetProperty (Fdt, Config1Node, "firmware", &TempLen); + Firmware = (CHAR8 *)(PropertyPtr->Data); + + FitParseFirmwarePropertyData (Fdt, Firmware, Context); + + Context->ImageBase = (EFI_PHYSICAL_ADDRESS)ImageBase; + Context->PayloadSize = UplSize; + Context->RelocateTableCount = (Context->PayloadEntrySize - (Context->RelocateTableOffset - Context->PayloadEntryOffset)) / sizeof (FIT_RELOCATE_ITEM); + + return EFI_SUCCESS; +} diff --git a/UefiPayloadPkg/PayloadLoaderPeim/FitPayloadLoaderPeim.c b/UefiPayloadPkg/PayloadLoaderPeim/FitPayloadLoaderPeim.c new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/UefiPayloadPkg/PayloadLoaderPeim/FitPayloadLoaderPeim.c @@ -XXX,XX +XXX,XX @@ +/** @file + FIT Load Image Support +Copyright (c) 2023, Intel Corporation. All rights reserved.<BR> +SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include <PiPei.h> +#include <UniversalPayload/UniversalPayload.h> +#include <Guid/UniversalPayloadBase.h> +#include <UniversalPayload/ExtraData.h> + +#include <Ppi/LoadFile.h> + +#include <Library/DebugLib.h> +#include <Library/HobLib.h> +#include <Library/PeiServicesLib.h> +#include <Library/MemoryAllocationLib.h> +#include <Library/BaseMemoryLib.h> + +#include "FitLib.h" + +/** + The wrapper function of PeiLoadImageLoadImage(). + @param This - Pointer to EFI_PEI_LOAD_FILE_PPI. + @param FileHandle - Pointer to the FFS file header of the image. + @param ImageAddressArg - Pointer to PE/TE image. + @param ImageSizeArg - Size of PE/TE image. + @param EntryPoint - Pointer to entry point of specified image file for output. + @param AuthenticationState - Pointer to attestation authentication state of image. + @return Status of PeiLoadImageLoadImage(). +**/ +EFI_STATUS +EFIAPI +PeiLoadFileLoadPayload ( + IN CONST EFI_PEI_LOAD_FILE_PPI *This, + IN EFI_PEI_FILE_HANDLE FileHandle, + OUT EFI_PHYSICAL_ADDRESS *ImageAddressArg OPTIONAL, + OUT UINT64 *ImageSizeArg OPTIONAL, + OUT EFI_PHYSICAL_ADDRESS *EntryPoint, + OUT UINT32 *AuthenticationState + ) +{ + EFI_STATUS Status; + FIT_IMAGE_CONTEXT Context; + UINTN Instance; + VOID *Binary; + FIT_RELOCATE_ITEM *RelocateTable; + UNIVERSAL_PAYLOAD_BASE *PayloadBase; + UINTN Length; + UINTN Delta; + UINTN Index; + + Instance = 0; + do { + Status = PeiServicesFfsFindSectionData3 (EFI_SECTION_RAW, Instance++, FileHandle, &Binary, AuthenticationState); + if (EFI_ERROR (Status)) { + return Status; + } + + ZeroMem (&Context, sizeof (Context)); + Status = ParseFitImage (Binary, &Context); + } while (EFI_ERROR (Status)); + + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + + DEBUG (( + DEBUG_INFO, + "Before Rebase Payload File Base: 0x%08x, File Size: 0x%08X, EntryPoint: 0x%08x\n", + Context.PayloadBaseAddress, + Context.PayloadSize, + Context.PayloadEntryPoint + )); + Context.PayloadBaseAddress = (EFI_PHYSICAL_ADDRESS)AllocatePages (EFI_SIZE_TO_PAGES (Context.PayloadSize)); + + RelocateTable = (FIT_RELOCATE_ITEM *)(UINTN)(Context.PayloadBaseAddress + Context.RelocateTableOffset); + CopyMem ((VOID *)Context.PayloadBaseAddress, Binary, Context.PayloadSize); + + if (Context.PayloadBaseAddress > Context.PayloadLoadAddress) { + Delta = Context.PayloadBaseAddress - Context.PayloadLoadAddress; + Context.PayloadEntryPoint += Delta; + for (Index = 0; Index < Context.RelocateTableCount; Index++) { + if ((RelocateTable[Index].RelocateType == 10) || (RelocateTable[Index].RelocateType == 3)) { + *((UINT64 *)(Context.PayloadBaseAddress + RelocateTable[Index].Offset)) = *((UINT64 *)(Context.PayloadBaseAddress + RelocateTable[Index].Offset)) + Delta; + } + } + } else { + Delta = Context.PayloadLoadAddress - Context.PayloadBaseAddress; + Context.PayloadEntryPoint -= Delta; + for (Index = 0; Index < Context.RelocateTableCount; Index++) { + if ((RelocateTable[Index].RelocateType == 10) || (RelocateTable[Index].RelocateType == 3)) { + *((UINT64 *)(Context.PayloadBaseAddress + RelocateTable[Index].Offset)) = *((UINT64 *)(Context.PayloadBaseAddress + RelocateTable[Index].Offset)) - Delta; + } + } + } + + DEBUG (( + DEBUG_INFO, + "After Rebase Payload File Base: 0x%08x, File Size: 0x%08X, EntryPoint: 0x%08x\n", + Context.PayloadBaseAddress, + Context.PayloadSize, + Context.PayloadEntryPoint + )); + + Length = sizeof (UNIVERSAL_PAYLOAD_BASE); + PayloadBase = BuildGuidHob ( + &gUniversalPayloadBaseGuid, + Length + ); + PayloadBase->Entry = (EFI_PHYSICAL_ADDRESS)Context.ImageBase; + + *ImageAddressArg = Context.PayloadBaseAddress; + *ImageSizeArg = Context.PayloadSize; + *EntryPoint = Context.PayloadEntryPoint; + + return EFI_SUCCESS; +} + +EFI_PEI_LOAD_FILE_PPI mPeiLoadFilePpi = { + PeiLoadFileLoadPayload +}; + +EFI_PEI_PPI_DESCRIPTOR gPpiLoadFilePpiList = { + (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST), + &gEfiPeiLoadFilePpiGuid, + &mPeiLoadFilePpi +}; + +/** + Install Pei Load File PPI. + @param FileHandle Handle of the file being invoked. + @param PeiServices Describes the list of possible PEI Services. + @retval EFI_SUCESS The entry point executes successfully. + @retval Others Some error occurs during the execution of this function. +**/ +EFI_STATUS +EFIAPI +InitializeFitPayloadLoaderPeim ( + IN EFI_PEI_FILE_HANDLE FileHandle, + IN CONST EFI_PEI_SERVICES **PeiServices + ) +{ + EFI_STATUS Status; + + Status = PeiServicesInstallPpi (&gPpiLoadFilePpiList); + + return Status; +} diff --git a/UefiPayloadPkg/PayloadLoaderPeim/FitPayloadLoaderPeim.inf b/UefiPayloadPkg/PayloadLoaderPeim/FitPayloadLoaderPeim.inf new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/UefiPayloadPkg/PayloadLoaderPeim/FitPayloadLoaderPeim.inf @@ -XXX,XX +XXX,XX @@ +## @file +# Produce LoadFile PPI for payload loading. +# +# Copyright (c) 2023, Intel Corporation. All rights reserved.<BR> +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = FitPayloadLoaderPeim + FILE_GUID = 55AC82C8-FC17-4C56-BCDA-990BB0A73E41 + MODULE_TYPE = PEIM + VERSION_STRING = 1.0 + + ENTRY_POINT = InitializeFitPayloadLoaderPeim + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 +# + +[Sources] + FitPayloadLoaderPeim.c + FitLib.h + FitLib/FitLib.c + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + PcAtChipsetPkg/PcAtChipsetPkg.dec + UefiPayloadPkg/UefiPayloadPkg.dec + +[LibraryClasses] + PcdLib + MemoryAllocationLib + BaseMemoryLib + PeiServicesLib + HobLib + BaseLib + PeimEntryPoint + DebugLib + FdtLib + +[Ppis] + gEfiPeiLoadFilePpiGuid ## PRODUCES + +[Pcd] + gPcAtChipsetPkgTokenSpaceGuid.PcdRtcIndexRegister + gPcAtChipsetPkgTokenSpaceGuid.PcdRtcTargetRegister + +[Guids] + gUniversalPayloadExtraDataGuid ## PRODUCES + gUniversalPayloadBaseGuid ## PRODUCES + +[Depex] + TRUE diff --git a/UefiPayloadPkg/Readme.md b/UefiPayloadPkg/Readme.md new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/UefiPayloadPkg/Readme.md @@ -XXX,XX +XXX,XX @@ +# UefiPayloadPkg +Provide UEFI Universal Payload for different bootloader to generate EFI environment + +# Spec +UniversalPayload URL: https://universalscalablefirmware.github.io/documentation/2_universal_payload.html +UniversalPayload URL: https://universalpayload.github.io/spec/ +ELF Format URL: https://refspecs.linuxfoundation.org/elf/elf.pdf +FIT Format URL: https://universalpayload.github.io/spec/chapter2-payload-image-format.html + +# Uefi UniversalPayload Format + | Binary Format | HandOffPayload - HOB | + |---------------|----------------------| + | ELF | V (Default) | + | FIT | V | + +# Binary Format + - ELF + ``` + + +-----------------------+ + | | UniversalPayloadEntry | <----------- UefiPayloadPkg\UefiPayloadEntry\UniversalPayloadEntry.c:_ModuleEntryPoint (HOB) + | +-----------------------+ + | | .upld_info | patch it directly + ELF Format | +-----------------------+ + | | .upld.uefi_fv | patch it directly + | +-----------------------+ + | | .upld.bds_fv | patch it directly + | +-----------------------+ + | | .upld.<afpx>_fv | patch it directly + + +-----------------------+ + ``` + + - FIT + ``` + + +-----------------------+ + FIT Data | | FIT Header | <----------- Generate by pylibfdt + + +-----------------------+ + PECOFF Format | | UniversalPayloadEntry | <----------- UefiPayloadPkg\UefiPayloadEntry\FitUniversalPayloadEntry.c:_ModuleEntryPoint (HOB) + + +-----------------------+ + Relocate Data | | reloc-start | + + +-----------------------+ + | | uefi_fv | patch it directly + | +-----------------------+ + Multi Binary | | bds_fv | patch it directly + | +-----------------------+ + | | afp_xxx_fv | patch it directly + | +-----------------------+ + | | afp_xxx_fv | patch it directly + + +-----------------------+ + ``` + +# Environment + - ELF + ``` + Download and install https://github.com/llvm/llvm-project/releases/tag/llvmorg-10.0.1 + ``` + - FIT + - Windows + ```powershell + Set-ExecutionPolicy Bypass -Scope Process -Force; [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; iex ((New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1')) + choco install dtc-msys2 + pip3 install pefile + pip3 install swig + pip3 install pylibfdt + ``` + - Ubuntu + ```bash + sudo apt install -y u-boot-tools + pip3 install pefile + pip3 install swig + pip3 install pylibfdt + ``` +# How to build UEFI UniversalPayload + - Windows + - edksetup Rebuild + - Linux + - make -C BaseTools + - source edksetup.sh + + - UniversalPayload.elf + - python UefiPayloadPkg/UniversalPayloadBuild.py -t <TOOL_CHAIN_TAG> + - llvm-objdump -h Build/UefiPayloadPkgX64/UniversalPayload.elf + + - UniversalPayload.fit + - python UefiPayloadPkg/UniversalPayloadBuild.py -t <TOOL_CHAIN_TAG> --Fit + - fdtdump Build/UefiPayloadPkgX64/UniversalPayload.fit + +# Edk2boot + UefiUniversalPayload +ELF Edk2boot use below way to support compress and sign. + +- ELF Behavior - Edk2boot + UefiUniversalPayload.elf + ``` + Boot Flow + +-------------------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------+-------------------+ + | Platform Init | Universal Loader Interface | OS | + +-------------------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------+-------------------+ + HOBs + SEC -> PEI -> DXE -> DXE IPL -> UefiPayloadPkg\PayloadLoaderPeim\PayloadLoaderPeim.c ------------------------------------------------------------------------------------> Load UniversalPayload.elf -> Operation System + + + | Platform Initialize - Edk2 | UniversalPayload - Edk2 | + +-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------+ + + Binary Format + + +-------------------+ + | BIOS.rom | + +-------------------+ + | Other Firmware | + +-------------------+ + | ... | FMMT UniversalPayloadBuild.py + +-------------------+<----------------+-----------------------+ GenFfs +-----------------------+ Rsa2048Sha256 Sign +-----------------------+ LzmaCompress +----------------------+ GenSec +--------------------------------+ + | | | EDK2 FFS Header |<-----------| Rsa2048Sha256 Hash |<--------------------| UniversalPayload.lzma |<--------------| EDK2 SEC Header |<--------| UniversalPayload.elf | + | RAW Data | +-----------------------+ +-----------------------+ +-----------------------+ +----------------------+ +--------------------------------+ + | | | Rsa2048Sha256 Hash | | UniversalPayload.lzma | | UniversalPayload.elf | | upld_info | + | | +-----------------------+ +-----------------------+ +----------------------+ +--------------------------------+ + | | | UniversalPayload.lzma | | upld_info | | upld.uefi_fv | + +-------------------+<----------------+-----------------------+ +----------------------+ +--------------------------------+ + | ... | | upld.uefi_fv | | upld.bds_fv | + +-------------------+ +----------------------+ +--------------------------------+ + | Other Firmware | | upld.bds_fv | | upld.AFP1 | + +-------------------+ +----------------------+ +--------------------------------+ + | upld.AFP1 | | upld.AFP2 | + +----------------------+ +--------------------------------+ + | upld.AFP2 | | ... | + +----------------------+ +--------------------------------+ + | ... | | upld.AFPn | + +----------------------+ +--------------------------------+ + | upld.AFPn | + +----------------------+ + ``` + +FIT Edk2boot use below way to support compress and sign +- FIT Behavior - Edk2boot + UefiUniversalPayload.fit + ``` + Boot Flow + +-------------------------------------------------------------------------------------+------------------------------------------------------------------------+-------------------+ + | Platform Init | Universal Loader Interface | OS | + +-------------------------------------------------------------------------------------+------------------------------------------------------------------------+-------------------+ + HOBs + SEC -> PEI -> DXE -> DXE IPL -> *UefiPayloadPkg\PayloadLoaderPeim\PayloadLoaderPeim.c ----------------------------------------------> Load UniversalPayload.fit -> Operation System + + Binary Format + + | Platform Initialize - Edk2 | UniversalPayload - Edk2 (UniversalPayloadBuild.py --Fit) | + +---------------------------------------------------------------------------------------------------------------------------+-----------------------------------------------------------------------------------------+ + + +-------------------+ + | BIOS.rom | + +-------------------+ + | Other Firmware | + +-------------------+ + | ... | FMMT UniversalPayloadBuild.py --Fit tianocore -> data-offset + +-------------------+<----------------+--------------------------------+ GenFfs +--------------------------------+ GenSec +--------------------------------+ tianocore -> reloc-start +--------------------------+ + | | | EDK2 FFS Header |<--------| EDK2 SEC Header |<--------| FIT Header |<-------------------------| UniversalPayload.pecoff | + | | +--------------------------------+ +--------------------------------+ | description = "Uefi Payload"; | +--------------------------+ + | | | EDK2 SEC Header | | FIT Header | | ... | + | RAW Data | +--------------------------------+ | | | images { | uefi-fv -> data-offset +--------------------------+ + | | | FIT Header | | | | tianocore {...}; |<-------------------------| uefi_fv | + | | | | +--------------------------------+ | uefi-fv {...}; | bds-fv -> data-offset +--------------------------+ + | | | | | tianocore -> data | | bds-fv {...}; |<-------------------------| bds_fv | + | | +--------------------------------+ +--------------------------------+ | afp1-fv {...}; | AFP1 -> data-offset +--------------------------+ + | | | tianocore -> data | | tianocore -> reloc-start | | ... |<-------------------------| AFP1 | + | | +--------------------------------+ +--------------------------------+ | afpn-fv {...}; | AFP2 -> data-offset +--------------------------+ + | | | tianocore -> reloc-start | | uefi-fv -> data | | } |<-------------------------| AFP2 | + | | +--------------------------------+ +--------------------------------+ | configurations { | ... +--------------------------+ + | | | uefi-fv -> data | | bds-fv -> data | | conf-1 {...} |<-------------------------| ... | + | | +--------------------------------+ +--------------------------------+ | } | AFPn -> data-offset +--------------------------+ + | | | bds-fv -> data | | AFP1-fv -> data | | |<-------------------------| AFPn | + | | +--------------------------------+ +--------------------------------+ | | +--------------------------+ + | | | AFP1-fv -> data | | AFP2-fv -> data | | | + | | +--------------------------------+ +--------------------------------+ +--------------------------------+ + | | | AFP2-fv -> data | | ... | | tianocore -> data | + | | +--------------------------------+ +--------------------------------+ +--------------------------------+ + | | | ... | | AFPn-fv -> data | | tianocore -> reloc-start | + | | +--------------------------------+ +--------------------------------+ +--------------------------------+ + | | | AFPn-fv -> data | | uefi-fv -> data | + +-------------------+<----------------+--------------------------------+ +--------------------------------+ + | ... | | bds-fv -> data | + +-------------------+ +--------------------------------+ + | Other Firmware | | AFP1-fv -> data | + +-------------------+ +--------------------------------+ + | AFP2-fv -> data | + +--------------------------------+ + | ... | + +--------------------------------+ + | AFPn-fv -> data | + +--------------------------------+ + + ``` diff --git a/UefiPayloadPkg/Tools/MkFitImage.py b/UefiPayloadPkg/Tools/MkFitImage.py new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/UefiPayloadPkg/Tools/MkFitImage.py @@ -XXX,XX +XXX,XX @@ +## @file +# This file is a script to build fit image. +# It generate a dtb header and combine a binary file after this header. +# +# Copyright (c) 2023, Intel Corporation. All rights reserved.<BR> +# SPDX-License-Identifier: BSD-2-Clause-Patent +## + +from os.path import exists +import libfdt +from ctypes import * +import time + +class FIT_IMAGE_INFO_HEADER: + """Class for user setting data to use MakeFitImage() + """ + _pack_ = 1 + _fields_ = [ + ('Compatible', str), + ('UplVersion', int), + ('Description', str), + ('Type', str), + ('Arch', str), + ('Compression', str), + ('Revision', int), + ('BuildType', str), + ('Capabilities', str), + ('Producer', str), + ('ImageId', str), + ('DataOffset', int), + ('DataSize', int), + ('RelocStart', int), + ('LoadAddr', int), + ('Entry', int), + ('Binary', str), + ('TargetPath', str), + ('UefifvPath', str), + ('BdsfvPath', str), + ('NetworkfvPath', str), + ('Project', str), + ] + + def __init__(self): + self.Compatible = 'universal-payload' + self.UplVersion = 0x0100 + self.TargetPath = 'mkimage.fit' + +def CreatFdt(Fdt): + FdtEmptyTree = libfdt.fdt_create_empty_tree(Fdt, len(Fdt)) + if FdtEmptyTree != 0: + print('\n- Failed - Create Fdt failed!') + return False + return True + +def BuildConfNode(Fdt, ParentNode, MultiImage): + ConfNode1 = libfdt.fdt_add_subnode(Fdt, ParentNode, 'conf-1') + + libfdt.fdt_setprop(Fdt, ConfNode1, 'require-fit', b'', 0) + libfdt.fdt_setprop(Fdt, ConfNode1, 'firmware', bytes('tianocore', 'utf-8'), len('tianocore') + 1) + +def BuildFvImageNode(Fdt, InfoHeader, ParentNode, DataOffset, DataSize, Description): + libfdt.fdt_setprop_u32(Fdt, ParentNode, 'data-size', DataSize) + libfdt.fdt_setprop_u32(Fdt, ParentNode, 'data-offset', DataOffset) + libfdt.fdt_setprop(Fdt, ParentNode, 'compression', bytes('none', 'utf-8'), len('none') + 1) + libfdt.fdt_setprop(Fdt, ParentNode, 'project ', bytes('tianocore', 'utf-8'), len('tianocore') + 1) + libfdt.fdt_setprop(Fdt, ParentNode, 'arch', bytes('x86_64', 'utf-8'), len('x86_64') + 1) + libfdt.fdt_setprop(Fdt, ParentNode, 'type', bytes('flat-binary', 'utf-8'), len('flat-binary') + 1) + libfdt.fdt_setprop(Fdt, ParentNode, 'description', bytes(Description, 'utf-8'), len(Description) + 1) + +def BuildTianoImageNode(Fdt, InfoHeader, ParentNode, DataOffset, DataSize, Description): + # + # Set 'load' and 'data-offset' to reserve the memory first. + # They would be set again when Fdt completes or this function parses target binary file. + # + if InfoHeader.LoadAddr is not None: + libfdt.fdt_setprop_u64(Fdt, ParentNode, 'load', InfoHeader.LoadAddr) + if InfoHeader.Entry is not None: + libfdt.fdt_setprop_u64(Fdt, ParentNode, 'entry-start', InfoHeader.Entry) + if InfoHeader.RelocStart is not None: + libfdt.fdt_setprop_u32(Fdt, ParentNode, 'reloc-start', InfoHeader.RelocStart) + if InfoHeader.DataSize is not None: + libfdt.fdt_setprop_u32(Fdt, ParentNode, 'data-size', DataSize) + if InfoHeader.DataOffset is not None: + libfdt.fdt_setprop_u32(Fdt, ParentNode, 'data-offset', DataOffset) + if InfoHeader.Producer is not None: + libfdt.fdt_setprop(Fdt, ParentNode, 'producer ', bytes(InfoHeader.Producer, 'utf-8'), len(InfoHeader.Producer) + 1) + if InfoHeader.Capabilities is not None: + CapStrs = ','.join(InfoHeader.Capabilities) + libfdt.fdt_setprop(Fdt, ParentNode, 'capabilities ', bytes(CapStrs, 'utf-8'), len(CapStrs) + 1) + if InfoHeader.Type is not None: + libfdt.fdt_setprop(Fdt, ParentNode, 'type ', bytes(InfoHeader.Type, 'utf-8'), len(InfoHeader.Type) + 1) + if InfoHeader.Arch is not None: + libfdt.fdt_setprop(Fdt, ParentNode, 'arch ', bytes(InfoHeader.Arch, 'utf-8'), len(InfoHeader.Arch) + 1) + if InfoHeader.Project is not None: + libfdt.fdt_setprop(Fdt, ParentNode, 'project ', bytes(InfoHeader.Project, 'utf-8'), len(InfoHeader.Project) + 1) + if InfoHeader.Description is not None: + libfdt.fdt_setprop(Fdt, ParentNode, 'description', bytes(Description, 'utf-8'), len(Description) + 1) + +# +# The subnode would be inserted from bottom to top of structure block. +# +def BuildFitImage(Fdt, InfoHeader): + MultiImage = [ + ["tianocore", InfoHeader.Binary, BuildTianoImageNode , InfoHeader.Description, None, 0 ], + ["uefi-fv", InfoHeader.UefifvPath, BuildFvImageNode, "UEFI Firmware Volume", None, 0 ], + ["bds-fv", InfoHeader.BdsfvPath, BuildFvImageNode , "BDS Firmware Volume", None, 0 ], + ["network-fv", InfoHeader.NetworkfvPath, BuildFvImageNode , "Network Firmware Volume", None, 0 ], + ] + + # + # Set basic information + # + libfdt.fdt_setprop_u32(Fdt, 0, 'build-revision ', InfoHeader.Revision) + libfdt.fdt_setprop_u32(Fdt, 0, 'spec-version', InfoHeader.UplVersion) + + # + # Build configurations node + # + ConfNode = libfdt.fdt_add_subnode(Fdt, 0, 'configurations') + BuildConfNode(Fdt, ConfNode, MultiImage) + + # Build image + DataOffset = InfoHeader.DataOffset + for Index in range (0, len (MultiImage)): + _, Path, _, _, _, _ = MultiImage[Index] + if exists(Path) == 1: + TempBinary = open(Path, 'rb') + BinaryData = TempBinary.read() + TempBinary.close() + MultiImage[Index][-2] = BinaryData + MultiImage[Index][-1] = DataOffset + DataOffset += len (BinaryData) + libfdt.fdt_setprop_u32(Fdt, 0, 'size', DataOffset) + posix_time = int(time.time()) + libfdt.fdt_setprop_u32(Fdt, 0, 'timestamp', posix_time) + DescriptionFit = 'Uefi OS Loader' + libfdt.fdt_setprop(Fdt, 0, 'description', bytes(DescriptionFit, 'utf-8'), len(DescriptionFit) + 1) + + ImageNode = libfdt.fdt_add_subnode(Fdt, 0, 'images') + for Item in reversed (MultiImage): + Name, Path, BuildFvNode, Description, BinaryData, DataOffset = Item + FvNode = libfdt.fdt_add_subnode(Fdt, ImageNode, Name) + BuildFvNode (Fdt, InfoHeader, FvNode, DataOffset, len(BinaryData), Description) + + # + # Create new image file and combine all binary. + # + DtbFile = open(InfoHeader.TargetPath, "wb") + DtbFile.truncate() + DtbFile.write(Fdt) + for Item in MultiImage: + _, _, _, _, BinaryData, _ = Item + DtbFile.write(BinaryData) + DtbFile.close() + + return True + +def MakeFitImage(InfoHeader): + # + # Allocate fdt byte array. + # + Fdt = bytearray(InfoHeader.DataOffset) + + # + # Create fdt empty tree. + # + if CreatFdt(Fdt) is False: + return False + + # + # Parse args to build fit image. + # + return BuildFitImage(Fdt, InfoHeader) + +def ReplaceFv (UplBinary, SectionFvFile, SectionName): + try: + # + # Get Original Multi Fv + # + with open (UplBinary, "rb") as File: + Dtb = File.read () + Fit = libfdt.Fdt (Dtb) + NewFitHeader = bytearray(Dtb[0:Fit.totalsize()]) + FitSize = len(Dtb) + + LoadablesList = [] + ImagesNode = libfdt.fdt_subnode_offset(NewFitHeader, 0, 'images') + FvNode = libfdt.fdt_subnode_offset(NewFitHeader, ImagesNode, 'uefi-fv') + NodeDepth = libfdt.fdt_node_depth (NewFitHeader, ImagesNode) + node_name = libfdt.fdt_get_name(NewFitHeader, FvNode) + FvNode = libfdt.fdt_next_node(NewFitHeader, FvNode, NodeDepth) + + while node_name[0][-2:] == 'fv': + LoadablesList.append (node_name[0]) + node_name = libfdt.fdt_get_name(NewFitHeader, FvNode[0]) + FvNode = libfdt.fdt_next_node(NewFitHeader, FvNode[0], NodeDepth) + # + # Get current Fit Binary FV data + # + MultiFvList = [] + for Item in LoadablesList: + ImageNode = libfdt.fdt_subnode_offset(NewFitHeader, ImagesNode, Item) + ImageOffset = int.from_bytes (libfdt.fdt_getprop (NewFitHeader, ImageNode, 'data-offset')[0], 'big') + ImageSize = int.from_bytes (libfdt.fdt_getprop (NewFitHeader, ImageNode, 'data-size')[0], 'big') + MultiFvList.append ([Item, Dtb[ImageOffset:ImageOffset + ImageSize]]) + + IsFvExist = False + for Index in range (0, len (MultiFvList)): + if MultiFvList[Index][0] == SectionName: + with open (SectionFvFile, 'rb') as File: + MultiFvList[Index][1] = File.read () + ImageNode = libfdt.fdt_subnode_offset(NewFitHeader, ImagesNode, SectionName) + ImageSize = int.from_bytes (libfdt.fdt_getprop (NewFitHeader, ImageNode, 'data-size')[0], 'big') + ReplaceOffset = int.from_bytes (libfdt.fdt_getprop (NewFitHeader, ImageNode, 'data-offset')[0], 'big') + OffsetDelta = len(MultiFvList[Index][1]) - ImageSize + FitSize += OffsetDelta + IsFvExist = True + libfdt.fdt_setprop_u32(NewFitHeader, ImageNode, 'data-size', len(MultiFvList[Index][1])) + + # + # Update new fit header + # + ImagesNode = libfdt.fdt_subnode_offset(NewFitHeader, 0, 'images') + if (IsFvExist == False): + with open (SectionFvFile, 'rb') as File: + SectionFvFileBinary = File.read () + MultiFvList.append ([SectionName, SectionFvFileBinary]) + FvNode = libfdt.fdt_add_subnode(NewFitHeader, ImagesNode, SectionName) + BuildFvImageNode (NewFitHeader, None, FvNode, FitSize, len(SectionFvFileBinary), SectionName + " Firmware Volume") + FitSize += len(SectionFvFileBinary) + else: + for Index in range (0, len (MultiFvList)): + ImageNode = libfdt.fdt_subnode_offset(NewFitHeader, ImagesNode, MultiFvList[Index][0]) + ImageOffset = int.from_bytes (libfdt.fdt_getprop (NewFitHeader, ImageNode, 'data-offset')[0], 'big') + if ImageOffset > ReplaceOffset: + libfdt.fdt_setprop_u32(NewFitHeader, ImageNode, 'data-offset', ImageOffset + OffsetDelta) + + ConfNodes = libfdt.fdt_subnode_offset(NewFitHeader, 0, 'configurations') + libfdt.fdt_setprop(NewFitHeader, ConfNodes, 'default ', bytes('conf-1', 'utf-8'), len('conf-1') + 1) + ConfNode = libfdt.fdt_subnode_offset(NewFitHeader, ConfNodes, 'conf-1') + + libfdt.fdt_setprop_u32(NewFitHeader, 0, 'size', FitSize) + + # + # Generate new fit image + # + ImagesNode = libfdt.fdt_subnode_offset(NewFitHeader, 0, 'images') + TianoNode = libfdt.fdt_subnode_offset(NewFitHeader, ImagesNode, 'tianocore') + TianoOffset = int.from_bytes (libfdt.fdt_getprop (NewFitHeader, TianoNode, 'data-offset')[0], 'big') + TianoSize = int.from_bytes (libfdt.fdt_getprop (NewFitHeader, TianoNode, 'data-size')[0], 'big') + TianoBinary = Dtb[TianoOffset:TianoOffset + TianoSize] + + print("\nGenerate new fit image:") + NewUplBinary = bytearray(FitSize) + print("Update fit header\t to 0x0\t\t ~ " + str(hex(len(NewFitHeader)))) + NewUplBinary[:len(NewFitHeader)] = NewFitHeader + print("Update tiano image\t to " + str(hex(len(NewFitHeader))) + "\t ~ " + str(hex(len(NewFitHeader) + len(TianoBinary)))) + NewUplBinary[len(NewFitHeader):len(NewFitHeader) + len(TianoBinary)] = TianoBinary + for Index in range (0, len (MultiFvList)): + ImageNode = libfdt.fdt_subnode_offset(NewFitHeader, ImagesNode, MultiFvList[Index][0]) + ImageOffset = int.from_bytes (libfdt.fdt_getprop (NewFitHeader, ImageNode, 'data-offset')[0], 'big') + ImageSize = int.from_bytes (libfdt.fdt_getprop (NewFitHeader, ImageNode, 'data-size')[0], 'big') + NewUplBinary[ImageOffset:ImageOffset + ImageSize] = MultiFvList[Index][1] + print("Update " + MultiFvList[Index][0] + "\t\t to " + str(hex(ImageOffset)) + "\t ~ " + str(hex(ImageOffset + ImageSize))) + + with open (UplBinary, "wb") as File: + File.write (NewUplBinary) + + return 0 + except Exception as Ex: + print(Ex) + return 1 diff --git a/UefiPayloadPkg/UefiPayloadEntry/FitUniversalPayloadEntry.c b/UefiPayloadPkg/UefiPayloadEntry/FitUniversalPayloadEntry.c new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/UefiPayloadPkg/UefiPayloadEntry/FitUniversalPayloadEntry.c @@ -XXX,XX +XXX,XX @@ +/** @file + Copyright (c) 2023, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include "UefiPayloadEntry.h" +#include <Library/FdtLib.h> +#include <Guid/UniversalPayloadBase.h> + +#define MEMORY_ATTRIBUTE_MASK (EFI_RESOURCE_ATTRIBUTE_PRESENT | \ + EFI_RESOURCE_ATTRIBUTE_INITIALIZED | \ + EFI_RESOURCE_ATTRIBUTE_TESTED | \ + EFI_RESOURCE_ATTRIBUTE_READ_PROTECTED | \ + EFI_RESOURCE_ATTRIBUTE_WRITE_PROTECTED | \ + EFI_RESOURCE_ATTRIBUTE_EXECUTION_PROTECTED | \ + EFI_RESOURCE_ATTRIBUTE_READ_ONLY_PROTECTED | \ + EFI_RESOURCE_ATTRIBUTE_16_BIT_IO | \ + EFI_RESOURCE_ATTRIBUTE_32_BIT_IO | \ + EFI_RESOURCE_ATTRIBUTE_64_BIT_IO | \ + EFI_RESOURCE_ATTRIBUTE_PERSISTENT ) + +#define TESTED_MEMORY_ATTRIBUTES (EFI_RESOURCE_ATTRIBUTE_PRESENT | \ + EFI_RESOURCE_ATTRIBUTE_INITIALIZED | \ + EFI_RESOURCE_ATTRIBUTE_TESTED ) + +extern VOID *mHobList; + +CHAR8 *mLineBuffer = NULL; + +/** + Print all HOBs info from the HOB list. + @return The pointer to the HOB list. +**/ +VOID +PrintHob ( + IN CONST VOID *HobStart + ); + +/** + Find the first substring. + @param String Point to the string where to find the substring. + @param CharSet Point to the string to be found. +**/ +UINTN +EFIAPI +AsciiStrSpn ( + IN CHAR8 *String, + IN CHAR8 *CharSet + ) +{ + UINTN Count; + CHAR8 *Str1; + CHAR8 *Str2; + + Count = 0; + + for (Str1 = String; *Str1 != L'\0'; Str1++) { + for (Str2 = CharSet; *Str2 != L'\0'; Str2++) { + if (*Str1 == *Str2) { + break; + } + } + + if (*Str2 == L'\0') { + return Count; + } + + Count++; + } + + return Count; +} + +/** + Searches a string for the first occurrence of a character contained in a + specified buffer. + @param String Point to the string where to find the substring. + @param CharSet Point to the string to be found. +**/ +CHAR8 * +EFIAPI +AsciiStrBrk ( + IN CHAR8 *String, + IN CHAR8 *CharSet + ) +{ + CHAR8 *Str1; + CHAR8 *Str2; + + for (Str1 = String; *Str1 != L'\0'; Str1++) { + for (Str2 = CharSet; *Str2 != L'\0'; Str2++) { + if (*Str1 == *Str2) { + return (CHAR8 *)Str1; + } + } + } + + return NULL; +} + +/** + Find the next token after one or more specified characters. + @param String Point to the string where to find the substring. + @param CharSet Point to the string to be found. +**/ +CHAR8 * +EFIAPI +AsciiStrTokenLine ( + IN CHAR8 *String OPTIONAL, + IN CHAR8 *CharSet + ) +{ + CHAR8 *Begin; + CHAR8 *End; + + Begin = (String == NULL) ? mLineBuffer : String; + if (Begin == NULL) { + return NULL; + } + + Begin += AsciiStrSpn (Begin, CharSet); + if (*Begin == L'\0') { + mLineBuffer = NULL; + return NULL; + } + + End = AsciiStrBrk (Begin, CharSet); + if ((End != NULL) && (*End != L'\0')) { + *End = L'\0'; + End++; + } + + mLineBuffer = End; + return Begin; +} + +/** + Some bootloader may pass a pcd database, and UPL also contain a PCD database. + Dxe PCD driver has the assumption that the two PCD database can be catenated and + the local token number should be successive. + This function will fix up the UPL PCD database to meet that assumption. + @param[in] DxeFv The FV where to find the Universal PCD database. + @retval EFI_SUCCESS If it completed successfully. + @retval other Failed to fix up. +**/ +EFI_STATUS +FixUpPcdDatabase ( + IN EFI_FIRMWARE_VOLUME_HEADER *DxeFv + ) +{ + EFI_STATUS Status; + EFI_FFS_FILE_HEADER *FileHeader; + VOID *PcdRawData; + PEI_PCD_DATABASE *PeiDatabase; + PEI_PCD_DATABASE *UplDatabase; + EFI_HOB_GUID_TYPE *GuidHob; + DYNAMICEX_MAPPING *ExMapTable; + UINTN Index; + + GuidHob = GetFirstGuidHob (&gPcdDataBaseHobGuid); + if (GuidHob == NULL) { + // + // No fix-up is needed. + // + return EFI_SUCCESS; + } + + PeiDatabase = (PEI_PCD_DATABASE *)GET_GUID_HOB_DATA (GuidHob); + DEBUG ((DEBUG_INFO, "Find the Pei PCD data base, the total local token number is %d\n", PeiDatabase->LocalTokenCount)); + + Status = FvFindFileByTypeGuid (DxeFv, EFI_FV_FILETYPE_DRIVER, PcdGetPtr (PcdPcdDriverFile), &FileHeader); + ASSERT_EFI_ERROR (Status); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = FileFindSection (FileHeader, EFI_SECTION_RAW, &PcdRawData); + ASSERT_EFI_ERROR (Status); + if (EFI_ERROR (Status)) { + return Status; + } + + UplDatabase = (PEI_PCD_DATABASE *)PcdRawData; + ExMapTable = (DYNAMICEX_MAPPING *)(UINTN)((UINTN)PcdRawData + UplDatabase->ExMapTableOffset); + + for (Index = 0; Index < UplDatabase->ExTokenCount; Index++) { + ExMapTable[Index].TokenNumber += PeiDatabase->LocalTokenCount; + } + + DEBUG ((DEBUG_INFO, "Fix up UPL PCD database successfully\n")); + return EFI_SUCCESS; +} + +/** + Add HOB into HOB list + @param[in] Hob The HOB to be added into the HOB list. +**/ +VOID +AddNewHob ( + IN EFI_PEI_HOB_POINTERS *Hob + ) +{ + EFI_PEI_HOB_POINTERS NewHob; + + if (Hob->Raw == NULL) { + return; + } + + NewHob.Header = CreateHob (Hob->Header->HobType, Hob->Header->HobLength); + + if (NewHob.Header != NULL) { + CopyMem (NewHob.Header + 1, Hob->Header + 1, Hob->Header->HobLength - sizeof (EFI_HOB_GENERIC_HEADER)); + } +} + +/** + Found the Resource Descriptor HOB that contains a range (Base, Top) + @param[in] HobList Hob start address + @param[in] Base Memory start address + @param[in] Top Memory end address. + @retval The pointer to the Resource Descriptor HOB. +**/ +EFI_HOB_RESOURCE_DESCRIPTOR * +FindResourceDescriptorByRange ( + IN VOID *HobList, + IN EFI_PHYSICAL_ADDRESS Base, + IN EFI_PHYSICAL_ADDRESS Top + ) +{ + EFI_PEI_HOB_POINTERS Hob; + EFI_HOB_RESOURCE_DESCRIPTOR *ResourceHob; + + for (Hob.Raw = (UINT8 *)HobList; !END_OF_HOB_LIST (Hob); Hob.Raw = GET_NEXT_HOB (Hob)) { + // + // Skip all HOBs except Resource Descriptor HOBs + // + if (GET_HOB_TYPE (Hob) != EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) { + continue; + } + + // + // Skip Resource Descriptor HOBs that do not describe tested system memory + // + ResourceHob = Hob.ResourceDescriptor; + if (ResourceHob->ResourceType != EFI_RESOURCE_SYSTEM_MEMORY) { + continue; + } + + if ((ResourceHob->ResourceAttribute & MEMORY_ATTRIBUTE_MASK) != TESTED_MEMORY_ATTRIBUTES) { + continue; + } + + // + // Skip Resource Descriptor HOBs that do not contain the PHIT range EfiFreeMemoryBottom..EfiFreeMemoryTop + // + if (Base < ResourceHob->PhysicalStart) { + continue; + } + + if (Top > (ResourceHob->PhysicalStart + ResourceHob->ResourceLength)) { + continue; + } + + return ResourceHob; + } + + return NULL; +} + +/** + Find the highest below 4G memory resource descriptor, except the input Resource Descriptor. + @param[in] HobList Hob start address + @param[in] MinimalNeededSize Minimal needed size. + @param[in] ExceptResourceHob Ignore this Resource Descriptor. + @retval The pointer to the Resource Descriptor HOB. +**/ +EFI_HOB_RESOURCE_DESCRIPTOR * +FindAnotherHighestBelow4GResourceDescriptor ( + IN VOID *HobList, + IN UINTN MinimalNeededSize, + IN EFI_HOB_RESOURCE_DESCRIPTOR *ExceptResourceHob + ) +{ + EFI_PEI_HOB_POINTERS Hob; + EFI_HOB_RESOURCE_DESCRIPTOR *ResourceHob; + EFI_HOB_RESOURCE_DESCRIPTOR *ReturnResourceHob; + + ReturnResourceHob = NULL; + + for (Hob.Raw = (UINT8 *)HobList; !END_OF_HOB_LIST (Hob); Hob.Raw = GET_NEXT_HOB (Hob)) { + // + // Skip all HOBs except Resource Descriptor HOBs + // + if (GET_HOB_TYPE (Hob) != EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) { + continue; + } + + // + // Skip Resource Descriptor HOBs that do not describe tested system memory + // + ResourceHob = Hob.ResourceDescriptor; + if (ResourceHob->ResourceType != EFI_RESOURCE_SYSTEM_MEMORY) { + continue; + } + + if ((ResourceHob->ResourceAttribute & MEMORY_ATTRIBUTE_MASK) != TESTED_MEMORY_ATTRIBUTES) { + continue; + } + + // + // Skip if the Resource Descriptor HOB equals to ExceptResourceHob + // + if (ResourceHob == ExceptResourceHob) { + continue; + } + + // + // Skip Resource Descriptor HOBs that are beyond 4G + // + if ((ResourceHob->PhysicalStart + ResourceHob->ResourceLength) > BASE_4GB) { + continue; + } + + // + // Skip Resource Descriptor HOBs that are too small + // + if (ResourceHob->ResourceLength < MinimalNeededSize) { + continue; + } + + // + // Return the topest Resource Descriptor + // + if (ReturnResourceHob == NULL) { + ReturnResourceHob = ResourceHob; + } else { + if (ReturnResourceHob->PhysicalStart < ResourceHob->PhysicalStart) { + ReturnResourceHob = ResourceHob; + } + } + } + + return ReturnResourceHob; +} + +/** + Check the HOB and decide if it is need inside Payload + Payload maintainer may make decision which HOB is need or needn't + Then add the check logic in the function. + @param[in] Hob The HOB to check + @retval TRUE If HOB is need inside Payload + @retval FALSE If HOB is needn't inside Payload +**/ +BOOLEAN +IsHobNeed ( + EFI_PEI_HOB_POINTERS Hob + ) +{ + if (Hob.Header->HobType == EFI_HOB_TYPE_HANDOFF) { + return FALSE; + } + + if (Hob.Header->HobType == EFI_HOB_TYPE_MEMORY_ALLOCATION) { + if (CompareGuid (&Hob.MemoryAllocationModule->MemoryAllocationHeader.Name, &gEfiHobMemoryAllocModuleGuid)) { + return FALSE; + } + } + + // Arrive here mean the HOB is need + return TRUE; +} + +/** + It will build Fv HOBs based on information from bootloaders. + @param[out] DxeFv The pointer to the DXE FV in memory. + @retval EFI_SUCCESS If it completed successfully. + @retval EFI_NOT_FOUND If it failed to find node in fit image. + @retval Others If it failed to build required HOBs. +**/ +EFI_STATUS +BuildFitLoadablesFvHob ( + OUT EFI_FIRMWARE_VOLUME_HEADER **DxeFv + ) +{ + EFI_STATUS Status; + VOID *Fdt; + UINT8 *GuidHob; + UNIVERSAL_PAYLOAD_BASE *PayloadBase; + INT32 ConfigNode; + INT32 Config1Node; + INT32 ImageNode; + INT32 FvNode; + INT32 Depth; + CONST FDT_PROPERTY *PropertyPtr; + INT32 TempLen; + CONST CHAR8 *Fvname; + UINT32 DataOffset; + UINT32 DataSize; + UINT32 *Data32; + + GuidHob = GetFirstGuidHob (&gUniversalPayloadBaseGuid); + if (GuidHob != NULL) { + PayloadBase = (UNIVERSAL_PAYLOAD_BASE *)GET_GUID_HOB_DATA (GuidHob); + Fdt = (VOID *)(UINTN)PayloadBase->Entry; + DEBUG ((DEBUG_INFO, "PayloadBase Entry = 0x%08x\n", PayloadBase->Entry)); + } + + Status = FdtCheckHeader (Fdt); + if (EFI_ERROR (Status)) { + return EFI_UNSUPPORTED; + } + + ConfigNode = FdtSubnodeOffsetNameLen (Fdt, 0, "configurations", (INT32)AsciiStrLen ("configurations")); + if (ConfigNode <= 0) { + return EFI_NOT_FOUND; + } + + Config1Node = FdtSubnodeOffsetNameLen (Fdt, ConfigNode, "conf-1", (INT32)AsciiStrLen ("conf-1")); + if (Config1Node <= 0) { + return EFI_NOT_FOUND; + } + + ImageNode = FdtSubnodeOffsetNameLen (Fdt, 0, "images", (INT32)AsciiStrLen ("images")); + if (ImageNode <= 0) { + return EFI_NOT_FOUND; + } + + FvNode = FdtSubnodeOffsetNameLen (Fdt, ImageNode, "tianocore", (INT32)AsciiStrLen ("tianocore")); + Depth = FdtNodeDepth (Fdt, FvNode); + FvNode = FdtNextNode (Fdt, FvNode, &Depth); + Fvname = FdtGetName (Fdt, FvNode, &TempLen); + while ((AsciiStrCmp ((Fvname + AsciiStrLen (Fvname) - 2), "fv") == 0)) { + if (FvNode <= 0) { + return EFI_NOT_FOUND; + } + + PropertyPtr = FdtGetProperty (Fdt, FvNode, "data-offset", &TempLen); + Data32 = (UINT32 *)(PropertyPtr->Data); + DataOffset = SwapBytes32 (*Data32); + + PropertyPtr = FdtGetProperty (Fdt, FvNode, "data-size", &TempLen); + Data32 = (UINT32 *)(PropertyPtr->Data); + DataSize = SwapBytes32 (*Data32); + + if (AsciiStrCmp (Fvname, "uefi-fv") == 0) { + *DxeFv = (EFI_FIRMWARE_VOLUME_HEADER *)((UINTN)PayloadBase->Entry + (UINTN)DataOffset); + ASSERT ((*DxeFv)->FvLength == DataSize); + } else { + BuildFvHob (((UINTN)PayloadBase->Entry + (UINTN)DataOffset), DataSize); + } + + DEBUG (( + DEBUG_INFO, + "UPL Multiple fv[%a], Base=0x%08x, size=0x%08x\n", + Fvname, + ((UINTN)PayloadBase->Entry + (UINTN)DataOffset), + DataSize, + DataOffset + )); + Depth = FdtNodeDepth (Fdt, FvNode); + FvNode = FdtNextNode (Fdt, FvNode, &Depth); + Fvname = FdtGetName (Fdt, FvNode, &TempLen); + } + + return EFI_SUCCESS; +} + +/** + It will build HOBs based on information from bootloaders. + @param[in] BootloaderParameter The starting memory address of bootloader parameter block. + @param[out] DxeFv The pointer to the DXE FV in memory. + @retval EFI_SUCCESS If it completed successfully. + @retval Others If it failed to build required HOBs. +**/ +EFI_STATUS +BuildHobs ( + IN UINTN BootloaderParameter, + OUT EFI_FIRMWARE_VOLUME_HEADER **DxeFv + ) +{ + EFI_PEI_HOB_POINTERS Hob; + UINTN MinimalNeededSize; + EFI_PHYSICAL_ADDRESS FreeMemoryBottom; + EFI_PHYSICAL_ADDRESS FreeMemoryTop; + EFI_PHYSICAL_ADDRESS MemoryBottom; + EFI_PHYSICAL_ADDRESS MemoryTop; + EFI_HOB_RESOURCE_DESCRIPTOR *PhitResourceHob; + EFI_HOB_RESOURCE_DESCRIPTOR *ResourceHob; + UINT8 *GuidHob; + EFI_HOB_FIRMWARE_VOLUME *FvHob; + UNIVERSAL_PAYLOAD_ACPI_TABLE *AcpiTable; + ACPI_BOARD_INFO *AcpiBoardInfo; + EFI_HOB_HANDOFF_INFO_TABLE *HobInfo; + + Hob.Raw = (UINT8 *)BootloaderParameter; + MinimalNeededSize = FixedPcdGet32 (PcdSystemMemoryUefiRegionSize); + + ASSERT (Hob.Raw != NULL); + ASSERT ((UINTN)Hob.HandoffInformationTable->EfiFreeMemoryTop == Hob.HandoffInformationTable->EfiFreeMemoryTop); + ASSERT ((UINTN)Hob.HandoffInformationTable->EfiMemoryTop == Hob.HandoffInformationTable->EfiMemoryTop); + ASSERT ((UINTN)Hob.HandoffInformationTable->EfiFreeMemoryBottom == Hob.HandoffInformationTable->EfiFreeMemoryBottom); + ASSERT ((UINTN)Hob.HandoffInformationTable->EfiMemoryBottom == Hob.HandoffInformationTable->EfiMemoryBottom); + + // + // Try to find Resource Descriptor HOB that contains Hob range EfiMemoryBottom..EfiMemoryTop + // + PhitResourceHob = FindResourceDescriptorByRange (Hob.Raw, Hob.HandoffInformationTable->EfiMemoryBottom, Hob.HandoffInformationTable->EfiMemoryTop); + if (PhitResourceHob == NULL) { + // + // Boot loader's Phit Hob is not in an available Resource Descriptor, find another Resource Descriptor for new Phit Hob + // + ResourceHob = FindAnotherHighestBelow4GResourceDescriptor (Hob.Raw, MinimalNeededSize, NULL); + if (ResourceHob == NULL) { + return EFI_NOT_FOUND; + } + + MemoryBottom = ResourceHob->PhysicalStart + ResourceHob->ResourceLength - MinimalNeededSize; + FreeMemoryBottom = MemoryBottom; + FreeMemoryTop = ResourceHob->PhysicalStart + ResourceHob->ResourceLength; + MemoryTop = FreeMemoryTop; + } else if (PhitResourceHob->PhysicalStart + PhitResourceHob->ResourceLength - Hob.HandoffInformationTable->EfiMemoryTop >= MinimalNeededSize) { + // + // New availiable Memory range in new hob is right above memory top in old hob. + // + MemoryBottom = Hob.HandoffInformationTable->EfiFreeMemoryTop; + FreeMemoryBottom = Hob.HandoffInformationTable->EfiMemoryTop; + FreeMemoryTop = FreeMemoryBottom + MinimalNeededSize; + MemoryTop = FreeMemoryTop; + } else if (Hob.HandoffInformationTable->EfiMemoryBottom - PhitResourceHob->PhysicalStart >= MinimalNeededSize) { + // + // New availiable Memory range in new hob is right below memory bottom in old hob. + // + MemoryBottom = Hob.HandoffInformationTable->EfiMemoryBottom - MinimalNeededSize; + FreeMemoryBottom = MemoryBottom; + FreeMemoryTop = Hob.HandoffInformationTable->EfiMemoryBottom; + MemoryTop = Hob.HandoffInformationTable->EfiMemoryTop; + } else { + // + // In the Resource Descriptor HOB contains boot loader Hob, there is no enough free memory size for payload hob + // Find another Resource Descriptor Hob + // + ResourceHob = FindAnotherHighestBelow4GResourceDescriptor (Hob.Raw, MinimalNeededSize, PhitResourceHob); + if (ResourceHob == NULL) { + return EFI_NOT_FOUND; + } + + MemoryBottom = ResourceHob->PhysicalStart + ResourceHob->ResourceLength - MinimalNeededSize; + FreeMemoryBottom = MemoryBottom; + FreeMemoryTop = ResourceHob->PhysicalStart + ResourceHob->ResourceLength; + MemoryTop = FreeMemoryTop; + } + + HobInfo = HobConstructor ((VOID *)(UINTN)MemoryBottom, (VOID *)(UINTN)MemoryTop, (VOID *)(UINTN)FreeMemoryBottom, (VOID *)(UINTN)FreeMemoryTop); + HobInfo->BootMode = Hob.HandoffInformationTable->BootMode; + // + // From now on, mHobList will point to the new Hob range. + // + + // + // Create an empty FvHob for the DXE FV that contains DXE core. + // + BuildFvHob ((EFI_PHYSICAL_ADDRESS)0, 0); + // + // Since payload created new Hob, move all hobs except PHIT from boot loader hob list. + // + while (!END_OF_HOB_LIST (Hob)) { + if (IsHobNeed (Hob)) { + // Add this hob to payload HOB + AddNewHob (&Hob); + } + + Hob.Raw = GET_NEXT_HOB (Hob); + } + + BuildFitLoadablesFvHob (DxeFv); + + // + // Create guid hob for acpi board information + // + GuidHob = GetFirstGuidHob (&gUniversalPayloadAcpiTableGuid); + if (GuidHob != NULL) { + AcpiTable = (UNIVERSAL_PAYLOAD_ACPI_TABLE *)GET_GUID_HOB_DATA (GuidHob); + GuidHob = GetFirstGuidHob (&gUefiAcpiBoardInfoGuid); + if (GuidHob == NULL) { + AcpiBoardInfo = BuildHobFromAcpi ((UINT64)AcpiTable->Rsdp); + ASSERT (AcpiBoardInfo != NULL); + } + } + + // + // Update DXE FV information to first fv hob in the hob list, which + // is the empty FvHob created before. + // + FvHob = GetFirstHob (EFI_HOB_TYPE_FV); + FvHob->BaseAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)*DxeFv; + FvHob->Length = (*DxeFv)->FvLength; + return EFI_SUCCESS; +} + +/** + Entry point to the C language phase of UEFI payload. + @param[in] BootloaderParameter The starting address of bootloader parameter block. + @retval It will not return if SUCCESS, and return error when passing bootloader parameter. +**/ +EFI_STATUS +EFIAPI +_ModuleEntryPoint ( + IN UINTN BootloaderParameter + ) +{ + EFI_STATUS Status; + PHYSICAL_ADDRESS DxeCoreEntryPoint; + EFI_PEI_HOB_POINTERS Hob; + EFI_FIRMWARE_VOLUME_HEADER *DxeFv; + + mHobList = (VOID *)BootloaderParameter; + DxeFv = NULL; + // Call constructor for all libraries + ProcessLibraryConstructorList (); + + DEBUG ((DEBUG_INFO, "Entering Universal Payload...\n")); + DEBUG ((DEBUG_INFO, "sizeof(UINTN) = 0x%x\n", sizeof (UINTN))); + + DEBUG_CODE ( + // + // Dump the Hobs from boot loader + // + PrintHob (mHobList); + ); + + // Initialize floating point operating environment to be compliant with UEFI spec. + InitializeFloatingPointUnits (); + + // Build HOB based on information from Bootloader + Status = BuildHobs (BootloaderParameter, &DxeFv); + ASSERT_EFI_ERROR (Status); + + FixUpPcdDatabase (DxeFv); + Status = UniversalLoadDxeCore (DxeFv, &DxeCoreEntryPoint); + ASSERT_EFI_ERROR (Status); + + // + // Mask off all legacy 8259 interrupt sources + // + IoWrite8 (LEGACY_8259_MASK_REGISTER_MASTER, 0xFF); + IoWrite8 (LEGACY_8259_MASK_REGISTER_SLAVE, 0xFF); + + Hob.HandoffInformationTable = (EFI_HOB_HANDOFF_INFO_TABLE *)GetFirstHob (EFI_HOB_TYPE_HANDOFF); + HandOffToDxeCore (DxeCoreEntryPoint, Hob); + + // Should not get here + CpuDeadLoop (); + return EFI_SUCCESS; +} diff --git a/UefiPayloadPkg/UefiPayloadEntry/FitUniversalPayloadEntry.inf b/UefiPayloadPkg/UefiPayloadEntry/FitUniversalPayloadEntry.inf new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/UefiPayloadPkg/UefiPayloadEntry/FitUniversalPayloadEntry.inf @@ -XXX,XX +XXX,XX @@ +## @file +# This is the first module for UEFI payload. +# +# Copyright (c) 2023, Intel Corporation. All rights reserved.<BR> +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = FitUniversalPayloadEntry + FILE_GUID = CED5A8A9-B6EA-4D5A-8689-577EE88566CF + MODULE_TYPE = SEC + VERSION_STRING = 1.0 + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 +# + +[Sources] + FitUniversalPayloadEntry.c + LoadDxeCore.c + MemoryAllocation.c + PrintHob.c + AcpiTable.c + +[Sources.Ia32] + X64/VirtualMemory.h + X64/VirtualMemory.c + Ia32/DxeLoadFunc.c + Ia32/IdtVectorAsm.nasm + +[Sources.X64] + X64/VirtualMemory.h + X64/VirtualMemory.c + X64/DxeLoadFunc.c + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + UefiCpuPkg/UefiCpuPkg.dec + UefiPayloadPkg/UefiPayloadPkg.dec + +[LibraryClasses] + BaseMemoryLib + DebugLib + BaseLib + SerialPortLib + IoLib + HobLib + PeCoffLib + CpuLib + FdtLib + +[Guids] + gEfiMemoryTypeInformationGuid + gEfiFirmwareFileSystem2Guid + gEfiGraphicsInfoHobGuid + gEfiGraphicsDeviceInfoHobGuid + gUefiAcpiBoardInfoGuid + gEfiSmbiosTableGuid + gUefiSerialPortInfoGuid + gUniversalPayloadExtraDataGuid + gUniversalPayloadBaseGuid + gPcdDataBaseHobGuid + gUniversalPayloadSmbiosTableGuid + gEfiHobMemoryAllocBspStoreGuid + gUniversalPayloadAcpiTableGuid + gUniversalPayloadPciRootBridgeInfoGuid + gUniversalPayloadSmbios3TableGuid + +[FeaturePcd.IA32] + gEfiMdeModulePkgTokenSpaceGuid.PcdDxeIplSwitchToLongMode ## CONSUMES + +[FeaturePcd.X64] + gEfiMdeModulePkgTokenSpaceGuid.PcdDxeIplBuildPageTables ## CONSUMES + + +[Pcd.IA32,Pcd.X64] + gUefiPayloadPkgTokenSpaceGuid.PcdPcdDriverFile + gEfiMdeModulePkgTokenSpaceGuid.PcdUse1GPageTable ## SOMETIMES_CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdPteMemoryEncryptionAddressOrMask ## CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdNullPointerDetectionPropertyMask ## CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdHeapGuardPropertyMask ## CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdCpuStackGuard ## CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdGhcbBase ## CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdGhcbSize ## CONSUMES + + gUefiPayloadPkgTokenSpaceGuid.PcdPayloadFdMemBase + gUefiPayloadPkgTokenSpaceGuid.PcdPayloadFdMemSize + gUefiPayloadPkgTokenSpaceGuid.PcdSystemMemoryUefiRegionSize + + gEfiMdeModulePkgTokenSpaceGuid.PcdSetNxForStack ## SOMETIMES_CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdDxeNxMemoryProtectionPolicy ## SOMETIMES_CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdImageProtectionPolicy ## SOMETIMES_CONSUMES diff --git a/UefiPayloadPkg/UefiPayloadPkg.dec b/UefiPayloadPkg/UefiPayloadPkg.dec index XXXXXXX..XXXXXXX 100644 --- a/UefiPayloadPkg/UefiPayloadPkg.dec +++ b/UefiPayloadPkg/UefiPayloadPkg.dec @@ -XXX,XX +XXX,XX @@ # gUefiPayloadPkgTokenSpaceGuid = {0x1d127ea, 0xf6f1, 0x4ef6, {0x94, 0x15, 0x8a, 0x0, 0x0, 0x93, 0xf8, 0x9d}} + ## Include/Guid/UniversalPayloadBase.h + gUniversalPayloadBaseGuid = { 0x03d4c61d, 0x2713, 0x4ec5, {0xa1, 0xcc, 0x88, 0x3b, 0xe9, 0xdc, 0x18, 0xe5 } } + # # Gop Temp # diff --git a/UefiPayloadPkg/UefiPayloadPkg.dsc b/UefiPayloadPkg/UefiPayloadPkg.dsc index XXXXXXX..XXXXXXX 100644 --- a/UefiPayloadPkg/UefiPayloadPkg.dsc +++ b/UefiPayloadPkg/UefiPayloadPkg.dsc @@ -XXX,XX +XXX,XX @@ DEFINE PS2_KEYBOARD_ENABLE = FALSE DEFINE RAM_DISK_ENABLE = FALSE DEFINE SIO_BUS_ENABLE = FALSE - DEFINE UNIVERSAL_PAYLOAD = FALSE DEFINE SECURITY_STUB_ENABLE = TRUE DEFINE SMM_SUPPORT = FALSE DEFINE PLATFORM_BOOT_TIMEOUT = 3 @@ -XXX,XX +XXX,XX @@ DEFINE BOOTSPLASH_IMAGE = FALSE DEFINE NVME_ENABLE = TRUE DEFINE CAPSULE_SUPPORT = FALSE + # + # Setup Universal Payload + # + # ELF: Build UniversalPayload file as UniversalPayload.elf + # FIT: Build UniversalPayload file as UniversalPayload.fit + # + DEFINE UNIVERSAL_PAYLOAD = FALSE + DEFINE UNIVERSAL_PAYLOAD_FORMAT = ELF # # NULL: NullMemoryTestDxe @@ -XXX,XX +XXX,XX @@ VariableFlashInfoLib|MdeModulePkg/Library/BaseVariableFlashInfoLib/BaseVariableFlashInfoLib.inf CcExitLib|UefiCpuPkg/Library/CcExitLibNull/CcExitLibNull.inf ReportStatusCodeLib|MdeModulePkg/Library/DxeReportStatusCodeLib/DxeReportStatusCodeLib.inf - + FdtLib|MdePkg/Library/BaseFdtLib/BaseFdtLib.inf [LibraryClasses.common] !if $(BOOTSPLASH_IMAGE) SafeIntLib|MdePkg/Library/BaseSafeIntLib/BaseSafeIntLib.inf @@ -XXX,XX +XXX,XX @@ !if "IA32" in "$(ARCH)" [Components.IA32] !if $(UNIVERSAL_PAYLOAD) == TRUE - UefiPayloadPkg/UefiPayloadEntry/UniversalPayloadEntry.inf + !if $(UNIVERSAL_PAYLOAD_FORMAT) == "ELF" + UefiPayloadPkg/UefiPayloadEntry/UniversalPayloadEntry.inf + !elseif $(UNIVERSAL_PAYLOAD_FORMAT) == "FIT" + UefiPayloadPkg/UefiPayloadEntry/FitUniversalPayloadEntry.inf + !else + UefiPayloadPkg/UefiPayloadEntry/UefiPayloadEntry.inf + !endif !else UefiPayloadPkg/UefiPayloadEntry/UefiPayloadEntry.inf !endif !else [Components.X64] !if $(UNIVERSAL_PAYLOAD) == TRUE - UefiPayloadPkg/UefiPayloadEntry/UniversalPayloadEntry.inf + !if $(UNIVERSAL_PAYLOAD_FORMAT) == "ELF" + UefiPayloadPkg/UefiPayloadEntry/UniversalPayloadEntry.inf + !elseif $(UNIVERSAL_PAYLOAD_FORMAT) == "FIT" + UefiPayloadPkg/UefiPayloadEntry/FitUniversalPayloadEntry.inf + !else + UefiPayloadPkg/UefiPayloadEntry/UefiPayloadEntry.inf + !endif !else UefiPayloadPkg/UefiPayloadEntry/UefiPayloadEntry.inf !endif diff --git a/UefiPayloadPkg/UniversalPayloadBuild.py b/UefiPayloadPkg/UniversalPayloadBuild.py index XXXXXXX..XXXXXXX 100644 --- a/UefiPayloadPkg/UniversalPayloadBuild.py +++ b/UefiPayloadPkg/UniversalPayloadBuild.py @@ -XXX,XX +XXX,XX @@ import subprocess import os import shutil import sys +import pathlib from ctypes import * -from Tools.ElfFv import ReplaceFv + sys.dont_write_bytecode = True +class bcolors: + HEADER = '\033[95m' + OKBLUE = '\033[94m' + OKCYAN = '\033[96m' + OKGREEN = '\033[92m' + WARNING = '\033[93m' + FAIL = '\033[91m' + ENDC = '\033[0m' + BOLD = '\033[1m' + UNDERLINE = '\033[4m' + class UPLD_INFO_HEADER(LittleEndianStructure): _pack_ = 1 _fields_ = [ @@ -XXX,XX +XXX,XX @@ class UPLD_INFO_HEADER(LittleEndianStructure): self.ImageId = b'UEFI' self.ProducerId = b'INTEL' -def BuildUniversalPayload(Args): - def RunCommand(cmd): - print(cmd) - p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT,cwd=os.environ['WORKSPACE']) - while True: - line = p.stdout.readline() - if not line: - break - print(line.strip().decode(errors='ignore')) - - p.communicate() - if p.returncode != 0: - print("- Failed - error happened when run command: %s"%cmd) - raise Exception("ERROR: when run command: %s"%cmd) +def ValidateSpecRevision (Argument): + try: + (MajorStr, MinorStr) = Argument.split('.') + except: + raise argparse.ArgumentTypeError ('{} is not a valid SpecRevision format (Major[8-bits].Minor[8-bits]).'.format (Argument)) + # + # Spec Revision Bits 15 : 8 - Major Version. Bits 7 : 0 - Minor Version. + # + if len(MinorStr) > 0 and len(MinorStr) < 3: + try: + Minor = int(MinorStr, 16) if len(MinorStr) == 2 else (int(MinorStr, 16) << 4) + except: + raise argparse.ArgumentTypeError ('{} Minor version of SpecRevision is not a valid integer value.'.format (Argument)) + else: + raise argparse.ArgumentTypeError ('{} is not a valid SpecRevision format (Major[8-bits].Minor[8-bits]).'.format (Argument)) + + if len(MajorStr) > 0 and len(MajorStr) < 3: + try: + Major = int(MajorStr, 16) + except: + raise argparse.ArgumentTypeError ('{} Major version of SpecRevision is not a valid integer value.'.format (Argument)) + else: + raise argparse.ArgumentTypeError ('{} is not a valid SpecRevision format (Major[8-bits].Minor[8-bits]).'.format (Argument)) + + return int('0x{0:02x}{1:02x}'.format(Major, Minor), 0) + +def Validate32BitInteger (Argument): + try: + Value = int (Argument, 0) + except: + raise argparse.ArgumentTypeError ('{} is not a valid integer value.'.format (Argument)) + if Value < 0: + raise argparse.ArgumentTypeError ('{} is a negative value.'.format (Argument)) + if Value > 0xffffffff: + raise argparse.ArgumentTypeError ('{} is larger than 32-bits.'.format (Argument)) + return Value +def ValidateAddFv (Argument): + Value = Argument.split ("=") + if len (Value) != 2: + raise argparse.ArgumentTypeError ('{} is incorrect format with "xxx_fv=xxx.fv"'.format (Argument)) + if Value[0][-3:] != "_fv": + raise argparse.ArgumentTypeError ('{} is incorrect format with "xxx_fv=xxx.fv"'.format (Argument)) + if Value[1][-3:].lower () != ".fv": + raise argparse.ArgumentTypeError ('{} is incorrect format with "xxx_fv=xxx.fv"'.format (Argument)) + if os.path.exists (Value[1]) == False: + raise argparse.ArgumentTypeError ('File {} is not found.'.format (Value[1])) + return Value + +def RunCommand(cmd): + print(cmd) + p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT,cwd=os.environ['WORKSPACE']) + while True: + line = p.stdout.readline() + if not line: + break + print(line.strip().decode(errors='ignore')) + + p.communicate() + if p.returncode != 0: + print("- Failed - error happened when run command: %s"%cmd) + raise Exception("ERROR: when run command: %s"%cmd) + +def BuildUniversalPayload(Args): BuildTarget = Args.Target ToolChain = Args.ToolChain Quiet = "--quiet" if Args.Quiet else "" - ElfToolChain = 'CLANGDWARF' - BuildDir = os.path.join(os.environ['WORKSPACE'], os.path.normpath("Build/UefiPayloadPkgX64")) - BuildModule = "" - BuildArch = "" + if Args.Fit == True: + PayloadEntryToolChain = ToolChain + Args.Macro.append("UNIVERSAL_PAYLOAD_FORMAT=FIT") + UpldEntryFile = "FitUniversalPayloadEntry" + else: + PayloadEntryToolChain = 'CLANGDWARF' + Args.Macro.append("UNIVERSAL_PAYLOAD_FORMAT=ELF") + UpldEntryFile = "UniversalPayloadEntry" + + BuildDir = os.path.join(os.environ['WORKSPACE'], os.path.normpath("Build/UefiPayloadPkgX64")) if Args.Arch == 'X64': BuildArch = "X64" - EntryOutputDir = os.path.join(BuildDir, "{}_{}".format (BuildTarget, ElfToolChain), os.path.normpath("X64/UefiPayloadPkg/UefiPayloadEntry/UniversalPayloadEntry/DEBUG/UniversalPayloadEntry.dll")) + FitArch = "x86_64" + ObjCopyFlag = "elf64-x86-64" + EntryOutputDir = os.path.join(BuildDir, "{}_{}".format (BuildTarget, PayloadEntryToolChain), os.path.normpath("X64/UefiPayloadPkg/UefiPayloadEntry/{}/DEBUG/{}.dll".format (UpldEntryFile, UpldEntryFile))) else: BuildArch = "IA32 -a X64" - EntryOutputDir = os.path.join(BuildDir, "{}_{}".format (BuildTarget, ElfToolChain), os.path.normpath("IA32/UefiPayloadPkg/UefiPayloadEntry/UniversalPayloadEntry/DEBUG/UniversalPayloadEntry.dll")) + FitArch = "x86" + ObjCopyFlag = "elf32-i386" + EntryOutputDir = os.path.join(BuildDir, "{}_{}".format (BuildTarget, PayloadEntryToolChain), os.path.normpath("IA32/UefiPayloadPkg/UefiPayloadEntry/{}/DEBUG/{}.dll".format (UpldEntryFile, UpldEntryFile))) + EntryModuleInf = os.path.normpath("UefiPayloadPkg/UefiPayloadEntry/{}.inf".format (UpldEntryFile)) DscPath = os.path.normpath("UefiPayloadPkg/UefiPayloadPkg.dsc") + DxeFvOutputDir = os.path.join(BuildDir, "{}_{}".format (BuildTarget, ToolChain), os.path.normpath("FV/DXEFV.Fv")) + BdsFvOutputDir = os.path.join(BuildDir, "{}_{}".format (BuildTarget, ToolChain), os.path.normpath("FV/BDSFV.Fv")) + NetworkFvOutputDir = os.path.join(BuildDir, "{}_{}".format (BuildTarget, ToolChain), os.path.normpath("FV/NETWORKFV.Fv")) + PayloadReportPath = os.path.join(BuildDir, "UefiUniversalPayload.txt") ModuleReportPath = os.path.join(BuildDir, "UefiUniversalPayloadEntry.txt") UpldInfoFile = os.path.join(BuildDir, "UniversalPayloadInfo.bin") + if "CLANG_BIN" in os.environ: + LlvmObjcopyPath = os.path.join(os.environ["CLANG_BIN"], "llvm-objcopy") + else: + LlvmObjcopyPath = "llvm-objcopy" + try: + RunCommand('"%s" --version'%LlvmObjcopyPath) + except: + print("- Failed - Please check if LLVM is installed or if CLANG_BIN is set correctly") + sys.exit(1) + Pcds = "" if (Args.pcd != None): for PcdItem in Args.pcd: @@ -XXX,XX +XXX,XX @@ def BuildUniversalPayload(Args): # Building DXE core and DXE drivers as DXEFV. # if Args.BuildEntryOnly == False: - PayloadReportPath = os.path.join(BuildDir, "UefiUniversalPayload.txt") BuildPayload = "build -p {} -b {} -a X64 -t {} -y {} {}".format (DscPath, BuildTarget, ToolChain, PayloadReportPath, Quiet) BuildPayload += Pcds BuildPayload += Defines @@ -XXX,XX +XXX,XX @@ def BuildUniversalPayload(Args): # Building Universal Payload entry. # if Args.PreBuildUplBinary is None: - EntryModuleInf = os.path.normpath("UefiPayloadPkg/UefiPayloadEntry/UniversalPayloadEntry.inf") - BuildModule = "build -p {} -b {} -a {} -m {} -t {} -y {} {}".format (DscPath, BuildTarget, BuildArch, EntryModuleInf, ElfToolChain, ModuleReportPath, Quiet) + BuildModule = "build -p {} -b {} -a {} -m {} -t {} -y {} {}".format (DscPath, BuildTarget, BuildArch, EntryModuleInf, PayloadEntryToolChain, ModuleReportPath, Quiet) BuildModule += Pcds BuildModule += Defines RunCommand(BuildModule) if Args.PreBuildUplBinary is not None: - EntryOutputDir = os.path.join(BuildDir, "UniversalPayload.elf") + if Args.Fit == False: + EntryOutputDir = os.path.join(BuildDir, "UniversalPayload.elf") + else: + EntryOutputDir = os.path.join(BuildDir, "UniversalPayload.fit") shutil.copy (os.path.abspath(Args.PreBuildUplBinary), EntryOutputDir) # - # Buid Universal Payload Information Section ".upld_info" + # Build Universal Payload Information Section ".upld_info" # - upld_info_hdr = UPLD_INFO_HEADER() - upld_info_hdr.SpecRevision = Args.SpecRevision - upld_info_hdr.Revision = Args.Revision - upld_info_hdr.ProducerId = Args.ProducerId.encode()[:16] - upld_info_hdr.ImageId = Args.ImageId.encode()[:16] - upld_info_hdr.Attribute |= 1 if BuildTarget == "DEBUG" else 0 - fp = open(UpldInfoFile, 'wb') - fp.write(bytearray(upld_info_hdr)) - fp.close() + if Args.Fit == False: + upld_info_hdr = UPLD_INFO_HEADER() + upld_info_hdr.SpecRevision = Args.SpecRevision + upld_info_hdr.Revision = Args.Revision + upld_info_hdr.ProducerId = Args.ProducerId.encode()[:16] + upld_info_hdr.ImageId = Args.ImageId.encode()[:16] + upld_info_hdr.Attribute |= 1 if BuildTarget == "DEBUG" else 0 + fp = open(UpldInfoFile, 'wb') + fp.write(bytearray(upld_info_hdr)) + fp.close() + + if Args.BuildEntryOnly == False: + import Tools.ElfFv as ElfFv + ElfFv.ReplaceFv (EntryOutputDir, UpldInfoFile, '.upld_info', Alignment = 4) + if Args.Fit == False: + shutil.copy (EntryOutputDir, os.path.join(BuildDir, 'UniversalPayload.elf')) + else: + shutil.copy (EntryOutputDir, os.path.join(BuildDir, 'UniversalPayload.fit')) MultiFvList = [] if Args.BuildEntryOnly == False: MultiFvList = [ - ['uefi_fv', os.path.join(BuildDir, "{}_{}".format (BuildTarget, ToolChain), os.path.normpath("FV/DXEFV.Fv")) ], - ['bds_fv', os.path.join(BuildDir, "{}_{}".format (BuildTarget, ToolChain), os.path.normpath("FV/BDSFV.Fv")) ], - ['network_fv', os.path.join(BuildDir, "{}_{}".format (BuildTarget, ToolChain), os.path.normpath("FV/NETWORKFV.Fv")) ], + ['uefi_fv', os.path.join(BuildDir, "{}_{}".format (BuildTarget, ToolChain), os.path.normpath("FV/DXEFV.Fv")) ], + ['bds_fv', os.path.join(BuildDir, "{}_{}".format (BuildTarget, ToolChain), os.path.normpath("FV/BDSFV.Fv")) ], + ['network_fv', os.path.join(BuildDir, "{}_{}".format (BuildTarget, ToolChain), os.path.normpath("FV/NETWORKFV.Fv"))], ] - AddSectionName = '.upld_info' - ReplaceFv (EntryOutputDir, UpldInfoFile, AddSectionName, Alignment = 4) - if Args.PreBuildUplBinary is None: - shutil.copy (EntryOutputDir, os.path.join(BuildDir, 'UniversalPayload.elf')) - return MultiFvList, os.path.join(BuildDir, 'UniversalPayload.elf') + if Args.Fit == True: + import Tools.MkFitImage as MkFitImage + import pefile + fit_image_info_header = MkFitImage.FIT_IMAGE_INFO_HEADER() + fit_image_info_header.Description = 'Uefi Universal Payload' + fit_image_info_header.UplVersion = Args.SpecRevision + fit_image_info_header.Type = 'flat-binary' + fit_image_info_header.Arch = FitArch + fit_image_info_header.Compression = 'none' + fit_image_info_header.Revision = Args.Revision + fit_image_info_header.BuildType = Args.Target.lower() + fit_image_info_header.Capabilities = None + fit_image_info_header.Producer = Args.ProducerId.lower() + fit_image_info_header.ImageId = Args.ImageId.lower() + fit_image_info_header.Binary = os.path.join(BuildDir, 'UniversalPayload.fit') + fit_image_info_header.TargetPath = os.path.join(BuildDir, 'UniversalPayload.fit') + fit_image_info_header.UefifvPath = DxeFvOutputDir + fit_image_info_header.BdsfvPath = BdsFvOutputDir + fit_image_info_header.NetworkfvPath = NetworkFvOutputDir + fit_image_info_header.DataOffset = 0x1000 + fit_image_info_header.LoadAddr = Args.LoadAddress + fit_image_info_header.Project = 'tianocore' + + TargetRebaseFile = fit_image_info_header.Binary.replace (pathlib.Path(fit_image_info_header.Binary).suffix, ".pecoff") + TargetRebaseEntryFile = fit_image_info_header.Binary.replace (pathlib.Path(fit_image_info_header.Binary).suffix, ".entry") + -def main(): - def ValidateSpecRevision (Argument): - try: - (MajorStr, MinorStr) = Argument.split('.') - except: - raise argparse.ArgumentTypeError ('{} is not a valid SpecRevision format (Major[8-bits].Minor[8-bits]).'.format (Argument)) # - # Spec Revision Bits 15 : 8 - Major Version. Bits 7 : 0 - Minor Version. + # Rebase PECOFF to load address # - if len(MinorStr) > 0 and len(MinorStr) < 3: - try: - Minor = int(MinorStr, 16) if len(MinorStr) == 2 else (int(MinorStr, 16) << 4) - except: - raise argparse.ArgumentTypeError ('{} Minor version of SpecRevision is not a valid integer value.'.format (Argument)) - else: - raise argparse.ArgumentTypeError ('{} is not a valid SpecRevision format (Major[8-bits].Minor[8-bits]).'.format (Argument)) + RunCommand ( + "GenFw -e SEC -o {} {}".format ( + TargetRebaseFile, + fit_image_info_header.Binary + )) + RunCommand ( + "GenFw --rebase 0x{:02X} -o {} {} ".format ( + fit_image_info_header.LoadAddr + fit_image_info_header.DataOffset, + TargetRebaseFile, + TargetRebaseFile, + )) - if len(MajorStr) > 0 and len(MajorStr) < 3: - try: - Major = int(MajorStr, 16) - except: - raise argparse.ArgumentTypeError ('{} Major version of SpecRevision is not a valid integer value.'.format (Argument)) - else: - raise argparse.ArgumentTypeError ('{} is not a valid SpecRevision format (Major[8-bits].Minor[8-bits]).'.format (Argument)) + # + # Open PECOFF relocation table binary. + # + RelocBinary = b'' + PeCoff = pefile.PE (TargetRebaseFile) + for reloc in PeCoff.DIRECTORY_ENTRY_BASERELOC: + for entry in reloc.entries: + if (entry.type == 0): + continue + Type = entry.type + Offset = entry.rva + fit_image_info_header.DataOffset + RelocBinary += Type.to_bytes (8, 'little') + Offset.to_bytes (8, 'little') + RelocBinary += b'\x00' * (0x1000 - (len(RelocBinary) % 0x1000)) - return int('0x{0:02x}{1:02x}'.format(Major, Minor), 0) + # + # Output UniversalPayload.entry + # + TempBinary = open (TargetRebaseFile, 'rb') + TianoBinary = TempBinary.read () + TempBinary.close () - def Validate32BitInteger (Argument): - try: - Value = int (Argument, 0) - except: - raise argparse.ArgumentTypeError ('{} is not a valid integer value.'.format (Argument)) - if Value < 0: - raise argparse.ArgumentTypeError ('{} is a negative value.'.format (Argument)) - if Value > 0xffffffff: - raise argparse.ArgumentTypeError ('{} is larger than 32-bits.'.format (Argument)) - return Value - - def ValidateAddFv (Argument): - Value = Argument.split ("=") - if len (Value) != 2: - raise argparse.ArgumentTypeError ('{} is incorrect format with "xxx_fv=xxx.fv"'.format (Argument)) - if Value[0][-3:] != "_fv": - raise argparse.ArgumentTypeError ('{} is incorrect format with "xxx_fv=xxx.fv"'.format (Argument)) - if Value[1][-3:].lower () != ".fv": - raise argparse.ArgumentTypeError ('{} is incorrect format with "xxx_fv=xxx.fv"'.format (Argument)) - if os.path.exists (Value[1]) == False: - raise argparse.ArgumentTypeError ('File {} is not found.'.format (Value[1])) - return Value + TianoEntryBinary = TianoBinary + RelocBinary + TianoEntryBinary += (b'\x00' * (0x1000 - (len(TianoBinary) % 0x1000))) + TianoEntryBinarySize = len (TianoEntryBinary) + + TempBinary = open(TargetRebaseEntryFile, "wb") + TempBinary.truncate() + TempBinary.write(TianoEntryBinary) + TempBinary.close() + + # + # Calculate entry and update relocation table start address and data-size. + # + fit_image_info_header.Entry = PeCoff.OPTIONAL_HEADER.ImageBase + PeCoff.OPTIONAL_HEADER.AddressOfEntryPoint + fit_image_info_header.RelocStart = fit_image_info_header.DataOffset + len(TianoBinary) + fit_image_info_header.DataSize = TianoEntryBinarySize + fit_image_info_header.Binary = TargetRebaseEntryFile + + if MkFitImage.MakeFitImage(fit_image_info_header) is True: + print('\nSuccessfully build Fit Image') + else: + sys.exit(1) + return MultiFvList, os.path.join(BuildDir, 'UniversalPayload.fit') + else: + return MultiFvList, os.path.join(BuildDir, 'UniversalPayload.elf') +def main(): parser = argparse.ArgumentParser(description='For building Universal Payload') parser.add_argument('-t', '--ToolChain') parser.add_argument('-b', '--Target', default='DEBUG') @@ -XXX,XX +XXX,XX @@ def main(): parser.add_argument("-s", "--SpecRevision", type=ValidateSpecRevision, default ='0.7', help='Indicates compliance with a revision of this specification in the BCD format.') parser.add_argument("-r", "--Revision", type=Validate32BitInteger, default ='0x0000010105', help='Revision of the Payload binary. Major.Minor.Revision.Build') parser.add_argument("-o", "--ProducerId", default ='INTEL', help='A null-terminated OEM-supplied string that identifies the payload producer (16 bytes maximal).') + parser.add_argument("-e", "--BuildEntryOnly", action='store_true', help='Build UniversalPayload Entry file') + parser.add_argument("-pb", "--PreBuildUplBinary", default=None, help='Specify the UniversalPayload file') parser.add_argument("-sk", "--SkipBuild", action='store_true', help='Skip UniversalPayload build') parser.add_argument("-af", "--AddFv", type=ValidateAddFv, action='append', help='Add or replace specific FV into payload, Ex: uefi_fv=XXX.fv') - command_group = parser.add_mutually_exclusive_group() - command_group.add_argument("-e", "--BuildEntryOnly", action='store_true', help='Build UniversalPayload Entry file') - command_group.add_argument("-pb", "--PreBuildUplBinary", default=None, help='Specify the UniversalPayload file') + parser.add_argument("-f", "--Fit", action='store_true', help='Build UniversalPayload file as UniversalPayload.fit', default=False) + parser.add_argument('-l', "--LoadAddress", type=int, help='Specify payload load address', default =0x000800000) + args = parser.parse_args() + MultiFvList = [] UniversalPayloadBinary = args.PreBuildUplBinary if (args.SkipBuild == False): @@ -XXX,XX +XXX,XX @@ def main(): for (SectionName, SectionFvFile) in args.AddFv: MultiFvList.append ([SectionName, SectionFvFile]) + def ReplaceFv (UplBinary, SectionFvFile, SectionName): + print (bcolors.OKGREEN + "Patch {}={} into {}".format (SectionName, SectionFvFile, UplBinary) + bcolors.ENDC) + if (args.Fit == False): + import Tools.ElfFv as ElfFv + return ElfFv.ReplaceFv (UplBinary, SectionFvFile, '.upld.{}'.format (SectionName)) + else: + import Tools.MkFitImage as MkFitImage + return MkFitImage.ReplaceFv (UplBinary, SectionFvFile, SectionName) + if (UniversalPayloadBinary != None): for (SectionName, SectionFvFile) in MultiFvList: if os.path.exists (SectionFvFile) == False: continue - print ("Patch {}={} into {}".format (SectionName, SectionFvFile, UniversalPayloadBinary)) - ReplaceFv (UniversalPayloadBinary, SectionFvFile, '.upld.{}'.format (SectionName)) + + status = ReplaceFv (UniversalPayloadBinary, SectionFvFile, SectionName.replace ("_", "-")) + if status != 0: + print (bcolors.FAIL + "[Fail] Patch {}={}".format (SectionName, SectionFvFile) + bcolors.ENDC) + return status print ("\nSuccessfully build Universal Payload") -- 2.39.1.windows.1 -=-=-=-=-=-=-=-=-=-=-=- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#108792): https://edk2.groups.io/g/devel/message/108792 Mute This Topic: https://groups.io/mt/101435620/1787277 Group Owner: devel+owner@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [importer@patchew.org] -=-=-=-=-=-=-=-=-=-=-=-