]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Library/UefiBootManagerLib/BmDriverHealth.c
MdeModulePkg: Fix EOL to be DOS format.
[mirror_edk2.git] / MdeModulePkg / Library / UefiBootManagerLib / BmDriverHealth.c
index 2b5257394e21847b22028fd2801a130692e84cff..d197816fa1fa99ab6ed74c1c414cdbeedb4fb744 100644 (file)
-/** @file
-  Library functions which relates with driver health.
-
-Copyright (c) 2011 - 2015, Intel Corporation. All rights reserved.<BR>
-This program and the accompanying materials
-are licensed and made available under the terms and conditions of the BSD License
-which accompanies this distribution.  The full text of the license may be found at
-http://opensource.org/licenses/bsd-license.php
-
-THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
-WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
-
-**/
-
-#include "InternalBm.h"
-
-GLOBAL_REMOVE_IF_UNREFERENCED
-  CHAR16 *mBmHealthStatusText[] = {
-    L"Healthy",
-    L"Repair Required",
-    L"Configuration Required",
-    L"Failed",
-    L"Reconnect Required",
-    L"Reboot Required"
-    };
-
-/**
-  Return the controller name.
-
-  @param DriverHealthHandle  The handle on which the Driver Health protocol instance is retrieved.
-  @param ControllerHandle    The handle of a controller that the driver specified by DriverBindingHandle is managing.
-                             This handle specifies the controller whose name is to be returned.
-  @param ChildHandle         The handle of the child controller to retrieve the name of. This is an
-                             optional parameter that may be NULL. It will be NULL for device drivers.
-                             It will also be NULL for bus drivers that attempt to retrieve the name
-                             of the bus controller. It will not be NULL for a bus driver that attempts
-                             to retrieve the name of a child controller.
-
-  @return A pointer to the Unicode string to return. This Unicode string is the name of the controller
-          specified by ControllerHandle and ChildHandle.
-**/
-CHAR16 *
-BmGetControllerName (
-  IN  EFI_HANDLE                   DriverHealthHandle,
-  IN  EFI_HANDLE                   ControllerHandle,
-  IN  EFI_HANDLE                   ChildHandle
-  )
-{
-  EFI_STATUS                       Status;
-  CHAR16                           *ControllerName;
-  CHAR8                            *LanguageVariable;
-  CHAR8                            *BestLanguage;
-  BOOLEAN                          Iso639Language;
-  EFI_COMPONENT_NAME_PROTOCOL      *ComponentName;
-
-  ControllerName = NULL;
-
-  //
-  // Locate Component Name (2) protocol on the driver binging handle.
-  //
-  Iso639Language = FALSE;
-  Status = gBS->HandleProtocol (
-                 DriverHealthHandle,
-                 &gEfiComponentName2ProtocolGuid,
-                 (VOID **) &ComponentName
-                 );
-  if (EFI_ERROR (Status)) {
-    Status = gBS->HandleProtocol (
-                    DriverHealthHandle,
-                    &gEfiComponentNameProtocolGuid,
-                    (VOID **) &ComponentName
-                    );
-    if (!EFI_ERROR (Status)) {
-      Iso639Language = TRUE;
-    }
-  }
-
-  if (!EFI_ERROR (Status)) {
-    LanguageVariable = GetEfiGlobalVariable (Iso639Language ? L"Lang" : L"PlatformLang");
-    BestLanguage     = GetBestLanguage(
-                         ComponentName->SupportedLanguages,
-                         Iso639Language,
-                         (LanguageVariable != NULL) ? LanguageVariable : "",
-                         Iso639Language ? "eng" : "en-US",
-                         NULL
-                         );
-    if (LanguageVariable != NULL) {
-      FreePool (LanguageVariable);
-    }
-
-    Status = ComponentName->GetControllerName (
-                              ComponentName,
-                              ControllerHandle, 
-                              ChildHandle,
-                              BestLanguage,
-                              &ControllerName
-                              );
-  }
-
-  if (!EFI_ERROR (Status)) {
-    return AllocateCopyPool (StrSize (ControllerName), ControllerName);
-  } else {
-    return ConvertDevicePathToText (
-             DevicePathFromHandle (ChildHandle != NULL ? ChildHandle : ControllerHandle),
-             FALSE,
-             FALSE
-             );
-  }
-}
-
-/**
-  Display a set of messages returned by the GetHealthStatus () service of the EFI Driver Health Protocol
-
-  @param DriverHealthInfo  Pointer to the Driver Health information entry.
-**/
-VOID
-BmDisplayMessages (
-  IN  EFI_BOOT_MANAGER_DRIVER_HEALTH_INFO *DriverHealthInfo
-  )
-{
-  UINTN                            Index;
-  EFI_STRING                       String;
-  CHAR16                           *ControllerName;
-
-  if (DriverHealthInfo->MessageList == NULL ||
-      DriverHealthInfo->MessageList[0].HiiHandle == NULL) {
-    return;
-  }
-
-  ControllerName = BmGetControllerName (
-                     DriverHealthInfo->DriverHealthHandle,
-                     DriverHealthInfo->ControllerHandle, 
-                     DriverHealthInfo->ChildHandle
-                     );
-
-  DEBUG ((EFI_D_INFO, "Controller: %s\n", ControllerName));
-  Print (L"Controller: %s\n", ControllerName);
-  for (Index = 0; DriverHealthInfo->MessageList[Index].HiiHandle != NULL; Index++) {
-    String = HiiGetString (
-               DriverHealthInfo->MessageList[Index].HiiHandle,
-               DriverHealthInfo->MessageList[Index].StringId,
-               NULL
-               );
-    if (String != NULL) {
-      Print (L"  %s\n", String);
-      DEBUG ((EFI_D_INFO, "  %s\n", String));
-      FreePool (String);
-    }
-  }
-
-  if (ControllerName != NULL) {
-    FreePool (ControllerName);
-  }
-}
-
-/**
-  The repair notify function.
-  @param Value  A value between 0 and Limit that identifies the current progress
-                of the repair operation.
-  @param Limit  The maximum value of Value for the current repair operation.
-                If Limit is 0, then the completion progress is indeterminate.
-                For example, a driver that wants to specify progress in percent
-                would use a Limit value of 100.
-
-  @retval EFI_SUCCESS  Successfully return from the notify function.
-**/
-EFI_STATUS
-EFIAPI
-BmRepairNotify (
-  IN UINTN        Value,
-  IN UINTN        Limit
-  )
-{
-  DEBUG ((EFI_D_INFO, "[BDS]RepairNotify: %d/%d\n", Value, Limit));
-  Print (L"[BDS]RepairNotify: %d/%d\n", Value, Limit);
-
-  return EFI_SUCCESS;
-}
-
-/**
-  Collect the Driver Health status of a single controller.
-  
-  @param DriverHealthInfo        A pointer to the array containing all of the platform driver health information.
-  @param Count                   Return the updated array count.
-  @param DriverHealthHandle      The handle on which the Driver Health protocol instance is retrieved.
-  @param ControllerHandle        The handle of the controller..
-  @param ChildHandle             The handle of the child controller to retrieve the health
-                                 status on.  This is an optional parameter that may be NULL.
-
-  @retval Status                 The status returned from GetHealthStatus.
-  @retval EFI_ABORTED            The health status is healthy so no further query is needed.
-
-**/
-EFI_STATUS
-BmGetSingleControllerHealthStatus (
-  IN OUT EFI_BOOT_MANAGER_DRIVER_HEALTH_INFO **DriverHealthInfo,
-  IN OUT UINTN                               *Count,
-  IN  EFI_HANDLE                             DriverHealthHandle,
-  IN  EFI_HANDLE                             ControllerHandle,  OPTIONAL
-  IN  EFI_HANDLE                             ChildHandle        OPTIONAL
-  )
-{
-  EFI_STATUS                     Status;
-  EFI_DRIVER_HEALTH_PROTOCOL     *DriverHealth;
-  EFI_DRIVER_HEALTH_HII_MESSAGE  *MessageList;
-  EFI_HII_HANDLE                 FormHiiHandle;
-  EFI_DRIVER_HEALTH_STATUS       HealthStatus;
-
-  ASSERT (DriverHealthHandle != NULL);
-  //
-  // Retrieve the Driver Health Protocol from DriverHandle
-  //
-  Status = gBS->HandleProtocol (
-                  DriverHealthHandle,
-                  &gEfiDriverHealthProtocolGuid,
-                  (VOID **) &DriverHealth
-                  );
-  ASSERT_EFI_ERROR (Status);
-  
-
-  if (ControllerHandle == NULL) {
-    //
-    // If ControllerHandle is NULL, the return the cumulative health status of the driver
-    //
-    Status = DriverHealth->GetHealthStatus (DriverHealth, NULL, NULL, &HealthStatus, NULL, NULL);
-    if (!EFI_ERROR (Status) && HealthStatus == EfiDriverHealthStatusHealthy) {
-      *DriverHealthInfo = ReallocatePool (
-                            (*Count)     * sizeof (EFI_BOOT_MANAGER_DRIVER_HEALTH_INFO),
-                            (*Count + 1) * sizeof (EFI_BOOT_MANAGER_DRIVER_HEALTH_INFO),
-                            *DriverHealthInfo
-                            );
-      ASSERT (*DriverHealthInfo != NULL);
-
-      (*DriverHealthInfo)[*Count].DriverHealthHandle = DriverHealthHandle;
-      (*DriverHealthInfo)[*Count].DriverHealth       = DriverHealth;
-      (*DriverHealthInfo)[*Count].HealthStatus       = HealthStatus;
-
-      *Count = *Count + 1;
-
-      Status = EFI_ABORTED;
-    }
-    return Status;
-  }
-
-  MessageList   = NULL;
-  FormHiiHandle = NULL;
-
-  //
-  // Collect the health status with the optional HII message list
-  //
-  Status = DriverHealth->GetHealthStatus (DriverHealth, ControllerHandle, ChildHandle, &HealthStatus, &MessageList, &FormHiiHandle);
-  if (!EFI_ERROR (Status)) {
-    *DriverHealthInfo = ReallocatePool (
-                          (*Count)     * sizeof (EFI_BOOT_MANAGER_DRIVER_HEALTH_INFO),
-                          (*Count + 1) * sizeof (EFI_BOOT_MANAGER_DRIVER_HEALTH_INFO),
-                          *DriverHealthInfo
-                          );
-    ASSERT (*DriverHealthInfo != NULL);
-    (*DriverHealthInfo)[*Count].DriverHealth       = DriverHealth;
-    (*DriverHealthInfo)[*Count].DriverHealthHandle = DriverHealthHandle;
-    (*DriverHealthInfo)[*Count].ControllerHandle   = ControllerHandle;
-    (*DriverHealthInfo)[*Count].ChildHandle        = ChildHandle;
-    (*DriverHealthInfo)[*Count].HiiHandle          = FormHiiHandle;
-    (*DriverHealthInfo)[*Count].MessageList        = MessageList;
-    (*DriverHealthInfo)[*Count].HealthStatus       = HealthStatus;
-
-    *Count = *Count + 1;
-  }
-
-  return Status;
-}
-
-/**
-  Return all the Driver Health information.
-
-  When the cumulative health status of all the controllers managed by the
-  driver who produces the EFI_DRIVER_HEALTH_PROTOCOL is healthy, only one
-  EFI_BOOT_MANAGER_DRIVER_HEALTH_INFO entry is created for such
-  EFI_DRIVER_HEALTH_PROTOCOL instance.
-  Otherwise, every controller creates one EFI_BOOT_MANAGER_DRIVER_HEALTH_INFO
-  entry. Additionally every child controller creates one
-  EFI_BOOT_MANAGER_DRIVER_HEALTH_INFO entry if the driver is a bus driver.
-
-  @param Count      Return the count of the Driver Health information.
-
-  @retval NULL      No Driver Health information is returned.
-  @retval !NULL     Pointer to the Driver Health information array.
-**/
-EFI_BOOT_MANAGER_DRIVER_HEALTH_INFO *
-EFIAPI
-EfiBootManagerGetDriverHealthInfo (
-  UINTN                      *Count
-  )
-{
-  EFI_STATUS                 Status;
-  UINTN                      NumHandles;
-  EFI_HANDLE                 *DriverHealthHandles;
-  EFI_DRIVER_HEALTH_STATUS   HealthStatus;
-  UINTN                      DriverHealthIndex;
-  EFI_HANDLE                 *Handles;
-  UINTN                      HandleCount;
-  UINTN                      ControllerIndex;
-  UINTN                      ChildIndex;
-  EFI_BOOT_MANAGER_DRIVER_HEALTH_INFO  *DriverHealthInfo;
-
-  //
-  // Initialize local variables
-  //
-  *Count                  = 0;
-  DriverHealthInfo        = NULL;
-  Handles                 = NULL;
-  DriverHealthHandles     = NULL;
-  NumHandles              = 0;
-  HandleCount             = 0;
-
-  HealthStatus = EfiDriverHealthStatusHealthy;
-
-  Status = gBS->LocateHandleBuffer (
-                  ByProtocol,
-                  &gEfiDriverHealthProtocolGuid,
-                  NULL,
-                  &NumHandles,
-                  &DriverHealthHandles
-                  );
-
-  if (Status == EFI_NOT_FOUND || NumHandles == 0) {
-    //
-    // If there are no Driver Health Protocols handles, then return EFI_NOT_FOUND
-    //
-    return NULL;
-  }
-
-  ASSERT_EFI_ERROR (Status);
-  ASSERT (DriverHealthHandles != NULL);
-
-  //
-  // Check the health status of all controllers in the platform
-  // Start by looping through all the Driver Health Protocol handles in the handle database
-  //
-  for (DriverHealthIndex = 0; DriverHealthIndex < NumHandles; DriverHealthIndex++) {
-    //
-    // Get the cumulative health status of the driver
-    //
-    Status = BmGetSingleControllerHealthStatus (&DriverHealthInfo, Count, DriverHealthHandles[DriverHealthIndex], NULL, NULL);
-    if (EFI_ERROR (Status)) {
-      continue;
-    }
-
-    //
-    // See if the list of all handles in the handle database has been retrieved
-    //
-    //
-    if (Handles == NULL) {
-      //
-      // Retrieve the list of all handles from the handle database
-      //
-      Status = gBS->LocateHandleBuffer (
-        AllHandles,
-        NULL,
-        NULL,
-        &HandleCount,
-        &Handles
-        );
-      ASSERT_EFI_ERROR (Status);
-    }
-    //
-    // Loop through all the controller handles in the handle database
-    //
-    for (ControllerIndex = 0; ControllerIndex < HandleCount; ControllerIndex++) {
-      Status = BmGetSingleControllerHealthStatus (&DriverHealthInfo, Count, DriverHealthHandles[DriverHealthIndex], Handles[ControllerIndex], NULL);
-      if (EFI_ERROR (Status)) {
-        continue;
-      }
-
-      //
-      // Loop through all the child handles in the handle database
-      //
-      for (ChildIndex = 0; ChildIndex < HandleCount; ChildIndex++) {
-        Status = BmGetSingleControllerHealthStatus (&DriverHealthInfo, Count, DriverHealthHandles[DriverHealthIndex], Handles[ControllerIndex], Handles[ChildIndex]);
-        if (EFI_ERROR (Status)) {
-          continue;
-        }
-      }
-    }
-  }
-
-  Status = EFI_SUCCESS;
-
-  if (Handles != NULL) {
-    FreePool (Handles);
-  }
-  if (DriverHealthHandles != NULL) {
-    FreePool (DriverHealthHandles);
-  }
-
-  return DriverHealthInfo;
-}
-
-/**
-  Free the Driver Health information array.
-
-  @param DriverHealthInfo       Pointer to array of the Driver Health information.
-  @param Count                  Count of the array.
-
-  @retval EFI_SUCCESS           The array is freed.
-  @retval EFI_INVALID_PARAMETER The array is NULL.
-**/
-EFI_STATUS
-EFIAPI
-EfiBootManagerFreeDriverHealthInfo (
-  EFI_BOOT_MANAGER_DRIVER_HEALTH_INFO *DriverHealthInfo,
-  UINTN                               Count
-  )
-{
-  UINTN                               Index;
-
-  for (Index = 0; Index < Count; Index++) {
-    if (DriverHealthInfo[Index].MessageList != NULL) {
-      FreePool (DriverHealthInfo[Index].MessageList);
-    }
-  }
-  return gBS->FreePool (DriverHealthInfo);
-}
-
-/**
-  Repair all the controllers according to the Driver Health status queried.
-**/
-VOID
-BmRepairAllControllers (
-  VOID
-  )
-{
-  EFI_STATUS                          Status;
-  EFI_BOOT_MANAGER_DRIVER_HEALTH_INFO *DriverHealthInfo;
-  EFI_DRIVER_HEALTH_STATUS            HealthStatus;
-  UINTN                               Count;
-  UINTN                               Index;
-  BOOLEAN                             RepairRequired;
-  BOOLEAN                             ConfigurationRequired;
-  BOOLEAN                             ReconnectRequired;
-  BOOLEAN                             RebootRequired;
-  EFI_HII_HANDLE                      *HiiHandles;
-  EFI_FORM_BROWSER2_PROTOCOL          *FormBrowser2;
-
-  //
-  // Configure PcdDriverHealthConfigureForm to ZeroGuid to disable driver health check.
-  //
-  if (CompareGuid (PcdGetPtr (PcdDriverHealthConfigureForm), &gZeroGuid)) {
-    return;
-  }
-
-  Status = gBS->LocateProtocol (&gEfiFormBrowser2ProtocolGuid, NULL, (VOID **) &FormBrowser2);
-  ASSERT_EFI_ERROR (Status);
-
-  do {
-    RepairRequired        = FALSE;
-    ConfigurationRequired = FALSE;
-
-    //
-    // Deal with Repair Required
-    //
-    DriverHealthInfo = EfiBootManagerGetDriverHealthInfo (&Count);
-    for (Index = 0; Index < Count; Index++) {
-      if (DriverHealthInfo[Index].HealthStatus == EfiDriverHealthStatusConfigurationRequired) {
-        ConfigurationRequired = TRUE;
-      }
-      
-      if (DriverHealthInfo[Index].HealthStatus == EfiDriverHealthStatusRepairRequired) {
-        RepairRequired        = TRUE;
-
-        BmDisplayMessages (&DriverHealthInfo[Index]);
-
-        Status = DriverHealthInfo[Index].DriverHealth->Repair (
-                                                         DriverHealthInfo[Index].DriverHealth,
-                                                         DriverHealthInfo[Index].ControllerHandle,
-                                                         DriverHealthInfo[Index].ChildHandle,
-                                                         BmRepairNotify
-                                                         );
-        if (!EFI_ERROR (Status) && !ConfigurationRequired) {
-          Status = DriverHealthInfo[Index].DriverHealth->GetHealthStatus (
-                                                           DriverHealthInfo[Index].DriverHealth,
-                                                           DriverHealthInfo[Index].ControllerHandle,
-                                                           DriverHealthInfo[Index].ChildHandle,
-                                                           &HealthStatus,
-                                                           NULL,
-                                                           NULL
-                                                           );
-          if (!EFI_ERROR (Status) && (HealthStatus == EfiDriverHealthStatusConfigurationRequired)) {
-            ConfigurationRequired = TRUE;
-          }
-        }
-      }
-    }
-
-    if (ConfigurationRequired) {
-      HiiHandles = HiiGetHiiHandles (NULL);
-      if (HiiHandles != NULL) {
-        for (Index = 0; HiiHandles[Index] != NULL; Index++) {
-          Status = FormBrowser2->SendForm (
-                                   FormBrowser2,
-                                   &HiiHandles[Index],
-                                   1,
-                                   PcdGetPtr (PcdDriverHealthConfigureForm),
-                                   0,
-                                   NULL,
-                                   NULL
-                                   );
-          if (!EFI_ERROR (Status)) {
-            break;
-          }
-        }
-        FreePool (HiiHandles);
-      }
-    }
-  
-    EfiBootManagerFreeDriverHealthInfo (DriverHealthInfo, Count);
-  } while (RepairRequired || ConfigurationRequired);
-
-  RebootRequired    = FALSE;
-  ReconnectRequired = FALSE;
-  DriverHealthInfo  = EfiBootManagerGetDriverHealthInfo (&Count);
-  for (Index = 0; Index < Count; Index++) {
-
-    BmDisplayMessages (&DriverHealthInfo[Index]);
-
-    if (DriverHealthInfo[Index].HealthStatus == EfiDriverHealthStatusReconnectRequired) {
-      Status = gBS->DisconnectController (DriverHealthInfo[Index].ControllerHandle, NULL, NULL);
-      if (EFI_ERROR (Status)) {
-        //
-        // Disconnect failed. Need to promote reconnect to a reboot.
-        //
-        RebootRequired    = TRUE;
-      } else {
-        gBS->ConnectController (DriverHealthInfo[Index].ControllerHandle, NULL, NULL, TRUE);
-        ReconnectRequired = TRUE;
-      }
-    }
-
-    if (DriverHealthInfo[Index].HealthStatus == EfiDriverHealthStatusRebootRequired) {
-      RebootRequired      = TRUE;
-    }
-  }
-  EfiBootManagerFreeDriverHealthInfo (DriverHealthInfo, Count);
-
-
-  if (ReconnectRequired) {
-    BmRepairAllControllers ();
-  }
-
-  DEBUG_CODE (
-    CHAR16 *ControllerName;
-
-    DriverHealthInfo = EfiBootManagerGetDriverHealthInfo (&Count);
-    for (Index = 0; Index < Count; Index++) {
-      ControllerName = BmGetControllerName (
-                         DriverHealthInfo[Index].DriverHealthHandle,
-                         DriverHealthInfo[Index].ControllerHandle,
-                         DriverHealthInfo[Index].ChildHandle
-                         );
-      DEBUG ((
-        EFI_D_INFO,
-        "%02d: %s - %s\n",
-        Index,
-        ControllerName,
-        mBmHealthStatusText[DriverHealthInfo[Index].HealthStatus]
-        ));
-      if (ControllerName != NULL) {
-        FreePool (ControllerName);
-      }
-    }
-    EfiBootManagerFreeDriverHealthInfo (DriverHealthInfo, Count);
-    );
-
-  if (RebootRequired) {
-    DEBUG ((EFI_D_INFO, "[BDS] One of the Driver Health instances requires rebooting.\n"));
-    gRT->ResetSystem (EfiResetWarm, EFI_SUCCESS, 0, NULL);
-  }
-}
+/** @file\r
+  Library functions which relates with driver health.\r
+\r
+Copyright (c) 2011 - 2015, 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
+\r
+**/\r
+\r
+#include "InternalBm.h"\r
+\r
+GLOBAL_REMOVE_IF_UNREFERENCED\r
+  CHAR16 *mBmHealthStatusText[] = {\r
+    L"Healthy",\r
+    L"Repair Required",\r
+    L"Configuration Required",\r
+    L"Failed",\r
+    L"Reconnect Required",\r
+    L"Reboot Required"\r
+    };\r
+\r
+/**\r
+  Return the controller name.\r
+\r
+  @param DriverHealthHandle  The handle on which the Driver Health protocol instance is retrieved.\r
+  @param ControllerHandle    The handle of a controller that the driver specified by DriverBindingHandle is managing.\r
+                             This handle specifies the controller whose name is to be returned.\r
+  @param ChildHandle         The handle of the child controller to retrieve the name of. This is an\r
+                             optional parameter that may be NULL. It will be NULL for device drivers.\r
+                             It will also be NULL for bus drivers that attempt to retrieve the name\r
+                             of the bus controller. It will not be NULL for a bus driver that attempts\r
+                             to retrieve the name of a child controller.\r
+\r
+  @return A pointer to the Unicode string to return. This Unicode string is the name of the controller\r
+          specified by ControllerHandle and ChildHandle.\r
+**/\r
+CHAR16 *\r
+BmGetControllerName (\r
+  IN  EFI_HANDLE                   DriverHealthHandle,\r
+  IN  EFI_HANDLE                   ControllerHandle,\r
+  IN  EFI_HANDLE                   ChildHandle\r
+  )\r
+{\r
+  EFI_STATUS                       Status;\r
+  CHAR16                           *ControllerName;\r
+  CHAR8                            *LanguageVariable;\r
+  CHAR8                            *BestLanguage;\r
+  BOOLEAN                          Iso639Language;\r
+  EFI_COMPONENT_NAME_PROTOCOL      *ComponentName;\r
+\r
+  ControllerName = NULL;\r
+\r
+  //\r
+  // Locate Component Name (2) protocol on the driver binging handle.\r
+  //\r
+  Iso639Language = FALSE;\r
+  Status = gBS->HandleProtocol (\r
+                 DriverHealthHandle,\r
+                 &gEfiComponentName2ProtocolGuid,\r
+                 (VOID **) &ComponentName\r
+                 );\r
+  if (EFI_ERROR (Status)) {\r
+    Status = gBS->HandleProtocol (\r
+                    DriverHealthHandle,\r
+                    &gEfiComponentNameProtocolGuid,\r
+                    (VOID **) &ComponentName\r
+                    );\r
+    if (!EFI_ERROR (Status)) {\r
+      Iso639Language = TRUE;\r
+    }\r
+  }\r
+\r
+  if (!EFI_ERROR (Status)) {\r
+    LanguageVariable = GetEfiGlobalVariable (Iso639Language ? L"Lang" : L"PlatformLang");\r
+    BestLanguage     = GetBestLanguage(\r
+                         ComponentName->SupportedLanguages,\r
+                         Iso639Language,\r
+                         (LanguageVariable != NULL) ? LanguageVariable : "",\r
+                         Iso639Language ? "eng" : "en-US",\r
+                         NULL\r
+                         );\r
+    if (LanguageVariable != NULL) {\r
+      FreePool (LanguageVariable);\r
+    }\r
+\r
+    Status = ComponentName->GetControllerName (\r
+                              ComponentName,\r
+                              ControllerHandle, \r
+                              ChildHandle,\r
+                              BestLanguage,\r
+                              &ControllerName\r
+                              );\r
+  }\r
+\r
+  if (!EFI_ERROR (Status)) {\r
+    return AllocateCopyPool (StrSize (ControllerName), ControllerName);\r
+  } else {\r
+    return ConvertDevicePathToText (\r
+             DevicePathFromHandle (ChildHandle != NULL ? ChildHandle : ControllerHandle),\r
+             FALSE,\r
+             FALSE\r
+             );\r
+  }\r
+}\r
+\r
+/**\r
+  Display a set of messages returned by the GetHealthStatus () service of the EFI Driver Health Protocol\r
+\r
+  @param DriverHealthInfo  Pointer to the Driver Health information entry.\r
+**/\r
+VOID\r
+BmDisplayMessages (\r
+  IN  EFI_BOOT_MANAGER_DRIVER_HEALTH_INFO *DriverHealthInfo\r
+  )\r
+{\r
+  UINTN                            Index;\r
+  EFI_STRING                       String;\r
+  CHAR16                           *ControllerName;\r
+\r
+  if (DriverHealthInfo->MessageList == NULL ||\r
+      DriverHealthInfo->MessageList[0].HiiHandle == NULL) {\r
+    return;\r
+  }\r
+\r
+  ControllerName = BmGetControllerName (\r
+                     DriverHealthInfo->DriverHealthHandle,\r
+                     DriverHealthInfo->ControllerHandle, \r
+                     DriverHealthInfo->ChildHandle\r
+                     );\r
+\r
+  DEBUG ((EFI_D_INFO, "Controller: %s\n", ControllerName));\r
+  Print (L"Controller: %s\n", ControllerName);\r
+  for (Index = 0; DriverHealthInfo->MessageList[Index].HiiHandle != NULL; Index++) {\r
+    String = HiiGetString (\r
+               DriverHealthInfo->MessageList[Index].HiiHandle,\r
+               DriverHealthInfo->MessageList[Index].StringId,\r
+               NULL\r
+               );\r
+    if (String != NULL) {\r
+      Print (L"  %s\n", String);\r
+      DEBUG ((EFI_D_INFO, "  %s\n", String));\r
+      FreePool (String);\r
+    }\r
+  }\r
+\r
+  if (ControllerName != NULL) {\r
+    FreePool (ControllerName);\r
+  }\r
+}\r
+\r
+/**\r
+  The repair notify function.\r
+  @param Value  A value between 0 and Limit that identifies the current progress\r
+                of the repair operation.\r
+  @param Limit  The maximum value of Value for the current repair operation.\r
+                If Limit is 0, then the completion progress is indeterminate.\r
+                For example, a driver that wants to specify progress in percent\r
+                would use a Limit value of 100.\r
+\r
+  @retval EFI_SUCCESS  Successfully return from the notify function.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+BmRepairNotify (\r
+  IN UINTN        Value,\r
+  IN UINTN        Limit\r
+  )\r
+{\r
+  DEBUG ((EFI_D_INFO, "[BDS]RepairNotify: %d/%d\n", Value, Limit));\r
+  Print (L"[BDS]RepairNotify: %d/%d\n", Value, Limit);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Collect the Driver Health status of a single controller.\r
+  \r
+  @param DriverHealthInfo        A pointer to the array containing all of the platform driver health information.\r
+  @param Count                   Return the updated array count.\r
+  @param DriverHealthHandle      The handle on which the Driver Health protocol instance is retrieved.\r
+  @param ControllerHandle        The handle of the controller..\r
+  @param ChildHandle             The handle of the child controller to retrieve the health\r
+                                 status on.  This is an optional parameter that may be NULL.\r
+\r
+  @retval Status                 The status returned from GetHealthStatus.\r
+  @retval EFI_ABORTED            The health status is healthy so no further query is needed.\r
+\r
+**/\r
+EFI_STATUS\r
+BmGetSingleControllerHealthStatus (\r
+  IN OUT EFI_BOOT_MANAGER_DRIVER_HEALTH_INFO **DriverHealthInfo,\r
+  IN OUT UINTN                               *Count,\r
+  IN  EFI_HANDLE                             DriverHealthHandle,\r
+  IN  EFI_HANDLE                             ControllerHandle,  OPTIONAL\r
+  IN  EFI_HANDLE                             ChildHandle        OPTIONAL\r
+  )\r
+{\r
+  EFI_STATUS                     Status;\r
+  EFI_DRIVER_HEALTH_PROTOCOL     *DriverHealth;\r
+  EFI_DRIVER_HEALTH_HII_MESSAGE  *MessageList;\r
+  EFI_HII_HANDLE                 FormHiiHandle;\r
+  EFI_DRIVER_HEALTH_STATUS       HealthStatus;\r
+\r
+  ASSERT (DriverHealthHandle != NULL);\r
+  //\r
+  // Retrieve the Driver Health Protocol from DriverHandle\r
+  //\r
+  Status = gBS->HandleProtocol (\r
+                  DriverHealthHandle,\r
+                  &gEfiDriverHealthProtocolGuid,\r
+                  (VOID **) &DriverHealth\r
+                  );\r
+  ASSERT_EFI_ERROR (Status);\r
+  \r
+\r
+  if (ControllerHandle == NULL) {\r
+    //\r
+    // If ControllerHandle is NULL, the return the cumulative health status of the driver\r
+    //\r
+    Status = DriverHealth->GetHealthStatus (DriverHealth, NULL, NULL, &HealthStatus, NULL, NULL);\r
+    if (!EFI_ERROR (Status) && HealthStatus == EfiDriverHealthStatusHealthy) {\r
+      *DriverHealthInfo = ReallocatePool (\r
+                            (*Count)     * sizeof (EFI_BOOT_MANAGER_DRIVER_HEALTH_INFO),\r
+                            (*Count + 1) * sizeof (EFI_BOOT_MANAGER_DRIVER_HEALTH_INFO),\r
+                            *DriverHealthInfo\r
+                            );\r
+      ASSERT (*DriverHealthInfo != NULL);\r
+\r
+      (*DriverHealthInfo)[*Count].DriverHealthHandle = DriverHealthHandle;\r
+      (*DriverHealthInfo)[*Count].DriverHealth       = DriverHealth;\r
+      (*DriverHealthInfo)[*Count].HealthStatus       = HealthStatus;\r
+\r
+      *Count = *Count + 1;\r
+\r
+      Status = EFI_ABORTED;\r
+    }\r
+    return Status;\r
+  }\r
+\r
+  MessageList   = NULL;\r
+  FormHiiHandle = NULL;\r
+\r
+  //\r
+  // Collect the health status with the optional HII message list\r
+  //\r
+  Status = DriverHealth->GetHealthStatus (DriverHealth, ControllerHandle, ChildHandle, &HealthStatus, &MessageList, &FormHiiHandle);\r
+  if (!EFI_ERROR (Status)) {\r
+    *DriverHealthInfo = ReallocatePool (\r
+                          (*Count)     * sizeof (EFI_BOOT_MANAGER_DRIVER_HEALTH_INFO),\r
+                          (*Count + 1) * sizeof (EFI_BOOT_MANAGER_DRIVER_HEALTH_INFO),\r
+                          *DriverHealthInfo\r
+                          );\r
+    ASSERT (*DriverHealthInfo != NULL);\r
+    (*DriverHealthInfo)[*Count].DriverHealth       = DriverHealth;\r
+    (*DriverHealthInfo)[*Count].DriverHealthHandle = DriverHealthHandle;\r
+    (*DriverHealthInfo)[*Count].ControllerHandle   = ControllerHandle;\r
+    (*DriverHealthInfo)[*Count].ChildHandle        = ChildHandle;\r
+    (*DriverHealthInfo)[*Count].HiiHandle          = FormHiiHandle;\r
+    (*DriverHealthInfo)[*Count].MessageList        = MessageList;\r
+    (*DriverHealthInfo)[*Count].HealthStatus       = HealthStatus;\r
+\r
+    *Count = *Count + 1;\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Return all the Driver Health information.\r
+\r
+  When the cumulative health status of all the controllers managed by the\r
+  driver who produces the EFI_DRIVER_HEALTH_PROTOCOL is healthy, only one\r
+  EFI_BOOT_MANAGER_DRIVER_HEALTH_INFO entry is created for such\r
+  EFI_DRIVER_HEALTH_PROTOCOL instance.\r
+  Otherwise, every controller creates one EFI_BOOT_MANAGER_DRIVER_HEALTH_INFO\r
+  entry. Additionally every child controller creates one\r
+  EFI_BOOT_MANAGER_DRIVER_HEALTH_INFO entry if the driver is a bus driver.\r
+\r
+  @param Count      Return the count of the Driver Health information.\r
+\r
+  @retval NULL      No Driver Health information is returned.\r
+  @retval !NULL     Pointer to the Driver Health information array.\r
+**/\r
+EFI_BOOT_MANAGER_DRIVER_HEALTH_INFO *\r
+EFIAPI\r
+EfiBootManagerGetDriverHealthInfo (\r
+  UINTN                      *Count\r
+  )\r
+{\r
+  EFI_STATUS                 Status;\r
+  UINTN                      NumHandles;\r
+  EFI_HANDLE                 *DriverHealthHandles;\r
+  EFI_DRIVER_HEALTH_STATUS   HealthStatus;\r
+  UINTN                      DriverHealthIndex;\r
+  EFI_HANDLE                 *Handles;\r
+  UINTN                      HandleCount;\r
+  UINTN                      ControllerIndex;\r
+  UINTN                      ChildIndex;\r
+  EFI_BOOT_MANAGER_DRIVER_HEALTH_INFO  *DriverHealthInfo;\r
+\r
+  //\r
+  // Initialize local variables\r
+  //\r
+  *Count                  = 0;\r
+  DriverHealthInfo        = NULL;\r
+  Handles                 = NULL;\r
+  DriverHealthHandles     = NULL;\r
+  NumHandles              = 0;\r
+  HandleCount             = 0;\r
+\r
+  HealthStatus = EfiDriverHealthStatusHealthy;\r
+\r
+  Status = gBS->LocateHandleBuffer (\r
+                  ByProtocol,\r
+                  &gEfiDriverHealthProtocolGuid,\r
+                  NULL,\r
+                  &NumHandles,\r
+                  &DriverHealthHandles\r
+                  );\r
+\r
+  if (Status == EFI_NOT_FOUND || NumHandles == 0) {\r
+    //\r
+    // If there are no Driver Health Protocols handles, then return EFI_NOT_FOUND\r
+    //\r
+    return NULL;\r
+  }\r
+\r
+  ASSERT_EFI_ERROR (Status);\r
+  ASSERT (DriverHealthHandles != NULL);\r
+\r
+  //\r
+  // Check the health status of all controllers in the platform\r
+  // Start by looping through all the Driver Health Protocol handles in the handle database\r
+  //\r
+  for (DriverHealthIndex = 0; DriverHealthIndex < NumHandles; DriverHealthIndex++) {\r
+    //\r
+    // Get the cumulative health status of the driver\r
+    //\r
+    Status = BmGetSingleControllerHealthStatus (&DriverHealthInfo, Count, DriverHealthHandles[DriverHealthIndex], NULL, NULL);\r
+    if (EFI_ERROR (Status)) {\r
+      continue;\r
+    }\r
+\r
+    //\r
+    // See if the list of all handles in the handle database has been retrieved\r
+    //\r
+    //\r
+    if (Handles == NULL) {\r
+      //\r
+      // Retrieve the list of all handles from the handle database\r
+      //\r
+      Status = gBS->LocateHandleBuffer (\r
+        AllHandles,\r
+        NULL,\r
+        NULL,\r
+        &HandleCount,\r
+        &Handles\r
+        );\r
+      ASSERT_EFI_ERROR (Status);\r
+    }\r
+    //\r
+    // Loop through all the controller handles in the handle database\r
+    //\r
+    for (ControllerIndex = 0; ControllerIndex < HandleCount; ControllerIndex++) {\r
+      Status = BmGetSingleControllerHealthStatus (&DriverHealthInfo, Count, DriverHealthHandles[DriverHealthIndex], Handles[ControllerIndex], NULL);\r
+      if (EFI_ERROR (Status)) {\r
+        continue;\r
+      }\r
+\r
+      //\r
+      // Loop through all the child handles in the handle database\r
+      //\r
+      for (ChildIndex = 0; ChildIndex < HandleCount; ChildIndex++) {\r
+        Status = BmGetSingleControllerHealthStatus (&DriverHealthInfo, Count, DriverHealthHandles[DriverHealthIndex], Handles[ControllerIndex], Handles[ChildIndex]);\r
+        if (EFI_ERROR (Status)) {\r
+          continue;\r
+        }\r
+      }\r
+    }\r
+  }\r
+\r
+  Status = EFI_SUCCESS;\r
+\r
+  if (Handles != NULL) {\r
+    FreePool (Handles);\r
+  }\r
+  if (DriverHealthHandles != NULL) {\r
+    FreePool (DriverHealthHandles);\r
+  }\r
+\r
+  return DriverHealthInfo;\r
+}\r
+\r
+/**\r
+  Free the Driver Health information array.\r
+\r
+  @param DriverHealthInfo       Pointer to array of the Driver Health information.\r
+  @param Count                  Count of the array.\r
+\r
+  @retval EFI_SUCCESS           The array is freed.\r
+  @retval EFI_INVALID_PARAMETER The array is NULL.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EfiBootManagerFreeDriverHealthInfo (\r
+  EFI_BOOT_MANAGER_DRIVER_HEALTH_INFO *DriverHealthInfo,\r
+  UINTN                               Count\r
+  )\r
+{\r
+  UINTN                               Index;\r
+\r
+  for (Index = 0; Index < Count; Index++) {\r
+    if (DriverHealthInfo[Index].MessageList != NULL) {\r
+      FreePool (DriverHealthInfo[Index].MessageList);\r
+    }\r
+  }\r
+  return gBS->FreePool (DriverHealthInfo);\r
+}\r
+\r
+/**\r
+  Repair all the controllers according to the Driver Health status queried.\r
+**/\r
+VOID\r
+BmRepairAllControllers (\r
+  VOID\r
+  )\r
+{\r
+  EFI_STATUS                          Status;\r
+  EFI_BOOT_MANAGER_DRIVER_HEALTH_INFO *DriverHealthInfo;\r
+  EFI_DRIVER_HEALTH_STATUS            HealthStatus;\r
+  UINTN                               Count;\r
+  UINTN                               Index;\r
+  BOOLEAN                             RepairRequired;\r
+  BOOLEAN                             ConfigurationRequired;\r
+  BOOLEAN                             ReconnectRequired;\r
+  BOOLEAN                             RebootRequired;\r
+  EFI_HII_HANDLE                      *HiiHandles;\r
+  EFI_FORM_BROWSER2_PROTOCOL          *FormBrowser2;\r
+\r
+  //\r
+  // Configure PcdDriverHealthConfigureForm to ZeroGuid to disable driver health check.\r
+  //\r
+  if (CompareGuid (PcdGetPtr (PcdDriverHealthConfigureForm), &gZeroGuid)) {\r
+    return;\r
+  }\r
+\r
+  Status = gBS->LocateProtocol (&gEfiFormBrowser2ProtocolGuid, NULL, (VOID **) &FormBrowser2);\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  do {\r
+    RepairRequired        = FALSE;\r
+    ConfigurationRequired = FALSE;\r
+\r
+    //\r
+    // Deal with Repair Required\r
+    //\r
+    DriverHealthInfo = EfiBootManagerGetDriverHealthInfo (&Count);\r
+    for (Index = 0; Index < Count; Index++) {\r
+      if (DriverHealthInfo[Index].HealthStatus == EfiDriverHealthStatusConfigurationRequired) {\r
+        ConfigurationRequired = TRUE;\r
+      }\r
+      \r
+      if (DriverHealthInfo[Index].HealthStatus == EfiDriverHealthStatusRepairRequired) {\r
+        RepairRequired        = TRUE;\r
+\r
+        BmDisplayMessages (&DriverHealthInfo[Index]);\r
+\r
+        Status = DriverHealthInfo[Index].DriverHealth->Repair (\r
+                                                         DriverHealthInfo[Index].DriverHealth,\r
+                                                         DriverHealthInfo[Index].ControllerHandle,\r
+                                                         DriverHealthInfo[Index].ChildHandle,\r
+                                                         BmRepairNotify\r
+                                                         );\r
+        if (!EFI_ERROR (Status) && !ConfigurationRequired) {\r
+          Status = DriverHealthInfo[Index].DriverHealth->GetHealthStatus (\r
+                                                           DriverHealthInfo[Index].DriverHealth,\r
+                                                           DriverHealthInfo[Index].ControllerHandle,\r
+                                                           DriverHealthInfo[Index].ChildHandle,\r
+                                                           &HealthStatus,\r
+                                                           NULL,\r
+                                                           NULL\r
+                                                           );\r
+          if (!EFI_ERROR (Status) && (HealthStatus == EfiDriverHealthStatusConfigurationRequired)) {\r
+            ConfigurationRequired = TRUE;\r
+          }\r
+        }\r
+      }\r
+    }\r
+\r
+    if (ConfigurationRequired) {\r
+      HiiHandles = HiiGetHiiHandles (NULL);\r
+      if (HiiHandles != NULL) {\r
+        for (Index = 0; HiiHandles[Index] != NULL; Index++) {\r
+          Status = FormBrowser2->SendForm (\r
+                                   FormBrowser2,\r
+                                   &HiiHandles[Index],\r
+                                   1,\r
+                                   PcdGetPtr (PcdDriverHealthConfigureForm),\r
+                                   0,\r
+                                   NULL,\r
+                                   NULL\r
+                                   );\r
+          if (!EFI_ERROR (Status)) {\r
+            break;\r
+          }\r
+        }\r
+        FreePool (HiiHandles);\r
+      }\r
+    }\r
+  \r
+    EfiBootManagerFreeDriverHealthInfo (DriverHealthInfo, Count);\r
+  } while (RepairRequired || ConfigurationRequired);\r
+\r
+  RebootRequired    = FALSE;\r
+  ReconnectRequired = FALSE;\r
+  DriverHealthInfo  = EfiBootManagerGetDriverHealthInfo (&Count);\r
+  for (Index = 0; Index < Count; Index++) {\r
+\r
+    BmDisplayMessages (&DriverHealthInfo[Index]);\r
+\r
+    if (DriverHealthInfo[Index].HealthStatus == EfiDriverHealthStatusReconnectRequired) {\r
+      Status = gBS->DisconnectController (DriverHealthInfo[Index].ControllerHandle, NULL, NULL);\r
+      if (EFI_ERROR (Status)) {\r
+        //\r
+        // Disconnect failed. Need to promote reconnect to a reboot.\r
+        //\r
+        RebootRequired    = TRUE;\r
+      } else {\r
+        gBS->ConnectController (DriverHealthInfo[Index].ControllerHandle, NULL, NULL, TRUE);\r
+        ReconnectRequired = TRUE;\r
+      }\r
+    }\r
+\r
+    if (DriverHealthInfo[Index].HealthStatus == EfiDriverHealthStatusRebootRequired) {\r
+      RebootRequired      = TRUE;\r
+    }\r
+  }\r
+  EfiBootManagerFreeDriverHealthInfo (DriverHealthInfo, Count);\r
+\r
+\r
+  if (ReconnectRequired) {\r
+    BmRepairAllControllers ();\r
+  }\r
+\r
+  DEBUG_CODE (\r
+    CHAR16 *ControllerName;\r
+\r
+    DriverHealthInfo = EfiBootManagerGetDriverHealthInfo (&Count);\r
+    for (Index = 0; Index < Count; Index++) {\r
+      ControllerName = BmGetControllerName (\r
+                         DriverHealthInfo[Index].DriverHealthHandle,\r
+                         DriverHealthInfo[Index].ControllerHandle,\r
+                         DriverHealthInfo[Index].ChildHandle\r
+                         );\r
+      DEBUG ((\r
+        EFI_D_INFO,\r
+        "%02d: %s - %s\n",\r
+        Index,\r
+        ControllerName,\r
+        mBmHealthStatusText[DriverHealthInfo[Index].HealthStatus]\r
+        ));\r
+      if (ControllerName != NULL) {\r
+        FreePool (ControllerName);\r
+      }\r
+    }\r
+    EfiBootManagerFreeDriverHealthInfo (DriverHealthInfo, Count);\r
+    );\r
+\r
+  if (RebootRequired) {\r
+    DEBUG ((EFI_D_INFO, "[BDS] One of the Driver Health instances requires rebooting.\n"));\r
+    gRT->ResetSystem (EfiResetWarm, EFI_SUCCESS, 0, NULL);\r
+  }\r
+}\r