]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleLib.c
MdeModulePkg DxeCapsuleLib: Use Attr to know whether reset is required
[mirror_edk2.git] / MdeModulePkg / Library / DxeCapsuleLibFmp / DxeCapsuleLib.c
index 56c8e98b8400a33298e89e2ec42f1c58d2e324c2..d4026dd5c783763d36791238c6f52bbe97c3dc40 100644 (file)
@@ -45,6 +45,7 @@
 #include <Protocol/GraphicsOutput.h>\r
 #include <Protocol/EsrtManagement.h>\r
 #include <Protocol/FirmwareManagement.h>\r
+#include <Protocol/FirmwareManagementProgress.h>\r
 #include <Protocol/DevicePath.h>\r
 \r
 EFI_SYSTEM_RESOURCE_TABLE *mEsrtTable                  = NULL;\r
@@ -53,6 +54,8 @@ BOOLEAN                   mIsVirtualAddrConverted      = FALSE;
 BOOLEAN                   mDxeCapsuleLibEndOfDxe       = FALSE;\r
 EFI_EVENT                 mDxeCapsuleLibEndOfDxeEvent  = NULL;\r
 \r
+EDKII_FIRMWARE_MANAGEMENT_PROGRESS_PROTOCOL  *mFmpProgress = NULL;\r
+\r
 /**\r
   Initialize capsule related variables.\r
 **/\r
