mirror of https://github.com/acidanthera/audk.git
UefiPayloadPkg: Add FIT support
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> Reviewed-by: Gua Guo <gua.guo@intel.com> Signed-off-by: BruceX Wang <brucex.wang@intel.com>
This commit is contained in:
parent
d6b05375b4
commit
39f3c26e8c
|
@ -411,9 +411,9 @@ FdtSetProp (
|
|||
CONST CHAR8 *
|
||||
EFIAPI
|
||||
FdtGetName (
|
||||
IN VOID *Fdt,
|
||||
IN INT32 NodeOffset,
|
||||
IN UINT32 *Length
|
||||
IN VOID *Fdt,
|
||||
IN INT32 NodeOffset,
|
||||
IN INT32 *Length
|
||||
);
|
||||
|
||||
/**
|
||||
|
|
|
@ -416,12 +416,12 @@ FdtSetProp (
|
|||
CONST CHAR8 *
|
||||
EFIAPI
|
||||
FdtGetName (
|
||||
IN VOID *Fdt,
|
||||
IN INT32 NodeOffset,
|
||||
IN UINT32 *Length
|
||||
IN VOID *Fdt,
|
||||
IN INT32 NodeOffset,
|
||||
IN INT32 *Length
|
||||
)
|
||||
{
|
||||
return fdt_get_name (Fdt, NodeOffset, (int *)Length);
|
||||
return fdt_get_name (Fdt, NodeOffset, Length);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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_
|
|
@ -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 {
|
||||
CHAR8 *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
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -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 |
|
||||
+--------------------------------+
|
||||
|
||||
```
|
|
@ -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
|
|
@ -0,0 +1,653 @@
|
|||
/** @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
|
||||
));
|
||||
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;
|
||||
}
|
|
@ -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
|
|
@ -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
|
||||
#
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 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):
|
||||
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)
|
||||
|
||||
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,139 @@ 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.PreBuildUplBinary is None:
|
||||
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")
|
||||
|
||||
|
||||
#
|
||||
# Rebase PECOFF to load address
|
||||
#
|
||||
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,
|
||||
))
|
||||
|
||||
#
|
||||
# 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))
|
||||
|
||||
#
|
||||
# Output UniversalPayload.entry
|
||||
#
|
||||
TempBinary = open (TargetRebaseFile, 'rb')
|
||||
TianoBinary = TempBinary.read ()
|
||||
TempBinary.close ()
|
||||
|
||||
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():
|
||||
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
|
||||
|
||||
parser = argparse.ArgumentParser(description='For building Universal Payload')
|
||||
parser.add_argument('-t', '--ToolChain')
|
||||
parser.add_argument('-b', '--Target', default='DEBUG')
|
||||
|
@ -192,13 +322,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 +341,26 @@ 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))
|
||||
if (args.Fit == False):
|
||||
status = ReplaceFv (UniversalPayloadBinary, SectionFvFile, SectionName)
|
||||
else:
|
||||
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")
|
||||
|
||||
|
|
Loading…
Reference in New Issue