mirror of https://github.com/acidanthera/audk.git
362 lines
9.8 KiB
C
362 lines
9.8 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 with a given Guid within a valid FV.
|
|
If input Guid is NULL, will locate the first section having the given file type
|
|
|
|
@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 Guid Will ignore if it is NULL.
|
|
@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
|
|
FvFindFileByTypeGuid (
|
|
IN EFI_FIRMWARE_VOLUME_HEADER *FvHeader,
|
|
IN EFI_FV_FILETYPE FileType,
|
|
IN EFI_GUID *Guid OPTIONAL,
|
|
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) {
|
|
if ((Guid == NULL) || CompareGuid (&File->Name, Guid)) {
|
|
*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 SectionType 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 = FvFindFileByTypeGuid (PayloadFv, EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE, NULL, &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 = FvFindFileByTypeGuid (DxeCoreFv, EFI_FV_FILETYPE_DXE_CORE, NULL, &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 = FvFindFileByTypeGuid (DxeFv, EFI_FV_FILETYPE_DXE_CORE, NULL, &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;
|
|
}
|