Revision: 17330
          http://sourceforge.net/p/edk2/code/17330
Author:   niruiyu
Date:     2015-05-06 04:50:23 +0000 (Wed, 06 May 2015)
Log Message:
-----------
IntelFrameworkModulePkg: Add LegacyBootManagerLib.

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 <[email protected]>
Reviewed-by: Eric Dong <[email protected]>

Modified Paths:
--------------
    trunk/edk2/IntelFrameworkModulePkg/IntelFrameworkModulePkg.dsc

Added Paths:
-----------
    trunk/edk2/IntelFrameworkModulePkg/Library/LegacyBootManagerLib/
    
trunk/edk2/IntelFrameworkModulePkg/Library/LegacyBootManagerLib/InternalLegacyBm.h
    trunk/edk2/IntelFrameworkModulePkg/Library/LegacyBootManagerLib/LegacyBm.c
    
trunk/edk2/IntelFrameworkModulePkg/Library/LegacyBootManagerLib/LegacyBootManagerLib.inf

Modified: trunk/edk2/IntelFrameworkModulePkg/IntelFrameworkModulePkg.dsc
===================================================================
--- trunk/edk2/IntelFrameworkModulePkg/IntelFrameworkModulePkg.dsc      
2015-05-06 04:49:30 UTC (rev 17329)
+++ trunk/edk2/IntelFrameworkModulePkg/IntelFrameworkModulePkg.dsc      
2015-05-06 04:50:23 UTC (rev 17330)
@@ -3,7 +3,7 @@
 #
 # This file is used to build all modules in IntelFrameworkModulePkg.
 #
-#Copyright (c) 2007 - 2014, Intel Corporation. All rights reserved.<BR>
+#Copyright (c) 2007 - 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 that accompanies this 
distribution.  
 #The full text of the license may be found at
@@ -139,6 +139,7 @@
   IntelFrameworkModulePkg/Library/PlatformBdsLibNull/PlatformBdsLibNull.inf
   IntelFrameworkModulePkg/Library/GenericBdsLib/GenericBdsLib.inf
   IntelFrameworkModulePkg/Library/DxeCapsuleLib/DxeCapsuleLib.inf
+  IntelFrameworkModulePkg/Library/LegacyBootManagerLib/LegacyBootManagerLib.inf
 
   IntelFrameworkModulePkg/Bus/Pci/IdeBusDxe/IdeBusDxe.inf
   IntelFrameworkModulePkg/Bus/Isa/IsaBusDxe/IsaBusDxe.inf

Added: 
trunk/edk2/IntelFrameworkModulePkg/Library/LegacyBootManagerLib/InternalLegacyBm.h
===================================================================
--- 
trunk/edk2/IntelFrameworkModulePkg/Library/LegacyBootManagerLib/InternalLegacyBm.h
                          (rev 0)
+++ 
trunk/edk2/IntelFrameworkModulePkg/Library/LegacyBootManagerLib/InternalLegacyBm.h
  2015-05-06 04:50:23 UTC (rev 17330)
@@ -0,0 +1,66 @@
+/** @file
+
+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.
+
+**/
+
+#ifndef _INTERNAL_LEGACY_BM_H_
+#define _INTERNAL_LEGACY_BM_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_BM_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
+LegacyBmBoot (
+  IN  EFI_BOOT_MANAGER_LOAD_OPTION           *BootOption
+  );
+
+/**
+  Refresh all legacy boot options.
+
+**/
+VOID
+EFIAPI
+LegacyBmRefreshAllBootOption (
+  VOID
+  );
+
+#endif // _INTERNAL_LEGACY_BM_H_
\ No newline at end of file

Added: 
trunk/edk2/IntelFrameworkModulePkg/Library/LegacyBootManagerLib/LegacyBm.c
===================================================================
--- trunk/edk2/IntelFrameworkModulePkg/Library/LegacyBootManagerLib/LegacyBm.c  
                        (rev 0)
