xref: /rk3399_rockchip-uboot/scripts/dtc/flattree.c (revision d18719a48ffdf6be4a0724f88d8968904df3a0d9)
1*d18719a4STom Rini /*
2*d18719a4STom Rini  * (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation.  2005.
3*d18719a4STom Rini  *
4*d18719a4STom Rini  *
5*d18719a4STom Rini  * This program is free software; you can redistribute it and/or
6*d18719a4STom Rini  * modify it under the terms of the GNU General Public License as
7*d18719a4STom Rini  * published by the Free Software Foundation; either version 2 of the
8*d18719a4STom Rini  * License, or (at your option) any later version.
9*d18719a4STom Rini  *
10*d18719a4STom Rini  *  This program is distributed in the hope that it will be useful,
11*d18719a4STom Rini  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12*d18719a4STom Rini  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13*d18719a4STom Rini  *  General Public License for more details.
14*d18719a4STom Rini  *
15*d18719a4STom Rini  *  You should have received a copy of the GNU General Public License
16*d18719a4STom Rini  *  along with this program; if not, write to the Free Software
17*d18719a4STom Rini  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
18*d18719a4STom Rini  *                                                                   USA
19*d18719a4STom Rini  */
20*d18719a4STom Rini 
21*d18719a4STom Rini #include "dtc.h"
22*d18719a4STom Rini #include "srcpos.h"
23*d18719a4STom Rini 
24*d18719a4STom Rini #define FTF_FULLPATH	0x1
25*d18719a4STom Rini #define FTF_VARALIGN	0x2
26*d18719a4STom Rini #define FTF_NAMEPROPS	0x4
27*d18719a4STom Rini #define FTF_BOOTCPUID	0x8
28*d18719a4STom Rini #define FTF_STRTABSIZE	0x10
29*d18719a4STom Rini #define FTF_STRUCTSIZE	0x20
30*d18719a4STom Rini #define FTF_NOPS	0x40
31*d18719a4STom Rini 
32*d18719a4STom Rini static struct version_info {
33*d18719a4STom Rini 	int version;
34*d18719a4STom Rini 	int last_comp_version;
35*d18719a4STom Rini 	int hdr_size;
36*d18719a4STom Rini 	int flags;
37*d18719a4STom Rini } version_table[] = {
38*d18719a4STom Rini 	{1, 1, FDT_V1_SIZE,
39*d18719a4STom Rini 	 FTF_FULLPATH|FTF_VARALIGN|FTF_NAMEPROPS},
40*d18719a4STom Rini 	{2, 1, FDT_V2_SIZE,
41*d18719a4STom Rini 	 FTF_FULLPATH|FTF_VARALIGN|FTF_NAMEPROPS|FTF_BOOTCPUID},
42*d18719a4STom Rini 	{3, 1, FDT_V3_SIZE,
43*d18719a4STom Rini 	 FTF_FULLPATH|FTF_VARALIGN|FTF_NAMEPROPS|FTF_BOOTCPUID|FTF_STRTABSIZE},
44*d18719a4STom Rini 	{16, 16, FDT_V3_SIZE,
45*d18719a4STom Rini 	 FTF_BOOTCPUID|FTF_STRTABSIZE|FTF_NOPS},
46*d18719a4STom Rini 	{17, 16, FDT_V17_SIZE,
47*d18719a4STom Rini 	 FTF_BOOTCPUID|FTF_STRTABSIZE|FTF_STRUCTSIZE|FTF_NOPS},
48*d18719a4STom Rini };
49*d18719a4STom Rini 
50*d18719a4STom Rini struct emitter {
51*d18719a4STom Rini 	void (*cell)(void *, cell_t);
52*d18719a4STom Rini 	void (*string)(void *, char *, int);
53*d18719a4STom Rini 	void (*align)(void *, int);
54*d18719a4STom Rini 	void (*data)(void *, struct data);
55*d18719a4STom Rini 	void (*beginnode)(void *, struct label *labels);
56*d18719a4STom Rini 	void (*endnode)(void *, struct label *labels);
57*d18719a4STom Rini 	void (*property)(void *, struct label *labels);
58*d18719a4STom Rini };
59*d18719a4STom Rini 
60*d18719a4STom Rini static void bin_emit_cell(void *e, cell_t val)
61*d18719a4STom Rini {
62*d18719a4STom Rini 	struct data *dtbuf = e;
63*d18719a4STom Rini 
64*d18719a4STom Rini 	*dtbuf = data_append_cell(*dtbuf, val);
65*d18719a4STom Rini }
66*d18719a4STom Rini 
67*d18719a4STom Rini static void bin_emit_string(void *e, char *str, int len)
68*d18719a4STom Rini {
69*d18719a4STom Rini 	struct data *dtbuf = e;
70*d18719a4STom Rini 
71*d18719a4STom Rini 	if (len == 0)
72*d18719a4STom Rini 		len = strlen(str);
73*d18719a4STom Rini 
74*d18719a4STom Rini 	*dtbuf = data_append_data(*dtbuf, str, len);
75*d18719a4STom Rini 	*dtbuf = data_append_byte(*dtbuf, '\0');
76*d18719a4STom Rini }
77*d18719a4STom Rini 
78*d18719a4STom Rini static void bin_emit_align(void *e, int a)
79*d18719a4STom Rini {
80*d18719a4STom Rini 	struct data *dtbuf = e;
81*d18719a4STom Rini 
82*d18719a4STom Rini 	*dtbuf = data_append_align(*dtbuf, a);
83*d18719a4STom Rini }
84*d18719a4STom Rini 
85*d18719a4STom Rini static void bin_emit_data(void *e, struct data d)
86*d18719a4STom Rini {
87*d18719a4STom Rini 	struct data *dtbuf = e;
88*d18719a4STom Rini 
89*d18719a4STom Rini 	*dtbuf = data_append_data(*dtbuf, d.val, d.len);
90*d18719a4STom Rini }
91*d18719a4STom Rini 
92*d18719a4STom Rini static void bin_emit_beginnode(void *e, struct label *labels)
93*d18719a4STom Rini {
94*d18719a4STom Rini 	bin_emit_cell(e, FDT_BEGIN_NODE);
95*d18719a4STom Rini }
96*d18719a4STom Rini 
97*d18719a4STom Rini static void bin_emit_endnode(void *e, struct label *labels)
98*d18719a4STom Rini {
99*d18719a4STom Rini 	bin_emit_cell(e, FDT_END_NODE);
100*d18719a4STom Rini }
101*d18719a4STom Rini 
102*d18719a4STom Rini static void bin_emit_property(void *e, struct label *labels)
103*d18719a4STom Rini {
104*d18719a4STom Rini 	bin_emit_cell(e, FDT_PROP);
105*d18719a4STom Rini }
106*d18719a4STom Rini 
107*d18719a4STom Rini static struct emitter bin_emitter = {
108*d18719a4STom Rini 	.cell = bin_emit_cell,
109*d18719a4STom Rini 	.string = bin_emit_string,
110*d18719a4STom Rini 	.align = bin_emit_align,
111*d18719a4STom Rini 	.data = bin_emit_data,
112*d18719a4STom Rini 	.beginnode = bin_emit_beginnode,
113*d18719a4STom Rini 	.endnode = bin_emit_endnode,
114*d18719a4STom Rini 	.property = bin_emit_property,
115*d18719a4STom Rini };
116*d18719a4STom Rini 
117*d18719a4STom Rini static void emit_label(FILE *f, const char *prefix, const char *label)
118*d18719a4STom Rini {
119*d18719a4STom Rini 	fprintf(f, "\t.globl\t%s_%s\n", prefix, label);
120*d18719a4STom Rini 	fprintf(f, "%s_%s:\n", prefix, label);
121*d18719a4STom Rini 	fprintf(f, "_%s_%s:\n", prefix, label);
122*d18719a4STom Rini }
123*d18719a4STom Rini 
124*d18719a4STom Rini static void emit_offset_label(FILE *f, const char *label, int offset)
125*d18719a4STom Rini {
126*d18719a4STom Rini 	fprintf(f, "\t.globl\t%s\n", label);
127*d18719a4STom Rini 	fprintf(f, "%s\t= . + %d\n", label, offset);
128*d18719a4STom Rini }
129*d18719a4STom Rini 
130*d18719a4STom Rini #define ASM_EMIT_BELONG(f, fmt, ...) \
131*d18719a4STom Rini 	{ \
132*d18719a4STom Rini 		fprintf((f), "\t.byte\t((" fmt ") >> 24) & 0xff\n", __VA_ARGS__); \
133*d18719a4STom Rini 		fprintf((f), "\t.byte\t((" fmt ") >> 16) & 0xff\n", __VA_ARGS__); \
134*d18719a4STom Rini 		fprintf((f), "\t.byte\t((" fmt ") >> 8) & 0xff\n", __VA_ARGS__); \
135*d18719a4STom Rini 		fprintf((f), "\t.byte\t(" fmt ") & 0xff\n", __VA_ARGS__); \
136*d18719a4STom Rini 	}
137*d18719a4STom Rini 
138*d18719a4STom Rini static void asm_emit_cell(void *e, cell_t val)
139*d18719a4STom Rini {
140*d18719a4STom Rini 	FILE *f = e;
141*d18719a4STom Rini 
142*d18719a4STom Rini 	fprintf(f, "\t.byte 0x%02x; .byte 0x%02x; .byte 0x%02x; .byte 0x%02x\n",
143*d18719a4STom Rini 		(val >> 24) & 0xff, (val >> 16) & 0xff,
144*d18719a4STom Rini 		(val >> 8) & 0xff, val & 0xff);
145*d18719a4STom Rini }
146*d18719a4STom Rini 
147*d18719a4STom Rini static void asm_emit_string(void *e, char *str, int len)
148*d18719a4STom Rini {
149*d18719a4STom Rini 	FILE *f = e;
150*d18719a4STom Rini 	char c = 0;
151*d18719a4STom Rini 
152*d18719a4STom Rini 	if (len != 0) {
153*d18719a4STom Rini 		/* XXX: ewww */
154*d18719a4STom Rini 		c = str[len];
155*d18719a4STom Rini 		str[len] = '\0';
156*d18719a4STom Rini 	}
157*d18719a4STom Rini 
158*d18719a4STom Rini 	fprintf(f, "\t.string\t\"%s\"\n", str);
159*d18719a4STom Rini 
160*d18719a4STom Rini 	if (len != 0) {
161*d18719a4STom Rini 		str[len] = c;
162*d18719a4STom Rini 	}
163*d18719a4STom Rini }
164*d18719a4STom Rini 
165*d18719a4STom Rini static void asm_emit_align(void *e, int a)
166*d18719a4STom Rini {
167*d18719a4STom Rini 	FILE *f = e;
168*d18719a4STom Rini 
169*d18719a4STom Rini 	fprintf(f, "\t.balign\t%d, 0\n", a);
170*d18719a4STom Rini }
171*d18719a4STom Rini 
172*d18719a4STom Rini static void asm_emit_data(void *e, struct data d)
173*d18719a4STom Rini {
174*d18719a4STom Rini 	FILE *f = e;
175*d18719a4STom Rini 	int off = 0;
176*d18719a4STom Rini 	struct marker *m = d.markers;
177*d18719a4STom Rini 
178*d18719a4STom Rini 	for_each_marker_of_type(m, LABEL)
179*d18719a4STom Rini 		emit_offset_label(f, m->ref, m->offset);
180*d18719a4STom Rini 
181*d18719a4STom Rini 	while ((d.len - off) >= sizeof(uint32_t)) {
182*d18719a4STom Rini 		asm_emit_cell(e, fdt32_to_cpu(*((uint32_t *)(d.val+off))));
183*d18719a4STom Rini 		off += sizeof(uint32_t);
184*d18719a4STom Rini 	}
185*d18719a4STom Rini 
186*d18719a4STom Rini 	while ((d.len - off) >= 1) {
187*d18719a4STom Rini 		fprintf(f, "\t.byte\t0x%hhx\n", d.val[off]);
188*d18719a4STom Rini 		off += 1;
189*d18719a4STom Rini 	}
190*d18719a4STom Rini 
191*d18719a4STom Rini 	assert(off == d.len);
192*d18719a4STom Rini }
193*d18719a4STom Rini 
194*d18719a4STom Rini static void asm_emit_beginnode(void *e, struct label *labels)
195*d18719a4STom Rini {
196*d18719a4STom Rini 	FILE *f = e;
197*d18719a4STom Rini 	struct label *l;
198*d18719a4STom Rini 
199*d18719a4STom Rini 	for_each_label(labels, l) {
200*d18719a4STom Rini 		fprintf(f, "\t.globl\t%s\n", l->label);
201*d18719a4STom Rini 		fprintf(f, "%s:\n", l->label);
202*d18719a4STom Rini 	}
203*d18719a4STom Rini 	fprintf(f, "\t/* FDT_BEGIN_NODE */\n");
204*d18719a4STom Rini 	asm_emit_cell(e, FDT_BEGIN_NODE);
205*d18719a4STom Rini }
206*d18719a4STom Rini 
207*d18719a4STom Rini static void asm_emit_endnode(void *e, struct label *labels)
208*d18719a4STom Rini {
209*d18719a4STom Rini 	FILE *f = e;
210*d18719a4STom Rini 	struct label *l;
211*d18719a4STom Rini 
212*d18719a4STom Rini 	fprintf(f, "\t/* FDT_END_NODE */\n");
213*d18719a4STom Rini 	asm_emit_cell(e, FDT_END_NODE);
214*d18719a4STom Rini 	for_each_label(labels, l) {
215*d18719a4STom Rini 		fprintf(f, "\t.globl\t%s_end\n", l->label);
216*d18719a4STom Rini 		fprintf(f, "%s_end:\n", l->label);
217*d18719a4STom Rini 	}
218*d18719a4STom Rini }
219*d18719a4STom Rini 
220*d18719a4STom Rini static void asm_emit_property(void *e, struct label *labels)
221*d18719a4STom Rini {
222*d18719a4STom Rini 	FILE *f = e;
223*d18719a4STom Rini 	struct label *l;
224*d18719a4STom Rini 
225*d18719a4STom Rini 	for_each_label(labels, l) {
226*d18719a4STom Rini 		fprintf(f, "\t.globl\t%s\n", l->label);
227*d18719a4STom Rini 		fprintf(f, "%s:\n", l->label);
228*d18719a4STom Rini 	}
229*d18719a4STom Rini 	fprintf(f, "\t/* FDT_PROP */\n");
230*d18719a4STom Rini 	asm_emit_cell(e, FDT_PROP);
231*d18719a4STom Rini }
232*d18719a4STom Rini 
233*d18719a4STom Rini static struct emitter asm_emitter = {
234*d18719a4STom Rini 	.cell = asm_emit_cell,
235*d18719a4STom Rini 	.string = asm_emit_string,
236*d18719a4STom Rini 	.align = asm_emit_align,
237*d18719a4STom Rini 	.data = asm_emit_data,
238*d18719a4STom Rini 	.beginnode = asm_emit_beginnode,
239*d18719a4STom Rini 	.endnode = asm_emit_endnode,
240*d18719a4STom Rini 	.property = asm_emit_property,
241*d18719a4STom Rini };
242*d18719a4STom Rini 
243*d18719a4STom Rini static int stringtable_insert(struct data *d, const char *str)
244*d18719a4STom Rini {
245*d18719a4STom Rini 	int i;
246*d18719a4STom Rini 
247*d18719a4STom Rini 	/* FIXME: do this more efficiently? */
248*d18719a4STom Rini 
249*d18719a4STom Rini 	for (i = 0; i < d->len; i++) {
250*d18719a4STom Rini 		if (streq(str, d->val + i))
251*d18719a4STom Rini 			return i;
252*d18719a4STom Rini 	}
253*d18719a4STom Rini 
254*d18719a4STom Rini 	*d = data_append_data(*d, str, strlen(str)+1);
255*d18719a4STom Rini 	return i;
256*d18719a4STom Rini }
257*d18719a4STom Rini 
258*d18719a4STom Rini static void flatten_tree(struct node *tree, struct emitter *emit,
259*d18719a4STom Rini 			 void *etarget, struct data *strbuf,
260*d18719a4STom Rini 			 struct version_info *vi)
261*d18719a4STom Rini {
262*d18719a4STom Rini 	struct property *prop;
263*d18719a4STom Rini 	struct node *child;
264*d18719a4STom Rini 	bool seen_name_prop = false;
265*d18719a4STom Rini 
266*d18719a4STom Rini 	if (tree->deleted)
267*d18719a4STom Rini 		return;
268*d18719a4STom Rini 
269*d18719a4STom Rini 	emit->beginnode(etarget, tree->labels);
270*d18719a4STom Rini 
271*d18719a4STom Rini 	if (vi->flags & FTF_FULLPATH)
272*d18719a4STom Rini 		emit->string(etarget, tree->fullpath, 0);
273*d18719a4STom Rini 	else
274*d18719a4STom Rini 		emit->string(etarget, tree->name, 0);
275*d18719a4STom Rini 
276*d18719a4STom Rini 	emit->align(etarget, sizeof(cell_t));
277*d18719a4STom Rini 
278*d18719a4STom Rini 	for_each_property(tree, prop) {
279*d18719a4STom Rini 		int nameoff;
280*d18719a4STom Rini 
281*d18719a4STom Rini 		if (streq(prop->name, "name"))
282*d18719a4STom Rini 			seen_name_prop = true;
283*d18719a4STom Rini 
284*d18719a4STom Rini 		nameoff = stringtable_insert(strbuf, prop->name);
285*d18719a4STom Rini 
286*d18719a4STom Rini 		emit->property(etarget, prop->labels);
287*d18719a4STom Rini 		emit->cell(etarget, prop->val.len);
288*d18719a4STom Rini 		emit->cell(etarget, nameoff);
289*d18719a4STom Rini 
290*d18719a4STom Rini 		if ((vi->flags & FTF_VARALIGN) && (prop->val.len >= 8))
291*d18719a4STom Rini 			emit->align(etarget, 8);
292*d18719a4STom Rini 
293*d18719a4STom Rini 		emit->data(etarget, prop->val);
294*d18719a4STom Rini 		emit->align(etarget, sizeof(cell_t));
295*d18719a4STom Rini 	}
296*d18719a4STom Rini 
297*d18719a4STom Rini 	if ((vi->flags & FTF_NAMEPROPS) && !seen_name_prop) {
298*d18719a4STom Rini 		emit->property(etarget, NULL);
299*d18719a4STom Rini 		emit->cell(etarget, tree->basenamelen+1);
300*d18719a4STom Rini 		emit->cell(etarget, stringtable_insert(strbuf, "name"));
301*d18719a4STom Rini 
302*d18719a4STom Rini 		if ((vi->flags & FTF_VARALIGN) && ((tree->basenamelen+1) >= 8))
303*d18719a4STom Rini 			emit->align(etarget, 8);
304*d18719a4STom Rini 
305*d18719a4STom Rini 		emit->string(etarget, tree->name, tree->basenamelen);
306*d18719a4STom Rini 		emit->align(etarget, sizeof(cell_t));
307*d18719a4STom Rini 	}
308*d18719a4STom Rini 
309*d18719a4STom Rini 	for_each_child(tree, child) {
310*d18719a4STom Rini 		flatten_tree(child, emit, etarget, strbuf, vi);
311*d18719a4STom Rini 	}
312*d18719a4STom Rini 
313*d18719a4STom Rini 	emit->endnode(etarget, tree->labels);
314*d18719a4STom Rini }
315*d18719a4STom Rini 
316*d18719a4STom Rini static struct data flatten_reserve_list(struct reserve_info *reservelist,
317*d18719a4STom Rini 				 struct version_info *vi)
318*d18719a4STom Rini {
319*d18719a4STom Rini 	struct reserve_info *re;
320*d18719a4STom Rini 	struct data d = empty_data;
321*d18719a4STom Rini 	static struct fdt_reserve_entry null_re = {0,0};
322*d18719a4STom Rini 	int    j;
323*d18719a4STom Rini 
324*d18719a4STom Rini 	for (re = reservelist; re; re = re->next) {
325*d18719a4STom Rini 		d = data_append_re(d, &re->re);
326*d18719a4STom Rini 	}
327*d18719a4STom Rini 	/*
328*d18719a4STom Rini 	 * Add additional reserved slots if the user asked for them.
329*d18719a4STom Rini 	 */
330*d18719a4STom Rini 	for (j = 0; j < reservenum; j++) {
331*d18719a4STom Rini 		d = data_append_re(d, &null_re);
332*d18719a4STom Rini 	}
333*d18719a4STom Rini 
334*d18719a4STom Rini 	return d;
335*d18719a4STom Rini }
336*d18719a4STom Rini 
337*d18719a4STom Rini static void make_fdt_header(struct fdt_header *fdt,
338*d18719a4STom Rini 			    struct version_info *vi,
339*d18719a4STom Rini 			    int reservesize, int dtsize, int strsize,
340*d18719a4STom Rini 			    int boot_cpuid_phys)
341*d18719a4STom Rini {
342*d18719a4STom Rini 	int reserve_off;
343*d18719a4STom Rini 
344*d18719a4STom Rini 	reservesize += sizeof(struct fdt_reserve_entry);
345*d18719a4STom Rini 
346*d18719a4STom Rini 	memset(fdt, 0xff, sizeof(*fdt));
347*d18719a4STom Rini 
348*d18719a4STom Rini 	fdt->magic = cpu_to_fdt32(FDT_MAGIC);
349*d18719a4STom Rini 	fdt->version = cpu_to_fdt32(vi->version);
350*d18719a4STom Rini 	fdt->last_comp_version = cpu_to_fdt32(vi->last_comp_version);
351*d18719a4STom Rini 
352*d18719a4STom Rini 	/* Reserve map should be doubleword aligned */
353*d18719a4STom Rini 	reserve_off = ALIGN(vi->hdr_size, 8);
354*d18719a4STom Rini 
355*d18719a4STom Rini 	fdt->off_mem_rsvmap = cpu_to_fdt32(reserve_off);
356*d18719a4STom Rini 	fdt->off_dt_struct = cpu_to_fdt32(reserve_off + reservesize);
357*d18719a4STom Rini 	fdt->off_dt_strings = cpu_to_fdt32(reserve_off + reservesize
358*d18719a4STom Rini 					  + dtsize);
359*d18719a4STom Rini 	fdt->totalsize = cpu_to_fdt32(reserve_off + reservesize + dtsize + strsize);
360*d18719a4STom Rini 
361*d18719a4STom Rini 	if (vi->flags & FTF_BOOTCPUID)
362*d18719a4STom Rini 		fdt->boot_cpuid_phys = cpu_to_fdt32(boot_cpuid_phys);
363*d18719a4STom Rini 	if (vi->flags & FTF_STRTABSIZE)
364*d18719a4STom Rini 		fdt->size_dt_strings = cpu_to_fdt32(strsize);
365*d18719a4STom Rini 	if (vi->flags & FTF_STRUCTSIZE)
366*d18719a4STom Rini 		fdt->size_dt_struct = cpu_to_fdt32(dtsize);
367*d18719a4STom Rini }
368*d18719a4STom Rini 
369*d18719a4STom Rini void dt_to_blob(FILE *f, struct dt_info *dti, int version)
370*d18719a4STom Rini {
371*d18719a4STom Rini 	struct version_info *vi = NULL;
372*d18719a4STom Rini 	int i;
373*d18719a4STom Rini 	struct data blob       = empty_data;
374*d18719a4STom Rini 	struct data reservebuf = empty_data;
375*d18719a4STom Rini 	struct data dtbuf      = empty_data;
376*d18719a4STom Rini 	struct data strbuf     = empty_data;
377*d18719a4STom Rini 	struct fdt_header fdt;
378*d18719a4STom Rini 	int padlen = 0;
379*d18719a4STom Rini 
380*d18719a4STom Rini 	for (i = 0; i < ARRAY_SIZE(version_table); i++) {
381*d18719a4STom Rini 		if (version_table[i].version == version)
382*d18719a4STom Rini 			vi = &version_table[i];
383*d18719a4STom Rini 	}
384*d18719a4STom Rini 	if (!vi)
385*d18719a4STom Rini 		die("Unknown device tree blob version %d\n", version);
386*d18719a4STom Rini 
387*d18719a4STom Rini 	flatten_tree(dti->dt, &bin_emitter, &dtbuf, &strbuf, vi);
388*d18719a4STom Rini 	bin_emit_cell(&dtbuf, FDT_END);
389*d18719a4STom Rini 
390*d18719a4STom Rini 	reservebuf = flatten_reserve_list(dti->reservelist, vi);
391*d18719a4STom Rini 
392*d18719a4STom Rini 	/* Make header */
393*d18719a4STom Rini 	make_fdt_header(&fdt, vi, reservebuf.len, dtbuf.len, strbuf.len,
394*d18719a4STom Rini 			dti->boot_cpuid_phys);
395*d18719a4STom Rini 
396*d18719a4STom Rini 	/*
397*d18719a4STom Rini 	 * If the user asked for more space than is used, adjust the totalsize.
398*d18719a4STom Rini 	 */
399*d18719a4STom Rini 	if (minsize > 0) {
400*d18719a4STom Rini 		padlen = minsize - fdt32_to_cpu(fdt.totalsize);
401*d18719a4STom Rini 		if (padlen < 0) {
402*d18719a4STom Rini 			padlen = 0;
403*d18719a4STom Rini 			if (quiet < 1)
404*d18719a4STom Rini 				fprintf(stderr,
405*d18719a4STom Rini 					"Warning: blob size %d >= minimum size %d\n",
406*d18719a4STom Rini 					fdt32_to_cpu(fdt.totalsize), minsize);
407*d18719a4STom Rini 		}
408*d18719a4STom Rini 	}
409*d18719a4STom Rini 
410*d18719a4STom Rini 	if (padsize > 0)
411*d18719a4STom Rini 		padlen = padsize;
412*d18719a4STom Rini 
413*d18719a4STom Rini 	if (alignsize > 0)
414*d18719a4STom Rini 		padlen = ALIGN(fdt32_to_cpu(fdt.totalsize) + padlen, alignsize)
415*d18719a4STom Rini 			- fdt32_to_cpu(fdt.totalsize);
416*d18719a4STom Rini 
417*d18719a4STom Rini 	if (padlen > 0) {
418*d18719a4STom Rini 		int tsize = fdt32_to_cpu(fdt.totalsize);
419*d18719a4STom Rini 		tsize += padlen;
420*d18719a4STom Rini 		fdt.totalsize = cpu_to_fdt32(tsize);
421*d18719a4STom Rini 	}
422*d18719a4STom Rini 
423*d18719a4STom Rini 	/*
424*d18719a4STom Rini 	 * Assemble the blob: start with the header, add with alignment
425*d18719a4STom Rini 	 * the reserve buffer, add the reserve map terminating zeroes,
426*d18719a4STom Rini 	 * the device tree itself, and finally the strings.
427*d18719a4STom Rini 	 */
428*d18719a4STom Rini 	blob = data_append_data(blob, &fdt, vi->hdr_size);
429*d18719a4STom Rini 	blob = data_append_align(blob, 8);
430*d18719a4STom Rini 	blob = data_merge(blob, reservebuf);
431*d18719a4STom Rini 	blob = data_append_zeroes(blob, sizeof(struct fdt_reserve_entry));
432*d18719a4STom Rini 	blob = data_merge(blob, dtbuf);
433*d18719a4STom Rini 	blob = data_merge(blob, strbuf);
434*d18719a4STom Rini 
435*d18719a4STom Rini 	/*
436*d18719a4STom Rini 	 * If the user asked for more space than is used, pad out the blob.
437*d18719a4STom Rini 	 */
438*d18719a4STom Rini 	if (padlen > 0)
439*d18719a4STom Rini 		blob = data_append_zeroes(blob, padlen);
440*d18719a4STom Rini 
441*d18719a4STom Rini 	if (fwrite(blob.val, blob.len, 1, f) != 1) {
442*d18719a4STom Rini 		if (ferror(f))
443*d18719a4STom Rini 			die("Error writing device tree blob: %s\n",
444*d18719a4STom Rini 			    strerror(errno));
445*d18719a4STom Rini 		else
446*d18719a4STom Rini 			die("Short write on device tree blob\n");
447*d18719a4STom Rini 	}
448*d18719a4STom Rini 
449*d18719a4STom Rini 	/*
450*d18719a4STom Rini 	 * data_merge() frees the right-hand element so only the blob
451*d18719a4STom Rini 	 * remains to be freed.
452*d18719a4STom Rini 	 */
453*d18719a4STom Rini 	data_free(blob);
454*d18719a4STom Rini }
455*d18719a4STom Rini 
456*d18719a4STom Rini static void dump_stringtable_asm(FILE *f, struct data strbuf)
457*d18719a4STom Rini {
458*d18719a4STom Rini 	const char *p;
459*d18719a4STom Rini 	int len;
460*d18719a4STom Rini 
461*d18719a4STom Rini 	p = strbuf.val;
462*d18719a4STom Rini 
463*d18719a4STom Rini 	while (p < (strbuf.val + strbuf.len)) {
464*d18719a4STom Rini 		len = strlen(p);
465*d18719a4STom Rini 		fprintf(f, "\t.string \"%s\"\n", p);
466*d18719a4STom Rini 		p += len+1;
467*d18719a4STom Rini 	}
468*d18719a4STom Rini }
469*d18719a4STom Rini 
470*d18719a4STom Rini void dt_to_asm(FILE *f, struct dt_info *dti, int version)
471*d18719a4STom Rini {
472*d18719a4STom Rini 	struct version_info *vi = NULL;
473*d18719a4STom Rini 	int i;
474*d18719a4STom Rini 	struct data strbuf = empty_data;
475*d18719a4STom Rini 	struct reserve_info *re;
476*d18719a4STom Rini 	const char *symprefix = "dt";
477*d18719a4STom Rini 
478*d18719a4STom Rini 	for (i = 0; i < ARRAY_SIZE(version_table); i++) {
479*d18719a4STom Rini 		if (version_table[i].version == version)
480*d18719a4STom Rini 			vi = &version_table[i];
481*d18719a4STom Rini 	}
482*d18719a4STom Rini 	if (!vi)
483*d18719a4STom Rini 		die("Unknown device tree blob version %d\n", version);
484*d18719a4STom Rini 
485*d18719a4STom Rini 	fprintf(f, "/* autogenerated by dtc, do not edit */\n\n");
486*d18719a4STom Rini 
487*d18719a4STom Rini 	emit_label(f, symprefix, "blob_start");
488*d18719a4STom Rini 	emit_label(f, symprefix, "header");
489*d18719a4STom Rini 	fprintf(f, "\t/* magic */\n");
490*d18719a4STom Rini 	asm_emit_cell(f, FDT_MAGIC);
491*d18719a4STom Rini 	fprintf(f, "\t/* totalsize */\n");
492*d18719a4STom Rini 	ASM_EMIT_BELONG(f, "_%s_blob_abs_end - _%s_blob_start",
493*d18719a4STom Rini 			symprefix, symprefix);
494*d18719a4STom Rini 	fprintf(f, "\t/* off_dt_struct */\n");
495*d18719a4STom Rini 	ASM_EMIT_BELONG(f, "_%s_struct_start - _%s_blob_start",
496*d18719a4STom Rini 		symprefix, symprefix);
497*d18719a4STom Rini 	fprintf(f, "\t/* off_dt_strings */\n");
498*d18719a4STom Rini 	ASM_EMIT_BELONG(f, "_%s_strings_start - _%s_blob_start",
499*d18719a4STom Rini 		symprefix, symprefix);
500*d18719a4STom Rini 	fprintf(f, "\t/* off_mem_rsvmap */\n");
501*d18719a4STom Rini 	ASM_EMIT_BELONG(f, "_%s_reserve_map - _%s_blob_start",
502*d18719a4STom Rini 		symprefix, symprefix);
503*d18719a4STom Rini 	fprintf(f, "\t/* version */\n");
504*d18719a4STom Rini 	asm_emit_cell(f, vi->version);
505*d18719a4STom Rini 	fprintf(f, "\t/* last_comp_version */\n");
506*d18719a4STom Rini 	asm_emit_cell(f, vi->last_comp_version);
507*d18719a4STom Rini 
508*d18719a4STom Rini 	if (vi->flags & FTF_BOOTCPUID) {
509*d18719a4STom Rini 		fprintf(f, "\t/* boot_cpuid_phys */\n");
510*d18719a4STom Rini 		asm_emit_cell(f, dti->boot_cpuid_phys);
511*d18719a4STom Rini 	}
512*d18719a4STom Rini 
513*d18719a4STom Rini 	if (vi->flags & FTF_STRTABSIZE) {
514*d18719a4STom Rini 		fprintf(f, "\t/* size_dt_strings */\n");
515*d18719a4STom Rini 		ASM_EMIT_BELONG(f, "_%s_strings_end - _%s_strings_start",
516*d18719a4STom Rini 				symprefix, symprefix);
517*d18719a4STom Rini 	}
518*d18719a4STom Rini 
519*d18719a4STom Rini 	if (vi->flags & FTF_STRUCTSIZE) {
520*d18719a4STom Rini 		fprintf(f, "\t/* size_dt_struct */\n");
521*d18719a4STom Rini 		ASM_EMIT_BELONG(f, "_%s_struct_end - _%s_struct_start",
522*d18719a4STom Rini 			symprefix, symprefix);
523*d18719a4STom Rini 	}
524*d18719a4STom Rini 
525*d18719a4STom Rini 	/*
526*d18719a4STom Rini 	 * Reserve map entries.
527*d18719a4STom Rini 	 * Align the reserve map to a doubleword boundary.
528*d18719a4STom Rini 	 * Each entry is an (address, size) pair of u64 values.
529*d18719a4STom Rini 	 * Always supply a zero-sized temination entry.
530*d18719a4STom Rini 	 */
531*d18719a4STom Rini 	asm_emit_align(f, 8);
532*d18719a4STom Rini 	emit_label(f, symprefix, "reserve_map");
533*d18719a4STom Rini 
534*d18719a4STom Rini 	fprintf(f, "/* Memory reserve map from source file */\n");
535*d18719a4STom Rini 
536*d18719a4STom Rini 	/*
537*d18719a4STom Rini 	 * Use .long on high and low halfs of u64s to avoid .quad
538*d18719a4STom Rini 	 * as it appears .quad isn't available in some assemblers.
539*d18719a4STom Rini 	 */
540*d18719a4STom Rini 	for (re = dti->reservelist; re; re = re->next) {
541*d18719a4STom Rini 		struct label *l;
542*d18719a4STom Rini 
543*d18719a4STom Rini 		for_each_label(re->labels, l) {
544*d18719a4STom Rini 			fprintf(f, "\t.globl\t%s\n", l->label);
545*d18719a4STom Rini 			fprintf(f, "%s:\n", l->label);
546*d18719a4STom Rini 		}
547*d18719a4STom Rini 		ASM_EMIT_BELONG(f, "0x%08x", (unsigned int)(re->re.address >> 32));
548*d18719a4STom Rini 		ASM_EMIT_BELONG(f, "0x%08x",
549*d18719a4STom Rini 				(unsigned int)(re->re.address & 0xffffffff));
550*d18719a4STom Rini 		ASM_EMIT_BELONG(f, "0x%08x", (unsigned int)(re->re.size >> 32));
551*d18719a4STom Rini 		ASM_EMIT_BELONG(f, "0x%08x", (unsigned int)(re->re.size & 0xffffffff));
552*d18719a4STom Rini 	}
553*d18719a4STom Rini 	for (i = 0; i < reservenum; i++) {
554*d18719a4STom Rini 		fprintf(f, "\t.long\t0, 0\n\t.long\t0, 0\n");
555*d18719a4STom Rini 	}
556*d18719a4STom Rini 
557*d18719a4STom Rini 	fprintf(f, "\t.long\t0, 0\n\t.long\t0, 0\n");
558*d18719a4STom Rini 
559*d18719a4STom Rini 	emit_label(f, symprefix, "struct_start");
560*d18719a4STom Rini 	flatten_tree(dti->dt, &asm_emitter, f, &strbuf, vi);
561*d18719a4STom Rini 
562*d18719a4STom Rini 	fprintf(f, "\t/* FDT_END */\n");
563*d18719a4STom Rini 	asm_emit_cell(f, FDT_END);
564*d18719a4STom Rini 	emit_label(f, symprefix, "struct_end");
565*d18719a4STom Rini 
566*d18719a4STom Rini 	emit_label(f, symprefix, "strings_start");
567*d18719a4STom Rini 	dump_stringtable_asm(f, strbuf);
568*d18719a4STom Rini 	emit_label(f, symprefix, "strings_end");
569*d18719a4STom Rini 
570*d18719a4STom Rini 	emit_label(f, symprefix, "blob_end");
571*d18719a4STom Rini 
572*d18719a4STom Rini 	/*
573*d18719a4STom Rini 	 * If the user asked for more space than is used, pad it out.
574*d18719a4STom Rini 	 */
575*d18719a4STom Rini 	if (minsize > 0) {
576*d18719a4STom Rini 		fprintf(f, "\t.space\t%d - (_%s_blob_end - _%s_blob_start), 0\n",
577*d18719a4STom Rini 			minsize, symprefix, symprefix);
578*d18719a4STom Rini 	}
579*d18719a4STom Rini 	if (padsize > 0) {
580*d18719a4STom Rini 		fprintf(f, "\t.space\t%d, 0\n", padsize);
581*d18719a4STom Rini 	}
582*d18719a4STom Rini 	if (alignsize > 0)
583*d18719a4STom Rini 		asm_emit_align(f, alignsize);
584*d18719a4STom Rini 	emit_label(f, symprefix, "blob_abs_end");
585*d18719a4STom Rini 
586*d18719a4STom Rini 	data_free(strbuf);
587*d18719a4STom Rini }
588*d18719a4STom Rini 
589*d18719a4STom Rini struct inbuf {
590*d18719a4STom Rini 	char *base, *limit, *ptr;
591*d18719a4STom Rini };
592*d18719a4STom Rini 
593*d18719a4STom Rini static void inbuf_init(struct inbuf *inb, void *base, void *limit)
594*d18719a4STom Rini {
595*d18719a4STom Rini 	inb->base = base;
596*d18719a4STom Rini 	inb->limit = limit;
597*d18719a4STom Rini 	inb->ptr = inb->base;
598*d18719a4STom Rini }
599*d18719a4STom Rini 
600*d18719a4STom Rini static void flat_read_chunk(struct inbuf *inb, void *p, int len)
601*d18719a4STom Rini {
602*d18719a4STom Rini 	if ((inb->ptr + len) > inb->limit)
603*d18719a4STom Rini 		die("Premature end of data parsing flat device tree\n");
604*d18719a4STom Rini 
605*d18719a4STom Rini 	memcpy(p, inb->ptr, len);
606*d18719a4STom Rini 
607*d18719a4STom Rini 	inb->ptr += len;
608*d18719a4STom Rini }
609*d18719a4STom Rini 
610*d18719a4STom Rini static uint32_t flat_read_word(struct inbuf *inb)
611*d18719a4STom Rini {
612*d18719a4STom Rini 	uint32_t val;
613*d18719a4STom Rini 
614*d18719a4STom Rini 	assert(((inb->ptr - inb->base) % sizeof(val)) == 0);
615*d18719a4STom Rini 
616*d18719a4STom Rini 	flat_read_chunk(inb, &val, sizeof(val));
617*d18719a4STom Rini 
618*d18719a4STom Rini 	return fdt32_to_cpu(val);
619*d18719a4STom Rini }
620*d18719a4STom Rini 
621*d18719a4STom Rini static void flat_realign(struct inbuf *inb, int align)
622*d18719a4STom Rini {
623*d18719a4STom Rini 	int off = inb->ptr - inb->base;
624*d18719a4STom Rini 
625*d18719a4STom Rini 	inb->ptr = inb->base + ALIGN(off, align);
626*d18719a4STom Rini 	if (inb->ptr > inb->limit)
627*d18719a4STom Rini 		die("Premature end of data parsing flat device tree\n");
628*d18719a4STom Rini }
629*d18719a4STom Rini 
630*d18719a4STom Rini static char *flat_read_string(struct inbuf *inb)
631*d18719a4STom Rini {
632*d18719a4STom Rini 	int len = 0;
633*d18719a4STom Rini 	const char *p = inb->ptr;
634*d18719a4STom Rini 	char *str;
635*d18719a4STom Rini 
636*d18719a4STom Rini 	do {
637*d18719a4STom Rini 		if (p >= inb->limit)
638*d18719a4STom Rini 			die("Premature end of data parsing flat device tree\n");
639*d18719a4STom Rini 		len++;
640*d18719a4STom Rini 	} while ((*p++) != '\0');
641*d18719a4STom Rini 
642*d18719a4STom Rini 	str = xstrdup(inb->ptr);
643*d18719a4STom Rini 
644*d18719a4STom Rini 	inb->ptr += len;
645*d18719a4STom Rini 
646*d18719a4STom Rini 	flat_realign(inb, sizeof(uint32_t));
647*d18719a4STom Rini 
648*d18719a4STom Rini 	return str;
649*d18719a4STom Rini }
650*d18719a4STom Rini 
651*d18719a4STom Rini static struct data flat_read_data(struct inbuf *inb, int len)
652*d18719a4STom Rini {
653*d18719a4STom Rini 	struct data d = empty_data;
654*d18719a4STom Rini 
655*d18719a4STom Rini 	if (len == 0)
656*d18719a4STom Rini 		return empty_data;
657*d18719a4STom Rini 
658*d18719a4STom Rini 	d = data_grow_for(d, len);
659*d18719a4STom Rini 	d.len = len;
660*d18719a4STom Rini 
661*d18719a4STom Rini 	flat_read_chunk(inb, d.val, len);
662*d18719a4STom Rini 
663*d18719a4STom Rini 	flat_realign(inb, sizeof(uint32_t));
664*d18719a4STom Rini 
665*d18719a4STom Rini 	return d;
666*d18719a4STom Rini }
667*d18719a4STom Rini 
668*d18719a4STom Rini static char *flat_read_stringtable(struct inbuf *inb, int offset)
669*d18719a4STom Rini {
670*d18719a4STom Rini 	const char *p;
671*d18719a4STom Rini 
672*d18719a4STom Rini 	p = inb->base + offset;
673*d18719a4STom Rini 	while (1) {
674*d18719a4STom Rini 		if (p >= inb->limit || p < inb->base)
675*d18719a4STom Rini 			die("String offset %d overruns string table\n",
676*d18719a4STom Rini 			    offset);
677*d18719a4STom Rini 
678*d18719a4STom Rini 		if (*p == '\0')
679*d18719a4STom Rini 			break;
680*d18719a4STom Rini 
681*d18719a4STom Rini 		p++;
682*d18719a4STom Rini 	}
683*d18719a4STom Rini 
684*d18719a4STom Rini 	return xstrdup(inb->base + offset);
685*d18719a4STom Rini }
686*d18719a4STom Rini 
687*d18719a4STom Rini static struct property *flat_read_property(struct inbuf *dtbuf,
688*d18719a4STom Rini 					   struct inbuf *strbuf, int flags)
689*d18719a4STom Rini {
690*d18719a4STom Rini 	uint32_t proplen, stroff;
691*d18719a4STom Rini 	char *name;
692*d18719a4STom Rini 	struct data val;
693*d18719a4STom Rini 
694*d18719a4STom Rini 	proplen = flat_read_word(dtbuf);
695*d18719a4STom Rini 	stroff = flat_read_word(dtbuf);
696*d18719a4STom Rini 
697*d18719a4STom Rini 	name = flat_read_stringtable(strbuf, stroff);
698*d18719a4STom Rini 
699*d18719a4STom Rini 	if ((flags & FTF_VARALIGN) && (proplen >= 8))
700*d18719a4STom Rini 		flat_realign(dtbuf, 8);
701*d18719a4STom Rini 
702*d18719a4STom Rini 	val = flat_read_data(dtbuf, proplen);
703*d18719a4STom Rini 
704*d18719a4STom Rini 	return build_property(name, val);
705*d18719a4STom Rini }
706*d18719a4STom Rini 
707*d18719a4STom Rini 
708*d18719a4STom Rini static struct reserve_info *flat_read_mem_reserve(struct inbuf *inb)
709*d18719a4STom Rini {
710*d18719a4STom Rini 	struct reserve_info *reservelist = NULL;
711*d18719a4STom Rini 	struct reserve_info *new;
712*d18719a4STom Rini 	struct fdt_reserve_entry re;
713*d18719a4STom Rini 
714*d18719a4STom Rini 	/*
715*d18719a4STom Rini 	 * Each entry is a pair of u64 (addr, size) values for 4 cell_t's.
716*d18719a4STom Rini 	 * List terminates at an entry with size equal to zero.
717*d18719a4STom Rini 	 *
718*d18719a4STom Rini 	 * First pass, count entries.
719*d18719a4STom Rini 	 */
720*d18719a4STom Rini 	while (1) {
721*d18719a4STom Rini 		flat_read_chunk(inb, &re, sizeof(re));
722*d18719a4STom Rini 		re.address  = fdt64_to_cpu(re.address);
723*d18719a4STom Rini 		re.size = fdt64_to_cpu(re.size);
724*d18719a4STom Rini 		if (re.size == 0)
725*d18719a4STom Rini 			break;
726*d18719a4STom Rini 
727*d18719a4STom Rini 		new = build_reserve_entry(re.address, re.size);
728*d18719a4STom Rini 		reservelist = add_reserve_entry(reservelist, new);
729*d18719a4STom Rini 	}
730*d18719a4STom Rini 
731*d18719a4STom Rini 	return reservelist;
732*d18719a4STom Rini }
733*d18719a4STom Rini 
734*d18719a4STom Rini 
735*d18719a4STom Rini static char *nodename_from_path(const char *ppath, const char *cpath)
736*d18719a4STom Rini {
737*d18719a4STom Rini 	int plen;
738*d18719a4STom Rini 
739*d18719a4STom Rini 	plen = strlen(ppath);
740*d18719a4STom Rini 
741*d18719a4STom Rini 	if (!strneq(ppath, cpath, plen))
742*d18719a4STom Rini 		die("Path \"%s\" is not valid as a child of \"%s\"\n",
743*d18719a4STom Rini 		    cpath, ppath);
744*d18719a4STom Rini 
745*d18719a4STom Rini 	/* root node is a special case */
746*d18719a4STom Rini 	if (!streq(ppath, "/"))
747*d18719a4STom Rini 		plen++;
748*d18719a4STom Rini 
749*d18719a4STom Rini 	return xstrdup(cpath + plen);
750*d18719a4STom Rini }
751*d18719a4STom Rini 
752*d18719a4STom Rini static struct node *unflatten_tree(struct inbuf *dtbuf,
753*d18719a4STom Rini 				   struct inbuf *strbuf,
754*d18719a4STom Rini 				   const char *parent_flatname, int flags)
755*d18719a4STom Rini {
756*d18719a4STom Rini 	struct node *node;
757*d18719a4STom Rini 	char *flatname;
758*d18719a4STom Rini 	uint32_t val;
759*d18719a4STom Rini 
760*d18719a4STom Rini 	node = build_node(NULL, NULL);
761*d18719a4STom Rini 
762*d18719a4STom Rini 	flatname = flat_read_string(dtbuf);
763*d18719a4STom Rini 
764*d18719a4STom Rini 	if (flags & FTF_FULLPATH)
765*d18719a4STom Rini 		node->name = nodename_from_path(parent_flatname, flatname);
766*d18719a4STom Rini 	else
767*d18719a4STom Rini 		node->name = flatname;
768*d18719a4STom Rini 
769*d18719a4STom Rini 	do {
770*d18719a4STom Rini 		struct property *prop;
771*d18719a4STom Rini 		struct node *child;
772*d18719a4STom Rini 
773*d18719a4STom Rini 		val = flat_read_word(dtbuf);
774*d18719a4STom Rini 		switch (val) {
775*d18719a4STom Rini 		case FDT_PROP:
776*d18719a4STom Rini 			if (node->children)
777*d18719a4STom Rini 				fprintf(stderr, "Warning: Flat tree input has "
778*d18719a4STom Rini 					"subnodes preceding a property.\n");
779*d18719a4STom Rini 			prop = flat_read_property(dtbuf, strbuf, flags);
780*d18719a4STom Rini 			add_property(node, prop);
781*d18719a4STom Rini 			break;
782*d18719a4STom Rini 
783*d18719a4STom Rini 		case FDT_BEGIN_NODE:
784*d18719a4STom Rini 			child = unflatten_tree(dtbuf,strbuf, flatname, flags);
785*d18719a4STom Rini 			add_child(node, child);
786*d18719a4STom Rini 			break;
787*d18719a4STom Rini 
788*d18719a4STom Rini 		case FDT_END_NODE:
789*d18719a4STom Rini 			break;
790*d18719a4STom Rini 
791*d18719a4STom Rini 		case FDT_END:
792*d18719a4STom Rini 			die("Premature FDT_END in device tree blob\n");
793*d18719a4STom Rini 			break;
794*d18719a4STom Rini 
795*d18719a4STom Rini 		case FDT_NOP:
796*d18719a4STom Rini 			if (!(flags & FTF_NOPS))
797*d18719a4STom Rini 				fprintf(stderr, "Warning: NOP tag found in flat tree"
798*d18719a4STom Rini 					" version <16\n");
799*d18719a4STom Rini 
800*d18719a4STom Rini 			/* Ignore */
801*d18719a4STom Rini 			break;
802*d18719a4STom Rini 
803*d18719a4STom Rini 		default:
804*d18719a4STom Rini 			die("Invalid opcode word %08x in device tree blob\n",
805*d18719a4STom Rini 			    val);
806*d18719a4STom Rini 		}
807*d18719a4STom Rini 	} while (val != FDT_END_NODE);
808*d18719a4STom Rini 
809*d18719a4STom Rini 	if (node->name != flatname) {
810*d18719a4STom Rini 		free(flatname);
811*d18719a4STom Rini 	}
812*d18719a4STom Rini 
813*d18719a4STom Rini 	return node;
814*d18719a4STom Rini }
815*d18719a4STom Rini 
816*d18719a4STom Rini 
817*d18719a4STom Rini struct dt_info *dt_from_blob(const char *fname)
818*d18719a4STom Rini {
819*d18719a4STom Rini 	FILE *f;
820*d18719a4STom Rini 	uint32_t magic, totalsize, version, size_dt, boot_cpuid_phys;
821*d18719a4STom Rini 	uint32_t off_dt, off_str, off_mem_rsvmap;
822*d18719a4STom Rini 	int rc;
823*d18719a4STom Rini 	char *blob;
824*d18719a4STom Rini 	struct fdt_header *fdt;
825*d18719a4STom Rini 	char *p;
826*d18719a4STom Rini 	struct inbuf dtbuf, strbuf;
827*d18719a4STom Rini 	struct inbuf memresvbuf;
828*d18719a4STom Rini 	int sizeleft;
829*d18719a4STom Rini 	struct reserve_info *reservelist;
830*d18719a4STom Rini 	struct node *tree;
831*d18719a4STom Rini 	uint32_t val;
832*d18719a4STom Rini 	int flags = 0;
833*d18719a4STom Rini 
834*d18719a4STom Rini 	f = srcfile_relative_open(fname, NULL);
835*d18719a4STom Rini 
836*d18719a4STom Rini 	rc = fread(&magic, sizeof(magic), 1, f);
837*d18719a4STom Rini 	if (ferror(f))
838*d18719a4STom Rini 		die("Error reading DT blob magic number: %s\n",
839*d18719a4STom Rini 		    strerror(errno));
840*d18719a4STom Rini 	if (rc < 1) {
841*d18719a4STom Rini 		if (feof(f))
842*d18719a4STom Rini 			die("EOF reading DT blob magic number\n");
843*d18719a4STom Rini 		else
844*d18719a4STom Rini 			die("Mysterious short read reading magic number\n");
845*d18719a4STom Rini 	}
846*d18719a4STom Rini 
847*d18719a4STom Rini 	magic = fdt32_to_cpu(magic);
848*d18719a4STom Rini 	if (magic != FDT_MAGIC)
849*d18719a4STom Rini 		die("Blob has incorrect magic number\n");
850*d18719a4STom Rini 
851*d18719a4STom Rini 	rc = fread(&totalsize, sizeof(totalsize), 1, f);
852*d18719a4STom Rini 	if (ferror(f))
853*d18719a4STom Rini 		die("Error reading DT blob size: %s\n", strerror(errno));
854*d18719a4STom Rini 	if (rc < 1) {
855*d18719a4STom Rini 		if (feof(f))
856*d18719a4STom Rini 			die("EOF reading DT blob size\n");
857*d18719a4STom Rini 		else
858*d18719a4STom Rini 			die("Mysterious short read reading blob size\n");
859*d18719a4STom Rini 	}
860*d18719a4STom Rini 
861*d18719a4STom Rini 	totalsize = fdt32_to_cpu(totalsize);
862*d18719a4STom Rini 	if (totalsize < FDT_V1_SIZE)
863*d18719a4STom Rini 		die("DT blob size (%d) is too small\n", totalsize);
864*d18719a4STom Rini 
865*d18719a4STom Rini 	blob = xmalloc(totalsize);
866*d18719a4STom Rini 
867*d18719a4STom Rini 	fdt = (struct fdt_header *)blob;
868*d18719a4STom Rini 	fdt->magic = cpu_to_fdt32(magic);
869*d18719a4STom Rini 	fdt->totalsize = cpu_to_fdt32(totalsize);
870*d18719a4STom Rini 
871*d18719a4STom Rini 	sizeleft = totalsize - sizeof(magic) - sizeof(totalsize);
872*d18719a4STom Rini 	p = blob + sizeof(magic)  + sizeof(totalsize);
873*d18719a4STom Rini 
874*d18719a4STom Rini 	while (sizeleft) {
875*d18719a4STom Rini 		if (feof(f))
876*d18719a4STom Rini 			die("EOF before reading %d bytes of DT blob\n",
877*d18719a4STom Rini 			    totalsize);
878*d18719a4STom Rini 
879*d18719a4STom Rini 		rc = fread(p, 1, sizeleft, f);
880*d18719a4STom Rini 		if (ferror(f))
881*d18719a4STom Rini 			die("Error reading DT blob: %s\n",
882*d18719a4STom Rini 			    strerror(errno));
883*d18719a4STom Rini 
884*d18719a4STom Rini 		sizeleft -= rc;
885*d18719a4STom Rini 		p += rc;
886*d18719a4STom Rini 	}
887*d18719a4STom Rini 
888*d18719a4STom Rini 	off_dt = fdt32_to_cpu(fdt->off_dt_struct);
889*d18719a4STom Rini 	off_str = fdt32_to_cpu(fdt->off_dt_strings);
890*d18719a4STom Rini 	off_mem_rsvmap = fdt32_to_cpu(fdt->off_mem_rsvmap);
891*d18719a4STom Rini 	version = fdt32_to_cpu(fdt->version);
892*d18719a4STom Rini 	boot_cpuid_phys = fdt32_to_cpu(fdt->boot_cpuid_phys);
893*d18719a4STom Rini 
894*d18719a4STom Rini 	if (off_mem_rsvmap >= totalsize)
895*d18719a4STom Rini 		die("Mem Reserve structure offset exceeds total size\n");
896*d18719a4STom Rini 
897*d18719a4STom Rini 	if (off_dt >= totalsize)
898*d18719a4STom Rini 		die("DT structure offset exceeds total size\n");
899*d18719a4STom Rini 
900*d18719a4STom Rini 	if (off_str > totalsize)
901*d18719a4STom Rini 		die("String table offset exceeds total size\n");
902*d18719a4STom Rini 
903*d18719a4STom Rini 	if (version >= 3) {
904*d18719a4STom Rini 		uint32_t size_str = fdt32_to_cpu(fdt->size_dt_strings);
905*d18719a4STom Rini 		if ((off_str+size_str < off_str) || (off_str+size_str > totalsize))
906*d18719a4STom Rini 			die("String table extends past total size\n");
907*d18719a4STom Rini 		inbuf_init(&strbuf, blob + off_str, blob + off_str + size_str);
908*d18719a4STom Rini 	} else {
909*d18719a4STom Rini 		inbuf_init(&strbuf, blob + off_str, blob + totalsize);
910*d18719a4STom Rini 	}
911*d18719a4STom Rini 
912*d18719a4STom Rini 	if (version >= 17) {
913*d18719a4STom Rini 		size_dt = fdt32_to_cpu(fdt->size_dt_struct);
914*d18719a4STom Rini 		if ((off_dt+size_dt < off_dt) || (off_dt+size_dt > totalsize))
915*d18719a4STom Rini 			die("Structure block extends past total size\n");
916*d18719a4STom Rini 	}
917*d18719a4STom Rini 
918*d18719a4STom Rini 	if (version < 16) {
919*d18719a4STom Rini 		flags |= FTF_FULLPATH | FTF_NAMEPROPS | FTF_VARALIGN;
920*d18719a4STom Rini 	} else {
921*d18719a4STom Rini 		flags |= FTF_NOPS;
922*d18719a4STom Rini 	}
923*d18719a4STom Rini 
924*d18719a4STom Rini 	inbuf_init(&memresvbuf,
925*d18719a4STom Rini 		   blob + off_mem_rsvmap, blob + totalsize);
926*d18719a4STom Rini 	inbuf_init(&dtbuf, blob + off_dt, blob + totalsize);
927*d18719a4STom Rini 
928*d18719a4STom Rini 	reservelist = flat_read_mem_reserve(&memresvbuf);
929*d18719a4STom Rini 
930*d18719a4STom Rini 	val = flat_read_word(&dtbuf);
931*d18719a4STom Rini 
932*d18719a4STom Rini 	if (val != FDT_BEGIN_NODE)
933*d18719a4STom Rini 		die("Device tree blob doesn't begin with FDT_BEGIN_NODE (begins with 0x%08x)\n", val);
934*d18719a4STom Rini 
935*d18719a4STom Rini 	tree = unflatten_tree(&dtbuf, &strbuf, "", flags);
936*d18719a4STom Rini 
937*d18719a4STom Rini 	val = flat_read_word(&dtbuf);
938*d18719a4STom Rini 	if (val != FDT_END)
939*d18719a4STom Rini 		die("Device tree blob doesn't end with FDT_END\n");
940*d18719a4STom Rini 
941*d18719a4STom Rini 	free(blob);
942*d18719a4STom Rini 
943*d18719a4STom Rini 	fclose(f);
944*d18719a4STom Rini 
945*d18719a4STom Rini 	return build_dt_info(DTSF_V1, reservelist, tree, boot_cpuid_phys);
946*d18719a4STom Rini }
947