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:
Brucex.Wang 2023-09-06 09:08:12 +08:00 committed by mergify[bot]
parent d6b05375b4
commit 39f3c26e8c
14 changed files with 1904 additions and 108 deletions

View File

@ -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
);
/**

View File

@ -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);
}
/**

View File

@ -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_

View File

@ -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

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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

189
UefiPayloadPkg/Readme.md Normal file
View File

@ -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 |
+--------------------------------+
```

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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
#

View File

@ -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

View File

@ -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")