]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Core/Dxe/FwVol/FwVol.c
MdeModulePkg: Replace BSD License with BSD+Patent License
[mirror_edk2.git] / MdeModulePkg / Core / Dxe / FwVol / FwVol.c
index 60c5fa19a2ad613c177ca4f9a12216dad88705c7..e2f58c4d82a81a770c493d2e9f5bec65692b47d6 100644 (file)
@@ -1,22 +1,16 @@
-/**@file\r
+/** @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
+  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
+Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>\r
+SPDX-License-Identifier: BSD-2-Clause-Patent\r
 \r
 **/\r
 \r
-#include <DxeMain.h>\r
+#include "DxeMain.h"\r
+#include "FwVolDriver.h"\r
 \r
-#define KEYSIZE       sizeof (UINTN)\r
 \r
 //\r
 // Protocol notify related globals\r
@@ -35,7 +29,7 @@ FV_DEVICE mFvDevice = {
     FvReadFileSection,\r
     FvWriteFile,\r
     FvGetNextFile,\r
-    KEYSIZE,\r
+  sizeof (UINTN),\r
     NULL,\r
     FvGetVolumeInfo,\r
     FvSetVolumeInfo\r
@@ -45,54 +39,182 @@ FV_DEVICE mFvDevice = {
   NULL,\r
   NULL,\r
   { NULL, NULL },\r
-  0\r
+  0,\r
+  0,\r
+  FALSE,\r
+  FALSE\r
 };\r
 \r
 \r
 //\r
 // FFS helper functions\r
 //\r
-\r
+/**\r
+  Read data from Firmware Block by FVB protocol Read.\r
+  The data may cross the multi block ranges.\r
+\r
+  @param  Fvb                   The FW_VOL_BLOCK_PROTOCOL instance from which to read data.\r
+  @param  StartLba              Pointer to StartLba.\r
+                                On input, the start logical block index from which to read.\r
+                                On output,the end logical block index after reading.\r
+  @param  Offset                Pointer to Offset\r
+                                On input, offset into the block at which to begin reading.\r
+                                On output, offset into the end block after reading.\r
+  @param  DataSize              Size of data to be read.\r
+  @param  Data                  Pointer to Buffer that the data will be read into.\r
+\r
+  @retval EFI_SUCCESS           Successfully read data from firmware block.\r
+  @retval others\r
+**/\r
 EFI_STATUS\r
-GetFwVolHeader (\r
+ReadFvbData (\r
   IN     EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL     *Fvb,\r
-  OUT    EFI_FIRMWARE_VOLUME_HEADER             **FwVolHeader\r
+  IN OUT EFI_LBA                                *StartLba,\r
+  IN OUT UINTN                                  *Offset,\r
+  IN     UINTN                                  DataSize,\r
+  OUT    UINT8                                  *Data\r
   )\r
-/*++\r
+{\r
+  UINTN                       BlockSize;\r
+  UINTN                       NumberOfBlocks;\r
+  UINTN                       BlockIndex;\r
+  UINTN                       ReadDataSize;\r
+  EFI_STATUS                  Status;\r
+\r
+  //\r
+  // Try read data in current block\r
+  //\r
+  BlockIndex   = 0;\r
+  ReadDataSize = DataSize;\r
+  Status = Fvb->Read (Fvb, *StartLba, *Offset, &ReadDataSize, Data);\r
+  if (Status == EFI_SUCCESS) {\r
+    *Offset  += DataSize;\r
+    return EFI_SUCCESS;\r
+  } else if (Status != EFI_BAD_BUFFER_SIZE) {\r
+    //\r
+    // other error will direct return\r
+    //\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Data crosses the blocks, read data from next block\r
+  //\r
+  DataSize -= ReadDataSize;\r
+  Data     += ReadDataSize;\r
+  *StartLba = *StartLba + 1;\r
+  while (DataSize > 0) {\r
+    Status = Fvb->GetBlockSize (Fvb, *StartLba, &BlockSize, &NumberOfBlocks);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+\r
+    //\r
+    // Read data from the crossing blocks\r
+    //\r
+    BlockIndex = 0;\r
+    while (BlockIndex < NumberOfBlocks && DataSize >= BlockSize) {\r
+      Status = Fvb->Read (Fvb, *StartLba + BlockIndex, 0, &BlockSize, Data);\r
+      if (EFI_ERROR (Status)) {\r
+        return Status;\r
+      }\r
+      Data += BlockSize;\r
+      DataSize -= BlockSize;\r
+      BlockIndex ++;\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
+    // Data doesn't exceed the current block range.\r
+    //\r
+    if (DataSize < BlockSize) {\r
+      break;\r
+    }\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
+    // Data must be got from the next block range.\r
+    //\r
+    *StartLba += NumberOfBlocks;\r
+  }\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
+  // read the remaining data\r
+  //\r
+  if (DataSize > 0) {\r
+    Status = Fvb->Read (Fvb, *StartLba + BlockIndex, 0, &DataSize, Data);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+  }\r
 \r
---*/\r
+  //\r
+  // Update Lba and Offset used by the following read.\r
+  //\r
+  *StartLba += BlockIndex;\r
+  *Offset   = DataSize;\r
 \r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Given the supplied FW_VOL_BLOCK_PROTOCOL, allocate a buffer for output and\r
+  copy the real length volume header into it.\r
+\r
+  @param  Fvb                   The FW_VOL_BLOCK_PROTOCOL instance from which to\r
+                                read the volume header\r
+  @param  FwVolHeader           Pointer to pointer to allocated buffer in which\r
+                                the volume header is returned.\r
+\r
+  @retval EFI_OUT_OF_RESOURCES  No enough buffer could be allocated.\r
+  @retval EFI_SUCCESS           Successfully read volume header to the allocated\r
+                                buffer.\r
+  @retval EFI_INVALID_PARAMETER The FV Header signature is not as expected or\r
+                                the file system could not be understood.\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
   EFI_STATUS                  Status;\r
   EFI_FIRMWARE_VOLUME_HEADER  TempFvh;\r
   UINTN                       FvhLength;\r
+  EFI_LBA                     StartLba;\r
+  UINTN                       Offset;\r
   UINT8                       *Buffer;\r
 \r
-\r
   //\r
-  //Determine the real length of FV header\r
+  // Read the standard FV header\r
   //\r
+  StartLba = 0;\r
+  Offset   = 0;\r
   FvhLength = sizeof (EFI_FIRMWARE_VOLUME_HEADER);\r
-  Status = Fvb->Read (Fvb, 0, 0, &FvhLength, (UINT8 *)&TempFvh);\r
+  Status = ReadFvbData (Fvb, &StartLba, &Offset, FvhLength, (UINT8 *)&TempFvh);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Validate FV Header signature, if not as expected, continue.\r
+  //\r
+  if (TempFvh.Signature != EFI_FVH_SIGNATURE) {\r
+    return EFI_INVALID_PARAMETER;\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 (&TempFvh.FileSystemGuid, &gEfiFirmwareFileSystem2Guid)) &&\r
+      (!CompareGuid (&TempFvh.FileSystemGuid, &gEfiFirmwareFileSystem3Guid))) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
 \r
   //\r
   // Allocate a buffer for the caller\r
   //\r
-  *FwVolHeader = CoreAllocateBootServicesPool (TempFvh.HeaderLength);\r
+  *FwVolHeader = AllocatePool (TempFvh.HeaderLength);\r
   if (*FwVolHeader == NULL) {\r
     return EFI_OUT_OF_RESOURCES;\r
   }\r
@@ -107,35 +229,29 @@ Returns:
   //\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
+  Status = ReadFvbData (Fvb, &StartLba, &Offset, FvhLength, Buffer);\r
   if (EFI_ERROR (Status)) {\r
     //\r
     // Read failed so free buffer\r
     //\r
     CoreFreePool (*FwVolHeader);\r
   }\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
+/**\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
+  @param  FvDevice              pointer to the FvDevice to be freed.\r
 \r
---*/\r
+**/\r
+VOID\r
+FreeFvDeviceResource (\r
+  IN FV_DEVICE  *FvDevice\r
+  )\r
 {\r
   FFS_FILE_LIST_ENTRY         *FfsFileEntry;\r
   LIST_ENTRY                  *NextEntry;\r
@@ -146,24 +262,32 @@ Returns:
   FfsFileEntry = (FFS_FILE_LIST_ENTRY *)FvDevice->FfsFileListHeader.ForwardLink;\r
   while (&FfsFileEntry->Link != &FvDevice->FfsFileListHeader) {\r
     NextEntry = (&FfsFileEntry->Link)->ForwardLink;\r
-    \r
+\r
     if (FfsFileEntry->StreamHandle != 0) {\r
       //\r
       // Close stream and free resources from SEP\r
       //\r
-      CloseSectionStream (FfsFileEntry->StreamHandle);\r
+      CloseSectionStream (FfsFileEntry->StreamHandle, FALSE);\r
+    }\r
+\r
+    if (FfsFileEntry->FileCached) {\r
+      //\r
+      // Free the cached file buffer.\r
+      //\r
+      CoreFreePool (FfsFileEntry->FfsHeader);\r
     }\r
 \r
     CoreFreePool (FfsFileEntry);\r
 \r
-    FfsFileEntry = (FFS_FILE_LIST_ENTRY *)NextEntry;\r
+    FfsFileEntry = (FFS_FILE_LIST_ENTRY *) NextEntry;\r
   }\r
 \r
-\r
-  //\r
-  // Free the cache\r
-  //\r
-  CoreFreePool (FvDevice->CachedFv);\r
+  if (!FvDevice->IsMemoryMapped) {\r
+    //\r
+    // Free the cached FV buffer.\r
+    //\r
+    CoreFreePool (FvDevice->CachedFv);\r
+  }\r
 \r
   //\r
   // Free Volume Header\r
@@ -174,123 +298,129 @@ Returns:
 }\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
+  Check if an FV is consistent and allocate cache for it.\r
 \r
-Arguments:\r
-  FvDevice - pointer to the FvDevice to be checked.\r
+  @param  FvDevice              A 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
+  @retval EFI_OUT_OF_RESOURCES  No enough buffer could be allocated.\r
+  @retval EFI_SUCCESS           FV is consistent and cache is allocated.\r
+  @retval EFI_VOLUME_CORRUPTED  File system is corrupted.\r
 \r
---*/\r
+**/\r
+EFI_STATUS\r
+FvCheck (\r
+  IN OUT FV_DEVICE  *FvDevice\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_FIRMWARE_VOLUME_EXT_HEADER        *FwVolExtHeader;\r
+  EFI_FVB_ATTRIBUTES_2                  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
+  EFI_PHYSICAL_ADDRESS                  PhysicalAddress;\r
+  BOOLEAN                               FileCached;\r
+  UINTN                                 WholeFileSize;\r
+  EFI_FFS_FILE_HEADER                   *CacheFfsHeader;\r
 \r
+  FileCached = FALSE;\r
+  CacheFfsHeader = NULL;\r
 \r
   Fvb = FvDevice->Fvb;\r
   FwVolHeader = FvDevice->FwVolHeader;\r
\r
+\r
   Status = Fvb->GetAttributes (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
+  Size = (UINTN) FwVolHeader->FvLength;\r
+  if ((FvbAttributes & EFI_FVB2_MEMORY_MAPPED) != 0) {\r
+    FvDevice->IsMemoryMapped = TRUE;\r
 \r
-  if (FvDevice->CachedFv == NULL) {\r
-    return EFI_OUT_OF_RESOURCES;\r
+    Status = Fvb->GetPhysicalAddress (Fvb, &PhysicalAddress);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+\r
+    //\r
+    // Don't cache memory mapped FV really.\r
+    //\r
+    FvDevice->CachedFv = (UINT8 *) (UINTN) PhysicalAddress;\r
+  } else {\r
+    FvDevice->IsMemoryMapped = FALSE;\r
+    FvDevice->CachedFv = AllocatePool (Size);\r
+\r
+    if (FvDevice->CachedFv == NULL) {\r
+      return EFI_OUT_OF_RESOURCES;\r
+    }\r
   }\r
 \r
   //\r
-  // Remember a pointer to the end fo the CachedFv\r
+  // Remember a pointer to the end of 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->BlockMap;\r
-  CacheLocation = FvDevice->CachedFv;\r
-  LbaIndex = 0;\r
-  LbaOffset = FwVolHeader->HeaderLength;\r
-  while ((BlockMap->NumBlocks != 0) || (BlockMap->Length != 0)) {\r
-    \r
-    for (Index = 0; Index < BlockMap->NumBlocks; Index ++) {\r
-\r
+  if (!FvDevice->IsMemoryMapped) {\r
+    //\r
+    // Copy FV into memory using the block map.\r
+    //\r
+    BlockMap = FwVolHeader->BlockMap;\r
+    CacheLocation = FvDevice->CachedFv;\r
+    LbaIndex = 0;\r
+    while ((BlockMap->NumBlocks != 0) || (BlockMap->Length != 0)) {\r
+      //\r
+      // read the FV data\r
+      //\r
       Size = BlockMap->Length;\r
-      if (Index == 0) {\r
+      for (Index = 0; Index < BlockMap->NumBlocks; Index++) {\r
+        Status = Fvb->Read (\r
+                        Fvb,\r
+                        LbaIndex,\r
+                        0,\r
+                        &Size,\r
+                        CacheLocation\r
+                        );\r
+\r
         //\r
-        // Cache does not include FV Header\r
+        // Not check EFI_BAD_BUFFER_SIZE, for Size = BlockMap->Length\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->Length\r
-      //\r
-      if (EFI_ERROR (Status)) {\r
-        goto Done;\r
+        if (EFI_ERROR (Status)) {\r
+          goto Done;\r
+        }\r
+\r
+        LbaIndex++;\r
+        CacheLocation += BlockMap->Length;\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
+      BlockMap++;\r
     }\r
-    BlockMap++;\r
   }\r
 \r
   //\r
   // Scan to check the free space & File list\r
   //\r
-  if (FvbAttributes & EFI_FVB2_ERASE_POLARITY) {\r
+  if ((FvbAttributes & EFI_FVB2_ERASE_POLARITY) != 0) {\r
     FvDevice->ErasePolarity = 1;\r
   } else {\r
     FvDevice->ErasePolarity = 0;\r
-  } \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
+  // Make a linked list of all the Ffs file headers\r
   //\r
   Status = EFI_SUCCESS;\r
   InitializeListHead (&FvDevice->FfsFileListHeader);\r
@@ -298,11 +428,25 @@ Returns:
   //\r
   // Build FFS list\r
   //\r
-  FfsHeader = (EFI_FFS_FILE_HEADER *)FvDevice->CachedFv;\r
+  if (FwVolHeader->ExtHeaderOffset != 0) {\r
+    //\r
+    // Searching for files starts on an 8 byte aligned boundary after the end of the Extended Header if it exists.\r
+    //\r
+    FwVolExtHeader = (EFI_FIRMWARE_VOLUME_EXT_HEADER *) (FvDevice->CachedFv + FwVolHeader->ExtHeaderOffset);\r
+    FfsHeader = (EFI_FFS_FILE_HEADER *) ((UINT8 *) FwVolExtHeader + FwVolExtHeader->ExtHeaderSize);\r
+  } else {\r
+    FfsHeader = (EFI_FFS_FILE_HEADER *) (FvDevice->CachedFv + FwVolHeader->HeaderLength);\r
+  }\r
+  FfsHeader = (EFI_FFS_FILE_HEADER *) ALIGN_POINTER (FfsHeader, 8);\r
   TopFvAddress = FvDevice->EndOfCachedFv;\r
-  while ((UINT8 *)FfsHeader < TopFvAddress) {\r
+  while (((UINTN) FfsHeader >= (UINTN) FvDevice->CachedFv) && ((UINTN) FfsHeader <= (UINTN) ((UINTN) TopFvAddress - sizeof (EFI_FFS_FILE_HEADER)))) {\r
 \r
-    TestLength = TopFvAddress - ((UINT8 *)FfsHeader);\r
+    if (FileCached) {\r
+      CoreFreePool (CacheFfsHeader);\r
+      FileCached = FALSE;\r
+    }\r
+\r
+    TestLength = TopFvAddress - ((UINT8 *) FfsHeader);\r
     if (TestLength > sizeof (EFI_FFS_FILE_HEADER)) {\r
       TestLength = sizeof (EFI_FFS_FILE_HEADER);\r
     }\r
@@ -315,12 +459,17 @@ Returns:
     }\r
 \r
     if (!IsValidFfsHeader (FvDevice->ErasePolarity, FfsHeader, &FileState)) {\r
-      if ((FileState == EFI_FILE_HEADER_INVALID) || \r
+      if ((FileState == EFI_FILE_HEADER_INVALID) ||\r
           (FileState == EFI_FILE_HEADER_CONSTRUCTION)) {\r
-        FfsHeader++;\r
-      \r
+        if (IS_FFS_FILE2 (FfsHeader)) {\r
+          if (!FvDevice->IsFfs3Fv) {\r
+            DEBUG ((EFI_D_ERROR, "Found a FFS3 formatted file: %g in a non-FFS3 formatted FV.\n", &FfsHeader->Name));\r
+          }\r
+          FfsHeader = (EFI_FFS_FILE_HEADER *) ((UINT8 *) FfsHeader + sizeof (EFI_FFS_FILE_HEADER2));\r
+        } else {\r
+          FfsHeader = (EFI_FFS_FILE_HEADER *) ((UINT8 *) FfsHeader + sizeof (EFI_FFS_FILE_HEADER));\r
+        }\r
         continue;\r
-      \r
       } else {\r
         //\r
         // File system is corrputed\r
@@ -330,7 +479,25 @@ Returns:
       }\r
     }\r
 \r
-    if (!IsValidFfsFile (FvDevice->ErasePolarity, FfsHeader)) {\r
+    CacheFfsHeader = FfsHeader;\r
+    if ((CacheFfsHeader->Attributes & FFS_ATTRIB_CHECKSUM) == FFS_ATTRIB_CHECKSUM) {\r
+      if (FvDevice->IsMemoryMapped) {\r
+        //\r
+        // Memory mapped FV has not been cached.\r
+        // Here is to cache FFS file to memory buffer for following checksum calculating.\r
+        // And then, the cached file buffer can be also used for FvReadFile.\r
+        //\r
+        WholeFileSize = IS_FFS_FILE2 (CacheFfsHeader) ? FFS_FILE2_SIZE (CacheFfsHeader): FFS_FILE_SIZE (CacheFfsHeader);\r
+        CacheFfsHeader = AllocateCopyPool (WholeFileSize, CacheFfsHeader);\r
+        if (CacheFfsHeader == NULL) {\r
+          Status = EFI_OUT_OF_RESOURCES;\r
+          goto Done;\r
+        }\r
+        FileCached = TRUE;\r
+      }\r
+    }\r
+\r
+    if (!IsValidFfsFile (FvDevice->ErasePolarity, CacheFfsHeader)) {\r
       //\r
       // File system is corrupted\r
       //\r
@@ -338,13 +505,21 @@ Returns:
       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
+    if (IS_FFS_FILE2 (CacheFfsHeader)) {\r
+      ASSERT (FFS_FILE2_SIZE (CacheFfsHeader) > 0x00FFFFFF);\r
+      if (!FvDevice->IsFfs3Fv) {\r
+        DEBUG ((EFI_D_ERROR, "Found a FFS3 formatted file: %g in a non-FFS3 formatted FV.\n", &CacheFfsHeader->Name));\r
+        FfsHeader = (EFI_FFS_FILE_HEADER *) ((UINT8 *) FfsHeader + FFS_FILE2_SIZE (CacheFfsHeader));\r
+        //\r
+        // Adjust pointer to the next 8-byte aligned boundary.\r
+        //\r
+        FfsHeader = (EFI_FFS_FILE_HEADER *) (((UINTN) FfsHeader + 7) & ~0x07);\r
+        continue;\r
+      }\r
+    }\r
+\r
+    FileState = GetFileState (FvDevice->ErasePolarity, CacheFfsHeader);\r
 \r
-    FileState = GetFileState (FvDevice->ErasePolarity, FfsHeader);\r
-    \r
     //\r
     // check for non-deleted file\r
     //\r
@@ -352,27 +527,37 @@ Returns:
       //\r
       // Create a FFS list entry for each non-deleted file\r
       //\r
-      FfsFileEntry = CoreAllocateZeroBootServicesPool (sizeof (FFS_FILE_LIST_ENTRY));\r
+      FfsFileEntry = AllocateZeroPool (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
+\r
+      FfsFileEntry->FfsHeader = CacheFfsHeader;\r
+      FfsFileEntry->FileCached = FileCached;\r
+      FileCached = FALSE;\r
       InsertTailList (&FvDevice->FfsFileListHeader, &FfsFileEntry->Link);\r
     }\r
 \r
-    FfsHeader =  (EFI_FFS_FILE_HEADER *)(((UINT8 *)FfsHeader) + FileLength);\r
-    \r
+    if (IS_FFS_FILE2 (CacheFfsHeader)) {\r
+      FfsHeader = (EFI_FFS_FILE_HEADER *) ((UINT8 *) FfsHeader + FFS_FILE2_SIZE (CacheFfsHeader));\r
+    } else {\r
+      FfsHeader = (EFI_FFS_FILE_HEADER *) ((UINT8 *) FfsHeader + FFS_FILE_SIZE (CacheFfsHeader));\r
+    }\r
+\r
     //\r
-    // Adjust pointer to the next 8-byte aligned boundry.\r
+    // Adjust pointer to the next 8-byte aligned boundary.\r
     //\r
     FfsHeader = (EFI_FFS_FILE_HEADER *)(((UINTN)FfsHeader + 7) & ~0x07);\r
-    \r
+\r
   }\r
 \r
 Done:\r
   if (EFI_ERROR (Status)) {\r
+    if (FileCached) {\r
+      CoreFreePool (CacheFfsHeader);\r
+      FileCached = FALSE;\r
+    }\r
     FreeFvDeviceResource (FvDevice);\r
   }\r
 \r
@@ -380,30 +565,23 @@ Done:
 }\r
 \r
 \r
-STATIC\r
+\r
+/**\r
+  This notification function is invoked when an instance of the\r
+  EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL is produced.  It layers an instance of the\r
+  EFI_FIRMWARE_VOLUME2_PROTOCOL on the same handle.  This is the function where\r
+  the actual initialization of the EFI_FIRMWARE_VOLUME2_PROTOCOL is done.\r
+\r
+  @param  Event                 The event that occured\r
+  @param  Context               For EFI compatiblity.  Not used.\r
+\r
+**/\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_VOLUME2_PROTOCOL on the same handle.  This is the function where\r
-    the actual initialization of the EFI_FIRMWARE_VOLUME2_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
@@ -438,36 +616,28 @@ Returns:
     if (EFI_ERROR (Status)) {\r
       continue;\r
     }\r
-    \r
+\r
     //\r
     // Get the FirmwareVolumeBlock protocol on that handle\r
     //\r
-    Status = CoreHandleProtocol (Handle, &gEfiFirmwareVolumeBlockProtocolGuid, (VOID **)&Fvb); \r
+    Status = CoreHandleProtocol (Handle, &gEfiFirmwareVolumeBlockProtocolGuid, (VOID **)&Fvb);\r
     ASSERT_EFI_ERROR (Status);\r
-    \r
+    ASSERT (Fvb != NULL);\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
+      continue;\r
     }\r
+    ASSERT (FwVolHeader != NULL);\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, &gEfiFirmwareFileSystem2Guid)) {\r
-      continue;\r
-    }\r
-\r
     //\r
     // Check if there is an FV protocol already installed in that handle\r
     //\r
@@ -476,7 +646,7 @@ Returns:
       //\r
       // Update Fv to use a new Fvb\r
       //\r
-      FvDevice = _CR (Fv, FV_DEVICE, Fv);\r
+      FvDevice = BASE_CR (Fv, FV_DEVICE, Fv);\r
       if (FvDevice->Signature == FV2_DEVICE_SIGNATURE) {\r
         //\r
         // Only write into our device structure if it's our device structure\r
@@ -488,63 +658,72 @@ Returns:
       //\r
       // No FwVol protocol on the handle so create a new one\r
       //\r
-      FvDevice = CoreAllocateCopyPool (sizeof (FV_DEVICE), &mFvDevice);\r
+      FvDevice = AllocateCopyPool (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
+\r
+      FvDevice->Fvb             = Fvb;\r
+      FvDevice->Handle          = Handle;\r
+      FvDevice->FwVolHeader     = FwVolHeader;\r
+      FvDevice->IsFfs3Fv        = CompareGuid (&FwVolHeader->FileSystemGuid, &gEfiFirmwareFileSystem3Guid);\r
       FvDevice->Fv.ParentHandle = Fvb->ParentHandle;\r
-      \r
       //\r
-      // Install an New FV protocol on the existing handle\r
+      // Inherit the authentication status from FVB.\r
       //\r
-      Status = CoreInstallProtocolInterface (\r
-                  &Handle,\r
-                  &gEfiFirmwareVolume2ProtocolGuid,\r
-                  EFI_NATIVE_INTERFACE,\r
-                  &FvDevice->Fv\r
-                  );\r
-      ASSERT_EFI_ERROR (Status);\r
+      FvDevice->AuthenticationStatus = GetFvbAuthenticationStatus (Fvb);\r
+\r
+      if (!EFI_ERROR (FvCheck (FvDevice))) {\r
+        //\r
+        // Install an New FV protocol on the existing handle\r
+        //\r
+        Status = CoreInstallProtocolInterface (\r
+                    &Handle,\r
+                    &gEfiFirmwareVolume2ProtocolGuid,\r
+                    EFI_NATIVE_INTERFACE,\r
+                    &FvDevice->Fv\r
+                    );\r
+        ASSERT_EFI_ERROR (Status);\r
+      } else {\r
+        //\r
+        // Free FvDevice Buffer for the corrupt FV image.\r
+        //\r
+        CoreFreePool (FvDevice);\r
+      }\r
     }\r
   }\r
-  \r
+\r
   return;\r
 }\r
 \r
 \r
+\r
+/**\r
+  This routine is the driver initialization entry point.  It registers\r
+  a notification function.  This notification function are responsible\r
+  for building the FV stack dynamically.\r
+\r
+  @param  ImageHandle           The image handle.\r
+  @param  SystemTable           The system table.\r
+\r
+  @retval EFI_SUCCESS           Function successfully returned.\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
+  gEfiFwVolBlockEvent = EfiCreateProtocolNotifyEvent (\r
                           &gEfiFirmwareVolumeBlockProtocolGuid,\r
                           TPL_CALLBACK,\r
                           NotifyFwVolBlock,\r
                           NULL,\r
-                          &gEfiFwVolBlockNotifyReg,\r
-                          TRUE\r
+                          &gEfiFwVolBlockNotifyReg\r
                           );\r
   return EFI_SUCCESS;\r
 }\r
 \r
+\r