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