]> git.proxmox.com Git - mirror_edk2.git/commitdiff
MdeModulePkg: Process Sys Prep load options in BdsDxe driver.
authorRuiyu Ni <ruiyu.ni@intel.com>
Mon, 11 May 2015 06:33:45 +0000 (06:33 +0000)
committerniruiyu <niruiyu@Edk2>
Mon, 11 May 2015 06:33:45 +0000 (06:33 +0000)
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Ruiyu Ni <ruiyu.ni@intel.com>
Reviewed-by: Eric Dong <eric.dong@intel.com>
git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@17403 6f19259b-4bc3-4df7-8a09-765794883524

MdeModulePkg/Include/Library/UefiBootManagerLib.h
MdeModulePkg/Library/UefiBootManagerLib/BmBoot.c
MdeModulePkg/Library/UefiBootManagerLib/BmConnect.c
MdeModulePkg/Library/UefiBootManagerLib/BmConsole.c
MdeModulePkg/Library/UefiBootManagerLib/BmLoadOption.c
MdeModulePkg/Library/UefiBootManagerLib/BmMisc.c
MdeModulePkg/Library/UefiBootManagerLib/InternalBm.h
MdeModulePkg/Universal/BdsDxe/BdsEntry.c

index 9b08364aaf35418c78c035cb17fee42a82fafc23..2ec80894adc65d531ba7dd8962a73932d74a6748 100644 (file)
@@ -27,8 +27,9 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 // Load Option Type
 //
 typedef enum {
-  LoadOptionTypeBoot,
   LoadOptionTypeDriver,
+  LoadOptionTypeSysPrep,
+  LoadOptionTypeBoot,
   LoadOptionTypeMax
 } EFI_BOOT_MANAGER_LOAD_OPTION_TYPE;
 
