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 (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 (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_STATUS                              Status;
    369   EFI_STATUS                              Status1;
    370 
    371   if ( (NumBytes == NULL) || (Buffer == NULL)) {
    372     return (EFI_INVALID_PARAMETER);
    373   }
    374   if (*NumBytes == 0) {
    375     return (EFI_INVALID_PARAMETER);
    376   }
    377 
    378   Status = FvbGetLbaAddress (Instance, Lba, &LbaAddress, &LbaLength, NULL);
    379   if (EFI_ERROR(Status)) {
    380     return Status;
    381   }
    382 
    383   //
    384   // Check if the FV is write enabled.
    385   //
    386   Attributes = FvbGetVolumeAttributes (Instance);
    387   if ( (Attributes & EFI_FVB2_WRITE_STATUS) == 0) {
    388     return (EFI_ACCESS_DENIED);
    389   }
    390 
    391   //
    392   // Perform boundary checks and adjust NumBytes.
    393   //
    394   if (BlockOffset > LbaLength) {
    395     return (EFI_INVALID_PARAMETER);
    396   }
    397 
    398   if ( LbaLength < ( *NumBytes + BlockOffset ) ) {
    399     DEBUG ((EFI_D_ERROR,
    400       "FvWriteBlock: Reducing Numbytes from 0x%x to 0x%x\n",
    401       *NumBytes,
    402       (UINT32)(LbaLength-BlockOffset))
    403       );
    404     *NumBytes = (UINT32) (LbaLength - BlockOffset);
    405     Status = EFI_BAD_BUFFER_SIZE;
    406   }
    407 
    408   LibFvbFlashDeviceBlockLock (LbaAddress, LbaLength, FALSE);
    409 
    410   Status1 = LibFvbFlashDeviceWrite (LbaAddress + BlockOffset, NumBytes, Buffer);
    411 
    412   LibFvbFlashDeviceBlockLock (LbaAddress, LbaLength, TRUE);
    413   WriteBackInvalidateDataCacheRange ((VOID *) (LbaAddress + BlockOffset), *NumBytes);
    414 
    415   if ( EFI_ERROR (Status1) ) {
    416     return Status1;
    417   }
    418 
    419   return Status;
    420 }
    421 
    422 
    423 /**
    424   Erases and initializes a firmware volume block.
    425 
    426   @param[in]    Instance           The FV instance to be erased.
    427   @param[in]    Lba                The logical block index to be erased.
    428 
    429   @retval   EFI_SUCCESS            The erase request was successfully completed.
    430   @retval   EFI_ACCESS_DENIED      The firmware volume is in the WriteDisabled state.
    431   @retval   EFI_DEVICE_ERROR       The block device is not functioning correctly and
    432                                    could not be written. Firmware device may have been
    433                                    partially erased.
    434   @retval   EFI_INVALID_PARAMETER  Instance not found.
    435 
    436 **/
    437 EFI_STATUS
    438 FvbEraseBlock (
    439   IN UINTN                                Instance,
    440   IN EFI_LBA                              Lba
    441   )
    442 {
    443   EFI_FVB_ATTRIBUTES_2                    Attributes;
    444   UINTN                                   LbaAddress;
    445   UINTN                                   LbaLength;
    446   EFI_STATUS                              Status;
    447 
    448   //
    449   // Check if the FV is write enabled.
    450   //
    451   Attributes = FvbGetVolumeAttributes (Instance);
    452 
    453   if( (Attributes & EFI_FVB2_WRITE_STATUS) == 0) {
    454     return (EFI_ACCESS_DENIED);
    455   }
    456 
    457   //
    458   // Get the starting address of the block for erase.
    459   //
    460   Status = FvbGetLbaAddress (Instance, Lba, &LbaAddress, &LbaLength, NULL);
    461   if (EFI_ERROR(Status)) {
    462     return Status;
    463   }
    464 
    465   LibFvbFlashDeviceBlockLock (LbaAddress, LbaLength, FALSE);
    466 
    467   Status = LibFvbFlashDeviceBlockErase (LbaAddress, LbaLength);
    468 
    469   LibFvbFlashDeviceBlockLock (LbaAddress, LbaLength, TRUE);
    470 
    471   WriteBackInvalidateDataCacheRange ((VOID *) LbaAddress, LbaLength);
    472 
    473   return Status;
    474 }
    475 
    476 
    477 /**
    478   Modifies the current settings of the firmware volume according to the
    479   input parameter, and returns the new setting of the volume.
    480 
    481   @param[in]  Instance              The FV instance whose attributes is going to be
    482                                     modified.
    483   @param[in]  Attributes            On input, it is a pointer to EFI_FVB_ATTRIBUTES_2
    484                                     containing the desired firmware volume settings.
    485                                     On successful return, it contains the new settings
    486                                     of the firmware volume.
    487 
    488   @retval     EFI_SUCCESS           Successfully returns.
    489   @retval     EFI_ACCESS_DENIED     The volume setting is locked and cannot be modified.
    490   @retval     EFI_INVALID_PARAMETER Instance not found, or The attributes requested are
    491                                     in conflict with the capabilities as declared in the
    492                                     firmware volume header.
    493 
    494 **/
    495 STATIC
    496 EFI_STATUS
    497 FvbSetVolumeAttributes (
    498   IN UINTN                                Instance,
    499   IN OUT EFI_FVB_ATTRIBUTES_2             *Attributes
    500   )
    501 {
    502   EFI_FW_VOL_INSTANCE                       *FwhInstance = NULL;
    503   EFI_FVB_ATTRIBUTES_2                      OldAttributes = 0;
    504   EFI_FVB_ATTRIBUTES_2                      *AttribPtr = NULL;
    505   EFI_FVB_ATTRIBUTES_2                      UnchangedAttributes;
    506   UINT32                                    Capabilities;
    507   UINT32                                    OldStatus, NewStatus;
    508 
    509   //
    510   // Find the right instance of the FVB private data.
    511   //
    512   FwhInstance = GetFvbInstance (Instance);
    513 
    514   AttribPtr     = (EFI_FVB_ATTRIBUTES_2 *) & (FwhInstance->VolumeHeader.Attributes);
    515   ASSERT (AttribPtr != NULL);
    516 
    517   if ( AttribPtr != NULL) {
    518     OldAttributes = *AttribPtr;
    519   }
    520 
    521   Capabilities  = OldAttributes & EFI_FVB2_CAPABILITIES;
    522   OldStatus     = OldAttributes & EFI_FVB2_STATUS;
    523   NewStatus     = *Attributes & EFI_FVB2_STATUS;
    524 
    525   UnchangedAttributes = EFI_FVB2_READ_DISABLED_CAP  | \
    526                         EFI_FVB2_READ_ENABLED_CAP   | \
    527                         EFI_FVB2_WRITE_DISABLED_CAP | \
    528                         EFI_FVB2_WRITE_ENABLED_CAP  | \
    529                         EFI_FVB2_LOCK_CAP           | \
    530                         EFI_FVB2_STICKY_WRITE       | \
    531                         EFI_FVB2_MEMORY_MAPPED      | \
    532                         EFI_FVB2_ERASE_POLARITY     | \
    533                         EFI_FVB2_READ_LOCK_CAP      | \
    534                         EFI_FVB2_WRITE_LOCK_CAP     | \
    535                         EFI_FVB2_ALIGNMENT;
    536 
    537   //
    538   // Some attributes of FV is read only can *not* be set.
    539   //
    540   if ((OldAttributes & UnchangedAttributes) ^ (*Attributes & UnchangedAttributes)) {
    541     return EFI_INVALID_PARAMETER;
    542   }
    543 
    544   //
    545   // If firmware volume is locked, no status bit can be updated.
    546   //
    547   if ( OldAttributes & EFI_FVB2_LOCK_STATUS ) {
    548     if ( OldStatus ^ NewStatus ) {
    549       return EFI_ACCESS_DENIED;
    550     }
    551   }
    552 
    553   //
    554   // Test read disable.
    555   //
    556   if ((Capabilities & EFI_FVB2_READ_DISABLED_CAP) == 0) {
    557     if ((NewStatus & EFI_FVB2_READ_STATUS) == 0) {
    558       return EFI_INVALID_PARAMETER;
    559     }
    560   }
    561 
    562   //
    563   // Test read enable.
    564   //
    565   if ((Capabilities & EFI_FVB2_READ_ENABLED_CAP) == 0) {
    566     if (NewStatus & EFI_FVB2_READ_STATUS) {
    567       return EFI_INVALID_PARAMETER;
    568     }
    569   }
    570 
    571   //
    572   // Test write disable.
    573   //
    574   if ((Capabilities & EFI_FVB2_WRITE_DISABLED_CAP) == 0) {
    575     if ((NewStatus & EFI_FVB2_WRITE_STATUS) == 0) {
    576       return EFI_INVALID_PARAMETER;
    577     }
    578   }
    579 
    580   //
    581   // Test write enable.
    582   //
    583   if ((Capabilities & EFI_FVB2_WRITE_ENABLED_CAP) == 0) {
    584     if (NewStatus & EFI_FVB2_WRITE_STATUS) {
    585       return EFI_INVALID_PARAMETER;
    586     }
    587   }
    588 
    589   //
    590   // Test lock.
    591   //
    592   if ((Capabilities & EFI_FVB2_LOCK_CAP) == 0) {
    593     if (NewStatus & EFI_FVB2_LOCK_STATUS) {
    594       return EFI_INVALID_PARAMETER;
    595     }
    596   }
    597 
    598   *AttribPtr  = (*AttribPtr) & (0xFFFFFFFF & (~EFI_FVB2_STATUS));
    599   *AttribPtr  = (*AttribPtr) | NewStatus;
    600   *Attributes = *AttribPtr;
    601 
    602   return EFI_SUCCESS;
    603 }
    604 
    605 //
    606 // FVB protocol APIs.
    607 //
    608 /**
    609   Retrieves the physical address of the device.
    610 
    611   @param[in]  This    A pointer to EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL.
    612   @param[out] Address Output buffer containing the address.
    613 
    614   retval      EFI_SUCCESS The function always return successfully.
    615 
    616 **/
    617 EFI_STATUS
    618 EFIAPI
    619 FvbProtocolGetPhysicalAddress (
    620   IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL  *This,
    621   OUT EFI_PHYSICAL_ADDRESS               *Address
    622   )
    623 {
    624   EFI_FW_VOL_BLOCK_DEVICE               *FvbDevice;
    625   EFI_FW_VOL_INSTANCE                   *FvInstance;
    626 
    627   FvbDevice = FVB_DEVICE_FROM_THIS (This);
    628   FvInstance = GetFvbInstance(FvbDevice->Instance);
    629 
    630   if (FvInstance != NULL) {
    631     *Address = FvInstance->FvBase;
    632   }
    633 
    634   return EFI_SUCCESS;
    635 }
    636 
    637 
    638 /**
    639   Retrieve the size of a logical block.
    640 
    641   @param[in]  This         Calling context.
    642   @param[in]  Lba          Indicates which block to return the size for.
    643   @param[out] BlockSize    A pointer to a caller allocated UINTN in which
    644                            the size of the block is returned.
    645   @param[out] NumOfBlocks  A pointer to a caller allocated UINTN in which the
    646                            number of consecutive blocks starting with Lba is
    647                            returned. All blocks in this range have a size of
    648                            BlockSize.
    649 
    650   @retval     EFI_SUCCESS  The function always return successfully.
    651 
    652 **/
    653 EFI_STATUS
    654 EFIAPI
    655 FvbProtocolGetBlockSize (
    656   IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL  *This,
    657   IN  EFI_LBA                            Lba,
    658   OUT UINTN                              *BlockSize,
    659   OUT UINTN                              *NumOfBlocks
    660   )
    661 {
    662   EFI_FW_VOL_BLOCK_DEVICE                 *FvbDevice;
    663 
    664   DEBUG((EFI_D_INFO,
    665     "FvbProtocolGetBlockSize: Lba: 0x%lx BlockSize: 0x%x NumOfBlocks: 0x%x\n",
    666     Lba,
    667     BlockSize,
    668     NumOfBlocks)
    669     );
    670 
    671   FvbDevice = FVB_DEVICE_FROM_THIS (This);
    672 
    673   return FvbGetLbaAddress (
    674            FvbDevice->Instance,
    675            Lba,
    676            NULL,
    677            BlockSize,
    678            NumOfBlocks
    679            );
    680 }
    681 
    682 
    683 /**
    684   Retrieves Volume attributes.  No polarity translations are done.
    685 
    686   @param[in]    This         Calling context.
    687   @param[out]   Attributes   Output buffer which contains attributes.
    688 
    689   @retval       EFI_SUCCESS  The function always return successfully.
    690 
    691 **/
    692 EFI_STATUS
    693 EFIAPI
    694 FvbProtocolGetAttributes (
    695   IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL   *This,
    696   OUT EFI_FVB_ATTRIBUTES_2                *Attributes
    697   )
    698 {
    699   EFI_FW_VOL_BLOCK_DEVICE               *FvbDevice;
    700 
    701   FvbDevice = FVB_DEVICE_FROM_THIS (This);
    702 
    703   *Attributes = FvbGetVolumeAttributes (FvbDevice->Instance);
    704 
    705   DEBUG ((EFI_D_INFO,
    706     "FvbProtocolGetAttributes: This: 0x%x Attributes: 0x%x\n",
    707     This,
    708     *Attributes)
    709     );
    710 
    711   return EFI_SUCCESS;
    712 }
    713 
    714 
    715 /**
    716   Sets Volume attributes. No polarity translations are done.
    717 
    718   @param[in]  This         Calling context.
    719   @param[out] Attributes   Output buffer which contains attributes.
    720 
    721   @retval     EFI_SUCCESS  The function always return successfully.
    722 
    723 **/
    724 EFI_STATUS
    725 EFIAPI
    726 FvbProtocolSetAttributes (
    727   IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL   *This,
    728   IN OUT EFI_FVB_ATTRIBUTES_2             *Attributes
    729   )
    730 {
    731   EFI_STATUS                            Status;
    732   EFI_FW_VOL_BLOCK_DEVICE               *FvbDevice;
    733 
    734   DEBUG((EFI_D_INFO,
    735     "FvbProtocolSetAttributes: Before SET -  This: 0x%x Attributes: 0x%x\n",
    736     This,
    737     *Attributes)
    738     );
    739 
    740   FvbDevice = FVB_DEVICE_FROM_THIS (This);
    741 
    742   Status = FvbSetVolumeAttributes (FvbDevice->Instance, Attributes);
    743 
    744   DEBUG((EFI_D_INFO,
    745     "FvbProtocolSetAttributes: After SET -  This: 0x%x Attributes: 0x%x\n",
    746     This,
    747     *Attributes)
    748     );
    749 
    750   return Status;
    751 }
    752 
    753 
    754 /**
    755   The EraseBlock() function erases one or more blocks as denoted by the
    756   variable argument list. The entire parameter list of blocks must be verified
    757   prior to erasing any blocks.  If a block is requested that does not exist
    758   within the associated firmware volume (it has a larger index than the last
    759   block of the firmware volume), the EraseBlock() function must return
    760   EFI_INVALID_PARAMETER without modifying the contents of the firmware volume.
    761 
    762   @param[in] This            Calling context.
    763   @param[in] ...             Starting LBA followed by Number of Lba to erase.
    764                              a -1 to terminate the list.
    765 
    766   @retval EFI_SUCCESS        The erase request was successfully completed.
    767   @retval EFI_ACCESS_DENIED  The firmware volume is in the WriteDisabled state.
    768   @retval EFI_DEVICE_ERROR   The block device is not functioning correctly and
    769                              could not be written. Firmware device may have been
    770                              partially erased.
    771 
    772 **/
    773 EFI_STATUS
    774 EFIAPI
    775 FvbProtocolEraseBlocks (
    776   IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL    *This,
    777   ...
    778   )
    779 {
    780   EFI_FW_VOL_BLOCK_DEVICE               *FvbDevice;
    781   EFI_FW_VOL_INSTANCE                   *FwhInstance;
    782   UINTN                                 NumOfBlocks = 0;
    783   VA_LIST                               args;
    784   EFI_LBA                               StartingLba;
    785   UINTN                                 NumOfLba;
    786   EFI_STATUS                            Status;
    787 
    788   DEBUG((EFI_D_INFO, "FvbProtocolEraseBlocks: \n"));
    789   FvbDevice = FVB_DEVICE_FROM_THIS (This);
    790 
    791   FwhInstance  = GetFvbInstance (FvbDevice->Instance);
    792 
    793   if (FwhInstance != NULL) {
    794     NumOfBlocks = FwhInstance->NumOfBlocks;
    795   }
    796 
    797   VA_START (args, This);
    798 
    799   do {
    800     StartingLba = VA_ARG (args, EFI_LBA);
    801     if ( StartingLba == EFI_LBA_LIST_TERMINATOR ) {
    802       break;
    803     }
    804 
    805     NumOfLba = VA_ARG (args, UINT32);
    806 
    807     //
    808     // Check input parameters.
    809     //
    810     if (NumOfLba == 0) {
    811       VA_END (args);
    812       return EFI_INVALID_PARAMETER;
    813     }
    814 
    815     if ( ( StartingLba + NumOfLba ) > NumOfBlocks ) {
    816       return EFI_INVALID_PARAMETER;
    817     }
    818   } while ( 1 );
    819 
    820   VA_END (args);
    821 
    822   VA_START (args, This);
    823   do {
    824     StartingLba = VA_ARG (args, EFI_LBA);
    825     if (StartingLba == EFI_LBA_LIST_TERMINATOR) {
    826       break;
    827     }
    828 
    829     NumOfLba = VA_ARG (args, UINT32);
    830 
    831     while ( NumOfLba > 0 ) {
    832       Status = FvbEraseBlock (FvbDevice->Instance, StartingLba);
    833       if ( EFI_ERROR(Status)) {
    834         VA_END (args);
    835         return Status;
    836       }
    837       StartingLba ++;
    838       NumOfLba --;
    839     }
    840 
    841   } while ( 1 );
    842 
    843   VA_END (args);
    844 
    845   return EFI_SUCCESS;
    846 }
    847 
    848 
    849 /**
    850   Writes data beginning at Lba:Offset from FV. The write terminates either
    851   when *NumBytes of data have been written, or when a block boundary is
    852   reached.  *NumBytes is updated to reflect the actual number of bytes
    853   written. The write opertion does not include erase. This routine will
    854   attempt to write only the specified bytes. If the writes do not stick,
    855   it will return an error.
    856 
    857   @param[in]      This      Calling context.
    858   @param[in]      Lba       Block in which to begin write.
    859   @param[in]      Offset    Offset in the block at which to begin write.
    860   @param[in,out]  NumBytes  On input, indicates the requested write size. On
    861                             output, indicates the actual number of bytes written
    862   @param[in]      Buffer    Buffer containing source data for the write.
    863 
    864   @retval EFI_SUCCESS           The firmware volume was written successfully.
    865   @retval EFI_BAD_BUFFER_SIZE   Write attempted across a LBA boundary. On output,
    866                                 NumBytes contains the total number of bytes
    867                                 actually written.
    868   @retval EFI_ACCESS_DENIED     The firmware volume is in the WriteDisabled state.
    869   @retval EFI_DEVICE_ERROR      The block device is not functioning correctly and
    870                                 could not be written.
    871   @retval EFI_INVALID_PARAMETER NumBytes or Buffer are NULL.
    872 
    873 **/
    874 EFI_STATUS
    875 EFIAPI
    876 FvbProtocolWrite (
    877   IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL   *This,
    878   IN EFI_LBA                              Lba,
    879   IN UINTN                                Offset,
    880   IN OUT UINTN                            *NumBytes,
    881   IN UINT8                                *Buffer
    882   )
    883 {
    884 
    885   EFI_FW_VOL_BLOCK_DEVICE               *FvbDevice;
    886 
    887   FvbDevice = FVB_DEVICE_FROM_THIS (This);
    888 
    889   DEBUG((EFI_D_INFO,
    890     "FvbProtocolWrite: Lba: 0x%lx Offset: 0x%x NumBytes: 0x%x, Buffer: 0x%x\n",
    891     Lba,
    892     Offset,
    893     *NumBytes,
    894     Buffer)
    895     );
    896 
    897   return FvbWriteBlock (FvbDevice->Instance, Lba, Offset, NumBytes, Buffer);
    898 }
    899 
    900 
    901 /**
    902   Reads data beginning at Lba:Offset from FV. The Read terminates either
    903   when *NumBytes of data have been read, or when a block boundary is
    904   reached.  *NumBytes is updated to reflect the actual number of bytes
    905   written. The write opertion does not include erase. This routine will
    906   attempt to write only the specified bytes. If the writes do not stick,
    907   it will return an error.
    908 
    909   @param[in]      This      Calling context.
    910   @param[in]      Lba       Block in which to begin write.
    911   @param[in]      Offset    Offset in the block at which to begin write
    912   @param[in,out]  NumBytes  On input, indicates the requested write size. On
    913                             output, indicates the actual number of bytes written.
    914   @param[in]      Buffer    Buffer containing source data for the write.
    915 
    916 
    917 Returns:
    918   @retval EFI_SUCCESS            The firmware volume was read successfully and
    919                                  contents are in Buffer.
    920   @retval EFI_BAD_BUFFER_SIZE    Read attempted across a LBA boundary. On output,
    921                                  NumBytes contains the total number of bytes returned
    922                                  in Buffer.
    923   @retval EFI_ACCESS_DENIED      The firmware volume is in the ReadDisabled state
    924   @retval EFI_DEVICE_ERROR       The block device is not functioning correctly and
    925                                  could not be read.
    926   @retval EFI_INVALID_PARAMETER  NumBytes or Buffer are NULL.
    927 
    928 **/
    929 EFI_STATUS
    930 EFIAPI
    931 FvbProtocolRead (
    932   IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL   *This,
    933   IN EFI_LBA                              Lba,
    934   IN UINTN                                Offset,
    935   IN OUT UINTN                            *NumBytes,
    936   OUT UINT8                                *Buffer
    937   )
    938 {
    939 
    940   EFI_FW_VOL_BLOCK_DEVICE   *FvbDevice;
    941   EFI_STATUS                Status;
    942 
    943   FvbDevice = FVB_DEVICE_FROM_THIS (This);
    944   Status = FvbReadBlock (FvbDevice->Instance, Lba, Offset, NumBytes, Buffer);
    945   DEBUG((EFI_D_INFO,
    946     "FvbProtocolRead: Lba: 0x%lx Offset: 0x%x NumBytes: 0x%x, Buffer: 0x%x\n",
    947     Lba,
    948     Offset,
    949     *NumBytes,
    950     Buffer)
    951     );
    952 
    953   return Status;
    954 }
    955 
    956 
    957 /**
    958   Check the integrity of firmware volume header.
    959 
    960   @param[in]  FwVolHeader   A pointer to a firmware volume header.
    961 
    962   @retval     TRUE          The firmware volume is consistent.
    963   @retval     FALSE         The firmware volume has corrupted.
    964 
    965 **/
    966 BOOLEAN
    967 IsFvHeaderValid (
    968   IN       EFI_PHYSICAL_ADDRESS          FvBase,
    969   IN CONST EFI_FIRMWARE_VOLUME_HEADER    *FwVolHeader
    970   )
    971 {
    972   if (FvBase == PcdGet32(PcdFlashNvStorageVariableBase)) {
    973     if (CompareMem (&FwVolHeader->FileSystemGuid, &gEfiSystemNvDataFvGuid, sizeof(EFI_GUID)) != 0 ) {
    974       return FALSE;
    975     }
    976   } else {
    977     if (CompareMem (&FwVolHeader->FileSystemGuid, &gEfiFirmwareFileSystem2Guid, sizeof(EFI_GUID)) != 0 ) {
    978       return FALSE;
    979     }
    980   }
    981   if ( (FwVolHeader->Revision != EFI_FVH_REVISION)   ||
    982        (FwVolHeader->Signature != EFI_FVH_SIGNATURE) ||
    983        (FwVolHeader->FvLength == ((UINTN) -1))       ||
    984        ((FwVolHeader->HeaderLength & 0x01 ) !=0) ) {
    985     return FALSE;
    986   }
    987 
    988   if (CalculateCheckSum16 ((UINT16 *) FwVolHeader, FwVolHeader->HeaderLength) != 0) {
    989     return FALSE;
    990   }
    991 
    992   return TRUE;
    993 }
    994 
    995 
    996 /**
    997   The function does the necessary initialization work for
    998   Firmware Volume Block Driver.
    999 
   1000   @retval     EFI_SUCCESS       This funtion always return EFI_SUCCESS.
   1001                                 It will ASSERT on errors.
   1002 
   1003 **/
   1004 EFI_STATUS
   1005 FvbInitialize (
   1006   VOID
   1007   )
   1008 {
   1009   EFI_FW_VOL_INSTANCE                   *FwhInstance;
   1010   EFI_FIRMWARE_VOLUME_HEADER            *FwVolHeader;
   1011   EFI_FIRMWARE_VOLUME_HEADER            *FvHeader;
   1012   EFI_FV_BLOCK_MAP_ENTRY                *PtrBlockMapEntry;
   1013   EFI_PHYSICAL_ADDRESS                  BaseAddress;
   1014   EFI_STATUS                            Status;
   1015   UINTN                                 BufferSize;
   1016   UINTN                                 TmpHeaderLength;
   1017   UINTN                                 Idx;
   1018   UINT32                                MaxLbaSize;
   1019 
   1020   //
   1021   // Calculate the total size for all firmware volume block instances.
   1022   //
   1023   BufferSize = 0;
   1024   for (Idx = 0; Idx < 1; Idx++) {
   1025     FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) mPlatformFvBaseAddress[Idx];
   1026     BufferSize +=  (FvHeader->HeaderLength +
   1027                     sizeof (EFI_FW_VOL_INSTANCE) -
   1028                     sizeof (EFI_FIRMWARE_VOLUME_HEADER)
   1029                    );
   1030   }
   1031 
   1032   mFvbModuleGlobal.FvInstance =  (EFI_FW_VOL_INSTANCE *) AllocateRuntimeZeroPool (BufferSize);
   1033   ASSERT (NULL != mFvbModuleGlobal.FvInstance);
   1034 
   1035 
   1036   MaxLbaSize      = 0;
   1037   FwhInstance     = mFvbModuleGlobal.FvInstance;
   1038   mFvbModuleGlobal.NumFv   = 0;
   1039 
   1040   for (Idx = 0; Idx < 1; Idx++) {
   1041     BaseAddress = mPlatformFvBaseAddress[Idx];
   1042     FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) BaseAddress;
   1043 
   1044     if (!IsFvHeaderValid (BaseAddress, FwVolHeader)) {
   1045       //
   1046       // If not valid, get FvbInfo from the information carried in
   1047       // FVB driver.
   1048       //
   1049       DEBUG ((EFI_D_ERROR, "Fvb: FV header @ 0x%lx invalid\n", BaseAddress));
   1050       Status          = GetFvbInfo (BaseAddress, &FwVolHeader);
   1051       ASSERT_EFI_ERROR(Status);
   1052       //
   1053       //  Write back a healthy FV header.
   1054       //
   1055       DEBUG ((EFI_D_ERROR, "FwBlockService.c: Writing back healthy FV header\n"));
   1056       LibFvbFlashDeviceBlockLock ((UINTN)BaseAddress, FwVolHeader->BlockMap->Length, FALSE);
   1057 
   1058       Status = LibFvbFlashDeviceBlockErase ((UINTN)BaseAddress, FwVolHeader->BlockMap->Length);
   1059 
   1060       TmpHeaderLength = (UINTN) FwVolHeader->HeaderLength;
   1061       Status = LibFvbFlashDeviceWrite (
   1062                  (UINTN)BaseAddress,
   1063                  &TmpHeaderLength,
   1064                  (UINT8 *) FwVolHeader
   1065                  );
   1066 
   1067       LibFvbFlashDeviceBlockLock ((UINTN)BaseAddress, FwVolHeader->BlockMap->Length, TRUE);
   1068 
   1069       WriteBackInvalidateDataCacheRange (
   1070         (VOID *) (UINTN) BaseAddress,
   1071         FwVolHeader->BlockMap->Length
   1072         );
   1073 
   1074     }
   1075 
   1076     CopyMem (&(FwhInstance->VolumeHeader), FwVolHeader, FwVolHeader->HeaderLength);
   1077 
   1078     FwVolHeader = &(FwhInstance->VolumeHeader);
   1079     FwhInstance->FvBase = (UINTN)BaseAddress;
   1080 
   1081     //
   1082     // Process the block map for each FV.
   1083     //
   1084     FwhInstance->NumOfBlocks = 0;
   1085     for (PtrBlockMapEntry = FwVolHeader->BlockMap; PtrBlockMapEntry->NumBlocks != 0; PtrBlockMapEntry++) {
   1086       //
   1087       // Get the maximum size of a block.
   1088       //
   1089       if (MaxLbaSize < PtrBlockMapEntry->Length) {
   1090         MaxLbaSize  = PtrBlockMapEntry->Length;
   1091       }
   1092       FwhInstance->NumOfBlocks += PtrBlockMapEntry->NumBlocks;
   1093     }
   1094 
   1095     //
   1096     // Add a FVB Protocol Instance.
   1097     //
   1098     mFvbModuleGlobal.NumFv++;
   1099     InstallFvbProtocol (FwhInstance, mFvbModuleGlobal.NumFv - 1);
   1100 
   1101     //
   1102     // Move on to the next FwhInstance.
   1103     //
   1104     FwhInstance = (EFI_FW_VOL_INSTANCE *) ((UINTN)((UINT8 *)FwhInstance) +
   1105                                           FwVolHeader->HeaderLength +
   1106                                           (sizeof (EFI_FW_VOL_INSTANCE) - sizeof (EFI_FIRMWARE_VOLUME_HEADER)));
   1107 
   1108   }
   1109 
   1110   return EFI_SUCCESS;
   1111 }
   1112 
   1113