]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Library/UefiBootManagerLib/BmDriverHealth.c
MdeModulePkg: Fix EOL to be DOS format.
[mirror_edk2.git] / MdeModulePkg / Library / UefiBootManagerLib / BmDriverHealth.c
CommitLineData
067ed98a
RN
1/** @file\r
2 Library functions which relates with driver health.\r
3\r
4Copyright (c) 2011 - 2015, Intel Corporation. All rights reserved.<BR>\r
5This program and the accompanying materials\r
6are licensed and made available under the terms and conditions of the BSD License\r
7which accompanies this distribution. The full text of the license may be found at\r
8http://opensource.org/licenses/bsd-license.php\r
9\r
10THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
11WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
12\r
13**/\r
14\r
15#include "InternalBm.h"\r
16\r
17GLOBAL_REMOVE_IF_UNREFERENCED\r
18 CHAR16 *mBmHealthStatusText[] = {\r
19 L"Healthy",\r
20 L"Repair Required",\r
21 L"Configuration Required",\r
22 L"Failed",\r
23 L"Reconnect Required",\r
24 L"Reboot Required"\r
25 };\r
26\r
27/**\r
28 Return the controller name.\r
29\r
30 @param DriverHealthHandle The handle on which the Driver Health protocol instance is retrieved.\r
31 @param ControllerHandle The handle of a controller that the driver specified by DriverBindingHandle is managing.\r
32 This handle specifies the controller whose name is to be returned.\r
33 @param ChildHandle The handle of the child controller to retrieve the name of. This is an\r
34 optional parameter that may be NULL. It will be NULL for device drivers.\r
35 It will also be NULL for bus drivers that attempt to retrieve the name\r
36 of the bus controller. It will not be NULL for a bus driver that attempts\r
37 to retrieve the name of a child controller.\r
38\r
39 @return A pointer to the Unicode string to return. This Unicode string is the name of the controller\r
40 specified by ControllerHandle and ChildHandle.\r
41**/\r
42CHAR16 *\r
43BmGetControllerName (\r
44 IN EFI_HANDLE DriverHealthHandle,\r
45 IN EFI_HANDLE ControllerHandle,\r
46 IN EFI_HANDLE ChildHandle\r
47 )\r
48{\r
49 EFI_STATUS Status;\r
50 CHAR16 *ControllerName;\r
51 CHAR8 *LanguageVariable;\r
52 CHAR8 *BestLanguage;\r
53 BOOLEAN Iso639Language;\r
54 EFI_COMPONENT_NAME_PROTOCOL *ComponentName;\r
55\r
56 ControllerName = NULL;\r
57\r
58 //\r
59 // Locate Component Name (2) protocol on the driver binging handle.\r
60 //\r
61 Iso639Language = FALSE;\r
62 Status = gBS->HandleProtocol (\r
63 DriverHealthHandle,\r
64 &gEfiComponentName2ProtocolGuid,\r
65 (VOID **) &ComponentName\r
66 );\r
67 if (EFI_ERROR (Status)) {\r
68 Status = gBS->HandleProtocol (\r
69 DriverHealthHandle,\r
70 &gEfiComponentNameProtocolGuid,\r
71 (VOID **) &ComponentName\r
72 );\r
73 if (!EFI_ERROR (Status)) {\r
74 Iso639Language = TRUE;\r
75 }\r
76 }\r
77\r
78 if (!EFI_ERROR (Status)) {\r
79 LanguageVariable = GetEfiGlobalVariable (Iso639Language ? L"Lang" : L"PlatformLang");\r
80 BestLanguage = GetBestLanguage(\r
81 ComponentName->SupportedLanguages,\r
82 Iso639Language,\r
83 (LanguageVariable != NULL) ? LanguageVariable : "",\r
84 Iso639Language ? "eng" : "en-US",\r
85 NULL\r
86 );\r
87 if (LanguageVariable != NULL) {\r
88 FreePool (LanguageVariable);\r
89 }\r
90\r
91 Status = ComponentName->GetControllerName (\r
92 ComponentName,\r
93 ControllerHandle, \r
94 ChildHandle,\r
95 BestLanguage,\r
96 &ControllerName\r
97 );\r
98 }\r
99\r
100 if (!EFI_ERROR (Status)) {\r
101 return AllocateCopyPool (StrSize (ControllerName), ControllerName);\r
102 } else {\r
103 return ConvertDevicePathToText (\r
104 DevicePathFromHandle (ChildHandle != NULL ? ChildHandle : ControllerHandle),\r
105 FALSE,\r
106 FALSE\r
107 );\r
108 }\r
109}\r
110\r
111/**\r
112 Display a set of messages returned by the GetHealthStatus () service of the EFI Driver Health Protocol\r
113\r
114 @param DriverHealthInfo Pointer to the Driver Health information entry.\r
115**/\r
116VOID\r
117BmDisplayMessages (\r
118 IN EFI_BOOT_MANAGER_DRIVER_HEALTH_INFO *DriverHealthInfo\r
119 )\r
120{\r
121 UINTN Index;\r
122 EFI_STRING String;\r
123 CHAR16 *ControllerName;\r
124\r
125 if (DriverHealthInfo->MessageList == NULL ||\r
126 DriverHealthInfo->MessageList[0].HiiHandle == NULL) {\r
127 return;\r
128 }\r
129\r
130 ControllerName = BmGetControllerName (\r
131 DriverHealthInfo->DriverHealthHandle,\r
132 DriverHealthInfo->ControllerHandle, \r
133 DriverHealthInfo->ChildHandle\r
134 );\r
135\r
136 DEBUG ((EFI_D_INFO, "Controller: %s\n", ControllerName));\r
137 Print (L"Controller: %s\n", ControllerName);\r
138 for (Index = 0; DriverHealthInfo->MessageList[Index].HiiHandle != NULL; Index++) {\r
139 String = HiiGetString (\r
140 DriverHealthInfo->MessageList[Index].HiiHandle,\r
141 DriverHealthInfo->MessageList[Index].StringId,\r
142 NULL\r
143 );\r
144 if (String != NULL) {\r
145 Print (L" %s\n", String);\r
146 DEBUG ((EFI_D_INFO, " %s\n", String));\r
147 FreePool (String);\r
148 }\r
149 }\r
150\r
151 if (ControllerName != NULL) {\r
152 FreePool (ControllerName);\r
153 }\r
154}\r
155\r
156/**\r
157 The repair notify function.\r
158 @param Value A value between 0 and Limit that identifies the current progress\r
159 of the repair operation.\r
160 @param Limit The maximum value of Value for the current repair operation.\r
161 If Limit is 0, then the completion progress is indeterminate.\r
162 For example, a driver that wants to specify progress in percent\r
163 would use a Limit value of 100.\r
164\r
165 @retval EFI_SUCCESS Successfully return from the notify function.\r
166**/\r
167EFI_STATUS\r
168EFIAPI\r
169BmRepairNotify (\r
170 IN UINTN Value,\r
171 IN UINTN Limit\r
172 )\r
173{\r
174 DEBUG ((EFI_D_INFO, "[BDS]RepairNotify: %d/%d\n", Value, Limit));\r
175 Print (L"[BDS]RepairNotify: %d/%d\n", Value, Limit);\r
176\r
177 return EFI_SUCCESS;\r
178}\r
179\r
180/**\r
181 Collect the Driver Health status of a single controller.\r
182 \r
183 @param DriverHealthInfo A pointer to the array containing all of the platform driver health information.\r
184 @param Count Return the updated array count.\r
185 @param DriverHealthHandle The handle on which the Driver Health protocol instance is retrieved.\r
186 @param ControllerHandle The handle of the controller..\r
187 @param ChildHandle The handle of the child controller to retrieve the health\r
188 status on. This is an optional parameter that may be NULL.\r
189\r
190 @retval Status The status returned from GetHealthStatus.\r
191 @retval EFI_ABORTED The health status is healthy so no further query is needed.\r
192\r
193**/\r
194EFI_STATUS\r
195BmGetSingleControllerHealthStatus (\r
196 IN OUT EFI_BOOT_MANAGER_DRIVER_HEALTH_INFO **DriverHealthInfo,\r
197 IN OUT UINTN *Count,\r
198 IN EFI_HANDLE DriverHealthHandle,\r
199 IN EFI_HANDLE ControllerHandle, OPTIONAL\r
200 IN EFI_HANDLE ChildHandle OPTIONAL\r
201 )\r
202{\r
203 EFI_STATUS Status;\r
204 EFI_DRIVER_HEALTH_PROTOCOL *DriverHealth;\r
205 EFI_DRIVER_HEALTH_HII_MESSAGE *MessageList;\r
206 EFI_HII_HANDLE FormHiiHandle;\r
207 EFI_DRIVER_HEALTH_STATUS HealthStatus;\r
208\r
209 ASSERT (DriverHealthHandle != NULL);\r
210 //\r
211 // Retrieve the Driver Health Protocol from DriverHandle\r
212 //\r
213 Status = gBS->HandleProtocol (\r
214 DriverHealthHandle,\r
215 &gEfiDriverHealthProtocolGuid,\r
216 (VOID **) &DriverHealth\r
217 );\r
218 ASSERT_EFI_ERROR (Status);\r
219 \r
220\r
221 if (ControllerHandle == NULL) {\r
222 //\r
223 // If ControllerHandle is NULL, the return the cumulative health status of the driver\r
224 //\r
225 Status = DriverHealth->GetHealthStatus (DriverHealth, NULL, NULL, &HealthStatus, NULL, NULL);\r
226 if (!EFI_ERROR (Status) && HealthStatus == EfiDriverHealthStatusHealthy) {\r
227 *DriverHealthInfo = ReallocatePool (\r
228 (*Count) * sizeof (EFI_BOOT_MANAGER_DRIVER_HEALTH_INFO),\r
229 (*Count + 1) * sizeof (EFI_BOOT_MANAGER_DRIVER_HEALTH_INFO),\r
230 *DriverHealthInfo\r
231 );\r
232 ASSERT (*DriverHealthInfo != NULL);\r
233\r
234 (*DriverHealthInfo)[*Count].DriverHealthHandle = DriverHealthHandle;\r
235 (*DriverHealthInfo)[*Count].DriverHealth = DriverHealth;\r
236 (*DriverHealthInfo)[*Count].HealthStatus = HealthStatus;\r
237\r
238 *Count = *Count + 1;\r
239\r
240 Status = EFI_ABORTED;\r
241 }\r
242 return Status;\r
243 }\r
244\r
245 MessageList = NULL;\r
246 FormHiiHandle = NULL;\r
247\r
248 //\r
249 // Collect the health status with the optional HII message list\r
250 //\r
251 Status = DriverHealth->GetHealthStatus (DriverHealth, ControllerHandle, ChildHandle, &HealthStatus, &MessageList, &FormHiiHandle);\r
252 if (!EFI_ERROR (Status)) {\r
253 *DriverHealthInfo = ReallocatePool (\r
254 (*Count) * sizeof (EFI_BOOT_MANAGER_DRIVER_HEALTH_INFO),\r
255 (*Count + 1) * sizeof (EFI_BOOT_MANAGER_DRIVER_HEALTH_INFO),\r
256 *DriverHealthInfo\r
257 );\r
258 ASSERT (*DriverHealthInfo != NULL);\r
259 (*DriverHealthInfo)[*Count].DriverHealth = DriverHealth;\r
260 (*DriverHealthInfo)[*Count].DriverHealthHandle = DriverHealthHandle;\r
261 (*DriverHealthInfo)[*Count].ControllerHandle = ControllerHandle;\r
262 (*DriverHealthInfo)[*Count].ChildHandle = ChildHandle;\r
263 (*DriverHealthInfo)[*Count].HiiHandle = FormHiiHandle;\r
264 (*DriverHealthInfo)[*Count].MessageList = MessageList;\r
265 (*DriverHealthInfo)[*Count].HealthStatus = HealthStatus;\r
266\r
267 *Count = *Count + 1;\r
268 }\r
269\r
270 return Status;\r
271}\r
272\r
273/**\r
274 Return all the Driver Health information.\r
275\r
276 When the cumulative health status of all the controllers managed by the\r
277 driver who produces the EFI_DRIVER_HEALTH_PROTOCOL is healthy, only one\r
278 EFI_BOOT_MANAGER_DRIVER_HEALTH_INFO entry is created for such\r
279 EFI_DRIVER_HEALTH_PROTOCOL instance.\r
280 Otherwise, every controller creates one EFI_BOOT_MANAGER_DRIVER_HEALTH_INFO\r
281 entry. Additionally every child controller creates one\r
282 EFI_BOOT_MANAGER_DRIVER_HEALTH_INFO entry if the driver is a bus driver.\r
283\r
284 @param Count Return the count of the Driver Health information.\r
285\r
286 @retval NULL No Driver Health information is returned.\r
287 @retval !NULL Pointer to the Driver Health information array.\r
288**/\r
289EFI_BOOT_MANAGER_DRIVER_HEALTH_INFO *\r
290EFIAPI\r
291EfiBootManagerGetDriverHealthInfo (\r
292 UINTN *Count\r
293 )\r
294{\r
295 EFI_STATUS Status;\r
296 UINTN NumHandles;\r
297 EFI_HANDLE *DriverHealthHandles;\r
298 EFI_DRIVER_HEALTH_STATUS HealthStatus;\r
299 UINTN DriverHealthIndex;\r
300 EFI_HANDLE *Handles;\r
301 UINTN HandleCount;\r
302 UINTN ControllerIndex;\r
303 UINTN ChildIndex;\r
304 EFI_BOOT_MANAGER_DRIVER_HEALTH_INFO *DriverHealthInfo;\r
305\r
306 //\r
307 // Initialize local variables\r
308 //\r
309 *Count = 0;\r
310 DriverHealthInfo = NULL;\r
311 Handles = NULL;\r
312 DriverHealthHandles = NULL;\r
313 NumHandles = 0;\r
314 HandleCount = 0;\r
315\r
316 HealthStatus = EfiDriverHealthStatusHealthy;\r
317\r
318 Status = gBS->LocateHandleBuffer (\r
319 ByProtocol,\r
320 &gEfiDriverHealthProtocolGuid,\r
321 NULL,\r
322 &NumHandles,\r
323 &DriverHealthHandles\r
324 );\r
325\r
326 if (Status == EFI_NOT_FOUND || NumHandles == 0) {\r
327 //\r
328 // If there are no Driver Health Protocols handles, then return EFI_NOT_FOUND\r
329 //\r
330 return NULL;\r
331 }\r
332\r
333 ASSERT_EFI_ERROR (Status);\r
334 ASSERT (DriverHealthHandles != NULL);\r
335\r
336 //\r
337 // Check the health status of all controllers in the platform\r
338 // Start by looping through all the Driver Health Protocol handles in the handle database\r
339 //\r
340 for (DriverHealthIndex = 0; DriverHealthIndex < NumHandles; DriverHealthIndex++) {\r
341 //\r
342 // Get the cumulative health status of the driver\r
343 //\r
344 Status = BmGetSingleControllerHealthStatus (&DriverHealthInfo, Count, DriverHealthHandles[DriverHealthIndex], NULL, NULL);\r
345 if (EFI_ERROR (Status)) {\r
346 continue;\r
347 }\r
348\r
349 //\r
350 // See if the list of all handles in the handle database has been retrieved\r
351 //\r
352 //\r
353 if (Handles == NULL) {\r
354 //\r
355 // Retrieve the list of all handles from the handle database\r
356 //\r
357 Status = gBS->LocateHandleBuffer (\r
358 AllHandles,\r
359 NULL,\r
360 NULL,\r
361 &HandleCount,\r
362 &Handles\r
363 );\r
364 ASSERT_EFI_ERROR (Status);\r
365 }\r
366 //\r
367 // Loop through all the controller handles in the handle database\r
368 //\r
369 for (ControllerIndex = 0; ControllerIndex < HandleCount; ControllerIndex++) {\r
370 Status = BmGetSingleControllerHealthStatus (&DriverHealthInfo, Count, DriverHealthHandles[DriverHealthIndex], Handles[ControllerIndex], NULL);\r
371 if (EFI_ERROR (Status)) {\r
372 continue;\r
373 }\r
374\r
375 //\r
376 // Loop through all the child handles in the handle database\r
377 //\r
378 for (ChildIndex = 0; ChildIndex < HandleCount; ChildIndex++) {\r
379 Status = BmGetSingleControllerHealthStatus (&DriverHealthInfo, Count, DriverHealthHandles[DriverHealthIndex], Handles[ControllerIndex], Handles[ChildIndex]);\r
380 if (EFI_ERROR (Status)) {\r
381 continue;\r
382 }\r
383 }\r
384 }\r
385 }\r
386\r
387 Status = EFI_SUCCESS;\r
388\r
389 if (Handles != NULL) {\r
390 FreePool (Handles);\r
391 }\r
392 if (DriverHealthHandles != NULL) {\r
393 FreePool (DriverHealthHandles);\r
394 }\r
395\r
396 return DriverHealthInfo;\r
397}\r
398\r
399/**\r
400 Free the Driver Health information array.\r
401\r
402 @param DriverHealthInfo Pointer to array of the Driver Health information.\r
403 @param Count Count of the array.\r
404\r
405 @retval EFI_SUCCESS The array is freed.\r
406 @retval EFI_INVALID_PARAMETER The array is NULL.\r
407**/\r
408EFI_STATUS\r
409EFIAPI\r
410EfiBootManagerFreeDriverHealthInfo (\r
411 EFI_BOOT_MANAGER_DRIVER_HEALTH_INFO *DriverHealthInfo,\r
412 UINTN Count\r
413 )\r
414{\r
415 UINTN Index;\r
416\r
417 for (Index = 0; Index < Count; Index++) {\r
418 if (DriverHealthInfo[Index].MessageList != NULL) {\r
419 FreePool (DriverHealthInfo[Index].MessageList);\r
420 }\r
421 }\r
422 return gBS->FreePool (DriverHealthInfo);\r
423}\r
424\r
425/**\r
426 Repair all the controllers according to the Driver Health status queried.\r
427**/\r
428VOID\r
429BmRepairAllControllers (\r
430 VOID\r
431 )\r
432{\r
433 EFI_STATUS Status;\r
434 EFI_BOOT_MANAGER_DRIVER_HEALTH_INFO *DriverHealthInfo;\r
435 EFI_DRIVER_HEALTH_STATUS HealthStatus;\r
436 UINTN Count;\r
437 UINTN Index;\r
438 BOOLEAN RepairRequired;\r
439 BOOLEAN ConfigurationRequired;\r
440 BOOLEAN ReconnectRequired;\r
441 BOOLEAN RebootRequired;\r
442 EFI_HII_HANDLE *HiiHandles;\r
443 EFI_FORM_BROWSER2_PROTOCOL *FormBrowser2;\r
444\r
445 //\r
446 // Configure PcdDriverHealthConfigureForm to ZeroGuid to disable driver health check.\r
447 //\r
448 if (CompareGuid (PcdGetPtr (PcdDriverHealthConfigureForm), &gZeroGuid)) {\r
449 return;\r
450 }\r
451\r
452 Status = gBS->LocateProtocol (&gEfiFormBrowser2ProtocolGuid, NULL, (VOID **) &FormBrowser2);\r
453 ASSERT_EFI_ERROR (Status);\r
454\r
455 do {\r
456 RepairRequired = FALSE;\r
457 ConfigurationRequired = FALSE;\r
458\r
459 //\r
460 // Deal with Repair Required\r
461 //\r
462 DriverHealthInfo = EfiBootManagerGetDriverHealthInfo (&Count);\r
463 for (Index = 0; Index < Count; Index++) {\r
464 if (DriverHealthInfo[Index].HealthStatus == EfiDriverHealthStatusConfigurationRequired) {\r
465 ConfigurationRequired = TRUE;\r
466 }\r
467 \r
468 if (DriverHealthInfo[Index].HealthStatus == EfiDriverHealthStatusRepairRequired) {\r
469 RepairRequired = TRUE;\r
470\r
471 BmDisplayMessages (&DriverHealthInfo[Index]);\r
472\r
473 Status = DriverHealthInfo[Index].DriverHealth->Repair (\r
474 DriverHealthInfo[Index].DriverHealth,\r
475 DriverHealthInfo[Index].ControllerHandle,\r
476 DriverHealthInfo[Index].ChildHandle,\r
477 BmRepairNotify\r
478 );\r
479 if (!EFI_ERROR (Status) && !ConfigurationRequired) {\r
480 Status = DriverHealthInfo[Index].DriverHealth->GetHealthStatus (\r
481 DriverHealthInfo[Index].DriverHealth,\r
482 DriverHealthInfo[Index].ControllerHandle,\r
483 DriverHealthInfo[Index].ChildHandle,\r
484 &HealthStatus,\r
485 NULL,\r
486 NULL\r
487 );\r
488 if (!EFI_ERROR (Status) && (HealthStatus == EfiDriverHealthStatusConfigurationRequired)) {\r
489 ConfigurationRequired = TRUE;\r
490 }\r
491 }\r
492 }\r
493 }\r
494\r
495 if (ConfigurationRequired) {\r
496 HiiHandles = HiiGetHiiHandles (NULL);\r
497 if (HiiHandles != NULL) {\r
498 for (Index = 0; HiiHandles[Index] != NULL; Index++) {\r
499 Status = FormBrowser2->SendForm (\r
500 FormBrowser2,\r
501 &HiiHandles[Index],\r
502 1,\r
503 PcdGetPtr (PcdDriverHealthConfigureForm),\r
504 0,\r
505 NULL,\r
506 NULL\r
507 );\r
508 if (!EFI_ERROR (Status)) {\r
509 break;\r
510 }\r
511 }\r
512 FreePool (HiiHandles);\r
513 }\r
514 }\r
515 \r
516 EfiBootManagerFreeDriverHealthInfo (DriverHealthInfo, Count);\r
517 } while (RepairRequired || ConfigurationRequired);\r
518\r
519 RebootRequired = FALSE;\r
520 ReconnectRequired = FALSE;\r
521 DriverHealthInfo = EfiBootManagerGetDriverHealthInfo (&Count);\r
522 for (Index = 0; Index < Count; Index++) {\r
523\r
524 BmDisplayMessages (&DriverHealthInfo[Index]);\r
525\r
526 if (DriverHealthInfo[Index].HealthStatus == EfiDriverHealthStatusReconnectRequired) {\r
527 Status = gBS->DisconnectController (DriverHealthInfo[Index].ControllerHandle, NULL, NULL);\r
528 if (EFI_ERROR (Status)) {\r
529 //\r
530 // Disconnect failed. Need to promote reconnect to a reboot.\r
531 //\r
532 RebootRequired = TRUE;\r
533 } else {\r
534 gBS->ConnectController (DriverHealthInfo[Index].ControllerHandle, NULL, NULL, TRUE);\r
535 ReconnectRequired = TRUE;\r
536 }\r
537 }\r
538\r
539 if (DriverHealthInfo[Index].HealthStatus == EfiDriverHealthStatusRebootRequired) {\r
540 RebootRequired = TRUE;\r
541 }\r
542 }\r
543 EfiBootManagerFreeDriverHealthInfo (DriverHealthInfo, Count);\r
544\r
545\r
546 if (ReconnectRequired) {\r
547 BmRepairAllControllers ();\r
548 }\r
549\r
550 DEBUG_CODE (\r
551 CHAR16 *ControllerName;\r
552\r
553 DriverHealthInfo = EfiBootManagerGetDriverHealthInfo (&Count);\r
554 for (Index = 0; Index < Count; Index++) {\r
555 ControllerName = BmGetControllerName (\r
556 DriverHealthInfo[Index].DriverHealthHandle,\r
557 DriverHealthInfo[Index].ControllerHandle,\r
558 DriverHealthInfo[Index].ChildHandle\r
559 );\r
560 DEBUG ((\r
561 EFI_D_INFO,\r
562 "%02d: %s - %s\n",\r
563 Index,\r
564 ControllerName,\r
565 mBmHealthStatusText[DriverHealthInfo[Index].HealthStatus]\r
566 ));\r
567 if (ControllerName != NULL) {\r
568 FreePool (ControllerName);\r
569 }\r
570 }\r
571 EfiBootManagerFreeDriverHealthInfo (DriverHealthInfo, Count);\r
572 );\r
573\r
574 if (RebootRequired) {\r
575 DEBUG ((EFI_D_INFO, "[BDS] One of the Driver Health instances requires rebooting.\n"));\r
576 gRT->ResetSystem (EfiResetWarm, EFI_SUCCESS, 0, NULL);\r
577 }\r
578}\r