blob: b6be786fb5bd6e5bc932210d47574d865d8c332d [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 Gibson92cb9a22007-12-04 14:26:15 +110054 void (*beginnode)(void *, const char *);
55 void (*endnode)(void *, const char *);
56 void (*property)(void *, const 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 Gibson92cb9a22007-12-04 14:26:15 +110091static void bin_emit_beginnode(void *e, const 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 Gibson92cb9a22007-12-04 14:26:15 +110096static void bin_emit_endnode(void *e, const 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 Gibson92cb9a22007-12-04 14:26:15 +1100101static void bin_emit_property(void *e, const 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 Gibson92cb9a22007-12-04 14:26:15 +1100116static void emit_label(FILE *f, const char *prefix, const 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
David Gibson92cb9a22007-12-04 14:26:15 +1100123static void emit_offset_label(FILE *f, const char *label, int offset)
Milton Miller6a99b132007-07-07 01:18:51 -0500124{
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;
David Gibsondc941772007-11-22 14:39:23 +1100165 struct marker *m;
Milton Miller6a99b132007-07-07 01:18:51 -0500166
David Gibsondc941772007-11-22 14:39:23 +1100167 m = d.markers;
168 while (m) {
169 if (m->type == LABEL)
170 emit_offset_label(f, m->ref, m->offset);
171 m = m->next;
Milton Miller6a99b132007-07-07 01:18:51 -0500172 }
David Gibsonfc14dad2005-06-08 17:18:34 +1000173
174 while ((d.len - off) >= sizeof(u32)) {
175 fprintf(f, "\t.long\t0x%x\n",
176 be32_to_cpu(*((u32 *)(d.val+off))));
177 off += sizeof(u32);
178 }
179
180 if ((d.len - off) >= sizeof(u16)) {
David Gibson63dc9c72007-09-18 11:44:04 +1000181 fprintf(f, "\t.short\t0x%hx\n",
David Gibsonfc14dad2005-06-08 17:18:34 +1000182 be16_to_cpu(*((u16 *)(d.val+off))));
183 off += sizeof(u16);
184 }
185
186 if ((d.len - off) >= 1) {
187 fprintf(f, "\t.byte\t0x%hhx\n", d.val[off]);
188 off += 1;
189 }
190
191 assert(off == d.len);
192}
193
David Gibson92cb9a22007-12-04 14:26:15 +1100194static void asm_emit_beginnode(void *e, const char *label)
David Gibsonfc14dad2005-06-08 17:18:34 +1000195{
196 FILE *f = e;
197
David Gibson4102d842005-06-16 14:36:37 +1000198 if (label) {
199 fprintf(f, "\t.globl\t%s\n", label);
200 fprintf(f, "%s:\n", label);
201 }
David Gibsonfb7c7ac2007-09-26 13:11:05 +1000202 fprintf(f, "\t.long\tFDT_BEGIN_NODE\n");
David Gibsonfc14dad2005-06-08 17:18:34 +1000203}
204
David Gibson92cb9a22007-12-04 14:26:15 +1100205static void asm_emit_endnode(void *e, const char *label)
David Gibsonfc14dad2005-06-08 17:18:34 +1000206{
207 FILE *f = e;
208
David Gibsonfb7c7ac2007-09-26 13:11:05 +1000209 fprintf(f, "\t.long\tFDT_END_NODE\n");
David Gibson4102d842005-06-16 14:36:37 +1000210 if (label) {
211 fprintf(f, "\t.globl\t%s_end\n", label);
212 fprintf(f, "%s_end:\n", label);
213 }
David Gibsonfc14dad2005-06-08 17:18:34 +1000214}
215
David Gibson92cb9a22007-12-04 14:26:15 +1100216static void asm_emit_property(void *e, const char *label)
David Gibsonfc14dad2005-06-08 17:18:34 +1000217{
218 FILE *f = e;
219
David Gibson4102d842005-06-16 14:36:37 +1000220 if (label) {
221 fprintf(f, "\t.globl\t%s\n", label);
222 fprintf(f, "%s:\n", label);
223 }
David Gibsonfb7c7ac2007-09-26 13:11:05 +1000224 fprintf(f, "\t.long\tFDT_PROP\n");
David Gibsonfc14dad2005-06-08 17:18:34 +1000225}
226
David Gibson230f2532005-08-29 12:48:02 +1000227static struct emitter asm_emitter = {
David Gibsonfc14dad2005-06-08 17:18:34 +1000228 .cell = asm_emit_cell,
229 .string = asm_emit_string,
230 .align = asm_emit_align,
231 .data = asm_emit_data,
232 .beginnode = asm_emit_beginnode,
233 .endnode = asm_emit_endnode,
David Gibson63dc9c72007-09-18 11:44:04 +1000234 .property = asm_emit_property,
David Gibsonfc14dad2005-06-08 17:18:34 +1000235};
236
David Gibson92cb9a22007-12-04 14:26:15 +1100237static int stringtable_insert(struct data *d, const char *str)
David Gibsonfc14dad2005-06-08 17:18:34 +1000238{
239 int i;
240
241 /* FIXME: do this more efficiently? */
242
243 for (i = 0; i < d->len; i++) {
244 if (streq(str, d->val + i))
245 return i;
246 }
247
248 *d = data_append_data(*d, str, strlen(str)+1);
David Gibsona6c69572005-07-11 17:09:42 +1000249 return i;
David Gibsonfc14dad2005-06-08 17:18:34 +1000250}
251
252static void flatten_tree(struct node *tree, struct emitter *emit,
253 void *etarget, struct data *strbuf,
254 struct version_info *vi)
255{
256 struct property *prop;
257 struct node *child;
258 int seen_name_prop = 0;
259
David Gibson4102d842005-06-16 14:36:37 +1000260 emit->beginnode(etarget, tree->label);
David Gibsonfc14dad2005-06-08 17:18:34 +1000261
262 if (vi->flags & FTF_FULLPATH)
263 emit->string(etarget, tree->fullpath, 0);
264 else
265 emit->string(etarget, tree->name, 0);
266
267 emit->align(etarget, sizeof(cell_t));
268
269 for_each_property(tree, prop) {
270 int nameoff;
271
272 if (streq(prop->name, "name"))
273 seen_name_prop = 1;
274
275 nameoff = stringtable_insert(strbuf, prop->name);
276
David Gibson4102d842005-06-16 14:36:37 +1000277 emit->property(etarget, prop->label);
David Gibsonfc14dad2005-06-08 17:18:34 +1000278 emit->cell(etarget, prop->val.len);
279 emit->cell(etarget, nameoff);
280
281 if ((vi->flags & FTF_VARALIGN) && (prop->val.len >= 8))
282 emit->align(etarget, 8);
283
284 emit->data(etarget, prop->val);
285 emit->align(etarget, sizeof(cell_t));
286 }
287
288 if ((vi->flags & FTF_NAMEPROPS) && !seen_name_prop) {
David Gibson4102d842005-06-16 14:36:37 +1000289 emit->property(etarget, NULL);
David Gibsonfc14dad2005-06-08 17:18:34 +1000290 emit->cell(etarget, tree->basenamelen+1);
291 emit->cell(etarget, stringtable_insert(strbuf, "name"));
292
293 if ((vi->flags & FTF_VARALIGN) && ((tree->basenamelen+1) >= 8))
294 emit->align(etarget, 8);
295
296 emit->string(etarget, tree->name, tree->basenamelen);
David Gibson41916132005-08-25 15:39:09 +1000297 emit->align(etarget, sizeof(cell_t));
David Gibsonfc14dad2005-06-08 17:18:34 +1000298 }
299
300 for_each_child(tree, child) {
301 flatten_tree(child, emit, etarget, strbuf, vi);
302 }
303
David Gibson4102d842005-06-16 14:36:37 +1000304 emit->endnode(etarget, tree->label);
David Gibsonfc14dad2005-06-08 17:18:34 +1000305}
306
David Gibsonf040d952005-10-24 18:18:38 +1000307static struct data flatten_reserve_list(struct reserve_info *reservelist,
308 struct version_info *vi)
309{
310 struct reserve_info *re;
311 struct data d = empty_data;
David Gibsonfb7c7ac2007-09-26 13:11:05 +1000312 static struct fdt_reserve_entry null_re = {0,0};
Jerry Van Baren4384b232007-04-04 22:04:33 -0400313 int j;
David Gibsonf040d952005-10-24 18:18:38 +1000314
315 for (re = reservelist; re; re = re->next) {
316 d = data_append_re(d, &re->re);
317 }
Jerry Van Baren4384b232007-04-04 22:04:33 -0400318 /*
319 * Add additional reserved slots if the user asked for them.
320 */
321 for (j = 0; j < reservenum; j++) {
322 d = data_append_re(d, &null_re);
323 }
Jerry Van Baren86c01ee2007-04-18 21:59:51 -0400324
David Gibsonf040d952005-10-24 18:18:38 +1000325 return d;
326}
Jerry Van Baren86c01ee2007-04-18 21:59:51 -0400327
David Gibsonfb7c7ac2007-09-26 13:11:05 +1000328static void make_fdt_header(struct fdt_header *fdt,
329 struct version_info *vi,
330 int reservesize, int dtsize, int strsize,
331 int boot_cpuid_phys)
David Gibsonfc14dad2005-06-08 17:18:34 +1000332{
David Gibson47f23de2005-07-11 17:19:26 +1000333 int reserve_off;
David Gibsonf040d952005-10-24 18:18:38 +1000334
David Gibsonfb7c7ac2007-09-26 13:11:05 +1000335 reservesize += sizeof(struct fdt_reserve_entry);
David Gibsonfc14dad2005-06-08 17:18:34 +1000336
David Gibsonfb7c7ac2007-09-26 13:11:05 +1000337 memset(fdt, 0xff, sizeof(*fdt));
David Gibsonfc14dad2005-06-08 17:18:34 +1000338
David Gibsonfb7c7ac2007-09-26 13:11:05 +1000339 fdt->magic = cpu_to_be32(FDT_MAGIC);
340 fdt->version = cpu_to_be32(vi->version);
341 fdt->last_comp_version = cpu_to_be32(vi->last_comp_version);
David Gibsonfc14dad2005-06-08 17:18:34 +1000342
David Gibson47f23de2005-07-11 17:19:26 +1000343 /* Reserve map should be doubleword aligned */
344 reserve_off = ALIGN(vi->hdr_size, 8);
345
David Gibsonfb7c7ac2007-09-26 13:11:05 +1000346 fdt->off_mem_rsvmap = cpu_to_be32(reserve_off);
347 fdt->off_dt_struct = cpu_to_be32(reserve_off + reservesize);
348 fdt->off_dt_strings = cpu_to_be32(reserve_off + reservesize
David Gibsonfc14dad2005-06-08 17:18:34 +1000349 + dtsize);
David Gibsonfb7c7ac2007-09-26 13:11:05 +1000350 fdt->totalsize = cpu_to_be32(reserve_off + reservesize + dtsize + strsize);
Jerry Van Baren4384b232007-04-04 22:04:33 -0400351
David Gibsonfc14dad2005-06-08 17:18:34 +1000352 if (vi->flags & FTF_BOOTCPUID)
David Gibsonfb7c7ac2007-09-26 13:11:05 +1000353 fdt->boot_cpuid_phys = cpu_to_be32(boot_cpuid_phys);
David Gibsonfc14dad2005-06-08 17:18:34 +1000354 if (vi->flags & FTF_STRTABSIZE)
David Gibsonfb7c7ac2007-09-26 13:11:05 +1000355 fdt->size_dt_strings = cpu_to_be32(strsize);
David Gibson46c88df2007-03-14 11:02:40 +1100356 if (vi->flags & FTF_STRUCTSIZE)
David Gibsonfb7c7ac2007-09-26 13:11:05 +1000357 fdt->size_dt_struct = cpu_to_be32(dtsize);
David Gibsonfc14dad2005-06-08 17:18:34 +1000358}
359
Michael Neuling38e8f8f2006-05-31 08:31:51 +1000360void dt_to_blob(FILE *f, struct boot_info *bi, int version,
361 int boot_cpuid_phys)
David Gibsonfc14dad2005-06-08 17:18:34 +1000362{
363 struct version_info *vi = NULL;
364 int i;
Jerry Van Baren86c01ee2007-04-18 21:59:51 -0400365 struct data blob = empty_data;
366 struct data reservebuf = empty_data;
367 struct data dtbuf = empty_data;
368 struct data strbuf = empty_data;
David Gibsonfb7c7ac2007-09-26 13:11:05 +1000369 struct fdt_header fdt;
Kumar Gala2b7dc8d2007-11-28 10:21:12 -0600370 int padlen = 0;
David Gibsonfc14dad2005-06-08 17:18:34 +1000371
372 for (i = 0; i < ARRAY_SIZE(version_table); i++) {
373 if (version_table[i].version == version)
374 vi = &version_table[i];
375 }
376 if (!vi)
377 die("Unknown device tree blob version %d\n", version);
378
David Gibsonf0517db2005-07-15 17:14:24 +1000379 flatten_tree(bi->dt, &bin_emitter, &dtbuf, &strbuf, vi);
David Gibsonfb7c7ac2007-09-26 13:11:05 +1000380 bin_emit_cell(&dtbuf, FDT_END);
David Gibsonfc14dad2005-06-08 17:18:34 +1000381
David Gibsonf040d952005-10-24 18:18:38 +1000382 reservebuf = flatten_reserve_list(bi->reservelist, vi);
383
David Gibsonf0517db2005-07-15 17:14:24 +1000384 /* Make header */
David Gibsonfb7c7ac2007-09-26 13:11:05 +1000385 make_fdt_header(&fdt, vi, reservebuf.len, dtbuf.len, strbuf.len,
386 boot_cpuid_phys);
David Gibsonfc14dad2005-06-08 17:18:34 +1000387
Jerry Van Baren86c01ee2007-04-18 21:59:51 -0400388 /*
Jerry Van Baren7ea144f2007-04-19 22:22:35 -0400389 * If the user asked for more space than is used, adjust the totalsize.
390 */
Kumar Gala2b7dc8d2007-11-28 10:21:12 -0600391 if (minsize > 0) {
392 padlen = minsize - be32_to_cpu(fdt.totalsize);
393 if ((padlen < 0) && (quiet < 1))
Jerry Van Baren7ea144f2007-04-19 22:22:35 -0400394 fprintf(stderr,
395 "Warning: blob size %d >= minimum size %d\n",
David Gibsonfb7c7ac2007-09-26 13:11:05 +1000396 be32_to_cpu(fdt.totalsize), minsize);
Jerry Van Baren7ea144f2007-04-19 22:22:35 -0400397 }
398
Kumar Gala2b7dc8d2007-11-28 10:21:12 -0600399 if (padsize > 0)
400 padlen = padsize;
401
Kumar Gala80c72a82007-12-04 17:36:08 -0600402 if (padlen > 0) {
403 int tsize = be32_to_cpu(fdt.totalsize);
404 tsize += padlen;
405 fdt.totalsize = cpu_to_be32(tsize);
406 }
407
Jerry Van Baren7ea144f2007-04-19 22:22:35 -0400408 /*
Jerry Van Baren86c01ee2007-04-18 21:59:51 -0400409 * Assemble the blob: start with the header, add with alignment
410 * the reserve buffer, add the reserve map terminating zeroes,
411 * the device tree itself, and finally the strings.
412 */
David Gibsonfb7c7ac2007-09-26 13:11:05 +1000413 blob = data_append_data(blob, &fdt, sizeof(fdt));
Jerry Van Baren86c01ee2007-04-18 21:59:51 -0400414 blob = data_append_align(blob, 8);
415 blob = data_merge(blob, reservebuf);
David Gibsonfb7c7ac2007-09-26 13:11:05 +1000416 blob = data_append_zeroes(blob, sizeof(struct fdt_reserve_entry));
Jerry Van Baren86c01ee2007-04-18 21:59:51 -0400417 blob = data_merge(blob, dtbuf);
418 blob = data_merge(blob, strbuf);
David Gibson47f23de2005-07-11 17:19:26 +1000419
David Gibsonf0517db2005-07-15 17:14:24 +1000420 /*
Jerry Van Baren86c01ee2007-04-18 21:59:51 -0400421 * If the user asked for more space than is used, pad out the blob.
David Gibsonf0517db2005-07-15 17:14:24 +1000422 */
Kumar Gala80c72a82007-12-04 17:36:08 -0600423 if (padlen > 0)
Jerry Van Baren7ea144f2007-04-19 22:22:35 -0400424 blob = data_append_zeroes(blob, padlen);
Jerry Van Baren86c01ee2007-04-18 21:59:51 -0400425
426 fwrite(blob.val, blob.len, 1, f);
David Gibsonfc14dad2005-06-08 17:18:34 +1000427
428 if (ferror(f))
429 die("Error writing device tree blob: %s\n", strerror(errno));
430
Jerry Van Baren86c01ee2007-04-18 21:59:51 -0400431 /*
432 * data_merge() frees the right-hand element so only the blob
433 * remains to be freed.
434 */
435 data_free(blob);
David Gibsonfc14dad2005-06-08 17:18:34 +1000436}
437
David Gibson230f2532005-08-29 12:48:02 +1000438static void dump_stringtable_asm(FILE *f, struct data strbuf)
David Gibsonfc14dad2005-06-08 17:18:34 +1000439{
David Gibson92cb9a22007-12-04 14:26:15 +1100440 const char *p;
David Gibsonfc14dad2005-06-08 17:18:34 +1000441 int len;
442
443 p = strbuf.val;
444
445 while (p < (strbuf.val + strbuf.len)) {
446 len = strlen(p);
447 fprintf(f, "\t.string \"%s\"\n", p);
448 p += len+1;
449 }
450}
451
Michael Neuling38e8f8f2006-05-31 08:31:51 +1000452void dt_to_asm(FILE *f, struct boot_info *bi, int version, int boot_cpuid_phys)
David Gibsonfc14dad2005-06-08 17:18:34 +1000453{
454 struct version_info *vi = NULL;
455 int i;
456 struct data strbuf = empty_data;
David Gibsonf040d952005-10-24 18:18:38 +1000457 struct reserve_info *re;
David Gibson92cb9a22007-12-04 14:26:15 +1100458 const char *symprefix = "dt";
David Gibsonfc14dad2005-06-08 17:18:34 +1000459
460 for (i = 0; i < ARRAY_SIZE(version_table); i++) {
461 if (version_table[i].version == version)
462 vi = &version_table[i];
463 }
464 if (!vi)
465 die("Unknown device tree blob version %d\n", version);
466
467 fprintf(f, "/* autogenerated by dtc, do not edit */\n\n");
David Gibsonfb7c7ac2007-09-26 13:11:05 +1000468 fprintf(f, "#define FDT_MAGIC 0x%x\n", FDT_MAGIC);
469 fprintf(f, "#define FDT_BEGIN_NODE 0x%x\n", FDT_BEGIN_NODE);
470 fprintf(f, "#define FDT_END_NODE 0x%x\n", FDT_END_NODE);
471 fprintf(f, "#define FDT_PROP 0x%x\n", FDT_PROP);
472 fprintf(f, "#define FDT_END 0x%x\n", FDT_END);
David Gibsonfc14dad2005-06-08 17:18:34 +1000473 fprintf(f, "\n");
474
475 emit_label(f, symprefix, "blob_start");
476 emit_label(f, symprefix, "header");
David Gibsonfb7c7ac2007-09-26 13:11:05 +1000477 fprintf(f, "\t.long\tFDT_MAGIC\t\t\t\t/* magic */\n");
Milton Miller7f456662007-07-07 01:18:53 -0500478 fprintf(f, "\t.long\t_%s_blob_abs_end - _%s_blob_start\t/* totalsize */\n",
David Gibsonfc14dad2005-06-08 17:18:34 +1000479 symprefix, symprefix);
Milton Miller7f456662007-07-07 01:18:53 -0500480 fprintf(f, "\t.long\t_%s_struct_start - _%s_blob_start\t/* off_dt_struct */\n",
David Gibsonfc14dad2005-06-08 17:18:34 +1000481 symprefix, symprefix);
Milton Miller7f456662007-07-07 01:18:53 -0500482 fprintf(f, "\t.long\t_%s_strings_start - _%s_blob_start\t/* off_dt_strings */\n",
David Gibsonfc14dad2005-06-08 17:18:34 +1000483 symprefix, symprefix);
Milton Miller7f456662007-07-07 01:18:53 -0500484 fprintf(f, "\t.long\t_%s_reserve_map - _%s_blob_start\t/* off_dt_strings */\n",
David Gibsonfc14dad2005-06-08 17:18:34 +1000485 symprefix, symprefix);
Milton Miller7f456662007-07-07 01:18:53 -0500486 fprintf(f, "\t.long\t%d\t\t\t\t\t/* version */\n", vi->version);
487 fprintf(f, "\t.long\t%d\t\t\t\t\t/* last_comp_version */\n",
David Gibsonfc14dad2005-06-08 17:18:34 +1000488 vi->last_comp_version);
489
490 if (vi->flags & FTF_BOOTCPUID)
Milton Miller7f456662007-07-07 01:18:53 -0500491 fprintf(f, "\t.long\t%i\t\t\t\t\t/* boot_cpuid_phys */\n",
Michael Neuling38e8f8f2006-05-31 08:31:51 +1000492 boot_cpuid_phys);
David Gibsonfc14dad2005-06-08 17:18:34 +1000493
494 if (vi->flags & FTF_STRTABSIZE)
495 fprintf(f, "\t.long\t_%s_strings_end - _%s_strings_start\t/* size_dt_strings */\n",
496 symprefix, symprefix);
497
Milton Miller81fda8a2007-07-07 01:18:47 -0500498 if (vi->flags & FTF_STRUCTSIZE)
499 fprintf(f, "\t.long\t_%s_struct_end - _%s_struct_start\t/* size_dt_struct */\n",
500 symprefix, symprefix);
501
David Gibsonf0517db2005-07-15 17:14:24 +1000502 /*
503 * Reserve map entries.
504 * Align the reserve map to a doubleword boundary.
505 * Each entry is an (address, size) pair of u64 values.
David Gibsonf0517db2005-07-15 17:14:24 +1000506 * Always supply a zero-sized temination entry.
507 */
David Gibson47f23de2005-07-11 17:19:26 +1000508 asm_emit_align(f, 8);
David Gibsonfc14dad2005-06-08 17:18:34 +1000509 emit_label(f, symprefix, "reserve_map");
David Gibsonf0517db2005-07-15 17:14:24 +1000510
David Gibsonf040d952005-10-24 18:18:38 +1000511 fprintf(f, "/* Memory reserve map from source file */\n");
Jon Loeliger05ae3d82006-04-19 11:58:45 -0500512
513 /*
514 * Use .long on high and low halfs of u64s to avoid .quad
515 * as it appears .quad isn't available in some assemblers.
516 */
David Gibsonf040d952005-10-24 18:18:38 +1000517 for (re = bi->reservelist; re; re = re->next) {
Milton Millerd4290332007-07-07 01:18:49 -0500518 if (re->label) {
519 fprintf(f, "\t.globl\t%s\n", re->label);
520 fprintf(f, "%s:\n", re->label);
521 }
Milton Miller445d55d2007-07-07 01:18:54 -0500522 fprintf(f, "\t.long\t0x%08x, 0x%08x\n",
Jon Loeliger05ae3d82006-04-19 11:58:45 -0500523 (unsigned int)(re->re.address >> 32),
524 (unsigned int)(re->re.address & 0xffffffff));
Milton Miller445d55d2007-07-07 01:18:54 -0500525 fprintf(f, "\t.long\t0x%08x, 0x%08x\n",
Jon Loeliger05ae3d82006-04-19 11:58:45 -0500526 (unsigned int)(re->re.size >> 32),
527 (unsigned int)(re->re.size & 0xffffffff));
David Gibsonfc14dad2005-06-08 17:18:34 +1000528 }
Jerry Van Barenca25e542007-04-17 18:14:41 -0400529 for (i = 0; i < reservenum; i++) {
530 fprintf(f, "\t.long\t0, 0\n\t.long\t0, 0\n");
531 }
David Gibsonfc14dad2005-06-08 17:18:34 +1000532
Jon Loeliger05ae3d82006-04-19 11:58:45 -0500533 fprintf(f, "\t.long\t0, 0\n\t.long\t0, 0\n");
David Gibsonf0517db2005-07-15 17:14:24 +1000534
David Gibsonfc14dad2005-06-08 17:18:34 +1000535 emit_label(f, symprefix, "struct_start");
David Gibsonf0517db2005-07-15 17:14:24 +1000536 flatten_tree(bi->dt, &asm_emitter, f, &strbuf, vi);
David Gibsonfb7c7ac2007-09-26 13:11:05 +1000537 fprintf(f, "\t.long\tFDT_END\n");
David Gibsonfc14dad2005-06-08 17:18:34 +1000538 emit_label(f, symprefix, "struct_end");
539
540 emit_label(f, symprefix, "strings_start");
541 dump_stringtable_asm(f, strbuf);
542 emit_label(f, symprefix, "strings_end");
543
544 emit_label(f, symprefix, "blob_end");
545
Jerry Van Baren86c01ee2007-04-18 21:59:51 -0400546 /*
547 * If the user asked for more space than is used, pad it out.
548 */
549 if (minsize > 0) {
550 fprintf(f, "\t.space\t%d - (_%s_blob_end - _%s_blob_start), 0\n",
551 minsize, symprefix, symprefix);
552 }
Kumar Gala2b7dc8d2007-11-28 10:21:12 -0600553 if (padsize > 0) {
554 fprintf(f, "\t.space\t%d, 0\n", padsize);
555 }
Jerry Van Baren86c01ee2007-04-18 21:59:51 -0400556 emit_label(f, symprefix, "blob_abs_end");
557
David Gibsonfc14dad2005-06-08 17:18:34 +1000558 data_free(strbuf);
559}
560
561struct inbuf {
562 char *base, *limit, *ptr;
563};
564
565static void inbuf_init(struct inbuf *inb, void *base, void *limit)
566{
567 inb->base = base;
568 inb->limit = limit;
569 inb->ptr = inb->base;
570}
571
572static void flat_read_chunk(struct inbuf *inb, void *p, int len)
573{
574 if ((inb->ptr + len) > inb->limit)
575 die("Premature end of data parsing flat device tree\n");
576
577 memcpy(p, inb->ptr, len);
578
579 inb->ptr += len;
580}
581
582static u32 flat_read_word(struct inbuf *inb)
583{
584 u32 val;
585
586 assert(((inb->ptr - inb->base) % sizeof(val)) == 0);
587
588 flat_read_chunk(inb, &val, sizeof(val));
589
590 return be32_to_cpu(val);
591}
592
593static void flat_realign(struct inbuf *inb, int align)
594{
595 int off = inb->ptr - inb->base;
596
597 inb->ptr = inb->base + ALIGN(off, align);
598 if (inb->ptr > inb->limit)
599 die("Premature end of data parsing flat device tree\n");
600}
601
602static char *flat_read_string(struct inbuf *inb)
603{
604 int len = 0;
David Gibson92cb9a22007-12-04 14:26:15 +1100605 const char *p = inb->ptr;
David Gibsonfc14dad2005-06-08 17:18:34 +1000606 char *str;
607
608 do {
609 if (p >= inb->limit)
610 die("Premature end of data parsing flat device tree\n");
611 len++;
612 } while ((*p++) != '\0');
613
614 str = strdup(inb->ptr);
615
616 inb->ptr += len;
617
618 flat_realign(inb, sizeof(u32));
619
620 return str;
621}
622
623static struct data flat_read_data(struct inbuf *inb, int len)
624{
625 struct data d = empty_data;
626
627 if (len == 0)
628 return empty_data;
629
630 d = data_grow_for(d, len);
631 d.len = len;
632
633 flat_read_chunk(inb, d.val, len);
634
635 flat_realign(inb, sizeof(u32));
636
637 return d;
638}
639
640static char *flat_read_stringtable(struct inbuf *inb, int offset)
641{
David Gibson92cb9a22007-12-04 14:26:15 +1100642 const char *p;
David Gibsonfc14dad2005-06-08 17:18:34 +1000643
644 p = inb->base + offset;
645 while (1) {
David Gibson4ddf7c02005-08-19 16:11:11 +1000646 if (p >= inb->limit || p < inb->base)
David Gibson7ee3ffd2005-07-11 16:45:57 +1000647 die("String offset %d overruns string table\n",
648 offset);
David Gibsonfc14dad2005-06-08 17:18:34 +1000649
650 if (*p == '\0')
651 break;
652
653 p++;
654 }
655
656 return strdup(inb->base + offset);
657}
658
David Gibson230f2532005-08-29 12:48:02 +1000659static struct property *flat_read_property(struct inbuf *dtbuf,
660 struct inbuf *strbuf, int flags)
David Gibsonfc14dad2005-06-08 17:18:34 +1000661{
662 u32 proplen, stroff;
663 char *name;
664 struct data val;
665
666 proplen = flat_read_word(dtbuf);
667 stroff = flat_read_word(dtbuf);
668
669 name = flat_read_stringtable(strbuf, stroff);
670
671 if ((flags & FTF_VARALIGN) && (proplen >= 8))
672 flat_realign(dtbuf, 8);
673
674 val = flat_read_data(dtbuf, proplen);
675
David Gibson4102d842005-06-16 14:36:37 +1000676 return build_property(name, val, NULL);
David Gibsonfc14dad2005-06-08 17:18:34 +1000677}
678
David Gibsonf0517db2005-07-15 17:14:24 +1000679
David Gibsonf040d952005-10-24 18:18:38 +1000680static struct reserve_info *flat_read_mem_reserve(struct inbuf *inb)
David Gibsonf0517db2005-07-15 17:14:24 +1000681{
David Gibsonf040d952005-10-24 18:18:38 +1000682 struct reserve_info *reservelist = NULL;
683 struct reserve_info *new;
David Gibson92cb9a22007-12-04 14:26:15 +1100684 const char *p;
David Gibsonfb7c7ac2007-09-26 13:11:05 +1000685 struct fdt_reserve_entry re;
David Gibsonf0517db2005-07-15 17:14:24 +1000686
687 /*
688 * Each entry is a pair of u64 (addr, size) values for 4 cell_t's.
689 * List terminates at an entry with size equal to zero.
690 *
691 * First pass, count entries.
692 */
693 p = inb->ptr;
David Gibson6c0f3672005-08-29 13:36:15 +1000694 while (1) {
695 flat_read_chunk(inb, &re, sizeof(re));
Michael Neuling332c5362006-07-07 23:28:10 +1000696 re.address = be64_to_cpu(re.address);
697 re.size = be64_to_cpu(re.size);
David Gibson6c0f3672005-08-29 13:36:15 +1000698 if (re.size == 0)
699 break;
David Gibsonf0517db2005-07-15 17:14:24 +1000700
David Gibsonf040d952005-10-24 18:18:38 +1000701 new = build_reserve_entry(re.address, re.size, NULL);
702 reservelist = add_reserve_entry(reservelist, new);
David Gibson6c0f3672005-08-29 13:36:15 +1000703 }
David Gibsonf0517db2005-07-15 17:14:24 +1000704
David Gibsonf040d952005-10-24 18:18:38 +1000705 return reservelist;
David Gibsonf0517db2005-07-15 17:14:24 +1000706}
707
708
David Gibson92cb9a22007-12-04 14:26:15 +1100709static char *nodename_from_path(const char *ppath, const char *cpath)
David Gibsonfc14dad2005-06-08 17:18:34 +1000710{
David Gibson92cb9a22007-12-04 14:26:15 +1100711 const char *lslash;
David Gibsonfc14dad2005-06-08 17:18:34 +1000712 int plen;
713
714 lslash = strrchr(cpath, '/');
715 if (! lslash)
716 return NULL;
717
718 plen = lslash - cpath;
719
720 if (streq(cpath, "/") && streq(ppath, ""))
721 return "";
722
723 if ((plen == 0) && streq(ppath, "/"))
724 return strdup(lslash+1);
725
David Gibson81f2e892005-06-16 17:04:00 +1000726 if (! strneq(ppath, cpath, plen))
David Gibsonfc14dad2005-06-08 17:18:34 +1000727 return NULL;
David Gibson63dc9c72007-09-18 11:44:04 +1000728
David Gibsonfc14dad2005-06-08 17:18:34 +1000729 return strdup(lslash+1);
730}
731
David Gibsonfa5b5202008-02-27 13:45:13 +1100732static int find_basenamelen(const char *name)
David Gibsonfc14dad2005-06-08 17:18:34 +1000733{
David Gibsonfa5b5202008-02-27 13:45:13 +1100734 const char *atpos = strchr(name, '@');
David Gibsonfc14dad2005-06-08 17:18:34 +1000735
736 if (atpos)
David Gibsonfa5b5202008-02-27 13:45:13 +1100737 return atpos - name;
David Gibsonfc14dad2005-06-08 17:18:34 +1000738 else
David Gibsonfa5b5202008-02-27 13:45:13 +1100739 return strlen(name);
David Gibsonfc14dad2005-06-08 17:18:34 +1000740}
741
742static struct node *unflatten_tree(struct inbuf *dtbuf,
743 struct inbuf *strbuf,
David Gibson92cb9a22007-12-04 14:26:15 +1100744 const char *parent_path, int flags)
David Gibsonfc14dad2005-06-08 17:18:34 +1000745{
746 struct node *node;
747 u32 val;
748
749 node = build_node(NULL, NULL);
750
751 if (flags & FTF_FULLPATH) {
752 node->fullpath = flat_read_string(dtbuf);
753 node->name = nodename_from_path(parent_path, node->fullpath);
754
755 if (! node->name)
756 die("Path \"%s\" is not valid as a child of \"%s\"\n",
757 node->fullpath, parent_path);
758 } else {
759 node->name = flat_read_string(dtbuf);
760 node->fullpath = join_path(parent_path, node->name);
761 }
David Gibson63dc9c72007-09-18 11:44:04 +1000762
David Gibsonfa5b5202008-02-27 13:45:13 +1100763 node->basenamelen = find_basenamelen(node->name);
David Gibsonfc14dad2005-06-08 17:18:34 +1000764
765 do {
766 struct property *prop;
767 struct node *child;
768
769 val = flat_read_word(dtbuf);
770 switch (val) {
David Gibsonfb7c7ac2007-09-26 13:11:05 +1000771 case FDT_PROP:
David Gibson592ea582007-09-04 10:43:03 +1000772 if (node->children)
773 fprintf(stderr, "Warning: Flat tree input has "
774 "subnodes preceding a property.\n");
David Gibsonfc14dad2005-06-08 17:18:34 +1000775 prop = flat_read_property(dtbuf, strbuf, flags);
776 add_property(node, prop);
777 break;
778
David Gibsonfb7c7ac2007-09-26 13:11:05 +1000779 case FDT_BEGIN_NODE:
David Gibsonfc14dad2005-06-08 17:18:34 +1000780 child = unflatten_tree(dtbuf,strbuf, node->fullpath,
781 flags);
782 add_child(node, child);
783 break;
784
David Gibsonfb7c7ac2007-09-26 13:11:05 +1000785 case FDT_END_NODE:
David Gibsonfc14dad2005-06-08 17:18:34 +1000786 break;
787
David Gibsonfb7c7ac2007-09-26 13:11:05 +1000788 case FDT_END:
789 die("Premature FDT_END in device tree blob\n");
David Gibsonfc14dad2005-06-08 17:18:34 +1000790 break;
791
David Gibsonfb7c7ac2007-09-26 13:11:05 +1000792 case FDT_NOP:
David Gibson07387742007-06-26 11:30:47 +1000793 if (!(flags & FTF_NOPS))
794 fprintf(stderr, "Warning: NOP tag found in flat tree"
795 " version <16\n");
Milton Millerce243222007-06-09 23:21:31 -0500796
David Gibson07387742007-06-26 11:30:47 +1000797 /* Ignore */
Milton Millerce243222007-06-09 23:21:31 -0500798 break;
799
David Gibsonfc14dad2005-06-08 17:18:34 +1000800 default:
801 die("Invalid opcode word %08x in device tree blob\n",
802 val);
803 }
David Gibsonfb7c7ac2007-09-26 13:11:05 +1000804 } while (val != FDT_END_NODE);
David Gibsonfc14dad2005-06-08 17:18:34 +1000805
806 return node;
807}
808
David Gibsonf0517db2005-07-15 17:14:24 +1000809
810struct boot_info *dt_from_blob(FILE *f)
David Gibsonfc14dad2005-06-08 17:18:34 +1000811{
David Gibson46c88df2007-03-14 11:02:40 +1100812 u32 magic, totalsize, version, size_str, size_dt;
David Gibsonf0517db2005-07-15 17:14:24 +1000813 u32 off_dt, off_str, off_mem_rsvmap;
David Gibsonfc14dad2005-06-08 17:18:34 +1000814 int rc;
815 char *blob;
David Gibsonfb7c7ac2007-09-26 13:11:05 +1000816 struct fdt_header *fdt;
David Gibsonfc14dad2005-06-08 17:18:34 +1000817 char *p;
818 struct inbuf dtbuf, strbuf;
David Gibsonf0517db2005-07-15 17:14:24 +1000819 struct inbuf memresvbuf;
David Gibsonfc14dad2005-06-08 17:18:34 +1000820 int sizeleft;
David Gibsonf040d952005-10-24 18:18:38 +1000821 struct reserve_info *reservelist;
David Gibsonfc14dad2005-06-08 17:18:34 +1000822 struct node *tree;
823 u32 val;
824 int flags = 0;
825
826 rc = fread(&magic, sizeof(magic), 1, f);
827 if (ferror(f))
828 die("Error reading DT blob magic number: %s\n",
829 strerror(errno));
830 if (rc < 1) {
831 if (feof(f))
832 die("EOF reading DT blob magic number\n");
833 else
834 die("Mysterious short read reading magic number\n");
835 }
836
837 magic = be32_to_cpu(magic);
David Gibsonfb7c7ac2007-09-26 13:11:05 +1000838 if (magic != FDT_MAGIC)
David Gibsonfc14dad2005-06-08 17:18:34 +1000839 die("Blob has incorrect magic number\n");
840
841 rc = fread(&totalsize, sizeof(totalsize), 1, f);
842 if (ferror(f))
843 die("Error reading DT blob size: %s\n", strerror(errno));
844 if (rc < 1) {
845 if (feof(f))
846 die("EOF reading DT blob size\n");
847 else
848 die("Mysterious short read reading blob size\n");
849 }
850
851 totalsize = be32_to_cpu(totalsize);
David Gibsonfb7c7ac2007-09-26 13:11:05 +1000852 if (totalsize < FDT_V1_SIZE)
David Gibsonfc14dad2005-06-08 17:18:34 +1000853 die("DT blob size (%d) is too small\n", totalsize);
854
855 blob = xmalloc(totalsize);
856
David Gibsonfb7c7ac2007-09-26 13:11:05 +1000857 fdt = (struct fdt_header *)blob;
858 fdt->magic = cpu_to_be32(magic);
859 fdt->totalsize = cpu_to_be32(totalsize);
David Gibsonfc14dad2005-06-08 17:18:34 +1000860
861 sizeleft = totalsize - sizeof(magic) - sizeof(totalsize);
862 p = blob + sizeof(magic) + sizeof(totalsize);
863
864 while (sizeleft) {
865 if (feof(f))
866 die("EOF before reading %d bytes of DT blob\n",
867 totalsize);
868
869 rc = fread(p, 1, sizeleft, f);
870 if (ferror(f))
871 die("Error reading DT blob: %s\n",
872 strerror(errno));
873
874 sizeleft -= rc;
875 p += rc;
876 }
877
David Gibsonfb7c7ac2007-09-26 13:11:05 +1000878 off_dt = be32_to_cpu(fdt->off_dt_struct);
879 off_str = be32_to_cpu(fdt->off_dt_strings);
880 off_mem_rsvmap = be32_to_cpu(fdt->off_mem_rsvmap);
881 version = be32_to_cpu(fdt->version);
David Gibsonfc14dad2005-06-08 17:18:34 +1000882
David Gibsonf0517db2005-07-15 17:14:24 +1000883 if (off_mem_rsvmap >= totalsize)
884 die("Mem Reserve structure offset exceeds total size\n");
885
David Gibsonfc14dad2005-06-08 17:18:34 +1000886 if (off_dt >= totalsize)
887 die("DT structure offset exceeds total size\n");
888
889 if (off_str > totalsize)
890 die("String table offset exceeds total size\n");
891
David Gibsonbf944972007-08-31 16:21:23 +1000892 size_str = -1;
David Gibsonfc14dad2005-06-08 17:18:34 +1000893 if (version >= 3) {
David Gibsonfb7c7ac2007-09-26 13:11:05 +1000894 size_str = be32_to_cpu(fdt->size_dt_strings);
David Gibsonfc14dad2005-06-08 17:18:34 +1000895 if (off_str+size_str > totalsize)
896 die("String table extends past total size\n");
897 }
David Gibson46c88df2007-03-14 11:02:40 +1100898
899 if (version >= 17) {
David Gibsonfb7c7ac2007-09-26 13:11:05 +1000900 size_dt = be32_to_cpu(fdt->size_dt_struct);
David Gibson46c88df2007-03-14 11:02:40 +1100901 if (off_dt+size_dt > totalsize)
902 die("Structure block extends past total size\n");
903 }
David Gibson63dc9c72007-09-18 11:44:04 +1000904
David Gibson46c88df2007-03-14 11:02:40 +1100905 if (version < 16) {
David Gibsonfc14dad2005-06-08 17:18:34 +1000906 flags |= FTF_FULLPATH | FTF_NAMEPROPS | FTF_VARALIGN;
Milton Millerce243222007-06-09 23:21:31 -0500907 } else {
908 flags |= FTF_NOPS;
David Gibsonfc14dad2005-06-08 17:18:34 +1000909 }
910
David Gibsonf0517db2005-07-15 17:14:24 +1000911 inbuf_init(&memresvbuf,
912 blob + off_mem_rsvmap, blob + totalsize);
David Gibsonfc14dad2005-06-08 17:18:34 +1000913 inbuf_init(&dtbuf, blob + off_dt, blob + totalsize);
David Gibsonbf944972007-08-31 16:21:23 +1000914 if (size_str >= 0)
915 inbuf_init(&strbuf, blob + off_str, blob + off_str + size_str);
916 else
917 inbuf_init(&strbuf, blob + off_str, blob + totalsize);
David Gibsonfc14dad2005-06-08 17:18:34 +1000918
David Gibsonf040d952005-10-24 18:18:38 +1000919 reservelist = flat_read_mem_reserve(&memresvbuf);
David Gibsonf0517db2005-07-15 17:14:24 +1000920
David Gibsonfc14dad2005-06-08 17:18:34 +1000921 val = flat_read_word(&dtbuf);
922
David Gibsonfb7c7ac2007-09-26 13:11:05 +1000923 if (val != FDT_BEGIN_NODE)
924 die("Device tree blob doesn't begin with FDT_BEGIN_NODE (begins with 0x%08x)\n", val);
David Gibsonfc14dad2005-06-08 17:18:34 +1000925
926 tree = unflatten_tree(&dtbuf, &strbuf, "", flags);
927
928 val = flat_read_word(&dtbuf);
David Gibsonfb7c7ac2007-09-26 13:11:05 +1000929 if (val != FDT_END)
930 die("Device tree blob doesn't end with FDT_END\n");
David Gibsonfc14dad2005-06-08 17:18:34 +1000931
932 free(blob);
933
David Gibsonf040d952005-10-24 18:18:38 +1000934 return build_boot_info(reservelist, tree);
David Gibsonfc14dad2005-06-08 17:18:34 +1000935}