Files
system76-edk2/UefiPayloadPkg/UefiPayloadEntry/LoadDxeCore.c
Zhiguang Liu b208d37c73 UefiPayloadPkg: Get and enter DxeCore for Universal Payload
From gUniversalPayloadExtraDataGuid Guid Hob, get the Dxe FV information,
and get the Dxe Core from the FV.
Also, make sure if there are muliple FV hob, the FV hob pointing to this FV
will be the first in the hob list.

Cc: Maurice Ma <maurice.ma@intel.com>
Cc: Guo Dong <guo.dong@intel.com>
Cc: Benjamin You <benjamin.you@intel.com>
Reviewed-by: Guo Dong <guo.dong@intel.com>
Signed-off-by: Zhiguang Liu <zhiguang.liu@intel.com>
2021-06-24 09:16:22 +00:00

355 lines
9.6 KiB
C

/** @file
Copyright (c) 2020, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include "UefiPayloadEntry.h"
/**
Allocate pages for code.
@param[in] Pages Number of pages to be allocated.
@return Allocated memory.
**/
VOID*
AllocateCodePages (
IN UINTN Pages
)
{
VOID *Alloc;
EFI_PEI_HOB_POINTERS Hob;
Alloc = AllocatePages (Pages);
if (Alloc == NULL) {
return NULL;
}
// find the HOB we just created, and change the type to EfiBootServicesCode
Hob.Raw = GetFirstHob (EFI_HOB_TYPE_MEMORY_ALLOCATION);
while (Hob.Raw != NULL) {
if (Hob.MemoryAllocation->AllocDescriptor.MemoryBaseAddress == (UINTN)Alloc) {
Hob.MemoryAllocation->AllocDescriptor.MemoryType = EfiBootServicesCode;
return Alloc;
}
Hob.Raw = GetNextHob (EFI_HOB_TYPE_MEMORY_ALLOCATION, GET_NEXT_HOB (Hob));
}
ASSERT (FALSE);
FreePages (Alloc, Pages);
return NULL;
}
/**
Loads and relocates a PE/COFF image
@param[in] PeCoffImage Point to a Pe/Coff image.
@param[out] ImageAddress The image memory address after relocation.
@param[out] ImageSize The image size.
@param[out] EntryPoint The image entry point.
@return EFI_SUCCESS If the image is loaded and relocated successfully.
@return Others If the image failed to load or relocate.
**/
EFI_STATUS
LoadPeCoffImage (
IN VOID *PeCoffImage,
OUT EFI_PHYSICAL_ADDRESS *ImageAddress,
OUT UINT64 *ImageSize,
OUT EFI_PHYSICAL_ADDRESS *EntryPoint
)
{
RETURN_STATUS Status;
PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;
VOID *Buffer;
ZeroMem (&ImageContext, sizeof (ImageContext));
ImageContext.Handle = PeCoffImage;
ImageContext.ImageRead = PeCoffLoaderImageReadFromMemory;
Status = PeCoffLoaderGetImageInfo (&ImageContext);
if (EFI_ERROR (Status)) {
ASSERT_EFI_ERROR (Status);
return Status;
}
//
// Allocate Memory for the image
//
Buffer = AllocateCodePages (EFI_SIZE_TO_PAGES((UINT32)ImageContext.ImageSize));
if (Buffer == NULL) {
return EFI_OUT_OF_RESOURCES;
}
ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)Buffer;
//
// Load the image to our new buffer
//
Status = PeCoffLoaderLoadImage (&ImageContext);
if (EFI_ERROR (Status)) {
ASSERT_EFI_ERROR (Status);
return Status;
}
//
// Relocate the image in our new buffer
//
Status = PeCoffLoaderRelocateImage (&ImageContext);
if (EFI_ERROR (Status)) {
ASSERT_EFI_ERROR (Status);
return Status;
}
*ImageAddress = ImageContext.ImageAddress;
*ImageSize = ImageContext.ImageSize;
*EntryPoint = ImageContext.EntryPoint;
return EFI_SUCCESS;
}
/**
This function searchs a given file type within a valid FV.
@param FvHeader A pointer to firmware volume header that contains the set of files
to be searched.
@param FileType File type to be searched.
@param FileHeader A pointer to the discovered file, if successful.
@retval EFI_SUCCESS Successfully found FileType
@retval EFI_NOT_FOUND File type can't be found.
**/
EFI_STATUS
FvFindFile (
IN EFI_FIRMWARE_VOLUME_HEADER *FvHeader,
IN EFI_FV_FILETYPE FileType,
OUT EFI_FFS_FILE_HEADER **FileHeader
)
{
EFI_PHYSICAL_ADDRESS CurrentAddress;
EFI_PHYSICAL_ADDRESS EndOfFirmwareVolume;
EFI_FFS_FILE_HEADER *File;
UINT32 Size;
EFI_PHYSICAL_ADDRESS EndOfFile;
CurrentAddress = (EFI_PHYSICAL_ADDRESS)(UINTN) FvHeader;
EndOfFirmwareVolume = CurrentAddress + FvHeader->FvLength;
//
// Loop through the FFS files
//
for (EndOfFile = CurrentAddress + FvHeader->HeaderLength; ; ) {
CurrentAddress = (EndOfFile + 7) & 0xfffffffffffffff8ULL;
if (CurrentAddress > EndOfFirmwareVolume) {
break;
}
File = (EFI_FFS_FILE_HEADER*)(UINTN) CurrentAddress;
if (IS_FFS_FILE2 (File)) {
Size = FFS_FILE2_SIZE (File);
if (Size <= 0x00FFFFFF) {
break;
}
} else {
Size = FFS_FILE_SIZE (File);
if (Size < sizeof (EFI_FFS_FILE_HEADER)) {
break;
}
}
EndOfFile = CurrentAddress + Size;
if (EndOfFile > EndOfFirmwareVolume) {
break;
}
//
// Look for file type
//
if (File->Type == FileType) {
*FileHeader = File;
return EFI_SUCCESS;
}
}
return EFI_NOT_FOUND;
}
/**
This function searchs a given section type within a valid FFS file.
@param FileHeader A pointer to the file header that contains the set of sections to
be searched.
@param SearchType The value of the section type to search.
@param SectionData A pointer to the discovered section, if successful.
@retval EFI_SUCCESS The section was found.
@retval EFI_NOT_FOUND The section was not found.
**/
EFI_STATUS
FileFindSection (
IN EFI_FFS_FILE_HEADER *FileHeader,
IN EFI_SECTION_TYPE SectionType,
OUT VOID **SectionData
)
{
UINT32 FileSize;
EFI_COMMON_SECTION_HEADER *Section;
UINT32 SectionSize;
UINT32 Index;
if (IS_FFS_FILE2 (FileHeader)) {
FileSize = FFS_FILE2_SIZE (FileHeader);
} else {
FileSize = FFS_FILE_SIZE (FileHeader);
}
FileSize -= sizeof (EFI_FFS_FILE_HEADER);
Section = (EFI_COMMON_SECTION_HEADER *)(FileHeader + 1);
Index = 0;
while (Index < FileSize) {
if (Section->Type == SectionType) {
if (IS_SECTION2 (Section)) {
*SectionData = (VOID *)((UINT8 *) Section + sizeof (EFI_COMMON_SECTION_HEADER2));
} else {
*SectionData = (VOID *)((UINT8 *) Section + sizeof (EFI_COMMON_SECTION_HEADER));
}
return EFI_SUCCESS;
}
if (IS_SECTION2 (Section)) {
SectionSize = SECTION2_SIZE (Section);
} else {
SectionSize = SECTION_SIZE (Section);
}
SectionSize = GET_OCCUPIED_SIZE (SectionSize, 4);
ASSERT (SectionSize != 0);
Index += SectionSize;
Section = (EFI_COMMON_SECTION_HEADER *)((UINT8 *)Section + SectionSize);
}
return EFI_NOT_FOUND;
}
/**
Find DXE core from FV and build DXE core HOBs.
@param[out] DxeCoreEntryPoint DXE core entry point
@retval EFI_SUCCESS If it completed successfully.
@retval EFI_NOT_FOUND If it failed to load DXE FV.
**/
EFI_STATUS
LoadDxeCore (
OUT PHYSICAL_ADDRESS *DxeCoreEntryPoint
)
{
EFI_STATUS Status;
EFI_FIRMWARE_VOLUME_HEADER *PayloadFv;
EFI_FIRMWARE_VOLUME_HEADER *DxeCoreFv;
EFI_FFS_FILE_HEADER *FileHeader;
VOID *PeCoffImage;
EFI_PHYSICAL_ADDRESS ImageAddress;
UINT64 ImageSize;
PayloadFv = (EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)PcdGet32 (PcdPayloadFdMemBase);
//
// DXE FV is inside Payload FV. Here find DXE FV from Payload FV
//
Status = FvFindFile (PayloadFv, EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE, &FileHeader);
if (EFI_ERROR (Status)) {
return Status;
}
Status = FileFindSection (FileHeader, EFI_SECTION_FIRMWARE_VOLUME_IMAGE, (VOID **)&DxeCoreFv);
if (EFI_ERROR (Status)) {
return Status;
}
//
// Report DXE FV to DXE core
//
BuildFvHob ((EFI_PHYSICAL_ADDRESS) (UINTN) DxeCoreFv, DxeCoreFv->FvLength);
//
// Find DXE core file from DXE FV
//
Status = FvFindFile (DxeCoreFv, EFI_FV_FILETYPE_DXE_CORE, &FileHeader);
if (EFI_ERROR (Status)) {
return Status;
}
Status = FileFindSection (FileHeader, EFI_SECTION_PE32, (VOID **)&PeCoffImage);
if (EFI_ERROR (Status)) {
return Status;
}
//
// Get DXE core info
//
Status = LoadPeCoffImage (PeCoffImage, &ImageAddress, &ImageSize, DxeCoreEntryPoint);
if (EFI_ERROR (Status)) {
return Status;
}
BuildModuleHob (&FileHeader->Name, ImageAddress, EFI_SIZE_TO_PAGES ((UINT32) ImageSize) * EFI_PAGE_SIZE, *DxeCoreEntryPoint);
return EFI_SUCCESS;
}
/**
Find DXE core from FV and build DXE core HOBs.
@param[in] DxeFv The FV where to find the DXE core.
@param[out] DxeCoreEntryPoint DXE core entry point
@retval EFI_SUCCESS If it completed successfully.
@retval EFI_NOT_FOUND If it failed to load DXE FV.
**/
EFI_STATUS
UniversalLoadDxeCore (
IN EFI_FIRMWARE_VOLUME_HEADER *DxeFv,
OUT PHYSICAL_ADDRESS *DxeCoreEntryPoint
)
{
EFI_STATUS Status;
EFI_FFS_FILE_HEADER *FileHeader;
VOID *PeCoffImage;
EFI_PHYSICAL_ADDRESS ImageAddress;
UINT64 ImageSize;
//
// Find DXE core file from DXE FV
//
Status = FvFindFile (DxeFv, EFI_FV_FILETYPE_DXE_CORE, &FileHeader);
if (EFI_ERROR (Status)) {
return Status;
}
Status = FileFindSection (FileHeader, EFI_SECTION_PE32, (VOID **)&PeCoffImage);
if (EFI_ERROR (Status)) {
return Status;
}
//
// Get DXE core info
//
Status = LoadPeCoffImage (PeCoffImage, &ImageAddress, &ImageSize, DxeCoreEntryPoint);
if (EFI_ERROR (Status)) {
return Status;
}
BuildModuleHob (&FileHeader->Name, ImageAddress, EFI_SIZE_TO_PAGES ((UINT32) ImageSize) * EFI_PAGE_SIZE, *DxeCoreEntryPoint);
return EFI_SUCCESS;
}