fdtdump.c revision 1.2 1 /*
2 * fdtdump.c - Contributed by Pantelis Antoniou <pantelis.antoniou AT gmail.com>
3 */
4
5 #include <stdbool.h>
6 #include <stdint.h>
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <string.h>
10 #include <ctype.h>
11
12 #include <libfdt.h>
13 #include <libfdt_env.h>
14 #include <fdt.h>
15
16 #include "util.h"
17
18 #define GET_CELL(p) (p += 4, *((const uint32_t *)(p-4)))
19
20 static const char *tagname(uint32_t tag)
21 {
22 static const char * const names[] = {
23 #define TN(t) [t] = #t
24 TN(FDT_BEGIN_NODE),
25 TN(FDT_END_NODE),
26 TN(FDT_PROP),
27 TN(FDT_NOP),
28 TN(FDT_END),
29 #undef TN
30 };
31 if (tag < ARRAY_SIZE(names))
32 if (names[tag])
33 return names[tag];
34 return "FDT_???";
35 }
36
37 #define dumpf(fmt, args...) \
38 do { if (debug) printf("// " fmt, ## args); } while (0)
39
40 static void dump_blob(void *blob, bool debug)
41 {
42 uintptr_t blob_off = (uintptr_t)blob;
43 struct fdt_header *bph = blob;
44 uint32_t off_mem_rsvmap = fdt32_to_cpu(bph->off_mem_rsvmap);
45 uint32_t off_dt = fdt32_to_cpu(bph->off_dt_struct);
46 uint32_t off_str = fdt32_to_cpu(bph->off_dt_strings);
47 struct fdt_reserve_entry *p_rsvmap =
48 (struct fdt_reserve_entry *)((char *)blob + off_mem_rsvmap);
49 const char *p_struct = (const char *)blob + off_dt;
50 const char *p_strings = (const char *)blob + off_str;
51 uint32_t version = fdt32_to_cpu(bph->version);
52 uint32_t totalsize = fdt32_to_cpu(bph->totalsize);
53 uint32_t tag;
54 const char *p, *s, *t;
55 int depth, sz, shift;
56 int i;
57 uint64_t addr, size;
58
59 depth = 0;
60 shift = 4;
61
62 printf("/dts-v1/;\n");
63 printf("// magic:\t\t0x%x\n", fdt32_to_cpu(bph->magic));
64 printf("// totalsize:\t\t0x%x (%d)\n", totalsize, totalsize);
65 printf("// off_dt_struct:\t0x%x\n", off_dt);
66 printf("// off_dt_strings:\t0x%x\n", off_str);
67 printf("// off_mem_rsvmap:\t0x%x\n", off_mem_rsvmap);
68 printf("// version:\t\t%d\n", version);
69 printf("// last_comp_version:\t%d\n",
70 fdt32_to_cpu(bph->last_comp_version));
71 if (version >= 2)
72 printf("// boot_cpuid_phys:\t0x%x\n",
73 fdt32_to_cpu(bph->boot_cpuid_phys));
74
75 if (version >= 3)
76 printf("// size_dt_strings:\t0x%x\n",
77 fdt32_to_cpu(bph->size_dt_strings));
78 if (version >= 17)
79 printf("// size_dt_struct:\t0x%x\n",
80 fdt32_to_cpu(bph->size_dt_struct));
81 printf("\n");
82
83 for (i = 0; ; i++) {
84 addr = fdt64_to_cpu(p_rsvmap[i].address);
85 size = fdt64_to_cpu(p_rsvmap[i].size);
86 if (addr == 0 && size == 0)
87 break;
88
89 printf("/memreserve/ %#llx %#llx;\n",
90 (unsigned long long)addr, (unsigned long long)size);
91 }
92
93 p = p_struct;
94 while ((tag = fdt32_to_cpu(GET_CELL(p))) != FDT_END) {
95
96 dumpf("%04zx: tag: 0x%08x (%s)\n",
97 (uintptr_t)p - blob_off - 4, tag, tagname(tag));
98
99 if (tag == FDT_BEGIN_NODE) {
100 s = p;
101 p = PALIGN(p + strlen(s) + 1, 4);
102
103 if (*s == '\0')
104 s = "/";
105
106 printf("%*s%s {\n", depth * shift, "", s);
107
108 depth++;
109 continue;
110 }
111
112 if (tag == FDT_END_NODE) {
113 depth--;
114
115 printf("%*s};\n", depth * shift, "");
116 continue;
117 }
118
119 if (tag == FDT_NOP) {
120 printf("%*s// [NOP]\n", depth * shift, "");
121 continue;
122 }
123
124 if (tag != FDT_PROP) {
125 fprintf(stderr, "%*s ** Unknown tag 0x%08x\n", depth * shift, "", tag);
126 break;
127 }
128 sz = fdt32_to_cpu(GET_CELL(p));
129 s = p_strings + fdt32_to_cpu(GET_CELL(p));
130 if (version < 16 && sz >= 8)
131 p = PALIGN(p, 8);
132 t = p;
133
134 p = PALIGN(p + sz, 4);
135
136 dumpf("%04zx: string: %s\n", (uintptr_t)s - blob_off, s);
137 dumpf("%04zx: value\n", (uintptr_t)t - blob_off);
138 printf("%*s%s", depth * shift, "", s);
139 utilfdt_print_data(t, sz);
140 printf(";\n");
141 }
142 }
143
144 /* Usage related data. */
145 static const char usage_synopsis[] = "fdtdump [options] <file>";
146 static const char usage_short_opts[] = "ds" USAGE_COMMON_SHORT_OPTS;
147 static struct option const usage_long_opts[] = {
148 {"debug", no_argument, NULL, 'd'},
149 {"scan", no_argument, NULL, 's'},
150 USAGE_COMMON_LONG_OPTS
151 };
152 static const char * const usage_opts_help[] = {
153 "Dump debug information while decoding the file",
154 "Scan for an embedded fdt in file",
155 USAGE_COMMON_OPTS_HELP
156 };
157
158 int main(int argc, char *argv[])
159 {
160 int opt;
161 const char *file;
162 char *buf;
163 bool debug = false;
164 bool scan = false;
165 off_t len;
166
167 while ((opt = util_getopt_long()) != EOF) {
168 switch (opt) {
169 case_USAGE_COMMON_FLAGS
170
171 case 'd':
172 debug = true;
173 break;
174 case 's':
175 scan = true;
176 break;
177 }
178 }
179 if (optind != argc - 1)
180 usage("missing input filename");
181 file = argv[optind];
182
183 buf = utilfdt_read_len(file, &len);
184 if (!buf)
185 die("could not read: %s\n", file);
186
187 /* try and locate an embedded fdt in a bigger blob */
188 if (scan) {
189 unsigned char smagic[4];
190 char *p = buf;
191 char *endp = buf + len;
192
193 fdt_set_magic(smagic, FDT_MAGIC);
194
195 /* poor man's memmem */
196 while (true) {
197 p = memchr(p, smagic[0], endp - p - 4);
198 if (!p)
199 break;
200 if (fdt_magic(p) == FDT_MAGIC) {
201 /* try and validate the main struct */
202 off_t this_len = endp - p;
203 fdt32_t max_version = 17;
204 if (fdt_version(p) <= max_version &&
205 fdt_last_comp_version(p) < max_version &&
206 fdt_totalsize(p) < this_len &&
207 fdt_off_dt_struct(p) < this_len &&
208 fdt_off_dt_strings(p) < this_len)
209 break;
210 if (debug)
211 printf("%s: skipping fdt magic at offset %#zx\n",
212 file, p - buf);
213 }
214 ++p;
215 }
216 if (!p)
217 die("%s: could not locate fdt magic\n", file);
218 printf("%s: found fdt at offset %#zx\n", file, p - buf);
219 buf = p;
220 }
221
222 dump_blob(buf, debug);
223
224 return 0;
225 }
226