+++ /dev/null
-/**@file\r
- Firmware File System driver that produce Firmware Volume protocol.\r
- Layers on top of Firmware Block protocol to produce a file abstraction \r
- of FV based files.\r
- \r
-Copyright (c) 2006 - 2007 Intel Corporation. <BR>\r
-All rights reserved. This program and the accompanying materials \r
-are licensed and made available under the terms and conditions of the BSD License \r
-which accompanies this distribution. The full text of the license may be found at \r
-http://opensource.org/licenses/bsd-license.php \r
- \r
-THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
-WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. \r
-\r
-**/\r
-\r
-#include <DxeMain.h>\r
-\r
-#define KEYSIZE sizeof (UINTN)\r
-\r
-//\r
-// Protocol notify related globals\r
-//\r
-VOID *gEfiFwVolBlockNotifyReg;\r
-EFI_EVENT gEfiFwVolBlockEvent;\r
-\r
-FV_DEVICE mFvDevice = {\r
- FV_DEVICE_SIGNATURE,\r
- NULL,\r
- NULL,\r
- {\r
- FvGetVolumeAttributes,\r
- FvSetVolumeAttributes,\r
- FvReadFile,\r
- FvReadFileSection,\r
- FvWriteFile,\r
- FvGetNextFile,\r
- KEYSIZE\r
- },\r
- NULL,\r
- NULL,\r
- NULL,\r
- NULL,\r
- { NULL, NULL },\r
- 0\r
-};\r
-\r
-\r
-//\r
-// FFS helper functions\r
-//\r
-\r
-EFI_STATUS\r
-GetFwVolHeader (\r
- IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb,\r
- OUT EFI_FIRMWARE_VOLUME_HEADER **FwVolHeader\r
- )\r
-/*++\r
-\r
-Routine Description:\r
- given the supplied FW_VOL_BLOCK_PROTOCOL, allocate a buffer for output and\r
- copy the volume header into it.\r
-\r
-Arguments:\r
- Fvb - The FW_VOL_BLOCK_PROTOCOL instance from which to read the volume\r
- header\r
- FwVolHeader - Pointer to pointer to allocated buffer in which the volume\r
- header is returned.\r
-\r
-Returns:\r
- EFI_OUT_OF_RESOURCES - No enough buffer could be allocated.\r
- EFI_SUCCESS - Successfully read volume header to the allocated buffer.\r
-\r
---*/\r
-\r
-{\r
- EFI_STATUS Status;\r
- EFI_FIRMWARE_VOLUME_HEADER TempFvh;\r
- UINTN FvhLength;\r
- UINT8 *Buffer;\r
-\r
-\r
- //\r
- //Determine the real length of FV header\r
- //\r
- FvhLength = sizeof (EFI_FIRMWARE_VOLUME_HEADER);\r
- Status = Fvb->Read (Fvb, 0, 0, &FvhLength, (UINT8 *)&TempFvh);\r
-\r
- //\r
- // Allocate a buffer for the caller\r
- //\r
- *FwVolHeader = CoreAllocateBootServicesPool (TempFvh.HeaderLength);\r
- if (*FwVolHeader == NULL) {\r
- return EFI_OUT_OF_RESOURCES;\r
- }\r
-\r
- //\r
- // Copy the standard header into the buffer\r
- //\r
- CopyMem (*FwVolHeader, &TempFvh, sizeof (EFI_FIRMWARE_VOLUME_HEADER));\r
-\r
- //\r
- // Read the rest of the header\r
- //\r
- FvhLength = TempFvh.HeaderLength - sizeof (EFI_FIRMWARE_VOLUME_HEADER);\r
- Buffer = (UINT8 *)*FwVolHeader + sizeof (EFI_FIRMWARE_VOLUME_HEADER);\r
- Status = Fvb->Read (Fvb, 0, sizeof (EFI_FIRMWARE_VOLUME_HEADER), &FvhLength, Buffer);\r
- if (EFI_ERROR (Status)) {\r
- //\r
- // Read failed so free buffer\r
- //\r
- CoreFreePool (*FwVolHeader);\r
- }\r
- \r
- return Status;\r
-}\r
-\r
-\r
-STATIC\r
-VOID\r
-FreeFvDeviceResource (\r
- IN FV_DEVICE *FvDevice\r
- )\r
-/*++\r
-\r
-Routine Description:\r
- Free FvDevice resource when error happens\r
-\r
-Arguments:\r
- FvDevice - pointer to the FvDevice to be freed.\r
-\r
-Returns:\r
- None.\r
-\r
---*/\r
-{\r
- FFS_FILE_LIST_ENTRY *FfsFileEntry;\r
- LIST_ENTRY *NextEntry;\r
-\r
- //\r
- // Free File List Entry\r
- //\r
- FfsFileEntry = (FFS_FILE_LIST_ENTRY *)FvDevice->FfsFileListHeader.ForwardLink;\r
- while (&FfsFileEntry->Link != &FvDevice->FfsFileListHeader) {\r
- NextEntry = (&FfsFileEntry->Link)->ForwardLink;\r
- \r
- if (FfsFileEntry->StreamHandle != 0) {\r
- //\r
- // Close stream and free resources from SEP\r
- //\r
- FfsFileEntry->Sep->CloseSectionStream (FfsFileEntry->Sep, FfsFileEntry->StreamHandle);\r
- }\r
-\r
- CoreFreePool (FfsFileEntry);\r
-\r
- FfsFileEntry = (FFS_FILE_LIST_ENTRY *)NextEntry;\r
- }\r
-\r
-\r
- //\r
- // Free the cache\r
- //\r
- CoreFreePool (FvDevice->CachedFv);\r
-\r
- //\r
- // Free Volume Header\r
- //\r
- CoreFreePool (FvDevice->FwVolHeader);\r
-\r
- return;\r
-}\r
-\r
-\r
-EFI_STATUS\r
-FvCheck (\r
- IN OUT FV_DEVICE *FvDevice\r
- )\r
-/*++\r
-\r
-Routine Description:\r
- Check if a FV is consistent and allocate cache\r
-\r
-Arguments:\r
- FvDevice - pointer to the FvDevice to be checked.\r
-\r
-Returns:\r
- EFI_OUT_OF_RESOURCES - No enough buffer could be allocated.\r
- EFI_SUCCESS - FV is consistent and cache is allocated.\r
- EFI_VOLUME_CORRUPTED - File system is corrupted.\r
-\r
---*/\r
-{\r
- EFI_STATUS Status;\r
- EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;\r
- EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;\r
- EFI_FVB_ATTRIBUTES FvbAttributes;\r
- EFI_FV_BLOCK_MAP_ENTRY *BlockMap;\r
- FFS_FILE_LIST_ENTRY *FfsFileEntry;\r
- EFI_FFS_FILE_HEADER *FfsHeader;\r
- UINT8 *CacheLocation;\r
- UINTN LbaOffset;\r
- UINTN Index;\r
- EFI_LBA LbaIndex;\r
- UINTN Size;\r
- UINTN FileLength;\r
- EFI_FFS_FILE_STATE FileState;\r
- UINT8 *TopFvAddress;\r
- UINTN TestLength;\r
-\r
-\r
- Fvb = FvDevice->Fvb;\r
- FwVolHeader = FvDevice->FwVolHeader;\r
- \r
- Status = Fvb->GetVolumeAttributes (Fvb, &FvbAttributes);\r
- if (EFI_ERROR (Status)) {\r
- return Status;\r
- }\r
-\r
- //\r
- // Size is the size of the FV minus the head. We have already allocated\r
- // the header to check to make sure the volume is valid\r
- //\r
- Size = (UINTN)(FwVolHeader->FvLength - FwVolHeader->HeaderLength);\r
- FvDevice->CachedFv = CoreAllocateBootServicesPool (Size);\r
-\r
- if (FvDevice->CachedFv == NULL) {\r
- return EFI_OUT_OF_RESOURCES;\r
- }\r
-\r
- //\r
- // Remember a pointer to the end fo the CachedFv\r
- //\r
- FvDevice->EndOfCachedFv = FvDevice->CachedFv + Size;\r
-\r
- //\r
- // Copy FV minus header into memory using the block map we have all ready\r
- // read into memory.\r
- //\r
- BlockMap = FwVolHeader->FvBlockMap;\r
- CacheLocation = FvDevice->CachedFv;\r
- LbaIndex = 0;\r
- LbaOffset = FwVolHeader->HeaderLength;\r
- while ((BlockMap->NumBlocks != 0) || (BlockMap->BlockLength != 0)) {\r
- \r
- for (Index = 0; Index < BlockMap->NumBlocks; Index ++) {\r
-\r
- Size = BlockMap->BlockLength;\r
- if (Index == 0) {\r
- //\r
- // Cache does not include FV Header\r
- //\r
- Size -= LbaOffset;\r
- }\r
- Status = Fvb->Read (Fvb,\r
- LbaIndex,\r
- LbaOffset,\r
- &Size,\r
- CacheLocation\r
- );\r
- //\r
- // Not check EFI_BAD_BUFFER_SIZE, for Size = BlockMap->BlockLength\r
- //\r
- if (EFI_ERROR (Status)) {\r
- goto Done;\r
- }\r
- \r
- //\r
- // After we skip Fv Header always read from start of block\r
- //\r
- LbaOffset = 0;\r
-\r
- LbaIndex++;\r
- CacheLocation += Size;\r
- }\r
- BlockMap++;\r
- }\r
-\r
- //\r
- // Scan to check the free space & File list\r
- //\r
- if (FvbAttributes & EFI_FVB_ERASE_POLARITY) {\r
- FvDevice->ErasePolarity = 1;\r
- } else {\r
- FvDevice->ErasePolarity = 0;\r
- } \r
-\r
-\r
- //\r
- // go through the whole FV cache, check the consistence of the FV.\r
- // Make a linked list off all the Ffs file headers\r
- //\r
- Status = EFI_SUCCESS;\r
- InitializeListHead (&FvDevice->FfsFileListHeader);\r
-\r
- //\r
- // Build FFS list\r
- //\r
- FfsHeader = (EFI_FFS_FILE_HEADER *)FvDevice->CachedFv;\r
- TopFvAddress = FvDevice->EndOfCachedFv;\r
- while ((UINT8 *)FfsHeader < TopFvAddress) {\r
-\r
- TestLength = TopFvAddress - ((UINT8 *)FfsHeader);\r
- if (TestLength > sizeof (EFI_FFS_FILE_HEADER)) {\r
- TestLength = sizeof (EFI_FFS_FILE_HEADER);\r
- }\r
-\r
- if (IsBufferErased (FvDevice->ErasePolarity, FfsHeader, TestLength)) {\r
- //\r
- // We have found the free space so we are done!\r
- //\r
- goto Done;\r
- }\r
-\r
- if (!IsValidFfsHeader (FvDevice->ErasePolarity, FfsHeader, &FileState)) {\r
- if ((FileState == EFI_FILE_HEADER_INVALID) || \r
- (FileState == EFI_FILE_HEADER_CONSTRUCTION)) {\r
- FfsHeader++;\r
- \r
- continue;\r
- \r
- } else {\r
- //\r
- // File system is corrputed\r
- //\r
- Status = EFI_VOLUME_CORRUPTED;\r
- goto Done;\r
- }\r
- }\r
-\r
- if (!IsValidFfsFile (FvDevice->ErasePolarity, FfsHeader)) {\r
- //\r
- // File system is corrupted\r
- //\r
- Status = EFI_VOLUME_CORRUPTED;\r
- goto Done;\r
- }\r
-\r
- //\r
- // Size[3] is a three byte array, read 4 bytes and throw one away\r
- //\r
- FileLength = *(UINT32 *)&FfsHeader->Size[0] & 0x00FFFFFF;\r
-\r
- FileState = GetFileState (FvDevice->ErasePolarity, FfsHeader);\r
- \r
- //\r
- // check for non-deleted file\r
- //\r
- if (FileState != EFI_FILE_DELETED) {\r
- //\r
- // Create a FFS list entry for each non-deleted file\r
- //\r
- FfsFileEntry = CoreAllocateZeroBootServicesPool (sizeof (FFS_FILE_LIST_ENTRY));\r
- if (FfsFileEntry == NULL) {\r
- Status = EFI_OUT_OF_RESOURCES;\r
- goto Done;\r
- }\r
- \r
- FfsFileEntry->FfsHeader = FfsHeader;\r
- InsertTailList (&FvDevice->FfsFileListHeader, &FfsFileEntry->Link);\r
- }\r
-\r
- FfsHeader = (EFI_FFS_FILE_HEADER *)(((UINT8 *)FfsHeader) + FileLength);\r
- \r
- //\r
- // Adjust pointer to the next 8-byte aligned boundry.\r
- //\r
- FfsHeader = (EFI_FFS_FILE_HEADER *)(((UINTN)FfsHeader + 7) & ~0x07);\r
- \r
- }\r
-\r
-Done:\r
- if (EFI_ERROR (Status)) {\r
- FreeFvDeviceResource (FvDevice);\r
- }\r
-\r
- return Status;\r
-}\r
-\r
-\r
-STATIC\r
-VOID\r
-EFIAPI\r
-NotifyFwVolBlock (\r
- IN EFI_EVENT Event,\r
- IN VOID *Context\r
- )\r
-/*++\r
-\r
-Routine Description:\r
- This notification function is invoked when an instance of the\r
- EFI_FW_VOLUME_BLOCK_PROTOCOL is produced. It layers an instance of the\r
- EFI_FIRMWARE_VOLUME_PROTOCOL on the same handle. This is the function where\r
- the actual initialization of the EFI_FIRMWARE_VOLUME_PROTOCOL is done.\r
-\r
-Arguments:\r
- Event - The event that occured\r
- Context - For EFI compatiblity. Not used.\r
-\r
-Returns:\r
-\r
- None.\r
-\r
---*/\r
-{\r
- EFI_HANDLE Handle;\r
- EFI_STATUS Status;\r
- UINTN BufferSize;\r
- EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;\r
- EFI_FIRMWARE_VOLUME_PROTOCOL *Fv;\r
- FV_DEVICE *FvDevice;\r
- EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;\r
- //\r
- // Examine all new handles\r
- //\r
- for (;;) {\r
- //\r
- // Get the next handle\r
- //\r
- BufferSize = sizeof (Handle);\r
- Status = CoreLocateHandle (\r
- ByRegisterNotify,\r
- NULL,\r
- gEfiFwVolBlockNotifyReg,\r
- &BufferSize,\r
- &Handle\r
- );\r
-\r
- //\r
- // If not found, we're done\r
- //\r
- if (EFI_NOT_FOUND == Status) {\r
- break;\r
- }\r
-\r
- if (EFI_ERROR (Status)) {\r
- continue;\r
- }\r
- \r
- //\r
- // Get the FirmwareVolumeBlock protocol on that handle\r
- //\r
- Status = CoreHandleProtocol (Handle, &gEfiFirmwareVolumeBlockProtocolGuid, (VOID **)&Fvb); \r
- ASSERT_EFI_ERROR (Status);\r
- \r
-\r
- //\r
- // Make sure the Fv Header is O.K.\r
- //\r
- Status = GetFwVolHeader (Fvb, &FwVolHeader);\r
- if (EFI_ERROR (Status)) {\r
- return;\r
- }\r
-\r
- if (!VerifyFvHeaderChecksum (FwVolHeader)) {\r
- CoreFreePool (FwVolHeader);\r
- continue;\r
- }\r
-\r
-\r
- //\r
- // Check to see that the file system is indeed formatted in a way we can\r
- // understand it...\r
- //\r
- if (!CompareGuid (&FwVolHeader->FileSystemGuid, &gEfiFirmwareFileSystemGuid)) {\r
- continue;\r
- }\r
-\r
- //\r
- // Check if there is an FV protocol already installed in that handle\r
- //\r
- Status = CoreHandleProtocol (Handle, &gEfiFirmwareVolumeProtocolGuid, (VOID **)&Fv);\r
- if (!EFI_ERROR (Status)) {\r
- //\r
- // Update Fv to use a new Fvb\r
- //\r
- FvDevice = _CR (Fv, FV_DEVICE, Fv);\r
- if (FvDevice->Signature == FV_DEVICE_SIGNATURE) {\r
- //\r
- // Only write into our device structure if it's our device structure\r
- //\r
- FvDevice->Fvb = Fvb;\r
- }\r
-\r
- } else {\r
- //\r
- // No FwVol protocol on the handle so create a new one\r
- //\r
- FvDevice = CoreAllocateCopyPool (sizeof (FV_DEVICE), &mFvDevice);\r
- if (FvDevice == NULL) {\r
- return;\r
- }\r
- \r
- FvDevice->Fvb = Fvb;\r
- FvDevice->Handle = Handle;\r
- FvDevice->FwVolHeader = FwVolHeader;\r
- FvDevice->Fv.ParentHandle = Fvb->ParentHandle;\r
- \r
- //\r
- // Install an New FV protocol on the existing handle\r
- //\r
- Status = CoreInstallProtocolInterface (\r
- &Handle,\r
- &gEfiFirmwareVolumeProtocolGuid,\r
- EFI_NATIVE_INTERFACE,\r
- &FvDevice->Fv\r
- );\r
- ASSERT_EFI_ERROR (Status);\r
- }\r
- }\r
- \r
- return;\r
-}\r
-\r
-\r
-EFI_STATUS\r
-EFIAPI\r
-FwVolDriverInit (\r
- IN EFI_HANDLE ImageHandle,\r
- IN EFI_SYSTEM_TABLE *SystemTable\r
- )\r
-/*++\r
-\r
-Routine Description:\r
- This routine is the driver initialization entry point. It initializes the\r
- libraries, and registers two notification functions. These notification\r
- functions are responsible for building the FV stack dynamically.\r
- \r
-Arguments:\r
- ImageHandle - The image handle.\r
- SystemTable - The system table.\r
- \r
-Returns:\r
- EFI_SUCCESS - Function successfully returned.\r
-\r
---*/\r
-{\r
- gEfiFwVolBlockEvent = CoreCreateProtocolNotifyEvent (\r
- &gEfiFirmwareVolumeBlockProtocolGuid,\r
- TPL_CALLBACK,\r
- NotifyFwVolBlock,\r
- NULL,\r
- &gEfiFwVolBlockNotifyReg,\r
- TRUE\r
- );\r
- return EFI_SUCCESS;\r
-}\r
-\r