]> git.proxmox.com Git - mirror_edk2.git/blobdiff - ArmPkg/Library/BdsLib/BdsFilePath.c
ARM Packages: Fixed line endings
[mirror_edk2.git] / ArmPkg / Library / BdsLib / BdsFilePath.c
index a8b77a3d22712f26f14943faed2e593c7e813f55..2c93243795ca1f446f89a8cab5d591b74d8738f7 100644 (file)
-/** @file
-*
-*  Copyright (c) 2011-2012, ARM Limited. All rights reserved.
-*  
-*  This program and the accompanying materials                          
-*  are licensed and made available under the terms and conditions of the BSD License         
-*  which accompanies this distribution.  The full text of the license may be found at        
-*  http://opensource.org/licenses/bsd-license.php                                            
-*
-*  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,                     
-*  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.             
-*
-**/
-
-#include "BdsInternal.h"
-
-#include <Protocol/UsbIo.h>
-#include <Protocol/DiskIo.h>
-#include <Protocol/LoadedImage.h>
-
-#define IS_DEVICE_PATH_NODE(node,type,subtype) (((node)->Type == (type)) && ((node)->SubType == (subtype)))
-
-// Extract the FilePath from the Device Path
-CHAR16*
-BdsExtractFilePathFromDevicePath (
-  IN  CONST CHAR16    *StrDevicePath,
-  IN  UINTN           NumberDevicePathNode
-  )
-{
-  UINTN       Node;
-  CHAR16      *Str;
-
-  Str = (CHAR16*)StrDevicePath;
-  Node = 0;
-  while ((Str != NULL) && (*Str != L'\0') && (Node < NumberDevicePathNode)) {
-    if ((*Str == L'/') || (*Str == L'\\')) {
-        Node++;
-    }
-    Str++;
-  }
-
-  if (*Str == L'\0') {
-    return NULL;
-  } else {
-    return Str;
-  }
-}
-
-BOOLEAN
-BdsIsRemovableUsb (
-  IN  EFI_DEVICE_PATH*  DevicePath
-  )
-{
-  return ((DevicePathType (DevicePath) == MESSAGING_DEVICE_PATH) &&
-          ((DevicePathSubType (DevicePath) == MSG_USB_CLASS_DP) ||
-           (DevicePathSubType (DevicePath) == MSG_USB_WWID_DP)));
-}
-
-EFI_STATUS
-BdsGetDeviceUsb (
-  IN  EFI_DEVICE_PATH*  RemovableDevicePath,
-  OUT EFI_HANDLE*       DeviceHandle,
-  OUT EFI_DEVICE_PATH** NewDevicePath
-  )
-{
-  EFI_STATUS                    Status;
-  UINTN                         Index;
-  UINTN                         UsbIoHandleCount;
-  EFI_HANDLE                    *UsbIoBuffer;
-  EFI_DEVICE_PATH*              UsbIoDevicePath;
-  EFI_DEVICE_PATH*              TmpDevicePath;
-  USB_WWID_DEVICE_PATH*         WwidDevicePath1;
-  USB_WWID_DEVICE_PATH*         WwidDevicePath2;
-  USB_CLASS_DEVICE_PATH*        UsbClassDevicePath1;
-  USB_CLASS_DEVICE_PATH*        UsbClassDevicePath2;
-
-  // Get all the UsbIo handles
-  UsbIoHandleCount = 0;
-  Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiUsbIoProtocolGuid, NULL, &UsbIoHandleCount, &UsbIoBuffer);
-  if (EFI_ERROR(Status) || (UsbIoHandleCount == 0)) {
-    return Status;
-  }
-
-  // Check if one of the handles matches the USB description
-  for (Index = 0; Index < UsbIoHandleCount; Index++) {
-    Status = gBS->HandleProtocol (UsbIoBuffer[Index], &gEfiDevicePathProtocolGuid, (VOID **) &UsbIoDevicePath);
-    if (!EFI_ERROR(Status)) {
-      TmpDevicePath = UsbIoDevicePath;
-      while (!IsDevicePathEnd (TmpDevicePath)) {
-        // Check if the Device Path node is a USB Removable device Path node
-        if (BdsIsRemovableUsb (TmpDevicePath)) {
-          if (TmpDevicePath->SubType == MSG_USB_WWID_DP) {
-            WwidDevicePath1 = (USB_WWID_DEVICE_PATH*)RemovableDevicePath;
-            WwidDevicePath2 = (USB_WWID_DEVICE_PATH*)TmpDevicePath;
-            if ((WwidDevicePath1->VendorId == WwidDevicePath2->VendorId) &&
-                (WwidDevicePath1->ProductId == WwidDevicePath2->ProductId) &&
-                (CompareMem (WwidDevicePath1+1, WwidDevicePath2+1, DevicePathNodeLength(WwidDevicePath1)-sizeof(USB_WWID_DEVICE_PATH)) == 0))
-            {
-              *DeviceHandle = UsbIoBuffer[Index];
-              // Add the additional original Device Path Nodes (eg: FilePath Device Path Node) to the new Device Path
-              *NewDevicePath = AppendDevicePath (UsbIoDevicePath, NextDevicePathNode(RemovableDevicePath));
-              return EFI_SUCCESS;
-            }
-          } else {
-            UsbClassDevicePath1 = (USB_CLASS_DEVICE_PATH*)RemovableDevicePath;
-            UsbClassDevicePath2 = (USB_CLASS_DEVICE_PATH*)TmpDevicePath;
-            if ((UsbClassDevicePath1->VendorId != 0xFFFF) && (UsbClassDevicePath1->VendorId == UsbClassDevicePath2->VendorId) &&
-                (UsbClassDevicePath1->ProductId != 0xFFFF) && (UsbClassDevicePath1->ProductId == UsbClassDevicePath2->ProductId) &&
-                (UsbClassDevicePath1->DeviceClass != 0xFF) && (UsbClassDevicePath1->DeviceClass == UsbClassDevicePath2->DeviceClass) &&
-                (UsbClassDevicePath1->DeviceSubClass != 0xFF) && (UsbClassDevicePath1->DeviceSubClass == UsbClassDevicePath2->DeviceSubClass) &&
-                (UsbClassDevicePath1->DeviceProtocol != 0xFF) && (UsbClassDevicePath1->DeviceProtocol == UsbClassDevicePath2->DeviceProtocol))
-            {
-              *DeviceHandle = UsbIoBuffer[Index];
-              // Add the additional original Device Path Nodes (eg: FilePath Device Path Node) to the new Device Path
-              *NewDevicePath = AppendDevicePath (UsbIoDevicePath, NextDevicePathNode(RemovableDevicePath));
-              return EFI_SUCCESS;
-            }
-          }
-        }
-        TmpDevicePath = NextDevicePathNode (TmpDevicePath);
-      }
-
-    }
-  }
-
-  return EFI_NOT_FOUND;
-}
-
-BOOLEAN
-BdsIsRemovableHd (
-  IN  EFI_DEVICE_PATH*  DevicePath
-  )
-{
-  return IS_DEVICE_PATH_NODE(DevicePath, MEDIA_DEVICE_PATH, MEDIA_HARDDRIVE_DP);
-}
-
-EFI_STATUS
-BdsGetDeviceHd (
-  IN  EFI_DEVICE_PATH*  RemovableDevicePath,
-  OUT EFI_HANDLE*       DeviceHandle,
-  OUT EFI_DEVICE_PATH** NewDevicePath
-  )
-{
-  EFI_STATUS                    Status;
-  UINTN                         Index;
-  UINTN                         PartitionHandleCount;
-  EFI_HANDLE                    *PartitionBuffer;
-  EFI_DEVICE_PATH*              PartitionDevicePath;
-  EFI_DEVICE_PATH*              TmpDevicePath;
-  HARDDRIVE_DEVICE_PATH*        HardDriveDevicePath1;
-  HARDDRIVE_DEVICE_PATH*        HardDriveDevicePath2;
-
-  // Get all the DiskIo handles
-  PartitionHandleCount = 0;
-  Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiDiskIoProtocolGuid, NULL, &PartitionHandleCount, &PartitionBuffer);
-  if (EFI_ERROR(Status) || (PartitionHandleCount == 0)) {
-    return Status;
-  }
-
-  // Check if one of the handles matches the Hard Disk Description
-  for (Index = 0; Index < PartitionHandleCount; Index++) {
-    Status = gBS->HandleProtocol (PartitionBuffer[Index], &gEfiDevicePathProtocolGuid, (VOID **) &PartitionDevicePath);
-    if (!EFI_ERROR(Status)) {
-      TmpDevicePath = PartitionDevicePath;
-      while (!IsDevicePathEnd (TmpDevicePath)) {
-        // Check if the Device Path node is a HD Removable device Path node
-        if (BdsIsRemovableHd (TmpDevicePath)) {
-          HardDriveDevicePath1 = (HARDDRIVE_DEVICE_PATH*)RemovableDevicePath;
-          HardDriveDevicePath2 = (HARDDRIVE_DEVICE_PATH*)TmpDevicePath;
-          if ((HardDriveDevicePath1->SignatureType == HardDriveDevicePath2->SignatureType) &&
-              (CompareGuid ((EFI_GUID *)HardDriveDevicePath1->Signature,(EFI_GUID *)HardDriveDevicePath2->Signature) == TRUE) &&
-              (HardDriveDevicePath1->PartitionNumber == HardDriveDevicePath2->PartitionNumber))
-          {
-            *DeviceHandle = PartitionBuffer[Index];
-            // Add the additional original Device Path Nodes (eg: FilePath Device Path Node) to the new Device Path
-            *NewDevicePath = AppendDevicePath (PartitionDevicePath, NextDevicePathNode(RemovableDevicePath));
-            return EFI_SUCCESS;
-          }
-        }
-        TmpDevicePath = NextDevicePathNode (TmpDevicePath);
-      }
-
-    }
-  }
-
-  return EFI_NOT_FOUND;
-}
-
-/*BOOLEAN
-BdsIsRemovableCdrom (
-  IN  EFI_DEVICE_PATH*  DevicePath
-  )
-{
-  return IS_DEVICE_PATH_NODE(DevicePath, MEDIA_DEVICE_PATH, MEDIA_CDROM_DP);
-}
-
-EFI_STATUS
-BdsGetDeviceCdrom (
-  IN  EFI_DEVICE_PATH*  RemovableDevicePath,
-  OUT EFI_HANDLE*       DeviceHandle,
-  OUT EFI_DEVICE_PATH** DevicePath
-  )
-{
-  ASSERT(0);
-  return EFI_UNSUPPORTED;
-}*/
-
-typedef BOOLEAN
-(*BDS_IS_REMOVABLE) (
-  IN  EFI_DEVICE_PATH*  DevicePath
-  );
-
-typedef EFI_STATUS
-(*BDS_GET_DEVICE) (
-  IN  EFI_DEVICE_PATH*  RemovableDevicePath,
-  OUT EFI_HANDLE*       DeviceHandle,
-  OUT EFI_DEVICE_PATH** DevicePath
-  );
-
-typedef struct {
-  BDS_IS_REMOVABLE    IsRemovable;
-  BDS_GET_DEVICE      GetDevice;
-} BDS_REMOVABLE_DEVICE_SUPPORT;
-
-BDS_REMOVABLE_DEVICE_SUPPORT  RemovableDeviceSupport[] = {
-  { BdsIsRemovableUsb, BdsGetDeviceUsb },
-  { BdsIsRemovableHd, BdsGetDeviceHd },
-  //{ BdsIsRemovableCdrom, BdsGetDeviceCdrom }
-};
-
-STATIC
-BOOLEAN
-IsRemovableDevice (
-  IN  EFI_DEVICE_PATH*  DevicePath
-  )
-{
-  UINTN             Index;
-  EFI_DEVICE_PATH*  TmpDevicePath;
-
-  TmpDevicePath = DevicePath;
-  while (!IsDevicePathEnd (TmpDevicePath)) {
-    for (Index = 0; Index < sizeof(RemovableDeviceSupport) / sizeof(BDS_REMOVABLE_DEVICE_SUPPORT); Index++) {
-      if (RemovableDeviceSupport[Index].IsRemovable(TmpDevicePath)) {
-        return TRUE;
-      }
-    }
-    TmpDevicePath = NextDevicePathNode (TmpDevicePath);
-  }
-
-  return FALSE;
-}
-
-STATIC
-EFI_STATUS
-TryRemovableDevice (
-  IN  EFI_DEVICE_PATH*  DevicePath,
-  OUT EFI_HANDLE*       DeviceHandle,
-  OUT EFI_DEVICE_PATH** NewDevicePath
-  )
-{
-  EFI_STATUS        Status;
-  UINTN             Index;
-  EFI_DEVICE_PATH*  TmpDevicePath;
-  BDS_REMOVABLE_DEVICE_SUPPORT* RemovableDevice;
-  EFI_DEVICE_PATH* RemovableDevicePath;
-  BOOLEAN         RemovableFound;
-
-  RemovableDevice     = NULL;
-  RemovableDevicePath = NULL;
-  RemovableFound      = FALSE;
-  TmpDevicePath       = DevicePath;
-
-  while (!IsDevicePathEnd (TmpDevicePath) && !RemovableFound) {
-    for (Index = 0; Index < sizeof(RemovableDeviceSupport) / sizeof(BDS_REMOVABLE_DEVICE_SUPPORT); Index++) {
-      RemovableDevice = &RemovableDeviceSupport[Index];
-      if (RemovableDevice->IsRemovable(TmpDevicePath)) {
-        RemovableDevicePath = TmpDevicePath;
-        RemovableFound = TRUE;
-        break;
-      }
-    }
-    TmpDevicePath = NextDevicePathNode (TmpDevicePath);
-  }
-
-  if (!RemovableFound) {
-    return EFI_NOT_FOUND;
-  }
-
-  // Search into the current started drivers
-  Status = RemovableDevice->GetDevice (RemovableDevicePath, DeviceHandle, NewDevicePath);
-  if (Status == EFI_NOT_FOUND) {
-    // Connect all the drivers
-    BdsConnectAllDrivers ();
-
-    // Search again into all the drivers
-    Status = RemovableDevice->GetDevice (RemovableDevicePath, DeviceHandle, NewDevicePath);
-  }
-
-  return Status;
-}
-
-/**
-  Connect a Device Path and return the handle of the driver that support this DevicePath
-
-  @param  DevicePath            Device Path of the File to connect
-  @param  Handle                Handle of the driver that support this DevicePath
-  @param  RemainingDevicePath   Remaining DevicePath nodes that do not match the driver DevicePath
-
-  @retval EFI_SUCCESS           A driver that matches the Device Path has been found
-  @retval EFI_NOT_FOUND         No handles match the search.
-  @retval EFI_INVALID_PARAMETER DevicePath or Handle is NULL
-
-**/
-EFI_STATUS
-BdsConnectDevicePath (
-  IN  EFI_DEVICE_PATH_PROTOCOL* DevicePath,
-  OUT EFI_HANDLE                *Handle,
-  OUT EFI_DEVICE_PATH_PROTOCOL  **RemainingDevicePath
-  )
-{
-  EFI_DEVICE_PATH*            Remaining;
-  EFI_DEVICE_PATH*            NewDevicePath;
-  EFI_STATUS                  Status;
-
-  if ((DevicePath == NULL) || (Handle == NULL)) {
-    return EFI_INVALID_PARAMETER;
-  }
-
-  do {
-    Remaining = DevicePath;
-    // The LocateDevicePath() function locates all devices on DevicePath that support Protocol and returns
-    // the handle to the device that is closest to DevicePath. On output, the device path pointer is modified
-    // to point to the remaining part of the device path
-    Status = gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid, &Remaining, Handle);
-    if (!EFI_ERROR (Status)) {
-      // Recursive = FALSE: We do not want to start all the device tree
-      Status = gBS->ConnectController (*Handle, NULL, Remaining, FALSE);
-    }
-
-    /*// We need to check if RemainingDevicePath does not point on the last node. Otherwise, calling
-    // NextDevicePathNode() will return an undetermined Device Path Node
-    if (!IsDevicePathEnd (RemainingDevicePath)) {
-      RemainingDevicePath = NextDevicePathNode (RemainingDevicePath);
-    }*/
-  } while (!EFI_ERROR (Status) && !IsDevicePathEnd (Remaining));
-
-  if (!EFI_ERROR (Status)) {
-    // Now, we have got the whole Device Path connected, call again ConnectController to ensure all the supported Driver
-    // Binding Protocol are connected (such as DiskIo and SimpleFileSystem)
-    Remaining = DevicePath;
-    Status = gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid,&Remaining,Handle);
-    if (!EFI_ERROR (Status)) {
-      Status = gBS->ConnectController (*Handle, NULL, Remaining, FALSE);
-      if (EFI_ERROR (Status)) {
-        // If the last node is a Memory Map Device Path just return EFI_SUCCESS.
-        if ((Remaining->Type == HARDWARE_DEVICE_PATH) && (Remaining->SubType == HW_MEMMAP_DP)) {
-            Status = EFI_SUCCESS;
-        }
-      }
-    }
-  } else if (!IsDevicePathEnd (Remaining) && !IsRemovableDevice (Remaining)) {
-
-    /*// If the remaining Device Path is a FilePath or MemoryMap then we consider the Device Path has been loaded correctly
-    if ((Remaining->Type == MEDIA_DEVICE_PATH) && (Remaining->SubType == MEDIA_FILEPATH_DP)) {
-      Status = EFI_SUCCESS;
-    } else if ((Remaining->Type == HARDWARE_DEVICE_PATH) && (Remaining->SubType == HW_MEMMAP_DP)) {
-      Status = EFI_SUCCESS;
-    }*/
-
-    //TODO: Should we just return success and leave the caller decide if it is the expected RemainingPath
-    Status = EFI_SUCCESS;
-  } else {
-    Status = TryRemovableDevice (DevicePath, Handle, &NewDevicePath);
-    if (!EFI_ERROR (Status)) {
-      return BdsConnectDevicePath (NewDevicePath, Handle, RemainingDevicePath);
-    }
-  }
-
-  if (RemainingDevicePath) {
-    *RemainingDevicePath = Remaining;
-  }
-
-  return Status;
-}
-
-BOOLEAN
-BdsFileSystemSupport (
-  IN EFI_DEVICE_PATH *DevicePath,
-  IN EFI_HANDLE Handle,
-  IN EFI_DEVICE_PATH *RemainingDevicePath
-  )
-{
-  EFI_STATUS  Status;
-  EFI_SIMPLE_FILE_SYSTEM_PROTOCOL     *FsProtocol;
-
-  Status = gBS->HandleProtocol (Handle,&gEfiSimpleFileSystemProtocolGuid, (VOID **)&FsProtocol);
-
-  return (!EFI_ERROR(Status) && IS_DEVICE_PATH_NODE(RemainingDevicePath,MEDIA_DEVICE_PATH,MEDIA_FILEPATH_DP));
-}
-
-EFI_STATUS
-BdsFileSystemLoadImage (
-  IN     EFI_DEVICE_PATH *DevicePath,
-  IN     EFI_HANDLE Handle,
-  IN     EFI_DEVICE_PATH *RemainingDevicePath,
-  IN     EFI_ALLOCATE_TYPE     Type,
-  IN OUT EFI_PHYSICAL_ADDRESS* Image,
-  OUT    UINTN                 *ImageSize
-  )
-{
-  FILEPATH_DEVICE_PATH*             FilePathDevicePath;
-  EFI_SIMPLE_FILE_SYSTEM_PROTOCOL     *FsProtocol;
-  EFI_FILE_PROTOCOL                   *Fs;
-  EFI_STATUS Status;
-  EFI_FILE_INFO       *FileInfo;
-  EFI_FILE_PROTOCOL   *File;
-  UINTN               Size;
-
-  ASSERT (IS_DEVICE_PATH_NODE(RemainingDevicePath,MEDIA_DEVICE_PATH,MEDIA_FILEPATH_DP));
-
-  FilePathDevicePath = (FILEPATH_DEVICE_PATH*)RemainingDevicePath;
-
-  Status = gBS->HandleProtocol(Handle,&gEfiSimpleFileSystemProtocolGuid, (VOID **)&FsProtocol);
-  if (EFI_ERROR(Status)) {
-    return Status;
-  }
-
-  // Try to Open the volume and get root directory
-  Status = FsProtocol->OpenVolume (FsProtocol, &Fs);
-  if (EFI_ERROR(Status)) {
-    return Status;
-  }
-
-  File = NULL;
-  Status = Fs->Open(Fs, &File, FilePathDevicePath->PathName, EFI_FILE_MODE_READ, 0);
-  if (EFI_ERROR(Status)) {
-    return Status;
-  }
-
-  Size = 0;
-  File->GetInfo(File, &gEfiFileInfoGuid, &Size, NULL);
-  FileInfo = AllocatePool (Size);
-  Status = File->GetInfo(File, &gEfiFileInfoGuid, &Size, FileInfo);
-  if (EFI_ERROR(Status)) {
-    return Status;
-  }
-
-  // Get the file size
-  Size = FileInfo->FileSize;
-  if (ImageSize) {
-    *ImageSize = Size;
-  }
-  FreePool(FileInfo);
-
-  Status = gBS->AllocatePages (Type, EfiBootServicesCode, EFI_SIZE_TO_PAGES(Size), Image);
-  // Try to allocate in any pages if failed to allocate memory at the defined location
-  if ((Status == EFI_OUT_OF_RESOURCES) && (Type != AllocateAnyPages)) {
-    Status = gBS->AllocatePages (AllocateAnyPages, EfiBootServicesCode, EFI_SIZE_TO_PAGES(Size), Image);
-  }
-  if (!EFI_ERROR(Status)) {
-    Status = File->Read (File, &Size, (VOID*)(UINTN)(*Image));
-  }
-
-  return Status;
-}
-
-BOOLEAN
-BdsMemoryMapSupport (
-  IN EFI_DEVICE_PATH *DevicePath,
-  IN EFI_HANDLE Handle,
-  IN EFI_DEVICE_PATH *RemainingDevicePath
-  )
-{
-  return IS_DEVICE_PATH_NODE(DevicePath,HARDWARE_DEVICE_PATH,HW_MEMMAP_DP) ||
-         IS_DEVICE_PATH_NODE(RemainingDevicePath,HARDWARE_DEVICE_PATH,HW_MEMMAP_DP);
-}
-
-EFI_STATUS
-BdsMemoryMapLoadImage (
-  IN     EFI_DEVICE_PATH *DevicePath,
-  IN     EFI_HANDLE Handle,
-  IN     EFI_DEVICE_PATH *RemainingDevicePath,
-  IN     EFI_ALLOCATE_TYPE     Type,
-  IN OUT EFI_PHYSICAL_ADDRESS* Image,
-  OUT    UINTN                 *ImageSize
-  )
-{
-  EFI_STATUS            Status;
-  MEMMAP_DEVICE_PATH*   MemMapPathDevicePath;
-  UINTN                 Size;
-
-  if (IS_DEVICE_PATH_NODE(RemainingDevicePath,HARDWARE_DEVICE_PATH,HW_MEMMAP_DP)) {
-    MemMapPathDevicePath = (MEMMAP_DEVICE_PATH*)RemainingDevicePath;
-  } else {
-    ASSERT (IS_DEVICE_PATH_NODE(DevicePath,HARDWARE_DEVICE_PATH,HW_MEMMAP_DP));
-    MemMapPathDevicePath = (MEMMAP_DEVICE_PATH*)DevicePath;
-  }
-
-  Size = MemMapPathDevicePath->EndingAddress - MemMapPathDevicePath->StartingAddress;
-  if (Size == 0) {
-      return EFI_INVALID_PARAMETER;
-  }
-
-  Status = gBS->AllocatePages (Type, EfiBootServicesCode, EFI_SIZE_TO_PAGES(Size), Image);
-  // Try to allocate in any pages if failed to allocate memory at the defined location
-  if ((Status == EFI_OUT_OF_RESOURCES) && (Type != AllocateAnyPages)) {
-    Status = gBS->AllocatePages (AllocateAnyPages, EfiBootServicesCode, EFI_SIZE_TO_PAGES(Size), Image);
-  }
-  if (!EFI_ERROR(Status)) {
-    CopyMem ((VOID*)(UINTN)(*Image), (CONST VOID*)(UINTN)MemMapPathDevicePath->StartingAddress, Size);
-
-    if (ImageSize != NULL) {
-        *ImageSize = Size;
-    }
-  }
-
-  return Status;
-}
-
-BOOLEAN
-BdsFirmwareVolumeSupport (
-  IN EFI_DEVICE_PATH *DevicePath,
-  IN EFI_HANDLE Handle,
-  IN EFI_DEVICE_PATH *RemainingDevicePath
-  )
-{
-  return IS_DEVICE_PATH_NODE(RemainingDevicePath, MEDIA_DEVICE_PATH, MEDIA_PIWG_FW_FILE_DP);
-}
-
-EFI_STATUS
-BdsFirmwareVolumeLoadImage (
-  IN     EFI_DEVICE_PATH *DevicePath,
-  IN     EFI_HANDLE Handle,
-  IN     EFI_DEVICE_PATH *RemainingDevicePath,
-  IN     EFI_ALLOCATE_TYPE     Type,
-  IN OUT EFI_PHYSICAL_ADDRESS* Image,
-  OUT    UINTN                 *ImageSize
-  )
-{
-  EFI_STATUS            Status;
-  EFI_FIRMWARE_VOLUME2_PROTOCOL     *FwVol;
-  EFI_GUID                          *FvNameGuid;
-  EFI_SECTION_TYPE                  SectionType;
-  EFI_FV_FILETYPE                   FvType;
-  EFI_FV_FILE_ATTRIBUTES            Attrib;
-  UINT32                            AuthenticationStatus;
-  VOID* ImageBuffer;
-
-  ASSERT (IS_DEVICE_PATH_NODE(RemainingDevicePath, MEDIA_DEVICE_PATH, MEDIA_PIWG_FW_FILE_DP));
-
-  Status = gBS->HandleProtocol(Handle,&gEfiFirmwareVolume2ProtocolGuid, (VOID **)&FwVol);
-  if (EFI_ERROR(Status)) {
-    return Status;
-  }
-
-  FvNameGuid = EfiGetNameGuidFromFwVolDevicePathNode ((CONST MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *)RemainingDevicePath);
-  if (FvNameGuid == NULL) {
-    Status = EFI_INVALID_PARAMETER;
-  }
-
-  SectionType = EFI_SECTION_PE32;
-  AuthenticationStatus = 0;
-  //Note: ReadSection at the opposite of ReadFile does not allow to pass ImageBuffer == NULL to get the size of the file.
-  ImageBuffer = NULL;
-  Status = FwVol->ReadSection (
-                    FwVol,
-                    FvNameGuid,
-                    SectionType,
-                    0,
-                    &ImageBuffer,
-                    ImageSize,
-                    &AuthenticationStatus
-                    );
-  if (!EFI_ERROR (Status)) {
-#if 0
-    // In case the buffer has some address requirements, we must copy the buffer to a buffer following the requirements
-    if (Type != AllocateAnyPages) {
-      Status = gBS->AllocatePages (Type, EfiBootServicesCode, EFI_SIZE_TO_PAGES(*ImageSize),Image);
-      if (!EFI_ERROR(Status)) {
-        CopyMem ((VOID*)(UINTN)(*Image), ImageBuffer, *ImageSize);
-        FreePool (ImageBuffer);
-      }
-    }
-#else
-    // We must copy the buffer into a page allocations. Otherwise, the caller could call gBS->FreePages() on the pool allocation
-    Status = gBS->AllocatePages (Type, EfiBootServicesCode, EFI_SIZE_TO_PAGES(*ImageSize), Image);
-    // Try to allocate in any pages if failed to allocate memory at the defined location
-    if ((Status == EFI_OUT_OF_RESOURCES) && (Type != AllocateAnyPages)) {
-      Status = gBS->AllocatePages (AllocateAnyPages, EfiBootServicesCode, EFI_SIZE_TO_PAGES(*ImageSize), Image);
-    }
-    if (!EFI_ERROR(Status)) {
-      CopyMem ((VOID*)(UINTN)(*Image), ImageBuffer, *ImageSize);
-      FreePool (ImageBuffer);
-    }
-#endif
-  } else {
-    // Try a raw file, since a PE32 SECTION does not exist
-    Status = FwVol->ReadFile (
-                        FwVol,
-                        FvNameGuid,
-                        NULL,
-                        ImageSize,
-                        &FvType,
-                        &Attrib,
-                        &AuthenticationStatus
-                        );
-    if (!EFI_ERROR(Status)) {
-      Status = gBS->AllocatePages (Type, EfiBootServicesCode, EFI_SIZE_TO_PAGES(*ImageSize), Image);
-      // Try to allocate in any pages if failed to allocate memory at the defined location
-      if ((Status == EFI_OUT_OF_RESOURCES) && (Type != AllocateAnyPages)) {
-        Status = gBS->AllocatePages (AllocateAnyPages, EfiBootServicesCode, EFI_SIZE_TO_PAGES(*ImageSize), Image);
-      }
-      if (!EFI_ERROR(Status)) {
-        Status = FwVol->ReadFile (
-                                FwVol,
-                                FvNameGuid,
-                                (VOID*)(UINTN)(*Image),
-                                ImageSize,
-                                &FvType,
-                                &Attrib,
-                                &AuthenticationStatus
-                                );
-      }
-    }
-  }
-  return Status;
-}
-
-BOOLEAN
-BdsPxeSupport (
-  IN EFI_DEVICE_PATH*           DevicePath,
-  IN EFI_HANDLE                 Handle,
-  IN EFI_DEVICE_PATH*           RemainingDevicePath
-  )
-{
-  EFI_STATUS                  Status;
-  EFI_PXE_BASE_CODE_PROTOCOL* PxeBcProtocol;
-
-  if (!IsDevicePathEnd(RemainingDevicePath)) {
-    return FALSE;
-  }
-
-  Status = gBS->HandleProtocol (Handle, &gEfiPxeBaseCodeProtocolGuid, (VOID **)&PxeBcProtocol);
-  if (EFI_ERROR (Status)) {
-    return FALSE;
-  } else {
-    return TRUE;
-  }
-}
-
-EFI_STATUS
-BdsPxeLoadImage (
-  IN     EFI_DEVICE_PATH*       DevicePath,
-  IN     EFI_HANDLE             Handle,
-  IN     EFI_DEVICE_PATH*       RemainingDevicePath,
-  IN     EFI_ALLOCATE_TYPE      Type,
-  IN OUT EFI_PHYSICAL_ADDRESS   *Image,
-  OUT    UINTN                  *ImageSize
-  )
-{
-  EFI_STATUS              Status;
-  EFI_LOAD_FILE_PROTOCOL  *LoadFileProtocol;
-  UINTN                   BufferSize;
-
-  // Get Load File Protocol attached to the PXE protocol
-  Status = gBS->HandleProtocol (Handle, &gEfiLoadFileProtocolGuid, (VOID **)&LoadFileProtocol);
-  if (EFI_ERROR (Status)) {
-    return Status;
-  }
-
-  Status = LoadFileProtocol->LoadFile (LoadFileProtocol, DevicePath, TRUE, &BufferSize, NULL);
-  if (Status == EFI_BUFFER_TOO_SMALL) {
-    Status = gBS->AllocatePages (Type, EfiBootServicesCode, EFI_SIZE_TO_PAGES(BufferSize), Image);
-    if (EFI_ERROR(Status)) {
-      return Status;
-    }
-
-    Status = LoadFileProtocol->LoadFile (LoadFileProtocol, DevicePath, TRUE, &BufferSize, (VOID*)(UINTN)(*Image));
-    if (!EFI_ERROR(Status) && (ImageSize != NULL)) {
-      *ImageSize = BufferSize;
-    }
-  }
-
-  return Status;
-}
-
-BOOLEAN
-BdsTftpSupport (
-  IN EFI_DEVICE_PATH*           DevicePath,
-  IN EFI_HANDLE                 Handle,
-  IN EFI_DEVICE_PATH*           RemainingDevicePath
-  )
-{
-  EFI_STATUS  Status;
-  EFI_DEVICE_PATH  *NextDevicePath;
-  EFI_PXE_BASE_CODE_PROTOCOL  *PxeBcProtocol;
-
-  // Validate the Remaining Device Path
-  if (IsDevicePathEnd(RemainingDevicePath)) {
-    return FALSE;
-  }
-  if (!IS_DEVICE_PATH_NODE(RemainingDevicePath,MESSAGING_DEVICE_PATH,MSG_IPv4_DP) &&
-      !IS_DEVICE_PATH_NODE(RemainingDevicePath,MESSAGING_DEVICE_PATH,MSG_IPv6_DP)) {
-    return FALSE;
-  }
-  NextDevicePath = NextDevicePathNode (RemainingDevicePath);
-  if (IsDevicePathEnd(NextDevicePath)) {
-    return FALSE;
-  }
-  if (!IS_DEVICE_PATH_NODE(NextDevicePath,MEDIA_DEVICE_PATH,MEDIA_FILEPATH_DP)) {
-    return FALSE;
-  }
-
-  Status = gBS->HandleProtocol (Handle, &gEfiPxeBaseCodeProtocolGuid, (VOID **)&PxeBcProtocol);
-  if (EFI_ERROR (Status)) {
-    return FALSE;
-  } else {
-    return TRUE;
-  }
-}
-
-EFI_STATUS
-BdsTftpLoadImage (
-  IN     EFI_DEVICE_PATH*       DevicePath,
-  IN     EFI_HANDLE             Handle,
-  IN     EFI_DEVICE_PATH*       RemainingDevicePath,
-  IN     EFI_ALLOCATE_TYPE      Type,
-  IN OUT EFI_PHYSICAL_ADDRESS   *Image,
-  OUT    UINTN                  *ImageSize
-  )
-{
-  EFI_STATUS                  Status;
-  EFI_PXE_BASE_CODE_PROTOCOL  *Pxe;
-  UINT64                      TftpBufferSize;
-  VOID*                       TftpBuffer;
-  EFI_IP_ADDRESS              ServerIp;
-  IPv4_DEVICE_PATH*           IPv4DevicePathNode;
-  FILEPATH_DEVICE_PATH*       FilePathDevicePath;
-  EFI_IP_ADDRESS              LocalIp;
-
-  ASSERT(IS_DEVICE_PATH_NODE(RemainingDevicePath,MESSAGING_DEVICE_PATH,MSG_IPv4_DP));
-
-  IPv4DevicePathNode = (IPv4_DEVICE_PATH*)RemainingDevicePath;
-  FilePathDevicePath = (FILEPATH_DEVICE_PATH*)(IPv4DevicePathNode + 1);
-
-  Status = gBS->LocateProtocol (&gEfiPxeBaseCodeProtocolGuid, NULL, (VOID **)&Pxe);
-  if (EFI_ERROR(Status)) {
-    return Status;
-  }
-
-  Status = Pxe->Start (Pxe, FALSE);
-  if (EFI_ERROR(Status) && (Status != EFI_ALREADY_STARTED)) {
-    return Status;
-  }
-
-  if (!IPv4DevicePathNode->StaticIpAddress) {
-    Status = Pxe->Dhcp(Pxe, TRUE);
-  } else {
-    CopyMem (&LocalIp.v4, &IPv4DevicePathNode->LocalIpAddress, sizeof (EFI_IPv4_ADDRESS));
-    Status = Pxe->SetStationIp (Pxe, &LocalIp, NULL);
-  }
-  if (EFI_ERROR(Status)) {
-    return Status;
-  }
-
-  CopyMem (&ServerIp.v4, &IPv4DevicePathNode->RemoteIpAddress, sizeof (EFI_IPv4_ADDRESS));
-
-  Status = Pxe->Mtftp (
-                  Pxe,
-                  EFI_PXE_BASE_CODE_TFTP_GET_FILE_SIZE,
-                  NULL,
-                  FALSE,
-                  &TftpBufferSize,
-                  NULL,
-                  &ServerIp,
-                  (UINT8 *)FilePathDevicePath->PathName,
-                  NULL,
-                  TRUE
-                  );
-  if (EFI_ERROR(Status)) {
-    return Status;
-  }
-
-  // Allocate a buffer to hold the whole file.
-  TftpBuffer = AllocatePool(TftpBufferSize);
-  if (TftpBuffer == NULL) {
-    return EFI_OUT_OF_RESOURCES;
-  }
-
-  Status = Pxe->Mtftp (
-                  Pxe,
-                  EFI_PXE_BASE_CODE_TFTP_READ_FILE,
-                  TftpBuffer,
-                  FALSE,
-                  &TftpBufferSize,
-                  NULL,
-                  &ServerIp,
-                  (UINT8 *)FilePathDevicePath->PathName,
-                  NULL,
-                  FALSE
-                  );
-  if (EFI_ERROR(Status)) {
-    FreePool(TftpBuffer);
-  } else if (ImageSize != NULL) {
-    *ImageSize = (UINTN)TftpBufferSize;
-  }
-
-  return Status;
-}
-
-BDS_FILE_LOADER FileLoaders[] = {
-    { BdsFileSystemSupport, BdsFileSystemLoadImage },
-    { BdsFirmwareVolumeSupport, BdsFirmwareVolumeLoadImage },
-    //{ BdsLoadFileSupport, BdsLoadFileLoadImage },
-    { BdsMemoryMapSupport, BdsMemoryMapLoadImage },
-    { BdsPxeSupport, BdsPxeLoadImage },
-    { BdsTftpSupport, BdsTftpLoadImage },
-    { NULL, NULL }
-};
-
-EFI_STATUS
-BdsLoadImage (
-  IN     EFI_DEVICE_PATH       *DevicePath,
-  IN     EFI_ALLOCATE_TYPE     Type,
-  IN OUT EFI_PHYSICAL_ADDRESS* Image,
-  OUT    UINTN                 *FileSize
-  )
-{
-  EFI_STATUS      Status;
-  EFI_HANDLE      Handle;
-  EFI_DEVICE_PATH *RemainingDevicePath;
-  BDS_FILE_LOADER*  FileLoader;
-
-  Status = BdsConnectDevicePath (DevicePath, &Handle, &RemainingDevicePath);
-  if (EFI_ERROR (Status)) {
-    return Status;
-  }
-
-  FileLoader = FileLoaders;
-  while (FileLoader->Support != NULL) {
-    if (FileLoader->Support (DevicePath, Handle, RemainingDevicePath)) {
-      return FileLoader->LoadImage (DevicePath, Handle, RemainingDevicePath, Type, Image, FileSize);
-    }
-    FileLoader++;
-  }
-
-  return EFI_UNSUPPORTED;
-}
-
-/**
-  Start an EFI Application from a Device Path
-
-  @param  ParentImageHandle     Handle of the calling image
-  @param  DevicePath            Location of the EFI Application
-
-  @retval EFI_SUCCESS           All drivers have been connected
-  @retval EFI_NOT_FOUND         The Linux kernel Device Path has not been found
-  @retval EFI_OUT_OF_RESOURCES  There is not enough resource memory to store the matching results.
-
-**/
-EFI_STATUS
-BdsStartEfiApplication (
-  IN EFI_HANDLE                  ParentImageHandle,
-  IN EFI_DEVICE_PATH_PROTOCOL    *DevicePath,
-  IN UINTN                       LoadOptionsSize,
-  IN VOID*                       LoadOptions
-  )
-{
-  EFI_STATUS                   Status;
-  EFI_HANDLE                   ImageHandle;
-  EFI_PHYSICAL_ADDRESS         BinaryBuffer;
-  UINTN                        BinarySize;
-  EFI_LOADED_IMAGE_PROTOCOL*   LoadedImage;
-
-  // Find the nearest supported file loader
-  Status = BdsLoadImage (DevicePath, AllocateAnyPages, &BinaryBuffer, &BinarySize);
-  if (EFI_ERROR(Status)) {
-    return Status;
-  }
-
-  // Load the image from the Buffer with Boot Services function
-  Status = gBS->LoadImage (TRUE, ParentImageHandle, DevicePath, (VOID*)(UINTN)BinaryBuffer, BinarySize, &ImageHandle);
-  if (EFI_ERROR(Status)) {
-    return Status;
-  }
-
-  // Passed LoadOptions to the EFI Application
-  if (LoadOptionsSize != 0) {
-    Status = gBS->HandleProtocol (ImageHandle, &gEfiLoadedImageProtocolGuid, (VOID **) &LoadedImage);
-    if (EFI_ERROR(Status)) {
-      return Status;
-    }
-
-    LoadedImage->LoadOptionsSize  = LoadOptionsSize;
-    LoadedImage->LoadOptions      = LoadOptions;
-  }
-
-  // Before calling the image, enable the Watchdog Timer for  the 5 Minute period
-  gBS->SetWatchdogTimer (5 * 60, 0x0000, 0x00, NULL);
-  // Start the image
-  Status = gBS->StartImage (ImageHandle, NULL, NULL);
-  // Clear the Watchdog Timer after the image returns
-  gBS->SetWatchdogTimer (0x0000, 0x0000, 0x0000, NULL);
-
-  return Status;
-}
+/** @file\r
+*\r
+*  Copyright (c) 2011-2012, ARM Limited. All rights reserved.\r
+*  \r
+*  This program and the accompanying materials                          \r
+*  are licensed and made available under the terms and conditions of the BSD License         \r
+*  which accompanies this distribution.  The full text of the license may be found at        \r
+*  http://opensource.org/licenses/bsd-license.php                                            \r
+*\r
+*  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,                     \r
+*  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.             \r
+*\r
+**/\r
+\r
+#include "BdsInternal.h"\r
+\r
+#include <Protocol/UsbIo.h>\r
+#include <Protocol/DiskIo.h>\r
+#include <Protocol/LoadedImage.h>\r
+\r
+#define IS_DEVICE_PATH_NODE(node,type,subtype) (((node)->Type == (type)) && ((node)->SubType == (subtype)))\r
+\r
+// Extract the FilePath from the Device Path\r
+CHAR16*\r
+BdsExtractFilePathFromDevicePath (\r
+  IN  CONST CHAR16    *StrDevicePath,\r
+  IN  UINTN           NumberDevicePathNode\r
+  )\r
+{\r
+  UINTN       Node;\r
+  CHAR16      *Str;\r
+\r
+  Str = (CHAR16*)StrDevicePath;\r
+  Node = 0;\r
+  while ((Str != NULL) && (*Str != L'\0') && (Node < NumberDevicePathNode)) {\r
+    if ((*Str == L'/') || (*Str == L'\\')) {\r
+        Node++;\r
+    }\r
+    Str++;\r
+  }\r
+\r
+  if (*Str == L'\0') {\r
+    return NULL;\r
+  } else {\r
+    return Str;\r
+  }\r
+}\r
+\r
+BOOLEAN\r
+BdsIsRemovableUsb (\r
+  IN  EFI_DEVICE_PATH*  DevicePath\r
+  )\r
+{\r
+  return ((DevicePathType (DevicePath) == MESSAGING_DEVICE_PATH) &&\r
+          ((DevicePathSubType (DevicePath) == MSG_USB_CLASS_DP) ||\r
+           (DevicePathSubType (DevicePath) == MSG_USB_WWID_DP)));\r
+}\r
+\r
+EFI_STATUS\r
+BdsGetDeviceUsb (\r
+  IN  EFI_DEVICE_PATH*  RemovableDevicePath,\r
+  OUT EFI_HANDLE*       DeviceHandle,\r
+  OUT EFI_DEVICE_PATH** NewDevicePath\r
+  )\r
+{\r
+  EFI_STATUS                    Status;\r
+  UINTN                         Index;\r
+  UINTN                         UsbIoHandleCount;\r
+  EFI_HANDLE                    *UsbIoBuffer;\r
+  EFI_DEVICE_PATH*              UsbIoDevicePath;\r
+  EFI_DEVICE_PATH*              TmpDevicePath;\r
+  USB_WWID_DEVICE_PATH*         WwidDevicePath1;\r
+  USB_WWID_DEVICE_PATH*         WwidDevicePath2;\r
+  USB_CLASS_DEVICE_PATH*        UsbClassDevicePath1;\r
+  USB_CLASS_DEVICE_PATH*        UsbClassDevicePath2;\r
+\r
+  // Get all the UsbIo handles\r
+  UsbIoHandleCount = 0;\r
+  Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiUsbIoProtocolGuid, NULL, &UsbIoHandleCount, &UsbIoBuffer);\r
+  if (EFI_ERROR(Status) || (UsbIoHandleCount == 0)) {\r
+    return Status;\r
+  }\r
+\r
+  // Check if one of the handles matches the USB description\r
+  for (Index = 0; Index < UsbIoHandleCount; Index++) {\r
+    Status = gBS->HandleProtocol (UsbIoBuffer[Index], &gEfiDevicePathProtocolGuid, (VOID **) &UsbIoDevicePath);\r
+    if (!EFI_ERROR(Status)) {\r
+      TmpDevicePath = UsbIoDevicePath;\r
+      while (!IsDevicePathEnd (TmpDevicePath)) {\r
+        // Check if the Device Path node is a USB Removable device Path node\r
+        if (BdsIsRemovableUsb (TmpDevicePath)) {\r
+          if (TmpDevicePath->SubType == MSG_USB_WWID_DP) {\r
+            WwidDevicePath1 = (USB_WWID_DEVICE_PATH*)RemovableDevicePath;\r
+            WwidDevicePath2 = (USB_WWID_DEVICE_PATH*)TmpDevicePath;\r
+            if ((WwidDevicePath1->VendorId == WwidDevicePath2->VendorId) &&\r
+                (WwidDevicePath1->ProductId == WwidDevicePath2->ProductId) &&\r
+                (CompareMem (WwidDevicePath1+1, WwidDevicePath2+1, DevicePathNodeLength(WwidDevicePath1)-sizeof(USB_WWID_DEVICE_PATH)) == 0))\r
+            {\r
+              *DeviceHandle = UsbIoBuffer[Index];\r
+              // Add the additional original Device Path Nodes (eg: FilePath Device Path Node) to the new Device Path\r
+              *NewDevicePath = AppendDevicePath (UsbIoDevicePath, NextDevicePathNode(RemovableDevicePath));\r
+              return EFI_SUCCESS;\r
+            }\r
+          } else {\r
+            UsbClassDevicePath1 = (USB_CLASS_DEVICE_PATH*)RemovableDevicePath;\r
+            UsbClassDevicePath2 = (USB_CLASS_DEVICE_PATH*)TmpDevicePath;\r
+            if ((UsbClassDevicePath1->VendorId != 0xFFFF) && (UsbClassDevicePath1->VendorId == UsbClassDevicePath2->VendorId) &&\r
+                (UsbClassDevicePath1->ProductId != 0xFFFF) && (UsbClassDevicePath1->ProductId == UsbClassDevicePath2->ProductId) &&\r
+                (UsbClassDevicePath1->DeviceClass != 0xFF) && (UsbClassDevicePath1->DeviceClass == UsbClassDevicePath2->DeviceClass) &&\r
+                (UsbClassDevicePath1->DeviceSubClass != 0xFF) && (UsbClassDevicePath1->DeviceSubClass == UsbClassDevicePath2->DeviceSubClass) &&\r
+                (UsbClassDevicePath1->DeviceProtocol != 0xFF) && (UsbClassDevicePath1->DeviceProtocol == UsbClassDevicePath2->DeviceProtocol))\r
+            {\r
+              *DeviceHandle = UsbIoBuffer[Index];\r
+              // Add the additional original Device Path Nodes (eg: FilePath Device Path Node) to the new Device Path\r
+              *NewDevicePath = AppendDevicePath (UsbIoDevicePath, NextDevicePathNode(RemovableDevicePath));\r
+              return EFI_SUCCESS;\r
+            }\r
+          }\r
+        }\r
+        TmpDevicePath = NextDevicePathNode (TmpDevicePath);\r
+      }\r
+\r
+    }\r
+  }\r
+\r
+  return EFI_NOT_FOUND;\r
+}\r
+\r
+BOOLEAN\r
+BdsIsRemovableHd (\r
+  IN  EFI_DEVICE_PATH*  DevicePath\r
+  )\r
+{\r
+  return IS_DEVICE_PATH_NODE(DevicePath, MEDIA_DEVICE_PATH, MEDIA_HARDDRIVE_DP);\r
+}\r
+\r
+EFI_STATUS\r
+BdsGetDeviceHd (\r
+  IN  EFI_DEVICE_PATH*  RemovableDevicePath,\r
+  OUT EFI_HANDLE*       DeviceHandle,\r
+  OUT EFI_DEVICE_PATH** NewDevicePath\r
+  )\r
+{\r
+  EFI_STATUS                    Status;\r
+  UINTN                         Index;\r
+  UINTN                         PartitionHandleCount;\r
+  EFI_HANDLE                    *PartitionBuffer;\r
+  EFI_DEVICE_PATH*              PartitionDevicePath;\r
+  EFI_DEVICE_PATH*              TmpDevicePath;\r
+  HARDDRIVE_DEVICE_PATH*        HardDriveDevicePath1;\r
+  HARDDRIVE_DEVICE_PATH*        HardDriveDevicePath2;\r
+\r
+  // Get all the DiskIo handles\r
+  PartitionHandleCount = 0;\r
+  Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiDiskIoProtocolGuid, NULL, &PartitionHandleCount, &PartitionBuffer);\r
+  if (EFI_ERROR(Status) || (PartitionHandleCount == 0)) {\r
+    return Status;\r
+  }\r
+\r
+  // Check if one of the handles matches the Hard Disk Description\r
+  for (Index = 0; Index < PartitionHandleCount; Index++) {\r
+    Status = gBS->HandleProtocol (PartitionBuffer[Index], &gEfiDevicePathProtocolGuid, (VOID **) &PartitionDevicePath);\r
+    if (!EFI_ERROR(Status)) {\r
+      TmpDevicePath = PartitionDevicePath;\r
+      while (!IsDevicePathEnd (TmpDevicePath)) {\r
+        // Check if the Device Path node is a HD Removable device Path node\r
+        if (BdsIsRemovableHd (TmpDevicePath)) {\r
+          HardDriveDevicePath1 = (HARDDRIVE_DEVICE_PATH*)RemovableDevicePath;\r
+          HardDriveDevicePath2 = (HARDDRIVE_DEVICE_PATH*)TmpDevicePath;\r
+          if ((HardDriveDevicePath1->SignatureType == HardDriveDevicePath2->SignatureType) &&\r
+              (CompareGuid ((EFI_GUID *)HardDriveDevicePath1->Signature,(EFI_GUID *)HardDriveDevicePath2->Signature) == TRUE) &&\r
+              (HardDriveDevicePath1->PartitionNumber == HardDriveDevicePath2->PartitionNumber))\r
+          {\r
+            *DeviceHandle = PartitionBuffer[Index];\r
+            // Add the additional original Device Path Nodes (eg: FilePath Device Path Node) to the new Device Path\r
+            *NewDevicePath = AppendDevicePath (PartitionDevicePath, NextDevicePathNode(RemovableDevicePath));\r
+            return EFI_SUCCESS;\r
+          }\r
+        }\r
+        TmpDevicePath = NextDevicePathNode (TmpDevicePath);\r
+      }\r
+\r
+    }\r
+  }\r
+\r
+  return EFI_NOT_FOUND;\r
+}\r
+\r
+/*BOOLEAN\r
+BdsIsRemovableCdrom (\r
+  IN  EFI_DEVICE_PATH*  DevicePath\r
+  )\r
+{\r
+  return IS_DEVICE_PATH_NODE(DevicePath, MEDIA_DEVICE_PATH, MEDIA_CDROM_DP);\r
+}\r
+\r
+EFI_STATUS\r
+BdsGetDeviceCdrom (\r
+  IN  EFI_DEVICE_PATH*  RemovableDevicePath,\r
+  OUT EFI_HANDLE*       DeviceHandle,\r
+  OUT EFI_DEVICE_PATH** DevicePath\r
+  )\r
+{\r
+  ASSERT(0);\r
+  return EFI_UNSUPPORTED;\r
+}*/\r
+\r
+typedef BOOLEAN\r
+(*BDS_IS_REMOVABLE) (\r
+  IN  EFI_DEVICE_PATH*  DevicePath\r
+  );\r
+\r
+typedef EFI_STATUS\r
+(*BDS_GET_DEVICE) (\r
+  IN  EFI_DEVICE_PATH*  RemovableDevicePath,\r
+  OUT EFI_HANDLE*       DeviceHandle,\r
+  OUT EFI_DEVICE_PATH** DevicePath\r
+  );\r
+\r
+typedef struct {\r
+  BDS_IS_REMOVABLE    IsRemovable;\r
+  BDS_GET_DEVICE      GetDevice;\r
+} BDS_REMOVABLE_DEVICE_SUPPORT;\r
+\r
+BDS_REMOVABLE_DEVICE_SUPPORT  RemovableDeviceSupport[] = {\r
+  { BdsIsRemovableUsb, BdsGetDeviceUsb },\r
+  { BdsIsRemovableHd, BdsGetDeviceHd },\r
+  //{ BdsIsRemovableCdrom, BdsGetDeviceCdrom }\r
+};\r
+\r
+STATIC\r
+BOOLEAN\r
+IsRemovableDevice (\r
+  IN  EFI_DEVICE_PATH*  DevicePath\r
+  )\r
+{\r
+  UINTN             Index;\r
+  EFI_DEVICE_PATH*  TmpDevicePath;\r
+\r
+  TmpDevicePath = DevicePath;\r
+  while (!IsDevicePathEnd (TmpDevicePath)) {\r
+    for (Index = 0; Index < sizeof(RemovableDeviceSupport) / sizeof(BDS_REMOVABLE_DEVICE_SUPPORT); Index++) {\r
+      if (RemovableDeviceSupport[Index].IsRemovable(TmpDevicePath)) {\r
+        return TRUE;\r
+      }\r
+    }\r
+    TmpDevicePath = NextDevicePathNode (TmpDevicePath);\r
+  }\r
+\r
+  return FALSE;\r
+}\r
+\r
+STATIC\r
+EFI_STATUS\r
+TryRemovableDevice (\r
+  IN  EFI_DEVICE_PATH*  DevicePath,\r
+  OUT EFI_HANDLE*       DeviceHandle,\r
+  OUT EFI_DEVICE_PATH** NewDevicePath\r
+  )\r
+{\r
+  EFI_STATUS        Status;\r
+  UINTN             Index;\r
+  EFI_DEVICE_PATH*  TmpDevicePath;\r
+  BDS_REMOVABLE_DEVICE_SUPPORT* RemovableDevice;\r
+  EFI_DEVICE_PATH* RemovableDevicePath;\r
+  BOOLEAN         RemovableFound;\r
+\r
+  RemovableDevice     = NULL;\r
+  RemovableDevicePath = NULL;\r
+  RemovableFound      = FALSE;\r
+  TmpDevicePath       = DevicePath;\r
+\r
+  while (!IsDevicePathEnd (TmpDevicePath) && !RemovableFound) {\r
+    for (Index = 0; Index < sizeof(RemovableDeviceSupport) / sizeof(BDS_REMOVABLE_DEVICE_SUPPORT); Index++) {\r
+      RemovableDevice = &RemovableDeviceSupport[Index];\r
+      if (RemovableDevice->IsRemovable(TmpDevicePath)) {\r
+        RemovableDevicePath = TmpDevicePath;\r
+        RemovableFound = TRUE;\r
+        break;\r
+      }\r
+    }\r
+    TmpDevicePath = NextDevicePathNode (TmpDevicePath);\r
+  }\r
+\r
+  if (!RemovableFound) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  // Search into the current started drivers\r
+  Status = RemovableDevice->GetDevice (RemovableDevicePath, DeviceHandle, NewDevicePath);\r
+  if (Status == EFI_NOT_FOUND) {\r
+    // Connect all the drivers\r
+    BdsConnectAllDrivers ();\r
+\r
+    // Search again into all the drivers\r
+    Status = RemovableDevice->GetDevice (RemovableDevicePath, DeviceHandle, NewDevicePath);\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Connect a Device Path and return the handle of the driver that support this DevicePath\r
+\r
+  @param  DevicePath            Device Path of the File to connect\r
+  @param  Handle                Handle of the driver that support this DevicePath\r
+  @param  RemainingDevicePath   Remaining DevicePath nodes that do not match the driver DevicePath\r
+\r
+  @retval EFI_SUCCESS           A driver that matches the Device Path has been found\r
+  @retval EFI_NOT_FOUND         No handles match the search.\r
+  @retval EFI_INVALID_PARAMETER DevicePath or Handle is NULL\r
+\r
+**/\r
+EFI_STATUS\r
+BdsConnectDevicePath (\r
+  IN  EFI_DEVICE_PATH_PROTOCOL* DevicePath,\r
+  OUT EFI_HANDLE                *Handle,\r
+  OUT EFI_DEVICE_PATH_PROTOCOL  **RemainingDevicePath\r
+  )\r
+{\r
+  EFI_DEVICE_PATH*            Remaining;\r
+  EFI_DEVICE_PATH*            NewDevicePath;\r
+  EFI_STATUS                  Status;\r
+\r
+  if ((DevicePath == NULL) || (Handle == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  do {\r
+    Remaining = DevicePath;\r
+    // The LocateDevicePath() function locates all devices on DevicePath that support Protocol and returns\r
+    // the handle to the device that is closest to DevicePath. On output, the device path pointer is modified\r
+    // to point to the remaining part of the device path\r
+    Status = gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid, &Remaining, Handle);\r
+    if (!EFI_ERROR (Status)) {\r
+      // Recursive = FALSE: We do not want to start all the device tree\r
+      Status = gBS->ConnectController (*Handle, NULL, Remaining, FALSE);\r
+    }\r
+\r
+    /*// We need to check if RemainingDevicePath does not point on the last node. Otherwise, calling\r
+    // NextDevicePathNode() will return an undetermined Device Path Node\r
+    if (!IsDevicePathEnd (RemainingDevicePath)) {\r
+      RemainingDevicePath = NextDevicePathNode (RemainingDevicePath);\r
+    }*/\r
+  } while (!EFI_ERROR (Status) && !IsDevicePathEnd (Remaining));\r
+\r
+  if (!EFI_ERROR (Status)) {\r
+    // Now, we have got the whole Device Path connected, call again ConnectController to ensure all the supported Driver\r
+    // Binding Protocol are connected (such as DiskIo and SimpleFileSystem)\r
+    Remaining = DevicePath;\r
+    Status = gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid,&Remaining,Handle);\r
+    if (!EFI_ERROR (Status)) {\r
+      Status = gBS->ConnectController (*Handle, NULL, Remaining, FALSE);\r
+      if (EFI_ERROR (Status)) {\r
+        // If the last node is a Memory Map Device Path just return EFI_SUCCESS.\r
+        if ((Remaining->Type == HARDWARE_DEVICE_PATH) && (Remaining->SubType == HW_MEMMAP_DP)) {\r
+            Status = EFI_SUCCESS;\r
+        }\r
+      }\r
+    }\r
+  } else if (!IsDevicePathEnd (Remaining) && !IsRemovableDevice (Remaining)) {\r
+\r
+    /*// If the remaining Device Path is a FilePath or MemoryMap then we consider the Device Path has been loaded correctly\r
+    if ((Remaining->Type == MEDIA_DEVICE_PATH) && (Remaining->SubType == MEDIA_FILEPATH_DP)) {\r
+      Status = EFI_SUCCESS;\r
+    } else if ((Remaining->Type == HARDWARE_DEVICE_PATH) && (Remaining->SubType == HW_MEMMAP_DP)) {\r
+      Status = EFI_SUCCESS;\r
+    }*/\r
+\r
+    //TODO: Should we just return success and leave the caller decide if it is the expected RemainingPath\r
+    Status = EFI_SUCCESS;\r
+  } else {\r
+    Status = TryRemovableDevice (DevicePath, Handle, &NewDevicePath);\r
+    if (!EFI_ERROR (Status)) {\r
+      return BdsConnectDevicePath (NewDevicePath, Handle, RemainingDevicePath);\r
+    }\r
+  }\r
+\r
+  if (RemainingDevicePath) {\r
+    *RemainingDevicePath = Remaining;\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+BOOLEAN\r
+BdsFileSystemSupport (\r
+  IN EFI_DEVICE_PATH *DevicePath,\r
+  IN EFI_HANDLE Handle,\r
+  IN EFI_DEVICE_PATH *RemainingDevicePath\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+  EFI_SIMPLE_FILE_SYSTEM_PROTOCOL     *FsProtocol;\r
+\r
+  Status = gBS->HandleProtocol (Handle,&gEfiSimpleFileSystemProtocolGuid, (VOID **)&FsProtocol);\r
+\r
+  return (!EFI_ERROR(Status) && IS_DEVICE_PATH_NODE(RemainingDevicePath,MEDIA_DEVICE_PATH,MEDIA_FILEPATH_DP));\r
+}\r
+\r
+EFI_STATUS\r
+BdsFileSystemLoadImage (\r
+  IN     EFI_DEVICE_PATH *DevicePath,\r
+  IN     EFI_HANDLE Handle,\r
+  IN     EFI_DEVICE_PATH *RemainingDevicePath,\r
+  IN     EFI_ALLOCATE_TYPE     Type,\r
+  IN OUT EFI_PHYSICAL_ADDRESS* Image,\r
+  OUT    UINTN                 *ImageSize\r
+  )\r
+{\r
+  FILEPATH_DEVICE_PATH*             FilePathDevicePath;\r
+  EFI_SIMPLE_FILE_SYSTEM_PROTOCOL     *FsProtocol;\r
+  EFI_FILE_PROTOCOL                   *Fs;\r
+  EFI_STATUS Status;\r
+  EFI_FILE_INFO       *FileInfo;\r
+  EFI_FILE_PROTOCOL   *File;\r
+  UINTN               Size;\r
+\r
+  ASSERT (IS_DEVICE_PATH_NODE(RemainingDevicePath,MEDIA_DEVICE_PATH,MEDIA_FILEPATH_DP));\r
+\r
+  FilePathDevicePath = (FILEPATH_DEVICE_PATH*)RemainingDevicePath;\r
+\r
+  Status = gBS->HandleProtocol(Handle,&gEfiSimpleFileSystemProtocolGuid, (VOID **)&FsProtocol);\r
+  if (EFI_ERROR(Status)) {\r
+    return Status;\r
+  }\r
+\r
+  // Try to Open the volume and get root directory\r
+  Status = FsProtocol->OpenVolume (FsProtocol, &Fs);\r
+  if (EFI_ERROR(Status)) {\r
+    return Status;\r
+  }\r
+\r
+  File = NULL;\r
+  Status = Fs->Open(Fs, &File, FilePathDevicePath->PathName, EFI_FILE_MODE_READ, 0);\r
+  if (EFI_ERROR(Status)) {\r
+    return Status;\r
+  }\r
+\r
+  Size = 0;\r
+  File->GetInfo(File, &gEfiFileInfoGuid, &Size, NULL);\r
+  FileInfo = AllocatePool (Size);\r
+  Status = File->GetInfo(File, &gEfiFileInfoGuid, &Size, FileInfo);\r
+  if (EFI_ERROR(Status)) {\r
+    return Status;\r
+  }\r
+\r
+  // Get the file size\r
+  Size = FileInfo->FileSize;\r
+  if (ImageSize) {\r
+    *ImageSize = Size;\r
+  }\r
+  FreePool(FileInfo);\r
+\r
+  Status = gBS->AllocatePages (Type, EfiBootServicesCode, EFI_SIZE_TO_PAGES(Size), Image);\r
+  // Try to allocate in any pages if failed to allocate memory at the defined location\r
+  if ((Status == EFI_OUT_OF_RESOURCES) && (Type != AllocateAnyPages)) {\r
+    Status = gBS->AllocatePages (AllocateAnyPages, EfiBootServicesCode, EFI_SIZE_TO_PAGES(Size), Image);\r
+  }\r
+  if (!EFI_ERROR(Status)) {\r
+    Status = File->Read (File, &Size, (VOID*)(UINTN)(*Image));\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+BOOLEAN\r
+BdsMemoryMapSupport (\r
+  IN EFI_DEVICE_PATH *DevicePath,\r
+  IN EFI_HANDLE Handle,\r
+  IN EFI_DEVICE_PATH *RemainingDevicePath\r
+  )\r
+{\r
+  return IS_DEVICE_PATH_NODE(DevicePath,HARDWARE_DEVICE_PATH,HW_MEMMAP_DP) ||\r
+         IS_DEVICE_PATH_NODE(RemainingDevicePath,HARDWARE_DEVICE_PATH,HW_MEMMAP_DP);\r
+}\r
+\r
+EFI_STATUS\r
+BdsMemoryMapLoadImage (\r
+  IN     EFI_DEVICE_PATH *DevicePath,\r
+  IN     EFI_HANDLE Handle,\r
+  IN     EFI_DEVICE_PATH *RemainingDevicePath,\r
+  IN     EFI_ALLOCATE_TYPE     Type,\r
+  IN OUT EFI_PHYSICAL_ADDRESS* Image,\r
+  OUT    UINTN                 *ImageSize\r
+  )\r
+{\r
+  EFI_STATUS            Status;\r
+  MEMMAP_DEVICE_PATH*   MemMapPathDevicePath;\r
+  UINTN                 Size;\r
+\r
+  if (IS_DEVICE_PATH_NODE(RemainingDevicePath,HARDWARE_DEVICE_PATH,HW_MEMMAP_DP)) {\r
+    MemMapPathDevicePath = (MEMMAP_DEVICE_PATH*)RemainingDevicePath;\r
+  } else {\r
+    ASSERT (IS_DEVICE_PATH_NODE(DevicePath,HARDWARE_DEVICE_PATH,HW_MEMMAP_DP));\r
+    MemMapPathDevicePath = (MEMMAP_DEVICE_PATH*)DevicePath;\r
+  }\r
+\r
+  Size = MemMapPathDevicePath->EndingAddress - MemMapPathDevicePath->StartingAddress;\r
+  if (Size == 0) {\r
+      return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Status = gBS->AllocatePages (Type, EfiBootServicesCode, EFI_SIZE_TO_PAGES(Size), Image);\r
+  // Try to allocate in any pages if failed to allocate memory at the defined location\r
+  if ((Status == EFI_OUT_OF_RESOURCES) && (Type != AllocateAnyPages)) {\r
+    Status = gBS->AllocatePages (AllocateAnyPages, EfiBootServicesCode, EFI_SIZE_TO_PAGES(Size), Image);\r
+  }\r
+  if (!EFI_ERROR(Status)) {\r
+    CopyMem ((VOID*)(UINTN)(*Image), (CONST VOID*)(UINTN)MemMapPathDevicePath->StartingAddress, Size);\r
+\r
+    if (ImageSize != NULL) {\r
+        *ImageSize = Size;\r
+    }\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+BOOLEAN\r
+BdsFirmwareVolumeSupport (\r
+  IN EFI_DEVICE_PATH *DevicePath,\r
+  IN EFI_HANDLE Handle,\r
+  IN EFI_DEVICE_PATH *RemainingDevicePath\r
+  )\r
+{\r
+  return IS_DEVICE_PATH_NODE(RemainingDevicePath, MEDIA_DEVICE_PATH, MEDIA_PIWG_FW_FILE_DP);\r
+}\r
+\r
+EFI_STATUS\r
+BdsFirmwareVolumeLoadImage (\r
+  IN     EFI_DEVICE_PATH *DevicePath,\r
+  IN     EFI_HANDLE Handle,\r
+  IN     EFI_DEVICE_PATH *RemainingDevicePath,\r
+  IN     EFI_ALLOCATE_TYPE     Type,\r
+  IN OUT EFI_PHYSICAL_ADDRESS* Image,\r
+  OUT    UINTN                 *ImageSize\r
+  )\r
+{\r
+  EFI_STATUS            Status;\r
+  EFI_FIRMWARE_VOLUME2_PROTOCOL     *FwVol;\r
+  EFI_GUID                          *FvNameGuid;\r
+  EFI_SECTION_TYPE                  SectionType;\r
+  EFI_FV_FILETYPE                   FvType;\r
+  EFI_FV_FILE_ATTRIBUTES            Attrib;\r
+  UINT32                            AuthenticationStatus;\r
+  VOID* ImageBuffer;\r
+\r
+  ASSERT (IS_DEVICE_PATH_NODE(RemainingDevicePath, MEDIA_DEVICE_PATH, MEDIA_PIWG_FW_FILE_DP));\r
+\r
+  Status = gBS->HandleProtocol(Handle,&gEfiFirmwareVolume2ProtocolGuid, (VOID **)&FwVol);\r
+  if (EFI_ERROR(Status)) {\r
+    return Status;\r
+  }\r
+\r
+  FvNameGuid = EfiGetNameGuidFromFwVolDevicePathNode ((CONST MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *)RemainingDevicePath);\r
+  if (FvNameGuid == NULL) {\r
+    Status = EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  SectionType = EFI_SECTION_PE32;\r
+  AuthenticationStatus = 0;\r
+  //Note: ReadSection at the opposite of ReadFile does not allow to pass ImageBuffer == NULL to get the size of the file.\r
+  ImageBuffer = NULL;\r
+  Status = FwVol->ReadSection (\r
+                    FwVol,\r
+                    FvNameGuid,\r
+                    SectionType,\r
+                    0,\r
+                    &ImageBuffer,\r
+                    ImageSize,\r
+                    &AuthenticationStatus\r
+                    );\r
+  if (!EFI_ERROR (Status)) {\r
+#if 0\r
+    // In case the buffer has some address requirements, we must copy the buffer to a buffer following the requirements\r
+    if (Type != AllocateAnyPages) {\r
+      Status = gBS->AllocatePages (Type, EfiBootServicesCode, EFI_SIZE_TO_PAGES(*ImageSize),Image);\r
+      if (!EFI_ERROR(Status)) {\r
+        CopyMem ((VOID*)(UINTN)(*Image), ImageBuffer, *ImageSize);\r
+        FreePool (ImageBuffer);\r
+      }\r
+    }\r
+#else\r
+    // We must copy the buffer into a page allocations. Otherwise, the caller could call gBS->FreePages() on the pool allocation\r
+    Status = gBS->AllocatePages (Type, EfiBootServicesCode, EFI_SIZE_TO_PAGES(*ImageSize), Image);\r
+    // Try to allocate in any pages if failed to allocate memory at the defined location\r
+    if ((Status == EFI_OUT_OF_RESOURCES) && (Type != AllocateAnyPages)) {\r
+      Status = gBS->AllocatePages (AllocateAnyPages, EfiBootServicesCode, EFI_SIZE_TO_PAGES(*ImageSize), Image);\r
+    }\r
+    if (!EFI_ERROR(Status)) {\r
+      CopyMem ((VOID*)(UINTN)(*Image), ImageBuffer, *ImageSize);\r
+      FreePool (ImageBuffer);\r
+    }\r
+#endif\r
+  } else {\r
+    // Try a raw file, since a PE32 SECTION does not exist\r
+    Status = FwVol->ReadFile (\r
+                        FwVol,\r
+                        FvNameGuid,\r
+                        NULL,\r
+                        ImageSize,\r
+                        &FvType,\r
+                        &Attrib,\r
+                        &AuthenticationStatus\r
+                        );\r
+    if (!EFI_ERROR(Status)) {\r
+      Status = gBS->AllocatePages (Type, EfiBootServicesCode, EFI_SIZE_TO_PAGES(*ImageSize), Image);\r
+      // Try to allocate in any pages if failed to allocate memory at the defined location\r
+      if ((Status == EFI_OUT_OF_RESOURCES) && (Type != AllocateAnyPages)) {\r
+        Status = gBS->AllocatePages (AllocateAnyPages, EfiBootServicesCode, EFI_SIZE_TO_PAGES(*ImageSize), Image);\r
+      }\r
+      if (!EFI_ERROR(Status)) {\r
+        Status = FwVol->ReadFile (\r
+                                FwVol,\r
+                                FvNameGuid,\r
+                                (VOID*)(UINTN)(*Image),\r
+                                ImageSize,\r
+                                &FvType,\r
+                                &Attrib,\r
+                                &AuthenticationStatus\r
+                                );\r
+      }\r
+    }\r
+  }\r
+  return Status;\r
+}\r
+\r
+BOOLEAN\r
+BdsPxeSupport (\r
+  IN EFI_DEVICE_PATH*           DevicePath,\r
+  IN EFI_HANDLE                 Handle,\r
+  IN EFI_DEVICE_PATH*           RemainingDevicePath\r
+  )\r
+{\r
+  EFI_STATUS                  Status;\r
+  EFI_PXE_BASE_CODE_PROTOCOL* PxeBcProtocol;\r
+\r
+  if (!IsDevicePathEnd(RemainingDevicePath)) {\r
+    return FALSE;\r
+  }\r
+\r
+  Status = gBS->HandleProtocol (Handle, &gEfiPxeBaseCodeProtocolGuid, (VOID **)&PxeBcProtocol);\r
+  if (EFI_ERROR (Status)) {\r
+    return FALSE;\r
+  } else {\r
+    return TRUE;\r
+  }\r
+}\r
+\r
+EFI_STATUS\r
+BdsPxeLoadImage (\r
+  IN     EFI_DEVICE_PATH*       DevicePath,\r
+  IN     EFI_HANDLE             Handle,\r
+  IN     EFI_DEVICE_PATH*       RemainingDevicePath,\r
+  IN     EFI_ALLOCATE_TYPE      Type,\r
+  IN OUT EFI_PHYSICAL_ADDRESS   *Image,\r
+  OUT    UINTN                  *ImageSize\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+  EFI_LOAD_FILE_PROTOCOL  *LoadFileProtocol;\r
+  UINTN                   BufferSize;\r
+\r
+  // Get Load File Protocol attached to the PXE protocol\r
+  Status = gBS->HandleProtocol (Handle, &gEfiLoadFileProtocolGuid, (VOID **)&LoadFileProtocol);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  Status = LoadFileProtocol->LoadFile (LoadFileProtocol, DevicePath, TRUE, &BufferSize, NULL);\r
+  if (Status == EFI_BUFFER_TOO_SMALL) {\r
+    Status = gBS->AllocatePages (Type, EfiBootServicesCode, EFI_SIZE_TO_PAGES(BufferSize), Image);\r
+    if (EFI_ERROR(Status)) {\r
+      return Status;\r
+    }\r
+\r
+    Status = LoadFileProtocol->LoadFile (LoadFileProtocol, DevicePath, TRUE, &BufferSize, (VOID*)(UINTN)(*Image));\r
+    if (!EFI_ERROR(Status) && (ImageSize != NULL)) {\r
+      *ImageSize = BufferSize;\r
+    }\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+BOOLEAN\r
+BdsTftpSupport (\r
+  IN EFI_DEVICE_PATH*           DevicePath,\r
+  IN EFI_HANDLE                 Handle,\r
+  IN EFI_DEVICE_PATH*           RemainingDevicePath\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+  EFI_DEVICE_PATH  *NextDevicePath;\r
+  EFI_PXE_BASE_CODE_PROTOCOL  *PxeBcProtocol;\r
+\r
+  // Validate the Remaining Device Path\r
+  if (IsDevicePathEnd(RemainingDevicePath)) {\r
+    return FALSE;\r
+  }\r
+  if (!IS_DEVICE_PATH_NODE(RemainingDevicePath,MESSAGING_DEVICE_PATH,MSG_IPv4_DP) &&\r
+      !IS_DEVICE_PATH_NODE(RemainingDevicePath,MESSAGING_DEVICE_PATH,MSG_IPv6_DP)) {\r
+    return FALSE;\r
+  }\r
+  NextDevicePath = NextDevicePathNode (RemainingDevicePath);\r
+  if (IsDevicePathEnd(NextDevicePath)) {\r
+    return FALSE;\r
+  }\r
+  if (!IS_DEVICE_PATH_NODE(NextDevicePath,MEDIA_DEVICE_PATH,MEDIA_FILEPATH_DP)) {\r
+    return FALSE;\r
+  }\r
+\r
+  Status = gBS->HandleProtocol (Handle, &gEfiPxeBaseCodeProtocolGuid, (VOID **)&PxeBcProtocol);\r
+  if (EFI_ERROR (Status)) {\r
+    return FALSE;\r
+  } else {\r
+    return TRUE;\r
+  }\r
+}\r
+\r
+EFI_STATUS\r
+BdsTftpLoadImage (\r
+  IN     EFI_DEVICE_PATH*       DevicePath,\r
+  IN     EFI_HANDLE             Handle,\r
+  IN     EFI_DEVICE_PATH*       RemainingDevicePath,\r
+  IN     EFI_ALLOCATE_TYPE      Type,\r
+  IN OUT EFI_PHYSICAL_ADDRESS   *Image,\r
+  OUT    UINTN                  *ImageSize\r
+  )\r
+{\r
+  EFI_STATUS                  Status;\r
+  EFI_PXE_BASE_CODE_PROTOCOL  *Pxe;\r
+  UINT64                      TftpBufferSize;\r
+  VOID*                       TftpBuffer;\r
+  EFI_IP_ADDRESS              ServerIp;\r
+  IPv4_DEVICE_PATH*           IPv4DevicePathNode;\r
+  FILEPATH_DEVICE_PATH*       FilePathDevicePath;\r
+  EFI_IP_ADDRESS              LocalIp;\r
+\r
+  ASSERT(IS_DEVICE_PATH_NODE(RemainingDevicePath,MESSAGING_DEVICE_PATH,MSG_IPv4_DP));\r
+\r
+  IPv4DevicePathNode = (IPv4_DEVICE_PATH*)RemainingDevicePath;\r
+  FilePathDevicePath = (FILEPATH_DEVICE_PATH*)(IPv4DevicePathNode + 1);\r
+\r
+  Status = gBS->LocateProtocol (&gEfiPxeBaseCodeProtocolGuid, NULL, (VOID **)&Pxe);\r
+  if (EFI_ERROR(Status)) {\r
+    return Status;\r
+  }\r
+\r
+  Status = Pxe->Start (Pxe, FALSE);\r
+  if (EFI_ERROR(Status) && (Status != EFI_ALREADY_STARTED)) {\r
+    return Status;\r
+  }\r
+\r
+  if (!IPv4DevicePathNode->StaticIpAddress) {\r
+    Status = Pxe->Dhcp(Pxe, TRUE);\r
+  } else {\r
+    CopyMem (&LocalIp.v4, &IPv4DevicePathNode->LocalIpAddress, sizeof (EFI_IPv4_ADDRESS));\r
+    Status = Pxe->SetStationIp (Pxe, &LocalIp, NULL);\r
+  }\r
+  if (EFI_ERROR(Status)) {\r
+    return Status;\r
+  }\r
+\r
+  CopyMem (&ServerIp.v4, &IPv4DevicePathNode->RemoteIpAddress, sizeof (EFI_IPv4_ADDRESS));\r
+\r
+  Status = Pxe->Mtftp (\r
+                  Pxe,\r
+                  EFI_PXE_BASE_CODE_TFTP_GET_FILE_SIZE,\r
+                  NULL,\r
+                  FALSE,\r
+                  &TftpBufferSize,\r
+                  NULL,\r
+                  &ServerIp,\r
+                  (UINT8 *)FilePathDevicePath->PathName,\r
+                  NULL,\r
+                  TRUE\r
+                  );\r
+  if (EFI_ERROR(Status)) {\r
+    return Status;\r
+  }\r
+\r
+  // Allocate a buffer to hold the whole file.\r
+  TftpBuffer = AllocatePool(TftpBufferSize);\r
+  if (TftpBuffer == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  Status = Pxe->Mtftp (\r
+                  Pxe,\r
+                  EFI_PXE_BASE_CODE_TFTP_READ_FILE,\r
+                  TftpBuffer,\r
+                  FALSE,\r
+                  &TftpBufferSize,\r
+                  NULL,\r
+                  &ServerIp,\r
+                  (UINT8 *)FilePathDevicePath->PathName,\r
+                  NULL,\r
+                  FALSE\r
+                  );\r
+  if (EFI_ERROR(Status)) {\r
+    FreePool(TftpBuffer);\r
+  } else if (ImageSize != NULL) {\r
+    *ImageSize = (UINTN)TftpBufferSize;\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+BDS_FILE_LOADER FileLoaders[] = {\r
+    { BdsFileSystemSupport, BdsFileSystemLoadImage },\r
+    { BdsFirmwareVolumeSupport, BdsFirmwareVolumeLoadImage },\r
+    //{ BdsLoadFileSupport, BdsLoadFileLoadImage },\r
+    { BdsMemoryMapSupport, BdsMemoryMapLoadImage },\r
+    { BdsPxeSupport, BdsPxeLoadImage },\r
+    { BdsTftpSupport, BdsTftpLoadImage },\r
+    { NULL, NULL }\r
+};\r
+\r
+EFI_STATUS\r
+BdsLoadImage (\r
+  IN     EFI_DEVICE_PATH       *DevicePath,\r
+  IN     EFI_ALLOCATE_TYPE     Type,\r
+  IN OUT EFI_PHYSICAL_ADDRESS* Image,\r
+  OUT    UINTN                 *FileSize\r
+  )\r
+{\r
+  EFI_STATUS      Status;\r
+  EFI_HANDLE      Handle;\r
+  EFI_DEVICE_PATH *RemainingDevicePath;\r
+  BDS_FILE_LOADER*  FileLoader;\r
+\r
+  Status = BdsConnectDevicePath (DevicePath, &Handle, &RemainingDevicePath);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  FileLoader = FileLoaders;\r
+  while (FileLoader->Support != NULL) {\r
+    if (FileLoader->Support (DevicePath, Handle, RemainingDevicePath)) {\r
+      return FileLoader->LoadImage (DevicePath, Handle, RemainingDevicePath, Type, Image, FileSize);\r
+    }\r
+    FileLoader++;\r
+  }\r
+\r
+  return EFI_UNSUPPORTED;\r
+}\r
+\r
+/**\r
+  Start an EFI Application from a Device Path\r
+\r
+  @param  ParentImageHandle     Handle of the calling image\r
+  @param  DevicePath            Location of the EFI Application\r
+\r
+  @retval EFI_SUCCESS           All drivers have been connected\r
+  @retval EFI_NOT_FOUND         The Linux kernel Device Path has not been found\r
+  @retval EFI_OUT_OF_RESOURCES  There is not enough resource memory to store the matching results.\r
+\r
+**/\r
+EFI_STATUS\r
+BdsStartEfiApplication (\r
+  IN EFI_HANDLE                  ParentImageHandle,\r
+  IN EFI_DEVICE_PATH_PROTOCOL    *DevicePath,\r
+  IN UINTN                       LoadOptionsSize,\r
+  IN VOID*                       LoadOptions\r
+  )\r
+{\r
+  EFI_STATUS                   Status;\r
+  EFI_HANDLE                   ImageHandle;\r
+  EFI_PHYSICAL_ADDRESS         BinaryBuffer;\r
+  UINTN                        BinarySize;\r
+  EFI_LOADED_IMAGE_PROTOCOL*   LoadedImage;\r
+\r
+  // Find the nearest supported file loader\r
+  Status = BdsLoadImage (DevicePath, AllocateAnyPages, &BinaryBuffer, &BinarySize);\r
+  if (EFI_ERROR(Status)) {\r
+    return Status;\r
+  }\r
+\r
+  // Load the image from the Buffer with Boot Services function\r
+  Status = gBS->LoadImage (TRUE, ParentImageHandle, DevicePath, (VOID*)(UINTN)BinaryBuffer, BinarySize, &ImageHandle);\r
+  if (EFI_ERROR(Status)) {\r
+    return Status;\r
+  }\r
+\r
+  // Passed LoadOptions to the EFI Application\r
+  if (LoadOptionsSize != 0) {\r
+    Status = gBS->HandleProtocol (ImageHandle, &gEfiLoadedImageProtocolGuid, (VOID **) &LoadedImage);\r
+    if (EFI_ERROR(Status)) {\r
+      return Status;\r
+    }\r
+\r
+    LoadedImage->LoadOptionsSize  = LoadOptionsSize;\r
+    LoadedImage->LoadOptions      = LoadOptions;\r
+  }\r
+\r
+  // Before calling the image, enable the Watchdog Timer for  the 5 Minute period\r
+  gBS->SetWatchdogTimer (5 * 60, 0x0000, 0x00, NULL);\r
+  // Start the image\r
+  Status = gBS->StartImage (ImageHandle, NULL, NULL);\r
+  // Clear the Watchdog Timer after the image returns\r
+  gBS->SetWatchdogTimer (0x0000, 0x0000, 0x0000, NULL);\r
+\r
+  return Status;\r
+}\r