mirror of
https://github.com/CloverHackyColor/CloverBootloader.git
synced 2024-11-28 12:25:19 +01:00
928 lines
22 KiB
C
928 lines
22 KiB
C
|
/** @file
|
||
|
These functions assist in parsing and manipulating a Firmware Volume.
|
||
|
|
||
|
Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>
|
||
|
SPDX-License-Identifier: BSD-2-Clause-Patent
|
||
|
|
||
|
**/
|
||
|
|
||
|
//
|
||
|
// Include files
|
||
|
//
|
||
|
#include "FvLib.h"
|
||
|
#include "CommonLib.h"
|
||
|
#include "EfiUtilityMsgs.h"
|
||
|
|
||
|
//
|
||
|
// Module global variables
|
||
|
//
|
||
|
EFI_FIRMWARE_VOLUME_HEADER *mFvHeader = NULL;
|
||
|
UINT32 mFvLength = 0;
|
||
|
|
||
|
//
|
||
|
// External function implementations
|
||
|
//
|
||
|
EFI_STATUS
|
||
|
InitializeFvLib (
|
||
|
IN VOID *Fv,
|
||
|
IN UINT32 FvLength
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
This initializes the FV lib with a pointer to the FV and length. It does not
|
||
|
verify the FV in any way.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
Fv Buffer containing the FV.
|
||
|
FvLength Length of the FV
|
||
|
|
||
|
Returns:
|
||
|
|
||
|
EFI_SUCCESS Function Completed successfully.
|
||
|
EFI_INVALID_PARAMETER A required parameter was NULL.
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
//
|
||
|
// Verify input arguments
|
||
|
//
|
||
|
if (Fv == NULL) {
|
||
|
return EFI_INVALID_PARAMETER;
|
||
|
}
|
||
|
|
||
|
mFvHeader = (EFI_FIRMWARE_VOLUME_HEADER *) Fv;
|
||
|
mFvLength = FvLength;
|
||
|
|
||
|
return EFI_SUCCESS;
|
||
|
}
|
||
|
|
||
|
EFI_STATUS
|
||
|
GetFvHeader (
|
||
|
OUT EFI_FIRMWARE_VOLUME_HEADER **FvHeader,
|
||
|
OUT UINT32 *FvLength
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
This function returns a pointer to the current FV and the size.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
FvHeader Pointer to the FV buffer.
|
||
|
FvLength Length of the FV
|
||
|
|
||
|
Returns:
|
||
|
|
||
|
EFI_SUCCESS Function Completed successfully.
|
||
|
EFI_INVALID_PARAMETER A required parameter was NULL.
|
||
|
EFI_ABORTED The library needs to be initialized.
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
//
|
||
|
// Verify library has been initialized.
|
||
|
//
|
||
|
if (mFvHeader == NULL || mFvLength == 0) {
|
||
|
return EFI_ABORTED;
|
||
|
}
|
||
|
//
|
||
|
// Verify input arguments
|
||
|
//
|
||
|
if (FvHeader == NULL) {
|
||
|
return EFI_INVALID_PARAMETER;
|
||
|
}
|
||
|
|
||
|
*FvHeader = mFvHeader;
|
||
|
*FvLength = mFvLength;
|
||
|
return EFI_SUCCESS;
|
||
|
}
|
||
|
|
||
|
EFI_STATUS
|
||
|
GetNextFile (
|
||
|
IN EFI_FFS_FILE_HEADER *CurrentFile,
|
||
|
OUT EFI_FFS_FILE_HEADER **NextFile
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
This function returns the next file. If the current file is NULL, it returns
|
||
|
the first file in the FV. If the function returns EFI_SUCCESS and the file
|
||
|
pointer is NULL, then there are no more files in the FV.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
CurrentFile Pointer to the current file, must be within the current FV.
|
||
|
NextFile Pointer to the next file in the FV.
|
||
|
|
||
|
Returns:
|
||
|
|
||
|
EFI_SUCCESS Function completed successfully.
|
||
|
EFI_INVALID_PARAMETER A required parameter was NULL or is out of range.
|
||
|
EFI_ABORTED The library needs to be initialized.
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
EFI_STATUS Status;
|
||
|
|
||
|
//
|
||
|
// Verify library has been initialized.
|
||
|
//
|
||
|
if (mFvHeader == NULL || mFvLength == 0) {
|
||
|
return EFI_ABORTED;
|
||
|
}
|
||
|
//
|
||
|
// Verify input arguments
|
||
|
//
|
||
|
if (NextFile == NULL) {
|
||
|
return EFI_INVALID_PARAMETER;
|
||
|
}
|
||
|
//
|
||
|
// Verify FV header
|
||
|
//
|
||
|
Status = VerifyFv (mFvHeader);
|
||
|
if (EFI_ERROR (Status)) {
|
||
|
return EFI_ABORTED;
|
||
|
}
|
||
|
//
|
||
|
// Get first file
|
||
|
//
|
||
|
if (CurrentFile == NULL) {
|
||
|
CurrentFile = (EFI_FFS_FILE_HEADER *) ((UINTN) mFvHeader + mFvHeader->HeaderLength);
|
||
|
|
||
|
//
|
||
|
// Verify file is valid
|
||
|
//
|
||
|
Status = VerifyFfsFile (CurrentFile);
|
||
|
if (EFI_ERROR (Status)) {
|
||
|
//
|
||
|
// no files in this FV
|
||
|
//
|
||
|
*NextFile = NULL;
|
||
|
return EFI_SUCCESS;
|
||
|
} else {
|
||
|
//
|
||
|
// Verify file is in this FV.
|
||
|
//
|
||
|
if ((UINTN) CurrentFile + GetFfsFileLength(CurrentFile) > (UINTN) mFvHeader + mFvLength) {
|
||
|
*NextFile = NULL;
|
||
|
return EFI_SUCCESS;
|
||
|
}
|
||
|
|
||
|
*NextFile = CurrentFile;
|
||
|
return EFI_SUCCESS;
|
||
|
}
|
||
|
}
|
||
|
//
|
||
|
// Verify current file is in range
|
||
|
//
|
||
|
if (((UINTN) CurrentFile < (UINTN) mFvHeader + mFvHeader->HeaderLength) ||
|
||
|
((UINTN) CurrentFile + GetFfsFileLength(CurrentFile) > (UINTN) mFvHeader + mFvLength)
|
||
|
) {
|
||
|
return EFI_INVALID_PARAMETER;
|
||
|
}
|
||
|
//
|
||
|
// Get next file, compensate for 8 byte alignment if necessary.
|
||
|
//
|
||
|
*NextFile = (EFI_FFS_FILE_HEADER *) ((((UINTN) CurrentFile - (UINTN) mFvHeader + GetFfsFileLength(CurrentFile) + 0x07) & (~(UINTN) 7)) + (UINT8 *) mFvHeader);
|
||
|
|
||
|
//
|
||
|
// Verify file is in this FV.
|
||
|
//
|
||
|
if (((UINTN) *NextFile + GetFfsHeaderLength(*NextFile) >= (UINTN) mFvHeader + mFvLength) ||
|
||
|
((UINTN) *NextFile + GetFfsFileLength (*NextFile) > (UINTN) mFvHeader + mFvLength)
|
||
|
) {
|
||
|
*NextFile = NULL;
|
||
|
return EFI_SUCCESS;
|
||
|
}
|
||
|
//
|
||
|
// Verify file is valid
|
||
|
//
|
||
|
Status = VerifyFfsFile (*NextFile);
|
||
|
if (EFI_ERROR (Status)) {
|
||
|
//
|
||
|
// no more files in this FV
|
||
|
//
|
||
|
*NextFile = NULL;
|
||
|
return EFI_SUCCESS;
|
||
|
}
|
||
|
|
||
|
return EFI_SUCCESS;
|
||
|
}
|
||
|
|
||
|
EFI_STATUS
|
||
|
GetFileByName (
|
||
|
IN EFI_GUID *FileName,
|
||
|
OUT EFI_FFS_FILE_HEADER **File
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Find a file by name. The function will return NULL if the file is not found.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
FileName The GUID file name of the file to search for.
|
||
|
File Return pointer. In the case of an error, contents are undefined.
|
||
|
|
||
|
Returns:
|
||
|
|
||
|
EFI_SUCCESS The function completed successfully.
|
||
|
EFI_ABORTED An error was encountered.
|
||
|
EFI_INVALID_PARAMETER One of the parameters was NULL.
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
EFI_FFS_FILE_HEADER *CurrentFile;
|
||
|
EFI_STATUS Status;
|
||
|
CHAR8 FileGuidString[80];
|
||
|
|
||
|
//
|
||
|
// Verify library has been initialized.
|
||
|
//
|
||
|
if (mFvHeader == NULL || mFvLength == 0) {
|
||
|
return EFI_ABORTED;
|
||
|
}
|
||
|
//
|
||
|
// Verify input parameters
|
||
|
//
|
||
|
if (FileName == NULL || File == NULL) {
|
||
|
return EFI_INVALID_PARAMETER;
|
||
|
}
|
||
|
//
|
||
|
// File Guid String Name
|
||
|
//
|
||
|
PrintGuidToBuffer (FileName, (UINT8 *)FileGuidString, sizeof (FileGuidString), TRUE);
|
||
|
//
|
||
|
// Verify FV header
|
||
|
//
|
||
|
Status = VerifyFv (mFvHeader);
|
||
|
if (EFI_ERROR (Status)) {
|
||
|
return EFI_ABORTED;
|
||
|
}
|
||
|
//
|
||
|
// Get the first file
|
||
|
//
|
||
|
Status = GetNextFile (NULL, &CurrentFile);
|
||
|
if (EFI_ERROR (Status)) {
|
||
|
Error (NULL, 0, 0003, "error parsing FV image", "FFS file with Guid %s can't be found", FileGuidString);
|
||
|
return EFI_ABORTED;
|
||
|
}
|
||
|
//
|
||
|
// Loop as long as we have a valid file
|
||
|
//
|
||
|
while (CurrentFile) {
|
||
|
if (!CompareGuid (&CurrentFile->Name, FileName)) {
|
||
|
*File = CurrentFile;
|
||
|
return EFI_SUCCESS;
|
||
|
}
|
||
|
|
||
|
Status = GetNextFile (CurrentFile, &CurrentFile);
|
||
|
if (EFI_ERROR (Status)) {
|
||
|
Error (NULL, 0, 0003, "error parsing FV image", "FFS file with Guid %s can't be found", FileGuidString);
|
||
|
return EFI_ABORTED;
|
||
|
}
|
||
|
}
|
||
|
//
|
||
|
// File not found in this FV.
|
||
|
//
|
||
|
*File = NULL;
|
||
|
return EFI_SUCCESS;
|
||
|
}
|
||
|
|
||
|
EFI_STATUS
|
||
|
GetFileByType (
|
||
|
IN EFI_FV_FILETYPE FileType,
|
||
|
IN UINTN Instance,
|
||
|
OUT EFI_FFS_FILE_HEADER **File
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Find a file by type and instance. An instance of 1 is the first instance.
|
||
|
The function will return NULL if a matching file cannot be found.
|
||
|
File type EFI_FV_FILETYPE_ALL means any file type is valid.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
FileType Type of file to search for.
|
||
|
Instance Instance of the file type to return.
|
||
|
File Return pointer. In the case of an error, contents are undefined.
|
||
|
|
||
|
Returns:
|
||
|
|
||
|
EFI_SUCCESS The function completed successfully.
|
||
|
EFI_ABORTED An error was encountered.
|
||
|
EFI_INVALID_PARAMETER One of the parameters was NULL.
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
EFI_FFS_FILE_HEADER *CurrentFile;
|
||
|
EFI_STATUS Status;
|
||
|
UINTN FileCount;
|
||
|
|
||
|
//
|
||
|
// Verify library has been initialized.
|
||
|
//
|
||
|
if (mFvHeader == NULL || mFvLength == 0) {
|
||
|
return EFI_ABORTED;
|
||
|
}
|
||
|
//
|
||
|
// Verify input parameters
|
||
|
//
|
||
|
if (File == NULL) {
|
||
|
return EFI_INVALID_PARAMETER;
|
||
|
}
|
||
|
//
|
||
|
// Verify FV header
|
||
|
//
|
||
|
Status = VerifyFv (mFvHeader);
|
||
|
if (EFI_ERROR (Status)) {
|
||
|
return EFI_ABORTED;
|
||
|
}
|
||
|
//
|
||
|
// Initialize the number of matching files found.
|
||
|
//
|
||
|
FileCount = 0;
|
||
|
|
||
|
//
|
||
|
// Get the first file
|
||
|
//
|
||
|
Status = GetNextFile (NULL, &CurrentFile);
|
||
|
if (EFI_ERROR (Status)) {
|
||
|
Error (NULL, 0, 0003, "error parsing FV image", "FFS file with FileType 0x%x can't be found", FileType);
|
||
|
return EFI_ABORTED;
|
||
|
}
|
||
|
//
|
||
|
// Loop as long as we have a valid file
|
||
|
//
|
||
|
while (CurrentFile) {
|
||
|
if (FileType == EFI_FV_FILETYPE_ALL || CurrentFile->Type == FileType) {
|
||
|
FileCount++;
|
||
|
}
|
||
|
|
||
|
if (FileCount == Instance) {
|
||
|
*File = CurrentFile;
|
||
|
return EFI_SUCCESS;
|
||
|
}
|
||
|
|
||
|
Status = GetNextFile (CurrentFile, &CurrentFile);
|
||
|
if (EFI_ERROR (Status)) {
|
||
|
Error (NULL, 0, 0003, "error parsing FV image", "FFS file with FileType 0x%x can't be found", FileType);
|
||
|
return EFI_ABORTED;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
*File = NULL;
|
||
|
return EFI_SUCCESS;
|
||
|
}
|
||
|
|
||
|
EFI_STATUS
|
||
|
SearchSectionByType (
|
||
|
IN EFI_FILE_SECTION_POINTER FirstSection,
|
||
|
IN UINT8 *SearchEnd,
|
||
|
IN EFI_SECTION_TYPE SectionType,
|
||
|
IN OUT UINTN *StartIndex,
|
||
|
IN UINTN Instance,
|
||
|
OUT EFI_FILE_SECTION_POINTER *Section
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Helper function to search a sequence of sections from the section pointed
|
||
|
by FirstSection to SearchEnd for the Instance-th section of type SectionType.
|
||
|
The current counter is saved in StartIndex and when the section is found, it's
|
||
|
saved in Section. GUID-defined sections, if special processing is not required,
|
||
|
are searched recursively in a depth-first manner.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
FirstSection The first section to start searching from.
|
||
|
SearchEnd The end address to stop search.
|
||
|
SectionType The type of section to search.
|
||
|
StartIndex The current counter is saved.
|
||
|
Instance The requested n-th section number.
|
||
|
Section The found section returned.
|
||
|
|
||
|
Returns:
|
||
|
|
||
|
EFI_SUCCESS The function completed successfully.
|
||
|
EFI_NOT_FOUND The section is not found.
|
||
|
--*/
|
||
|
{
|
||
|
EFI_FILE_SECTION_POINTER CurrentSection;
|
||
|
EFI_FILE_SECTION_POINTER InnerSection;
|
||
|
EFI_STATUS Status;
|
||
|
UINTN SectionSize;
|
||
|
UINT16 GuidSecAttr;
|
||
|
UINT16 GuidDataOffset;
|
||
|
|
||
|
GuidSecAttr = 0;
|
||
|
GuidDataOffset = 0;
|
||
|
CurrentSection = FirstSection;
|
||
|
|
||
|
while ((UINTN) CurrentSection.CommonHeader < (UINTN) SearchEnd) {
|
||
|
if (CurrentSection.CommonHeader->Type == SectionType) {
|
||
|
(*StartIndex)++;
|
||
|
}
|
||
|
|
||
|
if (*StartIndex == Instance) {
|
||
|
*Section = CurrentSection;
|
||
|
return EFI_SUCCESS;
|
||
|
}
|
||
|
//
|
||
|
// If the requesting section is not GUID-defined and
|
||
|
// we find a GUID-defined section that doesn't need
|
||
|
// special processing, go ahead to search the requesting
|
||
|
// section inside the GUID-defined section.
|
||
|
//
|
||
|
if (CurrentSection.CommonHeader->Type == EFI_SECTION_GUID_DEFINED) {
|
||
|
if (GetLength(CurrentSection.CommonHeader->Size) == 0xffffff) {
|
||
|
GuidSecAttr = CurrentSection.GuidDefinedSection2->Attributes;
|
||
|
GuidDataOffset = CurrentSection.GuidDefinedSection2->DataOffset;
|
||
|
} else {
|
||
|
GuidSecAttr = CurrentSection.GuidDefinedSection->Attributes;
|
||
|
GuidDataOffset = CurrentSection.GuidDefinedSection->DataOffset;
|
||
|
}
|
||
|
}
|
||
|
if (SectionType != EFI_SECTION_GUID_DEFINED &&
|
||
|
CurrentSection.CommonHeader->Type == EFI_SECTION_GUID_DEFINED &&
|
||
|
!(GuidSecAttr & EFI_GUIDED_SECTION_PROCESSING_REQUIRED)) {
|
||
|
InnerSection.CommonHeader = (EFI_COMMON_SECTION_HEADER *)
|
||
|
((UINTN) CurrentSection.CommonHeader + GuidDataOffset);
|
||
|
SectionSize = GetSectionFileLength(CurrentSection.CommonHeader);
|
||
|
Status = SearchSectionByType (
|
||
|
InnerSection,
|
||
|
(UINT8 *) ((UINTN) CurrentSection.CommonHeader + SectionSize),
|
||
|
SectionType,
|
||
|
StartIndex,
|
||
|
Instance,
|
||
|
Section
|
||
|
);
|
||
|
if (!EFI_ERROR (Status)) {
|
||
|
return EFI_SUCCESS;
|
||
|
}
|
||
|
}
|
||
|
//
|
||
|
// Find next section (including compensating for alignment issues.
|
||
|
//
|
||
|
CurrentSection.CommonHeader = (EFI_COMMON_SECTION_HEADER *) ((((UINTN) CurrentSection.CommonHeader) + GetSectionFileLength(CurrentSection.CommonHeader) + 0x03) & (~(UINTN) 3));
|
||
|
}
|
||
|
|
||
|
return EFI_NOT_FOUND;
|
||
|
}
|
||
|
|
||
|
EFI_STATUS
|
||
|
GetSectionByType (
|
||
|
IN EFI_FFS_FILE_HEADER *File,
|
||
|
IN EFI_SECTION_TYPE SectionType,
|
||
|
IN UINTN Instance,
|
||
|
OUT EFI_FILE_SECTION_POINTER *Section
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Find a section in a file by type and instance. An instance of 1 is the first
|
||
|
instance. The function will return NULL if a matching section cannot be found.
|
||
|
GUID-defined sections, if special processing is not needed, are handled in a
|
||
|
depth-first manner.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
File The file to search.
|
||
|
SectionType Type of file to search for.
|
||
|
Instance Instance of the section to return.
|
||
|
Section Return pointer. In the case of an error, contents are undefined.
|
||
|
|
||
|
Returns:
|
||
|
|
||
|
EFI_SUCCESS The function completed successfully.
|
||
|
EFI_ABORTED An error was encountered.
|
||
|
EFI_INVALID_PARAMETER One of the parameters was NULL.
|
||
|
EFI_NOT_FOUND No found.
|
||
|
--*/
|
||
|
{
|
||
|
EFI_FILE_SECTION_POINTER CurrentSection;
|
||
|
EFI_STATUS Status;
|
||
|
UINTN SectionCount;
|
||
|
|
||
|
//
|
||
|
// Verify input parameters
|
||
|
//
|
||
|
if (File == NULL || Instance == 0) {
|
||
|
return EFI_INVALID_PARAMETER;
|
||
|
}
|
||
|
//
|
||
|
// Verify FFS header
|
||
|
//
|
||
|
Status = VerifyFfsFile (File);
|
||
|
if (EFI_ERROR (Status)) {
|
||
|
Error (NULL, 0, 0006, "invalid FFS file", NULL);
|
||
|
return EFI_ABORTED;
|
||
|
}
|
||
|
//
|
||
|
// Initialize the number of matching sections found.
|
||
|
//
|
||
|
SectionCount = 0;
|
||
|
|
||
|
//
|
||
|
// Get the first section
|
||
|
//
|
||
|
CurrentSection.CommonHeader = (EFI_COMMON_SECTION_HEADER *) ((UINTN) File + GetFfsHeaderLength(File));
|
||
|
|
||
|
//
|
||
|
// Depth-first manner to find section file.
|
||
|
//
|
||
|
Status = SearchSectionByType (
|
||
|
CurrentSection,
|
||
|
(UINT8 *) ((UINTN) File + GetFfsFileLength (File)),
|
||
|
SectionType,
|
||
|
&SectionCount,
|
||
|
Instance,
|
||
|
Section
|
||
|
);
|
||
|
|
||
|
if (!EFI_ERROR (Status)) {
|
||
|
return EFI_SUCCESS;
|
||
|
} else {
|
||
|
//
|
||
|
// Section not found
|
||
|
//
|
||
|
(*Section).Code16Section = NULL;
|
||
|
return EFI_NOT_FOUND;
|
||
|
}
|
||
|
}
|
||
|
//
|
||
|
// will not parse compressed sections
|
||
|
//
|
||
|
EFI_STATUS
|
||
|
VerifyFv (
|
||
|
IN EFI_FIRMWARE_VOLUME_HEADER *FvHeader
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Verify the current pointer points to a valid FV header.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
FvHeader Pointer to an alleged FV file.
|
||
|
|
||
|
Returns:
|
||
|
|
||
|
EFI_SUCCESS The FV header is valid.
|
||
|
EFI_VOLUME_CORRUPTED The FV header is not valid.
|
||
|
EFI_INVALID_PARAMETER A required parameter was NULL.
|
||
|
EFI_ABORTED Operation aborted.
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
UINT16 Checksum;
|
||
|
|
||
|
//
|
||
|
// Verify input parameters
|
||
|
//
|
||
|
if (FvHeader == NULL) {
|
||
|
return EFI_INVALID_PARAMETER;
|
||
|
}
|
||
|
|
||
|
if (FvHeader->Signature != EFI_FVH_SIGNATURE) {
|
||
|
Error (NULL, 0, 0006, "invalid FV header signature", NULL);
|
||
|
return EFI_VOLUME_CORRUPTED;
|
||
|
}
|
||
|
//
|
||
|
// Verify header checksum
|
||
|
//
|
||
|
Checksum = CalculateSum16 ((UINT16 *) FvHeader, FvHeader->HeaderLength / sizeof (UINT16));
|
||
|
|
||
|
if (Checksum != 0) {
|
||
|
Error (NULL, 0, 0006, "invalid FV header checksum", NULL);
|
||
|
return EFI_ABORTED;
|
||
|
}
|
||
|
|
||
|
return EFI_SUCCESS;
|
||
|
}
|
||
|
|
||
|
EFI_STATUS
|
||
|
VerifyFfsFile (
|
||
|
IN EFI_FFS_FILE_HEADER *FfsHeader
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Verify the current pointer points to a FFS file header.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
FfsHeader Pointer to an alleged FFS file.
|
||
|
|
||
|
Returns:
|
||
|
|
||
|
EFI_SUCCESS The Ffs header is valid.
|
||
|
EFI_NOT_FOUND This "file" is the beginning of free space.
|
||
|
EFI_VOLUME_CORRUPTED The Ffs header is not valid.
|
||
|
EFI_ABORTED The erase polarity is not known.
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
BOOLEAN ErasePolarity;
|
||
|
EFI_STATUS Status;
|
||
|
EFI_FFS_FILE_HEADER2 BlankHeader;
|
||
|
UINT8 Checksum;
|
||
|
UINT32 FileLength;
|
||
|
UINT8 SavedChecksum;
|
||
|
UINT8 SavedState;
|
||
|
UINT8 FileGuidString[80];
|
||
|
UINT32 FfsHeaderSize;
|
||
|
|
||
|
//
|
||
|
// Verify library has been initialized.
|
||
|
//
|
||
|
if (mFvHeader == NULL || mFvLength == 0) {
|
||
|
return EFI_ABORTED;
|
||
|
}
|
||
|
//
|
||
|
// Verify FV header
|
||
|
//
|
||
|
Status = VerifyFv (mFvHeader);
|
||
|
if (EFI_ERROR (Status)) {
|
||
|
return EFI_ABORTED;
|
||
|
}
|
||
|
//
|
||
|
// Get the erase polarity.
|
||
|
//
|
||
|
Status = GetErasePolarity (&ErasePolarity);
|
||
|
if (EFI_ERROR (Status)) {
|
||
|
return EFI_ABORTED;
|
||
|
}
|
||
|
|
||
|
FfsHeaderSize = GetFfsHeaderLength(FfsHeader);
|
||
|
//
|
||
|
// Check if we have free space
|
||
|
//
|
||
|
if (ErasePolarity) {
|
||
|
memset (&BlankHeader, -1, FfsHeaderSize);
|
||
|
} else {
|
||
|
memset (&BlankHeader, 0, FfsHeaderSize);
|
||
|
}
|
||
|
|
||
|
if (memcmp (&BlankHeader, FfsHeader, FfsHeaderSize) == 0) {
|
||
|
return EFI_NOT_FOUND;
|
||
|
}
|
||
|
//
|
||
|
// Convert the GUID to a string so we can at least report which file
|
||
|
// if we find an error.
|
||
|
//
|
||
|
PrintGuidToBuffer (&FfsHeader->Name, FileGuidString, sizeof (FileGuidString), TRUE);
|
||
|
//
|
||
|
// Verify file header checksum
|
||
|
//
|
||
|
SavedState = FfsHeader->State;
|
||
|
FfsHeader->State = 0;
|
||
|
SavedChecksum = FfsHeader->IntegrityCheck.Checksum.File;
|
||
|
FfsHeader->IntegrityCheck.Checksum.File = 0;
|
||
|
Checksum = CalculateSum8 ((UINT8 *) FfsHeader, FfsHeaderSize);
|
||
|
FfsHeader->State = SavedState;
|
||
|
FfsHeader->IntegrityCheck.Checksum.File = SavedChecksum;
|
||
|
if (Checksum != 0) {
|
||
|
Error (NULL, 0, 0006, "invalid FFS file header checksum", "Ffs file with Guid %s", FileGuidString);
|
||
|
return EFI_ABORTED;
|
||
|
}
|
||
|
//
|
||
|
// Verify file checksum
|
||
|
//
|
||
|
if (FfsHeader->Attributes & FFS_ATTRIB_CHECKSUM) {
|
||
|
//
|
||
|
// Verify file data checksum
|
||
|
//
|
||
|
FileLength = GetFfsFileLength (FfsHeader);
|
||
|
Checksum = CalculateSum8 ((UINT8 *) ((UINT8 *)FfsHeader + FfsHeaderSize), FileLength - FfsHeaderSize);
|
||
|
Checksum = Checksum + FfsHeader->IntegrityCheck.Checksum.File;
|
||
|
if (Checksum != 0) {
|
||
|
Error (NULL, 0, 0006, "invalid FFS file checksum", "Ffs file with Guid %s", FileGuidString);
|
||
|
return EFI_ABORTED;
|
||
|
}
|
||
|
} else {
|
||
|
//
|
||
|
// File does not have a checksum
|
||
|
// Verify contents are 0xAA as spec'd
|
||
|
//
|
||
|
if (FfsHeader->IntegrityCheck.Checksum.File != FFS_FIXED_CHECKSUM) {
|
||
|
Error (NULL, 0, 0006, "invalid fixed FFS file header checksum", "Ffs file with Guid %s", FileGuidString);
|
||
|
return EFI_ABORTED;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return EFI_SUCCESS;
|
||
|
}
|
||
|
|
||
|
UINT32
|
||
|
GetFfsHeaderLength(
|
||
|
IN EFI_FFS_FILE_HEADER *FfsHeader
|
||
|
)
|
||
|
{
|
||
|
if (FfsHeader == NULL) {
|
||
|
return 0;
|
||
|
}
|
||
|
if (FfsHeader->Attributes & FFS_ATTRIB_LARGE_FILE) {
|
||
|
return sizeof(EFI_FFS_FILE_HEADER2);
|
||
|
}
|
||
|
return sizeof(EFI_FFS_FILE_HEADER);
|
||
|
}
|
||
|
|
||
|
UINT32
|
||
|
GetSectionHeaderLength(
|
||
|
IN EFI_COMMON_SECTION_HEADER *SectionHeader
|
||
|
)
|
||
|
{
|
||
|
if (SectionHeader == NULL) {
|
||
|
return 0;
|
||
|
}
|
||
|
if (GetLength(SectionHeader->Size) == 0xffffff) {
|
||
|
return sizeof(EFI_COMMON_SECTION_HEADER2);
|
||
|
}
|
||
|
return sizeof(EFI_COMMON_SECTION_HEADER);
|
||
|
}
|
||
|
|
||
|
UINT32
|
||
|
GetFfsFileLength (
|
||
|
EFI_FFS_FILE_HEADER *FfsHeader
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Get FFS file length including FFS header.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
FfsHeader Pointer to EFI_FFS_FILE_HEADER.
|
||
|
|
||
|
Returns:
|
||
|
|
||
|
UINT32 Length of FFS file header.
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
if (FfsHeader == NULL) {
|
||
|
return 0;
|
||
|
}
|
||
|
if (FfsHeader->Attributes & FFS_ATTRIB_LARGE_FILE) {
|
||
|
return (UINT32) ((EFI_FFS_FILE_HEADER2 *)FfsHeader)->ExtendedSize;
|
||
|
} else {
|
||
|
return GetLength(FfsHeader->Size);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
UINT32
|
||
|
GetSectionFileLength (
|
||
|
EFI_COMMON_SECTION_HEADER *SectionHeader
|
||
|
)
|
||
|
{
|
||
|
UINT32 Length;
|
||
|
if (SectionHeader == NULL) {
|
||
|
return 0;
|
||
|
}
|
||
|
Length = GetLength(SectionHeader->Size);
|
||
|
if (Length == 0xffffff) {
|
||
|
Length = ((EFI_COMMON_SECTION_HEADER2 *)SectionHeader)->ExtendedSize;
|
||
|
}
|
||
|
return Length;
|
||
|
}
|
||
|
|
||
|
UINT32
|
||
|
GetLength (
|
||
|
UINT8 *ThreeByteLength
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Converts a three byte length value into a UINT32.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
ThreeByteLength Pointer to the first of the 3 byte length.
|
||
|
|
||
|
Returns:
|
||
|
|
||
|
UINT32 Size of the section
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
UINT32 Length;
|
||
|
|
||
|
if (ThreeByteLength == NULL) {
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
Length = *((UINT32 *) ThreeByteLength);
|
||
|
Length = Length & 0x00FFFFFF;
|
||
|
|
||
|
return Length;
|
||
|
}
|
||
|
|
||
|
EFI_STATUS
|
||
|
GetErasePolarity (
|
||
|
OUT BOOLEAN *ErasePolarity
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
This function returns with the FV erase polarity. If the erase polarity
|
||
|
for a bit is 1, the function return TRUE.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
ErasePolarity A pointer to the erase polarity.
|
||
|
|
||
|
Returns:
|
||
|
|
||
|
EFI_SUCCESS The function completed successfully.
|
||
|
EFI_INVALID_PARAMETER One of the input parameters was invalid.
|
||
|
EFI_ABORTED Operation aborted.
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
EFI_STATUS Status;
|
||
|
|
||
|
//
|
||
|
// Verify library has been initialized.
|
||
|
//
|
||
|
if (mFvHeader == NULL || mFvLength == 0) {
|
||
|
return EFI_ABORTED;
|
||
|
}
|
||
|
//
|
||
|
// Verify FV header
|
||
|
//
|
||
|
Status = VerifyFv (mFvHeader);
|
||
|
if (EFI_ERROR (Status)) {
|
||
|
return EFI_ABORTED;
|
||
|
}
|
||
|
//
|
||
|
// Verify input parameters.
|
||
|
//
|
||
|
if (ErasePolarity == NULL) {
|
||
|
return EFI_INVALID_PARAMETER;
|
||
|
}
|
||
|
|
||
|
if (mFvHeader->Attributes & EFI_FVB2_ERASE_POLARITY) {
|
||
|
*ErasePolarity = TRUE;
|
||
|
} else {
|
||
|
*ErasePolarity = FALSE;
|
||
|
}
|
||
|
|
||
|
return EFI_SUCCESS;
|
||
|
}
|
||
|
|
||
|
UINT8
|
||
|
GetFileState (
|
||
|
IN BOOLEAN ErasePolarity,
|
||
|
IN EFI_FFS_FILE_HEADER *FfsHeader
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
This function returns a the highest state bit in the FFS that is set.
|
||
|
It in no way validate the FFS file.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
ErasePolarity The erase polarity for the file state bits.
|
||
|
FfsHeader Pointer to a FFS file.
|
||
|
|
||
|
Returns:
|
||
|
|
||
|
UINT8 The hightest set state of the file.
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
UINT8 FileState;
|
||
|
UINT8 HighestBit;
|
||
|
|
||
|
FileState = FfsHeader->State;
|
||
|
|
||
|
if (ErasePolarity) {
|
||
|
FileState = (UINT8)~FileState;
|
||
|
}
|
||
|
|
||
|
HighestBit = 0x80;
|
||
|
while (HighestBit != 0 && (HighestBit & FileState) == 0) {
|
||
|
HighestBit >>= 1;
|
||
|
}
|
||
|
|
||
|
return HighestBit;
|
||
|
}
|