@@ -101,18 +104,17 @@ RecordFmpCapsuleStatusVariable (
   Function indicate the current completion progress of the firmware\r
   update. Platform may override with own specific progress function.\r
 \r
-  @param[in]  Completion    A value between 1 and 100 indicating the current completion progress of the firmware update\r
+  @param[in]  Completion  A value between 1 and 100 indicating the current\r
+                          completion progress of the firmware update\r
 \r
-  @retval EFI_SUCESS    Input capsule is a correct FMP capsule.\r
+  @retval EFI_SUCESS             The capsule update progress was updated.\r
+  @retval EFI_INVALID_PARAMETER  Completion is greater than 100%.\r
 **/\r
 EFI_STATUS\r
 EFIAPI\r
-Update_Image_Progress (\r
+UpdateImageProgress (\r
   IN UINTN  Completion\r
-  )\r
-{\r
-  return EFI_SUCCESS;\r
-}\r
+  );\r
 \r
 /**\r
   Return if this CapsuleGuid is a FMP capsule GUID or not.\r
@@ -250,7 +252,7 @@ ValidateFmpCapsule (
     //\r
     if (Index > 0) {\r
       if (ItemOffsetList[Index] <= ItemOffsetList[Index - 1]) {\r
-        DEBUG((DEBUG_ERROR, "ItemOffsetList[%d](0x%lx) < ItemOffsetList[%d](0x%x)\n", Index, ItemOffsetList[Index], Index, ItemOffsetList[Index - 1]));\r
+        DEBUG((DEBUG_ERROR, "ItemOffsetList[%d](0x%lx) < ItemOffsetList[%d](0x%x)\n", Index, ItemOffsetList[Index], Index - 1, ItemOffsetList[Index - 1]));\r
         return EFI_INVALID_PARAMETER;\r
       }\r
     }\r
@@ -266,10 +268,6 @@ ValidateFmpCapsule (
     }\r
     FmpImageSize = (UINTN)EndOfPayload - ItemOffsetList[Index];\r
 \r
-    if (FmpImageSize < OFFSET_OF(EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER, UpdateHardwareInstance)) {\r
-      DEBUG((DEBUG_ERROR, "FmpImageSize(0x%lx) < EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER\n", FmpImageSize));\r
-      return EFI_INVALID_PARAMETER;\r
-    }\r
     FmpImageHeaderSize = sizeof(EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER);\r
     if ((ImageHeader->Version > EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER_INIT_VERSION) ||\r
         (ImageHeader->Version < 1)) {\r
@@ -279,6 +277,10 @@ ValidateFmpCapsule (
     if (ImageHeader->Version < EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER_INIT_VERSION) {\r
       FmpImageHeaderSize = OFFSET_OF(EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER, UpdateHardwareInstance);\r
     }\r
+    if (FmpImageSize < FmpImageHeaderSize) {\r
+      DEBUG((DEBUG_ERROR, "FmpImageSize(0x%lx) < FmpImageHeaderSize(0x%x)\n", FmpImageSize, FmpImageHeaderSize));\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
 \r
     // No overflow\r
     if (FmpImageSize != (UINT64)FmpImageHeaderSize + (UINT64)ImageHeader->UpdateImageSize + (UINT64)ImageHeader->UpdateVendorCodeSize) {\r
@@ -330,8 +332,25 @@ DisplayCapsuleImage (
   UINTN                         Width;\r
   EFI_GRAPHICS_OUTPUT_PROTOCOL  *GraphicsOutput;\r
 \r
-  ImagePayload = (DISPLAY_DISPLAY_PAYLOAD *)(CapsuleHeader + 1);\r
-  PayloadSize = CapsuleHeader->CapsuleImageSize - sizeof(EFI_CAPSULE_HEADER);\r
+  //\r
+  // UX capsule doesn't have extended header entries.\r
+  //\r
+  if (CapsuleHeader->HeaderSize != sizeof (EFI_CAPSULE_HEADER)) {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+  ImagePayload = (DISPLAY_DISPLAY_PAYLOAD *)((UINTN) CapsuleHeader + CapsuleHeader->HeaderSize);\r
+  //\r
+  // (CapsuleImageSize > HeaderSize) is guaranteed by IsValidCapsuleHeader().\r
+  //\r
+  PayloadSize = CapsuleHeader->CapsuleImageSize - CapsuleHeader->HeaderSize;\r
+\r
+  //\r
+  // Make sure the image payload at least contain the DISPLAY_DISPLAY_PAYLOAD header.\r
+  // Further size check is performed by the logic translating BMP to GOP BLT.\r
+  //\r
+  if (PayloadSize <= sizeof (DISPLAY_DISPLAY_PAYLOAD)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
 \r
   if (ImagePayload->Version != 1) {\r
     return EFI_UNSUPPORTED;\r
@@ -599,11 +618,14 @@ DumpAllFmpInfo (
 \r
   @param[in]     UpdateImageTypeId       Used to identify device firmware targeted by this update.\r
   @param[in]     UpdateHardwareInstance  The HardwareInstance to target with this update.\r
-  @param[in,out] NoHandles               The number of handles returned in Buffer.\r
-  @param[out]    Buffer[out]             A pointer to the buffer to return the requested array of handles.\r
-\r
-  @retval EFI_SUCCESS            The array of handles was returned in Buffer, and the number of\r
-                                 handles in Buffer was returned in NoHandles.\r
+  @param[out]    NoHandles               The number of handles returned in HandleBuf.\r
+  @param[out]    HandleBuf               A pointer to the buffer to return the requested array of handles.\r
+  @param[out]    ResetRequiredBuf        A pointer to the buffer to return reset required flag for\r
+                                         the requested array of handles.\r
+\r
+  @retval EFI_SUCCESS            The array of handles and their reset required flag were returned in\r
+                                 HandleBuf and ResetRequiredBuf, and the number of handles in HandleBuf\r
+                                 was returned in NoHandles.\r
   @retval EFI_NOT_FOUND          No handles match the search.\r
   @retval EFI_OUT_OF_RESOURCES   There is not enough pool memory to store the matching results.\r
 **/\r
@@ -611,14 +633,16 @@ EFI_STATUS
 GetFmpHandleBufferByType (\r
   IN     EFI_GUID                     *UpdateImageTypeId,\r
   IN     UINT64                       UpdateHardwareInstance,\r
-  IN OUT UINTN                        *NoHandles,\r
-  OUT    EFI_HANDLE                   **Buffer\r
+  OUT    UINTN                        *NoHandles, OPTIONAL\r
+  OUT    EFI_HANDLE                   **HandleBuf, OPTIONAL\r
+  OUT    BOOLEAN                      **ResetRequiredBuf OPTIONAL\r
   )\r
 {\r
   EFI_STATUS                                    Status;\r
   EFI_HANDLE                                    *HandleBuffer;\r
   UINTN                                         NumberOfHandles;\r
   EFI_HANDLE                                    *MatchedHandleBuffer;\r
+  BOOLEAN                                       *MatchedResetRequiredBuffer;\r
   UINTN                                         MatchedNumberOfHandles;\r
   EFI_FIRMWARE_MANAGEMENT_PROTOCOL              *Fmp;\r
   UINTN                                         Index;\r
@@ -632,8 +656,15 @@ GetFmpHandleBufferByType (
   UINTN                                         Index2;\r
   EFI_FIRMWARE_IMAGE_DESCRIPTOR                 *TempFmpImageInfo;\r
 \r
-  *NoHandles = 0;\r
-  *Buffer = NULL;\r
+  if (NoHandles != NULL) {\r
+    *NoHandles = 0;\r
+  }\r
+  if (HandleBuf != NULL) {\r
+    *HandleBuf = NULL;\r
+  }\r
+  if (ResetRequiredBuf != NULL) {\r
+    *ResetRequiredBuf = NULL;\r
+  }\r
 \r
   Status = gBS->LocateHandleBuffer (\r
                   ByProtocol,\r
@@ -647,10 +678,26 @@ GetFmpHandleBufferByType (
   }\r
 \r
   MatchedNumberOfHandles = 0;\r
-  MatchedHandleBuffer = AllocateZeroPool (sizeof(EFI_HANDLE) * NumberOfHandles);\r
-  if (MatchedHandleBuffer == NULL) {\r
-    FreePool (HandleBuffer);\r
-    return EFI_OUT_OF_RESOURCES;\r
+\r
+  MatchedHandleBuffer = NULL;\r
+  if (HandleBuf != NULL) {\r
+    MatchedHandleBuffer = AllocateZeroPool (sizeof(EFI_HANDLE) * NumberOfHandles);\r
+    if (MatchedHandleBuffer == NULL) {\r
+      FreePool (HandleBuffer);\r
+      return EFI_OUT_OF_RESOURCES;\r
+    }\r
+  }\r
+\r
+  MatchedResetRequiredBuffer = NULL;\r
+  if (ResetRequiredBuf != NULL) {\r
+    MatchedResetRequiredBuffer = AllocateZeroPool (sizeof(BOOLEAN) * NumberOfHandles);\r
+    if (MatchedResetRequiredBuffer == NULL) {\r
+      if (MatchedHandleBuffer != NULL) {\r
+        FreePool (MatchedHandleBuffer);\r
+      }\r
+      FreePool (HandleBuffer);\r
+      return EFI_OUT_OF_RESOURCES;\r
+    }\r
   }\r
 \r
   for (Index = 0; Index < NumberOfHandles; Index++) {\r
@@ -712,7 +759,15 @@ GetFmpHandleBufferByType (
         if ((UpdateHardwareInstance == 0) ||\r
             ((FmpImageInfoDescriptorVer >= EFI_FIRMWARE_IMAGE_DESCRIPTOR_VERSION) &&\r
              (UpdateHardwareInstance == TempFmpImageInfo->HardwareInstance))) {\r
-          MatchedHandleBuffer[MatchedNumberOfHandles] = HandleBuffer[Index];\r
+          if (MatchedHandleBuffer != NULL) {\r
+            MatchedHandleBuffer[MatchedNumberOfHandles] = HandleBuffer[Index];\r
+          }\r
+          if (MatchedResetRequiredBuffer != NULL) {\r
+            MatchedResetRequiredBuffer[MatchedNumberOfHandles] = (((TempFmpImageInfo->AttributesSupported & \r
+                                                                 IMAGE_ATTRIBUTE_RESET_REQUIRED) != 0) &&\r
+                                                                 ((TempFmpImageInfo->AttributesSetting &\r
+                                                                 IMAGE_ATTRIBUTE_RESET_REQUIRED) != 0));\r
+          }\r
           MatchedNumberOfHandles++;\r
           break;\r
         }\r
@@ -726,8 +781,15 @@ GetFmpHandleBufferByType (
     return EFI_NOT_FOUND;\r
   }\r
 \r
-  *NoHandles = MatchedNumberOfHandles;\r
-  *Buffer = MatchedHandleBuffer;\r
+  if (NoHandles != NULL) {\r
+    *NoHandles = MatchedNumberOfHandles;\r
+  }\r
+  if (HandleBuf != NULL) {\r
+    *HandleBuf = MatchedHandleBuffer;\r
+  }\r
+  if (ResetRequiredBuf != NULL) {\r
+    *ResetRequiredBuf = MatchedResetRequiredBuffer;\r
+  }\r
 \r
   return EFI_SUCCESS;\r
 }\r
@@ -822,6 +884,7 @@ SetFmpImageData (
   UINT8                                         *Image;\r
   VOID                                          *VendorCode;\r
   CHAR16                                        *AbortReason;\r
+  EFI_FIRMWARE_MANAGEMENT_UPDATE_IMAGE_PROGRESS ProgressCallback;\r
 \r
   Status = gBS->HandleProtocol(\r
                   Handle,\r
@@ -832,6 +895,19 @@ SetFmpImageData (
     return Status;\r
   }\r
 \r
+  //\r
+  // Lookup Firmware Management Progress Protocol before SetImage() is called\r
+  // This is an optional protocol that may not be present on Handle.\r
+  //\r
+  Status = gBS->HandleProtocol (\r
+                  Handle,\r
+                  &gEdkiiFirmwareManagementProgressProtocolGuid,\r
+                  (VOID **)&mFmpProgress\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    mFmpProgress = NULL;\r
+  }\r
+\r
   if (ImageHeader->Version >= EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER_INIT_VERSION) {\r
     Image = (UINT8 *)(ImageHeader + 1);\r
   } else {\r
@@ -856,21 +932,43 @@ SetFmpImageData (
     DEBUG((DEBUG_INFO, "(UpdateHardwareInstance - 0x%x)", ImageHeader->UpdateHardwareInstance));\r
   }\r
   DEBUG((DEBUG_INFO, "\n"));\r
+\r
+  //\r
+  // Before calling SetImage(), reset the progress bar to 0%\r
+  //\r
+  ProgressCallback = UpdateImageProgress;\r
+  Status = UpdateImageProgress (0);\r
+  if (EFI_ERROR (Status)) {\r
+    ProgressCallback = NULL;\r
+  }\r
+\r
   Status = Fmp->SetImage(\r
                   Fmp,\r
                   ImageHeader->UpdateImageIndex,          // ImageIndex\r
                   Image,                                  // Image\r
                   ImageHeader->UpdateImageSize,           // ImageSize\r
                   VendorCode,                             // VendorCode\r
-                  Update_Image_Progress,                  // Progress\r
+                  ProgressCallback,                       // Progress\r
                   &AbortReason                            // AbortReason\r
                   );\r
+  //\r
+  // Set the progress bar to 100% after returning from SetImage()\r
+  //\r
+  if (ProgressCallback != NULL) {\r
+    UpdateImageProgress (100);\r
+  }\r
+\r
   DEBUG((DEBUG_INFO, "Fmp->SetImage - %r\n", Status));\r
   if (AbortReason != NULL) {\r
     DEBUG ((DEBUG_ERROR, "%s\n", AbortReason));\r
     FreePool(AbortReason);\r
   }\r
 \r
+  //\r
+  // Clear mFmpProgress after SetImage() returns\r
+  //\r
+  mFmpProgress = NULL;\r
+\r
   return Status;\r
 }\r
 \r
@@ -992,7 +1090,7 @@ RecordFmpCapsuleStatus (
 \r
   //\r
   // Update EsrtEntry For V1, V2 FMP instance.\r
-  // V3 FMP ESRT cache will be synced up through EsrtSyncFmp interface\r
+  // V3 FMP ESRT cache will be synced up through SyncEsrtFmp interface\r
   //\r
   FmpImageInfoDescriptorVer = GetFmpImageInfoDescriptorVer (Handle);\r
   if (FmpImageInfoDescriptorVer < EFI_FIRMWARE_IMAGE_DESCRIPTOR_VERSION) {\r
@@ -1019,7 +1117,8 @@ RecordFmpCapsuleStatus (
 \r
   This function need support nested FMP capsule.\r
 \r
-  @param[in]   CapsuleHeader         Points to a capsule header.\r
+  @param[in]  CapsuleHeader         Points to a capsule header.\r
+  @param[out] ResetRequired         Indicates whether reset is required or not.\r
 \r
   @retval EFI_SUCESS            Process Capsule Image successfully.\r
   @retval EFI_UNSUPPORTED       Capsule image is not supported by the firmware.\r
@@ -1029,7 +1128,8 @@ RecordFmpCapsuleStatus (
 **/\r
 EFI_STATUS\r
 ProcessFmpCapsuleImage (\r
-  IN EFI_CAPSULE_HEADER  *CapsuleHeader\r
+  IN EFI_CAPSULE_HEADER  *CapsuleHeader,\r
+  OUT BOOLEAN            *ResetRequired OPTIONAL\r
   )\r
 {\r
   EFI_STATUS                                    Status;\r
@@ -1039,6 +1139,7 @@ ProcessFmpCapsuleImage (
   UINT32                                        ItemNum;\r
   UINTN                                         Index;\r
   EFI_HANDLE                                    *HandleBuffer;\r
+  BOOLEAN                                       *ResetRequiredBuffer;\r
   UINTN                                         NumberOfHandles;\r
   UINTN                                         DriverLen;\r
   UINT64                                        UpdateHardwareInstance;\r
@@ -1047,7 +1148,7 @@ ProcessFmpCapsuleImage (
   BOOLEAN                                       Abort;\r
 \r
   if (!IsFmpCapsuleGuid(&CapsuleHeader->CapsuleGuid)) {\r
-    return ProcessFmpCapsuleImage ((EFI_CAPSULE_HEADER *)((UINTN)CapsuleHeader + CapsuleHeader->HeaderSize));\r
+    return ProcessFmpCapsuleImage ((EFI_CAPSULE_HEADER *)((UINTN)CapsuleHeader + CapsuleHeader->HeaderSize), ResetRequired);\r
   }\r
 \r
   NotReady = FALSE;\r
@@ -1117,7 +1218,8 @@ ProcessFmpCapsuleImage (
                &ImageHeader->UpdateImageTypeId,\r
                UpdateHardwareInstance,\r
                &NumberOfHandles,\r
-               &HandleBuffer\r
+               &HandleBuffer,\r
+               &ResetRequiredBuffer\r
                );\r
     if (EFI_ERROR(Status)) {\r
       NotReady = TRUE;\r
@@ -1150,6 +1252,10 @@ ProcessFmpCapsuleImage (
                  );\r
       if (Status != EFI_SUCCESS) {\r
         Abort = TRUE;\r
+      } else {\r
+        if (ResetRequired != NULL) {\r
+          *ResetRequired |= ResetRequiredBuffer[Index2];\r
+        }\r
       }\r
 \r
       RecordFmpCapsuleStatus (\r
@@ -1163,6 +1269,9 @@ ProcessFmpCapsuleImage (
     if (HandleBuffer != NULL) {\r
       FreePool(HandleBuffer);\r
     }\r
+    if (ResetRequiredBuffer != NULL) {\r
+      FreePool(ResetRequiredBuffer);\r
+    }\r
   }\r
 \r
   if (NotReady) {\r
@@ -1190,7 +1299,6 @@ IsNestedFmpCapsule (
   )\r
 {\r
   EFI_STATUS                 Status;\r
-  EFI_SYSTEM_RESOURCE_TABLE  *Esrt;\r
   EFI_SYSTEM_RESOURCE_ENTRY  *EsrtEntry;\r
   UINTN                      Index;\r
   BOOLEAN                    EsrtGuidFound;\r
@@ -1223,19 +1331,18 @@ IsNestedFmpCapsule (
     }\r
 \r
     //\r
-    // Check ESRT configuration table\r
+    // Check Firmware Management Protocols\r
     //\r
     if (!EsrtGuidFound) {\r
-      Status = EfiGetSystemConfigurationTable(&gEfiSystemResourceTableGuid, (VOID **)&Esrt);\r
+      Status = GetFmpHandleBufferByType (\r
+                 &CapsuleHeader->CapsuleGuid,\r
+                 0,\r
+                 NULL,\r
+                 NULL,\r
+                 NULL\r
+                 );\r
       if (!EFI_ERROR(Status)) {\r
-        ASSERT (Esrt != NULL);\r
-        EsrtEntry = (VOID *)(Esrt + 1);\r
-        for (Index = 0; Index < Esrt->FwResourceCount; Index++, EsrtEntry++) {\r
-          if (CompareGuid(&EsrtEntry->FwClass, &CapsuleHeader->CapsuleGuid)) {\r
-            EsrtGuidFound = TRUE;\r
-            break;\r
-          }\r
-        }\r
+        EsrtGuidFound = TRUE;\r
       }\r
     }\r
   }\r
@@ -1324,6 +1431,7 @@ SupportCapsuleImage (
   Caution: This function may receive untrusted input.\r
 \r
   @param[in]  CapsuleHeader         Points to a capsule header.\r
+  @param[out] ResetRequired         Indicates whether reset is required or not.\r
 \r
   @retval EFI_SUCESS            Process Capsule Image successfully.\r
   @retval EFI_UNSUPPORTED       Capsule image is not supported by the firmware.\r
@@ -1332,8 +1440,9 @@ SupportCapsuleImage (
 **/\r
 EFI_STATUS\r
 EFIAPI\r
-ProcessCapsuleImage (\r
-  IN EFI_CAPSULE_HEADER  *CapsuleHeader\r
+ProcessThisCapsuleImage (\r
+  IN EFI_CAPSULE_HEADER  *CapsuleHeader,\r
+  OUT BOOLEAN            *ResetRequired OPTIONAL\r
   )\r
 {\r
   EFI_STATUS                   Status;\r
@@ -1367,10 +1476,10 @@ ProcessCapsuleImage (
     }\r
 \r
     //\r
-    // Press EFI FMP Capsule\r
+    // Process EFI FMP Capsule\r
     //\r
     DEBUG((DEBUG_INFO, "ProcessFmpCapsuleImage ...\n"));\r
-    Status = ProcessFmpCapsuleImage(CapsuleHeader);\r
+    Status = ProcessFmpCapsuleImage(CapsuleHeader, ResetRequired);\r
     DEBUG((DEBUG_INFO, "ProcessFmpCapsuleImage - %r\n", Status));\r
 \r
     return Status;\r
@@ -1379,6 +1488,27 @@ ProcessCapsuleImage (
   return EFI_UNSUPPORTED;\r
 }\r
 \r
+/**\r
+  The firmware implements to process the capsule image.\r
+\r
+  Caution: This function may receive untrusted input.\r
+\r
+  @param[in]  CapsuleHeader         Points to a capsule header.\r
+\r
+  @retval EFI_SUCESS            Process Capsule Image successfully.\r
+  @retval EFI_UNSUPPORTED       Capsule image is not supported by the firmware.\r
+  @retval EFI_VOLUME_CORRUPTED  FV volume in the capsule is corrupted.\r
+  @retval EFI_OUT_OF_RESOURCES  Not enough memory.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+ProcessCapsuleImage (\r
+  IN EFI_CAPSULE_HEADER  *CapsuleHeader\r
+  )\r
+{\r
+  return ProcessThisCapsuleImage (CapsuleHeader, NULL);\r
+}\r
+\r
 /**\r
   Callback function executed when the EndOfDxe event group is signaled.\r
 \r