summaryrefslogtreecommitdiffstats
path: root/UefiPayloadPkg/UefiPayloadEntry/LoadDxeCore.c
diff options
context:
space:
mode:
Diffstat (limited to 'UefiPayloadPkg/UefiPayloadEntry/LoadDxeCore.c')
-rw-r--r--UefiPayloadPkg/UefiPayloadEntry/LoadDxeCore.c307
1 files changed, 307 insertions, 0 deletions
diff --git a/UefiPayloadPkg/UefiPayloadEntry/LoadDxeCore.c b/UefiPayloadPkg/UefiPayloadEntry/LoadDxeCore.c
new file mode 100644
index 0000000000..de9dbb0b0e
--- /dev/null
+++ b/UefiPayloadPkg/UefiPayloadEntry/LoadDxeCore.c
@@ -0,0 +1,307 @@
+/** @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;
+}