]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Library/UefiBootManagerLib/BmBoot.c
MdeModulePkg: Replace BSD License with BSD+Patent License
[mirror_edk2.git] / MdeModulePkg / Library / UefiBootManagerLib / BmBoot.c
index 8a3a4027eec0139d8203eee14a080eaf95cec3df..952033fc825bb72891918bff59eb0695182efffe 100644 (file)
@@ -1,15 +1,9 @@
 /** @file\r
   Library functions which relates with booting.\r
 \r
-Copyright (c) 2011 - 2017, Intel Corporation. All rights reserved.<BR>\r
+Copyright (c) 2011 - 2019, Intel Corporation. All rights reserved.<BR>\r
 (C) Copyright 2015-2016 Hewlett Packard Enterprise Development LP<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
-http://opensource.org/licenses/bsd-license.php\r
-\r
-THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
-WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+SPDX-License-Identifier: BSD-2-Clause-Patent\r
 \r
 **/\r
 \r
@@ -27,6 +21,29 @@ EFI_BOOT_MANAGER_LEGACY_BOOT                 mBmLegacyBoot              = NULL;
 EFI_GUID mBmHardDriveBootVariableGuid = { 0xfab7e9e1, 0x39dd, 0x4f2b, { 0x84, 0x08, 0xe2, 0x0e, 0x90, 0x6c, 0xb6, 0xde } };\r
 EFI_GUID mBmAutoCreateBootOptionGuid  = { 0x8108ac4e, 0x9f11, 0x4d59, { 0x85, 0x0e, 0xe2, 0x1a, 0x52, 0x2c, 0x59, 0xb2 } };\r
 \r
+/**\r
+\r
+  End Perf entry of BDS\r
+\r
+  @param  Event                 The triggered event.\r
+  @param  Context               Context for this event.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+BmEndOfBdsPerfCode (\r
+  IN EFI_EVENT  Event,\r
+  IN VOID       *Context\r
+  )\r
+{\r
+  //\r
+  // Record the performance data for End of BDS\r
+  //\r
+  PERF_CROSSMODULE_END("BDS");\r
+\r
+  return ;\r
+}\r
+\r
 /**\r
   The function registers the legacy boot support capabilities.\r
 \r
@@ -86,7 +103,7 @@ BmFindBootOptionInVariable (
   EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions;\r
   UINTN                        BootOptionCount;\r
   UINTN                        Index;\r
-  \r
+\r
   OptionNumber = LoadOptionNumberUnassigned;\r
 \r
   //\r
@@ -131,21 +148,16 @@ BmFindBootOptionInVariable (
 }\r
 \r
 /**\r
-  Get the file buffer using a Memory Mapped Device Path.\r
-\r
+  Return the correct FV file path.\r
   FV address may change across reboot. This routine promises the FV file device path is right.\r
 \r
   @param  FilePath     The Memory Mapped Device Path to get the file buffer.\r
-  @param  FullPath     Receive the updated FV Device Path pointint to the file.\r
-  @param  FileSize     Receive the file buffer size.\r
 \r
-  @return  The file buffer.\r
+  @return  The updated FV Device Path pointint to the file.\r
 **/\r
