/** @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> | |
// | |
// List of file types supported by dispatcher | |
// | |
EFI_FV_FILETYPE mMmFileTypes[] = { | |
EFI_FV_FILETYPE_MM, | |
0xE, // EFI_FV_FILETYPE_MM_STANDALONE, | |
// | |
// Note: DXE core will process the FV image file, so skip it in MM core | |
// EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE | |
// | |
}; | |
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; | |
EFI_FV_FILETYPE FileType; | |
VOID *Pe32Data; | |
UINTN Pe32DataSize; | |
VOID *Depex; | |
UINTN DepexSize; | |
UINTN Index; | |
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); | |
for (Index = 0; Index < sizeof (mMmFileTypes) / sizeof (mMmFileTypes[0]); Index++) { | |
DEBUG ((DEBUG_INFO, "Check MmFileTypes - 0x%x\n", mMmFileTypes[Index])); | |
FileType = mMmFileTypes[Index]; | |
FileHeader = NULL; | |
do { | |
Status = FfsFindNextFile (FileType, 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; | |
} |