Home | History | Annotate | Download | only in DeviceMngr
      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
    125 DeviceManagerCallback (
    126   IN  CONST EFI_HII_CONFIG_ACCESS_PROTOCOL   *This,
    127   IN  EFI_BROWSER_ACTION                     Action,
    128   IN  EFI_QUESTION_ID                        QuestionId,
    129   IN  UINT8                                  Type,
    130   IN  EFI_IFR_TYPE_VALUE                     *Value,
    131   OUT EFI_BROWSER_ACTION_REQUEST             *ActionRequest
    132   )
    133 {
    134   UINTN CurIndex;
    135 
    136   if (Action != EFI_BROWSER_ACTION_CHANGING) {
    137     //
    138     // All other action return unsupported.
    139     //
    140     return EFI_UNSUPPORTED;
    141   }
    142 
    143   if (Value == NULL) {
    144     return EFI_INVALID_PARAMETER;
    145   }
    146 
    147   gCallbackKey = QuestionId;
    148   if ((QuestionId < MAX_KEY_SECTION_LEN + NETWORK_DEVICE_LIST_KEY_OFFSET) && (QuestionId >= NETWORK_DEVICE_LIST_KEY_OFFSET)) {
    149     //
    150     // If user select the mac address, need to record mac address string to support next form show.
    151     //
    152     for (CurIndex = 0; CurIndex < mMacDeviceList.CurListLen; CurIndex ++) {
    153       if (mMacDeviceList.NodeList[CurIndex].QuestionId == QuestionId) {
    154          mSelectedMacAddrString = HiiGetString (gDeviceManagerPrivate.HiiHandle, mMacDeviceList.NodeList[CurIndex].PromptId, NULL);
    155       }
    156     }
    157   }
    158 
    159   return EFI_SUCCESS;
    160 }
    161 
    162 /**
    163 
    164   This function registers HII packages to HII database.
    165 
    166   @retval  EFI_SUCCESS           HII packages for the Device Manager were registered successfully.
    167   @retval  EFI_OUT_OF_RESOURCES  HII packages for the Device Manager failed to be registered.
    168 
    169 **/
    170 EFI_STATUS
    171 InitializeDeviceManager (
    172   VOID
    173   )
    174 {
    175   EFI_STATUS                  Status;
    176 
    177   //
    178   // Install Device Path Protocol and Config Access protocol to driver handle
    179   //
    180   Status = gBS->InstallMultipleProtocolInterfaces (
    181                   &gDeviceManagerPrivate.DriverHandle,
    182                   &gEfiDevicePathProtocolGuid,
    183                   &mDeviceManagerHiiVendorDevicePath,
    184                   &gEfiHiiConfigAccessProtocolGuid,
    185                   &gDeviceManagerPrivate.ConfigAccess,
    186                   NULL
    187                   );
    188   ASSERT_EFI_ERROR (Status);
    189 
    190   Status = gBS->InstallMultipleProtocolInterfaces (
    191                   &gDeviceManagerPrivate.DriverHealthHandle,
    192                   &gEfiDevicePathProtocolGuid,
    193                   &mDriverHealthHiiVendorDevicePath,
    194                   &gEfiHiiConfigAccessProtocolGuid,
    195                   &gDeviceManagerPrivate.DriverHealthConfigAccess,
    196                   NULL
    197                   );
    198   ASSERT_EFI_ERROR (Status);
    199 
    200   mMacDeviceList.CurListLen = 0;
    201   mMacDeviceList.MaxListLen = 0;
    202 
    203   return Status;
    204 }
    205 
    206 /**
    207   Extract the displayed formset for given HII handle and class guid.
    208 
    209   @param Handle          The HII handle.
    210   @param SetupClassGuid  The class guid specifies which form set will be displayed.
    211   @param 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
    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
    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
    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
    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
    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
    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
    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
    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
   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
   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
   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
   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
   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
   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
   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
   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
   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 *
   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
   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
   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
   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
   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
   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