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