| /** @file |
| Implementation of the 6 PEI Ffs (FV) APIs in library form. |
| |
| This code only knows about a FV if it has a EFI_HOB_TYPE_FV entry in the HOB list |
| |
| Copyright (c) 2008-2009, Apple Inc. All rights reserved. |
| |
| All rights reserved. This program and the accompanying materials |
| are licensed and made available under the terms and conditions of the BSD License |
| which accompanies this distribution. The full text of the license may be found at |
| http://opensource.org/licenses/bsd-license.php |
| |
| THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, |
| WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. |
| |
| **/ |
| |
| #include <PrePi.h> |
| #include <Library/ExtractGuidedSectionLib.h> |
| |
| |
| #define GET_OCCUPIED_SIZE(ActualSize, Alignment) \ |
| (ActualSize) + (((Alignment) - ((ActualSize) & ((Alignment) - 1))) & ((Alignment) - 1)) |
| |
| |
| /** |
| Returns the highest bit set of the State field |
| |
| @param ErasePolarity Erase Polarity as defined by EFI_FVB2_ERASE_POLARITY |
| in the Attributes field. |
| @param FfsHeader Pointer to FFS File Header |
| |
| |
| @retval the highest bit in the State field |
| |
| **/ |
| STATIC |
| EFI_FFS_FILE_STATE |
| GetFileState( |
| IN UINT8 ErasePolarity, |
| IN EFI_FFS_FILE_HEADER *FfsHeader |
| ) |
| { |
| EFI_FFS_FILE_STATE FileState; |
| EFI_FFS_FILE_STATE HighestBit; |
| |
| FileState = FfsHeader->State; |
| |
| if (ErasePolarity != 0) { |
| FileState = (EFI_FFS_FILE_STATE)~FileState; |
| } |
| |
| HighestBit = 0x80; |
| while (HighestBit != 0 && (HighestBit & FileState) == 0) { |
| HighestBit >>= 1; |
| } |
| |
| return HighestBit; |
| } |
| |
| |
| /** |
| Calculates the checksum of the header of a file. |
| The header is a zero byte checksum, so zero means header is good |
| |
| @param FfsHeader Pointer to FFS File Header |
| |
| @retval Checksum of the header |
| |
| **/ |
| STATIC |
| UINT8 |
| CalculateHeaderChecksum ( |
| IN EFI_FFS_FILE_HEADER *FileHeader |
| ) |
| { |
| UINT8 *Ptr; |
| UINTN Index; |
| UINT8 Sum; |
| |
| Sum = 0; |
| Ptr = (UINT8 *)FileHeader; |
| |
| for (Index = 0; Index < sizeof(EFI_FFS_FILE_HEADER) - 3; Index += 4) { |
| Sum = (UINT8)(Sum + Ptr[Index]); |
| Sum = (UINT8)(Sum + Ptr[Index+1]); |
| Sum = (UINT8)(Sum + Ptr[Index+2]); |
| Sum = (UINT8)(Sum + Ptr[Index+3]); |
| } |
| |
| for (; Index < sizeof(EFI_FFS_FILE_HEADER); Index++) { |
| Sum = (UINT8)(Sum + Ptr[Index]); |
| } |
| |
| // |
| // State field (since this indicates the different state of file). |
| // |
| Sum = (UINT8)(Sum - FileHeader->State); |
| // |
| // Checksum field of the file is not part of the header checksum. |
| // |
| Sum = (UINT8)(Sum - FileHeader->IntegrityCheck.Checksum.File); |
| |
| return Sum; |
| } |
| |
| |
| /** |
| Given a FileHandle return the VolumeHandle |
| |
| @param FileHandle File handle to look up |
| @param VolumeHandle Match for FileHandle |
| |
| @retval TRUE VolumeHandle is valid |
| |
| **/ |
| STATIC |
| BOOLEAN |
| EFIAPI |
| FileHandleToVolume ( |
| IN EFI_PEI_FILE_HANDLE FileHandle, |
| OUT EFI_PEI_FV_HANDLE *VolumeHandle |
| ) |
| { |
| EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader; |
| EFI_PEI_HOB_POINTERS Hob; |
| |
| Hob.Raw = GetHobList (); |
| if (Hob.Raw == NULL) { |
| return FALSE; |
| } |
| |
| do { |
| Hob.Raw = GetNextHob (EFI_HOB_TYPE_FV, Hob.Raw); |
| if (Hob.Raw != NULL) { |
| FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)(Hob.FirmwareVolume->BaseAddress); |
| if (((UINT64) (UINTN) FileHandle > (UINT64) (UINTN) FwVolHeader ) && \ |
| ((UINT64) (UINTN) FileHandle <= ((UINT64) (UINTN) FwVolHeader + FwVolHeader->FvLength - 1))) { |
| *VolumeHandle = (EFI_PEI_FV_HANDLE)FwVolHeader; |
| return TRUE; |
| } |
| |
| Hob.Raw = GetNextHob (EFI_HOB_TYPE_FV, GET_NEXT_HOB (Hob)); |
| } |
| } while (Hob.Raw != NULL); |
| |
| return FALSE; |
| } |
| |
| |
| |
| /** |
| Given the input file pointer, search for the next matching file in the |
| FFS volume as defined by SearchType. The search starts from FileHeader inside |
| the Firmware Volume defined by FwVolHeader. |
| |
| @param FileHandle File handle to look up |
| @param VolumeHandle Match for FileHandle |
| |
| |
| **/ |
| EFI_STATUS |
| FindFileEx ( |
| IN CONST EFI_PEI_FV_HANDLE FvHandle, |
| IN CONST EFI_GUID *FileName, OPTIONAL |
| IN EFI_FV_FILETYPE SearchType, |
| IN OUT EFI_PEI_FILE_HANDLE *FileHandle |
| ) |
| { |
| EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader; |
| EFI_FFS_FILE_HEADER **FileHeader; |
| EFI_FFS_FILE_HEADER *FfsFileHeader; |
| EFI_FIRMWARE_VOLUME_EXT_HEADER *FwVolExHeaderInfo; |
| UINT32 FileLength; |
| UINT32 FileOccupiedSize; |
| UINT32 FileOffset; |
| UINT64 FvLength; |
| UINT8 ErasePolarity; |
| UINT8 FileState; |
| |
| FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *)FvHandle; |
| FileHeader = (EFI_FFS_FILE_HEADER **)FileHandle; |
| |
| FvLength = FwVolHeader->FvLength; |
| if (FwVolHeader->Attributes & EFI_FVB2_ERASE_POLARITY) { |
| ErasePolarity = 1; |
| } else { |
| ErasePolarity = 0; |
| } |
| |
| // |
| // If FileHeader is not specified (NULL) or FileName is not NULL, |
| // start with the first file in the firmware volume. Otherwise, |
| // start from the FileHeader. |
| // |
| if ((*FileHeader == NULL) || (FileName != NULL)) { |
| FfsFileHeader = (EFI_FFS_FILE_HEADER *)((UINT8 *)FwVolHeader + FwVolHeader->HeaderLength); |
| if (FwVolHeader->ExtHeaderOffset != 0) { |
| FwVolExHeaderInfo = (EFI_FIRMWARE_VOLUME_EXT_HEADER *)(((UINT8 *)FwVolHeader) + FwVolHeader->ExtHeaderOffset); |
| FfsFileHeader = (EFI_FFS_FILE_HEADER *)(((UINT8 *)FwVolExHeaderInfo) + FwVolExHeaderInfo->ExtHeaderSize); |
| } |
| } else { |
| // |
| // Length is 24 bits wide so mask upper 8 bits |
| // FileLength is adjusted to FileOccupiedSize as it is 8 byte aligned. |
| // |
| FileLength = *(UINT32 *)(*FileHeader)->Size & 0x00FFFFFF; |
| FileOccupiedSize = GET_OCCUPIED_SIZE (FileLength, 8); |
| FfsFileHeader = (EFI_FFS_FILE_HEADER *)((UINT8 *)*FileHeader + FileOccupiedSize); |
| } |
| |
| FileOffset = (UINT32) ((UINT8 *)FfsFileHeader - (UINT8 *)FwVolHeader); |
| ASSERT (FileOffset <= 0xFFFFFFFF); |
| |
| while (FileOffset < (FvLength - sizeof (EFI_FFS_FILE_HEADER))) { |
| // |
| // Get FileState which is the highest bit of the State |
| // |
| FileState = GetFileState (ErasePolarity, FfsFileHeader); |
| |
| switch (FileState) { |
| |
| case EFI_FILE_HEADER_INVALID: |
| FileOffset += sizeof(EFI_FFS_FILE_HEADER); |
| FfsFileHeader = (EFI_FFS_FILE_HEADER *)((UINT8 *)FfsFileHeader + sizeof(EFI_FFS_FILE_HEADER)); |
| break; |
| |
| case EFI_FILE_DATA_VALID: |
| case EFI_FILE_MARKED_FOR_UPDATE: |
| if (CalculateHeaderChecksum (FfsFileHeader) != 0) { |
| ASSERT (FALSE); |
| *FileHeader = NULL; |
| return EFI_NOT_FOUND; |
| } |
| |
| FileLength = *(UINT32 *)(FfsFileHeader->Size) & 0x00FFFFFF; |
| FileOccupiedSize = GET_OCCUPIED_SIZE(FileLength, 8); |
| |
| if (FileName != NULL) { |
| if (CompareGuid (&FfsFileHeader->Name, (EFI_GUID*)FileName)) { |
| *FileHeader = FfsFileHeader; |
| return EFI_SUCCESS; |
| } |
| } else if (((SearchType == FfsFileHeader->Type) || (SearchType == EFI_FV_FILETYPE_ALL)) && |
| (FfsFileHeader->Type != EFI_FV_FILETYPE_FFS_PAD)) { |
| *FileHeader = FfsFileHeader; |
| return EFI_SUCCESS; |
| } |
| |
| FileOffset += FileOccupiedSize; |
| FfsFileHeader = (EFI_FFS_FILE_HEADER *)((UINT8 *)FfsFileHeader + FileOccupiedSize); |
| break; |
| |
| case EFI_FILE_DELETED: |
| FileLength = *(UINT32 *)(FfsFileHeader->Size) & 0x00FFFFFF; |
| FileOccupiedSize = GET_OCCUPIED_SIZE(FileLength, 8); |
| FileOffset += FileOccupiedSize; |
| FfsFileHeader = (EFI_FFS_FILE_HEADER *)((UINT8 *)FfsFileHeader + FileOccupiedSize); |
| break; |
| |
| default: |
| *FileHeader = NULL; |
| return EFI_NOT_FOUND; |
| } |
| } |
| |
| |
| *FileHeader = NULL; |
| return EFI_NOT_FOUND; |
| } |
| |
| |
| /** |
| Go through the file to search SectionType section, |
| when meeting an encapsuled section. |
| |
| @param SectionType - Filter to find only section of this type. |
| @param Section - From where to search. |
| @param SectionSize - The file size to search. |
| @param OutputBuffer - Pointer to the section to search. |
| |
| @retval EFI_SUCCESS |
| **/ |
| EFI_STATUS |
| FfsProcessSection ( |
| IN EFI_SECTION_TYPE SectionType, |
| IN EFI_COMMON_SECTION_HEADER *Section, |
| IN UINTN SectionSize, |
| OUT VOID **OutputBuffer |
| ) |
| { |
| EFI_STATUS Status; |
| UINT32 SectionLength; |
| UINT32 ParsedLength; |
| EFI_COMPRESSION_SECTION *CompressionSection; |
| UINTN DstBufferSize; |
| VOID *ScratchBuffer; |
| UINT32 ScratchBufferSize; |
| VOID *DstBuffer; |
| UINT16 SectionAttribute; |
| UINT32 AuthenticationStatus; |
| |
| |
| *OutputBuffer = NULL; |
| ParsedLength = 0; |
| Status = EFI_NOT_FOUND; |
| while (ParsedLength < SectionSize) { |
| if (Section->Type == SectionType) { |
| *OutputBuffer = (VOID *)(Section + 1); |
| |
| return EFI_SUCCESS; |
| } else if ((Section->Type == EFI_SECTION_COMPRESSION) || (Section->Type == EFI_SECTION_GUID_DEFINED)) { |
| |
| if (Section->Type == EFI_SECTION_COMPRESSION) { |
| CompressionSection = (EFI_COMPRESSION_SECTION *) Section; |
| SectionLength = *(UINT32 *)Section->Size & 0x00FFFFFF; |
| |
| if (CompressionSection->CompressionType != EFI_STANDARD_COMPRESSION) { |
| return EFI_UNSUPPORTED; |
| } |
| |
| Status = UefiDecompressGetInfo ( |
| (UINT8 *) ((EFI_COMPRESSION_SECTION *) Section + 1), |
| (UINT32) SectionLength - sizeof (EFI_COMPRESSION_SECTION), |
| (UINT32 *) &DstBufferSize, |
| &ScratchBufferSize |
| ); |
| } else if (Section->Type == EFI_SECTION_GUID_DEFINED) { |
| Status = ExtractGuidedSectionGetInfo ( |
| Section, |
| (UINT32 *) &DstBufferSize, |
| &ScratchBufferSize, |
| &SectionAttribute |
| ); |
| } |
| |
| if (EFI_ERROR (Status)) { |
| // |
| // GetInfo failed |
| // |
| DEBUG ((EFI_D_ERROR, "Decompress GetInfo Failed - %r\n", Status)); |
| return EFI_NOT_FOUND; |
| } |
| // |
| // 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 |
| // |
| DstBuffer = (VOID *)(UINTN)AllocatePages (EFI_SIZE_TO_PAGES (DstBufferSize) + 1); |
| if (DstBuffer == NULL) { |
| return EFI_OUT_OF_RESOURCES; |
| } |
| // |
| // DstBuffer still is one section. Adjust DstBuffer offset, skip EFI section header |
| // to make section data at page alignment. |
| // |
| DstBuffer = (UINT8 *)DstBuffer + EFI_PAGE_SIZE - sizeof (EFI_COMMON_SECTION_HEADER); |
| // |
| // Call decompress function |
| // |
| if (Section->Type == EFI_SECTION_COMPRESSION) { |
| Status = UefiDecompress ( |
| (CHAR8 *) ((EFI_COMPRESSION_SECTION *) Section + 1), |
| DstBuffer, |
| ScratchBuffer |
| ); |
| } else if (Section->Type == EFI_SECTION_GUID_DEFINED) { |
| Status = ExtractGuidedSectionDecode ( |
| Section, |
| &DstBuffer, |
| ScratchBuffer, |
| &AuthenticationStatus |
| ); |
| } |
| |
| if (EFI_ERROR (Status)) { |
| // |
| // Decompress failed |
| // |
| DEBUG ((EFI_D_ERROR, "Decompress Failed - %r\n", Status)); |
| return EFI_NOT_FOUND; |
| } else { |
| return FfsProcessSection ( |
| SectionType, |
| DstBuffer, |
| DstBufferSize, |
| OutputBuffer |
| ); |
| } |
| } |
| |
| // |
| // Size is 24 bits wide so mask upper 8 bits. |
| // SectionLength is adjusted it is 4 byte aligned. |
| // Go to the next section |
| // |
| SectionLength = *(UINT32 *)Section->Size & 0x00FFFFFF; |
| SectionLength = GET_OCCUPIED_SIZE (SectionLength, 4); |
| ASSERT (SectionLength != 0); |
| ParsedLength += SectionLength; |
| Section = (EFI_COMMON_SECTION_HEADER *)((UINT8 *)Section + SectionLength); |
| } |
| |
| return EFI_NOT_FOUND; |
| } |
| |
| |
| |
| /** |
| This service enables discovery sections of a given type within a valid FFS file. |
| |
| @param SearchType The value of the section type to find. |
| @param FfsFileHeader A pointer to the file header that contains the set of sections to |
| be searched. |
| @param SectionData A pointer to the discovered section, if successful. |
| |
| @retval EFI_SUCCESS The section was found. |
| @retval EFI_NOT_FOUND The section was not found. |
| |
| **/ |
| EFI_STATUS |
| EFIAPI |
| FfsFindSectionData ( |
| IN EFI_SECTION_TYPE SectionType, |
| IN EFI_PEI_FILE_HANDLE FileHandle, |
| OUT VOID **SectionData |
| ) |
| { |
| EFI_FFS_FILE_HEADER *FfsFileHeader; |
| UINT32 FileSize; |
| EFI_COMMON_SECTION_HEADER *Section; |
| |
| FfsFileHeader = (EFI_FFS_FILE_HEADER *)(FileHandle); |
| |
| // |
| // Size is 24 bits wide so mask upper 8 bits. |
| // Does not include FfsFileHeader header size |
| // FileSize is adjusted to FileOccupiedSize as it is 8 byte aligned. |
| // |
| Section = (EFI_COMMON_SECTION_HEADER *)(FfsFileHeader + 1); |
| FileSize = *(UINT32 *)(FfsFileHeader->Size) & 0x00FFFFFF; |
| FileSize -= sizeof (EFI_FFS_FILE_HEADER); |
| |
| return FfsProcessSection ( |
| SectionType, |
| Section, |
| FileSize, |
| SectionData |
| ); |
| } |
| |
| |
| |
| |
| |
| |
| /** |
| This service enables discovery of additional firmware files. |
| |
| @param SearchType A filter to find files only of this type. |
| @param FwVolHeader Pointer to the firmware volume header of the volume to search. |
| This parameter must point to a valid FFS volume. |
| @param FileHeader Pointer to the current file from which to begin searching. |
| |
| @retval EFI_SUCCESS The file was found. |
| @retval EFI_NOT_FOUND The file was not found. |
| @retval EFI_NOT_FOUND The header checksum was not zero. |
| |
| **/ |
| EFI_STATUS |
| EFIAPI |
| FfsFindNextFile ( |
| IN UINT8 SearchType, |
| IN EFI_PEI_FV_HANDLE VolumeHandle, |
| IN OUT EFI_PEI_FILE_HANDLE *FileHandle |
| ) |
| { |
| return FindFileEx (VolumeHandle, NULL, SearchType, FileHandle); |
| } |
| |
| |
| /** |
| This service enables discovery of additional firmware volumes. |
| |
| @param Instance This instance of the firmware volume to find. The value 0 is the |
| Boot Firmware Volume (BFV). |
| @param FwVolHeader Pointer to the firmware volume header of the volume to return. |
| |
| @retval EFI_SUCCESS The volume was found. |
| @retval EFI_NOT_FOUND The volume was not found. |
| |
| **/ |
| EFI_STATUS |
| EFIAPI |
| FfsFindNextVolume ( |
| IN UINTN Instance, |
| IN OUT EFI_PEI_FV_HANDLE *VolumeHandle |
| ) |
| { |
| EFI_PEI_HOB_POINTERS Hob; |
| |
| |
| Hob.Raw = GetHobList (); |
| if (Hob.Raw == NULL) { |
| return EFI_NOT_FOUND; |
| } |
| |
| do { |
| Hob.Raw = GetNextHob (EFI_HOB_TYPE_FV, Hob.Raw); |
| if (Hob.Raw != NULL) { |
| if (Instance-- == 0) { |
| *VolumeHandle = (EFI_PEI_FV_HANDLE)(UINTN)(Hob.FirmwareVolume->BaseAddress); |
| return EFI_SUCCESS; |
| } |
| |
| Hob.Raw = GetNextHob (EFI_HOB_TYPE_FV, GET_NEXT_HOB (Hob)); |
| } |
| } while (Hob.Raw != NULL); |
| |
| return EFI_NOT_FOUND; |
| |
| } |
| |
| |
| /** |
| Find a file in the volume by name |
| |
| @param FileName A pointer to the name of the file to |
| find within the firmware volume. |
| |
| @param VolumeHandle The firmware volume to search FileHandle |
| Upon exit, points to the found file's |
| handle or NULL if it could not be found. |
| |
| @retval EFI_SUCCESS File was found. |
| |
| @retval EFI_NOT_FOUND File was not found. |
| |
| @retval EFI_INVALID_PARAMETER VolumeHandle or FileHandle or |
| FileName was NULL. |
| |
| **/ |
| EFI_STATUS |
| EFIAPI |
| FfsFindFileByName ( |
| IN CONST EFI_GUID *FileName, |
| IN EFI_PEI_FV_HANDLE VolumeHandle, |
| OUT EFI_PEI_FILE_HANDLE *FileHandle |
| ) |
| { |
| EFI_STATUS Status; |
| if ((VolumeHandle == NULL) || (FileName == NULL) || (FileHandle == NULL)) { |
| return EFI_INVALID_PARAMETER; |
| } |
| Status = FindFileEx (VolumeHandle, FileName, 0, FileHandle); |
| if (Status == EFI_NOT_FOUND) { |
| *FileHandle = NULL; |
| } |
| return Status; |
| } |
| |
| |
| |
| |
| /** |
| Get information about the file by name. |
| |
| @param FileHandle Handle of the file. |
| |
| @param FileInfo Upon exit, points to the file's |
| information. |
| |
| @retval EFI_SUCCESS File information returned. |
| |
| @retval EFI_INVALID_PARAMETER If FileHandle does not |
| represent a valid file. |
| |
| @retval EFI_INVALID_PARAMETER If FileInfo is NULL. |
| |
| **/ |
| EFI_STATUS |
| EFIAPI |
| FfsGetFileInfo ( |
| IN EFI_PEI_FILE_HANDLE FileHandle, |
| OUT EFI_FV_FILE_INFO *FileInfo |
| ) |
| { |
| UINT8 FileState; |
| UINT8 ErasePolarity; |
| EFI_FFS_FILE_HEADER *FileHeader; |
| EFI_PEI_FV_HANDLE VolumeHandle; |
| |
| if ((FileHandle == NULL) || (FileInfo == NULL)) { |
| return EFI_INVALID_PARAMETER; |
| } |
| |
| VolumeHandle = 0; |
| // |
| // Retrieve the FirmwareVolume which the file resides in. |
| // |
| if (!FileHandleToVolume(FileHandle, &VolumeHandle)) { |
| return EFI_INVALID_PARAMETER; |
| } |
| |
| if (((EFI_FIRMWARE_VOLUME_HEADER*)VolumeHandle)->Attributes & EFI_FVB2_ERASE_POLARITY) { |
| ErasePolarity = 1; |
| } else { |
| ErasePolarity = 0; |
| } |
| |
| // |
| // Get FileState which is the highest bit of the State |
| // |
| FileState = GetFileState (ErasePolarity, (EFI_FFS_FILE_HEADER*)FileHandle); |
| |
| switch (FileState) { |
| case EFI_FILE_DATA_VALID: |
| case EFI_FILE_MARKED_FOR_UPDATE: |
| break; |
| default: |
| return EFI_INVALID_PARAMETER; |
| } |
| |
| FileHeader = (EFI_FFS_FILE_HEADER *)FileHandle; |
| CopyMem (&FileInfo->FileName, &FileHeader->Name, sizeof(EFI_GUID)); |
| FileInfo->FileType = FileHeader->Type; |
| FileInfo->FileAttributes = FileHeader->Attributes; |
| FileInfo->BufferSize = ((*(UINT32 *)FileHeader->Size) & 0x00FFFFFF) - sizeof (EFI_FFS_FILE_HEADER); |
| FileInfo->Buffer = (FileHeader + 1); |
| return EFI_SUCCESS; |
| } |
| |
| |
| /** |
| Get Information about the volume by name |
| |
| @param VolumeHandle Handle of the volume. |
| |
| @param VolumeInfo Upon exit, points to the volume's |
| information. |
| |
| @retval EFI_SUCCESS File information returned. |
| |
| @retval EFI_INVALID_PARAMETER If FileHandle does not |
| represent a valid file. |
| |
| @retval EFI_INVALID_PARAMETER If FileInfo is NULL. |
| |
| **/ |
| EFI_STATUS |
| EFIAPI |
| FfsGetVolumeInfo ( |
| IN EFI_PEI_FV_HANDLE VolumeHandle, |
| OUT EFI_FV_INFO *VolumeInfo |
| ) |
| { |
| EFI_FIRMWARE_VOLUME_HEADER FwVolHeader; |
| EFI_FIRMWARE_VOLUME_EXT_HEADER *FwVolExHeaderInfo; |
| |
| if (VolumeInfo == NULL) { |
| return EFI_INVALID_PARAMETER; |
| } |
| |
| // |
| // VolumeHandle may not align at 8 byte, |
| // but FvLength is UINT64 type, which requires FvHeader align at least 8 byte. |
| // So, Copy FvHeader into the local FvHeader structure. |
| // |
| CopyMem (&FwVolHeader, VolumeHandle, sizeof (EFI_FIRMWARE_VOLUME_HEADER)); |
| // |
| // Check Fv Image Signature |
| // |
| if (FwVolHeader.Signature != EFI_FVH_SIGNATURE) { |
| return EFI_INVALID_PARAMETER; |
| } |
| VolumeInfo->FvAttributes = FwVolHeader.Attributes; |
| VolumeInfo->FvStart = (VOID *) VolumeHandle; |
| VolumeInfo->FvSize = FwVolHeader.FvLength; |
| CopyMem (&VolumeInfo->FvFormat, &FwVolHeader.FileSystemGuid, sizeof(EFI_GUID)); |
| |
| if (FwVolHeader.ExtHeaderOffset != 0) { |
| FwVolExHeaderInfo = (EFI_FIRMWARE_VOLUME_EXT_HEADER*)(((UINT8 *)VolumeHandle) + FwVolHeader.ExtHeaderOffset); |
| CopyMem (&VolumeInfo->FvName, &FwVolExHeaderInfo->FvName, sizeof(EFI_GUID)); |
| } |
| return EFI_SUCCESS; |
| } |
| |
| |
| |
| /** |
| Search through every FV until you find a file of type FileType |
| |
| @param FileType File handle of a Fv type file. |
| @param Volumehandle On succes Volume Handle of the match |
| @param FileHandle On success File Handle of the match |
| |
| @retval EFI_NOT_FOUND FV image can't be found. |
| @retval EFI_SUCCESS Successfully found FileType |
| |
| **/ |
| EFI_STATUS |
| EFIAPI |
| FfsAnyFvFindFirstFile ( |
| IN EFI_FV_FILETYPE FileType, |
| OUT EFI_PEI_FV_HANDLE *VolumeHandle, |
| OUT EFI_PEI_FILE_HANDLE *FileHandle |
| ) |
| { |
| EFI_STATUS Status; |
| UINTN Instance; |
| |
| // |
| // Search every FV for the DXE Core |
| // |
| Instance = 0; |
| *FileHandle = NULL; |
| |
| while (1) |
| { |
| Status = FfsFindNextVolume (Instance++, VolumeHandle); |
| if (EFI_ERROR (Status)) |
| { |
| break; |
| } |
| |
| Status = FfsFindNextFile (FileType, *VolumeHandle, FileHandle); |
| if (!EFI_ERROR (Status)) |
| { |
| break; |
| } |
| } |
| |
| return Status; |
| } |
| |
| |
| |
| /** |
| Get Fv image from the FV type file, then add FV & FV2 Hob. |
| |
| @param FileHandle File handle of a Fv type file. |
| |
| |
| @retval EFI_NOT_FOUND FV image can't be found. |
| @retval EFI_SUCCESS Successfully to process it. |
| |
| **/ |
| EFI_STATUS |
| EFIAPI |
| FfsProcessFvFile ( |
| IN EFI_PEI_FILE_HANDLE FvFileHandle |
| ) |
| { |
| EFI_STATUS Status; |
| EFI_PEI_FV_HANDLE FvImageHandle; |
| EFI_FV_INFO FvImageInfo; |
| UINT32 FvAlignment; |
| VOID *FvBuffer; |
| EFI_PEI_HOB_POINTERS HobFv2; |
| |
| FvBuffer = NULL; |
| |
| |
| // |
| // Check if this EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE file has already |
| // been extracted. |
| // |
| HobFv2.Raw = GetHobList (); |
| while ((HobFv2.Raw = GetNextHob (EFI_HOB_TYPE_FV2, HobFv2.Raw)) != NULL) { |
| if (CompareGuid (&(((EFI_FFS_FILE_HEADER *)FvFileHandle)->Name), &HobFv2.FirmwareVolume2->FileName)) { |
| // |
| // this FILE has been dispatched, it will not be dispatched again. |
| // |
| return EFI_SUCCESS; |
| } |
| HobFv2.Raw = GET_NEXT_HOB (HobFv2); |
| } |
| |
| // |
| // Find FvImage in FvFile |
| // |
| Status = FfsFindSectionData (EFI_SECTION_FIRMWARE_VOLUME_IMAGE, FvFileHandle, (VOID **)&FvImageHandle); |
| if (EFI_ERROR (Status)) { |
| return Status; |
| } |
| |
| // |
| // Collect FvImage Info. |
| // |
| Status = FfsGetVolumeInfo (FvImageHandle, &FvImageInfo); |
| ASSERT_EFI_ERROR (Status); |
| |
| // |
| // FvAlignment must be more than 8 bytes required by FvHeader structure. |
| // |
| FvAlignment = 1 << ((FvImageInfo.FvAttributes & EFI_FVB2_ALIGNMENT) >> 16); |
| if (FvAlignment < 8) { |
| FvAlignment = 8; |
| } |
| |
| // |
| // Check FvImage |
| // |
| if ((UINTN) FvImageInfo.FvStart % FvAlignment != 0) { |
| FvBuffer = AllocateAlignedPages (EFI_SIZE_TO_PAGES ((UINT32) FvImageInfo.FvSize), FvAlignment); |
| if (FvBuffer == NULL) { |
| return EFI_OUT_OF_RESOURCES; |
| } |
| CopyMem (FvBuffer, FvImageInfo.FvStart, (UINTN) FvImageInfo.FvSize); |
| // |
| // Update FvImageInfo after reload FvImage to new aligned memory |
| // |
| FfsGetVolumeInfo ((EFI_PEI_FV_HANDLE) FvBuffer, &FvImageInfo); |
| } |
| |
| |
| // |
| // Inform HOB consumer phase, i.e. DXE core, the existance of this FV |
| // |
| BuildFvHob ((EFI_PHYSICAL_ADDRESS) (UINTN) FvImageInfo.FvStart, FvImageInfo.FvSize); |
| |
| // |
| // Makes the encapsulated volume show up in DXE phase to skip processing of |
| // encapsulated file again. |
| // |
| BuildFv2Hob ( |
| (EFI_PHYSICAL_ADDRESS) (UINTN) FvImageInfo.FvStart, |
| FvImageInfo.FvSize, |
| &FvImageInfo.FvName, |
| &(((EFI_FFS_FILE_HEADER *)FvFileHandle)->Name) |
| ); |
| |
| return EFI_SUCCESS; |
| } |
| |
| |