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
DriverHealthManagerFakeExtractConfig(IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL * This,IN CONST EFI_STRING Request,OUT EFI_STRING * Progress,OUT EFI_STRING * Results)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
DriverHealthManagerFakeRouteConfig(IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL * This,IN CONST EFI_STRING Configuration,OUT EFI_STRING * Progress)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
InitializeDriverHealthManager(EFI_HANDLE ImageHandle,EFI_SYSTEM_TABLE * SystemTable)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 *
DriverHealthManagerSelectBestLanguage(IN CHAR8 * SupportedLanguages,IN BOOLEAN Iso639Language)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
DriverHealthManagerGetComponentNameWorker(IN EFI_GUID * ProtocolGuid,IN EFI_HANDLE DriverBindingHandle,OUT EFI_COMPONENT_NAME_PROTOCOL ** ComponentName,OUT CHAR8 ** SupportedLanguage)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
DriverHealthManagerGetDriverNameWorker(IN EFI_GUID * ProtocolGuid,IN EFI_HANDLE DriverBindingHandle,OUT CHAR16 ** DriverName)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 *
DriverHealthManagerGetDriverName(IN EFI_HANDLE DriverBindingHandle)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
DriverHealthManagerGetControllerNameWorker(IN EFI_GUID * ProtocolGuid,IN EFI_HANDLE DriverBindingHandle,IN EFI_HANDLE ControllerHandle,IN EFI_HANDLE ChildHandle,OUT CHAR16 ** ControllerName)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 *
DriverHealthManagerGetControllerName(IN EFI_HANDLE DriverBindingHandle,IN EFI_HANDLE ControllerHandle,IN EFI_HANDLE ChildHandle)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
DriverHealthManagerRepairNotify(IN UINTN Value,IN UINTN Limit)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
DriverHealthManagerGetFormsetId(IN EFI_HII_HANDLE Handle,OUT EFI_GUID * FormsetGuid)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
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)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
DriverHealthManagerUpdateForm(BOOLEAN ConfigureOnly)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
DriverHealthManagerCleanDynamicString(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
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)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