]> git.proxmox.com Git - mirror_edk2.git/blobdiff - EdkUnixPkg/Dxe/PlatformBds/Generic/BootMaint/BBSsupport.c
Unix version of EFI emulator
[mirror_edk2.git] / EdkUnixPkg / Dxe / PlatformBds / Generic / BootMaint / BBSsupport.c
diff --git a/EdkUnixPkg/Dxe/PlatformBds/Generic/BootMaint/BBSsupport.c b/EdkUnixPkg/Dxe/PlatformBds/Generic/BootMaint/BBSsupport.c
new file mode 100644 (file)
index 0000000..c9f2402
--- /dev/null
@@ -0,0 +1,1601 @@
+/*++\r
+\r
+Copyright (c) 2006, Intel Corporation                                                          \r
+All rights reserved. This program and the accompanying materials                          \r
+are licensed and made available under the terms and conditions of the BSD License         \r
+which accompanies this distribution.  The full text of the license may be found at        \r
+http://opensource.org/licenses/bsd-license.php                                            \r
+                                                                                          \r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,                     \r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.             \r
+\r
+Module Name:\r
+\r
+  BBSsupport.c\r
+\r
+Abstract:\r
+\r
+  This function deal with the legacy boot option, it create, delete\r
+  and manage the legacy boot option, all legacy boot option is getting from\r
+  the legacy BBS table.\r
+\r
+--*/\r
+\r
+#include "BBSsupport.h"\r
+\r
+EFI_DEVICE_PATH_PROTOCOL  EndDevicePath[] = {\r
+  END_DEVICE_PATH_TYPE,\r
+  END_ENTIRE_DEVICE_PATH_SUBTYPE,\r
+  END_DEVICE_PATH_LENGTH,\r
+  0\r
+};\r
+\r
+VOID\r
+AsciiToUnicodeSize (\r
+  IN UINT8              *a,\r
+  IN UINTN              Size,\r
+  OUT UINT16            *u\r
+  )\r
+/*++\r
+\r
+  Routine Description:\r
+\r
+    Translate the first n characters of an Ascii string to\r
+    Unicode characters. The count n is indicated by parameter\r
+    Size. If Size is greater than the length of string, then\r
+    the entire string is translated.\r
+\r
+  Arguments:\r
+\r
+    a         - Pointer to input Ascii string.\r
+    Size      - The number of characters to translate.\r
+    u         - Pointer to output Unicode string buffer.\r
+\r
+  Returns:\r
+\r
+    None\r
+\r
+--*/\r
+{\r
+  UINTN i;\r
+\r
+  i = 0;\r
+  while (a[i] != 0) {\r
+    u[i] = (CHAR16) a[i];\r
+    if (i == Size) {\r
+      break;\r
+    }\r
+\r
+    i++;\r
+  }\r
+  u[i] = 0;\r
+}\r
+\r
+VOID\r
+BdsBuildLegacyDevNameString (\r
+  IN BBS_TABLE                 *CurBBSEntry,\r
+  IN UINTN                     Index,\r
+  IN UINTN                     BufSize,\r
+  OUT CHAR16                   *BootString\r
+  )\r
+{\r
+  CHAR16  *Fmt;\r
+  CHAR16  *Type;\r
+  UINT8   *StringDesc;\r
+  CHAR16  temp[80];\r
+\r
+  switch (Index) {\r
+  //\r
+  // Primary Master\r
+  //\r
+  case 1:\r
+    Fmt = L"Primary Master %s";\r
+    break;\r
+\r
+ //\r
+ // Primary Slave\r
+ //\r
+  case 2:\r
+    Fmt = L"Primary Slave %s";\r
+    break;\r
+\r
+  //\r
+  // Secondary Master\r
+  //\r
+  case 3:\r
+    Fmt = L"Secondary Master %s";\r
+    break;\r
+\r
+  //\r
+  // Secondary Slave\r
+  //\r
+  case 4:\r
+    Fmt = L"Secondary Slave %s";\r
+    break;\r
+\r
+  default:\r
+    Fmt = L"%s";\r
+    break;\r
+  }\r
+\r
+  switch (CurBBSEntry->DeviceType) {\r
+  case BBS_FLOPPY:\r
+    Type = L"Floppy";\r
+    break;\r
+\r
+  case BBS_HARDDISK:\r
+    Type = L"Harddisk";\r
+    break;\r
+\r
+  case BBS_CDROM:\r
+    Type = L"CDROM";\r
+    break;\r
+\r
+  case BBS_PCMCIA:\r
+    Type = L"PCMCIAe";\r
+    break;\r
+\r
+  case BBS_USB:\r
+    Type = L"USB";\r
+    break;\r
+\r
+  case BBS_EMBED_NETWORK:\r
+    Type = L"Network";\r
+    break;\r
+\r
+  case BBS_BEV_DEVICE:\r
+    Type = L"BEVe";\r
+    break;\r
+\r
+  case BBS_UNKNOWN:\r
+  default:\r
+    Type = L"Unknown";\r
+    break;\r
+  }\r
+  //\r
+  // If current BBS entry has its description then use it.\r
+  //\r
+  StringDesc = (UINT8 *) (UINTN) ((CurBBSEntry->DescStringSegment << 4) + CurBBSEntry->DescStringOffset);\r
+  if (NULL != StringDesc) {\r
+    //\r
+    // Only get fisrt 32 characters, this is suggested by BBS spec\r
+    //\r
+    AsciiToUnicodeSize (StringDesc, 32, temp);\r
+    Fmt   = L"%s";\r
+    Type  = temp;\r
+  }\r
+\r
+  UnicodeSPrint (BootString, BufSize, Fmt, Type);\r
+}\r
+\r
+EFI_STATUS\r
+BdsCreateLegacyBootOption (\r
+  IN BBS_TABLE                        *CurrentBbsEntry,\r
+  IN EFI_DEVICE_PATH_PROTOCOL         *CurrentBbsDevPath,\r
+  IN UINTN                            Index,\r
+  IN OUT UINT16                       **BootOrderList,\r
+  IN OUT UINTN                        *BootOrderListSize\r
+  )\r
+/*++\r
+\r
+  Routine Description:\r
+\r
+    Create a legacy boot option for the specified entry of\r
+    BBS table, save it as variable, and append it to the boot\r
+    order list.\r
+\r
+  Arguments:\r
+\r
+    CurrentBbsEntry        - Pointer to current BBS table.\r
+    CurrentBbsDevPath      - Pointer to the Device Path Protocol instance of BBS\r
+    Index                  - Index of the specified entry in BBS table.\r
+    BootOrderList          - On input, the original boot order list.\r
+                             On output, the new boot order list attached with the\r
+                             created node.\r
+    BootOrderListSize      - On input, the original size of boot order list.\r
+                           - On output, the size of new boot order list.\r
+\r
+  Returns:\r
+\r
+    EFI_SUCCESS            - Boot Option successfully created.\r
+    EFI_OUT_OF_RESOURCES   - Fail to allocate necessary memory.\r
+    Other                  - Error occurs while setting variable.\r
+\r
+--*/\r
+{\r
+  EFI_STATUS  Status;\r
+  UINT16      CurrentBootOptionNo;\r
+  UINT16      BootString[10];\r
+  UINT16      BootDesc[100];\r
+  UINT16      *NewBootOrderList;\r
+  UINTN       BufferSize;\r
+  VOID        *Buffer;\r
+  UINT8       *Ptr;\r
+  UINT16      CurrentBbsDevPathSize;\r
+  UINTN       BootOrderIndex;\r
+  UINTN       BootOrderLastIndex;\r
+  UINTN       ArrayIndex;\r
+  BOOLEAN     IndexNotFound;\r
+\r
+  if (NULL == (*BootOrderList)) {\r
+    CurrentBootOptionNo = 0;\r
+  } else {\r
+    for (ArrayIndex = 0; ArrayIndex < (UINTN) (*BootOrderListSize / sizeof (UINT16)); ArrayIndex++) {\r
+      IndexNotFound = TRUE;\r
+      for (BootOrderIndex = 0; BootOrderIndex < (UINTN) (*BootOrderListSize / sizeof (UINT16)); BootOrderIndex++) {\r
+        if ((*BootOrderList)[BootOrderIndex] == ArrayIndex) {\r
+          IndexNotFound = FALSE;\r
+          break;\r
+        }\r
+      }\r
+\r
+      if (!IndexNotFound) {\r
+        continue;\r
+      } else {\r
+        break;\r
+      }\r
+    }\r
+\r
+    CurrentBootOptionNo = (UINT16) ArrayIndex;\r
+  }\r
+\r
+  UnicodeSPrint (\r
+    BootString,\r
+    sizeof (BootString),\r
+    L"Boot%04x",\r
+    CurrentBootOptionNo\r
+    );\r
+\r
+  BdsBuildLegacyDevNameString (CurrentBbsEntry, Index, sizeof (BootDesc), BootDesc);\r
+\r
+  CurrentBbsDevPathSize = (UINT16) (GetDevicePathSize (CurrentBbsDevPath));\r
+\r
+  BufferSize = sizeof (UINT32) +\r
+    sizeof (UINT16) +\r
+    StrSize (BootDesc) +\r
+    CurrentBbsDevPathSize +\r
+    sizeof (BBS_TABLE) +\r
+    sizeof (UINT16);\r
+\r
+  Buffer = AllocateZeroPool (BufferSize);\r
+  if (Buffer == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  Ptr               = (UINT8 *) Buffer;\r
+\r
+  *((UINT32 *) Ptr) = LOAD_OPTION_ACTIVE;\r
+  Ptr += sizeof (UINT32);\r
+\r
+  *((UINT16 *) Ptr) = CurrentBbsDevPathSize;\r
+  Ptr += sizeof (UINT16);\r
+\r
+  CopyMem (\r
+    Ptr,\r
+    BootDesc,\r
+    StrSize (BootDesc)\r
+    );\r
+  Ptr += StrSize (BootDesc);\r
+\r
+  CopyMem (\r
+    Ptr,\r
+    CurrentBbsDevPath,\r
+    CurrentBbsDevPathSize\r
+    );\r
+  Ptr += CurrentBbsDevPathSize;\r
+\r
+  CopyMem (\r
+    Ptr,\r
+    CurrentBbsEntry,\r
+    sizeof (BBS_TABLE)\r
+    );\r
+\r
+  Ptr += sizeof (BBS_TABLE);\r
+  *((UINT16 *) Ptr) = (UINT16) Index;\r
+\r
+  Status = gRT->SetVariable (\r
+                  BootString,\r
+                  &gEfiGlobalVariableGuid,\r
+                  VAR_FLAG,\r
+                  BufferSize,\r
+                  Buffer\r
+                  );\r
+\r
+  SafeFreePool (Buffer);\r
+  Buffer = NULL;\r
+\r
+  NewBootOrderList = AllocateZeroPool (*BootOrderListSize + sizeof (UINT16));\r
+  if (NULL == NewBootOrderList) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  if (NULL != *BootOrderList) {\r
+    CopyMem (NewBootOrderList, *BootOrderList, *BootOrderListSize);\r
+  }\r
+\r
+  SafeFreePool (*BootOrderList);\r
+\r
+  BootOrderLastIndex                    = (UINTN) (*BootOrderListSize / sizeof (UINT16));\r
+  NewBootOrderList[BootOrderLastIndex]  = CurrentBootOptionNo;\r
+  *BootOrderListSize += sizeof (UINT16);\r
+  *BootOrderList = NewBootOrderList;\r
+\r
+  return Status;\r
+}\r
+\r
+BOOLEAN\r
+BdsIsLegacyBootOption (\r
+  IN UINT8                 *BootOptionVar,\r
+  OUT BBS_TABLE            **BbsEntry,\r
+  OUT UINT16               *BbsIndex\r
+  )\r
+{\r
+  UINT8                     *Ptr;\r
+  EFI_DEVICE_PATH_PROTOCOL  *DevicePath;\r
+  BOOLEAN                   Ret;\r
+  UINT16                    DevPathLen;\r
+\r
+  Ptr = BootOptionVar;\r
+  Ptr += sizeof (UINT32);\r
+  DevPathLen = *(UINT16 *) Ptr;\r
+  Ptr += sizeof (UINT16);\r
+  Ptr += StrSize ((UINT16 *) Ptr);\r
+  DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) Ptr;\r
+  if ((BBS_DEVICE_PATH == DevicePath->Type) && (BBS_BBS_DP == DevicePath->SubType)) {\r
+    Ptr += DevPathLen;\r
+    *BbsEntry = (BBS_TABLE *) Ptr;\r
+    Ptr += sizeof (BBS_TABLE);\r
+    *BbsIndex = *(UINT16 *) Ptr;\r
+    Ret       = TRUE;\r
+  } else {\r
+    *BbsEntry = NULL;\r
+    Ret       = FALSE;\r
+  }\r
+\r
+  return Ret;\r
+}\r
+\r
+EFI_STATUS\r
+BdsDeleteBootOption (\r
+  IN UINTN                       OptionNumber,\r
+  IN OUT UINT16                  *BootOrder,\r
+  IN OUT UINTN                   *BootOrderSize\r
+  )\r
+{\r
+  UINT16      BootOption[100];\r
+  UINTN       Index;\r
+  EFI_STATUS  Status;\r
+  UINTN       Index2Del;\r
+\r
+  Status    = EFI_SUCCESS;\r
+  Index2Del = 0;\r
+\r
+  UnicodeSPrint (BootOption, sizeof (BootOption), L"Boot%04x", OptionNumber);\r
+  Status = EfiLibDeleteVariable (BootOption, &gEfiGlobalVariableGuid);\r
+  //\r
+  // adjust boot order array\r
+  //\r
+  for (Index = 0; Index < *BootOrderSize / sizeof (UINT16); Index++) {\r
+    if (BootOrder[Index] == OptionNumber) {\r
+      Index2Del = Index;\r
+      break;\r
+    }\r
+  }\r
+\r
+  if (Index != *BootOrderSize / sizeof (UINT16)) {\r
+    for (Index = 0; Index < *BootOrderSize / sizeof (UINT16) - 1; Index++) {\r
+      if (Index >= Index2Del) {\r
+        BootOrder[Index] = BootOrder[Index + 1];\r
+      }\r
+    }\r
+\r
+    *BootOrderSize -= sizeof (UINT16);\r
+  }\r
+\r
+  return Status;\r
+\r
+}\r
+\r
+EFI_STATUS\r
+BdsDeleteAllInvalidLegacyBootOptions (\r
+  VOID\r
+  )\r
+/*++\r
+\r
+  Routine Description:\r
+\r
+    Delete all the invalid legacy boot options.\r
+\r
+  Arguments:\r
+\r
+    None.\r
+\r
+  Returns:\r
+\r
+    EFI_SUCCESS            - All invalide legacy boot options are deleted.\r
+    EFI_OUT_OF_RESOURCES   - Fail to allocate necessary memory.\r
+    EFI_NOT_FOUND          - Fail to retrive variable of boot order.\r
+    Other                  - Error occurs while setting variable or locating\r
+                             protocol.\r
+\r
+--*/\r
+{\r
+  UINT16                    *BootOrder;\r
+  UINT8                     *BootOptionVar;\r
+  UINTN                     BootOrderSize;\r
+  UINTN                     BootOptionSize;\r
+  EFI_STATUS                Status;\r
+  UINT16                    HddCount;\r
+  UINT16                    BbsCount;\r
+  HDD_INFO                  *LocalHddInfo;\r
+  BBS_TABLE                 *LocalBbsTable;\r
+  BBS_TABLE                 *BbsEntry;\r
+  UINT16                    BbsIndex;\r
+  EFI_LEGACY_BIOS_PROTOCOL  *LegacyBios;\r
+  UINTN                     Index;\r
+  UINT16                    BootOption[10];\r
+  UINT16                    BootDesc[100];\r
+  BOOLEAN                   DescStringMatch;\r
+\r
+  Status        = EFI_SUCCESS;\r
+  BootOrder     = NULL;\r
+  BootOrderSize = 0;\r
+  HddCount      = 0;\r
+  BbsCount      = 0;\r
+  LocalHddInfo  = NULL;\r
+  LocalBbsTable = NULL;\r
+  BbsEntry      = NULL;\r
+\r
+  Status        = EfiLibLocateProtocol (&gEfiLegacyBiosProtocolGuid, &LegacyBios);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  LegacyBios->GetBbsInfo (\r
+                LegacyBios,\r
+                &HddCount,\r
+                &LocalHddInfo,\r
+                &BbsCount,\r
+                &LocalBbsTable\r
+                );\r
+\r
+  BootOrder = BdsLibGetVariableAndSize (\r
+                L"BootOrder",\r
+                &gEfiGlobalVariableGuid,\r
+                &BootOrderSize\r
+                );\r
+  if (NULL == BootOrder) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  Index = 0;\r
+  while (Index < BootOrderSize / sizeof (UINT16)) {\r
+    UnicodeSPrint (BootOption, sizeof (BootOption), L"Boot%04x", BootOrder[Index]);\r
+    BootOptionVar = BdsLibGetVariableAndSize (\r
+                      BootOption,\r
+                      &gEfiGlobalVariableGuid,\r
+                      &BootOptionSize\r
+                      );\r
+    if (NULL == BootOptionVar) {\r
+      SafeFreePool (BootOrder);\r
+      return EFI_OUT_OF_RESOURCES;\r
+    }\r
+\r
+    if (!BdsIsLegacyBootOption (BootOptionVar, &BbsEntry, &BbsIndex)) {\r
+      SafeFreePool (BootOptionVar);\r
+      Index++;\r
+      continue;\r
+    }\r
\r
+    //\r
+    // Check if BBS Description String is changed\r
+    //\r
+    DescStringMatch = FALSE;\r
+    \r
+    BdsBuildLegacyDevNameString (\r
+      &LocalBbsTable[BbsIndex], \r
+      BbsIndex, \r
+      sizeof(BootDesc), \r
+      BootDesc\r
+      );\r
+    \r
+    if (StrCmp (BootDesc, (UINT16*)(BootOptionVar + sizeof (UINT32) + sizeof (UINT16))) == 0) {\r
+      DescStringMatch = TRUE;\r
+    }\r
+\r
+    if (!((LocalBbsTable[BbsIndex].BootPriority == BBS_IGNORE_ENTRY) ||\r
+          (LocalBbsTable[BbsIndex].BootPriority == BBS_DO_NOT_BOOT_FROM) ||\r
+          (LocalBbsTable[BbsIndex].BootPriority == BBS_LOWEST_PRIORITY)) &&\r
+        (LocalBbsTable[BbsIndex].DeviceType == BbsEntry->DeviceType) &&\r
+        DescStringMatch) {\r
+      Index++;\r
+      continue;\r
+    }\r
+\r
+    SafeFreePool (BootOptionVar);\r
+    //\r
+    // should delete\r
+    //\r
+    BdsDeleteBootOption (\r
+      BootOrder[Index],\r
+      BootOrder,\r
+      &BootOrderSize\r
+      );\r
+  }\r
+\r
+  if (BootOrderSize) {\r
+    Status = gRT->SetVariable (\r
+                    L"BootOrder",\r
+                    &gEfiGlobalVariableGuid,\r
+                    VAR_FLAG,\r
+                    BootOrderSize,\r
+                    BootOrder\r
+                    );\r
+  } else {\r
+    EfiLibDeleteVariable (L"BootOrder", &gEfiGlobalVariableGuid);\r
+  }\r
+\r
+  SafeFreePool (BootOrder);\r
+\r
+  return Status;\r
+}\r
+\r
+BOOLEAN\r
+BdsFindLegacyBootOptionByDevType (\r
+  IN UINT16                 *BootOrder,\r
+  IN UINTN                  BootOptionNum,\r
+  IN UINT16                 DevType,\r
+  OUT UINT32                *Attribute,\r
+  OUT UINT16                *BbsIndex,\r
+  OUT UINTN                 *OptionNumber\r
+  )\r
+{\r
+  UINTN     Index;\r
+  UINTN     BootOrderIndex;\r
+  UINT16    BootOption[100];\r
+  UINTN     BootOptionSize;\r
+  UINT8     *BootOptionVar;\r
+  BBS_TABLE *BbsEntry;\r
+  BOOLEAN   Found;\r
+\r
+  BbsEntry  = NULL;\r
+  Found     = FALSE;\r
+\r
+  if (NULL == BootOrder) {\r
+    return Found;\r
+  }\r
+\r
+  for (BootOrderIndex = 0; BootOrderIndex < BootOptionNum; BootOrderIndex++) {\r
+    Index = (UINTN) BootOrder[BootOrderIndex];\r
+    UnicodeSPrint (BootOption, sizeof (BootOption), L"Boot%04x", Index);\r
+    BootOptionVar = BdsLibGetVariableAndSize (\r
+                      BootOption,\r
+                      &gEfiGlobalVariableGuid,\r
+                      &BootOptionSize\r
+                      );\r
+    if (NULL == BootOptionVar) {\r
+      continue;\r
+    }\r
+\r
+    if (!BdsIsLegacyBootOption (BootOptionVar, &BbsEntry, BbsIndex)) {\r
+      SafeFreePool (BootOptionVar);\r
+      continue;\r
+    }\r
+\r
+    if (BbsEntry->DeviceType != DevType) {\r
+      SafeFreePool (BootOptionVar);\r
+      continue;\r
+    }\r
+\r
+    *Attribute    = *(UINT32 *) BootOptionVar;\r
+    *OptionNumber = Index;\r
+    Found         = TRUE;\r
+    SafeFreePool (BootOptionVar);\r
+    break;\r
+  }\r
+\r
+  return Found;\r
+}\r
+\r
+EFI_STATUS\r
+BdsCreateOneLegacyBootOption (\r
+  IN BBS_TABLE              *BbsItem,\r
+  IN UINTN                  Index,\r
+  IN OUT UINT16             **BootOrderList,\r
+  IN OUT UINTN              *BootOrderListSize\r
+  )\r
+{\r
+  BBS_BBS_DEVICE_PATH       BbsDevPathNode;\r
+  EFI_STATUS                Status;\r
+  EFI_DEVICE_PATH_PROTOCOL  *DevPath;\r
+\r
+  DevPath                       = NULL;\r
+\r
+  BbsDevPathNode.Header.Type    = BBS_DEVICE_PATH;\r
+  BbsDevPathNode.Header.SubType = BBS_BBS_DP;\r
+  SetDevicePathNodeLength (&BbsDevPathNode.Header, sizeof (BBS_BBS_DEVICE_PATH));\r
+  BbsDevPathNode.DeviceType = BbsItem->DeviceType;\r
+  CopyMem (&BbsDevPathNode.StatusFlag, &BbsItem->StatusFlags, sizeof (UINT16));\r
+\r
+  DevPath = AppendDevicePathNode (\r
+              EndDevicePath,\r
+              (EFI_DEVICE_PATH_PROTOCOL *) &BbsDevPathNode\r
+              );\r
+  if (NULL == DevPath) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  Status = BdsCreateLegacyBootOption (\r
+            BbsItem,\r
+            DevPath,\r
+            Index,\r
+            BootOrderList,\r
+            BootOrderListSize\r
+            );\r
+  BbsItem->BootPriority = 0x00;\r
+\r
+  gBS->FreePool (DevPath);\r
+\r
+  return Status;\r
+}\r
+\r
+EFI_STATUS\r
+BdsAddNonExistingLegacyBootOptions (\r
+  VOID\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Add the legacy boot options from BBS table if they do not exist.\r
+\r
+Arguments:\r
+\r
+  None.\r
+\r
+Returns:\r
+\r
+  EFI_SUCCESS       - The boot options are added successfully or they are already in boot options.\r
+  others            - An error occurred when creating legacy boot options.\r
+\r
+--*/\r
+{\r
+  UINT16                    *BootOrder;\r
+  UINTN                     BootOrderSize;\r
+  EFI_STATUS                Status;\r
+  UINT16                    HddCount;\r
+  UINT16                    BbsCount;\r
+  HDD_INFO                  *LocalHddInfo;\r
+  BBS_TABLE                 *LocalBbsTable;\r
+  UINT16                    BbsIndex;\r
+  EFI_LEGACY_BIOS_PROTOCOL  *LegacyBios;\r
+  UINTN                     Index;\r
+  UINT32                    Attribute;\r
+  UINTN                     OptionNumber;\r
+  BOOLEAN                   Ret;\r
+\r
+  BootOrder     = NULL;\r
+  HddCount      = 0;\r
+  BbsCount      = 0;\r
+  LocalHddInfo  = NULL;\r
+  LocalBbsTable = NULL;\r
+\r
+  Status        = EfiLibLocateProtocol (&gEfiLegacyBiosProtocolGuid, &LegacyBios);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  LegacyBios->GetBbsInfo (\r
+                LegacyBios,\r
+                &HddCount,\r
+                &LocalHddInfo,\r
+                &BbsCount,\r
+                &LocalBbsTable\r
+                );\r
+\r
+  BootOrder = BdsLibGetVariableAndSize (\r
+                L"BootOrder",\r
+                &gEfiGlobalVariableGuid,\r
+                &BootOrderSize\r
+                );\r
+  if (NULL == BootOrder) {\r
+    BootOrderSize = 0;\r
+  }\r
+\r
+  for (Index = 0; Index < BbsCount; Index++) {\r
+    if ((LocalBbsTable[Index].BootPriority == BBS_IGNORE_ENTRY) ||\r
+        (LocalBbsTable[Index].BootPriority == BBS_DO_NOT_BOOT_FROM)\r
+        ) {\r
+      continue;\r
+    }\r
+\r
+    Ret = BdsFindLegacyBootOptionByDevType (\r
+            BootOrder,\r
+            BootOrderSize / sizeof (UINT16),\r
+            LocalBbsTable[Index].DeviceType,\r
+            &Attribute,\r
+            &BbsIndex,\r
+            &OptionNumber\r
+            );\r
+    if (Ret && (Attribute & LOAD_OPTION_ACTIVE) != 0) {\r
+      continue;\r
+    }\r
+\r
+    if (Ret) {\r
+      if (Index != BbsIndex) {\r
+        BdsDeleteBootOption (\r
+          OptionNumber,\r
+          BootOrder,\r
+          &BootOrderSize\r
+          );\r
+      } else {\r
+        continue;\r
+      }\r
+    }\r
+    //\r
+    // Not found such type of legacy device in boot options or we found but it's disabled\r
+    // so we have to create one and put it to the tail of boot order list\r
+    //\r
+    Status = BdsCreateOneLegacyBootOption (\r
+              &LocalBbsTable[Index],\r
+              Index,\r
+              &BootOrder,\r
+              &BootOrderSize\r
+              );\r
+    if (EFI_ERROR (Status)) {\r
+      break;\r
+    }\r
+  }\r
+\r
+  if (BootOrderSize > 0) {\r
+    Status = gRT->SetVariable (\r
+                    L"BootOrder",\r
+                    &gEfiGlobalVariableGuid,\r
+                    VAR_FLAG,\r
+                    BootOrderSize,\r
+                    BootOrder\r
+                    );\r
+  } else {\r
+    EfiLibDeleteVariable (L"BootOrder", &gEfiGlobalVariableGuid);\r
+  }\r
+\r
+  if (BootOrder != NULL) {\r
+    SafeFreePool (BootOrder);\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+UINT16 *\r
+BdsFillDevOrderBuf (\r
+  IN BBS_TABLE                    *BbsTable,\r
+  IN BBS_TYPE                     BbsType,\r
+  IN UINTN                        BbsCount,\r
+  IN UINT16                       *Buf\r
+  )\r
+{\r
+  UINTN Index;\r
+\r
+  for (Index = 0; Index < BbsCount; Index++) {\r
+    if (BbsTable[Index].BootPriority == BBS_IGNORE_ENTRY) {\r
+      continue;\r
+    }\r
+\r
+    if (BbsTable[Index].DeviceType != BbsType) {\r
+      continue;\r
+    }\r
+\r
+    *Buf = (UINT16) (Index & 0xFF);\r
+    Buf++;\r
+  }\r
+\r
+  return Buf;\r
+}\r
+\r
+EFI_STATUS\r
+BdsCreateDevOrder (\r
+  IN BBS_TABLE                  *BbsTable,\r
+  IN UINT16                     BbsCount\r
+  )\r
+{\r
+  UINTN       Index;\r
+  UINTN       FDCount;\r
+  UINTN       HDCount;\r
+  UINTN       CDCount;\r
+  UINTN       NETCount;\r
+  UINTN       BEVCount;\r
+  UINTN       TotalSize;\r
+  UINTN       HeaderSize;\r
+  UINT8       *DevOrder;\r
+  UINT8       *Ptr;\r
+  EFI_STATUS  Status;\r
+\r
+  FDCount     = 0;\r
+  HDCount     = 0;\r
+  CDCount     = 0;\r
+  NETCount    = 0;\r
+  BEVCount    = 0;\r
+  TotalSize   = 0;\r
+  HeaderSize  = sizeof (BBS_TYPE) + sizeof (UINT16);\r
+  DevOrder    = NULL;\r
+  Ptr         = NULL;\r
+  Status      = EFI_SUCCESS;\r
+\r
+  for (Index = 0; Index < BbsCount; Index++) {\r
+    if (BbsTable[Index].BootPriority == BBS_IGNORE_ENTRY) {\r
+      continue;\r
+    }\r
+\r
+    switch (BbsTable[Index].DeviceType) {\r
+    case BBS_FLOPPY:\r
+      FDCount++;\r
+      break;\r
+\r
+    case BBS_HARDDISK:\r
+      HDCount++;\r
+      break;\r
+\r
+    case BBS_CDROM:\r
+      CDCount++;\r
+      break;\r
+\r
+    case BBS_EMBED_NETWORK:\r
+      NETCount++;\r
+      break;\r
+\r
+    case BBS_BEV_DEVICE:\r
+      BEVCount++;\r
+      break;\r
+\r
+    default:\r
+      break;\r
+    }\r
+  }\r
+\r
+  TotalSize += (HeaderSize + sizeof (UINT16) * FDCount);\r
+  TotalSize += (HeaderSize + sizeof (UINT16) * HDCount);\r
+  TotalSize += (HeaderSize + sizeof (UINT16) * CDCount);\r
+  TotalSize += (HeaderSize + sizeof (UINT16) * NETCount);\r
+  TotalSize += (HeaderSize + sizeof (UINT16) * BEVCount);\r
+\r
+  DevOrder = AllocateZeroPool (TotalSize);\r
+  if (NULL == DevOrder) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  Ptr                 = DevOrder;\r
+\r
+  *((BBS_TYPE *) Ptr) = BBS_FLOPPY;\r
+  Ptr += sizeof (BBS_TYPE);\r
+  *((UINT16 *) Ptr) = (UINT16) (sizeof (UINT16) + FDCount * sizeof (UINT16));\r
+  Ptr += sizeof (UINT16);\r
+  if (FDCount) {\r
+    Ptr = (UINT8 *) BdsFillDevOrderBuf (BbsTable, BBS_FLOPPY, BbsCount, (UINT16 *) Ptr);\r
+  }\r
+\r
+  *((BBS_TYPE *) Ptr) = BBS_HARDDISK;\r
+  Ptr += sizeof (BBS_TYPE);\r
+  *((UINT16 *) Ptr) = (UINT16) (sizeof (UINT16) + HDCount * sizeof (UINT16));\r
+  Ptr += sizeof (UINT16);\r
+  if (HDCount) {\r
+    Ptr = (UINT8 *) BdsFillDevOrderBuf (BbsTable, BBS_HARDDISK, BbsCount, (UINT16 *) Ptr);\r
+  }\r
+\r
+  *((BBS_TYPE *) Ptr) = BBS_CDROM;\r
+  Ptr += sizeof (BBS_TYPE);\r
+  *((UINT16 *) Ptr) = (UINT16) (sizeof (UINT16) + CDCount * sizeof (UINT16));\r
+  Ptr += sizeof (UINT16);\r
+  if (CDCount) {\r
+    Ptr = (UINT8 *) BdsFillDevOrderBuf (BbsTable, BBS_CDROM, BbsCount, (UINT16 *) Ptr);\r
+  }\r
+\r
+  *((BBS_TYPE *) Ptr) = BBS_EMBED_NETWORK;\r
+  Ptr += sizeof (BBS_TYPE);\r
+  *((UINT16 *) Ptr) = (UINT16) (sizeof (UINT16) + NETCount * sizeof (UINT16));\r
+  Ptr += sizeof (UINT16);\r
+  if (NETCount) {\r
+    Ptr = (UINT8 *) BdsFillDevOrderBuf (BbsTable, BBS_EMBED_NETWORK, BbsCount, (UINT16 *) Ptr);\r
+  }\r
+\r
+  *((BBS_TYPE *) Ptr) = BBS_BEV_DEVICE;\r
+  Ptr += sizeof (BBS_TYPE);\r
+  *((UINT16 *) Ptr) = (UINT16) (sizeof (UINT16) + BEVCount * sizeof (UINT16));\r
+  Ptr += sizeof (UINT16);\r
+  if (BEVCount) {\r
+    Ptr = (UINT8 *) BdsFillDevOrderBuf (BbsTable, BBS_BEV_DEVICE, BbsCount, (UINT16 *) Ptr);\r
+  }\r
+\r
+  Status = gRT->SetVariable (\r
+                  VarLegacyDevOrder,\r
+                  &EfiLegacyDevOrderGuid,\r
+                  VAR_FLAG,\r
+                  TotalSize,\r
+                  DevOrder\r
+                  );\r
+  SafeFreePool (DevOrder);\r
+\r
+  return Status;\r
+}\r
+\r
+EFI_STATUS\r
+BdsUpdateLegacyDevOrder (\r
+  VOID\r
+  )\r
+/*++\r
+Format of LegacyDevOrder variable:\r
+|-----------------------------------------------------------------------------------------------------------------\r
+| BBS_FLOPPY | Length | Index0 | Index1 | ... | BBS_HARDDISK | Length | Index0 | Index1 | ... | BBS_CDROM | Length | Index0 | ...\r
+|-----------------------------------------------------------------------------------------------------------------\r
+\r
+Length is a 16 bit integer, it indicates how many Indexes follows, including the size of itself.\r
+Index# is a 16 bit integer, the low byte of it stands for the index in BBS table\r
+           the high byte of it only have two value 0 and 0xFF, 0xFF means this device has been\r
+           disabled by user.\r
+--*/\r
+{\r
+  UINT8                     *DevOrder;\r
+  UINT8                     *NewDevOrder;\r
+  UINTN                     DevOrderSize;\r
+  EFI_LEGACY_BIOS_PROTOCOL  *LegacyBios;\r
+  EFI_STATUS                Status;\r
+  UINT16                    HddCount;\r
+  UINT16                    BbsCount;\r
+  HDD_INFO                  *LocalHddInfo;\r
+  BBS_TABLE                 *LocalBbsTable;\r
+  UINTN                     Index;\r
+  UINTN                     Index2;\r
+  UINTN                     *Idx;\r
+  UINTN                     FDCount;\r
+  UINTN                     HDCount;\r
+  UINTN                     CDCount;\r
+  UINTN                     NETCount;\r
+  UINTN                     BEVCount;\r
+  UINTN                     TotalSize;\r
+  UINTN                     HeaderSize;\r
+  UINT8                     *Ptr;\r
+  UINT8                     *NewPtr;\r
+  UINT16                    *NewFDPtr;\r
+  UINT16                    *NewHDPtr;\r
+  UINT16                    *NewCDPtr;\r
+  UINT16                    *NewNETPtr;\r
+  UINT16                    *NewBEVPtr;\r
+  UINT16                    *NewDevPtr;\r
+  UINT16                    Length;\r
+  UINT16                    tmp;\r
+  UINTN                     FDIndex;\r
+  UINTN                     HDIndex;\r
+  UINTN                     CDIndex;\r
+  UINTN                     NETIndex;\r
+  UINTN                     BEVIndex;\r
+\r
+  LocalHddInfo  = NULL;\r
+  LocalBbsTable = NULL;\r
+  Idx           = NULL;\r
+  FDCount       = 0;\r
+  HDCount       = 0;\r
+  CDCount       = 0;\r
+  NETCount      = 0;\r
+  BEVCount      = 0;\r
+  TotalSize     = 0;\r
+  HeaderSize    = sizeof (BBS_TYPE) + sizeof (UINT16);\r
+  FDIndex       = 0;\r
+  HDIndex       = 0;\r
+  CDIndex       = 0;\r
+  NETIndex      = 0;\r
+  BEVIndex      = 0;\r
+  NewDevPtr     = NULL;\r
+\r
+  Status        = EfiLibLocateProtocol (&gEfiLegacyBiosProtocolGuid, &LegacyBios);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  LegacyBios->GetBbsInfo (\r
+                LegacyBios,\r
+                &HddCount,\r
+                &LocalHddInfo,\r
+                &BbsCount,\r
+                &LocalBbsTable\r
+                );\r
+\r
+  DevOrder = (UINT8 *) BdsLibGetVariableAndSize (\r
+                        VarLegacyDevOrder,\r
+                        &EfiLegacyDevOrderGuid,\r
+                        &DevOrderSize\r
+                        );\r
+  if (NULL == DevOrder) {\r
+    return BdsCreateDevOrder (LocalBbsTable, BbsCount);\r
+  }\r
+  //\r
+  // First we figure out how many boot devices with same device type respectively\r
+  //\r
+  for (Index = 0; Index < BbsCount; Index++) {\r
+    if ((LocalBbsTable[Index].BootPriority == BBS_IGNORE_ENTRY) ||\r
+        (LocalBbsTable[Index].BootPriority == BBS_DO_NOT_BOOT_FROM) ||\r
+        (LocalBbsTable[Index].BootPriority == BBS_LOWEST_PRIORITY)\r
+        ) {\r
+      continue;\r
+    }\r
+\r
+    switch (LocalBbsTable[Index].DeviceType) {\r
+    case BBS_FLOPPY:\r
+      FDCount++;\r
+      break;\r
+\r
+    case BBS_HARDDISK:\r
+      HDCount++;\r
+      break;\r
+\r
+    case BBS_CDROM:\r
+      CDCount++;\r
+      break;\r
+\r
+    case BBS_EMBED_NETWORK:\r
+      NETCount++;\r
+      break;\r
+\r
+    case BBS_BEV_DEVICE:\r
+      BEVCount++;\r
+      break;\r
+\r
+    default:\r
+      break;\r
+    }\r
+  }\r
+\r
+  TotalSize += (HeaderSize + FDCount * sizeof (UINT16));\r
+  TotalSize += (HeaderSize + HDCount * sizeof (UINT16));\r
+  TotalSize += (HeaderSize + CDCount * sizeof (UINT16));\r
+  TotalSize += (HeaderSize + NETCount * sizeof (UINT16));\r
+  TotalSize += (HeaderSize + BEVCount * sizeof (UINT16));\r
+\r
+  NewDevOrder = AllocateZeroPool (TotalSize);\r
+  if (NULL == NewDevOrder) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  NewFDPtr  = (UINT16 *) (NewDevOrder + HeaderSize);\r
+  NewHDPtr  = (UINT16 *) ((UINT8 *) NewFDPtr + FDCount * sizeof (UINT16) + HeaderSize);\r
+  NewCDPtr  = (UINT16 *) ((UINT8 *) NewHDPtr + HDCount * sizeof (UINT16) + HeaderSize);\r
+  NewNETPtr = (UINT16 *) ((UINT8 *) NewCDPtr + CDCount * sizeof (UINT16) + HeaderSize);\r
+  NewBEVPtr = (UINT16 *) ((UINT8 *) NewNETPtr + NETCount * sizeof (UINT16) + HeaderSize);\r
+\r
+  //\r
+  // copy FD\r
+  //\r
+  Ptr                     = DevOrder;\r
+  NewPtr                  = NewDevOrder;\r
+  *((BBS_TYPE *) NewPtr)  = *((BBS_TYPE *) Ptr);\r
+  Ptr += sizeof (BBS_TYPE);\r
+  NewPtr += sizeof (BBS_TYPE);\r
+  Length                = *((UINT16 *) Ptr);\r
+  *((UINT16 *) NewPtr)  = (UINT16) (sizeof (UINT16) + FDCount * sizeof (UINT16));\r
+  Ptr += sizeof (UINT16);\r
+\r
+  for (Index = 0; Index < Length / sizeof (UINT16) - 1; Index++) {\r
+    if (LocalBbsTable[*Ptr].BootPriority == BBS_IGNORE_ENTRY ||\r
+        LocalBbsTable[*Ptr].BootPriority == BBS_DO_NOT_BOOT_FROM ||\r
+        LocalBbsTable[*Ptr].BootPriority == BBS_LOWEST_PRIORITY ||\r
+        LocalBbsTable[*Ptr].DeviceType != BBS_FLOPPY\r
+        ) {\r
+      Ptr += sizeof (UINT16);\r
+      continue;\r
+    }\r
+\r
+    NewFDPtr[FDIndex] = *(UINT16 *) Ptr;\r
+    FDIndex++;\r
+    Ptr += sizeof (UINT16);\r
+  }\r
+  //\r
+  // copy HD\r
+  //\r
+  NewPtr                  = (UINT8 *) NewHDPtr - HeaderSize;\r
+  *((BBS_TYPE *) NewPtr)  = *((BBS_TYPE *) Ptr);\r
+  Ptr += sizeof (BBS_TYPE);\r
+  NewPtr += sizeof (BBS_TYPE);\r
+  Length                = *((UINT16 *) Ptr);\r
+  *((UINT16 *) NewPtr)  = (UINT16) (sizeof (UINT16) + HDCount * sizeof (UINT16));\r
+  Ptr += sizeof (UINT16);\r
+\r
+  for (Index = 0; Index < Length / sizeof (UINT16) - 1; Index++) {\r
+    if (LocalBbsTable[*Ptr].BootPriority == BBS_IGNORE_ENTRY ||\r
+        LocalBbsTable[*Ptr].BootPriority == BBS_DO_NOT_BOOT_FROM ||\r
+        LocalBbsTable[*Ptr].BootPriority == BBS_LOWEST_PRIORITY ||\r
+        LocalBbsTable[*Ptr].DeviceType != BBS_HARDDISK\r
+        ) {\r
+      Ptr += sizeof (UINT16);\r
+      continue;\r
+    }\r
+\r
+    NewHDPtr[HDIndex] = *(UINT16 *) Ptr;\r
+    HDIndex++;\r
+    Ptr += sizeof (UINT16);\r
+  }\r
+  //\r
+  // copy CD\r
+  //\r
+  NewPtr                  = (UINT8 *) NewCDPtr - HeaderSize;\r
+  *((BBS_TYPE *) NewPtr)  = *((BBS_TYPE *) Ptr);\r
+  Ptr += sizeof (BBS_TYPE);\r
+  NewPtr += sizeof (BBS_TYPE);\r
+  Length                = *((UINT16 *) Ptr);\r
+  *((UINT16 *) NewPtr)  = (UINT16) (sizeof (UINT16) + CDCount * sizeof (UINT16));\r
+  Ptr += sizeof (UINT16);\r
+\r
+  for (Index = 0; Index < Length / sizeof (UINT16) - 1; Index++) {\r
+    if (LocalBbsTable[*Ptr].BootPriority == BBS_IGNORE_ENTRY ||\r
+        LocalBbsTable[*Ptr].BootPriority == BBS_DO_NOT_BOOT_FROM ||\r
+        LocalBbsTable[*Ptr].BootPriority == BBS_LOWEST_PRIORITY ||\r
+        LocalBbsTable[*Ptr].DeviceType != BBS_CDROM\r
+        ) {\r
+      Ptr += sizeof (UINT16);\r
+      continue;\r
+    }\r
+\r
+    NewCDPtr[CDIndex] = *(UINT16 *) Ptr;\r
+    CDIndex++;\r
+    Ptr += sizeof (UINT16);\r
+  }\r
+  //\r
+  // copy NET\r
+  //\r
+  NewPtr                  = (UINT8 *) NewNETPtr - HeaderSize;\r
+  *((BBS_TYPE *) NewPtr)  = *((BBS_TYPE *) Ptr);\r
+  Ptr += sizeof (BBS_TYPE);\r
+  NewPtr += sizeof (BBS_TYPE);\r
+  Length                = *((UINT16 *) Ptr);\r
+  *((UINT16 *) NewPtr)  = (UINT16) (sizeof (UINT16) + NETCount * sizeof (UINT16));\r
+  Ptr += sizeof (UINT16);\r
+\r
+  for (Index = 0; Index < Length / sizeof (UINT16) - 1; Index++) {\r
+    if (LocalBbsTable[*Ptr].BootPriority == BBS_IGNORE_ENTRY ||\r
+        LocalBbsTable[*Ptr].BootPriority == BBS_DO_NOT_BOOT_FROM ||\r
+        LocalBbsTable[*Ptr].BootPriority == BBS_LOWEST_PRIORITY ||\r
+        LocalBbsTable[*Ptr].DeviceType != BBS_EMBED_NETWORK\r
+        ) {\r
+      Ptr += sizeof (UINT16);\r
+      continue;\r
+    }\r
+\r
+    NewNETPtr[NETIndex] = *(UINT16 *) Ptr;\r
+    NETIndex++;\r
+    Ptr += sizeof (UINT16);\r
+  }\r
+  //\r
+  // copy BEV\r
+  //\r
+  NewPtr                  = (UINT8 *) NewBEVPtr - HeaderSize;\r
+  *((BBS_TYPE *) NewPtr)  = *((BBS_TYPE *) Ptr);\r
+  Ptr += sizeof (BBS_TYPE);\r
+  NewPtr += sizeof (BBS_TYPE);\r
+  Length                = *((UINT16 *) Ptr);\r
+  *((UINT16 *) NewPtr)  = (UINT16) (sizeof (UINT16) + BEVCount * sizeof (UINT16));\r
+  Ptr += sizeof (UINT16);\r
+\r
+  for (Index = 0; Index < Length / sizeof (UINT16) - 1; Index++) {\r
+    if (LocalBbsTable[*Ptr].BootPriority == BBS_IGNORE_ENTRY ||\r
+        LocalBbsTable[*Ptr].BootPriority == BBS_DO_NOT_BOOT_FROM ||\r
+        LocalBbsTable[*Ptr].BootPriority == BBS_LOWEST_PRIORITY ||\r
+        LocalBbsTable[*Ptr].DeviceType != BBS_BEV_DEVICE\r
+        ) {\r
+      Ptr += sizeof (UINT16);\r
+      continue;\r
+    }\r
+\r
+    NewBEVPtr[BEVIndex] = *(UINT16 *) Ptr;\r
+    BEVIndex++;\r
+    Ptr += sizeof (UINT16);\r
+  }\r
+\r
+  for (Index = 0; Index < BbsCount; Index++) {\r
+    if ((LocalBbsTable[Index].BootPriority == BBS_IGNORE_ENTRY) ||\r
+        (LocalBbsTable[Index].BootPriority == BBS_DO_NOT_BOOT_FROM) ||\r
+        (LocalBbsTable[Index].BootPriority == BBS_LOWEST_PRIORITY)\r
+        ) {\r
+      continue;\r
+    }\r
+\r
+    switch (LocalBbsTable[Index].DeviceType) {\r
+    case BBS_FLOPPY:\r
+      Idx       = &FDIndex;\r
+      NewDevPtr = NewFDPtr;\r
+      break;\r
+\r
+    case BBS_HARDDISK:\r
+      Idx       = &HDIndex;\r
+      NewDevPtr = NewHDPtr;\r
+      break;\r
+\r
+    case BBS_CDROM:\r
+      Idx       = &CDIndex;\r
+      NewDevPtr = NewCDPtr;\r
+      break;\r
+\r
+    case BBS_EMBED_NETWORK:\r
+      Idx       = &NETIndex;\r
+      NewDevPtr = NewNETPtr;\r
+      break;\r
+\r
+    case BBS_BEV_DEVICE:\r
+      Idx       = &BEVIndex;\r
+      NewDevPtr = NewBEVPtr;\r
+      break;\r
+\r
+    default:\r
+      Idx = NULL;\r
+      break;\r
+    }\r
+    //\r
+    // at this point we have copied those valid indexes to new buffer\r
+    // and we should check if there is any new appeared boot device\r
+    //\r
+    if (Idx) {\r
+      for (Index2 = 0; Index2 < *Idx; Index2++) {\r
+        if ((NewDevPtr[Index2] & 0xFF) == (UINT16) Index) {\r
+          break;\r
+        }\r
+      }\r
+\r
+      if (Index2 == *Idx) {\r
+        //\r
+        // Index2 == *Idx means we didn't find Index\r
+        // so Index is a new appeared device's index in BBS table\r
+        // save it.\r
+        //\r
+        NewDevPtr[*Idx] = (UINT16) (Index & 0xFF);\r
+        (*Idx)++;\r
+      }\r
+    }\r
+  }\r
+\r
+  if (FDCount) {\r
+    //\r
+    // Just to make sure that disabled indexes are all at the end of the array\r
+    //\r
+    for (Index = 0; Index < FDIndex - 1; Index++) {\r
+      if (0xFF00 != (NewFDPtr[Index] & 0xFF00)) {\r
+        continue;\r
+      }\r
+\r
+      for (Index2 = Index + 1; Index2 < FDIndex; Index2++) {\r
+        if (0 == (NewFDPtr[Index2] & 0xFF00)) {\r
+          tmp               = NewFDPtr[Index];\r
+          NewFDPtr[Index]   = NewFDPtr[Index2];\r
+          NewFDPtr[Index2]  = tmp;\r
+          break;\r
+        }\r
+      }\r
+    }\r
+  }\r
+\r
+  if (HDCount) {\r
+    //\r
+    // Just to make sure that disabled indexes are all at the end of the array\r
+    //\r
+    for (Index = 0; Index < HDIndex - 1; Index++) {\r
+      if (0xFF00 != (NewHDPtr[Index] & 0xFF00)) {\r
+        continue;\r
+      }\r
+\r
+      for (Index2 = Index + 1; Index2 < HDIndex; Index2++) {\r
+        if (0 == (NewHDPtr[Index2] & 0xFF00)) {\r
+          tmp               = NewHDPtr[Index];\r
+          NewHDPtr[Index]   = NewHDPtr[Index2];\r
+          NewHDPtr[Index2]  = tmp;\r
+          break;\r
+        }\r
+      }\r
+    }\r
+  }\r
+\r
+  if (CDCount) {\r
+    //\r
+    // Just to make sure that disabled indexes are all at the end of the array\r
+    //\r
+    for (Index = 0; Index < CDIndex - 1; Index++) {\r
+      if (0xFF00 != (NewCDPtr[Index] & 0xFF00)) {\r
+        continue;\r
+      }\r
+\r
+      for (Index2 = Index + 1; Index2 < CDIndex; Index2++) {\r
+        if (0 == (NewCDPtr[Index2] & 0xFF00)) {\r
+          tmp               = NewCDPtr[Index];\r
+          NewCDPtr[Index]   = NewCDPtr[Index2];\r
+          NewCDPtr[Index2]  = tmp;\r
+          break;\r
+        }\r
+      }\r
+    }\r
+  }\r
+\r
+  if (NETCount) {\r
+    //\r
+    // Just to make sure that disabled indexes are all at the end of the array\r
+    //\r
+    for (Index = 0; Index < NETIndex - 1; Index++) {\r
+      if (0xFF00 != (NewNETPtr[Index] & 0xFF00)) {\r
+        continue;\r
+      }\r
+\r
+      for (Index2 = Index + 1; Index2 < NETIndex; Index2++) {\r
+        if (0 == (NewNETPtr[Index2] & 0xFF00)) {\r
+          tmp               = NewNETPtr[Index];\r
+          NewNETPtr[Index]  = NewNETPtr[Index2];\r
+          NewNETPtr[Index2] = tmp;\r
+          break;\r
+        }\r
+      }\r
+    }\r
+  }\r
+\r
+  if (BEVCount) {\r
+    //\r
+    // Just to make sure that disabled indexes are all at the end of the array\r
+    //\r
+    for (Index = 0; Index < BEVIndex - 1; Index++) {\r
+      if (0xFF00 != (NewBEVPtr[Index] & 0xFF00)) {\r
+        continue;\r
+      }\r
+\r
+      for (Index2 = Index + 1; Index2 < BEVIndex; Index2++) {\r
+        if (0 == (NewBEVPtr[Index2] & 0xFF00)) {\r
+          tmp               = NewBEVPtr[Index];\r
+          NewBEVPtr[Index]  = NewBEVPtr[Index2];\r
+          NewBEVPtr[Index2] = tmp;\r
+          break;\r
+        }\r
+      }\r
+    }\r
+  }\r
+\r
+  SafeFreePool (DevOrder);\r
+\r
+  Status = gRT->SetVariable (\r
+                  VarLegacyDevOrder,\r
+                  &EfiLegacyDevOrderGuid,\r
+                  VAR_FLAG,\r
+                  TotalSize,\r
+                  NewDevOrder\r
+                  );\r
+  SafeFreePool (NewDevOrder);\r
+\r
+  return Status;\r
+}\r
+\r
+EFI_STATUS\r
+BdsSetBootPriority4SameTypeDev (\r
+  IN UINT16                                              DeviceType,\r
+  IN OUT BBS_TABLE                                       *LocalBbsTable,\r
+  IN OUT UINT16                                          *Priority\r
+  )\r
+/*++\r
+DeviceType           - BBS_FLOPPY, BBS_HARDDISK, BBS_CDROM and so on\r
+LocalBbsTable       - BBS table instance\r
+Priority                 - As input arg, it is the start point of boot priority, as output arg, it is the start point of boot\r
+                              priority can be used next time.\r
+--*/\r
+{\r
+  UINT8   *DevOrder;\r
+\r
+  UINT8   *OrigBuffer;\r
+  UINT16  *DevIndex;\r
+  UINTN   DevOrderSize;\r
+  UINTN   DevCount;\r
+  UINTN   Index;\r
+\r
+  DevOrder = BdsLibGetVariableAndSize (\r
+              VarLegacyDevOrder,\r
+              &EfiLegacyDevOrderGuid,\r
+              &DevOrderSize\r
+              );\r
+  if (NULL == DevOrder) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  OrigBuffer = DevOrder;\r
+  while (DevOrder < OrigBuffer + DevOrderSize) {\r
+    if (DeviceType == * (BBS_TYPE *) DevOrder) {\r
+      break;\r
+    }\r
+\r
+    DevOrder += sizeof (BBS_TYPE);\r
+    DevOrder += *(UINT16 *) DevOrder;\r
+  }\r
+\r
+  if (DevOrder >= OrigBuffer + DevOrderSize) {\r
+    SafeFreePool (OrigBuffer);\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  DevOrder += sizeof (BBS_TYPE);\r
+  DevCount  = (*((UINT16 *) DevOrder) - sizeof (UINT16)) / sizeof (UINT16);\r
+  DevIndex  = (UINT16 *) (DevOrder + sizeof (UINT16));\r
+  //\r
+  // If the high byte of the DevIndex is 0xFF, it indicates that this device has been disabled.\r
+  //\r
+  for (Index = 0; Index < DevCount; Index++) {\r
+    if ((DevIndex[Index] & 0xFF00) == 0xFF00) {\r
+      //\r
+      // LocalBbsTable[DevIndex[Index] & 0xFF].BootPriority = BBS_DISABLED_ENTRY;\r
+      //\r
+    } else {\r
+      LocalBbsTable[DevIndex[Index] & 0xFF].BootPriority = *Priority;\r
+      (*Priority)++;\r
+    }\r
+  }\r
+\r
+  SafeFreePool (OrigBuffer);\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+VOID\r
+PrintBbsTable (\r
+  IN BBS_TABLE                      *LocalBbsTable\r
+  )\r
+{\r
+  UINT16  Idx;\r
+\r
+  DEBUG ((EFI_D_ERROR, "\n"));\r
+  DEBUG ((EFI_D_ERROR, " NO  Prio bb/dd/ff cl/sc Type Stat segm:offs\n"));\r
+  DEBUG ((EFI_D_ERROR, "=============================================\n"));\r
+  for (Idx = 0; Idx < MAX_BBS_ENTRIES; Idx++) {\r
+    if ((LocalBbsTable[Idx].BootPriority == BBS_IGNORE_ENTRY) ||\r
+        (LocalBbsTable[Idx].BootPriority == BBS_DO_NOT_BOOT_FROM) ||\r
+        (LocalBbsTable[Idx].BootPriority == BBS_LOWEST_PRIORITY)\r
+        ) {\r
+      continue;\r
+    }\r
+\r
+    DEBUG (\r
+      (EFI_D_ERROR,\r
+      " %02x: %04x %02x/%02x/%02x %02x/02%x %04x %04x %04x:%04x\n",\r
+      (UINTN) Idx,\r
+      (UINTN) LocalBbsTable[Idx].BootPriority,\r
+      (UINTN) LocalBbsTable[Idx].Bus,\r
+      (UINTN) LocalBbsTable[Idx].Device,\r
+      (UINTN) LocalBbsTable[Idx].Function,\r
+      (UINTN) LocalBbsTable[Idx].Class,\r
+      (UINTN) LocalBbsTable[Idx].SubClass,\r
+      (UINTN) LocalBbsTable[Idx].DeviceType,\r
+      (UINTN) * (UINT16 *) &LocalBbsTable[Idx].StatusFlags,\r
+      (UINTN) LocalBbsTable[Idx].BootHandlerSegment,\r
+      (UINTN) LocalBbsTable[Idx].BootHandlerOffset,\r
+      (UINTN) ((LocalBbsTable[Idx].MfgStringSegment << 4) + LocalBbsTable[Idx].MfgStringOffset),\r
+      (UINTN) ((LocalBbsTable[Idx].DescStringSegment << 4) + LocalBbsTable[Idx].DescStringOffset))\r
+      );\r
+  }\r
+\r
+  DEBUG ((EFI_D_ERROR, "\n"));\r
+}\r
+\r
+EFI_STATUS\r
+BdsRefreshBbsTableForBoot (\r
+  IN BDS_COMMON_OPTION        *Entry\r
+  )\r
+{\r
+  EFI_STATUS                Status;\r
+  UINT16                    HddCount;\r
+  UINT16                    BbsCount;\r
+  HDD_INFO                  *LocalHddInfo;\r
+  BBS_TABLE                 *LocalBbsTable;\r
+  UINT16                    DevType;\r
+  EFI_LEGACY_BIOS_PROTOCOL  *LegacyBios;\r
+  UINTN                     Index;\r
+  UINT16                    Priority;\r
+  UINT16                    *BootOrder;\r
+  UINTN                     BootOrderSize;\r
+  UINT8                     *BootOptionVar;\r
+  UINTN                     BootOptionSize;\r
+  UINT16                    BootOption[100];\r
+  UINT8                     *Ptr;\r
+  UINT16                    DevPathLen;\r
+  EFI_DEVICE_PATH_PROTOCOL  *DevPath;\r
+\r
+  HddCount      = 0;\r
+  BbsCount      = 0;\r
+  LocalHddInfo  = NULL;\r
+  LocalBbsTable = NULL;\r
+  DevType       = BBS_UNKNOWN;\r
+\r
+  Status        = EfiLibLocateProtocol (&gEfiLegacyBiosProtocolGuid, &LegacyBios);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  LegacyBios->GetBbsInfo (\r
+                LegacyBios,\r
+                &HddCount,\r
+                &LocalHddInfo,\r
+                &BbsCount,\r
+                &LocalBbsTable\r
+                );\r
+  //\r
+  // First, set all the present devices' boot priority to BBS_UNPRIORITIZED_ENTRY\r
+  // We will set them according to the settings setup by user\r
+  //\r
+  for (Index = 0; Index < BbsCount; Index++) {\r
+    if (!((BBS_IGNORE_ENTRY == LocalBbsTable[Index].BootPriority) ||\r
+        (BBS_DO_NOT_BOOT_FROM == LocalBbsTable[Index].BootPriority) ||\r
+         (BBS_LOWEST_PRIORITY == LocalBbsTable[Index].BootPriority))) {\r
+      LocalBbsTable[Index].BootPriority = BBS_UNPRIORITIZED_ENTRY;\r
+    }\r
+  }\r
+  //\r
+  // boot priority always starts at 0\r
+  //\r
+  Priority = 0;\r
+  if (Entry->LoadOptionsSize == sizeof (BBS_TABLE) + sizeof (UINT16)) {\r
+    //\r
+    // If Entry stands for a legacy boot option, we prioritize the devices with the same type first.\r
+    //\r
+    DevType = ((BBS_TABLE *) Entry->LoadOptions)->DeviceType;\r
+    Status = BdsSetBootPriority4SameTypeDev (\r
+              DevType,\r
+              LocalBbsTable,\r
+              &Priority\r
+              );\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+  }\r
+  //\r
+  // we have to set the boot priority for other BBS entries with different device types\r
+  //\r
+  BootOrder = (UINT16 *) BdsLibGetVariableAndSize (\r
+                          L"BootOrder",\r
+                          &gEfiGlobalVariableGuid,\r
+                          &BootOrderSize\r
+                          );\r
+  for (Index = 0; BootOrder && Index < BootOrderSize / sizeof (UINT16); Index++) {\r
+    UnicodeSPrint (BootOption, sizeof (BootOption), L"Boot%04x", BootOrder[Index]);\r
+    BootOptionVar = BdsLibGetVariableAndSize (\r
+                      BootOption,\r
+                      &gEfiGlobalVariableGuid,\r
+                      &BootOptionSize\r
+                      );\r
+    if (NULL == BootOptionVar) {\r
+      continue;\r
+    }\r
+\r
+    Ptr = BootOptionVar;\r
+\r
+    Ptr += sizeof (UINT32);\r
+    DevPathLen = *(UINT16 *) Ptr;\r
+    Ptr += sizeof (UINT16);\r
+    Ptr += StrSize ((UINT16 *) Ptr);\r
+    DevPath = (EFI_DEVICE_PATH_PROTOCOL *) Ptr;\r
+    if (BBS_DEVICE_PATH != DevPath->Type || BBS_BBS_DP != DevPath->SubType) {\r
+      SafeFreePool (BootOptionVar);\r
+      continue;\r
+    }\r
+\r
+    Ptr += DevPathLen;\r
+    if (DevType == ((BBS_TABLE *) Ptr)->DeviceType) {\r
+      //\r
+      // We don't want to process twice for a device type\r
+      //\r
+      SafeFreePool (BootOptionVar);\r
+      continue;\r
+    }\r
+\r
+    Status = BdsSetBootPriority4SameTypeDev (\r
+              ((BBS_TABLE *) Ptr)->DeviceType,\r
+              LocalBbsTable,\r
+              &Priority\r
+              );\r
+    SafeFreePool (BootOptionVar);\r
+    if (EFI_ERROR (Status)) {\r
+      break;\r
+    }\r
+  }\r
+\r
+  if (BootOrder) {\r
+    SafeFreePool (BootOrder);\r
+  }\r
+  //\r
+  // For debug\r
+  //\r
+  PrintBbsTable (LocalBbsTable);\r
+\r
+  return Status;\r
+}\r