]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Application/CapsuleApp/CapsuleApp.c
MdeModulePkg/Application: Fix various typos
[mirror_edk2.git] / MdeModulePkg / Application / CapsuleApp / CapsuleApp.c
index 51372593de4ed125ddf674bb8ea7ae4d846559d4..40347147734b260edb25fc92105b80d67ca77e13 100644 (file)
@@ -1,50 +1,12 @@
 /** @file\r
   A shell application that triggers capsule update process.\r
 \r
-  Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>\r
-  This program and the accompanying materials\r
-  are licensed and made available under the terms and conditions of the BSD License\r
-  which accompanies this distribution.  The full text of the license may be found at\r
-  http://opensource.org/licenses/bsd-license.php\r
-\r
-  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
-  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+  Copyright (c) 2016 - 2019, Intel Corporation. All rights reserved.<BR>\r
+  SPDX-License-Identifier: BSD-2-Clause-Patent\r
 \r
 **/\r
 \r
-#include <Uefi.h>\r
-#include <Library/BaseLib.h>\r
-#include <Library/DebugLib.h>\r
-#include <Library/BaseMemoryLib.h>\r
-#include <Library/MemoryAllocationLib.h>\r
-#include <Library/UefiBootServicesTableLib.h>\r
-#include <Library/UefiRuntimeServicesTableLib.h>\r
-#include <Library/UefiLib.h>\r
-#include <Library/PrintLib.h>\r
-#include <Protocol/LoadedImage.h>\r
-#include <Protocol/SimpleFileSystem.h>\r
-#include <Protocol/GraphicsOutput.h>\r
-#include <Guid/FileInfo.h>\r
-#include <Guid/Gpt.h>\r
-#include <Guid/GlobalVariable.h>\r
-#include <Guid/CapsuleReport.h>\r
-#include <Guid/SystemResourceTable.h>\r
-#include <Guid/FmpCapsule.h>\r
-#include <IndustryStandard/WindowsUxCapsule.h>\r
-\r
-#define CAPSULE_HEADER_SIZE  0x20\r
-\r
-#define NESTED_CAPSULE_HEADER_SIZE  SIZE_4KB\r
-#define SYSTEM_FIRMWARE_FLAG 0x50000\r
-#define DEVICE_FIRMWARE_FLAG 0x78010\r
-\r
-#define MAJOR_VERSION   1\r
-#define MINOR_VERSION   0\r
-\r
-#define MAX_CAPSULE_NUM 10\r
-\r
-extern UINTN  Argc;\r
-extern CHAR16 **Argv;\r
+#include "CapsuleApp.h"\r
 \r
 //\r
 // Define how many block descriptors we want to test with.\r
@@ -53,124 +15,6 @@ UINTN  NumberOfDescriptors = 1;
 UINTN  CapsuleFirstIndex;\r
 UINTN  CapsuleLastIndex;\r
 \r
