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 - 2011, Intel Corporation. All rights reserved.<BR>
7 This program and the accompanying materials
8 are licensed and made available under the terms and conditions of the BSD License
9 which accompanies this distribution. The full text of the license may be found at
10 http://opensource.org/licenses/bsd-license.php
12 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
13 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
18 #include "FwVolDriver.h"
22 // Protocol notify related globals
24 VOID
*gEfiFwVolBlockNotifyReg
;
25 EFI_EVENT gEfiFwVolBlockEvent
;
27 FV_DEVICE mFvDevice
= {
32 FvGetVolumeAttributes
,
33 FvSetVolumeAttributes
,
53 // FFS helper functions
56 Read data from Firmware Block by FVB protocol Read.
57 The data may cross the multi block ranges.
59 @param Fvb The FW_VOL_BLOCK_PROTOCOL instance from which to read data.
60 @param StartLba Pointer to StartLba.
61 On input, the start logical block index from which to read.
62 On output,the end logical block index after reading.
63 @param Offset Pointer to Offset
64 On input, offset into the block at which to begin reading.
65 On output, offset into the end block after reading.
66 @param DataSize Size of data to be read.
67 @param Data Pointer to Buffer that the data will be read into.
69 @retval EFI_SUCCESS Successfully read data from firmware block.
74 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*Fvb
,
75 IN OUT EFI_LBA
*StartLba
,
88 // Try read data in current block
91 ReadDataSize
= DataSize
;
92 Status
= Fvb
->Read (Fvb
, *StartLba
, *Offset
, &ReadDataSize
, Data
);
93 if (Status
== EFI_SUCCESS
) {
96 } else if (Status
!= EFI_BAD_BUFFER_SIZE
) {
98 // other error will direct return
104 // Data crosses the blocks, read data from next block
106 DataSize
-= ReadDataSize
;
107 Data
+= ReadDataSize
;
108 *StartLba
= *StartLba
+ 1;
109 while (DataSize
> 0) {
110 Status
= Fvb
->GetBlockSize (Fvb
, *StartLba
, &BlockSize
, &NumberOfBlocks
);
111 if (EFI_ERROR (Status
)) {
116 // Read data from the crossing blocks
119 while (BlockIndex
< NumberOfBlocks
&& DataSize
>= BlockSize
) {
120 Status
= Fvb
->Read (Fvb
, *StartLba
+ BlockIndex
, 0, &BlockSize
, Data
);
121 if (EFI_ERROR (Status
)) {
125 DataSize
-= BlockSize
;
130 // Data doesn't exceed the current block range.
132 if (DataSize
< BlockSize
) {
137 // Data must be got from the next block range.
139 *StartLba
+= NumberOfBlocks
;
143 // read the remaining data
146 Status
= Fvb
->Read (Fvb
, *StartLba
+ BlockIndex
, 0, &DataSize
, Data
);
147 if (EFI_ERROR (Status
)) {
153 // Update Lba and Offset used by the following read.
155 *StartLba
+= BlockIndex
;
162 Given the supplied FW_VOL_BLOCK_PROTOCOL, allocate a buffer for output and
163 copy the real length volume header into it.
165 @param Fvb The FW_VOL_BLOCK_PROTOCOL instance from which to
166 read the volume header
167 @param FwVolHeader Pointer to pointer to allocated buffer in which
168 the volume header is returned.
170 @retval EFI_OUT_OF_RESOURCES No enough buffer could be allocated.
171 @retval EFI_SUCCESS Successfully read volume header to the allocated
177 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*Fvb
,
178 OUT EFI_FIRMWARE_VOLUME_HEADER
**FwVolHeader
182 EFI_FIRMWARE_VOLUME_HEADER TempFvh
;
189 // Read the standard FV header
193 FvhLength
= sizeof (EFI_FIRMWARE_VOLUME_HEADER
);
194 Status
= ReadFvbData (Fvb
, &StartLba
, &Offset
, FvhLength
, (UINT8
*)&TempFvh
);
195 if (EFI_ERROR (Status
)) {
200 // Allocate a buffer for the caller
202 *FwVolHeader
= AllocatePool (TempFvh
.HeaderLength
);
203 if (*FwVolHeader
== NULL
) {
204 return EFI_OUT_OF_RESOURCES
;
208 // Copy the standard header into the buffer
210 CopyMem (*FwVolHeader
, &TempFvh
, sizeof (EFI_FIRMWARE_VOLUME_HEADER
));
213 // Read the rest of the header
215 FvhLength
= TempFvh
.HeaderLength
- sizeof (EFI_FIRMWARE_VOLUME_HEADER
);
216 Buffer
= (UINT8
*)*FwVolHeader
+ sizeof (EFI_FIRMWARE_VOLUME_HEADER
);
217 Status
= ReadFvbData (Fvb
, &StartLba
, &Offset
, FvhLength
, Buffer
);
218 if (EFI_ERROR (Status
)) {
220 // Read failed so free buffer
222 CoreFreePool (*FwVolHeader
);
231 Free FvDevice resource when error happens
233 @param FvDevice pointer to the FvDevice to be freed.
237 FreeFvDeviceResource (
238 IN FV_DEVICE
*FvDevice
241 FFS_FILE_LIST_ENTRY
*FfsFileEntry
;
242 LIST_ENTRY
*NextEntry
;
245 // Free File List Entry
247 FfsFileEntry
= (FFS_FILE_LIST_ENTRY
*)FvDevice
->FfsFileListHeader
.ForwardLink
;
248 while (&FfsFileEntry
->Link
!= &FvDevice
->FfsFileListHeader
) {
249 NextEntry
= (&FfsFileEntry
->Link
)->ForwardLink
;
251 if (FfsFileEntry
->StreamHandle
!= 0) {
253 // Close stream and free resources from SEP
255 CloseSectionStream (FfsFileEntry
->StreamHandle
);
258 CoreFreePool (FfsFileEntry
);
260 FfsFileEntry
= (FFS_FILE_LIST_ENTRY
*) NextEntry
;
267 CoreFreePool (FvDevice
->CachedFv
);
270 // Free Volume Header
272 CoreFreePool (FvDevice
->FwVolHeader
);
280 Check if an FV is consistent and allocate cache for it.
282 @param FvDevice A pointer to the FvDevice to be checked.
284 @retval EFI_OUT_OF_RESOURCES No enough buffer could be allocated.
285 @retval EFI_SUCCESS FV is consistent and cache is allocated.
286 @retval EFI_VOLUME_CORRUPTED File system is corrupted.
291 IN OUT FV_DEVICE
*FvDevice
295 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*Fvb
;
296 EFI_FIRMWARE_VOLUME_HEADER
*FwVolHeader
;
297 EFI_FVB_ATTRIBUTES_2 FvbAttributes
;
298 EFI_FV_BLOCK_MAP_ENTRY
*BlockMap
;
299 FFS_FILE_LIST_ENTRY
*FfsFileEntry
;
300 EFI_FFS_FILE_HEADER
*FfsHeader
;
301 UINT8
*CacheLocation
;
307 EFI_FFS_FILE_STATE FileState
;
313 FwVolHeader
= FvDevice
->FwVolHeader
;
315 Status
= Fvb
->GetAttributes (Fvb
, &FvbAttributes
);
316 if (EFI_ERROR (Status
)) {
321 // Size is the size of the FV minus the head. We have already allocated
322 // the header to check to make sure the volume is valid
324 Size
= (UINTN
)(FwVolHeader
->FvLength
- FwVolHeader
->HeaderLength
);
325 FvDevice
->CachedFv
= AllocatePool (Size
);
327 if (FvDevice
->CachedFv
== NULL
) {
328 return EFI_OUT_OF_RESOURCES
;
332 // Remember a pointer to the end fo the CachedFv
334 FvDevice
->EndOfCachedFv
= FvDevice
->CachedFv
+ Size
;
337 // Copy FV minus header into memory using the block map we have all ready
340 BlockMap
= FwVolHeader
->BlockMap
;
341 CacheLocation
= FvDevice
->CachedFv
;
344 HeaderSize
= FwVolHeader
->HeaderLength
;
345 while ((BlockMap
->NumBlocks
!= 0) || (BlockMap
->Length
!= 0)) {
347 Size
= BlockMap
->Length
;
348 if (HeaderSize
> 0) {
352 for (; Index
< BlockMap
->NumBlocks
&& HeaderSize
>= BlockMap
->Length
; Index
++) {
353 HeaderSize
-= BlockMap
->Length
;
358 // Check whether FvHeader is crossing the multi block range.
360 if (Index
>= BlockMap
->NumBlocks
) {
363 } else if (HeaderSize
> 0) {
364 LbaOffset
= HeaderSize
;
365 Size
= BlockMap
->Length
- HeaderSize
;
373 for (; Index
< BlockMap
->NumBlocks
; Index
++) {
374 Status
= Fvb
->Read (Fvb
,
382 // Not check EFI_BAD_BUFFER_SIZE, for Size = BlockMap->Length
384 if (EFI_ERROR (Status
)) {
389 CacheLocation
+= Size
;
392 // After we skip Fv Header always read from start of block
395 Size
= BlockMap
->Length
;
402 // Scan to check the free space & File list
404 if ((FvbAttributes
& EFI_FVB2_ERASE_POLARITY
) != 0) {
405 FvDevice
->ErasePolarity
= 1;
407 FvDevice
->ErasePolarity
= 0;
412 // go through the whole FV cache, check the consistence of the FV.
413 // Make a linked list off all the Ffs file headers
415 Status
= EFI_SUCCESS
;
416 InitializeListHead (&FvDevice
->FfsFileListHeader
);
421 FfsHeader
= (EFI_FFS_FILE_HEADER
*) FvDevice
->CachedFv
;
422 TopFvAddress
= FvDevice
->EndOfCachedFv
;
423 while ((UINT8
*) FfsHeader
< TopFvAddress
) {
425 TestLength
= TopFvAddress
- ((UINT8
*) FfsHeader
);
426 if (TestLength
> sizeof (EFI_FFS_FILE_HEADER
)) {
427 TestLength
= sizeof (EFI_FFS_FILE_HEADER
);
430 if (IsBufferErased (FvDevice
->ErasePolarity
, FfsHeader
, TestLength
)) {
432 // We have found the free space so we are done!
437 if (!IsValidFfsHeader (FvDevice
->ErasePolarity
, FfsHeader
, &FileState
)) {
438 if ((FileState
== EFI_FILE_HEADER_INVALID
) ||
439 (FileState
== EFI_FILE_HEADER_CONSTRUCTION
)) {
440 if (IS_FFS_FILE2 (FfsHeader
)) {
441 if (!FvDevice
->IsFfs3Fv
) {
442 DEBUG ((EFI_D_ERROR
, "Found a FFS3 formatted file: %g in a non-FFS3 formatted FV.\n", &FfsHeader
->Name
));
444 FfsHeader
= (EFI_FFS_FILE_HEADER
*) ((UINT8
*) FfsHeader
+ sizeof (EFI_FFS_FILE_HEADER2
));
446 FfsHeader
= (EFI_FFS_FILE_HEADER
*) ((UINT8
*) FfsHeader
+ sizeof (EFI_FFS_FILE_HEADER
));
451 // File system is corrputed
453 Status
= EFI_VOLUME_CORRUPTED
;
458 if (!IsValidFfsFile (FvDevice
->ErasePolarity
, FfsHeader
)) {
460 // File system is corrupted
462 Status
= EFI_VOLUME_CORRUPTED
;
466 if (IS_FFS_FILE2 (FfsHeader
)) {
467 ASSERT (FFS_FILE2_SIZE (FfsHeader
) > 0x00FFFFFF);
468 if (!FvDevice
->IsFfs3Fv
) {
469 DEBUG ((EFI_D_ERROR
, "Found a FFS3 formatted file: %g in a non-FFS3 formatted FV.\n", &FfsHeader
->Name
));
470 FfsHeader
= (EFI_FFS_FILE_HEADER
*) ((UINT8
*) FfsHeader
+ FFS_FILE2_SIZE (FfsHeader
));
472 // Adjust pointer to the next 8-byte aligned boundry.
474 FfsHeader
= (EFI_FFS_FILE_HEADER
*) (((UINTN
) FfsHeader
+ 7) & ~0x07);
479 FileState
= GetFileState (FvDevice
->ErasePolarity
, FfsHeader
);
482 // check for non-deleted file
484 if (FileState
!= EFI_FILE_DELETED
) {
486 // Create a FFS list entry for each non-deleted file
488 FfsFileEntry
= AllocateZeroPool (sizeof (FFS_FILE_LIST_ENTRY
));
489 if (FfsFileEntry
== NULL
) {
490 Status
= EFI_OUT_OF_RESOURCES
;
494 FfsFileEntry
->FfsHeader
= FfsHeader
;
495 InsertTailList (&FvDevice
->FfsFileListHeader
, &FfsFileEntry
->Link
);
498 if (IS_FFS_FILE2 (FfsHeader
)) {
499 FfsHeader
= (EFI_FFS_FILE_HEADER
*) ((UINT8
*) FfsHeader
+ FFS_FILE2_SIZE (FfsHeader
));
501 FfsHeader
= (EFI_FFS_FILE_HEADER
*) ((UINT8
*) FfsHeader
+ FFS_FILE_SIZE (FfsHeader
));
505 // Adjust pointer to the next 8-byte aligned boundry.
507 FfsHeader
= (EFI_FFS_FILE_HEADER
*)(((UINTN
)FfsHeader
+ 7) & ~0x07);
512 if (EFI_ERROR (Status
)) {
513 FreeFvDeviceResource (FvDevice
);
522 This notification function is invoked when an instance of the
523 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL is produced. It layers an instance of the
524 EFI_FIRMWARE_VOLUME2_PROTOCOL on the same handle. This is the function where
525 the actual initialization of the EFI_FIRMWARE_VOLUME2_PROTOCOL is done.
527 @param Event The event that occured
528 @param Context For EFI compatiblity. Not used.
541 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*Fvb
;
542 EFI_FIRMWARE_VOLUME2_PROTOCOL
*Fv
;
544 EFI_FIRMWARE_VOLUME_HEADER
*FwVolHeader
;
546 // Examine all new handles
550 // Get the next handle
552 BufferSize
= sizeof (Handle
);
553 Status
= CoreLocateHandle (
556 gEfiFwVolBlockNotifyReg
,
562 // If not found, we're done
564 if (EFI_NOT_FOUND
== Status
) {
568 if (EFI_ERROR (Status
)) {
573 // Get the FirmwareVolumeBlock protocol on that handle
575 Status
= CoreHandleProtocol (Handle
, &gEfiFirmwareVolumeBlockProtocolGuid
, (VOID
**)&Fvb
);
576 ASSERT_EFI_ERROR (Status
);
577 ASSERT (Fvb
!= NULL
);
580 // Make sure the Fv Header is O.K.
582 Status
= GetFwVolHeader (Fvb
, &FwVolHeader
);
583 if (EFI_ERROR (Status
)) {
586 ASSERT (FwVolHeader
!= NULL
);
588 if (!VerifyFvHeaderChecksum (FwVolHeader
)) {
589 CoreFreePool (FwVolHeader
);
595 // Check to see that the file system is indeed formatted in a way we can
598 if ((!CompareGuid (&FwVolHeader
->FileSystemGuid
, &gEfiFirmwareFileSystem2Guid
)) &&
599 (!CompareGuid (&FwVolHeader
->FileSystemGuid
, &gEfiFirmwareFileSystem3Guid
))) {
604 // Check if there is an FV protocol already installed in that handle
606 Status
= CoreHandleProtocol (Handle
, &gEfiFirmwareVolume2ProtocolGuid
, (VOID
**)&Fv
);
607 if (!EFI_ERROR (Status
)) {
609 // Update Fv to use a new Fvb
611 FvDevice
= BASE_CR (Fv
, FV_DEVICE
, Fv
);
612 if (FvDevice
->Signature
== FV2_DEVICE_SIGNATURE
) {
614 // Only write into our device structure if it's our device structure
621 // No FwVol protocol on the handle so create a new one
623 FvDevice
= AllocateCopyPool (sizeof (FV_DEVICE
), &mFvDevice
);
624 if (FvDevice
== NULL
) {
629 FvDevice
->Handle
= Handle
;
630 FvDevice
->FwVolHeader
= FwVolHeader
;
631 FvDevice
->Fv
.ParentHandle
= Fvb
->ParentHandle
;
632 FvDevice
->IsFfs3Fv
= CompareGuid (&FwVolHeader
->FileSystemGuid
, &gEfiFirmwareFileSystem3Guid
);
635 // Install an New FV protocol on the existing handle
637 Status
= CoreInstallProtocolInterface (
639 &gEfiFirmwareVolume2ProtocolGuid
,
640 EFI_NATIVE_INTERFACE
,
643 ASSERT_EFI_ERROR (Status
);
653 This routine is the driver initialization entry point. It registers
654 a notification function. This notification function are responsible
655 for building the FV stack dynamically.
657 @param ImageHandle The image handle.
658 @param SystemTable The system table.
660 @retval EFI_SUCCESS Function successfully returned.
666 IN EFI_HANDLE ImageHandle
,
667 IN EFI_SYSTEM_TABLE
*SystemTable
670 gEfiFwVolBlockEvent
= EfiCreateProtocolNotifyEvent (
671 &gEfiFirmwareVolumeBlockProtocolGuid
,
675 &gEfiFwVolBlockNotifyReg