/** @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.<BR> | |
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; | |
UINT32 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), | |
&DstBufferSize, | |
&ScratchBufferSize | |
); | |
} else if (Section->Type == EFI_SECTION_GUID_DEFINED) { | |
Status = ExtractGuidedSectionGetInfo ( | |
Section, | |
&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. | |
// | |
ZeroMem (&FvImageInfo, sizeof (FvImageInfo)); | |
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; | |
} | |