EmbeddedPkg/FdtPlatformDxe: Introduce EFI Shell command 'dumfdt'
authorOlivier Martin <olivier.martin@arm.com>
Tue, 5 May 2015 15:31:11 +0000 (15:31 +0000)
committeroliviermartin <oliviermartin@Edk2>
Tue, 5 May 2015 15:31:11 +0000 (15:31 +0000)
This command dumps the Flat Device Tree currently installed
in the EFI Configuration Table.

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

EmbeddedPkg/Drivers/FdtPlatformDxe/FdtPlatform.c
EmbeddedPkg/Drivers/FdtPlatformDxe/FdtPlatform.h
EmbeddedPkg/Drivers/FdtPlatformDxe/FdtPlatformDxe.inf
EmbeddedPkg/Drivers/FdtPlatformDxe/ShellDumpFdt.c [new file with mode: 0644]
EmbeddedPkg/EmbeddedPkg.dec

index 38f31005f3a59d790a23f9828fa823f5d079d98a..b6f5c3e58d3ae1e20b2e5d0d2e932419f4bc01ba 100644 (file)
@@ -20,8 +20,6 @@
 \r
 #include <Protocol/DevicePath.h>\r
 \r
-#include <libfdt.h>\r
-\r
 //\r
 // Internal variables\r
 //\r
@@ -32,6 +30,12 @@ STATIC CONST EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL mShellDynCmdProtocolSetFdt = {
     ShellDynCmdSetFdtGetHelp  // GetHelp\r
 };\r
 \r
