]> git.proxmox.com Git - mirror_edk2.git/commitdiff
MdeModulePkg/CapsuleApp: Add Fmp->GetImage() support.
authorJiewen Yao <jiewen.yao@intel.com>
Tue, 29 Nov 2016 13:37:28 +0000 (21:37 +0800)
committerJiewen Yao <jiewen.yao@intel.com>
Thu, 1 Dec 2016 07:28:05 +0000 (15:28 +0800)
We add Fmp->GetImage() support in CapsuleApp. So that user may call
Fmp->GetImage() in UEFI shell environment.
This is useful to do unit test for FMP which supports GetImage(),
or user wants to get current image, such as Microcode.

Cc: Eric Dong <eric.dong@intel.com>
Cc: Jeff Fan <jeff.fan@intel.com>
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Jiewen Yao <jiewen.yao@intel.com>
Reviewed-by: Jeff Fan <jeff.fan@intel.com>
MdeModulePkg/Application/CapsuleApp/AppSupport.c
MdeModulePkg/Application/CapsuleApp/CapsuleApp.c
MdeModulePkg/Application/CapsuleApp/CapsuleDump.c

index 0a1224db546487721db92023e3cbbbec8fb80283..6aea76a7201d8c4e2fadf8b6d6409526c15b6014 100644 (file)
@@ -27,6 +27,9 @@
 #include <Guid/FileInfo.h>\r
 #include <Guid/Gpt.h>\r
 \r
+#define IS_HYPHEN(a)               ((a) == L'-')\r
+#define IS_NULL(a)                 ((a) == L'\0')\r
+\r
 #define MAX_ARG_NUM     11\r
 \r
 UINTN  Argc;\r
@@ -60,6 +63,144 @@ GetArg (
   return EFI_SUCCESS;\r
 }\r
 \r
