diff options
Diffstat (limited to 'MdeModulePkg/Library/UefiBootManagerLib/BmDriverHealth.c')
-rw-r--r-- | MdeModulePkg/Library/UefiBootManagerLib/BmDriverHealth.c | 1156 |
1 files changed, 578 insertions, 578 deletions
diff --git a/MdeModulePkg/Library/UefiBootManagerLib/BmDriverHealth.c b/MdeModulePkg/Library/UefiBootManagerLib/BmDriverHealth.c index 2b5257394e..d197816fa1 100644 --- a/MdeModulePkg/Library/UefiBootManagerLib/BmDriverHealth.c +++ b/MdeModulePkg/Library/UefiBootManagerLib/BmDriverHealth.c @@ -1,578 +1,578 @@ -/** @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
+ 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);
+ }
+}
|