[edk2] [PATCH edk2-platforms 2/4] Platform/ARM: import FdtPlatformDxe driver from EDK2

Ard Biesheuvel posted 4 patches 7 years, 1 month ago
[edk2] [PATCH edk2-platforms 2/4] Platform/ARM: import FdtPlatformDxe driver from EDK2
Posted by Ard Biesheuvel 7 years, 1 month ago
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

_______________________________________________
edk2-devel mailing list
edk2-devel@lists.01.org
https://lists.01.org/mailman/listinfo/edk2-devel