]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleProcessLib.c
MdeModulePkg/CapsuleLib: Fix runtime issue
[mirror_edk2.git] / MdeModulePkg / Library / DxeCapsuleLibFmp / DxeCapsuleProcessLib.c
index 62257a43cc382cf568112b8b3528f58cf0b886dc..ba3ff90b9f731c4a8136c95e3f932aa65845dd77 100644 (file)
@@ -95,60 +95,23 @@ IsValidCapsuleHeader (
   );\r
 \r
 extern BOOLEAN                   mDxeCapsuleLibEndOfDxe;\r
-extern BOOLEAN                   mAreAllImagesProcessed;\r
 BOOLEAN                          mNeedReset;\r
 \r
-/**\r
-\r
-  This routine is called to process capsules.\r
-\r
-  Caution: This function may receive untrusted input.\r
-\r
-  Each individual capsule result is recorded in capsule record variable.\r
-\r
-  @param[in]  NeedBlockDriver         TRUE: Need skip the FMP capsules with non zero EmbeddedDriverCount.\r
-                                      FALSE: No need to skip any FMP capsules.\r
-\r
-  @retval EFI_SUCCESS             There is no error when processing capsules.\r
-  @retval EFI_OUT_OF_RESOURCES    No enough resource to process capsules.\r
+VOID                        **mCapsulePtr;\r
+EFI_STATUS                  *mCapsuleStatusArray;\r
+UINT32                      mCapsuleTotalNumber;\r
 \r
+/**\r
+  This function initializes the mCapsulePtr, mCapsuleStatusArray and mCapsuleTotalNumber.\r
 **/\r
