Home | History | Annotate | Download | only in FwVol
      1 /** @file
      2   Firmware File System driver that produce Firmware Volume protocol.
      3   Layers on top of Firmware Block protocol to produce a file abstraction
      4   of FV based files.
      5 
      6 Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
      7 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
     11 
     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.
     14 
     15 **/
     16 
     17 #include "DxeMain.h"
     18 #include "FwVolDriver.h"
     19 
     20 
     21 //
     22 // Protocol notify related globals
     23 //
     24 VOID          *gEfiFwVolBlockNotifyReg;
     25 EFI_EVENT     gEfiFwVolBlockEvent;
     26 
     27 FV_DEVICE mFvDevice = {
     28   FV2_DEVICE_SIGNATURE,
     29   NULL,
     30   NULL,
     31   {
     32     FvGetVolumeAttributes,
     33     FvSetVolumeAttributes,
     34     FvReadFile,
     35     FvReadFileSection,
     36     FvWriteFile,
     37     FvGetNextFile,
     38 	sizeof (UINTN),
     39     NULL,
     40     FvGetVolumeInfo,
     41     FvSetVolumeInfo
     42   },
     43   NULL,
     44   NULL,
     45   NULL,
     46   NULL,
     47   { NULL, NULL },
     48   0,
     49   0,
     50   FALSE,
     51   FALSE
     52 };
     53 
     54 
     55 //
     56 // FFS helper functions
     57 //
     58 /**
     59   Read data from Firmware Block by FVB protocol Read.
     60   The data may cross the multi block ranges.
     61 
     62   @param  Fvb                   The FW_VOL_BLOCK_PROTOCOL instance from which to read data.
     63   @param  StartLba              Pointer to StartLba.
     64                                 On input, the start logical block index from which to read.
     65                                 On output,the end logical block index after reading.
     66   @param  Offset                Pointer to Offset
     67                                 On input, offset into the block at which to begin reading.
     68                                 On output, offset into the end block after reading.
     69   @param  DataSize              Size of data to be read.
     70   @param  Data                  Pointer to Buffer that the data will be read into.
     71 
     72   @retval EFI_SUCCESS           Successfully read data from firmware block.
     73   @retval others
     74 **/
     75 EFI_STATUS
     76 ReadFvbData (
     77   IN     EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL     *Fvb,
     78   IN OUT EFI_LBA                                *StartLba,
     79   IN OUT UINTN                                  *Offset,
     80   IN     UINTN                                  DataSize,
     81   OUT    UINT8                                  *Data
     82   )
     83 {
     84   UINTN                       BlockSize;
     85   UINTN                       NumberOfBlocks;
     86   UINTN                       BlockIndex;
     87   UINTN                       ReadDataSize;
     88   EFI_STATUS                  Status;
     89 
     90   //
     91   // Try read data in current block
     92   //
     93   BlockIndex   = 0;
     94   ReadDataSize = DataSize;
     95   Status = Fvb->Read (Fvb, *StartLba, *Offset, &ReadDataSize, Data);
     96   if (Status == EFI_SUCCESS) {
     97     *Offset  += DataSize;
     98     return EFI_SUCCESS;
     99   } else if (Status != EFI_BAD_BUFFER_SIZE) {
    100     //
    101     // other error will direct return
    102     //
    103     return Status;
    104   }
    105 
    106   //
    107   // Data crosses the blocks, read data from next block
    108   //
    109   DataSize -= ReadDataSize;
    110   Data     += ReadDataSize;
    111   *StartLba = *StartLba + 1;
    112   while (DataSize > 0) {
    113     Status = Fvb->GetBlockSize (Fvb, *StartLba, &BlockSize, &NumberOfBlocks);
    114     if (EFI_ERROR (Status)) {
    115       return Status;
    116     }
    117 
    118     //
    119     // Read data from the crossing blocks
    120     //
    121     BlockIndex = 0;
    122     while (BlockIndex < NumberOfBlocks && DataSize >= BlockSize) {
    123       Status = Fvb->Read (Fvb, *StartLba + BlockIndex, 0, &BlockSize, Data);
    124       if (EFI_ERROR (Status)) {
    125         return Status;
    126       }
    127       Data += BlockSize;
    128       DataSize -= BlockSize;
    129       BlockIndex ++;
    130     }
    131 
    132     //
    133     // Data doesn't exceed the current block range.
    134     //
    135     if (DataSize < BlockSize) {
    136       break;
    137     }
    138 
    139     //
    140     // Data must be got from the next block range.
    141     //
    142     *StartLba += NumberOfBlocks;
    143   }
    144 
    145   //
    146   // read the remaining data
    147   //
    148   if (DataSize > 0) {
    149     Status = Fvb->Read (Fvb, *StartLba + BlockIndex, 0, &DataSize, Data);
    150     if (EFI_ERROR (Status)) {
    151       return Status;
    152     }
    153   }
    154 
    155   //
    156   // Update Lba and Offset used by the following read.
    157   //
    158   *StartLba += BlockIndex;
    159   *Offset   = DataSize;
    160 
    161   return EFI_SUCCESS;
    162 }
    163 
    164 /**
    165   Given the supplied FW_VOL_BLOCK_PROTOCOL, allocate a buffer for output and
    166   copy the real length volume header into it.
    167 
    168   @param  Fvb                   The FW_VOL_BLOCK_PROTOCOL instance from which to
    169                                 read the volume header
    170   @param  FwVolHeader           Pointer to pointer to allocated buffer in which
    171                                 the volume header is returned.
    172 
    173   @retval EFI_OUT_OF_RESOURCES  No enough buffer could be allocated.
    174   @retval EFI_SUCCESS           Successfully read volume header to the allocated
    175                                 buffer.
    176   @retval EFI_INVALID_PARAMETER The FV Header signature is not as expected or
    177                                 the file system could not be understood.
    178 
    179 **/
    180 EFI_STATUS
    181 GetFwVolHeader (
    182   IN     EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL     *Fvb,
    183   OUT    EFI_FIRMWARE_VOLUME_HEADER             **FwVolHeader
    184   )
    185 {
    186   EFI_STATUS                  Status;
    187   EFI_FIRMWARE_VOLUME_HEADER  TempFvh;
    188   UINTN                       FvhLength;
    189   EFI_LBA                     StartLba;
    190   UINTN                       Offset;
    191   UINT8                       *Buffer;
    192 
    193   //
    194   // Read the standard FV header
    195   //
    196   StartLba = 0;
    197   Offset   = 0;
    198   FvhLength = sizeof (EFI_FIRMWARE_VOLUME_HEADER);
    199   Status = ReadFvbData (Fvb, &StartLba, &Offset, FvhLength, (UINT8 *)&TempFvh);
    200   if (EFI_ERROR (Status)) {
    201     return Status;
    202   }
    203 
    204   //
    205   // Validate FV Header signature, if not as expected, continue.
    206   //
    207   if (TempFvh.Signature != EFI_FVH_SIGNATURE) {
    208     return EFI_INVALID_PARAMETER;
    209   }
    210 
    211   //
    212   // Check to see that the file system is indeed formatted in a way we can
    213   // understand it...
    214   //
    215   if ((!CompareGuid (&TempFvh.FileSystemGuid, &gEfiFirmwareFileSystem2Guid)) &&
    216       (!CompareGuid (&TempFvh.FileSystemGuid, &gEfiFirmwareFileSystem3Guid))) {
    217     return EFI_INVALID_PARAMETER;
    218   }
    219 
    220   //
    221   // Allocate a buffer for the caller
    222   //
    223   *FwVolHeader = AllocatePool (TempFvh.HeaderLength);
    224   if (*FwVolHeader == NULL) {
    225     return EFI_OUT_OF_RESOURCES;
    226   }
    227 
    228   //
    229   // Copy the standard header into the buffer
    230   //
    231   CopyMem (*FwVolHeader, &TempFvh, sizeof (EFI_FIRMWARE_VOLUME_HEADER));
    232 
    233   //
    234   // Read the rest of the header
    235   //
    236   FvhLength = TempFvh.HeaderLength - sizeof (EFI_FIRMWARE_VOLUME_HEADER);
    237   Buffer = (UINT8 *)*FwVolHeader + sizeof (EFI_FIRMWARE_VOLUME_HEADER);
    238   Status = ReadFvbData (Fvb, &StartLba, &Offset, FvhLength, Buffer);
    239   if (EFI_ERROR (Status)) {
    240     //
    241     // Read failed so free buffer
    242     //
    243     CoreFreePool (*FwVolHeader);
    244   }
    245 
    246   return Status;
    247 }
    248 
    249 
    250 
    251 /**
    252   Free FvDevice resource when error happens
    253 
    254   @param  FvDevice              pointer to the FvDevice to be freed.
    255 
    256 **/
    257 VOID
    258 FreeFvDeviceResource (
    259   IN FV_DEVICE  *FvDevice
    260   )
    261 {
    262   FFS_FILE_LIST_ENTRY         *FfsFileEntry;
    263   LIST_ENTRY                  *NextEntry;
    264 
    265   //
    266   // Free File List Entry
    267   //
    268   FfsFileEntry = (FFS_FILE_LIST_ENTRY *)FvDevice->FfsFileListHeader.ForwardLink;
    269   while (&FfsFileEntry->Link != &FvDevice->FfsFileListHeader) {
    270     NextEntry = (&FfsFileEntry->Link)->ForwardLink;
    271 
    272     if (FfsFileEntry->StreamHandle != 0) {
    273       //
    274       // Close stream and free resources from SEP
    275       //
    276       CloseSectionStream (FfsFileEntry->StreamHandle, FALSE);
    277     }
    278 
    279     if (FfsFileEntry->FileCached) {
    280       //
    281       // Free the cached file buffer.
    282       //
    283       CoreFreePool (FfsFileEntry->FfsHeader);
    284     }
    285 
    286     CoreFreePool (FfsFileEntry);
    287 
    288     FfsFileEntry = (FFS_FILE_LIST_ENTRY *) NextEntry;
    289   }
    290 
    291   if (!FvDevice->IsMemoryMapped) {
    292     //
    293     // Free the cached FV buffer.
    294     //
    295     CoreFreePool (FvDevice->CachedFv);
    296   }
    297 
    298   //
    299   // Free Volume Header
    300   //
    301   CoreFreePool (FvDevice->FwVolHeader);
    302 
    303   return;
    304 }
    305 
    306 
    307 
    308 /**
    309   Check if an FV is consistent and allocate cache for it.
    310 
    311   @param  FvDevice              A pointer to the FvDevice to be checked.
    312 
    313   @retval EFI_OUT_OF_RESOURCES  No enough buffer could be allocated.
    314   @retval EFI_SUCCESS           FV is consistent and cache is allocated.
    315   @retval EFI_VOLUME_CORRUPTED  File system is corrupted.
    316 
    317 **/
    318 EFI_STATUS
    319 FvCheck (
    320   IN OUT FV_DEVICE  *FvDevice
    321   )
    322 {
    323   EFI_STATUS                            Status;
    324   EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL    *Fvb;
    325   EFI_FIRMWARE_VOLUME_HEADER            *FwVolHeader;
    326   EFI_FIRMWARE_VOLUME_EXT_HEADER        *FwVolExtHeader;
    327   EFI_FVB_ATTRIBUTES_2                  FvbAttributes;
    328   EFI_FV_BLOCK_MAP_ENTRY                *BlockMap;
    329   FFS_FILE_LIST_ENTRY                   *FfsFileEntry;
    330   EFI_FFS_FILE_HEADER                   *FfsHeader;
    331   UINT8                                 *CacheLocation;
    332   UINTN                                 LbaOffset;
    333   UINTN                                 HeaderSize;
    334   UINTN                                 Index;
    335   EFI_LBA                               LbaIndex;
    336   UINTN                                 Size;
    337   EFI_FFS_FILE_STATE                    FileState;
    338   UINT8                                 *TopFvAddress;
    339   UINTN                                 TestLength;
    340   EFI_PHYSICAL_ADDRESS                  PhysicalAddress;
    341   BOOLEAN                               FileCached;
    342   UINTN                                 WholeFileSize;
    343   EFI_FFS_FILE_HEADER                   *CacheFfsHeader;
    344 
    345   FileCached = FALSE;
    346   CacheFfsHeader = NULL;
    347 
    348   Fvb = FvDevice->Fvb;
    349   FwVolHeader = FvDevice->FwVolHeader;
    350 
    351   Status = Fvb->GetAttributes (Fvb, &FvbAttributes);
    352   if (EFI_ERROR (Status)) {
    353     return Status;
    354   }
    355 
    356   //
    357   // Size is the size of the FV minus the head. We have already allocated
    358   // the header to check to make sure the volume is valid
    359   //
    360   Size = (UINTN)(FwVolHeader->FvLength - FwVolHeader->HeaderLength);
    361   if ((FvbAttributes & EFI_FVB2_MEMORY_MAPPED) != 0) {
    362     FvDevice->IsMemoryMapped = TRUE;
    363 
    364     Status = Fvb->GetPhysicalAddress (Fvb, &PhysicalAddress);
    365     if (EFI_ERROR (Status)) {
    366       return Status;
    367     }
    368 
    369     //
    370     // Don't cache memory mapped FV really.
    371     //
    372     FvDevice->CachedFv = (UINT8 *) (UINTN) (PhysicalAddress + FwVolHeader->HeaderLength);
    373   } else {
    374     FvDevice->IsMemoryMapped = FALSE;
    375     FvDevice->CachedFv = AllocatePool (Size);
    376 
    377     if (FvDevice->CachedFv == NULL) {
    378       return EFI_OUT_OF_RESOURCES;
    379     }
    380   }
    381 
    382   //
    383   // Remember a pointer to the end fo the CachedFv
    384   //
    385   FvDevice->EndOfCachedFv = FvDevice->CachedFv + Size;
    386 
    387   if (!FvDevice->IsMemoryMapped) {
    388     //
    389     // Copy FV minus header into memory using the block map we have all ready
    390     // read into memory.
    391     //
    392     BlockMap = FwVolHeader->BlockMap;
    393     CacheLocation = FvDevice->CachedFv;
    394     LbaIndex = 0;
    395     LbaOffset = 0;
    396     HeaderSize = FwVolHeader->HeaderLength;
    397     while ((BlockMap->NumBlocks != 0) || (BlockMap->Length != 0)) {
    398       Index = 0;
    399       Size  = BlockMap->Length;
    400       if (HeaderSize > 0) {
    401         //
    402         // Skip header size
    403         //
    404         for (; Index < BlockMap->NumBlocks && HeaderSize >= BlockMap->Length; Index ++) {
    405           HeaderSize -= BlockMap->Length;
    406           LbaIndex ++;
    407         }
    408 
    409         //
    410         // Check whether FvHeader is crossing the multi block range.
    411         //
    412         if (Index >= BlockMap->NumBlocks) {
    413           BlockMap++;
    414           continue;
    415         } else if (HeaderSize > 0) {
    416           LbaOffset = HeaderSize;
    417           Size = BlockMap->Length - HeaderSize;
    418           HeaderSize = 0;
    419         }
    420       }
    421 
    422       //
    423       // read the FV data
    424       //
    425       for (; Index < BlockMap->NumBlocks; Index ++) {
    426         Status = Fvb->Read (Fvb,
    427                         LbaIndex,
    428                         LbaOffset,
    429                         &Size,
    430                         CacheLocation
    431                         );
    432 
    433         //
    434         // Not check EFI_BAD_BUFFER_SIZE, for Size = BlockMap->Length
    435         //
    436         if (EFI_ERROR (Status)) {
    437           goto Done;
    438         }
    439 
    440         LbaIndex++;
    441         CacheLocation += Size;
    442 
    443         //
    444         // After we skip Fv Header always read from start of block
    445         //
    446         LbaOffset = 0;
    447         Size  = BlockMap->Length;
    448       }
    449 
    450       BlockMap++;
    451     }
    452   }
    453 
    454   //
    455   // Scan to check the free space & File list
    456   //
    457   if ((FvbAttributes & EFI_FVB2_ERASE_POLARITY) != 0) {
    458     FvDevice->ErasePolarity = 1;
    459   } else {
    460     FvDevice->ErasePolarity = 0;
    461   }
    462 
    463 
    464   //
    465   // go through the whole FV cache, check the consistence of the FV.
    466   // Make a linked list of all the Ffs file headers
    467   //
    468   Status = EFI_SUCCESS;
    469   InitializeListHead (&FvDevice->FfsFileListHeader);
    470 
    471   //
    472   // Build FFS list
    473   //
    474   if (FwVolHeader->ExtHeaderOffset != 0) {
    475     //
    476     // Searching for files starts on an 8 byte aligned boundary after the end of the Extended Header if it exists.
    477     //
    478     FwVolExtHeader = (EFI_FIRMWARE_VOLUME_EXT_HEADER *) (FvDevice->CachedFv + (FwVolHeader->ExtHeaderOffset - FwVolHeader->HeaderLength));
    479     FfsHeader = (EFI_FFS_FILE_HEADER *) ((UINT8 *) FwVolExtHeader + FwVolExtHeader->ExtHeaderSize);
    480     FfsHeader = (EFI_FFS_FILE_HEADER *) ALIGN_POINTER (FfsHeader, 8);
    481   } else {
    482     FfsHeader = (EFI_FFS_FILE_HEADER *) (FvDevice->CachedFv);
    483   }
    484   TopFvAddress = FvDevice->EndOfCachedFv;
    485   while (((UINTN) FfsHeader >= (UINTN) FvDevice->CachedFv) && ((UINTN) FfsHeader <= (UINTN) ((UINTN) TopFvAddress - sizeof (EFI_FFS_FILE_HEADER)))) {
    486 
    487     if (FileCached) {
    488       CoreFreePool (CacheFfsHeader);
    489       FileCached = FALSE;
    490     }
    491 
    492     TestLength = TopFvAddress - ((UINT8 *) FfsHeader);
    493     if (TestLength > sizeof (EFI_FFS_FILE_HEADER)) {
    494       TestLength = sizeof (EFI_FFS_FILE_HEADER);
    495     }
    496 
    497     if (IsBufferErased (FvDevice->ErasePolarity, FfsHeader, TestLength)) {
    498       //
    499       // We have found the free space so we are done!
    500       //
    501       goto Done;
    502     }
    503 
    504     if (!IsValidFfsHeader (FvDevice->ErasePolarity, FfsHeader, &FileState)) {
    505       if ((FileState == EFI_FILE_HEADER_INVALID) ||
    506           (FileState == EFI_FILE_HEADER_CONSTRUCTION)) {
    507         if (IS_FFS_FILE2 (FfsHeader)) {
    508           if (!FvDevice->IsFfs3Fv) {
    509             DEBUG ((EFI_D_ERROR, "Found a FFS3 formatted file: %g in a non-FFS3 formatted FV.\n", &FfsHeader->Name));
    510           }
    511           FfsHeader = (EFI_FFS_FILE_HEADER *) ((UINT8 *) FfsHeader + sizeof (EFI_FFS_FILE_HEADER2));
    512         } else {
    513           FfsHeader = (EFI_FFS_FILE_HEADER *) ((UINT8 *) FfsHeader + sizeof (EFI_FFS_FILE_HEADER));
    514         }
    515         continue;
    516       } else {
    517         //
    518         // File system is corrputed
    519         //
    520         Status = EFI_VOLUME_CORRUPTED;
    521         goto Done;
    522       }
    523     }
    524 
    525     CacheFfsHeader = FfsHeader;
    526     if ((CacheFfsHeader->Attributes & FFS_ATTRIB_CHECKSUM) == FFS_ATTRIB_CHECKSUM) {
    527       if (FvDevice->IsMemoryMapped) {
    528         //
    529         // Memory mapped FV has not been cached.
    530         // Here is to cache FFS file to memory buffer for following checksum calculating.
    531         // And then, the cached file buffer can be also used for FvReadFile.
    532         //
    533         WholeFileSize = IS_FFS_FILE2 (CacheFfsHeader) ? FFS_FILE2_SIZE (CacheFfsHeader): FFS_FILE_SIZE (CacheFfsHeader);
    534         CacheFfsHeader = AllocateCopyPool (WholeFileSize, CacheFfsHeader);
    535         if (CacheFfsHeader == NULL) {
    536           Status = EFI_OUT_OF_RESOURCES;
    537           goto Done;
    538         }
    539         FileCached = TRUE;
    540       }
    541     }
    542 
    543     if (!IsValidFfsFile (FvDevice->ErasePolarity, CacheFfsHeader)) {
    544       //
    545       // File system is corrupted
    546       //
    547       Status = EFI_VOLUME_CORRUPTED;
    548       goto Done;
    549     }
    550 
    551     if (IS_FFS_FILE2 (CacheFfsHeader)) {
    552       ASSERT (FFS_FILE2_SIZE (CacheFfsHeader) > 0x00FFFFFF);
    553       if (!FvDevice->IsFfs3Fv) {
    554         DEBUG ((EFI_D_ERROR, "Found a FFS3 formatted file: %g in a non-FFS3 formatted FV.\n", &CacheFfsHeader->Name));
    555         FfsHeader = (EFI_FFS_FILE_HEADER *) ((UINT8 *) FfsHeader + FFS_FILE2_SIZE (CacheFfsHeader));
    556         //
    557         // Adjust pointer to the next 8-byte aligned boundry.
    558         //
    559         FfsHeader = (EFI_FFS_FILE_HEADER *) (((UINTN) FfsHeader + 7) & ~0x07);
    560         continue;
    561       }
    562     }
    563 
    564     FileState = GetFileState (FvDevice->ErasePolarity, CacheFfsHeader);
    565 
    566     //
    567     // check for non-deleted file
    568     //
    569     if (FileState != EFI_FILE_DELETED) {
    570       //
    571       // Create a FFS list entry for each non-deleted file
    572       //
    573       FfsFileEntry = AllocateZeroPool (sizeof (FFS_FILE_LIST_ENTRY));
    574       if (FfsFileEntry == NULL) {
    575         Status = EFI_OUT_OF_RESOURCES;
    576         goto Done;
    577       }
    578 
    579       FfsFileEntry->FfsHeader = CacheFfsHeader;
    580       FfsFileEntry->FileCached = FileCached;
    581       FileCached = FALSE;
    582       InsertTailList (&FvDevice->FfsFileListHeader, &FfsFileEntry->Link);
    583     }
    584 
    585     if (IS_FFS_FILE2 (CacheFfsHeader)) {
    586       FfsHeader = (EFI_FFS_FILE_HEADER *) ((UINT8 *) FfsHeader + FFS_FILE2_SIZE (CacheFfsHeader));
    587     } else {
    588       FfsHeader = (EFI_FFS_FILE_HEADER *) ((UINT8 *) FfsHeader + FFS_FILE_SIZE (CacheFfsHeader));
    589     }
    590 
    591     //
    592     // Adjust pointer to the next 8-byte aligned boundry.
    593     //
    594     FfsHeader = (EFI_FFS_FILE_HEADER *)(((UINTN)FfsHeader + 7) & ~0x07);
    595 
    596   }
    597 
    598 Done:
    599   if (EFI_ERROR (Status)) {
    600     if (FileCached) {
    601       CoreFreePool (CacheFfsHeader);
    602       FileCached = FALSE;
    603     }
    604     FreeFvDeviceResource (FvDevice);
    605   }
    606 
    607   return Status;
    608 }
    609 
    610 
    611 
    612 /**
    613   This notification function is invoked when an instance of the
    614   EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL is produced.  It layers an instance of the
    615   EFI_FIRMWARE_VOLUME2_PROTOCOL on the same handle.  This is the function where
    616   the actual initialization of the EFI_FIRMWARE_VOLUME2_PROTOCOL is done.
    617 
    618   @param  Event                 The event that occured
    619   @param  Context               For EFI compatiblity.  Not used.
    620 
    621 **/
    622 VOID
    623 EFIAPI
    624 NotifyFwVolBlock (
    625   IN  EFI_EVENT Event,
    626   IN  VOID      *Context
    627   )
    628 {
    629   EFI_HANDLE                            Handle;
    630   EFI_STATUS                            Status;
    631   UINTN                                 BufferSize;
    632   EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL    *Fvb;
    633   EFI_FIRMWARE_VOLUME2_PROTOCOL         *Fv;
    634   FV_DEVICE                             *FvDevice;
    635   EFI_FIRMWARE_VOLUME_HEADER            *FwVolHeader;
    636   //
    637   // Examine all new handles
    638   //
    639   for (;;) {
    640     //
    641     // Get the next handle
    642     //
    643     BufferSize = sizeof (Handle);
    644     Status = CoreLocateHandle (
    645               ByRegisterNotify,
    646               NULL,
    647               gEfiFwVolBlockNotifyReg,
    648               &BufferSize,
    649               &Handle
    650               );
    651 
    652     //
    653     // If not found, we're done
    654     //
    655     if (EFI_NOT_FOUND == Status) {
    656       break;
    657     }
    658 
    659     if (EFI_ERROR (Status)) {
    660       continue;
    661     }
    662 
    663     //
    664     // Get the FirmwareVolumeBlock protocol on that handle
    665     //
    666     Status = CoreHandleProtocol (Handle, &gEfiFirmwareVolumeBlockProtocolGuid, (VOID **)&Fvb);
    667     ASSERT_EFI_ERROR (Status);
    668     ASSERT (Fvb != NULL);
    669 
    670     //
    671     // Make sure the Fv Header is O.K.
    672     //
    673     Status = GetFwVolHeader (Fvb, &FwVolHeader);
    674     if (EFI_ERROR (Status)) {
    675       continue;
    676     }
    677     ASSERT (FwVolHeader != NULL);
    678 
    679     if (!VerifyFvHeaderChecksum (FwVolHeader)) {
    680       CoreFreePool (FwVolHeader);
    681       continue;
    682     }
    683 
    684     //
    685     // Check if there is an FV protocol already installed in that handle
    686     //
    687     Status = CoreHandleProtocol (Handle, &gEfiFirmwareVolume2ProtocolGuid, (VOID **)&Fv);
    688     if (!EFI_ERROR (Status)) {
    689       //
    690       // Update Fv to use a new Fvb
    691       //
    692       FvDevice = BASE_CR (Fv, FV_DEVICE, Fv);
    693       if (FvDevice->Signature == FV2_DEVICE_SIGNATURE) {
    694         //
    695         // Only write into our device structure if it's our device structure
    696         //
    697         FvDevice->Fvb = Fvb;
    698       }
    699 
    700     } else {
    701       //
    702       // No FwVol protocol on the handle so create a new one
    703       //
    704       FvDevice = AllocateCopyPool (sizeof (FV_DEVICE), &mFvDevice);
    705       if (FvDevice == NULL) {
    706         return;
    707       }
    708 
    709       FvDevice->Fvb             = Fvb;
    710       FvDevice->Handle          = Handle;
    711       FvDevice->FwVolHeader     = FwVolHeader;
    712       FvDevice->IsFfs3Fv        = CompareGuid (&FwVolHeader->FileSystemGuid, &gEfiFirmwareFileSystem3Guid);
    713       FvDevice->Fv.ParentHandle = Fvb->ParentHandle;
    714 
    715       if (Fvb->ParentHandle != NULL) {
    716         //
    717         // Inherit the authentication status from FVB.
    718         //
    719         FvDevice->AuthenticationStatus = GetFvbAuthenticationStatus (Fvb);
    720       }
    721 
    722       if (!EFI_ERROR (FvCheck (FvDevice))) {
    723         //
    724         // Install an New FV protocol on the existing handle
    725         //
    726         Status = CoreInstallProtocolInterface (
    727                     &Handle,
    728                     &gEfiFirmwareVolume2ProtocolGuid,
    729                     EFI_NATIVE_INTERFACE,
    730                     &FvDevice->Fv
    731                     );
    732         ASSERT_EFI_ERROR (Status);
    733       } else {
    734         //
    735         // Free FvDevice Buffer for the corrupt FV image.
    736         //
    737         CoreFreePool (FvDevice);
    738       }
    739     }
    740   }
    741 
    742   return;
    743 }
    744 
    745 
    746 
    747 /**
    748   This routine is the driver initialization entry point.  It registers
    749   a notification function.  This notification function are responsible
    750   for building the FV stack dynamically.
    751 
    752   @param  ImageHandle           The image handle.
    753   @param  SystemTable           The system table.
    754 
    755   @retval EFI_SUCCESS           Function successfully returned.
    756 
    757 **/
    758 EFI_STATUS
    759 EFIAPI
    760 FwVolDriverInit (
    761   IN EFI_HANDLE                   ImageHandle,
    762   IN EFI_SYSTEM_TABLE             *SystemTable
    763   )
    764 {
    765   gEfiFwVolBlockEvent = EfiCreateProtocolNotifyEvent (
    766                           &gEfiFirmwareVolumeBlockProtocolGuid,
    767                           TPL_CALLBACK,
    768                           NotifyFwVolBlock,
    769                           NULL,
    770                           &gEfiFwVolBlockNotifyReg
    771                           );
    772   return EFI_SUCCESS;
    773 }
    774 
    775 
    776