From b0866ad398ba5034ddd298b7d5d7b1fff752d19a Mon Sep 17 00:00:00 2001 From: Olivier Martin Date: Tue, 5 May 2015 15:31:11 +0000 Subject: [PATCH] EmbeddedPkg/FdtPlatformDxe: Introduce EFI Shell command 'dumfdt' 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 Reviewed-by: Ronald Cron git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@17303 6f19259b-4bc3-4df7-8a09-765794883524 --- .../Drivers/FdtPlatformDxe/FdtPlatform.c | 58 +++- .../Drivers/FdtPlatformDxe/FdtPlatform.h | 44 +++ .../Drivers/FdtPlatformDxe/FdtPlatformDxe.inf | 2 + .../Drivers/FdtPlatformDxe/ShellDumpFdt.c | 279 ++++++++++++++++++ EmbeddedPkg/EmbeddedPkg.dec | 3 + 5 files changed, 375 insertions(+), 11 deletions(-) create mode 100644 EmbeddedPkg/Drivers/FdtPlatformDxe/ShellDumpFdt.c diff --git a/EmbeddedPkg/Drivers/FdtPlatformDxe/FdtPlatform.c b/EmbeddedPkg/Drivers/FdtPlatformDxe/FdtPlatform.c index 38f31005f3..b6f5c3e58d 100644 --- a/EmbeddedPkg/Drivers/FdtPlatformDxe/FdtPlatform.c +++ b/EmbeddedPkg/Drivers/FdtPlatformDxe/FdtPlatform.c @@ -20,8 +20,6 @@ #include -#include - // // Internal variables // @@ -32,6 +30,12 @@ STATIC CONST EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL mShellDynCmdProtocolSetFdt = { 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} @@ -159,6 +163,7 @@ FdtPlatformEntryPoint ( ) { EFI_STATUS Status; + EFI_HANDLE Handle; // // Install the Device Tree from its expected location @@ -168,14 +173,7 @@ FdtPlatformEntryPoint ( return Status; } - // - // 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 (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 @@ -192,10 +190,22 @@ FdtPlatformEntryPoint ( 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 ( - &ImageHandle, + &Handle, &gEfiShellDynamicCommandProtocolGuid, &mShellDynCmdProtocolSetFdt, NULL @@ -215,6 +225,32 @@ FdtPlatformEntryPoint ( } } + 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; } diff --git a/EmbeddedPkg/Drivers/FdtPlatformDxe/FdtPlatform.h b/EmbeddedPkg/Drivers/FdtPlatformDxe/FdtPlatform.h index 297927aaac..d49dd42c00 100644 --- a/EmbeddedPkg/Drivers/FdtPlatformDxe/FdtPlatform.h +++ b/EmbeddedPkg/Drivers/FdtPlatformDxe/FdtPlatform.h @@ -127,4 +127,48 @@ ShellDynCmdSetFdtGetHelp ( 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/EmbeddedPkg/Drivers/FdtPlatformDxe/FdtPlatformDxe.inf b/EmbeddedPkg/Drivers/FdtPlatformDxe/FdtPlatformDxe.inf index 3558958f84..b95f1d6eab 100644 --- a/EmbeddedPkg/Drivers/FdtPlatformDxe/FdtPlatformDxe.inf +++ b/EmbeddedPkg/Drivers/FdtPlatformDxe/FdtPlatformDxe.inf @@ -24,6 +24,7 @@ [Sources.common] FdtPlatform.c FdtPlatformDxe.uni + ShellDumpFdt.c ShellSetFdt.c [Packages] @@ -56,6 +57,7 @@ [FeaturePcd] gEmbeddedTokenSpaceGuid.PcdOverridePlatformFdt + gEmbeddedTokenSpaceGuid.PcdDumpFdtShellCommand [Pcd] gEmbeddedTokenSpaceGuid.PcdFdtDevicePaths diff --git a/EmbeddedPkg/Drivers/FdtPlatformDxe/ShellDumpFdt.c b/EmbeddedPkg/Drivers/FdtPlatformDxe/ShellDumpFdt.c new file mode 100644 index 0000000000..c7dc898568 --- /dev/null +++ b/EmbeddedPkg/Drivers/FdtPlatformDxe/ShellDumpFdt.c @@ -0,0 +1,279 @@ +/** @file + + Copyright (c) 2015, ARM Ltd. All rights reserved.
+ + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "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/EmbeddedPkg/EmbeddedPkg.dec b/EmbeddedPkg/EmbeddedPkg.dec index 1acfd4e5c1..6e6e95449a 100644 --- a/EmbeddedPkg/EmbeddedPkg.dec +++ b/EmbeddedPkg/EmbeddedPkg.dec @@ -82,7 +82,10 @@ gEmbeddedTokenSpaceGuid.PcdPrePiProduceMemoryTypeInformationHob|FALSE|BOOLEAN|0x0000001b gEmbeddedTokenSpaceGuid.PcdCacheEnable|FALSE|BOOLEAN|0x00000042 gEmbeddedTokenSpaceGuid.PcdGdbSerial|FALSE|BOOLEAN|0x00000053 + # Enable the development specific features gEmbeddedTokenSpaceGuid.PcdOverridePlatformFdt|TRUE|BOOLEAN|0x00000054 + # Add 'dumpfdt' EFI Shell command + gEmbeddedTokenSpaceGuid.PcdDumpFdtShellCommand|TRUE|BOOLEAN|0x00000056 [PcdsFixedAtBuild.common] -- 2.39.2