Home | History | Annotate | Download | only in UpdateDriverDxe
      1 /** @file
      2   Functions in this file will program the image into flash area.
      3 
      4   Copyright (c) 2002 - 2010, Intel Corporation. All rights reserved.<BR>
      5 
      6   This program and the accompanying materials
      7   are licensed and made available under the terms and conditions
      8   of the BSD License which accompanies this distribution.  The
      9   full text of the license may be found at
     10   http://opensource.org/licenses/bsd-license.php
     11 
     12   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     13   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     14 
     15 **/
     16 
     17 #include "UpdateDriver.h"
     18 
     19 /**
     20   Write a block size data into flash.
     21 
     22   @param FvbProtocol     Pointer to FVB protocol.
     23   @param Lba             Logic block index to be updated.
     24   @param BlockSize       Block size
     25   @param Buffer          Buffer data to be written.
     26 
     27   @retval EFI_SUCCESS   Write data successfully.
     28   @retval other errors  Write data failed.
     29 
     30 **/
     31 EFI_STATUS
     32 UpdateOneBlock (
     33   IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvbProtocol,
     34   IN EFI_LBA                            Lba,
     35   IN UINTN                              BlockSize,
     36   IN UINT8                              *Buffer
     37   )
     38 {
     39   EFI_STATUS                            Status;
     40   UINTN                                 Size;
     41 
     42   //
     43   // First erase the block
     44   //
     45   Status                = FvbProtocol->EraseBlocks (
     46                                          FvbProtocol,
     47                                          Lba,                        // Lba
     48                                          1,                          // NumOfBlocks
     49                                          EFI_LBA_LIST_TERMINATOR
     50                                          );
     51   if (EFI_ERROR (Status)) {
     52     return Status;
     53   }
     54 
     55   //
     56   // Write the block
     57   //
     58   Size                  = BlockSize;
     59   Status                = FvbProtocol->Write (
     60                                          FvbProtocol,
     61                                          Lba,                        // Lba
     62                                          0,                          // Offset
     63                                          &Size,                      // Size
     64                                          Buffer                      // Buffer
     65                                          );
     66   if ((EFI_ERROR (Status)) || (Size != BlockSize)) {
     67     return Status;
     68   }
     69 
     70   return EFI_SUCCESS;
     71 }
     72 
     73 /**
     74   Write buffer data in a flash block.
     75 
     76   @param FvbProtocol     Pointer to FVB protocol.
     77   @param Lba             Logic block index to be updated.
     78   @param Offset          The offset within the block.
     79   @param Length          Size of buffer to be updated.
     80   @param BlockSize       Block size.
     81   @param Buffer          Buffer data to be updated.
     82 
     83   @retval EFI_SUCCESS   Write data successfully.
     84   @retval other errors  Write data failed.
     85 
     86 **/
     87 EFI_STATUS
     88 UpdateBufferInOneBlock (
     89   IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvbProtocol,
     90   IN EFI_LBA                            Lba,
     91   IN UINTN                              Offset,
     92   IN UINTN                              Length,
     93   IN UINTN                              BlockSize,
     94   IN UINT8                              *Buffer
     95   )
     96 {
     97   EFI_STATUS                            Status;
     98   UINTN                                 Size;
     99   UINT8                                 *ReservedBuffer;
    100 
    101   //
    102   // If we are going to update a whole block
    103   //
    104   if ((Offset == 0) && (Length == BlockSize)) {
    105     Status              = UpdateOneBlock (
    106                             FvbProtocol,
    107                             Lba,
    108                             BlockSize,
    109                             Buffer
    110                             );
    111     return Status;
    112   }
    113 
    114   //
    115   // If it is not a full block update, we need to coalesce data in
    116   // the block that is not going to be updated and new data together.
    117   //
    118 
    119   //
    120   // Allocate a reserved buffer to make up the final buffer for update
    121   //
    122   ReservedBuffer        = NULL;
    123   ReservedBuffer = AllocatePool (BlockSize);
    124   if (ReservedBuffer == NULL) {
    125     return EFI_OUT_OF_RESOURCES;
    126   }
    127   //
    128   // First get the original content of the block
    129   //
    130   Size                  = BlockSize;
    131   Status                = FvbProtocol->Read (
    132                                          FvbProtocol,
    133                                          Lba,
    134                                          0,
    135                                          &Size,
    136                                          ReservedBuffer
    137                                          );
    138   if ((EFI_ERROR (Status)) || (Size != BlockSize)) {
    139     FreePool (ReservedBuffer);
    140     return Status;
    141   }
    142 
    143   //
    144   // Overwrite the reserved buffer with new content
    145   //
    146   CopyMem (ReservedBuffer + Offset, Buffer, Length);
    147 
    148   Status                = UpdateOneBlock (
    149                             FvbProtocol,
    150                             Lba,
    151                             BlockSize,
    152                             ReservedBuffer
    153                             );
    154 
    155   FreePool (ReservedBuffer);
    156 
    157   return Status;
    158 }
    159 
    160 /**
    161   Get the last write log, and check the status of last write.
    162   If not complete, restart will be taken.
    163 
    164   @param FvbHandle       Handle of FVB protocol.
    165   @param FtwProtocol     FTW protocol instance.
    166   @param ConfigData      Config data on updating driver.
    167   @param PrivateDataSize bytes from the private data
    168                          stored for this write.
    169   @param PrivateData     A pointer to a buffer. The function will copy.
    170   @param Lba             The logical block address of the last write.
    171   @param Offset          The offset within the block of the last write.
    172   @param Length          The length of the last write.
    173   @param Pending         A Boolean value with TRUE indicating
    174                          that the write was completed.
    175 
    176   @retval EFI_OUT_OF_RESOURCES  No enough memory is allocated.
    177   @retval EFI_ABORTED           The FTW work space is damaged.
    178   @retval EFI_NOT_FOUND         The last write is not done by this driver.
    179   @retval EFI_SUCCESS           Last write log is got.
    180 
    181 **/
    182 EFI_STATUS
    183 RetrieveLastWrite (
    184   IN EFI_HANDLE                         FvbHandle,
    185   IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL  *FtwProtocol,
    186   IN UPDATE_CONFIG_DATA                 *ConfigData,
    187   IN UINTN                              PrivateDataSize,
    188   IN OUT UPDATE_PRIVATE_DATA            *PrivateData,
    189   IN OUT EFI_LBA                        *Lba,
    190   IN OUT UINTN                          *Offset,
    191   IN OUT UINTN                          *Length,
    192   IN OUT BOOLEAN                        *Pending
    193   )
    194 {
    195   EFI_STATUS                            Status;
    196   EFI_GUID                              CallerId;
    197   UINTN                                 PrivateBufferSize;
    198   BOOLEAN                               Complete;
    199   VOID                                  *PrivateDataBuffer;
    200 
    201   //
    202   // Get the last write
    203   //
    204   *Pending              = FALSE;
    205   PrivateBufferSize     = PrivateDataSize;
    206   PrivateDataBuffer     = NULL;
    207   Status                = FtwProtocol->GetLastWrite (
    208                                          FtwProtocol,
    209                                          &CallerId,
    210                                          Lba,
    211                                          Offset,
    212                                          Length,
    213                                          &PrivateBufferSize,
    214                                          PrivateData,
    215                                          &Complete
    216                                          );
    217   if (EFI_ERROR (Status)) {
    218     //
    219     // If there is no incompleted record, return success.
    220     //
    221     if ((Status == EFI_NOT_FOUND) && Complete) {
    222       return EFI_SUCCESS;
    223     } else if (Status == EFI_BUFFER_TOO_SMALL) {
    224       //
    225       // If buffer too small, reallocate buffer and call getlastwrite again
    226       //
    227       PrivateDataBuffer = AllocatePool (PrivateBufferSize);
    228 
    229       if (PrivateDataBuffer == NULL) {
    230         return EFI_OUT_OF_RESOURCES;
    231       }
    232 
    233       Status            = FtwProtocol->GetLastWrite (
    234                                          FtwProtocol,
    235                                          &CallerId,
    236                                          Lba,
    237                                          Offset,
    238                                          Length,
    239                                          &PrivateBufferSize,
    240                                          PrivateDataBuffer,
    241                                          &Complete
    242                                          );
    243       if (EFI_ERROR (Status)) {
    244         FreePool ( PrivateDataBuffer);
    245         return EFI_ABORTED;
    246       } else {
    247         CopyMem (PrivateData, PrivateDataBuffer, PrivateDataSize);
    248         FreePool (PrivateDataBuffer);
    249         PrivateDataBuffer = NULL;
    250       }
    251     } else {
    252       return EFI_ABORTED;
    253     }
    254   }
    255 
    256   *Pending              = TRUE;
    257 
    258   //
    259   // If the caller is not the update driver, then return.
    260   // The update driver cannot continue to perform the update
    261   //
    262   if (CompareMem (&CallerId, &gEfiCallerIdGuid, sizeof (EFI_GUID)) != 0) {
    263     return EFI_NOT_FOUND;
    264   }
    265 
    266   //
    267   // Check the private data and see if it is the one I need.
    268   //
    269   if (CompareMem (&(PrivateData->FileGuid), &(ConfigData->FileGuid), sizeof(EFI_GUID)) != 0) {
    270     return EFI_NOT_FOUND;
    271   }
    272 
    273   //
    274   // If the caller is the update driver and complete is not true, then restart().
    275   //
    276   if (!Complete) {
    277     //
    278     //  Re-start the update
    279     //
    280     Status              = FtwProtocol->Restart (
    281                                          FtwProtocol,
    282                                          FvbHandle
    283                                          );
    284     //
    285     // If restart() error, then abort().
    286     //
    287     if (EFI_ERROR (Status)) {
    288       FtwProtocol->Abort (FtwProtocol);
    289       //
    290       // Now set Pending as FALSE as this record has been cleared
    291       //
    292       *Pending          = FALSE;
    293       return EFI_SUCCESS;
    294     }
    295 
    296   }
    297 
    298   return Status;
    299 }
    300 
    301 /**
    302   Update the whole FV image in fault tolerant write method.
    303 
    304   @param FvbHandle       Handle of FVB protocol for the updated flash range.
    305   @param FvbProtocol     FVB protocol.
    306   @param BlockMap        Block array to specify flash area.
    307   @param ConfigData      Config data on updating driver.
    308   @param ImageBuffer     Image buffer to be updated.
    309   @param ImageSize       Image size.
    310 
    311   @retval EFI_SUCCESS            FV image is writed into flash.
    312   @retval EFI_INVALID_PARAMETER  Config data is not valid.
    313   @retval EFI_NOT_FOUND          FTW protocol doesn't exist.
    314   @retval EFI_OUT_OF_RESOURCES   No enough backup space.
    315   @retval EFI_ABORTED            Error happen when update FV.
    316 
    317 **/
    318 EFI_STATUS
    319 FaultTolerantUpdateOnWholeFv (
    320   IN EFI_HANDLE                         FvbHandle,
    321   IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvbProtocol,
    322   IN EFI_FV_BLOCK_MAP_ENTRY             *BlockMap,
    323   IN UPDATE_CONFIG_DATA                 *ConfigData,
    324   IN UINT8                              *ImageBuffer,
    325   IN UINTN                              ImageSize
    326   )
    327 {
    328   EFI_STATUS                            Status;
    329   EFI_FAULT_TOLERANT_WRITE_PROTOCOL     *FtwProtocol;
    330   UINTN                                 MaxBlockSize;
    331   UINTN                                 FtwMaxBlockSize;
    332   BOOLEAN                               Pending;
    333   UPDATE_PRIVATE_DATA                   PrivateData;
    334   EFI_LBA                               PendingLba;
    335   EFI_LBA                               Lba;
    336   UINTN                                 PendingOffset;
    337   UINTN                                 Offset;
    338   UINTN                                 PendingLength;
    339   UINTN                                 Length;
    340   EFI_FV_BLOCK_MAP_ENTRY                *PtrMap;
    341   UINTN                                 NumOfBlocks;
    342   UINTN                                 Index;
    343   UINT8                                 *UpdateBuffer;
    344 
    345   if ((ConfigData->UpdateType != UpdateWholeFV)
    346     || (!ConfigData->FaultTolerant)) {
    347     return EFI_INVALID_PARAMETER;
    348   }
    349 
    350   //
    351   // Get the FTW protocol
    352   //
    353   Status                = gBS->LocateProtocol (
    354                                  &gEfiFaultTolerantWriteProtocolGuid,
    355                                  NULL,
    356                                  (VOID **) &FtwProtocol
    357                                  );
    358   if (EFI_ERROR (Status)) {
    359     return EFI_NOT_FOUND;
    360   }
    361 
    362   //
    363   // Get the maximum block size of the FV, and number of blocks
    364   // NumOfBlocks will be the NumOfUdpates.
    365   //
    366   MaxBlockSize          = 0;
    367   NumOfBlocks           = 0;
    368   PtrMap                = BlockMap;
    369   while (TRUE) {
    370     if ((PtrMap->NumBlocks == 0) || (PtrMap->Length == 0)) {
    371       break;
    372     }
    373     if (MaxBlockSize < PtrMap->Length) {
    374       MaxBlockSize      = PtrMap->Length;
    375     }
    376     NumOfBlocks         = NumOfBlocks + PtrMap->NumBlocks;
    377     PtrMap++;
    378   }
    379 
    380   FtwProtocol->GetMaxBlockSize (FtwProtocol, &FtwMaxBlockSize);
    381   //
    382   // Not enough backup space. return directly
    383   //
    384   if (FtwMaxBlockSize < MaxBlockSize) {
    385     return EFI_OUT_OF_RESOURCES;
    386   }
    387 
    388   PendingLba            = 0;
    389   PendingOffset         = 0;
    390   PendingLength         = 0;
    391   Pending               = FALSE;
    392 
    393   //
    394   // Fault Tolerant Write can only support actual fault tolerance if the write
    395   // is a reclaim operation, which means the data buffer (new and old) are
    396   // acutally both stored in flash. But for component update write, the data
    397   // are now in memory. So we cannot actually recover the data after power
    398   // failure.
    399   //
    400   Status                = RetrieveLastWrite (
    401                             FvbHandle,
    402                             FtwProtocol,
    403                             ConfigData,
    404                             sizeof (UPDATE_PRIVATE_DATA),
    405                             &PrivateData,
    406                             &PendingLba,
    407                             &PendingOffset,
    408                             &PendingLength,
    409                             &Pending
    410                             );
    411 
    412   if (Pending && (Status == EFI_NOT_FOUND)) {
    413     //
    414     // Cannot continue with the write operation
    415     //
    416     return EFI_ABORTED;
    417   }
    418 
    419   if (EFI_ERROR(Status)) {
    420     return EFI_ABORTED;
    421   }
    422 
    423   //
    424   // Currently we start from the pending write if there is any. But as we
    425   // are going to update a whole FV, we can just abort last write and start
    426   // from the very begining.
    427   //
    428   if (!Pending) {
    429     //
    430     // Now allocte the update private data in FTW. If there is pending
    431     // write, it has already been allocated and no need to allocate here.
    432     //
    433     Status              = FtwProtocol->Allocate (
    434                                          FtwProtocol,
    435                                          &gEfiCallerIdGuid,
    436                                          sizeof (UPDATE_PRIVATE_DATA),
    437                                          NumOfBlocks
    438                                          );
    439     if (EFI_ERROR (Status)) {
    440       return Status;
    441     }
    442   }
    443 
    444   //
    445   // Perform the update now. If there are pending writes, we need to
    446   // start from the pending write instead of the very beginning.
    447   //
    448   PtrMap                = BlockMap;
    449   Lba                   = 0;
    450   Offset                = 0;
    451   UpdateBuffer          = ImageBuffer;
    452   CopyMem (
    453   	(VOID *) &PrivateData.FileGuid,
    454   	(VOID *) &ConfigData->FileGuid,
    455    	sizeof (EFI_GUID)
    456   );
    457 
    458   while (TRUE) {
    459     if ((PtrMap->NumBlocks == 0) || (PtrMap->Length == 0)) {
    460       break;
    461     }
    462     Length              = (UINTN)PtrMap->Length;
    463     for (Index = 0; Index < PtrMap->NumBlocks; Index++) {
    464 
    465       //
    466       // Add an extra check here to see if the pending record is correct
    467       //
    468       if (Pending && (Lba == PendingLba)) {
    469         if ((PendingOffset != Offset) || (PendingLength != Length)) {
    470           //
    471           // Error.
    472           //
    473           Status          = EFI_ABORTED;
    474           break;
    475         }
    476       }
    477 
    478       if ((!Pending) || (Lba >= PendingLba)) {
    479         Status            = FtwProtocol->Write (
    480                                            FtwProtocol,
    481                                            Lba,                  // Lba
    482                                            Offset,               // Offset
    483                                            Length,               // Size
    484                                            &PrivateData,         // Private Data
    485                                            FvbHandle,            // FVB handle
    486                                            UpdateBuffer          // Buffer
    487                                            );
    488       }
    489 
    490       if (EFI_ERROR (Status)) {
    491         break;
    492       }
    493       Lba++;
    494       UpdateBuffer      = (UINT8 *) ((UINTN)UpdateBuffer + Length);
    495     }
    496 
    497     if (EFI_ERROR (Status)) {
    498       break;
    499     }
    500     PtrMap++;
    501   }
    502 
    503   return Status;
    504 
    505 }
    506 
    507 /**
    508   Directly update the whole FV image without fault tolerant write method.
    509 
    510   @param FvbHandle       Handle of FVB protocol for the updated flash range.
    511   @param FvbProtocol     FVB protocol.
    512   @param BlockMap        Block array to specify flash area.
    513   @param ConfigData      Config data on updating driver.
    514   @param ImageBuffer     Image buffer to be updated.
    515   @param ImageSize       Image size.
    516 
    517   @retval EFI_SUCCESS            FV image is writed into flash.
    518   @retval EFI_INVALID_PARAMETER  Config data is not valid.
    519   @retval EFI_ABORTED            Error happen when update FV.
    520 
    521 **/
    522 EFI_STATUS
    523 NonFaultTolerantUpdateOnWholeFv (
    524   IN EFI_HANDLE                         FvbHandle,
    525   IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvbProtocol,
    526   IN EFI_FV_BLOCK_MAP_ENTRY             *BlockMap,
    527   IN UPDATE_CONFIG_DATA                 *ConfigData,
    528   IN UINT8                              *ImageBuffer,
    529   IN UINTN                              ImageSize
    530   )
    531 {
    532   EFI_STATUS                            Status;
    533   EFI_FV_BLOCK_MAP_ENTRY                *PtrMap;
    534   UINTN                                 Index;
    535   EFI_LBA                               UpdateLba;
    536   UINT8                                 *UpdateBuffer;
    537   UINTN                                 UpdateSize;
    538 
    539   if ((ConfigData->UpdateType != UpdateWholeFV )
    540     || (ConfigData->FaultTolerant)) {
    541     return EFI_INVALID_PARAMETER;
    542   }
    543 
    544   Status                = EFI_SUCCESS;
    545   PtrMap                = BlockMap;
    546   UpdateLba             = 0;
    547   UpdateBuffer          = ImageBuffer;
    548 
    549   //
    550   // Perform the update now
    551   //
    552   while (TRUE) {
    553     if ((PtrMap->NumBlocks == 0) || (PtrMap->Length == 0)) {
    554       break;
    555     }
    556     UpdateSize          = (UINTN)PtrMap->Length;
    557     for (Index = 0; Index < PtrMap->NumBlocks; Index++) {
    558       Status            = UpdateOneBlock (
    559                             FvbProtocol,
    560                             UpdateLba,
    561                             UpdateSize,
    562                             UpdateBuffer
    563                             );
    564       if (EFI_ERROR (Status)) {
    565         break;
    566       }
    567 
    568       UpdateLba++;
    569       UpdateBuffer      = (UINT8 *) ((UINTN)UpdateBuffer + UpdateSize);
    570     }
    571 
    572     if (EFI_ERROR (Status)) {
    573       break;
    574     }
    575     PtrMap++;
    576   }
    577 
    578   return Status;
    579 }
    580 
    581 /**
    582   Update the whole FV image, and reinsall FVB protocol for the updated FV image.
    583 
    584   @param FvbHandle       Handle of FVB protocol for the updated flash range.
    585   @param FvbProtocol     FVB protocol.
    586   @param ConfigData      Config data on updating driver.
    587   @param ImageBuffer     Image buffer to be updated.
    588   @param ImageSize       Image size.
    589 
    590   @retval EFI_INVALID_PARAMETER  Update type is not UpdateWholeFV.
    591                                  Or Image size is not same to the size of whole FV.
    592   @retval EFI_OUT_OF_RESOURCES   No enoug memory is allocated.
    593   @retval EFI_SUCCESS            FV image is updated, and its FVB protocol is reinstalled.
    594 
    595 **/
    596 EFI_STATUS
    597 PerformUpdateOnWholeFv (
    598   IN EFI_HANDLE                         FvbHandle,
    599   IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvbProtocol,
    600   IN UPDATE_CONFIG_DATA                 *ConfigData,
    601   IN UINT8                              *ImageBuffer,
    602   IN UINTN                              ImageSize
    603 )
    604 {
    605   EFI_STATUS                            Status;
    606   EFI_FIRMWARE_VOLUME_HEADER            *FwVolHeader;
    607   EFI_FV_BLOCK_MAP_ENTRY                *BlockMap;
    608   CHAR16                                *TmpStr;
    609 
    610   if (ConfigData->UpdateType != UpdateWholeFV) {
    611     return EFI_INVALID_PARAMETER;
    612   }
    613 
    614   //
    615   // Get the header of the firmware volume
    616   //
    617   FwVolHeader           = NULL;
    618   FwVolHeader = AllocatePool (((EFI_FIRMWARE_VOLUME_HEADER *) ((UINTN) (ConfigData->BaseAddress)))->HeaderLength);
    619   if (FwVolHeader == NULL) {
    620     return EFI_OUT_OF_RESOURCES;
    621   }
    622   CopyMem (
    623     FwVolHeader,
    624     (VOID *) ((UINTN) (ConfigData->BaseAddress)),
    625     ((EFI_FIRMWARE_VOLUME_HEADER *) ((UINTN) (ConfigData->BaseAddress)))->HeaderLength
    626     );
    627 
    628   //
    629   // Check if ImageSize is the same as the size of the whole FV
    630   //
    631   if ((UINT64)ImageSize != FwVolHeader->FvLength) {
    632     FreePool (FwVolHeader);
    633     return EFI_INVALID_PARAMETER;
    634   }
    635 
    636   //
    637   // Print on screen
    638   //
    639   TmpStr  = HiiGetString (gHiiHandle, STRING_TOKEN(UPDATE_FIRMWARE_VOLUME), NULL);
    640   if (TmpStr != NULL) {
    641     Print (TmpStr, ConfigData->BaseAddress, (FwVolHeader->FvLength + ConfigData->BaseAddress));
    642     FreePool (TmpStr);
    643   }
    644 
    645   DEBUG ((EFI_D_UPDATE, "UpdateDriver: updating whole FV from %08LX to %08LX\n",
    646     ConfigData->BaseAddress, (FwVolHeader->FvLength + ConfigData->BaseAddress)));
    647 
    648   //
    649   // Get the block map of the firmware volume
    650   //
    651   BlockMap              = &(FwVolHeader->BlockMap[0]);
    652 
    653   //
    654   // It is about the same if we are going to fault tolerantly update
    655   // a certain FV in our current design. But we divide non-fault tolerant
    656   // and fault tolerant udpate here for better maintenance as fault
    657   // tolerance may change and may be done more wisely if we have space.
    658   //
    659   if (ConfigData->FaultTolerant) {
    660     Status              = FaultTolerantUpdateOnWholeFv (
    661                             FvbHandle,
    662                             FvbProtocol,
    663                             BlockMap,
    664                             ConfigData,
    665                             ImageBuffer,
    666                             ImageSize
    667                             );
    668   } else {
    669     Status              = NonFaultTolerantUpdateOnWholeFv (
    670                             FvbHandle,
    671                             FvbProtocol,
    672                             BlockMap,
    673                             ConfigData,
    674                             ImageBuffer,
    675                             ImageSize
    676                             );
    677   }
    678 
    679   FreePool (FwVolHeader);
    680 
    681   if (EFI_ERROR (Status)) {
    682     return Status;
    683   }
    684 
    685   //
    686   // As the whole FV has been replaced, the FV driver shall re-parse the
    687   // firmware volume. So re-install FVB protocol here
    688   //
    689   Status                =  gBS->ReinstallProtocolInterface (
    690                                    FvbHandle,
    691                                    &gEfiFirmwareVolumeBlockProtocolGuid,
    692                                    FvbProtocol,
    693                                    FvbProtocol
    694                                    );
    695 
    696   return Status;
    697 }
    698 
    699 /**
    700   Update certain file in the FV.
    701 
    702   @param FvbHandle       Handle of FVB protocol for the updated flash range.
    703   @param FvbProtocol     FVB protocol.
    704   @param ConfigData      Config data on updating driver.
    705   @param ImageBuffer     Image buffer to be updated.
    706   @param ImageSize       Image size.
    707   @param FileType        FFS file type.
    708   @param FileAttributes  FFS file attribute
    709 
    710   @retval EFI_INVALID_PARAMETER  Update type is not UpdateFvFile.
    711                                  Or Image size is not same to the size of whole FV.
    712   @retval EFI_UNSUPPORTED        PEIM FFS is unsupported to be updated.
    713   @retval EFI_SUCCESS            The FFS file is added into FV.
    714 
    715 **/
    716 EFI_STATUS
    717 PerformUpdateOnFvFile (
    718   IN EFI_HANDLE                         FvbHandle,
    719   IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvbProtocol,
    720   IN UPDATE_CONFIG_DATA                 *ConfigData,
    721   IN UINT8                              *ImageBuffer,
    722   IN UINTN                              ImageSize,
    723   IN EFI_FV_FILETYPE                    FileType,
    724   IN EFI_FV_FILE_ATTRIBUTES             FileAttributes
    725   )
    726 {
    727   EFI_STATUS                            Status;
    728   EFI_FIRMWARE_VOLUME2_PROTOCOL          *FwVolProtocol;
    729   EFI_FV_WRITE_FILE_DATA                FileData;
    730   CHAR16                                *TmpStr;
    731 
    732   if (ConfigData->UpdateType != UpdateFvFile) {
    733     return EFI_INVALID_PARAMETER;
    734   }
    735 
    736   //
    737   // Print on screen
    738   //
    739   TmpStr  = HiiGetString (gHiiHandle, STRING_TOKEN(UPDATE_FIRMWARE_VOLUME_FILE), NULL);
    740   if (TmpStr != NULL) {
    741     Print (TmpStr, &(ConfigData->FileGuid));
    742     FreePool (TmpStr);
    743   }
    744 
    745   DEBUG ((EFI_D_UPDATE, "UpdateDriver: updating file: %g\n",
    746     &(ConfigData->FileGuid)));
    747 
    748   //
    749   // Get Firmware volume protocol on this FVB protocol
    750   //
    751   Status                = gBS->HandleProtocol (
    752                                   FvbHandle,
    753                                   &gEfiFirmwareVolume2ProtocolGuid,
    754                                   (VOID **) &FwVolProtocol
    755                                   );
    756   if (EFI_ERROR (Status)) {
    757     return Status;
    758   }
    759 
    760   //
    761   // If it is a PEIM, we need first to rebase it before committing
    762   // the write to target
    763   //
    764   if ((FileType == EFI_FV_FILETYPE_PEI_CORE) || (FileType == EFI_FV_FILETYPE_PEIM )
    765     || (FileType == EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER)) {
    766     return EFI_UNSUPPORTED;
    767   }
    768 
    769   FileData.NameGuid         = &(ConfigData->FileGuid);
    770   FileData.Type             = FileType;
    771   FileData.FileAttributes   = FileAttributes;
    772   FileData.Buffer           = ImageBuffer;
    773   FileData.BufferSize       = (UINT32) ImageSize;
    774 
    775   Status                    = FwVolProtocol->WriteFile (
    776                                                 FwVolProtocol,
    777                                                 1,                        // NumberOfFiles
    778                                                 (EFI_FV_WRITE_POLICY)ConfigData->FaultTolerant,
    779                                                 &FileData
    780                                                 );
    781   return Status;
    782 }
    783 
    784 /**
    785   Update the buffer into flash area in fault tolerant write method.
    786 
    787   @param ImageBuffer     Image buffer to be updated.
    788   @param SizeLeft        Size of the image buffer.
    789   @param UpdatedSize     Size of the updated buffer.
    790   @param ConfigData      Config data on updating driver.
    791   @param FlashAddress    Flash address to be updated as start address.
    792   @param FvbProtocol     FVB protocol.
    793   @param FvbHandle       Handle of FVB protocol for the updated flash range.
    794 
    795   @retval EFI_SUCCESS            Buffer data is updated into flash.
    796   @retval EFI_INVALID_PARAMETER  Base flash address is not in FVB flash area.
    797   @retval EFI_NOT_FOUND          FTW protocol doesn't exist.
    798   @retval EFI_OUT_OF_RESOURCES   No enough backup space.
    799   @retval EFI_ABORTED            Error happen when update flash area.
    800 
    801 **/
    802 EFI_STATUS
    803 FaultTolerantUpdateOnPartFv (
    804   IN       UINT8                         *ImageBuffer,
    805   IN       UINTN                         SizeLeft,
    806   IN OUT   UINTN                         *UpdatedSize,
    807   IN       UPDATE_CONFIG_DATA            *ConfigData,
    808   IN       EFI_PHYSICAL_ADDRESS          FlashAddress,
    809   IN       EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvbProtocol,
    810   IN       EFI_HANDLE                    FvbHandle
    811   )
    812 {
    813   EFI_STATUS                            Status;
    814   EFI_FIRMWARE_VOLUME_HEADER            *FwVolHeader;
    815   EFI_FIRMWARE_VOLUME_HEADER            *FwVolHeaderTmp;
    816   EFI_PHYSICAL_ADDRESS                  BaseAddress;
    817   EFI_PHYSICAL_ADDRESS                  FvBase;
    818   EFI_PHYSICAL_ADDRESS                  NextBlock;
    819   EFI_FV_BLOCK_MAP_ENTRY                *BlockMap;
    820   EFI_FV_BLOCK_MAP_ENTRY                *PtrMap;
    821   UINTN                                 NumOfUpdates;
    822   UINTN                                 TotalSize;
    823   EFI_PHYSICAL_ADDRESS                  StartAddress;
    824   EFI_FAULT_TOLERANT_WRITE_PROTOCOL     *FtwProtocol;
    825   UINTN                                 MaxBlockSize;
    826   UINTN                                 FtwMaxBlockSize;
    827   BOOLEAN                               Pending;
    828   UPDATE_PRIVATE_DATA                   PrivateData;
    829   EFI_LBA                               PendingLba;
    830   EFI_LBA                               Lba;
    831   UINTN                                 BlockSize;
    832   UINTN                                 PendingOffset;
    833   UINTN                                 Offset;
    834   UINTN                                 PendingLength;
    835   UINTN                                 Length;
    836   UINTN                                 Index;
    837   UINT8                                 *Image;
    838 
    839   //
    840   // Get the block map to update the block one by one
    841   //
    842   Status = FvbProtocol->GetPhysicalAddress (
    843                           FvbProtocol,
    844                           &FvBase
    845                           );
    846   if (EFI_ERROR (Status)) {
    847     return Status;
    848   }
    849 
    850   FwVolHeaderTmp = (EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)FvBase;
    851   if ((FlashAddress < FvBase) || (FlashAddress > (FvBase + FwVolHeaderTmp->FvLength))) {
    852     return EFI_INVALID_PARAMETER;
    853   }
    854 
    855   FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *)AllocateCopyPool (
    856                                                 FwVolHeaderTmp->HeaderLength,
    857                                                 FwVolHeaderTmp
    858                                                 );
    859   if (FwVolHeader == NULL) {
    860     return EFI_OUT_OF_RESOURCES;
    861   }
    862 
    863   //
    864   // For fault tolerant write, we have to know how many blocks we need to
    865   // update. So we will calculate number of updates and max block size first
    866   //
    867   NumOfUpdates          = 0;
    868   MaxBlockSize          = 0;
    869   TotalSize             = SizeLeft;
    870   StartAddress          = FlashAddress;
    871   BaseAddress           = FvBase;
    872   BlockMap              = &(FwVolHeader->BlockMap[0]);
    873   PtrMap                = BlockMap;
    874 
    875   while (TotalSize > 0) {
    876     if ((PtrMap->NumBlocks == 0) || (PtrMap->Length == 0)) {
    877       break;
    878     }
    879 
    880     BlockSize           = PtrMap->Length;
    881     for (Index = 0; Index < PtrMap->NumBlocks; Index++) {
    882       NextBlock         = BaseAddress + BlockSize;
    883       //
    884       // Check if this block need to be updated
    885       //
    886       if ((StartAddress >= BaseAddress) && (StartAddress < NextBlock)) {
    887         //
    888         // Get the maximum block size
    889         //
    890         if (MaxBlockSize < BlockSize) {
    891           MaxBlockSize  = BlockSize;
    892         }
    893 
    894         //
    895         // This block shall be udpated. So increment number of updates
    896         //
    897         NumOfUpdates++;
    898         Offset          = (UINTN) (StartAddress - BaseAddress);
    899         Length          = TotalSize;
    900         if ((Length + Offset ) > BlockSize) {
    901           Length        = BlockSize - Offset;
    902         }
    903 
    904         StartAddress    = StartAddress + Length;
    905         TotalSize       = TotalSize - Length;
    906         if (TotalSize <= 0) {
    907           break;
    908         }
    909       }
    910       BaseAddress       = NextBlock;
    911     }
    912     PtrMap++;
    913   }
    914 
    915   //
    916   // Get the FTW protocol
    917   //
    918   Status = gBS->LocateProtocol (
    919                   &gEfiFaultTolerantWriteProtocolGuid,
    920                   NULL,
    921                   (VOID **) &FtwProtocol
    922                   );
    923   if (EFI_ERROR (Status)) {
    924     FreePool (FwVolHeader);
    925     return EFI_NOT_FOUND;
    926   }
    927 
    928   FtwProtocol->GetMaxBlockSize (FtwProtocol, &FtwMaxBlockSize);
    929 
    930   //
    931   // Not enough backup space. return directly
    932   //
    933   if (FtwMaxBlockSize < MaxBlockSize) {
    934     FreePool (FwVolHeader);
    935     return EFI_OUT_OF_RESOURCES;
    936   }
    937 
    938   PendingLba            = 0;
    939   PendingOffset         = 0;
    940   PendingLength         = 0;
    941   Pending               = FALSE;
    942 
    943   //
    944   // Fault Tolerant Write can only support actual fault tolerance if the write
    945   // is a reclaim operation, which means the data buffer (new and old) are
    946   // acutally both stored in flash. But for component update write, the data
    947   // are now in memory. So we cannot actually recover the data after power
    948   // failure.
    949   //
    950   Status = RetrieveLastWrite (
    951              FvbHandle,
    952              FtwProtocol,
    953              ConfigData,
    954              sizeof (UPDATE_PRIVATE_DATA),
    955              &PrivateData,
    956              &PendingLba,
    957              &PendingOffset,
    958              &PendingLength,
    959              &Pending
    960              );
    961   if (Pending && (Status == EFI_NOT_FOUND)) {
    962     //
    963     // I'm not the owner of the pending fault tolerant write record
    964     // Cannot continue with the write operation
    965     //
    966     FreePool (FwVolHeader);
    967     return EFI_ABORTED;
    968   }
    969 
    970   if (EFI_ERROR(Status)) {
    971     FreePool (FwVolHeader);
    972     return EFI_ABORTED;
    973   }
    974 
    975   //
    976   // Currently we start from the pending write if there is any. But if the
    977   // caller is exactly the same, and the new data is already a in memory, (it
    978   // cannot be stored in flash in last write,) we can just abort last write
    979   // and start from the very begining.
    980   //
    981   if (!Pending) {
    982     //
    983     // Now allocte the update private data in FTW. If there is pending
    984     // write, it has already been allocated and no need to allocate here.
    985     //
    986     Status = FtwProtocol->Allocate (
    987                             FtwProtocol,
    988                             &gEfiCallerIdGuid,
    989                             sizeof (UPDATE_PRIVATE_DATA),
    990                             NumOfUpdates
    991                             );
    992     if (EFI_ERROR (Status)) {
    993       FreePool (FwVolHeader);
    994       return Status;
    995     }
    996   }
    997 
    998   //
    999   // Perform the update now. If there are pending writes, we need to
   1000   // start from the pending write instead of the very beginning.
   1001   //
   1002   TotalSize             = SizeLeft;
   1003   Lba                   = 0;
   1004   StartAddress          = FlashAddress;
   1005   BaseAddress           = FvBase;
   1006   PtrMap                = BlockMap;
   1007   Image                 = ImageBuffer;
   1008   CopyMem (
   1009   	(VOID *) &PrivateData.FileGuid,
   1010   	(VOID *) &ConfigData->FileGuid,
   1011    	sizeof (EFI_GUID)
   1012   );
   1013 
   1014   while (TotalSize > 0) {
   1015     if ((PtrMap->NumBlocks == 0) || (PtrMap->Length == 0)) {
   1016       break;
   1017     }
   1018 
   1019     BlockSize           = (UINTN)PtrMap->Length;
   1020     for (Index = 0;  Index < PtrMap->NumBlocks; Index++) {
   1021       NextBlock         = BaseAddress + BlockSize;
   1022       if ((StartAddress >= BaseAddress) && (StartAddress < NextBlock)) {
   1023         //
   1024         // So we need to update this block
   1025         //
   1026         Offset          = (UINTN) (StartAddress - BaseAddress);
   1027         Length          = TotalSize;
   1028         if ((Length + Offset ) > BlockSize) {
   1029           Length        = BlockSize - Offset;
   1030         }
   1031 
   1032         //
   1033         // Add an extra check here to see if the pending record is correct
   1034         //
   1035         if (Pending && (Lba == PendingLba)) {
   1036           if ((PendingOffset != Offset) || (PendingLength != Length)) {
   1037             //
   1038             // Error.
   1039             //
   1040             Status          = EFI_ABORTED;
   1041             break;
   1042           }
   1043         }
   1044 
   1045         if ((!Pending) || (Lba >= PendingLba)) {
   1046           DEBUG ((EFI_D_UPDATE, "Update Flash area from %08LX to %08LX\n", StartAddress, (UINT64)StartAddress + Length));
   1047           Status            = FtwProtocol->Write (
   1048                                              FtwProtocol,
   1049                                              Lba,                  // Lba
   1050                                              Offset,               // Offset
   1051                                              Length,               // Size
   1052                                              &PrivateData,         // Private Data
   1053                                              FvbHandle,            // FVB handle
   1054                                              Image                 // Buffer
   1055                                              );
   1056           if (EFI_ERROR (Status)) {
   1057             break;
   1058           }
   1059         }
   1060 
   1061         //
   1062         // Now increment StartAddress, ImageBuffer and decrease the
   1063         // left size to prepare for the next block update.
   1064         //
   1065         StartAddress    = StartAddress + Length;
   1066         Image           = Image + Length;
   1067         TotalSize       = TotalSize - Length;
   1068         if (TotalSize <= 0) {
   1069           break;
   1070         }
   1071       }
   1072       BaseAddress       = NextBlock;
   1073       Lba++;
   1074     }
   1075 
   1076     if (EFI_ERROR (Status)) {
   1077       break;
   1078     }
   1079     PtrMap++;
   1080   }
   1081 
   1082   FreePool (FwVolHeader);
   1083 
   1084   *UpdatedSize = SizeLeft - TotalSize;
   1085 
   1086   return EFI_SUCCESS;
   1087 }
   1088 
   1089 /**
   1090   Directly update the buffer into flash area without fault tolerant write method.
   1091 
   1092   @param ImageBuffer     Image buffer to be updated.
   1093   @param SizeLeft        Size of the image buffer.
   1094   @param UpdatedSize     Size of the updated buffer.
   1095   @param FlashAddress    Flash address to be updated as start address.
   1096   @param FvbProtocol     FVB protocol.
   1097   @param FvbHandle       Handle of FVB protocol for the updated flash range.
   1098 
   1099   @retval EFI_SUCCESS            Buffer data is updated into flash.
   1100   @retval EFI_INVALID_PARAMETER  Base flash address is not in FVB flash area.
   1101   @retval EFI_OUT_OF_RESOURCES   No enough backup space.
   1102 
   1103 **/
   1104 EFI_STATUS
   1105 NonFaultTolerantUpdateOnPartFv (
   1106   IN      UINT8                         *ImageBuffer,
   1107   IN      UINTN                         SizeLeft,
   1108   IN OUT  UINTN                         *UpdatedSize,
   1109   IN      EFI_PHYSICAL_ADDRESS          FlashAddress,
   1110   IN      EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvbProtocol,
   1111   IN      EFI_HANDLE                    FvbHandle
   1112   )
   1113 {
   1114   EFI_STATUS                            Status;
   1115   EFI_FIRMWARE_VOLUME_HEADER            *FwVolHeader;
   1116   EFI_FIRMWARE_VOLUME_HEADER            *FwVolHeaderTmp;
   1117   EFI_PHYSICAL_ADDRESS                  BaseAddress;
   1118   EFI_PHYSICAL_ADDRESS                  NextBlock;
   1119   EFI_FV_BLOCK_MAP_ENTRY                *BlockMap;
   1120   UINTN                                 Index;
   1121   UINTN                                 TotalSize;
   1122   UINTN                                 BlockSize;
   1123   EFI_LBA                               Lba;
   1124   UINTN                                 Offset;
   1125   UINTN                                 Length;
   1126   UINT8                                 *Image;
   1127 
   1128   //
   1129   // Get the block map to update the block one by one
   1130   //
   1131   Status                = FvbProtocol->GetPhysicalAddress (
   1132                                          FvbProtocol,
   1133                                          &BaseAddress
   1134                                          );
   1135   if (EFI_ERROR (Status)) {
   1136     return Status;
   1137   }
   1138 
   1139   FwVolHeaderTmp = (EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)BaseAddress;
   1140   if ((FlashAddress < BaseAddress) || (FlashAddress > ( BaseAddress + FwVolHeaderTmp->FvLength ))) {
   1141     return EFI_INVALID_PARAMETER;
   1142   }
   1143 
   1144   FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *)AllocateCopyPool (
   1145                                                 FwVolHeaderTmp->HeaderLength,
   1146                                                 FwVolHeaderTmp
   1147                                                 );
   1148   if (FwVolHeader == NULL) {
   1149     return EFI_OUT_OF_RESOURCES;
   1150   }
   1151 
   1152   Image                 = ImageBuffer;
   1153   TotalSize             = SizeLeft;
   1154   BlockMap              = &(FwVolHeader->BlockMap[0]);
   1155   Lba                   = 0;
   1156 
   1157   while (TotalSize > 0) {
   1158     if ((BlockMap->NumBlocks == 0) || (BlockMap->Length == 0)) {
   1159       break;
   1160     }
   1161 
   1162     BlockSize           = BlockMap->Length;
   1163     for (Index = 0 ; Index < BlockMap->NumBlocks ; Index++) {
   1164       NextBlock         = BaseAddress + BlockSize;
   1165       if ((FlashAddress >= BaseAddress) && (FlashAddress < NextBlock)) {
   1166         //
   1167         // So we need to update this block
   1168         //
   1169         Offset          = (UINTN) FlashAddress - (UINTN) BaseAddress;
   1170         Length          = TotalSize;
   1171         if ((Length + Offset ) > BlockSize) {
   1172           Length        = BlockSize - Offset;
   1173         }
   1174 
   1175         DEBUG ((EFI_D_UPDATE, "Update Flash area from %08LX to %08LX\n", FlashAddress, (UINT64)FlashAddress + Length));
   1176         //
   1177         // Update the block
   1178         //
   1179         Status          = UpdateBufferInOneBlock (
   1180                             FvbProtocol,
   1181                             Lba,
   1182                             Offset,
   1183                             Length,
   1184                             BlockSize,
   1185                             Image
   1186                             );
   1187         if (EFI_ERROR (Status)) {
   1188           FreePool (FwVolHeader);
   1189           return Status;
   1190         }
   1191 
   1192         //
   1193         // Now increment FlashAddress, ImageBuffer and decrease the
   1194         // left size to prepare for the next block update.
   1195         //
   1196         FlashAddress    = FlashAddress + Length;
   1197         Image           = Image + Length;
   1198         TotalSize       = TotalSize - Length;
   1199         if (TotalSize <= 0) {
   1200           break;
   1201         }
   1202       }
   1203       BaseAddress       = NextBlock;
   1204       Lba++;
   1205     }
   1206 
   1207     if (EFI_ERROR (Status)) {
   1208       break;
   1209     }
   1210     BlockMap++;
   1211   }
   1212 
   1213   FreePool (FwVolHeader);
   1214 
   1215   *UpdatedSize          = SizeLeft - TotalSize;
   1216 
   1217   return EFI_SUCCESS;
   1218 }
   1219