LegacyBootManagerLib is a NULL class library to work with UefiBootManagerLib
providing legacy boot support.

Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Ruiyu Ni <ruiyu...@intel.com>
---
 .../InternalLegacyBootManagerLib.h                 |   66 +
 .../LegacyBootManagerLib/LegacyBootManagerLib.c    | 1578 ++++++++++++++++++++
 .../LegacyBootManagerLib/LegacyBootManagerLib.inf  |   65 +
 3 files changed, 1709 insertions(+)
 create mode 100644 
IntelFrameworkModulePkg/Library/LegacyBootManagerLib/InternalLegacyBootManagerLib.h
 create mode 100644 
IntelFrameworkModulePkg/Library/LegacyBootManagerLib/LegacyBootManagerLib.c
 create mode 100644 
IntelFrameworkModulePkg/Library/LegacyBootManagerLib/LegacyBootManagerLib.inf

diff --git 
a/IntelFrameworkModulePkg/Library/LegacyBootManagerLib/InternalLegacyBootManagerLib.h
 
b/IntelFrameworkModulePkg/Library/LegacyBootManagerLib/InternalLegacyBootManagerLib.h
new file mode 100644
index 0000000..cf03186
--- /dev/null
+++ 
b/IntelFrameworkModulePkg/Library/LegacyBootManagerLib/InternalLegacyBootManagerLib.h
@@ -0,0 +1,66 @@
+/** @file
+
+Copyright (c) 2011 - 2013, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD 
License
+which accompanies this distribution.  The full text of the license may be 
found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _INTERNAL_LEGACY_BOOT_MANAGER_LIB_H_
+#define _INTERNAL_LEGACY_BOOT_MANAGER_LIB_H_
+
+#include <PiDxe.h>
+#include <Guid/LegacyDevOrder.h>
+#include <Guid/GlobalVariable.h>
+#include <Protocol/LegacyBios.h>
+#include <Protocol/PciRootBridgeIo.h>
+#include <Protocol/PciIo.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/UefiLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/UefiBootManagerLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/PrintLib.h>
+#include <Library/PerformanceLib.h>
+
+#pragma pack(1)
+typedef struct {
+  UINT16     BbsIndex;
+} LEGACY_BOOT_OPTION_BBS_DATA;
+#pragma pack()
+
+/**
+  Boot the legacy system with the boot option.
+
+  @param  BootOption The legacy boot option which have BBS device path
+                     On return, BootOption->Status contains the boot status.
+                     EFI_UNSUPPORTED    There is no legacybios protocol, do 
not support
+                                        legacy boot.
+                     EFI_STATUS         The status of LegacyBios->LegacyBoot 
().
+**/
+VOID
+EFIAPI
+LegacyBoot (
+  IN  EFI_BOOT_MANAGER_LOAD_OPTION           *BootOption
+  );
+
+/**
+  Refresh all legacy boot options.
+
+**/
+VOID
+EFIAPI
+LegacyBootManagerRefreshAllBootOption (
+  VOID
+  );
+
+#endif
diff --git 
a/IntelFrameworkModulePkg/Library/LegacyBootManagerLib/LegacyBootManagerLib.c 
b/IntelFrameworkModulePkg/Library/LegacyBootManagerLib/LegacyBootManagerLib.c
new file mode 100644
index 0000000..60f5a33
--- /dev/null
+++ 
b/IntelFrameworkModulePkg/Library/LegacyBootManagerLib/LegacyBootManagerLib.c
@@ -0,0 +1,1578 @@
+/** @file
+  This function deal with the legacy boot option, it create, delete
+  and manage the legacy boot option, all legacy boot option is getting from
+  the legacy BBS table.
+
+Copyright (c) 2011 - 2015, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD 
License
+which accompanies this distribution.  The full text of the license may be 
found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "InternalLegacyBootManagerLib.h"
+
+#define  BOOT_DESCRIPTION_LENGTH  32
+
+/**
+  Initialize legacy boot manager library by call 
EfiBootManagerRegisterLegacyBootSupport
+  function to export two function pointer.
+
+  @param ImageHandle     The image handle.
+  @param SystemTable     The system table.
+
+  @retval EFI_SUCCESS    The legacy boot manager library is initialized 
correctly.
+  @return Other value if failed to initialize the legacy boot manager library.
+**/
+EFI_STATUS
+EFIAPI
+LegacyBootManagerConstructor (
+  IN EFI_HANDLE                            ImageHandle,
+  IN EFI_SYSTEM_TABLE                      *SystemTable
+)
+{
+  EfiBootManagerRegisterLegacyBootSupport (
+    LegacyBootManagerRefreshAllBootOption,
+    LegacyBoot
+    );
+  return EFI_SUCCESS;
+}
+
+/**
+  Get the device type from the input legacy device path.
+
+  @param DevicePath     The legacy device path.
+
+  @retval               The legacy device type.
+**/
+UINT16
+LegacyDeviceType (
+  EFI_DEVICE_PATH_PROTOCOL *DevicePath
+  )
+{
+  ASSERT ((DevicePathType (DevicePath) == BBS_DEVICE_PATH) &&
+          (DevicePathSubType (DevicePath) == BBS_BBS_DP));
+  return ((BBS_BBS_DEVICE_PATH *) DevicePath)->DeviceType;
+}
+
+/**
+  Validate the BbsEntry base on the Boot Priority info in the BbsEntry.
+
+  @param BbsEntry       The input bbs entry info.
+
+  @retval TRUE          The BbsEntry is valid.
+  @retval FALSE         The BbsEntry is invalid.
+**/
+BOOLEAN
+ValidBbsEntry (
+  IN BBS_TABLE   *BbsEntry
+  )
+{
+  switch (BbsEntry->BootPriority) {
+    case BBS_IGNORE_ENTRY:
+    case BBS_DO_NOT_BOOT_FROM:
+    case BBS_LOWEST_PRIORITY:
+      return FALSE;
+    default:
+      return TRUE;
+  }
+}
+
+/**
+  Build Legacy Device Name String according.
+
+  @param CurBBSEntry     BBS Table.
+  @param Index           Index.
+  @param BufSize         The buffer size.
+  @param BootString      The output string.
+
+**/
+VOID
+BuildLegacyDevNameString (
+  IN  BBS_TABLE                 *CurBBSEntry,
+  IN  UINTN                     Index,
+  IN  UINTN                     BufSize,
+  OUT CHAR16                    *BootString
+  )
+{
+  CHAR16  *Fmt;
+  CHAR16  *Type;
+  CHAR8   *StringDesc;
+  CHAR8   StringBufferA[BOOT_DESCRIPTION_LENGTH + 1];
+  CHAR16  StringBufferU[BOOT_DESCRIPTION_LENGTH + 1];
+
+  switch (Index) {
+  //
+  // Primary Master
+  //
+  case 1:
+    Fmt = L"Primary Master %s";
+    break;
+
+ //
+ // Primary Slave
+ //
+  case 2:
+    Fmt = L"Primary Slave %s";
+    break;
+
+  //
+  // Secondary Master
+  //
+  case 3:
+    Fmt = L"Secondary Master %s";
+    break;
+
+  //
+  // Secondary Slave
+  //
+  case 4:
+    Fmt = L"Secondary Slave %s";
+    break;
+
+  default:
+    Fmt = L"%s";
+    break;
+  }
+
+  switch (CurBBSEntry->DeviceType) {
+  case BBS_FLOPPY:
+    Type = L"Floppy";
+    break;
+
+  case BBS_HARDDISK:
+    Type = L"Harddisk";
+    break;
+
+  case BBS_CDROM:
+    Type = L"CDROM";
+    break;
+
+  case BBS_PCMCIA:
+    Type = L"PCMCIAe";
+    break;
+
+  case BBS_USB:
+    Type = L"USB";
+    break;
+
+  case BBS_EMBED_NETWORK:
+    Type = L"Network";
+    break;
+
+  case BBS_BEV_DEVICE:
+    Type = L"BEVe";
+    break;
+
+  case BBS_UNKNOWN:
+  default:
+    Type = L"Unknown";
+    break;
+  }
+  //
+  // If current BBS entry has its description then use it.
+  //
+  StringDesc = (CHAR8 *) (UINTN) ((CurBBSEntry->DescStringSegment << 4) + 
CurBBSEntry->DescStringOffset);
+  if (NULL != StringDesc) {
+    //
+    // Only get fisrt 32 characters, this is suggested by BBS spec
+    //
+    CopyMem (StringBufferA, StringDesc, BOOT_DESCRIPTION_LENGTH);
+    StringBufferA[BOOT_DESCRIPTION_LENGTH] = 0;
+    AsciiStrToUnicodeStr (StringBufferA, StringBufferU);
+    Fmt   = L"%s";
+    Type  = StringBufferU;
+  }
+
+  //
+  // BbsTable 16 entries are for onboard IDE.
+  // Set description string for SATA harddisks, Harddisk 0 ~ Harddisk 11
+  //
+  if (Index >= 5 && Index <= 16 && (CurBBSEntry->DeviceType == BBS_HARDDISK || 
CurBBSEntry->DeviceType == BBS_CDROM)) {
+    Fmt = L"%s %d";
+    UnicodeSPrint (BootString, BufSize, Fmt, Type, Index - 5);
+  } else {
+    UnicodeSPrint (BootString, BufSize, Fmt, Type);
+  }
+}
+
+/**
+  Get the Bbs index for the input boot option.
+
+  @param BootOption     The input boot option info.
+  @param BbsTable       The input Bbs table.
+  @param BbsCount       The input total bbs entry number.
+  @param BbsIndexUsed   The array shows how many BBS table indexs have been 
used.
+
+  @retval The index for the input boot option.
+**/
+UINT16
+FuzzyMatch (
+  EFI_BOOT_MANAGER_LOAD_OPTION  *BootOption,
+  BBS_TABLE                     *BbsTable,
+  UINT16                        BbsCount,
+  BOOLEAN                       *BbsIndexUsed
+  )
+{
+  UINT16                        Index;
+  LEGACY_BOOT_OPTION_BBS_DATA   *BbsData;
+  CHAR16                        Description[BOOT_DESCRIPTION_LENGTH + 1];
+
+  BbsData = (LEGACY_BOOT_OPTION_BBS_DATA *) BootOption->OptionalData;
+
+  //
+  // Directly check the BBS index stored in BootOption
+  //
+  if ((BbsData->BbsIndex < BbsCount) &&
+      (LegacyDeviceType (BootOption->FilePath) == 
BbsTable[BbsData->BbsIndex].DeviceType)) {
+    BuildLegacyDevNameString (
+      &BbsTable[BbsData->BbsIndex],
+      BbsData->BbsIndex,
+      sizeof (Description),
+      Description
+      );
+    if ((StrCmp (Description, BootOption->Description) == 0) && 
!BbsIndexUsed[BbsData->BbsIndex]) {
+      //
+      // If devices with the same description string are connected, 
+      // the BbsIndex of the first device is returned for the other device 
also.
+      // So, check if the BbsIndex is already being used, before assigning the 
BbsIndex.
+      //
+      BbsIndexUsed[BbsData->BbsIndex] = TRUE;
+      return BbsData->BbsIndex;
+    }
+  }
+
+  //
+  // BBS table could be changed (entry removed/moved)
+  // find the correct BBS index
+  //
+  for (Index = 0; Index < BbsCount; Index++) {
+    if (!ValidBbsEntry (&BbsTable[Index]) ||
+        (BbsTable[Index].DeviceType != LegacyDeviceType 
(BootOption->FilePath))) {
+      continue;
+    }
+
+    BuildLegacyDevNameString (
+      &BbsTable[Index],
+      Index,
+      sizeof (Description),
+      Description
+      );
+    if ((StrCmp (Description, BootOption->Description) == 0) && 
!BbsIndexUsed[Index]) {
+      //
+      // If devices with the same description string are connected, 
+      // the BbsIndex of the first device is assigned for the other device 
also.
+      // So, check if the BbsIndex is already being used, before assigning the 
corrected BbsIndex.
+      //
+      break;
+    }
+  }
+
+  //
+  // Add the corrected BbsIndex in the UsedBbsIndex Buffer
+  //
+  if (Index != BbsCount) {
+    BbsIndexUsed[Index] = TRUE;
+  }
+
+  return Index;
+}
+
+/**
+
+  Update legacy device order base on the input info.
+
+  @param   LegacyDevOrder     Legacy device order data buffer.
+  @param   LegacyDevOrderSize Legacy device order data buffer size.
+  @param   DeviceType         Device type which need to check.
+  @param   OldBbsIndex        Old Bds Index.
+  @param   NewBbsIndex        New Bds Index, if it is -1,means remove this 
option.
+
+**/
+VOID
+UpdateBbsIndex (
+  LEGACY_DEV_ORDER_ENTRY   *LegacyDevOrder,
+  UINTN                    *LegacyDevOrderSize,
+  UINT16                   DeviceType,
+  UINT16                   OldBbsIndex,
+  UINT16                   NewBbsIndex // Delete entry if -1
+  )
+{
+  LEGACY_DEV_ORDER_ENTRY   *Entry;
+  UINTN                    Index;
+
+  ASSERT (((LegacyDevOrder == NULL) && (*LegacyDevOrderSize == 0)) ||
+          ((LegacyDevOrder != NULL) && (*LegacyDevOrderSize != 0))
+         );
+
+  for (Entry = LegacyDevOrder; 
+       Entry < (LEGACY_DEV_ORDER_ENTRY *) ((UINT8 *) LegacyDevOrder + 
*LegacyDevOrderSize);
+       Entry = (LEGACY_DEV_ORDER_ENTRY *) ((UINTN) Entry + sizeof (BBS_TYPE) + 
Entry->Length)
+       ) {
+    if (Entry->BbsType == DeviceType) {
+      for (Index = 0; Index < Entry->Length / sizeof (UINT16) - 1; Index++) {
+        if (Entry->Data[Index] == OldBbsIndex) {
+          if (NewBbsIndex == (UINT16) -1) {
+            //
+            // Delete the old entry
+            //
+            CopyMem (
+              &Entry->Data[Index], 
+              &Entry->Data[Index + 1], 
+              (UINT8 *) LegacyDevOrder + *LegacyDevOrderSize - (UINT8 *) 
&Entry->Data[Index + 1]
+              );
+            Entry->Length       -= sizeof (UINT16);
+            *LegacyDevOrderSize -= sizeof(UINT16);
+          } else {
+            Entry->Data[Index]   = NewBbsIndex;
+          }
+          break;
+        }
+      }
+      break;
+    }
+  }
+}
+
+/**
+  Delete all the legacy boot options.
+
+  @retval EFI_SUCCESS            All legacy boot options are deleted.
+**/
+EFI_STATUS
+DeleteAllLegacyBootOptions (
+  VOID
+  )
+{
+  EFI_STATUS                    Status;
+  UINTN                         Index;
+  EFI_BOOT_MANAGER_LOAD_OPTION  *BootOption;
+  UINTN                         BootOptionCount;
+
+  BootOption = EfiBootManagerGetLoadOptions (&BootOptionCount, 
LoadOptionTypeBoot);
+  for (Index = 0; Index < BootOptionCount; Index++) {
+    if ((DevicePathType (BootOption[Index].FilePath) == BBS_DEVICE_PATH) &&
+        (DevicePathSubType (BootOption[Index].FilePath) == BBS_BBS_DP)) {
+      Status = EfiBootManagerDeleteLoadOptionVariable 
(BootOption[Index].OptionNumber, BootOption[Index].OptionType);
+      //
+      // Deleting variable with current variable implementation shouldn't fail.
+      //
+      ASSERT_EFI_ERROR (Status);
+    }
+  }
+
+  Status = gRT->SetVariable (
+                  VAR_LEGACY_DEV_ORDER,
+                  &gEfiLegacyDevOrderVariableGuid,
+                  0,
+                  0,
+                  NULL
+                  );
+  //
+  // Deleting variable with current variable implementation shouldn't fail.
+  //
+  ASSERT (Status == EFI_SUCCESS || Status == EFI_NOT_FOUND);
+
+  return EFI_SUCCESS;
+}
+
+
+/**
+  Delete all the invalid legacy boot options.
+
+  @retval EFI_SUCCESS             All invalide legacy boot options are deleted.
+  @retval EFI_OUT_OF_RESOURCES    Fail to allocate necessary memory.
+  @retval EFI_NOT_FOUND           Fail to retrive variable of boot order.
+**/
+EFI_STATUS
+DeleteAllInvalidLegacyBootOptions (
+  VOID
+  )
+{
+  EFI_STATUS                    Status;
+  UINT16                        HddCount;
+  UINT16                        BbsCount;
+  HDD_INFO                      *HddInfo;
+  BBS_TABLE                     *BbsTable;
+  UINT16                        BbsIndex;
+  EFI_LEGACY_BIOS_PROTOCOL      *LegacyBios;
+  UINTN                         Index;
+  EFI_BOOT_MANAGER_LOAD_OPTION  *BootOption;
+  UINTN                         BootOptionCount;
+  LEGACY_DEV_ORDER_ENTRY        *LegacyDevOrder;
+  UINTN                         LegacyDevOrderSize;
+  BOOLEAN                       *BbsIndexUsed;
+
+  HddCount      = 0;
+  BbsCount      = 0;
+  HddInfo       = NULL;
+  BbsTable      = NULL;
+
+  Status        = gBS->LocateProtocol (&gEfiLegacyBiosProtocolGuid, NULL, 
(VOID **) &LegacyBios);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  Status = LegacyBios->GetBbsInfo (
+                         LegacyBios,
+                         &HddCount,
+                         &HddInfo,
+                         &BbsCount,
+                         &BbsTable
+                         );
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  GetVariable2 (VAR_LEGACY_DEV_ORDER, &gEfiLegacyDevOrderVariableGuid, (VOID 
**) &LegacyDevOrder, &LegacyDevOrderSize);
+
+  BootOption = EfiBootManagerGetLoadOptions (&BootOptionCount, 
LoadOptionTypeBoot);
+
+  BbsIndexUsed = AllocateZeroPool (BbsCount * sizeof (BOOLEAN));
+  ASSERT (BbsIndexUsed != NULL);
+
+  for (Index = 0; Index < BootOptionCount; Index++) {
+    //
+    // Skip non legacy boot option
+    //
+    if ((DevicePathType (BootOption[Index].FilePath) != BBS_DEVICE_PATH) ||
+        (DevicePathSubType (BootOption[Index].FilePath) != BBS_BBS_DP)) {
+      continue;
+    }
+
+    BbsIndex = FuzzyMatch (&BootOption[Index], BbsTable, BbsCount, 
BbsIndexUsed);
+    if (BbsIndex == BbsCount) {
+      DEBUG ((EFI_D_INFO, "[LegacyBds] Delete Boot Option Boot%04x: %s\n", 
(UINTN) BootOption[Index].OptionNumber, BootOption[Index].Description));
+      //
+      // Delete entry from LegacyDevOrder
+      //
+      UpdateBbsIndex (
+        LegacyDevOrder,
+        &LegacyDevOrderSize,
+        LegacyDeviceType (BootOption[Index].FilePath),
+        ((LEGACY_BOOT_OPTION_BBS_DATA *) 
BootOption[Index].OptionalData)->BbsIndex,
+        (UINT16) -1
+        );
+      EfiBootManagerDeleteLoadOptionVariable (BootOption[Index].OptionNumber, 
BootOption[Index].OptionType);
+    } else {
+      if (((LEGACY_BOOT_OPTION_BBS_DATA *) 
BootOption[Index].OptionalData)->BbsIndex != BbsIndex) {
+        DEBUG ((EFI_D_INFO, "[LegacyBds] Update Boot Option Boot%04x: %s 
Bbs0x%04x->Bbs0x%04x\n", (UINTN) BootOption[Index].OptionNumber, 
BootOption[Index].Description,
+                (UINTN) ((LEGACY_BOOT_OPTION_BBS_DATA *) 
BootOption[Index].OptionalData)->BbsIndex, (UINTN) BbsIndex));
+        //
+        // Update the BBS index in LegacyDevOrder
+        //
+        UpdateBbsIndex (
+          LegacyDevOrder,
+          &LegacyDevOrderSize,
+          LegacyDeviceType (BootOption[Index].FilePath),
+          ((LEGACY_BOOT_OPTION_BBS_DATA *) 
BootOption[Index].OptionalData)->BbsIndex,
+          BbsIndex
+          );
+
+        //
+        // Update the OptionalData in the Boot#### variable
+        //
+        ((LEGACY_BOOT_OPTION_BBS_DATA *) 
BootOption[Index].OptionalData)->BbsIndex = BbsIndex;
+        EfiBootManagerLoadOptionToVariable (&BootOption[Index]);
+      }
+    }
+  }
+  EfiBootManagerFreeLoadOptions (BootOption, BootOptionCount);
+
+  if (LegacyDevOrder != NULL) {
+    Status = gRT->SetVariable (
+                    VAR_LEGACY_DEV_ORDER,
+                    &gEfiLegacyDevOrderVariableGuid,
+                    EFI_VARIABLE_BOOTSERVICE_ACCESS | 
EFI_VARIABLE_NON_VOLATILE,
+                    LegacyDevOrderSize,
+                    LegacyDevOrder
+                    );
+    //
+    // Shrink variable with current variable implementation shouldn't fail.
+    //
+    ASSERT_EFI_ERROR (Status);
+
+    FreePool (LegacyDevOrder);
+  }
+  FreePool(BbsIndexUsed);
+  return Status;
+}
+
+/**
+  Find legacy boot option index in the boot option.
+
+  @param Key         The input boot option which is compared with.
+  @param Array       The input boot option array.
+  @param Count       The count of the input boot options.
+
+  @retval  The index of the input boot option in the array.
+
+**/
+INTN
+FindLegacyBootOption (
+  IN EFI_BOOT_MANAGER_LOAD_OPTION  *Key,
+  IN EFI_BOOT_MANAGER_LOAD_OPTION  *Array,
+  IN UINTN                         Count
+  )
+{
+  UINTN                         Index;
+  
+  for (Index = 0; Index < Count; Index++) {
+    if ((DevicePathType (Array[Index].FilePath) == BBS_DEVICE_PATH) &&
+        (DevicePathSubType (Array[Index].FilePath) == BBS_BBS_DP)) {
+      //
+      // Just compare the FilePath and the Description field
+      //
+      if ((LegacyDeviceType (Array[Index].FilePath) == LegacyDeviceType 
(Key->FilePath)) &&
+          (StrCmp (Array[Index].Description, Key->Description) == 0)) {
+        //
+        // The BbsIndex field should match because it was updated in the 
LegacyBootManagerDeleteAllInvalidBootOptions
+        //
+        ASSERT (
+          ((LEGACY_BOOT_OPTION_BBS_DATA *) 
Array[Index].OptionalData)->BbsIndex ==
+          ((LEGACY_BOOT_OPTION_BBS_DATA *) Key->OptionalData)->BbsIndex
+          );
+        return (INTN) Index;
+      }
+    }
+  }
+
+  return -1;
+}
+
+/**
+  Create legacy boot option.
+
+  @param BootOption        Ponter to the boot option which will be crated.
+  @param BbsEntry          The input bbs entry info.
+  @param BbsIndex          The BBS index.
+
+  @retval EFI_SUCCESS            Create legacy boot option successfully.
+  @retval EFI_INVALID_PARAMETER  Invalid input parameter.
+
+**/
+EFI_STATUS
+CreateLegacyBootOption (
+  IN OUT EFI_BOOT_MANAGER_LOAD_OPTION  *BootOption,
+  IN BBS_TABLE                         *BbsEntry,
+  IN UINT16                            BbsIndex
+  )
+{
+  EFI_STATUS                   Status;
+  EFI_DEVICE_PATH_PROTOCOL     *DevicePath;
+  CHAR16                       Description[BOOT_DESCRIPTION_LENGTH + 1];
+  CHAR8                        HelpString[BOOT_DESCRIPTION_LENGTH + 1];
+  UINTN                        StringLen;
+  LEGACY_BOOT_OPTION_BBS_DATA  *OptionalData;
+  BBS_BBS_DEVICE_PATH          *BbsNode;
+
+  if ((BootOption == NULL) || (BbsEntry == NULL)) {
+    return EFI_INVALID_PARAMETER;
+  }
+  
+  BuildLegacyDevNameString (BbsEntry, BbsIndex, sizeof (Description), 
Description);
+
+  //
+  // Create the BBS device path with description string
+  //
+  UnicodeStrToAsciiStr (Description, HelpString);
+  StringLen = AsciiStrLen (HelpString);
+  DevicePath = AllocatePool (sizeof (BBS_BBS_DEVICE_PATH) + StringLen + 
END_DEVICE_PATH_LENGTH);
+  ASSERT (DevicePath != NULL);
+
+  BbsNode = (BBS_BBS_DEVICE_PATH *) DevicePath;
+  SetDevicePathNodeLength (BbsNode, sizeof (BBS_BBS_DEVICE_PATH) + StringLen);
+  BbsNode->Header.Type    = BBS_DEVICE_PATH;
+  BbsNode->Header.SubType = BBS_BBS_DP;
+  BbsNode->DeviceType     = BbsEntry->DeviceType;
+  CopyMem (&BbsNode->StatusFlag, &BbsEntry->StatusFlags, sizeof 
(BBS_STATUS_FLAGS));
+  CopyMem (BbsNode->String, HelpString, StringLen + 1);
+
+  SetDevicePathEndNode (NextDevicePathNode (BbsNode));
+
+  //
+  // Create the OptionalData
+  //
+  OptionalData = AllocatePool (sizeof (LEGACY_BOOT_OPTION_BBS_DATA));
+  ASSERT (OptionalData != NULL);
+  OptionalData->BbsIndex = BbsIndex;
+
+  //
+  // Create the BootOption
+  //
+  Status = EfiBootManagerInitializeLoadOption (
+             BootOption,
+             LoadOptionNumberUnassigned,
+             LoadOptionTypeBoot,
+             LOAD_OPTION_ACTIVE,
+             Description,
+             DevicePath,
+             (UINT8 *) OptionalData,
+             sizeof (LEGACY_BOOT_OPTION_BBS_DATA)
+             );
+  FreePool (DevicePath);
+  FreePool (OptionalData);
+  
+  return Status;
+}
+
+/**
+  Fill the device order buffer.
+
+  @param BbsTable        The BBS table.
+  @param BbsType         The BBS Type.
+  @param BbsCount        The BBS Count.
+  @param Buf             device order buffer.
+
+  @return The device order buffer.
+
+**/
+UINT16 *
+FillDevOrderBuf (
+  IN BBS_TABLE                    *BbsTable,
+  IN BBS_TYPE                     BbsType,
+  IN UINTN                        BbsCount,
+  OUT UINT16                      *Buf
+  )
+{
+  UINTN Index;
+
+  for (Index = 0; Index < BbsCount; Index++) {
+    if (!ValidBbsEntry (&BbsTable[Index])) {
+      continue;
+    }
+
+    if (BbsTable[Index].DeviceType != BbsType) {
+      continue;
+    }
+
+    *Buf = (UINT16) (Index & 0xFF);
+    Buf++;
+  }
+
+  return Buf;
+}
+
+/**
+  Create the device order buffer.
+
+  @param BbsTable        The BBS table.
+  @param BbsCount        The BBS Count.
+
+  @retval EFI_SUCCES             The buffer is created and the EFI variable 
named 
+                                 VAR_LEGACY_DEV_ORDER and 
EfiLegacyDevOrderGuid is
+                                 set correctly.
+  @retval EFI_OUT_OF_RESOURCES   Memmory or storage is not enough.
+  @retval EFI_DEVICE_ERROR       Fail to add the device order into EFI 
variable fail
+                                 because of hardware error.
+**/
+EFI_STATUS
+CreateDevOrder (
+  IN BBS_TABLE                  *BbsTable,
+  IN UINT16                     BbsCount
+  )
+{
+  UINTN                       Index;
+  UINTN                       FDCount;
+  UINTN                       HDCount;
+  UINTN                       CDCount;
+  UINTN                       NETCount;
+  UINTN                       BEVCount;
+  UINTN                       TotalSize;
+  UINTN                       HeaderSize;
+  LEGACY_DEV_ORDER_ENTRY      *DevOrder;
+  LEGACY_DEV_ORDER_ENTRY      *DevOrderPtr;
+  EFI_STATUS                  Status;
+
+  FDCount     = 0;
+  HDCount     = 0;
+  CDCount     = 0;
+  NETCount    = 0;
+  BEVCount    = 0;
+  TotalSize   = 0;
+  HeaderSize  = sizeof (BBS_TYPE) + sizeof (UINT16);
+  DevOrder    = NULL;
+  Status      = EFI_SUCCESS;
+
+  //
+  // Count all boot devices
+  //
+  for (Index = 0; Index < BbsCount; Index++) {
+    if (!ValidBbsEntry (&BbsTable[Index])) {
+      continue;
+    }
+
+    switch (BbsTable[Index].DeviceType) {
+    case BBS_FLOPPY:
+      FDCount++;
+      break;
+
+    case BBS_HARDDISK:
+      HDCount++;
+      break;
+
+    case BBS_CDROM:
+      CDCount++;
+      break;
+
+    case BBS_EMBED_NETWORK:
+      NETCount++;
+      break;
+
+    case BBS_BEV_DEVICE:
+      BEVCount++;
+      break;
+
+    default:
+      break;
+    }
+  }
+
+  TotalSize += (HeaderSize + sizeof (UINT16) * FDCount);
+  TotalSize += (HeaderSize + sizeof (UINT16) * HDCount);
+  TotalSize += (HeaderSize + sizeof (UINT16) * CDCount);
+  TotalSize += (HeaderSize + sizeof (UINT16) * NETCount);
+  TotalSize += (HeaderSize + sizeof (UINT16) * BEVCount);
+
+  //
+  // Create buffer to hold all boot device order
+  //
+  DevOrder = AllocateZeroPool (TotalSize);
+  if (NULL == DevOrder) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+  DevOrderPtr          = DevOrder;
+
+  DevOrderPtr->BbsType = BBS_FLOPPY;
+  DevOrderPtr->Length  = (UINT16) (sizeof (DevOrderPtr->Length) + FDCount * 
sizeof (UINT16));
+  DevOrderPtr          = (LEGACY_DEV_ORDER_ENTRY *) FillDevOrderBuf (BbsTable, 
BBS_FLOPPY, BbsCount, DevOrderPtr->Data);
+
+  DevOrderPtr->BbsType = BBS_HARDDISK;
+  DevOrderPtr->Length  = (UINT16) (sizeof (UINT16) + HDCount * sizeof 
(UINT16));
+  DevOrderPtr          = (LEGACY_DEV_ORDER_ENTRY *) FillDevOrderBuf (BbsTable, 
BBS_HARDDISK, BbsCount, DevOrderPtr->Data);
+  
+  DevOrderPtr->BbsType = BBS_CDROM;
+  DevOrderPtr->Length  = (UINT16) (sizeof (UINT16) + CDCount * sizeof 
(UINT16));
+  DevOrderPtr          = (LEGACY_DEV_ORDER_ENTRY *) FillDevOrderBuf (BbsTable, 
BBS_CDROM, BbsCount, DevOrderPtr->Data);
+  
+  DevOrderPtr->BbsType = BBS_EMBED_NETWORK;
+  DevOrderPtr->Length  = (UINT16) (sizeof (UINT16) + NETCount * sizeof 
(UINT16));
+  DevOrderPtr          = (LEGACY_DEV_ORDER_ENTRY *) FillDevOrderBuf (BbsTable, 
BBS_EMBED_NETWORK, BbsCount, DevOrderPtr->Data);
+
+  DevOrderPtr->BbsType = BBS_BEV_DEVICE;
+  DevOrderPtr->Length  = (UINT16) (sizeof (UINT16) + BEVCount * sizeof 
(UINT16));
+  DevOrderPtr          = (LEGACY_DEV_ORDER_ENTRY *) FillDevOrderBuf (BbsTable, 
BBS_BEV_DEVICE, BbsCount, DevOrderPtr->Data);
+
+  ASSERT (TotalSize == (UINTN) ((UINT8 *) DevOrderPtr - (UINT8 *) DevOrder));
+
+  //
+  // Save device order for legacy boot device to variable.
+  //
+  Status = gRT->SetVariable (
+                  VAR_LEGACY_DEV_ORDER,
+                  &gEfiLegacyDevOrderVariableGuid,
+                  EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE,
+                  TotalSize,
+                  DevOrder
+                  );
+  FreePool (DevOrder);
+
+  return Status;
+}
+
+/**
+  Add the legacy boot devices from BBS table into 
+  the legacy device boot order.
+
+  @retval EFI_SUCCESS           The boot devices are added successfully.
+  @retval EFI_NOT_FOUND         The legacy boot devices are not found.
+  @retval EFI_OUT_OF_RESOURCES  Memmory or storage is not enough.
+  @retval EFI_DEVICE_ERROR      Fail to add the legacy device boot order into 
EFI variable
+                                because of hardware error.
+**/
+EFI_STATUS
+UpdateLegacyDevOrder (
+  VOID
+  )
+{
+  LEGACY_DEV_ORDER_ENTRY      *DevOrder;
+  LEGACY_DEV_ORDER_ENTRY      *NewDevOrder;
+  LEGACY_DEV_ORDER_ENTRY      *Ptr;
+  LEGACY_DEV_ORDER_ENTRY      *NewPtr;
+  EFI_LEGACY_BIOS_PROTOCOL    *LegacyBios;
+  EFI_STATUS                  Status;
+  UINT16                      HddCount;
+  UINT16                      BbsCount;
+  HDD_INFO                    *LocalHddInfo;
+  BBS_TABLE                   *LocalBbsTable;
+  UINTN                       Index;
+  UINTN                       Index2;
+  UINTN                       *Idx;
+  UINTN                       FDCount;
+  UINTN                       HDCount;
+  UINTN                       CDCount;
+  UINTN                       NETCount;
+  UINTN                       BEVCount;
+  UINTN                       TotalSize;
+  UINTN                       HeaderSize;
+  UINT16                      *NewFDPtr;
+  UINT16                      *NewHDPtr;
+  UINT16                      *NewCDPtr;
+  UINT16                      *NewNETPtr;
+  UINT16                      *NewBEVPtr;
+  UINT16                      *NewDevPtr;
+  UINTN                       FDIndex;
+  UINTN                       HDIndex;
+  UINTN                       CDIndex;
+  UINTN                       NETIndex;
+  UINTN                       BEVIndex;
+
+  Idx           = NULL;
+  FDCount       = 0;
+  HDCount       = 0;
+  CDCount       = 0;
+  NETCount      = 0;
+  BEVCount      = 0;
+  TotalSize     = 0;
+  HeaderSize    = sizeof (BBS_TYPE) + sizeof (UINT16);
+  FDIndex       = 0;
+  HDIndex       = 0;
+  CDIndex       = 0;
+  NETIndex      = 0;
+  BEVIndex      = 0;
+  NewDevPtr     = NULL;
+
+  Status        = gBS->LocateProtocol (&gEfiLegacyBiosProtocolGuid, NULL, 
(VOID **) &LegacyBios);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  Status = LegacyBios->GetBbsInfo (
+                         LegacyBios,
+                         &HddCount,
+                         &LocalHddInfo,
+                         &BbsCount,
+                         &LocalBbsTable
+                         );
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  GetVariable2 (VAR_LEGACY_DEV_ORDER, &gEfiLegacyDevOrderVariableGuid, (VOID 
**) &DevOrder, NULL);
+  if (NULL == DevOrder) {
+    return CreateDevOrder (LocalBbsTable, BbsCount);
+  }
+  //
+  // First we figure out how many boot devices with same device type 
respectively
+  //
+  for (Index = 0; Index < BbsCount; Index++) {
+    if (!ValidBbsEntry (&LocalBbsTable[Index])) {
+      continue;
+    }
+
+    switch (LocalBbsTable[Index].DeviceType) {
+    case BBS_FLOPPY:
+      FDCount++;
+      break;
+
+    case BBS_HARDDISK:
+      HDCount++;
+      break;
+
+    case BBS_CDROM:
+      CDCount++;
+      break;
+
+    case BBS_EMBED_NETWORK:
+      NETCount++;
+      break;
+
+    case BBS_BEV_DEVICE:
+      BEVCount++;
+      break;
+
+    default:
+      break;
+    }
+  }
+
+  TotalSize += (HeaderSize + FDCount * sizeof (UINT16));
+  TotalSize += (HeaderSize + HDCount * sizeof (UINT16));
+  TotalSize += (HeaderSize + CDCount * sizeof (UINT16));
+  TotalSize += (HeaderSize + NETCount * sizeof (UINT16));
+  TotalSize += (HeaderSize + BEVCount * sizeof (UINT16));
+
+  NewDevOrder = AllocateZeroPool (TotalSize);
+  if (NULL == NewDevOrder) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  //
+  // copy FD
+  //
+  Ptr             = DevOrder;
+  NewPtr          = NewDevOrder;
+  NewPtr->BbsType = Ptr->BbsType;
+  NewPtr->Length  = (UINT16) (sizeof (UINT16) + FDCount * sizeof (UINT16));
+  for (Index = 0; Index < Ptr->Length / sizeof (UINT16) - 1; Index++) {
+    if (!ValidBbsEntry (&LocalBbsTable[Ptr->Data[Index] & 0xFF]) ||
+        LocalBbsTable[Ptr->Data[Index] & 0xFF].DeviceType != BBS_FLOPPY
+        ) {
+      continue;
+    }
+
+    NewPtr->Data[FDIndex] = Ptr->Data[Index];
+    FDIndex++;
+  }
+  NewFDPtr = NewPtr->Data;
+
+  //
+  // copy HD
+  //
+  Ptr             = (LEGACY_DEV_ORDER_ENTRY *) (&Ptr->Data[Ptr->Length / 
sizeof (UINT16) - 1]);
+  NewPtr          = (LEGACY_DEV_ORDER_ENTRY *) (&NewPtr->Data[NewPtr->Length / 
sizeof (UINT16) -1]);
+  NewPtr->BbsType = Ptr->BbsType;
+  NewPtr->Length  = (UINT16) (sizeof (UINT16) + HDCount * sizeof (UINT16));
+  for (Index = 0; Index < Ptr->Length / sizeof (UINT16) - 1; Index++) {
+    if (!ValidBbsEntry (&LocalBbsTable[Ptr->Data[Index] & 0xFF]) ||
+        LocalBbsTable[Ptr->Data[Index] & 0xFF].DeviceType != BBS_HARDDISK
+        ) {
+      continue;
+    }
+
+    NewPtr->Data[HDIndex] = Ptr->Data[Index];
+    HDIndex++;
+  }
+  NewHDPtr = NewPtr->Data;
+
+  //
+  // copy CD
+  //
+  Ptr    = (LEGACY_DEV_ORDER_ENTRY *) (&Ptr->Data[Ptr->Length / sizeof 
(UINT16) - 1]);
+  NewPtr = (LEGACY_DEV_ORDER_ENTRY *) (&NewPtr->Data[NewPtr->Length / sizeof 
(UINT16) -1]);
+  NewPtr->BbsType = Ptr->BbsType;
+  NewPtr->Length  = (UINT16) (sizeof (UINT16) + CDCount * sizeof (UINT16));
+  for (Index = 0; Index < Ptr->Length / sizeof (UINT16) - 1; Index++) {
+    if (!ValidBbsEntry (&LocalBbsTable[Ptr->Data[Index] & 0xFF]) ||
+        LocalBbsTable[Ptr->Data[Index] & 0xFF].DeviceType != BBS_CDROM
+        ) {
+      continue;
+    }
+
+    NewPtr->Data[CDIndex] = Ptr->Data[Index];
+    CDIndex++;
+  }
+  NewCDPtr = NewPtr->Data;
+
+  //
+  // copy NET
+  //
+  Ptr    = (LEGACY_DEV_ORDER_ENTRY *) (&Ptr->Data[Ptr->Length / sizeof 
(UINT16) - 1]);
+  NewPtr = (LEGACY_DEV_ORDER_ENTRY *) (&NewPtr->Data[NewPtr->Length / sizeof 
(UINT16) -1]);
+  NewPtr->BbsType = Ptr->BbsType;
+  NewPtr->Length  = (UINT16) (sizeof (UINT16) + NETCount * sizeof (UINT16));
+  for (Index = 0; Index < Ptr->Length / sizeof (UINT16) - 1; Index++) {
+    if (!ValidBbsEntry (&LocalBbsTable[Ptr->Data[Index] & 0xFF]) ||
+        LocalBbsTable[Ptr->Data[Index] & 0xFF].DeviceType != BBS_EMBED_NETWORK
+        ) {
+      continue;
+    }
+
+    NewPtr->Data[NETIndex] = Ptr->Data[Index];
+    NETIndex++;
+  }
+  NewNETPtr = NewPtr->Data;
+  
+  //
+  // copy BEV
+  //
+  Ptr    = (LEGACY_DEV_ORDER_ENTRY *) (&Ptr->Data[Ptr->Length / sizeof 
(UINT16) - 1]);
+  NewPtr = (LEGACY_DEV_ORDER_ENTRY *) (&NewPtr->Data[NewPtr->Length / sizeof 
(UINT16) -1]);
+  NewPtr->BbsType = Ptr->BbsType;
+  NewPtr->Length  = (UINT16) (sizeof (UINT16) + BEVCount * sizeof (UINT16));
+  for (Index = 0; Index < Ptr->Length / sizeof (UINT16) - 1; Index++) {
+    if (!ValidBbsEntry (&LocalBbsTable[Ptr->Data[Index] & 0xFF]) ||
+        LocalBbsTable[Ptr->Data[Index] & 0xFF].DeviceType != BBS_BEV_DEVICE
+        ) {
+      continue;
+    }
+
+    NewPtr->Data[BEVIndex] = Ptr->Data[Index];
+    BEVIndex++;
+  }
+  NewBEVPtr = NewPtr->Data;
+
+  for (Index = 0; Index < BbsCount; Index++) {
+    if (!ValidBbsEntry (&LocalBbsTable[Index])) {
+      continue;
+    }
+
+    switch (LocalBbsTable[Index].DeviceType) {
+    case BBS_FLOPPY:
+      Idx       = &FDIndex;
+      NewDevPtr = NewFDPtr;
+      break;
+
+    case BBS_HARDDISK:
+      Idx       = &HDIndex;
+      NewDevPtr = NewHDPtr;
+      break;
+
+    case BBS_CDROM:
+      Idx       = &CDIndex;
+      NewDevPtr = NewCDPtr;
+      break;
+
+    case BBS_EMBED_NETWORK:
+      Idx       = &NETIndex;
+      NewDevPtr = NewNETPtr;
+      break;
+
+    case BBS_BEV_DEVICE:
+      Idx       = &BEVIndex;
+      NewDevPtr = NewBEVPtr;
+      break;
+
+    default:
+      Idx = NULL;
+      break;
+    }
+    //
+    // at this point we have copied those valid indexes to new buffer
+    // and we should check if there is any new appeared boot device
+    //
+    if (Idx != NULL) {
+      for (Index2 = 0; Index2 < *Idx; Index2++) {
+        if ((NewDevPtr[Index2] & 0xFF) == (UINT16) Index) {
+          break;
+        }
+      }
+
+      if (Index2 == *Idx) {
+        //
+        // Index2 == *Idx means we didn't find Index
+        // so Index is a new appeared device's index in BBS table
+        // insert it before disabled indexes.
+        //
+        for (Index2 = 0; Index2 < *Idx; Index2++) {
+          if ((NewDevPtr[Index2] & 0xFF00) == 0xFF00) {
+            break;
+          }
+        }
+        CopyMem (&NewDevPtr[Index2 + 1], &NewDevPtr[Index2], (*Idx - Index2) * 
sizeof (UINT16));
+        NewDevPtr[Index2] = (UINT16) (Index & 0xFF);
+        (*Idx)++;
+      }
+    }
+  }
+
+  FreePool (DevOrder);
+
+  Status = gRT->SetVariable (
+                  VAR_LEGACY_DEV_ORDER,
+                  &gEfiLegacyDevOrderVariableGuid,
+                  EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE,
+                  TotalSize,
+                  NewDevOrder
+                  );
+  FreePool (NewDevOrder);
+
+  return Status;
+}
+
+/**
+  Set Boot Priority for specified device type.
+
+  @param DeviceType      The device type.
+  @param BbsIndex        The BBS index to set the highest priority. Ignore 
when -1.
+  @param LocalBbsTable   The BBS table.
+  @param Priority        The prority table.
+
+  @retval EFI_SUCCESS           The function completes successfully.
+  @retval EFI_NOT_FOUND         Failed to find device.
+  @retval EFI_OUT_OF_RESOURCES  Failed to get the efi variable of device order.
+
+**/
+EFI_STATUS
+SetBootPriority4SameTypeDev (
+  IN UINT16                                              DeviceType,
+  IN UINTN                                               BbsIndex,
+  IN OUT BBS_TABLE                                       *LocalBbsTable,
+  IN OUT UINT16                                          *Priority
+  )
+{
+  LEGACY_DEV_ORDER_ENTRY      *DevOrder;
+  LEGACY_DEV_ORDER_ENTRY      *DevOrderPtr;
+  UINTN                       DevOrderSize;
+  UINTN                       Index;
+
+  GetVariable2 (VAR_LEGACY_DEV_ORDER, &gEfiLegacyDevOrderVariableGuid, (VOID 
**) &DevOrder, &DevOrderSize);
+  if (NULL == DevOrder) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  DevOrderPtr = DevOrder;
+  while ((UINT8 *) DevOrderPtr < (UINT8 *) DevOrder + DevOrderSize) {
+    if (DevOrderPtr->BbsType == DeviceType) {
+      break;
+    }
+
+    DevOrderPtr = (LEGACY_DEV_ORDER_ENTRY *) ((UINTN) DevOrderPtr + sizeof 
(BBS_TYPE) + DevOrderPtr->Length);
+  }
+
+  if ((UINT8 *) DevOrderPtr >= (UINT8 *) DevOrder + DevOrderSize) {
+    FreePool (DevOrder);
+    return EFI_NOT_FOUND;
+  }
+
+  if (BbsIndex != (UINTN) -1) {
+    //
+    // In case the BBS entry isn't valid because devices were plugged or 
removed.
+    //
+    if (!ValidBbsEntry (&LocalBbsTable[BbsIndex]) || 
(LocalBbsTable[BbsIndex].DeviceType != DeviceType)) {
+      FreePool (DevOrder);
+      return EFI_NOT_FOUND;
+    }
+    LocalBbsTable[BbsIndex].BootPriority = *Priority;
+    (*Priority)++;
+  }
+  //
+  // If the high byte of the DevIndex is 0xFF, it indicates that this device 
has been disabled.
+  //
+  for (Index = 0; Index < DevOrderPtr->Length / sizeof (UINT16) - 1; Index++) {
+    if ((DevOrderPtr->Data[Index] & 0xFF00) == 0xFF00) {
+      //
+      // LocalBbsTable[DevIndex[Index] & 0xFF].BootPriority = 
BBS_DISABLED_ENTRY;
+      //
+    } else if (DevOrderPtr->Data[Index] != BbsIndex) {
+      LocalBbsTable[DevOrderPtr->Data[Index]].BootPriority = *Priority;
+      (*Priority)++;
+    }
+  }
+
+  FreePool (DevOrder);
+  return EFI_SUCCESS;
+}
+
+/**
+  Print the BBS Table.
+
+  @param LocalBbsTable   The BBS table.
+  @param BbsCount        The count of entry in BBS table.
+**/
+VOID
+PrintBbsTable (
+  IN BBS_TABLE  *LocalBbsTable,
+  IN UINT16     BbsCount
+  )
+{
+  UINT16  Index;
+
+  DEBUG ((DEBUG_INFO, "\n"));
+  DEBUG ((DEBUG_INFO, " NO  Prio bb/dd/ff cl/sc Type Stat segm:offs\n"));
+  DEBUG ((DEBUG_INFO, "=============================================\n"));
+  for (Index = 0; Index < BbsCount; Index++) {
+    if (!ValidBbsEntry (&LocalBbsTable[Index])) {
+      continue;
+    }
+
+    DEBUG (
+      (DEBUG_INFO,
+      " %02x: %04x %02x/%02x/%02x %02x/%02x %04x %04x %04x:%04x\n",
+      (UINTN) Index,
+      (UINTN) LocalBbsTable[Index].BootPriority,
+      (UINTN) LocalBbsTable[Index].Bus,
+      (UINTN) LocalBbsTable[Index].Device,
+      (UINTN) LocalBbsTable[Index].Function,
+      (UINTN) LocalBbsTable[Index].Class,
+      (UINTN) LocalBbsTable[Index].SubClass,
+      (UINTN) LocalBbsTable[Index].DeviceType,
+      (UINTN) * (UINT16 *) &LocalBbsTable[Index].StatusFlags,
+      (UINTN) LocalBbsTable[Index].BootHandlerSegment,
+      (UINTN) LocalBbsTable[Index].BootHandlerOffset,
+      (UINTN) ((LocalBbsTable[Index].MfgStringSegment << 4) + 
LocalBbsTable[Index].MfgStringOffset),
+      (UINTN) ((LocalBbsTable[Index].DescStringSegment << 4) + 
LocalBbsTable[Index].DescStringOffset))
+      );
+  }
+
+  DEBUG ((DEBUG_INFO, "\n"));
+}
+
+/**
+  Set the boot priority for BBS entries based on boot option entry and boot 
order.
+
+  @param  BootOption            The boot option is to be checked for refresh 
BBS table.
+  
+  @retval EFI_SUCCESS           The boot priority for BBS entries is refreshed 
successfully.
+  @retval EFI_NOT_FOUND         BBS entries can't be found.
+  @retval EFI_OUT_OF_RESOURCES  Failed to get the legacy device boot order.
+**/
+EFI_STATUS
+RefreshBbsTableForBoot (
+  IN EFI_BOOT_MANAGER_LOAD_OPTION        *BootOption
+  )
+{
+  EFI_STATUS                    Status;
+  UINT16                        BbsIndex;
+  UINT16                        HddCount;
+  UINT16                        BbsCount;
+  HDD_INFO                      *LocalHddInfo;
+  BBS_TABLE                     *LocalBbsTable;
+  UINT16                        DevType;
+  EFI_LEGACY_BIOS_PROTOCOL      *LegacyBios;
+  UINTN                         Index;
+  UINT16                        Priority;
+  UINT16                        *DeviceType;
+  UINTN                         DeviceTypeCount;
+  UINTN                         DeviceTypeIndex;
+  EFI_BOOT_MANAGER_LOAD_OPTION  *Option;
+  UINTN                         OptionCount;
+
+  HddCount      = 0;
+  BbsCount      = 0;
+  LocalHddInfo  = NULL;
+  LocalBbsTable = NULL;
+  DevType       = BBS_UNKNOWN;
+
+  Status        = gBS->LocateProtocol (&gEfiLegacyBiosProtocolGuid, NULL, 
(VOID **) &LegacyBios);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  Status = LegacyBios->GetBbsInfo (
+                         LegacyBios,
+                         &HddCount,
+                         &LocalHddInfo,
+                         &BbsCount,
+                         &LocalBbsTable
+                         );
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  //
+  // First, set all the present devices' boot priority to 
BBS_UNPRIORITIZED_ENTRY
+  // We will set them according to the settings setup by user
+  //
+  for (Index = 0; Index < BbsCount; Index++) {
+    if (ValidBbsEntry (&LocalBbsTable[Index])) {
+      LocalBbsTable[Index].BootPriority = BBS_UNPRIORITIZED_ENTRY;
+    }
+  }
+  //
+  // boot priority always starts at 0
+  //
+  Priority = 0;  
+  if ((DevicePathType (BootOption->FilePath) == BBS_DEVICE_PATH) &&
+      (DevicePathSubType (BootOption->FilePath) == BBS_BBS_DP)) {
+    //
+    // If BootOption stands for a legacy boot option, we prioritize the 
devices with the same type first.
+    //
+    DevType  = LegacyDeviceType (BootOption->FilePath);
+    BbsIndex = ((LEGACY_BOOT_OPTION_BBS_DATA *) 
BootOption->OptionalData)->BbsIndex;
+    Status = SetBootPriority4SameTypeDev (
+               DevType,
+               BbsIndex,
+               LocalBbsTable,
+               &Priority
+               );
+    if (EFI_ERROR (Status)) {
+      return Status;
+    }
+  }
+  //
+  // we have to set the boot priority for other BBS entries with different 
device types
+  //
+  Option          = EfiBootManagerGetLoadOptions (&OptionCount, 
LoadOptionTypeBoot);
+  DeviceType      = AllocatePool (sizeof (UINT16) * OptionCount);
+  ASSERT (DeviceType != NULL);
+  DeviceType[0]   = DevType;
+  DeviceTypeCount = 1;
+  for (Index = 0; Index < OptionCount; Index++) {
+    if ((DevicePathType (Option[Index].FilePath) != BBS_DEVICE_PATH) ||
+        (DevicePathSubType (Option[Index].FilePath) != BBS_BBS_DP)) {
+      continue;
+    }
+    
+    DevType = LegacyDeviceType (Option[Index].FilePath);
+    for (DeviceTypeIndex = 0; DeviceTypeIndex < DeviceTypeCount; 
DeviceTypeIndex++) {
+      if (DeviceType[DeviceTypeIndex] == DevType) {
+        break;
+      }
+    }
+    if (DeviceTypeIndex < DeviceTypeCount) {
+      //
+      // We don't want to process twice for a device type
+      //
+      continue;
+    }
+
+    DeviceType[DeviceTypeCount] = DevType;
+    DeviceTypeCount++;
+
+    Status = SetBootPriority4SameTypeDev (
+               DevType,
+               (UINTN) -1,
+               LocalBbsTable,
+               &Priority
+               );
+  }
+  EfiBootManagerFreeLoadOptions (Option, OptionCount);
+
+  DEBUG_CODE_BEGIN();
+    PrintBbsTable (LocalBbsTable, BbsCount);
+  DEBUG_CODE_END();
+  
+  return Status;
+}
+
+
+/**
+  Boot the legacy system with the boot option.
+
+  @param  BootOption The legacy boot option which have BBS device path
+                     On return, BootOption->Status contains the boot status.
+                     EFI_UNSUPPORTED    There is no legacybios protocol, do 
not support
+                                        legacy boot.
+                     EFI_STATUS         The status of LegacyBios->LegacyBoot 
().
+**/
+VOID
+EFIAPI
+LegacyBoot (
+  IN  EFI_BOOT_MANAGER_LOAD_OPTION           *BootOption
+  )
+{
+  EFI_STATUS                Status;
+  EFI_LEGACY_BIOS_PROTOCOL  *LegacyBios;
+
+  Status = gBS->LocateProtocol (&gEfiLegacyBiosProtocolGuid, NULL, (VOID **) 
&LegacyBios);
+  if (EFI_ERROR (Status)) {
+    //
+    // If no LegacyBios protocol we do not support legacy boot
+    //
+    BootOption->Status = EFI_UNSUPPORTED;
+    return;
+  }
+  //
+  // Notes: if we separate the int 19, then we don't need to refresh BBS
+  //
+  Status = RefreshBbsTableForBoot (BootOption);
+  if (EFI_ERROR (Status)) {
+    BootOption->Status = Status;
+    return;
+  }
+
+  BootOption->Status = LegacyBios->LegacyBoot (
+                                     LegacyBios,
+                                     (BBS_BBS_DEVICE_PATH *) 
BootOption->FilePath,
+                                     BootOption->OptionalDataSize,
+                                     BootOption->OptionalData
+                                     );
+}
+
+/**
+  This function enumerates all the legacy boot options.
+
+  @param BootOptionCount   Return the legacy boot option count.
+
+  @retval    Pointer to the legacy boot option buffer.
+**/
+EFI_BOOT_MANAGER_LOAD_OPTION *
+EnumerateLegacyBootOptions (
+  UINTN                         *BootOptionCount
+  )
+{
+  EFI_STATUS                    Status;
+  UINT16                        HddCount;
+  UINT16                        BbsCount;
+  HDD_INFO                      *HddInfo;
+  BBS_TABLE                     *BbsTable;
+  EFI_LEGACY_BIOS_PROTOCOL      *LegacyBios;
+  UINT16                        Index;
+  EFI_BOOT_MANAGER_LOAD_OPTION  *BootOptions;
+
+  ASSERT (BootOptionCount != NULL);
+
+  BootOptions      = NULL;
+  *BootOptionCount = 0;
+  BbsCount         = 0;
+
+  Status        = gBS->LocateProtocol (&gEfiLegacyBiosProtocolGuid, NULL, 
(VOID **) &LegacyBios);
+  if (EFI_ERROR (Status)) {
+    return NULL;
+  }
+
+  Status = LegacyBios->GetBbsInfo (
+                         LegacyBios,
+                         &HddCount,
+                         &HddInfo,
+                         &BbsCount,
+                         &BbsTable
+                         );
+  if (EFI_ERROR (Status)) {
+    return NULL;
+  }
+
+  for (Index = 0; Index < BbsCount; Index++) {
+    if (!ValidBbsEntry (&BbsTable[Index])) {
+      continue;
+    }
+
+    BootOptions = ReallocatePool (
+                    sizeof (EFI_BOOT_MANAGER_LOAD_OPTION) * (*BootOptionCount),
+                    sizeof (EFI_BOOT_MANAGER_LOAD_OPTION) * (*BootOptionCount 
+ 1),
+                    BootOptions
+                    );
+    ASSERT (BootOptions != NULL);
+
+    Status = CreateLegacyBootOption (&BootOptions[(*BootOptionCount)++], 
&BbsTable[Index], Index);
+    ASSERT_EFI_ERROR (Status);
+  }
+
+  return BootOptions;
+}
+
+/**
+  Return the index of the boot option in the boot option array.
+
+  The function compares the Description, FilePath, OptionalData.
+
+  @param Key         The input boot option which is compared with.
+  @param Array       The input boot option array.
+  @param Count       The count of the input boot options.
+
+  @retval  The index of the input boot option in the array.
+
+**/
+INTN
+LegacyBootManagerFindBootOption (
+  IN CONST EFI_BOOT_MANAGER_LOAD_OPTION *Key,
+  IN CONST EFI_BOOT_MANAGER_LOAD_OPTION *Array,
+  IN UINTN                              Count
+  )
+{
+  UINTN                             Index;
+
+  for (Index = 0; Index < Count; Index++) {
+    if ((StrCmp (Key->Description, Array[Index].Description) == 0) &&
+        (CompareMem (Key->FilePath, Array[Index].FilePath, GetDevicePathSize 
(Key->FilePath)) == 0) &&
+        (Key->OptionalDataSize == Array[Index].OptionalDataSize) &&
+        (CompareMem (Key->OptionalData, Array[Index].OptionalData, 
Key->OptionalDataSize) == 0)) {
+      return (INTN) Index;
+    }
+  }
+
+  return -1;
+}
+
+/**
+  Refresh all legacy boot options.
+
+**/
+VOID
+EFIAPI
+LegacyBootManagerRefreshAllBootOption (
+  VOID
+  )
+{
+  EFI_STATUS                                 Status;
+  EFI_LEGACY_BIOS_PROTOCOL                   *LegacyBios;
+  UINTN                                      RootBridgeHandleCount;
+  EFI_HANDLE                                 *RootBridgeHandleBuffer;
+  UINTN                                      HandleCount;
+  EFI_HANDLE                                 *HandleBuffer;
+  UINTN                                      RootBridgeIndex;
+  UINTN                                      Index;
+  UINTN                                      Flags;
+  EFI_BOOT_MANAGER_LOAD_OPTION               *BootOptions;
+  UINTN                                      BootOptionCount;
+  EFI_BOOT_MANAGER_LOAD_OPTION               *ExistingBootOptions;
+  UINTN                                      ExistingBootOptionCount;
+
+  Status = gBS->LocateProtocol (&gEfiLegacyBiosProtocolGuid, NULL, (VOID **) 
&LegacyBios);
+  if (EFI_ERROR (Status)) {
+    DeleteAllLegacyBootOptions ();
+    return;
+  }
+  PERF_START (NULL, "LegacyBootOptionEnum", "BDS", 0);
+
+  //
+  // Before enumerating the legacy boot option, we need to dispatch all the 
legacy option roms 
+  // to ensure the GetBbsInfo() counts all the legacy devices.
+  //
+  gBS->LocateHandleBuffer (
+         ByProtocol,
+         &gEfiPciRootBridgeIoProtocolGuid,
+         NULL,
+         &RootBridgeHandleCount,
+         &RootBridgeHandleBuffer
+         );
+  for (RootBridgeIndex = 0; RootBridgeIndex < RootBridgeHandleCount; 
RootBridgeIndex++) {
+    gBS->ConnectController (RootBridgeHandleBuffer[RootBridgeIndex], NULL, 
NULL, FALSE);
+    gBS->LocateHandleBuffer (
+           ByProtocol,
+           &gEfiPciIoProtocolGuid,
+           NULL,
+           &HandleCount,
+           &HandleBuffer
+           );
+    for (Index = 0; Index < HandleCount; Index++) {
+      //
+      // Start the thunk driver so that the legacy option rom gets dispatched.
+      // Note: We don't directly call InstallPciRom because some thunk drivers 
+      // (e.g. BlockIo thunk driver) depend on the immediate result after 
dispatching
+      //
+      Status = LegacyBios->CheckPciRom (
+                             LegacyBios,
+                             HandleBuffer[Index],
+                             NULL,
+                             NULL,
+                             &Flags
+                             );
+      if (!EFI_ERROR (Status)) {
+        gBS->ConnectController (HandleBuffer[Index], NULL, NULL, FALSE);
+      }
+    }
+  }
+
+  //
+  // Same algorithm pattern as the EfiBootManagerRefreshAllBootOption
+  // Firstly delete the invalid legacy boot options,
+  // then enumreate and save the newly appeared legacy boot options
+  // the last step is legacy boot option special action to refresh the 
LegacyDevOrder variable
+  //
+  DeleteAllInvalidLegacyBootOptions ();
+
+  ExistingBootOptions = EfiBootManagerGetLoadOptions 
(&ExistingBootOptionCount, LoadOptionTypeBoot);
+  BootOptions         = EnumerateLegacyBootOptions   (&BootOptionCount);
+
+  for (Index = 0; Index < BootOptionCount; Index++) {
+    if (LegacyBootManagerFindBootOption (&BootOptions[Index], 
ExistingBootOptions, ExistingBootOptionCount) == -1) {
+      Status = EfiBootManagerAddLoadOptionVariable (&BootOptions[Index], 
(UINTN) -1);
+      DEBUG ((
+        EFI_D_INFO, "[LegacyBds] New Boot Option: Boot%04x Bbs0x%04x %s %r\n",
+        (UINTN) BootOptions[Index].OptionNumber,
+        (UINTN) ((LEGACY_BOOT_OPTION_BBS_DATA *) 
BootOptions[Index].OptionalData)->BbsIndex,
+        BootOptions[Index].Description,
+        Status
+        ));
+      //
+      // Continue upon failure to add boot option.
+      //
+    }
+  }
+
+  EfiBootManagerFreeLoadOptions (ExistingBootOptions, ExistingBootOptionCount);
+  EfiBootManagerFreeLoadOptions (BootOptions,         BootOptionCount);
+
+  //
+  // Failure to create LegacyDevOrder variable only impacts the boot order.
+  //
+  UpdateLegacyDevOrder ();
+
+  PERF_END   (NULL, "LegacyBootOptionEnum", "BDS", 0);
+}
diff --git 
a/IntelFrameworkModulePkg/Library/LegacyBootManagerLib/LegacyBootManagerLib.inf 
b/IntelFrameworkModulePkg/Library/LegacyBootManagerLib/LegacyBootManagerLib.inf
new file mode 100644
index 0000000..ef8eabc
--- /dev/null
+++ 
b/IntelFrameworkModulePkg/Library/LegacyBootManagerLib/LegacyBootManagerLib.inf
@@ -0,0 +1,65 @@
+## @file
+#  This function deal with the legacy boot option, it create, delete
+#  and manage the legacy boot option, all legacy boot option is getting from
+#  the legacy BBS table.
+#
+#  Copyright (c) 2011 - 2015, Intel Corporation. All rights reserved.<BR>
+#  This program and the accompanying materials
+#  are licensed and made available under the terms and conditions of the BSD 
License
+#  which accompanies this distribution.  The full text of the license may be 
found at
+#  http://opensource.org/licenses/bsd-license.php
+#  
+#  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR 
IMPLIED.
+#  
+##
+
+[Defines]
+  INF_VERSION                    = 0x00010005
+  BASE_NAME                      = LegacyBootManagerLib
+  FILE_GUID                      = F1B87BE4-0ACC-409A-A52B-7BFFABCC96A0
+  MODULE_TYPE                    = DXE_DRIVER
+  VERSION_STRING                 = 1.0
+  LIBRARY_CLASS                  = NULL|DXE_DRIVER UEFI_APPLICATION
+  CONSTRUCTOR                    = LegacyBootManagerConstructor
+
+#
+# The following information is for reference only and not required by the 
build tools.
+#
+#  VALID_ARCHITECTURES           = IA32 X64 EBC
+#
+
+[Sources]
+  LegacyBootManagerLib.c
+  InternalLegacyBootManagerLib.h
+  
+[Packages]
+  MdePkg/MdePkg.dec
+  MdeModulePkg/MdeModulePkg.dec
+  IntelFrameworkPkg/IntelFrameworkPkg.dec
+  IntelFrameworkModulePkg/IntelFrameworkModulePkg.dec
+
+[LibraryClasses]
+  BaseLib
+  BaseMemoryLib
+  UefiBootServicesTableLib
+  UefiRuntimeServicesTableLib
+  DevicePathLib
+  MemoryAllocationLib
+  UefiLib
+  DebugLib
+  PrintLib
+  PerformanceLib
+  UefiBootManagerLib
+
+[Guids]
+  gEfiGlobalVariableGuid                        ## SOMETIMES_PRODUCES ## 
Variable:L"Boot####" (Boot option variable)
+                                                ## SOMETIMES_CONSUMES ## 
Variable:L"BootOrder" (The boot option array)
+  gEfiLegacyDevOrderVariableGuid
+
+[Protocols]
+  gEfiLegacyBiosProtocolGuid                    ## SOMETIMES_CONSUMES
+
+[FeaturePcd]
+
+[Pcd]
-- 
1.9.5.msysgit.1



------------------------------------------------------------------------------
BPM Camp - Free Virtual Workshop May 6th at 10am PDT/1PM EDT
Develop your own process in accordance with the BPMN 2 standard
Learn Process modeling best practices with Bonita BPM through live exercises
http://www.bonitasoft.com/be-part-of-it/events/bpm-camp-virtual- event?utm_
source=Sourceforge_BPM_Camp_5_6_15&utm_medium=email&utm_campaign=VA_SF
_______________________________________________
edk2-devel mailing list
edk2-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/edk2-devel

Reply via email to