-VOID *\r
-BmGetFileBufferByFvFilePath (\r
-  IN EFI_DEVICE_PATH_PROTOCOL      *FilePath,\r
-  OUT EFI_DEVICE_PATH_PROTOCOL     **FullPath,\r
-  OUT UINTN                        *FileSize\r
+EFI_DEVICE_PATH_PROTOCOL *\r
+BmAdjustFvFilePath (\r
+  IN EFI_DEVICE_PATH_PROTOCOL      *FilePath\r
   )\r
 {\r
   EFI_STATUS                    Status;\r
@@ -153,11 +165,10 @@ BmGetFileBufferByFvFilePath (
   EFI_DEVICE_PATH_PROTOCOL      *FvFileNode;\r
   EFI_HANDLE                    FvHandle;\r
   EFI_LOADED_IMAGE_PROTOCOL     *LoadedImage;\r
-  UINT32                        AuthenticationStatus;\r
   UINTN                         FvHandleCount;\r
   EFI_HANDLE                    *FvHandles;\r
   EFI_DEVICE_PATH_PROTOCOL      *NewDevicePath;\r
-  VOID                          *FileBuffer;\r
+  EFI_DEVICE_PATH_PROTOCOL      *FullPath;\r
 \r
   //\r
   // Get the file buffer by using the exactly FilePath.\r
@@ -165,11 +176,7 @@ BmGetFileBufferByFvFilePath (
   FvFileNode = FilePath;\r
   Status = gBS->LocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid, &FvFileNode, &FvHandle);\r
   if (!EFI_ERROR (Status)) {\r
-    FileBuffer = GetFileBufferByFilePath (TRUE, FilePath, FileSize, &AuthenticationStatus);\r
-    if (FileBuffer != NULL) {\r
-      *FullPath = DuplicateDevicePath (FilePath);\r
-    }\r
-    return FileBuffer;\r
+    return DuplicateDevicePath (FilePath);\r
   }\r
 \r
   //\r
@@ -190,11 +197,10 @@ BmGetFileBufferByFvFilePath (
          (VOID **) &LoadedImage\r
          );\r
   NewDevicePath = AppendDevicePathNode (DevicePathFromHandle (LoadedImage->DeviceHandle), FvFileNode);\r
-  FileBuffer = BmGetFileBufferByFvFilePath (NewDevicePath, FullPath, FileSize);\r
+  FullPath = BmAdjustFvFilePath (NewDevicePath);\r
   FreePool (NewDevicePath);\r
-\r
-  if (FileBuffer != NULL) {\r
-    return FileBuffer;\r
+  if (FullPath != NULL) {\r
+    return FullPath;\r
   }\r
 \r
   //\r
@@ -207,27 +213,30 @@ BmGetFileBufferByFvFilePath (
          &FvHandleCount,\r
          &FvHandles\r
          );\r
-  for (Index = 0; (Index < FvHandleCount) && (FileBuffer == NULL); Index++) {\r
+  for (Index = 0; Index < FvHandleCount; Index++) {\r
     if (FvHandles[Index] == LoadedImage->DeviceHandle) {\r
       //\r
-      // Skip current FV\r
+      // Skip current FV, it was handed in first step.\r
       //\r
       continue;\r
     }\r
     NewDevicePath = AppendDevicePathNode (DevicePathFromHandle (FvHandles[Index]), FvFileNode);\r
-    FileBuffer = BmGetFileBufferByFvFilePath (NewDevicePath, FullPath, FileSize);\r
+    FullPath = BmAdjustFvFilePath (NewDevicePath);\r
     FreePool (NewDevicePath);\r
+    if (FullPath != NULL) {\r
+      break;\r
+    }\r
   }\r
-  \r
+\r
   if (FvHandles != NULL) {\r
     FreePool (FvHandles);\r
   }\r
-  return FileBuffer;\r
+  return FullPath;\r
 }\r
 \r
 /**\r
   Check if it's a Device Path pointing to FV file.\r
-  \r
+\r
   The function doesn't garentee the device path points to existing FV file.\r
 \r
   @param  DevicePath     Input device path.\r
@@ -456,13 +465,13 @@ BmMatchUsbWwid (
 }\r
 \r
 /**\r
-  Find a USB device which match the specified short-form device path start with \r
+  Find a USB device which match the specified short-form device path start with\r
   USB Class or USB WWID device path. If ParentDevicePath is NULL, this function\r
   will search in all USB devices of the platform. If ParentDevicePath is not NULL,\r
   this function will only search in its child devices.\r
 \r
   @param DevicePath           The device path that contains USB Class or USB WWID device path.\r
-  @param ParentDevicePathSize The length of the device path before the USB Class or \r
+  @param ParentDevicePathSize The length of the device path before the USB Class or\r
                               USB WWID device path.\r
   @param UsbIoHandleCount     A pointer to the count of the returned USB IO handles.\r
 \r
@@ -484,7 +493,7 @@ BmFindUsbDevice (
   UINTN                     Index;\r
   BOOLEAN                   Matched;\r
 \r
-  ASSERT (UsbIoHandleCount != NULL);  \r
+  ASSERT (UsbIoHandleCount != NULL);\r
 \r
   //\r
   // Get all UsbIo Handles.\r
@@ -555,46 +564,64 @@ BmFindUsbDevice (
 \r
   @param FilePath      The device path pointing to a load option.\r
                        It could be a short-form device path.\r
-  @param FullPath      Return the full device path of the load option after\r
-                       short-form device path expanding.\r
-                       Caller is responsible to free it.\r
-  @param FileSize      Return the load option size.\r
+  @param FullPath      The full path returned by the routine in last call.\r
+                       Set to NULL in first call.\r
   @param ShortformNode Pointer to the USB short-form device path node in the FilePath buffer.\r
 \r
-  @return The load option buffer. Caller is responsible to free the memory.\r
+  @return The next possible full path pointing to the load option.\r
+          Caller is responsible to free the memory.\r
 **/\r
-VOID *\r
+EFI_DEVICE_PATH_PROTOCOL *\r
 BmExpandUsbDevicePath (\r
   IN  EFI_DEVICE_PATH_PROTOCOL  *FilePath,\r
-  OUT EFI_DEVICE_PATH_PROTOCOL  **FullPath,\r
-  OUT UINTN                     *FileSize,\r
-  IN EFI_DEVICE_PATH_PROTOCOL   *ShortformNode\r
+  IN  EFI_DEVICE_PATH_PROTOCOL  *FullPath,\r
+  IN  EFI_DEVICE_PATH_PROTOCOL  *ShortformNode\r
   )\r
 {\r
   UINTN                             ParentDevicePathSize;\r
   EFI_DEVICE_PATH_PROTOCOL          *RemainingDevicePath;\r
-  EFI_DEVICE_PATH_PROTOCOL          *FullDevicePath;\r
+  EFI_DEVICE_PATH_PROTOCOL          *NextFullPath;\r
   EFI_HANDLE                        *Handles;\r
   UINTN                             HandleCount;\r
   UINTN                             Index;\r
-  VOID                              *FileBuffer;\r
+  BOOLEAN                           GetNext;\r
 \r
+  NextFullPath = NULL;\r
+  GetNext = (BOOLEAN)(FullPath == NULL);\r
   ParentDevicePathSize = (UINTN) ShortformNode - (UINTN) FilePath;\r
   RemainingDevicePath = NextDevicePathNode (ShortformNode);\r
-  FileBuffer = NULL;\r
   Handles = BmFindUsbDevice (FilePath, ParentDevicePathSize, &HandleCount);\r
 \r
-  for (Index = 0; (Index < HandleCount) && (FileBuffer == NULL); Index++) {\r
-    FullDevicePath = AppendDevicePath (DevicePathFromHandle (Handles[Index]), RemainingDevicePath);\r
-    FileBuffer = EfiBootManagerGetLoadOptionBuffer (FullDevicePath, FullPath, FileSize);\r
-    FreePool (FullDevicePath);\r
+  for (Index = 0; Index < HandleCount; Index++) {\r
+    FilePath = AppendDevicePath (DevicePathFromHandle (Handles[Index]), RemainingDevicePath);\r
+    if (FilePath == NULL) {\r
+      //\r
+      // Out of memory.\r
+      //\r
+      continue;\r
+    }\r
+    NextFullPath = BmGetNextLoadOptionDevicePath (FilePath, NULL);\r
+    FreePool (FilePath);\r
+    if (NextFullPath == NULL) {\r
+      //\r
+      // No BlockIo or SimpleFileSystem under FilePath.\r
+      //\r
+      continue;\r
+    }\r
+    if (GetNext) {\r
+      break;\r
+    } else {\r
+      GetNext = (BOOLEAN)(CompareMem (NextFullPath, FullPath, GetDevicePathSize (NextFullPath)) == 0);\r
+      FreePool (NextFullPath);\r
+      NextFullPath = NULL;\r
+    }\r
   }\r
 \r
   if (Handles != NULL) {\r
     FreePool (Handles);\r
   }\r
 \r
-  return FileBuffer;\r
+  return NextFullPath;\r
 }\r
 \r
 /**\r
@@ -602,18 +629,16 @@ BmExpandUsbDevicePath (
 \r
   @param FilePath      The device path pointing to a load option.\r
                        It could be a short-form device path.\r
-  @param FullPath      Return the full device path of the load option after\r
-                       short-form device path expanding.\r
-                       Caller is responsible to free it.\r
-  @param FileSize      Return the load option size.\r
+  @param FullPath      The full path returned by the routine in last call.\r
+                       Set to NULL in first call.\r
 \r
-  @return The load option buffer. Caller is responsible to free the memory.\r
+  @return The next possible full path pointing to the load option.\r
+          Caller is responsible to free the memory.\r
 **/\r
-VOID *\r
+EFI_DEVICE_PATH_PROTOCOL *\r
 BmExpandFileDevicePath (\r
   IN  EFI_DEVICE_PATH_PROTOCOL    *FilePath,\r
-  OUT EFI_DEVICE_PATH_PROTOCOL    **FullPath,\r
-  OUT UINTN                       *FileSize\r
+  IN  EFI_DEVICE_PATH_PROTOCOL    *FullPath\r
   )\r
 {\r
   EFI_STATUS                      Status;\r
@@ -622,10 +647,9 @@ BmExpandFileDevicePath (
   EFI_HANDLE                      *Handles;\r
   EFI_BLOCK_IO_PROTOCOL           *BlockIo;\r
   UINTN                           MediaType;\r
-  EFI_DEVICE_PATH_PROTOCOL        *FullDevicePath;\r
-  VOID                            *FileBuffer;\r
-  UINT32                          AuthenticationStatus;\r
-  \r
+  EFI_DEVICE_PATH_PROTOCOL        *NextFullPath;\r
+  BOOLEAN                         GetNext;\r
+\r
   EfiBootManagerConnectAll ();\r
   Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiSimpleFileSystemProtocolGuid, NULL, &HandleCount, &Handles);\r
   if (EFI_ERROR (Status)) {\r
@@ -633,6 +657,8 @@ BmExpandFileDevicePath (
     Handles = NULL;\r
   }\r
 \r
+  GetNext = (BOOLEAN)(FullPath == NULL);\r
+  NextFullPath = NULL;\r
   //\r
   // Enumerate all removable media devices followed by all fixed media devices,\r
   //   followed by media devices which don't layer on block io.\r
@@ -647,24 +673,26 @@ BmExpandFileDevicePath (
           (MediaType == 1 && BlockIo != NULL && !BlockIo->Media->RemovableMedia) ||\r
           (MediaType == 2 && BlockIo == NULL)\r
           ) {\r
-        FullDevicePath = AppendDevicePath (DevicePathFromHandle (Handles[Index]), FilePath);\r
-        FileBuffer = GetFileBufferByFilePath (TRUE, FullDevicePath, FileSize, &AuthenticationStatus);\r
-        if (FileBuffer != NULL) {\r
-          *FullPath = FullDevicePath;\r
-          FreePool (Handles);\r
-          return FileBuffer;\r
+        NextFullPath = AppendDevicePath (DevicePathFromHandle (Handles[Index]), FilePath);\r
+        if (GetNext) {\r
+          break;\r
+        } else {\r
+          GetNext = (BOOLEAN)(CompareMem (NextFullPath, FullPath, GetDevicePathSize (NextFullPath)) == 0);\r
+          FreePool (NextFullPath);\r
+          NextFullPath = NULL;\r
         }\r
-        FreePool (FullDevicePath);\r
       }\r
     }\r
+    if (NextFullPath != NULL) {\r
+      break;\r
+    }\r
   }\r
 \r
   if (Handles != NULL) {\r
     FreePool (Handles);\r
   }\r
 \r
-  *FullPath = NULL;\r
-  return NULL;\r
+  return NextFullPath;\r
 }\r
 \r
 /**\r
@@ -672,25 +700,25 @@ BmExpandFileDevicePath (
 \r
   @param FilePath      The device path pointing to a load option.\r
                        It could be a short-form device path.\r
-  @param FullPath      Return the full device path of the load option after\r
-                       short-form device path expanding.\r
-                       Caller is responsible to free it.\r
-  @param FileSize      Return the load option size.\r
+  @param FullPath      The full path returned by the routine in last call.\r
+                       Set to NULL in first call.\r
 \r
-  @return The load option buffer. Caller is responsible to free the memory.\r
+  @return The next possible full path pointing to the load option.\r
+          Caller is responsible to free the memory.\r
 **/\r
-VOID *\r
+EFI_DEVICE_PATH_PROTOCOL *\r
 BmExpandUriDevicePath (\r
   IN  EFI_DEVICE_PATH_PROTOCOL    *FilePath,\r
-  OUT EFI_DEVICE_PATH_PROTOCOL    **FullPath,\r
-  OUT UINTN                       *FileSize\r
+  IN  EFI_DEVICE_PATH_PROTOCOL    *FullPath\r
   )\r
 {\r
   EFI_STATUS                      Status;\r
   UINTN                           Index;\r
   UINTN                           HandleCount;\r
   EFI_HANDLE                      *Handles;\r
-  VOID                            *FileBuffer;\r
+  EFI_DEVICE_PATH_PROTOCOL        *NextFullPath;\r
+  EFI_DEVICE_PATH_PROTOCOL        *RamDiskDevicePath;\r
+  BOOLEAN                         GetNext;\r
 \r
   EfiBootManagerConnectAll ();\r
   Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiLoadFileProtocolGuid, NULL, &HandleCount, &Handles);\r
@@ -699,11 +727,29 @@ BmExpandUriDevicePath (
     Handles = NULL;\r
   }\r
 \r
-  FileBuffer = NULL;\r
+  NextFullPath = NULL;\r
+  GetNext = (BOOLEAN)(FullPath == NULL);\r
   for (Index = 0; Index < HandleCount; Index++) {\r
-    FileBuffer = BmGetFileBufferFromLoadFile (Handles[Index], FilePath, FullPath, FileSize);\r
-    if (FileBuffer != NULL) {\r
+    NextFullPath = BmExpandLoadFile (Handles[Index], FilePath);\r
+\r
+    if (NextFullPath == NULL) {\r
+      continue;\r
+    }\r
+\r
+    if (GetNext) {\r
       break;\r
+    } else {\r
+      GetNext = (BOOLEAN)(CompareMem (NextFullPath, FullPath, GetDevicePathSize (NextFullPath)) == 0);\r
+      //\r
+      // Free the resource occupied by the RAM disk.\r
+      //\r
+      RamDiskDevicePath = BmGetRamDiskDevicePath (NextFullPath);\r
+      if (RamDiskDevicePath != NULL) {\r
+        BmDestroyRamDisk (RamDiskDevicePath);\r
+        FreePool (RamDiskDevicePath);\r
+      }\r
+      FreePool (NextFullPath);\r
+      NextFullPath = NULL;\r
     }\r
   }\r
 \r
@@ -711,7 +757,7 @@ BmExpandUriDevicePath (
     FreePool (Handles);\r
   }\r
 \r
-  return FileBuffer;\r
+  return NextFullPath;\r
 }\r
 \r
 /**\r
@@ -728,7 +774,7 @@ BmCachePartitionDevicePath (
 {\r
   EFI_DEVICE_PATH_PROTOCOL        *TempDevicePath;\r
   UINTN                           Count;\r
-  \r
+\r
   if (BmMatchDevicePaths (*CachedDevicePath, DevicePath)) {\r
     TempDevicePath = *CachedDevicePath;\r
     *CachedDevicePath = BmDelPartMatchInstance (*CachedDevicePath, DevicePath);\r
@@ -781,35 +827,28 @@ BmCachePartitionDevicePath (
 \r
   @param FilePath      The device path pointing to a load option.\r
                        It could be a short-form device path.\r
-  @param FullPath      Return the full device path of the load option after\r
-                       short-form device path expanding.\r
-                       Caller is responsible to free it.\r
-  @param FileSize      Return the load option size.\r
 \r
-  @return The load option buffer. Caller is responsible to free the memory.\r
+  @return The full device path pointing to the load option.\r
 **/\r
-VOID *\r
+EFI_DEVICE_PATH_PROTOCOL *\r
 BmExpandPartitionDevicePath (\r
-  IN  EFI_DEVICE_PATH_PROTOCOL  *FilePath,\r
-  OUT EFI_DEVICE_PATH_PROTOCOL  **FullPath,\r
-  OUT UINTN                     *FileSize\r
+  IN  EFI_DEVICE_PATH_PROTOCOL  *FilePath\r
   )\r
 {\r
   EFI_STATUS                Status;\r
   UINTN                     BlockIoHandleCount;\r
   EFI_HANDLE                *BlockIoBuffer;\r
-  VOID                      *FileBuffer;\r
   EFI_DEVICE_PATH_PROTOCOL  *BlockIoDevicePath;\r
   UINTN                     Index;\r
   EFI_DEVICE_PATH_PROTOCOL  *CachedDevicePath;\r
   EFI_DEVICE_PATH_PROTOCOL  *TempNewDevicePath;\r
   EFI_DEVICE_PATH_PROTOCOL  *TempDevicePath;\r
+  EFI_DEVICE_PATH_PROTOCOL  *FullPath;\r
   UINTN                     CachedDevicePathSize;\r
   BOOLEAN                   NeedAdjust;\r
   EFI_DEVICE_PATH_PROTOCOL  *Instance;\r
   UINTN                     Size;\r
 \r
-  FileBuffer = NULL;\r
   //\r
   // Check if there is prestore 'HDDP' variable.\r
   // If exist, search the front path which point to partition node in the variable instants.\r
@@ -833,6 +872,7 @@ BmExpandPartitionDevicePath (
     ASSERT_EFI_ERROR (Status);\r
   }\r
 \r
+  FullPath = NULL;\r
   if (CachedDevicePath != NULL) {\r
     TempNewDevicePath = CachedDevicePath;\r
     NeedAdjust = FALSE;\r
@@ -851,10 +891,20 @@ BmExpandPartitionDevicePath (
         Status = EfiBootManagerConnectDevicePath (Instance, NULL);\r
         if (!EFI_ERROR (Status)) {\r
           TempDevicePath = AppendDevicePath (Instance, NextDevicePathNode (FilePath));\r
-          FileBuffer = EfiBootManagerGetLoadOptionBuffer (TempDevicePath, FullPath, FileSize);\r
+          //\r
+          // TempDevicePath = ACPI()/PCI()/ATA()/Partition()\r
+          // or             = ACPI()/PCI()/ATA()/Partition()/.../A.EFI\r
+          //\r
+          // When TempDevicePath = ACPI()/PCI()/ATA()/Partition(),\r
+          // it may expand to two potienal full paths (nested partition, rarely happen):\r
+          //   1. ACPI()/PCI()/ATA()/Partition()/Partition(A1)/EFI/BootX64.EFI\r
+          //   2. ACPI()/PCI()/ATA()/Partition()/Partition(A2)/EFI/BootX64.EFI\r
+          // For simplicity, only #1 is returned.\r
+          //\r
+          FullPath = BmGetNextLoadOptionDevicePath (TempDevicePath, NULL);\r
           FreePool (TempDevicePath);\r
 \r
-          if (FileBuffer != NULL) {\r
+          if (FullPath != NULL) {\r
             //\r
             // Adjust the 'HDDP' instances sequence if the matched one is not first one.\r
             //\r
@@ -875,7 +925,7 @@ BmExpandPartitionDevicePath (
 \r
             FreePool (Instance);\r
             FreePool (CachedDevicePath);\r
-            return FileBuffer;\r
+            return FullPath;\r
           }\r
         }\r
       }\r
@@ -911,10 +961,10 @@ BmExpandPartitionDevicePath (
       // Find the matched partition device path\r
       //\r
       TempDevicePath = AppendDevicePath (BlockIoDevicePath, NextDevicePathNode (FilePath));\r
-      FileBuffer = EfiBootManagerGetLoadOptionBuffer (TempDevicePath, FullPath, FileSize);\r
+      FullPath = BmGetNextLoadOptionDevicePath (TempDevicePath, NULL);\r
       FreePool (TempDevicePath);\r
 \r
-      if (FileBuffer != NULL) {\r
+      if (FullPath != NULL) {\r
         BmCachePartitionDevicePath (&CachedDevicePath, BlockIoDevicePath);\r
 \r
         //\r
@@ -940,7 +990,7 @@ BmExpandPartitionDevicePath (
   if (BlockIoBuffer != NULL) {\r
     FreePool (BlockIoBuffer);\r
   }\r
-  return FileBuffer;\r
+  return FullPath;\r
 }\r
 \r
 /**\r
@@ -948,16 +998,16 @@ BmExpandPartitionDevicePath (
   by appending EFI_REMOVABLE_MEDIA_FILE_NAME.\r
 \r
   @param DevicePath  The media device path pointing to a BlockIo or SimpleFileSystem instance.\r
-  @param FullPath    Return the full device path pointing to the load option.\r
-  @param FileSize    Return the size of the load option.\r
+  @param FullPath    The full path returned by the routine in last call.\r
+                     Set to NULL in first call.\r
 \r
-  @return  The load option buffer.\r
+  @return The next possible full path pointing to the load option.\r
+          Caller is responsible to free the memory.\r
 **/\r
-VOID *\r
+EFI_DEVICE_PATH_PROTOCOL *\r
 BmExpandMediaDevicePath (\r
   IN  EFI_DEVICE_PATH_PROTOCOL        *DevicePath,\r
-  OUT EFI_DEVICE_PATH_PROTOCOL        **FullPath,\r
-  OUT UINTN                           *FileSize\r
+  IN  EFI_DEVICE_PATH_PROTOCOL        *FullPath\r
   )\r
 {\r
   EFI_STATUS                          Status;\r
@@ -965,14 +1015,15 @@ BmExpandMediaDevicePath (
   EFI_BLOCK_IO_PROTOCOL               *BlockIo;\r
   VOID                                *Buffer;\r
   EFI_DEVICE_PATH_PROTOCOL            *TempDevicePath;\r
+  EFI_DEVICE_PATH_PROTOCOL            *NextFullPath;\r
   UINTN                               Size;\r
   UINTN                               TempSize;\r
   EFI_HANDLE                          *SimpleFileSystemHandles;\r
   UINTN                               NumberSimpleFileSystemHandles;\r
   UINTN                               Index;\r
-  VOID                                *FileBuffer;\r
-  UINT32                              AuthenticationStatus;\r
+  BOOLEAN                             GetNext;\r
 \r
+  GetNext = (BOOLEAN)(FullPath == NULL);\r
   //\r
   // Check whether the device is connected\r
   //\r
@@ -981,14 +1032,16 @@ BmExpandMediaDevicePath (
   if (!EFI_ERROR (Status)) {\r
     ASSERT (IsDevicePathEnd (TempDevicePath));\r
 \r
-    TempDevicePath = FileDevicePath (Handle, EFI_REMOVABLE_MEDIA_FILE_NAME);\r
-    FileBuffer = GetFileBufferByFilePath (TRUE, TempDevicePath, FileSize, &AuthenticationStatus);\r
-    if (FileBuffer == NULL) {\r
-      FreePool (TempDevicePath);\r
-      TempDevicePath = NULL;\r
+    NextFullPath = FileDevicePath (Handle, EFI_REMOVABLE_MEDIA_FILE_NAME);\r
+    //\r
+    // For device path pointing to simple file system, it only expands to one full path.\r
+    //\r
+    if (GetNext) {\r
+      return NextFullPath;\r
+    } else {\r
+      FreePool (NextFullPath);\r
+      return NULL;\r
     }\r
-    *FullPath = TempDevicePath;\r
-    return FileBuffer;\r
   }\r
 \r
   Status = gBS->LocateDevicePath (&gEfiBlockIoProtocolGuid, &TempDevicePath, &Handle);\r
@@ -1010,6 +1063,9 @@ BmExpandMediaDevicePath (
   //\r
   Status = gBS->HandleProtocol (Handle, &gEfiBlockIoProtocolGuid, (VOID **) &BlockIo);\r
   ASSERT_EFI_ERROR (Status);\r
+  if (EFI_ERROR (Status)) {\r
+    return NULL;\r
+  }\r
   Buffer = AllocatePool (BlockIo->Media->BlockSize);\r
   if (Buffer != NULL) {\r
     BlockIo->ReadBlocks (\r
@@ -1025,8 +1081,7 @@ BmExpandMediaDevicePath (
   //\r
   // Detect the the default boot file from removable Media\r
   //\r
-  FileBuffer = NULL;\r
-  *FullPath = NULL;\r
+  NextFullPath = NULL;\r
   Size = GetDevicePathSize (DevicePath) - END_DEVICE_PATH_LENGTH;\r
   gBS->LocateHandleBuffer (\r
          ByProtocol,\r
@@ -1045,13 +1100,14 @@ BmExpandMediaDevicePath (
     // Check whether the device path of boot option is part of the SimpleFileSystem handle's device path\r
     //\r
     if ((Size <= TempSize) && (CompareMem (TempDevicePath, DevicePath, Size) == 0)) {\r
-      TempDevicePath = FileDevicePath (SimpleFileSystemHandles[Index], EFI_REMOVABLE_MEDIA_FILE_NAME);\r
-      FileBuffer = GetFileBufferByFilePath (TRUE, TempDevicePath, FileSize, &AuthenticationStatus);\r
-      if (FileBuffer != NULL) {\r
-        *FullPath = TempDevicePath;\r
+      NextFullPath = FileDevicePath (SimpleFileSystemHandles[Index], EFI_REMOVABLE_MEDIA_FILE_NAME);\r
+      if (GetNext) {\r
         break;\r
+      } else {\r
+        GetNext = (BOOLEAN)(CompareMem (NextFullPath, FullPath, GetDevicePathSize (NextFullPath)) == 0);\r
+        FreePool (NextFullPath);\r
+        NextFullPath = NULL;\r
       }\r
-      FreePool (TempDevicePath);\r
     }\r
   }\r
 \r
@@ -1059,7 +1115,7 @@ BmExpandMediaDevicePath (
     FreePool (SimpleFileSystemHandles);\r
   }\r
 \r
-  return FileBuffer;\r
+  return NextFullPath;\r
 }\r
 \r
 /**\r
@@ -1083,6 +1139,14 @@ BmMatchHttpBootDevicePath (
         return FALSE;\r
       }\r
 \r
+      if (DevicePathSubType (Left) == MSG_DNS_DP) {\r
+        Left = NextDevicePathNode (Left);\r
+      }\r
+\r
+      if (DevicePathSubType (Right) == MSG_DNS_DP) {\r
+        Right = NextDevicePathNode (Right);\r
+      }\r
+\r
       if (((DevicePathSubType (Left) != MSG_IPv4_DP) || (DevicePathSubType (Right) != MSG_IPv4_DP)) &&\r
           ((DevicePathSubType (Left) != MSG_IPv6_DP) || (DevicePathSubType (Right) != MSG_IPv6_DP)) &&\r
           ((DevicePathSubType (Left) != MSG_URI_DP)  || (DevicePathSubType (Right) != MSG_URI_DP))\r
@@ -1098,17 +1162,14 @@ BmMatchHttpBootDevicePath (
   Get the file buffer from the file system produced by Load File instance.\r
 \r
   @param LoadFileHandle The handle of LoadFile instance.\r
-  @param FullPath       Return the full device path pointing to the load option.\r
-  @param FileSize       Return the size of the load option.\r
   @param RamDiskHandle  Return the RAM Disk handle.\r
 \r
-  @return  The load option buffer.\r
+  @return The next possible full path pointing to the load option.\r
+          Caller is responsible to free the memory.\r
 **/\r
-VOID *\r
-BmGetFileBufferFromLoadFileSystem (\r
+EFI_DEVICE_PATH_PROTOCOL *\r
+BmExpandNetworkFileSystem (\r
   IN  EFI_HANDLE                      LoadFileHandle,\r
-  OUT EFI_DEVICE_PATH_PROTOCOL        **FullPath,\r
-  OUT UINTN                           *FileSize,\r
   OUT EFI_HANDLE                      *RamDiskHandle\r
   )\r
 {\r
@@ -1138,6 +1199,9 @@ BmGetFileBufferFromLoadFileSystem (
     if (!EFI_ERROR (Status) &&\r
         (Handle == LoadFileHandle) &&\r
         (DevicePathType (Node) == MEDIA_DEVICE_PATH) && (DevicePathSubType (Node) == MEDIA_RAM_DISK_DP)) {\r
+      //\r
+      // Find the BlockIo instance populated from the LoadFile.\r
+      //\r
       Handle = Handles[Index];\r
       break;\r
     }\r
@@ -1154,13 +1218,16 @@ BmGetFileBufferFromLoadFileSystem (
   *RamDiskHandle = Handle;\r
 \r
   if (Handle != NULL) {\r
-    return BmExpandMediaDevicePath (DevicePathFromHandle (Handle), FullPath, FileSize);\r
+    //\r
+    // Re-use BmExpandMediaDevicePath() to get the full device path of load option.\r
+    // But assume only one SimpleFileSystem can be found under the BlockIo.\r
+    //\r
+    return BmExpandMediaDevicePath (DevicePathFromHandle (Handle), NULL);\r
   } else {\r
     return NULL;\r
   }\r
 }\r
 \r
-\r
 /**\r
   Return the RAM Disk device path created by LoadFile.\r
 \r
@@ -1274,27 +1341,21 @@ BmDestroyRamDisk (
 \r
   @param LoadFileHandle The specified Load File instance.\r
   @param FilePath       The file path which will pass to LoadFile().\r
-  @param FullPath       Return the full device path pointing to the load option.\r
-  @param FileSize       Return the size of the load option.\r
 \r
-  @return  The load option buffer or NULL if fails.\r
+  @return  The full device path pointing to the load option buffer.\r
 **/\r
-VOID *\r
-BmGetFileBufferFromLoadFile (\r
+EFI_DEVICE_PATH_PROTOCOL *\r
+BmExpandLoadFile (\r
   IN  EFI_HANDLE                      LoadFileHandle,\r
-  IN  EFI_DEVICE_PATH_PROTOCOL        *FilePath,\r
-  OUT EFI_DEVICE_PATH_PROTOCOL        **FullPath,\r
-  OUT UINTN                           *FileSize\r
+  IN  EFI_DEVICE_PATH_PROTOCOL        *FilePath\r
   )\r
 {\r
   EFI_STATUS                          Status;\r
   EFI_LOAD_FILE_PROTOCOL              *LoadFile;\r
   VOID                                *FileBuffer;\r
-  BOOLEAN                             LoadFileSystem;\r
   EFI_HANDLE                          RamDiskHandle;\r
   UINTN                               BufferSize;\r
-\r
-  *FileSize = 0;\r
+  EFI_DEVICE_PATH_PROTOCOL            *FullPath;\r
 \r
   Status = gBS->OpenProtocol (\r
                   LoadFileHandle,\r
@@ -1313,52 +1374,60 @@ BmGetFileBufferFromLoadFile (
     return NULL;\r
   }\r
 \r
-  LoadFileSystem = (BOOLEAN) (Status == EFI_WARN_FILE_SYSTEM);\r
-  FileBuffer = LoadFileSystem ? AllocateReservedPages (EFI_SIZE_TO_PAGES (BufferSize)) : AllocatePool (BufferSize);\r
+  if (Status == EFI_BUFFER_TOO_SMALL) {\r
+    //\r
+    // The load option buffer is directly returned by LoadFile.\r
+    //\r
+    return DuplicateDevicePath (DevicePathFromHandle (LoadFileHandle));\r
+  }\r
+\r
+  //\r
+  // The load option resides in a RAM disk.\r
+  //\r
+  FileBuffer = AllocateReservedPages (EFI_SIZE_TO_PAGES (BufferSize));\r
   if (FileBuffer == NULL) {\r
     return NULL;\r
   }\r
 \r
   Status = LoadFile->LoadFile (LoadFile, FilePath, TRUE, &BufferSize, FileBuffer);\r
   if (EFI_ERROR (Status)) {\r
-    if (LoadFileSystem) {\r
-      FreePages (FileBuffer, EFI_SIZE_TO_PAGES (BufferSize));\r
-    } else {\r
-      FreePool (FileBuffer);\r
-    }\r
+    FreePages (FileBuffer, EFI_SIZE_TO_PAGES (BufferSize));\r
     return NULL;\r
   }\r
 \r
-  if (LoadFileSystem) {\r
-    FileBuffer = BmGetFileBufferFromLoadFileSystem (LoadFileHandle, FullPath, FileSize, &RamDiskHandle);\r
-    if (FileBuffer == NULL) {\r
-      //\r
-      // If there is no bootable executable in the populated\r
-      //\r
-      BmDestroyRamDisk (DevicePathFromHandle (RamDiskHandle));\r
-    }\r
-  } else {\r
-    *FileSize = BufferSize;\r
-    *FullPath = DuplicateDevicePath (DevicePathFromHandle (LoadFileHandle));\r
+  FullPath = BmExpandNetworkFileSystem (LoadFileHandle, &RamDiskHandle);\r
+  if (FullPath == NULL) {\r
+    //\r
+    // Free the memory occupied by the RAM disk if there is no BlockIo or SimpleFileSystem instance.\r
+    //\r
+    BmDestroyRamDisk (DevicePathFromHandle (RamDiskHandle));\r
   }\r
 \r
-  return FileBuffer;\r
+  return FullPath;\r
 }\r
 \r
 /**\r
-  Get the file buffer from all the Load File instances.\r
+  Return the full device path pointing to the load option.\r
+\r
+  FilePath may:\r
+  1. Exactly matches to a LoadFile instance.\r
+  2. Cannot match to any LoadFile instance. Wide match is required.\r
+  In either case, the routine may return:\r
+  1. A copy of FilePath when FilePath matches to a LoadFile instance and\r
+     the LoadFile returns a load option buffer.\r
+  2. A new device path with IP and URI information updated when wide match\r
+     happens.\r
+  3. A new device path pointing to a load option in RAM disk.\r
+  In either case, only one full device path is returned for a specified\r
+  FilePath.\r
 \r
   @param FilePath    The media device path pointing to a LoadFile instance.\r
-  @param FullPath    Return the full device path pointing to the load option.\r
-  @param FileSize    Return the size of the load option.\r
 \r
   @return  The load option buffer.\r
 **/\r
-VOID *\r
-BmGetFileBufferFromLoadFiles (\r
-  IN  EFI_DEVICE_PATH_PROTOCOL        *FilePath,\r
-  OUT EFI_DEVICE_PATH_PROTOCOL        **FullPath,\r
-  OUT UINTN                           *FileSize\r
+EFI_DEVICE_PATH_PROTOCOL *\r
+BmExpandLoadFiles (\r
+  IN  EFI_DEVICE_PATH_PROTOCOL        *FilePath\r
   )\r
 {\r
   EFI_STATUS                      Status;\r
@@ -1411,7 +1480,7 @@ BmGetFileBufferFromLoadFiles (
     return NULL;\r
   }\r
 \r
-  return BmGetFileBufferFromLoadFile (Handle, FilePath, FullPath, FileSize);\r
+  return BmExpandLoadFile (Handle, FilePath);\r
 }\r
 \r
 /**\r
@@ -1433,20 +1502,38 @@ EfiBootManagerGetLoadOptionBuffer (
   OUT EFI_DEVICE_PATH_PROTOCOL          **FullPath,\r
   OUT UINTN                             *FileSize\r
   )\r
+{\r
+  *FullPath = NULL;\r
+\r
+  EfiBootManagerConnectDevicePath (FilePath, NULL);\r
+  return BmGetNextLoadOptionBuffer (LoadOptionTypeMax, FilePath, FullPath, FileSize);\r
+}\r
+\r
+/**\r
+  Get the next possible full path pointing to the load option.\r
+  The routine doesn't guarantee the returned full path points to an existing\r
+  file, and it also doesn't guarantee the existing file is a valid load option.\r
+  BmGetNextLoadOptionBuffer() guarantees.\r
+\r
+  @param FilePath  The device path pointing to a load option.\r
+                   It could be a short-form device path.\r
+  @param FullPath  The full path returned by the routine in last call.\r
+                   Set to NULL in first call.\r
+\r
+  @return The next possible full path pointing to the load option.\r
+          Caller is responsible to free the memory.\r
+**/\r
+EFI_DEVICE_PATH_PROTOCOL *\r
+BmGetNextLoadOptionDevicePath (\r
+  IN  EFI_DEVICE_PATH_PROTOCOL          *FilePath,\r
+  IN  EFI_DEVICE_PATH_PROTOCOL          *FullPath\r
+  )\r
 {\r
   EFI_HANDLE                      Handle;\r
-  VOID                            *FileBuffer;\r
-  UINT32                          AuthenticationStatus;\r
   EFI_DEVICE_PATH_PROTOCOL        *Node;\r
   EFI_STATUS                      Status;\r
 \r
-  ASSERT ((FilePath != NULL) && (FullPath != NULL) && (FileSize != NULL));\r
-\r
-  EfiBootManagerConnectDevicePath (FilePath, NULL);\r
-\r
-  *FullPath  = NULL;\r
-  *FileSize  = 0;\r
-  FileBuffer = NULL;\r
+  ASSERT (FilePath != NULL);\r
 \r
   //\r
   // Boot from media device by adding a default file name \EFI\BOOT\BOOT{machine type short-name}.EFI\r
@@ -1458,7 +1545,7 @@ EfiBootManagerGetLoadOptionBuffer (
   }\r
 \r
   if (!EFI_ERROR (Status) && IsDevicePathEnd (Node)) {\r
-    return BmExpandMediaDevicePath (FilePath, FullPath, FileSize);\r
+    return BmExpandMediaDevicePath (FilePath, FullPath);\r
   }\r
 \r
   //\r
@@ -1469,66 +1556,84 @@ EfiBootManagerGetLoadOptionBuffer (
     //\r
     // Expand the Harddrive device path\r
     //\r
-    return BmExpandPartitionDevicePath (FilePath, FullPath, FileSize);\r
+    if (FullPath == NULL) {\r
+      return BmExpandPartitionDevicePath (FilePath);\r
+    } else {\r
+      return NULL;\r
+    }\r
   } else if ((DevicePathType (FilePath) == MEDIA_DEVICE_PATH) &&\r
              (DevicePathSubType (FilePath) == MEDIA_FILEPATH_DP)) {\r
     //\r
     // Expand the File-path device path\r
     //\r
-    return BmExpandFileDevicePath (FilePath, FullPath, FileSize);\r
+    return BmExpandFileDevicePath (FilePath, FullPath);\r
   } else if ((DevicePathType (FilePath) == MESSAGING_DEVICE_PATH) &&\r
              (DevicePathSubType (FilePath) == MSG_URI_DP)) {\r
     //\r
     // Expand the URI device path\r
     //\r
-    return BmExpandUriDevicePath (FilePath, FullPath, FileSize);\r
+    return BmExpandUriDevicePath (FilePath, FullPath);\r
   } else {\r
-    for (Node = FilePath; !IsDevicePathEnd (Node); Node = NextDevicePathNode (Node)) {\r
-      if ((DevicePathType (Node) == MESSAGING_DEVICE_PATH) &&\r
-          ((DevicePathSubType (Node) == MSG_USB_CLASS_DP) || (DevicePathSubType (Node) == MSG_USB_WWID_DP))) {\r
-        break;\r
+    Node = FilePath;\r
+    Status = gBS->LocateDevicePath (&gEfiUsbIoProtocolGuid, &Node, &Handle);\r
+    if (EFI_ERROR (Status)) {\r
+      //\r
+      // Only expand the USB WWID/Class device path\r
+      // when FilePath doesn't point to a physical UsbIo controller.\r
+      // Otherwise, infinite recursion will happen.\r
+      //\r
+      for (Node = FilePath; !IsDevicePathEnd (Node); Node = NextDevicePathNode (Node)) {\r
+        if ((DevicePathType (Node) == MESSAGING_DEVICE_PATH) &&\r
+            ((DevicePathSubType (Node) == MSG_USB_CLASS_DP) || (DevicePathSubType (Node) == MSG_USB_WWID_DP))) {\r
+          break;\r
+        }\r
       }\r
-    }\r
 \r
-    if (!IsDevicePathEnd (Node)) {\r
       //\r
       // Expand the USB WWID/Class device path\r
       //\r
-      FileBuffer = BmExpandUsbDevicePath (FilePath, FullPath, FileSize, Node);\r
-      if ((FileBuffer == NULL) && (FilePath == Node)) {\r
-        //\r
-        // Boot Option device path starts with USB Class or USB WWID device path.\r
-        // For Boot Option device path which doesn't begin with the USB Class or\r
-        // USB WWID device path, it's not needed to connect again here.\r
-        //\r
-        BmConnectUsbShortFormDevicePath (FilePath);\r
-        FileBuffer = BmExpandUsbDevicePath (FilePath, FullPath, FileSize, Node);\r
+      if (!IsDevicePathEnd (Node)) {\r
+        if (FilePath == Node) {\r
+          //\r
+          // Boot Option device path starts with USB Class or USB WWID device path.\r
+          // For Boot Option device path which doesn't begin with the USB Class or\r
+          // USB WWID device path, it's not needed to connect again here.\r
+          //\r
+          BmConnectUsbShortFormDevicePath (FilePath);\r
+        }\r
+        return BmExpandUsbDevicePath (FilePath, FullPath, Node);\r
       }\r
-      return FileBuffer;\r
     }\r
   }\r
 \r
   //\r
-  // Get file buffer from FV file path.\r
+  // For the below cases, FilePath only expands to one Full path.\r
+  // So just handle the case when FullPath == NULL.\r
+  //\r
+  if (FullPath != NULL) {\r
+    return NULL;\r
+  }\r
+\r
+  //\r
+  // Load option resides in FV.\r
   //\r
   if (BmIsFvFilePath (FilePath)) {\r
-    return BmGetFileBufferByFvFilePath (FilePath, FullPath, FileSize);\r
+    return BmAdjustFvFilePath (FilePath);\r
   }\r
 \r
   //\r
-  // Get file buffer from simple file system.\r
+  // Load option resides in Simple File System.\r
   //\r
   Node   = FilePath;\r
   Status = gBS->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid, &Node, &Handle);\r
   if (!EFI_ERROR (Status)) {\r
-    FileBuffer = GetFileBufferByFilePath (TRUE, FilePath, FileSize, &AuthenticationStatus);\r
-    if (FileBuffer != NULL) {\r
-      *FullPath = DuplicateDevicePath (FilePath);\r
-    }\r
-    return FileBuffer;\r
+    return DuplicateDevicePath (FilePath);\r
   }\r
 \r
-  return BmGetFileBufferFromLoadFiles (FilePath, FullPath, FileSize);\r
+  //\r
+  // Last chance to try: Load option may be loaded through LoadFile.\r
+  //\r
+  return BmExpandLoadFiles (FilePath);\r
 }\r
 \r
 /**\r
@@ -1559,15 +1664,60 @@ BmIsBootManagerMenuFilePath (
   return FALSE;\r
 }\r
 \r
+/**\r
+  Report status code with EFI_RETURN_STATUS_EXTENDED_DATA about LoadImage() or\r
+  StartImage() failure.\r
+\r
+  @param[in] ErrorCode      An Error Code in the Software Class, DXE Boot\r
+                            Service Driver Subclass. ErrorCode will be used to\r
+                            compose the Value parameter for status code\r
+                            reporting. Must be one of\r
+                            EFI_SW_DXE_BS_EC_BOOT_OPTION_LOAD_ERROR and\r
+                            EFI_SW_DXE_BS_EC_BOOT_OPTION_FAILED.\r
+\r
+  @param[in] FailureStatus  The failure status returned by the boot service\r
+                            that should be reported.\r
+**/\r
+VOID\r
+BmReportLoadFailure (\r
+  IN UINT32     ErrorCode,\r
+  IN EFI_STATUS FailureStatus\r
+  )\r
+{\r
+  EFI_RETURN_STATUS_EXTENDED_DATA ExtendedData;\r
+\r
+  if (!ReportErrorCodeEnabled ()) {\r
+    return;\r
+  }\r
+\r
+  ASSERT (\r
+    (ErrorCode == EFI_SW_DXE_BS_EC_BOOT_OPTION_LOAD_ERROR) ||\r
+    (ErrorCode == EFI_SW_DXE_BS_EC_BOOT_OPTION_FAILED)\r
+    );\r
+\r
+  ZeroMem (&ExtendedData, sizeof (ExtendedData));\r
+  ExtendedData.ReturnStatus = FailureStatus;\r
+\r
+  REPORT_STATUS_CODE_EX (\r
+    (EFI_ERROR_CODE | EFI_ERROR_MINOR),\r
+    (EFI_SOFTWARE_DXE_BS_DRIVER | ErrorCode),\r
+    0,\r
+    NULL,\r
+    NULL,\r
+    &ExtendedData.DataHeader + 1,\r
+    sizeof (ExtendedData) - sizeof (ExtendedData.DataHeader)\r
+    );\r
+}\r
+\r
 /**\r
   Attempt to boot the EFI boot option. This routine sets L"BootCurent" and\r
   also signals the EFI ready to boot event. If the device path for the option\r
-  starts with a BBS device path a legacy boot is attempted via the registered \r
-  gLegacyBoot function. Short form device paths are also supported via this \r
+  starts with a BBS device path a legacy boot is attempted via the registered\r
+  gLegacyBoot function. Short form device paths are also supported via this\r
   rountine. A device path starting with MEDIA_HARDDRIVE_DP, MSG_USB_WWID_DP,\r
   MSG_USB_CLASS_DP gets expaned out to find the first device that matches.\r
-  If the BootOption Device Path fails the removable media boot algorithm \r
-  is attempted (\EFI\BOOTIA32.EFI, \EFI\BOOTX64.EFI,... only one file type \r
+  If the BootOption Device Path fails the removable media boot algorithm\r
+  is attempted (\EFI\BOOTIA32.EFI, \EFI\BOOTX64.EFI,... only one file type\r
   is tried per processor type)\r
 \r
   @param  BootOption    Boot Option to try and boot.\r
@@ -1659,7 +1809,7 @@ EfiBootManagerBoot (
     //\r
     // 4. Repair system through DriverHealth protocol\r
     //\r
-    BmRepairAllControllers ();\r
+    BmRepairAllControllers (0);\r
   }\r
 \r
   PERF_START_EX (gImageHandle, "BdsAttempt", NULL, 0, (UINT32) OptionNumber);\r
@@ -1686,21 +1836,13 @@ EfiBootManagerBoot (
   ImageHandle       = NULL;\r
   RamDiskDevicePath = NULL;\r
   if (DevicePathType (BootOption->FilePath) != BBS_DEVICE_PATH) {\r
-    Status     = EFI_NOT_FOUND;\r
-    FileBuffer = EfiBootManagerGetLoadOptionBuffer (BootOption->FilePath, &FilePath, &FileSize);\r
+    Status   = EFI_NOT_FOUND;\r
+    FilePath = NULL;\r
+    EfiBootManagerConnectDevicePath (BootOption->FilePath, NULL);\r
+    FileBuffer = BmGetNextLoadOptionBuffer (LoadOptionTypeBoot, BootOption->FilePath, &FilePath, &FileSize);\r
     if (FileBuffer != NULL) {\r
       RamDiskDevicePath = BmGetRamDiskDevicePath (FilePath);\r
-    }\r
-    DEBUG_CODE (\r
-      if (FileBuffer != NULL && CompareMem (BootOption->FilePath, FilePath, GetDevicePathSize (FilePath)) != 0) {\r
-        DEBUG ((EFI_D_INFO, "[Bds] DevicePath expand: "));\r
-        BmPrintDp (BootOption->FilePath);\r
-        DEBUG ((EFI_D_INFO, " -> "));\r
-        BmPrintDp (FilePath);\r
-        DEBUG ((EFI_D_INFO, "\n"));\r
-      }\r
-    );\r
-    if (BmIsLoadOptionPeHeaderValid (BootOption->OptionType, FileBuffer, FileSize)) {\r
+\r
       REPORT_STATUS_CODE (EFI_PROGRESS_CODE, PcdGet32 (PcdProgressCodeOsLoaderLoad));\r
       Status = gBS->LoadImage (\r
                       TRUE,\r
@@ -1720,12 +1862,9 @@ EfiBootManagerBoot (
 \r
     if (EFI_ERROR (Status)) {\r
       //\r
-      // Report Status Code to indicate that the failure to load boot option\r
+      // Report Status Code with the failure status 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
+      BmReportLoadFailure (EFI_SW_DXE_BS_EC_BOOT_OPTION_LOAD_ERROR, Status);\r
       BootOption->Status = Status;\r
       //\r
       // Destroy the RAM disk\r
@@ -1753,8 +1892,8 @@ EfiBootManagerBoot (
         //\r
         Status = EfiCreateEventLegacyBootEx(\r
                    TPL_NOTIFY,\r
-                   BmWriteBootToOsPerformanceData,\r
-                   NULL, \r
+                   BmEndOfBdsPerfCode,\r
+                   NULL,\r
                    &LegacyBootEvent\r
                    );\r
         ASSERT_EFI_ERROR (Status);\r
@@ -1768,7 +1907,7 @@ EfiBootManagerBoot (
     PERF_END_EX (gImageHandle, "BdsAttempt", NULL, 0, (UINT32) OptionNumber);\r
     return;\r
   }\r
\r
+\r
   //\r
   // Provide the image with its load options\r
   //\r
@@ -1794,7 +1933,7 @@ EfiBootManagerBoot (
   // Write boot to OS performance data for UEFI boot\r
   //\r
   PERF_CODE (\r
-    BmWriteBootToOsPerformanceData (NULL, NULL);\r
+    BmEndOfBdsPerfCode (NULL, NULL);\r
   );\r
 \r
   REPORT_STATUS_CODE (EFI_PROGRESS_CODE, PcdGet32 (PcdProgressCodeOsLoaderStart));\r
@@ -1804,12 +1943,9 @@ EfiBootManagerBoot (
   BootOption->Status = Status;\r
   if (EFI_ERROR (Status)) {\r
     //\r
-    // Report Status Code to indicate that boot failure\r
+    // Report Status Code with the failure status 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
+    BmReportLoadFailure (EFI_SW_DXE_BS_EC_BOOT_OPTION_FAILED, Status);\r
   }\r
   PERF_END_EX (gImageHandle, "BdsAttempt", NULL, 0, (UINT32) OptionNumber);\r
 \r
@@ -1879,37 +2015,33 @@ BmMatchPartitionDevicePathNode (
   }\r
 \r
   //\r
-  // find the partition device path node\r
+  // Match all the partition device path nodes including the nested partition nodes\r
   //\r
   while (!IsDevicePathEnd (BlockIoDevicePath)) {\r
     if ((DevicePathType (BlockIoDevicePath) == MEDIA_DEVICE_PATH) &&\r
         (DevicePathSubType (BlockIoDevicePath) == MEDIA_HARDDRIVE_DP)\r
         ) {\r
-      break;\r
+      //\r
+      // See if the harddrive device path in blockio matches the orig Hard Drive Node\r
+      //\r
+      Node = (HARDDRIVE_DEVICE_PATH *) BlockIoDevicePath;\r
+\r
+      //\r
+      // Match Signature and PartitionNumber.\r
+      // Unused bytes in Signature are initiaized with zeros.\r
+      //\r
+      if ((Node->PartitionNumber == HardDriveDevicePath->PartitionNumber) &&\r
+          (Node->MBRType == HardDriveDevicePath->MBRType) &&\r
+          (Node->SignatureType == HardDriveDevicePath->SignatureType) &&\r
+          (CompareMem (Node->Signature, HardDriveDevicePath->Signature, sizeof (Node->Signature)) == 0)) {\r
+        return TRUE;\r
+      }\r
     }\r
 \r
     BlockIoDevicePath = NextDevicePathNode (BlockIoDevicePath);\r
   }\r
 \r
-  if (IsDevicePathEnd (BlockIoDevicePath)) {\r
-    return FALSE;\r
-  }\r
-\r
-  //\r
-  // See if the harddrive device path in blockio matches the orig Hard Drive Node\r
-  //\r
-  Node = (HARDDRIVE_DEVICE_PATH *) BlockIoDevicePath;\r
-\r
-  //\r
-  // Match Signature and PartitionNumber.\r
-  // Unused bytes in Signature are initiaized with zeros.\r
-  //\r
-  return (BOOLEAN) (\r
-    (Node->PartitionNumber == HardDriveDevicePath->PartitionNumber) &&\r
-    (Node->MBRType == HardDriveDevicePath->MBRType) &&\r
-    (Node->SignatureType == HardDriveDevicePath->SignatureType) &&\r
-    (CompareMem (Node->Signature, HardDriveDevicePath->Signature, sizeof (Node->Signature)) == 0)\r
-    );\r
+  return FALSE;\r
 }\r
 \r
 /**\r
@@ -1921,7 +2053,7 @@ BmMatchPartitionDevicePathNode (
   3. Non-BlockIo SimpleFileSystem - The boot option points to a device supporting\r
                                     SimpleFileSystem Protocol, but not supporting BlockIo\r
                                     protocol.\r
-  4. LoadFile                     - The boot option points to the media supporting \r
+  4. LoadFile                     - The boot option points to the media supporting\r
                                     LoadFile protocol.\r
   Reference: UEFI Spec chapter 3.3 Boot Option Variables Default Boot Behavior\r
 \r
@@ -2146,7 +2278,7 @@ EfiBootManagerRefreshAllBootOption (
   // Remove invalid EFI boot options from NV\r
   //\r
   for (Index = 0; Index < NvBootOptionCount; Index++) {\r
-    if (((DevicePathType (NvBootOptions[Index].FilePath) != BBS_DEVICE_PATH) || \r
+    if (((DevicePathType (NvBootOptions[Index].FilePath) != BBS_DEVICE_PATH) ||\r
          (DevicePathSubType (NvBootOptions[Index].FilePath) != BBS_BBS_DP)\r
         ) && BmIsAutoCreateBootOption (&NvBootOptions[Index])\r
        ) {\r
@@ -2329,7 +2461,7 @@ EfiBootManagerGetBootManagerMenu (
   UINTN                        BootOptionCount;\r
   EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions;\r
   UINTN                        Index;\r
-  \r
+\r
   BootOptions = EfiBootManagerGetLoadOptions (&BootOptionCount, LoadOptionTypeBoot);\r
 \r
   for (Index = 0; Index < BootOptionCount; Index++) {\r
@@ -2361,3 +2493,26 @@ EfiBootManagerGetBootManagerMenu (
   }\r
 }\r
 \r
+/**\r
+  Get the next possible full path pointing to the load option.\r
+  The routine doesn't guarantee the returned full path points to an existing\r
+  file, and it also doesn't guarantee the existing file is a valid load option.\r
+  BmGetNextLoadOptionBuffer() guarantees.\r
+\r
+  @param FilePath  The device path pointing to a load option.\r
+                   It could be a short-form device path.\r
+  @param FullPath  The full path returned by the routine in last call.\r
+                   Set to NULL in first call.\r
+\r
+  @return The next possible full path pointing to the load option.\r
+          Caller is responsible to free the memory.\r
+**/\r
+EFI_DEVICE_PATH_PROTOCOL *\r
+EFIAPI\r
+EfiBootManagerGetNextLoadOptionDevicePath (\r
+  IN  EFI_DEVICE_PATH_PROTOCOL          *FilePath,\r
+  IN  EFI_DEVICE_PATH_PROTOCOL          *FullPath\r
+  )\r
+{\r
+  return BmGetNextLoadOptionDevicePath(FilePath, FullPath);\r
+}\r