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
);
88 // Allocate a buffer for the caller
90 *FwVolHeader
= CoreAllocateBootServicesPool (TempFvh
.HeaderLength
);
91 if (*FwVolHeader
== NULL
) {
92 return EFI_OUT_OF_RESOURCES
;
96 // Copy the standard header into the buffer
98 CopyMem (*FwVolHeader
, &TempFvh
, sizeof (EFI_FIRMWARE_VOLUME_HEADER
));
101 // Read the rest of the header
103 FvhLength
= TempFvh
.HeaderLength
- sizeof (EFI_FIRMWARE_VOLUME_HEADER
);
104 Buffer
= (UINT8
*)*FwVolHeader
+ sizeof (EFI_FIRMWARE_VOLUME_HEADER
);
105 Status
= Fvb
->Read (Fvb
, 0, sizeof (EFI_FIRMWARE_VOLUME_HEADER
), &FvhLength
, Buffer
);
106 if (EFI_ERROR (Status
)) {
108 // Read failed so free buffer
110 CoreFreePool (*FwVolHeader
);
119 Free FvDevice resource when error happens
121 @param FvDevice pointer to the FvDevice to be freed.
125 FreeFvDeviceResource (
126 IN FV_DEVICE
*FvDevice
129 FFS_FILE_LIST_ENTRY
*FfsFileEntry
;
130 LIST_ENTRY
*NextEntry
;
133 // Free File List Entry
135 FfsFileEntry
= (FFS_FILE_LIST_ENTRY
*)FvDevice
->FfsFileListHeader
.ForwardLink
;
136 while (&FfsFileEntry
->Link
!= &FvDevice
->FfsFileListHeader
) {
137 NextEntry
= (&FfsFileEntry
->Link
)->ForwardLink
;
139 if (FfsFileEntry
->StreamHandle
!= 0) {
141 // Close stream and free resources from SEP
143 CloseSectionStream (FfsFileEntry
->StreamHandle
);
146 CoreFreePool (FfsFileEntry
);
148 FfsFileEntry
= (FFS_FILE_LIST_ENTRY
*) NextEntry
;
155 CoreFreePool (FvDevice
->CachedFv
);
158 // Free Volume Header
160 CoreFreePool (FvDevice
->FwVolHeader
);
168 Check if an FV is consistent and allocate cache for it.
170 @param FvDevice A pointer to the FvDevice to be checked.
172 @retval EFI_OUT_OF_RESOURCES No enough buffer could be allocated.
173 @retval EFI_SUCCESS FV is consistent and cache is allocated.
174 @retval EFI_VOLUME_CORRUPTED File system is corrupted.
179 IN OUT FV_DEVICE
*FvDevice
183 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*Fvb
;
184 EFI_FIRMWARE_VOLUME_HEADER
*FwVolHeader
;
185 EFI_FVB_ATTRIBUTES FvbAttributes
;
186 EFI_FV_BLOCK_MAP_ENTRY
*BlockMap
;
187 FFS_FILE_LIST_ENTRY
*FfsFileEntry
;
188 EFI_FFS_FILE_HEADER
*FfsHeader
;
189 UINT8
*CacheLocation
;
195 EFI_FFS_FILE_STATE FileState
;
201 FwVolHeader
= FvDevice
->FwVolHeader
;
203 Status
= Fvb
->GetAttributes (Fvb
, &FvbAttributes
);
204 if (EFI_ERROR (Status
)) {
209 // Size is the size of the FV minus the head. We have already allocated
210 // the header to check to make sure the volume is valid
212 Size
= (UINTN
)(FwVolHeader
->FvLength
- FwVolHeader
->HeaderLength
);
213 FvDevice
->CachedFv
= CoreAllocateBootServicesPool (Size
);
215 if (FvDevice
->CachedFv
== NULL
) {
216 return EFI_OUT_OF_RESOURCES
;
220 // Remember a pointer to the end fo the CachedFv
222 FvDevice
->EndOfCachedFv
= FvDevice
->CachedFv
+ Size
;
225 // Copy FV minus header into memory using the block map we have all ready
228 BlockMap
= FwVolHeader
->BlockMap
;
229 CacheLocation
= FvDevice
->CachedFv
;
231 LbaOffset
= FwVolHeader
->HeaderLength
;
232 while ((BlockMap
->NumBlocks
!= 0) || (BlockMap
->Length
!= 0)) {
234 for (Index
= 0; Index
< BlockMap
->NumBlocks
; Index
++) {
236 Size
= BlockMap
->Length
;
239 // Cache does not include FV Header
243 Status
= Fvb
->Read (Fvb
,
250 // Not check EFI_BAD_BUFFER_SIZE, for Size = BlockMap->Length
252 if (EFI_ERROR (Status
)) {
257 // After we skip Fv Header always read from start of block
262 CacheLocation
+= Size
;
268 // Scan to check the free space & File list
270 if ((FvbAttributes
& EFI_FVB2_ERASE_POLARITY
) != 0) {
271 FvDevice
->ErasePolarity
= 1;
273 FvDevice
->ErasePolarity
= 0;
278 // go through the whole FV cache, check the consistence of the FV.
279 // Make a linked list off all the Ffs file headers
281 Status
= EFI_SUCCESS
;
282 InitializeListHead (&FvDevice
->FfsFileListHeader
);
287 FfsHeader
= (EFI_FFS_FILE_HEADER
*) FvDevice
->CachedFv
;
288 TopFvAddress
= FvDevice
->EndOfCachedFv
;
289 while ((UINT8
*) FfsHeader
< TopFvAddress
) {
291 TestLength
= TopFvAddress
- ((UINT8
*) FfsHeader
);
292 if (TestLength
> sizeof (EFI_FFS_FILE_HEADER
)) {
293 TestLength
= sizeof (EFI_FFS_FILE_HEADER
);
296 if (IsBufferErased (FvDevice
->ErasePolarity
, FfsHeader
, TestLength
)) {
298 // We have found the free space so we are done!
303 if (!IsValidFfsHeader (FvDevice
->ErasePolarity
, FfsHeader
, &FileState
)) {
304 if ((FileState
== EFI_FILE_HEADER_INVALID
) ||
305 (FileState
== EFI_FILE_HEADER_CONSTRUCTION
)) {
310 // File system is corrputed
312 Status
= EFI_VOLUME_CORRUPTED
;
317 if (!IsValidFfsFile (FvDevice
->ErasePolarity
, FfsHeader
)) {
319 // File system is corrupted
321 Status
= EFI_VOLUME_CORRUPTED
;
326 // Size[3] is a three byte array, read 4 bytes and throw one away
328 FileLength
= *(UINT32
*)&FfsHeader
->Size
[0] & 0x00FFFFFF;
330 FileState
= GetFileState (FvDevice
->ErasePolarity
, FfsHeader
);
333 // check for non-deleted file
335 if (FileState
!= EFI_FILE_DELETED
) {
337 // Create a FFS list entry for each non-deleted file
339 FfsFileEntry
= CoreAllocateZeroBootServicesPool (sizeof (FFS_FILE_LIST_ENTRY
));
340 if (FfsFileEntry
== NULL
) {
341 Status
= EFI_OUT_OF_RESOURCES
;
345 FfsFileEntry
->FfsHeader
= FfsHeader
;
346 InsertTailList (&FvDevice
->FfsFileListHeader
, &FfsFileEntry
->Link
);
349 FfsHeader
= (EFI_FFS_FILE_HEADER
*)(((UINT8
*)FfsHeader
) + FileLength
);
352 // Adjust pointer to the next 8-byte aligned boundry.
354 FfsHeader
= (EFI_FFS_FILE_HEADER
*)(((UINTN
)FfsHeader
+ 7) & ~0x07);
359 if (EFI_ERROR (Status
)) {
360 FreeFvDeviceResource (FvDevice
);
369 This notification function is invoked when an instance of the
370 EFI_FW_VOLUME_BLOCK_PROTOCOL is produced. It layers an instance of the
371 EFI_FIRMWARE_VOLUME2_PROTOCOL on the same handle. This is the function where
372 the actual initialization of the EFI_FIRMWARE_VOLUME2_PROTOCOL is done.
374 @param Event The event that occured
375 @param Context For EFI compatiblity. Not used.
388 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*Fvb
;
389 EFI_FIRMWARE_VOLUME2_PROTOCOL
*Fv
;
391 EFI_FIRMWARE_VOLUME_HEADER
*FwVolHeader
;
393 // Examine all new handles
397 // Get the next handle
399 BufferSize
= sizeof (Handle
);
400 Status
= CoreLocateHandle (
403 gEfiFwVolBlockNotifyReg
,
409 // If not found, we're done
411 if (EFI_NOT_FOUND
== Status
) {
415 if (EFI_ERROR (Status
)) {
420 // Get the FirmwareVolumeBlock protocol on that handle
422 Status
= CoreHandleProtocol (Handle
, &gEfiFirmwareVolumeBlockProtocolGuid
, (VOID
**)&Fvb
);
423 ASSERT_EFI_ERROR (Status
);
427 // Make sure the Fv Header is O.K.
429 Status
= GetFwVolHeader (Fvb
, &FwVolHeader
);
430 if (EFI_ERROR (Status
)) {
434 if (!VerifyFvHeaderChecksum (FwVolHeader
)) {
435 CoreFreePool (FwVolHeader
);
441 // Check to see that the file system is indeed formatted in a way we can
444 if (!CompareGuid (&FwVolHeader
->FileSystemGuid
, &gEfiFirmwareFileSystem2Guid
)) {
449 // Check if there is an FV protocol already installed in that handle
451 Status
= CoreHandleProtocol (Handle
, &gEfiFirmwareVolume2ProtocolGuid
, (VOID
**)&Fv
);
452 if (!EFI_ERROR (Status
)) {
454 // Update Fv to use a new Fvb
456 FvDevice
= _CR (Fv
, FV_DEVICE
, Fv
);
457 if (FvDevice
->Signature
== FV2_DEVICE_SIGNATURE
) {
459 // Only write into our device structure if it's our device structure
466 // No FwVol protocol on the handle so create a new one
468 FvDevice
= CoreAllocateCopyPool (sizeof (FV_DEVICE
), &mFvDevice
);
469 if (FvDevice
== NULL
) {
474 FvDevice
->Handle
= Handle
;
475 FvDevice
->FwVolHeader
= FwVolHeader
;
476 FvDevice
->Fv
.ParentHandle
= Fvb
->ParentHandle
;
479 // Install an New FV protocol on the existing handle
481 Status
= CoreInstallProtocolInterface (
483 &gEfiFirmwareVolume2ProtocolGuid
,
484 EFI_NATIVE_INTERFACE
,
487 ASSERT_EFI_ERROR (Status
);
497 This routine is the driver initialization entry point. It initializes the
498 libraries, and registers two notification functions. These notification
499 functions are responsible for building the FV stack dynamically.
501 @param ImageHandle The image handle.
502 @param SystemTable The system table.
504 @retval EFI_SUCCESS Function successfully returned.
510 IN EFI_HANDLE ImageHandle
,
511 IN EFI_SYSTEM_TABLE
*SystemTable
514 gEfiFwVolBlockEvent
= CoreCreateProtocolNotifyEvent (
515 &gEfiFirmwareVolumeBlockProtocolGuid
,
519 &gEfiFwVolBlockNotifyReg
,