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