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