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