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