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