blob: 588990036eac5a15e4b58db6650de392bffd6320 [file] [log] [blame]
David Gibsonfc14dad2005-06-08 17:18:34 +10001/*
2 * (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation. 2005.
3 *
David Gibson63dc9c72007-09-18 11:44:04 +10004 *
David Gibsonfc14dad2005-06-08 17:18:34 +10005 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation; either version 2 of the
8 * License, or (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
David Gibson63dc9c72007-09-18 11:44:04 +100014 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
18 * USA
David Gibsonfc14dad2005-06-08 17:18:34 +100019 */
20
21#include "dtc.h"
David Gibsonfc14dad2005-06-08 17:18:34 +100022
23#define FTF_FULLPATH 0x1
24#define FTF_VARALIGN 0x2
25#define FTF_NAMEPROPS 0x4
26#define FTF_BOOTCPUID 0x8
27#define FTF_STRTABSIZE 0x10
David Gibson46c88df2007-03-14 11:02:40 +110028#define FTF_STRUCTSIZE 0x20
Milton Millerce243222007-06-09 23:21:31 -050029#define FTF_NOPS 0x40
David Gibsonfc14dad2005-06-08 17:18:34 +100030
David Gibson230f2532005-08-29 12:48:02 +100031static struct version_info {
David Gibsonfc14dad2005-06-08 17:18:34 +100032 int version;
33 int last_comp_version;
34 int hdr_size;
35 int flags;
36} version_table[] = {
David Gibsonfb7c7ac2007-09-26 13:11:05 +100037 {1, 1, FDT_V1_SIZE,
David Gibsonfc14dad2005-06-08 17:18:34 +100038 FTF_FULLPATH|FTF_VARALIGN|FTF_NAMEPROPS},
David Gibsonfb7c7ac2007-09-26 13:11:05 +100039 {2, 1, FDT_V2_SIZE,
David Gibsonfc14dad2005-06-08 17:18:34 +100040 FTF_FULLPATH|FTF_VARALIGN|FTF_NAMEPROPS|FTF_BOOTCPUID},
David Gibsonfb7c7ac2007-09-26 13:11:05 +100041 {3, 1, FDT_V3_SIZE,
David Gibsonfc14dad2005-06-08 17:18:34 +100042 FTF_FULLPATH|FTF_VARALIGN|FTF_NAMEPROPS|FTF_BOOTCPUID|FTF_STRTABSIZE},
David Gibsonfb7c7ac2007-09-26 13:11:05 +100043 {16, 16, FDT_V3_SIZE,
Milton Millerce243222007-06-09 23:21:31 -050044 FTF_BOOTCPUID|FTF_STRTABSIZE|FTF_NOPS},
David Gibsonfb7c7ac2007-09-26 13:11:05 +100045 {17, 16, FDT_V17_SIZE,
Milton Millerce243222007-06-09 23:21:31 -050046 FTF_BOOTCPUID|FTF_STRTABSIZE|FTF_STRUCTSIZE|FTF_NOPS},
David Gibsonfc14dad2005-06-08 17:18:34 +100047};
48
49struct emitter {
50 void (*cell)(void *, cell_t);
51 void (*string)(void *, char *, int);
52 void (*align)(void *, int);
53 void (*data)(void *, struct data);
David Gibson4102d842005-06-16 14:36:37 +100054 void (*beginnode)(void *, char *);
55 void (*endnode)(void *, char *);
56 void (*property)(void *, char *);
David Gibsonfc14dad2005-06-08 17:18:34 +100057};
58
59static void bin_emit_cell(void *e, cell_t val)
60{
61 struct data *dtbuf = e;
62
63 *dtbuf = data_append_cell(*dtbuf, val);
64}
65
66static void bin_emit_string(void *e, char *str, int len)
67{
68 struct data *dtbuf = e;
69
70 if (len == 0)
71 len = strlen(str);
72
73 *dtbuf = data_append_data(*dtbuf, str, len);
74 *dtbuf = data_append_byte(*dtbuf, '\0');
75}
76
77static void bin_emit_align(void *e, int a)
78{
79 struct data *dtbuf = e;
80
81 *dtbuf = data_append_align(*dtbuf, a);
82}
83
84static void bin_emit_data(void *e, struct data d)
85{
86 struct data *dtbuf = e;
87
88 *dtbuf = data_append_data(*dtbuf, d.val, d.len);
89}
90
David Gibson4102d842005-06-16 14:36:37 +100091static void bin_emit_beginnode(void *e, char *label)
David Gibsonfc14dad2005-06-08 17:18:34 +100092{
David Gibsonfb7c7ac2007-09-26 13:11:05 +100093 bin_emit_cell(e, FDT_BEGIN_NODE);
David Gibsonfc14dad2005-06-08 17:18:34 +100094}
95
David Gibson4102d842005-06-16 14:36:37 +100096static void bin_emit_endnode(void *e, char *label)
David Gibsonfc14dad2005-06-08 17:18:34 +100097{
David Gibsonfb7c7ac2007-09-26 13:11:05 +100098 bin_emit_cell(e, FDT_END_NODE);
David Gibsonfc14dad2005-06-08 17:18:34 +100099}
100
David Gibson4102d842005-06-16 14:36:37 +1000101static void bin_emit_property(void *e, char *label)
David Gibsonfc14dad2005-06-08 17:18:34 +1000102{
David Gibsonfb7c7ac2007-09-26 13:11:05 +1000103 bin_emit_cell(e, FDT_PROP);
David Gibsonfc14dad2005-06-08 17:18:34 +1000104}
105
David Gibson230f2532005-08-29 12:48:02 +1000106static struct emitter bin_emitter = {
David Gibsonfc14dad2005-06-08 17:18:34 +1000107 .cell = bin_emit_cell,
108 .string = bin_emit_string,
109 .align = bin_emit_align,
110 .data = bin_emit_data,
111 .beginnode = bin_emit_beginnode,
112 .endnode = bin_emit_endnode,
David Gibson63dc9c72007-09-18 11:44:04 +1000113 .property = bin_emit_property,
David Gibsonfc14dad2005-06-08 17:18:34 +1000114};
115
David Gibson230f2532005-08-29 12:48:02 +1000116static void emit_label(FILE *f, char *prefix, char *label)
David Gibson4102d842005-06-16 14:36:37 +1000117{
118 fprintf(f, "\t.globl\t%s_%s\n", prefix, label);
119 fprintf(f, "%s_%s:\n", prefix, label);
120 fprintf(f, "_%s_%s:\n", prefix, label);
121}
122
Milton Miller6a99b132007-07-07 01:18:51 -0500123static void emit_offset_label(FILE *f, char *label, int offset)
124{
125 fprintf(f, "\t.globl\t%s\n", label);
126 fprintf(f, "%s\t= . + %d\n", label, offset);
127}
128
David Gibsonfc14dad2005-06-08 17:18:34 +1000129static void asm_emit_cell(void *e, cell_t val)
130{
131 FILE *f = e;
132
Mark A. Greer7a9f6632006-03-15 18:59:24 -0700133 fprintf(f, "\t.long\t0x%x\n", val);
David Gibsonfc14dad2005-06-08 17:18:34 +1000134}
135
136static void asm_emit_string(void *e, char *str, int len)
137{
138 FILE *f = e;
Jon Loeliger2d50f8f2007-10-18 09:46:52 -0500139 char c = 0;
David Gibsonfc14dad2005-06-08 17:18:34 +1000140
141 if (len != 0) {
142 /* XXX: ewww */
143 c = str[len];
144 str[len] = '\0';
145 }
David Gibson63dc9c72007-09-18 11:44:04 +1000146
David Gibsonfc14dad2005-06-08 17:18:34 +1000147 fprintf(f, "\t.string\t\"%s\"\n", str);
148
149 if (len != 0) {
150 str[len] = c;
151 }
152}
153
154static void asm_emit_align(void *e, int a)
155{
156 FILE *f = e;
157
158 fprintf(f, "\t.balign\t%d\n", a);
159}
160
161static void asm_emit_data(void *e, struct data d)
162{
163 FILE *f = e;
164 int off = 0;
Milton Miller6a99b132007-07-07 01:18:51 -0500165 struct fixup *l;
166
167 l = d.labels;
168 while (l) {
169 emit_offset_label(f, l->ref, l->offset);
170 l = l->next;
171 }
David Gibsonfc14dad2005-06-08 17:18:34 +1000172
173 while ((d.len - off) >= sizeof(u32)) {
174 fprintf(f, "\t.long\t0x%x\n",
175 be32_to_cpu(*((u32 *)(d.val+off))));
176 off += sizeof(u32);
177 }
178
179 if ((d.len - off) >= sizeof(u16)) {
David Gibson63dc9c72007-09-18 11:44:04 +1000180 fprintf(f, "\t.short\t0x%hx\n",
David Gibsonfc14dad2005-06-08 17:18:34 +1000181 be16_to_cpu(*((u16 *)(d.val+off))));
182 off += sizeof(u16);
183 }
184
185 if ((d.len - off) >= 1) {
186 fprintf(f, "\t.byte\t0x%hhx\n", d.val[off]);
187 off += 1;
188 }
189
190 assert(off == d.len);
191}
192
David Gibson4102d842005-06-16 14:36:37 +1000193static void asm_emit_beginnode(void *e, char *label)
David Gibsonfc14dad2005-06-08 17:18:34 +1000194{
195 FILE *f = e;
196
David Gibson4102d842005-06-16 14:36:37 +1000197 if (label) {
198 fprintf(f, "\t.globl\t%s\n", label);
199 fprintf(f, "%s:\n", label);
200 }
David Gibsonfb7c7ac2007-09-26 13:11:05 +1000201 fprintf(f, "\t.long\tFDT_BEGIN_NODE\n");
David Gibsonfc14dad2005-06-08 17:18:34 +1000202}
203
David Gibson4102d842005-06-16 14:36:37 +1000204static void asm_emit_endnode(void *e, char *label)
David Gibsonfc14dad2005-06-08 17:18:34 +1000205{
206 FILE *f = e;
207
David Gibsonfb7c7ac2007-09-26 13:11:05 +1000208 fprintf(f, "\t.long\tFDT_END_NODE\n");
David Gibson4102d842005-06-16 14:36:37 +1000209 if (label) {
210 fprintf(f, "\t.globl\t%s_end\n", label);
211 fprintf(f, "%s_end:\n", label);
212 }
David Gibsonfc14dad2005-06-08 17:18:34 +1000213}
214
David Gibson4102d842005-06-16 14:36:37 +1000215static void asm_emit_property(void *e, char *label)
David Gibsonfc14dad2005-06-08 17:18:34 +1000216{
217 FILE *f = e;
218
David Gibson4102d842005-06-16 14:36:37 +1000219 if (label) {
220 fprintf(f, "\t.globl\t%s\n", label);
221 fprintf(f, "%s:\n", label);
222 }
David Gibsonfb7c7ac2007-09-26 13:11:05 +1000223 fprintf(f, "\t.long\tFDT_PROP\n");
David Gibsonfc14dad2005-06-08 17:18:34 +1000224}
225
David Gibson230f2532005-08-29 12:48:02 +1000226static struct emitter asm_emitter = {
David Gibsonfc14dad2005-06-08 17:18:34 +1000227 .cell = asm_emit_cell,
228 .string = asm_emit_string,
229 .align = asm_emit_align,
230 .data = asm_emit_data,
231 .beginnode = asm_emit_beginnode,
232 .endnode = asm_emit_endnode,
David Gibson63dc9c72007-09-18 11:44:04 +1000233 .property = asm_emit_property,
David Gibsonfc14dad2005-06-08 17:18:34 +1000234};
235
236static int stringtable_insert(struct data *d, char *str)
237{
238 int i;
239
240 /* FIXME: do this more efficiently? */
241
242 for (i = 0; i < d->len; i++) {
243 if (streq(str, d->val + i))
244 return i;
245 }
246
247 *d = data_append_data(*d, str, strlen(str)+1);
David Gibsona6c69572005-07-11 17:09:42 +1000248 return i;
David Gibsonfc14dad2005-06-08 17:18:34 +1000249}
250
251static void flatten_tree(struct node *tree, struct emitter *emit,
252 void *etarget, struct data *strbuf,
253 struct version_info *vi)
254{
255 struct property *prop;
256 struct node *child;
257 int seen_name_prop = 0;
258
David Gibson4102d842005-06-16 14:36:37 +1000259 emit->beginnode(etarget, tree->label);
David Gibsonfc14dad2005-06-08 17:18:34 +1000260
261 if (vi->flags & FTF_FULLPATH)
262 emit->string(etarget, tree->fullpath, 0);
263 else
264 emit->string(etarget, tree->name, 0);
265
266 emit->align(etarget, sizeof(cell_t));
267
268 for_each_property(tree, prop) {
269 int nameoff;
270
271 if (streq(prop->name, "name"))
272 seen_name_prop = 1;
273
274 nameoff = stringtable_insert(strbuf, prop->name);
275
David Gibson4102d842005-06-16 14:36:37 +1000276 emit->property(etarget, prop->label);
David Gibsonfc14dad2005-06-08 17:18:34 +1000277 emit->cell(etarget, prop->val.len);
278 emit->cell(etarget, nameoff);
279
280 if ((vi->flags & FTF_VARALIGN) && (prop->val.len >= 8))
281 emit->align(etarget, 8);
282
283 emit->data(etarget, prop->val);
284 emit->align(etarget, sizeof(cell_t));
285 }
286
287 if ((vi->flags & FTF_NAMEPROPS) && !seen_name_prop) {
David Gibson4102d842005-06-16 14:36:37 +1000288 emit->property(etarget, NULL);
David Gibsonfc14dad2005-06-08 17:18:34 +1000289 emit->cell(etarget, tree->basenamelen+1);
290 emit->cell(etarget, stringtable_insert(strbuf, "name"));
291
292 if ((vi->flags & FTF_VARALIGN) && ((tree->basenamelen+1) >= 8))
293 emit->align(etarget, 8);
294
295 emit->string(etarget, tree->name, tree->basenamelen);
David Gibson41916132005-08-25 15:39:09 +1000296 emit->align(etarget, sizeof(cell_t));
David Gibsonfc14dad2005-06-08 17:18:34 +1000297 }
298
299 for_each_child(tree, child) {
300 flatten_tree(child, emit, etarget, strbuf, vi);
301 }
302
David Gibson4102d842005-06-16 14:36:37 +1000303 emit->endnode(etarget, tree->label);
David Gibsonfc14dad2005-06-08 17:18:34 +1000304}
305
David Gibsonf040d952005-10-24 18:18:38 +1000306static struct data flatten_reserve_list(struct reserve_info *reservelist,
307 struct version_info *vi)
308{
309 struct reserve_info *re;
310 struct data d = empty_data;
David Gibsonfb7c7ac2007-09-26 13:11:05 +1000311 static struct fdt_reserve_entry null_re = {0,0};
Jerry Van Baren4384b232007-04-04 22:04:33 -0400312 int j;
David Gibsonf040d952005-10-24 18:18:38 +1000313
314 for (re = reservelist; re; re = re->next) {
315 d = data_append_re(d, &re->re);
316 }
Jerry Van Baren4384b232007-04-04 22:04:33 -0400317 /*
318 * Add additional reserved slots if the user asked for them.
319 */
320 for (j = 0; j < reservenum; j++) {
321 d = data_append_re(d, &null_re);
322 }
Jerry Van Baren86c01ee2007-04-18 21:59:51 -0400323
David Gibsonf040d952005-10-24 18:18:38 +1000324 return d;
325}
Jerry Van Baren86c01ee2007-04-18 21:59:51 -0400326
David Gibsonfb7c7ac2007-09-26 13:11:05 +1000327static void make_fdt_header(struct fdt_header *fdt,
328 struct version_info *vi,
329 int reservesize, int dtsize, int strsize,
330 int boot_cpuid_phys)
David Gibsonfc14dad2005-06-08 17:18:34 +1000331{
David Gibson47f23de2005-07-11 17:19:26 +1000332 int reserve_off;
David Gibsonf040d952005-10-24 18:18:38 +1000333
David Gibsonfb7c7ac2007-09-26 13:11:05 +1000334 reservesize += sizeof(struct fdt_reserve_entry);
David Gibsonfc14dad2005-06-08 17:18:34 +1000335
David Gibsonfb7c7ac2007-09-26 13:11:05 +1000336 memset(fdt, 0xff, sizeof(*fdt));
David Gibsonfc14dad2005-06-08 17:18:34 +1000337
David Gibsonfb7c7ac2007-09-26 13:11:05 +1000338 fdt->magic = cpu_to_be32(FDT_MAGIC);
339 fdt->version = cpu_to_be32(vi->version);
340 fdt->last_comp_version = cpu_to_be32(vi->last_comp_version);
David Gibsonfc14dad2005-06-08 17:18:34 +1000341
David Gibson47f23de2005-07-11 17:19:26 +1000342 /* Reserve map should be doubleword aligned */
343 reserve_off = ALIGN(vi->hdr_size, 8);
344
David Gibsonfb7c7ac2007-09-26 13:11:05 +1000345 fdt->off_mem_rsvmap = cpu_to_be32(reserve_off);
346 fdt->off_dt_struct = cpu_to_be32(reserve_off + reservesize);
347 fdt->off_dt_strings = cpu_to_be32(reserve_off + reservesize
David Gibsonfc14dad2005-06-08 17:18:34 +1000348 + dtsize);
David Gibsonfb7c7ac2007-09-26 13:11:05 +1000349 fdt->totalsize = cpu_to_be32(reserve_off + reservesize + dtsize + strsize);
Jerry Van Baren4384b232007-04-04 22:04:33 -0400350
David Gibsonfc14dad2005-06-08 17:18:34 +1000351 if (vi->flags & FTF_BOOTCPUID)
David Gibsonfb7c7ac2007-09-26 13:11:05 +1000352 fdt->boot_cpuid_phys = cpu_to_be32(boot_cpuid_phys);
David Gibsonfc14dad2005-06-08 17:18:34 +1000353 if (vi->flags & FTF_STRTABSIZE)
David Gibsonfb7c7ac2007-09-26 13:11:05 +1000354 fdt->size_dt_strings = cpu_to_be32(strsize);
David Gibson46c88df2007-03-14 11:02:40 +1100355 if (vi->flags & FTF_STRUCTSIZE)
David Gibsonfb7c7ac2007-09-26 13:11:05 +1000356 fdt->size_dt_struct = cpu_to_be32(dtsize);
David Gibsonfc14dad2005-06-08 17:18:34 +1000357}
358
Michael Neuling38e8f8f2006-05-31 08:31:51 +1000359void dt_to_blob(FILE *f, struct boot_info *bi, int version,
360 int boot_cpuid_phys)
David Gibsonfc14dad2005-06-08 17:18:34 +1000361{
362 struct version_info *vi = NULL;
363 int i;
Jerry Van Baren86c01ee2007-04-18 21:59:51 -0400364 struct data blob = empty_data;
365 struct data reservebuf = empty_data;
366 struct data dtbuf = empty_data;
367 struct data strbuf = empty_data;
David Gibsonfb7c7ac2007-09-26 13:11:05 +1000368 struct fdt_header fdt;
Jerry Van Baren7ea144f2007-04-19 22:22:35 -0400369 int padlen;
David Gibsonfc14dad2005-06-08 17:18:34 +1000370
371 for (i = 0; i < ARRAY_SIZE(version_table); i++) {
372 if (version_table[i].version == version)
373 vi = &version_table[i];
374 }
375 if (!vi)
376 die("Unknown device tree blob version %d\n", version);
377
David Gibsonf0517db2005-07-15 17:14:24 +1000378 flatten_tree(bi->dt, &bin_emitter, &dtbuf, &strbuf, vi);
David Gibsonfb7c7ac2007-09-26 13:11:05 +1000379 bin_emit_cell(&dtbuf, FDT_END);
David Gibsonfc14dad2005-06-08 17:18:34 +1000380
David Gibsonf040d952005-10-24 18:18:38 +1000381 reservebuf = flatten_reserve_list(bi->reservelist, vi);
382
David Gibsonf0517db2005-07-15 17:14:24 +1000383 /* Make header */
David Gibsonfb7c7ac2007-09-26 13:11:05 +1000384 make_fdt_header(&fdt, vi, reservebuf.len, dtbuf.len, strbuf.len,
385 boot_cpuid_phys);
David Gibsonfc14dad2005-06-08 17:18:34 +1000386
Jerry Van Baren86c01ee2007-04-18 21:59:51 -0400387 /*
Jerry Van Baren7ea144f2007-04-19 22:22:35 -0400388 * If the user asked for more space than is used, adjust the totalsize.
389 */
David Gibsonfb7c7ac2007-09-26 13:11:05 +1000390 padlen = minsize - be32_to_cpu(fdt.totalsize);
Jerry Van Baren7ea144f2007-04-19 22:22:35 -0400391 if (padlen > 0) {
David Gibsonfb7c7ac2007-09-26 13:11:05 +1000392 fdt.totalsize = cpu_to_be32(minsize);
Jerry Van Baren7ea144f2007-04-19 22:22:35 -0400393 } else {
394 if ((minsize > 0) && (quiet < 1))
395 fprintf(stderr,
396 "Warning: blob size %d >= minimum size %d\n",
David Gibsonfb7c7ac2007-09-26 13:11:05 +1000397 be32_to_cpu(fdt.totalsize), minsize);
Jerry Van Baren7ea144f2007-04-19 22:22:35 -0400398 }
399
400 /*
Jerry Van Baren86c01ee2007-04-18 21:59:51 -0400401 * Assemble the blob: start with the header, add with alignment
402 * the reserve buffer, add the reserve map terminating zeroes,
403 * the device tree itself, and finally the strings.
404 */
David Gibsonfb7c7ac2007-09-26 13:11:05 +1000405 blob = data_append_data(blob, &fdt, sizeof(fdt));
Jerry Van Baren86c01ee2007-04-18 21:59:51 -0400406 blob = data_append_align(blob, 8);
407 blob = data_merge(blob, reservebuf);
David Gibsonfb7c7ac2007-09-26 13:11:05 +1000408 blob = data_append_zeroes(blob, sizeof(struct fdt_reserve_entry));
Jerry Van Baren86c01ee2007-04-18 21:59:51 -0400409 blob = data_merge(blob, dtbuf);
410 blob = data_merge(blob, strbuf);
David Gibson47f23de2005-07-11 17:19:26 +1000411
David Gibsonf0517db2005-07-15 17:14:24 +1000412 /*
Jerry Van Baren86c01ee2007-04-18 21:59:51 -0400413 * If the user asked for more space than is used, pad out the blob.
David Gibsonf0517db2005-07-15 17:14:24 +1000414 */
Jerry Van Baren7ea144f2007-04-19 22:22:35 -0400415 if (padlen > 0) {
416 blob = data_append_zeroes(blob, padlen);
David Gibsonfb7c7ac2007-09-26 13:11:05 +1000417 fdt.totalsize = cpu_to_be32(minsize);
Jerry Van Baren86c01ee2007-04-18 21:59:51 -0400418 }
419
420 fwrite(blob.val, blob.len, 1, f);
David Gibsonfc14dad2005-06-08 17:18:34 +1000421
422 if (ferror(f))
423 die("Error writing device tree blob: %s\n", strerror(errno));
424
Jerry Van Baren86c01ee2007-04-18 21:59:51 -0400425 /*
426 * data_merge() frees the right-hand element so only the blob
427 * remains to be freed.
428 */
429 data_free(blob);
David Gibsonfc14dad2005-06-08 17:18:34 +1000430}
431
David Gibson230f2532005-08-29 12:48:02 +1000432static void dump_stringtable_asm(FILE *f, struct data strbuf)
David Gibsonfc14dad2005-06-08 17:18:34 +1000433{
434 char *p;
435 int len;
436
437 p = strbuf.val;
438
439 while (p < (strbuf.val + strbuf.len)) {
440 len = strlen(p);
441 fprintf(f, "\t.string \"%s\"\n", p);
442 p += len+1;
443 }
444}
445
Michael Neuling38e8f8f2006-05-31 08:31:51 +1000446void dt_to_asm(FILE *f, struct boot_info *bi, int version, int boot_cpuid_phys)
David Gibsonfc14dad2005-06-08 17:18:34 +1000447{
448 struct version_info *vi = NULL;
449 int i;
450 struct data strbuf = empty_data;
David Gibsonf040d952005-10-24 18:18:38 +1000451 struct reserve_info *re;
David Gibsonfc14dad2005-06-08 17:18:34 +1000452 char *symprefix = "dt";
453
454 for (i = 0; i < ARRAY_SIZE(version_table); i++) {
455 if (version_table[i].version == version)
456 vi = &version_table[i];
457 }
458 if (!vi)
459 die("Unknown device tree blob version %d\n", version);
460
461 fprintf(f, "/* autogenerated by dtc, do not edit */\n\n");
David Gibsonfb7c7ac2007-09-26 13:11:05 +1000462 fprintf(f, "#define FDT_MAGIC 0x%x\n", FDT_MAGIC);
463 fprintf(f, "#define FDT_BEGIN_NODE 0x%x\n", FDT_BEGIN_NODE);
464 fprintf(f, "#define FDT_END_NODE 0x%x\n", FDT_END_NODE);
465 fprintf(f, "#define FDT_PROP 0x%x\n", FDT_PROP);
466 fprintf(f, "#define FDT_END 0x%x\n", FDT_END);
David Gibsonfc14dad2005-06-08 17:18:34 +1000467 fprintf(f, "\n");
468
469 emit_label(f, symprefix, "blob_start");
470 emit_label(f, symprefix, "header");
David Gibsonfb7c7ac2007-09-26 13:11:05 +1000471 fprintf(f, "\t.long\tFDT_MAGIC\t\t\t\t/* magic */\n");
Milton Miller7f456662007-07-07 01:18:53 -0500472 fprintf(f, "\t.long\t_%s_blob_abs_end - _%s_blob_start\t/* totalsize */\n",
David Gibsonfc14dad2005-06-08 17:18:34 +1000473 symprefix, symprefix);
Milton Miller7f456662007-07-07 01:18:53 -0500474 fprintf(f, "\t.long\t_%s_struct_start - _%s_blob_start\t/* off_dt_struct */\n",
David Gibsonfc14dad2005-06-08 17:18:34 +1000475 symprefix, symprefix);
Milton Miller7f456662007-07-07 01:18:53 -0500476 fprintf(f, "\t.long\t_%s_strings_start - _%s_blob_start\t/* off_dt_strings */\n",
David Gibsonfc14dad2005-06-08 17:18:34 +1000477 symprefix, symprefix);
Milton Miller7f456662007-07-07 01:18:53 -0500478 fprintf(f, "\t.long\t_%s_reserve_map - _%s_blob_start\t/* off_dt_strings */\n",
David Gibsonfc14dad2005-06-08 17:18:34 +1000479 symprefix, symprefix);
Milton Miller7f456662007-07-07 01:18:53 -0500480 fprintf(f, "\t.long\t%d\t\t\t\t\t/* version */\n", vi->version);
481 fprintf(f, "\t.long\t%d\t\t\t\t\t/* last_comp_version */\n",
David Gibsonfc14dad2005-06-08 17:18:34 +1000482 vi->last_comp_version);
483
484 if (vi->flags & FTF_BOOTCPUID)
Milton Miller7f456662007-07-07 01:18:53 -0500485 fprintf(f, "\t.long\t%i\t\t\t\t\t/* boot_cpuid_phys */\n",
Michael Neuling38e8f8f2006-05-31 08:31:51 +1000486 boot_cpuid_phys);
David Gibsonfc14dad2005-06-08 17:18:34 +1000487
488 if (vi->flags & FTF_STRTABSIZE)
489 fprintf(f, "\t.long\t_%s_strings_end - _%s_strings_start\t/* size_dt_strings */\n",
490 symprefix, symprefix);
491
Milton Miller81fda8a2007-07-07 01:18:47 -0500492 if (vi->flags & FTF_STRUCTSIZE)
493 fprintf(f, "\t.long\t_%s_struct_end - _%s_struct_start\t/* size_dt_struct */\n",
494 symprefix, symprefix);
495
David Gibsonf0517db2005-07-15 17:14:24 +1000496 /*
497 * Reserve map entries.
498 * Align the reserve map to a doubleword boundary.
499 * Each entry is an (address, size) pair of u64 values.
David Gibsonf0517db2005-07-15 17:14:24 +1000500 * Always supply a zero-sized temination entry.
501 */
David Gibson47f23de2005-07-11 17:19:26 +1000502 asm_emit_align(f, 8);
David Gibsonfc14dad2005-06-08 17:18:34 +1000503 emit_label(f, symprefix, "reserve_map");
David Gibsonf0517db2005-07-15 17:14:24 +1000504
David Gibsonf040d952005-10-24 18:18:38 +1000505 fprintf(f, "/* Memory reserve map from source file */\n");
Jon Loeliger05ae3d82006-04-19 11:58:45 -0500506
507 /*
508 * Use .long on high and low halfs of u64s to avoid .quad
509 * as it appears .quad isn't available in some assemblers.
510 */
David Gibsonf040d952005-10-24 18:18:38 +1000511 for (re = bi->reservelist; re; re = re->next) {
Milton Millerd4290332007-07-07 01:18:49 -0500512 if (re->label) {
513 fprintf(f, "\t.globl\t%s\n", re->label);
514 fprintf(f, "%s:\n", re->label);
515 }
Milton Miller445d55d2007-07-07 01:18:54 -0500516 fprintf(f, "\t.long\t0x%08x, 0x%08x\n",
Jon Loeliger05ae3d82006-04-19 11:58:45 -0500517 (unsigned int)(re->re.address >> 32),
518 (unsigned int)(re->re.address & 0xffffffff));
Milton Miller445d55d2007-07-07 01:18:54 -0500519 fprintf(f, "\t.long\t0x%08x, 0x%08x\n",
Jon Loeliger05ae3d82006-04-19 11:58:45 -0500520 (unsigned int)(re->re.size >> 32),
521 (unsigned int)(re->re.size & 0xffffffff));
David Gibsonfc14dad2005-06-08 17:18:34 +1000522 }
Jerry Van Barenca25e542007-04-17 18:14:41 -0400523 for (i = 0; i < reservenum; i++) {
524 fprintf(f, "\t.long\t0, 0\n\t.long\t0, 0\n");
525 }
David Gibsonfc14dad2005-06-08 17:18:34 +1000526
Jon Loeliger05ae3d82006-04-19 11:58:45 -0500527 fprintf(f, "\t.long\t0, 0\n\t.long\t0, 0\n");
David Gibsonf0517db2005-07-15 17:14:24 +1000528
David Gibsonfc14dad2005-06-08 17:18:34 +1000529 emit_label(f, symprefix, "struct_start");
David Gibsonf0517db2005-07-15 17:14:24 +1000530 flatten_tree(bi->dt, &asm_emitter, f, &strbuf, vi);
David Gibsonfb7c7ac2007-09-26 13:11:05 +1000531 fprintf(f, "\t.long\tFDT_END\n");
David Gibsonfc14dad2005-06-08 17:18:34 +1000532 emit_label(f, symprefix, "struct_end");
533
534 emit_label(f, symprefix, "strings_start");
535 dump_stringtable_asm(f, strbuf);
536 emit_label(f, symprefix, "strings_end");
537
538 emit_label(f, symprefix, "blob_end");
539
Jerry Van Baren86c01ee2007-04-18 21:59:51 -0400540 /*
541 * If the user asked for more space than is used, pad it out.
542 */
543 if (minsize > 0) {
544 fprintf(f, "\t.space\t%d - (_%s_blob_end - _%s_blob_start), 0\n",
545 minsize, symprefix, symprefix);
546 }
547 emit_label(f, symprefix, "blob_abs_end");
548
David Gibsonfc14dad2005-06-08 17:18:34 +1000549 data_free(strbuf);
550}
551
552struct inbuf {
553 char *base, *limit, *ptr;
554};
555
556static void inbuf_init(struct inbuf *inb, void *base, void *limit)
557{
558 inb->base = base;
559 inb->limit = limit;
560 inb->ptr = inb->base;
561}
562
563static void flat_read_chunk(struct inbuf *inb, void *p, int len)
564{
565 if ((inb->ptr + len) > inb->limit)
566 die("Premature end of data parsing flat device tree\n");
567
568 memcpy(p, inb->ptr, len);
569
570 inb->ptr += len;
571}
572
573static u32 flat_read_word(struct inbuf *inb)
574{
575 u32 val;
576
577 assert(((inb->ptr - inb->base) % sizeof(val)) == 0);
578
579 flat_read_chunk(inb, &val, sizeof(val));
580
581 return be32_to_cpu(val);
582}
583
584static void flat_realign(struct inbuf *inb, int align)
585{
586 int off = inb->ptr - inb->base;
587
588 inb->ptr = inb->base + ALIGN(off, align);
589 if (inb->ptr > inb->limit)
590 die("Premature end of data parsing flat device tree\n");
591}
592
593static char *flat_read_string(struct inbuf *inb)
594{
595 int len = 0;
596 char *p = inb->ptr;
597 char *str;
598
599 do {
600 if (p >= inb->limit)
601 die("Premature end of data parsing flat device tree\n");
602 len++;
603 } while ((*p++) != '\0');
604
605 str = strdup(inb->ptr);
606
607 inb->ptr += len;
608
609 flat_realign(inb, sizeof(u32));
610
611 return str;
612}
613
614static struct data flat_read_data(struct inbuf *inb, int len)
615{
616 struct data d = empty_data;
617
618 if (len == 0)
619 return empty_data;
620
621 d = data_grow_for(d, len);
622 d.len = len;
623
624 flat_read_chunk(inb, d.val, len);
625
626 flat_realign(inb, sizeof(u32));
627
628 return d;
629}
630
631static char *flat_read_stringtable(struct inbuf *inb, int offset)
632{
633 char *p;
634
635 p = inb->base + offset;
636 while (1) {
David Gibson4ddf7c02005-08-19 16:11:11 +1000637 if (p >= inb->limit || p < inb->base)
David Gibson7ee3ffd2005-07-11 16:45:57 +1000638 die("String offset %d overruns string table\n",
639 offset);
David Gibsonfc14dad2005-06-08 17:18:34 +1000640
641 if (*p == '\0')
642 break;
643
644 p++;
645 }
646
647 return strdup(inb->base + offset);
648}
649
David Gibson230f2532005-08-29 12:48:02 +1000650static struct property *flat_read_property(struct inbuf *dtbuf,
651 struct inbuf *strbuf, int flags)
David Gibsonfc14dad2005-06-08 17:18:34 +1000652{
653 u32 proplen, stroff;
654 char *name;
655 struct data val;
656
657 proplen = flat_read_word(dtbuf);
658 stroff = flat_read_word(dtbuf);
659
660 name = flat_read_stringtable(strbuf, stroff);
661
662 if ((flags & FTF_VARALIGN) && (proplen >= 8))
663 flat_realign(dtbuf, 8);
664
665 val = flat_read_data(dtbuf, proplen);
666
David Gibson4102d842005-06-16 14:36:37 +1000667 return build_property(name, val, NULL);
David Gibsonfc14dad2005-06-08 17:18:34 +1000668}
669
David Gibsonf0517db2005-07-15 17:14:24 +1000670
David Gibsonf040d952005-10-24 18:18:38 +1000671static struct reserve_info *flat_read_mem_reserve(struct inbuf *inb)
David Gibsonf0517db2005-07-15 17:14:24 +1000672{
David Gibsonf040d952005-10-24 18:18:38 +1000673 struct reserve_info *reservelist = NULL;
674 struct reserve_info *new;
David Gibsonf0517db2005-07-15 17:14:24 +1000675 char *p;
David Gibsonfb7c7ac2007-09-26 13:11:05 +1000676 struct fdt_reserve_entry re;
David Gibsonf0517db2005-07-15 17:14:24 +1000677
678 /*
679 * Each entry is a pair of u64 (addr, size) values for 4 cell_t's.
680 * List terminates at an entry with size equal to zero.
681 *
682 * First pass, count entries.
683 */
684 p = inb->ptr;
David Gibson6c0f3672005-08-29 13:36:15 +1000685 while (1) {
686 flat_read_chunk(inb, &re, sizeof(re));
Michael Neuling332c5362006-07-07 23:28:10 +1000687 re.address = be64_to_cpu(re.address);
688 re.size = be64_to_cpu(re.size);
David Gibson6c0f3672005-08-29 13:36:15 +1000689 if (re.size == 0)
690 break;
David Gibsonf0517db2005-07-15 17:14:24 +1000691
David Gibsonf040d952005-10-24 18:18:38 +1000692 new = build_reserve_entry(re.address, re.size, NULL);
693 reservelist = add_reserve_entry(reservelist, new);
David Gibson6c0f3672005-08-29 13:36:15 +1000694 }
David Gibsonf0517db2005-07-15 17:14:24 +1000695
David Gibsonf040d952005-10-24 18:18:38 +1000696 return reservelist;
David Gibsonf0517db2005-07-15 17:14:24 +1000697}
698
699
David Gibsonfc14dad2005-06-08 17:18:34 +1000700static char *nodename_from_path(char *ppath, char *cpath)
701{
702 char *lslash;
703 int plen;
704
705 lslash = strrchr(cpath, '/');
706 if (! lslash)
707 return NULL;
708
709 plen = lslash - cpath;
710
711 if (streq(cpath, "/") && streq(ppath, ""))
712 return "";
713
714 if ((plen == 0) && streq(ppath, "/"))
715 return strdup(lslash+1);
716
David Gibson81f2e892005-06-16 17:04:00 +1000717 if (! strneq(ppath, cpath, plen))
David Gibsonfc14dad2005-06-08 17:18:34 +1000718 return NULL;
David Gibson63dc9c72007-09-18 11:44:04 +1000719
David Gibsonfc14dad2005-06-08 17:18:34 +1000720 return strdup(lslash+1);
721}
722
723static const char PROPCHAR[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789,._+*#?-";
724static const char UNITCHAR[] = "0123456789abcdef,";
725
726static int check_node_name(char *name)
727{
728 char *atpos;
729 int basenamelen;
730
731 atpos = strrchr(name, '@');
732
733 if (atpos)
734 basenamelen = atpos - name;
735 else
736 basenamelen = strlen(name);
737
738 if (strspn(name, PROPCHAR) < basenamelen)
739 return -1;
740
741 if (atpos
742 && ((basenamelen + 1 + strspn(atpos+1, UNITCHAR)) < strlen(name)))
743 return -1;
744
745 return basenamelen;
746}
747
748static struct node *unflatten_tree(struct inbuf *dtbuf,
749 struct inbuf *strbuf,
750 char *parent_path, int flags)
751{
752 struct node *node;
753 u32 val;
754
755 node = build_node(NULL, NULL);
756
757 if (flags & FTF_FULLPATH) {
758 node->fullpath = flat_read_string(dtbuf);
759 node->name = nodename_from_path(parent_path, node->fullpath);
760
761 if (! node->name)
762 die("Path \"%s\" is not valid as a child of \"%s\"\n",
763 node->fullpath, parent_path);
764 } else {
765 node->name = flat_read_string(dtbuf);
766 node->fullpath = join_path(parent_path, node->name);
767 }
David Gibson63dc9c72007-09-18 11:44:04 +1000768
David Gibsonfc14dad2005-06-08 17:18:34 +1000769 node->basenamelen = check_node_name(node->name);
770 if (node->basenamelen < 0) {
771 fprintf(stderr, "Warning \"%s\" has incorrect format\n", node->name);
772 }
773
774 do {
775 struct property *prop;
776 struct node *child;
777
778 val = flat_read_word(dtbuf);
779 switch (val) {
David Gibsonfb7c7ac2007-09-26 13:11:05 +1000780 case FDT_PROP:
David Gibson592ea582007-09-04 10:43:03 +1000781 if (node->children)
782 fprintf(stderr, "Warning: Flat tree input has "
783 "subnodes preceding a property.\n");
David Gibsonfc14dad2005-06-08 17:18:34 +1000784 prop = flat_read_property(dtbuf, strbuf, flags);
785 add_property(node, prop);
786 break;
787
David Gibsonfb7c7ac2007-09-26 13:11:05 +1000788 case FDT_BEGIN_NODE:
David Gibsonfc14dad2005-06-08 17:18:34 +1000789 child = unflatten_tree(dtbuf,strbuf, node->fullpath,
790 flags);
791 add_child(node, child);
792 break;
793
David Gibsonfb7c7ac2007-09-26 13:11:05 +1000794 case FDT_END_NODE:
David Gibsonfc14dad2005-06-08 17:18:34 +1000795 break;
796
David Gibsonfb7c7ac2007-09-26 13:11:05 +1000797 case FDT_END:
798 die("Premature FDT_END in device tree blob\n");
David Gibsonfc14dad2005-06-08 17:18:34 +1000799 break;
800
David Gibsonfb7c7ac2007-09-26 13:11:05 +1000801 case FDT_NOP:
David Gibson07387742007-06-26 11:30:47 +1000802 if (!(flags & FTF_NOPS))
803 fprintf(stderr, "Warning: NOP tag found in flat tree"
804 " version <16\n");
Milton Millerce243222007-06-09 23:21:31 -0500805
David Gibson07387742007-06-26 11:30:47 +1000806 /* Ignore */
Milton Millerce243222007-06-09 23:21:31 -0500807 break;
808
David Gibsonfc14dad2005-06-08 17:18:34 +1000809 default:
810 die("Invalid opcode word %08x in device tree blob\n",
811 val);
812 }
David Gibsonfb7c7ac2007-09-26 13:11:05 +1000813 } while (val != FDT_END_NODE);
David Gibsonfc14dad2005-06-08 17:18:34 +1000814
815 return node;
816}
817
David Gibsonf0517db2005-07-15 17:14:24 +1000818
819struct boot_info *dt_from_blob(FILE *f)
David Gibsonfc14dad2005-06-08 17:18:34 +1000820{
David Gibson46c88df2007-03-14 11:02:40 +1100821 u32 magic, totalsize, version, size_str, size_dt;
David Gibsonf0517db2005-07-15 17:14:24 +1000822 u32 off_dt, off_str, off_mem_rsvmap;
David Gibsonfc14dad2005-06-08 17:18:34 +1000823 int rc;
824 char *blob;
David Gibsonfb7c7ac2007-09-26 13:11:05 +1000825 struct fdt_header *fdt;
David Gibsonfc14dad2005-06-08 17:18:34 +1000826 char *p;
827 struct inbuf dtbuf, strbuf;
David Gibsonf0517db2005-07-15 17:14:24 +1000828 struct inbuf memresvbuf;
David Gibsonfc14dad2005-06-08 17:18:34 +1000829 int sizeleft;
David Gibsonf040d952005-10-24 18:18:38 +1000830 struct reserve_info *reservelist;
David Gibsonfc14dad2005-06-08 17:18:34 +1000831 struct node *tree;
832 u32 val;
833 int flags = 0;
834
835 rc = fread(&magic, sizeof(magic), 1, f);
836 if (ferror(f))
837 die("Error reading DT blob magic number: %s\n",
838 strerror(errno));
839 if (rc < 1) {
840 if (feof(f))
841 die("EOF reading DT blob magic number\n");
842 else
843 die("Mysterious short read reading magic number\n");
844 }
845
846 magic = be32_to_cpu(magic);
David Gibsonfb7c7ac2007-09-26 13:11:05 +1000847 if (magic != FDT_MAGIC)
David Gibsonfc14dad2005-06-08 17:18:34 +1000848 die("Blob has incorrect magic number\n");
849
850 rc = fread(&totalsize, sizeof(totalsize), 1, f);
851 if (ferror(f))
852 die("Error reading DT blob size: %s\n", strerror(errno));
853 if (rc < 1) {
854 if (feof(f))
855 die("EOF reading DT blob size\n");
856 else
857 die("Mysterious short read reading blob size\n");
858 }
859
860 totalsize = be32_to_cpu(totalsize);
David Gibsonfb7c7ac2007-09-26 13:11:05 +1000861 if (totalsize < FDT_V1_SIZE)
David Gibsonfc14dad2005-06-08 17:18:34 +1000862 die("DT blob size (%d) is too small\n", totalsize);
863
864 blob = xmalloc(totalsize);
865
David Gibsonfb7c7ac2007-09-26 13:11:05 +1000866 fdt = (struct fdt_header *)blob;
867 fdt->magic = cpu_to_be32(magic);
868 fdt->totalsize = cpu_to_be32(totalsize);
David Gibsonfc14dad2005-06-08 17:18:34 +1000869
870 sizeleft = totalsize - sizeof(magic) - sizeof(totalsize);
871 p = blob + sizeof(magic) + sizeof(totalsize);
872
873 while (sizeleft) {
874 if (feof(f))
875 die("EOF before reading %d bytes of DT blob\n",
876 totalsize);
877
878 rc = fread(p, 1, sizeleft, f);
879 if (ferror(f))
880 die("Error reading DT blob: %s\n",
881 strerror(errno));
882
883 sizeleft -= rc;
884 p += rc;
885 }
886
David Gibsonfb7c7ac2007-09-26 13:11:05 +1000887 off_dt = be32_to_cpu(fdt->off_dt_struct);
888 off_str = be32_to_cpu(fdt->off_dt_strings);
889 off_mem_rsvmap = be32_to_cpu(fdt->off_mem_rsvmap);
890 version = be32_to_cpu(fdt->version);
David Gibsonfc14dad2005-06-08 17:18:34 +1000891
892 fprintf(stderr, "\tmagic:\t\t\t0x%x\n", magic);
893 fprintf(stderr, "\ttotalsize:\t\t%d\n", totalsize);
894 fprintf(stderr, "\toff_dt_struct:\t\t0x%x\n", off_dt);
895 fprintf(stderr, "\toff_dt_strings:\t\t0x%x\n", off_str);
David Gibsonf0517db2005-07-15 17:14:24 +1000896 fprintf(stderr, "\toff_mem_rsvmap:\t\t0x%x\n", off_mem_rsvmap);
David Gibsonfc14dad2005-06-08 17:18:34 +1000897 fprintf(stderr, "\tversion:\t\t0x%x\n", version );
898 fprintf(stderr, "\tlast_comp_version:\t0x%x\n",
David Gibsonfb7c7ac2007-09-26 13:11:05 +1000899 be32_to_cpu(fdt->last_comp_version));
David Gibsonfc14dad2005-06-08 17:18:34 +1000900
David Gibsonf0517db2005-07-15 17:14:24 +1000901 if (off_mem_rsvmap >= totalsize)
902 die("Mem Reserve structure offset exceeds total size\n");
903
David Gibsonfc14dad2005-06-08 17:18:34 +1000904 if (off_dt >= totalsize)
905 die("DT structure offset exceeds total size\n");
906
907 if (off_str > totalsize)
908 die("String table offset exceeds total size\n");
909
910 if (version >= 2)
911 fprintf(stderr, "\tboot_cpuid_phys:\t0x%x\n",
David Gibsonfb7c7ac2007-09-26 13:11:05 +1000912 be32_to_cpu(fdt->boot_cpuid_phys));
David Gibsonfc14dad2005-06-08 17:18:34 +1000913
David Gibsonbf944972007-08-31 16:21:23 +1000914 size_str = -1;
David Gibsonfc14dad2005-06-08 17:18:34 +1000915 if (version >= 3) {
David Gibsonfb7c7ac2007-09-26 13:11:05 +1000916 size_str = be32_to_cpu(fdt->size_dt_strings);
David Gibsonfc14dad2005-06-08 17:18:34 +1000917 fprintf(stderr, "\tsize_dt_strings:\t%d\n", size_str);
918 if (off_str+size_str > totalsize)
919 die("String table extends past total size\n");
920 }
David Gibson46c88df2007-03-14 11:02:40 +1100921
922 if (version >= 17) {
David Gibsonfb7c7ac2007-09-26 13:11:05 +1000923 size_dt = be32_to_cpu(fdt->size_dt_struct);
David Gibson46c88df2007-03-14 11:02:40 +1100924 fprintf(stderr, "\tsize_dt_struct:\t\t%d\n", size_dt);
925 if (off_dt+size_dt > totalsize)
926 die("Structure block extends past total size\n");
927 }
David Gibson63dc9c72007-09-18 11:44:04 +1000928
David Gibson46c88df2007-03-14 11:02:40 +1100929 if (version < 16) {
David Gibsonfc14dad2005-06-08 17:18:34 +1000930 flags |= FTF_FULLPATH | FTF_NAMEPROPS | FTF_VARALIGN;
Milton Millerce243222007-06-09 23:21:31 -0500931 } else {
932 flags |= FTF_NOPS;
David Gibsonfc14dad2005-06-08 17:18:34 +1000933 }
934
David Gibsonf0517db2005-07-15 17:14:24 +1000935 inbuf_init(&memresvbuf,
936 blob + off_mem_rsvmap, blob + totalsize);
David Gibsonfc14dad2005-06-08 17:18:34 +1000937 inbuf_init(&dtbuf, blob + off_dt, blob + totalsize);
David Gibsonbf944972007-08-31 16:21:23 +1000938 if (size_str >= 0)
939 inbuf_init(&strbuf, blob + off_str, blob + off_str + size_str);
940 else
941 inbuf_init(&strbuf, blob + off_str, blob + totalsize);
David Gibsonfc14dad2005-06-08 17:18:34 +1000942
David Gibsonf040d952005-10-24 18:18:38 +1000943 reservelist = flat_read_mem_reserve(&memresvbuf);
David Gibsonf0517db2005-07-15 17:14:24 +1000944
David Gibsonfc14dad2005-06-08 17:18:34 +1000945 val = flat_read_word(&dtbuf);
946
David Gibsonfb7c7ac2007-09-26 13:11:05 +1000947 if (val != FDT_BEGIN_NODE)
948 die("Device tree blob doesn't begin with FDT_BEGIN_NODE (begins with 0x%08x)\n", val);
David Gibsonfc14dad2005-06-08 17:18:34 +1000949
950 tree = unflatten_tree(&dtbuf, &strbuf, "", flags);
951
952 val = flat_read_word(&dtbuf);
David Gibsonfb7c7ac2007-09-26 13:11:05 +1000953 if (val != FDT_END)
954 die("Device tree blob doesn't end with FDT_END\n");
David Gibsonfc14dad2005-06-08 17:18:34 +1000955
956 free(blob);
957
David Gibsonf040d952005-10-24 18:18:38 +1000958 return build_boot_info(reservelist, tree);
David Gibsonfc14dad2005-06-08 17:18:34 +1000959}