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
 | 
						|
                );
 | 
						|
}
 |