audk/OvmfPkg/Library/PeilessStartupLib/DxeLoad.c

219 lines
5.7 KiB
C

/** @file
Responsibility of this file is to load the DXE Core from a Firmware Volume.
Copyright (c) 2016 HP Development Company, L.P.
Copyright (c) 2006 - 2020, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include "PeilessStartupInternal.h"
#include <Library/DebugLib.h>
#include <Library/BaseLib.h>
#include <Library/BaseMemoryLib.h>
#include <Library/MemoryAllocationLib.h>
#include <Library/PcdLib.h>
#include <Guid/MemoryTypeInformation.h>
#include <Guid/MemoryAllocationHob.h>
#include <Guid/PcdDataBaseSignatureGuid.h>
#include <Register/Intel/Cpuid.h>
#include <Library/PrePiLib.h>
#include "X64/PageTables.h"
#include <Library/ReportStatusCodeLib.h>
#define STACK_SIZE 0x20000
/**
Transfers control to DxeCore.
This function performs a CPU architecture specific operations to execute
the entry point of DxeCore
@param DxeCoreEntryPoint The entry point of DxeCore.
**/
VOID
HandOffToDxeCore (
IN EFI_PHYSICAL_ADDRESS DxeCoreEntryPoint
)
{
VOID *BaseOfStack;
VOID *TopOfStack;
UINTN PageTables;
//
// Clear page 0 and mark it as allocated if NULL pointer detection is enabled.
//
if (IsNullDetectionEnabled ()) {
ClearFirst4KPage (GetHobList ());
BuildMemoryAllocationHob (0, EFI_PAGES_TO_SIZE (1), EfiBootServicesData);
}
//
// Allocate 128KB for the Stack
//
BaseOfStack = AllocatePages (EFI_SIZE_TO_PAGES (STACK_SIZE));
ASSERT (BaseOfStack != NULL);
//
// Compute the top of the stack we were allocated. Pre-allocate a UINTN
// for safety.
//
TopOfStack = (VOID *)((UINTN)BaseOfStack + EFI_SIZE_TO_PAGES (STACK_SIZE) * EFI_PAGE_SIZE - CPU_STACK_ALIGNMENT);
TopOfStack = ALIGN_POINTER (TopOfStack, CPU_STACK_ALIGNMENT);
DEBUG ((DEBUG_INFO, "BaseOfStack=0x%x, TopOfStack=0x%x\n", BaseOfStack, TopOfStack));
//
// Create page table and save PageMapLevel4 to CR3
//
PageTables = CreateIdentityMappingPageTables (
(EFI_PHYSICAL_ADDRESS)(UINTN)BaseOfStack,
STACK_SIZE
);
if (PageTables == 0) {
DEBUG ((DEBUG_ERROR, "Failed to create idnetity mapping page tables.\n"));
CpuDeadLoop ();
}
AsmWriteCr3 (PageTables);
//
// Update the contents of BSP stack HOB to reflect the real stack info passed to DxeCore.
//
UpdateStackHob ((EFI_PHYSICAL_ADDRESS)(UINTN)BaseOfStack, STACK_SIZE);
DEBUG ((DEBUG_INFO, "SwitchStack then Jump to DxeCore\n"));
//
// Transfer the control to the entry point of DxeCore.
//
SwitchStack (
(SWITCH_STACK_ENTRY_POINT)(UINTN)DxeCoreEntryPoint,
GetHobList (),
NULL,
TopOfStack
);
}
/**
Searches DxeCore in all firmware Volumes and loads the first
instance that contains DxeCore.
@return FileHandle of DxeCore to load DxeCore.
**/
EFI_STATUS
FindDxeCore (
IN INTN FvInstance,
IN OUT EFI_PEI_FILE_HANDLE *FileHandle
)
{
EFI_STATUS Status;
EFI_PEI_FV_HANDLE VolumeHandle;
if (FileHandle == NULL) {
ASSERT (FALSE);
return EFI_INVALID_PARAMETER;
}
*FileHandle = NULL;
//
// Caller passed in a specific FV to try, so only try that one
//
Status = FfsFindNextVolume (FvInstance, &VolumeHandle);
if (!EFI_ERROR (Status)) {
Status = FfsFindNextFile (EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE, VolumeHandle, FileHandle);
if (*FileHandle) {
// Assume the FV that contains multiple compressed FVs.
// So decompress the compressed FVs
Status = FfsProcessFvFile (*FileHandle);
ASSERT_EFI_ERROR (Status);
Status = FfsAnyFvFindFirstFile (EFI_FV_FILETYPE_DXE_CORE, &VolumeHandle, FileHandle);
}
}
return Status;
}
/**
This function finds DXE Core in the firmware volume and transfer the control to
DXE core.
@return EFI_SUCCESS DXE core was successfully loaded.
@return EFI_OUT_OF_RESOURCES There are not enough resources to load DXE core.
**/
EFI_STATUS
EFIAPI
DxeLoadCore (
IN INTN FvInstance
)
{
EFI_STATUS Status;
EFI_FV_FILE_INFO DxeCoreFileInfo;
EFI_PHYSICAL_ADDRESS DxeCoreAddress;
UINT64 DxeCoreSize;
EFI_PHYSICAL_ADDRESS DxeCoreEntryPoint;
EFI_PEI_FILE_HANDLE FileHandle;
VOID *PeCoffImage;
//
// Look in all the FVs present and find the DXE Core FileHandle
//
Status = FindDxeCore (FvInstance, &FileHandle);
if (EFI_ERROR (Status)) {
ASSERT (FALSE);
return Status;
}
//
// Load the DXE Core from a Firmware Volume.
//
Status = FfsFindSectionData (EFI_SECTION_PE32, FileHandle, &PeCoffImage);
if (EFI_ERROR (Status)) {
return Status;
}
Status = LoadPeCoffImage (PeCoffImage, &DxeCoreAddress, &DxeCoreSize, &DxeCoreEntryPoint);
ASSERT_EFI_ERROR (Status);
//
// Extract the DxeCore GUID file name.
//
Status = FfsGetFileInfo (FileHandle, &DxeCoreFileInfo);
ASSERT_EFI_ERROR (Status);
//
// Add HOB for the DXE Core
//
BuildModuleHob (
&DxeCoreFileInfo.FileName,
DxeCoreAddress,
ALIGN_VALUE (DxeCoreSize, EFI_PAGE_SIZE),
DxeCoreEntryPoint
);
DEBUG ((
DEBUG_INFO | DEBUG_LOAD,
"Loading DXE CORE at 0x%11p EntryPoint=0x%11p\n",
(VOID *)(UINTN)DxeCoreAddress,
FUNCTION_ENTRY_POINT (DxeCoreEntryPoint)
));
// Transfer control to the DXE Core
// The hand off state is simply a pointer to the HOB list
//
HandOffToDxeCore (DxeCoreEntryPoint);
//
// If we get here, then the DXE Core returned. This is an error
// DxeCore should not return.
//
ASSERT (FALSE);
CpuDeadLoop ();
return EFI_OUT_OF_RESOURCES;
}