]> git.proxmox.com Git - mirror_edk2.git/blob - IntelFrameworkModulePkg/Universal/BdsDxe/DeviceMngr/DeviceManager.c
IntelFrameworkModulePkg: Replace BSD License with BSD+Patent License
[mirror_edk2.git] / IntelFrameworkModulePkg / Universal / BdsDxe / DeviceMngr / DeviceManager.c
1 /** @file
2 The platform device manager reference implementation
3
4 Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
6
7 **/
8
9 #include "DeviceManager.h"
10
11 DEVICE_MANAGER_CALLBACK_DATA gDeviceManagerPrivate = {
12 DEVICE_MANAGER_CALLBACK_DATA_SIGNATURE,
13 NULL,
14 NULL,
15 NULL,
16 NULL,
17 {
18 FakeExtractConfig,
19 FakeRouteConfig,
20 DeviceManagerCallback
21 },
22 {
23 FakeExtractConfig,
24 FakeRouteConfig,
25 DriverHealthCallback
26 }
27 };
28
29 #define MAX_MAC_ADDRESS_NODE_LIST_LEN 10
30
31 //
32 // Which Mac Address string is select
33 // it will decide what menu need to show in the NETWORK_DEVICE_FORM_ID form.
34 //
35 EFI_STRING mSelectedMacAddrString;
36
37 //
38 // Which form Id need to be show.
39 //
40 EFI_FORM_ID mNextShowFormId = DEVICE_MANAGER_FORM_ID;
41
42 //
43 // The Mac Address show in the NETWORK_DEVICE_LIST_FORM_ID
44 //
45 MAC_ADDRESS_NODE_LIST mMacDeviceList;
46
47 DEVICE_MANAGER_MENU_ITEM mDeviceManagerMenuItemTable[] = {
48 { STRING_TOKEN (STR_DISK_DEVICE), EFI_DISK_DEVICE_CLASS },
49 { STRING_TOKEN (STR_VIDEO_DEVICE), EFI_VIDEO_DEVICE_CLASS },
50 { STRING_TOKEN (STR_NETWORK_DEVICE), EFI_NETWORK_DEVICE_CLASS },
51 { STRING_TOKEN (STR_INPUT_DEVICE), EFI_INPUT_DEVICE_CLASS },
52 { STRING_TOKEN (STR_ON_BOARD_DEVICE), EFI_ON_BOARD_DEVICE_CLASS },
53 { STRING_TOKEN (STR_OTHER_DEVICE), EFI_OTHER_DEVICE_CLASS }
54 };
55
56 HII_VENDOR_DEVICE_PATH mDeviceManagerHiiVendorDevicePath = {
57 {
58 {
59 HARDWARE_DEVICE_PATH,
60 HW_VENDOR_DP,
61 {
62 (UINT8) (sizeof (VENDOR_DEVICE_PATH)),
63 (UINT8) ((sizeof (VENDOR_DEVICE_PATH)) >> 8)
64 }
65 },
66 DEVICE_MANAGER_FORMSET_GUID
67 },
68 {
69 END_DEVICE_PATH_TYPE,
70 END_ENTIRE_DEVICE_PATH_SUBTYPE,
71 {
72 (UINT8) (END_DEVICE_PATH_LENGTH),
73 (UINT8) ((END_DEVICE_PATH_LENGTH) >> 8)
74 }
75 }
76 };
77
78 HII_VENDOR_DEVICE_PATH mDriverHealthHiiVendorDevicePath = {
79 {
80 {
81 HARDWARE_DEVICE_PATH,
82 HW_VENDOR_DP,
83 {
84 (UINT8) (sizeof (VENDOR_DEVICE_PATH)),
85 (UINT8) ((sizeof (VENDOR_DEVICE_PATH)) >> 8)
86 }
87 },
88 DRIVER_HEALTH_FORMSET_GUID
89 },
90 {
91 END_DEVICE_PATH_TYPE,
92 END_ENTIRE_DEVICE_PATH_SUBTYPE,
93 {
94 (UINT8) (END_DEVICE_PATH_LENGTH),
95 (UINT8) ((END_DEVICE_PATH_LENGTH) >> 8)
96 }
97 }
98 };
99
100 /**
101 This function is invoked if user selected a interactive opcode from Device Manager's
102 Formset. The decision by user is saved to gCallbackKey for later processing. If
103 user set VBIOS, the new value is saved to EFI variable.
104
105 @param This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
106 @param Action Specifies the type of action taken by the browser.
107 @param QuestionId A unique value which is sent to the original exporting driver
108 so that it can identify the type of data to expect.
109 @param Type The type of value for the question.
110 @param Value A pointer to the data being sent to the original exporting driver.
111 @param ActionRequest On return, points to the action requested by the callback function.
112
113 @retval EFI_SUCCESS The callback successfully handled the action.
114 @retval EFI_INVALID_PARAMETER The setup browser call this function with invalid parameters.
115
116 **/
117 EFI_STATUS
118 EFIAPI
119 DeviceManagerCallback (
120 IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
121 IN EFI_BROWSER_ACTION Action,
122 IN EFI_QUESTION_ID QuestionId,
123 IN UINT8 Type,
124 IN EFI_IFR_TYPE_VALUE *Value,
125 OUT EFI_BROWSER_ACTION_REQUEST *ActionRequest
126 )
127 {
128 UINTN CurIndex;
129
130 if (Action != EFI_BROWSER_ACTION_CHANGING) {
131 //
132 // All other action return unsupported.
133 //
134 return EFI_UNSUPPORTED;
135 }
136
137 if (Value == NULL) {
138 return EFI_INVALID_PARAMETER;
139 }
140
141 gCallbackKey = QuestionId;
142 if ((QuestionId < MAX_KEY_SECTION_LEN + NETWORK_DEVICE_LIST_KEY_OFFSET) && (QuestionId >= NETWORK_DEVICE_LIST_KEY_OFFSET)) {
143 //
144 // If user select the mac address, need to record mac address string to support next form show.
145 //
146 for (CurIndex = 0; CurIndex < mMacDeviceList.CurListLen; CurIndex ++) {
147 if (mMacDeviceList.NodeList[CurIndex].QuestionId == QuestionId) {
148 mSelectedMacAddrString = HiiGetString (gDeviceManagerPrivate.HiiHandle, mMacDeviceList.NodeList[CurIndex].PromptId, NULL);
149 }
150 }
151 }
152
153 return EFI_SUCCESS;
154 }
155
156 /**
157
158 This function registers HII packages to HII database.
159
160 @retval EFI_SUCCESS HII packages for the Device Manager were registered successfully.
161 @retval EFI_OUT_OF_RESOURCES HII packages for the Device Manager failed to be registered.
162
163 **/
164 EFI_STATUS
165 InitializeDeviceManager (
166 VOID
167 )
168 {
169 EFI_STATUS Status;
170
171 //
172 // Install Device Path Protocol and Config Access protocol to driver handle
173 //
174 Status = gBS->InstallMultipleProtocolInterfaces (
175 &gDeviceManagerPrivate.DriverHandle,
176 &gEfiDevicePathProtocolGuid,
177 &mDeviceManagerHiiVendorDevicePath,
178 &gEfiHiiConfigAccessProtocolGuid,
179 &gDeviceManagerPrivate.ConfigAccess,
180 NULL
181 );
182 ASSERT_EFI_ERROR (Status);
183
184 Status = gBS->InstallMultipleProtocolInterfaces (
185 &gDeviceManagerPrivate.DriverHealthHandle,
186 &gEfiDevicePathProtocolGuid,
187 &mDriverHealthHiiVendorDevicePath,
188 &gEfiHiiConfigAccessProtocolGuid,
189 &gDeviceManagerPrivate.DriverHealthConfigAccess,
190 NULL
191 );
192 ASSERT_EFI_ERROR (Status);
193
194 mMacDeviceList.CurListLen = 0;
195 mMacDeviceList.MaxListLen = 0;
196
197 return Status;
198 }
199
200 /**
201 Extract the displayed formset for given HII handle and class guid.
202
203 @param Handle The HII handle.
204 @param SetupClassGuid The class guid specifies which form set will be displayed.
205 @param SkipCount Skip some formsets which has processed before.
206 @param FormSetTitle Formset title string.
207 @param FormSetHelp Formset help string.
208 @param FormSetGuid Return the formset guid for this formset.
209
210 @retval TRUE The formset for given HII handle will be displayed.
211 @return FALSE The formset for given HII handle will not be displayed.
212
213 **/
214 BOOLEAN
215 ExtractDisplayedHiiFormFromHiiHandle (
216 IN EFI_HII_HANDLE Handle,
217 IN EFI_GUID *SetupClassGuid,
218 IN UINTN SkipCount,
219 OUT EFI_STRING_ID *FormSetTitle,
220 OUT EFI_STRING_ID *FormSetHelp,
221 OUT EFI_GUID **FormSetGuid
222 )
223 {
224 EFI_STATUS Status;
225 UINTN BufferSize;
226 EFI_HII_PACKAGE_LIST_HEADER *HiiPackageList;
227 UINT8 *Package;
228 UINT8 *OpCodeData;
229 UINT32 Offset;
230 UINT32 Offset2;
231 UINT32 PackageListLength;
232 EFI_HII_PACKAGE_HEADER PackageHeader;
233 EFI_GUID *ClassGuid;
234 UINT8 ClassGuidNum;
235
236 ASSERT (Handle != NULL);
237 ASSERT (SetupClassGuid != NULL);
238 ASSERT (FormSetTitle != NULL);
239 ASSERT (FormSetHelp != NULL);
240
241 *FormSetTitle = 0;
242 *FormSetHelp = 0;
243 ClassGuidNum = 0;
244 ClassGuid = NULL;
245
246 //
247 // Get HII PackageList
248 //
249 BufferSize = 0;
250 HiiPackageList = NULL;
251 Status = gHiiDatabase->ExportPackageLists (gHiiDatabase, Handle, &BufferSize, HiiPackageList);
252 //
253 // Handle is a invalid handle. Check if Handle is corrupted.
254 //
255 ASSERT (Status != EFI_NOT_FOUND);
256 //
257 // The return status should always be EFI_BUFFER_TOO_SMALL as input buffer's size is 0.
258 //
259 ASSERT (Status == EFI_BUFFER_TOO_SMALL);
260
261 HiiPackageList = AllocatePool (BufferSize);
262 ASSERT (HiiPackageList != NULL);
263
264 Status = gHiiDatabase->ExportPackageLists (gHiiDatabase, Handle, &BufferSize, HiiPackageList);
265 if (EFI_ERROR (Status)) {
266 return FALSE;
267 }
268
269 //
270 // Get Form package from this HII package List
271 //
272 Offset = sizeof (EFI_HII_PACKAGE_LIST_HEADER);
273 Offset2 = 0;
274 PackageListLength = ReadUnaligned32 (&HiiPackageList->PackageLength);
275
276 while (Offset < PackageListLength) {
277 Package = ((UINT8 *) HiiPackageList) + Offset;
278 CopyMem (&PackageHeader, Package, sizeof (EFI_HII_PACKAGE_HEADER));
279
280 if (PackageHeader.Type == EFI_HII_PACKAGE_FORMS) {
281 //
282 // Search FormSet Opcode in this Form Package
283 //
284 Offset2 = sizeof (EFI_HII_PACKAGE_HEADER);
285 while (Offset2 < PackageHeader.Length) {
286 OpCodeData = Package + Offset2;
287 Offset2 += ((EFI_IFR_OP_HEADER *) OpCodeData)->Length;
288
289 if (((EFI_IFR_OP_HEADER *) OpCodeData)->OpCode == EFI_IFR_FORM_SET_OP) {
290 if (SkipCount != 0) {
291 SkipCount --;
292 continue;
293 }
294
295 if (((EFI_IFR_OP_HEADER *) OpCodeData)->Length > OFFSET_OF (EFI_IFR_FORM_SET, Flags)) {
296 //
297 // Find FormSet OpCode
298 //
299 ClassGuidNum = (UINT8) (((EFI_IFR_FORM_SET *) OpCodeData)->Flags & 0x3);
300 ClassGuid = (EFI_GUID *) (VOID *)(OpCodeData + sizeof (EFI_IFR_FORM_SET));
301 while (ClassGuidNum-- > 0) {
302 if (CompareGuid (SetupClassGuid, ClassGuid)) {
303 CopyMem (FormSetTitle, &((EFI_IFR_FORM_SET *) OpCodeData)->FormSetTitle, sizeof (EFI_STRING_ID));
304 CopyMem (FormSetHelp, &((EFI_IFR_FORM_SET *) OpCodeData)->Help, sizeof (EFI_STRING_ID));
305 *FormSetGuid = AllocateCopyPool (sizeof (EFI_GUID), &((EFI_IFR_FORM_SET *) OpCodeData)->Guid);
306 ASSERT (*FormSetGuid != NULL);
307 FreePool (HiiPackageList);
308 return TRUE;
309 }
310 ClassGuid ++;
311 }
312 } else {
313 CopyMem (FormSetTitle, &((EFI_IFR_FORM_SET *) OpCodeData)->FormSetTitle, sizeof (EFI_STRING_ID));
314 CopyMem (FormSetHelp, &((EFI_IFR_FORM_SET *) OpCodeData)->Help, sizeof (EFI_STRING_ID));
315 *FormSetGuid = AllocateCopyPool (sizeof (EFI_GUID), &((EFI_IFR_FORM_SET *) OpCodeData)->Guid);
316 ASSERT (*FormSetGuid != NULL);
317 FreePool (HiiPackageList);
318 return TRUE;
319 }
320 }
321 }
322 }
323
324 //
325 // Go to next package
326 //
327 Offset += PackageHeader.Length;
328 }
329
330 FreePool (HiiPackageList);
331
332 return FALSE;
333 }
334
335 /**
336 Get the mac address string from the device path.
337 if the device path has the vlan, get the vanid also.
338
339 @param MacAddressNode Device path begin with mac address
340 @param PBuffer Output string buffer contain mac address.
341
342 **/
343 BOOLEAN
344 GetMacAddressString(
345 IN MAC_ADDR_DEVICE_PATH *MacAddressNode,
346 OUT CHAR16 **PBuffer
347 )
348 {
349 UINTN HwAddressSize;
350 UINTN Index;
351 UINT8 *HwAddress;
352 EFI_DEVICE_PATH_PROTOCOL *Node;
353 UINT16 VlanId;
354 CHAR16 *String;
355 UINTN BufferLen;
356
357 VlanId = 0;
358 String = NULL;
359 ASSERT(MacAddressNode != NULL);
360
361 HwAddressSize = sizeof (EFI_MAC_ADDRESS);
362 if (MacAddressNode->IfType == 0x01 || MacAddressNode->IfType == 0x00) {
363 HwAddressSize = 6;
364 }
365
366 //
367 // The output format is MAC:XX:XX:XX:...\XXXX
368 // The size is the Number size + ":" size + Vlan size(\XXXX) + End
369 //
370 BufferLen = (4 + 2 * HwAddressSize + (HwAddressSize - 1) + 5 + 1) * sizeof (CHAR16);
371 String = AllocateZeroPool (BufferLen);
372 if (String == NULL) {
373 return FALSE;
374 }
375
376 *PBuffer = String;
377 StrCpyS (String, BufferLen / sizeof (CHAR16), L"MAC:");
378 String += 4;
379
380 //
381 // Convert the MAC address into a unicode string.
382 //
383 HwAddress = &MacAddressNode->MacAddress.Addr[0];
384 for (Index = 0; Index < HwAddressSize; Index++) {
385 UnicodeValueToStringS (
386 String,
387 BufferLen - ((UINTN)String - (UINTN)*PBuffer),
388 PREFIX_ZERO | RADIX_HEX,
389 *(HwAddress++),
390 2
391 );
392 String += StrnLenS (String, (BufferLen - ((UINTN)String - (UINTN)*PBuffer)) / sizeof (CHAR16));
393 if (Index < HwAddressSize - 1) {
394 *String++ = L':';
395 }
396 }
397
398 //
399 // If VLAN is configured, it will need extra 5 characters like "\0005".
400 // Plus one unicode character for the null-terminator.
401 //
402 Node = (EFI_DEVICE_PATH_PROTOCOL *)MacAddressNode;
403 while (!IsDevicePathEnd (Node)) {
404 if (Node->Type == MESSAGING_DEVICE_PATH && Node->SubType == MSG_VLAN_DP) {
405 VlanId = ((VLAN_DEVICE_PATH *) Node)->VlanId;
406 }
407 Node = NextDevicePathNode (Node);
408 }
409
410 if (VlanId != 0) {
411 *String++ = L'\\';
412 UnicodeValueToStringS (
413 String,
414 BufferLen - ((UINTN)String - (UINTN)*PBuffer),
415 PREFIX_ZERO | RADIX_HEX,
416 VlanId,
417 4
418 );
419 String += StrnLenS (String, (BufferLen - ((UINTN)String - (UINTN)*PBuffer)) / sizeof (CHAR16));
420 }
421
422 //
423 // Null terminate the Unicode string
424 //
425 *String = L'\0';
426
427 return TRUE;
428 }
429
430 /**
431 Save question id and prompt id to the mac device list.
432 If the same mac address has saved yet, no need to add more.
433
434 @param MacAddrString Mac address string.
435
436 @retval EFI_SUCCESS Add the item is successful.
437 @return Other values if failed to Add the item.
438 **/
439 BOOLEAN
440 AddIdToMacDeviceList (
441 IN EFI_STRING MacAddrString
442 )
443 {
444 MENU_INFO_ITEM *TempDeviceList;
445 UINTN Index;
446 EFI_STRING StoredString;
447 EFI_STRING_ID PromptId;
448 EFI_HII_HANDLE HiiHandle;
449
450 HiiHandle = gDeviceManagerPrivate.HiiHandle;
451 TempDeviceList = NULL;
452
453 for (Index = 0; Index < mMacDeviceList.CurListLen; Index ++) {
454 StoredString = HiiGetString (HiiHandle, mMacDeviceList.NodeList[Index].PromptId, NULL);
455 if (StoredString == NULL) {
456 return FALSE;
457 }
458
459 //
460 // Already has save the same mac address to the list.
461 //
462 if (StrCmp (MacAddrString, StoredString) == 0) {
463 return FALSE;
464 }
465 }
466
467 PromptId = HiiSetString(HiiHandle, 0, MacAddrString, NULL);
468 //
469 // If not in the list, save it.
470 //
471 if (mMacDeviceList.MaxListLen > mMacDeviceList.CurListLen + 1) {
472 mMacDeviceList.NodeList[mMacDeviceList.CurListLen].PromptId = PromptId;
473 mMacDeviceList.NodeList[mMacDeviceList.CurListLen].QuestionId = (EFI_QUESTION_ID) (mMacDeviceList.CurListLen + NETWORK_DEVICE_LIST_KEY_OFFSET);
474 } else {
475 mMacDeviceList.MaxListLen += MAX_MAC_ADDRESS_NODE_LIST_LEN;
476 if (mMacDeviceList.CurListLen != 0) {
477 TempDeviceList = ReallocatePool (
478 sizeof (MENU_INFO_ITEM) * mMacDeviceList.CurListLen,
479 sizeof (MENU_INFO_ITEM) * mMacDeviceList.MaxListLen,
480 mMacDeviceList.NodeList
481 );
482 } else {
483 TempDeviceList = (MENU_INFO_ITEM *)AllocatePool (sizeof (MENU_INFO_ITEM) * mMacDeviceList.MaxListLen);
484 }
485
486 if (TempDeviceList == NULL) {
487 return FALSE;
488 }
489 TempDeviceList[mMacDeviceList.CurListLen].PromptId = PromptId;
490 TempDeviceList[mMacDeviceList.CurListLen].QuestionId = (EFI_QUESTION_ID) (mMacDeviceList.CurListLen + NETWORK_DEVICE_LIST_KEY_OFFSET);
491
492 mMacDeviceList.NodeList = TempDeviceList;
493 }
494 mMacDeviceList.CurListLen ++;
495
496 return TRUE;
497 }
498
499 /**
500 Check the devcie path, try to find whether it has mac address path.
501
502 In this function, first need to check whether this path has mac address path.
503 second, when the mac address device path has find, also need to deicide whether
504 need to add this mac address relate info to the menu.
505
506 @param *Node Input device which need to be check.
507 @param *NeedAddItem Whether need to add the menu in the network device list.
508
509 @retval TRUE Has mac address device path.
510 @retval FALSE NOT Has mac address device path.
511
512 **/
513 BOOLEAN
514 IsMacAddressDevicePath (
515 IN VOID *Node,
516 OUT BOOLEAN *NeedAddItem
517 )
518 {
519 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
520 CHAR16 *Buffer;
521 BOOLEAN ReturnVal;
522
523 ASSERT (Node != NULL);
524 *NeedAddItem = FALSE;
525 ReturnVal = FALSE;
526 Buffer = NULL;
527
528 DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) Node;
529
530 //
531 // find the partition device path node
532 //
533 while (!IsDevicePathEnd (DevicePath)) {
534 if ((DevicePathType (DevicePath) == MESSAGING_DEVICE_PATH) &&
535 (DevicePathSubType (DevicePath) == MSG_MAC_ADDR_DP)) {
536 ReturnVal = TRUE;
537
538 if (DEVICE_MANAGER_FORM_ID == mNextShowFormId) {
539 *NeedAddItem = TRUE;
540 break;
541 }
542
543 if (!GetMacAddressString((MAC_ADDR_DEVICE_PATH*)DevicePath, &Buffer)) {
544 break;
545 }
546
547 if (NETWORK_DEVICE_FORM_ID == mNextShowFormId) {
548 if (StrCmp (Buffer, mSelectedMacAddrString) == 0) {
549 *NeedAddItem = TRUE;
550 }
551 break;
552 }
553
554 if (NETWORK_DEVICE_LIST_FORM_ID == mNextShowFormId) {
555 //
556 // Same handle may has two network child handle, so the questionid
557 // has the offset of SAME_HANDLE_KEY_OFFSET.
558 //
559 if (AddIdToMacDeviceList (Buffer)) {
560 *NeedAddItem = TRUE;
561 }
562 break;
563 }
564 }
565 DevicePath = NextDevicePathNode (DevicePath);
566 }
567
568 if (Buffer != NULL) {
569 FreePool (Buffer);
570 }
571
572 return ReturnVal;
573 }
574
575 /**
576 Check to see if the device path is for the network device.
577
578 @param Handle The HII handle which include the mac address device path.
579 @param ItemCount The new add Mac address item count.
580
581 @retval TRUE Need to add new item in the menu.
582 @return FALSE Do not need to add the menu about the network.
583
584 **/
585 BOOLEAN
586 IsNeedAddNetworkMenu (
587 IN EFI_HII_HANDLE Handle,
588 OUT UINTN *ItemCount
589 )
590 {
591 EFI_STATUS Status;
592 UINTN EntryCount;
593 UINTN Index;
594 EFI_HANDLE DriverHandle;
595 EFI_HANDLE ControllerHandle;
596 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
597 EFI_DEVICE_PATH_PROTOCOL *TmpDevicePath;
598 EFI_DEVICE_PATH_PROTOCOL *ChildDevicePath;
599 EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *OpenInfoBuffer;
600 BOOLEAN IsNeedAdd;
601
602 IsNeedAdd = FALSE;
603 OpenInfoBuffer = NULL;
604 if ((Handle == NULL) || (ItemCount == NULL)) {
605 return FALSE;
606 }
607 *ItemCount = 0;
608
609 Status = gHiiDatabase->GetPackageListHandle (gHiiDatabase, Handle, &DriverHandle);
610 if (EFI_ERROR (Status)) {
611 return FALSE;
612 }
613 //
614 // Get the device path by the got Driver handle .
615 //
616 Status = gBS->HandleProtocol (DriverHandle, &gEfiDevicePathProtocolGuid, (VOID **) &DevicePath);
617 if (EFI_ERROR (Status)) {
618 return FALSE;
619 }
620 TmpDevicePath = DevicePath;
621
622 //
623 // Check whether this device path include mac address device path.
624 // If this path has mac address path, get the value whether need
625 // add this info to the menu and return.
626 // Else check more about the child handle devcie path.
627 //
628 if (IsMacAddressDevicePath(TmpDevicePath, &IsNeedAdd)) {
629 if ((NETWORK_DEVICE_LIST_FORM_ID == mNextShowFormId) && IsNeedAdd) {
630 (*ItemCount) = 1;
631 }
632 return IsNeedAdd;
633 }
634
635 //
636 // Search whether this path is the controller path, not he child handle path.
637 // And the child handle has the network devcie connected.
638 //
639 TmpDevicePath = DevicePath;
640 Status = gBS->LocateDevicePath(&gEfiDevicePathProtocolGuid, &TmpDevicePath, &ControllerHandle);
641 if (EFI_ERROR (Status)) {
642 return FALSE;
643 }
644
645 if (!IsDevicePathEnd (TmpDevicePath)) {
646 return FALSE;
647 }
648
649 //
650 // Retrieve the list of agents that are consuming the specific protocol
651 // on ControllerHandle.
652 // The buffer point by OpenInfoBuffer need be free at this function.
653 //
654 Status = gBS->OpenProtocolInformation (
655 ControllerHandle,
656 &gEfiPciIoProtocolGuid,
657 &OpenInfoBuffer,
658 &EntryCount
659 );
660 if (EFI_ERROR (Status)) {
661 return FALSE;
662 }
663
664 //
665 // Inspect if ChildHandle is one of the agents.
666 //
667 Status = EFI_UNSUPPORTED;
668 for (Index = 0; Index < EntryCount; Index++) {
669 //
670 // Query all the children created by the controller handle's driver
671 //
672 if ((OpenInfoBuffer[Index].Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) != 0) {
673 Status = gBS->OpenProtocol (
674 OpenInfoBuffer[Index].ControllerHandle,
675 &gEfiDevicePathProtocolGuid,
676 (VOID **) &ChildDevicePath,
677 NULL,
678 NULL,
679 EFI_OPEN_PROTOCOL_GET_PROTOCOL
680 );
681 if (EFI_ERROR (Status)) {
682 continue;
683 }
684
685 //
686 // Check whether this device path include mac address device path.
687 //
688 if (!IsMacAddressDevicePath(ChildDevicePath, &IsNeedAdd)) {
689 //
690 // If this path not has mac address path, check the other.
691 //
692 continue;
693 } else {
694 //
695 // If need to update the NETWORK_DEVICE_LIST_FORM, try to get more.
696 //
697 if ((NETWORK_DEVICE_LIST_FORM_ID == mNextShowFormId)) {
698 if (IsNeedAdd) {
699 (*ItemCount) += 1;
700 }
701 continue;
702 } else {
703 //
704 // If need to update other form, return whether need to add to the menu.
705 //
706 goto Done;
707 }
708 }
709 }
710 }
711
712 Done:
713 if (OpenInfoBuffer != NULL) {
714 FreePool (OpenInfoBuffer);
715 }
716 return IsNeedAdd;
717 }
718
719 /**
720 Get HiiHandle total number.
721
722 @param HiiHandles The input HiiHandle array.
723
724 @retval the Hiihandle count.
725
726 **/
727 UINTN
728 GetHiiHandleCount (
729 IN EFI_HII_HANDLE *HiiHandles
730 )
731 {
732 UINTN Index;
733
734 for (Index = 0; HiiHandles[Index] != NULL; Index++) {
735 }
736
737 return Index;
738 }
739
740 /**
741 Insert the new HiiHandle + FormsetGuid at the NewPair[InsertOffset].
742
743 @param HiiHandles The input HiiHandle array.
744 @param GuidLists The input form set guid lists.
745 @param ArrayCount The input array count, new array will be arraycount + 1 size.
746 @param Offset The current used HiiHandle's Offset.
747 @param FormSetGuid The new found formset guid.
748
749 **/
750 VOID
751 AdjustArrayData (
752 IN OUT EFI_HII_HANDLE **HiiHandles,
753 IN OUT EFI_GUID ***GuidLists,
754 IN UINTN ArrayCount,
755 IN UINTN Offset,
756 IN EFI_GUID *FormSetGuid
757 )
758 {
759 EFI_HII_HANDLE *NewHiiHandles;
760 EFI_GUID **NewGuidLists;
761
762 //
763 // +2 means include the new HiiHandle and the last empty NULL pointer.
764 //
765 NewHiiHandles = AllocateZeroPool ((ArrayCount + 2) * sizeof (EFI_HII_HANDLE));
766 ASSERT (NewHiiHandles != NULL);
767
768 CopyMem (NewHiiHandles, *HiiHandles, Offset * sizeof (EFI_HII_HANDLE));
769 NewHiiHandles[Offset] = NewHiiHandles[Offset - 1];
770 CopyMem (NewHiiHandles + Offset + 1, *HiiHandles + Offset, (ArrayCount - Offset) * sizeof (EFI_HII_HANDLE));
771
772 NewGuidLists = AllocateZeroPool ((ArrayCount + 2) * sizeof (EFI_GUID *));
773 ASSERT (NewGuidLists != NULL);
774
775 CopyMem (NewGuidLists, *GuidLists, Offset * sizeof (EFI_GUID *));
776 NewGuidLists[Offset] = FormSetGuid;
777
778 FreePool (*HiiHandles);
779 *HiiHandles = NewHiiHandles;
780 FreePool (*GuidLists);
781 *GuidLists = NewGuidLists;
782 }
783
784 /**
785 Call the browser and display the device manager to allow user
786 to configure the platform.
787
788 This function create the dynamic content for device manager. It includes
789 section header for all class of devices, one-of opcode to set VBIOS.
790
791 @retval EFI_SUCCESS Operation is successful.
792 @return Other values if failed to clean up the dynamic content from HII
793 database.
794
795 **/
796 EFI_STATUS
797 CallDeviceManager (
798 VOID
799 )
800 {
801 EFI_STATUS Status;
802 UINTN Index;
803 EFI_STRING String;
804 EFI_STRING_ID Token;
805 EFI_STRING_ID TokenHelp;
806 EFI_HII_HANDLE *HiiHandles;
807 EFI_HII_HANDLE HiiHandle;
808 EFI_STRING_ID FormSetTitle;
809 EFI_STRING_ID FormSetHelp;
810 EFI_BROWSER_ACTION_REQUEST ActionRequest;
811 VOID *StartOpCodeHandle;
812 VOID *EndOpCodeHandle;
813 EFI_IFR_GUID_LABEL *StartLabel;
814 EFI_IFR_GUID_LABEL *EndLabel;
815 UINTN NumHandles;
816 EFI_HANDLE *DriverHealthHandles;
817 BOOLEAN AddNetworkMenu;
818 UINTN AddItemCount;
819 UINTN NewStringLen;
820 EFI_STRING NewStringTitle;
821 EFI_GUID **GuidLists;
822 UINTN HandleNum;
823 UINTN SkipCount;
824 EFI_GUID *FormSetGuid;
825
826 GuidLists = NULL;
827 HiiHandles = NULL;
828 Status = EFI_SUCCESS;
829 gCallbackKey = 0;
830 NumHandles = 0;
831 DriverHealthHandles = NULL;
832 AddNetworkMenu = FALSE;
833 AddItemCount = 0;
834 SkipCount = 0;
835 FormSetGuid = NULL;
836
837 //
838 // Connect all prior to entering the platform setup menu.
839 //
840 if (!gConnectAllHappened) {
841 BdsLibConnectAllDriversToAllControllers ();
842 gConnectAllHappened = TRUE;
843 }
844
845 HiiHandle = gDeviceManagerPrivate.HiiHandle;
846 if (HiiHandle == NULL) {
847 //
848 // Publish our HII data.
849 //
850 HiiHandle = HiiAddPackages (
851 &gDeviceManagerFormSetGuid,
852 gDeviceManagerPrivate.DriverHandle,
853 DeviceManagerVfrBin,
854 BdsDxeStrings,
855 NULL
856 );
857 if (HiiHandle == NULL) {
858 return EFI_OUT_OF_RESOURCES;
859 }
860
861 gDeviceManagerPrivate.HiiHandle = HiiHandle;
862 }
863
864 //
865 // If need show the Network device list form, clear the old save list first.
866 //
867 if ((mNextShowFormId == NETWORK_DEVICE_LIST_FORM_ID) && (mMacDeviceList.CurListLen > 0)) {
868 mMacDeviceList.CurListLen = 0;
869 }
870
871 //
872 // Update the network device form titile.
873 //
874 if (mNextShowFormId == NETWORK_DEVICE_FORM_ID) {
875 String = HiiGetString (HiiHandle, STRING_TOKEN (STR_FORM_NETWORK_DEVICE_TITLE), NULL);
876 NewStringLen = StrLen(mSelectedMacAddrString) * 2;
877 NewStringLen += (StrLen(String) + 2) * 2;
878 NewStringTitle = AllocatePool (NewStringLen);
879 UnicodeSPrint (NewStringTitle, NewStringLen, L"%s %s", String, mSelectedMacAddrString);
880 HiiSetString (HiiHandle, STRING_TOKEN (STR_FORM_NETWORK_DEVICE_TITLE), NewStringTitle, NULL);
881 FreePool (String);
882 FreePool (NewStringTitle);
883 }
884
885 //
886 // Allocate space for creation of UpdateData Buffer
887 //
888 StartOpCodeHandle = HiiAllocateOpCodeHandle ();
889 ASSERT (StartOpCodeHandle != NULL);
890
891 EndOpCodeHandle = HiiAllocateOpCodeHandle ();
892 ASSERT (EndOpCodeHandle != NULL);
893
894 //
895 // Create Hii Extend Label OpCode as the start opcode
896 //
897 StartLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (StartOpCodeHandle, &gEfiIfrTianoGuid, NULL, sizeof (EFI_IFR_GUID_LABEL));
898 StartLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
899 //
900 // According to the next show Form id(mNextShowFormId) to decide which form need to update.
901 //
902 StartLabel->Number = (UINT16) (LABEL_FORM_ID_OFFSET + mNextShowFormId);
903
904 //
905 // Create Hii Extend Label OpCode as the end opcode
906 //
907 EndLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (EndOpCodeHandle, &gEfiIfrTianoGuid, NULL, sizeof (EFI_IFR_GUID_LABEL));
908 EndLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
909 EndLabel->Number = LABEL_END;
910
911 //
912 // Get all the Hii handles
913 //
914 HiiHandles = HiiGetHiiHandles (NULL);
915 ASSERT (HiiHandles != NULL);
916
917 HandleNum = GetHiiHandleCount (HiiHandles);
918 GuidLists = AllocateZeroPool ((HandleNum + 1) * sizeof (EFI_GUID *));
919 ASSERT (GuidLists != NULL);
920
921 //
922 // Search for formset of each class type
923 //
924 for (Index = 0; HiiHandles[Index] != NULL; Index++) {
925 //
926 // The QuestionId in the form which will call the driver form has this asssumption.
927 // QuestionId = Handle Index + NETWORK_DEVICE_LIST_KEY_OFFSET;
928 // Different QuestionId at least has the section of NETWORK_DEVICE_LIST_KEY_OFFSET.
929 //
930 ASSERT(Index < MAX_KEY_SECTION_LEN);
931
932 if (!ExtractDisplayedHiiFormFromHiiHandle (HiiHandles[Index], &gEfiHiiPlatformSetupFormsetGuid, SkipCount, &FormSetTitle, &FormSetHelp, &FormSetGuid)) {
933 SkipCount = 0;
934 continue;
935 }
936
937 //
938 // One HiiHandle has more than one formset can be shown,
939 // Insert a new pair of HiiHandle + Guid to the HiiHandles and GuidLists list.
940 //
941 if (SkipCount > 0) {
942 AdjustArrayData (&HiiHandles, &GuidLists, HandleNum, Index + 1, FormSetGuid);
943 HandleNum ++;
944 Index ++;
945 }
946
947 String = HiiGetString (HiiHandles[Index], FormSetTitle, NULL);
948 if (String == NULL) {
949 String = HiiGetString (HiiHandle, STR_MISSING_STRING, NULL);
950 ASSERT (String != NULL);
951 }
952 Token = HiiSetString (HiiHandle, 0, String, NULL);
953 FreePool (String);
954
955 String = HiiGetString (HiiHandles[Index], FormSetHelp, NULL);
956 if (String == NULL) {
957 String = HiiGetString (HiiHandle, STR_MISSING_STRING, NULL);
958 ASSERT (String != NULL);
959 }
960 TokenHelp = HiiSetString (HiiHandle, 0, String, NULL);
961 FreePool (String);
962
963 //
964 // Network device process
965 //
966 if (IsNeedAddNetworkMenu (HiiHandles[Index], &AddItemCount)) {
967 if (mNextShowFormId == DEVICE_MANAGER_FORM_ID) {
968 //
969 // Only show one menu item "Network Config" in the device manger form.
970 //
971 if (!AddNetworkMenu) {
972 AddNetworkMenu = TRUE;
973 HiiCreateGotoOpCode (
974 StartOpCodeHandle,
975 INVALID_FORM_ID,
976 STRING_TOKEN (STR_FORM_NETWORK_DEVICE_LIST_TITLE),
977 STRING_TOKEN (STR_FORM_NETWORK_DEVICE_LIST_HELP),
978 EFI_IFR_FLAG_CALLBACK,
979 (EFI_QUESTION_ID) QUESTION_NETWORK_DEVICE_ID
980 );
981 }
982 } else if (mNextShowFormId == NETWORK_DEVICE_LIST_FORM_ID) {
983 //
984 // In network device list form, same mac address device only show one menu.
985 //
986 while (AddItemCount > 0) {
987 HiiCreateGotoOpCode (
988 StartOpCodeHandle,
989 INVALID_FORM_ID,
990 mMacDeviceList.NodeList[mMacDeviceList.CurListLen - AddItemCount].PromptId,
991 STRING_TOKEN (STR_NETWORK_DEVICE_HELP),
992 EFI_IFR_FLAG_CALLBACK,
993 mMacDeviceList.NodeList[mMacDeviceList.CurListLen - AddItemCount].QuestionId
994 );
995 AddItemCount -= 1;
996 }
997 } else if (mNextShowFormId == NETWORK_DEVICE_FORM_ID) {
998 //
999 // In network device form, only the selected mac address device need to be show.
1000 //
1001 HiiCreateGotoOpCode (
1002 StartOpCodeHandle,
1003 INVALID_FORM_ID,
1004 Token,
1005 TokenHelp,
1006 EFI_IFR_FLAG_CALLBACK,
1007 (EFI_QUESTION_ID) (Index + DEVICE_KEY_OFFSET)
1008 );
1009 }
1010 } else {
1011 //
1012 //
1013 // Not network device process, only need to show at device manger form.
1014 //
1015 if (mNextShowFormId == DEVICE_MANAGER_FORM_ID) {
1016 HiiCreateGotoOpCode (
1017 StartOpCodeHandle,
1018 INVALID_FORM_ID,
1019 Token,
1020 TokenHelp,
1021 EFI_IFR_FLAG_CALLBACK,
1022 (EFI_QUESTION_ID) (Index + DEVICE_KEY_OFFSET)
1023 );
1024 }
1025 }
1026
1027 //
1028 // Try to find more formset in this HiiHandle.
1029 //
1030 SkipCount++;
1031 Index--;
1032 }
1033
1034 Status = gBS->LocateHandleBuffer (
1035 ByProtocol,
1036 &gEfiDriverHealthProtocolGuid,
1037 NULL,
1038 &NumHandles,
1039 &DriverHealthHandles
1040 );
1041
1042 //
1043 // If there are no drivers installed driver health protocol, do not create driver health entry in UI
1044 //
1045 if (NumHandles != 0) {
1046 //
1047 // If driver health protocol is installed, create Driver Health subtitle and entry
1048 //
1049 HiiCreateSubTitleOpCode (StartOpCodeHandle, STRING_TOKEN (STR_DM_DRIVER_HEALTH_TITLE), 0, 0, 0);
1050 HiiCreateGotoOpCode (
1051 StartOpCodeHandle,
1052 DRIVER_HEALTH_FORM_ID,
1053 STRING_TOKEN(STR_DRIVER_HEALTH_ALL_HEALTHY), // Prompt text
1054 STRING_TOKEN(STR_DRIVER_HEALTH_STATUS_HELP), // Help text
1055 EFI_IFR_FLAG_CALLBACK,
1056 DEVICE_MANAGER_KEY_DRIVER_HEALTH // Question ID
1057 );
1058
1059 //
1060 // Check All Driver health status
1061 //
1062 if (!PlaformHealthStatusCheck ()) {
1063 //
1064 // At least one driver in the platform are not in healthy status
1065 //
1066 HiiSetString (HiiHandle, STRING_TOKEN (STR_DRIVER_HEALTH_ALL_HEALTHY), GetStringById (STRING_TOKEN (STR_DRIVER_NOT_HEALTH)), NULL);
1067 } else {
1068 //
1069 // For the string of STR_DRIVER_HEALTH_ALL_HEALTHY previously has been updated and we need to update it while re-entry.
1070 //
1071 HiiSetString (HiiHandle, STRING_TOKEN (STR_DRIVER_HEALTH_ALL_HEALTHY), GetStringById (STRING_TOKEN (STR_DRIVER_HEALTH_ALL_HEALTHY)), NULL);
1072 }
1073 }
1074
1075 HiiUpdateForm (
1076 HiiHandle,
1077 &gDeviceManagerFormSetGuid,
1078 mNextShowFormId,
1079 StartOpCodeHandle,
1080 EndOpCodeHandle
1081 );
1082
1083 ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;
1084 Status = gFormBrowser2->SendForm (
1085 gFormBrowser2,
1086 &HiiHandle,
1087 1,
1088 &gDeviceManagerFormSetGuid,
1089 mNextShowFormId,
1090 NULL,
1091 &ActionRequest
1092 );
1093 if (ActionRequest == EFI_BROWSER_ACTION_REQUEST_RESET) {
1094 EnableResetRequired ();
1095 }
1096
1097 //
1098 // We will have returned from processing a callback, selected
1099 // a target to display
1100 //
1101 if ((gCallbackKey >= DEVICE_KEY_OFFSET)) {
1102 ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;
1103 Status = gFormBrowser2->SendForm (
1104 gFormBrowser2,
1105 &HiiHandles[gCallbackKey - DEVICE_KEY_OFFSET],
1106 1,
1107 GuidLists[gCallbackKey - DEVICE_KEY_OFFSET],
1108 0,
1109 NULL,
1110 &ActionRequest
1111 );
1112
1113 if (ActionRequest == EFI_BROWSER_ACTION_REQUEST_RESET) {
1114 EnableResetRequired ();
1115 }
1116
1117 //
1118 // Force return to Device Manager
1119 //
1120 gCallbackKey = FRONT_PAGE_KEY_DEVICE_MANAGER;
1121 goto Done;
1122 }
1123
1124 //
1125 // Driver Health item chose.
1126 //
1127 if (gCallbackKey == DEVICE_MANAGER_KEY_DRIVER_HEALTH) {
1128 CallDriverHealth ();
1129 //
1130 // Force return to Device Manager
1131 //
1132 gCallbackKey = FRONT_PAGE_KEY_DEVICE_MANAGER;
1133 goto Done;
1134 }
1135
1136 //
1137 // Enter from device manager and into the network device list.
1138 //
1139 if (gCallbackKey == QUESTION_NETWORK_DEVICE_ID) {
1140 mNextShowFormId = NETWORK_DEVICE_LIST_FORM_ID;
1141 gCallbackKey = FRONT_PAGE_KEY_DEVICE_MANAGER;
1142 goto Done;
1143 }
1144
1145 //
1146 // In this case, go from the network device list to the specify device.
1147 //
1148 if ((gCallbackKey < MAX_KEY_SECTION_LEN + NETWORK_DEVICE_LIST_KEY_OFFSET ) && (gCallbackKey >= NETWORK_DEVICE_LIST_KEY_OFFSET)) {
1149 mNextShowFormId = NETWORK_DEVICE_FORM_ID;
1150 gCallbackKey = FRONT_PAGE_KEY_DEVICE_MANAGER;
1151 goto Done;
1152 }
1153
1154 //
1155 // Select the ESC, the gCallbackKey == 0.
1156 //
1157 if(mNextShowFormId - 1 < DEVICE_MANAGER_FORM_ID) {
1158 mNextShowFormId = DEVICE_MANAGER_FORM_ID;
1159 } else {
1160 mNextShowFormId = (UINT16) (mNextShowFormId - 1);
1161 gCallbackKey = FRONT_PAGE_KEY_DEVICE_MANAGER;
1162 }
1163
1164 Done:
1165 //
1166 // Remove our packagelist from HII database.
1167 //
1168 HiiRemovePackages (HiiHandle);
1169 gDeviceManagerPrivate.HiiHandle = NULL;
1170
1171 HiiFreeOpCodeHandle (StartOpCodeHandle);
1172 HiiFreeOpCodeHandle (EndOpCodeHandle);
1173 FreePool (HiiHandles);
1174
1175 for (Index = 0; Index < HandleNum; Index++) {
1176 if (GuidLists[Index] != NULL) {
1177 FreePool (GuidLists[Index]);
1178 }
1179 }
1180 FreePool (GuidLists);
1181
1182 return Status;
1183 }
1184
1185 /**
1186 This function is invoked if user selected a interactive opcode from Driver Health's
1187 Formset. The decision by user is saved to gCallbackKey for later processing.
1188
1189 @param This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
1190 @param Action Specifies the type of action taken by the browser.
1191 @param QuestionId A unique value which is sent to the original exporting driver
1192 so that it can identify the type of data to expect.
1193 @param Type The type of value for the question.
1194 @param Value A pointer to the data being sent to the original exporting driver.
1195 @param ActionRequest On return, points to the action requested by the callback function.
1196
1197 @retval EFI_SUCCESS The callback successfully handled the action.
1198 @retval EFI_INVALID_PARAMETER The setup browser call this function with invalid parameters.
1199
1200 **/
1201 EFI_STATUS
1202 EFIAPI
1203 DriverHealthCallback (
1204 IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
1205 IN EFI_BROWSER_ACTION Action,
1206 IN EFI_QUESTION_ID QuestionId,
1207 IN UINT8 Type,
1208 IN EFI_IFR_TYPE_VALUE *Value,
1209 OUT EFI_BROWSER_ACTION_REQUEST *ActionRequest
1210 )
1211 {
1212 if (Action == EFI_BROWSER_ACTION_CHANGED) {
1213 if ((Value == NULL) || (ActionRequest == NULL)) {
1214 return EFI_INVALID_PARAMETER;
1215 }
1216
1217 gCallbackKey = QuestionId;
1218
1219 //
1220 // Request to exit SendForm(), so as to switch to selected form
1221 //
1222 *ActionRequest = EFI_BROWSER_ACTION_REQUEST_EXIT;
1223
1224 return EFI_SUCCESS;
1225 }
1226
1227 //
1228 // All other action return unsupported.
1229 //
1230 return EFI_UNSUPPORTED;
1231 }
1232
1233 /**
1234 Collect and display the platform's driver health relative information, allow user to do interactive
1235 operation while the platform is unhealthy.
1236
1237 This function display a form which divided into two parts. The one list all modules which has installed
1238 driver health protocol. The list usually contain driver name, controller name, and it's health info.
1239 While the driver name can't be retrieved, will use device path as backup. The other part of the form provide
1240 a choice to the user to repair all platform.
1241
1242 **/
1243 VOID
1244 CallDriverHealth (
1245 VOID
1246 )
1247 {
1248 EFI_STATUS Status;
1249 EFI_HII_HANDLE HiiHandle;
1250 EFI_BROWSER_ACTION_REQUEST ActionRequest;
1251 EFI_IFR_GUID_LABEL *StartLabel;
1252 EFI_IFR_GUID_LABEL *StartLabelRepair;
1253 EFI_IFR_GUID_LABEL *EndLabel;
1254 EFI_IFR_GUID_LABEL *EndLabelRepair;
1255 VOID *StartOpCodeHandle;
1256 VOID *EndOpCodeHandle;
1257 VOID *StartOpCodeHandleRepair;
1258 VOID *EndOpCodeHandleRepair;
1259 UINTN Index;
1260 EFI_STRING_ID Token;
1261 EFI_STRING_ID TokenHelp;
1262 EFI_STRING String;
1263 EFI_STRING TmpString;
1264 EFI_STRING DriverName;
1265 EFI_STRING ControllerName;
1266 LIST_ENTRY DriverHealthList;
1267 DRIVER_HEALTH_INFO *DriverHealthInfo;
1268 LIST_ENTRY *Link;
1269 EFI_DEVICE_PATH_PROTOCOL *DriverDevicePath;
1270 BOOLEAN RebootRequired;
1271 BOOLEAN IsControllerNameEmpty;
1272 UINTN StringSize;
1273
1274 Index = 0;
1275 DriverHealthInfo = NULL;
1276 DriverDevicePath = NULL;
1277 IsControllerNameEmpty = FALSE;
1278 InitializeListHead (&DriverHealthList);
1279
1280 HiiHandle = gDeviceManagerPrivate.DriverHealthHiiHandle;
1281 if (HiiHandle == NULL) {
1282 //
1283 // Publish Driver Health HII data.
1284 //
1285 HiiHandle = HiiAddPackages (
1286 &gDeviceManagerFormSetGuid,
1287 gDeviceManagerPrivate.DriverHealthHandle,
1288 DriverHealthVfrBin,
1289 BdsDxeStrings,
1290 NULL
1291 );
1292 if (HiiHandle == NULL) {
1293 return;
1294 }
1295
1296 gDeviceManagerPrivate.DriverHealthHiiHandle = HiiHandle;
1297 }
1298
1299 //
1300 // Allocate space for creation of UpdateData Buffer
1301 //
1302 StartOpCodeHandle = HiiAllocateOpCodeHandle ();
1303 ASSERT (StartOpCodeHandle != NULL);
1304
1305 EndOpCodeHandle = HiiAllocateOpCodeHandle ();
1306 ASSERT (EndOpCodeHandle != NULL);
1307
1308 StartOpCodeHandleRepair = HiiAllocateOpCodeHandle ();
1309 ASSERT (StartOpCodeHandleRepair != NULL);
1310
1311 EndOpCodeHandleRepair = HiiAllocateOpCodeHandle ();
1312 ASSERT (EndOpCodeHandleRepair != NULL);
1313
1314 //
1315 // Create Hii Extend Label OpCode as the start opcode
1316 //
1317 StartLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (StartOpCodeHandle, &gEfiIfrTianoGuid, NULL, sizeof (EFI_IFR_GUID_LABEL));
1318 StartLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
1319 StartLabel->Number = LABEL_DRIVER_HEALTH;
1320
1321 //
1322 // Create Hii Extend Label OpCode as the start opcode
1323 //
1324 StartLabelRepair = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (StartOpCodeHandleRepair, &gEfiIfrTianoGuid, NULL, sizeof (EFI_IFR_GUID_LABEL));
1325 StartLabelRepair->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
1326 StartLabelRepair->Number = LABEL_DRIVER_HEALTH_REAPIR_ALL;
1327
1328 //
1329 // Create Hii Extend Label OpCode as the end opcode
1330 //
1331 EndLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (EndOpCodeHandle, &gEfiIfrTianoGuid, NULL, sizeof (EFI_IFR_GUID_LABEL));
1332 EndLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
1333 EndLabel->Number = LABEL_DRIVER_HEALTH_END;
1334
1335 //
1336 // Create Hii Extend Label OpCode as the end opcode
1337 //
1338 EndLabelRepair = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (EndOpCodeHandleRepair, &gEfiIfrTianoGuid, NULL, sizeof (EFI_IFR_GUID_LABEL));
1339 EndLabelRepair->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
1340 EndLabelRepair->Number = LABEL_DRIVER_HEALTH_REAPIR_ALL_END;
1341
1342 HiiCreateSubTitleOpCode (StartOpCodeHandle, STRING_TOKEN (STR_DH_STATUS_LIST), 0, 0, 1);
1343
1344 Status = GetAllControllersHealthStatus (&DriverHealthList);
1345 ASSERT (Status != EFI_OUT_OF_RESOURCES);
1346
1347 Link = GetFirstNode (&DriverHealthList);
1348
1349 while (!IsNull (&DriverHealthList, Link)) {
1350 DriverHealthInfo = DEVICE_MANAGER_HEALTH_INFO_FROM_LINK (Link);
1351
1352 Status = DriverHealthGetDriverName (DriverHealthInfo->DriverHandle, &DriverName);
1353 if (EFI_ERROR (Status)) {
1354 //
1355 // Can not get the Driver name, so use the Device path
1356 //
1357 DriverDevicePath = DevicePathFromHandle (DriverHealthInfo->DriverHandle);
1358 DriverName = DevicePathToStr (DriverDevicePath);
1359 }
1360 StringSize = StrSize (DriverName);
1361
1362 Status = DriverHealthGetControllerName (
1363 DriverHealthInfo->DriverHandle,
1364 DriverHealthInfo->ControllerHandle,
1365 DriverHealthInfo->ChildHandle,
1366 &ControllerName
1367 );
1368
1369 if (!EFI_ERROR (Status)) {
1370 IsControllerNameEmpty = FALSE;
1371 StringSize += StrLen (L" ") * sizeof(CHAR16);
1372 StringSize += StrLen (ControllerName) * sizeof(CHAR16);
1373 } else {
1374 IsControllerNameEmpty = TRUE;
1375 }
1376
1377 //
1378 // Add the message of the Module itself provided after the string item.
1379 //
1380 if ((DriverHealthInfo->MessageList != NULL) && (DriverHealthInfo->MessageList->StringId != 0)) {
1381 TmpString = HiiGetString (
1382 DriverHealthInfo->MessageList->HiiHandle,
1383 DriverHealthInfo->MessageList->StringId,
1384 NULL
1385 );
1386 ASSERT (TmpString != NULL);
1387
1388 StringSize += StrLen (L" ") * sizeof(CHAR16);
1389 StringSize += StrLen (TmpString) * sizeof(CHAR16);
1390
1391 String = (EFI_STRING) AllocateZeroPool (StringSize);
1392 ASSERT (String != NULL);
1393
1394 StrCpyS (String, StringSize / sizeof(CHAR16), DriverName);
1395 if (!IsControllerNameEmpty) {
1396 StrCatS (String, StringSize / sizeof(CHAR16), L" ");
1397 StrCatS (String, StringSize / sizeof(CHAR16), ControllerName);
1398 }
1399
1400 StrCatS (String, StringSize / sizeof(CHAR16), L" ");
1401 StrCatS (String, StringSize / sizeof(CHAR16), TmpString);
1402
1403 } else {
1404 //
1405 // Update the string will be displayed base on the driver's health status
1406 //
1407 switch(DriverHealthInfo->HealthStatus) {
1408 case EfiDriverHealthStatusRepairRequired:
1409 TmpString = GetStringById (STRING_TOKEN (STR_REPAIR_REQUIRED));
1410 break;
1411 case EfiDriverHealthStatusConfigurationRequired:
1412 TmpString = GetStringById (STRING_TOKEN (STR_CONFIGURATION_REQUIRED));
1413 break;
1414 case EfiDriverHealthStatusFailed:
1415 TmpString = GetStringById (STRING_TOKEN (STR_OPERATION_FAILED));
1416 break;
1417 case EfiDriverHealthStatusReconnectRequired:
1418 TmpString = GetStringById (STRING_TOKEN (STR_RECONNECT_REQUIRED));
1419 break;
1420 case EfiDriverHealthStatusRebootRequired:
1421 TmpString = GetStringById (STRING_TOKEN (STR_REBOOT_REQUIRED));
1422 break;
1423 default:
1424 TmpString = GetStringById (STRING_TOKEN (STR_DRIVER_HEALTH_HEALTHY));
1425 break;
1426 }
1427 ASSERT (TmpString != NULL);
1428
1429 StringSize += StrLen (TmpString) * sizeof(CHAR16);
1430
1431 String = (EFI_STRING) AllocateZeroPool (StringSize);
1432 ASSERT (String != NULL);
1433
1434 StrCpyS (String, StringSize / sizeof (CHAR16), DriverName);
1435 if (!IsControllerNameEmpty) {
1436 StrCatS (String, StringSize / sizeof (CHAR16), L" ");
1437 StrCatS (String, StringSize / sizeof (CHAR16), ControllerName);
1438 }
1439
1440 StrCatS (String, StringSize / sizeof (CHAR16), TmpString);
1441 }
1442
1443 FreePool (TmpString);
1444
1445 Token = HiiSetString (HiiHandle, 0, String, NULL);
1446 FreePool (String);
1447
1448 TokenHelp = HiiSetString (HiiHandle, 0, GetStringById( STRING_TOKEN (STR_DH_REPAIR_SINGLE_HELP)), NULL);
1449
1450 HiiCreateActionOpCode (
1451 StartOpCodeHandle,
1452 (EFI_QUESTION_ID) (Index + DRIVER_HEALTH_KEY_OFFSET),
1453 Token,
1454 TokenHelp,
1455 EFI_IFR_FLAG_CALLBACK,
1456 0
1457 );
1458 Index++;
1459 Link = GetNextNode (&DriverHealthList, Link);
1460 }
1461
1462 //
1463 // Add End Opcode for Subtitle
1464 //
1465 HiiCreateEndOpCode (StartOpCodeHandle);
1466
1467 HiiCreateSubTitleOpCode (StartOpCodeHandleRepair, STRING_TOKEN (STR_DRIVER_HEALTH_REPAIR_ALL), 0, 0, 1);
1468 TokenHelp = HiiSetString (HiiHandle, 0, GetStringById( STRING_TOKEN (STR_DH_REPAIR_ALL_HELP)), NULL);
1469
1470 if (PlaformHealthStatusCheck ()) {
1471 //
1472 // No action need to do for the platform
1473 //
1474 Token = HiiSetString (HiiHandle, 0, GetStringById( STRING_TOKEN (STR_DRIVER_HEALTH_ALL_HEALTHY)), NULL);
1475 HiiCreateActionOpCode (
1476 StartOpCodeHandleRepair,
1477 0,
1478 Token,
1479 TokenHelp,
1480 EFI_IFR_FLAG_READ_ONLY,
1481 0
1482 );
1483 } else {
1484 //
1485 // Create ActionOpCode only while the platform need to do health related operation.
1486 //
1487 Token = HiiSetString (HiiHandle, 0, GetStringById( STRING_TOKEN (STR_DH_REPAIR_ALL_TITLE)), NULL);
1488 HiiCreateActionOpCode (
1489 StartOpCodeHandleRepair,
1490 (EFI_QUESTION_ID) DRIVER_HEALTH_REPAIR_ALL_KEY,
1491 Token,
1492 TokenHelp,
1493 EFI_IFR_FLAG_CALLBACK,
1494 0
1495 );
1496 }
1497
1498 HiiCreateEndOpCode (StartOpCodeHandleRepair);
1499
1500 Status = HiiUpdateForm (
1501 HiiHandle,
1502 &gDriverHealthFormSetGuid,
1503 DRIVER_HEALTH_FORM_ID,
1504 StartOpCodeHandle,
1505 EndOpCodeHandle
1506 );
1507 ASSERT (Status != EFI_NOT_FOUND);
1508 ASSERT (Status != EFI_BUFFER_TOO_SMALL);
1509
1510 Status = HiiUpdateForm (
1511 HiiHandle,
1512 &gDriverHealthFormSetGuid,
1513 DRIVER_HEALTH_FORM_ID,
1514 StartOpCodeHandleRepair,
1515 EndOpCodeHandleRepair
1516 );
1517 ASSERT (Status != EFI_NOT_FOUND);
1518 ASSERT (Status != EFI_BUFFER_TOO_SMALL);
1519
1520 ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;
1521 Status = gFormBrowser2->SendForm (
1522 gFormBrowser2,
1523 &HiiHandle,
1524 1,
1525 &gDriverHealthFormSetGuid,
1526 DRIVER_HEALTH_FORM_ID,
1527 NULL,
1528 &ActionRequest
1529 );
1530 if (ActionRequest == EFI_BROWSER_ACTION_REQUEST_RESET) {
1531 EnableResetRequired ();
1532 }
1533
1534 //
1535 // We will have returned from processing a callback - user either hit ESC to exit, or selected
1536 // a target to display.
1537 // Process the diver health status states here.
1538 //
1539 if (gCallbackKey >= DRIVER_HEALTH_KEY_OFFSET && gCallbackKey != DRIVER_HEALTH_REPAIR_ALL_KEY) {
1540 ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;
1541
1542 Link = GetFirstNode (&DriverHealthList);
1543 Index = 0;
1544
1545 while (!IsNull (&DriverHealthList, Link)) {
1546 //
1547 // Got the item relative node in the List
1548 //
1549 if (Index == (gCallbackKey - DRIVER_HEALTH_KEY_OFFSET)) {
1550 DriverHealthInfo = DEVICE_MANAGER_HEALTH_INFO_FROM_LINK (Link);
1551 //
1552 // Process the driver's healthy status for the specify module
1553 //
1554 RebootRequired = FALSE;
1555 ProcessSingleControllerHealth (
1556 DriverHealthInfo->DriverHealth,
1557 DriverHealthInfo->ControllerHandle,
1558 DriverHealthInfo->ChildHandle,
1559 DriverHealthInfo->HealthStatus,
1560 &(DriverHealthInfo->MessageList),
1561 DriverHealthInfo->HiiHandle,
1562 &RebootRequired
1563 );
1564 if (RebootRequired) {
1565 gRT->ResetSystem (EfiResetWarm, EFI_SUCCESS, 0, NULL);
1566 }
1567 break;
1568 }
1569 Index++;
1570 Link = GetNextNode (&DriverHealthList, Link);
1571 }
1572
1573 if (ActionRequest == EFI_BROWSER_ACTION_REQUEST_RESET) {
1574 EnableResetRequired ();
1575 }
1576
1577 //
1578 // Force return to the form of Driver Health in Device Manager
1579 //
1580 gCallbackKey = DRIVER_HEALTH_RETURN_KEY;
1581 }
1582
1583 //
1584 // Repair the whole platform
1585 //
1586 if (gCallbackKey == DRIVER_HEALTH_REPAIR_ALL_KEY) {
1587 ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;
1588
1589 PlatformRepairAll (&DriverHealthList);
1590
1591 gCallbackKey = DRIVER_HEALTH_RETURN_KEY;
1592 }
1593
1594 //
1595 // Remove driver health packagelist from HII database.
1596 //
1597 HiiRemovePackages (HiiHandle);
1598 gDeviceManagerPrivate.DriverHealthHiiHandle = NULL;
1599
1600 //
1601 // Free driver health info list
1602 //
1603 while (!IsListEmpty (&DriverHealthList)) {
1604
1605 Link = GetFirstNode(&DriverHealthList);
1606 DriverHealthInfo = DEVICE_MANAGER_HEALTH_INFO_FROM_LINK (Link);
1607 RemoveEntryList (Link);
1608
1609 if (DriverHealthInfo->MessageList != NULL) {
1610 FreePool(DriverHealthInfo->MessageList);
1611 FreePool (DriverHealthInfo);
1612 }
1613 }
1614
1615 HiiFreeOpCodeHandle (StartOpCodeHandle);
1616 HiiFreeOpCodeHandle (EndOpCodeHandle);
1617 HiiFreeOpCodeHandle (StartOpCodeHandleRepair);
1618 HiiFreeOpCodeHandle (EndOpCodeHandleRepair);
1619
1620 if (gCallbackKey == DRIVER_HEALTH_RETURN_KEY) {
1621 //
1622 // Force return to Driver Health Form
1623 //
1624 gCallbackKey = DEVICE_MANAGER_KEY_DRIVER_HEALTH;
1625 CallDriverHealth ();
1626 }
1627 }
1628
1629
1630 /**
1631 Check the Driver Health status of a single controller and try to process it if not healthy.
1632
1633 This function called by CheckAllControllersHealthStatus () function in order to process a specify
1634 contoller's health state.
1635
1636 @param DriverHealthList A Pointer to the list contain all of the platform driver health information.
1637 @param DriverHandle The handle of driver.
1638 @param ControllerHandle The class guid specifies which form set will be displayed.
1639 @param ChildHandle The handle of the child controller to retrieve the health
1640 status on. This is an optional parameter that may be NULL.
1641 @param DriverHealth A pointer to the EFI_DRIVER_HEALTH_PROTOCOL instance.
1642 @param HealthStatus The health status of the controller.
1643
1644 @retval EFI_INVALID_PARAMETER HealthStatus or DriverHealth is NULL.
1645 @retval HealthStatus The Health status of specify controller.
1646 @retval EFI_OUT_OF_RESOURCES The list of Driver Health Protocol handles can not be retrieved.
1647 @retval EFI_NOT_FOUND No controller in the platform install Driver Health Protocol.
1648 @retval EFI_SUCCESS The Health related operation has been taken successfully.
1649
1650 **/
1651 EFI_STATUS
1652 EFIAPI
1653 GetSingleControllerHealthStatus (
1654 IN OUT LIST_ENTRY *DriverHealthList,
1655 IN EFI_HANDLE DriverHandle,
1656 IN EFI_HANDLE ControllerHandle, OPTIONAL
1657 IN EFI_HANDLE ChildHandle, OPTIONAL
1658 IN EFI_DRIVER_HEALTH_PROTOCOL *DriverHealth,
1659 IN EFI_DRIVER_HEALTH_STATUS *HealthStatus
1660 )
1661 {
1662 EFI_STATUS Status;
1663 EFI_DRIVER_HEALTH_HII_MESSAGE *MessageList;
1664 EFI_HII_HANDLE FormHiiHandle;
1665 DRIVER_HEALTH_INFO *DriverHealthInfo;
1666
1667 if (HealthStatus == NULL) {
1668 //
1669 // If HealthStatus is NULL, then return EFI_INVALID_PARAMETER
1670 //
1671 return EFI_INVALID_PARAMETER;
1672 }
1673
1674 //
1675 // Assume the HealthStatus is healthy
1676 //
1677 *HealthStatus = EfiDriverHealthStatusHealthy;
1678
1679 if (DriverHealth == NULL) {
1680 //
1681 // If DriverHealth is NULL, then return EFI_INVALID_PARAMETER
1682 //
1683 return EFI_INVALID_PARAMETER;
1684 }
1685
1686 if (ControllerHandle == NULL) {
1687 //
1688 // If ControllerHandle is NULL, the return the cumulative health status of the driver
1689 //
1690 Status = DriverHealth->GetHealthStatus (DriverHealth, NULL, NULL, HealthStatus, NULL, NULL);
1691 if (*HealthStatus == EfiDriverHealthStatusHealthy) {
1692 //
1693 // Add the driver health related information into the list
1694 //
1695 DriverHealthInfo = AllocateZeroPool (sizeof (DRIVER_HEALTH_INFO));
1696 if (DriverHealthInfo == NULL) {
1697 return EFI_OUT_OF_RESOURCES;
1698 }
1699
1700 DriverHealthInfo->Signature = DEVICE_MANAGER_DRIVER_HEALTH_INFO_SIGNATURE;
1701 DriverHealthInfo->DriverHandle = DriverHandle;
1702 DriverHealthInfo->ControllerHandle = NULL;
1703 DriverHealthInfo->ChildHandle = NULL;
1704 DriverHealthInfo->HiiHandle = NULL;
1705 DriverHealthInfo->DriverHealth = DriverHealth;
1706 DriverHealthInfo->MessageList = NULL;
1707 DriverHealthInfo->HealthStatus = *HealthStatus;
1708
1709 InsertTailList (DriverHealthList, &DriverHealthInfo->Link);
1710 }
1711 return Status;
1712 }
1713
1714 MessageList = NULL;
1715 FormHiiHandle = NULL;
1716
1717 //
1718 // Collect the health status with the optional HII message list
1719 //
1720 Status = DriverHealth->GetHealthStatus (DriverHealth, ControllerHandle, ChildHandle, HealthStatus, &MessageList, &FormHiiHandle);
1721
1722 if (EFI_ERROR (Status)) {
1723 //
1724 // If the health status could not be retrieved, then return immediately
1725 //
1726 return Status;
1727 }
1728
1729 //
1730 // Add the driver health related information into the list
1731 //
1732 DriverHealthInfo = AllocateZeroPool (sizeof (DRIVER_HEALTH_INFO));
1733 if (DriverHealthInfo == NULL) {
1734 return EFI_OUT_OF_RESOURCES;
1735 }
1736
1737 DriverHealthInfo->Signature = DEVICE_MANAGER_DRIVER_HEALTH_INFO_SIGNATURE;
1738 DriverHealthInfo->DriverHandle = DriverHandle;
1739 DriverHealthInfo->ControllerHandle = ControllerHandle;
1740 DriverHealthInfo->ChildHandle = ChildHandle;
1741 DriverHealthInfo->HiiHandle = FormHiiHandle;
1742 DriverHealthInfo->DriverHealth = DriverHealth;
1743 DriverHealthInfo->MessageList = MessageList;
1744 DriverHealthInfo->HealthStatus = *HealthStatus;
1745
1746 InsertTailList (DriverHealthList, &DriverHealthInfo->Link);
1747
1748 return EFI_SUCCESS;
1749 }
1750
1751 /**
1752 Collects all the EFI Driver Health Protocols currently present in the EFI Handle Database,
1753 and queries each EFI Driver Health Protocol to determine if one or more of the controllers
1754 managed by each EFI Driver Health Protocol instance are not healthy.
1755
1756 @param DriverHealthList A Pointer to the list contain all of the platform driver health
1757 information.
1758
1759 @retval EFI_NOT_FOUND No controller in the platform install Driver Health Protocol.
1760 @retval EFI_SUCCESS All the controllers in the platform are healthy.
1761 @retval EFI_OUT_OF_RESOURCES The list of Driver Health Protocol handles can not be retrieved.
1762
1763 **/
1764 EFI_STATUS
1765 GetAllControllersHealthStatus (
1766 IN OUT LIST_ENTRY *DriverHealthList
1767 )
1768 {
1769 EFI_STATUS Status;
1770 UINTN NumHandles;
1771 EFI_HANDLE *DriverHealthHandles;
1772 EFI_DRIVER_HEALTH_PROTOCOL *DriverHealth;
1773 EFI_DRIVER_HEALTH_STATUS HealthStatus;
1774 UINTN DriverHealthIndex;
1775 EFI_HANDLE *Handles;
1776 UINTN HandleCount;
1777 UINTN ControllerIndex;
1778 UINTN ChildIndex;
1779
1780 //
1781 // Initialize local variables
1782 //
1783 Handles = NULL;
1784 DriverHealthHandles = NULL;
1785 NumHandles = 0;
1786 HandleCount = 0;
1787
1788 HealthStatus = EfiDriverHealthStatusHealthy;
1789
1790 Status = gBS->LocateHandleBuffer (
1791 ByProtocol,
1792 &gEfiDriverHealthProtocolGuid,
1793 NULL,
1794 &NumHandles,
1795 &DriverHealthHandles
1796 );
1797
1798 if (Status == EFI_NOT_FOUND || NumHandles == 0) {
1799 //
1800 // If there are no Driver Health Protocols handles, then return EFI_NOT_FOUND
1801 //
1802 return EFI_NOT_FOUND;
1803 }
1804
1805 if (EFI_ERROR (Status) || DriverHealthHandles == NULL) {
1806 //
1807 // If the list of Driver Health Protocol handles can not be retrieved, then
1808 // return EFI_OUT_OF_RESOURCES
1809 //
1810 return EFI_OUT_OF_RESOURCES;
1811 }
1812
1813 //
1814 // Check the health status of all controllers in the platform
1815 // Start by looping through all the Driver Health Protocol handles in the handle database
1816 //
1817 for (DriverHealthIndex = 0; DriverHealthIndex < NumHandles; DriverHealthIndex++) {
1818 //
1819 // Skip NULL Driver Health Protocol handles
1820 //
1821 if (DriverHealthHandles[DriverHealthIndex] == NULL) {
1822 continue;
1823 }
1824
1825 //
1826 // Retrieve the Driver Health Protocol from DriverHandle
1827 //
1828 Status = gBS->HandleProtocol (
1829 DriverHealthHandles[DriverHealthIndex],
1830 &gEfiDriverHealthProtocolGuid,
1831 (VOID **)&DriverHealth
1832 );
1833 if (EFI_ERROR (Status)) {
1834 //
1835 // If the Driver Health Protocol can not be retrieved, then skip to the next
1836 // Driver Health Protocol handle
1837 //
1838 continue;
1839 }
1840
1841 //
1842 // Check the health of all the controllers managed by a Driver Health Protocol handle
1843 //
1844 Status = GetSingleControllerHealthStatus (DriverHealthList, DriverHealthHandles[DriverHealthIndex], NULL, NULL, DriverHealth, &HealthStatus);
1845
1846 //
1847 // If Status is an error code, then the health information could not be retrieved, so assume healthy
1848 // and skip to the next Driver Health Protocol handle
1849 //
1850 if (EFI_ERROR (Status)) {
1851 continue;
1852 }
1853
1854 //
1855 // If all the controllers managed by this Driver Health Protocol are healthy, then skip to the next
1856 // Driver Health Protocol handle
1857 //
1858 if (HealthStatus == EfiDriverHealthStatusHealthy) {
1859 continue;
1860 }
1861
1862 //
1863 // See if the list of all handles in the handle database has been retrieved
1864 //
1865 //
1866 if (Handles == NULL) {
1867 //
1868 // Retrieve the list of all handles from the handle database
1869 //
1870 Status = gBS->LocateHandleBuffer (
1871 AllHandles,
1872 NULL,
1873 NULL,
1874 &HandleCount,
1875 &Handles
1876 );
1877 if (EFI_ERROR (Status) || Handles == NULL) {
1878 //
1879 // If all the handles in the handle database can not be retrieved, then
1880 // return EFI_OUT_OF_RESOURCES
1881 //
1882 Status = EFI_OUT_OF_RESOURCES;
1883 goto Done;
1884 }
1885 }
1886 //
1887 // Loop through all the controller handles in the handle database
1888 //
1889 for (ControllerIndex = 0; ControllerIndex < HandleCount; ControllerIndex++) {
1890 //
1891 // Skip NULL controller handles
1892 //
1893 if (Handles[ControllerIndex] == NULL) {
1894 continue;
1895 }
1896
1897 Status = GetSingleControllerHealthStatus (DriverHealthList, DriverHealthHandles[DriverHealthIndex], Handles[ControllerIndex], NULL, DriverHealth, &HealthStatus);
1898 if (EFI_ERROR (Status)) {
1899 //
1900 // If Status is an error code, then the health information could not be retrieved, so assume healthy
1901 //
1902 HealthStatus = EfiDriverHealthStatusHealthy;
1903 }
1904
1905 //
1906 // If CheckHealthSingleController() returned an error on a terminal state, then do not check the health of child controllers
1907 //
1908 if (EFI_ERROR (Status)) {
1909 continue;
1910 }
1911
1912 //
1913 // Loop through all the child handles in the handle database
1914 //
1915 for (ChildIndex = 0; ChildIndex < HandleCount; ChildIndex++) {
1916 //
1917 // Skip NULL child handles
1918 //
1919 if (Handles[ChildIndex] == NULL) {
1920 continue;
1921 }
1922
1923 Status = GetSingleControllerHealthStatus (DriverHealthList, DriverHealthHandles[DriverHealthIndex], Handles[ControllerIndex], Handles[ChildIndex], DriverHealth, &HealthStatus);
1924 if (EFI_ERROR (Status)) {
1925 //
1926 // If Status is an error code, then the health information could not be retrieved, so assume healthy
1927 //
1928 HealthStatus = EfiDriverHealthStatusHealthy;
1929 }
1930
1931 //
1932 // If CheckHealthSingleController() returned an error on a terminal state, then skip to the next child
1933 //
1934 if (EFI_ERROR (Status)) {
1935 continue;
1936 }
1937 }
1938 }
1939 }
1940
1941 Status = EFI_SUCCESS;
1942
1943 Done:
1944 if (Handles != NULL) {
1945 gBS->FreePool (Handles);
1946 }
1947 if (DriverHealthHandles != NULL) {
1948 gBS->FreePool (DriverHealthHandles);
1949 }
1950
1951 return Status;
1952 }
1953
1954
1955 /**
1956 Check the healthy status of the platform, this function will return immediately while found one driver
1957 in the platform are not healthy.
1958
1959 @retval FALSE at least one driver in the platform are not healthy.
1960 @retval TRUE No controller install Driver Health Protocol,
1961 or all controllers in the platform are in healthy status.
1962 **/
1963 BOOLEAN
1964 PlaformHealthStatusCheck (
1965 VOID
1966 )
1967 {
1968 EFI_DRIVER_HEALTH_STATUS HealthStatus;
1969 EFI_STATUS Status;
1970 UINTN Index;
1971 UINTN NoHandles;
1972 EFI_HANDLE *DriverHealthHandles;
1973 EFI_DRIVER_HEALTH_PROTOCOL *DriverHealth;
1974 BOOLEAN AllHealthy;
1975
1976 //
1977 // Initialize local variables
1978 //
1979 DriverHealthHandles = NULL;
1980 DriverHealth = NULL;
1981
1982 HealthStatus = EfiDriverHealthStatusHealthy;
1983
1984 Status = gBS->LocateHandleBuffer (
1985 ByProtocol,
1986 &gEfiDriverHealthProtocolGuid,
1987 NULL,
1988 &NoHandles,
1989 &DriverHealthHandles
1990 );
1991 //
1992 // There are no handles match the search for Driver Health Protocol has been installed.
1993 //
1994 if (Status == EFI_NOT_FOUND) {
1995 return TRUE;
1996 }
1997 //
1998 // Assume all modules are healthy.
1999 //
2000 AllHealthy = TRUE;
2001
2002 //
2003 // Found one or more Handles.
2004 //
2005 if (!EFI_ERROR (Status)) {
2006 for (Index = 0; Index < NoHandles; Index++) {
2007 Status = gBS->HandleProtocol (
2008 DriverHealthHandles[Index],
2009 &gEfiDriverHealthProtocolGuid,
2010 (VOID **) &DriverHealth
2011 );
2012 if (!EFI_ERROR (Status)) {
2013 Status = DriverHealth->GetHealthStatus (
2014 DriverHealth,
2015 NULL,
2016 NULL,
2017 &HealthStatus,
2018 NULL,
2019 NULL
2020 );
2021 }
2022 //
2023 // Get the healthy status of the module
2024 //
2025 if (!EFI_ERROR (Status)) {
2026 if (HealthStatus != EfiDriverHealthStatusHealthy) {
2027 //
2028 // Return immediately one driver's status not in healthy.
2029 //
2030 return FALSE;
2031 }
2032 }
2033 }
2034 }
2035 return AllHealthy;
2036 }
2037
2038 /**
2039 Processes a single controller using the EFI Driver Health Protocol associated with
2040 that controller. This algorithm continues to query the GetHealthStatus() service until
2041 one of the legal terminal states of the EFI Driver Health Protocol is reached. This may
2042 require the processing of HII Messages, HII Form, and invocation of repair operations.
2043
2044 @param DriverHealth A pointer to the EFI_DRIVER_HEALTH_PROTOCOL instance.
2045 @param ControllerHandle The class guid specifies which form set will be displayed.
2046 @param ChildHandle The handle of the child controller to retrieve the health
2047 status on. This is an optional parameter that may be NULL.
2048 @param HealthStatus The health status of the controller.
2049 @param MessageList An array of warning or error messages associated
2050 with the controller specified by ControllerHandle and
2051 ChildHandle. This is an optional parameter that may be NULL.
2052 @param FormHiiHandle The HII handle for an HII form associated with the
2053 controller specified by ControllerHandle and ChildHandle.
2054 @param RebootRequired Indicate whether a reboot is required to repair the controller.
2055 **/
2056 VOID
2057 ProcessSingleControllerHealth (
2058 IN EFI_DRIVER_HEALTH_PROTOCOL *DriverHealth,
2059 IN EFI_HANDLE ControllerHandle, OPTIONAL
2060 IN EFI_HANDLE ChildHandle, OPTIONAL
2061 IN EFI_DRIVER_HEALTH_STATUS HealthStatus,
2062 IN EFI_DRIVER_HEALTH_HII_MESSAGE **MessageList, OPTIONAL
2063 IN EFI_HII_HANDLE FormHiiHandle,
2064 IN OUT BOOLEAN *RebootRequired
2065 )
2066 {
2067 EFI_STATUS Status;
2068 EFI_DRIVER_HEALTH_STATUS LocalHealthStatus;
2069
2070 LocalHealthStatus = HealthStatus;
2071 //
2072 // If the module need to be repaired or reconfiguration, will process it until
2073 // reach a terminal status. The status from EfiDriverHealthStatusRepairRequired after repair
2074 // will be in (Health, Failed, Configuration Required).
2075 //
2076 while(LocalHealthStatus == EfiDriverHealthStatusConfigurationRequired ||
2077 LocalHealthStatus == EfiDriverHealthStatusRepairRequired) {
2078
2079 if (LocalHealthStatus == EfiDriverHealthStatusRepairRequired) {
2080 Status = DriverHealth->Repair (
2081 DriverHealth,
2082 ControllerHandle,
2083 ChildHandle,
2084 RepairNotify
2085 );
2086 }
2087 //
2088 // Via a form of the driver need to do configuration provided to process of status in
2089 // EfiDriverHealthStatusConfigurationRequired. The status after configuration should be in
2090 // (Healthy, Reboot Required, Failed, Reconnect Required, Repair Required).
2091 //
2092 if (LocalHealthStatus == EfiDriverHealthStatusConfigurationRequired) {
2093 if (FormHiiHandle != NULL) {
2094 Status = gFormBrowser2->SendForm (
2095 gFormBrowser2,
2096 &FormHiiHandle,
2097 1,
2098 &gEfiHiiDriverHealthFormsetGuid,
2099 0,
2100 NULL,
2101 NULL
2102 );
2103 ASSERT( !EFI_ERROR (Status));
2104 } else {
2105 //
2106 // Exit the loop in case no FormHiiHandle is supplied to prevent dead-loop
2107 //
2108 break;
2109 }
2110 }
2111
2112 Status = DriverHealth->GetHealthStatus (
2113 DriverHealth,
2114 ControllerHandle,
2115 ChildHandle,
2116 &LocalHealthStatus,
2117 NULL,
2118 &FormHiiHandle
2119 );
2120 ASSERT_EFI_ERROR (Status);
2121
2122 if (*MessageList != NULL) {
2123 ProcessMessages (*MessageList);
2124 }
2125 }
2126
2127 //
2128 // Health status in {Healthy, Failed} may also have Messages need to process
2129 //
2130 if (LocalHealthStatus == EfiDriverHealthStatusHealthy || LocalHealthStatus == EfiDriverHealthStatusFailed) {
2131 if (*MessageList != NULL) {
2132 ProcessMessages (*MessageList);
2133 }
2134 }
2135 //
2136 // Check for RebootRequired or ReconnectRequired
2137 //
2138 if (LocalHealthStatus == EfiDriverHealthStatusRebootRequired) {
2139 *RebootRequired = TRUE;
2140 }
2141
2142 //
2143 // Do reconnect if need.
2144 //
2145 if (LocalHealthStatus == EfiDriverHealthStatusReconnectRequired) {
2146 Status = gBS->DisconnectController (ControllerHandle, NULL, NULL);
2147 if (EFI_ERROR (Status)) {
2148 //
2149 // Disconnect failed. Need to promote reconnect to a reboot.
2150 //
2151 *RebootRequired = TRUE;
2152 } else {
2153 gBS->ConnectController (ControllerHandle, NULL, NULL, TRUE);
2154 }
2155 }
2156 }
2157
2158
2159 /**
2160 Reports the progress of a repair operation.
2161
2162 @param[in] Value A value between 0 and Limit that identifies the current
2163 progress of the repair operation.
2164
2165 @param[in] Limit The maximum value of Value for the current repair operation.
2166 For example, a driver that wants to specify progress in
2167 percent would use a Limit value of 100.
2168
2169 @retval EFI_SUCCESS The progress of a repair operation is reported successfully.
2170
2171 **/
2172 EFI_STATUS
2173 EFIAPI
2174 RepairNotify (
2175 IN UINTN Value,
2176 IN UINTN Limit
2177 )
2178 {
2179 UINTN Percent;
2180
2181 if (Limit == 0) {
2182 Print(L"Repair Progress Undefined\n\r");
2183 } else {
2184 Percent = Value * 100 / Limit;
2185 Print(L"Repair Progress = %3d%%\n\r", Percent);
2186 }
2187 return EFI_SUCCESS;
2188 }
2189
2190 /**
2191 Processes a set of messages returned by the GetHealthStatus ()
2192 service of the EFI Driver Health Protocol
2193
2194 @param MessageList The MessageList point to messages need to processed.
2195
2196 **/
2197 VOID
2198 ProcessMessages (
2199 IN EFI_DRIVER_HEALTH_HII_MESSAGE *MessageList
2200 )
2201 {
2202 UINTN MessageIndex;
2203 EFI_STRING MessageString;
2204
2205 for (MessageIndex = 0;
2206 MessageList[MessageIndex].HiiHandle != NULL;
2207 MessageIndex++) {
2208
2209 MessageString = HiiGetString (
2210 MessageList[MessageIndex].HiiHandle,
2211 MessageList[MessageIndex].StringId,
2212 NULL
2213 );
2214 if (MessageString != NULL) {
2215 //
2216 // User can customize the output. Just simply print out the MessageString like below.
2217 // Also can use the HiiHandle to display message on the front page.
2218 //
2219 // Print(L"%s\n",MessageString);
2220 // gBS->Stall (100000);
2221 }
2222 }
2223
2224 }
2225
2226 /**
2227 Repair the whole platform.
2228
2229 This function is the main entry for user choose "Repair All" in the front page.
2230 It will try to do recovery job till all the driver health protocol installed modules
2231 reach a terminal state.
2232
2233 @param DriverHealthList A Pointer to the list contain all of the platform driver health
2234 information.
2235
2236 **/
2237 VOID
2238 PlatformRepairAll (
2239 IN LIST_ENTRY *DriverHealthList
2240 )
2241 {
2242 DRIVER_HEALTH_INFO *DriverHealthInfo;
2243 LIST_ENTRY *Link;
2244 BOOLEAN RebootRequired;
2245
2246 ASSERT (DriverHealthList != NULL);
2247
2248 RebootRequired = FALSE;
2249
2250 for ( Link = GetFirstNode (DriverHealthList)
2251 ; !IsNull (DriverHealthList, Link)
2252 ; Link = GetNextNode (DriverHealthList, Link)
2253 ) {
2254 DriverHealthInfo = DEVICE_MANAGER_HEALTH_INFO_FROM_LINK (Link);
2255 //
2256 // Do driver health status operation by each link node
2257 //
2258 ASSERT (DriverHealthInfo != NULL);
2259
2260 ProcessSingleControllerHealth (
2261 DriverHealthInfo->DriverHealth,
2262 DriverHealthInfo->ControllerHandle,
2263 DriverHealthInfo->ChildHandle,
2264 DriverHealthInfo->HealthStatus,
2265 &(DriverHealthInfo->MessageList),
2266 DriverHealthInfo->HiiHandle,
2267 &RebootRequired
2268 );
2269 }
2270
2271 if (RebootRequired) {
2272 gRT->ResetSystem (EfiResetWarm, EFI_SUCCESS, 0, NULL);
2273 }
2274 }
2275
2276 /**
2277
2278 Select the best matching language according to front page policy for best user experience.
2279
2280 This function supports both ISO 639-2 and RFC 4646 language codes, but language
2281 code types may not be mixed in a single call to this function.
2282
2283 @param SupportedLanguages A pointer to a Null-terminated ASCII string that
2284 contains a set of language codes in the format
2285 specified by Iso639Language.
2286 @param Iso639Language If TRUE, then all language codes are assumed to be
2287 in ISO 639-2 format. If FALSE, then all language
2288 codes are assumed to be in RFC 4646 language format.
2289
2290 @retval NULL The best matching language could not be found in SupportedLanguages.
2291 @retval NULL There are not enough resources available to return the best matching
2292 language.
2293 @retval Other A pointer to a Null-terminated ASCII string that is the best matching
2294 language in SupportedLanguages.
2295 **/
2296 CHAR8 *
2297 DriverHealthSelectBestLanguage (
2298 IN CHAR8 *SupportedLanguages,
2299 IN BOOLEAN Iso639Language
2300 )
2301 {
2302 CHAR8 *LanguageVariable;
2303 CHAR8 *BestLanguage;
2304
2305 GetEfiGlobalVariable2 (Iso639Language ? L"Lang" : L"PlatformLang", (VOID**)&LanguageVariable, NULL);
2306
2307 BestLanguage = GetBestLanguage(
2308 SupportedLanguages,
2309 Iso639Language,
2310 (LanguageVariable != NULL) ? LanguageVariable : "",
2311 Iso639Language ? "eng" : "en-US",
2312 NULL
2313 );
2314 if (LanguageVariable != NULL) {
2315 FreePool (LanguageVariable);
2316 }
2317
2318 return BestLanguage;
2319 }
2320
2321
2322
2323 /**
2324
2325 This is an internal worker function to get the Component Name (2) protocol interface
2326 and the language it supports.
2327
2328 @param ProtocolGuid A pointer to an EFI_GUID. It points to Component Name (2) protocol GUID.
2329 @param DriverBindingHandle The handle on which the Component Name (2) protocol instance is retrieved.
2330 @param ComponentName A pointer to the Component Name (2) protocol interface.
2331 @param SupportedLanguage The best suitable language that matches the SupportedLangues interface for the
2332 located Component Name (2) instance.
2333
2334 @retval EFI_SUCCESS The Component Name (2) protocol instance is successfully located and we find
2335 the best matching language it support.
2336 @retval EFI_UNSUPPORTED The input Language is not supported by the Component Name (2) protocol.
2337 @retval Other Some error occurs when locating Component Name (2) protocol instance or finding
2338 the supported language.
2339
2340 **/
2341 EFI_STATUS
2342 GetComponentNameWorker (
2343 IN EFI_GUID *ProtocolGuid,
2344 IN EFI_HANDLE DriverBindingHandle,
2345 OUT EFI_COMPONENT_NAME_PROTOCOL **ComponentName,
2346 OUT CHAR8 **SupportedLanguage
2347 )
2348 {
2349 EFI_STATUS Status;
2350
2351 //
2352 // Locate Component Name (2) protocol on the driver binging handle.
2353 //
2354 Status = gBS->OpenProtocol (
2355 DriverBindingHandle,
2356 ProtocolGuid,
2357 (VOID **) ComponentName,
2358 NULL,
2359 NULL,
2360 EFI_OPEN_PROTOCOL_GET_PROTOCOL
2361 );
2362 if (EFI_ERROR (Status)) {
2363 return Status;
2364 }
2365
2366 //
2367 // Apply shell policy to select the best language.
2368 //
2369 *SupportedLanguage = DriverHealthSelectBestLanguage (
2370 (*ComponentName)->SupportedLanguages,
2371 (BOOLEAN) (ProtocolGuid == &gEfiComponentNameProtocolGuid)
2372 );
2373 if (*SupportedLanguage == NULL) {
2374 Status = EFI_UNSUPPORTED;
2375 }
2376
2377 return Status;
2378 }
2379
2380 /**
2381
2382 This is an internal worker function to get driver name from Component Name (2) protocol interface.
2383
2384
2385 @param ProtocolGuid A pointer to an EFI_GUID. It points to Component Name (2) protocol GUID.
2386 @param DriverBindingHandle The handle on which the Component Name (2) protocol instance is retrieved.
2387 @param DriverName A pointer to the Unicode string to return. This Unicode string is the name
2388 of the driver specified by This.
2389
2390 @retval EFI_SUCCESS The driver name is successfully retrieved from Component Name (2) protocol
2391 interface.
2392 @retval Other The driver name cannot be retrieved from Component Name (2) protocol
2393 interface.
2394
2395 **/
2396 EFI_STATUS
2397 GetDriverNameWorker (
2398 IN EFI_GUID *ProtocolGuid,
2399 IN EFI_HANDLE DriverBindingHandle,
2400 OUT CHAR16 **DriverName
2401 )
2402 {
2403 EFI_STATUS Status;
2404 CHAR8 *BestLanguage;
2405 EFI_COMPONENT_NAME_PROTOCOL *ComponentName;
2406
2407 //
2408 // Retrieve Component Name (2) protocol instance on the driver binding handle and
2409 // find the best language this instance supports.
2410 //
2411 Status = GetComponentNameWorker (
2412 ProtocolGuid,
2413 DriverBindingHandle,
2414 &ComponentName,
2415 &BestLanguage
2416 );
2417 if (EFI_ERROR (Status)) {
2418 return Status;
2419 }
2420
2421 //
2422 // Get the driver name from Component Name (2) protocol instance on the driver binging handle.
2423 //
2424 Status = ComponentName->GetDriverName (
2425 ComponentName,
2426 BestLanguage,
2427 DriverName
2428 );
2429 FreePool (BestLanguage);
2430
2431 return Status;
2432 }
2433
2434 /**
2435
2436 This function gets driver name from Component Name 2 protocol interface and Component Name protocol interface
2437 in turn. It first tries UEFI 2.0 Component Name 2 protocol interface and try to get the driver name.
2438 If the attempt fails, it then gets the driver name from EFI 1.1 Component Name protocol for backward
2439 compatibility support.
2440
2441 @param DriverBindingHandle The handle on which the Component Name (2) protocol instance is retrieved.
2442 @param DriverName A pointer to the Unicode string to return. This Unicode string is the name
2443 of the driver specified by This.
2444
2445 @retval EFI_SUCCESS The driver name is successfully retrieved from Component Name (2) protocol
2446 interface.
2447 @retval Other The driver name cannot be retrieved from Component Name (2) protocol
2448 interface.
2449
2450 **/
2451 EFI_STATUS
2452 DriverHealthGetDriverName (
2453 IN EFI_HANDLE DriverBindingHandle,
2454 OUT CHAR16 **DriverName
2455 )
2456 {
2457 EFI_STATUS Status;
2458
2459 //
2460 // Get driver name from UEFI 2.0 Component Name 2 protocol interface.
2461 //
2462 Status = GetDriverNameWorker (&gEfiComponentName2ProtocolGuid, DriverBindingHandle, DriverName);
2463 if (EFI_ERROR (Status)) {
2464 //
2465 // If it fails to get the driver name from Component Name protocol interface, we should fall back on
2466 // EFI 1.1 Component Name protocol interface.
2467 //
2468 Status = GetDriverNameWorker (&gEfiComponentNameProtocolGuid, DriverBindingHandle, DriverName);
2469 }
2470
2471 return Status;
2472 }
2473
2474
2475
2476 /**
2477 This function gets controller name from Component Name 2 protocol interface and Component Name protocol interface
2478 in turn. It first tries UEFI 2.0 Component Name 2 protocol interface and try to get the controller name.
2479 If the attempt fails, it then gets the controller name from EFI 1.1 Component Name protocol for backward
2480 compatibility support.
2481
2482 @param ProtocolGuid A pointer to an EFI_GUID. It points to Component Name (2) protocol GUID.
2483 @param DriverBindingHandle The handle on which the Component Name (2) protocol instance is retrieved.
2484 @param ControllerHandle The handle of a controller that the driver specified by This is managing.
2485 This handle specifies the controller whose name is to be returned.
2486 @param ChildHandle The handle of the child controller to retrieve the name of. This is an
2487 optional parameter that may be NULL. It will be NULL for device drivers.
2488 It will also be NULL for bus drivers that attempt to retrieve the name
2489 of the bus controller. It will not be NULL for a bus driver that attempts
2490 to retrieve the name of a child controller.
2491 @param ControllerName A pointer to the Unicode string to return. This Unicode string
2492 is the name of the controller specified by ControllerHandle and ChildHandle.
2493
2494 @retval EFI_SUCCESS The controller name is successfully retrieved from Component Name (2) protocol
2495 interface.
2496 @retval Other The controller name cannot be retrieved from Component Name (2) protocol.
2497
2498 **/
2499 EFI_STATUS
2500 GetControllerNameWorker (
2501 IN EFI_GUID *ProtocolGuid,
2502 IN EFI_HANDLE DriverBindingHandle,
2503 IN EFI_HANDLE ControllerHandle,
2504 IN EFI_HANDLE ChildHandle,
2505 OUT CHAR16 **ControllerName
2506 )
2507 {
2508 EFI_STATUS Status;
2509 CHAR8 *BestLanguage;
2510 EFI_COMPONENT_NAME_PROTOCOL *ComponentName;
2511
2512 //
2513 // Retrieve Component Name (2) protocol instance on the driver binding handle and
2514 // find the best language this instance supports.
2515 //
2516 Status = GetComponentNameWorker (
2517 ProtocolGuid,
2518 DriverBindingHandle,
2519 &ComponentName,
2520 &BestLanguage
2521 );
2522 if (EFI_ERROR (Status)) {
2523 return Status;
2524 }
2525
2526 //
2527 // Get the controller name from Component Name (2) protocol instance on the driver binging handle.
2528 //
2529 Status = ComponentName->GetControllerName (
2530 ComponentName,
2531 ControllerHandle,
2532 ChildHandle,
2533 BestLanguage,
2534 ControllerName
2535 );
2536 FreePool (BestLanguage);
2537
2538 return Status;
2539 }
2540
2541 /**
2542
2543 This function gets controller name from Component Name 2 protocol interface and Component Name protocol interface
2544 in turn. It first tries UEFI 2.0 Component Name 2 protocol interface and try to get the controller name.
2545 If the attempt fails, it then gets the controller name from EFI 1.1 Component Name protocol for backward
2546 compatibility support.
2547
2548 @param DriverBindingHandle The handle on which the Component Name (2) protocol instance is retrieved.
2549 @param ControllerHandle The handle of a controller that the driver specified by This is managing.
2550 This handle specifies the controller whose name is to be returned.
2551 @param ChildHandle The handle of the child controller to retrieve the name of. This is an
2552 optional parameter that may be NULL. It will be NULL for device drivers.
2553 It will also be NULL for bus drivers that attempt to retrieve the name
2554 of the bus controller. It will not be NULL for a bus driver that attempts
2555 to retrieve the name of a child controller.
2556 @param ControllerName A pointer to the Unicode string to return. This Unicode string
2557 is the name of the controller specified by ControllerHandle and ChildHandle.
2558
2559 @retval EFI_SUCCESS The controller name is successfully retrieved from Component Name (2) protocol
2560 interface.
2561 @retval Other The controller name cannot be retrieved from Component Name (2) protocol.
2562
2563 **/
2564 EFI_STATUS
2565 DriverHealthGetControllerName (
2566 IN EFI_HANDLE DriverBindingHandle,
2567 IN EFI_HANDLE ControllerHandle,
2568 IN EFI_HANDLE ChildHandle,
2569 OUT CHAR16 **ControllerName
2570 )
2571 {
2572 EFI_STATUS Status;
2573
2574 //
2575 // Get controller name from UEFI 2.0 Component Name 2 protocol interface.
2576 //
2577 Status = GetControllerNameWorker (
2578 &gEfiComponentName2ProtocolGuid,
2579 DriverBindingHandle,
2580 ControllerHandle,
2581 ChildHandle,
2582 ControllerName
2583 );
2584 if (EFI_ERROR (Status)) {
2585 //
2586 // If it fails to get the controller name from Component Name protocol interface, we should fall back on
2587 // EFI 1.1 Component Name protocol interface.
2588 //
2589 Status = GetControllerNameWorker (
2590 &gEfiComponentNameProtocolGuid,
2591 DriverBindingHandle,
2592 ControllerHandle,
2593 ChildHandle,
2594 ControllerName
2595 );
2596 }
2597
2598 return Status;
2599 }