EmbeddedPkg : Add FdtPlatformDxe driver
authorRonald Cron <Ronald.Cron@arm.com>
Wed, 25 Feb 2015 19:20:57 +0000 (19:20 +0000)
committeroliviermartin <oliviermartin@Edk2>
Wed, 25 Feb 2015 19:20:57 +0000 (19:20 +0000)
The FdtPlatformDxe driver installs the FDT of the platform it
is running on into the UEFI Configuration table at the end of
the DXE phase.

Please refer to the README.txt file for a global overview of
the driver.

Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Ronald Cron <Ronald.Cron@arm.com>
Reviewed-by: Olivier Martin <olivier.martin@arm.com>
git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@16933 6f19259b-4bc3-4df7-8a09-765794883524

EmbeddedPkg/Drivers/FdtPlatformDxe/FdtPlatform.c [new file with mode: 0644]
EmbeddedPkg/Drivers/FdtPlatformDxe/FdtPlatformDxe.inf [new file with mode: 0644]
EmbeddedPkg/Drivers/FdtPlatformDxe/README.txt [new file with mode: 0644]
EmbeddedPkg/EmbeddedPkg.dec
EmbeddedPkg/EmbeddedPkg.dsc
EmbeddedPkg/Include/Guid/Fdt.h

diff --git a/EmbeddedPkg/Drivers/FdtPlatformDxe/FdtPlatform.c b/EmbeddedPkg/Drivers/FdtPlatformDxe/FdtPlatform.c
new file mode 100644 (file)
index 0000000..8608fcf
--- /dev/null
@@ -0,0 +1,742 @@
+/** @file\r
+\r
+  Copyright (c) 2015, ARM Ltd. All rights reserved.<BR>\r
+\r
+  This program and the accompanying materials\r
+  are licensed and made available under the terms and conditions of the BSD License\r
+  which accompanies this distribution.  The full text of the license may be found at\r
+  http://opensource.org/licenses/bsd-license.php\r
+\r
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+#include <Uefi.h>\r
+\r
+#include <Library/UefiLib.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/UefiBootServicesTableLib.h>\r
+#include <Library/UefiRuntimeServicesTableLib.h>\r
+#include <Library/PcdLib.h>\r
+#include <Library/DevicePathLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+\r
+#include <Library/BdsLib.h>\r
+\r
+#include <Protocol/DevicePathFromText.h>\r
+#include <Protocol/DevicePath.h>\r
+\r
+#include <Guid/EventGroup.h>\r
+#include <Guid/Fdt.h>\r
+\r
+#include <libfdt.h>\r
+\r
+//\r
+// Internal types\r
+//\r
+STATIC VOID OnEndOfDxe (\r
+  IN EFI_EVENT  Event,\r
+  IN VOID       *Context\r
+  );\r
+STATIC EFI_STATUS RunFdtInstallation (\r
+  VOID\r
+  );\r
+STATIC EFI_STATUS InstallFdt (\r
+  IN CONST CHAR16*  TextDevicePath\r
+  );\r
+\r
+/**\r
+  Main entry point of the FDT platform driver.\r
+\r
+  @param[in]  ImageHandle   The firmware allocated handle for the present driver\r
+                            UEFI image.\r
+  @param[in]  *SystemTable  A pointer to the EFI System table.\r
+\r
+  @retval  EFI_SUCCESS           The driver was initialized.\r
+  @retval  EFI_OUT_OF_RESOURCES  The "End of DXE" event could not be allocated.\r
+\r
+**/\r
+EFI_STATUS\r
+FdtPlatformEntryPoint (\r
+  IN EFI_HANDLE        ImageHandle,\r
+  IN EFI_SYSTEM_TABLE  *SystemTable\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+  EFI_EVENT   EndOfDxeEvent;\r
+\r
+  //\r
+  // Create an event belonging to the "gEfiEndOfDxeEventGroupGuid" group.\r
+  // The "OnEndOfDxe()" function is declared as the call back function.\r
+  // It will be called at the end of the DXE phase when an event of the\r
+  // same group is signalled to inform about the end of the DXE phase.\r
+  //\r
+  Status = gBS->CreateEventEx (\r
+                  EVT_NOTIFY_SIGNAL,\r
+                  TPL_CALLBACK,\r
+                  OnEndOfDxe,\r
+                  NULL,\r
+                  &gEfiEndOfDxeEventGroupGuid,\r
+                  &EndOfDxeEvent\r
+                  );\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Notification function of the event defined as belonging to the\r
+  EFI_END_OF_DXE_EVENT_GROUP_GUID event group that was created in\r
+  the entry point of the driver.\r
+\r
+  This function is called when an event belonging to the\r
+  EFI_END_OF_DXE_EVENT_GROUP_GUID event group is signalled. Such an\r
+  event is signalled once at the end of the dispatching of all\r
+  drivers (end of the so called DXE phase).\r
+\r
+  @param[in]  Event    Event declared in the entry point of the driver whose\r
+                       notification function is being invoked.\r
+  @param[in]  Context  NULL\r
+\r
+**/\r
+STATIC\r
+VOID\r
+OnEndOfDxe (\r
+  IN EFI_EVENT  Event,\r
+  IN VOID       *Context\r
+  )\r
+{\r
+  RunFdtInstallation ();\r
+  gBS->CloseEvent (Event);\r
+}\r
+\r
+/**\r
+  Run the FDT installation process.\r
+\r
+  Loop in priority order over the device paths from which the FDT has\r
+  been asked to be retrieved for. For each device path, try to install\r
+  the FDT. Stop as soon as an installation succeeds.\r
+\r
+  @retval  EFI_SUCCESS            The FDT was installed.\r
+  @retval  EFI_NOT_FOUND          Failed to locate a protocol or a file.\r
+  @retval  EFI_INVALID_PARAMETER  Invalid device path.\r
+  @retval  EFI_UNSUPPORTED        Device path not supported.\r
+  @retval  EFI_OUT_OF_RESOURCES   An allocation failed.\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+RunFdtInstallation (\r
+  VOID\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+  UINTN       DataSize;\r
+  VOID        *Data;\r
+  CHAR16      *TextDevicePathStart;\r
+  CHAR16      *TextDevicePathSeparator;\r
+  UINTN       TextDevicePathLen;\r
+  CHAR16      *TextDevicePath;\r
+\r
+  //\r
+  // For development purpose, if enabled through the "PcdOverridePlatformFdt"\r
+  // feature PCD, try first to install the FDT specified by the device path in\r
+  // text form stored in the "Fdt" UEFI variable.\r
+  //\r
+  if (FeaturePcdGet (PcdOverridePlatformFdt)) {\r
+    Data     = NULL;\r
+    DataSize = 0;\r
+    Status = gRT->GetVariable (\r
+                    L"Fdt",\r
+                    &gFdtVariableGuid,\r
+                    NULL,\r
+                    &DataSize,\r
+                    Data\r
+                    );\r
+\r
+    //\r
+    // Keep going only if the "Fdt" variable is defined.\r
+    //\r
+\r
+    if (Status == EFI_BUFFER_TOO_SMALL) {\r
+      Data = AllocatePool (DataSize);\r
+      if (Data == NULL) {\r
+        Status = EFI_OUT_OF_RESOURCES;\r
+      } else {\r
+        Status = gRT->GetVariable (\r
+                        L"Fdt",\r
+                        &gFdtVariableGuid,\r
+                        NULL,\r
+                        &DataSize,\r
+                        Data\r
+                        );\r
+        if (!EFI_ERROR (Status)) {\r
+          Status = InstallFdt ((CHAR16*)Data);\r
+          if (!EFI_ERROR (Status)) {\r
+            DEBUG ((\r
+              EFI_D_WARN,\r
+              "Installation of the FDT using the device path <%s> completed.\n",\r
+              (CHAR16*)Data\r
+              ));\r
+          }\r
+        }\r
+        FreePool (Data);\r
+      }\r
+\r
+      if (EFI_ERROR (Status)) {\r
+        DEBUG ((\r
+          EFI_D_ERROR,\r
+          "Installation of the FDT specified by the \"Fdt\" UEFI variable failed - %r\n",\r
+          Status\r
+          ));\r
+      } else {\r
+        return Status;\r
+      }\r
+    }\r
+  }\r
+\r
+  //\r
+  // Loop over the device path list provided by "PcdFdtDevicePaths". The device\r
+  // paths are in text form and separated by a semi-colon.\r
+  //\r
+\r
+  Status = EFI_SUCCESS;\r
+  for (TextDevicePathStart = (CHAR16*)PcdGetPtr (PcdFdtDevicePaths);\r
+       *TextDevicePathStart != L'\0'                               ; ) {\r
+    TextDevicePathSeparator = StrStr (TextDevicePathStart, L";");\r
+\r
+    //\r
+    // Last device path of the list\r
+    //\r
+    if (TextDevicePathSeparator == NULL) {\r
+      TextDevicePath = TextDevicePathStart;\r
+    } else {\r
+      TextDevicePathLen = (UINTN)(TextDevicePathSeparator - TextDevicePathStart);\r
+      TextDevicePath = AllocateCopyPool (\r
+                         (TextDevicePathLen + 1) * sizeof (CHAR16),\r
+                         TextDevicePathStart\r
+                         );\r
+      if (TextDevicePath == NULL) {\r
+        Status = EFI_OUT_OF_RESOURCES;\r
+        DEBUG ((EFI_D_ERROR, "Memory allocation error during FDT installation process.\n"));\r
+        break;\r
+      }\r
+      TextDevicePath[TextDevicePathLen] = L'\0';\r
+    }\r
+\r
+    Status = InstallFdt (TextDevicePath);\r
+    if (EFI_ERROR (Status)) {\r
+      DEBUG ((EFI_D_WARN, "Installation of the FDT using the device path <%s> failed - %r.\n",\r
+        TextDevicePath, Status\r
+        ));\r
+    } else {\r
+      DEBUG ((EFI_D_WARN, "Installation of the FDT using the device path <%s> completed.\n",\r
+        TextDevicePath\r
+        ));\r
+    }\r
+\r
+    if (TextDevicePathSeparator == NULL) {\r
+      break;\r
+    } else {\r
+      FreePool (TextDevicePath);\r
+      if (!EFI_ERROR (Status)) {\r
+        break;\r
+      }\r
+      TextDevicePathStart = TextDevicePathSeparator + 1;\r
+    }\r
+  }\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_ERROR, "Failed to install the FDT - %r.\n", Status));\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Install the FDT specified by its device path in text form.\r
+\r
+  @param[in]  TextDevicePath  Device path of the FDT to install in text form\r
+\r
+  @retval  EFI_SUCCESS            The FDT was installed.\r
+  @retval  EFI_NOT_FOUND          Failed to locate a protocol or a file.\r
+  @retval  EFI_INVALID_PARAMETER  Invalid device path.\r
+  @retval  EFI_UNSUPPORTED        Device path not supported.\r
+  @retval  EFI_OUT_OF_RESOURCES   An allocation failed.\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+InstallFdt (\r
+  IN CONST CHAR16*  TextDevicePath\r
+  )\r
+{\r
+  EFI_STATUS                          Status;\r
+  EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL  *EfiDevicePathFromTextProtocol;\r
+  EFI_DEVICE_PATH                     *DevicePath;\r
+  EFI_PHYSICAL_ADDRESS                FdtBlobBase;\r
+  UINTN                               FdtBlobSize;\r
+  UINTN                               NbPages;\r
+  EFI_PHYSICAL_ADDRESS                RsFdtBlobBase;\r
+\r
+  Status = gBS->LocateProtocol (\r
+                  &gEfiDevicePathFromTextProtocolGuid,\r
+                  NULL,\r
+                  (VOID **)&EfiDevicePathFromTextProtocol\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_ERROR, "InstallFdt() - Failed to locate EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL protocol\n"));\r
+    return Status;\r
+  }\r
+\r
+  DevicePath = (EFI_DEVICE_PATH*)EfiDevicePathFromTextProtocol->ConvertTextToDevicePath (TextDevicePath);\r
+  if (DevicePath == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  //\r
+  // Load the FDT given its device path.\r
+  // This operation may fail if the device path is not supported.\r
+  //\r
+  FdtBlobBase = 0;\r
+  NbPages     = 0;\r
+  Status = BdsLoadImage (DevicePath, AllocateAnyPages, &FdtBlobBase, &FdtBlobSize);\r
+  if (EFI_ERROR (Status)) {\r
+    goto Error;\r
+  }\r
+\r
+  // Check the FDT header is valid. We only make this check in DEBUG mode in\r
+  // case the FDT header change on production device and this ASSERT() becomes\r
+  // not valid.\r
+  ASSERT (fdt_check_header ((VOID*)(UINTN)FdtBlobBase) == 0);\r
+\r
+  //\r
+  // Ensure the Size of the Device Tree is smaller than the size of the read file\r
+  //\r
+  ASSERT ((UINTN)fdt_totalsize ((VOID*)(UINTN)FdtBlobBase) <= FdtBlobSize);\r
+\r
+  //\r
+  // Store the FDT as Runtime Service Data to prevent the Kernel from\r
+  // overwritting its data.\r
+  //\r
+  NbPages = EFI_SIZE_TO_PAGES (FdtBlobSize);\r
+  Status = gBS->AllocatePages (\r
+                  AllocateAnyPages, EfiRuntimeServicesData,\r
+                  NbPages, &RsFdtBlobBase\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    goto Error;\r
+  }\r
+  CopyMem (\r
+    (VOID*)((UINTN)RsFdtBlobBase),\r
+    (VOID*)((UINTN)FdtBlobBase),\r
+    FdtBlobSize\r
+    );\r
+\r
+  //\r
+  // Install the FDT into the Configuration Table\r
+  //\r
+  Status = gBS->InstallConfigurationTable (\r
+                  &gFdtTableGuid,\r
+                  (VOID*)((UINTN)RsFdtBlobBase)\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    gBS->FreePages (RsFdtBlobBase, NbPages);\r
+  }\r
+\r
+Error :\r
+\r
+  if (FdtBlobBase != 0) {\r
+    gBS->FreePages (FdtBlobBase, NbPages);\r
+  }\r
+  FreePool (DevicePath);\r
+\r
+  return Status;\r
+}\r
+\r
+=======\r
+\r
+/**\r
+  This is the shell command "setfdt" handler function. This function handles\r
+  the command when it is invoked in the shell.\r
+\r
+  @param[in]  This             The instance of the\r
+                               EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL.\r
+  @param[in]  SystemTable      The pointer to the UEFI system table.\r
+  @param[in]  ShellParameters  The parameters associated with the command.\r
+  @param[in]  Shell            The instance of the shell protocol used in the\r
+                               context of processing this command.\r
+\r
+  @return  SHELL_SUCCESS            The operation was successful.\r
+  @return  SHELL_ABORTED            Operation aborted due to internal error.\r
+  @return  SHELL_INVALID_PARAMETER  The parameters of the command are not valid.\r
+  @return  SHELL_INVALID_PARAMETER  The EFI Shell file path is not valid.\r
+  @return  SHELL_NOT_FOUND          Failed to locate a protocol or a file.\r
+  @return  SHELL_UNSUPPORTED        Device path not supported.\r
+  @return  SHELL_OUT_OF_RESOURCES   A memory allocation failed.\r
+  @return  SHELL_DEVICE_ERROR       The "Fdt" variable could not be saved due to a hardware failure.\r
+  @return  SHELL_ACCESS_DENIED      The "Fdt" variable is read-only.\r
+  @return  SHELL_ACCESS_DENIED      The "Fdt" variable cannot be deleted.\r
+  @return  SHELL_ACCESS_DENIED      The "Fdt" variable could not be written due to security violation.\r
+\r
+**/\r
+STATIC\r
+SHELL_STATUS\r
+EFIAPI\r
+ShellDynCmdSetFdtHandler (\r
+  IN EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL  *This,\r
+  IN EFI_SYSTEM_TABLE                    *SystemTable,\r
+  IN EFI_SHELL_PARAMETERS_PROTOCOL       *ShellParameters,\r
+  IN EFI_SHELL_PROTOCOL                  *Shell\r
+  )\r
+{\r
+  SHELL_STATUS  ShellStatus;\r
+  EFI_STATUS    Status;\r
+  LIST_ENTRY    *ParamPackage;\r
+  BOOLEAN       FilePath;\r
+  CONST CHAR16  *ValueStr;\r
+\r
+  ShellStatus  = SHELL_SUCCESS;\r
+  ParamPackage = NULL;\r
+  FilePath     = FALSE;\r
+\r
+  //\r
+  // Install the Shell and Shell Parameters Protocols on the driver\r
+  // image. This is necessary for the initialisation of the Shell\r
+  // Library to succeed in the next step.\r
+  //\r
+  Status = gBS->InstallMultipleProtocolInterfaces (\r
+                  &gImageHandle,\r
+                  &gEfiShellProtocolGuid, Shell,\r
+                  &gEfiShellParametersProtocolGuid, ShellParameters,\r
+                  NULL\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    return SHELL_ABORTED;\r
+  }\r
+\r
+  //\r
+  // Initialise the Shell Library as we are going to use it.\r
+  // Assert that the return code is EFI_SUCCESS as it should.\r
+  // To anticipate any change is the codes returned by\r
+  // ShellInitialize(), leave in case of error.\r
+  //\r
+  Status = ShellInitialize ();\r
+  if (EFI_ERROR (Status)) {\r
+    ASSERT_EFI_ERROR (Status);\r
+    return SHELL_ABORTED;\r
+  }\r
+\r
+  Status = ShellCommandLineParse (ParamList, &ParamPackage, NULL, TRUE);\r
+  if (!EFI_ERROR (Status)) {\r
+    switch (ShellCommandLineGetCount (ParamPackage)) {\r
+    case 1:\r
+      //\r
+      // Case "setfdt -i"\r
+      //\r
+      if (!ShellCommandLineGetFlag (ParamPackage, L"-i")) {\r
+        Status = EFI_INVALID_PARAMETER;\r
+      }\r
+      break;\r
+\r
+    case 2:\r
+      //\r
+      // Case "setfdt file_path"    or\r
+      //      "setfdt -i file_path" or\r
+      //      "setfdt file_path -i"\r
+      //\r
+      FilePath = TRUE;\r
+      break;\r
+\r
+    default:\r
+      Status = EFI_INVALID_PARAMETER;\r
+    }\r
+  }\r
+  if (EFI_ERROR (Status)) {\r
+    ShellStatus = EfiCodeToShellCode (Status);\r
+    ShellPrintHiiEx (\r
+      -1, -1, NULL,\r
+      STRING_TOKEN (STR_SETFDT_ERROR),\r
+      mFdtPlatformDxeHiiHandle,\r
+      Status\r
+      );\r
+    goto Error;\r
+  }\r
+\r
+  //\r
+  // Update the preferred device path for the FDT if asked for.\r
+  //\r
+  if (FilePath) {\r
+    ValueStr = ShellCommandLineGetRawValue (ParamPackage, 1);\r
+    ShellPrintHiiEx (\r
+      -1, -1, NULL,\r
+      STRING_TOKEN (STR_SETFDT_UPDATING),\r
+      mFdtPlatformDxeHiiHandle\r
+      );\r
+    ShellStatus = UpdateFdtTextDevicePath (Shell, ValueStr);\r
+    if (ShellStatus != SHELL_SUCCESS) {\r
+      goto Error;\r
+    }\r
+  }\r
+\r
+  //\r
+  // Run the FDT installation process if asked for.\r
+  //\r
+  if (ShellCommandLineGetFlag (ParamPackage, L"-i")) {\r
+    ShellPrintHiiEx (\r
+      -1, -1, NULL,\r
+      STRING_TOKEN (STR_SETFDT_INSTALLING),\r
+      mFdtPlatformDxeHiiHandle\r
+      );\r
+    Status = RunFdtInstallation ();\r
+    ShellStatus = EfiCodeToShellCode (Status);\r
+    if (!EFI_ERROR (Status)) {\r
+      ShellPrintHiiEx (\r
+        -1, -1, NULL,\r
+        STRING_TOKEN (STR_SETFDT_INSTALL_SUCCEEDED),\r
+        mFdtPlatformDxeHiiHandle\r
+        );\r
+    } else {\r
+      if (Status == EFI_INVALID_PARAMETER) {\r
+        ShellPrintHiiEx (\r
+          -1, -1, NULL,\r
+          STRING_TOKEN (STR_SETFDT_INVALID_DEVICE_PATH),\r
+          mFdtPlatformDxeHiiHandle\r
+          );\r
+      } else {\r
+        ShellPrintHiiEx (\r
+          -1, -1, NULL,\r
+          STRING_TOKEN (STR_SETFDT_ERROR),\r
+          mFdtPlatformDxeHiiHandle,\r
+          Status\r
+          );\r
+      }\r
+    }\r
+  }\r
+\r
+Error:\r
+\r
+  gBS->UninstallMultipleProtocolInterfaces (\r
+         gImageHandle,\r
+         &gEfiShellProtocolGuid, Shell,\r
+         &gEfiShellParametersProtocolGuid, ShellParameters,\r
+         NULL\r
+         );\r
+  ShellCommandLineFreeVarList (ParamPackage);\r
+\r
+  return ShellStatus;\r
+}\r
+\r
+/**\r
+  This is the shell command "setfdt" help handler function. This\r
+  function returns the formatted help for the "setfdt" command.\r
+  The format matchs that in Appendix B of the revision 2.1 of the\r
+  UEFI Shell Specification.\r
+\r
+  @param[in]  This      The instance of the EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL.\r
+  @param[in]  Language  The pointer to the language string to use.\r
+\r
+  @return  CHAR16*  Pool allocated help string, must be freed by caller.\r
+**/\r
+STATIC\r
+CHAR16*\r
+EFIAPI\r
+ShellDynCmdSetFdtGetHelp (\r
+  IN EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL  *This,\r
+  IN CONST CHAR8                         *Language\r
+  )\r
+{\r
+  //\r
+  // This allocates memory. The caller has to free the allocated memory.\r
+  //\r
+  return HiiGetString (\r
+                mFdtPlatformDxeHiiHandle,\r
+                STRING_TOKEN (STR_GET_HELP_SETFDT),\r
+                Language\r
+                );\r
+}\r
+\r
+/**\r
+  Update the text device path stored in the "Fdt" UEFI variable given\r
+  an EFI Shell file path or a text device path.\r
+\r
+  This function is a subroutine of the ShellDynCmdSetFdtHandler() function\r
+  to make its code easier to read.\r
+\r
+  @param[in]  Shell          The instance of the shell protocol used in the\r
+                             context of processing the "setfdt" command.\r
+  @param[in]  FilePath       EFI Shell path or the device path to the FDT file.\r
+\r
+  @return  SHELL_SUCCESS            The text device path was succesfully updated.\r
+  @return  SHELL_INVALID_PARAMETER  The Shell file path is not valid.\r
+  @return  SHELL_OUT_OF_RESOURCES   A memory allocation failed.\r
+  @return  SHELL_DEVICE_ERROR       The "Fdt" variable could not be saved due to a hardware failure.\r
+  @return  SHELL_ACCESS_DENIED      The "Fdt" variable is read-only.\r
+  @return  SHELL_ACCESS_DENIED      The "Fdt" variable cannot be deleted.\r
+  @return  SHELL_ACCESS_DENIED      The "Fdt" variable could not be written due to security violation.\r
+  @return  SHELL_NOT_FOUND          Device path to text protocol not found.\r
+  @return  SHELL_ABORTED            Operation aborted.\r
+\r
+**/\r
+STATIC\r
+SHELL_STATUS\r
+UpdateFdtTextDevicePath (\r
+  IN EFI_SHELL_PROTOCOL  *Shell,\r
+  IN CONST CHAR16        *FilePath\r
+  )\r
+{\r
+  EFI_STATUS                          Status;\r
+  EFI_DEVICE_PATH                     *DevicePath;\r
+  EFI_DEVICE_PATH_TO_TEXT_PROTOCOL    *EfiDevicePathToTextProtocol;\r
+  CHAR16                              *TextDevicePath;\r
+  CHAR16                              *FdtVariableValue;\r
+  EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL  *EfiDevicePathFromTextProtocol;\r
+  SHELL_STATUS                        ShellStatus;\r
+\r
+  ASSERT (FilePath != NULL);\r
+  TextDevicePath   = NULL;\r
+  FdtVariableValue = NULL;\r
+\r
+  DevicePath = Shell->GetDevicePathFromFilePath (FilePath);\r
+  if (DevicePath != NULL) {\r
+    Status = gBS->LocateProtocol (\r
+                    &gEfiDevicePathToTextProtocolGuid,\r
+                    NULL,\r
+                    (VOID **)&EfiDevicePathToTextProtocol\r
+                    );\r
+    if (EFI_ERROR (Status)) {\r
+      goto Error;\r
+    }\r
+\r
+    TextDevicePath = EfiDevicePathToTextProtocol->ConvertDevicePathToText (\r
+                                                    DevicePath,\r
+                                                    FALSE,\r
+                                                    FALSE\r
+                                                    );\r
+    if (TextDevicePath == NULL) {\r
+      Status = EFI_OUT_OF_RESOURCES;\r
+      goto Error;\r
+    }\r
+    FdtVariableValue = TextDevicePath;\r
+  } else {\r
+    //\r
+    // Try to convert back the EFI Device Path String into a EFI device Path\r
+    // to ensure the format is valid\r
+    //\r
+    Status = gBS->LocateProtocol (\r
+                    &gEfiDevicePathFromTextProtocolGuid,\r
+                    NULL,\r
+                    (VOID **)&EfiDevicePathFromTextProtocol\r
+                    );\r
+    if (EFI_ERROR (Status)) {\r
+      goto Error;\r
+    }\r
+\r
+    DevicePath = EfiDevicePathFromTextProtocol->ConvertTextToDevicePath (\r
+                                                  FilePath\r
+                                                  );\r
+    if (DevicePath == NULL) {\r
+      Status = EFI_INVALID_PARAMETER;\r
+      goto Error;\r
+    }\r
+    FdtVariableValue = (CHAR16*)FilePath;\r
+  }\r
+\r
+  Status = gRT->SetVariable (\r
+                  (CHAR16*)L"Fdt",\r
+                  &gFdtVariableGuid,\r
+                  EFI_VARIABLE_RUNTIME_ACCESS    |\r
+                  EFI_VARIABLE_NON_VOLATILE      |\r
+                  EFI_VARIABLE_BOOTSERVICE_ACCESS ,\r
+                  StrSize (FdtVariableValue),\r
+                  FdtVariableValue\r
+                  );\r
+\r
+Error:\r
+  ShellStatus = EfiCodeToShellCode (Status);\r
+  if (!EFI_ERROR (Status)) {\r
+    ShellPrintHiiEx (\r
+      -1, -1, NULL,\r
+      STRING_TOKEN (STR_SETFDT_UPDATE_SUCCEEDED),\r
+      mFdtPlatformDxeHiiHandle,\r
+      FdtVariableValue\r
+      );\r
+  } else {\r
+    if (Status == EFI_INVALID_PARAMETER) {\r
+      ShellPrintHiiEx (\r
+        -1, -1, NULL,\r
+        STRING_TOKEN (STR_SETFDT_INVALID_PATH),\r
+        mFdtPlatformDxeHiiHandle,\r
+        FilePath\r
+        );\r
+    } else {\r
+      ShellPrintHiiEx (\r
+        -1, -1, NULL,\r
+        STRING_TOKEN (STR_SETFDT_ERROR),\r
+        mFdtPlatformDxeHiiHandle,\r
+        Status\r
+        );\r
+    }\r
+  }\r
+\r
+  if (DevicePath != NULL) {\r
+    FreePool (DevicePath);\r
+  }\r
+  if (TextDevicePath != NULL) {\r
+    FreePool (TextDevicePath);\r
+  }\r
+\r
+  return ShellStatus;\r
+}\r
+\r
+/**\r
+  Transcode one of the EFI return code used by the model into an EFI Shell return code.\r
+\r
+  @param[in]  Status  EFI return code.\r
+\r
+  @return  Transcoded EFI Shell return code.\r
+\r
+**/\r
+STATIC\r
+SHELL_STATUS\r
+EfiCodeToShellCode (\r
+  IN EFI_STATUS  Status\r
+  )\r
+{\r
+  SHELL_STATUS  ShellStatus;\r
+\r
+  switch (Status) {\r
+  case EFI_SUCCESS :\r
+    ShellStatus = SHELL_SUCCESS;\r
+    break;\r
+\r
+  case EFI_INVALID_PARAMETER :\r
+    ShellStatus = SHELL_INVALID_PARAMETER;\r
+    break;\r
+\r
+  case EFI_UNSUPPORTED :\r
+    ShellStatus = SHELL_UNSUPPORTED;\r
+    break;\r
+\r
+  case EFI_DEVICE_ERROR :\r
+    ShellStatus = SHELL_DEVICE_ERROR;\r
+    break;\r
+\r
+  case EFI_WRITE_PROTECTED    :\r
+  case EFI_SECURITY_VIOLATION :\r
+    ShellStatus = SHELL_ACCESS_DENIED;\r
+    break;\r
+\r
+  case EFI_OUT_OF_RESOURCES :\r
+    ShellStatus = SHELL_OUT_OF_RESOURCES;\r
+    break;\r
+\r
+  case EFI_NOT_FOUND :\r
+    ShellStatus = SHELL_NOT_FOUND;\r
+    break;\r
+\r
+  default :\r
+    ShellStatus = SHELL_ABORTED;\r
+  }\r
+\r
+  return ShellStatus;\r
+}\r
+>>>>>>> 4ac4fed... EmbeddedPkg/FdtPlatformDxe: Fix typo issue\r
diff --git a/EmbeddedPkg/Drivers/FdtPlatformDxe/FdtPlatformDxe.inf b/EmbeddedPkg/Drivers/FdtPlatformDxe/FdtPlatformDxe.inf
new file mode 100644 (file)
index 0000000..ea45baa
--- /dev/null
@@ -0,0 +1,55 @@
+#/** @file\r
+#\r
+#  Copyright (c) 2015, ARM Ltd. All rights reserved.<BR>\r
+#\r
+#  This program and the accompanying materials\r
+#  are licensed and made available under the terms and conditions of the BSD License\r
+#  which accompanies this distribution.  The full text of the license may be found at\r
+#  http://opensource.org/licenses/bsd-license.php\r
+#\r
+#  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+#  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+#\r
+#**/\r
+\r
+[Defines]\r
+  INF_VERSION     = 0x00010006\r
+  BASE_NAME       = FdtPlatformDxe\r
+  FILE_GUID       = 6e9a4c69-57c6-4fcd-b083-4f2c3bdb6051\r
+  MODULE_TYPE     = DXE_DRIVER\r
+  VERSION_STRING  = 0.1\r
+  ENTRY_POINT     = FdtPlatformEntryPoint\r
+\r
+[Sources.common]\r
+  FdtPlatform.c\r
+\r
+[Packages]\r
+  EmbeddedPkg/EmbeddedPkg.dec\r
+  ArmPkg/ArmPkg.dec\r
+  MdePkg/MdePkg.dec\r
+\r
+[LibraryClasses]\r
+  UefiDriverEntryPoint\r
+  BdsLib\r
+  DxeServicesTableLib\r
+  BaseMemoryLib\r
+  DebugLib\r
+  UefiBootServicesTableLib\r
+  UefiRuntimeServicesTableLib\r
+\r
+[Protocols]\r
+  gEfiDevicePathFromTextProtocolGuid\r
+\r
+[Guids]\r
+  gEfiEndOfDxeEventGroupGuid\r
+  gFdtTableGuid\r
+  gFdtVariableGuid\r
+\r
+[FeaturePcd]\r
+  gEmbeddedTokenSpaceGuid.PcdOverridePlatformFdt\r
+\r
+[Pcd]\r
+  gEmbeddedTokenSpaceGuid.PcdFdtDevicePaths\r
+\r
+[Depex]\r
+  TRUE\r
diff --git a/EmbeddedPkg/Drivers/FdtPlatformDxe/README.txt b/EmbeddedPkg/Drivers/FdtPlatformDxe/README.txt
new file mode 100644 (file)
index 0000000..bf61e66
--- /dev/null
@@ -0,0 +1,50 @@
+/** @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
+"gEmbeddedTokenSpaceGuid.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 "gEmbeddedTokenSpaceGuid.
+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.
index 600d0e5..1a498d2 100644 (file)
@@ -52,6 +52,7 @@
   ## FDT Configuration Table\r
   # Include/Guid/Fdt.h\r
   gFdtTableGuid = { 0xb1b621d5, 0xf19c, 0x41a5, { 0x83, 0x0b, 0xd9, 0x15, 0x2c, 0x69, 0xaa, 0xe0 } }\r
+  gFdtVariableGuid = { 0x25a4fd4a, 0x9703, 0x4ba9, { 0xa1, 0x90, 0xb7, 0xc8, 0x4e, 0xfb, 0x3e, 0x57 } }\r
 \r
 [Protocols.common]\r
   gHardwareInterruptProtocolGuid =  { 0x2890B3EA, 0x053D, 0x1643, { 0xAD, 0x0C, 0xD6, 0x48, 0x08, 0xDA, 0x3F, 0xF1 } }\r
@@ -79,6 +80,7 @@
   gEmbeddedTokenSpaceGuid.PcdPrePiProduceMemoryTypeInformationHob|FALSE|BOOLEAN|0x0000001b\r
   gEmbeddedTokenSpaceGuid.PcdCacheEnable|FALSE|BOOLEAN|0x00000042\r
   gEmbeddedTokenSpaceGuid.PcdGdbSerial|FALSE|BOOLEAN|0x00000053\r
+  gEmbeddedTokenSpaceGuid.PcdOverridePlatformFdt|TRUE|BOOLEAN|0x00000054\r
 \r
 \r
 [PcdsFixedAtBuild.common]\r
   gEmbeddedTokenSpaceGuid.PcdAndroidFastbootUsbProductId|0xbeef|UINT32|0x00000023\r
   gEmbeddedTokenSpaceGuid.PcdAndroidFastbootTcpPort|1234|UINT32|0x00000024\r
 \r
+\r
 [PcdsFixedAtBuild.ARM]\r
   gEmbeddedTokenSpaceGuid.PcdPrePiCpuMemorySize|32|UINT8|0x00000010\r
   gEmbeddedTokenSpaceGuid.PcdPrePiCpuIoSize|0|UINT8|0x00000011\r
 [PcdsFixedAtBuild.X64]\r
   gEmbeddedTokenSpaceGuid.PcdPrePiCpuMemorySize|52|UINT8|0x00000010\r
   gEmbeddedTokenSpaceGuid.PcdPrePiCpuIoSize|16|UINT8|0x00000011\r
+\r
+[PcdsFixedAtBuild.common, PcdsDynamic.common]\r
+  gEmbeddedTokenSpaceGuid.PcdFdtDevicePaths|L""|VOID*|0x00000055\r
index a3a136d..8a58b9b 100644 (file)
 \r
   EmbeddedPkg/Universal/MmcDxe/MmcDxe.inf\r
 \r
-  # FDT Support\r
+  # FDT installation\r
   EmbeddedPkg/Library/FdtLoadLib/FdtLoadLib.inf\r
+  EmbeddedPkg/Drivers/FdtPlatformDxe/FdtPlatformDxe.inf\r
 \r
   EmbeddedPkg/Application/AndroidFastboot/AndroidFastbootApp.inf\r
   EmbeddedPkg/Drivers/AndroidFastbootTransportUsbDxe/FastbootTransportUsbDxe.inf\r
index f2397ff..74c85dc 100644 (file)
 *\r
 **/\r
 \r
-#ifndef __FDT_GUID_H__\r
-#define __FDT_GUID_H__\r
+#ifndef __FDT_H__\r
+#define __FDT_H__\r
 \r
 #define FDT_TABLE_GUID \\r
   { 0xb1b621d5, 0xf19c, 0x41a5, { 0x83, 0x0b, 0xd9, 0x15, 0x2c, 0x69, 0xaa, 0xe0 } }\r
 \r
 extern EFI_GUID gFdtTableGuid;\r
 \r
-#endif /* __FDT_GUID_H__ */\r
+#define FDT_VARIABLE_GUID \\r
+  { 0x25a4fd4a, 0x9703, 0x4ba9, { 0xa1, 0x90, 0xb7, 0xc8, 0x4e, 0xfb, 0x3e, 0x57 } }\r
+\r
+extern EFI_GUID gFdtVariableGuid;\r
+\r
+#endif /* __FDT_H__ */\r