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 - 2008, Intel Corporation. <BR>
7 All rights reserved. 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.
19 #define KEYSIZE sizeof (UINTN)
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 given the supplied FW_VOL_BLOCK_PROTOCOL, allocate a buffer for output and
57 copy the volume header into it.
59 @param Fvb The FW_VOL_BLOCK_PROTOCOL instance from which to
60 read the volume header
61 @param FwVolHeader Pointer to pointer to allocated buffer in which
62 the volume header is returned.
64 @retval EFI_OUT_OF_RESOURCES No enough buffer could be allocated.
65 @retval EFI_SUCCESS Successfully read volume header to the allocated
71 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*Fvb
,
72 OUT EFI_FIRMWARE_VOLUME_HEADER
**FwVolHeader
76 EFI_FIRMWARE_VOLUME_HEADER TempFvh
;
82 //Determine the real length of FV header
84 FvhLength
= sizeof (EFI_FIRMWARE_VOLUME_HEADER
);
85 Status
= Fvb
->Read (Fvb
, 0, 0, &FvhLength
, (UINT8
*)&TempFvh
);
86 if (EFI_ERROR (Status
)) {
91 // Allocate a buffer for the caller
93 *FwVolHeader
= AllocatePool (TempFvh
.HeaderLength
);
94 if (*FwVolHeader
== NULL
) {
95 return EFI_OUT_OF_RESOURCES
;
99 // Copy the standard header into the buffer
101 CopyMem (*FwVolHeader
, &TempFvh
, sizeof (EFI_FIRMWARE_VOLUME_HEADER
));
104 // Read the rest of the header
106 FvhLength
= TempFvh
.HeaderLength
- sizeof (EFI_FIRMWARE_VOLUME_HEADER
);
107 Buffer
= (UINT8
*)*FwVolHeader
+ sizeof (EFI_FIRMWARE_VOLUME_HEADER
);
108 Status
= Fvb
->Read (Fvb
, 0, sizeof (EFI_FIRMWARE_VOLUME_HEADER
), &FvhLength
, Buffer
);
109 if (EFI_ERROR (Status
)) {
111 // Read failed so free buffer
113 CoreFreePool (*FwVolHeader
);
122 Free FvDevice resource when error happens
124 @param FvDevice pointer to the FvDevice to be freed.
128 FreeFvDeviceResource (
129 IN FV_DEVICE
*FvDevice
132 FFS_FILE_LIST_ENTRY
*FfsFileEntry
;
133 LIST_ENTRY
*NextEntry
;
136 // Free File List Entry
138 FfsFileEntry
= (FFS_FILE_LIST_ENTRY
*)FvDevice
->FfsFileListHeader
.ForwardLink
;
139 while (&FfsFileEntry
->Link
!= &FvDevice
->FfsFileListHeader
) {
140 NextEntry
= (&FfsFileEntry
->Link
)->ForwardLink
;
142 if (FfsFileEntry
->StreamHandle
!= 0) {
144 // Close stream and free resources from SEP
146 CloseSectionStream (FfsFileEntry
->StreamHandle
);
149 CoreFreePool (FfsFileEntry
);
151 FfsFileEntry
= (FFS_FILE_LIST_ENTRY
*) NextEntry
;
158 CoreFreePool (FvDevice
->CachedFv
);
161 // Free Volume Header
163 CoreFreePool (FvDevice
->FwVolHeader
);
171 Check if an FV is consistent and allocate cache for it.
173 @param FvDevice A pointer to the FvDevice to be checked.
175 @retval EFI_OUT_OF_RESOURCES No enough buffer could be allocated.
176 @retval EFI_SUCCESS FV is consistent and cache is allocated.
177 @retval EFI_VOLUME_CORRUPTED File system is corrupted.
182 IN OUT FV_DEVICE
*FvDevice
186 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*Fvb
;
187 EFI_FIRMWARE_VOLUME_HEADER
*FwVolHeader
;
188 EFI_FVB_ATTRIBUTES_2 FvbAttributes
;
189 EFI_FV_BLOCK_MAP_ENTRY
*BlockMap
;
190 FFS_FILE_LIST_ENTRY
*FfsFileEntry
;
191 EFI_FFS_FILE_HEADER
*FfsHeader
;
192 UINT8
*CacheLocation
;
198 EFI_FFS_FILE_STATE FileState
;
204 FwVolHeader
= FvDevice
->FwVolHeader
;
206 Status
= Fvb
->GetAttributes (Fvb
, &FvbAttributes
);
207 if (EFI_ERROR (Status
)) {
212 // Size is the size of the FV minus the head. We have already allocated
213 // the header to check to make sure the volume is valid
215 Size
= (UINTN
)(FwVolHeader
->FvLength
- FwVolHeader
->HeaderLength
);
216 FvDevice
->CachedFv
= AllocatePool (Size
);
218 if (FvDevice
->CachedFv
== NULL
) {
219 return EFI_OUT_OF_RESOURCES
;
223 // Remember a pointer to the end fo the CachedFv
225 FvDevice
->EndOfCachedFv
= FvDevice
->CachedFv
+ Size
;
228 // Copy FV minus header into memory using the block map we have all ready
231 BlockMap
= FwVolHeader
->BlockMap
;
232 CacheLocation
= FvDevice
->CachedFv
;
234 LbaOffset
= FwVolHeader
->HeaderLength
;
235 while ((BlockMap
->NumBlocks
!= 0) || (BlockMap
->Length
!= 0)) {
237 for (Index
= 0; Index
< BlockMap
->NumBlocks
; Index
++) {
239 Size
= BlockMap
->Length
;
242 // Cache does not include FV Header
246 Status
= Fvb
->Read (Fvb
,
253 // Not check EFI_BAD_BUFFER_SIZE, for Size = BlockMap->Length
255 if (EFI_ERROR (Status
)) {
260 // After we skip Fv Header always read from start of block
265 CacheLocation
+= Size
;
271 // Scan to check the free space & File list
273 if ((FvbAttributes
& EFI_FVB2_ERASE_POLARITY
) != 0) {
274 FvDevice
->ErasePolarity
= 1;
276 FvDevice
->ErasePolarity
= 0;
281 // go through the whole FV cache, check the consistence of the FV.
282 // Make a linked list off all the Ffs file headers
284 Status
= EFI_SUCCESS
;
285 InitializeListHead (&FvDevice
->FfsFileListHeader
);
290 FfsHeader
= (EFI_FFS_FILE_HEADER
*) FvDevice
->CachedFv
;
291 TopFvAddress
= FvDevice
->EndOfCachedFv
;
292 while ((UINT8
*) FfsHeader
< TopFvAddress
) {
294 TestLength
= TopFvAddress
- ((UINT8
*) FfsHeader
);
295 if (TestLength
> sizeof (EFI_FFS_FILE_HEADER
)) {
296 TestLength
= sizeof (EFI_FFS_FILE_HEADER
);
299 if (IsBufferErased (FvDevice
->ErasePolarity
, FfsHeader
, TestLength
)) {
301 // We have found the free space so we are done!
306 if (!IsValidFfsHeader (FvDevice
->ErasePolarity
, FfsHeader
, &FileState
)) {
307 if ((FileState
== EFI_FILE_HEADER_INVALID
) ||
308 (FileState
== EFI_FILE_HEADER_CONSTRUCTION
)) {
313 // File system is corrputed
315 Status
= EFI_VOLUME_CORRUPTED
;
320 if (!IsValidFfsFile (FvDevice
->ErasePolarity
, FfsHeader
)) {
322 // File system is corrupted
324 Status
= EFI_VOLUME_CORRUPTED
;
329 // Size[3] is a three byte array, read 4 bytes and throw one away
331 FileLength
= *(UINT32
*)&FfsHeader
->Size
[0] & 0x00FFFFFF;
333 FileState
= GetFileState (FvDevice
->ErasePolarity
, FfsHeader
);
336 // check for non-deleted file
338 if (FileState
!= EFI_FILE_DELETED
) {
340 // Create a FFS list entry for each non-deleted file
342 FfsFileEntry
= AllocateZeroPool (sizeof (FFS_FILE_LIST_ENTRY
));
343 if (FfsFileEntry
== NULL
) {
344 Status
= EFI_OUT_OF_RESOURCES
;
348 FfsFileEntry
->FfsHeader
= FfsHeader
;
349 InsertTailList (&FvDevice
->FfsFileListHeader
, &FfsFileEntry
->Link
);
352 FfsHeader
= (EFI_FFS_FILE_HEADER
*)(((UINT8
*)FfsHeader
) + FileLength
);
355 // Adjust pointer to the next 8-byte aligned boundry.
357 FfsHeader
= (EFI_FFS_FILE_HEADER
*)(((UINTN
)FfsHeader
+ 7) & ~0x07);
362 if (EFI_ERROR (Status
)) {
363 FreeFvDeviceResource (FvDevice
);
372 This notification function is invoked when an instance of the
373 EFI_FW_VOLUME_BLOCK_PROTOCOL is produced. It layers an instance of the
374 EFI_FIRMWARE_VOLUME2_PROTOCOL on the same handle. This is the function where
375 the actual initialization of the EFI_FIRMWARE_VOLUME2_PROTOCOL is done.
377 @param Event The event that occured
378 @param Context For EFI compatiblity. Not used.
391 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*Fvb
;
392 EFI_FIRMWARE_VOLUME2_PROTOCOL
*Fv
;
394 EFI_FIRMWARE_VOLUME_HEADER
*FwVolHeader
;
396 // Examine all new handles
400 // Get the next handle
402 BufferSize
= sizeof (Handle
);
403 Status
= CoreLocateHandle (
406 gEfiFwVolBlockNotifyReg
,
412 // If not found, we're done
414 if (EFI_NOT_FOUND
== Status
) {
418 if (EFI_ERROR (Status
)) {
423 // Get the FirmwareVolumeBlock protocol on that handle
425 Status
= CoreHandleProtocol (Handle
, &gEfiFirmwareVolumeBlockProtocolGuid
, (VOID
**)&Fvb
);
426 ASSERT_EFI_ERROR (Status
);
430 // Make sure the Fv Header is O.K.
432 Status
= GetFwVolHeader (Fvb
, &FwVolHeader
);
433 if (EFI_ERROR (Status
)) {
437 if (!VerifyFvHeaderChecksum (FwVolHeader
)) {
438 CoreFreePool (FwVolHeader
);
444 // Check to see that the file system is indeed formatted in a way we can
447 if (!CompareGuid (&FwVolHeader
->FileSystemGuid
, &gEfiFirmwareFileSystem2Guid
)) {
452 // Check if there is an FV protocol already installed in that handle
454 Status
= CoreHandleProtocol (Handle
, &gEfiFirmwareVolume2ProtocolGuid
, (VOID
**)&Fv
);
455 if (!EFI_ERROR (Status
)) {
457 // Update Fv to use a new Fvb
459 FvDevice
= _CR (Fv
, FV_DEVICE
, Fv
);
460 if (FvDevice
->Signature
== FV2_DEVICE_SIGNATURE
) {
462 // Only write into our device structure if it's our device structure
469 // No FwVol protocol on the handle so create a new one
471 FvDevice
= AllocateCopyPool (sizeof (FV_DEVICE
), &mFvDevice
);
472 if (FvDevice
== NULL
) {
477 FvDevice
->Handle
= Handle
;
478 FvDevice
->FwVolHeader
= FwVolHeader
;
479 FvDevice
->Fv
.ParentHandle
= Fvb
->ParentHandle
;
482 // Install an New FV protocol on the existing handle
484 Status
= CoreInstallProtocolInterface (
486 &gEfiFirmwareVolume2ProtocolGuid
,
487 EFI_NATIVE_INTERFACE
,
490 ASSERT_EFI_ERROR (Status
);
500 This routine is the driver initialization entry point. It registers
501 a notification function. This notification function are responsible
502 for building the FV stack dynamically.
504 @param ImageHandle The image handle.
505 @param SystemTable The system table.
507 @retval EFI_SUCCESS Function successfully returned.
513 IN EFI_HANDLE ImageHandle
,
514 IN EFI_SYSTEM_TABLE
*SystemTable
517 gEfiFwVolBlockEvent
= EfiCreateProtocolNotifyEvent (
518 &gEfiFirmwareVolumeBlockProtocolGuid
,
522 &gEfiFwVolBlockNotifyReg