]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Application/CapsuleApp/CapsuleApp.c
MdeModulePkg CapsuleApp: Check Arg count for -D option
[mirror_edk2.git] / MdeModulePkg / Application / CapsuleApp / CapsuleApp.c
index 81a98ae705286bb1b64b3fab85e59f8e18e152f7..90f1a02d9af6f8dc70c68281e8342c6d455cf12b 100644 (file)
@@ -1,7 +1,7 @@
 /** @file\r
   A shell application that triggers capsule update process.\r
 \r
-  Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>\r
+  Copyright (c) 2016 - 2018, 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
 #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 <Library/BmpSupportLib.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
@@ -38,9 +35,6 @@
 #define SYSTEM_FIRMWARE_FLAG 0x50000\r
 #define DEVICE_FIRMWARE_FLAG 0x78010\r
 \r
-#define EFI_CAPSULE_FROM_FILE_DIR                           L"\\EFI\\UpdateCapsule\\"\r
-#define EFI_OS_INDICATIONS_FILE_CAPSULE_DELIVERY_SUPPORTED  0x0000000000000004\r
-\r
 #define MAJOR_VERSION   1\r
 #define MINOR_VERSION   0\r
 \r
@@ -88,6 +82,22 @@ DumpFmpData (
   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
@@ -104,7 +114,8 @@ DumpEsrtData (
   @param[out] Buffer          The file buffer\r
 \r
   @retval EFI_SUCCESS    Read file successfully\r
-  @retval EFI_NOT_FOUND  File not found\r
+  @retval EFI_NOT_FOUND  Shell protocol or file not found\r
+  @retval others         Read file failed\r
 **/\r
 EFI_STATUS\r
 ReadFileToBuffer (\r
@@ -121,6 +132,8 @@ ReadFileToBuffer (
   @param[in] Buffer          The file buffer\r
 \r
   @retval EFI_SUCCESS    Write file successfully\r
+  @retval EFI_NOT_FOUND  Shell protocol not found\r
+  @retval others         Write file failed\r
 **/\r
 EFI_STATUS\r
 WriteFileFromBuffer (\r
@@ -161,15 +174,21 @@ 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
@@ -195,6 +214,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
@@ -214,8 +262,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
@@ -364,7 +431,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
@@ -485,7 +552,7 @@ 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
@@ -641,7 +708,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
@@ -657,7 +724,7 @@ PrintUsage (
   )\r
 {\r
   Print(L"CapsuleApp:  usage\n");\r
-  Print(L"  CapsuleApp <Capsule...>\n");\r
+  Print(L"  CapsuleApp <Capsule...> [-NR]\n");\r
   Print(L"  CapsuleApp -S\n");\r
   Print(L"  CapsuleApp -C\n");\r
   Print(L"  CapsuleApp -P\n");\r
@@ -665,7 +732,10 @@ PrintUsage (
   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"  -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
@@ -699,6 +769,7 @@ UefiMain (
   )\r
 {\r
   EFI_STATUS                    Status;\r
+  RETURN_STATUS                 RStatus;\r
   UINTN                         FileSize[MAX_CAPSULE_NUM];\r
   VOID                          *CapsuleBuffer[MAX_CAPSULE_NUM];\r
   EFI_CAPSULE_BLOCK_DESCRIPTOR  *BlockDescriptors;\r
@@ -706,6 +777,7 @@ UefiMain (
   UINT64                         MaxCapsuleSize;\r
   EFI_RESET_TYPE                 ResetType;\r
   BOOLEAN                        NeedReset;\r
+  BOOLEAN                        NoReset;\r
   CHAR16                         *CapsuleName;\r
   UINTN                          CapsuleNum;\r
   UINTN                          Index;\r
@@ -720,6 +792,10 @@ UefiMain (
     return EFI_INVALID_PARAMETER;\r
   }\r
   if (StrCmp(Argv[1], L"-D") == 0) {\r
+    if (Argc < 3) {\r
+      Print(L"CapsuleApp: NO input capsule name.\n");\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
     Status = DumpCapsule(Argv[2]);\r
     return Status;\r
   }\r
@@ -740,7 +816,27 @@ UefiMain (
     return Status;\r
   }\r
   if (StrCmp(Argv[1], L"-P") == 0) {\r
-    DumpFmpData();\r
+    if (Argc == 2) {\r
+      DumpFmpData();\r
+    }\r
+    if (Argc >= 3) {\r
+      if (StrCmp(Argv[2], L"GET") == 0) {\r
+        EFI_GUID  ImageTypeId;\r
+        UINTN     ImageIndex;\r
+        //\r
+        // FMP->GetImage()\r
+        //\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 EFI_INVALID_PARAMETER;\r
+        }\r
+        ImageIndex = StrDecimalToUintn(Argv[4]);\r
+        if (StrCmp(Argv[5], L"-O") == 0) {\r
+          DumpFmpImage(&ImageTypeId, ImageIndex, Argv[6]);\r
+        }\r
+      }\r
+    }\r
     return EFI_SUCCESS;\r
   }\r
   if (StrCmp(Argv[1], L"-E") == 0) {\r
@@ -748,7 +844,13 @@ UefiMain (
     return EFI_SUCCESS;\r
   }\r
   CapsuleFirstIndex = 1;\r
-  CapsuleLastIndex = Argc - 1;\r
+  NoReset = FALSE;\r
+  if ((Argc > 1) && (StrCmp(Argv[Argc - 1], L"-NR") == 0)) {\r
+    NoReset = TRUE;\r
+    CapsuleLastIndex = Argc - 2;\r
+  } else {\r
+    CapsuleLastIndex = Argc - 1;\r
+  }\r
   CapsuleNum = CapsuleLastIndex - CapsuleFirstIndex + 1;\r
 \r
   if (CapsuleFirstIndex > CapsuleLastIndex) {\r
@@ -820,10 +922,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