+/**\r
+  Converts a list of string to a specified buffer.\r
+\r
+  @param[out] Buf             The output buffer that contains the string.\r
+  @param[in]  BufferLength    The length of the buffer\r
+  @param[in]  Str             The input string that contains the hex number\r
+\r
+  @retval EFI_SUCCESS    The string was successfully converted to the buffer.\r
+\r
+**/\r
+EFI_STATUS\r
+StrToBuf (\r
+  OUT UINT8    *Buf,\r
+  IN  UINTN    BufferLength,\r
+  IN  CHAR16   *Str\r
+  )\r
+{\r
+  UINTN       Index;\r
+  UINTN       StrLength;\r
+  UINT8       Digit;\r
+  UINT8       Byte;\r
+\r
+  Digit = 0;\r
+\r
+  //\r
+  // Two hex char make up one byte\r
+  //\r
+  StrLength = BufferLength * sizeof (CHAR16);\r
+\r
+  for(Index = 0; Index < StrLength; Index++, Str++) {\r
+\r
+    if ((*Str >= L'a') && (*Str <= L'f')) {\r
+      Digit = (UINT8) (*Str - L'a' + 0x0A);\r
+    } else if ((*Str >= L'A') && (*Str <= L'F')) {\r
+      Digit = (UINT8) (*Str - L'A' + 0x0A);\r
+    } else if ((*Str >= L'0') && (*Str <= L'9')) {\r
+      Digit = (UINT8) (*Str - L'0');\r
+    } else {\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
+\r
+    //\r
+    // For odd characters, write the upper nibble for each buffer byte,\r
+    // and for even characters, the lower nibble.\r
+    //\r
+    if ((Index & 1) == 0) {\r
+      Byte = (UINT8) (Digit << 4);\r
+    } else {\r
+      Byte = Buf[Index / 2];\r
+      Byte &= 0xF0;\r
+      Byte = (UINT8) (Byte | Digit);\r
+    }\r
+\r
+    Buf[Index / 2] = Byte;\r
+  }\r
+\r
+  return EFI_SUCCESS;\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
+  // Get the first UINT32 data\r
+  //\r
+  Guid->Data1 = (UINT32) StrHexToUint64  (Str);\r
+  while (!IS_HYPHEN (*Str) && !IS_NULL (*Str)) {\r
+    Str ++;\r
+  }\r
+\r
+  if (IS_HYPHEN (*Str)) {\r
+    Str++;\r
+  } else {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  //\r
+  // Get the second UINT16 data\r
+  //\r
+  Guid->Data2 = (UINT16) StrHexToUint64  (Str);\r
+  while (!IS_HYPHEN (*Str) && !IS_NULL (*Str)) {\r
+    Str ++;\r
+  }\r
+\r
+  if (IS_HYPHEN (*Str)) {\r
+    Str++;\r
+  } else {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  //\r
+  // Get the third UINT16 data\r
+  //\r
+  Guid->Data3 = (UINT16) StrHexToUint64  (Str);\r
+  while (!IS_HYPHEN (*Str) && !IS_NULL (*Str)) {\r
+    Str ++;\r
+  }\r
+\r
+  if (IS_HYPHEN (*Str)) {\r
+    Str++;\r
+  } else {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  //\r
+  // Get the following 8 bytes data\r
+  //\r
+  StrToBuf (&Guid->Data4[0], 2, Str);\r
+  //\r
+  // Skip 2 byte hex chars\r
+  //\r
+  Str += 2 * 2;\r
+\r
+  if (IS_HYPHEN (*Str)) {\r
+    Str++;\r
+  } else {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+  StrToBuf (&Guid->Data4[2], 6, Str);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
 /**\r
   Return File System Volume containing this shell application.\r
 \r
index 23672ae47ba7ba909241d9c4a83bd6f9b35152e0..51372593de4ed125ddf674bb8ea7ae4d846559d4 100644 (file)
@@ -85,6 +85,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
@@ -126,6 +142,24 @@ WriteFileFromBuffer (
   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
@@ -662,6 +696,7 @@ 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"  -S:  Dump capsule report variable (EFI_CAPSULE_REPORT_GUID),\n");\r
   Print(L"       which is defined in UEFI specification.\n");\r
@@ -737,7 +772,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
+        Status = StrToGuid(Argv[3], &ImageTypeId);\r
+        if (EFI_ERROR(Status)) {\r
+          Print (L"Invalid ImageTypeId - %s\n", Argv[3]);\r
+          return Status;\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
index d09b938fed3b7a70e11da1d1f30b3366f3f5269c..3d83ec4498a3b5eddca4982cb046de83430eaa86 100644 (file)
@@ -45,6 +45,22 @@ ReadFileToBuffer (
   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
   Dump UX capsule information.\r
 \r
@@ -738,3 +754,201 @@ DumpFmpData (
 EXIT:\r
   FreePool(HandleBuffer);\r
 }\r
+\r
+/**\r
+  Check if the ImageInfo includes the ImageTypeId.\r
+\r
+  @param[in] ImageInfo           A pointer to EFI_FIRMWARE_IMAGE_DESCRIPTOR.\r
+  @param[in] DescriptorCount     The count of EFI_FIRMWARE_IMAGE_DESCRIPTOR.\r
+  @param[in] DescriptorSize      The size of an individual EFI_FIRMWARE_IMAGE_DESCRIPTOR, in bytes.\r
+  @param[in] ImageTypeId         A unique GUID identifying the firmware image type.\r
+\r
+  @return TRUE  This ImageInfo includes the ImageTypeId\r
+  @return FALSE This ImageInfo does not include the ImageTypeId\r
+**/\r
+BOOLEAN\r
+IsThisFmpImageInfo (\r
+  IN EFI_FIRMWARE_IMAGE_DESCRIPTOR   *ImageInfo,\r
+  IN UINT8                           DescriptorCount,\r
+  IN UINTN                           DescriptorSize,\r
+  IN EFI_GUID                        *ImageTypeId\r
+  )\r
+{\r
+  EFI_FIRMWARE_IMAGE_DESCRIPTOR                 *CurrentImageInfo;\r
+  UINTN                                         Index;\r
+\r
+  CurrentImageInfo = ImageInfo;\r
+  for (Index = 0; Index < DescriptorCount; Index++) {\r
+    if (CompareGuid (&CurrentImageInfo->ImageTypeId, ImageTypeId)) {\r
+      return TRUE;\r
+    }\r
+    CurrentImageInfo = (EFI_FIRMWARE_IMAGE_DESCRIPTOR *)((UINT8 *)CurrentImageInfo + DescriptorSize);\r
+  }\r
+  return FALSE;\r
+}\r
+\r
+/**\r
+  return the FMP whoes ImageInfo includes the ImageTypeId.\r
+\r
+  @param[in] ImageTypeId         A unique GUID identifying the firmware image type.\r
+\r
+  @return The FMP whoes ImageInfo includes the ImageTypeId\r
+**/\r
+EFI_FIRMWARE_MANAGEMENT_PROTOCOL *\r
+FindFmpFromImageTypeId (\r
+  IN EFI_GUID  *ImageTypeId\r
+  )\r
+{\r
+  EFI_STATUS                                    Status;\r
+  EFI_FIRMWARE_MANAGEMENT_PROTOCOL              *Fmp;\r
+  EFI_FIRMWARE_MANAGEMENT_PROTOCOL              *TargetFmp;\r
+  EFI_HANDLE                                    *HandleBuffer;\r
+  UINTN                                         NumberOfHandles;\r
+  UINTN                                         Index;\r
+  EFI_FIRMWARE_IMAGE_DESCRIPTOR                 *FmpImageInfoBuf;\r
+  UINTN                                         ImageInfoSize;\r
+  UINT32                                        FmpImageInfoDescriptorVer;\r
+  UINT8                                         FmpImageInfoCount;\r
+  UINTN                                         DescriptorSize;\r
+  UINT32                                        PackageVersion;\r
+  CHAR16                                        *PackageVersionName;\r
+\r
+  Status = gBS->LocateHandleBuffer (\r
+                  ByProtocol,\r
+                  &gEfiFirmwareManagementProtocolGuid,\r
+                  NULL,\r
+                  &NumberOfHandles,\r
+                  &HandleBuffer\r
+                  );\r
+  if (EFI_ERROR(Status)) {\r
+    Print(L"FMP protocol - %r\n", EFI_NOT_FOUND);\r
+    return NULL;\r
+  }\r
+\r
+  TargetFmp = NULL;\r
+  for (Index = 0; Index < NumberOfHandles; Index++) {\r
+    Status = gBS->HandleProtocol(\r
+                    HandleBuffer[Index],\r
+                    &gEfiFirmwareManagementProtocolGuid,\r
+                    (VOID **)&Fmp\r
+                    );\r
+    if (EFI_ERROR(Status)) {\r
+      continue;\r
+    }\r
+\r
+    ImageInfoSize = 0;\r
+    Status = Fmp->GetImageInfo (\r
+                    Fmp,\r
+                    &ImageInfoSize,\r
+                    NULL,\r
+                    NULL,\r
+                    NULL,\r
+                    NULL,\r
+                    NULL,\r
+                    NULL\r
+                    );\r
+    if (Status != EFI_BUFFER_TOO_SMALL) {\r
+      continue;\r
+    }\r
+\r
+    FmpImageInfoBuf = NULL;\r
+    FmpImageInfoBuf = AllocateZeroPool (ImageInfoSize);\r
+    if (FmpImageInfoBuf == NULL) {\r
+      FreePool(HandleBuffer);\r
+      Print(L"Out of resource\n");\r
+      return NULL;\r
+    }\r
+\r
+    PackageVersionName = NULL;\r
+    Status = Fmp->GetImageInfo (\r
+                    Fmp,\r
+                    &ImageInfoSize,               // ImageInfoSize\r
+                    FmpImageInfoBuf,              // ImageInfo\r
+                    &FmpImageInfoDescriptorVer,   // DescriptorVersion\r
+                    &FmpImageInfoCount,           // DescriptorCount\r
+                    &DescriptorSize,              // DescriptorSize\r
+                    &PackageVersion,              // PackageVersion\r
+                    &PackageVersionName           // PackageVersionName\r
+                    );\r
+\r
+    //\r
+    // If FMP GetInformation interface failed, skip this resource\r
+    //\r
+    if (EFI_ERROR(Status)) {\r
+      FreePool(FmpImageInfoBuf);\r
+      continue;\r
+    }\r
+\r
+    if (PackageVersionName != NULL) {\r
+      FreePool(PackageVersionName);\r
+    }\r
+\r
+    if (IsThisFmpImageInfo (FmpImageInfoBuf, FmpImageInfoCount, DescriptorSize, ImageTypeId)) {\r
+      TargetFmp = Fmp;\r
+    }\r
+    FreePool(FmpImageInfoBuf);\r
+    if (TargetFmp != NULL) {\r
+      break;\r
+    }\r
+  }\r
+  FreePool(HandleBuffer);\r
+  return TargetFmp;\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
+  EFI_STATUS                                    Status;\r
+  EFI_FIRMWARE_MANAGEMENT_PROTOCOL              *Fmp;\r
+  VOID                                          *Image;\r
+  UINTN                                         ImageSize;\r
+\r
+  Fmp = FindFmpFromImageTypeId (ImageTypeId);\r
+  if (Fmp == NULL) {\r
+    Print(L"No FMP include ImageTypeId %g\n", ImageTypeId);\r
+    return ;\r
+  }\r
+\r
+  if (ImageIndex > 0xFF) {\r
+    Print(L"ImageIndex 0x%x too big\n", ImageIndex);\r
+    return ;\r
+  }\r
+\r
+  Image = Fmp;\r
+  ImageSize = 0;\r
+  Status = Fmp->GetImage (Fmp, (UINT8)ImageIndex, Image, &ImageSize);\r
+  if (Status != EFI_BUFFER_TOO_SMALL) {\r
+    Print(L"Fmp->GetImage - %r\n", Status);\r
+    return ;\r
+  }\r
+\r
+  Image = AllocatePool (ImageSize);\r
+  if (Image == NULL) {\r
+    Print(L"Allocate FmpImage 0x%x - %r\n", ImageSize, EFI_OUT_OF_RESOURCES);\r
+    return ;\r
+  }\r
+\r
+  Status = Fmp->GetImage (Fmp, (UINT8)ImageIndex, Image, &ImageSize);\r
+  if (EFI_ERROR(Status)) {\r
+    Print(L"Fmp->GetImage - %r\n", Status);\r
+    return ;\r
+  }\r
+\r
+  Status = WriteFileFromBuffer(ImageName, ImageSize, Image);\r
+  Print(L"CapsuleApp: Dump %g ImageIndex (0x%x) to %s %r\n", ImageTypeId, ImageIndex, ImageName, Status);\r
+\r
+  return ;\r
+}\r