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