Home | History | Annotate | Download | only in FvbRuntimeDxe
      1 /** @file
      2   Firmware Volume Block Driver for Lakeport Platform.
      3 
      4   Firmware volume block driver for FWH or SPI device.
      5   It depends on which Flash Device Library to be linked with this driver.
      6 
      7 Copyright (c) 2006  - 2014, Intel Corporation. All rights reserved.<BR>
      8 
      9   This program and the accompanying materials are licensed and made available under
     11   the terms and conditions of the BSD License that accompanies this distribution.
     13   The full text of the license may be found at
     15   http://opensource.org/licenses/bsd-license.php.
     17 
     19   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     21   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     23 
     25 
     27 **/
     28 
     29 #include "FvbService.h"
     30 
     31 //
     32 // Global variable for this FVB driver  which contains
     33 // the private data of all firmware volume block instances.
     34 //
     35 FWB_GLOBAL   mFvbModuleGlobal;
     36 
     37 //
     38 // This platform driver knows there are 3 FVs on
     39 // FD, which are FvRecovery, FvMain and FvNvStorage.
     40 //
     41 UINT32 mPlatformFvBaseAddress[] = {
     42   FixedPcdGet32(PcdFlashNvStorageVariableBase),
     43 };
     44 
     45 FV_MEMMAP_DEVICE_PATH mFvMemmapDevicePathTemplate = {
     46   {
     47     {
     48       HARDWARE_DEVICE_PATH,
     49       HW_MEMMAP_DP,
     50       {
     51         (UINT8)(sizeof (MEMMAP_DEVICE_PATH)),
     52         (UINT8)(sizeof (MEMMAP_DEVICE_PATH) >> 8)
     53       }
     54     },
     55     EfiMemoryMappedIO,
     56     (EFI_PHYSICAL_ADDRESS) 0,
     57     (EFI_PHYSICAL_ADDRESS) 0,
     58   },
     59   {
     60     END_DEVICE_PATH_TYPE,
     61     END_ENTIRE_DEVICE_PATH_SUBTYPE,
     62     {
     63       END_DEVICE_PATH_LENGTH,
     64       0
     65     }
     66   }
     67 };
     68 
     69 FV_PIWG_DEVICE_PATH mFvPIWGDevicePathTemplate = {
     70   {
     71     {
     72       MEDIA_DEVICE_PATH,
     73       MEDIA_PIWG_FW_VOL_DP,
     74       {
     75         (UINT8)(sizeof (MEDIA_FW_VOL_DEVICE_PATH)),
     76         (UINT8)(sizeof (MEDIA_FW_VOL_DEVICE_PATH) >> 8)
     77       }
     78     },
     79     { 0 }
     80   },
     81   {
     82     END_DEVICE_PATH_TYPE,
     83     END_ENTIRE_DEVICE_PATH_SUBTYPE,
     84     {
     85       END_DEVICE_PATH_LENGTH,
     86       0
     87     }
     88   }
     89 };
     90 
     91 //
     92 // Template structure used when installing FVB protocol.
     93 //
     94 EFI_FW_VOL_BLOCK_DEVICE mFvbDeviceTemplate = {
     95   FVB_DEVICE_SIGNATURE,
     96   NULL,
     97   0, // Instance
     98   {
     99     FvbProtocolGetAttributes,
    100     FvbProtocolSetAttributes,
    101     FvbProtocolGetPhysicalAddress,
    102     FvbProtocolGetBlockSize,
    103     FvbProtocolRead,
    104     FvbProtocolWrite,
    105     FvbProtocolEraseBlocks,
    106     NULL
    107   } // FwVolBlockInstance
    108 };
    109 
    110 
    111 /**
    112   Get the pointer to EFI_FW_VOL_INSTANCE from the buffer pointed
    113   by mFvbModuleGlobal.FvInstance based on a index.
    114   Each EFI_FW_VOL_INSTANCE is  with variable length as
    115   we have a block map at the end of the EFI_FIRMWARE_VOLUME_HEADER.
    116 
    117   @param[in] Instance The index of the EFI_FW_VOL_INSTANCE.
    118 
    119   @return A pointer to EFI_FW_VOL_INSTANCE.
    120 
    121 **/
    122 EFI_FW_VOL_INSTANCE *
    123 GetFvbInstance (
    124   IN  UINTN             Instance
    125   )
    126 {
    127   EFI_FW_VOL_INSTANCE   *FwhRecord;
    128 
    129   if ( Instance >= mFvbModuleGlobal.NumFv ) {
    130     ASSERT_EFI_ERROR (EFI_INVALID_PARAMETER);
    131     return NULL;
    132   }
    133 
    134   //
    135   // Find the right instance of the FVB private data.
    136   //
    137   FwhRecord = mFvbModuleGlobal.FvInstance;
    138   while ( Instance > 0 ) {
    139     FwhRecord = (EFI_FW_VOL_INSTANCE *) ((UINTN)((UINT8 *)FwhRecord) +
    140                 FwhRecord->VolumeHeader.HeaderLength +
    141                 (sizeof (EFI_FW_VOL_INSTANCE) - sizeof (EFI_FIRMWARE_VOLUME_HEADER)));
    142     Instance --;
    143   }
    144 
    145   return FwhRecord;
    146 
    147 }
    148 
    149 
    150 /**
    151   Get the EFI_FVB_ATTRIBUTES_2 of a FV.
    152 
    153   @param[in]  The index of the EFI_FW_VOL_INSTANCE.
    154 
    155   @return     EFI_FVB_ATTRIBUTES_2 of the FV identified by Instance.
    156 
    157 **/
    158 STATIC
    159 EFI_FVB_ATTRIBUTES_2
    160 FvbGetVolumeAttributes (
    161   IN UINTN                                Instance
    162   )
    163 {
    164   EFI_FW_VOL_INSTANCE *    FwInstance = NULL;
    165   FwInstance = GetFvbInstance(Instance);
    166   ASSERT_EFI_ERROR (FwInstance != NULL);
    167 
    168   if ( FwInstance != NULL ) {
    169     return FwInstance->VolumeHeader.Attributes;
    170   } else {
    171     return 0;
    172   }
    173 }
    174 
    175 
    176 /**
    177   Retrieves the starting address of an LBA in an FV. It also
    178   return a few other attribut of the FV.
    179 
    180   @param[in]  Instance               The index of the EFI_FW_VOL_INSTANCE.
    181   @param[in]  Lba                    The logical block address.
    182   @param[out] LbaAddress             On output, contains the physical starting address
    183                                      of the Lba.
    184   @param[out] LbaLength              On output, contains the length of the block.
    185   @param[out] NumOfBlocks            A pointer to a caller allocated UINTN in which the
    186                                      number of consecutive blocks starting with Lba is
    187                                      returned. All blocks in this range have a size of
    188                                      BlockSize.
    189 
    190   @retval  EFI_SUCCESS Successfully  returns.
    191   @retval  EFI_INVALID_PARAMETER     Instance not found.
    192 
    193 **/
    194 STATIC
    195 EFI_STATUS
    196 FvbGetLbaAddress (
    197   IN  UINTN                               Instance,
    198   IN  EFI_LBA                             Lba,
    199   OUT UINTN                               *LbaAddress,
    200   OUT UINTN                               *LbaLength,
    201   OUT UINTN                               *NumOfBlocks
    202   )
    203 {
    204   UINT32                                  NumBlocks = 0;
    205   UINT32                                  BlockLength = 0;
    206   UINTN                                   Offset;
    207   EFI_LBA                                 StartLba;
    208   EFI_LBA                                 NextLba;
    209   EFI_FW_VOL_INSTANCE                     *FwhInstance;
    210   EFI_FV_BLOCK_MAP_ENTRY                  *BlockMap = NULL;
    211 
    212   //
    213   // Find the right instance of the FVB private data.
    214   //
    215   FwhInstance = GetFvbInstance (Instance);
    216 
    217   StartLba  = 0;
    218   Offset    = 0;
    219   BlockMap  = &(FwhInstance->VolumeHeader.BlockMap[0]);
    220   ASSERT_EFI_ERROR (BlockMap != NULL);
    221 
    222   //
    223   // Parse the blockmap of the FV to find which map entry the Lba belongs to.
    224   //
    225   while (TRUE) {
    226     if ( BlockMap != NULL) {
    227       NumBlocks   = BlockMap->NumBlocks;
    228       BlockLength = BlockMap->Length;
    229     }
    230 
    231     if ( NumBlocks == 0 || BlockLength == 0) {
    232       return EFI_INVALID_PARAMETER;
    233     }
    234 
    235     NextLba = StartLba + NumBlocks;
    236 
    237     //
    238     // The map entry found.
    239     //
    240     if (Lba >= StartLba && Lba < NextLba) {
    241       Offset = Offset + (UINTN)MultU64x32((Lba - StartLba), BlockLength);
    242       if ( LbaAddress && FwhInstance ) {
    243         *LbaAddress = FwhInstance->FvBase + Offset;
    244       }
    245 
    246       if (LbaLength ) {
    247         *LbaLength = BlockLength;
    248       }
    249 
    250       if (NumOfBlocks ) {
    251         *NumOfBlocks = (UINTN)(NextLba - Lba);
    252       }
    253       return EFI_SUCCESS;
    254     }
    255 
    256     StartLba  = NextLba;
    257     Offset    = Offset + NumBlocks * BlockLength;
    258     BlockMap++;
    259   }
    260 }
    261 
    262 
    263 /**
    264   Reads specified number of bytes into a buffer from the specified block.
    265 
    266   @param[in]      Instance               The FV instance to be read from.
    267   @param[in]      Lba                    The logical block address to be read from.
    268   @param[in]      BlockOffset            Offset into the block at which to begin reading.
    269   @param[in]      NumBytes               Pointer that on input contains the total size of
    270                                          the buffer. On output, it contains the total number
    271                                          of bytes read.
    272   @param[in]      Buffer                 Pointer to a caller allocated buffer that will be
    273                                          used to hold the data read.
    274 
    275 
    276   @retval         EFI_SUCCESS            The firmware volume was read successfully and
    277                                          contents are in Buffer.
    278   @retval         EFI_BAD_BUFFER_SIZE    Read attempted across a LBA boundary. On output,
    279                                          NumBytes contains the total number of bytes returned
    280                                          in Buffer.
    281   @retval         EFI_ACCESS_DENIED      The firmware volume is in the ReadDisabled state.
    282   @retval         EFI_DEVICE_ERROR       The block device is not functioning correctly and
    283                                          could not be read.
    284   @retval         EFI_INVALID_PARAMETER  Instance not found, or NumBytes, Buffer are NULL.
    285 
    286 **/
    287 STATIC
    288 EFI_STATUS
    289 FvbReadBlock (
    290   IN UINTN                                Instance,
    291   IN EFI_LBA                              Lba,
    292   IN UINTN                                BlockOffset,
    293   IN OUT UINTN                            *NumBytes,
    294   IN UINT8                                *Buffer
    295   )
    296 {
    297   EFI_FVB_ATTRIBUTES_2                    Attributes;
    298   UINTN                                   LbaAddress;
    299   UINTN                                   LbaLength;
    300   EFI_STATUS                              Status;
    301 
    302   if ( (NumBytes == NULL) || (Buffer == NULL)) {
    303     return (EFI_INVALID_PARAMETER);
    304   }
    305   if (*NumBytes == 0) {
    306     return (EFI_INVALID_PARAMETER);
    307   }
    308 
    309   Status = FvbGetLbaAddress (Instance, Lba, &LbaAddress, &LbaLength, NULL);
    310   if (EFI_ERROR(Status)) {
    311     return Status;
    312   }
    313 
    314   Attributes = FvbGetVolumeAttributes (Instance);
    315 
    316   if ( (Attributes & EFI_FVB2_READ_STATUS) == 0) {
    317     return (EFI_ACCESS_DENIED);
    318   }
    319 
    320   if (BlockOffset > LbaLength) {
    321    return (EFI_INVALID_PARAMETER);
    322   }
    323 
    324   if (LbaLength < ( *NumBytes + BlockOffset ) ) {
    325     *NumBytes = (UINT32) (LbaLength - BlockOffset);
    326     Status = EFI_BAD_BUFFER_SIZE;
    327   }
    328 
    329   LibFvbFlashDeviceRead (LbaAddress + BlockOffset, NumBytes, Buffer);
    330 
    331   return Status;
    332 }
    333 
    334 
    335 /**
    336   Writes specified number of bytes from the input buffer to the block.
    337 
    338   @param[in]  Instance               The FV instance to be written to.
    339   @param[in]  Lba                    The starting logical block index to write to.
    340   @param[in]  BlockOffset            Offset into the block at which to begin writing.
    341   @param[in]  NumBytes               Pointer that on input contains the total size of
    342                                      the buffer. On output, it contains the total number
    343                                      of bytes actually written.
    344   @param[in]  Buffer                 Pointer to a caller allocated buffer that contains
    345                                      the source for the write.
    346   @retval     EFI_SUCCESS            The firmware volume was written successfully.
    347   @retval     EFI_BAD_BUFFER_SIZE    Write attempted across a LBA boundary. On output,
    348                                      NumBytes contains the total number of bytes
    349                                      actually writte.
    350   @retval     EFI_ACCESS_DENIED      The firmware volume is in the WriteDisabled state.
    351   @retval     EFI_DEVICE_ERROR       The block device is not functioning correctly and
    352                                      could not be written.
    353   @retval     EFI_INVALID_PARAMETER  Instance not found, or NumBytes, Buffer are NULL.
    354 
    355 **/
    356 EFI_STATUS
    357 FvbWriteBlock (
    358   IN UINTN                                Instance,
    359   IN EFI_LBA                              Lba,
    360   IN UINTN                                BlockOffset,
    361   IN OUT UINTN                            *NumBytes,
    362   IN UINT8                                *Buffer
    363   )
    364 {
    365   EFI_FVB_ATTRIBUTES_2                    Attributes;
    366   UINTN                                   LbaAddress;
    367   UINTN                                   LbaLength;
    368   EFI_FW_VOL_INSTANCE                     *FwhInstance;
    369   EFI_STATUS                              Status;
    370   EFI_STATUS                              Status1;
    371 
    372   FwhInstance = GetFvbInstance (Instance);
    373 
    374   if ( (NumBytes == NULL) || (Buffer == NULL)) {
    375     return (EFI_INVALID_PARAMETER);
    376   }
    377   if (*NumBytes == 0) {
    378     return (EFI_INVALID_PARAMETER);
    379   }
    380 
    381   Status = FvbGetLbaAddress (Instance, Lba, &LbaAddress, &LbaLength, NULL);
    382   if (EFI_ERROR(Status)) {
    383     return Status;
    384   }
    385 
    386   //
    387   // Check if the FV is write enabled.
    388   //
    389   Attributes = FvbGetVolumeAttributes (Instance);
    390   if ( (Attributes & EFI_FVB2_WRITE_STATUS) == 0) {
    391     return (EFI_ACCESS_DENIED);
    392   }
    393 
    394   //
    395   // Perform boundary checks and adjust NumBytes.
    396   //
    397   if (BlockOffset > LbaLength) {
    398     return (EFI_INVALID_PARAMETER);
    399   }
    400 
    401   if ( LbaLength < ( *NumBytes + BlockOffset ) ) {
    402     DEBUG ((EFI_D_ERROR,
    403       "FvWriteBlock: Reducing Numbytes from 0x%x to 0x%x\n",
    404       *NumBytes,
    405       (UINT32)(LbaLength-BlockOffset))
    406       );
    407     *NumBytes = (UINT32) (LbaLength - BlockOffset);
    408     Status = EFI_BAD_BUFFER_SIZE;
    409   }
    410 
    411   LibFvbFlashDeviceBlockLock (LbaAddress, LbaLength, FALSE);
    412 
    413   Status1 = LibFvbFlashDeviceWrite (LbaAddress + BlockOffset, NumBytes, Buffer);
    414 
    415   LibFvbFlashDeviceBlockLock (LbaAddress, LbaLength, TRUE);
    416   WriteBackInvalidateDataCacheRange ((VOID *) (LbaAddress + BlockOffset), *NumBytes);
    417 
    418   if ( EFI_ERROR (Status1) ) {
    419     return Status1;
    420   }
    421 
    422   return Status;
    423 }
    424 
    425 
    426 /**
    427   Erases and initializes a firmware volume block.
    428 
    429   @param[in]    Instance           The FV instance to be erased.
    430   @param[in]    Lba                The logical block index to be erased.
    431 
    432   @retval   EFI_SUCCESS            The erase request was successfully completed.
    433   @retval   EFI_ACCESS_DENIED      The firmware volume is in the WriteDisabled state.
    434   @retval   EFI_DEVICE_ERROR       The block device is not functioning correctly and
    435                                    could not be written. Firmware device may have been
    436                                    partially erased.
    437   @retval   EFI_INVALID_PARAMETER  Instance not found.
    438 
    439 **/
    440 EFI_STATUS
    441 FvbEraseBlock (
    442   IN UINTN                                Instance,
    443   IN EFI_LBA                              Lba
    444   )
    445 {
    446   EFI_FVB_ATTRIBUTES_2                    Attributes;
    447   UINTN                                   LbaAddress;
    448   EFI_FW_VOL_INSTANCE                     *FwhInstance;
    449   UINTN                                   LbaLength;
    450   EFI_STATUS                              Status;
    451 
    452   //
    453   // Find the right instance of the FVB private data.
    454   //
    455   FwhInstance = GetFvbInstance (Instance);
    456 
    457   //
    458   // Check if the FV is write enabled.
    459   //
    460   Attributes = FvbGetVolumeAttributes (Instance);
    461 
    462   if( (Attributes & EFI_FVB2_WRITE_STATUS) == 0) {
    463     return (EFI_ACCESS_DENIED);
    464   }
    465 
    466   //
    467   // Get the starting address of the block for erase.
    468   //
    469   Status = FvbGetLbaAddress (Instance, Lba, &LbaAddress, &LbaLength, NULL);
    470   if (EFI_ERROR(Status)) {
    471     return Status;
    472   }
    473 
    474   LibFvbFlashDeviceBlockLock (LbaAddress, LbaLength, FALSE);
    475 
    476   Status = LibFvbFlashDeviceBlockErase (LbaAddress, LbaLength);
    477 
    478   LibFvbFlashDeviceBlockLock (LbaAddress, LbaLength, TRUE);
    479 
    480   WriteBackInvalidateDataCacheRange ((VOID *) LbaAddress, LbaLength);
    481 
    482   return Status;
    483 }
    484 
    485 
    486 /**
    487   Modifies the current settings of the firmware volume according to the
    488   input parameter, and returns the new setting of the volume.
    489 
    490   @param[in]  Instance              The FV instance whose attributes is going to be
    491                                     modified.
    492   @param[in]  Attributes            On input, it is a pointer to EFI_FVB_ATTRIBUTES_2
    493                                     containing the desired firmware volume settings.
    494                                     On successful return, it contains the new settings
    495                                     of the firmware volume.
    496 
    497   @retval     EFI_SUCCESS           Successfully returns.
    498   @retval     EFI_ACCESS_DENIED     The volume setting is locked and cannot be modified.
    499   @retval     EFI_INVALID_PARAMETER Instance not found, or The attributes requested are
    500                                     in conflict with the capabilities as declared in the
    501                                     firmware volume header.
    502 
    503 **/
    504 STATIC
    505 EFI_STATUS
    506 FvbSetVolumeAttributes (
    507   IN UINTN                                Instance,
    508   IN OUT EFI_FVB_ATTRIBUTES_2             *Attributes
    509   )
    510 {
    511   EFI_FW_VOL_INSTANCE                       *FwhInstance = NULL;
    512   EFI_FVB_ATTRIBUTES_2                      OldAttributes = 0;
    513   EFI_FVB_ATTRIBUTES_2                      *AttribPtr = NULL;
    514   EFI_FVB_ATTRIBUTES_2                      UnchangedAttributes;
    515   UINT32                                    Capabilities;
    516   UINT32                                    OldStatus, NewStatus;
    517 
    518   //
    519   // Find the right instance of the FVB private data.
    520   //
    521   FwhInstance = GetFvbInstance (Instance);
    522 
    523   AttribPtr     = (EFI_FVB_ATTRIBUTES_2 *) & (FwhInstance->VolumeHeader.Attributes);
    524   ASSERT_EFI_ERROR (AttribPtr != NULL);
    525 
    526   if ( AttribPtr != NULL) {
    527     OldAttributes = *AttribPtr;
    528   }
    529 
    530   Capabilities  = OldAttributes & EFI_FVB2_CAPABILITIES;
    531   OldStatus     = OldAttributes & EFI_FVB2_STATUS;
    532   NewStatus     = *Attributes & EFI_FVB2_STATUS;
    533 
    534   UnchangedAttributes = EFI_FVB2_READ_DISABLED_CAP  | \
    535                         EFI_FVB2_READ_ENABLED_CAP   | \
    536                         EFI_FVB2_WRITE_DISABLED_CAP | \
    537                         EFI_FVB2_WRITE_ENABLED_CAP  | \
    538                         EFI_FVB2_LOCK_CAP           | \
    539                         EFI_FVB2_STICKY_WRITE       | \
    540                         EFI_FVB2_MEMORY_MAPPED      | \
    541                         EFI_FVB2_ERASE_POLARITY     | \
    542                         EFI_FVB2_READ_LOCK_CAP      | \
    543                         EFI_FVB2_WRITE_LOCK_CAP     | \
    544                         EFI_FVB2_ALIGNMENT;
    545 
    546   //
    547   // Some attributes of FV is read only can *not* be set.
    548   //
    549   if ((OldAttributes & UnchangedAttributes) ^ (*Attributes & UnchangedAttributes)) {
    550     return EFI_INVALID_PARAMETER;
    551   }
    552 
    553   //
    554   // If firmware volume is locked, no status bit can be updated.
    555   //
    556   if ( OldAttributes & EFI_FVB2_LOCK_STATUS ) {
    557     if ( OldStatus ^ NewStatus ) {
    558       return EFI_ACCESS_DENIED;
    559     }
    560   }
    561 
    562   //
    563   // Test read disable.
    564   //
    565   if ((Capabilities & EFI_FVB2_READ_DISABLED_CAP) == 0) {
    566     if ((NewStatus & EFI_FVB2_READ_STATUS) == 0) {
    567       return EFI_INVALID_PARAMETER;
    568     }
    569   }
    570 
    571   //
    572   // Test read enable.
    573   //
    574   if ((Capabilities & EFI_FVB2_READ_ENABLED_CAP) == 0) {
    575     if (NewStatus & EFI_FVB2_READ_STATUS) {
    576       return EFI_INVALID_PARAMETER;
    577     }
    578   }
    579 
    580   //
    581   // Test write disable.
    582   //
    583   if ((Capabilities & EFI_FVB2_WRITE_DISABLED_CAP) == 0) {
    584     if ((NewStatus & EFI_FVB2_WRITE_STATUS) == 0) {
    585       return EFI_INVALID_PARAMETER;
    586     }
    587   }
    588 
    589   //
    590   // Test write enable.
    591   //
    592   if ((Capabilities & EFI_FVB2_WRITE_ENABLED_CAP) == 0) {
    593     if (NewStatus & EFI_FVB2_WRITE_STATUS) {
    594       return EFI_INVALID_PARAMETER;
    595     }
    596   }
    597 
    598   //
    599   // Test lock.
    600   //
    601   if ((Capabilities & EFI_FVB2_LOCK_CAP) == 0) {
    602     if (NewStatus & EFI_FVB2_LOCK_STATUS) {
    603       return EFI_INVALID_PARAMETER;
    604     }
    605   }
    606 
    607   *AttribPtr  = (*AttribPtr) & (0xFFFFFFFF & (~EFI_FVB2_STATUS));
    608   *AttribPtr  = (*AttribPtr) | NewStatus;
    609   *Attributes = *AttribPtr;
    610 
    611   return EFI_SUCCESS;
    612 }
    613 
    614 //
    615 // FVB protocol APIs.
    616 //
    617 /**
    618   Retrieves the physical address of the device.
    619 
    620   @param[in]  This    A pointer to EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL.
    621   @param[out] Address Output buffer containing the address.
    622 
    623   retval      EFI_SUCCESS The function always return successfully.
    624 
    625 **/
    626 EFI_STATUS
    627 EFIAPI
    628 FvbProtocolGetPhysicalAddress (
    629   IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL  *This,
    630   OUT EFI_PHYSICAL_ADDRESS               *Address
    631   )
    632 {
    633   EFI_FW_VOL_BLOCK_DEVICE               *FvbDevice;
    634   EFI_FW_VOL_INSTANCE                   *FvInstance;
    635 
    636   FvbDevice = FVB_DEVICE_FROM_THIS (This);
    637   FvInstance = GetFvbInstance(FvbDevice->Instance);
    638 
    639   if (FvInstance != NULL) {
    640     *Address = FvInstance->FvBase;
    641   }
    642 
    643   return EFI_SUCCESS;
    644 }
    645 
    646 
    647 /**
    648   Retrieve the size of a logical block.
    649 
    650   @param[in]  This         Calling context.
    651   @param[in]  Lba          Indicates which block to return the size for.
    652   @param[out] BlockSize    A pointer to a caller allocated UINTN in which
    653                            the size of the block is returned.
    654   @param[out] NumOfBlocks  A pointer to a caller allocated UINTN in which the
    655                            number of consecutive blocks starting with Lba is
    656                            returned. All blocks in this range have a size of
    657                            BlockSize.
    658 
    659   @retval     EFI_SUCCESS  The function always return successfully.
    660 
    661 **/
    662 EFI_STATUS
    663 EFIAPI
    664 FvbProtocolGetBlockSize (
    665   IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL  *This,
    666   IN  EFI_LBA                            Lba,
    667   OUT UINTN                              *BlockSize,
    668   OUT UINTN                              *NumOfBlocks
    669   )
    670 {
    671   EFI_FW_VOL_BLOCK_DEVICE                 *FvbDevice;
    672 
    673   DEBUG((EFI_D_INFO,
    674     "FvbProtocolGetBlockSize: Lba: 0x%lx BlockSize: 0x%x NumOfBlocks: 0x%x\n",
    675     Lba,
    676     BlockSize,
    677     NumOfBlocks)
    678     );
    679 
    680   FvbDevice = FVB_DEVICE_FROM_THIS (This);
    681 
    682   return FvbGetLbaAddress (
    683            FvbDevice->Instance,
    684            Lba,
    685            NULL,
    686            BlockSize,
    687            NumOfBlocks
    688            );
    689 }
    690 
    691 
    692 /**
    693   Retrieves Volume attributes.  No polarity translations are done.
    694 
    695   @param[in]    This         Calling context.
    696   @param[out]   Attributes   Output buffer which contains attributes.
    697 
    698   @retval       EFI_SUCCESS  The function always return successfully.
    699 
    700 **/
    701 EFI_STATUS
    702 EFIAPI
    703 FvbProtocolGetAttributes (
    704   IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL   *This,
    705   OUT EFI_FVB_ATTRIBUTES_2                *Attributes
    706   )
    707 {
    708   EFI_FW_VOL_BLOCK_DEVICE               *FvbDevice;
    709 
    710   FvbDevice = FVB_DEVICE_FROM_THIS (This);
    711 
    712   *Attributes = FvbGetVolumeAttributes (FvbDevice->Instance);
    713 
    714   DEBUG ((EFI_D_INFO,
    715     "FvbProtocolGetAttributes: This: 0x%x Attributes: 0x%x\n",
    716     This,
    717     *Attributes)
    718     );
    719 
    720   return EFI_SUCCESS;
    721 }
    722 
    723 
    724 /**
    725   Sets Volume attributes. No polarity translations are done.
    726 
    727   @param[in]  This         Calling context.
    728   @param[out] Attributes   Output buffer which contains attributes.
    729 
    730   @retval     EFI_SUCCESS  The function always return successfully.
    731 
    732 **/
    733 EFI_STATUS
    734 EFIAPI
    735 FvbProtocolSetAttributes (
    736   IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL   *This,
    737   IN OUT EFI_FVB_ATTRIBUTES_2             *Attributes
    738   )
    739 {
    740   EFI_STATUS                            Status;
    741   EFI_FW_VOL_BLOCK_DEVICE               *FvbDevice;
    742 
    743   DEBUG((EFI_D_INFO,
    744     "FvbProtocolSetAttributes: Before SET -  This: 0x%x Attributes: 0x%x\n",
    745     This,
    746     *Attributes)
    747     );
    748 
    749   FvbDevice = FVB_DEVICE_FROM_THIS (This);
    750 
    751   Status = FvbSetVolumeAttributes (FvbDevice->Instance, Attributes);
    752 
    753   DEBUG((EFI_D_INFO,
    754     "FvbProtocolSetAttributes: After SET -  This: 0x%x Attributes: 0x%x\n",
    755     This,
    756     *Attributes)
    757     );
    758 
    759   return Status;
    760 }
    761 
    762 
    763 /**
    764   The EraseBlock() function erases one or more blocks as denoted by the
    765   variable argument list. The entire parameter list of blocks must be verified
    766   prior to erasing any blocks.  If a block is requested that does not exist
    767   within the associated firmware volume (it has a larger index than the last
    768   block of the firmware volume), the EraseBlock() function must return
    769   EFI_INVALID_PARAMETER without modifying the contents of the firmware volume.
    770 
    771   @param[in] This            Calling context.
    772   @param[in] ...             Starting LBA followed by Number of Lba to erase.
    773                              a -1 to terminate the list.
    774 
    775   @retval EFI_SUCCESS        The erase request was successfully completed.
    776   @retval EFI_ACCESS_DENIED  The firmware volume is in the WriteDisabled state.
    777   @retval EFI_DEVICE_ERROR   The block device is not functioning correctly and
    778                              could not be written. Firmware device may have been
    779                              partially erased.
    780 
    781 **/
    782 EFI_STATUS
    783 EFIAPI
    784 FvbProtocolEraseBlocks (
    785   IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL    *This,
    786   ...
    787   )
    788 {
    789   EFI_FW_VOL_BLOCK_DEVICE               *FvbDevice;
    790   EFI_FW_VOL_INSTANCE                   *FwhInstance;
    791   UINTN                                 NumOfBlocks = 0;
    792   VA_LIST                               args;
    793   EFI_LBA                               StartingLba;
    794   UINTN                                 NumOfLba;
    795   EFI_STATUS                            Status;
    796 
    797   DEBUG((EFI_D_INFO, "FvbProtocolEraseBlocks: \n"));
    798   FvbDevice = FVB_DEVICE_FROM_THIS (This);
    799 
    800   FwhInstance  = GetFvbInstance (FvbDevice->Instance);
    801 
    802   if (FwhInstance != NULL) {
    803     NumOfBlocks = FwhInstance->NumOfBlocks;
    804   }
    805 
    806   VA_START (args, This);
    807 
    808   do {
    809     StartingLba = VA_ARG (args, EFI_LBA);
    810     if ( StartingLba == EFI_LBA_LIST_TERMINATOR ) {
    811       break;
    812     }
    813 
    814     NumOfLba = VA_ARG (args, UINT32);
    815 
    816     //
    817     // Check input parameters.
    818     //
    819     if (NumOfLba == 0) {
    820       VA_END (args);
    821       return EFI_INVALID_PARAMETER;
    822     }
    823 
    824     if ( ( StartingLba + NumOfLba ) > NumOfBlocks ) {
    825       return EFI_INVALID_PARAMETER;
    826     }
    827   } while ( 1 );
    828 
    829   VA_END (args);
    830 
    831   VA_START (args, This);
    832   do {
    833     StartingLba = VA_ARG (args, EFI_LBA);
    834     if (StartingLba == EFI_LBA_LIST_TERMINATOR) {
    835       break;
    836     }
    837 
    838     NumOfLba = VA_ARG (args, UINT32);
    839 
    840     while ( NumOfLba > 0 ) {
    841       Status = FvbEraseBlock (FvbDevice->Instance, StartingLba);
    842       if ( EFI_ERROR(Status)) {
    843         VA_END (args);
    844         return Status;
    845       }
    846       StartingLba ++;
    847       NumOfLba --;
    848     }
    849 
    850   } while ( 1 );
    851 
    852   VA_END (args);
    853 
    854   return EFI_SUCCESS;
    855 }
    856 
    857 
    858 /**
    859   Writes data beginning at Lba:Offset from FV. The write terminates either
    860   when *NumBytes of data have been written, or when a block boundary is
    861   reached.  *NumBytes is updated to reflect the actual number of bytes
    862   written. The write opertion does not include erase. This routine will
    863   attempt to write only the specified bytes. If the writes do not stick,
    864   it will return an error.
    865 
    866   @param[in]      This      Calling context.
    867   @param[in]      Lba       Block in which to begin write.
    868   @param[in]      Offset    Offset in the block at which to begin write.
    869   @param[in,out]  NumBytes  On input, indicates the requested write size. On
    870                             output, indicates the actual number of bytes written
    871   @param[in]      Buffer    Buffer containing source data for the write.
    872 
    873   @retval EFI_SUCCESS           The firmware volume was written successfully.
    874   @retval EFI_BAD_BUFFER_SIZE   Write attempted across a LBA boundary. On output,
    875                                 NumBytes contains the total number of bytes
    876                                 actually written.
    877   @retval EFI_ACCESS_DENIED     The firmware volume is in the WriteDisabled state.
    878   @retval EFI_DEVICE_ERROR      The block device is not functioning correctly and
    879                                 could not be written.
    880   @retval EFI_INVALID_PARAMETER NumBytes or Buffer are NULL.
    881 
    882 **/
    883 EFI_STATUS
    884 EFIAPI
    885 FvbProtocolWrite (
    886   IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL   *This,
    887   IN EFI_LBA                              Lba,
    888   IN UINTN                                Offset,
    889   IN OUT UINTN                            *NumBytes,
    890   IN UINT8                                *Buffer
    891   )
    892 {
    893 
    894   EFI_FW_VOL_BLOCK_DEVICE               *FvbDevice;
    895 
    896   FvbDevice = FVB_DEVICE_FROM_THIS (This);
    897 
    898   DEBUG((EFI_D_INFO,
    899     "FvbProtocolWrite: Lba: 0x%lx Offset: 0x%x NumBytes: 0x%x, Buffer: 0x%x\n",
    900     Lba,
    901     Offset,
    902     *NumBytes,
    903     Buffer)
    904     );
    905 
    906   return FvbWriteBlock (FvbDevice->Instance, Lba, Offset, NumBytes, Buffer);
    907 }
    908 
    909 
    910 /**
    911   Reads data beginning at Lba:Offset from FV. The Read terminates either
    912   when *NumBytes of data have been read, or when a block boundary is
    913   reached.  *NumBytes is updated to reflect the actual number of bytes
    914   written. The write opertion does not include erase. This routine will
    915   attempt to write only the specified bytes. If the writes do not stick,
    916   it will return an error.
    917 
    918   @param[in]      This      Calling context.
    919   @param[in]      Lba       Block in which to begin write.
    920   @param[in]      Offset    Offset in the block at which to begin write
    921   @param[in,out]  NumBytes  On input, indicates the requested write size. On
    922                             output, indicates the actual number of bytes written.
    923   @param[in]      Buffer    Buffer containing source data for the write.
    924 
    925 
    926 Returns:
    927   @retval EFI_SUCCESS            The firmware volume was read successfully and
    928                                  contents are in Buffer.
    929   @retval EFI_BAD_BUFFER_SIZE    Read attempted across a LBA boundary. On output,
    930                                  NumBytes contains the total number of bytes returned
    931                                  in Buffer.
    932   @retval EFI_ACCESS_DENIED      The firmware volume is in the ReadDisabled state
    933   @retval EFI_DEVICE_ERROR       The block device is not functioning correctly and
    934                                  could not be read.
    935   @retval EFI_INVALID_PARAMETER  NumBytes or Buffer are NULL.
    936 
    937 **/
    938 EFI_STATUS
    939 EFIAPI
    940 FvbProtocolRead (
    941   IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL   *This,
    942   IN EFI_LBA                              Lba,
    943   IN UINTN                                Offset,
    944   IN OUT UINTN                            *NumBytes,
    945   OUT UINT8                                *Buffer
    946   )
    947 {
    948 
    949   EFI_FW_VOL_BLOCK_DEVICE   *FvbDevice;
    950   EFI_STATUS                Status;
    951 
    952   FvbDevice = FVB_DEVICE_FROM_THIS (This);
    953   Status = FvbReadBlock (FvbDevice->Instance, Lba, Offset, NumBytes, Buffer);
    954   DEBUG((EFI_D_INFO,
    955     "FvbProtocolRead: Lba: 0x%lx Offset: 0x%x NumBytes: 0x%x, Buffer: 0x%x\n",
    956     Lba,
    957     Offset,
    958     *NumBytes,
    959     Buffer)
    960     );
    961 
    962   return Status;
    963 }
    964 
    965 
    966 /**
    967   Check the integrity of firmware volume header.
    968 
    969   @param[in]  FwVolHeader   A pointer to a firmware volume header.
    970 
    971   @retval     TRUE          The firmware volume is consistent.
    972   @retval     FALSE         The firmware volume has corrupted.
    973 
    974 **/
    975 BOOLEAN
    976 IsFvHeaderValid (
    977   IN       EFI_PHYSICAL_ADDRESS          FvBase,
    978   IN CONST EFI_FIRMWARE_VOLUME_HEADER    *FwVolHeader
    979   )
    980 {
    981   if (FvBase == PcdGet32(PcdFlashNvStorageVariableBase)) {
    982     if (CompareMem (&FwVolHeader->FileSystemGuid, &gEfiSystemNvDataFvGuid, sizeof(EFI_GUID)) != 0 ) {
    983       return FALSE;
    984     }
    985   } else {
    986     if (CompareMem (&FwVolHeader->FileSystemGuid, &gEfiFirmwareFileSystem2Guid, sizeof(EFI_GUID)) != 0 ) {
    987       return FALSE;
    988     }
    989   }
    990   if ( (FwVolHeader->Revision != EFI_FVH_REVISION)   ||
    991        (FwVolHeader->Signature != EFI_FVH_SIGNATURE) ||
    992        (FwVolHeader->FvLength == ((UINTN) -1))       ||
    993        ((FwVolHeader->HeaderLength & 0x01 ) !=0) ) {
    994     return FALSE;
    995   }
    996 
    997   if (CalculateCheckSum16 ((UINT16 *) FwVolHeader, FwVolHeader->HeaderLength) != 0) {
    998     return FALSE;
    999   }
   1000 
   1001   return TRUE;
   1002 }
   1003 
   1004 
   1005 /**
   1006   The function does the necessary initialization work for
   1007   Firmware Volume Block Driver.
   1008 
   1009   @retval     EFI_SUCCESS       This funtion always return EFI_SUCCESS.
   1010                                 It will ASSERT on errors.
   1011 
   1012 **/
   1013 EFI_STATUS
   1014 FvbInitialize (
   1015   VOID
   1016   )
   1017 {
   1018   EFI_FW_VOL_INSTANCE                   *FwhInstance;
   1019   EFI_FIRMWARE_VOLUME_HEADER            *FwVolHeader;
   1020   EFI_FIRMWARE_VOLUME_HEADER            *FvHeader;
   1021   EFI_FV_BLOCK_MAP_ENTRY                *PtrBlockMapEntry;
   1022   EFI_PHYSICAL_ADDRESS                  BaseAddress;
   1023   EFI_STATUS                            Status;
   1024   UINTN                                 BufferSize;
   1025   UINTN                                 TmpHeaderLength;
   1026   UINTN                                 Idx;
   1027   UINT32                                MaxLbaSize;
   1028   BOOLEAN                               FvHeaderValid;
   1029 
   1030   //
   1031   // Calculate the total size for all firmware volume block instances.
   1032   //
   1033   BufferSize = 0;
   1034   for (Idx = 0; Idx < 1; Idx++) {
   1035     FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) mPlatformFvBaseAddress[Idx];
   1036     BufferSize +=  (FvHeader->HeaderLength +
   1037                     sizeof (EFI_FW_VOL_INSTANCE) -
   1038                     sizeof (EFI_FIRMWARE_VOLUME_HEADER)
   1039                    );
   1040   }
   1041 
   1042   mFvbModuleGlobal.FvInstance =  (EFI_FW_VOL_INSTANCE *) AllocateRuntimeZeroPool (BufferSize);
   1043   ASSERT (NULL != mFvbModuleGlobal.FvInstance);
   1044 
   1045 
   1046   MaxLbaSize      = 0;
   1047   FwhInstance     = mFvbModuleGlobal.FvInstance;
   1048   mFvbModuleGlobal.NumFv   = 0;
   1049 
   1050   for (Idx = 0; Idx < 1; Idx++) {
   1051     BaseAddress = mPlatformFvBaseAddress[Idx];
   1052     FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) BaseAddress;
   1053 
   1054     if (!IsFvHeaderValid (BaseAddress, FwVolHeader)) {
   1055       FvHeaderValid = FALSE;
   1056       //
   1057       // If not valid, get FvbInfo from the information carried in
   1058       // FVB driver.
   1059       //
   1060       DEBUG ((EFI_D_ERROR, "Fvb: FV header @ 0x%lx invalid\n", BaseAddress));
   1061       Status          = GetFvbInfo (BaseAddress, &FwVolHeader);
   1062       ASSERT_EFI_ERROR(Status);
   1063       //
   1064       //  Write back a healthy FV header.
   1065       //
   1066       DEBUG ((EFI_D_ERROR, "FwBlockService.c: Writing back healthy FV header\n"));
   1067       LibFvbFlashDeviceBlockLock ((UINTN)BaseAddress, FwVolHeader->BlockMap->Length, FALSE);
   1068 
   1069       Status = LibFvbFlashDeviceBlockErase ((UINTN)BaseAddress, FwVolHeader->BlockMap->Length);
   1070 
   1071       TmpHeaderLength = (UINTN) FwVolHeader->HeaderLength;
   1072       Status = LibFvbFlashDeviceWrite (
   1073                  (UINTN)BaseAddress,
   1074                  &TmpHeaderLength,
   1075                  (UINT8 *) FwVolHeader
   1076                  );
   1077 
   1078       LibFvbFlashDeviceBlockLock ((UINTN)BaseAddress, FwVolHeader->BlockMap->Length, TRUE);
   1079 
   1080       WriteBackInvalidateDataCacheRange (
   1081         (VOID *) (UINTN) BaseAddress,
   1082         FwVolHeader->BlockMap->Length
   1083         );
   1084 
   1085     }
   1086 
   1087     CopyMem (&(FwhInstance->VolumeHeader), FwVolHeader, FwVolHeader->HeaderLength);
   1088 
   1089     FwVolHeader = &(FwhInstance->VolumeHeader);
   1090     FwhInstance->FvBase = (UINTN)BaseAddress;
   1091 
   1092     //
   1093     // Process the block map for each FV.
   1094     //
   1095     FwhInstance->NumOfBlocks = 0;
   1096     for (PtrBlockMapEntry = FwVolHeader->BlockMap; PtrBlockMapEntry->NumBlocks != 0; PtrBlockMapEntry++) {
   1097       //
   1098       // Get the maximum size of a block.
   1099       //
   1100       if (MaxLbaSize < PtrBlockMapEntry->Length) {
   1101         MaxLbaSize  = PtrBlockMapEntry->Length;
   1102       }
   1103       FwhInstance->NumOfBlocks += PtrBlockMapEntry->NumBlocks;
   1104     }
   1105 
   1106     //
   1107     // Add a FVB Protocol Instance.
   1108     //
   1109     mFvbModuleGlobal.NumFv++;
   1110     InstallFvbProtocol (FwhInstance, mFvbModuleGlobal.NumFv - 1);
   1111 
   1112     //
   1113     // Move on to the next FwhInstance.
   1114     //
   1115     FwhInstance = (EFI_FW_VOL_INSTANCE *) ((UINTN)((UINT8 *)FwhInstance) +
   1116                                           FwVolHeader->HeaderLength +
   1117                                           (sizeof (EFI_FW_VOL_INSTANCE) - sizeof (EFI_FIRMWARE_VOLUME_HEADER)));
   1118 
   1119   }
   1120 
   1121   return EFI_SUCCESS;
   1122 }
   1123 
   1124