Home | History | Annotate | Download | only in UpdateDriverDxe
      1 /** @file
      2   Functions in this file will mainly focus on looking through the capsule
      3   for the image to be programmed, and the flash area that is going to be
      4   programed.
      5 
      6   Copyright (c) 2002 - 2014, Intel Corporation. All rights reserved.<BR>
      7 
      8   This program and the accompanying materials
      9   are licensed and made available under the terms and conditions
     10   of the BSD License which accompanies this distribution.  The
     11   full text of the license may be found at
     12   http://opensource.org/licenses/bsd-license.php
     13 
     14   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     15   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     16 
     17 **/
     18 
     19 #include "UpdateDriver.h"
     20 
     21 EFI_HII_HANDLE  gHiiHandle;
     22 
     23 /**
     24   Update the whole FV, or certain files in the FV.
     25 
     26   @param ConfigData      Pointer to the config data on updating file.
     27   @param ImageBuffer     Image buffer to be updated.
     28   @param ImageSize       Image size.
     29   @param FileType        FFS file type.
     30   @param FileAttributes  FFS file attribute.
     31 
     32   @retval EFI_NOT_FOUND  The matched FVB protocol is not found.
     33   @retval EFI_SUCCESS    The image buffer is updated into FV.
     34 
     35 **/
     36 EFI_STATUS
     37 PerformUpdateOnFirmwareVolume (
     38   IN UPDATE_CONFIG_DATA                 *ConfigData,
     39   IN UINT8                              *ImageBuffer,
     40   IN UINTN                              ImageSize,
     41   IN EFI_FV_FILETYPE                    FileType,
     42   IN EFI_FV_FILE_ATTRIBUTES             FileAttributes
     43   )
     44 {
     45   EFI_STATUS                            Status;
     46   BOOLEAN                               Found;
     47   EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL    *FvbProtocol;
     48   UINTN                                 Index;
     49   UINTN                                 NumOfHandles;
     50   EFI_HANDLE                            *HandleBuffer;
     51   EFI_PHYSICAL_ADDRESS                  BaseAddress;
     52   EFI_FVB_ATTRIBUTES_2                  Attributes;
     53 
     54   //
     55   // Locate all Fvb protocol
     56   //
     57   HandleBuffer = NULL;
     58   Status          = gBS->LocateHandleBuffer (
     59                            ByProtocol,
     60                            &gEfiFirmwareVolumeBlockProtocolGuid,
     61                            NULL,
     62                            &NumOfHandles,
     63                            &HandleBuffer
     64                            );
     65   if ((EFI_ERROR (Status)) || (NumOfHandles == 0) || (HandleBuffer == NULL)) {
     66     if (HandleBuffer != NULL) {
     67       FreePool (HandleBuffer);
     68     }
     69     return EFI_NOT_FOUND;
     70   }
     71 
     72   //
     73   // Check the FVB protocol one by one
     74   //
     75   Found               = FALSE;
     76   FvbProtocol         = NULL;
     77   for (Index = 0; Index < NumOfHandles; Index++) {
     78     Status            = gBS->HandleProtocol (
     79                                HandleBuffer[Index],
     80                                &gEfiFirmwareVolumeBlockProtocolGuid,
     81                                (VOID **) &FvbProtocol
     82                                );
     83     if (EFI_ERROR (Status)) {
     84       break;
     85     }
     86 
     87     //
     88     // Ensure this FVB protocol supported Write operation.
     89     //
     90     Status = FvbProtocol->GetAttributes (FvbProtocol, &Attributes);
     91     if (EFI_ERROR (Status) || ((Attributes & EFI_FVB2_WRITE_STATUS) == 0)) {
     92       continue;
     93     }
     94 
     95     Status            = FvbProtocol->GetPhysicalAddress (
     96                                        FvbProtocol,
     97                                        &BaseAddress
     98                                       );
     99     if (EFI_ERROR (Status)) {
    100       break;
    101     }
    102     if (BaseAddress == ConfigData->BaseAddress) {
    103       Found           = TRUE;
    104       break;
    105     }
    106   }
    107 
    108   if (!Found) {
    109     if (HandleBuffer != NULL) {
    110       FreePool (HandleBuffer);
    111       HandleBuffer = NULL;
    112     }
    113     return EFI_NOT_FOUND;
    114   }
    115 
    116   //
    117   // Now we have got the corresponding FVB protocol. Use the FVB protocol
    118   // to update the whole FV, or certain files in the FV.
    119   //
    120   if (ConfigData->UpdateType == UpdateWholeFV) {
    121     if (FileType != EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE) {
    122       Status    = EFI_INVALID_PARAMETER;
    123     } else {
    124       Status    = PerformUpdateOnWholeFv (
    125                     HandleBuffer[Index],
    126                     FvbProtocol,
    127                     ConfigData,
    128                     ImageBuffer,
    129                     ImageSize
    130                     );
    131     }
    132   } else if (ConfigData->UpdateType == UpdateFvFile) {
    133     Status = PerformUpdateOnFvFile (
    134                HandleBuffer[Index],
    135                FvbProtocol,
    136                ConfigData,
    137                ImageBuffer,
    138                ImageSize,
    139                FileType,
    140                FileAttributes
    141                );
    142   }
    143 
    144   if (HandleBuffer != NULL) {
    145     FreePool (HandleBuffer);
    146     HandleBuffer = NULL;
    147   }
    148 
    149   return Status;
    150 }
    151 
    152 /**
    153   Update the file directly into flash area.
    154 
    155   @param ConfigData      Pointer to the config data on updating file.
    156   @param ImageBuffer     Image buffer to be updated.
    157   @param ImageSize       Image size.
    158 
    159   @retval EFI_SUCCESS    The file is updated into flash area.
    160   @retval EFI_NOT_FOUND  The FVB protocol for the updated flash area is not found.
    161 
    162 **/
    163 EFI_STATUS
    164 PerformUpdateOnFlashArea (
    165   IN UPDATE_CONFIG_DATA                 *ConfigData,
    166   IN UINT8                              *ImageBuffer,
    167   IN UINTN                              ImageSize
    168   )
    169 {
    170   EFI_STATUS                            Status;
    171   UINTN                                 SizeLeft;
    172   EFI_PHYSICAL_ADDRESS                  FlashAddress;
    173   UINT8                                 *PtrImage;
    174   BOOLEAN                               Found;
    175   EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL    *FvbProtocol;
    176   UINTN                                 Index;
    177   UINTN                                 NumOfHandles;
    178   EFI_HANDLE                            *HandleBuffer;
    179   EFI_PHYSICAL_ADDRESS                  BaseAddress;
    180   EFI_FIRMWARE_VOLUME_HEADER            *FwVolHeader;
    181   EFI_HANDLE                            FvbHandle;
    182   UINTN                                 SizeUpdated;
    183   CHAR16                                *TmpStr;
    184   EFI_FVB_ATTRIBUTES_2                  Attributes;
    185 
    186   SizeLeft              = ImageSize;
    187   PtrImage              = ImageBuffer;
    188   FlashAddress          = ConfigData->BaseAddress;
    189   Status                = EFI_SUCCESS;
    190   HandleBuffer          = NULL;
    191 
    192   //
    193   // Print on screen
    194   //
    195   TmpStr = HiiGetString (gHiiHandle, STRING_TOKEN(UPDATE_FLASH_RANGE), NULL);
    196   if (TmpStr != NULL) {
    197     Print (TmpStr, FlashAddress, ((UINT64)SizeLeft + FlashAddress));
    198     FreePool (TmpStr);
    199   }
    200 
    201   //
    202   // Locate all Fvb protocol
    203   //
    204   Status          = gBS->LocateHandleBuffer (
    205                            ByProtocol,
    206                            &gEfiFirmwareVolumeBlockProtocolGuid,
    207                            NULL,
    208                            &NumOfHandles,
    209                            &HandleBuffer
    210                            );
    211   if ((EFI_ERROR (Status)) || (NumOfHandles == 0) || (HandleBuffer == NULL)) {
    212     if (HandleBuffer != NULL) {
    213       FreePool (HandleBuffer);
    214     }
    215     return EFI_NOT_FOUND;
    216   }
    217 
    218   while (SizeLeft > 0) {
    219     //
    220     // First get the FVB protocols. If the flash area is a FV, or sub FV,
    221     // we can directly locate all the FVB protocol. Otherwise we should use
    222     // implementation specific method to get the alternate FVB protocol
    223     //
    224     Found               = FALSE;
    225     FvbProtocol         = NULL;
    226 
    227     //
    228     // Check the FVB protocol one by one
    229     //
    230     for (Index = 0; Index < NumOfHandles; Index++) {
    231       Status        = gBS->HandleProtocol (
    232                              HandleBuffer[Index],
    233                              &gEfiFirmwareVolumeBlockProtocolGuid,
    234                              (VOID **) &FvbProtocol
    235                              );
    236       if (EFI_ERROR (Status)) {
    237         break;
    238       }
    239 
    240       //
    241       // Ensure this FVB protocol supported Write operation.
    242       //
    243       Status = FvbProtocol->GetAttributes (FvbProtocol, &Attributes);
    244       if (EFI_ERROR (Status) || ((Attributes & EFI_FVB2_WRITE_STATUS) == 0)) {
    245         continue;
    246       }
    247 
    248       Status        = FvbProtocol->GetPhysicalAddress (
    249                                      FvbProtocol,
    250                                      &BaseAddress
    251                                      );
    252       if (EFI_ERROR (Status)) {
    253         break;
    254       }
    255       FwVolHeader   = (EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)BaseAddress;
    256 
    257       //
    258       // This sub area entry falls in the range of the FV
    259       //
    260       if ((FlashAddress >= BaseAddress) && (FlashAddress < (BaseAddress + FwVolHeader->FvLength))) {
    261         Found       = TRUE;
    262         break;
    263       }
    264     }
    265 
    266     if (!Found) {
    267       if (HandleBuffer != NULL) {
    268         FreePool (HandleBuffer);
    269         HandleBuffer    = NULL;
    270       }
    271       return EFI_NOT_FOUND;
    272     }
    273 
    274     FvbHandle           = HandleBuffer[Index];
    275     SizeUpdated         = 0;
    276 
    277     //
    278     // If the flash area is boot required, the update must be fault tolerant
    279     //
    280     if (ConfigData->FaultTolerant) {
    281       //
    282       // Finally we are here. We have got the corresponding FVB protocol. Now
    283       // we need to convert the physical address to LBA and offset and call
    284       // FTW write. Also check if the flash range is larger than the FV.
    285       //
    286       Status            = FaultTolerantUpdateOnPartFv (
    287                             PtrImage,
    288                             SizeLeft,
    289                             &SizeUpdated,
    290                             ConfigData,
    291                             FlashAddress,
    292                             FvbProtocol,
    293                             FvbHandle
    294                             );
    295     } else {
    296       //
    297       // Finally we are here. We have got the corresponding FVB protocol. Now
    298       // we need to convert the physical address to LBA and offset and call
    299       // FVB write. Also check if the flash range is larger than the FV.
    300       //
    301       Status            = NonFaultTolerantUpdateOnPartFv (
    302                             PtrImage,
    303                             SizeLeft,
    304                             &SizeUpdated,
    305                             FlashAddress,
    306                             FvbProtocol,
    307                             FvbHandle
    308                             );
    309     }
    310 
    311     if (EFI_ERROR (Status)) {
    312       return Status;
    313     }
    314 
    315     //
    316     // As part of the FV has been replaced, the FV driver shall re-parse
    317     // the firmware volume. So re-install FVB protocol here
    318     //
    319     Status                =  gBS->ReinstallProtocolInterface (
    320                                     FvbHandle,
    321                                     &gEfiFirmwareVolumeBlockProtocolGuid,
    322                                     FvbProtocol,
    323                                     FvbProtocol
    324                                     );
    325 
    326     if (EFI_ERROR (Status)) {
    327       return Status;
    328     }
    329 
    330     //
    331     // Check if we are done with the update
    332     //
    333     SizeLeft            = SizeLeft - SizeUpdated;
    334     FlashAddress        = FlashAddress + SizeUpdated;
    335     PtrImage            = PtrImage + SizeUpdated;
    336   }
    337 
    338   if (HandleBuffer != NULL) {
    339     FreePool (HandleBuffer);
    340     HandleBuffer = NULL;
    341   }
    342 
    343   return Status;
    344 }
    345 
    346 /**
    347   Find the updated file, and program it into the flash area based on the config data.
    348 
    349   @param FwVolProtocol   Pointer to FV protocol that contains the updated file.
    350   @param ConfigData      Pointer to the Config Data on updating file.
    351 
    352   @retval EFI_INVALID_PARAMETER  The update operation is not valid.
    353   @retval EFI_NOT_FOUND          The updated file is not found.
    354   @retval EFI_SUCCESS            The file is updated into the flash area.
    355 
    356 **/
    357 EFI_STATUS
    358 PerformUpdate (
    359   IN EFI_FIRMWARE_VOLUME2_PROTOCOL      *FwVolProtocol,
    360   IN UPDATE_CONFIG_DATA                 *ConfigData
    361   )
    362 {
    363   EFI_STATUS                            Status;
    364   UINT8                                 *FileBuffer;
    365   UINTN                                 FileBufferSize;
    366   EFI_FV_FILETYPE                       FileType;
    367   EFI_FV_FILE_ATTRIBUTES                Attrib;
    368   EFI_SECTION_TYPE                      SectionType;
    369   UINT32                                AuthenticationStatus;
    370   CHAR16                                *TmpStr;
    371   BOOLEAN                               StartToUpdate;
    372 
    373   Status            = EFI_SUCCESS;
    374   FileBuffer        = NULL;
    375   FileBufferSize    = 0;
    376   Status            = FwVolProtocol->ReadFile (
    377                                        FwVolProtocol,
    378                                        &(ConfigData->FileGuid),
    379                                        (VOID **) &FileBuffer,
    380                                        &FileBufferSize,
    381                                        &FileType,
    382                                        &Attrib,
    383                                        &AuthenticationStatus
    384                                        );
    385   if (EFI_ERROR (Status)) {
    386     return Status;
    387   }
    388 
    389   StartToUpdate = FALSE;
    390 
    391   //
    392   // Check if the update image is the one we require
    393   // and then perform the update
    394   //
    395   switch (ConfigData->UpdateType) {
    396 
    397     case UpdateWholeFV:
    398 
    399       //
    400       // For UpdateWholeFv, the update file shall be a firmware volume
    401       // image file.
    402       //
    403       if (FileType != EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE) {
    404         DEBUG ((EFI_D_UPDATE, "UpdateDriver: Data file should be of TYPE EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE\n"));
    405         Status          = EFI_INVALID_PARAMETER;
    406       } else {
    407         if (FileBuffer != NULL) {
    408           FreePool (FileBuffer);
    409         }
    410         SectionType     = EFI_SECTION_FIRMWARE_VOLUME_IMAGE;
    411         FileBuffer      = NULL;
    412         FileBufferSize  = 0;
    413         Status          = FwVolProtocol->ReadSection (
    414                                            FwVolProtocol,
    415                                            &(ConfigData->FileGuid),
    416                                            SectionType,
    417                                            0,
    418                                            (VOID **) &FileBuffer,
    419                                            &FileBufferSize,
    420                                            &AuthenticationStatus
    421                                            );
    422         if (!EFI_ERROR (Status)) {
    423           //
    424           // Execute the update. For UpdateWholeFv, the update
    425           // will always execute on a whole FV
    426           //
    427           StartToUpdate = TRUE;
    428           Status        = PerformUpdateOnFirmwareVolume (
    429                             ConfigData,
    430                             FileBuffer,
    431                             FileBufferSize,
    432                             FileType,
    433                             Attrib
    434                             );
    435 
    436         } else {
    437           DEBUG ((EFI_D_UPDATE, "UpdateDriver: Data file should be sectioned with TYPE EFI_SECTION_FIRMWARE_VOLUME_IMAGE\n"));
    438         }
    439       }
    440       break;
    441 
    442     case UpdateFvRange:
    443 
    444       //
    445       // For UpdateFvRange, the update file shall be a raw file
    446       // which does not contain any sections. The contents of the file
    447       // will be directly programmed.
    448       //
    449       if (FileType != EFI_FV_FILETYPE_RAW) {
    450         DEBUG ((EFI_D_UPDATE, "UpdateDriver: Data file should of TYPE EFI_FV_FILETYPE_RAW\n"));
    451         Status          = EFI_INVALID_PARAMETER;
    452       } else {
    453         //
    454         // For UpdateFvRange, the update may be performed on a sub area
    455         // of a certain FV, or a flash area that is not FV, or part of FV.
    456         // The update may also go across more than one FVs.
    457         //
    458         StartToUpdate   = TRUE;
    459         Status          = PerformUpdateOnFlashArea (
    460                             ConfigData,
    461                             FileBuffer,
    462                             FileBufferSize
    463                           );
    464       }
    465       break;
    466 
    467     case UpdateFvFile:
    468 
    469       //
    470       // No check will be done the the file got. The contents of the file
    471       // will be directly programmed.
    472       // Though UpdateFvFile will only update a single file, but the update
    473       // will always execute on a FV
    474       //
    475       StartToUpdate = TRUE;
    476       Status        = PerformUpdateOnFirmwareVolume (
    477                         ConfigData,
    478                         FileBuffer,
    479                         FileBufferSize,
    480                         FileType,
    481                         Attrib
    482                         );
    483       break;
    484 
    485     default:
    486       Status        = EFI_INVALID_PARAMETER;
    487   }
    488 
    489   if (StartToUpdate) {
    490     if (EFI_ERROR (Status)) {
    491       TmpStr  = HiiGetString (gHiiHandle, STRING_TOKEN(UPDATE_DRIVER_ABORTED), NULL);
    492     } else {
    493       TmpStr  = HiiGetString (gHiiHandle, STRING_TOKEN(UPDATE_DRIVER_DONE), NULL);
    494     }
    495     if (TmpStr != NULL) {
    496       Print (TmpStr);
    497       FreePool (TmpStr);
    498     }
    499   }
    500 
    501   if (FileBuffer != NULL) {
    502     FreePool(FileBuffer);
    503     FileBuffer = NULL;
    504   }
    505 
    506   return Status;
    507 }
    508 
    509 /**
    510   Process the input firmware volume by using DXE service ProcessFirmwareVolume.
    511 
    512   @param DataBuffer      Point to the FV image to be processed.
    513   @param BufferSize      Size of the FV image buffer.
    514   @param FwVolProtocol   Point to the installed FV protocol for the input FV image.
    515 
    516   @retval EFI_OUT_OF_RESOURCES   No enough memory is allocated.
    517   @retval EFI_VOLUME_CORRUPTED   FV image is corrupted.
    518   @retval EFI_SUCCESS            FV image is processed and FV protocol is installed.
    519 
    520 **/
    521 EFI_STATUS
    522 ProcessUpdateImage (
    523   UINT8                                 *DataBuffer,
    524   UINTN                                 BufferSize,
    525   EFI_FIRMWARE_VOLUME2_PROTOCOL          **FwVolProtocol
    526   )
    527 {
    528   EFI_FIRMWARE_VOLUME_HEADER            *FwVolHeader;
    529   EFI_HANDLE                            FwVolHandle;
    530   EFI_STATUS                            Status;
    531   UINT8                                 *ProcessedDataBuffer;
    532   UINT32                                FvAlignment;
    533 
    534   ProcessedDataBuffer = NULL;
    535   FwVolHeader   = (EFI_FIRMWARE_VOLUME_HEADER *) DataBuffer;
    536   if (FwVolHeader->FvLength != BufferSize) {
    537     return EFI_VOLUME_CORRUPTED;
    538   }
    539 
    540   FvAlignment = 1 << ((FwVolHeader->Attributes & EFI_FVB2_ALIGNMENT) >> 16);
    541   //
    542   // FvAlignment must be greater than or equal to 8 bytes of the minimum FFS alignment value.
    543   //
    544   if (FvAlignment < 8) {
    545     FvAlignment = 8;
    546   }
    547   //
    548   // Check FvImage Align is required.
    549   //
    550   if (((UINTN) FwVolHeader % FvAlignment) == 0) {
    551     ProcessedDataBuffer = DataBuffer;
    552   } else {
    553     //
    554     // Allocate new aligned buffer to store DataBuffer.
    555     //
    556     ProcessedDataBuffer = AllocateAlignedPages (EFI_SIZE_TO_PAGES (BufferSize), (UINTN) FvAlignment);
    557     if (ProcessedDataBuffer == NULL) {
    558       return EFI_OUT_OF_RESOURCES;
    559     }
    560     CopyMem (ProcessedDataBuffer, DataBuffer, BufferSize);
    561   }
    562   //
    563   // Process the firmware volume
    564   //
    565   gDS->ProcessFirmwareVolume (
    566          ProcessedDataBuffer,
    567          BufferSize,
    568          &FwVolHandle
    569          );
    570 
    571   //
    572   // Get the FwVol protocol
    573   //
    574   Status = gBS->HandleProtocol (
    575                   FwVolHandle,
    576                   &gEfiFirmwareVolume2ProtocolGuid,
    577                   (VOID **) FwVolProtocol
    578                   );
    579 
    580   return Status;
    581 }
    582 
    583 /**
    584   Find the image in the same FV and program it in a target Firmware Volume device.
    585   After update image, it will reset system and no return.
    586 
    587   @param ImageHandle   A handle for the image that is initializing this driver
    588   @param SystemTable   A pointer to the EFI system table
    589 
    590   @retval EFI_ABORTED    System reset failed.
    591   @retval EFI_NOT_FOUND  The updated image is not found in the same FV.
    592 
    593 **/
    594 EFI_STATUS
    595 EFIAPI
    596 InitializeUpdateDriver (
    597   IN EFI_HANDLE                         ImageHandle,
    598   IN EFI_SYSTEM_TABLE                   *SystemTable
    599   )
    600 {
    601   EFI_STATUS                            Status;
    602   EFI_LOADED_IMAGE_PROTOCOL             *LoadedImageProtocol;
    603   EFI_FIRMWARE_VOLUME2_PROTOCOL         *FwVolProtocol;
    604   EFI_FIRMWARE_VOLUME2_PROTOCOL         *DataFwVolProtocol;
    605   MEDIA_FW_VOL_FILEPATH_DEVICE_PATH     *FwVolFilePathNode;
    606   MEDIA_FW_VOL_FILEPATH_DEVICE_PATH     *AlignedDevPathNode;
    607   EFI_DEVICE_PATH_PROTOCOL              *FilePathNode;
    608   EFI_SECTION_TYPE                      SectionType;
    609   UINT8                                 *FileBuffer;
    610   UINTN                                 FileBufferSize;
    611   EFI_FV_FILETYPE                       FileType;
    612   EFI_FV_FILE_ATTRIBUTES                Attrib;
    613   UINT32                                AuthenticationStatus;
    614   UPDATE_CONFIG_DATA                    *ConfigData;
    615   UPDATE_CONFIG_DATA                    *UpdateConfigData;
    616   UINTN                                 NumOfUpdates;
    617   UINTN                                 Index;
    618   CHAR16                                *TmpStr;
    619 
    620   //
    621   // Clear screen
    622   //
    623   if (gST->ConOut != NULL) {
    624     gST->ConOut->ClearScreen (gST->ConOut);
    625     gST->ConOut->SetAttribute (gST->ConOut, EFI_YELLOW | EFI_BRIGHT);
    626     gST->ConOut->EnableCursor (gST->ConOut, FALSE);
    627   }
    628 
    629   gHiiHandle = HiiAddPackages (
    630                  &gEfiCallerIdGuid,
    631                  NULL,
    632                  UpdateDriverDxeStrings,
    633                  NULL
    634                  );
    635   ASSERT (gHiiHandle != NULL);
    636 
    637   //
    638   // In order to look for the update data file and programmed image file
    639   // from the same volume which this driver is dispatched from, we need
    640   // to get the device path of this driver image. It is done by first
    641   // locate the LoadedImageProtocol and then get its device path
    642   //
    643   Status            = gBS->OpenProtocol (
    644                              ImageHandle,
    645                              &gEfiLoadedImageProtocolGuid,
    646                              (VOID **)&LoadedImageProtocol,
    647                              ImageHandle,
    648                              NULL,
    649                              EFI_OPEN_PROTOCOL_GET_PROTOCOL
    650                              );
    651   if (EFI_ERROR (Status)) {
    652     return Status;
    653   }
    654   //
    655   // Get the firmware volume protocol where this file resides
    656   //
    657   Status            = gBS->HandleProtocol (
    658                              LoadedImageProtocol->DeviceHandle,
    659                              &gEfiFirmwareVolume2ProtocolGuid,
    660                              (VOID **)  &FwVolProtocol
    661                              );
    662   if (EFI_ERROR (Status)) {
    663     return EFI_NOT_FOUND;
    664   }
    665 
    666   //
    667   // Shall do some extra check to see if it is really contained in the FV?
    668   // Should be able to find the section of this driver in the the FV.
    669   //
    670   FilePathNode      = LoadedImageProtocol->FilePath;
    671   FwVolFilePathNode = NULL;
    672   while (!IsDevicePathEnd (FilePathNode)) {
    673     if (EfiGetNameGuidFromFwVolDevicePathNode ((MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *)FilePathNode)!= NULL) {
    674       FwVolFilePathNode = (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *) FilePathNode;
    675       break;
    676     }
    677     FilePathNode    = NextDevicePathNode (FilePathNode);
    678   }
    679 
    680   if (FwVolFilePathNode != NULL) {
    681     AlignedDevPathNode = AllocateCopyPool (DevicePathNodeLength (FwVolFilePathNode), FwVolFilePathNode);
    682 
    683     SectionType     = EFI_SECTION_PE32;
    684     FileBuffer      = NULL;
    685     FileBufferSize  = 0;
    686     Status          = FwVolProtocol->ReadSection (
    687                                        FwVolProtocol,
    688                                        &(AlignedDevPathNode->FvFileName),
    689                                        SectionType,
    690                                        0,
    691                                        (VOID **) &FileBuffer,
    692                                        &FileBufferSize,
    693                                        &AuthenticationStatus
    694                                        );
    695     if (EFI_ERROR (Status)) {
    696       FreePool (AlignedDevPathNode);
    697       return Status;
    698     }
    699 
    700     if (FileBuffer != NULL) {
    701       FreePool(FileBuffer);
    702       FileBuffer = NULL;
    703     }
    704 
    705     //
    706     // Check the NameGuid of the udpate driver so that it can be
    707     // used as the CallerId in fault tolerant write protocol
    708     //
    709     if (!CompareGuid (&gEfiCallerIdGuid, &(AlignedDevPathNode->FvFileName))) {
    710       FreePool (AlignedDevPathNode);
    711       return EFI_NOT_FOUND;
    712     }
    713     FreePool (AlignedDevPathNode);
    714   } else {
    715     return EFI_NOT_FOUND;
    716   }
    717 
    718   //
    719   // Now try to find the script file. The script file is usually
    720   // a raw data file which does not contain any sections.
    721   //
    722   FileBuffer        = NULL;
    723   FileBufferSize    = 0;
    724   Status            = FwVolProtocol->ReadFile (
    725                                        FwVolProtocol,
    726                                        &gEfiConfigFileNameGuid,
    727                                        (VOID **) &FileBuffer,
    728                                        &FileBufferSize,
    729                                        &FileType,
    730                                        &Attrib,
    731                                        &AuthenticationStatus
    732                                        );
    733   if (EFI_ERROR (Status)) {
    734     return Status;
    735   }
    736   if (FileType != EFI_FV_FILETYPE_RAW) {
    737     return EFI_NOT_FOUND;
    738   }
    739 
    740   //
    741   // Parse the configuration file.
    742   //
    743   ConfigData        = NULL;
    744   NumOfUpdates      = 0;
    745   Status            = ParseUpdateDataFile (
    746                         FileBuffer,
    747                         FileBufferSize,
    748                         &NumOfUpdates,
    749                         &ConfigData
    750                         );
    751   if (FileBuffer != NULL) {
    752     FreePool (FileBuffer);
    753     FileBuffer = NULL;
    754   }
    755   if (EFI_ERROR (Status)) {
    756     return Status;
    757   }
    758   ASSERT (ConfigData != NULL);
    759 
    760   //
    761   // Now find the update image. The update image should be put in a FV, and then
    762   // encapsulated as a raw FFS file. This is to prevent the update image from
    763   // being dispatched. So the raw data we get here should be an FV. We need to
    764   // process this FV and read the files that is going to be updated.
    765   //
    766   FileBuffer        = NULL;
    767   FileBufferSize    = 0;
    768   Status            = FwVolProtocol->ReadFile (
    769                                        FwVolProtocol,
    770                                        &gEfiUpdateDataFileGuid,
    771                                        (VOID **) &FileBuffer,
    772                                        &FileBufferSize,
    773                                        &FileType,
    774                                        &Attrib,
    775                                        &AuthenticationStatus
    776                                        );
    777   if (EFI_ERROR (Status)) {
    778     return Status;
    779   }
    780   if (FileType != EFI_FV_FILETYPE_RAW) {
    781     return EFI_NOT_FOUND;
    782   }
    783 
    784   //
    785   // FileBuffer should be an FV. Process the FV
    786   //
    787   DataFwVolProtocol = NULL;
    788   Status            = ProcessUpdateImage (
    789                         FileBuffer,
    790                         FileBufferSize,
    791                         &DataFwVolProtocol
    792                         );
    793   if (EFI_ERROR (Status)) {
    794     FreePool (FileBuffer);
    795     return Status;
    796   }
    797 
    798   //
    799   // Print on screen
    800   //
    801   TmpStr  = HiiGetString (gHiiHandle, STRING_TOKEN(UPDATE_PROCESS_DATA), NULL);
    802   if (TmpStr != NULL) {
    803     Print (TmpStr);
    804     FreePool(TmpStr);
    805   }
    806 
    807   //
    808   // Execute the update
    809   //
    810   Index = 0;
    811   UpdateConfigData = ConfigData;
    812   while (Index < NumOfUpdates) {
    813     Status = PerformUpdate (
    814                DataFwVolProtocol,
    815                UpdateConfigData
    816                );
    817     //
    818     // Shall updates be serialized so that if an update is not successfully completed,
    819     // the remaining updates won't be performed.
    820     //
    821     if (EFI_ERROR (Status)) {
    822       break;
    823     }
    824 
    825     Index++;
    826     UpdateConfigData++;
    827   }
    828 
    829   if (EFI_ERROR (Status)) {
    830     if (ConfigData != NULL) {
    831       FreePool(ConfigData);
    832       ConfigData = NULL;
    833     }
    834     return Status;
    835   }
    836 
    837   //
    838   // Call system reset
    839   //
    840   gRT->ResetSystem (EfiResetCold, EFI_SUCCESS, 0, NULL);
    841 
    842   //
    843   // Hopefully it won't be reached
    844   //
    845   return EFI_ABORTED;
    846 }
    847