3 Firmware File System driver that produce full Firmware Volume2 protocol.
4 Layers on top of Firmware Block protocol to produce a file abstraction
7 Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
9 SPDX-License-Identifier: BSD-2-Clause-Patent
13 #include "FwVolDriver.h"
15 #define KEYSIZE sizeof (UINTN)
18 Given the supplied FW_VOL_BLOCK_PROTOCOL, allocate a buffer for output and
19 copy the real length volume header into it.
21 @param Fvb The FW_VOL_BLOCK_PROTOCOL instance from which to
22 read the volume header
23 @param FwVolHeader Pointer to pointer to allocated buffer in which
24 the volume header is returned.
26 @retval EFI_OUT_OF_RESOURCES No enough buffer could be allocated.
27 @retval EFI_SUCCESS Successfully read volume header to the allocated
29 @retval EFI_ACCESS_DENIED Read status of FV is not enabled.
30 @retval EFI_INVALID_PARAMETER The FV Header signature is not as expected or
31 the file system could not be understood.
35 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*Fvb
,
36 OUT EFI_FIRMWARE_VOLUME_HEADER
**FwVolHeader
40 EFI_FIRMWARE_VOLUME_HEADER TempFvh
;
41 EFI_FVB_ATTRIBUTES_2 FvbAttributes
;
43 EFI_PHYSICAL_ADDRESS BaseAddress
;
46 // Determine the real length of FV header
48 Status
= Fvb
->GetAttributes (
52 if (EFI_ERROR (Status
)) {
56 if ((FvbAttributes
& EFI_FVB2_READ_STATUS
) == 0) {
57 return EFI_ACCESS_DENIED
;
61 // Just avoid compiling warning
64 FvhLength
= sizeof (EFI_FIRMWARE_VOLUME_HEADER
);
67 // memory-mapped FV and non memory-mapped has different ways to read
69 if ((FvbAttributes
& EFI_FVB2_MEMORY_MAPPED
) != 0) {
70 Status
= Fvb
->GetPhysicalAddress (
74 if (EFI_ERROR (Status
)) {
77 CopyMem (&TempFvh
, (VOID
*) (UINTN
) BaseAddress
, FvhLength
);
89 // Validate FV Header signature, if not as expected, continue.
91 if (TempFvh
.Signature
!= EFI_FVH_SIGNATURE
) {
92 return EFI_INVALID_PARAMETER
;
96 // Check to see that the file system is indeed formatted in a way we can
99 if ((!CompareGuid (&TempFvh
.FileSystemGuid
, &gEfiFirmwareFileSystem2Guid
)) &&
100 (!CompareGuid (&TempFvh
.FileSystemGuid
, &gEfiFirmwareFileSystem3Guid
))) {
101 return EFI_INVALID_PARAMETER
;
104 *FwVolHeader
= AllocatePool (TempFvh
.HeaderLength
);
105 if (*FwVolHeader
== NULL
) {
106 return EFI_OUT_OF_RESOURCES
;
109 // Read the whole header
111 if ((FvbAttributes
& EFI_FVB2_MEMORY_MAPPED
) != 0) {
112 CopyMem (*FwVolHeader
, (VOID
*) (UINTN
) BaseAddress
, TempFvh
.HeaderLength
);
115 // Assumed the first block is bigger than the length of Fv headder
117 FvhLength
= TempFvh
.HeaderLength
;
123 (UINT8
*) *FwVolHeader
126 // Check whether Read successes.
128 if (EFI_ERROR (Status
)) {
129 FreePool (*FwVolHeader
);
139 Free FvDevice resource when error happens.
141 @param FvDevice Pointer to the FvDevice to be freed.
144 FreeFvDeviceResource (
145 IN FV_DEVICE
*FvDevice
149 FREE_SPACE_ENTRY
*FreeSpaceEntry
;
150 FFS_FILE_LIST_ENTRY
*FfsFileEntry
;
151 LIST_ENTRY
*NextEntry
;
156 LbaEntry
= (LBA_ENTRY
*) FvDevice
->LbaHeader
.ForwardLink
;
157 while (&LbaEntry
->Link
!= &FvDevice
->LbaHeader
) {
158 NextEntry
= (&LbaEntry
->Link
)->ForwardLink
;
160 LbaEntry
= (LBA_ENTRY
*) NextEntry
;
163 // Free File List Entry
165 FfsFileEntry
= (FFS_FILE_LIST_ENTRY
*) FvDevice
->FfsFileListHeader
.ForwardLink
;
166 while (&FfsFileEntry
->Link
!= &FvDevice
->FfsFileListHeader
) {
167 NextEntry
= (&FfsFileEntry
->Link
)->ForwardLink
;
168 FreePool (FfsFileEntry
);
169 FfsFileEntry
= (FFS_FILE_LIST_ENTRY
*) NextEntry
;
174 FreeSpaceEntry
= (FREE_SPACE_ENTRY
*) FvDevice
->FreeSpaceHeader
.ForwardLink
;
175 while (&FreeSpaceEntry
->Link
!= &FvDevice
->FreeSpaceHeader
) {
176 NextEntry
= (&FreeSpaceEntry
->Link
)->ForwardLink
;
177 FreePool (FreeSpaceEntry
);
178 FreeSpaceEntry
= (FREE_SPACE_ENTRY
*) NextEntry
;
183 FreePool ((UINT8
*) (UINTN
) FvDevice
->CachedFv
);
190 Firmware volume inherits authentication status from the FV image file and section(in another firmware volume)
191 where it came from or propagated from PEI-phase.
193 @param FvDevice A pointer to the FvDevice.
197 FwVolInheritAuthenticationStatus (
198 IN FV_DEVICE
*FvDevice
202 EFI_FIRMWARE_VOLUME_HEADER
*CachedFvHeader
;
203 EFI_FIRMWARE_VOLUME_EXT_HEADER
*CachedFvExtHeader
;
204 EFI_FIRMWARE_VOLUME2_PROTOCOL
*ParentFvProtocol
;
206 EFI_GUID FileNameGuid
;
207 EFI_FV_FILETYPE FileType
;
208 EFI_FV_FILE_ATTRIBUTES FileAttributes
;
210 EFI_SECTION_TYPE SectionType
;
211 UINT32 AuthenticationStatus
;
212 EFI_FIRMWARE_VOLUME_HEADER
*FvHeader
;
213 EFI_FIRMWARE_VOLUME_EXT_HEADER
*FvExtHeader
;
215 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*Fvb
;
216 EFI_FVB_ATTRIBUTES_2 FvbAttributes
;
217 EFI_PHYSICAL_ADDRESS BaseAddress
;
218 EFI_PEI_HOB_POINTERS Fv3Hob
;
220 if (FvDevice
->Fv
.ParentHandle
!= NULL
) {
221 CachedFvHeader
= (EFI_FIRMWARE_VOLUME_HEADER
*) (UINTN
) FvDevice
->CachedFv
;
224 // By Parent Handle, find out the FV image file and section(in another firmware volume) where the firmware volume came from
226 Status
= gBS
->HandleProtocol (FvDevice
->Fv
.ParentHandle
, &gEfiFirmwareVolume2ProtocolGuid
, (VOID
**) &ParentFvProtocol
);
227 if (!EFI_ERROR (Status
) && (ParentFvProtocol
!= NULL
)) {
230 FileType
= EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE
;
231 Status
= ParentFvProtocol
->GetNextFile (
239 if (EFI_ERROR (Status
)) {
243 SectionType
= EFI_SECTION_FIRMWARE_VOLUME_IMAGE
;
246 Status
= ParentFvProtocol
->ReadSection (
253 &AuthenticationStatus
255 if (!EFI_ERROR (Status
)) {
256 if ((FvHeader
->FvLength
== CachedFvHeader
->FvLength
) &&
257 (FvHeader
->ExtHeaderOffset
== CachedFvHeader
->ExtHeaderOffset
)) {
258 if (FvHeader
->ExtHeaderOffset
!= 0) {
260 // Both FVs contain extension header, then compare their FV Name GUID
262 FvExtHeader
= (EFI_FIRMWARE_VOLUME_EXT_HEADER
*) ((UINTN
) FvHeader
+ FvHeader
->ExtHeaderOffset
);
263 CachedFvExtHeader
= (EFI_FIRMWARE_VOLUME_EXT_HEADER
*) ((UINTN
) CachedFvHeader
+ CachedFvHeader
->ExtHeaderOffset
);
264 if (CompareGuid (&FvExtHeader
->FvName
, &CachedFvExtHeader
->FvName
)) {
266 // Found the FV image section where the firmware volume came from,
267 // and then inherit authentication status from it.
269 FvDevice
->AuthenticationStatus
= AuthenticationStatus
;
270 FreePool ((VOID
*) FvHeader
);
275 // Both FVs don't contain extension header, then compare their whole FV Image.
277 if (CompareMem ((VOID
*) FvHeader
, (VOID
*) CachedFvHeader
, (UINTN
) FvHeader
->FvLength
) == 0) {
279 // Found the FV image section where the firmware volume came from
280 // and then inherit authentication status from it.
282 FvDevice
->AuthenticationStatus
= AuthenticationStatus
;
283 FreePool ((VOID
*) FvHeader
);
288 FreePool ((VOID
*) FvHeader
);
295 Status
= Fvb
->GetAttributes (Fvb
, &FvbAttributes
);
296 if (EFI_ERROR (Status
)) {
300 if ((FvbAttributes
& EFI_FVB2_MEMORY_MAPPED
) != 0) {
302 // Get volume base address
304 Status
= Fvb
->GetPhysicalAddress (Fvb
, &BaseAddress
);
305 if (EFI_ERROR (Status
)) {
310 // Get the authentication status propagated from PEI-phase to DXE.
312 Fv3Hob
.Raw
= GetHobList ();
313 while ((Fv3Hob
.Raw
= GetNextHob (EFI_HOB_TYPE_FV3
, Fv3Hob
.Raw
)) != NULL
) {
314 if (Fv3Hob
.FirmwareVolume3
->BaseAddress
== BaseAddress
) {
315 FvDevice
->AuthenticationStatus
= Fv3Hob
.FirmwareVolume3
->AuthenticationStatus
;
318 Fv3Hob
.Raw
= GET_NEXT_HOB (Fv3Hob
);
325 Check if an FV is consistent and allocate cache for it.
327 @param FvDevice A pointer to the FvDevice to be checked.
329 @retval EFI_OUT_OF_RESOURCES No enough buffer could be allocated.
330 @retval EFI_VOLUME_CORRUPTED File system is corrupted.
331 @retval EFI_SUCCESS FV is consistent and cache is allocated.
336 IN FV_DEVICE
*FvDevice
340 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*Fvb
;
341 EFI_FVB_ATTRIBUTES_2 FvbAttributes
;
342 EFI_FV_BLOCK_MAP_ENTRY
*BlockMap
;
343 EFI_FIRMWARE_VOLUME_HEADER
*FwVolHeader
;
344 EFI_FIRMWARE_VOLUME_EXT_HEADER
*FwVolExtHeader
;
347 FREE_SPACE_ENTRY
*FreeSpaceEntry
;
348 FFS_FILE_LIST_ENTRY
*FfsFileEntry
;
357 EFI_FFS_FILE_STATE FileState
;
360 EFI_PHYSICAL_ADDRESS BaseAddress
;
364 Status
= Fvb
->GetAttributes (Fvb
, &FvbAttributes
);
365 if (EFI_ERROR (Status
)) {
369 InitializeListHead (&FvDevice
->LbaHeader
);
370 InitializeListHead (&FvDevice
->FreeSpaceHeader
);
371 InitializeListHead (&FvDevice
->FfsFileListHeader
);
374 Status
= GetFwVolHeader (Fvb
, &FwVolHeader
);
375 if (EFI_ERROR (Status
)) {
378 ASSERT (FwVolHeader
!= NULL
);
380 FvDevice
->IsFfs3Fv
= CompareGuid (&FwVolHeader
->FileSystemGuid
, &gEfiFirmwareFileSystem3Guid
);
383 // Double Check firmware volume header here
385 if (!VerifyFvHeaderChecksum (FwVolHeader
)) {
386 FreePool (FwVolHeader
);
387 return EFI_VOLUME_CORRUPTED
;
390 BlockMap
= FwVolHeader
->BlockMap
;
393 // FwVolHeader->FvLength is the whole FV length including FV header
395 FwCache
= AllocateZeroPool ((UINTN
) FwVolHeader
->FvLength
);
396 if (FwCache
== NULL
) {
397 FreePool (FwVolHeader
);
398 return EFI_OUT_OF_RESOURCES
;
401 FvDevice
->CachedFv
= (EFI_PHYSICAL_ADDRESS
) (UINTN
) FwCache
;
410 if ((FvbAttributes
& EFI_FVB2_MEMORY_MAPPED
) != 0) {
412 // Get volume base address
414 Status
= Fvb
->GetPhysicalAddress (Fvb
, &BaseAddress
);
415 if (EFI_ERROR (Status
)) {
416 FreePool (FwVolHeader
);
420 Ptr
= (UINT8
*) ((UINTN
) BaseAddress
);
422 DEBUG((EFI_D_INFO
, "Fv Base Address is 0x%LX\n", BaseAddress
));
425 // Copy whole FV into the memory
427 while ((BlockMap
->NumBlocks
!= 0) || (BlockMap
->Length
!= 0)) {
429 for (Index
= 0; Index
< BlockMap
->NumBlocks
; Index
++) {
430 LbaEntry
= AllocatePool (sizeof (LBA_ENTRY
));
431 if (LbaEntry
== NULL
) {
432 FreePool (FwVolHeader
);
433 FreeFvDeviceResource (FvDevice
);
434 return EFI_OUT_OF_RESOURCES
;
437 LbaEntry
->LbaIndex
= LbaIndex
;
438 LbaEntry
->StartingAddress
= LbaStart
;
439 LbaEntry
->BlockLength
= BlockMap
->Length
;
442 // Copy each LBA into memory
444 if ((FvbAttributes
& EFI_FVB2_MEMORY_MAPPED
) != 0) {
446 CopyMem (LbaStart
, Ptr
, BlockMap
->Length
);
447 Ptr
+= BlockMap
->Length
;
451 Size
= BlockMap
->Length
;
460 // Not check EFI_BAD_BUFFER_SIZE, for Size = BlockMap->Length
462 if (EFI_ERROR (Status
)) {
463 FreePool (FwVolHeader
);
464 FreeFvDeviceResource (FvDevice
);
471 LbaStart
+= BlockMap
->Length
;
473 InsertTailList (&FvDevice
->LbaHeader
, &LbaEntry
->Link
);
479 FvDevice
->FwVolHeader
= (EFI_FIRMWARE_VOLUME_HEADER
*) FwCache
;
482 // it is not used any more, so free FwVolHeader
484 FreePool (FwVolHeader
);
487 // Scan to check the free space & File list
489 if ((FvbAttributes
& EFI_FVB2_ERASE_POLARITY
) != 0) {
495 FvDevice
->ErasePolarity
= ErasePolarity
;
498 // go through the whole FV cache, check the consistence of the FV
500 if (FvDevice
->FwVolHeader
->ExtHeaderOffset
!= 0) {
502 // Searching for files starts on an 8 byte aligned boundary after the end of the Extended Header if it exists.
504 FwVolExtHeader
= (EFI_FIRMWARE_VOLUME_EXT_HEADER
*) (UINTN
) (FvDevice
->CachedFv
+ FvDevice
->FwVolHeader
->ExtHeaderOffset
);
505 Ptr
= (UINT8
*) FwVolExtHeader
+ FwVolExtHeader
->ExtHeaderSize
;
507 Ptr
= (UINT8
*) (UINTN
) (FvDevice
->CachedFv
+ FvDevice
->FwVolHeader
->HeaderLength
);
509 Ptr
= (UINT8
*) ALIGN_POINTER (Ptr
, 8);
510 TopFvAddress
= (UINT8
*) (UINTN
) (FvDevice
->CachedFv
+ FvDevice
->FwVolHeader
->FvLength
);
513 // Build FFS list & Free Space List here
515 while (Ptr
< TopFvAddress
) {
516 TestLength
= TopFvAddress
- Ptr
;
518 if (TestLength
> sizeof (EFI_FFS_FILE_HEADER
)) {
519 TestLength
= sizeof (EFI_FFS_FILE_HEADER
);
522 if (IsBufferErased (ErasePolarity
, Ptr
, TestLength
)) {
524 // We found free space
530 TestLength
= TopFvAddress
- Ptr
;
532 if (TestLength
> sizeof (EFI_FFS_FILE_HEADER
)) {
533 TestLength
= sizeof (EFI_FFS_FILE_HEADER
);
536 if (!IsBufferErased (ErasePolarity
, Ptr
, TestLength
)) {
540 FreeSize
+= TestLength
;
542 } while (Ptr
< TopFvAddress
);
544 FreeSpaceEntry
= AllocateZeroPool (sizeof (FREE_SPACE_ENTRY
));
545 if (FreeSpaceEntry
== NULL
) {
546 FreeFvDeviceResource (FvDevice
);
547 return EFI_OUT_OF_RESOURCES
;
550 // Create a Free space entry
552 FreeSpaceEntry
->StartingAddress
= FreeStart
;
553 FreeSpaceEntry
->Length
= FreeSize
;
554 InsertTailList (&FvDevice
->FreeSpaceHeader
, &FreeSpaceEntry
->Link
);
558 // double check boundary
560 if (TestLength
< sizeof (EFI_FFS_FILE_HEADER
)) {
564 if (!IsValidFFSHeader (
565 FvDevice
->ErasePolarity
,
566 (EFI_FFS_FILE_HEADER
*) Ptr
568 FileState
= GetFileState (
569 FvDevice
->ErasePolarity
,
570 (EFI_FFS_FILE_HEADER
*) Ptr
572 if ((FileState
== EFI_FILE_HEADER_INVALID
) || (FileState
== EFI_FILE_HEADER_CONSTRUCTION
)) {
573 if (IS_FFS_FILE2 (Ptr
)) {
574 if (!FvDevice
->IsFfs3Fv
) {
575 DEBUG ((EFI_D_ERROR
, "Found a FFS3 formatted file: %g in a non-FFS3 formatted FV.\n", &((EFI_FFS_FILE_HEADER
*) Ptr
)->Name
));
577 Ptr
= Ptr
+ sizeof (EFI_FFS_FILE_HEADER2
);
579 Ptr
= Ptr
+ sizeof (EFI_FFS_FILE_HEADER
);
586 // File system is corrputed, return
588 FreeFvDeviceResource (FvDevice
);
589 return EFI_VOLUME_CORRUPTED
;
593 if (IS_FFS_FILE2 (Ptr
)) {
594 ASSERT (FFS_FILE2_SIZE (Ptr
) > 0x00FFFFFF);
595 if (!FvDevice
->IsFfs3Fv
) {
596 DEBUG ((EFI_D_ERROR
, "Found a FFS3 formatted file: %g in a non-FFS3 formatted FV.\n", &((EFI_FFS_FILE_HEADER
*) Ptr
)->Name
));
597 Ptr
= Ptr
+ FFS_FILE2_SIZE (Ptr
);
599 // Adjust Ptr to the next 8-byte aligned boundary.
601 while (((UINTN
) Ptr
& 0x07) != 0) {
608 if (IsValidFFSFile (FvDevice
, (EFI_FFS_FILE_HEADER
*) Ptr
)) {
609 FileState
= GetFileState (
610 FvDevice
->ErasePolarity
,
611 (EFI_FFS_FILE_HEADER
*) Ptr
615 // check for non-deleted file
617 if (FileState
!= EFI_FILE_DELETED
) {
619 // Create a FFS list entry for each non-deleted file
621 FfsFileEntry
= AllocateZeroPool (sizeof (FFS_FILE_LIST_ENTRY
));
622 if (FfsFileEntry
== NULL
) {
623 FreeFvDeviceResource (FvDevice
);
624 return EFI_OUT_OF_RESOURCES
;
627 FfsFileEntry
->FfsHeader
= Ptr
;
628 InsertTailList (&FvDevice
->FfsFileListHeader
, &FfsFileEntry
->Link
);
631 if (IS_FFS_FILE2 (Ptr
)) {
632 Ptr
= Ptr
+ FFS_FILE2_SIZE (Ptr
);
634 Ptr
= Ptr
+ FFS_FILE_SIZE (Ptr
);
638 // Adjust Ptr to the next 8-byte aligned boundary.
640 while (((UINTN
) Ptr
& 0x07) != 0) {
645 // File system is corrupted, return
647 FreeFvDeviceResource (FvDevice
);
648 return EFI_VOLUME_CORRUPTED
;
652 FvDevice
->CurrentFfsFile
= NULL
;
658 Entry point function does install/reinstall FV2 protocol with full functionality.
660 @param ImageHandle A handle for the image that is initializing this driver
661 @param SystemTable A pointer to the EFI system table
663 @retval EFI_SUCCESS At least one Fv protocol install/reinstall successfully.
664 @retval EFI_NOT_FOUND No FV protocol install/reinstall successfully.
669 IN EFI_HANDLE ImageHandle
,
670 IN EFI_SYSTEM_TABLE
*SystemTable
674 EFI_HANDLE
*HandleBuffer
;
677 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*Fvb
;
678 EFI_FIRMWARE_VOLUME2_PROTOCOL
*Fv
;
680 EFI_FIRMWARE_VOLUME_HEADER
*FwVolHeader
;
684 DEBUG ((EFI_D_INFO
, "=========FwVol writable driver installed\n"));
687 // Locate all handles of Fvb protocol
689 Status
= gBS
->LocateHandleBuffer (
691 &gEfiFirmwareVolumeBlockProtocolGuid
,
696 if (EFI_ERROR (Status
)) {
697 return EFI_NOT_FOUND
;
700 for (Index
= 0; Index
< HandleCount
; Index
+= 1) {
701 Status
= gBS
->HandleProtocol (
703 &gEfiFirmwareVolumeBlockProtocolGuid
,
706 if (EFI_ERROR (Status
)) {
711 Status
= GetFwVolHeader (Fvb
, &FwVolHeader
);
712 if (EFI_ERROR (Status
)) {
715 ASSERT (FwVolHeader
!= NULL
);
716 FreePool (FwVolHeader
);
720 // Check if there is an FV protocol already installed in that handle
722 Status
= gBS
->HandleProtocol (
724 &gEfiFirmwareVolume2ProtocolGuid
,
727 if (!EFI_ERROR (Status
)) {
731 // FwVol protocol on the handle so create a new one
733 FvDevice
= AllocateZeroPool (sizeof (FV_DEVICE
));
734 if (FvDevice
== NULL
) {
738 FvDevice
->Signature
= FV_DEVICE_SIGNATURE
;
742 // Firmware Volume Protocol interface
744 FvDevice
->Fv
.GetVolumeAttributes
= FvGetVolumeAttributes
;
745 FvDevice
->Fv
.SetVolumeAttributes
= FvSetVolumeAttributes
;
746 FvDevice
->Fv
.ReadFile
= FvReadFile
;
747 FvDevice
->Fv
.ReadSection
= FvReadFileSection
;
748 FvDevice
->Fv
.WriteFile
= FvWriteFile
;
749 FvDevice
->Fv
.GetNextFile
= FvGetNextFile
;
750 FvDevice
->Fv
.KeySize
= KEYSIZE
;
751 FvDevice
->Fv
.GetInfo
= FvGetVolumeInfo
;
752 FvDevice
->Fv
.SetInfo
= FvSetVolumeInfo
;
753 FvDevice
->Fv
.ParentHandle
= Fvb
->ParentHandle
;
755 Status
= FvCheck (FvDevice
);
756 if (EFI_ERROR (Status
)) {
758 // The file system is not consistence
764 FwVolInheritAuthenticationStatus (FvDevice
);
768 // Reinstall an New FV protocol
770 // FvDevice = FV_DEVICE_FROM_THIS (Fv);
771 // FvDevice->Fvb = Fvb;
772 // FreeFvDeviceResource (FvDevice);
774 Status
= gBS
->ReinstallProtocolInterface (
776 &gEfiFirmwareVolume2ProtocolGuid
,
780 if (!EFI_ERROR (Status
)) {
786 DEBUG ((EFI_D_INFO
, "Reinstall FV protocol as writable - %r\n", Status
));
787 ASSERT_EFI_ERROR (Status
);
790 // Install an New FV protocol
792 Status
= gBS
->InstallProtocolInterface (
794 &gEfiFirmwareVolume2ProtocolGuid
,
795 EFI_NATIVE_INTERFACE
,
798 if (!EFI_ERROR (Status
)) {
804 DEBUG ((EFI_D_INFO
, "Install FV protocol as writable - %r\n", Status
));
805 ASSERT_EFI_ERROR (Status
);
811 // As long as one Fv protocol install/reinstall successfully,
812 // success should return to ensure this image will be not unloaded.
813 // Otherwise, new Fv protocols are corrupted by other loaded driver.
820 // No FV protocol install/reinstall successfully.
821 // EFI_NOT_FOUND should return to ensure this image will be unloaded.
823 return EFI_NOT_FOUND
;