Home | History | Annotate | Download | only in LegacyBootManagerLib
      1 /** @file
      2   This function deal with the legacy boot option, it create, delete
      3   and manage the legacy boot option, all legacy boot option is getting from
      4   the legacy BBS table.
      5 
      6 Copyright (c) 2011 - 2016, Intel Corporation. All rights reserved.<BR>
      7 This program and the accompanying materials
      8 are licensed and made available under the terms and conditions of the BSD License
      9 which accompanies this distribution.  The full text of the license may be found at
     10 http://opensource.org/licenses/bsd-license.php
     11 
     12 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     13 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     14 
     15 **/
     16 
     17 #include "InternalLegacyBm.h"
     18 
     19 #define  LEGACY_BM_BOOT_DESCRIPTION_LENGTH  32
     20 
     21 /**
     22   Initialize legacy boot manager library by call EfiBootManagerRegisterLegacyBootSupport
     23   function to export two function pointer.
     24 
     25   @param ImageHandle     The image handle.
     26   @param SystemTable     The system table.
     27 
     28   @retval EFI_SUCCESS    The legacy boot manager library is initialized correctly.
     29   @return Other value if failed to initialize the legacy boot manager library.
     30 **/
     31 EFI_STATUS
     32 EFIAPI
     33 LegacyBootManagerLibConstructor (
     34   IN EFI_HANDLE                            ImageHandle,
     35   IN EFI_SYSTEM_TABLE                      *SystemTable
     36 )
     37 {
     38   EfiBootManagerRegisterLegacyBootSupport (
     39     LegacyBmRefreshAllBootOption,
     40     LegacyBmBoot
     41     );
     42   return EFI_SUCCESS;
     43 }
     44 
     45 /**
     46   Get the device type from the input legacy device path.
     47 
     48   @param DevicePath     The legacy device path.
     49 
     50   @retval               The legacy device type.
     51 **/
     52 UINT16
     53 LegacyBmDeviceType (
     54   EFI_DEVICE_PATH_PROTOCOL *DevicePath
     55   )
     56 {
     57   ASSERT ((DevicePathType (DevicePath) == BBS_DEVICE_PATH) &&
     58           (DevicePathSubType (DevicePath) == BBS_BBS_DP));
     59   return ((BBS_BBS_DEVICE_PATH *) DevicePath)->DeviceType;
     60 }
     61 
     62 /**
     63   Validate the BbsEntry base on the Boot Priority info in the BbsEntry.
     64 
     65   @param BbsEntry       The input bbs entry info.
     66 
     67   @retval TRUE          The BbsEntry is valid.
     68   @retval FALSE         The BbsEntry is invalid.
     69 **/
     70 BOOLEAN
     71 LegacyBmValidBbsEntry (
     72   IN BBS_TABLE   *BbsEntry
     73   )
     74 {
     75   switch (BbsEntry->BootPriority) {
     76     case BBS_IGNORE_ENTRY:
     77     case BBS_DO_NOT_BOOT_FROM:
     78     case BBS_LOWEST_PRIORITY:
     79       return FALSE;
     80     default:
     81       return TRUE;
     82   }
     83 }
     84 
     85 /**
     86   Build Legacy Device Name String according.
     87 
     88   @param CurBBSEntry     BBS Table.
     89   @param Index           Index.
     90   @param BufSize         The buffer size.
     91   @param BootString      The output string.
     92 
     93 **/
     94 VOID
     95 LegacyBmBuildLegacyDevNameString (
     96   IN  BBS_TABLE                 *CurBBSEntry,
     97   IN  UINTN                     Index,
     98   IN  UINTN                     BufSize,
     99   OUT CHAR16                    *BootString
    100   )
    101 {
    102   CHAR16  *Fmt;
    103   CHAR16  *Type;
    104   CHAR8   *StringDesc;
    105   CHAR8   StringBufferA[LEGACY_BM_BOOT_DESCRIPTION_LENGTH + 1];
    106   CHAR16  StringBufferU[LEGACY_BM_BOOT_DESCRIPTION_LENGTH + 1];
    107 
    108   switch (Index) {
    109   //
    110   // Primary Master
    111   //
    112   case 1:
    113     Fmt = L"Primary Master %s";
    114     break;
    115 
    116  //
    117  // Primary Slave
    118  //
    119   case 2:
    120     Fmt = L"Primary Slave %s";
    121     break;
    122 
    123   //
    124   // Secondary Master
    125   //
    126   case 3:
    127     Fmt = L"Secondary Master %s";
    128     break;
    129 
    130   //
    131   // Secondary Slave
    132   //
    133   case 4:
    134     Fmt = L"Secondary Slave %s";
    135     break;
    136 
    137   default:
    138     Fmt = L"%s";
    139     break;
    140   }
    141 
    142   switch (CurBBSEntry->DeviceType) {
    143   case BBS_FLOPPY:
    144     Type = L"Floppy";
    145     break;
    146 
    147   case BBS_HARDDISK:
    148     Type = L"Harddisk";
    149     break;
    150 
    151   case BBS_CDROM:
    152     Type = L"CDROM";
    153     break;
    154 
    155   case BBS_PCMCIA:
    156     Type = L"PCMCIAe";
    157     break;
    158 
    159   case BBS_USB:
    160     Type = L"USB";
    161     break;
    162 
    163   case BBS_EMBED_NETWORK:
    164     Type = L"Network";
    165     break;
    166 
    167   case BBS_BEV_DEVICE:
    168     Type = L"BEVe";
    169     break;
    170 
    171   case BBS_UNKNOWN:
    172   default:
    173     Type = L"Unknown";
    174     break;
    175   }
    176   //
    177   // If current BBS entry has its description then use it.
    178   //
    179   StringDesc = (CHAR8 *) (UINTN) ((CurBBSEntry->DescStringSegment << 4) + CurBBSEntry->DescStringOffset);
    180   if (NULL != StringDesc) {
    181     //
    182     // Only get fisrt 32 characters, this is suggested by BBS spec
    183     //
    184     CopyMem (StringBufferA, StringDesc, LEGACY_BM_BOOT_DESCRIPTION_LENGTH);
    185     StringBufferA[LEGACY_BM_BOOT_DESCRIPTION_LENGTH] = 0;
    186     AsciiStrToUnicodeStrS (StringBufferA, StringBufferU, ARRAY_SIZE (StringBufferU));
    187     Fmt   = L"%s";
    188     Type  = StringBufferU;
    189   }
    190 
    191   //
    192   // BbsTable 16 entries are for onboard IDE.
    193   // Set description string for SATA harddisks, Harddisk 0 ~ Harddisk 11
    194   //
    195   if (Index >= 5 && Index <= 16 && (CurBBSEntry->DeviceType == BBS_HARDDISK || CurBBSEntry->DeviceType == BBS_CDROM)) {
    196     Fmt = L"%s %d";
    197     UnicodeSPrint (BootString, BufSize, Fmt, Type, Index - 5);
    198   } else {
    199     UnicodeSPrint (BootString, BufSize, Fmt, Type);
    200   }
    201 }
    202 
    203 /**
    204   Get the Bbs index for the input boot option.
    205 
    206   @param BootOption     The input boot option info.
    207   @param BbsTable       The input Bbs table.
    208   @param BbsCount       The input total bbs entry number.
    209   @param BbsIndexUsed   The array shows how many BBS table indexs have been used.
    210 
    211   @retval The index for the input boot option.
    212 **/
    213 UINT16
    214 LegacyBmFuzzyMatch (
    215   EFI_BOOT_MANAGER_LOAD_OPTION   *BootOption,
    216   BBS_TABLE                      *BbsTable,
    217   UINT16                         BbsCount,
    218   BOOLEAN                        *BbsIndexUsed
    219   )
    220 {
    221   UINT16                         Index;
    222   LEGACY_BM_BOOT_OPTION_BBS_DATA *BbsData;
    223   CHAR16                         Description[LEGACY_BM_BOOT_DESCRIPTION_LENGTH + 1];
    224 
    225   BbsData = (LEGACY_BM_BOOT_OPTION_BBS_DATA *) BootOption->OptionalData;
    226 
    227   //
    228   // Directly check the BBS index stored in BootOption
    229   //
    230   if ((BbsData->BbsIndex < BbsCount) &&
    231       (LegacyBmDeviceType (BootOption->FilePath) == BbsTable[BbsData->BbsIndex].DeviceType)) {
    232     LegacyBmBuildLegacyDevNameString (
    233       &BbsTable[BbsData->BbsIndex],
    234       BbsData->BbsIndex,
    235       sizeof (Description),
    236       Description
    237       );
    238     if ((StrCmp (Description, BootOption->Description) == 0) && !BbsIndexUsed[BbsData->BbsIndex]) {
    239       //
    240       // If devices with the same description string are connected,
    241       // the BbsIndex of the first device is returned for the other device also.
    242       // So, check if the BbsIndex is already being used, before assigning the BbsIndex.
    243       //
    244       BbsIndexUsed[BbsData->BbsIndex] = TRUE;
    245       return BbsData->BbsIndex;
    246     }
    247   }
    248 
    249   //
    250   // BBS table could be changed (entry removed/moved)
    251   // find the correct BBS index
    252   //
    253   for (Index = 0; Index < BbsCount; Index++) {
    254     if (!LegacyBmValidBbsEntry (&BbsTable[Index]) ||
    255         (BbsTable[Index].DeviceType != LegacyBmDeviceType (BootOption->FilePath))) {
    256       continue;
    257     }
    258 
    259     LegacyBmBuildLegacyDevNameString (
    260       &BbsTable[Index],
    261       Index,
    262       sizeof (Description),
    263       Description
    264       );
    265     if ((StrCmp (Description, BootOption->Description) == 0) && !BbsIndexUsed[Index]) {
    266       //
    267       // If devices with the same description string are connected,
    268       // the BbsIndex of the first device is assigned for the other device also.
    269       // So, check if the BbsIndex is already being used, before assigning the corrected BbsIndex.
    270       //
    271       break;
    272     }
    273   }
    274 
    275   //
    276   // Add the corrected BbsIndex in the UsedBbsIndex Buffer
    277   //
    278   if (Index != BbsCount) {
    279     BbsIndexUsed[Index] = TRUE;
    280   }
    281 
    282   return Index;
    283 }
    284 
    285 /**
    286 
    287   Update legacy device order base on the input info.
    288 
    289   @param   LegacyDevOrder     Legacy device order data buffer.
    290   @param   LegacyDevOrderSize Legacy device order data buffer size.
    291   @param   DeviceType         Device type which need to check.
    292   @param   OldBbsIndex        Old Bds Index.
    293   @param   NewBbsIndex        New Bds Index, if it is -1,means remove this option.
    294 
    295 **/
    296 VOID
    297 LegacyBmUpdateBbsIndex (
    298   LEGACY_DEV_ORDER_ENTRY   *LegacyDevOrder,
    299   UINTN                    *LegacyDevOrderSize,
    300   UINT16                   DeviceType,
    301   UINT16                   OldBbsIndex,
    302   UINT16                   NewBbsIndex // Delete entry if -1
    303   )
    304 {
    305   LEGACY_DEV_ORDER_ENTRY   *Entry;
    306   UINTN                    Index;
    307 
    308   ASSERT (((LegacyDevOrder == NULL) && (*LegacyDevOrderSize == 0)) ||
    309           ((LegacyDevOrder != NULL) && (*LegacyDevOrderSize != 0))
    310          );
    311 
    312   for (Entry = LegacyDevOrder;
    313        Entry < (LEGACY_DEV_ORDER_ENTRY *) ((UINT8 *) LegacyDevOrder + *LegacyDevOrderSize);
    314        Entry = (LEGACY_DEV_ORDER_ENTRY *) ((UINTN) Entry + sizeof (BBS_TYPE) + Entry->Length)
    315        ) {
    316     if (Entry->BbsType == DeviceType) {
    317       for (Index = 0; Index < Entry->Length / sizeof (UINT16) - 1; Index++) {
    318         if (Entry->Data[Index] == OldBbsIndex) {
    319           if (NewBbsIndex == (UINT16) -1) {
    320             //
    321             // Delete the old entry
    322             //
    323             CopyMem (
    324               &Entry->Data[Index],
    325               &Entry->Data[Index + 1],
    326               (UINT8 *) LegacyDevOrder + *LegacyDevOrderSize - (UINT8 *) &Entry->Data[Index + 1]
    327               );
    328             Entry->Length       -= sizeof (UINT16);
    329             *LegacyDevOrderSize -= sizeof(UINT16);
    330           } else {
    331             Entry->Data[Index]   = NewBbsIndex;
    332           }
    333           break;
    334         }
    335       }
    336       break;
    337     }
    338   }
    339 }
    340 
    341 /**
    342   Delete all the legacy boot options.
    343 
    344   @retval EFI_SUCCESS            All legacy boot options are deleted.
    345 **/
    346 EFI_STATUS
    347 LegacyBmDeleteAllBootOptions (
    348   VOID
    349   )
    350 {
    351   EFI_STATUS                    Status;
    352   UINTN                         Index;
    353   EFI_BOOT_MANAGER_LOAD_OPTION  *BootOption;
    354   UINTN                         BootOptionCount;
    355 
    356   BootOption = EfiBootManagerGetLoadOptions (&BootOptionCount, LoadOptionTypeBoot);
    357   for (Index = 0; Index < BootOptionCount; Index++) {
    358     if ((DevicePathType (BootOption[Index].FilePath) == BBS_DEVICE_PATH) &&
    359         (DevicePathSubType (BootOption[Index].FilePath) == BBS_BBS_DP)) {
    360       Status = EfiBootManagerDeleteLoadOptionVariable (BootOption[Index].OptionNumber, BootOption[Index].OptionType);
    361       //
    362       // Deleting variable with current variable implementation shouldn't fail.
    363       //
    364       ASSERT_EFI_ERROR (Status);
    365     }
    366   }
    367 
    368   Status = gRT->SetVariable (
    369                   VAR_LEGACY_DEV_ORDER,
    370                   &gEfiLegacyDevOrderVariableGuid,
    371                   0,
    372                   0,
    373                   NULL
    374                   );
    375   //
    376   // Deleting variable with current variable implementation shouldn't fail.
    377   //
    378   ASSERT (Status == EFI_SUCCESS || Status == EFI_NOT_FOUND);
    379 
    380   return EFI_SUCCESS;
    381 }
    382 
    383 
    384 /**
    385   Delete all the invalid legacy boot options.
    386 
    387   @retval EFI_SUCCESS             All invalide legacy boot options are deleted.
    388   @retval EFI_OUT_OF_RESOURCES    Fail to allocate necessary memory.
    389   @retval EFI_NOT_FOUND           Fail to retrive variable of boot order.
    390 **/
    391 EFI_STATUS
    392 LegacyBmDeleteAllInvalidBootOptions (
    393   VOID
    394   )
    395 {
    396   EFI_STATUS                    Status;
    397   UINT16                        HddCount;
    398   UINT16                        BbsCount;
    399   HDD_INFO                      *HddInfo;
    400   BBS_TABLE                     *BbsTable;
    401   UINT16                        BbsIndex;
    402   EFI_LEGACY_BIOS_PROTOCOL      *LegacyBios;
    403   UINTN                         Index;
    404   EFI_BOOT_MANAGER_LOAD_OPTION  *BootOption;
    405   UINTN                         BootOptionCount;
    406   LEGACY_DEV_ORDER_ENTRY        *LegacyDevOrder;
    407   UINTN                         LegacyDevOrderSize;
    408   BOOLEAN                       *BbsIndexUsed;
    409 
    410   HddCount      = 0;
    411   BbsCount      = 0;
    412   HddInfo       = NULL;
    413   BbsTable      = NULL;
    414 
    415   Status        = gBS->LocateProtocol (&gEfiLegacyBiosProtocolGuid, NULL, (VOID **) &LegacyBios);
    416   if (EFI_ERROR (Status)) {
    417     return Status;
    418   }
    419 
    420   Status = LegacyBios->GetBbsInfo (
    421                          LegacyBios,
    422                          &HddCount,
    423                          &HddInfo,
    424                          &BbsCount,
    425                          &BbsTable
    426                          );
    427   if (EFI_ERROR (Status)) {
    428     return Status;
    429   }
    430 
    431   GetVariable2 (VAR_LEGACY_DEV_ORDER, &gEfiLegacyDevOrderVariableGuid, (VOID **) &LegacyDevOrder, &LegacyDevOrderSize);
    432 
    433   BootOption = EfiBootManagerGetLoadOptions (&BootOptionCount, LoadOptionTypeBoot);
    434 
    435   BbsIndexUsed = AllocateZeroPool (BbsCount * sizeof (BOOLEAN));
    436   ASSERT (BbsIndexUsed != NULL);
    437 
    438   for (Index = 0; Index < BootOptionCount; Index++) {
    439     //
    440     // Skip non legacy boot option
    441     //
    442     if ((DevicePathType (BootOption[Index].FilePath) != BBS_DEVICE_PATH) ||
    443         (DevicePathSubType (BootOption[Index].FilePath) != BBS_BBS_DP)) {
    444       continue;
    445     }
    446 
    447     BbsIndex = LegacyBmFuzzyMatch (&BootOption[Index], BbsTable, BbsCount, BbsIndexUsed);
    448     if (BbsIndex == BbsCount) {
    449       DEBUG ((EFI_D_INFO, "[LegacyBds] Delete Boot Option Boot%04x: %s\n", (UINTN) BootOption[Index].OptionNumber, BootOption[Index].Description));
    450       //
    451       // Delete entry from LegacyDevOrder
    452       //
    453       LegacyBmUpdateBbsIndex (
    454         LegacyDevOrder,
    455         &LegacyDevOrderSize,
    456         LegacyBmDeviceType (BootOption[Index].FilePath),
    457         ((LEGACY_BM_BOOT_OPTION_BBS_DATA *) BootOption[Index].OptionalData)->BbsIndex,
    458         (UINT16) -1
    459         );
    460       EfiBootManagerDeleteLoadOptionVariable (BootOption[Index].OptionNumber, BootOption[Index].OptionType);
    461     } else {
    462       if (((LEGACY_BM_BOOT_OPTION_BBS_DATA *) BootOption[Index].OptionalData)->BbsIndex != BbsIndex) {
    463         DEBUG ((EFI_D_INFO, "[LegacyBds] Update Boot Option Boot%04x: %s Bbs0x%04x->Bbs0x%04x\n", (UINTN) BootOption[Index].OptionNumber, BootOption[Index].Description,
    464                 (UINTN) ((LEGACY_BM_BOOT_OPTION_BBS_DATA *) BootOption[Index].OptionalData)->BbsIndex, (UINTN) BbsIndex));
    465         //
    466         // Update the BBS index in LegacyDevOrder
    467         //
    468         LegacyBmUpdateBbsIndex (
    469           LegacyDevOrder,
    470           &LegacyDevOrderSize,
    471           LegacyBmDeviceType (BootOption[Index].FilePath),
    472           ((LEGACY_BM_BOOT_OPTION_BBS_DATA *) BootOption[Index].OptionalData)->BbsIndex,
    473           BbsIndex
    474           );
    475 
    476         //
    477         // Update the OptionalData in the Boot#### variable
    478         //
    479         ((LEGACY_BM_BOOT_OPTION_BBS_DATA *) BootOption[Index].OptionalData)->BbsIndex = BbsIndex;
    480         EfiBootManagerLoadOptionToVariable (&BootOption[Index]);
    481       }
    482     }
    483   }
    484   EfiBootManagerFreeLoadOptions (BootOption, BootOptionCount);
    485 
    486   if (LegacyDevOrder != NULL) {
    487     Status = gRT->SetVariable (
    488                     VAR_LEGACY_DEV_ORDER,
    489                     &gEfiLegacyDevOrderVariableGuid,
    490                     EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE,
    491                     LegacyDevOrderSize,
    492                     LegacyDevOrder
    493                     );
    494     //
    495     // Shrink variable with current variable implementation shouldn't fail.
    496     //
    497     ASSERT_EFI_ERROR (Status);
    498 
    499     FreePool (LegacyDevOrder);
    500   }
    501   FreePool(BbsIndexUsed);
    502   return Status;
    503 }
    504 
    505 /**
    506   Create legacy boot option.
    507 
    508   @param BootOption        Ponter to the boot option which will be crated.
    509   @param BbsEntry          The input bbs entry info.
    510   @param BbsIndex          The BBS index.
    511 
    512   @retval EFI_SUCCESS            Create legacy boot option successfully.
    513   @retval EFI_INVALID_PARAMETER  Invalid input parameter.
    514 
    515 **/
    516 EFI_STATUS
    517 LegacyBmCreateLegacyBootOption (
    518   IN OUT EFI_BOOT_MANAGER_LOAD_OPTION  *BootOption,
    519   IN BBS_TABLE                         *BbsEntry,
    520   IN UINT16                            BbsIndex
    521   )
    522 {
    523   EFI_STATUS                   Status;
    524   EFI_DEVICE_PATH_PROTOCOL     *DevicePath;
    525   CHAR16                       Description[LEGACY_BM_BOOT_DESCRIPTION_LENGTH + 1];
    526   CHAR8                        HelpString[LEGACY_BM_BOOT_DESCRIPTION_LENGTH + 1];
    527   UINTN                        StringLen;
    528   LEGACY_BM_BOOT_OPTION_BBS_DATA  *OptionalData;
    529   BBS_BBS_DEVICE_PATH          *BbsNode;
    530 
    531   if ((BootOption == NULL) || (BbsEntry == NULL)) {
    532     return EFI_INVALID_PARAMETER;
    533   }
    534 
    535   LegacyBmBuildLegacyDevNameString (BbsEntry, BbsIndex, sizeof (Description), Description);
    536 
    537   //
    538   // Create the BBS device path with description string
    539   //
    540   UnicodeStrToAsciiStrS (Description, HelpString, sizeof (HelpString));
    541   StringLen = AsciiStrLen (HelpString);
    542   DevicePath = AllocatePool (sizeof (BBS_BBS_DEVICE_PATH) + StringLen + END_DEVICE_PATH_LENGTH);
    543   ASSERT (DevicePath != NULL);
    544 
    545   BbsNode = (BBS_BBS_DEVICE_PATH *) DevicePath;
    546   SetDevicePathNodeLength (BbsNode, sizeof (BBS_BBS_DEVICE_PATH) + StringLen);
    547   BbsNode->Header.Type    = BBS_DEVICE_PATH;
    548   BbsNode->Header.SubType = BBS_BBS_DP;
    549   BbsNode->DeviceType     = BbsEntry->DeviceType;
    550   CopyMem (&BbsNode->StatusFlag, &BbsEntry->StatusFlags, sizeof (BBS_STATUS_FLAGS));
    551   CopyMem (BbsNode->String, HelpString, StringLen + 1);
    552 
    553   SetDevicePathEndNode (NextDevicePathNode (BbsNode));
    554 
    555   //
    556   // Create the OptionalData
    557   //
    558   OptionalData = AllocatePool (sizeof (LEGACY_BM_BOOT_OPTION_BBS_DATA));
    559   ASSERT (OptionalData != NULL);
    560   OptionalData->BbsIndex = BbsIndex;
    561 
    562   //
    563   // Create the BootOption
    564   //
    565   Status = EfiBootManagerInitializeLoadOption (
    566              BootOption,
    567              LoadOptionNumberUnassigned,
    568              LoadOptionTypeBoot,
    569              LOAD_OPTION_ACTIVE,
    570              Description,
    571              DevicePath,
    572              (UINT8 *) OptionalData,
    573              sizeof (LEGACY_BM_BOOT_OPTION_BBS_DATA)
    574              );
    575   FreePool (DevicePath);
    576   FreePool (OptionalData);
    577 
    578   return Status;
    579 }
    580 
    581 /**
    582   Fill the device order buffer.
    583 
    584   @param BbsTable        The BBS table.
    585   @param BbsType         The BBS Type.
    586   @param BbsCount        The BBS Count.
    587   @param Buf             device order buffer.
    588 
    589   @return The device order buffer.
    590 
    591 **/
    592 UINT16 *
    593 LegacyBmFillDevOrderBuf (
    594   IN BBS_TABLE                    *BbsTable,
    595   IN BBS_TYPE                     BbsType,
    596   IN UINTN                        BbsCount,
    597   OUT UINT16                      *Buf
    598   )
    599 {
    600   UINTN Index;
    601 
    602   for (Index = 0; Index < BbsCount; Index++) {
    603     if (!LegacyBmValidBbsEntry (&BbsTable[Index])) {
    604       continue;
    605     }
    606 
    607     if (BbsTable[Index].DeviceType != BbsType) {
    608       continue;
    609     }
    610 
    611     *Buf = (UINT16) (Index & 0xFF);
    612     Buf++;
    613   }
    614 
    615   return Buf;
    616 }
    617 
    618 /**
    619   Create the device order buffer.
    620 
    621   @param BbsTable        The BBS table.
    622   @param BbsCount        The BBS Count.
    623 
    624   @retval EFI_SUCCES             The buffer is created and the EFI variable named
    625                                  VAR_LEGACY_DEV_ORDER and EfiLegacyDevOrderGuid is
    626                                  set correctly.
    627   @retval EFI_OUT_OF_RESOURCES   Memmory or storage is not enough.
    628   @retval EFI_DEVICE_ERROR       Fail to add the device order into EFI variable fail
    629                                  because of hardware error.
    630 **/
    631 EFI_STATUS
    632 LegacyBmCreateDevOrder (
    633   IN BBS_TABLE                  *BbsTable,
    634   IN UINT16                     BbsCount
    635   )
    636 {
    637   UINTN                       Index;
    638   UINTN                       FDCount;
    639   UINTN                       HDCount;
    640   UINTN                       CDCount;
    641   UINTN                       NETCount;
    642   UINTN                       BEVCount;
    643   UINTN                       TotalSize;
    644   UINTN                       HeaderSize;
    645   LEGACY_DEV_ORDER_ENTRY      *DevOrder;
    646   LEGACY_DEV_ORDER_ENTRY      *DevOrderPtr;
    647   EFI_STATUS                  Status;
    648 
    649   FDCount     = 0;
    650   HDCount     = 0;
    651   CDCount     = 0;
    652   NETCount    = 0;
    653   BEVCount    = 0;
    654   TotalSize   = 0;
    655   HeaderSize  = sizeof (BBS_TYPE) + sizeof (UINT16);
    656   DevOrder    = NULL;
    657   Status      = EFI_SUCCESS;
    658 
    659   //
    660   // Count all boot devices
    661   //
    662   for (Index = 0; Index < BbsCount; Index++) {
    663     if (!LegacyBmValidBbsEntry (&BbsTable[Index])) {
    664       continue;
    665     }
    666 
    667     switch (BbsTable[Index].DeviceType) {
    668     case BBS_FLOPPY:
    669       FDCount++;
    670       break;
    671 
    672     case BBS_HARDDISK:
    673       HDCount++;
    674       break;
    675 
    676     case BBS_CDROM:
    677       CDCount++;
    678       break;
    679 
    680     case BBS_EMBED_NETWORK:
    681       NETCount++;
    682       break;
    683 
    684     case BBS_BEV_DEVICE:
    685       BEVCount++;
    686       break;
    687 
    688     default:
    689       break;
    690     }
    691   }
    692 
    693   TotalSize += (HeaderSize + sizeof (UINT16) * FDCount);
    694   TotalSize += (HeaderSize + sizeof (UINT16) * HDCount);
    695   TotalSize += (HeaderSize + sizeof (UINT16) * CDCount);
    696   TotalSize += (HeaderSize + sizeof (UINT16) * NETCount);
    697   TotalSize += (HeaderSize + sizeof (UINT16) * BEVCount);
    698 
    699   //
    700   // Create buffer to hold all boot device order
    701   //
    702   DevOrder = AllocateZeroPool (TotalSize);
    703   if (NULL == DevOrder) {
    704     return EFI_OUT_OF_RESOURCES;
    705   }
    706   DevOrderPtr          = DevOrder;
    707 
    708   DevOrderPtr->BbsType = BBS_FLOPPY;
    709   DevOrderPtr->Length  = (UINT16) (sizeof (DevOrderPtr->Length) + FDCount * sizeof (UINT16));
    710   DevOrderPtr          = (LEGACY_DEV_ORDER_ENTRY *) LegacyBmFillDevOrderBuf (BbsTable, BBS_FLOPPY, BbsCount, DevOrderPtr->Data);
    711 
    712   DevOrderPtr->BbsType = BBS_HARDDISK;
    713   DevOrderPtr->Length  = (UINT16) (sizeof (UINT16) + HDCount * sizeof (UINT16));
    714   DevOrderPtr          = (LEGACY_DEV_ORDER_ENTRY *) LegacyBmFillDevOrderBuf (BbsTable, BBS_HARDDISK, BbsCount, DevOrderPtr->Data);
    715 
    716   DevOrderPtr->BbsType = BBS_CDROM;
    717   DevOrderPtr->Length  = (UINT16) (sizeof (UINT16) + CDCount * sizeof (UINT16));
    718   DevOrderPtr          = (LEGACY_DEV_ORDER_ENTRY *) LegacyBmFillDevOrderBuf (BbsTable, BBS_CDROM, BbsCount, DevOrderPtr->Data);
    719 
    720   DevOrderPtr->BbsType = BBS_EMBED_NETWORK;
    721   DevOrderPtr->Length  = (UINT16) (sizeof (UINT16) + NETCount * sizeof (UINT16));
    722   DevOrderPtr          = (LEGACY_DEV_ORDER_ENTRY *) LegacyBmFillDevOrderBuf (BbsTable, BBS_EMBED_NETWORK, BbsCount, DevOrderPtr->Data);
    723 
    724   DevOrderPtr->BbsType = BBS_BEV_DEVICE;
    725   DevOrderPtr->Length  = (UINT16) (sizeof (UINT16) + BEVCount * sizeof (UINT16));
    726   DevOrderPtr          = (LEGACY_DEV_ORDER_ENTRY *) LegacyBmFillDevOrderBuf (BbsTable, BBS_BEV_DEVICE, BbsCount, DevOrderPtr->Data);
    727 
    728   ASSERT (TotalSize == (UINTN) ((UINT8 *) DevOrderPtr - (UINT8 *) DevOrder));
    729 
    730   //
    731   // Save device order for legacy boot device to variable.
    732   //
    733   Status = gRT->SetVariable (
    734                   VAR_LEGACY_DEV_ORDER,
    735                   &gEfiLegacyDevOrderVariableGuid,
    736                   EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE,
    737                   TotalSize,
    738                   DevOrder
    739                   );
    740   FreePool (DevOrder);
    741 
    742   return Status;
    743 }
    744 
    745 /**
    746   Add the legacy boot devices from BBS table into
    747   the legacy device boot order.
    748 
    749   @retval EFI_SUCCESS           The boot devices are added successfully.
    750   @retval EFI_NOT_FOUND         The legacy boot devices are not found.
    751   @retval EFI_OUT_OF_RESOURCES  Memmory or storage is not enough.
    752   @retval EFI_DEVICE_ERROR      Fail to add the legacy device boot order into EFI variable
    753                                 because of hardware error.
    754 **/
    755 EFI_STATUS
    756 LegacyBmUpdateDevOrder (
    757   VOID
    758   )
    759 {
    760   LEGACY_DEV_ORDER_ENTRY      *DevOrder;
    761   LEGACY_DEV_ORDER_ENTRY      *NewDevOrder;
    762   LEGACY_DEV_ORDER_ENTRY      *Ptr;
    763   LEGACY_DEV_ORDER_ENTRY      *NewPtr;
    764   EFI_LEGACY_BIOS_PROTOCOL    *LegacyBios;
    765   EFI_STATUS                  Status;
    766   UINT16                      HddCount;
    767   UINT16                      BbsCount;
    768   HDD_INFO                    *LocalHddInfo;
    769   BBS_TABLE                   *LocalBbsTable;
    770   UINTN                       Index;
    771   UINTN                       Index2;
    772   UINTN                       *Idx;
    773   UINTN                       FDCount;
    774   UINTN                       HDCount;
    775   UINTN                       CDCount;
    776   UINTN                       NETCount;
    777   UINTN                       BEVCount;
    778   UINTN                       TotalSize;
    779   UINTN                       HeaderSize;
    780   UINT16                      *NewFDPtr;
    781   UINT16                      *NewHDPtr;
    782   UINT16                      *NewCDPtr;
    783   UINT16                      *NewNETPtr;
    784   UINT16                      *NewBEVPtr;
    785   UINT16                      *NewDevPtr;
    786   UINTN                       FDIndex;
    787   UINTN                       HDIndex;
    788   UINTN                       CDIndex;
    789   UINTN                       NETIndex;
    790   UINTN                       BEVIndex;
    791 
    792   Idx           = NULL;
    793   FDCount       = 0;
    794   HDCount       = 0;
    795   CDCount       = 0;
    796   NETCount      = 0;
    797   BEVCount      = 0;
    798   TotalSize     = 0;
    799   HeaderSize    = sizeof (BBS_TYPE) + sizeof (UINT16);
    800   FDIndex       = 0;
    801   HDIndex       = 0;
    802   CDIndex       = 0;
    803   NETIndex      = 0;
    804   BEVIndex      = 0;
    805   NewDevPtr     = NULL;
    806 
    807   Status        = gBS->LocateProtocol (&gEfiLegacyBiosProtocolGuid, NULL, (VOID **) &LegacyBios);
    808   if (EFI_ERROR (Status)) {
    809     return Status;
    810   }
    811 
    812   Status = LegacyBios->GetBbsInfo (
    813                          LegacyBios,
    814                          &HddCount,
    815                          &LocalHddInfo,
    816                          &BbsCount,
    817                          &LocalBbsTable
    818                          );
    819   if (EFI_ERROR (Status)) {
    820     return Status;
    821   }
    822 
    823   GetVariable2 (VAR_LEGACY_DEV_ORDER, &gEfiLegacyDevOrderVariableGuid, (VOID **) &DevOrder, NULL);
    824   if (NULL == DevOrder) {
    825     return LegacyBmCreateDevOrder (LocalBbsTable, BbsCount);
    826   }
    827   //
    828   // First we figure out how many boot devices with same device type respectively
    829   //
    830   for (Index = 0; Index < BbsCount; Index++) {
    831     if (!LegacyBmValidBbsEntry (&LocalBbsTable[Index])) {
    832       continue;
    833     }
    834 
    835     switch (LocalBbsTable[Index].DeviceType) {
    836     case BBS_FLOPPY:
    837       FDCount++;
    838       break;
    839 
    840     case BBS_HARDDISK:
    841       HDCount++;
    842       break;
    843 
    844     case BBS_CDROM:
    845       CDCount++;
    846       break;
    847 
    848     case BBS_EMBED_NETWORK:
    849       NETCount++;
    850       break;
    851 
    852     case BBS_BEV_DEVICE:
    853       BEVCount++;
    854       break;
    855 
    856     default:
    857       break;
    858     }
    859   }
    860 
    861   TotalSize += (HeaderSize + FDCount * sizeof (UINT16));
    862   TotalSize += (HeaderSize + HDCount * sizeof (UINT16));
    863   TotalSize += (HeaderSize + CDCount * sizeof (UINT16));
    864   TotalSize += (HeaderSize + NETCount * sizeof (UINT16));
    865   TotalSize += (HeaderSize + BEVCount * sizeof (UINT16));
    866 
    867   NewDevOrder = AllocateZeroPool (TotalSize);
    868   if (NULL == NewDevOrder) {
    869     return EFI_OUT_OF_RESOURCES;
    870   }
    871 
    872   //
    873   // copy FD
    874   //
    875   Ptr             = DevOrder;
    876   NewPtr          = NewDevOrder;
    877   NewPtr->BbsType = Ptr->BbsType;
    878   NewPtr->Length  = (UINT16) (sizeof (UINT16) + FDCount * sizeof (UINT16));
    879   for (Index = 0; Index < Ptr->Length / sizeof (UINT16) - 1; Index++) {
    880     if (!LegacyBmValidBbsEntry (&LocalBbsTable[Ptr->Data[Index] & 0xFF]) ||
    881         LocalBbsTable[Ptr->Data[Index] & 0xFF].DeviceType != BBS_FLOPPY
    882         ) {
    883       continue;
    884     }
    885 
    886     NewPtr->Data[FDIndex] = Ptr->Data[Index];
    887     FDIndex++;
    888   }
    889   NewFDPtr = NewPtr->Data;
    890 
    891   //
    892   // copy HD
    893   //
    894   Ptr             = (LEGACY_DEV_ORDER_ENTRY *) (&Ptr->Data[Ptr->Length / sizeof (UINT16) - 1]);
    895   NewPtr          = (LEGACY_DEV_ORDER_ENTRY *) (&NewPtr->Data[NewPtr->Length / sizeof (UINT16) -1]);
    896   NewPtr->BbsType = Ptr->BbsType;
    897   NewPtr->Length  = (UINT16) (sizeof (UINT16) + HDCount * sizeof (UINT16));
    898   for (Index = 0; Index < Ptr->Length / sizeof (UINT16) - 1; Index++) {
    899     if (!LegacyBmValidBbsEntry (&LocalBbsTable[Ptr->Data[Index] & 0xFF]) ||
    900         LocalBbsTable[Ptr->Data[Index] & 0xFF].DeviceType != BBS_HARDDISK
    901         ) {
    902       continue;
    903     }
    904 
    905     NewPtr->Data[HDIndex] = Ptr->Data[Index];
    906     HDIndex++;
    907   }
    908   NewHDPtr = NewPtr->Data;
    909 
    910   //
    911   // copy CD
    912   //
    913   Ptr    = (LEGACY_DEV_ORDER_ENTRY *) (&Ptr->Data[Ptr->Length / sizeof (UINT16) - 1]);
    914   NewPtr = (LEGACY_DEV_ORDER_ENTRY *) (&NewPtr->Data[NewPtr->Length / sizeof (UINT16) -1]);
    915   NewPtr->BbsType = Ptr->BbsType;
    916   NewPtr->Length  = (UINT16) (sizeof (UINT16) + CDCount * sizeof (UINT16));
    917   for (Index = 0; Index < Ptr->Length / sizeof (UINT16) - 1; Index++) {
    918     if (!LegacyBmValidBbsEntry (&LocalBbsTable[Ptr->Data[Index] & 0xFF]) ||
    919         LocalBbsTable[Ptr->Data[Index] & 0xFF].DeviceType != BBS_CDROM
    920         ) {
    921       continue;
    922     }
    923 
    924     NewPtr->Data[CDIndex] = Ptr->Data[Index];
    925     CDIndex++;
    926   }
    927   NewCDPtr = NewPtr->Data;
    928 
    929   //
    930   // copy NET
    931   //
    932   Ptr    = (LEGACY_DEV_ORDER_ENTRY *) (&Ptr->Data[Ptr->Length / sizeof (UINT16) - 1]);
    933   NewPtr = (LEGACY_DEV_ORDER_ENTRY *) (&NewPtr->Data[NewPtr->Length / sizeof (UINT16) -1]);
    934   NewPtr->BbsType = Ptr->BbsType;
    935   NewPtr->Length  = (UINT16) (sizeof (UINT16) + NETCount * sizeof (UINT16));
    936   for (Index = 0; Index < Ptr->Length / sizeof (UINT16) - 1; Index++) {
    937     if (!LegacyBmValidBbsEntry (&LocalBbsTable[Ptr->Data[Index] & 0xFF]) ||
    938         LocalBbsTable[Ptr->Data[Index] & 0xFF].DeviceType != BBS_EMBED_NETWORK
    939         ) {
    940       continue;
    941     }
    942 
    943     NewPtr->Data[NETIndex] = Ptr->Data[Index];
    944     NETIndex++;
    945   }
    946   NewNETPtr = NewPtr->Data;
    947 
    948   //
    949   // copy BEV
    950   //
    951   Ptr    = (LEGACY_DEV_ORDER_ENTRY *) (&Ptr->Data[Ptr->Length / sizeof (UINT16) - 1]);
    952   NewPtr = (LEGACY_DEV_ORDER_ENTRY *) (&NewPtr->Data[NewPtr->Length / sizeof (UINT16) -1]);
    953   NewPtr->BbsType = Ptr->BbsType;
    954   NewPtr->Length  = (UINT16) (sizeof (UINT16) + BEVCount * sizeof (UINT16));
    955   for (Index = 0; Index < Ptr->Length / sizeof (UINT16) - 1; Index++) {
    956     if (!LegacyBmValidBbsEntry (&LocalBbsTable[Ptr->Data[Index] & 0xFF]) ||
    957         LocalBbsTable[Ptr->Data[Index] & 0xFF].DeviceType != BBS_BEV_DEVICE
    958         ) {
    959       continue;
    960     }
    961 
    962     NewPtr->Data[BEVIndex] = Ptr->Data[Index];
    963     BEVIndex++;
    964   }
    965   NewBEVPtr = NewPtr->Data;
    966 
    967   for (Index = 0; Index < BbsCount; Index++) {
    968     if (!LegacyBmValidBbsEntry (&LocalBbsTable[Index])) {
    969       continue;
    970     }
    971 
    972     switch (LocalBbsTable[Index].DeviceType) {
    973     case BBS_FLOPPY:
    974       Idx       = &FDIndex;
    975       NewDevPtr = NewFDPtr;
    976       break;
    977 
    978     case BBS_HARDDISK:
    979       Idx       = &HDIndex;
    980       NewDevPtr = NewHDPtr;
    981       break;
    982 
    983     case BBS_CDROM:
    984       Idx       = &CDIndex;
    985       NewDevPtr = NewCDPtr;
    986       break;
    987 
    988     case BBS_EMBED_NETWORK:
    989       Idx       = &NETIndex;
    990       NewDevPtr = NewNETPtr;
    991       break;
    992 
    993     case BBS_BEV_DEVICE:
    994       Idx       = &BEVIndex;
    995       NewDevPtr = NewBEVPtr;
    996       break;
    997 
    998     default:
    999       Idx = NULL;
   1000       break;
   1001     }
   1002     //
   1003     // at this point we have copied those valid indexes to new buffer
   1004     // and we should check if there is any new appeared boot device
   1005     //
   1006     if (Idx != NULL) {
   1007       for (Index2 = 0; Index2 < *Idx; Index2++) {
   1008         if ((NewDevPtr[Index2] & 0xFF) == (UINT16) Index) {
   1009           break;
   1010         }
   1011       }
   1012 
   1013       if (Index2 == *Idx) {
   1014         //
   1015         // Index2 == *Idx means we didn't find Index
   1016         // so Index is a new appeared device's index in BBS table
   1017         // insert it before disabled indexes.
   1018         //
   1019         for (Index2 = 0; Index2 < *Idx; Index2++) {
   1020           if ((NewDevPtr[Index2] & 0xFF00) == 0xFF00) {
   1021             break;
   1022           }
   1023         }
   1024         CopyMem (&NewDevPtr[Index2 + 1], &NewDevPtr[Index2], (*Idx - Index2) * sizeof (UINT16));
   1025         NewDevPtr[Index2] = (UINT16) (Index & 0xFF);
   1026         (*Idx)++;
   1027       }
   1028     }
   1029   }
   1030 
   1031   FreePool (DevOrder);
   1032 
   1033   Status = gRT->SetVariable (
   1034                   VAR_LEGACY_DEV_ORDER,
   1035                   &gEfiLegacyDevOrderVariableGuid,
   1036                   EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE,
   1037                   TotalSize,
   1038                   NewDevOrder
   1039                   );
   1040   FreePool (NewDevOrder);
   1041 
   1042   return Status;
   1043 }
   1044 
   1045 /**
   1046   Set Boot Priority for specified device type.
   1047 
   1048   @param DeviceType      The device type.
   1049   @param BbsIndex        The BBS index to set the highest priority. Ignore when -1.
   1050   @param LocalBbsTable   The BBS table.
   1051   @param Priority        The prority table.
   1052 
   1053   @retval EFI_SUCCESS           The function completes successfully.
   1054   @retval EFI_NOT_FOUND         Failed to find device.
   1055   @retval EFI_OUT_OF_RESOURCES  Failed to get the efi variable of device order.
   1056 
   1057 **/
   1058 EFI_STATUS
   1059 LegacyBmSetPriorityForSameTypeDev (
   1060   IN UINT16                                              DeviceType,
   1061   IN UINTN                                               BbsIndex,
   1062   IN OUT BBS_TABLE                                       *LocalBbsTable,
   1063   IN OUT UINT16                                          *Priority
   1064   )
   1065 {
   1066   LEGACY_DEV_ORDER_ENTRY      *DevOrder;
   1067   LEGACY_DEV_ORDER_ENTRY      *DevOrderPtr;
   1068   UINTN                       DevOrderSize;
   1069   UINTN                       Index;
   1070 
   1071   GetVariable2 (VAR_LEGACY_DEV_ORDER, &gEfiLegacyDevOrderVariableGuid, (VOID **) &DevOrder, &DevOrderSize);
   1072   if (NULL == DevOrder) {
   1073     return EFI_OUT_OF_RESOURCES;
   1074   }
   1075 
   1076   DevOrderPtr = DevOrder;
   1077   while ((UINT8 *) DevOrderPtr < (UINT8 *) DevOrder + DevOrderSize) {
   1078     if (DevOrderPtr->BbsType == DeviceType) {
   1079       break;
   1080     }
   1081 
   1082     DevOrderPtr = (LEGACY_DEV_ORDER_ENTRY *) ((UINTN) DevOrderPtr + sizeof (BBS_TYPE) + DevOrderPtr->Length);
   1083   }
   1084 
   1085   if ((UINT8 *) DevOrderPtr >= (UINT8 *) DevOrder + DevOrderSize) {
   1086     FreePool (DevOrder);
   1087     return EFI_NOT_FOUND;
   1088   }
   1089 
   1090   if (BbsIndex != (UINTN) -1) {
   1091     //
   1092     // In case the BBS entry isn't valid because devices were plugged or removed.
   1093     //
   1094     if (!LegacyBmValidBbsEntry (&LocalBbsTable[BbsIndex]) || (LocalBbsTable[BbsIndex].DeviceType != DeviceType)) {
   1095       FreePool (DevOrder);
   1096       return EFI_NOT_FOUND;
   1097     }
   1098     LocalBbsTable[BbsIndex].BootPriority = *Priority;
   1099     (*Priority)++;
   1100   }
   1101   //
   1102   // If the high byte of the DevIndex is 0xFF, it indicates that this device has been disabled.
   1103   //
   1104   for (Index = 0; Index < DevOrderPtr->Length / sizeof (UINT16) - 1; Index++) {
   1105     if ((DevOrderPtr->Data[Index] & 0xFF00) == 0xFF00) {
   1106       //
   1107       // LocalBbsTable[DevIndex[Index] & 0xFF].BootPriority = BBS_DISABLED_ENTRY;
   1108       //
   1109     } else if (DevOrderPtr->Data[Index] != BbsIndex) {
   1110       LocalBbsTable[DevOrderPtr->Data[Index]].BootPriority = *Priority;
   1111       (*Priority)++;
   1112     }
   1113   }
   1114 
   1115   FreePool (DevOrder);
   1116   return EFI_SUCCESS;
   1117 }
   1118 
   1119 /**
   1120   Print the BBS Table.
   1121 
   1122   @param LocalBbsTable   The BBS table.
   1123   @param BbsCount        The count of entry in BBS table.
   1124 **/
   1125 VOID
   1126 LegacyBmPrintBbsTable (
   1127   IN BBS_TABLE  *LocalBbsTable,
   1128   IN UINT16     BbsCount
   1129   )
   1130 {
   1131   UINT16  Index;
   1132 
   1133   DEBUG ((DEBUG_INFO, "\n"));
   1134   DEBUG ((DEBUG_INFO, " NO  Prio bb/dd/ff cl/sc Type Stat segm:offs\n"));
   1135   DEBUG ((DEBUG_INFO, "=============================================\n"));
   1136   for (Index = 0; Index < BbsCount; Index++) {
   1137     if (!LegacyBmValidBbsEntry (&LocalBbsTable[Index])) {
   1138       continue;
   1139     }
   1140 
   1141     DEBUG (
   1142       (DEBUG_INFO,
   1143       " %02x: %04x %02x/%02x/%02x %02x/%02x %04x %04x %04x:%04x\n",
   1144       (UINTN) Index,
   1145       (UINTN) LocalBbsTable[Index].BootPriority,
   1146       (UINTN) LocalBbsTable[Index].Bus,
   1147       (UINTN) LocalBbsTable[Index].Device,
   1148       (UINTN) LocalBbsTable[Index].Function,
   1149       (UINTN) LocalBbsTable[Index].Class,
   1150       (UINTN) LocalBbsTable[Index].SubClass,
   1151       (UINTN) LocalBbsTable[Index].DeviceType,
   1152       (UINTN) * (UINT16 *) &LocalBbsTable[Index].StatusFlags,
   1153       (UINTN) LocalBbsTable[Index].BootHandlerSegment,
   1154       (UINTN) LocalBbsTable[Index].BootHandlerOffset,
   1155       (UINTN) ((LocalBbsTable[Index].MfgStringSegment << 4) + LocalBbsTable[Index].MfgStringOffset),
   1156       (UINTN) ((LocalBbsTable[Index].DescStringSegment << 4) + LocalBbsTable[Index].DescStringOffset))
   1157       );
   1158   }
   1159 
   1160   DEBUG ((DEBUG_INFO, "\n"));
   1161 }
   1162 
   1163 /**
   1164   Set the boot priority for BBS entries based on boot option entry and boot order.
   1165 
   1166   @param  BootOption            The boot option is to be checked for refresh BBS table.
   1167 
   1168   @retval EFI_SUCCESS           The boot priority for BBS entries is refreshed successfully.
   1169   @retval EFI_NOT_FOUND         BBS entries can't be found.
   1170   @retval EFI_OUT_OF_RESOURCES  Failed to get the legacy device boot order.
   1171 **/
   1172 EFI_STATUS
   1173 LegacyBmRefreshBbsTableForBoot (
   1174   IN EFI_BOOT_MANAGER_LOAD_OPTION        *BootOption
   1175   )
   1176 {
   1177   EFI_STATUS                    Status;
   1178   UINT16                        BbsIndex;
   1179   UINT16                        HddCount;
   1180   UINT16                        BbsCount;
   1181   HDD_INFO                      *LocalHddInfo;
   1182   BBS_TABLE                     *LocalBbsTable;
   1183   UINT16                        DevType;
   1184   EFI_LEGACY_BIOS_PROTOCOL      *LegacyBios;
   1185   UINTN                         Index;
   1186   UINT16                        Priority;
   1187   UINT16                        *DeviceType;
   1188   UINTN                         DeviceTypeCount;
   1189   UINTN                         DeviceTypeIndex;
   1190   EFI_BOOT_MANAGER_LOAD_OPTION  *Option;
   1191   UINTN                         OptionCount;
   1192 
   1193   HddCount      = 0;
   1194   BbsCount      = 0;
   1195   LocalHddInfo  = NULL;
   1196   LocalBbsTable = NULL;
   1197   DevType       = BBS_UNKNOWN;
   1198 
   1199   Status        = gBS->LocateProtocol (&gEfiLegacyBiosProtocolGuid, NULL, (VOID **) &LegacyBios);
   1200   if (EFI_ERROR (Status)) {
   1201     return Status;
   1202   }
   1203 
   1204   Status = LegacyBios->GetBbsInfo (
   1205                          LegacyBios,
   1206                          &HddCount,
   1207                          &LocalHddInfo,
   1208                          &BbsCount,
   1209                          &LocalBbsTable
   1210                          );
   1211   if (EFI_ERROR (Status)) {
   1212     return Status;
   1213   }
   1214 
   1215   //
   1216   // First, set all the present devices' boot priority to BBS_UNPRIORITIZED_ENTRY
   1217   // We will set them according to the settings setup by user
   1218   //
   1219   for (Index = 0; Index < BbsCount; Index++) {
   1220     if (LegacyBmValidBbsEntry (&LocalBbsTable[Index])) {
   1221       LocalBbsTable[Index].BootPriority = BBS_UNPRIORITIZED_ENTRY;
   1222     }
   1223   }
   1224   //
   1225   // boot priority always starts at 0
   1226   //
   1227   Priority = 0;
   1228   if ((DevicePathType (BootOption->FilePath) == BBS_DEVICE_PATH) &&
   1229       (DevicePathSubType (BootOption->FilePath) == BBS_BBS_DP)) {
   1230     //
   1231     // If BootOption stands for a legacy boot option, we prioritize the devices with the same type first.
   1232     //
   1233     DevType  = LegacyBmDeviceType (BootOption->FilePath);
   1234     BbsIndex = ((LEGACY_BM_BOOT_OPTION_BBS_DATA *) BootOption->OptionalData)->BbsIndex;
   1235     Status = LegacyBmSetPriorityForSameTypeDev (
   1236                DevType,
   1237                BbsIndex,
   1238                LocalBbsTable,
   1239                &Priority
   1240                );
   1241     if (EFI_ERROR (Status)) {
   1242       return Status;
   1243     }
   1244   }
   1245   //
   1246   // we have to set the boot priority for other BBS entries with different device types
   1247   //
   1248   Option          = EfiBootManagerGetLoadOptions (&OptionCount, LoadOptionTypeBoot);
   1249   DeviceType      = AllocatePool (sizeof (UINT16) * OptionCount);
   1250   ASSERT (DeviceType != NULL);
   1251   DeviceType[0]   = DevType;
   1252   DeviceTypeCount = 1;
   1253   for (Index = 0; Index < OptionCount; Index++) {
   1254     if ((DevicePathType (Option[Index].FilePath) != BBS_DEVICE_PATH) ||
   1255         (DevicePathSubType (Option[Index].FilePath) != BBS_BBS_DP)) {
   1256       continue;
   1257     }
   1258 
   1259     DevType = LegacyBmDeviceType (Option[Index].FilePath);
   1260     for (DeviceTypeIndex = 0; DeviceTypeIndex < DeviceTypeCount; DeviceTypeIndex++) {
   1261       if (DeviceType[DeviceTypeIndex] == DevType) {
   1262         break;
   1263       }
   1264     }
   1265     if (DeviceTypeIndex < DeviceTypeCount) {
   1266       //
   1267       // We don't want to process twice for a device type
   1268       //
   1269       continue;
   1270     }
   1271 
   1272     DeviceType[DeviceTypeCount] = DevType;
   1273     DeviceTypeCount++;
   1274 
   1275     Status = LegacyBmSetPriorityForSameTypeDev (
   1276                DevType,
   1277                (UINTN) -1,
   1278                LocalBbsTable,
   1279                &Priority
   1280                );
   1281   }
   1282   EfiBootManagerFreeLoadOptions (Option, OptionCount);
   1283 
   1284   DEBUG_CODE_BEGIN();
   1285     LegacyBmPrintBbsTable (LocalBbsTable, BbsCount);
   1286   DEBUG_CODE_END();
   1287 
   1288   return Status;
   1289 }
   1290 
   1291 
   1292 /**
   1293   Boot the legacy system with the boot option.
   1294 
   1295   @param  BootOption The legacy boot option which have BBS device path
   1296                      On return, BootOption->Status contains the boot status.
   1297                      EFI_UNSUPPORTED    There is no legacybios protocol, do not support
   1298                                         legacy boot.
   1299                      EFI_STATUS         The status of LegacyBios->LegacyBoot ().
   1300 **/
   1301 VOID
   1302 EFIAPI
   1303 LegacyBmBoot (
   1304   IN  EFI_BOOT_MANAGER_LOAD_OPTION           *BootOption
   1305   )
   1306 {
   1307   EFI_STATUS                Status;
   1308   EFI_LEGACY_BIOS_PROTOCOL  *LegacyBios;
   1309 
   1310   Status = gBS->LocateProtocol (&gEfiLegacyBiosProtocolGuid, NULL, (VOID **) &LegacyBios);
   1311   if (EFI_ERROR (Status)) {
   1312     //
   1313     // If no LegacyBios protocol we do not support legacy boot
   1314     //
   1315     BootOption->Status = EFI_UNSUPPORTED;
   1316     return;
   1317   }
   1318   //
   1319   // Notes: if we separate the int 19, then we don't need to refresh BBS
   1320   //
   1321   Status = LegacyBmRefreshBbsTableForBoot (BootOption);
   1322   if (EFI_ERROR (Status)) {
   1323     BootOption->Status = Status;
   1324     return;
   1325   }
   1326 
   1327   BootOption->Status = LegacyBios->LegacyBoot (
   1328                                      LegacyBios,
   1329                                      (BBS_BBS_DEVICE_PATH *) BootOption->FilePath,
   1330                                      BootOption->OptionalDataSize,
   1331                                      BootOption->OptionalData
   1332                                      );
   1333 }
   1334 
   1335 /**
   1336   This function enumerates all the legacy boot options.
   1337 
   1338   @param BootOptionCount   Return the legacy boot option count.
   1339 
   1340   @retval    Pointer to the legacy boot option buffer.
   1341 **/
   1342 EFI_BOOT_MANAGER_LOAD_OPTION *
   1343 LegacyBmEnumerateAllBootOptions (
   1344   UINTN                         *BootOptionCount
   1345   )
   1346 {
   1347   EFI_STATUS                    Status;
   1348   UINT16                        HddCount;
   1349   UINT16                        BbsCount;
   1350   HDD_INFO                      *HddInfo;
   1351   BBS_TABLE                     *BbsTable;
   1352   EFI_LEGACY_BIOS_PROTOCOL      *LegacyBios;
   1353   UINT16                        Index;
   1354   EFI_BOOT_MANAGER_LOAD_OPTION  *BootOptions;
   1355 
   1356   ASSERT (BootOptionCount != NULL);
   1357 
   1358   BootOptions      = NULL;
   1359   *BootOptionCount = 0;
   1360   BbsCount         = 0;
   1361 
   1362   Status        = gBS->LocateProtocol (&gEfiLegacyBiosProtocolGuid, NULL, (VOID **) &LegacyBios);
   1363   if (EFI_ERROR (Status)) {
   1364     return NULL;
   1365   }
   1366 
   1367   Status = LegacyBios->GetBbsInfo (
   1368                          LegacyBios,
   1369                          &HddCount,
   1370                          &HddInfo,
   1371                          &BbsCount,
   1372                          &BbsTable
   1373                          );
   1374   if (EFI_ERROR (Status)) {
   1375     return NULL;
   1376   }
   1377 
   1378   for (Index = 0; Index < BbsCount; Index++) {
   1379     if (!LegacyBmValidBbsEntry (&BbsTable[Index])) {
   1380       continue;
   1381     }
   1382 
   1383     BootOptions = ReallocatePool (
   1384                     sizeof (EFI_BOOT_MANAGER_LOAD_OPTION) * (*BootOptionCount),
   1385                     sizeof (EFI_BOOT_MANAGER_LOAD_OPTION) * (*BootOptionCount + 1),
   1386                     BootOptions
   1387                     );
   1388     ASSERT (BootOptions != NULL);
   1389 
   1390     Status = LegacyBmCreateLegacyBootOption (&BootOptions[(*BootOptionCount)++], &BbsTable[Index], Index);
   1391     ASSERT_EFI_ERROR (Status);
   1392   }
   1393 
   1394   return BootOptions;
   1395 }
   1396 
   1397 /**
   1398   Return the index of the boot option in the boot option array.
   1399 
   1400   The function compares the Description, FilePath, OptionalData.
   1401 
   1402   @param Key         The input boot option which is compared with.
   1403   @param Array       The input boot option array.
   1404   @param Count       The count of the input boot options.
   1405 
   1406   @retval  The index of the input boot option in the array.
   1407 
   1408 **/
   1409 INTN
   1410 LegacyBmFindBootOption (
   1411   IN CONST EFI_BOOT_MANAGER_LOAD_OPTION *Key,
   1412   IN CONST EFI_BOOT_MANAGER_LOAD_OPTION *Array,
   1413   IN UINTN                              Count
   1414   )
   1415 {
   1416   UINTN                             Index;
   1417 
   1418   for (Index = 0; Index < Count; Index++) {
   1419     if ((StrCmp (Key->Description, Array[Index].Description) == 0) &&
   1420         (CompareMem (Key->FilePath, Array[Index].FilePath, GetDevicePathSize (Key->FilePath)) == 0) &&
   1421         (Key->OptionalDataSize == Array[Index].OptionalDataSize) &&
   1422         (CompareMem (Key->OptionalData, Array[Index].OptionalData, Key->OptionalDataSize) == 0)) {
   1423       return (INTN) Index;
   1424     }
   1425   }
   1426 
   1427   return -1;
   1428 }
   1429 
   1430 /**
   1431   Refresh all legacy boot options.
   1432 
   1433 **/
   1434 VOID
   1435 EFIAPI
   1436 LegacyBmRefreshAllBootOption (
   1437   VOID
   1438   )
   1439 {
   1440   EFI_STATUS                                 Status;
   1441   EFI_LEGACY_BIOS_PROTOCOL                   *LegacyBios;
   1442   UINTN                                      RootBridgeHandleCount;
   1443   EFI_HANDLE                                 *RootBridgeHandleBuffer;
   1444   UINTN                                      HandleCount;
   1445   EFI_HANDLE                                 *HandleBuffer;
   1446   UINTN                                      RootBridgeIndex;
   1447   UINTN                                      Index;
   1448   UINTN                                      Flags;
   1449   EFI_BOOT_MANAGER_LOAD_OPTION               *BootOptions;
   1450   UINTN                                      BootOptionCount;
   1451   EFI_BOOT_MANAGER_LOAD_OPTION               *ExistingBootOptions;
   1452   UINTN                                      ExistingBootOptionCount;
   1453 
   1454   Status = gBS->LocateProtocol (&gEfiLegacyBiosProtocolGuid, NULL, (VOID **) &LegacyBios);
   1455   if (EFI_ERROR (Status)) {
   1456     LegacyBmDeleteAllBootOptions ();
   1457     return;
   1458   }
   1459   PERF_START (NULL, "LegacyBootOptionEnum", "BDS", 0);
   1460 
   1461   //
   1462   // Before enumerating the legacy boot option, we need to dispatch all the legacy option roms
   1463   // to ensure the GetBbsInfo() counts all the legacy devices.
   1464   //
   1465   gBS->LocateHandleBuffer (
   1466          ByProtocol,
   1467          &gEfiPciRootBridgeIoProtocolGuid,
   1468          NULL,
   1469          &RootBridgeHandleCount,
   1470          &RootBridgeHandleBuffer
   1471          );
   1472   for (RootBridgeIndex = 0; RootBridgeIndex < RootBridgeHandleCount; RootBridgeIndex++) {
   1473     gBS->ConnectController (RootBridgeHandleBuffer[RootBridgeIndex], NULL, NULL, FALSE);
   1474     gBS->LocateHandleBuffer (
   1475            ByProtocol,
   1476            &gEfiPciIoProtocolGuid,
   1477            NULL,
   1478            &HandleCount,
   1479            &HandleBuffer
   1480            );
   1481     for (Index = 0; Index < HandleCount; Index++) {
   1482       //
   1483       // Start the thunk driver so that the legacy option rom gets dispatched.
   1484       // Note: We don't directly call InstallPciRom because some thunk drivers
   1485       // (e.g. BlockIo thunk driver) depend on the immediate result after dispatching
   1486       //
   1487       Status = LegacyBios->CheckPciRom (
   1488                              LegacyBios,
   1489                              HandleBuffer[Index],
   1490                              NULL,
   1491                              NULL,
   1492                              &Flags
   1493                              );
   1494       if (!EFI_ERROR (Status)) {
   1495         gBS->ConnectController (HandleBuffer[Index], NULL, NULL, FALSE);
   1496       }
   1497     }
   1498   }
   1499 
   1500   //
   1501   // Same algorithm pattern as the EfiBootManagerRefreshAllBootOption
   1502   // Firstly delete the invalid legacy boot options,
   1503   // then enumreate and save the newly appeared legacy boot options
   1504   // the last step is legacy boot option special action to refresh the LegacyDevOrder variable
   1505   //
   1506   LegacyBmDeleteAllInvalidBootOptions ();
   1507 
   1508   ExistingBootOptions = EfiBootManagerGetLoadOptions (&ExistingBootOptionCount, LoadOptionTypeBoot);
   1509   BootOptions         = LegacyBmEnumerateAllBootOptions   (&BootOptionCount);
   1510 
   1511   for (Index = 0; Index < BootOptionCount; Index++) {
   1512     if (LegacyBmFindBootOption (&BootOptions[Index], ExistingBootOptions, ExistingBootOptionCount) == -1) {
   1513       Status = EfiBootManagerAddLoadOptionVariable (&BootOptions[Index], (UINTN) -1);
   1514       DEBUG ((
   1515         EFI_D_INFO, "[LegacyBds] New Boot Option: Boot%04x Bbs0x%04x %s %r\n",
   1516         (UINTN) BootOptions[Index].OptionNumber,
   1517         (UINTN) ((LEGACY_BM_BOOT_OPTION_BBS_DATA *) BootOptions[Index].OptionalData)->BbsIndex,
   1518         BootOptions[Index].Description,
   1519         Status
   1520         ));
   1521       //
   1522       // Continue upon failure to add boot option.
   1523       //
   1524     }
   1525   }
   1526 
   1527   EfiBootManagerFreeLoadOptions (ExistingBootOptions, ExistingBootOptionCount);
   1528   EfiBootManagerFreeLoadOptions (BootOptions,         BootOptionCount);
   1529 
   1530   //
   1531   // Failure to create LegacyDevOrder variable only impacts the boot order.
   1532   //
   1533   LegacyBmUpdateDevOrder ();
   1534 
   1535   PERF_END   (NULL, "LegacyBootOptionEnum", "BDS", 0);
   1536 }
   1537