/** @file Firmware volume helper interfaces. Copyright (c) 2015, Intel Corporation. All rights reserved.
Copyright (c) 2016 - 2021, Arm Limited. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent **/ #include "StandaloneMmCore.h" #include #include // // 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 UINT32 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; UINT32 Pe32DataSize; VOID *Depex; UINT32 DepexSize; UINTN Index; EFI_COMMON_SECTION_HEADER *Section; VOID *SectionData; UINT32 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; }