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 - 2012, 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.
40 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*Fvb
,
41 OUT EFI_FIRMWARE_VOLUME_HEADER
**FwVolHeader
45 EFI_FIRMWARE_VOLUME_HEADER TempFvh
;
46 EFI_FVB_ATTRIBUTES_2 FvbAttributes
;
48 EFI_PHYSICAL_ADDRESS BaseAddress
;
51 // Determine the real length of FV header
53 Status
= Fvb
->GetAttributes (
57 if (EFI_ERROR (Status
)) {
61 if ((FvbAttributes
& EFI_FVB2_READ_STATUS
) == 0) {
62 return EFI_ACCESS_DENIED
;
66 // Just avoid compiling warning
69 FvhLength
= sizeof (EFI_FIRMWARE_VOLUME_HEADER
);
72 // memory-mapped FV and non memory-mapped has different ways to read
74 if ((FvbAttributes
& EFI_FVB2_MEMORY_MAPPED
) != 0) {
75 Status
= Fvb
->GetPhysicalAddress (
79 if (EFI_ERROR (Status
)) {
82 CopyMem (&TempFvh
, (VOID
*) (UINTN
) BaseAddress
, FvhLength
);
93 *FwVolHeader
= AllocatePool (TempFvh
.HeaderLength
);
94 if (*FwVolHeader
== NULL
) {
95 return EFI_OUT_OF_RESOURCES
;
98 // Read the whole header
100 if ((FvbAttributes
& EFI_FVB2_MEMORY_MAPPED
) != 0) {
101 CopyMem (*FwVolHeader
, (VOID
*) (UINTN
) BaseAddress
, TempFvh
.HeaderLength
);
104 // Assumed the first block is bigger than the length of Fv headder
106 FvhLength
= TempFvh
.HeaderLength
;
112 (UINT8
*) *FwVolHeader
115 // Check whether Read successes.
117 if (EFI_ERROR (Status
)) {
118 FreePool (*FwVolHeader
);
128 Free FvDevice resource when error happens.
130 @param FvDevice Pointer to the FvDevice to be freed.
133 FreeFvDeviceResource (
134 IN FV_DEVICE
*FvDevice
138 FREE_SPACE_ENTRY
*FreeSpaceEntry
;
139 FFS_FILE_LIST_ENTRY
*FfsFileEntry
;
140 LIST_ENTRY
*NextEntry
;
145 LbaEntry
= (LBA_ENTRY
*) FvDevice
->LbaHeader
.ForwardLink
;
146 while (&LbaEntry
->Link
!= &FvDevice
->LbaHeader
) {
147 NextEntry
= (&LbaEntry
->Link
)->ForwardLink
;
149 LbaEntry
= (LBA_ENTRY
*) NextEntry
;
152 // Free File List Entry
154 FfsFileEntry
= (FFS_FILE_LIST_ENTRY
*) FvDevice
->FfsFileListHeader
.ForwardLink
;
155 while (&FfsFileEntry
->Link
!= &FvDevice
->FfsFileListHeader
) {
156 NextEntry
= (&FfsFileEntry
->Link
)->ForwardLink
;
157 FreePool (FfsFileEntry
);
158 FfsFileEntry
= (FFS_FILE_LIST_ENTRY
*) NextEntry
;
163 FreeSpaceEntry
= (FREE_SPACE_ENTRY
*) FvDevice
->FreeSpaceHeader
.ForwardLink
;
164 while (&FreeSpaceEntry
->Link
!= &FvDevice
->FreeSpaceHeader
) {
165 NextEntry
= (&FreeSpaceEntry
->Link
)->ForwardLink
;
166 FreePool (FreeSpaceEntry
);
167 FreeSpaceEntry
= (FREE_SPACE_ENTRY
*) NextEntry
;
172 FreePool ((UINT8
*) (UINTN
) FvDevice
->CachedFv
);
179 Firmware volume inherits authentication status from the FV image file and section(in another firmware volume)
182 @param FvDevice A pointer to the FvDevice.
186 FwVolInheritAuthenticationStatus (
187 IN FV_DEVICE
*FvDevice
191 EFI_FIRMWARE_VOLUME_HEADER
*CachedFvHeader
;
192 EFI_FIRMWARE_VOLUME_EXT_HEADER
*CachedFvExtHeader
;
193 EFI_FIRMWARE_VOLUME2_PROTOCOL
*ParentFvProtocol
;
195 EFI_GUID FileNameGuid
;
196 EFI_FV_FILETYPE FileType
;
197 EFI_FV_FILE_ATTRIBUTES FileAttributes
;
199 EFI_SECTION_TYPE SectionType
;
200 UINT32 AuthenticationStatus
;
201 EFI_FIRMWARE_VOLUME_HEADER
*FvHeader
;
202 EFI_FIRMWARE_VOLUME_EXT_HEADER
*FvExtHeader
;
205 CachedFvHeader
= (EFI_FIRMWARE_VOLUME_HEADER
*) (UINTN
) FvDevice
->CachedFv
;
207 if (FvDevice
->Fv
.ParentHandle
!= NULL
) {
209 // By Parent Handle, find out the FV image file and section(in another firmware volume) where the firmware volume came from
211 Status
= gBS
->HandleProtocol (FvDevice
->Fv
.ParentHandle
, &gEfiFirmwareVolume2ProtocolGuid
, (VOID
**) &ParentFvProtocol
);
212 if (!EFI_ERROR (Status
) && (ParentFvProtocol
!= NULL
)) {
215 FileType
= EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE
;
216 Status
= ParentFvProtocol
->GetNextFile (
224 if (EFI_ERROR (Status
)) {
228 SectionType
= EFI_SECTION_FIRMWARE_VOLUME_IMAGE
;
231 Status
= ParentFvProtocol
->ReadSection (
238 &AuthenticationStatus
240 if (!EFI_ERROR (Status
)) {
241 if ((FvHeader
->FvLength
== CachedFvHeader
->FvLength
) &&
242 (FvHeader
->ExtHeaderOffset
== CachedFvHeader
->ExtHeaderOffset
)) {
243 if (FvHeader
->ExtHeaderOffset
!=0) {
245 // Both FVs contain extension header, then compare their FV Name GUID
247 FvExtHeader
= (EFI_FIRMWARE_VOLUME_EXT_HEADER
*) ((UINTN
) FvHeader
+ FvHeader
->ExtHeaderOffset
);
248 CachedFvExtHeader
= (EFI_FIRMWARE_VOLUME_EXT_HEADER
*) ((UINTN
) CachedFvHeader
+ CachedFvHeader
->ExtHeaderOffset
);
249 if (CompareGuid (&FvExtHeader
->FvName
, &CachedFvExtHeader
->FvName
)) {
251 // Found the FV image section where the firmware volume came from,
252 // and then inherit authentication status from it.
254 FvDevice
->AuthenticationStatus
= AuthenticationStatus
;
255 FreePool ((VOID
*) FvHeader
);
260 // Both FVs don't contain extension header, then compare their whole FV Image.
262 if (CompareMem ((VOID
*) FvHeader
, (VOID
*) CachedFvHeader
, (UINTN
) FvHeader
->FvLength
) == 0) {
264 // Found the FV image section where the firmware volume came from
265 // and then inherit authentication status from it.
267 FvDevice
->AuthenticationStatus
= AuthenticationStatus
;
268 FreePool ((VOID
*) FvHeader
);
273 FreePool ((VOID
*) FvHeader
);
281 Check if an FV is consistent and allocate cache for it.
283 @param FvDevice A pointer to the FvDevice to be checked.
285 @retval EFI_OUT_OF_RESOURCES No enough buffer could be allocated.
286 @retval EFI_VOLUME_CORRUPTED File system is corrupted.
287 @retval EFI_SUCCESS FV is consistent and cache is allocated.
292 IN FV_DEVICE
*FvDevice
296 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*Fvb
;
297 EFI_FVB_ATTRIBUTES_2 FvbAttributes
;
298 EFI_FV_BLOCK_MAP_ENTRY
*BlockMap
;
299 EFI_FIRMWARE_VOLUME_HEADER
*FwVolHeader
;
300 EFI_FIRMWARE_VOLUME_EXT_HEADER
*FwVolExtHeader
;
303 FREE_SPACE_ENTRY
*FreeSpaceEntry
;
304 FFS_FILE_LIST_ENTRY
*FfsFileEntry
;
313 EFI_FFS_FILE_STATE FileState
;
316 EFI_PHYSICAL_ADDRESS BaseAddress
;
320 Status
= Fvb
->GetAttributes (Fvb
, &FvbAttributes
);
321 if (EFI_ERROR (Status
)) {
325 InitializeListHead (&FvDevice
->LbaHeader
);
326 InitializeListHead (&FvDevice
->FreeSpaceHeader
);
327 InitializeListHead (&FvDevice
->FfsFileListHeader
);
330 Status
= GetFwVolHeader (Fvb
, &FwVolHeader
);
331 if (EFI_ERROR (Status
)) {
334 ASSERT (FwVolHeader
!= NULL
);
336 FvDevice
->IsFfs3Fv
= CompareGuid (&FwVolHeader
->FileSystemGuid
, &gEfiFirmwareFileSystem3Guid
);
339 // Double Check firmware volume header here
341 if (!VerifyFvHeaderChecksum (FwVolHeader
)) {
342 FreePool (FwVolHeader
);
343 return EFI_VOLUME_CORRUPTED
;
346 BlockMap
= FwVolHeader
->BlockMap
;
349 // FwVolHeader->FvLength is the whole FV length including FV header
351 FwCache
= AllocateZeroPool ((UINTN
) FwVolHeader
->FvLength
);
352 if (FwCache
== NULL
) {
353 FreePool (FwVolHeader
);
354 return EFI_OUT_OF_RESOURCES
;
357 FvDevice
->CachedFv
= (EFI_PHYSICAL_ADDRESS
) (UINTN
) FwCache
;
366 if ((FvbAttributes
& EFI_FVB2_MEMORY_MAPPED
) != 0) {
368 // Get volume base address
370 Status
= Fvb
->GetPhysicalAddress (Fvb
, &BaseAddress
);
371 if (EFI_ERROR (Status
)) {
372 FreePool (FwVolHeader
);
376 Ptr
= (UINT8
*) ((UINTN
) BaseAddress
);
378 DEBUG((EFI_D_INFO
, "Fv Base Address is 0x%LX\n", BaseAddress
));
381 // Copy whole FV into the memory
383 while ((BlockMap
->NumBlocks
!= 0) || (BlockMap
->Length
!= 0)) {
385 for (Index
= 0; Index
< BlockMap
->NumBlocks
; Index
++) {
386 LbaEntry
= AllocatePool (sizeof (LBA_ENTRY
));
387 if (LbaEntry
== NULL
) {
388 FreePool (FwVolHeader
);
389 FreeFvDeviceResource (FvDevice
);
390 return EFI_OUT_OF_RESOURCES
;
393 LbaEntry
->LbaIndex
= LbaIndex
;
394 LbaEntry
->StartingAddress
= LbaStart
;
395 LbaEntry
->BlockLength
= BlockMap
->Length
;
398 // Copy each LBA into memory
400 if ((FvbAttributes
& EFI_FVB2_MEMORY_MAPPED
) != 0) {
402 CopyMem (LbaStart
, Ptr
, BlockMap
->Length
);
403 Ptr
+= BlockMap
->Length
;
407 Size
= BlockMap
->Length
;
416 // Not check EFI_BAD_BUFFER_SIZE, for Size = BlockMap->Length
418 if (EFI_ERROR (Status
)) {
419 FreePool (FwVolHeader
);
420 FreeFvDeviceResource (FvDevice
);
427 LbaStart
+= BlockMap
->Length
;
429 InsertTailList (&FvDevice
->LbaHeader
, &LbaEntry
->Link
);
435 FvDevice
->FwVolHeader
= (EFI_FIRMWARE_VOLUME_HEADER
*) FwCache
;
438 // it is not used any more, so free FwVolHeader
440 FreePool (FwVolHeader
);
443 // Scan to check the free space & File list
445 if ((FvbAttributes
& EFI_FVB2_ERASE_POLARITY
) != 0) {
451 FvDevice
->ErasePolarity
= ErasePolarity
;
454 // go through the whole FV cache, check the consistence of the FV
456 if (FvDevice
->FwVolHeader
->ExtHeaderOffset
!= 0) {
458 // Searching for files starts on an 8 byte aligned boundary after the end of the Extended Header if it exists.
460 FwVolExtHeader
= (EFI_FIRMWARE_VOLUME_EXT_HEADER
*) (UINTN
) (FvDevice
->CachedFv
+ FvDevice
->FwVolHeader
->ExtHeaderOffset
);
461 Ptr
= (UINT8
*) FwVolExtHeader
+ FwVolExtHeader
->ExtHeaderSize
;
462 Ptr
= (UINT8
*) ALIGN_POINTER (Ptr
, 8);
464 Ptr
= (UINT8
*) (UINTN
) (FvDevice
->CachedFv
+ FvDevice
->FwVolHeader
->HeaderLength
);
466 TopFvAddress
= (UINT8
*) (UINTN
) (FvDevice
->CachedFv
+ FvDevice
->FwVolHeader
->FvLength
);
469 // Build FFS list & Free Space List here
471 while (Ptr
< TopFvAddress
) {
472 TestLength
= TopFvAddress
- Ptr
;
474 if (TestLength
> sizeof (EFI_FFS_FILE_HEADER
)) {
475 TestLength
= sizeof (EFI_FFS_FILE_HEADER
);
478 if (IsBufferErased (ErasePolarity
, Ptr
, TestLength
)) {
480 // We found free space
486 TestLength
= TopFvAddress
- Ptr
;
488 if (TestLength
> sizeof (EFI_FFS_FILE_HEADER
)) {
489 TestLength
= sizeof (EFI_FFS_FILE_HEADER
);
492 if (!IsBufferErased (ErasePolarity
, Ptr
, TestLength
)) {
496 FreeSize
+= TestLength
;
498 } while (Ptr
< TopFvAddress
);
500 FreeSpaceEntry
= AllocateZeroPool (sizeof (FREE_SPACE_ENTRY
));
501 if (FreeSpaceEntry
== NULL
) {
502 FreeFvDeviceResource (FvDevice
);
503 return EFI_OUT_OF_RESOURCES
;
506 // Create a Free space entry
508 FreeSpaceEntry
->StartingAddress
= FreeStart
;
509 FreeSpaceEntry
->Length
= FreeSize
;
510 InsertTailList (&FvDevice
->FreeSpaceHeader
, &FreeSpaceEntry
->Link
);
514 // double check boundry
516 if (TestLength
< sizeof (EFI_FFS_FILE_HEADER
)) {
520 if (!IsValidFFSHeader (
521 FvDevice
->ErasePolarity
,
522 (EFI_FFS_FILE_HEADER
*) Ptr
524 FileState
= GetFileState (
525 FvDevice
->ErasePolarity
,
526 (EFI_FFS_FILE_HEADER
*) Ptr
528 if ((FileState
== EFI_FILE_HEADER_INVALID
) || (FileState
== EFI_FILE_HEADER_CONSTRUCTION
)) {
529 if (IS_FFS_FILE2 (Ptr
)) {
530 if (!FvDevice
->IsFfs3Fv
) {
531 DEBUG ((EFI_D_ERROR
, "Found a FFS3 formatted file: %g in a non-FFS3 formatted FV.\n", &((EFI_FFS_FILE_HEADER
*) Ptr
)->Name
));
533 Ptr
= Ptr
+ sizeof (EFI_FFS_FILE_HEADER2
);
535 Ptr
= Ptr
+ sizeof (EFI_FFS_FILE_HEADER
);
542 // File system is corrputed, return
544 FreeFvDeviceResource (FvDevice
);
545 return EFI_VOLUME_CORRUPTED
;
549 if (IS_FFS_FILE2 (Ptr
)) {
550 ASSERT (FFS_FILE2_SIZE (Ptr
) > 0x00FFFFFF);
551 if (!FvDevice
->IsFfs3Fv
) {
552 DEBUG ((EFI_D_ERROR
, "Found a FFS3 formatted file: %g in a non-FFS3 formatted FV.\n", &((EFI_FFS_FILE_HEADER
*) Ptr
)->Name
));
553 Ptr
= Ptr
+ FFS_FILE2_SIZE (Ptr
);
555 // Adjust Ptr to the next 8-byte aligned boundry.
557 while (((UINTN
) Ptr
& 0x07) != 0) {
564 if (IsValidFFSFile (FvDevice
, (EFI_FFS_FILE_HEADER
*) Ptr
)) {
565 FileState
= GetFileState (
566 FvDevice
->ErasePolarity
,
567 (EFI_FFS_FILE_HEADER
*) Ptr
571 // check for non-deleted file
573 if (FileState
!= EFI_FILE_DELETED
) {
575 // Create a FFS list entry for each non-deleted file
577 FfsFileEntry
= AllocateZeroPool (sizeof (FFS_FILE_LIST_ENTRY
));
578 if (FfsFileEntry
== NULL
) {
579 FreeFvDeviceResource (FvDevice
);
580 return EFI_OUT_OF_RESOURCES
;
583 FfsFileEntry
->FfsHeader
= Ptr
;
584 InsertTailList (&FvDevice
->FfsFileListHeader
, &FfsFileEntry
->Link
);
587 if (IS_FFS_FILE2 (Ptr
)) {
588 Ptr
= Ptr
+ FFS_FILE2_SIZE (Ptr
);
590 Ptr
= Ptr
+ FFS_FILE_SIZE (Ptr
);
594 // Adjust Ptr to the next 8-byte aligned boundry.
596 while (((UINTN
) Ptr
& 0x07) != 0) {
601 // File system is corrupted, return
603 FreeFvDeviceResource (FvDevice
);
604 return EFI_VOLUME_CORRUPTED
;
608 FvDevice
->CurrentFfsFile
= NULL
;
614 Entry point function does install/reinstall FV2 protocol with full functionality.
616 @param ImageHandle A handle for the image that is initializing this driver
617 @param SystemTable A pointer to the EFI system table
619 @retval EFI_SUCCESS At least one Fv protocol install/reinstall successfully.
620 @retval EFI_NOT_FOUND No FV protocol install/reinstall successfully.
625 IN EFI_HANDLE ImageHandle
,
626 IN EFI_SYSTEM_TABLE
*SystemTable
630 EFI_HANDLE
*HandleBuffer
;
633 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*Fvb
;
634 EFI_FIRMWARE_VOLUME2_PROTOCOL
*Fv
;
636 EFI_FIRMWARE_VOLUME_HEADER
*FwVolHeader
;
640 DEBUG ((EFI_D_INFO
, "=========FwVol writable driver installed\n"));
643 // Locate all handles of Fvb protocol
645 Status
= gBS
->LocateHandleBuffer (
647 &gEfiFirmwareVolumeBlockProtocolGuid
,
652 if (EFI_ERROR (Status
)) {
653 return EFI_NOT_FOUND
;
656 for (Index
= 0; Index
< HandleCount
; Index
+= 1) {
657 Status
= gBS
->HandleProtocol (
659 &gEfiFirmwareVolumeBlockProtocolGuid
,
662 if (EFI_ERROR (Status
)) {
667 Status
= GetFwVolHeader (Fvb
, &FwVolHeader
);
668 if (EFI_ERROR (Status
)) {
671 ASSERT (FwVolHeader
!= NULL
);
673 // Check to see that the file system is indeed formatted in a way we can
676 if ((!CompareGuid (&FwVolHeader
->FileSystemGuid
, &gEfiFirmwareFileSystem2Guid
)) &&
677 (!CompareGuid (&FwVolHeader
->FileSystemGuid
, &gEfiFirmwareFileSystem3Guid
))) {
678 FreePool (FwVolHeader
);
681 FreePool (FwVolHeader
);
685 // Check if there is an FV protocol already installed in that handle
687 Status
= gBS
->HandleProtocol (
689 &gEfiFirmwareVolume2ProtocolGuid
,
692 if (!EFI_ERROR (Status
)) {
696 // FwVol protocol on the handle so create a new one
698 FvDevice
= AllocateZeroPool (sizeof (FV_DEVICE
));
699 if (FvDevice
== NULL
) {
703 FvDevice
->Signature
= FV_DEVICE_SIGNATURE
;
707 // Firmware Volume Protocol interface
709 FvDevice
->Fv
.GetVolumeAttributes
= FvGetVolumeAttributes
;
710 FvDevice
->Fv
.SetVolumeAttributes
= FvSetVolumeAttributes
;
711 FvDevice
->Fv
.ReadFile
= FvReadFile
;
712 FvDevice
->Fv
.ReadSection
= FvReadFileSection
;
713 FvDevice
->Fv
.WriteFile
= FvWriteFile
;
714 FvDevice
->Fv
.GetNextFile
= FvGetNextFile
;
715 FvDevice
->Fv
.KeySize
= KEYSIZE
;
716 FvDevice
->Fv
.GetInfo
= FvGetVolumeInfo
;
717 FvDevice
->Fv
.SetInfo
= FvSetVolumeInfo
;
718 FvDevice
->Fv
.ParentHandle
= Fvb
->ParentHandle
;
720 Status
= FvCheck (FvDevice
);
721 if (EFI_ERROR (Status
)) {
723 // The file system is not consistence
729 FwVolInheritAuthenticationStatus (FvDevice
);
733 // Reinstall an New FV protocol
735 // FvDevice = FV_DEVICE_FROM_THIS (Fv);
736 // FvDevice->Fvb = Fvb;
737 // FreeFvDeviceResource (FvDevice);
739 Status
= gBS
->ReinstallProtocolInterface (
741 &gEfiFirmwareVolume2ProtocolGuid
,
745 if (!EFI_ERROR (Status
)) {
751 DEBUG ((EFI_D_INFO
, "Reinstall FV protocol as writable - %r\n", Status
));
752 ASSERT_EFI_ERROR (Status
);
755 // Install an New FV protocol
757 Status
= gBS
->InstallProtocolInterface (
759 &gEfiFirmwareVolume2ProtocolGuid
,
760 EFI_NATIVE_INTERFACE
,
763 if (!EFI_ERROR (Status
)) {
769 DEBUG ((EFI_D_INFO
, "Install FV protocol as writable - %r\n", Status
));
770 ASSERT_EFI_ERROR (Status
);
776 // As long as one Fv protocol install/reinstall successfully,
777 // success should return to ensure this image will be not unloaded.
778 // Otherwise, new Fv protocols are corrupted by other loaded driver.
785 // No FV protocol install/reinstall successfully.
786 // EFI_NOT_FOUND should return to ensure this image will be unloaded.
788 return EFI_NOT_FOUND
;