1/** @file
2
3  Copyright (c) 2015, ARM Ltd. All rights reserved.<BR>
4
5  This program and the accompanying materials
6  are licensed and made available under the terms and conditions of the BSD License
7  which accompanies this distribution.  The full text of the license may be found at
8  http://opensource.org/licenses/bsd-license.php
9
10  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12
13**/
14
15#include "FdtPlatform.h"
16
17#define ALIGN(x, a)     (((x) + ((a) - 1)) & ~((a) - 1))
18#define PALIGN(p, a)    ((void *)(ALIGN ((unsigned long)(p), (a))))
19#define GET_CELL(p)     (p += 4, *((const uint32_t *)(p-4)))
20
21STATIC
22UINTN
23IsPrintableString (
24  IN CONST VOID* data,
25  IN UINTN len
26  )
27{
28  CONST CHAR8 *s = data;
29  CONST CHAR8 *ss;
30
31  // Zero length is not
32  if (len == 0) {
33    return 0;
34  }
35
36  // Must terminate with zero
37  if (s[len - 1] != '\0') {
38    return 0;
39  }
40
41  ss = s;
42  while (*s/* && isprint (*s)*/) {
43    s++;
44  }
45
46  // Not zero, or not done yet
47  if (*s != '\0' || (s + 1 - ss) < len) {
48    return 0;
49  }
50
51  return 1;
52}
53
54STATIC
55VOID
56PrintData (
57  IN CONST CHAR8* data,
58  IN UINTN len
59  )
60{
61  UINTN i;
62  CONST CHAR8 *p = data;
63
64  // No data, don't print
65  if (len == 0)
66    return;
67
68  if (IsPrintableString (data, len)) {
69    Print (L" = \"%a\"", (const char *)data);
70  } else if ((len % 4) == 0) {
71    Print (L" = <");
72    for (i = 0; i < len; i += 4) {
73      Print (L"0x%08x%a", fdt32_to_cpu (GET_CELL (p)), i < (len - 4) ? " " : "");
74    }
75    Print (L">");
76  } else {
77    Print (L" = [");
78    for (i = 0; i < len; i++)
79      Print (L"%02x%a", *p++, i < len - 1 ? " " : "");
80    Print (L"]");
81  }
82}
83
84STATIC
85VOID
86DumpFdt (
87  IN VOID*                FdtBlob
88  )
89{
90  struct fdt_header *bph;
91  UINT32 off_dt;
92  UINT32 off_str;
93  CONST CHAR8* p_struct;
94  CONST CHAR8* p_strings;
95  CONST CHAR8* p;
96  CONST CHAR8* s;
97  CONST CHAR8* t;
98  UINT32 tag;
99  UINTN sz;
100  UINTN depth;
101  UINTN shift;
102  UINT32 version;
103
104  {
105    // Can 'memreserve' be printed by below code?
106    INTN num = fdt_num_mem_rsv (FdtBlob);
107    INTN i, err;
108    UINT64 addr = 0, size = 0;
109
110    for (i = 0; i < num; i++) {
111      err = fdt_get_mem_rsv (FdtBlob, i, &addr, &size);
112      if (err) {
113        DEBUG ((EFI_D_ERROR, "Error (%d) : Cannot get memreserve section (%d)\n", err, i));
114      }
115      else {
116        Print (L"/memreserve/ \t0x%lx \t0x%lx;\n", addr, size);
117      }
118    }
119  }
120
121  depth = 0;
122  shift = 4;
123
124  bph = FdtBlob;
125  off_dt = fdt32_to_cpu (bph->off_dt_struct);
126  off_str = fdt32_to_cpu (bph->off_dt_strings);
127  p_struct = (CONST CHAR8*)FdtBlob + off_dt;
128  p_strings = (CONST CHAR8*)FdtBlob + off_str;
129  version = fdt32_to_cpu (bph->version);
130
131  p = p_struct;
132  while ((tag = fdt32_to_cpu (GET_CELL (p))) != FDT_END) {
133    if (tag == FDT_BEGIN_NODE) {
134      s = p;
135      p = PALIGN (p + AsciiStrLen (s) + 1, 4);
136
137      if (*s == '\0')
138              s = "/";
139
140      Print (L"%*s%a {\n", depth * shift, L" ", s);
141
142      depth++;
143      continue;
144    }
145
146    if (tag == FDT_END_NODE) {
147      depth--;
148
149      Print (L"%*s};\n", depth * shift, L" ");
150      continue;
151    }
152
153    if (tag == FDT_NOP) {
154      Print (L"%*s// [NOP]\n", depth * shift, L" ");
155      continue;
156    }
157
158    if (tag != FDT_PROP) {
159      Print (L"%*s ** Unknown tag 0x%08x\n", depth * shift, L" ", tag);
160      break;
161    }
162    sz = fdt32_to_cpu (GET_CELL (p));
163    s = p_strings + fdt32_to_cpu (GET_CELL (p));
164    if (version < 16 && sz >= 8)
165            p = PALIGN (p, 8);
166    t = p;
167
168    p = PALIGN (p + sz, 4);
169
170    Print (L"%*s%a", depth * shift, L" ", s);
171    PrintData (t, sz);
172    Print (L";\n");
173  }
174}
175
176/**
177  This is the shell command "dumpfdt" handler function. This function handles
178  the command when it is invoked in the shell.
179
180  @param[in]  This             The instance of the
181                               EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL.
182  @param[in]  SystemTable      The pointer to the UEFI system table.
183  @param[in]  ShellParameters  The parameters associated with the command.
184  @param[in]  Shell            The instance of the shell protocol used in the
185                               context of processing this command.
186
187  @return  SHELL_SUCCESS            The operation was successful.
188  @return  SHELL_ABORTED            Operation aborted due to internal error.
189  @return  SHELL_NOT_FOUND          Failed to locate the Device Tree into the EFI Configuration Table
190  @return  SHELL_OUT_OF_RESOURCES   A memory allocation failed.
191
192**/
193SHELL_STATUS
194EFIAPI
195ShellDynCmdDumpFdtHandler (
196  IN EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL  *This,
197  IN EFI_SYSTEM_TABLE                    *SystemTable,
198  IN EFI_SHELL_PARAMETERS_PROTOCOL       *ShellParameters,
199  IN EFI_SHELL_PROTOCOL                  *Shell
200  )
201{
202  SHELL_STATUS  ShellStatus;
203  EFI_STATUS    Status;
204  VOID          *FdtBlob;
205
206  ShellStatus  = SHELL_SUCCESS;
207
208  //
209  // Install the Shell and Shell Parameters Protocols on the driver
210  // image. This is necessary for the initialisation of the Shell
211  // Library to succeed in the next step.
212  //
213  Status = gBS->InstallMultipleProtocolInterfaces (
214                  &gImageHandle,
215                  &gEfiShellProtocolGuid, Shell,
216                  &gEfiShellParametersProtocolGuid, ShellParameters,
217                  NULL
218                  );
219  if (EFI_ERROR (Status)) {
220    return SHELL_ABORTED;
221  }
222
223  //
224  // Initialise the Shell Library as we are going to use it.
225  // Assert that the return code is EFI_SUCCESS as it should.
226  // To anticipate any change is the codes returned by
227  // ShellInitialize(), leave in case of error.
228  //
229  Status = ShellInitialize ();
230  if (EFI_ERROR (Status)) {
231    ASSERT_EFI_ERROR (Status);
232    return SHELL_ABORTED;
233  }
234
235  Status = EfiGetSystemConfigurationTable (&gFdtTableGuid, &FdtBlob);
236  if (EFI_ERROR (Status)) {
237    Print (L"ERROR: Did not find the Fdt Blob.\n");
238    return EfiCodeToShellCode (Status);
239  }
240
241  DumpFdt (FdtBlob);
242
243  gBS->UninstallMultipleProtocolInterfaces (
244         gImageHandle,
245         &gEfiShellProtocolGuid, Shell,
246         &gEfiShellParametersProtocolGuid, ShellParameters,
247         NULL
248         );
249
250  return ShellStatus;
251}
252
253/**
254  This is the shell command "dumpfdt" help handler function. This
255  function returns the formatted help for the "dumpfdt" command.
256  The format matchs that in Appendix B of the revision 2.1 of the
257  UEFI Shell Specification.
258
259  @param[in]  This      The instance of the EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL.
260  @param[in]  Language  The pointer to the language string to use.
261
262  @return  CHAR16*  Pool allocated help string, must be freed by caller.
263**/
264CHAR16*
265EFIAPI
266ShellDynCmdDumpFdtGetHelp (
267  IN EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL  *This,
268  IN CONST CHAR8                         *Language
269  )
270{
271  //
272  // This allocates memory. The caller has to free the allocated memory.
273  //
274  return HiiGetString (
275                mFdtPlatformDxeHiiHandle,
276                STRING_TOKEN (STR_GET_HELP_DUMPFDT),
277                Language
278                );
279}
280