-/** @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
+(C) Copyright 2015 Hewlett-Packard Development Company, L.P.<BR>\r
+(C) Copyright 2016 Hewlett Packard Enterprise Development LP<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
+ GetEfiGlobalVariable2 (Iso639Language ? L"Lang" : L"PlatformLang", (VOID**)&LanguageVariable, NULL);\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
+ 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
+ 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
+ UINT32 MaxRepairCount;\r
+ UINT32 RepairCount;\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
+ MaxRepairCount = PcdGet32 (PcdMaxRepairCount);\r
+ RepairCount = 0;\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
+ RepairCount++;\r
+ } while ((RepairRequired || ConfigurationRequired) && ((MaxRepairCount == 0) || (RepairCount < MaxRepairCount)));\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