UefiPayloadPkg: Add PayloadLoaderPeim which can load ELF payload
Per universal payload spec, the payload is in ELF format. The patch adds a payload loader that supports to load ELF image. The location of extra data sections whose names start with "upld." is stored in UNIVERSAL_PAYLOAD_EXTRA_DATA HOB. Signed-off-by: Maurice Ma <maurice.ma@intel.com> Signed-off-by: Ray Ni <ray.ni@intel.com> Cc: Maurice Ma <maurice.ma@intel.com> Reviewed-by: Guo Dong <guo.dong@intel.com> Cc: Benjamin You <benjamin.you@intel.com>
This commit is contained in:
187
UefiPayloadPkg/PayloadLoaderPeim/PayloadLoaderPeim.c
Normal file
187
UefiPayloadPkg/PayloadLoaderPeim/PayloadLoaderPeim.c
Normal file
@@ -0,0 +1,187 @@
|
||||
/** @file
|
||||
ELF Load Image Support
|
||||
|
||||
Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
|
||||
SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||
|
||||
**/
|
||||
|
||||
#include <PiPei.h>
|
||||
#include <UniversalPayload/UniversalPayload.h>
|
||||
#include <UniversalPayload/ExtraData.h>
|
||||
|
||||
#include <Ppi/LoadFile.h>
|
||||
|
||||
#include <Library/DebugLib.h>
|
||||
#include <Library/HobLib.h>
|
||||
#include <Library/PeiServicesLib.h>
|
||||
#include <Library/MemoryAllocationLib.h>
|
||||
#include <Library/BaseMemoryLib.h>
|
||||
|
||||
#include "ElfLib.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;
|
||||
VOID *Elf;
|
||||
UNIVERSAL_PAYLOAD_EXTRA_DATA *ExtraData;
|
||||
ELF_IMAGE_CONTEXT Context;
|
||||
UNIVERSAL_PAYLOAD_INFO_HEADER *PldInfo;
|
||||
UINT32 Index;
|
||||
UINT16 ExtraDataIndex;
|
||||
CHAR8 *SectionName;
|
||||
UINTN Offset;
|
||||
UINTN Size;
|
||||
UINT32 ExtraDataCount;
|
||||
UINTN Instance;
|
||||
|
||||
//
|
||||
// ELF is added to file as RAW section for EDKII bootloader.
|
||||
// But RAW section might be added by build tool before the ELF RAW section when alignment is specified for ELF RAW section.
|
||||
// Below loop skips the RAW section that doesn't contain valid ELF image.
|
||||
//
|
||||
Instance = 0;
|
||||
do {
|
||||
Status = PeiServicesFfsFindSectionData3 (EFI_SECTION_RAW, Instance++, FileHandle, &Elf, AuthenticationState);
|
||||
if (EFI_ERROR (Status)) {
|
||||
return Status;
|
||||
}
|
||||
|
||||
ZeroMem (&Context, sizeof (Context));
|
||||
Status = ParseElfImage (Elf, &Context);
|
||||
} while (EFI_ERROR (Status));
|
||||
|
||||
DEBUG ((
|
||||
DEBUG_INFO, "Payload File Size: 0x%08X, Mem Size: 0x%08x, Reload: %d\n",
|
||||
Context.FileSize, Context.ImageSize, Context.ReloadRequired
|
||||
));
|
||||
|
||||
//
|
||||
// Get UNIVERSAL_PAYLOAD_INFO_HEADER and number of additional PLD sections.
|
||||
//
|
||||
PldInfo = NULL;
|
||||
ExtraDataCount = 0;
|
||||
for (Index = 0; Index < Context.ShNum; Index++) {
|
||||
Status = GetElfSectionName (&Context, Index, &SectionName);
|
||||
if (EFI_ERROR(Status)) {
|
||||
continue;
|
||||
}
|
||||
DEBUG ((DEBUG_INFO, "Payload Section[%d]: %a\n", Index, SectionName));
|
||||
if (AsciiStrCmp(SectionName, UNIVERSAL_PAYLOAD_INFO_SEC_NAME) == 0) {
|
||||
Status = GetElfSectionPos (&Context, Index, &Offset, &Size);
|
||||
if (!EFI_ERROR(Status)) {
|
||||
PldInfo = (UNIVERSAL_PAYLOAD_INFO_HEADER *)(Context.FileBase + Offset);
|
||||
}
|
||||
} else if (AsciiStrnCmp(SectionName, UNIVERSAL_PAYLOAD_EXTRA_SEC_NAME_PREFIX, UNIVERSAL_PAYLOAD_EXTRA_SEC_NAME_PREFIX_LENGTH) == 0) {
|
||||
Status = GetElfSectionPos (&Context, Index, &Offset, &Size);
|
||||
if (!EFI_ERROR (Status)) {
|
||||
ExtraDataCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Report the additional PLD sections through HOB.
|
||||
//
|
||||
ExtraData = BuildGuidHob (
|
||||
&gUniversalPayloadExtraDataGuid,
|
||||
sizeof (UNIVERSAL_PAYLOAD_EXTRA_DATA) + ExtraDataCount * sizeof (UNIVERSAL_PAYLOAD_EXTRA_DATA_ENTRY)
|
||||
);
|
||||
ExtraData->Count = ExtraDataCount;
|
||||
if (ExtraDataCount != 0) {
|
||||
for (ExtraDataIndex = 0, Index = 0; Index < Context.ShNum; Index++) {
|
||||
Status = GetElfSectionName (&Context, Index, &SectionName);
|
||||
if (EFI_ERROR(Status)) {
|
||||
continue;
|
||||
}
|
||||
if (AsciiStrnCmp(SectionName, UNIVERSAL_PAYLOAD_EXTRA_SEC_NAME_PREFIX, UNIVERSAL_PAYLOAD_EXTRA_SEC_NAME_PREFIX_LENGTH) == 0) {
|
||||
Status = GetElfSectionPos (&Context, Index, &Offset, &Size);
|
||||
if (!EFI_ERROR (Status)) {
|
||||
ASSERT (ExtraDataIndex < ExtraDataCount);
|
||||
AsciiStrCpyS (
|
||||
ExtraData->Entry[ExtraDataIndex].Identifier,
|
||||
sizeof(ExtraData->Entry[ExtraDataIndex].Identifier),
|
||||
SectionName + UNIVERSAL_PAYLOAD_EXTRA_SEC_NAME_PREFIX_LENGTH
|
||||
);
|
||||
ExtraData->Entry[ExtraDataIndex].Base = (UINTN)(Context.FileBase + Offset);
|
||||
ExtraData->Entry[ExtraDataIndex].Size = Size;
|
||||
ExtraDataIndex++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (Context.ReloadRequired || Context.PreferredImageAddress != Context.FileBase) {
|
||||
Context.ImageAddress = AllocatePages (EFI_SIZE_TO_PAGES (Context.ImageSize));
|
||||
} else {
|
||||
Context.ImageAddress = Context.FileBase;
|
||||
}
|
||||
|
||||
//
|
||||
// Load ELF into the required base
|
||||
//
|
||||
Status = LoadElfImage (&Context);
|
||||
if (!EFI_ERROR(Status)) {
|
||||
*ImageAddressArg = (UINTN) Context.ImageAddress;
|
||||
*EntryPoint = Context.EntryPoint;
|
||||
*ImageSizeArg = Context.ImageSize;
|
||||
}
|
||||
return Status;
|
||||
}
|
||||
|
||||
|
||||
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
|
||||
InitializePayloadLoaderPeim (
|
||||
IN EFI_PEI_FILE_HANDLE FileHandle,
|
||||
IN CONST EFI_PEI_SERVICES **PeiServices
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
Status = PeiServicesInstallPpi (&gPpiLoadFilePpiList);
|
||||
|
||||
return Status;
|
||||
}
|
Reference in New Issue
Block a user