1 /** @file
2 *
3 *  Copyright (c) 2011-2013, ARM Limited. All rights reserved.
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 <Base.h>
16 #include <Uefi.h>
17 #include <Library/MemoryAllocationLib.h>
18 #include <Library/BdsLib.h>
19 #include <Library/DebugLib.h>
20 #include <Library/PcdLib.h>
21 #include <Library/PrintLib.h>
22 #include <Library/UefiLib.h>
23 #include <Library/UefiApplicationEntryPoint.h>
24 #include <Library/UefiBootServicesTableLib.h>
25 #include <Library/UefiRuntimeServicesTableLib.h>
26 
27 #include <Protocol/DevicePathFromText.h>
28 
29 #include <Guid/Fdt.h>
30 
31 #include <libfdt.h>
32 
33 #define ALIGN(x, a)     (((x) + ((a) - 1)) & ~((a) - 1))
34 #define PALIGN(p, a)    ((void *)(ALIGN((unsigned long)(p), (a))))
35 #define GET_CELL(p)     (p += 4, *((const uint32_t *)(p-4)))
36 
37 STATIC
38 UINTN
IsPrintableString(IN CONST VOID * data,IN UINTN len)39 IsPrintableString (
40   IN CONST VOID* data,
41   IN UINTN len
42   )
43 {
44   CONST CHAR8 *s = data;
45   CONST CHAR8 *ss;
46 
47   // Zero length is not
48   if (len == 0) {
49     return 0;
50   }
51 
52   // Must terminate with zero
53   if (s[len - 1] != '\0') {
54     return 0;
55   }
56 
57   ss = s;
58   while (*s/* && isprint(*s)*/) {
59     s++;
60   }
61 
62   // Not zero, or not done yet
63   if (*s != '\0' || (s + 1 - ss) < len) {
64     return 0;
65   }
66 
67   return 1;
68 }
69 
70 STATIC
71 VOID
PrintData(IN CONST CHAR8 * data,IN UINTN len)72 PrintData (
73   IN CONST CHAR8* data,
74   IN UINTN len
75   )
76 {
77   UINTN i;
78   CONST CHAR8 *p = data;
79 
80   // No data, don't print
81   if (len == 0)
82     return;
83 
84   if (IsPrintableString (data, len)) {
85     Print(L" = \"%a\"", (const char *)data);
86   } else if ((len % 4) == 0) {
87     Print(L" = <");
88     for (i = 0; i < len; i += 4) {
89       Print(L"0x%08x%a", fdt32_to_cpu(GET_CELL(p)),i < (len - 4) ? " " : "");
90     }
91     Print(L">");
92   } else {
93     Print(L" = [");
94     for (i = 0; i < len; i++)
95       Print(L"%02x%a", *p++, i < len - 1 ? " " : "");
96     Print(L"]");
97   }
98 }
99 
100 VOID
DumpFdt(IN VOID * FdtBlob)101 DumpFdt (
102   IN VOID*                FdtBlob
103   )
104 {
105   struct fdt_header *bph;
106   UINT32 off_dt;
107   UINT32 off_str;
108   CONST CHAR8* p_struct;
109   CONST CHAR8* p_strings;
110   CONST CHAR8* p;
111   CONST CHAR8* s;
112   CONST CHAR8* t;
113   UINT32 tag;
114   UINTN sz;
115   UINTN depth;
116   UINTN shift;
117   UINT32 version;
118 
119   depth = 0;
120   shift = 4;
121 
122   bph = FdtBlob;
123   off_dt = fdt32_to_cpu(bph->off_dt_struct);
124   off_str = fdt32_to_cpu(bph->off_dt_strings);
125   p_struct = (CONST CHAR8*)FdtBlob + off_dt;
126   p_strings = (CONST CHAR8*)FdtBlob + off_str;
127   version = fdt32_to_cpu(bph->version);
128 
129   p = p_struct;
130   while ((tag = fdt32_to_cpu(GET_CELL(p))) != FDT_END) {
131 
132     if (tag == FDT_BEGIN_NODE) {
133       s = p;
134       p = PALIGN(p + strlen(s) + 1, 4);
135 
136       if (*s == '\0')
137               s = "/";
138 
139       Print(L"%*s%a {\n", depth * shift, L" ", s);
140 
141       depth++;
142       continue;
143     }
144 
145     if (tag == FDT_END_NODE) {
146       depth--;
147 
148       Print(L"%*s};\n", depth * shift, L" ");
149       continue;
150     }
151 
152     if (tag == FDT_NOP) {
153       Print(L"%*s// [NOP]\n", depth * shift, L" ");
154       continue;
155     }
156 
157     if (tag != FDT_PROP) {
158       Print(L"%*s ** Unknown tag 0x%08x\n", depth * shift, L" ", tag);
159       break;
160     }
161     sz = fdt32_to_cpu(GET_CELL(p));
162     s = p_strings + fdt32_to_cpu(GET_CELL(p));
163     if (version < 16 && sz >= 8)
164             p = PALIGN(p, 8);
165     t = p;
166 
167     p = PALIGN(p + sz, 4);
168 
169     Print(L"%*s%a", depth * shift, L" ", s);
170     PrintData(t, sz);
171     Print(L";\n");
172   }
173 }
174 
175 EFI_STATUS
EblDumpFdt(IN UINTN Argc,IN CHAR8 ** Argv)176 EblDumpFdt (
177   IN UINTN  Argc,
178   IN CHAR8  **Argv
179   )
180 {
181   EFI_STATUS  Status;
182   VOID        *FdtBlob;
183   UINTN       Ret;
184 
185   // If no FDT file is passed to the argument then get the one from the platform
186   if (Argc < 2) {
187     Status = EfiGetSystemConfigurationTable (&gFdtTableGuid, &FdtBlob);
188     if (EFI_ERROR (Status)) {
189       Print (L"ERROR: Did not find the Fdt Blob.\n");
190       return Status;
191     }
192   } else {
193     return EFI_NOT_FOUND;
194   }
195 
196   Ret = fdt_check_header (FdtBlob);
197   if (Ret != 0) {
198     Print (L"ERROR: Device Tree header not valid (err:%d)\n", Ret);
199     return EFI_INVALID_PARAMETER;
200   }
201 
202   DumpFdt (FdtBlob);
203 
204   return EFI_SUCCESS;
205 }
206