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