2 Firmware File System driver that produce Firmware Volume protocol.
3 Layers on top of Firmware Block protocol to produce a file abstraction
6 Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
7 SPDX-License-Identifier: BSD-2-Clause-Patent
12 #include "FwVolDriver.h"
16 // Protocol notify related globals
18 VOID
*gEfiFwVolBlockNotifyReg
;
19 EFI_EVENT gEfiFwVolBlockEvent
;
21 FV_DEVICE mFvDevice
= {
26 FvGetVolumeAttributes
,
27 FvSetVolumeAttributes
,
50 // FFS helper functions
53 Read data from Firmware Block by FVB protocol Read.
54 The data may cross the multi block ranges.
56 @param Fvb The FW_VOL_BLOCK_PROTOCOL instance from which to read data.
57 @param StartLba Pointer to StartLba.
58 On input, the start logical block index from which to read.
59 On output,the end logical block index after reading.
60 @param Offset Pointer to Offset
61 On input, offset into the block at which to begin reading.
62 On output, offset into the end block after reading.
63 @param DataSize Size of data to be read.
64 @param Data Pointer to Buffer that the data will be read into.
66 @retval EFI_SUCCESS Successfully read data from firmware block.
71 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*Fvb
,
72 IN OUT EFI_LBA
*StartLba
,
85 // Try read data in current block
88 ReadDataSize
= DataSize
;
89 Status
= Fvb
->Read (Fvb
, *StartLba
, *Offset
, &ReadDataSize
, Data
);
90 if (Status
== EFI_SUCCESS
) {
93 } else if (Status
!= EFI_BAD_BUFFER_SIZE
) {
95 // other error will direct return
101 // Data crosses the blocks, read data from next block
103 DataSize
-= ReadDataSize
;
104 Data
+= ReadDataSize
;
105 *StartLba
= *StartLba
+ 1;
106 while (DataSize
> 0) {
107 Status
= Fvb
->GetBlockSize (Fvb
, *StartLba
, &BlockSize
, &NumberOfBlocks
);
108 if (EFI_ERROR (Status
)) {
113 // Read data from the crossing blocks
116 while (BlockIndex
< NumberOfBlocks
&& DataSize
>= BlockSize
) {
117 Status
= Fvb
->Read (Fvb
, *StartLba
+ BlockIndex
, 0, &BlockSize
, Data
);
118 if (EFI_ERROR (Status
)) {
122 DataSize
-= BlockSize
;
127 // Data doesn't exceed the current block range.
129 if (DataSize
< BlockSize
) {
134 // Data must be got from the next block range.
136 *StartLba
+= NumberOfBlocks
;
140 // read the remaining data
143 Status
= Fvb
->Read (Fvb
, *StartLba
+ BlockIndex
, 0, &DataSize
, Data
);
144 if (EFI_ERROR (Status
)) {
150 // Update Lba and Offset used by the following read.
152 *StartLba
+= BlockIndex
;
159 Given the supplied FW_VOL_BLOCK_PROTOCOL, allocate a buffer for output and
160 copy the real length volume header into it.
162 @param Fvb The FW_VOL_BLOCK_PROTOCOL instance from which to
163 read the volume header
164 @param FwVolHeader Pointer to pointer to allocated buffer in which
165 the volume header is returned.
167 @retval EFI_OUT_OF_RESOURCES No enough buffer could be allocated.
168 @retval EFI_SUCCESS Successfully read volume header to the allocated
170 @retval EFI_INVALID_PARAMETER The FV Header signature is not as expected or
171 the file system could not be understood.
176 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*Fvb
,
177 OUT EFI_FIRMWARE_VOLUME_HEADER
**FwVolHeader
181 EFI_FIRMWARE_VOLUME_HEADER TempFvh
;
188 // Read the standard FV header
192 FvhLength
= sizeof (EFI_FIRMWARE_VOLUME_HEADER
);
193 Status
= ReadFvbData (Fvb
, &StartLba
, &Offset
, FvhLength
, (UINT8
*)&TempFvh
);
194 if (EFI_ERROR (Status
)) {
199 // Validate FV Header signature, if not as expected, continue.
201 if (TempFvh
.Signature
!= EFI_FVH_SIGNATURE
) {
202 return EFI_INVALID_PARAMETER
;
206 // Check to see that the file system is indeed formatted in a way we can
209 if ((!CompareGuid (&TempFvh
.FileSystemGuid
, &gEfiFirmwareFileSystem2Guid
)) &&
210 (!CompareGuid (&TempFvh
.FileSystemGuid
, &gEfiFirmwareFileSystem3Guid
))) {
211 return EFI_INVALID_PARAMETER
;
215 // Allocate a buffer for the caller
217 *FwVolHeader
= AllocatePool (TempFvh
.HeaderLength
);
218 if (*FwVolHeader
== NULL
) {
219 return EFI_OUT_OF_RESOURCES
;
223 // Copy the standard header into the buffer
225 CopyMem (*FwVolHeader
, &TempFvh
, sizeof (EFI_FIRMWARE_VOLUME_HEADER
));
228 // Read the rest of the header
230 FvhLength
= TempFvh
.HeaderLength
- sizeof (EFI_FIRMWARE_VOLUME_HEADER
);
231 Buffer
= (UINT8
*)*FwVolHeader
+ sizeof (EFI_FIRMWARE_VOLUME_HEADER
);
232 Status
= ReadFvbData (Fvb
, &StartLba
, &Offset
, FvhLength
, Buffer
);
233 if (EFI_ERROR (Status
)) {
235 // Read failed so free buffer
237 CoreFreePool (*FwVolHeader
);
246 Free FvDevice resource when error happens
248 @param FvDevice pointer to the FvDevice to be freed.
252 FreeFvDeviceResource (
253 IN FV_DEVICE
*FvDevice
256 FFS_FILE_LIST_ENTRY
*FfsFileEntry
;
257 LIST_ENTRY
*NextEntry
;
260 // Free File List Entry
262 FfsFileEntry
= (FFS_FILE_LIST_ENTRY
*)FvDevice
->FfsFileListHeader
.ForwardLink
;
263 while (&FfsFileEntry
->Link
!= &FvDevice
->FfsFileListHeader
) {
264 NextEntry
= (&FfsFileEntry
->Link
)->ForwardLink
;
266 if (FfsFileEntry
->StreamHandle
!= 0) {
268 // Close stream and free resources from SEP
270 CloseSectionStream (FfsFileEntry
->StreamHandle
, FALSE
);
273 if (FfsFileEntry
->FileCached
) {
275 // Free the cached file buffer.
277 CoreFreePool (FfsFileEntry
->FfsHeader
);
280 CoreFreePool (FfsFileEntry
);
282 FfsFileEntry
= (FFS_FILE_LIST_ENTRY
*) NextEntry
;
285 if (!FvDevice
->IsMemoryMapped
) {
287 // Free the cached FV buffer.
289 CoreFreePool (FvDevice
->CachedFv
);
293 // Free Volume Header
295 CoreFreePool (FvDevice
->FwVolHeader
);
303 Check if an FV is consistent and allocate cache for it.
305 @param FvDevice A pointer to the FvDevice to be checked.
307 @retval EFI_OUT_OF_RESOURCES No enough buffer could be allocated.
308 @retval EFI_SUCCESS FV is consistent and cache is allocated.
309 @retval EFI_VOLUME_CORRUPTED File system is corrupted.
314 IN OUT FV_DEVICE
*FvDevice
318 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*Fvb
;
319 EFI_FIRMWARE_VOLUME_HEADER
*FwVolHeader
;
320 EFI_FIRMWARE_VOLUME_EXT_HEADER
*FwVolExtHeader
;
321 EFI_FVB_ATTRIBUTES_2 FvbAttributes
;
322 EFI_FV_BLOCK_MAP_ENTRY
*BlockMap
;
323 FFS_FILE_LIST_ENTRY
*FfsFileEntry
;
324 EFI_FFS_FILE_HEADER
*FfsHeader
;
325 UINT8
*CacheLocation
;
329 EFI_FFS_FILE_STATE FileState
;
332 EFI_PHYSICAL_ADDRESS PhysicalAddress
;
335 EFI_FFS_FILE_HEADER
*CacheFfsHeader
;
338 CacheFfsHeader
= NULL
;
341 FwVolHeader
= FvDevice
->FwVolHeader
;
343 Status
= Fvb
->GetAttributes (Fvb
, &FvbAttributes
);
344 if (EFI_ERROR (Status
)) {
348 Size
= (UINTN
) FwVolHeader
->FvLength
;
349 if ((FvbAttributes
& EFI_FVB2_MEMORY_MAPPED
) != 0) {
350 FvDevice
->IsMemoryMapped
= TRUE
;
352 Status
= Fvb
->GetPhysicalAddress (Fvb
, &PhysicalAddress
);
353 if (EFI_ERROR (Status
)) {
358 // Don't cache memory mapped FV really.
360 FvDevice
->CachedFv
= (UINT8
*) (UINTN
) PhysicalAddress
;
362 FvDevice
->IsMemoryMapped
= FALSE
;
363 FvDevice
->CachedFv
= AllocatePool (Size
);
365 if (FvDevice
->CachedFv
== NULL
) {
366 return EFI_OUT_OF_RESOURCES
;
371 // Remember a pointer to the end of the CachedFv
373 FvDevice
->EndOfCachedFv
= FvDevice
->CachedFv
+ Size
;
375 if (!FvDevice
->IsMemoryMapped
) {
377 // Copy FV into memory using the block map.
379 BlockMap
= FwVolHeader
->BlockMap
;
380 CacheLocation
= FvDevice
->CachedFv
;
382 while ((BlockMap
->NumBlocks
!= 0) || (BlockMap
->Length
!= 0)) {
386 Size
= BlockMap
->Length
;
387 for (Index
= 0; Index
< BlockMap
->NumBlocks
; Index
++) {
397 // Not check EFI_BAD_BUFFER_SIZE, for Size = BlockMap->Length
399 if (EFI_ERROR (Status
)) {
404 CacheLocation
+= BlockMap
->Length
;
412 // Scan to check the free space & File list
414 if ((FvbAttributes
& EFI_FVB2_ERASE_POLARITY
) != 0) {
415 FvDevice
->ErasePolarity
= 1;
417 FvDevice
->ErasePolarity
= 0;
422 // go through the whole FV cache, check the consistence of the FV.
423 // Make a linked list of all the Ffs file headers
425 Status
= EFI_SUCCESS
;
426 InitializeListHead (&FvDevice
->FfsFileListHeader
);
431 if (FwVolHeader
->ExtHeaderOffset
!= 0) {
433 // Searching for files starts on an 8 byte aligned boundary after the end of the Extended Header if it exists.
435 FwVolExtHeader
= (EFI_FIRMWARE_VOLUME_EXT_HEADER
*) (FvDevice
->CachedFv
+ FwVolHeader
->ExtHeaderOffset
);
436 FfsHeader
= (EFI_FFS_FILE_HEADER
*) ((UINT8
*) FwVolExtHeader
+ FwVolExtHeader
->ExtHeaderSize
);
438 FfsHeader
= (EFI_FFS_FILE_HEADER
*) (FvDevice
->CachedFv
+ FwVolHeader
->HeaderLength
);
440 FfsHeader
= (EFI_FFS_FILE_HEADER
*) ALIGN_POINTER (FfsHeader
, 8);
441 TopFvAddress
= FvDevice
->EndOfCachedFv
;
442 while (((UINTN
) FfsHeader
>= (UINTN
) FvDevice
->CachedFv
) && ((UINTN
) FfsHeader
<= (UINTN
) ((UINTN
) TopFvAddress
- sizeof (EFI_FFS_FILE_HEADER
)))) {
445 CoreFreePool (CacheFfsHeader
);
449 TestLength
= TopFvAddress
- ((UINT8
*) FfsHeader
);
450 if (TestLength
> sizeof (EFI_FFS_FILE_HEADER
)) {
451 TestLength
= sizeof (EFI_FFS_FILE_HEADER
);
454 if (IsBufferErased (FvDevice
->ErasePolarity
, FfsHeader
, TestLength
)) {
456 // We have found the free space so we are done!
461 if (!IsValidFfsHeader (FvDevice
->ErasePolarity
, FfsHeader
, &FileState
)) {
462 if ((FileState
== EFI_FILE_HEADER_INVALID
) ||
463 (FileState
== EFI_FILE_HEADER_CONSTRUCTION
)) {
464 if (IS_FFS_FILE2 (FfsHeader
)) {
465 if (!FvDevice
->IsFfs3Fv
) {
466 DEBUG ((EFI_D_ERROR
, "Found a FFS3 formatted file: %g in a non-FFS3 formatted FV.\n", &FfsHeader
->Name
));
468 FfsHeader
= (EFI_FFS_FILE_HEADER
*) ((UINT8
*) FfsHeader
+ sizeof (EFI_FFS_FILE_HEADER2
));
470 FfsHeader
= (EFI_FFS_FILE_HEADER
*) ((UINT8
*) FfsHeader
+ sizeof (EFI_FFS_FILE_HEADER
));
475 // File system is corrputed
477 Status
= EFI_VOLUME_CORRUPTED
;
482 CacheFfsHeader
= FfsHeader
;
483 if ((CacheFfsHeader
->Attributes
& FFS_ATTRIB_CHECKSUM
) == FFS_ATTRIB_CHECKSUM
) {
484 if (FvDevice
->IsMemoryMapped
) {
486 // Memory mapped FV has not been cached.
487 // Here is to cache FFS file to memory buffer for following checksum calculating.
488 // And then, the cached file buffer can be also used for FvReadFile.
490 WholeFileSize
= IS_FFS_FILE2 (CacheFfsHeader
) ? FFS_FILE2_SIZE (CacheFfsHeader
): FFS_FILE_SIZE (CacheFfsHeader
);
491 CacheFfsHeader
= AllocateCopyPool (WholeFileSize
, CacheFfsHeader
);
492 if (CacheFfsHeader
== NULL
) {
493 Status
= EFI_OUT_OF_RESOURCES
;
500 if (!IsValidFfsFile (FvDevice
->ErasePolarity
, CacheFfsHeader
)) {
502 // File system is corrupted
504 Status
= EFI_VOLUME_CORRUPTED
;
508 if (IS_FFS_FILE2 (CacheFfsHeader
)) {
509 ASSERT (FFS_FILE2_SIZE (CacheFfsHeader
) > 0x00FFFFFF);
510 if (!FvDevice
->IsFfs3Fv
) {
511 DEBUG ((EFI_D_ERROR
, "Found a FFS3 formatted file: %g in a non-FFS3 formatted FV.\n", &CacheFfsHeader
->Name
));
512 FfsHeader
= (EFI_FFS_FILE_HEADER
*) ((UINT8
*) FfsHeader
+ FFS_FILE2_SIZE (CacheFfsHeader
));
514 // Adjust pointer to the next 8-byte aligned boundary.
516 FfsHeader
= (EFI_FFS_FILE_HEADER
*) (((UINTN
) FfsHeader
+ 7) & ~0x07);
521 FileState
= GetFileState (FvDevice
->ErasePolarity
, CacheFfsHeader
);
524 // check for non-deleted file
526 if (FileState
!= EFI_FILE_DELETED
) {
528 // Create a FFS list entry for each non-deleted file
530 FfsFileEntry
= AllocateZeroPool (sizeof (FFS_FILE_LIST_ENTRY
));
531 if (FfsFileEntry
== NULL
) {
532 Status
= EFI_OUT_OF_RESOURCES
;
536 FfsFileEntry
->FfsHeader
= CacheFfsHeader
;
537 FfsFileEntry
->FileCached
= FileCached
;
539 InsertTailList (&FvDevice
->FfsFileListHeader
, &FfsFileEntry
->Link
);
542 if (IS_FFS_FILE2 (CacheFfsHeader
)) {
543 FfsHeader
= (EFI_FFS_FILE_HEADER
*) ((UINT8
*) FfsHeader
+ FFS_FILE2_SIZE (CacheFfsHeader
));
545 FfsHeader
= (EFI_FFS_FILE_HEADER
*) ((UINT8
*) FfsHeader
+ FFS_FILE_SIZE (CacheFfsHeader
));
549 // Adjust pointer to the next 8-byte aligned boundary.
551 FfsHeader
= (EFI_FFS_FILE_HEADER
*)(((UINTN
)FfsHeader
+ 7) & ~0x07);
556 if (EFI_ERROR (Status
)) {
558 CoreFreePool (CacheFfsHeader
);
561 FreeFvDeviceResource (FvDevice
);
570 This notification function is invoked when an instance of the
571 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL is produced. It layers an instance of the
572 EFI_FIRMWARE_VOLUME2_PROTOCOL on the same handle. This is the function where
573 the actual initialization of the EFI_FIRMWARE_VOLUME2_PROTOCOL is done.
575 @param Event The event that occured
576 @param Context For EFI compatiblity. Not used.
589 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*Fvb
;
590 EFI_FIRMWARE_VOLUME2_PROTOCOL
*Fv
;
592 EFI_FIRMWARE_VOLUME_HEADER
*FwVolHeader
;
594 // Examine all new handles
598 // Get the next handle
600 BufferSize
= sizeof (Handle
);
601 Status
= CoreLocateHandle (
604 gEfiFwVolBlockNotifyReg
,
610 // If not found, we're done
612 if (EFI_NOT_FOUND
== Status
) {
616 if (EFI_ERROR (Status
)) {
621 // Get the FirmwareVolumeBlock protocol on that handle
623 Status
= CoreHandleProtocol (Handle
, &gEfiFirmwareVolumeBlockProtocolGuid
, (VOID
**)&Fvb
);
624 ASSERT_EFI_ERROR (Status
);
625 ASSERT (Fvb
!= NULL
);
628 // Make sure the Fv Header is O.K.
630 Status
= GetFwVolHeader (Fvb
, &FwVolHeader
);
631 if (EFI_ERROR (Status
)) {
634 ASSERT (FwVolHeader
!= NULL
);
636 if (!VerifyFvHeaderChecksum (FwVolHeader
)) {
637 CoreFreePool (FwVolHeader
);
642 // Check if there is an FV protocol already installed in that handle
644 Status
= CoreHandleProtocol (Handle
, &gEfiFirmwareVolume2ProtocolGuid
, (VOID
**)&Fv
);
645 if (!EFI_ERROR (Status
)) {
647 // Update Fv to use a new Fvb
649 FvDevice
= BASE_CR (Fv
, FV_DEVICE
, Fv
);
650 if (FvDevice
->Signature
== FV2_DEVICE_SIGNATURE
) {
652 // Only write into our device structure if it's our device structure
659 // No FwVol protocol on the handle so create a new one
661 FvDevice
= AllocateCopyPool (sizeof (FV_DEVICE
), &mFvDevice
);
662 if (FvDevice
== NULL
) {
667 FvDevice
->Handle
= Handle
;
668 FvDevice
->FwVolHeader
= FwVolHeader
;
669 FvDevice
->IsFfs3Fv
= CompareGuid (&FwVolHeader
->FileSystemGuid
, &gEfiFirmwareFileSystem3Guid
);
670 FvDevice
->Fv
.ParentHandle
= Fvb
->ParentHandle
;
672 // Inherit the authentication status from FVB.
674 FvDevice
->AuthenticationStatus
= GetFvbAuthenticationStatus (Fvb
);
676 if (!EFI_ERROR (FvCheck (FvDevice
))) {
678 // Install an New FV protocol on the existing handle
680 Status
= CoreInstallProtocolInterface (
682 &gEfiFirmwareVolume2ProtocolGuid
,
683 EFI_NATIVE_INTERFACE
,
686 ASSERT_EFI_ERROR (Status
);
689 // Free FvDevice Buffer for the corrupt FV image.
691 CoreFreePool (FvDevice
);
702 This routine is the driver initialization entry point. It registers
703 a notification function. This notification function are responsible
704 for building the FV stack dynamically.
706 @param ImageHandle The image handle.
707 @param SystemTable The system table.
709 @retval EFI_SUCCESS Function successfully returned.
715 IN EFI_HANDLE ImageHandle
,
716 IN EFI_SYSTEM_TABLE
*SystemTable
719 gEfiFwVolBlockEvent
= EfiCreateProtocolNotifyEvent (
720 &gEfiFirmwareVolumeBlockProtocolGuid
,
724 &gEfiFwVolBlockNotifyReg