]> 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 2829092e178cdc9ee3852c22b69f42ab23ffb469..e2f58c4d82a81a770c493d2e9f5bec65692b47d6 100644 (file)
@@ -3,14 +3,8 @@
   Layers on top of Firmware Block protocol to produce a file abstraction\r
   of FV based files.\r
 \r
-Copyright (c) 2006 - 2008, 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
+Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>\r
+SPDX-License-Identifier: BSD-2-Clause-Patent\r
 \r
 **/\r
 \r
@@ -34,8 +28,8 @@ FV_DEVICE mFvDevice = {
     FvReadFile,\r
     FvReadFileSection,\r
     FvWriteFile,\r
-    FvGetNextFile,   \r
-       sizeof (UINTN),\r
+    FvGetNextFile,\r
+  sizeof (UINTN),\r
     NULL,\r
     FvGetVolumeInfo,\r
     FvSetVolumeInfo\r
@@ -45,7 +39,10 @@ FV_DEVICE mFvDevice = {
   NULL,\r
   NULL,\r
   { NULL, NULL },\r
-  0\r
+  0,\r
+  0,\r
+  FALSE,\r
+  FALSE\r
 };\r
 \r
 \r
@@ -53,7 +50,7 @@ FV_DEVICE mFvDevice = {
 // FFS helper functions\r
 //\r
 /**\r
-  Read data from Firmware Block by FVB protocol Read. \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
@@ -83,7 +80,7 @@ ReadFvbData (
   UINTN                       BlockIndex;\r
   UINTN                       ReadDataSize;\r
   EFI_STATUS                  Status;\r
-  \r
+\r
   //\r
   // Try read data in current block\r
   //\r
@@ -99,7 +96,7 @@ ReadFvbData (
     //\r
     return Status;\r
   }\r
-  \r
+\r
   //\r
   // Data crosses the blocks, read data from next block\r
   //\r
@@ -115,7 +112,7 @@ ReadFvbData (
     //\r
     // Read data from the crossing blocks\r
     //\r
-    BlockIndex = 0; \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
@@ -125,20 +122,20 @@ ReadFvbData (
       DataSize -= BlockSize;\r
       BlockIndex ++;\r
     }\r
-    \r
+\r
     //\r
     // Data doesn't exceed the current block range.\r
     //\r
     if (DataSize < BlockSize) {\r
       break;\r
     }\r
-    \r
+\r
     //\r
     // Data must be got from the next block range.\r
     //\r
     *StartLba += NumberOfBlocks;\r
   }\r
-  \r
+\r
   //\r
   // read the remaining data\r
   //\r
@@ -148,7 +145,7 @@ ReadFvbData (
       return Status;\r
     }\r
   }\r
-  \r
+\r
   //\r
   // Update Lba and Offset used by the following read.\r
   //\r
@@ -170,6 +167,8 @@ ReadFvbData (
   @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
@@ -184,7 +183,7 @@ GetFwVolHeader (
   EFI_LBA                     StartLba;\r
   UINTN                       Offset;\r
   UINT8                       *Buffer;\r
-  \r
+\r
   //\r
   // Read the standard FV header\r
   //\r
@@ -196,6 +195,22 @@ GetFwVolHeader (
     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
@@ -252,7 +267,14 @@ FreeFvDeviceResource (
       //\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
@@ -260,11 +282,12 @@ FreeFvDeviceResource (
     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
@@ -294,21 +317,25 @@ FvCheck (
   EFI_STATUS                            Status;\r
   EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL    *Fvb;\r
   EFI_FIRMWARE_VOLUME_HEADER            *FwVolHeader;\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                                 HeaderSize;\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
@@ -318,85 +345,67 @@ FvCheck (
     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 = AllocatePool (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 = 0;\r
-  HeaderSize = FwVolHeader->HeaderLength;\r
-  while ((BlockMap->NumBlocks != 0) || (BlockMap->Length != 0)) {\r
-    Index = 0;\r
-    Size  = BlockMap->Length;\r
-    if (HeaderSize > 0) {\r
-      //\r
-      // Skip header size\r
-      //\r
-      for (; Index < BlockMap->NumBlocks && HeaderSize >= BlockMap->Length; Index ++) {\r
-        HeaderSize -= BlockMap->Length;\r
-        LbaIndex ++;\r
-      }\r
-\r
-      //\r
-      // Check whether FvHeader is crossing the multi block range.\r
-      //\r
-      if (HeaderSize > BlockMap->Length) {\r
-        BlockMap++;\r
-        continue;\r
-      } else if (HeaderSize > 0) {\r
-        LbaOffset = HeaderSize;\r
-        Size = BlockMap->Length - HeaderSize;\r
-        HeaderSize = 0;\r
-      }\r
-    }\r
-    \r
+  if (!FvDevice->IsMemoryMapped) {\r
     //\r
-    // read the FV data  \r
+    // Copy FV into memory using the block map.\r
     //\r
-    for (; Index < BlockMap->NumBlocks; Index ++) {\r
-      Status = Fvb->Read (Fvb,\r
-                      LbaIndex,\r
-                      LbaOffset,\r
-                      &Size,\r
-                      CacheLocation\r
-                      );\r
-\r
+    BlockMap = FwVolHeader->BlockMap;\r
+    CacheLocation = FvDevice->CachedFv;\r
+    LbaIndex = 0;\r
+    while ((BlockMap->NumBlocks != 0) || (BlockMap->Length != 0)) {\r
       //\r
-      // Not check EFI_BAD_BUFFER_SIZE, for Size = BlockMap->Length\r
+      // read the FV data\r
       //\r
-      if (EFI_ERROR (Status)) {\r
-        goto Done;\r
-      }\r
+      Size = BlockMap->Length;\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
+        // Not check EFI_BAD_BUFFER_SIZE, for Size = BlockMap->Length\r
+        //\r
+        if (EFI_ERROR (Status)) {\r
+          goto Done;\r
+        }\r
 \r
-      LbaIndex++;\r
-      CacheLocation += Size;\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
-      Size  = BlockMap->Length;\r
+      BlockMap++;\r
     }\r
-\r
-    BlockMap++;\r
   }\r
 \r
   //\r
@@ -411,7 +420,7 @@ FvCheck (
 \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
@@ -419,9 +428,23 @@ FvCheck (
   //\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
+    if (FileCached) {\r
+      CoreFreePool (CacheFfsHeader);\r
+      FileCached = FALSE;\r
+    }\r
 \r
     TestLength = TopFvAddress - ((UINT8 *) FfsHeader);\r
     if (TestLength > sizeof (EFI_FFS_FILE_HEADER)) {\r
@@ -438,7 +461,14 @@ FvCheck (
     if (!IsValidFfsHeader (FvDevice->ErasePolarity, FfsHeader, &FileState)) {\r
       if ((FileState == EFI_FILE_HEADER_INVALID) ||\r
           (FileState == EFI_FILE_HEADER_CONSTRUCTION)) {\r
-        FfsHeader++;\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
       } else {\r
         //\r
@@ -449,7 +479,25 @@ FvCheck (
       }\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
@@ -457,12 +505,20 @@ FvCheck (
       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, FfsHeader);\r
+    FileState = GetFileState (FvDevice->ErasePolarity, CacheFfsHeader);\r
 \r
     //\r
     // check for non-deleted file\r
@@ -477,14 +533,20 @@ FvCheck (
         goto Done;\r
       }\r
 \r
-      FfsFileEntry->FfsHeader = FfsHeader;\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
+    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
@@ -492,6 +554,10 @@ FvCheck (
 \r
 Done:\r
   if (EFI_ERROR (Status)) {\r
+    if (FileCached) {\r
+      CoreFreePool (CacheFfsHeader);\r
+      FileCached = FALSE;\r
+    }\r
     FreeFvDeviceResource (FvDevice);\r
   }\r
 \r
@@ -502,7 +568,7 @@ Done:
 \r
 /**\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_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
@@ -556,30 +622,22 @@ NotifyFwVolBlock (
     //\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
@@ -608,18 +666,30 @@ NotifyFwVolBlock (
       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