@@ -51,6 +52,7 @@ typedef struct {
   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 @@ EfiBootManagerLoadOptionToVariable (
   );
 
 /**
-  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 @@ EfiBootManagerConnectAll (
 /**
   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 @@ typedef enum {
 /**
   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 @@ EfiBootManagerFreeDriverHealthInfo (
   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
index ddda9ae605bc90c704a500f7ba05d3eb6abaa402..8d1a8c9d2355759cb5fc868a4b949d24a2f92c93 100644 (file)
@@ -71,7 +71,7 @@ EfiBootManagerRegisterLegacyBootSupport (
 
 **/
 BM_BOOT_TYPE
-BmBootTypeFromDevicePath (
+BmDevicePathType (
   IN  EFI_DEVICE_PATH_PROTOCOL     *DevicePath
   )
 {
@@ -144,22 +144,6 @@ BmBootTypeFromDevicePath (
   return BmMiscBoot;
 }
 
-/**
-  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.
 
@@ -176,7 +160,7 @@ BmFindBootOptionInVariable (
   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 @@ BmFindBootOptionInVariable (
   // 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 @@ BmFindBootOptionInVariable (
 }
 
 /**
-  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.
+
+  FV address may change across reboot. This routine promises the FV file device path is right.
 
-  @param  DevicePath   The Fv file device path to be fixed up.
+  @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 @@ BmFixupMemmapFvFilePath (
          &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 @@ BmFixupMemmapFvFilePath (
          &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 @@ BmGetMiscDescription (
   CHAR16                         *Description;
   EFI_BLOCK_IO_PROTOCOL          *BlockIo;
 
-  switch (BmBootTypeFromDevicePath (DevicePathFromHandle (Handle))) {
+  switch (BmDevicePathType (DevicePathFromHandle (Handle))) {
   case BmAcpiFloppyBoot:
     Description = L"Floppy";
     break;
@@ -824,26 +801,6 @@ BmMatchUsbWwid (
   return FALSE;
 }
 
-/**
-  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
@@ -944,97 +901,105 @@ BmFindUsbDevice (
      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 @@ BmExpandUsbShortFormDevicePath (
   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 @@ BmExpandPartitionShortFormDevicePath (
 
   if (CachedDevicePath != NULL) {
     TempNewDevicePath = CachedDevicePath;
-    DeviceExist = FALSE;
     NeedAdjust = FALSE;
     do {
       //
@@ -1107,15 +1074,40 @@ BmExpandPartitionShortFormDevicePath (
       // 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 @@ BmExpandPartitionShortFormDevicePath (
       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 @@ BmExpandPartitionShortFormDevicePath (
   // 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) {
-        //
-        // Save the matched partition device path as first instance of 'HDDP' variable
-        //
-        if (BmMatchDevicePaths (CachedDevicePath, BlockIoDevicePath)) {
-          TempNewDevicePath = CachedDevicePath;
-          CachedDevicePath = BmDelPartMatchInstance (CachedDevicePath, BlockIoDevicePath);
-          FreePool(TempNewDevicePath);
-        }
-
-        if (CachedDevicePath != NULL) {
-          TempNewDevicePath = CachedDevicePath;
-          CachedDevicePath = AppendDevicePathInstance (BlockIoDevicePath, CachedDevicePath);
-          FreePool(TempNewDevicePath);
-        } else {
-          CachedDevicePath = DuplicateDevicePath (BlockIoDevicePath);
-        }
+      if (FileBuffer != NULL) {
+        BmCachePartitionDevicePath (&CachedDevicePath, 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.
+        // 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
         //
-        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);
-      }
-
-      //
-      // 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
-                      );
+        Status = gRT->SetVariable (
+                        L"HDDP",
+                        &mBmHardDriveBootVariableGuid,
+                        EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE,
+                        GetDevicePathSize (CachedDevicePath),
+                        CachedDevicePath
+                        );
 
-      break;
+        break;
+      }
     }
   }
 
@@ -1267,92 +1171,92 @@ BmExpandPartitionShortFormDevicePath (
   if (BlockIoBuffer != NULL) {
     FreePool (BlockIoBuffer);
   }
-  BmFreeAndSet ((VOID **) DevicePath, FullDevicePath);
+  return FileBuffer;
 }
 
 /**
-  Algorithm follows the UEFI Spec chapter 3.4 Boot Mechanisms.
-
-  @param  DevicePath  Device Path to a  bootable device
+  Expand the media device path which points to a BlockIo or SimpleFileSystem instance
+  by appending EFI_REMOVABLE_MEDIA_FILE_NAME.
 
-  @return  The bootable media handle. If the media on the DevicePath is not bootable, NULL will return.
+  @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 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;
-
-  ReturnHandle      = NULL;
-  UpdatedDevicePath = DevicePath;
+  VOID                                *FileBuffer;
+  UINT32                              AuthenticationStatus;
 
   //
   // 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);
-    }
-  } 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);
+  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;
     }
+    *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 @@ BmGetBootableDeviceHandle (
     // 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. 
-
-  @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.
-
-  @retval NULL   The file can't be found.
-  @retval other  The file buffer. The caller is responsible to free memory.
+  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 *
-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,50 +1358,34 @@ BmLoadEfiBootOption (
       //
       // 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 (FileBuffer == NULL) {
-    FileBuffer = GetFileBufferByFilePath (TRUE, *FilePath, FileSize, &AuthenticationStatus);
+  if (BmIsMemmapFvFilePath (FilePath)) {
+    return BmGetFileBufferByMemmapFv (FilePath, FullPath, FileSize);
   }
 
   //
-  // 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);
-    }
-  }
-
-  if (FileBuffer == NULL) {
-    BmFreeAndSet ((VOID **) FilePath, NULL);
+  FileBuffer = GetFileBufferByFilePath (TRUE, FilePath, FileSize, &AuthenticationStatus);
+  if (FileBuffer != NULL) {
+    *FullPath = DuplicateDevicePath (FilePath);
   }
 
   return FileBuffer;
@@ -1547,7 +1435,7 @@ EfiBootManagerBoot (
     return;
   }
 
-  if (BootOption->FilePath == NULL) {
+  if (BootOption->FilePath == NULL || BootOption->OptionType != LoadOptionTypeBoot) {
     BootOption->Status = EFI_INVALID_PARAMETER;
     return;
   }
@@ -1557,7 +1445,7 @@ EfiBootManagerBoot (
   //
   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 @@ EfiBootManagerBoot (
     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 @@ EfiBootManagerBoot (
   // 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 @@ EfiBootManagerBoot (
                       FileSize,
                       &ImageHandle
                       );
+    }
+    if (FileBuffer != NULL) {
       FreePool (FileBuffer);
+    }
+    if (FilePath != NULL) {
       FreePool (FilePath);
     }
 
@@ -1790,63 +1691,44 @@ BmMatchPartitionDevicePathNode (
   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)
+    );
 }
 
 /**
index 0172f959d752b4f4c60316895ad5c5de586528cd..9e3a683e25f9a7958147df093e1b989dbd73606e 100644 (file)
@@ -102,12 +102,13 @@ EfiBootManagerConnectAll (
                                 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 @@ EfiBootManagerConnectDevicePath (
         // 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 @@ EfiBootManagerConnectDevicePath (
         //    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;
         }
index 49b99957e0a483d7e1b061a5cffee009fcb86b33..4f5c8b04c2106e4bdcd5d00874e37a87bdc19595 100644 (file)
@@ -695,28 +695,42 @@ EfiBootManagerConnectAllConsoles (
 /**
   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 @@ EfiBootManagerConnectAllDefaultConsoles (
           &gST->Hdr.CRC32
           );
   }
+
+  return OneConnected ? EFI_SUCCESS : EFI_DEVICE_ERROR;
 }
index fc3e29a62ed171829b8a5a8c2f87e8f28cdb7f71..27a8db733e5f555c19e1a77b494464bf77a120cb 100644 (file)
@@ -14,21 +14,77 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 
 #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 @@ BmGetFreeOptionNumber (
   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 @@ BmGetFreeOptionNumber (
 }
 
 /**
-  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 @@ EfiBootManagerLoadOptionToVariable (
   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 @@ structure.
 
   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 @@ EfiBootManagerAddLoadOptionVariable (
     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 @@ EfiBootManagerAddLoadOptionVariable (
     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 @@ EfiBootManagerAddLoadOptionVariable (
     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 @@ EfiBootManagerSortLoadOptionVariable (
   }
 
   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 @@ EfiBootManagerInitializeLoadOption (
     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 @@ BmFindLoadOption (
 }
 
 /**
-  Update the BootOrder or DriverOrder to delete OptionNumber .
-
-  @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;
-}
+  Delete the load option.
 
-/**
-  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 @@ EfiBootManagerDeleteLoadOptionVariable (
   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 @@ BmCharToUint (
   }
 
   ASSERT (FALSE);
-  return 0;
+  return (UINTN) -1;
 }
 
 /**
@@ -645,10 +693,10 @@ BmStrSizeEx (
 }
 
 /**
-  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 @@ BmValidateOption (
   )
 {
   UINT16                    FilePathSize;
-  UINT8                     *TempPtr;
   EFI_DEVICE_PATH_PROTOCOL  *DevicePath;
-  UINTN                     TempSize;
+  UINTN                     DescriptionSize;
 
   if (VariableSize <= sizeof (UINT16) + sizeof (UINT32)) {
     return FALSE;
@@ -672,47 +719,100 @@ BmValidateOption (
   //
   // 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;
   }
 
   return (BOOLEAN) (BmGetDevicePathSizeEx (DevicePath, FilePathSize) != 0);
 }
 
+/**
+  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 @@ BmValidateOption (
 **/
 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,80 +843,62 @@ EfiBootManagerVariableToLoadOption (
     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);
     return EFI_INVALID_PARAMETER;
   }
 
-  //
-  // 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,11 +910,32 @@ EfiBootManagerVariableToLoadOption (
              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.
@@ -857,63 +960,56 @@ EfiBootManagerGetLoadOptions (
   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 @@ EfiBootManagerFreeLoadOptions (
 
   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;
+}
index 1cfb4bb039c55c9b43c07eb17bcde55d05860ca7..30d955111ec8ae3032e8327a9bb771f21f299051 100644 (file)
@@ -120,146 +120,6 @@ BmMatchDevicePaths (
   return FALSE;
 }
 
-/**
-  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 @@ BmSetVariableAndReportStatusCodeOnError (
   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);
+  }
+}
index c8dc226058d196da7f4ba2f28681ea8b23134c71..c362d8d7cc8a52a79173ff61a134cbd7ce554b98 100644 (file)
@@ -100,6 +100,37 @@ CHAR16 *
   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 @@ BmLoadEfiBootOption (
 /**
   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 @@ BmLoadEfiBootOption (
 **/
 EFI_STATUS
 BmGetFreeOptionNumber (
-  IN  CHAR16    *OrderVariableName,
-  OUT UINT16    *FreeOptionNumber
+  IN  EFI_BOOT_MANAGER_LOAD_OPTION_TYPE LoadOptionType,
+  OUT UINT16                            *FreeOptionNumber
   );
 
 /**
@@ -294,6 +325,42 @@ BmSetVariableAndReportStatusCodeOnError (
   IN VOID       *Data
   );
 
+/**
+  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 @@ BmRepairAllControllers (
   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_
index 7eebe8402110f0d9cab239ab1c27eb6a9b02bb20..020f18d48c3a7bb0d0cf8d59f7dcf536d4b45caa 100644 (file)
@@ -47,6 +47,12 @@ CHAR16  *mReadOnlyVariables[] = {
   EFI_OS_INDICATIONS_SUPPORT_VARIABLE_NAME\r
   };\r
 \r
+CHAR16 *mBdsLoadOptionName[] = {\r
+  L"Driver",\r
+  L"SysPrep",\r
+  L"Boot"\r
+};\r
+\r
 CHAR16  mRecoveryBoot[] = L"Recovery Boot";\r
 /**\r
   Event to Connect ConIn.\r
@@ -75,7 +81,7 @@ BdsDxeOnConnectConInCallBack (
     // Should not enter this case, if enter, the keyboard will not work.\r
     // May need platfrom policy to connect keyboard.\r
     //\r
-    DEBUG ((EFI_D_WARN, "[Bds] ASSERT Connect ConIn failed!!!\n"));\r
+    DEBUG ((EFI_D_WARN, "[Bds] Connect ConIn failed - %r!!!\n", Status));\r
   }\r
 }\r
 \r
@@ -553,103 +559,55 @@ DefaultBootBehavior (
 }\r
 \r
 /**\r
-  The function will go through the driver option link list, load and start\r
-  every driver the driver option device path point to.\r
+  The function will load and start every Driver####/SysPrep####.\r
 \r
-  @param  DriverOption        Input driver option array.\r
-  @param  DriverOptionCount   Input driver option count.\r
+  @param  LoadOptions        Load option array.\r
+  @param  LoadOptionCount    Load option count.\r
 \r
 **/\r
 VOID\r
-LoadDrivers (\r
-  IN EFI_BOOT_MANAGER_LOAD_OPTION       *DriverOption,\r
-  IN UINTN                              DriverOptionCount\r
+ProcessLoadOptions (\r
+  IN EFI_BOOT_MANAGER_LOAD_OPTION       *LoadOptions,\r
+  IN UINTN                              LoadOptionCount\r
   )\r
 {\r
-  EFI_STATUS                Status;\r
-  UINTN                     Index;\r
-  EFI_HANDLE                ImageHandle;\r
-  EFI_LOADED_IMAGE_PROTOCOL *ImageInfo;\r
-  BOOLEAN                   ReconnectAll;\r
+  EFI_STATUS                        Status;\r
+  UINTN                             Index;\r
+  BOOLEAN                           ReconnectAll;\r
+  EFI_BOOT_MANAGER_LOAD_OPTION_TYPE LoadOptionType;\r
 \r
   ReconnectAll = FALSE;\r
+  LoadOptionType = LoadOptionTypeMax;\r
 \r
   //\r
   // Process the driver option\r
   //\r
-  for (Index = 0; Index < DriverOptionCount; Index++) {\r
+  for (Index = 0; Index < LoadOptionCount; Index++) {\r
     //\r
-    // If a load option is not marked as LOAD_OPTION_ACTIVE,\r
-    // the boot manager will not automatically load the option.\r
+    // All the load options in the array should be of the same type.\r
     //\r
-    if ((DriverOption[Index].Attributes & LOAD_OPTION_ACTIVE) == 0) {\r
-      continue;\r
-    }\r
-    \r
-    //\r
-    // If a driver load option is marked as LOAD_OPTION_FORCE_RECONNECT,\r
-    // then all of the EFI drivers in the system will be disconnected and\r
-    // reconnected after the last driver load option is processed.\r
-    //\r
-    if ((DriverOption[Index].Attributes & LOAD_OPTION_FORCE_RECONNECT) != 0) {\r
-      ReconnectAll = TRUE;\r
+    if (LoadOptionType == LoadOptionTypeMax) {\r
+      LoadOptionType = LoadOptions[Index].OptionType;\r
     }\r
-    \r
-    //\r
-    // Make sure the driver path is connected.\r
-    //\r
-    EfiBootManagerConnectDevicePath (DriverOption[Index].FilePath, NULL);\r
+    ASSERT (LoadOptionType == LoadOptions[Index].OptionType);\r
+    ASSERT (LoadOptionType == LoadOptionTypeDriver || LoadOptionType == LoadOptionTypeSysPrep);\r
 \r
-    //\r
-    // Load and start the image that Driver#### describes\r
-    //\r
-    Status = gBS->LoadImage (\r
-                    FALSE,\r
-                    gImageHandle,\r
-                    DriverOption[Index].FilePath,\r
-                    NULL,\r
-                    0,\r
-                    &ImageHandle\r
-                    );\r
+    Status = EfiBootManagerProcessLoadOption (&LoadOptions[Index]);\r
 \r
-    if (!EFI_ERROR (Status)) {\r
-      gBS->HandleProtocol (ImageHandle, &gEfiLoadedImageProtocolGuid, (VOID **) &ImageInfo);\r
-\r
-      //\r
-      // Verify whether this image is a driver, if not,\r
-      // exit it and continue to parse next load option\r
-      //\r
-      if (ImageInfo->ImageCodeType != EfiBootServicesCode && ImageInfo->ImageCodeType != EfiRuntimeServicesCode) {\r
-        gBS->Exit (ImageHandle, EFI_INVALID_PARAMETER, 0, NULL);\r
-        continue;\r
-      }\r
-\r
-      ImageInfo->LoadOptionsSize  = DriverOption[Index].OptionalDataSize;\r
-      ImageInfo->LoadOptions      = DriverOption[Index].OptionalData;\r
-      //\r
-      // Before calling the image, enable the Watchdog Timer for\r
-      // the 5 Minute period\r
-      //\r
-      gBS->SetWatchdogTimer (5 * 60, 0x0000, 0x00, NULL);\r
-\r
-      DriverOption[Index].Status = gBS->StartImage (ImageHandle, &DriverOption[Index].ExitDataSize, &DriverOption[Index].ExitData);\r
-      DEBUG ((DEBUG_INFO | DEBUG_LOAD, "Driver Return Status = %r\n", DriverOption[Index].Status));\r
-\r
-      //\r
-      // Clear the Watchdog Timer after the image returns\r
-      //\r
-      gBS->SetWatchdogTimer (0x0000, 0x0000, 0x0000, NULL);\r
+    if (!EFI_ERROR (Status) && ((LoadOptions[Index].Attributes & LOAD_OPTION_FORCE_RECONNECT) != 0)) {\r
+      ReconnectAll = TRUE;\r
     }\r
   }\r
-  \r
+\r
   //\r
-  // Process the LOAD_OPTION_FORCE_RECONNECT driver option\r
+  // If a driver load option is marked as LOAD_OPTION_FORCE_RECONNECT,\r
+  // then all of the EFI drivers in the system will be disconnected and\r
+  // reconnected after the last driver load option is processed.\r
   //\r
-  if (ReconnectAll) {\r
+  if (ReconnectAll && LoadOptionType == LoadOptionTypeDriver) {\r
     EfiBootManagerDisconnectAll ();\r
     EfiBootManagerConnectAll ();\r
   }\r
-\r
 }\r
 \r
 /**\r
@@ -855,9 +813,8 @@ BdsEntry (
   IN EFI_BDS_ARCH_PROTOCOL  *This\r
   )\r
 {\r
-  EFI_BOOT_MANAGER_LOAD_OPTION    *DriverOption;\r
-  EFI_BOOT_MANAGER_LOAD_OPTION    BootOption;\r
-  UINTN                           DriverOptionCount;\r
+  EFI_BOOT_MANAGER_LOAD_OPTION    *LoadOptions;\r
+  UINTN                           LoadOptionCount;\r
   CHAR16                          *FirmwareVendor;\r
   EFI_EVENT                       HotkeyTriggered;\r
   UINT64                          OsIndication;\r
@@ -867,8 +824,11 @@ BdsEntry (
   UINT16                          BootTimeOut;\r
   EDKII_VARIABLE_LOCK_PROTOCOL    *VariableLock;\r
   UINTN                           Index;\r
+  EFI_BOOT_MANAGER_LOAD_OPTION    BootOption;\r
   UINT16                          *BootNext;\r
   CHAR16                          BootNextVariableName[sizeof ("Boot####")];\r
+  EFI_BOOT_MANAGER_LOAD_OPTION    BootManagerMenu;\r
+  BOOLEAN                         BootFwUi;\r
 \r
   HotkeyTriggered = NULL;\r
   Status          = EFI_SUCCESS;\r
@@ -939,7 +899,7 @@ BdsEntry (
   // Initialize L"BootOptionSupport" EFI global variable.\r
   // Lazy-ConIn implictly disables BDS hotkey.\r
   //\r
-  BootOptionSupport = EFI_BOOT_OPTION_SUPPORT_APP;\r
+  BootOptionSupport = EFI_BOOT_OPTION_SUPPORT_APP | EFI_BOOT_OPTION_SUPPORT_SYSPREP;\r
   if (!PcdGetBool (PcdConInConnectOnDemand)) {\r
     BootOptionSupport |= EFI_BOOT_OPTION_SUPPORT_KEY;\r
     SET_BOOT_OPTION_SUPPORT_KEY_COUNT (BootOptionSupport, 3);\r
@@ -1010,11 +970,11 @@ BdsEntry (
   EfiBootManagerStartHotkeyService (&HotkeyTriggered);\r
 \r
   //\r
-  // Load Driver Options\r
+  // Execute Driver Options\r
   //\r
-  DriverOption = EfiBootManagerGetLoadOptions (&DriverOptionCount, LoadOptionTypeDriver);\r
-  LoadDrivers (DriverOption, DriverOptionCount);\r
-  EfiBootManagerFreeLoadOptions (DriverOption, DriverOptionCount);\r
+  LoadOptions = EfiBootManagerGetLoadOptions (&LoadOptionCount, LoadOptionTypeDriver);\r
+  ProcessLoadOptions (LoadOptions, LoadOptionCount);\r
+  EfiBootManagerFreeLoadOptions (LoadOptions, LoadOptionCount);\r
 \r
   //\r
   // Connect consoles\r
@@ -1059,23 +1019,28 @@ BdsEntry (
   PERF_END   (NULL, "PlatformBootManagerAfterConsole", "BDS", 0);\r
 \r
   DEBUG_CODE (\r
-    EFI_BOOT_MANAGER_LOAD_OPTION    *BootOptions;\r
-    UINTN                           BootOptionCount;\r
-    UINTN                           Index;\r
-\r
-    BootOptions = EfiBootManagerGetLoadOptions (&BootOptionCount, LoadOptionTypeBoot);\r
-    DEBUG ((EFI_D_INFO, "[Bds]=============Dumping Boot Options=============\n"));\r
-    for (Index = 0; Index < BootOptionCount; Index++) {\r
+    UINTN                             Index;\r
+    EFI_BOOT_MANAGER_LOAD_OPTION_TYPE LoadOptionType;\r
+    DEBUG ((EFI_D_INFO, "[Bds]=============Begin Load Options Dumping ...=============\n"));\r
+    for (LoadOptionType = 0; LoadOptionType < LoadOptionTypeMax; LoadOptionType++) {\r
       DEBUG ((\r
-        EFI_D_INFO, "[Bds]Boot%04x: %s \t\t 0x%04x\n",\r
-        BootOptions[Index].OptionNumber, \r
-        BootOptions[Index].Description, \r
-        BootOptions[Index].Attributes\r
+        EFI_D_INFO, "  %s Options:\n",\r
+        mBdsLoadOptionName[LoadOptionType]\r
         ));\r
+      LoadOptions = EfiBootManagerGetLoadOptions (&LoadOptionCount, LoadOptionType);\r
+      for (Index = 0; Index < LoadOptionCount; Index++) {\r
+        DEBUG ((\r
+          EFI_D_INFO, "    %s%04x: %s \t\t 0x%04x\n",\r
+          mBdsLoadOptionName[LoadOptionType],\r
+          LoadOptions[Index].OptionNumber,\r
+          LoadOptions[Index].Description,\r
+          LoadOptions[Index].Attributes\r
+          ));\r
+      }\r
+      EfiBootManagerFreeLoadOptions (LoadOptions, LoadOptionCount);\r
     }\r
-    DEBUG ((EFI_D_INFO, "[Bds]=============Dumping Boot Options Finished====\n"));\r
-    EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount);\r
-    );\r
+    DEBUG ((EFI_D_INFO, "[Bds]=============End Load Options Dumping=============\n"));\r
+  );\r
 \r
   //\r
   // Boot to Boot Manager Menu when EFI_OS_INDICATIONS_BOOT_TO_FW_UI is set. Skip HotkeyBoot\r
@@ -1088,10 +1053,15 @@ BdsEntry (
                   &DataSize,\r
                   &OsIndication\r
                   );\r
-  if (!EFI_ERROR(Status) && ((OsIndication & EFI_OS_INDICATIONS_BOOT_TO_FW_UI) != 0)) {\r
-    //\r
-    // Clear EFI_OS_INDICATIONS_BOOT_TO_FW_UI to acknowledge OS\r
-    // \r
+  if (EFI_ERROR (Status)) {\r
+    OsIndication = 0;\r
+  }\r
+\r
+  BootFwUi = (BOOLEAN) ((OsIndication & EFI_OS_INDICATIONS_BOOT_TO_FW_UI) != 0);\r
+  //\r
+  // Clear EFI_OS_INDICATIONS_BOOT_TO_FW_UI to acknowledge OS\r
+  // \r
+  if (BootFwUi) {\r
     OsIndication &= ~((UINT64) EFI_OS_INDICATIONS_BOOT_TO_FW_UI);\r
     Status = gRT->SetVariable (\r
                L"OsIndications",\r
@@ -1104,7 +1074,12 @@ BdsEntry (
     // Changing the content without increasing its size with current variable implementation shouldn't fail.\r
     //\r
     ASSERT_EFI_ERROR (Status);\r
+  }\r
 \r
+  //\r
+  // Launch Boot Manager Menu directly when EFI_OS_INDICATIONS_BOOT_TO_FW_UI is set. Skip HotkeyBoot\r
+  //\r
+  if (BootFwUi) {\r
     //\r
     // Follow generic rule, Call BdsDxeOnConnectConInCallBack to connect ConIn before enter UI\r
     //\r
@@ -1113,24 +1088,35 @@ BdsEntry (
     }\r
 \r
     //\r
-    // Directly boot to Boot Manager Menu.\r
+    // Directly enter the setup page.\r
+    // BootManagerMenu always contains the correct information even call fails.\r
     //\r
-    EfiBootManagerGetBootManagerMenu (&BootOption);\r
-    EfiBootManagerBoot (&BootOption);\r
-    EfiBootManagerFreeLoadOption (&BootOption);\r
-  } else {\r
-    PERF_START (NULL, "BdsWait", "BDS", 0);\r
-    BdsWait (HotkeyTriggered);\r
-    PERF_END   (NULL, "BdsWait", "BDS", 0);\r
-\r
-    //\r
-    // BdsReadKeys() be removed after all keyboard drivers invoke callback in timer callback.\r
-    //\r
-    BdsReadKeys ();\r
-    \r
-    EfiBootManagerHotkeyBoot ();\r
+    EfiBootManagerGetBootManagerMenu (&BootManagerMenu);\r
+    EfiBootManagerBoot (&BootManagerMenu);\r
+    EfiBootManagerFreeLoadOption (&BootManagerMenu);\r
   }\r
 \r
+  //\r
+  // Execute SysPrep####\r
+  //\r
+  LoadOptions = EfiBootManagerGetLoadOptions (&LoadOptionCount, LoadOptionTypeSysPrep);\r
+  ProcessLoadOptions (LoadOptions, LoadOptionCount);\r
+  EfiBootManagerFreeLoadOptions (LoadOptions, LoadOptionCount);\r
+\r
+  //\r
+  // Execute Key####\r
+  //\r
+  PERF_START (NULL, "BdsWait", "BDS", 0);\r
+  BdsWait (HotkeyTriggered);\r
+  PERF_END   (NULL, "BdsWait", "BDS", 0);\r
+\r
+  //\r
+  // BdsReadKeys() be removed after all keyboard drivers invoke callback in timer callback.\r
+  //\r
+  BdsReadKeys ();\r
+\r
+  EfiBootManagerHotkeyBoot ();\r
+\r
   //\r
   // Boot to "BootNext"\r
   //\r