]> git.proxmox.com Git - mirror_edk2.git/blobdiff - IntelFrameworkModulePkg/Library/GenericBdsLib/BdsBoot.c
Remove the RT attribute for HDDP variable and validate the variable content before...
[mirror_edk2.git] / IntelFrameworkModulePkg / Library / GenericBdsLib / BdsBoot.c
index 61699edeb892c51df30df8ac2d0f4dd094d864b0..de69a04b04be9b1bda379f5c33b5f220e0b93a53 100644 (file)
@@ -1,7 +1,7 @@
 /** @file\r
   BDS Lib functions which relate with create or process the boot option.\r
 \r
-Copyright (c) 2004 - 2010, Intel Corporation. All rights reserved.<BR>\r
+Copyright (c) 2004 - 2014, Intel Corporation. All rights reserved.<BR>\r
 This program and the accompanying materials\r
 are licensed and made available under the terms and conditions of the BSD License\r
 which accompanies this distribution.  The full text of the license may be found at\r
@@ -18,56 +18,1639 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 BOOLEAN mEnumBootDevice = FALSE;\r
 EFI_HII_HANDLE gBdsLibStringPackHandle = NULL;\r
 \r
-///\r
-/// This GUID is used for an EFI Variable that stores the front device pathes\r
-/// for a partial device path that starts with the HD node.\r
-///\r
-EFI_GUID  mHdBootVariablePrivateGuid = { 0xfab7e9e1, 0x39dd, 0x4f2b, { 0x84, 0x8, 0xe2, 0xe, 0x90, 0x6c, 0xb6, 0xde } };\r
+/**\r
+  The constructor function register UNI strings into imageHandle.\r
+  \r
+  It will ASSERT() if that operation fails and it will always return EFI_SUCCESS. \r
+\r
+  @param  ImageHandle   The firmware allocated handle for the EFI image.\r
+  @param  SystemTable   A pointer to the EFI System Table.\r
+  \r
+  @retval EFI_SUCCESS   The constructor successfully added string package.\r
+  @retval Other value   The constructor can't add string package.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+GenericBdsLibConstructor (\r
+  IN EFI_HANDLE        ImageHandle,\r
+  IN EFI_SYSTEM_TABLE  *SystemTable\r
+  )\r
+{\r
+\r
+  gBdsLibStringPackHandle = HiiAddPackages (\r
+                              &gBdsLibStringPackageGuid,\r
+                              ImageHandle,\r
+                              GenericBdsLibStrings,\r
+                              NULL\r
+                              );\r
+\r
+  ASSERT (gBdsLibStringPackHandle != NULL);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Deletete the Boot Option from EFI Variable. The Boot Order Arrray\r
+  is also updated.\r
+\r
+  @param OptionNumber    The number of Boot option want to be deleted.\r
+  @param BootOrder       The Boot Order array.\r
+  @param BootOrderSize   The size of the Boot Order Array.\r
+\r
+  @retval  EFI_SUCCESS           The Boot Option Variable was found and removed\r
+  @retval  EFI_UNSUPPORTED       The Boot Option Variable store was inaccessible\r
+  @retval  EFI_NOT_FOUND         The Boot Option Variable was not found\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+BdsDeleteBootOption (\r
+  IN UINTN                       OptionNumber,\r
+  IN OUT UINT16                  *BootOrder,\r
+  IN OUT UINTN                   *BootOrderSize\r
+  )\r
+{\r
+  CHAR16      BootOption[9];\r
+  UINTN       Index;\r
+  EFI_STATUS  Status;\r
+\r
+  UnicodeSPrint (BootOption, sizeof (BootOption), L"Boot%04x", OptionNumber);\r
+  Status = gRT->SetVariable (\r
+                  BootOption,\r
+                  &gEfiGlobalVariableGuid,\r
+                  0,\r
+                  0,\r
+                  NULL\r
+                  );\r
+  //\r
+  // Deleting variable with existing variable implementation shouldn't fail.\r
+  //\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  //\r
+  // adjust boot order array\r
+  //\r
+  for (Index = 0; Index < *BootOrderSize / sizeof (UINT16); Index++) {\r
+    if (BootOrder[Index] == OptionNumber) {\r
+      CopyMem (&BootOrder[Index], &BootOrder[Index+1], *BootOrderSize - (Index+1) * sizeof (UINT16));\r
+      *BootOrderSize -= sizeof (UINT16);\r
+      break;\r
+    }\r
+  }\r
+\r
+  return Status;\r
+}\r
+/**\r
+\r
+  Translate the first n characters of an Ascii string to\r
+  Unicode characters. The count n is indicated by parameter\r
+  Size. If Size is greater than the length of string, then\r
+  the entire string is translated.\r
+\r
+\r
+  @param AStr               Pointer to input Ascii string.\r
+  @param Size               The number of characters to translate.\r
+  @param UStr               Pointer to output Unicode string buffer.\r
+\r
+**/\r
+VOID\r
+AsciiToUnicodeSize (\r
+  IN UINT8              *AStr,\r
+  IN UINTN              Size,\r
+  OUT UINT16            *UStr\r
+  )\r
+{\r
+  UINTN Idx;\r
+\r
+  Idx = 0;\r
+  while (AStr[Idx] != 0) {\r
+    UStr[Idx] = (CHAR16) AStr[Idx];\r
+    if (Idx == Size) {\r
+      break;\r
+    }\r
+\r
+    Idx++;\r
+  }\r
+  UStr[Idx] = 0;\r
+}\r
+\r
+/**\r
+  Build Legacy Device Name String according.\r
+\r
+  @param CurBBSEntry     BBS Table.\r
+  @param Index           Index.\r
+  @param BufSize         The buffer size.\r
+  @param BootString      The output string.\r
+\r
+**/\r
+VOID\r
+BdsBuildLegacyDevNameString (\r
+  IN  BBS_TABLE                 *CurBBSEntry,\r
+  IN  UINTN                     Index,\r
+  IN  UINTN                     BufSize,\r
+  OUT CHAR16                    *BootString\r
+  )\r
+{\r
+  CHAR16  *Fmt;\r
+  CHAR16  *Type;\r
+  UINT8   *StringDesc;\r
+  CHAR16  Temp[80];\r
+\r
+  switch (Index) {\r
+  //\r
+  // Primary Master\r
+  //\r
+  case 1:\r
+    Fmt = L"Primary Master %s";\r
+    break;\r
+\r
+ //\r
+ // Primary Slave\r
+ //\r
+  case 2:\r
+    Fmt = L"Primary Slave %s";\r
+    break;\r
+\r
+  //\r
+  // Secondary Master\r
+  //\r
+  case 3:\r
+    Fmt = L"Secondary Master %s";\r
+    break;\r
+\r
+  //\r
+  // Secondary Slave\r
+  //\r
+  case 4:\r
+    Fmt = L"Secondary Slave %s";\r
+    break;\r
+\r
+  default:\r
+    Fmt = L"%s";\r
+    break;\r
+  }\r
+\r
+  switch (CurBBSEntry->DeviceType) {\r
+  case BBS_FLOPPY:\r
+    Type = L"Floppy";\r
+    break;\r
+\r
+  case BBS_HARDDISK:\r
+    Type = L"Harddisk";\r
+    break;\r
+\r
+  case BBS_CDROM:\r
+    Type = L"CDROM";\r
+    break;\r
+\r
+  case BBS_PCMCIA:\r
+    Type = L"PCMCIAe";\r
+    break;\r
+\r
+  case BBS_USB:\r
+    Type = L"USB";\r
+    break;\r
+\r
+  case BBS_EMBED_NETWORK:\r
+    Type = L"Network";\r
+    break;\r
+\r
+  case BBS_BEV_DEVICE:\r
+    Type = L"BEVe";\r
+    break;\r
+\r
+  case BBS_UNKNOWN:\r
+  default:\r
+    Type = L"Unknown";\r
+    break;\r
+  }\r
+  //\r
+  // If current BBS entry has its description then use it.\r
+  //\r
+  StringDesc = (UINT8 *) (UINTN) ((CurBBSEntry->DescStringSegment << 4) + CurBBSEntry->DescStringOffset);\r
+  if (NULL != StringDesc) {\r
+    //\r
+    // Only get fisrt 32 characters, this is suggested by BBS spec\r
+    //\r
+    AsciiToUnicodeSize (StringDesc, 32, Temp);\r
+    Fmt   = L"%s";\r
+    Type  = Temp;\r
+  }\r
+\r
+  //\r
+  // BbsTable 16 entries are for onboard IDE.\r
+  // Set description string for SATA harddisks, Harddisk 0 ~ Harddisk 11\r
+  //\r
+  if (Index >= 5 && Index <= 16 && (CurBBSEntry->DeviceType == BBS_HARDDISK || CurBBSEntry->DeviceType == BBS_CDROM)) {\r
+    Fmt = L"%s %d";\r
+    UnicodeSPrint (BootString, BufSize, Fmt, Type, Index - 5);\r
+  } else {\r
+    UnicodeSPrint (BootString, BufSize, Fmt, Type);\r
+  }\r
+}\r
+\r
+/**\r
+\r
+  Create a legacy boot option for the specified entry of\r
+  BBS table, save it as variable, and append it to the boot\r
+  order list.\r
+\r
+\r
+  @param CurrentBbsEntry    Pointer to current BBS table.\r
+  @param CurrentBbsDevPath  Pointer to the Device Path Protocol instance of BBS\r
+  @param Index              Index of the specified entry in BBS table.\r
+  @param BootOrderList      On input, the original boot order list.\r
+                            On output, the new boot order list attached with the\r
+                            created node.\r
+  @param BootOrderListSize  On input, the original size of boot order list.\r
+                            On output, the size of new boot order list.\r
+\r
+  @retval  EFI_SUCCESS             Boot Option successfully created.\r
+  @retval  EFI_OUT_OF_RESOURCES    Fail to allocate necessary memory.\r
+  @retval  Other                   Error occurs while setting variable.\r
+\r
+**/\r
+EFI_STATUS\r
+BdsCreateLegacyBootOption (\r
+  IN BBS_TABLE                        *CurrentBbsEntry,\r
+  IN EFI_DEVICE_PATH_PROTOCOL         *CurrentBbsDevPath,\r
+  IN UINTN                            Index,\r
+  IN OUT UINT16                       **BootOrderList,\r
+  IN OUT UINTN                        *BootOrderListSize\r
+  )\r
+{\r
+  EFI_STATUS           Status;\r
+  UINT16               CurrentBootOptionNo;\r
+  UINT16               BootString[10];\r
+  CHAR16               BootDesc[100];\r
+  CHAR8                HelpString[100];\r
+  UINT16               *NewBootOrderList;\r
+  UINTN                BufferSize;\r
+  UINTN                StringLen;\r
+  VOID                 *Buffer;\r
+  UINT8                *Ptr;\r
+  UINT16               CurrentBbsDevPathSize;\r
+  UINTN                BootOrderIndex;\r
+  UINTN                BootOrderLastIndex;\r
+  UINTN                ArrayIndex;\r
+  BOOLEAN              IndexNotFound;\r
+  BBS_BBS_DEVICE_PATH  *NewBbsDevPathNode;\r
+\r
+  if ((*BootOrderList) == NULL) {\r
+    CurrentBootOptionNo = 0;\r
+  } else {\r
+    for (ArrayIndex = 0; ArrayIndex < (UINTN) (*BootOrderListSize / sizeof (UINT16)); ArrayIndex++) {\r
+      IndexNotFound = TRUE;\r
+      for (BootOrderIndex = 0; BootOrderIndex < (UINTN) (*BootOrderListSize / sizeof (UINT16)); BootOrderIndex++) {\r
+        if ((*BootOrderList)[BootOrderIndex] == ArrayIndex) {\r
+          IndexNotFound = FALSE;\r
+          break;\r
+        }\r
+      }\r
+\r
+      if (!IndexNotFound) {\r
+        continue;\r
+      } else {\r
+        break;\r
+      }\r
+    }\r
+\r
+    CurrentBootOptionNo = (UINT16) ArrayIndex;\r
+  }\r
+\r
+  UnicodeSPrint (\r
+    BootString,\r
+    sizeof (BootString),\r
+    L"Boot%04x",\r
+    CurrentBootOptionNo\r
+    );\r
+\r
+  BdsBuildLegacyDevNameString (CurrentBbsEntry, Index, sizeof (BootDesc), BootDesc);\r
+\r
+  //\r
+  // Create new BBS device path node with description string\r
+  //\r
+  UnicodeStrToAsciiStr (BootDesc, HelpString);\r
+\r
+  StringLen = AsciiStrLen (HelpString);\r
+  NewBbsDevPathNode = AllocateZeroPool (sizeof (BBS_BBS_DEVICE_PATH) + StringLen);\r
+  if (NewBbsDevPathNode == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+  CopyMem (NewBbsDevPathNode, CurrentBbsDevPath, sizeof (BBS_BBS_DEVICE_PATH));\r
+  CopyMem (NewBbsDevPathNode->String, HelpString, StringLen + 1);\r
+  SetDevicePathNodeLength (&(NewBbsDevPathNode->Header), sizeof (BBS_BBS_DEVICE_PATH) + StringLen);\r
+\r
+  //\r
+  // Create entire new CurrentBbsDevPath with end node\r
+  //\r
+  CurrentBbsDevPath = AppendDevicePathNode (\r
+                        NULL,\r
+                        (EFI_DEVICE_PATH_PROTOCOL *) NewBbsDevPathNode\r
+                        );\r
+   if (CurrentBbsDevPath == NULL) {\r
+    FreePool (NewBbsDevPathNode);\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  CurrentBbsDevPathSize = (UINT16) (GetDevicePathSize (CurrentBbsDevPath));\r
+\r
+  BufferSize = sizeof (UINT32) +\r
+    sizeof (UINT16) +\r
+    StrSize (BootDesc) +\r
+    CurrentBbsDevPathSize +\r
+    sizeof (BBS_TABLE) +\r
+    sizeof (UINT16);\r
+\r
+  Buffer = AllocateZeroPool (BufferSize);\r
+  if (Buffer == NULL) {\r
+    FreePool (NewBbsDevPathNode);\r
+    FreePool (CurrentBbsDevPath);\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  Ptr               = (UINT8 *) Buffer;\r
+\r
+  *((UINT32 *) Ptr) = LOAD_OPTION_ACTIVE;\r
+  Ptr += sizeof (UINT32);\r
+\r
+  *((UINT16 *) Ptr) = CurrentBbsDevPathSize;\r
+  Ptr += sizeof (UINT16);\r
+\r
+  CopyMem (\r
+    Ptr,\r
+    BootDesc,\r
+    StrSize (BootDesc)\r
+    );\r
+  Ptr += StrSize (BootDesc);\r
+\r
+  CopyMem (\r
+    Ptr,\r
+    CurrentBbsDevPath,\r
+    CurrentBbsDevPathSize\r
+    );\r
+  Ptr += CurrentBbsDevPathSize;\r
+\r
+  CopyMem (\r
+    Ptr,\r
+    CurrentBbsEntry,\r
+    sizeof (BBS_TABLE)\r
+    );\r
+\r
+  Ptr += sizeof (BBS_TABLE);\r
+  *((UINT16 *) Ptr) = (UINT16) Index;\r
+\r
+  Status = gRT->SetVariable (\r
+                  BootString,\r
+                  &gEfiGlobalVariableGuid,\r
+                  EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,\r
+                  BufferSize,\r
+                  Buffer\r
+                  );\r
+\r
+  FreePool (Buffer);\r
+  \r
+  Buffer = NULL;\r
+\r
+  NewBootOrderList = AllocateZeroPool (*BootOrderListSize + sizeof (UINT16));\r
+  if (NULL == NewBootOrderList) {\r
+    FreePool (NewBbsDevPathNode);\r
+    FreePool (CurrentBbsDevPath);\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  if (*BootOrderList != NULL) {\r
+    CopyMem (NewBootOrderList, *BootOrderList, *BootOrderListSize);\r
+    FreePool (*BootOrderList);\r
+  }\r
+\r
+  BootOrderLastIndex                    = (UINTN) (*BootOrderListSize / sizeof (UINT16));\r
+  NewBootOrderList[BootOrderLastIndex]  = CurrentBootOptionNo;\r
+  *BootOrderListSize += sizeof (UINT16);\r
+  *BootOrderList = NewBootOrderList;\r
+\r
+  FreePool (NewBbsDevPathNode);\r
+  FreePool (CurrentBbsDevPath);\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Check if the boot option is a legacy one.\r
+\r
+  @param BootOptionVar   The boot option data payload.\r
+  @param BbsEntry        The BBS Table.\r
+  @param BbsIndex        The table index.\r
+\r
+  @retval TRUE           It is a legacy boot option.\r
+  @retval FALSE          It is not a legacy boot option.\r
+\r
+**/\r
+BOOLEAN\r
+BdsIsLegacyBootOption (\r
+  IN UINT8                 *BootOptionVar,\r
+  OUT BBS_TABLE            **BbsEntry,\r
+  OUT UINT16               *BbsIndex\r
+  )\r
+{\r
+  UINT8                     *Ptr;\r
+  EFI_DEVICE_PATH_PROTOCOL  *DevicePath;\r
+  BOOLEAN                   Ret;\r
+  UINT16                    DevPathLen;\r
+\r
+  Ptr = BootOptionVar;\r
+  Ptr += sizeof (UINT32);\r
+  DevPathLen = *(UINT16 *) Ptr;\r
+  Ptr += sizeof (UINT16);\r
+  Ptr += StrSize ((UINT16 *) Ptr);\r
+  DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) Ptr;\r
+  if ((BBS_DEVICE_PATH == DevicePath->Type) && (BBS_BBS_DP == DevicePath->SubType)) {\r
+    Ptr += DevPathLen;\r
+    *BbsEntry = (BBS_TABLE *) Ptr;\r
+    Ptr += sizeof (BBS_TABLE);\r
+    *BbsIndex = *(UINT16 *) Ptr;\r
+    Ret       = TRUE;\r
+  } else {\r
+    *BbsEntry = NULL;\r
+    Ret       = FALSE;\r
+  }\r
+\r
+  return Ret;\r
+}\r
+\r
+/**\r
+  Delete all the invalid legacy boot options.\r
+\r
+  @retval EFI_SUCCESS             All invalide legacy boot options are deleted.\r
+  @retval EFI_OUT_OF_RESOURCES    Fail to allocate necessary memory.\r
+  @retval EFI_NOT_FOUND           Fail to retrive variable of boot order.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+BdsDeleteAllInvalidLegacyBootOptions (\r
+  VOID\r
+  )\r
+{\r
+  UINT16                    *BootOrder;\r
+  UINT8                     *BootOptionVar;\r
+  UINTN                     BootOrderSize;\r
+  UINTN                     BootOptionSize;\r
+  EFI_STATUS                Status;\r
+  UINT16                    HddCount;\r
+  UINT16                    BbsCount;\r
+  HDD_INFO                  *LocalHddInfo;\r
+  BBS_TABLE                 *LocalBbsTable;\r
+  BBS_TABLE                 *BbsEntry;\r
+  UINT16                    BbsIndex;\r
+  EFI_LEGACY_BIOS_PROTOCOL  *LegacyBios;\r
+  UINTN                     Index;\r
+  UINT16                    BootOption[10];\r
+  UINT16                    BootDesc[100];\r
+  BOOLEAN                   DescStringMatch;\r
+\r
+  Status        = EFI_SUCCESS;\r
+  BootOrder     = NULL;\r
+  BootOrderSize = 0;\r
+  HddCount      = 0;\r
+  BbsCount      = 0;\r
+  LocalHddInfo  = NULL;\r
+  LocalBbsTable = NULL;\r
+  BbsEntry      = NULL;\r
+\r
+  Status        = gBS->LocateProtocol (&gEfiLegacyBiosProtocolGuid, NULL, (VOID **) &LegacyBios);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  BootOrder = BdsLibGetVariableAndSize (\r
+                L"BootOrder",\r
+                &gEfiGlobalVariableGuid,\r
+                &BootOrderSize\r
+                );\r
+  if (BootOrder == NULL) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  LegacyBios->GetBbsInfo (\r
+                LegacyBios,\r
+                &HddCount,\r
+                &LocalHddInfo,\r
+                &BbsCount,\r
+                &LocalBbsTable\r
+                );\r
+\r
+  Index = 0;\r
+  while (Index < BootOrderSize / sizeof (UINT16)) {\r
+    UnicodeSPrint (BootOption, sizeof (BootOption), L"Boot%04x", BootOrder[Index]);\r
+    BootOptionVar = BdsLibGetVariableAndSize (\r
+                      BootOption,\r
+                      &gEfiGlobalVariableGuid,\r
+                      &BootOptionSize\r
+                      );\r
+    if (NULL == BootOptionVar) {\r
+      BootOptionSize = 0;\r
+      Status = gRT->GetVariable (\r
+                      BootOption,\r
+                      &gEfiGlobalVariableGuid,\r
+                      NULL,\r
+                      &BootOptionSize,\r
+                      BootOptionVar\r
+                      );\r
+      if (Status == EFI_NOT_FOUND) {\r
+        //\r
+        // Update BootOrder\r
+        //\r
+        BdsDeleteBootOption (\r
+          BootOrder[Index],\r
+          BootOrder,\r
+          &BootOrderSize\r
+          );\r
+        continue;\r
+      } else {\r
+        FreePool (BootOrder);\r
+        return EFI_OUT_OF_RESOURCES;\r
+      }\r
+    }\r
+  \r
+    //\r
+    // Skip Non-Legacy boot option\r
+    // \r
+    if (!BdsIsLegacyBootOption (BootOptionVar, &BbsEntry, &BbsIndex)) {\r
+      if (BootOptionVar!= NULL) {\r
+        FreePool (BootOptionVar);\r
+      }\r
+      Index++;\r
+      continue;\r
+    }\r
+\r
+    if (BbsIndex < BbsCount) {\r
+      //\r
+      // Check if BBS Description String is changed\r
+      //\r
+      DescStringMatch = FALSE;\r
+      BdsBuildLegacyDevNameString (\r
+        &LocalBbsTable[BbsIndex],\r
+        BbsIndex,\r
+        sizeof (BootDesc),\r
+        BootDesc\r
+        );\r
+\r
+      if (StrCmp (BootDesc, (UINT16*)(BootOptionVar + sizeof (UINT32) + sizeof (UINT16))) == 0) {\r
+        DescStringMatch = TRUE;\r
+      }\r
+\r
+      if (!((LocalBbsTable[BbsIndex].BootPriority == BBS_IGNORE_ENTRY) ||\r
+            (LocalBbsTable[BbsIndex].BootPriority == BBS_DO_NOT_BOOT_FROM)) &&\r
+          (LocalBbsTable[BbsIndex].DeviceType == BbsEntry->DeviceType) &&\r
+          DescStringMatch) {\r
+        Index++;\r
+        continue;\r
+      }\r
+    }\r
+\r
+    if (BootOptionVar != NULL) {\r
+      FreePool (BootOptionVar);\r
+    }\r
+    //\r
+    // should delete\r
+    //\r
+    BdsDeleteBootOption (\r
+      BootOrder[Index],\r
+      BootOrder,\r
+      &BootOrderSize\r
+      );\r
+  }\r
+\r
+  //\r
+  // Adjust the number of boot options.\r
+  //\r
+  Status = gRT->SetVariable (\r
+                  L"BootOrder",\r
+                  &gEfiGlobalVariableGuid,\r
+                  EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,\r
+                  BootOrderSize,\r
+                  BootOrder\r
+                  );\r
+  //\r
+  // Shrinking variable with existing variable implementation shouldn't fail.\r
+  //\r
+  ASSERT_EFI_ERROR (Status);\r
+  FreePool (BootOrder);\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Find all legacy boot option by device type.\r
+\r
+  @param BootOrder       The boot order array.\r
+  @param BootOptionNum   The number of boot option.\r
+  @param DevType         Device type.\r
+  @param DevName         Device name.\r
+  @param Attribute       The boot option attribute.\r
+  @param BbsIndex        The BBS table index.\r
+  @param OptionNumber    The boot option index.\r
+\r
+  @retval TRUE           The Legacy boot option is found.\r
+  @retval FALSE          The legacy boot option is not found.\r
+\r
+**/\r
+BOOLEAN\r
+BdsFindLegacyBootOptionByDevTypeAndName (\r
+  IN UINT16                 *BootOrder,\r
+  IN UINTN                  BootOptionNum,\r
+  IN UINT16                 DevType,\r
+  IN CHAR16                 *DevName,\r
+  OUT UINT32                *Attribute,\r
+  OUT UINT16                *BbsIndex,\r
+  OUT UINT16                *OptionNumber\r
+  )\r
+{\r
+  UINTN     Index;\r
+  CHAR16    BootOption[9];\r
+  UINTN     BootOptionSize;\r
+  UINT8     *BootOptionVar;\r
+  BBS_TABLE *BbsEntry;\r
+  BOOLEAN   Found;\r
+\r
+  BbsEntry  = NULL;\r
+  Found     = FALSE;\r
+\r
+  if (NULL == BootOrder) {\r
+    return Found;\r
+  }\r
+\r
+  //\r
+  // Loop all boot option from variable\r
+  //\r
+  for (Index = 0; Index < BootOptionNum; Index++) {\r
+    UnicodeSPrint (BootOption, sizeof (BootOption), L"Boot%04x", (UINTN) BootOrder[Index]);\r
+    BootOptionVar = BdsLibGetVariableAndSize (\r
+                      BootOption,\r
+                      &gEfiGlobalVariableGuid,\r
+                      &BootOptionSize\r
+                      );\r
+    if (NULL == BootOptionVar) {\r
+      continue;\r
+    }\r
+\r
+    //\r
+    // Skip Non-legacy boot option\r
+    //\r
+    if (!BdsIsLegacyBootOption (BootOptionVar, &BbsEntry, BbsIndex)) {\r
+      FreePool (BootOptionVar);\r
+      continue;\r
+    }\r
+\r
+    if (\r
+        (BbsEntry->DeviceType != DevType) ||\r
+        (StrCmp (DevName, (CHAR16*)(BootOptionVar + sizeof (UINT32) + sizeof (UINT16))) != 0)\r
+       ) {\r
+      FreePool (BootOptionVar);\r
+      continue;\r
+    }\r
+\r
+    *Attribute    = *(UINT32 *) BootOptionVar;\r
+    *OptionNumber = BootOrder[Index];\r
+    Found         = TRUE;\r
+    FreePool (BootOptionVar);\r
+    break;\r
+  }\r
+\r
+  return Found;\r
+}\r
+\r
+/**\r
+  Create a legacy boot option.\r
+\r
+  @param BbsItem         The BBS Table entry.\r
+  @param Index           Index of the specified entry in BBS table.\r
+  @param BootOrderList   The boot order list.\r
+  @param BootOrderListSize The size of boot order list.\r
+\r
+  @retval EFI_OUT_OF_RESOURCE  No enough memory.\r
+  @retval EFI_SUCCESS          The function complete successfully.\r
+  @return Other value if the legacy boot option is not created.\r
+\r
+**/\r
+EFI_STATUS\r
+BdsCreateOneLegacyBootOption (\r
+  IN BBS_TABLE              *BbsItem,\r
+  IN UINTN                  Index,\r
+  IN OUT UINT16             **BootOrderList,\r
+  IN OUT UINTN              *BootOrderListSize\r
+  )\r
+{\r
+  BBS_BBS_DEVICE_PATH       BbsDevPathNode;\r
+  EFI_STATUS                Status;\r
+  EFI_DEVICE_PATH_PROTOCOL  *DevPath;\r
+\r
+  DevPath                       = NULL;\r
+\r
+  //\r
+  // Create device path node.\r
+  //\r
+  BbsDevPathNode.Header.Type    = BBS_DEVICE_PATH;\r
+  BbsDevPathNode.Header.SubType = BBS_BBS_DP;\r
+  SetDevicePathNodeLength (&BbsDevPathNode.Header, sizeof (BBS_BBS_DEVICE_PATH));\r
+  BbsDevPathNode.DeviceType = BbsItem->DeviceType;\r
+  CopyMem (&BbsDevPathNode.StatusFlag, &BbsItem->StatusFlags, sizeof (UINT16));\r
+\r
+  DevPath = AppendDevicePathNode (\r
+              NULL,\r
+              (EFI_DEVICE_PATH_PROTOCOL *) &BbsDevPathNode\r
+              );\r
+  if (NULL == DevPath) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  Status = BdsCreateLegacyBootOption (\r
+            BbsItem,\r
+            DevPath,\r
+            Index,\r
+            BootOrderList,\r
+            BootOrderListSize\r
+            );\r
+  BbsItem->BootPriority = 0x00;\r
+\r
+  FreePool (DevPath);\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Add the legacy boot options from BBS table if they do not exist.\r
+\r
+  @retval EFI_SUCCESS          The boot options are added successfully \r
+                               or they are already in boot options.\r
+  @retval EFI_NOT_FOUND        No legacy boot options is found.\r
+  @retval EFI_OUT_OF_RESOURCE  No enough memory.\r
+  @return Other value          LegacyBoot options are not added.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+BdsAddNonExistingLegacyBootOptions (\r
+  VOID\r
+  )\r
+{\r
+  UINT16                    *BootOrder;\r
+  UINTN                     BootOrderSize;\r
+  EFI_STATUS                Status;\r
+  CHAR16                    Desc[100];\r
+  UINT16                    HddCount;\r
+  UINT16                    BbsCount;\r
+  HDD_INFO                  *LocalHddInfo;\r
+  BBS_TABLE                 *LocalBbsTable;\r
+  UINT16                    BbsIndex;\r
+  EFI_LEGACY_BIOS_PROTOCOL  *LegacyBios;\r
+  UINT16                    Index;\r
+  UINT32                    Attribute;\r
+  UINT16                    OptionNumber;\r
+  BOOLEAN                   Exist;\r
+\r
+  HddCount      = 0;\r
+  BbsCount      = 0;\r
+  LocalHddInfo  = NULL;\r
+  LocalBbsTable = NULL;\r
+\r
+  Status        = gBS->LocateProtocol (&gEfiLegacyBiosProtocolGuid, NULL, (VOID **) &LegacyBios);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  LegacyBios->GetBbsInfo (\r
+                LegacyBios,\r
+                &HddCount,\r
+                &LocalHddInfo,\r
+                &BbsCount,\r
+                &LocalBbsTable\r
+                );\r
+\r
+  BootOrder = BdsLibGetVariableAndSize (\r
+                L"BootOrder",\r
+                &gEfiGlobalVariableGuid,\r
+                &BootOrderSize\r
+                );\r
+  if (BootOrder == NULL) {\r
+    BootOrderSize = 0;\r
+  }\r
+\r
+  for (Index = 0; Index < BbsCount; Index++) {\r
+    if ((LocalBbsTable[Index].BootPriority == BBS_IGNORE_ENTRY) ||\r
+        (LocalBbsTable[Index].BootPriority == BBS_DO_NOT_BOOT_FROM)\r
+        ) {\r
+      continue;\r
+    }\r
+\r
+    BdsBuildLegacyDevNameString (&LocalBbsTable[Index], Index, sizeof (Desc), Desc);\r
+\r
+    Exist = BdsFindLegacyBootOptionByDevTypeAndName (\r
+              BootOrder,\r
+              BootOrderSize / sizeof (UINT16),\r
+              LocalBbsTable[Index].DeviceType,\r
+              Desc,\r
+              &Attribute,\r
+              &BbsIndex,\r
+              &OptionNumber\r
+              );\r
+    if (!Exist) {\r
+      //\r
+      // Not found such type of legacy device in boot options or we found but it's disabled\r
+      // so we have to create one and put it to the tail of boot order list\r
+      //\r
+      Status = BdsCreateOneLegacyBootOption (\r
+                &LocalBbsTable[Index],\r
+                Index,\r
+                &BootOrder,\r
+                &BootOrderSize\r
+                );\r
+      if (!EFI_ERROR (Status)) {\r
+        BbsIndex     = Index;\r
+        OptionNumber = BootOrder[BootOrderSize / sizeof (UINT16) - 1];\r
+      }\r
+    }\r
+\r
+    ASSERT (BbsIndex == Index);\r
+  }\r
+\r
+  Status = gRT->SetVariable (\r
+                  L"BootOrder",\r
+                  &gEfiGlobalVariableGuid,\r
+                  EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,\r
+                  BootOrderSize,\r
+                  BootOrder\r
+                  );\r
+  if (BootOrder != NULL) {\r
+    FreePool (BootOrder);\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Fill the device order buffer.\r
+\r
+  @param BbsTable        The BBS table.\r
+  @param BbsType         The BBS Type.\r
+  @param BbsCount        The BBS Count.\r
+  @param Buf             device order buffer.\r
+\r
+  @return The device order buffer.\r
+\r
+**/\r
+UINT16 *\r
+BdsFillDevOrderBuf (\r
+  IN BBS_TABLE                    *BbsTable,\r
+  IN BBS_TYPE                     BbsType,\r
+  IN UINTN                        BbsCount,\r
+  OUT UINT16                      *Buf\r
+  )\r
+{\r
+  UINTN Index;\r
+\r
+  for (Index = 0; Index < BbsCount; Index++) {\r
+    if (BbsTable[Index].BootPriority == BBS_IGNORE_ENTRY) {\r
+      continue;\r
+    }\r
+\r
+    if (BbsTable[Index].DeviceType != BbsType) {\r
+      continue;\r
+    }\r
+\r
+    *Buf = (UINT16) (Index & 0xFF);\r
+    Buf++;\r
+  }\r
+\r
+  return Buf;\r
+}\r
+\r
+/**\r
+  Create the device order buffer.\r
+\r
+  @param BbsTable        The BBS table.\r
+  @param BbsCount        The BBS Count.\r
+\r
+  @retval EFI_SUCCES             The buffer is created and the EFI variable named \r
+                                 VAR_LEGACY_DEV_ORDER and gEfiLegacyDevOrderVariableGuid is\r
+                                 set correctly.\r
+  @retval EFI_OUT_OF_RESOURCES   Memmory or storage is not enough.\r
+  @retval EFI_DEVICE_ERROR       Fail to add the device order into EFI variable fail\r
+                                 because of hardware error.\r
+**/\r
+EFI_STATUS\r
+BdsCreateDevOrder (\r
+  IN BBS_TABLE                  *BbsTable,\r
+  IN UINT16                     BbsCount\r
+  )\r
+{\r
+  UINTN                       Index;\r
+  UINTN                       FDCount;\r
+  UINTN                       HDCount;\r
+  UINTN                       CDCount;\r
+  UINTN                       NETCount;\r
+  UINTN                       BEVCount;\r
+  UINTN                       TotalSize;\r
+  UINTN                       HeaderSize;\r
+  LEGACY_DEV_ORDER_ENTRY      *DevOrder;\r
+  LEGACY_DEV_ORDER_ENTRY      *DevOrderPtr;\r
+  EFI_STATUS                  Status;\r
+\r
+  FDCount     = 0;\r
+  HDCount     = 0;\r
+  CDCount     = 0;\r
+  NETCount    = 0;\r
+  BEVCount    = 0;\r
+  TotalSize   = 0;\r
+  HeaderSize  = sizeof (BBS_TYPE) + sizeof (UINT16);\r
+  DevOrder    = NULL;\r
+  Status      = EFI_SUCCESS;\r
+\r
+  //\r
+  // Count all boot devices\r
+  //\r
+  for (Index = 0; Index < BbsCount; Index++) {\r
+    if (BbsTable[Index].BootPriority == BBS_IGNORE_ENTRY) {\r
+      continue;\r
+    }\r
+\r
+    switch (BbsTable[Index].DeviceType) {\r
+    case BBS_FLOPPY:\r
+      FDCount++;\r
+      break;\r
+\r
+    case BBS_HARDDISK:\r
+      HDCount++;\r
+      break;\r
+\r
+    case BBS_CDROM:\r
+      CDCount++;\r
+      break;\r
+\r
+    case BBS_EMBED_NETWORK:\r
+      NETCount++;\r
+      break;\r
+\r
+    case BBS_BEV_DEVICE:\r
+      BEVCount++;\r
+      break;\r
+\r
+    default:\r
+      break;\r
+    }\r
+  }\r
+\r
+  TotalSize += (HeaderSize + sizeof (UINT16) * FDCount);\r
+  TotalSize += (HeaderSize + sizeof (UINT16) * HDCount);\r
+  TotalSize += (HeaderSize + sizeof (UINT16) * CDCount);\r
+  TotalSize += (HeaderSize + sizeof (UINT16) * NETCount);\r
+  TotalSize += (HeaderSize + sizeof (UINT16) * BEVCount);\r
+\r
+  //\r
+  // Create buffer to hold all boot device order\r
+  //\r
+  DevOrder = AllocateZeroPool (TotalSize);\r
+  if (NULL == DevOrder) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+  DevOrderPtr          = DevOrder;\r
+\r
+  DevOrderPtr->BbsType = BBS_FLOPPY;\r
+  DevOrderPtr->Length  = (UINT16) (sizeof (DevOrderPtr->Length) + FDCount * sizeof (UINT16));\r
+  DevOrderPtr          = (LEGACY_DEV_ORDER_ENTRY *) BdsFillDevOrderBuf (BbsTable, BBS_FLOPPY, BbsCount, DevOrderPtr->Data);\r
+\r
+  DevOrderPtr->BbsType = BBS_HARDDISK;\r
+  DevOrderPtr->Length  = (UINT16) (sizeof (UINT16) + HDCount * sizeof (UINT16));\r
+  DevOrderPtr          = (LEGACY_DEV_ORDER_ENTRY *) BdsFillDevOrderBuf (BbsTable, BBS_HARDDISK, BbsCount, DevOrderPtr->Data);\r
+  \r
+  DevOrderPtr->BbsType = BBS_CDROM;\r
+  DevOrderPtr->Length  = (UINT16) (sizeof (UINT16) + CDCount * sizeof (UINT16));\r
+  DevOrderPtr          = (LEGACY_DEV_ORDER_ENTRY *) BdsFillDevOrderBuf (BbsTable, BBS_CDROM, BbsCount, DevOrderPtr->Data);\r
+  \r
+  DevOrderPtr->BbsType = BBS_EMBED_NETWORK;\r
+  DevOrderPtr->Length  = (UINT16) (sizeof (UINT16) + NETCount * sizeof (UINT16));\r
+  DevOrderPtr          = (LEGACY_DEV_ORDER_ENTRY *) BdsFillDevOrderBuf (BbsTable, BBS_EMBED_NETWORK, BbsCount, DevOrderPtr->Data);\r
+\r
+  DevOrderPtr->BbsType = BBS_BEV_DEVICE;\r
+  DevOrderPtr->Length  = (UINT16) (sizeof (UINT16) + BEVCount * sizeof (UINT16));\r
+  DevOrderPtr          = (LEGACY_DEV_ORDER_ENTRY *) BdsFillDevOrderBuf (BbsTable, BBS_BEV_DEVICE, BbsCount, DevOrderPtr->Data);\r
+\r
+  ASSERT (TotalSize == (UINTN) ((UINT8 *) DevOrderPtr - (UINT8 *) DevOrder));\r
+\r
+  //\r
+  // Save device order for legacy boot device to variable.\r
+  //\r
+  Status = gRT->SetVariable (\r
+                  VAR_LEGACY_DEV_ORDER,\r
+                  &gEfiLegacyDevOrderVariableGuid,\r
+                  EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,\r
+                  TotalSize,\r
+                  DevOrder\r
+                  );\r
+  FreePool (DevOrder);\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Add the legacy boot devices from BBS table into \r
+  the legacy device boot order.\r
+\r
+  @retval EFI_SUCCESS           The boot devices are added successfully.\r
+  @retval EFI_NOT_FOUND         The legacy boot devices are not found.\r
+  @retval EFI_OUT_OF_RESOURCES  Memmory or storage is not enough.\r
+  @retval EFI_DEVICE_ERROR      Fail to add the legacy device boot order into EFI variable\r
+                                because of hardware error.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+BdsUpdateLegacyDevOrder (\r
+  VOID\r
+  )\r
+{\r
+  LEGACY_DEV_ORDER_ENTRY      *DevOrder;\r
+  LEGACY_DEV_ORDER_ENTRY      *NewDevOrder;\r
+  LEGACY_DEV_ORDER_ENTRY      *Ptr;\r
+  LEGACY_DEV_ORDER_ENTRY      *NewPtr;\r
+  UINTN                       DevOrderSize;\r
+  EFI_LEGACY_BIOS_PROTOCOL    *LegacyBios;\r
+  EFI_STATUS                  Status;\r
+  UINT16                      HddCount;\r
+  UINT16                      BbsCount;\r
+  HDD_INFO                    *LocalHddInfo;\r
+  BBS_TABLE                   *LocalBbsTable;\r
+  UINTN                       Index;\r
+  UINTN                       Index2;\r
+  UINTN                       *Idx;\r
+  UINTN                       FDCount;\r
+  UINTN                       HDCount;\r
+  UINTN                       CDCount;\r
+  UINTN                       NETCount;\r
+  UINTN                       BEVCount;\r
+  UINTN                       TotalSize;\r
+  UINTN                       HeaderSize;\r
+  UINT16                      *NewFDPtr;\r
+  UINT16                      *NewHDPtr;\r
+  UINT16                      *NewCDPtr;\r
+  UINT16                      *NewNETPtr;\r
+  UINT16                      *NewBEVPtr;\r
+  UINT16                      *NewDevPtr;\r
+  UINTN                       FDIndex;\r
+  UINTN                       HDIndex;\r
+  UINTN                       CDIndex;\r
+  UINTN                       NETIndex;\r
+  UINTN                       BEVIndex;\r
+\r
+  Idx           = NULL;\r
+  FDCount       = 0;\r
+  HDCount       = 0;\r
+  CDCount       = 0;\r
+  NETCount      = 0;\r
+  BEVCount      = 0;\r
+  TotalSize     = 0;\r
+  HeaderSize    = sizeof (BBS_TYPE) + sizeof (UINT16);\r
+  FDIndex       = 0;\r
+  HDIndex       = 0;\r
+  CDIndex       = 0;\r
+  NETIndex      = 0;\r
+  BEVIndex      = 0;\r
+  NewDevPtr     = NULL;\r
+\r
+  Status        = gBS->LocateProtocol (&gEfiLegacyBiosProtocolGuid, NULL, (VOID **) &LegacyBios);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  Status = LegacyBios->GetBbsInfo (\r
+                         LegacyBios,\r
+                         &HddCount,\r
+                         &LocalHddInfo,\r
+                         &BbsCount,\r
+                         &LocalBbsTable\r
+                         );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  DevOrder = BdsLibGetVariableAndSize (\r
+               VAR_LEGACY_DEV_ORDER,\r
+               &gEfiLegacyDevOrderVariableGuid,\r
+               &DevOrderSize\r
+               );\r
+  if (NULL == DevOrder) {\r
+    return BdsCreateDevOrder (LocalBbsTable, BbsCount);\r
+  }\r
+  //\r
+  // First we figure out how many boot devices with same device type respectively\r
+  //\r
+  for (Index = 0; Index < BbsCount; Index++) {\r
+    if ((LocalBbsTable[Index].BootPriority == BBS_IGNORE_ENTRY) ||\r
+        (LocalBbsTable[Index].BootPriority == BBS_DO_NOT_BOOT_FROM)\r
+        ) {\r
+      continue;\r
+    }\r
+\r
+    switch (LocalBbsTable[Index].DeviceType) {\r
+    case BBS_FLOPPY:\r
+      FDCount++;\r
+      break;\r
+\r
+    case BBS_HARDDISK:\r
+      HDCount++;\r
+      break;\r
+\r
+    case BBS_CDROM:\r
+      CDCount++;\r
+      break;\r
+\r
+    case BBS_EMBED_NETWORK:\r
+      NETCount++;\r
+      break;\r
+\r
+    case BBS_BEV_DEVICE:\r
+      BEVCount++;\r
+      break;\r
+\r
+    default:\r
+      break;\r
+    }\r
+  }\r
+\r
+  TotalSize += (HeaderSize + FDCount * sizeof (UINT16));\r
+  TotalSize += (HeaderSize + HDCount * sizeof (UINT16));\r
+  TotalSize += (HeaderSize + CDCount * sizeof (UINT16));\r
+  TotalSize += (HeaderSize + NETCount * sizeof (UINT16));\r
+  TotalSize += (HeaderSize + BEVCount * sizeof (UINT16));\r
+\r
+  NewDevOrder = AllocateZeroPool (TotalSize);\r
+  if (NULL == NewDevOrder) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+\r
+\r
+  //\r
+  // copy FD\r
+  //\r
+  Ptr             = DevOrder;\r
+  NewPtr          = NewDevOrder;\r
+  NewPtr->BbsType = Ptr->BbsType;\r
+  NewPtr->Length  = (UINT16) (sizeof (UINT16) + FDCount * sizeof (UINT16));\r
+  for (Index = 0; Index < Ptr->Length / sizeof (UINT16) - 1; Index++) {\r
+    if (LocalBbsTable[Ptr->Data[Index] & 0xFF].BootPriority == BBS_IGNORE_ENTRY ||\r
+        LocalBbsTable[Ptr->Data[Index] & 0xFF].BootPriority == BBS_DO_NOT_BOOT_FROM ||\r
+        LocalBbsTable[Ptr->Data[Index] & 0xFF].DeviceType != BBS_FLOPPY\r
+        ) {\r
+      continue;\r
+    }\r
+\r
+    NewPtr->Data[FDIndex] = Ptr->Data[Index];\r
+    FDIndex++;\r
+  }\r
+  NewFDPtr = NewPtr->Data;\r
+\r
+  //\r
+  // copy HD\r
+  //\r
+  Ptr             = (LEGACY_DEV_ORDER_ENTRY *) (&Ptr->Data[Ptr->Length / sizeof (UINT16) - 1]);\r
+  NewPtr          = (LEGACY_DEV_ORDER_ENTRY *) (&NewPtr->Data[NewPtr->Length / sizeof (UINT16) -1]);\r
+  NewPtr->BbsType = Ptr->BbsType;\r
+  NewPtr->Length  = (UINT16) (sizeof (UINT16) + HDCount * sizeof (UINT16));\r
+  for (Index = 0; Index < Ptr->Length / sizeof (UINT16) - 1; Index++) {\r
+    if (LocalBbsTable[Ptr->Data[Index] & 0xFF].BootPriority == BBS_IGNORE_ENTRY ||\r
+        LocalBbsTable[Ptr->Data[Index] & 0xFF].BootPriority == BBS_DO_NOT_BOOT_FROM ||\r
+        LocalBbsTable[Ptr->Data[Index] & 0xFF].BootPriority == BBS_LOWEST_PRIORITY ||\r
+        LocalBbsTable[Ptr->Data[Index] & 0xFF].DeviceType != BBS_HARDDISK\r
+        ) {\r
+      continue;\r
+    }\r
+\r
+    NewPtr->Data[HDIndex] = Ptr->Data[Index];\r
+    HDIndex++;\r
+  }\r
+  NewHDPtr = NewPtr->Data;\r
+\r
+  //\r
+  // copy CD\r
+  //\r
+  Ptr    = (LEGACY_DEV_ORDER_ENTRY *) (&Ptr->Data[Ptr->Length / sizeof (UINT16) - 1]);\r
+  NewPtr = (LEGACY_DEV_ORDER_ENTRY *) (&NewPtr->Data[NewPtr->Length / sizeof (UINT16) -1]);\r
+  NewPtr->BbsType = Ptr->BbsType;\r
+  NewPtr->Length  = (UINT16) (sizeof (UINT16) + CDCount * sizeof (UINT16));\r
+  for (Index = 0; Index < Ptr->Length / sizeof (UINT16) - 1; Index++) {\r
+    if (LocalBbsTable[Ptr->Data[Index] & 0xFF].BootPriority == BBS_IGNORE_ENTRY ||\r
+        LocalBbsTable[Ptr->Data[Index] & 0xFF].BootPriority == BBS_DO_NOT_BOOT_FROM ||\r
+        LocalBbsTable[Ptr->Data[Index] & 0xFF].BootPriority == BBS_LOWEST_PRIORITY ||\r
+        LocalBbsTable[Ptr->Data[Index] & 0xFF].DeviceType != BBS_CDROM\r
+        ) {\r
+      continue;\r
+    }\r
+\r
+    NewPtr->Data[CDIndex] = Ptr->Data[Index];\r
+    CDIndex++;\r
+  }\r
+  NewCDPtr = NewPtr->Data;\r
+\r
+  //\r
+  // copy NET\r
+  //\r
+  Ptr    = (LEGACY_DEV_ORDER_ENTRY *) (&Ptr->Data[Ptr->Length / sizeof (UINT16) - 1]);\r
+  NewPtr = (LEGACY_DEV_ORDER_ENTRY *) (&NewPtr->Data[NewPtr->Length / sizeof (UINT16) -1]);\r
+  NewPtr->BbsType = Ptr->BbsType;\r
+  NewPtr->Length  = (UINT16) (sizeof (UINT16) + NETCount * sizeof (UINT16));\r
+  for (Index = 0; Index < Ptr->Length / sizeof (UINT16) - 1; Index++) {\r
+    if (LocalBbsTable[Ptr->Data[Index] & 0xFF].BootPriority == BBS_IGNORE_ENTRY ||\r
+        LocalBbsTable[Ptr->Data[Index] & 0xFF].BootPriority == BBS_DO_NOT_BOOT_FROM ||\r
+        LocalBbsTable[Ptr->Data[Index] & 0xFF].BootPriority == BBS_LOWEST_PRIORITY ||\r
+        LocalBbsTable[Ptr->Data[Index] & 0xFF].DeviceType != BBS_EMBED_NETWORK\r
+        ) {\r
+      continue;\r
+    }\r
+\r
+    NewPtr->Data[NETIndex] = Ptr->Data[Index];\r
+    NETIndex++;\r
+  }\r
+  NewNETPtr = NewPtr->Data;\r
+  \r
+  //\r
+  // copy BEV\r
+  //\r
+  Ptr    = (LEGACY_DEV_ORDER_ENTRY *) (&Ptr->Data[Ptr->Length / sizeof (UINT16) - 1]);\r
+  NewPtr = (LEGACY_DEV_ORDER_ENTRY *) (&NewPtr->Data[NewPtr->Length / sizeof (UINT16) -1]);\r
+  NewPtr->BbsType = Ptr->BbsType;\r
+  NewPtr->Length  = (UINT16) (sizeof (UINT16) + BEVCount * sizeof (UINT16));\r
+  for (Index = 0; Index < Ptr->Length / sizeof (UINT16) - 1; Index++) {\r
+    if (LocalBbsTable[Ptr->Data[Index] & 0xFF].BootPriority == BBS_IGNORE_ENTRY ||\r
+        LocalBbsTable[Ptr->Data[Index] & 0xFF].BootPriority == BBS_DO_NOT_BOOT_FROM ||\r
+        LocalBbsTable[Ptr->Data[Index] & 0xFF].BootPriority == BBS_LOWEST_PRIORITY ||\r
+        LocalBbsTable[Ptr->Data[Index] & 0xFF].DeviceType != BBS_BEV_DEVICE\r
+        ) {\r
+      continue;\r
+    }\r
+\r
+    NewPtr->Data[BEVIndex] = Ptr->Data[Index];\r
+    BEVIndex++;\r
+  }\r
+  NewBEVPtr = NewPtr->Data;\r
+\r
+  for (Index = 0; Index < BbsCount; Index++) {\r
+    if ((LocalBbsTable[Index].BootPriority == BBS_IGNORE_ENTRY) ||\r
+        (LocalBbsTable[Index].BootPriority == BBS_DO_NOT_BOOT_FROM)\r
+        ) {\r
+      continue;\r
+    }\r
+\r
+    switch (LocalBbsTable[Index].DeviceType) {\r
+    case BBS_FLOPPY:\r
+      Idx       = &FDIndex;\r
+      NewDevPtr = NewFDPtr;\r
+      break;\r
+\r
+    case BBS_HARDDISK:\r
+      Idx       = &HDIndex;\r
+      NewDevPtr = NewHDPtr;\r
+      break;\r
+\r
+    case BBS_CDROM:\r
+      Idx       = &CDIndex;\r
+      NewDevPtr = NewCDPtr;\r
+      break;\r
+\r
+    case BBS_EMBED_NETWORK:\r
+      Idx       = &NETIndex;\r
+      NewDevPtr = NewNETPtr;\r
+      break;\r
+\r
+    case BBS_BEV_DEVICE:\r
+      Idx       = &BEVIndex;\r
+      NewDevPtr = NewBEVPtr;\r
+      break;\r
+\r
+    default:\r
+      Idx = NULL;\r
+      break;\r
+    }\r
+    //\r
+    // at this point we have copied those valid indexes to new buffer\r
+    // and we should check if there is any new appeared boot device\r
+    //\r
+    if (Idx != NULL) {\r
+      for (Index2 = 0; Index2 < *Idx; Index2++) {\r
+        if ((NewDevPtr[Index2] & 0xFF) == (UINT16) Index) {\r
+          break;\r
+        }\r
+      }\r
+\r
+      if (Index2 == *Idx) {\r
+        //\r
+        // Index2 == *Idx means we didn't find Index\r
+        // so Index is a new appeared device's index in BBS table\r
+        // insert it before disabled indexes.\r
+        //\r
+        for (Index2 = 0; Index2 < *Idx; Index2++) {\r
+          if ((NewDevPtr[Index2] & 0xFF00) == 0xFF00) {\r
+            break;\r
+          }\r
+        }\r
+        CopyMem (&NewDevPtr[Index2 + 1], &NewDevPtr[Index2], (*Idx - Index2) * sizeof (UINT16));\r
+        NewDevPtr[Index2] = (UINT16) (Index & 0xFF);\r
+        (*Idx)++;\r
+      }\r
+    }\r
+  }\r
+\r
+  FreePool (DevOrder);\r
+\r
+  Status = gRT->SetVariable (\r
+                  VAR_LEGACY_DEV_ORDER,\r
+                  &gEfiLegacyDevOrderVariableGuid,\r
+                  EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,\r
+                  TotalSize,\r
+                  NewDevOrder\r
+                  );\r
+  FreePool (NewDevOrder);\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Set Boot Priority for specified device type.\r
+\r
+  @param DeviceType      The device type.\r
+  @param BbsIndex        The BBS index to set the highest priority. Ignore when -1.\r
+  @param LocalBbsTable   The BBS table.\r
+  @param Priority        The prority table.\r
 \r
-///\r
-/// This GUID is used for register UNI string.\r
-///\r
-EFI_GUID mBdsLibStringPackGuid = {  0x3b4d9b23, 0x95ac, 0x44f6, { 0x9f, 0xcd, 0xe, 0x95, 0x94, 0x58, 0x6c, 0x72 } };\r
+  @retval EFI_SUCCESS           The function completes successfully.\r
+  @retval EFI_NOT_FOUND         Failed to find device.\r
+  @retval EFI_OUT_OF_RESOURCES  Failed to get the efi variable of device order.\r
+\r
+**/\r
+EFI_STATUS\r
+BdsSetBootPriority4SameTypeDev (\r
+  IN UINT16                                              DeviceType,\r
+  IN UINTN                                               BbsIndex,\r
+  IN OUT BBS_TABLE                                       *LocalBbsTable,\r
+  IN OUT UINT16                                          *Priority\r
+  )\r
+{\r
+  LEGACY_DEV_ORDER_ENTRY      *DevOrder;\r
+  LEGACY_DEV_ORDER_ENTRY      *DevOrderPtr;\r
+  UINTN                       DevOrderSize;\r
+  UINTN                       Index;\r
+\r
+  DevOrder = BdsLibGetVariableAndSize (\r
+               VAR_LEGACY_DEV_ORDER,\r
+               &gEfiLegacyDevOrderVariableGuid,\r
+               &DevOrderSize\r
+               );\r
+  if (NULL == DevOrder) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  DevOrderPtr = DevOrder;\r
+  while ((UINT8 *) DevOrderPtr < (UINT8 *) DevOrder + DevOrderSize) {\r
+    if (DevOrderPtr->BbsType == DeviceType) {\r
+      break;\r
+    }\r
+\r
+    DevOrderPtr = (LEGACY_DEV_ORDER_ENTRY *) ((UINT8 *) DevOrderPtr + sizeof (BBS_TYPE) + DevOrderPtr->Length);\r
+  }\r
+\r
+  if ((UINT8 *) DevOrderPtr >= (UINT8 *) DevOrder + DevOrderSize) {\r
+    FreePool (DevOrder);\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  if (BbsIndex != (UINTN) -1) {\r
+    LocalBbsTable[BbsIndex].BootPriority = *Priority;\r
+    (*Priority)++;\r
+  }\r
+  //\r
+  // If the high byte of the DevIndex is 0xFF, it indicates that this device has been disabled.\r
+  //\r
+  for (Index = 0; Index < DevOrderPtr->Length / sizeof (UINT16) - 1; Index++) {\r
+    if ((DevOrderPtr->Data[Index] & 0xFF00) == 0xFF00) {\r
+      //\r
+      // LocalBbsTable[DevIndex[Index] & 0xFF].BootPriority = BBS_DISABLED_ENTRY;\r
+      //\r
+    } else if (DevOrderPtr->Data[Index] != BbsIndex) {\r
+      LocalBbsTable[DevOrderPtr->Data[Index]].BootPriority = *Priority;\r
+      (*Priority)++;\r
+    }\r
+  }\r
+\r
+  FreePool (DevOrder);\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Print the BBS Table.\r
+\r
+  @param LocalBbsTable   The BBS table.\r
+  @param BbsCount        The count of entry in BBS table.\r
+**/\r
+VOID\r
+PrintBbsTable (\r
+  IN BBS_TABLE  *LocalBbsTable,\r
+  IN UINT16     BbsCount\r
+  )\r
+{\r
+  UINT16  Idx;\r
+\r
+  DEBUG ((DEBUG_ERROR, "\n"));\r
+  DEBUG ((DEBUG_ERROR, " NO  Prio bb/dd/ff cl/sc Type Stat segm:offs\n"));\r
+  DEBUG ((DEBUG_ERROR, "=============================================\n"));\r
+  for (Idx = 0; Idx < BbsCount; Idx++) {\r
+    if ((LocalBbsTable[Idx].BootPriority == BBS_IGNORE_ENTRY) ||\r
+        (LocalBbsTable[Idx].BootPriority == BBS_DO_NOT_BOOT_FROM) ||\r
+        (LocalBbsTable[Idx].BootPriority == BBS_LOWEST_PRIORITY)\r
+        ) {\r
+      continue;\r
+    }\r
+\r
+    DEBUG (\r
+      (DEBUG_ERROR,\r
+      " %02x: %04x %02x/%02x/%02x %02x/%02x %04x %04x %04x:%04x\n",\r
+      (UINTN) Idx,\r
+      (UINTN) LocalBbsTable[Idx].BootPriority,\r
+      (UINTN) LocalBbsTable[Idx].Bus,\r
+      (UINTN) LocalBbsTable[Idx].Device,\r
+      (UINTN) LocalBbsTable[Idx].Function,\r
+      (UINTN) LocalBbsTable[Idx].Class,\r
+      (UINTN) LocalBbsTable[Idx].SubClass,\r
+      (UINTN) LocalBbsTable[Idx].DeviceType,\r
+      (UINTN) * (UINT16 *) &LocalBbsTable[Idx].StatusFlags,\r
+      (UINTN) LocalBbsTable[Idx].BootHandlerSegment,\r
+      (UINTN) LocalBbsTable[Idx].BootHandlerOffset,\r
+      (UINTN) ((LocalBbsTable[Idx].MfgStringSegment << 4) + LocalBbsTable[Idx].MfgStringOffset),\r
+      (UINTN) ((LocalBbsTable[Idx].DescStringSegment << 4) + LocalBbsTable[Idx].DescStringOffset))\r
+      );\r
+  }\r
+\r
+  DEBUG ((DEBUG_ERROR, "\n"));\r
+}\r
+\r
+/**\r
+  Set the boot priority for BBS entries based on boot option entry and boot order.\r
+\r
+  @param  Entry             The boot option is to be checked for refresh BBS table.\r
+  \r
+  @retval EFI_SUCCESS           The boot priority for BBS entries is refreshed successfully.\r
+  @retval EFI_NOT_FOUND         BBS entries can't be found.\r
+  @retval EFI_OUT_OF_RESOURCES  Failed to get the legacy device boot order.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+BdsRefreshBbsTableForBoot (\r
+  IN BDS_COMMON_OPTION        *Entry\r
+  )\r
+{\r
+  EFI_STATUS                Status;\r
+  UINT16                    BbsIndex;\r
+  UINT16                    HddCount;\r
+  UINT16                    BbsCount;\r
+  HDD_INFO                  *LocalHddInfo;\r
+  BBS_TABLE                 *LocalBbsTable;\r
+  UINT16                    DevType;\r
+  EFI_LEGACY_BIOS_PROTOCOL  *LegacyBios;\r
+  UINTN                     Index;\r
+  UINT16                    Priority;\r
+  UINT16                    *BootOrder;\r
+  UINTN                     BootOrderSize;\r
+  UINT8                     *BootOptionVar;\r
+  UINTN                     BootOptionSize;\r
+  CHAR16                    BootOption[9];\r
+  UINT8                     *Ptr;\r
+  UINT16                    DevPathLen;\r
+  EFI_DEVICE_PATH_PROTOCOL  *DevPath;\r
+  UINT16                    *DeviceType;\r
+  UINTN                     DeviceTypeCount;\r
+  UINTN                     DeviceTypeIndex;\r
+\r
+  HddCount      = 0;\r
+  BbsCount      = 0;\r
+  LocalHddInfo  = NULL;\r
+  LocalBbsTable = NULL;\r
+  DevType       = BBS_UNKNOWN;\r
+\r
+  Status        = gBS->LocateProtocol (&gEfiLegacyBiosProtocolGuid, NULL, (VOID **) &LegacyBios);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  LegacyBios->GetBbsInfo (\r
+                LegacyBios,\r
+                &HddCount,\r
+                &LocalHddInfo,\r
+                &BbsCount,\r
+                &LocalBbsTable\r
+                );\r
+  //\r
+  // First, set all the present devices' boot priority to BBS_UNPRIORITIZED_ENTRY\r
+  // We will set them according to the settings setup by user\r
+  //\r
+  for (Index = 0; Index < BbsCount; Index++) {\r
+    if (!((BBS_IGNORE_ENTRY == LocalBbsTable[Index].BootPriority) ||\r
+        (BBS_DO_NOT_BOOT_FROM == LocalBbsTable[Index].BootPriority) ||\r
+         (BBS_LOWEST_PRIORITY == LocalBbsTable[Index].BootPriority))) {\r
+      LocalBbsTable[Index].BootPriority = BBS_UNPRIORITIZED_ENTRY;\r
+    }\r
+  }\r
+  //\r
+  // boot priority always starts at 0\r
+  //\r
+  Priority = 0;\r
+  if (Entry->LoadOptionsSize == sizeof (BBS_TABLE) + sizeof (UINT16)) {\r
+    //\r
+    // If Entry stands for a legacy boot option, we prioritize the devices with the same type first.\r
+    //\r
+    DevType  = ((BBS_TABLE *) Entry->LoadOptions)->DeviceType;\r
+    BbsIndex = *(UINT16 *) ((BBS_TABLE *) Entry->LoadOptions + 1);\r
+    Status = BdsSetBootPriority4SameTypeDev (\r
+              DevType,\r
+              BbsIndex,\r
+              LocalBbsTable,\r
+              &Priority\r
+              );\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+  }\r
+  //\r
+  // we have to set the boot priority for other BBS entries with different device types\r
+  //\r
+  BootOrder = BdsLibGetVariableAndSize (\r
+                L"BootOrder",\r
+                &gEfiGlobalVariableGuid,\r
+                &BootOrderSize\r
+                );\r
+  DeviceType = AllocatePool (BootOrderSize + sizeof (UINT16));\r
+  ASSERT (DeviceType != NULL);\r
 \r
-///\r
-/// This GUID is used for Set/Get platform language into/from variable at last time enumeration to ensure the enumeration will\r
-/// only execute once.\r
-///\r
-EFI_GUID mBdsLibLastLangGuid = { 0xe8c545b, 0xa2ee, 0x470d, { 0x8e, 0x26, 0xbd, 0xa1, 0xa1, 0x3c, 0xa, 0xa3 } };\r
+  DeviceType[0]   = DevType;\r
+  DeviceTypeCount = 1;\r
+  for (Index = 0; ((BootOrder != NULL) && (Index < BootOrderSize / sizeof (UINT16))); Index++) {\r
+    UnicodeSPrint (BootOption, sizeof (BootOption), L"Boot%04x", BootOrder[Index]);\r
+    BootOptionVar = BdsLibGetVariableAndSize (\r
+                      BootOption,\r
+                      &gEfiGlobalVariableGuid,\r
+                      &BootOptionSize\r
+                      );\r
+    if (NULL == BootOptionVar) {\r
+      continue;\r
+    }\r
 \r
-/**\r
-  The constructor function register UNI strings into imageHandle.\r
-  \r
-  It will ASSERT() if that operation fails and it will always return EFI_SUCCESS. \r
+    Ptr = BootOptionVar;\r
 \r
-  @param  ImageHandle   The firmware allocated handle for the EFI image.\r
-  @param  SystemTable   A pointer to the EFI System Table.\r
-  \r
-  @retval EFI_SUCCESS   The constructor successfully added string package.\r
-  @retval Other value   The constructor can't add string package.\r
+    Ptr += sizeof (UINT32);\r
+    DevPathLen = *(UINT16 *) Ptr;\r
+    Ptr += sizeof (UINT16);\r
+    Ptr += StrSize ((UINT16 *) Ptr);\r
+    DevPath = (EFI_DEVICE_PATH_PROTOCOL *) Ptr;\r
+    if (BBS_DEVICE_PATH != DevPath->Type || BBS_BBS_DP != DevPath->SubType) {\r
+      FreePool (BootOptionVar);\r
+      continue;\r
+    }\r
 \r
-**/\r
-EFI_STATUS\r
-EFIAPI\r
-GenericBdsLibConstructor (\r
-  IN EFI_HANDLE        ImageHandle,\r
-  IN EFI_SYSTEM_TABLE  *SystemTable\r
-  )\r
-{\r
+    Ptr += DevPathLen;\r
+    DevType = ((BBS_TABLE *) Ptr)->DeviceType;\r
+    for (DeviceTypeIndex = 0; DeviceTypeIndex < DeviceTypeCount; DeviceTypeIndex++) {\r
+      if (DeviceType[DeviceTypeIndex] == DevType) {\r
+        break;\r
+      }\r
+    }\r
+    if (DeviceTypeIndex < DeviceTypeCount) {\r
+      //\r
+      // We don't want to process twice for a device type\r
+      //\r
+      FreePool (BootOptionVar);\r
+      continue;\r
+    }\r
 \r
-  gBdsLibStringPackHandle = HiiAddPackages (\r
-                              &mBdsLibStringPackGuid,\r
-                              &ImageHandle,\r
-                              GenericBdsLibStrings,\r
-                              NULL\r
-                              );\r
+    DeviceType[DeviceTypeCount] = DevType;\r
+    DeviceTypeCount++;\r
 \r
-  ASSERT (gBdsLibStringPackHandle != NULL);\r
+    Status = BdsSetBootPriority4SameTypeDev (\r
+              DevType,\r
+              (UINTN) -1,\r
+              LocalBbsTable,\r
+              &Priority\r
+              );\r
+    FreePool (BootOptionVar);\r
+    if (EFI_ERROR (Status)) {\r
+      break;\r
+    }\r
+  }\r
 \r
-  return EFI_SUCCESS;\r
-}\r
+  if (BootOrder != NULL) {\r
+    FreePool (BootOrder);\r
+  }\r
 \r
+  DEBUG_CODE_BEGIN();\r
+    PrintBbsTable (LocalBbsTable, BbsCount);\r
+  DEBUG_CODE_END();\r
 \r
+  return Status;\r
+}\r
 \r
 /**\r
   Boot the legacy system with the boot option\r
@@ -86,6 +1669,7 @@ BdsLibDoLegacyBoot (
 {\r
   EFI_STATUS                Status;\r
   EFI_LEGACY_BIOS_PROTOCOL  *LegacyBios;\r
+  EFI_EVENT                 LegacyBootEvent;\r
 \r
   Status = gBS->LocateProtocol (&gEfiLegacyBiosProtocolGuid, NULL, (VOID **) &LegacyBios);\r
   if (EFI_ERROR (Status)) {\r
@@ -103,7 +1687,16 @@ BdsLibDoLegacyBoot (
   // Write boot to OS performance data for legacy boot.\r
   //\r
   PERF_CODE (\r
-    WriteBootToOsPerformanceData ();\r
+    //\r
+    // Create an event to be signalled when Legacy Boot occurs to write performance data.\r
+    //\r
+    Status = EfiCreateEventLegacyBootEx(\r
+               TPL_NOTIFY,\r
+               WriteBootToOsPerformanceData,\r
+               NULL, \r
+               &LegacyBootEvent\r
+               );\r
+    ASSERT_EFI_ERROR (Status);\r
   );\r
 \r
   DEBUG ((DEBUG_INFO | DEBUG_LOAD, "Legacy Boot: %S\n", Option->Description));\r
@@ -145,19 +1738,467 @@ IsBootOptionValidNVVarialbe (
   }\r
 \r
   //\r
-  // If the Boot Option Number and Device Path matches, OptionToCheck matches a\r
-  // valid EFI NV Boot####.\r
+  // If the Boot Option Number and Device Path matches, OptionToCheck matches a\r
+  // valid EFI NV Boot####.\r
+  //\r
+  if ((OptionToCheck->BootCurrent == BootOption->BootCurrent) &&\r
+      (CompareMem (OptionToCheck->DevicePath, BootOption->DevicePath, GetDevicePathSize (OptionToCheck->DevicePath)) == 0))\r
+      {\r
+    Valid = TRUE;\r
+  }\r
+\r
+  FreePool (BootOption);\r
+\r
+  return Valid;\r
+}\r
+\r
+/**\r
+  Check whether a USB device match the specified USB Class device path. This\r
+  function follows "Load Option Processing" behavior in UEFI specification.\r
+\r
+  @param UsbIo       USB I/O protocol associated with the USB device.\r
+  @param UsbClass    The USB Class device path to match.\r
+\r
+  @retval TRUE       The USB device match the USB Class device path.\r
+  @retval FALSE      The USB device does not match the USB Class device path.\r
+\r
+**/\r
+BOOLEAN\r
+BdsMatchUsbClass (\r
+  IN EFI_USB_IO_PROTOCOL        *UsbIo,\r
+  IN USB_CLASS_DEVICE_PATH      *UsbClass\r
+  )\r
+{\r
+  EFI_STATUS                    Status;\r
+  EFI_USB_DEVICE_DESCRIPTOR     DevDesc;\r
+  EFI_USB_INTERFACE_DESCRIPTOR  IfDesc;\r
+  UINT8                         DeviceClass;\r
+  UINT8                         DeviceSubClass;\r
+  UINT8                         DeviceProtocol;\r
+\r
+  if ((DevicePathType (UsbClass) != MESSAGING_DEVICE_PATH) ||\r
+      (DevicePathSubType (UsbClass) != MSG_USB_CLASS_DP)){\r
+    return FALSE;\r
+  }\r
+\r
+  //\r
+  // Check Vendor Id and Product Id.\r
+  //\r
+  Status = UsbIo->UsbGetDeviceDescriptor (UsbIo, &DevDesc);\r
+  if (EFI_ERROR (Status)) {\r
+    return FALSE;\r
+  }\r
+\r
+  if ((UsbClass->VendorId != 0xffff) &&\r
+      (UsbClass->VendorId != DevDesc.IdVendor)) {\r
+    return FALSE;\r
+  }\r
+\r
+  if ((UsbClass->ProductId != 0xffff) &&\r
+      (UsbClass->ProductId != DevDesc.IdProduct)) {\r
+    return FALSE;\r
+  }\r
+\r
+  DeviceClass    = DevDesc.DeviceClass;\r
+  DeviceSubClass = DevDesc.DeviceSubClass;\r
+  DeviceProtocol = DevDesc.DeviceProtocol;\r
+  if (DeviceClass == 0) {\r
+    //\r
+    // If Class in Device Descriptor is set to 0, use the Class, SubClass and\r
+    // Protocol in Interface Descriptor instead.\r
+    //\r
+    Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &IfDesc);\r
+    if (EFI_ERROR (Status)) {\r
+      return FALSE;\r
+    }\r
+\r
+    DeviceClass    = IfDesc.InterfaceClass;\r
+    DeviceSubClass = IfDesc.InterfaceSubClass;\r
+    DeviceProtocol = IfDesc.InterfaceProtocol;\r
+  }\r
+\r
+  //\r
+  // Check Class, SubClass and Protocol.\r
+  //\r
+  if ((UsbClass->DeviceClass != 0xff) &&\r
+      (UsbClass->DeviceClass != DeviceClass)) {\r
+    return FALSE;\r
+  }\r
+\r
+  if ((UsbClass->DeviceSubClass != 0xff) &&\r
+      (UsbClass->DeviceSubClass != DeviceSubClass)) {\r
+    return FALSE;\r
+  }\r
+\r
+  if ((UsbClass->DeviceProtocol != 0xff) &&\r
+      (UsbClass->DeviceProtocol != DeviceProtocol)) {\r
+    return FALSE;\r
+  }\r
+\r
+  return TRUE;\r
+}\r
+\r
+/**\r
+  Check whether a USB device match the specified USB WWID device path. This\r
+  function follows "Load Option Processing" behavior in UEFI specification.\r
+\r
+  @param UsbIo       USB I/O protocol associated with the USB device.\r
+  @param UsbWwid     The USB WWID device path to match.\r
+\r
+  @retval TRUE       The USB device match the USB WWID device path.\r
+  @retval FALSE      The USB device does not match the USB WWID device path.\r
+\r
+**/\r
+BOOLEAN\r
+BdsMatchUsbWwid (\r
+  IN EFI_USB_IO_PROTOCOL        *UsbIo,\r
+  IN USB_WWID_DEVICE_PATH       *UsbWwid\r
+  )\r
+{\r
+  EFI_STATUS                   Status;\r
+  EFI_USB_DEVICE_DESCRIPTOR    DevDesc;\r
+  EFI_USB_INTERFACE_DESCRIPTOR IfDesc;\r
+  UINT16                       *LangIdTable;\r
+  UINT16                       TableSize;\r
+  UINT16                       Index;\r
+  CHAR16                       *CompareStr;\r
+  UINTN                        CompareLen;\r
+  CHAR16                       *SerialNumberStr;\r
+  UINTN                        Length;\r
+\r
+  if ((DevicePathType (UsbWwid) != MESSAGING_DEVICE_PATH) ||\r
+      (DevicePathSubType (UsbWwid) != MSG_USB_WWID_DP )){\r
+    return FALSE;\r
+  }\r
+\r
+  //\r
+  // Check Vendor Id and Product Id.\r
+  //\r
+  Status = UsbIo->UsbGetDeviceDescriptor (UsbIo, &DevDesc);\r
+  if (EFI_ERROR (Status)) {\r
+    return FALSE;\r
+  }\r
+  if ((DevDesc.IdVendor != UsbWwid->VendorId) ||\r
+      (DevDesc.IdProduct != UsbWwid->ProductId)) {\r
+    return FALSE;\r
+  }\r
+\r
+  //\r
+  // Check Interface Number.\r
+  //\r
+  Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &IfDesc);\r
+  if (EFI_ERROR (Status)) {\r
+    return FALSE;\r
+  }\r
+  if (IfDesc.InterfaceNumber != UsbWwid->InterfaceNumber) {\r
+    return FALSE;\r
+  }\r
+\r
+  //\r
+  // Check Serial Number.\r
+  //\r
+  if (DevDesc.StrSerialNumber == 0) {\r
+    return FALSE;\r
+  }\r
+\r
+  //\r
+  // Get all supported languages.\r
+  //\r
+  TableSize = 0;\r
+  LangIdTable = NULL;\r
+  Status = UsbIo->UsbGetSupportedLanguages (UsbIo, &LangIdTable, &TableSize);\r
+  if (EFI_ERROR (Status) || (TableSize == 0) || (LangIdTable == NULL)) {\r
+    return FALSE;\r
+  }\r
+\r
+  //\r
+  // Serial number in USB WWID device path is the last 64-or-less UTF-16 characters.\r
+  //\r
+  CompareStr = (CHAR16 *) (UINTN) (UsbWwid + 1);\r
+  CompareLen = (DevicePathNodeLength (UsbWwid) - sizeof (USB_WWID_DEVICE_PATH)) / sizeof (CHAR16);\r
+  if (CompareStr[CompareLen - 1] == L'\0') {\r
+    CompareLen--;\r
+  }\r
+\r
+  //\r
+  // Compare serial number in each supported language.\r
+  //\r
+  for (Index = 0; Index < TableSize / sizeof (UINT16); Index++) {\r
+    SerialNumberStr = NULL;\r
+    Status = UsbIo->UsbGetStringDescriptor (\r
+                      UsbIo,\r
+                      LangIdTable[Index],\r
+                      DevDesc.StrSerialNumber,\r
+                      &SerialNumberStr\r
+                      );\r
+    if (EFI_ERROR (Status) || (SerialNumberStr == NULL)) {\r
+      continue;\r
+    }\r
+\r
+    Length = StrLen (SerialNumberStr);\r
+    if ((Length >= CompareLen) &&\r
+        (CompareMem (SerialNumberStr + Length - CompareLen, CompareStr, CompareLen * sizeof (CHAR16)) == 0)) {\r
+      FreePool (SerialNumberStr);\r
+      return TRUE;\r
+    }\r
+\r
+    FreePool (SerialNumberStr);\r
+  }\r
+\r
+  return FALSE;\r
+}\r
+\r
+/**\r
+  Find a USB device path which match the specified short-form device path start\r
+  with USB Class or USB WWID device path and load the boot file then return the \r
+  image handle. If ParentDevicePath is NULL, this function will search in all USB\r
+  devices of the platform. If ParentDevicePath is not NULL,this function will only\r
+  search in its child devices.\r
+\r
+  @param ParentDevicePath      The device path of the parent.\r
+  @param ShortFormDevicePath   The USB Class or USB WWID device path to match.\r
+\r
+  @return  The image Handle if find load file from specified short-form device path\r
+           or NULL if not found.\r
+\r
+**/\r
+EFI_HANDLE *\r
+BdsFindUsbDevice (\r
+  IN EFI_DEVICE_PATH_PROTOCOL   *ParentDevicePath,\r
+  IN EFI_DEVICE_PATH_PROTOCOL   *ShortFormDevicePath\r
+  )\r
+{\r
+  EFI_STATUS                Status;\r
+  UINTN                     UsbIoHandleCount;\r
+  EFI_HANDLE                *UsbIoHandleBuffer;\r
+  EFI_DEVICE_PATH_PROTOCOL  *UsbIoDevicePath;\r
+  EFI_USB_IO_PROTOCOL       *UsbIo;\r
+  UINTN                     Index;\r
+  UINTN                     ParentSize;\r
+  UINTN                     Size;\r
+  EFI_HANDLE                ImageHandle;\r
+  EFI_HANDLE                Handle;\r
+  EFI_DEVICE_PATH_PROTOCOL  *FullDevicePath;\r
+  EFI_DEVICE_PATH_PROTOCOL  *NextDevicePath;\r
+\r
+  FullDevicePath = NULL;\r
+  ImageHandle    = NULL;\r
+\r
+  //\r
+  // Get all UsbIo Handles.\r
+  //\r
+  UsbIoHandleCount = 0;\r
+  UsbIoHandleBuffer = NULL;\r
+  Status = gBS->LocateHandleBuffer (\r
+                  ByProtocol,\r
+                  &gEfiUsbIoProtocolGuid,\r
+                  NULL,\r
+                  &UsbIoHandleCount,\r
+                  &UsbIoHandleBuffer\r
+                  );\r
+  if (EFI_ERROR (Status) || (UsbIoHandleCount == 0) || (UsbIoHandleBuffer == NULL)) {\r
+    return NULL;\r
+  }\r
+\r
+  ParentSize = (ParentDevicePath == NULL) ? 0 : GetDevicePathSize (ParentDevicePath);\r
+  for (Index = 0; Index < UsbIoHandleCount; Index++) {\r
+    //\r
+    // Get the Usb IO interface.\r
+    //\r
+    Status = gBS->HandleProtocol(\r
+                    UsbIoHandleBuffer[Index],\r
+                    &gEfiUsbIoProtocolGuid,\r
+                    (VOID **) &UsbIo\r
+                    );\r
+    if (EFI_ERROR (Status)) {\r
+      continue;\r
+    }\r
+\r
+    UsbIoDevicePath = DevicePathFromHandle (UsbIoHandleBuffer[Index]);\r
+    if (UsbIoDevicePath == NULL) {\r
+      continue;\r
+    }\r
+\r
+    if (ParentDevicePath != NULL) {\r
+      //\r
+      // Compare starting part of UsbIoHandle's device path with ParentDevicePath.\r
+      //\r
+      Size = GetDevicePathSize (UsbIoDevicePath);\r
+      if ((Size < ParentSize) ||\r
+          (CompareMem (UsbIoDevicePath, ParentDevicePath, ParentSize - END_DEVICE_PATH_LENGTH) != 0)) {\r
+        continue;\r
+      }\r
+    }\r
+\r
+    if (BdsMatchUsbClass (UsbIo, (USB_CLASS_DEVICE_PATH *) ShortFormDevicePath) ||\r
+        BdsMatchUsbWwid (UsbIo, (USB_WWID_DEVICE_PATH *) ShortFormDevicePath)) {\r
+      //\r
+      // Try to find if there is the boot file in this DevicePath\r
+      //\r
+      NextDevicePath = NextDevicePathNode (ShortFormDevicePath);\r
+      if (!IsDevicePathEnd (NextDevicePath)) {\r
+        FullDevicePath = AppendDevicePath (UsbIoDevicePath, NextDevicePath);\r
+        //\r
+        // Connect the full device path, so that Simple File System protocol\r
+        // could be installed for this USB device.\r
+        //\r
+        BdsLibConnectDevicePath (FullDevicePath);\r
+        REPORT_STATUS_CODE (EFI_PROGRESS_CODE, PcdGet32 (PcdProgressCodeOsLoaderLoad));\r
+        Status = gBS->LoadImage (\r
+                       TRUE,\r
+                       gImageHandle,\r
+                       FullDevicePath,\r
+                       NULL,\r
+                       0,\r
+                       &ImageHandle\r
+                       );\r
+        FreePool (FullDevicePath);\r
+      } else {\r
+        FullDevicePath = UsbIoDevicePath;\r
+        Status = EFI_NOT_FOUND;\r
+      }\r
+\r
+      //\r
+      // If we didn't find an image directly, we need to try as if it is a removable device boot option\r
+      // and load the image according to the default boot behavior for removable device.\r
+      //\r
+      if (EFI_ERROR (Status)) {\r
+        //\r
+        // check if there is a bootable removable media could be found in this device path ,\r
+        // and get the bootable media handle\r
+        //\r
+        Handle = BdsLibGetBootableHandle(UsbIoDevicePath);\r
+        if (Handle == NULL) {\r
+          continue;\r
+        }\r
+        //\r
+        // Load the default boot file \EFI\BOOT\boot{machinename}.EFI from removable Media\r
+        //  machinename is ia32, ia64, x64, ...\r
+        //\r
+        FullDevicePath = FileDevicePath (Handle, EFI_REMOVABLE_MEDIA_FILE_NAME);\r
+        if (FullDevicePath != NULL) {\r
+          REPORT_STATUS_CODE (EFI_PROGRESS_CODE, PcdGet32 (PcdProgressCodeOsLoaderLoad));\r
+          Status = gBS->LoadImage (\r
+                          TRUE,\r
+                          gImageHandle,\r
+                          FullDevicePath,\r
+                          NULL,\r
+                          0,\r
+                          &ImageHandle\r
+                          );\r
+          if (EFI_ERROR (Status)) {\r
+            //\r
+            // The DevicePath failed, and it's not a valid\r
+            // removable media device.\r
+            //\r
+            continue;\r
+          }\r
+        } else {\r
+          continue;\r
+        }\r
+      }\r
+      break;\r
+    }\r
+  }\r
+\r
+  FreePool (UsbIoHandleBuffer);\r
+  return ImageHandle;\r
+}\r
+\r
+/**\r
+  Expand USB Class or USB WWID device path node to be full device path of a USB\r
+  device in platform then load the boot file on this full device path and return the \r
+  image handle.\r
+\r
+  This function support following 4 cases:\r
+  1) Boot Option device path starts with a USB Class or USB WWID device path,\r
+     and there is no Media FilePath device path in the end.\r
+     In this case, it will follow Removable Media Boot Behavior.\r
+  2) Boot Option device path starts with a USB Class or USB WWID device path,\r
+     and ended with Media FilePath device path.\r
+  3) Boot Option device path starts with a full device path to a USB Host Controller,\r
+     contains a USB Class or USB WWID device path node, while not ended with Media\r
+     FilePath device path. In this case, it will follow Removable Media Boot Behavior.\r
+  4) Boot Option device path starts with a full device path to a USB Host Controller,\r
+     contains a USB Class or USB WWID device path node, and ended with Media\r
+     FilePath device path.\r
+\r
+  @param  DevicePath    The Boot Option device path.\r
+\r
+  @return  The image handle of boot file, or NULL if there is no boot file found in\r
+           the specified USB Class or USB WWID device path.\r
+\r
+**/\r
+EFI_HANDLE *\r
+BdsExpandUsbShortFormDevicePath (\r
+  IN EFI_DEVICE_PATH_PROTOCOL       *DevicePath\r
+  )\r
+{\r
+  EFI_HANDLE                *ImageHandle;\r
+  EFI_DEVICE_PATH_PROTOCOL  *TempDevicePath;\r
+  EFI_DEVICE_PATH_PROTOCOL  *ShortFormDevicePath;\r
+\r
+  //\r
+  // Search for USB Class or USB WWID device path node.\r
   //\r
-  if ((OptionToCheck->BootCurrent == BootOption->BootCurrent) &&\r
-      (CompareMem (OptionToCheck->DevicePath, BootOption->DevicePath, GetDevicePathSize (OptionToCheck->DevicePath)) == 0))\r
-      {\r
-    Valid = TRUE;\r
+  ShortFormDevicePath = NULL;\r
+  ImageHandle         = NULL;\r
+  TempDevicePath      = DevicePath;\r
+  while (!IsDevicePathEnd (TempDevicePath)) {\r
+    if ((DevicePathType (TempDevicePath) == MESSAGING_DEVICE_PATH) &&\r
+        ((DevicePathSubType (TempDevicePath) == MSG_USB_CLASS_DP) ||\r
+         (DevicePathSubType (TempDevicePath) == MSG_USB_WWID_DP))) {\r
+      ShortFormDevicePath = TempDevicePath;\r
+      break;\r
+    }\r
+    TempDevicePath = NextDevicePathNode (TempDevicePath);\r
   }\r
 \r
-  FreePool (BootOption);\r
+  if (ShortFormDevicePath == NULL) {\r
+    //\r
+    // No USB Class or USB WWID device path node found, do nothing.\r
+    //\r
+    return NULL;\r
+  }\r
 \r
-  return Valid;\r
+  if (ShortFormDevicePath == DevicePath) {\r
+    //\r
+    // Boot Option device path starts with USB Class or USB WWID device path.\r
+    //\r
+    ImageHandle = BdsFindUsbDevice (NULL, ShortFormDevicePath);\r
+    if (ImageHandle == NULL) {\r
+      //\r
+      // Failed to find a match in existing devices, connect the short form USB\r
+      // device path and try again.\r
+      //\r
+      BdsLibConnectUsbDevByShortFormDP (0xff, ShortFormDevicePath);\r
+      ImageHandle = BdsFindUsbDevice (NULL, ShortFormDevicePath);\r
+    }\r
+  } else {\r
+    //\r
+    // Boot Option device path contains USB Class or USB WWID device path node.\r
+    //\r
+\r
+    //\r
+    // Prepare the parent device path for search.\r
+    //\r
+    TempDevicePath = DuplicateDevicePath (DevicePath);\r
+    ASSERT (TempDevicePath != NULL);\r
+    SetDevicePathEndNode (((UINT8 *) TempDevicePath) + ((UINTN) ShortFormDevicePath - (UINTN) DevicePath));\r
+\r
+    //\r
+    // The USB Host Controller device path is already in Boot Option device path\r
+    // and USB Bus driver already support RemainingDevicePath starts with USB\r
+    // Class or USB WWID device path, so just search in existing USB devices and\r
+    // doesn't perform ConnectController here.\r
+    //\r
+    ImageHandle = BdsFindUsbDevice (TempDevicePath, ShortFormDevicePath);\r
+    FreePool (TempDevicePath);\r
+  }\r
+\r
+  return ImageHandle;\r
 }\r
+\r
 /**\r
   Process the boot option follow the UEFI specification and\r
   special treat the legacy boot option with BBS_DEVICE_PATH.\r
@@ -183,6 +2224,7 @@ BdsLibBootViaBootOption (
   )\r
 {\r
   EFI_STATUS                Status;\r
+  EFI_STATUS                StatusLogo;\r
   EFI_HANDLE                Handle;\r
   EFI_HANDLE                ImageHandle;\r
   EFI_DEVICE_PATH_PROTOCOL  *FilePath;\r
@@ -190,11 +2232,7 @@ BdsLibBootViaBootOption (
   EFI_DEVICE_PATH_PROTOCOL  *WorkingDevicePath;\r
   EFI_ACPI_S3_SAVE_PROTOCOL *AcpiS3Save;\r
   LIST_ENTRY                TempBootLists;\r
-\r
-  //\r
-  // Record the performance data for End of BDS\r
-  //\r
-  PERF_END(NULL, "BDS", NULL, 0);\r
+  EFI_BOOT_LOGO_PROTOCOL    *BootLogo;\r
 \r
   *ExitDataSize = 0;\r
   *ExitData     = NULL;\r
@@ -222,17 +2260,6 @@ BdsLibBootViaBootOption (
       DevicePath = WorkingDevicePath;\r
     }\r
   }\r
-  //\r
-  // Signal the EVT_SIGNAL_READY_TO_BOOT event\r
-  //\r
-  EfiSignalEventReadyToBoot();\r
-\r
-  //\r
-  // Adjust the different type memory page number just before booting\r
-  // and save the updated info into the variable for next boot to use\r
-  //\r
-  BdsSetMemoryTypeInformationVariable ();\r
-\r
 \r
   //\r
   // Set Boot Current\r
@@ -243,7 +2270,7 @@ BdsLibBootViaBootOption (
     // In this case, "BootCurrent" is not created.\r
     // Only create the BootCurrent variable when it points to a valid Boot#### variable.\r
     //\r
-    gRT->SetVariable (\r
+    SetVariableAndReportStatusCodeOnError (\r
           L"BootCurrent",\r
           &gEfiGlobalVariableGuid,\r
           EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
@@ -252,41 +2279,69 @@ BdsLibBootViaBootOption (
           );\r
   }\r
 \r
-  ASSERT (Option->DevicePath != NULL);\r
-  if ((DevicePathType (Option->DevicePath) == BBS_DEVICE_PATH) &&\r
-      (DevicePathSubType (Option->DevicePath) == BBS_BBS_DP)\r
-    ) {\r
-    //\r
-    // Check to see if we should legacy BOOT. If yes then do the legacy boot\r
-    //\r
-    return BdsLibDoLegacyBoot (Option);\r
-  }\r
+  //\r
+  // Report Status Code to indicate ReadyToBoot event will be signalled\r
+  //\r
+  REPORT_STATUS_CODE (EFI_PROGRESS_CODE, (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_DXE_BS_PC_READY_TO_BOOT_EVENT));\r
+\r
+  //\r
+  // Signal the EVT_SIGNAL_READY_TO_BOOT event\r
+  //\r
+  EfiSignalEventReadyToBoot();\r
+\r
+  //\r
+  // Expand USB Class or USB WWID device path node to be full device path of a USB\r
+  // device in platform then load the boot file on this full device path and get the\r
+  // image handle.\r
+  //\r
+  ImageHandle = BdsExpandUsbShortFormDevicePath (DevicePath);\r
+\r
+  //\r
+  // Adjust the different type memory page number just before booting\r
+  // and save the updated info into the variable for next boot to use\r
+  //\r
+  BdsSetMemoryTypeInformationVariable ();\r
 \r
   //\r
-  // If the boot option point to Internal FV shell, make sure it is valid\r
+  // By expanding the USB Class or WWID device path, the ImageHandle has returnned.\r
+  // Here get the ImageHandle for the non USB class or WWID device path.\r
   //\r
-  Status = BdsLibUpdateFvFileDevicePath (&DevicePath, PcdGetPtr(PcdShellFile));\r
-  if (!EFI_ERROR(Status)) {\r
-    if (Option->DevicePath != NULL) {\r
-      FreePool(Option->DevicePath);\r
+  if (ImageHandle == NULL) {\r
+    ASSERT (Option->DevicePath != NULL);\r
+    if ((DevicePathType (Option->DevicePath) == BBS_DEVICE_PATH) &&\r
+        (DevicePathSubType (Option->DevicePath) == BBS_BBS_DP)\r
+       ) {\r
+      //\r
+      // Check to see if we should legacy BOOT. If yes then do the legacy boot\r
+      //\r
+      return BdsLibDoLegacyBoot (Option);\r
     }\r
-    Option->DevicePath  = AllocateZeroPool (GetDevicePathSize (DevicePath));\r
-    ASSERT(Option->DevicePath != NULL);\r
-    CopyMem (Option->DevicePath, DevicePath, GetDevicePathSize (DevicePath));\r
-    //\r
-    // Update the shell boot option\r
-    //\r
-    InitializeListHead (&TempBootLists);\r
-    BdsLibRegisterNewOption (&TempBootLists, DevicePath, L"EFI Internal Shell", L"BootOrder");\r
 \r
     //\r
-    // free the temporary device path created by BdsLibUpdateFvFileDevicePath()\r
+    // If the boot option point to Internal FV shell, make sure it is valid\r
     //\r
-    FreePool (DevicePath);\r
-    DevicePath = Option->DevicePath;\r
-  }\r
+    Status = BdsLibUpdateFvFileDevicePath (&DevicePath, PcdGetPtr(PcdShellFile));\r
+    if (!EFI_ERROR(Status)) {\r
+      if (Option->DevicePath != NULL) {\r
+        FreePool(Option->DevicePath);\r
+      }\r
+      Option->DevicePath  = AllocateZeroPool (GetDevicePathSize (DevicePath));\r
+      ASSERT(Option->DevicePath != NULL);\r
+      CopyMem (Option->DevicePath, DevicePath, GetDevicePathSize (DevicePath));\r
+      //\r
+      // Update the shell boot option\r
+      //\r
+      InitializeListHead (&TempBootLists);\r
+      BdsLibRegisterNewOption (&TempBootLists, DevicePath, L"EFI Internal Shell", L"BootOrder");\r
 \r
-  DEBUG_CODE_BEGIN();\r
+      //\r
+      // free the temporary device path created by BdsLibUpdateFvFileDevicePath()\r
+      //\r
+      FreePool (DevicePath);\r
+      DevicePath = Option->DevicePath;\r
+    }\r
+\r
+    DEBUG_CODE_BEGIN();\r
 \r
     if (Option->Description == NULL) {\r
       DEBUG ((DEBUG_INFO | DEBUG_LOAD, "Booting from unknown device path\n"));\r
@@ -294,63 +2349,65 @@ BdsLibBootViaBootOption (
       DEBUG ((DEBUG_INFO | DEBUG_LOAD, "Booting %S\n", Option->Description));\r
     }\r
         \r
-  DEBUG_CODE_END();\r
+    DEBUG_CODE_END();\r
   \r
-  Status = gBS->LoadImage (\r
-                  TRUE,\r
-                  gImageHandle,\r
-                  DevicePath,\r
-                  NULL,\r
-                  0,\r
-                  &ImageHandle\r
-                  );\r
-\r
-  //\r
-  // If we didn't find an image directly, we need to try as if it is a removable device boot option\r
-  // and load the image according to the default boot behavior for removable device.\r
-  //\r
-  if (EFI_ERROR (Status)) {\r
     //\r
-    // check if there is a bootable removable media could be found in this device path ,\r
-    // and get the bootable media handle\r
+    // Report status code for OS Loader LoadImage.\r
     //\r
-    Handle = BdsLibGetBootableHandle(DevicePath);\r
-    if (Handle == NULL) {\r
-       goto Done;\r
-    }\r
+    REPORT_STATUS_CODE (EFI_PROGRESS_CODE, PcdGet32 (PcdProgressCodeOsLoaderLoad));\r
+    Status = gBS->LoadImage (\r
+                    TRUE,\r
+                    gImageHandle,\r
+                    DevicePath,\r
+                    NULL,\r
+                    0,\r
+                    &ImageHandle\r
+                    );\r
+\r
     //\r
-    // Load the default boot file \EFI\BOOT\boot{machinename}.EFI from removable Media\r
-    //  machinename is ia32, ia64, x64, ...\r
+    // If we didn't find an image directly, we need to try as if it is a removable device boot option\r
+    // and load the image according to the default boot behavior for removable device.\r
     //\r
-    FilePath = FileDevicePath (Handle, EFI_REMOVABLE_MEDIA_FILE_NAME);\r
-    if (FilePath != NULL) {\r
-      Status = gBS->LoadImage (\r
-                      TRUE,\r
-                      gImageHandle,\r
-                      FilePath,\r
-                      NULL,\r
-                      0,\r
-                      &ImageHandle\r
-                      );\r
-      if (EFI_ERROR (Status)) {\r
+    if (EFI_ERROR (Status)) {\r
+      //\r
+      // check if there is a bootable removable media could be found in this device path ,\r
+      // and get the bootable media handle\r
+      //\r
+      Handle = BdsLibGetBootableHandle(DevicePath);\r
+      if (Handle != NULL) {\r
         //\r
-        // The DevicePath failed, and it's not a valid\r
-        // removable media device.\r
+        // Load the default boot file \EFI\BOOT\boot{machinename}.EFI from removable Media\r
+        //  machinename is ia32, ia64, x64, ...\r
         //\r
-        goto Done;\r
+        FilePath = FileDevicePath (Handle, EFI_REMOVABLE_MEDIA_FILE_NAME);\r
+        if (FilePath != NULL) {\r
+          REPORT_STATUS_CODE (EFI_PROGRESS_CODE, PcdGet32 (PcdProgressCodeOsLoaderLoad));\r
+          Status = gBS->LoadImage (\r
+                          TRUE,\r
+                          gImageHandle,\r
+                          FilePath,\r
+                          NULL,\r
+                          0,\r
+                          &ImageHandle\r
+                          );\r
+        }\r
       }\r
     }\r
   }\r
-\r
-  if (EFI_ERROR (Status)) {\r
+  //\r
+  // Provide the image with it's load options\r
+  //\r
+  if ((ImageHandle == NULL) || (EFI_ERROR(Status))) {\r
     //\r
-    // It there is any error from the Boot attempt exit now.\r
+    // Report Status Code to indicate that the failure to load boot option\r
     //\r
+    REPORT_STATUS_CODE (\r
+      EFI_ERROR_CODE | EFI_ERROR_MINOR,\r
+      (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_DXE_BS_EC_BOOT_OPTION_LOAD_ERROR)\r
+      );    \r
     goto Done;\r
   }\r
-  //\r
-  // Provide the image with it's load options\r
-  //\r
+\r
   Status = gBS->HandleProtocol (ImageHandle, &gEfiLoadedImageProtocolGuid, (VOID **) &ImageInfo);\r
   ASSERT_EFI_ERROR (Status);\r
 \r
@@ -358,6 +2415,12 @@ BdsLibBootViaBootOption (
     ImageInfo->LoadOptionsSize  = Option->LoadOptionsSize;\r
     ImageInfo->LoadOptions      = Option->LoadOptions;\r
   }\r
+\r
+  //\r
+  // Clean to NULL because the image is loaded directly from the firmwares boot manager.\r
+  //\r
+  ImageInfo->ParentHandle = NULL;\r
+\r
   //\r
   // Before calling the image, enable the Watchdog Timer for\r
   // the 5 Minute period\r
@@ -368,11 +2431,25 @@ BdsLibBootViaBootOption (
   // Write boot to OS performance data for UEFI boot\r
   //\r
   PERF_CODE (\r
-    WriteBootToOsPerformanceData ();\r
+    WriteBootToOsPerformanceData (NULL, NULL);\r
   );\r
 \r
+  //\r
+  // Report status code for OS Loader StartImage.\r
+  //\r
+  REPORT_STATUS_CODE (EFI_PROGRESS_CODE, PcdGet32 (PcdProgressCodeOsLoaderStart));\r
+\r
   Status = gBS->StartImage (ImageHandle, ExitDataSize, ExitData);\r
   DEBUG ((DEBUG_INFO | DEBUG_LOAD, "Image Return Status = %r\n", Status));\r
+  if (EFI_ERROR (Status)) {\r
+    //\r
+    // Report Status Code to indicate that boot failure\r
+    //\r
+    REPORT_STATUS_CODE (\r
+      EFI_ERROR_CODE | EFI_ERROR_MINOR,\r
+      (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_DXE_BS_EC_BOOT_OPTION_FAILED)\r
+      );\r
+  }\r
 \r
   //\r
   // Clear the Watchdog Timer after the image returns\r
@@ -380,15 +2457,25 @@ BdsLibBootViaBootOption (
   gBS->SetWatchdogTimer (0x0000, 0x0000, 0x0000, NULL);\r
 \r
 Done:\r
+  //\r
+  // Set Logo status invalid after trying one boot option\r
+  //\r
+  BootLogo = NULL;\r
+  StatusLogo = gBS->LocateProtocol (&gEfiBootLogoProtocolGuid, NULL, (VOID **) &BootLogo);\r
+  if (!EFI_ERROR (StatusLogo) && (BootLogo != NULL)) {\r
+    BootLogo->SetBootLogo (BootLogo, NULL, 0, 0, 0, 0);\r
+  }\r
+\r
   //\r
   // Clear Boot Current\r
+  // Deleting variable with current implementation shouldn't fail.\r
   //\r
   gRT->SetVariable (\r
         L"BootCurrent",\r
         &gEfiGlobalVariableGuid,\r
         EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
         0,\r
-        &Option->BootCurrent\r
+        NULL\r
         );\r
 \r
   return Status;\r
@@ -433,15 +2520,32 @@ BdsExpandPartitionPartialDevicePathToFull (
 \r
   FullDevicePath = NULL;\r
   //\r
-  // Check if there is prestore 'HDDP' variable.\r
+  // Check if there is prestore HD_BOOT_DEVICE_PATH_VARIABLE_NAME variable.\r
   // If exist, search the front path which point to partition node in the variable instants.\r
-  // If fail to find or 'HDDP' not exist, reconnect all and search in all system\r
+  // If fail to find or HD_BOOT_DEVICE_PATH_VARIABLE_NAME not exist, reconnect all and search in all system\r
   //\r
-  CachedDevicePath = BdsLibGetVariableAndSize (\r
-                      L"HDDP",\r
-                      &mHdBootVariablePrivateGuid,\r
-                      &CachedDevicePathSize\r
-                      );\r
+  GetVariable2 (\r
+    HD_BOOT_DEVICE_PATH_VARIABLE_NAME,\r
+    &gHdBootDevicePathVariablGuid,\r
+    (VOID **) &CachedDevicePath,\r
+    &CachedDevicePathSize\r
+    );\r
+\r
+  //\r
+  // Delete the invalid HD_BOOT_DEVICE_PATH_VARIABLE_NAME variable.\r
+  //\r
+  if ((CachedDevicePath != NULL) && !IsDevicePathValid (CachedDevicePath, CachedDevicePathSize)) {\r
+    FreePool (CachedDevicePath);\r
+    CachedDevicePath = NULL;\r
+    Status = gRT->SetVariable (\r
+                    HD_BOOT_DEVICE_PATH_VARIABLE_NAME,\r
+                    &gHdBootDevicePathVariablGuid,\r
+                    0,\r
+                    0,\r
+                    NULL\r
+                    );\r
+    ASSERT_EFI_ERROR (Status);\r
+  }\r
 \r
   if (CachedDevicePath != NULL) {\r
     TempNewDevicePath = CachedDevicePath;\r
@@ -481,7 +2585,7 @@ BdsExpandPartitionPartialDevicePathToFull (
       FullDevicePath = AppendDevicePath (Instance, DevicePath);\r
 \r
       //\r
-      // Adjust the 'HDDP' instances sequence if the matched one is not first one.\r
+      // Adjust the HD_BOOT_DEVICE_PATH_VARIABLE_NAME instances sequence if the matched one is not first one.\r
       //\r
       if (NeedAdjust) {\r
         //\r
@@ -499,11 +2603,12 @@ BdsExpandPartitionPartialDevicePathToFull (
         FreePool (TempNewDevicePath);\r
         //\r
         // Save the matching Device Path so we don't need to do a connect all next time\r
+        // Failure to set the variable only impacts the performance when next time expanding the short-form device path.\r
         //\r
         Status = gRT->SetVariable (\r
-                        L"HDDP",\r
-                        &mHdBootVariablePrivateGuid,\r
-                        EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,\r
+                        HD_BOOT_DEVICE_PATH_VARIABLE_NAME,\r
+                        &gHdBootDevicePathVariablGuid,\r
+                        EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE,\r
                         GetDevicePathSize (CachedDevicePath),\r
                         CachedDevicePath\r
                         );\r
@@ -516,7 +2621,7 @@ BdsExpandPartitionPartialDevicePathToFull (
   }\r
 \r
   //\r
-  // If we get here we fail to find or 'HDDP' not exist, and now we need\r
+  // If we get here we fail to find or HD_BOOT_DEVICE_PATH_VARIABLE_NAME not exist, and now we need\r
   // to search all devices in the system for a matched partition\r
   //\r
   BdsLibConnectAllDriversToAllControllers ();\r
@@ -546,30 +2651,30 @@ BdsExpandPartitionPartialDevicePathToFull (
       FullDevicePath = AppendDevicePath (BlockIoDevicePath, DevicePath);\r
 \r
       //\r
-      // Save the matched partition device path in 'HDDP' variable\r
+      // Save the matched partition device path in HD_BOOT_DEVICE_PATH_VARIABLE_NAME variable\r
       //\r
       if (CachedDevicePath != NULL) {\r
         //\r
-        // Save the matched partition device path as first instance of 'HDDP' variable\r
+        // Save the matched partition device path as first instance of HD_BOOT_DEVICE_PATH_VARIABLE_NAME variable\r
         //\r
         if (BdsLibMatchDevicePaths (CachedDevicePath, BlockIoDevicePath)) {\r
           TempNewDevicePath = CachedDevicePath;\r
           CachedDevicePath = BdsLibDelPartMatchInstance (CachedDevicePath, BlockIoDevicePath);\r
           FreePool(TempNewDevicePath);\r
+        }\r
 \r
-          TempNewDevicePath = CachedDevicePath;\r
-          CachedDevicePath = AppendDevicePathInstance (BlockIoDevicePath, CachedDevicePath);\r
-          if (TempNewDevicePath != NULL) {\r
-            FreePool(TempNewDevicePath);\r
-          }\r
-        } else {\r
+        if (CachedDevicePath != NULL) {\r
           TempNewDevicePath = CachedDevicePath;\r
           CachedDevicePath = AppendDevicePathInstance (BlockIoDevicePath, CachedDevicePath);\r
           FreePool(TempNewDevicePath);\r
+        } else {\r
+          CachedDevicePath = DuplicateDevicePath (BlockIoDevicePath);\r
         }\r
+\r
         //\r
         // Here limit the device path instance number to 12, which is max number for a system support 3 IDE controller\r
-        // If the user try to boot many OS in different HDs or partitions, in theory, the 'HDDP' variable maybe become larger and larger.\r
+        // If the user try to boot many OS in different HDs or partitions, in theory, \r
+        // the HD_BOOT_DEVICE_PATH_VARIABLE_NAME variable maybe become larger and larger.\r
         //\r
         InstanceNum = 0;\r
         ASSERT (CachedDevicePath != NULL);\r
@@ -597,11 +2702,12 @@ BdsExpandPartitionPartialDevicePathToFull (
 \r
       //\r
       // Save the matching Device Path so we don't need to do a connect all next time\r
+      // Failure to set the variable only impacts the performance when next time expanding the short-form device path.\r
       //\r
       Status = gRT->SetVariable (\r
-                      L"HDDP",\r
-                      &mHdBootVariablePrivateGuid,\r
-                      EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,\r
+                      HD_BOOT_DEVICE_PATH_VARIABLE_NAME,\r
+                      &gHdBootDevicePathVariablGuid,\r
+                      EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE,\r
                       GetDevicePathSize (CachedDevicePath),\r
                       CachedDevicePath\r
                       );\r
@@ -769,6 +2875,13 @@ BdsLibDeleteOptionFromHandle (
       return EFI_OUT_OF_RESOURCES;\r
     }\r
 \r
+    if (!ValidateOption(BootOptionVar, BootOptionSize)) {\r
+      BdsDeleteBootOption (BootOrder[Index], BootOrder, &BootOrderSize);\r
+      FreePool (BootOptionVar);\r
+      Index++;\r
+      continue;\r
+    }\r
+\r
     TempPtr = BootOptionVar;\r
     TempPtr += sizeof (UINT32) + sizeof (UINT16);\r
     TempPtr += StrSize ((CHAR16 *) TempPtr);\r
@@ -799,6 +2912,10 @@ BdsLibDeleteOptionFromHandle (
                   BootOrderSize,\r
                   BootOrder\r
                   );\r
+  //\r
+  // Shrinking variable with existing variable implementation shouldn't fail.\r
+  //\r
+  ASSERT_EFI_ERROR (Status);\r
 \r
   FreePool (BootOrder);\r
 \r
@@ -831,10 +2948,14 @@ BdsDeleteAllInvalidEfiBootOption (
   EFI_DEVICE_PATH_PROTOCOL  *OptionDevicePath;\r
   UINT8                     *TempPtr;\r
   CHAR16                    *Description;\r
+  BOOLEAN                   Corrupted;\r
 \r
-  Status        = EFI_SUCCESS;\r
-  BootOrder     = NULL;\r
-  BootOrderSize = 0;\r
+  Status           = EFI_SUCCESS;\r
+  BootOrder        = NULL;\r
+  Description      = NULL;\r
+  OptionDevicePath = NULL;\r
+  BootOrderSize    = 0;\r
+  Corrupted        = FALSE;\r
 \r
   //\r
   // Check "BootOrder" variable firstly, this variable hold the number of boot options\r
@@ -861,23 +2982,27 @@ BdsDeleteAllInvalidEfiBootOption (
       return EFI_OUT_OF_RESOURCES;\r
     }\r
 \r
-    TempPtr = BootOptionVar;\r
-    TempPtr += sizeof (UINT32) + sizeof (UINT16);\r
-    Description = (CHAR16 *) TempPtr;\r
-    TempPtr += StrSize ((CHAR16 *) TempPtr);\r
-    OptionDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) TempPtr;\r
+    if (!ValidateOption(BootOptionVar, BootOptionSize)) {\r
+      Corrupted = TRUE;\r
+    } else {\r
+      TempPtr = BootOptionVar;\r
+      TempPtr += sizeof (UINT32) + sizeof (UINT16);\r
+      Description = (CHAR16 *) TempPtr;\r
+      TempPtr += StrSize ((CHAR16 *) TempPtr);\r
+      OptionDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) TempPtr;\r
 \r
-    //\r
-    // Skip legacy boot option (BBS boot device)\r
-    //\r
-    if ((DevicePathType (OptionDevicePath) == BBS_DEVICE_PATH) &&\r
-        (DevicePathSubType (OptionDevicePath) == BBS_BBS_DP)) {\r
-      FreePool (BootOptionVar);\r
-      Index++;\r
-      continue;\r
+      //\r
+      // Skip legacy boot option (BBS boot device)\r
+      //\r
+      if ((DevicePathType (OptionDevicePath) == BBS_DEVICE_PATH) &&\r
+          (DevicePathSubType (OptionDevicePath) == BBS_BBS_DP)) {\r
+        FreePool (BootOptionVar);\r
+        Index++;\r
+        continue;\r
+      }\r
     }\r
 \r
-    if (!BdsLibIsValidEFIBootOptDevicePathExt (OptionDevicePath, FALSE, Description)) {\r
+    if (Corrupted || !BdsLibIsValidEFIBootOptDevicePathExt (OptionDevicePath, FALSE, Description)) {\r
       //\r
       // Delete this invalid boot option "Boot####"\r
       //\r
@@ -889,9 +3014,14 @@ BdsDeleteAllInvalidEfiBootOption (
                       NULL\r
                       );\r
       //\r
+      // Deleting variable with current variable implementation shouldn't fail.\r
+      //\r
+      ASSERT_EFI_ERROR (Status);\r
+      //\r
       // Mark this boot option in boot order as deleted\r
       //\r
       BootOrder[Index] = 0xffff;\r
+      Corrupted        = FALSE;\r
     }\r
 \r
     FreePool (BootOptionVar);\r
@@ -915,6 +3045,10 @@ BdsDeleteAllInvalidEfiBootOption (
                   Index2 * sizeof (UINT16),\r
                   BootOrder\r
                   );\r
+  //\r
+  // Shrinking variable with current variable implementation shouldn't fail.\r
+  //\r
+  ASSERT_EFI_ERROR (Status);\r
 \r
   FreePool (BootOrder);\r
 \r
@@ -974,6 +3108,7 @@ BdsLibEnumerateAllBootOption (
 {\r
   EFI_STATUS                    Status;\r
   UINT16                        FloppyNumber;\r
+  UINT16                        HarddriveNumber;\r
   UINT16                        CdromNumber;\r
   UINT16                        UsbNumber;\r
   UINT16                        MiscNumber;\r
@@ -982,6 +3117,8 @@ BdsLibEnumerateAllBootOption (
   UINTN                         NumberBlockIoHandles;\r
   EFI_HANDLE                    *BlockIoHandles;\r
   EFI_BLOCK_IO_PROTOCOL         *BlkIo;\r
+  BOOLEAN                       Removable[2];\r
+  UINTN                         RemovableIndex;\r
   UINTN                         Index;\r
   UINTN                         NumOfLoadFileHandles;\r
   EFI_HANDLE                    *LoadFileHandles;\r
@@ -1004,13 +3141,14 @@ BdsLibEnumerateAllBootOption (
   EFI_IMAGE_OPTIONAL_HEADER_UNION       HdrData;\r
   EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION   Hdr;\r
 \r
-  FloppyNumber  = 0;\r
-  CdromNumber   = 0;\r
-  UsbNumber     = 0;\r
-  MiscNumber    = 0;\r
-  ScsiNumber    = 0;\r
-  PlatLang      = NULL;\r
-  LastLang      = NULL;\r
+  FloppyNumber    = 0;\r
+  HarddriveNumber = 0;\r
+  CdromNumber     = 0;\r
+  UsbNumber       = 0;\r
+  MiscNumber      = 0;\r
+  ScsiNumber      = 0;\r
+  PlatLang        = NULL;\r
+  LastLang        = NULL;\r
   ZeroMem (Buffer, sizeof (Buffer));\r
 \r
   //\r
@@ -1018,8 +3156,8 @@ BdsLibEnumerateAllBootOption (
   // device from the boot order variable\r
   //\r
   if (mEnumBootDevice) {\r
-    LastLang = GetVariable (L"LastEnumLang", &mBdsLibLastLangGuid);\r
-    PlatLang = GetEfiGlobalVariable (L"PlatformLang");\r
+    GetVariable2 (LAST_ENUM_LANGUAGE_VARIABLE_NAME, &gLastEnumLangGuid, (VOID**)&LastLang, NULL);\r
+    GetEfiGlobalVariable2 (L"PlatformLang", (VOID**)&PlatLang, NULL);\r
     ASSERT (PlatLang != NULL);\r
     if ((LastLang != NULL) && (AsciiStrCmp (LastLang, PlatLang) == 0)) {\r
       Status = BdsLibBuildOptionFromVar (BdsBootOptionList, L"BootOrder");\r
@@ -1028,13 +3166,15 @@ BdsLibEnumerateAllBootOption (
       return Status;\r
     } else {\r
       Status = gRT->SetVariable (\r
-        L"LastEnumLang",\r
-        &mBdsLibLastLangGuid,\r
+        LAST_ENUM_LANGUAGE_VARIABLE_NAME,\r
+        &gLastEnumLangGuid,\r
         EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE,\r
         AsciiStrSize (PlatLang),\r
         PlatLang\r
         );\r
-      ASSERT_EFI_ERROR (Status);\r
+      //\r
+      // Failure to set the variable only impacts the performance next time enumerating the boot options.\r
+      //\r
 \r
       if (LastLang != NULL) {\r
         FreePool (LastLang);\r
@@ -1056,8 +3196,13 @@ BdsLibEnumerateAllBootOption (
   BdsDeleteAllInvalidEfiBootOption ();\r
 \r
   //\r
-  // Parse removable media\r
+  // Parse removable media followed by fixed media.\r
+  // The Removable[] array is used by the for-loop below to create removable media boot options \r
+  // at first, and then to create fixed media boot options.\r
   //\r
+  Removable[0]  = FALSE;\r
+  Removable[1]  = TRUE;\r
+\r
   gBS->LocateHandleBuffer (\r
         ByProtocol,\r
         &gEfiBlockIoProtocolGuid,\r
@@ -1066,81 +3211,90 @@ BdsLibEnumerateAllBootOption (
         &BlockIoHandles\r
         );\r
 \r
-  for (Index = 0; Index < NumberBlockIoHandles; Index++) {\r
-    Status = gBS->HandleProtocol (\r
-                    BlockIoHandles[Index],\r
-                    &gEfiBlockIoProtocolGuid,\r
-                    (VOID **) &BlkIo\r
-                    );\r
-    if (!EFI_ERROR (Status)) {\r
-      if (!BlkIo->Media->RemovableMedia) {\r
-        //\r
-        // skip the non-removable block devices\r
-        //\r
+  for (RemovableIndex = 0; RemovableIndex < 2; RemovableIndex++) {\r
+    for (Index = 0; Index < NumberBlockIoHandles; Index++) {\r
+      Status = gBS->HandleProtocol (\r
+                      BlockIoHandles[Index],\r
+                      &gEfiBlockIoProtocolGuid,\r
+                      (VOID **) &BlkIo\r
+                      );\r
+      //\r
+      // skip the fixed block io then the removable block io\r
+      //\r
+      if (EFI_ERROR (Status) || (BlkIo->Media->RemovableMedia == Removable[RemovableIndex])) {\r
         continue;\r
       }\r
-    }\r
-    DevicePath  = DevicePathFromHandle (BlockIoHandles[Index]);\r
-    DevicePathType = BdsGetBootTypeFromDevicePath (DevicePath);\r
+      DevicePath  = DevicePathFromHandle (BlockIoHandles[Index]);\r
+      DevicePathType = BdsGetBootTypeFromDevicePath (DevicePath);\r
 \r
-    switch (DevicePathType) {\r
-    case BDS_EFI_ACPI_FLOPPY_BOOT:\r
-      if (FloppyNumber != 0) {\r
-        UnicodeSPrint (Buffer, sizeof (Buffer), L"%s %d", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_FLOPPY)), FloppyNumber);\r
-      } else {\r
-        UnicodeSPrint (Buffer, sizeof (Buffer), L"%s", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_FLOPPY)));\r
-      }\r
-      BdsLibBuildOptionFromHandle (BlockIoHandles[Index], BdsBootOptionList, Buffer);\r
-      FloppyNumber++;\r
-      break;\r
+      switch (DevicePathType) {\r
+      case BDS_EFI_ACPI_FLOPPY_BOOT:\r
+        if (FloppyNumber != 0) {\r
+          UnicodeSPrint (Buffer, sizeof (Buffer), L"%s %d", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_FLOPPY)), FloppyNumber);\r
+        } else {\r
+          UnicodeSPrint (Buffer, sizeof (Buffer), L"%s", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_FLOPPY)));\r
+        }\r
+        BdsLibBuildOptionFromHandle (BlockIoHandles[Index], BdsBootOptionList, Buffer);\r
+        FloppyNumber++;\r
+        break;\r
 \r
-    //\r
-    // Assume a removable SATA device should be the DVD/CD device\r
-    //\r
-    case BDS_EFI_MESSAGE_ATAPI_BOOT:\r
-    case BDS_EFI_MESSAGE_SATA_BOOT:\r
-      if (CdromNumber != 0) {\r
-        UnicodeSPrint (Buffer, sizeof (Buffer), L"%s %d", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_CD_DVD)), CdromNumber);\r
-      } else {\r
-        UnicodeSPrint (Buffer, sizeof (Buffer), L"%s", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_CD_DVD)));\r
-      }\r
-      DEBUG ((DEBUG_INFO | DEBUG_LOAD, "Buffer: %S\n", Buffer));\r
-      BdsLibBuildOptionFromHandle (BlockIoHandles[Index], BdsBootOptionList, Buffer);\r
-      CdromNumber++;\r
-      break;\r
+      //\r
+      // Assume a removable SATA device should be the DVD/CD device, a fixed SATA device should be the Hard Drive device.\r
+      //\r
+      case BDS_EFI_MESSAGE_ATAPI_BOOT:\r
+      case BDS_EFI_MESSAGE_SATA_BOOT:\r
+        if (BlkIo->Media->RemovableMedia) {\r
+          if (CdromNumber != 0) {\r
+            UnicodeSPrint (Buffer, sizeof (Buffer), L"%s %d", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_CD_DVD)), CdromNumber);\r
+          } else {\r
+            UnicodeSPrint (Buffer, sizeof (Buffer), L"%s", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_CD_DVD)));\r
+          }\r
+          CdromNumber++;\r
+        } else {\r
+          if (HarddriveNumber != 0) {\r
+            UnicodeSPrint (Buffer, sizeof (Buffer), L"%s %d", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_HARDDRIVE)), HarddriveNumber);\r
+          } else {\r
+            UnicodeSPrint (Buffer, sizeof (Buffer), L"%s", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_HARDDRIVE)));\r
+          }\r
+          HarddriveNumber++;\r
+        }\r
+        DEBUG ((DEBUG_INFO | DEBUG_LOAD, "Buffer: %S\n", Buffer));\r
+        BdsLibBuildOptionFromHandle (BlockIoHandles[Index], BdsBootOptionList, Buffer);\r
+        break;\r
 \r
-    case BDS_EFI_MESSAGE_USB_DEVICE_BOOT:\r
-      if (UsbNumber != 0) {\r
-        UnicodeSPrint (Buffer, sizeof (Buffer), L"%s %d", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_USB)), UsbNumber);\r
-      } else {\r
-        UnicodeSPrint (Buffer, sizeof (Buffer), L"%s", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_USB)));\r
-      }\r
-      BdsLibBuildOptionFromHandle (BlockIoHandles[Index], BdsBootOptionList, Buffer);\r
-      UsbNumber++;\r
-      break;\r
+      case BDS_EFI_MESSAGE_USB_DEVICE_BOOT:\r
+        if (UsbNumber != 0) {\r
+          UnicodeSPrint (Buffer, sizeof (Buffer), L"%s %d", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_USB)), UsbNumber);\r
+        } else {\r
+          UnicodeSPrint (Buffer, sizeof (Buffer), L"%s", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_USB)));\r
+        }\r
+        BdsLibBuildOptionFromHandle (BlockIoHandles[Index], BdsBootOptionList, Buffer);\r
+        UsbNumber++;\r
+        break;\r
 \r
-    case BDS_EFI_MESSAGE_SCSI_BOOT:\r
-      if (ScsiNumber != 0) {\r
-        UnicodeSPrint (Buffer, sizeof (Buffer), L"%s %d", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_SCSI)), ScsiNumber);\r
-      } else {\r
-        UnicodeSPrint (Buffer, sizeof (Buffer), L"%s", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_SCSI)));\r
-      }\r
-      BdsLibBuildOptionFromHandle (BlockIoHandles[Index], BdsBootOptionList, Buffer);\r
-      ScsiNumber++;\r
-      break;\r
+      case BDS_EFI_MESSAGE_SCSI_BOOT:\r
+        if (ScsiNumber != 0) {\r
+          UnicodeSPrint (Buffer, sizeof (Buffer), L"%s %d", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_SCSI)), ScsiNumber);\r
+        } else {\r
+          UnicodeSPrint (Buffer, sizeof (Buffer), L"%s", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_SCSI)));\r
+        }\r
+        BdsLibBuildOptionFromHandle (BlockIoHandles[Index], BdsBootOptionList, Buffer);\r
+        ScsiNumber++;\r
+        break;\r
 \r
-    case BDS_EFI_MESSAGE_MISC_BOOT:\r
-      if (MiscNumber != 0) {\r
-        UnicodeSPrint (Buffer, sizeof (Buffer), L"%s %d", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_MISC)), MiscNumber);\r
-      } else {\r
-        UnicodeSPrint (Buffer, sizeof (Buffer), L"%s", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_MISC)));\r
-      }\r
-      BdsLibBuildOptionFromHandle (BlockIoHandles[Index], BdsBootOptionList, Buffer);\r
-      MiscNumber++;\r
-      break;\r
+      case BDS_EFI_MESSAGE_MISC_BOOT:\r
+        if (MiscNumber != 0) {\r
+          UnicodeSPrint (Buffer, sizeof (Buffer), L"%s %d", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_MISC)), MiscNumber);\r
+        } else {\r
+          UnicodeSPrint (Buffer, sizeof (Buffer), L"%s", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_MISC)));\r
+        }\r
+        BdsLibBuildOptionFromHandle (BlockIoHandles[Index], BdsBootOptionList, Buffer);\r
+        MiscNumber++;\r
+        break;\r
 \r
-    default:\r
-      break;\r
+      default:\r
+        break;\r
+      }\r
     }\r
   }\r
 \r
@@ -1176,7 +3330,7 @@ BdsLibEnumerateAllBootOption (
     // Do the removable Media thing. \EFI\BOOT\boot{machinename}.EFI\r
     //  machinename is ia32, ia64, x64, ...\r
     //\r
-    Hdr.Union = &HdrData;\r
+    Hdr.Union  = &HdrData;\r
     NeedDelete = TRUE;\r
     Status     = BdsLibGetImageHeader (\r
                    FileSystemHandles[Index],\r
@@ -1363,6 +3517,7 @@ BdsLibBootNext (
   VOID\r
   )\r
 {\r
+  EFI_STATUS        Status;\r
   UINT16            *BootNext;\r
   UINTN             BootNextSize;\r
   CHAR16            Buffer[20];\r
@@ -1387,13 +3542,17 @@ BdsLibBootNext (
   // Clear the boot next variable first\r
   //\r
   if (BootNext != NULL) {\r
-    gRT->SetVariable (\r
-          L"BootNext",\r
-          &gEfiGlobalVariableGuid,\r
-          EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,\r
-          0,\r
-          BootNext\r
-          );\r
+    Status = gRT->SetVariable (\r
+                    L"BootNext",\r
+                    &gEfiGlobalVariableGuid,\r
+                    EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,\r
+                    0,\r
+                    NULL\r
+                    );\r
+    //\r
+    // Deleting variable with current variable implementation shouldn't fail.\r
+    //\r
+    ASSERT_EFI_ERROR (Status);\r
 \r
     //\r
     // Start to build the boot option and try to boot\r
@@ -1425,6 +3584,7 @@ BdsLibGetBootableHandle (
   )\r
 {\r
   EFI_STATUS                      Status;\r
+  EFI_TPL                         OldTpl;\r
   EFI_DEVICE_PATH_PROTOCOL        *UpdatedDevicePath;\r
   EFI_DEVICE_PATH_PROTOCOL        *DupDevicePath;\r
   EFI_HANDLE                      Handle;\r
@@ -1444,6 +3604,12 @@ BdsLibGetBootableHandle (
 \r
   UpdatedDevicePath = DevicePath;\r
 \r
+  //\r
+  // Enter to critical section to protect the acquired BlockIo instance \r
+  // from getting released due to the USB mass storage hotplug event\r
+  //\r
+  OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
+\r
   //\r
   // Check whether the device is connected\r
   //\r
@@ -1471,6 +3637,8 @@ BdsLibGetBootableHandle (
     // Get BlockIo protocol and check removable attribute\r
     //\r
     Status = gBS->HandleProtocol (Handle, &gEfiBlockIoProtocolGuid, (VOID **)&BlockIo);\r
+    ASSERT_EFI_ERROR (Status);\r
+\r
     //\r
     // Issue a dummy read to the device to check for media change.\r
     // When the removable media is changed, any Block IO read/write will\r
@@ -1567,6 +3735,8 @@ BdsLibGetBootableHandle (
     FreePool(SimpleFileSystemHandles);\r
   }\r
 \r
+  gBS->RestoreTPL (OldTpl);\r
+\r
   return ReturnHandle;\r
 }\r
 \r
@@ -1882,8 +4052,19 @@ BdsLibIsValidEFIBootOptDevicePathExt (
   // and assume it is ready to boot now\r
   //\r
   while (!IsDevicePathEnd (TempDevicePath)) {\r
-     LastDeviceNode = TempDevicePath;\r
-     TempDevicePath = NextDevicePathNode (TempDevicePath);\r
+    //\r
+    // If there is USB Class or USB WWID device path node, treat it as valid EFI\r
+    // Boot Option. BdsExpandUsbShortFormDevicePath () will be used to expand it\r
+    // to full device path.\r
+    //\r
+    if ((DevicePathType (TempDevicePath) == MESSAGING_DEVICE_PATH) &&\r
+        ((DevicePathSubType (TempDevicePath) == MSG_USB_CLASS_DP) ||\r
+         (DevicePathSubType (TempDevicePath) == MSG_USB_WWID_DP))) {\r
+      return TRUE;\r
+    }\r
+\r
+    LastDeviceNode = TempDevicePath;\r
+    TempDevicePath = NextDevicePathNode (TempDevicePath);\r
   }\r
   if ((DevicePathType (LastDeviceNode) == MEDIA_DEVICE_PATH) &&\r
     (DevicePathSubType (LastDeviceNode) == MEDIA_FILEPATH_DP)) {\r
@@ -1891,14 +4072,17 @@ BdsLibIsValidEFIBootOptDevicePathExt (
   }\r
 \r
   //\r
-  // Check if it's a valid boot option for internal Shell\r
+  // Check if it's a valid boot option for internal FV application\r
   //\r
   if (EfiGetNameGuidFromFwVolDevicePathNode ((MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *) LastDeviceNode) != NULL) {\r
     //\r
-    // If the boot option point to Internal FV shell, make sure it is valid\r
+    // If the boot option point to internal FV application, make sure it is valid\r
     //\r
     TempDevicePath = DevPath;\r
-    Status = BdsLibUpdateFvFileDevicePath (&TempDevicePath, PcdGetPtr(PcdShellFile));\r
+    Status = BdsLibUpdateFvFileDevicePath (\r
+               &TempDevicePath,\r
+               EfiGetNameGuidFromFwVolDevicePathNode ((MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *) LastDeviceNode)\r
+               );\r
     if (Status == EFI_ALREADY_STARTED) {\r
       return TRUE;\r
     } else {\r