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