audk/IntelFrameworkModulePkg/Universal/FirmwareVolume/FwVolDxe/FwVol.c

825 lines
25 KiB
C

/** @file
Firmware File System driver that produce full Firmware Volume2 protocol.
Layers on top of Firmware Block protocol to produce a file abstraction
of FV based files.
Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include "FwVolDriver.h"
#define KEYSIZE sizeof (UINTN)
/**
Given the supplied FW_VOL_BLOCK_PROTOCOL, allocate a buffer for output and
copy the real length volume header into it.
@param Fvb The FW_VOL_BLOCK_PROTOCOL instance from which to
read the volume header
@param FwVolHeader Pointer to pointer to allocated buffer in which
the volume header is returned.
@retval EFI_OUT_OF_RESOURCES No enough buffer could be allocated.
@retval EFI_SUCCESS Successfully read volume header to the allocated
buffer.
@retval EFI_ACCESS_DENIED Read status of FV is not enabled.
@retval EFI_INVALID_PARAMETER The FV Header signature is not as expected or
the file system could not be understood.
**/
EFI_STATUS
GetFwVolHeader (
IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb,
OUT EFI_FIRMWARE_VOLUME_HEADER **FwVolHeader
)
{
EFI_STATUS Status;
EFI_FIRMWARE_VOLUME_HEADER TempFvh;
EFI_FVB_ATTRIBUTES_2 FvbAttributes;
UINTN FvhLength;
EFI_PHYSICAL_ADDRESS BaseAddress;
//
// Determine the real length of FV header
//
Status = Fvb->GetAttributes (
Fvb,
&FvbAttributes
);
if (EFI_ERROR (Status)) {
return Status;
}
if ((FvbAttributes & EFI_FVB2_READ_STATUS) == 0) {
return EFI_ACCESS_DENIED;
}
//
// Just avoid compiling warning
//
BaseAddress = 0;
FvhLength = sizeof (EFI_FIRMWARE_VOLUME_HEADER);
//
// memory-mapped FV and non memory-mapped has different ways to read
//
if ((FvbAttributes & EFI_FVB2_MEMORY_MAPPED) != 0) {
Status = Fvb->GetPhysicalAddress (
Fvb,
&BaseAddress
);
if (EFI_ERROR (Status)) {
return Status;
}
CopyMem (&TempFvh, (VOID *) (UINTN) BaseAddress, FvhLength);
} else {
Status = Fvb->Read (
Fvb,
0,
0,
&FvhLength,
(UINT8 *) &TempFvh
);
}
//
// Validate FV Header signature, if not as expected, continue.
//
if (TempFvh.Signature != EFI_FVH_SIGNATURE) {
return EFI_INVALID_PARAMETER;
}
//
// Check to see that the file system is indeed formatted in a way we can
// understand it...
//
if ((!CompareGuid (&TempFvh.FileSystemGuid, &gEfiFirmwareFileSystem2Guid)) &&
(!CompareGuid (&TempFvh.FileSystemGuid, &gEfiFirmwareFileSystem3Guid))) {
return EFI_INVALID_PARAMETER;
}
*FwVolHeader = AllocatePool (TempFvh.HeaderLength);
if (*FwVolHeader == NULL) {
return EFI_OUT_OF_RESOURCES;
}
//
// Read the whole header
//
if ((FvbAttributes & EFI_FVB2_MEMORY_MAPPED) != 0) {
CopyMem (*FwVolHeader, (VOID *) (UINTN) BaseAddress, TempFvh.HeaderLength);
} else {
//
// Assumed the first block is bigger than the length of Fv headder
//
FvhLength = TempFvh.HeaderLength;
Status = Fvb->Read (
Fvb,
0,
0,
&FvhLength,
(UINT8 *) *FwVolHeader
);
//
// Check whether Read successes.
//
if (EFI_ERROR (Status)) {
FreePool (*FwVolHeader);
*FwVolHeader = NULL;
return Status;
}
}
return EFI_SUCCESS;
}
/**
Free FvDevice resource when error happens.
@param FvDevice Pointer to the FvDevice to be freed.
**/
VOID
FreeFvDeviceResource (
IN FV_DEVICE *FvDevice
)
{
LBA_ENTRY *LbaEntry;
FREE_SPACE_ENTRY *FreeSpaceEntry;
FFS_FILE_LIST_ENTRY *FfsFileEntry;
LIST_ENTRY *NextEntry;
//
// Free LAB Entry
//
LbaEntry = (LBA_ENTRY *) FvDevice->LbaHeader.ForwardLink;
while (&LbaEntry->Link != &FvDevice->LbaHeader) {
NextEntry = (&LbaEntry->Link)->ForwardLink;
FreePool (LbaEntry);
LbaEntry = (LBA_ENTRY *) NextEntry;
}
//
// Free File List Entry
//
FfsFileEntry = (FFS_FILE_LIST_ENTRY *) FvDevice->FfsFileListHeader.ForwardLink;
while (&FfsFileEntry->Link != &FvDevice->FfsFileListHeader) {
NextEntry = (&FfsFileEntry->Link)->ForwardLink;
FreePool (FfsFileEntry);
FfsFileEntry = (FFS_FILE_LIST_ENTRY *) NextEntry;
}
//
// Free Space Entry
//
FreeSpaceEntry = (FREE_SPACE_ENTRY *) FvDevice->FreeSpaceHeader.ForwardLink;
while (&FreeSpaceEntry->Link != &FvDevice->FreeSpaceHeader) {
NextEntry = (&FreeSpaceEntry->Link)->ForwardLink;
FreePool (FreeSpaceEntry);
FreeSpaceEntry = (FREE_SPACE_ENTRY *) NextEntry;
}
//
// Free the cache
//
FreePool ((UINT8 *) (UINTN) FvDevice->CachedFv);
return ;
}
/**
Firmware volume inherits authentication status from the FV image file and section(in another firmware volume)
where it came from or propagated from PEI-phase.
@param FvDevice A pointer to the FvDevice.
**/
VOID
FwVolInheritAuthenticationStatus (
IN FV_DEVICE *FvDevice
)
{
EFI_STATUS Status;
EFI_FIRMWARE_VOLUME_HEADER *CachedFvHeader;
EFI_FIRMWARE_VOLUME_EXT_HEADER *CachedFvExtHeader;
EFI_FIRMWARE_VOLUME2_PROTOCOL *ParentFvProtocol;
UINTN Key;
EFI_GUID FileNameGuid;
EFI_FV_FILETYPE FileType;
EFI_FV_FILE_ATTRIBUTES FileAttributes;
UINTN FileSize;
EFI_SECTION_TYPE SectionType;
UINT32 AuthenticationStatus;
EFI_FIRMWARE_VOLUME_HEADER *FvHeader;
EFI_FIRMWARE_VOLUME_EXT_HEADER *FvExtHeader;
UINTN BufferSize;
EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;
EFI_FVB_ATTRIBUTES_2 FvbAttributes;
EFI_PHYSICAL_ADDRESS BaseAddress;
EFI_PEI_HOB_POINTERS Fv3Hob;
if (FvDevice->Fv.ParentHandle != NULL) {
CachedFvHeader = (EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) FvDevice->CachedFv;
//
// By Parent Handle, find out the FV image file and section(in another firmware volume) where the firmware volume came from
//
Status = gBS->HandleProtocol (FvDevice->Fv.ParentHandle, &gEfiFirmwareVolume2ProtocolGuid, (VOID **) &ParentFvProtocol);
if (!EFI_ERROR (Status) && (ParentFvProtocol != NULL)) {
Key = 0;
do {
FileType = EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE;
Status = ParentFvProtocol->GetNextFile (
ParentFvProtocol,
&Key,
&FileType,
&FileNameGuid,
&FileAttributes,
&FileSize
);
if (EFI_ERROR (Status)) {
return;
}
SectionType = EFI_SECTION_FIRMWARE_VOLUME_IMAGE;
FvHeader = NULL;
BufferSize = 0;
Status = ParentFvProtocol->ReadSection (
ParentFvProtocol,
&FileNameGuid,
SectionType,
0,
(VOID **) &FvHeader,
&BufferSize,
&AuthenticationStatus
);
if (!EFI_ERROR (Status)) {
if ((FvHeader->FvLength == CachedFvHeader->FvLength) &&
(FvHeader->ExtHeaderOffset == CachedFvHeader->ExtHeaderOffset)) {
if (FvHeader->ExtHeaderOffset != 0) {
//
// Both FVs contain extension header, then compare their FV Name GUID
//
FvExtHeader = (EFI_FIRMWARE_VOLUME_EXT_HEADER *) ((UINTN) FvHeader + FvHeader->ExtHeaderOffset);
CachedFvExtHeader = (EFI_FIRMWARE_VOLUME_EXT_HEADER *) ((UINTN) CachedFvHeader + CachedFvHeader->ExtHeaderOffset);
if (CompareGuid (&FvExtHeader->FvName, &CachedFvExtHeader->FvName)) {
//
// Found the FV image section where the firmware volume came from,
// and then inherit authentication status from it.
//
FvDevice->AuthenticationStatus = AuthenticationStatus;
FreePool ((VOID *) FvHeader);
return;
}
} else {
//
// Both FVs don't contain extension header, then compare their whole FV Image.
//
if (CompareMem ((VOID *) FvHeader, (VOID *) CachedFvHeader, (UINTN) FvHeader->FvLength) == 0) {
//
// Found the FV image section where the firmware volume came from
// and then inherit authentication status from it.
//
FvDevice->AuthenticationStatus = AuthenticationStatus;
FreePool ((VOID *) FvHeader);
return;
}
}
}
FreePool ((VOID *) FvHeader);
}
} while (TRUE);
}
} else {
Fvb = FvDevice->Fvb;
Status = Fvb->GetAttributes (Fvb, &FvbAttributes);
if (EFI_ERROR (Status)) {
return;
}
if ((FvbAttributes & EFI_FVB2_MEMORY_MAPPED) != 0) {
//
// Get volume base address
//
Status = Fvb->GetPhysicalAddress (Fvb, &BaseAddress);
if (EFI_ERROR (Status)) {
return;
}
//
// Get the authentication status propagated from PEI-phase to DXE.
//
Fv3Hob.Raw = GetHobList ();
while ((Fv3Hob.Raw = GetNextHob (EFI_HOB_TYPE_FV3, Fv3Hob.Raw)) != NULL) {
if (Fv3Hob.FirmwareVolume3->BaseAddress == BaseAddress) {
FvDevice->AuthenticationStatus = Fv3Hob.FirmwareVolume3->AuthenticationStatus;
return;
}
Fv3Hob.Raw = GET_NEXT_HOB (Fv3Hob);
}
}
}
}
/**
Check if an FV is consistent and allocate cache for it.
@param FvDevice A pointer to the FvDevice to be checked.
@retval EFI_OUT_OF_RESOURCES No enough buffer could be allocated.
@retval EFI_VOLUME_CORRUPTED File system is corrupted.
@retval EFI_SUCCESS FV is consistent and cache is allocated.
**/
EFI_STATUS
FvCheck (
IN FV_DEVICE *FvDevice
)
{
EFI_STATUS Status;
EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;
EFI_FVB_ATTRIBUTES_2 FvbAttributes;
EFI_FV_BLOCK_MAP_ENTRY *BlockMap;
EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;
EFI_FIRMWARE_VOLUME_EXT_HEADER *FwVolExtHeader;
UINT8 *FwCache;
LBA_ENTRY *LbaEntry;
FREE_SPACE_ENTRY *FreeSpaceEntry;
FFS_FILE_LIST_ENTRY *FfsFileEntry;
UINT8 *LbaStart;
UINTN Index;
EFI_LBA LbaIndex;
UINT8 *Ptr;
UINTN Size;
UINT8 *FreeStart;
UINTN FreeSize;
UINT8 ErasePolarity;
EFI_FFS_FILE_STATE FileState;
UINT8 *TopFvAddress;
UINTN TestLength;
EFI_PHYSICAL_ADDRESS BaseAddress;
Fvb = FvDevice->Fvb;
Status = Fvb->GetAttributes (Fvb, &FvbAttributes);
if (EFI_ERROR (Status)) {
return Status;
}
InitializeListHead (&FvDevice->LbaHeader);
InitializeListHead (&FvDevice->FreeSpaceHeader);
InitializeListHead (&FvDevice->FfsFileListHeader);
FwVolHeader = NULL;
Status = GetFwVolHeader (Fvb, &FwVolHeader);
if (EFI_ERROR (Status)) {
return Status;
}
ASSERT (FwVolHeader != NULL);
FvDevice->IsFfs3Fv = CompareGuid (&FwVolHeader->FileSystemGuid, &gEfiFirmwareFileSystem3Guid);
//
// Double Check firmware volume header here
//
if (!VerifyFvHeaderChecksum (FwVolHeader)) {
FreePool (FwVolHeader);
return EFI_VOLUME_CORRUPTED;
}
BlockMap = FwVolHeader->BlockMap;
//
// FwVolHeader->FvLength is the whole FV length including FV header
//
FwCache = AllocateZeroPool ((UINTN) FwVolHeader->FvLength);
if (FwCache == NULL) {
FreePool (FwVolHeader);
return EFI_OUT_OF_RESOURCES;
}
FvDevice->CachedFv = (EFI_PHYSICAL_ADDRESS) (UINTN) FwCache;
//
// Copy to memory
//
LbaStart = FwCache;
LbaIndex = 0;
Ptr = NULL;
if ((FvbAttributes & EFI_FVB2_MEMORY_MAPPED) != 0) {
//
// Get volume base address
//
Status = Fvb->GetPhysicalAddress (Fvb, &BaseAddress);
if (EFI_ERROR (Status)) {
FreePool (FwVolHeader);
return Status;
}
Ptr = (UINT8 *) ((UINTN) BaseAddress);
DEBUG((EFI_D_INFO, "Fv Base Address is 0x%LX\n", BaseAddress));
}
//
// Copy whole FV into the memory
//
while ((BlockMap->NumBlocks != 0) || (BlockMap->Length != 0)) {
for (Index = 0; Index < BlockMap->NumBlocks; Index++) {
LbaEntry = AllocatePool (sizeof (LBA_ENTRY));
if (LbaEntry == NULL) {
FreePool (FwVolHeader);
FreeFvDeviceResource (FvDevice);
return EFI_OUT_OF_RESOURCES;
}
LbaEntry->LbaIndex = LbaIndex;
LbaEntry->StartingAddress = LbaStart;
LbaEntry->BlockLength = BlockMap->Length;
//
// Copy each LBA into memory
//
if ((FvbAttributes & EFI_FVB2_MEMORY_MAPPED) != 0) {
CopyMem (LbaStart, Ptr, BlockMap->Length);
Ptr += BlockMap->Length;
} else {
Size = BlockMap->Length;
Status = Fvb->Read (
Fvb,
LbaIndex,
0,
&Size,
LbaStart
);
//
// Not check EFI_BAD_BUFFER_SIZE, for Size = BlockMap->Length
//
if (EFI_ERROR (Status)) {
FreePool (FwVolHeader);
FreeFvDeviceResource (FvDevice);
return Status;
}
}
LbaIndex++;
LbaStart += BlockMap->Length;
InsertTailList (&FvDevice->LbaHeader, &LbaEntry->Link);
}
BlockMap++;
}
FvDevice->FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) FwCache;
//
// it is not used any more, so free FwVolHeader
//
FreePool (FwVolHeader);
//
// Scan to check the free space & File list
//
if ((FvbAttributes & EFI_FVB2_ERASE_POLARITY) != 0) {
ErasePolarity = 1;
} else {
ErasePolarity = 0;
}
FvDevice->ErasePolarity = ErasePolarity;
//
// go through the whole FV cache, check the consistence of the FV
//
if (FvDevice->FwVolHeader->ExtHeaderOffset != 0) {
//
// Searching for files starts on an 8 byte aligned boundary after the end of the Extended Header if it exists.
//
FwVolExtHeader = (EFI_FIRMWARE_VOLUME_EXT_HEADER *) (UINTN) (FvDevice->CachedFv + FvDevice->FwVolHeader->ExtHeaderOffset);
Ptr = (UINT8 *) FwVolExtHeader + FwVolExtHeader->ExtHeaderSize;
} else {
Ptr = (UINT8 *) (UINTN) (FvDevice->CachedFv + FvDevice->FwVolHeader->HeaderLength);
}
Ptr = (UINT8 *) ALIGN_POINTER (Ptr, 8);
TopFvAddress = (UINT8 *) (UINTN) (FvDevice->CachedFv + FvDevice->FwVolHeader->FvLength);
//
// Build FFS list & Free Space List here
//
while (Ptr < TopFvAddress) {
TestLength = TopFvAddress - Ptr;
if (TestLength > sizeof (EFI_FFS_FILE_HEADER)) {
TestLength = sizeof (EFI_FFS_FILE_HEADER);
}
if (IsBufferErased (ErasePolarity, Ptr, TestLength)) {
//
// We found free space
//
FreeStart = Ptr;
FreeSize = 0;
do {
TestLength = TopFvAddress - Ptr;
if (TestLength > sizeof (EFI_FFS_FILE_HEADER)) {
TestLength = sizeof (EFI_FFS_FILE_HEADER);
}
if (!IsBufferErased (ErasePolarity, Ptr, TestLength)) {
break;
}
FreeSize += TestLength;
Ptr += TestLength;
} while (Ptr < TopFvAddress);
FreeSpaceEntry = AllocateZeroPool (sizeof (FREE_SPACE_ENTRY));
if (FreeSpaceEntry == NULL) {
FreeFvDeviceResource (FvDevice);
return EFI_OUT_OF_RESOURCES;
}
//
// Create a Free space entry
//
FreeSpaceEntry->StartingAddress = FreeStart;
FreeSpaceEntry->Length = FreeSize;
InsertTailList (&FvDevice->FreeSpaceHeader, &FreeSpaceEntry->Link);
continue;
}
//
// double check boundary
//
if (TestLength < sizeof (EFI_FFS_FILE_HEADER)) {
break;
}
if (!IsValidFFSHeader (
FvDevice->ErasePolarity,
(EFI_FFS_FILE_HEADER *) Ptr
)) {
FileState = GetFileState (
FvDevice->ErasePolarity,
(EFI_FFS_FILE_HEADER *) Ptr
);
if ((FileState == EFI_FILE_HEADER_INVALID) || (FileState == EFI_FILE_HEADER_CONSTRUCTION)) {
if (IS_FFS_FILE2 (Ptr)) {
if (!FvDevice->IsFfs3Fv) {
DEBUG ((EFI_D_ERROR, "Found a FFS3 formatted file: %g in a non-FFS3 formatted FV.\n", &((EFI_FFS_FILE_HEADER *) Ptr)->Name));
}
Ptr = Ptr + sizeof (EFI_FFS_FILE_HEADER2);
} else {
Ptr = Ptr + sizeof (EFI_FFS_FILE_HEADER);
}
continue;
} else {
//
// File system is corrputed, return
//
FreeFvDeviceResource (FvDevice);
return EFI_VOLUME_CORRUPTED;
}
}
if (IS_FFS_FILE2 (Ptr)) {
ASSERT (FFS_FILE2_SIZE (Ptr) > 0x00FFFFFF);
if (!FvDevice->IsFfs3Fv) {
DEBUG ((EFI_D_ERROR, "Found a FFS3 formatted file: %g in a non-FFS3 formatted FV.\n", &((EFI_FFS_FILE_HEADER *) Ptr)->Name));
Ptr = Ptr + FFS_FILE2_SIZE (Ptr);
//
// Adjust Ptr to the next 8-byte aligned boundary.
//
while (((UINTN) Ptr & 0x07) != 0) {
Ptr++;
}
continue;
}
}
if (IsValidFFSFile (FvDevice, (EFI_FFS_FILE_HEADER *) Ptr)) {
FileState = GetFileState (
FvDevice->ErasePolarity,
(EFI_FFS_FILE_HEADER *) Ptr
);
//
// check for non-deleted file
//
if (FileState != EFI_FILE_DELETED) {
//
// Create a FFS list entry for each non-deleted file
//
FfsFileEntry = AllocateZeroPool (sizeof (FFS_FILE_LIST_ENTRY));
if (FfsFileEntry == NULL) {
FreeFvDeviceResource (FvDevice);
return EFI_OUT_OF_RESOURCES;
}
FfsFileEntry->FfsHeader = Ptr;
InsertTailList (&FvDevice->FfsFileListHeader, &FfsFileEntry->Link);
}
if (IS_FFS_FILE2 (Ptr)) {
Ptr = Ptr + FFS_FILE2_SIZE (Ptr);
} else {
Ptr = Ptr + FFS_FILE_SIZE (Ptr);
}
//
// Adjust Ptr to the next 8-byte aligned boundary.
//
while (((UINTN) Ptr & 0x07) != 0) {
Ptr++;
}
} else {
//
// File system is corrupted, return
//
FreeFvDeviceResource (FvDevice);
return EFI_VOLUME_CORRUPTED;
}
}
FvDevice->CurrentFfsFile = NULL;
return EFI_SUCCESS;
}
/**
Entry point function does install/reinstall FV2 protocol with full functionality.
@param ImageHandle A handle for the image that is initializing this driver
@param SystemTable A pointer to the EFI system table
@retval EFI_SUCCESS At least one Fv protocol install/reinstall successfully.
@retval EFI_NOT_FOUND No FV protocol install/reinstall successfully.
**/
EFI_STATUS
EFIAPI
FwVolDriverInit (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
EFI_STATUS Status;
EFI_HANDLE *HandleBuffer;
UINTN HandleCount;
UINTN Index;
EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;
EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv;
FV_DEVICE *FvDevice;
EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;
BOOLEAN Reinstall;
BOOLEAN InstallFlag;
DEBUG ((EFI_D_INFO, "=========FwVol writable driver installed\n"));
InstallFlag = FALSE;
//
// Locate all handles of Fvb protocol
//
Status = gBS->LocateHandleBuffer (
ByProtocol,
&gEfiFirmwareVolumeBlockProtocolGuid,
NULL,
&HandleCount,
&HandleBuffer
);
if (EFI_ERROR (Status)) {
return EFI_NOT_FOUND;
}
for (Index = 0; Index < HandleCount; Index += 1) {
Status = gBS->HandleProtocol (
HandleBuffer[Index],
&gEfiFirmwareVolumeBlockProtocolGuid,
(VOID **) &Fvb
);
if (EFI_ERROR (Status)) {
continue;
}
FwVolHeader = NULL;
Status = GetFwVolHeader (Fvb, &FwVolHeader);
if (EFI_ERROR (Status)) {
continue;
}
ASSERT (FwVolHeader != NULL);
FreePool (FwVolHeader);
Reinstall = FALSE;
//
// Check if there is an FV protocol already installed in that handle
//
Status = gBS->HandleProtocol (
HandleBuffer[Index],
&gEfiFirmwareVolume2ProtocolGuid,
(VOID **) &Fv
);
if (!EFI_ERROR (Status)) {
Reinstall = TRUE;
}
//
// FwVol protocol on the handle so create a new one
//
FvDevice = AllocateZeroPool (sizeof (FV_DEVICE));
if (FvDevice == NULL) {
goto Done;
}
FvDevice->Signature = FV_DEVICE_SIGNATURE;
FvDevice->Fvb = Fvb;
//
// Firmware Volume Protocol interface
//
FvDevice->Fv.GetVolumeAttributes = FvGetVolumeAttributes;
FvDevice->Fv.SetVolumeAttributes = FvSetVolumeAttributes;
FvDevice->Fv.ReadFile = FvReadFile;
FvDevice->Fv.ReadSection = FvReadFileSection;
FvDevice->Fv.WriteFile = FvWriteFile;
FvDevice->Fv.GetNextFile = FvGetNextFile;
FvDevice->Fv.KeySize = KEYSIZE;
FvDevice->Fv.GetInfo = FvGetVolumeInfo;
FvDevice->Fv.SetInfo = FvSetVolumeInfo;
FvDevice->Fv.ParentHandle = Fvb->ParentHandle;
Status = FvCheck (FvDevice);
if (EFI_ERROR (Status)) {
//
// The file system is not consistence
//
FreePool (FvDevice);
continue;
}
FwVolInheritAuthenticationStatus (FvDevice);
if (Reinstall) {
//
// Reinstall an New FV protocol
//
// FvDevice = FV_DEVICE_FROM_THIS (Fv);
// FvDevice->Fvb = Fvb;
// FreeFvDeviceResource (FvDevice);
//
Status = gBS->ReinstallProtocolInterface (
HandleBuffer[Index],
&gEfiFirmwareVolume2ProtocolGuid,
Fv,
&FvDevice->Fv
);
if (!EFI_ERROR (Status)) {
InstallFlag = TRUE;
} else {
FreePool (FvDevice);
}
DEBUG ((EFI_D_INFO, "Reinstall FV protocol as writable - %r\n", Status));
ASSERT_EFI_ERROR (Status);
} else {
//
// Install an New FV protocol
//
Status = gBS->InstallProtocolInterface (
&FvDevice->Handle,
&gEfiFirmwareVolume2ProtocolGuid,
EFI_NATIVE_INTERFACE,
&FvDevice->Fv
);
if (!EFI_ERROR (Status)) {
InstallFlag = TRUE;
} else {
FreePool (FvDevice);
}
DEBUG ((EFI_D_INFO, "Install FV protocol as writable - %r\n", Status));
ASSERT_EFI_ERROR (Status);
}
}
Done:
//
// As long as one Fv protocol install/reinstall successfully,
// success should return to ensure this image will be not unloaded.
// Otherwise, new Fv protocols are corrupted by other loaded driver.
//
if (InstallFlag) {
return EFI_SUCCESS;
}
//
// No FV protocol install/reinstall successfully.
// EFI_NOT_FOUND should return to ensure this image will be unloaded.
//
return EFI_NOT_FOUND;
}