Add new interface GetVariable2 and GetEfiGlobalVariable2 to return more info. Also...
[mirror_edk2.git] / IntelFrameworkModulePkg / Universal / BdsDxe / DeviceMngr / DeviceManager.c
1 /** @file
2 The platform device manager reference implementation
3
4 Copyright (c) 2004 - 2012, 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 (EFI_DRIVER_HEALTH_REPAIR_PROGRESS_NOTIFY) 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 Platform specific notification function for controller repair operations.
2023
2024 If the driver for a controller support the Driver Health Protocol and the
2025 current state of the controller is EfiDriverHealthStatusRepairRequired then
2026 when the Repair() service of the Driver Health Protocol is called, this
2027 platform specific notification function can display the progress of the repair
2028 operation. Some platforms may choose to not display anything, other may choose
2029 to show the percentage complete on text consoles, and other may choose to render
2030 a progress bar on text and graphical consoles.
2031
2032 This function displays the percentage of the repair operation that has been
2033 completed on text consoles. The percentage is Value / Limit * 100%.
2034
2035 @param Value Value in the range 0..Limit the the repair has completed..
2036 @param Limit The maximum value of Value
2037
2038 **/
2039 VOID
2040 RepairNotify (
2041 IN UINTN Value,
2042 IN UINTN Limit
2043 )
2044 {
2045 UINTN Percent;
2046
2047 if (Limit == 0) {
2048 Print(L"Repair Progress Undefined\n\r");
2049 } else {
2050 Percent = Value * 100 / Limit;
2051 Print(L"Repair Progress = %3d%%\n\r", Percent);
2052 }
2053 }
2054
2055 /**
2056 Processes a set of messages returned by the GetHealthStatus ()
2057 service of the EFI Driver Health Protocol
2058
2059 @param MessageList The MessageList point to messages need to processed.
2060
2061 **/
2062 VOID
2063 ProcessMessages (
2064 IN EFI_DRIVER_HEALTH_HII_MESSAGE *MessageList
2065 )
2066 {
2067 UINTN MessageIndex;
2068 EFI_STRING MessageString;
2069
2070 for (MessageIndex = 0;
2071 MessageList[MessageIndex].HiiHandle != NULL;
2072 MessageIndex++) {
2073
2074 MessageString = HiiGetString (
2075 MessageList[MessageIndex].HiiHandle,
2076 MessageList[MessageIndex].StringId,
2077 NULL
2078 );
2079 if (MessageString != NULL) {
2080 //
2081 // User can customize the output. Just simply print out the MessageString like below.
2082 // Also can use the HiiHandle to display message on the front page.
2083 //
2084 // Print(L"%s\n",MessageString);
2085 // gBS->Stall (100000);
2086 }
2087 }
2088
2089 }
2090
2091 /**
2092 Repair the whole platform.
2093
2094 This function is the main entry for user choose "Repair All" in the front page.
2095 It will try to do recovery job till all the driver health protocol installed modules
2096 reach a terminal state.
2097
2098 @param DriverHealthList A Pointer to the list contain all of the platform driver health
2099 information.
2100
2101 **/
2102 VOID
2103 PlatformRepairAll (
2104 IN LIST_ENTRY *DriverHealthList
2105 )
2106 {
2107 DRIVER_HEALTH_INFO *DriverHealthInfo;
2108 LIST_ENTRY *Link;
2109 BOOLEAN RebootRequired;
2110
2111 ASSERT (DriverHealthList != NULL);
2112
2113 RebootRequired = FALSE;
2114
2115 for ( Link = GetFirstNode (DriverHealthList)
2116 ; !IsNull (DriverHealthList, Link)
2117 ; Link = GetNextNode (DriverHealthList, Link)
2118 ) {
2119 DriverHealthInfo = DEVICE_MANAGER_HEALTH_INFO_FROM_LINK (Link);
2120 //
2121 // Do driver health status operation by each link node
2122 //
2123 ASSERT (DriverHealthInfo != NULL);
2124
2125 ProcessSingleControllerHealth (
2126 DriverHealthInfo->DriverHealth,
2127 DriverHealthInfo->ControllerHandle,
2128 DriverHealthInfo->ChildHandle,
2129 DriverHealthInfo->HealthStatus,
2130 &(DriverHealthInfo->MessageList),
2131 DriverHealthInfo->HiiHandle,
2132 &RebootRequired
2133 );
2134 }
2135
2136 if (RebootRequired) {
2137 gRT->ResetSystem (EfiResetWarm, EFI_SUCCESS, 0, NULL);
2138 }
2139 }
2140
2141 /**
2142
2143 Select the best matching language according to front page policy for best user experience.
2144
2145 This function supports both ISO 639-2 and RFC 4646 language codes, but language
2146 code types may not be mixed in a single call to this function.
2147
2148 @param SupportedLanguages A pointer to a Null-terminated ASCII string that
2149 contains a set of language codes in the format
2150 specified by Iso639Language.
2151 @param Iso639Language If TRUE, then all language codes are assumed to be
2152 in ISO 639-2 format. If FALSE, then all language
2153 codes are assumed to be in RFC 4646 language format.
2154
2155 @retval NULL The best matching language could not be found in SupportedLanguages.
2156 @retval NULL There are not enough resources available to return the best matching
2157 language.
2158 @retval Other A pointer to a Null-terminated ASCII string that is the best matching
2159 language in SupportedLanguages.
2160 **/
2161 CHAR8 *
2162 DriverHealthSelectBestLanguage (
2163 IN CHAR8 *SupportedLanguages,
2164 IN BOOLEAN Iso639Language
2165 )
2166 {
2167 CHAR8 *LanguageVariable;
2168 CHAR8 *BestLanguage;
2169
2170 GetEfiGlobalVariable2 (Iso639Language ? L"Lang" : L"PlatformLang", &LanguageVariable, NULL);
2171
2172 BestLanguage = GetBestLanguage(
2173 SupportedLanguages,
2174 Iso639Language,
2175 (LanguageVariable != NULL) ? LanguageVariable : "",
2176 Iso639Language ? "eng" : "en-US",
2177 NULL
2178 );
2179 if (LanguageVariable != NULL) {
2180 FreePool (LanguageVariable);
2181 }
2182
2183 return BestLanguage;
2184 }
2185
2186
2187
2188 /**
2189
2190 This is an internal worker function to get the Component Name (2) protocol interface
2191 and the language it supports.
2192
2193 @param ProtocolGuid A pointer to an EFI_GUID. It points to Component Name (2) protocol GUID.
2194 @param DriverBindingHandle The handle on which the Component Name (2) protocol instance is retrieved.
2195 @param ComponentName A pointer to the Component Name (2) protocol interface.
2196 @param SupportedLanguage The best suitable language that matches the SupportedLangues interface for the
2197 located Component Name (2) instance.
2198
2199 @retval EFI_SUCCESS The Component Name (2) protocol instance is successfully located and we find
2200 the best matching language it support.
2201 @retval EFI_UNSUPPORTED The input Language is not supported by the Component Name (2) protocol.
2202 @retval Other Some error occurs when locating Component Name (2) protocol instance or finding
2203 the supported language.
2204
2205 **/
2206 EFI_STATUS
2207 GetComponentNameWorker (
2208 IN EFI_GUID *ProtocolGuid,
2209 IN EFI_HANDLE DriverBindingHandle,
2210 OUT EFI_COMPONENT_NAME_PROTOCOL **ComponentName,
2211 OUT CHAR8 **SupportedLanguage
2212 )
2213 {
2214 EFI_STATUS Status;
2215
2216 //
2217 // Locate Component Name (2) protocol on the driver binging handle.
2218 //
2219 Status = gBS->OpenProtocol (
2220 DriverBindingHandle,
2221 ProtocolGuid,
2222 (VOID **) ComponentName,
2223 NULL,
2224 NULL,
2225 EFI_OPEN_PROTOCOL_GET_PROTOCOL
2226 );
2227 if (EFI_ERROR (Status)) {
2228 return Status;
2229 }
2230
2231 //
2232 // Apply shell policy to select the best language.
2233 //
2234 *SupportedLanguage = DriverHealthSelectBestLanguage (
2235 (*ComponentName)->SupportedLanguages,
2236 (BOOLEAN) (ProtocolGuid == &gEfiComponentNameProtocolGuid)
2237 );
2238 if (*SupportedLanguage == NULL) {
2239 Status = EFI_UNSUPPORTED;
2240 }
2241
2242 return Status;
2243 }
2244
2245 /**
2246
2247 This is an internal worker function to get driver name from Component Name (2) protocol interface.
2248
2249
2250 @param ProtocolGuid A pointer to an EFI_GUID. It points to Component Name (2) protocol GUID.
2251 @param DriverBindingHandle The handle on which the Component Name (2) protocol instance is retrieved.
2252 @param DriverName A pointer to the Unicode string to return. This Unicode string is the name
2253 of the driver specified by This.
2254
2255 @retval EFI_SUCCESS The driver name is successfully retrieved from Component Name (2) protocol
2256 interface.
2257 @retval Other The driver name cannot be retrieved from Component Name (2) protocol
2258 interface.
2259
2260 **/
2261 EFI_STATUS
2262 GetDriverNameWorker (
2263 IN EFI_GUID *ProtocolGuid,
2264 IN EFI_HANDLE DriverBindingHandle,
2265 OUT CHAR16 **DriverName
2266 )
2267 {
2268 EFI_STATUS Status;
2269 CHAR8 *BestLanguage;
2270 EFI_COMPONENT_NAME_PROTOCOL *ComponentName;
2271
2272 //
2273 // Retrieve Component Name (2) protocol instance on the driver binding handle and
2274 // find the best language this instance supports.
2275 //
2276 Status = GetComponentNameWorker (
2277 ProtocolGuid,
2278 DriverBindingHandle,
2279 &ComponentName,
2280 &BestLanguage
2281 );
2282 if (EFI_ERROR (Status)) {
2283 return Status;
2284 }
2285
2286 //
2287 // Get the driver name from Component Name (2) protocol instance on the driver binging handle.
2288 //
2289 Status = ComponentName->GetDriverName (
2290 ComponentName,
2291 BestLanguage,
2292 DriverName
2293 );
2294 FreePool (BestLanguage);
2295
2296 return Status;
2297 }
2298
2299 /**
2300
2301 This function gets driver name from Component Name 2 protocol interface and Component Name protocol interface
2302 in turn. It first tries UEFI 2.0 Component Name 2 protocol interface and try to get the driver name.
2303 If the attempt fails, it then gets the driver name from EFI 1.1 Component Name protocol for backward
2304 compatibility support.
2305
2306 @param DriverBindingHandle The handle on which the Component Name (2) protocol instance is retrieved.
2307 @param DriverName A pointer to the Unicode string to return. This Unicode string is the name
2308 of the driver specified by This.
2309
2310 @retval EFI_SUCCESS The driver name is successfully retrieved from Component Name (2) protocol
2311 interface.
2312 @retval Other The driver name cannot be retrieved from Component Name (2) protocol
2313 interface.
2314
2315 **/
2316 EFI_STATUS
2317 DriverHealthGetDriverName (
2318 IN EFI_HANDLE DriverBindingHandle,
2319 OUT CHAR16 **DriverName
2320 )
2321 {
2322 EFI_STATUS Status;
2323
2324 //
2325 // Get driver name from UEFI 2.0 Component Name 2 protocol interface.
2326 //
2327 Status = GetDriverNameWorker (&gEfiComponentName2ProtocolGuid, DriverBindingHandle, DriverName);
2328 if (EFI_ERROR (Status)) {
2329 //
2330 // If it fails to get the driver name from Component Name protocol interface, we should fall back on
2331 // EFI 1.1 Component Name protocol interface.
2332 //
2333 Status = GetDriverNameWorker (&gEfiComponentNameProtocolGuid, DriverBindingHandle, DriverName);
2334 }
2335
2336 return Status;
2337 }
2338
2339
2340
2341 /**
2342 This function gets controller name from Component Name 2 protocol interface and Component Name protocol interface
2343 in turn. It first tries UEFI 2.0 Component Name 2 protocol interface and try to get the controller name.
2344 If the attempt fails, it then gets the controller name from EFI 1.1 Component Name protocol for backward
2345 compatibility support.
2346
2347 @param ProtocolGuid A pointer to an EFI_GUID. It points to Component Name (2) protocol GUID.
2348 @param DriverBindingHandle The handle on which the Component Name (2) protocol instance is retrieved.
2349 @param ControllerHandle The handle of a controller that the driver specified by This is managing.
2350 This handle specifies the controller whose name is to be returned.
2351 @param ChildHandle The handle of the child controller to retrieve the name of. This is an
2352 optional parameter that may be NULL. It will be NULL for device drivers.
2353 It will also be NULL for bus drivers that attempt to retrieve the name
2354 of the bus controller. It will not be NULL for a bus driver that attempts
2355 to retrieve the name of a child controller.
2356 @param ControllerName A pointer to the Unicode string to return. This Unicode string
2357 is the name of the controller specified by ControllerHandle and ChildHandle.
2358
2359 @retval EFI_SUCCESS The controller name is successfully retrieved from Component Name (2) protocol
2360 interface.
2361 @retval Other The controller name cannot be retrieved from Component Name (2) protocol.
2362
2363 **/
2364 EFI_STATUS
2365 GetControllerNameWorker (
2366 IN EFI_GUID *ProtocolGuid,
2367 IN EFI_HANDLE DriverBindingHandle,
2368 IN EFI_HANDLE ControllerHandle,
2369 IN EFI_HANDLE ChildHandle,
2370 OUT CHAR16 **ControllerName
2371 )
2372 {
2373 EFI_STATUS Status;
2374 CHAR8 *BestLanguage;
2375 EFI_COMPONENT_NAME_PROTOCOL *ComponentName;
2376
2377 //
2378 // Retrieve Component Name (2) protocol instance on the driver binding handle and
2379 // find the best language this instance supports.
2380 //
2381 Status = GetComponentNameWorker (
2382 ProtocolGuid,
2383 DriverBindingHandle,
2384 &ComponentName,
2385 &BestLanguage
2386 );
2387 if (EFI_ERROR (Status)) {
2388 return Status;
2389 }
2390
2391 //
2392 // Get the controller name from Component Name (2) protocol instance on the driver binging handle.
2393 //
2394 Status = ComponentName->GetControllerName (
2395 ComponentName,
2396 ControllerHandle,
2397 ChildHandle,
2398 BestLanguage,
2399 ControllerName
2400 );
2401 FreePool (BestLanguage);
2402
2403 return Status;
2404 }
2405
2406 /**
2407
2408 This function gets controller name from Component Name 2 protocol interface and Component Name protocol interface
2409 in turn. It first tries UEFI 2.0 Component Name 2 protocol interface and try to get the controller name.
2410 If the attempt fails, it then gets the controller name from EFI 1.1 Component Name protocol for backward
2411 compatibility support.
2412
2413 @param DriverBindingHandle The handle on which the Component Name (2) protocol instance is retrieved.
2414 @param ControllerHandle The handle of a controller that the driver specified by This is managing.
2415 This handle specifies the controller whose name is to be returned.
2416 @param ChildHandle The handle of the child controller to retrieve the name of. This is an
2417 optional parameter that may be NULL. It will be NULL for device drivers.
2418 It will also be NULL for bus drivers that attempt to retrieve the name
2419 of the bus controller. It will not be NULL for a bus driver that attempts
2420 to retrieve the name of a child controller.
2421 @param ControllerName A pointer to the Unicode string to return. This Unicode string
2422 is the name of the controller specified by ControllerHandle and ChildHandle.
2423
2424 @retval EFI_SUCCESS The controller name is successfully retrieved from Component Name (2) protocol
2425 interface.
2426 @retval Other The controller name cannot be retrieved from Component Name (2) protocol.
2427
2428 **/
2429 EFI_STATUS
2430 DriverHealthGetControllerName (
2431 IN EFI_HANDLE DriverBindingHandle,
2432 IN EFI_HANDLE ControllerHandle,
2433 IN EFI_HANDLE ChildHandle,
2434 OUT CHAR16 **ControllerName
2435 )
2436 {
2437 EFI_STATUS Status;
2438
2439 //
2440 // Get controller name from UEFI 2.0 Component Name 2 protocol interface.
2441 //
2442 Status = GetControllerNameWorker (
2443 &gEfiComponentName2ProtocolGuid,
2444 DriverBindingHandle,
2445 ControllerHandle,
2446 ChildHandle,
2447 ControllerName
2448 );
2449 if (EFI_ERROR (Status)) {
2450 //
2451 // If it fails to get the controller name from Component Name protocol interface, we should fall back on
2452 // EFI 1.1 Component Name protocol interface.
2453 //
2454 Status = GetControllerNameWorker (
2455 &gEfiComponentNameProtocolGuid,
2456 DriverBindingHandle,
2457 ControllerHandle,
2458 ChildHandle,
2459 ControllerName
2460 );
2461 }
2462
2463 return Status;
2464 }