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