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
58 given the supplied FW_VOL_BLOCK_PROTOCOL, allocate a buffer for output and
59 copy the volume header into it.
61 @param Fvb The FW_VOL_BLOCK_PROTOCOL instance from which to
62 read the volume header
63 @param FwVolHeader Pointer to pointer to allocated buffer in which
64 the volume header is returned.
66 @retval EFI_OUT_OF_RESOURCES No enough buffer could be allocated.
67 @retval EFI_SUCCESS Successfully read volume header to the allocated
73 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*Fvb
,
74 OUT EFI_FIRMWARE_VOLUME_HEADER
**FwVolHeader
78 EFI_FIRMWARE_VOLUME_HEADER TempFvh
;
84 //Determine the real length of FV header
86 FvhLength
= sizeof (EFI_FIRMWARE_VOLUME_HEADER
);
87 Status
= Fvb
->Read (Fvb
, 0, 0, &FvhLength
, (UINT8
*)&TempFvh
);
90 // Allocate a buffer for the caller
92 *FwVolHeader
= CoreAllocateBootServicesPool (TempFvh
.HeaderLength
);
93 if (*FwVolHeader
== NULL
) {
94 return EFI_OUT_OF_RESOURCES
;
98 // Copy the standard header into the buffer
100 CopyMem (*FwVolHeader
, &TempFvh
, sizeof (EFI_FIRMWARE_VOLUME_HEADER
));
103 // Read the rest of the header
105 FvhLength
= TempFvh
.HeaderLength
- sizeof (EFI_FIRMWARE_VOLUME_HEADER
);
106 Buffer
= (UINT8
*)*FwVolHeader
+ sizeof (EFI_FIRMWARE_VOLUME_HEADER
);
107 Status
= Fvb
->Read (Fvb
, 0, sizeof (EFI_FIRMWARE_VOLUME_HEADER
), &FvhLength
, Buffer
);
108 if (EFI_ERROR (Status
)) {
110 // Read failed so free buffer
112 CoreFreePool (*FwVolHeader
);
121 Free FvDevice resource when error happens
123 @param FvDevice pointer to the FvDevice to be freed.
130 FreeFvDeviceResource (
131 IN FV_DEVICE
*FvDevice
134 FFS_FILE_LIST_ENTRY
*FfsFileEntry
;
135 LIST_ENTRY
*NextEntry
;
138 // Free File List Entry
140 FfsFileEntry
= (FFS_FILE_LIST_ENTRY
*)FvDevice
->FfsFileListHeader
.ForwardLink
;
141 while (&FfsFileEntry
->Link
!= &FvDevice
->FfsFileListHeader
) {
142 NextEntry
= (&FfsFileEntry
->Link
)->ForwardLink
;
144 if (FfsFileEntry
->StreamHandle
!= 0) {
146 // Close stream and free resources from SEP
148 CloseSectionStream (FfsFileEntry
->StreamHandle
);
151 CoreFreePool (FfsFileEntry
);
153 FfsFileEntry
= (FFS_FILE_LIST_ENTRY
*)NextEntry
;
160 CoreFreePool (FvDevice
->CachedFv
);
163 // Free Volume Header
165 CoreFreePool (FvDevice
->FwVolHeader
);
173 Check if a FV is consistent and allocate cache
175 @param FvDevice pointer to the FvDevice to be checked.
177 @retval EFI_OUT_OF_RESOURCES No enough buffer could be allocated.
178 @retval EFI_SUCCESS FV is consistent and cache is allocated.
179 @retval EFI_VOLUME_CORRUPTED File system is corrupted.
184 IN OUT FV_DEVICE
*FvDevice
188 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*Fvb
;
189 EFI_FIRMWARE_VOLUME_HEADER
*FwVolHeader
;
190 EFI_FVB_ATTRIBUTES FvbAttributes
;
191 EFI_FV_BLOCK_MAP_ENTRY
*BlockMap
;
192 FFS_FILE_LIST_ENTRY
*FfsFileEntry
;
193 EFI_FFS_FILE_HEADER
*FfsHeader
;
194 UINT8
*CacheLocation
;
200 EFI_FFS_FILE_STATE FileState
;
206 FwVolHeader
= FvDevice
->FwVolHeader
;
208 Status
= Fvb
->GetAttributes (Fvb
, &FvbAttributes
);
209 if (EFI_ERROR (Status
)) {
214 // Size is the size of the FV minus the head. We have already allocated
215 // the header to check to make sure the volume is valid
217 Size
= (UINTN
)(FwVolHeader
->FvLength
- FwVolHeader
->HeaderLength
);
218 FvDevice
->CachedFv
= CoreAllocateBootServicesPool (Size
);
220 if (FvDevice
->CachedFv
== NULL
) {
221 return EFI_OUT_OF_RESOURCES
;
225 // Remember a pointer to the end fo the CachedFv
227 FvDevice
->EndOfCachedFv
= FvDevice
->CachedFv
+ Size
;
230 // Copy FV minus header into memory using the block map we have all ready
233 BlockMap
= FwVolHeader
->BlockMap
;
234 CacheLocation
= FvDevice
->CachedFv
;
236 LbaOffset
= FwVolHeader
->HeaderLength
;
237 while ((BlockMap
->NumBlocks
!= 0) || (BlockMap
->Length
!= 0)) {
239 for (Index
= 0; Index
< BlockMap
->NumBlocks
; Index
++) {
241 Size
= BlockMap
->Length
;
244 // Cache does not include FV Header
248 Status
= Fvb
->Read (Fvb
,
255 // Not check EFI_BAD_BUFFER_SIZE, for Size = BlockMap->Length
257 if (EFI_ERROR (Status
)) {
262 // After we skip Fv Header always read from start of block
267 CacheLocation
+= Size
;
273 // Scan to check the free space & File list
275 if (FvbAttributes
& EFI_FVB2_ERASE_POLARITY
) {
276 FvDevice
->ErasePolarity
= 1;
278 FvDevice
->ErasePolarity
= 0;
283 // go through the whole FV cache, check the consistence of the FV.
284 // Make a linked list off all the Ffs file headers
286 Status
= EFI_SUCCESS
;
287 InitializeListHead (&FvDevice
->FfsFileListHeader
);
292 FfsHeader
= (EFI_FFS_FILE_HEADER
*)FvDevice
->CachedFv
;
293 TopFvAddress
= FvDevice
->EndOfCachedFv
;
294 while ((UINT8
*)FfsHeader
< TopFvAddress
) {
296 TestLength
= TopFvAddress
- ((UINT8
*)FfsHeader
);
297 if (TestLength
> sizeof (EFI_FFS_FILE_HEADER
)) {
298 TestLength
= sizeof (EFI_FFS_FILE_HEADER
);
301 if (IsBufferErased (FvDevice
->ErasePolarity
, FfsHeader
, TestLength
)) {
303 // We have found the free space so we are done!
308 if (!IsValidFfsHeader (FvDevice
->ErasePolarity
, FfsHeader
, &FileState
)) {
309 if ((FileState
== EFI_FILE_HEADER_INVALID
) ||
310 (FileState
== EFI_FILE_HEADER_CONSTRUCTION
)) {
317 // File system is corrputed
319 Status
= EFI_VOLUME_CORRUPTED
;
324 if (!IsValidFfsFile (FvDevice
->ErasePolarity
, FfsHeader
)) {
326 // File system is corrupted
328 Status
= EFI_VOLUME_CORRUPTED
;
333 // Size[3] is a three byte array, read 4 bytes and throw one away
335 FileLength
= *(UINT32
*)&FfsHeader
->Size
[0] & 0x00FFFFFF;
337 FileState
= GetFileState (FvDevice
->ErasePolarity
, FfsHeader
);
340 // check for non-deleted file
342 if (FileState
!= EFI_FILE_DELETED
) {
344 // Create a FFS list entry for each non-deleted file
346 FfsFileEntry
= CoreAllocateZeroBootServicesPool (sizeof (FFS_FILE_LIST_ENTRY
));
347 if (FfsFileEntry
== NULL
) {
348 Status
= EFI_OUT_OF_RESOURCES
;
352 FfsFileEntry
->FfsHeader
= FfsHeader
;
353 InsertTailList (&FvDevice
->FfsFileListHeader
, &FfsFileEntry
->Link
);
356 FfsHeader
= (EFI_FFS_FILE_HEADER
*)(((UINT8
*)FfsHeader
) + FileLength
);
359 // Adjust pointer to the next 8-byte aligned boundry.
361 FfsHeader
= (EFI_FFS_FILE_HEADER
*)(((UINTN
)FfsHeader
+ 7) & ~0x07);
366 if (EFI_ERROR (Status
)) {
367 FreeFvDeviceResource (FvDevice
);
376 This notification function is invoked when an instance of the
377 EFI_FW_VOLUME_BLOCK_PROTOCOL is produced. It layers an instance of the
378 EFI_FIRMWARE_VOLUME2_PROTOCOL on the same handle. This is the function where
379 the actual initialization of the EFI_FIRMWARE_VOLUME2_PROTOCOL is done.
381 @param Event The event that occured
382 @param Context For EFI compatiblity. Not used.
396 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*Fvb
;
397 EFI_FIRMWARE_VOLUME2_PROTOCOL
*Fv
;
399 EFI_FIRMWARE_VOLUME_HEADER
*FwVolHeader
;
401 // Examine all new handles
405 // Get the next handle
407 BufferSize
= sizeof (Handle
);
408 Status
= CoreLocateHandle (
411 gEfiFwVolBlockNotifyReg
,
417 // If not found, we're done
419 if (EFI_NOT_FOUND
== Status
) {
423 if (EFI_ERROR (Status
)) {
428 // Get the FirmwareVolumeBlock protocol on that handle
430 Status
= CoreHandleProtocol (Handle
, &gEfiFirmwareVolumeBlockProtocolGuid
, (VOID
**)&Fvb
);
431 ASSERT_EFI_ERROR (Status
);
435 // Make sure the Fv Header is O.K.
437 Status
= GetFwVolHeader (Fvb
, &FwVolHeader
);
438 if (EFI_ERROR (Status
)) {
442 if (!VerifyFvHeaderChecksum (FwVolHeader
)) {
443 CoreFreePool (FwVolHeader
);
449 // Check to see that the file system is indeed formatted in a way we can
452 if (!CompareGuid (&FwVolHeader
->FileSystemGuid
, &gEfiFirmwareFileSystem2Guid
)) {
457 // Check if there is an FV protocol already installed in that handle
459 Status
= CoreHandleProtocol (Handle
, &gEfiFirmwareVolume2ProtocolGuid
, (VOID
**)&Fv
);
460 if (!EFI_ERROR (Status
)) {
462 // Update Fv to use a new Fvb
464 FvDevice
= _CR (Fv
, FV_DEVICE
, Fv
);
465 if (FvDevice
->Signature
== FV2_DEVICE_SIGNATURE
) {
467 // Only write into our device structure if it's our device structure
474 // No FwVol protocol on the handle so create a new one
476 FvDevice
= CoreAllocateCopyPool (sizeof (FV_DEVICE
), &mFvDevice
);
477 if (FvDevice
== NULL
) {
482 FvDevice
->Handle
= Handle
;
483 FvDevice
->FwVolHeader
= FwVolHeader
;
484 FvDevice
->Fv
.ParentHandle
= Fvb
->ParentHandle
;
487 // Install an New FV protocol on the existing handle
489 Status
= CoreInstallProtocolInterface (
491 &gEfiFirmwareVolume2ProtocolGuid
,
492 EFI_NATIVE_INTERFACE
,
495 ASSERT_EFI_ERROR (Status
);
505 This routine is the driver initialization entry point. It initializes the
506 libraries, and registers two notification functions. These notification
507 functions are responsible for building the FV stack dynamically.
509 @param ImageHandle The image handle.
510 @param SystemTable The system table.
512 @retval EFI_SUCCESS Function successfully returned.
518 IN EFI_HANDLE ImageHandle
,
519 IN EFI_SYSTEM_TABLE
*SystemTable
522 gEfiFwVolBlockEvent
= CoreCreateProtocolNotifyEvent (
523 &gEfiFirmwareVolumeBlockProtocolGuid
,
527 &gEfiFwVolBlockNotifyReg
,