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 
21 STATIC
22 UINTN
IsPrintableString(IN CONST VOID * data,IN UINTN len)23 IsPrintableString (
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 
54 STATIC
55 VOID
PrintData(IN CONST CHAR8 * data,IN UINTN len)56 PrintData (
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 
84 STATIC
85 VOID
DumpFdt(IN VOID * FdtBlob)86 DumpFdt (
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 **/
193 SHELL_STATUS
194 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)195 ShellDynCmdDumpFdtHandler (
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 **/
264 CHAR16*
265 EFIAPI
ShellDynCmdDumpFdtGetHelp(IN EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL * This,IN CONST CHAR8 * Language)266 ShellDynCmdDumpFdtGetHelp (
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