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 - 2011, 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
);
178 Check if an FV is consistent and allocate cache for it.
180 @param FvDevice A pointer to the FvDevice to be checked.
182 @retval EFI_OUT_OF_RESOURCES No enough buffer could be allocated.
183 @retval EFI_VOLUME_CORRUPTED File system is corrupted.
184 @retval EFI_SUCCESS FV is consistent and cache is allocated.
189 IN FV_DEVICE
*FvDevice
193 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*Fvb
;
194 EFI_FVB_ATTRIBUTES_2 FvbAttributes
;
195 EFI_FV_BLOCK_MAP_ENTRY
*BlockMap
;
196 EFI_FIRMWARE_VOLUME_HEADER
*FwVolHeader
;
199 FREE_SPACE_ENTRY
*FreeSpaceEntry
;
200 FFS_FILE_LIST_ENTRY
*FfsFileEntry
;
209 EFI_FFS_FILE_STATE FileState
;
212 EFI_PHYSICAL_ADDRESS BaseAddress
;
216 Status
= Fvb
->GetAttributes (Fvb
, &FvbAttributes
);
217 if (EFI_ERROR (Status
)) {
221 InitializeListHead (&FvDevice
->LbaHeader
);
222 InitializeListHead (&FvDevice
->FreeSpaceHeader
);
223 InitializeListHead (&FvDevice
->FfsFileListHeader
);
226 Status
= GetFwVolHeader (Fvb
, &FwVolHeader
);
227 if (EFI_ERROR (Status
)) {
230 ASSERT (FwVolHeader
!= NULL
);
232 FvDevice
->IsFfs3Fv
= CompareGuid (&FwVolHeader
->FileSystemGuid
, &gEfiFirmwareFileSystem3Guid
);
235 // Double Check firmware volume header here
237 if (!VerifyFvHeaderChecksum (FwVolHeader
)) {
238 FreePool (FwVolHeader
);
239 return EFI_VOLUME_CORRUPTED
;
242 BlockMap
= FwVolHeader
->BlockMap
;
245 // FwVolHeader->FvLength is the whole FV length including FV header
247 FwCache
= AllocateZeroPool ((UINTN
) FwVolHeader
->FvLength
);
248 if (FwCache
== NULL
) {
249 FreePool (FwVolHeader
);
250 return EFI_OUT_OF_RESOURCES
;
253 FvDevice
->CachedFv
= (EFI_PHYSICAL_ADDRESS
) (UINTN
) FwCache
;
262 if ((FvbAttributes
& EFI_FVB2_MEMORY_MAPPED
) != 0) {
264 // Get volume base address
266 Status
= Fvb
->GetPhysicalAddress (Fvb
, &BaseAddress
);
267 if (EFI_ERROR (Status
)) {
268 FreePool (FwVolHeader
);
272 Ptr
= (UINT8
*) ((UINTN
) BaseAddress
);
274 DEBUG((EFI_D_INFO
, "Fv Base Address is 0x%LX\n", BaseAddress
));
277 // Copy whole FV into the memory
279 while ((BlockMap
->NumBlocks
!= 0) || (BlockMap
->Length
!= 0)) {
281 for (Index
= 0; Index
< BlockMap
->NumBlocks
; Index
++) {
282 LbaEntry
= AllocatePool (sizeof (LBA_ENTRY
));
283 if (LbaEntry
== NULL
) {
284 FreePool (FwVolHeader
);
285 FreeFvDeviceResource (FvDevice
);
286 return EFI_OUT_OF_RESOURCES
;
289 LbaEntry
->LbaIndex
= LbaIndex
;
290 LbaEntry
->StartingAddress
= LbaStart
;
291 LbaEntry
->BlockLength
= BlockMap
->Length
;
294 // Copy each LBA into memory
296 if ((FvbAttributes
& EFI_FVB2_MEMORY_MAPPED
) != 0) {
298 CopyMem (LbaStart
, Ptr
, BlockMap
->Length
);
299 Ptr
+= BlockMap
->Length
;
303 Size
= BlockMap
->Length
;
312 // Not check EFI_BAD_BUFFER_SIZE, for Size = BlockMap->Length
314 if (EFI_ERROR (Status
)) {
315 FreePool (FwVolHeader
);
316 FreeFvDeviceResource (FvDevice
);
323 LbaStart
+= BlockMap
->Length
;
325 InsertTailList (&FvDevice
->LbaHeader
, &LbaEntry
->Link
);
331 FvDevice
->FwVolHeader
= (EFI_FIRMWARE_VOLUME_HEADER
*) FwCache
;
334 // it is not used any more, so free FwVolHeader
336 FreePool (FwVolHeader
);
339 // Scan to check the free space & File list
341 if ((FvbAttributes
& EFI_FVB2_ERASE_POLARITY
) != 0) {
347 FvDevice
->ErasePolarity
= ErasePolarity
;
350 // go through the whole FV cache, check the consistence of the FV
352 Ptr
= (UINT8
*) (UINTN
) (FvDevice
->CachedFv
+ FvDevice
->FwVolHeader
->HeaderLength
);
353 TopFvAddress
= (UINT8
*) (UINTN
) (FvDevice
->CachedFv
+ FvDevice
->FwVolHeader
->FvLength
- 1);
356 // Build FFS list & Free Space List here
358 while (Ptr
<= TopFvAddress
) {
359 TestLength
= TopFvAddress
- Ptr
+ 1;
361 if (TestLength
> sizeof (EFI_FFS_FILE_HEADER
)) {
362 TestLength
= sizeof (EFI_FFS_FILE_HEADER
);
365 if (IsBufferErased (ErasePolarity
, Ptr
, TestLength
)) {
367 // We found free space
373 TestLength
= TopFvAddress
- Ptr
+ 1;
375 if (TestLength
> sizeof (EFI_FFS_FILE_HEADER
)) {
376 TestLength
= sizeof (EFI_FFS_FILE_HEADER
);
379 if (!IsBufferErased (ErasePolarity
, Ptr
, TestLength
)) {
383 FreeSize
+= TestLength
;
385 } while (Ptr
<= TopFvAddress
);
387 FreeSpaceEntry
= AllocateZeroPool (sizeof (FREE_SPACE_ENTRY
));
388 if (FreeSpaceEntry
== NULL
) {
389 FreeFvDeviceResource (FvDevice
);
390 return EFI_OUT_OF_RESOURCES
;
393 // Create a Free space entry
395 FreeSpaceEntry
->StartingAddress
= FreeStart
;
396 FreeSpaceEntry
->Length
= FreeSize
;
397 InsertTailList (&FvDevice
->FreeSpaceHeader
, &FreeSpaceEntry
->Link
);
401 // double check boundry
403 if (TestLength
< sizeof (EFI_FFS_FILE_HEADER
)) {
407 if (!IsValidFFSHeader (
408 FvDevice
->ErasePolarity
,
409 (EFI_FFS_FILE_HEADER
*) Ptr
411 FileState
= GetFileState (
412 FvDevice
->ErasePolarity
,
413 (EFI_FFS_FILE_HEADER
*) Ptr
415 if ((FileState
== EFI_FILE_HEADER_INVALID
) || (FileState
== EFI_FILE_HEADER_CONSTRUCTION
)) {
416 if (IS_FFS_FILE2 (Ptr
)) {
417 if (!FvDevice
->IsFfs3Fv
) {
418 DEBUG ((EFI_D_ERROR
, "Found a FFS3 formatted file: %g in a non-FFS3 formatted FV.\n", &((EFI_FFS_FILE_HEADER
*) Ptr
)->Name
));
420 Ptr
= Ptr
+ sizeof (EFI_FFS_FILE_HEADER2
);
422 Ptr
= Ptr
+ sizeof (EFI_FFS_FILE_HEADER
);
429 // File system is corrputed, return
431 FreeFvDeviceResource (FvDevice
);
432 return EFI_VOLUME_CORRUPTED
;
436 if (IS_FFS_FILE2 (Ptr
)) {
437 ASSERT (FFS_FILE2_SIZE (Ptr
) > 0x00FFFFFF);
438 if (!FvDevice
->IsFfs3Fv
) {
439 DEBUG ((EFI_D_ERROR
, "Found a FFS3 formatted file: %g in a non-FFS3 formatted FV.\n", &((EFI_FFS_FILE_HEADER
*) Ptr
)->Name
));
440 Ptr
= Ptr
+ FFS_FILE2_SIZE (Ptr
);
442 // Adjust Ptr to the next 8-byte aligned boundry.
444 while (((UINTN
) Ptr
& 0x07) != 0) {
451 if (IsValidFFSFile (FvDevice
, (EFI_FFS_FILE_HEADER
*) Ptr
)) {
452 FileState
= GetFileState (
453 FvDevice
->ErasePolarity
,
454 (EFI_FFS_FILE_HEADER
*) Ptr
458 // check for non-deleted file
460 if (FileState
!= EFI_FILE_DELETED
) {
462 // Create a FFS list entry for each non-deleted file
464 FfsFileEntry
= AllocateZeroPool (sizeof (FFS_FILE_LIST_ENTRY
));
465 if (FfsFileEntry
== NULL
) {
466 FreeFvDeviceResource (FvDevice
);
467 return EFI_OUT_OF_RESOURCES
;
470 FfsFileEntry
->FfsHeader
= Ptr
;
471 InsertTailList (&FvDevice
->FfsFileListHeader
, &FfsFileEntry
->Link
);
474 if (IS_FFS_FILE2 (Ptr
)) {
475 Ptr
= Ptr
+ FFS_FILE2_SIZE (Ptr
);
477 Ptr
= Ptr
+ FFS_FILE_SIZE (Ptr
);
481 // Adjust Ptr to the next 8-byte aligned boundry.
483 while (((UINTN
) Ptr
& 0x07) != 0) {
488 // File system is corrupted, return
490 FreeFvDeviceResource (FvDevice
);
491 return EFI_VOLUME_CORRUPTED
;
495 FvDevice
->CurrentFfsFile
= NULL
;
501 Entry point function does install/reinstall FV2 protocol with full functionality.
503 @param ImageHandle A handle for the image that is initializing this driver
504 @param SystemTable A pointer to the EFI system table
506 @retval EFI_SUCCESS At least one Fv protocol install/reinstall successfully.
507 @retval EFI_NOT_FOUND No FV protocol install/reinstall successfully.
512 IN EFI_HANDLE ImageHandle
,
513 IN EFI_SYSTEM_TABLE
*SystemTable
517 EFI_HANDLE
*HandleBuffer
;
520 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*Fvb
;
521 EFI_FIRMWARE_VOLUME2_PROTOCOL
*Fv
;
523 EFI_FIRMWARE_VOLUME_HEADER
*FwVolHeader
;
527 DEBUG ((EFI_D_INFO
, "=========FwVol writable driver installed\n"));
530 // Locate all handles of Fvb protocol
532 Status
= gBS
->LocateHandleBuffer (
534 &gEfiFirmwareVolumeBlockProtocolGuid
,
539 if (EFI_ERROR (Status
)) {
540 return EFI_NOT_FOUND
;
543 for (Index
= 0; Index
< HandleCount
; Index
+= 1) {
544 Status
= gBS
->HandleProtocol (
546 &gEfiFirmwareVolumeBlockProtocolGuid
,
549 if (EFI_ERROR (Status
)) {
554 Status
= GetFwVolHeader (Fvb
, &FwVolHeader
);
555 if (EFI_ERROR (Status
)) {
558 ASSERT (FwVolHeader
!= NULL
);
560 // Check to see that the file system is indeed formatted in a way we can
563 if ((!CompareGuid (&FwVolHeader
->FileSystemGuid
, &gEfiFirmwareFileSystem2Guid
)) &&
564 (!CompareGuid (&FwVolHeader
->FileSystemGuid
, &gEfiFirmwareFileSystem3Guid
))) {
565 FreePool (FwVolHeader
);
568 FreePool (FwVolHeader
);
572 // Check if there is an FV protocol already installed in that handle
574 Status
= gBS
->HandleProtocol (
576 &gEfiFirmwareVolume2ProtocolGuid
,
579 if (!EFI_ERROR (Status
)) {
583 // FwVol protocol on the handle so create a new one
585 FvDevice
= AllocateZeroPool (sizeof (FV_DEVICE
));
586 if (FvDevice
== NULL
) {
590 FvDevice
->Signature
= FV_DEVICE_SIGNATURE
;
594 // Firmware Volume Protocol interface
596 FvDevice
->Fv
.GetVolumeAttributes
= FvGetVolumeAttributes
;
597 FvDevice
->Fv
.SetVolumeAttributes
= FvSetVolumeAttributes
;
598 FvDevice
->Fv
.ReadFile
= FvReadFile
;
599 FvDevice
->Fv
.ReadSection
= FvReadFileSection
;
600 FvDevice
->Fv
.WriteFile
= FvWriteFile
;
601 FvDevice
->Fv
.GetNextFile
= FvGetNextFile
;
602 FvDevice
->Fv
.KeySize
= KEYSIZE
;
603 FvDevice
->Fv
.GetInfo
= FvGetVolumeInfo
;
604 FvDevice
->Fv
.SetInfo
= FvSetVolumeInfo
;
606 Status
= FvCheck (FvDevice
);
607 if (EFI_ERROR (Status
)) {
609 // The file system is not consistence
617 // Reinstall an New FV protocol
619 // FvDevice = FV_DEVICE_FROM_THIS (Fv);
620 // FvDevice->Fvb = Fvb;
621 // FreeFvDeviceResource (FvDevice);
623 Status
= gBS
->ReinstallProtocolInterface (
625 &gEfiFirmwareVolume2ProtocolGuid
,
629 if (!EFI_ERROR (Status
)) {
635 DEBUG ((EFI_D_INFO
, "Reinstall FV protocol as writable - %r\n", Status
));
636 ASSERT_EFI_ERROR (Status
);
639 // Install an New FV protocol
641 Status
= gBS
->InstallProtocolInterface (
643 &gEfiFirmwareVolume2ProtocolGuid
,
644 EFI_NATIVE_INTERFACE
,
647 if (!EFI_ERROR (Status
)) {
653 DEBUG ((EFI_D_INFO
, "Install FV protocol as writable - %r\n", Status
));
654 ASSERT_EFI_ERROR (Status
);
660 // As long as one Fv protocol install/reinstall successfully,
661 // success should return to ensure this image will be not unloaded.
662 // Otherwise, new Fv protocols are corrupted by other loaded driver.
669 // No FV protocol install/reinstall successfully.
670 // EFI_NOT_FOUND should return to ensure this image will be unloaded.
672 return EFI_NOT_FOUND
;