public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
* [PATCH edk2-platforms 0/4] Platform/ARM: import BdsLib and FdtPlatformDxe
@ 2017-11-20 11:37 Ard Biesheuvel
  2017-11-20 11:37 ` [PATCH edk2-platforms 1/4] Platform/ARM: import BdsLib from ArmPkg Ard Biesheuvel
                   ` (4 more replies)
  0 siblings, 5 replies; 7+ messages in thread
From: Ard Biesheuvel @ 2017-11-20 11:37 UTC (permalink / raw)
  To: edk2-devel; +Cc: leif.lindholm, Ard Biesheuvel

The only remnant of the deprecated ARM BDS in EDK2 is its BdsLib, which is
depended upon by FdtPlatformDxe in EmbeddedPkg, which itself is something
we'd prefer to get rid of. Since only TC2 and Juno actually use this driver,
let's move both FdtPlatformDxe and BdsLib under Platform/ARM, so that we can
remove it from the main EDK2 repository.

Ard Biesheuvel (4):
  Platform/ARM: import BdsLib from ArmPkg
  Platform/ARM: import FdtPlatformDxe driver from EDK2
  Platform/ARM/Juno: move to migrated FdtPlatformDxe
  Platform/TC2: move to private FdtPlatformDxe implementation

 Platform/ARM/Drivers/FdtPlatformDxe/FdtPlatform.c      |  461 +++++++
 Platform/ARM/Drivers/FdtPlatformDxe/FdtPlatform.h      |  174 +++
 Platform/ARM/Drivers/FdtPlatformDxe/FdtPlatformDxe.dec |   31 +
 Platform/ARM/Drivers/FdtPlatformDxe/FdtPlatformDxe.inf |   65 +
 Platform/ARM/Drivers/FdtPlatformDxe/FdtPlatformDxe.uni |  109 ++
 Platform/ARM/Drivers/FdtPlatformDxe/README.txt         |   72 +
 Platform/ARM/Drivers/FdtPlatformDxe/ShellDumpFdt.c     |  279 ++++
 Platform/ARM/Drivers/FdtPlatformDxe/ShellSetFdt.c      |  468 +++++++
 Platform/ARM/JunoPkg/ArmJuno.dsc                       |    6 +-
 Platform/ARM/JunoPkg/ArmJuno.fdf                       |    2 +-
 Platform/ARM/JunoPkg/Drivers/ArmJunoDxe/ArmJunoDxe.inf |    3 +-
 Platform/ARM/Library/BdsLib/BdsAppLoader.c             |  253 ++++
 Platform/ARM/Library/BdsLib/BdsFilePath.c              | 1413 ++++++++++++++++++++
 Platform/ARM/Library/BdsLib/BdsHelper.c                |  183 +++
 Platform/ARM/Library/BdsLib/BdsInternal.h              |  111 ++
 Platform/ARM/Library/BdsLib/BdsLib.inf                 |   62 +
 Platform/ARM/Library/BdsLib/BdsLoadOption.c            |  272 ++++
 Platform/ARM/VExpressPkg/ArmVExpress-CTA15-A7.dsc      |    6 +-
 Platform/ARM/VExpressPkg/ArmVExpress-CTA15-A7.fdf      |    2 +-
 Platform/ARM/VExpressPkg/ArmVExpress.dsc.inc           |    5 +-
 20 files changed, 3964 insertions(+), 13 deletions(-)
 create mode 100644 Platform/ARM/Drivers/FdtPlatformDxe/FdtPlatform.c
 create mode 100644 Platform/ARM/Drivers/FdtPlatformDxe/FdtPlatform.h
 create mode 100644 Platform/ARM/Drivers/FdtPlatformDxe/FdtPlatformDxe.dec
 create mode 100644 Platform/ARM/Drivers/FdtPlatformDxe/FdtPlatformDxe.inf
 create mode 100644 Platform/ARM/Drivers/FdtPlatformDxe/FdtPlatformDxe.uni
 create mode 100644 Platform/ARM/Drivers/FdtPlatformDxe/README.txt
 create mode 100644 Platform/ARM/Drivers/FdtPlatformDxe/ShellDumpFdt.c
 create mode 100644 Platform/ARM/Drivers/FdtPlatformDxe/ShellSetFdt.c
 create mode 100644 Platform/ARM/Library/BdsLib/BdsAppLoader.c
 create mode 100644 Platform/ARM/Library/BdsLib/BdsFilePath.c
 create mode 100644 Platform/ARM/Library/BdsLib/BdsHelper.c
 create mode 100644 Platform/ARM/Library/BdsLib/BdsInternal.h
 create mode 100644 Platform/ARM/Library/BdsLib/BdsLib.inf
 create mode 100644 Platform/ARM/Library/BdsLib/BdsLoadOption.c

-- 
2.11.0



^ permalink raw reply	[flat|nested] 7+ messages in thread

* [PATCH edk2-platforms 1/4] Platform/ARM: import BdsLib from ArmPkg
  2017-11-20 11:37 [PATCH edk2-platforms 0/4] Platform/ARM: import BdsLib and FdtPlatformDxe Ard Biesheuvel
@ 2017-11-20 11:37 ` Ard Biesheuvel
  2017-11-20 11:37 ` [PATCH edk2-platforms 2/4] Platform/ARM: import FdtPlatformDxe driver from EDK2 Ard Biesheuvel
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 7+ messages in thread
From: Ard Biesheuvel @ 2017-11-20 11:37 UTC (permalink / raw)
  To: edk2-devel; +Cc: leif.lindholm, Ard Biesheuvel

We are about to migrate the only remaining user of the deprecated ARM
BdsLib, i.e., FdtPlatformDxe, into Platform/ARM. So create our own
copy of BdsLib, allowing us to finally remove it from upstream EDK2.

Contributed-under: TianoCore Contribution Agreement 1.1
Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
---
 Platform/ARM/Library/BdsLib/BdsAppLoader.c  |  253 ++++
 Platform/ARM/Library/BdsLib/BdsFilePath.c   | 1413 ++++++++++++++++++++
 Platform/ARM/Library/BdsLib/BdsHelper.c     |  183 +++
 Platform/ARM/Library/BdsLib/BdsInternal.h   |  111 ++
 Platform/ARM/Library/BdsLib/BdsLib.inf      |   62 +
 Platform/ARM/Library/BdsLib/BdsLoadOption.c |  272 ++++
 6 files changed, 2294 insertions(+)

