* [edk2-devel] [PATCH v4 0/4] UefiPayloadPkg: Add FIT support @ 2023-09-18 6:37 brucex.wang 2023-09-18 6:37 ` [edk2-devel] [PATCH v4 1/4] OvmfPkg: Remove applicationProcessorEntryPoint brucex.wang ` (3 more replies) 0 siblings, 4 replies; 6+ messages in thread From: brucex.wang @ 2023-09-18 6:37 UTC (permalink / raw) To: devel; +Cc: brucex.wang 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 (#108783): https://edk2.groups.io/g/devel/message/108783 Mute This Topic: https://groups.io/mt/101435612/7686176 Group Owner: devel+owner@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io] -=-=-=-=-=-=-=-=-=-=-=- ^ permalink raw reply [flat|nested] 6+ messages in thread
* [edk2-devel] [PATCH v4 1/4] OvmfPkg: Remove applicationProcessorEntryPoint 2023-09-18 6:37 [edk2-devel] [PATCH v4 0/4] UefiPayloadPkg: Add FIT support brucex.wang @ 2023-09-18 6:37 ` brucex.wang 2023-09-18 6:37 ` [edk2-devel] [PATCH v4 2/4] UefiCpuPkg/ResetVector: Remove AP waking vector from ResetVector brucex.wang ` (2 subsequent siblings) 3 siblings, 0 replies; 6+ messages in thread From: brucex.wang @ 2023-09-18 6:37 UTC (permalink / raw) To: devel Cc: brucex.wang, Zhiguang Liu, Ard Biesheuvel, Jiewen Yao, Jordan Justen, Gerd Hoffmann, Anthony Perard, Julien Grall, Ray Ni 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 12f2cedd67..8f94da89f7 100644 --- a/OvmfPkg/ResetVector/Ia16/ResetVectorVtf0.asm +++ b/OvmfPkg/ResetVector/Ia16/ResetVectorVtf0.asm @@ -160,22 +160,13 @@ 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 56749bdbc9..67156d8252 100644 --- a/OvmfPkg/XenResetVector/Ia16/ResetVectorVtf0.asm +++ b/OvmfPkg/XenResetVector/Ia16/ResetVectorVtf0.asm @@ -39,23 +39,13 @@ 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 (#108784): https://edk2.groups.io/g/devel/message/108784 Mute This Topic: https://groups.io/mt/101435613/7686176 Group Owner: devel+owner@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io] -=-=-=-=-=-=-=-=-=-=-=- ^ permalink raw reply related [flat|nested] 6+ messages in thread
* [edk2-devel] [PATCH v4 2/4] UefiCpuPkg/ResetVector: Remove AP waking vector from ResetVector 2023-09-18 6:37 [edk2-devel] [PATCH v4 0/4] UefiPayloadPkg: Add FIT support brucex.wang 2023-09-18 6:37 ` [edk2-devel] [PATCH v4 1/4] OvmfPkg: Remove applicationProcessorEntryPoint brucex.wang @ 2023-09-18 6:37 ` brucex.wang 2023-09-18 6:37 ` [edk2-devel] [PATCH v4 3/4] MdePkg/BaseFdtLib: Add Fdt function brucex.wang 2023-09-18 6:37 ` [edk2-devel] [PATCH v4 4/4] UefiPayloadPkg: Add FIT support brucex.wang 3 siblings, 0 replies; 6+ messages in thread From: brucex.wang @ 2023-09-18 6:37 UTC (permalink / raw) To: devel Cc: brucex.wang, Zhiguang Liu, Eric Dong, Ray Ni, Rahul Kumar, Gerd Hoffmann 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 cbdadee166..02b9a0303c 100644 --- a/UefiCpuPkg/ResetVector/Vtf0/Ia16/Init16.asm +++ b/UefiCpuPkg/ResetVector/Vtf0/Ia16/Init16.asm @@ -17,13 +17,6 @@ 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 fe5bbea803..384b1d4d98 100644 --- a/UefiCpuPkg/ResetVector/Vtf0/Ia16/ResetVectorVtf0.asm +++ b/UefiCpuPkg/ResetVector/Vtf0/Ia16/ResetVectorVtf0.asm @@ -32,22 +32,13 @@ 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 (#108785): https://edk2.groups.io/g/devel/message/108785 Mute This Topic: https://groups.io/mt/101435614/7686176 Group Owner: devel+owner@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io] -=-=-=-=-=-=-=-=-=-=-=- ^ permalink raw reply related [flat|nested] 6+ messages in thread
* [edk2-devel] [PATCH v4 3/4] MdePkg/BaseFdtLib: Add Fdt function. 2023-09-18 6:37 [edk2-devel] [PATCH v4 0/4] UefiPayloadPkg: Add FIT support brucex.wang 2023-09-18 6:37 ` [edk2-devel] [PATCH v4 1/4] OvmfPkg: Remove applicationProcessorEntryPoint brucex.wang 2023-09-18 6:37 ` [edk2-devel] [PATCH v4 2/4] UefiCpuPkg/ResetVector: Remove AP waking vector from ResetVector brucex.wang @ 2023-09-18 6:37 ` brucex.wang 2023-09-18 6:37 ` [edk2-devel] [PATCH v4 4/4] UefiPayloadPkg: Add FIT support brucex.wang 3 siblings, 0 replies; 6+ messages in thread From: brucex.wang @ 2023-09-18 6:37 UTC (permalink / raw) To: devel; +Cc: brucex.wang, Benny Lin, Gua Guo, Chasel Chiu, James Lu 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 cf5ceba9e9..d9300a18e3 100644 --- a/MdePkg/Include/Library/FdtLib.h +++ b/MdePkg/Include/Library/FdtLib.h @@ -398,4 +398,38 @@ 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 090b0b3fd4..1ef99ea882 100644 --- a/MdePkg/Library/BaseFdtLib/FdtLib.c +++ b/MdePkg/Library/BaseFdtLib/FdtLib.c @@ -402,3 +402,43 @@ 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 (#108786): https://edk2.groups.io/g/devel/message/108786 Mute This Topic: https://groups.io/mt/101435615/7686176 Group Owner: devel+owner@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io] -=-=-=-=-=-=-=-=-=-=-=- ^ permalink raw reply related [flat|nested] 6+ messages in thread
* [edk2-devel] [PATCH v4 4/4] UefiPayloadPkg: Add FIT support 2023-09-18 6:37 [edk2-devel] [PATCH v4 0/4] UefiPayloadPkg: Add FIT support brucex.wang ` (2 preceding siblings ...) 2023-09-18 6:37 ` [edk2-devel] [PATCH v4 3/4] MdePkg/BaseFdtLib: Add Fdt function brucex.wang @ 2023-09-18 6:37 ` brucex.wang 3 siblings, 0 replies; 6+ messages in thread From: brucex.wang @ 2023-09-18 6:37 UTC (permalink / raw) To: devel; +Cc: brucex.wang, Guo Dong, Sean Rhodes, James Lu, Gua Guo 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 0000000000..60f2aa37dd --- /dev/null +++ b/UefiPayloadPkg/Include/Guid/UniversalPayloadBase.h @@ -0,0 +1,19 @@ +/** @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 0000000000..0514d675a6 --- /dev/null +++ b/UefiPayloadPkg/PayloadLoaderPeim/FitLib.h @@ -0,0 +1,60 @@ +/** @file + FIT Load Image Support +Copyright (c) 2023, Intel Corporation. All rights reserved.<BR> +SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#ifndef FIT_LIB_H_ +#define FIT_LIB_H_ + +#include <PiPei.h> +#include <Library/DebugLib.h> +#include <Library/FdtLib.h> + +typedef struct { + UINT64 RelocateType; + UINT64 Offset; +} FIT_RELOCATE_ITEM; + +typedef struct { + EFI_PHYSICAL_ADDRESS ImageBase; + EFI_PHYSICAL_ADDRESS PayloadBaseAddress; + UINT64 PayloadSize; + UINTN PayloadEntryOffset; + UINTN PayloadEntrySize; + EFI_PHYSICAL_ADDRESS PayloadEntryPoint; + UINTN RelocateTableOffset; + UINTN RelocateTableCount; + EFI_PHYSICAL_ADDRESS PayloadLoadAddress; +} FIT_IMAGE_CONTEXT; + +typedef struct { + UINT8 *Name; + UINT32 Offset; +} PROPERTY_DATA; + +#define IMAGE_BASE_OFFSET OFFSET_OF (FIT_IMAGE_CONTEXT, ImageBase) +#define PAYLOAD_BASE_ADDR_OFFSET OFFSET_OF (FIT_IMAGE_CONTEXT, PayloadBaseAddress) +#define PAYLOAD_BASE_SIZE_OFFSET OFFSET_OF (FIT_IMAGE_CONTEXT, PayloadSize) +#define PAYLOAD_ENTRY_OFFSET_OFFSET OFFSET_OF (FIT_IMAGE_CONTEXT, PayloadEntryOffset) +#define PAYLOAD_ENTRY_SIZE_OFFSET OFFSET_OF (FIT_IMAGE_CONTEXT, PayloadEntrySize) +#define PAYLOAD_ENTRY_POINT_OFFSET OFFSET_OF (FIT_IMAGE_CONTEXT, PayloadEntryPoint) +#define RELOCATE_TABLE_OFFSET_OFFSET OFFSET_OF (FIT_IMAGE_CONTEXT, RelocateTableOffset) +#define RELOCATE_TABLE_COUNT_OFFSET OFFSET_OF (FIT_IMAGE_CONTEXT, RelocateTableCount) +#define PAYLOAD_LOAD_ADDR_OFFSET OFFSET_OF (FIT_IMAGE_CONTEXT, PayloadLoadAddress) + +/** + Parse the FIT image info. + @param[in] ImageBase Memory address of an image. + @param[out] Context The FIT image context pointer. + @retval EFI_UNSUPPORTED Unsupported binary type. + @retval EFI_SUCCESS FIT binary is loaded successfully. +**/ +EFI_STATUS +EFIAPI +ParseFitImage ( + IN VOID *ImageBase, + OUT FIT_IMAGE_CONTEXT *Context + ); + +#endif diff --git a/UefiPayloadPkg/PayloadLoaderPeim/FitLib/FitLib.c b/UefiPayloadPkg/PayloadLoaderPeim/FitLib/FitLib.c new file mode 100644 index 0000000000..9d1d8a4f61 --- /dev/null +++ b/UefiPayloadPkg/PayloadLoaderPeim/FitLib/FitLib.c @@ -0,0 +1,127 @@ +/** @file + FIT Load Image Support +Copyright (c) 2023, Intel Corporation. All rights reserved.<BR> +SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include "FitLib.h" + +PROPERTY_DATA PropertyData32List[] = { + { "data-offset", PAYLOAD_ENTRY_OFFSET_OFFSET }, + { "data-size", PAYLOAD_ENTRY_SIZE_OFFSET }, + { "reloc-start", RELOCATE_TABLE_OFFSET_OFFSET } +}; + +PROPERTY_DATA PropertyData64List[] = { + { "entry-start", PAYLOAD_ENTRY_POINT_OFFSET }, + { "load", PAYLOAD_LOAD_ADDR_OFFSET } +}; + +/** + Parse the target firmware image info in FIT. + @param[in] Fdt Memory address of a fdt. + @param[in] Firmware Target name of an image. + @param[out] Context The FIT image context pointer. + @retval EFI_NOT_FOUND FIT node dose not find. + @retval EFI_SUCCESS FIT binary is loaded successfully. +**/ +EFI_STATUS +EFIAPI +FitParseFirmwarePropertyData ( + IN VOID *Fdt, + IN CHAR8 *Firmware, + OUT FIT_IMAGE_CONTEXT *Context + ) +{ + CONST FDT_PROPERTY *PropertyPtr; + INT32 ImageNode; + INT32 TianoNode; + INT32 TempLen; + UINT32 *Data32; + UINT64 *Data64; + UINT32 *ContextOffset32; + UINT64 *ContextOffset64; + INT32 Index; + + ImageNode = FdtSubnodeOffsetNameLen (Fdt, 0, "images", (INT32)AsciiStrLen ("images")); + if (ImageNode <= 0) { + return EFI_NOT_FOUND; + } + + TianoNode = FdtSubnodeOffsetNameLen (Fdt, ImageNode, Firmware, (INT32)AsciiStrLen (Firmware)); + if (TianoNode <= 0) { + return EFI_NOT_FOUND; + } + + for (Index = 0; Index < sizeof (PropertyData32List) / sizeof (PROPERTY_DATA); Index++) { + PropertyPtr = FdtGetProperty (Fdt, TianoNode, PropertyData32List[Index].Name, &TempLen); + Data32 = (UINT32 *)(PropertyPtr->Data); + ContextOffset32 = (UINT32 *)((UINTN)Context + PropertyData32List[Index].Offset); + *ContextOffset32 = Fdt32ToCpu (*Data32); + } + + for (Index = 0; Index < sizeof (PropertyData64List)/sizeof (PROPERTY_DATA); Index++) { + PropertyPtr = FdtGetProperty (Fdt, TianoNode, PropertyData64List[Index].Name, &TempLen); + Data64 = (UINT64 *)(PropertyPtr->Data); + ContextOffset64 = (UINT64 *)((UINTN)Context + PropertyData64List[Index].Offset); + *ContextOffset64 = Fdt64ToCpu (*Data64); + } + + return EFI_SUCCESS; +} + +/** + Parse the FIT image info. + @param[in] ImageBase Memory address of an image. + @param[out] Context The FIT image context pointer. + @retval EFI_UNSUPPORTED Unsupported binary type. + @retval EFI_SUCCESS FIT binary is loaded successfully. +**/ +EFI_STATUS +EFIAPI +ParseFitImage ( + IN VOID *ImageBase, + OUT FIT_IMAGE_CONTEXT *Context + ) +{ + VOID *Fdt; + INT32 ConfigNode; + INT32 Config1Node; + CONST FDT_PROPERTY *PropertyPtr; + INT32 TempLen; + UINT32 *Data32; + UINT64 Value; + EFI_STATUS Status; + UINTN UplSize; + CHAR8 *Firmware; + + Status = FdtCheckHeader (ImageBase); + if (EFI_ERROR (Status)) { + return EFI_UNSUPPORTED; + } + + Fdt = ImageBase; + PropertyPtr = FdtGetProperty (Fdt, 0, "size", &TempLen); + Data32 = (UINT32 *)(PropertyPtr->Data); + UplSize = Value = Fdt32ToCpu (*Data32); + ConfigNode = FdtSubnodeOffsetNameLen (Fdt, 0, "configurations", (INT32)AsciiStrLen ("configurations")); + if (ConfigNode <= 0) { + return EFI_NOT_FOUND; + } + + Config1Node = FdtSubnodeOffsetNameLen (Fdt, ConfigNode, "conf-1", (INT32)AsciiStrLen ("conf-1")); + if (Config1Node <= 0) { + return EFI_NOT_FOUND; + } + + PropertyPtr = FdtGetProperty (Fdt, Config1Node, "firmware", &TempLen); + Firmware = (CHAR8 *)(PropertyPtr->Data); + + FitParseFirmwarePropertyData (Fdt, Firmware, Context); + + Context->ImageBase = (EFI_PHYSICAL_ADDRESS)ImageBase; + Context->PayloadSize = UplSize; + Context->RelocateTableCount = (Context->PayloadEntrySize - (Context->RelocateTableOffset - Context->PayloadEntryOffset)) / sizeof (FIT_RELOCATE_ITEM); + + return EFI_SUCCESS; +} diff --git a/UefiPayloadPkg/PayloadLoaderPeim/FitPayloadLoaderPeim.c b/UefiPayloadPkg/PayloadLoaderPeim/FitPayloadLoaderPeim.c new file mode 100644 index 0000000000..de33d49bd1 --- /dev/null +++ b/UefiPayloadPkg/PayloadLoaderPeim/FitPayloadLoaderPeim.c @@ -0,0 +1,150 @@ +/** @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 0000000000..cd0cb186e1 --- /dev/null +++ b/UefiPayloadPkg/PayloadLoaderPeim/FitPayloadLoaderPeim.inf @@ -0,0 +1,59 @@ +## @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 0000000000..cb7f39b3f7 --- /dev/null +++ b/UefiPayloadPkg/Readme.md @@ -0,0 +1,189 @@ +# 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 0000000000..82ab933d6d --- /dev/null +++ b/UefiPayloadPkg/Tools/MkFitImage.py @@ -0,0 +1,272 @@ +## @file +# This file is a script to build fit image. +# It generate a dtb header and combine a binary file after this header. +# +# Copyright (c) 2023, Intel Corporation. All rights reserved.<BR> +# SPDX-License-Identifier: BSD-2-Clause-Patent +## + +from os.path import exists +import libfdt +from ctypes import * +import time + +class FIT_IMAGE_INFO_HEADER: + """Class for user setting data to use MakeFitImage() + """ + _pack_ = 1 + _fields_ = [ + ('Compatible', str), + ('UplVersion', int), + ('Description', str), + ('Type', str), + ('Arch', str), + ('Compression', str), + ('Revision', int), + ('BuildType', str), + ('Capabilities', str), + ('Producer', str), + ('ImageId', str), + ('DataOffset', int), + ('DataSize', int), + ('RelocStart', int), + ('LoadAddr', int), + ('Entry', int), + ('Binary', str), + ('TargetPath', str), + ('UefifvPath', str), + ('BdsfvPath', str), + ('NetworkfvPath', str), + ('Project', str), + ] + + def __init__(self): + self.Compatible = 'universal-payload' + self.UplVersion = 0x0100 + self.TargetPath = 'mkimage.fit' + +def CreatFdt(Fdt): + FdtEmptyTree = libfdt.fdt_create_empty_tree(Fdt, len(Fdt)) + if FdtEmptyTree != 0: + print('\n- Failed - Create Fdt failed!') + return False + return True + +def BuildConfNode(Fdt, ParentNode, MultiImage): + ConfNode1 = libfdt.fdt_add_subnode(Fdt, ParentNode, 'conf-1') + + libfdt.fdt_setprop(Fdt, ConfNode1, 'require-fit', b'', 0) + libfdt.fdt_setprop(Fdt, ConfNode1, 'firmware', bytes('tianocore', 'utf-8'), len('tianocore') + 1) + +def BuildFvImageNode(Fdt, InfoHeader, ParentNode, DataOffset, DataSize, Description): + libfdt.fdt_setprop_u32(Fdt, ParentNode, 'data-size', DataSize) + libfdt.fdt_setprop_u32(Fdt, ParentNode, 'data-offset', DataOffset) + libfdt.fdt_setprop(Fdt, ParentNode, 'compression', bytes('none', 'utf-8'), len('none') + 1) + libfdt.fdt_setprop(Fdt, ParentNode, 'project ', bytes('tianocore', 'utf-8'), len('tianocore') + 1) + libfdt.fdt_setprop(Fdt, ParentNode, 'arch', bytes('x86_64', 'utf-8'), len('x86_64') + 1) + libfdt.fdt_setprop(Fdt, ParentNode, 'type', bytes('flat-binary', 'utf-8'), len('flat-binary') + 1) + libfdt.fdt_setprop(Fdt, ParentNode, 'description', bytes(Description, 'utf-8'), len(Description) + 1) + +def BuildTianoImageNode(Fdt, InfoHeader, ParentNode, DataOffset, DataSize, Description): + # + # Set 'load' and 'data-offset' to reserve the memory first. + # They would be set again when Fdt completes or this function parses target binary file. + # + if InfoHeader.LoadAddr is not None: + libfdt.fdt_setprop_u64(Fdt, ParentNode, 'load', InfoHeader.LoadAddr) + if InfoHeader.Entry is not None: + libfdt.fdt_setprop_u64(Fdt, ParentNode, 'entry-start', InfoHeader.Entry) + if InfoHeader.RelocStart is not None: + libfdt.fdt_setprop_u32(Fdt, ParentNode, 'reloc-start', InfoHeader.RelocStart) + if InfoHeader.DataSize is not None: + libfdt.fdt_setprop_u32(Fdt, ParentNode, 'data-size', DataSize) + if InfoHeader.DataOffset is not None: + libfdt.fdt_setprop_u32(Fdt, ParentNode, 'data-offset', DataOffset) + if InfoHeader.Producer is not None: + libfdt.fdt_setprop(Fdt, ParentNode, 'producer ', bytes(InfoHeader.Producer, 'utf-8'), len(InfoHeader.Producer) + 1) + if InfoHeader.Capabilities is not None: + CapStrs = ','.join(InfoHeader.Capabilities) + libfdt.fdt_setprop(Fdt, ParentNode, 'capabilities ', bytes(CapStrs, 'utf-8'), len(CapStrs) + 1) + if InfoHeader.Type is not None: + libfdt.fdt_setprop(Fdt, ParentNode, 'type ', bytes(InfoHeader.Type, 'utf-8'), len(InfoHeader.Type) + 1) + if InfoHeader.Arch is not None: + libfdt.fdt_setprop(Fdt, ParentNode, 'arch ', bytes(InfoHeader.Arch, 'utf-8'), len(InfoHeader.Arch) + 1) + if InfoHeader.Project is not None: + libfdt.fdt_setprop(Fdt, ParentNode, 'project ', bytes(InfoHeader.Project, 'utf-8'), len(InfoHeader.Project) + 1) + if InfoHeader.Description is not None: + libfdt.fdt_setprop(Fdt, ParentNode, 'description', bytes(Description, 'utf-8'), len(Description) + 1) + +# +# The subnode would be inserted from bottom to top of structure block. +# +def BuildFitImage(Fdt, InfoHeader): + MultiImage = [ + ["tianocore", InfoHeader.Binary, BuildTianoImageNode , InfoHeader.Description, None, 0 ], + ["uefi-fv", InfoHeader.UefifvPath, BuildFvImageNode, "UEFI Firmware Volume", None, 0 ], + ["bds-fv", InfoHeader.BdsfvPath, BuildFvImageNode , "BDS Firmware Volume", None, 0 ], + ["network-fv", InfoHeader.NetworkfvPath, BuildFvImageNode , "Network Firmware Volume", None, 0 ], + ] + + # + # Set basic information + # + libfdt.fdt_setprop_u32(Fdt, 0, 'build-revision ', InfoHeader.Revision) + libfdt.fdt_setprop_u32(Fdt, 0, 'spec-version', InfoHeader.UplVersion) + + # + # Build configurations node + # + ConfNode = libfdt.fdt_add_subnode(Fdt, 0, 'configurations') + BuildConfNode(Fdt, ConfNode, MultiImage) + + # Build image + DataOffset = InfoHeader.DataOffset + for Index in range (0, len (MultiImage)): + _, Path, _, _, _, _ = MultiImage[Index] + if exists(Path) == 1: + TempBinary = open(Path, 'rb') + BinaryData = TempBinary.read() + TempBinary.close() + MultiImage[Index][-2] = BinaryData + MultiImage[Index][-1] = DataOffset + DataOffset += len (BinaryData) + libfdt.fdt_setprop_u32(Fdt, 0, 'size', DataOffset) + posix_time = int(time.time()) + libfdt.fdt_setprop_u32(Fdt, 0, 'timestamp', posix_time) + DescriptionFit = 'Uefi OS Loader' + libfdt.fdt_setprop(Fdt, 0, 'description', bytes(DescriptionFit, 'utf-8'), len(DescriptionFit) + 1) + + ImageNode = libfdt.fdt_add_subnode(Fdt, 0, 'images') + for Item in reversed (MultiImage): + Name, Path, BuildFvNode, Description, BinaryData, DataOffset = Item + FvNode = libfdt.fdt_add_subnode(Fdt, ImageNode, Name) + BuildFvNode (Fdt, InfoHeader, FvNode, DataOffset, len(BinaryData), Description) + + # + # Create new image file and combine all binary. + # + DtbFile = open(InfoHeader.TargetPath, "wb") + DtbFile.truncate() + DtbFile.write(Fdt) + for Item in MultiImage: + _, _, _, _, BinaryData, _ = Item + DtbFile.write(BinaryData) + DtbFile.close() + + return True + +def MakeFitImage(InfoHeader): + # + # Allocate fdt byte array. + # + Fdt = bytearray(InfoHeader.DataOffset) + + # + # Create fdt empty tree. + # + if CreatFdt(Fdt) is False: + return False + + # + # Parse args to build fit image. + # + return BuildFitImage(Fdt, InfoHeader) + +def ReplaceFv (UplBinary, SectionFvFile, SectionName): + try: + # + # Get Original Multi Fv + # + with open (UplBinary, "rb") as File: + Dtb = File.read () + Fit = libfdt.Fdt (Dtb) + NewFitHeader = bytearray(Dtb[0:Fit.totalsize()]) + FitSize = len(Dtb) + + LoadablesList = [] + ImagesNode = libfdt.fdt_subnode_offset(NewFitHeader, 0, 'images') + FvNode = libfdt.fdt_subnode_offset(NewFitHeader, ImagesNode, 'uefi-fv') + NodeDepth = libfdt.fdt_node_depth (NewFitHeader, ImagesNode) + node_name = libfdt.fdt_get_name(NewFitHeader, FvNode) + FvNode = libfdt.fdt_next_node(NewFitHeader, FvNode, NodeDepth) + + while node_name[0][-2:] == 'fv': + LoadablesList.append (node_name[0]) + node_name = libfdt.fdt_get_name(NewFitHeader, FvNode[0]) + FvNode = libfdt.fdt_next_node(NewFitHeader, FvNode[0], NodeDepth) + # + # Get current Fit Binary FV data + # + MultiFvList = [] + for Item in LoadablesList: + ImageNode = libfdt.fdt_subnode_offset(NewFitHeader, ImagesNode, Item) + ImageOffset = int.from_bytes (libfdt.fdt_getprop (NewFitHeader, ImageNode, 'data-offset')[0], 'big') + ImageSize = int.from_bytes (libfdt.fdt_getprop (NewFitHeader, ImageNode, 'data-size')[0], 'big') + MultiFvList.append ([Item, Dtb[ImageOffset:ImageOffset + ImageSize]]) + + IsFvExist = False + for Index in range (0, len (MultiFvList)): + if MultiFvList[Index][0] == SectionName: + with open (SectionFvFile, 'rb') as File: + MultiFvList[Index][1] = File.read () + ImageNode = libfdt.fdt_subnode_offset(NewFitHeader, ImagesNode, SectionName) + ImageSize = int.from_bytes (libfdt.fdt_getprop (NewFitHeader, ImageNode, 'data-size')[0], 'big') + ReplaceOffset = int.from_bytes (libfdt.fdt_getprop (NewFitHeader, ImageNode, 'data-offset')[0], 'big') + OffsetDelta = len(MultiFvList[Index][1]) - ImageSize + FitSize += OffsetDelta + IsFvExist = True + libfdt.fdt_setprop_u32(NewFitHeader, ImageNode, 'data-size', len(MultiFvList[Index][1])) + + # + # Update new fit header + # + ImagesNode = libfdt.fdt_subnode_offset(NewFitHeader, 0, 'images') + if (IsFvExist == False): + with open (SectionFvFile, 'rb') as File: + SectionFvFileBinary = File.read () + MultiFvList.append ([SectionName, SectionFvFileBinary]) + FvNode = libfdt.fdt_add_subnode(NewFitHeader, ImagesNode, SectionName) + BuildFvImageNode (NewFitHeader, None, FvNode, FitSize, len(SectionFvFileBinary), SectionName + " Firmware Volume") + FitSize += len(SectionFvFileBinary) + else: + for Index in range (0, len (MultiFvList)): + ImageNode = libfdt.fdt_subnode_offset(NewFitHeader, ImagesNode, MultiFvList[Index][0]) + ImageOffset = int.from_bytes (libfdt.fdt_getprop (NewFitHeader, ImageNode, 'data-offset')[0], 'big') + if ImageOffset > ReplaceOffset: + libfdt.fdt_setprop_u32(NewFitHeader, ImageNode, 'data-offset', ImageOffset + OffsetDelta) + + ConfNodes = libfdt.fdt_subnode_offset(NewFitHeader, 0, 'configurations') + libfdt.fdt_setprop(NewFitHeader, ConfNodes, 'default ', bytes('conf-1', 'utf-8'), len('conf-1') + 1) + ConfNode = libfdt.fdt_subnode_offset(NewFitHeader, ConfNodes, 'conf-1') + + libfdt.fdt_setprop_u32(NewFitHeader, 0, 'size', FitSize) + + # + # Generate new fit image + # + ImagesNode = libfdt.fdt_subnode_offset(NewFitHeader, 0, 'images') + TianoNode = libfdt.fdt_subnode_offset(NewFitHeader, ImagesNode, 'tianocore') + TianoOffset = int.from_bytes (libfdt.fdt_getprop (NewFitHeader, TianoNode, 'data-offset')[0], 'big') + TianoSize = int.from_bytes (libfdt.fdt_getprop (NewFitHeader, TianoNode, 'data-size')[0], 'big') + TianoBinary = Dtb[TianoOffset:TianoOffset + TianoSize] + + print("\nGenerate new fit image:") + NewUplBinary = bytearray(FitSize) + print("Update fit header\t to 0x0\t\t ~ " + str(hex(len(NewFitHeader)))) + NewUplBinary[:len(NewFitHeader)] = NewFitHeader + print("Update tiano image\t to " + str(hex(len(NewFitHeader))) + "\t ~ " + str(hex(len(NewFitHeader) + len(TianoBinary)))) + NewUplBinary[len(NewFitHeader):len(NewFitHeader) + len(TianoBinary)] = TianoBinary + for Index in range (0, len (MultiFvList)): + ImageNode = libfdt.fdt_subnode_offset(NewFitHeader, ImagesNode, MultiFvList[Index][0]) + ImageOffset = int.from_bytes (libfdt.fdt_getprop (NewFitHeader, ImageNode, 'data-offset')[0], 'big') + ImageSize = int.from_bytes (libfdt.fdt_getprop (NewFitHeader, ImageNode, 'data-size')[0], 'big') + NewUplBinary[ImageOffset:ImageOffset + ImageSize] = MultiFvList[Index][1] + print("Update " + MultiFvList[Index][0] + "\t\t to " + str(hex(ImageOffset)) + "\t ~ " + str(hex(ImageOffset + ImageSize))) + + with open (UplBinary, "wb") as File: + File.write (NewUplBinary) + + return 0 + except Exception as Ex: + print(Ex) + return 1 diff --git a/UefiPayloadPkg/UefiPayloadEntry/FitUniversalPayloadEntry.c b/UefiPayloadPkg/UefiPayloadEntry/FitUniversalPayloadEntry.c new file mode 100644 index 0000000000..ad04ad7eb9 --- /dev/null +++ b/UefiPayloadPkg/UefiPayloadEntry/FitUniversalPayloadEntry.c @@ -0,0 +1,654 @@ +/** @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 0000000000..01fb3aceb3 --- /dev/null +++ b/UefiPayloadPkg/UefiPayloadEntry/FitUniversalPayloadEntry.inf @@ -0,0 +1,98 @@ +## @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 e2e4a79db3..2f1fd82487 100644 --- a/UefiPayloadPkg/UefiPayloadPkg.dec +++ b/UefiPayloadPkg/UefiPayloadPkg.dec @@ -24,6 +24,9 @@ # gUefiPayloadPkgTokenSpaceGuid = {0x1d127ea, 0xf6f1, 0x4ef6, {0x94, 0x15, 0x8a, 0x0, 0x0, 0x93, 0xf8, 0x9d}} + ## Include/Guid/UniversalPayloadBase.h + gUniversalPayloadBaseGuid = { 0x03d4c61d, 0x2713, 0x4ec5, {0xa1, 0xcc, 0x88, 0x3b, 0xe9, 0xdc, 0x18, 0xe5 } } + # # Gop Temp # diff --git a/UefiPayloadPkg/UefiPayloadPkg.dsc b/UefiPayloadPkg/UefiPayloadPkg.dsc index 47812048dd..af9308ef8e 100644 --- a/UefiPayloadPkg/UefiPayloadPkg.dsc +++ b/UefiPayloadPkg/UefiPayloadPkg.dsc @@ -30,7 +30,6 @@ DEFINE PS2_KEYBOARD_ENABLE = FALSE DEFINE RAM_DISK_ENABLE = FALSE DEFINE SIO_BUS_ENABLE = FALSE - DEFINE UNIVERSAL_PAYLOAD = FALSE DEFINE SECURITY_STUB_ENABLE = TRUE DEFINE SMM_SUPPORT = FALSE DEFINE PLATFORM_BOOT_TIMEOUT = 3 @@ -44,6 +43,14 @@ DEFINE BOOTSPLASH_IMAGE = FALSE DEFINE NVME_ENABLE = TRUE DEFINE CAPSULE_SUPPORT = FALSE + # + # Setup Universal Payload + # + # ELF: Build UniversalPayload file as UniversalPayload.elf + # FIT: Build UniversalPayload file as UniversalPayload.fit + # + DEFINE UNIVERSAL_PAYLOAD = FALSE + DEFINE UNIVERSAL_PAYLOAD_FORMAT = ELF # # NULL: NullMemoryTestDxe @@ -311,7 +318,7 @@ VariableFlashInfoLib|MdeModulePkg/Library/BaseVariableFlashInfoLib/BaseVariableFlashInfoLib.inf CcExitLib|UefiCpuPkg/Library/CcExitLibNull/CcExitLibNull.inf ReportStatusCodeLib|MdeModulePkg/Library/DxeReportStatusCodeLib/DxeReportStatusCodeLib.inf - + FdtLib|MdePkg/Library/BaseFdtLib/BaseFdtLib.inf [LibraryClasses.common] !if $(BOOTSPLASH_IMAGE) SafeIntLib|MdePkg/Library/BaseSafeIntLib/BaseSafeIntLib.inf @@ -600,14 +607,26 @@ !if "IA32" in "$(ARCH)" [Components.IA32] !if $(UNIVERSAL_PAYLOAD) == TRUE - UefiPayloadPkg/UefiPayloadEntry/UniversalPayloadEntry.inf + !if $(UNIVERSAL_PAYLOAD_FORMAT) == "ELF" + UefiPayloadPkg/UefiPayloadEntry/UniversalPayloadEntry.inf + !elseif $(UNIVERSAL_PAYLOAD_FORMAT) == "FIT" + UefiPayloadPkg/UefiPayloadEntry/FitUniversalPayloadEntry.inf + !else + UefiPayloadPkg/UefiPayloadEntry/UefiPayloadEntry.inf + !endif !else UefiPayloadPkg/UefiPayloadEntry/UefiPayloadEntry.inf !endif !else [Components.X64] !if $(UNIVERSAL_PAYLOAD) == TRUE - UefiPayloadPkg/UefiPayloadEntry/UniversalPayloadEntry.inf + !if $(UNIVERSAL_PAYLOAD_FORMAT) == "ELF" + UefiPayloadPkg/UefiPayloadEntry/UniversalPayloadEntry.inf + !elseif $(UNIVERSAL_PAYLOAD_FORMAT) == "FIT" + UefiPayloadPkg/UefiPayloadEntry/FitUniversalPayloadEntry.inf + !else + UefiPayloadPkg/UefiPayloadEntry/UefiPayloadEntry.inf + !endif !else UefiPayloadPkg/UefiPayloadEntry/UefiPayloadEntry.inf !endif diff --git a/UefiPayloadPkg/UniversalPayloadBuild.py b/UefiPayloadPkg/UniversalPayloadBuild.py index 47f37b3377..9a83fc9e44 100644 --- a/UefiPayloadPkg/UniversalPayloadBuild.py +++ b/UefiPayloadPkg/UniversalPayloadBuild.py @@ -10,10 +10,22 @@ import subprocess import os import shutil import sys +import pathlib from ctypes import * -from Tools.ElfFv import ReplaceFv + sys.dont_write_bytecode = True +class bcolors: + HEADER = '\033[95m' + OKBLUE = '\033[94m' + OKCYAN = '\033[96m' + OKGREEN = '\033[92m' + WARNING = '\033[93m' + FAIL = '\033[91m' + ENDC = '\033[0m' + BOLD = '\033[1m' + UNDERLINE = '\033[4m' + class UPLD_INFO_HEADER(LittleEndianStructure): _pack_ = 1 _fields_ = [ @@ -36,40 +48,114 @@ class UPLD_INFO_HEADER(LittleEndianStructure): self.ImageId = b'UEFI' self.ProducerId = b'INTEL' -def BuildUniversalPayload(Args): - def RunCommand(cmd): - print(cmd) - p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT,cwd=os.environ['WORKSPACE']) - while True: - line = p.stdout.readline() - if not line: - break - print(line.strip().decode(errors='ignore')) - - p.communicate() - if p.returncode != 0: - print("- Failed - error happened when run command: %s"%cmd) - raise Exception("ERROR: when run command: %s"%cmd) +def ValidateSpecRevision (Argument): + try: + (MajorStr, MinorStr) = Argument.split('.') + except: + raise argparse.ArgumentTypeError ('{} is not a valid SpecRevision format (Major[8-bits].Minor[8-bits]).'.format (Argument)) + # + # Spec Revision Bits 15 : 8 - Major Version. Bits 7 : 0 - Minor Version. + # + if len(MinorStr) > 0 and len(MinorStr) < 3: + try: + Minor = int(MinorStr, 16) if len(MinorStr) == 2 else (int(MinorStr, 16) << 4) + except: + raise argparse.ArgumentTypeError ('{} Minor version of SpecRevision is not a valid integer value.'.format (Argument)) + else: + raise argparse.ArgumentTypeError ('{} is not a valid SpecRevision format (Major[8-bits].Minor[8-bits]).'.format (Argument)) + + if len(MajorStr) > 0 and len(MajorStr) < 3: + try: + Major = int(MajorStr, 16) + except: + raise argparse.ArgumentTypeError ('{} Major version of SpecRevision is not a valid integer value.'.format (Argument)) + else: + raise argparse.ArgumentTypeError ('{} is not a valid SpecRevision format (Major[8-bits].Minor[8-bits]).'.format (Argument)) + + return int('0x{0:02x}{1:02x}'.format(Major, Minor), 0) + +def Validate32BitInteger (Argument): + try: + Value = int (Argument, 0) + except: + raise argparse.ArgumentTypeError ('{} is not a valid integer value.'.format (Argument)) + if Value < 0: + raise argparse.ArgumentTypeError ('{} is a negative value.'.format (Argument)) + if Value > 0xffffffff: + raise argparse.ArgumentTypeError ('{} is larger than 32-bits.'.format (Argument)) + return Value +def ValidateAddFv (Argument): + Value = Argument.split ("=") + if len (Value) != 2: + raise argparse.ArgumentTypeError ('{} is incorrect format with "xxx_fv=xxx.fv"'.format (Argument)) + if Value[0][-3:] != "_fv": + raise argparse.ArgumentTypeError ('{} is incorrect format with "xxx_fv=xxx.fv"'.format (Argument)) + if Value[1][-3:].lower () != ".fv": + raise argparse.ArgumentTypeError ('{} is incorrect format with "xxx_fv=xxx.fv"'.format (Argument)) + if os.path.exists (Value[1]) == False: + raise argparse.ArgumentTypeError ('File {} is not found.'.format (Value[1])) + return Value + +def RunCommand(cmd): + print(cmd) + p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT,cwd=os.environ['WORKSPACE']) + while True: + line = p.stdout.readline() + if not line: + break + print(line.strip().decode(errors='ignore')) + + p.communicate() + if p.returncode != 0: + print("- Failed - error happened when run command: %s"%cmd) + raise Exception("ERROR: when run command: %s"%cmd) + +def BuildUniversalPayload(Args): BuildTarget = Args.Target ToolChain = Args.ToolChain Quiet = "--quiet" if Args.Quiet else "" - ElfToolChain = 'CLANGDWARF' - BuildDir = os.path.join(os.environ['WORKSPACE'], os.path.normpath("Build/UefiPayloadPkgX64")) - BuildModule = "" - BuildArch = "" + if Args.Fit == True: + PayloadEntryToolChain = ToolChain + Args.Macro.append("UNIVERSAL_PAYLOAD_FORMAT=FIT") + UpldEntryFile = "FitUniversalPayloadEntry" + else: + PayloadEntryToolChain = 'CLANGDWARF' + Args.Macro.append("UNIVERSAL_PAYLOAD_FORMAT=ELF") + UpldEntryFile = "UniversalPayloadEntry" + + BuildDir = os.path.join(os.environ['WORKSPACE'], os.path.normpath("Build/UefiPayloadPkgX64")) if Args.Arch == 'X64': BuildArch = "X64" - EntryOutputDir = os.path.join(BuildDir, "{}_{}".format (BuildTarget, ElfToolChain), os.path.normpath("X64/UefiPayloadPkg/UefiPayloadEntry/UniversalPayloadEntry/DEBUG/UniversalPayloadEntry.dll")) + FitArch = "x86_64" + ObjCopyFlag = "elf64-x86-64" + EntryOutputDir = os.path.join(BuildDir, "{}_{}".format (BuildTarget, PayloadEntryToolChain), os.path.normpath("X64/UefiPayloadPkg/UefiPayloadEntry/{}/DEBUG/{}.dll".format (UpldEntryFile, UpldEntryFile))) else: BuildArch = "IA32 -a X64" - EntryOutputDir = os.path.join(BuildDir, "{}_{}".format (BuildTarget, ElfToolChain), os.path.normpath("IA32/UefiPayloadPkg/UefiPayloadEntry/UniversalPayloadEntry/DEBUG/UniversalPayloadEntry.dll")) + FitArch = "x86" + ObjCopyFlag = "elf32-i386" + EntryOutputDir = os.path.join(BuildDir, "{}_{}".format (BuildTarget, PayloadEntryToolChain), os.path.normpath("IA32/UefiPayloadPkg/UefiPayloadEntry/{}/DEBUG/{}.dll".format (UpldEntryFile, UpldEntryFile))) + EntryModuleInf = os.path.normpath("UefiPayloadPkg/UefiPayloadEntry/{}.inf".format (UpldEntryFile)) DscPath = os.path.normpath("UefiPayloadPkg/UefiPayloadPkg.dsc") + DxeFvOutputDir = os.path.join(BuildDir, "{}_{}".format (BuildTarget, ToolChain), os.path.normpath("FV/DXEFV.Fv")) + BdsFvOutputDir = os.path.join(BuildDir, "{}_{}".format (BuildTarget, ToolChain), os.path.normpath("FV/BDSFV.Fv")) + NetworkFvOutputDir = os.path.join(BuildDir, "{}_{}".format (BuildTarget, ToolChain), os.path.normpath("FV/NETWORKFV.Fv")) + PayloadReportPath = os.path.join(BuildDir, "UefiUniversalPayload.txt") ModuleReportPath = os.path.join(BuildDir, "UefiUniversalPayloadEntry.txt") UpldInfoFile = os.path.join(BuildDir, "UniversalPayloadInfo.bin") + if "CLANG_BIN" in os.environ: + LlvmObjcopyPath = os.path.join(os.environ["CLANG_BIN"], "llvm-objcopy") + else: + LlvmObjcopyPath = "llvm-objcopy" + try: + RunCommand('"%s" --version'%LlvmObjcopyPath) + except: + print("- Failed - Please check if LLVM is installed or if CLANG_BIN is set correctly") + sys.exit(1) + Pcds = "" if (Args.pcd != None): for PcdItem in Args.pcd: @@ -84,7 +170,6 @@ def BuildUniversalPayload(Args): # Building DXE core and DXE drivers as DXEFV. # if Args.BuildEntryOnly == False: - PayloadReportPath = os.path.join(BuildDir, "UefiUniversalPayload.txt") BuildPayload = "build -p {} -b {} -a X64 -t {} -y {} {}".format (DscPath, BuildTarget, ToolChain, PayloadReportPath, Quiet) BuildPayload += Pcds BuildPayload += Defines @@ -93,94 +178,138 @@ def BuildUniversalPayload(Args): # Building Universal Payload entry. # if Args.PreBuildUplBinary is None: - EntryModuleInf = os.path.normpath("UefiPayloadPkg/UefiPayloadEntry/UniversalPayloadEntry.inf") - BuildModule = "build -p {} -b {} -a {} -m {} -t {} -y {} {}".format (DscPath, BuildTarget, BuildArch, EntryModuleInf, ElfToolChain, ModuleReportPath, Quiet) + BuildModule = "build -p {} -b {} -a {} -m {} -t {} -y {} {}".format (DscPath, BuildTarget, BuildArch, EntryModuleInf, PayloadEntryToolChain, ModuleReportPath, Quiet) BuildModule += Pcds BuildModule += Defines RunCommand(BuildModule) if Args.PreBuildUplBinary is not None: - EntryOutputDir = os.path.join(BuildDir, "UniversalPayload.elf") + if Args.Fit == False: + EntryOutputDir = os.path.join(BuildDir, "UniversalPayload.elf") + else: + EntryOutputDir = os.path.join(BuildDir, "UniversalPayload.fit") shutil.copy (os.path.abspath(Args.PreBuildUplBinary), EntryOutputDir) # - # Buid Universal Payload Information Section ".upld_info" + # Build Universal Payload Information Section ".upld_info" # - upld_info_hdr = UPLD_INFO_HEADER() - upld_info_hdr.SpecRevision = Args.SpecRevision - upld_info_hdr.Revision = Args.Revision - upld_info_hdr.ProducerId = Args.ProducerId.encode()[:16] - upld_info_hdr.ImageId = Args.ImageId.encode()[:16] - upld_info_hdr.Attribute |= 1 if BuildTarget == "DEBUG" else 0 - fp = open(UpldInfoFile, 'wb') - fp.write(bytearray(upld_info_hdr)) - fp.close() + if Args.Fit == False: + upld_info_hdr = UPLD_INFO_HEADER() + upld_info_hdr.SpecRevision = Args.SpecRevision + upld_info_hdr.Revision = Args.Revision + upld_info_hdr.ProducerId = Args.ProducerId.encode()[:16] + upld_info_hdr.ImageId = Args.ImageId.encode()[:16] + upld_info_hdr.Attribute |= 1 if BuildTarget == "DEBUG" else 0 + fp = open(UpldInfoFile, 'wb') + fp.write(bytearray(upld_info_hdr)) + fp.close() + + if Args.BuildEntryOnly == False: + import Tools.ElfFv as ElfFv + ElfFv.ReplaceFv (EntryOutputDir, UpldInfoFile, '.upld_info', Alignment = 4) + if Args.Fit == False: + shutil.copy (EntryOutputDir, os.path.join(BuildDir, 'UniversalPayload.elf')) + else: + shutil.copy (EntryOutputDir, os.path.join(BuildDir, 'UniversalPayload.fit')) MultiFvList = [] if Args.BuildEntryOnly == False: MultiFvList = [ - ['uefi_fv', os.path.join(BuildDir, "{}_{}".format (BuildTarget, ToolChain), os.path.normpath("FV/DXEFV.Fv")) ], - ['bds_fv', os.path.join(BuildDir, "{}_{}".format (BuildTarget, ToolChain), os.path.normpath("FV/BDSFV.Fv")) ], - ['network_fv', os.path.join(BuildDir, "{}_{}".format (BuildTarget, ToolChain), os.path.normpath("FV/NETWORKFV.Fv")) ], + ['uefi_fv', os.path.join(BuildDir, "{}_{}".format (BuildTarget, ToolChain), os.path.normpath("FV/DXEFV.Fv")) ], + ['bds_fv', os.path.join(BuildDir, "{}_{}".format (BuildTarget, ToolChain), os.path.normpath("FV/BDSFV.Fv")) ], + ['network_fv', os.path.join(BuildDir, "{}_{}".format (BuildTarget, ToolChain), os.path.normpath("FV/NETWORKFV.Fv"))], ] - AddSectionName = '.upld_info' - ReplaceFv (EntryOutputDir, UpldInfoFile, AddSectionName, Alignment = 4) - if Args.PreBuildUplBinary is None: - shutil.copy (EntryOutputDir, os.path.join(BuildDir, 'UniversalPayload.elf')) - return MultiFvList, os.path.join(BuildDir, 'UniversalPayload.elf') + if Args.Fit == True: + import Tools.MkFitImage as MkFitImage + import pefile + fit_image_info_header = MkFitImage.FIT_IMAGE_INFO_HEADER() + fit_image_info_header.Description = 'Uefi Universal Payload' + fit_image_info_header.UplVersion = Args.SpecRevision + fit_image_info_header.Type = 'flat-binary' + fit_image_info_header.Arch = FitArch + fit_image_info_header.Compression = 'none' + fit_image_info_header.Revision = Args.Revision + fit_image_info_header.BuildType = Args.Target.lower() + fit_image_info_header.Capabilities = None + fit_image_info_header.Producer = Args.ProducerId.lower() + fit_image_info_header.ImageId = Args.ImageId.lower() + fit_image_info_header.Binary = os.path.join(BuildDir, 'UniversalPayload.fit') + fit_image_info_header.TargetPath = os.path.join(BuildDir, 'UniversalPayload.fit') + fit_image_info_header.UefifvPath = DxeFvOutputDir + fit_image_info_header.BdsfvPath = BdsFvOutputDir + fit_image_info_header.NetworkfvPath = NetworkFvOutputDir + fit_image_info_header.DataOffset = 0x1000 + fit_image_info_header.LoadAddr = Args.LoadAddress + fit_image_info_header.Project = 'tianocore' + + TargetRebaseFile = fit_image_info_header.Binary.replace (pathlib.Path(fit_image_info_header.Binary).suffix, ".pecoff") + TargetRebaseEntryFile = fit_image_info_header.Binary.replace (pathlib.Path(fit_image_info_header.Binary).suffix, ".entry") + -def main(): - def ValidateSpecRevision (Argument): - try: - (MajorStr, MinorStr) = Argument.split('.') - except: - raise argparse.ArgumentTypeError ('{} is not a valid SpecRevision format (Major[8-bits].Minor[8-bits]).'.format (Argument)) # - # Spec Revision Bits 15 : 8 - Major Version. Bits 7 : 0 - Minor Version. + # Rebase PECOFF to load address # - if len(MinorStr) > 0 and len(MinorStr) < 3: - try: - Minor = int(MinorStr, 16) if len(MinorStr) == 2 else (int(MinorStr, 16) << 4) - except: - raise argparse.ArgumentTypeError ('{} Minor version of SpecRevision is not a valid integer value.'.format (Argument)) - else: - raise argparse.ArgumentTypeError ('{} is not a valid SpecRevision format (Major[8-bits].Minor[8-bits]).'.format (Argument)) + RunCommand ( + "GenFw -e SEC -o {} {}".format ( + TargetRebaseFile, + fit_image_info_header.Binary + )) + RunCommand ( + "GenFw --rebase 0x{:02X} -o {} {} ".format ( + fit_image_info_header.LoadAddr + fit_image_info_header.DataOffset, + TargetRebaseFile, + TargetRebaseFile, + )) - if len(MajorStr) > 0 and len(MajorStr) < 3: - try: - Major = int(MajorStr, 16) - except: - raise argparse.ArgumentTypeError ('{} Major version of SpecRevision is not a valid integer value.'.format (Argument)) - else: - raise argparse.ArgumentTypeError ('{} is not a valid SpecRevision format (Major[8-bits].Minor[8-bits]).'.format (Argument)) + # + # Open PECOFF relocation table binary. + # + RelocBinary = b'' + PeCoff = pefile.PE (TargetRebaseFile) + for reloc in PeCoff.DIRECTORY_ENTRY_BASERELOC: + for entry in reloc.entries: + if (entry.type == 0): + continue + Type = entry.type + Offset = entry.rva + fit_image_info_header.DataOffset + RelocBinary += Type.to_bytes (8, 'little') + Offset.to_bytes (8, 'little') + RelocBinary += b'\x00' * (0x1000 - (len(RelocBinary) % 0x1000)) - return int('0x{0:02x}{1:02x}'.format(Major, Minor), 0) + # + # Output UniversalPayload.entry + # + TempBinary = open (TargetRebaseFile, 'rb') + TianoBinary = TempBinary.read () + TempBinary.close () - def Validate32BitInteger (Argument): - try: - Value = int (Argument, 0) - except: - raise argparse.ArgumentTypeError ('{} is not a valid integer value.'.format (Argument)) - if Value < 0: - raise argparse.ArgumentTypeError ('{} is a negative value.'.format (Argument)) - if Value > 0xffffffff: - raise argparse.ArgumentTypeError ('{} is larger than 32-bits.'.format (Argument)) - return Value - - def ValidateAddFv (Argument): - Value = Argument.split ("=") - if len (Value) != 2: - raise argparse.ArgumentTypeError ('{} is incorrect format with "xxx_fv=xxx.fv"'.format (Argument)) - if Value[0][-3:] != "_fv": - raise argparse.ArgumentTypeError ('{} is incorrect format with "xxx_fv=xxx.fv"'.format (Argument)) - if Value[1][-3:].lower () != ".fv": - raise argparse.ArgumentTypeError ('{} is incorrect format with "xxx_fv=xxx.fv"'.format (Argument)) - if os.path.exists (Value[1]) == False: - raise argparse.ArgumentTypeError ('File {} is not found.'.format (Value[1])) - return Value + TianoEntryBinary = TianoBinary + RelocBinary + TianoEntryBinary += (b'\x00' * (0x1000 - (len(TianoBinary) % 0x1000))) + TianoEntryBinarySize = len (TianoEntryBinary) + + TempBinary = open(TargetRebaseEntryFile, "wb") + TempBinary.truncate() + TempBinary.write(TianoEntryBinary) + TempBinary.close() + + # + # Calculate entry and update relocation table start address and data-size. + # + fit_image_info_header.Entry = PeCoff.OPTIONAL_HEADER.ImageBase + PeCoff.OPTIONAL_HEADER.AddressOfEntryPoint + fit_image_info_header.RelocStart = fit_image_info_header.DataOffset + len(TianoBinary) + fit_image_info_header.DataSize = TianoEntryBinarySize + fit_image_info_header.Binary = TargetRebaseEntryFile + + if MkFitImage.MakeFitImage(fit_image_info_header) is True: + print('\nSuccessfully build Fit Image') + else: + sys.exit(1) + return MultiFvList, os.path.join(BuildDir, 'UniversalPayload.fit') + else: + return MultiFvList, os.path.join(BuildDir, 'UniversalPayload.elf') +def main(): parser = argparse.ArgumentParser(description='For building Universal Payload') parser.add_argument('-t', '--ToolChain') parser.add_argument('-b', '--Target', default='DEBUG') @@ -192,13 +321,16 @@ def main(): parser.add_argument("-s", "--SpecRevision", type=ValidateSpecRevision, default ='0.7', help='Indicates compliance with a revision of this specification in the BCD format.') parser.add_argument("-r", "--Revision", type=Validate32BitInteger, default ='0x0000010105', help='Revision of the Payload binary. Major.Minor.Revision.Build') parser.add_argument("-o", "--ProducerId", default ='INTEL', help='A null-terminated OEM-supplied string that identifies the payload producer (16 bytes maximal).') + parser.add_argument("-e", "--BuildEntryOnly", action='store_true', help='Build UniversalPayload Entry file') + parser.add_argument("-pb", "--PreBuildUplBinary", default=None, help='Specify the UniversalPayload file') parser.add_argument("-sk", "--SkipBuild", action='store_true', help='Skip UniversalPayload build') parser.add_argument("-af", "--AddFv", type=ValidateAddFv, action='append', help='Add or replace specific FV into payload, Ex: uefi_fv=XXX.fv') - command_group = parser.add_mutually_exclusive_group() - command_group.add_argument("-e", "--BuildEntryOnly", action='store_true', help='Build UniversalPayload Entry file') - command_group.add_argument("-pb", "--PreBuildUplBinary", default=None, help='Specify the UniversalPayload file') + parser.add_argument("-f", "--Fit", action='store_true', help='Build UniversalPayload file as UniversalPayload.fit', default=False) + parser.add_argument('-l', "--LoadAddress", type=int, help='Specify payload load address', default =0x000800000) + args = parser.parse_args() + MultiFvList = [] UniversalPayloadBinary = args.PreBuildUplBinary if (args.SkipBuild == False): @@ -208,12 +340,24 @@ def main(): for (SectionName, SectionFvFile) in args.AddFv: MultiFvList.append ([SectionName, SectionFvFile]) + def ReplaceFv (UplBinary, SectionFvFile, SectionName): + print (bcolors.OKGREEN + "Patch {}={} into {}".format (SectionName, SectionFvFile, UplBinary) + bcolors.ENDC) + if (args.Fit == False): + import Tools.ElfFv as ElfFv + return ElfFv.ReplaceFv (UplBinary, SectionFvFile, '.upld.{}'.format (SectionName)) + else: + import Tools.MkFitImage as MkFitImage + return MkFitImage.ReplaceFv (UplBinary, SectionFvFile, SectionName) + if (UniversalPayloadBinary != None): for (SectionName, SectionFvFile) in MultiFvList: if os.path.exists (SectionFvFile) == False: continue - print ("Patch {}={} into {}".format (SectionName, SectionFvFile, UniversalPayloadBinary)) - ReplaceFv (UniversalPayloadBinary, SectionFvFile, '.upld.{}'.format (SectionName)) + + status = ReplaceFv (UniversalPayloadBinary, SectionFvFile, SectionName.replace ("_", "-")) + if status != 0: + print (bcolors.FAIL + "[Fail] Patch {}={}".format (SectionName, SectionFvFile) + bcolors.ENDC) + return status print ("\nSuccessfully build Universal Payload") -- 2.39.1.windows.1 -=-=-=-=-=-=-=-=-=-=-=- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#108787): https://edk2.groups.io/g/devel/message/108787 Mute This Topic: https://groups.io/mt/101435616/7686176 Group Owner: devel+owner@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io] -=-=-=-=-=-=-=-=-=-=-=- ^ permalink raw reply related [flat|nested] 6+ messages in thread
* [edk2-devel] [PATCH v4 0/4] UefiPayloadPkg: Add FIT support @ 2023-09-18 6:42 brucex.wang 2023-09-18 6:42 ` [edk2-devel] [PATCH v4 4/4] " brucex.wang 0 siblings, 1 reply; 6+ messages in thread From: brucex.wang @ 2023-09-18 6:42 UTC (permalink / raw) To: devel; +Cc: brucex.wang 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/7686176 Group Owner: devel+owner@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io] -=-=-=-=-=-=-=-=-=-=-=- ^ permalink raw reply [flat|nested] 6+ messages in thread
* [edk2-devel] [PATCH v4 4/4] UefiPayloadPkg: Add FIT support 2023-09-18 6:42 [edk2-devel] [PATCH v4 0/4] " brucex.wang @ 2023-09-18 6:42 ` brucex.wang 0 siblings, 0 replies; 6+ messages in thread From: brucex.wang @ 2023-09-18 6:42 UTC (permalink / raw) To: devel; +Cc: brucex.wang, Guo Dong, Sean Rhodes, James Lu, Gua Guo 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 0000000000..60f2aa37dd --- /dev/null +++ b/UefiPayloadPkg/Include/Guid/UniversalPayloadBase.h @@ -0,0 +1,19 @@ +/** @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 0000000000..0514d675a6 --- /dev/null +++ b/UefiPayloadPkg/PayloadLoaderPeim/FitLib.h @@ -0,0 +1,60 @@ +/** @file + FIT Load Image Support +Copyright (c) 2023, Intel Corporation. All rights reserved.<BR> +SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#ifndef FIT_LIB_H_ +#define FIT_LIB_H_ + +#include <PiPei.h> +#include <Library/DebugLib.h> +#include <Library/FdtLib.h> + +typedef struct { + UINT64 RelocateType; + UINT64 Offset; +} FIT_RELOCATE_ITEM; + +typedef struct { + EFI_PHYSICAL_ADDRESS ImageBase; + EFI_PHYSICAL_ADDRESS PayloadBaseAddress; + UINT64 PayloadSize; + UINTN PayloadEntryOffset; + UINTN PayloadEntrySize; + EFI_PHYSICAL_ADDRESS PayloadEntryPoint; + UINTN RelocateTableOffset; + UINTN RelocateTableCount; + EFI_PHYSICAL_ADDRESS PayloadLoadAddress; +} FIT_IMAGE_CONTEXT; + +typedef struct { + UINT8 *Name; + UINT32 Offset; +} PROPERTY_DATA; + +#define IMAGE_BASE_OFFSET OFFSET_OF (FIT_IMAGE_CONTEXT, ImageBase) +#define PAYLOAD_BASE_ADDR_OFFSET OFFSET_OF (FIT_IMAGE_CONTEXT, PayloadBaseAddress) +#define PAYLOAD_BASE_SIZE_OFFSET OFFSET_OF (FIT_IMAGE_CONTEXT, PayloadSize) +#define PAYLOAD_ENTRY_OFFSET_OFFSET OFFSET_OF (FIT_IMAGE_CONTEXT, PayloadEntryOffset) +#define PAYLOAD_ENTRY_SIZE_OFFSET OFFSET_OF (FIT_IMAGE_CONTEXT, PayloadEntrySize) +#define PAYLOAD_ENTRY_POINT_OFFSET OFFSET_OF (FIT_IMAGE_CONTEXT, PayloadEntryPoint) +#define RELOCATE_TABLE_OFFSET_OFFSET OFFSET_OF (FIT_IMAGE_CONTEXT, RelocateTableOffset) +#define RELOCATE_TABLE_COUNT_OFFSET OFFSET_OF (FIT_IMAGE_CONTEXT, RelocateTableCount) +#define PAYLOAD_LOAD_ADDR_OFFSET OFFSET_OF (FIT_IMAGE_CONTEXT, PayloadLoadAddress) + +/** + Parse the FIT image info. + @param[in] ImageBase Memory address of an image. + @param[out] Context The FIT image context pointer. + @retval EFI_UNSUPPORTED Unsupported binary type. + @retval EFI_SUCCESS FIT binary is loaded successfully. +**/ +EFI_STATUS +EFIAPI +ParseFitImage ( + IN VOID *ImageBase, + OUT FIT_IMAGE_CONTEXT *Context + ); + +#endif diff --git a/UefiPayloadPkg/PayloadLoaderPeim/FitLib/FitLib.c b/UefiPayloadPkg/PayloadLoaderPeim/FitLib/FitLib.c new file mode 100644 index 0000000000..9d1d8a4f61 --- /dev/null +++ b/UefiPayloadPkg/PayloadLoaderPeim/FitLib/FitLib.c @@ -0,0 +1,127 @@ +/** @file + FIT Load Image Support +Copyright (c) 2023, Intel Corporation. All rights reserved.<BR> +SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include "FitLib.h" + +PROPERTY_DATA PropertyData32List[] = { + { "data-offset", PAYLOAD_ENTRY_OFFSET_OFFSET }, + { "data-size", PAYLOAD_ENTRY_SIZE_OFFSET }, + { "reloc-start", RELOCATE_TABLE_OFFSET_OFFSET } +}; + +PROPERTY_DATA PropertyData64List[] = { + { "entry-start", PAYLOAD_ENTRY_POINT_OFFSET }, + { "load", PAYLOAD_LOAD_ADDR_OFFSET } +}; + +/** + Parse the target firmware image info in FIT. + @param[in] Fdt Memory address of a fdt. + @param[in] Firmware Target name of an image. + @param[out] Context The FIT image context pointer. + @retval EFI_NOT_FOUND FIT node dose not find. + @retval EFI_SUCCESS FIT binary is loaded successfully. +**/ +EFI_STATUS +EFIAPI +FitParseFirmwarePropertyData ( + IN VOID *Fdt, + IN CHAR8 *Firmware, + OUT FIT_IMAGE_CONTEXT *Context + ) +{ + CONST FDT_PROPERTY *PropertyPtr; + INT32 ImageNode; + INT32 TianoNode; + INT32 TempLen; + UINT32 *Data32; + UINT64 *Data64; + UINT32 *ContextOffset32; + UINT64 *ContextOffset64; + INT32 Index; + + ImageNode = FdtSubnodeOffsetNameLen (Fdt, 0, "images", (INT32)AsciiStrLen ("images")); + if (ImageNode <= 0) { + return EFI_NOT_FOUND; + } + + TianoNode = FdtSubnodeOffsetNameLen (Fdt, ImageNode, Firmware, (INT32)AsciiStrLen (Firmware)); + if (TianoNode <= 0) { + return EFI_NOT_FOUND; + } + + for (Index = 0; Index < sizeof (PropertyData32List) / sizeof (PROPERTY_DATA); Index++) { + PropertyPtr = FdtGetProperty (Fdt, TianoNode, PropertyData32List[Index].Name, &TempLen); + Data32 = (UINT32 *)(PropertyPtr->Data); + ContextOffset32 = (UINT32 *)((UINTN)Context + PropertyData32List[Index].Offset); + *ContextOffset32 = Fdt32ToCpu (*Data32); + } + + for (Index = 0; Index < sizeof (PropertyData64List)/sizeof (PROPERTY_DATA); Index++) { + PropertyPtr = FdtGetProperty (Fdt, TianoNode, PropertyData64List[Index].Name, &TempLen); + Data64 = (UINT64 *)(PropertyPtr->Data); + ContextOffset64 = (UINT64 *)((UINTN)Context + PropertyData64List[Index].Offset); + *ContextOffset64 = Fdt64ToCpu (*Data64); + } + + return EFI_SUCCESS; +} + +/** + Parse the FIT image info. + @param[in] ImageBase Memory address of an image. + @param[out] Context The FIT image context pointer. + @retval EFI_UNSUPPORTED Unsupported binary type. + @retval EFI_SUCCESS FIT binary is loaded successfully. +**/ +EFI_STATUS +EFIAPI +ParseFitImage ( + IN VOID *ImageBase, + OUT FIT_IMAGE_CONTEXT *Context + ) +{ + VOID *Fdt; + INT32 ConfigNode; + INT32 Config1Node; + CONST FDT_PROPERTY *PropertyPtr; + INT32 TempLen; + UINT32 *Data32; + UINT64 Value; + EFI_STATUS Status; + UINTN UplSize; + CHAR8 *Firmware; + + Status = FdtCheckHeader (ImageBase); + if (EFI_ERROR (Status)) { + return EFI_UNSUPPORTED; + } + + Fdt = ImageBase; + PropertyPtr = FdtGetProperty (Fdt, 0, "size", &TempLen); + Data32 = (UINT32 *)(PropertyPtr->Data); + UplSize = Value = Fdt32ToCpu (*Data32); + ConfigNode = FdtSubnodeOffsetNameLen (Fdt, 0, "configurations", (INT32)AsciiStrLen ("configurations")); + if (ConfigNode <= 0) { + return EFI_NOT_FOUND; + } + + Config1Node = FdtSubnodeOffsetNameLen (Fdt, ConfigNode, "conf-1", (INT32)AsciiStrLen ("conf-1")); + if (Config1Node <= 0) { + return EFI_NOT_FOUND; + } + + PropertyPtr = FdtGetProperty (Fdt, Config1Node, "firmware", &TempLen); + Firmware = (CHAR8 *)(PropertyPtr->Data); + + FitParseFirmwarePropertyData (Fdt, Firmware, Context); + + Context->ImageBase = (EFI_PHYSICAL_ADDRESS)ImageBase; + Context->PayloadSize = UplSize; + Context->RelocateTableCount = (Context->PayloadEntrySize - (Context->RelocateTableOffset - Context->PayloadEntryOffset)) / sizeof (FIT_RELOCATE_ITEM); + + return EFI_SUCCESS; +} diff --git a/UefiPayloadPkg/PayloadLoaderPeim/FitPayloadLoaderPeim.c b/UefiPayloadPkg/PayloadLoaderPeim/FitPayloadLoaderPeim.c new file mode 100644 index 0000000000..de33d49bd1 --- /dev/null +++ b/UefiPayloadPkg/PayloadLoaderPeim/FitPayloadLoaderPeim.c @@ -0,0 +1,150 @@ +/** @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 0000000000..cd0cb186e1 --- /dev/null +++ b/UefiPayloadPkg/PayloadLoaderPeim/FitPayloadLoaderPeim.inf @@ -0,0 +1,59 @@ +## @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 0000000000..cb7f39b3f7 --- /dev/null +++ b/UefiPayloadPkg/Readme.md @@ -0,0 +1,189 @@ +# 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 0000000000..82ab933d6d --- /dev/null +++ b/UefiPayloadPkg/Tools/MkFitImage.py @@ -0,0 +1,272 @@ +## @file +# This file is a script to build fit image. +# It generate a dtb header and combine a binary file after this header. +# +# Copyright (c) 2023, Intel Corporation. All rights reserved.<BR> +# SPDX-License-Identifier: BSD-2-Clause-Patent +## + +from os.path import exists +import libfdt +from ctypes import * +import time + +class FIT_IMAGE_INFO_HEADER: + """Class for user setting data to use MakeFitImage() + """ + _pack_ = 1 + _fields_ = [ + ('Compatible', str), + ('UplVersion', int), + ('Description', str), + ('Type', str), + ('Arch', str), + ('Compression', str), + ('Revision', int), + ('BuildType', str), + ('Capabilities', str), + ('Producer', str), + ('ImageId', str), + ('DataOffset', int), + ('DataSize', int), + ('RelocStart', int), + ('LoadAddr', int), + ('Entry', int), + ('Binary', str), + ('TargetPath', str), + ('UefifvPath', str), + ('BdsfvPath', str), + ('NetworkfvPath', str), + ('Project', str), + ] + + def __init__(self): + self.Compatible = 'universal-payload' + self.UplVersion = 0x0100 + self.TargetPath = 'mkimage.fit' + +def CreatFdt(Fdt): + FdtEmptyTree = libfdt.fdt_create_empty_tree(Fdt, len(Fdt)) + if FdtEmptyTree != 0: + print('\n- Failed - Create Fdt failed!') + return False + return True + +def BuildConfNode(Fdt, ParentNode, MultiImage): + ConfNode1 = libfdt.fdt_add_subnode(Fdt, ParentNode, 'conf-1') + + libfdt.fdt_setprop(Fdt, ConfNode1, 'require-fit', b'', 0) + libfdt.fdt_setprop(Fdt, ConfNode1, 'firmware', bytes('tianocore', 'utf-8'), len('tianocore') + 1) + +def BuildFvImageNode(Fdt, InfoHeader, ParentNode, DataOffset, DataSize, Description): + libfdt.fdt_setprop_u32(Fdt, ParentNode, 'data-size', DataSize) + libfdt.fdt_setprop_u32(Fdt, ParentNode, 'data-offset', DataOffset) + libfdt.fdt_setprop(Fdt, ParentNode, 'compression', bytes('none', 'utf-8'), len('none') + 1) + libfdt.fdt_setprop(Fdt, ParentNode, 'project ', bytes('tianocore', 'utf-8'), len('tianocore') + 1) + libfdt.fdt_setprop(Fdt, ParentNode, 'arch', bytes('x86_64', 'utf-8'), len('x86_64') + 1) + libfdt.fdt_setprop(Fdt, ParentNode, 'type', bytes('flat-binary', 'utf-8'), len('flat-binary') + 1) + libfdt.fdt_setprop(Fdt, ParentNode, 'description', bytes(Description, 'utf-8'), len(Description) + 1) + +def BuildTianoImageNode(Fdt, InfoHeader, ParentNode, DataOffset, DataSize, Description): + # + # Set 'load' and 'data-offset' to reserve the memory first. + # They would be set again when Fdt completes or this function parses target binary file. + # + if InfoHeader.LoadAddr is not None: + libfdt.fdt_setprop_u64(Fdt, ParentNode, 'load', InfoHeader.LoadAddr) + if InfoHeader.Entry is not None: + libfdt.fdt_setprop_u64(Fdt, ParentNode, 'entry-start', InfoHeader.Entry) + if InfoHeader.RelocStart is not None: + libfdt.fdt_setprop_u32(Fdt, ParentNode, 'reloc-start', InfoHeader.RelocStart) + if InfoHeader.DataSize is not None: + libfdt.fdt_setprop_u32(Fdt, ParentNode, 'data-size', DataSize) + if InfoHeader.DataOffset is not None: + libfdt.fdt_setprop_u32(Fdt, ParentNode, 'data-offset', DataOffset) + if InfoHeader.Producer is not None: + libfdt.fdt_setprop(Fdt, ParentNode, 'producer ', bytes(InfoHeader.Producer, 'utf-8'), len(InfoHeader.Producer) + 1) + if InfoHeader.Capabilities is not None: + CapStrs = ','.join(InfoHeader.Capabilities) + libfdt.fdt_setprop(Fdt, ParentNode, 'capabilities ', bytes(CapStrs, 'utf-8'), len(CapStrs) + 1) + if InfoHeader.Type is not None: + libfdt.fdt_setprop(Fdt, ParentNode, 'type ', bytes(InfoHeader.Type, 'utf-8'), len(InfoHeader.Type) + 1) + if InfoHeader.Arch is not None: + libfdt.fdt_setprop(Fdt, ParentNode, 'arch ', bytes(InfoHeader.Arch, 'utf-8'), len(InfoHeader.Arch) + 1) + if InfoHeader.Project is not None: + libfdt.fdt_setprop(Fdt, ParentNode, 'project ', bytes(InfoHeader.Project, 'utf-8'), len(InfoHeader.Project) + 1) + if InfoHeader.Description is not None: + libfdt.fdt_setprop(Fdt, ParentNode, 'description', bytes(Description, 'utf-8'), len(Description) + 1) + +# +# The subnode would be inserted from bottom to top of structure block. +# +def BuildFitImage(Fdt, InfoHeader): + MultiImage = [ + ["tianocore", InfoHeader.Binary, BuildTianoImageNode , InfoHeader.Description, None, 0 ], + ["uefi-fv", InfoHeader.UefifvPath, BuildFvImageNode, "UEFI Firmware Volume", None, 0 ], + ["bds-fv", InfoHeader.BdsfvPath, BuildFvImageNode , "BDS Firmware Volume", None, 0 ], + ["network-fv", InfoHeader.NetworkfvPath, BuildFvImageNode , "Network Firmware Volume", None, 0 ], + ] + + # + # Set basic information + # + libfdt.fdt_setprop_u32(Fdt, 0, 'build-revision ', InfoHeader.Revision) + libfdt.fdt_setprop_u32(Fdt, 0, 'spec-version', InfoHeader.UplVersion) + + # + # Build configurations node + # + ConfNode = libfdt.fdt_add_subnode(Fdt, 0, 'configurations') + BuildConfNode(Fdt, ConfNode, MultiImage) + + # Build image + DataOffset = InfoHeader.DataOffset + for Index in range (0, len (MultiImage)): + _, Path, _, _, _, _ = MultiImage[Index] + if exists(Path) == 1: + TempBinary = open(Path, 'rb') + BinaryData = TempBinary.read() + TempBinary.close() + MultiImage[Index][-2] = BinaryData + MultiImage[Index][-1] = DataOffset + DataOffset += len (BinaryData) + libfdt.fdt_setprop_u32(Fdt, 0, 'size', DataOffset) + posix_time = int(time.time()) + libfdt.fdt_setprop_u32(Fdt, 0, 'timestamp', posix_time) + DescriptionFit = 'Uefi OS Loader' + libfdt.fdt_setprop(Fdt, 0, 'description', bytes(DescriptionFit, 'utf-8'), len(DescriptionFit) + 1) + + ImageNode = libfdt.fdt_add_subnode(Fdt, 0, 'images') + for Item in reversed (MultiImage): + Name, Path, BuildFvNode, Description, BinaryData, DataOffset = Item + FvNode = libfdt.fdt_add_subnode(Fdt, ImageNode, Name) + BuildFvNode (Fdt, InfoHeader, FvNode, DataOffset, len(BinaryData), Description) + + # + # Create new image file and combine all binary. + # + DtbFile = open(InfoHeader.TargetPath, "wb") + DtbFile.truncate() + DtbFile.write(Fdt) + for Item in MultiImage: + _, _, _, _, BinaryData, _ = Item + DtbFile.write(BinaryData) + DtbFile.close() + + return True + +def MakeFitImage(InfoHeader): + # + # Allocate fdt byte array. + # + Fdt = bytearray(InfoHeader.DataOffset) + + # + # Create fdt empty tree. + # + if CreatFdt(Fdt) is False: + return False + + # + # Parse args to build fit image. + # + return BuildFitImage(Fdt, InfoHeader) + +def ReplaceFv (UplBinary, SectionFvFile, SectionName): + try: + # + # Get Original Multi Fv + # + with open (UplBinary, "rb") as File: + Dtb = File.read () + Fit = libfdt.Fdt (Dtb) + NewFitHeader = bytearray(Dtb[0:Fit.totalsize()]) + FitSize = len(Dtb) + + LoadablesList = [] + ImagesNode = libfdt.fdt_subnode_offset(NewFitHeader, 0, 'images') + FvNode = libfdt.fdt_subnode_offset(NewFitHeader, ImagesNode, 'uefi-fv') + NodeDepth = libfdt.fdt_node_depth (NewFitHeader, ImagesNode) + node_name = libfdt.fdt_get_name(NewFitHeader, FvNode) + FvNode = libfdt.fdt_next_node(NewFitHeader, FvNode, NodeDepth) + + while node_name[0][-2:] == 'fv': + LoadablesList.append (node_name[0]) + node_name = libfdt.fdt_get_name(NewFitHeader, FvNode[0]) + FvNode = libfdt.fdt_next_node(NewFitHeader, FvNode[0], NodeDepth) + # + # Get current Fit Binary FV data + # + MultiFvList = [] + for Item in LoadablesList: + ImageNode = libfdt.fdt_subnode_offset(NewFitHeader, ImagesNode, Item) + ImageOffset = int.from_bytes (libfdt.fdt_getprop (NewFitHeader, ImageNode, 'data-offset')[0], 'big') + ImageSize = int.from_bytes (libfdt.fdt_getprop (NewFitHeader, ImageNode, 'data-size')[0], 'big') + MultiFvList.append ([Item, Dtb[ImageOffset:ImageOffset + ImageSize]]) + + IsFvExist = False + for Index in range (0, len (MultiFvList)): + if MultiFvList[Index][0] == SectionName: + with open (SectionFvFile, 'rb') as File: + MultiFvList[Index][1] = File.read () + ImageNode = libfdt.fdt_subnode_offset(NewFitHeader, ImagesNode, SectionName) + ImageSize = int.from_bytes (libfdt.fdt_getprop (NewFitHeader, ImageNode, 'data-size')[0], 'big') + ReplaceOffset = int.from_bytes (libfdt.fdt_getprop (NewFitHeader, ImageNode, 'data-offset')[0], 'big') + OffsetDelta = len(MultiFvList[Index][1]) - ImageSize + FitSize += OffsetDelta + IsFvExist = True + libfdt.fdt_setprop_u32(NewFitHeader, ImageNode, 'data-size', len(MultiFvList[Index][1])) + + # + # Update new fit header + # + ImagesNode = libfdt.fdt_subnode_offset(NewFitHeader, 0, 'images') + if (IsFvExist == False): + with open (SectionFvFile, 'rb') as File: + SectionFvFileBinary = File.read () + MultiFvList.append ([SectionName, SectionFvFileBinary]) + FvNode = libfdt.fdt_add_subnode(NewFitHeader, ImagesNode, SectionName) + BuildFvImageNode (NewFitHeader, None, FvNode, FitSize, len(SectionFvFileBinary), SectionName + " Firmware Volume") + FitSize += len(SectionFvFileBinary) + else: + for Index in range (0, len (MultiFvList)): + ImageNode = libfdt.fdt_subnode_offset(NewFitHeader, ImagesNode, MultiFvList[Index][0]) + ImageOffset = int.from_bytes (libfdt.fdt_getprop (NewFitHeader, ImageNode, 'data-offset')[0], 'big') + if ImageOffset > ReplaceOffset: + libfdt.fdt_setprop_u32(NewFitHeader, ImageNode, 'data-offset', ImageOffset + OffsetDelta) + + ConfNodes = libfdt.fdt_subnode_offset(NewFitHeader, 0, 'configurations') + libfdt.fdt_setprop(NewFitHeader, ConfNodes, 'default ', bytes('conf-1', 'utf-8'), len('conf-1') + 1) + ConfNode = libfdt.fdt_subnode_offset(NewFitHeader, ConfNodes, 'conf-1') + + libfdt.fdt_setprop_u32(NewFitHeader, 0, 'size', FitSize) + + # + # Generate new fit image + # + ImagesNode = libfdt.fdt_subnode_offset(NewFitHeader, 0, 'images') + TianoNode = libfdt.fdt_subnode_offset(NewFitHeader, ImagesNode, 'tianocore') + TianoOffset = int.from_bytes (libfdt.fdt_getprop (NewFitHeader, TianoNode, 'data-offset')[0], 'big') + TianoSize = int.from_bytes (libfdt.fdt_getprop (NewFitHeader, TianoNode, 'data-size')[0], 'big') + TianoBinary = Dtb[TianoOffset:TianoOffset + TianoSize] + + print("\nGenerate new fit image:") + NewUplBinary = bytearray(FitSize) + print("Update fit header\t to 0x0\t\t ~ " + str(hex(len(NewFitHeader)))) + NewUplBinary[:len(NewFitHeader)] = NewFitHeader + print("Update tiano image\t to " + str(hex(len(NewFitHeader))) + "\t ~ " + str(hex(len(NewFitHeader) + len(TianoBinary)))) + NewUplBinary[len(NewFitHeader):len(NewFitHeader) + len(TianoBinary)] = TianoBinary + for Index in range (0, len (MultiFvList)): + ImageNode = libfdt.fdt_subnode_offset(NewFitHeader, ImagesNode, MultiFvList[Index][0]) + ImageOffset = int.from_bytes (libfdt.fdt_getprop (NewFitHeader, ImageNode, 'data-offset')[0], 'big') + ImageSize = int.from_bytes (libfdt.fdt_getprop (NewFitHeader, ImageNode, 'data-size')[0], 'big') + NewUplBinary[ImageOffset:ImageOffset + ImageSize] = MultiFvList[Index][1] + print("Update " + MultiFvList[Index][0] + "\t\t to " + str(hex(ImageOffset)) + "\t ~ " + str(hex(ImageOffset + ImageSize))) + + with open (UplBinary, "wb") as File: + File.write (NewUplBinary) + + return 0 + except Exception as Ex: + print(Ex) + return 1 diff --git a/UefiPayloadPkg/UefiPayloadEntry/FitUniversalPayloadEntry.c b/UefiPayloadPkg/UefiPayloadEntry/FitUniversalPayloadEntry.c new file mode 100644 index 0000000000..ad04ad7eb9 --- /dev/null +++ b/UefiPayloadPkg/UefiPayloadEntry/FitUniversalPayloadEntry.c @@ -0,0 +1,654 @@ +/** @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 0000000000..01fb3aceb3 --- /dev/null +++ b/UefiPayloadPkg/UefiPayloadEntry/FitUniversalPayloadEntry.inf @@ -0,0 +1,98 @@ +## @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 e2e4a79db3..2f1fd82487 100644 --- a/UefiPayloadPkg/UefiPayloadPkg.dec +++ b/UefiPayloadPkg/UefiPayloadPkg.dec @@ -24,6 +24,9 @@ # gUefiPayloadPkgTokenSpaceGuid = {0x1d127ea, 0xf6f1, 0x4ef6, {0x94, 0x15, 0x8a, 0x0, 0x0, 0x93, 0xf8, 0x9d}} + ## Include/Guid/UniversalPayloadBase.h + gUniversalPayloadBaseGuid = { 0x03d4c61d, 0x2713, 0x4ec5, {0xa1, 0xcc, 0x88, 0x3b, 0xe9, 0xdc, 0x18, 0xe5 } } + # # Gop Temp # diff --git a/UefiPayloadPkg/UefiPayloadPkg.dsc b/UefiPayloadPkg/UefiPayloadPkg.dsc index 47812048dd..af9308ef8e 100644 --- a/UefiPayloadPkg/UefiPayloadPkg.dsc +++ b/UefiPayloadPkg/UefiPayloadPkg.dsc @@ -30,7 +30,6 @@ DEFINE PS2_KEYBOARD_ENABLE = FALSE DEFINE RAM_DISK_ENABLE = FALSE DEFINE SIO_BUS_ENABLE = FALSE - DEFINE UNIVERSAL_PAYLOAD = FALSE DEFINE SECURITY_STUB_ENABLE = TRUE DEFINE SMM_SUPPORT = FALSE DEFINE PLATFORM_BOOT_TIMEOUT = 3 @@ -44,6 +43,14 @@ DEFINE BOOTSPLASH_IMAGE = FALSE DEFINE NVME_ENABLE = TRUE DEFINE CAPSULE_SUPPORT = FALSE + # + # Setup Universal Payload + # + # ELF: Build UniversalPayload file as UniversalPayload.elf + # FIT: Build UniversalPayload file as UniversalPayload.fit + # + DEFINE UNIVERSAL_PAYLOAD = FALSE + DEFINE UNIVERSAL_PAYLOAD_FORMAT = ELF # # NULL: NullMemoryTestDxe @@ -311,7 +318,7 @@ VariableFlashInfoLib|MdeModulePkg/Library/BaseVariableFlashInfoLib/BaseVariableFlashInfoLib.inf CcExitLib|UefiCpuPkg/Library/CcExitLibNull/CcExitLibNull.inf ReportStatusCodeLib|MdeModulePkg/Library/DxeReportStatusCodeLib/DxeReportStatusCodeLib.inf - + FdtLib|MdePkg/Library/BaseFdtLib/BaseFdtLib.inf [LibraryClasses.common] !if $(BOOTSPLASH_IMAGE) SafeIntLib|MdePkg/Library/BaseSafeIntLib/BaseSafeIntLib.inf @@ -600,14 +607,26 @@ !if "IA32" in "$(ARCH)" [Components.IA32] !if $(UNIVERSAL_PAYLOAD) == TRUE - UefiPayloadPkg/UefiPayloadEntry/UniversalPayloadEntry.inf + !if $(UNIVERSAL_PAYLOAD_FORMAT) == "ELF" + UefiPayloadPkg/UefiPayloadEntry/UniversalPayloadEntry.inf + !elseif $(UNIVERSAL_PAYLOAD_FORMAT) == "FIT" + UefiPayloadPkg/UefiPayloadEntry/FitUniversalPayloadEntry.inf + !else + UefiPayloadPkg/UefiPayloadEntry/UefiPayloadEntry.inf + !endif !else UefiPayloadPkg/UefiPayloadEntry/UefiPayloadEntry.inf !endif !else [Components.X64] !if $(UNIVERSAL_PAYLOAD) == TRUE - UefiPayloadPkg/UefiPayloadEntry/UniversalPayloadEntry.inf + !if $(UNIVERSAL_PAYLOAD_FORMAT) == "ELF" + UefiPayloadPkg/UefiPayloadEntry/UniversalPayloadEntry.inf + !elseif $(UNIVERSAL_PAYLOAD_FORMAT) == "FIT" + UefiPayloadPkg/UefiPayloadEntry/FitUniversalPayloadEntry.inf + !else + UefiPayloadPkg/UefiPayloadEntry/UefiPayloadEntry.inf + !endif !else UefiPayloadPkg/UefiPayloadEntry/UefiPayloadEntry.inf !endif diff --git a/UefiPayloadPkg/UniversalPayloadBuild.py b/UefiPayloadPkg/UniversalPayloadBuild.py index 47f37b3377..9a83fc9e44 100644 --- a/UefiPayloadPkg/UniversalPayloadBuild.py +++ b/UefiPayloadPkg/UniversalPayloadBuild.py @@ -10,10 +10,22 @@ import subprocess import os import shutil import sys +import pathlib from ctypes import * -from Tools.ElfFv import ReplaceFv + sys.dont_write_bytecode = True +class bcolors: + HEADER = '\033[95m' + OKBLUE = '\033[94m' + OKCYAN = '\033[96m' + OKGREEN = '\033[92m' + WARNING = '\033[93m' + FAIL = '\033[91m' + ENDC = '\033[0m' + BOLD = '\033[1m' + UNDERLINE = '\033[4m' + class UPLD_INFO_HEADER(LittleEndianStructure): _pack_ = 1 _fields_ = [ @@ -36,40 +48,114 @@ class UPLD_INFO_HEADER(LittleEndianStructure): self.ImageId = b'UEFI' self.ProducerId = b'INTEL' -def BuildUniversalPayload(Args): - def RunCommand(cmd): - print(cmd) - p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT,cwd=os.environ['WORKSPACE']) - while True: - line = p.stdout.readline() - if not line: - break - print(line.strip().decode(errors='ignore')) - - p.communicate() - if p.returncode != 0: - print("- Failed - error happened when run command: %s"%cmd) - raise Exception("ERROR: when run command: %s"%cmd) +def ValidateSpecRevision (Argument): + try: + (MajorStr, MinorStr) = Argument.split('.') + except: + raise argparse.ArgumentTypeError ('{} is not a valid SpecRevision format (Major[8-bits].Minor[8-bits]).'.format (Argument)) + # + # Spec Revision Bits 15 : 8 - Major Version. Bits 7 : 0 - Minor Version. + # + if len(MinorStr) > 0 and len(MinorStr) < 3: + try: + Minor = int(MinorStr, 16) if len(MinorStr) == 2 else (int(MinorStr, 16) << 4) + except: + raise argparse.ArgumentTypeError ('{} Minor version of SpecRevision is not a valid integer value.'.format (Argument)) + else: + raise argparse.ArgumentTypeError ('{} is not a valid SpecRevision format (Major[8-bits].Minor[8-bits]).'.format (Argument)) + + if len(MajorStr) > 0 and len(MajorStr) < 3: + try: + Major = int(MajorStr, 16) + except: + raise argparse.ArgumentTypeError ('{} Major version of SpecRevision is not a valid integer value.'.format (Argument)) + else: + raise argparse.ArgumentTypeError ('{} is not a valid SpecRevision format (Major[8-bits].Minor[8-bits]).'.format (Argument)) + + return int('0x{0:02x}{1:02x}'.format(Major, Minor), 0) + +def Validate32BitInteger (Argument): + try: + Value = int (Argument, 0) + except: + raise argparse.ArgumentTypeError ('{} is not a valid integer value.'.format (Argument)) + if Value < 0: + raise argparse.ArgumentTypeError ('{} is a negative value.'.format (Argument)) + if Value > 0xffffffff: + raise argparse.ArgumentTypeError ('{} is larger than 32-bits.'.format (Argument)) + return Value +def ValidateAddFv (Argument): + Value = Argument.split ("=") + if len (Value) != 2: + raise argparse.ArgumentTypeError ('{} is incorrect format with "xxx_fv=xxx.fv"'.format (Argument)) + if Value[0][-3:] != "_fv": + raise argparse.ArgumentTypeError ('{} is incorrect format with "xxx_fv=xxx.fv"'.format (Argument)) + if Value[1][-3:].lower () != ".fv": + raise argparse.ArgumentTypeError ('{} is incorrect format with "xxx_fv=xxx.fv"'.format (Argument)) + if os.path.exists (Value[1]) == False: + raise argparse.ArgumentTypeError ('File {} is not found.'.format (Value[1])) + return Value + +def RunCommand(cmd): + print(cmd) + p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT,cwd=os.environ['WORKSPACE']) + while True: + line = p.stdout.readline() + if not line: + break + print(line.strip().decode(errors='ignore')) + + p.communicate() + if p.returncode != 0: + print("- Failed - error happened when run command: %s"%cmd) + raise Exception("ERROR: when run command: %s"%cmd) + +def BuildUniversalPayload(Args): BuildTarget = Args.Target ToolChain = Args.ToolChain Quiet = "--quiet" if Args.Quiet else "" - ElfToolChain = 'CLANGDWARF' - BuildDir = os.path.join(os.environ['WORKSPACE'], os.path.normpath("Build/UefiPayloadPkgX64")) - BuildModule = "" - BuildArch = "" + if Args.Fit == True: + PayloadEntryToolChain = ToolChain + Args.Macro.append("UNIVERSAL_PAYLOAD_FORMAT=FIT") + UpldEntryFile = "FitUniversalPayloadEntry" + else: + PayloadEntryToolChain = 'CLANGDWARF' + Args.Macro.append("UNIVERSAL_PAYLOAD_FORMAT=ELF") + UpldEntryFile = "UniversalPayloadEntry" + + BuildDir = os.path.join(os.environ['WORKSPACE'], os.path.normpath("Build/UefiPayloadPkgX64")) if Args.Arch == 'X64': BuildArch = "X64" - EntryOutputDir = os.path.join(BuildDir, "{}_{}".format (BuildTarget, ElfToolChain), os.path.normpath("X64/UefiPayloadPkg/UefiPayloadEntry/UniversalPayloadEntry/DEBUG/UniversalPayloadEntry.dll")) + FitArch = "x86_64" + ObjCopyFlag = "elf64-x86-64" + EntryOutputDir = os.path.join(BuildDir, "{}_{}".format (BuildTarget, PayloadEntryToolChain), os.path.normpath("X64/UefiPayloadPkg/UefiPayloadEntry/{}/DEBUG/{}.dll".format (UpldEntryFile, UpldEntryFile))) else: BuildArch = "IA32 -a X64" - EntryOutputDir = os.path.join(BuildDir, "{}_{}".format (BuildTarget, ElfToolChain), os.path.normpath("IA32/UefiPayloadPkg/UefiPayloadEntry/UniversalPayloadEntry/DEBUG/UniversalPayloadEntry.dll")) + FitArch = "x86" + ObjCopyFlag = "elf32-i386" + EntryOutputDir = os.path.join(BuildDir, "{}_{}".format (BuildTarget, PayloadEntryToolChain), os.path.normpath("IA32/UefiPayloadPkg/UefiPayloadEntry/{}/DEBUG/{}.dll".format (UpldEntryFile, UpldEntryFile))) + EntryModuleInf = os.path.normpath("UefiPayloadPkg/UefiPayloadEntry/{}.inf".format (UpldEntryFile)) DscPath = os.path.normpath("UefiPayloadPkg/UefiPayloadPkg.dsc") + DxeFvOutputDir = os.path.join(BuildDir, "{}_{}".format (BuildTarget, ToolChain), os.path.normpath("FV/DXEFV.Fv")) + BdsFvOutputDir = os.path.join(BuildDir, "{}_{}".format (BuildTarget, ToolChain), os.path.normpath("FV/BDSFV.Fv")) + NetworkFvOutputDir = os.path.join(BuildDir, "{}_{}".format (BuildTarget, ToolChain), os.path.normpath("FV/NETWORKFV.Fv")) + PayloadReportPath = os.path.join(BuildDir, "UefiUniversalPayload.txt") ModuleReportPath = os.path.join(BuildDir, "UefiUniversalPayloadEntry.txt") UpldInfoFile = os.path.join(BuildDir, "UniversalPayloadInfo.bin") + if "CLANG_BIN" in os.environ: + LlvmObjcopyPath = os.path.join(os.environ["CLANG_BIN"], "llvm-objcopy") + else: + LlvmObjcopyPath = "llvm-objcopy" + try: + RunCommand('"%s" --version'%LlvmObjcopyPath) + except: + print("- Failed - Please check if LLVM is installed or if CLANG_BIN is set correctly") + sys.exit(1) + Pcds = "" if (Args.pcd != None): for PcdItem in Args.pcd: @@ -84,7 +170,6 @@ def BuildUniversalPayload(Args): # Building DXE core and DXE drivers as DXEFV. # if Args.BuildEntryOnly == False: - PayloadReportPath = os.path.join(BuildDir, "UefiUniversalPayload.txt") BuildPayload = "build -p {} -b {} -a X64 -t {} -y {} {}".format (DscPath, BuildTarget, ToolChain, PayloadReportPath, Quiet) BuildPayload += Pcds BuildPayload += Defines @@ -93,94 +178,138 @@ def BuildUniversalPayload(Args): # Building Universal Payload entry. # if Args.PreBuildUplBinary is None: - EntryModuleInf = os.path.normpath("UefiPayloadPkg/UefiPayloadEntry/UniversalPayloadEntry.inf") - BuildModule = "build -p {} -b {} -a {} -m {} -t {} -y {} {}".format (DscPath, BuildTarget, BuildArch, EntryModuleInf, ElfToolChain, ModuleReportPath, Quiet) + BuildModule = "build -p {} -b {} -a {} -m {} -t {} -y {} {}".format (DscPath, BuildTarget, BuildArch, EntryModuleInf, PayloadEntryToolChain, ModuleReportPath, Quiet) BuildModule += Pcds BuildModule += Defines RunCommand(BuildModule) if Args.PreBuildUplBinary is not None: - EntryOutputDir = os.path.join(BuildDir, "UniversalPayload.elf") + if Args.Fit == False: + EntryOutputDir = os.path.join(BuildDir, "UniversalPayload.elf") + else: + EntryOutputDir = os.path.join(BuildDir, "UniversalPayload.fit") shutil.copy (os.path.abspath(Args.PreBuildUplBinary), EntryOutputDir) # - # Buid Universal Payload Information Section ".upld_info" + # Build Universal Payload Information Section ".upld_info" # - upld_info_hdr = UPLD_INFO_HEADER() - upld_info_hdr.SpecRevision = Args.SpecRevision - upld_info_hdr.Revision = Args.Revision - upld_info_hdr.ProducerId = Args.ProducerId.encode()[:16] - upld_info_hdr.ImageId = Args.ImageId.encode()[:16] - upld_info_hdr.Attribute |= 1 if BuildTarget == "DEBUG" else 0 - fp = open(UpldInfoFile, 'wb') - fp.write(bytearray(upld_info_hdr)) - fp.close() + if Args.Fit == False: + upld_info_hdr = UPLD_INFO_HEADER() + upld_info_hdr.SpecRevision = Args.SpecRevision + upld_info_hdr.Revision = Args.Revision + upld_info_hdr.ProducerId = Args.ProducerId.encode()[:16] + upld_info_hdr.ImageId = Args.ImageId.encode()[:16] + upld_info_hdr.Attribute |= 1 if BuildTarget == "DEBUG" else 0 + fp = open(UpldInfoFile, 'wb') + fp.write(bytearray(upld_info_hdr)) + fp.close() + + if Args.BuildEntryOnly == False: + import Tools.ElfFv as ElfFv + ElfFv.ReplaceFv (EntryOutputDir, UpldInfoFile, '.upld_info', Alignment = 4) + if Args.Fit == False: + shutil.copy (EntryOutputDir, os.path.join(BuildDir, 'UniversalPayload.elf')) + else: + shutil.copy (EntryOutputDir, os.path.join(BuildDir, 'UniversalPayload.fit')) MultiFvList = [] if Args.BuildEntryOnly == False: MultiFvList = [ - ['uefi_fv', os.path.join(BuildDir, "{}_{}".format (BuildTarget, ToolChain), os.path.normpath("FV/DXEFV.Fv")) ], - ['bds_fv', os.path.join(BuildDir, "{}_{}".format (BuildTarget, ToolChain), os.path.normpath("FV/BDSFV.Fv")) ], - ['network_fv', os.path.join(BuildDir, "{}_{}".format (BuildTarget, ToolChain), os.path.normpath("FV/NETWORKFV.Fv")) ], + ['uefi_fv', os.path.join(BuildDir, "{}_{}".format (BuildTarget, ToolChain), os.path.normpath("FV/DXEFV.Fv")) ], + ['bds_fv', os.path.join(BuildDir, "{}_{}".format (BuildTarget, ToolChain), os.path.normpath("FV/BDSFV.Fv")) ], + ['network_fv', os.path.join(BuildDir, "{}_{}".format (BuildTarget, ToolChain), os.path.normpath("FV/NETWORKFV.Fv"))], ] - AddSectionName = '.upld_info' - ReplaceFv (EntryOutputDir, UpldInfoFile, AddSectionName, Alignment = 4) - if Args.PreBuildUplBinary is None: - shutil.copy (EntryOutputDir, os.path.join(BuildDir, 'UniversalPayload.elf')) - return MultiFvList, os.path.join(BuildDir, 'UniversalPayload.elf') + if Args.Fit == True: + import Tools.MkFitImage as MkFitImage + import pefile + fit_image_info_header = MkFitImage.FIT_IMAGE_INFO_HEADER() + fit_image_info_header.Description = 'Uefi Universal Payload' + fit_image_info_header.UplVersion = Args.SpecRevision + fit_image_info_header.Type = 'flat-binary' + fit_image_info_header.Arch = FitArch + fit_image_info_header.Compression = 'none' + fit_image_info_header.Revision = Args.Revision + fit_image_info_header.BuildType = Args.Target.lower() + fit_image_info_header.Capabilities = None + fit_image_info_header.Producer = Args.ProducerId.lower() + fit_image_info_header.ImageId = Args.ImageId.lower() + fit_image_info_header.Binary = os.path.join(BuildDir, 'UniversalPayload.fit') + fit_image_info_header.TargetPath = os.path.join(BuildDir, 'UniversalPayload.fit') + fit_image_info_header.UefifvPath = DxeFvOutputDir + fit_image_info_header.BdsfvPath = BdsFvOutputDir + fit_image_info_header.NetworkfvPath = NetworkFvOutputDir + fit_image_info_header.DataOffset = 0x1000 + fit_image_info_header.LoadAddr = Args.LoadAddress + fit_image_info_header.Project = 'tianocore' + + TargetRebaseFile = fit_image_info_header.Binary.replace (pathlib.Path(fit_image_info_header.Binary).suffix, ".pecoff") + TargetRebaseEntryFile = fit_image_info_header.Binary.replace (pathlib.Path(fit_image_info_header.Binary).suffix, ".entry") + -def main(): - def ValidateSpecRevision (Argument): - try: - (MajorStr, MinorStr) = Argument.split('.') - except: - raise argparse.ArgumentTypeError ('{} is not a valid SpecRevision format (Major[8-bits].Minor[8-bits]).'.format (Argument)) # - # Spec Revision Bits 15 : 8 - Major Version. Bits 7 : 0 - Minor Version. + # Rebase PECOFF to load address # - if len(MinorStr) > 0 and len(MinorStr) < 3: - try: - Minor = int(MinorStr, 16) if len(MinorStr) == 2 else (int(MinorStr, 16) << 4) - except: - raise argparse.ArgumentTypeError ('{} Minor version of SpecRevision is not a valid integer value.'.format (Argument)) - else: - raise argparse.ArgumentTypeError ('{} is not a valid SpecRevision format (Major[8-bits].Minor[8-bits]).'.format (Argument)) + RunCommand ( + "GenFw -e SEC -o {} {}".format ( + TargetRebaseFile, + fit_image_info_header.Binary + )) + RunCommand ( + "GenFw --rebase 0x{:02X} -o {} {} ".format ( + fit_image_info_header.LoadAddr + fit_image_info_header.DataOffset, + TargetRebaseFile, + TargetRebaseFile, + )) - if len(MajorStr) > 0 and len(MajorStr) < 3: - try: - Major = int(MajorStr, 16) - except: - raise argparse.ArgumentTypeError ('{} Major version of SpecRevision is not a valid integer value.'.format (Argument)) - else: - raise argparse.ArgumentTypeError ('{} is not a valid SpecRevision format (Major[8-bits].Minor[8-bits]).'.format (Argument)) + # + # Open PECOFF relocation table binary. + # + RelocBinary = b'' + PeCoff = pefile.PE (TargetRebaseFile) + for reloc in PeCoff.DIRECTORY_ENTRY_BASERELOC: + for entry in reloc.entries: + if (entry.type == 0): + continue + Type = entry.type + Offset = entry.rva + fit_image_info_header.DataOffset + RelocBinary += Type.to_bytes (8, 'little') + Offset.to_bytes (8, 'little') + RelocBinary += b'\x00' * (0x1000 - (len(RelocBinary) % 0x1000)) - return int('0x{0:02x}{1:02x}'.format(Major, Minor), 0) + # + # Output UniversalPayload.entry + # + TempBinary = open (TargetRebaseFile, 'rb') + TianoBinary = TempBinary.read () + TempBinary.close () - def Validate32BitInteger (Argument): - try: - Value = int (Argument, 0) - except: - raise argparse.ArgumentTypeError ('{} is not a valid integer value.'.format (Argument)) - if Value < 0: - raise argparse.ArgumentTypeError ('{} is a negative value.'.format (Argument)) - if Value > 0xffffffff: - raise argparse.ArgumentTypeError ('{} is larger than 32-bits.'.format (Argument)) - return Value - - def ValidateAddFv (Argument): - Value = Argument.split ("=") - if len (Value) != 2: - raise argparse.ArgumentTypeError ('{} is incorrect format with "xxx_fv=xxx.fv"'.format (Argument)) - if Value[0][-3:] != "_fv": - raise argparse.ArgumentTypeError ('{} is incorrect format with "xxx_fv=xxx.fv"'.format (Argument)) - if Value[1][-3:].lower () != ".fv": - raise argparse.ArgumentTypeError ('{} is incorrect format with "xxx_fv=xxx.fv"'.format (Argument)) - if os.path.exists (Value[1]) == False: - raise argparse.ArgumentTypeError ('File {} is not found.'.format (Value[1])) - return Value + TianoEntryBinary = TianoBinary + RelocBinary + TianoEntryBinary += (b'\x00' * (0x1000 - (len(TianoBinary) % 0x1000))) + TianoEntryBinarySize = len (TianoEntryBinary) + + TempBinary = open(TargetRebaseEntryFile, "wb") + TempBinary.truncate() + TempBinary.write(TianoEntryBinary) + TempBinary.close() + + # + # Calculate entry and update relocation table start address and data-size. + # + fit_image_info_header.Entry = PeCoff.OPTIONAL_HEADER.ImageBase + PeCoff.OPTIONAL_HEADER.AddressOfEntryPoint + fit_image_info_header.RelocStart = fit_image_info_header.DataOffset + len(TianoBinary) + fit_image_info_header.DataSize = TianoEntryBinarySize + fit_image_info_header.Binary = TargetRebaseEntryFile + + if MkFitImage.MakeFitImage(fit_image_info_header) is True: + print('\nSuccessfully build Fit Image') + else: + sys.exit(1) + return MultiFvList, os.path.join(BuildDir, 'UniversalPayload.fit') + else: + return MultiFvList, os.path.join(BuildDir, 'UniversalPayload.elf') +def main(): parser = argparse.ArgumentParser(description='For building Universal Payload') parser.add_argument('-t', '--ToolChain') parser.add_argument('-b', '--Target', default='DEBUG') @@ -192,13 +321,16 @@ def main(): parser.add_argument("-s", "--SpecRevision", type=ValidateSpecRevision, default ='0.7', help='Indicates compliance with a revision of this specification in the BCD format.') parser.add_argument("-r", "--Revision", type=Validate32BitInteger, default ='0x0000010105', help='Revision of the Payload binary. Major.Minor.Revision.Build') parser.add_argument("-o", "--ProducerId", default ='INTEL', help='A null-terminated OEM-supplied string that identifies the payload producer (16 bytes maximal).') + parser.add_argument("-e", "--BuildEntryOnly", action='store_true', help='Build UniversalPayload Entry file') + parser.add_argument("-pb", "--PreBuildUplBinary", default=None, help='Specify the UniversalPayload file') parser.add_argument("-sk", "--SkipBuild", action='store_true', help='Skip UniversalPayload build') parser.add_argument("-af", "--AddFv", type=ValidateAddFv, action='append', help='Add or replace specific FV into payload, Ex: uefi_fv=XXX.fv') - command_group = parser.add_mutually_exclusive_group() - command_group.add_argument("-e", "--BuildEntryOnly", action='store_true', help='Build UniversalPayload Entry file') - command_group.add_argument("-pb", "--PreBuildUplBinary", default=None, help='Specify the UniversalPayload file') + parser.add_argument("-f", "--Fit", action='store_true', help='Build UniversalPayload file as UniversalPayload.fit', default=False) + parser.add_argument('-l', "--LoadAddress", type=int, help='Specify payload load address', default =0x000800000) + args = parser.parse_args() + MultiFvList = [] UniversalPayloadBinary = args.PreBuildUplBinary if (args.SkipBuild == False): @@ -208,12 +340,24 @@ def main(): for (SectionName, SectionFvFile) in args.AddFv: MultiFvList.append ([SectionName, SectionFvFile]) + def ReplaceFv (UplBinary, SectionFvFile, SectionName): + print (bcolors.OKGREEN + "Patch {}={} into {}".format (SectionName, SectionFvFile, UplBinary) + bcolors.ENDC) + if (args.Fit == False): + import Tools.ElfFv as ElfFv + return ElfFv.ReplaceFv (UplBinary, SectionFvFile, '.upld.{}'.format (SectionName)) + else: + import Tools.MkFitImage as MkFitImage + return MkFitImage.ReplaceFv (UplBinary, SectionFvFile, SectionName) + if (UniversalPayloadBinary != None): for (SectionName, SectionFvFile) in MultiFvList: if os.path.exists (SectionFvFile) == False: continue - print ("Patch {}={} into {}".format (SectionName, SectionFvFile, UniversalPayloadBinary)) - ReplaceFv (UniversalPayloadBinary, SectionFvFile, '.upld.{}'.format (SectionName)) + + status = ReplaceFv (UniversalPayloadBinary, SectionFvFile, SectionName.replace ("_", "-")) + if status != 0: + print (bcolors.FAIL + "[Fail] Patch {}={}".format (SectionName, SectionFvFile) + bcolors.ENDC) + return status print ("\nSuccessfully build Universal Payload") -- 2.39.1.windows.1 -=-=-=-=-=-=-=-=-=-=-=- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#108792): https://edk2.groups.io/g/devel/message/108792 Mute This Topic: https://groups.io/mt/101435620/7686176 Group Owner: devel+owner@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io] -=-=-=-=-=-=-=-=-=-=-=- ^ permalink raw reply related [flat|nested] 6+ messages in thread
end of thread, other threads:[~2023-09-18 15:17 UTC | newest] Thread overview: 6+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2023-09-18 6:37 [edk2-devel] [PATCH v4 0/4] UefiPayloadPkg: Add FIT support brucex.wang 2023-09-18 6:37 ` [edk2-devel] [PATCH v4 1/4] OvmfPkg: Remove applicationProcessorEntryPoint brucex.wang 2023-09-18 6:37 ` [edk2-devel] [PATCH v4 2/4] UefiCpuPkg/ResetVector: Remove AP waking vector from ResetVector brucex.wang 2023-09-18 6:37 ` [edk2-devel] [PATCH v4 3/4] MdePkg/BaseFdtLib: Add Fdt function brucex.wang 2023-09-18 6:37 ` [edk2-devel] [PATCH v4 4/4] UefiPayloadPkg: Add FIT support brucex.wang -- strict thread matches above, loose matches on Subject: below -- 2023-09-18 6:42 [edk2-devel] [PATCH v4 0/4] " brucex.wang 2023-09-18 6:42 ` [edk2-devel] [PATCH v4 4/4] " brucex.wang
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox