3 Copyright (c) 2006, Intel Corporation
4 All rights reserved. This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
18 Firmware File System driver that produce Firmware Volume protocol.
19 Layers on top of Firmware Block protocol to produce a file abstraction
26 #define KEYSIZE sizeof (UINTN)
29 // Protocol notify related globals
31 VOID
*gEfiFwVolBlockNotifyReg
;
32 EFI_EVENT gEfiFwVolBlockEvent
;
34 FV_DEVICE mFvDevice
= {
39 FvGetVolumeAttributes
,
40 FvSetVolumeAttributes
,
57 // FFS helper functions
62 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*Fvb
,
63 OUT EFI_FIRMWARE_VOLUME_HEADER
**FwVolHeader
68 given the supplied FW_VOL_BLOCK_PROTOCOL, allocate a buffer for output and
69 copy the volume header into it.
72 Fvb - The FW_VOL_BLOCK_PROTOCOL instance from which to read the volume
74 FwVolHeader - Pointer to pointer to allocated buffer in which the volume
78 EFI_OUT_OF_RESOURCES - No enough buffer could be allocated.
79 EFI_SUCCESS - Successfully read volume header to the allocated buffer.
85 EFI_FIRMWARE_VOLUME_HEADER TempFvh
;
91 //Determine the real length of FV header
93 FvhLength
= sizeof (EFI_FIRMWARE_VOLUME_HEADER
);
94 Status
= Fvb
->Read (Fvb
, 0, 0, &FvhLength
, (UINT8
*)&TempFvh
);
97 // Allocate a buffer for the caller
99 *FwVolHeader
= CoreAllocateBootServicesPool (TempFvh
.HeaderLength
);
100 if (*FwVolHeader
== NULL
) {
101 return EFI_OUT_OF_RESOURCES
;
105 // Copy the standard header into the buffer
107 CopyMem (*FwVolHeader
, &TempFvh
, sizeof (EFI_FIRMWARE_VOLUME_HEADER
));
110 // Read the rest of the header
112 FvhLength
= TempFvh
.HeaderLength
- sizeof (EFI_FIRMWARE_VOLUME_HEADER
);
113 Buffer
= (UINT8
*)*FwVolHeader
+ sizeof (EFI_FIRMWARE_VOLUME_HEADER
);
114 Status
= Fvb
->Read (Fvb
, 0, sizeof (EFI_FIRMWARE_VOLUME_HEADER
), &FvhLength
, Buffer
);
115 if (EFI_ERROR (Status
)) {
117 // Read failed so free buffer
119 CoreFreePool (*FwVolHeader
);
128 FreeFvDeviceResource (
129 IN FV_DEVICE
*FvDevice
134 Free FvDevice resource when error happens
137 FvDevice - pointer to the FvDevice to be freed.
144 FFS_FILE_LIST_ENTRY
*FfsFileEntry
;
145 LIST_ENTRY
*NextEntry
;
148 // Free File List Entry
150 FfsFileEntry
= (FFS_FILE_LIST_ENTRY
*)FvDevice
->FfsFileListHeader
.ForwardLink
;
151 while (&FfsFileEntry
->Link
!= &FvDevice
->FfsFileListHeader
) {
152 NextEntry
= (&FfsFileEntry
->Link
)->ForwardLink
;
154 if (FfsFileEntry
->StreamHandle
!= 0) {
156 // Close stream and free resources from SEP
158 FfsFileEntry
->Sep
->CloseSectionStream (FfsFileEntry
->Sep
, FfsFileEntry
->StreamHandle
);
161 CoreFreePool (FfsFileEntry
);
163 FfsFileEntry
= (FFS_FILE_LIST_ENTRY
*)NextEntry
;
170 CoreFreePool (FvDevice
->CachedFv
);
173 // Free Volume Header
175 CoreFreePool (FvDevice
->FwVolHeader
);
183 IN OUT FV_DEVICE
*FvDevice
188 Check if a FV is consistent and allocate cache
191 FvDevice - pointer to the FvDevice to be checked.
194 EFI_OUT_OF_RESOURCES - No enough buffer could be allocated.
195 EFI_SUCCESS - FV is consistent and cache is allocated.
196 EFI_VOLUME_CORRUPTED - File system is corrupted.
201 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*Fvb
;
202 EFI_FIRMWARE_VOLUME_HEADER
*FwVolHeader
;
203 EFI_FVB_ATTRIBUTES FvbAttributes
;
204 EFI_FV_BLOCK_MAP_ENTRY
*BlockMap
;
205 FFS_FILE_LIST_ENTRY
*FfsFileEntry
;
206 EFI_FFS_FILE_HEADER
*FfsHeader
;
207 UINT8
*CacheLocation
;
213 EFI_FFS_FILE_STATE FileState
;
219 FwVolHeader
= FvDevice
->FwVolHeader
;
221 Status
= Fvb
->GetVolumeAttributes (Fvb
, &FvbAttributes
);
222 if (EFI_ERROR (Status
)) {
227 // Size is the size of the FV minus the head. We have already allocated
228 // the header to check to make sure the volume is valid
230 Size
= (UINTN
)(FwVolHeader
->FvLength
- FwVolHeader
->HeaderLength
);
231 FvDevice
->CachedFv
= CoreAllocateZeroBootServicesPool (Size
);
232 if (FvDevice
->CachedFv
== NULL
) {
233 return EFI_OUT_OF_RESOURCES
;
237 // Remember a pointer to the end fo the CachedFv
239 FvDevice
->EndOfCachedFv
= FvDevice
->CachedFv
+ Size
;
242 // Copy FV minus header into memory using the block map we have all ready
245 BlockMap
= FwVolHeader
->FvBlockMap
;
246 CacheLocation
= FvDevice
->CachedFv
;
248 LbaOffset
= FwVolHeader
->HeaderLength
;
249 while ((BlockMap
->NumBlocks
!= 0) || (BlockMap
->BlockLength
!= 0)) {
251 for (Index
= 0; Index
< BlockMap
->NumBlocks
; Index
++) {
253 Size
= BlockMap
->BlockLength
;
256 // Cache does not include FV Header
260 Status
= Fvb
->Read (Fvb
,
267 // Not check EFI_BAD_BUFFER_SIZE, for Size = BlockMap->BlockLength
269 if (EFI_ERROR (Status
)) {
274 // After we skip Fv Header always read from start of block
279 CacheLocation
+= Size
;
285 // Scan to check the free space & File list
287 if (FvbAttributes
& EFI_FVB_ERASE_POLARITY
) {
288 FvDevice
->ErasePolarity
= 1;
290 FvDevice
->ErasePolarity
= 0;
295 // go through the whole FV cache, check the consistence of the FV.
296 // Make a linked list off all the Ffs file headers
298 Status
= EFI_SUCCESS
;
299 InitializeListHead (&FvDevice
->FfsFileListHeader
);
304 FfsHeader
= (EFI_FFS_FILE_HEADER
*)FvDevice
->CachedFv
;
305 TopFvAddress
= FvDevice
->EndOfCachedFv
;
306 while ((UINT8
*)FfsHeader
< TopFvAddress
) {
308 TestLength
= TopFvAddress
- ((UINT8
*)FfsHeader
);
309 if (TestLength
> sizeof (EFI_FFS_FILE_HEADER
)) {
310 TestLength
= sizeof (EFI_FFS_FILE_HEADER
);
313 if (IsBufferErased (FvDevice
->ErasePolarity
, FfsHeader
, TestLength
)) {
315 // We have found the free space so we are done!
320 if (!IsValidFfsHeader (FvDevice
->ErasePolarity
, FfsHeader
, &FileState
)) {
321 if ((FileState
== EFI_FILE_HEADER_INVALID
) ||
322 (FileState
== EFI_FILE_HEADER_CONSTRUCTION
)) {
329 // File system is corrputed
331 Status
= EFI_VOLUME_CORRUPTED
;
336 if (!IsValidFfsFile (FvDevice
->ErasePolarity
, FfsHeader
)) {
338 // File system is corrupted
340 Status
= EFI_VOLUME_CORRUPTED
;
345 // Size[3] is a three byte array, read 4 bytes and throw one away
347 FileLength
= *(UINT32
*)&FfsHeader
->Size
[0] & 0x00FFFFFF;
349 FileState
= GetFileState (FvDevice
->ErasePolarity
, FfsHeader
);
352 // check for non-deleted file
354 if (FileState
!= EFI_FILE_DELETED
) {
356 // Create a FFS list entry for each non-deleted file
358 FfsFileEntry
= CoreAllocateZeroBootServicesPool (sizeof (FFS_FILE_LIST_ENTRY
));
359 if (FfsFileEntry
== NULL
) {
360 Status
= EFI_OUT_OF_RESOURCES
;
364 FfsFileEntry
->FfsHeader
= FfsHeader
;
365 InsertTailList (&FvDevice
->FfsFileListHeader
, &FfsFileEntry
->Link
);
368 FfsHeader
= (EFI_FFS_FILE_HEADER
*)(((UINT8
*)FfsHeader
) + FileLength
);
371 // Adjust pointer to the next 8-byte aligned boundry.
373 FfsHeader
= (EFI_FFS_FILE_HEADER
*)(((UINTN
)FfsHeader
+ 7) & ~0x07);
378 if (EFI_ERROR (Status
)) {
379 FreeFvDeviceResource (FvDevice
);
396 This notification function is invoked when an instance of the
397 EFI_FW_VOLUME_BLOCK_PROTOCOL is produced. It layers an instance of the
398 EFI_FIRMWARE_VOLUME_PROTOCOL on the same handle. This is the function where
399 the actual initialization of the EFI_FIRMWARE_VOLUME_PROTOCOL is done.
402 Event - The event that occured
403 Context - For EFI compatiblity. Not used.
414 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*Fvb
;
415 EFI_FIRMWARE_VOLUME_PROTOCOL
*Fv
;
417 EFI_FIRMWARE_VOLUME_HEADER
*FwVolHeader
;
419 // Examine all new handles
423 // Get the next handle
425 BufferSize
= sizeof (Handle
);
426 Status
= CoreLocateHandle (
429 gEfiFwVolBlockNotifyReg
,
435 // If not found, we're done
437 if (EFI_NOT_FOUND
== Status
) {
441 if (EFI_ERROR (Status
)) {
446 // Get the FirmwareVolumeBlock protocol on that handle
448 Status
= CoreHandleProtocol (Handle
, &gEfiFirmwareVolumeBlockProtocolGuid
, (VOID
**)&Fvb
);
449 ASSERT_EFI_ERROR (Status
);
453 // Make sure the Fv Header is O.K.
455 Status
= GetFwVolHeader (Fvb
, &FwVolHeader
);
456 if (EFI_ERROR (Status
)) {
460 if (!VerifyFvHeaderChecksum (FwVolHeader
)) {
461 CoreFreePool (FwVolHeader
);
467 // Check to see that the file system is indeed formatted in a way we can
470 if (!CompareGuid (&FwVolHeader
->FileSystemGuid
, &gEfiFirmwareFileSystemGuid
)) {
475 // Check if there is an FV protocol already installed in that handle
477 Status
= CoreHandleProtocol (Handle
, &gEfiFirmwareVolumeProtocolGuid
, (VOID
**)&Fv
);
478 if (!EFI_ERROR (Status
)) {
480 // Update Fv to use a new Fvb
482 FvDevice
= _CR (Fv
, FV_DEVICE
, Fv
);
483 if (FvDevice
->Signature
== FV_DEVICE_SIGNATURE
) {
485 // Only write into our device structure if it's our device structure
492 // No FwVol protocol on the handle so create a new one
494 FvDevice
= CoreAllocateCopyPool (sizeof (FV_DEVICE
), &mFvDevice
);
495 if (FvDevice
== NULL
) {
500 FvDevice
->Handle
= Handle
;
501 FvDevice
->FwVolHeader
= FwVolHeader
;
502 FvDevice
->Fv
.ParentHandle
= Fvb
->ParentHandle
;
505 // Install an New FV protocol on the existing handle
507 Status
= CoreInstallProtocolInterface (
509 &gEfiFirmwareVolumeProtocolGuid
,
510 EFI_NATIVE_INTERFACE
,
513 ASSERT_EFI_ERROR (Status
);
524 IN EFI_HANDLE ImageHandle
,
525 IN EFI_SYSTEM_TABLE
*SystemTable
530 This routine is the driver initialization entry point. It initializes the
531 libraries, and registers two notification functions. These notification
532 functions are responsible for building the FV stack dynamically.
535 ImageHandle - The image handle.
536 SystemTable - The system table.
539 EFI_SUCCESS - Function successfully returned.
543 gEfiFwVolBlockEvent
= CoreCreateProtocolNotifyEvent (
544 &gEfiFirmwareVolumeBlockProtocolGuid
,
548 &gEfiFwVolBlockNotifyReg
,