-/**\r
-  Dump capsule information\r
-\r
-  @param[in] CapsuleName  The name of the capsule image.\r
-\r
-  @retval EFI_SUCCESS            The capsule information is dumped.\r
-  @retval EFI_UNSUPPORTED        Input parameter is not valid.\r
-**/\r
-EFI_STATUS\r
-DumpCapsule (\r
-  IN CHAR16                                        *CapsuleName\r
-  );\r
-\r
-/**\r
-  Dump capsule status variable.\r
-\r
-  @retval EFI_SUCCESS            The capsule status variable is dumped.\r
-  @retval EFI_UNSUPPORTED        Input parameter is not valid.\r
-**/\r
-EFI_STATUS\r
-DmpCapsuleStatusVariable (\r
-  VOID\r
-  );\r
-\r
-/**\r
-  Dump FMP protocol info.\r
-**/\r
-VOID\r
-DumpFmpData (\r
-  VOID\r
-  );\r
-\r
-/**\r
-  Dump FMP image data.\r
-\r
-  @param[in]  ImageTypeId   The ImageTypeId of the FMP image.\r
-                            It is used to identify the FMP protocol.\r
-  @param[in]  ImageIndex    The ImageIndex of the FMP image.\r
-                            It is the input parameter for FMP->GetImage().\r
-  @param[in]  ImageName     The file name to hold the output FMP image.\r
-**/\r
-VOID\r
-DumpFmpImage (\r
-  IN EFI_GUID  *ImageTypeId,\r
-  IN UINTN     ImageIndex,\r
-  IN CHAR16    *ImageName\r
-  );\r
-\r
-/**\r
-  Dump ESRT info.\r
-**/\r
-VOID\r
-DumpEsrtData (\r
-  VOID\r
-  );\r
-\r
-/**\r
-  Read a file.\r
-\r
-  @param[in]  FileName        The file to be read.\r
-  @param[out] BufferSize      The file buffer size\r
-  @param[out] Buffer          The file buffer\r
-\r
-  @retval EFI_SUCCESS    Read file successfully\r
-  @retval EFI_NOT_FOUND  File not found\r
-**/\r
-EFI_STATUS\r
-ReadFileToBuffer (\r
-  IN  CHAR16                               *FileName,\r
-  OUT UINTN                                *BufferSize,\r
-  OUT VOID                                 **Buffer\r
-  );\r
-\r
-/**\r
-  Write a file.\r
-\r
-  @param[in] FileName        The file to be written.\r
-  @param[in] BufferSize      The file buffer size\r
-  @param[in] Buffer          The file buffer\r
-\r
-  @retval EFI_SUCCESS    Write file successfully\r
-**/\r
-EFI_STATUS\r
-WriteFileFromBuffer (\r
-  IN  CHAR16                               *FileName,\r
-  IN  UINTN                                BufferSize,\r
-  IN  VOID                                 *Buffer\r
-  );\r
-\r
-/**\r
-  Converts a string to GUID value.\r
-  Guid Format is xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx\r
-\r
-  @param[in]  Str              The registry format GUID string that contains the GUID value.\r
-  @param[out] Guid             A pointer to the converted GUID value.\r
-\r
-  @retval EFI_SUCCESS     The GUID string was successfully converted to the GUID value.\r
-  @retval EFI_UNSUPPORTED The input string is not in registry format.\r
-  @return others          Some error occurred when converting part of GUID value.\r
-\r
-**/\r
-EFI_STATUS\r
-StrToGuid (\r
-  IN  CHAR16   *Str,\r
-  OUT EFI_GUID *Guid\r
-  );\r
-\r
-/**\r
-\r
-  This function parse application ARG.\r
-\r
-  @return Status\r
-**/\r
-EFI_STATUS\r
-GetArg (\r
-  VOID\r
-  );\r
-\r
 /**\r
   Create UX capsule.\r
 \r
@@ -192,20 +36,26 @@ CreateBmpFmp (
   EFI_DISPLAY_CAPSULE                           *DisplayCapsule;\r
   EFI_STATUS                                    Status;\r
   EFI_GRAPHICS_OUTPUT_PROTOCOL                  *Gop;\r
+  EFI_GRAPHICS_OUTPUT_MODE_INFORMATION          *Info;\r
+  EFI_GRAPHICS_OUTPUT_BLT_PIXEL                 *GopBlt;\r
+  UINTN                                         GopBltSize;\r
+  UINTN                                         Height;\r
+  UINTN                                         Width;\r
 \r
   Status = gBS->LocateProtocol(&gEfiGraphicsOutputProtocolGuid, NULL, (VOID **)&Gop);\r
   if (EFI_ERROR(Status)) {\r
     Print(L"CapsuleApp: NO GOP is found.\n");\r
     return EFI_UNSUPPORTED;\r
   }\r
+  Info = Gop->Mode->Info;\r
   Print(L"Current GOP: Mode - %d, ", Gop->Mode->Mode);\r
-  Print(L"HorizontalResolution - %d, ", Gop->Mode->Info->HorizontalResolution);\r
-  Print(L"VerticalResolution - %d\n", Gop->Mode->Info->VerticalResolution);\r
+  Print(L"HorizontalResolution - %d, ", Info->HorizontalResolution);\r
+  Print(L"VerticalResolution - %d\n", Info->VerticalResolution);\r
   // HorizontalResolution >= BMP_IMAGE_HEADER.PixelWidth\r
   // VerticalResolution   >= BMP_IMAGE_HEADER.PixelHeight\r
 \r
   if (Argc != 5) {\r
-    Print(L"CapsuleApp: Invalid Parameter.\n");\r
+    Print(L"CapsuleApp: Incorrect parameter count.\n");\r
     return EFI_UNSUPPORTED;\r
   }\r
 \r
@@ -226,6 +76,35 @@ CreateBmpFmp (
     goto Done;\r
   }\r
 \r
+  GopBlt = NULL;\r
+  Status = TranslateBmpToGopBlt (\r
+             BmpBuffer,\r
+             FileSize,\r
+             &GopBlt,\r
+             &GopBltSize,\r
+             &Height,\r
+             &Width\r
+             );\r
+  if (EFI_ERROR(Status)) {\r
+    Print(L"CapsuleApp: BMP image (%s) is not valid.\n", BmpName);\r
+    goto Done;\r
+  }\r
+  if (GopBlt != NULL) {\r
+    FreePool (GopBlt);\r
+  }\r
+  Print(L"BMP image (%s), Width - %d, Height - %d\n", BmpName, Width, Height);\r
+\r
+  if (Height > Info->VerticalResolution) {\r
+    Status = EFI_INVALID_PARAMETER;\r
+    Print(L"CapsuleApp: BMP image (%s) height is larger than current resolution.\n", BmpName);\r
+    goto Done;\r
+  }\r
+  if (Width > Info->HorizontalResolution) {\r
+    Status = EFI_INVALID_PARAMETER;\r
+    Print(L"CapsuleApp: BMP image (%s) width is larger than current resolution.\n", BmpName);\r
+    goto Done;\r
+  }\r
+\r
   FullCapsuleBufferSize = sizeof(EFI_DISPLAY_CAPSULE) + FileSize;\r
   FullCapsuleBuffer = AllocatePool(FullCapsuleBufferSize);\r
   if (FullCapsuleBuffer == NULL) {\r
@@ -245,8 +124,27 @@ CreateBmpFmp (
   DisplayCapsule->ImagePayload.ImageType = 0; // BMP\r
   DisplayCapsule->ImagePayload.Reserved = 0;\r
   DisplayCapsule->ImagePayload.Mode = Gop->Mode->Mode;\r
-  DisplayCapsule->ImagePayload.OffsetX = 0;\r
-  DisplayCapsule->ImagePayload.OffsetY = 0;\r
+\r
+  //\r
+  // Center the bitmap horizontally\r
+  //\r
+  DisplayCapsule->ImagePayload.OffsetX = (UINT32)((Info->HorizontalResolution - Width) / 2);\r
+\r
+  //\r
+  // Put bitmap 3/4 down the display.  If bitmap is too tall, then align bottom\r
+  // of bitmap at bottom of display.\r
+  //\r
+  DisplayCapsule->ImagePayload.OffsetY =\r
+    MIN (\r
+      (UINT32)(Info->VerticalResolution - Height),\r
+      (UINT32)(((3 * Info->VerticalResolution) - (2 * Height)) / 4)\r
+      );\r
+\r
+  Print(L"BMP image (%s), OffsetX - %d, OffsetY - %d\n",\r
+    BmpName,\r
+    DisplayCapsule->ImagePayload.OffsetX,\r
+    DisplayCapsule->ImagePayload.OffsetY\r
+    );\r
 \r
   CopyMem((DisplayCapsule + 1), BmpBuffer, FileSize);\r
 \r
@@ -326,6 +224,60 @@ GetEsrtFwType (
   return ESRT_FW_TYPE_UNKNOWN;\r
 }\r
 \r
+/**\r
+  Validate if it is valid capsule header\r
+\r
+  This function assumes the caller provided correct CapsuleHeader pointer\r
+  and CapsuleSize.\r
+\r
+  This function validates the fields in EFI_CAPSULE_HEADER.\r
+\r
+  @param[in] CapsuleHeader  Points to a capsule header.\r
+  @param[in] CapsuleSize    Size of the whole capsule image.\r
+\r
+**/\r
+BOOLEAN\r
+IsValidCapsuleHeader (\r
+  IN EFI_CAPSULE_HEADER     *CapsuleHeader,\r
+  IN UINT64                 CapsuleSize\r
+  )\r
+{\r
+  if (CapsuleSize < sizeof (EFI_CAPSULE_HEADER)) {\r
+    return FALSE;\r
+  }\r
+  if (CapsuleHeader->CapsuleImageSize != CapsuleSize) {\r
+    return FALSE;\r
+  }\r
+  if (CapsuleHeader->HeaderSize > CapsuleHeader->CapsuleImageSize) {\r
+    return FALSE;\r
+  }\r
+  if (CapsuleHeader->HeaderSize < sizeof (EFI_CAPSULE_HEADER)) {\r
+    return FALSE;\r
+  }\r
+\r
+  return TRUE;\r
+}\r
+\r
+/**\r
+  Return if this CapsuleGuid is a FMP capsule GUID or not.\r
+\r
+  @param[in] CapsuleGuid A pointer to EFI_GUID\r
+\r
+  @retval TRUE  It is a FMP capsule GUID.\r
+  @retval FALSE It is not a FMP capsule GUID.\r
+**/\r
+BOOLEAN\r
+IsFmpCapsuleGuid (\r
+  IN EFI_GUID  *CapsuleGuid\r
+  )\r
+{\r
+  if (CompareGuid(&gEfiFmpCapsuleGuid, CapsuleGuid)) {\r
+    return TRUE;\r
+  }\r
+\r
+  return FALSE;\r
+}\r
+\r
 /**\r
   Append a capsule header on top of current image.\r
   This function follows Windows UEFI Firmware Update Platform document.\r
@@ -351,7 +303,7 @@ CreateNestedFmp (
   EFI_STATUS                                    Status;\r
 \r
   if (Argc != 5) {\r
-    Print(L"CapsuleApp: Invalid Parameter.\n");\r
+    Print(L"CapsuleApp: Incorrect parameter count.\n");\r
     return EFI_UNSUPPORTED;\r
   }\r
 \r
@@ -371,15 +323,28 @@ CreateNestedFmp (
     Print(L"CapsuleApp: Capsule image (%s) is not found.\n", CapsuleName);\r
     goto Done;\r
   }\r
+  if (!IsValidCapsuleHeader (CapsuleBuffer, FileSize)) {\r
+    Print(L"CapsuleApp: Capsule image (%s) is not a valid capsule.\n", CapsuleName);\r
+    Status = EFI_INVALID_PARAMETER;\r
+    goto Done;\r
+  }\r
+\r
+  if (!IsFmpCapsuleGuid (&((EFI_CAPSULE_HEADER *) CapsuleBuffer)->CapsuleGuid)) {\r
+    Print(L"CapsuleApp: Capsule image (%s) is not a FMP capsule.\n", CapsuleName);\r
+    Status = EFI_INVALID_PARAMETER;\r
+    goto Done;\r
+  }\r
 \r
   ImageTypeId = GetCapsuleImageTypeId(CapsuleBuffer);\r
   if (ImageTypeId == NULL) {\r
     Print(L"CapsuleApp: Capsule ImageTypeId is not found.\n");\r
+    Status = EFI_INVALID_PARAMETER;\r
     goto Done;\r
   }\r
   FwType = GetEsrtFwType(ImageTypeId);\r
   if ((FwType != ESRT_FW_TYPE_SYSTEMFIRMWARE) && (FwType != ESRT_FW_TYPE_DEVICEFIRMWARE)) {\r
     Print(L"CapsuleApp: Capsule FwType is invalid.\n");\r
+    Status = EFI_INVALID_PARAMETER;\r
     goto Done;\r
   }\r
 \r
@@ -395,7 +360,7 @@ CreateNestedFmp (
   ZeroMem(NestedCapsuleHeader, NESTED_CAPSULE_HEADER_SIZE);\r
   CopyGuid(&NestedCapsuleHeader->CapsuleGuid, ImageTypeId);\r
   NestedCapsuleHeader->HeaderSize = NESTED_CAPSULE_HEADER_SIZE;\r
-  NestedCapsuleHeader->Flags = (FwType == ESRT_FW_TYPE_DEVICEFIRMWARE) ? SYSTEM_FIRMWARE_FLAG : DEVICE_FIRMWARE_FLAG;\r
+  NestedCapsuleHeader->Flags = (FwType == ESRT_FW_TYPE_SYSTEMFIRMWARE) ? SYSTEM_FIRMWARE_FLAG : DEVICE_FIRMWARE_FLAG;\r
   NestedCapsuleHeader->CapsuleImageSize = (UINT32)FullCapsuleBufferSize;\r
 \r
   CopyMem((UINT8 *)NestedCapsuleHeader + NestedCapsuleHeader->HeaderSize, CapsuleBuffer, FileSize);\r
@@ -430,11 +395,13 @@ ClearCapsuleStatusVariable (
   UINT32                              Index;\r
   CHAR16                              CapsuleVarName[20];\r
   CHAR16                              *TempVarName;\r
+  BOOLEAN                             Found;\r
 \r
   StrCpyS (CapsuleVarName, sizeof(CapsuleVarName)/sizeof(CapsuleVarName[0]), L"Capsule");\r
   TempVarName = CapsuleVarName + StrLen (CapsuleVarName);\r
   Index = 0;\r
 \r
+  Found = FALSE;\r
   while (TRUE) {\r
     UnicodeSPrint (TempVarName, 5 * sizeof(CHAR16), L"%04x", Index);\r
 \r
@@ -445,12 +412,15 @@ ClearCapsuleStatusVariable (
                     0,\r
                     (VOID *)NULL\r
                     );\r
-    if (EFI_ERROR(Status)) {\r
+    if (Status == EFI_NOT_FOUND) {\r
       //\r
-      // There is no capsule variables, quit\r
+      // There is no more capsule variables, quit\r
       //\r
       break;\r
     }\r
+    Found = TRUE;\r
+\r
+    Print (L"Clear %s %r\n", CapsuleVarName, Status);\r
 \r
     Index++;\r
     if (Index > 0xFFFF) {\r
@@ -458,6 +428,10 @@ ClearCapsuleStatusVariable (
     }\r
   }\r
 \r
+  if (!Found) {\r
+    Print (L"No any Capsule#### variable found\n");\r
+  }\r
+\r
   return EFI_SUCCESS;\r
 }\r
 \r
@@ -516,11 +490,11 @@ BuildGatherList (
       goto ERREXIT;\r
     } else {\r
       Print (L"CapsuleApp: creating capsule descriptors at 0x%X\n", (UINTN) BlockDescriptors1);\r
-      Print (L"CapsuleApp: capsule data starts          at 0x%X with size 0x%X\n", (UINTN) CapsuleBuffer, FileSize);\r
+      Print (L"CapsuleApp: capsule data starts          at 0x%X with size 0x%X\n", (UINTN) CapsuleBuffer[Index], FileSize[Index]);\r
     }\r
 \r
     //\r
-    // Record descirptor header\r
+    // Record descriptor header\r
     //\r
     if (Index == 0) {\r
       BlockDescriptorsHeader = BlockDescriptors1;\r
@@ -672,7 +646,7 @@ CleanGatherList (
         break;\r
       }\r
 \r
-      TempBlockPtr2 = (VOID *) ((UINTN) TempBlockPtr->Union.ContinuationPointer);\r
+      TempBlockPtr2 = (VOID *) ((UINTN) TempBlockPtr[Index].Union.ContinuationPointer);\r
       FreePool(TempBlockPtr1);\r
       TempBlockPtr1 = TempBlockPtr2;\r
     }\r
@@ -688,29 +662,41 @@ PrintUsage (
   )\r
 {\r
   Print(L"CapsuleApp:  usage\n");\r
-  Print(L"  CapsuleApp <Capsule...>\n");\r
+  Print(L"  CapsuleApp <Capsule...> [-NR] [-OD [FSx]]\n");\r
   Print(L"  CapsuleApp -S\n");\r
   Print(L"  CapsuleApp -C\n");\r
   Print(L"  CapsuleApp -P\n");\r
   Print(L"  CapsuleApp -E\n");\r
+  Print(L"  CapsuleApp -L\n");\r
+  Print(L"  CapsuleApp -L INFO\n");\r
+  Print(L"  CapsuleApp -F\n");\r
   Print(L"  CapsuleApp -G <BMP> -O <Capsule>\n");\r
   Print(L"  CapsuleApp -N <Capsule> -O <NestedCapsule>\n");\r
   Print(L"  CapsuleApp -D <Capsule>\n");\r
   Print(L"  CapsuleApp -P GET <ImageTypeId> <Index> -O <FileName>\n");\r
   Print(L"Parameter:\n");\r
+  Print(L"  -NR: No reset will be triggered for the capsule\n");\r
+  Print(L"       with CAPSULE_FLAGS_PERSIST_ACROSS_RESET and without CAPSULE_FLAGS_INITIATE_RESET.\n");\r
+  Print(L"  -OD: Delivery of Capsules via file on Mass Storage device.\n");\r
   Print(L"  -S:  Dump capsule report variable (EFI_CAPSULE_REPORT_GUID),\n");\r
   Print(L"       which is defined in UEFI specification.\n");\r
-  Print(L"  -C:  Clear capsule report variable (EFI_CAPSULE_RPORT_GUID),\n");\r
+  Print(L"  -C:  Clear capsule report variable (EFI_CAPSULE_REPORT_GUID),\n");\r
   Print(L"       which is defined in UEFI specification.\n");\r
-  Print(L"  -P:  Dump UEFI FMP protocol info.\n");\r
+  Print(L"  -P:  Dump UEFI FMP protocol info, or get image with specified\n");\r
+  Print(L"       ImageTypeId and Index (decimal format) to a file if 'GET'\n");\r
+  Print(L"       option is used.\n");\r
   Print(L"  -E:  Dump UEFI ESRT table info.\n");\r
-  Print(L"  -G:  Convert a BMP file to be a UX capsule,\n");\r
+  Print(L"  -L:  Dump provisioned capsule image information.\n");\r
+  Print(L"  -F:  Dump all EFI System Partition.\n");\r
+  Print(L"  -G:  Convert a BMP file to be an UX capsule,\n");\r
   Print(L"       according to Windows Firmware Update document\n");\r
-  Print(L"  -N:  Append a Capsule Header to an existing capsule image,\n");\r
+  Print(L"  -N:  Append a Capsule Header to an existing FMP capsule image\n");\r
+  Print(L"       with its ImageTypeId supported by the system,\n");\r
   Print(L"       according to Windows Firmware Update document\n");\r
   Print(L"  -O:  Output new Capsule file name\n");\r
-  Print(L"  -D:  Dump Capsule image header information and FMP header information,\n");\r
-  Print(L"       if it is an FMP capsule.\n");\r
+  Print(L"  -D:  Dump Capsule image header information, image payload\n");\r
+  Print(L"       information if it is an UX capsule and FMP header\n");\r
+  Print(L"       information if it is a FMP capsule.\n");\r
 }\r
 \r
 /**\r
@@ -720,7 +706,8 @@ PrintUsage (
   @param[in]  SystemTable     The system table.\r
 \r
   @retval EFI_SUCCESS            Command completed successfully.\r
-  @retval EFI_INVALID_PARAMETER  Command usage error.\r
+  @retval EFI_UNSUPPORTED        Command usage unsupported.\r
+  @retval EFI_INVALID_PARAMETER  Command usage invalid.\r
   @retval EFI_NOT_FOUND          The input file can't be found.\r
 **/\r
 EFI_STATUS\r
