|
1 /* |
|
2 * ftdump.c - Contributed by Pantelis Antoniou <pantelis.antoniou AT gmail.com> |
|
3 */ |
|
4 |
|
5 #include <stdint.h> |
|
6 #include <stdio.h> |
|
7 #include <string.h> |
|
8 #include <ctype.h> |
|
9 #include <getopt.h> |
|
10 |
|
11 #include <fdt.h> |
|
12 #include <libfdt_env.h> |
|
13 #include <version_gen.h> |
|
14 |
|
15 #define ALIGN(x, a) (((x) + ((a) - 1)) & ~((a) - 1)) |
|
16 #define PALIGN(p, a) ((void *)(ALIGN((unsigned long)(p), (a)))) |
|
17 #define GET_CELL(p) (p += 4, *((uint32_t *)(p-4))) |
|
18 |
|
19 static int is_printable_string(const void *data, int len) |
|
20 { |
|
21 const char *s = data; |
|
22 const char *ss; |
|
23 |
|
24 /* zero length is not */ |
|
25 if (len == 0) |
|
26 return 0; |
|
27 |
|
28 /* must terminate with zero */ |
|
29 if (s[len - 1] != '\0') |
|
30 return 0; |
|
31 |
|
32 ss = s; |
|
33 while (*s && isprint(*s)) |
|
34 s++; |
|
35 |
|
36 /* not zero, or not done yet */ |
|
37 if (*s != '\0' || (s + 1 - ss) < len) |
|
38 return 0; |
|
39 |
|
40 return 1; |
|
41 } |
|
42 |
|
43 static void print_data(const void *data, int len) |
|
44 { |
|
45 int i; |
|
46 const uint8_t *s; |
|
47 |
|
48 /* no data, don't print */ |
|
49 if (len == 0) |
|
50 return; |
|
51 |
|
52 if (is_printable_string(data, len)) { |
|
53 printf(" = \"%s\"", (const char *)data); |
|
54 } else if ((len % 4) == 0) { |
|
55 printf(" = <"); |
|
56 for (i = 0; i < len; i += 4) |
|
57 printf("%08x%s", *((const uint32_t *)data + i), |
|
58 i < (len - 4) ? " " : ""); |
|
59 printf(">"); |
|
60 } else { |
|
61 printf(" = ["); |
|
62 for (i = 0, s = data; i < len; i++) |
|
63 printf("%02x%s", s[i], i < len - 1 ? " " : ""); |
|
64 printf("]"); |
|
65 } |
|
66 } |
|
67 |
|
68 static void dump_blob(void *blob) |
|
69 { |
|
70 struct fdt_header *bph = blob; |
|
71 uint32_t off_mem_rsvmap = fdt32_to_cpu(bph->off_mem_rsvmap); |
|
72 uint32_t off_dt = fdt32_to_cpu(bph->off_dt_struct); |
|
73 uint32_t off_str = fdt32_to_cpu(bph->off_dt_strings); |
|
74 struct fdt_reserve_entry *p_rsvmap = |
|
75 (struct fdt_reserve_entry *)((char *)blob + off_mem_rsvmap); |
|
76 char *p_struct = (char *)blob + off_dt; |
|
77 char *p_strings = (char *)blob + off_str; |
|
78 uint32_t version = fdt32_to_cpu(bph->version); |
|
79 uint32_t totalsize = fdt32_to_cpu(bph->totalsize); |
|
80 uint32_t tag; |
|
81 char *p; |
|
82 char *s, *t; |
|
83 int depth, sz, shift; |
|
84 int i; |
|
85 uint64_t addr, size; |
|
86 |
|
87 depth = 0; |
|
88 shift = 4; |
|
89 |
|
90 printf("// magic:\t\t0x%x\n", fdt32_to_cpu(bph->magic)); |
|
91 printf("// totalsize:\t\t0x%x (%d)\n", totalsize, totalsize); |
|
92 printf("// off_dt_struct:\t0x%x\n", off_dt); |
|
93 printf("// off_dt_strings:\t0x%x\n", off_str); |
|
94 printf("// off_mem_rsvmap:\t0x%x\n", off_mem_rsvmap); |
|
95 printf("// version:\t\t%d\n", version); |
|
96 printf("// last_comp_version:\t%d\n", |
|
97 fdt32_to_cpu(bph->last_comp_version)); |
|
98 if (version >= 2) |
|
99 printf("// boot_cpuid_phys:\t0x%x\n", |
|
100 fdt32_to_cpu(bph->boot_cpuid_phys)); |
|
101 |
|
102 if (version >= 3) |
|
103 printf("// size_dt_strings:\t0x%x\n", |
|
104 fdt32_to_cpu(bph->size_dt_strings)); |
|
105 if (version >= 17) |
|
106 printf("// size_dt_struct:\t0x%x\n", |
|
107 fdt32_to_cpu(bph->size_dt_struct)); |
|
108 printf("\n"); |
|
109 |
|
110 for (i = 0; ; i++) { |
|
111 addr = fdt64_to_cpu(p_rsvmap[i].address); |
|
112 size = fdt64_to_cpu(p_rsvmap[i].size); |
|
113 if (addr == 0 && size == 0) |
|
114 break; |
|
115 |
|
116 printf("/memreserve/ %llx %llx;\n", |
|
117 (unsigned long long)addr, (unsigned long long)size); |
|
118 } |
|
119 |
|
120 p = p_struct; |
|
121 while ((tag = fdt32_to_cpu(GET_CELL(p))) != FDT_END) { |
|
122 |
|
123 /* printf("tag: 0x%08x (%d)\n", tag, p - p_struct); */ |
|
124 |
|
125 if (tag == FDT_BEGIN_NODE) { |
|
126 s = p; |
|
127 p = PALIGN(p + strlen(s) + 1, 4); |
|
128 |
|
129 if (*s == '\0') |
|
130 s = "/"; |
|
131 |
|
132 printf("%*s%s {\n", depth * shift, "", s); |
|
133 |
|
134 depth++; |
|
135 continue; |
|
136 } |
|
137 |
|
138 if (tag == FDT_END_NODE) { |
|
139 depth--; |
|
140 |
|
141 printf("%*s};\n", depth * shift, ""); |
|
142 continue; |
|
143 } |
|
144 |
|
145 if (tag == FDT_NOP) { |
|
146 printf("%*s// [NOP]\n", depth * shift, ""); |
|
147 continue; |
|
148 } |
|
149 |
|
150 if (tag != FDT_PROP) { |
|
151 fprintf(stderr, "%*s ** Unknown tag 0x%08x\n", depth * shift, "", tag); |
|
152 break; |
|
153 } |
|
154 sz = fdt32_to_cpu(GET_CELL(p)); |
|
155 s = p_strings + fdt32_to_cpu(GET_CELL(p)); |
|
156 if (version < 16 && sz >= 8) |
|
157 p = PALIGN(p, 8); |
|
158 t = p; |
|
159 |
|
160 p = PALIGN(p + sz, 4); |
|
161 |
|
162 printf("%*s%s", depth * shift, "", s); |
|
163 print_data(t, sz); |
|
164 printf(";\n"); |
|
165 } |
|
166 } |
|
167 |
|
168 static void __attribute__ ((noreturn)) usage(int error) |
|
169 { |
|
170 FILE *f = error ? stderr : stdout; |
|
171 fprintf(f, "Usage:\n"); |
|
172 fprintf(f, "\tftdump [options] <input file>\n"); |
|
173 fprintf(f, "\nOptions:\n"); |
|
174 fprintf(f, "\t-h\n"); |
|
175 fprintf(f, "\t\tThis help text\n"); |
|
176 fprintf(f, "\t-v\n"); |
|
177 fprintf(f, "\t\tPrint ftdump version and exit\n"); |
|
178 fprintf(f, "\n"); |
|
179 fprintf(f, "Report bugs to %s\n", BUG_URL); |
|
180 exit(error ? 3 : 0); |
|
181 } |
|
182 |
|
183 int main(int argc, char *argv[]) |
|
184 { |
|
185 static const struct option longopts[] = { |
|
186 {"help", no_argument, NULL, 'h'}, |
|
187 {"version", no_argument, NULL, 'v'}, |
|
188 {NULL, 0, NULL, 0} |
|
189 }; |
|
190 int opt; |
|
191 FILE *fp; |
|
192 char buf[16384]; /* 16k max */ |
|
193 int size; |
|
194 |
|
195 while ((opt = getopt_long(argc, argv, "hv", |
|
196 longopts, NULL)) != EOF) { |
|
197 switch (opt) { |
|
198 case 'h': |
|
199 usage(0); |
|
200 case 'v': |
|
201 printf("Version: %s\n", DTC_VERSION); |
|
202 exit(0); |
|
203 default: |
|
204 usage(1); |
|
205 } |
|
206 } |
|
207 |
|
208 if (argc != optind + 1) { |
|
209 usage(1); |
|
210 } |
|
211 |
|
212 fp = fopen(argv[optind], "rb"); |
|
213 if (fp == NULL) { |
|
214 fprintf(stderr, "unable to open %s\n", argv[1]); |
|
215 return 10; |
|
216 } |
|
217 |
|
218 size = fread(buf, 1, sizeof(buf), fp); |
|
219 if (size == sizeof(buf)) { /* too large */ |
|
220 fprintf(stderr, "file too large\n"); |
|
221 return 10; |
|
222 } |
|
223 |
|
224 dump_blob(buf); |
|
225 |
|
226 fclose(fp); |
|
227 |
|
228 return 0; |
|
229 } |