mirror of https://github.com/acidanthera/audk.git
338 lines
9.4 KiB
C
338 lines
9.4 KiB
C
/** @file
|
|
Firmware volume helper interfaces.
|
|
|
|
Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
|
|
Copyright (c) 2016 - 2021, Arm Limited. All rights reserved.<BR>
|
|
SPDX-License-Identifier: BSD-2-Clause-Patent
|
|
|
|
**/
|
|
|
|
#include "StandaloneMmCore.h"
|
|
#include <Library/FvLib.h>
|
|
#include <Library/ExtractGuidedSectionLib.h>
|
|
|
|
#define MAX_MM_FV_COUNT 2
|
|
|
|
EFI_FIRMWARE_VOLUME_HEADER *mMmFv[MAX_MM_FV_COUNT];
|
|
|
|
EFI_STATUS
|
|
MmAddToDriverList (
|
|
IN EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader,
|
|
IN VOID *Pe32Data,
|
|
IN UINTN Pe32DataSize,
|
|
IN VOID *Depex,
|
|
IN UINTN DepexSize,
|
|
IN EFI_GUID *DriverName
|
|
);
|
|
|
|
BOOLEAN
|
|
FvHasBeenProcessed (
|
|
IN EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader
|
|
);
|
|
|
|
VOID
|
|
FvIsBeingProcessed (
|
|
IN EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader
|
|
);
|
|
|
|
/**
|
|
Given the pointer to the Firmware Volume Header find the
|
|
MM driver and return its PE32 image.
|
|
|
|
@param [in] FwVolHeader Pointer to memory mapped FV
|
|
@param [in] Depth Nesting depth of encapsulation sections. Callers
|
|
different from MmCoreFfsFindMmDriver() are
|
|
responsible for passing in a zero Depth.
|
|
|
|
@retval EFI_SUCCESS Success.
|
|
@retval EFI_INVALID_PARAMETER Invalid parameter.
|
|
@retval EFI_NOT_FOUND Could not find section data.
|
|
@retval EFI_OUT_OF_RESOURCES Out of resources.
|
|
@retval EFI_VOLUME_CORRUPTED Firmware volume is corrupted.
|
|
@retval EFI_UNSUPPORTED Operation not supported.
|
|
@retval EFI_ABORTED Recursion aborted because Depth has been
|
|
greater than or equal to
|
|
PcdFwVolMmMaxEncapsulationDepth.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
MmCoreFfsFindMmDriver (
|
|
IN EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader,
|
|
IN UINT32 Depth
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_STATUS DepexStatus;
|
|
EFI_FFS_FILE_HEADER *FileHeader;
|
|
VOID *Pe32Data;
|
|
UINTN Pe32DataSize;
|
|
VOID *Depex;
|
|
UINTN DepexSize;
|
|
EFI_COMMON_SECTION_HEADER *Section;
|
|
VOID *SectionData;
|
|
UINTN SectionDataSize;
|
|
UINT32 DstBufferSize;
|
|
VOID *ScratchBuffer;
|
|
UINT32 ScratchBufferSize;
|
|
VOID *AllocatedDstBuffer;
|
|
VOID *DstBuffer;
|
|
UINT16 SectionAttribute;
|
|
UINT32 AuthenticationStatus;
|
|
EFI_FIRMWARE_VOLUME_HEADER *InnerFvHeader;
|
|
|
|
DEBUG ((DEBUG_INFO, "MmCoreFfsFindMmDriver - 0x%x\n", FwVolHeader));
|
|
|
|
if (Depth >= PcdGet32 (PcdFwVolMmMaxEncapsulationDepth)) {
|
|
DEBUG ((DEBUG_ERROR, "%a: recursion aborted due to nesting depth\n", __func__));
|
|
return EFI_ABORTED;
|
|
}
|
|
|
|
if (FvHasBeenProcessed (FwVolHeader)) {
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
FvIsBeingProcessed (FwVolHeader);
|
|
|
|
//
|
|
// First check for encapsulated compressed firmware volumes
|
|
//
|
|
FileHeader = NULL;
|
|
do {
|
|
Status = FfsFindNextFile (
|
|
EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE,
|
|
FwVolHeader,
|
|
&FileHeader
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Check uncompressed firmware volumes
|
|
//
|
|
Status = FfsFindSectionData (
|
|
EFI_SECTION_FIRMWARE_VOLUME_IMAGE,
|
|
FileHeader,
|
|
&SectionData,
|
|
&SectionDataSize
|
|
);
|
|
if (!EFI_ERROR (Status)) {
|
|
if (SectionDataSize > sizeof (EFI_FIRMWARE_VOLUME_HEADER)) {
|
|
InnerFvHeader = (EFI_FIRMWARE_VOLUME_HEADER *)SectionData;
|
|
MmCoreFfsFindMmDriver (InnerFvHeader, Depth + 1);
|
|
continue;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Check compressed firmware volumes
|
|
//
|
|
Status = FfsFindSection (
|
|
EFI_SECTION_GUID_DEFINED,
|
|
FileHeader,
|
|
&Section
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
break;
|
|
}
|
|
|
|
Status = ExtractGuidedSectionGetInfo (
|
|
Section,
|
|
&DstBufferSize,
|
|
&ScratchBufferSize,
|
|
&SectionAttribute
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Allocate scratch buffer
|
|
//
|
|
ScratchBuffer = (VOID *)(UINTN)AllocatePages (EFI_SIZE_TO_PAGES (ScratchBufferSize));
|
|
if (ScratchBuffer == NULL) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
//
|
|
// Allocate destination buffer, extra one page for adjustment
|
|
//
|
|
AllocatedDstBuffer = (VOID *)(UINTN)AllocatePages (EFI_SIZE_TO_PAGES (DstBufferSize));
|
|
if (AllocatedDstBuffer == NULL) {
|
|
FreePages (ScratchBuffer, EFI_SIZE_TO_PAGES (ScratchBufferSize));
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
//
|
|
// Call decompress function
|
|
//
|
|
DstBuffer = AllocatedDstBuffer;
|
|
Status = ExtractGuidedSectionDecode (
|
|
Section,
|
|
&DstBuffer,
|
|
ScratchBuffer,
|
|
&AuthenticationStatus
|
|
);
|
|
FreePages (ScratchBuffer, EFI_SIZE_TO_PAGES (ScratchBufferSize));
|
|
if (EFI_ERROR (Status)) {
|
|
goto FreeDstBuffer;
|
|
}
|
|
|
|
//
|
|
// Free allocated DstBuffer if it is not used
|
|
//
|
|
if (DstBuffer != AllocatedDstBuffer) {
|
|
FreePages (AllocatedDstBuffer, EFI_SIZE_TO_PAGES (DstBufferSize));
|
|
AllocatedDstBuffer = NULL;
|
|
}
|
|
|
|
DEBUG ((
|
|
DEBUG_INFO,
|
|
"Processing compressed firmware volume (AuthenticationStatus == %x)\n",
|
|
AuthenticationStatus
|
|
));
|
|
|
|
Status = FindFfsSectionInSections (
|
|
DstBuffer,
|
|
DstBufferSize,
|
|
EFI_SECTION_FIRMWARE_VOLUME_IMAGE,
|
|
&Section
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
goto FreeDstBuffer;
|
|
}
|
|
|
|
if (IS_SECTION2 (Section)) {
|
|
InnerFvHeader = (VOID *)((EFI_COMMON_SECTION_HEADER2 *)Section + 1);
|
|
} else {
|
|
InnerFvHeader = (VOID *)(Section + 1);
|
|
}
|
|
|
|
Status = MmCoreFfsFindMmDriver (InnerFvHeader, Depth + 1);
|
|
if (EFI_ERROR (Status)) {
|
|
goto FreeDstBuffer;
|
|
}
|
|
} while (TRUE);
|
|
|
|
DEBUG ((DEBUG_INFO, "Check MmFileTypes - 0x%x\n", EFI_FV_FILETYPE_MM_STANDALONE));
|
|
FileHeader = NULL;
|
|
do {
|
|
Status = FfsFindNextFile (EFI_FV_FILETYPE_MM_STANDALONE, FwVolHeader, &FileHeader);
|
|
if (!EFI_ERROR (Status)) {
|
|
Status = FfsFindSectionData (EFI_SECTION_PE32, FileHeader, &Pe32Data, &Pe32DataSize);
|
|
DEBUG ((DEBUG_INFO, "Find PE data - 0x%x\n", Pe32Data));
|
|
DepexStatus = FfsFindSectionData (EFI_SECTION_MM_DEPEX, FileHeader, &Depex, &DepexSize);
|
|
if (!EFI_ERROR (DepexStatus)) {
|
|
MmAddToDriverList (FwVolHeader, Pe32Data, Pe32DataSize, Depex, DepexSize, &FileHeader->Name);
|
|
}
|
|
}
|
|
} while (!EFI_ERROR (Status));
|
|
|
|
return EFI_SUCCESS;
|
|
|
|
FreeDstBuffer:
|
|
if (AllocatedDstBuffer != NULL) {
|
|
FreePages (AllocatedDstBuffer, EFI_SIZE_TO_PAGES (DstBufferSize));
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
Dispatch Standalone MM FVs.
|
|
The FVs will be shadowed into MMRAM, caller is responsible for calling
|
|
MmFreeShadowedFvs() to free the shadowed MM FVs.
|
|
|
|
**/
|
|
VOID
|
|
MmDispatchFvs (
|
|
VOID
|
|
)
|
|
{
|
|
UINTN Index;
|
|
EFI_PEI_HOB_POINTERS FvHob;
|
|
EFI_FIRMWARE_VOLUME_HEADER *Fv;
|
|
|
|
ZeroMem (mMmFv, sizeof (mMmFv));
|
|
|
|
Index = 0;
|
|
FvHob.Raw = GetHobList ();
|
|
while ((FvHob.Raw = GetNextHob (EFI_HOB_TYPE_FV, FvHob.Raw)) != NULL) {
|
|
if (Index == ARRAY_SIZE (mMmFv)) {
|
|
DEBUG ((
|
|
DEBUG_INFO,
|
|
"%a: The number of FV Hobs exceed the max supported FVs (%d) in StandaloneMmCore\n",
|
|
__func__,
|
|
ARRAY_SIZE (mMmFv)
|
|
));
|
|
return;
|
|
}
|
|
|
|
DEBUG ((DEBUG_INFO, "%a: FV[%d] address - 0x%x\n", __func__, Index, FvHob.FirmwareVolume->BaseAddress));
|
|
DEBUG ((DEBUG_INFO, "%a: FV[%d] size - 0x%x\n", __func__, Index, FvHob.FirmwareVolume->Length));
|
|
|
|
if (FvHob.FirmwareVolume->Length == 0x00) {
|
|
DEBUG ((
|
|
DEBUG_INFO,
|
|
"%a: Skip invalid FV[%d]- 0x%x/0x%x\n",
|
|
__func__,
|
|
Index,
|
|
FvHob.FirmwareVolume->BaseAddress,
|
|
FvHob.FirmwareVolume->Length
|
|
));
|
|
continue;
|
|
}
|
|
|
|
if (!FixedPcdGetBool (PcdShadowBfv)) {
|
|
Fv = (EFI_FIRMWARE_VOLUME_HEADER *)((UINTN)FvHob.FirmwareVolume->BaseAddress);
|
|
} else {
|
|
Fv = AllocatePool (FvHob.FirmwareVolume->Length);
|
|
if (Fv == NULL) {
|
|
DEBUG ((DEBUG_ERROR, "Fail to allocate memory for Fv\n"));
|
|
CpuDeadLoop ();
|
|
return;
|
|
}
|
|
|
|
CopyMem (
|
|
(VOID *)Fv,
|
|
(VOID *)(UINTN)FvHob.FirmwareVolume->BaseAddress,
|
|
FvHob.FirmwareVolume->Length
|
|
);
|
|
}
|
|
|
|
MmCoreFfsFindMmDriver (Fv, 0);
|
|
mMmFv[Index++] = Fv;
|
|
|
|
FvHob.Raw = GET_NEXT_HOB (FvHob);
|
|
}
|
|
|
|
if (Index == 0) {
|
|
DEBUG ((DEBUG_ERROR, "No FV hob is found\n"));
|
|
return;
|
|
}
|
|
|
|
MmDispatcher ();
|
|
}
|
|
|
|
/**
|
|
Free the shadowed MM FVs.
|
|
|
|
**/
|
|
VOID
|
|
MmFreeShadowedFvs (
|
|
VOID
|
|
)
|
|
{
|
|
UINTN Index;
|
|
|
|
if (!FixedPcdGetBool (PcdShadowBfv)) {
|
|
return;
|
|
}
|
|
|
|
for (Index = 0; Index < ARRAY_SIZE (mMmFv); Index++) {
|
|
if (mMmFv[Index] != NULL) {
|
|
FreePool (mMmFv[Index]);
|
|
}
|
|
}
|
|
}
|