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
		
			
				
	
	
		
			280 lines
		
	
	
		
			7.1 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			280 lines
		
	
	
		
			7.1 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /** @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
 | |
|                 );
 | |
| }
 |