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