From af1a266670d040d2f4083ff309d732d648afba2a Mon Sep 17 00:00:00 2001 From: Angelos Mouzakitis Date: Tue, 10 Oct 2023 14:33:42 +0000 Subject: Add submodule dependency files Change-Id: Iaf8d18082d3991dec7c0ebbea540f092188eb4ec --- .../DriverHealthManagerDxe.c | 987 +++++++++++++++++++++ 1 file changed, 987 insertions(+) create mode 100644 roms/edk2/MdeModulePkg/Universal/DriverHealthManagerDxe/DriverHealthManagerDxe.c (limited to 'roms/edk2/MdeModulePkg/Universal/DriverHealthManagerDxe/DriverHealthManagerDxe.c') diff --git a/roms/edk2/MdeModulePkg/Universal/DriverHealthManagerDxe/DriverHealthManagerDxe.c b/roms/edk2/MdeModulePkg/Universal/DriverHealthManagerDxe/DriverHealthManagerDxe.c new file mode 100644 index 000000000..92c738a3f --- /dev/null +++ b/roms/edk2/MdeModulePkg/Universal/DriverHealthManagerDxe/DriverHealthManagerDxe.c @@ -0,0 +1,987 @@ +/** @file + This module produces two driver health manager forms. + One will be used by BDS core to configure the Configured Required + driver health instances, the other will be automatically included by + firmware setup (UI). + +Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.
+(C) Copyright 2018 Hewlett Packard Enterprise Development LP
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "DriverHealthManagerDxe.h" +#include "DriverHealthManagerVfr.h" + +EFI_HII_CONFIG_ACCESS_PROTOCOL mDriverHealthManagerConfigAccess = { + DriverHealthManagerFakeExtractConfig, + DriverHealthManagerFakeRouteConfig, + DriverHealthManagerCallback +}; + +EFI_GUID mDriverHealthManagerForm = DRIVER_HEALTH_MANAGER_FORMSET_GUID; + +FORM_DEVICE_PATH mDriverHealthManagerFormDevicePath = { + { + { + HARDWARE_DEVICE_PATH, + HW_VENDOR_DP, + { + (UINT8) (sizeof (VENDOR_DEVICE_PATH)), + (UINT8) ((sizeof (VENDOR_DEVICE_PATH)) >> 8) + } + }, + EFI_CALLER_ID_GUID + }, + { + END_DEVICE_PATH_TYPE, + END_ENTIRE_DEVICE_PATH_SUBTYPE, + { + (UINT8) (END_DEVICE_PATH_LENGTH), + (UINT8) ((END_DEVICE_PATH_LENGTH) >> 8) + } + } +}; + +EFI_HII_HANDLE mDriverHealthManagerHiiHandle; +EFI_BOOT_MANAGER_DRIVER_HEALTH_INFO *mDriverHealthManagerHealthInfo = NULL; +UINTN mDriverHealthManagerHealthInfoCount = 0; +EFI_HII_DATABASE_PROTOCOL *mDriverHealthManagerDatabase; + + +extern UINT8 DriverHealthManagerVfrBin[]; +extern UINT8 DriverHealthConfigureVfrBin[]; + +/** + This function allows a caller to extract the current configuration for one + or more named elements from the target driver. + + + @param This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL. + @param Request A null-terminated Unicode string in format. + @param Progress On return, points to a character in the Request string. + Points to the string's null terminator if request was successful. + Points to the most recent '&' before the first failing name/value + pair (or the beginning of the string if the failure is in the + first name/value pair) if the request was not successful. + @param Results A null-terminated Unicode string in format which + has all values filled in for the names in the Request string. + String to be allocated by the called function. + + @retval EFI_SUCCESS The Results is filled with the requested values. + @retval EFI_OUT_OF_RESOURCES Not enough memory to store the results. + @retval EFI_INVALID_PARAMETER Request is illegal syntax, or unknown name. + @retval EFI_NOT_FOUND Routing data doesn't match any storage in this driver. + +**/ +EFI_STATUS +EFIAPI +DriverHealthManagerFakeExtractConfig ( + IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This, + IN CONST EFI_STRING Request, + OUT EFI_STRING *Progress, + OUT EFI_STRING *Results + ) +{ + if (Progress == NULL || Results == NULL) { + return EFI_INVALID_PARAMETER; + } + *Progress = Request; + return EFI_NOT_FOUND; +} + +/** + This function processes the results of changes in configuration. + + + @param This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL. + @param Configuration A null-terminated Unicode string in format. + @param Progress A pointer to a string filled in with the offset of the most + recent '&' before the first failing name/value pair (or the + beginning of the string if the failure is in the first + name/value pair) or the terminating NULL if all was successful. + + @retval EFI_SUCCESS The Results is processed successfully. + @retval EFI_INVALID_PARAMETER Configuration is NULL. + @retval EFI_NOT_FOUND Routing data doesn't match any storage in this driver. + +**/ +EFI_STATUS +EFIAPI +DriverHealthManagerFakeRouteConfig ( + IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This, + IN CONST EFI_STRING Configuration, + OUT EFI_STRING *Progress + ) +{ + if (Configuration == NULL || Progress == NULL) { + return EFI_INVALID_PARAMETER; + } + + *Progress = Configuration; + + return EFI_NOT_FOUND; +} + +/** + + Install the health manager forms. + One will be used by BDS core to configure the Configured Required + driver health instances, the other will be automatically included by + firmware setup (UI). + + @param ImageHandle The image handle. + @param SystemTable The system table. + + @retval EFI_SUCEESS The health manager forms are successfully installed. + +**/ +EFI_STATUS +EFIAPI +InitializeDriverHealthManager ( + EFI_HANDLE ImageHandle, + EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + EFI_HANDLE Handle; + + Status = gBS->LocateProtocol ( + &gEfiHiiDatabaseProtocolGuid, + NULL, + (VOID **) &mDriverHealthManagerDatabase + ); + ASSERT_EFI_ERROR (Status); + + Handle = NULL; + Status = gBS->InstallMultipleProtocolInterfaces ( + &Handle, + &gEfiDevicePathProtocolGuid, + &mDriverHealthManagerFormDevicePath, + &gEfiHiiConfigAccessProtocolGuid, + &mDriverHealthManagerConfigAccess, + NULL + ); + ASSERT_EFI_ERROR (Status); + + + // + // Publish Driver Health HII data. + // + mDriverHealthManagerHiiHandle = HiiAddPackages ( + &gEfiCallerIdGuid, + Handle, + DriverHealthManagerVfrBin, + DriverHealthConfigureVfrBin, + STRING_ARRAY_NAME, + NULL + ); + ASSERT (mDriverHealthManagerHiiHandle != NULL); + + return EFI_SUCCESS; +} + +/** + + Select the best matching language according to front page policy for best user experience. + + This function supports both ISO 639-2 and RFC 4646 language codes, but language + code types may not be mixed in a single call to this function. + + @param SupportedLanguages A pointer to a Null-terminated ASCII string that + contains a set of language codes in the format + specified by Iso639Language. + @param Iso639Language If TRUE, then all language codes are assumed to be + in ISO 639-2 format. If FALSE, then all language + codes are assumed to be in RFC 4646 language format. + + @retval NULL The best matching language could not be found in SupportedLanguages. + @retval NULL There are not enough resources available to return the best matching + language. + @retval Other A pointer to a Null-terminated ASCII string that is the best matching + language in SupportedLanguages. +**/ +CHAR8 * +DriverHealthManagerSelectBestLanguage ( + IN CHAR8 *SupportedLanguages, + IN BOOLEAN Iso639Language + ) +{ + CHAR8 *LanguageVariable; + CHAR8 *BestLanguage; + + GetEfiGlobalVariable2 (Iso639Language ? L"Lang" : L"PlatformLang", (VOID**)&LanguageVariable, NULL); + + BestLanguage = GetBestLanguage( + SupportedLanguages, + Iso639Language, + (LanguageVariable != NULL) ? LanguageVariable : "", + Iso639Language ? "eng" : "en-US", + NULL + ); + if (LanguageVariable != NULL) { + FreePool (LanguageVariable); + } + + return BestLanguage; +} + + + +/** + + This is an internal worker function to get the Component Name (2) protocol interface + and the language it supports. + + @param ProtocolGuid A pointer to an EFI_GUID. It points to Component Name (2) protocol GUID. + @param DriverBindingHandle The handle on which the Component Name (2) protocol instance is retrieved. + @param ComponentName A pointer to the Component Name (2) protocol interface. + @param SupportedLanguage The best suitable language that matches the SupportedLangues interface for the + located Component Name (2) instance. + + @retval EFI_SUCCESS The Component Name (2) protocol instance is successfully located and we find + the best matching language it support. + @retval EFI_UNSUPPORTED The input Language is not supported by the Component Name (2) protocol. + @retval Other Some error occurs when locating Component Name (2) protocol instance or finding + the supported language. + +**/ +EFI_STATUS +DriverHealthManagerGetComponentNameWorker ( + IN EFI_GUID *ProtocolGuid, + IN EFI_HANDLE DriverBindingHandle, + OUT EFI_COMPONENT_NAME_PROTOCOL **ComponentName, + OUT CHAR8 **SupportedLanguage + ) +{ + EFI_STATUS Status; + + // + // Locate Component Name (2) protocol on the driver binging handle. + // + Status = gBS->OpenProtocol ( + DriverBindingHandle, + ProtocolGuid, + (VOID **) ComponentName, + NULL, + NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Apply shell policy to select the best language. + // + *SupportedLanguage = DriverHealthManagerSelectBestLanguage ( + (*ComponentName)->SupportedLanguages, + (BOOLEAN) (ProtocolGuid == &gEfiComponentNameProtocolGuid) + ); + if (*SupportedLanguage == NULL) { + Status = EFI_UNSUPPORTED; + } + + return Status; +} + +/** + + This is an internal worker function to get driver name from Component Name (2) protocol interface. + + @param ProtocolGuid A pointer to an EFI_GUID. It points to Component Name (2) protocol GUID. + @param DriverBindingHandle The handle on which the Component Name (2) protocol instance is retrieved. + @param DriverName A pointer to the Unicode string to return. This Unicode string is the name + of the driver specified by This. + + @retval EFI_SUCCESS The driver name is successfully retrieved from Component Name (2) protocol + interface. + @retval Other The driver name cannot be retrieved from Component Name (2) protocol + interface. + +**/ +EFI_STATUS +DriverHealthManagerGetDriverNameWorker ( + IN EFI_GUID *ProtocolGuid, + IN EFI_HANDLE DriverBindingHandle, + OUT CHAR16 **DriverName + ) +{ + EFI_STATUS Status; + CHAR8 *BestLanguage; + EFI_COMPONENT_NAME_PROTOCOL *ComponentName; + + // + // Retrieve Component Name (2) protocol instance on the driver binding handle and + // find the best language this instance supports. + // + Status = DriverHealthManagerGetComponentNameWorker ( + ProtocolGuid, + DriverBindingHandle, + &ComponentName, + &BestLanguage + ); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Get the driver name from Component Name (2) protocol instance on the driver binging handle. + // + Status = ComponentName->GetDriverName ( + ComponentName, + BestLanguage, + DriverName + ); + FreePool (BestLanguage); + + return Status; +} + +/** + This function gets driver name from Component Name 2 protocol interface and Component Name protocol interface + in turn. It first tries UEFI 2.0 Component Name 2 protocol interface and try to get the driver name. + If the attempt fails, it then gets the driver name from EFI 1.1 Component Name protocol for backward + compatibility support. + + @param DriverBindingHandle The handle on which the Component Name (2) protocol instance is retrieved. + + @return A pointer to the Unicode string to return. This Unicode string is the name of the controller + specified by ControllerHandle and ChildHandle. + + +**/ +CHAR16 * +DriverHealthManagerGetDriverName ( + IN EFI_HANDLE DriverBindingHandle + ) +{ + EFI_STATUS Status; + CHAR16 *DriverName; + + // + // Get driver name from UEFI 2.0 Component Name 2 protocol interface. + // + Status = DriverHealthManagerGetDriverNameWorker (&gEfiComponentName2ProtocolGuid, DriverBindingHandle, &DriverName); + if (EFI_ERROR (Status)) { + // + // If it fails to get the driver name from Component Name protocol interface, we should fall back on + // EFI 1.1 Component Name protocol interface. + // + Status = DriverHealthManagerGetDriverNameWorker (&gEfiComponentNameProtocolGuid, DriverBindingHandle, &DriverName); + } + + if (!EFI_ERROR (Status)) { + return AllocateCopyPool (StrSize (DriverName), DriverName); + } else { + return ConvertDevicePathToText (DevicePathFromHandle (DriverBindingHandle), FALSE, TRUE); + } +} + + + +/** + This function gets controller name from Component Name 2 protocol interface and Component Name protocol interface + in turn. It first tries UEFI 2.0 Component Name 2 protocol interface and try to get the controller name. + If the attempt fails, it then gets the controller name from EFI 1.1 Component Name protocol for backward + compatibility support. + + @param ProtocolGuid A pointer to an EFI_GUID. It points to Component Name (2) protocol GUID. + @param DriverBindingHandle The handle on which the Component Name (2) protocol instance is retrieved. + @param ControllerHandle The handle of a controller that the driver specified by This 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. + @param ControllerName A pointer to the Unicode string to return. This Unicode string + is the name of the controller specified by ControllerHandle and ChildHandle. + + @retval EFI_SUCCESS The controller name is successfully retrieved from Component Name (2) protocol + interface. + @retval Other The controller name cannot be retrieved from Component Name (2) protocol. + +**/ +EFI_STATUS +DriverHealthManagerGetControllerNameWorker ( + IN EFI_GUID *ProtocolGuid, + IN EFI_HANDLE DriverBindingHandle, + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE ChildHandle, + OUT CHAR16 **ControllerName + ) +{ + EFI_STATUS Status; + CHAR8 *BestLanguage; + EFI_COMPONENT_NAME_PROTOCOL *ComponentName; + + // + // Retrieve Component Name (2) protocol instance on the driver binding handle and + // find the best language this instance supports. + // + Status = DriverHealthManagerGetComponentNameWorker ( + ProtocolGuid, + DriverBindingHandle, + &ComponentName, + &BestLanguage + ); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Get the controller name from Component Name (2) protocol instance on the driver binging handle. + // + Status = ComponentName->GetControllerName ( + ComponentName, + ControllerHandle, + ChildHandle, + BestLanguage, + ControllerName + ); + FreePool (BestLanguage); + + return Status; +} + +/** + + This function gets controller name from Component Name 2 protocol interface and Component Name protocol interface + in turn. It first tries UEFI 2.0 Component Name 2 protocol interface and try to get the controller name. + If the attempt fails, it then gets the controller name from EFI 1.1 Component Name protocol for backward + compatibility support. + + @param DriverBindingHandle The handle on which the Component Name (2) 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 * +DriverHealthManagerGetControllerName ( + IN EFI_HANDLE DriverBindingHandle, + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE ChildHandle + ) +{ + EFI_STATUS Status; + CHAR16 *ControllerName; + + // + // Get controller name from UEFI 2.0 Component Name 2 protocol interface. + // + Status = DriverHealthManagerGetControllerNameWorker ( + &gEfiComponentName2ProtocolGuid, + DriverBindingHandle, + ControllerHandle, + ChildHandle, + &ControllerName + ); + if (EFI_ERROR (Status)) { + // + // If it fails to get the controller name from Component Name protocol interface, we should fall back on + // EFI 1.1 Component Name protocol interface. + // + Status = DriverHealthManagerGetControllerNameWorker ( + &gEfiComponentNameProtocolGuid, + DriverBindingHandle, + ControllerHandle, + ChildHandle, + &ControllerName + ); + } + + if (!EFI_ERROR (Status)) { + return AllocateCopyPool (StrSize (ControllerName), ControllerName); + } else { + return ConvertDevicePathToText (DevicePathFromHandle (ChildHandle != NULL ? ChildHandle : ControllerHandle), FALSE, TRUE); + } +} + +/** + 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 +DriverHealthManagerRepairNotify ( + IN UINTN Value, + IN UINTN Limit + ) +{ + DEBUG ((EFI_D_INFO, "[DriverHealthManagement]RepairNotify: %d/%d\n", Value, Limit)); + return EFI_SUCCESS; +} + +/** + Look for the formset GUID which has the gEfiHiiDriverHealthFormsetGuid class GUID in the specified HII package list. + + @param Handle Handle to the HII package list. + @param FormsetGuid Return the formset GUID. + + @retval EFI_SUCCESS The formset is found successfully. + @retval EFI_NOT_FOUND The formset cannot be found. +**/ +EFI_STATUS +DriverHealthManagerGetFormsetId ( + IN EFI_HII_HANDLE Handle, + OUT EFI_GUID *FormsetGuid + ) +{ + EFI_STATUS Status; + EFI_HII_PACKAGE_LIST_HEADER *HiiPackageList; + UINTN BufferSize; + UINT8 *Package; + UINT8 *OpCodeData; + UINT32 Offset; + UINT32 Offset2; + EFI_HII_PACKAGE_HEADER PackageHeader; + UINT8 Index; + UINT8 NumberOfClassGuid; + EFI_GUID *ClassGuid; + + // + // Get HII PackageList + // + BufferSize = 0; + HiiPackageList = NULL; + Status = mDriverHealthManagerDatabase->ExportPackageLists (mDriverHealthManagerDatabase, Handle, &BufferSize, HiiPackageList); + if (Status == EFI_BUFFER_TOO_SMALL) { + HiiPackageList = AllocatePool (BufferSize); + ASSERT (HiiPackageList != NULL); + + Status = mDriverHealthManagerDatabase->ExportPackageLists (mDriverHealthManagerDatabase, Handle, &BufferSize, HiiPackageList); + } + if (EFI_ERROR (Status)) { + return Status; + } + ASSERT (HiiPackageList != NULL); + + // + // Get Form package from this HII package List + // + for (Offset = sizeof (EFI_HII_PACKAGE_LIST_HEADER); Offset < ReadUnaligned32 (&HiiPackageList->PackageLength); Offset += PackageHeader.Length) { + Package = ((UINT8 *) HiiPackageList) + Offset; + CopyMem (&PackageHeader, Package, sizeof (EFI_HII_PACKAGE_HEADER)); + + if (PackageHeader.Type == EFI_HII_PACKAGE_FORMS) { + // + // Search FormSet in this Form Package + // + + for (Offset2 = sizeof (EFI_HII_PACKAGE_HEADER); Offset2 < PackageHeader.Length; Offset2 += ((EFI_IFR_OP_HEADER *) OpCodeData)->Length) { + OpCodeData = Package + Offset2; + + if ((((EFI_IFR_OP_HEADER *) OpCodeData)->OpCode == EFI_IFR_FORM_SET_OP) && + (((EFI_IFR_OP_HEADER *) OpCodeData)->Length > OFFSET_OF (EFI_IFR_FORM_SET, Flags))) { + // + // Try to compare against formset class GUID + // + NumberOfClassGuid = (UINT8) (((EFI_IFR_FORM_SET *) OpCodeData)->Flags & 0x3); + ClassGuid = (EFI_GUID *) (OpCodeData + sizeof (EFI_IFR_FORM_SET)); + for (Index = 0; Index < NumberOfClassGuid; Index++) { + if (CompareGuid (&gEfiHiiDriverHealthFormsetGuid, &ClassGuid[Index])) { + CopyMem (FormsetGuid, &((EFI_IFR_FORM_SET *) OpCodeData)->Guid, sizeof (EFI_GUID)); + FreePool (HiiPackageList); + return EFI_SUCCESS; + } + } + } + } + } + } + + // + // Form package not found in this Package List + // + FreePool (HiiPackageList); + return EFI_NOT_FOUND; +} + +/** + Processes a single controller using the EFI Driver Health Protocol associated with + that controller. + + @param DriverHealth A pointer to the EFI_DRIVER_HEALTH_PROTOCOL instance. + @param ControllerHandle The class guid specifies which form set will be displayed. + @param ChildHandle The handle of the child controller to retrieve the health + status on. This is an optional parameter that may be NULL. + @param HealthStatus The health status of the controller. + @param MessageList An array of warning or error messages associated + with the controller specified by ControllerHandle and + ChildHandle. This is an optional parameter that may be NULL. + @param FormHiiHandle The HII handle for an HII form associated with the + controller specified by ControllerHandle and ChildHandle. +**/ +VOID +DriverHealthManagerProcessSingleControllerHealth ( + IN EFI_DRIVER_HEALTH_PROTOCOL *DriverHealth, + IN EFI_HANDLE ControllerHandle, OPTIONAL + IN EFI_HANDLE ChildHandle, OPTIONAL + IN EFI_DRIVER_HEALTH_STATUS HealthStatus, + IN EFI_DRIVER_HEALTH_HII_MESSAGE **MessageList, OPTIONAL + IN EFI_HII_HANDLE FormHiiHandle + ) +{ + EFI_STATUS Status; + + ASSERT (HealthStatus != EfiDriverHealthStatusConfigurationRequired); + // + // If the module need to be repaired or reconfiguration, will process it until + // reach a terminal status. The status from EfiDriverHealthStatusRepairRequired after repair + // will be in (Health, Failed, Configuration Required). + // + switch (HealthStatus) { + + case EfiDriverHealthStatusRepairRequired: + Status = DriverHealth->Repair ( + DriverHealth, + ControllerHandle, + ChildHandle, + DriverHealthManagerRepairNotify + ); + break; + + case EfiDriverHealthStatusRebootRequired: + gRT->ResetSystem (EfiResetWarm, EFI_SUCCESS, 0, NULL); + break; + + case EfiDriverHealthStatusReconnectRequired: + Status = gBS->DisconnectController (ControllerHandle, NULL, NULL); + if (EFI_ERROR (Status)) { + // + // Disconnect failed. Need to promote reconnect to a reboot. + // + gRT->ResetSystem (EfiResetWarm, EFI_SUCCESS, 0, NULL); + } else { + gBS->ConnectController (ControllerHandle, NULL, NULL, TRUE); + } + break; + + default: + break; + } +} + +/** + Update the form to include the driver health instances. + + @param ConfigureOnly Only include the configure required driver health instances + when TRUE, include all the driver health instances otherwise. +**/ +VOID +DriverHealthManagerUpdateForm ( + BOOLEAN ConfigureOnly + ) +{ + EFI_STATUS Status; + EFI_IFR_GUID_LABEL *StartLabel; + EFI_IFR_GUID_LABEL *EndLabel; + VOID *StartOpCodeHandle; + VOID *EndOpCodeHandle; + UINTN Index; + EFI_STRING_ID Prompt; + EFI_STRING_ID Help; + CHAR16 String[512]; + UINTN StringCount; + EFI_STRING TmpString; + EFI_STRING DriverName; + EFI_STRING ControllerName; + UINTN MessageIndex; + EFI_HANDLE DriverHandle; + EFI_STRING_ID DevicePath; + EFI_GUID FormsetGuid; + + EfiBootManagerFreeDriverHealthInfo (mDriverHealthManagerHealthInfo, mDriverHealthManagerHealthInfoCount); + mDriverHealthManagerHealthInfo = EfiBootManagerGetDriverHealthInfo (&mDriverHealthManagerHealthInfoCount); + + // + // Allocate space for creation of UpdateData Buffer + // + StartOpCodeHandle = HiiAllocateOpCodeHandle (); + ASSERT (StartOpCodeHandle != NULL); + + EndOpCodeHandle = HiiAllocateOpCodeHandle (); + ASSERT (EndOpCodeHandle != NULL); + + // + // Create Hii Extend Label OpCode as the start opcode + // + StartLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (StartOpCodeHandle, &gEfiIfrTianoGuid, NULL, sizeof (EFI_IFR_GUID_LABEL)); + StartLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL; + StartLabel->Number = LABEL_BEGIN; + + // + // Create Hii Extend Label OpCode as the end opcode + // + EndLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (EndOpCodeHandle, &gEfiIfrTianoGuid, NULL, sizeof (EFI_IFR_GUID_LABEL)); + EndLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL; + EndLabel->Number = LABEL_END; + + for (Index = 0; Index < mDriverHealthManagerHealthInfoCount; Index++) { + if (ConfigureOnly && mDriverHealthManagerHealthInfo[Index].HealthStatus != EfiDriverHealthStatusConfigurationRequired) { + continue; + } + DriverName = DriverHealthManagerGetDriverName (mDriverHealthManagerHealthInfo[Index].DriverHealthHandle); + ASSERT (DriverName != NULL); + + if (mDriverHealthManagerHealthInfo[Index].ControllerHandle == NULL) { + // + // The ControllerHandle is set to NULL and the HealthStatus is set to EfiDriverHealthStatusHealthy + // if all the controllers managed by the driver are in healthy state. + // + ASSERT (mDriverHealthManagerHealthInfo[Index].HealthStatus == EfiDriverHealthStatusHealthy); + UnicodeSPrint (String, sizeof (String), L"%s", DriverName); + } else { + ControllerName = DriverHealthManagerGetControllerName ( + mDriverHealthManagerHealthInfo[Index].DriverHealthHandle, + mDriverHealthManagerHealthInfo[Index].ControllerHandle, + mDriverHealthManagerHealthInfo[Index].ChildHandle + ); + ASSERT (ControllerName != NULL); + UnicodeSPrint (String, sizeof (String), L"%s %s", DriverName, ControllerName); + FreePool (ControllerName); + } + FreePool (DriverName); + + Prompt = HiiSetString (mDriverHealthManagerHiiHandle, 0, String, NULL); + + switch(mDriverHealthManagerHealthInfo[Index].HealthStatus) { + case EfiDriverHealthStatusRepairRequired: + TmpString = HiiGetString (mDriverHealthManagerHiiHandle, STRING_TOKEN (STR_REPAIR_REQUIRED), NULL); + break; + case EfiDriverHealthStatusConfigurationRequired: + TmpString = HiiGetString (mDriverHealthManagerHiiHandle, STRING_TOKEN (STR_CONFIGURATION_REQUIRED), NULL); + break; + case EfiDriverHealthStatusFailed: + TmpString = HiiGetString (mDriverHealthManagerHiiHandle, STRING_TOKEN (STR_FAILED), NULL); + break; + case EfiDriverHealthStatusReconnectRequired: + TmpString = HiiGetString (mDriverHealthManagerHiiHandle, STRING_TOKEN (STR_RECONNECT_REQUIRED), NULL); + break; + case EfiDriverHealthStatusRebootRequired: + TmpString = HiiGetString (mDriverHealthManagerHiiHandle, STRING_TOKEN (STR_REBOOT_REQUIRED), NULL); + break; + default: + ASSERT (mDriverHealthManagerHealthInfo[Index].HealthStatus == EfiDriverHealthStatusHealthy); + TmpString = HiiGetString (mDriverHealthManagerHiiHandle, STRING_TOKEN (STR_HEALTHY), NULL); + break; + } + StringCount = UnicodeSPrint (String, sizeof (String), L"%s\n", TmpString); + FreePool (TmpString); + + // + // Add the message of the Module itself provided as the help. + // + if (mDriverHealthManagerHealthInfo[Index].MessageList != NULL) { + for (MessageIndex = 0; mDriverHealthManagerHealthInfo[Index].MessageList[MessageIndex].HiiHandle != NULL; MessageIndex++) { + TmpString = HiiGetString ( + mDriverHealthManagerHealthInfo[Index].MessageList[MessageIndex].HiiHandle, + mDriverHealthManagerHealthInfo[Index].MessageList[MessageIndex].StringId, + NULL + ); + StringCount += UnicodeSPrint (String + StringCount, sizeof (String) - sizeof (String[0]) * StringCount, L"\n%s", TmpString); + FreePool (TmpString); + } + } + Help = HiiSetString (mDriverHealthManagerHiiHandle, 0, String, NULL); + + switch (mDriverHealthManagerHealthInfo[Index].HealthStatus) { + case EfiDriverHealthStatusConfigurationRequired: + Status = mDriverHealthManagerDatabase->GetPackageListHandle ( + mDriverHealthManagerDatabase, + mDriverHealthManagerHealthInfo[Index].HiiHandle, + &DriverHandle + ); + ASSERT_EFI_ERROR (Status); + TmpString = ConvertDevicePathToText (DevicePathFromHandle (DriverHandle), FALSE, TRUE); + DevicePath = HiiSetString (mDriverHealthManagerHiiHandle, 0, TmpString, NULL); + FreePool (TmpString); + + Status = DriverHealthManagerGetFormsetId (mDriverHealthManagerHealthInfo[Index].HiiHandle, &FormsetGuid); + ASSERT_EFI_ERROR (Status); + + HiiCreateGotoExOpCode ( + StartOpCodeHandle, + 0, + Prompt, + Help, + 0, + 0, + 0, + &FormsetGuid, + DevicePath + ); + break; + + case EfiDriverHealthStatusRepairRequired: + case EfiDriverHealthStatusReconnectRequired: + case EfiDriverHealthStatusRebootRequired: + HiiCreateActionOpCode ( + StartOpCodeHandle, + (EFI_QUESTION_ID) (Index + QUESTION_ID_DRIVER_HEALTH_BASE), + Prompt, + Help, + EFI_IFR_FLAG_CALLBACK, + 0 + ); + break; + + default: + ASSERT (mDriverHealthManagerHealthInfo[Index].HealthStatus == EfiDriverHealthStatusHealthy || + mDriverHealthManagerHealthInfo[Index].HealthStatus == EfiDriverHealthStatusFailed); + HiiCreateTextOpCode ( + StartOpCodeHandle, + Prompt, + Help, + 0 + ); + break; + } + } + + Status = HiiUpdateForm ( + mDriverHealthManagerHiiHandle, + ConfigureOnly ? PcdGetPtr (PcdDriverHealthConfigureForm) : &mDriverHealthManagerForm, + DRIVER_HEALTH_FORM_ID, + StartOpCodeHandle, + EndOpCodeHandle + ); + ASSERT_EFI_ERROR (Status); + + HiiFreeOpCodeHandle (StartOpCodeHandle); + HiiFreeOpCodeHandle (EndOpCodeHandle); +} + +/** + Called when the form is closing to remove the dynamicly added string from the HII package list. +**/ +VOID +DriverHealthManagerCleanDynamicString ( + VOID + ) +{ + EFI_STATUS Status; + EFI_HII_PACKAGE_LIST_HEADER *HiiPackageList; + UINTN BufferSize; + EFI_HII_PACKAGE_HEADER *PackageHeader; + UINT32 FixedStringSize; + + FixedStringSize = *(UINT32 *) &STRING_ARRAY_NAME - sizeof (UINT32); + BufferSize = sizeof (EFI_HII_PACKAGE_LIST_HEADER) + FixedStringSize + sizeof (EFI_HII_PACKAGE_HEADER); + HiiPackageList = AllocatePool (BufferSize); + ASSERT (HiiPackageList != NULL); + + HiiPackageList->PackageLength = (UINT32) BufferSize; + CopyMem (&HiiPackageList->PackageListGuid, &gEfiCallerIdGuid, sizeof (EFI_GUID)); + + PackageHeader = (EFI_HII_PACKAGE_HEADER *) (HiiPackageList + 1); + CopyMem (PackageHeader, STRING_ARRAY_NAME + sizeof (UINT32), FixedStringSize); + + PackageHeader = (EFI_HII_PACKAGE_HEADER *) ((UINT8 *) PackageHeader + PackageHeader->Length); + PackageHeader->Type = EFI_HII_PACKAGE_END; + PackageHeader->Length = sizeof (EFI_HII_PACKAGE_HEADER); + + Status = mDriverHealthManagerDatabase->UpdatePackageList ( + mDriverHealthManagerDatabase, + mDriverHealthManagerHiiHandle, + HiiPackageList + ); + ASSERT_EFI_ERROR (Status); + + // + // Form package not found in this Package List + // + FreePool (HiiPackageList); +} + +/** + This function is invoked if user selected a interactive opcode from Driver Health's + Formset. + + @param This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL. + @param Action Specifies the type of action taken by the browser. + @param QuestionId A unique value which is sent to the original exporting driver + so that it can identify the type of data to expect. + @param Type The type of value for the question. + @param Value A pointer to the data being sent to the original exporting driver. + @param ActionRequest On return, points to the action requested by the callback function. + + @retval EFI_SUCCESS The callback successfully handled the action. + @retval EFI_INVALID_PARAMETER The setup browser call this function with invalid parameters. + +**/ +EFI_STATUS +EFIAPI +DriverHealthManagerCallback ( + IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This, + IN EFI_BROWSER_ACTION Action, + IN EFI_QUESTION_ID QuestionId, + IN UINT8 Type, + IN EFI_IFR_TYPE_VALUE *Value, + OUT EFI_BROWSER_ACTION_REQUEST *ActionRequest + ) +{ + UINTN Index; + + if (QuestionId == QUESTION_ID_REFRESH_MANAGER || QuestionId == QUESTION_ID_REFRESH_CONFIGURE) { + if (Action == EFI_BROWSER_ACTION_FORM_OPEN) { + DriverHealthManagerUpdateForm ((BOOLEAN) (QuestionId == QUESTION_ID_REFRESH_CONFIGURE)); + } else if (Action == EFI_BROWSER_ACTION_FORM_CLOSE) { + DriverHealthManagerCleanDynamicString (); + } + return EFI_SUCCESS; + } + + if (Action != EFI_BROWSER_ACTION_CHANGED) { + // + // Do nothing for other UEFI Action. Only do call back when data is changed. + // + return EFI_UNSUPPORTED; + } + + if ((Value == NULL) || (ActionRequest == NULL)) { + return EFI_INVALID_PARAMETER; + } + + DEBUG ((EFI_D_ERROR, "QuestionId = %x\n", QuestionId)); + + // + // We will have returned from processing a callback - user either hit ESC to exit, or selected + // a target to display. + // Process the diver health status states here. + // + Index = QuestionId - QUESTION_ID_DRIVER_HEALTH_BASE; + ASSERT (Index < mDriverHealthManagerHealthInfoCount); + // + // Process the driver's healthy status for the specify module + // + DriverHealthManagerProcessSingleControllerHealth ( + mDriverHealthManagerHealthInfo[Index].DriverHealth, + mDriverHealthManagerHealthInfo[Index].ControllerHandle, + mDriverHealthManagerHealthInfo[Index].ChildHandle, + mDriverHealthManagerHealthInfo[Index].HealthStatus, + &(mDriverHealthManagerHealthInfo[Index].MessageList), + mDriverHealthManagerHealthInfo[Index].HiiHandle + ); + + DriverHealthManagerUpdateForm ((BOOLEAN) (QuestionId == QUESTION_ID_REFRESH_CONFIGURE)); + + return EFI_SUCCESS; +} + + -- cgit