]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Library/UefiBootManagerLib/BmBoot.c
MdeModulePkg/UefiBootManagerLib: Generate boot description for NVME
[mirror_edk2.git] / MdeModulePkg / Library / UefiBootManagerLib / BmBoot.c
index f6c68458abb11f3de8fcd34917167962fdf750d6..8a3a4027eec0139d8203eee14a080eaf95cec3df 100644 (file)
@@ -1,8 +1,8 @@
 /** @file\r
   Library functions which relates with booting.\r
 \r
-Copyright (c) 2011 - 2016, Intel Corporation. All rights reserved.<BR>\r
-(C) Copyright 2015 Hewlett Packard Enterprise Development LP<BR>\r
+Copyright (c) 2011 - 2017, 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
@@ -15,6 +15,8 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 \r
 #include "InternalBm.h"\r
 \r
+EFI_RAM_DISK_PROTOCOL                        *mRamDisk                  = NULL;\r
+\r
 EFI_BOOT_MANAGER_REFRESH_LEGACY_BOOT_OPTION  mBmRefreshLegacyBootOption = NULL;\r
 EFI_BOOT_MANAGER_LEGACY_BOOT                 mBmLegacyBoot              = NULL;\r
 \r
@@ -584,7 +586,7 @@ BmExpandUsbDevicePath (
 \r
   for (Index = 0; (Index < HandleCount) && (FileBuffer == NULL); Index++) {\r
     FullDevicePath = AppendDevicePath (DevicePathFromHandle (Handles[Index]), RemainingDevicePath);\r
-    FileBuffer = BmGetLoadOptionBuffer (FullDevicePath, FullPath, FileSize);\r
+    FileBuffer = EfiBootManagerGetLoadOptionBuffer (FullDevicePath, FullPath, FileSize);\r
     FreePool (FullDevicePath);\r
   }\r
 \r
@@ -688,7 +690,6 @@ BmExpandUriDevicePath (
   UINTN                           Index;\r
   UINTN                           HandleCount;\r
   EFI_HANDLE                      *Handles;\r
-  EFI_LOAD_FILE_PROTOCOL          *LoadFile;\r
   VOID                            *FileBuffer;\r
 \r
   EfiBootManagerConnectAll ();\r
@@ -699,36 +700,10 @@ BmExpandUriDevicePath (
   }\r
 \r
   FileBuffer = NULL;\r
-\r
   for (Index = 0; Index < HandleCount; Index++) {\r
-    Status = gBS->HandleProtocol (Handles[Index], &gEfiLoadFileProtocolGuid, (VOID *) &LoadFile);\r
-    ASSERT_EFI_ERROR (Status);\r
-\r
-    FileBuffer = NULL;\r
-    Status = LoadFile->LoadFile (LoadFile, FilePath, TRUE, FileSize, FileBuffer);\r
-    if (Status == EFI_BUFFER_TOO_SMALL) {\r
-      FileBuffer = AllocatePool (*FileSize);\r
-      if (FileBuffer == NULL) {\r
-        break;\r
-      }\r
-      Status = LoadFile->LoadFile (LoadFile, FilePath, TRUE, FileSize, FileBuffer);\r
-    }\r
-\r
-    if (!EFI_ERROR (Status)) {\r
-      //\r
-      // LoadFile() returns a file buffer mapping to a file system.\r
-      //\r
-      if (Status == EFI_WARN_FILE_SYSTEM) {\r
-        return BmGetFileBufferFromLoadFileFileSystem (Handles[Index], FullPath, FileSize);\r
-      }\r
-\r
-      ASSERT (Status == EFI_SUCCESS);\r
-      *FullPath = DuplicateDevicePath (DevicePathFromHandle (Handles[Index]));\r
-      break;\r
-    }\r
-\r
+    FileBuffer = BmGetFileBufferFromLoadFile (Handles[Index], FilePath, FullPath, FileSize);\r
     if (FileBuffer != NULL) {\r
-      FreePool (FileBuffer);\r
+      break;\r
     }\r
   }\r
 \r
@@ -876,7 +851,7 @@ BmExpandPartitionDevicePath (
         Status = EfiBootManagerConnectDevicePath (Instance, NULL);\r
         if (!EFI_ERROR (Status)) {\r
           TempDevicePath = AppendDevicePath (Instance, NextDevicePathNode (FilePath));\r
-          FileBuffer = BmGetLoadOptionBuffer (TempDevicePath, FullPath, FileSize);\r
+          FileBuffer = EfiBootManagerGetLoadOptionBuffer (TempDevicePath, FullPath, FileSize);\r
           FreePool (TempDevicePath);\r
 \r
           if (FileBuffer != NULL) {\r
@@ -936,7 +911,7 @@ BmExpandPartitionDevicePath (
       // Find the matched partition device path\r
       //\r
       TempDevicePath = AppendDevicePath (BlockIoDevicePath, NextDevicePathNode (FilePath));\r
-      FileBuffer = BmGetLoadOptionBuffer (TempDevicePath, FullPath, FileSize);\r
+      FileBuffer = EfiBootManagerGetLoadOptionBuffer (TempDevicePath, FullPath, FileSize);\r
       FreePool (TempDevicePath);\r
 \r
       if (FileBuffer != NULL) {\r
@@ -1016,9 +991,13 @@ BmExpandMediaDevicePath (
     return FileBuffer;\r
   }\r
 \r
+  Status = gBS->LocateDevicePath (&gEfiBlockIoProtocolGuid, &TempDevicePath, &Handle);\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
   //\r
-  // For device boot option only pointing to the removable device handle, \r
-  // should make sure all its children handles (its child partion or media handles) are created and connected. \r
+  // For device boot option only pointing to the removable device handle,\r
+  // should make sure all its children handles (its child partion or media handles)\r
+  // are created and connected.\r
   //\r
   gBS->ConnectController (Handle, NULL, NULL, TRUE);\r
 \r
@@ -1029,8 +1008,6 @@ BmExpandMediaDevicePath (
   // returned. After the Block IO protocol is reinstalled, subsequent\r
   // Block IO read/write will success.\r
   //\r
-  Status = gBS->LocateDevicePath (&gEfiBlockIoProtocolGuid, &TempDevicePath, &Handle);\r
-  ASSERT_EFI_ERROR (Status);\r
   Status = gBS->HandleProtocol (Handle, &gEfiBlockIoProtocolGuid, (VOID **) &BlockIo);\r
   ASSERT_EFI_ERROR (Status);\r
   Buffer = AllocatePool (BlockIo->Media->BlockSize);\r
@@ -1123,14 +1100,16 @@ BmMatchHttpBootDevicePath (
   @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
 **/\r
 VOID *\r
