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