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 - 2010, 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
;
210 EFI_FFS_FILE_STATE FileState
;
213 EFI_PHYSICAL_ADDRESS BaseAddress
;
217 Status
= Fvb
->GetAttributes (Fvb
, &FvbAttributes
);
218 if (EFI_ERROR (Status
)) {
222 InitializeListHead (&FvDevice
->LbaHeader
);
223 InitializeListHead (&FvDevice
->FreeSpaceHeader
);
224 InitializeListHead (&FvDevice
->FfsFileListHeader
);
227 Status
= GetFwVolHeader (Fvb
, &FwVolHeader
);
228 if (EFI_ERROR (Status
)) {
231 ASSERT (FwVolHeader
!= NULL
);
234 // Double Check firmware volume header here
236 if (!VerifyFvHeaderChecksum (FwVolHeader
)) {
237 FreePool (FwVolHeader
);
238 return EFI_VOLUME_CORRUPTED
;
241 BlockMap
= FwVolHeader
->BlockMap
;
244 // FwVolHeader->FvLength is the whole FV length including FV header
246 FwCache
= AllocateZeroPool ((UINTN
) FwVolHeader
->FvLength
);
247 if (FwCache
== NULL
) {
248 FreePool (FwVolHeader
);
249 return EFI_OUT_OF_RESOURCES
;
252 FvDevice
->CachedFv
= (EFI_PHYSICAL_ADDRESS
) (UINTN
) FwCache
;
261 if ((FvbAttributes
& EFI_FVB2_MEMORY_MAPPED
) != 0) {
263 // Get volume base address
265 Status
= Fvb
->GetPhysicalAddress (Fvb
, &BaseAddress
);
266 if (EFI_ERROR (Status
)) {
267 FreePool (FwVolHeader
);
271 Ptr
= (UINT8
*) ((UINTN
) BaseAddress
);
273 DEBUG((EFI_D_INFO
, "Fv Base Address is 0x%LX\n", BaseAddress
));
276 // Copy whole FV into the memory
278 while ((BlockMap
->NumBlocks
!= 0) || (BlockMap
->Length
!= 0)) {
280 for (Index
= 0; Index
< BlockMap
->NumBlocks
; Index
++) {
281 LbaEntry
= AllocatePool (sizeof (LBA_ENTRY
));
282 if (LbaEntry
== NULL
) {
283 FreePool (FwVolHeader
);
284 FreeFvDeviceResource (FvDevice
);
285 return EFI_OUT_OF_RESOURCES
;
288 LbaEntry
->LbaIndex
= LbaIndex
;
289 LbaEntry
->StartingAddress
= LbaStart
;
290 LbaEntry
->BlockLength
= BlockMap
->Length
;
293 // Copy each LBA into memory
295 if ((FvbAttributes
& EFI_FVB2_MEMORY_MAPPED
) != 0) {
297 CopyMem (LbaStart
, Ptr
, BlockMap
->Length
);
298 Ptr
+= BlockMap
->Length
;
302 Size
= BlockMap
->Length
;
311 // Not check EFI_BAD_BUFFER_SIZE, for Size = BlockMap->Length
313 if (EFI_ERROR (Status
)) {
314 FreePool (FwVolHeader
);
315 FreeFvDeviceResource (FvDevice
);
322 LbaStart
+= BlockMap
->Length
;
324 InsertTailList (&FvDevice
->LbaHeader
, &LbaEntry
->Link
);
330 FvDevice
->FwVolHeader
= (EFI_FIRMWARE_VOLUME_HEADER
*) FwCache
;
333 // it is not used any more, so free FwVolHeader
335 FreePool (FwVolHeader
);
338 // Scan to check the free space & File list
340 if ((FvbAttributes
& EFI_FVB2_ERASE_POLARITY
) != 0) {
346 FvDevice
->ErasePolarity
= ErasePolarity
;
349 // go through the whole FV cache, check the consistence of the FV
351 Ptr
= (UINT8
*) (UINTN
) (FvDevice
->CachedFv
+ FvDevice
->FwVolHeader
->HeaderLength
);
352 TopFvAddress
= (UINT8
*) (UINTN
) (FvDevice
->CachedFv
+ FvDevice
->FwVolHeader
->FvLength
- 1);
355 // Build FFS list & Free Space List here
357 while (Ptr
<= TopFvAddress
) {
358 TestLength
= TopFvAddress
- Ptr
+ 1;
360 if (TestLength
> sizeof (EFI_FFS_FILE_HEADER
)) {
361 TestLength
= sizeof (EFI_FFS_FILE_HEADER
);
364 if (IsBufferErased (ErasePolarity
, Ptr
, TestLength
)) {
366 // We found free space
372 TestLength
= TopFvAddress
- Ptr
+ 1;
374 if (TestLength
> sizeof (EFI_FFS_FILE_HEADER
)) {
375 TestLength
= sizeof (EFI_FFS_FILE_HEADER
);
378 if (!IsBufferErased (ErasePolarity
, Ptr
, TestLength
)) {
382 FreeSize
+= TestLength
;
384 } while (Ptr
<= TopFvAddress
);
386 FreeSpaceEntry
= AllocateZeroPool (sizeof (FREE_SPACE_ENTRY
));
387 if (FreeSpaceEntry
== NULL
) {
388 FreeFvDeviceResource (FvDevice
);
389 return EFI_OUT_OF_RESOURCES
;
392 // Create a Free space entry
394 FreeSpaceEntry
->StartingAddress
= FreeStart
;
395 FreeSpaceEntry
->Length
= FreeSize
;
396 InsertTailList (&FvDevice
->FreeSpaceHeader
, &FreeSpaceEntry
->Link
);
400 // double check boundry
402 if (TestLength
< sizeof (EFI_FFS_FILE_HEADER
)) {
406 if (!IsValidFFSHeader (
407 FvDevice
->ErasePolarity
,
408 (EFI_FFS_FILE_HEADER
*) Ptr
410 FileState
= GetFileState (
411 FvDevice
->ErasePolarity
,
412 (EFI_FFS_FILE_HEADER
*) Ptr
414 if ((FileState
== EFI_FILE_HEADER_INVALID
) || (FileState
== EFI_FILE_HEADER_CONSTRUCTION
)) {
415 Ptr
+= sizeof (EFI_FFS_FILE_HEADER
);
421 // File system is corrputed, return
423 FreeFvDeviceResource (FvDevice
);
424 return EFI_VOLUME_CORRUPTED
;
428 if (IsValidFFSFile (FvDevice
, (EFI_FFS_FILE_HEADER
*) Ptr
)) {
429 FileLength
= *(UINT32
*) ((EFI_FFS_FILE_HEADER
*) Ptr
)->Size
& 0x00FFFFFF;
430 FileState
= GetFileState (
431 FvDevice
->ErasePolarity
,
432 (EFI_FFS_FILE_HEADER
*) Ptr
436 // check for non-deleted file
438 if (FileState
!= EFI_FILE_DELETED
) {
440 // Create a FFS list entry for each non-deleted file
442 FfsFileEntry
= AllocateZeroPool (sizeof (FFS_FILE_LIST_ENTRY
));
443 if (FfsFileEntry
== NULL
) {
444 FreeFvDeviceResource (FvDevice
);
445 return EFI_OUT_OF_RESOURCES
;
448 FfsFileEntry
->FfsHeader
= Ptr
;
449 InsertTailList (&FvDevice
->FfsFileListHeader
, &FfsFileEntry
->Link
);
455 // Adjust Ptr to the next 8-byte aligned boundry.
457 while (((UINTN
) Ptr
& 0x07) != 0) {
462 // File system is corrupted, return
464 FreeFvDeviceResource (FvDevice
);
465 return EFI_VOLUME_CORRUPTED
;
469 FvDevice
->CurrentFfsFile
= NULL
;
475 Entry point function does install/reinstall FV2 protocol with full functionality.
477 @param ImageHandle A handle for the image that is initializing this driver
478 @param SystemTable A pointer to the EFI system table
480 @retval EFI_SUCCESS At least one Fv protocol install/reinstall successfully.
481 @retval EFI_NOT_FOUND No FV protocol install/reinstall successfully.
486 IN EFI_HANDLE ImageHandle
,
487 IN EFI_SYSTEM_TABLE
*SystemTable
491 EFI_HANDLE
*HandleBuffer
;
494 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*Fvb
;
495 EFI_FIRMWARE_VOLUME2_PROTOCOL
*Fv
;
497 EFI_FIRMWARE_VOLUME_HEADER
*FwVolHeader
;
501 DEBUG ((EFI_D_INFO
, "=========FwVol writable driver installed\n"));
504 // Locate all handles of Fvb protocol
506 Status
= gBS
->LocateHandleBuffer (
508 &gEfiFirmwareVolumeBlockProtocolGuid
,
513 if (EFI_ERROR (Status
)) {
514 return EFI_NOT_FOUND
;
517 // Get FV with gEfiFirmwareFileSystemGuid
519 for (Index
= 0; Index
< HandleCount
; Index
+= 1) {
520 Status
= gBS
->HandleProtocol (
522 &gEfiFirmwareVolumeBlockProtocolGuid
,
525 if (EFI_ERROR (Status
)) {
530 Status
= GetFwVolHeader (Fvb
, &FwVolHeader
);
531 if (EFI_ERROR (Status
)) {
534 ASSERT (FwVolHeader
!= NULL
);
536 // Check to see that the file system is indeed formatted in a way we can
540 &FwVolHeader
->FileSystemGuid
,
541 &gEfiFirmwareFileSystem2Guid
543 FreePool (FwVolHeader
);
546 FreePool (FwVolHeader
);
550 // Check if there is an FV protocol already installed in that handle
552 Status
= gBS
->HandleProtocol (
554 &gEfiFirmwareVolume2ProtocolGuid
,
557 if (!EFI_ERROR (Status
)) {
561 // FwVol protocol on the handle so create a new one
563 FvDevice
= AllocateZeroPool (sizeof (FV_DEVICE
));
564 if (FvDevice
== NULL
) {
568 FvDevice
->Signature
= FV_DEVICE_SIGNATURE
;
572 // Firmware Volume Protocol interface
574 FvDevice
->Fv
.GetVolumeAttributes
= FvGetVolumeAttributes
;
575 FvDevice
->Fv
.SetVolumeAttributes
= FvSetVolumeAttributes
;
576 FvDevice
->Fv
.ReadFile
= FvReadFile
;
577 FvDevice
->Fv
.ReadSection
= FvReadFileSection
;
578 FvDevice
->Fv
.WriteFile
= FvWriteFile
;
579 FvDevice
->Fv
.GetNextFile
= FvGetNextFile
;
580 FvDevice
->Fv
.KeySize
= KEYSIZE
;
581 FvDevice
->Fv
.GetInfo
= FvGetVolumeInfo
;
582 FvDevice
->Fv
.SetInfo
= FvSetVolumeInfo
;
584 Status
= FvCheck (FvDevice
);
585 if (EFI_ERROR (Status
)) {
587 // The file system is not consistence
595 // Reinstall an New FV protocol
597 // FvDevice = FV_DEVICE_FROM_THIS (Fv);
598 // FvDevice->Fvb = Fvb;
599 // FreeFvDeviceResource (FvDevice);
601 Status
= gBS
->ReinstallProtocolInterface (
603 &gEfiFirmwareVolume2ProtocolGuid
,
607 if (!EFI_ERROR (Status
)) {
613 DEBUG ((EFI_D_INFO
, "Reinstall FV protocol as writable - %r\n", Status
));
614 ASSERT_EFI_ERROR (Status
);
617 // Install an New FV protocol
619 Status
= gBS
->InstallProtocolInterface (
621 &gEfiFirmwareVolume2ProtocolGuid
,
622 EFI_NATIVE_INTERFACE
,
625 if (!EFI_ERROR (Status
)) {
631 DEBUG ((EFI_D_INFO
, "Install FV protocol as writable - %r\n", Status
));
632 ASSERT_EFI_ERROR (Status
);
638 // As long as one Fv protocol install/reinstall successfully,
639 // success should return to ensure this image will be not unloaded.
640 // Otherwise, new Fv protocols are corrupted by other loaded driver.
647 // No FV protocol install/reinstall successfully.
648 // EFI_NOT_FOUND should return to ensure this image will be unloaded.
650 return EFI_NOT_FOUND
;