diff --git a/Platform/ARM/Library/BdsLib/BdsAppLoader.c b/Platform/ARM/Library/BdsLib/BdsAppLoader.c
new file mode 100644
index 000000000000..1f208f8dd796
--- /dev/null
+++ b/Platform/ARM/Library/BdsLib/BdsAppLoader.c
@@ -0,0 +1,253 @@
+/** @file
+*
+*  Copyright (c) 2011-2015, 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"
+
+/**
+  Locate an EFI application in a the Firmware Volumes by its Name
+
+  @param  EfiAppGuid            Guid of the EFI Application into the Firmware Volume
+  @param  DevicePath            EFI Device Path of the EFI application
+
+  @return EFI_SUCCESS           The function completed successfully.
+  @return EFI_NOT_FOUND         The protocol could not be located.
+  @return EFI_OUT_OF_RESOURCES  There are not enough resources to find the protocol.
+
+**/
+EFI_STATUS
+LocateEfiApplicationInFvByName (
+  IN  CONST CHAR16*             EfiAppName,
+  OUT EFI_DEVICE_PATH           **DevicePath
+  )
+{
+  VOID                          *Key;
+  EFI_STATUS                    Status, FileStatus;
+  EFI_GUID                      NameGuid;
+  EFI_FV_FILETYPE               FileType;
+  EFI_FV_FILE_ATTRIBUTES        Attributes;
+  UINTN                         Size;
+  UINTN                         UiStringLen;
+  CHAR16                        *UiSection;
+  UINT32                        Authentication;
+  EFI_DEVICE_PATH               *FvDevicePath;
+  MEDIA_FW_VOL_FILEPATH_DEVICE_PATH    FileDevicePath;
+  EFI_HANDLE                    *HandleBuffer;
+  UINTN                         NumberOfHandles;
+  UINTN                         Index;
+  EFI_FIRMWARE_VOLUME2_PROTOCOL *FvInstance;
+
+  ASSERT (DevicePath != NULL);
+
+  // Length of FilePath
+  UiStringLen = StrLen (EfiAppName);
+
+  // Locate all the Firmware Volume protocols.
+  Status = gBS->LocateHandleBuffer (
+                   ByProtocol,
+                   &gEfiFirmwareVolume2ProtocolGuid,
+                   NULL,
+                   &NumberOfHandles,
+                   &HandleBuffer
+                   );
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  *DevicePath = NULL;
+
+  // Looking for FV with ACPI storage file
+  for (Index = 0; Index < NumberOfHandles; Index++) {
+    //
+    // Get the protocol on this handle
+    // This should not fail because of LocateHandleBuffer
+    //
+    Status = gBS->HandleProtocol (
+                     HandleBuffer[Index],
+                     &gEfiFirmwareVolume2ProtocolGuid,
+                     (VOID**) &FvInstance
+                     );
+    if (EFI_ERROR (Status)) {
+      goto FREE_HANDLE_BUFFER;
+    }
+
+    // Allocate Key
+    Key = AllocatePool (FvInstance->KeySize);
+    ASSERT (Key != NULL);
+    ZeroMem (Key, FvInstance->KeySize);
+
+    do {
+      // Search in all files
+      FileType = EFI_FV_FILETYPE_ALL;
+
+      Status = FvInstance->GetNextFile (FvInstance, Key, &FileType, &NameGuid, &Attributes, &Size);
+      if (!EFI_ERROR (Status)) {
+        UiSection = NULL;
+        FileStatus = FvInstance->ReadSection (
+                      FvInstance,
+                      &NameGuid,
+                      EFI_SECTION_USER_INTERFACE,
+                      0,
+                      (VOID **)&UiSection,
+                      &Size,
+                      &Authentication
+                      );
+        if (!EFI_ERROR (FileStatus)) {
+          if (StrnCmp (EfiAppName, UiSection, UiStringLen) == 0) {
+            //
+            // We found a UiString match.
+            //
+            Status = gBS->HandleProtocol (HandleBuffer[Index], &gEfiDevicePathProtocolGuid, (VOID **)&FvDevicePath);
+
+            // Generate the Device Path for the file
+            EfiInitializeFwVolDevicepathNode (&FileDevicePath, &NameGuid);
+            *DevicePath = AppendDevicePathNode (FvDevicePath, (EFI_DEVICE_PATH_PROTOCOL *)&FileDevicePath);
+            ASSERT (*DevicePath != NULL);
+
+            FreePool (Key);
+            FreePool (UiSection);
+            FreePool (HandleBuffer);
+            return FileStatus;
+          }
+          FreePool (UiSection);
+        }
+      }
+    } while (!EFI_ERROR (Status));
+
+    FreePool (Key);
+  }
+
+FREE_HANDLE_BUFFER:
+  FreePool (HandleBuffer);
+  return EFI_NOT_FOUND;
+}
+
+/**
+  Locate an EFI application in a the Firmware Volumes by its GUID
+
+  @param  EfiAppGuid            Guid of the EFI Application into the Firmware Volume
+  @param  DevicePath            EFI Device Path of the EFI application
+
+  @return EFI_SUCCESS           The function completed successfully.
+  @return EFI_NOT_FOUND         The protocol could not be located.
+  @return EFI_OUT_OF_RESOURCES  There are not enough resources to find the protocol.
+
+**/
+EFI_STATUS
+LocateEfiApplicationInFvByGuid (
+  IN  CONST EFI_GUID            *EfiAppGuid,
+  OUT EFI_DEVICE_PATH           **DevicePath
+  )
+{
+  EFI_STATUS                    Status;
+  EFI_DEVICE_PATH               *FvDevicePath;
+  EFI_HANDLE                    *HandleBuffer;
+  UINTN                         NumberOfHandles;
+  UINTN                         Index;
+  EFI_FIRMWARE_VOLUME2_PROTOCOL *FvInstance;
+  EFI_FV_FILE_ATTRIBUTES        Attributes;
+  UINT32                        AuthenticationStatus;
+  EFI_FV_FILETYPE               Type;
+  UINTN                         Size;
+  CHAR16                        *UiSection;
+  MEDIA_FW_VOL_FILEPATH_DEVICE_PATH FvFileDevicePath;
+
+  ASSERT (DevicePath != NULL);
+
+  // Locate all the Firmware Volume protocols.
+  Status = gBS->LocateHandleBuffer (
+                   ByProtocol,
+                   &gEfiFirmwareVolume2ProtocolGuid,
+                   NULL,
+                   &NumberOfHandles,
+                   &HandleBuffer
+                   );
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  *DevicePath = NULL;
+
+  // Looking for FV with ACPI storage file
+  for (Index = 0; Index < NumberOfHandles; Index++) {
+    //
+    // Get the protocol on this handle
+    // This should not fail because of LocateHandleBuffer
+    //
+    Status = gBS->HandleProtocol (
+                     HandleBuffer[Index],
+                     &gEfiFirmwareVolume2ProtocolGuid,
+                     (VOID**) &FvInstance
+                     );
+    if (EFI_ERROR (Status)) {
+      goto FREE_HANDLE_BUFFER;
+    }
+
+    Status = FvInstance->ReadFile (
+                  FvInstance,
+                  EfiAppGuid,
+                  NULL,
+                  &Size,
+                  &Type,
+                  &Attributes,
+                  &AuthenticationStatus
+                  );
+    if (EFI_ERROR (Status)) {
+      //
+      // Skip if no EFI application file in the FV
+      //
+      continue;
+    } else {
+      UiSection = NULL;
+      Status = FvInstance->ReadSection (
+                    FvInstance,
+                    EfiAppGuid,
+                    EFI_SECTION_USER_INTERFACE,
+                    0,
+                    (VOID **)&UiSection,
+                    &Size,
+                    &AuthenticationStatus
+                    );
+      if (!EFI_ERROR (Status)) {
+        //
+        // Create the EFI Device Path for the application using the Filename of the application
+        //
+        *DevicePath = FileDevicePath (HandleBuffer[Index], UiSection);
+      } else {
+        Status = gBS->HandleProtocol (HandleBuffer[Index], &gEfiDevicePathProtocolGuid, (VOID**)&FvDevicePath);
+        ASSERT_EFI_ERROR (Status);
+
+        //
+        // Create the EFI Device Path for the application using the EFI GUID of the application
+        //
+        EfiInitializeFwVolDevicepathNode (&FvFileDevicePath, EfiAppGuid);
+
+        *DevicePath = AppendDevicePathNode (FvDevicePath, (EFI_DEVICE_PATH_PROTOCOL *)&FvFileDevicePath);
+        ASSERT (*DevicePath != NULL);
+      }
+      break;
+    }
+  }
+
+FREE_HANDLE_BUFFER:
+  //
+  // Free any allocated buffers
+  //
+  FreePool (HandleBuffer);
+
+  if (*DevicePath == NULL) {
+    return EFI_NOT_FOUND;
+  } else {
+    return EFI_SUCCESS;
+  }
+}
diff --git a/Platform/ARM/Library/BdsLib/BdsFilePath.c b/Platform/ARM/Library/BdsLib/BdsFilePath.c
new file mode 100644
index 000000000000..7a4a5052a786
--- /dev/null
+++ b/Platform/ARM/Library/BdsLib/BdsFilePath.c
@@ -0,0 +1,1413 @@
+/** @file
+*
+*  Copyright (c) 2011-2014, 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 <Library/NetLib.h>
+
+#include <Protocol/Bds.h>
+#include <Protocol/UsbIo.h>
+#include <Protocol/DiskIo.h>
+#include <Protocol/LoadedImage.h>
+#include <Protocol/SimpleNetwork.h>
+#include <Protocol/Dhcp4.h>
+#include <Protocol/Mtftp4.h>
+
+#define MAX_TFTP_FILE_SIZE    0x01000000
+
+/* Type and defines to set up the DHCP4 options */
+
+typedef struct {
+  EFI_DHCP4_PACKET_OPTION Head;
+  UINT8                   Route;
+} DHCP4_OPTION;
+
+#define DHCP_TAG_PARA_LIST  55
+#define DHCP_TAG_NETMASK     1
+#define DHCP_TAG_ROUTER      3
+
+/*
+   Constant strings and define related to the message indicating the amount of
+   progress in the dowloading of a TFTP file.
+*/
+
+// Frame for the progression slider
+STATIC CONST CHAR16 mTftpProgressFrame[] = L"[                                        ]";
+
+// Number of steps in the progression slider
+#define TFTP_PROGRESS_SLIDER_STEPS  ((sizeof (mTftpProgressFrame) / sizeof (CHAR16)) - 3)
+
+// Size in number of characters plus one (final zero) of the message to
+// indicate the progress of a tftp download. The format is "[(progress slider:
+// 40 characters)] (nb of KBytes downloaded so far: 7 characters) Kb". There
+// are thus the number of characters in mTftpProgressFrame[] plus 11 characters
+// (2 // spaces, "Kb" and seven characters for the number of KBytes).
+#define TFTP_PROGRESS_MESSAGE_SIZE  ((sizeof (mTftpProgressFrame) / sizeof (CHAR16)) + 12)
+
+// String to delete the tftp progress message to be able to update it :
+// (TFTP_PROGRESS_MESSAGE_SIZE-1) '\b'
+STATIC CONST CHAR16 mTftpProgressDelete[] = L"\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b";
+
+
+// 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;
+}
+
+STATIC
+EFI_STATUS
+BdsConnectAndUpdateDevicePath (
+  IN OUT 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;
+  EFI_HANDLE                  PreviousHandle;
+
+  if ((DevicePath == NULL) || (*DevicePath == NULL) || (Handle == NULL)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  PreviousHandle = NULL;
+  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)) {
+      if (*Handle == PreviousHandle) {
+        //
+        // If no forward progress is made try invoking the Dispatcher.
+        // A new FV may have been added to the system and new drivers
+        // may now be found.
+        // Status == EFI_SUCCESS means a driver was dispatched
+        // Status == EFI_NOT_FOUND means no new drivers were dispatched
+        //
+        Status = gDS->Dispatch ();
+      }
+
+      if (!EFI_ERROR (Status)) {
+        PreviousHandle = *Handle;
+
+        // Recursive = FALSE: We do not want to start the whole device tree
+        Status = gBS->ConnectController (*Handle, NULL, Remaining, FALSE);
+      }
+    }
+  } 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)) {
+      Status = BdsConnectAndUpdateDevicePath (&NewDevicePath, Handle, RemainingDevicePath);
+      *DevicePath = NewDevicePath;
+      return Status;
+    }
+  }
+
+  if (RemainingDevicePath) {
+    *RemainingDevicePath = Remaining;
+  }
+
+  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
+  )
+{
+  return BdsConnectAndUpdateDevicePath (&DevicePath, Handle, RemainingDevicePath);
+}
+
+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 OUT 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;
+  FILEPATH_DEVICE_PATH             *FilePathDevicePath;
+  EFI_SIMPLE_FILE_SYSTEM_PROTOCOL  *FsProtocol;
+  EFI_FILE_PROTOCOL                *Fs;
+  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->OpenProtocol (
+                  Handle,
+                  &gEfiSimpleFileSystemProtocolGuid,
+                  (VOID**)&FsProtocol,
+                  gImageHandle,
+                  Handle,
+                  EFI_OPEN_PROTOCOL_BY_DRIVER
+                  );
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  // Try to Open the volume and get root directory
+  Status = FsProtocol->OpenVolume (FsProtocol, &Fs);
+  if (EFI_ERROR (Status)) {
+    goto CLOSE_PROTOCOL;
+  }
+
+  Status = Fs->Open (Fs, &File, FilePathDevicePath->PathName, EFI_FILE_MODE_READ, 0);
+  if (EFI_ERROR (Status)) {
+    goto CLOSE_PROTOCOL;
+  }
+
+  Size = 0;
+  File->GetInfo (File, &gEfiFileInfoGuid, &Size, NULL);
+  FileInfo = AllocatePool (Size);
+  Status = File->GetInfo (File, &gEfiFileInfoGuid, &Size, FileInfo);
+  if (EFI_ERROR (Status)) {
+    goto CLOSE_FILE;
+  }
+
+  // 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));
+  }
+
+CLOSE_FILE:
+  File->Close (File);
+
+CLOSE_PROTOCOL:
+  gBS->CloseProtocol (
+         Handle,
+         &gEfiSimpleFileSystemProtocolGuid,
+         gImageHandle,
+         Handle);
+
+  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 OUT 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 OUT 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**)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 OUT 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;
+  EFI_PXE_BASE_CODE_PROTOCOL *Pxe;
+
+  // 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, RemainingDevicePath, 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, RemainingDevicePath, TRUE, &BufferSize, (VOID*)(UINTN)(*Image));
+    if (!EFI_ERROR (Status) && (ImageSize != NULL)) {
+      *ImageSize = BufferSize;
+    }
+  }
+
+  if (Status == EFI_ALREADY_STARTED) {
+    Status = gBS->LocateProtocol (&gEfiPxeBaseCodeProtocolGuid, NULL, (VOID **)&Pxe);
+    if (!EFI_ERROR(Status)) {
+      // If PXE is already started, we stop it
+      Pxe->Stop (Pxe);
+      // And we try again
+      return BdsPxeLoadImage (DevicePath, Handle, RemainingDevicePath, Type, Image, ImageSize);
+    }
+  }
+  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;
+  VOID             *Interface;
+
+  // 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, &gEfiDevicePathProtocolGuid,
+                  &Interface
+                  );
+  if (EFI_ERROR (Status)) {
+    return FALSE;
+  }
+
+  //
+  // Check that the controller (identified by its handle "Handle") supports the
+  // MTFTPv4 Service Binding Protocol. If it does, it means that it supports the
+  // EFI MTFTPv4 Protocol needed to download the image through TFTP.
+  //
+  Status = gBS->HandleProtocol (
+                  Handle, &gEfiMtftp4ServiceBindingProtocolGuid,
+                  &Interface
+                  );
+  if (EFI_ERROR (Status)) {
+    return FALSE;
+  }
+
+  return TRUE;
+}
+
+/**
+  Worker function that get the size in numbers of bytes of a file from a TFTP
+  server before to download the file.
+
+  @param[in]   Mtftp4    MTFTP4 protocol interface
+  @param[in]   FilePath  Path of the file, Ascii encoded
+  @param[out]  FileSize  Address where to store the file size in number of
+                         bytes.
+
+  @retval  EFI_SUCCESS   The size of the file was returned.
+  @retval  !EFI_SUCCESS  The size of the file was not returned.
+
+**/
+STATIC
+EFI_STATUS
+Mtftp4GetFileSize (
+  IN  EFI_MTFTP4_PROTOCOL  *Mtftp4,
+  IN  CHAR8                *FilePath,
+  OUT UINT64               *FileSize
+  )
+{
+  EFI_STATUS         Status;
+  EFI_MTFTP4_OPTION  ReqOpt[1];
+  EFI_MTFTP4_PACKET  *Packet;
+  UINT32             PktLen;
+  EFI_MTFTP4_OPTION  *TableOfOptions;
+  EFI_MTFTP4_OPTION  *Option;
+  UINT32             OptCnt;
+  UINT8              OptBuf[128];
+
+  ReqOpt[0].OptionStr = (UINT8*)"tsize";
+  OptBuf[0] = '0';
+  OptBuf[1] = 0;
+  ReqOpt[0].ValueStr = OptBuf;
+
+  Status = Mtftp4->GetInfo (
+             Mtftp4,
+             NULL,
+             (UINT8*)FilePath,
+             NULL,
+             1,
+             ReqOpt,
+             &PktLen,
+             &Packet
+             );
+
+  if (EFI_ERROR (Status)) {
+    goto Error;
+  }
+
+  Status = Mtftp4->ParseOptions (
+                     Mtftp4,
+                     PktLen,
+                     Packet,
+                     (UINT32 *) &OptCnt,
+                     &TableOfOptions
+                     );
+  if (EFI_ERROR (Status)) {
+    goto Error;
+  }
+
+  Option = TableOfOptions;
+  while (OptCnt != 0) {
+    if (AsciiStrnCmp ((CHAR8 *)Option->OptionStr, "tsize", 5) == 0) {
+      *FileSize = AsciiStrDecimalToUint64 ((CHAR8 *)Option->ValueStr);
+      break;
+    }
+    OptCnt--;
+    Option++;
+  }
+  FreePool (TableOfOptions);
+
+  if (OptCnt == 0) {
+    Status = EFI_UNSUPPORTED;
+  }
+
+Error :
+
+  return Status;
+}
+
+/**
+  Update the progress of a file download
+  This procedure is called each time a new TFTP packet is received.
+
+  @param[in]  This       MTFTP4 protocol interface
+  @param[in]  Token      Parameters for the download of the file
+  @param[in]  PacketLen  Length of the packet
+  @param[in]  Packet     Address of the packet
+
+  @retval  EFI_SUCCESS  All packets are accepted.
+
+**/
+STATIC
+EFI_STATUS
+Mtftp4CheckPacket (
+  IN EFI_MTFTP4_PROTOCOL  *This,
+  IN EFI_MTFTP4_TOKEN     *Token,
+  IN UINT16               PacketLen,
+  IN EFI_MTFTP4_PACKET    *Packet
+  )
+{
+  BDS_TFTP_CONTEXT  *Context;
+  CHAR16            Progress[TFTP_PROGRESS_MESSAGE_SIZE];
+  UINT64            NbOfKb;
+  UINTN             Index;
+  UINTN             LastStep;
+  UINTN             Step;
+  UINT64            LastNbOf50Kb;
+  UINT64            NbOf50Kb;
+
+  if ((NTOHS (Packet->OpCode)) == EFI_MTFTP4_OPCODE_DATA) {
+    Context = (BDS_TFTP_CONTEXT*)Token->Context;
+
+    if (Context->DownloadedNbOfBytes == 0) {
+      if (Context->FileSize > 0) {
+        Print (L"%s       0 Kb", mTftpProgressFrame);
+      } else {
+        Print (L"    0 Kb");
+      }
+    }
+
+    //
+    // The data is the packet are prepended with two UINT16 :
+    // . OpCode = EFI_MTFTP4_OPCODE_DATA
+    // . Block  = the number of this block of data
+    //
+    Context->DownloadedNbOfBytes += PacketLen - sizeof (Packet->OpCode) - sizeof (Packet->Data.Block);
+    NbOfKb = Context->DownloadedNbOfBytes / 1024;
+
+    Progress[0] = L'\0';
+    if (Context->FileSize > 0) {
+      LastStep  = (Context->LastReportedNbOfBytes * TFTP_PROGRESS_SLIDER_STEPS) / Context->FileSize;
+      Step      = (Context->DownloadedNbOfBytes   * TFTP_PROGRESS_SLIDER_STEPS) / Context->FileSize;
+      if (Step > LastStep) {
+        Print (mTftpProgressDelete);
+        CopyMem (Progress, mTftpProgressFrame, sizeof mTftpProgressFrame);
+        for (Index = 1; Index < Step; Index++) {
+          Progress[Index] = L'=';
+        }
+        Progress[Step] = L'>';
+
+        UnicodeSPrint (
+          Progress + (sizeof (mTftpProgressFrame) / sizeof (CHAR16)) - 1,
+          sizeof (Progress) - sizeof (mTftpProgressFrame),
+          L" %7d Kb",
+          NbOfKb
+          );
+        Context->LastReportedNbOfBytes = Context->DownloadedNbOfBytes;
+      }
+    } else {
+      //
+      // Case when we do not know the size of the final file.
+      // We print the updated size every 50KB of downloaded data
+      //
+      LastNbOf50Kb = Context->LastReportedNbOfBytes / (50*1024);
+      NbOf50Kb     = Context->DownloadedNbOfBytes   / (50*1024);
+      if (NbOf50Kb > LastNbOf50Kb) {
+        Print (L"\b\b\b\b\b\b\b\b\b\b");
+        UnicodeSPrint (Progress, sizeof (Progress), L"%7d Kb", NbOfKb);
+        Context->LastReportedNbOfBytes = Context->DownloadedNbOfBytes;
+      }
+    }
+    if (Progress[0] != L'\0') {
+      Print (L"%s", Progress);
+    }
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Download an image from a TFTP server
+
+  @param[in]   DevicePath           Device path of the TFTP boot option
+  @param[in]   ControllerHandle     Handle of the network controller
+  @param[in]   RemainingDevicePath  Device path of the TFTP boot option but
+                                    the first node that identifies the network controller
+  @param[in]   Type                 Type to allocate memory pages
+  @param[out]  Image                Address of the bufer where the image is stored in
+                                    case of success
+  @param[out]  ImageSize            Size in number of bytes of the i;age in case of
+                                    success
+
+  @retval  EFI_SUCCESS   The image was returned.
+  @retval  !EFI_SUCCESS  Something went wrong.
+
+**/
+EFI_STATUS
+BdsTftpLoadImage (
+  IN OUT EFI_DEVICE_PATH       **DevicePath,
+  IN     EFI_HANDLE            ControllerHandle,
+  IN     EFI_DEVICE_PATH       *RemainingDevicePath,
+  IN     EFI_ALLOCATE_TYPE     Type,
+  IN OUT EFI_PHYSICAL_ADDRESS  *Image,
+  OUT    UINTN                 *ImageSize
+  )
+{
+  EFI_STATUS               Status;
+  EFI_HANDLE               Dhcp4ChildHandle;
+  EFI_DHCP4_PROTOCOL       *Dhcp4;
+  BOOLEAN                  Dhcp4ToStop;
+  EFI_HANDLE               Mtftp4ChildHandle;
+  EFI_MTFTP4_PROTOCOL      *Mtftp4;
+  DHCP4_OPTION             ParaList;
+  EFI_DHCP4_PACKET_OPTION  *OptionList[2];
+  EFI_DHCP4_CONFIG_DATA    Dhcp4CfgData;
+  EFI_DHCP4_MODE_DATA      Dhcp4Mode;
+  EFI_MTFTP4_CONFIG_DATA   Mtftp4CfgData;
+  IPv4_DEVICE_PATH         *IPv4DevicePathNode;
+  CHAR16                   *PathName;
+  CHAR8                    *AsciiFilePath;
+  EFI_MTFTP4_TOKEN         Mtftp4Token;
+  UINT64                   FileSize;
+  UINT64                   TftpBufferSize;
+  BDS_TFTP_CONTEXT         *TftpContext;
+  UINTN                    PathNameLen;
+
+  ASSERT(IS_DEVICE_PATH_NODE (RemainingDevicePath, MESSAGING_DEVICE_PATH, MSG_IPv4_DP));
+  IPv4DevicePathNode = (IPv4_DEVICE_PATH*)RemainingDevicePath;
+
+  Dhcp4ChildHandle  = NULL;
+  Dhcp4             = NULL;
+  Dhcp4ToStop       = FALSE;
+  Mtftp4ChildHandle = NULL;
+  Mtftp4            = NULL;
+  AsciiFilePath     = NULL;
+  TftpContext       = NULL;
+
+  if (!IPv4DevicePathNode->StaticIpAddress) {
+    //
+    // Using the DHCP4 Service Binding Protocol, create a child handle of the DHCP4 service and
+    // install the DHCP4 protocol on it. Then, open the DHCP protocol.
+    //
+    Status = NetLibCreateServiceChild (
+               ControllerHandle,
+               gImageHandle,
+               &gEfiDhcp4ServiceBindingProtocolGuid,
+               &Dhcp4ChildHandle
+               );
+    if (!EFI_ERROR (Status)) {
+      Status = gBS->OpenProtocol (
+                      Dhcp4ChildHandle,
+                      &gEfiDhcp4ProtocolGuid,
+                      (VOID **) &Dhcp4,
+                      gImageHandle,
+                      ControllerHandle,
+                      EFI_OPEN_PROTOCOL_BY_DRIVER
+                      );
+    }
+    if (EFI_ERROR (Status)) {
+      Print (L"Unable to open DHCP4 protocol\n");
+      goto Error;
+    }
+  }
+
+  //
+  // Using the MTFTP4 Service Binding Protocol, create a child handle of the MTFTP4 service and
+  // install the MTFTP4 protocol on it. Then, open the MTFTP4 protocol.
+  //
+  Status = NetLibCreateServiceChild (
+             ControllerHandle,
+             gImageHandle,
+             &gEfiMtftp4ServiceBindingProtocolGuid,
+             &Mtftp4ChildHandle
+             );
+  if (!EFI_ERROR (Status)) {
+    Status = gBS->OpenProtocol (
+                    Mtftp4ChildHandle,
+                    &gEfiMtftp4ProtocolGuid,
+                    (VOID **) &Mtftp4,
+                    gImageHandle,
+                    ControllerHandle,
+                    EFI_OPEN_PROTOCOL_BY_DRIVER
+                    );
+  }
+  if (EFI_ERROR (Status)) {
+    Print (L"Unable to open MTFTP4 protocol\n");
+    goto Error;
+  }
+
+  if (!IPv4DevicePathNode->StaticIpAddress) {
+    //
+    // Configure the DHCP4, all default settings. It is acceptable for the configuration to
+    // fail if the return code is equal to EFI_ACCESS_DENIED which means that the configuration
+    // has been done by another instance of the DHCP4 protocol or that the DHCP configuration
+    // process has been started but is not completed yet.
+    //
+    ZeroMem (&Dhcp4CfgData, sizeof (EFI_DHCP4_CONFIG_DATA));
+    ParaList.Head.OpCode     = DHCP_TAG_PARA_LIST;
+    ParaList.Head.Length     = 2;
+    ParaList.Head.Data[0]    = DHCP_TAG_NETMASK;
+    ParaList.Route           = DHCP_TAG_ROUTER;
+    OptionList[0]            = &ParaList.Head;
+    Dhcp4CfgData.OptionCount = 1;
+    Dhcp4CfgData.OptionList  = OptionList;
+
+    Status = Dhcp4->Configure (Dhcp4, &Dhcp4CfgData);
+    if (EFI_ERROR (Status)) {
+      if (Status != EFI_ACCESS_DENIED) {
+        Print (L"Error while configuring the DHCP4 protocol\n");
+        goto Error;
+      }
+    }
+
+    //
+    // Start the DHCP configuration. This may have already been done thus do not leave in error
+    // if the return code is EFI_ALREADY_STARTED.
+    //
+    Status = Dhcp4->Start (Dhcp4, NULL);
+    if (EFI_ERROR (Status)) {
+      if (Status != EFI_ALREADY_STARTED) {
+        Print (L"DHCP configuration failed\n");
+        goto Error;
+      }
+    } else {
+      Dhcp4ToStop = TRUE;
+    }
+
+    Status = Dhcp4->GetModeData (Dhcp4, &Dhcp4Mode);
+    if (EFI_ERROR (Status)) {
+      goto Error;
+    }
+
+    if (Dhcp4Mode.State != Dhcp4Bound) {
+      Status = EFI_TIMEOUT;
+      Print (L"DHCP configuration failed\n");
+      goto Error;
+    }
+  }
+
+  //
+  // Configure the TFTP4 protocol
+  //
+
+  ZeroMem (&Mtftp4CfgData, sizeof (EFI_MTFTP4_CONFIG_DATA));
+  Mtftp4CfgData.UseDefaultSetting = FALSE;
+  Mtftp4CfgData.TimeoutValue      = 4;
+  Mtftp4CfgData.TryCount          = 6;
+
+  if (IPv4DevicePathNode->StaticIpAddress) {
+    CopyMem (&Mtftp4CfgData.StationIp , &IPv4DevicePathNode->LocalIpAddress, sizeof (EFI_IPv4_ADDRESS));
+    CopyMem (&Mtftp4CfgData.SubnetMask, &IPv4DevicePathNode->SubnetMask, sizeof (EFI_IPv4_ADDRESS));
+    CopyMem (&Mtftp4CfgData.GatewayIp , &IPv4DevicePathNode->GatewayIpAddress, sizeof (EFI_IPv4_ADDRESS));
+  } else {
+    CopyMem (&Mtftp4CfgData.StationIp , &Dhcp4Mode.ClientAddress, sizeof (EFI_IPv4_ADDRESS));
+    CopyMem (&Mtftp4CfgData.SubnetMask, &Dhcp4Mode.SubnetMask   , sizeof (EFI_IPv4_ADDRESS));
+    CopyMem (&Mtftp4CfgData.GatewayIp , &Dhcp4Mode.RouterAddress, sizeof (EFI_IPv4_ADDRESS));
+  }
+
+  CopyMem (&Mtftp4CfgData.ServerIp  , &IPv4DevicePathNode->RemoteIpAddress, sizeof (EFI_IPv4_ADDRESS));
+
+  Status = Mtftp4->Configure (Mtftp4, &Mtftp4CfgData);
+  if (EFI_ERROR (Status)) {
+    Print (L"Error while configuring the MTFTP4 protocol\n");
+    goto Error;
+  }
+
+  // The Device Path might contain multiple FilePath nodes
+  PathName      = ConvertDevicePathToText ((EFI_DEVICE_PATH_PROTOCOL*)(IPv4DevicePathNode + 1), FALSE, FALSE);
+  PathNameLen   = StrLen (PathName) + 1;
+  AsciiFilePath = AllocatePool (PathNameLen);
+  UnicodeStrToAsciiStrS (PathName, AsciiFilePath, PathNameLen);
+
+  //
+  // Try to get the size of the file in bytes from the server. If it fails,
+  // start with a 8MB buffer to download the file.
+  //
+  FileSize = 0;
+  if (Mtftp4GetFileSize (Mtftp4, AsciiFilePath, &FileSize) == EFI_SUCCESS) {
+    TftpBufferSize = FileSize;
+  } else {
+    TftpBufferSize = SIZE_16MB;
+  }
+
+  TftpContext = AllocatePool (sizeof (BDS_TFTP_CONTEXT));
+  if (TftpContext == NULL) {
+    Status = EFI_OUT_OF_RESOURCES;
+    goto Error;
+  }
+  TftpContext->FileSize = FileSize;
+
+  for (; TftpBufferSize <= MAX_TFTP_FILE_SIZE;
+         TftpBufferSize = (TftpBufferSize + SIZE_16MB) & (~(SIZE_16MB-1))) {
+    //
+    // Allocate a buffer to hold the whole file.
+    //
+    Status = gBS->AllocatePages (
+                    Type,
+                    EfiBootServicesCode,
+                    EFI_SIZE_TO_PAGES (TftpBufferSize),
+                    Image
+                    );
+    if (EFI_ERROR (Status)) {
+      Print (L"Failed to allocate space for image\n");
+      goto Error;
+    }
+
+    TftpContext->DownloadedNbOfBytes   = 0;
+    TftpContext->LastReportedNbOfBytes = 0;
+
+    ZeroMem (&Mtftp4Token, sizeof (EFI_MTFTP4_TOKEN));
+    Mtftp4Token.Filename    = (UINT8*)AsciiFilePath;
+    Mtftp4Token.BufferSize  = TftpBufferSize;
+    Mtftp4Token.Buffer      = (VOID *)(UINTN)*Image;
+    Mtftp4Token.CheckPacket = Mtftp4CheckPacket;
+    Mtftp4Token.Context     = (VOID*)TftpContext;
+
+    Print (L"Downloading the file <%a> from the TFTP server\n", AsciiFilePath);
+    Status = Mtftp4->ReadFile (Mtftp4, &Mtftp4Token);
+    Print (L"\n");
+    if (EFI_ERROR (Status)) {
+      gBS->FreePages (*Image, EFI_SIZE_TO_PAGES (TftpBufferSize));
+      if (Status == EFI_BUFFER_TOO_SMALL) {
+        Print (L"Downloading failed, file larger than expected.\n");
+        continue;
+      } else {
+        goto Error;
+      }
+    }
+
+    *ImageSize = Mtftp4Token.BufferSize;
+    break;
+  }
+
+Error:
+  if (Dhcp4ChildHandle != NULL) {
+    if (Dhcp4 != NULL) {
+      if (Dhcp4ToStop) {
+        Dhcp4->Stop (Dhcp4);
+      }
+      gBS->CloseProtocol (
+             Dhcp4ChildHandle,
+             &gEfiDhcp4ProtocolGuid,
+             gImageHandle,
+             ControllerHandle
+            );
+    }
+    NetLibDestroyServiceChild (
+      ControllerHandle,
+      gImageHandle,
+      &gEfiDhcp4ServiceBindingProtocolGuid,
+      Dhcp4ChildHandle
+      );
+  }
+
+  if (Mtftp4ChildHandle != NULL) {
+    if (Mtftp4 != NULL) {
+      if (AsciiFilePath != NULL) {
+        FreePool (AsciiFilePath);
+      }
+      if (TftpContext != NULL) {
+        FreePool (TftpContext);
+      }
+      gBS->CloseProtocol (
+             Mtftp4ChildHandle,
+             &gEfiMtftp4ProtocolGuid,
+             gImageHandle,
+             ControllerHandle
+            );
+    }
+    NetLibDestroyServiceChild (
+      ControllerHandle,
+      gImageHandle,
+      &gEfiMtftp4ServiceBindingProtocolGuid,
+      Mtftp4ChildHandle
+      );
+  }
+
+  if (EFI_ERROR (Status)) {
+    *Image = 0;
+    Print (L"Failed to download the file - Error=%r\n", Status);
+  }
+
+  return Status;
+}
+
+BDS_FILE_LOADER FileLoaders[] = {
+    { BdsFileSystemSupport, BdsFileSystemLoadImage },
+    { BdsFirmwareVolumeSupport, BdsFirmwareVolumeLoadImage },
+    //{ BdsLoadFileSupport, BdsLoadFileLoadImage },
+    { BdsMemoryMapSupport, BdsMemoryMapLoadImage },
+    { BdsPxeSupport, BdsPxeLoadImage },
+    { BdsTftpSupport, BdsTftpLoadImage },
+    { NULL, NULL }
+};
+
+EFI_STATUS
+BdsLoadImageAndUpdateDevicePath (
+  IN OUT 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 = BdsConnectAndUpdateDevicePath (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;
+}
+
+EFI_STATUS
+BdsLoadImage (
+  IN     EFI_DEVICE_PATH       *DevicePath,
+  IN     EFI_ALLOCATE_TYPE     Type,
+  IN OUT EFI_PHYSICAL_ADDRESS* Image,
+  OUT    UINTN                 *FileSize
+  )
+{
+  return BdsLoadImageAndUpdateDevicePath (&DevicePath, Type, Image, FileSize);
+}
+
+/**
+  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 = BdsLoadImageAndUpdateDevicePath (&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;
+}
diff --git a/Platform/ARM/Library/BdsLib/BdsHelper.c b/Platform/ARM/Library/BdsLib/BdsHelper.c
new file mode 100644
index 000000000000..b10fe2074d53
--- /dev/null
+++ b/Platform/ARM/Library/BdsLib/BdsHelper.c
@@ -0,0 +1,183 @@
+/** @file
+*
+*  Copyright (c) 2011-2015, 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"
+
+EFI_STATUS
+ShutdownUefiBootServices (
+  VOID
+  )
+{
+  EFI_STATUS              Status;
+  UINTN                   MemoryMapSize;
+  EFI_MEMORY_DESCRIPTOR   *MemoryMap;
+  UINTN                   MapKey;
+  UINTN                   DescriptorSize;
+  UINT32                  DescriptorVersion;
+  UINTN                   Pages;
+
+  MemoryMap = NULL;
+  MemoryMapSize = 0;
+  Pages = 0;
+
+  do {
+    Status = gBS->GetMemoryMap (
+                    &MemoryMapSize,
+                    MemoryMap,
+                    &MapKey,
+                    &DescriptorSize,
+                    &DescriptorVersion
+                    );
+    if (Status == EFI_BUFFER_TOO_SMALL) {
+
+      Pages = EFI_SIZE_TO_PAGES (MemoryMapSize) + 1;
+      MemoryMap = AllocatePages (Pages);
+
+      //
+      // Get System MemoryMap
+      //
+      Status = gBS->GetMemoryMap (
+                      &MemoryMapSize,
+                      MemoryMap,
+                      &MapKey,
+                      &DescriptorSize,
+                      &DescriptorVersion
+                      );
+    }
+
+    // Don't do anything between the GetMemoryMap() and ExitBootServices()
+    if (!EFI_ERROR(Status)) {
+      Status = gBS->ExitBootServices (gImageHandle, MapKey);
+      if (EFI_ERROR(Status)) {
+        FreePages (MemoryMap, Pages);
+        MemoryMap = NULL;
+        MemoryMapSize = 0;
+      }
+    }
+  } while (EFI_ERROR(Status));
+
+  return Status;
+}
+
+/**
+  Connect all DXE drivers
+
+  @retval EFI_SUCCESS           All drivers have been connected
+  @retval EFI_NOT_FOUND         No handles match the search.
+  @retval EFI_OUT_OF_RESOURCES  There is not resource pool memory to store the matching results.
+
+**/
+EFI_STATUS
+BdsConnectAllDrivers (
+  VOID
+  )
+{
+  UINTN                     HandleCount, Index;
+  EFI_HANDLE                *HandleBuffer;
+  EFI_STATUS                Status;
+
+  do {
+    // Locate all the driver handles
+    Status = gBS->LocateHandleBuffer (
+                AllHandles,
+                NULL,
+                NULL,
+                &HandleCount,
+                &HandleBuffer
+                );
+    if (EFI_ERROR (Status)) {
+      break;
+    }
+
+    // Connect every handles
+    for (Index = 0; Index < HandleCount; Index++) {
+      gBS->ConnectController (HandleBuffer[Index], NULL, NULL, TRUE);
+    }
+
+    if (HandleBuffer != NULL) {
+      FreePool (HandleBuffer);
+    }
+
+    // Check if new handles have been created after the start of the previous handles
+    Status = gDS->Dispatch ();
+  } while (!EFI_ERROR(Status));
+
+  return EFI_SUCCESS;
+}
+
+EFI_STATUS
+GetGlobalEnvironmentVariable (
+  IN     CONST CHAR16*   VariableName,
+  IN     VOID*           DefaultValue,
+  IN OUT UINTN*          Size,
+  OUT    VOID**          Value
+  )
+{
+  return GetEnvironmentVariable (VariableName, &gEfiGlobalVariableGuid,
+           DefaultValue, Size, Value);
+}
+
+EFI_STATUS
+GetEnvironmentVariable (
+  IN     CONST CHAR16*   VariableName,
+  IN     EFI_GUID*       VendorGuid,
+  IN     VOID*           DefaultValue,
+  IN OUT UINTN*          Size,
+  OUT    VOID**          Value
+  )
+{
+  EFI_STATUS  Status;
+  UINTN       VariableSize;
+
+  // Try to get the variable size.
+  *Value = NULL;
+  VariableSize = 0;
+  Status = gRT->GetVariable ((CHAR16 *) VariableName, VendorGuid, NULL, &VariableSize, *Value);
+  if (Status == EFI_NOT_FOUND) {
+    if ((DefaultValue != NULL) && (Size != NULL) && (*Size != 0)) {
+      // If the environment variable does not exist yet then set it with the default value
+      Status = gRT->SetVariable (
+                    (CHAR16*)VariableName,
+                    VendorGuid,
+                    EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
+                    *Size,
+                    DefaultValue
+                    );
+      *Value = AllocateCopyPool (*Size, DefaultValue);
+    } else {
+      return EFI_NOT_FOUND;
+    }
+  } else if (Status == EFI_BUFFER_TOO_SMALL) {
+    // Get the environment variable value
+    *Value = AllocatePool (VariableSize);
+    if (*Value == NULL) {
+      return EFI_OUT_OF_RESOURCES;
+    }
+
+    Status = gRT->GetVariable ((CHAR16 *)VariableName, VendorGuid, NULL, &VariableSize, *Value);
+    if (EFI_ERROR (Status)) {
+      FreePool(*Value);
+      return EFI_INVALID_PARAMETER;
+    }
+
+    if (Size) {
+      *Size = VariableSize;
+    }
+  } else {
+    *Value = AllocateCopyPool (*Size, DefaultValue);
+    return Status;
+  }
+
+  return EFI_SUCCESS;
+}
diff --git a/Platform/ARM/Library/BdsLib/BdsInternal.h b/Platform/ARM/Library/BdsLib/BdsInternal.h
new file mode 100644
index 000000000000..f70aae603d69
--- /dev/null
+++ b/Platform/ARM/Library/BdsLib/BdsInternal.h
@@ -0,0 +1,111 @@
+/** @file
+*
+*  Copyright (c) 2011-2015, 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.
+*
+**/
+
+#ifndef __BDS_INTERNAL_H__
+#define __BDS_INTERNAL_H__
+
+#include <PiDxe.h>
+#include <Library/ArmLib.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DxeServicesTableLib.h>
+#include <Library/HobLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/DebugLib.h>
+#include <Library/BdsLib.h>
+#include <Library/PcdLib.h>
+#include <Library/PrintLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+
+#include <Guid/GlobalVariable.h>
+#include <Guid/FileInfo.h>
+
+#include <Protocol/DevicePath.h>
+#include <Protocol/DevicePathFromText.h>
+#include <Protocol/SimpleFileSystem.h>
+#include <Protocol/FirmwareVolume2.h>
+#include <Protocol/LoadFile.h>
+#include <Protocol/PxeBaseCode.h>
+
+#include <Uefi.h>
+
+/**
+ * Check if the file loader can support this device path.
+ *
+ * @param DevicePath    EFI Device Path of the image to load.
+ *                      This device path generally comes from the boot entry (ie: Boot####).
+ * @param Handle        Handle of the driver supporting the device path
+ * @param RemainingDevicePath   Part of the EFI Device Path that has not been resolved during
+ *                      the Device Path discovery
+ */
+typedef BOOLEAN (*BDS_FILE_LOADER_SUPPORT) (
+  IN EFI_DEVICE_PATH            *DevicePath,
+  IN EFI_HANDLE                 Handle,
+  IN EFI_DEVICE_PATH            *RemainingDevicePath
+  );
+
+/**
+ * Function to load an image from a given Device Path for a
+ * specific support (FileSystem, TFTP, PXE, ...)
+ *
+ * @param DevicePath    EFI Device Path of the image to load.
+ *                      This device path generally comes from the boot entry (ie: Boot####).
+ *                      This path is also defined as 'OUT' as there are some device paths that
+ *                      might not be completed such as EFI path for removable device. In these
+ *                      cases, it is expected the loader to add \EFI\BOOT\BOOT(ARM|AA64).EFI
+ * @param Handle        Handle of the driver supporting the device path
+ * @param RemainingDevicePath   Part of the EFI Device Path that has not been resolved during
+ *                      the Device Path discovery
+ * @param Type          Define where the image should be loaded (see EFI_ALLOCATE_TYPE definition)
+ * @param Image         Base Address of the image has been loaded
+ * @param ImageSize     Size of the image that has been loaded
+ */
+typedef EFI_STATUS (*BDS_FILE_LOADER_LOAD_IMAGE) (
+  IN OUT 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
+  );
+
+typedef struct {
+  BDS_FILE_LOADER_SUPPORT     Support;
+  BDS_FILE_LOADER_LOAD_IMAGE  LoadImage;
+} BDS_FILE_LOADER;
+
+typedef struct _BDS_SYSTEM_MEMORY_RESOURCE {
+  LIST_ENTRY                  Link; // This attribute must be the first entry of this structure (to avoid pointer computation)
+  EFI_PHYSICAL_ADDRESS        PhysicalStart;
+  UINT64                      ResourceLength;
+} BDS_SYSTEM_MEMORY_RESOURCE;
+
+typedef struct {
+  UINT64  FileSize;
+  UINT64  DownloadedNbOfBytes;
+  UINT64  LastReportedNbOfBytes;
+} BDS_TFTP_CONTEXT;
+
+EFI_STATUS
+BdsLoadImage (
+  IN     EFI_DEVICE_PATH       *DevicePath,
+  IN     EFI_ALLOCATE_TYPE     Type,
+  IN OUT EFI_PHYSICAL_ADDRESS* Image,
+  OUT    UINTN                 *FileSize
+  );
+
+#endif
diff --git a/Platform/ARM/Library/BdsLib/BdsLib.inf b/Platform/ARM/Library/BdsLib/BdsLib.inf
new file mode 100644
index 000000000000..96c1d6e7e200
--- /dev/null
+++ b/Platform/ARM/Library/BdsLib/BdsLib.inf
@@ -0,0 +1,62 @@
+#/* @file
+#
+#  Copyright (c) 2011-2014, 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.
+#
+#*/
+
+[Defines]
+  INF_VERSION                    = 0x00010005
+  BASE_NAME                      = BdsLib
+  FILE_GUID                      = ddbf73a0-bb25-11df-8e4e-0002a5d5c51b
+  MODULE_TYPE                    = DXE_DRIVER
+  VERSION_STRING                 = 1.0
+  LIBRARY_CLASS                  = BdsLib
+
+[Sources.common]
+  BdsFilePath.c
+  BdsAppLoader.c
+  BdsHelper.c
+  BdsLoadOption.c
+
+[Packages]
+  ArmPkg/ArmPkg.dec
+  EmbeddedPkg/EmbeddedPkg.dec
+  MdeModulePkg/MdeModulePkg.dec
+  MdePkg/MdePkg.dec
+
+[LibraryClasses]
+  ArmLib
+  BaseLib
+  DebugLib
+  DevicePathLib
+  HobLib
+  PcdLib
+  NetLib
+
+[Guids]
+  gEfiFileInfoGuid
+
+[Protocols]
+  gEfiBdsArchProtocolGuid
+  gEfiDevicePathProtocolGuid
+  gEfiDevicePathFromTextProtocolGuid
+  gEfiSimpleFileSystemProtocolGuid
+  gEfiFirmwareVolume2ProtocolGuid
+  gEfiLoadFileProtocolGuid
+  gEfiPxeBaseCodeProtocolGuid
+  gEfiDiskIoProtocolGuid
+  gEfiUsbIoProtocolGuid
+  gEfiLoadedImageProtocolGuid
+  gEfiSimpleNetworkProtocolGuid
+  gEfiDhcp4ServiceBindingProtocolGuid
+  gEfiDhcp4ProtocolGuid
+  gEfiMtftp4ServiceBindingProtocolGuid
+  gEfiMtftp4ProtocolGuid
diff --git a/Platform/ARM/Library/BdsLib/BdsLoadOption.c b/Platform/ARM/Library/BdsLib/BdsLoadOption.c
new file mode 100644
index 000000000000..766a9890fc09
--- /dev/null
+++ b/Platform/ARM/Library/BdsLib/BdsLoadOption.c
@@ -0,0 +1,272 @@
+/** @file
+*
+*  Copyright (c) 2011-2013, 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"
+
+EFI_STATUS
+BootOptionParseLoadOption (
+  IN     EFI_LOAD_OPTION *EfiLoadOption,
+  IN     UINTN           EfiLoadOptionSize,
+  IN OUT BDS_LOAD_OPTION **BdsLoadOption
+  )
+{
+  BDS_LOAD_OPTION *LoadOption;
+  UINTN           DescriptionLength;
+  UINTN           EfiLoadOptionPtr;
+
+  if (EfiLoadOption == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if (EfiLoadOptionSize < sizeof(UINT32) + sizeof(UINT16) + sizeof(CHAR16) + sizeof(EFI_DEVICE_PATH_PROTOCOL)) {
+    return EFI_BAD_BUFFER_SIZE;
+  }
+
+  if (*BdsLoadOption == NULL) {
+    LoadOption = (BDS_LOAD_OPTION*)AllocateZeroPool (sizeof(BDS_LOAD_OPTION));
+    if (LoadOption == NULL) {
+      return EFI_OUT_OF_RESOURCES;
+    }
+  } else {
+    LoadOption = *BdsLoadOption;
+  }
+
+  EfiLoadOptionPtr           = (UINTN)EfiLoadOption;
+  LoadOption->LoadOption     = EfiLoadOption;
+  LoadOption->LoadOptionSize = EfiLoadOptionSize;
+
+  LoadOption->Attributes         = *(UINT32*)EfiLoadOptionPtr;
+  LoadOption->FilePathListLength = *(UINT16*)(EfiLoadOptionPtr + sizeof(UINT32));
+  LoadOption->Description        = (CHAR16*)(EfiLoadOptionPtr + sizeof(UINT32) + sizeof(UINT16));
+  DescriptionLength              = StrSize (LoadOption->Description);
+  LoadOption->FilePathList       = (EFI_DEVICE_PATH_PROTOCOL*)(EfiLoadOptionPtr + sizeof(UINT32) + sizeof(UINT16) + DescriptionLength);
+
+  // If ((End of EfiLoadOptiony - Start of EfiLoadOption) == EfiLoadOptionSize) then No Optional Data
+  if ((UINTN)((UINTN)LoadOption->FilePathList + LoadOption->FilePathListLength - EfiLoadOptionPtr) == EfiLoadOptionSize) {
+    LoadOption->OptionalData     = NULL;
+    LoadOption->OptionalDataSize = 0;
+  } else {
+    LoadOption->OptionalData     = (VOID*)((UINTN)(LoadOption->FilePathList) + LoadOption->FilePathListLength);
+    LoadOption->OptionalDataSize = EfiLoadOptionSize - ((UINTN)LoadOption->OptionalData - EfiLoadOptionPtr);
+  }
+
+  if (*BdsLoadOption == NULL) {
+    *BdsLoadOption = LoadOption;
+  }
+
+  return EFI_SUCCESS;
+}
+
+EFI_STATUS
+BootOptionFromLoadOptionVariable (
+  IN  CHAR16*           BootVariableName,
+  OUT BDS_LOAD_OPTION** BdsLoadOption
+  )
+{
+  EFI_STATUS            Status;
+  EFI_LOAD_OPTION       *EfiLoadOption;
+  UINTN                 EfiLoadOptionSize;
+
+  Status = GetGlobalEnvironmentVariable (BootVariableName, NULL, &EfiLoadOptionSize, (VOID**)&EfiLoadOption);
+  if (!EFI_ERROR(Status)) {
+    *BdsLoadOption = NULL;
+    Status = BootOptionParseLoadOption (EfiLoadOption, EfiLoadOptionSize, BdsLoadOption);
+  }
+
+  return Status;
+}
+
+EFI_STATUS
+BootOptionFromLoadOptionIndex (
+  IN  UINT16            LoadOptionIndex,
+  OUT BDS_LOAD_OPTION **BdsLoadOption
+  )
+{
+  CHAR16        BootVariableName[9];
+  EFI_STATUS    Status;
+
+  UnicodeSPrint (BootVariableName, 9 * sizeof(CHAR16), L"Boot%04X", LoadOptionIndex);
+
+  Status = BootOptionFromLoadOptionVariable (BootVariableName, BdsLoadOption);
+  if (!EFI_ERROR(Status)) {
+    (*BdsLoadOption)->LoadOptionIndex = LoadOptionIndex;
+  }
+
+  return Status;
+}
+
+EFI_STATUS
+BootOptionToLoadOptionVariable (
+  IN BDS_LOAD_OPTION*   BdsLoadOption
+  )
+{
+  EFI_STATUS                    Status;
+  UINTN                         DescriptionSize;
+  //UINT16                        FilePathListLength;
+  EFI_DEVICE_PATH_PROTOCOL*     DevicePathNode;
+  UINTN                         NodeLength;
+  UINT8*                        EfiLoadOptionPtr;
+  VOID*                         OldLoadOption;
+  CHAR16                        BootVariableName[9];
+  UINTN                         BootOrderSize;
+  UINT16*                       BootOrder;
+
+  // If we are overwriting an existent Boot Option then we have to free previously allocated memory
+  if (BdsLoadOption->LoadOptionSize > 0) {
+    OldLoadOption = BdsLoadOption->LoadOption;
+  } else {
+    OldLoadOption = NULL;
+
+    // If this function is called at the creation of the Boot Device entry (not at the update) the
+    // BootOption->LoadOptionSize must be zero then we get a new BootIndex for this entry
+    BdsLoadOption->LoadOptionIndex = BootOptionAllocateBootIndex ();
+
+    //TODO: Add to the the Boot Entry List
+  }
+
+  DescriptionSize = StrSize(BdsLoadOption->Description);
+
+  // Ensure the FilePathListLength information is correct
+  ASSERT (GetDevicePathSize (BdsLoadOption->FilePathList) == BdsLoadOption->FilePathListLength);
+
+  // Allocate the memory for the EFI Load Option
+  BdsLoadOption->LoadOptionSize = sizeof(UINT32) + sizeof(UINT16) + DescriptionSize + BdsLoadOption->FilePathListLength + BdsLoadOption->OptionalDataSize;
+
+  BdsLoadOption->LoadOption = (EFI_LOAD_OPTION *)AllocateZeroPool (BdsLoadOption->LoadOptionSize);
+  if (BdsLoadOption->LoadOption == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  EfiLoadOptionPtr = (UINT8 *) BdsLoadOption->LoadOption;
+
+  //
+  // Populate the EFI Load Option and BDS Boot Option structures
+  //
+
+  // Attributes fields
+  *(UINT32*)EfiLoadOptionPtr = BdsLoadOption->Attributes;
+  EfiLoadOptionPtr += sizeof(UINT32);
+
+  // FilePath List fields
+  *(UINT16*)EfiLoadOptionPtr = BdsLoadOption->FilePathListLength;
+  EfiLoadOptionPtr += sizeof(UINT16);
+
+  // Boot description fields
+  CopyMem (EfiLoadOptionPtr, BdsLoadOption->Description, DescriptionSize);
+  EfiLoadOptionPtr += DescriptionSize;
+
+  // File path fields
+  DevicePathNode = BdsLoadOption->FilePathList;
+  while (!IsDevicePathEndType (DevicePathNode)) {
+    NodeLength = DevicePathNodeLength(DevicePathNode);
+    CopyMem (EfiLoadOptionPtr, DevicePathNode, NodeLength);
+    EfiLoadOptionPtr += NodeLength;
+    DevicePathNode = NextDevicePathNode (DevicePathNode);
+  }
+
+  // Set the End Device Path Type
+  SetDevicePathEndNode (EfiLoadOptionPtr);
+  EfiLoadOptionPtr += sizeof(EFI_DEVICE_PATH);
+
+  // Fill the Optional Data
+  if (BdsLoadOption->OptionalDataSize > 0) {
+    CopyMem (EfiLoadOptionPtr, BdsLoadOption->OptionalData, BdsLoadOption->OptionalDataSize);
+  }
+
+  // Case where the fields have been updated
+  if (OldLoadOption) {
+    // Now, the old data has been copied to the new allocated packed structure, we need to update the pointers of BdsLoadOption
+    BootOptionParseLoadOption (BdsLoadOption->LoadOption, BdsLoadOption->LoadOptionSize, &BdsLoadOption);
+    // Free the old packed structure
+    FreePool (OldLoadOption);
+  }
+
+  // Create/Update Boot#### environment variable
+  UnicodeSPrint (BootVariableName, 9 * sizeof(CHAR16), L"Boot%04X", BdsLoadOption->LoadOptionIndex);
+  Status = gRT->SetVariable (
+      BootVariableName,
+      &gEfiGlobalVariableGuid,
+      EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
+      BdsLoadOption->LoadOptionSize,
+      BdsLoadOption->LoadOption
+      );
+
+  // When it is a new entry we must add the entry to the BootOrder
+  if (OldLoadOption == NULL) {
+    // Add the new Boot Index to the list
+    Status = GetGlobalEnvironmentVariable (L"BootOrder", NULL, &BootOrderSize, (VOID**)&BootOrder);
+    if (!EFI_ERROR(Status)) {
+      BootOrder = ReallocatePool (BootOrderSize, BootOrderSize + sizeof(UINT16), BootOrder);
+      // Add the new index at the end
+      BootOrder[BootOrderSize / sizeof(UINT16)] = BdsLoadOption->LoadOptionIndex;
+      BootOrderSize += sizeof(UINT16);
+    } else {
+      // BootOrder does not exist. Create it
+      BootOrderSize = sizeof(UINT16);
+      BootOrder = &(BdsLoadOption->LoadOptionIndex);
+    }
+
+    // Update (or Create) the BootOrder environment variable
+    gRT->SetVariable (
+        L"BootOrder",
+        &gEfiGlobalVariableGuid,
+        EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
+        BootOrderSize,
+        BootOrder
+        );
+    DEBUG((EFI_D_ERROR,"Create %s\n",BootVariableName));
+
+    // Free memory allocated by GetGlobalEnvironmentVariable
+    if (!EFI_ERROR(Status)) {
+      FreePool (BootOrder);
+    }
+  } else {
+    DEBUG((EFI_D_ERROR,"Update %s\n",BootVariableName));
+  }
+
+  return EFI_SUCCESS;
+}
+
+UINT16
+BootOptionAllocateBootIndex (
+  VOID
+  )
+{
+  EFI_STATUS        Status;
+  UINTN             Index;
+  UINT32            BootIndex;
+  UINT16            *BootOrder;
+  UINTN             BootOrderSize;
+  BOOLEAN           Found;
+
+  // Get the Boot Option Order from the environment variable
+  Status = GetGlobalEnvironmentVariable (L"BootOrder", NULL, &BootOrderSize, (VOID**)&BootOrder);
+  if (!EFI_ERROR(Status)) {
+    for (BootIndex = 0; BootIndex <= 0xFFFF; BootIndex++) {
+      Found = FALSE;
+      for (Index = 0; Index < BootOrderSize / sizeof (UINT16); Index++) {
+        if (BootOrder[Index] == BootIndex) {
+          Found = TRUE;
+          break;
+        }
+      }
+      if (!Found) {
+        return BootIndex;
+      }
+    }
+    FreePool (BootOrder);
+  }
+  // Return the first index
+  return 0;
+}
-- 
2.11.0



^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH edk2-platforms 2/4] Platform/ARM: import FdtPlatformDxe driver from EDK2
  2017-11-20 11:37 [PATCH edk2-platforms 0/4] Platform/ARM: import BdsLib and FdtPlatformDxe Ard Biesheuvel
  2017-11-20 11:37 ` [PATCH edk2-platforms 1/4] Platform/ARM: import BdsLib from ArmPkg Ard Biesheuvel
@ 2017-11-20 11:37 ` Ard Biesheuvel
  2017-11-20 11:37 ` [PATCH edk2-platforms 3/4] Platform/ARM/Juno: move to migrated FdtPlatformDxe Ard Biesheuvel
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 7+ messages in thread
From: Ard Biesheuvel @ 2017-11-20 11:37 UTC (permalink / raw)
  To: edk2-devel; +Cc: leif.lindholm, Ard Biesheuvel

Import FdtPlatformDxe from EmbeddedPkg into Platform/ARM, given that it
is not used anywhere else, nor should it be.

Contributed-under: TianoCore Contribution Agreement 1.1
Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
---
 Platform/ARM/Drivers/FdtPlatformDxe/FdtPlatform.c      | 461 +++++++++++++++++++
 Platform/ARM/Drivers/FdtPlatformDxe/FdtPlatform.h      | 174 ++++++++
 Platform/ARM/Drivers/FdtPlatformDxe/FdtPlatformDxe.dec |  31 ++
 Platform/ARM/Drivers/FdtPlatformDxe/FdtPlatformDxe.inf |  65 +++
 Platform/ARM/Drivers/FdtPlatformDxe/FdtPlatformDxe.uni | 109 +++++
 Platform/ARM/Drivers/FdtPlatformDxe/README.txt         |  72 +++
 Platform/ARM/Drivers/FdtPlatformDxe/ShellDumpFdt.c     | 279 ++++++++++++
 Platform/ARM/Drivers/FdtPlatformDxe/ShellSetFdt.c      | 468 ++++++++++++++++++++
 8 files changed, 1659 insertions(+)

diff --git a/Platform/ARM/Drivers/FdtPlatformDxe/FdtPlatform.c b/Platform/ARM/Drivers/FdtPlatformDxe/FdtPlatform.c
new file mode 100644
index 000000000000..b4be2a078991
--- /dev/null
+++ b/Platform/ARM/Drivers/FdtPlatformDxe/FdtPlatform.c
@@ -0,0 +1,461 @@
+/** @file
+
+  Copyright (c) 2015, ARM Ltd. All rights reserved.<BR>
+
+  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 "FdtPlatform.h"
+
+#include <Library/PcdLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/BdsLib.h>
+
+#include <Protocol/DevicePath.h>
+
+//
+// Internal variables
+//
+
+STATIC CONST EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL mShellDynCmdProtocolSetFdt = {
+    L"setfdt",                // Name of the command
+    ShellDynCmdSetFdtHandler, // Handler
+    ShellDynCmdSetFdtGetHelp  // GetHelp
+};
+
+STATIC CONST EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL mShellDynCmdProtocolDumpFdt = {
+    L"dumpfdt",                // Name of the command
+    ShellDynCmdDumpFdtHandler, // Handler
+    ShellDynCmdDumpFdtGetHelp  // GetHelp
+};
+
+STATIC CONST EFI_GUID  mFdtPlatformDxeHiiGuid = {
+                         0x8afa7610, 0x62b1, 0x46aa,
+                         {0xb5, 0x34, 0xc3, 0xde, 0xff, 0x39, 0x77, 0x8c}
+                         };
+
+EFI_HANDLE mFdtPlatformDxeHiiHandle;
+
+/**
+  Install the FDT specified by its device path in text form.
+
+  @param[in]  TextDevicePath  Device path of the FDT to install in text form
+
+  @retval  EFI_SUCCESS            The FDT was installed.
+  @retval  EFI_NOT_FOUND          Failed to locate a protocol or a file.
+  @retval  EFI_INVALID_PARAMETER  Invalid device path.
+  @retval  EFI_UNSUPPORTED        Device path not supported.
+  @retval  EFI_OUT_OF_RESOURCES   An allocation failed.
+**/
+STATIC
+EFI_STATUS
+InstallFdt (
+  IN CONST CHAR16*  TextDevicePath
+  )
+{
+  EFI_STATUS                          Status;
+  EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL  *EfiDevicePathFromTextProtocol;
+  EFI_DEVICE_PATH                     *DevicePath;
+  EFI_PHYSICAL_ADDRESS                FdtBlobBase;
+  UINTN                               FdtBlobSize;
+  UINTN                               NumPages;
+  EFI_PHYSICAL_ADDRESS                FdtConfigurationTableBase;
+
+  Status = gBS->LocateProtocol (
+                  &gEfiDevicePathFromTextProtocolGuid,
+                  NULL,
+                  (VOID **)&EfiDevicePathFromTextProtocol
+                  );
+  if (EFI_ERROR (Status)) {
+    DEBUG ((EFI_D_ERROR, "InstallFdt() - Failed to locate EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL protocol\n"));
+    return Status;
+  }
+
+  DevicePath = (EFI_DEVICE_PATH*)EfiDevicePathFromTextProtocol->ConvertTextToDevicePath (TextDevicePath);
+  if (DevicePath == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  //
+  // Load the FDT given its device path.
+  // This operation may fail if the device path is not supported.
+  //
+  FdtBlobBase = 0;
+  NumPages    = 0;
+  Status = BdsLoadImage (DevicePath, AllocateAnyPages, &FdtBlobBase, &FdtBlobSize);
+  if (EFI_ERROR (Status)) {
+    goto Error;
+  }
+
+  //
+  // Ensure that the FDT header is valid and that the Size of the Device Tree
+  // is smaller than the size of the read file
+  //
+  if (fdt_check_header ((VOID*)(UINTN)FdtBlobBase) != 0 ||
+      (UINTN)fdt_totalsize ((VOID*)(UINTN)FdtBlobBase) > FdtBlobSize) {
+    DEBUG ((EFI_D_ERROR, "InstallFdt() - loaded FDT binary image seems corrupt\n"));
+    Status = EFI_LOAD_ERROR;
+    goto Error;
+  }
+
+  //
+  // Store the FDT as Runtime Service Data to prevent the Kernel from
+  // overwritting its data.
+  //
+  NumPages = EFI_SIZE_TO_PAGES (FdtBlobSize);
+  Status = gBS->AllocatePages (
+                  AllocateAnyPages, EfiRuntimeServicesData,
+                  NumPages, &FdtConfigurationTableBase
+                  );
+  if (EFI_ERROR (Status)) {
+    goto Error;
+  }
+  CopyMem (
+    (VOID*)(UINTN)FdtConfigurationTableBase,
+    (VOID*)(UINTN)FdtBlobBase,
+    FdtBlobSize
+    );
+
+  //
+  // Install the FDT into the Configuration Table
+  //
+  Status = gBS->InstallConfigurationTable (
+                  &gFdtTableGuid,
+                  (VOID*)(UINTN)FdtConfigurationTableBase
+                  );
+  if (EFI_ERROR (Status)) {
+    gBS->FreePages (FdtConfigurationTableBase, NumPages);
+  }
+
+Error:
+  if (FdtBlobBase != 0) {
+    gBS->FreePages (FdtBlobBase, NumPages);
+  }
+  FreePool (DevicePath);
+
+  return Status;
+}
+
+/**
+  Main entry point of the FDT platform driver.
+
+  @param[in]  ImageHandle   The firmware allocated handle for the present driver
+                            UEFI image.
+  @param[in]  *SystemTable  A pointer to the EFI System table.
+
+  @retval  EFI_SUCCESS           The driver was initialized.
+  @retval  EFI_OUT_OF_RESOURCES  The "End of DXE" event could not be allocated or
+                                 there was not enough memory in pool to install
+                                 the Shell Dynamic Command protocol.
+  @retval  EFI_LOAD_ERROR        Unable to add the HII package.
+
+**/
+EFI_STATUS
+FdtPlatformEntryPoint (
+  IN EFI_HANDLE        ImageHandle,
+  IN EFI_SYSTEM_TABLE  *SystemTable
+  )
+{
+  EFI_STATUS  Status;
+  EFI_HANDLE  Handle;
+
+  //
+  // Install the Device Tree from its expected location
+  //
+  Status = RunFdtInstallation (NULL);
+
+  if (FeaturePcdGet (PcdOverridePlatformFdt) || FeaturePcdGet (PcdDumpFdtShellCommand)) {
+    //
+    // Register the strings for the user interface in the HII Database.
+    // This shows the way to the multi-language support, even if
+    // only the English language is actually supported. The strings to register
+    // are stored in the "ShellSetFdtStrings[]" array. This array is
+    // built by the building process from the "*.uni" file associated to
+    // the present driver (cf. FdtPlatfromDxe.inf). Examine your Build
+    // folder under your package's DEBUG folder and you will find the array
+    // defined in a xxxStrDefs.h file.
+    //
+    mFdtPlatformDxeHiiHandle = HiiAddPackages (
+                                 &mFdtPlatformDxeHiiGuid,
+                                 ImageHandle,
+                                 FdtPlatformDxeStrings,
+                                 NULL
+                                 );
+  }
+
+  //
+  // If the development features are enabled, install the dynamic shell
+  // command "setfdt" to be able to define a device path for the FDT
+  // that has precedence over the device paths defined by
+  // "PcdFdtDevicePaths".
+  //
+
+  if (FeaturePcdGet (PcdOverridePlatformFdt)) {
+    if (mFdtPlatformDxeHiiHandle != NULL) {
+      // We install dynamic EFI command on separate handles as we cannot register
+      // more than one protocol of the same protocol interface on the same handle.
+      Handle = NULL;
+      Status = gBS->InstallMultipleProtocolInterfaces (
+                      &Handle,
+                      &gEfiShellDynamicCommandProtocolGuid,
+                      &mShellDynCmdProtocolSetFdt,
+                      NULL
+                      );
+      if (EFI_ERROR (Status)) {
+        HiiRemovePackages (mFdtPlatformDxeHiiHandle);
+      }
+    } else {
+      Status = EFI_LOAD_ERROR;
+    }
+    if (EFI_ERROR (Status)) {
+      DEBUG ((
+        EFI_D_WARN,
+        "Unable to install \"setfdt\" EFI Shell command - %r \n",
+        Status
+        ));
+    }
+  }
+
+  if (FeaturePcdGet (PcdDumpFdtShellCommand)) {
+    if (mFdtPlatformDxeHiiHandle != NULL) {
+      // We install dynamic EFI command on separate handles as we cannot register
+      // more than one protocol of the same protocol interface on the same handle.
+      Handle = NULL;
+      Status = gBS->InstallMultipleProtocolInterfaces (
+                      &Handle,
+                      &gEfiShellDynamicCommandProtocolGuid,
+                      &mShellDynCmdProtocolDumpFdt,
+                      NULL
+                      );
+      if (EFI_ERROR (Status)) {
+        HiiRemovePackages (mFdtPlatformDxeHiiHandle);
+      }
+    } else {
+      Status = EFI_LOAD_ERROR;
+    }
+    if (EFI_ERROR (Status)) {
+      DEBUG ((
+        EFI_D_WARN,
+        "Unable to install \"dumpfdt\" EFI Shell command - %r \n",
+        Status
+        ));
+    }
+  }
+
+  return Status;
+}
+
+/**
+  Run the FDT installation process.
+
+  Loop in priority order over the device paths from which the FDT has
+  been asked to be retrieved for. For each device path, try to install
+  the FDT. Stop as soon as an installation succeeds.
+
+  @param[in]  SuccessfullDevicePath  If not NULL, address where to store the
+                                     pointer to the text device path from
+                                     which the FDT was successfully retrieved.
+                                     Not used if the FDT installation failed.
+                                     The returned address is the address of
+                                     an allocated buffer that has to be
+                                     freed by the caller.
+
+  @retval  EFI_SUCCESS            The FDT was installed.
+  @retval  EFI_NOT_FOUND          Failed to locate a protocol or a file.
+  @retval  EFI_INVALID_PARAMETER  Invalid device path.
+  @retval  EFI_UNSUPPORTED        Device path not supported.
+  @retval  EFI_OUT_OF_RESOURCES   An allocation failed.
+
+**/
+EFI_STATUS
+RunFdtInstallation (
+  OUT CHAR16  **SuccessfullDevicePath
+  )
+{
+  EFI_STATUS  Status;
+  UINTN       DataSize;
+  CHAR16      *TextDevicePath;
+  CHAR16      *TextDevicePathStart;
+  CHAR16      *TextDevicePathSeparator;
+  UINTN       TextDevicePathLen;
+
+  TextDevicePath = NULL;
+  //
+  // For development purpose, if enabled through the "PcdOverridePlatformFdt"
+  // feature PCD, try first to install the FDT specified by the device path in
+  // text form stored in the "Fdt" UEFI variable.
+  //
+  if (FeaturePcdGet (PcdOverridePlatformFdt)) {
+    DataSize = 0;
+    Status = gRT->GetVariable (
+                    L"Fdt",
+                    &gFdtVariableGuid,
+                    NULL,
+                    &DataSize,
+                    NULL
+                    );
+
+    //
+    // Keep going only if the "Fdt" variable is defined.
+    //
+
+    if (Status == EFI_BUFFER_TOO_SMALL) {
+      TextDevicePath = AllocatePool (DataSize);
+      if (TextDevicePath == NULL) {
+        Status = EFI_OUT_OF_RESOURCES;
+        goto Error;
+      }
+
+      Status = gRT->GetVariable (
+                      L"Fdt",
+                      &gFdtVariableGuid,
+                      NULL,
+                      &DataSize,
+                      TextDevicePath
+                      );
+      if (EFI_ERROR (Status)) {
+        FreePool (TextDevicePath);
+        goto Error;
+      }
+
+      Status = InstallFdt (TextDevicePath);
+      if (!EFI_ERROR (Status)) {
+        DEBUG ((
+          EFI_D_WARN,
+          "Installation of the FDT using the device path <%s> completed.\n",
+          TextDevicePath
+          ));
+        goto Done;
+      }
+      DEBUG ((
+        EFI_D_ERROR,
+        "Installation of the FDT specified by the \"Fdt\" UEFI variable failed - %r\n",
+        Status
+        ));
+      FreePool (TextDevicePath);
+    }
+  }
+
+  //
+  // Loop over the device path list provided by "PcdFdtDevicePaths". The device
+  // paths are in text form and separated by a semi-colon.
+  //
+
+  Status = EFI_NOT_FOUND;
+  for (TextDevicePathStart = (CHAR16*)PcdGetPtr (PcdFdtDevicePaths);
+       *TextDevicePathStart != L'\0'                               ; ) {
+    TextDevicePathSeparator = StrStr (TextDevicePathStart, L";");
+
+    //
+    // Last device path of the list
+    //
+    if (TextDevicePathSeparator == NULL) {
+      TextDevicePathLen = StrLen (TextDevicePathStart);
+    } else {
+      TextDevicePathLen = (UINTN)(TextDevicePathSeparator - TextDevicePathStart);
+    }
+
+    TextDevicePath = AllocateCopyPool (
+                       (TextDevicePathLen + 1) * sizeof (CHAR16),
+                       TextDevicePathStart
+                       );
+    if (TextDevicePath == NULL) {
+      Status = EFI_OUT_OF_RESOURCES;
+      goto Error;
+    }
+    TextDevicePath[TextDevicePathLen] = L'\0';
+
+    Status = InstallFdt (TextDevicePath);
+    if (!EFI_ERROR (Status)) {
+      DEBUG ((EFI_D_WARN, "Installation of the FDT using the device path <%s> completed.\n",
+        TextDevicePath
+        ));
+      goto Done;
+    }
+
+    DEBUG ((EFI_D_WARN, "Installation of the FDT using the device path <%s> failed - %r.\n",
+      TextDevicePath, Status
+      ));
+    FreePool (TextDevicePath);
+
+    if (TextDevicePathSeparator == NULL) {
+      goto Error;
+    }
+    TextDevicePathStart = TextDevicePathSeparator + 1;
+  }
+
+Error:
+Done:
+
+  if (EFI_ERROR (Status)) {
+    DEBUG ((EFI_D_ERROR, "Failed to install the FDT - %r.\n", Status));
+    return Status;
+  }
+
+  if (SuccessfullDevicePath != NULL) {
+    *SuccessfullDevicePath = TextDevicePath;
+  } else {
+    FreePool (TextDevicePath);
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Transcode one of the EFI return code used by the model into an EFI Shell return code.
+
+  @param[in]  Status  EFI return code.
+
+  @return  Transcoded EFI Shell return code.
+
+**/
+SHELL_STATUS
+EfiCodeToShellCode (
+  IN EFI_STATUS  Status
+  )
+{
+  SHELL_STATUS  ShellStatus;
+
+  switch (Status) {
+  case EFI_SUCCESS :
+    ShellStatus = SHELL_SUCCESS;
+    break;
+
+  case EFI_INVALID_PARAMETER :
+    ShellStatus = SHELL_INVALID_PARAMETER;
+    break;
+
+  case EFI_UNSUPPORTED :
+    ShellStatus = SHELL_UNSUPPORTED;
+    break;
+
+  case EFI_DEVICE_ERROR :
+    ShellStatus = SHELL_DEVICE_ERROR;
+    break;
+
+  case EFI_WRITE_PROTECTED    :
+  case EFI_SECURITY_VIOLATION :
+    ShellStatus = SHELL_ACCESS_DENIED;
+    break;
+
+  case EFI_OUT_OF_RESOURCES :
+    ShellStatus = SHELL_OUT_OF_RESOURCES;
+    break;
+
+  case EFI_NOT_FOUND :
+    ShellStatus = SHELL_NOT_FOUND;
+    break;
+
+  default :
+    ShellStatus = SHELL_ABORTED;
+  }
+
+  return ShellStatus;
+}
diff --git a/Platform/ARM/Drivers/FdtPlatformDxe/FdtPlatform.h b/Platform/ARM/Drivers/FdtPlatformDxe/FdtPlatform.h
new file mode 100644
index 000000000000..a631f2847bf5
--- /dev/null
+++ b/Platform/ARM/Drivers/FdtPlatformDxe/FdtPlatform.h
@@ -0,0 +1,174 @@
+/** @file
+
+  Copyright (c) 2015, ARM Ltd. All rights reserved.<BR>
+
+  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.
+
+**/
+
+#ifndef __FDT_PLATFORM_DXE_H__
+#define __FDT_PLATFORM_DXE_H__
+
+#include <Uefi.h>
+
+#include <Protocol/DevicePathToText.h>
+#include <Protocol/DevicePathFromText.h>
+#include <Protocol/Shell.h>
+#include <Protocol/ShellDynamicCommand.h>
+
+#include <Library/DebugLib.h>
+#include <Library/HiiLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+#include <Library/ShellLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+
+#include <Guid/Fdt.h>
+
+#include <libfdt.h>
+
+extern EFI_HANDLE mFdtPlatformDxeHiiHandle;
+
+/**
+  Transcode one of the EFI return code used by the model into an EFI Shell return code.
+
+  @param[in]  Status  EFI return code.
+
+  @return  Transcoded EFI Shell return code.
+
+**/
+SHELL_STATUS
+EfiCodeToShellCode (
+  IN EFI_STATUS  Status
+  );
+
+/**
+  Run the FDT installation process.
+
+  Loop in priority order over the device paths from which the FDT has
+  been asked to be retrieved for. For each device path, try to install
+  the FDT. Stop as soon as an installation succeeds.
+
+  @param[in]  SuccessfullDevicePath  If not NULL, address where to store the
+                                     pointer to the text device path from
+                                     which the FDT was successfully retrieved.
+                                     Not used if the FDT installation failed.
+                                     The returned address is the address of
+                                     an allocated buffer that has to be
+                                     freed by the caller.
+
+  @retval  EFI_SUCCESS            The FDT was installed.
+  @retval  EFI_NOT_FOUND          Failed to locate a protocol or a file.
+  @retval  EFI_INVALID_PARAMETER  Invalid device path.
+  @retval  EFI_UNSUPPORTED        Device path not supported.
+  @retval  EFI_OUT_OF_RESOURCES   An allocation failed.
+
+**/
+EFI_STATUS
+RunFdtInstallation (
+  OUT CHAR16  **SuccessfullDevicePath
+  );
+
+/**
+  This is the shell command "setfdt" handler function. This function handles
+  the command when it is invoked in the shell.
+
+  @param[in]  This             The instance of the
+                               EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL.
+  @param[in]  SystemTable      The pointer to the UEFI system table.
+  @param[in]  ShellParameters  The parameters associated with the command.
+  @param[in]  Shell            The instance of the shell protocol used in the
+                               context of processing this command.
+
+  @return  SHELL_SUCCESS            The operation was successful.
+  @return  SHELL_ABORTED            Operation aborted due to internal error.
+  @return  SHELL_INVALID_PARAMETER  The parameters of the command are not valid.
+  @return  SHELL_INVALID_PARAMETER  The EFI Shell file path is not valid.
+  @return  SHELL_NOT_FOUND          Failed to locate a protocol or a file.
+  @return  SHELL_UNSUPPORTED        Device path not supported.
+  @return  SHELL_OUT_OF_RESOURCES   A memory allocation failed.
+  @return  SHELL_DEVICE_ERROR       The "Fdt" variable could not be saved due to a hardware failure.
+  @return  SHELL_ACCESS_DENIED      The "Fdt" variable is read-only.
+  @return  SHELL_ACCESS_DENIED      The "Fdt" variable cannot be deleted.
+  @return  SHELL_ACCESS_DENIED      The "Fdt" variable could not be written due to security violation.
+
+**/
+SHELL_STATUS
+EFIAPI
+ShellDynCmdSetFdtHandler (
+  IN EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL  *This,
+  IN EFI_SYSTEM_TABLE                    *SystemTable,
+  IN EFI_SHELL_PARAMETERS_PROTOCOL       *ShellParameters,
+  IN EFI_SHELL_PROTOCOL                  *Shell
+  );
+
+/**
+  This is the shell command "setfdt" help handler function. This
+  function returns the formatted help for the "setfdt" command.
+  The format matchs that in Appendix B of the revision 2.1 of the
+  UEFI Shell Specification.
+
+  @param[in]  This      The instance of the EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL.
+  @param[in]  Language  The pointer to the language string to use.
+
+  @return  CHAR16*  Pool allocated help string, must be freed by caller.
+**/
+CHAR16*
+EFIAPI
+ShellDynCmdSetFdtGetHelp (
+  IN EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL  *This,
+  IN CONST CHAR8                         *Language
+  );
+
+/**
+  This is the shell command "dumpfdt" handler function. This function handles
+  the command when it is invoked in the shell.
+
+  @param[in]  This             The instance of the
+                               EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL.
+  @param[in]  SystemTable      The pointer to the UEFI system table.
+  @param[in]  ShellParameters  The parameters associated with the command.
+  @param[in]  Shell            The instance of the shell protocol used in the
+                               context of processing this command.
+
+  @return  SHELL_SUCCESS            The operation was successful.
+  @return  SHELL_ABORTED            Operation aborted due to internal error.
+  @return  SHELL_NOT_FOUND          Failed to locate the Device Tree into the EFI Configuration Table
+  @return  SHELL_OUT_OF_RESOURCES   A memory allocation failed.
+
+**/
+SHELL_STATUS
+EFIAPI
+ShellDynCmdDumpFdtHandler (
+  IN EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL  *This,
+  IN EFI_SYSTEM_TABLE                    *SystemTable,
+  IN EFI_SHELL_PARAMETERS_PROTOCOL       *ShellParameters,
+  IN EFI_SHELL_PROTOCOL                  *Shell
+  );
+
+/**
+  This is the shell command "dumpfdt" help handler function. This
+  function returns the formatted help for the "dumpfdt" command.
+  The format matchs that in Appendix B of the revision 2.1 of the
+  UEFI Shell Specification.
+
+  @param[in]  This      The instance of the EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL.
+  @param[in]  Language  The pointer to the language string to use.
+
+  @return  CHAR16*  Pool allocated help string, must be freed by caller.
+**/
+CHAR16*
+EFIAPI
+ShellDynCmdDumpFdtGetHelp (
+  IN EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL  *This,
+  IN CONST CHAR8                         *Language
+  );
+
+#endif /* __FDT_PLATFORM_DXE_H__ */
diff --git a/Platform/ARM/Drivers/FdtPlatformDxe/FdtPlatformDxe.dec b/Platform/ARM/Drivers/FdtPlatformDxe/FdtPlatformDxe.dec
new file mode 100644
index 000000000000..3faced589504
--- /dev/null
+++ b/Platform/ARM/Drivers/FdtPlatformDxe/FdtPlatformDxe.dec
@@ -0,0 +1,31 @@
+#/** @file
+#
+#  Copyright (c) 2011-2017, 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.
+#
+#**/
+
+[Defines]
+  DEC_SPECIFICATION              = 0x0001001A
+  PACKAGE_NAME                   = FdtPlatformDxe
+  PACKAGE_GUID                   = ed22c1e5-71cb-48d6-a9d8-c20f8d6b909f
+  PACKAGE_VERSION                = 0.1
+
+[Guids]
+  gFdtPlatformDxeTokenSpaceGuid = { 0xbfcaa0af, 0xedd4, 0x4ce7, { 0xbd, 0xb3, 0x39, 0x15, 0x07, 0x28, 0x65, 0x77 } }
+
+[PcdsFeatureFlag.common]
+  # Enable the development specific features
+  gFdtPlatformDxeTokenSpaceGuid.PcdOverridePlatformFdt|TRUE|BOOLEAN|0x00000001
+  # Add 'dumpfdt' EFI Shell command
+  gFdtPlatformDxeTokenSpaceGuid.PcdDumpFdtShellCommand|TRUE|BOOLEAN|0x00000002
+
+[PcdsFixedAtBuild.common, PcdsDynamic.common]
+  gFdtPlatformDxeTokenSpaceGuid.PcdFdtDevicePaths|L""|VOID*|0x00000055
diff --git a/Platform/ARM/Drivers/FdtPlatformDxe/FdtPlatformDxe.inf b/Platform/ARM/Drivers/FdtPlatformDxe/FdtPlatformDxe.inf
new file mode 100644
index 000000000000..f9a5aee3596e
--- /dev/null
+++ b/Platform/ARM/Drivers/FdtPlatformDxe/FdtPlatformDxe.inf
@@ -0,0 +1,65 @@
+#/** @file
+#
+#  Copyright (c) 2015, ARM Ltd. All rights reserved.<BR>
+#
+#  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.
+#
+#**/
+
+[Defines]
+  INF_VERSION                 = 0x00010006
+  BASE_NAME                   = FdtPlatformDxe
+  MODULE_UNI_FILE             = FdtPlatformDxe.uni
+  FILE_GUID                   = 4bd726b2-d1c8-4e98-ba08-2bc2ab251daf
+  MODULE_TYPE                 = UEFI_DRIVER
+  VERSION_STRING              = 0.1
+  ENTRY_POINT                 = FdtPlatformEntryPoint
+
+[Sources.common]
+  FdtPlatform.c
+  FdtPlatformDxe.uni
+  ShellDumpFdt.c
+  ShellSetFdt.c
+
+[Packages]
+  ArmPkg/ArmPkg.dec
+  EmbeddedPkg/EmbeddedPkg.dec
+  MdeModulePkg/MdeModulePkg.dec
+  MdePkg/MdePkg.dec
+  Platform/ARM/Drivers/FdtPlatformDxe/FdtPlatformDxe.dec
+  ShellPkg/ShellPkg.dec
+
+[LibraryClasses]
+  BaseMemoryLib
+  BdsLib
+  DebugLib
+  DxeServicesTableLib
+  FdtLib
+  HiiLib
+  ShellLib
+  UefiBootServicesTableLib
+  UefiDriverEntryPoint
+  UefiRuntimeServicesTableLib
+
+[Protocols]
+  gEfiDevicePathFromTextProtocolGuid
+  gEfiDevicePathToTextProtocolGuid
+  gEfiShellDynamicCommandProtocolGuid
+
+[Guids]
+  gEfiEndOfDxeEventGroupGuid
+  gFdtTableGuid
+  gFdtVariableGuid
+
+[FeaturePcd]
+  gFdtPlatformDxeTokenSpaceGuid.PcdDumpFdtShellCommand
+  gFdtPlatformDxeTokenSpaceGuid.PcdOverridePlatformFdt
+
+[Pcd]
+  gFdtPlatformDxeTokenSpaceGuid.PcdFdtDevicePaths
diff --git a/Platform/ARM/Drivers/FdtPlatformDxe/FdtPlatformDxe.uni b/Platform/ARM/Drivers/FdtPlatformDxe/FdtPlatformDxe.uni
new file mode 100644
index 000000000000..f8bde834841d
--- /dev/null
+++ b/Platform/ARM/Drivers/FdtPlatformDxe/FdtPlatformDxe.uni
@@ -0,0 +1,109 @@
+// *++
+//
+// Copyright (c) 2014, ARM Ltd. All rights reserved.<BR>
+//
+// 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.
+//
+//
+// Module Name:
+//
+//   FdtPlatformDxe
+//
+// Abstract:
+//
+//   String definitions for the EFI Shell 'setfdt' command
+//
+// Revision History:
+//
+// --*/
+
+/=#
+
+#langdef   en-US "English"
+
+#string STR_SETFDT_INSTALLING          #language en-US  "Installing the FDT ...\r\n"
+#string STR_SETFDT_INSTALL_SUCCEEDED   #language en-US  "Installation of\r\n'%s'\r\ncompleted.\r\n"
+
+#string STR_SETFDT_UPDATING            #language en-US  "Updating the FDT device path ...\r\n"
+#string STR_SETFDT_UPDATE_SUCCEEDED    #language en-US  "Update of the FDT device path '%s' completed.\r\n"
+#string STR_SETFDT_UPDATE_DELETED      #language en-US  "The UEFI variable "Fdt" was deleted.\r\n"
+
+#string STR_SETFDT_INVALID_DEVICE_PATH #language en-US  "Invalid device path.\r\n"
+#string STR_SETFDT_INVALID_PATH        #language en-US  "The EFI Shell or device file path '%s' is invalid.\r\n"
+#string STR_SETFDT_ERROR               #language en-US  "Error - %r.\r\n"
+#string STR_SETFDT_DEVICE_PATH_LIST    #language en-US  "FDT device paths :\r\n"
+#string STR_SETFDT_DEVICE_PATH         #language en-US  "'%s'\r\n"
+
+#string STR_GET_HELP_SETFDT            #language en-US ""
+".TH setfdt 0 "Define and/or install a new Flat Device Tree (FDT) for the platform."\r\n"
+".SH NAME\r\n"
+"Define and/or re-install a Flat Device Tree (FDT)\r\n"
+".SH SYNOPSIS\r\n"
+"setfdt [-i] [fdt_path]\r\n"
+".SH OPTIONS\r\n"
+"-i         run the FDT installation process\r\n"
+"file_path  EFI Shell file path or device path to a FDT\r\n"
+"\r\n"
+".SH DESCRIPTION\r\n"
+"NOTES:\r\n"
+"1. If a valid EFI Shell file path is passed to the command, then the\r\n"
+"   command translates the EFI Shell file path into a device path in the\r\n"
+"   text form and saves it in the non volatile UEFI variable "Fdt". If\r\n"
+"   the path to the FDT is a device path in the text form, it is saved as\r\n"
+"   it is in the non volatile UEFI variable "Fdt". The next time the FDT\r\n"
+"   installation process is run, it will first try to install the FDT from\r\n"
+"   the device path specified by the UEFI variable "Fdt".\r\n"
+" \r\n
+"2. If the option -i is passed to the command, then the FDT installation\r\n"
+"   process is run. If a path to the FDT is passed to the command as well,\r\n"
+"   the update of the "Fdt" UEFI variable is done first before to launch\r\n"
+"   the FDT installation process.\r\n"
+" \r\n
+".SH RETURNVALUES\r\n"
+"SHELL_SUCCESS            Operation(s) completed.\r\n"
+"SHELL_ABORTED            Operation aborted.\r\n"
+"SHELL_INVALID_PARAMETER  Invalid argument(s).\r\n"
+"SHELL_NOT_FOUND          Failed to locate a protocol or a file.\r\n"
+"SHELL_UNSUPPORTED        Device path not supported.\r\n"
+"SHELL_OUT_OF_RESOURCES   A memory allocation failed.\r\n"
+"SHELL_DEVICE ERROR       Hardware failure.\r\n"
+"SHELL_ACCESS_DENIED      Access to the Fdt UEFI variable for modification denied.\r\n"
+".SH EXAMPLES\r\n"
+"EXAMPLES:\r\n"
+"1. Relaunch the FDT installation process :\r\n"
+"   Shell> setfdt -i\r\n"
+"   \r\n"
+"2. Set the EFI Shell file path 'fs0:\>fdt.dtb' to be the default path\r\n"
+"   to the FDT :\r\n"
+"   Shell> setfdt fs0:fdt.dtb\r\n"
+"   \r\n"
+"3. Set a TFTP device path to be the default path to the FDT :\r\n"
+"   Shell> setfdt MAC(0002f700570b,0x1)/IPv4(192.168.1.1)/fdt.dtb\r\n"
+"     where . 00:02:f7:00:57:0b is the MAC address of the network\r\n"
+"             interface card to be used. The 'ifconfig -l' EFI Shell\r\n"
+"             command allows to get the MAC address of the network\r\n"
+"             interface cards.\r\n"
+"           . 192.168.1.1 is the address of the TFTP server.\r\n"
+"           . fdt.dtb is the file path to the FDT file on the server.\r\n"
+"4. Display the FDT device paths from the highest to the lowest\r\n"
+"   priority :\r\n"
+"   Shell> setfdt\r\n"
+"5. Delete the "Fdt" UEFI variable :\r\n"
+"   Shell> setfdt ""\r\n"
+"\r\n"
+
+#string STR_GET_HELP_DUMPFDT            #language en-US ""
+".TH dumpfdt 0 "Dump installed Flat Device Tree (FDT) of the platform."\r\n"
+".SH NAME\r\n"
+"Dump current Flat Device Tree (FDT)\r\n"
+".SH SYNOPSIS\r\n"
+"dumpfdt\r\n"
+"\r\n"
+".SH DESCRIPTION\r\n"
+"\r\n"
diff --git a/Platform/ARM/Drivers/FdtPlatformDxe/README.txt b/Platform/ARM/Drivers/FdtPlatformDxe/README.txt
new file mode 100644
index 000000000000..5f052d9a63aa
--- /dev/null
+++ b/Platform/ARM/Drivers/FdtPlatformDxe/README.txt
@@ -0,0 +1,72 @@
+/** @file
+
+  Copyright (c) 2015, ARM Ltd. All rights reserved.<BR>
+
+  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.
+
+**/
+
+The purpose of the FdtPlatformDxe UEFI driver is to install the Flat Device
+Tree (FDT) of the platform the UEFI frimware is running on into the UEFI
+Configuration Table. The FDT is identified within the UEFI Configuration
+Table by the "gFdtTableGuid" GUID defined in "EmbeddedPkg.dec".
+
+Once installed, an UEFI application or OS boot loader can get from the UEFI
+Configuration Table the FDT of the platform from the "gFdtTableGuid" GUID.
+
+The installation is done after each boot at the end of the DXE phase,
+just before the BDS phase. It is done at the end of the DXE phase to be sure
+that all drivers have been dispatched. That way, all UEFI protocols that may
+be needed to retrieve the FDT can be made available. It is done before the BDS
+phase to be able to provide the FDT during that phase.
+
+The present driver tries to retrieve the FDT from the device paths defined in the
+"gFdtPlatformDxeTokenSpaceGuid.PcdFdtDevicePaths" PCD. The "PcdFdtDevicePaths"
+PCD contains a list a device paths. The device paths are in the text form and
+separated by semi-colons. The present driver tries the device paths in the order
+it finds them in the "PcdFdtDevicePaths" PCD as long as he did not install
+succesfully a FDT.
+
+The "PcdFdtDevicePaths" PCD is a dynamic PCD that can be modified during the
+DXE phase. This allows for exemple to select the right FDT when a binary is
+intended to run on several platforms and/or variants of a platform.
+
+If the driver manages to download a FDT from one of the device paths mentioned
+above then it installs it in the UEFI Configuration table and the run over the
+device paths is stopped.
+
+For development purposes only, if the feature PCD "gFdtPlatformDxeTokenSpaceGuid.
+PcdOverridePlatformFdt" is equal to TRUE, then before to try to install the
+FDT from the device paths listed in the "PcdFdtDevicePaths" PCD, the present
+driver tries to install it using the device path defined by the UEFI variable
+"Fdt". If the variable does not exist or the installation using the device path
+defined by the UEFI variable fails then the installation proceeds as described
+above.
+
+Furthermore and again for development purposes only, if the feature PCD
+"PcdOverridePlatformFdt" is equal to TRUE, the current driver provides the EFI
+Shell command "setfdt" to define the location of the FDT by the mean of an EFI
+Shell file path (like "fs2:\boot\fdt.dtb") or a device path.
+
+If the path passed in to the command is a valid EFI Shell file path, the
+command translates it into the corresponding device path and stores that
+device path in the "Fdt" UEFI variable asking for the variable to be non
+volatile.
+
+If the path passed in to the command is not recognised as a valid EFI
+Shell device path, the command handles it as device path and stored
+in the "Fdt" UEFI variable as it is.
+
+Finally, the "-i" option of the "setfdt" command allows to trigger the FDT
+installation process. The installation process is completed when the command
+returns. The command can be invoked with the "-i" option only and in that
+case the "Fdt" UEFI variable is not updated and the command just runs the
+FDT installation process. If the command is invoked with the "-i" option and
+an EFI Shell file path then first the "Fdt" UEFI variable is updated accordingly
+and then the FDT installation process is run.
diff --git a/Platform/ARM/Drivers/FdtPlatformDxe/ShellDumpFdt.c b/Platform/ARM/Drivers/FdtPlatformDxe/ShellDumpFdt.c
new file mode 100644
index 000000000000..c7dc8985685b
--- /dev/null
+++ b/Platform/ARM/Drivers/FdtPlatformDxe/ShellDumpFdt.c
@@ -0,0 +1,279 @@
+/** @file
+
+  Copyright (c) 2015, ARM Ltd. All rights reserved.<BR>
+
+  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 "FdtPlatform.h"
+
+#define ALIGN(x, a)     (((x) + ((a) - 1)) & ~((a) - 1))
+#define PALIGN(p, a)    ((void *)(ALIGN ((unsigned long)(p), (a))))
+#define GET_CELL(p)     (p += 4, *((const uint32_t *)(p-4)))
+
+STATIC
+UINTN
+IsPrintableString (
+  IN CONST VOID* data,
+  IN UINTN len
+  )
+{
+  CONST CHAR8 *s = data;
+  CONST CHAR8 *ss;
+
+  // Zero length is not
+  if (len == 0) {
+    return 0;
+  }
+
+  // Must terminate with zero
+  if (s[len - 1] != '\0') {
+    return 0;
+  }
+
+  ss = s;
+  while (*s/* && isprint (*s)*/) {
+    s++;
+  }
+
+  // Not zero, or not done yet
+  if (*s != '\0' || (s + 1 - ss) < len) {
+    return 0;
+  }
+
+  return 1;
+}
+
+STATIC
+VOID
+PrintData (
+  IN CONST CHAR8* data,
+  IN UINTN len
+  )
+{
+  UINTN i;
+  CONST CHAR8 *p = data;
+
+  // No data, don't print
+  if (len == 0)
+    return;
+
+  if (IsPrintableString (data, len)) {
+    Print (L" = \"%a\"", (const char *)data);
+  } else if ((len % 4) == 0) {
+    Print (L" = <");
+    for (i = 0; i < len; i += 4) {
+      Print (L"0x%08x%a", fdt32_to_cpu (GET_CELL (p)), i < (len - 4) ? " " : "");
+    }
+    Print (L">");
+  } else {
+    Print (L" = [");
+    for (i = 0; i < len; i++)
+      Print (L"%02x%a", *p++, i < len - 1 ? " " : "");
+    Print (L"]");
+  }
+}
+
+STATIC
+VOID
+DumpFdt (
+  IN VOID*                FdtBlob
+  )
+{
+  struct fdt_header *bph;
+  UINT32 off_dt;
+  UINT32 off_str;
+  CONST CHAR8* p_struct;
+  CONST CHAR8* p_strings;
+  CONST CHAR8* p;
+  CONST CHAR8* s;
+  CONST CHAR8* t;
+  UINT32 tag;
+  UINTN sz;
+  UINTN depth;
+  UINTN shift;
+  UINT32 version;
+
+  {
+    // Can 'memreserve' be printed by below code?
+    INTN num = fdt_num_mem_rsv (FdtBlob);
+    INTN i, err;
+    UINT64 addr = 0, size = 0;
+
+    for (i = 0; i < num; i++) {
+      err = fdt_get_mem_rsv (FdtBlob, i, &addr, &size);
+      if (err) {
+        DEBUG ((EFI_D_ERROR, "Error (%d) : Cannot get memreserve section (%d)\n", err, i));
+      }
+      else {
+        Print (L"/memreserve/ \t0x%lx \t0x%lx;\n", addr, size);
+      }
+    }
+  }
+
+  depth = 0;
+  shift = 4;
+
+  bph = FdtBlob;
+  off_dt = fdt32_to_cpu (bph->off_dt_struct);
+  off_str = fdt32_to_cpu (bph->off_dt_strings);
+  p_struct = (CONST CHAR8*)FdtBlob + off_dt;
+  p_strings = (CONST CHAR8*)FdtBlob + off_str;
+  version = fdt32_to_cpu (bph->version);
+
+  p = p_struct;
+  while ((tag = fdt32_to_cpu (GET_CELL (p))) != FDT_END) {
+    if (tag == FDT_BEGIN_NODE) {
+      s = p;
+      p = PALIGN (p + AsciiStrLen (s) + 1, 4);
+
+      if (*s == '\0')
+              s = "/";
+
+      Print (L"%*s%a {\n", depth * shift, L" ", s);
+
+      depth++;
+      continue;
+    }
+
+    if (tag == FDT_END_NODE) {
+      depth--;
+
+      Print (L"%*s};\n", depth * shift, L" ");
+      continue;
+    }
+
+    if (tag == FDT_NOP) {
+      Print (L"%*s// [NOP]\n", depth * shift, L" ");
+      continue;
+    }
+
+    if (tag != FDT_PROP) {
+      Print (L"%*s ** Unknown tag 0x%08x\n", depth * shift, L" ", tag);
+      break;
+    }
+    sz = fdt32_to_cpu (GET_CELL (p));
+    s = p_strings + fdt32_to_cpu (GET_CELL (p));
+    if (version < 16 && sz >= 8)
+            p = PALIGN (p, 8);
+    t = p;
+
+    p = PALIGN (p + sz, 4);
+
+    Print (L"%*s%a", depth * shift, L" ", s);
+    PrintData (t, sz);
+    Print (L";\n");
+  }
+}
+
+/**
+  This is the shell command "dumpfdt" handler function. This function handles
+  the command when it is invoked in the shell.
+
+  @param[in]  This             The instance of the
+                               EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL.
+  @param[in]  SystemTable      The pointer to the UEFI system table.
+  @param[in]  ShellParameters  The parameters associated with the command.
+  @param[in]  Shell            The instance of the shell protocol used in the
+                               context of processing this command.
+
+  @return  SHELL_SUCCESS            The operation was successful.
+  @return  SHELL_ABORTED            Operation aborted due to internal error.
+  @return  SHELL_NOT_FOUND          Failed to locate the Device Tree into the EFI Configuration Table
+  @return  SHELL_OUT_OF_RESOURCES   A memory allocation failed.
+
+**/
+SHELL_STATUS
+EFIAPI
+ShellDynCmdDumpFdtHandler (
+  IN EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL  *This,
+  IN EFI_SYSTEM_TABLE                    *SystemTable,
+  IN EFI_SHELL_PARAMETERS_PROTOCOL       *ShellParameters,
+  IN EFI_SHELL_PROTOCOL                  *Shell
+  )
+{
+  SHELL_STATUS  ShellStatus;
+  EFI_STATUS    Status;
+  VOID          *FdtBlob;
+
+  ShellStatus  = SHELL_SUCCESS;
+
+  //
+  // Install the Shell and Shell Parameters Protocols on the driver
+  // image. This is necessary for the initialisation of the Shell
+  // Library to succeed in the next step.
+  //
+  Status = gBS->InstallMultipleProtocolInterfaces (
+                  &gImageHandle,
+                  &gEfiShellProtocolGuid, Shell,
+                  &gEfiShellParametersProtocolGuid, ShellParameters,
+                  NULL
+                  );
+  if (EFI_ERROR (Status)) {
+    return SHELL_ABORTED;
+  }
+
+  //
+  // Initialise the Shell Library as we are going to use it.
+  // Assert that the return code is EFI_SUCCESS as it should.
+  // To anticipate any change is the codes returned by
+  // ShellInitialize(), leave in case of error.
+  //
+  Status = ShellInitialize ();
+  if (EFI_ERROR (Status)) {
+    ASSERT_EFI_ERROR (Status);
+    return SHELL_ABORTED;
+  }
+
+  Status = EfiGetSystemConfigurationTable (&gFdtTableGuid, &FdtBlob);
+  if (EFI_ERROR (Status)) {
+    Print (L"ERROR: Did not find the Fdt Blob.\n");
+    return EfiCodeToShellCode (Status);
+  }
+
+  DumpFdt (FdtBlob);
+
+  gBS->UninstallMultipleProtocolInterfaces (
+         gImageHandle,
+         &gEfiShellProtocolGuid, Shell,
+         &gEfiShellParametersProtocolGuid, ShellParameters,
+         NULL
+         );
+
+  return ShellStatus;
+}
+
+/**
+  This is the shell command "dumpfdt" help handler function. This
+  function returns the formatted help for the "dumpfdt" command.
+  The format matchs that in Appendix B of the revision 2.1 of the
+  UEFI Shell Specification.
+
+  @param[in]  This      The instance of the EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL.
+  @param[in]  Language  The pointer to the language string to use.
+
+  @return  CHAR16*  Pool allocated help string, must be freed by caller.
+**/
+CHAR16*
+EFIAPI
+ShellDynCmdDumpFdtGetHelp (
+  IN EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL  *This,
+  IN CONST CHAR8                         *Language
+  )
+{
+  //
+  // This allocates memory. The caller has to free the allocated memory.
+  //
+  return HiiGetString (
+                mFdtPlatformDxeHiiHandle,
+                STRING_TOKEN (STR_GET_HELP_DUMPFDT),
+                Language
+                );
+}
diff --git a/Platform/ARM/Drivers/FdtPlatformDxe/ShellSetFdt.c b/Platform/ARM/Drivers/FdtPlatformDxe/ShellSetFdt.c
new file mode 100644
index 000000000000..9be23c845593
--- /dev/null
+++ b/Platform/ARM/Drivers/FdtPlatformDxe/ShellSetFdt.c
@@ -0,0 +1,468 @@
+/** @file
+
+  Copyright (c) 2015, ARM Ltd. All rights reserved.<BR>
+
+  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 "FdtPlatform.h"
+
+STATIC CONST SHELL_PARAM_ITEM ParamList[] = {
+  {L"-i", TypeFlag },
+  {NULL , TypeMax  }
+};
+
+/**
+  Display FDT device paths.
+
+  Display in text form the device paths used to install the FDT from the
+  highest to the lowest priority.
+
+**/
+STATIC
+VOID
+DisplayFdtDevicePaths (
+  VOID
+  )
+{
+  EFI_STATUS  Status;
+  UINTN       DataSize;
+  CHAR16      *TextDevicePath;
+  CHAR16      *TextDevicePaths;
+  CHAR16      *TextDevicePathSeparator;
+
+  ShellPrintHiiEx (
+    -1, -1, NULL,
+    STRING_TOKEN (STR_SETFDT_DEVICE_PATH_LIST),
+    mFdtPlatformDxeHiiHandle
+    );
+
+  if (FeaturePcdGet (PcdOverridePlatformFdt)) {
+    DataSize = 0;
+    Status = gRT->GetVariable (
+                    L"Fdt",
+                    &gFdtVariableGuid,
+                    NULL,
+                    &DataSize,
+                    NULL
+                    );
+
+    //
+    // Keep going only if the "Fdt" variable is defined.
+    //
+
+    if (Status == EFI_BUFFER_TOO_SMALL) {
+      TextDevicePath = AllocatePool (DataSize);
+      if (TextDevicePath == NULL) {
+        return;
+      }
+
+      Status = gRT->GetVariable (
+                      L"Fdt",
+                      &gFdtVariableGuid,
+                      NULL,
+                      &DataSize,
+                      TextDevicePath
+                      );
+      if (!EFI_ERROR (Status)) {
+        ShellPrintHiiEx (
+          -1, -1, NULL,
+          STRING_TOKEN (STR_SETFDT_DEVICE_PATH),
+          mFdtPlatformDxeHiiHandle,
+          TextDevicePath
+          );
+      }
+
+      FreePool (TextDevicePath);
+    }
+  }
+
+  //
+  // Loop over the device path list provided by "PcdFdtDevicePaths". The device
+  // paths are in text form and separated by a semi-colon.
+  //
+
+  TextDevicePaths = AllocateCopyPool (
+                      StrSize ((CHAR16*)PcdGetPtr (PcdFdtDevicePaths)),
+                      (CHAR16*)PcdGetPtr (PcdFdtDevicePaths)
+                      );
+  if (TextDevicePaths == NULL) {
+    return;
+  }
+
+  for (TextDevicePath = TextDevicePaths;
+       *TextDevicePath != L'\0'        ; ) {
+    TextDevicePathSeparator = StrStr (TextDevicePath, L";");
+
+    if (TextDevicePathSeparator != NULL) {
+      *TextDevicePathSeparator = L'\0';
+    }
+
+    ShellPrintHiiEx (
+      -1, -1, NULL,
+      STRING_TOKEN (STR_SETFDT_DEVICE_PATH),
+      mFdtPlatformDxeHiiHandle,
+      TextDevicePath
+      );
+
+    if (TextDevicePathSeparator == NULL) {
+      break;
+    }
+    TextDevicePath = TextDevicePathSeparator + 1;
+  }
+
+  FreePool (TextDevicePaths);
+}
+
+/**
+  Update the text device path stored in the "Fdt" UEFI variable given
+  an EFI Shell file path or a text device path.
+
+  This function is a subroutine of the ShellDynCmdSetFdtHandler() function
+  to make its code easier to read.
+
+  @param[in]  Shell          The instance of the shell protocol used in the
+                             context of processing the "setfdt" command.
+  @param[in]  FilePath       EFI Shell path or the device path to the FDT file.
+
+  @return  SHELL_SUCCESS            The text device path was succesfully updated.
+  @return  SHELL_INVALID_PARAMETER  The Shell file path is not valid.
+  @return  SHELL_OUT_OF_RESOURCES   A memory allocation failed.
+  @return  SHELL_DEVICE_ERROR       The "Fdt" variable could not be saved due to a hardware failure.
+  @return  SHELL_ACCESS_DENIED      The "Fdt" variable is read-only.
+  @return  SHELL_ACCESS_DENIED      The "Fdt" variable cannot be deleted.
+  @return  SHELL_ACCESS_DENIED      The "Fdt" variable could not be written due to security violation.
+  @return  SHELL_NOT_FOUND          Device path to text protocol not found.
+  @return  SHELL_ABORTED            Operation aborted.
+
+**/
+STATIC
+SHELL_STATUS
+UpdateFdtTextDevicePath (
+  IN EFI_SHELL_PROTOCOL  *Shell,
+  IN CONST CHAR16        *FilePath
+  )
+{
+  EFI_STATUS                          Status;
+  EFI_DEVICE_PATH                     *DevicePath;
+  EFI_DEVICE_PATH_TO_TEXT_PROTOCOL    *EfiDevicePathToTextProtocol;
+  CHAR16                              *TextDevicePath;
+  CHAR16                              *FdtVariableValue;
+  EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL  *EfiDevicePathFromTextProtocol;
+  SHELL_STATUS                        ShellStatus;
+
+  ASSERT (FilePath != NULL);
+  DevicePath       = NULL;
+  TextDevicePath   = NULL;
+  FdtVariableValue = NULL;
+
+  if (*FilePath != L'\0') {
+    DevicePath = Shell->GetDevicePathFromFilePath (FilePath);
+    if (DevicePath != NULL) {
+      Status = gBS->LocateProtocol (
+                      &gEfiDevicePathToTextProtocolGuid,
+                      NULL,
+                      (VOID **)&EfiDevicePathToTextProtocol
+                      );
+      if (EFI_ERROR (Status)) {
+        goto Error;
+      }
+
+      TextDevicePath = EfiDevicePathToTextProtocol->ConvertDevicePathToText (
+                                                      DevicePath,
+                                                      FALSE,
+                                                      FALSE
+                                                      );
+      if (TextDevicePath == NULL) {
+        Status = EFI_OUT_OF_RESOURCES;
+        goto Error;
+      }
+      FdtVariableValue = TextDevicePath;
+    } else {
+      //
+      // Try to convert back the EFI Device Path String into a EFI device Path
+      // to ensure the format is valid
+      //
+      Status = gBS->LocateProtocol (
+                      &gEfiDevicePathFromTextProtocolGuid,
+                      NULL,
+                      (VOID **)&EfiDevicePathFromTextProtocol
+                      );
+      if (EFI_ERROR (Status)) {
+        goto Error;
+      }
+
+      DevicePath = EfiDevicePathFromTextProtocol->ConvertTextToDevicePath (
+                                                    FilePath
+                                                    );
+      if (DevicePath == NULL) {
+        Status = EFI_INVALID_PARAMETER;
+        goto Error;
+      }
+      FdtVariableValue = (CHAR16*)FilePath;
+    }
+  }
+
+  Status = gRT->SetVariable (
+                  (CHAR16*)L"Fdt",
+                  &gFdtVariableGuid,
+                  EFI_VARIABLE_RUNTIME_ACCESS    |
+                  EFI_VARIABLE_NON_VOLATILE      |
+                  EFI_VARIABLE_BOOTSERVICE_ACCESS ,
+                  (FdtVariableValue != NULL) ?
+                  StrSize (FdtVariableValue) : 0,
+                  FdtVariableValue
+                  );
+
+Error:
+  ShellStatus = EfiCodeToShellCode (Status);
+  if (!EFI_ERROR (Status)) {
+    if (FdtVariableValue != NULL) {
+      ShellPrintHiiEx (
+        -1, -1, NULL,
+        STRING_TOKEN (STR_SETFDT_UPDATE_SUCCEEDED),
+        mFdtPlatformDxeHiiHandle,
+        FdtVariableValue
+        );
+    } else {
+      ShellPrintHiiEx (
+        -1, -1, NULL,
+        STRING_TOKEN (STR_SETFDT_UPDATE_DELETED),
+        mFdtPlatformDxeHiiHandle
+        );
+    }
+  } else {
+    if (Status == EFI_INVALID_PARAMETER) {
+      ShellPrintHiiEx (
+        -1, -1, NULL,
+        STRING_TOKEN (STR_SETFDT_INVALID_PATH),
+        mFdtPlatformDxeHiiHandle,
+        FilePath
+        );
+    } else {
+      ShellPrintHiiEx (
+        -1, -1, NULL,
+        STRING_TOKEN (STR_SETFDT_ERROR),
+        mFdtPlatformDxeHiiHandle,
+        Status
+        );
+    }
+  }
+
+  if (DevicePath != NULL) {
+    FreePool (DevicePath);
+  }
+  if (TextDevicePath != NULL) {
+    FreePool (TextDevicePath);
+  }
+
+  return ShellStatus;
+}
+
+/**
+  This is the shell command "setfdt" handler function. This function handles
+  the command when it is invoked in the shell.
+
+  @param[in]  This             The instance of the
+                               EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL.
+  @param[in]  SystemTable      The pointer to the UEFI system table.
+  @param[in]  ShellParameters  The parameters associated with the command.
+  @param[in]  Shell            The instance of the shell protocol used in the
+                               context of processing this command.
+
+  @return  SHELL_SUCCESS            The operation was successful.
+  @return  SHELL_ABORTED            Operation aborted due to internal error.
+  @return  SHELL_INVALID_PARAMETER  The parameters of the command are not valid.
+  @return  SHELL_INVALID_PARAMETER  The EFI Shell file path is not valid.
+  @return  SHELL_NOT_FOUND          Failed to locate a protocol or a file.
+  @return  SHELL_UNSUPPORTED        Device path not supported.
+  @return  SHELL_OUT_OF_RESOURCES   A memory allocation failed.
+  @return  SHELL_DEVICE_ERROR       The "Fdt" variable could not be saved due to a hardware failure.
+  @return  SHELL_ACCESS_DENIED      The "Fdt" variable is read-only.
+  @return  SHELL_ACCESS_DENIED      The "Fdt" variable cannot be deleted.
+  @return  SHELL_ACCESS_DENIED      The "Fdt" variable could not be written due to security violation.
+
+**/
+SHELL_STATUS
+EFIAPI
+ShellDynCmdSetFdtHandler (
+  IN EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL  *This,
+  IN EFI_SYSTEM_TABLE                    *SystemTable,
+  IN EFI_SHELL_PARAMETERS_PROTOCOL       *ShellParameters,
+  IN EFI_SHELL_PROTOCOL                  *Shell
+  )
+{
+  SHELL_STATUS  ShellStatus;
+  EFI_STATUS    Status;
+  LIST_ENTRY    *ParamPackage;
+  BOOLEAN       FilePath;
+  CONST CHAR16  *ValueStr;
+  CHAR16        *TextDevicePath;
+
+  ShellStatus  = SHELL_SUCCESS;
+  ParamPackage = NULL;
+  FilePath     = FALSE;
+
+  //
+  // Install the Shell and Shell Parameters Protocols on the driver
+  // image. This is necessary for the initialisation of the Shell
+  // Library to succeed in the next step.
+  //
+  Status = gBS->InstallMultipleProtocolInterfaces (
+                  &gImageHandle,
+                  &gEfiShellProtocolGuid, Shell,
+                  &gEfiShellParametersProtocolGuid, ShellParameters,
+                  NULL
+                  );
+  if (EFI_ERROR (Status)) {
+    return SHELL_ABORTED;
+  }
+
+  //
+  // Initialise the Shell Library as we are going to use it.
+  // Assert that the return code is EFI_SUCCESS as it should.
+  // To anticipate any change is the codes returned by
+  // ShellInitialize(), leave in case of error.
+  //
+  Status = ShellInitialize ();
+  if (EFI_ERROR (Status)) {
+    ASSERT_EFI_ERROR (Status);
+    return SHELL_ABORTED;
+  }
+
+  Status = ShellCommandLineParse (ParamList, &ParamPackage, NULL, TRUE);
+  if (!EFI_ERROR (Status)) {
+    switch (ShellCommandLineGetCount (ParamPackage)) {
+    case 1:
+      //
+      // Case "setfdt" or "setfdt -i"
+      //
+      if (!ShellCommandLineGetFlag (ParamPackage, L"-i")) {
+        DisplayFdtDevicePaths ();
+      }
+      break;
+
+    case 2:
+      //
+      // Case "setfdt file_path"    or
+      //      "setfdt -i file_path" or
+      //      "setfdt file_path -i"
+      //
+      FilePath = TRUE;
+      break;
+
+    default:
+      Status = EFI_INVALID_PARAMETER;
+    }
+  }
+  if (EFI_ERROR (Status)) {
+    ShellStatus = EfiCodeToShellCode (Status);
+    ShellPrintHiiEx (
+      -1, -1, NULL,
+      STRING_TOKEN (STR_SETFDT_ERROR),
+      mFdtPlatformDxeHiiHandle,
+      Status
+      );
+    goto Error;
+  }
+
+  //
+  // Update the preferred device path for the FDT if asked for.
+  //
+  if (FilePath) {
+    ValueStr = ShellCommandLineGetRawValue (ParamPackage, 1);
+    ShellPrintHiiEx (
+      -1, -1, NULL,
+      STRING_TOKEN (STR_SETFDT_UPDATING),
+      mFdtPlatformDxeHiiHandle
+      );
+    ShellStatus = UpdateFdtTextDevicePath (Shell, ValueStr);
+    if (ShellStatus != SHELL_SUCCESS) {
+      goto Error;
+    }
+  }
+
+  //
+  // Run the FDT installation process if asked for.
+  //
+  if (ShellCommandLineGetFlag (ParamPackage, L"-i")) {
+    ShellPrintHiiEx (
+      -1, -1, NULL,
+      STRING_TOKEN (STR_SETFDT_INSTALLING),
+      mFdtPlatformDxeHiiHandle
+      );
+    Status = RunFdtInstallation (&TextDevicePath);
+    ShellStatus = EfiCodeToShellCode (Status);
+    if (!EFI_ERROR (Status)) {
+      ShellPrintHiiEx (
+        -1, -1, NULL,
+        STRING_TOKEN (STR_SETFDT_INSTALL_SUCCEEDED),
+        mFdtPlatformDxeHiiHandle,
+        TextDevicePath
+        );
+      FreePool (TextDevicePath);
+    } else {
+      if (Status == EFI_INVALID_PARAMETER) {
+        ShellPrintHiiEx (
+          -1, -1, NULL,
+          STRING_TOKEN (STR_SETFDT_INVALID_DEVICE_PATH),
+          mFdtPlatformDxeHiiHandle
+          );
+      } else {
+        ShellPrintHiiEx (
+          -1, -1, NULL,
+          STRING_TOKEN (STR_SETFDT_ERROR),
+          mFdtPlatformDxeHiiHandle,
+          Status
+          );
+      }
+      DisplayFdtDevicePaths ();
+    }
+  }
+
+Error:
+  gBS->UninstallMultipleProtocolInterfaces (
+         gImageHandle,
+         &gEfiShellProtocolGuid, Shell,
+         &gEfiShellParametersProtocolGuid, ShellParameters,
+         NULL
+         );
+  ShellCommandLineFreeVarList (ParamPackage);
+
+  return ShellStatus;
+}
+
+/**
+  This is the shell command "setfdt" help handler function. This
+  function returns the formatted help for the "setfdt" command.
+  The format matchs that in Appendix B of the revision 2.1 of the
+  UEFI Shell Specification.
+
+  @param[in]  This      The instance of the EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL.
+  @param[in]  Language  The pointer to the language string to use.
+
+  @return  CHAR16*  Pool allocated help string, must be freed by caller.
+**/
+CHAR16*
+EFIAPI
+ShellDynCmdSetFdtGetHelp (
+  IN EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL  *This,
+  IN CONST CHAR8                         *Language
+  )
+{
+  //
+  // This allocates memory. The caller has to free the allocated memory.
+  //
+  return HiiGetString (
+                mFdtPlatformDxeHiiHandle,
+                STRING_TOKEN (STR_GET_HELP_SETFDT),
+                Language
+                );
+}
-- 
2.11.0



^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH edk2-platforms 3/4] Platform/ARM/Juno: move to migrated FdtPlatformDxe
  2017-11-20 11:37 [PATCH edk2-platforms 0/4] Platform/ARM: import BdsLib and FdtPlatformDxe Ard Biesheuvel
  2017-11-20 11:37 ` [PATCH edk2-platforms 1/4] Platform/ARM: import BdsLib from ArmPkg Ard Biesheuvel
  2017-11-20 11:37 ` [PATCH edk2-platforms 2/4] Platform/ARM: import FdtPlatformDxe driver from EDK2 Ard Biesheuvel
@ 2017-11-20 11:37 ` Ard Biesheuvel
  2017-11-20 11:37 ` [PATCH edk2-platforms 4/4] Platform/TC2: move to private FdtPlatformDxe implementation Ard Biesheuvel
  2017-11-25 13:28 ` [PATCH edk2-platforms 0/4] Platform/ARM: import BdsLib and FdtPlatformDxe Leif Lindholm
  4 siblings, 0 replies; 7+ messages in thread
From: Ard Biesheuvel @ 2017-11-20 11:37 UTC (permalink / raw)
  To: edk2-devel; +Cc: leif.lindholm, Ard Biesheuvel

Move Juno to the migrated version of FdtPlatformDxe.

Contributed-under: TianoCore Contribution Agreement 1.1
Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
---
 Platform/ARM/JunoPkg/ArmJuno.dsc                       | 6 +++---
 Platform/ARM/JunoPkg/ArmJuno.fdf                       | 2 +-
 Platform/ARM/JunoPkg/Drivers/ArmJunoDxe/ArmJunoDxe.inf | 3 ++-
 Platform/ARM/VExpressPkg/ArmVExpress.dsc.inc           | 5 +----
 4 files changed, 7 insertions(+), 9 deletions(-)

diff --git a/Platform/ARM/JunoPkg/ArmJuno.dsc b/Platform/ARM/JunoPkg/ArmJuno.dsc
index 4c63309d36f1..e7cb280ff381 100644
--- a/Platform/ARM/JunoPkg/ArmJuno.dsc
+++ b/Platform/ARM/JunoPkg/ArmJuno.dsc
@@ -200,7 +200,7 @@ [PcdsDynamicDefault.common]
   # character "empty" string, to allow to be able to set FDT text device paths
   # up to 128 characters long.
   #
-  gEmbeddedTokenSpaceGuid.PcdFdtDevicePaths|L"                                                                                                                                "
+  gFdtPlatformDxeTokenSpaceGuid.PcdFdtDevicePaths|L"                                                                                                                                "
 
   # Not all Juno platforms support PCI. This dynamic PCD disables or enable
   # PCI support.
@@ -352,9 +352,9 @@ [Components.common]
   #
   # FDT installation
   #
-  EmbeddedPkg/Drivers/FdtPlatformDxe/FdtPlatformDxe.inf {
+  Platform/ARM/Drivers/FdtPlatformDxe/FdtPlatformDxe.inf {
     <LibraryClasses>
-      BdsLib|ArmPkg/Library/BdsLib/BdsLib.inf
+      BdsLib|Platform/ARM/Library/BdsLib/BdsLib.inf
   }
 
 [Components.AARCH64]
diff --git a/Platform/ARM/JunoPkg/ArmJuno.fdf b/Platform/ARM/JunoPkg/ArmJuno.fdf
index 04d58323d130..898c471248d7 100644
--- a/Platform/ARM/JunoPkg/ArmJuno.fdf
+++ b/Platform/ARM/JunoPkg/ArmJuno.fdf
@@ -230,7 +230,7 @@ [FV.FvMain]
   #
   # The UEFI driver is at the end of the list of the driver to be dispatched
   # after the device drivers (eg: Ethernet) to ensure we have support for them.
-  INF EmbeddedPkg/Drivers/FdtPlatformDxe/FdtPlatformDxe.inf
+  INF Platform/ARM/Drivers/FdtPlatformDxe/FdtPlatformDxe.inf
 
 !if $(ARCH) == AARCH64
   #
diff --git a/Platform/ARM/JunoPkg/Drivers/ArmJunoDxe/ArmJunoDxe.inf b/Platform/ARM/JunoPkg/Drivers/ArmJunoDxe/ArmJunoDxe.inf
index 70175c2d2405..7da336fbd8e7 100644
--- a/Platform/ARM/JunoPkg/Drivers/ArmJunoDxe/ArmJunoDxe.inf
+++ b/Platform/ARM/JunoPkg/Drivers/ArmJunoDxe/ArmJunoDxe.inf
@@ -29,6 +29,7 @@ [Packages]
   MdePkg/MdePkg.dec
   MdeModulePkg/MdeModulePkg.dec
   Platform/ARM/ARM.dec
+  Platform/ARM/Drivers/FdtPlatformDxe/FdtPlatformDxe.dec
   Platform/ARM/JunoPkg/ArmJuno.dec
 
 [LibraryClasses]
@@ -81,7 +82,7 @@ [FixedPcd]
   gArmTokenSpaceGuid.PcdPciBusMax
 
 [Pcd]
-  gEmbeddedTokenSpaceGuid.PcdFdtDevicePaths
+  gFdtPlatformDxeTokenSpaceGuid.PcdFdtDevicePaths
   gEfiMdeModulePkgTokenSpaceGuid.PcdPciDisableBusEnumeration
 
 [Depex]
diff --git a/Platform/ARM/VExpressPkg/ArmVExpress.dsc.inc b/Platform/ARM/VExpressPkg/ArmVExpress.dsc.inc
index 75f4e924cb9f..3679530decf0 100644
--- a/Platform/ARM/VExpressPkg/ArmVExpress.dsc.inc
+++ b/Platform/ARM/VExpressPkg/ArmVExpress.dsc.inc
@@ -457,10 +457,7 @@ [Components.common]
   #
   # Android Fastboot
   #
-  EmbeddedPkg/Application/AndroidFastboot/AndroidFastbootApp.inf {
-    <LibraryClasses>
-      BdsLib|ArmPkg/Library/BdsLib/BdsLib.inf
-  }
+  EmbeddedPkg/Application/AndroidFastboot/AndroidFastbootApp.inf
   EmbeddedPkg/Drivers/AndroidFastbootTransportUsbDxe/FastbootTransportUsbDxe.inf
   Platform/ARM/VExpressPkg/Drivers/ArmVExpressFastBootDxe/ArmVExpressFastBootDxe.inf
 
-- 
2.11.0



^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH edk2-platforms 4/4] Platform/TC2: move to private FdtPlatformDxe implementation
  2017-11-20 11:37 [PATCH edk2-platforms 0/4] Platform/ARM: import BdsLib and FdtPlatformDxe Ard Biesheuvel
                   ` (2 preceding siblings ...)
  2017-11-20 11:37 ` [PATCH edk2-platforms 3/4] Platform/ARM/Juno: move to migrated FdtPlatformDxe Ard Biesheuvel
@ 2017-11-20 11:37 ` Ard Biesheuvel
  2017-11-25 13:28 ` [PATCH edk2-platforms 0/4] Platform/ARM: import BdsLib and FdtPlatformDxe Leif Lindholm
  4 siblings, 0 replies; 7+ messages in thread
From: Ard Biesheuvel @ 2017-11-20 11:37 UTC (permalink / raw)
  To: edk2-devel; +Cc: leif.lindholm, Ard Biesheuvel

Move to our own private copy of FdtPlatformDxe and BdsLib so that we
can get rid of the upstream version.

Contributed-under: TianoCore Contribution Agreement 1.1
Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
---
 Platform/ARM/VExpressPkg/ArmVExpress-CTA15-A7.dsc | 6 +++---
 Platform/ARM/VExpressPkg/ArmVExpress-CTA15-A7.fdf | 2 +-
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/Platform/ARM/VExpressPkg/ArmVExpress-CTA15-A7.dsc b/Platform/ARM/VExpressPkg/ArmVExpress-CTA15-A7.dsc
index 1e6884ad5480..995dacd0b473 100644
--- a/Platform/ARM/VExpressPkg/ArmVExpress-CTA15-A7.dsc
+++ b/Platform/ARM/VExpressPkg/ArmVExpress-CTA15-A7.dsc
@@ -183,7 +183,7 @@ [PcdsFixedAtBuild.common]
   #
   # Define the device path to the FDT for the platform
   #
-  gEmbeddedTokenSpaceGuid.PcdFdtDevicePaths|L"VenHw(E7223039-5836-41E1-B542-D7EC736C5E59)/ca15a7"
+  gFdtPlatformDxeTokenSpaceGuid.PcdFdtDevicePaths|L"VenHw(E7223039-5836-41E1-B542-D7EC736C5E59)/ca15a7"
 
   #
   # ARM Architectural Timer Frequency
@@ -296,7 +296,7 @@ [Components.common]
   #
   # FDT installation
   #
-  EmbeddedPkg/Drivers/FdtPlatformDxe/FdtPlatformDxe.inf {
+  Platform/ARM/Drivers/FdtPlatformDxe/FdtPlatformDxe.inf {
     <LibraryClasses>
-      BdsLib|ArmPkg/Library/BdsLib/BdsLib.inf
+      BdsLib|Platform/ARM/Library/BdsLib/BdsLib.inf
   }
diff --git a/Platform/ARM/VExpressPkg/ArmVExpress-CTA15-A7.fdf b/Platform/ARM/VExpressPkg/ArmVExpress-CTA15-A7.fdf
index ed901f9f1f86..86d6f1415383 100644
--- a/Platform/ARM/VExpressPkg/ArmVExpress-CTA15-A7.fdf
+++ b/Platform/ARM/VExpressPkg/ArmVExpress-CTA15-A7.fdf
@@ -183,7 +183,7 @@ [FV.FvMain]
   #
   # The UEFI driver is at the end of the list of the driver to be dispatched
   # after the device drivers (eg: Ethernet) to ensure we have support for them.
-  INF EmbeddedPkg/Drivers/FdtPlatformDxe/FdtPlatformDxe.inf
+  INF Platform/ARM/Drivers/FdtPlatformDxe/FdtPlatformDxe.inf
 
   # Example to add a Device Tree to the Firmware Volume
   #FILE FREEFORM = PCD(gArmVExpressTokenSpaceGuid.PcdFdtVExpressHwA15x2A7x3) {
-- 
2.11.0



^ permalink raw reply related	[flat|nested] 7+ messages in thread

* Re: [PATCH edk2-platforms 0/4] Platform/ARM: import BdsLib and FdtPlatformDxe
  2017-11-20 11:37 [PATCH edk2-platforms 0/4] Platform/ARM: import BdsLib and FdtPlatformDxe Ard Biesheuvel
                   ` (3 preceding siblings ...)
  2017-11-20 11:37 ` [PATCH edk2-platforms 4/4] Platform/TC2: move to private FdtPlatformDxe implementation Ard Biesheuvel
@ 2017-11-25 13:28 ` Leif Lindholm
  2017-11-26 10:41   ` Ard Biesheuvel
  4 siblings, 1 reply; 7+ messages in thread
From: Leif Lindholm @ 2017-11-25 13:28 UTC (permalink / raw)
  To: Ard Biesheuvel; +Cc: edk2-devel

On Mon, Nov 20, 2017 at 11:37:10AM +0000, Ard Biesheuvel wrote:
> The only remnant of the deprecated ARM BDS in EDK2 is its BdsLib, which is
> depended upon by FdtPlatformDxe in EmbeddedPkg, which itself is something
> we'd prefer to get rid of. Since only TC2 and Juno actually use this driver,
> let's move both FdtPlatformDxe and BdsLib under Platform/ARM, so that we can
> remove it from the main EDK2 repository.

I see no issue with this series as such (and agree with its intent).
However, on the EDK2 side, we still have some users of BdsLib in the
EmbeddedPkg Android loaders.

(I have sent out a trivial series to get rid of these, but this move
should be ordered against that set.)

Once that's in, for the series:
Reviewed-by: Leif Lindholm <leif.lindholm@linaro.org>

/
    Leif

> Ard Biesheuvel (4):
>   Platform/ARM: import BdsLib from ArmPkg
>   Platform/ARM: import FdtPlatformDxe driver from EDK2
>   Platform/ARM/Juno: move to migrated FdtPlatformDxe
>   Platform/TC2: move to private FdtPlatformDxe implementation
>
>  Platform/ARM/Drivers/FdtPlatformDxe/FdtPlatform.c      |  461 +++++++
>  Platform/ARM/Drivers/FdtPlatformDxe/FdtPlatform.h      |  174 +++
>  Platform/ARM/Drivers/FdtPlatformDxe/FdtPlatformDxe.dec |   31 +
>  Platform/ARM/Drivers/FdtPlatformDxe/FdtPlatformDxe.inf |   65 +
>  Platform/ARM/Drivers/FdtPlatformDxe/FdtPlatformDxe.uni |  109 ++
>  Platform/ARM/Drivers/FdtPlatformDxe/README.txt         |   72 +
>  Platform/ARM/Drivers/FdtPlatformDxe/ShellDumpFdt.c     |  279 ++++
>  Platform/ARM/Drivers/FdtPlatformDxe/ShellSetFdt.c      |  468 +++++++
>  Platform/ARM/JunoPkg/ArmJuno.dsc                       |    6 +-
>  Platform/ARM/JunoPkg/ArmJuno.fdf                       |    2 +-
>  Platform/ARM/JunoPkg/Drivers/ArmJunoDxe/ArmJunoDxe.inf |    3 +-
>  Platform/ARM/Library/BdsLib/BdsAppLoader.c             |  253 ++++
>  Platform/ARM/Library/BdsLib/BdsFilePath.c              | 1413 ++++++++++++++++++++
>  Platform/ARM/Library/BdsLib/BdsHelper.c                |  183 +++
>  Platform/ARM/Library/BdsLib/BdsInternal.h              |  111 ++
>  Platform/ARM/Library/BdsLib/BdsLib.inf                 |   62 +
>  Platform/ARM/Library/BdsLib/BdsLoadOption.c            |  272 ++++
>  Platform/ARM/VExpressPkg/ArmVExpress-CTA15-A7.dsc      |    6 +-
>  Platform/ARM/VExpressPkg/ArmVExpress-CTA15-A7.fdf      |    2 +-
>  Platform/ARM/VExpressPkg/ArmVExpress.dsc.inc           |    5 +-
>  20 files changed, 3964 insertions(+), 13 deletions(-)
>  create mode 100644 Platform/ARM/Drivers/FdtPlatformDxe/FdtPlatform.c
>  create mode 100644 Platform/ARM/Drivers/FdtPlatformDxe/FdtPlatform.h
>  create mode 100644 Platform/ARM/Drivers/FdtPlatformDxe/FdtPlatformDxe.dec
>  create mode 100644 Platform/ARM/Drivers/FdtPlatformDxe/FdtPlatformDxe.inf
>  create mode 100644 Platform/ARM/Drivers/FdtPlatformDxe/FdtPlatformDxe.uni
>  create mode 100644 Platform/ARM/Drivers/FdtPlatformDxe/README.txt
>  create mode 100644 Platform/ARM/Drivers/FdtPlatformDxe/ShellDumpFdt.c
>  create mode 100644 Platform/ARM/Drivers/FdtPlatformDxe/ShellSetFdt.c
>  create mode 100644 Platform/ARM/Library/BdsLib/BdsAppLoader.c
>  create mode 100644 Platform/ARM/Library/BdsLib/BdsFilePath.c
>  create mode 100644 Platform/ARM/Library/BdsLib/BdsHelper.c
>  create mode 100644 Platform/ARM/Library/BdsLib/BdsInternal.h
>  create mode 100644 Platform/ARM/Library/BdsLib/BdsLib.inf
>  create mode 100644 Platform/ARM/Library/BdsLib/BdsLoadOption.c
> 
> -- 
> 2.11.0
> 


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH edk2-platforms 0/4] Platform/ARM: import BdsLib and FdtPlatformDxe
  2017-11-25 13:28 ` [PATCH edk2-platforms 0/4] Platform/ARM: import BdsLib and FdtPlatformDxe Leif Lindholm
@ 2017-11-26 10:41   ` Ard Biesheuvel
  0 siblings, 0 replies; 7+ messages in thread
From: Ard Biesheuvel @ 2017-11-26 10:41 UTC (permalink / raw)
  To: Leif Lindholm; +Cc: edk2-devel@lists.01.org

On 25 November 2017 at 13:28, Leif Lindholm <leif.lindholm@linaro.org> wrote:
> On Mon, Nov 20, 2017 at 11:37:10AM +0000, Ard Biesheuvel wrote:
>> The only remnant of the deprecated ARM BDS in EDK2 is its BdsLib, which is
>> depended upon by FdtPlatformDxe in EmbeddedPkg, which itself is something
>> we'd prefer to get rid of. Since only TC2 and Juno actually use this driver,
>> let's move both FdtPlatformDxe and BdsLib under Platform/ARM, so that we can
>> remove it from the main EDK2 repository.
>
> I see no issue with this series as such (and agree with its intent).
> However, on the EDK2 side, we still have some users of BdsLib in the
> EmbeddedPkg Android loaders.
>
> (I have sent out a trivial series to get rid of these, but this move
> should be ordered against that set.)
>
> Once that's in, for the series:
> Reviewed-by: Leif Lindholm <leif.lindholm@linaro.org>
>

Thanks. Pushed as 4591a21d5a8e..9bf000f2bd38


^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2017-11-26 10:36 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2017-11-20 11:37 [PATCH edk2-platforms 0/4] Platform/ARM: import BdsLib and FdtPlatformDxe Ard Biesheuvel
2017-11-20 11:37 ` [PATCH edk2-platforms 1/4] Platform/ARM: import BdsLib from ArmPkg Ard Biesheuvel
2017-11-20 11:37 ` [PATCH edk2-platforms 2/4] Platform/ARM: import FdtPlatformDxe driver from EDK2 Ard Biesheuvel
2017-11-20 11:37 ` [PATCH edk2-platforms 3/4] Platform/ARM/Juno: move to migrated FdtPlatformDxe Ard Biesheuvel
2017-11-20 11:37 ` [PATCH edk2-platforms 4/4] Platform/TC2: move to private FdtPlatformDxe implementation Ard Biesheuvel
2017-11-25 13:28 ` [PATCH edk2-platforms 0/4] Platform/ARM: import BdsLib and FdtPlatformDxe Leif Lindholm
2017-11-26 10:41   ` Ard Biesheuvel

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox