Revision: 17403
          http://sourceforge.net/p/edk2/code/17403
Author:   niruiyu
Date:     2015-05-11 06:33:45 +0000 (Mon, 11 May 2015)
Log Message:
-----------
MdeModulePkg: Process Sys Prep load options in BdsDxe driver.

Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Ruiyu Ni <[email protected]>
Reviewed-by: Eric Dong <[email protected]>

Modified Paths:
--------------
    trunk/edk2/MdeModulePkg/Include/Library/UefiBootManagerLib.h
    trunk/edk2/MdeModulePkg/Library/UefiBootManagerLib/BmBoot.c
    trunk/edk2/MdeModulePkg/Library/UefiBootManagerLib/BmConnect.c
    trunk/edk2/MdeModulePkg/Library/UefiBootManagerLib/BmConsole.c
    trunk/edk2/MdeModulePkg/Library/UefiBootManagerLib/BmLoadOption.c
    trunk/edk2/MdeModulePkg/Library/UefiBootManagerLib/BmMisc.c
    trunk/edk2/MdeModulePkg/Library/UefiBootManagerLib/InternalBm.h
    trunk/edk2/MdeModulePkg/Universal/BdsDxe/BdsEntry.c

Modified: trunk/edk2/MdeModulePkg/Include/Library/UefiBootManagerLib.h
===================================================================
--- trunk/edk2/MdeModulePkg/Include/Library/UefiBootManagerLib.h        
2015-05-11 06:32:51 UTC (rev 17402)
+++ trunk/edk2/MdeModulePkg/Include/Library/UefiBootManagerLib.h        
2015-05-11 06:33:45 UTC (rev 17403)
@@ -27,8 +27,9 @@
 // Load Option Type
 //
 typedef enum {
+  LoadOptionTypeDriver,
+  LoadOptionTypeSysPrep,
   LoadOptionTypeBoot,
-  LoadOptionTypeDriver,
   LoadOptionTypeMax
 } EFI_BOOT_MANAGER_LOAD_OPTION_TYPE;
 
@@ -51,6 +52,7 @@
   EFI_DEVICE_PATH_PROTOCOL          *FilePath;          // Load Option Device 
Path
   UINT8                             *OptionalData;      // Load Option 
optional data to pass into image
   UINT32                            OptionalDataSize;   // Load Option size of 
OptionalData
+  EFI_GUID                          VendorGuid;
 
   //
   // Used at runtime
@@ -172,11 +174,11 @@
   );
 
 /**
-  This function will update the Boot####/Driver#### and the 
BootOrder/DriverOrder
-  to add a new load option.
+  This function will update the Boot####/Driver####/SysPrep#### and the 
+  BootOrder/DriverOrder/SysPrepOrder to add a new load option.
 
   @param  Option        Pointer to load option to add.
-  @param  Position      Position of the new load option to put in the 
BootOrder/DriverOrder.
+  @param  Position      Position of the new load option to put in the 
BootOrder/DriverOrder/SysPrepOrder.
 
   @retval EFI_SUCCESS   The load option has been successfully added.
   @retval Others        Error status returned by RT->SetVariable.
@@ -458,17 +460,20 @@
 /**
   This function will create all handles associate with every device
   path node. If the handle associate with one device path node can not
-  be created successfully, then still give one chance to do the dispatch,
+  be created successfully, then still give chance to do the dispatch,
   which load the missing drivers if possible.
 
-  @param  DevicePathToConnect   The device path which will be connected, it 
CANNOT be
+  @param  DevicePathToConnect   The device path which will be connected, it 
can be
                                 a multi-instance device path
   @param  MatchingHandle        Return the controller handle closest to the 
DevicePathToConnect
 
-  @retval EFI_INVALID_PARAMETER DevicePathToConnect is NULL.
-  @retval EFI_NOT_FOUND         Failed to create all handles associate with 
every device path node.
-  @retval EFI_SUCCESS           Successful to create all handles associate 
with every device path node.
-
+  @retval EFI_SUCCESS            All handles associate with every device path 
node
+                                 have been created.
+  @retval EFI_OUT_OF_RESOURCES   There is no resource to create new handles.
+  @retval EFI_NOT_FOUND          Create the handle associate with one device 
path
+                                 node failed.
+  @retval EFI_SECURITY_VIOLATION The user has no permission to start UEFI 
device 
+                                 drivers on the DevicePath.
 **/
 EFI_STATUS
 EFIAPI
@@ -508,8 +513,12 @@
 /**
   This function will connect all the console devices base on the console
   device variable ConIn, ConOut and ErrOut.
+
+  @retval EFI_DEVICE_ERROR         All the consoles were not connected due to 
an error.
+  @retval EFI_SUCCESS              Success connect any one instance of the 
console
+                                   device path base on the variable ConVarName.
 **/
-VOID
+EFI_STATUS
 EFIAPI
 EfiBootManagerConnectAllDefaultConsoles (
   VOID
@@ -654,4 +663,19 @@
   UINTN                                Count
   );
 
+/**
+  Process (load and execute) the load option.
+
+  @param LoadOption  Pointer to the load option.
+
+  @retval EFI_INVALID_PARAMETER  The load option type is invalid, 
+                                 or the load option file path doesn't point to 
a valid file.
+  @retval EFI_UNSUPPORTED        The load option type is of LoadOptionTypeBoot.
+  @retval EFI_SUCCESS            The load option is inactive, or successfully 
loaded and executed.
+**/
+EFI_STATUS
+EFIAPI
+EfiBootManagerProcessLoadOption (
+  EFI_BOOT_MANAGER_LOAD_OPTION       *LoadOption
+  );
 #endif

Modified: trunk/edk2/MdeModulePkg/Library/UefiBootManagerLib/BmBoot.c
===================================================================
--- trunk/edk2/MdeModulePkg/Library/UefiBootManagerLib/BmBoot.c 2015-05-11 
06:32:51 UTC (rev 17402)
+++ trunk/edk2/MdeModulePkg/Library/UefiBootManagerLib/BmBoot.c 2015-05-11 
06:33:45 UTC (rev 17403)
@@ -71,7 +71,7 @@
 
 **/
 BM_BOOT_TYPE