+++ trunk/edk2/IntelFrameworkModulePkg/Library/LegacyBootManagerLib/LegacyBm.c  
2015-05-06 04:50:23 UTC (rev 17330)
@@ -0,0 +1,1536 @@
+/** @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 "InternalLegacyBm.h"
+
+#define  LEGACY_BM_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
+LegacyBootManagerLibConstructor (
+  IN EFI_HANDLE                            ImageHandle,
+  IN EFI_SYSTEM_TABLE                      *SystemTable
+)
+{
+  EfiBootManagerRegisterLegacyBootSupport (
+    LegacyBmRefreshAllBootOption,
+    LegacyBmBoot
+    );
+  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
+LegacyBmDeviceType (
+  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
+LegacyBmValidBbsEntry (
+  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
+LegacyBmBuildLegacyDevNameString (
+  IN  BBS_TABLE                 *CurBBSEntry,
+  IN  UINTN                     Index,
+  IN  UINTN                     BufSize,
+  OUT CHAR16                    *BootString
+  )
+{
+  CHAR16  *Fmt;
+  CHAR16  *Type;
+  CHAR8   *StringDesc;
+  CHAR8   StringBufferA[LEGACY_BM_BOOT_DESCRIPTION_LENGTH + 1];
+  CHAR16  StringBufferU[LEGACY_BM_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, LEGACY_BM_BOOT_DESCRIPTION_LENGTH);
+    StringBufferA[LEGACY_BM_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
+LegacyBmFuzzyMatch (
+  EFI_BOOT_MANAGER_LOAD_OPTION   *BootOption,
+  BBS_TABLE                      *BbsTable,
+  UINT16                         BbsCount,
+  BOOLEAN                        *BbsIndexUsed
+  )
+{
+  UINT16                         Index;
+  LEGACY_BM_BOOT_OPTION_BBS_DATA *BbsData;
+  CHAR16                         Description[LEGACY_BM_BOOT_DESCRIPTION_LENGTH 
+ 1];
+
+  BbsData = (LEGACY_BM_BOOT_OPTION_BBS_DATA *) BootOption->OptionalData;
+
+  //
+  // Directly check the BBS index stored in BootOption
+  //
+  if ((BbsData->BbsIndex < BbsCount) &&
+      (LegacyBmDeviceType (BootOption->FilePath) == 
BbsTable[BbsData->BbsIndex].DeviceType)) {
+    LegacyBmBuildLegacyDevNameString (
+      &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 (!LegacyBmValidBbsEntry (&BbsTable[Index]) ||
+        (BbsTable[Index].DeviceType != LegacyBmDeviceType 
(BootOption->FilePath))) {
+      continue;
+    }
+
+    LegacyBmBuildLegacyDevNameString (
+      &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
+LegacyBmUpdateBbsIndex (
+  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
+LegacyBmDeleteAllBootOptions (
+  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
+LegacyBmDeleteAllInvalidBootOptions (
+  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 = LegacyBmFuzzyMatch (&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
+      //
+      LegacyBmUpdateBbsIndex (
+        LegacyDevOrder,
+        &LegacyDevOrderSize,
+        LegacyBmDeviceType (BootOption[Index].FilePath),
+        ((LEGACY_BM_BOOT_OPTION_BBS_DATA *) 
BootOption[Index].OptionalData)->BbsIndex,
+        (UINT16) -1
+        );
+      EfiBootManagerDeleteLoadOptionVariable (BootOption[Index].OptionNumber, 
BootOption[Index].OptionType);
+    } else {
+      if (((LEGACY_BM_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_BM_BOOT_OPTION_BBS_DATA *) 
BootOption[Index].OptionalData)->BbsIndex, (UINTN) BbsIndex));
+        //
+        // Update the BBS index in LegacyDevOrder
+        //
+        LegacyBmUpdateBbsIndex (
+          LegacyDevOrder,
+          &LegacyDevOrderSize,
+          LegacyBmDeviceType (BootOption[Index].FilePath),
+          ((LEGACY_BM_BOOT_OPTION_BBS_DATA *) 
BootOption[Index].OptionalData)->BbsIndex,
+          BbsIndex
+          );
+
+        //
+        // Update the OptionalData in the Boot#### variable
+        //
+        ((LEGACY_BM_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;
+}
+
+/**
+  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
+LegacyBmCreateLegacyBootOption (
+  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[LEGACY_BM_BOOT_DESCRIPTION_LENGTH + 
1];
+  CHAR8                        HelpString[LEGACY_BM_BOOT_DESCRIPTION_LENGTH + 
1];
+  UINTN                        StringLen;
+  LEGACY_BM_BOOT_OPTION_BBS_DATA  *OptionalData;
+  BBS_BBS_DEVICE_PATH          *BbsNode;
+
+  if ((BootOption == NULL) || (BbsEntry == NULL)) {
+    return EFI_INVALID_PARAMETER;
+  }
+  
+  LegacyBmBuildLegacyDevNameString (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_BM_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_BM_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 *
+LegacyBmFillDevOrderBuf (
+  IN BBS_TABLE                    *BbsTable,
+  IN BBS_TYPE                     BbsType,
+  IN UINTN                        BbsCount,
+  OUT UINT16                      *Buf
+  )
+{
+  UINTN Index;
+
+  for (Index = 0; Index < BbsCount; Index++) {
+    if (!LegacyBmValidBbsEntry (&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
+LegacyBmCreateDevOrder (
+  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 (!LegacyBmValidBbsEntry (&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 *) LegacyBmFillDevOrderBuf 
(BbsTable, BBS_FLOPPY, BbsCount, DevOrderPtr->Data);
+
+  DevOrderPtr->BbsType = BBS_HARDDISK;
+  DevOrderPtr->Length  = (UINT16) (sizeof (UINT16) + HDCount * sizeof 
(UINT16));
+  DevOrderPtr          = (LEGACY_DEV_ORDER_ENTRY *) LegacyBmFillDevOrderBuf 
(BbsTable, BBS_HARDDISK, BbsCount, DevOrderPtr->Data);
+  
+  DevOrderPtr->BbsType = BBS_CDROM;
+  DevOrderPtr->Length  = (UINT16) (sizeof (UINT16) + CDCount * sizeof 
(UINT16));
+  DevOrderPtr          = (LEGACY_DEV_ORDER_ENTRY *) LegacyBmFillDevOrderBuf 
(BbsTable, BBS_CDROM, BbsCount, DevOrderPtr->Data);
+  
+  DevOrderPtr->BbsType = BBS_EMBED_NETWORK;
+  DevOrderPtr->Length  = (UINT16) (sizeof (UINT16) + NETCount * sizeof 
(UINT16));
+  DevOrderPtr          = (LEGACY_DEV_ORDER_ENTRY *) LegacyBmFillDevOrderBuf 
(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 *) LegacyBmFillDevOrderBuf 
(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
+LegacyBmUpdateDevOrder (
+  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 LegacyBmCreateDevOrder (LocalBbsTable, BbsCount);
+  }
+  //
+  // First we figure out how many boot devices with same device type 
respectively
+  //
+  for (Index = 0; Index < BbsCount; Index++) {
+    if (!LegacyBmValidBbsEntry (&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 (!LegacyBmValidBbsEntry (&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 (!LegacyBmValidBbsEntry (&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 (!LegacyBmValidBbsEntry (&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 (!LegacyBmValidBbsEntry (&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 (!LegacyBmValidBbsEntry (&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 (!LegacyBmValidBbsEntry (&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
+LegacyBmSetPriorityForSameTypeDev (
+  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 (!LegacyBmValidBbsEntry (&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
+LegacyBmPrintBbsTable (
+  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 (!LegacyBmValidBbsEntry (&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
+LegacyBmRefreshBbsTableForBoot (
+  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 (LegacyBmValidBbsEntry (&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  = LegacyBmDeviceType (BootOption->FilePath);
+    BbsIndex = ((LEGACY_BM_BOOT_OPTION_BBS_DATA *) 
BootOption->OptionalData)->BbsIndex;
+    Status = LegacyBmSetPriorityForSameTypeDev (
+               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 = LegacyBmDeviceType (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 = LegacyBmSetPriorityForSameTypeDev (
+               DevType,
+               (UINTN) -1,
+               LocalBbsTable,
+               &Priority
+               );
+  }
+  EfiBootManagerFreeLoadOptions (Option, OptionCount);
+
+  DEBUG_CODE_BEGIN();
+    LegacyBmPrintBbsTable (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
+LegacyBmBoot (
+  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 = LegacyBmRefreshBbsTableForBoot (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 *
+LegacyBmEnumerateAllBootOptions (
+  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 (!LegacyBmValidBbsEntry (&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 = LegacyBmCreateLegacyBootOption 
(&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
+LegacyBmFindBootOption (
+  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
+LegacyBmRefreshAllBootOption (
+  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)) {
+    LegacyBmDeleteAllBootOptions ();
+    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
+  //
+  LegacyBmDeleteAllInvalidBootOptions ();
+
+  ExistingBootOptions = EfiBootManagerGetLoadOptions 
(&ExistingBootOptionCount, LoadOptionTypeBoot);
+  BootOptions         = LegacyBmEnumerateAllBootOptions   (&BootOptionCount);
+
+  for (Index = 0; Index < BootOptionCount; Index++) {
+    if (LegacyBmFindBootOption (&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_BM_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.
+  //
+  LegacyBmUpdateDevOrder ();
+
+  PERF_END   (NULL, "LegacyBootOptionEnum", "BDS", 0);
+}

Added: 
trunk/edk2/IntelFrameworkModulePkg/Library/LegacyBootManagerLib/LegacyBootManagerLib.inf
===================================================================
--- 
trunk/edk2/IntelFrameworkModulePkg/Library/LegacyBootManagerLib/LegacyBootManagerLib.inf
                            (rev 0)
+++ 
trunk/edk2/IntelFrameworkModulePkg/Library/LegacyBootManagerLib/LegacyBootManagerLib.inf
    2015-05-06 04:50:23 UTC (rev 17330)
@@ -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                    = LegacyBootManagerLibConstructor
+
+#
+# The following information is for reference only and not required by the 
build tools.
+#
+#  VALID_ARCHITECTURES           = IA32 X64 EBC
+#
+
+[Sources]
+  LegacyBm.c
+  InternalLegacyBm.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]


------------------------------------------------------------------------------
One dashboard for servers and applications across Physical-Virtual-Cloud 
Widest out-of-the-box monitoring support with 50+ applications
Performance metrics, stats and reports that give you Actionable Insights
Deep dive visibility with transaction tracing using APM Insight.
http://ad.doubleclick.net/ddm/clk/290420510;117567292;y
_______________________________________________
edk2-commits mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/edk2-commits

Reply via email to