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