/** @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.<BR> | |
(C) Copyright 2018 Hewlett Packard Enterprise Development LP<BR> | |
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 <ConfigRequest> 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 <ConfigAltResp> 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 <ConfigResp> 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 ((DEBUG_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 ((DEBUG_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; | |
} |