/** @file
ELF Load Image Support
Copyright (c) 2021, Intel Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#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;
UINT32 Index;
UINT16 ExtraDataIndex;
CHAR8 *SectionName;
UINTN Offset;
UINTN Size;
UINT32 ExtraDataCount;
UINTN Instance;
UINTN Length;
//
// 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.
//
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);
} 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.
//
Length = sizeof (UNIVERSAL_PAYLOAD_EXTRA_DATA) + ExtraDataCount * sizeof (UNIVERSAL_PAYLOAD_EXTRA_DATA_ENTRY);
ExtraData = BuildGuidHob (
&gUniversalPayloadExtraDataGuid,
Length
);
ExtraData->Count = ExtraDataCount;
ExtraData->Header.Revision = UNIVERSAL_PAYLOAD_EXTRA_DATA_REVISION;
ExtraData->Header.Length = (UINT16)Length;
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;
}