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 <stdlib.h>
8#include <string.h>
9#include <ctype.h>
10
11#include <fdt.h>
12#include <libfdt_env.h>
13
14#define FTDUMP_BUF_SIZE	65536
15
16#define ALIGN(x, a)	(((x) + ((a) - 1)) & ~((a) - 1))
17#define PALIGN(p, a)	((void *)(ALIGN((unsigned long)(p), (a))))
18#define GET_CELL(p)	(p += 4, *((const uint32_t *)(p-4)))
19
20static int is_printable_string(const void *data, int len)
21{
22	const char *s = data;
23	const char *ss;
24
25	/* zero length is not */
26	if (len == 0)
27		return 0;
28
29	/* must terminate with zero */
30	if (s[len - 1] != '\0')
31		return 0;
32
33	ss = s;
34	while (*s && isprint(*s))
35		s++;
36
37	/* not zero, or not done yet */
38	if (*s != '\0' || (s + 1 - ss) < len)
39		return 0;
40
41	return 1;
42}
43
44static void print_data(const char *data, int len)
45{
46	int i;
47	const char *p = data;
48
49	/* no data, don't print */
50	if (len == 0)
51		return;
52
53	if (is_printable_string(data, len)) {
54		printf(" = \"%s\"", (const char *)data);
55	} else if ((len % 4) == 0) {
56		printf(" = <");
57		for (i = 0; i < len; i += 4)
58			printf("0x%08x%s", fdt32_to_cpu(GET_CELL(p)),
59			       i < (len - 4) ? " " : "");
60		printf(">");
61	} else {
62		printf(" = [");
63		for (i = 0; i < len; i++)
64			printf("%02x%s", *p++, i < len - 1 ? " " : "");
65		printf("]");
66	}
67}
68
69static void dump_blob(void *blob)
70{
71	struct fdt_header *bph = blob;
72	uint32_t off_mem_rsvmap = fdt32_to_cpu(bph->off_mem_rsvmap);
73	uint32_t off_dt = fdt32_to_cpu(bph->off_dt_struct);
74	uint32_t off_str = fdt32_to_cpu(bph->off_dt_strings);
75	struct fdt_reserve_entry *p_rsvmap =
76		(struct fdt_reserve_entry *)((char *)blob + off_mem_rsvmap);
77	const char *p_struct = (const char *)blob + off_dt;
78	const char *p_strings = (const char *)blob + off_str;
79	uint32_t version = fdt32_to_cpu(bph->version);
80	uint32_t totalsize = fdt32_to_cpu(bph->totalsize);
81	uint32_t tag;
82	const char *p, *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("/dts-v1/;\n");
91	printf("// magic:\t\t0x%x\n", fdt32_to_cpu(bph->magic));
92	printf("// totalsize:\t\t0x%x (%d)\n", totalsize, totalsize);
93	printf("// off_dt_struct:\t0x%x\n", off_dt);
94	printf("// off_dt_strings:\t0x%x\n", off_str);
95	printf("// off_mem_rsvmap:\t0x%x\n", off_mem_rsvmap);
96	printf("// version:\t\t%d\n", version);
97	printf("// last_comp_version:\t%d\n",
98	       fdt32_to_cpu(bph->last_comp_version));
99	if (version >= 2)
100		printf("// boot_cpuid_phys:\t0x%x\n",
101		       fdt32_to_cpu(bph->boot_cpuid_phys));
102
103	if (version >= 3)
104		printf("// size_dt_strings:\t0x%x\n",
105		       fdt32_to_cpu(bph->size_dt_strings));
106	if (version >= 17)
107		printf("// size_dt_struct:\t0x%x\n",
108		       fdt32_to_cpu(bph->size_dt_struct));
109	printf("\n");
110
111	for (i = 0; ; i++) {
112		addr = fdt64_to_cpu(p_rsvmap[i].address);
113		size = fdt64_to_cpu(p_rsvmap[i].size);
114		if (addr == 0 && size == 0)
115			break;
116
117		printf("/memreserve/ %llx %llx;\n",
118		       (unsigned long long)addr, (unsigned long long)size);
119	}
120
121	p = p_struct;
122	while ((tag = fdt32_to_cpu(GET_CELL(p))) != FDT_END) {
123
124		/* printf("tag: 0x%08x (%d)\n", tag, p - p_struct); */
125
126		if (tag == FDT_BEGIN_NODE) {
127			s = p;
128			p = PALIGN(p + strlen(s) + 1, 4);
129
130			if (*s == '\0')
131				s = "/";
132
133			printf("%*s%s {\n", depth * shift, "", s);
134
135			depth++;
136			continue;
137		}
138
139		if (tag == FDT_END_NODE) {
140			depth--;
141
142			printf("%*s};\n", depth * shift, "");
143			continue;
144		}
145
146		if (tag == FDT_NOP) {
147			printf("%*s// [NOP]\n", depth * shift, "");
148			continue;
149		}
150
151		if (tag != FDT_PROP) {
152			fprintf(stderr, "%*s ** Unknown tag 0x%08x\n", depth * shift, "", tag);
153			break;
154		}
155		sz = fdt32_to_cpu(GET_CELL(p));
156		s = p_strings + fdt32_to_cpu(GET_CELL(p));
157		if (version < 16 && sz >= 8)
158			p = PALIGN(p, 8);
159		t = p;
160
161		p = PALIGN(p + sz, 4);
162
163		printf("%*s%s", depth * shift, "", s);
164		print_data(t, sz);
165		printf(";\n");
166	}
167}
168
169
170int main(int argc, char *argv[])
171{
172	FILE *fp;
173	char *buf;
174	int size;
175
176	if (argc < 2) {
177		fprintf(stderr, "supply input filename\n");
178		return 5;
179	}
180
181	if (strcmp(argv[1], "-") == 0) {
182		fp = stdin;
183	} else {
184		fp = fopen(argv[1], "rb");
185		if (fp == NULL) {
186			fprintf(stderr, "unable to open %s\n", argv[1]);
187			return 10;
188		}
189	}
190
191	buf = malloc(FTDUMP_BUF_SIZE);
192	if (!buf) {
193		fprintf(stderr, "Couldn't allocate %d byte buffer\n", FTDUMP_BUF_SIZE);
194		return 10;
195	}
196
197	size = fread(buf, 1, FTDUMP_BUF_SIZE, fp);
198	if (size == FTDUMP_BUF_SIZE) {
199		fprintf(stderr, "file too large (maximum is %d bytes)\n", FTDUMP_BUF_SIZE);
200		return 10;
201	}
202
203	dump_blob(buf);
204
205	fclose(fp);
206
207	return 0;
208}
209