]> code.delx.au - refind/commitdiff
New CSM/BIOS/legacy support code for UEFI PCs.
authorsrs5694 <srs5694@users.sourceforge.net>
Wed, 28 Aug 2013 08:00:20 +0000 (04:00 -0400)
committersrs5694 <srs5694@users.sourceforge.net>
Wed, 28 Aug 2013 08:00:20 +0000 (04:00 -0400)
EfiLib/legacy.c [new file with mode: 0644]
EfiLib/legacy.h [new file with mode: 0644]

diff --git a/EfiLib/legacy.c b/EfiLib/legacy.c
new file mode 100644 (file)
index 0000000..3aae71d
--- /dev/null
@@ -0,0 +1,1363 @@
+/*
+ * EfiLib/legacy.c
+ * CSM/legacy boot support functions
+ * 
+ * Taken from Tianocore source code (mostly IntelFrameworkModulePkg/Universal/BdsDxe/BootMaint/BBSsupport.c)
+ *
+ * Copyright (c) 2004 - 2011, 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 "../include/tiano_includes.h"
+#include "legacy.h"
+
+BOOT_OPTION_BBS_MAPPING  *mBootOptionBbsMapping     = NULL;
+UINTN                    mBootOptionBbsMappingCount = 0;
+
+extern EFI_DEVICE_PATH EndDevicePath[];
+
+/**
+
+  Translate the first n characters of an Ascii string to
+  Unicode characters. The count n is indicated by parameter
+  Size. If Size is greater than the length of string, then
+  the entire string is translated.
+
+
+  @param AStr               Pointer to input Ascii string.
+  @param Size               The number of characters to translate.
+  @param UStr               Pointer to output Unicode string buffer.
+
+**/
+VOID
+AsciiToUnicodeSize (
+  IN UINT8              *AStr,
+  IN UINTN              Size,
+  OUT UINT16            *UStr
+  )
+{
+  UINTN Idx;
+
+  Idx = 0;
+  while (AStr[Idx] != 0) {
+    UStr[Idx] = (CHAR16) AStr[Idx];
+    if (Idx == Size) {
+      break;
+    }
+
+    Idx++;
+  }
+  UStr[Idx] = 0;
+}
+
+/**
+  Build Legacy Device Name String according.
+
+  @param CurBBSEntry     BBS Table.
+  @param Index           Index.
+  @param BufSize         The buffer size.
+  @param BootString      The output string.
+
+**/
+VOID
+BdsBuildLegacyDevNameString (
+  IN  BBS_TABLE                 *CurBBSEntry,
+  IN  UINTN                     Index,
+  IN  UINTN                     BufSize,
+  OUT CHAR16                    *BootString
+  )
+{
+  CHAR16  *Fmt;
+  CHAR16  *Type;
+  UINT8   *StringDesc;
+  CHAR16  Temp[80];
+
+  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 = (UINT8 *) (UINTN) ((CurBBSEntry->DescStringSegment << 4) + CurBBSEntry->DescStringOffset);
+  if (NULL != StringDesc) {
+    //
+    // Only get fisrt 32 characters, this is suggested by BBS spec
+    //
+    AsciiToUnicodeSize (StringDesc, 32, Temp);
+    Fmt   = L"%s";
+    Type  = Temp;
+  }
+
+  //
+  // 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);
+  }
+}
+
+/**
+  Check if the boot option is a legacy one.
+
+  @param BootOptionVar   The boot option data payload.
+  @param BbsEntry        The BBS Table.
+  @param BbsIndex        The table index.
+
+  @retval TRUE           It is a legacy boot option.
+  @retval FALSE          It is not a legacy boot option.
+
+**/
+BOOLEAN
+BdsIsLegacyBootOption (
+  IN UINT8                 *BootOptionVar,
+  OUT BBS_TABLE            **BbsEntry,
+  OUT UINT16               *BbsIndex
+  )
+{
+  UINT8                     *Ptr;
+  EFI_DEVICE_PATH_PROTOCOL  *DevicePath;
+  BOOLEAN                   Ret;
+  UINT16                    DevPathLen;
+
+  Ptr = BootOptionVar;
+  Ptr += sizeof (UINT32);
+  DevPathLen = *(UINT16 *) Ptr;
+  Ptr += sizeof (UINT16);
+  Ptr += StrSize ((UINT16 *) Ptr);
+  DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) Ptr;
+  if ((BBS_DEVICE_PATH == DevicePath->Type) && (BBS_BBS_DP == DevicePath->SubType)) {
+    Ptr += DevPathLen;
+    *BbsEntry = (BBS_TABLE *) Ptr;
+    Ptr += sizeof (BBS_TABLE);
+    *BbsIndex = *(UINT16 *) Ptr;
+    Ret       = TRUE;
+  } else {
+    *BbsEntry = NULL;
+    Ret       = FALSE;
+  }
+
+  return Ret;
+}
+
+/**
+  Find all legacy boot option by device type.
+
+  @param BootOrder       The boot order array.
+  @param BootOptionNum   The number of boot option.
+  @param DevType         Device type.
+  @param DevName         Device name.
+  @param Attribute       The boot option attribute.
+  @param BbsIndex        The BBS table index.
+  @param OptionNumber    The boot option index.
+
+  @retval TRUE           The Legacy boot option is found.
+  @retval FALSE          The legacy boot option is not found.
+
+**/
+BOOLEAN
+BdsFindLegacyBootOptionByDevTypeAndName (
+  IN UINT16                 *BootOrder,
+  IN UINTN                  BootOptionNum,
+  IN UINT16                 DevType,
+  IN CHAR16                 *DevName,
+  OUT UINT32                *Attribute,
+  OUT UINT16                *BbsIndex,
+  OUT UINT16                *OptionNumber
+  )
+{
+  UINTN     Index;
+  CHAR16    BootOption[9];
+  UINTN     BootOptionSize;
+  UINT8     *BootOptionVar;
+  BBS_TABLE *BbsEntry;
+  BOOLEAN   Found;
+
+  BbsEntry  = NULL;
+  Found     = FALSE;
+
+  if (NULL == BootOrder) {
+    return Found;
+  }
+
+  //
+  // Loop all boot option from variable
+  //
+  for (Index = 0; Index < BootOptionNum; Index++) {
+    UnicodeSPrint (BootOption, sizeof (BootOption), L"Boot%04x", (UINTN) BootOrder[Index]);
+    BootOptionVar = BdsLibGetVariableAndSize (
+                      BootOption,
+                      &gEfiGlobalVariableGuid,
+                      &BootOptionSize
+                      );
+    if (NULL == BootOptionVar) {
+      continue;
+    }
+
+    //
+    // Skip Non-legacy boot option
+    //
+    if (!BdsIsLegacyBootOption (BootOptionVar, &BbsEntry, BbsIndex)) {
+      FreePool (BootOptionVar);
+      continue;
+    }
+
+    if (
+        (BbsEntry->DeviceType != DevType) ||
+        (StrCmp (DevName, (CHAR16*)(BootOptionVar + sizeof (UINT32) + sizeof (UINT16))) != 0)
+       ) {
+      FreePool (BootOptionVar);
+      continue;
+    }
+
+    *Attribute    = *(UINT32 *) BootOptionVar;
+    *OptionNumber = BootOrder[Index];
+    Found         = TRUE;
+    FreePool (BootOptionVar);
+    break;
+  }
+
+  return Found;
+}
+
+/**
+
+  Create a legacy boot option for the specified entry of
+  BBS table, save it as variable, and append it to the boot
+  order list.
+
+
+  @param CurrentBbsEntry    Pointer to current BBS table.
+  @param CurrentBbsDevPath  Pointer to the Device Path Protocol instance of BBS
+  @param Index              Index of the specified entry in BBS table.
+  @param BootOrderList      On input, the original boot order list.
+                            On output, the new boot order list attached with the
+                            created node.
+  @param BootOrderListSize  On input, the original size of boot order list.
+                            On output, the size of new boot order list.
+
+  @retval  EFI_SUCCESS             Boot Option successfully created.
+  @retval  EFI_OUT_OF_RESOURCES    Fail to allocate necessary memory.
+  @retval  Other                   Error occurs while setting variable.
+
+**/
+EFI_STATUS
+BdsCreateLegacyBootOption (
+  IN BBS_TABLE                        *CurrentBbsEntry,
+  IN EFI_DEVICE_PATH_PROTOCOL         *CurrentBbsDevPath,
+  IN UINTN                            Index,
+  IN OUT UINT16                       **BootOrderList,
+  IN OUT UINTN                        *BootOrderListSize
+  )
+{
+  EFI_STATUS           Status;
+  UINT16               CurrentBootOptionNo;
+  UINT16               BootString[10];
+  CHAR16               BootDesc[100];
+  CHAR8                HelpString[100];
+  UINT16               *NewBootOrderList;
+  UINTN                BufferSize;
+  UINTN                StringLen;
+  VOID                 *Buffer;
+  UINT8                *Ptr;
+  UINT16               CurrentBbsDevPathSize;
+  UINTN                BootOrderIndex;
+  UINTN                BootOrderLastIndex;
+  UINTN                ArrayIndex;
+  BOOLEAN              IndexNotFound;
+  BBS_BBS_DEVICE_PATH  *NewBbsDevPathNode;
+
+  if ((*BootOrderList) == NULL) {
+    CurrentBootOptionNo = 0;
+  } else {
+    for (ArrayIndex = 0; ArrayIndex < (UINTN) (*BootOrderListSize / sizeof (UINT16)); ArrayIndex++) {
+      IndexNotFound = TRUE;
+      for (BootOrderIndex = 0; BootOrderIndex < (UINTN) (*BootOrderListSize / sizeof (UINT16)); BootOrderIndex++) {
+        if ((*BootOrderList)[BootOrderIndex] == ArrayIndex) {
+          IndexNotFound = FALSE;
+          break;
+        }
+      }
+
+      if (!IndexNotFound) {
+        continue;
+      } else {
+        break;
+      }
+    }
+
+    CurrentBootOptionNo = (UINT16) ArrayIndex;
+  }
+
+  UnicodeSPrint (
+    BootString,
+    sizeof (BootString),
+    L"Boot%04x",
+    CurrentBootOptionNo
+    );
+
+  BdsBuildLegacyDevNameString (CurrentBbsEntry, Index, sizeof (BootDesc), BootDesc);
+
+  //
+  // Create new BBS device path node with description string
+  //
+  UnicodeStrToAsciiStr (BootDesc, HelpString);
+
+  StringLen = AsciiStrLen (HelpString);
+  NewBbsDevPathNode = AllocateZeroPool (sizeof (BBS_BBS_DEVICE_PATH) + StringLen);
+  if (NewBbsDevPathNode == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+  CopyMem (NewBbsDevPathNode, CurrentBbsDevPath, sizeof (BBS_BBS_DEVICE_PATH));
+  CopyMem (NewBbsDevPathNode->String, HelpString, StringLen + 1);
+  SetDevicePathNodeLength (&(NewBbsDevPathNode->Header), sizeof (BBS_BBS_DEVICE_PATH) + StringLen);
+
+  //
+  // Create entire new CurrentBbsDevPath with end node
+  //
+  CurrentBbsDevPath = AppendDevicePathNode (
+                        EndDevicePath,
+                        (EFI_DEVICE_PATH_PROTOCOL *) NewBbsDevPathNode
+                        );
+   if (CurrentBbsDevPath == NULL) {
+    FreePool (NewBbsDevPathNode);
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  CurrentBbsDevPathSize = (UINT16) (GetDevicePathSize (CurrentBbsDevPath));
+
+  BufferSize = sizeof (UINT32) +
+    sizeof (UINT16) +
+    StrSize (BootDesc) +
+    CurrentBbsDevPathSize +
+    sizeof (BBS_TABLE) +
+    sizeof (UINT16);
+
+  Buffer = AllocateZeroPool (BufferSize);
+  if (Buffer == NULL) {
+    FreePool (NewBbsDevPathNode);
+    FreePool (CurrentBbsDevPath);
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  Ptr               = (UINT8 *) Buffer;
+
+  *((UINT32 *) Ptr) = LOAD_OPTION_ACTIVE;
+  Ptr += sizeof (UINT32);
+
+  *((UINT16 *) Ptr) = CurrentBbsDevPathSize;
+  Ptr += sizeof (UINT16);
+
+  CopyMem (
+    Ptr,
+    BootDesc,
+    StrSize (BootDesc)
+    );
+  Ptr += StrSize (BootDesc);
+
+  CopyMem (
+    Ptr,
+    CurrentBbsDevPath,
+    CurrentBbsDevPathSize
+    );
+  Ptr += CurrentBbsDevPathSize;
+
+  CopyMem (
+    Ptr,
+    CurrentBbsEntry,
+    sizeof (BBS_TABLE)
+    );
+
+  Ptr += sizeof (BBS_TABLE);
+  *((UINT16 *) Ptr) = (UINT16) Index;
+
+  Status = gRT->SetVariable (
+                  BootString,
+                  &gEfiGlobalVariableGuid,
+                  VAR_FLAG,
+                  BufferSize,
+                  Buffer
+                  );
+
+  FreePool (Buffer);
+  
+  Buffer = NULL;
+
+  NewBootOrderList = AllocateZeroPool (*BootOrderListSize + sizeof (UINT16));
+  if (NULL == NewBootOrderList) {
+    FreePool (NewBbsDevPathNode);
+    FreePool (CurrentBbsDevPath);
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  if (*BootOrderList != NULL) {
+    CopyMem (NewBootOrderList, *BootOrderList, *BootOrderListSize);
+    FreePool (*BootOrderList);
+  }
+
+  BootOrderLastIndex                    = (UINTN) (*BootOrderListSize / sizeof (UINT16));
+  NewBootOrderList[BootOrderLastIndex]  = CurrentBootOptionNo;
+  *BootOrderListSize += sizeof (UINT16);
+  *BootOrderList = NewBootOrderList;
+
+  FreePool (NewBbsDevPathNode);
+  FreePool (CurrentBbsDevPath);
+  return Status;
+}
+
+/**
+  Create a legacy boot option.
+
+  @param BbsItem         The BBS Table entry.
+  @param Index           Index of the specified entry in BBS table.
+  @param BootOrderList   The boot order list.
+  @param BootOrderListSize The size of boot order list.
+
+  @retval EFI_OUT_OF_RESOURCE  No enough memory.
+  @retval EFI_SUCCESS          The function complete successfully.
+  @return Other value if the legacy boot option is not created.
+
+**/
+EFI_STATUS
+BdsCreateOneLegacyBootOption (
+  IN BBS_TABLE              *BbsItem,
+  IN UINTN                  Index,
+  IN OUT UINT16             **BootOrderList,
+  IN OUT UINTN              *BootOrderListSize
+  )
+{
+  BBS_BBS_DEVICE_PATH       BbsDevPathNode;
+  EFI_STATUS                Status;
+  EFI_DEVICE_PATH_PROTOCOL  *DevPath;
+
+  DevPath                       = NULL;
+
+  //
+  // Create device path node.
+  //
+  BbsDevPathNode.Header.Type    = BBS_DEVICE_PATH;
+  BbsDevPathNode.Header.SubType = BBS_BBS_DP;
+  SetDevicePathNodeLength (&BbsDevPathNode.Header, sizeof (BBS_BBS_DEVICE_PATH));
+  BbsDevPathNode.DeviceType = BbsItem->DeviceType;
+  CopyMem (&BbsDevPathNode.StatusFlag, &BbsItem->StatusFlags, sizeof (UINT16));
+
+  DevPath = AppendDevicePathNode (
+              EndDevicePath,
+              (EFI_DEVICE_PATH_PROTOCOL *) &BbsDevPathNode
+              );
+  if (NULL == DevPath) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  Status = BdsCreateLegacyBootOption (
+            BbsItem,
+            DevPath,
+            Index,
+            BootOrderList,
+            BootOrderListSize
+            );
+  BbsItem->BootPriority = 0x00;
+
+  FreePool (DevPath);
+
+  return Status;
+}
+
+/**
+  Group the legacy boot options in the BootOption.
+
+  The routine assumes the boot options in the beginning that covers all the device 
+  types are ordered properly and re-position the following boot options just after
+  the corresponding boot options with the same device type.
+  For example:
+  1. Input  = [Harddisk1 CdRom2 Efi1 Harddisk0 CdRom0 CdRom1 Harddisk2 Efi0]
+     Assuming [Harddisk1 CdRom2 Efi1] is ordered properly
+     Output = [Harddisk1 Harddisk0 Harddisk2 CdRom2 CdRom0 CdRom1 Efi1 Efi0]
+
+  2. Input  = [Efi1 Efi0 CdRom1 Harddisk0 Harddisk1 Harddisk2 CdRom0 CdRom2]
+     Assuming [Efi1 Efi0 CdRom1 Harddisk0] is ordered properly
+     Output = [Efi1 Efi0 CdRom1 CdRom0 CdRom2 Harddisk0 Harddisk1 Harddisk2]
+
+  @param BootOption      Pointer to buffer containing Boot Option Numbers
+  @param BootOptionCount Count of the Boot Option Numbers
+**/
+VOID
+GroupMultipleLegacyBootOption4SameType (
+  UINT16                   *BootOption,
+  UINTN                    BootOptionCount
+  )
+{
+  UINTN                    DeviceTypeIndex[7];
+  UINTN                    Index;
+  UINTN                    MappingIndex;
+  UINTN                    *NextIndex;
+  UINT16                   OptionNumber;
+  UINTN                    DeviceIndex;
+
+  SetMem (DeviceTypeIndex, sizeof (DeviceTypeIndex), 0xFF);
+
+  for (Index = 0; Index < BootOptionCount; Index++) {
+
+    //
+    // Find the DeviceType
+    //
+    for (MappingIndex = 0; MappingIndex < mBootOptionBbsMappingCount; MappingIndex++) {
+      if (mBootOptionBbsMapping[MappingIndex].BootOptionNumber == BootOption[Index]) {
+        break;
+      }
+    }
+    if (MappingIndex == mBootOptionBbsMappingCount) {
+      //
+      // Is not a legacy boot option
+      //
+      continue;
+    }
+
+    ASSERT ((mBootOptionBbsMapping[MappingIndex].BbsType & 0xF) < 
+             sizeof (DeviceTypeIndex) / sizeof (DeviceTypeIndex[0]));
+    NextIndex = &DeviceTypeIndex[mBootOptionBbsMapping[MappingIndex].BbsType & 0xF];
+    if (*NextIndex == (UINTN) -1) {
+      //
+      // *NextIndex is the index in BootOption to put the next Option Number for the same type
+      //
+      *NextIndex = Index + 1;
+    } else {
+      //
+      // insert the current boot option before *NextIndex, causing [*Next .. Index] shift right one position
+      //
+      OptionNumber = BootOption[Index];
+      CopyMem (&BootOption[*NextIndex + 1], &BootOption[*NextIndex], (Index - *NextIndex) * sizeof (UINT16));
+      BootOption[*NextIndex] = OptionNumber;
+
+      //
+      // Update the DeviceTypeIndex array to reflect the right shift operation
+      //
+      for (DeviceIndex = 0; DeviceIndex < sizeof (DeviceTypeIndex) / sizeof (DeviceTypeIndex[0]); DeviceIndex++) {
+        if (DeviceTypeIndex[DeviceIndex] != (UINTN) -1 && DeviceTypeIndex[DeviceIndex] >= *NextIndex) {
+          DeviceTypeIndex[DeviceIndex]++;
+        }
+      }
+    }
+  }
+}
+
+/**
+  Function returns the value of the specified variable.
+
+
+  @param Name            A Null-terminated Unicode string that is
+                         the name of the vendor's variable.
+  @param VendorGuid      A unique identifier for the vendor.
+
+  @return               The payload of the variable.
+  @retval NULL          If the variable can't be read.
+
+**/
+VOID *
+EfiLibGetVariable (
+  IN CHAR16               *Name,
+  IN EFI_GUID             *VendorGuid
+  )
+{
+  UINTN VarSize;
+
+  return BdsLibGetVariableAndSize (Name, VendorGuid, &VarSize);
+}
+
+/**
+  Function deletes the variable specified by VarName and VarGuid.
+
+  @param VarName           A Null-terminated Unicode string that is
+                           the name of the vendor's variable.
+                         
+  @param VarGuid           A unique identifier for the vendor.
+
+  @retval  EFI_SUCCESS           The variable was found and removed
+  @retval  EFI_UNSUPPORTED       The variable store was inaccessible
+  @retval  EFI_OUT_OF_RESOURCES  The temporary buffer was not available
+  @retval  EFI_NOT_FOUND         The variable was not found
+
+**/
+EFI_STATUS
+EfiLibDeleteVariable (
+  IN CHAR16   *VarName,
+  IN EFI_GUID *VarGuid
+  )
+{
+  VOID        *VarBuf;
+  EFI_STATUS  Status;
+
+  VarBuf  = EfiLibGetVariable (VarName, VarGuid);
+  Status  = EFI_NOT_FOUND;
+
+  if (VarBuf != NULL) {
+    //
+    // Delete variable from Storage
+    //
+    Status = gRT->SetVariable (VarName, VarGuid, VAR_FLAG, 0, NULL);
+    ASSERT (!EFI_ERROR (Status));
+    FreePool (VarBuf);
+  }
+
+  return Status;
+}
+
+/**
+  Add the legacy boot options from BBS table if they do not exist.
+
+  @retval EFI_SUCCESS          The boot options are added successfully 
+                               or they are already in boot options.
+  @retval EFI_NOT_FOUND        No legacy boot options is found.
+  @retval EFI_OUT_OF_RESOURCE  No enough memory.
+  @return Other value          LegacyBoot options are not added.
+**/
+EFI_STATUS
+EFIAPI
+BdsAddNonExistingLegacyBootOptions (
+  VOID
+  )
+{
+  UINT16                    *BootOrder;
+  UINTN                     BootOrderSize;
+  EFI_STATUS                Status;
+  CHAR16                    Desc[100];
+  UINT16                    HddCount;
+  UINT16                    BbsCount;
+  HDD_INFO                  *LocalHddInfo;
+  BBS_TABLE                 *LocalBbsTable;
+  UINT16                    BbsIndex;
+  EFI_LEGACY_BIOS_PROTOCOL  *LegacyBios;
+  UINT16                    Index;
+  UINT32                    Attribute;
+  UINT16                    OptionNumber;
+  BOOLEAN                   Exist;
+
+  HddCount      = 0;
+  BbsCount      = 0;
+  LocalHddInfo  = NULL;
+  LocalBbsTable = NULL;
+
+  Status        = EfiLibLocateProtocol (&gEfiLegacyBiosProtocolGuid, (VOID **) &LegacyBios);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  if (mBootOptionBbsMapping != NULL) {
+    FreePool (mBootOptionBbsMapping);
+
+    mBootOptionBbsMapping      = NULL;
+    mBootOptionBbsMappingCount = 0;
+  }
+
+  LegacyBios->GetBbsInfo (
+                LegacyBios,
+                &HddCount,
+                &LocalHddInfo,
+                &BbsCount,
+                &LocalBbsTable
+                );
+
+  BootOrder = BdsLibGetVariableAndSize (
+                L"BootOrder",
+                &gEfiGlobalVariableGuid,
+                &BootOrderSize
+                );
+  if (BootOrder == NULL) {
+    BootOrderSize = 0;
+  }
+
+  for (Index = 0; Index < BbsCount; Index++) {
+    if ((LocalBbsTable[Index].BootPriority == BBS_IGNORE_ENTRY) ||
+        (LocalBbsTable[Index].BootPriority == BBS_DO_NOT_BOOT_FROM)
+        ) {
+      continue;
+    }
+
+    BdsBuildLegacyDevNameString (&LocalBbsTable[Index], Index, sizeof (Desc), Desc);
+
+    Exist = BdsFindLegacyBootOptionByDevTypeAndName (
+              BootOrder,
+              BootOrderSize / sizeof (UINT16),
+              LocalBbsTable[Index].DeviceType,
+              Desc,
+              &Attribute,
+              &BbsIndex,
+              &OptionNumber
+              );
+    if (!Exist) {
+      //
+      // Not found such type of legacy device in boot options or we found but it's disabled
+      // so we have to create one and put it to the tail of boot order list
+      //
+      Status = BdsCreateOneLegacyBootOption (
+                &LocalBbsTable[Index],
+                Index,
+                &BootOrder,
+                &BootOrderSize
+                );
+      if (EFI_ERROR (Status)) {
+        break;
+      }
+      BbsIndex     = Index;
+      OptionNumber = BootOrder[BootOrderSize / sizeof (UINT16) - 1];
+    }
+
+    ASSERT (BbsIndex == Index);
+    //
+    // Save the BbsIndex
+    //
+    mBootOptionBbsMapping = ReallocatePool (
+                              mBootOptionBbsMappingCount * sizeof (BOOT_OPTION_BBS_MAPPING),
+                              (mBootOptionBbsMappingCount + 1) * sizeof (BOOT_OPTION_BBS_MAPPING),
+                              mBootOptionBbsMapping
+                              );
+    ASSERT (mBootOptionBbsMapping != NULL);
+    mBootOptionBbsMapping[mBootOptionBbsMappingCount].BootOptionNumber = OptionNumber;
+    mBootOptionBbsMapping[mBootOptionBbsMappingCount].BbsIndex         = Index;
+    mBootOptionBbsMapping[mBootOptionBbsMappingCount].BbsType          = LocalBbsTable[Index].DeviceType;
+    mBootOptionBbsMappingCount ++;
+  }
+
+  //
+  // Group the Boot Option Number in BootOrder for the same type devices
+  //
+  GroupMultipleLegacyBootOption4SameType (
+    BootOrder,
+    BootOrderSize / sizeof (UINT16)
+    );
+
+  if (BootOrderSize > 0) {
+    Status = gRT->SetVariable (
+                    L"BootOrder",
+                    &gEfiGlobalVariableGuid,
+                    VAR_FLAG,
+                    BootOrderSize,
+                    BootOrder
+                    );
+  } else {
+    EfiLibDeleteVariable (L"BootOrder", &gEfiGlobalVariableGuid);
+  }
+
+  if (BootOrder != NULL) {
+    FreePool (BootOrder);
+  }
+
+  return Status;
+}
+
+/**
+  Deletete the Boot Option from EFI Variable. The Boot Order Arrray
+  is also updated.
+
+  @param OptionNumber    The number of Boot option want to be deleted.
+  @param BootOrder       The Boot Order array.
+  @param BootOrderSize   The size of the Boot Order Array.
+
+  @retval  EFI_SUCCESS           The Boot Option Variable was found and removed
+  @retval  EFI_UNSUPPORTED       The Boot Option Variable store was inaccessible
+  @retval  EFI_NOT_FOUND         The Boot Option Variable was not found
+**/
+EFI_STATUS
+EFIAPI
+BdsDeleteBootOption (
+  IN UINTN                       OptionNumber,
+  IN OUT UINT16                  *BootOrder,
+  IN OUT UINTN                   *BootOrderSize
+  )
+{
+  UINT16      BootOption[100];
+  UINTN       Index;
+  EFI_STATUS  Status;
+  UINTN       Index2Del;
+
+  Status    = EFI_SUCCESS;
+  Index2Del = 0;
+
+  UnicodeSPrint (BootOption, sizeof (BootOption), L"Boot%04x", OptionNumber);
+  Status = EfiLibDeleteVariable (BootOption, &gEfiGlobalVariableGuid);
+
+  //
+  // adjust boot order array
+  //
+  for (Index = 0; Index < *BootOrderSize / sizeof (UINT16); Index++) {
+    if (BootOrder[Index] == OptionNumber) {
+      Index2Del = Index;
+      break;
+    }
+  }
+
+  if (Index != *BootOrderSize / sizeof (UINT16)) {
+    for (Index = 0; Index < *BootOrderSize / sizeof (UINT16) - 1; Index++) {
+      if (Index >= Index2Del) {
+        BootOrder[Index] = BootOrder[Index + 1];
+      }
+    }
+
+    *BootOrderSize -= sizeof (UINT16);
+  }
+
+  return Status;
+
+}
+
+/**
+  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
+EFIAPI
+BdsDeleteAllInvalidLegacyBootOptions (
+  VOID
+  )
+{
+  UINT16                    *BootOrder;
+  UINT8                     *BootOptionVar;
+  UINTN                     BootOrderSize;
+  UINTN                     BootOptionSize;
+  EFI_STATUS                Status;
+  UINT16                    HddCount;
+  UINT16                    BbsCount;
+  HDD_INFO                  *LocalHddInfo;
+  BBS_TABLE                 *LocalBbsTable;
+  BBS_TABLE                 *BbsEntry;
+  UINT16                    BbsIndex;
+  EFI_LEGACY_BIOS_PROTOCOL  *LegacyBios;
+  UINTN                     Index;
+  UINT16                    BootOption[10];
+  UINT16                    BootDesc[100];
+  BOOLEAN                   DescStringMatch;
+
+  Status        = EFI_SUCCESS;
+  BootOrder     = NULL;
+  BootOrderSize = 0;
+  HddCount      = 0;
+  BbsCount      = 0;
+  LocalHddInfo  = NULL;
+  LocalBbsTable = NULL;
+  BbsEntry      = NULL;
+
+  Status        = EfiLibLocateProtocol (&gEfiLegacyBiosProtocolGuid, (VOID **) &LegacyBios);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  LegacyBios->GetBbsInfo (
+                LegacyBios,
+                &HddCount,
+                &LocalHddInfo,
+                &BbsCount,
+                &LocalBbsTable
+                );
+
+  BootOrder = BdsLibGetVariableAndSize (
+                L"BootOrder",
+                &gEfiGlobalVariableGuid,
+                &BootOrderSize
+                );
+  if (BootOrder == NULL) {
+    BootOrderSize = 0;
+  }
+
+  Index = 0;
+  while (Index < BootOrderSize / sizeof (UINT16)) {
+    UnicodeSPrint (BootOption, sizeof (BootOption), L"Boot%04x", BootOrder[Index]);
+    BootOptionVar = BdsLibGetVariableAndSize (
+                      BootOption,
+                      &gEfiGlobalVariableGuid,
+                      &BootOptionSize
+                      );
+    if (NULL == BootOptionVar) {
+      BootOptionSize = 0;
+      Status = gRT->GetVariable (
+                      BootOption,
+                      &gEfiGlobalVariableGuid,
+                      NULL,
+                      &BootOptionSize,
+                      BootOptionVar
+                      );
+      if (Status == EFI_NOT_FOUND) {
+        //
+        // Update BootOrder
+        //
+        BdsDeleteBootOption (
+          BootOrder[Index],
+          BootOrder,
+          &BootOrderSize
+          );
+        continue;
+      } else {
+        FreePool (BootOrder);
+        return EFI_OUT_OF_RESOURCES;
+      }
+    }
+  
+    //
+    // Skip Non-Legacy boot option
+    // 
+    if (!BdsIsLegacyBootOption (BootOptionVar, &BbsEntry, &BbsIndex)) {
+      if (BootOptionVar!= NULL) {
+        FreePool (BootOptionVar);
+      }
+      Index++;
+      continue;
+    }
+
+    if (BbsIndex < BbsCount) {
+      //
+      // Check if BBS Description String is changed
+      //
+      DescStringMatch = FALSE;
+      BdsBuildLegacyDevNameString (
+        &LocalBbsTable[BbsIndex],
+        BbsIndex,
+        sizeof (BootDesc),
+        BootDesc
+        );
+
+      if (StrCmp (BootDesc, (UINT16*)(BootOptionVar + sizeof (UINT32) + sizeof (UINT16))) == 0) {
+        DescStringMatch = TRUE;
+      }
+
+      if (!((LocalBbsTable[BbsIndex].BootPriority == BBS_IGNORE_ENTRY) ||
+            (LocalBbsTable[BbsIndex].BootPriority == BBS_DO_NOT_BOOT_FROM)) &&
+          (LocalBbsTable[BbsIndex].DeviceType == BbsEntry->DeviceType) &&
+          DescStringMatch) {
+        Index++;
+        continue;
+      }
+    }
+
+    if (BootOptionVar != NULL) {
+      FreePool (BootOptionVar);
+    }
+    //
+    // should delete
+    //
+    BdsDeleteBootOption (
+      BootOrder[Index],
+      BootOrder,
+      &BootOrderSize
+      );
+  }
+
+  //
+  // Adjust the number of boot options.
+  //
+  if (BootOrderSize != 0) {
+    Status = gRT->SetVariable (
+                    L"BootOrder",
+                    &gEfiGlobalVariableGuid,
+                    VAR_FLAG,
+                    BootOrderSize,
+                    BootOrder
+                    );
+  } else {
+    EfiLibDeleteVariable (L"BootOrder", &gEfiGlobalVariableGuid);
+  }
+
+  if (BootOrder != NULL) {
+    FreePool (BootOrder);
+  }
+
+  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
+// EFIAPI
+// BdsUpdateLegacyDevOrder (
+//   VOID
+//   )
+// {
+//   LEGACY_DEV_ORDER_ENTRY      *DevOrder;
+//   LEGACY_DEV_ORDER_ENTRY      *NewDevOrder;
+//   LEGACY_DEV_ORDER_ENTRY      *Ptr;
+//   LEGACY_DEV_ORDER_ENTRY      *NewPtr;
+//   UINTN                       DevOrderSize;
+//   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        = EfiLibLocateProtocol (&gEfiLegacyBiosProtocolGuid, (VOID **) &LegacyBios);
+//   if (EFI_ERROR (Status)) {
+//     return Status;
+//   }
+// 
+//   Status = LegacyBios->GetBbsInfo (
+//                          LegacyBios,
+//                          &HddCount,
+//                          &LocalHddInfo,
+//                          &BbsCount,
+//                          &LocalBbsTable
+//                          );
+//   if (EFI_ERROR (Status)) {
+//     return Status;
+//   }
+// 
+//   DevOrder = BdsLibGetVariableAndSize (
+//                VAR_LEGACY_DEV_ORDER,
+//                &gEfiLegacyDevOrderVariableGuid,
+//                &DevOrderSize
+//                );
+//   if (NULL == DevOrder) {
+//     return BdsCreateDevOrder (LocalBbsTable, BbsCount);
+//   }
+//   //
+//   // First we figure out how many boot devices with same device type respectively
+//   //
+//   for (Index = 0; Index < BbsCount; Index++) {
+//     if ((LocalBbsTable[Index].BootPriority == BBS_IGNORE_ENTRY) ||
+//         (LocalBbsTable[Index].BootPriority == BBS_DO_NOT_BOOT_FROM)
+//         ) {
+//       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 (LocalBbsTable[Ptr->Data[Index] & 0xFF].BootPriority == BBS_IGNORE_ENTRY ||
+//         LocalBbsTable[Ptr->Data[Index] & 0xFF].BootPriority == BBS_DO_NOT_BOOT_FROM ||
+//         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 (LocalBbsTable[Ptr->Data[Index] & 0xFF].BootPriority == BBS_IGNORE_ENTRY ||
+//         LocalBbsTable[Ptr->Data[Index] & 0xFF].BootPriority == BBS_DO_NOT_BOOT_FROM ||
+//         LocalBbsTable[Ptr->Data[Index] & 0xFF].BootPriority == BBS_LOWEST_PRIORITY ||
+//         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 (LocalBbsTable[Ptr->Data[Index] & 0xFF].BootPriority == BBS_IGNORE_ENTRY ||
+//         LocalBbsTable[Ptr->Data[Index] & 0xFF].BootPriority == BBS_DO_NOT_BOOT_FROM ||
+//         LocalBbsTable[Ptr->Data[Index] & 0xFF].BootPriority == BBS_LOWEST_PRIORITY ||
+//         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 (LocalBbsTable[Ptr->Data[Index] & 0xFF].BootPriority == BBS_IGNORE_ENTRY ||
+//         LocalBbsTable[Ptr->Data[Index] & 0xFF].BootPriority == BBS_DO_NOT_BOOT_FROM ||
+//         LocalBbsTable[Ptr->Data[Index] & 0xFF].BootPriority == BBS_LOWEST_PRIORITY ||
+//         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 (LocalBbsTable[Ptr->Data[Index] & 0xFF].BootPriority == BBS_IGNORE_ENTRY ||
+//         LocalBbsTable[Ptr->Data[Index] & 0xFF].BootPriority == BBS_DO_NOT_BOOT_FROM ||
+//         LocalBbsTable[Ptr->Data[Index] & 0xFF].BootPriority == BBS_LOWEST_PRIORITY ||
+//         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 ((LocalBbsTable[Index].BootPriority == BBS_IGNORE_ENTRY) ||
+//         (LocalBbsTable[Index].BootPriority == BBS_DO_NOT_BOOT_FROM)
+//         ) {
+//       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,
+//                   VAR_FLAG,
+//                   TotalSize,
+//                   NewDevOrder
+//                   );
+//   FreePool (NewDevOrder);
+// 
+//   return Status;
+// }
+
diff --git a/EfiLib/legacy.h b/EfiLib/legacy.h
new file mode 100644 (file)
index 0000000..61dba38
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * EfiLib/legacy.h
+ * CSM/legacy boot support functions
+ * 
+ * Taken from Tianocore source code (mostly IntelFrameworkModulePkg/Universal/BdsDxe/BootMaint/BBSsupport.c)
+ *
+ * Copyright (c) 2004 - 2011, 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 __LEGACY_H_
+#define __LEGACY_H_
+
+#define VAR_FLAG  EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE
+
+#pragma pack(1)
+///
+/// For each legacy boot option in BBS table, a corresponding Boot#### variables is created.
+/// The structure saves the mapping relationship between #### and the index in the BBS table.
+///
+typedef struct {
+   UINT16    BootOptionNumber;
+   UINT16    BbsIndex;
+   UINT16    BbsType;
+} BOOT_OPTION_BBS_MAPPING;
+#pragma pack()
+
+EFI_STATUS
+EFIAPI
+BdsAddNonExistingLegacyBootOptions (
+   VOID
+);
+
+/**
+  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
+EFIAPI
+BdsDeleteAllInvalidLegacyBootOptions (
+  VOID
+  );
+
+/**
+  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
+// EFIAPI
+// BdsUpdateLegacyDevOrder (
+//   VOID
+//   );
+
+#endif
\ No newline at end of file