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