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 - 2014, Intel Corporation. All rights reserved.<BR>
9 This program and the accompanying materials
10 are licensed and made available under the terms and conditions
11 of the BSD License which accompanies this distribution. The
12 full text of the license may be found at
13 http://opensource.org/licenses/bsd-license.php
15 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
16 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
20 #include "FwVolDriver.h"
22 #define KEYSIZE sizeof (UINTN)
25 Given the supplied FW_VOL_BLOCK_PROTOCOL, allocate a buffer for output and
26 copy the real length volume header into it.
28 @param Fvb The FW_VOL_BLOCK_PROTOCOL instance from which to
29 read the volume header
30 @param FwVolHeader Pointer to pointer to allocated buffer in which
31 the volume header is returned.
33 @retval EFI_OUT_OF_RESOURCES No enough buffer could be allocated.
34 @retval EFI_SUCCESS Successfully read volume header to the allocated
36 @retval EFI_ACCESS_DENIED Read status of FV is not enabled.
37 @retval EFI_INVALID_PARAMETER The FV Header signature is not as expected or
38 the file system could not be understood.
42 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*Fvb
,
43 OUT EFI_FIRMWARE_VOLUME_HEADER
**FwVolHeader
47 EFI_FIRMWARE_VOLUME_HEADER TempFvh
;
48 EFI_FVB_ATTRIBUTES_2 FvbAttributes
;
50 EFI_PHYSICAL_ADDRESS BaseAddress
;
53 // Determine the real length of FV header
55 Status
= Fvb
->GetAttributes (
59 if (EFI_ERROR (Status
)) {
63 if ((FvbAttributes
& EFI_FVB2_READ_STATUS
) == 0) {
64 return EFI_ACCESS_DENIED
;
68 // Just avoid compiling warning
71 FvhLength
= sizeof (EFI_FIRMWARE_VOLUME_HEADER
);
74 // memory-mapped FV and non memory-mapped has different ways to read
76 if ((FvbAttributes
& EFI_FVB2_MEMORY_MAPPED
) != 0) {
77 Status
= Fvb
->GetPhysicalAddress (
81 if (EFI_ERROR (Status
)) {
84 CopyMem (&TempFvh
, (VOID
*) (UINTN
) BaseAddress
, FvhLength
);
96 // Validate FV Header signature, if not as expected, continue.
98 if (TempFvh
.Signature
!= EFI_FVH_SIGNATURE
) {
99 return EFI_INVALID_PARAMETER
;
103 // Check to see that the file system is indeed formatted in a way we can
106 if ((!CompareGuid (&TempFvh
.FileSystemGuid
, &gEfiFirmwareFileSystem2Guid
)) &&
107 (!CompareGuid (&TempFvh
.FileSystemGuid
, &gEfiFirmwareFileSystem3Guid
))) {
108 return EFI_INVALID_PARAMETER
;
111 *FwVolHeader
= AllocatePool (TempFvh
.HeaderLength
);
112 if (*FwVolHeader
== NULL
) {
113 return EFI_OUT_OF_RESOURCES
;
116 // Read the whole header
118 if ((FvbAttributes
& EFI_FVB2_MEMORY_MAPPED
) != 0) {
119 CopyMem (*FwVolHeader
, (VOID
*) (UINTN
) BaseAddress
, TempFvh
.HeaderLength
);
122 // Assumed the first block is bigger than the length of Fv headder
124 FvhLength
= TempFvh
.HeaderLength
;
130 (UINT8
*) *FwVolHeader
133 // Check whether Read successes.
135 if (EFI_ERROR (Status
)) {
136 FreePool (*FwVolHeader
);
146 Free FvDevice resource when error happens.
148 @param FvDevice Pointer to the FvDevice to be freed.
151 FreeFvDeviceResource (
152 IN FV_DEVICE
*FvDevice
156 FREE_SPACE_ENTRY
*FreeSpaceEntry
;
157 FFS_FILE_LIST_ENTRY
*FfsFileEntry
;
158 LIST_ENTRY
*NextEntry
;
163 LbaEntry
= (LBA_ENTRY
*) FvDevice
->LbaHeader
.ForwardLink
;
164 while (&LbaEntry
->Link
!= &FvDevice
->LbaHeader
) {
165 NextEntry
= (&LbaEntry
->Link
)->ForwardLink
;
167 LbaEntry
= (LBA_ENTRY
*) NextEntry
;
170 // Free File List Entry
172 FfsFileEntry
= (FFS_FILE_LIST_ENTRY
*) FvDevice
->FfsFileListHeader
.ForwardLink
;
173 while (&FfsFileEntry
->Link
!= &FvDevice
->FfsFileListHeader
) {
174 NextEntry
= (&FfsFileEntry
->Link
)->ForwardLink
;
175 FreePool (FfsFileEntry
);
176 FfsFileEntry
= (FFS_FILE_LIST_ENTRY
*) NextEntry
;
181 FreeSpaceEntry
= (FREE_SPACE_ENTRY
*) FvDevice
->FreeSpaceHeader
.ForwardLink
;
182 while (&FreeSpaceEntry
->Link
!= &FvDevice
->FreeSpaceHeader
) {
183 NextEntry
= (&FreeSpaceEntry
->Link
)->ForwardLink
;
184 FreePool (FreeSpaceEntry
);
185 FreeSpaceEntry
= (FREE_SPACE_ENTRY
*) NextEntry
;
190 FreePool ((UINT8
*) (UINTN
) FvDevice
->CachedFv
);
197 Firmware volume inherits authentication status from the FV image file and section(in another firmware volume)
200 @param FvDevice A pointer to the FvDevice.
204 FwVolInheritAuthenticationStatus (
205 IN FV_DEVICE
*FvDevice
209 EFI_FIRMWARE_VOLUME_HEADER
*CachedFvHeader
;
210 EFI_FIRMWARE_VOLUME_EXT_HEADER
*CachedFvExtHeader
;
211 EFI_FIRMWARE_VOLUME2_PROTOCOL
*ParentFvProtocol
;
213 EFI_GUID FileNameGuid
;
214 EFI_FV_FILETYPE FileType
;
215 EFI_FV_FILE_ATTRIBUTES FileAttributes
;
217 EFI_SECTION_TYPE SectionType
;
218 UINT32 AuthenticationStatus
;
219 EFI_FIRMWARE_VOLUME_HEADER
*FvHeader
;
220 EFI_FIRMWARE_VOLUME_EXT_HEADER
*FvExtHeader
;
223 CachedFvHeader
= (EFI_FIRMWARE_VOLUME_HEADER
*) (UINTN
) FvDevice
->CachedFv
;
225 if (FvDevice
->Fv
.ParentHandle
!= NULL
) {
227 // By Parent Handle, find out the FV image file and section(in another firmware volume) where the firmware volume came from
229 Status
= gBS
->HandleProtocol (FvDevice
->Fv
.ParentHandle
, &gEfiFirmwareVolume2ProtocolGuid
, (VOID
**) &ParentFvProtocol
);
230 if (!EFI_ERROR (Status
) && (ParentFvProtocol
!= NULL
)) {
233 FileType
= EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE
;
234 Status
= ParentFvProtocol
->GetNextFile (
242 if (EFI_ERROR (Status
)) {
246 SectionType
= EFI_SECTION_FIRMWARE_VOLUME_IMAGE
;
249 Status
= ParentFvProtocol
->ReadSection (
256 &AuthenticationStatus
258 if (!EFI_ERROR (Status
)) {
259 if ((FvHeader
->FvLength
== CachedFvHeader
->FvLength
) &&
260 (FvHeader
->ExtHeaderOffset
== CachedFvHeader
->ExtHeaderOffset
)) {
261 if (FvHeader
->ExtHeaderOffset
!=0) {
263 // Both FVs contain extension header, then compare their FV Name GUID
265 FvExtHeader
= (EFI_FIRMWARE_VOLUME_EXT_HEADER
*) ((UINTN
) FvHeader
+ FvHeader
->ExtHeaderOffset
);
266 CachedFvExtHeader
= (EFI_FIRMWARE_VOLUME_EXT_HEADER
*) ((UINTN
) CachedFvHeader
+ CachedFvHeader
->ExtHeaderOffset
);
267 if (CompareGuid (&FvExtHeader
->FvName
, &CachedFvExtHeader
->FvName
)) {
269 // Found the FV image section where the firmware volume came from,
270 // and then inherit authentication status from it.
272 FvDevice
->AuthenticationStatus
= AuthenticationStatus
;
273 FreePool ((VOID
*) FvHeader
);
278 // Both FVs don't contain extension header, then compare their whole FV Image.
280 if (CompareMem ((VOID
*) FvHeader
, (VOID
*) CachedFvHeader
, (UINTN
) FvHeader
->FvLength
) == 0) {
282 // Found the FV image section where the firmware volume came from
283 // and then inherit authentication status from it.
285 FvDevice
->AuthenticationStatus
= AuthenticationStatus
;
286 FreePool ((VOID
*) FvHeader
);
291 FreePool ((VOID
*) FvHeader
);
299 Check if an FV is consistent and allocate cache for it.
301 @param FvDevice A pointer to the FvDevice to be checked.
303 @retval EFI_OUT_OF_RESOURCES No enough buffer could be allocated.
304 @retval EFI_VOLUME_CORRUPTED File system is corrupted.
305 @retval EFI_SUCCESS FV is consistent and cache is allocated.
310 IN FV_DEVICE
*FvDevice
314 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*Fvb
;
315 EFI_FVB_ATTRIBUTES_2 FvbAttributes
;
316 EFI_FV_BLOCK_MAP_ENTRY
*BlockMap
;
317 EFI_FIRMWARE_VOLUME_HEADER
*FwVolHeader
;
318 EFI_FIRMWARE_VOLUME_EXT_HEADER
*FwVolExtHeader
;
321 FREE_SPACE_ENTRY
*FreeSpaceEntry
;
322 FFS_FILE_LIST_ENTRY
*FfsFileEntry
;
331 EFI_FFS_FILE_STATE FileState
;
334 EFI_PHYSICAL_ADDRESS BaseAddress
;
338 Status
= Fvb
->GetAttributes (Fvb
, &FvbAttributes
);
339 if (EFI_ERROR (Status
)) {
343 InitializeListHead (&FvDevice
->LbaHeader
);
344 InitializeListHead (&FvDevice
->FreeSpaceHeader
);
345 InitializeListHead (&FvDevice
->FfsFileListHeader
);
348 Status
= GetFwVolHeader (Fvb
, &FwVolHeader
);
349 if (EFI_ERROR (Status
)) {
352 ASSERT (FwVolHeader
!= NULL
);
354 FvDevice
->IsFfs3Fv
= CompareGuid (&FwVolHeader
->FileSystemGuid
, &gEfiFirmwareFileSystem3Guid
);
357 // Double Check firmware volume header here
359 if (!VerifyFvHeaderChecksum (FwVolHeader
)) {
360 FreePool (FwVolHeader
);
361 return EFI_VOLUME_CORRUPTED
;
364 BlockMap
= FwVolHeader
->BlockMap
;
367 // FwVolHeader->FvLength is the whole FV length including FV header
369 FwCache
= AllocateZeroPool ((UINTN
) FwVolHeader
->FvLength
);
370 if (FwCache
== NULL
) {
371 FreePool (FwVolHeader
);
372 return EFI_OUT_OF_RESOURCES
;
375 FvDevice
->CachedFv
= (EFI_PHYSICAL_ADDRESS
) (UINTN
) FwCache
;
384 if ((FvbAttributes
& EFI_FVB2_MEMORY_MAPPED
) != 0) {
386 // Get volume base address
388 Status
= Fvb
->GetPhysicalAddress (Fvb
, &BaseAddress
);
389 if (EFI_ERROR (Status
)) {
390 FreePool (FwVolHeader
);
394 Ptr
= (UINT8
*) ((UINTN
) BaseAddress
);
396 DEBUG((EFI_D_INFO
, "Fv Base Address is 0x%LX\n", BaseAddress
));
399 // Copy whole FV into the memory
401 while ((BlockMap
->NumBlocks
!= 0) || (BlockMap
->Length
!= 0)) {
403 for (Index
= 0; Index
< BlockMap
->NumBlocks
; Index
++) {
404 LbaEntry
= AllocatePool (sizeof (LBA_ENTRY
));
405 if (LbaEntry
== NULL
) {
406 FreePool (FwVolHeader
);
407 FreeFvDeviceResource (FvDevice
);
408 return EFI_OUT_OF_RESOURCES
;
411 LbaEntry
->LbaIndex
= LbaIndex
;
412 LbaEntry
->StartingAddress
= LbaStart
;
413 LbaEntry
->BlockLength
= BlockMap
->Length
;
416 // Copy each LBA into memory
418 if ((FvbAttributes
& EFI_FVB2_MEMORY_MAPPED
) != 0) {
420 CopyMem (LbaStart
, Ptr
, BlockMap
->Length
);
421 Ptr
+= BlockMap
->Length
;
425 Size
= BlockMap
->Length
;
434 // Not check EFI_BAD_BUFFER_SIZE, for Size = BlockMap->Length
436 if (EFI_ERROR (Status
)) {
437 FreePool (FwVolHeader
);
438 FreeFvDeviceResource (FvDevice
);
445 LbaStart
+= BlockMap
->Length
;
447 InsertTailList (&FvDevice
->LbaHeader
, &LbaEntry
->Link
);
453 FvDevice
->FwVolHeader
= (EFI_FIRMWARE_VOLUME_HEADER
*) FwCache
;
456 // it is not used any more, so free FwVolHeader
458 FreePool (FwVolHeader
);
461 // Scan to check the free space & File list
463 if ((FvbAttributes
& EFI_FVB2_ERASE_POLARITY
) != 0) {
469 FvDevice
->ErasePolarity
= ErasePolarity
;
472 // go through the whole FV cache, check the consistence of the FV
474 if (FvDevice
->FwVolHeader
->ExtHeaderOffset
!= 0) {
476 // Searching for files starts on an 8 byte aligned boundary after the end of the Extended Header if it exists.
478 FwVolExtHeader
= (EFI_FIRMWARE_VOLUME_EXT_HEADER
*) (UINTN
) (FvDevice
->CachedFv
+ FvDevice
->FwVolHeader
->ExtHeaderOffset
);
479 Ptr
= (UINT8
*) FwVolExtHeader
+ FwVolExtHeader
->ExtHeaderSize
;
480 Ptr
= (UINT8
*) ALIGN_POINTER (Ptr
, 8);
482 Ptr
= (UINT8
*) (UINTN
) (FvDevice
->CachedFv
+ FvDevice
->FwVolHeader
->HeaderLength
);
484 TopFvAddress
= (UINT8
*) (UINTN
) (FvDevice
->CachedFv
+ FvDevice
->FwVolHeader
->FvLength
);
487 // Build FFS list & Free Space List here
489 while (Ptr
< TopFvAddress
) {
490 TestLength
= TopFvAddress
- Ptr
;
492 if (TestLength
> sizeof (EFI_FFS_FILE_HEADER
)) {
493 TestLength
= sizeof (EFI_FFS_FILE_HEADER
);
496 if (IsBufferErased (ErasePolarity
, Ptr
, TestLength
)) {
498 // We found free space
504 TestLength
= TopFvAddress
- Ptr
;
506 if (TestLength
> sizeof (EFI_FFS_FILE_HEADER
)) {
507 TestLength
= sizeof (EFI_FFS_FILE_HEADER
);
510 if (!IsBufferErased (ErasePolarity
, Ptr
, TestLength
)) {
514 FreeSize
+= TestLength
;
516 } while (Ptr
< TopFvAddress
);
518 FreeSpaceEntry
= AllocateZeroPool (sizeof (FREE_SPACE_ENTRY
));
519 if (FreeSpaceEntry
== NULL
) {
520 FreeFvDeviceResource (FvDevice
);
521 return EFI_OUT_OF_RESOURCES
;
524 // Create a Free space entry
526 FreeSpaceEntry
->StartingAddress
= FreeStart
;
527 FreeSpaceEntry
->Length
= FreeSize
;
528 InsertTailList (&FvDevice
->FreeSpaceHeader
, &FreeSpaceEntry
->Link
);
532 // double check boundry
534 if (TestLength
< sizeof (EFI_FFS_FILE_HEADER
)) {
538 if (!IsValidFFSHeader (
539 FvDevice
->ErasePolarity
,
540 (EFI_FFS_FILE_HEADER
*) Ptr
542 FileState
= GetFileState (
543 FvDevice
->ErasePolarity
,
544 (EFI_FFS_FILE_HEADER
*) Ptr
546 if ((FileState
== EFI_FILE_HEADER_INVALID
) || (FileState
== EFI_FILE_HEADER_CONSTRUCTION
)) {
547 if (IS_FFS_FILE2 (Ptr
)) {
548 if (!FvDevice
->IsFfs3Fv
) {
549 DEBUG ((EFI_D_ERROR
, "Found a FFS3 formatted file: %g in a non-FFS3 formatted FV.\n", &((EFI_FFS_FILE_HEADER
*) Ptr
)->Name
));
551 Ptr
= Ptr
+ sizeof (EFI_FFS_FILE_HEADER2
);
553 Ptr
= Ptr
+ sizeof (EFI_FFS_FILE_HEADER
);
560 // File system is corrputed, return
562 FreeFvDeviceResource (FvDevice
);
563 return EFI_VOLUME_CORRUPTED
;
567 if (IS_FFS_FILE2 (Ptr
)) {
568 ASSERT (FFS_FILE2_SIZE (Ptr
) > 0x00FFFFFF);
569 if (!FvDevice
->IsFfs3Fv
) {
570 DEBUG ((EFI_D_ERROR
, "Found a FFS3 formatted file: %g in a non-FFS3 formatted FV.\n", &((EFI_FFS_FILE_HEADER
*) Ptr
)->Name
));
571 Ptr
= Ptr
+ FFS_FILE2_SIZE (Ptr
);
573 // Adjust Ptr to the next 8-byte aligned boundry.
575 while (((UINTN
) Ptr
& 0x07) != 0) {
582 if (IsValidFFSFile (FvDevice
, (EFI_FFS_FILE_HEADER
*) Ptr
)) {
583 FileState
= GetFileState (
584 FvDevice
->ErasePolarity
,
585 (EFI_FFS_FILE_HEADER
*) Ptr
589 // check for non-deleted file
591 if (FileState
!= EFI_FILE_DELETED
) {
593 // Create a FFS list entry for each non-deleted file
595 FfsFileEntry
= AllocateZeroPool (sizeof (FFS_FILE_LIST_ENTRY
));
596 if (FfsFileEntry
== NULL
) {
597 FreeFvDeviceResource (FvDevice
);
598 return EFI_OUT_OF_RESOURCES
;
601 FfsFileEntry
->FfsHeader
= Ptr
;
602 InsertTailList (&FvDevice
->FfsFileListHeader
, &FfsFileEntry
->Link
);
605 if (IS_FFS_FILE2 (Ptr
)) {
606 Ptr
= Ptr
+ FFS_FILE2_SIZE (Ptr
);
608 Ptr
= Ptr
+ FFS_FILE_SIZE (Ptr
);
612 // Adjust Ptr to the next 8-byte aligned boundry.
614 while (((UINTN
) Ptr
& 0x07) != 0) {
619 // File system is corrupted, return
621 FreeFvDeviceResource (FvDevice
);
622 return EFI_VOLUME_CORRUPTED
;
626 FvDevice
->CurrentFfsFile
= NULL
;
632 Entry point function does install/reinstall FV2 protocol with full functionality.
634 @param ImageHandle A handle for the image that is initializing this driver
635 @param SystemTable A pointer to the EFI system table
637 @retval EFI_SUCCESS At least one Fv protocol install/reinstall successfully.
638 @retval EFI_NOT_FOUND No FV protocol install/reinstall successfully.
643 IN EFI_HANDLE ImageHandle
,
644 IN EFI_SYSTEM_TABLE
*SystemTable
648 EFI_HANDLE
*HandleBuffer
;
651 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*Fvb
;
652 EFI_FIRMWARE_VOLUME2_PROTOCOL
*Fv
;
654 EFI_FIRMWARE_VOLUME_HEADER
*FwVolHeader
;
658 DEBUG ((EFI_D_INFO
, "=========FwVol writable driver installed\n"));
661 // Locate all handles of Fvb protocol
663 Status
= gBS
->LocateHandleBuffer (
665 &gEfiFirmwareVolumeBlockProtocolGuid
,
670 if (EFI_ERROR (Status
)) {
671 return EFI_NOT_FOUND
;
674 for (Index
= 0; Index
< HandleCount
; Index
+= 1) {
675 Status
= gBS
->HandleProtocol (
677 &gEfiFirmwareVolumeBlockProtocolGuid
,
680 if (EFI_ERROR (Status
)) {
685 Status
= GetFwVolHeader (Fvb
, &FwVolHeader
);
686 if (EFI_ERROR (Status
)) {
689 ASSERT (FwVolHeader
!= NULL
);
690 FreePool (FwVolHeader
);
694 // Check if there is an FV protocol already installed in that handle
696 Status
= gBS
->HandleProtocol (
698 &gEfiFirmwareVolume2ProtocolGuid
,
701 if (!EFI_ERROR (Status
)) {
705 // FwVol protocol on the handle so create a new one
707 FvDevice
= AllocateZeroPool (sizeof (FV_DEVICE
));
708 if (FvDevice
== NULL
) {
712 FvDevice
->Signature
= FV_DEVICE_SIGNATURE
;
716 // Firmware Volume Protocol interface
718 FvDevice
->Fv
.GetVolumeAttributes
= FvGetVolumeAttributes
;
719 FvDevice
->Fv
.SetVolumeAttributes
= FvSetVolumeAttributes
;
720 FvDevice
->Fv
.ReadFile
= FvReadFile
;
721 FvDevice
->Fv
.ReadSection
= FvReadFileSection
;
722 FvDevice
->Fv
.WriteFile
= FvWriteFile
;
723 FvDevice
->Fv
.GetNextFile
= FvGetNextFile
;
724 FvDevice
->Fv
.KeySize
= KEYSIZE
;
725 FvDevice
->Fv
.GetInfo
= FvGetVolumeInfo
;
726 FvDevice
->Fv
.SetInfo
= FvSetVolumeInfo
;
727 FvDevice
->Fv
.ParentHandle
= Fvb
->ParentHandle
;
729 Status
= FvCheck (FvDevice
);
730 if (EFI_ERROR (Status
)) {
732 // The file system is not consistence
738 FwVolInheritAuthenticationStatus (FvDevice
);
742 // Reinstall an New FV protocol
744 // FvDevice = FV_DEVICE_FROM_THIS (Fv);
745 // FvDevice->Fvb = Fvb;
746 // FreeFvDeviceResource (FvDevice);
748 Status
= gBS
->ReinstallProtocolInterface (
750 &gEfiFirmwareVolume2ProtocolGuid
,
754 if (!EFI_ERROR (Status
)) {
760 DEBUG ((EFI_D_INFO
, "Reinstall FV protocol as writable - %r\n", Status
));
761 ASSERT_EFI_ERROR (Status
);
764 // Install an New FV protocol
766 Status
= gBS
->InstallProtocolInterface (
768 &gEfiFirmwareVolume2ProtocolGuid
,
769 EFI_NATIVE_INTERFACE
,
772 if (!EFI_ERROR (Status
)) {
778 DEBUG ((EFI_D_INFO
, "Install FV protocol as writable - %r\n", Status
));
779 ASSERT_EFI_ERROR (Status
);
785 // As long as one Fv protocol install/reinstall successfully,
786 // success should return to ensure this image will be not unloaded.
787 // Otherwise, new Fv protocols are corrupted by other loaded driver.
794 // No FV protocol install/reinstall successfully.
795 // EFI_NOT_FOUND should return to ensure this image will be unloaded.
797 return EFI_NOT_FOUND
;