IntelFrameworkModulePkg: Add FwVolDxe driver
Signed-off-by: jljusten Reviewed-by: rsun3 Reviewed-by: lgao4 git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@12256 6f19259b-4bc3-4df7-8a09-765794883524
This commit is contained in:
625
IntelFrameworkModulePkg/Universal/FirmwareVolume/FwVolDxe/Ffs.c
Normal file
625
IntelFrameworkModulePkg/Universal/FirmwareVolume/FwVolDxe/Ffs.c
Normal file
@ -0,0 +1,625 @@
|
||||
/** @file
|
||||
FFS file access utilities.
|
||||
|
||||
Copyright (c) 2006 - 2011, Intel Corporation. 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 "FwVolDriver.h"
|
||||
|
||||
#define PHYSICAL_ADDRESS_TO_POINTER(Address) ((VOID *) ((UINTN) Address))
|
||||
|
||||
/**
|
||||
Set File State in the FfsHeader.
|
||||
|
||||
@param State File state to be set into FFS header.
|
||||
@param FfsHeader Points to the FFS file header
|
||||
|
||||
**/
|
||||
VOID
|
||||
SetFileState (
|
||||
IN UINT8 State,
|
||||
IN EFI_FFS_FILE_HEADER *FfsHeader
|
||||
)
|
||||
{
|
||||
//
|
||||
// Set File State in the FfsHeader
|
||||
//
|
||||
FfsHeader->State = (EFI_FFS_FILE_STATE) (FfsHeader->State ^ State);
|
||||
return ;
|
||||
}
|
||||
|
||||
/**
|
||||
Get the FFS file state by checking the highest bit set in the header's state field.
|
||||
|
||||
@param ErasePolarity Erase polarity attribute of the firmware volume
|
||||
@param FfsHeader Points to the FFS file header
|
||||
|
||||
@return FFS File state
|
||||
|
||||
**/
|
||||
EFI_FFS_FILE_STATE
|
||||
GetFileState (
|
||||
IN UINT8 ErasePolarity,
|
||||
IN EFI_FFS_FILE_HEADER *FfsHeader
|
||||
)
|
||||
{
|
||||
EFI_FFS_FILE_STATE FileState;
|
||||
UINT8 HighestBit;
|
||||
|
||||
FileState = FfsHeader->State;
|
||||
|
||||
if (ErasePolarity != 0) {
|
||||
FileState = (EFI_FFS_FILE_STATE)~FileState;
|
||||
}
|
||||
|
||||
HighestBit = 0x80;
|
||||
while (HighestBit != 0 && ((HighestBit & FileState) == 0)) {
|
||||
HighestBit >>= 1;
|
||||
}
|
||||
|
||||
return (EFI_FFS_FILE_STATE) HighestBit;
|
||||
}
|
||||
|
||||
/**
|
||||
Convert the Buffer Address to LBA Entry Address.
|
||||
|
||||
@param FvDevice Cached FvDevice
|
||||
@param BufferAddress Address of Buffer
|
||||
@param LbaListEntry Pointer to the got LBA entry that contains the address.
|
||||
|
||||
@retval EFI_NOT_FOUND Buffer address is out of FvDevice.
|
||||
@retval EFI_SUCCESS LBA entry is found for Buffer address.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
Buffer2LbaEntry (
|
||||
IN FV_DEVICE *FvDevice,
|
||||
IN EFI_PHYSICAL_ADDRESS BufferAddress,
|
||||
OUT LBA_ENTRY **LbaListEntry
|
||||
)
|
||||
{
|
||||
LBA_ENTRY *LbaEntry;
|
||||
LIST_ENTRY *Link;
|
||||
|
||||
Link = FvDevice->LbaHeader.ForwardLink;
|
||||
LbaEntry = (LBA_ENTRY *) Link;
|
||||
|
||||
//
|
||||
// Locate LBA which contains the address
|
||||
//
|
||||
while (&LbaEntry->Link != &FvDevice->LbaHeader) {
|
||||
if ((EFI_PHYSICAL_ADDRESS) (UINTN) (LbaEntry->StartingAddress) > BufferAddress) {
|
||||
break;
|
||||
}
|
||||
|
||||
Link = LbaEntry->Link.ForwardLink;
|
||||
LbaEntry = (LBA_ENTRY *) Link;
|
||||
}
|
||||
|
||||
if (&LbaEntry->Link == &FvDevice->LbaHeader) {
|
||||
return EFI_NOT_FOUND;
|
||||
}
|
||||
|
||||
Link = LbaEntry->Link.BackLink;
|
||||
LbaEntry = (LBA_ENTRY *) Link;
|
||||
|
||||
if (&LbaEntry->Link == &FvDevice->LbaHeader) {
|
||||
return EFI_NOT_FOUND;
|
||||
}
|
||||
|
||||
*LbaListEntry = LbaEntry;
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
Convert the Buffer Address to LBA Address & Offset.
|
||||
|
||||
@param FvDevice Cached FvDevice
|
||||
@param BufferAddress Address of Buffer
|
||||
@param Lba Pointer to the gob Lba value
|
||||
@param Offset Pointer to the got Offset
|
||||
|
||||
@retval EFI_NOT_FOUND Buffer address is out of FvDevice.
|
||||
@retval EFI_SUCCESS LBA and Offset is found for Buffer address.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
Buffer2Lba (
|
||||
IN FV_DEVICE *FvDevice,
|
||||
IN EFI_PHYSICAL_ADDRESS BufferAddress,
|
||||
OUT EFI_LBA *Lba,
|
||||
OUT UINTN *Offset
|
||||
)
|
||||
{
|
||||
LBA_ENTRY *LbaEntry;
|
||||
EFI_STATUS Status;
|
||||
|
||||
LbaEntry = NULL;
|
||||
|
||||
Status = Buffer2LbaEntry (
|
||||
FvDevice,
|
||||
BufferAddress,
|
||||
&LbaEntry
|
||||
);
|
||||
if (EFI_ERROR (Status)) {
|
||||
return Status;
|
||||
}
|
||||
|
||||
*Lba = LbaEntry->LbaIndex;
|
||||
*Offset = (UINTN) BufferAddress - (UINTN) LbaEntry->StartingAddress;
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
Check if a block of buffer is erased.
|
||||
|
||||
@param ErasePolarity Erase polarity attribute of the firmware volume
|
||||
@param Buffer The buffer to be checked
|
||||
@param BufferSize Size of the buffer in bytes
|
||||
|
||||
@retval TRUE The block of buffer is erased
|
||||
@retval FALSE The block of buffer is not erased
|
||||
|
||||
**/
|
||||
BOOLEAN
|
||||
IsBufferErased (
|
||||
IN UINT8 ErasePolarity,
|
||||
IN UINT8 *Buffer,
|
||||
IN UINTN BufferSize
|
||||
)
|
||||
{
|
||||
UINTN Count;
|
||||
UINT8 EraseByte;
|
||||
|
||||
if (ErasePolarity == 1) {
|
||||
EraseByte = 0xFF;
|
||||
} else {
|
||||
EraseByte = 0;
|
||||
}
|
||||
|
||||
for (Count = 0; Count < BufferSize; Count++) {
|
||||
if (Buffer[Count] != EraseByte) {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
Verify checksum of the firmware volume header.
|
||||
|
||||
@param FvHeader Points to the firmware volume header to be checked
|
||||
|
||||
@retval TRUE Checksum verification passed
|
||||
@retval FALSE Checksum verification failed
|
||||
|
||||
**/
|
||||
BOOLEAN
|
||||
VerifyFvHeaderChecksum (
|
||||
IN EFI_FIRMWARE_VOLUME_HEADER *FvHeader
|
||||
)
|
||||
{
|
||||
UINT16 Checksum;
|
||||
|
||||
Checksum = CalculateSum16 ((UINT16 *) FvHeader, FvHeader->HeaderLength);
|
||||
|
||||
if (Checksum == 0) {
|
||||
return TRUE;
|
||||
} else {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Verify checksum of the FFS file header.
|
||||
|
||||
@param FfsHeader Points to the FFS file header to be checked
|
||||
|
||||
@retval TRUE Checksum verification passed
|
||||
@retval FALSE Checksum verification failed
|
||||
|
||||
**/
|
||||
BOOLEAN
|
||||
VerifyHeaderChecksum (
|
||||
IN EFI_FFS_FILE_HEADER *FfsHeader
|
||||
)
|
||||
{
|
||||
UINT8 HeaderChecksum;
|
||||
|
||||
HeaderChecksum = CalculateSum8 ((UINT8 *) FfsHeader, sizeof (EFI_FFS_FILE_HEADER));
|
||||
HeaderChecksum = (UINT8) (HeaderChecksum - FfsHeader->State - FfsHeader->IntegrityCheck.Checksum.File);
|
||||
|
||||
if (HeaderChecksum == 0) {
|
||||
return TRUE;
|
||||
} else {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Verify checksum of the FFS file data.
|
||||
|
||||
@param FfsHeader Points to the FFS file header to be checked
|
||||
|
||||
@retval TRUE Checksum verification passed
|
||||
@retval FALSE Checksum verification failed
|
||||
|
||||
**/
|
||||
BOOLEAN
|
||||
VerifyFileChecksum (
|
||||
IN EFI_FFS_FILE_HEADER *FfsHeader
|
||||
)
|
||||
{
|
||||
UINT8 FileChecksum;
|
||||
EFI_FV_FILE_ATTRIBUTES Attributes;
|
||||
UINT32 FileSize;
|
||||
|
||||
Attributes = FfsHeader->Attributes;
|
||||
|
||||
if ((Attributes & FFS_ATTRIB_CHECKSUM) != 0) {
|
||||
|
||||
FileSize = *(UINT32 *) FfsHeader->Size & 0x00FFFFFF;
|
||||
|
||||
//
|
||||
// Check checksum of FFS data
|
||||
//
|
||||
FileChecksum = CalculateSum8 ((UINT8 *) FfsHeader + sizeof (EFI_FFS_FILE_HEADER), FileSize - sizeof (EFI_FFS_FILE_HEADER));
|
||||
FileChecksum = (UINT8) (FileChecksum + FfsHeader->IntegrityCheck.Checksum.File);
|
||||
|
||||
if (FileChecksum == 0) {
|
||||
return TRUE;
|
||||
} else {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
if (FfsHeader->IntegrityCheck.Checksum.File != FFS_FIXED_CHECKSUM) {
|
||||
return FALSE;
|
||||
} else {
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
Check if it's a valid FFS file header.
|
||||
|
||||
@param ErasePolarity Erase polarity attribute of the firmware volume
|
||||
@param FfsHeader Points to the FFS file header to be checked
|
||||
|
||||
@retval TRUE Valid FFS file header
|
||||
@retval FALSE Invalid FFS file header
|
||||
|
||||
**/
|
||||
BOOLEAN
|
||||
IsValidFFSHeader (
|
||||
IN UINT8 ErasePolarity,
|
||||
IN EFI_FFS_FILE_HEADER *FfsHeader
|
||||
)
|
||||
{
|
||||
EFI_FFS_FILE_STATE FileState;
|
||||
|
||||
//
|
||||
// Check if it is a free space
|
||||
//
|
||||
if (IsBufferErased (
|
||||
ErasePolarity,
|
||||
(UINT8 *) FfsHeader,
|
||||
sizeof (EFI_FFS_FILE_HEADER)
|
||||
)) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
FileState = GetFileState (ErasePolarity, FfsHeader);
|
||||
|
||||
switch (FileState) {
|
||||
case EFI_FILE_HEADER_CONSTRUCTION:
|
||||
//
|
||||
// fall through
|
||||
//
|
||||
case EFI_FILE_HEADER_INVALID:
|
||||
return FALSE;
|
||||
|
||||
case EFI_FILE_HEADER_VALID:
|
||||
//
|
||||
// fall through
|
||||
//
|
||||
case EFI_FILE_DATA_VALID:
|
||||
//
|
||||
// fall through
|
||||
//
|
||||
case EFI_FILE_MARKED_FOR_UPDATE:
|
||||
//
|
||||
// fall through
|
||||
//
|
||||
case EFI_FILE_DELETED:
|
||||
//
|
||||
// Here we need to verify header checksum
|
||||
//
|
||||
if (!VerifyHeaderChecksum (FfsHeader)) {
|
||||
return FALSE;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
//
|
||||
// return
|
||||
//
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
Get next possible of Firmware File System Header.
|
||||
|
||||
@param ErasePolarity Erase polarity attribute of the firmware volume
|
||||
@param FfsHeader Points to the FFS file header to be skipped.
|
||||
|
||||
@return Pointer to next FFS header.
|
||||
|
||||
**/
|
||||
EFI_PHYSICAL_ADDRESS
|
||||
GetNextPossibleFileHeader (
|
||||
IN UINT8 ErasePolarity,
|
||||
IN EFI_FFS_FILE_HEADER *FfsHeader
|
||||
)
|
||||
{
|
||||
UINT32 FileLength;
|
||||
UINT32 SkipLength;
|
||||
|
||||
if (!IsValidFFSHeader (ErasePolarity, FfsHeader)) {
|
||||
//
|
||||
// Skip this header
|
||||
//
|
||||
return (EFI_PHYSICAL_ADDRESS) (UINTN) FfsHeader + sizeof (EFI_FFS_FILE_HEADER);
|
||||
}
|
||||
|
||||
FileLength = *(UINT32 *) FfsHeader->Size & 0x00FFFFFF;
|
||||
|
||||
//
|
||||
// Since FileLength is not multiple of 8, we need skip some bytes
|
||||
// to get next possible header
|
||||
//
|
||||
SkipLength = FileLength;
|
||||
while ((SkipLength & 0x07) != 0) {
|
||||
SkipLength++;
|
||||
}
|
||||
|
||||
return (EFI_PHYSICAL_ADDRESS) (UINTN) FfsHeader + SkipLength;
|
||||
}
|
||||
|
||||
/**
|
||||
Search FFS file with the same FFS name in FV Cache.
|
||||
|
||||
@param FvDevice Cached FV image.
|
||||
@param FfsHeader Points to the FFS file header to be skipped.
|
||||
@param StateBit FFS file state bit to be checked.
|
||||
|
||||
@return Pointer to next found FFS header. NULL will return if no found.
|
||||
|
||||
**/
|
||||
EFI_FFS_FILE_HEADER *
|
||||
DuplicateFileExist (
|
||||
IN FV_DEVICE *FvDevice,
|
||||
IN EFI_FFS_FILE_HEADER *FfsHeader,
|
||||
IN EFI_FFS_FILE_STATE StateBit
|
||||
)
|
||||
{
|
||||
UINT8 *Ptr;
|
||||
EFI_FFS_FILE_HEADER *NextFfsFile;
|
||||
|
||||
//
|
||||
// Search duplicate file, not from the beginning of FV,
|
||||
// just search the next ocurrence of this file
|
||||
//
|
||||
NextFfsFile = FfsHeader;
|
||||
|
||||
do {
|
||||
Ptr = (UINT8 *) PHYSICAL_ADDRESS_TO_POINTER (
|
||||
GetNextPossibleFileHeader (FvDevice->ErasePolarity,
|
||||
NextFfsFile)
|
||||
);
|
||||
NextFfsFile = (EFI_FFS_FILE_HEADER *) Ptr;
|
||||
|
||||
if ((UINT8 *) PHYSICAL_ADDRESS_TO_POINTER (FvDevice->CachedFv) + FvDevice->FwVolHeader->FvLength - Ptr <
|
||||
sizeof (EFI_FFS_FILE_HEADER)
|
||||
) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (!IsValidFFSHeader (FvDevice->ErasePolarity, NextFfsFile)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!VerifyFileChecksum (NextFfsFile)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (CompareGuid (&NextFfsFile->Name, &FfsHeader->Name)) {
|
||||
if (GetFileState (FvDevice->ErasePolarity, NextFfsFile) == StateBit) {
|
||||
return NextFfsFile;
|
||||
}
|
||||
}
|
||||
} while (Ptr < (UINT8 *) PHYSICAL_ADDRESS_TO_POINTER (FvDevice->CachedFv) + FvDevice->FwVolHeader->FvLength);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
Change FFS file header state and write to FV.
|
||||
|
||||
@param FvDevice Cached FV image.
|
||||
@param FfsHeader Points to the FFS file header to be updated.
|
||||
@param State FFS file state to be set.
|
||||
|
||||
@retval EFI_SUCCESS File state is writen into FV.
|
||||
@retval others File state can't be writen into FV.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
UpdateHeaderBit (
|
||||
IN FV_DEVICE *FvDevice,
|
||||
IN EFI_FFS_FILE_HEADER *FfsHeader,
|
||||
IN EFI_FFS_FILE_STATE State
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
EFI_LBA Lba;
|
||||
UINTN Offset;
|
||||
UINTN NumBytesWritten;
|
||||
|
||||
Lba = 0;
|
||||
Offset = 0;
|
||||
|
||||
SetFileState (State, FfsHeader);
|
||||
|
||||
Buffer2Lba (
|
||||
FvDevice,
|
||||
(EFI_PHYSICAL_ADDRESS) (UINTN) (&FfsHeader->State),
|
||||
&Lba,
|
||||
&Offset
|
||||
);
|
||||
//
|
||||
// Write the state byte into FV
|
||||
//
|
||||
NumBytesWritten = sizeof (EFI_FFS_FILE_STATE);
|
||||
Status = FvDevice->Fvb->Write (
|
||||
FvDevice->Fvb,
|
||||
Lba,
|
||||
Offset,
|
||||
&NumBytesWritten,
|
||||
&FfsHeader->State
|
||||
);
|
||||
return Status;
|
||||
}
|
||||
|
||||
/**
|
||||
Check if it's a valid FFS file.
|
||||
Here we are sure that it has a valid FFS file header since we must call IsValidFfsHeader() first.
|
||||
|
||||
@param FvDevice Cached FV image.
|
||||
@param FfsHeader Points to the FFS file to be checked
|
||||
|
||||
@retval TRUE Valid FFS file
|
||||
@retval FALSE Invalid FFS file
|
||||
|
||||
**/
|
||||
BOOLEAN
|
||||
IsValidFFSFile (
|
||||
IN FV_DEVICE *FvDevice,
|
||||
IN EFI_FFS_FILE_HEADER *FfsHeader
|
||||
)
|
||||
{
|
||||
EFI_FFS_FILE_STATE FileState;
|
||||
UINT8 ErasePolarity;
|
||||
|
||||
ErasePolarity = FvDevice->ErasePolarity;
|
||||
|
||||
FileState = GetFileState (ErasePolarity, FfsHeader);
|
||||
|
||||
switch (FileState) {
|
||||
case EFI_FILE_DATA_VALID:
|
||||
if (!VerifyFileChecksum (FfsHeader)) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (FfsHeader->Type == EFI_FV_FILETYPE_FFS_PAD) {
|
||||
break;
|
||||
}
|
||||
//
|
||||
// Check if there is another duplicated file with the EFI_FILE_DATA_VALID
|
||||
//
|
||||
if (DuplicateFileExist (FvDevice, FfsHeader, EFI_FILE_DATA_VALID) != NULL) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case EFI_FILE_MARKED_FOR_UPDATE:
|
||||
if (!VerifyFileChecksum (FfsHeader)) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (FfsHeader->Type == EFI_FV_FILETYPE_FFS_PAD) {
|
||||
//
|
||||
// since its data area is not unperturbed, it cannot be reclaimed,
|
||||
// marked it as deleted
|
||||
//
|
||||
UpdateHeaderBit (FvDevice, FfsHeader, EFI_FILE_DELETED);
|
||||
return TRUE;
|
||||
|
||||
} else if (DuplicateFileExist (FvDevice, FfsHeader, EFI_FILE_DATA_VALID) != NULL) {
|
||||
//
|
||||
// Here the found file is more recent than this file,
|
||||
// mark it as deleted
|
||||
//
|
||||
UpdateHeaderBit (FvDevice, FfsHeader, EFI_FILE_DELETED);
|
||||
return TRUE;
|
||||
|
||||
} else {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case EFI_FILE_DELETED:
|
||||
if (!VerifyFileChecksum (FfsHeader)) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
Locate the first file in FV.
|
||||
|
||||
@param FvDevice Cached FV image.
|
||||
@param FirstFile Points to the got first FFS file header.
|
||||
|
||||
@retval EFI_NOT_FOUND No FFS file is found in FV.
|
||||
@retval EFI_SUCCESS The first FFS file is got.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
FvLocateFirstFile (
|
||||
IN FV_DEVICE *FvDevice,
|
||||
OUT EFI_FFS_FILE_HEADER **FirstFile
|
||||
)
|
||||
{
|
||||
FFS_FILE_LIST_ENTRY *TmpFileList;
|
||||
LIST_ENTRY *Link;
|
||||
|
||||
Link = FvDevice->FfsFileListHeader.ForwardLink;
|
||||
|
||||
if (Link == &FvDevice->FfsFileListHeader) {
|
||||
return EFI_NOT_FOUND;
|
||||
}
|
||||
|
||||
TmpFileList = (FFS_FILE_LIST_ENTRY *) Link;
|
||||
*FirstFile = (EFI_FFS_FILE_HEADER *) TmpFileList->FfsHeader;
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
Reference in New Issue
Block a user