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.
129 FreeFvDeviceResource (
130 IN FV_DEVICE
*FvDevice
133 FFS_FILE_LIST_ENTRY
*FfsFileEntry
;
134 LIST_ENTRY
*NextEntry
;
137 // Free File List Entry
139 FfsFileEntry
= (FFS_FILE_LIST_ENTRY
*)FvDevice
->FfsFileListHeader
.ForwardLink
;
140 while (&FfsFileEntry
->Link
!= &FvDevice
->FfsFileListHeader
) {
141 NextEntry
= (&FfsFileEntry
->Link
)->ForwardLink
;
143 if (FfsFileEntry
->StreamHandle
!= 0) {
145 // Close stream and free resources from SEP
147 CloseSectionStream (FfsFileEntry
->StreamHandle
);
150 CoreFreePool (FfsFileEntry
);
152 FfsFileEntry
= (FFS_FILE_LIST_ENTRY
*)NextEntry
;
159 CoreFreePool (FvDevice
->CachedFv
);
162 // Free Volume Header
164 CoreFreePool (FvDevice
->FwVolHeader
);
172 Check if a FV is consistent and allocate cache
174 @param FvDevice pointer to the FvDevice to be checked.
176 @retval EFI_OUT_OF_RESOURCES No enough buffer could be allocated.
177 @retval EFI_SUCCESS FV is consistent and cache is allocated.
178 @retval EFI_VOLUME_CORRUPTED File system is corrupted.
183 IN OUT FV_DEVICE
*FvDevice
187 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*Fvb
;
188 EFI_FIRMWARE_VOLUME_HEADER
*FwVolHeader
;
189 EFI_FVB_ATTRIBUTES FvbAttributes
;
190 EFI_FV_BLOCK_MAP_ENTRY
*BlockMap
;
191 FFS_FILE_LIST_ENTRY
*FfsFileEntry
;
192 EFI_FFS_FILE_HEADER
*FfsHeader
;
193 UINT8
*CacheLocation
;
199 EFI_FFS_FILE_STATE FileState
;
205 FwVolHeader
= FvDevice
->FwVolHeader
;
207 Status
= Fvb
->GetAttributes (Fvb
, &FvbAttributes
);
208 if (EFI_ERROR (Status
)) {
213 // Size is the size of the FV minus the head. We have already allocated
214 // the header to check to make sure the volume is valid
216 Size
= (UINTN
)(FwVolHeader
->FvLength
- FwVolHeader
->HeaderLength
);
217 FvDevice
->CachedFv
= CoreAllocateBootServicesPool (Size
);
219 if (FvDevice
->CachedFv
== NULL
) {
220 return EFI_OUT_OF_RESOURCES
;
224 // Remember a pointer to the end fo the CachedFv
226 FvDevice
->EndOfCachedFv
= FvDevice
->CachedFv
+ Size
;
229 // Copy FV minus header into memory using the block map we have all ready
232 BlockMap
= FwVolHeader
->BlockMap
;
233 CacheLocation
= FvDevice
->CachedFv
;
235 LbaOffset
= FwVolHeader
->HeaderLength
;
236 while ((BlockMap
->NumBlocks
!= 0) || (BlockMap
->Length
!= 0)) {
238 for (Index
= 0; Index
< BlockMap
->NumBlocks
; Index
++) {
240 Size
= BlockMap
->Length
;
243 // Cache does not include FV Header
247 Status
= Fvb
->Read (Fvb
,
254 // Not check EFI_BAD_BUFFER_SIZE, for Size = BlockMap->Length
256 if (EFI_ERROR (Status
)) {
261 // After we skip Fv Header always read from start of block
266 CacheLocation
+= Size
;
272 // Scan to check the free space & File list
274 if ((FvbAttributes
& EFI_FVB2_ERASE_POLARITY
) != 0) {
275 FvDevice
->ErasePolarity
= 1;
277 FvDevice
->ErasePolarity
= 0;
282 // go through the whole FV cache, check the consistence of the FV.
283 // Make a linked list off all the Ffs file headers
285 Status
= EFI_SUCCESS
;
286 InitializeListHead (&FvDevice
->FfsFileListHeader
);
291 FfsHeader
= (EFI_FFS_FILE_HEADER
*)FvDevice
->CachedFv
;
292 TopFvAddress
= FvDevice
->EndOfCachedFv
;
293 while ((UINT8
*)FfsHeader
< TopFvAddress
) {
295 TestLength
= TopFvAddress
- ((UINT8
*)FfsHeader
);
296 if (TestLength
> sizeof (EFI_FFS_FILE_HEADER
)) {
297 TestLength
= sizeof (EFI_FFS_FILE_HEADER
);
300 if (IsBufferErased (FvDevice
->ErasePolarity
, FfsHeader
, TestLength
)) {
302 // We have found the free space so we are done!
307 if (!IsValidFfsHeader (FvDevice
->ErasePolarity
, FfsHeader
, &FileState
)) {
308 if ((FileState
== EFI_FILE_HEADER_INVALID
) ||
309 (FileState
== EFI_FILE_HEADER_CONSTRUCTION
)) {
316 // File system is corrputed
318 Status
= EFI_VOLUME_CORRUPTED
;
323 if (!IsValidFfsFile (FvDevice
->ErasePolarity
, FfsHeader
)) {
325 // File system is corrupted
327 Status
= EFI_VOLUME_CORRUPTED
;
332 // Size[3] is a three byte array, read 4 bytes and throw one away
334 FileLength
= *(UINT32
*)&FfsHeader
->Size
[0] & 0x00FFFFFF;
336 FileState
= GetFileState (FvDevice
->ErasePolarity
, FfsHeader
);
339 // check for non-deleted file
341 if (FileState
!= EFI_FILE_DELETED
) {
343 // Create a FFS list entry for each non-deleted file
345 FfsFileEntry
= CoreAllocateZeroBootServicesPool (sizeof (FFS_FILE_LIST_ENTRY
));
346 if (FfsFileEntry
== NULL
) {
347 Status
= EFI_OUT_OF_RESOURCES
;
351 FfsFileEntry
->FfsHeader
= FfsHeader
;
352 InsertTailList (&FvDevice
->FfsFileListHeader
, &FfsFileEntry
->Link
);
355 FfsHeader
= (EFI_FFS_FILE_HEADER
*)(((UINT8
*)FfsHeader
) + FileLength
);
358 // Adjust pointer to the next 8-byte aligned boundry.
360 FfsHeader
= (EFI_FFS_FILE_HEADER
*)(((UINTN
)FfsHeader
+ 7) & ~0x07);
365 if (EFI_ERROR (Status
)) {
366 FreeFvDeviceResource (FvDevice
);
375 This notification function is invoked when an instance of the
376 EFI_FW_VOLUME_BLOCK_PROTOCOL is produced. It layers an instance of the
377 EFI_FIRMWARE_VOLUME2_PROTOCOL on the same handle. This is the function where
378 the actual initialization of the EFI_FIRMWARE_VOLUME2_PROTOCOL is done.
380 @param Event The event that occured
381 @param Context For EFI compatiblity. Not used.
394 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*Fvb
;
395 EFI_FIRMWARE_VOLUME2_PROTOCOL
*Fv
;
397 EFI_FIRMWARE_VOLUME_HEADER
*FwVolHeader
;
399 // Examine all new handles
403 // Get the next handle
405 BufferSize
= sizeof (Handle
);
406 Status
= CoreLocateHandle (
409 gEfiFwVolBlockNotifyReg
,
415 // If not found, we're done
417 if (EFI_NOT_FOUND
== Status
) {
421 if (EFI_ERROR (Status
)) {
426 // Get the FirmwareVolumeBlock protocol on that handle
428 Status
= CoreHandleProtocol (Handle
, &gEfiFirmwareVolumeBlockProtocolGuid
, (VOID
**)&Fvb
);
429 ASSERT_EFI_ERROR (Status
);
433 // Make sure the Fv Header is O.K.
435 Status
= GetFwVolHeader (Fvb
, &FwVolHeader
);
436 if (EFI_ERROR (Status
)) {
440 if (!VerifyFvHeaderChecksum (FwVolHeader
)) {
441 CoreFreePool (FwVolHeader
);
447 // Check to see that the file system is indeed formatted in a way we can
450 if (!CompareGuid (&FwVolHeader
->FileSystemGuid
, &gEfiFirmwareFileSystem2Guid
)) {
455 // Check if there is an FV protocol already installed in that handle
457 Status
= CoreHandleProtocol (Handle
, &gEfiFirmwareVolume2ProtocolGuid
, (VOID
**)&Fv
);
458 if (!EFI_ERROR (Status
)) {
460 // Update Fv to use a new Fvb
462 FvDevice
= _CR (Fv
, FV_DEVICE
, Fv
);
463 if (FvDevice
->Signature
== FV2_DEVICE_SIGNATURE
) {
465 // Only write into our device structure if it's our device structure
472 // No FwVol protocol on the handle so create a new one
474 FvDevice
= CoreAllocateCopyPool (sizeof (FV_DEVICE
), &mFvDevice
);
475 if (FvDevice
== NULL
) {
480 FvDevice
->Handle
= Handle
;
481 FvDevice
->FwVolHeader
= FwVolHeader
;
482 FvDevice
->Fv
.ParentHandle
= Fvb
->ParentHandle
;
485 // Install an New FV protocol on the existing handle
487 Status
= CoreInstallProtocolInterface (
489 &gEfiFirmwareVolume2ProtocolGuid
,
490 EFI_NATIVE_INTERFACE
,
493 ASSERT_EFI_ERROR (Status
);
503 This routine is the driver initialization entry point. It initializes the
504 libraries, and registers two notification functions. These notification
505 functions are responsible for building the FV stack dynamically.
507 @param ImageHandle The image handle.
508 @param SystemTable The system table.
510 @retval EFI_SUCCESS Function successfully returned.
516 IN EFI_HANDLE ImageHandle
,
517 IN EFI_SYSTEM_TABLE
*SystemTable
520 gEfiFwVolBlockEvent
= CoreCreateProtocolNotifyEvent (
521 &gEfiFirmwareVolumeBlockProtocolGuid
,
525 &gEfiFwVolBlockNotifyReg
,