mirror of https://github.com/acidanthera/audk.git
885 lines
26 KiB
C
885 lines
26 KiB
C
/** @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);
|
|
}
|
|
|
|
// FFS files begin with a header that is aligned on an 8-byte boundary
|
|
FfsFileHeader = ALIGN_POINTER (FfsFileHeader, 8);
|
|
|
|
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;
|
|
EFI_COMPRESSION_SECTION2 *CompressionSection2;
|
|
UINT32 DstBufferSize;
|
|
VOID *ScratchBuffer;
|
|
UINT32 ScratchBufferSize;
|
|
VOID *DstBuffer;
|
|
UINT16 SectionAttribute;
|
|
UINT32 AuthenticationStatus;
|
|
CHAR8 *CompressedData;
|
|
UINTN CompressedDataLength;
|
|
|
|
|
|
*OutputBuffer = NULL;
|
|
ParsedLength = 0;
|
|
Status = EFI_NOT_FOUND;
|
|
while (ParsedLength < SectionSize) {
|
|
if (IS_SECTION2 (Section)) {
|
|
ASSERT (SECTION2_SIZE (Section) > 0x00FFFFFF);
|
|
}
|
|
|
|
if (Section->Type == SectionType) {
|
|
if (IS_SECTION2 (Section)) {
|
|
*OutputBuffer = (VOID *)((UINT8 *) Section + sizeof (EFI_COMMON_SECTION_HEADER2));
|
|
} else {
|
|
*OutputBuffer = (VOID *)((UINT8 *) Section + sizeof (EFI_COMMON_SECTION_HEADER));
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
} else if ((Section->Type == EFI_SECTION_COMPRESSION) || (Section->Type == EFI_SECTION_GUID_DEFINED)) {
|
|
|
|
if (Section->Type == EFI_SECTION_COMPRESSION) {
|
|
if (IS_SECTION2 (Section)) {
|
|
CompressionSection2 = (EFI_COMPRESSION_SECTION2 *) Section;
|
|
SectionLength = SECTION2_SIZE (Section);
|
|
|
|
if (CompressionSection2->CompressionType != EFI_STANDARD_COMPRESSION) {
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
CompressedData = (CHAR8 *) ((EFI_COMPRESSION_SECTION2 *) Section + 1);
|
|
CompressedDataLength = (UINT32) SectionLength - sizeof (EFI_COMPRESSION_SECTION2);
|
|
} else {
|
|
CompressionSection = (EFI_COMPRESSION_SECTION *) Section;
|
|
SectionLength = SECTION_SIZE (Section);
|
|
|
|
if (CompressionSection->CompressionType != EFI_STANDARD_COMPRESSION) {
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
CompressedData = (CHAR8 *) ((EFI_COMPRESSION_SECTION *) Section + 1);
|
|
CompressedDataLength = (UINT32) SectionLength - sizeof (EFI_COMPRESSION_SECTION);
|
|
}
|
|
|
|
Status = UefiDecompressGetInfo (
|
|
CompressedData,
|
|
CompressedDataLength,
|
|
&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.
|
|
//
|
|
if (IS_SECTION2 (Section))
|
|
DstBuffer = (UINT8 *)DstBuffer + EFI_PAGE_SIZE - sizeof (EFI_COMMON_SECTION_HEADER2);
|
|
else
|
|
DstBuffer = (UINT8 *)DstBuffer + EFI_PAGE_SIZE - sizeof (EFI_COMMON_SECTION_HEADER);
|
|
//
|
|
// Call decompress function
|
|
//
|
|
if (Section->Type == EFI_SECTION_COMPRESSION) {
|
|
if (IS_SECTION2 (Section)) {
|
|
CompressedData = (CHAR8 *) ((EFI_COMPRESSION_SECTION2 *) Section + 1);
|
|
}
|
|
else {
|
|
CompressedData = (CHAR8 *) ((EFI_COMPRESSION_SECTION *) Section + 1);
|
|
}
|
|
|
|
Status = UefiDecompress (
|
|
CompressedData,
|
|
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
|
|
);
|
|
}
|
|
}
|
|
|
|
if (IS_SECTION2 (Section)) {
|
|
SectionLength = SECTION2_SIZE (Section);
|
|
} else {
|
|
SectionLength = SECTION_SIZE (Section);
|
|
}
|
|
//
|
|
// SectionLength is adjusted it is 4 byte aligned.
|
|
// Go to the next section
|
|
//
|
|
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;
|
|
}
|
|
|
|
|