blob: fa3b56130e0db3ab8361d9bbdbae48c0d19ce687 [file] [log] [blame]
David Gibsonb2543fc2005-08-29 14:58:27 +10001/*
Mike Frysinger8f459c52011-10-25 17:29:24 -04002 * fdtdump.c - Contributed by Pantelis Antoniou <pantelis.antoniou AT gmail.com>
David Gibsonb2543fc2005-08-29 14:58:27 +10003 */
4
Mike Frysingerfdc73872013-04-15 22:13:13 -04005#include <stdbool.h>
David Gibsonb2543fc2005-08-29 14:58:27 +10006#include <stdint.h>
7#include <stdio.h>
David Gibson0ef21052009-11-17 17:00:53 +11008#include <stdlib.h>
David Gibsonb2543fc2005-08-29 14:58:27 +10009#include <string.h>
10#include <ctype.h>
David Gibsonb2543fc2005-08-29 14:58:27 +100011
Mike Frysingerfdc73872013-04-15 22:13:13 -040012#include <libfdt.h>
David Gibson11d71002008-06-26 10:43:06 +100013#include <libfdt_env.h>
Kim Phillips20b866a2012-11-13 18:34:09 -060014#include <fdt.h>
David Gibsonb2543fc2005-08-29 14:58:27 +100015
Simon Glass492f9d52011-07-05 12:02:49 -070016#include "util.h"
17
Jean-Christophe Duboise24d39a2016-07-13 02:31:13 +020018#define FDT_MAGIC_SIZE 4
Heinrich Schuchardt0931cea2016-12-22 00:59:06 +010019#define MAX_VERSION 17
Jean-Christophe Duboise24d39a2016-07-13 02:31:13 +020020
David Gibsonb2543fc2005-08-29 14:58:27 +100021#define ALIGN(x, a) (((x) + ((a) - 1)) & ~((a) - 1))
22#define PALIGN(p, a) ((void *)(ALIGN((unsigned long)(p), (a))))
David Gibsonbad5b282017-03-06 12:08:53 +110023#define GET_CELL(p) (p += 4, *((const fdt32_t *)(p-4)))
David Gibsonb2543fc2005-08-29 14:58:27 +100024
Mike Frysinger8ec013a2013-04-15 22:13:17 -040025static const char *tagname(uint32_t tag)
David Gibsonb2543fc2005-08-29 14:58:27 +100026{
Mike Frysinger8ec013a2013-04-15 22:13:17 -040027 static const char * const names[] = {
Phil Elwell242c2642014-10-17 23:22:11 +010028#define TN(t) [t] = #t
Mike Frysinger8ec013a2013-04-15 22:13:17 -040029 TN(FDT_BEGIN_NODE),
30 TN(FDT_END_NODE),
31 TN(FDT_PROP),
32 TN(FDT_NOP),
33 TN(FDT_END),
34#undef TN
35 };
36 if (tag < ARRAY_SIZE(names))
37 if (names[tag])
38 return names[tag];
39 return "FDT_???";
40}
41
42#define dumpf(fmt, args...) \
43 do { if (debug) printf("// " fmt, ## args); } while (0)
44
45static void dump_blob(void *blob, bool debug)
46{
47 uintptr_t blob_off = (uintptr_t)blob;
David Gibsonfb7c7ac2007-09-26 13:11:05 +100048 struct fdt_header *bph = blob;
David Gibson11d71002008-06-26 10:43:06 +100049 uint32_t off_mem_rsvmap = fdt32_to_cpu(bph->off_mem_rsvmap);
50 uint32_t off_dt = fdt32_to_cpu(bph->off_dt_struct);
51 uint32_t off_str = fdt32_to_cpu(bph->off_dt_strings);
David Gibsonfb7c7ac2007-09-26 13:11:05 +100052 struct fdt_reserve_entry *p_rsvmap =
David Gibson36786db2008-07-07 10:10:48 +100053 (struct fdt_reserve_entry *)((char *)blob + off_mem_rsvmap);
David Gibson0ef21052009-11-17 17:00:53 +110054 const char *p_struct = (const char *)blob + off_dt;
55 const char *p_strings = (const char *)blob + off_str;
David Gibson11d71002008-06-26 10:43:06 +100056 uint32_t version = fdt32_to_cpu(bph->version);
57 uint32_t totalsize = fdt32_to_cpu(bph->totalsize);
David Gibsonb2543fc2005-08-29 14:58:27 +100058 uint32_t tag;
David Gibson0ef21052009-11-17 17:00:53 +110059 const char *p, *s, *t;
David Gibsonb2543fc2005-08-29 14:58:27 +100060 int depth, sz, shift;
61 int i;
62 uint64_t addr, size;
63
64 depth = 0;
65 shift = 4;
66
David Gibson0ef21052009-11-17 17:00:53 +110067 printf("/dts-v1/;\n");
David Gibson11d71002008-06-26 10:43:06 +100068 printf("// magic:\t\t0x%x\n", fdt32_to_cpu(bph->magic));
David Gibson3bb78bf2008-01-03 15:48:43 +110069 printf("// totalsize:\t\t0x%x (%d)\n", totalsize, totalsize);
70 printf("// off_dt_struct:\t0x%x\n", off_dt);
71 printf("// off_dt_strings:\t0x%x\n", off_str);
72 printf("// off_mem_rsvmap:\t0x%x\n", off_mem_rsvmap);
73 printf("// version:\t\t%d\n", version);
74 printf("// last_comp_version:\t%d\n",
David Gibson11d71002008-06-26 10:43:06 +100075 fdt32_to_cpu(bph->last_comp_version));
David Gibson3bb78bf2008-01-03 15:48:43 +110076 if (version >= 2)
77 printf("// boot_cpuid_phys:\t0x%x\n",
David Gibson11d71002008-06-26 10:43:06 +100078 fdt32_to_cpu(bph->boot_cpuid_phys));
David Gibson3bb78bf2008-01-03 15:48:43 +110079
80 if (version >= 3)
81 printf("// size_dt_strings:\t0x%x\n",
David Gibson11d71002008-06-26 10:43:06 +100082 fdt32_to_cpu(bph->size_dt_strings));
David Gibson3bb78bf2008-01-03 15:48:43 +110083 if (version >= 17)
84 printf("// size_dt_struct:\t0x%x\n",
David Gibson11d71002008-06-26 10:43:06 +100085 fdt32_to_cpu(bph->size_dt_struct));
David Gibson3bb78bf2008-01-03 15:48:43 +110086 printf("\n");
87
David Gibsonb2543fc2005-08-29 14:58:27 +100088 for (i = 0; ; i++) {
David Gibson11d71002008-06-26 10:43:06 +100089 addr = fdt64_to_cpu(p_rsvmap[i].address);
90 size = fdt64_to_cpu(p_rsvmap[i].size);
David Gibsonb2543fc2005-08-29 14:58:27 +100091 if (addr == 0 && size == 0)
92 break;
93
Simon Glassdfcfb7f2014-06-18 01:00:22 -060094 printf("/memreserve/ %#llx %#llx;\n",
David Gibsonb2543fc2005-08-29 14:58:27 +100095 (unsigned long long)addr, (unsigned long long)size);
96 }
97
98 p = p_struct;
David Gibson11d71002008-06-26 10:43:06 +100099 while ((tag = fdt32_to_cpu(GET_CELL(p))) != FDT_END) {
David Gibsonb2543fc2005-08-29 14:58:27 +1000100
Mike Frysinger8ec013a2013-04-15 22:13:17 -0400101 dumpf("%04zx: tag: 0x%08x (%s)\n",
102 (uintptr_t)p - blob_off - 4, tag, tagname(tag));
David Gibsonb2543fc2005-08-29 14:58:27 +1000103
David Gibsonfb7c7ac2007-09-26 13:11:05 +1000104 if (tag == FDT_BEGIN_NODE) {
David Gibsonb2543fc2005-08-29 14:58:27 +1000105 s = p;
106 p = PALIGN(p + strlen(s) + 1, 4);
107
108 if (*s == '\0')
109 s = "/";
110
111 printf("%*s%s {\n", depth * shift, "", s);
112
113 depth++;
114 continue;
115 }
116
David Gibsonfb7c7ac2007-09-26 13:11:05 +1000117 if (tag == FDT_END_NODE) {
David Gibsonb2543fc2005-08-29 14:58:27 +1000118 depth--;
119
120 printf("%*s};\n", depth * shift, "");
121 continue;
122 }
123
David Gibsonfb7c7ac2007-09-26 13:11:05 +1000124 if (tag == FDT_NOP) {
David Gibsonb2543fc2005-08-29 14:58:27 +1000125 printf("%*s// [NOP]\n", depth * shift, "");
126 continue;
127 }
128
David Gibsonfb7c7ac2007-09-26 13:11:05 +1000129 if (tag != FDT_PROP) {
David Gibsonb2543fc2005-08-29 14:58:27 +1000130 fprintf(stderr, "%*s ** Unknown tag 0x%08x\n", depth * shift, "", tag);
131 break;
132 }
David Gibson11d71002008-06-26 10:43:06 +1000133 sz = fdt32_to_cpu(GET_CELL(p));
134 s = p_strings + fdt32_to_cpu(GET_CELL(p));
David Gibson46c88df2007-03-14 11:02:40 +1100135 if (version < 16 && sz >= 8)
David Gibsonb2543fc2005-08-29 14:58:27 +1000136 p = PALIGN(p, 8);
137 t = p;
138
139 p = PALIGN(p + sz, 4);
140
Mike Frysinger8ec013a2013-04-15 22:13:17 -0400141 dumpf("%04zx: string: %s\n", (uintptr_t)s - blob_off, s);
142 dumpf("%04zx: value\n", (uintptr_t)t - blob_off);
David Gibsonb2543fc2005-08-29 14:58:27 +1000143 printf("%*s%s", depth * shift, "", s);
Simon Glassd20391d2013-01-21 12:59:16 -0800144 utilfdt_print_data(t, sz);
David Gibsonb2543fc2005-08-29 14:58:27 +1000145 printf(";\n");
146 }
147}
148
Mike Frysingerbe8d1c82013-04-15 22:13:12 -0400149/* Usage related data. */
150static const char usage_synopsis[] = "fdtdump [options] <file>";
Mike Frysinger8ec013a2013-04-15 22:13:17 -0400151static const char usage_short_opts[] = "ds" USAGE_COMMON_SHORT_OPTS;
Mike Frysingerbe8d1c82013-04-15 22:13:12 -0400152static struct option const usage_long_opts[] = {
Mike Frysinger8ec013a2013-04-15 22:13:17 -0400153 {"debug", no_argument, NULL, 'd'},
Mike Frysingerfdc73872013-04-15 22:13:13 -0400154 {"scan", no_argument, NULL, 's'},
Mike Frysingerbe8d1c82013-04-15 22:13:12 -0400155 USAGE_COMMON_LONG_OPTS
156};
157static const char * const usage_opts_help[] = {
Mike Frysinger8ec013a2013-04-15 22:13:17 -0400158 "Dump debug information while decoding the file",
Mike Frysingerfdc73872013-04-15 22:13:13 -0400159 "Scan for an embedded fdt in file",
Mike Frysingerbe8d1c82013-04-15 22:13:12 -0400160 USAGE_COMMON_OPTS_HELP
161};
David Gibsonb2543fc2005-08-29 14:58:27 +1000162
Heinrich Schuchardt0931cea2016-12-22 00:59:06 +0100163static bool valid_header(char *p, off_t len)
164{
165 if (len < sizeof(struct fdt_header) ||
166 fdt_magic(p) != FDT_MAGIC ||
167 fdt_version(p) > MAX_VERSION ||
David Gibsonc2258842017-04-18 12:52:08 +1000168 fdt_last_comp_version(p) > MAX_VERSION ||
Heinrich Schuchardt0931cea2016-12-22 00:59:06 +0100169 fdt_totalsize(p) >= len ||
170 fdt_off_dt_struct(p) >= len ||
171 fdt_off_dt_strings(p) >= len)
172 return 0;
173 else
174 return 1;
175}
176
David Gibsonb2543fc2005-08-29 14:58:27 +1000177int main(int argc, char *argv[])
178{
Mike Frysingerbe8d1c82013-04-15 22:13:12 -0400179 int opt;
180 const char *file;
David Gibson0ef21052009-11-17 17:00:53 +1100181 char *buf;
Mike Frysinger8ec013a2013-04-15 22:13:17 -0400182 bool debug = false;
Mike Frysingerfdc73872013-04-15 22:13:13 -0400183 bool scan = false;
184 off_t len;
David Gibsonb2543fc2005-08-29 14:58:27 +1000185
David Gibson548aea22017-04-18 13:05:08 +1000186 fprintf(stderr, "\n"
187"**** fdtdump is a low-level debugging tool, not meant for general use.\n"
188"**** If you want to decompile a dtb, you probably want\n"
189"**** dtc -I dtb -O dts <filename>\n\n"
190 );
Mike Frysingerbe8d1c82013-04-15 22:13:12 -0400191 while ((opt = util_getopt_long()) != EOF) {
192 switch (opt) {
193 case_USAGE_COMMON_FLAGS
Mike Frysingerfdc73872013-04-15 22:13:13 -0400194
Mike Frysinger8ec013a2013-04-15 22:13:17 -0400195 case 'd':
196 debug = true;
197 break;
Mike Frysingerfdc73872013-04-15 22:13:13 -0400198 case 's':
199 scan = true;
200 break;
Mike Frysingerbe8d1c82013-04-15 22:13:12 -0400201 }
David Gibsonb2543fc2005-08-29 14:58:27 +1000202 }
Mike Frysingerbe8d1c82013-04-15 22:13:12 -0400203 if (optind != argc - 1)
Mike Frysingerb9e80652013-05-24 18:04:43 +1000204 usage("missing input filename");
Mike Frysingerbe8d1c82013-04-15 22:13:12 -0400205 file = argv[optind];
David Gibsonb2543fc2005-08-29 14:58:27 +1000206
Mike Frysingerfdc73872013-04-15 22:13:13 -0400207 buf = utilfdt_read_len(file, &len);
Mike Frysingerbe8d1c82013-04-15 22:13:12 -0400208 if (!buf)
209 die("could not read: %s\n", file);
210
Mike Frysingerfdc73872013-04-15 22:13:13 -0400211 /* try and locate an embedded fdt in a bigger blob */
212 if (scan) {
Jean-Christophe Duboise24d39a2016-07-13 02:31:13 +0200213 unsigned char smagic[FDT_MAGIC_SIZE];
Mike Frysingerfdc73872013-04-15 22:13:13 -0400214 char *p = buf;
215 char *endp = buf + len;
216
217 fdt_set_magic(smagic, FDT_MAGIC);
218
219 /* poor man's memmem */
Jean-Christophe Duboise24d39a2016-07-13 02:31:13 +0200220 while ((endp - p) >= FDT_MAGIC_SIZE) {
221 p = memchr(p, smagic[0], endp - p - FDT_MAGIC_SIZE);
Mike Frysingerfdc73872013-04-15 22:13:13 -0400222 if (!p)
223 break;
224 if (fdt_magic(p) == FDT_MAGIC) {
225 /* try and validate the main struct */
226 off_t this_len = endp - p;
Heinrich Schuchardt0931cea2016-12-22 00:59:06 +0100227 if (valid_header(p, this_len))
Mike Frysingerfdc73872013-04-15 22:13:13 -0400228 break;
Mike Frysinger8ec013a2013-04-15 22:13:17 -0400229 if (debug)
230 printf("%s: skipping fdt magic at offset %#zx\n",
231 file, p - buf);
Mike Frysingerfdc73872013-04-15 22:13:13 -0400232 }
233 ++p;
234 }
Heinrich Schuchardt0931cea2016-12-22 00:59:06 +0100235 if (!p || endp - p < sizeof(struct fdt_header))
Mike Frysingerfdc73872013-04-15 22:13:13 -0400236 die("%s: could not locate fdt magic\n", file);
237 printf("%s: found fdt at offset %#zx\n", file, p - buf);
238 buf = p;
Heinrich Schuchardt0931cea2016-12-22 00:59:06 +0100239 } else if (!valid_header(buf, len))
240 die("%s: header is not valid\n", file);
Mike Frysingerfdc73872013-04-15 22:13:13 -0400241
Mike Frysinger8ec013a2013-04-15 22:13:17 -0400242 dump_blob(buf, debug);
David Gibsonb2543fc2005-08-29 14:58:27 +1000243
244 return 0;
245}