Home | History | Annotate | Download | only in DriverHealthManagerDxe
      1 /** @file
      2   This module produces two driver health manager forms.
      3   One will be used by BDS core to configure the Configured Required
      4   driver health instances, the other will be automatically included by
      5   firmware setup (UI).
      6 
      7 Copyright (c) 2013 - 2015, Intel Corporation. All rights reserved.<BR>
      8 This program and the accompanying materials
      9 are licensed and made available under the terms and conditions of the BSD License
     10 which accompanies this distribution.  The full text of the license may be found at
     11 http://opensource.org/licenses/bsd-license.php
     12 
     13 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     14 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     15 
     16 **/
     17 
     18 #include "DriverHealthManagerDxe.h"
     19 #include "DriverHealthManagerVfr.h"
     20 
     21 EFI_HII_CONFIG_ACCESS_PROTOCOL mDriverHealthManagerConfigAccess     = {
     22   DriverHealthManagerFakeExtractConfig,
     23   DriverHealthManagerFakeRouteConfig,
     24   DriverHealthManagerCallback
     25 };
     26 
     27 EFI_GUID mDriverHealthManagerForm = DRIVER_HEALTH_MANAGER_FORMSET_GUID;
     28 
     29 FORM_DEVICE_PATH  mDriverHealthManagerFormDevicePath = {
     30   {
     31     {
     32       HARDWARE_DEVICE_PATH,
     33       HW_VENDOR_DP,
     34       {
     35         (UINT8) (sizeof (VENDOR_DEVICE_PATH)),
     36         (UINT8) ((sizeof (VENDOR_DEVICE_PATH)) >> 8)
     37       }
     38     },
     39     EFI_CALLER_ID_GUID
     40   },
     41   {
     42     END_DEVICE_PATH_TYPE,
     43     END_ENTIRE_DEVICE_PATH_SUBTYPE,
     44     {
     45       (UINT8) (END_DEVICE_PATH_LENGTH),
     46       (UINT8) ((END_DEVICE_PATH_LENGTH) >> 8)
     47     }
     48   }
     49 };
     50 
     51 EFI_HII_HANDLE                       mDriverHealthManagerHiiHandle;
     52 EFI_BOOT_MANAGER_DRIVER_HEALTH_INFO  *mDriverHealthManagerHealthInfo     = NULL;
     53 UINTN                                mDriverHealthManagerHealthInfoCount = 0;
     54 EFI_HII_DATABASE_PROTOCOL            *mDriverHealthManagerDatabase;
     55 
     56 
     57 extern UINT8 DriverHealthManagerVfrBin[];
     58 extern UINT8 DriverHealthConfigureVfrBin[];
     59 
     60 /**
     61   This function allows a caller to extract the current configuration for one
     62   or more named elements from the target driver.
     63 
     64 
     65   @param This            Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
     66   @param Request         A null-terminated Unicode string in <ConfigRequest> format.
     67   @param Progress        On return, points to a character in the Request string.
     68                          Points to the string's null terminator if request was successful.
     69                          Points to the most recent '&' before the first failing name/value
     70                          pair (or the beginning of the string if the failure is in the
     71                          first name/value pair) if the request was not successful.
     72   @param Results         A null-terminated Unicode string in <ConfigAltResp> format which
     73                          has all values filled in for the names in the Request string.
     74                          String to be allocated by the called function.
     75 
     76   @retval  EFI_SUCCESS            The Results is filled with the requested values.
     77   @retval  EFI_OUT_OF_RESOURCES   Not enough memory to store the results.
     78   @retval  EFI_INVALID_PARAMETER  Request is illegal syntax, or unknown name.
     79   @retval  EFI_NOT_FOUND          Routing data doesn't match any storage in this driver.
     80 
     81 **/
     82 EFI_STATUS
     83 EFIAPI
     84 DriverHealthManagerFakeExtractConfig (
     85   IN  CONST EFI_HII_CONFIG_ACCESS_PROTOCOL   *This,
     86   IN  CONST EFI_STRING                       Request,
     87   OUT EFI_STRING                             *Progress,
     88   OUT EFI_STRING                             *Results
     89   )
     90 {
     91   if (Progress == NULL || Results == NULL) {
     92     return EFI_INVALID_PARAMETER;
     93   }
     94   *Progress = Request;
     95   return EFI_NOT_FOUND;
     96 }
     97 
     98 /**
     99   This function processes the results of changes in configuration.
    100 
    101 
    102   @param This            Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
    103   @param Configuration   A null-terminated Unicode string in <ConfigResp> format.
    104   @param Progress        A pointer to a string filled in with the offset of the most
    105                          recent '&' before the first failing name/value pair (or the
    106                          beginning of the string if the failure is in the first
    107                          name/value pair) or the terminating NULL if all was successful.
    108 
    109   @retval  EFI_SUCCESS            The Results is processed successfully.
    110   @retval  EFI_INVALID_PARAMETER  Configuration is NULL.
    111   @retval  EFI_NOT_FOUND          Routing data doesn't match any storage in this driver.
    112 
    113 **/
    114 EFI_STATUS
    115 EFIAPI
    116 DriverHealthManagerFakeRouteConfig (
    117   IN  CONST EFI_HII_CONFIG_ACCESS_PROTOCOL   *This,
    118   IN  CONST EFI_STRING                       Configuration,
    119   OUT EFI_STRING                             *Progress
    120   )
    121 {
    122   if (Configuration == NULL || Progress == NULL) {
    123     return EFI_INVALID_PARAMETER;
    124   }
    125 
    126   return EFI_NOT_FOUND;
    127 }
    128 
    129 /**
    130 
    131   Install the health manager forms.
    132   One will be used by BDS core to configure the Configured Required
    133   driver health instances, the other will be automatically included by
    134   firmware setup (UI).
    135 
    136   @param ImageHandle     The image handle.
    137   @param SystemTable     The system table.
    138 
    139   @retval  EFI_SUCEESS   The health manager forms are successfully installed.
    140 
    141 **/
    142 EFI_STATUS
    143 EFIAPI
    144 InitializeDriverHealthManager (
    145   EFI_HANDLE                 ImageHandle,
    146   EFI_SYSTEM_TABLE           *SystemTable
    147   )
    148 {
    149   EFI_STATUS                  Status;
    150   EFI_HANDLE                  Handle;
    151 
    152   Status = gBS->LocateProtocol (
    153                   &gEfiHiiDatabaseProtocolGuid,
    154                   NULL,
    155                   (VOID **) &mDriverHealthManagerDatabase
    156                   );
    157   ASSERT_EFI_ERROR (Status);
    158 
    159   Handle = NULL;
    160   Status = gBS->InstallMultipleProtocolInterfaces (
    161                   &Handle,
    162                   &gEfiDevicePathProtocolGuid,
    163                   &mDriverHealthManagerFormDevicePath,
    164                   &gEfiHiiConfigAccessProtocolGuid,
    165                   &mDriverHealthManagerConfigAccess,
    166                   NULL
    167                   );
    168   ASSERT_EFI_ERROR (Status);
    169 
    170 
    171   //
    172   // Publish Driver Health HII data.
    173   //
    174   mDriverHealthManagerHiiHandle = HiiAddPackages (
    175                                     &gEfiCallerIdGuid,
    176                                     Handle,
    177                                     DriverHealthManagerVfrBin,
    178                                     DriverHealthConfigureVfrBin,
    179                                     STRING_ARRAY_NAME,
    180                                     NULL
    181                                     );
    182   ASSERT (mDriverHealthManagerHiiHandle != NULL);
    183 
    184   return EFI_SUCCESS;
    185 }
    186 
    187 /**
    188 
    189   Select the best matching language according to front page policy for best user experience.
    190 
    191   This function supports both ISO 639-2 and RFC 4646 language codes, but language
    192   code types may not be mixed in a single call to this function.
    193 
    194   @param  SupportedLanguages   A pointer to a Null-terminated ASCII string that
    195                                contains a set of language codes in the format
    196                                specified by Iso639Language.
    197   @param  Iso639Language       If TRUE, then all language codes are assumed to be
    198                                in ISO 639-2 format.  If FALSE, then all language
    199                                codes are assumed to be in RFC 4646 language format.
    200 
    201   @retval NULL                 The best matching language could not be found in SupportedLanguages.
    202   @retval NULL                 There are not enough resources available to return the best matching
    203                                language.
    204   @retval Other                A pointer to a Null-terminated ASCII string that is the best matching
    205                                language in SupportedLanguages.
    206 **/
    207 CHAR8 *
    208 DriverHealthManagerSelectBestLanguage (
    209   IN CHAR8        *SupportedLanguages,
    210   IN BOOLEAN      Iso639Language
    211   )
    212 {
    213   CHAR8           *LanguageVariable;
    214   CHAR8           *BestLanguage;
    215 
    216   GetEfiGlobalVariable2 (Iso639Language ? L"Lang" : L"PlatformLang", (VOID**)&LanguageVariable, NULL);
    217 
    218   BestLanguage = GetBestLanguage(
    219                    SupportedLanguages,
    220                    Iso639Language,
    221                    (LanguageVariable != NULL) ? LanguageVariable : "",
    222                    Iso639Language ? "eng" : "en-US",
    223                    NULL
    224                    );
    225   if (LanguageVariable != NULL) {
    226     FreePool (LanguageVariable);
    227   }
    228 
    229   return BestLanguage;
    230 }
    231 
    232 
    233 
    234 /**
    235 
    236   This is an internal worker function to get the Component Name (2) protocol interface
    237   and the language it supports.
    238 
    239   @param  ProtocolGuid         A pointer to an EFI_GUID. It points to Component Name (2) protocol GUID.
    240   @param  DriverBindingHandle  The handle on which the Component Name (2) protocol instance is retrieved.
    241   @param  ComponentName        A pointer to the Component Name (2) protocol interface.
    242   @param  SupportedLanguage    The best suitable language that matches the SupportedLangues interface for the
    243                                located Component Name (2) instance.
    244 
    245   @retval EFI_SUCCESS          The Component Name (2) protocol instance is successfully located and we find
    246                                the best matching language it support.
    247   @retval EFI_UNSUPPORTED      The input Language is not supported by the Component Name (2) protocol.
    248   @retval Other                Some error occurs when locating Component Name (2) protocol instance or finding
    249                                the supported language.
    250 
    251 **/
    252 EFI_STATUS
    253 DriverHealthManagerGetComponentNameWorker (
    254   IN  EFI_GUID                    *ProtocolGuid,
    255   IN  EFI_HANDLE                  DriverBindingHandle,
    256   OUT EFI_COMPONENT_NAME_PROTOCOL **ComponentName,
    257   OUT CHAR8                       **SupportedLanguage
    258   )
    259 {
    260   EFI_STATUS                      Status;
    261 
    262   //
    263   // Locate Component Name (2) protocol on the driver binging handle.
    264   //
    265   Status = gBS->OpenProtocol (
    266                  DriverBindingHandle,
    267                  ProtocolGuid,
    268                  (VOID **) ComponentName,
    269                  NULL,
    270                  NULL,
    271                  EFI_OPEN_PROTOCOL_GET_PROTOCOL
    272                  );
    273   if (EFI_ERROR (Status)) {
    274     return Status;
    275   }
    276 
    277   //
    278   // Apply shell policy to select the best language.
    279   //
    280   *SupportedLanguage = DriverHealthManagerSelectBestLanguage (
    281                          (*ComponentName)->SupportedLanguages,
    282                          (BOOLEAN) (ProtocolGuid == &gEfiComponentNameProtocolGuid)
    283                          );
    284   if (*SupportedLanguage == NULL) {
    285     Status = EFI_UNSUPPORTED;
    286   }
    287 
    288   return Status;
    289 }
    290 
    291 /**
    292 
    293   This is an internal worker function to get driver name from Component Name (2) protocol interface.
    294 
    295   @param  ProtocolGuid         A pointer to an EFI_GUID. It points to Component Name (2) protocol GUID.
    296   @param  DriverBindingHandle  The handle on which the Component Name (2) protocol instance is retrieved.
    297   @param  DriverName           A pointer to the Unicode string to return. This Unicode string is the name
    298                                of the driver specified by This.
    299 
    300   @retval EFI_SUCCESS          The driver name is successfully retrieved from Component Name (2) protocol
    301                                interface.
    302   @retval Other                The driver name cannot be retrieved from Component Name (2) protocol
    303                                interface.
    304 
    305 **/
    306 EFI_STATUS
    307 DriverHealthManagerGetDriverNameWorker (
    308   IN  EFI_GUID    *ProtocolGuid,
    309   IN  EFI_HANDLE  DriverBindingHandle,
    310   OUT CHAR16      **DriverName
    311   )
    312 {
    313   EFI_STATUS                     Status;
    314   CHAR8                          *BestLanguage;
    315   EFI_COMPONENT_NAME_PROTOCOL    *ComponentName;
    316 
    317   //
    318   // Retrieve Component Name (2) protocol instance on the driver binding handle and
    319   // find the best language this instance supports.
    320   //
    321   Status = DriverHealthManagerGetComponentNameWorker (
    322              ProtocolGuid,
    323              DriverBindingHandle,
    324              &ComponentName,
    325              &BestLanguage
    326              );
    327   if (EFI_ERROR (Status)) {
    328     return Status;
    329   }
    330 
    331   //
    332   // Get the driver name from Component Name (2) protocol instance on the driver binging handle.
    333   //
    334   Status = ComponentName->GetDriverName (
    335                             ComponentName,
    336                             BestLanguage,
    337                             DriverName
    338                             );
    339   FreePool (BestLanguage);
    340 
    341   return Status;
    342 }
    343 
    344 /**
    345   This function gets driver name from Component Name 2 protocol interface and Component Name protocol interface
    346   in turn. It first tries UEFI 2.0 Component Name 2 protocol interface and try to get the driver name.
    347   If the attempt fails, it then gets the driver name from EFI 1.1 Component Name protocol for backward
    348   compatibility support.
    349 
    350   @param  DriverBindingHandle  The handle on which the Component Name (2) protocol instance is retrieved.
    351 
    352   @return A pointer to the Unicode string to return. This Unicode string is the name of the controller
    353           specified by ControllerHandle and ChildHandle.
    354 
    355 
    356 **/
    357 CHAR16 *
    358 DriverHealthManagerGetDriverName (
    359   IN  EFI_HANDLE  DriverBindingHandle
    360   )
    361 {
    362   EFI_STATUS      Status;
    363   CHAR16          *DriverName;
    364 
    365   //
    366   // Get driver name from UEFI 2.0 Component Name 2 protocol interface.
    367   //
    368   Status = DriverHealthManagerGetDriverNameWorker (&gEfiComponentName2ProtocolGuid, DriverBindingHandle, &DriverName);
    369   if (EFI_ERROR (Status)) {
    370     //
    371     // If it fails to get the driver name from Component Name protocol interface, we should fall back on
    372     // EFI 1.1 Component Name protocol interface.
    373     //
    374     Status = DriverHealthManagerGetDriverNameWorker (&gEfiComponentNameProtocolGuid, DriverBindingHandle, &DriverName);
    375   }
    376 
    377   if (!EFI_ERROR (Status)) {
    378     return AllocateCopyPool (StrSize (DriverName), DriverName);
    379   } else {
    380     return ConvertDevicePathToText (DevicePathFromHandle (DriverBindingHandle), FALSE, TRUE);
    381   }
    382 }
    383 
    384 
    385 
    386 /**
    387   This function gets controller name from Component Name 2 protocol interface and Component Name protocol interface
    388   in turn. It first tries UEFI 2.0 Component Name 2 protocol interface and try to get the controller name.
    389   If the attempt fails, it then gets the controller name from EFI 1.1 Component Name protocol for backward
    390   compatibility support.
    391 
    392   @param  ProtocolGuid         A pointer to an EFI_GUID. It points to Component Name (2) protocol GUID.
    393   @param  DriverBindingHandle  The handle on which the Component Name (2) protocol instance is retrieved.
    394   @param  ControllerHandle     The handle of a controller that the driver specified by This is managing.
    395                                This handle specifies the controller whose name is to be returned.
    396   @param  ChildHandle          The handle of the child controller to retrieve the name of. This is an
    397                                optional parameter that may be NULL. It will be NULL for device drivers.
    398                                It will also be NULL for bus drivers that attempt to retrieve the name
    399                                of the bus controller. It will not be NULL for a bus driver that attempts
    400                                to retrieve the name of a child controller.
    401   @param  ControllerName       A pointer to the Unicode string to return. This Unicode string
    402                                is the name of the controller specified by ControllerHandle and ChildHandle.
    403 
    404   @retval  EFI_SUCCESS         The controller name is successfully retrieved from Component Name (2) protocol
    405                                interface.
    406   @retval  Other               The controller name cannot be retrieved from Component Name (2) protocol.
    407 
    408 **/
    409 EFI_STATUS
    410 DriverHealthManagerGetControllerNameWorker (
    411   IN  EFI_GUID    *ProtocolGuid,
    412   IN  EFI_HANDLE  DriverBindingHandle,
    413   IN  EFI_HANDLE  ControllerHandle,
    414   IN  EFI_HANDLE  ChildHandle,
    415   OUT CHAR16      **ControllerName
    416   )
    417 {
    418   EFI_STATUS                     Status;
    419   CHAR8                          *BestLanguage;
    420   EFI_COMPONENT_NAME_PROTOCOL    *ComponentName;
    421 
    422   //
    423   // Retrieve Component Name (2) protocol instance on the driver binding handle and
    424   // find the best language this instance supports.
    425   //
    426   Status = DriverHealthManagerGetComponentNameWorker (
    427              ProtocolGuid,
    428              DriverBindingHandle,
    429              &ComponentName,
    430              &BestLanguage
    431              );
    432   if (EFI_ERROR (Status)) {
    433     return Status;
    434   }
    435 
    436   //
    437   // Get the controller name from Component Name (2) protocol instance on the driver binging handle.
    438   //
    439   Status = ComponentName->GetControllerName (
    440                             ComponentName,
    441                             ControllerHandle,
    442                             ChildHandle,
    443                             BestLanguage,
    444                             ControllerName
    445                             );
    446   FreePool (BestLanguage);
    447 
    448   return Status;
    449 }
    450 
    451 /**
    452 
    453   This function gets controller name from Component Name 2 protocol interface and Component Name protocol interface
    454   in turn. It first tries UEFI 2.0 Component Name 2 protocol interface and try to get the controller name.
    455   If the attempt fails, it then gets the controller name from EFI 1.1 Component Name protocol for backward
    456   compatibility support.
    457 
    458   @param  DriverBindingHandle  The handle on which the Component Name (2) protocol instance is retrieved.
    459   @param  ControllerHandle     The handle of a controller that the driver specified by DriverBindingHandle is managing.
    460                                This handle specifies the controller whose name is to be returned.
    461   @param  ChildHandle          The handle of the child controller to retrieve the name of. This is an
    462                                optional parameter that may be NULL. It will be NULL for device drivers.
    463                                It will also be NULL for bus drivers that attempt to retrieve the name
    464                                of the bus controller. It will not be NULL for a bus driver that attempts
    465                                to retrieve the name of a child controller.
    466 
    467   @return A pointer to the Unicode string to return. This Unicode string is the name of the controller
    468           specified by ControllerHandle and ChildHandle.
    469 **/
    470 CHAR16 *
    471 DriverHealthManagerGetControllerName (
    472   IN  EFI_HANDLE  DriverBindingHandle,
    473   IN  EFI_HANDLE  ControllerHandle,
    474   IN  EFI_HANDLE  ChildHandle
    475   )
    476 {
    477   EFI_STATUS      Status;
    478   CHAR16          *ControllerName;
    479 
    480   //
    481   // Get controller name from UEFI 2.0 Component Name 2 protocol interface.
    482   //
    483   Status = DriverHealthManagerGetControllerNameWorker (
    484              &gEfiComponentName2ProtocolGuid,
    485              DriverBindingHandle,
    486              ControllerHandle,
    487              ChildHandle,
    488              &ControllerName
    489              );
    490   if (EFI_ERROR (Status)) {
    491     //
    492     // If it fails to get the controller name from Component Name protocol interface, we should fall back on
    493     // EFI 1.1 Component Name protocol interface.
    494     //
    495     Status = DriverHealthManagerGetControllerNameWorker (
    496                &gEfiComponentNameProtocolGuid,
    497                DriverBindingHandle,
    498                ControllerHandle,
    499                ChildHandle,
    500                &ControllerName
    501                );
    502   }
    503 
    504   if (!EFI_ERROR (Status)) {
    505     return AllocateCopyPool (StrSize (ControllerName), ControllerName);
    506   } else {
    507     return ConvertDevicePathToText (DevicePathFromHandle (ChildHandle != NULL ? ChildHandle : ControllerHandle), FALSE, TRUE);
    508   }
    509 }
    510 
    511 /**
    512   The repair notify function.
    513   @param Value  A value between 0 and Limit that identifies the current progress
    514                 of the repair operation.
    515   @param Limit  The maximum value of Value for the current repair operation.
    516                 If Limit is 0, then the completion progress is indeterminate.
    517                 For example, a driver that wants to specify progress in percent
    518                 would use a Limit value of 100.
    519 
    520   @retval EFI_SUCCESS  Successfully return from the notify function.
    521 **/
    522 EFI_STATUS
    523 EFIAPI
    524 DriverHealthManagerRepairNotify (
    525   IN UINTN        Value,
    526   IN UINTN        Limit
    527   )
    528 {
    529   DEBUG ((EFI_D_INFO, "[DriverHealthManagement]RepairNotify: %d/%d\n", Value, Limit));
    530   return EFI_SUCCESS;
    531 }
    532 
    533 /**
    534   Look for the formset GUID which has the gEfiHiiDriverHealthFormsetGuid class GUID in the specified HII package list.
    535 
    536   @param Handle         Handle to the HII package list.
    537   @param FormsetGuid    Return the formset GUID.
    538 
    539   @retval EFI_SUCCESS   The formset is found successfully.
    540   @retval EFI_NOT_FOUND The formset cannot be found.
    541 **/
    542 EFI_STATUS
    543 DriverHealthManagerGetFormsetId (
    544   IN  EFI_HII_HANDLE   Handle,
    545   OUT EFI_GUID         *FormsetGuid
    546   )
    547 {
    548   EFI_STATUS                   Status;
    549   EFI_HII_PACKAGE_LIST_HEADER  *HiiPackageList;
    550   UINTN                        BufferSize;
    551   UINT8                        *Package;
    552   UINT8                        *OpCodeData;
    553   UINT32                       Offset;
    554   UINT32                       Offset2;
    555   EFI_HII_PACKAGE_HEADER       PackageHeader;
    556   UINT8                        Index;
    557   UINT8                        NumberOfClassGuid;
    558   EFI_GUID                     *ClassGuid;
    559 
    560   //
    561   // Get HII PackageList
    562   //
    563   BufferSize     = 0;
    564   HiiPackageList = NULL;
    565   Status = mDriverHealthManagerDatabase->ExportPackageLists (mDriverHealthManagerDatabase, Handle, &BufferSize, HiiPackageList);
    566   if (Status == EFI_BUFFER_TOO_SMALL) {
    567     HiiPackageList = AllocatePool (BufferSize);
    568     ASSERT (HiiPackageList != NULL);
    569 
    570     Status = mDriverHealthManagerDatabase->ExportPackageLists (mDriverHealthManagerDatabase, Handle, &BufferSize, HiiPackageList);
    571   }
    572   if (EFI_ERROR (Status)) {
    573     return Status;
    574   }
    575   ASSERT (HiiPackageList != NULL);
    576 
    577   //
    578   // Get Form package from this HII package List
    579   //
    580   for (Offset = sizeof (EFI_HII_PACKAGE_LIST_HEADER); Offset < ReadUnaligned32 (&HiiPackageList->PackageLength); Offset += PackageHeader.Length) {
    581     Package = ((UINT8 *) HiiPackageList) + Offset;
    582     CopyMem (&PackageHeader, Package, sizeof (EFI_HII_PACKAGE_HEADER));
    583 
    584     if (PackageHeader.Type == EFI_HII_PACKAGE_FORMS) {
    585       //
    586       // Search FormSet in this Form Package
    587       //
    588 
    589       for (Offset2 = sizeof (EFI_HII_PACKAGE_HEADER); Offset2 < PackageHeader.Length; Offset2 += ((EFI_IFR_OP_HEADER *) OpCodeData)->Length) {
    590         OpCodeData = Package + Offset2;
    591 
    592         if ((((EFI_IFR_OP_HEADER *) OpCodeData)->OpCode == EFI_IFR_FORM_SET_OP) &&
    593             (((EFI_IFR_OP_HEADER *) OpCodeData)->Length > OFFSET_OF (EFI_IFR_FORM_SET, Flags))) {
    594           //
    595           // Try to compare against formset class GUID
    596           //
    597           NumberOfClassGuid = (UINT8) (((EFI_IFR_FORM_SET *) OpCodeData)->Flags & 0x3);
    598           ClassGuid         = (EFI_GUID *) (OpCodeData + sizeof (EFI_IFR_FORM_SET));
    599           for (Index = 0; Index < NumberOfClassGuid; Index++) {
    600             if (CompareGuid (&gEfiHiiDriverHealthFormsetGuid, &ClassGuid[Index])) {
    601               CopyMem (FormsetGuid, &((EFI_IFR_FORM_SET *) OpCodeData)->Guid, sizeof (EFI_GUID));
    602               FreePool (HiiPackageList);
    603               return EFI_SUCCESS;
    604             }
    605           }
    606         }
    607       }
    608     }
    609   }
    610 
    611   //
    612   // Form package not found in this Package List
    613   //
    614   FreePool (HiiPackageList);
    615   return EFI_NOT_FOUND;
    616 }
    617 
    618 /**
    619   Processes a single controller using the EFI Driver Health Protocol associated with
    620   that controller.
    621 
    622   @param DriverHealth       A pointer to the EFI_DRIVER_HEALTH_PROTOCOL instance.
    623   @param ControllerHandle   The class guid specifies which form set will be displayed.
    624   @param ChildHandle        The handle of the child controller to retrieve the health
    625                             status on.  This is an optional parameter that may be NULL.
    626   @param HealthStatus       The health status of the controller.
    627   @param MessageList        An array of warning or error messages associated
    628                             with the controller specified by ControllerHandle and
    629                             ChildHandle.  This is an optional parameter that may be NULL.
    630   @param FormHiiHandle      The HII handle for an HII form associated with the
    631                             controller specified by ControllerHandle and ChildHandle.
    632 **/
    633 VOID
    634 DriverHealthManagerProcessSingleControllerHealth (
    635   IN  EFI_DRIVER_HEALTH_PROTOCOL         *DriverHealth,
    636   IN  EFI_HANDLE                         ControllerHandle, OPTIONAL
    637   IN  EFI_HANDLE                         ChildHandle,      OPTIONAL
    638   IN  EFI_DRIVER_HEALTH_STATUS           HealthStatus,
    639   IN  EFI_DRIVER_HEALTH_HII_MESSAGE      **MessageList,    OPTIONAL
    640   IN  EFI_HII_HANDLE                     FormHiiHandle
    641   )
    642 {
    643   EFI_STATUS                         Status;
    644 
    645   ASSERT (HealthStatus != EfiDriverHealthStatusConfigurationRequired);
    646   //
    647   // If the module need to be repaired or reconfiguration,  will process it until
    648   // reach a terminal status. The status from EfiDriverHealthStatusRepairRequired after repair
    649   // will be in (Health, Failed, Configuration Required).
    650   //
    651   switch (HealthStatus) {
    652 
    653   case EfiDriverHealthStatusRepairRequired:
    654     Status = DriverHealth->Repair (
    655                              DriverHealth,
    656                              ControllerHandle,
    657                              ChildHandle,
    658                              DriverHealthManagerRepairNotify
    659                              );
    660     break;
    661 
    662   case EfiDriverHealthStatusRebootRequired:
    663     gRT->ResetSystem (EfiResetWarm, EFI_SUCCESS, 0, NULL);
    664     break;
    665 
    666   case EfiDriverHealthStatusReconnectRequired:
    667     Status = gBS->DisconnectController (ControllerHandle, NULL, NULL);
    668     if (EFI_ERROR (Status)) {
    669       //
    670       // Disconnect failed.  Need to promote reconnect to a reboot.
    671       //
    672       gRT->ResetSystem (EfiResetWarm, EFI_SUCCESS, 0, NULL);
    673     } else {
    674       gBS->ConnectController (ControllerHandle, NULL, NULL, TRUE);
    675     }
    676     break;
    677 
    678   default:
    679     break;
    680   }
    681 }
    682 
    683 /**
    684   Update the form to include the driver health instances.
    685 
    686   @param ConfigureOnly  Only include the configure required driver health instances
    687                         when TRUE, include all the driver health instances otherwise.
    688 **/
    689 VOID
    690 DriverHealthManagerUpdateForm (
    691   BOOLEAN                     ConfigureOnly
    692   )
    693 {
    694   EFI_STATUS                  Status;
    695   EFI_IFR_GUID_LABEL          *StartLabel;
    696   EFI_IFR_GUID_LABEL          *EndLabel;
    697   VOID                        *StartOpCodeHandle;
    698   VOID                        *EndOpCodeHandle;
    699   UINTN                       Index;
    700   EFI_STRING_ID               Prompt;
    701   EFI_STRING_ID               Help;
    702   CHAR16                      String[512];
    703   UINTN                       StringCount;
    704   EFI_STRING                  TmpString;
    705   EFI_STRING                  DriverName;
    706   EFI_STRING                  ControllerName;
    707   UINTN                       MessageIndex;
    708   EFI_HANDLE                  DriverHandle;
    709   EFI_STRING_ID               DevicePath;
    710   EFI_GUID                    FormsetGuid;
    711 
    712   EfiBootManagerFreeDriverHealthInfo (mDriverHealthManagerHealthInfo, mDriverHealthManagerHealthInfoCount);
    713   mDriverHealthManagerHealthInfo = EfiBootManagerGetDriverHealthInfo (&mDriverHealthManagerHealthInfoCount);
    714 
    715   //
    716   // Allocate space for creation of UpdateData Buffer
    717   //
    718   StartOpCodeHandle = HiiAllocateOpCodeHandle ();
    719   ASSERT (StartOpCodeHandle != NULL);
    720 
    721   EndOpCodeHandle = HiiAllocateOpCodeHandle ();
    722   ASSERT (EndOpCodeHandle != NULL);
    723 
    724   //
    725   // Create Hii Extend Label OpCode as the start opcode
    726   //
    727   StartLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (StartOpCodeHandle, &gEfiIfrTianoGuid, NULL, sizeof (EFI_IFR_GUID_LABEL));
    728   StartLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
    729   StartLabel->Number       = LABEL_BEGIN;
    730 
    731   //
    732   // Create Hii Extend Label OpCode as the end opcode
    733   //
    734   EndLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (EndOpCodeHandle, &gEfiIfrTianoGuid, NULL, sizeof (EFI_IFR_GUID_LABEL));
    735   EndLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
    736   EndLabel->Number       = LABEL_END;
    737 
    738   for (Index = 0; Index < mDriverHealthManagerHealthInfoCount; Index++) {
    739     if (ConfigureOnly && mDriverHealthManagerHealthInfo[Index].HealthStatus != EfiDriverHealthStatusConfigurationRequired) {
    740       continue;
    741     }
    742     DriverName = DriverHealthManagerGetDriverName (mDriverHealthManagerHealthInfo[Index].DriverHealthHandle);
    743     ASSERT (DriverName != NULL);
    744 
    745     if (mDriverHealthManagerHealthInfo[Index].ControllerHandle == NULL) {
    746       //
    747       // The ControllerHandle is set to NULL and the HealthStatus is set to EfiDriverHealthStatusHealthy
    748       // if all the controllers managed by the driver are in healthy state.
    749       //
    750       ASSERT (mDriverHealthManagerHealthInfo[Index].HealthStatus == EfiDriverHealthStatusHealthy);
    751       UnicodeSPrint (String, sizeof (String), L"%s", DriverName);
    752     } else {
    753       ControllerName = DriverHealthManagerGetControllerName (
    754                          mDriverHealthManagerHealthInfo[Index].DriverHealthHandle,
    755                          mDriverHealthManagerHealthInfo[Index].ControllerHandle,
    756                          mDriverHealthManagerHealthInfo[Index].ChildHandle
    757                          );
    758       ASSERT (ControllerName != NULL);
    759       UnicodeSPrint (String, sizeof (String), L"%s    %s", DriverName, ControllerName);
    760       FreePool (ControllerName);
    761     }
    762     FreePool (DriverName);
    763 
    764     Prompt = HiiSetString (mDriverHealthManagerHiiHandle, 0, String, NULL);
    765 
    766     switch(mDriverHealthManagerHealthInfo[Index].HealthStatus) {
    767     case EfiDriverHealthStatusRepairRequired:
    768       TmpString = HiiGetString (mDriverHealthManagerHiiHandle, STRING_TOKEN (STR_REPAIR_REQUIRED), NULL);
    769       break;
    770     case EfiDriverHealthStatusConfigurationRequired:
    771       TmpString = HiiGetString (mDriverHealthManagerHiiHandle, STRING_TOKEN (STR_CONFIGURATION_REQUIRED), NULL);
    772       break;
    773     case EfiDriverHealthStatusFailed:
    774       TmpString = HiiGetString (mDriverHealthManagerHiiHandle, STRING_TOKEN (STR_FAILED), NULL);
    775       break;
    776     case EfiDriverHealthStatusReconnectRequired:
    777       TmpString = HiiGetString (mDriverHealthManagerHiiHandle, STRING_TOKEN (STR_RECONNECT_REQUIRED), NULL);
    778       break;
    779     case EfiDriverHealthStatusRebootRequired:
    780       TmpString = HiiGetString (mDriverHealthManagerHiiHandle, STRING_TOKEN (STR_REBOOT_REQUIRED), NULL);
    781       break;
    782     default:
    783       ASSERT (mDriverHealthManagerHealthInfo[Index].HealthStatus == EfiDriverHealthStatusHealthy);
    784       TmpString = HiiGetString (mDriverHealthManagerHiiHandle, STRING_TOKEN (STR_HEALTHY), NULL);
    785       break;
    786     }
    787     StringCount = UnicodeSPrint (String, sizeof (String), L"%s\n", TmpString);
    788     FreePool (TmpString);
    789 
    790     //
    791     // Add the message of the Module itself provided as the help.
    792     //
    793     if (mDriverHealthManagerHealthInfo[Index].MessageList != NULL) {
    794       for (MessageIndex = 0; mDriverHealthManagerHealthInfo[Index].MessageList[MessageIndex].HiiHandle != NULL; MessageIndex++) {
    795         TmpString = HiiGetString (
    796                       mDriverHealthManagerHealthInfo[Index].MessageList[MessageIndex].HiiHandle,
    797                       mDriverHealthManagerHealthInfo[Index].MessageList[MessageIndex].StringId,
    798                       NULL
    799                       );
    800         StringCount += UnicodeSPrint (String + StringCount, sizeof (String) - sizeof (String[0]) * StringCount, L"\n%s", TmpString);
    801         FreePool (TmpString);
    802       }
    803     }
    804     Help = HiiSetString (mDriverHealthManagerHiiHandle, 0, String, NULL);
    805 
    806     switch (mDriverHealthManagerHealthInfo[Index].HealthStatus) {
    807     case EfiDriverHealthStatusConfigurationRequired:
    808       Status = mDriverHealthManagerDatabase->GetPackageListHandle (
    809                                                mDriverHealthManagerDatabase,
    810                                                mDriverHealthManagerHealthInfo[Index].HiiHandle,
    811                                                &DriverHandle
    812                                                );
    813       ASSERT_EFI_ERROR (Status);
    814       TmpString  = ConvertDevicePathToText (DevicePathFromHandle (DriverHandle), FALSE, TRUE);
    815       DevicePath = HiiSetString (mDriverHealthManagerHiiHandle, 0, TmpString, NULL);
    816       FreePool (TmpString);
    817 
    818       Status = DriverHealthManagerGetFormsetId (mDriverHealthManagerHealthInfo[Index].HiiHandle, &FormsetGuid);
    819       ASSERT_EFI_ERROR (Status);
    820 
    821       HiiCreateGotoExOpCode (
    822         StartOpCodeHandle,
    823         0,
    824         Prompt,
    825         Help,
    826         0,
    827         0,
    828         0,
    829         &FormsetGuid,
    830         DevicePath
    831         );
    832       break;
    833 
    834     case EfiDriverHealthStatusRepairRequired:
    835     case EfiDriverHealthStatusReconnectRequired:
    836     case EfiDriverHealthStatusRebootRequired:
    837       HiiCreateActionOpCode (
    838         StartOpCodeHandle,
    839         (EFI_QUESTION_ID) (Index + QUESTION_ID_DRIVER_HEALTH_BASE),
    840         Prompt,
    841         Help,
    842         EFI_IFR_FLAG_CALLBACK,
    843         0
    844         );
    845       break;
    846 
    847     default:
    848       ASSERT (mDriverHealthManagerHealthInfo[Index].HealthStatus == EfiDriverHealthStatusHealthy ||
    849               mDriverHealthManagerHealthInfo[Index].HealthStatus == EfiDriverHealthStatusFailed);
    850       HiiCreateTextOpCode (
    851         StartOpCodeHandle,
    852         Prompt,
    853         Help,
    854         0
    855         );
    856       break;
    857     }
    858   }
    859 
    860   Status = HiiUpdateForm (
    861              mDriverHealthManagerHiiHandle,
    862              ConfigureOnly ? PcdGetPtr (PcdDriverHealthConfigureForm) : &mDriverHealthManagerForm,
    863              DRIVER_HEALTH_FORM_ID,
    864              StartOpCodeHandle,
    865              EndOpCodeHandle
    866              );
    867   ASSERT_EFI_ERROR (Status);
    868 
    869   HiiFreeOpCodeHandle (StartOpCodeHandle);
    870   HiiFreeOpCodeHandle (EndOpCodeHandle);
    871 }
    872 
    873 /**
    874   Called when the form is closing to remove the dynamicly added string from the HII package list.
    875 **/
    876 VOID
    877 DriverHealthManagerCleanDynamicString (
    878   VOID
    879   )
    880 {
    881   EFI_STATUS                   Status;
    882   EFI_HII_PACKAGE_LIST_HEADER  *HiiPackageList;
    883   UINTN                        BufferSize;
    884   EFI_HII_PACKAGE_HEADER       *PackageHeader;
    885   UINT32                       FixedStringSize;
    886 
    887   FixedStringSize = *(UINT32 *) &STRING_ARRAY_NAME - sizeof (UINT32);
    888   BufferSize      = sizeof (EFI_HII_PACKAGE_LIST_HEADER) + FixedStringSize + sizeof (EFI_HII_PACKAGE_HEADER);
    889   HiiPackageList  = AllocatePool (BufferSize);
    890   ASSERT (HiiPackageList != NULL);
    891 
    892   HiiPackageList->PackageLength = (UINT32) BufferSize;
    893   CopyMem (&HiiPackageList->PackageListGuid, &gEfiCallerIdGuid, sizeof (EFI_GUID));
    894 
    895   PackageHeader = (EFI_HII_PACKAGE_HEADER *) (HiiPackageList + 1);
    896   CopyMem (PackageHeader, STRING_ARRAY_NAME + sizeof (UINT32), FixedStringSize);
    897 
    898   PackageHeader = (EFI_HII_PACKAGE_HEADER *) ((UINT8 *) PackageHeader + PackageHeader->Length);
    899   PackageHeader->Type   = EFI_HII_PACKAGE_END;
    900   PackageHeader->Length = sizeof (EFI_HII_PACKAGE_HEADER);
    901 
    902   Status = mDriverHealthManagerDatabase->UpdatePackageList (
    903                                            mDriverHealthManagerDatabase,
    904                                            mDriverHealthManagerHiiHandle,
    905                                            HiiPackageList
    906                                            );
    907   ASSERT_EFI_ERROR (Status);
    908 
    909   //
    910   // Form package not found in this Package List
    911   //
    912   FreePool (HiiPackageList);
    913 }
    914 
    915 /**
    916   This function is invoked if user selected a interactive opcode from Driver Health's
    917   Formset.
    918 
    919   @param This            Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
    920   @param Action          Specifies the type of action taken by the browser.
    921   @param QuestionId      A unique value which is sent to the original exporting driver
    922                          so that it can identify the type of data to expect.
    923   @param Type            The type of value for the question.
    924   @param Value           A pointer to the data being sent to the original exporting driver.
    925   @param ActionRequest   On return, points to the action requested by the callback function.
    926 
    927   @retval  EFI_SUCCESS           The callback successfully handled the action.
    928   @retval  EFI_INVALID_PARAMETER The setup browser call this function with invalid parameters.
    929 
    930 **/
    931 EFI_STATUS
    932 EFIAPI
    933 DriverHealthManagerCallback (
    934   IN  CONST EFI_HII_CONFIG_ACCESS_PROTOCOL   *This,
    935   IN  EFI_BROWSER_ACTION                     Action,
    936   IN  EFI_QUESTION_ID                        QuestionId,
    937   IN  UINT8                                  Type,
    938   IN  EFI_IFR_TYPE_VALUE                     *Value,
    939   OUT EFI_BROWSER_ACTION_REQUEST             *ActionRequest
    940   )
    941 {
    942   UINTN                                      Index;
    943 
    944   if (QuestionId == QUESTION_ID_REFRESH_MANAGER || QuestionId == QUESTION_ID_REFRESH_CONFIGURE) {
    945     if (Action == EFI_BROWSER_ACTION_FORM_OPEN) {
    946       DriverHealthManagerUpdateForm ((BOOLEAN) (QuestionId == QUESTION_ID_REFRESH_CONFIGURE));
    947     } else if (Action == EFI_BROWSER_ACTION_FORM_CLOSE) {
    948       DriverHealthManagerCleanDynamicString ();
    949     }
    950     return EFI_SUCCESS;
    951   }
    952 
    953   if (Action != EFI_BROWSER_ACTION_CHANGED) {
    954     //
    955     // Do nothing for other UEFI Action. Only do call back when data is changed.
    956     //
    957     return EFI_UNSUPPORTED;
    958   }
    959 
    960   if ((Value == NULL) || (ActionRequest == NULL)) {
    961     return EFI_INVALID_PARAMETER;
    962   }
    963 
    964   DEBUG ((EFI_D_ERROR, "QuestionId = %x\n", QuestionId));
    965 
    966   //
    967   // We will have returned from processing a callback - user either hit ESC to exit, or selected
    968   // a target to display.
    969   // Process the diver health status states here.
    970   //
    971   Index = QuestionId - QUESTION_ID_DRIVER_HEALTH_BASE;
    972   ASSERT (Index < mDriverHealthManagerHealthInfoCount);
    973   //
    974   // Process the driver's healthy status for the specify module
    975   //
    976   DriverHealthManagerProcessSingleControllerHealth (
    977     mDriverHealthManagerHealthInfo[Index].DriverHealth,
    978     mDriverHealthManagerHealthInfo[Index].ControllerHandle,
    979     mDriverHealthManagerHealthInfo[Index].ChildHandle,
    980     mDriverHealthManagerHealthInfo[Index].HealthStatus,
    981     &(mDriverHealthManagerHealthInfo[Index].MessageList),
    982     mDriverHealthManagerHealthInfo[Index].HiiHandle
    983     );
    984 
    985   DriverHealthManagerUpdateForm ((BOOLEAN) (QuestionId == QUESTION_ID_REFRESH_CONFIGURE));
    986 
    987   return EFI_SUCCESS;
    988 }
    989 
    990 
    991