-EFI_STATUS\r
-ProcessTheseCapsules (\r
-  IN BOOLEAN  NeedBlockDriver\r
+VOID\r
+InitCapsulePtr (\r
+  VOID\r
   )\r
 {\r
-  EFI_STATUS                  Status;\r
   EFI_PEI_HOB_POINTERS        HobPointer;\r
-  EFI_CAPSULE_HEADER          *CapsuleHeader;\r
-  UINT32                      Size;\r
-  UINT32                      CapsuleNumber;\r
-  UINT32                      CapsuleTotalNumber;\r
-  EFI_CAPSULE_TABLE           *CapsuleTable;\r
-  UINT32                      Index;\r
-  UINT32                      CacheIndex;\r
-  UINT32                      CacheNumber;\r
-  VOID                        **CapsulePtr;\r
-  VOID                        **CapsulePtrCache;\r
-  EFI_GUID                    *CapsuleGuidCache;\r
-  EFI_STATUS                  *CapsuleStatusArray;\r
-  BOOLEAN                     DisplayCapsuleExist;\r
-  ESRT_MANAGEMENT_PROTOCOL    *EsrtManagement;\r
-  UINT16                      EmbeddedDriverCount;\r
-\r
-  REPORT_STATUS_CODE(EFI_PROGRESS_CODE, (EFI_SOFTWARE | PcdGet32(PcdStatusCodeSubClassCapsule) | PcdGet32(PcdCapsuleStatusCodeProcessCapsulesBegin)));\r
+  UINTN                       Index;\r
 \r
-  CapsuleNumber       = 0;\r
-  CapsuleTotalNumber  = 0;\r
-  CacheIndex          = 0;\r
-  CacheNumber         = 0;\r
-  CapsulePtr          = NULL;\r
-  CapsulePtrCache     = NULL;\r
-  CapsuleGuidCache    = NULL;\r
-  DisplayCapsuleExist = FALSE;\r
-  EsrtManagement      = NULL;\r
-\r
-  Status = EFI_SUCCESS;\r
   //\r
   // Find all capsule images from hob\r
   //\r
@@ -157,61 +120,108 @@ ProcessTheseCapsules (
     if (!IsValidCapsuleHeader((VOID *)(UINTN)HobPointer.Capsule->BaseAddress, HobPointer.Capsule->Length)) {\r
       HobPointer.Header->HobType = EFI_HOB_TYPE_UNUSED; // Mark this hob as invalid\r
     } else {\r
-      CapsuleTotalNumber++;\r
+      mCapsuleTotalNumber++;\r
     }\r
     HobPointer.Raw = GET_NEXT_HOB (HobPointer);\r
   }\r
 \r
-  if (CapsuleTotalNumber == 0) {\r
-    //\r
-    // We didn't find a hob, so had no errors.\r
-    //\r
-    DEBUG ((DEBUG_ERROR, "We can not find capsule data in capsule update boot mode.\n"));\r
-    Status = EFI_SUCCESS;\r
-    goto Done;\r
+  DEBUG ((DEBUG_INFO, "mCapsuleTotalNumber - 0x%x\n", mCapsuleTotalNumber));\r
+\r
+  if (mCapsuleTotalNumber == 0) {\r
+    return ;\r
   }\r
 \r
   //\r
   // Init temp Capsule Data table.\r
   //\r
-  CapsulePtr       = (VOID **) AllocateZeroPool (sizeof (VOID *) * CapsuleTotalNumber);\r
-  ASSERT (CapsulePtr != NULL);\r
-  if (CapsulePtr == NULL) {\r
-    Status = EFI_OUT_OF_RESOURCES;\r
-    goto Done;\r
-  }\r
-  CapsulePtrCache  = (VOID **) AllocateZeroPool (sizeof (VOID *) * CapsuleTotalNumber);\r
-  ASSERT (CapsulePtrCache != NULL);\r
-  if (CapsulePtrCache == NULL) {\r
-    Status = EFI_OUT_OF_RESOURCES;\r
-    goto Done;\r
+  mCapsulePtr       = (VOID **) AllocateZeroPool (sizeof (VOID *) * mCapsuleTotalNumber);\r
+  if (mCapsulePtr == NULL) {\r
+    DEBUG ((DEBUG_ERROR, "Allocate mCapsulePtr fail!\n"));\r
+    mCapsuleTotalNumber = 0;\r
+    return ;\r
   }\r
-  CapsuleGuidCache = (EFI_GUID *) AllocateZeroPool (sizeof (EFI_GUID) * CapsuleTotalNumber);\r
-  ASSERT (CapsuleGuidCache != NULL);\r
-  if (CapsuleGuidCache == NULL) {\r
-    Status = EFI_OUT_OF_RESOURCES;\r
-    goto Done;\r
-  }\r
-  CapsuleStatusArray = (EFI_STATUS *) AllocateZeroPool (sizeof (EFI_STATUS) * CapsuleTotalNumber);\r
-  ASSERT (CapsuleStatusArray != NULL);\r
-  if (CapsuleStatusArray == NULL) {\r
-    Status = EFI_OUT_OF_RESOURCES;\r
-    goto Done;\r
+  mCapsuleStatusArray = (EFI_STATUS *) AllocateZeroPool (sizeof (EFI_STATUS) * mCapsuleTotalNumber);\r
+  if (mCapsuleStatusArray == NULL) {\r
+    DEBUG ((DEBUG_ERROR, "Allocate mCapsuleStatusArray fail!\n"));\r
+    FreePool (mCapsulePtr);\r
+    mCapsulePtr = NULL;\r
+    mCapsuleTotalNumber = 0;\r
+    return ;\r
   }\r
+  SetMemN (mCapsuleStatusArray, sizeof (EFI_STATUS) * mCapsuleTotalNumber, EFI_NOT_READY);\r
 \r
   //\r
   // Find all capsule images from hob\r
   //\r
   HobPointer.Raw = GetHobList ();\r
+  Index = 0;\r
   while ((HobPointer.Raw = GetNextHob (EFI_HOB_TYPE_UEFI_CAPSULE, HobPointer.Raw)) != NULL) {\r
-    CapsulePtr [CapsuleNumber++] = (VOID *) (UINTN) HobPointer.Capsule->BaseAddress;\r
+    mCapsulePtr [Index++] = (VOID *) (UINTN) HobPointer.Capsule->BaseAddress;\r
     HobPointer.Raw = GET_NEXT_HOB (HobPointer);\r
   }\r
+}\r
 \r
-  //\r
-  // Check the capsule flags,if contains CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE, install\r
-  // capsuleTable to configure table with EFI_CAPSULE_GUID\r
-  //\r
+/**\r
+  This function returns if all capsule images are processed.\r
+\r
+  @retval TRUE   All capsule images are processed.\r
+  @retval FALSE  Not all capsule images are processed.\r
+**/\r
+BOOLEAN\r
+AreAllImagesProcessed (\r
+  VOID\r
+  )\r
+{\r
+  UINTN  Index;\r
+\r
+  for (Index = 0; Index < mCapsuleTotalNumber; Index++) {\r
+    if (mCapsuleStatusArray[Index] == EFI_NOT_READY) {\r
+      return FALSE;\r
+    }\r
+  }\r
+\r
+  return TRUE;\r
+}\r
+\r
+/**\r
+  This function populates capsule in the configuration table.\r
+**/\r
+VOID\r
+PopulateCapsuleInConfigurationTable (\r
+  VOID\r
+  )\r
+{\r
+  VOID                        **CapsulePtrCache;\r
+  EFI_GUID                    *CapsuleGuidCache;\r
+  EFI_CAPSULE_HEADER          *CapsuleHeader;\r
+  EFI_CAPSULE_TABLE           *CapsuleTable;\r
+  UINT32                      CacheIndex;\r
+  UINT32                      CacheNumber;\r
+  UINT32                      CapsuleNumber;\r
+  UINTN                       Index;\r
+  UINTN                       Size;\r
+  EFI_STATUS                  Status;\r
+\r
+  if (mCapsuleTotalNumber == 0) {\r
+    return ;\r
+  }\r
+\r
+  CapsulePtrCache     = NULL;\r
+  CapsuleGuidCache    = NULL;\r
+  CacheIndex          = 0;\r
+  CacheNumber         = 0;\r
+\r
+  CapsulePtrCache  = (VOID **) AllocateZeroPool (sizeof (VOID *) * mCapsuleTotalNumber);\r
+  if (CapsulePtrCache == NULL) {\r
+    DEBUG ((DEBUG_ERROR, "Allocate CapsulePtrCache fail!\n"));\r
+    return ;\r
+  }\r
+  CapsuleGuidCache = (EFI_GUID *) AllocateZeroPool (sizeof (EFI_GUID) * mCapsuleTotalNumber);\r
+  if (CapsuleGuidCache == NULL) {\r
+    DEBUG ((DEBUG_ERROR, "Allocate CapsuleGuidCache fail!\n"));\r
+    FreePool (CapsulePtrCache);\r
+    return ;\r
+  }\r
 \r
   //\r
   // Capsules who have CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE always are used for operating\r
@@ -223,9 +233,8 @@ ProcessTheseCapsules (
   // Firstly, Loop for all coalesced capsules, record unique CapsuleGuids and cache them in an\r
   // array for later sorting capsules by CapsuleGuid.\r
   //\r
-  for (Index = 0; Index < CapsuleTotalNumber; Index++) {\r
-    CapsuleStatusArray [Index] = EFI_UNSUPPORTED;\r
-    CapsuleHeader = (EFI_CAPSULE_HEADER*) CapsulePtr [Index];\r
+  for (Index = 0; Index < mCapsuleTotalNumber; Index++) {\r
+    CapsuleHeader = (EFI_CAPSULE_HEADER*) mCapsulePtr [Index];\r
     if ((CapsuleHeader->Flags & CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE) != 0) {\r
       //\r
       // For each capsule, we compare it with known CapsuleGuid in the CacheArray.\r
@@ -254,38 +263,90 @@ ProcessTheseCapsules (
   // will look in EFI System Table and search for the capsule's Guid and associated\r
   // pointer to retrieve the data.\r
   //\r
-  CacheIndex = 0;\r
-  while (CacheIndex < CacheNumber) {\r
+  for (CacheIndex = 0; CacheIndex < CacheNumber; CacheIndex++) {\r
     CapsuleNumber = 0;\r
-    for (Index = 0; Index < CapsuleTotalNumber; Index++) {\r
-      CapsuleHeader = (EFI_CAPSULE_HEADER*) CapsulePtr [Index];\r
+    for (Index = 0; Index < mCapsuleTotalNumber; Index++) {\r
+      CapsuleHeader = (EFI_CAPSULE_HEADER*) mCapsulePtr [Index];\r
       if ((CapsuleHeader->Flags & CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE) != 0) {\r
         if (CompareGuid (&CapsuleGuidCache[CacheIndex], &CapsuleHeader->CapsuleGuid)) {\r
           //\r
           // Cache Caspuleheader to the array, this array is uniqued with certain CapsuleGuid.\r
           //\r
           CapsulePtrCache[CapsuleNumber++] = (VOID*)CapsuleHeader;\r
-          //\r
-          // When a Capsule is listed in CapsulePtrCache, it will be reported in ConfigurationTable\r
-          // So, report the CapsuleStatus as "processed successfully".\r
-          //\r
-          CapsuleStatusArray [Index] = EFI_SUCCESS;\r
         }\r
       }\r
     }\r
     if (CapsuleNumber != 0) {\r
       Size = sizeof(EFI_CAPSULE_TABLE) + (CapsuleNumber - 1) * sizeof(VOID*);\r
       CapsuleTable = AllocateRuntimePool (Size);\r
-      ASSERT (CapsuleTable != NULL);\r
       if (CapsuleTable == NULL) {\r
-        return EFI_OUT_OF_RESOURCES;\r
+        DEBUG ((DEBUG_ERROR, "Allocate CapsuleTable (%g) fail!\n", &CapsuleGuidCache[CacheIndex]));\r
+        continue;\r
       }\r
       CapsuleTable->CapsuleArrayNumber =  CapsuleNumber;\r
       CopyMem(&CapsuleTable->CapsulePtr[0], CapsulePtrCache, CapsuleNumber * sizeof(VOID*));\r
       Status = gBS->InstallConfigurationTable (&CapsuleGuidCache[CacheIndex], (VOID*)CapsuleTable);\r
-      ASSERT_EFI_ERROR (Status);\r
+      if (EFI_ERROR (Status)) {\r
+        DEBUG ((DEBUG_ERROR, "InstallConfigurationTable (%g) fail!\n", &CapsuleGuidCache[CacheIndex]));\r
+      }\r
     }\r
-    CacheIndex++;\r
+  }\r
+\r
+  FreePool(CapsuleGuidCache);\r
+  FreePool(CapsulePtrCache);\r
+}\r
+\r
+/**\r
+\r
+  This routine is called to process capsules.\r
+\r
+  Caution: This function may receive untrusted input.\r
+\r
+  Each individual capsule result is recorded in capsule record variable.\r
+\r
+  @param[in]  FirstRound         TRUE:  First round. Need skip the FMP capsules with non zero EmbeddedDriverCount.\r
+                                 FALSE: Process rest FMP capsules.\r
+\r
+  @retval EFI_SUCCESS             There is no error when processing capsules.\r
+  @retval EFI_OUT_OF_RESOURCES    No enough resource to process capsules.\r
+\r
+**/\r
+EFI_STATUS\r
+ProcessTheseCapsules (\r
+  IN BOOLEAN  FirstRound\r
+  )\r
+{\r
+  EFI_STATUS                  Status;\r
+  EFI_CAPSULE_HEADER          *CapsuleHeader;\r
+  UINT32                      Index;\r
+  BOOLEAN                     DisplayCapsuleExist;\r
+  ESRT_MANAGEMENT_PROTOCOL    *EsrtManagement;\r
+  UINT16                      EmbeddedDriverCount;\r
+\r
+  REPORT_STATUS_CODE(EFI_PROGRESS_CODE, (EFI_SOFTWARE | PcdGet32(PcdStatusCodeSubClassCapsule) | PcdGet32(PcdCapsuleStatusCodeProcessCapsulesBegin)));\r
+\r
+  if (FirstRound) {\r
+    InitCapsulePtr ();\r
+  }\r
+\r
+  if (mCapsuleTotalNumber == 0) {\r
+    //\r
+    // We didn't find a hob, so had no errors.\r
+    //\r
+    DEBUG ((DEBUG_ERROR, "We can not find capsule data in capsule update boot mode.\n"));\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  if (AreAllImagesProcessed ()) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  //\r
+  // Check the capsule flags,if contains CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE, install\r
+  // capsuleTable to configure table with EFI_CAPSULE_GUID\r
+  //\r
+  if (FirstRound) {\r
+    PopulateCapsuleInConfigurationTable ();\r
   }\r
 \r
   REPORT_STATUS_CODE(EFI_PROGRESS_CODE, (EFI_SOFTWARE | PcdGet32(PcdStatusCodeSubClassCapsule) | PcdGet32(PcdCapsuleStatusCodeUpdatingFirmware)));\r
@@ -293,15 +354,16 @@ ProcessTheseCapsules (
   //\r
   // If Windows UX capsule exist, process it first\r
   //\r
-  for (Index = 0; Index < CapsuleTotalNumber; Index++) {\r
-    CapsuleHeader = (EFI_CAPSULE_HEADER*) CapsulePtr [Index];\r
-    if (CompareGuid(&CapsuleHeader->CapsuleGuid ,&gWindowsUxCapsuleGuid)) {\r
+  DisplayCapsuleExist = FALSE;\r
+  for (Index = 0; Index < mCapsuleTotalNumber; Index++) {\r
+    CapsuleHeader = (EFI_CAPSULE_HEADER*) mCapsulePtr [Index];\r
+    if (CompareGuid (&CapsuleHeader->CapsuleGuid, &gWindowsUxCapsuleGuid)) {\r
       DEBUG ((DEBUG_INFO, "ProcessCapsuleImage (Ux) - 0x%x\n", CapsuleHeader));\r
       DisplayCapsuleExist = TRUE;\r
       DEBUG ((DEBUG_INFO, "Display logo capsule is found.\n"));\r
       Status = ProcessCapsuleImage (CapsuleHeader);\r
+      mCapsuleStatusArray [Index] = EFI_SUCCESS;\r
       DEBUG((DEBUG_INFO, "ProcessCapsuleImage (Ux) - %r\n", Status));\r
-      CapsuleStatusArray [Index] = Status;\r
       break;\r
     }\r
   }\r
@@ -316,38 +378,48 @@ ProcessTheseCapsules (
   //\r
   // All capsules left are recognized by platform.\r
   //\r
-  for (Index = 0; Index < CapsuleTotalNumber; Index++) {\r
-    CapsuleHeader = (EFI_CAPSULE_HEADER*) CapsulePtr [Index];\r
-    if (!CompareGuid(&CapsuleHeader->CapsuleGuid ,&gWindowsUxCapsuleGuid)) {\r
+  for (Index = 0; Index < mCapsuleTotalNumber; Index++) {\r
+    if (mCapsuleStatusArray [Index] != EFI_NOT_READY) {\r
+      // already processed\r
+      continue;\r
+    }\r
+    CapsuleHeader = (EFI_CAPSULE_HEADER*) mCapsulePtr [Index];\r
+    if (!CompareGuid (&CapsuleHeader->CapsuleGuid, &gWindowsUxCapsuleGuid)) {\r
       //\r
       // Call capsule library to process capsule image.\r
       //\r
       EmbeddedDriverCount = 0;\r
       if (IsFmpCapsule(CapsuleHeader)) {\r
-        Status = ValidateFmpCapsule(CapsuleHeader, &EmbeddedDriverCount);\r
+        Status = ValidateFmpCapsule (CapsuleHeader, &EmbeddedDriverCount);\r
         if (EFI_ERROR(Status)) {\r
           DEBUG((DEBUG_ERROR, "ValidateFmpCapsule failed. Ignore!\n"));\r
+          mCapsuleStatusArray [Index] = EFI_ABORTED;\r
           continue;\r
         }\r
+      } else {\r
+        mCapsuleStatusArray [Index] = EFI_ABORTED;\r
+        continue;\r
       }\r
 \r
-      if ((!NeedBlockDriver) || (EmbeddedDriverCount == 0)) {\r
+      if ((!FirstRound) || (EmbeddedDriverCount == 0)) {\r
         DEBUG((DEBUG_INFO, "ProcessCapsuleImage - 0x%x\n", CapsuleHeader));\r
         Status = ProcessCapsuleImage (CapsuleHeader);\r
-        CapsuleStatusArray [Index] = Status;\r
+        mCapsuleStatusArray [Index] = Status;\r
         DEBUG((DEBUG_INFO, "ProcessCapsuleImage - %r\n", Status));\r
 \r
-        if (EFI_ERROR(Status)) {\r
-          REPORT_STATUS_CODE(EFI_ERROR_CODE, (EFI_SOFTWARE | PcdGet32(PcdStatusCodeSubClassCapsule) | PcdGet32(PcdCapsuleStatusCodeUpdateFirmwareFailed)));\r
-          DEBUG ((DEBUG_ERROR, "Capsule process failed. reset the system!\n"));\r
-          Print (L"Firmware update failed...\r\n");\r
-        } else {\r
-          REPORT_STATUS_CODE(EFI_PROGRESS_CODE, (EFI_SOFTWARE | PcdGet32(PcdStatusCodeSubClassCapsule) | PcdGet32(PcdCapsuleStatusCodeUpdateFirmwareSuccess)));\r
-        }\r
-\r
-        if ((CapsuleHeader->Flags & PcdGet16(PcdSystemRebootAfterCapsuleProcessFlag)) != 0 ||\r
-            IsFmpCapsule(CapsuleHeader)) {\r
-          mNeedReset = TRUE;\r
+        if (Status != EFI_NOT_READY) {\r
+          if (EFI_ERROR(Status)) {\r
+            REPORT_STATUS_CODE(EFI_ERROR_CODE, (EFI_SOFTWARE | PcdGet32(PcdStatusCodeSubClassCapsule) | PcdGet32(PcdCapsuleStatusCodeUpdateFirmwareFailed)));\r
+            DEBUG ((DEBUG_ERROR, "Capsule process failed!\n"));\r
+            Print (L"Firmware update failed...\r\n");\r
+          } else {\r
+            REPORT_STATUS_CODE(EFI_PROGRESS_CODE, (EFI_SOFTWARE | PcdGet32(PcdStatusCodeSubClassCapsule) | PcdGet32(PcdCapsuleStatusCodeUpdateFirmwareSuccess)));\r
+          }\r
+\r
+          if ((CapsuleHeader->Flags & PcdGet16(PcdSystemRebootAfterCapsuleProcessFlag)) != 0 ||\r
+              IsFmpCapsule(CapsuleHeader)) {\r
+            mNeedReset = TRUE;\r
+          }\r
         }\r
       }\r
     }\r
@@ -362,20 +434,6 @@ ProcessTheseCapsules (
   }\r
   Status = EFI_SUCCESS;\r
 \r
-Done:\r
-  //\r
-  // Free the allocated temp memory space.\r
-  //\r
-  if (CapsuleGuidCache != NULL) {\r
-    FreePool(CapsuleGuidCache);\r
-  }\r
-  if (CapsulePtrCache != NULL) {\r
-    FreePool(CapsulePtrCache);\r
-  }\r
-  if (CapsulePtr != NULL) {\r
-    FreePool(CapsulePtr);\r
-  }\r
-\r
   REPORT_STATUS_CODE(EFI_PROGRESS_CODE, (EFI_SOFTWARE | PcdGet32(PcdStatusCodeSubClassCapsule) | PcdGet32(PcdCapsuleStatusCodeProcessCapsulesEnd)));\r
 \r
   return Status;\r
@@ -446,20 +504,13 @@ ProcessCapsules (
   EFI_STATUS                    Status;\r
 \r
   if (!mDxeCapsuleLibEndOfDxe) {\r
-    //\r
-    // Initialize mAreAllImagesProcessed to be TRUE.\r
-    //\r
-    // It will be updated to FALSE in ProcessTheseCapsules()->ProcessCapsuleImage(),\r
-    // if there is any FMP image in any FMP capsule not processed.\r
-    //\r
-    mAreAllImagesProcessed = TRUE;\r
-\r
     Status = ProcessTheseCapsules(TRUE);\r
+\r
     //\r
     // Reboot System if and only if all capsule processed.\r
     // If not, defer reset to 2nd process.\r
     //\r
-    if (mNeedReset && mAreAllImagesProcessed) {\r
+    if (mNeedReset && AreAllImagesProcessed()) {\r
       DoResetSystem();\r
     }\r
   } else {\r