-BmBootTypeFromDevicePath (
+BmDevicePathType (
   IN  EFI_DEVICE_PATH_PROTOCOL     *DevicePath
   )
 {
@@ -145,22 +145,6 @@
 }
 
 /**
-  Free old buffer and reuse the pointer to return new buffer.
-
-  @param Orig  Pointer to the old buffer.
-  @param New   Pointer to the new buffer.
-**/
-VOID
-BmFreeAndSet (
-  VOID   **Orig,
-  VOID   *New
-  )
-{
-  FreePool (*Orig);
-  *Orig = New;
-}
-
-/**
   Find the boot option in the NV storage and return the option number.
 
   @param OptionToFind  Boot option to be checked.
@@ -176,7 +160,7 @@
   EFI_STATUS                   Status;
   EFI_BOOT_MANAGER_LOAD_OPTION BootOption;
   UINTN                        OptionNumber;
-  CHAR16                       OptionName[sizeof ("Boot####")];
+  CHAR16                       OptionName[BM_OPTION_NAME_LEN];
   EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions;
   UINTN                        BootOptionCount;
   UINTN                        Index;
@@ -187,7 +171,10 @@
   // Try to match the variable exactly if the option number is assigned
   //
   if (OptionToFind->OptionNumber != LoadOptionNumberUnassigned) {
-    UnicodeSPrint (OptionName, sizeof (OptionName), L"Boot%04x", 
OptionToFind->OptionNumber);
+    UnicodeSPrint (
+      OptionName, sizeof (OptionName), L"%s%04x",
+      mBmLoadOptionName[OptionToFind->OptionType], OptionToFind->OptionNumber
+      );
     Status = EfiBootManagerVariableToLoadOption (OptionName, &BootOption);
 
     if (!EFI_ERROR (Status)) {
@@ -222,56 +209,45 @@
 }
 
 /**
-  According to a file guild, check a Fv file device path is valid. If it is 
invalid,
-  try to return the valid device path.
-  FV address maybe changes for memory layout adjust from time to time, use 
this function
-  could promise the Fv file device path is right.
+  Get the file buffer using a Memory Mapped Device Path.
 
-  @param  DevicePath   The Fv file device path to be fixed up.
+  FV address may change across reboot. This routine promises the FV file 
device path is right.
 
+  @param  DevicePath   The Memory Mapped Device Path to get the file buffer.
+  @param  FullPath     Receive the updated FV Device Path pointint to the file.
+  @param  FileSize     Receive the file buffer size.
+
+  @return  The file buffer.
 **/
-VOID
-BmFixupMemmapFvFilePath (
-  IN OUT EFI_DEVICE_PATH_PROTOCOL      **DevicePath
+VOID *
+BmGetFileBufferByMemmapFv (
+  IN EFI_DEVICE_PATH_PROTOCOL      *DevicePath,
+  OUT EFI_DEVICE_PATH_PROTOCOL     **FullPath,
+  OUT UINTN                        *FileSize
   )
 {
   EFI_STATUS                    Status;
   UINTN                         Index;
-  EFI_DEVICE_PATH_PROTOCOL      *Node;
+  EFI_DEVICE_PATH_PROTOCOL      *FvFileNode;
   EFI_HANDLE                    FvHandle;
-  EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv;
   EFI_LOADED_IMAGE_PROTOCOL     *LoadedImage;
-  UINTN                         Size;
-  EFI_FV_FILETYPE               Type;
-  EFI_FV_FILE_ATTRIBUTES        Attributes;
   UINT32                        AuthenticationStatus;
   UINTN                         FvHandleCount;
-  EFI_HANDLE                    *FvHandleBuffer;
+  EFI_HANDLE                    *FvHandles;
   EFI_DEVICE_PATH_PROTOCOL      *NewDevicePath;
+  VOID                          *FileBuffer;
   
-  Node = *DevicePath;
-  Status = gBS->LocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid, &Node, 
&FvHandle);
+  FvFileNode = DevicePath;
+  Status = gBS->LocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid, 
&FvFileNode, &FvHandle);
   if (!EFI_ERROR (Status)) {
-    Status = gBS->HandleProtocol (FvHandle, &gEfiFirmwareVolume2ProtocolGuid, 
(VOID **) &Fv);
-    ASSERT_EFI_ERROR (Status);
-
-    Status = Fv->ReadFile (
-                   Fv,
-                   EfiGetNameGuidFromFwVolDevicePathNode ((CONST 
MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *) Node),
-                   NULL,
-                   &Size,
-                   &Type,
-                   &Attributes,
-                   &AuthenticationStatus
-                   );
-    if (EFI_ERROR (Status)) {
-      BmFreeAndSet ((VOID **) DevicePath, NULL);
+    FileBuffer = GetFileBufferByFilePath (TRUE, DevicePath, FileSize, 
&AuthenticationStatus);
+    if (FileBuffer != NULL) {
+      *FullPath = DuplicateDevicePath (DevicePath);
     }
-    return;
+    return FileBuffer;
   }
 
-    
-  Node = NextDevicePathNode (DevicePath);
+  FvFileNode = NextDevicePathNode (DevicePath);
 
   //
   // Firstly find the FV file in current FV
@@ -281,12 +257,12 @@
          &gEfiLoadedImageProtocolGuid,
          (VOID **) &LoadedImage
          );
-  NewDevicePath = AppendDevicePathNode (DevicePathFromHandle 
(LoadedImage->DeviceHandle), Node);
-  BmFixupMemmapFvFilePath (&NewDevicePath);
+  NewDevicePath = AppendDevicePathNode (DevicePathFromHandle 
(LoadedImage->DeviceHandle), FvFileNode);
+  FileBuffer = BmGetFileBufferByMemmapFv (NewDevicePath, FullPath, FileSize);
+  FreePool (NewDevicePath);
 
-  if (NewDevicePath != NULL) {
-    BmFreeAndSet ((VOID **) DevicePath, NewDevicePath);
-    return;
+  if (FileBuffer != NULL) {
+    return FileBuffer;
   }
 
   //
@@ -297,34 +273,35 @@
          &gEfiFirmwareVolume2ProtocolGuid,
          NULL,
          &FvHandleCount,
-         &FvHandleBuffer
+         &FvHandles
          );
-  for (Index = 0; Index < FvHandleCount; Index++) {
-    if (FvHandleBuffer[Index] == LoadedImage->DeviceHandle) {
+  for (Index = 0; (Index < FvHandleCount) && (FileBuffer == NULL); Index++) {
+    if (FvHandles[Index] == LoadedImage->DeviceHandle) {
       //
       // Skip current FV
       //
       continue;
     }
-    NewDevicePath = AppendDevicePathNode (DevicePathFromHandle 
(FvHandleBuffer[Index]), Node);
-    BmFixupMemmapFvFilePath (&NewDevicePath);
-
-    if (NewDevicePath != NULL) {
-      BmFreeAndSet ((VOID **) DevicePath, NewDevicePath);
-      return;
-    }
+    NewDevicePath = AppendDevicePathNode (DevicePathFromHandle 
(FvHandles[Index]), FvFileNode);
+    FileBuffer = BmGetFileBufferByMemmapFv (NewDevicePath, FullPath, FileSize);
+    FreePool (NewDevicePath);
   }
+  
+  if (FvHandles != NULL) {
+    FreePool (FvHandles);
+  }
+  return FileBuffer;
 }
 
 /**
-  Check if it's of Fv file device path type.
+  Check if it's a Memory Mapped FV Device Path.
   
-  The function doesn't garentee the device path points to existing Fv file.
+  The function doesn't garentee the device path points to existing FV file.
 
-  @param  DevicePath     Input device path info.
+  @param  DevicePath     Input device path.
 
-  @retval TRUE   The device path is of Fv file device path type.
-  @retval FALSE  The device path isn't of Fv file device path type.
+  @retval TRUE   The device path is a Memory Mapped FV Device Path.
+  @retval FALSE  The device path is NOT a Memory Mapped FV Device Path.
 **/
 BOOLEAN
 BmIsMemmapFvFilePath (
@@ -668,7 +645,7 @@
   CHAR16                         *Description;
   EFI_BLOCK_IO_PROTOCOL          *BlockIo;
 
-  switch (BmBootTypeFromDevicePath (DevicePathFromHandle (Handle))) {
+  switch (BmDevicePathType (DevicePathFromHandle (Handle))) {
   case BmAcpiFloppyBoot:
     Description = L"Floppy";
     break;
@@ -825,26 +802,6 @@
 }
 
 /**
-  Print the device path info.
-
-  @param DevicePath           The device path need to print.
-
-**/
-VOID
-BmPrintDp (
-  EFI_DEVICE_PATH_PROTOCOL            *DevicePath
-  )
-{
-  CHAR16                              *Str;
-
-  Str = ConvertDevicePathToText (DevicePath, FALSE, FALSE);
-  DEBUG ((EFI_D_INFO, "%s", Str));
-  if (Str != NULL) {
-    FreePool (Str);
-  }
-}
-
-/**
   Find a USB device which match the specified short-form device path start 
with 
   USB Class or USB WWID device path. If ParentDevicePath is NULL, this function
   will search in all USB devices of the platform. If ParentDevicePath is not 
NULL,
@@ -944,97 +901,105 @@
      contains a USB Class or USB WWID device path node, and ended with Media
      FilePath device path.
 
-  @param  DevicePath    On input, a pointer to an allocated buffer that 
contains the 
-                        file device path.
-                        On output, a pointer to an reallocated buffer that 
contains 
-                        the expanded device path. It would point to NULL if 
the file
-                        cannot be read.
+  @param FilePath      The device path pointing to a load option.
+                       It could be a short-form device path.
+  @param FullPath      Return the full device path of the load option after
+                       short-form device path expanding.
+                       Caller is responsible to free it.
+  @param FileSize      Return the load option size.
+  @param ShortformNode Pointer to the USB short-form device path node in the 
FilePath buffer.
 
-  @param  FileSize      A pointer to the file size.
-
-  @retval !NULL  The file buffer.
-  @retval NULL   The input device path doesn't point to a valid file.
+  @return The load option buffer. Caller is responsible to free the memory.
 **/
 VOID *
-BmExpandUsbShortFormDevicePath (
-  IN OUT EFI_DEVICE_PATH_PROTOCOL  **DevicePath,
-  OUT UINTN                        *FileSize
+BmExpandUsbDevicePath (
+  IN  EFI_DEVICE_PATH_PROTOCOL  *FilePath,
+  OUT EFI_DEVICE_PATH_PROTOCOL  **FullPath,
+  OUT UINTN                     *FileSize,
+  IN EFI_DEVICE_PATH_PROTOCOL   *ShortformNode
   )
 {
   UINTN                             ParentDevicePathSize;
-  EFI_DEVICE_PATH_PROTOCOL          *ShortformNode;
   EFI_DEVICE_PATH_PROTOCOL          *RemainingDevicePath;
   EFI_DEVICE_PATH_PROTOCOL          *FullDevicePath;
-  EFI_HANDLE                        *UsbIoHandles;
-  UINTN                             UsbIoHandleCount;
+  EFI_HANDLE                        *Handles;
+  UINTN                             HandleCount;
   UINTN                             Index;
   VOID                              *FileBuffer;
-  
-  //
-  // Search for USB Class or USB WWID device path node.
-  //
-  for ( ShortformNode = *DevicePath
-      ; !IsDevicePathEnd (ShortformNode)
-      ; ShortformNode = NextDevicePathNode (ShortformNode)
-      ) {
-    if ((DevicePathType (ShortformNode) == MESSAGING_DEVICE_PATH) &&
-        ((DevicePathSubType (ShortformNode) == MSG_USB_CLASS_DP) ||
-         (DevicePathSubType (ShortformNode) == MSG_USB_WWID_DP))) {
-      break;
-    }
+
+  ParentDevicePathSize = (UINTN) ShortformNode - (UINTN) FilePath;
+  RemainingDevicePath = NextDevicePathNode (ShortformNode);
+  FileBuffer = NULL;
+  Handles = BmFindUsbDevice (FilePath, ParentDevicePathSize, &HandleCount);
+
+  for (Index = 0; (Index < HandleCount) && (FileBuffer == NULL); Index++) {
+    FullDevicePath = AppendDevicePath (DevicePathFromHandle (Handles[Index]), 
RemainingDevicePath);
+    FileBuffer = BmGetLoadOptionBuffer (FullDevicePath, FullPath, FileSize);
+    FreePool (FullDevicePath);
   }
-  ASSERT (!IsDevicePathEnd (ShortformNode));
 
-  FullDevicePath       = NULL;
-  ParentDevicePathSize = (UINTN) ShortformNode - (UINTN) *DevicePath;
-  RemainingDevicePath  = NextDevicePathNode (ShortformNode);
-  FileBuffer           = NULL;
-  UsbIoHandles         = BmFindUsbDevice (*DevicePath, ParentDevicePathSize, 
&UsbIoHandleCount);
+  if (Handles != NULL) {
+    FreePool (Handles);
+  }
 
-  for (Index = 0; Index < UsbIoHandleCount; Index++) {
-    FullDevicePath = AppendDevicePath (DevicePathFromHandle 
(UsbIoHandles[Index]), RemainingDevicePath);
-    DEBUG ((EFI_D_INFO, "[Bds] FullDp1[%d]:", Index)); DEBUG_CODE (BmPrintDp 
(FullDevicePath); ); DEBUG ((EFI_D_INFO, "\n"));
-    FileBuffer = BmLoadEfiBootOption (&FullDevicePath, FileSize);
-    if (FileBuffer != NULL) {
-      DEBUG ((EFI_D_INFO, "-->")); DEBUG_CODE (BmPrintDp (FullDevicePath); ); 
DEBUG ((EFI_D_INFO, FileBuffer != NULL ? " - Found\n" : "\n"));
-      break;
-    }
+  return FileBuffer;
+}
+
+/**
+  Save the partition DevicePath to the CachedDevicePath as the first instance.
+
+  @param CachedDevicePath  The device path cache.
+  @param DevicePath        The partition device path to be cached.
+**/
+VOID
+BmCachePartitionDevicePath (
+  IN OUT EFI_DEVICE_PATH_PROTOCOL **CachedDevicePath,
+  IN EFI_DEVICE_PATH_PROTOCOL     *DevicePath
+  )
+{
+  EFI_DEVICE_PATH_PROTOCOL        *TempDevicePath;
+  UINTN                           Count;
+  
+  if (BmMatchDevicePaths (*CachedDevicePath, DevicePath)) {
+    TempDevicePath = *CachedDevicePath;
+    *CachedDevicePath = BmDelPartMatchInstance (*CachedDevicePath, DevicePath);
+    FreePool (TempDevicePath);
   }
 
-  if (UsbIoHandles != NULL) {
-    FreePool (UsbIoHandles);
+  if (*CachedDevicePath == NULL) {
+    *CachedDevicePath = DuplicateDevicePath (DevicePath);
+    return;
   }
 
-  if (FileBuffer == NULL) {
+  TempDevicePath = *CachedDevicePath;
+  *CachedDevicePath = AppendDevicePathInstance (DevicePath, *CachedDevicePath);
+  if (TempDevicePath != NULL) {
+    FreePool (TempDevicePath);
+  }
+
+  //
+  // Here limit the device path instance number to 12, which is max number for 
a system support 3 IDE controller
+  // If the user try to boot many OS in different HDs or partitions, in 
theory, the 'HDDP' variable maybe become larger and larger.
+  //
+  Count = 0;
+  TempDevicePath = *CachedDevicePath;
+  while (!IsDevicePathEnd (TempDevicePath)) {
+    TempDevicePath = NextDevicePathNode (TempDevicePath);
     //
-    // Boot Option device path starts with USB Class or USB WWID device path.
-    // For Boot Option device path which doesn't begin with the USB Class or
-    // USB WWID device path, it's not needed to connect again here.
+    // Parse one instance
     //
-    if ((DevicePathType (*DevicePath) == MESSAGING_DEVICE_PATH) &&
-        ((DevicePathSubType (*DevicePath) == MSG_USB_CLASS_DP) ||
-         (DevicePathSubType (*DevicePath) == MSG_USB_WWID_DP))) {
-      BmConnectUsbShortFormDevicePath (*DevicePath);
-
-      UsbIoHandles = BmFindUsbDevice (*DevicePath, ParentDevicePathSize, 
&UsbIoHandleCount);
-      for (Index = 0; Index < UsbIoHandleCount; Index++) {
-        FullDevicePath = AppendDevicePath (DevicePathFromHandle 
(UsbIoHandles[Index]), RemainingDevicePath);
-        DEBUG ((EFI_D_INFO, "[Bds] FullDp2[%d]:", Index)); DEBUG_CODE 
(BmPrintDp (FullDevicePath); ); DEBUG ((EFI_D_INFO, "\n"));
-        FileBuffer = BmLoadEfiBootOption (&FullDevicePath, FileSize);
-        if (FileBuffer != NULL) {
-          DEBUG ((EFI_D_INFO, "-->")); DEBUG_CODE (BmPrintDp (FullDevicePath); 
); DEBUG ((EFI_D_INFO, FileBuffer != NULL ? " - Found\n" : "\n"));
-          break;
-        }
-      }
-
-      if (UsbIoHandles != NULL) {
-        FreePool (UsbIoHandles);
-      }
+    while (!IsDevicePathEndType (TempDevicePath)) {
+      TempDevicePath = NextDevicePathNode (TempDevicePath);
     }
+    Count++;
+    //
+    // If the CachedDevicePath variable contain too much instance, only remain 
12 instances.
+    //
+    if (Count == 12) {
+      SetDevicePathEndNode (TempDevicePath);
+      break;
+    }
   }
-
-  BmFreeAndSet ((VOID **) DevicePath, FullDevicePath);
-  return FileBuffer;
 }
 
 /**
@@ -1045,34 +1010,37 @@
   so a connect all is not required on every boot. All successful history 
device path
   which point to partition node (the front part) will be saved.
 
-  @param  DevicePath    On input, a pointer to an allocated buffer that 
contains the 
-                        file device path.
-                        On output, a pointer to an reallocated buffer that 
contains 
-                        the expanded device path. It would point to NULL if 
the file
-                        cannot be read.
+  @param FilePath      The device path pointing to a load option.
+                       It could be a short-form device path.
+  @param FullPath      Return the full device path of the load option after
+                       short-form device path expanding.
+                       Caller is responsible to free it.
+  @param FileSize      Return the load option size.
 
+  @return The load option buffer. Caller is responsible to free the memory.
 **/
-VOID
-BmExpandPartitionShortFormDevicePath (
-  IN OUT EFI_DEVICE_PATH_PROTOCOL      **DevicePath
+VOID *
+BmExpandPartitionDevicePath (
+  IN  EFI_DEVICE_PATH_PROTOCOL  *FilePath,
+  OUT EFI_DEVICE_PATH_PROTOCOL  **FullPath,
+  OUT UINTN                     *FileSize
   )
 {
   EFI_STATUS                Status;
   UINTN                     BlockIoHandleCount;
   EFI_HANDLE                *BlockIoBuffer;
-  EFI_DEVICE_PATH_PROTOCOL  *FullDevicePath;
+  VOID                      *FileBuffer;
   EFI_DEVICE_PATH_PROTOCOL  *BlockIoDevicePath;
   UINTN                     Index;
-  UINTN                     InstanceNum;
   EFI_DEVICE_PATH_PROTOCOL  *CachedDevicePath;
   EFI_DEVICE_PATH_PROTOCOL  *TempNewDevicePath;
+  EFI_DEVICE_PATH_PROTOCOL  *TempDevicePath;
   UINTN                     CachedDevicePathSize;
-  BOOLEAN                   DeviceExist;
   BOOLEAN                   NeedAdjust;
   EFI_DEVICE_PATH_PROTOCOL  *Instance;
   UINTN                     Size;
 
-  FullDevicePath      = NULL;
+  FileBuffer = NULL;
   //
   // Check if there is prestore 'HDDP' variable.
   // If exist, search the front path which point to partition node in the 
variable instants.
@@ -1098,7 +1066,6 @@
 
   if (CachedDevicePath != NULL) {
     TempNewDevicePath = CachedDevicePath;
-    DeviceExist = FALSE;
     NeedAdjust = FALSE;
     do {
       //
@@ -1107,15 +1074,40 @@
       // partial partition boot option. Second, check whether the instance 
could be connected.
       //
       Instance  = GetNextDevicePathInstance (&TempNewDevicePath, &Size);
-      if (BmMatchPartitionDevicePathNode (Instance, (HARDDRIVE_DEVICE_PATH *) 
*DevicePath)) {
+      if (BmMatchPartitionDevicePathNode (Instance, (HARDDRIVE_DEVICE_PATH *) 
FilePath)) {
         //
         // Connect the device path instance, the device path point to hard 
drive media device path node
         // e.g. ACPI() /PCI()/ATA()/Partition()
         //
         Status = EfiBootManagerConnectDevicePath (Instance, NULL);
         if (!EFI_ERROR (Status)) {
-          DeviceExist = TRUE;
-          break;
+          TempDevicePath = AppendDevicePath (Instance, NextDevicePathNode 
(FilePath));
+          FileBuffer = BmGetLoadOptionBuffer (TempDevicePath, FullPath, 
FileSize);
+          FreePool (TempDevicePath);
+
+          if (FileBuffer != NULL) {
+            //
+            // Adjust the 'HDDP' instances sequence if the matched one is not 
first one.
+            //
+            if (NeedAdjust) {
+              BmCachePartitionDevicePath (&CachedDevicePath, Instance);
+              //
+              // Save the matching Device Path so we don't need to do a 
connect all next time
+              // Failing to save only impacts performance next time expanding 
the short-form device path
+              //
+              Status = gRT->SetVariable (
+                L"HDDP",
+                &mBmHardDriveBootVariableGuid,
+                EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE,
+                GetDevicePathSize (CachedDevicePath),
+                CachedDevicePath
+                );
+            }
+
+            FreePool (Instance);
+            FreePool (CachedDevicePath);
+            return FileBuffer;
+          }
         }
       }
       //
@@ -1124,50 +1116,6 @@
       NeedAdjust = TRUE;
       FreePool(Instance);
     } while (TempNewDevicePath != NULL);
-
-    if (DeviceExist) {
-      //
-      // Find the matched device path.
-      // Append the file path information from the boot option and return the 
fully expanded device path.
-      //
-      FullDevicePath = AppendDevicePath (Instance, NextDevicePathNode 
(*DevicePath));
-
-      //
-      // Adjust the 'HDDP' instances sequence if the matched one is not first 
one.
-      //
-      if (NeedAdjust) {
-        //
-        // First delete the matched instance.
-        //
-        TempNewDevicePath = CachedDevicePath;
-        CachedDevicePath  = BmDelPartMatchInstance (CachedDevicePath, 
Instance);
-        FreePool (TempNewDevicePath);
-
-        //
-        // Second, append the remaining path after the matched instance
-        //
-        TempNewDevicePath = CachedDevicePath;
-        CachedDevicePath = AppendDevicePathInstance (Instance, 
CachedDevicePath );
-        FreePool (TempNewDevicePath);
-        //
-        // Save the matching Device Path so we don't need to do a connect all 
next time
-        // Failing to save only impacts performance next time expanding the 
short-form device path
-        //
-        Status = gRT->SetVariable (
-                        L"HDDP",
-                        &mBmHardDriveBootVariableGuid,
-                        EFI_VARIABLE_BOOTSERVICE_ACCESS | 
EFI_VARIABLE_NON_VOLATILE,
-                        GetDevicePathSize (CachedDevicePath),
-                        CachedDevicePath
-                        );
-      }
-
-      FreePool (Instance);
-      FreePool (CachedDevicePath);
-      FreePool (*DevicePath);
-      *DevicePath = FullDevicePath;
-      return;
-    }
   }
 
   //
@@ -1184,80 +1132,36 @@
   // Loop through all the device handles that support the BLOCK_IO Protocol
   //
   for (Index = 0; Index < BlockIoHandleCount; Index++) {
-
-    Status = gBS->HandleProtocol (BlockIoBuffer[Index], 
&gEfiDevicePathProtocolGuid, (VOID *) &BlockIoDevicePath);
-    if (EFI_ERROR (Status) || BlockIoDevicePath == NULL) {
+    BlockIoDevicePath = DevicePathFromHandle (BlockIoBuffer[Index]);
+    if (BlockIoDevicePath == NULL) {
       continue;
     }
 
-    if (BmMatchPartitionDevicePathNode (BlockIoDevicePath, 
(HARDDRIVE_DEVICE_PATH *) *DevicePath)) {
+    if (BmMatchPartitionDevicePathNode (BlockIoDevicePath, 
(HARDDRIVE_DEVICE_PATH *) FilePath)) {
       //
       // Find the matched partition device path
       //
-      FullDevicePath = AppendDevicePath (BlockIoDevicePath, NextDevicePathNode 
(*DevicePath));
+      TempDevicePath = AppendDevicePath (BlockIoDevicePath, NextDevicePathNode 
(FilePath));
+      FileBuffer = BmGetLoadOptionBuffer (TempDevicePath, FullPath, FileSize);
+      FreePool (TempDevicePath);
 
-      //
-      // Save the matched partition device path in 'HDDP' variable
-      //
-      if (CachedDevicePath != NULL) {
+      if (FileBuffer != NULL) {
+        BmCachePartitionDevicePath (&CachedDevicePath, BlockIoDevicePath);
+
         //
-        // Save the matched partition device path as first instance of 'HDDP' 
variable
+        // Save the matching Device Path so we don't need to do a connect all 
next time
+        // Failing to save only impacts performance next time expanding the 
short-form device path
         //
-        if (BmMatchDevicePaths (CachedDevicePath, BlockIoDevicePath)) {
-          TempNewDevicePath = CachedDevicePath;
-          CachedDevicePath = BmDelPartMatchInstance (CachedDevicePath, 
BlockIoDevicePath);
-          FreePool(TempNewDevicePath);
-        }
+        Status = gRT->SetVariable (
+                        L"HDDP",
+                        &mBmHardDriveBootVariableGuid,
+                        EFI_VARIABLE_BOOTSERVICE_ACCESS | 
EFI_VARIABLE_NON_VOLATILE,
+                        GetDevicePathSize (CachedDevicePath),
+                        CachedDevicePath
+                        );
 
-        if (CachedDevicePath != NULL) {
-          TempNewDevicePath = CachedDevicePath;
-          CachedDevicePath = AppendDevicePathInstance (BlockIoDevicePath, 
CachedDevicePath);
-          FreePool(TempNewDevicePath);
-        } else {
-          CachedDevicePath = DuplicateDevicePath (BlockIoDevicePath);
-        }
-
-        //
-        // Here limit the device path instance number to 12, which is max 
number for a system support 3 IDE controller
-        // If the user try to boot many OS in different HDs or partitions, in 
theory, the 'HDDP' variable maybe become larger and larger.
-        //
-        InstanceNum = 0;
-        ASSERT (CachedDevicePath != NULL);
-        TempNewDevicePath = CachedDevicePath;
-        while (!IsDevicePathEnd (TempNewDevicePath)) {
-          TempNewDevicePath = NextDevicePathNode (TempNewDevicePath);
-          //
-          // Parse one instance
-          //
-          while (!IsDevicePathEndType (TempNewDevicePath)) {
-            TempNewDevicePath = NextDevicePathNode (TempNewDevicePath);
-          }
-          InstanceNum++;
-          //
-          // If the CachedDevicePath variable contain too much instance, only 
remain 12 instances.
-          //
-          if (InstanceNum >= 12) {
-            SetDevicePathEndNode (TempNewDevicePath);
-            break;
-          }
-        }
-      } else {
-        CachedDevicePath = DuplicateDevicePath (BlockIoDevicePath);
+        break;
       }
-
-      //
-      // Save the matching Device Path so we don't need to do a connect all 
next time
-      // Failing to save only impacts performance next time expanding the 
short-form device path
-      //
-      Status = gRT->SetVariable (
-                      L"HDDP",
-                      &mBmHardDriveBootVariableGuid,
-                      EFI_VARIABLE_BOOTSERVICE_ACCESS | 
EFI_VARIABLE_NON_VOLATILE,
-                      GetDevicePathSize (CachedDevicePath),
-                      CachedDevicePath
-                      );
-
-      break;
     }
   }
 
@@ -1267,92 +1171,92 @@
   if (BlockIoBuffer != NULL) {
     FreePool (BlockIoBuffer);
   }
-  BmFreeAndSet ((VOID **) DevicePath, FullDevicePath);
+  return FileBuffer;
 }
 
 /**
-  Algorithm follows the UEFI Spec chapter 3.4 Boot Mechanisms.
+  Expand the media device path which points to a BlockIo or SimpleFileSystem 
instance
+  by appending EFI_REMOVABLE_MEDIA_FILE_NAME.
 
-  @param  DevicePath  Device Path to a  bootable device
+  @param DevicePath  The media device path pointing to a BlockIo or 
SimpleFileSystem instance.
+  @param FullPath    Return the full device path pointing to the load option.
+  @param FileSize    Return the size of the load option.
 
-  @return  The bootable media handle. If the media on the DevicePath is not 
bootable, NULL will return.
-
+  @return  The load option buffer.
 **/
-EFI_HANDLE
-BmGetBootableDeviceHandle (
-  IN  EFI_DEVICE_PATH_PROTOCOL        *DevicePath
+VOID *
+BmExpandMediaDevicePath (
+  IN  EFI_DEVICE_PATH_PROTOCOL        *DevicePath,
+  OUT EFI_DEVICE_PATH_PROTOCOL        **FullPath,
+  OUT UINTN                           *FileSize
   )
 {
   EFI_STATUS                          Status;
-  EFI_DEVICE_PATH_PROTOCOL            *UpdatedDevicePath;
   EFI_HANDLE                          Handle;
   EFI_BLOCK_IO_PROTOCOL               *BlockIo;
   VOID                                *Buffer;
   EFI_DEVICE_PATH_PROTOCOL            *TempDevicePath;
   UINTN                               Size;
   UINTN                               TempSize;
-  EFI_HANDLE                          ReturnHandle;
   EFI_HANDLE                          *SimpleFileSystemHandles;
   UINTN                               NumberSimpleFileSystemHandles;
   UINTN                               Index;
-  EFI_IMAGE_DOS_HEADER                DosHeader;
-  EFI_IMAGE_OPTIONAL_HEADER_UNION     HdrData;
-  EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;
+  VOID                                *FileBuffer;
+  UINT32                              AuthenticationStatus;
 
-  ReturnHandle      = NULL;
-  UpdatedDevicePath = DevicePath;
-
   //
   // Check whether the device is connected
   //
-  Status = gBS->LocateDevicePath (&gEfiBlockIoProtocolGuid, 
&UpdatedDevicePath, &Handle);
-  if (EFI_ERROR (Status)) {
-    //
-    // Skip the case that the boot option point to a simple file protocol 
which does not consume block Io protocol,
-    //
-    Status = gBS->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid, 
&UpdatedDevicePath, &Handle);
-    if (EFI_ERROR (Status)) {
-      //
-      // Fail to find the proper BlockIo and simple file protocol, maybe 
because device not present,  we need to connect it firstly
-      //
-      UpdatedDevicePath = DevicePath;
-      Status            = gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid, 
&UpdatedDevicePath, &Handle);
-      gBS->ConnectController (Handle, NULL, NULL, TRUE);
+  TempDevicePath = DevicePath;
+  Status = gBS->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid, 
&TempDevicePath, &Handle);
+  if (!EFI_ERROR (Status)) {
+    ASSERT (IsDevicePathEnd (TempDevicePath));
+
+    TempDevicePath = FileDevicePath (Handle, EFI_REMOVABLE_MEDIA_FILE_NAME);
+    FileBuffer = GetFileBufferByFilePath (TRUE, TempDevicePath, FileSize, 
&AuthenticationStatus);
+    if (FileBuffer == NULL) {
+      FreePool (TempDevicePath);
+      TempDevicePath = NULL;
     }
-  } else {
-    //
-    // For removable device boot option, its contained device path only point 
to the removable device handle, 
-    // should make sure all its children handles (its child partion or media 
handles) are created and connected. 
-    //
-    gBS->ConnectController (Handle, NULL, NULL, TRUE); 
-    //
-    // Get BlockIo protocol and check removable attribute
-    //
-    Status = gBS->HandleProtocol (Handle, &gEfiBlockIoProtocolGuid, (VOID 
**)&BlockIo);
-    //
-    // Issue a dummy read to the device to check for media change.
-    // When the removable media is changed, any Block IO read/write will
-    // cause the BlockIo protocol be reinstalled and EFI_MEDIA_CHANGED is
-    // returned. After the Block IO protocol is reinstalled, subsequent
-    // Block IO read/write will success.
-    //
-    Buffer = AllocatePool (BlockIo->Media->BlockSize);
-    if (Buffer != NULL) {
-      BlockIo->ReadBlocks (
-               BlockIo,
-               BlockIo->Media->MediaId,
-               0,
-               BlockIo->Media->BlockSize,
-               Buffer
-               );
-      FreePool(Buffer);
-    }
+    *FullPath = TempDevicePath;
+    return FileBuffer;
   }
 
   //
+  // For device boot option only pointing to the removable device handle, 
+  // should make sure all its children handles (its child partion or media 
handles) are created and connected. 
+  //
+  gBS->ConnectController (Handle, NULL, NULL, TRUE);
+
+  //
+  // Issue a dummy read to the device to check for media change.
+  // When the removable media is changed, any Block IO read/write will
+  // cause the BlockIo protocol be reinstalled and EFI_MEDIA_CHANGED is
+  // returned. After the Block IO protocol is reinstalled, subsequent
+  // Block IO read/write will success.
+  //
+  Status = gBS->LocateDevicePath (&gEfiBlockIoProtocolGuid, &TempDevicePath, 
&Handle);
+  ASSERT_EFI_ERROR (Status);
+  Status = gBS->HandleProtocol (Handle, &gEfiBlockIoProtocolGuid, (VOID **) 
&BlockIo);
+  ASSERT_EFI_ERROR (Status);
+  Buffer = AllocatePool (BlockIo->Media->BlockSize);
+  if (Buffer != NULL) {
+    BlockIo->ReadBlocks (
+      BlockIo,
+      BlockIo->Media->MediaId,
+      0,
+      BlockIo->Media->BlockSize,
+      Buffer
+      );
+    FreePool (Buffer);
+  }
+
+  //
   // Detect the the default boot file from removable Media
   //
-  Size = GetDevicePathSize(DevicePath) - END_DEVICE_PATH_LENGTH;
+  FileBuffer = NULL;
+  *FullPath = NULL;
+  Size = GetDevicePathSize (DevicePath) - END_DEVICE_PATH_LENGTH;
   gBS->LocateHandleBuffer (
          ByProtocol,
          &gEfiSimpleFileSystemProtocolGuid,
@@ -1365,87 +1269,87 @@
     // Get the device path size of SimpleFileSystem handle
     //
     TempDevicePath = DevicePathFromHandle (SimpleFileSystemHandles[Index]);
-    TempSize       = GetDevicePathSize (TempDevicePath)- 
END_DEVICE_PATH_LENGTH;
+    TempSize = GetDevicePathSize (TempDevicePath) - END_DEVICE_PATH_LENGTH;
     //
     // Check whether the device path of boot option is part of the 
SimpleFileSystem handle's device path
     //
     if ((Size <= TempSize) && (CompareMem (TempDevicePath, DevicePath, Size) 
== 0)) {
-      //
-      // Load the default boot file \EFI\BOOT\boot{machinename}.EFI from 
removable Media
-      //  machinename is ia32, ia64, x64, ...
-      //
-      Hdr.Union = &HdrData;
-      Status = BmGetImageHeader (
-                 SimpleFileSystemHandles[Index],
-                 EFI_REMOVABLE_MEDIA_FILE_NAME,
-                 &DosHeader,
-                 Hdr
-                 );
-      if (!EFI_ERROR (Status) && EFI_IMAGE_MACHINE_TYPE_SUPPORTED 
(Hdr.Pe32->FileHeader.Machine) &&
-          (Hdr.Pe32->OptionalHeader.Subsystem == 
EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION)
-         ) {
-        ReturnHandle = SimpleFileSystemHandles[Index];
+      TempDevicePath = FileDevicePath (SimpleFileSystemHandles[Index], 
EFI_REMOVABLE_MEDIA_FILE_NAME);
+      FileBuffer = GetFileBufferByFilePath (TRUE, TempDevicePath, FileSize, 
&AuthenticationStatus);
+      if (FileBuffer != NULL) {
+        *FullPath = TempDevicePath;
         break;
       }
+      FreePool (TempDevicePath);
     }
   }
 
   if (SimpleFileSystemHandles != NULL) {
-    FreePool(SimpleFileSystemHandles);
+    FreePool (SimpleFileSystemHandles);
   }
 
-  return ReturnHandle;
+  return FileBuffer;
 }
 
 /**
-  Get the image file buffer data and buffer size by its device path. 
+  Get the load option by its device path.
 
-  @param FilePath  On input, a pointer to an allocated buffer that contains 
the 
-                   file device path.
-                   On output the device path pointer could be modified to 
point to
-                   a new allocated buffer that contains the full device path.
-                   It could be caused by either short-form device path 
expanding,
-                   or default boot file path appending.
-  @param FileSize  A pointer to the size of the file buffer.
+  @param FilePath  The device path pointing to a load option.
+                   It could be a short-form device path.
+  @param FullPath  Return the full device path of the load option after
+                   short-form device path expanding.
+                   Caller is responsible to free it.
+  @param FileSize  Return the load option size.
 
-  @retval NULL   The file can't be found.
-  @retval other  The file buffer. The caller is responsible to free memory.
+  @return The load option buffer. Caller is responsible to free the memory.
 **/
 VOID *
-BmLoadEfiBootOption (
-  IN OUT EFI_DEVICE_PATH_PROTOCOL **FilePath,
-  OUT    UINTN                    *FileSize
+BmGetLoadOptionBuffer (
+  IN  EFI_DEVICE_PATH_PROTOCOL          *FilePath,
+  OUT EFI_DEVICE_PATH_PROTOCOL          **FullPath,
+  OUT UINTN                             *FileSize
   )
 {
   EFI_HANDLE                      Handle;
   VOID                            *FileBuffer;
   UINT32                          AuthenticationStatus;
   EFI_DEVICE_PATH_PROTOCOL        *Node;
+  EFI_STATUS                      Status;
 
-  ASSERT ((FilePath != NULL) && (*FilePath != NULL) && (FileSize != NULL));
+  ASSERT ((FilePath != NULL) && (FullPath != NULL) && (FileSize != NULL));
 
-  EfiBootManagerConnectDevicePath (*FilePath, NULL);
+  EfiBootManagerConnectDevicePath (FilePath, NULL);
 
+  *FullPath  = NULL;
   *FileSize  = 0;
   FileBuffer = NULL;
+
   //
+  // Boot from media device by adding a default file name 
\EFI\BOOT\BOOT{machine type short-name}.EFI
+  //
+  Node = FilePath;
+  Status = gBS->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid, &Node, 
&Handle);
+  if (EFI_ERROR (Status)) {
+    Status = gBS->LocateDevicePath (&gEfiBlockIoProtocolGuid, &Node, &Handle);
+  }
+
+  if (!EFI_ERROR (Status) && IsDevicePathEnd (Node)) {
+    return BmExpandMediaDevicePath (FilePath, FullPath, FileSize);
+  }
+
+  //
   // Expand the short-form device path to full device path
   //
-  if ((DevicePathType (*FilePath) == MEDIA_DEVICE_PATH) &&
-      (DevicePathSubType (*FilePath) == MEDIA_HARDDRIVE_DP)) {
+  if ((DevicePathType (FilePath) == MEDIA_DEVICE_PATH) &&
+      (DevicePathSubType (FilePath) == MEDIA_HARDDRIVE_DP)) {
     //
     // Expand the Harddrive device path
     //
-    BmExpandPartitionShortFormDevicePath (FilePath);
-    if (*FilePath == NULL) {
-      return NULL;
-    }
-
+    return BmExpandPartitionDevicePath (FilePath, FullPath, FileSize);
   } else {
-    for (Node = *FilePath; !IsDevicePathEnd (Node); Node = NextDevicePathNode 
(Node)) {
+    for (Node = FilePath; !IsDevicePathEnd (Node); Node = NextDevicePathNode 
(Node)) {
       if ((DevicePathType (Node) == MESSAGING_DEVICE_PATH) &&
-          ((DevicePathSubType (Node) == MSG_USB_CLASS_DP) ||
-           (DevicePathSubType (Node) == MSG_USB_WWID_DP))) {
+          ((DevicePathSubType (Node) == MSG_USB_CLASS_DP) || 
(DevicePathSubType (Node) == MSG_USB_WWID_DP))) {
         break;
       }
     }
@@ -1454,52 +1358,36 @@
       //
       // Expand the USB WWID/Class device path
       //
-      FileBuffer = BmExpandUsbShortFormDevicePath (FilePath, FileSize);
-      if (FileBuffer == NULL) {
-        return NULL;
+      FileBuffer = BmExpandUsbDevicePath (FilePath, FullPath, FileSize, Node);
+      if ((FileBuffer == NULL) && (FilePath == Node)) {
+        //
+        // Boot Option device path starts with USB Class or USB WWID device 
path.
+        // For Boot Option device path which doesn't begin with the USB Class 
or
+        // USB WWID device path, it's not needed to connect again here.
+        //
+        BmConnectUsbShortFormDevicePath (FilePath);
+        FileBuffer = BmExpandUsbDevicePath (FilePath, FullPath, FileSize, 
Node);
       }
+      return FileBuffer;
     }
   }
 
   //
   // Fix up the boot option path if it points to a FV in memory map style of 
device path
   //
-  if (BmIsMemmapFvFilePath (*FilePath)) {
-    BmFixupMemmapFvFilePath (FilePath);
-    if (*FilePath == NULL) {
-      return NULL;
-    }
+  if (BmIsMemmapFvFilePath (FilePath)) {
+    return BmGetFileBufferByMemmapFv (FilePath, FullPath, FileSize);
   }
 
-  if (FileBuffer == NULL) {
-    FileBuffer = GetFileBufferByFilePath (TRUE, *FilePath, FileSize, 
&AuthenticationStatus);
-  }
-
   //
-  // If we didn't find an image directly, we need to try as if it is a 
removable device boot option
-  // and load the image according to the default boot behavior.
+  // Directly reads the load option when it doesn't reside in simple file 
system instance (LoadFile/LoadFile2),
+  //   or it directly points to a file in simple file system instance.
   //
-  if (FileBuffer == NULL) {
-    //
-    // check if there is a bootable media could be found in this device path,
-    // and get the bootable media handle
-    //
-    Handle = BmGetBootableDeviceHandle (*FilePath);
-    if (Handle != NULL) {
-      //
-      // Load the default boot file \EFI\BOOT\boot{machinename}.EFI from the 
media
-      //  machinename is ia32, ia64, x64, ...
-      //
-      BmFreeAndSet ((VOID **) FilePath, FileDevicePath (Handle, 
EFI_REMOVABLE_MEDIA_FILE_NAME));
-      ASSERT (*FilePath != NULL);
-      FileBuffer = GetFileBufferByFilePath (TRUE, *FilePath, FileSize, 
&AuthenticationStatus);
-    }
+  FileBuffer = GetFileBufferByFilePath (TRUE, FilePath, FileSize, 
&AuthenticationStatus);
+  if (FileBuffer != NULL) {
+    *FullPath = DuplicateDevicePath (FilePath);
   }
 
-  if (FileBuffer == NULL) {
-    BmFreeAndSet ((VOID **) FilePath, NULL);
-  }
-
   return FileBuffer;
 }
 
@@ -1547,7 +1435,7 @@
     return;
   }
 
-  if (BootOption->FilePath == NULL) {
+  if (BootOption->FilePath == NULL || BootOption->OptionType != 
LoadOptionTypeBoot) {
     BootOption->Status = EFI_INVALID_PARAMETER;
     return;
   }
@@ -1557,7 +1445,7 @@
   //
   OptionNumber = BmFindBootOptionInVariable (BootOption);
   if (OptionNumber == LoadOptionNumberUnassigned) {
-    Status = BmGetFreeOptionNumber (L"BootOrder", &Uint16);
+    Status = BmGetFreeOptionNumber (LoadOptionTypeBoot, &Uint16);
     if (!EFI_ERROR (Status)) {
       //
       // Save the BootOption->OptionNumber to restore later
@@ -1601,9 +1489,12 @@
     DEBUG ((EFI_D_INFO, "[Bds] Booting Boot Manager Menu.\n"));
     BmStopHotkeyService (NULL, NULL);
   } else {
-    REPORT_STATUS_CODE (EFI_PROGRESS_CODE, (EFI_SOFTWARE_DXE_BS_DRIVER | 
EFI_SW_DXE_BS_PC_READY_TO_BOOT_EVENT));
     EfiSignalEventReadyToBoot();
     //
+    // Report Status Code to indicate ReadyToBoot was signalled
+    //
+    REPORT_STATUS_CODE (EFI_PROGRESS_CODE, (EFI_SOFTWARE_DXE_BS_DRIVER | 
EFI_SW_DXE_BS_PC_READY_TO_BOOT_EVENT));
+    //
     // 4. Repair system through DriverHealth protocol
     //
     BmRepairAllControllers ();
@@ -1615,14 +1506,20 @@
   // 5. Load EFI boot option to ImageHandle
   //
   ImageHandle = NULL;
-  if (DevicePathType (BootOption->FilePath) != BBS_DEVICE_PATH) {
+  if (BmDevicePathType (BootOption->FilePath) != BBS_DEVICE_PATH) {
     Status     = EFI_NOT_FOUND;
-    FilePath   = DuplicateDevicePath (BootOption->FilePath);
-    FileBuffer = BmLoadEfiBootOption (&FilePath, &FileSize);
-    if (FileBuffer != NULL) {
-
+    FileBuffer = BmGetLoadOptionBuffer (BootOption->FilePath, &FilePath, 
&FileSize);
+    DEBUG_CODE (
+      if (FileBuffer != NULL && CompareMem (BootOption->FilePath, FilePath, 
GetDevicePathSize (FilePath)) != 0) {
+        DEBUG ((EFI_D_INFO, "[Bds] DevicePath expand: "));
+        BmPrintDp (BootOption->FilePath);
+        DEBUG ((EFI_D_INFO, " -> "));
+        BmPrintDp (FilePath);
+        DEBUG ((EFI_D_INFO, "\n"));
+      }
+    );
+    if (BmIsLoadOptionPeHeaderValid (BootOption->OptionType, FileBuffer, 
FileSize)) {
       REPORT_STATUS_CODE (EFI_PROGRESS_CODE, PcdGet32 
(PcdProgressCodeOsLoaderLoad));
-
       Status = gBS->LoadImage (
                       TRUE,
                       gImageHandle,
@@ -1631,7 +1528,11 @@
                       FileSize,
                       &ImageHandle
                       );
+    }
+    if (FileBuffer != NULL) {
       FreePool (FileBuffer);
+    }
+    if (FilePath != NULL) {
       FreePool (FilePath);
     }
 
@@ -1790,63 +1691,44 @@
   IN  HARDDRIVE_DEVICE_PATH      *HardDriveDevicePath
   )
 {
-  HARDDRIVE_DEVICE_PATH     *TmpHdPath;
-  EFI_DEVICE_PATH_PROTOCOL  *DevicePath;
-  BOOLEAN                   Match;
-  EFI_DEVICE_PATH_PROTOCOL  *BlockIoHdDevicePathNode;
+  HARDDRIVE_DEVICE_PATH     *Node;
 
   if ((BlockIoDevicePath == NULL) || (HardDriveDevicePath == NULL)) {
     return FALSE;
   }
 
   //
-  // Make PreviousDevicePath == the device path node before the end node
-  //
-  DevicePath              = BlockIoDevicePath;
-  BlockIoHdDevicePathNode = NULL;
-
-  //
   // find the partition device path node
   //
-  while (!IsDevicePathEnd (DevicePath)) {
-    if ((DevicePathType (DevicePath) == MEDIA_DEVICE_PATH) &&
-        (DevicePathSubType (DevicePath) == MEDIA_HARDDRIVE_DP)
+  while (!IsDevicePathEnd (BlockIoDevicePath)) {
+    if ((DevicePathType (BlockIoDevicePath) == MEDIA_DEVICE_PATH) &&
+        (DevicePathSubType (BlockIoDevicePath) == MEDIA_HARDDRIVE_DP)
         ) {
-      BlockIoHdDevicePathNode = DevicePath;
       break;
     }
 
-    DevicePath = NextDevicePathNode (DevicePath);
+    BlockIoDevicePath = NextDevicePathNode (BlockIoDevicePath);
   }
 
-  if (BlockIoHdDevicePathNode == NULL) {
+  if (IsDevicePathEnd (BlockIoDevicePath)) {
     return FALSE;
   }
+
   //
   // See if the harddrive device path in blockio matches the orig Hard Drive 
Node
   //
-  TmpHdPath = (HARDDRIVE_DEVICE_PATH *) BlockIoHdDevicePathNode;
-  Match = FALSE;
+  Node = (HARDDRIVE_DEVICE_PATH *) BlockIoDevicePath;
 
   //
-  // Check for the match
+  // Match Signature and PartitionNumber.
+  // Unused bytes in Signature are initiaized with zeros.
   //
-  if ((TmpHdPath->MBRType == HardDriveDevicePath->MBRType) &&
-      (TmpHdPath->SignatureType == HardDriveDevicePath->SignatureType)) {
-    switch (TmpHdPath->SignatureType) {
-    case SIGNATURE_TYPE_GUID:
-      Match = CompareGuid ((EFI_GUID *)TmpHdPath->Signature, (EFI_GUID 
*)HardDriveDevicePath->Signature);
-      break;
-    case SIGNATURE_TYPE_MBR:
-      Match = (BOOLEAN) (*((UINT32 *) (&(TmpHdPath->Signature[0]))) == 
ReadUnaligned32((UINT32 *)(&(HardDriveDevicePath->Signature[0]))));
-      break;
-    default:
-      Match = FALSE;
-      break;
-    }
-  }
-
-  return Match;
+  return (BOOLEAN) (
+    (Node->PartitionNumber == HardDriveDevicePath->PartitionNumber) &&
+    (Node->MBRType == HardDriveDevicePath->MBRType) &&
+    (Node->SignatureType == HardDriveDevicePath->SignatureType) &&
+    (CompareMem (Node->Signature, HardDriveDevicePath->Signature, sizeof 
(Node->Signature)) == 0)
+    );
 }
 
 /**

Modified: trunk/edk2/MdeModulePkg/Library/UefiBootManagerLib/BmConnect.c
===================================================================
--- trunk/edk2/MdeModulePkg/Library/UefiBootManagerLib/BmConnect.c      
2015-05-11 06:32:51 UTC (rev 17402)
+++ trunk/edk2/MdeModulePkg/Library/UefiBootManagerLib/BmConnect.c      
2015-05-11 06:33:45 UTC (rev 17403)
@@ -102,12 +102,13 @@
                                 a multi-instance device path
   @param  MatchingHandle        Return the controller handle closest to the 
DevicePathToConnect
 
-  @retval EFI_SUCCESS           All handles associate with every device path  
node
-                                have been created
-  @retval EFI_OUT_OF_RESOURCES  There is no resource to create new handles
-  @retval EFI_NOT_FOUND         Create the handle associate with one device  
path
-                                node failed
-
+  @retval EFI_SUCCESS            All handles associate with every device path 
node
+                                 have been created.
+  @retval EFI_OUT_OF_RESOURCES   There is no resource to create new handles.
+  @retval EFI_NOT_FOUND          Create the handle associate with one device 
path
+                                 node failed.
+  @retval EFI_SECURITY_VIOLATION The user has no permission to start UEFI 
device 
+                                 drivers on the DevicePath.
 **/
 EFI_STATUS
 EFIAPI
@@ -166,9 +167,8 @@
         // Connect all drivers that apply to Handle and RemainingDevicePath,
         // the Recursive flag is FALSE so only one level will be expanded.
         //
-        // Do not check the connect status here, if the connect controller 
fail,
-        // then still give the chance to do dispatch, because partial
-        // RemainingDevicepath may be in the new FV
+        // If ConnectController fails to find a driver, then still give the 
chance to 
+        // do dispatch, because partial RemainingDevicePath may be in the new 
FV
         //
         // 1. If the connect fail, RemainingDevicepath and handle will not
         //    change, so next time will do the dispatch, then dispatch's status
@@ -177,7 +177,10 @@
         //    change, then avoid the dispatch, we have chance to continue the
         //    next connection
         //
-        gBS->ConnectController (Handle, NULL, RemainingDevicePath, FALSE);
+        Status = gBS->ConnectController (Handle, NULL, RemainingDevicePath, 
FALSE);
+        if (Status == EFI_NOT_FOUND) {
+          Status = EFI_SUCCESS;
+        }
         if (MatchingHandle != NULL) {
           *MatchingHandle = Handle;
         }

Modified: trunk/edk2/MdeModulePkg/Library/UefiBootManagerLib/BmConsole.c
===================================================================
--- trunk/edk2/MdeModulePkg/Library/UefiBootManagerLib/BmConsole.c      
2015-05-11 06:32:51 UTC (rev 17402)
+++ trunk/edk2/MdeModulePkg/Library/UefiBootManagerLib/BmConsole.c      
2015-05-11 06:33:45 UTC (rev 17403)
@@ -695,28 +695,42 @@
 /**
   This function will connect all the console devices base on the console
   device variable ConIn, ConOut and ErrOut.
+
+  @retval EFI_DEVICE_ERROR         All the consoles were not connected due to 
an error.
+  @retval EFI_SUCCESS              Success connect any one instance of the 
console
+                                   device path base on the variable ConVarName.
 **/
-VOID
+EFI_STATUS
 EFIAPI
 EfiBootManagerConnectAllDefaultConsoles (
   VOID
   )
 {
+  EFI_STATUS                Status;
+  BOOLEAN                   OneConnected;
   BOOLEAN                   SystemTableUpdated;
 
-  EfiBootManagerConnectConsoleVariable (ConOut);
+  OneConnected = FALSE;
+
+  Status = EfiBootManagerConnectConsoleVariable (ConOut);
+  if (!EFI_ERROR (Status)) {
+    OneConnected = TRUE;
+  }
   PERF_START (NULL, "ConOutReady", "BDS", 1);
   PERF_END   (NULL, "ConOutReady", "BDS", 0);
 
   
-  EfiBootManagerConnectConsoleVariable (ConIn);
+  Status = EfiBootManagerConnectConsoleVariable (ConIn);
+  if (!EFI_ERROR (Status)) {
+    OneConnected = TRUE;
+  }
   PERF_START (NULL, "ConInReady", "BDS", 1);
   PERF_END   (NULL, "ConInReady", "BDS", 0);
 
-  //
-  // The _ModuleEntryPoint err out var is legal.
-  //
-  EfiBootManagerConnectConsoleVariable (ErrOut);
+  Status = EfiBootManagerConnectConsoleVariable (ErrOut);
+  if (!EFI_ERROR (Status)) {
+    OneConnected = TRUE;
+  }
   PERF_START (NULL, "ErrOutReady", "BDS", 1);
   PERF_END   (NULL, "ErrOutReady", "BDS", 0);
 
@@ -745,4 +759,6 @@
           &gST->Hdr.CRC32
           );
   }
+
+  return OneConnected ? EFI_SUCCESS : EFI_DEVICE_ERROR;
 }

Modified: trunk/edk2/MdeModulePkg/Library/UefiBootManagerLib/BmLoadOption.c
===================================================================
--- trunk/edk2/MdeModulePkg/Library/UefiBootManagerLib/BmLoadOption.c   
2015-05-11 06:32:51 UTC (rev 17402)
+++ trunk/edk2/MdeModulePkg/Library/UefiBootManagerLib/BmLoadOption.c   
2015-05-11 06:33:45 UTC (rev 17403)
@@ -14,21 +14,77 @@
 
 #include "InternalBm.h"
 
+GLOBAL_REMOVE_IF_UNREFERENCED
+  CHAR16 *mBmLoadOptionName[] = {
+    L"Driver",
+    L"SysPrep",
+    L"Boot"
+  };
+
+GLOBAL_REMOVE_IF_UNREFERENCED
+  CHAR16 *mBmLoadOptionOrderName[] = {
+    EFI_DRIVER_ORDER_VARIABLE_NAME,
+    EFI_SYS_PREP_ORDER_VARIABLE_NAME,
+    EFI_BOOT_ORDER_VARIABLE_NAME
+  };
+
 /**
+  Call Visitor function for each variable in variable storage.
+
+  @param Visitor  Visitor function.
+  @param Context  The context passed to Visitor function.
+**/
+VOID
+BmForEachVariable (
+  VARIABLE_VISITOR            Visitor,
+  VOID                        *Context
+  )
+{
+  EFI_STATUS                  Status;
+  CHAR16                      *Name;
+  EFI_GUID                    Guid;
+  UINTN                       NameSize;
+  UINTN                       NewNameSize;
+
+  NameSize = sizeof (CHAR16);
+  Name = AllocateZeroPool (NameSize);
+  ASSERT (Name != NULL);
+  while (TRUE) {
+    NewNameSize = NameSize;
+    Status = gRT->GetNextVariableName (&NewNameSize, Name, &Guid);
+    if (Status == EFI_BUFFER_TOO_SMALL) {
+      Name = ReallocatePool (NameSize, NewNameSize, Name);
+      ASSERT (Name != NULL);
+      Status = gRT->GetNextVariableName (&NewNameSize, Name, &Guid);
+      NameSize = NewNameSize;
+    }
+
+    if (Status == EFI_NOT_FOUND) {
+      break;
+    }
+    ASSERT_EFI_ERROR (Status);
+
+    Visitor (Name, &Guid, Context);
+  }
+
+  FreePool (Name);
+}
+
+/**
   Get the Option Number that wasn't used.
 
-  @param  OrderVariableName   Could be L"BootOrder" or L"DriverOrder".
-  @param  FreeOptionNumber    To receive the minimal free option number.
+  @param  LoadOptionType      The load option type.
+  @param  FreeOptionNumber    Return the minimal free option number.
 
-  @retval EFI_SUCCESS           The option number is found
+  @retval EFI_SUCCESS           The option number is found and will be 
returned.
   @retval EFI_OUT_OF_RESOURCES  There is no free option number that can be 
used.
   @retval EFI_INVALID_PARAMETER FreeOptionNumber is NULL
 
 **/
 EFI_STATUS
 BmGetFreeOptionNumber (
-  IN  CHAR16    *OrderVariableName,
-  OUT UINT16    *FreeOptionNumber
+  IN  EFI_BOOT_MANAGER_LOAD_OPTION_TYPE LoadOptionType,
+  OUT UINT16                            *FreeOptionNumber
   )
 {
   
@@ -38,13 +94,14 @@
   UINTN         OptionOrderSize;
   UINT16        *BootNext;
 
-  if (FreeOptionNumber == NULL) {
-    return EFI_INVALID_PARAMETER;
-  }
+  ASSERT (FreeOptionNumber != NULL);
+  ASSERT (LoadOptionType == LoadOptionTypeDriver || 
+          LoadOptionType == LoadOptionTypeBoot ||
+          LoadOptionType == LoadOptionTypeSysPrep);
 
-  GetEfiGlobalVariable2 (OrderVariableName, (VOID **) &OptionOrder, 
&OptionOrderSize);
+  GetEfiGlobalVariable2 (mBmLoadOptionOrderName[LoadOptionType], (VOID **) 
&OptionOrder, &OptionOrderSize);
   BootNext = NULL;
-  if (*OrderVariableName == L'B') {
+  if (LoadOptionType == LoadOptionTypeBoot) {
     GetEfiGlobalVariable2 (L"BootNext", (VOID**) &BootNext, NULL);
   }
 
@@ -94,72 +151,7 @@
 }
 
 /**
-  Update order variable .
-
-  @param  OptionOrderName     Order variable name which need to be updated.
-  @param  OptionNumber        Option number for the new option.
-  @param  Position            Position of the new load option to put in the 
****Order variable.
-
-  @retval EFI_SUCCESS           The boot#### or driver#### have been 
successfully registered.
-  @retval EFI_ALREADY_STARTED   The option number of Option is being used 
already.
-  @retval EFI_STATUS            Return the status of gRT->SetVariable ().
-
-**/
-EFI_STATUS
-BmAddOptionNumberToOrderVariable (
-  IN CHAR16               *OptionOrderName,
-  IN UINT16               OptionNumber,
-  IN UINTN                Position
-  )
-{
-  EFI_STATUS              Status;
-  UINTN                   Index;
-  UINT16                  *OptionOrder;
-  UINT16                  *NewOptionOrder;
-  UINTN                   OptionOrderSize;
-  //
-  // Update the option order variable
-  //
-  GetEfiGlobalVariable2 (OptionOrderName, (VOID **) &OptionOrder, 
&OptionOrderSize);
-
-  Status = EFI_SUCCESS;
-  for (Index = 0; Index < OptionOrderSize / sizeof (UINT16); Index++) {
-    if (OptionOrder[Index] == OptionNumber) {
-      Status = EFI_ALREADY_STARTED;
-      break;
-    }
-  }
-
-  if (!EFI_ERROR (Status)) {
-    Position       = MIN (Position, OptionOrderSize / sizeof (UINT16));
-
-    NewOptionOrder = AllocatePool (OptionOrderSize + sizeof (UINT16));
-    ASSERT (NewOptionOrder != NULL);
-    if (OptionOrderSize != 0) {
-      CopyMem (NewOptionOrder, OptionOrder, Position * sizeof (UINT16));
-      CopyMem (&NewOptionOrder[Position + 1], &OptionOrder[Position], 
OptionOrderSize - Position * sizeof (UINT16));
-    }
-    NewOptionOrder[Position] = OptionNumber;
-
-    Status = gRT->SetVariable (
-                    OptionOrderName,
-                    &gEfiGlobalVariableGuid,
-                    EFI_VARIABLE_BOOTSERVICE_ACCESS | 
EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
-                    OptionOrderSize + sizeof (UINT16),
-                    NewOptionOrder
-                    );
-    FreePool (NewOptionOrder);
-  }
-
-  if (OptionOrder != NULL) {
-    FreePool (OptionOrder);
-  }
-
-  return Status;
-}
-
-/**
-  Create the Boot#### or Driver#### variable from the load option.
+  Create the Boot####, Driver####, SysPrep####, variable from the load option.
   
   @param  LoadOption      Pointer to the load option.
 
@@ -175,13 +167,14 @@
   UINTN                            VariableSize;
   UINT8                            *Variable;
   UINT8                            *Ptr;
-  CHAR16                           OptionName[sizeof ("Driver####")];
+  CHAR16                           OptionName[BM_OPTION_NAME_LEN];
   CHAR16                           *Description;
   CHAR16                           NullChar;
+  UINT32                           VariableAttributes;
 
   if ((Option->OptionNumber == LoadOptionNumberUnassigned) ||
       (Option->FilePath == NULL) ||
-      (Option->OptionType >= LoadOptionTypeMax)
+      ((UINT32) Option->OptionType >= LoadOptionTypeMax)
      ) {
     return EFI_INVALID_PARAMETER;
   }
@@ -218,42 +211,108 @@
 
   Variable     = AllocatePool (VariableSize);
   ASSERT (Variable != NULL);
-  
+
   Ptr             = Variable;
-  *(UINT32 *) Ptr = Option->Attributes;
+  WriteUnaligned32 ((UINT32 *) Ptr, Option->Attributes);
   Ptr            += sizeof (Option->Attributes);
-  *(UINT16 *) Ptr = (UINT16) GetDevicePathSize (Option->FilePath);
+
+  WriteUnaligned16 ((UINT16 *) Ptr, (UINT16) GetDevicePathSize 
(Option->FilePath));
   Ptr            += sizeof (UINT16);
+
   CopyMem (Ptr, Description, StrSize (Description));
   Ptr            += StrSize (Description);
+
   CopyMem (Ptr, Option->FilePath, GetDevicePathSize (Option->FilePath));
   Ptr            += GetDevicePathSize (Option->FilePath);
+
   CopyMem (Ptr, Option->OptionalData, Option->OptionalDataSize);
 
-  UnicodeSPrint (
-    OptionName,
-    sizeof (OptionName),
-    (Option->OptionType == LoadOptionTypeBoot) ? L"Boot%04x" : L"Driver%04x",
-    Option->OptionNumber
-    );
+  UnicodeSPrint (OptionName, sizeof (OptionName), L"%s%04x", 
mBmLoadOptionName[Option->OptionType], Option->OptionNumber);
 
+  VariableAttributes = EFI_VARIABLE_BOOTSERVICE_ACCESS | 
EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE;
+
   return gRT->SetVariable (
                 OptionName,
                 &gEfiGlobalVariableGuid,
-                EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS 
| EFI_VARIABLE_NON_VOLATILE,
+                VariableAttributes,
                 VariableSize,
                 Variable
                 );
 }
 
 /**
-  This function will register the new boot#### or driver#### option.
-  After the boot#### or driver#### updated, the BootOrder or DriverOrder will 
also be updated.
+  Update order variable .
 
+  @param  OptionOrderName     Order variable name which need to be updated.
+  @param  OptionNumber        Option number for the new option.
+  @param  Position            Position of the new load option to put in the 
****Order variable.
+
+  @retval EFI_SUCCESS           The boot#### or driver#### have been 
successfully registered.
+  @retval EFI_ALREADY_STARTED   The option number of Option is being used 
already.
+  @retval EFI_STATUS            Return the status of gRT->SetVariable ().
+
+**/
+EFI_STATUS
+BmAddOptionNumberToOrderVariable (
+  IN CHAR16               *OptionOrderName,
+  IN UINT16               OptionNumber,
+  IN UINTN                Position
+  )
+{
+  EFI_STATUS              Status;
+  UINTN                   Index;
+  UINT16                  *OptionOrder;
+  UINT16                  *NewOptionOrder;
+  UINTN                   OptionOrderSize;
+  //
+  // Update the option order variable
+  //
+  GetEfiGlobalVariable2 (OptionOrderName, (VOID **) &OptionOrder, 
&OptionOrderSize);
+
+  Status = EFI_SUCCESS;
+  for (Index = 0; Index < OptionOrderSize / sizeof (UINT16); Index++) {
+    if (OptionOrder[Index] == OptionNumber) {
+      Status = EFI_ALREADY_STARTED;
+      break;
+    }
+  }
+
+  if (!EFI_ERROR (Status)) {
+    Position       = MIN (Position, OptionOrderSize / sizeof (UINT16));
+
+    NewOptionOrder = AllocatePool (OptionOrderSize + sizeof (UINT16));
+    ASSERT (NewOptionOrder != NULL);
+    if (OptionOrderSize != 0) {
+      CopyMem (NewOptionOrder, OptionOrder, Position * sizeof (UINT16));
+      CopyMem (&NewOptionOrder[Position + 1], &OptionOrder[Position], 
OptionOrderSize - Position * sizeof (UINT16));
+    }
+    NewOptionOrder[Position] = OptionNumber;
+
+    Status = gRT->SetVariable (
+                    OptionOrderName,
+                    &gEfiGlobalVariableGuid,
+                    EFI_VARIABLE_BOOTSERVICE_ACCESS | 
EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
+                    OptionOrderSize + sizeof (UINT16),
+                    NewOptionOrder
+                    );
+    FreePool (NewOptionOrder);
+  }
+
+  if (OptionOrder != NULL) {
+    FreePool (OptionOrder);
+  }
+
+  return Status;
+}
+
+/**
+  This function will register the new Boot####, Driver#### or SysPrep#### 
option.
+  After the *#### is updated, the *Order will also be updated.
+
   @param  Option            Pointer to load option to add.
   @param  Position          Position of the new load option to put in the 
****Order variable.
 
-  @retval EFI_SUCCESS           The boot#### or driver#### have been 
successfully registered.
+  @retval EFI_SUCCESS           The *#### have been successfully registered.
   @retval EFI_INVALID_PARAMETER The option number exceeds 0xFFFF.
   @retval EFI_ALREADY_STARTED   The option number of Option is being used 
already.
                                 Note: this API only adds new load option, no 
replacement support.
@@ -276,14 +335,18 @@
     return EFI_INVALID_PARAMETER;
   }
 
+  if (Option->OptionType != LoadOptionTypeDriver && 
+      Option->OptionType != LoadOptionTypeSysPrep &&
+      Option->OptionType != LoadOptionTypeBoot
+      ) {
+    return EFI_INVALID_PARAMETER;
+  }
+
   //
   // Get the free option number if the option number is unassigned
   //
   if (Option->OptionNumber == LoadOptionNumberUnassigned) {
-    Status = BmGetFreeOptionNumber (
-               Option->OptionType == LoadOptionTypeBoot ? L"BootOrder" : 
L"DriverOrder",
-               &OptionNumber
-               );
+    Status = BmGetFreeOptionNumber (Option->OptionType, &OptionNumber);
     if (EFI_ERROR (Status)) {
       return Status;
     }
@@ -294,11 +357,7 @@
     return EFI_INVALID_PARAMETER;
   }
 
-  Status = BmAddOptionNumberToOrderVariable (
-             Option->OptionType == LoadOptionTypeBoot ? L"BootOrder" : 
L"DriverOrder",
-             (UINT16) Option->OptionNumber,
-             Position
-             );
+  Status = BmAddOptionNumberToOrderVariable 
(mBmLoadOptionOrderName[Option->OptionType], (UINT16) Option->OptionNumber, 
Position);
   if (!EFI_ERROR (Status)) {
     //
     // Save the Boot#### or Driver#### variable
@@ -306,7 +365,7 @@
     Status = EfiBootManagerLoadOptionToVariable (Option);
     if (EFI_ERROR (Status)) {
       //
-      // Remove the #### from *Order variable when the Boot####/Driver#### 
cannot be saved.
+      // Remove the #### from *Order variable when the 
Driver####/SysPrep####/Boot#### cannot be saved.
       //
       EfiBootManagerDeleteLoadOptionVariable (Option->OptionNumber, 
Option->OptionType);
     }
@@ -357,7 +416,7 @@
   }
 
   Status = gRT->SetVariable (
-                  OptionType == LoadOptionTypeBoot ? L"BootOrder" : 
L"DriverOrder",
+                  mBmLoadOptionOrderName[OptionType],
                   &gEfiGlobalVariableGuid,
                   EFI_VARIABLE_BOOTSERVICE_ACCESS | 
EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
                   LoadOptionCount * sizeof (UINT16),
@@ -409,6 +468,10 @@
     return EFI_INVALID_PARAMETER;
   }
 
+  if ((UINT32) OptionType >= LoadOptionTypeMax) {
+    return EFI_INVALID_PARAMETER;
+  }
+
   ZeroMem (Option, sizeof (EFI_BOOT_MANAGER_LOAD_OPTION));
   Option->OptionNumber       = OptionNumber;
   Option->OptionType         = OptionType;
@@ -461,58 +524,15 @@
 }
 
 /**
-  Update the BootOrder or DriverOrder to delete OptionNumber .
+  Delete the load option.
 
-  @param  OptionOrderVariable  Order variable name which need to be updated.
-  @param  OptionNumber         Indicate the option number of load option
-
-  @retval EFI_NOT_FOUND         The load option cannot be found
-  @retval EFI_SUCCESS           The load option was deleted
-  @retval others                Status of RT->SetVariable()
-**/
-EFI_STATUS
-BmDeleteOptionVariable (
-  IN CHAR16                            *OptionOrderVariable,
-  IN UINT16                            OptionNumber
-  )
-{
-  UINT16           *OptionOrder;
-  UINTN            OptionOrderSize;
-  EFI_STATUS       Status;
-  UINTN            Index;
-
-  Status      = EFI_NOT_FOUND;
-  GetEfiGlobalVariable2 (OptionOrderVariable, (VOID **) &OptionOrder, 
&OptionOrderSize);
-  for (Index = 0; Index < OptionOrderSize / sizeof (UINT16); Index++) {
-    if (OptionOrder[Index] == OptionNumber) {
-      OptionOrderSize -= sizeof (UINT16);
-      CopyMem (&OptionOrder[Index], &OptionOrder[Index + 1], OptionOrderSize - 
Index * sizeof (UINT16));
-      Status = gRT->SetVariable (
-                      OptionOrderVariable,
-                      &gEfiGlobalVariableGuid,
-                      EFI_VARIABLE_BOOTSERVICE_ACCESS | 
EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
-                      OptionOrderSize,
-                      OptionOrder
-                      );
-      break;
-    }
-  }
-  if (OptionOrder != NULL) {
-    FreePool (OptionOrder);
-  }
-
-  return Status;
-}
-
-/**
-  Update the BootOrder or DriverOrder according to the OptionType to delete 
OptionNumber .
-  
   @param  OptionNumber        Indicate the option number of load option
   @param  OptionType          Indicate the type of load option
 
   @retval EFI_INVALID_PARAMETER OptionType or OptionNumber is invalid.
   @retval EFI_NOT_FOUND         The load option cannot be found
   @retval EFI_SUCCESS           The load option was deleted
+  @retval others                Status of RT->SetVariable()
 **/
 EFI_STATUS
 EFIAPI
@@ -521,14 +541,42 @@
   IN EFI_BOOT_MANAGER_LOAD_OPTION_TYPE  OptionType
   )
 {
-  if ((OptionType >= LoadOptionTypeMax) || (OptionNumber >= 
LoadOptionNumberMax)) {
+  UINT16                            *OptionOrder;
+  UINTN                             OptionOrderSize;
+  EFI_STATUS                        Status;
+  UINTN                             Index;
+
+  if (((UINT32) OptionType >= LoadOptionTypeMax) || (OptionNumber >= 
LoadOptionNumberMax)) {
     return EFI_INVALID_PARAMETER;
   }
 
-  return BmDeleteOptionVariable (
-           OptionType == LoadOptionTypeBoot ? L"BootOrder" : L"DriverOrder",
-           (UINT16) OptionNumber
-           );
+  Status = EFI_NOT_FOUND;
+
+  if (OptionType == LoadOptionTypeDriver || OptionType == 
LoadOptionTypeSysPrep || OptionType == LoadOptionTypeBoot) {
+    //
+    // If the associated *Order exists, just remove the reference in *Order.
+    //
+    GetEfiGlobalVariable2 (mBmLoadOptionOrderName[OptionType], &OptionOrder, 
&OptionOrderSize);
+    for (Index = 0; Index < OptionOrderSize / sizeof (UINT16); Index++) {
+      if (OptionOrder[Index] == OptionNumber) {
+        OptionOrderSize -= sizeof (UINT16);
+        CopyMem (&OptionOrder[Index], &OptionOrder[Index + 1], OptionOrderSize 
- Index * sizeof (UINT16));
+        Status = gRT->SetVariable (
+          mBmLoadOptionOrderName[OptionType],
+          &gEfiGlobalVariableGuid,
+          EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | 
EFI_VARIABLE_NON_VOLATILE,
+          OptionOrderSize,
+          OptionOrder
+          );
+        break;
+      }
+    }
+    if (OptionOrder != NULL) {
+      FreePool (OptionOrder);
+    }
+  }
+
+  return Status;
 }
 
 /**
@@ -551,7 +599,7 @@
   }
 
   ASSERT (FALSE);
-  return 0;
+  return (UINTN) -1;
 }
 
 /**
@@ -645,10 +693,10 @@
 }
 
 /**
-  Validate the EFI Boot#### variable (VendorGuid/Name)
+  Validate the Boot####, Driver####, SysPrep#### variable (VendorGuid/Name)
 
-  @param  Variable              Boot#### variable data.
-  @param  VariableSize          Returns the size of the EFI variable that was 
read
+  @param  Variable              The variable data.
+  @param  VariableSize          The variable size.
 
   @retval TRUE                  The variable data is correct.
   @retval FALSE                 The variable data is corrupted.
@@ -661,9 +709,8 @@
   )
 {
   UINT16                    FilePathSize;
-  UINT8                     *TempPtr;
   EFI_DEVICE_PATH_PROTOCOL  *DevicePath;
-  UINTN                     TempSize;
+  UINTN                     DescriptionSize;
 
   if (VariableSize <= sizeof (UINT16) + sizeof (UINT32)) {
     return FALSE;
@@ -672,35 +719,33 @@
   //
   // Skip the option attribute
   //
-  TempPtr    = Variable;
-  TempPtr   += sizeof (UINT32);
+  Variable += sizeof (UINT32);
 
   //
   // Get the option's device path size
   //
-  FilePathSize  = *(UINT16 *) TempPtr;
-  TempPtr      += sizeof (UINT16);
+  FilePathSize = ReadUnaligned16 ((UINT16 *) Variable);
+  Variable += sizeof (UINT16);
 
   //
   // Get the option's description string size
   //
-  TempSize = BmStrSizeEx ((CHAR16 *) TempPtr, VariableSize - sizeof (UINT16) - 
sizeof (UINT32));
-  TempPtr += TempSize;
+  DescriptionSize = BmStrSizeEx ((CHAR16 *) Variable, VariableSize - sizeof 
(UINT16) - sizeof (UINT32));
+  Variable += DescriptionSize;
 
   //
   // Get the option's device path
   //
-  DevicePath =  (EFI_DEVICE_PATH_PROTOCOL *) TempPtr;
-  TempPtr   += FilePathSize;
+  DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) Variable;
 
   //
   // Validation boot option variable.
   //
-  if ((FilePathSize == 0) || (TempSize == 0)) {
+  if ((FilePathSize == 0) || (DescriptionSize == 0)) {
     return FALSE;
   }
 
-  if (TempSize + FilePathSize + sizeof (UINT16) + sizeof (UINT32) > 
VariableSize) {
+  if (sizeof (UINT32) + sizeof (UINT16) + DescriptionSize + FilePathSize > 
VariableSize) {
     return FALSE;
   }
 
@@ -708,11 +753,66 @@
 }
 
 /**
+  Check whether the VariableName is a valid load option variable name
+  and return the load option type and option number.
+
+  @param VariableName The name of the load option variable.
+  @param OptionType   Return the load option type.
+  @param OptionNumber Return the load option number.
+
+  @retval TRUE  The variable name is valid; The load option type and
+                load option number is returned.
+  @retval FALSE The variable name is NOT valid.
+**/
+BOOLEAN
+BmIsValidLoadOptionVariableName (
+  IN CHAR16                             *VariableName,
+  OUT EFI_BOOT_MANAGER_LOAD_OPTION_TYPE *OptionType,
+  OUT UINT16                            *OptionNumber
+  )
+{
+  UINTN                             VariableNameLen;
+  UINTN                             Index;
+  UINTN                             Uint;
+
+  VariableNameLen = StrLen (VariableName);
+
+  if (VariableNameLen <= 4) {
+    return FALSE;
+  }
+
+  for (Index = 0; Index < sizeof (mBmLoadOptionName) / sizeof 
(mBmLoadOptionName[0]); Index++) {
+    if ((VariableNameLen - 4 == StrLen (mBmLoadOptionName[Index])) &&
+        (StrnCmp (VariableName, mBmLoadOptionName[Index], VariableNameLen - 4) 
== 0)
+        ) {
+      break;
+    }
+  }
+
+  if (Index == sizeof (mBmLoadOptionName) / sizeof (mBmLoadOptionName[0])) {
+    return FALSE;
+  }
+
+  *OptionType = (EFI_BOOT_MANAGER_LOAD_OPTION_TYPE) Index;
+  *OptionNumber = 0;
+  for (Index = VariableNameLen - 4; Index < VariableNameLen; Index++) {
+    Uint = BmCharToUint (VariableName[Index]);
+    if (Uint == -1) {
+      break;
+    } else {
+      *OptionNumber = (UINT16) Uint + *OptionNumber * 0x10;
+    }
+  }
+
+  return (BOOLEAN) (Index == VariableNameLen);
+}
+
+/**
   Build the Boot#### or Driver#### option from the VariableName.
 
-  @param  VariableName          EFI Variable name indicate if it is Boot#### or
-                                Driver####
-  @param  Option                Return the Boot#### or Driver#### option.
+  @param  VariableName          Variable name of the load option
+  @param  VendorGuid            Variable GUID of the load option
+  @param  Option                Return the load option.
 
   @retval EFI_SUCCESS     Get the option just been created
   @retval EFI_NOT_FOUND   Failed to get the new option
@@ -720,22 +820,22 @@
 **/
 EFI_STATUS
 EFIAPI
-EfiBootManagerVariableToLoadOption (
-  IN  CHAR16                          *VariableName,
-  IN OUT EFI_BOOT_MANAGER_LOAD_OPTION *Option
+EfiBootManagerVariableToLoadOptionEx (
+  IN CHAR16                           *VariableName,
+  IN EFI_GUID                         *VendorGuid,
+  IN OUT EFI_BOOT_MANAGER_LOAD_OPTION *Option  
   )
 {
   EFI_STATUS                         Status;
   UINT32                             Attribute;
   UINT16                             FilePathSize;
   UINT8                              *Variable;
-  UINT8                              *TempPtr;
+  UINT8                              *VariablePtr;
   UINTN                              VariableSize;
   EFI_DEVICE_PATH_PROTOCOL           *FilePath;
   UINT8                              *OptionalData;
   UINT32                             OptionalDataSize;
   CHAR16                             *Description;
-  UINT8                              NumOff;
   EFI_BOOT_MANAGER_LOAD_OPTION_TYPE  OptionType;
   UINT16                             OptionNumber;
 
@@ -743,16 +843,20 @@
     return EFI_INVALID_PARAMETER;
   }
 
+  if (!BmIsValidLoadOptionVariableName (VariableName, &OptionType, 
&OptionNumber)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
   //
   // Read the variable
   //
-  GetEfiGlobalVariable2 (VariableName, (VOID **) &Variable, &VariableSize);
+  GetVariable2 (VariableName, VendorGuid, (VOID **) &Variable, &VariableSize);
   if (Variable == NULL) {
     return EFI_NOT_FOUND;
   }
 
   //
-  // Validate Boot#### variable data.
+  // Validate *#### variable data.
   //
   if (!BmValidateOption(Variable, VariableSize)) {
     FreePool (Variable);
@@ -760,63 +864,41 @@
   }
 
   //
-  // Notes: careful defined the variable of Boot#### or
-  // Driver####, consider use some macro to abstract the code
-  //
-  //
   // Get the option attribute
   //
-  TempPtr   =  Variable;
-  Attribute =  *(UINT32 *) Variable;
-  TempPtr   += sizeof (UINT32);
+  VariablePtr = Variable;
+  Attribute = ReadUnaligned32 ((UINT32 *) VariablePtr);
+  VariablePtr += sizeof (UINT32);
 
   //
   // Get the option's device path size
   //
-  FilePathSize =  *(UINT16 *) TempPtr;
-  TempPtr     += sizeof (UINT16);
+  FilePathSize = ReadUnaligned16 ((UINT16 *) VariablePtr);
+  VariablePtr += sizeof (UINT16);
 
   //
   // Get the option's description string
   //
-  Description  = (CHAR16 *) TempPtr;
+  Description = (CHAR16 *) VariablePtr;
 
   //
   // Get the option's description string size
   //
-  TempPtr     += StrSize ((CHAR16 *) TempPtr);
+  VariablePtr += StrSize ((CHAR16 *) VariablePtr);
 
   //
   // Get the option's device path
   //
-  FilePath     =  (EFI_DEVICE_PATH_PROTOCOL *) TempPtr;
-  TempPtr     += FilePathSize;
+  FilePath = (EFI_DEVICE_PATH_PROTOCOL *) VariablePtr;
+  VariablePtr += FilePathSize;
 
-  OptionalDataSize = (UINT32) (VariableSize - (UINTN) (TempPtr - Variable));
+  OptionalDataSize = (UINT32) (VariableSize - (UINTN) (VariablePtr - 
Variable));
   if (OptionalDataSize == 0) {
     OptionalData = NULL;
   } else {
-    OptionalData = TempPtr;
+    OptionalData = VariablePtr;
   }
 
-  if (*VariableName == L'B') {
-    OptionType = LoadOptionTypeBoot;
-    NumOff = (UINT8) (sizeof (L"Boot") / sizeof (CHAR16) - 1);
-  } else {
-    OptionType = LoadOptionTypeDriver;
-    NumOff = (UINT8) (sizeof (L"Driver") / sizeof (CHAR16) - 1);
-  }
-  
-  //
-  // Get the value from VariableName Unicode string
-  // since the ISO standard assumes ASCII equivalent abbreviations, we can be 
safe in converting this
-  // Unicode stream to ASCII without any loss in meaning.
-  //  
-  OptionNumber = (UINT16) (BmCharToUint (VariableName[NumOff+0]) * 0x1000) 
-               + (UINT16) (BmCharToUint (VariableName[NumOff+1]) * 0x100)
-               + (UINT16) (BmCharToUint (VariableName[NumOff+2]) * 0x10)
-               + (UINT16) (BmCharToUint (VariableName[NumOff+3]) * 0x1);
-
   Status = EfiBootManagerInitializeLoadOption (
              Option,
              OptionNumber,
@@ -828,12 +910,33 @@
              OptionalDataSize
              );
   ASSERT_EFI_ERROR (Status);
-  
+
+  CopyGuid (&Option->VendorGuid, VendorGuid);
+
   FreePool (Variable);
   return Status;
 }
 
 /**
+Build the Boot#### or Driver#### option from the VariableName.
+
+@param  VariableName          EFI Variable name indicate if it is Boot#### or 
Driver####
+@param  Option                Return the Boot#### or Driver#### option.
+
+@retval EFI_SUCCESS     Get the option just been created
+@retval EFI_NOT_FOUND   Failed to get the new option
+**/
+EFI_STATUS
+EFIAPI
+EfiBootManagerVariableToLoadOption (
+  IN  CHAR16                          *VariableName,
+  IN OUT EFI_BOOT_MANAGER_LOAD_OPTION *Option
+  )
+{
+  return EfiBootManagerVariableToLoadOptionEx (VariableName, 
&gEfiGlobalVariableGuid, Option);
+}
+
+/**
   Returns an array of load options based on the EFI variable
   L"BootOrder"/L"DriverOrder" and the L"Boot####"/L"Driver####" variables 
impled by it.
   #### is the hex value of the UINT16 in each BootOrder/DriverOrder entry. 
@@ -857,63 +960,56 @@
   UINTN                        OptionOrderSize;
   UINTN                        Index;
   UINTN                        OptionIndex;
-  EFI_BOOT_MANAGER_LOAD_OPTION *Option;
-  CHAR16                       OptionName[sizeof ("Driver####")];
+  EFI_BOOT_MANAGER_LOAD_OPTION *Options;
+  CHAR16                       OptionName[BM_OPTION_NAME_LEN];
   UINT16                       OptionNumber;
 
   *OptionCount = 0;
 
-  //
-  // Read the BootOrder, or DriverOrder variable.
-  //
-  GetEfiGlobalVariable2 (
-    (LoadOptionType == LoadOptionTypeBoot) ? L"BootOrder" : L"DriverOrder",
-    (VOID **) &OptionOrder,
-    &OptionOrderSize
-    );
-  if (OptionOrder == NULL) {
-    return NULL;
-  }
+  if (LoadOptionType == LoadOptionTypeDriver || LoadOptionType == 
LoadOptionTypeSysPrep || LoadOptionType == LoadOptionTypeBoot) {
+    //
+    // Read the BootOrder, or DriverOrder variable.
+    //
+    GetEfiGlobalVariable2 (mBmLoadOptionOrderName[LoadOptionType], (VOID **) 
&OptionOrder, &OptionOrderSize);
+    if (OptionOrder == NULL) {
+      return NULL;
+    }
 
-  *OptionCount = OptionOrderSize / sizeof (UINT16);
+    *OptionCount = OptionOrderSize / sizeof (UINT16);
 
-  Option = AllocatePool (*OptionCount * sizeof (EFI_BOOT_MANAGER_LOAD_OPTION));
-  ASSERT (Option != NULL);
+    Options = AllocatePool (*OptionCount * sizeof 
(EFI_BOOT_MANAGER_LOAD_OPTION));
+    ASSERT (Options != NULL);
 
-  OptionIndex = 0;
-  for (Index = 0; Index < *OptionCount; Index++) {
-    OptionNumber = OptionOrder[Index];
-    if (LoadOptionType == LoadOptionTypeBoot) {
-      UnicodeSPrint (OptionName, sizeof (OptionName), L"Boot%04x", 
OptionNumber);
-    } else {
-      UnicodeSPrint (OptionName, sizeof (OptionName), L"Driver%04x", 
OptionNumber);
+    OptionIndex = 0;
+    for (Index = 0; Index < *OptionCount; Index++) {
+      OptionNumber = OptionOrder[Index];
+      UnicodeSPrint (OptionName, sizeof (OptionName), L"%s%04x", 
mBmLoadOptionName[LoadOptionType], OptionNumber);
+
+      Status = EfiBootManagerVariableToLoadOption (OptionName, 
&Options[OptionIndex]);
+      if (EFI_ERROR (Status)) {
+        DEBUG ((EFI_D_INFO, "[Bds] %s doesn't exist - Update ****Order 
variable to remove the reference!!", OptionName));
+        EfiBootManagerDeleteLoadOptionVariable (OptionNumber, LoadOptionType);
+      } else {
+        ASSERT (Options[OptionIndex].OptionNumber == OptionNumber);
+        OptionIndex++;
+      }
     }
 
-    Status = EfiBootManagerVariableToLoadOption (OptionName, 
&Option[OptionIndex]);
-    if (EFI_ERROR (Status)) {
-      DEBUG ((EFI_D_INFO, "[Bds] %s doesn't exist - Update ****Order variable 
to remove the reference!!", OptionName));
-      EfiBootManagerDeleteLoadOptionVariable (OptionNumber, 
LoadOptionTypeBoot);
-    } else {
-      ASSERT (Option[OptionIndex].OptionNumber == OptionNumber);
-      OptionIndex++;
+    if (OptionOrder != NULL) {
+      FreePool (OptionOrder);
     }
-  }
 
-  if (OptionOrder != NULL) {
-    FreePool (OptionOrder);
-  }
+    if (OptionIndex < *OptionCount) {
+      Options = ReallocatePool (*OptionCount * sizeof 
(EFI_BOOT_MANAGER_LOAD_OPTION), OptionIndex * sizeof 
(EFI_BOOT_MANAGER_LOAD_OPTION), Options);
+      ASSERT (Options != NULL);
+      *OptionCount = OptionIndex;
+    }
 
-  if (OptionIndex < *OptionCount) {
-    Option = ReallocatePool (
-               *OptionCount * sizeof (EFI_BOOT_MANAGER_LOAD_OPTION),
-               OptionIndex * sizeof (EFI_BOOT_MANAGER_LOAD_OPTION),
-               Option
-               );
-    ASSERT (Option != NULL);
-    *OptionCount = OptionIndex;
+  } else {
+    return NULL;
   }
 
-  return Option;
+  return Options;
 }
 
 /**
@@ -980,3 +1076,173 @@
 
   return EFI_SUCCESS;
 }
+
+/**
+  Return whether the PE header of the load option is valid or not.
+
+  @param[in] Type       The load option type.
+  @param[in] FileBuffer The PE file buffer of the load option.
+  @param[in] FileSize   The size of the load option file.
+
+  @retval TRUE  The PE header of the load option is valid.
+  @retval FALSE The PE header of the load option is not valid.
+**/
+BOOLEAN
+BmIsLoadOptionPeHeaderValid (
+  IN EFI_BOOT_MANAGER_LOAD_OPTION_TYPE Type,
+  IN VOID                              *FileBuffer,
+  IN UINTN                             FileSize
+  )
+{
+  EFI_IMAGE_DOS_HEADER              *DosHeader;
+  EFI_IMAGE_OPTIONAL_HEADER_UNION   *PeHeader;
+  EFI_IMAGE_OPTIONAL_HEADER32       *OptionalHeader;
+  UINT16                            Subsystem;
+
+  if (FileBuffer == NULL || FileSize == 0) {
+    return FALSE;
+  }
+
+  //
+  // Read dos header
+  //
+  DosHeader = (EFI_IMAGE_DOS_HEADER *) FileBuffer;
+  if (FileSize >= sizeof (EFI_IMAGE_DOS_HEADER) &&
+      FileSize > DosHeader->e_lfanew && DosHeader->e_magic == 
EFI_IMAGE_DOS_SIGNATURE
+      ) {
+    //
+    // Read and check PE signature
+    //
+    PeHeader = (EFI_IMAGE_OPTIONAL_HEADER_UNION *) ((UINT8 *) FileBuffer + 
DosHeader->e_lfanew);
+    if (FileSize >= DosHeader->e_lfanew + sizeof 
(EFI_IMAGE_OPTIONAL_HEADER_UNION) &&
+        PeHeader->Pe32.Signature == EFI_IMAGE_NT_SIGNATURE
+        ) {
+      //
+      // Check PE32 or PE32+ magic, and machine type
+      //
+      OptionalHeader = (EFI_IMAGE_OPTIONAL_HEADER32 *) 
&PeHeader->Pe32.OptionalHeader;
+      if ((OptionalHeader->Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC || 
+           OptionalHeader->Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) &&
+          EFI_IMAGE_MACHINE_TYPE_SUPPORTED (PeHeader->Pe32.FileHeader.Machine)
+          ) {
+        //
+        // Check the Subsystem:
+        //   Driver#### must be of type BootServiceDriver or RuntimeDriver
+        //   SysPrep####, Boot####, OsRecovery####, PlatformRecovery#### must 
be of type Application
+        //
+        Subsystem = OptionalHeader->Subsystem;
+        if ((Type == LoadOptionTypeDriver && Subsystem == 
EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER) ||
+            (Type == LoadOptionTypeDriver && Subsystem == 
EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER) ||
+            (Type == LoadOptionTypeSysPrep && Subsystem == 
EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION) ||
+            (Type == LoadOptionTypeBoot && Subsystem == 
EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION)
+            ) {
+          return TRUE;
+        }
+      }
+    }
+  }
+
+  return FALSE;
+}
+
+/**
+  Process (load and execute) the load option.
+
+  @param LoadOption  Pointer to the load option.
+
+  @retval EFI_INVALID_PARAMETER  The load option type is invalid, 
+                                 or the load option file path doesn't point to 
a valid file.
+  @retval EFI_UNSUPPORTED        The load option type is of LoadOptionTypeBoot.
+  @retval EFI_SUCCESS            The load option is inactive, or successfully 
loaded and executed.
+**/
+EFI_STATUS
+EFIAPI
+EfiBootManagerProcessLoadOption (
+  IN EFI_BOOT_MANAGER_LOAD_OPTION       *LoadOption
+  )
+{
+  EFI_STATUS                        Status;
+  EFI_DEVICE_PATH_PROTOCOL          *FilePath;
+  EFI_HANDLE                        ImageHandle;
+  EFI_LOADED_IMAGE_PROTOCOL         *ImageInfo;
+  VOID                              *FileBuffer;
+  UINTN                             FileSize;
+
+  if ((UINT32) LoadOption->OptionType >= LoadOptionTypeMax) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if (LoadOption->OptionType == LoadOptionTypeBoot) {
+    return EFI_UNSUPPORTED;
+  }
+
+  //
+  // If a load option is not marked as LOAD_OPTION_ACTIVE,
+  // the boot manager will not automatically load the option.
+  //
+  if ((LoadOption->Attributes & LOAD_OPTION_ACTIVE) == 0) {
+    return EFI_SUCCESS;
+  }
+
+  Status = EFI_INVALID_PARAMETER;
+
+  //
+  // Load and start the load option.
+  //
+  DEBUG ((
+    DEBUG_INFO | DEBUG_LOAD, "Process Load Option (%s%04x) ...\n",
+    mBmLoadOptionName[LoadOption->OptionType], LoadOption->OptionNumber
+    ));
+  ImageHandle = NULL;
+  FileBuffer = BmGetLoadOptionBuffer (LoadOption->FilePath, &FilePath, 
&FileSize);
+  DEBUG_CODE (
+    if (FileBuffer != NULL && CompareMem (LoadOption->FilePath, FilePath, 
GetDevicePathSize (FilePath)) != 0) {
+      DEBUG ((EFI_D_INFO, "[Bds] DevicePath expand: "));
+      BmPrintDp (LoadOption->FilePath);
+      DEBUG ((EFI_D_INFO, " -> "));
+      BmPrintDp (FilePath);
+      DEBUG ((EFI_D_INFO, "\n"));
+    }
+  );
+  if (BmIsLoadOptionPeHeaderValid (LoadOption->OptionType, FileBuffer, 
FileSize)) {
+    Status = gBS->LoadImage (
+                    FALSE,
+                    gImageHandle,
+                    FilePath,
+                    FileBuffer,
+                    FileSize,
+                    &ImageHandle
+                    );
+  }
+  if (FilePath != NULL) {
+    FreePool (FilePath);
+  }
+  if (FileBuffer != NULL) {
+    FreePool (FileBuffer);
+  }
+
+  if (!EFI_ERROR (Status)) {
+    Status = gBS->HandleProtocol (ImageHandle, &gEfiLoadedImageProtocolGuid, 
(VOID **) &ImageInfo);
+    ASSERT_EFI_ERROR (Status);
+
+    ImageInfo->LoadOptionsSize = LoadOption->OptionalDataSize;
+    ImageInfo->LoadOptions = LoadOption->OptionalData;
+    //
+    // Before calling the image, enable the Watchdog Timer for the 5-minute 
period
+    //
+    gBS->SetWatchdogTimer (5 * 60, 0, 0, NULL);
+
+    LoadOption->Status = gBS->StartImage (ImageHandle, 
&LoadOption->ExitDataSize, &LoadOption->ExitData);
+    DEBUG ((
+      DEBUG_INFO | DEBUG_LOAD, "Load Option (%s%04x) Return Status = %r\n",
+      mBmLoadOptionName[LoadOption->OptionType], LoadOption->OptionNumber, 
LoadOption->Status
+      ));
+
+    //
+    // Clear the Watchdog Timer after the image returns
+    //
+    gBS->SetWatchdogTimer (0, 0, 0, NULL);
+  }
+
+  return Status;
+}

Modified: trunk/edk2/MdeModulePkg/Library/UefiBootManagerLib/BmMisc.c
===================================================================
--- trunk/edk2/MdeModulePkg/Library/UefiBootManagerLib/BmMisc.c 2015-05-11 
06:32:51 UTC (rev 17402)
+++ trunk/edk2/MdeModulePkg/Library/UefiBootManagerLib/BmMisc.c 2015-05-11 
06:33:45 UTC (rev 17403)
@@ -121,146 +121,6 @@
 }
 
 /**
-  Get the headers (dos, image, optional header) from an image
-
-  @param  Device                SimpleFileSystem device handle
-  @param  FileName              File name for the image
-  @param  DosHeader             Pointer to dos header
-  @param  Hdr                   The buffer in which to return the PE32, PE32+, 
or TE header.
-
-  @retval EFI_SUCCESS           Successfully get the machine type.
-  @retval EFI_NOT_FOUND         The file is not found.
-  @retval EFI_LOAD_ERROR        File is not a valid image file.
-
-**/
-EFI_STATUS
-BmGetImageHeader (
-  IN  EFI_HANDLE                  Device,
-  IN  CHAR16                      *FileName,
-  OUT EFI_IMAGE_DOS_HEADER        *DosHeader,
-  OUT EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION   Hdr
-  )
-{
-  EFI_STATUS                       Status;
-  EFI_SIMPLE_FILE_SYSTEM_PROTOCOL  *Volume;
-  EFI_FILE_HANDLE                  Root;
-  EFI_FILE_HANDLE                  ThisFile;
-  UINTN                            BufferSize;
-  UINT64                           FileSize;
-  EFI_FILE_INFO                    *Info;
-
-  Root     = NULL;
-  ThisFile = NULL;
-  //
-  // Handle the file system interface to the device
-  //
-  Status = gBS->HandleProtocol (
-                  Device,
-                  &gEfiSimpleFileSystemProtocolGuid,
-                  (VOID *) &Volume
-                  );
-  if (EFI_ERROR (Status)) {
-    goto Done;
-  }
-
-  Status = Volume->OpenVolume (
-                     Volume,
-                     &Root
-                     );
-  if (EFI_ERROR (Status)) {
-    Root = NULL;
-    goto Done;
-  }
-  ASSERT (Root != NULL);
-  Status = Root->Open (Root, &ThisFile, FileName, EFI_FILE_MODE_READ, 0);
-  if (EFI_ERROR (Status)) {
-    goto Done;
-  }
-  ASSERT (ThisFile != NULL);
-
-  //
-  // Get file size
-  //
-  BufferSize  = SIZE_OF_EFI_FILE_INFO + 200;
-  do {
-    Info   = NULL;
-    Status = gBS->AllocatePool (EfiBootServicesData, BufferSize, (VOID **) 
&Info);
-    if (EFI_ERROR (Status)) {
-      goto Done;
-    }
-    Status = ThisFile->GetInfo (
-                         ThisFile,
-                         &gEfiFileInfoGuid,
-                         &BufferSize,
-                         Info
-                         );
-    if (!EFI_ERROR (Status)) {
-      break;
-    }
-    if (Status != EFI_BUFFER_TOO_SMALL) {
-      FreePool (Info);
-      goto Done;
-    }
-    FreePool (Info);
-  } while (TRUE);
-
-  FileSize = Info->FileSize;
-  FreePool (Info);
-
-  //
-  // Read dos header
-  //
-  BufferSize = sizeof (EFI_IMAGE_DOS_HEADER);
-  Status = ThisFile->Read (ThisFile, &BufferSize, DosHeader);
-  if (EFI_ERROR (Status) ||
-      BufferSize < sizeof (EFI_IMAGE_DOS_HEADER) ||
-      FileSize <= DosHeader->e_lfanew ||
-      DosHeader->e_magic != EFI_IMAGE_DOS_SIGNATURE) {
-    Status = EFI_LOAD_ERROR;
-    goto Done;
-  }
-
-  //
-  // Move to PE signature
-  //
-  Status = ThisFile->SetPosition (ThisFile, DosHeader->e_lfanew);
-  if (EFI_ERROR (Status)) {
-    Status = EFI_LOAD_ERROR;
-    goto Done;
-  }
-
-  //
-  // Read and check PE signature
-  //
-  BufferSize = sizeof (EFI_IMAGE_OPTIONAL_HEADER_UNION);
-  Status = ThisFile->Read (ThisFile, &BufferSize, Hdr.Pe32);
-  if (EFI_ERROR (Status) ||
-      BufferSize < sizeof (EFI_IMAGE_OPTIONAL_HEADER_UNION) ||
-      Hdr.Pe32->Signature != EFI_IMAGE_NT_SIGNATURE) {
-    Status = EFI_LOAD_ERROR;
-    goto Done;
-  }
-
-  //
-  // Check PE32 or PE32+ magic
-  //
-  if (Hdr.Pe32->OptionalHeader.Magic != EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC &&
-      Hdr.Pe32->OptionalHeader.Magic != EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
-    Status = EFI_LOAD_ERROR;
-    goto Done;
-  }
-
- Done:
-  if (ThisFile != NULL) {
-    ThisFile->Close (ThisFile);
-  }
-  if (Root != NULL) {
-    Root->Close (Root);
-  }
-  return Status;
-}
-
-/**
   This routine adjust the memory information for different memory type and 
   save them into the variables for next boot.
 **/
@@ -505,3 +365,22 @@
   return Status;
 }
 
+
+/**
+  Print the device path info.
+
+  @param DevicePath           The device path need to print.
+**/
+VOID
+BmPrintDp (
+  EFI_DEVICE_PATH_PROTOCOL            *DevicePath
+  )
+{
+  CHAR16                              *Str;
+
+  Str = ConvertDevicePathToText (DevicePath, FALSE, FALSE);
+  DEBUG ((EFI_D_INFO, "%s", Str));
+  if (Str != NULL) {
+    FreePool (Str);
+  }
+}

Modified: trunk/edk2/MdeModulePkg/Library/UefiBootManagerLib/InternalBm.h
===================================================================
--- trunk/edk2/MdeModulePkg/Library/UefiBootManagerLib/InternalBm.h     
2015-05-11 06:32:51 UTC (rev 17402)
+++ trunk/edk2/MdeModulePkg/Library/UefiBootManagerLib/InternalBm.h     
2015-05-11 06:33:45 UTC (rev 17403)
@@ -100,6 +100,37 @@
   IN EFI_HANDLE          Handle
   );
 
+#define BM_OPTION_NAME_LEN                          sizeof ("SysPrep####")
+extern CHAR16  *mBmLoadOptionName[];
+
+typedef
+VOID
+(*VARIABLE_VISITOR) (
+  CHAR16                *Name,
+  EFI_GUID              *Guid,
+  VOID                  *Context
+  );
+
+/**
+  Call Visitor function for each variable in variable storage.
+
+  @param Visitor   Visitor function.
+  @param Context   The context passed to Visitor function.
+**/
+VOID
+ForEachVariable (
+  VARIABLE_VISITOR            Visitor,
+  VOID                        *Context
+  );
+
+/**
+  Repair all the controllers according to the Driver Health status queried.
+**/
+VOID
+BmRepairAllControllers (
+  VOID
+  );
+
 #define BM_HOTKEY_SIGNATURE SIGNATURE_32 ('b', 'm', 'h', 'k')
 typedef struct {
   UINT32                    Signature;
@@ -139,7 +170,7 @@
 /**
   Get the Option Number that wasn't used.
 
-  @param  OrderVariableName   Could be L"BootOrder" or L"DriverOrder".
+  @param  LoadOptionType      Load option type.
   @param  FreeOptionNumber    To receive the minimal free option number.
 
   @retval EFI_SUCCESS           The option number is found
@@ -149,8 +180,8 @@
 **/
 EFI_STATUS
 BmGetFreeOptionNumber (
-  IN  CHAR16    *OrderVariableName,
-  OUT UINT16    *FreeOptionNumber
+  IN  EFI_BOOT_MANAGER_LOAD_OPTION_TYPE LoadOptionType,
+  OUT UINT16                            *FreeOptionNumber
   );
 
 /**
@@ -295,6 +326,42 @@
   );
 
 /**
+  Get the load option by its device path.
+
+  @param FilePath  The device path pointing to a load option.
+                   It could be a short-form device path.
+  @param FullPath  Return the full device path of the load option after
+                   short-form device path expanding.
+                   Caller is responsible to free it.
+  @param FileSize  Return the load option size.
+
+  @return The load option buffer. Caller is responsible to free the memory.
+**/
+VOID *
+BmGetLoadOptionBuffer (
+  IN  EFI_DEVICE_PATH_PROTOCOL          *FilePath,
+  OUT EFI_DEVICE_PATH_PROTOCOL          **FullPath,
+  OUT UINTN                             *FileSize
+  );
+
+/**
+  Return whether the PE header of the load option is valid or not.
+
+  @param[in] Type       The load option type.
+  @param[in] FileBuffer The PE file buffer of the load option.
+  @param[in] FileSize   The size of the load option file.
+
+  @retval TRUE  The PE header of the load option is valid.
+  @retval FALSE The PE header of the load option is not valid.
+**/
+BOOLEAN
+BmIsLoadOptionPeHeaderValid (
+  IN EFI_BOOT_MANAGER_LOAD_OPTION_TYPE Type,
+  IN VOID                              *FileBuffer,
+  IN UINTN                             FileSize
+  );
+
+/**
   Function compares a device path data structure to that of all the nodes of a
   second device path instance.
 
@@ -361,4 +428,14 @@
   VOID
   );
 
+/**
+  Print the device path info.
+
+  @param DevicePath           The device path need to print.
+**/
+VOID
+BmPrintDp (
+  EFI_DEVICE_PATH_PROTOCOL            *DevicePath
+  );
+
 #endif // _INTERNAL_BM_H_

Modified: trunk/edk2/MdeModulePkg/Universal/BdsDxe/BdsEntry.c
===================================================================
--- trunk/edk2/MdeModulePkg/Universal/BdsDxe/BdsEntry.c 2015-05-11 06:32:51 UTC 
(rev 17402)
+++ trunk/edk2/MdeModulePkg/Universal/BdsDxe/BdsEntry.c 2015-05-11 06:33:45 UTC 
(rev 17403)
@@ -47,6 +47,12 @@
   EFI_OS_INDICATIONS_SUPPORT_VARIABLE_NAME
   };
 
+CHAR16 *mBdsLoadOptionName[] = {
+  L"Driver",
+  L"SysPrep",
+  L"Boot"
+};
+
 CHAR16  mRecoveryBoot[] = L"Recovery Boot";
 /**
   Event to Connect ConIn.
@@ -75,7 +81,7 @@
     // Should not enter this case, if enter, the keyboard will not work.
     // May need platfrom policy to connect keyboard.
     //
-    DEBUG ((EFI_D_WARN, "[Bds] ASSERT Connect ConIn failed!!!\n"));
+    DEBUG ((EFI_D_WARN, "[Bds] Connect ConIn failed - %r!!!\n", Status));
   }
 }
 
@@ -553,103 +559,55 @@
 }
 
 /**
-  The function will go through the driver option link list, load and start
-  every driver the driver option device path point to.
+  The function will load and start every Driver####/SysPrep####.
 
-  @param  DriverOption        Input driver option array.
-  @param  DriverOptionCount   Input driver option count.
+  @param  LoadOptions        Load option array.
+  @param  LoadOptionCount    Load option count.
 
 **/
 VOID
-LoadDrivers (
-  IN EFI_BOOT_MANAGER_LOAD_OPTION       *DriverOption,
-  IN UINTN                              DriverOptionCount
+ProcessLoadOptions (
+  IN EFI_BOOT_MANAGER_LOAD_OPTION       *LoadOptions,
+  IN UINTN                              LoadOptionCount
   )
 {
-  EFI_STATUS                Status;
-  UINTN                     Index;
-  EFI_HANDLE                ImageHandle;
-  EFI_LOADED_IMAGE_PROTOCOL *ImageInfo;
-  BOOLEAN                   ReconnectAll;
+  EFI_STATUS                        Status;
+  UINTN                             Index;
+  BOOLEAN                           ReconnectAll;
+  EFI_BOOT_MANAGER_LOAD_OPTION_TYPE LoadOptionType;
 
   ReconnectAll = FALSE;
+  LoadOptionType = LoadOptionTypeMax;
 
   //
   // Process the driver option
   //
-  for (Index = 0; Index < DriverOptionCount; Index++) {
+  for (Index = 0; Index < LoadOptionCount; Index++) {
     //
-    // If a load option is not marked as LOAD_OPTION_ACTIVE,
-    // the boot manager will not automatically load the option.
+    // All the load options in the array should be of the same type.
     //
-    if ((DriverOption[Index].Attributes & LOAD_OPTION_ACTIVE) == 0) {
-      continue;
+    if (LoadOptionType == LoadOptionTypeMax) {
+      LoadOptionType = LoadOptions[Index].OptionType;
     }
-    
-    //
-    // If a driver load option is marked as LOAD_OPTION_FORCE_RECONNECT,
-    // then all of the EFI drivers in the system will be disconnected and
-    // reconnected after the last driver load option is processed.
-    //
-    if ((DriverOption[Index].Attributes & LOAD_OPTION_FORCE_RECONNECT) != 0) {
-      ReconnectAll = TRUE;
-    }
-    
-    //
-    // Make sure the driver path is connected.
-    //
-    EfiBootManagerConnectDevicePath (DriverOption[Index].FilePath, NULL);
+    ASSERT (LoadOptionType == LoadOptions[Index].OptionType);
+    ASSERT (LoadOptionType == LoadOptionTypeDriver || LoadOptionType == 
LoadOptionTypeSysPrep);
 
-    //
-    // Load and start the image that Driver#### describes
-    //
-    Status = gBS->LoadImage (
-                    FALSE,
-                    gImageHandle,
-                    DriverOption[Index].FilePath,
-                    NULL,
-                    0,
-                    &ImageHandle
-                    );
+    Status = EfiBootManagerProcessLoadOption (&LoadOptions[Index]);
 
-    if (!EFI_ERROR (Status)) {
-      gBS->HandleProtocol (ImageHandle, &gEfiLoadedImageProtocolGuid, (VOID 
**) &ImageInfo);
-
-      //
-      // Verify whether this image is a driver, if not,
-      // exit it and continue to parse next load option
-      //
-      if (ImageInfo->ImageCodeType != EfiBootServicesCode && 
ImageInfo->ImageCodeType != EfiRuntimeServicesCode) {
-        gBS->Exit (ImageHandle, EFI_INVALID_PARAMETER, 0, NULL);
-        continue;
-      }
-
-      ImageInfo->LoadOptionsSize  = DriverOption[Index].OptionalDataSize;
-      ImageInfo->LoadOptions      = DriverOption[Index].OptionalData;
-      //
-      // Before calling the image, enable the Watchdog Timer for
-      // the 5 Minute period
-      //

@@ Diff output truncated at 100000 characters. @@

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

Reply via email to