+STATIC CONST EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL mShellDynCmdProtocolDumpFdt = {\r
+    L"dumpfdt",                // Name of the command\r
+    ShellDynCmdDumpFdtHandler, // Handler\r
+    ShellDynCmdDumpFdtGetHelp  // GetHelp\r
+};\r
+\r
 STATIC CONST EFI_GUID  mFdtPlatformDxeHiiGuid = {\r
                          0x8afa7610, 0x62b1, 0x46aa,\r
                          {0xb5, 0x34, 0xc3, 0xde, 0xff, 0x39, 0x77, 0x8c}\r
@@ -159,6 +163,7 @@ FdtPlatformEntryPoint (
   )\r
 {\r
   EFI_STATUS  Status;\r
+  EFI_HANDLE  Handle;\r
 \r
   //\r
   // Install the Device Tree from its expected location\r
@@ -168,14 +173,7 @@ FdtPlatformEntryPoint (
     return Status;\r
   }\r
 \r
-  //\r
-  // If the development features are enabled, install the dynamic shell\r
-  // command "setfdt" to be able to define a device path for the FDT\r
-  // that has precedence over the device paths defined by\r
-  // "PcdFdtDevicePaths".\r
-  //\r
-\r
-  if (FeaturePcdGet (PcdOverridePlatformFdt)) {\r
+  if (FeaturePcdGet (PcdOverridePlatformFdt) || FeaturePcdGet (PcdDumpFdtShellCommand)) {\r
     //\r
     // Register the strings for the user interface in the HII Database.\r
     // This shows the way to the multi-language support, even if\r
@@ -192,10 +190,22 @@ FdtPlatformEntryPoint (
                                  FdtPlatformDxeStrings,\r
                                  NULL\r
                                  );\r
+  }\r
+\r
+  //\r
+  // If the development features are enabled, install the dynamic shell\r
+  // command "setfdt" to be able to define a device path for the FDT\r
+  // that has precedence over the device paths defined by\r
+  // "PcdFdtDevicePaths".\r
+  //\r
 \r
+  if (FeaturePcdGet (PcdOverridePlatformFdt)) {\r
     if (mFdtPlatformDxeHiiHandle != NULL) {\r
+      // We install dynamic EFI command on separate handles as we cannot register\r
+      // more than one protocol of the same protocol interface on the same handle.\r
+      Handle = NULL;\r
       Status = gBS->InstallMultipleProtocolInterfaces (\r
-                      &ImageHandle,\r
+                      &Handle,\r
                       &gEfiShellDynamicCommandProtocolGuid,\r
                       &mShellDynCmdProtocolSetFdt,\r
                       NULL\r
@@ -215,6 +225,32 @@ FdtPlatformEntryPoint (
     }\r
   }\r
 \r
+  if (FeaturePcdGet (PcdDumpFdtShellCommand)) {\r
+    if (mFdtPlatformDxeHiiHandle != NULL) {\r
+      // We install dynamic EFI command on separate handles as we cannot register\r
+      // more than one protocol of the same protocol interface on the same handle.\r
+      Handle = NULL;\r
+      Status = gBS->InstallMultipleProtocolInterfaces (\r
+                      &Handle,\r
+                      &gEfiShellDynamicCommandProtocolGuid,\r
+                      &mShellDynCmdProtocolDumpFdt,\r
+                      NULL\r
+                      );\r
+      if (EFI_ERROR (Status)) {\r
+        HiiRemovePackages (mFdtPlatformDxeHiiHandle);\r
+      }\r
+    } else {\r
+      Status = EFI_LOAD_ERROR;\r
+    }\r
+    if (EFI_ERROR (Status)) {\r
+      DEBUG ((\r
+        EFI_D_WARN,\r
+        "Unable to install \"dumpfdt\" EFI Shell command - %r \n",\r
+        Status\r
+        ));\r
+    }\r
+  }\r
+\r
   return Status;\r
 }\r
 \r
index 297927aaacf998ee76fc08675f423ab82d0bab9d..d49dd42c00be1990e142e9c7eba7b69795ebb219 100644 (file)
@@ -127,4 +127,48 @@ ShellDynCmdSetFdtGetHelp (
   IN CONST CHAR8                         *Language\r
   );\r
 \r
+/**\r
+  This is the shell command "dumpfdt" 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_NOT_FOUND          Failed to locate the Device Tree into the EFI Configuration Table\r
+  @return  SHELL_OUT_OF_RESOURCES   A memory allocation failed.\r
+\r
+**/\r
+SHELL_STATUS\r
+EFIAPI\r
+ShellDynCmdDumpFdtHandler (\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
+/**\r
+  This is the shell command "dumpfdt" help handler function. This\r
+  function returns the formatted help for the "dumpfdt" 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
+CHAR16*\r
+EFIAPI\r
+ShellDynCmdDumpFdtGetHelp (\r
+  IN EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL  *This,\r
+  IN CONST CHAR8                         *Language\r
+  );\r
+\r
 #endif /* __FDT_PLATFORM_DXE_H__ */\r
index 3558958f841c7e13a9881c65aa5c386cfe401820..b95f1d6eab8be2e598034de34ea943d71848c6e1 100644 (file)
@@ -24,6 +24,7 @@
 [Sources.common]\r
   FdtPlatform.c\r
   FdtPlatformDxe.uni\r
+  ShellDumpFdt.c\r
   ShellSetFdt.c\r
 \r
 [Packages]\r
@@ -56,6 +57,7 @@
 \r
 [FeaturePcd]\r
   gEmbeddedTokenSpaceGuid.PcdOverridePlatformFdt\r
+  gEmbeddedTokenSpaceGuid.PcdDumpFdtShellCommand\r
 \r
 [Pcd]\r
   gEmbeddedTokenSpaceGuid.PcdFdtDevicePaths\r
diff --git a/EmbeddedPkg/Drivers/FdtPlatformDxe/ShellDumpFdt.c b/EmbeddedPkg/Drivers/FdtPlatformDxe/ShellDumpFdt.c
new file mode 100644 (file)
index 0000000..c7dc898
--- /dev/null
@@ -0,0 +1,279 @@
+/** @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
+#include "FdtPlatform.h"\r
+\r
+#define ALIGN(x, a)     (((x) + ((a) - 1)) & ~((a) - 1))\r
+#define PALIGN(p, a)    ((void *)(ALIGN ((unsigned long)(p), (a))))\r
+#define GET_CELL(p)     (p += 4, *((const uint32_t *)(p-4)))\r
+\r
+STATIC\r
+UINTN\r
+IsPrintableString (\r
+  IN CONST VOID* data,\r
+  IN UINTN len\r
+  )\r
+{\r
+  CONST CHAR8 *s = data;\r
+  CONST CHAR8 *ss;\r
+\r
+  // Zero length is not\r
+  if (len == 0) {\r
+    return 0;\r
+  }\r
+\r
+  // Must terminate with zero\r
+  if (s[len - 1] != '\0') {\r
+    return 0;\r
+  }\r
+\r
+  ss = s;\r
+  while (*s/* && isprint (*s)*/) {\r
+    s++;\r
+  }\r
+\r
+  // Not zero, or not done yet\r
+  if (*s != '\0' || (s + 1 - ss) < len) {\r
+    return 0;\r
+  }\r
+\r
+  return 1;\r
+}\r
+\r
+STATIC\r
+VOID\r
+PrintData (\r
+  IN CONST CHAR8* data,\r
+  IN UINTN len\r
+  )\r
+{\r
+  UINTN i;\r
+  CONST CHAR8 *p = data;\r
+\r
+  // No data, don't print\r
+  if (len == 0)\r
+    return;\r
+\r
+  if (IsPrintableString (data, len)) {\r
+    Print (L" = \"%a\"", (const char *)data);\r
+  } else if ((len % 4) == 0) {\r
+    Print (L" = <");\r
+    for (i = 0; i < len; i += 4) {\r
+      Print (L"0x%08x%a", fdt32_to_cpu (GET_CELL (p)), i < (len - 4) ? " " : "");\r
+    }\r
+    Print (L">");\r
+  } else {\r
+    Print (L" = [");\r
+    for (i = 0; i < len; i++)\r
+      Print (L"%02x%a", *p++, i < len - 1 ? " " : "");\r
+    Print (L"]");\r
+  }\r
+}\r
+\r
+STATIC\r
+VOID\r
+DumpFdt (\r
+  IN VOID*                FdtBlob\r
+  )\r
+{\r
+  struct fdt_header *bph;\r
+  UINT32 off_dt;\r
+  UINT32 off_str;\r
+  CONST CHAR8* p_struct;\r
+  CONST CHAR8* p_strings;\r
+  CONST CHAR8* p;\r
+  CONST CHAR8* s;\r
+  CONST CHAR8* t;\r
+  UINT32 tag;\r
+  UINTN sz;\r
+  UINTN depth;\r
+  UINTN shift;\r
+  UINT32 version;\r
+\r
+  {\r
+    // Can 'memreserve' be printed by below code?\r
+    INTN num = fdt_num_mem_rsv (FdtBlob);\r
+    INTN i, err;\r
+    UINT64 addr = 0, size = 0;\r
+\r
+    for (i = 0; i < num; i++) {\r
+      err = fdt_get_mem_rsv (FdtBlob, i, &addr, &size);\r
+      if (err) {\r
+        DEBUG ((EFI_D_ERROR, "Error (%d) : Cannot get memreserve section (%d)\n", err, i));\r
+      }\r
+      else {\r
+        Print (L"/memreserve/ \t0x%lx \t0x%lx;\n", addr, size);\r
+      }\r
+    }\r
+  }\r
+\r
+  depth = 0;\r
+  shift = 4;\r
+\r
+  bph = FdtBlob;\r
+  off_dt = fdt32_to_cpu (bph->off_dt_struct);\r
+  off_str = fdt32_to_cpu (bph->off_dt_strings);\r
+  p_struct = (CONST CHAR8*)FdtBlob + off_dt;\r
+  p_strings = (CONST CHAR8*)FdtBlob + off_str;\r
+  version = fdt32_to_cpu (bph->version);\r
+\r
+  p = p_struct;\r
+  while ((tag = fdt32_to_cpu (GET_CELL (p))) != FDT_END) {\r
+    if (tag == FDT_BEGIN_NODE) {\r
+      s = p;\r
+      p = PALIGN (p + AsciiStrLen (s) + 1, 4);\r
+\r
+      if (*s == '\0')\r
+              s = "/";\r
+\r
+      Print (L"%*s%a {\n", depth * shift, L" ", s);\r
+\r
+      depth++;\r
+      continue;\r
+    }\r
+\r
+    if (tag == FDT_END_NODE) {\r
+      depth--;\r
+\r
+      Print (L"%*s};\n", depth * shift, L" ");\r
+      continue;\r
+    }\r
+\r
+    if (tag == FDT_NOP) {\r
+      Print (L"%*s// [NOP]\n", depth * shift, L" ");\r
+      continue;\r
+    }\r
+\r
+    if (tag != FDT_PROP) {\r
+      Print (L"%*s ** Unknown tag 0x%08x\n", depth * shift, L" ", tag);\r
+      break;\r
+    }\r
+    sz = fdt32_to_cpu (GET_CELL (p));\r
+    s = p_strings + fdt32_to_cpu (GET_CELL (p));\r
+    if (version < 16 && sz >= 8)\r
+            p = PALIGN (p, 8);\r
+    t = p;\r
+\r
+    p = PALIGN (p + sz, 4);\r
+\r
+    Print (L"%*s%a", depth * shift, L" ", s);\r
+    PrintData (t, sz);\r
+    Print (L";\n");\r
+  }\r
+}\r
+\r
+/**\r
+  This is the shell command "dumpfdt" 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_NOT_FOUND          Failed to locate the Device Tree into the EFI Configuration Table\r
+  @return  SHELL_OUT_OF_RESOURCES   A memory allocation failed.\r
+\r
+**/\r
+SHELL_STATUS\r
+EFIAPI\r
+ShellDynCmdDumpFdtHandler (\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
+  VOID          *FdtBlob;\r
+\r
+  ShellStatus  = SHELL_SUCCESS;\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 = EfiGetSystemConfigurationTable (&gFdtTableGuid, &FdtBlob);\r
+  if (EFI_ERROR (Status)) {\r
+    Print (L"ERROR: Did not find the Fdt Blob.\n");\r
+    return EfiCodeToShellCode (Status);\r
+  }\r
+\r
+  DumpFdt (FdtBlob);\r
+\r
+  gBS->UninstallMultipleProtocolInterfaces (\r
+         gImageHandle,\r
+         &gEfiShellProtocolGuid, Shell,\r
+         &gEfiShellParametersProtocolGuid, ShellParameters,\r
+         NULL\r
+         );\r
+\r
+  return ShellStatus;\r
+}\r
+\r
+/**\r
+  This is the shell command "dumpfdt" help handler function. This\r
+  function returns the formatted help for the "dumpfdt" 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
+CHAR16*\r
+EFIAPI\r
+ShellDynCmdDumpFdtGetHelp (\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_DUMPFDT),\r
+                Language\r
+                );\r
+}\r
index 1acfd4e5c10b254607f93b692c365c4aa40b5137..6e6e95449ab6235bde5ede9d6298b65cc19f3e8b 100644 (file)
   gEmbeddedTokenSpaceGuid.PcdPrePiProduceMemoryTypeInformationHob|FALSE|BOOLEAN|0x0000001b\r
   gEmbeddedTokenSpaceGuid.PcdCacheEnable|FALSE|BOOLEAN|0x00000042\r
   gEmbeddedTokenSpaceGuid.PcdGdbSerial|FALSE|BOOLEAN|0x00000053\r
+  # Enable the development specific features\r
   gEmbeddedTokenSpaceGuid.PcdOverridePlatformFdt|TRUE|BOOLEAN|0x00000054\r
+  # Add 'dumpfdt' EFI Shell command\r
+  gEmbeddedTokenSpaceGuid.PcdDumpFdtShellCommand|TRUE|BOOLEAN|0x00000056\r
 \r
 \r
 [PcdsFixedAtBuild.common]\r