Home | History | Annotate | Download | only in CapsuleApp
      1 /** @file
      2   A shell application that triggers capsule update process.
      3 
      4   Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
      5   This program and the accompanying materials
      6   are licensed and made available under the terms and conditions of the BSD License
      7   which accompanies this distribution.  The full text of the license may be found at
      8   http://opensource.org/licenses/bsd-license.php
      9 
     10   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     11   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     12 
     13 **/
     14 
     15 #include <Uefi.h>
     16 #include <Library/BaseLib.h>
     17 #include <Library/DebugLib.h>
     18 #include <Library/BaseMemoryLib.h>
     19 #include <Library/MemoryAllocationLib.h>
     20 #include <Library/UefiBootServicesTableLib.h>
     21 #include <Library/UefiRuntimeServicesTableLib.h>
     22 #include <Library/UefiLib.h>
     23 #include <Library/PrintLib.h>
     24 #include <Protocol/LoadedImage.h>
     25 #include <Protocol/SimpleFileSystem.h>
     26 #include <Protocol/GraphicsOutput.h>
     27 #include <Guid/FileInfo.h>
     28 #include <Guid/Gpt.h>
     29 #include <Guid/GlobalVariable.h>
     30 #include <Guid/CapsuleReport.h>
     31 #include <Guid/SystemResourceTable.h>
     32 #include <Guid/FmpCapsule.h>
     33 #include <IndustryStandard/WindowsUxCapsule.h>
     34 
     35 #define CAPSULE_HEADER_SIZE  0x20
     36 
     37 #define NESTED_CAPSULE_HEADER_SIZE  SIZE_4KB
     38 #define SYSTEM_FIRMWARE_FLAG 0x50000
     39 #define DEVICE_FIRMWARE_FLAG 0x78010
     40 
     41 #define MAJOR_VERSION   1
     42 #define MINOR_VERSION   0
     43 
     44 #define MAX_CAPSULE_NUM 10
     45 
     46 extern UINTN  Argc;
     47 extern CHAR16 **Argv;
     48 
     49 //
     50 // Define how many block descriptors we want to test with.
     51 //
     52 UINTN  NumberOfDescriptors = 1;
     53 UINTN  CapsuleFirstIndex;
     54 UINTN  CapsuleLastIndex;
     55 
     56 /**
     57   Dump capsule information
     58 
     59   @param[in] CapsuleName  The name of the capsule image.
     60 
     61   @retval EFI_SUCCESS            The capsule information is dumped.
     62   @retval EFI_UNSUPPORTED        Input parameter is not valid.
     63 **/
     64 EFI_STATUS
     65 DumpCapsule (
     66   IN CHAR16                                        *CapsuleName
     67   );
     68 
     69 /**
     70   Dump capsule status variable.
     71 
     72   @retval EFI_SUCCESS            The capsule status variable is dumped.
     73   @retval EFI_UNSUPPORTED        Input parameter is not valid.
     74 **/
     75 EFI_STATUS
     76 DmpCapsuleStatusVariable (
     77   VOID
     78   );
     79 
     80 /**
     81   Dump FMP protocol info.
     82 **/
     83 VOID
     84 DumpFmpData (
     85   VOID
     86   );
     87 
     88 /**
     89   Dump FMP image data.
     90 
     91   @param[in]  ImageTypeId   The ImageTypeId of the FMP image.
     92                             It is used to identify the FMP protocol.
     93   @param[in]  ImageIndex    The ImageIndex of the FMP image.
     94                             It is the input parameter for FMP->GetImage().
     95   @param[in]  ImageName     The file name to hold the output FMP image.
     96 **/
     97 VOID
     98 DumpFmpImage (
     99   IN EFI_GUID  *ImageTypeId,
    100   IN UINTN     ImageIndex,
    101   IN CHAR16    *ImageName
    102   );
    103 
    104 /**
    105   Dump ESRT info.
    106 **/
    107 VOID
    108 DumpEsrtData (
    109   VOID
    110   );
    111 
    112 /**
    113   Read a file.
    114 
    115   @param[in]  FileName        The file to be read.
    116   @param[out] BufferSize      The file buffer size
    117   @param[out] Buffer          The file buffer
    118 
    119   @retval EFI_SUCCESS    Read file successfully
    120   @retval EFI_NOT_FOUND  File not found
    121 **/
    122 EFI_STATUS
    123 ReadFileToBuffer (
    124   IN  CHAR16                               *FileName,
    125   OUT UINTN                                *BufferSize,
    126   OUT VOID                                 **Buffer
    127   );
    128 
    129 /**
    130   Write a file.
    131 
    132   @param[in] FileName        The file to be written.
    133   @param[in] BufferSize      The file buffer size
    134   @param[in] Buffer          The file buffer
    135 
    136   @retval EFI_SUCCESS    Write file successfully
    137 **/
    138 EFI_STATUS
    139 WriteFileFromBuffer (
    140   IN  CHAR16                               *FileName,
    141   IN  UINTN                                BufferSize,
    142   IN  VOID                                 *Buffer
    143   );
    144 
    145 /**
    146   Converts a string to GUID value.
    147   Guid Format is xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
    148 
    149   @param[in]  Str              The registry format GUID string that contains the GUID value.
    150   @param[out] Guid             A pointer to the converted GUID value.
    151 
    152   @retval EFI_SUCCESS     The GUID string was successfully converted to the GUID value.
    153   @retval EFI_UNSUPPORTED The input string is not in registry format.
    154   @return others          Some error occurred when converting part of GUID value.
    155 
    156 **/
    157 EFI_STATUS
    158 InternalStrToGuid (
    159   IN  CHAR16   *Str,
    160   OUT EFI_GUID *Guid
    161   );
    162 
    163 /**
    164 
    165   This function parse application ARG.
    166 
    167   @return Status
    168 **/
    169 EFI_STATUS
    170 GetArg (
    171   VOID
    172   );
    173 
    174 /**
    175   Create UX capsule.
    176 
    177   @retval EFI_SUCCESS            The capsule header is appended.
    178   @retval EFI_UNSUPPORTED        Input parameter is not valid.
    179   @retval EFI_OUT_OF_RESOURCES   No enough resource to create UX capsule.
    180 **/
    181 EFI_STATUS
    182 CreateBmpFmp (
    183   VOID
    184   )
    185 {
    186   CHAR16                                        *OutputCapsuleName;
    187   VOID                                          *BmpBuffer;
    188   UINTN                                         FileSize;
    189   CHAR16                                        *BmpName;
    190   UINT8                                         *FullCapsuleBuffer;
    191   UINTN                                         FullCapsuleBufferSize;
    192   EFI_DISPLAY_CAPSULE                           *DisplayCapsule;
    193   EFI_STATUS                                    Status;
    194   EFI_GRAPHICS_OUTPUT_PROTOCOL                  *Gop;
    195 
    196   Status = gBS->LocateProtocol(&gEfiGraphicsOutputProtocolGuid, NULL, (VOID **)&Gop);
    197   if (EFI_ERROR(Status)) {
    198     Print(L"CapsuleApp: NO GOP is found.\n");
    199     return EFI_UNSUPPORTED;
    200   }
    201   Print(L"Current GOP: Mode - %d, ", Gop->Mode->Mode);
    202   Print(L"HorizontalResolution - %d, ", Gop->Mode->Info->HorizontalResolution);
    203   Print(L"VerticalResolution - %d\n", Gop->Mode->Info->VerticalResolution);
    204   // HorizontalResolution >= BMP_IMAGE_HEADER.PixelWidth
    205   // VerticalResolution   >= BMP_IMAGE_HEADER.PixelHeight
    206 
    207   if (Argc != 5) {
    208     Print(L"CapsuleApp: Invalid Parameter.\n");
    209     return EFI_UNSUPPORTED;
    210   }
    211 
    212   if (StrCmp(Argv[3], L"-O") != 0) {
    213     Print(L"CapsuleApp: NO output capsule name.\n");
    214     return EFI_UNSUPPORTED;
    215   }
    216   OutputCapsuleName = Argv[4];
    217 
    218   BmpBuffer = NULL;
    219   FileSize = 0;
    220   FullCapsuleBuffer = NULL;
    221 
    222   BmpName = Argv[2];
    223   Status = ReadFileToBuffer(BmpName, &FileSize, &BmpBuffer);
    224   if (EFI_ERROR(Status)) {
    225     Print(L"CapsuleApp: BMP image (%s) is not found.\n", BmpName);
    226     goto Done;
    227   }
    228 
    229   FullCapsuleBufferSize = sizeof(EFI_DISPLAY_CAPSULE) + FileSize;
    230   FullCapsuleBuffer = AllocatePool(FullCapsuleBufferSize);
    231   if (FullCapsuleBuffer == NULL) {
    232     Print(L"CapsuleApp: Capsule Buffer size (0x%x) too big.\n", FullCapsuleBufferSize);
    233     Status = EFI_OUT_OF_RESOURCES;
    234     goto Done;
    235   }
    236 
    237   DisplayCapsule = (EFI_DISPLAY_CAPSULE *)FullCapsuleBuffer;
    238   CopyGuid(&DisplayCapsule->CapsuleHeader.CapsuleGuid, &gWindowsUxCapsuleGuid);
    239   DisplayCapsule->CapsuleHeader.HeaderSize = sizeof(DisplayCapsule->CapsuleHeader);
    240   DisplayCapsule->CapsuleHeader.Flags = CAPSULE_FLAGS_PERSIST_ACROSS_RESET;
    241   DisplayCapsule->CapsuleHeader.CapsuleImageSize = (UINT32)FullCapsuleBufferSize;
    242 
    243   DisplayCapsule->ImagePayload.Version = 1;
    244   DisplayCapsule->ImagePayload.Checksum = 0;
    245   DisplayCapsule->ImagePayload.ImageType = 0; // BMP
    246   DisplayCapsule->ImagePayload.Reserved = 0;
    247   DisplayCapsule->ImagePayload.Mode = Gop->Mode->Mode;
    248   DisplayCapsule->ImagePayload.OffsetX = 0;
    249   DisplayCapsule->ImagePayload.OffsetY = 0;
    250 
    251   CopyMem((DisplayCapsule + 1), BmpBuffer, FileSize);
    252 
    253   DisplayCapsule->ImagePayload.Checksum = CalculateCheckSum8(FullCapsuleBuffer, FullCapsuleBufferSize);
    254 
    255   Status = WriteFileFromBuffer(OutputCapsuleName, FullCapsuleBufferSize, FullCapsuleBuffer);
    256   Print(L"CapsuleApp: Write %s %r\n", OutputCapsuleName, Status);
    257 
    258 Done:
    259   if (BmpBuffer != NULL) {
    260     FreePool(BmpBuffer);
    261   }
    262 
    263   if (FullCapsuleBuffer != NULL) {
    264     FreePool(FullCapsuleBuffer);
    265   }
    266 
    267   return Status;
    268 }
    269 
    270 /**
    271   Get ImageTypeId in the FMP capsule header.
    272 
    273   @param[in] CapsuleHeader  The FMP capsule image header.
    274 
    275   @return ImageTypeId
    276 **/
    277 EFI_GUID *
    278 GetCapsuleImageTypeId (
    279   IN EFI_CAPSULE_HEADER                            *CapsuleHeader
    280   )
    281 {
    282   EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER       *FmpCapsuleHeader;
    283   UINT64                                       *ItemOffsetList;
    284   EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *ImageHeader;
    285 
    286   FmpCapsuleHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *)((UINT8 *)CapsuleHeader + CapsuleHeader->HeaderSize);
    287   ItemOffsetList = (UINT64 *)(FmpCapsuleHeader + 1);
    288   if (FmpCapsuleHeader->PayloadItemCount == 0) {
    289     return NULL;
    290   }
    291   ImageHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *)((UINT8 *)FmpCapsuleHeader + ItemOffsetList[FmpCapsuleHeader->EmbeddedDriverCount]);
    292   return &ImageHeader->UpdateImageTypeId;
    293 }
    294 
    295 /**
    296   Get ESRT FwType according to ImageTypeId
    297 
    298   @param[in]  ImageTypeId   ImageTypeId of an FMP capsule.
    299 
    300   @return ESRT FwType
    301 **/
    302 UINT32
    303 GetEsrtFwType (
    304   IN  EFI_GUID                                      *ImageTypeId
    305   )
    306 {
    307   EFI_STATUS                 Status;
    308   EFI_SYSTEM_RESOURCE_TABLE  *Esrt;
    309   EFI_SYSTEM_RESOURCE_ENTRY  *EsrtEntry;
    310   UINTN                      Index;
    311 
    312   //
    313   // Check ESRT
    314   //
    315   Status = EfiGetSystemConfigurationTable(&gEfiSystemResourceTableGuid, (VOID **)&Esrt);
    316   if (!EFI_ERROR(Status)) {
    317     ASSERT(Esrt != NULL);
    318     EsrtEntry = (VOID *)(Esrt + 1);
    319     for (Index = 0; Index < Esrt->FwResourceCount; Index++, EsrtEntry++) {
    320       if (CompareGuid(&EsrtEntry->FwClass, ImageTypeId)) {
    321         return EsrtEntry->FwType;
    322       }
    323     }
    324   }
    325 
    326   return ESRT_FW_TYPE_UNKNOWN;
    327 }
    328 
    329 /**
    330   Append a capsule header on top of current image.
    331   This function follows Windows UEFI Firmware Update Platform document.
    332 
    333   @retval EFI_SUCCESS            The capsule header is appended.
    334   @retval EFI_UNSUPPORTED        Input parameter is not valid.
    335   @retval EFI_OUT_OF_RESOURCES   No enough resource to append capsule header.
    336 **/
    337 EFI_STATUS
    338 CreateNestedFmp (
    339   VOID
    340   )
    341 {
    342   CHAR16                                        *OutputCapsuleName;
    343   VOID                                          *CapsuleBuffer;
    344   UINTN                                         FileSize;
    345   CHAR16                                        *CapsuleName;
    346   UINT8                                         *FullCapsuleBuffer;
    347   UINTN                                         FullCapsuleBufferSize;
    348   EFI_CAPSULE_HEADER                            *NestedCapsuleHeader;
    349   EFI_GUID                                      *ImageTypeId;
    350   UINT32                                        FwType;
    351   EFI_STATUS                                    Status;
    352 
    353   if (Argc != 5) {
    354     Print(L"CapsuleApp: Invalid Parameter.\n");
    355     return EFI_UNSUPPORTED;
    356   }
    357 
    358   if (StrCmp(Argv[3], L"-O") != 0) {
    359     Print(L"CapsuleApp: NO output capsule name.\n");
    360     return EFI_UNSUPPORTED;
    361   }
    362   OutputCapsuleName = Argv[4];
    363 
    364   CapsuleBuffer = NULL;
    365   FileSize = 0;
    366   FullCapsuleBuffer = NULL;
    367 
    368   CapsuleName = Argv[2];
    369   Status = ReadFileToBuffer(CapsuleName, &FileSize, &CapsuleBuffer);
    370   if (EFI_ERROR(Status)) {
    371     Print(L"CapsuleApp: Capsule image (%s) is not found.\n", CapsuleName);
    372     goto Done;
    373   }
    374 
    375   ImageTypeId = GetCapsuleImageTypeId(CapsuleBuffer);
    376   if (ImageTypeId == NULL) {
    377     Print(L"CapsuleApp: Capsule ImageTypeId is not found.\n");
    378     goto Done;
    379   }
    380   FwType = GetEsrtFwType(ImageTypeId);
    381   if ((FwType != ESRT_FW_TYPE_SYSTEMFIRMWARE) && (FwType != ESRT_FW_TYPE_DEVICEFIRMWARE)) {
    382     Print(L"CapsuleApp: Capsule FwType is invalid.\n");
    383     goto Done;
    384   }
    385 
    386   FullCapsuleBufferSize = NESTED_CAPSULE_HEADER_SIZE + FileSize;
    387   FullCapsuleBuffer = AllocatePool(FullCapsuleBufferSize);
    388   if (FullCapsuleBuffer == NULL) {
    389     Print(L"CapsuleApp: Capsule Buffer size (0x%x) too big.\n", FullCapsuleBufferSize);
    390     Status = EFI_OUT_OF_RESOURCES;
    391     goto Done;
    392   }
    393 
    394   NestedCapsuleHeader = (EFI_CAPSULE_HEADER *)FullCapsuleBuffer;
    395   ZeroMem(NestedCapsuleHeader, NESTED_CAPSULE_HEADER_SIZE);
    396   CopyGuid(&NestedCapsuleHeader->CapsuleGuid, ImageTypeId);
    397   NestedCapsuleHeader->HeaderSize = NESTED_CAPSULE_HEADER_SIZE;
    398   NestedCapsuleHeader->Flags = (FwType == ESRT_FW_TYPE_DEVICEFIRMWARE) ? SYSTEM_FIRMWARE_FLAG : DEVICE_FIRMWARE_FLAG;
    399   NestedCapsuleHeader->CapsuleImageSize = (UINT32)FullCapsuleBufferSize;
    400 
    401   CopyMem((UINT8 *)NestedCapsuleHeader + NestedCapsuleHeader->HeaderSize, CapsuleBuffer, FileSize);
    402 
    403   Status = WriteFileFromBuffer(OutputCapsuleName, FullCapsuleBufferSize, FullCapsuleBuffer);
    404   Print(L"CapsuleApp: Write %s %r\n", OutputCapsuleName, Status);
    405 
    406 Done:
    407   if (CapsuleBuffer != NULL) {
    408     FreePool(CapsuleBuffer);
    409   }
    410 
    411   if (FullCapsuleBuffer != NULL) {
    412     FreePool(FullCapsuleBuffer);
    413   }
    414 
    415   return Status;
    416 }
    417 
    418 
    419 /**
    420   Clear capsule status variable.
    421 
    422   @retval EFI_SUCCESS            The capsule status variable is cleared.
    423 **/
    424 EFI_STATUS
    425 ClearCapsuleStatusVariable (
    426   VOID
    427   )
    428 {
    429   EFI_STATUS                          Status;
    430   UINT32                              Index;
    431   CHAR16                              CapsuleVarName[20];
    432   CHAR16                              *TempVarName;
    433 
    434   StrCpyS (CapsuleVarName, sizeof(CapsuleVarName)/sizeof(CapsuleVarName[0]), L"Capsule");
    435   TempVarName = CapsuleVarName + StrLen (CapsuleVarName);
    436   Index = 0;
    437 
    438   while (TRUE) {
    439     UnicodeSPrint (TempVarName, 5 * sizeof(CHAR16), L"%04x", Index);
    440 
    441     Status = gRT->SetVariable (
    442                     CapsuleVarName,
    443                     &gEfiCapsuleReportGuid,
    444                     EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS,
    445                     0,
    446                     (VOID *)NULL
    447                     );
    448     if (EFI_ERROR(Status)) {
    449       //
    450       // There is no capsule variables, quit
    451       //
    452       break;
    453     }
    454 
    455     Index++;
    456     if (Index > 0xFFFF) {
    457       break;
    458     }
    459   }
    460 
    461   return EFI_SUCCESS;
    462 }
    463 
    464 /**
    465   Build Gather list for a list of capsule images.
    466 
    467   @param[in]  CapsuleBuffer    An array of pointer to capsule images
    468   @param[in]  FileSize         An array of UINTN to capsule images size
    469   @param[in]  CapsuleNum       The count of capsule images
    470   @param[out] BlockDescriptors The block descriptors for the capsule images
    471 
    472   @retval EFI_SUCCESS The block descriptors for the capsule images are constructed.
    473 **/
    474 EFI_STATUS
    475 BuildGatherList (
    476   IN VOID                          **CapsuleBuffer,
    477   IN UINTN                         *FileSize,
    478   IN UINTN                         CapsuleNum,
    479   OUT EFI_CAPSULE_BLOCK_DESCRIPTOR **BlockDescriptors
    480   )
    481 {
    482   EFI_STATUS                    Status;
    483   EFI_CAPSULE_BLOCK_DESCRIPTOR  *BlockDescriptors1;
    484   EFI_CAPSULE_BLOCK_DESCRIPTOR  *BlockDescriptors2;
    485   EFI_CAPSULE_BLOCK_DESCRIPTOR  *BlockDescriptorPre;
    486   EFI_CAPSULE_BLOCK_DESCRIPTOR  *BlockDescriptorsHeader;
    487   EFI_CAPSULE_BLOCK_DESCRIPTOR  *TempBlockPtr;
    488   UINT8                         *TempDataPtr;
    489   UINTN                         SizeLeft;
    490   UINTN                         Size;
    491   INT32                         Count;
    492   INT32                         Number;
    493   UINTN                         Index;
    494 
    495   TempBlockPtr           = NULL;
    496   BlockDescriptors1      = NULL;
    497   BlockDescriptors2      = NULL;
    498   BlockDescriptorPre     = NULL;
    499   BlockDescriptorsHeader = NULL;
    500 
    501   for (Index = 0; Index < CapsuleNum; Index++) {
    502     //
    503     // Allocate memory for the descriptors.
    504     //
    505     if (NumberOfDescriptors == 1) {
    506       Count = 2;
    507     } else {
    508       Count = (INT32)(NumberOfDescriptors + 2) / 2;
    509     }
    510 
    511     Size               = Count * sizeof (EFI_CAPSULE_BLOCK_DESCRIPTOR);
    512     BlockDescriptors1  = AllocateRuntimeZeroPool (Size);
    513     if (BlockDescriptors1 == NULL) {
    514       Print (L"CapsuleApp: failed to allocate memory for descriptors\n");
    515       Status = EFI_OUT_OF_RESOURCES;
    516       goto ERREXIT;
    517     } else {
    518       Print (L"CapsuleApp: creating capsule descriptors at 0x%X\n", (UINTN) BlockDescriptors1);
    519       Print (L"CapsuleApp: capsule data starts          at 0x%X with size 0x%X\n", (UINTN) CapsuleBuffer, FileSize);
    520     }
    521 
    522     //
    523     // Record descirptor header
    524     //
    525     if (Index == 0) {
    526       BlockDescriptorsHeader = BlockDescriptors1;
    527     }
    528 
    529     if (BlockDescriptorPre != NULL) {
    530       BlockDescriptorPre->Union.ContinuationPointer = (UINTN) BlockDescriptors1;
    531       BlockDescriptorPre->Length = 0;
    532     }
    533 
    534     //
    535     // Fill them in
    536     //
    537     TempBlockPtr  = BlockDescriptors1;
    538     TempDataPtr   = CapsuleBuffer[Index];
    539     SizeLeft      = FileSize[Index];
    540     for (Number = 0; (Number < Count - 1) && (SizeLeft != 0); Number++) {
    541       //
    542       // Divide remaining data in half
    543       //
    544       if (NumberOfDescriptors != 1) {
    545         if (SizeLeft == 1) {
    546           Size = 1;
    547         } else {
    548           Size = SizeLeft / 2;
    549         }
    550       } else {
    551         Size = SizeLeft;
    552       }
    553       TempBlockPtr->Union.DataBlock    = (UINTN)TempDataPtr;
    554       TempBlockPtr->Length  = Size;
    555       Print (L"CapsuleApp: capsule block/size              0x%X/0x%X\n", (UINTN) TempDataPtr, Size);
    556       SizeLeft -= Size;
    557       TempDataPtr += Size;
    558       TempBlockPtr++;
    559     }
    560 
    561     //
    562     // Allocate the second list, point the first block's last entry to point
    563     // to this one, and fill this one in. Worst case is that the previous
    564     // list only had one element that pointed here, so we need at least two
    565     // elements -- one to point to all the data, another to terminate the list.
    566     //
    567     if ((NumberOfDescriptors != 1) && (SizeLeft != 0)) {
    568       Count = (INT32)(NumberOfDescriptors + 2) - Count;
    569       if (Count == 1) {
    570         Count++;
    571       }
    572 
    573       Size              = Count * sizeof (EFI_CAPSULE_BLOCK_DESCRIPTOR);
    574       BlockDescriptors2 = AllocateRuntimeZeroPool (Size);
    575       if (BlockDescriptors2 == NULL) {
    576         Print (L"CapsuleApp: failed to allocate memory for descriptors\n");
    577         Status = EFI_OUT_OF_RESOURCES;
    578         goto ERREXIT;
    579       }
    580 
    581       //
    582       // Point the first list's last element to point to this second list.
    583       //
    584       TempBlockPtr->Union.ContinuationPointer   = (UINTN) BlockDescriptors2;
    585 
    586       TempBlockPtr->Length  = 0;
    587       TempBlockPtr = BlockDescriptors2;
    588       for (Number = 0; Number < Count - 1; Number++) {
    589         //
    590         // If second-to-last one, then dump rest to this element
    591         //
    592         if (Number == (Count - 2)) {
    593           Size = SizeLeft;
    594         } else {
    595           //
    596           // Divide remaining data in half
    597           //
    598           if (SizeLeft == 1) {
    599             Size = 1;
    600           } else {
    601             Size = SizeLeft / 2;
    602           }
    603         }
    604 
    605         TempBlockPtr->Union.DataBlock    = (UINTN)TempDataPtr;
    606         TempBlockPtr->Length  = Size;
    607         Print (L"CapsuleApp: capsule block/size              0x%X/0x%X\n", (UINTN) TempDataPtr, Size);
    608         SizeLeft -= Size;
    609         TempDataPtr += Size;
    610         TempBlockPtr++;
    611         if (SizeLeft == 0) {
    612           break;
    613         }
    614       }
    615     }
    616 
    617     BlockDescriptorPre = TempBlockPtr;
    618     BlockDescriptors1  = NULL;
    619   }
    620 
    621   //
    622   // Null-terminate.
    623   //
    624   if (TempBlockPtr != NULL) {
    625     TempBlockPtr->Union.ContinuationPointer    = (UINTN)NULL;
    626     TempBlockPtr->Length  = 0;
    627     *BlockDescriptors = BlockDescriptorsHeader;
    628   }
    629 
    630   return EFI_SUCCESS;
    631 
    632 ERREXIT:
    633   if (BlockDescriptors1 != NULL) {
    634     FreePool(BlockDescriptors1);
    635   }
    636 
    637   if (BlockDescriptors2 != NULL) {
    638     FreePool(BlockDescriptors2);
    639   }
    640 
    641   return Status;
    642 }
    643 
    644 /**
    645   Clear the Gather list for a list of capsule images.
    646 
    647   @param[in]  BlockDescriptors The block descriptors for the capsule images
    648   @param[in]  CapsuleNum       The count of capsule images
    649 **/
    650 VOID
    651 CleanGatherList (
    652   IN EFI_CAPSULE_BLOCK_DESCRIPTOR   *BlockDescriptors,
    653   IN UINTN                          CapsuleNum
    654   )
    655 {
    656   EFI_CAPSULE_BLOCK_DESCRIPTOR   *TempBlockPtr;
    657   EFI_CAPSULE_BLOCK_DESCRIPTOR   *TempBlockPtr1;
    658   EFI_CAPSULE_BLOCK_DESCRIPTOR   *TempBlockPtr2;
    659   UINTN                          Index;
    660 
    661   if (BlockDescriptors != NULL) {
    662     TempBlockPtr1 = BlockDescriptors;
    663     while (1){
    664       TempBlockPtr = TempBlockPtr1;
    665       for (Index = 0; Index < CapsuleNum; Index++) {
    666         if (TempBlockPtr[Index].Length == 0) {
    667           break;
    668         }
    669       }
    670 
    671       if (TempBlockPtr[Index].Union.ContinuationPointer == (UINTN)NULL) {
    672         break;
    673       }
    674 
    675       TempBlockPtr2 = (VOID *) ((UINTN) TempBlockPtr->Union.ContinuationPointer);
    676       FreePool(TempBlockPtr1);
    677       TempBlockPtr1 = TempBlockPtr2;
    678     }
    679   }
    680 }
    681 
    682 /**
    683   Print APP usage.
    684 **/
    685 VOID
    686 PrintUsage (
    687   VOID
    688   )
    689 {
    690   Print(L"CapsuleApp:  usage\n");
    691   Print(L"  CapsuleApp <Capsule...>\n");
    692   Print(L"  CapsuleApp -S\n");
    693   Print(L"  CapsuleApp -C\n");
    694   Print(L"  CapsuleApp -P\n");
    695   Print(L"  CapsuleApp -E\n");
    696   Print(L"  CapsuleApp -G <BMP> -O <Capsule>\n");
    697   Print(L"  CapsuleApp -N <Capsule> -O <NestedCapsule>\n");
    698   Print(L"  CapsuleApp -D <Capsule>\n");
    699   Print(L"  CapsuleApp -P GET <ImageTypeId> <Index> -O <FileName>\n");
    700   Print(L"Parameter:\n");
    701   Print(L"  -S:  Dump capsule report variable (EFI_CAPSULE_REPORT_GUID),\n");
    702   Print(L"       which is defined in UEFI specification.\n");
    703   Print(L"  -C:  Clear capsule report variable (EFI_CAPSULE_RPORT_GUID),\n");
    704   Print(L"       which is defined in UEFI specification.\n");
    705   Print(L"  -P:  Dump UEFI FMP protocol info.\n");
    706   Print(L"  -E:  Dump UEFI ESRT table info.\n");
    707   Print(L"  -G:  Convert a BMP file to be a UX capsule,\n");
    708   Print(L"       according to Windows Firmware Update document\n");
    709   Print(L"  -N:  Append a Capsule Header to an existing capsule image,\n");
    710   Print(L"       according to Windows Firmware Update document\n");
    711   Print(L"  -O:  Output new Capsule file name\n");
    712   Print(L"  -D:  Dump Capsule image header information and FMP header information,\n");
    713   Print(L"       if it is an FMP capsule.\n");
    714 }
    715 
    716 /**
    717   Update Capsule image.
    718 
    719   @param[in]  ImageHandle     The image handle.
    720   @param[in]  SystemTable     The system table.
    721 
    722   @retval EFI_SUCCESS            Command completed successfully.
    723   @retval EFI_INVALID_PARAMETER  Command usage error.
    724   @retval EFI_NOT_FOUND          The input file can't be found.
    725 **/
    726 EFI_STATUS
    727 EFIAPI
    728 UefiMain (
    729   IN EFI_HANDLE        ImageHandle,
    730   IN EFI_SYSTEM_TABLE  *SystemTable
    731   )
    732 {
    733   EFI_STATUS                    Status;
    734   UINTN                         FileSize[MAX_CAPSULE_NUM];
    735   VOID                          *CapsuleBuffer[MAX_CAPSULE_NUM];
    736   EFI_CAPSULE_BLOCK_DESCRIPTOR  *BlockDescriptors;
    737   EFI_CAPSULE_HEADER             *CapsuleHeaderArray[MAX_CAPSULE_NUM + 1];
    738   UINT64                         MaxCapsuleSize;
    739   EFI_RESET_TYPE                 ResetType;
    740   BOOLEAN                        NeedReset;
    741   CHAR16                         *CapsuleName;
    742   UINTN                          CapsuleNum;
    743   UINTN                          Index;
    744 
    745   Status = GetArg();
    746   if (EFI_ERROR(Status)) {
    747     Print(L"Please use UEFI SHELL to run this application!\n", Status);
    748     return Status;
    749   }
    750   if (Argc < 2) {
    751     PrintUsage();
    752     return EFI_INVALID_PARAMETER;
    753   }
    754   if (StrCmp(Argv[1], L"-D") == 0) {
    755     Status = DumpCapsule(Argv[2]);
    756     return Status;
    757   }
    758   if (StrCmp(Argv[1], L"-G") == 0) {
    759     Status = CreateBmpFmp();
    760     return Status;
    761   }
    762   if (StrCmp(Argv[1], L"-N") == 0) {
    763     Status = CreateNestedFmp();
    764     return Status;
    765   }
    766   if (StrCmp(Argv[1], L"-S") == 0) {
    767     Status = DmpCapsuleStatusVariable();
    768     return EFI_SUCCESS;
    769   }
    770   if (StrCmp(Argv[1], L"-C") == 0) {
    771     Status = ClearCapsuleStatusVariable();
    772     return Status;
    773   }
    774   if (StrCmp(Argv[1], L"-P") == 0) {
    775     if (Argc == 2) {
    776       DumpFmpData();
    777     }
    778     if (Argc >= 3) {
    779       if (StrCmp(Argv[2], L"GET") == 0) {
    780         EFI_GUID  ImageTypeId;
    781         UINTN     ImageIndex;
    782         //
    783         // FMP->GetImage()
    784         //
    785         Status = InternalStrToGuid(Argv[3], &ImageTypeId);
    786         if (EFI_ERROR(Status)) {
    787           Print (L"Invalid ImageTypeId - %s\n", Argv[3]);
    788           return Status;
    789         }
    790         ImageIndex = StrDecimalToUintn(Argv[4]);
    791         if (StrCmp(Argv[5], L"-O") == 0) {
    792           DumpFmpImage(&ImageTypeId, ImageIndex, Argv[6]);
    793         }
    794       }
    795     }
    796     return EFI_SUCCESS;
    797   }
    798   if (StrCmp(Argv[1], L"-E") == 0) {
    799     DumpEsrtData();
    800     return EFI_SUCCESS;
    801   }
    802   CapsuleFirstIndex = 1;
    803   CapsuleLastIndex = Argc - 1;
    804   CapsuleNum = CapsuleLastIndex - CapsuleFirstIndex + 1;
    805 
    806   if (CapsuleFirstIndex > CapsuleLastIndex) {
    807     Print(L"CapsuleApp: NO capsule image.\n");
    808     return EFI_UNSUPPORTED;
    809   }
    810   if (CapsuleNum > MAX_CAPSULE_NUM) {
    811     Print(L"CapsuleApp: Too many capsule images.\n");
    812     return EFI_UNSUPPORTED;
    813   }
    814 
    815   ZeroMem(&CapsuleBuffer, sizeof(CapsuleBuffer));
    816   ZeroMem(&FileSize, sizeof(FileSize));
    817   BlockDescriptors = NULL;
    818 
    819   for (Index = 0; Index < CapsuleNum; Index++) {
    820     CapsuleName = Argv[CapsuleFirstIndex + Index];
    821     Status = ReadFileToBuffer(CapsuleName, &FileSize[Index], &CapsuleBuffer[Index]);
    822     if (EFI_ERROR(Status)) {
    823       Print(L"CapsuleApp: capsule image (%s) is not found.\n", CapsuleName);
    824       goto Done;
    825     }
    826   }
    827 
    828   //
    829   // Every capsule use 2 descriptor 1 for data 1 for end
    830   //
    831   Status = BuildGatherList(CapsuleBuffer, FileSize, CapsuleNum, &BlockDescriptors);
    832   if (EFI_ERROR(Status)) {
    833     goto Done;
    834   }
    835 
    836   //
    837   // Call the runtime service capsule.
    838   //
    839   NeedReset = FALSE;
    840   for (Index = 0; Index < CapsuleNum; Index++) {
    841     CapsuleHeaderArray[Index] = (EFI_CAPSULE_HEADER *) CapsuleBuffer[Index];
    842     if ((CapsuleHeaderArray[Index]->Flags & CAPSULE_FLAGS_PERSIST_ACROSS_RESET) != 0) {
    843       NeedReset = TRUE;
    844     }
    845   }
    846   CapsuleHeaderArray[CapsuleNum] = NULL;
    847 
    848   //
    849   // Inquire platform capability of UpdateCapsule.
    850   //
    851   Status = gRT->QueryCapsuleCapabilities (CapsuleHeaderArray, CapsuleNum, &MaxCapsuleSize, &ResetType);
    852   if (EFI_ERROR(Status)) {
    853     Print (L"CapsuleApp: failed to query capsule capability - %r\n", Status);
    854     goto Done;
    855   }
    856 
    857   for (Index = 0; Index < CapsuleNum; Index++) {
    858     if (FileSize[Index] > MaxCapsuleSize) {
    859       Print (L"CapsuleApp: capsule is too large to update, %ld is allowed\n", MaxCapsuleSize);
    860       Status = EFI_UNSUPPORTED;
    861       goto Done;
    862     }
    863   }
    864 
    865   //
    866   // Check whether the input capsule image has the flag of persist across system reset.
    867   //
    868   if (NeedReset) {
    869     Status = gRT->UpdateCapsule(CapsuleHeaderArray,CapsuleNum,(UINTN) BlockDescriptors);
    870     if (Status != EFI_SUCCESS) {
    871       Print (L"CapsuleApp: failed to update capsule - %r\n", Status);
    872       goto Done;
    873     }
    874     //
    875     // For capsule who has reset flag, after calling UpdateCapsule service,triger a
    876     // system reset to process capsule persist across a system reset.
    877     //
    878     gRT->ResetSystem (ResetType, EFI_SUCCESS, 0, NULL);
    879   } else {
    880     //
    881     // For capsule who has no reset flag, only call UpdateCapsule Service without a
    882     // system reset. The service will process the capsule immediately.
    883     //
    884     Status = gRT->UpdateCapsule (CapsuleHeaderArray,CapsuleNum,(UINTN) BlockDescriptors);
    885     if (Status != EFI_SUCCESS) {
    886       Print (L"CapsuleApp: failed to update capsule - %r\n", Status);
    887     }
    888   }
    889 
    890   Status = EFI_SUCCESS;
    891 
    892 Done:
    893   for (Index = 0; Index < CapsuleNum; Index++) {
    894     if (CapsuleBuffer[Index] != NULL) {
    895       FreePool (CapsuleBuffer[Index]);
    896     }
    897   }
    898 
    899   CleanGatherList(BlockDescriptors, CapsuleNum);
    900 
    901   return Status;
    902 }
    903