-BmGetFileBufferFromLoadFileFileSystem (\r
+BmGetFileBufferFromLoadFileSystem (\r
   IN  EFI_HANDLE                      LoadFileHandle,\r
   OUT EFI_DEVICE_PATH_PROTOCOL        **FullPath,\r
-  OUT UINTN                           *FileSize\r
+  OUT UINTN                           *FileSize,\r
+  OUT EFI_HANDLE                      *RamDiskHandle\r
   )\r
 {\r
   EFI_STATUS                      Status;\r
@@ -1168,15 +1147,206 @@ BmGetFileBufferFromLoadFileFileSystem (
     FreePool (Handles);\r
   }\r
 \r
-  if (Index != HandleCount) {\r
+  if (Index == HandleCount) {\r
+    Handle = NULL;\r
+  }\r
+\r
+  *RamDiskHandle = Handle;\r
+\r
+  if (Handle != NULL) {\r
     return BmExpandMediaDevicePath (DevicePathFromHandle (Handle), FullPath, FileSize);\r
   } else {\r
     return NULL;\r
   }\r
 }\r
 \r
+\r
+/**\r
+  Return the RAM Disk device path created by LoadFile.\r
+\r
+  @param FilePath  The source file path.\r
+\r
+  @return Callee-to-free RAM Disk device path\r
+**/\r
+EFI_DEVICE_PATH_PROTOCOL *\r
+BmGetRamDiskDevicePath (\r
+  IN EFI_DEVICE_PATH_PROTOCOL *FilePath\r
+  )\r
+{\r
+  EFI_STATUS                  Status;\r
+  EFI_DEVICE_PATH_PROTOCOL    *RamDiskDevicePath;\r
+  EFI_DEVICE_PATH_PROTOCOL    *Node;\r
+  EFI_HANDLE                  Handle;\r
+\r
+  Node = FilePath;\r
+  Status = gBS->LocateDevicePath (&gEfiLoadFileProtocolGuid, &Node, &Handle);\r
+  if (!EFI_ERROR (Status) &&\r
+      (DevicePathType (Node) == MEDIA_DEVICE_PATH) &&\r
+      (DevicePathSubType (Node) == MEDIA_RAM_DISK_DP)\r
+      ) {\r
+\r
+    //\r
+    // Construct the device path pointing to RAM Disk\r
+    //\r
+    Node = NextDevicePathNode (Node);\r
+    RamDiskDevicePath = DuplicateDevicePath (FilePath);\r
+    ASSERT (RamDiskDevicePath != NULL);\r
+    SetDevicePathEndNode ((VOID *) ((UINTN) RamDiskDevicePath + ((UINTN) Node - (UINTN) FilePath)));\r
+    return RamDiskDevicePath;\r
+  }\r
+\r
+  return NULL;\r
+}\r
+\r
+/**\r
+  Return the buffer and buffer size occupied by the RAM Disk.\r
+\r
+  @param RamDiskDevicePath  RAM Disk device path.\r
+  @param RamDiskSizeInPages Return RAM Disk size in pages.\r
+\r
+  @retval RAM Disk buffer.\r
+**/\r
+VOID *\r
+BmGetRamDiskMemoryInfo (\r
+  IN EFI_DEVICE_PATH_PROTOCOL *RamDiskDevicePath,\r
+  OUT UINTN                   *RamDiskSizeInPages\r
+  )\r
+{\r
+\r
+  EFI_STATUS                  Status;\r
+  EFI_HANDLE                  Handle;\r
+  UINT64                      StartingAddr;\r
+  UINT64                      EndingAddr;\r
+\r
+  ASSERT (RamDiskDevicePath != NULL);\r
+\r
+  *RamDiskSizeInPages = 0;\r
+\r
+  //\r
+  // Get the buffer occupied by RAM Disk.\r
+  //\r
+  Status = gBS->LocateDevicePath (&gEfiLoadFileProtocolGuid, &RamDiskDevicePath, &Handle);\r
+  ASSERT_EFI_ERROR (Status);\r
+  ASSERT ((DevicePathType (RamDiskDevicePath) == MEDIA_DEVICE_PATH) &&\r
+          (DevicePathSubType (RamDiskDevicePath) == MEDIA_RAM_DISK_DP));\r
+  StartingAddr = ReadUnaligned64 ((UINT64 *) ((MEDIA_RAM_DISK_DEVICE_PATH *) RamDiskDevicePath)->StartingAddr);\r
+  EndingAddr   = ReadUnaligned64 ((UINT64 *) ((MEDIA_RAM_DISK_DEVICE_PATH *) RamDiskDevicePath)->EndingAddr);\r
+  *RamDiskSizeInPages = EFI_SIZE_TO_PAGES ((UINTN) (EndingAddr - StartingAddr + 1));\r
+  return (VOID *) (UINTN) StartingAddr;\r
+}\r
+\r
 /**\r
-  Get the file buffer from Load File instance.\r
+  Destroy the RAM Disk.\r
+\r
+  The destroy operation includes to call RamDisk.Unregister to\r
+  unregister the RAM DISK from RAM DISK driver, free the memory\r
+  allocated for the RAM Disk.\r
+\r
+  @param RamDiskDevicePath    RAM Disk device path.\r
+**/\r
+VOID\r
+BmDestroyRamDisk (\r
+  IN EFI_DEVICE_PATH_PROTOCOL *RamDiskDevicePath\r
+  )\r
+{\r
+  EFI_STATUS                  Status;\r
+  VOID                        *RamDiskBuffer;\r
+  UINTN                       RamDiskSizeInPages;\r
+\r
+  ASSERT (RamDiskDevicePath != NULL);\r
+\r
+  RamDiskBuffer = BmGetRamDiskMemoryInfo (RamDiskDevicePath, &RamDiskSizeInPages);\r
+\r
+  //\r
+  // Destroy RAM Disk.\r
+  //\r
+  if (mRamDisk == NULL) {\r
+    Status = gBS->LocateProtocol (&gEfiRamDiskProtocolGuid, NULL, (VOID *) &mRamDisk);\r
+    ASSERT_EFI_ERROR (Status);\r
+  }\r
+  Status = mRamDisk->Unregister (RamDiskDevicePath);\r
+  ASSERT_EFI_ERROR (Status);\r
+  FreePages (RamDiskBuffer, RamDiskSizeInPages);\r
+}\r
+\r
+/**\r
+  Get the file buffer from the specified Load File instance.\r
+\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
+**/\r
+VOID *\r
+BmGetFileBufferFromLoadFile (\r
+  IN  EFI_HANDLE                      LoadFileHandle,\r
+  IN  EFI_DEVICE_PATH_PROTOCOL        *FilePath,\r
+  OUT EFI_DEVICE_PATH_PROTOCOL        **FullPath,\r
+  OUT UINTN                           *FileSize\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
+\r
+  Status = gBS->OpenProtocol (\r
+                  LoadFileHandle,\r
+                  &gEfiLoadFileProtocolGuid,\r
+                  (VOID **) &LoadFile,\r
+                  gImageHandle,\r
+                  NULL,\r
+                  EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+                  );\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  FileBuffer = NULL;\r
+  BufferSize = 0;\r
+  Status = LoadFile->LoadFile (LoadFile, FilePath, TRUE, &BufferSize, FileBuffer);\r
+  if ((Status != EFI_WARN_FILE_SYSTEM) && (Status != EFI_BUFFER_TOO_SMALL)) {\r
+    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 (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
+    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
+  }\r
+\r
+  return FileBuffer;\r
+}\r
+\r
+/**\r
+  Get the file buffer from all the Load File instances.\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
@@ -1185,7 +1355,7 @@ BmGetFileBufferFromLoadFileFileSystem (
   @return  The load option buffer.\r
 **/\r
 VOID *\r
-BmGetFileBufferFromLoadFile (\r
+BmGetFileBufferFromLoadFiles (\r
   IN  EFI_DEVICE_PATH_PROTOCOL        *FilePath,\r
   OUT EFI_DEVICE_PATH_PROTOCOL        **FullPath,\r
   OUT UINTN                           *FileSize\r
@@ -1193,13 +1363,10 @@ BmGetFileBufferFromLoadFile (
 {\r
   EFI_STATUS                      Status;\r
   EFI_HANDLE                      Handle;\r
-  VOID                            *FileBuffer;\r
   EFI_HANDLE                      *Handles;\r
   UINTN                           HandleCount;\r
   UINTN                           Index;\r
   EFI_DEVICE_PATH_PROTOCOL        *Node;\r
-  EFI_LOAD_FILE_PROTOCOL          *LoadFile;\r
-  UINTN                           BufferSize;\r
 \r
   //\r
   // Get file buffer from load file instance.\r
@@ -1244,41 +1411,7 @@ BmGetFileBufferFromLoadFile (
     return NULL;\r
   }\r
 \r
-  Status = gBS->HandleProtocol (Handle, &gEfiLoadFileProtocolGuid, (VOID **) &LoadFile);\r
-  ASSERT_EFI_ERROR (Status);\r
-\r
-  BufferSize = 0;\r
-  FileBuffer = NULL;\r
-  Status = LoadFile->LoadFile (LoadFile, FilePath, TRUE, &BufferSize, FileBuffer);\r
-  if (Status == EFI_BUFFER_TOO_SMALL) {\r
-    FileBuffer = AllocatePool (BufferSize);\r
-    if (FileBuffer != NULL) {\r
-      Status = EFI_SUCCESS;\r
-    }\r
-  }\r
-\r
-  if (!EFI_ERROR (Status)) {\r
-    Status = LoadFile->LoadFile (LoadFile, FilePath, TRUE, &BufferSize, FileBuffer);\r
-  }\r
-\r
-  if (!EFI_ERROR (Status)) {\r
-    //\r
-    // LoadFile() returns a file buffer mapping to a file system.\r
-    //\r
-    if (Status == EFI_WARN_FILE_SYSTEM) {\r
-      return BmGetFileBufferFromLoadFileFileSystem (Handle, FullPath, FileSize);\r
-    }\r
-\r
-    ASSERT (Status == EFI_SUCCESS);\r
-    //\r
-    // LoadFile () may cause the device path of the Handle be updated.\r
-    //\r
-    *FullPath = DuplicateDevicePath (DevicePathFromHandle (Handle));\r
-    *FileSize = BufferSize;\r
-    return FileBuffer;\r
-  } else {\r
-    return NULL;\r
-  }\r
+  return BmGetFileBufferFromLoadFile (Handle, FilePath, FullPath, FileSize);\r
 }\r
 \r
 /**\r
@@ -1294,7 +1427,8 @@ BmGetFileBufferFromLoadFile (
   @return The load option buffer. Caller is responsible to free the memory.\r
 **/\r
 VOID *\r
-BmGetLoadOptionBuffer (\r
+EFIAPI\r
+EfiBootManagerGetLoadOptionBuffer (\r
   IN  EFI_DEVICE_PATH_PROTOCOL          *FilePath,\r
   OUT EFI_DEVICE_PATH_PROTOCOL          **FullPath,\r
   OUT UINTN                             *FileSize\r
@@ -1394,7 +1528,35 @@ BmGetLoadOptionBuffer (
     return FileBuffer;\r
   }\r
 \r
-  return BmGetFileBufferFromLoadFile (FilePath, FullPath, FileSize);\r
+  return BmGetFileBufferFromLoadFiles (FilePath, FullPath, FileSize);\r
+}\r
+\r
+/**\r
+  Check if it's a Device Path pointing to BootManagerMenu.\r
+\r
+  @param  DevicePath     Input device path.\r
+\r
+  @retval TRUE   The device path is BootManagerMenu File Device Path.\r
+  @retval FALSE  The device path is NOT BootManagerMenu File Device Path.\r
+**/\r
+BOOLEAN\r
+BmIsBootManagerMenuFilePath (\r
+  EFI_DEVICE_PATH_PROTOCOL     *DevicePath\r
+)\r
+{\r
+  EFI_HANDLE                      FvHandle;\r
+  VOID                            *NameGuid;\r
+  EFI_STATUS                      Status;\r
+\r
+  Status = gBS->LocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid, &DevicePath, &FvHandle);\r
+  if (!EFI_ERROR (Status)) {\r
+    NameGuid = EfiGetNameGuidFromFwVolDevicePathNode ((CONST MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *) DevicePath);\r
+    if (NameGuid != NULL) {\r
+      return CompareGuid (NameGuid, PcdGetPtr (PcdBootManagerMenuFile));\r
+    }\r
+  }\r
+\r
+  return FALSE;\r
 }\r
 \r
 /**\r
@@ -1430,8 +1592,7 @@ EfiBootManagerBoot (
   UINTN                     OptionNumber;\r
   UINTN                     OriginalOptionNumber;\r
   EFI_DEVICE_PATH_PROTOCOL  *FilePath;\r
-  EFI_DEVICE_PATH_PROTOCOL  *Node;\r
-  EFI_HANDLE                FvHandle;\r
+  EFI_DEVICE_PATH_PROTOCOL  *RamDiskDevicePath;\r
   VOID                      *FileBuffer;\r
   UINTN                     FileSize;\r
   EFI_BOOT_LOGO_PROTOCOL    *BootLogo;\r
@@ -1486,12 +1647,7 @@ EfiBootManagerBoot (
   // 3. Signal the EVT_SIGNAL_READY_TO_BOOT event when we are about to load and execute\r
   //    the boot option.\r
   //\r
-  Node   = BootOption->FilePath;\r
-  Status = gBS->LocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid, &Node, &FvHandle);\r
-  if (!EFI_ERROR (Status) && CompareGuid (\r
-        EfiGetNameGuidFromFwVolDevicePathNode ((CONST MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *) Node),\r
-        PcdGetPtr (PcdBootManagerMenuFile)\r
-        )) {\r
+  if (BmIsBootManagerMenuFilePath (BootOption->FilePath)) {\r
     DEBUG ((EFI_D_INFO, "[Bds] Booting Boot Manager Menu.\n"));\r
     BmStopHotkeyService (NULL, NULL);\r
   } else {\r
@@ -1509,12 +1665,32 @@ EfiBootManagerBoot (
   PERF_START_EX (gImageHandle, "BdsAttempt", NULL, 0, (UINT32) OptionNumber);\r
 \r
   //\r
-  // 5. Load EFI boot option to ImageHandle\r
+  // 5. 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
+  BmSetMemoryTypeInformationVariable (\r
+    (BOOLEAN) ((BootOption->Attributes & LOAD_OPTION_CATEGORY) == LOAD_OPTION_CATEGORY_BOOT)\r
+  );\r
+\r
   //\r
-  ImageHandle = NULL;\r
+  // 6. Load EFI boot option to ImageHandle\r
+  //\r
+  DEBUG_CODE_BEGIN ();\r
+  if (BootOption->Description == NULL) {\r
+    DEBUG ((DEBUG_INFO | DEBUG_LOAD, "[Bds]Booting from unknown device path\n"));\r
+  } else {\r
+    DEBUG ((DEBUG_INFO | DEBUG_LOAD, "[Bds]Booting %s\n", BootOption->Description));\r
+  }\r
+  DEBUG_CODE_END ();\r
+\r
+  ImageHandle       = NULL;\r
+  RamDiskDevicePath = NULL;\r
   if (DevicePathType (BootOption->FilePath) != BBS_DEVICE_PATH) {\r
     Status     = EFI_NOT_FOUND;\r
-    FileBuffer = BmGetLoadOptionBuffer (BootOption->FilePath, &FilePath, &FileSize);\r
+    FileBuffer = EfiBootManagerGetLoadOptionBuffer (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
@@ -1551,26 +1727,17 @@ EfiBootManagerBoot (
         (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_DXE_BS_EC_BOOT_OPTION_LOAD_ERROR)\r
         );\r
       BootOption->Status = Status;\r
+      //\r
+      // Destroy the RAM disk\r
+      //\r
+      if (RamDiskDevicePath != NULL) {\r
+        BmDestroyRamDisk (RamDiskDevicePath);\r
+        FreePool (RamDiskDevicePath);\r
+      }\r
       return;\r
     }\r
   }\r
 \r
-  //\r
-  // 6. 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
-  BmSetMemoryTypeInformationVariable (\r
-    (BOOLEAN) ((BootOption->Attributes & LOAD_OPTION_CATEGORY) == LOAD_OPTION_CATEGORY_BOOT)\r
-    );\r
-\r
-  DEBUG_CODE_BEGIN();\r
-    if (BootOption->Description == NULL) {\r
-      DEBUG ((DEBUG_INFO | DEBUG_LOAD, "[Bds]Booting from unknown device path\n"));\r
-    } else {\r
-      DEBUG ((DEBUG_INFO | DEBUG_LOAD, "[Bds]Booting %s\n", BootOption->Description));\r
-    }\r
-  DEBUG_CODE_END();\r
-\r
   //\r
   // Check to see if we should legacy BOOT. If yes then do the legacy boot\r
   // Write boot to OS performance data for Legacy boot\r
@@ -1646,6 +1813,14 @@ EfiBootManagerBoot (
   }\r
   PERF_END_EX (gImageHandle, "BdsAttempt", NULL, 0, (UINT32) OptionNumber);\r
 \r
+  //\r
+  // Destroy the RAM disk\r
+  //\r
+  if (RamDiskDevicePath != NULL) {\r
+    BmDestroyRamDisk (RamDiskDevicePath);\r
+    FreePool (RamDiskDevicePath);\r
+  }\r
+\r
   //\r
   // Clear the Watchdog Timer after the image returns\r
   //\r
@@ -1886,7 +2061,7 @@ BmEnumerateBootOptions (
   }\r
 \r
   //\r
-  // Parse load file, assuming UEFI Network boot option\r
+  // Parse load file protocol\r
   //\r
   gBS->LocateHandleBuffer (\r
          ByProtocol,\r
@@ -1896,6 +2071,12 @@ BmEnumerateBootOptions (
          &Handles\r
          );\r
   for (Index = 0; Index < HandleCount; Index++) {\r
+    //\r
+    // Ignore BootManagerMenu. its boot option will be created by EfiBootManagerGetBootManagerMenu().\r
+    //\r
+    if (BmIsBootManagerMenuFilePath (DevicePathFromHandle (Handles[Index]))) {\r
+      continue;\r
+    }\r
 \r
     Description = BmGetBootDescription (Handles[Index]);\r
     BootOptions = ReallocatePool (\r
@@ -1973,7 +2154,7 @@ EfiBootManagerRefreshAllBootOption (
       // Only check those added by BDS\r
       // so that the boot options added by end-user or OS installer won't be deleted\r
       //\r
-      if (EfiBootManagerFindLoadOption (&NvBootOptions[Index], BootOptions, BootOptionCount) == (UINTN) -1) {\r
+      if (EfiBootManagerFindLoadOption (&NvBootOptions[Index], BootOptions, BootOptionCount) == -1) {\r
         Status = EfiBootManagerDeleteLoadOptionVariable (NvBootOptions[Index].OptionNumber, LoadOptionTypeBoot);\r
         //\r
         // Deleting variable with current variable implementation shouldn't fail.\r
@@ -1987,7 +2168,7 @@ EfiBootManagerRefreshAllBootOption (
   // Add new EFI boot options to NV\r
   //\r
   for (Index = 0; Index < BootOptionCount; Index++) {\r
-    if (EfiBootManagerFindLoadOption (&BootOptions[Index], NvBootOptions, NvBootOptionCount) == (UINTN) -1) {\r
+    if (EfiBootManagerFindLoadOption (&BootOptions[Index], NvBootOptions, NvBootOptionCount) == -1) {\r
       EfiBootManagerAddLoadOptionVariable (&BootOptions[Index], (UINTN) -1);\r
       //\r
       // Try best to add the boot options so continue upon failure.\r
@@ -2000,7 +2181,7 @@ EfiBootManagerRefreshAllBootOption (
 }\r
 \r
 /**\r
-  This function is called to create the boot option for the Boot Manager Menu.\r
+  This function is called to get or create the boot option for the Boot Manager Menu.\r
 \r
   The Boot Manager Menu is shown after successfully booting a boot option.\r
   Assume the BootManagerMenuFile is in the same FV as the module links to this library.\r
@@ -2008,8 +2189,10 @@ EfiBootManagerRefreshAllBootOption (
   @param  BootOption    Return the boot option of the Boot Manager Menu\r
 \r
   @retval EFI_SUCCESS   Successfully register the Boot Manager Menu.\r
-  @retval Status        Return status of gRT->SetVariable (). BootOption still points\r
-                        to the Boot Manager Menu even the Status is not EFI_SUCCESS.\r
+  @retval EFI_NOT_FOUND The Boot Manager Menu cannot be found.\r
+  @retval others        Return status of gRT->SetVariable (). BootOption still points\r
+                        to the Boot Manager Menu even the Status is not EFI_SUCCESS\r
+                        and EFI_NOT_FOUND.\r
 **/\r
 EFI_STATUS\r
 BmRegisterBootManagerMenu (\r
@@ -2022,30 +2205,79 @@ BmRegisterBootManagerMenu (
   EFI_DEVICE_PATH_PROTOCOL           *DevicePath;\r
   EFI_LOADED_IMAGE_PROTOCOL          *LoadedImage;\r
   MEDIA_FW_VOL_FILEPATH_DEVICE_PATH  FileNode;\r
+  UINTN                              HandleCount;\r
+  EFI_HANDLE                         *Handles;\r
+  UINTN                              Index;\r
+  VOID                               *Data;\r
+  UINTN                              DataSize;\r
 \r
-  Status = GetSectionFromFv (\r
-             PcdGetPtr (PcdBootManagerMenuFile),\r
-             EFI_SECTION_USER_INTERFACE,\r
-             0,\r
-             (VOID **) &Description,\r
-             &DescriptionLength\r
-             );\r
-  if (EFI_ERROR (Status)) {\r
-    Description = NULL;\r
+  DevicePath = NULL;\r
+  Description = NULL;\r
+  //\r
+  // Try to find BootManagerMenu from LoadFile protocol\r
+  //\r
+  gBS->LocateHandleBuffer (\r
+         ByProtocol,\r
+         &gEfiLoadFileProtocolGuid,\r
+         NULL,\r
+         &HandleCount,\r
+         &Handles\r
+         );\r
+  for (Index = 0; Index < HandleCount; Index++) {\r
+    if (BmIsBootManagerMenuFilePath (DevicePathFromHandle (Handles[Index]))) {\r
+      DevicePath  = DuplicateDevicePath (DevicePathFromHandle (Handles[Index]));\r
+      Description = BmGetBootDescription (Handles[Index]);\r
+      break;\r
+    }\r
+  }\r
+  if (HandleCount != 0) {\r
+    FreePool (Handles);\r
   }\r
 \r
-  EfiInitializeFwVolDevicepathNode (&FileNode, PcdGetPtr (PcdBootManagerMenuFile));\r
-  Status = gBS->HandleProtocol (\r
-                  gImageHandle,\r
-                  &gEfiLoadedImageProtocolGuid,\r
-                  (VOID **) &LoadedImage\r
-                  );\r
-  ASSERT_EFI_ERROR (Status);\r
-  DevicePath = AppendDevicePathNode (\r
-                 DevicePathFromHandle (LoadedImage->DeviceHandle),\r
-                 (EFI_DEVICE_PATH_PROTOCOL *) &FileNode\r
-                 );\r
-  ASSERT (DevicePath != NULL);\r
+  if (DevicePath == NULL) {\r
+    Data = NULL;\r
+    Status = GetSectionFromFv (\r
+               PcdGetPtr (PcdBootManagerMenuFile),\r
+               EFI_SECTION_PE32,\r
+               0,\r
+               (VOID **) &Data,\r
+               &DataSize\r
+               );\r
+    if (Data != NULL) {\r
+      FreePool (Data);\r
+    }\r
+    if (EFI_ERROR (Status)) {\r
+      DEBUG ((EFI_D_WARN, "[Bds]BootManagerMenu FFS section can not be found, skip its boot option registration\n"));\r
+      return EFI_NOT_FOUND;\r
+    }\r
+\r
+    //\r
+    // Get BootManagerMenu application's description from EFI User Interface Section.\r
+    //\r
+    Status = GetSectionFromFv (\r
+               PcdGetPtr (PcdBootManagerMenuFile),\r
+               EFI_SECTION_USER_INTERFACE,\r
+               0,\r
+               (VOID **) &Description,\r
+               &DescriptionLength\r
+               );\r
+    if (EFI_ERROR (Status)) {\r
+      Description = NULL;\r
+    }\r
+\r
+    EfiInitializeFwVolDevicepathNode (&FileNode, PcdGetPtr (PcdBootManagerMenuFile));\r
+    Status = gBS->HandleProtocol (\r
+                    gImageHandle,\r
+                    &gEfiLoadedImageProtocolGuid,\r
+                    (VOID **) &LoadedImage\r
+                    );\r
+    ASSERT_EFI_ERROR (Status);\r
+    DevicePath = AppendDevicePathNode (\r
+                   DevicePathFromHandle (LoadedImage->DeviceHandle),\r
+                   (EFI_DEVICE_PATH_PROTOCOL *) &FileNode\r
+                   );\r
+    ASSERT (DevicePath != NULL);\r
+  }\r
 \r
   Status = EfiBootManagerInitializeLoadOption (\r
              BootOption,\r
@@ -2078,12 +2310,14 @@ BmRegisterBootManagerMenu (
 /**\r
   Return the boot option corresponding to the Boot Manager Menu.\r
   It may automatically create one if the boot option hasn't been created yet.\r
-  \r
+\r
   @param BootOption    Return the Boot Manager Menu.\r
 \r
   @retval EFI_SUCCESS   The Boot Manager Menu is successfully returned.\r
-  @retval Status        Return status of gRT->SetVariable (). BootOption still points\r
-                        to the Boot Manager Menu even the Status is not EFI_SUCCESS.\r
+  @retval EFI_NOT_FOUND The Boot Manager Menu cannot be found.\r
+  @retval others        Return status of gRT->SetVariable (). BootOption still points\r
+                        to the Boot Manager Menu even the Status is not EFI_SUCCESS\r
+                        and EFI_NOT_FOUND.\r
 **/\r
 EFI_STATUS\r
 EFIAPI\r
@@ -2095,20 +2329,11 @@ EfiBootManagerGetBootManagerMenu (
   UINTN                        BootOptionCount;\r
   EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions;\r
   UINTN                        Index;\r
-  EFI_DEVICE_PATH_PROTOCOL     *Node;\r
-  EFI_HANDLE                   FvHandle;\r
   \r
   BootOptions = EfiBootManagerGetLoadOptions (&BootOptionCount, LoadOptionTypeBoot);\r
 \r
   for (Index = 0; Index < BootOptionCount; Index++) {\r
-    Node   = BootOptions[Index].FilePath;\r
-    Status = gBS->LocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid, &Node, &FvHandle);\r
-    if (!EFI_ERROR (Status)) {\r
-      if (CompareGuid (\r
-            EfiGetNameGuidFromFwVolDevicePathNode ((CONST MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *) Node),\r
-            PcdGetPtr (PcdBootManagerMenuFile)\r
-            )\r
-          ) {        \r
+    if (BmIsBootManagerMenuFilePath (BootOptions[Index].FilePath)) {\r
         Status = EfiBootManagerInitializeLoadOption (\r
                    BootOption,\r
                    BootOptions[Index].OptionNumber,\r
@@ -2121,7 +2346,6 @@ EfiBootManagerGetBootManagerMenu (
                    );\r
         ASSERT_EFI_ERROR (Status);\r
         break;\r
-      }\r
     }\r
   }\r
 \r