@@ -731,16 +718,29 @@ UefiMain (
   )\r
 {\r
   EFI_STATUS                    Status;\r
-  UINTN                         FileSize[MAX_CAPSULE_NUM];\r
+  RETURN_STATUS                 RStatus;\r
+  UINTN                         CapsuleBufferSize[MAX_CAPSULE_NUM];\r
   VOID                          *CapsuleBuffer[MAX_CAPSULE_NUM];\r
   EFI_CAPSULE_BLOCK_DESCRIPTOR  *BlockDescriptors;\r
-  EFI_CAPSULE_HEADER             *CapsuleHeaderArray[MAX_CAPSULE_NUM + 1];\r
-  UINT64                         MaxCapsuleSize;\r
-  EFI_RESET_TYPE                 ResetType;\r
-  BOOLEAN                        NeedReset;\r
-  CHAR16                         *CapsuleName;\r
-  UINTN                          CapsuleNum;\r
-  UINTN                          Index;\r
+  EFI_CAPSULE_HEADER            *CapsuleHeaderArray[MAX_CAPSULE_NUM + 1];\r
+  UINT64                        MaxCapsuleSize;\r
+  EFI_RESET_TYPE                ResetType;\r
+  BOOLEAN                       NeedReset;\r
+  BOOLEAN                       NoReset;\r
+  BOOLEAN                       CapsuleOnDisk;\r
+  CHAR16                        *CapsuleName;\r
+  CHAR16                        *CapsuleNames[MAX_CAPSULE_NUM];\r
+  CHAR16                        *MapFsStr;\r
+  UINTN                         CapsuleNum;\r
+  UINTN                         Index;\r
+  UINTN                         ParaOdIndex;\r
+  UINTN                         ParaNrIndex;\r
+  EFI_GUID                      ImageTypeId;\r
+  UINTN                         ImageIndex;\r
+\r
+  BlockDescriptors  = NULL;\r
+  MapFsStr          = NULL;\r
+  CapsuleNum        = 0;\r
 \r
   Status = GetArg();\r
   if (EFI_ERROR(Status)) {\r
@@ -749,9 +749,13 @@ UefiMain (
   }\r
   if (Argc < 2) {\r
     PrintUsage();\r
-    return EFI_INVALID_PARAMETER;\r
+    return EFI_UNSUPPORTED;\r
   }\r
   if (StrCmp(Argv[1], L"-D") == 0) {\r
+    if (Argc != 3) {\r
+      Print(L"CapsuleApp: Incorrect parameter count.\n");\r
+      return EFI_UNSUPPORTED;\r
+    }\r
     Status = DumpCapsule(Argv[2]);\r
     return Status;\r
   }\r
@@ -764,7 +768,7 @@ UefiMain (
     return Status;\r
   }\r
   if (StrCmp(Argv[1], L"-S") == 0) {\r
-    Status = DmpCapsuleStatusVariable();\r
+    Status = DumpCapsuleStatusVariable();\r
     return EFI_SUCCESS;\r
   }\r
   if (StrCmp(Argv[1], L"-C") == 0) {\r
@@ -776,31 +780,109 @@ UefiMain (
       DumpFmpData();\r
     }\r
     if (Argc >= 3) {\r
-      if (StrCmp(Argv[2], L"GET") == 0) {\r
-        EFI_GUID  ImageTypeId;\r
-        UINTN     ImageIndex;\r
+      if (StrCmp(Argv[2], L"GET") != 0) {\r
+        Print(L"CapsuleApp: Unrecognized option(%s).\n", Argv[2]);\r
+        return EFI_UNSUPPORTED;\r
+      } else {\r
+        if (Argc != 7) {\r
+          Print(L"CapsuleApp: Incorrect parameter count.\n");\r
+          return EFI_UNSUPPORTED;\r
+        }\r
+\r
         //\r
         // FMP->GetImage()\r
         //\r
-        Status = StrToGuid(Argv[3], &ImageTypeId);\r
-        if (EFI_ERROR(Status)) {\r
+        RStatus = StrToGuid (Argv[3], &ImageTypeId);\r
+        if (RETURN_ERROR (RStatus) || (Argv[3][GUID_STRING_LENGTH] != L'\0')) {\r
           Print (L"Invalid ImageTypeId - %s\n", Argv[3]);\r
-          return Status;\r
+          return EFI_INVALID_PARAMETER;\r
         }\r
         ImageIndex = StrDecimalToUintn(Argv[4]);\r
-        if (StrCmp(Argv[5], L"-O") == 0) {\r
-          DumpFmpImage(&ImageTypeId, ImageIndex, Argv[6]);\r
+        if (StrCmp(Argv[5], L"-O") != 0) {\r
+          Print(L"CapsuleApp: NO output file name.\n");\r
+          return EFI_UNSUPPORTED;\r
         }\r
+        DumpFmpImage(&ImageTypeId, ImageIndex, Argv[6]);\r
       }\r
     }\r
     return EFI_SUCCESS;\r
   }\r
+\r
   if (StrCmp(Argv[1], L"-E") == 0) {\r
     DumpEsrtData();\r
     return EFI_SUCCESS;\r
   }\r
+\r
+  if (StrCmp(Argv[1], L"-L") == 0) {\r
+    if (Argc >= 3 && StrCmp(Argv[2], L"INFO") == 0) {\r
+      DumpProvisionedCapsule(TRUE);\r
+    } else {\r
+      DumpProvisionedCapsule(FALSE);\r
+    }\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  if (StrCmp(Argv[1], L"-F") == 0) {\r
+    DumpAllEfiSysPartition();\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  if (Argv[1][0] == L'-') {\r
+    Print(L"CapsuleApp: Unrecognized option(%s).\n", Argv[1]);\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
   CapsuleFirstIndex = 1;\r
-  CapsuleLastIndex = Argc - 1;\r
+  NoReset = FALSE;\r
+  CapsuleOnDisk = FALSE;\r
+  ParaOdIndex = 0;\r
+  ParaNrIndex = 0;\r
+\r
+  for (Index = 1; Index < Argc; Index++) {\r
+    if (StrCmp(Argv[Index], L"-OD") == 0) {\r
+      ParaOdIndex = Index;\r
+      CapsuleOnDisk = TRUE;\r
+    } else if (StrCmp(Argv[Index], L"-NR") == 0) {\r
+      ParaNrIndex = Index;\r
+      NoReset = TRUE;\r
+    }\r
+  }\r
+\r
+  if (ParaOdIndex > ParaNrIndex) {\r
+    if (ParaNrIndex != 0) {\r
+      CapsuleLastIndex = ParaNrIndex - 1;\r
+    } else {\r
+      CapsuleLastIndex = ParaOdIndex - 1;\r
+    }\r
+\r
+    if (ParaOdIndex == Argc -1) {\r
+      MapFsStr = NULL;\r
+    } else if (ParaOdIndex == Argc - 2) {\r
+      MapFsStr = Argv[Argc-1];\r
+    } else {\r
+      Print (L"CapsuleApp: Cannot specify more than one FS mapping!\n");\r
+      Status = EFI_INVALID_PARAMETER;\r
+      goto Done;\r
+    }\r
+  } else if (ParaOdIndex < ParaNrIndex) {\r
+    if (ParaOdIndex != 0) {\r
+      CapsuleLastIndex = ParaOdIndex - 1;\r
+      if (ParaOdIndex == ParaNrIndex - 1) {\r
+        MapFsStr = NULL;\r
+      } else if (ParaOdIndex == ParaNrIndex - 2) {\r
+        MapFsStr = Argv[ParaOdIndex + 1];\r
+      } else {\r
+        Print (L"CapsuleApp: Cannot specify more than one FS mapping!\n");\r
+        Status = EFI_INVALID_PARAMETER;\r
+        goto Done;\r
+      }\r
+    } else {\r
+      CapsuleLastIndex = ParaNrIndex - 1;\r
+    }\r
+  } else {\r
+    CapsuleLastIndex = Argc - 1;\r
+  }\r
+\r
   CapsuleNum = CapsuleLastIndex - CapsuleFirstIndex + 1;\r
 \r
   if (CapsuleFirstIndex > CapsuleLastIndex) {\r
@@ -813,22 +895,27 @@ UefiMain (
   }\r
 \r
   ZeroMem(&CapsuleBuffer, sizeof(CapsuleBuffer));\r
-  ZeroMem(&FileSize, sizeof(FileSize));\r
+  ZeroMem(&CapsuleBufferSize, sizeof(CapsuleBufferSize));\r
   BlockDescriptors = NULL;\r
 \r
   for (Index = 0; Index < CapsuleNum; Index++) {\r
     CapsuleName = Argv[CapsuleFirstIndex + Index];\r
-    Status = ReadFileToBuffer(CapsuleName, &FileSize[Index], &CapsuleBuffer[Index]);\r
+    Status = ReadFileToBuffer(CapsuleName, &CapsuleBufferSize[Index], &CapsuleBuffer[Index]);\r
     if (EFI_ERROR(Status)) {\r
       Print(L"CapsuleApp: capsule image (%s) is not found.\n", CapsuleName);\r
       goto Done;\r
     }\r
+    if (!IsValidCapsuleHeader (CapsuleBuffer[Index], CapsuleBufferSize[Index])) {\r
+      Print(L"CapsuleApp: Capsule image (%s) is not a valid capsule.\n", CapsuleName);\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
+    CapsuleNames[Index] = CapsuleName;\r
   }\r
 \r
   //\r
   // Every capsule use 2 descriptor 1 for data 1 for end\r
   //\r
-  Status = BuildGatherList(CapsuleBuffer, FileSize, CapsuleNum, &BlockDescriptors);\r
+  Status = BuildGatherList(CapsuleBuffer, CapsuleBufferSize, CapsuleNum, &BlockDescriptors);\r
   if (EFI_ERROR(Status)) {\r
     goto Done;\r
   }\r
@@ -855,13 +942,30 @@ UefiMain (
   }\r
 \r
   for (Index = 0; Index < CapsuleNum; Index++) {\r
-    if (FileSize[Index] > MaxCapsuleSize) {\r
+    if (CapsuleBufferSize[Index] > MaxCapsuleSize) {\r
       Print (L"CapsuleApp: capsule is too large to update, %ld is allowed\n", MaxCapsuleSize);\r
       Status = EFI_UNSUPPORTED;\r
       goto Done;\r
     }\r
   }\r
 \r
+  //\r
+  // Check whether is capsule on disk.\r
+  //\r
+  if (CapsuleOnDisk) {\r
+    Status = ProcessCapsuleOnDisk (CapsuleBuffer, CapsuleBufferSize, CapsuleNames, MapFsStr, CapsuleNum);\r
+    if (Status != EFI_SUCCESS) {\r
+      Print (L"CapsuleApp: failed to update capsule - %r\n", Status);\r
+      goto Done;\r
+    } else {\r
+      if (!NoReset) {\r
+        gRT->ResetSystem (ResetType, EFI_SUCCESS, 0, NULL);\r
+      } else {\r
+        goto Done;\r
+      }\r
+    }\r
+  }\r
+\r
   //\r
   // Check whether the input capsule image has the flag of persist across system reset.\r
   //\r
@@ -872,10 +976,19 @@ UefiMain (
       goto Done;\r
     }\r
     //\r
-    // For capsule who has reset flag, after calling UpdateCapsule service,triger a\r
-    // system reset to process capsule persist across a system reset.\r
+    // For capsule with CAPSULE_FLAGS_PERSIST_ACROSS_RESET + CAPSULE_FLAGS_INITIATE_RESET,\r
+    // a system reset should have been triggered by gRT->UpdateCapsule() calling above.\r
     //\r
-    gRT->ResetSystem (ResetType, EFI_SUCCESS, 0, NULL);\r
+    // For capsule with CAPSULE_FLAGS_PERSIST_ACROSS_RESET and without CAPSULE_FLAGS_INITIATE_RESET,\r
+    // check if -NR (no-reset) has been specified or not.\r
+    //\r
+    if (!NoReset) {\r
+      //\r
+      // For capsule who has reset flag and no -NR (no-reset) has been specified, after calling UpdateCapsule service,\r
+      // trigger a system reset to process capsule persist across a system reset.\r
+      //\r
+      gRT->ResetSystem (ResetType, EFI_SUCCESS, 0, NULL);\r
+    }\r
   } else {\r
     //\r
     // For capsule who has no reset flag, only call UpdateCapsule Service without a\r