Edk2 bootloader will pass the pei pcd database, and UPL also contain a PCD database. Dxe PCD driver has the assumption that the two PCD database can be catenated and the local token number should be successive。 This patch will manually fix up the UPL PCD database to meet that assumption. 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>
360 lines
9.9 KiB
C
360 lines
9.9 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 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 = 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;
|
|
}
|