Home | History | Annotate | Download | only in FwVolBlock
      1 /** @file
      2   Implementations for Firmware Volume Block protocol.
      3 
      4   It consumes FV HOBs and creates read-only Firmare Volume Block protocol
      5   instances for each of them.
      6 
      7 Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
      8 This program and the accompanying materials
      9 are licensed and made available under the terms and conditions of the BSD License
     10 which accompanies this distribution.  The full text of the license may be found at
     11 http://opensource.org/licenses/bsd-license.php
     12 
     13 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     14 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     15 
     16 **/
     17 
     18 #include "DxeMain.h"
     19 #include "FwVolBlock.h"
     20 
     21 FV_MEMMAP_DEVICE_PATH mFvMemmapDevicePathTemplate = {
     22   {
     23     {
     24       HARDWARE_DEVICE_PATH,
     25       HW_MEMMAP_DP,
     26       {
     27         (UINT8)(sizeof (MEMMAP_DEVICE_PATH)),
     28         (UINT8)(sizeof (MEMMAP_DEVICE_PATH) >> 8)
     29       }
     30     },
     31     EfiMemoryMappedIO,
     32     (EFI_PHYSICAL_ADDRESS) 0,
     33     (EFI_PHYSICAL_ADDRESS) 0,
     34   },
     35   {
     36     END_DEVICE_PATH_TYPE,
     37     END_ENTIRE_DEVICE_PATH_SUBTYPE,
     38     {
     39       END_DEVICE_PATH_LENGTH,
     40       0
     41     }
     42   }
     43 };
     44 
     45 FV_PIWG_DEVICE_PATH mFvPIWGDevicePathTemplate = {
     46   {
     47     {
     48       MEDIA_DEVICE_PATH,
     49       MEDIA_PIWG_FW_VOL_DP,
     50       {
     51         (UINT8)(sizeof (MEDIA_FW_VOL_DEVICE_PATH)),
     52         (UINT8)(sizeof (MEDIA_FW_VOL_DEVICE_PATH) >> 8)
     53       }
     54     },
     55     { 0 }
     56   },
     57   {
     58     END_DEVICE_PATH_TYPE,
     59     END_ENTIRE_DEVICE_PATH_SUBTYPE,
     60     {
     61       END_DEVICE_PATH_LENGTH,
     62       0
     63     }
     64   }
     65 };
     66 
     67 EFI_FW_VOL_BLOCK_DEVICE  mFwVolBlock = {
     68   FVB_DEVICE_SIGNATURE,
     69   NULL,
     70   NULL,
     71   {
     72     FwVolBlockGetAttributes,
     73     (EFI_FVB_SET_ATTRIBUTES)FwVolBlockSetAttributes,
     74     FwVolBlockGetPhysicalAddress,
     75     FwVolBlockGetBlockSize,
     76     FwVolBlockReadBlock,
     77     (EFI_FVB_WRITE)FwVolBlockWriteBlock,
     78     (EFI_FVB_ERASE_BLOCKS)FwVolBlockEraseBlock,
     79     NULL
     80   },
     81   0,
     82   NULL,
     83   0,
     84   0,
     85   0
     86 };
     87 
     88 
     89 
     90 /**
     91   Retrieves Volume attributes.  No polarity translations are done.
     92 
     93   @param  This                   Calling context
     94   @param  Attributes             output buffer which contains attributes
     95 
     96   @retval EFI_SUCCESS            The firmware volume attributes were returned.
     97 
     98 **/
     99 EFI_STATUS
    100 EFIAPI
    101 FwVolBlockGetAttributes (
    102   IN CONST  EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL  *This,
    103   OUT       EFI_FVB_ATTRIBUTES_2                *Attributes
    104   )
    105 {
    106   EFI_FW_VOL_BLOCK_DEVICE               *FvbDevice;
    107 
    108   FvbDevice = FVB_DEVICE_FROM_THIS (This);
    109 
    110   //
    111   // Since we are read only, it's safe to get attributes data from our in-memory copy.
    112   //
    113   *Attributes = FvbDevice->FvbAttributes & ~EFI_FVB2_WRITE_STATUS;
    114 
    115   return EFI_SUCCESS;
    116 }
    117 
    118 
    119 
    120 /**
    121   Modifies the current settings of the firmware volume according to the input parameter.
    122 
    123   @param  This                   Calling context
    124   @param  Attributes             input buffer which contains attributes
    125 
    126   @retval EFI_SUCCESS            The firmware volume attributes were returned.
    127   @retval EFI_INVALID_PARAMETER  The attributes requested are in conflict with
    128                                  the capabilities as declared in the firmware
    129                                  volume header.
    130   @retval EFI_UNSUPPORTED        Not supported.
    131 
    132 **/
    133 EFI_STATUS
    134 EFIAPI
    135 FwVolBlockSetAttributes (
    136   IN CONST  EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL  *This,
    137   IN CONST  EFI_FVB_ATTRIBUTES_2                *Attributes
    138   )
    139 {
    140   return EFI_UNSUPPORTED;
    141 }
    142 
    143 
    144 
    145 /**
    146   The EraseBlock() function erases one or more blocks as denoted by the
    147   variable argument list. The entire parameter list of blocks must be verified
    148   prior to erasing any blocks.  If a block is requested that does not exist
    149   within the associated firmware volume (it has a larger index than the last
    150   block of the firmware volume), the EraseBlock() function must return
    151   EFI_INVALID_PARAMETER without modifying the contents of the firmware volume.
    152 
    153   @param  This                   Calling context
    154   @param  ...                    Starting LBA followed by Number of Lba to erase.
    155                                  a -1 to terminate the list.
    156 
    157   @retval EFI_SUCCESS            The erase request was successfully completed.
    158   @retval EFI_ACCESS_DENIED      The firmware volume is in the WriteDisabled
    159                                  state.
    160   @retval EFI_DEVICE_ERROR       The block device is not functioning correctly
    161                                  and could not be written. The firmware device
    162                                  may have been partially erased.
    163   @retval EFI_INVALID_PARAMETER  One or more of the LBAs listed in the variable
    164                                  argument list do
    165   @retval EFI_UNSUPPORTED        Not supported.
    166 
    167 **/
    168 EFI_STATUS
    169 EFIAPI
    170 FwVolBlockEraseBlock (
    171   IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL    *This,
    172   ...
    173   )
    174 {
    175   return EFI_UNSUPPORTED;
    176 }
    177 
    178 
    179 
    180 /**
    181   Read the specified number of bytes from the block to the input buffer.
    182 
    183   @param  This                   Indicates the calling context.
    184   @param  Lba                    The starting logical block index to read.
    185   @param  Offset                 Offset into the block at which to begin reading.
    186   @param  NumBytes               Pointer to a UINT32. At entry, *NumBytes
    187                                  contains the total size of the buffer. At exit,
    188                                  *NumBytes contains the total number of bytes
    189                                  actually read.
    190   @param  Buffer                 Pinter to a caller-allocated buffer that
    191                                  contains the destine for the read.
    192 
    193   @retval EFI_SUCCESS            The firmware volume was read successfully.
    194   @retval EFI_BAD_BUFFER_SIZE    The read was attempted across an LBA boundary.
    195   @retval EFI_ACCESS_DENIED      Access denied.
    196   @retval EFI_DEVICE_ERROR       The block device is malfunctioning and could not
    197                                  be read.
    198 
    199 **/
    200 EFI_STATUS
    201 EFIAPI
    202 FwVolBlockReadBlock (
    203   IN CONST  EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL   *This,
    204   IN CONST  EFI_LBA                              Lba,
    205   IN CONST  UINTN                                Offset,
    206   IN OUT    UINTN                                *NumBytes,
    207   IN OUT    UINT8                                *Buffer
    208   )
    209 {
    210   EFI_FW_VOL_BLOCK_DEVICE               *FvbDevice;
    211   EFI_FIRMWARE_VOLUME_HEADER            *FwVolHeader;
    212   UINT8                                 *LbaOffset;
    213   UINTN                                 LbaStart;
    214   UINTN                                 NumOfBytesRead;
    215   UINTN                                 LbaIndex;
    216 
    217   FvbDevice = FVB_DEVICE_FROM_THIS (This);
    218 
    219   //
    220   // Check if This FW can be read
    221   //
    222   if ((FvbDevice->FvbAttributes & EFI_FVB2_READ_STATUS) == 0) {
    223     return EFI_ACCESS_DENIED;
    224   }
    225 
    226   LbaIndex = (UINTN) Lba;
    227   if (LbaIndex >= FvbDevice->NumBlocks) {
    228     //
    229     // Invalid Lba, read nothing.
    230     //
    231     *NumBytes = 0;
    232     return EFI_BAD_BUFFER_SIZE;
    233   }
    234 
    235   if (Offset > FvbDevice->LbaCache[LbaIndex].Length) {
    236     //
    237     // all exceed boundry, read nothing.
    238     //
    239     *NumBytes = 0;
    240     return EFI_BAD_BUFFER_SIZE;
    241   }
    242 
    243   NumOfBytesRead = *NumBytes;
    244   if (Offset + NumOfBytesRead > FvbDevice->LbaCache[LbaIndex].Length) {
    245     //
    246     // partial exceed boundry, read data from current postion to end.
    247     //
    248     NumOfBytesRead = FvbDevice->LbaCache[LbaIndex].Length - Offset;
    249   }
    250 
    251   LbaStart = FvbDevice->LbaCache[LbaIndex].Base;
    252   FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *)((UINTN) FvbDevice->BaseAddress);
    253   LbaOffset = (UINT8 *) FwVolHeader + LbaStart + Offset;
    254 
    255   //
    256   // Perform read operation
    257   //
    258   CopyMem (Buffer, LbaOffset, NumOfBytesRead);
    259 
    260   if (NumOfBytesRead == *NumBytes) {
    261     return EFI_SUCCESS;
    262   }
    263 
    264   *NumBytes = NumOfBytesRead;
    265   return EFI_BAD_BUFFER_SIZE;
    266 }
    267 
    268 
    269 
    270 /**
    271   Writes the specified number of bytes from the input buffer to the block.
    272 
    273   @param  This                   Indicates the calling context.
    274   @param  Lba                    The starting logical block index to write to.
    275   @param  Offset                 Offset into the block at which to begin writing.
    276   @param  NumBytes               Pointer to a UINT32. At entry, *NumBytes
    277                                  contains the total size of the buffer. At exit,
    278                                  *NumBytes contains the total number of bytes
    279                                  actually written.
    280   @param  Buffer                 Pinter to a caller-allocated buffer that
    281                                  contains the source for the write.
    282 
    283   @retval EFI_SUCCESS            The firmware volume was written successfully.
    284   @retval EFI_BAD_BUFFER_SIZE    The write was attempted across an LBA boundary.
    285                                  On output, NumBytes contains the total number of
    286                                  bytes actually written.
    287   @retval EFI_ACCESS_DENIED      The firmware volume is in the WriteDisabled
    288                                  state.
    289   @retval EFI_DEVICE_ERROR       The block device is malfunctioning and could not
    290                                  be written.
    291   @retval EFI_UNSUPPORTED        Not supported.
    292 
    293 **/
    294 EFI_STATUS
    295 EFIAPI
    296 FwVolBlockWriteBlock (
    297   IN     EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL   *This,
    298   IN     EFI_LBA                              Lba,
    299   IN     UINTN                                Offset,
    300   IN OUT UINTN                                *NumBytes,
    301   IN     UINT8                                *Buffer
    302   )
    303 {
    304   return EFI_UNSUPPORTED;
    305 }
    306 
    307 
    308 
    309 /**
    310   Get Fvb's base address.
    311 
    312   @param  This                   Indicates the calling context.
    313   @param  Address                Fvb device base address.
    314 
    315   @retval EFI_SUCCESS            Successfully got Fvb's base address.
    316   @retval EFI_UNSUPPORTED        Not supported.
    317 
    318 **/
    319 EFI_STATUS
    320 EFIAPI
    321 FwVolBlockGetPhysicalAddress (
    322   IN CONST  EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL  *This,
    323   OUT       EFI_PHYSICAL_ADDRESS                *Address
    324   )
    325 {
    326   EFI_FW_VOL_BLOCK_DEVICE               *FvbDevice;
    327 
    328   FvbDevice = FVB_DEVICE_FROM_THIS (This);
    329 
    330   if ((FvbDevice->FvbAttributes & EFI_FVB2_MEMORY_MAPPED) != 0) {
    331     *Address = FvbDevice->BaseAddress;
    332     return EFI_SUCCESS;
    333   }
    334 
    335   return EFI_UNSUPPORTED;
    336 }
    337 
    338 
    339 
    340 /**
    341   Retrieves the size in bytes of a specific block within a firmware volume.
    342 
    343   @param  This                   Indicates the calling context.
    344   @param  Lba                    Indicates the block for which to return the
    345                                  size.
    346   @param  BlockSize              Pointer to a caller-allocated UINTN in which the
    347                                  size of the block is returned.
    348   @param  NumberOfBlocks         Pointer to a caller-allocated UINTN in which the
    349                                  number of consecutive blocks starting with Lba
    350                                  is returned. All blocks in this range have a
    351                                  size of BlockSize.
    352 
    353   @retval EFI_SUCCESS            The firmware volume base address is returned.
    354   @retval EFI_INVALID_PARAMETER  The requested LBA is out of range.
    355 
    356 **/
    357 EFI_STATUS
    358 EFIAPI
    359 FwVolBlockGetBlockSize (
    360   IN CONST  EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL  *This,
    361   IN CONST  EFI_LBA                             Lba,
    362   IN OUT    UINTN                               *BlockSize,
    363   IN OUT    UINTN                               *NumberOfBlocks
    364   )
    365 {
    366   UINTN                                 TotalBlocks;
    367   EFI_FW_VOL_BLOCK_DEVICE               *FvbDevice;
    368   EFI_FV_BLOCK_MAP_ENTRY                *PtrBlockMapEntry;
    369   EFI_FIRMWARE_VOLUME_HEADER            *FwVolHeader;
    370 
    371   FvbDevice = FVB_DEVICE_FROM_THIS (This);
    372 
    373   //
    374   // Do parameter checking
    375   //
    376   if (Lba >= FvbDevice->NumBlocks) {
    377     return EFI_INVALID_PARAMETER;
    378   }
    379 
    380   FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *)((UINTN)FvbDevice->BaseAddress);
    381 
    382   PtrBlockMapEntry = FwVolHeader->BlockMap;
    383 
    384   //
    385   // Search the block map for the given block
    386   //
    387   TotalBlocks = 0;
    388   while ((PtrBlockMapEntry->NumBlocks != 0) || (PtrBlockMapEntry->Length !=0 )) {
    389     TotalBlocks += PtrBlockMapEntry->NumBlocks;
    390     if (Lba < TotalBlocks) {
    391       //
    392       // We find the range
    393       //
    394       break;
    395     }
    396 
    397     PtrBlockMapEntry++;
    398   }
    399 
    400   *BlockSize = PtrBlockMapEntry->Length;
    401   *NumberOfBlocks = TotalBlocks - (UINTN)Lba;
    402 
    403   return EFI_SUCCESS;
    404 }
    405 
    406 /**
    407 
    408   Get FVB authentication status
    409 
    410   @param FvbProtocol    FVB protocol.
    411 
    412   @return Authentication status.
    413 
    414 **/
    415 UINT32
    416 GetFvbAuthenticationStatus (
    417   IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL     *FvbProtocol
    418   )
    419 {
    420   EFI_FW_VOL_BLOCK_DEVICE   *FvbDevice;
    421   UINT32                    AuthenticationStatus;
    422 
    423   AuthenticationStatus = 0;
    424   FvbDevice = BASE_CR (FvbProtocol, EFI_FW_VOL_BLOCK_DEVICE, FwVolBlockInstance);
    425   if (FvbDevice->Signature == FVB_DEVICE_SIGNATURE) {
    426     AuthenticationStatus = FvbDevice->AuthenticationStatus;
    427   }
    428 
    429   return AuthenticationStatus;
    430 }
    431 
    432 /**
    433   This routine produces a firmware volume block protocol on a given
    434   buffer.
    435 
    436   @param  BaseAddress            base address of the firmware volume image
    437   @param  Length                 length of the firmware volume image
    438   @param  ParentHandle           handle of parent firmware volume, if this image
    439                                  came from an FV image file and section in another firmware
    440                                  volume (ala capsules)
    441   @param  AuthenticationStatus   Authentication status inherited, if this image
    442                                  came from an FV image file and section in another firmware volume.
    443   @param  FvProtocol             Firmware volume block protocol produced.
    444 
    445   @retval EFI_VOLUME_CORRUPTED   Volume corrupted.
    446   @retval EFI_OUT_OF_RESOURCES   No enough buffer to be allocated.
    447   @retval EFI_SUCCESS            Successfully produced a FVB protocol on given
    448                                  buffer.
    449 
    450 **/
    451 EFI_STATUS
    452 ProduceFVBProtocolOnBuffer (
    453   IN EFI_PHYSICAL_ADDRESS   BaseAddress,
    454   IN UINT64                 Length,
    455   IN EFI_HANDLE             ParentHandle,
    456   IN UINT32                 AuthenticationStatus,
    457   OUT EFI_HANDLE            *FvProtocol  OPTIONAL
    458   )
    459 {
    460   EFI_STATUS                    Status;
    461   EFI_FW_VOL_BLOCK_DEVICE       *FvbDev;
    462   EFI_FIRMWARE_VOLUME_HEADER    *FwVolHeader;
    463   UINTN                         BlockIndex;
    464   UINTN                         BlockIndex2;
    465   UINTN                         LinearOffset;
    466   UINT32                        FvAlignment;
    467   EFI_FV_BLOCK_MAP_ENTRY        *PtrBlockMapEntry;
    468 
    469   FvAlignment = 0;
    470   FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *)(UINTN) BaseAddress;
    471   //
    472   // Validate FV Header, if not as expected, return
    473   //
    474   if (FwVolHeader->Signature != EFI_FVH_SIGNATURE) {
    475     return EFI_VOLUME_CORRUPTED;
    476   }
    477 
    478   //
    479   // If EFI_FVB2_WEAK_ALIGNMENT is set in the volume header then the first byte of the volume
    480   // can be aligned on any power-of-two boundary. A weakly aligned volume can not be moved from
    481   // its initial linked location and maintain its alignment.
    482   //
    483   if ((FwVolHeader->Attributes & EFI_FVB2_WEAK_ALIGNMENT) != EFI_FVB2_WEAK_ALIGNMENT) {
    484     //
    485     // Get FvHeader alignment
    486     //
    487     FvAlignment = 1 << ((FwVolHeader->Attributes & EFI_FVB2_ALIGNMENT) >> 16);
    488     //
    489     // FvAlignment must be greater than or equal to 8 bytes of the minimum FFS alignment value.
    490     //
    491     if (FvAlignment < 8) {
    492       FvAlignment = 8;
    493     }
    494     if ((UINTN)BaseAddress % FvAlignment != 0) {
    495       //
    496       // FvImage buffer is not at its required alignment.
    497       //
    498       return EFI_VOLUME_CORRUPTED;
    499     }
    500   }
    501 
    502   //
    503   // Allocate EFI_FW_VOL_BLOCK_DEVICE
    504   //
    505   FvbDev = AllocateCopyPool (sizeof (EFI_FW_VOL_BLOCK_DEVICE), &mFwVolBlock);
    506   if (FvbDev == NULL) {
    507     return EFI_OUT_OF_RESOURCES;
    508   }
    509 
    510   FvbDev->BaseAddress   = BaseAddress;
    511   FvbDev->FvbAttributes = FwVolHeader->Attributes;
    512   FvbDev->FwVolBlockInstance.ParentHandle = ParentHandle;
    513   if (ParentHandle != NULL) {
    514     FvbDev->AuthenticationStatus = AuthenticationStatus;
    515   }
    516 
    517   //
    518   // Init the block caching fields of the device
    519   // First, count the number of blocks
    520   //
    521   FvbDev->NumBlocks = 0;
    522   for (PtrBlockMapEntry = FwVolHeader->BlockMap;
    523        PtrBlockMapEntry->NumBlocks != 0;
    524        PtrBlockMapEntry++) {
    525     FvbDev->NumBlocks += PtrBlockMapEntry->NumBlocks;
    526   }
    527 
    528   //
    529   // Second, allocate the cache
    530   //
    531   if (FvbDev->NumBlocks >= (MAX_ADDRESS / sizeof (LBA_CACHE))) {
    532     CoreFreePool (FvbDev);
    533     return EFI_OUT_OF_RESOURCES;
    534   }
    535   FvbDev->LbaCache = AllocatePool (FvbDev->NumBlocks * sizeof (LBA_CACHE));
    536   if (FvbDev->LbaCache == NULL) {
    537     CoreFreePool (FvbDev);
    538     return EFI_OUT_OF_RESOURCES;
    539   }
    540 
    541   //
    542   // Last, fill in the cache with the linear address of the blocks
    543   //
    544   BlockIndex = 0;
    545   LinearOffset = 0;
    546   for (PtrBlockMapEntry = FwVolHeader->BlockMap;
    547        PtrBlockMapEntry->NumBlocks != 0; PtrBlockMapEntry++) {
    548     for (BlockIndex2 = 0; BlockIndex2 < PtrBlockMapEntry->NumBlocks; BlockIndex2++) {
    549       FvbDev->LbaCache[BlockIndex].Base = LinearOffset;
    550       FvbDev->LbaCache[BlockIndex].Length = PtrBlockMapEntry->Length;
    551       LinearOffset += PtrBlockMapEntry->Length;
    552       BlockIndex++;
    553     }
    554   }
    555 
    556   //
    557   // Judget whether FV name guid is produced in Fv extension header
    558   //
    559   if (FwVolHeader->ExtHeaderOffset == 0) {
    560     //
    561     // FV does not contains extension header, then produce MEMMAP_DEVICE_PATH
    562     //
    563     FvbDev->DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) AllocateCopyPool (sizeof (FV_MEMMAP_DEVICE_PATH), &mFvMemmapDevicePathTemplate);
    564     if (FvbDev->DevicePath == NULL) {
    565       FreePool (FvbDev);
    566       return EFI_OUT_OF_RESOURCES;
    567     }
    568     ((FV_MEMMAP_DEVICE_PATH *) FvbDev->DevicePath)->MemMapDevPath.StartingAddress = BaseAddress;
    569     ((FV_MEMMAP_DEVICE_PATH *) FvbDev->DevicePath)->MemMapDevPath.EndingAddress   = BaseAddress + FwVolHeader->FvLength - 1;
    570   } else {
    571     //
    572     // FV contains extension header, then produce MEDIA_FW_VOL_DEVICE_PATH
    573     //
    574     FvbDev->DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) AllocateCopyPool (sizeof (FV_PIWG_DEVICE_PATH), &mFvPIWGDevicePathTemplate);
    575     if (FvbDev->DevicePath == NULL) {
    576       FreePool (FvbDev);
    577       return EFI_OUT_OF_RESOURCES;
    578     }
    579     CopyGuid (
    580       &((FV_PIWG_DEVICE_PATH *)FvbDev->DevicePath)->FvDevPath.FvName,
    581       (GUID *)(UINTN)(BaseAddress + FwVolHeader->ExtHeaderOffset)
    582       );
    583   }
    584 
    585   //
    586   //
    587   // Attach FvVolBlock Protocol to new handle
    588   //
    589   Status = CoreInstallMultipleProtocolInterfaces (
    590              &FvbDev->Handle,
    591              &gEfiFirmwareVolumeBlockProtocolGuid,     &FvbDev->FwVolBlockInstance,
    592              &gEfiDevicePathProtocolGuid,              FvbDev->DevicePath,
    593              NULL
    594              );
    595 
    596   //
    597   // If they want the handle back, set it.
    598   //
    599   if (FvProtocol != NULL) {
    600     *FvProtocol = FvbDev->Handle;
    601   }
    602 
    603   return Status;
    604 }
    605 
    606 
    607 
    608 /**
    609   This routine consumes FV hobs and produces instances of FW_VOL_BLOCK_PROTOCOL as appropriate.
    610 
    611   @param  ImageHandle            The image handle.
    612   @param  SystemTable            The system table.
    613 
    614   @retval EFI_SUCCESS            Successfully initialized firmware volume block
    615                                  driver.
    616 
    617 **/
    618 EFI_STATUS
    619 EFIAPI
    620 FwVolBlockDriverInit (
    621   IN EFI_HANDLE                 ImageHandle,
    622   IN EFI_SYSTEM_TABLE           *SystemTable
    623   )
    624 {
    625   EFI_PEI_HOB_POINTERS          FvHob;
    626 
    627   //
    628   // Core Needs Firmware Volumes to function
    629   //
    630   FvHob.Raw = GetHobList ();
    631   while ((FvHob.Raw = GetNextHob (EFI_HOB_TYPE_FV, FvHob.Raw)) != NULL) {
    632     //
    633     // Produce an FVB protocol for it
    634     //
    635     ProduceFVBProtocolOnBuffer (FvHob.FirmwareVolume->BaseAddress, FvHob.FirmwareVolume->Length, NULL, 0, NULL);
    636     FvHob.Raw = GET_NEXT_HOB (FvHob);
    637   }
    638 
    639   return EFI_SUCCESS;
    640 }
    641 
    642 
    643 
    644 /**
    645   This DXE service routine is used to process a firmware volume. In
    646   particular, it can be called by BDS to process a single firmware
    647   volume found in a capsule.
    648 
    649   Caution: The caller need validate the input firmware volume to follow
    650   PI specification.
    651   DxeCore will trust the input data and process firmware volume directly.
    652 
    653   @param  FvHeader               pointer to a firmware volume header
    654   @param  Size                   the size of the buffer pointed to by FvHeader
    655   @param  FVProtocolHandle       the handle on which a firmware volume protocol
    656                                  was produced for the firmware volume passed in.
    657 
    658   @retval EFI_OUT_OF_RESOURCES   if an FVB could not be produced due to lack of
    659                                  system resources
    660   @retval EFI_VOLUME_CORRUPTED   if the volume was corrupted
    661   @retval EFI_SUCCESS            a firmware volume protocol was produced for the
    662                                  firmware volume
    663 
    664 **/
    665 EFI_STATUS
    666 EFIAPI
    667 CoreProcessFirmwareVolume (
    668   IN VOID                             *FvHeader,
    669   IN UINTN                            Size,
    670   OUT EFI_HANDLE                      *FVProtocolHandle
    671   )
    672 {
    673   VOID        *Ptr;
    674   EFI_STATUS  Status;
    675 
    676   *FVProtocolHandle = NULL;
    677   Status = ProduceFVBProtocolOnBuffer (
    678             (EFI_PHYSICAL_ADDRESS) (UINTN) FvHeader,
    679             (UINT64)Size,
    680             NULL,
    681             0,
    682             FVProtocolHandle
    683             );
    684   //
    685   // Since in our implementation we use register-protocol-notify to put a
    686   // FV protocol on the FVB protocol handle, we can't directly verify that
    687   // the FV protocol was produced. Therefore here we will check the handle
    688   // and make sure an FV protocol is on it. This indicates that all went
    689   // well. Otherwise we have to assume that the volume was corrupted
    690   // somehow.
    691   //
    692   if (!EFI_ERROR(Status)) {
    693     ASSERT (*FVProtocolHandle != NULL);
    694     Ptr = NULL;
    695     Status = CoreHandleProtocol (*FVProtocolHandle, &gEfiFirmwareVolume2ProtocolGuid, (VOID **) &Ptr);
    696     if (EFI_ERROR(Status) || (Ptr == NULL)) {
    697       return EFI_VOLUME_CORRUPTED;
    698     }
    699     return EFI_SUCCESS;
    700   }
    701   return Status;
    702 }
    703 
    704 
    705 
    706