| /** @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 | |
| ); | |
| } |