mirror of https://github.com/acidanthera/audk.git
839 lines
26 KiB
C
839 lines
26 KiB
C
/** @file
|
|
Last PEIM.
|
|
Responsibility of this module is to load the DXE Core from a Firmware Volume.
|
|
|
|
Copyright (c) 2016 HP Development Company, L.P.
|
|
Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
|
|
SPDX-License-Identifier: BSD-2-Clause-Patent
|
|
|
|
**/
|
|
|
|
#include "DxeIpl.h"
|
|
|
|
//
|
|
// Module Globals used in the DXE to PEI hand off
|
|
// These must be module globals, so the stack can be switched
|
|
//
|
|
CONST EFI_DXE_IPL_PPI mDxeIplPpi = {
|
|
DxeLoadCore
|
|
};
|
|
|
|
CONST EFI_PEI_PPI_DESCRIPTOR mDxeIplPpiList = {
|
|
EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST,
|
|
&gEfiDxeIplPpiGuid,
|
|
(VOID *)&mDxeIplPpi
|
|
};
|
|
|
|
CONST EFI_PEI_GUIDED_SECTION_EXTRACTION_PPI mCustomGuidedSectionExtractionPpi = {
|
|
CustomGuidedSectionExtract
|
|
};
|
|
|
|
CONST EFI_PEI_DECOMPRESS_PPI mDecompressPpi = {
|
|
Decompress
|
|
};
|
|
|
|
CONST EFI_PEI_PPI_DESCRIPTOR mDecompressPpiList = {
|
|
(EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
|
|
&gEfiPeiDecompressPpiGuid,
|
|
(VOID *)&mDecompressPpi
|
|
};
|
|
|
|
CONST EFI_PEI_PPI_DESCRIPTOR gEndOfPeiSignalPpi = {
|
|
(EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
|
|
&gEfiEndOfPeiSignalPpiGuid,
|
|
NULL
|
|
};
|
|
|
|
CONST EFI_PEI_NOTIFY_DESCRIPTOR mMemoryDiscoveredNotifyList = {
|
|
(EFI_PEI_PPI_DESCRIPTOR_NOTIFY_DISPATCH | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
|
|
&gEfiPeiMemoryDiscoveredPpiGuid,
|
|
InstallIplPermanentMemoryPpis
|
|
};
|
|
|
|
/**
|
|
Entry point of DXE IPL PEIM.
|
|
|
|
This function installs DXE IPL PPI. It also reloads
|
|
itself to memory on non-S3 resume boot path.
|
|
|
|
@param FileHandle Handle of the file being invoked.
|
|
@param PeiServices Describes the list of possible PEI Services.
|
|
|
|
@retval EFI_SUCESS The entry point of DXE IPL PEIM executes successfully.
|
|
@retval Others Some error occurs during the execution of this function.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
PeimInitializeDxeIpl (
|
|
IN EFI_PEI_FILE_HANDLE FileHandle,
|
|
IN CONST EFI_PEI_SERVICES **PeiServices
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_BOOT_MODE BootMode;
|
|
VOID *Dummy;
|
|
|
|
BootMode = GetBootModeHob ();
|
|
|
|
if (BootMode != BOOT_ON_S3_RESUME) {
|
|
Status = PeiServicesRegisterForShadow (FileHandle);
|
|
if (Status == EFI_SUCCESS) {
|
|
//
|
|
// EFI_SUCESS means it is the first time to call register for shadow.
|
|
//
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// Ensure that DXE IPL is shadowed to permanent memory.
|
|
//
|
|
ASSERT (Status == EFI_ALREADY_STARTED);
|
|
|
|
//
|
|
// DXE core load requires permanent memory.
|
|
//
|
|
Status = PeiServicesLocatePpi (
|
|
&gEfiPeiMemoryDiscoveredPpiGuid,
|
|
0,
|
|
NULL,
|
|
(VOID **)&Dummy
|
|
);
|
|
ASSERT_EFI_ERROR (Status);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// Now the permanent memory exists, install the PPIs for decompression
|
|
// and section extraction.
|
|
//
|
|
Status = InstallIplPermanentMemoryPpis (NULL, NULL, NULL);
|
|
ASSERT_EFI_ERROR (Status);
|
|
} else {
|
|
//
|
|
// Install memory discovered PPI notification to install PPIs for
|
|
// decompression and section extraction.
|
|
//
|
|
Status = PeiServicesNotifyPpi (&mMemoryDiscoveredNotifyList);
|
|
ASSERT_EFI_ERROR (Status);
|
|
}
|
|
|
|
//
|
|
// Install DxeIpl PPI.
|
|
//
|
|
Status = PeiServicesInstallPpi (&mDxeIplPpiList);
|
|
ASSERT_EFI_ERROR (Status);
|
|
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
This function installs the PPIs that require permanent memory.
|
|
|
|
@param PeiServices Indirect reference to the PEI Services Table.
|
|
@param NotifyDescriptor Address of the notification descriptor data structure.
|
|
@param Ppi Address of the PPI that was installed.
|
|
|
|
@return EFI_SUCCESS The PPIs were installed successfully.
|
|
@return Others Some error occurs during the execution of this function.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
InstallIplPermanentMemoryPpis (
|
|
IN EFI_PEI_SERVICES **PeiServices,
|
|
IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,
|
|
IN VOID *Ppi
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_GUID *ExtractHandlerGuidTable;
|
|
UINTN ExtractHandlerNumber;
|
|
EFI_PEI_PPI_DESCRIPTOR *GuidPpi;
|
|
|
|
//
|
|
// Get custom extract guided section method guid list
|
|
//
|
|
ExtractHandlerNumber = ExtractGuidedSectionGetGuidList (&ExtractHandlerGuidTable);
|
|
|
|
//
|
|
// Install custom guided section extraction PPI
|
|
//
|
|
if (ExtractHandlerNumber > 0) {
|
|
GuidPpi = (EFI_PEI_PPI_DESCRIPTOR *)AllocatePool (ExtractHandlerNumber * sizeof (EFI_PEI_PPI_DESCRIPTOR));
|
|
ASSERT (GuidPpi != NULL);
|
|
while (ExtractHandlerNumber-- > 0) {
|
|
GuidPpi->Flags = EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST;
|
|
GuidPpi->Ppi = (VOID *)&mCustomGuidedSectionExtractionPpi;
|
|
GuidPpi->Guid = &ExtractHandlerGuidTable[ExtractHandlerNumber];
|
|
Status = PeiServicesInstallPpi (GuidPpi++);
|
|
ASSERT_EFI_ERROR (Status);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Install Decompress PPI.
|
|
//
|
|
Status = PeiServicesInstallPpi (&mDecompressPpiList);
|
|
ASSERT_EFI_ERROR (Status);
|
|
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
Validate variable data for the MemoryTypeInformation.
|
|
|
|
@param MemoryData Variable data.
|
|
@param MemoryDataSize Variable data length.
|
|
|
|
@return TRUE The variable data is valid.
|
|
@return FALSE The variable data is invalid.
|
|
|
|
**/
|
|
BOOLEAN
|
|
ValidateMemoryTypeInfoVariable (
|
|
IN EFI_MEMORY_TYPE_INFORMATION *MemoryData,
|
|
IN UINTN MemoryDataSize
|
|
)
|
|
{
|
|
UINTN Count;
|
|
UINTN Index;
|
|
|
|
// Check the input parameter.
|
|
if (MemoryData == NULL) {
|
|
return FALSE;
|
|
}
|
|
|
|
// Get Count
|
|
Count = MemoryDataSize / sizeof (*MemoryData);
|
|
|
|
// Check Size
|
|
if (Count * sizeof (*MemoryData) != MemoryDataSize) {
|
|
return FALSE;
|
|
}
|
|
|
|
// Check last entry type filed.
|
|
if (MemoryData[Count - 1].Type != EfiMaxMemoryType) {
|
|
return FALSE;
|
|
}
|
|
|
|
// Check the type filed.
|
|
for (Index = 0; Index < Count - 1; Index++) {
|
|
if (MemoryData[Index].Type >= EfiMaxMemoryType) {
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/**
|
|
Main entry point to last PEIM.
|
|
|
|
This function finds DXE Core in the firmware volume and transfer the control to
|
|
DXE core.
|
|
|
|
@param This Entry point for DXE IPL PPI.
|
|
@param PeiServices General purpose services available to every PEIM.
|
|
@param HobList Address to the Pei HOB list.
|
|
|
|
@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 CONST EFI_DXE_IPL_PPI *This,
|
|
IN EFI_PEI_SERVICES **PeiServices,
|
|
IN EFI_PEI_HOB_POINTERS HobList
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_FV_FILE_INFO DxeCoreFileInfo;
|
|
EFI_PHYSICAL_ADDRESS DxeCoreAddress;
|
|
UINT64 DxeCoreSize;
|
|
EFI_PHYSICAL_ADDRESS DxeCoreEntryPoint;
|
|
EFI_BOOT_MODE BootMode;
|
|
EFI_PEI_FILE_HANDLE FileHandle;
|
|
EFI_PEI_READ_ONLY_VARIABLE2_PPI *Variable;
|
|
EFI_PEI_LOAD_FILE_PPI *LoadFile;
|
|
UINTN Instance;
|
|
UINT32 AuthenticationState;
|
|
UINTN DataSize;
|
|
EFI_PEI_S3_RESUME2_PPI *S3Resume;
|
|
EFI_PEI_RECOVERY_MODULE_PPI *PeiRecovery;
|
|
EDKII_PEI_CAPSULE_ON_DISK_PPI *PeiCapsuleOnDisk;
|
|
EFI_MEMORY_TYPE_INFORMATION MemoryData[EfiMaxMemoryType + 1];
|
|
VOID *CapsuleOnDiskModePpi;
|
|
|
|
//
|
|
// if in S3 Resume, restore configure
|
|
//
|
|
BootMode = GetBootModeHob ();
|
|
|
|
if (BootMode == BOOT_ON_S3_RESUME) {
|
|
Status = PeiServicesLocatePpi (
|
|
&gEfiPeiS3Resume2PpiGuid,
|
|
0,
|
|
NULL,
|
|
(VOID **)&S3Resume
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
//
|
|
// Report Status code that S3Resume PPI can not be found
|
|
//
|
|
REPORT_STATUS_CODE (
|
|
EFI_ERROR_CODE | EFI_ERROR_MAJOR,
|
|
(EFI_SOFTWARE_PEI_MODULE | EFI_SW_PEI_EC_S3_RESUME_PPI_NOT_FOUND)
|
|
);
|
|
}
|
|
|
|
ASSERT_EFI_ERROR (Status);
|
|
|
|
Status = S3Resume->S3RestoreConfig2 (S3Resume);
|
|
ASSERT_EFI_ERROR (Status);
|
|
} else if (BootMode == BOOT_IN_RECOVERY_MODE) {
|
|
REPORT_STATUS_CODE (EFI_PROGRESS_CODE, (EFI_SOFTWARE_PEI_MODULE | EFI_SW_PEI_PC_RECOVERY_BEGIN));
|
|
Status = PeiServicesLocatePpi (
|
|
&gEfiPeiRecoveryModulePpiGuid,
|
|
0,
|
|
NULL,
|
|
(VOID **)&PeiRecovery
|
|
);
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((DEBUG_ERROR, "Locate Recovery PPI Failed.(Status = %r)\n", Status));
|
|
//
|
|
// Report Status code the failure of locating Recovery PPI
|
|
//
|
|
REPORT_STATUS_CODE (
|
|
EFI_ERROR_CODE | EFI_ERROR_MAJOR,
|
|
(EFI_SOFTWARE_PEI_MODULE | EFI_SW_PEI_EC_RECOVERY_PPI_NOT_FOUND)
|
|
);
|
|
CpuDeadLoop ();
|
|
}
|
|
|
|
REPORT_STATUS_CODE (EFI_PROGRESS_CODE, (EFI_SOFTWARE_PEI_MODULE | EFI_SW_PEI_PC_CAPSULE_LOAD));
|
|
Status = PeiRecovery->LoadRecoveryCapsule (PeiServices, PeiRecovery);
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((DEBUG_ERROR, "Load Recovery Capsule Failed.(Status = %r)\n", Status));
|
|
//
|
|
// Report Status code that recovery image can not be found
|
|
//
|
|
REPORT_STATUS_CODE (
|
|
EFI_ERROR_CODE | EFI_ERROR_MAJOR,
|
|
(EFI_SOFTWARE_PEI_MODULE | EFI_SW_PEI_EC_NO_RECOVERY_CAPSULE)
|
|
);
|
|
CpuDeadLoop ();
|
|
}
|
|
|
|
REPORT_STATUS_CODE (EFI_PROGRESS_CODE, (EFI_SOFTWARE_PEI_MODULE | EFI_SW_PEI_PC_CAPSULE_START));
|
|
//
|
|
// Now should have a HOB with the DXE core
|
|
//
|
|
} else if (BootMode == BOOT_ON_FLASH_UPDATE) {
|
|
//
|
|
// If Capsule On Disk mode, call storage stack to read Capsule Relocation file
|
|
// IoMmmu is highly recommmended to enable before reading
|
|
//
|
|
Status = PeiServicesLocatePpi (
|
|
&gEdkiiPeiBootInCapsuleOnDiskModePpiGuid,
|
|
0,
|
|
NULL,
|
|
&CapsuleOnDiskModePpi
|
|
);
|
|
if (!EFI_ERROR (Status)) {
|
|
Status = PeiServicesLocatePpi (
|
|
&gEdkiiPeiCapsuleOnDiskPpiGuid,
|
|
0,
|
|
NULL,
|
|
(VOID **)&PeiCapsuleOnDisk
|
|
);
|
|
|
|
//
|
|
// Whether failed, still goes to Firmware Update boot path. BDS will clear corresponding indicator and reboot later on
|
|
//
|
|
if (!EFI_ERROR (Status)) {
|
|
Status = PeiCapsuleOnDisk->LoadCapsuleOnDisk (PeiServices, PeiCapsuleOnDisk);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (GetFirstGuidHob ((CONST EFI_GUID *)&gEfiMemoryTypeInformationGuid) == NULL) {
|
|
//
|
|
// Don't build GuidHob if GuidHob has been installed.
|
|
//
|
|
Status = PeiServicesLocatePpi (
|
|
&gEfiPeiReadOnlyVariable2PpiGuid,
|
|
0,
|
|
NULL,
|
|
(VOID **)&Variable
|
|
);
|
|
if (!EFI_ERROR (Status)) {
|
|
DataSize = sizeof (MemoryData);
|
|
Status = Variable->GetVariable (
|
|
Variable,
|
|
EFI_MEMORY_TYPE_INFORMATION_VARIABLE_NAME,
|
|
&gEfiMemoryTypeInformationGuid,
|
|
NULL,
|
|
&DataSize,
|
|
&MemoryData
|
|
);
|
|
if (!EFI_ERROR (Status) && ValidateMemoryTypeInfoVariable (MemoryData, DataSize)) {
|
|
//
|
|
// Build the GUID'd HOB for DXE
|
|
//
|
|
BuildGuidDataHob (
|
|
&gEfiMemoryTypeInformationGuid,
|
|
MemoryData,
|
|
DataSize
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Look in all the FVs present in PEI and find the DXE Core FileHandle
|
|
//
|
|
FileHandle = DxeIplFindDxeCore ();
|
|
|
|
//
|
|
// Load the DXE Core from a Firmware Volume.
|
|
//
|
|
Instance = 0;
|
|
do {
|
|
Status = PeiServicesLocatePpi (&gEfiPeiLoadFilePpiGuid, Instance++, NULL, (VOID **)&LoadFile);
|
|
//
|
|
// These must exist an instance of EFI_PEI_LOAD_FILE_PPI to support to load DxeCore file handle successfully.
|
|
//
|
|
ASSERT_EFI_ERROR (Status);
|
|
|
|
Status = LoadFile->LoadFile (
|
|
LoadFile,
|
|
FileHandle,
|
|
&DxeCoreAddress,
|
|
&DxeCoreSize,
|
|
&DxeCoreEntryPoint,
|
|
&AuthenticationState
|
|
);
|
|
} while (EFI_ERROR (Status));
|
|
|
|
//
|
|
// Get the DxeCore File Info from the FileHandle for the DxeCore GUID file name.
|
|
//
|
|
Status = PeiServicesFfsGetFileInfo (FileHandle, &DxeCoreFileInfo);
|
|
ASSERT_EFI_ERROR (Status);
|
|
|
|
//
|
|
// Add HOB for the DXE Core
|
|
//
|
|
BuildModuleHob (
|
|
&DxeCoreFileInfo.FileName,
|
|
DxeCoreAddress,
|
|
ALIGN_VALUE (DxeCoreSize, EFI_PAGE_SIZE),
|
|
DxeCoreEntryPoint
|
|
);
|
|
|
|
//
|
|
// Report Status Code EFI_SW_PEI_PC_HANDOFF_TO_NEXT
|
|
//
|
|
REPORT_STATUS_CODE (EFI_PROGRESS_CODE, (EFI_SOFTWARE_PEI_CORE | EFI_SW_PEI_CORE_PC_HANDOFF_TO_NEXT));
|
|
|
|
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, HobList);
|
|
//
|
|
// 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;
|
|
}
|
|
|
|
/**
|
|
Searches DxeCore in all firmware Volumes and loads the first
|
|
instance that contains DxeCore.
|
|
|
|
@return FileHandle of DxeCore to load DxeCore.
|
|
|
|
**/
|
|
EFI_PEI_FILE_HANDLE
|
|
DxeIplFindDxeCore (
|
|
VOID
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINTN Instance;
|
|
EFI_PEI_FV_HANDLE VolumeHandle;
|
|
EFI_PEI_FILE_HANDLE FileHandle;
|
|
|
|
Instance = 0;
|
|
while (TRUE) {
|
|
//
|
|
// Traverse all firmware volume instances
|
|
//
|
|
Status = PeiServicesFfsFindNextVolume (Instance, &VolumeHandle);
|
|
//
|
|
// If some error occurs here, then we cannot find any firmware
|
|
// volume that may contain DxeCore.
|
|
//
|
|
if (EFI_ERROR (Status)) {
|
|
REPORT_STATUS_CODE (EFI_PROGRESS_CODE, (EFI_SOFTWARE_PEI_MODULE | EFI_SW_PEI_CORE_EC_DXE_CORRUPT));
|
|
}
|
|
|
|
ASSERT_EFI_ERROR (Status);
|
|
|
|
//
|
|
// Find the DxeCore file type from the beginning in this firmware volume.
|
|
//
|
|
FileHandle = NULL;
|
|
Status = PeiServicesFfsFindNextFile (EFI_FV_FILETYPE_DXE_CORE, VolumeHandle, &FileHandle);
|
|
if (!EFI_ERROR (Status)) {
|
|
//
|
|
// Find DxeCore FileHandle in this volume, then we skip other firmware volume and
|
|
// return the FileHandle.
|
|
//
|
|
return FileHandle;
|
|
}
|
|
|
|
//
|
|
// We cannot find DxeCore in this firmware volume, then search the next volume.
|
|
//
|
|
Instance++;
|
|
}
|
|
}
|
|
|
|
/**
|
|
The ExtractSection() function processes the input section and
|
|
returns a pointer to the section contents. If the section being
|
|
extracted does not require processing (if the section
|
|
GuidedSectionHeader.Attributes has the
|
|
EFI_GUIDED_SECTION_PROCESSING_REQUIRED field cleared), then
|
|
OutputBuffer is just updated to point to the start of the
|
|
section's contents. Otherwise, *Buffer must be allocated
|
|
from PEI permanent memory.
|
|
|
|
@param This Indicates the
|
|
EFI_PEI_GUIDED_SECTION_EXTRACTION_PPI instance.
|
|
Buffer containing the input GUIDed section to be
|
|
processed. OutputBuffer OutputBuffer is
|
|
allocated from PEI permanent memory and contains
|
|
the new section stream.
|
|
@param InputSection A pointer to the input buffer, which contains
|
|
the input section to be processed.
|
|
@param OutputBuffer A pointer to a caller-allocated buffer, whose
|
|
size is specified by the contents of OutputSize.
|
|
@param OutputSize A pointer to a caller-allocated
|
|
UINTN in which the size of *OutputBuffer
|
|
allocation is stored. If the function
|
|
returns anything other than EFI_SUCCESS,
|
|
the value of OutputSize is undefined.
|
|
@param AuthenticationStatus A pointer to a caller-allocated
|
|
UINT32 that indicates the
|
|
authentication status of the
|
|
output buffer. If the input
|
|
section's GuidedSectionHeader.
|
|
Attributes field has the
|
|
EFI_GUIDED_SECTION_AUTH_STATUS_VALID
|
|
bit as clear,
|
|
AuthenticationStatus must return
|
|
zero. These bits reflect the
|
|
status of the extraction
|
|
operation. If the function
|
|
returns anything other than
|
|
EFI_SUCCESS, the value of
|
|
AuthenticationStatus is
|
|
undefined.
|
|
|
|
@retval EFI_SUCCESS The InputSection was
|
|
successfully processed and the
|
|
section contents were returned.
|
|
|
|
@retval EFI_OUT_OF_RESOURCES The system has insufficient
|
|
resources to process the request.
|
|
|
|
@retval EFI_INVALID_PARAMETER The GUID in InputSection does
|
|
not match this instance of the
|
|
GUIDed Section Extraction PPI.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
CustomGuidedSectionExtract (
|
|
IN CONST EFI_PEI_GUIDED_SECTION_EXTRACTION_PPI *This,
|
|
IN CONST VOID *InputSection,
|
|
OUT VOID **OutputBuffer,
|
|
OUT UINTN *OutputSize,
|
|
OUT UINT32 *AuthenticationStatus
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINT8 *ScratchBuffer;
|
|
UINT32 ScratchBufferSize;
|
|
UINT32 OutputBufferSize;
|
|
UINT16 SectionAttribute;
|
|
|
|
//
|
|
// Init local variable
|
|
//
|
|
ScratchBuffer = NULL;
|
|
|
|
//
|
|
// Call GetInfo to get the size and attribute of input guided section data.
|
|
//
|
|
Status = ExtractGuidedSectionGetInfo (
|
|
InputSection,
|
|
&OutputBufferSize,
|
|
&ScratchBufferSize,
|
|
&SectionAttribute
|
|
);
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((DEBUG_ERROR, "GetInfo from guided section Failed - %r\n", Status));
|
|
return Status;
|
|
}
|
|
|
|
if (ScratchBufferSize != 0) {
|
|
//
|
|
// Allocate scratch buffer
|
|
//
|
|
ScratchBuffer = AllocatePages (EFI_SIZE_TO_PAGES (ScratchBufferSize));
|
|
if (ScratchBuffer == NULL) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
}
|
|
|
|
if (((SectionAttribute & EFI_GUIDED_SECTION_PROCESSING_REQUIRED) != 0) && (OutputBufferSize > 0)) {
|
|
//
|
|
// Allocate output buffer
|
|
//
|
|
*OutputBuffer = AllocatePages (EFI_SIZE_TO_PAGES (OutputBufferSize));
|
|
if (*OutputBuffer == NULL) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
DEBUG ((DEBUG_INFO, "Customized Guided section Memory Size required is 0x%x and address is 0x%p\n", OutputBufferSize, *OutputBuffer));
|
|
}
|
|
|
|
Status = ExtractGuidedSectionDecode (
|
|
InputSection,
|
|
OutputBuffer,
|
|
ScratchBuffer,
|
|
AuthenticationStatus
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
//
|
|
// Decode failed
|
|
//
|
|
DEBUG ((DEBUG_ERROR, "Extract guided section Failed - %r\n", Status));
|
|
return Status;
|
|
}
|
|
|
|
*OutputSize = (UINTN)OutputBufferSize;
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Decompresses a section to the output buffer.
|
|
|
|
This function looks up the compression type field in the input section and
|
|
applies the appropriate compression algorithm to compress the section to a
|
|
callee allocated buffer.
|
|
|
|
@param This Points to this instance of the
|
|
EFI_PEI_DECOMPRESS_PEI PPI.
|
|
@param CompressionSection Points to the compressed section.
|
|
@param OutputBuffer Holds the returned pointer to the decompressed
|
|
sections.
|
|
@param OutputSize Holds the returned size of the decompress
|
|
section streams.
|
|
|
|
@retval EFI_SUCCESS The section was decompressed successfully.
|
|
OutputBuffer contains the resulting data and
|
|
OutputSize contains the resulting size.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
Decompress (
|
|
IN CONST EFI_PEI_DECOMPRESS_PPI *This,
|
|
IN CONST EFI_COMPRESSION_SECTION *CompressionSection,
|
|
OUT VOID **OutputBuffer,
|
|
OUT UINTN *OutputSize
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINT8 *DstBuffer;
|
|
UINT8 *ScratchBuffer;
|
|
UINT32 DstBufferSize;
|
|
UINT32 ScratchBufferSize;
|
|
VOID *CompressionSource;
|
|
UINT32 CompressionSourceSize;
|
|
UINT32 UncompressedLength;
|
|
UINT8 CompressionType;
|
|
|
|
if (CompressionSection->CommonHeader.Type != EFI_SECTION_COMPRESSION) {
|
|
ASSERT (FALSE);
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
if (IS_SECTION2 (CompressionSection)) {
|
|
CompressionSource = (VOID *)((UINT8 *)CompressionSection + sizeof (EFI_COMPRESSION_SECTION2));
|
|
CompressionSourceSize = (UINT32)(SECTION2_SIZE (CompressionSection) - sizeof (EFI_COMPRESSION_SECTION2));
|
|
UncompressedLength = ((EFI_COMPRESSION_SECTION2 *)CompressionSection)->UncompressedLength;
|
|
CompressionType = ((EFI_COMPRESSION_SECTION2 *)CompressionSection)->CompressionType;
|
|
} else {
|
|
CompressionSource = (VOID *)((UINT8 *)CompressionSection + sizeof (EFI_COMPRESSION_SECTION));
|
|
CompressionSourceSize = (UINT32)(SECTION_SIZE (CompressionSection) - sizeof (EFI_COMPRESSION_SECTION));
|
|
UncompressedLength = CompressionSection->UncompressedLength;
|
|
CompressionType = CompressionSection->CompressionType;
|
|
}
|
|
|
|
//
|
|
// This is a compression set, expand it
|
|
//
|
|
switch (CompressionType) {
|
|
case EFI_STANDARD_COMPRESSION:
|
|
if (FeaturePcdGet (PcdDxeIplSupportUefiDecompress)) {
|
|
//
|
|
// Load EFI standard compression.
|
|
// For compressed data, decompress them to destination buffer.
|
|
//
|
|
Status = UefiDecompressGetInfo (
|
|
CompressionSource,
|
|
CompressionSourceSize,
|
|
&DstBufferSize,
|
|
&ScratchBufferSize
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
//
|
|
// GetInfo failed
|
|
//
|
|
DEBUG ((DEBUG_ERROR, "Decompress GetInfo Failed - %r\n", Status));
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
//
|
|
// Allocate scratch buffer
|
|
//
|
|
ScratchBuffer = AllocatePages (EFI_SIZE_TO_PAGES (ScratchBufferSize));
|
|
if (ScratchBuffer == NULL) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
//
|
|
// Allocate destination buffer
|
|
//
|
|
DstBuffer = AllocatePages (EFI_SIZE_TO_PAGES (DstBufferSize));
|
|
if (DstBuffer == NULL) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
//
|
|
// Call decompress function
|
|
//
|
|
Status = UefiDecompress (
|
|
CompressionSource,
|
|
DstBuffer,
|
|
ScratchBuffer
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
//
|
|
// Decompress failed
|
|
//
|
|
DEBUG ((DEBUG_ERROR, "Decompress Failed - %r\n", Status));
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
break;
|
|
} else {
|
|
//
|
|
// PcdDxeIplSupportUefiDecompress is FALSE
|
|
// Don't support UEFI decompression algorithm.
|
|
//
|
|
ASSERT (FALSE);
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
case EFI_NOT_COMPRESSED:
|
|
//
|
|
// Allocate destination buffer
|
|
//
|
|
DstBufferSize = UncompressedLength;
|
|
DstBuffer = AllocatePages (EFI_SIZE_TO_PAGES (DstBufferSize));
|
|
if (DstBuffer == NULL) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
//
|
|
// stream is not actually compressed, just encapsulated. So just copy it.
|
|
//
|
|
CopyMem (DstBuffer, CompressionSource, DstBufferSize);
|
|
break;
|
|
|
|
default:
|
|
//
|
|
// Don't support other unknown compression type.
|
|
//
|
|
ASSERT (FALSE);
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
*OutputSize = DstBufferSize;
|
|
*OutputBuffer = DstBuffer;
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Updates the Stack HOB passed to DXE phase.
|
|
|
|
This function traverses the whole HOB list and update the stack HOB to
|
|
reflect the real stack that is used by DXE core.
|
|
|
|
@param BaseAddress The lower address of stack used by DxeCore.
|
|
@param Length The length of stack used by DxeCore.
|
|
|
|
**/
|
|
VOID
|
|
UpdateStackHob (
|
|
IN EFI_PHYSICAL_ADDRESS BaseAddress,
|
|
IN UINT64 Length
|
|
)
|
|
{
|
|
EFI_PEI_HOB_POINTERS Hob;
|
|
|
|
Hob.Raw = GetHobList ();
|
|
while ((Hob.Raw = GetNextHob (EFI_HOB_TYPE_MEMORY_ALLOCATION, Hob.Raw)) != NULL) {
|
|
if (CompareGuid (&gEfiHobMemoryAllocStackGuid, &(Hob.MemoryAllocationStack->AllocDescriptor.Name))) {
|
|
//
|
|
// Build a new memory allocation HOB with old stack info with EfiBootServicesData type. Need to
|
|
// avoid this region be reclaimed by DXE core as the IDT built in SEC might be on stack, and some
|
|
// PEIMs may also keep key information on stack
|
|
//
|
|
BuildMemoryAllocationHob (
|
|
Hob.MemoryAllocationStack->AllocDescriptor.MemoryBaseAddress,
|
|
Hob.MemoryAllocationStack->AllocDescriptor.MemoryLength,
|
|
EfiBootServicesData
|
|
);
|
|
//
|
|
// Update the BSP Stack Hob to reflect the new stack info.
|
|
//
|
|
Hob.MemoryAllocationStack->AllocDescriptor.MemoryBaseAddress = BaseAddress;
|
|
Hob.MemoryAllocationStack->AllocDescriptor.MemoryLength = Length;
|
|
break;
|
|
}
|
|
|
|
Hob.Raw = GET_NEXT_HOB (Hob);
|
|
}
|
|
}
|