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