/** @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 #include "ElfLib.h" CONST EFI_PEI_PPI_DESCRIPTOR gReadyToPayloadSignalPpi = { (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST), &gUplReadyToPayloadPpiGuid, NULL }; /** Notify ReadyToPayLoad signal. @param[in] PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation. @param[in] NotifyDescriptor Address of the notification descriptor data structure. @param[in] Ppi Address of the PPI that was installed. @retval EFI_SUCCESS Hobs data is discovered. @return Others No Hobs data is discovered. **/ EFI_STATUS EFIAPI EndOfPeiPpiNotifyCallback ( IN EFI_PEI_SERVICES **PeiServices, IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor, IN VOID *Ppi ) { EFI_STATUS Status; // // Ready to Payload phase signal // Status = PeiServicesInstallPpi (&gReadyToPayloadSignalPpi); return Status; } EFI_PEI_NOTIFY_DESCRIPTOR mEndOfPeiNotifyList[] = { { (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST), &gEfiEndOfPeiSignalPpiGuid, EndOfPeiPpiNotifyCallback } }; /** 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; UNIVERSAL_PAYLOAD_BASE *PayloadBase; 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)); Length = sizeof (UNIVERSAL_PAYLOAD_BASE); PayloadBase = BuildGuidHob ( &gUniversalPayloadBaseGuid, Length ); PayloadBase->Entry = (EFI_PHYSICAL_ADDRESS)Context.FileBase; 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; } DEBUG ((DEBUG_INFO, "LoadElfImage :%r, EntryPoint :%x\n", Status, (UINTN)Context.EntryPoint)); Status = PeiServicesNotifyPpi (&mEndOfPeiNotifyList[0]); ASSERT_EFI_ERROR (Status); 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_SUCCESS 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; }